Merge branches 'core/softlockup', 'core/softirq', 'core/resources', 'core/printk' and 'core/misc' into core-v28-for-linus
diff --git a/Documentation/00-INDEX b/Documentation/00-INDEX
index 5b5aba4..4382778 100644
--- a/Documentation/00-INDEX
+++ b/Documentation/00-INDEX
@@ -159,8 +159,6 @@
 	- info on using the Hayes ESP serial driver.
 highuid.txt
 	- notes on the change from 16 bit to 32 bit user/group IDs.
-hpet.txt
-	- High Precision Event Timer Driver for Linux.
 timers/
 	- info on the timer related topics
 hw_random.txt
@@ -251,8 +249,6 @@
 	- how to execute Mono-based .NET binaries with the help of BINFMT_MISC.
 moxa-smartio
 	- file with info on installing/using Moxa multiport serial driver.
-mtrr.txt
-	- how to use PPro Memory Type Range Registers to increase performance.
 mutex-design.txt
 	- info on the generic mutex subsystem.
 namespaces/
diff --git a/Documentation/ABI/testing/sysfs-class-regulator b/Documentation/ABI/testing/sysfs-class-regulator
index 79a4a75..3731f6f 100644
--- a/Documentation/ABI/testing/sysfs-class-regulator
+++ b/Documentation/ABI/testing/sysfs-class-regulator
@@ -1,7 +1,7 @@
 What:		/sys/class/regulator/.../state
 Date:		April 2008
 KernelVersion:	2.6.26
-Contact:	Liam Girdwood <lg@opensource.wolfsonmicro.com>
+Contact:	Liam Girdwood <lrg@slimlogic.co.uk>
 Description:
 		Each regulator directory will contain a field called
 		state. This holds the regulator output state.
@@ -27,7 +27,7 @@
 What:		/sys/class/regulator/.../type
 Date:		April 2008
 KernelVersion:	2.6.26
-Contact:	Liam Girdwood <lg@opensource.wolfsonmicro.com>
+Contact:	Liam Girdwood <lrg@slimlogic.co.uk>
 Description:
 		Each regulator directory will contain a field called
 		type. This holds the regulator type.
@@ -51,7 +51,7 @@
 What:		/sys/class/regulator/.../microvolts
 Date:		April 2008
 KernelVersion:	2.6.26
-Contact:	Liam Girdwood <lg@opensource.wolfsonmicro.com>
+Contact:	Liam Girdwood <lrg@slimlogic.co.uk>
 Description:
 		Each regulator directory will contain a field called
 		microvolts. This holds the regulator output voltage setting
@@ -65,7 +65,7 @@
 What:		/sys/class/regulator/.../microamps
 Date:		April 2008
 KernelVersion:	2.6.26
-Contact:	Liam Girdwood <lg@opensource.wolfsonmicro.com>
+Contact:	Liam Girdwood <lrg@slimlogic.co.uk>
 Description:
 		Each regulator directory will contain a field called
 		microamps. This holds the regulator output current limit
@@ -79,7 +79,7 @@
 What:		/sys/class/regulator/.../opmode
 Date:		April 2008
 KernelVersion:	2.6.26
-Contact:	Liam Girdwood <lg@opensource.wolfsonmicro.com>
+Contact:	Liam Girdwood <lrg@slimlogic.co.uk>
 Description:
 		Each regulator directory will contain a field called
 		opmode. This holds the regulator operating mode setting.
@@ -102,7 +102,7 @@
 What:		/sys/class/regulator/.../min_microvolts
 Date:		April 2008
 KernelVersion:	2.6.26
-Contact:	Liam Girdwood <lg@opensource.wolfsonmicro.com>
+Contact:	Liam Girdwood <lrg@slimlogic.co.uk>
 Description:
 		Each regulator directory will contain a field called
 		min_microvolts. This holds the minimum safe working regulator
@@ -116,7 +116,7 @@
 What:		/sys/class/regulator/.../max_microvolts
 Date:		April 2008
 KernelVersion:	2.6.26
-Contact:	Liam Girdwood <lg@opensource.wolfsonmicro.com>
+Contact:	Liam Girdwood <lrg@slimlogic.co.uk>
 Description:
 		Each regulator directory will contain a field called
 		max_microvolts. This holds the maximum safe working regulator
@@ -130,7 +130,7 @@
 What:		/sys/class/regulator/.../min_microamps
 Date:		April 2008
 KernelVersion:	2.6.26
-Contact:	Liam Girdwood <lg@opensource.wolfsonmicro.com>
+Contact:	Liam Girdwood <lrg@slimlogic.co.uk>
 Description:
 		Each regulator directory will contain a field called
 		min_microamps. This holds the minimum safe working regulator
@@ -145,7 +145,7 @@
 What:		/sys/class/regulator/.../max_microamps
 Date:		April 2008
 KernelVersion:	2.6.26
-Contact:	Liam Girdwood <lg@opensource.wolfsonmicro.com>
+Contact:	Liam Girdwood <lrg@slimlogic.co.uk>
 Description:
 		Each regulator directory will contain a field called
 		max_microamps. This holds the maximum safe working regulator
@@ -157,10 +157,23 @@
 		platform code.
 
 
+What:		/sys/class/regulator/.../name
+Date:		October 2008
+KernelVersion:	2.6.28
+Contact:	Liam Girdwood <lrg@slimlogic.co.uk>
+Description:
+		Each regulator directory will contain a field called
+		name. This holds a string identifying the regulator for
+		display purposes.
+
+		NOTE: this will be empty if no suitable name is provided
+		by platform or regulator drivers.
+
+
 What:		/sys/class/regulator/.../num_users
 Date:		April 2008
 KernelVersion:	2.6.26
-Contact:	Liam Girdwood <lg@opensource.wolfsonmicro.com>
+Contact:	Liam Girdwood <lrg@slimlogic.co.uk>
 Description:
 		Each regulator directory will contain a field called
 		num_users. This holds the number of consumer devices that
@@ -170,7 +183,7 @@
 What:		/sys/class/regulator/.../requested_microamps
 Date:		April 2008
 KernelVersion:	2.6.26
-Contact:	Liam Girdwood <lg@opensource.wolfsonmicro.com>
+Contact:	Liam Girdwood <lrg@slimlogic.co.uk>
 Description:
 		Each regulator directory will contain a field called
 		requested_microamps. This holds the total requested load
@@ -181,7 +194,7 @@
 What:		/sys/class/regulator/.../parent
 Date:		April 2008
 KernelVersion:	2.6.26
-Contact:	Liam Girdwood <lg@opensource.wolfsonmicro.com>
+Contact:	Liam Girdwood <lrg@slimlogic.co.uk>
 Description:
 		Some regulator directories will contain a link called parent.
 		This points to the parent or supply regulator if one exists.
@@ -189,7 +202,7 @@
 What:		/sys/class/regulator/.../suspend_mem_microvolts
 Date:		May 2008
 KernelVersion:	2.6.26
-Contact:	Liam Girdwood <lg@opensource.wolfsonmicro.com>
+Contact:	Liam Girdwood <lrg@slimlogic.co.uk>
 Description:
 		Each regulator directory will contain a field called
 		suspend_mem_microvolts. This holds the regulator output
@@ -203,7 +216,7 @@
 What:		/sys/class/regulator/.../suspend_disk_microvolts
 Date:		May 2008
 KernelVersion:	2.6.26
-Contact:	Liam Girdwood <lg@opensource.wolfsonmicro.com>
+Contact:	Liam Girdwood <lrg@slimlogic.co.uk>
 Description:
 		Each regulator directory will contain a field called
 		suspend_disk_microvolts. This holds the regulator output
@@ -217,7 +230,7 @@
 What:		/sys/class/regulator/.../suspend_standby_microvolts
 Date:		May 2008
 KernelVersion:	2.6.26
-Contact:	Liam Girdwood <lg@opensource.wolfsonmicro.com>
+Contact:	Liam Girdwood <lrg@slimlogic.co.uk>
 Description:
 		Each regulator directory will contain a field called
 		suspend_standby_microvolts. This holds the regulator output
@@ -231,7 +244,7 @@
 What:		/sys/class/regulator/.../suspend_mem_mode
 Date:		May 2008
 KernelVersion:	2.6.26
-Contact:	Liam Girdwood <lg@opensource.wolfsonmicro.com>
+Contact:	Liam Girdwood <lrg@slimlogic.co.uk>
 Description:
 		Each regulator directory will contain a field called
 		suspend_mem_mode. This holds the regulator operating mode
@@ -245,7 +258,7 @@
 What:		/sys/class/regulator/.../suspend_disk_mode
 Date:		May 2008
 KernelVersion:	2.6.26
-Contact:	Liam Girdwood <lg@opensource.wolfsonmicro.com>
+Contact:	Liam Girdwood <lrg@slimlogic.co.uk>
 Description:
 		Each regulator directory will contain a field called
 		suspend_disk_mode. This holds the regulator operating mode
@@ -258,7 +271,7 @@
 What:		/sys/class/regulator/.../suspend_standby_mode
 Date:		May 2008
 KernelVersion:	2.6.26
-Contact:	Liam Girdwood <lg@opensource.wolfsonmicro.com>
+Contact:	Liam Girdwood <lrg@slimlogic.co.uk>
 Description:
 		Each regulator directory will contain a field called
 		suspend_standby_mode. This holds the regulator operating mode
@@ -272,7 +285,7 @@
 What:		/sys/class/regulator/.../suspend_mem_state
 Date:		May 2008
 KernelVersion:	2.6.26
-Contact:	Liam Girdwood <lg@opensource.wolfsonmicro.com>
+Contact:	Liam Girdwood <lrg@slimlogic.co.uk>
 Description:
 		Each regulator directory will contain a field called
 		suspend_mem_state. This holds the regulator operating state
@@ -287,7 +300,7 @@
 What:		/sys/class/regulator/.../suspend_disk_state
 Date:		May 2008
 KernelVersion:	2.6.26
-Contact:	Liam Girdwood <lg@opensource.wolfsonmicro.com>
+Contact:	Liam Girdwood <lrg@slimlogic.co.uk>
 Description:
 		Each regulator directory will contain a field called
 		suspend_disk_state. This holds the regulator operating state
@@ -302,7 +315,7 @@
 What:		/sys/class/regulator/.../suspend_standby_state
 Date:		May 2008
 KernelVersion:	2.6.26
-Contact:	Liam Girdwood <lg@opensource.wolfsonmicro.com>
+Contact:	Liam Girdwood <lrg@slimlogic.co.uk>
 Description:
 		Each regulator directory will contain a field called
 		suspend_standby_state. This holds the regulator operating
diff --git a/Documentation/DMA-API.txt b/Documentation/DMA-API.txt
index d8b63d1..b8e8646 100644
--- a/Documentation/DMA-API.txt
+++ b/Documentation/DMA-API.txt
@@ -337,7 +337,7 @@
 	int i, count = dma_map_sg(dev, sglist, nents, direction);
 	struct scatterlist *sg;
 
-	for (i = 0, sg = sglist; i < count; i++, sg++) {
+	for_each_sg(sglist, sg, count, i) {
 		hw_address[i] = sg_dma_address(sg);
 		hw_len[i] = sg_dma_len(sg);
 	}
diff --git a/Documentation/DMA-mapping.txt b/Documentation/DMA-mapping.txt
index b463ecd..c74fec8 100644
--- a/Documentation/DMA-mapping.txt
+++ b/Documentation/DMA-mapping.txt
@@ -740,7 +740,7 @@
 	dma_addr_t dma_handle;
 
 	dma_handle = pci_map_single(pdev, addr, size, direction);
-	if (pci_dma_mapping_error(dma_handle)) {
+	if (pci_dma_mapping_error(pdev, dma_handle)) {
 		/*
 		 * reduce current DMA mapping usage,
 		 * delay and try again later or
diff --git a/Documentation/DocBook/kernel-api.tmpl b/Documentation/DocBook/kernel-api.tmpl
index b7b1482..9d0058e 100644
--- a/Documentation/DocBook/kernel-api.tmpl
+++ b/Documentation/DocBook/kernel-api.tmpl
@@ -283,6 +283,7 @@
   <chapter id="security">
      <title>Security Framework</title>
 !Isecurity/security.c
+!Esecurity/inode.c
   </chapter>
 
   <chapter id="audit">
@@ -364,6 +365,10 @@
 !Eblock/blk-barrier.c
 !Eblock/blk-tag.c
 !Iblock/blk-tag.c
+!Eblock/blk-integrity.c
+!Iblock/blktrace.c
+!Iblock/genhd.c
+!Eblock/genhd.c
   </chapter>
 
   <chapter id="chrdev">
diff --git a/Documentation/DocBook/mac80211.tmpl b/Documentation/DocBook/mac80211.tmpl
index b651e0a..77c3c20 100644
--- a/Documentation/DocBook/mac80211.tmpl
+++ b/Documentation/DocBook/mac80211.tmpl
@@ -145,7 +145,6 @@
         this though and the recommendation to allow only a single
         interface in STA mode at first!
       </para>
-!Finclude/net/mac80211.h ieee80211_if_types
 !Finclude/net/mac80211.h ieee80211_if_init_conf
 !Finclude/net/mac80211.h ieee80211_if_conf
     </chapter>
@@ -177,8 +176,7 @@
         <title>functions/definitions</title>
 !Finclude/net/mac80211.h ieee80211_rx_status
 !Finclude/net/mac80211.h mac80211_rx_flags
-!Finclude/net/mac80211.h ieee80211_tx_control
-!Finclude/net/mac80211.h ieee80211_tx_status_flags
+!Finclude/net/mac80211.h ieee80211_tx_info
 !Finclude/net/mac80211.h ieee80211_rx
 !Finclude/net/mac80211.h ieee80211_rx_irqsafe
 !Finclude/net/mac80211.h ieee80211_tx_status
@@ -189,12 +187,11 @@
 !Finclude/net/mac80211.h ieee80211_ctstoself_duration
 !Finclude/net/mac80211.h ieee80211_generic_frame_duration
 !Finclude/net/mac80211.h ieee80211_get_hdrlen_from_skb
-!Finclude/net/mac80211.h ieee80211_get_hdrlen
+!Finclude/net/mac80211.h ieee80211_hdrlen
 !Finclude/net/mac80211.h ieee80211_wake_queue
 !Finclude/net/mac80211.h ieee80211_stop_queue
-!Finclude/net/mac80211.h ieee80211_start_queues
-!Finclude/net/mac80211.h ieee80211_stop_queues
 !Finclude/net/mac80211.h ieee80211_wake_queues
+!Finclude/net/mac80211.h ieee80211_stop_queues
       </sect1>
     </chapter>
 
@@ -230,8 +227,7 @@
       <title>Multiple queues and QoS support</title>
       <para>TBD</para>
 !Finclude/net/mac80211.h ieee80211_tx_queue_params
-!Finclude/net/mac80211.h ieee80211_tx_queue_stats_data
-!Finclude/net/mac80211.h ieee80211_tx_queue
+!Finclude/net/mac80211.h ieee80211_tx_queue_stats
     </chapter>
 
     <chapter id="AP">
diff --git a/Documentation/HOWTO b/Documentation/HOWTO
index c2371c5..48a3955 100644
--- a/Documentation/HOWTO
+++ b/Documentation/HOWTO
@@ -77,7 +77,8 @@
 When a kernel change causes the interface that the kernel exposes to
 userspace to change, it is recommended that you send the information or
 a patch to the manual pages explaining the change to the manual pages
-maintainer at mtk.manpages@gmail.com.
+maintainer at mtk.manpages@gmail.com, and CC the list
+linux-api@vger.kernel.org.
 
 Here is a list of files that are in the kernel source tree that are
 required reading:
diff --git a/Documentation/RCU/checklist.txt b/Documentation/RCU/checklist.txt
index cf5562c..6e25340 100644
--- a/Documentation/RCU/checklist.txt
+++ b/Documentation/RCU/checklist.txt
@@ -210,7 +210,7 @@
 		number of updates per grace period.
 
 9.	All RCU list-traversal primitives, which include
-	rcu_dereference(), list_for_each_rcu(), list_for_each_entry_rcu(),
+	rcu_dereference(), list_for_each_entry_rcu(),
 	list_for_each_continue_rcu(), and list_for_each_safe_rcu(),
 	must be either within an RCU read-side critical section or
 	must be protected by appropriate update-side locks.  RCU
diff --git a/Documentation/RCU/rcuref.txt b/Documentation/RCU/rcuref.txt
index 451de2a..4202ad0 100644
--- a/Documentation/RCU/rcuref.txt
+++ b/Documentation/RCU/rcuref.txt
@@ -29,9 +29,9 @@
 					}
 
 If this list/array is made lock free using RCU as in changing the
-write_lock() in add() and delete() to spin_lock and changing read_lock
-in search_and_reference to rcu_read_lock(), the atomic_get in
-search_and_reference could potentially hold reference to an element which
+write_lock() in add() and delete() to spin_lock() and changing read_lock()
+in search_and_reference() to rcu_read_lock(), the atomic_inc() in
+search_and_reference() could potentially hold reference to an element which
 has already been deleted from the list/array.  Use atomic_inc_not_zero()
 in this scenario as follows:
 
@@ -40,20 +40,20 @@
 {					{
     alloc_object			    rcu_read_lock();
     ...					    search_for_element
-    atomic_set(&el->rc, 1);		    if (atomic_inc_not_zero(&el->rc)) {
-    write_lock(&list_lock);		        rcu_read_unlock();
+    atomic_set(&el->rc, 1);		    if (!atomic_inc_not_zero(&el->rc)) {
+    spin_lock(&list_lock);		        rcu_read_unlock();
 					        return FAIL;
     add_element				    }
     ...					    ...
-    write_unlock(&list_lock);		    rcu_read_unlock();
+    spin_unlock(&list_lock);		    rcu_read_unlock();
 }					}
 3.					4.
 release_referenced()			delete()
 {					{
-    ...					    write_lock(&list_lock);
+    ...					    spin_lock(&list_lock);
     if (atomic_dec_and_test(&el->rc))       ...
         call_rcu(&el->head, el_free);       delete_element
-    ...                                     write_unlock(&list_lock);
+    ...                                     spin_unlock(&list_lock);
 } 					    ...
 					    if (atomic_dec_and_test(&el->rc))
 					        call_rcu(&el->head, el_free);
diff --git a/Documentation/RCU/whatisRCU.txt b/Documentation/RCU/whatisRCU.txt
index e04d643..9617082 100644
--- a/Documentation/RCU/whatisRCU.txt
+++ b/Documentation/RCU/whatisRCU.txt
@@ -786,8 +786,6 @@
 	list_for_each_entry_rcu
 	hlist_for_each_entry_rcu
 
-	list_for_each_rcu		(to be deprecated in favor of
-					 list_for_each_entry_rcu)
 	list_for_each_continue_rcu	(to be deprecated in favor of new
 					 list_for_each_entry_continue_rcu)
 
diff --git a/Documentation/SELinux.txt b/Documentation/SELinux.txt
new file mode 100644
index 0000000..07eae00f
--- /dev/null
+++ b/Documentation/SELinux.txt
@@ -0,0 +1,27 @@
+If you want to use SELinux, chances are you will want
+to use the distro-provided policies, or install the
+latest reference policy release from
+	http://oss.tresys.com/projects/refpolicy
+
+However, if you want to install a dummy policy for
+testing, you can do using 'mdp' provided under
+scripts/selinux.  Note that this requires the selinux
+userspace to be installed - in particular you will
+need checkpolicy to compile a kernel, and setfiles and
+fixfiles to label the filesystem.
+
+	1. Compile the kernel with selinux enabled.
+	2. Type 'make' to compile mdp.
+	3. Make sure that you are not running with
+	   SELinux enabled and a real policy.  If
+	   you are, reboot with selinux disabled
+	   before continuing.
+	4. Run install_policy.sh:
+		cd scripts/selinux
+		sh install_policy.sh
+
+Step 4 will create a new dummy policy valid for your
+kernel, with a single selinux user, role, and type.
+It will compile the policy, will set your SELINUXTYPE to
+dummy in /etc/selinux/config, install the compiled policy
+as 'dummy', and relabel your filesystem.
diff --git a/Documentation/SubmitChecklist b/Documentation/SubmitChecklist
index da10e07..21f0795 100644
--- a/Documentation/SubmitChecklist
+++ b/Documentation/SubmitChecklist
@@ -67,6 +67,8 @@
 
 19: All new userspace interfaces are documented in Documentation/ABI/.
     See Documentation/ABI/README for more information.
+    Patches that change userspace interfaces should be CCed to
+    linux-api@vger.kernel.org.
 
 20: Check that it all passes `make headers_check'.
 
diff --git a/Documentation/blackfin/kgdb.txt b/Documentation/blackfin/kgdb.txt
deleted file mode 100644
index 84f6a484..0000000
--- a/Documentation/blackfin/kgdb.txt
+++ /dev/null
@@ -1,155 +0,0 @@
-			A Simple Guide to Configure KGDB
-
-			Sonic Zhang <sonic.zhang@analog.com>
-				Aug. 24th 2006
-
-
-This KGDB patch enables the kernel developer to do source level debugging on
-the kernel for the Blackfin architecture.  The debugging works over either the
-ethernet interface or one of the uarts.  Both software breakpoints and
-hardware breakpoints are supported in this version.
-http://docs.blackfin.uclinux.org/doku.php?id=kgdb
-
-
-2 known issues:
-1. This bug:
-       http://blackfin.uclinux.org/tracker/index.php?func=detail&aid=544&group_id=18&atid=145
-   The GDB client for Blackfin uClinux causes incorrect values of local
-   variables to be displayed when the user breaks the running of kernel in GDB.
-2. Because of a hardware bug in Blackfin 533 v1.0.3:
-       05000067 - Watchpoints (Hardware Breakpoints) are not supported
-   Hardware breakpoints cannot be set properly.
-
-
-Debug over Ethernet:
- 
-1. Compile and install the cross platform version of gdb for blackfin, which
-   can be found at $(BINROOT)/bfin-elf-gdb.
-
-2. Apply this patch to the 2.6.x kernel.  Select the menuconfig option under
-   "Kernel hacking" -> "Kernel debugging" -> "KGDB: kernel debug with remote gdb".
-   With this selected, option "Full Symbolic/Source Debugging support" and 
-   "Compile the kernel with frame pointers" are also selected.
-
-3. Select option "KGDB: connect over (Ethernet)".  Add "kgdboe=@target-IP/,@host-IP/" to
-   the option "Compiled-in Kernel Boot Parameter" under "Kernel hacking".
-
-4. Connect minicom to the serial port and boot the kernel image.
-
-5. Configure the IP "/> ifconfig eth0 target-IP"
-
-6. Start GDB client "bfin-elf-gdb vmlinux".
-
-7. Connect to the target "(gdb) target remote udp:target-IP:6443".
-
-8. Set software breakpoint "(gdb) break sys_open".
-
-9. Continue "(gdb) c".
-
-10. Run ls in the target console "/> ls".
-
-11. Breakpoint hits. "Breakpoint 1: sys_open(..."
-
-12. Display local variables and function paramters.
-    (*) This operation gives wrong results, see known issue 1.
-
-13. Single stepping "(gdb) si".
-
-14. Remove breakpoint 1. "(gdb) del 1"
-
-15. Set hardware breakpoint "(gdb) hbreak sys_open".
-
-16. Continue "(gdb) c".
-
-17. Run ls in the target console "/> ls".
-
-18. Hardware breakpoint hits. "Breakpoint 1: sys_open(...".
-    (*) This hardware breakpoint will not be hit, see known issue 2.
-
-19. Continue "(gdb) c".
-
-20. Interrupt the target in GDB "Ctrl+C".
-
-21. Detach from the target "(gdb) detach".
-
-22. Exit GDB "(gdb) quit".
-
-
-Debug over the UART:
-
-1. Compile and install the cross platform version of gdb for blackfin, which
-   can be found at $(BINROOT)/bfin-elf-gdb.
-
-2. Apply this patch to the 2.6.x kernel.  Select the menuconfig option under
-   "Kernel hacking" -> "Kernel debugging" -> "KGDB: kernel debug with remote gdb".
-   With this selected, option "Full Symbolic/Source Debugging support" and 
-   "Compile the kernel with frame pointers" are also selected.
-
-3. Select option "KGDB: connect over (UART)".  Set "KGDB: UART port number" to be
-   a different one from the console.  Don't forget to change the mode of
-   blackfin serial driver to PIO.  Otherwise kgdb works incorrectly on UART.
- 
-4. If you want connect to kgdb when the kernel boots, enable
-   "KGDB: Wait for gdb connection early" 
-
-5. Compile kernel.
-
-6. Connect minicom to the serial port of the console and boot the kernel image.
-
-7. Start GDB client "bfin-elf-gdb vmlinux".
-
-8. Set the baud rate in GDB "(gdb) set remotebaud 57600".
-
-9. Connect to the target on the second serial port "(gdb) target remote /dev/ttyS1".
-
-10. Set software breakpoint "(gdb) break sys_open".
-
-11. Continue "(gdb) c". 
-
-12. Run ls in the target console "/> ls". 
-
-13. A breakpoint is hit. "Breakpoint 1: sys_open(..."
-
-14. All other operations are the same as that in KGDB over Ethernet. 
-
-
-Debug over the same UART as console:
-
-1. Compile and install the cross platform version of gdb for blackfin, which
-   can be found at $(BINROOT)/bfin-elf-gdb.
-
-2. Apply this patch to the 2.6.x kernel.  Select the menuconfig option under
-   "Kernel hacking" -> "Kernel debugging" -> "KGDB: kernel debug with remote gdb".
-   With this selected, option "Full Symbolic/Source Debugging support" and 
-   "Compile the kernel with frame pointers" are also selected.
-
-3. Select option "KGDB: connect over UART".  Set "KGDB: UART port number" to console.
-   Don't forget to change the mode of blackfin serial driver to PIO.
-   Otherwise kgdb works incorrectly on UART.
- 
-4. If you want connect to kgdb when the kernel boots, enable
-   "KGDB: Wait for gdb connection early" 
-
-5. Connect minicom to the serial port and boot the kernel image. 
-
-6. (Optional) Ask target to wait for gdb connection by entering Ctrl+A. In minicom, you should enter Ctrl+A+A.
-
-7. Start GDB client "bfin-elf-gdb vmlinux".
-
-8. Set the baud rate in GDB "(gdb) set remotebaud 57600".
-
-9. Connect to the target "(gdb) target remote /dev/ttyS0".
-
-10. Set software breakpoint "(gdb) break sys_open".
-
-11. Continue "(gdb) c". Then enter Ctrl+C twice to stop GDB connection.
-
-12. Run ls in the target console "/> ls". Dummy string can be seen on the console.
-
-13. Then connect the gdb to target again. "(gdb) target remote /dev/ttyS0".
-    Now you will find a breakpoint is hit. "Breakpoint 1: sys_open(..."
-
-14. All other operations are the same as that in KGDB over Ethernet.  The only
-    difference is that after continue command in GDB, please stop GDB
-    connection by 2 "Ctrl+C"s and connect again after breakpoints are hit or
-    Ctrl+A is entered.
diff --git a/Documentation/block/deadline-iosched.txt b/Documentation/block/deadline-iosched.txt
index c23cab1..7257676 100644
--- a/Documentation/block/deadline-iosched.txt
+++ b/Documentation/block/deadline-iosched.txt
@@ -30,12 +30,18 @@
 Similar to read_expire mentioned above, but for writes.
 
 
-fifo_batch
+fifo_batch	(number of requests)
 ----------
 
-When a read request expires its deadline, we must move some requests from
-the sorted io scheduler list to the block device dispatch queue. fifo_batch
-controls how many requests we move.
+Requests are grouped into ``batches'' of a particular data direction (read or
+write) which are serviced in increasing sector order.  To limit extra seeking,
+deadline expiries are only checked between batches.  fifo_batch controls the
+maximum number of requests per batch.
+
+This parameter tunes the balance between per-request latency and aggregate
+throughput.  When low latency is the primary concern, smaller is better (where
+a value of 1 yields first-come first-served behaviour).  Increasing fifo_batch
+generally improves throughput, at the cost of latency variation.
 
 
 writes_starved	(number of dispatches)
diff --git a/Documentation/cdrom/ide-cd b/Documentation/cdrom/ide-cd
index 91c0dcc..2c558cd 100644
--- a/Documentation/cdrom/ide-cd
+++ b/Documentation/cdrom/ide-cd
@@ -145,8 +145,7 @@
 
 To play an audio CD, you should first unmount and remove any data
 CDROM.  Any of the CDROM player programs should then work (workman,
-workbone, cdplayer, etc.).  Lacking anything else, you could use the
-cdtester program in Documentation/cdrom/sbpcd.
+workbone, cdplayer, etc.).
 
 On a few drives, you can read digital audio directly using a program
 such as cdda2wav.  The only types of drive which I've heard support
diff --git a/Documentation/cpu-freq/index.txt b/Documentation/cpu-freq/index.txt
index ffdb532..3d0b915 100644
--- a/Documentation/cpu-freq/index.txt
+++ b/Documentation/cpu-freq/index.txt
@@ -35,11 +35,9 @@
 ------------
 There is a CPU frequency changing CVS commit and general list where
 you can report bugs, problems or submit patches. To post a message,
-send an email to cpufreq@lists.linux.org.uk, to subscribe go to
-http://lists.linux.org.uk/mailman/listinfo/cpufreq. Previous post to the
-mailing list are available to subscribers at
-http://lists.linux.org.uk/mailman/private/cpufreq/.
-
+send an email to cpufreq@vger.kernel.org, to subscribe go to
+http://vger.kernel.org/vger-lists.html#cpufreq and follow the
+instructions there.
 
 Links
 -----
@@ -50,7 +48,7 @@
 * http://cvs.arm.linux.org.uk/
 
 the CPUFreq Mailing list:
-* http://lists.linux.org.uk/mailman/listinfo/cpufreq
+* http://vger.kernel.org/vger-lists.html#cpufreq
 
 Clock and voltage scaling for the SA-1100:
 * http://www.lartmaker.nl/projects/scaling
diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt
index 83c88ca..4d2566a 100644
--- a/Documentation/feature-removal-schedule.txt
+++ b/Documentation/feature-removal-schedule.txt
@@ -6,6 +6,24 @@
 
 ---------------------------
 
+What:	old static regulatory information and ieee80211_regdom module parameter
+When:	2.6.29
+Why:	The old regulatory infrastructure has been replaced with a new one
+	which does not require statically defined regulatory domains. We do
+	not want to keep static regulatory domains in the kernel due to the
+	the dynamic nature of regulatory law and localization. We kept around
+	the old static definitions for the regulatory domains of:
+		* US
+		* JP
+		* EU
+	and used by default the US when CONFIG_WIRELESS_OLD_REGULATORY was
+	set. We also kept around the ieee80211_regdom module parameter in case
+	some applications were relying on it. Changing regulatory domains
+	can now be done instead by using nl80211, as is done with iw.
+Who:	Luis R. Rodriguez <lrodriguez@atheros.com>
+
+---------------------------
+
 What:	dev->power.power_state
 When:	July 2007
 Why:	Broken design for runtime control over driver power states, confusing
@@ -232,6 +250,9 @@
 	- xt_mark match revision 0
 	  (superseded by xt_mark match revision 1)
 
+	- xt_recent: the old ipt_recent proc dir
+	  (superseded by /proc/net/xt_recent)
+
 When:	January 2009 or Linux 2.7.0, whichever comes first
 Why:	Superseded by newer revisions or modules
 Who:	Jan Engelhardt <jengelh@computergmbh.de>
@@ -266,11 +287,10 @@
 
 ---------------------------
 
-What:	old style serial driver for ColdFire (CONFIG_SERIAL_COLDFIRE)
-When:	2.6.28
-Why:	This driver still uses the old interface and has been replaced
-	by CONFIG_SERIAL_MCF.
-Who:	Sebastian Siewior <sebastian@breakpoint.cc>
+What:	remove HID compat support
+When:	2.6.29
+Why:	needed only as a temporary solution until distros fix themselves up
+Who:	Jiri Slaby <jirislaby@gmail.com>
 
 ---------------------------
 
diff --git a/Documentation/filesystems/ext4.txt b/Documentation/filesystems/ext4.txt
index 0d53949..eb154ef 100644
--- a/Documentation/filesystems/ext4.txt
+++ b/Documentation/filesystems/ext4.txt
@@ -32,9 +32,9 @@
     you will need to merge your changes with the version from e2fsprogs
     1.41.x.
 
-  - Create a new filesystem using the ext4dev filesystem type:
+  - Create a new filesystem using the ext4 filesystem type:
 
-    	# mke2fs -t ext4dev /dev/hda1
+    	# mke2fs -t ext4 /dev/hda1
 
     Or configure an existing ext3 filesystem to support extents and set
     the test_fs flag to indicate that it's ok for an in-development
@@ -47,13 +47,13 @@
 
         # tune2fs -I 256 /dev/hda1
 
-    (Note: we currently do not have tools to convert an ext4dev
+    (Note: we currently do not have tools to convert an ext4
     filesystem back to ext3; so please do not do try this on production
     filesystems.)
 
   - Mounting:
 
-	# mount -t ext4dev /dev/hda1 /wherever
+	# mount -t ext4 /dev/hda1 /wherever
 
   - When comparing performance with other filesystems, remember that
     ext3/4 by default offers higher data integrity guarantees than most.
@@ -177,6 +177,11 @@
 			your disks are battery-backed in one way or another,
 			disabling barriers may safely improve performance.
 
+inode_readahead=n	This tuning parameter controls the maximum
+			number of inode table blocks that ext4's inode
+			table readahead algorithm will pre-read into
+			the buffer cache.  The default value is 32 blocks.
+
 orlov		(*)	This enables the new Orlov block allocator. It is
 			enabled by default.
 
@@ -218,6 +223,11 @@
 errors=continue		Keep going on a filesystem error.
 errors=panic		Panic and halt the machine if an error occurs.
 
+data_err=ignore(*)	Just print an error message if an error occurs
+			in a file data buffer in ordered mode.
+data_err=abort		Abort the journal if an error occurs in a file
+			data buffer in ordered mode.
+
 grpid			Give objects the same group ID as their creator.
 bsdgroups
 
@@ -252,6 +262,7 @@
 delalloc	(*)	Deferring block allocation until write-out time.
 nodelalloc		Disable delayed allocation. Blocks are allocation
 			when data is copied from user to page cache.
+
 Data Mode
 =========
 There are 3 different data modes:
diff --git a/Documentation/filesystems/fiemap.txt b/Documentation/filesystems/fiemap.txt
new file mode 100644
index 0000000..1e3defc
--- /dev/null
+++ b/Documentation/filesystems/fiemap.txt
@@ -0,0 +1,228 @@
+============
+Fiemap Ioctl
+============
+
+The fiemap ioctl is an efficient method for userspace to get file
+extent mappings. Instead of block-by-block mapping (such as bmap), fiemap
+returns a list of extents.
+
+
+Request Basics
+--------------
+
+A fiemap request is encoded within struct fiemap:
+
+struct fiemap {
+	__u64	fm_start;	 /* logical offset (inclusive) at
+				  * which to start mapping (in) */
+	__u64	fm_length;	 /* logical length of mapping which
+				  * userspace cares about (in) */
+	__u32	fm_flags;	 /* FIEMAP_FLAG_* flags for request (in/out) */
+	__u32	fm_mapped_extents; /* number of extents that were
+				    * mapped (out) */
+	__u32	fm_extent_count; /* size of fm_extents array (in) */
+	__u32	fm_reserved;
+	struct fiemap_extent fm_extents[0]; /* array of mapped extents (out) */
+};
+
+
+fm_start, and fm_length specify the logical range within the file
+which the process would like mappings for. Extents returned mirror
+those on disk - that is, the logical offset of the 1st returned extent
+may start before fm_start, and the range covered by the last returned
+extent may end after fm_length. All offsets and lengths are in bytes.
+
+Certain flags to modify the way in which mappings are looked up can be
+set in fm_flags. If the kernel doesn't understand some particular
+flags, it will return EBADR and the contents of fm_flags will contain
+the set of flags which caused the error. If the kernel is compatible
+with all flags passed, the contents of fm_flags will be unmodified.
+It is up to userspace to determine whether rejection of a particular
+flag is fatal to it's operation. This scheme is intended to allow the
+fiemap interface to grow in the future but without losing
+compatibility with old software.
+
+fm_extent_count specifies the number of elements in the fm_extents[] array
+that can be used to return extents.  If fm_extent_count is zero, then the
+fm_extents[] array is ignored (no extents will be returned), and the
+fm_mapped_extents count will hold the number of extents needed in
+fm_extents[] to hold the file's current mapping.  Note that there is
+nothing to prevent the file from changing between calls to FIEMAP.
+
+The following flags can be set in fm_flags:
+
+* FIEMAP_FLAG_SYNC
+If this flag is set, the kernel will sync the file before mapping extents.
+
+* FIEMAP_FLAG_XATTR
+If this flag is set, the extents returned will describe the inodes
+extended attribute lookup tree, instead of it's data tree.
+
+
+Extent Mapping
+--------------
+
+Extent information is returned within the embedded fm_extents array
+which userspace must allocate along with the fiemap structure. The
+number of elements in the fiemap_extents[] array should be passed via
+fm_extent_count. The number of extents mapped by kernel will be
+returned via fm_mapped_extents. If the number of fiemap_extents
+allocated is less than would be required to map the requested range,
+the maximum number of extents that can be mapped in the fm_extent[]
+array will be returned and fm_mapped_extents will be equal to
+fm_extent_count. In that case, the last extent in the array will not
+complete the requested range and will not have the FIEMAP_EXTENT_LAST
+flag set (see the next section on extent flags).
+
+Each extent is described by a single fiemap_extent structure as
+returned in fm_extents.
+
+struct fiemap_extent {
+	__u64	fe_logical;  /* logical offset in bytes for the start of
+			      * the extent */
+	__u64	fe_physical; /* physical offset in bytes for the start
+			      * of the extent */
+	__u64	fe_length;   /* length in bytes for the extent */
+	__u64	fe_reserved64[2];
+	__u32	fe_flags;    /* FIEMAP_EXTENT_* flags for this extent */
+	__u32	fe_reserved[3];
+};
+
+All offsets and lengths are in bytes and mirror those on disk.  It is valid
+for an extents logical offset to start before the request or it's logical
+length to extend past the request.  Unless FIEMAP_EXTENT_NOT_ALIGNED is
+returned, fe_logical, fe_physical, and fe_length will be aligned to the
+block size of the file system.  With the exception of extents flagged as
+FIEMAP_EXTENT_MERGED, adjacent extents will not be merged.
+
+The fe_flags field contains flags which describe the extent returned.
+A special flag, FIEMAP_EXTENT_LAST is always set on the last extent in
+the file so that the process making fiemap calls can determine when no
+more extents are available, without having to call the ioctl again.
+
+Some flags are intentionally vague and will always be set in the
+presence of other more specific flags. This way a program looking for
+a general property does not have to know all existing and future flags
+which imply that property.
+
+For example, if FIEMAP_EXTENT_DATA_INLINE or FIEMAP_EXTENT_DATA_TAIL
+are set, FIEMAP_EXTENT_NOT_ALIGNED will also be set. A program looking
+for inline or tail-packed data can key on the specific flag. Software
+which simply cares not to try operating on non-aligned extents
+however, can just key on FIEMAP_EXTENT_NOT_ALIGNED, and not have to
+worry about all present and future flags which might imply unaligned
+data. Note that the opposite is not true - it would be valid for
+FIEMAP_EXTENT_NOT_ALIGNED to appear alone.
+
+* FIEMAP_EXTENT_LAST
+This is the last extent in the file. A mapping attempt past this
+extent will return nothing.
+
+* FIEMAP_EXTENT_UNKNOWN
+The location of this extent is currently unknown. This may indicate
+the data is stored on an inaccessible volume or that no storage has
+been allocated for the file yet.
+
+* FIEMAP_EXTENT_DELALLOC
+  - This will also set FIEMAP_EXTENT_UNKNOWN.
+Delayed allocation - while there is data for this extent, it's
+physical location has not been allocated yet.
+
+* FIEMAP_EXTENT_ENCODED
+This extent does not consist of plain filesystem blocks but is
+encoded (e.g. encrypted or compressed).  Reading the data in this
+extent via I/O to the block device will have undefined results.
+
+Note that it is *always* undefined to try to update the data
+in-place by writing to the indicated location without the
+assistance of the filesystem, or to access the data using the
+information returned by the FIEMAP interface while the filesystem
+is mounted.  In other words, user applications may only read the
+extent data via I/O to the block device while the filesystem is
+unmounted, and then only if the FIEMAP_EXTENT_ENCODED flag is
+clear; user applications must not try reading or writing to the
+filesystem via the block device under any other circumstances.
+
+* FIEMAP_EXTENT_DATA_ENCRYPTED
+  - This will also set FIEMAP_EXTENT_ENCODED
+The data in this extent has been encrypted by the file system.
+
+* FIEMAP_EXTENT_NOT_ALIGNED
+Extent offsets and length are not guaranteed to be block aligned.
+
+* FIEMAP_EXTENT_DATA_INLINE
+  This will also set FIEMAP_EXTENT_NOT_ALIGNED
+Data is located within a meta data block.
+
+* FIEMAP_EXTENT_DATA_TAIL
+  This will also set FIEMAP_EXTENT_NOT_ALIGNED
+Data is packed into a block with data from other files.
+
+* FIEMAP_EXTENT_UNWRITTEN
+Unwritten extent - the extent is allocated but it's data has not been
+initialized.  This indicates the extent's data will be all zero if read
+through the filesystem but the contents are undefined if read directly from
+the device.
+
+* FIEMAP_EXTENT_MERGED
+This will be set when a file does not support extents, i.e., it uses a block
+based addressing scheme.  Since returning an extent for each block back to
+userspace would be highly inefficient, the kernel will try to merge most
+adjacent blocks into 'extents'.
+
+
+VFS -> File System Implementation
+---------------------------------
+
+File systems wishing to support fiemap must implement a ->fiemap callback on
+their inode_operations structure. The fs ->fiemap call is responsible for
+defining it's set of supported fiemap flags, and calling a helper function on
+each discovered extent:
+
+struct inode_operations {
+       ...
+
+       int (*fiemap)(struct inode *, struct fiemap_extent_info *, u64 start,
+                     u64 len);
+
+->fiemap is passed struct fiemap_extent_info which describes the
+fiemap request:
+
+struct fiemap_extent_info {
+	unsigned int fi_flags;		/* Flags as passed from user */
+	unsigned int fi_extents_mapped;	/* Number of mapped extents */
+	unsigned int fi_extents_max;	/* Size of fiemap_extent array */
+	struct fiemap_extent *fi_extents_start;	/* Start of fiemap_extent array */
+};
+
+It is intended that the file system should not need to access any of this
+structure directly.
+
+
+Flag checking should be done at the beginning of the ->fiemap callback via the
+fiemap_check_flags() helper:
+
+int fiemap_check_flags(struct fiemap_extent_info *fieinfo, u32 fs_flags);
+
+The struct fieinfo should be passed in as recieved from ioctl_fiemap(). The
+set of fiemap flags which the fs understands should be passed via fs_flags. If
+fiemap_check_flags finds invalid user flags, it will place the bad values in
+fieinfo->fi_flags and return -EBADR. If the file system gets -EBADR, from
+fiemap_check_flags(), it should immediately exit, returning that error back to
+ioctl_fiemap().
+
+
+For each extent in the request range, the file system should call
+the helper function, fiemap_fill_next_extent():
+
+int fiemap_fill_next_extent(struct fiemap_extent_info *info, u64 logical,
+			    u64 phys, u64 len, u32 flags, u32 dev);
+
+fiemap_fill_next_extent() will use the passed values to populate the
+next free extent in the fm_extents array. 'General' extent flags will
+automatically be set from specific flags on behalf of the calling file
+system so that the userspace API is not broken.
+
+fiemap_fill_next_extent() returns 0 on success, and 1 when the
+user-supplied fm_extents array is full. If an error is encountered
+while copying the extent to user memory, -EFAULT will be returned.
diff --git a/Documentation/filesystems/ocfs2.txt b/Documentation/filesystems/ocfs2.txt
index c318a8b..4340cc8 100644
--- a/Documentation/filesystems/ocfs2.txt
+++ b/Documentation/filesystems/ocfs2.txt
@@ -76,3 +76,9 @@
 			large, the fs will silently revert it to the default.
 			Localalloc is not enabled for local mounts.
 localflocks		This disables cluster aware flock.
+inode64			Indicates that Ocfs2 is allowed to create inodes at
+			any location in the filesystem, including those which
+			will result in inode numbers occupying more than 32
+			bits of significance.
+user_xattr	(*)	Enables Extended User Attributes.
+nouser_xattr		Disables Extended User Attributes.
diff --git a/Documentation/filesystems/proc.txt b/Documentation/filesystems/proc.txt
index f566ad9..b488eda 100644
--- a/Documentation/filesystems/proc.txt
+++ b/Documentation/filesystems/proc.txt
@@ -923,45 +923,44 @@
 The   "procs_blocked" line gives  the  number of  processes currently blocked,
 waiting for I/O to complete.
 
+
 1.9 Ext4 file system parameters
 ------------------------------
-Ext4 file system have one directory per partition under /proc/fs/ext4/
-# ls /proc/fs/ext4/hdc/
-group_prealloc  max_to_scan  mb_groups  mb_history  min_to_scan  order2_req
-stats  stream_req
 
-mb_groups:
-This file gives the details of multiblock allocator buddy cache of free blocks
+Information about mounted ext4 file systems can be found in
+/proc/fs/ext4.  Each mounted filesystem will have a directory in
+/proc/fs/ext4 based on its device name (i.e., /proc/fs/ext4/hdc or
+/proc/fs/ext4/dm-0).   The files in each per-device directory are shown
+in Table 1-10, below.
 
-mb_history:
-Multiblock allocation history.
+Table 1-10: Files in /proc/fs/ext4/<devname>
+..............................................................................
+ File            Content                                        
+ mb_groups       details of multiblock allocator buddy cache of free blocks
+ mb_history      multiblock allocation history
+ stats           controls whether the multiblock allocator should start
+                 collecting statistics, which are shown during the unmount
+ group_prealloc  the multiblock allocator will round up allocation
+                 requests to a multiple of this tuning parameter if the
+                 stripe size is not set in the ext4 superblock
+ max_to_scan     The maximum number of extents the multiblock allocator
+                 will search to find the best extent
+ min_to_scan     The minimum number of extents the multiblock allocator
+                 will search to find the best extent
+ order2_req      Tuning parameter which controls the minimum size for 
+                 requests (as a power of 2) where the buddy cache is
+                 used
+ stream_req      Files which have fewer blocks than this tunable
+                 parameter will have their blocks allocated out of a
+                 block group specific preallocation pool, so that small
+                 files are packed closely together.  Each large file
+                 will have its blocks allocated out of its own unique
+                 preallocation pool.
+inode_readahead  Tuning parameter which controls the maximum number of
+                 inode table blocks that ext4's inode table readahead
+                 algorithm will pre-read into the buffer cache
+..............................................................................
 
-stats:
-This file indicate whether the multiblock allocator should start collecting
-statistics. The statistics are shown during unmount
-
-group_prealloc:
-The multiblock allocator normalize the block allocation request to
-group_prealloc filesystem blocks if we don't have strip value set.
-The stripe value can be specified at mount time or during mke2fs.
-
-max_to_scan:
-How long multiblock allocator can look for a best extent (in found extents)
-
-min_to_scan:
-How long multiblock allocator  must look for a best extent
-
-order2_req:
-Multiblock allocator use  2^N search using buddies only for requests greater
-than or equal to order2_req. The request size is specfied in file system
-blocks. A value of 2 indicate only if the requests are greater than or equal
-to 4 blocks.
-
-stream_req:
-Files smaller than stream_req are served by the stream allocator, whose
-purpose is to pack requests as close each to other as possible to
-produce smooth I/O traffic. Avalue of 16 indicate that file smaller than 16
-filesystem block size will use group based preallocation.
 
 ------------------------------------------------------------------------------
 Summary
@@ -1332,13 +1331,6 @@
 Because the NMI watchdog shares registers with oprofile, by disabling the NMI
 watchdog, oprofile may have more registers to utilize.
 
-maps_protect
-------------
-
-Enables/Disables the protection of the per-process proc entries "maps" and
-"smaps".  When enabled, the contents of these files are visible only to
-readers that are allowed to ptrace() the given process.
-
 msgmni
 ------
 
diff --git a/Documentation/hpet.txt b/Documentation/hpet.txt
deleted file mode 100644
index 6ad52d9..0000000
--- a/Documentation/hpet.txt
+++ /dev/null
@@ -1,300 +0,0 @@
-		High Precision Event Timer Driver for Linux
-
-The High Precision Event Timer (HPET) hardware is the future replacement
-for the 8254 and Real Time Clock (RTC) periodic timer functionality.
-Each HPET can have up to 32 timers.  It is possible to configure the
-first two timers as legacy replacements for 8254 and RTC periodic timers.
-A specification done by Intel and Microsoft can be found at
-<http://www.intel.com/technology/architecture/hpetspec.htm>.
-
-The driver supports detection of HPET driver allocation and initialization
-of the HPET before the driver module_init routine is called.  This enables
-platform code which uses timer 0 or 1 as the main timer to intercept HPET
-initialization.  An example of this initialization can be found in
-arch/i386/kernel/time_hpet.c.
-
-The driver provides two APIs which are very similar to the API found in
-the rtc.c driver.  There is a user space API and a kernel space API.
-An example user space program is provided below.
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <string.h>
-#include <memory.h>
-#include <malloc.h>
-#include <time.h>
-#include <ctype.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <signal.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <sys/time.h>
-#include <linux/hpet.h>
-
-
-extern void hpet_open_close(int, const char **);
-extern void hpet_info(int, const char **);
-extern void hpet_poll(int, const char **);
-extern void hpet_fasync(int, const char **);
-extern void hpet_read(int, const char **);
-
-#include <sys/poll.h>
-#include <sys/ioctl.h>
-#include <signal.h>
-
-struct hpet_command {
-	char		*command;
-	void		(*func)(int argc, const char ** argv);
-} hpet_command[] = {
-	{
-		"open-close",
-		hpet_open_close
-	},
-	{
-		"info",
-		hpet_info
-	},
-	{
-		"poll",
-		hpet_poll
-	},
-	{
-		"fasync",
-		hpet_fasync
-	},
-};
-
-int
-main(int argc, const char ** argv)
-{
-	int	i;
-
-	argc--;
-	argv++;
-
-	if (!argc) {
-		fprintf(stderr, "-hpet: requires command\n");
-		return -1;
-	}
-
-
-	for (i = 0; i < (sizeof (hpet_command) / sizeof (hpet_command[0])); i++)
-		if (!strcmp(argv[0], hpet_command[i].command)) {
-			argc--;
-			argv++;
-			fprintf(stderr, "-hpet: executing %s\n",
-				hpet_command[i].command);
-			hpet_command[i].func(argc, argv);
-			return 0;
-		}
-
-	fprintf(stderr, "do_hpet: command %s not implemented\n", argv[0]);
-
-	return -1;
-}
-
-void
-hpet_open_close(int argc, const char **argv)
-{
-	int	fd;
-
-	if (argc != 1) {
-		fprintf(stderr, "hpet_open_close: device-name\n");
-		return;
-	}
-
-	fd = open(argv[0], O_RDONLY);
-	if (fd < 0)
-		fprintf(stderr, "hpet_open_close: open failed\n");
-	else
-		close(fd);
-
-	return;
-}
-
-void
-hpet_info(int argc, const char **argv)
-{
-}
-
-void
-hpet_poll(int argc, const char **argv)
-{
-	unsigned long		freq;
-	int			iterations, i, fd;
-	struct pollfd		pfd;
-	struct hpet_info	info;
-	struct timeval		stv, etv;
-	struct timezone		tz;
-	long			usec;
-
-	if (argc != 3) {
-		fprintf(stderr, "hpet_poll: device-name freq iterations\n");
-		return;
-	}
-
-	freq = atoi(argv[1]);
-	iterations = atoi(argv[2]);
-
-	fd = open(argv[0], O_RDONLY);
-
-	if (fd < 0) {
-		fprintf(stderr, "hpet_poll: open of %s failed\n", argv[0]);
-		return;
-	}
-
-	if (ioctl(fd, HPET_IRQFREQ, freq) < 0) {
-		fprintf(stderr, "hpet_poll: HPET_IRQFREQ failed\n");
-		goto out;
-	}
-
-	if (ioctl(fd, HPET_INFO, &info) < 0) {
-		fprintf(stderr, "hpet_poll: failed to get info\n");
-		goto out;
-	}
-
-	fprintf(stderr, "hpet_poll: info.hi_flags 0x%lx\n", info.hi_flags);
-
-	if (info.hi_flags && (ioctl(fd, HPET_EPI, 0) < 0)) {
-		fprintf(stderr, "hpet_poll: HPET_EPI failed\n");
-		goto out;
-	}
-
-	if (ioctl(fd, HPET_IE_ON, 0) < 0) {
-		fprintf(stderr, "hpet_poll, HPET_IE_ON failed\n");
-		goto out;
-	}
-
-	pfd.fd = fd;
-	pfd.events = POLLIN;
-
-	for (i = 0; i < iterations; i++) {
-		pfd.revents = 0;
-		gettimeofday(&stv, &tz);
-		if (poll(&pfd, 1, -1) < 0)
-			fprintf(stderr, "hpet_poll: poll failed\n");
-		else {
-			long 	data;
-
-			gettimeofday(&etv, &tz);
-			usec = stv.tv_sec * 1000000 + stv.tv_usec;
-			usec = (etv.tv_sec * 1000000 + etv.tv_usec) - usec;
-
-			fprintf(stderr,
-				"hpet_poll: expired time = 0x%lx\n", usec);
-
-			fprintf(stderr, "hpet_poll: revents = 0x%x\n",
-				pfd.revents);
-
-			if (read(fd, &data, sizeof(data)) != sizeof(data)) {
-				fprintf(stderr, "hpet_poll: read failed\n");
-			}
-			else
-				fprintf(stderr, "hpet_poll: data 0x%lx\n",
-					data);
-		}
-	}
-
-out:
-	close(fd);
-	return;
-}
-
-static int hpet_sigio_count;
-
-static void
-hpet_sigio(int val)
-{
-	fprintf(stderr, "hpet_sigio: called\n");
-	hpet_sigio_count++;
-}
-
-void
-hpet_fasync(int argc, const char **argv)
-{
-	unsigned long		freq;
-	int			iterations, i, fd, value;
-	sig_t			oldsig;
-	struct hpet_info	info;
-
-	hpet_sigio_count = 0;
-	fd = -1;
-
-	if ((oldsig = signal(SIGIO, hpet_sigio)) == SIG_ERR) {
-		fprintf(stderr, "hpet_fasync: failed to set signal handler\n");
-		return;
-	}
-
-	if (argc != 3) {
-		fprintf(stderr, "hpet_fasync: device-name freq iterations\n");
-		goto out;
-	}
-
-	fd = open(argv[0], O_RDONLY);
-
-	if (fd < 0) {
-		fprintf(stderr, "hpet_fasync: failed to open %s\n", argv[0]);
-		return;
-	}
-
-
-	if ((fcntl(fd, F_SETOWN, getpid()) == 1) ||
-		((value = fcntl(fd, F_GETFL)) == 1) ||
-		(fcntl(fd, F_SETFL, value | O_ASYNC) == 1)) {
-		fprintf(stderr, "hpet_fasync: fcntl failed\n");
-		goto out;
-	}
-
-	freq = atoi(argv[1]);
-	iterations = atoi(argv[2]);
-
-	if (ioctl(fd, HPET_IRQFREQ, freq) < 0) {
-		fprintf(stderr, "hpet_fasync: HPET_IRQFREQ failed\n");
-		goto out;
-	}
-
-	if (ioctl(fd, HPET_INFO, &info) < 0) {
-		fprintf(stderr, "hpet_fasync: failed to get info\n");
-		goto out;
-	}
-
-	fprintf(stderr, "hpet_fasync: info.hi_flags 0x%lx\n", info.hi_flags);
-
-	if (info.hi_flags && (ioctl(fd, HPET_EPI, 0) < 0)) {
-		fprintf(stderr, "hpet_fasync: HPET_EPI failed\n");
-		goto out;
-	}
-
-	if (ioctl(fd, HPET_IE_ON, 0) < 0) {
-		fprintf(stderr, "hpet_fasync, HPET_IE_ON failed\n");
-		goto out;
-	}
-
-	for (i = 0; i < iterations; i++) {
-		(void) pause();
-		fprintf(stderr, "hpet_fasync: count = %d\n", hpet_sigio_count);
-	}
-
-out:
-	signal(SIGIO, oldsig);
-
-	if (fd >= 0)
-		close(fd);
-
-	return;
-}
-
-The kernel API has three interfaces exported from the driver:
-
-	hpet_register(struct hpet_task *tp, int periodic)
-	hpet_unregister(struct hpet_task *tp)
-	hpet_control(struct hpet_task *tp, unsigned int cmd, unsigned long arg)
-
-The kernel module using this interface fills in the ht_func and ht_data
-members of the hpet_task structure before calling hpet_register.
-hpet_control simply vectors to the hpet_ioctl routine and has the same
-commands and respective arguments as the user API.  hpet_unregister
-is used to terminate usage of the HPET timer reserved by hpet_register.
diff --git a/Documentation/hwmon/adt7473 b/Documentation/hwmon/adt7473
index 2126de3..1cbf671 100644
--- a/Documentation/hwmon/adt7473
+++ b/Documentation/hwmon/adt7473
@@ -14,14 +14,14 @@
 
 This driver implements support for the Analog Devices ADT7473 chip family.
 
-The LM85 uses the 2-wire interface compatible with the SMBUS 2.0
+The ADT7473 uses the 2-wire interface compatible with the SMBUS 2.0
 specification. Using an analog to digital converter it measures three (3)
-temperatures and two (2) voltages. It has three (3) 16-bit counters for
+temperatures and two (2) voltages. It has four (4) 16-bit counters for
 measuring fan speed. There are three (3) PWM outputs that can be used
 to control fan speed.
 
 A sophisticated control system for the PWM outputs is designed into the
-LM85 that allows fan speed to be adjusted automatically based on any of the
+ADT7473 that allows fan speed to be adjusted automatically based on any of the
 three temperature sensors. Each PWM output is individually adjustable and
 programmable. Once configured, the ADT7473 will adjust the PWM outputs in
 response to the measured temperatures without further host intervention.
@@ -46,14 +46,6 @@
 The Analog Devices datasheet is very detailed and describes a procedure for
 determining an optimal configuration for the automatic PWM control.
 
-Hardware Configurations
------------------------
-
-The ADT7473 chips have an optional SMBALERT output that can be used to
-signal the chipset in case a limit is exceeded or the temperature sensors
-fail. Individual sensor interrupts can be masked so they won't trigger
-SMBALERT. The SMBALERT output if configured replaces the PWM2 function.
-
 Configuration Notes
 -------------------
 
@@ -61,8 +53,8 @@
 
 * PWM Control
 
-* pwm#_auto_point1_pwm and pwm#_auto_point1_temp and
-* pwm#_auto_point2_pwm and pwm#_auto_point2_temp -
+* pwm#_auto_point1_pwm and temp#_auto_point1_temp and
+* pwm#_auto_point2_pwm and temp#_auto_point2_temp -
 
 point1: Set the pwm speed at a lower temperature bound.
 point2: Set the pwm speed at a higher temperature bound.
diff --git a/Documentation/hwmon/sysfs-interface b/Documentation/hwmon/sysfs-interface
index 2d84573..6dbfd5e 100644
--- a/Documentation/hwmon/sysfs-interface
+++ b/Documentation/hwmon/sysfs-interface
@@ -329,6 +329,10 @@
 				Unit: microWatt
 				RO
 
+power[1-*]_average_interval	Power use averaging interval
+				Unit: milliseconds
+				RW
+
 power[1-*]_average_highest	Historical average maximum power use
 				Unit: microWatt
 				RO
@@ -354,6 +358,14 @@
 				WO
 
 **********
+* Energy *
+**********
+
+energy[1-*]_input		Cumulative energy use
+				Unit: microJoule
+				RO
+
+**********
 * Alarms *
 **********
 
diff --git a/Documentation/i2c/busses/i2c-viapro b/Documentation/i2c/busses/i2c-viapro
index 1405fb6..22efedf 100644
--- a/Documentation/i2c/busses/i2c-viapro
+++ b/Documentation/i2c/busses/i2c-viapro
@@ -16,6 +16,9 @@
   * VIA Technologies, Inc. CX700
     Datasheet: available on request and under NDA from VIA
 
+  * VIA Technologies, Inc. VX800/VX820
+    Datasheet: available on http://linux.via.com.tw
+
 Authors:
 	Kyösti Mälkki <kmalkki@cc.hut.fi>,
 	Mark D. Studebaker <mdsxyz123@yahoo.com>,
@@ -49,6 +52,7 @@
  device 1106:3372   (VT8237S)
  device 1106:3287   (VT8251)
  device 1106:8324   (CX700)
+ device 1106:8353   (VX800/VX820)
 
 If none of these show up, you should look in the BIOS for settings like
 enable ACPI / SMBus or even USB.
@@ -57,5 +61,5 @@
 VT8231), this driver supports I2C block transactions. Such transactions
 are mainly useful to read from and write to EEPROMs.
 
-The CX700 additionally appears to support SMBus PEC, although this driver
-doesn't implement it yet.
+The CX700/VX800/VX820 additionally appears to support SMBus PEC, although
+this driver doesn't implement it yet.
diff --git a/Documentation/i2c/dev-interface b/Documentation/i2c/dev-interface
index 9dd7912..3e742ba 100644
--- a/Documentation/i2c/dev-interface
+++ b/Documentation/i2c/dev-interface
@@ -4,6 +4,10 @@
 
 Each registered i2c adapter gets a number, counting from 0. You can
 examine /sys/class/i2c-dev/ to see what number corresponds to which adapter.
+Alternatively, you can run "i2cdetect -l" to obtain a formated list of all
+i2c adapters present on your system at a given time. i2cdetect is part of
+the i2c-tools package.
+
 I2C device files are character device files with major device number 89
 and a minor device number corresponding to the number assigned as 
 explained above. They should be called "i2c-%d" (i2c-0, i2c-1, ..., 
@@ -17,30 +21,34 @@
 first thing to do is "#include <linux/i2c-dev.h>". Please note that
 there are two files named "i2c-dev.h" out there, one is distributed
 with the Linux kernel and is meant to be included from kernel
-driver code, the other one is distributed with lm_sensors and is
+driver code, the other one is distributed with i2c-tools and is
 meant to be included from user-space programs. You obviously want
 the second one here.
 
 Now, you have to decide which adapter you want to access. You should
-inspect /sys/class/i2c-dev/ to decide this. Adapter numbers are assigned
-somewhat dynamically, so you can not even assume /dev/i2c-0 is the
-first adapter.
+inspect /sys/class/i2c-dev/ or run "i2cdetect -l" to decide this.
+Adapter numbers are assigned somewhat dynamically, so you can not
+assume much about them. They can even change from one boot to the next.
 
 Next thing, open the device file, as follows:
+
   int file;
   int adapter_nr = 2; /* probably dynamically determined */
   char filename[20];
   
-  sprintf(filename,"/dev/i2c-%d",adapter_nr);
-  if ((file = open(filename,O_RDWR)) < 0) {
+  snprintf(filename, 19, "/dev/i2c-%d", adapter_nr);
+  file = open(filename, O_RDWR);
+  if (file < 0) {
     /* ERROR HANDLING; you can check errno to see what went wrong */
     exit(1);
   }
 
 When you have opened the device, you must specify with what device
 address you want to communicate:
+
   int addr = 0x40; /* The I2C address */
-  if (ioctl(file,I2C_SLAVE,addr) < 0) {
+
+  if (ioctl(file, I2C_SLAVE, addr) < 0) {
     /* ERROR HANDLING; you can check errno to see what went wrong */
     exit(1);
   }
@@ -48,31 +56,41 @@
 Well, you are all set up now. You can now use SMBus commands or plain
 I2C to communicate with your device. SMBus commands are preferred if
 the device supports them. Both are illustrated below.
+
   __u8 register = 0x10; /* Device register to access */
   __s32 res;
   char buf[10];
+
   /* Using SMBus commands */
-  res = i2c_smbus_read_word_data(file,register);
+  res = i2c_smbus_read_word_data(file, register);
   if (res < 0) {
     /* ERROR HANDLING: i2c transaction failed */
   } else {
     /* res contains the read word */
   }
+
   /* Using I2C Write, equivalent of 
-           i2c_smbus_write_word_data(file,register,0x6543) */
+     i2c_smbus_write_word_data(file, register, 0x6543) */
   buf[0] = register;
   buf[1] = 0x43;
   buf[2] = 0x65;
-  if ( write(file,buf,3) != 3) {
+  if (write(file, buf, 3) ! =3) {
     /* ERROR HANDLING: i2c transaction failed */
   }
+
   /* Using I2C Read, equivalent of i2c_smbus_read_byte(file) */
-  if (read(file,buf,1) != 1) {
+  if (read(file, buf, 1) != 1) {
     /* ERROR HANDLING: i2c transaction failed */
   } else {
     /* buf[0] contains the read byte */
   }
 
+Note that only a subset of the I2C and SMBus protocols can be achieved by
+the means of read() and write() calls. In particular, so-called combined
+transactions (mixing read and write messages in the same transaction)
+aren't supported. For this reason, this interface is almost never used by
+user-space programs.
+
 IMPORTANT: because of the use of inline functions, you *have* to use
 '-O' or some variation when you compile your program!
 
@@ -80,31 +98,29 @@
 Full interface description
 ==========================
 
-The following IOCTLs are defined and fully supported 
-(see also i2c-dev.h):
+The following IOCTLs are defined:
 
-ioctl(file,I2C_SLAVE,long addr)
+ioctl(file, I2C_SLAVE, long addr)
   Change slave address. The address is passed in the 7 lower bits of the
   argument (except for 10 bit addresses, passed in the 10 lower bits in this
   case).
 
-ioctl(file,I2C_TENBIT,long select)
+ioctl(file, I2C_TENBIT, long select)
   Selects ten bit addresses if select not equals 0, selects normal 7 bit
   addresses if select equals 0. Default 0.  This request is only valid
   if the adapter has I2C_FUNC_10BIT_ADDR.
 
-ioctl(file,I2C_PEC,long select)
+ioctl(file, I2C_PEC, long select)
   Selects SMBus PEC (packet error checking) generation and verification
   if select not equals 0, disables if select equals 0. Default 0.
   Used only for SMBus transactions.  This request only has an effect if the
   the adapter has I2C_FUNC_SMBUS_PEC; it is still safe if not, it just
   doesn't have any effect.
 
-ioctl(file,I2C_FUNCS,unsigned long *funcs)
+ioctl(file, I2C_FUNCS, unsigned long *funcs)
   Gets the adapter functionality and puts it in *funcs.
 
-ioctl(file,I2C_RDWR,struct i2c_rdwr_ioctl_data *msgset)
-
+ioctl(file, I2C_RDWR, struct i2c_rdwr_ioctl_data *msgset)
   Do combined read/write transaction without stop in between.
   Only valid if the adapter has I2C_FUNC_I2C.  The argument is
   a pointer to a
@@ -120,10 +136,9 @@
   The slave address and whether to use ten bit address mode has to be
   set in each message, overriding the values set with the above ioctl's.
 
-
-Other values are NOT supported at this moment, except for I2C_SMBUS,
-which you should never directly call; instead, use the access functions
-below.
+ioctl(file, I2C_SMBUS, struct i2c_smbus_ioctl_data *args)
+  Not meant to be called  directly; instead, use the access functions
+  below.
 
 You can do plain i2c transactions by using read(2) and write(2) calls.
 You do not need to pass the address byte; instead, set it through
@@ -148,7 +163,52 @@
 returns the number of values read. The block buffers need not be longer
 than 32 bytes.
 
-The above functions are all macros, that resolve to calls to the
-i2c_smbus_access function, that on its turn calls a specific ioctl
+The above functions are all inline functions, that resolve to calls to
+the i2c_smbus_access function, that on its turn calls a specific ioctl
 with the data in a specific format. Read the source code if you
 want to know what happens behind the screens.
+
+
+Implementation details
+======================
+
+For the interested, here's the code flow which happens inside the kernel
+when you use the /dev interface to I2C:
+
+1* Your program opens /dev/i2c-N and calls ioctl() on it, as described in
+section "C example" above.
+
+2* These open() and ioctl() calls are handled by the i2c-dev kernel
+driver: see i2c-dev.c:i2cdev_open() and i2c-dev.c:i2cdev_ioctl(),
+respectively. You can think of i2c-dev as a generic I2C chip driver
+that can be programmed from user-space.
+
+3* Some ioctl() calls are for administrative tasks and are handled by
+i2c-dev directly. Examples include I2C_SLAVE (set the address of the
+device you want to access) and I2C_PEC (enable or disable SMBus error
+checking on future transactions.)
+
+4* Other ioctl() calls are converted to in-kernel function calls by
+i2c-dev. Examples include I2C_FUNCS, which queries the I2C adapter
+functionality using i2c.h:i2c_get_functionality(), and I2C_SMBUS, which
+performs an SMBus transaction using i2c-core.c:i2c_smbus_xfer().
+
+The i2c-dev driver is responsible for checking all the parameters that
+come from user-space for validity. After this point, there is no
+difference between these calls that came from user-space through i2c-dev
+and calls that would have been performed by kernel I2C chip drivers
+directly. This means that I2C bus drivers don't need to implement
+anything special to support access from user-space.
+
+5* These i2c-core.c/i2c.h functions are wrappers to the actual
+implementation of your I2C bus driver. Each adapter must declare
+callback functions implementing these standard calls.
+i2c.h:i2c_get_functionality() calls i2c_adapter.algo->functionality(),
+while i2c-core.c:i2c_smbus_xfer() calls either
+adapter.algo->smbus_xfer() if it is implemented, or if not,
+i2c-core.c:i2c_smbus_xfer_emulated() which in turn calls
+i2c_adapter.algo->master_xfer().
+
+After your I2C bus driver has processed these requests, execution runs
+up the call chain, with almost no processing done, except by i2c-dev to
+package the returned data, if any, in suitable format for the ioctl.
diff --git a/Documentation/i2c/smbus-protocol b/Documentation/i2c/smbus-protocol
index 24bfb65d..9df4744 100644
--- a/Documentation/i2c/smbus-protocol
+++ b/Documentation/i2c/smbus-protocol
@@ -109,8 +109,8 @@
 S Addr Wr [A] Comm [A] DataLow [A] DataHigh [A] P
 
 
-SMBus Process Call
-==================
+SMBus Process Call:  i2c_smbus_process_call()
+=============================================
 
 This command selects a device register (through the Comm byte), sends
 16 bits of data to it, and reads 16 bits of data in return.
diff --git a/Documentation/i2c/writing-clients b/Documentation/i2c/writing-clients
index 6b61b3a..d73ee11 100644
--- a/Documentation/i2c/writing-clients
+++ b/Documentation/i2c/writing-clients
@@ -606,6 +606,8 @@
   extern s32 i2c_smbus_read_word_data(struct i2c_client * client, u8 command);
   extern s32 i2c_smbus_write_word_data(struct i2c_client * client,
                                        u8 command, u16 value);
+  extern s32 i2c_smbus_process_call(struct i2c_client *client,
+                                    u8 command, u16 value);
   extern s32 i2c_smbus_read_block_data(struct i2c_client * client,
                                        u8 command, u8 *values);
   extern s32 i2c_smbus_write_block_data(struct i2c_client * client,
@@ -621,8 +623,6 @@
 be added back later if needed:
 
   extern s32 i2c_smbus_write_quick(struct i2c_client * client, u8 value);
-  extern s32 i2c_smbus_process_call(struct i2c_client * client,
-                                    u8 command, u16 value);
   extern s32 i2c_smbus_block_process_call(struct i2c_client *client,
                                           u8 command, u8 length,
                                           u8 *values)
diff --git a/Documentation/ioctl/cdrom.txt b/Documentation/ioctl/cdrom.txt
index 62d4af4..59df81c 100644
--- a/Documentation/ioctl/cdrom.txt
+++ b/Documentation/ioctl/cdrom.txt
@@ -271,14 +271,14 @@
 
 	usage:
 
-	  ioctl(fd, CDROMEJECT, 0);
+	  ioctl(fd, CDROMCLOSETRAY, 0);
 
 	inputs:		none
 
 	outputs:	none
 
 	error returns:
-	  ENOSYS	cd drive not capable of ejecting
+	  ENOSYS	cd drive not capable of closing the tray
 	  EBUSY		other processes are accessing drive, or door is locked
 
 	notes:
diff --git a/Documentation/kernel-doc-nano-HOWTO.txt b/Documentation/kernel-doc-nano-HOWTO.txt
index 0bd3274..c6841ee 100644
--- a/Documentation/kernel-doc-nano-HOWTO.txt
+++ b/Documentation/kernel-doc-nano-HOWTO.txt
@@ -168,10 +168,10 @@
 mkdir $ARGV[0],0777;
 $state = 0;
 while (<STDIN>) {
-    if (/^\.TH \"[^\"]*\" 4 \"([^\"]*)\"/) {
+    if (/^\.TH \"[^\"]*\" 9 \"([^\"]*)\"/) {
 	if ($state == 1) { close OUT }
 	$state = 1;
-	$fn = "$ARGV[0]/$1.4";
+	$fn = "$ARGV[0]/$1.9";
 	print STDERR "Creating $fn\n";
 	open OUT, ">$fn" or die "can't open $fn: $!\n";
 	print OUT $_;
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index 1150444..2443f5b 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -284,6 +284,11 @@
 			isolate - enable device isolation (each device, as far
 			          as possible, will get its own protection
 			          domain)
+			fullflush - enable flushing of IO/TLB entries when
+				    they are unmapped. Otherwise they are
+				    flushed before they will be reused, which
+				    is a lot of faster
+
 	amd_iommu_size= [HW,X86-64]
 			Define the size of the aperture for the AMD IOMMU
 			driver. Possible values are:
@@ -463,12 +468,6 @@
 			Range: 0 - 8192
 			Default: 64
 
-	disable_8254_timer
-	enable_8254_timer
-			[IA32/X86_64] Disable/Enable interrupt 0 timer routing
-			over the 8254 in addition to over the IO-APIC. The
-			kernel tries to set a sensible default.
-
 	hpet=		[X86-32,HPET] option to control HPET usage
 			Format: { enable (default) | disable | force }
 			disable: disable HPET and use PIT instead
@@ -659,11 +658,12 @@
 	earlyprintk=	[X86-32,X86-64,SH,BLACKFIN]
 			earlyprintk=vga
 			earlyprintk=serial[,ttySn[,baudrate]]
+			earlyprintk=dbgp
 
 			Append ",keep" to not disable it when the real console
 			takes over.
 
-			Only vga or serial at a time, not both.
+			Only vga or serial or usb debug port at a time.
 
 			Currently only ttyS0 and ttyS1 are supported.
 
@@ -1020,6 +1020,10 @@
 			(only serial suported for now)
 			Format: <serial_device>[,baud]
 
+	kmac=		[MIPS] korina ethernet MAC address.
+			Configure the RouterBoard 532 series on-chip
+			Ethernet adapter MAC address.
+
 	l2cr=		[PPC]
 
 	l3cr=		[PPC]
@@ -1228,6 +1232,29 @@
 			         or
 			         memmap=0x10000$0x18690000
 
+	memory_corruption_check=0/1 [X86]
+			Some BIOSes seem to corrupt the first 64k of
+			memory when doing things like suspend/resume.
+			Setting this option will scan the memory
+			looking for corruption.  Enabling this will
+			both detect corruption and prevent the kernel
+			from using the memory being corrupted.
+			However, its intended as a diagnostic tool; if
+			repeatable BIOS-originated corruption always
+			affects the same memory, you can use memmap=
+			to prevent the kernel from using that memory.
+
+	memory_corruption_check_size=size [X86]
+			By default it checks for corruption in the low
+			64k, making this memory unavailable for normal
+			use.  Use this parameter to scan for
+			corruption in more or less memory.
+
+	memory_corruption_check_period=seconds [X86]
+			By default it checks for corruption every 60
+			seconds.  Use this parameter to check at some
+			other rate.  0 disables periodic checking.
+
 	memtest=	[KNL,X86] Enable memtest
 			Format: <integer>
 			range: 0,4 : pattern number
@@ -1425,6 +1452,12 @@
 
 	nolapic_timer	[X86-32,APIC] Do not use the local APIC timer.
 
+	nox2apic	[X86-64,APIC] Do not enable x2APIC mode.
+
+	x2apic_phys	[X86-64,APIC] Use x2apic physical mode instead of
+			default x2apic cluster mode on platforms
+			supporting x2apic.
+
 	noltlbs		[PPC] Do not use large page/tlb entries for kernel
 			lowmem mapping on PPC40x.
 
@@ -1882,6 +1915,12 @@
 	shapers=	[NET]
 			Maximal number of shapers.
 
+	show_msr=	[x86] show boot-time MSR settings
+			Format: { <integer> }
+			Show boot-time (BIOS-initialized) MSR settings.
+			The parameter means the number of CPUs to show,
+			for example 1 means boot CPU only.
+
 	sim710=		[SCSI,HW]
 			See header of drivers/scsi/sim710.c.
 
diff --git a/Documentation/laptops/disk-shock-protection.txt b/Documentation/laptops/disk-shock-protection.txt
new file mode 100644
index 0000000..0e6ba26
--- /dev/null
+++ b/Documentation/laptops/disk-shock-protection.txt
@@ -0,0 +1,149 @@
+Hard disk shock protection
+==========================
+
+Author: Elias Oltmanns <eo@nebensachen.de>
+Last modified: 2008-10-03
+
+
+0. Contents
+-----------
+
+1. Intro
+2. The interface
+3. References
+4. CREDITS
+
+
+1. Intro
+--------
+
+ATA/ATAPI-7 specifies the IDLE IMMEDIATE command with unload feature.
+Issuing this command should cause the drive to switch to idle mode and
+unload disk heads. This feature is being used in modern laptops in
+conjunction with accelerometers and appropriate software to implement
+a shock protection facility. The idea is to stop all I/O operations on
+the internal hard drive and park its heads on the ramp when critical
+situations are anticipated. The desire to have such a feature
+available on GNU/Linux systems has been the original motivation to
+implement a generic disk head parking interface in the Linux kernel.
+Please note, however, that other components have to be set up on your
+system in order to get disk shock protection working (see
+section 3. References below for pointers to more information about
+that).
+
+
+2. The interface
+----------------
+
+For each ATA device, the kernel exports the file
+block/*/device/unload_heads in sysfs (here assumed to be mounted under
+/sys). Access to /sys/block/*/device/unload_heads is denied with
+-EOPNOTSUPP if the device does not support the unload feature.
+Otherwise, writing an integer value to this file will take the heads
+of the respective drive off the platter and block all I/O operations
+for the specified number of milliseconds. When the timeout expires and
+no further disk head park request has been issued in the meantime,
+normal operation will be resumed. The maximal value accepted for a
+timeout is 30000 milliseconds. Exceeding this limit will return
+-EOVERFLOW, but heads will be parked anyway and the timeout will be
+set to 30 seconds. However, you can always change a timeout to any
+value between 0 and 30000 by issuing a subsequent head park request
+before the timeout of the previous one has expired. In particular, the
+total timeout can exceed 30 seconds and, more importantly, you can
+cancel a previously set timeout and resume normal operation
+immediately by specifying a timeout of 0. Values below -2 are rejected
+with -EINVAL (see below for the special meaning of -1 and -2). If the
+timeout specified for a recent head park request has not yet expired,
+reading from /sys/block/*/device/unload_heads will report the number
+of milliseconds remaining until normal operation will be resumed;
+otherwise, reading the unload_heads attribute will return 0.
+
+For example, do the following in order to park the heads of drive
+/dev/sda and stop all I/O operations for five seconds:
+
+# echo 5000 > /sys/block/sda/device/unload_heads
+
+A simple
+
+# cat /sys/block/sda/device/unload_heads
+
+will show you how many milliseconds are left before normal operation
+will be resumed.
+
+A word of caution: The fact that the interface operates on a basis of
+milliseconds may raise expectations that cannot be satisfied in
+reality. In fact, the ATA specs clearly state that the time for an
+unload operation to complete is vendor specific. The hint in ATA-7
+that this will typically be within 500 milliseconds apparently has
+been dropped in ATA-8.
+
+There is a technical detail of this implementation that may cause some
+confusion and should be discussed here. When a head park request has
+been issued to a device successfully, all I/O operations on the
+controller port this device is attached to will be deferred. That is
+to say, any other device that may be connected to the same port will
+be affected too. The only exception is that a subsequent head unload
+request to that other device will be executed immediately. Further
+operations on that port will be deferred until the timeout specified
+for either device on the port has expired. As far as PATA (old style
+IDE) configurations are concerned, there can only be two devices
+attached to any single port. In SATA world we have port multipliers
+which means that a user-issued head parking request to one device may
+actually result in stopping I/O to a whole bunch of devices. However,
+since this feature is supposed to be used on laptops and does not seem
+to be very useful in any other environment, there will be mostly one
+device per port. Even if the CD/DVD writer happens to be connected to
+the same port as the hard drive, it generally *should* recover just
+fine from the occasional buffer under-run incurred by a head park
+request to the HD. Actually, when you are using an ide driver rather
+than its libata counterpart (i.e. your disk is called /dev/hda
+instead of /dev/sda), then parking the heads of one drive (drive X)
+will generally not affect the mode of operation of another drive
+(drive Y) on the same port as described above. It is only when a port
+reset is required to recover from an exception on drive Y that further
+I/O operations on that drive (and the reset itself) will be delayed
+until drive X is no longer in the parked state.
+
+Finally, there are some hard drives that only comply with an earlier
+version of the ATA standard than ATA-7, but do support the unload
+feature nonetheless. Unfortunately, there is no safe way Linux can
+detect these devices, so you won't be able to write to the
+unload_heads attribute. If you know that your device really does
+support the unload feature (for instance, because the vendor of your
+laptop or the hard drive itself told you so), then you can tell the
+kernel to enable the usage of this feature for that drive by writing
+the special value -1 to the unload_heads attribute:
+
+# echo -1 > /sys/block/sda/device/unload_heads
+
+will enable the feature for /dev/sda, and giving -2 instead of -1 will
+disable it again.
+
+
+3. References
+-------------
+
+There are several laptops from different vendors featuring shock
+protection capabilities. As manufacturers have refused to support open
+source development of the required software components so far, Linux
+support for shock protection varies considerably between different
+hardware implementations. Ideally, this section should contain a list
+of pointers at different projects aiming at an implementation of shock
+protection on different systems. Unfortunately, I only know of a
+single project which, although still considered experimental, is fit
+for use. Please feel free to add projects that have been the victims
+of my ignorance.
+
+- http://www.thinkwiki.org/wiki/HDAPS
+  See this page for information about Linux support of the hard disk
+  active protection system as implemented in IBM/Lenovo Thinkpads.
+
+
+4. CREDITS
+----------
+
+This implementation of disk head parking has been inspired by a patch
+originally published by Jon Escombe <lists@dresco.co.uk>. My efforts
+to develop an implementation of this feature that is fit to be merged
+into mainline have been aided by various kernel developers, in
+particular by Tejun Heo and Bartlomiej Zolnierkiewicz.
diff --git a/Documentation/mtrr.txt b/Documentation/mtrr.txt
deleted file mode 100644
index c39ac39..0000000
--- a/Documentation/mtrr.txt
+++ /dev/null
@@ -1,305 +0,0 @@
-MTRR (Memory Type Range Register) control
-3 Jun 1999
-Richard Gooch
-<rgooch@atnf.csiro.au>
-
-  On Intel P6 family processors (Pentium Pro, Pentium II and later)
-  the Memory Type Range Registers (MTRRs) may be used to control
-  processor access to memory ranges. This is most useful when you have
-  a video (VGA) card on a PCI or AGP bus. Enabling write-combining
-  allows bus write transfers to be combined into a larger transfer
-  before bursting over the PCI/AGP bus. This can increase performance
-  of image write operations 2.5 times or more.
-
-  The Cyrix 6x86, 6x86MX and M II processors have Address Range
-  Registers (ARRs) which provide a similar functionality to MTRRs. For
-  these, the ARRs are used to emulate the MTRRs.
-
-  The AMD K6-2 (stepping 8 and above) and K6-3 processors have two
-  MTRRs. These are supported.  The AMD Athlon family provide 8 Intel
-  style MTRRs.
-  
-  The Centaur C6 (WinChip) has 8 MCRs, allowing write-combining. These
-  are supported.
-
-  The VIA Cyrix III and VIA C3 CPUs offer 8 Intel style MTRRs.
-
-  The CONFIG_MTRR option creates a /proc/mtrr file which may be used
-  to manipulate your MTRRs. Typically the X server should use
-  this. This should have a reasonably generic interface so that
-  similar control registers on other processors can be easily
-  supported.
-
-
-There are two interfaces to /proc/mtrr: one is an ASCII interface
-which allows you to read and write. The other is an ioctl()
-interface. The ASCII interface is meant for administration. The
-ioctl() interface is meant for C programs (i.e. the X server). The
-interfaces are described below, with sample commands and C code.
-
-===============================================================================
-Reading MTRRs from the shell:
-
-% cat /proc/mtrr
-reg00: base=0x00000000 (   0MB), size= 128MB: write-back, count=1
-reg01: base=0x08000000 ( 128MB), size=  64MB: write-back, count=1
-===============================================================================
-Creating MTRRs from the C-shell:
-# echo "base=0xf8000000 size=0x400000 type=write-combining" >! /proc/mtrr
-or if you use bash:
-# echo "base=0xf8000000 size=0x400000 type=write-combining" >| /proc/mtrr
-
-And the result thereof:
-% cat /proc/mtrr
-reg00: base=0x00000000 (   0MB), size= 128MB: write-back, count=1
-reg01: base=0x08000000 ( 128MB), size=  64MB: write-back, count=1
-reg02: base=0xf8000000 (3968MB), size=   4MB: write-combining, count=1
-
-This is for video RAM at base address 0xf8000000 and size 4 megabytes. To
-find out your base address, you need to look at the output of your X
-server, which tells you where the linear framebuffer address is. A
-typical line that you may get is:
-
-(--) S3: PCI: 968 rev 0, Linear FB @ 0xf8000000
-
-Note that you should only use the value from the X server, as it may
-move the framebuffer base address, so the only value you can trust is
-that reported by the X server.
-
-To find out the size of your framebuffer (what, you don't actually
-know?), the following line will tell you:
-
-(--) S3: videoram:  4096k
-
-That's 4 megabytes, which is 0x400000 bytes (in hexadecimal).
-A patch is being written for XFree86 which will make this automatic:
-in other words the X server will manipulate /proc/mtrr using the
-ioctl() interface, so users won't have to do anything. If you use a
-commercial X server, lobby your vendor to add support for MTRRs.
-===============================================================================
-Creating overlapping MTRRs:
-
-%echo "base=0xfb000000 size=0x1000000 type=write-combining" >/proc/mtrr
-%echo "base=0xfb000000 size=0x1000 type=uncachable" >/proc/mtrr
-
-And the results: cat /proc/mtrr
-reg00: base=0x00000000 (   0MB), size=  64MB: write-back, count=1
-reg01: base=0xfb000000 (4016MB), size=  16MB: write-combining, count=1
-reg02: base=0xfb000000 (4016MB), size=   4kB: uncachable, count=1
-
-Some cards (especially Voodoo Graphics boards) need this 4 kB area 
-excluded from the beginning of the region because it is used for
-registers.
-
-NOTE: You can only create type=uncachable region, if the first
-region that you created is type=write-combining.
-===============================================================================
-Removing MTRRs from the C-shell:
-% echo "disable=2" >! /proc/mtrr
-or using bash:
-% echo "disable=2" >| /proc/mtrr
-===============================================================================
-Reading MTRRs from a C program using ioctl()'s:
-
-/*  mtrr-show.c
-
-    Source file for mtrr-show (example program to show MTRRs using ioctl()'s)
-
-    Copyright (C) 1997-1998  Richard Gooch
-
-    This program is free software; you can redistribute it and/or 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.
-
-    Richard Gooch may be reached by email at  rgooch@atnf.csiro.au
-    The postal address is:
-      Richard Gooch, c/o ATNF, P. O. Box 76, Epping, N.S.W., 2121, Australia.
-*/
-
-/*
-    This program will use an ioctl() on /proc/mtrr to show the current MTRR
-    settings. This is an alternative to reading /proc/mtrr.
-
-
-    Written by      Richard Gooch   17-DEC-1997
-
-    Last updated by Richard Gooch   2-MAY-1998
-
-
-*/
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <sys/ioctl.h>
-#include <errno.h>
-#include <asm/mtrr.h>
-
-#define TRUE 1
-#define FALSE 0
-#define ERRSTRING strerror (errno)
-
-static char *mtrr_strings[MTRR_NUM_TYPES] =
-{
-    "uncachable",               /* 0 */
-    "write-combining",          /* 1 */
-    "?",                        /* 2 */
-    "?",                        /* 3 */
-    "write-through",            /* 4 */
-    "write-protect",            /* 5 */
-    "write-back",               /* 6 */
-};
-
-int main ()
-{
-    int fd;
-    struct mtrr_gentry gentry;
-
-    if ( ( fd = open ("/proc/mtrr", O_RDONLY, 0) ) == -1 )
-    {
-	if (errno == ENOENT)
-	{
-	    fputs ("/proc/mtrr not found: not supported or you don't have a PPro?\n",
-		   stderr);
-	    exit (1);
-	}
-	fprintf (stderr, "Error opening /proc/mtrr\t%s\n", ERRSTRING);
-	exit (2);
-    }
-    for (gentry.regnum = 0; ioctl (fd, MTRRIOC_GET_ENTRY, &gentry) == 0;
-	 ++gentry.regnum)
-    {
-	if (gentry.size < 1)
-	{
-	    fprintf (stderr, "Register: %u disabled\n", gentry.regnum);
-	    continue;
-	}
-	fprintf (stderr, "Register: %u base: 0x%lx size: 0x%lx type: %s\n",
-		 gentry.regnum, gentry.base, gentry.size,
-		 mtrr_strings[gentry.type]);
-    }
-    if (errno == EINVAL) exit (0);
-    fprintf (stderr, "Error doing ioctl(2) on /dev/mtrr\t%s\n", ERRSTRING);
-    exit (3);
-}   /*  End Function main  */
-===============================================================================
-Creating MTRRs from a C programme using ioctl()'s:
-
-/*  mtrr-add.c
-
-    Source file for mtrr-add (example programme to add an MTRRs using ioctl())
-
-    Copyright (C) 1997-1998  Richard Gooch
-
-    This program is free software; you can redistribute it and/or 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.
-
-    Richard Gooch may be reached by email at  rgooch@atnf.csiro.au
-    The postal address is:
-      Richard Gooch, c/o ATNF, P. O. Box 76, Epping, N.S.W., 2121, Australia.
-*/
-
-/*
-    This programme will use an ioctl() on /proc/mtrr to add an entry. The first
-    available mtrr is used. This is an alternative to writing /proc/mtrr.
-
-
-    Written by      Richard Gooch   17-DEC-1997
-
-    Last updated by Richard Gooch   2-MAY-1998
-
-
-*/
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <sys/ioctl.h>
-#include <errno.h>
-#include <asm/mtrr.h>
-
-#define TRUE 1
-#define FALSE 0
-#define ERRSTRING strerror (errno)
-
-static char *mtrr_strings[MTRR_NUM_TYPES] =
-{
-    "uncachable",               /* 0 */
-    "write-combining",          /* 1 */
-    "?",                        /* 2 */
-    "?",                        /* 3 */
-    "write-through",            /* 4 */
-    "write-protect",            /* 5 */
-    "write-back",               /* 6 */
-};
-
-int main (int argc, char **argv)
-{
-    int fd;
-    struct mtrr_sentry sentry;
-
-    if (argc != 4)
-    {
-	fprintf (stderr, "Usage:\tmtrr-add base size type\n");
-	exit (1);
-    }
-    sentry.base = strtoul (argv[1], NULL, 0);
-    sentry.size = strtoul (argv[2], NULL, 0);
-    for (sentry.type = 0; sentry.type < MTRR_NUM_TYPES; ++sentry.type)
-    {
-	if (strcmp (argv[3], mtrr_strings[sentry.type]) == 0) break;
-    }
-    if (sentry.type >= MTRR_NUM_TYPES)
-    {
-	fprintf (stderr, "Illegal type: \"%s\"\n", argv[3]);
-	exit (2);
-    }
-    if ( ( fd = open ("/proc/mtrr", O_WRONLY, 0) ) == -1 )
-    {
-	if (errno == ENOENT)
-	{
-	    fputs ("/proc/mtrr not found: not supported or you don't have a PPro?\n",
-		   stderr);
-	    exit (3);
-	}
-	fprintf (stderr, "Error opening /proc/mtrr\t%s\n", ERRSTRING);
-	exit (4);
-    }
-    if (ioctl (fd, MTRRIOC_ADD_ENTRY, &sentry) == -1)
-    {
-	fprintf (stderr, "Error doing ioctl(2) on /dev/mtrr\t%s\n", ERRSTRING);
-	exit (5);
-    }
-    fprintf (stderr, "Sleeping for 5 seconds so you can see the new entry\n");
-    sleep (5);
-    close (fd);
-    fputs ("I've just closed /proc/mtrr so now the new entry should be gone\n",
-	   stderr);
-}   /*  End Function main  */
-===============================================================================
diff --git a/Documentation/networking/LICENSE.qlge b/Documentation/networking/LICENSE.qlge
new file mode 100644
index 0000000..123b6ed
--- /dev/null
+++ b/Documentation/networking/LICENSE.qlge
@@ -0,0 +1,46 @@
+Copyright (c)  2003-2008 QLogic Corporation
+QLogic Linux Networking HBA Driver
+
+This program includes a device driver for Linux 2.6 that may be
+distributed with QLogic hardware specific firmware binary file.
+You may modify and redistribute the device driver code under the
+GNU General Public License as published by the Free Software
+Foundation (version 2 or a later version).
+
+You may redistribute the hardware specific firmware binary file
+under the following terms:
+
+	1. Redistribution of source code (only if applicable),
+	   must retain the above copyright notice, this list of
+	   conditions and the following disclaimer.
+
+	2. Redistribution in binary form must reproduce the above
+	   copyright notice, this list of conditions and the
+	   following disclaimer in the documentation and/or other
+	   materials provided with the distribution.
+
+	3. The name of QLogic Corporation may not be used to
+	   endorse or promote products derived from this software
+	   without specific prior written permission
+
+REGARDLESS OF WHAT LICENSING MECHANISM IS USED OR APPLICABLE,
+THIS PROGRAM IS PROVIDED BY QLOGIC CORPORATION "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.
+
+USER ACKNOWLEDGES AND AGREES THAT USE OF THIS PROGRAM WILL NOT
+CREATE OR GIVE GROUNDS FOR A LICENSE BY IMPLICATION, ESTOPPEL, OR
+OTHERWISE IN ANY INTELLECTUAL PROPERTY RIGHTS (PATENT, COPYRIGHT,
+TRADE SECRET, MASK WORK, OR OTHER PROPRIETARY RIGHT) EMBODIED IN
+ANY OTHER QLOGIC HARDWARE OR SOFTWARE EITHER SOLELY OR IN
+COMBINATION WITH THIS PROGRAM.
+
diff --git a/Documentation/networking/can.txt b/Documentation/networking/can.txt
index 297ba7b..2035bc4 100644
--- a/Documentation/networking/can.txt
+++ b/Documentation/networking/can.txt
@@ -35,8 +35,9 @@
     6.1 general settings
     6.2 local loopback of sent frames
     6.3 CAN controller hardware filters
-    6.4 currently supported CAN hardware
-    6.5 todo
+    6.4 The virtual CAN driver (vcan)
+    6.5 currently supported CAN hardware
+    6.6 todo
 
   7 Credits
 
@@ -584,7 +585,42 @@
   @133MHz with four SJA1000 CAN controllers from 2002 under heavy bus
   load without any problems ...
 
-  6.4 currently supported CAN hardware (September 2007)
+  6.4 The virtual CAN driver (vcan)
+
+  Similar to the network loopback devices, vcan offers a virtual local
+  CAN interface. A full qualified address on CAN consists of
+
+  - a unique CAN Identifier (CAN ID)
+  - the CAN bus this CAN ID is transmitted on (e.g. can0)
+
+  so in common use cases more than one virtual CAN interface is needed.
+
+  The virtual CAN interfaces allow the transmission and reception of CAN
+  frames without real CAN controller hardware. Virtual CAN network
+  devices are usually named 'vcanX', like vcan0 vcan1 vcan2 ...
+  When compiled as a module the virtual CAN driver module is called vcan.ko
+
+  Since Linux Kernel version 2.6.24 the vcan driver supports the Kernel
+  netlink interface to create vcan network devices. The creation and
+  removal of vcan network devices can be managed with the ip(8) tool:
+
+  - Create a virtual CAN network interface:
+       ip link add type vcan
+
+  - Create a virtual CAN network interface with a specific name 'vcan42':
+       ip link add dev vcan42 type vcan
+
+  - Remove a (virtual CAN) network interface 'vcan42':
+       ip link del vcan42
+
+  The tool 'vcan' from the SocketCAN SVN repository on BerliOS is obsolete.
+
+  Virtual CAN network device creation in older Kernels:
+  In Linux Kernel versions < 2.6.24 the vcan driver creates 4 vcan
+  netdevices at module load time by default. This value can be changed
+  with the module parameter 'numdev'. E.g. 'modprobe vcan numdev=8'
+
+  6.5 currently supported CAN hardware
 
   On the project website http://developer.berlios.de/projects/socketcan
   there are different drivers available:
@@ -603,7 +639,7 @@
 
   Please check the Mailing Lists on the berlios OSS project website.
 
-  6.5 todo (September 2007)
+  6.6 todo
 
   The configuration interface for CAN network drivers is still an open
   issue that has not been finalized in the socketcan project. Also the
diff --git a/Documentation/networking/multiqueue.txt b/Documentation/networking/multiqueue.txt
index d391ea6..4caa0e3 100644
--- a/Documentation/networking/multiqueue.txt
+++ b/Documentation/networking/multiqueue.txt
@@ -24,4 +24,56 @@
 device is still operational.  netdev->queue_lock is still used when the device
 comes online or when it's completely shut down (unregister_netdev(), etc.).
 
-Author: Peter P. Waskiewicz Jr. <peter.p.waskiewicz.jr@intel.com>
+
+Section 2: Qdisc support for multiqueue devices
+
+-----------------------------------------------
+
+Currently two qdiscs are optimized for multiqueue devices.  The first is the
+default pfifo_fast qdisc.  This qdisc supports one qdisc per hardware queue.
+A new round-robin qdisc, sch_multiq also supports multiple hardware queues. The
+qdisc is responsible for classifying the skb's and then directing the skb's to
+bands and queues based on the value in skb->queue_mapping.  Use this field in
+the base driver to determine which queue to send the skb to.
+
+sch_multiq has been added for hardware that wishes to avoid head-of-line
+blocking.  It will cycle though the bands and verify that the hardware queue
+associated with the band is not stopped prior to dequeuing a packet.
+
+On qdisc load, the number of bands is based on the number of queues on the
+hardware.  Once the association is made, any skb with skb->queue_mapping set,
+will be queued to the band associated with the hardware queue.
+
+
+Section 3: Brief howto using MULTIQ for multiqueue devices
+---------------------------------------------------------------
+
+The userspace command 'tc,' part of the iproute2 package, is used to configure
+qdiscs.  To add the MULTIQ qdisc to your network device, assuming the device
+is called eth0, run the following command:
+
+# tc qdisc add dev eth0 root handle 1: multiq
+
+The qdisc will allocate the number of bands to equal the number of queues that
+the device reports, and bring the qdisc online.  Assuming eth0 has 4 Tx
+queues, the band mapping would look like:
+
+band 0 => queue 0
+band 1 => queue 1
+band 2 => queue 2
+band 3 => queue 3
+
+Traffic will begin flowing through each queue based on either the simple_tx_hash
+function or based on netdev->select_queue() if you have it defined.
+
+The behavior of tc filters remains the same.  However a new tc action,
+skbedit, has been added.  Assuming you wanted to route all traffic to a
+specific host, for example 192.168.0.3, through a specific queue you could use
+this action and establish a filter such as:
+
+tc filter add dev eth0 parent 1: protocol ip prio 1 u32 \
+	match ip dst 192.168.0.3 \
+	action skbedit queue_mapping 3
+
+Author: Alexander Duyck <alexander.h.duyck@intel.com>
+Original Author: Peter P. Waskiewicz Jr. <peter.p.waskiewicz.jr@intel.com>
diff --git a/Documentation/networking/phonet.txt b/Documentation/networking/phonet.txt
new file mode 100644
index 0000000..0e6e592
--- /dev/null
+++ b/Documentation/networking/phonet.txt
@@ -0,0 +1,175 @@
+Linux Phonet protocol family
+============================
+
+Introduction
+------------
+
+Phonet is a packet protocol used by Nokia cellular modems for both IPC
+and RPC. With the Linux Phonet socket family, Linux host processes can
+receive and send messages from/to the modem, or any other external
+device attached to the modem. The modem takes care of routing.
+
+Phonet packets can be exchanged through various hardware connections
+depending on the device, such as:
+  - USB with the CDC Phonet interface,
+  - infrared,
+  - Bluetooth,
+  - an RS232 serial port (with a dedicated "FBUS" line discipline),
+  - the SSI bus with some TI OMAP processors.
+
+
+Packets format
+--------------
+
+Phonet packets have a common header as follows:
+
+  struct phonethdr {
+    uint8_t  pn_media;  /* Media type (link-layer identifier) */
+    uint8_t  pn_rdev;   /* Receiver device ID */
+    uint8_t  pn_sdev;   /* Sender device ID */
+    uint8_t  pn_res;    /* Resource ID or function */
+    uint16_t pn_length; /* Big-endian message byte length (minus 6) */
+    uint8_t  pn_robj;   /* Receiver object ID */
+    uint8_t  pn_sobj;   /* Sender object ID */
+  };
+
+On Linux, the link-layer header includes the pn_media byte (see below).
+The next 7 bytes are part of the network-layer header.
+
+The device ID is split: the 6 higher-order bits consitute the device
+address, while the 2 lower-order bits are used for multiplexing, as are
+the 8-bit object identifiers. As such, Phonet can be considered as a
+network layer with 6 bits of address space and 10 bits for transport
+protocol (much like port numbers in IP world).
+
+The modem always has address number zero. All other device have a their
+own 6-bit address.
+
+
+Link layer
+----------
+
+Phonet links are always point-to-point links. The link layer header
+consists of a single Phonet media type byte. It uniquely identifies the
+link through which the packet is transmitted, from the modem's
+perspective. Each Phonet network device shall prepend and set the media
+type byte as appropriate. For convenience, a common phonet_header_ops
+link-layer header operations structure is provided. It sets the
+media type according to the network device hardware address.
+
+Linux Phonet network interfaces support a dedicated link layer packets
+type (ETH_P_PHONET) which is out of the Ethernet type range. They can
+only send and receive Phonet packets.
+
+The virtual TUN tunnel device driver can also be used for Phonet. This
+requires IFF_TUN mode, _without_ the IFF_NO_PI flag. In this case,
+there is no link-layer header, so there is no Phonet media type byte.
+
+Note that Phonet interfaces are not allowed to re-order packets, so
+only the (default) Linux FIFO qdisc should be used with them.
+
+
+Network layer
+-------------
+
+The Phonet socket address family maps the Phonet packet header:
+
+  struct sockaddr_pn {
+    sa_family_t spn_family;    /* AF_PHONET */
+    uint8_t     spn_obj;       /* Object ID */
+    uint8_t     spn_dev;       /* Device ID */
+    uint8_t     spn_resource;  /* Resource or function */
+    uint8_t     spn_zero[...]; /* Padding */
+  };
+
+The resource field is only used when sending and receiving;
+It is ignored by bind() and getsockname().
+
+
+Low-level datagram protocol
+---------------------------
+
+Applications can send Phonet messages using the Phonet datagram socket
+protocol from the PF_PHONET family. Each socket is bound to one of the
+2^10 object IDs available, and can send and receive packets with any
+other peer.
+
+  struct sockaddr_pn addr = { .spn_family = AF_PHONET, };
+  ssize_t len;
+  socklen_t addrlen = sizeof(addr);
+  int fd;
+
+  fd = socket(PF_PHONET, SOCK_DGRAM, 0);
+  bind(fd, (struct sockaddr *)&addr, sizeof(addr));
+  /* ... */
+
+  sendto(fd, msg, msglen, 0, (struct sockaddr *)&addr, sizeof(addr));
+  len = recvfrom(fd, buf, sizeof(buf), 0,
+                 (struct sockaddr *)&addr, &addrlen);
+
+This protocol follows the SOCK_DGRAM connection-less semantics.
+However, connect() and getpeername() are not supported, as they did
+not seem useful with Phonet usages (could be added easily).
+
+
+Phonet Pipe protocol
+--------------------
+
+The Phonet Pipe protocol is a simple sequenced packets protocol
+with end-to-end congestion control. It uses the passive listening
+socket paradigm. The listening socket is bound to an unique free object
+ID. Each listening socket can handle up to 255 simultaneous
+connections, one per accept()'d socket.
+
+  int lfd, cfd;
+
+  lfd = socket(PF_PHONET, SOCK_SEQPACKET, PN_PROTO_PIPE);
+  listen (lfd, INT_MAX);
+
+  /* ... */
+  cfd = accept(lfd, NULL, NULL);
+  for (;;)
+  {
+    char buf[...];
+    ssize_t len = read(cfd, buf, sizeof(buf));
+
+    /* ... */
+
+    write(cfd, msg, msglen);
+  }
+
+Connections are established between two endpoints by a "third party"
+application. This means that both endpoints are passive; so connect()
+is not possible.
+
+WARNING:
+When polling a connected pipe socket for writability, there is an
+intrinsic race condition whereby writability might be lost between the
+polling and the writing system calls. In this case, the socket will
+block until write because possible again, unless non-blocking mode
+becomes enabled.
+
+
+The pipe protocol provides two socket options at the SOL_PNPIPE level:
+
+  PNPIPE_ENCAP accepts one integer value (int) of:
+
+    PNPIPE_ENCAP_NONE: The socket operates normally (default).
+
+    PNPIPE_ENCAP_IP: The socket is used as a backend for a virtual IP
+      interface. This requires CAP_NET_ADMIN capability. GPRS data
+      support on Nokia modems can use this. Note that the socket cannot
+      be reliably poll()'d or read() from while in this mode.
+
+  PNPIPE_IFINDEX is a read-only integer value. It contains the
+    interface index of the network interface created by PNPIPE_ENCAP,
+    or zero if encapsulation is off.
+
+
+Authors
+-------
+
+Linux Phonet was initially written by Sakari Ailus.
+Other contributors include Mikä Liljeberg, Andras Domokos,
+Carlos Chinea and Rémi Denis-Courmont.
+Copyright (C) 2008 Nokia Corporation.
diff --git a/Documentation/networking/regulatory.txt b/Documentation/networking/regulatory.txt
new file mode 100644
index 0000000..a96989a
--- /dev/null
+++ b/Documentation/networking/regulatory.txt
@@ -0,0 +1,194 @@
+Linux wireless regulatory documentation
+---------------------------------------
+
+This document gives a brief review over how the Linux wireless
+regulatory infrastructure works.
+
+More up to date information can be obtained at the project's web page:
+
+http://wireless.kernel.org/en/developers/Regulatory
+
+Keeping regulatory domains in userspace
+---------------------------------------
+
+Due to the dynamic nature of regulatory domains we keep them
+in userspace and provide a framework for userspace to upload
+to the kernel one regulatory domain to be used as the central
+core regulatory domain all wireless devices should adhere to.
+
+How to get regulatory domains to the kernel
+-------------------------------------------
+
+Userspace gets a regulatory domain in the kernel by having
+a userspace agent build it and send it via nl80211. Only
+expected regulatory domains will be respected by the kernel.
+
+A currently available userspace agent which can accomplish this
+is CRDA - central regulatory domain agent. Its documented here:
+
+http://wireless.kernel.org/en/developers/Regulatory/CRDA
+
+Essentially the kernel will send a udev event when it knows
+it needs a new regulatory domain. A udev rule can be put in place
+to trigger crda to send the respective regulatory domain for a
+specific ISO/IEC 3166 alpha2.
+
+Below is an example udev rule which can be used:
+
+# Example file, should be put in /etc/udev/rules.d/regulatory.rules
+KERNEL=="regulatory*", ACTION=="change", SUBSYSTEM=="platform", RUN+="/sbin/crda"
+
+The alpha2 is passed as an environment variable under the variable COUNTRY.
+
+Who asks for regulatory domains?
+--------------------------------
+
+* Users
+
+Users can use iw:
+
+http://wireless.kernel.org/en/users/Documentation/iw
+
+An example:
+
+  # set regulatory domain to "Costa Rica"
+  iw reg set CR
+
+This will request the kernel to set the regulatory domain to
+the specificied alpha2. The kernel in turn will then ask userspace
+to provide a regulatory domain for the alpha2 specified by the user
+by sending a uevent.
+
+* Wireless subsystems for Country Information elements
+
+The kernel will send a uevent to inform userspace a new
+regulatory domain is required. More on this to be added
+as its integration is added.
+
+* Drivers
+
+If drivers determine they need a specific regulatory domain
+set they can inform the wireless core using regulatory_hint().
+They have two options -- they either provide an alpha2 so that
+crda can provide back a regulatory domain for that country or
+they can build their own regulatory domain based on internal
+custom knowledge so the wireless core can respect it.
+
+*Most* drivers will rely on the first mechanism of providing a
+regulatory hint with an alpha2. For these drivers there is an additional
+check that can be used to ensure compliance based on custom EEPROM
+regulatory data. This additional check can be used by drivers by
+registering on its struct wiphy a reg_notifier() callback. This notifier
+is called when the core's regulatory domain has been changed. The driver
+can use this to review the changes made and also review who made them
+(driver, user, country IE) and determine what to allow based on its
+internal EEPROM data. Devices drivers wishing to be capable of world
+roaming should use this callback. More on world roaming will be
+added to this document when its support is enabled.
+
+Device drivers who provide their own built regulatory domain
+do not need a callback as the channels registered by them are
+the only ones that will be allowed and therefore *additional*
+cannels cannot be enabled.
+
+Example code - drivers hinting an alpha2:
+------------------------------------------
+
+This example comes from the zd1211rw device driver. You can start
+by having a mapping of your device's EEPROM country/regulatory
+domain value to to a specific alpha2 as follows:
+
+static struct zd_reg_alpha2_map reg_alpha2_map[] = {
+	{ ZD_REGDOMAIN_FCC, "US" },
+	{ ZD_REGDOMAIN_IC, "CA" },
+	{ ZD_REGDOMAIN_ETSI, "DE" }, /* Generic ETSI, use most restrictive */
+	{ ZD_REGDOMAIN_JAPAN, "JP" },
+	{ ZD_REGDOMAIN_JAPAN_ADD, "JP" },
+	{ ZD_REGDOMAIN_SPAIN, "ES" },
+	{ ZD_REGDOMAIN_FRANCE, "FR" },
+
+Then you can define a routine to map your read EEPROM value to an alpha2,
+as follows:
+
+static int zd_reg2alpha2(u8 regdomain, char *alpha2)
+{
+	unsigned int i;
+	struct zd_reg_alpha2_map *reg_map;
+		for (i = 0; i < ARRAY_SIZE(reg_alpha2_map); i++) {
+			reg_map = &reg_alpha2_map[i];
+			if (regdomain == reg_map->reg) {
+			alpha2[0] = reg_map->alpha2[0];
+			alpha2[1] = reg_map->alpha2[1];
+			return 0;
+		}
+	}
+	return 1;
+}
+
+Lastly, you can then hint to the core of your discovered alpha2, if a match
+was found. You need to do this after you have registered your wiphy. You
+are expected to do this during initialization.
+
+	r = zd_reg2alpha2(mac->regdomain, alpha2);
+	if (!r)
+		regulatory_hint(hw->wiphy, alpha2, NULL);
+
+Example code - drivers providing a built in regulatory domain:
+--------------------------------------------------------------
+
+If you have regulatory information you can obtain from your
+driver and you *need* to use this we let you build a regulatory domain
+structure and pass it to the wireless core. To do this you should
+kmalloc() a structure big enough to hold your regulatory domain
+structure and you should then fill it with your data. Finally you simply
+call regulatory_hint() with the regulatory domain structure in it.
+
+Bellow is a simple example, with a regulatory domain cached using the stack.
+Your implementation may vary (read EEPROM cache instead, for example).
+
+Example cache of some regulatory domain
+
+struct ieee80211_regdomain mydriver_jp_regdom = {
+	.n_reg_rules = 3,
+	.alpha2 =  "JP",
+	//.alpha2 =  "99", /* If I have no alpha2 to map it to */
+	.reg_rules = {
+		/* IEEE 802.11b/g, channels 1..14 */
+		REG_RULE(2412-20, 2484+20, 40, 6, 20, 0),
+		/* IEEE 802.11a, channels 34..48 */
+		REG_RULE(5170-20, 5240+20, 40, 6, 20,
+			NL80211_RRF_PASSIVE_SCAN),
+		/* IEEE 802.11a, channels 52..64 */
+		REG_RULE(5260-20, 5320+20, 40, 6, 20,
+			NL80211_RRF_NO_IBSS |
+			NL80211_RRF_DFS),
+	}
+};
+
+Then in some part of your code after your wiphy has been registered:
+
+	int r;
+	struct ieee80211_regdomain *rd;
+	int size_of_regd;
+	int num_rules = mydriver_jp_regdom.n_reg_rules;
+	unsigned int i;
+
+	size_of_regd = sizeof(struct ieee80211_regdomain) +
+		(num_rules * sizeof(struct ieee80211_reg_rule));
+
+	rd = kzalloc(size_of_regd, GFP_KERNEL);
+	if (!rd)
+	return -ENOMEM;
+
+	memcpy(rd, &mydriver_jp_regdom, sizeof(struct ieee80211_regdomain));
+
+	for (i=0; i < num_rules; i++) {
+		memcpy(&rd->reg_rules[i], &mydriver_jp_regdom.reg_rules[i],
+			sizeof(struct ieee80211_reg_rule));
+	}
+	r = regulatory_hint(hw->wiphy, NULL, rd);
+	if (r) {
+		kfree(rd);
+		return r;
+	}
+
diff --git a/Documentation/networking/tproxy.txt b/Documentation/networking/tproxy.txt
new file mode 100644
index 0000000..7b5996d
--- /dev/null
+++ b/Documentation/networking/tproxy.txt
@@ -0,0 +1,85 @@
+Transparent proxy support
+=========================
+
+This feature adds Linux 2.2-like transparent proxy support to current kernels.
+To use it, enable NETFILTER_TPROXY, the socket match and the TPROXY target in
+your kernel config. You will need policy routing too, so be sure to enable that
+as well.
+
+
+1. Making non-local sockets work
+================================
+
+The idea is that you identify packets with destination address matching a local
+socket on your box, set the packet mark to a certain value, and then match on that
+value using policy routing to have those packets delivered locally:
+
+# iptables -t mangle -N DIVERT
+# iptables -t mangle -A PREROUTING -p tcp -m socket -j DIVERT
+# iptables -t mangle -A DIVERT -j MARK --set-mark 1
+# iptables -t mangle -A DIVERT -j ACCEPT
+
+# ip rule add fwmark 1 lookup 100
+# ip route add local 0.0.0.0/0 dev lo table 100
+
+Because of certain restrictions in the IPv4 routing output code you'll have to
+modify your application to allow it to send datagrams _from_ non-local IP
+addresses. All you have to do is enable the (SOL_IP, IP_TRANSPARENT) socket
+option before calling bind:
+
+fd = socket(AF_INET, SOCK_STREAM, 0);
+/* - 8< -*/
+int value = 1;
+setsockopt(fd, SOL_IP, IP_TRANSPARENT, &value, sizeof(value));
+/* - 8< -*/
+name.sin_family = AF_INET;
+name.sin_port = htons(0xCAFE);
+name.sin_addr.s_addr = htonl(0xDEADBEEF);
+bind(fd, &name, sizeof(name));
+
+A trivial patch for netcat is available here:
+http://people.netfilter.org/hidden/tproxy/netcat-ip_transparent-support.patch
+
+
+2. Redirecting traffic
+======================
+
+Transparent proxying often involves "intercepting" traffic on a router. This is
+usually done with the iptables REDIRECT target; however, there are serious
+limitations of that method. One of the major issues is that it actually
+modifies the packets to change the destination address -- which might not be
+acceptable in certain situations. (Think of proxying UDP for example: you won't
+be able to find out the original destination address. Even in case of TCP
+getting the original destination address is racy.)
+
+The 'TPROXY' target provides similar functionality without relying on NAT. Simply
+add rules like this to the iptables ruleset above:
+
+# iptables -t mangle -A PREROUTING -p tcp --dport 80 -j TPROXY \
+  --tproxy-mark 0x1/0x1 --on-port 50080
+
+Note that for this to work you'll have to modify the proxy to enable (SOL_IP,
+IP_TRANSPARENT) for the listening socket.
+
+
+3. Iptables extensions
+======================
+
+To use tproxy you'll need to have the 'socket' and 'TPROXY' modules
+compiled for iptables. A patched version of iptables is available
+here: http://git.balabit.hu/?p=bazsi/iptables-tproxy.git
+
+
+4. Application support
+======================
+
+4.1. Squid
+----------
+
+Squid 3.HEAD has support built-in. To use it, pass
+'--enable-linux-netfilter' to configure and set the 'tproxy' option on
+the HTTP listener you redirect traffic to with the TPROXY iptables
+target.
+
+For more information please consult the following page on the Squid
+wiki: http://wiki.squid-cache.org/Features/Tproxy4
diff --git a/Documentation/pcmcia/driver-changes.txt b/Documentation/pcmcia/driver-changes.txt
index 96f155e..0599343 100644
--- a/Documentation/pcmcia/driver-changes.txt
+++ b/Documentation/pcmcia/driver-changes.txt
@@ -1,5 +1,11 @@
 This file details changes in 2.6 which affect PCMCIA card driver authors:
 
+* New configuration loop helper (as of 2.6.28)
+   By calling pcmcia_loop_config(), a driver can iterate over all available
+   configuration options. During a driver's probe() phase, one doesn't need
+   to use pcmcia_get_{first,next}_tuple, pcmcia_get_tuple_data and
+   pcmcia_parse_tuple directly in most if not all cases.
+
 * New release helper (as of 2.6.17)
    Instead of calling pcmcia_release_{configuration,io,irq,win}, all that's
    necessary now is calling pcmcia_disable_device. As there is no valid
diff --git a/Documentation/power/regulator/machine.txt b/Documentation/power/regulator/machine.txt
index c9a3566..ce3487d 100644
--- a/Documentation/power/regulator/machine.txt
+++ b/Documentation/power/regulator/machine.txt
@@ -2,17 +2,8 @@
 ===================================
 
 The regulator machine driver interface is intended for board/machine specific
-initialisation code to configure the regulator subsystem. Typical things that
-machine drivers would do are :-
+initialisation code to configure the regulator subsystem.
 
- 1. Regulator -> Device mapping.
- 2. Regulator supply configuration.
- 3. Power Domain constraint setting.
-
-
-
-1. Regulator -> device mapping
-==============================
 Consider the following machine :-
 
   Regulator-1 -+-> Regulator-2 --> [Consumer A @ 1.8 - 2.0V]
@@ -21,81 +12,82 @@
 
 The drivers for consumers A & B must be mapped to the correct regulator in
 order to control their power supply. This mapping can be achieved in machine
-initialisation code by calling :-
+initialisation code by creating a struct regulator_consumer_supply for
+each regulator.
 
-int regulator_set_device_supply(const char *regulator, struct device *dev,
-				const char *supply);
+struct regulator_consumer_supply {
+	struct device *dev;	/* consumer */
+	const char *supply;	/* consumer supply - e.g. "vcc" */
+};
 
-and is shown with the following code :-
+e.g. for the machine above
 
-regulator_set_device_supply("Regulator-1", devB, "Vcc");
-regulator_set_device_supply("Regulator-2", devA, "Vcc");
+static struct regulator_consumer_supply regulator1_consumers[] = {
+{
+	.dev	= &platform_consumerB_device.dev,
+	.supply	= "Vcc",
+},};
+
+static struct regulator_consumer_supply regulator2_consumers[] = {
+{
+	.dev	= &platform_consumerA_device.dev,
+	.supply	= "Vcc",
+},};
 
 This maps Regulator-1 to the 'Vcc' supply for Consumer B and maps Regulator-2
 to the 'Vcc' supply for Consumer A.
 
+Constraints can now be registered by defining a struct regulator_init_data
+for each regulator power domain. This structure also maps the consumers
+to their supply regulator :-
 
-2. Regulator supply configuration.
-==================================
-Consider the following machine (again) :-
-
-  Regulator-1 -+-> Regulator-2 --> [Consumer A @ 1.8 - 2.0V]
-               |
-               +-> [Consumer B @ 3.3V]
+static struct regulator_init_data regulator1_data = {
+	.constraints = {
+		.min_uV = 3300000,
+		.max_uV = 3300000,
+		.valid_modes_mask = REGULATOR_MODE_NORMAL,
+	},
+	.num_consumer_supplies = ARRAY_SIZE(regulator1_consumers),
+	.consumer_supplies = regulator1_consumers,
+};
 
 Regulator-1 supplies power to Regulator-2. This relationship must be registered
 with the core so that Regulator-1 is also enabled when Consumer A enables it's
-supply (Regulator-2).
+supply (Regulator-2). The supply regulator is set by the supply_regulator_dev
+field below:-
 
-This relationship can be register with the core via :-
-
-int regulator_set_supply(const char *regulator, const char *regulator_supply);
-
-In this example we would use the following code :-
-
-regulator_set_supply("Regulator-2", "Regulator-1");
-
-Relationships can be queried by calling :-
-
-const char *regulator_get_supply(const char *regulator);
-
-
-3. Power Domain constraint setting.
-===================================
-Each power domain within a system has physical constraints on voltage and
-current. This must be defined in software so that the power domain is always
-operated within specifications.
-
-Consider the following machine (again) :-
-
-  Regulator-1 -+-> Regulator-2 --> [Consumer A @ 1.8 - 2.0V]
-               |
-               +-> [Consumer B @ 3.3V]
-
-This gives us two regulators and two power domains:
-
-                   Domain 1: Regulator-2, Consumer B.
-                   Domain 2: Consumer A.
-
-Constraints can be registered by calling :-
-
-int regulator_set_platform_constraints(const char *regulator,
-	struct regulation_constraints *constraints);
-
-The example is defined as follows :-
-
-struct regulation_constraints domain_1 = {
-	.min_uV = 3300000,
-	.max_uV = 3300000,
-	.valid_modes_mask = REGULATOR_MODE_NORMAL,
+static struct regulator_init_data regulator2_data = {
+	.supply_regulator_dev = &platform_regulator1_device.dev,
+	.constraints = {
+		.min_uV = 1800000,
+		.max_uV = 2000000,
+		.valid_ops_mask = REGULATOR_CHANGE_VOLTAGE,
+		.valid_modes_mask = REGULATOR_MODE_NORMAL,
+	},
+	.num_consumer_supplies = ARRAY_SIZE(regulator2_consumers),
+	.consumer_supplies = regulator2_consumers,
 };
 
-struct regulation_constraints domain_2 = {
-	.min_uV = 1800000,
-	.max_uV = 2000000,
-	.valid_ops_mask = REGULATOR_CHANGE_VOLTAGE,
-	.valid_modes_mask = REGULATOR_MODE_NORMAL,
-};
+Finally the regulator devices must be registered in the usual manner.
 
-regulator_set_platform_constraints("Regulator-1", &domain_1);
-regulator_set_platform_constraints("Regulator-2", &domain_2);
+static struct platform_device regulator_devices[] = {
+{
+	.name = "regulator",
+	.id = DCDC_1,
+	.dev = {
+		.platform_data = &regulator1_data,
+	},
+},
+{
+	.name = "regulator",
+	.id = DCDC_2,
+	.dev = {
+		.platform_data = &regulator2_data,
+	},
+},
+};
+/* register regulator 1 device */
+platform_device_register(&wm8350_regulator_devices[0]);
+
+/* register regulator 2 device */
+platform_device_register(&wm8350_regulator_devices[1]);
diff --git a/Documentation/power/regulator/regulator.txt b/Documentation/power/regulator/regulator.txt
index a690501..4200acc 100644
--- a/Documentation/power/regulator/regulator.txt
+++ b/Documentation/power/regulator/regulator.txt
@@ -10,11 +10,11 @@
 
 Drivers can register a regulator by calling :-
 
-struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc,
-					  void *reg_data);
+struct regulator_dev *regulator_register(struct device *dev,
+	struct regulator_desc *regulator_desc);
 
-This will register the regulators capabilities and operations the regulator
-core. The core does not touch reg_data (private to regulator driver).
+This will register the regulators capabilities and operations to the regulator
+core.
 
 Regulators can be unregistered by calling :-
 
diff --git a/Documentation/rfkill.txt b/Documentation/rfkill.txt
index 6fcb306..b65f079 100644
--- a/Documentation/rfkill.txt
+++ b/Documentation/rfkill.txt
@@ -341,6 +341,8 @@
 3.1 Guidelines for wireless device drivers
 ------------------------------------------
 
+(in this text, rfkill->foo means the foo field of struct rfkill).
+
 1. Each independent transmitter in a wireless device (usually there is only one
 transmitter per device) should have a SINGLE rfkill class attached to it.
 
@@ -363,10 +365,32 @@
 when possible) the overall transmitter rfkill state, not of a particular rfkill
 line.
 
-5. During suspend, the rfkill class will attempt to soft-block the radio
-through a call to rfkill->toggle_radio, and will try to restore its previous
-state during resume.  After a rfkill class is suspended, it will *not* call
-rfkill->toggle_radio until it is resumed.
+5. The wireless device driver MUST NOT leave the transmitter enabled during
+suspend and hibernation unless:
+
+	5.1. The transmitter has to be enabled for some sort of functionality
+	like wake-on-wireless-packet or autonomous packed forwarding in a mesh
+	network, and that functionality is enabled for this suspend/hibernation
+	cycle.
+
+AND
+
+	5.2. The device was not on a user-requested BLOCKED state before
+	the suspend (i.e. the driver must NOT unblock a device, not even
+	to support wake-on-wireless-packet or remain in the mesh).
+
+In other words, there is absolutely no allowed scenario where a driver can
+automatically take action to unblock a rfkill controller (obviously, this deals
+with scenarios where soft-blocking or both soft and hard blocking is happening.
+Scenarios where hardware rfkill lines are the only ones blocking the
+transmitter are outside of this rule, since the wireless device driver does not
+control its input hardware rfkill lines in the first place).
+
+6. During resume, rfkill will try to restore its previous state.
+
+7. After a rfkill class is suspended, it will *not* call rfkill->toggle_radio
+until it is resumed.
+
 
 Example of a WLAN wireless driver connected to the rfkill subsystem:
 --------------------------------------------------------------------
diff --git a/Documentation/s390/CommonIO b/Documentation/s390/CommonIO
index bf0baa1..339207d 100644
--- a/Documentation/s390/CommonIO
+++ b/Documentation/s390/CommonIO
@@ -70,13 +70,19 @@
 
   Note: While already known devices can be added to the list of devices to be
         ignored, there will be no effect on then. However, if such a device
-	disappears and then reappears, it will then be ignored.
+	disappears and then reappears, it will then be ignored. To make
+	known devices go away, you need the "purge" command (see below).
 
   For example,
 	"echo add 0.0.a000-0.0.accc, 0.0.af00-0.0.afff > /proc/cio_ignore"
   will add 0.0.a000-0.0.accc and 0.0.af00-0.0.afff to the list of ignored
   devices.
 
+  You can remove already known but now ignored devices via
+	"echo purge > /proc/cio_ignore"
+  All devices ignored but still registered and not online (= not in use)
+  will be deregistered and thus removed from the system.
+
   The devices can be specified either by bus id (0.x.abcd) or, for 2.4 backward
   compatibility, by the device number in hexadecimal (0xabcd or abcd). Device
   numbers given as 0xabcd will be interpreted as 0.0.abcd.
@@ -98,8 +104,7 @@
     handling).
 
   - /sys/kernel/debug/s390dbf/cio_msg/sprintf
-    Various debug messages from the common I/O-layer, including messages
-    printed when cio_msg=yes.
+    Various debug messages from the common I/O-layer.
 
   - /sys/kernel/debug/s390dbf/cio_trace/hex_ascii
     Logs the calling of functions in the common I/O-layer and, if applicable, 
diff --git a/Documentation/scheduler/sched-design-CFS.txt b/Documentation/scheduler/sched-design-CFS.txt
index 88bcb87..9d8eb55 100644
--- a/Documentation/scheduler/sched-design-CFS.txt
+++ b/Documentation/scheduler/sched-design-CFS.txt
@@ -1,151 +1,242 @@
-
-This is the CFS scheduler.
-
-80% of CFS's design can be summed up in a single sentence: CFS basically
-models an "ideal, precise multi-tasking CPU" on real hardware.
-
-"Ideal multi-tasking CPU" is a (non-existent  :-))  CPU that has 100%
-physical power and which can run each task at precise equal speed, in
-parallel, each at 1/nr_running speed. For example: if there are 2 tasks
-running then it runs each at 50% physical power - totally in parallel.
-
-On real hardware, we can run only a single task at once, so while that
-one task runs, the other tasks that are waiting for the CPU are at a
-disadvantage - the current task gets an unfair amount of CPU time. In
-CFS this fairness imbalance is expressed and tracked via the per-task
-p->wait_runtime (nanosec-unit) value. "wait_runtime" is the amount of
-time the task should now run on the CPU for it to become completely fair
-and balanced.
-
-( small detail: on 'ideal' hardware, the p->wait_runtime value would
-  always be zero - no task would ever get 'out of balance' from the
-  'ideal' share of CPU time. )
-
-CFS's task picking logic is based on this p->wait_runtime value and it
-is thus very simple: it always tries to run the task with the largest
-p->wait_runtime value. In other words, CFS tries to run the task with
-the 'gravest need' for more CPU time. So CFS always tries to split up
-CPU time between runnable tasks as close to 'ideal multitasking
-hardware' as possible.
-
-Most of the rest of CFS's design just falls out of this really simple
-concept, with a few add-on embellishments like nice levels,
-multiprocessing and various algorithm variants to recognize sleepers.
-
-In practice it works like this: the system runs a task a bit, and when
-the task schedules (or a scheduler tick happens) the task's CPU usage is
-'accounted for': the (small) time it just spent using the physical CPU
-is deducted from p->wait_runtime. [minus the 'fair share' it would have
-gotten anyway]. Once p->wait_runtime gets low enough so that another
-task becomes the 'leftmost task' of the time-ordered rbtree it maintains
-(plus a small amount of 'granularity' distance relative to the leftmost
-task so that we do not over-schedule tasks and trash the cache) then the
-new leftmost task is picked and the current task is preempted.
-
-The rq->fair_clock value tracks the 'CPU time a runnable task would have
-fairly gotten, had it been runnable during that time'. So by using
-rq->fair_clock values we can accurately timestamp and measure the
-'expected CPU time' a task should have gotten. All runnable tasks are
-sorted in the rbtree by the "rq->fair_clock - p->wait_runtime" key, and
-CFS picks the 'leftmost' task and sticks to it. As the system progresses
-forwards, newly woken tasks are put into the tree more and more to the
-right - slowly but surely giving a chance for every task to become the
-'leftmost task' and thus get on the CPU within a deterministic amount of
-time.
-
-Some implementation details:
-
- - the introduction of Scheduling Classes: an extensible hierarchy of
-   scheduler modules. These modules encapsulate scheduling policy
-   details and are handled by the scheduler core without the core
-   code assuming about them too much.
-
- - sched_fair.c implements the 'CFS desktop scheduler': it is a
-   replacement for the vanilla scheduler's SCHED_OTHER interactivity
-   code.
-
-   I'd like to give credit to Con Kolivas for the general approach here:
-   he has proven via RSDL/SD that 'fair scheduling' is possible and that
-   it results in better desktop scheduling. Kudos Con!
-
-   The CFS patch uses a completely different approach and implementation
-   from RSDL/SD. My goal was to make CFS's interactivity quality exceed
-   that of RSDL/SD, which is a high standard to meet :-) Testing
-   feedback is welcome to decide this one way or another. [ and, in any
-   case, all of SD's logic could be added via a kernel/sched_sd.c module
-   as well, if Con is interested in such an approach. ]
-
-   CFS's design is quite radical: it does not use runqueues, it uses a
-   time-ordered rbtree to build a 'timeline' of future task execution,
-   and thus has no 'array switch' artifacts (by which both the vanilla
-   scheduler and RSDL/SD are affected).
-
-   CFS uses nanosecond granularity accounting and does not rely on any
-   jiffies or other HZ detail. Thus the CFS scheduler has no notion of
-   'timeslices' and has no heuristics whatsoever. There is only one
-   central tunable (you have to switch on CONFIG_SCHED_DEBUG):
-
-         /proc/sys/kernel/sched_granularity_ns
-
-   which can be used to tune the scheduler from 'desktop' (low
-   latencies) to 'server' (good batching) workloads. It defaults to a
-   setting suitable for desktop workloads. SCHED_BATCH is handled by the
-   CFS scheduler module too.
-
-   Due to its design, the CFS scheduler is not prone to any of the
-   'attacks' that exist today against the heuristics of the stock
-   scheduler: fiftyp.c, thud.c, chew.c, ring-test.c, massive_intr.c all
-   work fine and do not impact interactivity and produce the expected
-   behavior.
-
-   the CFS scheduler has a much stronger handling of nice levels and
-   SCHED_BATCH: both types of workloads should be isolated much more
-   agressively than under the vanilla scheduler.
-
-   ( another detail: due to nanosec accounting and timeline sorting,
-     sched_yield() support is very simple under CFS, and in fact under
-     CFS sched_yield() behaves much better than under any other
-     scheduler i have tested so far. )
-
- - sched_rt.c implements SCHED_FIFO and SCHED_RR semantics, in a simpler
-   way than the vanilla scheduler does. It uses 100 runqueues (for all
-   100 RT priority levels, instead of 140 in the vanilla scheduler)
-   and it needs no expired array.
-
- - reworked/sanitized SMP load-balancing: the runqueue-walking
-   assumptions are gone from the load-balancing code now, and
-   iterators of the scheduling modules are used. The balancing code got
-   quite a bit simpler as a result.
+                      =============
+                      CFS Scheduler
+                      =============
 
 
-Group scheduler extension to CFS
-================================
+1.  OVERVIEW
 
-Normally the scheduler operates on individual tasks and strives to provide
-fair CPU time to each task. Sometimes, it may be desirable to group tasks
-and provide fair CPU time to each such task group. For example, it may
-be desirable to first provide fair CPU time to each user on the system
-and then to each task belonging to a user.
+CFS stands for "Completely Fair Scheduler," and is the new "desktop" process
+scheduler implemented by Ingo Molnar and merged in Linux 2.6.23.  It is the
+replacement for the previous vanilla scheduler's SCHED_OTHER interactivity
+code.
 
-CONFIG_FAIR_GROUP_SCHED strives to achieve exactly that. It lets
-SCHED_NORMAL/BATCH tasks be be grouped and divides CPU time fairly among such
-groups. At present, there are two (mutually exclusive) mechanisms to group
-tasks for CPU bandwidth control purpose:
+80% of CFS's design can be summed up in a single sentence: CFS basically models
+an "ideal, precise multi-tasking CPU" on real hardware.
 
-	- Based on user id (CONFIG_FAIR_USER_SCHED)
-		In this option, tasks are grouped according to their user id.
-	- Based on "cgroup" pseudo filesystem (CONFIG_FAIR_CGROUP_SCHED)
-		This options lets the administrator create arbitrary groups
-		of tasks, using the "cgroup" pseudo filesystem. See
-		Documentation/cgroups.txt for more information about this
-		filesystem.
+"Ideal multi-tasking CPU" is a (non-existent  :-)) CPU that has 100% physical
+power and which can run each task at precise equal speed, in parallel, each at
+1/nr_running speed.  For example: if there are 2 tasks running, then it runs
+each at 50% physical power --- i.e., actually in parallel.
+
+On real hardware, we can run only a single task at once, so we have to
+introduce the concept of "virtual runtime."  The virtual runtime of a task
+specifies when its next timeslice would start execution on the ideal
+multi-tasking CPU described above.  In practice, the virtual runtime of a task
+is its actual runtime normalized to the total number of running tasks.
+
+
+
+2.  FEW IMPLEMENTATION DETAILS
+
+In CFS the virtual runtime is expressed and tracked via the per-task
+p->se.vruntime (nanosec-unit) value.  This way, it's possible to accurately
+timestamp and measure the "expected CPU time" a task should have gotten.
+
+[ small detail: on "ideal" hardware, at any time all tasks would have the same
+  p->se.vruntime value --- i.e., tasks would execute simultaneously and no task
+  would ever get "out of balance" from the "ideal" share of CPU time.  ]
+
+CFS's task picking logic is based on this p->se.vruntime value and it is thus
+very simple: it always tries to run the task with the smallest p->se.vruntime
+value (i.e., the task which executed least so far).  CFS always tries to split
+up CPU time between runnable tasks as close to "ideal multitasking hardware" as
+possible.
+
+Most of the rest of CFS's design just falls out of this really simple concept,
+with a few add-on embellishments like nice levels, multiprocessing and various
+algorithm variants to recognize sleepers.
+
+
+
+3.  THE RBTREE
+
+CFS's design is quite radical: it does not use the old data structures for the
+runqueues, but it uses a time-ordered rbtree to build a "timeline" of future
+task execution, and thus has no "array switch" artifacts (by which both the
+previous vanilla scheduler and RSDL/SD are affected).
+
+CFS also maintains the rq->cfs.min_vruntime value, which is a monotonic
+increasing value tracking the smallest vruntime among all tasks in the
+runqueue.  The total amount of work done by the system is tracked using
+min_vruntime; that value is used to place newly activated entities on the left
+side of the tree as much as possible.
+
+The total number of running tasks in the runqueue is accounted through the
+rq->cfs.load value, which is the sum of the weights of the tasks queued on the
+runqueue.
+
+CFS maintains a time-ordered rbtree, where all runnable tasks are sorted by the
+p->se.vruntime key (there is a subtraction using rq->cfs.min_vruntime to
+account for possible wraparounds).  CFS picks the "leftmost" task from this
+tree and sticks to it.
+As the system progresses forwards, the executed tasks are put into the tree
+more and more to the right --- slowly but surely giving a chance for every task
+to become the "leftmost task" and thus get on the CPU within a deterministic
+amount of time.
+
+Summing up, CFS works like this: it runs a task a bit, and when the task
+schedules (or a scheduler tick happens) the task's CPU usage is "accounted
+for": the (small) time it just spent using the physical CPU is added to
+p->se.vruntime.  Once p->se.vruntime gets high enough so that another task
+becomes the "leftmost task" of the time-ordered rbtree it maintains (plus a
+small amount of "granularity" distance relative to the leftmost task so that we
+do not over-schedule tasks and trash the cache), then the new leftmost task is
+picked and the current task is preempted.
+
+
+
+4.  SOME FEATURES OF CFS
+
+CFS uses nanosecond granularity accounting and does not rely on any jiffies or
+other HZ detail.  Thus the CFS scheduler has no notion of "timeslices" in the
+way the previous scheduler had, and has no heuristics whatsoever.  There is
+only one central tunable (you have to switch on CONFIG_SCHED_DEBUG):
+
+   /proc/sys/kernel/sched_granularity_ns
+
+which can be used to tune the scheduler from "desktop" (i.e., low latencies) to
+"server" (i.e., good batching) workloads.  It defaults to a setting suitable
+for desktop workloads.  SCHED_BATCH is handled by the CFS scheduler module too.
+
+Due to its design, the CFS scheduler is not prone to any of the "attacks" that
+exist today against the heuristics of the stock scheduler: fiftyp.c, thud.c,
+chew.c, ring-test.c, massive_intr.c all work fine and do not impact
+interactivity and produce the expected behavior.
+
+The CFS scheduler has a much stronger handling of nice levels and SCHED_BATCH
+than the previous vanilla scheduler: both types of workloads are isolated much
+more aggressively.
+
+SMP load-balancing has been reworked/sanitized: the runqueue-walking
+assumptions are gone from the load-balancing code now, and iterators of the
+scheduling modules are used.  The balancing code got quite a bit simpler as a
+result.
+
+
+
+5. Scheduling policies
+
+CFS implements three scheduling policies:
+
+  - SCHED_NORMAL (traditionally called SCHED_OTHER): The scheduling
+    policy that is used for regular tasks.
+
+  - SCHED_BATCH: Does not preempt nearly as often as regular tasks
+    would, thereby allowing tasks to run longer and make better use of
+    caches but at the cost of interactivity. This is well suited for
+    batch jobs.
+
+  - SCHED_IDLE: This is even weaker than nice 19, but its not a true
+    idle timer scheduler in order to avoid to get into priority
+    inversion problems which would deadlock the machine.
+
+SCHED_FIFO/_RR are implemented in sched_rt.c and are as specified by
+POSIX.
+
+The command chrt from util-linux-ng 2.13.1.1 can set all of these except
+SCHED_IDLE.
+
+
+
+6.  SCHEDULING CLASSES
+
+The new CFS scheduler has been designed in such a way to introduce "Scheduling
+Classes," an extensible hierarchy of scheduler modules.  These modules
+encapsulate scheduling policy details and are handled by the scheduler core
+without the core code assuming too much about them.
+
+sched_fair.c implements the CFS scheduler described above.
+
+sched_rt.c implements SCHED_FIFO and SCHED_RR semantics, in a simpler way than
+the previous vanilla scheduler did.  It uses 100 runqueues (for all 100 RT
+priority levels, instead of 140 in the previous scheduler) and it needs no
+expired array.
+
+Scheduling classes are implemented through the sched_class structure, which
+contains hooks to functions that must be called whenever an interesting event
+occurs.
+
+This is the (partial) list of the hooks:
+
+ - enqueue_task(...)
+
+   Called when a task enters a runnable state.
+   It puts the scheduling entity (task) into the red-black tree and
+   increments the nr_running variable.
+
+ - dequeue_tree(...)
+
+   When a task is no longer runnable, this function is called to keep the
+   corresponding scheduling entity out of the red-black tree.  It decrements
+   the nr_running variable.
+
+ - yield_task(...)
+
+   This function is basically just a dequeue followed by an enqueue, unless the
+   compat_yield sysctl is turned on; in that case, it places the scheduling
+   entity at the right-most end of the red-black tree.
+
+ - check_preempt_curr(...)
+
+   This function checks if a task that entered the runnable state should
+   preempt the currently running task.
+
+ - pick_next_task(...)
+
+   This function chooses the most appropriate task eligible to run next.
+
+ - set_curr_task(...)
+
+   This function is called when a task changes its scheduling class or changes
+   its task group.
+
+ - task_tick(...)
+
+   This function is mostly called from time tick functions; it might lead to
+   process switch.  This drives the running preemption.
+
+ - task_new(...)
+
+   The core scheduler gives the scheduling module an opportunity to manage new
+   task startup.  The CFS scheduling module uses it for group scheduling, while
+   the scheduling module for a real-time task does not use it.
+
+
+
+7.  GROUP SCHEDULER EXTENSIONS TO CFS
+
+Normally, the scheduler operates on individual tasks and strives to provide
+fair CPU time to each task.  Sometimes, it may be desirable to group tasks and
+provide fair CPU time to each such task group.  For example, it may be
+desirable to first provide fair CPU time to each user on the system and then to
+each task belonging to a user.
+
+CONFIG_GROUP_SCHED strives to achieve exactly that.  It lets tasks to be
+grouped and divides CPU time fairly among such groups.
+
+CONFIG_RT_GROUP_SCHED permits to group real-time (i.e., SCHED_FIFO and
+SCHED_RR) tasks.
+
+CONFIG_FAIR_GROUP_SCHED permits to group CFS (i.e., SCHED_NORMAL and
+SCHED_BATCH) tasks.
+
+At present, there are two (mutually exclusive) mechanisms to group tasks for
+CPU bandwidth control purposes:
+
+ - Based on user id (CONFIG_USER_SCHED)
+
+   With this option, tasks are grouped according to their user id.
+
+ - Based on "cgroup" pseudo filesystem (CONFIG_CGROUP_SCHED)
+
+   This options needs CONFIG_CGROUPS to be defined, and lets the administrator
+   create arbitrary groups of tasks, using the "cgroup" pseudo filesystem.  See
+   Documentation/cgroups.txt for more information about this filesystem.
 
 Only one of these options to group tasks can be chosen and not both.
 
-Group scheduler tunables:
-
-When CONFIG_FAIR_USER_SCHED is defined, a directory is created in sysfs for
-each new user and a "cpu_share" file is added in that directory.
+When CONFIG_USER_SCHED is defined, a directory is created in sysfs for each new
+user and a "cpu_share" file is added in that directory.
 
 	# cd /sys/kernel/uids
 	# cat 512/cpu_share		# Display user 512's CPU share
@@ -155,16 +246,14 @@
 	2048
 	#
 
-CPU bandwidth between two users are divided in the ratio of their CPU shares.
-For ex: if you would like user "root" to get twice the bandwidth of user
-"guest", then set the cpu_share for both the users such that "root"'s
-cpu_share is twice "guest"'s cpu_share
+CPU bandwidth between two users is divided in the ratio of their CPU shares.
+For example: if you would like user "root" to get twice the bandwidth of user
+"guest," then set the cpu_share for both the users such that "root"'s cpu_share
+is twice "guest"'s cpu_share.
 
-
-When CONFIG_FAIR_CGROUP_SCHED is defined, a "cpu.shares" file is created
-for each group created using the pseudo filesystem. See example steps
-below to create task groups and modify their CPU share using the "cgroups"
-pseudo filesystem
+When CONFIG_CGROUP_SCHED is defined, a "cpu.shares" file is created for each
+group created using the pseudo filesystem.  See example steps below to create
+task groups and modify their CPU share using the "cgroups" pseudo filesystem.
 
 	# mkdir /dev/cpuctl
 	# mount -t cgroup -ocpu none /dev/cpuctl
diff --git a/Documentation/scsi/scsi_fc_transport.txt b/Documentation/scsi/scsi_fc_transport.txt
index 75143f0..38d324d6 100644
--- a/Documentation/scsi/scsi_fc_transport.txt
+++ b/Documentation/scsi/scsi_fc_transport.txt
@@ -436,6 +436,42 @@
     was updated to remove all vports for the fc_host as well.
 
 
+Transport supplied functions
+----------------------------
+
+The following functions are supplied by the FC-transport for use by LLDs.
+
+   fc_vport_create - create a vport
+   fc_vport_terminate - detach and remove a vport
+
+Details:
+
+/**
+ * fc_vport_create - Admin App or LLDD requests creation of a vport
+ * @shost:     scsi host the virtual port is connected to.
+ * @ids:       The world wide names, FC4 port roles, etc for
+ *              the virtual port.
+ *
+ * Notes:
+ *     This routine assumes no locks are held on entry.
+ */
+struct fc_vport *
+fc_vport_create(struct Scsi_Host *shost, struct fc_vport_identifiers *ids)
+
+/**
+ * fc_vport_terminate - Admin App or LLDD requests termination of a vport
+ * @vport:      fc_vport to be terminated
+ *
+ * Calls the LLDD vport_delete() function, then deallocates and removes
+ * the vport from the shost and object tree.
+ *
+ * Notes:
+ *      This routine assumes no locks are held on entry.
+ */
+int
+fc_vport_terminate(struct fc_vport *vport)
+
+
 Credits
 =======
 The following people have contributed to this document:
diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt
index b117e42..e0e54a2 100644
--- a/Documentation/sound/alsa/ALSA-Configuration.txt
+++ b/Documentation/sound/alsa/ALSA-Configuration.txt
@@ -746,8 +746,10 @@
   Module snd-hda-intel
   --------------------
 
-    Module for Intel HD Audio (ICH6, ICH6M, ESB2, ICH7, ICH8),
-		ATI SB450, SB600, RS600,
+    Module for Intel HD Audio (ICH6, ICH6M, ESB2, ICH7, ICH8, ICH9, ICH10,
+			PCH, SCH),
+		ATI SB450, SB600, R600, RS600, RS690, RS780, RV610, RV620,
+			RV630, RV635, RV670, RV770,
 		VIA VT8251/VT8237A,
 		SIS966, ULI M5461
 
@@ -807,6 +809,7 @@
 	ALC260
 	  hp		HP machines
 	  hp-3013	HP machines (3013-variant)
+	  hp-dc7600	HP DC7600
 	  fujitsu	Fujitsu S7020
 	  acer		Acer TravelMate
 	  will		Will laptops (PB V7900)
@@ -828,8 +831,11 @@
 	  hippo		Hippo (ATI) with jack detection, Sony UX-90s
 	  hippo_1	Hippo (Benq) with jack detection
 	  sony-assamd	Sony ASSAMD
+	  toshiba-s06	Toshiba S06
+	  toshiba-rx1	Toshiba RX1
 	  ultra		Samsung Q1 Ultra Vista model
 	  lenovo-3000	Lenovo 3000 y410
+	  nec		NEC Versa S9100
 	  basic		fixed pin assignment w/o SPDIF
 	  auto		auto-config reading BIOS (default)
 
@@ -838,6 +844,7 @@
 	  3stack	3-stack model
 	  toshiba	Toshiba A205
 	  acer		Acer laptops
+	  acer-aspire	Acer Aspire One
 	  dell		Dell OEM laptops (Vostro 1200)
 	  zepto		Zepto laptops
 	  test		for testing/debugging purpose, almost all controls can
@@ -847,6 +854,9 @@
 
 	ALC269
 	  basic		Basic preset
+	  quanta	Quanta FL1
+	  eeepc-p703	ASUS Eeepc P703 P900A
+	  eeepc-p901	ASUS Eeepc P901 S101
 
 	ALC662/663
 	  3stack-dig	3-stack (2-channel) with SPDIF
@@ -856,10 +866,17 @@
 	  lenovo-101e	 Lenovo laptop
 	  eeepc-p701	ASUS Eeepc P701
 	  eeepc-ep20	ASUS Eeepc EP20
+	  ecs		ECS/Foxconn mobo
 	  m51va		ASUS M51VA
 	  g71v		ASUS G71V
 	  h13		ASUS H13
 	  g50v		ASUS G50V
+	  asus-mode1	ASUS
+	  asus-mode2	ASUS
+	  asus-mode3	ASUS
+	  asus-mode4	ASUS
+	  asus-mode5	ASUS
+	  asus-mode6	ASUS
 	  auto		auto-config reading BIOS (default)
 
 	ALC882/885
@@ -891,12 +908,14 @@
 	  lenovo-101e	Lenovo 101E
 	  lenovo-nb0763	Lenovo NB0763
 	  lenovo-ms7195-dig Lenovo MS7195
+	  lenovo-sky	Lenovo Sky
 	  haier-w66	Haier W66
 	  3stack-hp	HP machines with 3stack (Lucknow, Samba boards)
 	  6stack-dell	Dell machines with 6stack (Inspiron 530)
 	  mitac		Mitac 8252D
 	  clevo-m720	Clevo M720 laptop series
 	  fujitsu-pi2515 Fujitsu AMILO Pi2515
+	  3stack-6ch-intel Intel DG33* boards
 	  auto		auto-config reading BIOS (default)
 
 	ALC861/660
@@ -929,7 +948,7 @@
 	  allout	5-jack in back, 2-jack in front, SPDIF out
 	  auto		auto-config reading BIOS (default)
 
-	AD1882
+	AD1882 / AD1882A
 	  3stack	3-stack mode (default)
 	  6stack	6-stack mode
 
@@ -1079,7 +1098,7 @@
 	    register value without FIFO size correction as the current
 	    DMA pointer.  position_fix=2 will make the driver to use
 	    the position buffer instead of reading SD_LPIB register.
-	    (Usually SD_LPLIB register is more accurate than the
+	    (Usually SD_LPIB register is more accurate than the
 	    position buffer.)
 
     NB: If you get many "azx_get_response timeout" messages at
@@ -1166,6 +1185,7 @@
 			* Event Electronics, EZ8
                         * Digigram VX442
 			* Lionstracs, Mediastaton
+			* Terrasoniq TS 88
 
     model       - Use the given board model, one of the following:
 		  delta1010, dio2496, delta66, delta44, audiophile, delta410,
@@ -1200,7 +1220,10 @@
 			* TerraTec Phase 22
 			* TerraTec Phase 28
 			* AudioTrak Prodigy 7.1
-			* AudioTrak Prodigy 7.1LT
+			* AudioTrak Prodigy 7.1 LT
+			* AudioTrak Prodigy 7.1 XT
+			* AudioTrak Prodigy 7.1 HIFI
+			* AudioTrak Prodigy 7.1 HD2
 			* AudioTrak Prodigy 192
 			* Pontis MS300
 			* Albatron K8X800 Pro II 
@@ -1211,12 +1234,16 @@
 			* Shuttle SN25P
 			* Onkyo SE-90PCI
 			* Onkyo SE-200PCI
+			* ESI Juli@
+			* Hercules Fortissimo IV
+			* EGO-SYS WaveTerminal 192M
 
     model       - Use the given board model, one of the following:
 		  revo51, revo71, amp2000, prodigy71, prodigy71lt,
-		  prodigy192, aureon51, aureon71, universe, ap192,
-		  k8x800, phase22, phase28, ms300, av710, se200pci,
-		  se90pci
+		  prodigy71xt, prodigy71hifi, prodigyhd2, prodigy192,
+		  juli, aureon51, aureon71, universe, ap192, k8x800,
+		  phase22, phase28, ms300, av710, se200pci, se90pci,
+		  fortissimo4, sn25p, WT192M
 
     This module supports multiple cards and autoprobe.
 
@@ -1255,7 +1282,7 @@
 
     Module for AC'97 motherboards from Intel and compatibles.
 			* Intel i810/810E, i815, i820, i830, i84x, MX440
-				ICH5, ICH6, ICH7, ESB2
+				ICH5, ICH6, ICH7, 6300ESB, ESB2
 			* SiS 7012 (SiS 735)
 			* NVidia NForce, NForce2, NForce3, MCP04, CK804
 				 CK8, CK8S, MCP501
@@ -1951,6 +1978,8 @@
 			* CHIC  True Sound 4Dwave
 			* Shark  Predator4D-PCI
 			* Jaton  SonicWave 4D
+			* SiS SI7018 PCI Audio
+			* Hoontech SoundTrack Digital 4DWave NX
 
     pcm_channels   - max channels (voices) reserved for PCM
     wavetable_size - max wavetable size in kB (4-?kb)
@@ -1966,12 +1995,25 @@
 
     vid             - Vendor ID for the device (optional)
     pid             - Product ID for the device (optional)
+    nrpacks	    - Max. number of packets per URB (default: 8)
+    async_unlink    - Use async unlink mode (default: yes)
     device_setup    - Device specific magic number (optional)
                     - Influence depends on the device
                     - Default: 0x0000 
+    ignore_ctl_error - Ignore any USB-controller regarding mixer
+    		       interface (default: no)
 
     This module supports multiple devices, autoprobe and hotplugging.
 
+    NB: nrpacks parameter can be modified dynamically via sysfs.
+        Don't put the value over 20.  Changing via sysfs has no sanity
+	check.
+    NB: async_unlink=0 would cause Oops.  It remains just for
+        debugging purpose (if any).
+    NB: ignore_ctl_error=1 may help when you get an error at accessing
+        the mixer element such as URB error -22.  This happens on some
+        buggy USB device or the controller.
+
   Module snd-usb-caiaq
   --------------------
 
@@ -2078,7 +2120,7 @@
   -------------------
 
     Module for sound cards based on the Asus AV100/AV200 chips,
-    i.e., Xonar D1, DX, D2 and D2X.
+    i.e., Xonar D1, DX, D2, D2X and HDAV1.3 (Deluxe).
 
     This module supports autoprobe and multiple cards.
 
diff --git a/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl b/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl
index e13c4e6..87a7c07a 100644
--- a/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl
+++ b/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl
@@ -5073,8 +5073,7 @@
       with <constant>SNDRV_DMA_TYPE_CONTINUOUS</constant> type and the
       <function>snd_dma_continuous_data(GFP_KERNEL)</function> device pointer,
       where <constant>GFP_KERNEL</constant> is the kernel allocation flag to
-      use.  For the SBUS, <constant>SNDRV_DMA_TYPE_SBUS</constant> and
-      <function>snd_dma_sbus_data(sbus_dev)</function> are used instead.
+      use.
       For the PCI scatter-gather buffers, use
       <constant>SNDRV_DMA_TYPE_DEV_SG</constant> with
       <function>snd_dma_pci_data(pci)</function>
@@ -6135,44 +6134,58 @@
       </para>
     </section>
 
-    <section id="useful-functions-snd-assert">
-      <title><function>snd_assert()</function></title>
-      <para>
-        <function>snd_assert()</function> macro is similar with the
-      normal <function>assert()</function> macro. For example,  
-
-        <informalexample>
-          <programlisting>
-<![CDATA[
-  snd_assert(pointer != NULL, return -EINVAL);
-]]>
-          </programlisting>
-        </informalexample>
-      </para>
-
-      <para>
-        The first argument is the expression to evaluate, and the
-      second argument is the action if it fails. When
-      <constant>CONFIG_SND_DEBUG</constant>, is set, it will show an
-      error message such as <computeroutput>BUG? (xxx)</computeroutput>
-      together with stack trace.
-      </para>
-      <para>
-	 When no debug flag is set, this macro is ignored. 
-      </para>
-    </section>
-
     <section id="useful-functions-snd-bug">
       <title><function>snd_BUG()</function></title>
       <para>
         It shows the <computeroutput>BUG?</computeroutput> message and
-      stack trace as well as <function>snd_assert</function> at the point.
+      stack trace as well as <function>snd_BUG_ON</function> at the point.
       It's useful to show that a fatal error happens there. 
       </para>
       <para>
 	 When no debug flag is set, this macro is ignored. 
       </para>
     </section>
+
+    <section id="useful-functions-snd-bug-on">
+      <title><function>snd_BUG_ON()</function></title>
+      <para>
+        <function>snd_BUG_ON()</function> macro is similar with
+	<function>WARN_ON()</function> macro. For example,  
+
+        <informalexample>
+          <programlisting>
+<![CDATA[
+  snd_BUG_ON(!pointer);
+]]>
+          </programlisting>
+        </informalexample>
+
+	or it can be used as the condition,
+        <informalexample>
+          <programlisting>
+<![CDATA[
+  if (snd_BUG_ON(non_zero_is_bug))
+          return -EINVAL;
+]]>
+          </programlisting>
+        </informalexample>
+
+      </para>
+
+      <para>
+        The macro takes an conditional expression to evaluate.
+	When <constant>CONFIG_SND_DEBUG</constant>, is set, the
+	expression is actually evaluated. If it's non-zero, it shows
+	the warning message such as
+	<computeroutput>BUG? (xxx)</computeroutput>
+	normally followed by stack trace.  It returns the evaluated
+	value.
+	When no <constant>CONFIG_SND_DEBUG</constant> is set, this
+	macro always returns zero.
+      </para>
+
+    </section>
+
   </chapter>
 
 
diff --git a/Documentation/sound/alsa/soc/dapm.txt b/Documentation/sound/alsa/soc/dapm.txt
index b2ed698..46f9684 100644
--- a/Documentation/sound/alsa/soc/dapm.txt
+++ b/Documentation/sound/alsa/soc/dapm.txt
@@ -135,11 +135,7 @@
 
 static int spitz_mic_bias(struct snd_soc_dapm_widget* w, int event)
 {
-	if(SND_SOC_DAPM_EVENT_ON(event))
-		set_scoop_gpio(&spitzscoop2_device.dev, SPITZ_SCP2_MIC_BIAS);
-	else
-		reset_scoop_gpio(&spitzscoop2_device.dev, SPITZ_SCP2_MIC_BIAS);
-
+	gpio_set_value(SPITZ_GPIO_MIC_BIAS, SND_SOC_DAPM_EVENT_ON(event));
 	return 0;
 }
 
@@ -269,11 +265,7 @@
 /* turn speaker amplifier on/off depending on use */
 static int corgi_amp_event(struct snd_soc_dapm_widget *w, int event)
 {
-	if (SND_SOC_DAPM_EVENT_ON(event))
-		set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_APM_ON);
-	else
-		reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_APM_ON);
-
+	gpio_set_value(CORGI_GPIO_APM_ON, SND_SOC_DAPM_EVENT_ON(event));
 	return 0;
 }
 
diff --git a/Documentation/sparc/sbus_drivers.txt b/Documentation/sparc/sbus_drivers.txt
deleted file mode 100644
index eb1e28a..0000000
--- a/Documentation/sparc/sbus_drivers.txt
+++ /dev/null
@@ -1,309 +0,0 @@
-
-		Writing SBUS Drivers
-
-	    David S. Miller (davem@redhat.com)
-
-	The SBUS driver interfaces of the Linux kernel have been
-revamped completely for 2.4.x for several reasons.  Foremost were
-performance and complexity concerns.  This document details these
-new interfaces and how they are used to write an SBUS device driver.
-
-	SBUS drivers need to include <asm/sbus.h> to get access
-to functions and structures described here.
-
-		Probing and Detection
-
-	Each SBUS device inside the machine is described by a
-structure called "struct sbus_dev".  Likewise, each SBUS bus
-found in the system is described by a "struct sbus_bus".  For
-each SBUS bus, the devices underneath are hung in a tree-like
-fashion off of the bus structure.
-
-	The SBUS device structure contains enough information
-for you to implement your device probing algorithm and obtain
-the bits necessary to run your device.  The most commonly
-used members of this structure, and their typical usage,
-will be detailed below.
-
-	Here is a piece of skeleton code for performing a device
-probe in an SBUS driver under Linux:
-
-	static int __devinit mydevice_probe_one(struct sbus_dev *sdev)
-	{
-		struct mysdevice *mp = kzalloc(sizeof(*mp), GFP_KERNEL);
-
-		if (!mp)
-			return -ENODEV;
-
-		...
-		dev_set_drvdata(&sdev->ofdev.dev, mp);
-		return 0;
-		...
-	}
-
-	static int __devinit mydevice_probe(struct of_device *dev,
-				            const struct of_device_id *match)
-	{
-		struct sbus_dev *sdev = to_sbus_device(&dev->dev);
-
-		return mydevice_probe_one(sdev);
-	}
-
-	static int __devexit mydevice_remove(struct of_device *dev)
-	{
-		struct sbus_dev *sdev = to_sbus_device(&dev->dev);
-		struct mydevice *mp = dev_get_drvdata(&dev->dev);
-
-		return mydevice_remove_one(sdev, mp);
-	}
-
-	static struct of_device_id mydevice_match[] = {
-		{
-			.name = "mydevice",
-		},
-		{},
-	};
-
-	MODULE_DEVICE_TABLE(of, mydevice_match);
-
-	static struct of_platform_driver mydevice_driver = {
-		.match_table	= mydevice_match,
-		.probe		= mydevice_probe,
-		.remove		= __devexit_p(mydevice_remove),
-		.driver		= {
-			.name		= "mydevice",
-		},
-	};
-
-	static int __init mydevice_init(void)
-	{
-		return of_register_driver(&mydevice_driver, &sbus_bus_type);
-	}
-
-	static void __exit mydevice_exit(void)
-	{
-		of_unregister_driver(&mydevice_driver);
-	}
-
-	module_init(mydevice_init);
-	module_exit(mydevice_exit);
-
-	The mydevice_match table is a series of entries which
-describes what SBUS devices your driver is meant for.  In the
-simplest case you specify a string for the 'name' field.  Every
-SBUS device with a 'name' property matching your string will
-be passed one-by-one to your .probe method.
-
-	You should store away your device private state structure
-pointer in the drvdata area so that you can retrieve it later on
-in your .remove method.
-
-	Any memory allocated, registers mapped, IRQs registered,
-etc. must be undone by your .remove method so that all resources
-of your device are released by the time it returns.
-
-	You should _NOT_ use the for_each_sbus(), for_each_sbusdev(),
-and for_all_sbusdev() interfaces.  They are deprecated, will be
-removed, and no new driver should reference them ever.
-
-		Mapping and Accessing I/O Registers
-
-	Each SBUS device structure contains an array of descriptors
-which describe each register set. We abuse struct resource for that.
-They each correspond to the "reg" properties provided by the OBP firmware.
-
-	Before you can access your device's registers you must map
-them.  And later if you wish to shutdown your driver (for module
-unload or similar) you must unmap them.  You must treat them as
-a resource, which you allocate (map) before using and free up
-(unmap) when you are done with it.
-
-	The mapping information is stored in an opaque value
-typed as an "unsigned long".  This is the type of the return value
-of the mapping interface, and the arguments to the unmapping
-interface.  Let's say you want to map the first set of registers.
-Perhaps part of your driver software state structure looks like:
-
-	struct mydevice {
-		unsigned long control_regs;
-	   ...
-		struct sbus_dev *sdev;
-	   ...
-	};
-
-	At initialization time you then use the sbus_ioremap
-interface to map in your registers, like so:
-
-	static void init_one_mydevice(struct sbus_dev *sdev)
-	{
-		struct mydevice *mp;
-		...
-
-		mp->control_regs = sbus_ioremap(&sdev->resource[0], 0,
-					CONTROL_REGS_SIZE, "mydevice regs");
-		if (!mp->control_regs) {
-			/* Failure, cleanup and return. */
-		}
-	}
-
-	Second argument to sbus_ioremap is an offset for
-cranky devices with broken OBP PROM. The sbus_ioremap uses only
-a start address and flags from the resource structure.
-Therefore it is possible to use the same resource to map
-several sets of registers or even to fabricate a resource
-structure if driver gets physical address from some private place.
-This practice is discouraged though. Use whatever OBP PROM
-provided to you.
-
-	And here is how you might unmap these registers later at
-driver shutdown or module unload time, using the sbus_iounmap
-interface:
-
-	static void mydevice_unmap_regs(struct mydevice *mp)
-	{
-		sbus_iounmap(mp->control_regs, CONTROL_REGS_SIZE);
-	}
-
-	Finally, to actually access your registers there are 6
-interface routines at your disposal.  Accesses are byte (8 bit),
-word (16 bit), or longword (32 bit) sized.  Here they are:
-
-	u8 sbus_readb(unsigned long reg)		/* read byte */
-	u16 sbus_readw(unsigned long reg)		/* read word */
-	u32 sbus_readl(unsigned long reg)		/* read longword */
-	void sbus_writeb(u8 value, unsigned long reg)	/* write byte */
-	void sbus_writew(u16 value, unsigned long reg)	/* write word */
-	void sbus_writel(u32 value, unsigned long reg)	/* write longword */
-
-	So, let's say your device has a control register of some sort
-at offset zero.  The following might implement resetting your device:
-
-	#define CONTROL		0x00UL
-
-	#define CONTROL_RESET	0x00000001	/* Reset hardware */
-
-	static void mydevice_reset(struct mydevice *mp)
-	{
-		sbus_writel(CONTROL_RESET, mp->regs + CONTROL);
-	}
-
-	Or perhaps there is a data port register at an offset of
-16 bytes which allows you to read bytes from a fifo in the device:
-
-	#define DATA		0x10UL
-
-	static u8 mydevice_get_byte(struct mydevice *mp)
-	{
-		return sbus_readb(mp->regs + DATA);
-	}
-
-	It's pretty straightforward, and clueful readers may have
-noticed that these interfaces mimick the PCI interfaces of the
-Linux kernel.  This was not by accident.
-
-	WARNING:
-
-		DO NOT try to treat these opaque register mapping
-		values as a memory mapped pointer to some structure
-		which you can dereference.
-
-		It may be memory mapped, it may not be.  In fact it
-		could be a physical address, or it could be the time
-		of day xor'd with 0xdeadbeef.  :-)
-
-		Whatever it is, it's an implementation detail.  The
-		interface was done this way to shield the driver
-		author from such complexities.
-
-			Doing DVMA
-
-	SBUS devices can perform DMA transactions in a way similar
-to PCI but dissimilar to ISA, e.g. DMA masters supply address.
-In contrast to PCI, however, that address (a bus address) is
-translated by IOMMU before a memory access is performed and therefore
-it is virtual. Sun calls this procedure DVMA.
-
-	Linux supports two styles of using SBUS DVMA: "consistent memory"
-and "streaming DVMA". CPU view of consistent memory chunk is, well,
-consistent with a view of a device. Think of it as an uncached memory.
-Typically this way of doing DVMA is not very fast and drivers use it
-mostly for control blocks or queues. On some CPUs we cannot flush or
-invalidate individual pages or cache lines and doing explicit flushing
-over ever little byte in every control block would be wasteful.
-
-Streaming DVMA is a preferred way to transfer large amounts of data.
-This process works in the following way:
-1. a CPU stops accessing a certain part of memory,
-   flushes its caches covering that memory;
-2. a device does DVMA accesses, then posts an interrupt;
-3. CPU invalidates its caches and starts to access the memory.
-
-A single streaming DVMA operation can touch several discontiguous
-regions of a virtual bus address space. This is called a scatter-gather
-DVMA.
-
-[TBD: Why do not we neither Solaris attempt to map disjoint pages
-into a single virtual chunk with the help of IOMMU, so that non SG
-DVMA masters would do SG? It'd be very helpful for RAID.]
-
-	In order to perform a consistent DVMA a driver does something
-like the following:
-
-	char *mem;		/* Address in the CPU space */
-	u32 busa;		/* Address in the SBus space */
-
-	mem = (char *) sbus_alloc_consistent(sdev, MYMEMSIZE, &busa);
-
-	Then mem is used when CPU accesses this memory and u32
-is fed to the device so that it can do DVMA. This is typically
-done with an sbus_writel() into some device register.
-
-	Do not forget to free the DVMA resources once you are done:
-
-	sbus_free_consistent(sdev, MYMEMSIZE, mem, busa);
-
-	Streaming DVMA is more interesting. First you allocate some
-memory suitable for it or pin down some user pages. Then it all works
-like this:
-
-	char *mem = argumen1;
-	unsigned int size = argument2;
-	u32 busa;		/* Address in the SBus space */
-
-	*mem = 1;		/* CPU can access */
-	busa = sbus_map_single(sdev, mem, size);
-	if (busa == 0) .......
-
-	/* Tell the device to use busa here */
-	/* CPU cannot access the memory without sbus_dma_sync_single() */
-
-	sbus_unmap_single(sdev, busa, size);
-	if (*mem == 0) ....	/* CPU can access again */
-
-	It is possible to retain mappings and ask the device to
-access data again and again without calling sbus_unmap_single.
-However, CPU caches must be invalidated with sbus_dma_sync_single
-before such access.
-
-[TBD but what about writeback caches here... do we have any?]
-
-	There is an equivalent set of functions doing the same thing
-only with several memory segments at once for devices capable of
-scatter-gather transfers. Use the Source, Luke.
-
-			Examples
-
-	drivers/net/sunhme.c
-	This is a complicated driver which illustrates many concepts
-discussed above and plus it handles both PCI and SBUS boards.
-
-	drivers/scsi/esp.c
-	Check it out for scatter-gather DVMA.
-
-	drivers/sbus/char/bpp.c
-	A non-DVMA device.
-
-	drivers/net/sunlance.c
-	Lance driver abuses consistent mappings for data transfer.
-It is a nifty trick which we do not particularly recommend...
-Just check it out and know that it's legal.
diff --git a/Documentation/timers/00-INDEX b/Documentation/timers/00-INDEX
new file mode 100644
index 0000000..397dc35
--- /dev/null
+++ b/Documentation/timers/00-INDEX
@@ -0,0 +1,10 @@
+00-INDEX
+	- this file
+highres.txt
+	- High resolution timers and dynamic ticks design notes
+hpet.txt
+	- High Precision Event Timer Driver for Linux
+hrtimers.txt
+	- subsystem for high-resolution kernel timers
+timer_stats.txt
+	- timer usage statistics
diff --git a/Documentation/timers/hpet.txt b/Documentation/timers/hpet.txt
new file mode 100644
index 0000000..e7c09ab
--- /dev/null
+++ b/Documentation/timers/hpet.txt
@@ -0,0 +1,299 @@
+		High Precision Event Timer Driver for Linux
+
+The High Precision Event Timer (HPET) hardware follows a specification
+by Intel and Microsoft which can be found at
+
+	http://www.intel.com/technology/architecture/hpetspec.htm
+
+Each HPET has one fixed-rate counter (at 10+ MHz, hence "High Precision")
+and up to 32 comparators.  Normally three or more comparators are provided,
+each of which can generate oneshot interupts and at least one of which has
+additional hardware to support periodic interrupts.  The comparators are
+also called "timers", which can be misleading since usually timers are
+independent of each other ... these share a counter, complicating resets.
+
+HPET devices can support two interrupt routing modes.  In one mode, the
+comparators are additional interrupt sources with no particular system
+role.  Many x86 BIOS writers don't route HPET interrupts at all, which
+prevents use of that mode.  They support the other "legacy replacement"
+mode where the first two comparators block interrupts from 8254 timers
+and from the RTC.
+
+The driver supports detection of HPET driver allocation and initialization
+of the HPET before the driver module_init routine is called.  This enables
+platform code which uses timer 0 or 1 as the main timer to intercept HPET
+initialization.  An example of this initialization can be found in
+arch/x86/kernel/hpet.c.
+
+The driver provides a userspace API which resembles the API found in the
+RTC driver framework.  An example user space program is provided below.
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <memory.h>
+#include <malloc.h>
+#include <time.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/time.h>
+#include <linux/hpet.h>
+
+
+extern void hpet_open_close(int, const char **);
+extern void hpet_info(int, const char **);
+extern void hpet_poll(int, const char **);
+extern void hpet_fasync(int, const char **);
+extern void hpet_read(int, const char **);
+
+#include <sys/poll.h>
+#include <sys/ioctl.h>
+#include <signal.h>
+
+struct hpet_command {
+	char		*command;
+	void		(*func)(int argc, const char ** argv);
+} hpet_command[] = {
+	{
+		"open-close",
+		hpet_open_close
+	},
+	{
+		"info",
+		hpet_info
+	},
+	{
+		"poll",
+		hpet_poll
+	},
+	{
+		"fasync",
+		hpet_fasync
+	},
+};
+
+int
+main(int argc, const char ** argv)
+{
+	int	i;
+
+	argc--;
+	argv++;
+
+	if (!argc) {
+		fprintf(stderr, "-hpet: requires command\n");
+		return -1;
+	}
+
+
+	for (i = 0; i < (sizeof (hpet_command) / sizeof (hpet_command[0])); i++)
+		if (!strcmp(argv[0], hpet_command[i].command)) {
+			argc--;
+			argv++;
+			fprintf(stderr, "-hpet: executing %s\n",
+				hpet_command[i].command);
+			hpet_command[i].func(argc, argv);
+			return 0;
+		}
+
+	fprintf(stderr, "do_hpet: command %s not implemented\n", argv[0]);
+
+	return -1;
+}
+
+void
+hpet_open_close(int argc, const char **argv)
+{
+	int	fd;
+
+	if (argc != 1) {
+		fprintf(stderr, "hpet_open_close: device-name\n");
+		return;
+	}
+
+	fd = open(argv[0], O_RDONLY);
+	if (fd < 0)
+		fprintf(stderr, "hpet_open_close: open failed\n");
+	else
+		close(fd);
+
+	return;
+}
+
+void
+hpet_info(int argc, const char **argv)
+{
+}
+
+void
+hpet_poll(int argc, const char **argv)
+{
+	unsigned long		freq;
+	int			iterations, i, fd;
+	struct pollfd		pfd;
+	struct hpet_info	info;
+	struct timeval		stv, etv;
+	struct timezone		tz;
+	long			usec;
+
+	if (argc != 3) {
+		fprintf(stderr, "hpet_poll: device-name freq iterations\n");
+		return;
+	}
+
+	freq = atoi(argv[1]);
+	iterations = atoi(argv[2]);
+
+	fd = open(argv[0], O_RDONLY);
+
+	if (fd < 0) {
+		fprintf(stderr, "hpet_poll: open of %s failed\n", argv[0]);
+		return;
+	}
+
+	if (ioctl(fd, HPET_IRQFREQ, freq) < 0) {
+		fprintf(stderr, "hpet_poll: HPET_IRQFREQ failed\n");
+		goto out;
+	}
+
+	if (ioctl(fd, HPET_INFO, &info) < 0) {
+		fprintf(stderr, "hpet_poll: failed to get info\n");
+		goto out;
+	}
+
+	fprintf(stderr, "hpet_poll: info.hi_flags 0x%lx\n", info.hi_flags);
+
+	if (info.hi_flags && (ioctl(fd, HPET_EPI, 0) < 0)) {
+		fprintf(stderr, "hpet_poll: HPET_EPI failed\n");
+		goto out;
+	}
+
+	if (ioctl(fd, HPET_IE_ON, 0) < 0) {
+		fprintf(stderr, "hpet_poll, HPET_IE_ON failed\n");
+		goto out;
+	}
+
+	pfd.fd = fd;
+	pfd.events = POLLIN;
+
+	for (i = 0; i < iterations; i++) {
+		pfd.revents = 0;
+		gettimeofday(&stv, &tz);
+		if (poll(&pfd, 1, -1) < 0)
+			fprintf(stderr, "hpet_poll: poll failed\n");
+		else {
+			long 	data;
+
+			gettimeofday(&etv, &tz);
+			usec = stv.tv_sec * 1000000 + stv.tv_usec;
+			usec = (etv.tv_sec * 1000000 + etv.tv_usec) - usec;
+
+			fprintf(stderr,
+				"hpet_poll: expired time = 0x%lx\n", usec);
+
+			fprintf(stderr, "hpet_poll: revents = 0x%x\n",
+				pfd.revents);
+
+			if (read(fd, &data, sizeof(data)) != sizeof(data)) {
+				fprintf(stderr, "hpet_poll: read failed\n");
+			}
+			else
+				fprintf(stderr, "hpet_poll: data 0x%lx\n",
+					data);
+		}
+	}
+
+out:
+	close(fd);
+	return;
+}
+
+static int hpet_sigio_count;
+
+static void
+hpet_sigio(int val)
+{
+	fprintf(stderr, "hpet_sigio: called\n");
+	hpet_sigio_count++;
+}
+
+void
+hpet_fasync(int argc, const char **argv)
+{
+	unsigned long		freq;
+	int			iterations, i, fd, value;
+	sig_t			oldsig;
+	struct hpet_info	info;
+
+	hpet_sigio_count = 0;
+	fd = -1;
+
+	if ((oldsig = signal(SIGIO, hpet_sigio)) == SIG_ERR) {
+		fprintf(stderr, "hpet_fasync: failed to set signal handler\n");
+		return;
+	}
+
+	if (argc != 3) {
+		fprintf(stderr, "hpet_fasync: device-name freq iterations\n");
+		goto out;
+	}
+
+	fd = open(argv[0], O_RDONLY);
+
+	if (fd < 0) {
+		fprintf(stderr, "hpet_fasync: failed to open %s\n", argv[0]);
+		return;
+	}
+
+
+	if ((fcntl(fd, F_SETOWN, getpid()) == 1) ||
+		((value = fcntl(fd, F_GETFL)) == 1) ||
+		(fcntl(fd, F_SETFL, value | O_ASYNC) == 1)) {
+		fprintf(stderr, "hpet_fasync: fcntl failed\n");
+		goto out;
+	}
+
+	freq = atoi(argv[1]);
+	iterations = atoi(argv[2]);
+
+	if (ioctl(fd, HPET_IRQFREQ, freq) < 0) {
+		fprintf(stderr, "hpet_fasync: HPET_IRQFREQ failed\n");
+		goto out;
+	}
+
+	if (ioctl(fd, HPET_INFO, &info) < 0) {
+		fprintf(stderr, "hpet_fasync: failed to get info\n");
+		goto out;
+	}
+
+	fprintf(stderr, "hpet_fasync: info.hi_flags 0x%lx\n", info.hi_flags);
+
+	if (info.hi_flags && (ioctl(fd, HPET_EPI, 0) < 0)) {
+		fprintf(stderr, "hpet_fasync: HPET_EPI failed\n");
+		goto out;
+	}
+
+	if (ioctl(fd, HPET_IE_ON, 0) < 0) {
+		fprintf(stderr, "hpet_fasync, HPET_IE_ON failed\n");
+		goto out;
+	}
+
+	for (i = 0; i < iterations; i++) {
+		(void) pause();
+		fprintf(stderr, "hpet_fasync: count = %d\n", hpet_sigio_count);
+	}
+
+out:
+	signal(SIGIO, oldsig);
+
+	if (fd >= 0)
+		close(fd);
+
+	return;
+}
diff --git a/Documentation/usb/anchors.txt b/Documentation/usb/anchors.txt
index 7304bcf..5e6b64c 100644
--- a/Documentation/usb/anchors.txt
+++ b/Documentation/usb/anchors.txt
@@ -42,9 +42,21 @@
 are called in the reverse temporal order they were submitted.
 This way no data can be reordered.
 
+usb_unlink_anchored_urbs()
+--------------------------
+
+This function unlinks all URBs associated with an anchor. The URBs
+are processed in the reverse temporal order they were submitted.
+This is similar to usb_kill_anchored_urbs(), but it will not sleep.
+Therefore no guarantee is made that the URBs have been unlinked when
+the call returns. They may be unlinked later but will be unlinked in
+finite time.
+
 usb_wait_anchor_empty_timeout()
 -------------------------------
 
 This function waits for all URBs associated with an anchor to finish
 or a timeout, whichever comes first. Its return value will tell you
 whether the timeout was reached.
+
+
diff --git a/Documentation/video4linux/CARDLIST.bttv b/Documentation/video4linux/CARDLIST.bttv
index f32efb6..60ba668 100644
--- a/Documentation/video4linux/CARDLIST.bttv
+++ b/Documentation/video4linux/CARDLIST.bttv
@@ -150,3 +150,4 @@
 149 -> Typhoon TV-Tuner PCI (50684)
 150 -> Geovision GV-600                                    [008a:763c]
 151 -> Kozumi KTV-01C
+152 -> Encore ENL TV-FM-2                                  [1000:1801]
diff --git a/Documentation/video4linux/CARDLIST.cx23885 b/Documentation/video4linux/CARDLIST.cx23885
index f0e613b..64823cc 100644
--- a/Documentation/video4linux/CARDLIST.cx23885
+++ b/Documentation/video4linux/CARDLIST.cx23885
@@ -9,3 +9,5 @@
   8 -> Hauppauge WinTV-HVR1700                             [0070:8101]
   9 -> Hauppauge WinTV-HVR1400                             [0070:8010]
  10 -> DViCO FusionHDTV7 Dual Express                      [18ac:d618]
+ 11 -> DViCO FusionHDTV DVB-T Dual Express                 [18ac:db78]
+ 12 -> Leadtek Winfast PxDVR3200 H                         [107d:6681]
diff --git a/Documentation/video4linux/CARDLIST.cx88 b/Documentation/video4linux/CARDLIST.cx88
index 7cf5685..a5227e3 100644
--- a/Documentation/video4linux/CARDLIST.cx88
+++ b/Documentation/video4linux/CARDLIST.cx88
@@ -66,3 +66,11 @@
  65 -> DViCO FusionHDTV 7 Gold                             [18ac:d610]
  66 -> Prolink Pixelview MPEG 8000GT                       [1554:4935]
  67 -> Kworld PlusTV HD PCI 120 (ATSC 120)                 [17de:08c1]
+ 68 -> Hauppauge WinTV-HVR4000 DVB-S/S2/T/Hybrid           [0070:6900,0070:6904,0070:6902]
+ 69 -> Hauppauge WinTV-HVR4000(Lite) DVB-S/S2              [0070:6905,0070:6906]
+ 70 -> TeVii S460 DVB-S/S2                                 [d460:9022]
+ 71 -> Omicom SS4 DVB-S/S2 PCI                             [A044:2011]
+ 72 -> TBS 8920 DVB-S/S2                                   [8920:8888]
+ 73 -> TeVii S420 DVB-S                                    [d420:9022]
+ 74 -> Prolink Pixelview Global Extreme                    [1554:4976]
+ 75 -> PROF 7300 DVB-S/S2                                  [B033:3033]
diff --git a/Documentation/video4linux/CARDLIST.em28xx b/Documentation/video4linux/CARDLIST.em28xx
index 89c7f32..187cc48 100644
--- a/Documentation/video4linux/CARDLIST.em28xx
+++ b/Documentation/video4linux/CARDLIST.em28xx
@@ -1,5 +1,5 @@
   0 -> Unknown EM2800 video grabber             (em2800)        [eb1a:2800]
-  1 -> Unknown EM2750/28xx video grabber        (em2820/em2840) [eb1a:2820,eb1a:2821,eb1a:2860,eb1a:2861,eb1a:2870,eb1a:2881,eb1a:2883]
+  1 -> Unknown EM2750/28xx video grabber        (em2820/em2840) [eb1a:2820,eb1a:2860,eb1a:2861,eb1a:2870,eb1a:2881,eb1a:2883]
   2 -> Terratec Cinergy 250 USB                 (em2820/em2840) [0ccd:0036]
   3 -> Pinnacle PCTV USB 2                      (em2820/em2840) [2304:0208]
   4 -> Hauppauge WinTV USB 2                    (em2820/em2840) [2040:4200,2040:4201]
@@ -12,7 +12,7 @@
  11 -> Terratec Hybrid XS                       (em2880)        [0ccd:0042]
  12 -> Kworld PVR TV 2800 RF                    (em2820/em2840)
  13 -> Terratec Prodigy XS                      (em2880)        [0ccd:0047]
- 14 -> Pixelview Prolink PlayTV USB 2.0         (em2820/em2840)
+ 14 -> Pixelview Prolink PlayTV USB 2.0         (em2820/em2840) [eb1a:2821]
  15 -> V-Gear PocketTV                          (em2800)
  16 -> Hauppauge WinTV HVR 950                  (em2883)        [2040:6513,2040:6517,2040:651b,2040:651f]
  17 -> Pinnacle PCTV HD Pro Stick               (em2880)        [2304:0227]
@@ -46,7 +46,7 @@
  45 -> Pinnacle PCTV DVB-T                      (em2870)
  46 -> Compro, VideoMate U3                     (em2870)        [185b:2870]
  47 -> KWorld DVB-T 305U                        (em2880)        [eb1a:e305]
- 48 -> KWorld DVB-T 310U                        (em2880)
+ 48 -> KWorld DVB-T 310U                        (em2880)        [eb1a:e310]
  49 -> MSI DigiVox A/D                          (em2880)        [eb1a:e310]
  50 -> MSI DigiVox A/D II                       (em2880)        [eb1a:e320]
  51 -> Terratec Hybrid XS Secam                 (em2880)        [0ccd:004c]
diff --git a/Documentation/video4linux/CARDLIST.saa7134 b/Documentation/video4linux/CARDLIST.saa7134
index 39868af..dc67eef 100644
--- a/Documentation/video4linux/CARDLIST.saa7134
+++ b/Documentation/video4linux/CARDLIST.saa7134
@@ -76,7 +76,7 @@
  75 -> AVerMedia AVerTVHD MCE A180              [1461:1044]
  76 -> SKNet MonsterTV Mobile                   [1131:4ee9]
  77 -> Pinnacle PCTV 40i/50i/110i (saa7133)     [11bd:002e]
- 78 -> ASUSTeK P7131 Dual                       [1043:4862,1043:4857]
+ 78 -> ASUSTeK P7131 Dual                       [1043:4862]
  79 -> Sedna/MuchTV PC TV Cardbus TV/Radio (ITO25 Rev:2B)
  80 -> ASUS Digimatrix TV                       [1043:0210]
  81 -> Philips Tiger reference design           [1131:2018]
@@ -145,3 +145,9 @@
 144 -> Beholder BeholdTV M6 Extra               [5ace:6193]
 145 -> AVerMedia MiniPCI DVB-T Hybrid M103      [1461:f636]
 146 -> ASUSTeK P7131 Analog
+147 -> Asus Tiger 3in1                          [1043:4878]
+148 -> Encore ENLTV-FM v5.3                     [1a7f:2008]
+149 -> Avermedia PCI pure analog (M135A)        [1461:f11d]
+150 -> Zogis Real Angel 220
+151 -> ADS Tech Instant HDTV                    [1421:0380]
+152 -> Asus Tiger Rev:1.00                      [1043:4857]
diff --git a/Documentation/video4linux/CARDLIST.tuner b/Documentation/video4linux/CARDLIST.tuner
index 0e23946..30bbdda 100644
--- a/Documentation/video4linux/CARDLIST.tuner
+++ b/Documentation/video4linux/CARDLIST.tuner
@@ -74,3 +74,4 @@
 tuner=73 - Samsung TCPG 6121P30A
 tuner=75 - Philips TEA5761 FM Radio
 tuner=76 - Xceive 5000 tuner
+tuner=77 - TCL tuner MF02GIP-5N-E
diff --git a/Documentation/video4linux/gspca.txt b/Documentation/video4linux/gspca.txt
index 0f03900..004818f 100644
--- a/Documentation/video4linux/gspca.txt
+++ b/Documentation/video4linux/gspca.txt
@@ -7,6 +7,7 @@
 xxxx		vend:prod
 ----
 spca501		0000:0000	MystFromOri Unknow Camera
+m5602		0402:5602	ALi Video Camera Controller
 spca501		040a:0002	Kodak DVC-325
 spca500		040a:0300	Kodak EZ200
 zc3xx		041e:041e	Creative WebCam Live!
@@ -42,6 +43,7 @@
 zc3xx		0458:700c	Genius VideoCam V3
 zc3xx		0458:700f	Genius VideoCam Web V2
 sonixj		0458:7025	Genius Eye 311Q
+sonixj		0458:702e	Genius Slim 310 NB
 sonixj		045e:00f5	MicroSoft VX3000
 sonixj		045e:00f7	MicroSoft VX1000
 ov519		045e:028c	Micro$oft xbox cam
@@ -81,7 +83,7 @@
 spca561		046d:092c	Logitech QC chat Elch2
 spca561		046d:092d	Logitech QC Elch2
 spca561		046d:092e	Logitech QC Elch2
-spca561		046d:092f	Logitech QC Elch2
+spca561		046d:092f	Logitech  QuickCam Express Plus
 sunplus		046d:0960	Logitech ClickSmart 420
 sunplus		0471:0322	Philips DMVC1300K
 zc3xx		0471:0325	Philips SPC 200 NC
@@ -96,6 +98,29 @@
 sunplus		04a5:3008	Benq DC 1500
 sunplus		04a5:300a	Benq DC 3410
 spca500		04a5:300c	Benq DC 1016
+finepix		04cb:0104	Fujifilm FinePix 4800
+finepix		04cb:0109	Fujifilm FinePix A202
+finepix		04cb:010b	Fujifilm FinePix A203
+finepix		04cb:010f	Fujifilm FinePix A204
+finepix		04cb:0111	Fujifilm FinePix A205
+finepix		04cb:0113	Fujifilm FinePix A210
+finepix		04cb:0115	Fujifilm FinePix A303
+finepix		04cb:0117	Fujifilm FinePix A310
+finepix		04cb:0119	Fujifilm FinePix F401
+finepix		04cb:011b	Fujifilm FinePix F402
+finepix		04cb:011d	Fujifilm FinePix F410
+finepix		04cb:0121	Fujifilm FinePix F601
+finepix		04cb:0123	Fujifilm FinePix F700
+finepix		04cb:0125	Fujifilm FinePix M603
+finepix		04cb:0127	Fujifilm FinePix S300
+finepix		04cb:0129	Fujifilm FinePix S304
+finepix		04cb:012b	Fujifilm FinePix S500
+finepix		04cb:012d	Fujifilm FinePix S602
+finepix		04cb:012f	Fujifilm FinePix S700
+finepix		04cb:0131	Fujifilm FinePix unknown model
+finepix		04cb:013b	Fujifilm FinePix unknown model
+finepix		04cb:013d	Fujifilm FinePix unknown model
+finepix		04cb:013f	Fujifilm FinePix F420
 sunplus		04f1:1001	JVC GC A50
 spca561		04fc:0561	Flexcam 100
 sunplus		04fc:500c	Sunplus CA500C
@@ -181,6 +206,7 @@
 pac207		093a:2470	Genius GF112
 pac207		093a:2471	Genius VideoCam ge111
 pac207		093a:2472	Genius VideoCam ge110
+pac207		093a:2476	Genius e-Messenger 112
 pac7311		093a:2600	PAC7311 Typhoon
 pac7311		093a:2601	Philips SPC 610 NC
 pac7311		093a:2603	PAC7312
@@ -190,6 +216,7 @@
 pac7311		093a:2621	PAC731x
 pac7311		093a:2624	PAC7302
 pac7311		093a:2626	Labtec 2200
+pac7311		093a:262a	Webcam 300k
 zc3xx		0ac8:0302	Z-star Vimicro zc0302
 vc032x		0ac8:0321	Vimicro generic vc0321
 vc032x		0ac8:0323	Vimicro Vc0323
diff --git a/Documentation/video4linux/m5602.txt b/Documentation/video4linux/m5602.txt
new file mode 100644
index 0000000..4450ab1
--- /dev/null
+++ b/Documentation/video4linux/m5602.txt
@@ -0,0 +1,12 @@
+This document describes the ALi m5602 bridge connected
+to the following supported sensors:
+OmniVision OV9650,
+Samsung s5k83a,
+Samsung s5k4aa,
+Micron mt9m111,
+Pixel plus PO1030
+
+This driver mimics the windows drivers, which have a braindead implementation sending bayer-encoded frames at VGA resolution.
+In a perfect world we should be able to reprogram the m5602 and the connected sensor in hardware instead, supporting a range of resolutions and pixelformats
+
+Anyway, have fun and please report any bugs to m560x-driver-devel@lists.sourceforge.net
diff --git a/Documentation/video4linux/soc-camera.txt b/Documentation/video4linux/soc-camera.txt
new file mode 100644
index 0000000..178ef3c
--- /dev/null
+++ b/Documentation/video4linux/soc-camera.txt
@@ -0,0 +1,120 @@
+			Soc-Camera Subsystem
+			====================
+
+Terminology
+-----------
+
+The following terms are used in this document:
+ - camera / camera device / camera sensor - a video-camera sensor chip, capable
+   of connecting to a variety of systems and interfaces, typically uses i2c for
+   control and configuration, and a parallel or a serial bus for data.
+ - camera host - an interface, to which a camera is connected. Typically a
+   specialised interface, present on many SoCs, e.g., PXA27x and PXA3xx, SuperH,
+   AVR32, i.MX27, i.MX31.
+ - camera host bus - a connection between a camera host and a camera. Can be
+   parallel or serial, consists of data and control lines, e.g., clock, vertical
+   and horizontal synchronization signals.
+
+Purpose of the soc-camera subsystem
+-----------------------------------
+
+The soc-camera subsystem provides a unified API between camera host drivers and
+camera sensor drivers. It implements a V4L2 interface to the user, currently
+only the mmap method is supported.
+
+This subsystem has been written to connect drivers for System-on-Chip (SoC)
+video capture interfaces with drivers for CMOS camera sensor chips to enable
+the reuse of sensor drivers with various hosts. The subsystem has been designed
+to support multiple camera host interfaces and multiple cameras per interface,
+although most applications have only one camera sensor.
+
+Existing drivers
+----------------
+
+As of 2.6.27-rc4 there are two host drivers in the mainline: pxa_camera.c for
+PXA27x SoCs and sh_mobile_ceu_camera.c for SuperH SoCs, and four sensor drivers:
+mt9m001.c, mt9m111.c, mt9v022.c and a generic soc_camera_platform.c driver. This
+list is not supposed to be updated, look for more examples in your tree.
+
+Camera host API
+---------------
+
+A host camera driver is registered using the
+
+soc_camera_host_register(struct soc_camera_host *);
+
+function. The host object can be initialized as follows:
+
+static struct soc_camera_host pxa_soc_camera_host = {
+	.drv_name	= PXA_CAM_DRV_NAME,
+	.ops		= &pxa_soc_camera_host_ops,
+};
+
+All camera host methods are passed in a struct soc_camera_host_ops:
+
+static struct soc_camera_host_ops pxa_soc_camera_host_ops = {
+	.owner		= THIS_MODULE,
+	.add		= pxa_camera_add_device,
+	.remove		= pxa_camera_remove_device,
+	.suspend	= pxa_camera_suspend,
+	.resume		= pxa_camera_resume,
+	.set_fmt_cap	= pxa_camera_set_fmt_cap,
+	.try_fmt_cap	= pxa_camera_try_fmt_cap,
+	.init_videobuf	= pxa_camera_init_videobuf,
+	.reqbufs	= pxa_camera_reqbufs,
+	.poll		= pxa_camera_poll,
+	.querycap	= pxa_camera_querycap,
+	.try_bus_param	= pxa_camera_try_bus_param,
+	.set_bus_param	= pxa_camera_set_bus_param,
+};
+
+.add and .remove methods are called when a sensor is attached to or detached
+from the host, apart from performing host-internal tasks they shall also call
+sensor driver's .init and .release methods respectively. .suspend and .resume
+methods implement host's power-management functionality and its their
+responsibility to call respective sensor's methods. .try_bus_param and
+.set_bus_param are used to negotiate physical connection parameters between the
+host and the sensor. .init_videobuf is called by soc-camera core when a
+video-device is opened, further video-buffer management is implemented completely
+by the specific camera host driver. The rest of the methods are called from
+respective V4L2 operations.
+
+Camera API
+----------
+
+Sensor drivers can use struct soc_camera_link, typically provided by the
+platform, and used to specify to which camera host bus the sensor is connected,
+and arbitrarily provide platform .power and .reset methods for the camera.
+soc_camera_device_register() and soc_camera_device_unregister() functions are
+used to add a sensor driver to or remove one from the system. The registration
+function takes a pointer to struct soc_camera_device as the only parameter.
+This struct can be initialized as follows:
+
+	/* link to driver operations */
+	icd->ops	= &mt9m001_ops;
+	/* link to the underlying physical (e.g., i2c) device */
+	icd->control	= &client->dev;
+	/* window geometry */
+	icd->x_min	= 20;
+	icd->y_min	= 12;
+	icd->x_current	= 20;
+	icd->y_current	= 12;
+	icd->width_min	= 48;
+	icd->width_max	= 1280;
+	icd->height_min	= 32;
+	icd->height_max	= 1024;
+	icd->y_skip_top	= 1;
+	/* camera bus ID, typically obtained from platform data */
+	icd->iface	= icl->bus_id;
+
+struct soc_camera_ops provides .probe and .remove methods, which are called by
+the soc-camera core, when a camera is matched against or removed from a camera
+host bus, .init, .release, .suspend, and .resume are called from the camera host
+driver as discussed above. Other members of this struct provide respective V4L2
+functionality.
+
+struct soc_camera_device also links to an array of struct soc_camera_data_format,
+listing pixel formats, supported by the camera.
+
+--
+Author: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
diff --git a/Documentation/x86/00-INDEX b/Documentation/x86/00-INDEX
new file mode 100644
index 0000000..dbe3377
--- /dev/null
+++ b/Documentation/x86/00-INDEX
@@ -0,0 +1,4 @@
+00-INDEX
+	- this file
+mtrr.txt
+	- how to use x86 Memory Type Range Registers to increase performance
diff --git a/Documentation/x86/boot.txt b/Documentation/x86/boot.txt
new file mode 100644
index 0000000..83c0033
--- /dev/null
+++ b/Documentation/x86/boot.txt
@@ -0,0 +1,900 @@
+		     THE LINUX/x86 BOOT PROTOCOL
+		     ---------------------------
+
+On the x86 platform, the Linux kernel uses a rather complicated boot
+convention.  This has evolved partially due to historical aspects, as
+well as the desire in the early days to have the kernel itself be a
+bootable image, the complicated PC memory model and due to changed
+expectations in the PC industry caused by the effective demise of
+real-mode DOS as a mainstream operating system.
+
+Currently, the following versions of the Linux/x86 boot protocol exist.
+
+Old kernels:	zImage/Image support only.  Some very early kernels
+		may not even support a command line.
+
+Protocol 2.00:	(Kernel 1.3.73) Added bzImage and initrd support, as
+		well as a formalized way to communicate between the
+		boot loader and the kernel.  setup.S made relocatable,
+		although the traditional setup area still assumed
+		writable.
+
+Protocol 2.01:	(Kernel 1.3.76) Added a heap overrun warning.
+
+Protocol 2.02:	(Kernel 2.4.0-test3-pre3) New command line protocol.
+		Lower the conventional memory ceiling.	No overwrite
+		of the traditional setup area, thus making booting
+		safe for systems which use the EBDA from SMM or 32-bit
+		BIOS entry points.  zImage deprecated but still
+		supported.
+
+Protocol 2.03:	(Kernel 2.4.18-pre1) Explicitly makes the highest possible
+		initrd address available to the bootloader.
+
+Protocol 2.04:	(Kernel 2.6.14) Extend the syssize field to four bytes.
+
+Protocol 2.05:	(Kernel 2.6.20) Make protected mode kernel relocatable.
+		Introduce relocatable_kernel and kernel_alignment fields.
+
+Protocol 2.06:	(Kernel 2.6.22) Added a field that contains the size of
+		the boot command line.
+
+Protocol 2.07:	(Kernel 2.6.24) Added paravirtualised boot protocol.
+		Introduced hardware_subarch and hardware_subarch_data
+		and KEEP_SEGMENTS flag in load_flags.
+
+Protocol 2.08:	(Kernel 2.6.26) Added crc32 checksum and ELF format
+		payload. Introduced payload_offset and payload length
+		fields to aid in locating the payload.
+
+Protocol 2.09:	(Kernel 2.6.26) Added a field of 64-bit physical
+		pointer to single linked list of struct	setup_data.
+
+**** MEMORY LAYOUT
+
+The traditional memory map for the kernel loader, used for Image or
+zImage kernels, typically looks like:
+
+	|			 |
+0A0000	+------------------------+
+	|  Reserved for BIOS	 |	Do not use.  Reserved for BIOS EBDA.
+09A000	+------------------------+
+	|  Command line		 |
+	|  Stack/heap		 |	For use by the kernel real-mode code.
+098000	+------------------------+	
+	|  Kernel setup		 |	The kernel real-mode code.
+090200	+------------------------+
+	|  Kernel boot sector	 |	The kernel legacy boot sector.
+090000	+------------------------+
+	|  Protected-mode kernel |	The bulk of the kernel image.
+010000	+------------------------+
+	|  Boot loader		 |	<- Boot sector entry point 0000:7C00
+001000	+------------------------+
+	|  Reserved for MBR/BIOS |
+000800	+------------------------+
+	|  Typically used by MBR |
+000600	+------------------------+ 
+	|  BIOS use only	 |
+000000	+------------------------+
+
+
+When using bzImage, the protected-mode kernel was relocated to
+0x100000 ("high memory"), and the kernel real-mode block (boot sector,
+setup, and stack/heap) was made relocatable to any address between
+0x10000 and end of low memory. Unfortunately, in protocols 2.00 and
+2.01 the 0x90000+ memory range is still used internally by the kernel;
+the 2.02 protocol resolves that problem.
+
+It is desirable to keep the "memory ceiling" -- the highest point in
+low memory touched by the boot loader -- as low as possible, since
+some newer BIOSes have begun to allocate some rather large amounts of
+memory, called the Extended BIOS Data Area, near the top of low
+memory.	 The boot loader should use the "INT 12h" BIOS call to verify
+how much low memory is available.
+
+Unfortunately, if INT 12h reports that the amount of memory is too
+low, there is usually nothing the boot loader can do but to report an
+error to the user.  The boot loader should therefore be designed to
+take up as little space in low memory as it reasonably can.  For
+zImage or old bzImage kernels, which need data written into the
+0x90000 segment, the boot loader should make sure not to use memory
+above the 0x9A000 point; too many BIOSes will break above that point.
+
+For a modern bzImage kernel with boot protocol version >= 2.02, a
+memory layout like the following is suggested:
+
+	~                        ~
+        |  Protected-mode kernel |
+100000  +------------------------+
+	|  I/O memory hole	 |
+0A0000	+------------------------+
+	|  Reserved for BIOS	 |	Leave as much as possible unused
+	~                        ~
+	|  Command line		 |	(Can also be below the X+10000 mark)
+X+10000	+------------------------+
+	|  Stack/heap		 |	For use by the kernel real-mode code.
+X+08000	+------------------------+	
+	|  Kernel setup		 |	The kernel real-mode code.
+	|  Kernel boot sector	 |	The kernel legacy boot sector.
+X       +------------------------+
+	|  Boot loader		 |	<- Boot sector entry point 0000:7C00
+001000	+------------------------+
+	|  Reserved for MBR/BIOS |
+000800	+------------------------+
+	|  Typically used by MBR |
+000600	+------------------------+ 
+	|  BIOS use only	 |
+000000	+------------------------+
+
+... where the address X is as low as the design of the boot loader
+permits.
+
+
+**** THE REAL-MODE KERNEL HEADER
+
+In the following text, and anywhere in the kernel boot sequence, "a
+sector" refers to 512 bytes.  It is independent of the actual sector
+size of the underlying medium.
+
+The first step in loading a Linux kernel should be to load the
+real-mode code (boot sector and setup code) and then examine the
+following header at offset 0x01f1.  The real-mode code can total up to
+32K, although the boot loader may choose to load only the first two
+sectors (1K) and then examine the bootup sector size.
+
+The header looks like:
+
+Offset	Proto	Name		Meaning
+/Size
+
+01F1/1	ALL(1	setup_sects	The size of the setup in sectors
+01F2/2	ALL	root_flags	If set, the root is mounted readonly
+01F4/4	2.04+(2	syssize		The size of the 32-bit code in 16-byte paras
+01F8/2	ALL	ram_size	DO NOT USE - for bootsect.S use only
+01FA/2	ALL	vid_mode	Video mode control
+01FC/2	ALL	root_dev	Default root device number
+01FE/2	ALL	boot_flag	0xAA55 magic number
+0200/2	2.00+	jump		Jump instruction
+0202/4	2.00+	header		Magic signature "HdrS"
+0206/2	2.00+	version		Boot protocol version supported
+0208/4	2.00+	realmode_swtch	Boot loader hook (see below)
+020C/2	2.00+	start_sys	The load-low segment (0x1000) (obsolete)
+020E/2	2.00+	kernel_version	Pointer to kernel version string
+0210/1	2.00+	type_of_loader	Boot loader identifier
+0211/1	2.00+	loadflags	Boot protocol option flags
+0212/2	2.00+	setup_move_size	Move to high memory size (used with hooks)
+0214/4	2.00+	code32_start	Boot loader hook (see below)
+0218/4	2.00+	ramdisk_image	initrd load address (set by boot loader)
+021C/4	2.00+	ramdisk_size	initrd size (set by boot loader)
+0220/4	2.00+	bootsect_kludge	DO NOT USE - for bootsect.S use only
+0224/2	2.01+	heap_end_ptr	Free memory after setup end
+0226/2	N/A	pad1		Unused
+0228/4	2.02+	cmd_line_ptr	32-bit pointer to the kernel command line
+022C/4	2.03+	initrd_addr_max	Highest legal initrd address
+0230/4	2.05+	kernel_alignment Physical addr alignment required for kernel
+0234/1	2.05+	relocatable_kernel Whether kernel is relocatable or not
+0235/3	N/A	pad2		Unused
+0238/4	2.06+	cmdline_size	Maximum size of the kernel command line
+023C/4	2.07+	hardware_subarch Hardware subarchitecture
+0240/8	2.07+	hardware_subarch_data Subarchitecture-specific data
+0248/4	2.08+	payload_offset	Offset of kernel payload
+024C/4	2.08+	payload_length	Length of kernel payload
+0250/8	2.09+	setup_data	64-bit physical pointer to linked list
+				of struct setup_data
+
+(1) For backwards compatibility, if the setup_sects field contains 0, the
+    real value is 4.
+
+(2) For boot protocol prior to 2.04, the upper two bytes of the syssize
+    field are unusable, which means the size of a bzImage kernel
+    cannot be determined.
+
+If the "HdrS" (0x53726448) magic number is not found at offset 0x202,
+the boot protocol version is "old".  Loading an old kernel, the
+following parameters should be assumed:
+
+	Image type = zImage
+	initrd not supported
+	Real-mode kernel must be located at 0x90000.
+
+Otherwise, the "version" field contains the protocol version,
+e.g. protocol version 2.01 will contain 0x0201 in this field.  When
+setting fields in the header, you must make sure only to set fields
+supported by the protocol version in use.
+
+
+**** DETAILS OF HEADER FIELDS
+
+For each field, some are information from the kernel to the bootloader
+("read"), some are expected to be filled out by the bootloader
+("write"), and some are expected to be read and modified by the
+bootloader ("modify").
+
+All general purpose boot loaders should write the fields marked
+(obligatory).  Boot loaders who want to load the kernel at a
+nonstandard address should fill in the fields marked (reloc); other
+boot loaders can ignore those fields.
+
+The byte order of all fields is littleendian (this is x86, after all.)
+
+Field name:	setup_sects
+Type:		read
+Offset/size:	0x1f1/1
+Protocol:	ALL
+
+  The size of the setup code in 512-byte sectors.  If this field is
+  0, the real value is 4.  The real-mode code consists of the boot
+  sector (always one 512-byte sector) plus the setup code.
+
+Field name:	 root_flags
+Type:		 modify (optional)
+Offset/size:	 0x1f2/2
+Protocol:	 ALL
+
+  If this field is nonzero, the root defaults to readonly.  The use of
+  this field is deprecated; use the "ro" or "rw" options on the
+  command line instead.
+
+Field name:	syssize
+Type:		read
+Offset/size:	0x1f4/4 (protocol 2.04+) 0x1f4/2 (protocol ALL)
+Protocol:	2.04+
+
+  The size of the protected-mode code in units of 16-byte paragraphs.
+  For protocol versions older than 2.04 this field is only two bytes
+  wide, and therefore cannot be trusted for the size of a kernel if
+  the LOAD_HIGH flag is set.
+
+Field name:	ram_size
+Type:		kernel internal
+Offset/size:	0x1f8/2
+Protocol:	ALL
+
+  This field is obsolete.
+
+Field name:	vid_mode
+Type:		modify (obligatory)
+Offset/size:	0x1fa/2
+
+  Please see the section on SPECIAL COMMAND LINE OPTIONS.
+
+Field name:	root_dev
+Type:		modify (optional)
+Offset/size:	0x1fc/2
+Protocol:	ALL
+
+  The default root device device number.  The use of this field is
+  deprecated, use the "root=" option on the command line instead.
+
+Field name:	boot_flag
+Type:		read
+Offset/size:	0x1fe/2
+Protocol:	ALL
+
+  Contains 0xAA55.  This is the closest thing old Linux kernels have
+  to a magic number.
+
+Field name:	jump
+Type:		read
+Offset/size:	0x200/2
+Protocol:	2.00+
+
+  Contains an x86 jump instruction, 0xEB followed by a signed offset
+  relative to byte 0x202.  This can be used to determine the size of
+  the header.
+
+Field name:	header
+Type:		read
+Offset/size:	0x202/4
+Protocol:	2.00+
+
+  Contains the magic number "HdrS" (0x53726448).
+
+Field name:	version
+Type:		read
+Offset/size:	0x206/2
+Protocol:	2.00+
+
+  Contains the boot protocol version, in (major << 8)+minor format,
+  e.g. 0x0204 for version 2.04, and 0x0a11 for a hypothetical version
+  10.17.
+
+Field name:	readmode_swtch
+Type:		modify (optional)
+Offset/size:	0x208/4
+Protocol:	2.00+
+
+  Boot loader hook (see ADVANCED BOOT LOADER HOOKS below.)
+
+Field name:	start_sys
+Type:		read
+Offset/size:	0x20c/2
+Protocol:	2.00+
+
+  The load low segment (0x1000).  Obsolete.
+
+Field name:	kernel_version
+Type:		read
+Offset/size:	0x20e/2
+Protocol:	2.00+
+
+  If set to a nonzero value, contains a pointer to a NUL-terminated
+  human-readable kernel version number string, less 0x200.  This can
+  be used to display the kernel version to the user.  This value
+  should be less than (0x200*setup_sects).
+
+  For example, if this value is set to 0x1c00, the kernel version
+  number string can be found at offset 0x1e00 in the kernel file.
+  This is a valid value if and only if the "setup_sects" field
+  contains the value 15 or higher, as:
+
+	0x1c00  < 15*0x200 (= 0x1e00) but
+	0x1c00 >= 14*0x200 (= 0x1c00)
+
+	0x1c00 >> 9 = 14, so the minimum value for setup_secs is 15.
+
+Field name:	type_of_loader
+Type:		write (obligatory)
+Offset/size:	0x210/1
+Protocol:	2.00+
+
+  If your boot loader has an assigned id (see table below), enter
+  0xTV here, where T is an identifier for the boot loader and V is
+  a version number.  Otherwise, enter 0xFF here.
+
+  Assigned boot loader ids:
+	0  LILO			(0x00 reserved for pre-2.00 bootloader)
+	1  Loadlin
+	2  bootsect-loader	(0x20, all other values reserved)
+	3  SYSLINUX
+	4  EtherBoot
+	5  ELILO
+	7  GRuB
+	8  U-BOOT
+	9  Xen
+	A  Gujin
+	B  Qemu
+
+  Please contact <hpa@zytor.com> if you need a bootloader ID
+  value assigned.
+
+Field name:	loadflags
+Type:		modify (obligatory)
+Offset/size:	0x211/1
+Protocol:	2.00+
+
+  This field is a bitmask.
+
+  Bit 0 (read):	LOADED_HIGH
+	- If 0, the protected-mode code is loaded at 0x10000.
+	- If 1, the protected-mode code is loaded at 0x100000.
+
+  Bit 5 (write): QUIET_FLAG
+	- If 0, print early messages.
+	- If 1, suppress early messages.
+		This requests to the kernel (decompressor and early
+		kernel) to not write early messages that require
+		accessing the display hardware directly.
+
+  Bit 6 (write): KEEP_SEGMENTS
+	Protocol: 2.07+
+	- If 0, reload the segment registers in the 32bit entry point.
+	- If 1, do not reload the segment registers in the 32bit entry point.
+		Assume that %cs %ds %ss %es are all set to flat segments with
+		a base of 0 (or the equivalent for their environment).
+
+  Bit 7 (write): CAN_USE_HEAP
+	Set this bit to 1 to indicate that the value entered in the
+	heap_end_ptr is valid.  If this field is clear, some setup code
+	functionality will be disabled.
+
+Field name:	setup_move_size
+Type:		modify (obligatory)
+Offset/size:	0x212/2
+Protocol:	2.00-2.01
+
+  When using protocol 2.00 or 2.01, if the real mode kernel is not
+  loaded at 0x90000, it gets moved there later in the loading
+  sequence.  Fill in this field if you want additional data (such as
+  the kernel command line) moved in addition to the real-mode kernel
+  itself.
+
+  The unit is bytes starting with the beginning of the boot sector.
+  
+  This field is can be ignored when the protocol is 2.02 or higher, or
+  if the real-mode code is loaded at 0x90000.
+
+Field name:	code32_start
+Type:		modify (optional, reloc)
+Offset/size:	0x214/4
+Protocol:	2.00+
+
+  The address to jump to in protected mode.  This defaults to the load
+  address of the kernel, and can be used by the boot loader to
+  determine the proper load address.
+
+  This field can be modified for two purposes:
+
+  1. as a boot loader hook (see ADVANCED BOOT LOADER HOOKS below.)
+
+  2. if a bootloader which does not install a hook loads a
+     relocatable kernel at a nonstandard address it will have to modify
+     this field to point to the load address.
+
+Field name:	ramdisk_image
+Type:		write (obligatory)
+Offset/size:	0x218/4
+Protocol:	2.00+
+
+  The 32-bit linear address of the initial ramdisk or ramfs.  Leave at
+  zero if there is no initial ramdisk/ramfs.
+
+Field name:	ramdisk_size
+Type:		write (obligatory)
+Offset/size:	0x21c/4
+Protocol:	2.00+
+
+  Size of the initial ramdisk or ramfs.  Leave at zero if there is no
+  initial ramdisk/ramfs.
+
+Field name:	bootsect_kludge
+Type:		kernel internal
+Offset/size:	0x220/4
+Protocol:	2.00+
+
+  This field is obsolete.
+
+Field name:	heap_end_ptr
+Type:		write (obligatory)
+Offset/size:	0x224/2
+Protocol:	2.01+
+
+  Set this field to the offset (from the beginning of the real-mode
+  code) of the end of the setup stack/heap, minus 0x0200.
+
+Field name:	cmd_line_ptr
+Type:		write (obligatory)
+Offset/size:	0x228/4
+Protocol:	2.02+
+
+  Set this field to the linear address of the kernel command line.
+  The kernel command line can be located anywhere between the end of
+  the setup heap and 0xA0000; it does not have to be located in the
+  same 64K segment as the real-mode code itself.
+
+  Fill in this field even if your boot loader does not support a
+  command line, in which case you can point this to an empty string
+  (or better yet, to the string "auto".)  If this field is left at
+  zero, the kernel will assume that your boot loader does not support
+  the 2.02+ protocol.
+
+Field name:	initrd_addr_max
+Type:		read
+Offset/size:	0x22c/4
+Protocol:	2.03+
+
+  The maximum address that may be occupied by the initial
+  ramdisk/ramfs contents.  For boot protocols 2.02 or earlier, this
+  field is not present, and the maximum address is 0x37FFFFFF.  (This
+  address is defined as the address of the highest safe byte, so if
+  your ramdisk is exactly 131072 bytes long and this field is
+  0x37FFFFFF, you can start your ramdisk at 0x37FE0000.)
+
+Field name:	kernel_alignment
+Type:		read (reloc)
+Offset/size:	0x230/4
+Protocol:	2.05+
+
+  Alignment unit required by the kernel (if relocatable_kernel is true.)
+
+Field name:	relocatable_kernel
+Type:		read (reloc)
+Offset/size:	0x234/1
+Protocol:	2.05+
+
+  If this field is nonzero, the protected-mode part of the kernel can
+  be loaded at any address that satisfies the kernel_alignment field.
+  After loading, the boot loader must set the code32_start field to
+  point to the loaded code, or to a boot loader hook.
+
+Field name:	cmdline_size
+Type:		read
+Offset/size:	0x238/4
+Protocol:	2.06+
+
+  The maximum size of the command line without the terminating
+  zero. This means that the command line can contain at most
+  cmdline_size characters. With protocol version 2.05 and earlier, the
+  maximum size was 255.
+
+Field name:	hardware_subarch
+Type:		write (optional, defaults to x86/PC)
+Offset/size:	0x23c/4
+Protocol:	2.07+
+
+  In a paravirtualized environment the hardware low level architectural
+  pieces such as interrupt handling, page table handling, and
+  accessing process control registers needs to be done differently.
+
+  This field allows the bootloader to inform the kernel we are in one
+  one of those environments.
+
+  0x00000000	The default x86/PC environment
+  0x00000001	lguest
+  0x00000002	Xen
+
+Field name:	hardware_subarch_data
+Type:		write (subarch-dependent)
+Offset/size:	0x240/8
+Protocol:	2.07+
+
+  A pointer to data that is specific to hardware subarch
+  This field is currently unused for the default x86/PC environment,
+  do not modify.
+
+Field name:	payload_offset
+Type:		read
+Offset/size:	0x248/4
+Protocol:	2.08+
+
+  If non-zero then this field contains the offset from the end of the
+  real-mode code to the payload.
+
+  The payload may be compressed. The format of both the compressed and
+  uncompressed data should be determined using the standard magic
+  numbers. Currently only gzip compressed ELF is used.
+  
+Field name:	payload_length
+Type:		read
+Offset/size:	0x24c/4
+Protocol:	2.08+
+
+  The length of the payload.
+
+Field name:	setup_data
+Type:		write (special)
+Offset/size:	0x250/8
+Protocol:	2.09+
+
+  The 64-bit physical pointer to NULL terminated single linked list of
+  struct setup_data. This is used to define a more extensible boot
+  parameters passing mechanism. The definition of struct setup_data is
+  as follow:
+
+  struct setup_data {
+	  u64 next;
+	  u32 type;
+	  u32 len;
+	  u8  data[0];
+  };
+
+  Where, the next is a 64-bit physical pointer to the next node of
+  linked list, the next field of the last node is 0; the type is used
+  to identify the contents of data; the len is the length of data
+  field; the data holds the real payload.
+
+  This list may be modified at a number of points during the bootup
+  process.  Therefore, when modifying this list one should always make
+  sure to consider the case where the linked list already contains
+  entries.
+
+
+**** THE IMAGE CHECKSUM
+
+From boot protocol version 2.08 onwards the CRC-32 is calculated over
+the entire file using the characteristic polynomial 0x04C11DB7 and an
+initial remainder of 0xffffffff.  The checksum is appended to the
+file; therefore the CRC of the file up to the limit specified in the
+syssize field of the header is always 0.
+
+
+**** THE KERNEL COMMAND LINE
+
+The kernel command line has become an important way for the boot
+loader to communicate with the kernel.  Some of its options are also
+relevant to the boot loader itself, see "special command line options"
+below.
+
+The kernel command line is a null-terminated string. The maximum
+length can be retrieved from the field cmdline_size.  Before protocol
+version 2.06, the maximum was 255 characters.  A string that is too
+long will be automatically truncated by the kernel.
+
+If the boot protocol version is 2.02 or later, the address of the
+kernel command line is given by the header field cmd_line_ptr (see
+above.)  This address can be anywhere between the end of the setup
+heap and 0xA0000.
+
+If the protocol version is *not* 2.02 or higher, the kernel
+command line is entered using the following protocol:
+
+	At offset 0x0020 (word), "cmd_line_magic", enter the magic
+	number 0xA33F.
+
+	At offset 0x0022 (word), "cmd_line_offset", enter the offset
+	of the kernel command line (relative to the start of the
+	real-mode kernel).
+	
+	The kernel command line *must* be within the memory region
+	covered by setup_move_size, so you may need to adjust this
+	field.
+
+
+**** MEMORY LAYOUT OF THE REAL-MODE CODE
+
+The real-mode code requires a stack/heap to be set up, as well as
+memory allocated for the kernel command line.  This needs to be done
+in the real-mode accessible memory in bottom megabyte.
+
+It should be noted that modern machines often have a sizable Extended
+BIOS Data Area (EBDA).  As a result, it is advisable to use as little
+of the low megabyte as possible.
+
+Unfortunately, under the following circumstances the 0x90000 memory
+segment has to be used:
+
+	- When loading a zImage kernel ((loadflags & 0x01) == 0).
+	- When loading a 2.01 or earlier boot protocol kernel.
+
+	  -> For the 2.00 and 2.01 boot protocols, the real-mode code
+	     can be loaded at another address, but it is internally
+	     relocated to 0x90000.  For the "old" protocol, the
+	     real-mode code must be loaded at 0x90000.
+
+When loading at 0x90000, avoid using memory above 0x9a000.
+
+For boot protocol 2.02 or higher, the command line does not have to be
+located in the same 64K segment as the real-mode setup code; it is
+thus permitted to give the stack/heap the full 64K segment and locate
+the command line above it.
+
+The kernel command line should not be located below the real-mode
+code, nor should it be located in high memory.
+
+
+**** SAMPLE BOOT CONFIGURATION
+
+As a sample configuration, assume the following layout of the real
+mode segment:
+
+    When loading below 0x90000, use the entire segment:
+
+	0x0000-0x7fff	Real mode kernel
+	0x8000-0xdfff	Stack and heap
+	0xe000-0xffff	Kernel command line
+
+    When loading at 0x90000 OR the protocol version is 2.01 or earlier:
+
+	0x0000-0x7fff	Real mode kernel
+	0x8000-0x97ff	Stack and heap
+	0x9800-0x9fff	Kernel command line
+
+Such a boot loader should enter the following fields in the header:
+
+	unsigned long base_ptr;	/* base address for real-mode segment */
+
+	if ( setup_sects == 0 ) {
+		setup_sects = 4;
+	}
+
+	if ( protocol >= 0x0200 ) {
+		type_of_loader = <type code>;
+		if ( loading_initrd ) {
+			ramdisk_image = <initrd_address>;
+			ramdisk_size = <initrd_size>;
+		}
+
+		if ( protocol >= 0x0202 && loadflags & 0x01 )
+			heap_end = 0xe000;
+		else
+			heap_end = 0x9800;
+
+		if ( protocol >= 0x0201 ) {
+			heap_end_ptr = heap_end - 0x200;
+			loadflags |= 0x80; /* CAN_USE_HEAP */
+		}
+
+		if ( protocol >= 0x0202 ) {
+			cmd_line_ptr = base_ptr + heap_end;
+			strcpy(cmd_line_ptr, cmdline);
+		} else {
+			cmd_line_magic	= 0xA33F;
+			cmd_line_offset = heap_end;
+			setup_move_size = heap_end + strlen(cmdline)+1;
+			strcpy(base_ptr+cmd_line_offset, cmdline);
+		}
+	} else {
+		/* Very old kernel */
+
+		heap_end = 0x9800;
+
+		cmd_line_magic	= 0xA33F;
+		cmd_line_offset = heap_end;
+
+		/* A very old kernel MUST have its real-mode code
+		   loaded at 0x90000 */
+
+		if ( base_ptr != 0x90000 ) {
+			/* Copy the real-mode kernel */
+			memcpy(0x90000, base_ptr, (setup_sects+1)*512);
+			base_ptr = 0x90000;		 /* Relocated */
+		}
+
+		strcpy(0x90000+cmd_line_offset, cmdline);
+
+		/* It is recommended to clear memory up to the 32K mark */
+		memset(0x90000 + (setup_sects+1)*512, 0,
+		       (64-(setup_sects+1))*512);
+	}
+
+
+**** LOADING THE REST OF THE KERNEL
+
+The 32-bit (non-real-mode) kernel starts at offset (setup_sects+1)*512
+in the kernel file (again, if setup_sects == 0 the real value is 4.)
+It should be loaded at address 0x10000 for Image/zImage kernels and
+0x100000 for bzImage kernels.
+
+The kernel is a bzImage kernel if the protocol >= 2.00 and the 0x01
+bit (LOAD_HIGH) in the loadflags field is set:
+
+	is_bzImage = (protocol >= 0x0200) && (loadflags & 0x01);
+	load_address = is_bzImage ? 0x100000 : 0x10000;
+
+Note that Image/zImage kernels can be up to 512K in size, and thus use
+the entire 0x10000-0x90000 range of memory.  This means it is pretty
+much a requirement for these kernels to load the real-mode part at
+0x90000.  bzImage kernels allow much more flexibility.
+
+
+**** SPECIAL COMMAND LINE OPTIONS
+
+If the command line provided by the boot loader is entered by the
+user, the user may expect the following command line options to work.
+They should normally not be deleted from the kernel command line even
+though not all of them are actually meaningful to the kernel.  Boot
+loader authors who need additional command line options for the boot
+loader itself should get them registered in
+Documentation/kernel-parameters.txt to make sure they will not
+conflict with actual kernel options now or in the future.
+
+  vga=<mode>
+	<mode> here is either an integer (in C notation, either
+	decimal, octal, or hexadecimal) or one of the strings
+	"normal" (meaning 0xFFFF), "ext" (meaning 0xFFFE) or "ask"
+	(meaning 0xFFFD).  This value should be entered into the
+	vid_mode field, as it is used by the kernel before the command
+	line is parsed.
+
+  mem=<size>
+	<size> is an integer in C notation optionally followed by
+	(case insensitive) K, M, G, T, P or E (meaning << 10, << 20,
+	<< 30, << 40, << 50 or << 60).  This specifies the end of
+	memory to the kernel. This affects the possible placement of
+	an initrd, since an initrd should be placed near end of
+	memory.  Note that this is an option to *both* the kernel and
+	the bootloader!
+
+  initrd=<file>
+	An initrd should be loaded.  The meaning of <file> is
+	obviously bootloader-dependent, and some boot loaders
+	(e.g. LILO) do not have such a command.
+
+In addition, some boot loaders add the following options to the
+user-specified command line:
+
+  BOOT_IMAGE=<file>
+	The boot image which was loaded.  Again, the meaning of <file>
+	is obviously bootloader-dependent.
+
+  auto
+	The kernel was booted without explicit user intervention.
+
+If these options are added by the boot loader, it is highly
+recommended that they are located *first*, before the user-specified
+or configuration-specified command line.  Otherwise, "init=/bin/sh"
+gets confused by the "auto" option.
+
+
+**** RUNNING THE KERNEL
+
+The kernel is started by jumping to the kernel entry point, which is
+located at *segment* offset 0x20 from the start of the real mode
+kernel.  This means that if you loaded your real-mode kernel code at
+0x90000, the kernel entry point is 9020:0000.
+
+At entry, ds = es = ss should point to the start of the real-mode
+kernel code (0x9000 if the code is loaded at 0x90000), sp should be
+set up properly, normally pointing to the top of the heap, and
+interrupts should be disabled.  Furthermore, to guard against bugs in
+the kernel, it is recommended that the boot loader sets fs = gs = ds =
+es = ss.
+
+In our example from above, we would do:
+
+	/* Note: in the case of the "old" kernel protocol, base_ptr must
+	   be == 0x90000 at this point; see the previous sample code */
+
+	seg = base_ptr >> 4;
+
+	cli();	/* Enter with interrupts disabled! */
+
+	/* Set up the real-mode kernel stack */
+	_SS = seg;
+	_SP = heap_end;
+
+	_DS = _ES = _FS = _GS = seg;
+	jmp_far(seg+0x20, 0);	/* Run the kernel */
+
+If your boot sector accesses a floppy drive, it is recommended to
+switch off the floppy motor before running the kernel, since the
+kernel boot leaves interrupts off and thus the motor will not be
+switched off, especially if the loaded kernel has the floppy driver as
+a demand-loaded module!
+
+
+**** ADVANCED BOOT LOADER HOOKS
+
+If the boot loader runs in a particularly hostile environment (such as
+LOADLIN, which runs under DOS) it may be impossible to follow the
+standard memory location requirements.  Such a boot loader may use the
+following hooks that, if set, are invoked by the kernel at the
+appropriate time.  The use of these hooks should probably be
+considered an absolutely last resort!
+
+IMPORTANT: All the hooks are required to preserve %esp, %ebp, %esi and
+%edi across invocation.
+
+  realmode_swtch:
+	A 16-bit real mode far subroutine invoked immediately before
+	entering protected mode.  The default routine disables NMI, so
+	your routine should probably do so, too.
+
+  code32_start:
+	A 32-bit flat-mode routine *jumped* to immediately after the
+	transition to protected mode, but before the kernel is
+	uncompressed.  No segments, except CS, are guaranteed to be
+	set up (current kernels do, but older ones do not); you should
+	set them up to BOOT_DS (0x18) yourself.
+
+	After completing your hook, you should jump to the address
+	that was in this field before your boot loader overwrote it
+	(relocated, if appropriate.)
+
+
+**** 32-bit BOOT PROTOCOL
+
+For machine with some new BIOS other than legacy BIOS, such as EFI,
+LinuxBIOS, etc, and kexec, the 16-bit real mode setup code in kernel
+based on legacy BIOS can not be used, so a 32-bit boot protocol needs
+to be defined.
+
+In 32-bit boot protocol, the first step in loading a Linux kernel
+should be to setup the boot parameters (struct boot_params,
+traditionally known as "zero page"). The memory for struct boot_params
+should be allocated and initialized to all zero. Then the setup header
+from offset 0x01f1 of kernel image on should be loaded into struct
+boot_params and examined. The end of setup header can be calculated as
+follow:
+
+	0x0202 + byte value at offset 0x0201
+
+In addition to read/modify/write the setup header of the struct
+boot_params as that of 16-bit boot protocol, the boot loader should
+also fill the additional fields of the struct boot_params as that
+described in zero-page.txt.
+
+After setupping the struct boot_params, the boot loader can load the
+32/64-bit kernel in the same way as that of 16-bit boot protocol.
+
+In 32-bit boot protocol, the kernel is started by jumping to the
+32-bit kernel entry point, which is the start address of loaded
+32/64-bit kernel.
+
+At entry, the CPU must be in 32-bit protected mode with paging
+disabled; a GDT must be loaded with the descriptors for selectors
+__BOOT_CS(0x10) and __BOOT_DS(0x18); both descriptors must be 4G flat
+segment; __BOOS_CS must have execute/read permission, and __BOOT_DS
+must have read/write permission; CS must be __BOOT_CS and DS, ES, SS
+must be __BOOT_DS; interrupt must be disabled; %esi must hold the base
+address of the struct boot_params; %ebp, %edi and %ebx must be zero.
diff --git a/Documentation/x86/i386/boot.txt b/Documentation/x86/i386/boot.txt
deleted file mode 100644
index 147bfe5..0000000
--- a/Documentation/x86/i386/boot.txt
+++ /dev/null
@@ -1,900 +0,0 @@
-		     THE LINUX/x86 BOOT PROTOCOL
-		     ---------------------------
-
-On the x86 platform, the Linux kernel uses a rather complicated boot
-convention.  This has evolved partially due to historical aspects, as
-well as the desire in the early days to have the kernel itself be a
-bootable image, the complicated PC memory model and due to changed
-expectations in the PC industry caused by the effective demise of
-real-mode DOS as a mainstream operating system.
-
-Currently, the following versions of the Linux/x86 boot protocol exist.
-
-Old kernels:	zImage/Image support only.  Some very early kernels
-		may not even support a command line.
-
-Protocol 2.00:	(Kernel 1.3.73) Added bzImage and initrd support, as
-		well as a formalized way to communicate between the
-		boot loader and the kernel.  setup.S made relocatable,
-		although the traditional setup area still assumed
-		writable.
-
-Protocol 2.01:	(Kernel 1.3.76) Added a heap overrun warning.
-
-Protocol 2.02:	(Kernel 2.4.0-test3-pre3) New command line protocol.
-		Lower the conventional memory ceiling.	No overwrite
-		of the traditional setup area, thus making booting
-		safe for systems which use the EBDA from SMM or 32-bit
-		BIOS entry points.  zImage deprecated but still
-		supported.
-
-Protocol 2.03:	(Kernel 2.4.18-pre1) Explicitly makes the highest possible
-		initrd address available to the bootloader.
-
-Protocol 2.04:	(Kernel 2.6.14) Extend the syssize field to four bytes.
-
-Protocol 2.05:	(Kernel 2.6.20) Make protected mode kernel relocatable.
-		Introduce relocatable_kernel and kernel_alignment fields.
-
-Protocol 2.06:	(Kernel 2.6.22) Added a field that contains the size of
-		the boot command line.
-
-Protocol 2.07:	(Kernel 2.6.24) Added paravirtualised boot protocol.
-		Introduced hardware_subarch and hardware_subarch_data
-		and KEEP_SEGMENTS flag in load_flags.
-
-Protocol 2.08:	(Kernel 2.6.26) Added crc32 checksum and ELF format
-		payload. Introduced payload_offset and payload length
-		fields to aid in locating the payload.
-
-Protocol 2.09:	(Kernel 2.6.26) Added a field of 64-bit physical
-		pointer to single linked list of struct	setup_data.
-
-**** MEMORY LAYOUT
-
-The traditional memory map for the kernel loader, used for Image or
-zImage kernels, typically looks like:
-
-	|			 |
-0A0000	+------------------------+
-	|  Reserved for BIOS	 |	Do not use.  Reserved for BIOS EBDA.
-09A000	+------------------------+
-	|  Command line		 |
-	|  Stack/heap		 |	For use by the kernel real-mode code.
-098000	+------------------------+	
-	|  Kernel setup		 |	The kernel real-mode code.
-090200	+------------------------+
-	|  Kernel boot sector	 |	The kernel legacy boot sector.
-090000	+------------------------+
-	|  Protected-mode kernel |	The bulk of the kernel image.
-010000	+------------------------+
-	|  Boot loader		 |	<- Boot sector entry point 0000:7C00
-001000	+------------------------+
-	|  Reserved for MBR/BIOS |
-000800	+------------------------+
-	|  Typically used by MBR |
-000600	+------------------------+ 
-	|  BIOS use only	 |
-000000	+------------------------+
-
-
-When using bzImage, the protected-mode kernel was relocated to
-0x100000 ("high memory"), and the kernel real-mode block (boot sector,
-setup, and stack/heap) was made relocatable to any address between
-0x10000 and end of low memory. Unfortunately, in protocols 2.00 and
-2.01 the 0x90000+ memory range is still used internally by the kernel;
-the 2.02 protocol resolves that problem.
-
-It is desirable to keep the "memory ceiling" -- the highest point in
-low memory touched by the boot loader -- as low as possible, since
-some newer BIOSes have begun to allocate some rather large amounts of
-memory, called the Extended BIOS Data Area, near the top of low
-memory.	 The boot loader should use the "INT 12h" BIOS call to verify
-how much low memory is available.
-
-Unfortunately, if INT 12h reports that the amount of memory is too
-low, there is usually nothing the boot loader can do but to report an
-error to the user.  The boot loader should therefore be designed to
-take up as little space in low memory as it reasonably can.  For
-zImage or old bzImage kernels, which need data written into the
-0x90000 segment, the boot loader should make sure not to use memory
-above the 0x9A000 point; too many BIOSes will break above that point.
-
-For a modern bzImage kernel with boot protocol version >= 2.02, a
-memory layout like the following is suggested:
-
-	~                        ~
-        |  Protected-mode kernel |
-100000  +------------------------+
-	|  I/O memory hole	 |
-0A0000	+------------------------+
-	|  Reserved for BIOS	 |	Leave as much as possible unused
-	~                        ~
-	|  Command line		 |	(Can also be below the X+10000 mark)
-X+10000	+------------------------+
-	|  Stack/heap		 |	For use by the kernel real-mode code.
-X+08000	+------------------------+	
-	|  Kernel setup		 |	The kernel real-mode code.
-	|  Kernel boot sector	 |	The kernel legacy boot sector.
-X       +------------------------+
-	|  Boot loader		 |	<- Boot sector entry point 0000:7C00
-001000	+------------------------+
-	|  Reserved for MBR/BIOS |
-000800	+------------------------+
-	|  Typically used by MBR |
-000600	+------------------------+ 
-	|  BIOS use only	 |
-000000	+------------------------+
-
-... where the address X is as low as the design of the boot loader
-permits.
-
-
-**** THE REAL-MODE KERNEL HEADER
-
-In the following text, and anywhere in the kernel boot sequence, "a
-sector" refers to 512 bytes.  It is independent of the actual sector
-size of the underlying medium.
-
-The first step in loading a Linux kernel should be to load the
-real-mode code (boot sector and setup code) and then examine the
-following header at offset 0x01f1.  The real-mode code can total up to
-32K, although the boot loader may choose to load only the first two
-sectors (1K) and then examine the bootup sector size.
-
-The header looks like:
-
-Offset	Proto	Name		Meaning
-/Size
-
-01F1/1	ALL(1	setup_sects	The size of the setup in sectors
-01F2/2	ALL	root_flags	If set, the root is mounted readonly
-01F4/4	2.04+(2	syssize		The size of the 32-bit code in 16-byte paras
-01F8/2	ALL	ram_size	DO NOT USE - for bootsect.S use only
-01FA/2	ALL	vid_mode	Video mode control
-01FC/2	ALL	root_dev	Default root device number
-01FE/2	ALL	boot_flag	0xAA55 magic number
-0200/2	2.00+	jump		Jump instruction
-0202/4	2.00+	header		Magic signature "HdrS"
-0206/2	2.00+	version		Boot protocol version supported
-0208/4	2.00+	realmode_swtch	Boot loader hook (see below)
-020C/2	2.00+	start_sys	The load-low segment (0x1000) (obsolete)
-020E/2	2.00+	kernel_version	Pointer to kernel version string
-0210/1	2.00+	type_of_loader	Boot loader identifier
-0211/1	2.00+	loadflags	Boot protocol option flags
-0212/2	2.00+	setup_move_size	Move to high memory size (used with hooks)
-0214/4	2.00+	code32_start	Boot loader hook (see below)
-0218/4	2.00+	ramdisk_image	initrd load address (set by boot loader)
-021C/4	2.00+	ramdisk_size	initrd size (set by boot loader)
-0220/4	2.00+	bootsect_kludge	DO NOT USE - for bootsect.S use only
-0224/2	2.01+	heap_end_ptr	Free memory after setup end
-0226/2	N/A	pad1		Unused
-0228/4	2.02+	cmd_line_ptr	32-bit pointer to the kernel command line
-022C/4	2.03+	initrd_addr_max	Highest legal initrd address
-0230/4	2.05+	kernel_alignment Physical addr alignment required for kernel
-0234/1	2.05+	relocatable_kernel Whether kernel is relocatable or not
-0235/3	N/A	pad2		Unused
-0238/4	2.06+	cmdline_size	Maximum size of the kernel command line
-023C/4	2.07+	hardware_subarch Hardware subarchitecture
-0240/8	2.07+	hardware_subarch_data Subarchitecture-specific data
-0248/4	2.08+	payload_offset	Offset of kernel payload
-024C/4	2.08+	payload_length	Length of kernel payload
-0250/8	2.09+	setup_data	64-bit physical pointer to linked list
-				of struct setup_data
-
-(1) For backwards compatibility, if the setup_sects field contains 0, the
-    real value is 4.
-
-(2) For boot protocol prior to 2.04, the upper two bytes of the syssize
-    field are unusable, which means the size of a bzImage kernel
-    cannot be determined.
-
-If the "HdrS" (0x53726448) magic number is not found at offset 0x202,
-the boot protocol version is "old".  Loading an old kernel, the
-following parameters should be assumed:
-
-	Image type = zImage
-	initrd not supported
-	Real-mode kernel must be located at 0x90000.
-
-Otherwise, the "version" field contains the protocol version,
-e.g. protocol version 2.01 will contain 0x0201 in this field.  When
-setting fields in the header, you must make sure only to set fields
-supported by the protocol version in use.
-
-
-**** DETAILS OF HEADER FIELDS
-
-For each field, some are information from the kernel to the bootloader
-("read"), some are expected to be filled out by the bootloader
-("write"), and some are expected to be read and modified by the
-bootloader ("modify").
-
-All general purpose boot loaders should write the fields marked
-(obligatory).  Boot loaders who want to load the kernel at a
-nonstandard address should fill in the fields marked (reloc); other
-boot loaders can ignore those fields.
-
-The byte order of all fields is littleendian (this is x86, after all.)
-
-Field name:	setup_sects
-Type:		read
-Offset/size:	0x1f1/1
-Protocol:	ALL
-
-  The size of the setup code in 512-byte sectors.  If this field is
-  0, the real value is 4.  The real-mode code consists of the boot
-  sector (always one 512-byte sector) plus the setup code.
-
-Field name:	 root_flags
-Type:		 modify (optional)
-Offset/size:	 0x1f2/2
-Protocol:	 ALL
-
-  If this field is nonzero, the root defaults to readonly.  The use of
-  this field is deprecated; use the "ro" or "rw" options on the
-  command line instead.
-
-Field name:	syssize
-Type:		read
-Offset/size:	0x1f4/4 (protocol 2.04+) 0x1f4/2 (protocol ALL)
-Protocol:	2.04+
-
-  The size of the protected-mode code in units of 16-byte paragraphs.
-  For protocol versions older than 2.04 this field is only two bytes
-  wide, and therefore cannot be trusted for the size of a kernel if
-  the LOAD_HIGH flag is set.
-
-Field name:	ram_size
-Type:		kernel internal
-Offset/size:	0x1f8/2
-Protocol:	ALL
-
-  This field is obsolete.
-
-Field name:	vid_mode
-Type:		modify (obligatory)
-Offset/size:	0x1fa/2
-
-  Please see the section on SPECIAL COMMAND LINE OPTIONS.
-
-Field name:	root_dev
-Type:		modify (optional)
-Offset/size:	0x1fc/2
-Protocol:	ALL
-
-  The default root device device number.  The use of this field is
-  deprecated, use the "root=" option on the command line instead.
-
-Field name:	boot_flag
-Type:		read
-Offset/size:	0x1fe/2
-Protocol:	ALL
-
-  Contains 0xAA55.  This is the closest thing old Linux kernels have
-  to a magic number.
-
-Field name:	jump
-Type:		read
-Offset/size:	0x200/2
-Protocol:	2.00+
-
-  Contains an x86 jump instruction, 0xEB followed by a signed offset
-  relative to byte 0x202.  This can be used to determine the size of
-  the header.
-
-Field name:	header
-Type:		read
-Offset/size:	0x202/4
-Protocol:	2.00+
-
-  Contains the magic number "HdrS" (0x53726448).
-
-Field name:	version
-Type:		read
-Offset/size:	0x206/2
-Protocol:	2.00+
-
-  Contains the boot protocol version, in (major << 8)+minor format,
-  e.g. 0x0204 for version 2.04, and 0x0a11 for a hypothetical version
-  10.17.
-
-Field name:	readmode_swtch
-Type:		modify (optional)
-Offset/size:	0x208/4
-Protocol:	2.00+
-
-  Boot loader hook (see ADVANCED BOOT LOADER HOOKS below.)
-
-Field name:	start_sys
-Type:		read
-Offset/size:	0x20c/4
-Protocol:	2.00+
-
-  The load low segment (0x1000).  Obsolete.
-
-Field name:	kernel_version
-Type:		read
-Offset/size:	0x20e/2
-Protocol:	2.00+
-
-  If set to a nonzero value, contains a pointer to a NUL-terminated
-  human-readable kernel version number string, less 0x200.  This can
-  be used to display the kernel version to the user.  This value
-  should be less than (0x200*setup_sects).
-
-  For example, if this value is set to 0x1c00, the kernel version
-  number string can be found at offset 0x1e00 in the kernel file.
-  This is a valid value if and only if the "setup_sects" field
-  contains the value 15 or higher, as:
-
-	0x1c00  < 15*0x200 (= 0x1e00) but
-	0x1c00 >= 14*0x200 (= 0x1c00)
-
-	0x1c00 >> 9 = 14, so the minimum value for setup_secs is 15.
-
-Field name:	type_of_loader
-Type:		write (obligatory)
-Offset/size:	0x210/1
-Protocol:	2.00+
-
-  If your boot loader has an assigned id (see table below), enter
-  0xTV here, where T is an identifier for the boot loader and V is
-  a version number.  Otherwise, enter 0xFF here.
-
-  Assigned boot loader ids:
-	0  LILO			(0x00 reserved for pre-2.00 bootloader)
-	1  Loadlin
-	2  bootsect-loader	(0x20, all other values reserved)
-	3  SYSLINUX
-	4  EtherBoot
-	5  ELILO
-	7  GRuB
-	8  U-BOOT
-	9  Xen
-	A  Gujin
-	B  Qemu
-
-  Please contact <hpa@zytor.com> if you need a bootloader ID
-  value assigned.
-
-Field name:	loadflags
-Type:		modify (obligatory)
-Offset/size:	0x211/1
-Protocol:	2.00+
-
-  This field is a bitmask.
-
-  Bit 0 (read):	LOADED_HIGH
-	- If 0, the protected-mode code is loaded at 0x10000.
-	- If 1, the protected-mode code is loaded at 0x100000.
-
-  Bit 5 (write): QUIET_FLAG
-	- If 0, print early messages.
-	- If 1, suppress early messages.
-		This requests to the kernel (decompressor and early
-		kernel) to not write early messages that require
-		accessing the display hardware directly.
-
-  Bit 6 (write): KEEP_SEGMENTS
-	Protocol: 2.07+
-	- If 0, reload the segment registers in the 32bit entry point.
-	- If 1, do not reload the segment registers in the 32bit entry point.
-		Assume that %cs %ds %ss %es are all set to flat segments with
-		a base of 0 (or the equivalent for their environment).
-
-  Bit 7 (write): CAN_USE_HEAP
-	Set this bit to 1 to indicate that the value entered in the
-	heap_end_ptr is valid.  If this field is clear, some setup code
-	functionality will be disabled.
-
-Field name:	setup_move_size
-Type:		modify (obligatory)
-Offset/size:	0x212/2
-Protocol:	2.00-2.01
-
-  When using protocol 2.00 or 2.01, if the real mode kernel is not
-  loaded at 0x90000, it gets moved there later in the loading
-  sequence.  Fill in this field if you want additional data (such as
-  the kernel command line) moved in addition to the real-mode kernel
-  itself.
-
-  The unit is bytes starting with the beginning of the boot sector.
-  
-  This field is can be ignored when the protocol is 2.02 or higher, or
-  if the real-mode code is loaded at 0x90000.
-
-Field name:	code32_start
-Type:		modify (optional, reloc)
-Offset/size:	0x214/4
-Protocol:	2.00+
-
-  The address to jump to in protected mode.  This defaults to the load
-  address of the kernel, and can be used by the boot loader to
-  determine the proper load address.
-
-  This field can be modified for two purposes:
-
-  1. as a boot loader hook (see ADVANCED BOOT LOADER HOOKS below.)
-
-  2. if a bootloader which does not install a hook loads a
-     relocatable kernel at a nonstandard address it will have to modify
-     this field to point to the load address.
-
-Field name:	ramdisk_image
-Type:		write (obligatory)
-Offset/size:	0x218/4
-Protocol:	2.00+
-
-  The 32-bit linear address of the initial ramdisk or ramfs.  Leave at
-  zero if there is no initial ramdisk/ramfs.
-
-Field name:	ramdisk_size
-Type:		write (obligatory)
-Offset/size:	0x21c/4
-Protocol:	2.00+
-
-  Size of the initial ramdisk or ramfs.  Leave at zero if there is no
-  initial ramdisk/ramfs.
-
-Field name:	bootsect_kludge
-Type:		kernel internal
-Offset/size:	0x220/4
-Protocol:	2.00+
-
-  This field is obsolete.
-
-Field name:	heap_end_ptr
-Type:		write (obligatory)
-Offset/size:	0x224/2
-Protocol:	2.01+
-
-  Set this field to the offset (from the beginning of the real-mode
-  code) of the end of the setup stack/heap, minus 0x0200.
-
-Field name:	cmd_line_ptr
-Type:		write (obligatory)
-Offset/size:	0x228/4
-Protocol:	2.02+
-
-  Set this field to the linear address of the kernel command line.
-  The kernel command line can be located anywhere between the end of
-  the setup heap and 0xA0000; it does not have to be located in the
-  same 64K segment as the real-mode code itself.
-
-  Fill in this field even if your boot loader does not support a
-  command line, in which case you can point this to an empty string
-  (or better yet, to the string "auto".)  If this field is left at
-  zero, the kernel will assume that your boot loader does not support
-  the 2.02+ protocol.
-
-Field name:	initrd_addr_max
-Type:		read
-Offset/size:	0x22c/4
-Protocol:	2.03+
-
-  The maximum address that may be occupied by the initial
-  ramdisk/ramfs contents.  For boot protocols 2.02 or earlier, this
-  field is not present, and the maximum address is 0x37FFFFFF.  (This
-  address is defined as the address of the highest safe byte, so if
-  your ramdisk is exactly 131072 bytes long and this field is
-  0x37FFFFFF, you can start your ramdisk at 0x37FE0000.)
-
-Field name:	kernel_alignment
-Type:		read (reloc)
-Offset/size:	0x230/4
-Protocol:	2.05+
-
-  Alignment unit required by the kernel (if relocatable_kernel is true.)
-
-Field name:	relocatable_kernel
-Type:		read (reloc)
-Offset/size:	0x234/1
-Protocol:	2.05+
-
-  If this field is nonzero, the protected-mode part of the kernel can
-  be loaded at any address that satisfies the kernel_alignment field.
-  After loading, the boot loader must set the code32_start field to
-  point to the loaded code, or to a boot loader hook.
-
-Field name:	cmdline_size
-Type:		read
-Offset/size:	0x238/4
-Protocol:	2.06+
-
-  The maximum size of the command line without the terminating
-  zero. This means that the command line can contain at most
-  cmdline_size characters. With protocol version 2.05 and earlier, the
-  maximum size was 255.
-
-Field name:	hardware_subarch
-Type:		write (optional, defaults to x86/PC)
-Offset/size:	0x23c/4
-Protocol:	2.07+
-
-  In a paravirtualized environment the hardware low level architectural
-  pieces such as interrupt handling, page table handling, and
-  accessing process control registers needs to be done differently.
-
-  This field allows the bootloader to inform the kernel we are in one
-  one of those environments.
-
-  0x00000000	The default x86/PC environment
-  0x00000001	lguest
-  0x00000002	Xen
-
-Field name:	hardware_subarch_data
-Type:		write (subarch-dependent)
-Offset/size:	0x240/8
-Protocol:	2.07+
-
-  A pointer to data that is specific to hardware subarch
-  This field is currently unused for the default x86/PC environment,
-  do not modify.
-
-Field name:	payload_offset
-Type:		read
-Offset/size:	0x248/4
-Protocol:	2.08+
-
-  If non-zero then this field contains the offset from the end of the
-  real-mode code to the payload.
-
-  The payload may be compressed. The format of both the compressed and
-  uncompressed data should be determined using the standard magic
-  numbers. Currently only gzip compressed ELF is used.
-  
-Field name:	payload_length
-Type:		read
-Offset/size:	0x24c/4
-Protocol:	2.08+
-
-  The length of the payload.
-
-Field name:	setup_data
-Type:		write (special)
-Offset/size:	0x250/8
-Protocol:	2.09+
-
-  The 64-bit physical pointer to NULL terminated single linked list of
-  struct setup_data. This is used to define a more extensible boot
-  parameters passing mechanism. The definition of struct setup_data is
-  as follow:
-
-  struct setup_data {
-	  u64 next;
-	  u32 type;
-	  u32 len;
-	  u8  data[0];
-  };
-
-  Where, the next is a 64-bit physical pointer to the next node of
-  linked list, the next field of the last node is 0; the type is used
-  to identify the contents of data; the len is the length of data
-  field; the data holds the real payload.
-
-  This list may be modified at a number of points during the bootup
-  process.  Therefore, when modifying this list one should always make
-  sure to consider the case where the linked list already contains
-  entries.
-
-
-**** THE IMAGE CHECKSUM
-
-From boot protocol version 2.08 onwards the CRC-32 is calculated over
-the entire file using the characteristic polynomial 0x04C11DB7 and an
-initial remainder of 0xffffffff.  The checksum is appended to the
-file; therefore the CRC of the file up to the limit specified in the
-syssize field of the header is always 0.
-
-
-**** THE KERNEL COMMAND LINE
-
-The kernel command line has become an important way for the boot
-loader to communicate with the kernel.  Some of its options are also
-relevant to the boot loader itself, see "special command line options"
-below.
-
-The kernel command line is a null-terminated string. The maximum
-length can be retrieved from the field cmdline_size.  Before protocol
-version 2.06, the maximum was 255 characters.  A string that is too
-long will be automatically truncated by the kernel.
-
-If the boot protocol version is 2.02 or later, the address of the
-kernel command line is given by the header field cmd_line_ptr (see
-above.)  This address can be anywhere between the end of the setup
-heap and 0xA0000.
-
-If the protocol version is *not* 2.02 or higher, the kernel
-command line is entered using the following protocol:
-
-	At offset 0x0020 (word), "cmd_line_magic", enter the magic
-	number 0xA33F.
-
-	At offset 0x0022 (word), "cmd_line_offset", enter the offset
-	of the kernel command line (relative to the start of the
-	real-mode kernel).
-	
-	The kernel command line *must* be within the memory region
-	covered by setup_move_size, so you may need to adjust this
-	field.
-
-
-**** MEMORY LAYOUT OF THE REAL-MODE CODE
-
-The real-mode code requires a stack/heap to be set up, as well as
-memory allocated for the kernel command line.  This needs to be done
-in the real-mode accessible memory in bottom megabyte.
-
-It should be noted that modern machines often have a sizable Extended
-BIOS Data Area (EBDA).  As a result, it is advisable to use as little
-of the low megabyte as possible.
-
-Unfortunately, under the following circumstances the 0x90000 memory
-segment has to be used:
-
-	- When loading a zImage kernel ((loadflags & 0x01) == 0).
-	- When loading a 2.01 or earlier boot protocol kernel.
-
-	  -> For the 2.00 and 2.01 boot protocols, the real-mode code
-	     can be loaded at another address, but it is internally
-	     relocated to 0x90000.  For the "old" protocol, the
-	     real-mode code must be loaded at 0x90000.
-
-When loading at 0x90000, avoid using memory above 0x9a000.
-
-For boot protocol 2.02 or higher, the command line does not have to be
-located in the same 64K segment as the real-mode setup code; it is
-thus permitted to give the stack/heap the full 64K segment and locate
-the command line above it.
-
-The kernel command line should not be located below the real-mode
-code, nor should it be located in high memory.
-
-
-**** SAMPLE BOOT CONFIGURATION
-
-As a sample configuration, assume the following layout of the real
-mode segment:
-
-    When loading below 0x90000, use the entire segment:
-
-	0x0000-0x7fff	Real mode kernel
-	0x8000-0xdfff	Stack and heap
-	0xe000-0xffff	Kernel command line
-
-    When loading at 0x90000 OR the protocol version is 2.01 or earlier:
-
-	0x0000-0x7fff	Real mode kernel
-	0x8000-0x97ff	Stack and heap
-	0x9800-0x9fff	Kernel command line
-
-Such a boot loader should enter the following fields in the header:
-
-	unsigned long base_ptr;	/* base address for real-mode segment */
-
-	if ( setup_sects == 0 ) {
-		setup_sects = 4;
-	}
-
-	if ( protocol >= 0x0200 ) {
-		type_of_loader = <type code>;
-		if ( loading_initrd ) {
-			ramdisk_image = <initrd_address>;
-			ramdisk_size = <initrd_size>;
-		}
-
-		if ( protocol >= 0x0202 && loadflags & 0x01 )
-			heap_end = 0xe000;
-		else
-			heap_end = 0x9800;
-
-		if ( protocol >= 0x0201 ) {
-			heap_end_ptr = heap_end - 0x200;
-			loadflags |= 0x80; /* CAN_USE_HEAP */
-		}
-
-		if ( protocol >= 0x0202 ) {
-			cmd_line_ptr = base_ptr + heap_end;
-			strcpy(cmd_line_ptr, cmdline);
-		} else {
-			cmd_line_magic	= 0xA33F;
-			cmd_line_offset = heap_end;
-			setup_move_size = heap_end + strlen(cmdline)+1;
-			strcpy(base_ptr+cmd_line_offset, cmdline);
-		}
-	} else {
-		/* Very old kernel */
-
-		heap_end = 0x9800;
-
-		cmd_line_magic	= 0xA33F;
-		cmd_line_offset = heap_end;
-
-		/* A very old kernel MUST have its real-mode code
-		   loaded at 0x90000 */
-
-		if ( base_ptr != 0x90000 ) {
-			/* Copy the real-mode kernel */
-			memcpy(0x90000, base_ptr, (setup_sects+1)*512);
-			base_ptr = 0x90000;		 /* Relocated */
-		}
-
-		strcpy(0x90000+cmd_line_offset, cmdline);
-
-		/* It is recommended to clear memory up to the 32K mark */
-		memset(0x90000 + (setup_sects+1)*512, 0,
-		       (64-(setup_sects+1))*512);
-	}
-
-
-**** LOADING THE REST OF THE KERNEL
-
-The 32-bit (non-real-mode) kernel starts at offset (setup_sects+1)*512
-in the kernel file (again, if setup_sects == 0 the real value is 4.)
-It should be loaded at address 0x10000 for Image/zImage kernels and
-0x100000 for bzImage kernels.
-
-The kernel is a bzImage kernel if the protocol >= 2.00 and the 0x01
-bit (LOAD_HIGH) in the loadflags field is set:
-
-	is_bzImage = (protocol >= 0x0200) && (loadflags & 0x01);
-	load_address = is_bzImage ? 0x100000 : 0x10000;
-
-Note that Image/zImage kernels can be up to 512K in size, and thus use
-the entire 0x10000-0x90000 range of memory.  This means it is pretty
-much a requirement for these kernels to load the real-mode part at
-0x90000.  bzImage kernels allow much more flexibility.
-
-
-**** SPECIAL COMMAND LINE OPTIONS
-
-If the command line provided by the boot loader is entered by the
-user, the user may expect the following command line options to work.
-They should normally not be deleted from the kernel command line even
-though not all of them are actually meaningful to the kernel.  Boot
-loader authors who need additional command line options for the boot
-loader itself should get them registered in
-Documentation/kernel-parameters.txt to make sure they will not
-conflict with actual kernel options now or in the future.
-
-  vga=<mode>
-	<mode> here is either an integer (in C notation, either
-	decimal, octal, or hexadecimal) or one of the strings
-	"normal" (meaning 0xFFFF), "ext" (meaning 0xFFFE) or "ask"
-	(meaning 0xFFFD).  This value should be entered into the
-	vid_mode field, as it is used by the kernel before the command
-	line is parsed.
-
-  mem=<size>
-	<size> is an integer in C notation optionally followed by
-	(case insensitive) K, M, G, T, P or E (meaning << 10, << 20,
-	<< 30, << 40, << 50 or << 60).  This specifies the end of
-	memory to the kernel. This affects the possible placement of
-	an initrd, since an initrd should be placed near end of
-	memory.  Note that this is an option to *both* the kernel and
-	the bootloader!
-
-  initrd=<file>
-	An initrd should be loaded.  The meaning of <file> is
-	obviously bootloader-dependent, and some boot loaders
-	(e.g. LILO) do not have such a command.
-
-In addition, some boot loaders add the following options to the
-user-specified command line:
-
-  BOOT_IMAGE=<file>
-	The boot image which was loaded.  Again, the meaning of <file>
-	is obviously bootloader-dependent.
-
-  auto
-	The kernel was booted without explicit user intervention.
-
-If these options are added by the boot loader, it is highly
-recommended that they are located *first*, before the user-specified
-or configuration-specified command line.  Otherwise, "init=/bin/sh"
-gets confused by the "auto" option.
-
-
-**** RUNNING THE KERNEL
-
-The kernel is started by jumping to the kernel entry point, which is
-located at *segment* offset 0x20 from the start of the real mode
-kernel.  This means that if you loaded your real-mode kernel code at
-0x90000, the kernel entry point is 9020:0000.
-
-At entry, ds = es = ss should point to the start of the real-mode
-kernel code (0x9000 if the code is loaded at 0x90000), sp should be
-set up properly, normally pointing to the top of the heap, and
-interrupts should be disabled.  Furthermore, to guard against bugs in
-the kernel, it is recommended that the boot loader sets fs = gs = ds =
-es = ss.
-
-In our example from above, we would do:
-
-	/* Note: in the case of the "old" kernel protocol, base_ptr must
-	   be == 0x90000 at this point; see the previous sample code */
-
-	seg = base_ptr >> 4;
-
-	cli();	/* Enter with interrupts disabled! */
-
-	/* Set up the real-mode kernel stack */
-	_SS = seg;
-	_SP = heap_end;
-
-	_DS = _ES = _FS = _GS = seg;
-	jmp_far(seg+0x20, 0);	/* Run the kernel */
-
-If your boot sector accesses a floppy drive, it is recommended to
-switch off the floppy motor before running the kernel, since the
-kernel boot leaves interrupts off and thus the motor will not be
-switched off, especially if the loaded kernel has the floppy driver as
-a demand-loaded module!
-
-
-**** ADVANCED BOOT LOADER HOOKS
-
-If the boot loader runs in a particularly hostile environment (such as
-LOADLIN, which runs under DOS) it may be impossible to follow the
-standard memory location requirements.  Such a boot loader may use the
-following hooks that, if set, are invoked by the kernel at the
-appropriate time.  The use of these hooks should probably be
-considered an absolutely last resort!
-
-IMPORTANT: All the hooks are required to preserve %esp, %ebp, %esi and
-%edi across invocation.
-
-  realmode_swtch:
-	A 16-bit real mode far subroutine invoked immediately before
-	entering protected mode.  The default routine disables NMI, so
-	your routine should probably do so, too.
-
-  code32_start:
-	A 32-bit flat-mode routine *jumped* to immediately after the
-	transition to protected mode, but before the kernel is
-	uncompressed.  No segments, except CS, are guaranteed to be
-	set up (current kernels do, but older ones do not); you should
-	set them up to BOOT_DS (0x18) yourself.
-
-	After completing your hook, you should jump to the address
-	that was in this field before your boot loader overwrote it
-	(relocated, if appropriate.)
-
-
-**** 32-bit BOOT PROTOCOL
-
-For machine with some new BIOS other than legacy BIOS, such as EFI,
-LinuxBIOS, etc, and kexec, the 16-bit real mode setup code in kernel
-based on legacy BIOS can not be used, so a 32-bit boot protocol needs
-to be defined.
-
-In 32-bit boot protocol, the first step in loading a Linux kernel
-should be to setup the boot parameters (struct boot_params,
-traditionally known as "zero page"). The memory for struct boot_params
-should be allocated and initialized to all zero. Then the setup header
-from offset 0x01f1 of kernel image on should be loaded into struct
-boot_params and examined. The end of setup header can be calculated as
-follow:
-
-	0x0202 + byte value at offset 0x0201
-
-In addition to read/modify/write the setup header of the struct
-boot_params as that of 16-bit boot protocol, the boot loader should
-also fill the additional fields of the struct boot_params as that
-described in zero-page.txt.
-
-After setupping the struct boot_params, the boot loader can load the
-32/64-bit kernel in the same way as that of 16-bit boot protocol.
-
-In 32-bit boot protocol, the kernel is started by jumping to the
-32-bit kernel entry point, which is the start address of loaded
-32/64-bit kernel.
-
-At entry, the CPU must be in 32-bit protected mode with paging
-disabled; a GDT must be loaded with the descriptors for selectors
-__BOOT_CS(0x10) and __BOOT_DS(0x18); both descriptors must be 4G flat
-segment; __BOOS_CS must have execute/read permission, and __BOOT_DS
-must have read/write permission; CS must be __BOOT_CS and DS, ES, SS
-must be __BOOT_DS; interrupt must be disabled; %esi must hold the base
-address of the struct boot_params; %ebp, %edi and %ebx must be zero.
diff --git a/Documentation/x86/mtrr.txt b/Documentation/x86/mtrr.txt
new file mode 100644
index 0000000..cc071dc
--- /dev/null
+++ b/Documentation/x86/mtrr.txt
@@ -0,0 +1,305 @@
+MTRR (Memory Type Range Register) control
+3 Jun 1999
+Richard Gooch
+<rgooch@atnf.csiro.au>
+
+  On Intel P6 family processors (Pentium Pro, Pentium II and later)
+  the Memory Type Range Registers (MTRRs) may be used to control
+  processor access to memory ranges. This is most useful when you have
+  a video (VGA) card on a PCI or AGP bus. Enabling write-combining
+  allows bus write transfers to be combined into a larger transfer
+  before bursting over the PCI/AGP bus. This can increase performance
+  of image write operations 2.5 times or more.
+
+  The Cyrix 6x86, 6x86MX and M II processors have Address Range
+  Registers (ARRs) which provide a similar functionality to MTRRs. For
+  these, the ARRs are used to emulate the MTRRs.
+
+  The AMD K6-2 (stepping 8 and above) and K6-3 processors have two
+  MTRRs. These are supported.  The AMD Athlon family provide 8 Intel
+  style MTRRs.
+
+  The Centaur C6 (WinChip) has 8 MCRs, allowing write-combining. These
+  are supported.
+
+  The VIA Cyrix III and VIA C3 CPUs offer 8 Intel style MTRRs.
+
+  The CONFIG_MTRR option creates a /proc/mtrr file which may be used
+  to manipulate your MTRRs. Typically the X server should use
+  this. This should have a reasonably generic interface so that
+  similar control registers on other processors can be easily
+  supported.
+
+
+There are two interfaces to /proc/mtrr: one is an ASCII interface
+which allows you to read and write. The other is an ioctl()
+interface. The ASCII interface is meant for administration. The
+ioctl() interface is meant for C programs (i.e. the X server). The
+interfaces are described below, with sample commands and C code.
+
+===============================================================================
+Reading MTRRs from the shell:
+
+% cat /proc/mtrr
+reg00: base=0x00000000 (   0MB), size= 128MB: write-back, count=1
+reg01: base=0x08000000 ( 128MB), size=  64MB: write-back, count=1
+===============================================================================
+Creating MTRRs from the C-shell:
+# echo "base=0xf8000000 size=0x400000 type=write-combining" >! /proc/mtrr
+or if you use bash:
+# echo "base=0xf8000000 size=0x400000 type=write-combining" >| /proc/mtrr
+
+And the result thereof:
+% cat /proc/mtrr
+reg00: base=0x00000000 (   0MB), size= 128MB: write-back, count=1
+reg01: base=0x08000000 ( 128MB), size=  64MB: write-back, count=1
+reg02: base=0xf8000000 (3968MB), size=   4MB: write-combining, count=1
+
+This is for video RAM at base address 0xf8000000 and size 4 megabytes. To
+find out your base address, you need to look at the output of your X
+server, which tells you where the linear framebuffer address is. A
+typical line that you may get is:
+
+(--) S3: PCI: 968 rev 0, Linear FB @ 0xf8000000
+
+Note that you should only use the value from the X server, as it may
+move the framebuffer base address, so the only value you can trust is
+that reported by the X server.
+
+To find out the size of your framebuffer (what, you don't actually
+know?), the following line will tell you:
+
+(--) S3: videoram:  4096k
+
+That's 4 megabytes, which is 0x400000 bytes (in hexadecimal).
+A patch is being written for XFree86 which will make this automatic:
+in other words the X server will manipulate /proc/mtrr using the
+ioctl() interface, so users won't have to do anything. If you use a
+commercial X server, lobby your vendor to add support for MTRRs.
+===============================================================================
+Creating overlapping MTRRs:
+
+%echo "base=0xfb000000 size=0x1000000 type=write-combining" >/proc/mtrr
+%echo "base=0xfb000000 size=0x1000 type=uncachable" >/proc/mtrr
+
+And the results: cat /proc/mtrr
+reg00: base=0x00000000 (   0MB), size=  64MB: write-back, count=1
+reg01: base=0xfb000000 (4016MB), size=  16MB: write-combining, count=1
+reg02: base=0xfb000000 (4016MB), size=   4kB: uncachable, count=1
+
+Some cards (especially Voodoo Graphics boards) need this 4 kB area
+excluded from the beginning of the region because it is used for
+registers.
+
+NOTE: You can only create type=uncachable region, if the first
+region that you created is type=write-combining.
+===============================================================================
+Removing MTRRs from the C-shell:
+% echo "disable=2" >! /proc/mtrr
+or using bash:
+% echo "disable=2" >| /proc/mtrr
+===============================================================================
+Reading MTRRs from a C program using ioctl()'s:
+
+/*  mtrr-show.c
+
+    Source file for mtrr-show (example program to show MTRRs using ioctl()'s)
+
+    Copyright (C) 1997-1998  Richard Gooch
+
+    This program is free software; you can redistribute it and/or 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.
+
+    Richard Gooch may be reached by email at  rgooch@atnf.csiro.au
+    The postal address is:
+      Richard Gooch, c/o ATNF, P. O. Box 76, Epping, N.S.W., 2121, Australia.
+*/
+
+/*
+    This program will use an ioctl() on /proc/mtrr to show the current MTRR
+    settings. This is an alternative to reading /proc/mtrr.
+
+
+    Written by      Richard Gooch   17-DEC-1997
+
+    Last updated by Richard Gooch   2-MAY-1998
+
+
+*/
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <errno.h>
+#include <asm/mtrr.h>
+
+#define TRUE 1
+#define FALSE 0
+#define ERRSTRING strerror (errno)
+
+static char *mtrr_strings[MTRR_NUM_TYPES] =
+{
+    "uncachable",               /* 0 */
+    "write-combining",          /* 1 */
+    "?",                        /* 2 */
+    "?",                        /* 3 */
+    "write-through",            /* 4 */
+    "write-protect",            /* 5 */
+    "write-back",               /* 6 */
+};
+
+int main ()
+{
+    int fd;
+    struct mtrr_gentry gentry;
+
+    if ( ( fd = open ("/proc/mtrr", O_RDONLY, 0) ) == -1 )
+    {
+	if (errno == ENOENT)
+	{
+	    fputs ("/proc/mtrr not found: not supported or you don't have a PPro?\n",
+		   stderr);
+	    exit (1);
+	}
+	fprintf (stderr, "Error opening /proc/mtrr\t%s\n", ERRSTRING);
+	exit (2);
+    }
+    for (gentry.regnum = 0; ioctl (fd, MTRRIOC_GET_ENTRY, &gentry) == 0;
+	 ++gentry.regnum)
+    {
+	if (gentry.size < 1)
+	{
+	    fprintf (stderr, "Register: %u disabled\n", gentry.regnum);
+	    continue;
+	}
+	fprintf (stderr, "Register: %u base: 0x%lx size: 0x%lx type: %s\n",
+		 gentry.regnum, gentry.base, gentry.size,
+		 mtrr_strings[gentry.type]);
+    }
+    if (errno == EINVAL) exit (0);
+    fprintf (stderr, "Error doing ioctl(2) on /dev/mtrr\t%s\n", ERRSTRING);
+    exit (3);
+}   /*  End Function main  */
+===============================================================================
+Creating MTRRs from a C programme using ioctl()'s:
+
+/*  mtrr-add.c
+
+    Source file for mtrr-add (example programme to add an MTRRs using ioctl())
+
+    Copyright (C) 1997-1998  Richard Gooch
+
+    This program is free software; you can redistribute it and/or 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.
+
+    Richard Gooch may be reached by email at  rgooch@atnf.csiro.au
+    The postal address is:
+      Richard Gooch, c/o ATNF, P. O. Box 76, Epping, N.S.W., 2121, Australia.
+*/
+
+/*
+    This programme will use an ioctl() on /proc/mtrr to add an entry. The first
+    available mtrr is used. This is an alternative to writing /proc/mtrr.
+
+
+    Written by      Richard Gooch   17-DEC-1997
+
+    Last updated by Richard Gooch   2-MAY-1998
+
+
+*/
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <errno.h>
+#include <asm/mtrr.h>
+
+#define TRUE 1
+#define FALSE 0
+#define ERRSTRING strerror (errno)
+
+static char *mtrr_strings[MTRR_NUM_TYPES] =
+{
+    "uncachable",               /* 0 */
+    "write-combining",          /* 1 */
+    "?",                        /* 2 */
+    "?",                        /* 3 */
+    "write-through",            /* 4 */
+    "write-protect",            /* 5 */
+    "write-back",               /* 6 */
+};
+
+int main (int argc, char **argv)
+{
+    int fd;
+    struct mtrr_sentry sentry;
+
+    if (argc != 4)
+    {
+	fprintf (stderr, "Usage:\tmtrr-add base size type\n");
+	exit (1);
+    }
+    sentry.base = strtoul (argv[1], NULL, 0);
+    sentry.size = strtoul (argv[2], NULL, 0);
+    for (sentry.type = 0; sentry.type < MTRR_NUM_TYPES; ++sentry.type)
+    {
+	if (strcmp (argv[3], mtrr_strings[sentry.type]) == 0) break;
+    }
+    if (sentry.type >= MTRR_NUM_TYPES)
+    {
+	fprintf (stderr, "Illegal type: \"%s\"\n", argv[3]);
+	exit (2);
+    }
+    if ( ( fd = open ("/proc/mtrr", O_WRONLY, 0) ) == -1 )
+    {
+	if (errno == ENOENT)
+	{
+	    fputs ("/proc/mtrr not found: not supported or you don't have a PPro?\n",
+		   stderr);
+	    exit (3);
+	}
+	fprintf (stderr, "Error opening /proc/mtrr\t%s\n", ERRSTRING);
+	exit (4);
+    }
+    if (ioctl (fd, MTRRIOC_ADD_ENTRY, &sentry) == -1)
+    {
+	fprintf (stderr, "Error doing ioctl(2) on /dev/mtrr\t%s\n", ERRSTRING);
+	exit (5);
+    }
+    fprintf (stderr, "Sleeping for 5 seconds so you can see the new entry\n");
+    sleep (5);
+    close (fd);
+    fputs ("I've just closed /proc/mtrr so now the new entry should be gone\n",
+	   stderr);
+}   /*  End Function main  */
+===============================================================================
diff --git a/Documentation/x86/pat.txt b/Documentation/x86/pat.txt
index 17965f9..c93ff5f 100644
--- a/Documentation/x86/pat.txt
+++ b/Documentation/x86/pat.txt
@@ -14,6 +14,10 @@
 ones that will be supported at this time are Write-back, Uncached,
 Write-combined and Uncached Minus.
 
+
+PAT APIs
+--------
+
 There are many different APIs in the kernel that allows setting of memory
 attributes at the page level. In order to avoid aliasing, these interfaces
 should be used thoughtfully. Below is a table of interfaces available,
@@ -26,38 +30,38 @@
 API                    |    RAM   |  ACPI,...  |  Reserved/Holes  |
 -----------------------|----------|------------|------------------|
                        |          |            |                  |
-ioremap                |    --    |    UC      |       UC         |
+ioremap                |    --    |    UC-     |       UC-        |
                        |          |            |                  |
 ioremap_cache          |    --    |    WB      |       WB         |
                        |          |            |                  |
-ioremap_nocache        |    --    |    UC      |       UC         |
+ioremap_nocache        |    --    |    UC-     |       UC-        |
                        |          |            |                  |
 ioremap_wc             |    --    |    --      |       WC         |
                        |          |            |                  |
-set_memory_uc          |    UC    |    --      |       --         |
+set_memory_uc          |    UC-   |    --      |       --         |
  set_memory_wb         |          |            |                  |
                        |          |            |                  |
 set_memory_wc          |    WC    |    --      |       --         |
  set_memory_wb         |          |            |                  |
                        |          |            |                  |
-pci sysfs resource     |    --    |    --      |       UC         |
+pci sysfs resource     |    --    |    --      |       UC-        |
                        |          |            |                  |
 pci sysfs resource_wc  |    --    |    --      |       WC         |
  is IORESOURCE_PREFETCH|          |            |                  |
                        |          |            |                  |
-pci proc               |    --    |    --      |       UC         |
+pci proc               |    --    |    --      |       UC-        |
  !PCIIOC_WRITE_COMBINE |          |            |                  |
                        |          |            |                  |
 pci proc               |    --    |    --      |       WC         |
  PCIIOC_WRITE_COMBINE  |          |            |                  |
                        |          |            |                  |
-/dev/mem               |    --    |    UC      |       UC         |
+/dev/mem               |    --    |  WB/WC/UC- |    WB/WC/UC-     |
  read-write            |          |            |                  |
                        |          |            |                  |
-/dev/mem               |    --    |    UC      |       UC         |
+/dev/mem               |    --    |    UC-     |       UC-        |
  mmap SYNC flag        |          |            |                  |
                        |          |            |                  |
-/dev/mem               |    --    |  WB/WC/UC  |    WB/WC/UC      |
+/dev/mem               |    --    |  WB/WC/UC- |    WB/WC/UC-     |
  mmap !SYNC flag       |          |(from exist-|  (from exist-    |
  and                   |          |  ing alias)|    ing alias)    |
  any alias to this area|          |            |                  |
@@ -68,7 +72,7 @@
  and                   |          |            |                  |
  MTRR says WB          |          |            |                  |
                        |          |            |                  |
-/dev/mem               |    --    |    --      |    UC_MINUS      |
+/dev/mem               |    --    |    --      |       UC-        |
  mmap !SYNC flag       |          |            |                  |
  no alias to this area |          |            |                  |
  and                   |          |            |                  |
@@ -98,3 +102,35 @@
 
 Drivers should use set_memory_[uc|wc] to set access type for RAM ranges.
 
+
+PAT debugging
+-------------
+
+With CONFIG_DEBUG_FS enabled, PAT memtype list can be examined by
+
+# mount -t debugfs debugfs /sys/kernel/debug
+# cat /sys/kernel/debug/x86/pat_memtype_list
+PAT memtype list:
+uncached-minus @ 0x7fadf000-0x7fae0000
+uncached-minus @ 0x7fb19000-0x7fb1a000
+uncached-minus @ 0x7fb1a000-0x7fb1b000
+uncached-minus @ 0x7fb1b000-0x7fb1c000
+uncached-minus @ 0x7fb1c000-0x7fb1d000
+uncached-minus @ 0x7fb1d000-0x7fb1e000
+uncached-minus @ 0x7fb1e000-0x7fb25000
+uncached-minus @ 0x7fb25000-0x7fb26000
+uncached-minus @ 0x7fb26000-0x7fb27000
+uncached-minus @ 0x7fb27000-0x7fb28000
+uncached-minus @ 0x7fb28000-0x7fb2e000
+uncached-minus @ 0x7fb2e000-0x7fb2f000
+uncached-minus @ 0x7fb2f000-0x7fb30000
+uncached-minus @ 0x7fb31000-0x7fb32000
+uncached-minus @ 0x80000000-0x90000000
+
+This list shows physical address ranges and various PAT settings used to
+access those physical address ranges.
+
+Another, more verbose way of getting PAT related debug messages is with
+"debugpat" boot parameter. With this parameter, various debug messages are
+printed to dmesg log.
+
diff --git a/Documentation/x86/i386/usb-legacy-support.txt b/Documentation/x86/usb-legacy-support.txt
similarity index 100%
rename from Documentation/x86/i386/usb-legacy-support.txt
rename to Documentation/x86/usb-legacy-support.txt
diff --git a/Documentation/x86/x86_64/boot-options.txt b/Documentation/x86/x86_64/boot-options.txt
index b0c7b6c..72ffb53 100644
--- a/Documentation/x86/x86_64/boot-options.txt
+++ b/Documentation/x86/x86_64/boot-options.txt
@@ -54,10 +54,6 @@
 		 apicmaintimer. Useful when your PIT timer is totally
 		 broken.
 
-   disable_8254_timer / enable_8254_timer
-		 Enable interrupt 0 timer routing over the 8254 in addition to over
-	         the IO-APIC. The kernel tries to set a sensible default.
-
 Early Console
 
    syntax: earlyprintk=vga
diff --git a/Documentation/x86/i386/zero-page.txt b/Documentation/x86/zero-page.txt
similarity index 100%
rename from Documentation/x86/i386/zero-page.txt
rename to Documentation/x86/zero-page.txt
diff --git a/MAINTAINERS b/MAINTAINERS
index 0a613cb..5d0b8a2 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -72,6 +72,7 @@
 L: Mailing list that is relevant to this area
 W: Web-page with status/info
 T: SCM tree type and location.  Type is one of: git, hg, quilt.
+F: Applicable files and/or directories
 S: Status, one of the following:
 
 	Supported:	Someone is actually paid to look after this.
@@ -102,14 +103,14 @@
 L:	netdev@vger.kernel.org
 S:	Maintained
 
-3W-XXXX ATA-RAID CONTROLLER DRIVER
+3W-9XXX SATA-RAID CONTROLLER DRIVER
 P:	Adam Radford
 M:	linuxraid@amcc.com
 L:	linux-scsi@vger.kernel.org
 W:	http://www.amcc.com
 S:	Supported
 
-3W-9XXX SATA-RAID CONTROLLER DRIVER
+3W-XXXX ATA-RAID CONTROLLER DRIVER
 P:	Adam Radford
 M:	linuxraid@amcc.com
 L:	linux-scsi@vger.kernel.org
@@ -163,16 +164,11 @@
 L:	linux-m68k@lists.linux-m68k.org
 S:	Maintained
 
-AFS FILESYSTEM & AF_RXRPC SOCKET DOMAIN
-P:	David Howells
-M:	dhowells@redhat.com
-L:	linux-afs@lists.infradead.org
-S:	Supported
-
-AIO
-P:	Benjamin LaHaise
-M:	bcrl@kvack.org
-L:	linux-aio@kvack.org
+AACRAID SCSI RAID DRIVER
+P:	Adaptec OEM Raid Solutions
+M:	aacraid@adaptec.com
+L:	linux-scsi@vger.kernel.org
+W:	http://www.adaptec.com/
 S:	Supported
 
 ABIT UGURU 1,2 HARDWARE MONITOR DRIVER
@@ -193,27 +189,6 @@
 L:	linux-acenic@sunsite.dk
 S:	Maintained
 
-IPS SCSI RAID DRIVER
-P:	Adaptec OEM Raid Solutions
-M:	aacraid@adaptec.com
-L:	linux-scsi@vger.kernel.org
-W:	http://www.adaptec.com/
-S:	Maintained
-
-DPT_I2O SCSI RAID DRIVER
-P:	Adaptec OEM Raid Solutions
-M:	aacraid@adaptec.com
-L:	linux-scsi@vger.kernel.org
-W:	http://www.adaptec.com/
-S:	Maintained
-
-AACRAID SCSI RAID DRIVER
-P:	Adaptec OEM Raid Solutions
-M:	aacraid@adaptec.com
-L:	linux-scsi@vger.kernel.org
-W:	http://www.adaptec.com/
-S:	Supported
-
 ACER WMI LAPTOP EXTRAS
 P:	Carlos Corbacho
 M:	carlos@strangeworlds.co.uk
@@ -271,20 +246,20 @@
 S:	Supported
 
 ACPI WMI DRIVER
-P:      Carlos Corbacho
-M:      carlos@strangeworlds.co.uk
-L:      linux-acpi@vger.kernel.org
-W:      http://www.lesswatts.org/projects/acpi/
-S:      Maintained
+P:	Carlos Corbacho
+M:	carlos@strangeworlds.co.uk
+L:	linux-acpi@vger.kernel.org
+W:	http://www.lesswatts.org/projects/acpi/
+S:	Maintained
 
 AD1889 ALSA SOUND DRIVER
-P:     Kyle McMartin
-M:     kyle@mcmartin.ca
-P:     Thibaut Varene
-M:     T-Bone@parisc-linux.org
-W:     http://wiki.parisc-linux.org/AD1889
-L:     linux-parisc@vger.kernel.org
-S:     Maintained
+P:	Kyle McMartin
+M:	kyle@mcmartin.ca
+P:	Thibaut Varene
+M:	T-Bone@parisc-linux.org
+W:	http://wiki.parisc-linux.org/AD1889
+L:	linux-parisc@vger.kernel.org
+S:	Maintained
 
 ADM1025 HARDWARE MONITOR DRIVER
 P:	Jean Delvare
@@ -327,6 +302,12 @@
 M:	zippel@linux-m68k.org
 S:	Maintained
 
+AFS FILESYSTEM & AF_RXRPC SOCKET DOMAIN
+P:	David Howells
+M:	dhowells@redhat.com
+L:	linux-afs@lists.infradead.org
+S:	Supported
+
 AGPGART DRIVER
 P:	David Airlie
 M:	airlied@linux.ie
@@ -345,6 +326,12 @@
 L:	linux-scsi@vger.kernel.org
 S:	Maintained
 
+AIO
+P:	Benjamin LaHaise
+M:	bcrl@kvack.org
+L:	linux-aio@kvack.org
+S:	Supported
+
 ALCATEL SPEEDTOUCH USB DRIVER
 P:	Duncan Sands
 M:	duncan.sands@free.fr
@@ -387,8 +374,14 @@
 P:	Joerg Roedel
 M:	joerg.roedel@amd.com
 L:	iommu@lists.linux-foundation.org
+T:	git://git.kernel.org/pub/scm/linux/kernel/git/joro/linux-2.6-iommu.git
 S:	Supported
 
+AMD MICROCODE UPDATE SUPPORT
+P:      Peter Oruba
+M:      peter.oruba@amd.com
+S:      Supported
+
 AMS (Apple Motion Sensor) DRIVER
 P:	Stelian Pop
 M:	stelian@popies.net
@@ -466,6 +459,12 @@
 L:	linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only)
 S:	Maintained
 
+ARM/AFEB9260 MACHINE SUPPORT
+P:	Sergey Lapin
+M:	slapin@ossfans.org
+L:	linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only)
+S:	Maintained
+
 ARM/AJECO 1ARM MACHINE SUPPORT
 P:	Lennert Buytenhek
 M:	kernel@wantstofly.org
@@ -473,11 +472,11 @@
 S:	Maintained
 
 ARM/ATMEL AT91RM9200 ARM ARCHITECTURE
-P:      Andrew Victor
-M:      linux@maxim.org.za
-L:      linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only)
-W:      http://maxim.org.za/at91_26.html
-S:      Maintained
+P:	Andrew Victor
+M:	linux@maxim.org.za
+L:	linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only)
+W:	http://maxim.org.za/at91_26.html
+S:	Maintained
 
 ARM/CIRRUS LOGIC EP93XX ARM ARCHITECTURE
 P:	Lennert Buytenhek
@@ -491,7 +490,7 @@
 L:	linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only)
 S:	Maintained
 
-ARM/COMPULAB CM-X270/EM-X270 MACHINE SUPPORT
+ARM/COMPULAB CM-X270/EM-X270 and CM-X300 MACHINE SUPPORT
 P:	Mike Rapoport
 M:	mike@compulab.co.il
 L:	linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only)
@@ -532,10 +531,10 @@
 S:	Maintained
 
 ARM/HP JORNADA 7XX MACHINE SUPPORT
-P:      Kristoffer Ericson
-M:      kristoffer.ericson@gmail.com
-W:      www.jlime.com
-S:      Maintained
+P:	Kristoffer Ericson
+M:	kristoffer.ericson@gmail.com
+W:	www.jlime.com
+S:	Maintained
 
 ARM/INTEL IOP32X ARM ARCHITECTURE
 P:	Lennert Buytenhek
@@ -623,6 +622,12 @@
 W:	http://hackndev.com
 S:	Maintained
 
+ARM/PALMZ72 SUPPORT
+P:     Sergey Lapin
+M:     slapin@ossfans.org
+W:     http://hackndev.com
+S:     Maintained
+
 ARM/PLEB SUPPORT
 P:	Peter Chubb
 M:	pleb@gelato.unsw.edu.au
@@ -719,7 +724,7 @@
 W:	http://sourceforge.net/projects/xscaleiop
 S:	Supported
 
-ATA OVER ETHERNET DRIVER
+ATA OVER ETHERNET (AOE) DRIVER
 P:	Ed L. Cashin
 M:	ecashin@coraid.com
 W:	http://www.coraid.com/support/linux
@@ -852,11 +857,48 @@
 W:	http://www.linux-ax25.org/
 S:	Maintained
 
+B43 WIRELESS DRIVER
+P:	Michael Buesch
+M:	mb@bu3sch.de
+P:	Stefano Brivio
+M:	stefano.brivio@polimi.it
+L:	linux-wireless@vger.kernel.org
+W:	http://linuxwireless.org/en/users/Drivers/b43
+S:	Maintained
+
+B43LEGACY WIRELESS DRIVER
+P:	Larry Finger
+M:	Larry.Finger@lwfinger.net
+P:	Stefano Brivio
+M:	stefano.brivio@polimi.it
+L:	linux-wireless@vger.kernel.org
+W:	http://linuxwireless.org/en/users/Drivers/b43
+S:	Maintained
+
 BACKLIGHT CLASS/SUBSYSTEM
 P:	Richard Purdie
 M:	rpurdie@rpsys.net
 S:	Maintained
 
+BAYCOM/HDLCDRV DRIVERS FOR AX.25
+P:	Thomas Sailer
+M:	t.sailer@alumni.ethz.ch
+L:	linux-hams@vger.kernel.org
+W:	http://www.baycom.org/~tom/ham/ham.html
+S:	Maintained
+
+BEFS FILE SYSTEM
+P:	Sergey S. Kostyliov
+M:	rathamahata@php4.ru
+L:	linux-kernel@vger.kernel.org
+S:	Maintained
+
+BFS FILE SYSTEM
+P:	Tigran A. Aivazian
+M:	tigran@aivazian.fsnet.co.uk
+L:	linux-kernel@vger.kernel.org
+S:	Maintained
+
 BLACKFIN ARCHITECTURE
 P:	Bryan Wu
 M:	cooloney@kernel.org
@@ -892,43 +934,6 @@
 W:	http://blackfin.uclinux.org
 S:	Supported
 
-BAYCOM/HDLCDRV DRIVERS FOR AX.25
-P:	Thomas Sailer
-M:	t.sailer@alumni.ethz.ch
-L:	linux-hams@vger.kernel.org
-W:	http://www.baycom.org/~tom/ham/ham.html
-S:	Maintained
-
-B43 WIRELESS DRIVER
-P:	Michael Buesch
-M:	mb@bu3sch.de
-P:	Stefano Brivio
-M:	stefano.brivio@polimi.it
-L:	linux-wireless@vger.kernel.org
-W:	http://linuxwireless.org/en/users/Drivers/b43
-S:	Maintained
-
-B43LEGACY WIRELESS DRIVER
-P:	Larry Finger
-M:	Larry.Finger@lwfinger.net
-P:	Stefano Brivio
-M:	stefano.brivio@polimi.it
-L:	linux-wireless@vger.kernel.org
-W:	http://linuxwireless.org/en/users/Drivers/b43
-S:	Maintained
-
-BEFS FILE SYSTEM
-P:	Sergey S. Kostyliov
-M:	rathamahata@php4.ru
-L:	linux-kernel@vger.kernel.org
-S:	Maintained
-
-BFS FILE SYSTEM
-P:	Tigran A. Aivazian
-M:	tigran@aivazian.fsnet.co.uk
-L:	linux-kernel@vger.kernel.org
-S:	Maintained
-
 BLACKFIN I2C TWI DRIVER
 P:	Sonic Zhang
 M:	sonic.zhang@analog.com
@@ -1017,20 +1022,11 @@
 S:	Maintained
 
 CAFE CMOS INTEGRATED CAMERA CONTROLLER DRIVER
-P:   	Jonathan Corbet
+P:	Jonathan Corbet
 M:	corbet@lwn.net
 L:	video4linux-list@redhat.com
 S:	Maintained
 
-CAN NETWORK LAYER
-P:	Urs Thuermann
-M:	urs.thuermann@volkswagen.de
-P:	Oliver Hartkopp
-M:	oliver.hartkopp@volkswagen.de
-L:	socketcan-core@lists.berlios.de (subscribers-only)
-W:	http://developer.berlios.de/projects/socketcan/
-S:	Maintained
-
 CALGARY x86-64 IOMMU
 P:	Muli Ben-Yehuda
 M:	muli@il.ibm.com
@@ -1040,6 +1036,15 @@
 L:	discuss@x86-64.org
 S:	Maintained
 
+CAN NETWORK LAYER
+P:	Urs Thuermann
+M:	urs.thuermann@volkswagen.de
+P:	Oliver Hartkopp
+M:	oliver.hartkopp@volkswagen.de
+L:	socketcan-core@lists.berlios.de (subscribers-only)
+W:	http://developer.berlios.de/projects/socketcan/
+S:	Maintained
+
 CELL BROADBAND ENGINE ARCHITECTURE
 P:	Arnd Bergmann
 M:	arnd@arndb.de
@@ -1079,19 +1084,11 @@
 M:	jschopp@austin.ibm.com
 S:	Supported
 
-COMMON INTERNET FILE SYSTEM (CIFS)
-P:	Steve French
-M:	sfrench@samba.org
-L:	linux-cifs-client@lists.samba.org
-L:	samba-technical@lists.samba.org
-W:	http://linux-cifs.samba.org/
-T:	git kernel.org:/pub/scm/linux/kernel/git/sfrench/cifs-2.6.git
-S:	Supported
-
-CONFIGFS
-P:	Joel Becker
-M:	joel.becker@oracle.com
-L:	linux-kernel@vger.kernel.org
+CISCO 10G ETHERNET DRIVER
+P:	Scott Feldman
+M:	scofeldm@cisco.com
+P:	Joe Eykholt
+M:	jeykholt@cisco.com
 S:	Supported
 
 CIRRUS LOGIC EP93XX ETHERNET DRIVER
@@ -1127,6 +1124,15 @@
 W:	http://www.coda.cs.cmu.edu/
 S:	Maintained
 
+COMMON INTERNET FILE SYSTEM (CIFS)
+P:	Steve French
+M:	sfrench@samba.org
+L:	linux-cifs-client@lists.samba.org
+L:	samba-technical@lists.samba.org
+W:	http://linux-cifs.samba.org/
+T:	git kernel.org:/pub/scm/linux/kernel/git/sfrench/cifs-2.6.git
+S:	Supported
+
 COMPACTPCI HOTPLUG CORE
 P:	Scott Murray
 M:	scottm@somanetworks.com
@@ -1166,6 +1172,12 @@
 W:	http://accessrunner.sourceforge.net/
 S:	Maintained
 
+CONFIGFS
+P:	Joel Becker
+M:	joel.becker@oracle.com
+L:	linux-kernel@vger.kernel.org
+S:	Supported
+
 CONTROL GROUPS (CGROUPS)
 P:	Paul Menage
 M:	menage@google.com
@@ -1198,9 +1210,7 @@
 S:	Maintained
 
 CPUSETS
-P:	Paul Jackson
 P:	Paul Menage
-M:	pj@sgi.com
 M:	menage@google.com
 L:	linux-kernel@vger.kernel.org
 W:	http://www.bullopensource.org/cpuset/
@@ -1291,6 +1301,20 @@
 L:	linux-hams@vger.kernel.org
 S:	Maintained
 
+DAVICOM FAST ETHERNET (DMFE) NETWORK DRIVER
+P:	Tobias Ringstrom
+M:	tori@unhappy.mine.nu
+L:	netdev@vger.kernel.org
+S:	Maintained
+
+DC390/AM53C974 SCSI driver
+P:	Kurt Garloff
+M:	garloff@suse.de
+W:	http://www.garloff.de/kurt/linux/dc390/
+P:	Guennadi Liakhovetski
+M:	g.liakhovetski@gmx.de
+S:	Maintained
+
 DC395x SCSI driver
 P:	Oliver Neukum
 M:	oliver@neukum.name
@@ -1303,14 +1327,6 @@
 L:	http://lists.twibble.org/mailman/listinfo/dc395x/
 S:	Maintained
 
-DC390/AM53C974 SCSI driver
-P:	Kurt Garloff
-M:	garloff@suse.de
-W:	http://www.garloff.de/kurt/linux/dc390/
-P:	Guennadi Liakhovetski
-M:	g.liakhovetski@gmx.de
-S:	Maintained
-
 DCCP PROTOCOL
 P:	Arnaldo Carvalho de Melo
 M:	acme@ghostprotocols.net
@@ -1341,12 +1357,6 @@
 M:	Douglas_Warzecha@dell.com
 S:	Maintained
 
-DEVICE-MAPPER  (LVM)
-P:	Alasdair Kergon
-L:	dm-devel@redhat.com
-W:	http://sources.redhat.com/dm
-S:	Maintained
-
 DEVICE NUMBER REGISTRY
 P:	Torben Mathiasen
 M:	device@lanana.org
@@ -1354,14 +1364,20 @@
 L:	linux-kernel@vger.kernel.org
 S:	Maintained
 
+DEVICE-MAPPER  (LVM)
+P:	Alasdair Kergon
+L:	dm-devel@redhat.com
+W:	http://sources.redhat.com/dm
+S:	Maintained
+
 DIGI INTL. EPCA DRIVER
 P:	Digi International, Inc
 M:	Eng.Linux@digi.com
 L:	Eng.Linux@digi.com
 W:	http://www.digi.com
-S:	Orphaned
+S:	Orphan
 
-DIRECTORY NOTIFICATION
+DIRECTORY NOTIFICATION (DNOTIFY)
 P:	Stephen Rothwell
 M:	sfr@canb.auug.org.au
 L:	linux-kernel@vger.kernel.org
@@ -1375,13 +1391,13 @@
 W:	http://www.win.tue.nl/~aeb/partitions/partition_types-1.html
 S:	Maintained
 
-DISKQUOTA:
+DISKQUOTA
 P:	Jan Kara
 M:	jack@suse.cz
 L:	linux-kernel@vger.kernel.org
 S:	Maintained
 
-DISTRIBUTED LOCK MANAGER
+DISTRIBUTED LOCK MANAGER (DLM)
 P:	Christine Caulfield
 M:	ccaulfie@redhat.com
 P:	David Teigland
@@ -1391,12 +1407,6 @@
 T:	git kernel.org:/pub/scm/linux/kernel/git/teigland/dlm.git
 S:	Supported
 
-DAVICOM FAST ETHERNET (DMFE) NETWORK DRIVER
-P:	Tobias Ringstrom
-M:	tori@unhappy.mine.nu
-L:	netdev@vger.kernel.org
-S:	Maintained
-
 DMA GENERIC OFFLOAD ENGINE SUBSYSTEM
 P:	Maciej Sosnowski
 M:	maciej.sosnowski@intel.com
@@ -1423,12 +1433,12 @@
 S:	Supported
 
 DOCUMENTATION (/Documentation directory)
-P:     Michael Kerrisk
-M:     mtk.manpages@gmail.com
-P:     Randy Dunlap
-M:     rdunlap@xenotime.net
-L:     linux-doc@vger.kernel.org
-S:     Maintained
+P:	Michael Kerrisk
+M:	mtk.manpages@gmail.com
+P:	Randy Dunlap
+M:	rdunlap@xenotime.net
+L:	linux-doc@vger.kernel.org
+S:	Maintained
 
 DOUBLETALK DRIVER
 P:	James R. Van Zandt
@@ -1436,6 +1446,13 @@
 L:	blinux-list@redhat.com
 S:	Maintained
 
+DPT_I2O SCSI RAID DRIVER
+P:	Adaptec OEM Raid Solutions
+M:	aacraid@adaptec.com
+L:	linux-scsi@vger.kernel.org
+W:	http://www.adaptec.com/
+S:	Maintained
+
 DRIVER CORE, KOBJECTS, AND SYSFS
 P:	Greg Kroah-Hartman
 M:	gregkh@suse.de
@@ -1459,7 +1476,7 @@
 DVB SUBSYSTEM AND DRIVERS
 P:	LinuxTV.org Project
 M:	v4l-dvb-maintainer@linuxtv.org
-L: 	linux-dvb@linuxtv.org (subscription required)
+L:	linux-dvb@linuxtv.org (subscription required)
 W:	http://linuxtv.org/
 T:	git kernel.org:/pub/scm/linux/kernel/git/mchehab/v4l-dvb.git
 S:	Maintained
@@ -1584,7 +1601,7 @@
 W:	http://aeschi.ch.eu.org/efs/
 S:	Orphan
 
-EHCA (IBM GX bus InfiniBand adapter) DRIVER:
+EHCA (IBM GX bus InfiniBand adapter) DRIVER
 P:	Hoang-Nam Nguyen
 M:	hnguyen@de.ibm.com
 P:	Christoph Raisch
@@ -1641,9 +1658,10 @@
 S:	Maintained
 
 EXT4 FILE SYSTEM
-P:	Stephen Tweedie, Andrew Morton
-M:	sct@redhat.com, akpm@linux-foundation.org, adilger@sun.com
+P:	Theodore Ts'o
+M:	tytso@mit.edu, adilger@sun.com
 L:	linux-ext4@vger.kernel.org
+W:	http://ext4.wiki.kernel.org
 S:	Maintained
 
 F71805F HARDWARE MONITORING DRIVER
@@ -1663,6 +1681,42 @@
 M:	akinobu.mita@gmail.com
 S:	Supported
 
+FILE LOCKING (flock() and fcntl()/lockf())
+P:	Matthew Wilcox
+M:	matthew@wil.cx
+L:	linux-fsdevel@vger.kernel.org
+S:	Maintained
+
+FILESYSTEMS (VFS and infrastructure)
+P:	Alexander Viro
+M:	viro@zeniv.linux.org.uk
+L:	linux-fsdevel@vger.kernel.org
+S:	Maintained
+
+FIREWIRE SUBSYSTEM (drivers/firewire, <linux/firewire*.h>)
+P:	Kristian Hoegsberg, Stefan Richter
+M:	krh@redhat.com, stefanr@s5r6.in-berlin.de
+L:	linux1394-devel@lists.sourceforge.net
+W:	http://www.linux1394.org/
+T:	git kernel.org:/pub/scm/linux/kernel/git/ieee1394/linux1394-2.6.git
+S:	Maintained
+
+FIRMWARE LOADER (request_firmware)
+L:	linux-kernel@vger.kernel.org
+S:	Orphan
+
+FPU EMULATOR
+P:	Bill Metzenthen
+M:	billm@suburbia.net
+W:	http://suburbia.net/~billm/floating-point/emulator/
+S:	Maintained
+
+FRAME RELAY DLCI/FRAD (Sangoma drivers too)
+P:	Mike McLagan
+M:	mike.mclagan@linux.org
+L:	netdev@vger.kernel.org
+S:	Maintained
+
 FRAMEBUFFER LAYER
 P:	Antonino Daplas
 M:	adaplas@gmail.com
@@ -1728,42 +1782,6 @@
 L:	linuxppc-dev@ozlabs.org
 S:	Supported
 
-FILE LOCKING (flock() and fcntl()/lockf())
-P:	Matthew Wilcox
-M:	matthew@wil.cx
-L:	linux-fsdevel@vger.kernel.org
-S:	Maintained
-
-FILESYSTEMS (VFS and infrastructure)
-P:	Alexander Viro
-M:	viro@zeniv.linux.org.uk
-L:	linux-fsdevel@vger.kernel.org
-S:	Maintained
-
-FIREWIRE SUBSYSTEM (drivers/firewire, <linux/firewire*.h>)
-P:	Kristian Hoegsberg, Stefan Richter
-M:	krh@redhat.com, stefanr@s5r6.in-berlin.de
-L:	linux1394-devel@lists.sourceforge.net
-W:	http://www.linux1394.org/
-T:	git kernel.org:/pub/scm/linux/kernel/git/ieee1394/linux1394-2.6.git
-S:	Maintained
-
-FIRMWARE LOADER (request_firmware)
-L:	linux-kernel@vger.kernel.org
-S:	Orphan
-
-FPU EMULATOR
-P:	Bill Metzenthen
-M:	billm@suburbia.net
-W:	http://suburbia.net/~billm/floating-point/emulator/
-S:	Maintained
-
-FRAME RELAY DLCI/FRAD (Sangoma drivers too)
-P:	Mike McLagan
-M:	mike.mclagan@linux.org
-L:	netdev@vger.kernel.org
-S:	Maintained
-
 FREEVXFS FILESYSTEM
 P:	Christoph Hellwig
 M:	hch@infradead.org
@@ -1797,7 +1815,7 @@
 P:	Rik Faith
 M:	faith@cs.unc.edu
 L:	linux-scsi@vger.kernel.org
-S:	Odd fixes (e.g., new signatures)
+S:	Odd Fixes (e.g., new signatures)
 
 GDT SCSI DISK ARRAY CONTROLLER DRIVER
 P:	Achim Leubner
@@ -1835,14 +1853,6 @@
 W:	http://gigaset307x.sourceforge.net/
 S:	Maintained
 
-HARDWARE MONITORING
-L:	lm-sensors@lm-sensors.org
-W:	http://www.lm-sensors.org/
-S:	Orphaned
-
-HARDWARE RANDOM NUMBER GENERATOR CORE
-S:	Orphaned
-
 HARD DRIVE ACTIVE PROTECTION SYSTEM (HDAPS) DRIVER
 P:	Robert Love
 M:	rlove@rlove.org
@@ -1850,6 +1860,14 @@
 W:	http://www.kernel.org/pub/linux/kernel/people/rml/hdaps/
 S:	Maintained
 
+HARDWARE MONITORING
+L:	lm-sensors@lm-sensors.org
+W:	http://www.lm-sensors.org/
+S:	Orphan
+
+HARDWARE RANDOM NUMBER GENERATOR CORE
+S:	Orphan
+
 HARMONY SOUND DRIVER
 P:	Kyle McMartin
 M:	kyle@mcmartin.ca
@@ -1863,6 +1881,24 @@
 W:	http://www.nyx.net/~arobinso
 S:	Maintained
 
+HEWLETT-PACKARD FIBRE CHANNEL 64-bit/66MHz PCI non-intelligent HBA
+P:	Chirag Kantharia
+M:	chirag.kantharia@hp.com
+L:	iss_storagedev@hp.com
+S:	Maintained
+
+HEWLETT-PACKARD SMART2 RAID DRIVER
+P:	Chirag Kantharia
+M:	chirag.kantharia@hp.com
+L:	iss_storagedev@hp.com
+S:	Maintained
+
+HEWLETT-PACKARD SMART CISS RAID DRIVER (cciss)
+P:	Mike Miller
+M:	mike.miller@hp.com
+L:	iss_storagedev@hp.com
+S:	Supported
+
 HFS FILESYSTEM
 P:	Roman Zippel
 M:	zippel@linux-m68k.org
@@ -1876,6 +1912,14 @@
 W:	http://drama.obuda.kando.hu/~fero/cgi-bin/hgafb.shtml
 S:	Maintained
 
+HIBERNATION (aka Software Suspend, aka swsusp)
+P:	Pavel Machek
+M:	pavel@suse.cz
+P:	Rafael J. Wysocki
+M:	rjw@sisk.pl
+L:	linux-pm@lists.linux-foundation.org
+S:	Supported
+
 HID CORE LAYER
 P:	Jiri Kosina
 M:	jkosina@suse.cz
@@ -1908,24 +1952,6 @@
 L:	linux-hippi@sunsite.dk
 S:	Maintained
 
-HEWLETT-PACKARD FIBRE CHANNEL 64-bit/66MHz PCI non-intelligent HBA
-P:	Chirag Kantharia
-M:	chirag.kantharia@hp.com
-L:	iss_storagedev@hp.com
-S:	Maintained
-
-HEWLETT-PACKARD SMART2 RAID DRIVER
-P:	Chirag Kantharia
-M:	chirag.kantharia@hp.com
-L:	iss_storagedev@hp.com
-S:	Maintained
-
-HEWLETT-PACKARD SMART CISS RAID DRIVER (cciss)
-P:	Mike Miller
-M:	mike.miller@hp.com
-L:	iss_storagedev@hp.com
-S:	Supported
-
 HOST AP DRIVER
 P:	Jouni Malinen
 M:	j@w1.fi
@@ -1934,16 +1960,16 @@
 W:	http://hostap.epitest.fi/
 S:	Maintained
 
-HP100:	Driver for HP 10/100 Mbit/s Voice Grade Network Adapter Series
-P:	Jaroslav Kysela
-M:	perex@perex.cz
-S:	Maintained
-
 HP COMPAQ TC1100 TABLET WMI EXTRAS DRIVER
 P:	Carlos Corbacho
 M:	carlos@strangeworlds.co.uk
 S:	Odd Fixes
 
+HP100:	Driver for HP 10/100 Mbit/s Voice Grade Network Adapter Series
+P:	Jaroslav Kysela
+M:	perex@perex.cz
+S:	Maintained
+
 HPET:	High Precision Event Timers driver (drivers/char/hpet.c)
 P:	Clemens Ladisch
 M:	clemens@ladisch.de
@@ -1984,7 +2010,7 @@
 I2C/SMBUS STUB DRIVER
 P:	Mark M. Hoffman
 M:	mhoffman@lightlink.com
-L:	lm-sensors@lm-sensors.org
+L:	i2c@lm-sensors.org
 S:	Maintained
 
 I2C SUBSYSTEM
@@ -2023,14 +2049,6 @@
 T:	git kernel.org:/pub/scm/linux/kernel/git/aegl/linux-2.6.git
 S:	Maintained
 
-SN-IA64 (Itanium) SUB-PLATFORM
-P:	Jes Sorensen
-M:	jes@sgi.com
-L:	linux-altix@sgi.com
-L:	linux-ia64@vger.kernel.org
-W:	http://www.sgi.com/altix
-S:	Maintained
-
 IBM MCA SCSI SUBSYSTEM DRIVER
 P:	Michael Lang
 M:	langa2@kph.uni-mainz.de
@@ -2108,20 +2126,12 @@
 P:	Sean Hefty
 M:	sean.hefty@intel.com
 P:	Hal Rosenstock
-M:	hal.rosenstock@gmail.com 
+M:	hal.rosenstock@gmail.com
 L:	general@lists.openfabrics.org
 W:	http://www.openib.org/
 T:	git kernel.org:/pub/scm/linux/kernel/git/roland/infiniband.git
 S:	Supported
 
-INPUT (KEYBOARD, MOUSE, JOYSTICK, TOUCHSCREEN) DRIVERS
-P:	Dmitry Torokhov
-M:	dmitry.torokhov@gmail.com
-M:	dtor@mail.ru
-L:	linux-input@vger.kernel.org
-T:	git kernel.org:/pub/scm/linux/kernel/git/dtor/input.git
-S:	Maintained
-
 INOTIFY
 P:	John McCutchan
 M:	ttb@tentacle.dhs.org
@@ -2130,6 +2140,14 @@
 L:	linux-kernel@vger.kernel.org
 S:	Maintained
 
+INPUT (KEYBOARD, MOUSE, JOYSTICK, TOUCHSCREEN) DRIVERS
+P:	Dmitry Torokhov
+M:	dmitry.torokhov@gmail.com
+M:	dtor@mail.ru
+L:	linux-input@vger.kernel.org
+T:	git kernel.org:/pub/scm/linux/kernel/git/dtor/input.git
+S:	Maintained
+
 INTEL FRAMEBUFFER DRIVER (excluding 810 and 815)
 P:	Sylvain Meyer
 M:	sylvain.meyer@worldonline.fr
@@ -2234,7 +2252,7 @@
 L:	linux-mips@linux-mips.org
 S:	Maintained
 
-IP MASQUERADING:
+IP MASQUERADING
 P:	Juanjo Ciarlante
 M:	jjciarla@raiz.uncu.edu.ar
 S:	Maintained
@@ -2249,7 +2267,7 @@
 L:	netdev@vger.kernel.org
 S:	Maintained
 
-IPATH DRIVER:
+IPATH DRIVER
 P:	Ralph Campbell
 M:	infinipath@qlogic.com
 L:	general@lists.openfabrics.org
@@ -2263,13 +2281,25 @@
 W:	http://openipmi.sourceforge.net/
 S:	Supported
 
-IPX NETWORK LAYER
-P:	Arnaldo Carvalho de Melo
-M:	acme@ghostprotocols.net
-L:	netdev@vger.kernel.org
+IPS SCSI RAID DRIVER
+P:	Adaptec OEM Raid Solutions
+M:	aacraid@adaptec.com
+L:	linux-scsi@vger.kernel.org
+W:	http://www.adaptec.com/
 S:	Maintained
 
-IPWIRELES DRIVER
+IPVS
+P:	Wensong Zhang
+M:	wensong@linux-vs.org
+P:	Simon Horman
+M:	horms@verge.net.au
+P:	Julian Anastasov
+M:	ja@ssi.bg
+L:	netdev@vger.kernel.org
+L:	lvs-devel@vger.kernel.org
+S:	Maintained
+
+IPWIRELESS DRIVER
 P:	Jiri Kosina
 M:	jkosina@suse.cz
 P:	David Sterba
@@ -2277,6 +2307,12 @@
 S:	Maintained
 T:	git://git.kernel.org/pub/scm/linux/kernel/git/jikos/ipwireless_cs.git
 
+IPX NETWORK LAYER
+P:	Arnaldo Carvalho de Melo
+M:	acme@ghostprotocols.net
+L:	netdev@vger.kernel.org
+S:	Maintained
+
 IRDA SUBSYSTEM
 P:	Samuel Ortiz
 M:	samuel@sortiz.org
@@ -2284,6 +2320,11 @@
 W:	http://irda.sourceforge.net/
 S:	Maintained
 
+ISAPNP
+P:	Jaroslav Kysela
+M:	perex@perex.cz
+S:	Maintained
+
 ISCSI
 P:	Mike Christie
 M:	michaelc@cs.wisc.edu
@@ -2292,11 +2333,6 @@
 T:	git kernel.org:/pub/scm/linux/kernel/mnc/linux-2.6-iscsi.git
 S:	Maintained
 
-ISAPNP
-P:	Jaroslav Kysela
-M:	perex@perex.cz
-S:	Maintained
-
 ISDN SUBSYSTEM
 P:	Karsten Keil
 M:	kkeil@suse.de
@@ -2321,23 +2357,6 @@
 W:	http://www.ivtvdriver.org
 S:	Maintained
 
-JOURNALLING FLASH FILE SYSTEM V2 (JFFS2)
-P:	David Woodhouse
-M:	dwmw2@infradead.org
-L:	linux-mtd@lists.infradead.org
-W:	http://www.linux-mtd.infradead.org/doc/jffs2.html
-S:	Maintained
-
-UBI FILE SYSTEM (UBIFS)
-P:	Artem Bityutskiy
-M:	dedekind@infradead.org
-P:	Adrian Hunter
-M:	ext-adrian.hunter@nokia.com
-L:	linux-mtd@lists.infradead.org
-T:	git git://git.infradead.org/~dedekind/ubifs-2.6.git
-W:	http://www.linux-mtd.infradead.org/doc/ubifs.html
-S:	Maintained
-
 JFS FILESYSTEM
 P:	Dave Kleikamp
 M:	shaggy@austin.ibm.com
@@ -2346,6 +2365,19 @@
 T:	git kernel.org:/pub/scm/linux/kernel/git/shaggy/jfs-2.6.git
 S:	Supported
 
+JME NETWORK DRIVER
+P:	Guo-Fu Tseng
+M:	cooldavid@cooldavid.org
+L:	netdev@vger.kernel.org
+S:	Maintained
+
+JOURNALLING FLASH FILE SYSTEM V2 (JFFS2)
+P:	David Woodhouse
+M:	dwmw2@infradead.org
+L:	linux-mtd@lists.infradead.org
+W:	http://www.linux-mtd.infradead.org/doc/jffs2.html
+S:	Maintained
+
 JOURNALLING LAYER FOR BLOCK DEVICES (JBD)
 P:	Stephen Tweedie, Andrew Morton
 M:	sct@redhat.com, akpm@linux-foundation.org
@@ -2582,11 +2614,6 @@
 L:	linuxppc-dev@ozlabs.org
 S:	Supported
 
-LLC (802.2)
-P:	Arnaldo Carvalho de Melo
-M:	acme@ghostprotocols.net
-S:	Maintained
-
 LINUX SECURITY MODULE (LSM) FRAMEWORK
 P:	Chris Wright
 M:	chrisw@sous-sol.org
@@ -2594,6 +2621,11 @@
 T:	git kernel.org:/pub/scm/linux/kernel/git/chrisw/lsm-2.6.git
 S:	Supported
 
+LLC (802.2)
+P:	Arnaldo Carvalho de Melo
+M:	acme@ghostprotocols.net
+S:	Maintained
+
 LM83 HARDWARE MONITOR DRIVER
 P:	Jean Delvare
 M:	khali@linux-fr.org
@@ -2694,19 +2726,12 @@
 L:	netdev@vger.kernel.org
 S:	Maintained
 
-MARVELL YUKON / SYSKONNECT DRIVER
-P:	Mirko Lindner
-M: 	mlindner@syskonnect.de
-P:	Ralph Roesler
-M: 	rroesler@syskonnect.de
-W: 	http://www.syskonnect.com
-S: 	Supported
-
 MAN-PAGES: MANUAL PAGES FOR LINUX -- Sections 2, 3, 4, 5, and 7
 P:	Michael Kerrisk
 M:	mtk.manpages@gmail.com
-W:     http://www.kernel.org/doc/man-pages
-S:     Supported
+W:	http://www.kernel.org/doc/man-pages
+L:	linux-man@vger.kernel.org
+S:	Supported
 
 MARVELL LIBERTAS WIRELESS DRIVER
 P:	Dan Williams
@@ -2720,6 +2745,14 @@
 L:	netdev@vger.kernel.org
 S:	Supported
 
+MARVELL YUKON / SYSKONNECT DRIVER
+P:	Mirko Lindner
+M:	mlindner@syskonnect.de
+P:	Ralph Roesler
+M:	rroesler@syskonnect.de
+W:	http://www.syskonnect.com
+S:	Supported
+
 MATROX FRAMEBUFFER DRIVER
 P:	Petr Vandrovec
 M:	vandrove@vc.cvut.cz
@@ -2735,7 +2768,7 @@
 MEGARAID SCSI DRIVERS
 P:	Neela Syam Kolli
 M:	megaraidlinux@lsi.com
-S:	linux-scsi@vger.kernel.org
+L:	linux-scsi@vger.kernel.org
 W:	http://megaraid.lsilogic.com
 S:	Maintained
 
@@ -2756,15 +2789,6 @@
 L:	linux-kernel@vger.kernel.org
 S:	Maintained
 
-MEI MN10300/AM33 PORT
-P:	David Howells
-M:	dhowells@redhat.com
-P:	Koichi Yasutake
-M:	yasutake.koichi@jp.panasonic.com
-L:	linux-am33-list@redhat.com (moderated for non-subscribers)
-W:	ftp://ftp.redhat.com/pub/redhat/gnupro/AM33/
-S:	Maintained
-
 MEMORY TECHNOLOGY DEVICES (MTD)
 P:	David Woodhouse
 M:	dwmw2@infradead.org
@@ -2773,14 +2797,6 @@
 T:	git git://git.infradead.org/mtd-2.6.git
 S:	Maintained
 
-UNSORTED BLOCK IMAGES (UBI)
-P:	Artem Bityutskiy
-M:	dedekind@infradead.org
-W:	http://www.linux-mtd.infradead.org/
-L:	linux-mtd@lists.infradead.org
-T:	git git://git.infradead.org/~dedekind/ubi-2.6.git
-S:	Maintained
-
 MICROTEK X6 SCANNER
 P:	Oliver Neukum
 M:	oliver@neukum.name
@@ -2853,7 +2869,7 @@
 P:	David Brownell
 M:	dbrownell@users.sourceforge.net
 L:	linux-kernel@vger.kernel.org
-S:	Odd fixes
+S:	Odd Fixes
 
 MULTISOUND SOUND DRIVER
 P:	Andrew Veliath
@@ -2867,10 +2883,10 @@
 S:	Maintained
 
 MUSB MULTIPOINT HIGH SPEED DUAL-ROLE CONTROLLER
-P:     Felipe Balbi
-M:     felipe.balbi@nokia.com
-L:     linux-usb@vger.kernel.org
-S:     Maintained
+P:	Felipe Balbi
+M:	felipe.balbi@nokia.com
+L:	linux-usb@vger.kernel.org
+S:	Maintained
 
 MYRICOM MYRI-10G 10GbE DRIVER (MYRI10GE)
 P:	Andrew Gallatin
@@ -2882,7 +2898,7 @@
 S:	Supported
 
 NATSEMI ETHERNET DRIVER (DP8381x)
-P: 	Tim Hockin
+P:	Tim Hockin
 M:	thockin@hockin.org
 S:	Maintained
 
@@ -3012,17 +3028,6 @@
 W:	http://www.netxen.com
 S:	Supported
 
-IPVS
-P:	Wensong Zhang
-M:	wensong@linux-vs.org
-P:	Simon Horman
-M:	horms@verge.net.au
-P:	Julian Anastasov
-M:	ja@ssi.bg
-L:	netdev@vger.kernel.org
-L:	lvs-devel@vger.kernel.org
-S:	Maintained
-
 NFS, SUNRPC, AND LOCKD CLIENTS
 P:	Trond Myklebust
 M:	Trond.Myklebust@netapp.com
@@ -3068,22 +3073,6 @@
 L:	linux-fbdev-devel@lists.sourceforge.net (moderated for non-subscribers)
 S:	Maintained
 
-OPENCORES I2C BUS DRIVER
-P:	Peter Korsgaard
-M:	jacmet@sunsite.dk
-L:	i2c@lm-sensors.org
-S:	Maintained
-
-ORACLE CLUSTER FILESYSTEM 2 (OCFS2)
-P:	Mark Fasheh
-M:	mfasheh@suse.com
-P:	Joel Becker
-M:	joel.becker@oracle.com
-L:	ocfs2-devel@oss.oracle.com (moderated for non-subscribers)
-W:	http://oss.oracle.com/projects/ocfs2/
-T:	git git://git.kernel.org/pub/scm/linux/kernel/git/mfasheh/ocfs2.git
-S:	Supported
-
 OMFS FILESYSTEM
 P:	Bob Copeland
 M:	me@bobcopeland.com
@@ -3101,7 +3090,7 @@
 S:	Maintained
 
 OMNIVISION OV7670 SENSOR DRIVER
-P:   	Jonathan Corbet
+P:	Jonathan Corbet
 M:	corbet@lwn.net
 L:	video4linux-list@redhat.com
 S:	Maintained
@@ -3119,12 +3108,28 @@
 L:	linux-scsi@vger.kernel.org
 S:	Maintained
 
+OPENCORES I2C BUS DRIVER
+P:	Peter Korsgaard
+M:	jacmet@sunsite.dk
+L:	i2c@lm-sensors.org
+S:	Maintained
+
 OPROFILE
 P:	Robert Richter
 M:	robert.richter@amd.com
 L:	oprofile-list@lists.sf.net
 S:	Maintained
 
+ORACLE CLUSTER FILESYSTEM 2 (OCFS2)
+P:	Mark Fasheh
+M:	mfasheh@suse.com
+P:	Joel Becker
+M:	joel.becker@oracle.com
+L:	ocfs2-devel@oss.oracle.com (moderated for non-subscribers)
+W:	http://oss.oracle.com/projects/ocfs2/
+T:	git git://git.kernel.org/pub/scm/linux/kernel/git/mfasheh/ocfs2.git
+S:	Supported
+
 ORINOCO DRIVER
 P:	Pavel Roskin
 M:	proski@gnu.org
@@ -3136,6 +3141,14 @@
 W:	http://www.nongnu.org/orinoco/
 S:	Maintained
 
+P54 WIRELESS DRIVER
+P:	Michael Wu
+M:	flamingice@sourmilk.net
+L:	linux-wireless@vger.kernel.org
+W:	http://prism54.org
+T:	git kernel.org:/pub/scm/linux/kernel/git/mwu/mac80211-drivers.git
+S:	Maintained
+
 PA SEMI ETHERNET DRIVER
 P:	Olof Johansson
 M:	olof@lixom.net
@@ -3148,10 +3161,32 @@
 L:	i2c@lm-sensors.org
 S:	Maintained
 
+PANASONIC MN10300/AM33 PORT
+P:	David Howells
+M:	dhowells@redhat.com
+P:	Koichi Yasutake
+M:	yasutake.koichi@jp.panasonic.com
+L:	linux-am33-list@redhat.com (moderated for non-subscribers)
+W:	ftp://ftp.redhat.com/pub/redhat/gnupro/AM33/
+S:	Maintained
+
 PARALLEL PORT SUPPORT
 L:	linux-parport@lists.infradead.org (subscribers-only)
 S:	Orphan
 
+PARAVIRT_OPS INTERFACE
+P:	Jeremy Fitzhardinge
+M:	jeremy@xensource.com
+P:	Chris Wright
+M:	chrisw@sous-sol.org
+P:	Zachary Amsden
+M:	zach@vmware.com
+P:	Rusty Russell
+M:	rusty@rustcorp.com.au
+L:	virtualization@lists.osdl.org
+L:	linux-kernel@vger.kernel.org
+S:	Supported
+
 PARIDE DRIVERS FOR PARALLEL PORT IDE DEVICES
 P:	Tim Waugh
 M:	tim@cyberelk.net
@@ -3171,19 +3206,6 @@
 T:	git kernel.org:/pub/scm/linux/kernel/git/kyle/parisc-2.6.git
 S:	Maintained
 
-PARAVIRT_OPS INTERFACE
-P:	Jeremy Fitzhardinge
-M:	jeremy@xensource.com
-P:	Chris Wright
-M:	chrisw@sous-sol.org
-P:	Zachary Amsden
-M:	zach@vmware.com
-P:	Rusty Russell
-M:	rusty@rustcorp.com.au
-L:	virtualization@lists.osdl.org
-L:	linux-kernel@vger.kernel.org
-S:	Supported
-
 PC87360 HARDWARE MONITORING DRIVER
 P:	Jim Cromie
 M:	jim.cromie@gmail.com
@@ -3211,7 +3233,7 @@
 S:	Supported
 
 PCI HOTPLUG CORE
-P: 	Kristen Carlson Accardi
+P:	Kristen Carlson Accardi
 M:	kristen.c.accardi@intel.com
 S:	Supported
 
@@ -3313,14 +3335,6 @@
 W:	ftp://ftp.kernel.org/pub/linux/kernel/people/rml/preempt-kernel
 S:	Supported
 
-P54 WIRELESS DRIVER
-P:	Michael Wu
-M:	flamingice@sourmilk.net
-L:	linux-wireless@vger.kernel.org
-W:	http://prism54.org
-T:	git kernel.org:/pub/scm/linux/kernel/git/mwu/mac80211-drivers.git
-S:	Maintained
-
 PRISM54 WIRELESS DRIVER
 P:	Luis R. Rodriguez
 M:	mcgrof@gmail.com
@@ -3385,6 +3399,13 @@
 L:	netdev@vger.kernel.org
 S:	Supported
 
+QLOGIC QLGE 10Gb ETHERNET DRIVER
+P:	Ron Mercer
+M:	linux-driver@qlogic.com
+M:	ron.mercer@qlogic.com
+L:	netdev@vger.kernel.org
+S:	Supported
+
 QNX4 FILESYSTEM
 P:	Anders Larsen
 M:	al@alarsen.net
@@ -3404,13 +3425,7 @@
 L:	linux-fbdev-devel@lists.sourceforge.net (moderated for non-subscribers)
 S:	Maintained
 
-RAYLINK/WEBGEAR 802.11 WIRELESS LAN DRIVER
-P:	Corey Thomas
-M:	coreythomas@charter.net
-L:	linux-wireless@vger.kernel.org
-S:	Maintained
-
-RALINK RT2X00 WLAN DRIVER
+RALINK RT2X00 WIRELESS LAN DRIVER
 P:	rt2x00 project
 L:	linux-wireless@vger.kernel.org
 L:	rt2400-devel@lists.sourceforge.net
@@ -3435,6 +3450,18 @@
 L:	linux-kernel@vger.kernel.org
 S:	Maintained
 
+RAYLINK/WEBGEAR 802.11 WIRELESS LAN DRIVER
+P:	Corey Thomas
+M:	coreythomas@charter.net
+L:	linux-wireless@vger.kernel.org
+S:	Maintained
+
+RCUTORTURE MODULE
+P:	Josh Triplett
+M:	josh@freedesktop.org
+L:	linux-kernel@vger.kernel.org
+S:	Maintained
+
 RDC R-321X SoC
 P:	Florian Fainelli
 M:	florian.fainelli@telecomint.eu
@@ -3454,12 +3481,6 @@
 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
@@ -3483,6 +3504,9 @@
 S:	Maintained
 F:	net/rfkill
 
+RISCOM8 DRIVER
+S:	Orphan
+
 ROCKETPORT DRIVER
 P:	Comtrol Corp.
 W:	http://www.comtrol.com
@@ -3495,9 +3519,6 @@
 W:	http://www.linux-ax25.org/
 S:	Maintained
 
-RISCOM8 DRIVER
-S:	Orphan
-
 RTL818X WIRELESS DRIVER
 P:	Michael Wu
 M:	flamingice@sourmilk.net
@@ -3637,6 +3658,12 @@
 L:	sdricohcs-devel@lists.sourceforge.net (subscribers-only)
 S:	Maintained
 
+SECURE DIGITAL HOST CONTROLLER INTERFACE (SDHCI) DRIVER
+P:	Pierre Ossman
+M:	drzeus-sdhci@drzeus.cx
+L:	sdhci-devel@list.drzeus.cx
+S:	Maintained
+
 SECURITY CONTACT
 P:	Security Officers
 M:	security@kernel.org
@@ -3651,7 +3678,8 @@
 M:	eparis@parisplace.org
 L:	linux-kernel@vger.kernel.org (kernel issues)
 L: 	selinux@tycho.nsa.gov (subscribers-only, general discussion)
-W:	http://www.nsa.gov/selinux
+W:	http://selinuxproject.org
+T:	git kernel.org:pub/scm/linux/kernel/git/jmorris/security-testing-2.6.git
 S:	Supported
 
 SENSABLE PHANTOM
@@ -3659,19 +3687,13 @@
 M:	jirislaby@gmail.com
 S:	Maintained
 
-SERIAL ATA (SATA) SUBSYSTEM:
+SERIAL ATA (SATA) SUBSYSTEM
 P:	Jeff Garzik
 M:	jgarzik@pobox.com
 L:	linux-ide@vger.kernel.org
 T:	git kernel.org:/pub/scm/linux/kernel/git/jgarzik/libata-dev.git
 S:	Supported
 
-SGI SN-IA64 (Altix) SERIAL CONSOLE DRIVER
-P:	Pat Gefre
-M:	pfg@sgi.com
-L:	linux-ia64@vger.kernel.org
-S:	Supported
-
 SFC NETWORK DRIVER
 P:	Steve Hodgson
 P:	Ben Hutchings
@@ -3679,6 +3701,17 @@
 M:	linux-net-drivers@solarflare.com
 S:	Supported
 
+SGI GRU DRIVER
+P:	Jack Steiner
+M:	steiner@sgi.com
+S:	Maintained
+
+SGI SN-IA64 (Altix) SERIAL CONSOLE DRIVER
+P:	Pat Gefre
+M:	pfg@sgi.com
+L:	linux-ia64@vger.kernel.org
+S:	Supported
+
 SGI VISUAL WORKSTATION 320 AND 540
 P:	Andrey Panin
 M:	pazke@donpac.ru
@@ -3686,16 +3719,24 @@
 W:	http://linux-visws.sf.net
 S:	Maintained for 2.6.
 
-SGI GRU DRIVER
-P:	Jack Steiner
-M:	steiner@sgi.com
-S:	Maintained
-
 SGI XP/XPC/XPNET DRIVER
 P:	Dean Nelson
 M:	dcn@sgi.com
 S:	Maintained
 
+SHARP LH SUPPORT (LH7952X & LH7A40X)
+P:	Marc Singer
+M:	elf@buici.com
+W:	http://projects.buici.com/arm
+L:	linux-arm-kernel@lists.arm.linux.org.uk	(subscribers-only)
+S:	Maintained
+
+SHPC HOTPLUG DRIVER
+P:	Kristen Carlson Accardi
+M:	kristen.c.accardi@intel.com
+L:	linux-pci@vger.kernel.org
+S:	Supported
+
 SIMTEC EB110ATX (Chalice CATS)
 P:	Ben Dooks
 P:	Vincent Sanders
@@ -3726,7 +3767,7 @@
 SIS 96X I2C/SMBUS DRIVER
 P:	Mark M. Hoffman
 M:	mhoffman@lightlink.com
-L:	lm-sensors@lm-sensors.org
+L:	i2c@lm-sensors.org
 S:	Maintained
 
 SIS FRAMEBUFFER DRIVER
@@ -3741,6 +3782,12 @@
 W:	http://www.winischhofer.at/linuxsisusbvga.shtml
 S:	Maintained
 
+SKGE, SKY2 10/100/1000 GIGABIT ETHERNET DRIVERS
+P:	Stephen Hemminger
+M:	shemminger@linux-foundation.org
+L:	netdev@vger.kernel.org
+S:	Maintained
+
 SLAB ALLOCATOR
 P:	Christoph Lameter
 M:	cl@linux-foundation.org
@@ -3767,11 +3814,24 @@
 M:	bn@niasdigital.com
 S:	Maintained
 
+SN-IA64 (Itanium) SUB-PLATFORM
+P:	Jes Sorensen
+M:	jes@sgi.com
+L:	linux-altix@sgi.com
+L:	linux-ia64@vger.kernel.org
+W:	http://www.sgi.com/altix
+S:	Maintained
+
 SOC-CAMERA V4L2 SUBSYSTEM
-P:     Guennadi Liakhovetski
-M:     g.liakhovetski@gmx.de
-L:     video4linux-list@redhat.com
-S:     Maintained
+P:	Guennadi Liakhovetski
+M:	g.liakhovetski@gmx.de
+L:	video4linux-list@redhat.com
+S:	Maintained
+
+SOEKRIS NET48XX LED SUPPORT
+P:	Chris Boot
+M:	bootc@bootc.net
+S:	Maintained
 
 SOFTWARE RAID (Multiple Disks) SUPPORT
 P:	Ingo Molnar
@@ -3781,24 +3841,6 @@
 L:	linux-raid@vger.kernel.org
 S:	Supported
 
-HIBERNATION (aka Software Suspend, aka swsusp):
-P:	Pavel Machek
-M:	pavel@suse.cz
-P:	Rafael J. Wysocki
-M:	rjw@sisk.pl
-L:	linux-pm@lists.linux-foundation.org
-S:	Supported
-
-SUSPEND TO RAM:
-P:	Len Brown
-M:	len.brown@intel.com
-P:	Pavel Machek
-M:	pavel@suse.cz
-P:	Rafael J. Wysocki
-M:	rjw@sisk.pl
-L:	linux-pm@lists.linux-foundation.org
-S:	Supported
-
 SONIC NETWORK DRIVER
 P:	Thomas Bogendoerfer
 M:	tsbogend@alpha.franken.de
@@ -3828,71 +3870,22 @@
 SOUND
 P:	Jaroslav Kysela
 M:	perex@perex.cz
+P:	Takashi Iwai
+M:	tiwai@suse.de
 L:	alsa-devel@alsa-project.org (subscribers-only)
 S:	Maintained
 
 SOUND - SOC LAYER / DYNAMIC AUDIO POWER MANAGEMENT
 P:	Liam Girdwood
-M:	liam.girdwood@wolfsonmicro.com
+M:	lrg@slimlogic.co.uk
 P:	Mark Brown
 M:	broonie@opensource.wolfsonmicro.com
 T:	git opensource.wolfsonmicro.com/linux-2.6-asoc
 L:	alsa-devel@alsa-project.org (subscribers-only)
+W:	http://alsa-project.org/main/index.php/ASoC
 S:	Supported
 
-SPI SUBSYSTEM
-P:	David Brownell
-M:	dbrownell@users.sourceforge.net
-L:	spi-devel-general@lists.sourceforge.net
-S:	Maintained
-
-SPU FILE SYSTEM
-P:	Jeremy Kerr
-M:	jk@ozlabs.org
-L:	linuxppc-dev@ozlabs.org
-L:	cbe-oss-dev@ozlabs.org
-W:	http://www.ibm.com/developerworks/power/cell/
-S:	Supported
-
-STABLE BRANCH:
-P:	Greg Kroah-Hartman
-M:	greg@kroah.com
-P:	Chris Wright
-M:	chrisw@sous-sol.org
-L:	stable@kernel.org
-S:	Maintained
-
-SHARP LH SUPPORT (LH7952X & LH7A40X)
-P:	Marc Singer
-M:	elf@buici.com
-W:	http://projects.buici.com/arm
-L:	linux-arm-kernel@lists.arm.linux.org.uk	(subscribers-only)
-S:	Maintained
-
-SHPC HOTPLUG DRIVER
-P:	Kristen Carlson Accardi
-M:	kristen.c.accardi@intel.com
-L:	linux-pci@vger.kernel.org
-S:	Supported
-
-SECURE DIGITAL HOST CONTROLLER INTERFACE DRIVER
-P:	Pierre Ossman
-M:	drzeus-sdhci@drzeus.cx
-L:	sdhci-devel@list.drzeus.cx
-S:	Maintained
-
-SKGE, SKY2 10/100/1000 GIGABIT ETHERNET DRIVERS
-P:	Stephen Hemminger
-M:	shemminger@linux-foundation.org
-L:	netdev@vger.kernel.org
-S:	Maintained
-
-SOEKRIS NET48XX LED SUPPORT
-P:	Chris Boot
-M:	bootc@bootc.net
-S:	Maintained
-
-SPARC (sparc32):
+SPARC (sparc32)
 P:	William L. Irwin
 M:	wli@holomorphy.com
 L:	sparclinux@vger.kernel.org
@@ -3904,6 +3897,12 @@
 L:	linux-kernel@vger.kernel.org ?
 S:	Supported
 
+SPI SUBSYSTEM
+P:	David Brownell
+M:	dbrownell@users.sourceforge.net
+L:	spi-devel-general@lists.sourceforge.net
+S:	Maintained
+
 SPIDERNET NETWORK DRIVER for CELL
 P:	Ishizaki Kou
 M:	kou.ishizaki@toshiba.co.jp
@@ -3912,12 +3911,28 @@
 L:	netdev@vger.kernel.org
 S:	Supported
 
+SPU FILE SYSTEM
+P:	Jeremy Kerr
+M:	jk@ozlabs.org
+L:	linuxppc-dev@ozlabs.org
+L:	cbe-oss-dev@ozlabs.org
+W:	http://www.ibm.com/developerworks/power/cell/
+S:	Supported
+
 SRM (Alpha) environment access
 P:	Jan-Benedict Glaw
 M:	jbglaw@lug-owl.de
 L:	linux-kernel@vger.kernel.org
 S:	Maintained
 
+STABLE BRANCH:
+P:	Greg Kroah-Hartman
+M:	greg@kroah.com
+P:	Chris Wright
+M:	chrisw@sous-sol.org
+L:	stable@kernel.org
+S:	Maintained
+
 STARFIRE/DURALAN NETWORK DRIVER
 P:	Ion Badulescu
 M:	ionut@cs.columbia.edu
@@ -3925,7 +3940,7 @@
 
 STARMODE RADIO IP (STRIP) PROTOCOL DRIVER
 W:	http://mosquitonet.Stanford.EDU/strip.html
-S:	Unsupported ?
+S:	Orphan
 
 STRADIS MPEG-2 DECODER DRIVER
 P:	Nathan Laredo
@@ -3933,6 +3948,12 @@
 W:	http://www.stradis.com/
 S:	Maintained
 
+SUN3/3X
+P:	Sam Creasey
+M:	sammy@sammy.net
+W:	http://sammy.net/sun3/
+S:	Maintained
+
 SUPERH
 P:	Paul Mundt
 M:	lethal@linux-sh.org
@@ -3941,11 +3962,15 @@
 T:	git kernel.org:/pub/scm/linux/kernel/git/lethal/sh-2.6.git
 S:	Supported
 
-SUN3/3X
-P:	Sam Creasey
-M:	sammy@sammy.net
-W:	http://sammy.net/sun3/
-S:	Maintained
+SUSPEND TO RAM
+P:	Len Brown
+M:	len.brown@intel.com
+P:	Pavel Machek
+M:	pavel@suse.cz
+P:	Rafael J. Wysocki
+M:	rjw@sisk.pl
+L:	linux-pm@lists.linux-foundation.org
+S:	Supported
 
 SVGA HANDLING
 P:	Martin Mares
@@ -3991,7 +4016,7 @@
 M:	mark.gross@intel.com
 S:	Supported
 
-TENSILICA XTENSA PORT (xtensa):
+TENSILICA XTENSA PORT (xtensa)
 P:	Chris Zankel
 M:	chris@zankel.net
 S:	Maintained
@@ -4006,9 +4031,9 @@
 S:	Maintained
 
 TI FLASH MEDIA INTERFACE DRIVER
-P:      Alex Dubov
-M:      oakad@yahoo.com
-S:      Maintained
+P:	Alex Dubov
+M:	oakad@yahoo.com
+S:	Maintained
 
 TI OMAP MMC INTERFACE DRIVER
 P:	Carlos Aguiar, Anderson Briglia and Syed Khasim
@@ -4105,6 +4130,16 @@
 L:	linux-scsi@vger.kernel.org
 S:	Maintained
 
+UBI FILE SYSTEM (UBIFS)
+P:	Artem Bityutskiy
+M:	dedekind@infradead.org
+P:	Adrian Hunter
+M:	ext-adrian.hunter@nokia.com
+L:	linux-mtd@lists.infradead.org
+T:	git git://git.infradead.org/~dedekind/ubifs-2.6.git
+W:	http://www.linux-mtd.infradead.org/doc/ubifs.html
+S:	Maintained
+
 UCLINUX (AND M68KNOMMU)
 P:	Greg Ungerer
 M:	gerg@uclinux.org
@@ -4130,7 +4165,7 @@
 L:	linux-kernel@vger.kernel.org
 S:	Maintained
 
-UltraSPARC (sparc64):
+UltraSPARC (sparc64)
 P:	David S. Miller
 M:	davem@davemloft.net
 L:	sparclinux@vger.kernel.org
@@ -4144,6 +4179,14 @@
 W:	http://www.kernel.dk
 S:	Maintained
 
+UNSORTED BLOCK IMAGES (UBI)
+P:	Artem Bityutskiy
+M:	dedekind@infradead.org
+W:	http://www.linux-mtd.infradead.org/
+L:	linux-mtd@lists.infradead.org
+T:	git git://git.infradead.org/~dedekind/ubi-2.6.git
+S:	Maintained
+
 USB ACM DRIVER
 P:	Oliver Neukum
 M:	oliver@neukum.name
@@ -4154,13 +4197,13 @@
 P:	Pete Zaitcev
 M:	zaitcev@redhat.com
 L:	linux-kernel@vger.kernel.org
-L:      linux-usb@vger.kernel.org
+L:	linux-usb@vger.kernel.org
 S:	Supported
 
 USB CDC ETHERNET DRIVER
 P:	Greg Kroah-Hartman
 M:	greg@kroah.com
-L:      linux-usb@vger.kernel.org
+L:	linux-usb@vger.kernel.org
 S:	Maintained
 W:	http://www.kroah.com/linux-usb/
 
@@ -4187,13 +4230,13 @@
 USB EHCI DRIVER
 P:	David Brownell
 M:	dbrownell@users.sourceforge.net
-L:      linux-usb@vger.kernel.org
+L:	linux-usb@vger.kernel.org
 S:	Odd Fixes
 
 USB ET61X[12]51 DRIVER
 P:	Luca Risolia
 M:	luca.risolia@studio.unibo.it
-L:      linux-usb@vger.kernel.org
+L:	linux-usb@vger.kernel.org
 L:	video4linux-list@redhat.com
 W:	http://www.linux-projects.org
 S:	Maintained
@@ -4201,33 +4244,33 @@
 USB GADGET/PERIPHERAL SUBSYSTEM
 P:	David Brownell
 M:	dbrownell@users.sourceforge.net
-L:      linux-usb@vger.kernel.org
+L:	linux-usb@vger.kernel.org
 W:	http://www.linux-usb.org/gadget
 S:	Maintained
 
 USB HID/HIDBP DRIVERS (USB KEYBOARDS, MICE, REMOTE CONTROLS, ...)
 P:	Jiri Kosina
 M:	jkosina@suse.cz
-L:      linux-usb@vger.kernel.org
+L:	linux-usb@vger.kernel.org
 T:	git kernel.org:/pub/scm/linux/kernel/git/jikos/hid.git
 S:	Maintained
 
 USB ISP116X DRIVER
 P:	Olav Kongas
 M:	ok@artecdesign.ee
-L:      linux-usb@vger.kernel.org
+L:	linux-usb@vger.kernel.org
 S:	Maintained
 
 USB KAWASAKI LSI DRIVER
 P:	Oliver Neukum
 M:	oliver@neukum.name
-L:      linux-usb@vger.kernel.org
+L:	linux-usb@vger.kernel.org
 S:	Maintained
 
 USB MASS STORAGE DRIVER
 P:	Matthew Dharm
 M:	mdharm-usb@one-eyed-alien.net
-L:      linux-usb@vger.kernel.org
+L:	linux-usb@vger.kernel.org
 L:	usb-storage@lists.one-eyed-alien.net
 S:	Maintained
 W:	http://www.one-eyed-alien.net/~mdharm/linux-usb/
@@ -4235,26 +4278,26 @@
 USB OHCI DRIVER
 P:	David Brownell
 M:	dbrownell@users.sourceforge.net
-L:      linux-usb@vger.kernel.org
+L:	linux-usb@vger.kernel.org
 S:	Odd Fixes
 
 USB OPTION-CARD DRIVER
 P:	Matthias Urlichs
 M:	smurf@smurf.noris.de
-L:      linux-usb@vger.kernel.org
+L:	linux-usb@vger.kernel.org
 S:	Maintained
 
 USB OV511 DRIVER
 P:	Mark McClelland
 M:	mmcclell@bigfoot.com
-L:      linux-usb@vger.kernel.org
+L:	linux-usb@vger.kernel.org
 W:	http://alpha.dyndns.org/ov511/
 S:	Maintained
 
 USB PEGASUS DRIVER
 P:	Petko Manolov
 M:	petkan@users.sourceforge.net
-L:      linux-usb@vger.kernel.org
+L:	linux-usb@vger.kernel.org
 L:	netdev@vger.kernel.org
 W:	http://pegasus2.sourceforge.net/
 S:	Maintained
@@ -4262,13 +4305,13 @@
 USB PRINTER DRIVER (usblp)
 P:	Pete Zaitcev
 M:	zaitcev@redhat.com
-L:      linux-usb@vger.kernel.org
+L:	linux-usb@vger.kernel.org
 S:	Supported
 
 USB RTL8150 DRIVER
 P:	Petko Manolov
 M:	petkan@users.sourceforge.net
-L:      linux-usb@vger.kernel.org
+L:	linux-usb@vger.kernel.org
 L:	netdev@vger.kernel.org
 W:	http://pegasus2.sourceforge.net/
 S:	Maintained
@@ -4276,20 +4319,20 @@
 USB SE401 DRIVER
 P:	Jeroen Vreeken
 M:	pe1rxq@amsat.org
-L:      linux-usb@vger.kernel.org
+L:	linux-usb@vger.kernel.org
 W:	http://www.chello.nl/~j.vreeken/se401/
 S:	Maintained
 
 USB SERIAL BELKIN F5U103 DRIVER
 P:	William Greathouse
 M:	wgreathouse@smva.com
-L:      linux-usb@vger.kernel.org
+L:	linux-usb@vger.kernel.org
 S:	Maintained
 
 USB SERIAL CYPRESS M8 DRIVER
 P:	Lonnie Mendez
 M:	dignome@gmail.com
-L:      linux-usb@vger.kernel.org
+L:	linux-usb@vger.kernel.org
 S:	Maintained
 W:	http://geocities.com/i0xox0i
 W:	http://firstlight.net/cvs
@@ -4304,39 +4347,45 @@
 P:	Peter Berger and Al Borchers
 M:	pberger@brimson.com
 M:	alborchers@steinerpoint.com
-L:      linux-usb@vger.kernel.org
+L:	linux-usb@vger.kernel.org
 S:	Maintained
 
 USB SERIAL DRIVER
 P:	Greg Kroah-Hartman
 M:	gregkh@suse.de
-L:      linux-usb@vger.kernel.org
+L:	linux-usb@vger.kernel.org
 S:	Supported
 
 USB SERIAL EMPEG EMPEG-CAR MARK I/II DRIVER
 P:	Gary Brubaker
 M:	xavyer@ix.netcom.com
-L:      linux-usb@vger.kernel.org
+L:	linux-usb@vger.kernel.org
 S:	Maintained
 
 USB SERIAL KEYSPAN DRIVER
 P:	Greg Kroah-Hartman
 M:	greg@kroah.com
-L:      linux-usb@vger.kernel.org
+L:	linux-usb@vger.kernel.org
 W:	http://www.kroah.com/linux/
 S:	Maintained
 
 USB SERIAL WHITEHEAT DRIVER
 P:	Support Department
 M:	support@connecttech.com
-L:      linux-usb@vger.kernel.org
+L:	linux-usb@vger.kernel.org
 W:	http://www.connecttech.com
 S:	Supported
 
+USB SMSC95XX ETHERNET DRIVER
+P:	Steve Glendinning
+M:	steve.glendinning@smsc.com
+L:	netdev@vger.kernel.org
+S:	Supported
+
 USB SN9C1xx DRIVER
 P:	Luca Risolia
 M:	luca.risolia@studio.unibo.it
-L:      linux-usb@vger.kernel.org
+L:	linux-usb@vger.kernel.org
 L:	video4linux-list@redhat.com
 W:	http://www.linux-projects.org
 S:	Maintained
@@ -4344,7 +4393,7 @@
 USB SUBSYSTEM
 P:	Greg Kroah-Hartman
 M:	gregkh@suse.de
-L:      linux-usb@vger.kernel.org
+L:	linux-usb@vger.kernel.org
 W:	http://www.linux-usb.org
 T:	quilt kernel.org/pub/linux/kernel/people/gregkh/gregkh-2.6/
 S:	Supported
@@ -4352,7 +4401,7 @@
 USB UHCI DRIVER
 P:	Alan Stern
 M:	stern@rowland.harvard.edu
-L:      linux-usb@vger.kernel.org
+L:	linux-usb@vger.kernel.org
 S:	Maintained
 
 USB "USBNET" DRIVER FRAMEWORK
@@ -4373,7 +4422,7 @@
 USB W996[87]CF DRIVER
 P:	Luca Risolia
 M:	luca.risolia@studio.unibo.it
-L:      linux-usb@vger.kernel.org
+L:	linux-usb@vger.kernel.org
 L:	video4linux-list@redhat.com
 W:	http://www.linux-projects.org
 S:	Maintained
@@ -4387,7 +4436,7 @@
 USB ZC0301 DRIVER
 P:	Luca Risolia
 M:	luca.risolia@studio.unibo.it
-L:      linux-usb@vger.kernel.org
+L:	linux-usb@vger.kernel.org
 L:	video4linux-list@redhat.com
 W:	http://www.linux-projects.org
 S:	Maintained
@@ -4395,19 +4444,19 @@
 USB ZD1201 DRIVER
 P:	Jeroen Vreeken
 M:	pe1rxq@amsat.org
-L:      linux-usb@vger.kernel.org
+L:	linux-usb@vger.kernel.org
 W:	http://linux-lc100020.sourceforge.net
 S:	Maintained
 
 USB ZR364XX DRIVER
 P:	Antoine Jacquet
 M:	royale@zerezo.com
-L:      linux-usb@vger.kernel.org
+L:	linux-usb@vger.kernel.org
 L:	video4linux-list@redhat.com
 W:	http://royale.zerezo.com/zr364xx/
 S:	Maintained
 
-USER-MODE LINUX
+USER-MODE LINUX (UML)
 P:	Jeff Dike
 M:	jdike@addtoit.com
 L:	user-mode-linux-devel@lists.sourceforge.net
@@ -4431,7 +4480,7 @@
 T:	git://git.kernel.org/pub/scm/utils/util-linux-ng/util-linux-ng.git
 S:	Maintained
 
-VFAT/FAT/MSDOS FILESYSTEM:
+VFAT/FAT/MSDOS FILESYSTEM
 P:	OGAWA Hirofumi
 M:	hirofumi@mail.parknet.co.jp
 L:	linux-kernel@vger.kernel.org
@@ -4454,7 +4503,7 @@
 L:	netdev@vger.kernel.org
 S:	Maintained
 
-VIDEO FOR LINUX
+VIDEO FOR LINUX (V4L)
 P:	Mauro Carvalho Chehab
 M:	mchehab@infradead.org
 M:	v4l-dvb-maintainer@linuxtv.org
@@ -4471,10 +4520,11 @@
 
 VOLTAGE AND CURRENT REGULATOR FRAMEWORK
 P:	Liam Girdwood
-M:	lg@opensource.wolfsonmicro.com
+M:	lrg@slimlogic.co.uk
 P:	Mark Brown
 M:	broonie@opensource.wolfsonmicro.com
 W:	http://opensource.wolfsonmicro.com/node/15
+W:	http://www.slimlogic.co.uk/?page_id=5
 T:	git kernel.org/pub/scm/linux/kernel/git/lrg/voltage-2.6.git
 S:	Supported
 
@@ -4560,6 +4610,17 @@
 L:	linux-x25@vger.kernel.org
 S:	Maintained
 
+X86 ARCHITECTURE (32-BIT AND 64-BIT)
+P:	Thomas Gleixner
+M:	tglx@linutronix.de
+P:	Ingo Molnar
+M:	mingo@redhat.com
+P:	H. Peter Anvin
+M:	hpa@zytor.com
+L:	linux-kernel@vger.kernel.org
+T:	git://git.kernel.org/pub/scm/linux/kernel/git/x86/linux-2.6-x86.git
+S:	Maintained
+
 XEN HYPERVISOR INTERFACE
 P:	Jeremy Fitzhardinge
 M:	jeremy@xensource.com
@@ -4591,17 +4652,6 @@
 L:	linux-serial@vger.kernel.org
 S:	Maintained
 
-X86 ARCHITECTURE (32-BIT AND 64-BIT)
-P:	Thomas Gleixner
-M:	tglx@linutronix.de
-P:	Ingo Molnar
-M:	mingo@redhat.com
-P:	H. Peter Anvin
-M:	hpa@zytor.com
-L:	linux-kernel@vger.kernel.org
-T:	git://git.kernel.org/pub/scm/linux/kernel/git/x86/linux-2.6-x86.git
-S:	Maintained
-
 YAM DRIVER FOR AX.25
 P:	Jean-Paul Roubelat
 M:	jpr@f6fbb.org
diff --git a/Makefile b/Makefile
index 4ff83ea..16e3fbb 100644
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 6
 SUBLEVEL = 27
-EXTRAVERSION = -rc6
+EXTRAVERSION =
 NAME = Rotary Wombat
 
 # *DOCUMENTATION*
diff --git a/arch/Kconfig b/arch/Kconfig
index 364c6da..0267bab 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -13,6 +13,20 @@
 
 	  If unsure, say N.
 
+config OPROFILE_IBS
+	bool "OProfile AMD IBS support (EXPERIMENTAL)"
+	default n
+	depends on OPROFILE && SMP && X86
+	help
+          Instruction-Based Sampling (IBS) is a new profiling
+          technique that provides rich, precise program performance
+          information. IBS is introduced by AMD Family10h processors
+          (AMD Opteron Quad-Core processor “Barcelona”) to overcome
+          the limitations of conventional performance counter
+          sampling.
+
+	  If unsure, say N.
+
 config HAVE_OPROFILE
 	def_bool n
 
diff --git a/arch/alpha/Kconfig b/arch/alpha/Kconfig
index 1bec55d..ee35226 100644
--- a/arch/alpha/Kconfig
+++ b/arch/alpha/Kconfig
@@ -5,6 +5,7 @@
 config ALPHA
 	bool
 	default y
+	select HAVE_AOUT
 	select HAVE_IDE
 	select HAVE_OPROFILE
 	help
@@ -68,9 +69,6 @@
 	depends on SMP
 	default y
 
-config ARCH_SUPPORTS_AOUT
-	def_bool y
-
 source "init/Kconfig"
 
 
diff --git a/arch/alpha/include/asm/statfs.h b/arch/alpha/include/asm/statfs.h
index ad15830..de35cd4 100644
--- a/arch/alpha/include/asm/statfs.h
+++ b/arch/alpha/include/asm/statfs.h
@@ -1,6 +1,10 @@
 #ifndef _ALPHA_STATFS_H
 #define _ALPHA_STATFS_H
 
+/* Alpha is the only 64-bit platform with 32-bit statfs. And doesn't
+   even seem to implement statfs64 */
+#define __statfs_word __u32
+
 #include <asm-generic/statfs.h>
 
 #endif
diff --git a/arch/alpha/kernel/smp.c b/arch/alpha/kernel/smp.c
index 83df541..06b6fda 100644
--- a/arch/alpha/kernel/smp.c
+++ b/arch/alpha/kernel/smp.c
@@ -149,6 +149,9 @@
 	atomic_inc(&init_mm.mm_count);
 	current->active_mm = &init_mm;
 
+	/* inform the notifiers about the new cpu */
+	notify_cpu_starting(cpuid);
+
 	/* Must have completely accurate bogos.  */
 	local_irq_enable();
 
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 70dba16..4853f9d 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -8,6 +8,7 @@
 config ARM
 	bool
 	default y
+	select HAVE_AOUT
 	select HAVE_IDE
 	select RTC_LIB
 	select SYS_SUPPORTS_APM_EMULATION
@@ -140,15 +141,11 @@
 	bool
 	default y
 
-config ARCH_SUPPORTS_AOUT
-	def_bool y
-
 config ARCH_MAY_HAVE_PC_FDC
 	bool
 
 config ZONE_DMA
 	bool
-	default y
 
 config GENERIC_ISA_DMA
 	bool
@@ -178,6 +175,11 @@
 config OPROFILE_ARM11_CORE
 	bool
 
+config OPROFILE_ARMV7
+	def_bool y
+	depends on CPU_V7 && !SMP
+	bool
+
 endif
 
 config VECTORS_BASE
@@ -245,6 +247,7 @@
 	select TIMER_ACORN
 	select ISA
 	select NO_IOPORT
+	select ARCH_SPARSEMEM_ENABLE
 	help
 	  Support for the Cirrus Logic PS7500FE system-on-a-chip.
 
@@ -306,6 +309,7 @@
 	select PLAT_IOP
 	select PCI
 	select ARCH_SUPPORTS_MSI
+	select VMSPLIT_1G
 	help
 	  Support for Intel's IOP13XX (XScale) family of processors.
 
@@ -350,6 +354,7 @@
 	select GENERIC_GPIO
 	select GENERIC_TIME
 	select GENERIC_CLOCKEVENTS
+	select ZONE_DMA if PCI
 	help
 	  Support for Intel's IXP4XX (XScale) family of processors.
 
@@ -434,7 +439,7 @@
 	help
 	  Support for the following Marvell Orion 5x series SoCs:
 	  Orion-1 (5181), Orion-VoIP (5181L), Orion-NAS (5182),
-	  Orion-2 (5281).
+	  Orion-2 (5281), Orion-1-90 (6183).
 
 config ARCH_PNX4008
 	bool "Philips Nexperia PNX4008 Mobile"
@@ -464,6 +469,7 @@
 	select HAVE_PATA_PLATFORM
 	select ISA_DMA_API
 	select NO_IOPORT
+	select ARCH_SPARSEMEM_ENABLE
 	help
 	  On the Acorn Risc-PC, Linux can support the internal IDE disk and
 	  CD-ROM interface, serial and parallel port, and the floppy drive.
@@ -471,9 +477,7 @@
 config ARCH_SA1100
 	bool "SA1100-based"
 	select ISA
-	select ARCH_DISCONTIGMEM_ENABLE
 	select ARCH_SPARSEMEM_ENABLE
-	select ARCH_SELECT_MEMORY_MODEL
 	select ARCH_MTD_XIP
 	select GENERIC_GPIO
 	select GENERIC_TIME
@@ -497,6 +501,7 @@
 	bool "Shark"
 	select ISA
 	select ISA_DMA
+	select ZONE_DMA
 	select PCI
 	help
 	  Support for the StrongARM based Digital DNARD machine, also known
@@ -504,6 +509,8 @@
 
 config ARCH_LH7A40X
 	bool "Sharp LH7A40X"
+	select ARCH_DISCONTIGMEM_ENABLE if !LH7A40X_CONTIGMEM
+	select ARCH_SPARSEMEM_ENABLE if !LH7A40X_CONTIGMEM
 	help
 	  Say Y here for systems based on one of the Sharp LH7A40X
 	  System on a Chip processors.  These CPUs include an ARM922T
@@ -515,7 +522,9 @@
 	select GENERIC_TIME
 	select GENERIC_CLOCKEVENTS
 	select GENERIC_GPIO
+	select ARCH_REQUIRE_GPIOLIB
 	select HAVE_CLK
+	select ZONE_DMA
 	help
 	  Support for TI's DaVinci platform.
 
@@ -734,6 +743,29 @@
 
 	  If you don't know what to do here, say N.
 
+choice
+	prompt "Memory split"
+	default VMSPLIT_3G
+	help
+	  Select the desired split between kernel and user memory.
+
+	  If you are not absolutely sure what you are doing, leave this
+	  option alone!
+
+	config VMSPLIT_3G
+		bool "3G/1G user/kernel split"
+	config VMSPLIT_2G
+		bool "2G/2G user/kernel split"
+	config VMSPLIT_1G
+		bool "1G/3G user/kernel split"
+endchoice
+
+config PAGE_OFFSET
+	hex
+	default 0x40000000 if VMSPLIT_1G
+	default 0x80000000 if VMSPLIT_2G
+	default 0xC0000000
+
 config NR_CPUS
 	int "Maximum number of CPUs (2-32)"
 	range 2 32
@@ -815,20 +847,18 @@
 	default y
 	depends on FLATMEM
 
+# Discontigmem is deprecated
 config ARCH_DISCONTIGMEM_ENABLE
 	bool
-	default (ARCH_LH7A40X && !LH7A40X_CONTIGMEM)
-	help
-	  Say Y to support efficient handling of discontiguous physical memory,
-	  for architectures which are either NUMA (Non-Uniform Memory Access)
-	  or have huge holes in the physical address space for other reasons.
-	  See <file:Documentation/vm/numa> for more.
 
 config ARCH_SPARSEMEM_ENABLE
 	bool
 
+config ARCH_SPARSEMEM_DEFAULT
+	def_bool ARCH_SPARSEMEM_ENABLE
+
 config ARCH_SELECT_MEMORY_MODEL
-	bool
+	def_bool ARCH_DISCONTIGMEM_ENABLE && ARCH_SPARSEMEM_ENABLE
 
 config NODES_SHIFT
 	int
@@ -845,7 +875,7 @@
 		   ARCH_LUBBOCK || MACH_MAINSTONE || ARCH_NETWINDER || \
 		   ARCH_OMAP || ARCH_P720T || ARCH_PXA_IDP || \
 		   ARCH_SA1100 || ARCH_SHARK || ARCH_VERSATILE || \
-		   ARCH_AT91 || MACH_TRIZEPS4 || ARCH_DAVINCI || \
+		   ARCH_AT91 || ARCH_DAVINCI || \
 		   ARCH_KS8695 || MACH_RD88F5182
 	help
 	  If you say Y here, the LEDs on your machine will be used
@@ -1005,9 +1035,9 @@
 
 endmenu
 
-if (ARCH_SA1100 || ARCH_INTEGRATOR || ARCH_OMAP || ARCH_IMX || ARCH_PXA)
+menu "CPU Power Management"
 
-menu "CPU Frequency scaling"
+if (ARCH_SA1100 || ARCH_INTEGRATOR || ARCH_OMAP || ARCH_IMX || ARCH_PXA)
 
 source "drivers/cpufreq/Kconfig"
 
@@ -1047,10 +1077,12 @@
 	default y
 	select CPU_FREQ_DEFAULT_GOV_USERSPACE
 
-endmenu
-
 endif
 
+source "drivers/cpuidle/Kconfig"
+
+endmenu
+
 menu "Floating point emulation"
 
 comment "At least one emulation must be selected"
@@ -1202,6 +1234,8 @@
 
 source "drivers/hwmon/Kconfig"
 
+source "drivers/thermal/Kconfig"
+
 source "drivers/watchdog/Kconfig"
 
 source "drivers/ssb/Kconfig"
@@ -1222,6 +1256,10 @@
 
 source "drivers/mmc/Kconfig"
 
+source "drivers/memstick/Kconfig"
+
+source "drivers/accessibility/Kconfig"
+
 source "drivers/leds/Kconfig"
 
 source "drivers/rtc/Kconfig"
@@ -1230,6 +1268,8 @@
 
 source "drivers/dca/Kconfig"
 
+source "drivers/auxdisplay/Kconfig"
+
 source "drivers/regulator/Kconfig"
 
 source "drivers/uio/Kconfig"
diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index 703a44f..e2274bc 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -47,7 +47,7 @@
 # Note that GCC does not numerically define an architecture version
 # macro, but instead defines a whole series of macros which makes
 # testing for a specific architecture or later rather impossible.
-arch-$(CONFIG_CPU_32v7)		:=-D__LINUX_ARM_ARCH__=7 $(call cc-option,-march=armv7a,-march=armv5t -Wa$(comma)-march=armv7a)
+arch-$(CONFIG_CPU_32v7)		:=-D__LINUX_ARM_ARCH__=7 $(call cc-option,-march=armv7-a,-march=armv5t -Wa$(comma)-march=armv7-a)
 arch-$(CONFIG_CPU_32v6)		:=-D__LINUX_ARM_ARCH__=6 $(call cc-option,-march=armv6,-march=armv5t -Wa$(comma)-march=armv6)
 # Only override the compiler option if ARMv6. The ARMv6K extensions are
 # always available in ARMv7
diff --git a/arch/arm/boot/compressed/Makefile b/arch/arm/boot/compressed/Makefile
index 94462a0..7a03f20 100644
--- a/arch/arm/boot/compressed/Makefile
+++ b/arch/arm/boot/compressed/Makefile
@@ -76,7 +76,7 @@
 endif
 
 EXTRA_CFLAGS  := -fpic -fno-builtin
-EXTRA_AFLAGS  :=
+EXTRA_AFLAGS  := -Wa,-march=all
 
 # Supply ZRELADDR, INITRD_PHYS and PARAMS_PHYS to the decompressor via
 # linker symbols.  We only define initrd_phys and params_phys if the
diff --git a/arch/arm/boot/compressed/head.S b/arch/arm/boot/compressed/head.S
index d42f89b..84a1e04 100644
--- a/arch/arm/boot/compressed/head.S
+++ b/arch/arm/boot/compressed/head.S
@@ -421,6 +421,7 @@
 		add	r1, r1, #1048576
 		str	r1, [r0]
 		mov	pc, lr
+ENDPROC(__setup_mmu)
 
 __armv4_mmu_cache_on:
 		mov	r12, lr
@@ -801,7 +802,7 @@
 		add	r2, r2, #4		@ add 4 (line length offset)
 		ldr	r4, =0x3ff
 		ands	r4, r4, r1, lsr #3	@ find maximum number on the way size
-		.word	0xe16f5f14		@ clz r5, r4 - find bit position of way size increment
+		clz	r5, r4			@ find bit position of way size increment
 		ldr	r7, =0x7fff
 		ands	r7, r7, r1, lsr #13	@ extract max number of the index size
 loop2:
diff --git a/arch/arm/common/Kconfig b/arch/arm/common/Kconfig
index 3e07346..2e32acc 100644
--- a/arch/arm/common/Kconfig
+++ b/arch/arm/common/Kconfig
@@ -12,7 +12,8 @@
 
 config SA1111
 	bool
-	select DMABOUNCE
+	select DMABOUNCE if !ARCH_PXA
+	select ZONE_DMA if !ARCH_PXA
 
 config DMABOUNCE
 	bool
diff --git a/arch/arm/common/dmabounce.c b/arch/arm/common/dmabounce.c
index aecc6c3..f030f07 100644
--- a/arch/arm/common/dmabounce.c
+++ b/arch/arm/common/dmabounce.c
@@ -154,9 +154,7 @@
 #endif
 
 	write_lock_irqsave(&device_info->lock, flags);
-
 	list_add(&buf->node, &device_info->safe_buffers);
-
 	write_unlock_irqrestore(&device_info->lock, flags);
 
 	return buf;
@@ -205,8 +203,22 @@
 
 /* ************************************************** */
 
-static inline dma_addr_t
-map_single(struct device *dev, void *ptr, size_t size,
+static struct safe_buffer *find_safe_buffer_dev(struct device *dev,
+		dma_addr_t dma_addr, const char *where)
+{
+	if (!dev || !dev->archdata.dmabounce)
+		return NULL;
+	if (dma_mapping_error(dev, dma_addr)) {
+		if (dev)
+			dev_err(dev, "Trying to %s invalid mapping\n", where);
+		else
+			pr_err("unknown device: Trying to %s invalid mapping\n", where);
+		return NULL;
+	}
+	return find_safe_buffer(dev->archdata.dmabounce, dma_addr);
+}
+
+static inline dma_addr_t map_single(struct device *dev, void *ptr, size_t size,
 		enum dma_data_direction dir)
 {
 	struct dmabounce_device_info *device_info = dev->archdata.dmabounce;
@@ -270,33 +282,21 @@
 	return dma_addr;
 }
 
-static inline void
-unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size,
-		enum dma_data_direction dir)
+static inline void unmap_single(struct device *dev, dma_addr_t dma_addr,
+		size_t size, enum dma_data_direction dir)
 {
-	struct dmabounce_device_info *device_info = dev->archdata.dmabounce;
-	struct safe_buffer *buf = NULL;
-
-	/*
-	 * Trying to unmap an invalid mapping
-	 */
-	if (dma_mapping_error(dev, dma_addr)) {
-		dev_err(dev, "Trying to unmap invalid mapping\n");
-		return;
-	}
-
-	if (device_info)
-		buf = find_safe_buffer(device_info, dma_addr);
+	struct safe_buffer *buf = find_safe_buffer_dev(dev, dma_addr, "unmap");
 
 	if (buf) {
 		BUG_ON(buf->size != size);
+		BUG_ON(buf->direction != dir);
 
 		dev_dbg(dev,
 			"%s: unsafe buffer %p (dma=%#x) mapped to %p (dma=%#x)\n",
 			__func__, buf->ptr, virt_to_dma(dev, buf->ptr),
 			buf->safe, buf->safe_dma_addr);
 
-		DO_STATS ( device_info->bounce_count++ );
+		DO_STATS(dev->archdata.dmabounce->bounce_count++);
 
 		if (dir == DMA_FROM_DEVICE || dir == DMA_BIDIRECTIONAL) {
 			void *ptr = buf->ptr;
@@ -317,74 +317,7 @@
 			dmac_clean_range(ptr, ptr + size);
 			outer_clean_range(__pa(ptr), __pa(ptr) + size);
 		}
-		free_safe_buffer(device_info, buf);
-	}
-}
-
-static int sync_single(struct device *dev, dma_addr_t dma_addr, size_t size,
-			enum dma_data_direction dir)
-{
-	struct dmabounce_device_info *device_info = dev->archdata.dmabounce;
-	struct safe_buffer *buf = NULL;
-
-	if (device_info)
-		buf = find_safe_buffer(device_info, dma_addr);
-
-	if (buf) {
-		/*
-		 * Both of these checks from original code need to be
-		 * commented out b/c some drivers rely on the following:
-		 *
-		 * 1) Drivers may map a large chunk of memory into DMA space
-		 *    but only sync a small portion of it. Good example is
-		 *    allocating a large buffer, mapping it, and then
-		 *    breaking it up into small descriptors. No point
-		 *    in syncing the whole buffer if you only have to
-		 *    touch one descriptor.
-		 *
-		 * 2) Buffers that are mapped as DMA_BIDIRECTIONAL are
-		 *    usually only synced in one dir at a time.
-		 *
-		 * See drivers/net/eepro100.c for examples of both cases.
-		 *
-		 * -ds
-		 *
-		 * BUG_ON(buf->size != size);
-		 * BUG_ON(buf->direction != dir);
-		 */
-
-		dev_dbg(dev,
-			"%s: unsafe buffer %p (dma=%#x) mapped to %p (dma=%#x)\n",
-			__func__, buf->ptr, virt_to_dma(dev, buf->ptr),
-			buf->safe, buf->safe_dma_addr);
-
-		DO_STATS ( device_info->bounce_count++ );
-
-		switch (dir) {
-		case DMA_FROM_DEVICE:
-			dev_dbg(dev,
-				"%s: copy back safe %p to unsafe %p size %d\n",
-				__func__, buf->safe, buf->ptr, size);
-			memcpy(buf->ptr, buf->safe, size);
-			break;
-		case DMA_TO_DEVICE:
-			dev_dbg(dev,
-				"%s: copy out unsafe %p to safe %p, size %d\n",
-				__func__,buf->ptr, buf->safe, size);
-			memcpy(buf->safe, buf->ptr, size);
-			break;
-		case DMA_BIDIRECTIONAL:
-			BUG();	/* is this allowed?  what does it mean? */
-		default:
-			BUG();
-		}
-		/*
-		 * No need to sync the safe buffer - it was allocated
-		 * via the coherent allocators.
-		 */
-		return 0;
-	} else {
-		return 1;
+		free_safe_buffer(dev->archdata.dmabounce, buf);
 	}
 }
 
@@ -396,21 +329,29 @@
  * substitute the safe buffer for the unsafe one.
  * (basically move the buffer from an unsafe area to a safe one)
  */
-dma_addr_t
-dma_map_single(struct device *dev, void *ptr, size_t size,
+dma_addr_t dma_map_single(struct device *dev, void *ptr, size_t size,
 		enum dma_data_direction dir)
 {
-	dma_addr_t dma_addr;
-
 	dev_dbg(dev, "%s(ptr=%p,size=%d,dir=%x)\n",
 		__func__, ptr, size, dir);
 
-	BUG_ON(dir == DMA_NONE);
+	BUG_ON(!valid_dma_direction(dir));
 
-	dma_addr = map_single(dev, ptr, size, dir);
-
-	return dma_addr;
+	return map_single(dev, ptr, size, dir);
 }
+EXPORT_SYMBOL(dma_map_single);
+
+dma_addr_t dma_map_page(struct device *dev, struct page *page,
+		unsigned long offset, size_t size, enum dma_data_direction dir)
+{
+	dev_dbg(dev, "%s(page=%p,off=%#lx,size=%zx,dir=%x)\n",
+		__func__, page, offset, size, dir);
+
+	BUG_ON(!valid_dma_direction(dir));
+
+	return map_single(dev, page_address(page) + offset, size, dir);
+}
+EXPORT_SYMBOL(dma_map_page);
 
 /*
  * see if a mapped address was really a "safe" buffer and if so, copy
@@ -419,126 +360,76 @@
  * should be)
  */
 
-void
-dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size,
-			enum dma_data_direction dir)
+void dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size,
+		enum dma_data_direction dir)
 {
 	dev_dbg(dev, "%s(ptr=%p,size=%d,dir=%x)\n",
 		__func__, (void *) dma_addr, size, dir);
 
-	BUG_ON(dir == DMA_NONE);
-
 	unmap_single(dev, dma_addr, size, dir);
 }
+EXPORT_SYMBOL(dma_unmap_single);
 
-int
-dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
-		enum dma_data_direction dir)
+int dmabounce_sync_for_cpu(struct device *dev, dma_addr_t addr,
+		unsigned long off, size_t sz, enum dma_data_direction dir)
 {
-	int i;
+	struct safe_buffer *buf;
 
-	dev_dbg(dev, "%s(sg=%p,nents=%d,dir=%x)\n",
-		__func__, sg, nents, dir);
+	dev_dbg(dev, "%s(dma=%#x,off=%#lx,sz=%zx,dir=%x)\n",
+		__func__, addr, off, sz, dir);
 
-	BUG_ON(dir == DMA_NONE);
+	buf = find_safe_buffer_dev(dev, addr, __func__);
+	if (!buf)
+		return 1;
 
-	for (i = 0; i < nents; i++, sg++) {
-		struct page *page = sg_page(sg);
-		unsigned int offset = sg->offset;
-		unsigned int length = sg->length;
-		void *ptr = page_address(page) + offset;
+	BUG_ON(buf->direction != dir);
 
-		sg->dma_address =
-			map_single(dev, ptr, length, dir);
+	dev_dbg(dev, "%s: unsafe buffer %p (dma=%#x) mapped to %p (dma=%#x)\n",
+		__func__, buf->ptr, virt_to_dma(dev, buf->ptr),
+		buf->safe, buf->safe_dma_addr);
+
+	DO_STATS(dev->archdata.dmabounce->bounce_count++);
+
+	if (dir == DMA_FROM_DEVICE || dir == DMA_BIDIRECTIONAL) {
+		dev_dbg(dev, "%s: copy back safe %p to unsafe %p size %d\n",
+			__func__, buf->safe + off, buf->ptr + off, sz);
+		memcpy(buf->ptr + off, buf->safe + off, sz);
 	}
-
-	return nents;
+	return 0;
 }
+EXPORT_SYMBOL(dmabounce_sync_for_cpu);
 
-void
-dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nents,
-		enum dma_data_direction dir)
+int dmabounce_sync_for_device(struct device *dev, dma_addr_t addr,
+		unsigned long off, size_t sz, enum dma_data_direction dir)
 {
-	int i;
+	struct safe_buffer *buf;
 
-	dev_dbg(dev, "%s(sg=%p,nents=%d,dir=%x)\n",
-		__func__, sg, nents, dir);
+	dev_dbg(dev, "%s(dma=%#x,off=%#lx,sz=%zx,dir=%x)\n",
+		__func__, addr, off, sz, dir);
 
-	BUG_ON(dir == DMA_NONE);
+	buf = find_safe_buffer_dev(dev, addr, __func__);
+	if (!buf)
+		return 1;
 
-	for (i = 0; i < nents; i++, sg++) {
-		dma_addr_t dma_addr = sg->dma_address;
-		unsigned int length = sg->length;
+	BUG_ON(buf->direction != dir);
 
-		unmap_single(dev, dma_addr, length, dir);
+	dev_dbg(dev, "%s: unsafe buffer %p (dma=%#x) mapped to %p (dma=%#x)\n",
+		__func__, buf->ptr, virt_to_dma(dev, buf->ptr),
+		buf->safe, buf->safe_dma_addr);
+
+	DO_STATS(dev->archdata.dmabounce->bounce_count++);
+
+	if (dir == DMA_TO_DEVICE || dir == DMA_BIDIRECTIONAL) {
+		dev_dbg(dev, "%s: copy out unsafe %p to safe %p, size %d\n",
+			__func__,buf->ptr + off, buf->safe + off, sz);
+		memcpy(buf->safe + off, buf->ptr + off, sz);
 	}
+	return 0;
 }
+EXPORT_SYMBOL(dmabounce_sync_for_device);
 
-void dma_sync_single_range_for_cpu(struct device *dev, dma_addr_t dma_addr,
-				   unsigned long offset, size_t size,
-				   enum dma_data_direction dir)
-{
-	dev_dbg(dev, "%s(dma=%#x,off=%#lx,size=%zx,dir=%x)\n",
-		__func__, dma_addr, offset, size, dir);
-
-	if (sync_single(dev, dma_addr, offset + size, dir))
-		dma_cache_maint(dma_to_virt(dev, dma_addr) + offset, size, dir);
-}
-EXPORT_SYMBOL(dma_sync_single_range_for_cpu);
-
-void dma_sync_single_range_for_device(struct device *dev, dma_addr_t dma_addr,
-				      unsigned long offset, size_t size,
-				      enum dma_data_direction dir)
-{
-	dev_dbg(dev, "%s(dma=%#x,off=%#lx,size=%zx,dir=%x)\n",
-		__func__, dma_addr, offset, size, dir);
-
-	if (sync_single(dev, dma_addr, offset + size, dir))
-		dma_cache_maint(dma_to_virt(dev, dma_addr) + offset, size, dir);
-}
-EXPORT_SYMBOL(dma_sync_single_range_for_device);
-
-void
-dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nents,
-			enum dma_data_direction dir)
-{
-	int i;
-
-	dev_dbg(dev, "%s(sg=%p,nents=%d,dir=%x)\n",
-		__func__, sg, nents, dir);
-
-	BUG_ON(dir == DMA_NONE);
-
-	for (i = 0; i < nents; i++, sg++) {
-		dma_addr_t dma_addr = sg->dma_address;
-		unsigned int length = sg->length;
-
-		sync_single(dev, dma_addr, length, dir);
-	}
-}
-
-void
-dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, int nents,
-			enum dma_data_direction dir)
-{
-	int i;
-
-	dev_dbg(dev, "%s(sg=%p,nents=%d,dir=%x)\n",
-		__func__, sg, nents, dir);
-
-	BUG_ON(dir == DMA_NONE);
-
-	for (i = 0; i < nents; i++, sg++) {
-		dma_addr_t dma_addr = sg->dma_address;
-		unsigned int length = sg->length;
-
-		sync_single(dev, dma_addr, length, dir);
-	}
-}
-
-static int
-dmabounce_init_pool(struct dmabounce_pool *pool, struct device *dev, const char *name,
-		    unsigned long size)
+static int dmabounce_init_pool(struct dmabounce_pool *pool, struct device *dev,
+		const char *name, unsigned long size)
 {
 	pool->size = size;
 	DO_STATS(pool->allocs = 0);
@@ -549,9 +440,8 @@
 	return pool->pool ? 0 : -ENOMEM;
 }
 
-int
-dmabounce_register_dev(struct device *dev, unsigned long small_buffer_size,
-			unsigned long large_buffer_size)
+int dmabounce_register_dev(struct device *dev, unsigned long small_buffer_size,
+		unsigned long large_buffer_size)
 {
 	struct dmabounce_device_info *device_info;
 	int ret;
@@ -607,9 +497,9 @@
 	kfree(device_info);
 	return ret;
 }
+EXPORT_SYMBOL(dmabounce_register_dev);
 
-void
-dmabounce_unregister_dev(struct device *dev)
+void dmabounce_unregister_dev(struct device *dev)
 {
 	struct dmabounce_device_info *device_info = dev->archdata.dmabounce;
 
@@ -642,15 +532,6 @@
 
 	dev_info(dev, "dmabounce: device unregistered\n");
 }
-
-
-EXPORT_SYMBOL(dma_map_single);
-EXPORT_SYMBOL(dma_unmap_single);
-EXPORT_SYMBOL(dma_map_sg);
-EXPORT_SYMBOL(dma_unmap_sg);
-EXPORT_SYMBOL(dma_sync_sg_for_cpu);
-EXPORT_SYMBOL(dma_sync_sg_for_device);
-EXPORT_SYMBOL(dmabounce_register_dev);
 EXPORT_SYMBOL(dmabounce_unregister_dev);
 
 MODULE_AUTHOR("Christopher Hoover <ch@hpl.hp.com>, Deepak Saxena <dsaxena@plexity.net>");
diff --git a/arch/arm/common/gic.c b/arch/arm/common/gic.c
index 0c89bd3..7fc9860 100644
--- a/arch/arm/common/gic.c
+++ b/arch/arm/common/gic.c
@@ -27,9 +27,9 @@
 #include <linux/list.h>
 #include <linux/smp.h>
 #include <linux/cpumask.h>
+#include <linux/io.h>
 
 #include <asm/irq.h>
-#include <asm/io.h>
 #include <asm/mach/irq.h>
 #include <asm/hardware/gic.h>
 
diff --git a/arch/arm/common/it8152.c b/arch/arm/common/it8152.c
index 5fe9588..2793447 100644
--- a/arch/arm/common/it8152.c
+++ b/arch/arm/common/it8152.c
@@ -66,14 +66,6 @@
        }
 }
 
-static inline void it8152_irq(int irq)
-{
-	struct irq_desc *desc;
-
-	desc = irq_desc + irq;
-	desc_handle_irq(irq, desc);
-}
-
 static struct irq_chip it8152_irq_chip = {
 	.name		= "it8152",
 	.ack		= it8152_mask_irq,
@@ -128,21 +120,21 @@
 	       bits_pd &= ((1 << IT8152_PD_IRQ_COUNT) - 1);
 	       while (bits_pd) {
 		       i = __ffs(bits_pd);
-		       it8152_irq(IT8152_PD_IRQ(i));
+		       generic_handle_irq(IT8152_PD_IRQ(i));
 		       bits_pd &= ~(1 << i);
 	       }
 
 	       bits_lp &= ((1 << IT8152_LP_IRQ_COUNT) - 1);
 	       while (bits_lp) {
 		       i = __ffs(bits_lp);
-		       it8152_irq(IT8152_LP_IRQ(i));
+		       generic_handle_irq(IT8152_LP_IRQ(i));
 		       bits_lp &= ~(1 << i);
 	       }
 
 	       bits_ld &= ((1 << IT8152_LD_IRQ_COUNT) - 1);
 	       while (bits_ld) {
 		       i = __ffs(bits_ld);
-		       it8152_irq(IT8152_LD_IRQ(i));
+		       generic_handle_irq(IT8152_LD_IRQ(i));
 		       bits_ld &= ~(1 << i);
 	       }
        }
diff --git a/arch/arm/common/locomo.c b/arch/arm/common/locomo.c
index 283051e..7c6b4b9 100644
--- a/arch/arm/common/locomo.c
+++ b/arch/arm/common/locomo.c
@@ -24,9 +24,9 @@
 #include <linux/platform_device.h>
 #include <linux/slab.h>
 #include <linux/spinlock.h>
+#include <linux/io.h>
 
 #include <mach/hardware.h>
-#include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/mach/irq.h>
 
@@ -169,7 +169,6 @@
 static void locomo_handler(unsigned int irq, struct irq_desc *desc)
 {
 	int req, i;
-	struct irq_desc *d;
 	void __iomem *mapbase = get_irq_chip_data(irq);
 
 	/* Acknowledge the parent IRQ */
@@ -181,10 +180,9 @@
 	if (req) {
 		/* generate the next interrupt(s) */
 		irq = LOCOMO_IRQ_START;
-		d = irq_desc + irq;
-		for (i = 0; i <= 3; i++, d++, irq++) {
+		for (i = 0; i <= 3; i++, irq++) {
 			if (req & (0x0100 << i)) {
-				desc_handle_irq(irq, d);
+				generic_handle_irq(irq);
 			}
 
 		}
@@ -222,12 +220,10 @@
 
 static void locomo_key_handler(unsigned int irq, struct irq_desc *desc)
 {
-	struct irq_desc *d;
 	void __iomem *mapbase = get_irq_chip_data(irq);
 
 	if (locomo_readl(mapbase + LOCOMO_KEYBOARD + LOCOMO_KIC) & 0x0001) {
-		d = irq_desc + LOCOMO_IRQ_KEY_START;
-		desc_handle_irq(LOCOMO_IRQ_KEY_START, d);
+		generic_handle_irq(LOCOMO_IRQ_KEY_START);
 	}
 }
 
@@ -268,7 +264,6 @@
 static void locomo_gpio_handler(unsigned int irq, struct irq_desc *desc)
 {
 	int req, i;
-	struct irq_desc *d;
 	void __iomem *mapbase = get_irq_chip_data(irq);
 
 	req = 	locomo_readl(mapbase + LOCOMO_GIR) &
@@ -277,10 +272,9 @@
 
 	if (req) {
 		irq = LOCOMO_IRQ_GPIO_START;
-		d = irq_desc + LOCOMO_IRQ_GPIO_START;
-		for (i = 0; i <= 15; i++, irq++, d++) {
+		for (i = 0; i <= 15; i++, irq++) {
 			if (req & (0x0001 << i)) {
-				desc_handle_irq(irq, d);
+				generic_handle_irq(irq);
 			}
 		}
 	}
@@ -361,12 +355,10 @@
 
 static void locomo_lt_handler(unsigned int irq, struct irq_desc *desc)
 {
-	struct irq_desc *d;
 	void __iomem *mapbase = get_irq_chip_data(irq);
 
 	if (locomo_readl(mapbase + LOCOMO_LTINT) & 0x0001) {
-		d = irq_desc + LOCOMO_IRQ_LT_START;
-		desc_handle_irq(LOCOMO_IRQ_LT_START, d);
+		generic_handle_irq(LOCOMO_IRQ_LT_START);
 	}
 }
 
@@ -407,17 +399,15 @@
 static void locomo_spi_handler(unsigned int irq, struct irq_desc *desc)
 {
 	int req, i;
-	struct irq_desc *d;
 	void __iomem *mapbase = get_irq_chip_data(irq);
 
 	req = locomo_readl(mapbase + LOCOMO_SPI + LOCOMO_SPIIR) & 0x000F;
 	if (req) {
 		irq = LOCOMO_IRQ_SPI_START;
-		d = irq_desc + irq;
 
-		for (i = 0; i <= 3; i++, irq++, d++) {
+		for (i = 0; i <= 3; i++, irq++) {
 			if (req & (0x0001 << i)) {
-				desc_handle_irq(irq, d);
+				generic_handle_irq(irq);
 			}
 		}
 	}
diff --git a/arch/arm/common/sa1111.c b/arch/arm/common/sa1111.c
index ec8a547..fb86f24 100644
--- a/arch/arm/common/sa1111.c
+++ b/arch/arm/common/sa1111.c
@@ -25,10 +25,10 @@
 #include <linux/spinlock.h>
 #include <linux/dma-mapping.h>
 #include <linux/clk.h>
+#include <linux/io.h>
 
 #include <mach/hardware.h>
 #include <asm/mach-types.h>
-#include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/mach/irq.h>
 #include <asm/sizes.h>
diff --git a/arch/arm/common/scoop.c b/arch/arm/common/scoop.c
index ae39553..697c649 100644
--- a/arch/arm/common/scoop.c
+++ b/arch/arm/common/scoop.c
@@ -15,7 +15,7 @@
 #include <linux/string.h>
 #include <linux/slab.h>
 #include <linux/platform_device.h>
-#include <asm/io.h>
+#include <linux/io.h>
 #include <asm/gpio.h>
 #include <asm/hardware/scoop.h>
 
diff --git a/arch/arm/common/sharpsl_param.c b/arch/arm/common/sharpsl_param.c
index aad4d94..d56c932 100644
--- a/arch/arm/common/sharpsl_param.c
+++ b/arch/arm/common/sharpsl_param.c
@@ -12,6 +12,7 @@
  */
 
 #include <linux/kernel.h>
+#include <linux/module.h>
 #include <linux/string.h>
 #include <asm/mach/sharpsl_param.h>
 
@@ -36,6 +37,7 @@
 #define PHAD_MAGIC	MAGIC_CHG('P','H','A','D')
 
 struct sharpsl_param_info sharpsl_param;
+EXPORT_SYMBOL(sharpsl_param);
 
 void sharpsl_save_param(void)
 {
diff --git a/arch/arm/common/time-acorn.c b/arch/arm/common/time-acorn.c
index df0983a..deeed56 100644
--- a/arch/arm/common/time-acorn.c
+++ b/arch/arm/common/time-acorn.c
@@ -17,9 +17,9 @@
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/irq.h>
+#include <linux/io.h>
 
 #include <mach/hardware.h>
-#include <asm/io.h>
 #include <asm/hardware/ioc.h>
 
 #include <asm/mach/time.h>
diff --git a/arch/arm/common/uengine.c b/arch/arm/common/uengine.c
index 7ecd3c0..b520e56 100644
--- a/arch/arm/common/uengine.c
+++ b/arch/arm/common/uengine.c
@@ -16,9 +16,9 @@
 #include <linux/slab.h>
 #include <linux/module.h>
 #include <linux/string.h>
+#include <linux/io.h>
 #include <mach/hardware.h>
 #include <asm/hardware/uengine.h>
-#include <asm/io.h>
 
 #if defined(CONFIG_ARCH_IXP2000)
 #define IXP_UENGINE_CSR_VIRT_BASE	IXP2000_UENGINE_CSR_VIRT_BASE
diff --git a/arch/arm/common/via82c505.c b/arch/arm/common/via82c505.c
index 79a8206..8421d39 100644
--- a/arch/arm/common/via82c505.c
+++ b/arch/arm/common/via82c505.c
@@ -4,8 +4,8 @@
 #include <linux/mm.h>
 #include <linux/init.h>
 #include <linux/ioport.h>
+#include <linux/io.h>
 
-#include <asm/io.h>
 #include <asm/system.h>
 
 #include <asm/mach/pci.h>
diff --git a/arch/arm/common/vic.c b/arch/arm/common/vic.c
index c026fa2..f1e4b8f 100644
--- a/arch/arm/common/vic.c
+++ b/arch/arm/common/vic.c
@@ -20,8 +20,8 @@
  */
 #include <linux/init.h>
 #include <linux/list.h>
+#include <linux/io.h>
 
-#include <asm/io.h>
 #include <asm/mach/irq.h>
 #include <asm/hardware/vic.h>
 
diff --git a/arch/arm/configs/afeb9260_defconfig b/arch/arm/configs/afeb9260_defconfig
new file mode 100644
index 0000000..ce90958
--- /dev/null
+++ b/arch/arm/configs/afeb9260_defconfig
@@ -0,0 +1,1259 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.27-rc2
+# Tue Aug 12 22:30:16 2008
+#
+CONFIG_ARM=y
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+CONFIG_GENERIC_GPIO=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_MMU=y
+# CONFIG_NO_IOPORT is not set
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_ARCH_SUPPORTS_AOUT=y
+CONFIG_ZONE_DMA=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
+CONFIG_VECTORS_BASE=0xffff0000
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=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_LOG_BUF_SHIFT=14
+# CONFIG_CGROUPS is not set
+# CONFIG_GROUP_SCHED is not set
+CONFIG_SYSFS_DEPRECATED=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+# CONFIG_RELAY is not set
+CONFIG_NAMESPACES=y
+# CONFIG_UTS_NS is not set
+# CONFIG_IPC_NS is not set
+# CONFIG_USER_NS is not set
+# CONFIG_PID_NS is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+# CONFIG_EMBEDDED is not set
+CONFIG_UID16=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_SYSCTL_SYSCALL_CHECK=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_COMPAT_BRK=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_ANON_INODES=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
+# CONFIG_PROFILING is not set
+# CONFIG_MARKERS is not set
+CONFIG_HAVE_OPROFILE=y
+# CONFIG_KPROBES is not set
+# CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS is not set
+# CONFIG_HAVE_IOREMAP_PROT is not set
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+# CONFIG_HAVE_ARCH_TRACEHOOK is not set
+# CONFIG_HAVE_DMA_ATTRS is not set
+# CONFIG_USE_GENERIC_SMP_HELPERS is not set
+CONFIG_HAVE_CLK=y
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_HAVE_GENERIC_DMA_COHERENT=y
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+# CONFIG_MODULE_FORCE_LOAD is not set
+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=y
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_BLK_DEV_INTEGRITY is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
+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_CLASSIC_RCU=y
+
+#
+# System Type
+#
+# CONFIG_ARCH_AAEC2000 is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_REALVIEW is not set
+# CONFIG_ARCH_VERSATILE is not set
+CONFIG_ARCH_AT91=y
+# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_EP93XX is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_NETX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_IOP13XX is not set
+# CONFIG_ARCH_IOP32X is not set
+# CONFIG_ARCH_IOP33X is not set
+# CONFIG_ARCH_IXP23XX is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_KIRKWOOD is not set
+# CONFIG_ARCH_KS8695 is not set
+# CONFIG_ARCH_NS9XXX is not set
+# CONFIG_ARCH_LOKI is not set
+# CONFIG_ARCH_MV78XX0 is not set
+# CONFIG_ARCH_MXC is not set
+# CONFIG_ARCH_ORION5X is not set
+# CONFIG_ARCH_PNX4008 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_DAVINCI is not set
+# CONFIG_ARCH_OMAP is not set
+# CONFIG_ARCH_MSM7X00A is not set
+
+#
+# Boot options
+#
+
+#
+# Power management
+#
+
+#
+# Atmel AT91 System-on-Chip
+#
+# CONFIG_ARCH_AT91RM9200 is not set
+CONFIG_ARCH_AT91SAM9260=y
+# CONFIG_ARCH_AT91SAM9261 is not set
+# CONFIG_ARCH_AT91SAM9263 is not set
+# CONFIG_ARCH_AT91SAM9RL is not set
+# CONFIG_ARCH_AT91SAM9G20 is not set
+# CONFIG_ARCH_AT91CAP9 is not set
+# CONFIG_ARCH_AT91X40 is not set
+CONFIG_AT91_PMC_UNIT=y
+
+#
+# AT91SAM9260 Variants
+#
+# CONFIG_ARCH_AT91SAM9260_SAM9XE is not set
+
+#
+# AT91SAM9260 / AT91SAM9XE Board Type
+#
+# CONFIG_MACH_AT91SAM9260EK is not set
+# CONFIG_MACH_CAM60 is not set
+# CONFIG_MACH_SAM9_L9260 is not set
+CONFIG_MACH_AFEB9260=y
+# CONFIG_MACH_USB_A9260 is not set
+# CONFIG_MACH_QIL_A9260 is not set
+
+#
+# AT91 Board Options
+#
+
+#
+# AT91 Feature Selections
+#
+CONFIG_AT91_PROGRAMMABLE_CLOCKS=y
+CONFIG_AT91_TIMER_HZ=100
+CONFIG_AT91_EARLY_DBGU=y
+# CONFIG_AT91_EARLY_USART0 is not set
+# CONFIG_AT91_EARLY_USART1 is not set
+# CONFIG_AT91_EARLY_USART2 is not set
+# CONFIG_AT91_EARLY_USART3 is not set
+# CONFIG_AT91_EARLY_USART4 is not set
+# CONFIG_AT91_EARLY_USART5 is not set
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_ARM926T=y
+CONFIG_CPU_32v5=y
+CONFIG_CPU_ABRT_EV5TJ=y
+CONFIG_CPU_PABRT_NOIFAR=y
+CONFIG_CPU_CACHE_VIVT=y
+CONFIG_CPU_COPY_V4WB=y
+CONFIG_CPU_TLB_V4WBI=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
+
+#
+# Processor Features
+#
+CONFIG_ARM_THUMB=y
+# CONFIG_CPU_ICACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_WRITETHROUGH is not set
+# CONFIG_CPU_CACHE_ROUND_ROBIN is not set
+# CONFIG_OUTER_CACHE is not set
+
+#
+# Bus support
+#
+# CONFIG_PCI_SYSCALL is not set
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+# CONFIG_TICK_ONESHOT is not set
+# CONFIG_NO_HZ is not set
+# CONFIG_HIGH_RES_TIMERS is not set
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+CONFIG_PREEMPT=y
+CONFIG_HZ=100
+CONFIG_AEABI=y
+CONFIG_OABI_COMPAT=y
+# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
+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_SPARSEMEM_VMEMMAP_ENABLE is not set
+CONFIG_PAGEFLAGS_EXTENDED=y
+CONFIG_SPLIT_PTLOCK_CPUS=4096
+# CONFIG_RESOURCES_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=1
+CONFIG_BOUNCE=y
+CONFIG_VIRT_TO_BUS=y
+# CONFIG_LEDS is not set
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="mem=64M console=ttyS0,115200 initrd=0x21100000,3145728 root=/dev/ram0 rw"
+# CONFIG_XIP_KERNEL is not set
+# CONFIG_KEXEC is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_FASTFPE is not set
+# CONFIG_VFP is not set
+
+#
+# Userspace binary formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Power management options
+#
+# CONFIG_PM is not set
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+# CONFIG_IP_PNP_DHCP is not set
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# 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
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_CAN is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+
+#
+# Wireless
+#
+# CONFIG_CFG80211 is not set
+# CONFIG_WIRELESS_EXT is not set
+# CONFIG_MAC80211 is not set
+# CONFIG_IEEE80211 is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=y
+CONFIG_FIRMWARE_IN_KERNEL=y
+CONFIG_EXTRA_FIRMWARE=""
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_CONNECTOR is not set
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+# CONFIG_MTD_CMDLINE_PARTS is not set
+# CONFIG_MTD_AFS_PARTS is not set
+# CONFIG_MTD_AR7_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+# CONFIG_MTD_OOPS is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+# CONFIG_MTD_CFI is not set
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+CONFIG_MTD_DATAFLASH=y
+# CONFIG_MTD_M25P80 is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+CONFIG_MTD_NAND=y
+# CONFIG_MTD_NAND_VERIFY_WRITE is not set
+# CONFIG_MTD_NAND_ECC_SMC is not set
+# CONFIG_MTD_NAND_MUSEUM_IDS is not set
+CONFIG_MTD_NAND_IDS=y
+# CONFIG_MTD_NAND_DISKONCHIP is not set
+CONFIG_MTD_NAND_ATMEL=y
+# CONFIG_MTD_NAND_ATMEL_ECC_HW is not set
+CONFIG_MTD_NAND_ATMEL_ECC_SOFT=y
+# CONFIG_MTD_NAND_ATMEL_ECC_NONE is not set
+# CONFIG_MTD_NAND_NANDSIM is not set
+# CONFIG_MTD_NAND_PLATFORM is not set
+# CONFIG_MTD_ALAUDA is not set
+# CONFIG_MTD_ONENAND is not set
+
+#
+# UBI - Unsorted block images
+#
+# CONFIG_MTD_UBI is not set
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_DEV_COW_COMMON is not set
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_UB is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=8192
+# CONFIG_BLK_DEV_XIP is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+CONFIG_MISC_DEVICES=y
+# CONFIG_ATMEL_PWM is not set
+# CONFIG_ATMEL_TCLIB is not set
+# CONFIG_EEPROM_93CX6 is not set
+CONFIG_ATMEL_SSC=y
+# CONFIG_ENCLOSURE_SERVICES is not set
+CONFIG_HAVE_IDE=y
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+# CONFIG_BLK_DEV_SR is not set
+# CONFIG_CHR_DEV_SG is not set
+# CONFIG_CHR_DEV_SCH is not set
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+CONFIG_SCSI_MULTI_LUN=y
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC is not set
+CONFIG_SCSI_WAIT_SCAN=m
+
+#
+# SCSI Transports
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+# CONFIG_SCSI_SRP_ATTRS is not set
+CONFIG_SCSI_LOWLEVEL=y
+# CONFIG_ISCSI_TCP is not set
+# CONFIG_SCSI_DEBUG is not set
+# CONFIG_SCSI_DH is not set
+# CONFIG_ATA is not set
+# CONFIG_MD is not set
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_VETH is not set
+CONFIG_PHYLIB=y
+
+#
+# MII PHY device drivers
+#
+# CONFIG_MARVELL_PHY is not set
+# CONFIG_DAVICOM_PHY is not set
+# CONFIG_QSEMI_PHY is not set
+# CONFIG_LXT_PHY is not set
+# CONFIG_CICADA_PHY is not set
+# CONFIG_VITESSE_PHY is not set
+# CONFIG_SMSC_PHY is not set
+# CONFIG_BROADCOM_PHY is not set
+# CONFIG_ICPLUS_PHY is not set
+# CONFIG_REALTEK_PHY is not set
+# CONFIG_FIXED_PHY is not set
+# CONFIG_MDIO_BITBANG is not set
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+CONFIG_MACB=y
+# CONFIG_AX88796 is not set
+# CONFIG_SMC91X is not set
+# CONFIG_DM9000 is not set
+# CONFIG_ENC28J60 is not set
+# CONFIG_IBM_NEW_EMAC_ZMII is not set
+# CONFIG_IBM_NEW_EMAC_RGMII is not set
+# CONFIG_IBM_NEW_EMAC_TAH is not set
+# CONFIG_IBM_NEW_EMAC_EMAC4 is not set
+# CONFIG_B44 is not set
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
+
+#
+# Wireless LAN
+#
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
+# CONFIG_IWLWIFI_LEDS is not set
+
+#
+# USB Network Adapters
+#
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_USBNET is not set
+# CONFIG_WAN is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_ISDN is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV 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_TABLET 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=y
+CONFIG_CONSOLE_TRANSLATIONS=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
+CONFIG_DEVKMEM=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_ATMEL=y
+CONFIG_SERIAL_ATMEL_CONSOLE=y
+CONFIG_SERIAL_ATMEL_PDC=y
+# CONFIG_SERIAL_ATMEL_TTYAT is not set
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_HW_RANDOM is not set
+# CONFIG_NVRAM is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_HELPER_AUTO=y
+CONFIG_I2C_ALGOBIT=y
+
+#
+# I2C Hardware Bus support
+#
+
+#
+# I2C system bus drivers (mostly embedded / system-on-chip)
+#
+CONFIG_I2C_GPIO=y
+# CONFIG_I2C_OCORES is not set
+# CONFIG_I2C_SIMTEC is not set
+
+#
+# External I2C/SMBus adapter drivers
+#
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_TAOS_EVM is not set
+# CONFIG_I2C_TINY_USB is not set
+
+#
+# Other I2C/SMBus bus drivers
+#
+# CONFIG_I2C_PCA_PLATFORM is not set
+# CONFIG_I2C_STUB is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_DS1682 is not set
+CONFIG_AT24=y
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_PCF8575 is not set
+# CONFIG_SENSORS_PCA9539 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_SENSORS_TSL2550 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
+CONFIG_SPI=y
+CONFIG_SPI_DEBUG=y
+CONFIG_SPI_MASTER=y
+
+#
+# SPI Master Controller Drivers
+#
+CONFIG_SPI_ATMEL=y
+# CONFIG_SPI_BITBANG is not set
+
+#
+# SPI Protocol Masters
+#
+# CONFIG_SPI_AT25 is not set
+CONFIG_SPI_SPIDEV=y
+# CONFIG_SPI_TLE62X0 is not set
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+# CONFIG_HWMON is not set
+CONFIG_WATCHDOG=y
+CONFIG_WATCHDOG_NOWAYOUT=y
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+
+#
+# USB-based Watchdog Cards
+#
+# CONFIG_USBPCWATCHDOG is not set
+
+#
+# Sonics Silicon Backplane
+#
+CONFIG_SSB_POSSIBLE=y
+# CONFIG_SSB is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_CORE is not set
+# CONFIG_MFD_SM501 is not set
+# CONFIG_HTC_PASIC3 is not set
+# CONFIG_MFD_TMIO is not set
+# CONFIG_MFD_T7L66XB is not set
+# CONFIG_MFD_TC6387XB is not set
+
+#
+# Multimedia devices
+#
+
+#
+# Multimedia core support
+#
+# CONFIG_VIDEO_DEV is not set
+# CONFIG_DVB_CORE is not set
+# CONFIG_VIDEO_MEDIA is not set
+
+#
+# Multimedia drivers
+#
+# CONFIG_DAB is not set
+
+#
+# Graphics support
+#
+# CONFIG_VGASTATE is not set
+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
+# CONFIG_FB is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+# CONFIG_SOUND is not set
+CONFIG_HID_SUPPORT=y
+CONFIG_HID=y
+# CONFIG_HID_DEBUG is not set
+# CONFIG_HIDRAW is not set
+
+#
+# USB Input Devices
+#
+# CONFIG_USB_HID is not set
+
+#
+# USB HID Boot Protocol drivers
+#
+# CONFIG_USB_KBD is not set
+# CONFIG_USB_MOUSE is not set
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+CONFIG_USB=y
+# CONFIG_USB_DEBUG is not set
+# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+CONFIG_USB_DEVICE_CLASS=y
+# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_OTG is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_C67X00_HCD is not set
+# CONFIG_USB_ISP116X_HCD is not set
+# CONFIG_USB_ISP1760_HCD is not set
+CONFIG_USB_OHCI_HCD=y
+# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set
+# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
+# CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_R8A66597_HCD is not set
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+# CONFIG_USB_WDM is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# may also be needed; see USB_STORAGE Help for more information
+#
+CONFIG_USB_STORAGE=y
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_ISD200 is not set
+# CONFIG_USB_STORAGE_DPCM is not set
+# CONFIG_USB_STORAGE_USBAT is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_STORAGE_ALAUDA is not set
+# CONFIG_USB_STORAGE_ONETOUCH is not set
+# CONFIG_USB_STORAGE_KARMA is not set
+# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set
+# CONFIG_USB_LIBUSUAL is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+CONFIG_USB_MON=y
+
+#
+# USB port drivers
+#
+# CONFIG_USB_SERIAL is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_ADUTUX is not set
+# CONFIG_USB_AUERSWALD is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_BERRY_CHARGE is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_PHIDGET is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_FTDI_ELAN is not set
+# CONFIG_USB_APPLEDISPLAY is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_IOWARRIOR is not set
+# CONFIG_USB_TEST is not set
+# CONFIG_USB_ISIGHTFW is not set
+CONFIG_USB_GADGET=y
+# CONFIG_USB_GADGET_DEBUG is not set
+# CONFIG_USB_GADGET_DEBUG_FILES is not set
+CONFIG_USB_GADGET_SELECTED=y
+# CONFIG_USB_GADGET_AMD5536UDC is not set
+# CONFIG_USB_GADGET_ATMEL_USBA is not set
+# CONFIG_USB_GADGET_FSL_USB2 is not set
+# CONFIG_USB_GADGET_NET2280 is not set
+# CONFIG_USB_GADGET_PXA25X is not set
+# CONFIG_USB_GADGET_M66592 is not set
+# CONFIG_USB_GADGET_PXA27X is not set
+# CONFIG_USB_GADGET_GOKU is not set
+# CONFIG_USB_GADGET_LH7A40X is not set
+# CONFIG_USB_GADGET_OMAP is not set
+# CONFIG_USB_GADGET_S3C2410 is not set
+CONFIG_USB_GADGET_AT91=y
+CONFIG_USB_AT91=y
+# CONFIG_USB_GADGET_DUMMY_HCD is not set
+# CONFIG_USB_GADGET_DUALSPEED is not set
+CONFIG_USB_ZERO=m
+# CONFIG_USB_ETH is not set
+CONFIG_USB_GADGETFS=m
+CONFIG_USB_FILE_STORAGE=m
+# CONFIG_USB_FILE_STORAGE_TEST is not set
+CONFIG_USB_G_SERIAL=m
+# CONFIG_USB_MIDI_GADGET is not set
+# CONFIG_USB_G_PRINTER is not set
+# CONFIG_USB_CDC_COMPOSITE is not set
+# CONFIG_MMC is not set
+# CONFIG_NEW_LEDS is not set
+CONFIG_RTC_LIB=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+CONFIG_RTC_DEBUG=y
+
+#
+# RTC interfaces
+#
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_DEV=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+# CONFIG_RTC_DRV_TEST is not set
+
+#
+# I2C RTC drivers
+#
+# CONFIG_RTC_DRV_DS1307 is not set
+# CONFIG_RTC_DRV_DS1374 is not set
+# CONFIG_RTC_DRV_DS1672 is not set
+# CONFIG_RTC_DRV_MAX6900 is not set
+# CONFIG_RTC_DRV_RS5C372 is not set
+# CONFIG_RTC_DRV_ISL1208 is not set
+# CONFIG_RTC_DRV_X1205 is not set
+# CONFIG_RTC_DRV_PCF8563 is not set
+# CONFIG_RTC_DRV_PCF8583 is not set
+# CONFIG_RTC_DRV_M41T80 is not set
+# CONFIG_RTC_DRV_S35390A is not set
+CONFIG_RTC_DRV_FM3130=y
+
+#
+# SPI RTC drivers
+#
+# CONFIG_RTC_DRV_M41T94 is not set
+# CONFIG_RTC_DRV_DS1305 is not set
+# CONFIG_RTC_DRV_MAX6902 is not set
+# CONFIG_RTC_DRV_R9701 is not set
+# CONFIG_RTC_DRV_RS5C348 is not set
+
+#
+# Platform RTC drivers
+#
+# CONFIG_RTC_DRV_CMOS is not set
+# CONFIG_RTC_DRV_DS1511 is not set
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_STK17TA8 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_M48T59 is not set
+# CONFIG_RTC_DRV_V3020 is not set
+
+#
+# on-CPU RTC drivers
+#
+# CONFIG_RTC_DRV_AT91SAM9 is not set
+# CONFIG_DMADEVICES is not set
+
+#
+# Voltage and Current regulators
+#
+# CONFIG_REGULATOR is not set
+# CONFIG_REGULATOR_FIXED_VOLTAGE is not set
+# CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set
+# CONFIG_REGULATOR_BQ24022 is not set
+# CONFIG_UIO is not set
+
+#
+# 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_EXT4DEV_FS is not set
+CONFIG_JBD=y
+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_DNOTIFY=y
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+# 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_FAT_FS=y
+# CONFIG_MSDOS_FS is not set
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+# 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_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_FS_WBUF_VERIFY is not set
+# CONFIG_JFFS2_SUMMARY is not set
+# CONFIG_JFFS2_FS_XATTR is not set
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+# CONFIG_JFFS2_LZO is not set
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+CONFIG_CRAMFS=y
+# CONFIG_VXFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_OMFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+CONFIG_NETWORK_FILESYSTEMS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+# CONFIG_NFS_V4 is not set
+CONFIG_ROOT_NFS=y
+# CONFIG_NFSD is not set
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# 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
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+CONFIG_NLS_CODEPAGE_850=y
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+CONFIG_NLS_ISO8859_1=y
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+# CONFIG_DLM is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_FRAME_WARN=1024
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
+CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set
+CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0
+CONFIG_SCHED_DEBUG=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_TIMER_STATS is not set
+# CONFIG_DEBUG_OBJECTS is not set
+# CONFIG_DEBUG_SLAB is not set
+CONFIG_DEBUG_PREEMPT=y
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_KOBJECT is not set
+CONFIG_DEBUG_BUGVERBOSE=y
+CONFIG_DEBUG_INFO=y
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_WRITECOUNT is not set
+CONFIG_DEBUG_MEMORY_INIT=y
+# CONFIG_DEBUG_LIST is not set
+# CONFIG_DEBUG_SG is not set
+CONFIG_FRAME_POINTER=y
+# CONFIG_BOOT_PRINTK_DELAY is not set
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_BACKTRACE_SELF_TEST is not set
+# CONFIG_FAULT_INJECTION is not set
+# CONFIG_LATENCYTOP is not set
+CONFIG_HAVE_FTRACE=y
+CONFIG_HAVE_DYNAMIC_FTRACE=y
+# CONFIG_FTRACE is not set
+# CONFIG_IRQSOFF_TRACER is not set
+# CONFIG_PREEMPT_TRACER is not set
+# CONFIG_SCHED_TRACER is not set
+# CONFIG_CONTEXT_SWITCH_TRACER is not set
+# CONFIG_SAMPLES is not set
+CONFIG_HAVE_ARCH_KGDB=y
+# CONFIG_KGDB is not set
+CONFIG_DEBUG_USER=y
+# CONFIG_DEBUG_ERRORS is not set
+# CONFIG_DEBUG_STACK_USAGE is not set
+CONFIG_DEBUG_LL=y
+# CONFIG_DEBUG_ICEDCC is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+# CONFIG_SECURITY_FILE_CAPABILITIES is not set
+# CONFIG_CRYPTO is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+# CONFIG_GENERIC_FIND_FIRST_BIT is not set
+# CONFIG_GENERIC_FIND_NEXT_BIT is not set
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+CONFIG_CRC_T10DIF=y
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
diff --git a/arch/arm/configs/at91sam9rlek_defconfig b/arch/arm/configs/at91sam9rlek_defconfig
index 1c76642..811bebb 100644
--- a/arch/arm/configs/at91sam9rlek_defconfig
+++ b/arch/arm/configs/at91sam9rlek_defconfig
@@ -496,6 +496,7 @@
 # CONFIG_TOUCHSCREEN_PENMOUNT is not set
 # CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set
 # CONFIG_TOUCHSCREEN_TOUCHWIN is not set
+CONFIG_TOUCHSCREEN_ATMEL_TSADCC=y
 # CONFIG_TOUCHSCREEN_UCB1400 is not set
 # CONFIG_TOUCHSCREEN_USB_COMPOSITE is not set
 # CONFIG_INPUT_MISC is not set
diff --git a/arch/arm/configs/cm_x300_defconfig b/arch/arm/configs/cm_x300_defconfig
new file mode 100644
index 0000000..46f1c9d
--- /dev/null
+++ b/arch/arm/configs/cm_x300_defconfig
@@ -0,0 +1,1466 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.27-rc3
+# Tue Aug 19 11:26:54 2008
+#
+CONFIG_ARM=y
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+CONFIG_GENERIC_GPIO=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_MMU=y
+# CONFIG_NO_IOPORT is not set
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_ARCH_SUPPORTS_AOUT=y
+CONFIG_ZONE_DMA=y
+CONFIG_ARCH_MTD_XIP=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
+CONFIG_VECTORS_BASE=0xffff0000
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION="-cm-x300"
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=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=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_BUF_SHIFT=18
+# CONFIG_CGROUPS is not set
+CONFIG_GROUP_SCHED=y
+CONFIG_FAIR_GROUP_SCHED=y
+# CONFIG_RT_GROUP_SCHED is not set
+CONFIG_USER_SCHED=y
+# CONFIG_CGROUP_SCHED is not set
+CONFIG_SYSFS_DEPRECATED=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+# CONFIG_RELAY is not set
+CONFIG_NAMESPACES=y
+# CONFIG_UTS_NS is not set
+# CONFIG_IPC_NS is not set
+# CONFIG_USER_NS is not set
+# CONFIG_PID_NS is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SYSCTL=y
+# CONFIG_EMBEDDED is not set
+CONFIG_UID16=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_COMPAT_BRK=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_ANON_INODES=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_SLUB_DEBUG=y
+# CONFIG_SLAB is not set
+CONFIG_SLUB=y
+# CONFIG_SLOB is not set
+# CONFIG_PROFILING is not set
+# CONFIG_MARKERS is not set
+CONFIG_HAVE_OPROFILE=y
+# CONFIG_KPROBES is not set
+# CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS is not set
+# CONFIG_HAVE_IOREMAP_PROT is not set
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+# CONFIG_HAVE_ARCH_TRACEHOOK is not set
+# CONFIG_HAVE_DMA_ATTRS is not set
+# CONFIG_USE_GENERIC_SMP_HELPERS is not set
+CONFIG_HAVE_CLK=y
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_HAVE_GENERIC_DMA_COHERENT=y
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+# CONFIG_MODULE_FORCE_LOAD is not set
+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=y
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_BLK_DEV_INTEGRITY is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_DEFAULT_AS is not set
+# CONFIG_DEFAULT_DEADLINE is not set
+CONFIG_DEFAULT_CFQ=y
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="cfq"
+CONFIG_CLASSIC_RCU=y
+
+#
+# System Type
+#
+# CONFIG_ARCH_AAEC2000 is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_REALVIEW is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_AT91 is not set
+# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_EP93XX is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_NETX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_IOP13XX is not set
+# CONFIG_ARCH_IOP32X is not set
+# CONFIG_ARCH_IOP33X is not set
+# CONFIG_ARCH_IXP23XX is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_KIRKWOOD is not set
+# CONFIG_ARCH_KS8695 is not set
+# CONFIG_ARCH_NS9XXX is not set
+# CONFIG_ARCH_LOKI is not set
+# CONFIG_ARCH_MV78XX0 is not set
+# CONFIG_ARCH_MXC is not set
+# CONFIG_ARCH_ORION5X is not set
+# CONFIG_ARCH_PNX4008 is not set
+CONFIG_ARCH_PXA=y
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_DAVINCI is not set
+# CONFIG_ARCH_OMAP is not set
+# CONFIG_ARCH_MSM7X00A is not set
+
+#
+# Intel PXA2xx/PXA3xx Implementations
+#
+
+#
+# Supported PXA3xx Processor Variants
+#
+CONFIG_CPU_PXA300=y
+# CONFIG_CPU_PXA310 is not set
+# CONFIG_CPU_PXA320 is not set
+# CONFIG_CPU_PXA930 is not set
+# CONFIG_ARCH_GUMSTIX is not set
+# CONFIG_ARCH_LUBBOCK is not set
+# CONFIG_MACH_LOGICPD_PXA270 is not set
+# CONFIG_MACH_MAINSTONE is not set
+# CONFIG_ARCH_PXA_IDP is not set
+# CONFIG_PXA_SHARPSL is not set
+# CONFIG_ARCH_PXA_ESERIES is not set
+# CONFIG_MACH_TRIZEPS4 is not set
+# CONFIG_MACH_EM_X270 is not set
+# CONFIG_MACH_COLIBRI is not set
+# CONFIG_MACH_ZYLONITE is not set
+# CONFIG_MACH_LITTLETON is not set
+# CONFIG_MACH_TAVOREVB is not set
+# CONFIG_MACH_SAAR is not set
+# CONFIG_MACH_ARMCORE is not set
+CONFIG_MACH_CM_X300=y
+# CONFIG_MACH_MAGICIAN is not set
+# CONFIG_MACH_PCM027 is not set
+# CONFIG_ARCH_PXA_PALM is not set
+# CONFIG_PXA_EZX is not set
+CONFIG_PXA3xx=y
+# CONFIG_PXA_PWM is not set
+
+#
+# Boot options
+#
+
+#
+# Power management
+#
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_XSC3=y
+CONFIG_CPU_32v5=y
+CONFIG_CPU_ABRT_EV5T=y
+CONFIG_CPU_PABRT_NOIFAR=y
+CONFIG_CPU_CACHE_VIVT=y
+CONFIG_CPU_TLB_V4WBI=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
+CONFIG_IO_36=y
+
+#
+# Processor Features
+#
+# CONFIG_ARM_THUMB is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_CPU_BPREDICT_DISABLE is not set
+CONFIG_OUTER_CACHE=y
+CONFIG_CACHE_XSC3L2=y
+CONFIG_IWMMXT=y
+
+#
+# Bus support
+#
+# CONFIG_PCI_SYSCALL is not set
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+CONFIG_TICK_ONESHOT=y
+CONFIG_NO_HZ=y
+# CONFIG_HIGH_RES_TIMERS is not set
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+# CONFIG_PREEMPT is not set
+CONFIG_HZ=100
+CONFIG_AEABI=y
+CONFIG_OABI_COMPAT=y
+# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
+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_SPARSEMEM_VMEMMAP_ENABLE is not set
+CONFIG_PAGEFLAGS_EXTENDED=y
+CONFIG_SPLIT_PTLOCK_CPUS=4096
+# CONFIG_RESOURCES_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=1
+CONFIG_BOUNCE=y
+CONFIG_VIRT_TO_BUS=y
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="root=/dev/mtdblock5 rootfstype=jffs2 console=ttyS2,38400"
+# CONFIG_XIP_KERNEL is not set
+# CONFIG_KEXEC is not set
+
+#
+# CPU Frequency scaling
+#
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_TABLE=y
+# CONFIG_CPU_FREQ_DEBUG is not set
+CONFIG_CPU_FREQ_STAT=y
+# CONFIG_CPU_FREQ_STAT_DETAILS is not set
+CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y
+# CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set
+CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
+# CONFIG_CPU_FREQ_GOV_POWERSAVE is not set
+CONFIG_CPU_FREQ_GOV_USERSPACE=y
+# CONFIG_CPU_FREQ_GOV_ONDEMAND is not set
+# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_FASTFPE is not set
+
+#
+# Userspace binary formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Power management options
+#
+CONFIG_PM=y
+# CONFIG_PM_DEBUG is not set
+CONFIG_PM_SLEEP=y
+CONFIG_SUSPEND=y
+CONFIG_SUSPEND_FREEZER=y
+CONFIG_APM_EMULATION=y
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+CONFIG_IP_PNP_RARP=y
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+# CONFIG_INET_DIAG is not set
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# 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
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_CAN is not set
+# CONFIG_IRDA is not set
+CONFIG_BT=m
+CONFIG_BT_L2CAP=m
+CONFIG_BT_SCO=m
+CONFIG_BT_RFCOMM=m
+CONFIG_BT_RFCOMM_TTY=y
+CONFIG_BT_BNEP=m
+CONFIG_BT_BNEP_MC_FILTER=y
+CONFIG_BT_BNEP_PROTO_FILTER=y
+CONFIG_BT_HIDP=m
+
+#
+# Bluetooth device drivers
+#
+CONFIG_BT_HCIUSB=m
+CONFIG_BT_HCIUSB_SCO=y
+# CONFIG_BT_HCIBTSDIO is not set
+# CONFIG_BT_HCIUART is not set
+# CONFIG_BT_HCIBCM203X is not set
+# CONFIG_BT_HCIBPA10X is not set
+# CONFIG_BT_HCIBFUSB is not set
+# CONFIG_BT_HCIVHCI is not set
+# CONFIG_AF_RXRPC is not set
+
+#
+# Wireless
+#
+# CONFIG_CFG80211 is not set
+CONFIG_WIRELESS_EXT=y
+CONFIG_WIRELESS_EXT_SYSFS=y
+# CONFIG_MAC80211 is not set
+CONFIG_IEEE80211=m
+# CONFIG_IEEE80211_DEBUG is not set
+CONFIG_IEEE80211_CRYPT_WEP=m
+CONFIG_IEEE80211_CRYPT_CCMP=m
+CONFIG_IEEE80211_CRYPT_TKIP=m
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=y
+CONFIG_FIRMWARE_IN_KERNEL=y
+CONFIG_EXTRA_FIRMWARE=""
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_CONNECTOR is not set
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+# CONFIG_MTD_CMDLINE_PARTS is not set
+# CONFIG_MTD_AFS_PARTS is not set
+# CONFIG_MTD_AR7_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+# CONFIG_MTD_OOPS is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+# CONFIG_MTD_CFI is not set
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_SHARP_SL is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+CONFIG_MTD_NAND=y
+# CONFIG_MTD_NAND_VERIFY_WRITE is not set
+# CONFIG_MTD_NAND_ECC_SMC is not set
+# CONFIG_MTD_NAND_MUSEUM_IDS is not set
+# CONFIG_MTD_NAND_H1900 is not set
+CONFIG_MTD_NAND_IDS=y
+# CONFIG_MTD_NAND_DISKONCHIP is not set
+# CONFIG_MTD_NAND_SHARPSL is not set
+CONFIG_MTD_NAND_PXA3xx=y
+# CONFIG_MTD_NAND_NANDSIM is not set
+# CONFIG_MTD_NAND_PLATFORM is not set
+# CONFIG_MTD_ALAUDA is not set
+# CONFIG_MTD_ONENAND is not set
+
+#
+# UBI - Unsorted block images
+#
+# CONFIG_MTD_UBI is not set
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# 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_UB is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=4096
+# CONFIG_BLK_DEV_XIP is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+# CONFIG_MISC_DEVICES is not set
+CONFIG_HAVE_IDE=y
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+# CONFIG_BLK_DEV_SR is not set
+# CONFIG_CHR_DEV_SG is not set
+# CONFIG_CHR_DEV_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
+# CONFIG_SCSI_SCAN_ASYNC is not set
+CONFIG_SCSI_WAIT_SCAN=m
+
+#
+# SCSI Transports
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+# CONFIG_SCSI_SRP_ATTRS is not set
+CONFIG_SCSI_LOWLEVEL=y
+# CONFIG_ISCSI_TCP is not set
+# CONFIG_SCSI_DEBUG is not set
+# CONFIG_SCSI_DH is not set
+# CONFIG_ATA is not set
+# CONFIG_MD is not set
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_VETH is not set
+# CONFIG_PHYLIB is not set
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_AX88796 is not set
+# CONFIG_SMC91X is not set
+CONFIG_DM9000=y
+CONFIG_DM9000_DEBUGLEVEL=0
+CONFIG_DM9000_FORCE_SIMPLE_PHY_POLL=y
+# CONFIG_SMC911X is not set
+# CONFIG_IBM_NEW_EMAC_ZMII is not set
+# CONFIG_IBM_NEW_EMAC_RGMII is not set
+# CONFIG_IBM_NEW_EMAC_TAH is not set
+# CONFIG_IBM_NEW_EMAC_EMAC4 is not set
+# CONFIG_B44 is not set
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
+
+#
+# Wireless LAN
+#
+# CONFIG_WLAN_PRE80211 is not set
+CONFIG_WLAN_80211=y
+CONFIG_LIBERTAS=m
+# CONFIG_LIBERTAS_USB is not set
+CONFIG_LIBERTAS_SDIO=m
+# CONFIG_LIBERTAS_DEBUG is not set
+# CONFIG_USB_ZD1201 is not set
+# CONFIG_USB_NET_RNDIS_WLAN is not set
+# CONFIG_IWLWIFI_LEDS is not set
+# CONFIG_HOSTAP is not set
+
+#
+# USB Network Adapters
+#
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_USBNET is not set
+# CONFIG_WAN is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_ISDN is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+# CONFIG_KEYBOARD_ATKBD is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_KEYBOARD_STOWAWAY is not set
+CONFIG_KEYBOARD_PXA27x=m
+# CONFIG_KEYBOARD_GPIO is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+CONFIG_INPUT_TOUCHSCREEN=y
+# CONFIG_TOUCHSCREEN_FUJITSU is not set
+# CONFIG_TOUCHSCREEN_GUNZE is not set
+# CONFIG_TOUCHSCREEN_ELO is not set
+# CONFIG_TOUCHSCREEN_MTOUCH is not set
+# CONFIG_TOUCHSCREEN_INEXIO is not set
+# CONFIG_TOUCHSCREEN_MK712 is not set
+# CONFIG_TOUCHSCREEN_PENMOUNT is not set
+# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set
+# CONFIG_TOUCHSCREEN_TOUCHWIN is not set
+# CONFIG_TOUCHSCREEN_UCB1400 is not set
+# CONFIG_TOUCHSCREEN_USB_COMPOSITE is not set
+# CONFIG_TOUCHSCREEN_TOUCHIT213 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=y
+CONFIG_CONSOLE_TRANSLATIONS=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
+CONFIG_DEVKMEM=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_PXA=y
+CONFIG_SERIAL_PXA_CONSOLE=y
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_HW_RANDOM is not set
+# CONFIG_NVRAM is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=y
+# CONFIG_I2C_CHARDEV is not set
+CONFIG_I2C_HELPER_AUTO=y
+
+#
+# I2C Hardware Bus support
+#
+
+#
+# I2C system bus drivers (mostly embedded / system-on-chip)
+#
+# CONFIG_I2C_GPIO is not set
+# CONFIG_I2C_OCORES is not set
+CONFIG_I2C_PXA=y
+# CONFIG_I2C_PXA_SLAVE is not set
+# CONFIG_I2C_SIMTEC is not set
+
+#
+# External I2C/SMBus adapter drivers
+#
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_TAOS_EVM is not set
+# CONFIG_I2C_TINY_USB is not set
+
+#
+# Other I2C/SMBus bus drivers
+#
+# CONFIG_I2C_PCA_PLATFORM is not set
+# CONFIG_I2C_STUB is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_DS1682 is not set
+# CONFIG_AT24 is not set
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_PCF8575 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_TPS65010 is not set
+# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_SENSORS_TSL2550 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
+# CONFIG_SPI is not set
+CONFIG_ARCH_REQUIRE_GPIOLIB=y
+CONFIG_GPIOLIB=y
+# CONFIG_DEBUG_GPIO is not set
+# CONFIG_GPIO_SYSFS is not set
+
+#
+# I2C GPIO expanders:
+#
+# CONFIG_GPIO_MAX732X is not set
+CONFIG_GPIO_PCA953X=y
+# CONFIG_GPIO_PCF857X is not set
+
+#
+# PCI GPIO expanders:
+#
+
+#
+# SPI GPIO expanders:
+#
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+# CONFIG_HWMON is not set
+# CONFIG_WATCHDOG is not set
+
+#
+# Sonics Silicon Backplane
+#
+CONFIG_SSB_POSSIBLE=y
+# CONFIG_SSB is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_CORE is not set
+# CONFIG_MFD_SM501 is not set
+# CONFIG_HTC_EGPIO is not set
+# CONFIG_HTC_PASIC3 is not set
+# CONFIG_MFD_TMIO is not set
+# CONFIG_MFD_T7L66XB is not set
+# CONFIG_MFD_TC6387XB is not set
+# CONFIG_MFD_TC6393XB is not set
+
+#
+# Multimedia devices
+#
+
+#
+# Multimedia core support
+#
+# CONFIG_VIDEO_DEV is not set
+# CONFIG_DVB_CORE is not set
+# CONFIG_VIDEO_MEDIA is not set
+
+#
+# Multimedia drivers
+#
+# CONFIG_DAB is not set
+
+#
+# Graphics support
+#
+# CONFIG_VGASTATE is not set
+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
+CONFIG_FB=y
+# CONFIG_FIRMWARE_EDID is not set
+# CONFIG_FB_DDC is not set
+CONFIG_FB_CFB_FILLRECT=y
+CONFIG_FB_CFB_COPYAREA=y
+CONFIG_FB_CFB_IMAGEBLIT=y
+# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
+# CONFIG_FB_SYS_FILLRECT is not set
+# CONFIG_FB_SYS_COPYAREA is not set
+# CONFIG_FB_SYS_IMAGEBLIT is not set
+# CONFIG_FB_FOREIGN_ENDIAN is not set
+# CONFIG_FB_SYS_FOPS is not set
+# CONFIG_FB_SVGALIB is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+
+#
+# Frame buffer hardware drivers
+#
+# CONFIG_FB_S1D13XXX is not set
+CONFIG_FB_PXA=y
+# CONFIG_FB_PXA_SMARTPANEL is not set
+# CONFIG_FB_PXA_PARAMETERS is not set
+# CONFIG_FB_MBX is not set
+# CONFIG_FB_W100 is not set
+# CONFIG_FB_AM200EPD is not set
+# CONFIG_FB_VIRTUAL is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y
+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
+CONFIG_FONTS=y
+# CONFIG_FONT_8x8 is not set
+# CONFIG_FONT_8x16 is not set
+CONFIG_FONT_6x11=y
+# CONFIG_FONT_7x14 is not set
+# CONFIG_FONT_PEARL_8x8 is not set
+# CONFIG_FONT_ACORN_8x8 is not set
+# CONFIG_FONT_MINI_4x6 is not set
+# CONFIG_FONT_SUN8x16 is not set
+# CONFIG_FONT_SUN12x22 is not set
+# CONFIG_FONT_10x18 is not set
+CONFIG_LOGO=y
+CONFIG_LOGO_LINUX_MONO=y
+CONFIG_LOGO_LINUX_VGA16=y
+CONFIG_LOGO_LINUX_CLUT224=y
+CONFIG_SOUND=m
+CONFIG_SND=m
+CONFIG_SND_TIMER=m
+CONFIG_SND_PCM=m
+# CONFIG_SND_SEQUENCER is not set
+# CONFIG_SND_MIXER_OSS is not set
+# CONFIG_SND_PCM_OSS is not set
+# CONFIG_SND_DYNAMIC_MINORS is not set
+CONFIG_SND_SUPPORT_OLD_API=y
+CONFIG_SND_VERBOSE_PROCFS=y
+# CONFIG_SND_VERBOSE_PRINTK is not set
+# CONFIG_SND_DEBUG is not set
+CONFIG_SND_DRIVERS=y
+# CONFIG_SND_DUMMY is not set
+# CONFIG_SND_MTPAV is not set
+# CONFIG_SND_SERIAL_U16550 is not set
+# CONFIG_SND_MPU401 is not set
+CONFIG_SND_ARM=y
+# CONFIG_SND_PXA2XX_AC97 is not set
+CONFIG_SND_USB=y
+# CONFIG_SND_USB_AUDIO is not set
+# CONFIG_SND_USB_CAIAQ is not set
+CONFIG_SND_SOC=m
+CONFIG_SND_PXA2XX_SOC=m
+# CONFIG_SOUND_PRIME is not set
+CONFIG_HID_SUPPORT=y
+CONFIG_HID=y
+CONFIG_HID_DEBUG=y
+# CONFIG_HIDRAW is not set
+
+#
+# USB Input Devices
+#
+CONFIG_USB_HID=y
+# CONFIG_USB_HIDINPUT_POWERBOOK is not set
+# CONFIG_HID_FF is not set
+# CONFIG_USB_HIDDEV is not set
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+CONFIG_USB=y
+# CONFIG_USB_DEBUG is not set
+# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+# CONFIG_USB_DEVICE_CLASS is not set
+# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_SUSPEND is not set
+# CONFIG_USB_OTG is not set
+CONFIG_USB_MON=y
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_C67X00_HCD is not set
+# CONFIG_USB_ISP116X_HCD is not set
+# CONFIG_USB_ISP1760_HCD is not set
+CONFIG_USB_OHCI_HCD=y
+# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set
+# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
+# CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_R8A66597_HCD is not set
+# CONFIG_USB_MUSB_HDRC is not set
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+# CONFIG_USB_WDM is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# may also be needed; see USB_STORAGE Help for more information
+#
+CONFIG_USB_STORAGE=y
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_ISD200 is not set
+# CONFIG_USB_STORAGE_DPCM is not set
+# CONFIG_USB_STORAGE_USBAT is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_STORAGE_ALAUDA is not set
+# CONFIG_USB_STORAGE_ONETOUCH is not set
+# CONFIG_USB_STORAGE_KARMA is not set
+# CONFIG_USB_STORAGE_SIERRA is not set
+# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set
+# CONFIG_USB_LIBUSUAL is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+
+#
+# USB port drivers
+#
+# CONFIG_USB_SERIAL is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_ADUTUX is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_BERRY_CHARGE is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_PHIDGET is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_FTDI_ELAN is not set
+# CONFIG_USB_APPLEDISPLAY is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_IOWARRIOR is not set
+# CONFIG_USB_TEST is not set
+# CONFIG_USB_ISIGHTFW is not set
+# CONFIG_USB_GADGET is not set
+CONFIG_MMC=m
+# CONFIG_MMC_DEBUG is not set
+# CONFIG_MMC_UNSAFE_RESUME is not set
+
+#
+# MMC/SD Card Drivers
+#
+CONFIG_MMC_BLOCK=m
+CONFIG_MMC_BLOCK_BOUNCE=y
+# CONFIG_SDIO_UART is not set
+# CONFIG_MMC_TEST is not set
+
+#
+# MMC/SD Host Controller Drivers
+#
+CONFIG_MMC_PXA=m
+# CONFIG_MMC_SDHCI is not set
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+
+#
+# LED drivers
+#
+# CONFIG_LEDS_PCA9532 is not set
+CONFIG_LEDS_GPIO=y
+# CONFIG_LEDS_PCA955X is not set
+
+#
+# LED Triggers
+#
+CONFIG_LEDS_TRIGGERS=y
+# CONFIG_LEDS_TRIGGER_TIMER is not set
+CONFIG_LEDS_TRIGGER_HEARTBEAT=y
+# CONFIG_LEDS_TRIGGER_DEFAULT_ON is not set
+CONFIG_RTC_LIB=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+# CONFIG_RTC_DEBUG is not set
+
+#
+# RTC interfaces
+#
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_DEV=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+# CONFIG_RTC_DRV_TEST is not set
+
+#
+# I2C RTC drivers
+#
+# CONFIG_RTC_DRV_DS1307 is not set
+# CONFIG_RTC_DRV_DS1374 is not set
+# CONFIG_RTC_DRV_DS1672 is not set
+# CONFIG_RTC_DRV_MAX6900 is not set
+# CONFIG_RTC_DRV_RS5C372 is not set
+# CONFIG_RTC_DRV_ISL1208 is not set
+# CONFIG_RTC_DRV_X1205 is not set
+# CONFIG_RTC_DRV_PCF8563 is not set
+# CONFIG_RTC_DRV_PCF8583 is not set
+# CONFIG_RTC_DRV_M41T80 is not set
+# CONFIG_RTC_DRV_S35390A is not set
+# CONFIG_RTC_DRV_FM3130 is not set
+
+#
+# SPI RTC drivers
+#
+
+#
+# Platform RTC drivers
+#
+# CONFIG_RTC_DRV_CMOS is not set
+# CONFIG_RTC_DRV_DS1511 is not set
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_STK17TA8 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_M48T59 is not set
+# CONFIG_RTC_DRV_V3020 is not set
+
+#
+# on-CPU RTC drivers
+#
+CONFIG_RTC_DRV_SA1100=y
+# CONFIG_DMADEVICES is not set
+
+#
+# Voltage and Current regulators
+#
+# CONFIG_REGULATOR is not set
+# CONFIG_REGULATOR_FIXED_VOLTAGE is not set
+# CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set
+# CONFIG_REGULATOR_BQ24022 is not set
+# CONFIG_UIO is not set
+
+#
+# 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 is not set
+# CONFIG_EXT4DEV_FS is not set
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+CONFIG_FS_POSIX_ACL=y
+# CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
+CONFIG_DNOTIFY=y
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+# 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_FAT_FS=m
+CONFIG_MSDOS_FS=m
+CONFIG_VFAT_FS=m
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+# 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_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_FS_WBUF_VERIFY is not set
+CONFIG_JFFS2_SUMMARY=y
+# CONFIG_JFFS2_FS_XATTR is not set
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+# CONFIG_JFFS2_LZO is not set
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_OMFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+CONFIG_NETWORK_FILESYSTEMS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+CONFIG_NFS_V3_ACL=y
+CONFIG_NFS_V4=y
+CONFIG_ROOT_NFS=y
+# CONFIG_NFSD is not set
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_ACL_SUPPORT=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=m
+# CONFIG_SMB_NLS_DEFAULT is not set
+CONFIG_CIFS=m
+# CONFIG_CIFS_STATS is not set
+CONFIG_CIFS_WEAK_PW_HASH=y
+# CONFIG_CIFS_XATTR is not set
+# CONFIG_CIFS_DEBUG2 is not set
+# CONFIG_CIFS_EXPERIMENTAL is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_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
+# CONFIG_SYSV68_PARTITION is not set
+CONFIG_NLS=m
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=m
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+CONFIG_NLS_ISO8859_1=m
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+# CONFIG_DLM is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_FRAME_WARN=1024
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+CONFIG_DEBUG_FS=y
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
+# CONFIG_DETECT_SOFTLOCKUP is not set
+# CONFIG_SCHED_DEBUG is not set
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_TIMER_STATS is not set
+# CONFIG_DEBUG_OBJECTS is not set
+# CONFIG_SLUB_DEBUG_ON is not set
+# CONFIG_SLUB_STATS is not set
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_KOBJECT is not set
+CONFIG_DEBUG_BUGVERBOSE=y
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_WRITECOUNT is not set
+CONFIG_DEBUG_MEMORY_INIT=y
+# CONFIG_DEBUG_LIST is not set
+# CONFIG_DEBUG_SG is not set
+CONFIG_FRAME_POINTER=y
+# CONFIG_BOOT_PRINTK_DELAY is not set
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_BACKTRACE_SELF_TEST is not set
+# CONFIG_FAULT_INJECTION is not set
+# CONFIG_LATENCYTOP is not set
+CONFIG_SYSCTL_SYSCALL_CHECK=y
+CONFIG_HAVE_FTRACE=y
+CONFIG_HAVE_DYNAMIC_FTRACE=y
+# CONFIG_FTRACE is not set
+# CONFIG_IRQSOFF_TRACER is not set
+# CONFIG_SCHED_TRACER is not set
+# CONFIG_CONTEXT_SWITCH_TRACER is not set
+# CONFIG_SAMPLES is not set
+CONFIG_HAVE_ARCH_KGDB=y
+# CONFIG_KGDB is not set
+CONFIG_DEBUG_USER=y
+# CONFIG_DEBUG_ERRORS is not set
+# CONFIG_DEBUG_STACK_USAGE is not set
+CONFIG_DEBUG_LL=y
+# CONFIG_DEBUG_ICEDCC is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+# CONFIG_SECURITY_FILE_CAPABILITIES is not set
+CONFIG_CRYPTO=y
+
+#
+# Crypto core or helper
+#
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_MANAGER=y
+# CONFIG_CRYPTO_GF128MUL is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_CRYPTD is not set
+# CONFIG_CRYPTO_AUTHENC is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Authenticated Encryption with Associated Data
+#
+# CONFIG_CRYPTO_CCM is not set
+# CONFIG_CRYPTO_GCM is not set
+# CONFIG_CRYPTO_SEQIV is not set
+
+#
+# Block modes
+#
+CONFIG_CRYPTO_CBC=y
+# CONFIG_CRYPTO_CTR is not set
+# CONFIG_CRYPTO_CTS is not set
+CONFIG_CRYPTO_ECB=m
+# CONFIG_CRYPTO_LRW is not set
+# CONFIG_CRYPTO_PCBC is not set
+# CONFIG_CRYPTO_XTS is not set
+
+#
+# Hash modes
+#
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_XCBC is not set
+
+#
+# Digest
+#
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_MD4 is not set
+CONFIG_CRYPTO_MD5=y
+CONFIG_CRYPTO_MICHAEL_MIC=m
+# CONFIG_CRYPTO_RMD128 is not set
+# CONFIG_CRYPTO_RMD160 is not set
+# CONFIG_CRYPTO_RMD256 is not set
+# CONFIG_CRYPTO_RMD320 is not set
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_WP512 is not set
+
+#
+# Ciphers
+#
+CONFIG_CRYPTO_AES=m
+# CONFIG_CRYPTO_ANUBIS is not set
+CONFIG_CRYPTO_ARC4=m
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_CAMELLIA is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+CONFIG_CRYPTO_DES=y
+# CONFIG_CRYPTO_FCRYPT is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_SALSA20 is not set
+# CONFIG_CRYPTO_SEED is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+
+#
+# Compression
+#
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_LZO is not set
+# CONFIG_CRYPTO_HW is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+# CONFIG_GENERIC_FIND_FIRST_BIT is not set
+# CONFIG_GENERIC_FIND_NEXT_BIT is not set
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+CONFIG_CRC_T10DIF=y
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
diff --git a/arch/arm/configs/jornada720_defconfig b/arch/arm/configs/jornada720_defconfig
index 0c55628..81fadaf 100644
--- a/arch/arm/configs/jornada720_defconfig
+++ b/arch/arm/configs/jornada720_defconfig
@@ -1,84 +1,174 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.12-rc1-bk2
-# Sun Mar 27 23:10:35 2005
+# Linux kernel version: 2.6.27-rc6
+# Tue Sep 16 18:56:58 2008
 #
 CONFIG_ARM=y
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+CONFIG_GENERIC_GPIO=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CLOCKEVENTS=y
 CONFIG_MMU=y
-CONFIG_UID16=y
+# CONFIG_NO_IOPORT is not set
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_GENERIC_IRQ_PROBE=y
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_GENERIC_HWEIGHT=y
 CONFIG_GENERIC_CALIBRATE_DELAY=y
-CONFIG_GENERIC_IOMAP=y
-
-#
-# Code maturity level options
-#
-CONFIG_EXPERIMENTAL=y
-CONFIG_CLEAN_COMPILE=y
-CONFIG_BROKEN_ON_SMP=y
+CONFIG_ARCH_SUPPORTS_AOUT=y
+CONFIG_ZONE_DMA=y
+CONFIG_ARCH_MTD_XIP=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
+CONFIG_VECTORS_BASE=0xffff0000
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
 
 #
 # General setup
 #
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
 CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
 CONFIG_SWAP=y
 CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
 # CONFIG_POSIX_MQUEUE is not set
 # CONFIG_BSD_PROCESS_ACCT is not set
-CONFIG_SYSCTL=y
+# CONFIG_TASKSTATS is not set
 # CONFIG_AUDIT is not set
-CONFIG_HOTPLUG=y
-CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_CGROUPS is not set
+# CONFIG_GROUP_SCHED is not set
+CONFIG_SYSFS_DEPRECATED=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+# CONFIG_RELAY is not set
+CONFIG_NAMESPACES=y
+# CONFIG_UTS_NS is not set
+# CONFIG_IPC_NS is not set
+# CONFIG_USER_NS is not set
+# CONFIG_PID_NS is not set
+# CONFIG_BLK_DEV_INITRD is not set
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
 # CONFIG_EMBEDDED is not set
+CONFIG_UID16=y
+CONFIG_SYSCTL_SYSCALL=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_ALL is not set
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_COMPAT_BRK=y
 CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
+CONFIG_ANON_INODES=y
 CONFIG_EPOLL=y
-CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
 CONFIG_SHMEM=y
-CONFIG_CC_ALIGN_FUNCTIONS=0
-CONFIG_CC_ALIGN_LABELS=0
-CONFIG_CC_ALIGN_LOOPS=0
-CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_SLUB_DEBUG=y
+# CONFIG_SLAB is not set
+CONFIG_SLUB=y
+# CONFIG_SLOB is not set
+# CONFIG_PROFILING is not set
+# CONFIG_MARKERS is not set
+CONFIG_HAVE_OPROFILE=y
+# CONFIG_KPROBES is not set
+# CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS is not set
+# CONFIG_HAVE_IOREMAP_PROT is not set
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+# CONFIG_HAVE_ARCH_TRACEHOOK is not set
+# CONFIG_HAVE_DMA_ATTRS is not set
+# CONFIG_USE_GENERIC_SMP_HELPERS is not set
+CONFIG_HAVE_CLK=y
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_HAVE_GENERIC_DMA_COHERENT=y
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
-
-#
-# Loadable module support
-#
 CONFIG_MODULES=y
+# CONFIG_MODULE_FORCE_LOAD is not set
 # CONFIG_MODULE_UNLOAD is not set
-CONFIG_OBSOLETE_MODPARM=y
 # CONFIG_MODVERSIONS is not set
 # CONFIG_MODULE_SRCVERSION_ALL is not set
 CONFIG_KMOD=y
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_BLK_DEV_INTEGRITY is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_DEFAULT_AS is not set
+# CONFIG_DEFAULT_DEADLINE is not set
+CONFIG_DEFAULT_CFQ=y
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="cfq"
+CONFIG_CLASSIC_RCU=y
 
 #
 # System Type
 #
+# CONFIG_ARCH_AAEC2000 is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_REALVIEW is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_AT91 is not set
 # CONFIG_ARCH_CLPS7500 is not set
 # CONFIG_ARCH_CLPS711X is not set
-# CONFIG_ARCH_CO285 is not set
 # CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_EP93XX is not set
 # CONFIG_ARCH_FOOTBRIDGE is not set
-# CONFIG_ARCH_INTEGRATOR is not set
-# CONFIG_ARCH_IOP3XX is not set
-# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_NETX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_IOP13XX is not set
+# CONFIG_ARCH_IOP32X is not set
+# CONFIG_ARCH_IOP33X is not set
+# CONFIG_ARCH_IXP23XX is not set
 # CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_IXP4XX is not set
 # CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_KIRKWOOD is not set
+# CONFIG_ARCH_KS8695 is not set
+# CONFIG_ARCH_NS9XXX is not set
+# CONFIG_ARCH_LOKI is not set
+# CONFIG_ARCH_MV78XX0 is not set
+# CONFIG_ARCH_MXC is not set
+# CONFIG_ARCH_ORION5X is not set
+# CONFIG_ARCH_PNX4008 is not set
 # CONFIG_ARCH_PXA is not set
 # CONFIG_ARCH_RPC is not set
 CONFIG_ARCH_SA1100=y
 # CONFIG_ARCH_S3C2410 is not set
 # CONFIG_ARCH_SHARK is not set
 # CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_DAVINCI is not set
 # CONFIG_ARCH_OMAP is not set
-# CONFIG_ARCH_VERSATILE is not set
-# CONFIG_ARCH_IMX is not set
-# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_MSM7X00A is not set
+CONFIG_DMABOUNCE=y
 
 #
 # SA11x0 Implementations
@@ -91,12 +181,21 @@
 # CONFIG_SA1100_H3800 is not set
 # CONFIG_SA1100_BADGE4 is not set
 CONFIG_SA1100_JORNADA720=y
+CONFIG_SA1100_JORNADA720_SSP=y
 # CONFIG_SA1100_HACKKIT is not set
 # CONFIG_SA1100_LART is not set
 # CONFIG_SA1100_PLEB is not set
 # CONFIG_SA1100_SHANNON is not set
 # CONFIG_SA1100_SIMPAD is not set
-# CONFIG_SA1100_SSP is not set
+CONFIG_SA1100_SSP=y
+
+#
+# Boot options
+#
+
+#
+# Power management
+#
 
 #
 # Processor Type
@@ -105,44 +204,71 @@
 CONFIG_CPU_SA1100=y
 CONFIG_CPU_32v4=y
 CONFIG_CPU_ABRT_EV4=y
+CONFIG_CPU_PABRT_NOIFAR=y
 CONFIG_CPU_CACHE_V4WB=y
 CONFIG_CPU_CACHE_VIVT=y
 CONFIG_CPU_TLB_V4WB=y
-CONFIG_CPU_MINICACHE=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
 
 #
 # Processor Features
 #
+# CONFIG_CPU_ICACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_OUTER_CACHE is not set
 CONFIG_SA1111=y
-CONFIG_DMABOUNCE=y
 CONFIG_FORCE_MAX_ZONEORDER=9
 
 #
 # Bus support
 #
 CONFIG_ISA=y
-
-#
-# PCCARD (PCMCIA/CardBus) support
-#
+# CONFIG_PCI_SYSCALL is not set
+# CONFIG_ARCH_SUPPORTS_MSI is not set
 CONFIG_PCCARD=y
 # CONFIG_PCMCIA_DEBUG is not set
 CONFIG_PCMCIA=y
+CONFIG_PCMCIA_LOAD_CIS=y
+CONFIG_PCMCIA_IOCTL=y
 
 #
 # PC-card bridges
 #
-CONFIG_I82365=y
+# CONFIG_I82365 is not set
 # CONFIG_TCIC is not set
 CONFIG_PCMCIA_SA1100=y
 # CONFIG_PCMCIA_SA1111 is not set
-CONFIG_PCCARD_NONSTATIC=y
 
 #
 # Kernel Features
 #
+CONFIG_TICK_ONESHOT=y
+# CONFIG_NO_HZ is not set
+# CONFIG_HIGH_RES_TIMERS is not set
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
 # CONFIG_PREEMPT is not set
+CONFIG_HZ=100
+# CONFIG_AEABI is not set
+CONFIG_ARCH_DISCONTIGMEM_ENABLE=y
+CONFIG_ARCH_SPARSEMEM_ENABLE=y
+CONFIG_ARCH_SELECT_MEMORY_MODEL=y
+CONFIG_NODES_SHIFT=2
+CONFIG_SELECT_MEMORY_MODEL=y
+# CONFIG_FLATMEM_MANUAL is not set
+CONFIG_DISCONTIGMEM_MANUAL=y
+# CONFIG_SPARSEMEM_MANUAL is not set
 CONFIG_DISCONTIGMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+CONFIG_NEED_MULTIPLE_NODES=y
+# CONFIG_SPARSEMEM_STATIC is not set
+# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set
+CONFIG_PAGEFLAGS_EXTENDED=y
+CONFIG_SPLIT_PTLOCK_CPUS=4096
+# CONFIG_RESOURCES_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=1
+CONFIG_BOUNCE=y
+CONFIG_VIRT_TO_BUS=y
 # CONFIG_LEDS is not set
 CONFIG_ALIGNMENT_TRAP=y
 
@@ -151,8 +277,9 @@
 #
 CONFIG_ZBOOT_ROM_TEXT=0x0
 CONFIG_ZBOOT_ROM_BSS=0x0
-CONFIG_CMDLINE="keepinitrd mem=32M"
+CONFIG_CMDLINE=""
 # CONFIG_XIP_KERNEL is not set
+# CONFIG_KEXEC is not set
 
 #
 # CPU Frequency scaling
@@ -174,7 +301,7 @@
 # Userspace binary formats
 #
 CONFIG_BINFMT_ELF=y
-CONFIG_BINFMT_AOUT=m
+CONFIG_BINFMT_AOUT=y
 # CONFIG_BINFMT_MISC is not set
 # CONFIG_ARTHUR is not set
 
@@ -182,188 +309,12 @@
 # Power management options
 #
 CONFIG_PM=y
-# CONFIG_PM_LEGACY is not set
-# CONFIG_APM is not set
-
-#
-# Device Drivers
-#
-
-#
-# Generic Driver Options
-#
-CONFIG_STANDALONE=y
-CONFIG_PREVENT_FIRMWARE_BUILD=y
-# CONFIG_FW_LOADER is not set
-# CONFIG_DEBUG_DRIVER is not set
-
-#
-# Memory Technology Devices (MTD)
-#
-CONFIG_MTD=y
-CONFIG_MTD_DEBUG=y
-CONFIG_MTD_DEBUG_VERBOSE=1
-# CONFIG_MTD_CONCAT is not set
-CONFIG_MTD_PARTITIONS=y
-# CONFIG_MTD_REDBOOT_PARTS is not set
-# CONFIG_MTD_CMDLINE_PARTS is not set
-# CONFIG_MTD_AFS_PARTS is not set
-
-#
-# User Modules And Translation Layers
-#
-CONFIG_MTD_CHAR=m
-CONFIG_MTD_BLOCK=y
-# CONFIG_FTL is not set
-# CONFIG_NFTL is not set
-# CONFIG_INFTL is not set
-
-#
-# RAM/ROM/Flash chip drivers
-#
-CONFIG_MTD_CFI=y
-# CONFIG_MTD_JEDECPROBE is not set
-CONFIG_MTD_GEN_PROBE=y
-CONFIG_MTD_CFI_ADV_OPTIONS=y
-CONFIG_MTD_CFI_NOSWAP=y
-# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set
-# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set
-CONFIG_MTD_CFI_GEOMETRY=y
-CONFIG_MTD_MAP_BANK_WIDTH_1=y
-CONFIG_MTD_MAP_BANK_WIDTH_2=y
-CONFIG_MTD_MAP_BANK_WIDTH_4=y
-# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
-# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
-# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
-CONFIG_MTD_CFI_I1=y
-CONFIG_MTD_CFI_I2=y
-# CONFIG_MTD_CFI_I4 is not set
-# CONFIG_MTD_CFI_I8 is not set
-CONFIG_MTD_CFI_INTELEXT=y
-# CONFIG_MTD_CFI_AMDSTD is not set
-# CONFIG_MTD_CFI_STAA is not set
-CONFIG_MTD_CFI_UTIL=y
-# CONFIG_MTD_RAM is not set
-# CONFIG_MTD_ROM is not set
-# CONFIG_MTD_ABSENT is not set
-# CONFIG_MTD_XIP is not set
-
-#
-# Mapping drivers for chip access
-#
-# CONFIG_MTD_COMPLEX_MAPPINGS is not set
-# CONFIG_MTD_PHYSMAP is not set
-# CONFIG_MTD_ARM_INTEGRATOR is not set
-CONFIG_MTD_SA1100=y
-# CONFIG_MTD_EDB7312 is not set
-
-#
-# Self-contained MTD device drivers
-#
-# CONFIG_MTD_SLRAM is not set
-# CONFIG_MTD_PHRAM is not set
-# CONFIG_MTD_MTDRAM is not set
-# CONFIG_MTD_BLKMTD is not set
-# CONFIG_MTD_BLOCK2MTD is not set
-
-#
-# Disk-On-Chip Device Drivers
-#
-# CONFIG_MTD_DOC2000 is not set
-# CONFIG_MTD_DOC2001 is not set
-# CONFIG_MTD_DOC2001PLUS is not set
-
-#
-# NAND Flash Device Drivers
-#
-# CONFIG_MTD_NAND is not set
-
-#
-# Parallel port support
-#
-# CONFIG_PARPORT is not set
-
-#
-# Plug and Play support
-#
-# CONFIG_PNP is not set
-
-#
-# Block devices
-#
-# CONFIG_BLK_DEV_FD is not set
-# CONFIG_BLK_DEV_XD is not set
-# CONFIG_BLK_DEV_COW_COMMON is not set
-CONFIG_BLK_DEV_LOOP=m
-# CONFIG_BLK_DEV_CRYPTOLOOP is not set
-CONFIG_BLK_DEV_NBD=m
-# CONFIG_BLK_DEV_RAM is not set
-CONFIG_BLK_DEV_RAM_COUNT=16
-CONFIG_INITRAMFS_SOURCE=""
-# CONFIG_CDROM_PKTCDVD is not set
-
-#
-# IO Schedulers
-#
-CONFIG_IOSCHED_NOOP=y
-CONFIG_IOSCHED_AS=y
-CONFIG_IOSCHED_DEADLINE=y
-CONFIG_IOSCHED_CFQ=y
-# CONFIG_ATA_OVER_ETH is not set
-
-#
-# ATA/ATAPI/MFM/RLL support
-#
-CONFIG_IDE=m
-CONFIG_BLK_DEV_IDE=m
-
-#
-# Please see Documentation/ide.txt for help/info on IDE drives
-#
-# CONFIG_BLK_DEV_IDE_SATA is not set
-CONFIG_BLK_DEV_IDEDISK=m
-# CONFIG_IDEDISK_MULTI_MODE is not set
-# CONFIG_BLK_DEV_IDECS is not set
-CONFIG_BLK_DEV_IDECD=m
-# CONFIG_BLK_DEV_IDETAPE is not set
-# CONFIG_BLK_DEV_IDEFLOPPY is not set
-# CONFIG_IDE_TASK_IOCTL is not set
-
-#
-# IDE chipset support/bugfixes
-#
-CONFIG_IDE_GENERIC=m
-# CONFIG_IDE_ARM is not set
-# CONFIG_IDE_CHIPSETS is not set
-# CONFIG_BLK_DEV_IDEDMA is not set
-# CONFIG_IDEDMA_AUTO is not set
-# CONFIG_BLK_DEV_HD is not set
-
-#
-# SCSI device support
-#
-# CONFIG_SCSI is not set
-
-#
-# Multi-device support (RAID and LVM)
-#
-# CONFIG_MD is not set
-
-#
-# Fusion MPT device support
-#
-
-#
-# IEEE 1394 (FireWire) support
-#
-
-#
-# I2O device support
-#
-
-#
-# Networking support
-#
+# CONFIG_PM_DEBUG is not set
+CONFIG_PM_SLEEP=y
+CONFIG_SUSPEND=y
+CONFIG_SUSPEND_FREEZER=y
+# CONFIG_APM_EMULATION is not set
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
 CONFIG_NET=y
 
 #
@@ -371,12 +322,17 @@
 #
 CONFIG_PACKET=y
 CONFIG_PACKET_MMAP=y
-# CONFIG_NETLINK_DEV is not set
 CONFIG_UNIX=y
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
+# CONFIG_XFRM_STATISTICS 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 is not set
 # CONFIG_NET_IPIP is not set
 # CONFIG_NET_IPGRE is not set
@@ -386,31 +342,42 @@
 # 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_IP_TCPDIAG is not set
-# CONFIG_IP_TCPDIAG_IPV6 is not set
-
-#
-# IP: Virtual Server Configuration
-#
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+# CONFIG_INET_LRO is not set
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
 # CONFIG_IP_VS is not set
 # CONFIG_IPV6 is not set
+# CONFIG_NETWORK_SECMARK is not set
 CONFIG_NETFILTER=y
 # CONFIG_NETFILTER_DEBUG is not set
+CONFIG_NETFILTER_ADVANCED=y
+
+#
+# Core Netfilter Configuration
+#
+# CONFIG_NETFILTER_NETLINK_QUEUE is not set
+# CONFIG_NETFILTER_NETLINK_LOG is not set
+# CONFIG_NF_CONNTRACK is not set
+# CONFIG_NETFILTER_XTABLES is not set
 
 #
 # IP: Netfilter Configuration
 #
-# CONFIG_IP_NF_CONNTRACK is not set
-# CONFIG_IP_NF_CONNTRACK_MARK is not set
 # CONFIG_IP_NF_QUEUE is not set
 # CONFIG_IP_NF_IPTABLES is not set
 # CONFIG_IP_NF_ARPTABLES is not set
-
-#
-# SCTP Configuration (EXPERIMENTAL)
-#
+# CONFIG_IP_DCCP is not set
 # CONFIG_IP_SCTP is not set
+# CONFIG_TIPC is not set
 # CONFIG_ATM is not set
 # CONFIG_BRIDGE is not set
 # CONFIG_VLAN_8021Q is not set
@@ -420,30 +387,22 @@
 # CONFIG_ATALK is not set
 # CONFIG_X25 is not set
 # CONFIG_LAPB is not set
-# CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
-
-#
-# QoS and/or fair queueing
-#
 # CONFIG_NET_SCHED is not set
-# CONFIG_NET_CLS_ROUTE is not set
 
 #
 # Network testing
 #
 # CONFIG_NET_PKTGEN is not set
-# CONFIG_NETPOLL is not set
-# CONFIG_NET_POLL_CONTROLLER is not set
 # CONFIG_HAMRADIO is not set
+# CONFIG_CAN is not set
 CONFIG_IRDA=m
 
 #
 # IrDA protocols
 #
 CONFIG_IRLAN=m
-# CONFIG_IRNET is not set
 CONFIG_IRCOMM=m
 # CONFIG_IRDA_ULTRA is not set
 
@@ -468,89 +427,105 @@
 #
 
 #
-# Old SIR device drivers
-#
-# CONFIG_IRPORT_SIR is not set
-
-#
-# Old Serial dongle support
-#
-
-#
 # FIR device drivers
 #
-# CONFIG_NSC_FIR is not set
-# CONFIG_WINBOND_FIR is not set
-# CONFIG_SMC_IRCC_FIR is not set
-# CONFIG_ALI_FIR is not set
 CONFIG_SA1100_FIR=m
 # CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+
+#
+# Wireless
+#
+# CONFIG_CFG80211 is not set
+# CONFIG_WIRELESS_EXT is not set
+# CONFIG_MAC80211 is not set
+# CONFIG_IEEE80211 is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=y
+CONFIG_FIRMWARE_IN_KERNEL=y
+CONFIG_EXTRA_FIRMWARE=""
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_CONNECTOR is not set
+# CONFIG_MTD is not set
+# CONFIG_PARPORT is not set
+# CONFIG_PNP is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=m
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+CONFIG_BLK_DEV_NBD=m
+# CONFIG_BLK_DEV_RAM is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+CONFIG_MISC_DEVICES=y
+# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_ENCLOSURE_SERVICES is not set
+CONFIG_HAVE_IDE=y
+CONFIG_IDE=y
+CONFIG_BLK_DEV_IDE=y
+
+#
+# Please see Documentation/ide/ide.txt for help/info on IDE drives
+#
+# CONFIG_BLK_DEV_IDE_SATA is not set
+CONFIG_BLK_DEV_IDEDISK=y
+# CONFIG_IDEDISK_MULTI_MODE is not set
+CONFIG_BLK_DEV_IDECS=y
+# CONFIG_BLK_DEV_IDECD is not set
+# CONFIG_BLK_DEV_IDETAPE is not set
+# CONFIG_BLK_DEV_IDEFLOPPY is not set
+# CONFIG_IDE_TASK_IOCTL is not set
+CONFIG_IDE_PROC_FS=y
+
+#
+# IDE chipset support/bugfixes
+#
+# CONFIG_BLK_DEV_PLATFORM is not set
+# CONFIG_BLK_DEV_IDEDMA is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+# CONFIG_SCSI is not set
+# CONFIG_SCSI_DMA is not set
+# CONFIG_SCSI_NETLINK is not set
+# CONFIG_ATA is not set
+# CONFIG_MD is not set
 CONFIG_NETDEVICES=y
-# CONFIG_DUMMY is not set
+CONFIG_DUMMY=y
 # CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
 # CONFIG_EQUALIZER is not set
 # CONFIG_TUN is not set
-
-#
-# ARCnet devices
-#
+# CONFIG_VETH is not set
 # CONFIG_ARCNET is not set
-
-#
-# Ethernet (10 or 100Mbit)
-#
 # CONFIG_NET_ETHERNET is not set
 CONFIG_MII=m
-
-#
-# Ethernet (1000 Mbit)
-#
-
-#
-# Ethernet (10000 Mbit)
-#
-
-#
-# Token Ring devices
-#
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
 # CONFIG_TR is not set
 
 #
-# Wireless LAN (non-hamradio)
+# Wireless LAN
 #
-CONFIG_NET_RADIO=y
-
-#
-# Obsolete Wireless cards support (pre-802.11)
-#
-# CONFIG_STRIP is not set
-CONFIG_ARLAN=m
-CONFIG_WAVELAN=m
-CONFIG_PCMCIA_WAVELAN=m
-# CONFIG_PCMCIA_NETWAVE is not set
-
-#
-# Wireless 802.11 Frequency Hopping cards support
-#
-# CONFIG_PCMCIA_RAYCS is not set
-
-#
-# Wireless 802.11b ISA/PCI cards support
-#
-CONFIG_HERMES=m
-# CONFIG_ATMEL is not set
-
-#
-# Wireless 802.11b Pcmcia/Cardbus cards support
-#
-CONFIG_PCMCIA_HERMES=m
-CONFIG_AIRO_CS=m
-# CONFIG_PCMCIA_WL3501 is not set
-CONFIG_NET_WIRELESS=y
-
-#
-# PCMCIA network device support
-#
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
+# CONFIG_IWLWIFI_LEDS is not set
 CONFIG_NET_PCMCIA=y
 CONFIG_PCMCIA_3C589=m
 CONFIG_PCMCIA_3C574=m
@@ -560,32 +535,20 @@
 CONFIG_PCMCIA_SMC91C92=m
 CONFIG_PCMCIA_XIRC2PS=m
 CONFIG_PCMCIA_AXNET=m
-
-#
-# Wan interfaces
-#
 # CONFIG_WAN is not set
-CONFIG_PPP=m
-# CONFIG_PPP_MULTILINK is not set
-# CONFIG_PPP_FILTER is not set
-CONFIG_PPP_ASYNC=m
-# CONFIG_PPP_SYNC_TTY is not set
-CONFIG_PPP_DEFLATE=m
-CONFIG_PPP_BSDCOMP=m
-# CONFIG_PPPOE is not set
+# CONFIG_PPP is not set
 # CONFIG_SLIP is not set
-# CONFIG_SHAPER is not set
 # CONFIG_NETCONSOLE is not set
-
-#
-# ISDN subsystem
-#
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
 # CONFIG_ISDN is not set
 
 #
 # Input device support
 #
 CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
 
 #
 # Userland interfaces
@@ -595,7 +558,6 @@
 CONFIG_INPUT_MOUSEDEV_SCREEN_X=640
 CONFIG_INPUT_MOUSEDEV_SCREEN_Y=240
 # CONFIG_INPUT_JOYDEV is not set
-# CONFIG_INPUT_TSDEV is not set
 # CONFIG_INPUT_EVDEV is not set
 # CONFIG_INPUT_EVBUG is not set
 
@@ -603,20 +565,31 @@
 # Input Device Drivers
 #
 CONFIG_INPUT_KEYBOARD=y
-CONFIG_KEYBOARD_ATKBD=y
+# CONFIG_KEYBOARD_ATKBD is not set
 # CONFIG_KEYBOARD_SUNKBD is not set
 # CONFIG_KEYBOARD_LKKBD is not set
 # CONFIG_KEYBOARD_XTKBD is not set
 # CONFIG_KEYBOARD_NEWTON is not set
-CONFIG_INPUT_MOUSE=y
-CONFIG_MOUSE_PS2=y
-# CONFIG_MOUSE_SERIAL is not set
-# CONFIG_MOUSE_INPORT is not set
-# CONFIG_MOUSE_LOGIBM is not set
-# CONFIG_MOUSE_PC110PAD is not set
-# CONFIG_MOUSE_VSXXXAA is not set
+# CONFIG_KEYBOARD_STOWAWAY is not set
+CONFIG_KEYBOARD_HP7XX=y
+# CONFIG_KEYBOARD_GPIO is not set
+# CONFIG_INPUT_MOUSE is not set
 # CONFIG_INPUT_JOYSTICK is not set
-# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_TABLET is not set
+CONFIG_INPUT_TOUCHSCREEN=y
+# CONFIG_TOUCHSCREEN_FUJITSU is not set
+# CONFIG_TOUCHSCREEN_GUNZE is not set
+# CONFIG_TOUCHSCREEN_ELO is not set
+# CONFIG_TOUCHSCREEN_MTOUCH is not set
+# CONFIG_TOUCHSCREEN_INEXIO is not set
+# CONFIG_TOUCHSCREEN_MK712 is not set
+CONFIG_TOUCHSCREEN_HP7XX=y
+# CONFIG_TOUCHSCREEN_HTCPEN is not set
+# CONFIG_TOUCHSCREEN_PENMOUNT is not set
+# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set
+# CONFIG_TOUCHSCREEN_TOUCHWIN is not set
+# CONFIG_TOUCHSCREEN_UCB1400 is not set
+# CONFIG_TOUCHSCREEN_TOUCHIT213 is not set
 # CONFIG_INPUT_MISC is not set
 
 #
@@ -625,17 +598,18 @@
 CONFIG_SERIO=y
 CONFIG_SERIO_SERPORT=y
 # CONFIG_SERIO_SA1111 is not set
-CONFIG_SERIO_LIBPS2=y
 # CONFIG_SERIO_RAW is not set
 # CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
 
 #
 # Character devices
 #
 CONFIG_VT=y
+CONFIG_CONSOLE_TRANSLATIONS=y
 CONFIG_VT_CONSOLE=y
 CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
+CONFIG_DEVKMEM=y
 # CONFIG_SERIAL_NONSTANDARD is not set
 
 #
@@ -652,69 +626,120 @@
 CONFIG_SERIAL_CORE_CONSOLE=y
 CONFIG_UNIX98_PTYS=y
 CONFIG_LEGACY_PTYS=y
-CONFIG_LEGACY_PTY_COUNT=256
-
-#
-# IPMI
-#
+CONFIG_LEGACY_PTY_COUNT=32
 # CONFIG_IPMI_HANDLER is not set
-
-#
-# Watchdog Cards
-#
-# CONFIG_WATCHDOG is not set
+CONFIG_HW_RANDOM=m
 # CONFIG_NVRAM is not set
-# CONFIG_RTC is not set
 # CONFIG_DTLK is not set
 # CONFIG_R3964 is not set
 
 #
-# Ftape, the floppy tape device driver
-#
-# CONFIG_DRM is not set
-
-#
 # PCMCIA character devices
 #
 # CONFIG_SYNCLINK_CS is not set
+# CONFIG_CARDMAN_4000 is not set
+# CONFIG_CARDMAN_4040 is not set
+# CONFIG_IPWIRELESS is not set
 # CONFIG_RAW_DRIVER is not set
-
-#
-# TPM devices
-#
 # CONFIG_TCG_TPM is not set
-
-#
-# I2C support
-#
+CONFIG_DEVPORT=y
 # CONFIG_I2C is not set
+# CONFIG_SPI is not set
+CONFIG_ARCH_REQUIRE_GPIOLIB=y
+CONFIG_GPIOLIB=y
+# CONFIG_DEBUG_GPIO is not set
+# CONFIG_GPIO_SYSFS is not set
 
 #
-# Misc devices
+# I2C GPIO expanders:
 #
 
 #
+# PCI GPIO expanders:
+#
+
+#
+# SPI GPIO expanders:
+#
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+# CONFIG_HWMON is not set
+# CONFIG_WATCHDOG is not set
+
+#
+# Sonics Silicon Backplane
+#
+CONFIG_SSB_POSSIBLE=y
+# CONFIG_SSB is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_CORE is not set
+# CONFIG_MFD_SM501 is not set
+# CONFIG_HTC_EGPIO is not set
+# CONFIG_HTC_PASIC3 is not set
+# CONFIG_MFD_TMIO is not set
+# CONFIG_MFD_T7L66XB is not set
+# CONFIG_MFD_TC6387XB is not set
+# CONFIG_MFD_TC6393XB is not set
+
+#
+# Multimedia Capabilities Port drivers
+#
+# CONFIG_MCP_SA11X0 is not set
+
+#
 # Multimedia devices
 #
-# CONFIG_VIDEO_DEV is not set
 
 #
-# Digital Video Broadcasting Devices
+# Multimedia core support
 #
-# CONFIG_DVB is not set
+# CONFIG_VIDEO_DEV is not set
+# CONFIG_DVB_CORE is not set
+# CONFIG_VIDEO_MEDIA is not set
+
+#
+# Multimedia drivers
+#
+# CONFIG_DAB is not set
 
 #
 # Graphics support
 #
+# CONFIG_VGASTATE is not set
+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
 CONFIG_FB=y
-# CONFIG_FB_CFB_FILLRECT is not set
-# CONFIG_FB_CFB_COPYAREA is not set
-# CONFIG_FB_CFB_IMAGEBLIT is not set
-# CONFIG_FB_SOFT_CURSOR is not set
+# CONFIG_FIRMWARE_EDID is not set
+# CONFIG_FB_DDC is not set
+CONFIG_FB_CFB_FILLRECT=y
+CONFIG_FB_CFB_COPYAREA=y
+CONFIG_FB_CFB_IMAGEBLIT=y
+# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
+# CONFIG_FB_SYS_FILLRECT is not set
+# CONFIG_FB_SYS_COPYAREA is not set
+# CONFIG_FB_SYS_IMAGEBLIT is not set
+# CONFIG_FB_FOREIGN_ENDIAN is not set
+# CONFIG_FB_SYS_FOPS is not set
+# CONFIG_FB_SVGALIB is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
 # CONFIG_FB_MODE_HELPERS is not set
 # CONFIG_FB_TILEBLITTING is not set
+
+#
+# Frame buffer hardware drivers
+#
 # CONFIG_FB_SA1100 is not set
+CONFIG_FB_S1D13XXX=y
 # CONFIG_FB_VIRTUAL is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
 
 #
 # Console display driver support
@@ -722,94 +747,110 @@
 # CONFIG_VGA_CONSOLE is not set
 # CONFIG_MDA_CONSOLE is not set
 CONFIG_DUMMY_CONSOLE=y
-# CONFIG_FRAMEBUFFER_CONSOLE is not set
-
-#
-# Logo configuration
-#
+CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y
+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
+# CONFIG_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
 # CONFIG_LOGO is not set
-# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
-
-#
-# Sound
-#
-CONFIG_SOUND=m
-
-#
-# Advanced Linux Sound Architecture
-#
-# CONFIG_SND is not set
-
-#
-# Open Sound System
-#
-# CONFIG_SOUND_PRIME is not set
-
-#
-# USB support
-#
-CONFIG_USB_ARCH_HAS_HCD=y
-CONFIG_USB_ARCH_HAS_OHCI=y
-# CONFIG_USB is not set
-
-#
-# USB Gadget Support
-#
-# CONFIG_USB_GADGET is not set
-
-#
-# MMC/SD Card support
-#
+# CONFIG_SOUND is not set
+# CONFIG_HID_SUPPORT is not set
+# CONFIG_USB_SUPPORT is not set
 # CONFIG_MMC is not set
+# CONFIG_NEW_LEDS is not set
+CONFIG_RTC_LIB=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+# CONFIG_RTC_DEBUG is not set
+
+#
+# RTC interfaces
+#
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_DEV=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+# CONFIG_RTC_DRV_TEST is not set
+
+#
+# SPI RTC drivers
+#
+
+#
+# Platform RTC drivers
+#
+# CONFIG_RTC_DRV_CMOS is not set
+# CONFIG_RTC_DRV_DS1511 is not set
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_STK17TA8 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_M48T59 is not set
+# CONFIG_RTC_DRV_V3020 is not set
+
+#
+# on-CPU RTC drivers
+#
+CONFIG_RTC_DRV_SA1100=y
+# CONFIG_DMADEVICES is not set
+
+#
+# Voltage and Current regulators
+#
+# CONFIG_REGULATOR is not set
+# CONFIG_REGULATOR_FIXED_VOLTAGE is not set
+# CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set
+# CONFIG_REGULATOR_BQ24022 is not set
+# CONFIG_UIO is not set
 
 #
 # File systems
 #
 CONFIG_EXT2_FS=y
 # CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
 # CONFIG_EXT3_FS is not set
-# CONFIG_JBD is not set
+# CONFIG_EXT4DEV_FS is not set
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
-
-#
-# XFS support
-#
+# CONFIG_FS_POSIX_ACL is not set
 # CONFIG_XFS_FS is not set
-# CONFIG_MINIX_FS is not set
-# CONFIG_ROMFS_FS is not set
-# CONFIG_QUOTA is not set
+# CONFIG_OCFS2_FS is not set
 CONFIG_DNOTIFY=y
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
 # 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=m
-# CONFIG_JOLIET is not set
-# CONFIG_ZISOFS is not set
+# 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_FAT_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
 # CONFIG_NTFS_FS is not set
 
 #
 # Pseudo filesystems
 #
 CONFIG_PROC_FS=y
+CONFIG_PROC_SYSCTL=y
 CONFIG_SYSFS=y
-CONFIG_DEVFS_FS=y
-CONFIG_DEVFS_MOUNT=y
-CONFIG_DEVFS_DEBUG=y
-# CONFIG_DEVPTS_FS_XATTR is not set
 # CONFIG_TMPFS is not set
 # CONFIG_HUGETLB_PAGE is not set
-CONFIG_RAMFS=y
+# CONFIG_CONFIGFS_FS is not set
 
 #
 # Miscellaneous filesystems
@@ -821,75 +862,122 @@
 # CONFIG_BEFS_FS is not set
 # CONFIG_BFS_FS is not set
 # CONFIG_EFS_FS is not set
-# CONFIG_JFFS_FS is not set
-CONFIG_JFFS2_FS=y
-CONFIG_JFFS2_FS_DEBUG=2
-# CONFIG_JFFS2_FS_NAND is not set
-# CONFIG_JFFS2_FS_NOR_ECC is not set
-# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
-CONFIG_JFFS2_ZLIB=y
-CONFIG_JFFS2_RTIME=y
-# CONFIG_JFFS2_RUBIN is not set
 # CONFIG_CRAMFS is not set
 # CONFIG_VXFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_OMFS_FS is not set
 # CONFIG_HPFS_FS is not set
 # CONFIG_QNX4FS_FS is not set
+# CONFIG_ROMFS_FS is not set
 # CONFIG_SYSV_FS is not set
 # CONFIG_UFS_FS is not set
-
-#
-# Network File Systems
-#
-CONFIG_NFS_FS=m
-CONFIG_NFS_V3=y
-# CONFIG_NFS_V4 is not set
-# CONFIG_NFS_DIRECTIO is not set
-# CONFIG_NFSD is not set
-CONFIG_LOCKD=m
-CONFIG_LOCKD_V4=y
-CONFIG_SUNRPC=m
-# CONFIG_RPCSEC_GSS_KRB5 is not set
-# 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_NETWORK_FILESYSTEMS is not set
 
 #
 # Partition Types
 #
 # CONFIG_PARTITION_ADVANCED is not set
 CONFIG_MSDOS_PARTITION=y
-
-#
-# Native Language Support
-#
-# CONFIG_NLS is not set
-
-#
-# Profiling support
-#
-# CONFIG_PROFILING is not set
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=m
+CONFIG_NLS_CODEPAGE_737=m
+CONFIG_NLS_CODEPAGE_775=m
+CONFIG_NLS_CODEPAGE_850=m
+CONFIG_NLS_CODEPAGE_852=m
+CONFIG_NLS_CODEPAGE_855=m
+CONFIG_NLS_CODEPAGE_857=m
+CONFIG_NLS_CODEPAGE_860=m
+CONFIG_NLS_CODEPAGE_861=m
+CONFIG_NLS_CODEPAGE_862=m
+CONFIG_NLS_CODEPAGE_863=m
+CONFIG_NLS_CODEPAGE_864=m
+CONFIG_NLS_CODEPAGE_865=m
+CONFIG_NLS_CODEPAGE_866=m
+CONFIG_NLS_CODEPAGE_869=m
+CONFIG_NLS_CODEPAGE_936=m
+CONFIG_NLS_CODEPAGE_950=m
+CONFIG_NLS_CODEPAGE_932=m
+CONFIG_NLS_CODEPAGE_949=m
+CONFIG_NLS_CODEPAGE_874=m
+CONFIG_NLS_ISO8859_8=m
+CONFIG_NLS_CODEPAGE_1250=m
+CONFIG_NLS_CODEPAGE_1251=m
+CONFIG_NLS_ASCII=m
+CONFIG_NLS_ISO8859_1=m
+CONFIG_NLS_ISO8859_2=m
+CONFIG_NLS_ISO8859_3=m
+CONFIG_NLS_ISO8859_4=m
+CONFIG_NLS_ISO8859_5=m
+CONFIG_NLS_ISO8859_6=m
+CONFIG_NLS_ISO8859_7=m
+CONFIG_NLS_ISO8859_9=m
+CONFIG_NLS_ISO8859_13=m
+CONFIG_NLS_ISO8859_14=m
+CONFIG_NLS_ISO8859_15=m
+CONFIG_NLS_KOI8_R=m
+CONFIG_NLS_KOI8_U=m
+CONFIG_NLS_UTF8=m
+# CONFIG_DLM is not set
 
 #
 # Kernel hacking
 #
 # CONFIG_PRINTK_TIME is not set
-CONFIG_DEBUG_KERNEL=y
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_FRAME_WARN=1024
 # CONFIG_MAGIC_SYSRQ is not set
-CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
+CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set
+CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0
+CONFIG_SCHED_DEBUG=y
 # CONFIG_SCHEDSTATS is not set
-CONFIG_DEBUG_SLAB=y
+# CONFIG_TIMER_STATS is not set
+# CONFIG_DEBUG_OBJECTS is not set
+# CONFIG_SLUB_DEBUG_ON is not set
+# CONFIG_SLUB_STATS is not set
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
 # CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
 # CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
 # CONFIG_DEBUG_KOBJECT is not set
 CONFIG_DEBUG_BUGVERBOSE=y
 # CONFIG_DEBUG_INFO is not set
-# CONFIG_DEBUG_FS is not set
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_WRITECOUNT is not set
+CONFIG_DEBUG_MEMORY_INIT=y
+# CONFIG_DEBUG_LIST is not set
+# CONFIG_DEBUG_SG is not set
 CONFIG_FRAME_POINTER=y
+# CONFIG_BOOT_PRINTK_DELAY is not set
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_BACKTRACE_SELF_TEST is not set
+# CONFIG_FAULT_INJECTION is not set
+# CONFIG_LATENCYTOP is not set
+# CONFIG_SYSCTL_SYSCALL_CHECK is not set
+CONFIG_HAVE_FTRACE=y
+CONFIG_HAVE_DYNAMIC_FTRACE=y
+# CONFIG_FTRACE is not set
+# CONFIG_IRQSOFF_TRACER is not set
+# CONFIG_SCHED_TRACER is not set
+# CONFIG_CONTEXT_SWITCH_TRACER is not set
+# CONFIG_SAMPLES is not set
+CONFIG_HAVE_ARCH_KGDB=y
+# CONFIG_KGDB is not set
 # CONFIG_DEBUG_USER is not set
 CONFIG_DEBUG_ERRORS=y
+# CONFIG_DEBUG_STACK_USAGE is not set
 CONFIG_DEBUG_LL=y
 # CONFIG_DEBUG_ICEDCC is not set
 
@@ -898,21 +986,100 @@
 #
 # CONFIG_KEYS is not set
 # CONFIG_SECURITY is not set
+# CONFIG_SECURITY_FILE_CAPABILITIES is not set
+CONFIG_CRYPTO=y
 
 #
-# Cryptographic options
+# Crypto core or helper
 #
-# CONFIG_CRYPTO is not set
+# CONFIG_CRYPTO_MANAGER is not set
+# CONFIG_CRYPTO_GF128MUL is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_CRYPTD is not set
+# CONFIG_CRYPTO_AUTHENC is not set
+# CONFIG_CRYPTO_TEST is not set
 
 #
-# Hardware crypto devices
+# Authenticated Encryption with Associated Data
 #
+# CONFIG_CRYPTO_CCM is not set
+# CONFIG_CRYPTO_GCM is not set
+# CONFIG_CRYPTO_SEQIV is not set
+
+#
+# Block modes
+#
+# CONFIG_CRYPTO_CBC is not set
+# CONFIG_CRYPTO_CTR is not set
+# CONFIG_CRYPTO_CTS is not set
+# CONFIG_CRYPTO_ECB is not set
+# CONFIG_CRYPTO_LRW is not set
+# CONFIG_CRYPTO_PCBC is not set
+# CONFIG_CRYPTO_XTS is not set
+
+#
+# Hash modes
+#
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_XCBC is not set
+
+#
+# Digest
+#
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_MD4 is not set
+# CONFIG_CRYPTO_MD5 is not set
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_RMD128 is not set
+# CONFIG_CRYPTO_RMD160 is not set
+# CONFIG_CRYPTO_RMD256 is not set
+# CONFIG_CRYPTO_RMD320 is not set
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_WP512 is not set
+
+#
+# Ciphers
+#
+# CONFIG_CRYPTO_AES is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_CAMELLIA is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_DES is not set
+# CONFIG_CRYPTO_FCRYPT is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_SALSA20 is not set
+# CONFIG_CRYPTO_SEED is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+
+#
+# Compression
+#
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_LZO is not set
+CONFIG_CRYPTO_HW=y
 
 #
 # Library routines
 #
+CONFIG_BITREVERSE=y
+# CONFIG_GENERIC_FIND_FIRST_BIT is not set
+# CONFIG_GENERIC_FIND_NEXT_BIT is not set
 CONFIG_CRC_CCITT=m
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_T10DIF is not set
+# CONFIG_CRC_ITU_T is not set
 CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
 # CONFIG_LIBCRC32C is not set
-CONFIG_ZLIB_INFLATE=y
-CONFIG_ZLIB_DEFLATE=y
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
diff --git a/arch/arm/configs/orion5x_defconfig b/arch/arm/configs/orion5x_defconfig
index 4017d83..b2456ca 100644
--- a/arch/arm/configs/orion5x_defconfig
+++ b/arch/arm/configs/orion5x_defconfig
@@ -176,14 +176,17 @@
 CONFIG_MACH_DNS323=y
 CONFIG_MACH_TS209=y
 CONFIG_MACH_LINKSTATION_PRO=y
+CONFIG_MACH_LINKSTATION_MINI=y
 CONFIG_MACH_TS409=y
 CONFIG_MACH_WRT350N_V2=y
 CONFIG_MACH_TS78XX=y
 CONFIG_MACH_MV2120=y
+CONFIG_MACH_EDMINI_V2=y
 CONFIG_MACH_MSS2=y
 CONFIG_MACH_WNR854T=y
 CONFIG_MACH_RD88F5181L_GE=y
 CONFIG_MACH_RD88F5181L_FXO=y
+CONFIG_MACH_RD88F6183AP_GE=y
 
 #
 # Boot options
diff --git a/arch/arm/configs/palmz72_defconfig b/arch/arm/configs/palmz72_defconfig
new file mode 100644
index 0000000..3245f8f
--- /dev/null
+++ b/arch/arm/configs/palmz72_defconfig
@@ -0,0 +1,951 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.27-rc4
+# Sun Aug 24 02:29:27 2008
+#
+CONFIG_ARM=y
+CONFIG_HAVE_PWM=y
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+CONFIG_GENERIC_GPIO=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_MMU=y
+# CONFIG_NO_IOPORT is not set
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_ARCH_SUPPORTS_AOUT=y
+CONFIG_ZONE_DMA=y
+CONFIG_ARCH_MTD_XIP=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
+CONFIG_VECTORS_BASE=0xffff0000
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=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_LOG_BUF_SHIFT=14
+# CONFIG_CGROUPS is not set
+# CONFIG_GROUP_SCHED is not set
+CONFIG_SYSFS_DEPRECATED=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+# CONFIG_RELAY is not set
+CONFIG_NAMESPACES=y
+# CONFIG_UTS_NS is not set
+# CONFIG_IPC_NS is not set
+# CONFIG_USER_NS is not set
+# CONFIG_PID_NS is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+# CONFIG_EMBEDDED is not set
+CONFIG_UID16=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_COMPAT_BRK=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_ANON_INODES=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
+# CONFIG_PROFILING is not set
+# CONFIG_MARKERS is not set
+CONFIG_HAVE_OPROFILE=y
+# CONFIG_KPROBES is not set
+# CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS is not set
+# CONFIG_HAVE_IOREMAP_PROT is not set
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+# CONFIG_HAVE_ARCH_TRACEHOOK is not set
+# CONFIG_HAVE_DMA_ATTRS is not set
+# CONFIG_USE_GENERIC_SMP_HELPERS is not set
+CONFIG_HAVE_CLK=y
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_HAVE_GENERIC_DMA_COHERENT=y
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+# CONFIG_MODULE_FORCE_LOAD is not set
+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=y
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_BLK_DEV_INTEGRITY is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
+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_CLASSIC_RCU=y
+
+#
+# System Type
+#
+# CONFIG_ARCH_AAEC2000 is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_REALVIEW is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_AT91 is not set
+# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_EP93XX is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_NETX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_IOP13XX is not set
+# CONFIG_ARCH_IOP32X is not set
+# CONFIG_ARCH_IOP33X is not set
+# CONFIG_ARCH_IXP23XX is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_KIRKWOOD is not set
+# CONFIG_ARCH_KS8695 is not set
+# CONFIG_ARCH_NS9XXX is not set
+# CONFIG_ARCH_LOKI is not set
+# CONFIG_ARCH_MV78XX0 is not set
+# CONFIG_ARCH_MXC is not set
+# CONFIG_ARCH_ORION5X is not set
+# CONFIG_ARCH_PNX4008 is not set
+CONFIG_ARCH_PXA=y
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_DAVINCI is not set
+# CONFIG_ARCH_OMAP is not set
+# CONFIG_ARCH_MSM7X00A is not set
+
+#
+# Intel PXA2xx/PXA3xx Implementations
+#
+# CONFIG_ARCH_GUMSTIX is not set
+# CONFIG_ARCH_LUBBOCK is not set
+# CONFIG_MACH_LOGICPD_PXA270 is not set
+# CONFIG_MACH_MAINSTONE is not set
+# CONFIG_ARCH_PXA_IDP is not set
+# CONFIG_PXA_SHARPSL is not set
+# CONFIG_ARCH_PXA_ESERIES is not set
+# CONFIG_MACH_TRIZEPS4 is not set
+# CONFIG_MACH_EM_X270 is not set
+# CONFIG_MACH_COLIBRI is not set
+# CONFIG_MACH_ZYLONITE is not set
+# CONFIG_MACH_LITTLETON is not set
+# CONFIG_MACH_TAVOREVB is not set
+# CONFIG_MACH_SAAR is not set
+# CONFIG_MACH_ARMCORE is not set
+# CONFIG_MACH_MAGICIAN is not set
+# CONFIG_MACH_PCM027 is not set
+CONFIG_ARCH_PXA_PALM=y
+# CONFIG_MACH_PALMTX is not set
+CONFIG_MACH_PALMZ72=y
+# CONFIG_PXA_EZX is not set
+CONFIG_PXA27x=y
+CONFIG_PXA_PWM=y
+
+#
+# Boot options
+#
+
+#
+# Power management
+#
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_XSCALE=y
+CONFIG_CPU_32v5=y
+CONFIG_CPU_ABRT_EV5T=y
+CONFIG_CPU_PABRT_NOIFAR=y
+CONFIG_CPU_CACHE_VIVT=y
+CONFIG_CPU_TLB_V4WBI=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
+
+#
+# Processor Features
+#
+CONFIG_ARM_THUMB=y
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_OUTER_CACHE is not set
+CONFIG_IWMMXT=y
+CONFIG_XSCALE_PMU=y
+
+#
+# Bus support
+#
+# CONFIG_PCI_SYSCALL is not set
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+CONFIG_TICK_ONESHOT=y
+# CONFIG_NO_HZ is not set
+# CONFIG_HIGH_RES_TIMERS is not set
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+CONFIG_PREEMPT=y
+CONFIG_HZ=100
+CONFIG_AEABI=y
+CONFIG_OABI_COMPAT=y
+# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
+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_SPARSEMEM_VMEMMAP_ENABLE is not set
+CONFIG_PAGEFLAGS_EXTENDED=y
+CONFIG_SPLIT_PTLOCK_CPUS=4096
+# CONFIG_RESOURCES_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=1
+CONFIG_BOUNCE=y
+CONFIG_VIRT_TO_BUS=y
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="mem=32M console=tty root=/dev/mmcblk0"
+# CONFIG_XIP_KERNEL is not set
+# CONFIG_KEXEC is not set
+
+#
+# CPU Frequency scaling
+#
+# CONFIG_CPU_FREQ is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_FASTFPE is not set
+
+#
+# Userspace binary formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Power management options
+#
+CONFIG_PM=y
+# CONFIG_PM_DEBUG is not set
+CONFIG_PM_SLEEP=y
+CONFIG_SUSPEND=y
+CONFIG_SUSPEND_FREEZER=y
+CONFIG_APM_EMULATION=y
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+# CONFIG_IP_PNP_DHCP is not set
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# 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
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_CAN is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+
+#
+# Wireless
+#
+# CONFIG_CFG80211 is not set
+# CONFIG_WIRELESS_EXT is not set
+# CONFIG_MAC80211 is not set
+# CONFIG_IEEE80211 is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=y
+CONFIG_FIRMWARE_IN_KERNEL=y
+CONFIG_EXTRA_FIRMWARE=""
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_CONNECTOR is not set
+# CONFIG_MTD is not set
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# 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_RAM is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+# CONFIG_MISC_DEVICES is not set
+CONFIG_HAVE_IDE=y
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+# CONFIG_SCSI is not set
+# CONFIG_SCSI_DMA is not set
+# CONFIG_SCSI_NETLINK is not set
+# CONFIG_ATA is not set
+# CONFIG_MD is not set
+# CONFIG_NETDEVICES is not set
+# CONFIG_ISDN is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+# CONFIG_KEYBOARD_ATKBD is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_KEYBOARD_STOWAWAY is not set
+CONFIG_KEYBOARD_PXA27x=y
+# CONFIG_KEYBOARD_GPIO is not set
+# CONFIG_KEYBOARD_MATRIX is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET 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=y
+CONFIG_CONSOLE_TRANSLATIONS=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
+CONFIG_DEVKMEM=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+# CONFIG_SERIAL_PXA is not set
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_HW_RANDOM is not set
+# CONFIG_NVRAM is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=y
+# CONFIG_I2C_CHARDEV is not set
+CONFIG_I2C_HELPER_AUTO=y
+
+#
+# I2C Hardware Bus support
+#
+
+#
+# I2C system bus drivers (mostly embedded / system-on-chip)
+#
+# CONFIG_I2C_GPIO is not set
+# CONFIG_I2C_OCORES is not set
+CONFIG_I2C_PXA=y
+# CONFIG_I2C_PXA_SLAVE is not set
+# CONFIG_I2C_SIMTEC is not set
+
+#
+# External I2C/SMBus adapter drivers
+#
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_TAOS_EVM is not set
+
+#
+# Other I2C/SMBus bus drivers
+#
+# CONFIG_I2C_PCA_PLATFORM is not set
+# CONFIG_I2C_STUB is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_DS1682 is not set
+# CONFIG_AT24 is not set
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_PCF8575 is not set
+# CONFIG_SENSORS_PCA9539 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_TPS65010 is not set
+# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_SENSORS_TSL2550 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
+CONFIG_SPI=y
+CONFIG_SPI_MASTER=y
+
+#
+# SPI Master Controller Drivers
+#
+# CONFIG_SPI_BITBANG is not set
+# CONFIG_SPI_PXA2XX is not set
+
+#
+# SPI Protocol Masters
+#
+# CONFIG_SPI_AT25 is not set
+CONFIG_SPI_SPIDEV=y
+# CONFIG_SPI_TLE62X0 is not set
+CONFIG_ARCH_REQUIRE_GPIOLIB=y
+CONFIG_GPIOLIB=y
+CONFIG_GPIO_SYSFS=y
+
+#
+# I2C GPIO expanders:
+#
+# CONFIG_GPIO_MAX732X is not set
+# CONFIG_GPIO_PCA953X is not set
+# CONFIG_GPIO_PCF857X is not set
+
+#
+# PCI GPIO expanders:
+#
+
+#
+# SPI GPIO expanders:
+#
+# CONFIG_GPIO_MAX7301 is not set
+# CONFIG_GPIO_MCP23S08 is not set
+# CONFIG_W1 is not set
+CONFIG_POWER_SUPPLY=y
+# CONFIG_POWER_SUPPLY_DEBUG is not set
+CONFIG_PDA_POWER=y
+# CONFIG_APM_POWER is not set
+# CONFIG_BATTERY_DS2760 is not set
+# CONFIG_HWMON is not set
+# CONFIG_WATCHDOG is not set
+
+#
+# Sonics Silicon Backplane
+#
+CONFIG_SSB_POSSIBLE=y
+# CONFIG_SSB is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_CORE is not set
+# CONFIG_MFD_SM501 is not set
+# CONFIG_HTC_EGPIO is not set
+# CONFIG_HTC_PASIC3 is not set
+# CONFIG_MFD_TMIO is not set
+# CONFIG_MFD_T7L66XB is not set
+# CONFIG_MFD_TC6387XB is not set
+# CONFIG_MFD_TC6393XB is not set
+
+#
+# Multimedia devices
+#
+
+#
+# Multimedia core support
+#
+# CONFIG_VIDEO_DEV is not set
+# CONFIG_DVB_CORE is not set
+# CONFIG_VIDEO_MEDIA is not set
+
+#
+# Multimedia drivers
+#
+# CONFIG_DAB is not set
+
+#
+# Graphics support
+#
+# CONFIG_VGASTATE is not set
+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
+CONFIG_FB=y
+# CONFIG_FIRMWARE_EDID is not set
+# CONFIG_FB_DDC is not set
+CONFIG_FB_CFB_FILLRECT=y
+CONFIG_FB_CFB_COPYAREA=y
+CONFIG_FB_CFB_IMAGEBLIT=y
+# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
+# CONFIG_FB_SYS_FILLRECT is not set
+# CONFIG_FB_SYS_COPYAREA is not set
+# CONFIG_FB_SYS_IMAGEBLIT is not set
+# CONFIG_FB_FOREIGN_ENDIAN is not set
+# CONFIG_FB_SYS_FOPS is not set
+# CONFIG_FB_SVGALIB is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+
+#
+# Frame buffer hardware drivers
+#
+# CONFIG_FB_S1D13XXX is not set
+CONFIG_FB_PXA=y
+# CONFIG_FB_PXA_SMARTPANEL is not set
+# CONFIG_FB_PXA_PARAMETERS is not set
+# CONFIG_FB_MBX is not set
+# CONFIG_FB_W100 is not set
+# CONFIG_FB_AM200EPD is not set
+# CONFIG_FB_VIRTUAL is not set
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+# CONFIG_LCD_CLASS_DEVICE is not set
+CONFIG_BACKLIGHT_CLASS_DEVICE=y
+# CONFIG_BACKLIGHT_CORGI is not set
+CONFIG_BACKLIGHT_PWM=y
+
+#
+# Display device support
+#
+CONFIG_DISPLAY_SUPPORT=y
+
+#
+# Display hardware drivers
+#
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set
+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
+CONFIG_FONTS=y
+CONFIG_FONT_8x8=y
+# CONFIG_FONT_8x16 is not set
+# CONFIG_FONT_6x11 is not set
+# CONFIG_FONT_7x14 is not set
+# CONFIG_FONT_PEARL_8x8 is not set
+# CONFIG_FONT_ACORN_8x8 is not set
+# CONFIG_FONT_MINI_4x6 is not set
+# CONFIG_FONT_SUN8x16 is not set
+# CONFIG_FONT_SUN12x22 is not set
+# CONFIG_FONT_10x18 is not set
+# CONFIG_LOGO is not set
+# CONFIG_SOUND is not set
+# CONFIG_HID_SUPPORT is not set
+# CONFIG_USB_SUPPORT is not set
+CONFIG_MMC=y
+CONFIG_MMC_DEBUG=y
+# CONFIG_MMC_UNSAFE_RESUME is not set
+
+#
+# MMC/SD Card Drivers
+#
+CONFIG_MMC_BLOCK=y
+CONFIG_MMC_BLOCK_BOUNCE=y
+# CONFIG_SDIO_UART is not set
+# CONFIG_MMC_TEST is not set
+
+#
+# MMC/SD Host Controller Drivers
+#
+CONFIG_MMC_PXA=y
+# CONFIG_MMC_SDHCI is not set
+# CONFIG_MMC_SPI is not set
+# CONFIG_NEW_LEDS is not set
+CONFIG_RTC_LIB=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+# CONFIG_RTC_DEBUG is not set
+
+#
+# RTC interfaces
+#
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_DEV=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+# CONFIG_RTC_DRV_TEST is not set
+
+#
+# I2C RTC drivers
+#
+# CONFIG_RTC_DRV_DS1307 is not set
+# CONFIG_RTC_DRV_DS1374 is not set
+# CONFIG_RTC_DRV_DS1672 is not set
+# CONFIG_RTC_DRV_MAX6900 is not set
+# CONFIG_RTC_DRV_RS5C372 is not set
+# CONFIG_RTC_DRV_ISL1208 is not set
+# CONFIG_RTC_DRV_X1205 is not set
+# CONFIG_RTC_DRV_PCF8563 is not set
+# CONFIG_RTC_DRV_PCF8583 is not set
+# CONFIG_RTC_DRV_M41T80 is not set
+# CONFIG_RTC_DRV_S35390A is not set
+# CONFIG_RTC_DRV_FM3130 is not set
+
+#
+# SPI RTC drivers
+#
+# CONFIG_RTC_DRV_M41T94 is not set
+# CONFIG_RTC_DRV_DS1305 is not set
+# CONFIG_RTC_DRV_MAX6902 is not set
+# CONFIG_RTC_DRV_R9701 is not set
+# CONFIG_RTC_DRV_RS5C348 is not set
+
+#
+# Platform RTC drivers
+#
+# CONFIG_RTC_DRV_CMOS is not set
+# CONFIG_RTC_DRV_DS1511 is not set
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_STK17TA8 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_M48T59 is not set
+# CONFIG_RTC_DRV_V3020 is not set
+
+#
+# on-CPU RTC drivers
+#
+CONFIG_RTC_DRV_SA1100=y
+# CONFIG_DMADEVICES is not set
+
+#
+# Voltage and Current regulators
+#
+# CONFIG_REGULATOR is not set
+# CONFIG_REGULATOR_FIXED_VOLTAGE is not set
+# CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set
+# CONFIG_REGULATOR_BQ24022 is not set
+# CONFIG_UIO is not set
+
+#
+# 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_EXT4DEV_FS is not set
+CONFIG_JBD=y
+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_DNOTIFY is not set
+# CONFIG_INOTIFY is not set
+# CONFIG_QUOTA is not set
+# 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_FAT_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=866
+CONFIG_FAT_DEFAULT_IOCHARSET="utf8"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+# 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_MINIX_FS is not set
+# CONFIG_OMFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+# CONFIG_NETWORK_FILESYSTEMS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="utf8"
+# CONFIG_NLS_CODEPAGE_437 is not set
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+CONFIG_NLS_CODEPAGE_866=y
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+# CONFIG_NLS_ISO8859_1 is not set
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+CONFIG_NLS_UTF8=y
+# CONFIG_DLM is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_FRAME_WARN=1024
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+# CONFIG_DEBUG_KERNEL is not set
+CONFIG_DEBUG_BUGVERBOSE=y
+CONFIG_DEBUG_MEMORY_INIT=y
+CONFIG_FRAME_POINTER=y
+# CONFIG_LATENCYTOP is not set
+CONFIG_SYSCTL_SYSCALL_CHECK=y
+CONFIG_HAVE_FTRACE=y
+CONFIG_HAVE_DYNAMIC_FTRACE=y
+# CONFIG_FTRACE is not set
+# CONFIG_IRQSOFF_TRACER is not set
+# CONFIG_PREEMPT_TRACER is not set
+# CONFIG_SCHED_TRACER is not set
+# CONFIG_CONTEXT_SWITCH_TRACER is not set
+# CONFIG_SAMPLES is not set
+CONFIG_HAVE_ARCH_KGDB=y
+CONFIG_DEBUG_USER=y
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+# CONFIG_SECURITY_FILE_CAPABILITIES is not set
+# CONFIG_CRYPTO is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+# CONFIG_GENERIC_FIND_FIRST_BIT is not set
+# CONFIG_GENERIC_FIND_NEXT_BIT is not set
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+CONFIG_CRC_T10DIF=y
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+# CONFIG_LIBCRC32C is not set
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
diff --git a/arch/arm/configs/viper_defconfig b/arch/arm/configs/viper_defconfig
new file mode 100644
index 0000000..d01fecb
--- /dev/null
+++ b/arch/arm/configs/viper_defconfig
@@ -0,0 +1,1678 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.27-rc4
+# Thu Aug 21 17:12:07 2008
+#
+CONFIG_ARM=y
+CONFIG_HAVE_PWM=y
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+CONFIG_GENERIC_GPIO=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_MMU=y
+# CONFIG_NO_IOPORT is not set
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_ARCH_SUPPORTS_AOUT=y
+CONFIG_ZONE_DMA=y
+CONFIG_ARCH_MTD_XIP=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
+CONFIG_VECTORS_BASE=0xffff0000
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+# CONFIG_SWAP is not set
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=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_LOG_BUF_SHIFT=13
+# CONFIG_CGROUPS is not set
+# CONFIG_GROUP_SCHED is not set
+CONFIG_SYSFS_DEPRECATED=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+# CONFIG_RELAY is not set
+# CONFIG_NAMESPACES is not set
+# CONFIG_BLK_DEV_INITRD is not set
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+CONFIG_EMBEDDED=y
+CONFIG_UID16=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+# CONFIG_ELF_CORE is not set
+CONFIG_COMPAT_BRK=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_ANON_INODES=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+# CONFIG_SHMEM is not set
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
+# CONFIG_PROFILING is not set
+# CONFIG_MARKERS is not set
+CONFIG_HAVE_OPROFILE=y
+# CONFIG_KPROBES is not set
+# CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS is not set
+# CONFIG_HAVE_IOREMAP_PROT is not set
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+# CONFIG_HAVE_ARCH_TRACEHOOK is not set
+# CONFIG_HAVE_DMA_ATTRS is not set
+# CONFIG_USE_GENERIC_SMP_HELPERS is not set
+CONFIG_HAVE_CLK=y
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_HAVE_GENERIC_DMA_COHERENT=y
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+CONFIG_TINY_SHMEM=y
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+# CONFIG_MODULE_FORCE_LOAD is not set
+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=y
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_BLK_DEV_INTEGRITY is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+# CONFIG_IOSCHED_AS is not set
+CONFIG_IOSCHED_DEADLINE=y
+# CONFIG_IOSCHED_CFQ is not set
+# CONFIG_DEFAULT_AS is not set
+CONFIG_DEFAULT_DEADLINE=y
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="deadline"
+CONFIG_CLASSIC_RCU=y
+
+#
+# System Type
+#
+# CONFIG_ARCH_AAEC2000 is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_REALVIEW is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_AT91 is not set
+# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_EP93XX is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_NETX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_IOP13XX is not set
+# CONFIG_ARCH_IOP32X is not set
+# CONFIG_ARCH_IOP33X is not set
+# CONFIG_ARCH_IXP23XX is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_KIRKWOOD is not set
+# CONFIG_ARCH_KS8695 is not set
+# CONFIG_ARCH_NS9XXX is not set
+# CONFIG_ARCH_LOKI is not set
+# CONFIG_ARCH_MV78XX0 is not set
+# CONFIG_ARCH_MXC is not set
+# CONFIG_ARCH_ORION5X is not set
+# CONFIG_ARCH_PNX4008 is not set
+CONFIG_ARCH_PXA=y
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_DAVINCI is not set
+# CONFIG_ARCH_OMAP is not set
+# CONFIG_ARCH_MSM7X00A is not set
+
+#
+# Intel PXA2xx/PXA3xx Implementations
+#
+# CONFIG_ARCH_GUMSTIX is not set
+# CONFIG_ARCH_LUBBOCK is not set
+# CONFIG_MACH_LOGICPD_PXA270 is not set
+# CONFIG_MACH_MAINSTONE is not set
+# CONFIG_ARCH_PXA_IDP is not set
+# CONFIG_PXA_SHARPSL is not set
+CONFIG_ARCH_VIPER=y
+# CONFIG_ARCH_PXA_ESERIES is not set
+# CONFIG_MACH_TRIZEPS4 is not set
+# CONFIG_MACH_EM_X270 is not set
+# CONFIG_MACH_COLIBRI is not set
+# CONFIG_MACH_ZYLONITE is not set
+# CONFIG_MACH_LITTLETON is not set
+# CONFIG_MACH_TAVOREVB is not set
+# CONFIG_MACH_SAAR is not set
+# CONFIG_MACH_ARMCORE is not set
+# CONFIG_MACH_MAGICIAN is not set
+# CONFIG_MACH_PCM027 is not set
+# CONFIG_ARCH_PXA_PALM is not set
+# CONFIG_PXA_EZX is not set
+CONFIG_PXA25x=y
+CONFIG_PXA_PWM=m
+CONFIG_PXA_HAVE_ISA_IRQS=y
+
+#
+# Boot options
+#
+
+#
+# Power management
+#
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_XSCALE=y
+CONFIG_CPU_32v5=y
+CONFIG_CPU_ABRT_EV5T=y
+CONFIG_CPU_PABRT_NOIFAR=y
+CONFIG_CPU_CACHE_VIVT=y
+CONFIG_CPU_TLB_V4WBI=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
+
+#
+# Processor Features
+#
+CONFIG_ARM_THUMB=y
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_OUTER_CACHE is not set
+CONFIG_IWMMXT=y
+CONFIG_XSCALE_PMU=y
+
+#
+# Bus support
+#
+CONFIG_ISA=y
+# CONFIG_PCI_SYSCALL is not set
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+CONFIG_PCCARD=m
+# CONFIG_PCMCIA_DEBUG is not set
+CONFIG_PCMCIA=m
+CONFIG_PCMCIA_LOAD_CIS=y
+CONFIG_PCMCIA_IOCTL=y
+
+#
+# PC-card bridges
+#
+# CONFIG_I82365 is not set
+# CONFIG_TCIC is not set
+CONFIG_PCMCIA_PXA2XX=m
+CONFIG_PCMCIA_PROBE=y
+
+#
+# Kernel Features
+#
+CONFIG_TICK_ONESHOT=y
+# CONFIG_NO_HZ is not set
+# CONFIG_HIGH_RES_TIMERS is not set
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+# CONFIG_PREEMPT is not set
+CONFIG_HZ=100
+CONFIG_AEABI=y
+CONFIG_OABI_COMPAT=y
+# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
+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_SPARSEMEM_VMEMMAP_ENABLE is not set
+CONFIG_PAGEFLAGS_EXTENDED=y
+CONFIG_SPLIT_PTLOCK_CPUS=4096
+# CONFIG_RESOURCES_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=1
+CONFIG_BOUNCE=y
+CONFIG_VIRT_TO_BUS=y
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="root=31:02 rootfstype=jffs2 ro console=ttyS0,115200"
+# CONFIG_XIP_KERNEL is not set
+# CONFIG_KEXEC is not set
+
+#
+# CPU Frequency scaling
+#
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_TABLE=y
+# CONFIG_CPU_FREQ_DEBUG is not set
+CONFIG_CPU_FREQ_STAT=y
+# CONFIG_CPU_FREQ_STAT_DETAILS is not set
+CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y
+# CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set
+CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
+CONFIG_CPU_FREQ_GOV_POWERSAVE=m
+CONFIG_CPU_FREQ_GOV_USERSPACE=m
+CONFIG_CPU_FREQ_GOV_ONDEMAND=m
+CONFIG_CPU_FREQ_GOV_CONSERVATIVE=m
+CONFIG_CPU_FREQ_PXA=y
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+# CONFIG_FPE_NWFPE is not set
+CONFIG_FPE_FASTFPE=y
+
+#
+# Userspace binary formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Power management options
+#
+CONFIG_PM=y
+# CONFIG_PM_DEBUG is not set
+CONFIG_PM_SLEEP=y
+CONFIG_SUSPEND=y
+CONFIG_SUSPEND_FREEZER=y
+# CONFIG_APM_EMULATION is not set
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
+# CONFIG_XFRM_STATISTICS is not set
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+# CONFIG_IP_PNP_BOOTP is not set
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+CONFIG_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_XFRM_MODE_BEET=y
+# CONFIG_INET_LRO is not set
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# 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
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_CAN is not set
+# CONFIG_IRDA is not set
+CONFIG_BT=m
+CONFIG_BT_L2CAP=m
+# CONFIG_BT_SCO is not set
+CONFIG_BT_RFCOMM=m
+CONFIG_BT_RFCOMM_TTY=y
+CONFIG_BT_BNEP=m
+# CONFIG_BT_BNEP_MC_FILTER is not set
+# CONFIG_BT_BNEP_PROTO_FILTER is not set
+# CONFIG_BT_HIDP is not set
+
+#
+# Bluetooth device drivers
+#
+CONFIG_BT_HCIUSB=m
+# CONFIG_BT_HCIUSB_SCO is not set
+# CONFIG_BT_HCIBTUSB is not set
+CONFIG_BT_HCIUART=m
+CONFIG_BT_HCIUART_H4=y
+CONFIG_BT_HCIUART_BCSP=y
+# CONFIG_BT_HCIUART_LL is not set
+# CONFIG_BT_HCIBCM203X is not set
+# CONFIG_BT_HCIBPA10X is not set
+# CONFIG_BT_HCIBFUSB is not set
+# CONFIG_BT_HCIDTL1 is not set
+# CONFIG_BT_HCIBT3C is not set
+# CONFIG_BT_HCIBLUECARD is not set
+# CONFIG_BT_HCIBTUART is not set
+# CONFIG_BT_HCIVHCI is not set
+# CONFIG_AF_RXRPC is not set
+
+#
+# Wireless
+#
+# CONFIG_CFG80211 is not set
+# CONFIG_WIRELESS_EXT is not set
+# CONFIG_MAC80211 is not set
+CONFIG_IEEE80211=m
+# CONFIG_IEEE80211_DEBUG is not set
+CONFIG_IEEE80211_CRYPT_WEP=m
+# CONFIG_IEEE80211_CRYPT_CCMP is not set
+# CONFIG_IEEE80211_CRYPT_TKIP is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=m
+CONFIG_FIRMWARE_IN_KERNEL=y
+CONFIG_EXTRA_FIRMWARE=""
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_CONNECTOR is not set
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_PARTITIONS=y
+CONFIG_MTD_REDBOOT_PARTS=y
+CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=0
+# CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED is not set
+# CONFIG_MTD_REDBOOT_PARTS_READONLY is not set
+# CONFIG_MTD_CMDLINE_PARTS is not set
+# CONFIG_MTD_AFS_PARTS is not set
+# CONFIG_MTD_AR7_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=m
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+# CONFIG_MTD_OOPS is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+CONFIG_MTD_JEDECPROBE=y
+CONFIG_MTD_GEN_PROBE=y
+CONFIG_MTD_CFI_ADV_OPTIONS=y
+CONFIG_MTD_CFI_NOSWAP=y
+# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set
+# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set
+CONFIG_MTD_CFI_GEOMETRY=y
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+# CONFIG_MTD_MAP_BANK_WIDTH_4 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+# CONFIG_MTD_CFI_I2 is not set
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_OTP is not set
+CONFIG_MTD_CFI_INTELEXT=y
+CONFIG_MTD_CFI_AMDSTD=y
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+CONFIG_MTD_RAM=y
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_XIP is not set
+
+#
+# Mapping drivers for chip access
+#
+CONFIG_MTD_COMPLEX_MAPPINGS=y
+CONFIG_MTD_PHYSMAP=y
+CONFIG_MTD_PHYSMAP_START=0x8000000
+CONFIG_MTD_PHYSMAP_LEN=0
+CONFIG_MTD_PHYSMAP_BANKWIDTH=2
+CONFIG_MTD_PXA2XX=y
+# CONFIG_MTD_ARM_INTEGRATOR is not set
+# CONFIG_MTD_IMPA7 is not set
+# CONFIG_MTD_SHARP_SL is not set
+# CONFIG_MTD_PLATRAM is not set
+CONFIG_MTD_SPARSE_RAM=y
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+# CONFIG_MTD_NAND is not set
+# CONFIG_MTD_ONENAND is not set
+
+#
+# UBI - Unsorted block images
+#
+# CONFIG_MTD_UBI is not set
+# CONFIG_PARPORT is not set
+# CONFIG_PNP is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=m
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_UB is not set
+# CONFIG_BLK_DEV_RAM is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+CONFIG_MISC_DEVICES=y
+# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_ENCLOSURE_SERVICES is not set
+CONFIG_HAVE_IDE=y
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=m
+CONFIG_SCSI_DMA=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
+# CONFIG_SCSI_PROC_FS is not set
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=m
+# 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
+# CONFIG_SCSI_SCAN_ASYNC is not set
+CONFIG_SCSI_WAIT_SCAN=m
+
+#
+# SCSI Transports
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+# CONFIG_SCSI_SRP_ATTRS is not set
+CONFIG_SCSI_LOWLEVEL=y
+# CONFIG_ISCSI_TCP is not set
+# CONFIG_SCSI_AHA152X is not set
+# CONFIG_SCSI_AIC7XXX_OLD is not set
+# CONFIG_SCSI_ADVANSYS is not set
+# CONFIG_SCSI_IN2000 is not set
+# CONFIG_SCSI_DTC3280 is not set
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_GENERIC_NCR5380 is not set
+# CONFIG_SCSI_GENERIC_NCR5380_MMIO is not set
+# CONFIG_SCSI_NCR53C406A is not set
+# CONFIG_SCSI_PAS16 is not set
+# CONFIG_SCSI_QLOGIC_FAS is not set
+# CONFIG_SCSI_SYM53C416 is not set
+# CONFIG_SCSI_T128 is not set
+# CONFIG_SCSI_DEBUG is not set
+# CONFIG_SCSI_LOWLEVEL_PCMCIA is not set
+# CONFIG_SCSI_DH is not set
+CONFIG_ATA=m
+# CONFIG_ATA_NONSTANDARD is not set
+# CONFIG_SATA_PMP is not set
+CONFIG_ATA_SFF=y
+# CONFIG_SATA_MV is not set
+# CONFIG_PATA_LEGACY is not set
+CONFIG_PATA_PCMCIA=m
+# CONFIG_PATA_QDI is not set
+# CONFIG_PATA_WINBOND_VLB is not set
+# CONFIG_PATA_PLATFORM is not set
+# CONFIG_MD is not set
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_VETH is not set
+# CONFIG_ARCNET is not set
+# CONFIG_PHYLIB is not set
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_AX88796 is not set
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_NET_VENDOR_SMC is not set
+CONFIG_SMC91X=y
+# CONFIG_DM9000 is not set
+# CONFIG_SMC911X is not set
+# CONFIG_NET_VENDOR_RACAL is not set
+# CONFIG_AT1700 is not set
+# CONFIG_DEPCA is not set
+# CONFIG_HP100 is not set
+# CONFIG_NET_ISA is not set
+# CONFIG_IBM_NEW_EMAC_ZMII is not set
+# CONFIG_IBM_NEW_EMAC_RGMII is not set
+# CONFIG_IBM_NEW_EMAC_TAH is not set
+# CONFIG_IBM_NEW_EMAC_EMAC4 is not set
+# CONFIG_NET_PCI is not set
+# CONFIG_B44 is not set
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
+# CONFIG_TR is not set
+
+#
+# Wireless LAN
+#
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
+# CONFIG_IWLWIFI_LEDS is not set
+
+#
+# USB Network Adapters
+#
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+CONFIG_USB_PEGASUS=m
+# CONFIG_USB_RTL8150 is not set
+CONFIG_USB_USBNET=m
+CONFIG_USB_NET_AX8817X=m
+CONFIG_USB_NET_CDCETHER=m
+# CONFIG_USB_NET_DM9601 is not set
+# CONFIG_USB_NET_GL620A is not set
+CONFIG_USB_NET_NET1080=m
+# CONFIG_USB_NET_PLUSB is not set
+# CONFIG_USB_NET_MCS7830 is not set
+# CONFIG_USB_NET_RNDIS_HOST is not set
+# CONFIG_USB_NET_CDC_SUBSET is not set
+CONFIG_USB_NET_ZAURUS=m
+CONFIG_NET_PCMCIA=y
+# CONFIG_PCMCIA_3C589 is not set
+# CONFIG_PCMCIA_3C574 is not set
+# CONFIG_PCMCIA_FMVJ18X is not set
+# CONFIG_PCMCIA_PCNET is not set
+# CONFIG_PCMCIA_NMCLAN is not set
+# CONFIG_PCMCIA_SMC91C92 is not set
+# CONFIG_PCMCIA_XIRC2PS is not set
+# CONFIG_PCMCIA_AXNET is not set
+# CONFIG_WAN is not set
+CONFIG_PPP=m
+# CONFIG_PPP_MULTILINK is not set
+# CONFIG_PPP_FILTER is not set
+CONFIG_PPP_ASYNC=m
+# CONFIG_PPP_SYNC_TTY is not set
+CONFIG_PPP_DEFLATE=m
+CONFIG_PPP_BSDCOMP=m
+# CONFIG_PPP_MPPE is not set
+# CONFIG_PPPOE is not set
+# CONFIG_PPPOL2TP is not set
+# CONFIG_SLIP is not set
+CONFIG_SLHC=m
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_ISDN is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=m
+# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+CONFIG_INPUT_EVDEV=m
+# 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_TABLET is not set
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_FUJITSU=m
+# CONFIG_TOUCHSCREEN_GUNZE is not set
+CONFIG_TOUCHSCREEN_ELO=m
+CONFIG_TOUCHSCREEN_MTOUCH=m
+CONFIG_TOUCHSCREEN_INEXIO=m
+# CONFIG_TOUCHSCREEN_MK712 is not set
+CONFIG_TOUCHSCREEN_HTCPEN=m
+CONFIG_TOUCHSCREEN_PENMOUNT=m
+CONFIG_TOUCHSCREEN_TOUCHRIGHT=m
+CONFIG_TOUCHSCREEN_TOUCHWIN=m
+# CONFIG_TOUCHSCREEN_UCB1400 is not set
+# CONFIG_TOUCHSCREEN_WM97XX is not set
+# CONFIG_TOUCHSCREEN_USB_COMPOSITE is not set
+CONFIG_TOUCHSCREEN_TOUCHIT213=m
+CONFIG_INPUT_MISC=y
+# CONFIG_INPUT_ATI_REMOTE is not set
+# CONFIG_INPUT_ATI_REMOTE2 is not set
+# CONFIG_INPUT_KEYSPAN_REMOTE is not set
+# CONFIG_INPUT_POWERMATE is not set
+# CONFIG_INPUT_YEALINK is not set
+CONFIG_INPUT_UINPUT=m
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+CONFIG_SERIO_SERPORT=y
+# CONFIG_SERIO_LIBPS2 is not set
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+# CONFIG_CONSOLE_TRANSLATIONS is not set
+# CONFIG_VT_CONSOLE is not set
+CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
+CONFIG_DEVKMEM=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=m
+# CONFIG_SERIAL_8250_CS is not set
+CONFIG_SERIAL_8250_NR_UARTS=5
+CONFIG_SERIAL_8250_RUNTIME_UARTS=5
+# CONFIG_SERIAL_8250_EXTENDED is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_PXA=y
+CONFIG_SERIAL_PXA_CONSOLE=y
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_IPMI_HANDLER is not set
+CONFIG_HW_RANDOM=m
+# CONFIG_NVRAM is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+
+#
+# PCMCIA character devices
+#
+# CONFIG_SYNCLINK_CS is not set
+# CONFIG_CARDMAN_4000 is not set
+# CONFIG_CARDMAN_4040 is not set
+# CONFIG_IPWIRELESS is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+CONFIG_DEVPORT=y
+CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_CHARDEV=y
+# CONFIG_I2C_HELPER_AUTO is not set
+
+#
+# I2C Algorithms
+#
+CONFIG_I2C_ALGOBIT=y
+# CONFIG_I2C_ALGOPCF is not set
+# CONFIG_I2C_ALGOPCA is not set
+
+#
+# I2C Hardware Bus support
+#
+
+#
+# I2C system bus drivers (mostly embedded / system-on-chip)
+#
+CONFIG_I2C_GPIO=y
+# CONFIG_I2C_OCORES is not set
+CONFIG_I2C_PXA=y
+# CONFIG_I2C_PXA_SLAVE is not set
+# CONFIG_I2C_SIMTEC is not set
+
+#
+# External I2C/SMBus adapter drivers
+#
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_TAOS_EVM is not set
+# CONFIG_I2C_TINY_USB is not set
+
+#
+# Other I2C/SMBus bus drivers
+#
+# CONFIG_I2C_ELEKTOR is not set
+# CONFIG_I2C_PCA_ISA is not set
+# CONFIG_I2C_PCA_PLATFORM is not set
+# CONFIG_I2C_STUB is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_DS1682 is not set
+# CONFIG_AT24 is not set
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_PCF8575 is not set
+# CONFIG_SENSORS_PCA9539 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_TPS65010 is not set
+# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_SENSORS_TSL2550 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
+# CONFIG_SPI is not set
+CONFIG_ARCH_REQUIRE_GPIOLIB=y
+CONFIG_GPIOLIB=y
+# CONFIG_DEBUG_GPIO is not set
+CONFIG_GPIO_SYSFS=y
+
+#
+# I2C GPIO expanders:
+#
+# CONFIG_GPIO_MAX732X is not set
+# CONFIG_GPIO_PCA953X is not set
+# CONFIG_GPIO_PCF857X is not set
+
+#
+# PCI GPIO expanders:
+#
+
+#
+# SPI GPIO expanders:
+#
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_SENSORS_AD7414 is not set
+# CONFIG_SENSORS_AD7418 is not set
+# CONFIG_SENSORS_ADM1021 is not set
+# CONFIG_SENSORS_ADM1025 is not set
+# CONFIG_SENSORS_ADM1026 is not set
+# CONFIG_SENSORS_ADM1029 is not set
+# CONFIG_SENSORS_ADM1031 is not set
+# CONFIG_SENSORS_ADM9240 is not set
+# CONFIG_SENSORS_ADT7470 is not set
+# CONFIG_SENSORS_ADT7473 is not set
+# CONFIG_SENSORS_ATXP1 is not set
+# CONFIG_SENSORS_DS1621 is not set
+# CONFIG_SENSORS_F71805F is not set
+# CONFIG_SENSORS_F71882FG is not set
+# CONFIG_SENSORS_F75375S 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_LM93 is not set
+# CONFIG_SENSORS_MAX1619 is not set
+# CONFIG_SENSORS_MAX6650 is not set
+# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_PC87427 is not set
+# CONFIG_SENSORS_DME1737 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47M192 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_ADS7828 is not set
+# CONFIG_SENSORS_THMC50 is not set
+# CONFIG_SENSORS_VT1211 is not set
+# CONFIG_SENSORS_W83781D is not set
+# CONFIG_SENSORS_W83791D is not set
+# CONFIG_SENSORS_W83792D is not set
+# CONFIG_SENSORS_W83793 is not set
+# CONFIG_SENSORS_W83L785TS is not set
+# CONFIG_SENSORS_W83L786NG is not set
+# CONFIG_SENSORS_W83627HF is not set
+# CONFIG_SENSORS_W83627EHF is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
+CONFIG_WATCHDOG=y
+# CONFIG_WATCHDOG_NOWAYOUT is not set
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+# CONFIG_SA1100_WATCHDOG is not set
+
+#
+# ISA-based Watchdog Cards
+#
+# CONFIG_PCWATCHDOG is not set
+# CONFIG_MIXCOMWD is not set
+# CONFIG_WDT is not set
+
+#
+# USB-based Watchdog Cards
+#
+# CONFIG_USBPCWATCHDOG is not set
+
+#
+# Sonics Silicon Backplane
+#
+CONFIG_SSB_POSSIBLE=y
+# CONFIG_SSB is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_CORE is not set
+# CONFIG_MFD_SM501 is not set
+# CONFIG_HTC_EGPIO is not set
+# CONFIG_HTC_PASIC3 is not set
+# CONFIG_MFD_TMIO is not set
+# CONFIG_MFD_T7L66XB is not set
+# CONFIG_MFD_TC6387XB is not set
+# CONFIG_MFD_TC6393XB is not set
+
+#
+# Multimedia devices
+#
+
+#
+# Multimedia core support
+#
+# CONFIG_VIDEO_DEV is not set
+# CONFIG_DVB_CORE is not set
+# CONFIG_VIDEO_MEDIA is not set
+
+#
+# Multimedia drivers
+#
+# CONFIG_DAB is not set
+
+#
+# Graphics support
+#
+# CONFIG_VGASTATE is not set
+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
+CONFIG_FB=y
+# CONFIG_FIRMWARE_EDID is not set
+# CONFIG_FB_DDC is not set
+CONFIG_FB_CFB_FILLRECT=m
+CONFIG_FB_CFB_COPYAREA=m
+CONFIG_FB_CFB_IMAGEBLIT=m
+# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
+# CONFIG_FB_SYS_FILLRECT is not set
+# CONFIG_FB_SYS_COPYAREA is not set
+# CONFIG_FB_SYS_IMAGEBLIT is not set
+# CONFIG_FB_FOREIGN_ENDIAN is not set
+# CONFIG_FB_SYS_FOPS is not set
+# CONFIG_FB_SVGALIB is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+
+#
+# Frame buffer hardware drivers
+#
+# CONFIG_FB_S1D13XXX is not set
+CONFIG_FB_PXA=m
+# CONFIG_FB_PXA_SMARTPANEL is not set
+CONFIG_FB_PXA_PARAMETERS=y
+# CONFIG_FB_MBX is not set
+# CONFIG_FB_W100 is not set
+# CONFIG_FB_AM200EPD is not set
+# CONFIG_FB_VIRTUAL is not set
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+CONFIG_LCD_CLASS_DEVICE=m
+# CONFIG_LCD_ILI9320 is not set
+# CONFIG_LCD_PLATFORM is not set
+CONFIG_BACKLIGHT_CLASS_DEVICE=m
+# CONFIG_BACKLIGHT_CORGI is not set
+CONFIG_BACKLIGHT_PWM=m
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+# CONFIG_MDA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=m
+# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set
+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
+# CONFIG_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+CONFIG_LOGO=y
+CONFIG_LOGO_LINUX_MONO=y
+CONFIG_LOGO_LINUX_VGA16=y
+CONFIG_LOGO_LINUX_CLUT224=y
+CONFIG_SOUND=m
+CONFIG_SND=m
+CONFIG_SND_TIMER=m
+CONFIG_SND_PCM=m
+# CONFIG_SND_SEQUENCER is not set
+CONFIG_SND_OSSEMUL=y
+CONFIG_SND_MIXER_OSS=m
+CONFIG_SND_PCM_OSS=m
+CONFIG_SND_PCM_OSS_PLUGINS=y
+# CONFIG_SND_DYNAMIC_MINORS is not set
+CONFIG_SND_SUPPORT_OLD_API=y
+CONFIG_SND_VERBOSE_PROCFS=y
+# CONFIG_SND_VERBOSE_PRINTK is not set
+# CONFIG_SND_DEBUG is not set
+CONFIG_SND_VMASTER=y
+CONFIG_SND_AC97_CODEC=m
+CONFIG_SND_DRIVERS=y
+# CONFIG_SND_DUMMY is not set
+# CONFIG_SND_MTPAV is not set
+# CONFIG_SND_SERIAL_U16550 is not set
+# CONFIG_SND_MPU401 is not set
+# CONFIG_SND_AC97_POWER_SAVE is not set
+CONFIG_SND_ARM=y
+CONFIG_SND_PXA2XX_PCM=m
+CONFIG_SND_PXA2XX_AC97=m
+CONFIG_SND_USB=y
+# CONFIG_SND_USB_AUDIO is not set
+# CONFIG_SND_USB_CAIAQ is not set
+CONFIG_SND_PCMCIA=y
+# CONFIG_SND_VXPOCKET is not set
+# CONFIG_SND_PDAUDIOCF is not set
+# CONFIG_SND_SOC is not set
+# CONFIG_SOUND_PRIME is not set
+CONFIG_AC97_BUS=m
+CONFIG_HID_SUPPORT=y
+CONFIG_HID=y
+# CONFIG_HID_DEBUG is not set
+# CONFIG_HIDRAW is not set
+
+#
+# USB Input Devices
+#
+CONFIG_USB_HID=m
+# CONFIG_USB_HIDINPUT_POWERBOOK is not set
+# CONFIG_HID_FF is not set
+# CONFIG_USB_HIDDEV is not set
+
+#
+# USB HID Boot Protocol drivers
+#
+# CONFIG_USB_KBD is not set
+# CONFIG_USB_MOUSE is not set
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_ARCH_HAS_HCD=y
+# CONFIG_USB_ARCH_HAS_OHCI is not set
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+CONFIG_USB=m
+# CONFIG_USB_DEBUG is not set
+# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+CONFIG_USB_DEVICE_CLASS=y
+# CONFIG_USB_DYNAMIC_MINORS is not set
+CONFIG_USB_SUSPEND=y
+# CONFIG_USB_OTG is not set
+# CONFIG_USB_OTG_WHITELIST is not set
+# CONFIG_USB_OTG_BLACKLIST_HUB is not set
+# CONFIG_USB_MON is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_C67X00_HCD is not set
+CONFIG_USB_ISP116X_HCD=m
+# CONFIG_USB_ISP1760_HCD is not set
+CONFIG_USB_SL811_HCD=m
+# CONFIG_USB_SL811_CS is not set
+CONFIG_USB_R8A66597_HCD=m
+# CONFIG_USB_MUSB_HDRC is not set
+# CONFIG_USB_GADGET_MUSB_HDRC is not set
+
+#
+# USB Device Class drivers
+#
+CONFIG_USB_ACM=m
+# CONFIG_USB_PRINTER is not set
+# CONFIG_USB_WDM is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# may also be needed; see USB_STORAGE Help for more information
+#
+CONFIG_USB_STORAGE=m
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_ISD200 is not set
+# CONFIG_USB_STORAGE_DPCM is not set
+# CONFIG_USB_STORAGE_USBAT is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_STORAGE_ALAUDA is not set
+# CONFIG_USB_STORAGE_ONETOUCH is not set
+# CONFIG_USB_STORAGE_KARMA is not set
+# CONFIG_USB_STORAGE_SIERRA is not set
+# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set
+# CONFIG_USB_LIBUSUAL is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+
+#
+# USB port drivers
+#
+CONFIG_USB_SERIAL=m
+# CONFIG_USB_EZUSB is not set
+CONFIG_USB_SERIAL_GENERIC=y
+# CONFIG_USB_SERIAL_AIRCABLE is not set
+# CONFIG_USB_SERIAL_ARK3116 is not set
+# CONFIG_USB_SERIAL_BELKIN is not set
+# CONFIG_USB_SERIAL_CH341 is not set
+# CONFIG_USB_SERIAL_WHITEHEAT is not set
+# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
+# CONFIG_USB_SERIAL_CP2101 is not set
+# CONFIG_USB_SERIAL_CYPRESS_M8 is not set
+# CONFIG_USB_SERIAL_EMPEG is not set
+# CONFIG_USB_SERIAL_FTDI_SIO is not set
+# CONFIG_USB_SERIAL_FUNSOFT is not set
+# CONFIG_USB_SERIAL_VISOR is not set
+# CONFIG_USB_SERIAL_IPAQ is not set
+# CONFIG_USB_SERIAL_IR is not set
+# CONFIG_USB_SERIAL_EDGEPORT is not set
+# CONFIG_USB_SERIAL_EDGEPORT_TI is not set
+# CONFIG_USB_SERIAL_GARMIN is not set
+# CONFIG_USB_SERIAL_IPW is not set
+# CONFIG_USB_SERIAL_IUU is not set
+# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
+# CONFIG_USB_SERIAL_KEYSPAN is not set
+# CONFIG_USB_SERIAL_KLSI is not set
+# CONFIG_USB_SERIAL_KOBIL_SCT is not set
+CONFIG_USB_SERIAL_MCT_U232=m
+# CONFIG_USB_SERIAL_MOS7720 is not set
+# CONFIG_USB_SERIAL_MOS7840 is not set
+# CONFIG_USB_SERIAL_MOTOROLA is not set
+# CONFIG_USB_SERIAL_NAVMAN is not set
+# CONFIG_USB_SERIAL_PL2303 is not set
+# CONFIG_USB_SERIAL_OTI6858 is not set
+# CONFIG_USB_SERIAL_SPCP8X5 is not set
+# CONFIG_USB_SERIAL_HP4X is not set
+# CONFIG_USB_SERIAL_SAFE is not set
+# CONFIG_USB_SERIAL_SIERRAWIRELESS is not set
+# CONFIG_USB_SERIAL_TI is not set
+# CONFIG_USB_SERIAL_CYBERJACK is not set
+# CONFIG_USB_SERIAL_XIRCOM is not set
+# CONFIG_USB_SERIAL_OPTION is not set
+# CONFIG_USB_SERIAL_OMNINET is not set
+# CONFIG_USB_SERIAL_DEBUG is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_ADUTUX is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_BERRY_CHARGE is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_PHIDGET is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_FTDI_ELAN is not set
+# CONFIG_USB_APPLEDISPLAY is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_IOWARRIOR is not set
+# CONFIG_USB_TEST is not set
+# CONFIG_USB_ISIGHTFW is not set
+CONFIG_USB_GADGET=m
+# CONFIG_USB_GADGET_DEBUG is not set
+# CONFIG_USB_GADGET_DEBUG_FILES is not set
+CONFIG_USB_GADGET_SELECTED=y
+# CONFIG_USB_GADGET_AMD5536UDC is not set
+# CONFIG_USB_GADGET_ATMEL_USBA is not set
+# CONFIG_USB_GADGET_FSL_USB2 is not set
+# CONFIG_USB_GADGET_NET2280 is not set
+CONFIG_USB_GADGET_PXA25X=y
+CONFIG_USB_PXA25X=m
+# CONFIG_USB_PXA25X_SMALL is not set
+# CONFIG_USB_GADGET_M66592 is not set
+# CONFIG_USB_GADGET_PXA27X is not set
+# CONFIG_USB_GADGET_GOKU is not set
+# CONFIG_USB_GADGET_LH7A40X is not set
+# CONFIG_USB_GADGET_OMAP is not set
+# CONFIG_USB_GADGET_S3C2410 is not set
+# CONFIG_USB_GADGET_AT91 is not set
+# CONFIG_USB_GADGET_DUMMY_HCD is not set
+# CONFIG_USB_GADGET_DUALSPEED is not set
+# CONFIG_USB_ZERO is not set
+CONFIG_USB_ETH=m
+CONFIG_USB_ETH_RNDIS=y
+CONFIG_USB_GADGETFS=m
+CONFIG_USB_FILE_STORAGE=m
+# CONFIG_USB_FILE_STORAGE_TEST is not set
+CONFIG_USB_G_SERIAL=m
+# CONFIG_USB_MIDI_GADGET is not set
+CONFIG_USB_G_PRINTER=m
+# CONFIG_USB_CDC_COMPOSITE is not set
+# CONFIG_MMC is not set
+# CONFIG_NEW_LEDS is not set
+CONFIG_RTC_LIB=y
+CONFIG_RTC_CLASS=m
+
+#
+# RTC interfaces
+#
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_DEV=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+# CONFIG_RTC_DRV_TEST is not set
+
+#
+# I2C RTC drivers
+#
+CONFIG_RTC_DRV_DS1307=m
+# CONFIG_RTC_DRV_DS1374 is not set
+# CONFIG_RTC_DRV_DS1672 is not set
+# CONFIG_RTC_DRV_MAX6900 is not set
+# CONFIG_RTC_DRV_RS5C372 is not set
+# CONFIG_RTC_DRV_ISL1208 is not set
+# CONFIG_RTC_DRV_X1205 is not set
+# CONFIG_RTC_DRV_PCF8563 is not set
+# CONFIG_RTC_DRV_PCF8583 is not set
+# CONFIG_RTC_DRV_M41T80 is not set
+# CONFIG_RTC_DRV_S35390A is not set
+# CONFIG_RTC_DRV_FM3130 is not set
+
+#
+# SPI RTC drivers
+#
+
+#
+# Platform RTC drivers
+#
+# CONFIG_RTC_DRV_CMOS is not set
+# CONFIG_RTC_DRV_DS1511 is not set
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_STK17TA8 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_M48T59 is not set
+# CONFIG_RTC_DRV_V3020 is not set
+
+#
+# on-CPU RTC drivers
+#
+CONFIG_RTC_DRV_SA1100=m
+# CONFIG_DMADEVICES is not set
+
+#
+# Voltage and Current regulators
+#
+# CONFIG_REGULATOR is not set
+# CONFIG_REGULATOR_FIXED_VOLTAGE is not set
+# CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set
+# CONFIG_REGULATOR_BQ24022 is not set
+# CONFIG_UIO is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=m
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT3_FS=m
+# CONFIG_EXT3_FS_XATTR is not set
+# CONFIG_EXT4DEV_FS is not set
+CONFIG_JBD=m
+# 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_DNOTIFY is not set
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+# 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_FAT_FS=m
+# CONFIG_MSDOS_FS is not set
+CONFIG_VFAT_FS=m
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+# 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_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_FS_WBUF_VERIFY is not set
+# CONFIG_JFFS2_SUMMARY is not set
+# CONFIG_JFFS2_FS_XATTR is not set
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+# CONFIG_JFFS2_LZO is not set
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_OMFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+CONFIG_NETWORK_FILESYSTEMS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+# CONFIG_NFS_V4 is not set
+CONFIG_ROOT_NFS=y
+CONFIG_NFSD=m
+CONFIG_NFSD_V3=y
+# CONFIG_NFSD_V3_ACL is not set
+# CONFIG_NFSD_V4 is not set
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_EXPORTFS=m
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# 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
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_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
+# CONFIG_SYSV68_PARTITION is not set
+CONFIG_NLS=m
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=m
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+CONFIG_NLS_CODEPAGE_850=m
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+CONFIG_NLS_ISO8859_1=m
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+CONFIG_NLS_ISO8859_15=m
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+CONFIG_NLS_UTF8=m
+# CONFIG_DLM is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_FRAME_WARN=1024
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
+CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set
+CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0
+CONFIG_SCHED_DEBUG=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_TIMER_STATS is not set
+# CONFIG_DEBUG_OBJECTS is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+CONFIG_DEBUG_MUTEXES=y
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_KOBJECT is not set
+CONFIG_DEBUG_BUGVERBOSE=y
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_WRITECOUNT is not set
+# CONFIG_DEBUG_MEMORY_INIT is not set
+# CONFIG_DEBUG_LIST is not set
+# CONFIG_DEBUG_SG is not set
+CONFIG_FRAME_POINTER=y
+# CONFIG_BOOT_PRINTK_DELAY is not set
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_BACKTRACE_SELF_TEST is not set
+# CONFIG_FAULT_INJECTION is not set
+# CONFIG_LATENCYTOP is not set
+CONFIG_SYSCTL_SYSCALL_CHECK=y
+CONFIG_HAVE_FTRACE=y
+CONFIG_HAVE_DYNAMIC_FTRACE=y
+# CONFIG_FTRACE is not set
+# CONFIG_IRQSOFF_TRACER is not set
+# CONFIG_SCHED_TRACER is not set
+# CONFIG_CONTEXT_SWITCH_TRACER is not set
+# CONFIG_SAMPLES is not set
+CONFIG_HAVE_ARCH_KGDB=y
+# CONFIG_KGDB is not set
+# CONFIG_DEBUG_USER is not set
+CONFIG_DEBUG_ERRORS=y
+# CONFIG_DEBUG_STACK_USAGE is not set
+# CONFIG_DEBUG_LL is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+# CONFIG_SECURITY_FILE_CAPABILITIES is not set
+CONFIG_CRYPTO=y
+
+#
+# Crypto core or helper
+#
+CONFIG_CRYPTO_ALGAPI=m
+CONFIG_CRYPTO_BLKCIPHER=m
+CONFIG_CRYPTO_MANAGER=m
+# CONFIG_CRYPTO_GF128MUL is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_CRYPTD is not set
+# CONFIG_CRYPTO_AUTHENC is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Authenticated Encryption with Associated Data
+#
+# CONFIG_CRYPTO_CCM is not set
+# CONFIG_CRYPTO_GCM is not set
+# CONFIG_CRYPTO_SEQIV is not set
+
+#
+# Block modes
+#
+# CONFIG_CRYPTO_CBC is not set
+# CONFIG_CRYPTO_CTR is not set
+# CONFIG_CRYPTO_CTS is not set
+CONFIG_CRYPTO_ECB=m
+# CONFIG_CRYPTO_LRW is not set
+# CONFIG_CRYPTO_PCBC is not set
+# CONFIG_CRYPTO_XTS is not set
+
+#
+# Hash modes
+#
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_XCBC is not set
+
+#
+# Digest
+#
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_MD4 is not set
+# CONFIG_CRYPTO_MD5 is not set
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_RMD128 is not set
+# CONFIG_CRYPTO_RMD160 is not set
+# CONFIG_CRYPTO_RMD256 is not set
+# CONFIG_CRYPTO_RMD320 is not set
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_WP512 is not set
+
+#
+# Ciphers
+#
+# CONFIG_CRYPTO_AES is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+CONFIG_CRYPTO_ARC4=m
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_CAMELLIA is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_DES is not set
+# CONFIG_CRYPTO_FCRYPT is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_SALSA20 is not set
+# CONFIG_CRYPTO_SEED is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+
+#
+# Compression
+#
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_LZO is not set
+CONFIG_CRYPTO_HW=y
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+# CONFIG_GENERIC_FIND_FIRST_BIT is not set
+# CONFIG_GENERIC_FIND_NEXT_BIT is not set
+CONFIG_CRC_CCITT=m
+# CONFIG_CRC16 is not set
+CONFIG_CRC_T10DIF=m
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
diff --git a/arch/arm/configs/xm_x270_defconfig b/arch/arm/configs/xm_x270_defconfig
deleted file mode 100644
index aa40d91..0000000
--- a/arch/arm/configs/xm_x270_defconfig
+++ /dev/null
@@ -1,1741 +0,0 @@
-#
-# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.25
-# Sun May 11 15:12:52 2008
-#
-CONFIG_ARM=y
-CONFIG_SYS_SUPPORTS_APM_EMULATION=y
-CONFIG_GENERIC_GPIO=y
-CONFIG_GENERIC_TIME=y
-CONFIG_GENERIC_CLOCKEVENTS=y
-CONFIG_MMU=y
-# CONFIG_NO_IOPORT is not set
-CONFIG_GENERIC_HARDIRQS=y
-CONFIG_STACKTRACE_SUPPORT=y
-CONFIG_LOCKDEP_SUPPORT=y
-CONFIG_TRACE_IRQFLAGS_SUPPORT=y
-CONFIG_HARDIRQS_SW_RESEND=y
-CONFIG_GENERIC_IRQ_PROBE=y
-CONFIG_RWSEM_GENERIC_SPINLOCK=y
-# CONFIG_ARCH_HAS_ILOG2_U32 is not set
-# CONFIG_ARCH_HAS_ILOG2_U64 is not set
-CONFIG_GENERIC_HWEIGHT=y
-CONFIG_GENERIC_CALIBRATE_DELAY=y
-CONFIG_ARCH_SUPPORTS_AOUT=y
-CONFIG_ZONE_DMA=y
-CONFIG_ARCH_MTD_XIP=y
-CONFIG_VECTORS_BASE=0xffff0000
-CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
-
-#
-# General setup
-#
-CONFIG_EXPERIMENTAL=y
-CONFIG_BROKEN_ON_SMP=y
-CONFIG_INIT_ENV_ARG_LIMIT=32
-CONFIG_LOCALVERSION=""
-# CONFIG_LOCALVERSION_AUTO is not set
-CONFIG_SWAP=y
-CONFIG_SYSVIPC=y
-CONFIG_SYSVIPC_SYSCTL=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=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_LOG_BUF_SHIFT=14
-# CONFIG_CGROUPS is not set
-CONFIG_GROUP_SCHED=y
-CONFIG_FAIR_GROUP_SCHED=y
-# CONFIG_RT_GROUP_SCHED is not set
-CONFIG_USER_SCHED=y
-# CONFIG_CGROUP_SCHED is not set
-CONFIG_SYSFS_DEPRECATED=y
-CONFIG_SYSFS_DEPRECATED_V2=y
-# CONFIG_RELAY is not set
-# CONFIG_NAMESPACES is not set
-CONFIG_BLK_DEV_INITRD=y
-CONFIG_INITRAMFS_SOURCE=""
-CONFIG_CC_OPTIMIZE_FOR_SIZE=y
-CONFIG_SYSCTL=y
-CONFIG_EMBEDDED=y
-CONFIG_UID16=y
-CONFIG_SYSCTL_SYSCALL=y
-CONFIG_SYSCTL_SYSCALL_CHECK=y
-CONFIG_KALLSYMS=y
-# CONFIG_KALLSYMS_ALL is not set
-# CONFIG_KALLSYMS_EXTRA_PASS is not set
-CONFIG_HOTPLUG=y
-CONFIG_PRINTK=y
-CONFIG_BUG=y
-CONFIG_ELF_CORE=y
-# CONFIG_COMPAT_BRK is not set
-CONFIG_BASE_FULL=y
-CONFIG_FUTEX=y
-CONFIG_ANON_INODES=y
-CONFIG_EPOLL=y
-CONFIG_SIGNALFD=y
-CONFIG_TIMERFD=y
-CONFIG_EVENTFD=y
-CONFIG_SHMEM=y
-# CONFIG_VM_EVENT_COUNTERS is not set
-# CONFIG_SLUB_DEBUG is not set
-# CONFIG_SLAB is not set
-CONFIG_SLUB=y
-# CONFIG_SLOB is not set
-# CONFIG_PROFILING is not set
-# CONFIG_MARKERS is not set
-CONFIG_HAVE_OPROFILE=y
-# CONFIG_KPROBES is not set
-CONFIG_HAVE_KPROBES=y
-CONFIG_HAVE_KRETPROBES=y
-# CONFIG_HAVE_DMA_ATTRS is not set
-# CONFIG_PROC_PAGE_MONITOR is not set
-CONFIG_RT_MUTEXES=y
-# CONFIG_TINY_SHMEM is not set
-CONFIG_BASE_SMALL=0
-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=y
-CONFIG_BLOCK=y
-# CONFIG_LBD is not set
-# CONFIG_BLK_DEV_IO_TRACE is not set
-# CONFIG_LSF is not set
-# CONFIG_BLK_DEV_BSG is not set
-
-#
-# IO Schedulers
-#
-CONFIG_IOSCHED_NOOP=y
-CONFIG_IOSCHED_AS=y
-CONFIG_IOSCHED_DEADLINE=y
-CONFIG_IOSCHED_CFQ=y
-# CONFIG_DEFAULT_AS is not set
-# CONFIG_DEFAULT_DEADLINE is not set
-CONFIG_DEFAULT_CFQ=y
-# CONFIG_DEFAULT_NOOP is not set
-CONFIG_DEFAULT_IOSCHED="cfq"
-CONFIG_CLASSIC_RCU=y
-
-#
-# System Type
-#
-# CONFIG_ARCH_AAEC2000 is not set
-# CONFIG_ARCH_INTEGRATOR is not set
-# CONFIG_ARCH_REALVIEW is not set
-# CONFIG_ARCH_VERSATILE is not set
-# CONFIG_ARCH_AT91 is not set
-# CONFIG_ARCH_CLPS7500 is not set
-# CONFIG_ARCH_CLPS711X is not set
-# CONFIG_ARCH_CO285 is not set
-# CONFIG_ARCH_EBSA110 is not set
-# CONFIG_ARCH_EP93XX is not set
-# CONFIG_ARCH_FOOTBRIDGE is not set
-# CONFIG_ARCH_NETX is not set
-# CONFIG_ARCH_H720X is not set
-# CONFIG_ARCH_IMX is not set
-# CONFIG_ARCH_IOP13XX is not set
-# CONFIG_ARCH_IOP32X is not set
-# CONFIG_ARCH_IOP33X is not set
-# CONFIG_ARCH_IXP23XX is not set
-# CONFIG_ARCH_IXP2000 is not set
-# CONFIG_ARCH_IXP4XX is not set
-# CONFIG_ARCH_L7200 is not set
-# CONFIG_ARCH_KS8695 is not set
-# CONFIG_ARCH_NS9XXX is not set
-# CONFIG_ARCH_MXC is not set
-# CONFIG_ARCH_ORION5X is not set
-# CONFIG_ARCH_PNX4008 is not set
-CONFIG_ARCH_PXA=y
-# CONFIG_ARCH_RPC is not set
-# CONFIG_ARCH_SA1100 is not set
-# CONFIG_ARCH_S3C2410 is not set
-# CONFIG_ARCH_SHARK is not set
-# CONFIG_ARCH_LH7A40X is not set
-# CONFIG_ARCH_DAVINCI is not set
-# CONFIG_ARCH_OMAP is not set
-# CONFIG_ARCH_MSM7X00A is not set
-CONFIG_DMABOUNCE=y
-
-#
-# Intel PXA2xx/PXA3xx Implementations
-#
-
-#
-# Select target boards
-#
-# CONFIG_ARCH_GUMSTIX is not set
-# CONFIG_ARCH_LUBBOCK is not set
-# CONFIG_MACH_LOGICPD_PXA270 is not set
-# CONFIG_MACH_MAINSTONE is not set
-# CONFIG_ARCH_PXA_IDP is not set
-# CONFIG_PXA_SHARPSL is not set
-# CONFIG_ARCH_PXA_ESERIES is not set
-# CONFIG_MACH_TRIZEPS4 is not set
-CONFIG_MACH_EM_X270=y
-# CONFIG_MACH_COLIBRI is not set
-# CONFIG_MACH_ZYLONITE is not set
-# CONFIG_MACH_LITTLETON is not set
-CONFIG_MACH_ARMCORE=y
-# CONFIG_MACH_MAGICIAN is not set
-# CONFIG_MACH_PCM027 is not set
-CONFIG_PXA27x=y
-# CONFIG_PXA_PWM is not set
-
-#
-# Boot options
-#
-
-#
-# Power management
-#
-
-#
-# Processor Type
-#
-CONFIG_CPU_32=y
-CONFIG_CPU_XSCALE=y
-CONFIG_CPU_32v5=y
-CONFIG_CPU_ABRT_EV5T=y
-CONFIG_CPU_PABRT_NOIFAR=y
-CONFIG_CPU_CACHE_VIVT=y
-CONFIG_CPU_TLB_V4WBI=y
-CONFIG_CPU_CP15=y
-CONFIG_CPU_CP15_MMU=y
-
-#
-# Processor Features
-#
-CONFIG_ARM_THUMB=y
-# CONFIG_CPU_DCACHE_DISABLE is not set
-# CONFIG_OUTER_CACHE is not set
-CONFIG_IWMMXT=y
-CONFIG_XSCALE_PMU=y
-
-#
-# Bus support
-#
-CONFIG_PCI=y
-CONFIG_PCI_SYSCALL=y
-CONFIG_PCI_HOST_ITE8152=y
-# CONFIG_ARCH_SUPPORTS_MSI is not set
-CONFIG_PCI_LEGACY=y
-# CONFIG_PCI_DEBUG is not set
-CONFIG_PCCARD=m
-# CONFIG_PCMCIA_DEBUG is not set
-CONFIG_PCMCIA=m
-CONFIG_PCMCIA_LOAD_CIS=y
-CONFIG_PCMCIA_IOCTL=y
-CONFIG_CARDBUS=y
-
-#
-# PC-card bridges
-#
-CONFIG_YENTA=m
-# CONFIG_YENTA_O2 is not set
-# CONFIG_YENTA_RICOH is not set
-CONFIG_YENTA_TI=y
-# CONFIG_YENTA_ENE_TUNE is not set
-# CONFIG_YENTA_TOSHIBA is not set
-# CONFIG_PD6729 is not set
-# CONFIG_I82092 is not set
-CONFIG_PCMCIA_PXA2XX=m
-CONFIG_PCCARD_NONSTATIC=m
-
-#
-# Kernel Features
-#
-CONFIG_TICK_ONESHOT=y
-CONFIG_NO_HZ=y
-# CONFIG_HIGH_RES_TIMERS is not set
-CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
-# CONFIG_PREEMPT is not set
-CONFIG_HZ=100
-CONFIG_AEABI=y
-CONFIG_OABI_COMPAT=y
-# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
-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_SPARSEMEM_VMEMMAP_ENABLE is not set
-CONFIG_PAGEFLAGS_EXTENDED=y
-CONFIG_SPLIT_PTLOCK_CPUS=4096
-# CONFIG_RESOURCES_64BIT is not set
-CONFIG_ZONE_DMA_FLAG=1
-CONFIG_BOUNCE=y
-CONFIG_VIRT_TO_BUS=y
-CONFIG_ALIGNMENT_TRAP=y
-
-#
-# Boot options
-#
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
-CONFIG_CMDLINE="root=1f03 mem=32M"
-# CONFIG_XIP_KERNEL is not set
-# CONFIG_KEXEC is not set
-
-#
-# CPU Frequency scaling
-#
-# CONFIG_CPU_FREQ is not set
-
-#
-# Floating point emulation
-#
-
-#
-# At least one emulation must be selected
-#
-CONFIG_FPE_NWFPE=y
-# CONFIG_FPE_NWFPE_XP is not set
-# CONFIG_FPE_FASTFPE is not set
-
-#
-# Userspace binary formats
-#
-CONFIG_BINFMT_ELF=y
-# CONFIG_BINFMT_AOUT is not set
-# CONFIG_BINFMT_MISC is not set
-
-#
-# Power management options
-#
-CONFIG_PM=y
-# CONFIG_PM_DEBUG is not set
-CONFIG_PM_SLEEP=y
-CONFIG_SUSPEND=y
-CONFIG_SUSPEND_FREEZER=y
-CONFIG_APM_EMULATION=m
-CONFIG_ARCH_SUSPEND_POSSIBLE=y
-
-#
-# Networking
-#
-CONFIG_NET=y
-
-#
-# Networking options
-#
-CONFIG_PACKET=y
-CONFIG_PACKET_MMAP=y
-CONFIG_UNIX=y
-CONFIG_XFRM=y
-# CONFIG_XFRM_USER is not set
-# CONFIG_XFRM_SUB_POLICY is not set
-# CONFIG_XFRM_MIGRATE is not set
-# CONFIG_XFRM_STATISTICS 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 is not set
-# 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_XFRM_MODE_BEET=y
-# CONFIG_INET_LRO is not set
-# CONFIG_INET_DIAG is not set
-# CONFIG_TCP_CONG_ADVANCED is not set
-CONFIG_TCP_CONG_CUBIC=y
-CONFIG_DEFAULT_TCP_CONG="cubic"
-# CONFIG_TCP_MD5SIG is not set
-# CONFIG_IPV6 is not set
-# CONFIG_NETWORK_SECMARK is not set
-# CONFIG_NETFILTER is not set
-# CONFIG_IP_DCCP is not set
-# CONFIG_IP_SCTP is not set
-# 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
-# CONFIG_NET_SCHED is not set
-
-#
-# Network testing
-#
-# CONFIG_NET_PKTGEN is not set
-# CONFIG_HAMRADIO is not set
-# CONFIG_CAN is not set
-# CONFIG_IRDA is not set
-CONFIG_BT=m
-CONFIG_BT_L2CAP=m
-CONFIG_BT_SCO=m
-CONFIG_BT_RFCOMM=m
-# CONFIG_BT_RFCOMM_TTY is not set
-CONFIG_BT_BNEP=m
-# CONFIG_BT_BNEP_MC_FILTER is not set
-# CONFIG_BT_BNEP_PROTO_FILTER is not set
-CONFIG_BT_HIDP=m
-
-#
-# Bluetooth device drivers
-#
-CONFIG_BT_HCIUSB=m
-CONFIG_BT_HCIUSB_SCO=y
-# CONFIG_BT_HCIBTSDIO is not set
-# CONFIG_BT_HCIUART is not set
-# CONFIG_BT_HCIBCM203X is not set
-# CONFIG_BT_HCIBPA10X is not set
-# CONFIG_BT_HCIBFUSB is not set
-# CONFIG_BT_HCIDTL1 is not set
-# CONFIG_BT_HCIBT3C is not set
-# CONFIG_BT_HCIBLUECARD is not set
-# CONFIG_BT_HCIBTUART is not set
-# CONFIG_BT_HCIVHCI is not set
-# CONFIG_AF_RXRPC is not set
-
-#
-# Wireless
-#
-# CONFIG_CFG80211 is not set
-CONFIG_WIRELESS_EXT=y
-# CONFIG_MAC80211 is not set
-# CONFIG_IEEE80211 is not set
-# CONFIG_RFKILL is not set
-# CONFIG_NET_9P is not set
-
-#
-# Device Drivers
-#
-
-#
-# Generic Driver Options
-#
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
-CONFIG_STANDALONE=y
-CONFIG_PREVENT_FIRMWARE_BUILD=y
-CONFIG_FW_LOADER=m
-# CONFIG_DEBUG_DRIVER is not set
-# CONFIG_DEBUG_DEVRES is not set
-# CONFIG_SYS_HYPERVISOR is not set
-# CONFIG_CONNECTOR is not set
-CONFIG_MTD=y
-# CONFIG_MTD_DEBUG is not set
-# CONFIG_MTD_CONCAT is not set
-CONFIG_MTD_PARTITIONS=y
-# CONFIG_MTD_REDBOOT_PARTS is not set
-CONFIG_MTD_CMDLINE_PARTS=y
-# CONFIG_MTD_AFS_PARTS is not set
-# CONFIG_MTD_AR7_PARTS is not set
-
-#
-# User Modules And Translation Layers
-#
-CONFIG_MTD_CHAR=y
-CONFIG_MTD_BLKDEVS=y
-CONFIG_MTD_BLOCK=y
-# CONFIG_FTL is not set
-# CONFIG_NFTL is not set
-# CONFIG_INFTL is not set
-# CONFIG_RFD_FTL is not set
-# CONFIG_SSFDC is not set
-# CONFIG_MTD_OOPS is not set
-
-#
-# RAM/ROM/Flash chip drivers
-#
-CONFIG_MTD_CFI=y
-CONFIG_MTD_JEDECPROBE=y
-CONFIG_MTD_GEN_PROBE=y
-CONFIG_MTD_CFI_ADV_OPTIONS=y
-CONFIG_MTD_CFI_NOSWAP=y
-# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set
-# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set
-# CONFIG_MTD_CFI_GEOMETRY is not set
-CONFIG_MTD_MAP_BANK_WIDTH_1=y
-CONFIG_MTD_MAP_BANK_WIDTH_2=y
-CONFIG_MTD_MAP_BANK_WIDTH_4=y
-# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
-# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
-# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
-CONFIG_MTD_CFI_I1=y
-CONFIG_MTD_CFI_I2=y
-# CONFIG_MTD_CFI_I4 is not set
-# CONFIG_MTD_CFI_I8 is not set
-# CONFIG_MTD_OTP is not set
-CONFIG_MTD_CFI_INTELEXT=y
-CONFIG_MTD_CFI_AMDSTD=y
-CONFIG_MTD_CFI_STAA=y
-CONFIG_MTD_CFI_UTIL=y
-# CONFIG_MTD_RAM is not set
-# CONFIG_MTD_ROM is not set
-# CONFIG_MTD_ABSENT is not set
-# CONFIG_MTD_XIP is not set
-
-#
-# Mapping drivers for chip access
-#
-# CONFIG_MTD_COMPLEX_MAPPINGS is not set
-CONFIG_MTD_PHYSMAP=y
-CONFIG_MTD_PHYSMAP_START=0x0
-CONFIG_MTD_PHYSMAP_LEN=0x400000
-CONFIG_MTD_PHYSMAP_BANKWIDTH=2
-CONFIG_MTD_PXA2XX=y
-# CONFIG_MTD_ARM_INTEGRATOR is not set
-# CONFIG_MTD_IMPA7 is not set
-# CONFIG_MTD_SHARP_SL is not set
-# CONFIG_MTD_INTEL_VR_NOR is not set
-# CONFIG_MTD_PLATRAM is not set
-
-#
-# Self-contained MTD device drivers
-#
-# CONFIG_MTD_PMC551 is not set
-# CONFIG_MTD_SLRAM is not set
-# CONFIG_MTD_PHRAM is not set
-# CONFIG_MTD_MTDRAM is not set
-# CONFIG_MTD_BLOCK2MTD is not set
-
-#
-# Disk-On-Chip Device Drivers
-#
-# CONFIG_MTD_DOC2000 is not set
-# CONFIG_MTD_DOC2001 is not set
-# CONFIG_MTD_DOC2001PLUS is not set
-CONFIG_MTD_NAND=y
-# CONFIG_MTD_NAND_VERIFY_WRITE is not set
-# CONFIG_MTD_NAND_ECC_SMC is not set
-# CONFIG_MTD_NAND_MUSEUM_IDS is not set
-# CONFIG_MTD_NAND_H1900 is not set
-CONFIG_MTD_NAND_IDS=y
-# CONFIG_MTD_NAND_DISKONCHIP is not set
-# CONFIG_MTD_NAND_SHARPSL is not set
-# CONFIG_MTD_NAND_CAFE is not set
-CONFIG_MTD_NAND_CM_X270=y
-# CONFIG_MTD_NAND_NANDSIM is not set
-CONFIG_MTD_NAND_PLATFORM=y
-# CONFIG_MTD_ALAUDA is not set
-# CONFIG_MTD_ONENAND is not set
-
-#
-# UBI - Unsorted block images
-#
-# CONFIG_MTD_UBI is not set
-# CONFIG_PARPORT is not set
-CONFIG_BLK_DEV=y
-# 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_UB is not set
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_COUNT=16
-CONFIG_BLK_DEV_RAM_SIZE=4096
-# CONFIG_BLK_DEV_XIP is not set
-# CONFIG_CDROM_PKTCDVD is not set
-# CONFIG_ATA_OVER_ETH is not set
-# CONFIG_MISC_DEVICES is not set
-CONFIG_HAVE_IDE=y
-# CONFIG_IDE is not set
-
-#
-# SCSI device support
-#
-# CONFIG_RAID_ATTRS is not set
-CONFIG_SCSI=y
-CONFIG_SCSI_DMA=y
-# CONFIG_SCSI_TGT is not set
-# CONFIG_SCSI_NETLINK is not set
-CONFIG_SCSI_PROC_FS=y
-
-#
-# SCSI support type (disk, tape, CD-ROM)
-#
-CONFIG_BLK_DEV_SD=y
-# CONFIG_CHR_DEV_ST is not set
-# CONFIG_CHR_DEV_OSST is not set
-# CONFIG_BLK_DEV_SR is not set
-# CONFIG_CHR_DEV_SG is not set
-# CONFIG_CHR_DEV_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
-# CONFIG_SCSI_SCAN_ASYNC is not set
-CONFIG_SCSI_WAIT_SCAN=m
-
-#
-# SCSI Transports
-#
-# CONFIG_SCSI_SPI_ATTRS is not set
-# CONFIG_SCSI_FC_ATTRS is not set
-# CONFIG_SCSI_ISCSI_ATTRS is not set
-# CONFIG_SCSI_SAS_LIBSAS is not set
-# CONFIG_SCSI_SRP_ATTRS is not set
-CONFIG_SCSI_LOWLEVEL=y
-# 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_AIC94XX is not set
-# CONFIG_SCSI_DPT_I2O is not set
-# CONFIG_SCSI_ADVANSYS is not set
-# CONFIG_SCSI_ARCMSR is not set
-# CONFIG_MEGARAID_NEWGEN is not set
-# CONFIG_MEGARAID_LEGACY is not set
-# CONFIG_MEGARAID_SAS is not set
-# CONFIG_SCSI_HPTIOP is not set
-# CONFIG_SCSI_DMX3191D is not set
-# CONFIG_SCSI_FUTURE_DOMAIN is not set
-# CONFIG_SCSI_IPS is not set
-# CONFIG_SCSI_INITIO is not set
-# CONFIG_SCSI_INIA100 is not set
-# CONFIG_SCSI_MVSAS is not set
-# CONFIG_SCSI_STEX 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_QLA_ISCSI 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
-# CONFIG_SCSI_SRP is not set
-# CONFIG_SCSI_LOWLEVEL_PCMCIA is not set
-CONFIG_ATA=m
-# CONFIG_ATA_NONSTANDARD is not set
-# CONFIG_SATA_PMP is not set
-# CONFIG_SATA_AHCI is not set
-# CONFIG_SATA_SIL24 is not set
-CONFIG_ATA_SFF=y
-# CONFIG_SATA_SVW is not set
-# CONFIG_ATA_PIIX is not set
-# CONFIG_SATA_MV is not set
-# CONFIG_SATA_NV is not set
-# CONFIG_PDC_ADMA is not set
-# CONFIG_SATA_QSTOR is not set
-# CONFIG_SATA_PROMISE is not set
-# CONFIG_SATA_SX4 is not set
-# CONFIG_SATA_SIL is not set
-# CONFIG_SATA_SIS is not set
-# CONFIG_SATA_ULI is not set
-# CONFIG_SATA_VIA is not set
-# CONFIG_SATA_VITESSE is not set
-# CONFIG_SATA_INIC162X is not set
-# CONFIG_PATA_ALI is not set
-# CONFIG_PATA_AMD is not set
-# CONFIG_PATA_ARTOP is not set
-# CONFIG_PATA_ATIIXP is not set
-# CONFIG_PATA_CMD640_PCI is not set
-# CONFIG_PATA_CMD64X is not set
-# CONFIG_PATA_CS5520 is not set
-# CONFIG_PATA_CS5530 is not set
-# CONFIG_PATA_CYPRESS is not set
-# CONFIG_PATA_EFAR is not set
-# CONFIG_ATA_GENERIC is not set
-# CONFIG_PATA_HPT366 is not set
-# CONFIG_PATA_HPT37X is not set
-# CONFIG_PATA_HPT3X2N is not set
-# CONFIG_PATA_HPT3X3 is not set
-# CONFIG_PATA_IT821X is not set
-# CONFIG_PATA_IT8213 is not set
-# CONFIG_PATA_JMICRON is not set
-# CONFIG_PATA_TRIFLEX is not set
-# CONFIG_PATA_MARVELL is not set
-# CONFIG_PATA_MPIIX is not set
-# CONFIG_PATA_OLDPIIX is not set
-# CONFIG_PATA_NETCELL is not set
-# CONFIG_PATA_NINJA32 is not set
-# CONFIG_PATA_NS87410 is not set
-# CONFIG_PATA_NS87415 is not set
-# CONFIG_PATA_OPTI is not set
-# CONFIG_PATA_OPTIDMA is not set
-CONFIG_PATA_PCMCIA=m
-# CONFIG_PATA_PDC_OLD is not set
-# CONFIG_PATA_RADISYS is not set
-# CONFIG_PATA_RZ1000 is not set
-# CONFIG_PATA_SC1200 is not set
-# CONFIG_PATA_SERVERWORKS is not set
-# CONFIG_PATA_PDC2027X is not set
-# CONFIG_PATA_SIL680 is not set
-# CONFIG_PATA_SIS is not set
-# CONFIG_PATA_VIA is not set
-# CONFIG_PATA_WINBOND is not set
-# CONFIG_PATA_PLATFORM is not set
-# CONFIG_MD is not set
-# CONFIG_FUSION is not set
-
-#
-# IEEE 1394 (FireWire) support
-#
-# CONFIG_FIREWIRE is not set
-# CONFIG_IEEE1394 is not set
-# CONFIG_I2O is not set
-CONFIG_NETDEVICES=y
-# CONFIG_NETDEVICES_MULTIQUEUE is not set
-# CONFIG_DUMMY is not set
-# CONFIG_BONDING is not set
-# CONFIG_MACVLAN is not set
-# CONFIG_EQUALIZER is not set
-# CONFIG_TUN is not set
-# CONFIG_VETH is not set
-# CONFIG_ARCNET is not set
-# CONFIG_PHYLIB is not set
-CONFIG_NET_ETHERNET=y
-CONFIG_MII=y
-# CONFIG_AX88796 is not set
-# CONFIG_HAPPYMEAL is not set
-# CONFIG_SUNGEM is not set
-# CONFIG_CASSINI is not set
-# CONFIG_NET_VENDOR_3COM is not set
-# CONFIG_SMC91X is not set
-CONFIG_DM9000=y
-CONFIG_DM9000_DEBUGLEVEL=1
-# CONFIG_SMC911X is not set
-# CONFIG_NET_TULIP is not set
-# CONFIG_HP100 is not set
-# CONFIG_IBM_NEW_EMAC_ZMII is not set
-# CONFIG_IBM_NEW_EMAC_RGMII is not set
-# CONFIG_IBM_NEW_EMAC_TAH is not set
-# CONFIG_IBM_NEW_EMAC_EMAC4 is not set
-CONFIG_NET_PCI=y
-# CONFIG_PCNET32 is not set
-# CONFIG_AMD8111_ETH is not set
-# CONFIG_ADAPTEC_STARFIRE is not set
-# CONFIG_B44 is not set
-# CONFIG_FORCEDETH is not set
-# CONFIG_EEPRO100 is not set
-# CONFIG_E100 is not set
-# CONFIG_FEALNX is not set
-# CONFIG_NATSEMI is not set
-# CONFIG_NE2K_PCI is not set
-# CONFIG_8139CP is not set
-CONFIG_8139TOO=y
-# CONFIG_8139TOO_PIO is not set
-# CONFIG_8139TOO_TUNE_TWISTER is not set
-# CONFIG_8139TOO_8129 is not set
-# CONFIG_8139_OLD_RX_RESET is not set
-# CONFIG_R6040 is not set
-# CONFIG_SIS900 is not set
-# CONFIG_EPIC100 is not set
-# CONFIG_SUNDANCE is not set
-# CONFIG_TLAN is not set
-# CONFIG_VIA_RHINE is not set
-# CONFIG_SC92031 is not set
-# CONFIG_NETDEV_1000 is not set
-# CONFIG_NETDEV_10000 is not set
-# CONFIG_TR is not set
-
-#
-# Wireless LAN
-#
-# CONFIG_WLAN_PRE80211 is not set
-CONFIG_WLAN_80211=y
-# CONFIG_PCMCIA_RAYCS is not set
-# CONFIG_IPW2100 is not set
-# CONFIG_IPW2200 is not set
-CONFIG_LIBERTAS=m
-# CONFIG_LIBERTAS_USB is not set
-# CONFIG_LIBERTAS_CS is not set
-CONFIG_LIBERTAS_SDIO=m
-# CONFIG_LIBERTAS_DEBUG is not set
-# CONFIG_HERMES is not set
-# CONFIG_ATMEL is not set
-# CONFIG_AIRO_CS is not set
-# CONFIG_PCMCIA_WL3501 is not set
-# CONFIG_PRISM54 is not set
-# CONFIG_USB_ZD1201 is not set
-# CONFIG_USB_NET_RNDIS_WLAN is not set
-# CONFIG_IWLWIFI is not set
-# CONFIG_IWLWIFI_LEDS is not set
-# CONFIG_HOSTAP is not set
-
-#
-# USB Network Adapters
-#
-# CONFIG_USB_CATC is not set
-# CONFIG_USB_KAWETH is not set
-# CONFIG_USB_PEGASUS is not set
-# CONFIG_USB_RTL8150 is not set
-# CONFIG_USB_USBNET is not set
-# CONFIG_NET_PCMCIA is not set
-# CONFIG_WAN is not set
-# CONFIG_FDDI is not set
-# CONFIG_HIPPI is not set
-CONFIG_PPP=m
-CONFIG_PPP_MULTILINK=y
-CONFIG_PPP_FILTER=y
-CONFIG_PPP_ASYNC=m
-# CONFIG_PPP_SYNC_TTY is not set
-CONFIG_PPP_DEFLATE=m
-CONFIG_PPP_BSDCOMP=m
-# CONFIG_PPP_MPPE is not set
-# CONFIG_PPPOE is not set
-# CONFIG_PPPOL2TP is not set
-# CONFIG_SLIP is not set
-CONFIG_SLHC=m
-# CONFIG_NET_FC is not set
-# CONFIG_NETCONSOLE is not set
-# CONFIG_NETPOLL is not set
-# CONFIG_NET_POLL_CONTROLLER is not set
-# CONFIG_ISDN is not set
-
-#
-# Input device support
-#
-CONFIG_INPUT=y
-# CONFIG_INPUT_FF_MEMLESS is not set
-# CONFIG_INPUT_POLLDEV is not set
-
-#
-# Userland interfaces
-#
-CONFIG_INPUT_MOUSEDEV=y
-CONFIG_INPUT_MOUSEDEV_PSAUX=y
-CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
-CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
-# CONFIG_INPUT_JOYDEV is not set
-CONFIG_INPUT_EVDEV=y
-# CONFIG_INPUT_EVBUG is not set
-# CONFIG_INPUT_APMPOWER is not set
-
-#
-# Input Device Drivers
-#
-CONFIG_INPUT_KEYBOARD=y
-CONFIG_KEYBOARD_ATKBD=y
-# CONFIG_KEYBOARD_SUNKBD is not set
-# CONFIG_KEYBOARD_LKKBD is not set
-# CONFIG_KEYBOARD_XTKBD is not set
-# CONFIG_KEYBOARD_NEWTON is not set
-# CONFIG_KEYBOARD_STOWAWAY is not set
-CONFIG_KEYBOARD_PXA27x=m
-# CONFIG_KEYBOARD_GPIO is not set
-# CONFIG_INPUT_MOUSE is not set
-# CONFIG_INPUT_JOYSTICK is not set
-# CONFIG_INPUT_TABLET is not set
-CONFIG_INPUT_TOUCHSCREEN=y
-# CONFIG_TOUCHSCREEN_FUJITSU is not set
-# CONFIG_TOUCHSCREEN_GUNZE is not set
-# CONFIG_TOUCHSCREEN_ELO is not set
-# CONFIG_TOUCHSCREEN_MTOUCH is not set
-# CONFIG_TOUCHSCREEN_MK712 is not set
-# CONFIG_TOUCHSCREEN_PENMOUNT is not set
-# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set
-# CONFIG_TOUCHSCREEN_TOUCHWIN is not set
-CONFIG_TOUCHSCREEN_UCB1400=m
-CONFIG_TOUCHSCREEN_WM97XX=m
-# CONFIG_TOUCHSCREEN_WM9705 is not set
-CONFIG_TOUCHSCREEN_WM9712=y
-# CONFIG_TOUCHSCREEN_WM9713 is not set
-# CONFIG_TOUCHSCREEN_WM97XX_MAINSTONE is not set
-# CONFIG_TOUCHSCREEN_USB_COMPOSITE is not set
-# CONFIG_INPUT_MISC is not set
-
-#
-# Hardware I/O ports
-#
-CONFIG_SERIO=y
-# CONFIG_SERIO_SERPORT is not set
-# CONFIG_SERIO_PCIPS2 is not set
-CONFIG_SERIO_LIBPS2=y
-# CONFIG_SERIO_RAW is not set
-# CONFIG_GAMEPORT is not set
-
-#
-# Character devices
-#
-CONFIG_VT=y
-CONFIG_VT_CONSOLE=y
-CONFIG_HW_CONSOLE=y
-# CONFIG_VT_HW_CONSOLE_BINDING is not set
-CONFIG_DEVKMEM=y
-# CONFIG_SERIAL_NONSTANDARD is not set
-# CONFIG_NOZOMI is not set
-
-#
-# Serial drivers
-#
-# CONFIG_SERIAL_8250 is not set
-
-#
-# Non-8250 serial port support
-#
-CONFIG_SERIAL_PXA=y
-CONFIG_SERIAL_PXA_CONSOLE=y
-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=16
-# CONFIG_IPMI_HANDLER is not set
-# CONFIG_HW_RANDOM is not set
-# CONFIG_NVRAM is not set
-# CONFIG_R3964 is not set
-# CONFIG_APPLICOM is not set
-
-#
-# PCMCIA character devices
-#
-# CONFIG_SYNCLINK_CS is not set
-# CONFIG_CARDMAN_4000 is not set
-# CONFIG_CARDMAN_4040 is not set
-# CONFIG_IPWIRELESS is not set
-# CONFIG_RAW_DRIVER is not set
-# CONFIG_TCG_TPM is not set
-CONFIG_DEVPORT=y
-CONFIG_I2C=y
-CONFIG_I2C_BOARDINFO=y
-CONFIG_I2C_CHARDEV=m
-
-#
-# 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_GPIO is not set
-# CONFIG_I2C_I801 is not set
-# CONFIG_I2C_I810 is not set
-CONFIG_I2C_PXA=y
-# CONFIG_I2C_PXA_SLAVE is not set
-# CONFIG_I2C_PIIX4 is not set
-# 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_SIMTEC is not set
-# CONFIG_I2C_SIS5595 is not set
-# CONFIG_I2C_SIS630 is not set
-# CONFIG_I2C_SIS96X is not set
-# CONFIG_I2C_TAOS_EVM is not set
-# CONFIG_I2C_STUB is not set
-# CONFIG_I2C_TINY_USB is not set
-# CONFIG_I2C_VIA is not set
-# CONFIG_I2C_VIAPRO is not set
-# CONFIG_I2C_VOODOO3 is not set
-# CONFIG_I2C_PCA_PLATFORM is not set
-
-#
-# Miscellaneous I2C Chip support
-#
-# CONFIG_DS1682 is not set
-# CONFIG_SENSORS_EEPROM is not set
-# CONFIG_SENSORS_PCF8574 is not set
-# CONFIG_PCF8575 is not set
-# CONFIG_SENSORS_PCF8591 is not set
-# CONFIG_TPS65010 is not set
-# CONFIG_SENSORS_MAX6875 is not set
-# CONFIG_SENSORS_TSL2550 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
-# CONFIG_SPI is not set
-CONFIG_HAVE_GPIO_LIB=y
-
-#
-# GPIO Support
-#
-# CONFIG_DEBUG_GPIO is not set
-
-#
-# I2C GPIO expanders:
-#
-# CONFIG_GPIO_PCA953X is not set
-# CONFIG_GPIO_PCF857X is not set
-
-#
-# SPI GPIO expanders:
-#
-# CONFIG_W1 is not set
-# CONFIG_POWER_SUPPLY is not set
-# CONFIG_HWMON is not set
-# CONFIG_WATCHDOG is not set
-
-#
-# Sonics Silicon Backplane
-#
-CONFIG_SSB_POSSIBLE=y
-# CONFIG_SSB is not set
-
-#
-# Multifunction device drivers
-#
-# CONFIG_MFD_SM501 is not set
-# CONFIG_MFD_ASIC3 is not set
-# CONFIG_HTC_EGPIO is not set
-# CONFIG_HTC_PASIC3 is not set
-
-#
-# Multimedia devices
-#
-
-#
-# Multimedia core support
-#
-# CONFIG_VIDEO_DEV is not set
-# CONFIG_DVB_CORE is not set
-
-#
-# Multimedia drivers
-#
-# CONFIG_DAB is not set
-
-#
-# Graphics support
-#
-# CONFIG_DRM is not set
-# CONFIG_VGASTATE is not set
-# CONFIG_VIDEO_OUTPUT_CONTROL is not set
-CONFIG_FB=y
-# CONFIG_FIRMWARE_EDID is not set
-# CONFIG_FB_DDC is not set
-CONFIG_FB_CFB_FILLRECT=y
-CONFIG_FB_CFB_COPYAREA=y
-CONFIG_FB_CFB_IMAGEBLIT=y
-# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
-# CONFIG_FB_SYS_FILLRECT is not set
-# CONFIG_FB_SYS_COPYAREA is not set
-# CONFIG_FB_SYS_IMAGEBLIT is not set
-# CONFIG_FB_FOREIGN_ENDIAN is not set
-# CONFIG_FB_SYS_FOPS is not set
-CONFIG_FB_DEFERRED_IO=y
-# CONFIG_FB_SVGALIB is not set
-# CONFIG_FB_MACMODES is not set
-# CONFIG_FB_BACKLIGHT is not set
-# CONFIG_FB_MODE_HELPERS is not set
-# CONFIG_FB_TILEBLITTING is not set
-
-#
-# Frame buffer hardware drivers
-#
-# CONFIG_FB_CIRRUS is not set
-# CONFIG_FB_PM2 is not set
-# CONFIG_FB_CYBER2000 is not set
-# CONFIG_FB_ASILIANT is not set
-# CONFIG_FB_IMSTT is not set
-# CONFIG_FB_S1D13XXX is not set
-# CONFIG_FB_NVIDIA is not set
-# CONFIG_FB_RIVA is not set
-# CONFIG_FB_MATROX is not set
-# CONFIG_FB_RADEON is not set
-# CONFIG_FB_ATY128 is not set
-# CONFIG_FB_ATY is not set
-# CONFIG_FB_S3 is not set
-# CONFIG_FB_SAVAGE is not set
-# CONFIG_FB_SIS is not set
-# CONFIG_FB_NEOMAGIC is not set
-# CONFIG_FB_KYRO is not set
-# CONFIG_FB_3DFX is not set
-# CONFIG_FB_VOODOO1 is not set
-# CONFIG_FB_VT8623 is not set
-# CONFIG_FB_TRIDENT is not set
-# CONFIG_FB_ARK is not set
-# CONFIG_FB_PM3 is not set
-CONFIG_FB_PXA=y
-# CONFIG_FB_PXA_SMARTPANEL is not set
-CONFIG_FB_PXA_PARAMETERS=y
-CONFIG_FB_MBX=m
-# CONFIG_FB_AM200EPD is not set
-# CONFIG_FB_VIRTUAL is not set
-# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
-
-#
-# Display device support
-#
-# CONFIG_DISPLAY_SUPPORT is not set
-
-#
-# Console display driver support
-#
-# CONFIG_VGA_CONSOLE is not set
-CONFIG_DUMMY_CONSOLE=y
-CONFIG_FRAMEBUFFER_CONSOLE=y
-# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set
-# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
-# CONFIG_FONTS is not set
-CONFIG_FONT_8x8=y
-CONFIG_FONT_8x16=y
-CONFIG_LOGO=y
-CONFIG_LOGO_LINUX_MONO=y
-CONFIG_LOGO_LINUX_VGA16=y
-CONFIG_LOGO_LINUX_CLUT224=y
-
-#
-# Sound
-#
-CONFIG_SOUND=m
-
-#
-# Advanced Linux Sound Architecture
-#
-CONFIG_SND=m
-CONFIG_SND_TIMER=m
-CONFIG_SND_PCM=m
-# CONFIG_SND_SEQUENCER is not set
-CONFIG_SND_OSSEMUL=y
-CONFIG_SND_MIXER_OSS=m
-CONFIG_SND_PCM_OSS=m
-CONFIG_SND_PCM_OSS_PLUGINS=y
-# CONFIG_SND_DYNAMIC_MINORS is not set
-CONFIG_SND_SUPPORT_OLD_API=y
-CONFIG_SND_VERBOSE_PROCFS=y
-# CONFIG_SND_VERBOSE_PRINTK is not set
-# CONFIG_SND_DEBUG is not set
-
-#
-# Generic devices
-#
-CONFIG_SND_AC97_CODEC=m
-# CONFIG_SND_DUMMY is not set
-# CONFIG_SND_MTPAV is not set
-# CONFIG_SND_SERIAL_U16550 is not set
-# CONFIG_SND_MPU401 is not set
-
-#
-# PCI devices
-#
-# CONFIG_SND_AD1889 is not set
-# CONFIG_SND_ALS300 is not set
-# CONFIG_SND_ALI5451 is not set
-# CONFIG_SND_ATIIXP is not set
-# CONFIG_SND_ATIIXP_MODEM is not set
-# CONFIG_SND_AU8810 is not set
-# CONFIG_SND_AU8820 is not set
-# CONFIG_SND_AU8830 is not set
-# CONFIG_SND_AW2 is not set
-# CONFIG_SND_AZT3328 is not set
-# CONFIG_SND_BT87X is not set
-# CONFIG_SND_CA0106 is not set
-# CONFIG_SND_CMIPCI is not set
-# CONFIG_SND_OXYGEN is not set
-# CONFIG_SND_CS4281 is not set
-# CONFIG_SND_CS46XX is not set
-# CONFIG_SND_DARLA20 is not set
-# CONFIG_SND_GINA20 is not set
-# CONFIG_SND_LAYLA20 is not set
-# CONFIG_SND_DARLA24 is not set
-# CONFIG_SND_GINA24 is not set
-# CONFIG_SND_LAYLA24 is not set
-# CONFIG_SND_MONA is not set
-# CONFIG_SND_MIA is not set
-# CONFIG_SND_ECHO3G is not set
-# CONFIG_SND_INDIGO is not set
-# CONFIG_SND_INDIGOIO is not set
-# CONFIG_SND_INDIGODJ is not set
-# CONFIG_SND_EMU10K1 is not set
-# CONFIG_SND_EMU10K1X is not set
-# CONFIG_SND_ENS1370 is not set
-# CONFIG_SND_ENS1371 is not set
-# CONFIG_SND_ES1938 is not set
-# CONFIG_SND_ES1968 is not set
-# CONFIG_SND_FM801 is not set
-# CONFIG_SND_HDA_INTEL is not set
-# CONFIG_SND_HDSP is not set
-# CONFIG_SND_HDSPM is not set
-# CONFIG_SND_HIFIER is not set
-# CONFIG_SND_ICE1712 is not set
-# CONFIG_SND_ICE1724 is not set
-# CONFIG_SND_INTEL8X0 is not set
-# CONFIG_SND_INTEL8X0M is not set
-# CONFIG_SND_KORG1212 is not set
-# CONFIG_SND_MAESTRO3 is not set
-# CONFIG_SND_MIXART is not set
-# CONFIG_SND_NM256 is not set
-# CONFIG_SND_PCXHR is not set
-# CONFIG_SND_RIPTIDE is not set
-# CONFIG_SND_RME32 is not set
-# CONFIG_SND_RME96 is not set
-# CONFIG_SND_RME9652 is not set
-# CONFIG_SND_SONICVIBES is not set
-# CONFIG_SND_TRIDENT is not set
-# CONFIG_SND_VIA82XX is not set
-# CONFIG_SND_VIA82XX_MODEM is not set
-# CONFIG_SND_VIRTUOSO is not set
-# CONFIG_SND_VX222 is not set
-# CONFIG_SND_YMFPCI is not set
-# CONFIG_SND_AC97_POWER_SAVE is not set
-
-#
-# ALSA ARM devices
-#
-CONFIG_SND_PXA2XX_PCM=m
-CONFIG_SND_PXA2XX_AC97=m
-
-#
-# USB devices
-#
-# CONFIG_SND_USB_AUDIO is not set
-# CONFIG_SND_USB_CAIAQ is not set
-
-#
-# PCMCIA devices
-#
-# CONFIG_SND_VXPOCKET is not set
-# CONFIG_SND_PDAUDIOCF is not set
-
-#
-# System on Chip audio support
-#
-# CONFIG_SND_SOC is not set
-
-#
-# ALSA SoC audio for Freescale SOCs
-#
-
-#
-# SoC Audio for the Texas Instruments OMAP
-#
-
-#
-# Open Sound System
-#
-# CONFIG_SOUND_PRIME is not set
-CONFIG_AC97_BUS=m
-CONFIG_HID_SUPPORT=y
-CONFIG_HID=y
-CONFIG_HID_DEBUG=y
-# CONFIG_HIDRAW is not set
-
-#
-# USB Input Devices
-#
-CONFIG_USB_HID=y
-# CONFIG_USB_HIDINPUT_POWERBOOK is not set
-# CONFIG_HID_FF is not set
-# CONFIG_USB_HIDDEV is not set
-CONFIG_USB_SUPPORT=y
-CONFIG_USB_ARCH_HAS_HCD=y
-CONFIG_USB_ARCH_HAS_OHCI=y
-CONFIG_USB_ARCH_HAS_EHCI=y
-CONFIG_USB=y
-# CONFIG_USB_DEBUG is not set
-# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set
-
-#
-# Miscellaneous USB options
-#
-CONFIG_USB_DEVICEFS=y
-# CONFIG_USB_DEVICE_CLASS is not set
-# CONFIG_USB_DYNAMIC_MINORS is not set
-# CONFIG_USB_SUSPEND is not set
-# CONFIG_USB_OTG is not set
-# CONFIG_USB_OTG_WHITELIST is not set
-# CONFIG_USB_OTG_BLACKLIST_HUB is not set
-
-#
-# USB Host Controller Drivers
-#
-# CONFIG_USB_EHCI_HCD is not set
-# CONFIG_USB_ISP116X_HCD is not set
-CONFIG_USB_OHCI_HCD=y
-# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set
-# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set
-CONFIG_USB_OHCI_LITTLE_ENDIAN=y
-# CONFIG_USB_UHCI_HCD is not set
-# CONFIG_USB_SL811_HCD is not set
-# CONFIG_USB_R8A66597_HCD is not set
-
-#
-# USB Device Class drivers
-#
-# CONFIG_USB_ACM is not set
-# CONFIG_USB_PRINTER is not set
-
-#
-# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
-#
-
-#
-# may also be needed; see USB_STORAGE Help for more information
-#
-CONFIG_USB_STORAGE=y
-# CONFIG_USB_STORAGE_DEBUG is not set
-# CONFIG_USB_STORAGE_DATAFAB is not set
-# CONFIG_USB_STORAGE_FREECOM is not set
-# CONFIG_USB_STORAGE_ISD200 is not set
-# CONFIG_USB_STORAGE_DPCM is not set
-# CONFIG_USB_STORAGE_USBAT is not set
-# CONFIG_USB_STORAGE_SDDR09 is not set
-# CONFIG_USB_STORAGE_SDDR55 is not set
-# CONFIG_USB_STORAGE_JUMPSHOT is not set
-# CONFIG_USB_STORAGE_ALAUDA is not set
-# CONFIG_USB_STORAGE_ONETOUCH is not set
-# CONFIG_USB_STORAGE_KARMA is not set
-# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set
-# CONFIG_USB_LIBUSUAL is not set
-
-#
-# USB Imaging devices
-#
-# CONFIG_USB_MDC800 is not set
-# CONFIG_USB_MICROTEK is not set
-CONFIG_USB_MON=y
-
-#
-# USB port drivers
-#
-# CONFIG_USB_SERIAL is not set
-
-#
-# USB Miscellaneous drivers
-#
-# CONFIG_USB_EMI62 is not set
-# CONFIG_USB_EMI26 is not set
-# CONFIG_USB_ADUTUX is not set
-# CONFIG_USB_AUERSWALD is not set
-# CONFIG_USB_RIO500 is not set
-# CONFIG_USB_LEGOTOWER is not set
-# CONFIG_USB_LCD is not set
-# CONFIG_USB_BERRY_CHARGE is not set
-# CONFIG_USB_LED is not set
-# CONFIG_USB_CYPRESS_CY7C63 is not set
-# CONFIG_USB_CYTHERM is not set
-# CONFIG_USB_PHIDGET is not set
-# CONFIG_USB_IDMOUSE is not set
-# CONFIG_USB_FTDI_ELAN is not set
-# CONFIG_USB_APPLEDISPLAY is not set
-# CONFIG_USB_LD is not set
-# CONFIG_USB_TRANCEVIBRATOR is not set
-# CONFIG_USB_IOWARRIOR is not set
-# CONFIG_USB_TEST is not set
-# CONFIG_USB_GADGET is not set
-CONFIG_MMC=m
-# CONFIG_MMC_DEBUG is not set
-# CONFIG_MMC_UNSAFE_RESUME is not set
-
-#
-# MMC/SD Card Drivers
-#
-CONFIG_MMC_BLOCK=m
-CONFIG_MMC_BLOCK_BOUNCE=y
-# CONFIG_SDIO_UART is not set
-
-#
-# MMC/SD Host Controller Drivers
-#
-CONFIG_MMC_PXA=m
-# CONFIG_MMC_SDHCI is not set
-# CONFIG_MMC_TIFM_SD is not set
-CONFIG_NEW_LEDS=y
-CONFIG_LEDS_CLASS=y
-
-#
-# LED drivers
-#
-# CONFIG_LEDS_GPIO is not set
-CONFIG_LEDS_CM_X270=y
-
-#
-# LED Triggers
-#
-CONFIG_LEDS_TRIGGERS=y
-# CONFIG_LEDS_TRIGGER_TIMER is not set
-CONFIG_LEDS_TRIGGER_HEARTBEAT=y
-# CONFIG_LEDS_TRIGGER_DEFAULT_ON is not set
-CONFIG_RTC_LIB=y
-CONFIG_RTC_CLASS=y
-CONFIG_RTC_HCTOSYS=y
-CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
-# CONFIG_RTC_DEBUG is not set
-
-#
-# RTC interfaces
-#
-CONFIG_RTC_INTF_SYSFS=y
-CONFIG_RTC_INTF_PROC=y
-CONFIG_RTC_INTF_DEV=y
-# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
-# CONFIG_RTC_DRV_TEST is not set
-
-#
-# I2C RTC drivers
-#
-# CONFIG_RTC_DRV_DS1307 is not set
-# CONFIG_RTC_DRV_DS1374 is not set
-# CONFIG_RTC_DRV_DS1672 is not set
-# CONFIG_RTC_DRV_MAX6900 is not set
-# CONFIG_RTC_DRV_RS5C372 is not set
-# CONFIG_RTC_DRV_ISL1208 is not set
-# CONFIG_RTC_DRV_X1205 is not set
-# CONFIG_RTC_DRV_PCF8563 is not set
-# CONFIG_RTC_DRV_PCF8583 is not set
-# CONFIG_RTC_DRV_M41T80 is not set
-# CONFIG_RTC_DRV_S35390A is not set
-
-#
-# SPI RTC drivers
-#
-
-#
-# Platform RTC drivers
-#
-# CONFIG_RTC_DRV_CMOS is not set
-# CONFIG_RTC_DRV_DS1511 is not set
-# CONFIG_RTC_DRV_DS1553 is not set
-# CONFIG_RTC_DRV_DS1742 is not set
-# CONFIG_RTC_DRV_STK17TA8 is not set
-# CONFIG_RTC_DRV_M48T86 is not set
-# CONFIG_RTC_DRV_M48T59 is not set
-CONFIG_RTC_DRV_V3020=y
-
-#
-# on-CPU RTC drivers
-#
-CONFIG_RTC_DRV_SA1100=y
-# CONFIG_UIO is not set
-
-#
-# 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_EXT4DEV_FS is not set
-CONFIG_JBD=y
-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_DNOTIFY=y
-CONFIG_INOTIFY=y
-CONFIG_INOTIFY_USER=y
-# CONFIG_QUOTA is not set
-# 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_FAT_FS=m
-# CONFIG_MSDOS_FS is not set
-CONFIG_VFAT_FS=m
-CONFIG_FAT_DEFAULT_CODEPAGE=437
-CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
-# CONFIG_NTFS_FS is not set
-
-#
-# Pseudo filesystems
-#
-CONFIG_PROC_FS=y
-CONFIG_PROC_SYSCTL=y
-CONFIG_SYSFS=y
-CONFIG_TMPFS=y
-# CONFIG_TMPFS_POSIX_ACL is not set
-# CONFIG_HUGETLB_PAGE is not set
-# 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_JFFS2_FS=y
-CONFIG_JFFS2_FS_DEBUG=0
-CONFIG_JFFS2_FS_WRITEBUFFER=y
-# CONFIG_JFFS2_FS_WBUF_VERIFY is not set
-CONFIG_JFFS2_SUMMARY=y
-# CONFIG_JFFS2_FS_XATTR is not set
-# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
-CONFIG_JFFS2_ZLIB=y
-# CONFIG_JFFS2_LZO is not set
-CONFIG_JFFS2_RTIME=y
-# CONFIG_JFFS2_RUBIN is not set
-# CONFIG_CRAMFS is not set
-# CONFIG_VXFS_FS is not set
-# CONFIG_MINIX_FS is not set
-# CONFIG_HPFS_FS is not set
-# CONFIG_QNX4FS_FS is not set
-# CONFIG_ROMFS_FS is not set
-# CONFIG_SYSV_FS is not set
-# CONFIG_UFS_FS is not set
-CONFIG_NETWORK_FILESYSTEMS=y
-CONFIG_NFS_FS=y
-CONFIG_NFS_V3=y
-# CONFIG_NFS_V3_ACL is not set
-# CONFIG_NFS_V4 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_BIND34 is not set
-# CONFIG_RPCSEC_GSS_KRB5 is not set
-# CONFIG_RPCSEC_GSS_SPKM3 is not set
-# CONFIG_SMB_FS is not set
-CONFIG_CIFS=m
-# CONFIG_CIFS_STATS is not set
-# CONFIG_CIFS_WEAK_PW_HASH is not set
-# CONFIG_CIFS_XATTR is not set
-# CONFIG_CIFS_DEBUG2 is not set
-# CONFIG_CIFS_EXPERIMENTAL is not set
-# CONFIG_NCP_FS is not set
-# CONFIG_CODA_FS is not set
-# CONFIG_AFS_FS is not set
-
-#
-# Partition Types
-#
-CONFIG_PARTITION_ADVANCED=y
-# CONFIG_ACORN_PARTITION is not set
-# CONFIG_OSF_PARTITION is not set
-# CONFIG_AMIGA_PARTITION is not set
-# CONFIG_ATARI_PARTITION is not set
-# CONFIG_MAC_PARTITION is not set
-CONFIG_MSDOS_PARTITION=y
-# CONFIG_BSD_DISKLABEL is not set
-# CONFIG_MINIX_SUBPARTITION is not set
-# CONFIG_SOLARIS_X86_PARTITION is not set
-# CONFIG_UNIXWARE_DISKLABEL is not set
-# CONFIG_LDM_PARTITION is not set
-# CONFIG_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
-# CONFIG_SYSV68_PARTITION is not set
-CONFIG_NLS=m
-CONFIG_NLS_DEFAULT="iso8859-1"
-CONFIG_NLS_CODEPAGE_437=m
-# CONFIG_NLS_CODEPAGE_737 is not set
-# CONFIG_NLS_CODEPAGE_775 is not set
-# CONFIG_NLS_CODEPAGE_850 is not set
-# CONFIG_NLS_CODEPAGE_852 is not set
-# CONFIG_NLS_CODEPAGE_855 is not set
-# CONFIG_NLS_CODEPAGE_857 is not set
-# CONFIG_NLS_CODEPAGE_860 is not set
-# CONFIG_NLS_CODEPAGE_861 is not set
-# CONFIG_NLS_CODEPAGE_862 is not set
-# CONFIG_NLS_CODEPAGE_863 is not set
-# CONFIG_NLS_CODEPAGE_864 is not set
-# CONFIG_NLS_CODEPAGE_865 is not set
-# CONFIG_NLS_CODEPAGE_866 is not set
-# CONFIG_NLS_CODEPAGE_869 is not set
-# CONFIG_NLS_CODEPAGE_936 is not set
-# CONFIG_NLS_CODEPAGE_950 is not set
-# CONFIG_NLS_CODEPAGE_932 is not set
-# CONFIG_NLS_CODEPAGE_949 is not set
-# CONFIG_NLS_CODEPAGE_874 is not set
-# CONFIG_NLS_ISO8859_8 is not set
-# CONFIG_NLS_CODEPAGE_1250 is not set
-# CONFIG_NLS_CODEPAGE_1251 is not set
-# CONFIG_NLS_ASCII is not set
-CONFIG_NLS_ISO8859_1=m
-# CONFIG_NLS_ISO8859_2 is not set
-# CONFIG_NLS_ISO8859_3 is not set
-# CONFIG_NLS_ISO8859_4 is not set
-# CONFIG_NLS_ISO8859_5 is not set
-# CONFIG_NLS_ISO8859_6 is not set
-# CONFIG_NLS_ISO8859_7 is not set
-# CONFIG_NLS_ISO8859_9 is not set
-# CONFIG_NLS_ISO8859_13 is not set
-# CONFIG_NLS_ISO8859_14 is not set
-# CONFIG_NLS_ISO8859_15 is not set
-# CONFIG_NLS_KOI8_R is not set
-# CONFIG_NLS_KOI8_U is not set
-CONFIG_NLS_UTF8=m
-# CONFIG_DLM is not set
-
-#
-# Kernel hacking
-#
-# CONFIG_PRINTK_TIME is not set
-CONFIG_ENABLE_WARN_DEPRECATED=y
-CONFIG_ENABLE_MUST_CHECK=y
-CONFIG_FRAME_WARN=0
-# CONFIG_MAGIC_SYSRQ is not set
-# CONFIG_UNUSED_SYMBOLS is not set
-# CONFIG_DEBUG_FS is not set
-# CONFIG_HEADERS_CHECK is not set
-CONFIG_DEBUG_KERNEL=y
-# CONFIG_DEBUG_SHIRQ is not set
-# CONFIG_DETECT_SOFTLOCKUP is not set
-# CONFIG_SCHED_DEBUG is not set
-# CONFIG_SCHEDSTATS is not set
-# CONFIG_TIMER_STATS is not set
-# CONFIG_DEBUG_OBJECTS is not set
-# CONFIG_DEBUG_RT_MUTEXES is not set
-# CONFIG_RT_MUTEX_TESTER is not set
-# CONFIG_DEBUG_SPINLOCK is not set
-# CONFIG_DEBUG_MUTEXES is not set
-# CONFIG_DEBUG_LOCK_ALLOC is not set
-# CONFIG_PROVE_LOCKING is not set
-# CONFIG_LOCK_STAT is not set
-# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
-# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
-# CONFIG_DEBUG_KOBJECT is not set
-# CONFIG_DEBUG_BUGVERBOSE is not set
-# CONFIG_DEBUG_INFO is not set
-# CONFIG_DEBUG_VM is not set
-# CONFIG_DEBUG_WRITECOUNT is not set
-# CONFIG_DEBUG_LIST is not set
-# CONFIG_DEBUG_SG is not set
-CONFIG_FRAME_POINTER=y
-# CONFIG_BOOT_PRINTK_DELAY is not set
-# CONFIG_RCU_TORTURE_TEST is not set
-# CONFIG_BACKTRACE_SELF_TEST is not set
-# CONFIG_FAULT_INJECTION is not set
-# CONFIG_SAMPLES is not set
-CONFIG_DEBUG_USER=y
-CONFIG_DEBUG_ERRORS=y
-# CONFIG_DEBUG_STACK_USAGE is not set
-CONFIG_DEBUG_LL=y
-# CONFIG_DEBUG_ICEDCC is not set
-
-#
-# Security options
-#
-# CONFIG_KEYS is not set
-# CONFIG_SECURITY is not set
-# CONFIG_SECURITY_FILE_CAPABILITIES is not set
-CONFIG_CRYPTO=y
-
-#
-# Crypto core or helper
-#
-# CONFIG_CRYPTO_MANAGER is not set
-# CONFIG_CRYPTO_GF128MUL is not set
-# CONFIG_CRYPTO_NULL is not set
-# CONFIG_CRYPTO_CRYPTD is not set
-# CONFIG_CRYPTO_AUTHENC is not set
-# CONFIG_CRYPTO_TEST is not set
-
-#
-# Authenticated Encryption with Associated Data
-#
-# CONFIG_CRYPTO_CCM is not set
-# CONFIG_CRYPTO_GCM is not set
-# CONFIG_CRYPTO_SEQIV is not set
-
-#
-# Block modes
-#
-# CONFIG_CRYPTO_CBC is not set
-# CONFIG_CRYPTO_CTR is not set
-# CONFIG_CRYPTO_CTS is not set
-# CONFIG_CRYPTO_ECB is not set
-# CONFIG_CRYPTO_LRW is not set
-# CONFIG_CRYPTO_PCBC is not set
-# CONFIG_CRYPTO_XTS is not set
-
-#
-# Hash modes
-#
-# CONFIG_CRYPTO_HMAC is not set
-# CONFIG_CRYPTO_XCBC is not set
-
-#
-# Digest
-#
-# CONFIG_CRYPTO_CRC32C is not set
-# CONFIG_CRYPTO_MD4 is not set
-# CONFIG_CRYPTO_MD5 is not set
-# CONFIG_CRYPTO_MICHAEL_MIC is not set
-# CONFIG_CRYPTO_SHA1 is not set
-# CONFIG_CRYPTO_SHA256 is not set
-# CONFIG_CRYPTO_SHA512 is not set
-# CONFIG_CRYPTO_TGR192 is not set
-# CONFIG_CRYPTO_WP512 is not set
-
-#
-# Ciphers
-#
-# CONFIG_CRYPTO_AES is not set
-# CONFIG_CRYPTO_ANUBIS is not set
-# CONFIG_CRYPTO_ARC4 is not set
-# CONFIG_CRYPTO_BLOWFISH is not set
-# CONFIG_CRYPTO_CAMELLIA is not set
-# CONFIG_CRYPTO_CAST5 is not set
-# CONFIG_CRYPTO_CAST6 is not set
-# CONFIG_CRYPTO_DES is not set
-# CONFIG_CRYPTO_FCRYPT is not set
-# CONFIG_CRYPTO_KHAZAD is not set
-# CONFIG_CRYPTO_SALSA20 is not set
-# CONFIG_CRYPTO_SEED is not set
-# CONFIG_CRYPTO_SERPENT is not set
-# CONFIG_CRYPTO_TEA is not set
-# CONFIG_CRYPTO_TWOFISH is not set
-
-#
-# Compression
-#
-# CONFIG_CRYPTO_DEFLATE is not set
-# CONFIG_CRYPTO_LZO is not set
-# CONFIG_CRYPTO_HW is not set
-
-#
-# Library routines
-#
-CONFIG_BITREVERSE=y
-# CONFIG_GENERIC_FIND_FIRST_BIT is not set
-# CONFIG_GENERIC_FIND_NEXT_BIT is not set
-CONFIG_CRC_CCITT=m
-# CONFIG_CRC16 is not set
-# CONFIG_CRC_ITU_T is not set
-CONFIG_CRC32=y
-# CONFIG_CRC7 is not set
-# CONFIG_LIBCRC32C is not set
-CONFIG_ZLIB_INFLATE=y
-CONFIG_ZLIB_DEFLATE=y
-CONFIG_PLIST=y
-CONFIG_HAS_IOMEM=y
-CONFIG_HAS_IOPORT=y
-CONFIG_HAS_DMA=y
diff --git a/arch/arm/configs/xm_x2xx_defconfig b/arch/arm/configs/xm_x2xx_defconfig
new file mode 100644
index 0000000..f891364
--- /dev/null
+++ b/arch/arm/configs/xm_x2xx_defconfig
@@ -0,0 +1,1806 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.27-rc8
+# Sun Oct  5 11:05:36 2008
+#
+CONFIG_ARM=y
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+CONFIG_GENERIC_GPIO=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_MMU=y
+# CONFIG_NO_IOPORT is not set
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_ARCH_SUPPORTS_AOUT=y
+CONFIG_ZONE_DMA=y
+CONFIG_ARCH_MTD_XIP=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
+CONFIG_VECTORS_BASE=0xffff0000
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=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=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_CGROUPS is not set
+CONFIG_GROUP_SCHED=y
+CONFIG_FAIR_GROUP_SCHED=y
+# CONFIG_RT_GROUP_SCHED is not set
+CONFIG_USER_SCHED=y
+# CONFIG_CGROUP_SCHED is not set
+CONFIG_SYSFS_DEPRECATED=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+# CONFIG_RELAY is not set
+# CONFIG_NAMESPACES is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+CONFIG_EMBEDDED=y
+CONFIG_UID16=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+# CONFIG_COMPAT_BRK is not set
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_ANON_INODES=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+# CONFIG_VM_EVENT_COUNTERS is not set
+# CONFIG_SLUB_DEBUG is not set
+# CONFIG_SLAB is not set
+CONFIG_SLUB=y
+# CONFIG_SLOB is not set
+# CONFIG_PROFILING is not set
+# CONFIG_MARKERS is not set
+CONFIG_HAVE_OPROFILE=y
+# CONFIG_KPROBES is not set
+# CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS is not set
+# CONFIG_HAVE_IOREMAP_PROT is not set
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+# CONFIG_HAVE_ARCH_TRACEHOOK is not set
+# CONFIG_HAVE_DMA_ATTRS is not set
+# CONFIG_USE_GENERIC_SMP_HELPERS is not set
+CONFIG_HAVE_CLK=y
+# CONFIG_PROC_PAGE_MONITOR is not set
+CONFIG_HAVE_GENERIC_DMA_COHERENT=y
+CONFIG_RT_MUTEXES=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+# CONFIG_MODULE_FORCE_LOAD is not set
+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=y
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_BLK_DEV_INTEGRITY is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_DEFAULT_AS is not set
+# CONFIG_DEFAULT_DEADLINE is not set
+CONFIG_DEFAULT_CFQ=y
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="cfq"
+CONFIG_CLASSIC_RCU=y
+
+#
+# System Type
+#
+# CONFIG_ARCH_AAEC2000 is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_REALVIEW is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_AT91 is not set
+# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_EP93XX is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_NETX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_IOP13XX is not set
+# CONFIG_ARCH_IOP32X is not set
+# CONFIG_ARCH_IOP33X is not set
+# CONFIG_ARCH_IXP23XX is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_KIRKWOOD is not set
+# CONFIG_ARCH_KS8695 is not set
+# CONFIG_ARCH_NS9XXX is not set
+# CONFIG_ARCH_LOKI is not set
+# CONFIG_ARCH_MV78XX0 is not set
+# CONFIG_ARCH_MXC is not set
+# CONFIG_ARCH_ORION5X is not set
+# CONFIG_ARCH_PNX4008 is not set
+CONFIG_ARCH_PXA=y
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_DAVINCI is not set
+# CONFIG_ARCH_OMAP is not set
+# CONFIG_ARCH_MSM7X00A is not set
+CONFIG_DMABOUNCE=y
+
+#
+# Intel PXA2xx/PXA3xx Implementations
+#
+# CONFIG_ARCH_GUMSTIX is not set
+# CONFIG_ARCH_LUBBOCK is not set
+# CONFIG_MACH_LOGICPD_PXA270 is not set
+# CONFIG_MACH_MAINSTONE is not set
+# CONFIG_MACH_MP900C is not set
+# CONFIG_ARCH_PXA_IDP is not set
+# CONFIG_PXA_SHARPSL is not set
+# CONFIG_ARCH_VIPER is not set
+# CONFIG_ARCH_PXA_ESERIES is not set
+# CONFIG_TRIZEPS_PXA is not set
+CONFIG_MACH_EM_X270=y
+# CONFIG_MACH_COLIBRI is not set
+# CONFIG_MACH_ZYLONITE is not set
+# CONFIG_MACH_LITTLETON is not set
+# CONFIG_MACH_TAVOREVB is not set
+# CONFIG_MACH_SAAR is not set
+CONFIG_MACH_ARMCORE=y
+# CONFIG_MACH_CM_X300 is not set
+# CONFIG_MACH_MAGICIAN is not set
+# CONFIG_MACH_MIOA701 is not set
+# CONFIG_MACH_PCM027 is not set
+# CONFIG_ARCH_PXA_PALM is not set
+# CONFIG_PXA_EZX is not set
+CONFIG_PXA25x=y
+CONFIG_PXA27x=y
+CONFIG_PXA_SSP=y
+# CONFIG_PXA_PWM is not set
+
+#
+# Boot options
+#
+
+#
+# Power management
+#
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_XSCALE=y
+CONFIG_CPU_32v5=y
+CONFIG_CPU_ABRT_EV5T=y
+CONFIG_CPU_PABRT_NOIFAR=y
+CONFIG_CPU_CACHE_VIVT=y
+CONFIG_CPU_TLB_V4WBI=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
+
+#
+# Processor Features
+#
+CONFIG_ARM_THUMB=y
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_OUTER_CACHE is not set
+CONFIG_IWMMXT=y
+CONFIG_XSCALE_PMU=y
+
+#
+# Bus support
+#
+CONFIG_PCI=y
+CONFIG_PCI_SYSCALL=y
+CONFIG_PCI_HOST_ITE8152=y
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+CONFIG_PCI_LEGACY=y
+# CONFIG_PCI_DEBUG is not set
+CONFIG_PCCARD=m
+# CONFIG_PCMCIA_DEBUG is not set
+CONFIG_PCMCIA=m
+CONFIG_PCMCIA_LOAD_CIS=y
+CONFIG_PCMCIA_IOCTL=y
+CONFIG_CARDBUS=y
+
+#
+# PC-card bridges
+#
+CONFIG_YENTA=m
+# CONFIG_YENTA_O2 is not set
+# CONFIG_YENTA_RICOH is not set
+CONFIG_YENTA_TI=y
+# CONFIG_YENTA_ENE_TUNE is not set
+# CONFIG_YENTA_TOSHIBA is not set
+# CONFIG_PD6729 is not set
+# CONFIG_I82092 is not set
+CONFIG_PCMCIA_PXA2XX=m
+CONFIG_PCCARD_NONSTATIC=m
+
+#
+# Kernel Features
+#
+CONFIG_TICK_ONESHOT=y
+CONFIG_NO_HZ=y
+# CONFIG_HIGH_RES_TIMERS is not set
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+CONFIG_VMSPLIT_3G=y
+# CONFIG_VMSPLIT_2G is not set
+# CONFIG_VMSPLIT_1G is not set
+CONFIG_PAGE_OFFSET=0xC0000000
+# CONFIG_PREEMPT is not set
+CONFIG_HZ=100
+CONFIG_AEABI=y
+CONFIG_OABI_COMPAT=y
+CONFIG_ARCH_FLATMEM_HAS_HOLES=y
+# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
+# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set
+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_SPARSEMEM_VMEMMAP_ENABLE is not set
+CONFIG_PAGEFLAGS_EXTENDED=y
+CONFIG_SPLIT_PTLOCK_CPUS=4096
+# CONFIG_RESOURCES_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=1
+CONFIG_BOUNCE=y
+CONFIG_VIRT_TO_BUS=y
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="root=1f03 mem=32M"
+# CONFIG_XIP_KERNEL is not set
+# CONFIG_KEXEC is not set
+
+#
+# CPU Power Management
+#
+# CONFIG_CPU_FREQ is not set
+# CONFIG_CPU_IDLE is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_FASTFPE is not set
+
+#
+# Userspace binary formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Power management options
+#
+CONFIG_PM=y
+# CONFIG_PM_DEBUG is not set
+CONFIG_PM_SLEEP=y
+CONFIG_SUSPEND=y
+CONFIG_SUSPEND_FREEZER=y
+CONFIG_APM_EMULATION=m
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+CONFIG_PACKET_MMAP=y
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
+# CONFIG_XFRM_STATISTICS 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 is not set
+# 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_XFRM_MODE_BEET=y
+# CONFIG_INET_LRO is not set
+# CONFIG_INET_DIAG is not set
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# 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
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_CAN is not set
+# CONFIG_IRDA is not set
+CONFIG_BT=m
+CONFIG_BT_L2CAP=m
+CONFIG_BT_SCO=m
+CONFIG_BT_RFCOMM=m
+# CONFIG_BT_RFCOMM_TTY is not set
+CONFIG_BT_BNEP=m
+# CONFIG_BT_BNEP_MC_FILTER is not set
+# CONFIG_BT_BNEP_PROTO_FILTER is not set
+CONFIG_BT_HIDP=m
+
+#
+# Bluetooth device drivers
+#
+CONFIG_BT_HCIUSB=m
+CONFIG_BT_HCIUSB_SCO=y
+# CONFIG_BT_HCIBTUSB is not set
+# CONFIG_BT_HCIBTSDIO is not set
+# CONFIG_BT_HCIUART is not set
+# CONFIG_BT_HCIBCM203X is not set
+# CONFIG_BT_HCIBPA10X is not set
+# CONFIG_BT_HCIBFUSB is not set
+# CONFIG_BT_HCIDTL1 is not set
+# CONFIG_BT_HCIBT3C is not set
+# CONFIG_BT_HCIBLUECARD is not set
+# CONFIG_BT_HCIBTUART is not set
+# CONFIG_BT_HCIVHCI is not set
+# CONFIG_AF_RXRPC is not set
+
+#
+# Wireless
+#
+# CONFIG_CFG80211 is not set
+CONFIG_WIRELESS_EXT=y
+CONFIG_WIRELESS_EXT_SYSFS=y
+# CONFIG_MAC80211 is not set
+# CONFIG_IEEE80211 is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=m
+CONFIG_FIRMWARE_IN_KERNEL=y
+CONFIG_EXTRA_FIRMWARE=""
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_CONNECTOR is not set
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+# CONFIG_MTD_AFS_PARTS is not set
+# CONFIG_MTD_AR7_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+# CONFIG_MTD_OOPS is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+CONFIG_MTD_JEDECPROBE=y
+CONFIG_MTD_GEN_PROBE=y
+CONFIG_MTD_CFI_ADV_OPTIONS=y
+CONFIG_MTD_CFI_NOSWAP=y
+# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set
+# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set
+# CONFIG_MTD_CFI_GEOMETRY is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_OTP is not set
+CONFIG_MTD_CFI_INTELEXT=y
+CONFIG_MTD_CFI_AMDSTD=y
+CONFIG_MTD_CFI_STAA=y
+CONFIG_MTD_CFI_UTIL=y
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_XIP is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+CONFIG_MTD_PHYSMAP=y
+CONFIG_MTD_PHYSMAP_START=0x0
+CONFIG_MTD_PHYSMAP_LEN=0x400000
+CONFIG_MTD_PHYSMAP_BANKWIDTH=2
+CONFIG_MTD_PXA2XX=y
+# CONFIG_MTD_ARM_INTEGRATOR is not set
+# CONFIG_MTD_IMPA7 is not set
+# CONFIG_MTD_SHARP_SL is not set
+# CONFIG_MTD_INTEL_VR_NOR is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_PMC551 is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+CONFIG_MTD_NAND=y
+# CONFIG_MTD_NAND_VERIFY_WRITE is not set
+# CONFIG_MTD_NAND_ECC_SMC is not set
+# CONFIG_MTD_NAND_MUSEUM_IDS is not set
+# CONFIG_MTD_NAND_H1900 is not set
+CONFIG_MTD_NAND_GPIO=m
+CONFIG_MTD_NAND_IDS=y
+# CONFIG_MTD_NAND_DISKONCHIP is not set
+# CONFIG_MTD_NAND_SHARPSL is not set
+# CONFIG_MTD_NAND_CAFE is not set
+CONFIG_MTD_NAND_CM_X270=y
+# CONFIG_MTD_NAND_NANDSIM is not set
+CONFIG_MTD_NAND_PLATFORM=y
+# CONFIG_MTD_ALAUDA is not set
+# CONFIG_MTD_ONENAND is not set
+
+#
+# UBI - Unsorted block images
+#
+# CONFIG_MTD_UBI is not set
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# 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_UB is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=4096
+# CONFIG_BLK_DEV_XIP is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+# CONFIG_MISC_DEVICES is not set
+CONFIG_HAVE_IDE=y
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+# CONFIG_BLK_DEV_SR is not set
+# CONFIG_CHR_DEV_SG is not set
+# CONFIG_CHR_DEV_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
+# CONFIG_SCSI_SCAN_ASYNC is not set
+CONFIG_SCSI_WAIT_SCAN=m
+
+#
+# SCSI Transports
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+# CONFIG_SCSI_SRP_ATTRS is not set
+CONFIG_SCSI_LOWLEVEL=y
+# 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_AIC94XX is not set
+# CONFIG_SCSI_DPT_I2O is not set
+# CONFIG_SCSI_ADVANSYS is not set
+# CONFIG_SCSI_ARCMSR is not set
+# CONFIG_MEGARAID_NEWGEN is not set
+# CONFIG_MEGARAID_LEGACY is not set
+# CONFIG_MEGARAID_SAS is not set
+# CONFIG_SCSI_HPTIOP is not set
+# CONFIG_SCSI_DMX3191D is not set
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_IPS is not set
+# CONFIG_SCSI_INITIO is not set
+# CONFIG_SCSI_INIA100 is not set
+# CONFIG_SCSI_MVSAS is not set
+# CONFIG_SCSI_STEX 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_QLA_ISCSI 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
+# CONFIG_SCSI_SRP is not set
+# CONFIG_SCSI_LOWLEVEL_PCMCIA is not set
+# CONFIG_SCSI_DH is not set
+CONFIG_ATA=m
+# CONFIG_ATA_NONSTANDARD is not set
+# CONFIG_SATA_PMP is not set
+# CONFIG_SATA_AHCI is not set
+# CONFIG_SATA_SIL24 is not set
+CONFIG_ATA_SFF=y
+# CONFIG_SATA_SVW is not set
+# CONFIG_ATA_PIIX is not set
+# CONFIG_SATA_MV is not set
+# CONFIG_SATA_NV is not set
+# CONFIG_PDC_ADMA is not set
+# CONFIG_SATA_QSTOR is not set
+# CONFIG_SATA_PROMISE is not set
+# CONFIG_SATA_SX4 is not set
+# CONFIG_SATA_SIL is not set
+# CONFIG_SATA_SIS is not set
+# CONFIG_SATA_ULI is not set
+# CONFIG_SATA_VIA is not set
+# CONFIG_SATA_VITESSE is not set
+# CONFIG_SATA_INIC162X is not set
+# CONFIG_PATA_ALI is not set
+# CONFIG_PATA_AMD is not set
+# CONFIG_PATA_ARTOP is not set
+# CONFIG_PATA_ATIIXP is not set
+# CONFIG_PATA_CMD640_PCI is not set
+# CONFIG_PATA_CMD64X is not set
+# CONFIG_PATA_CS5520 is not set
+# CONFIG_PATA_CS5530 is not set
+# CONFIG_PATA_CYPRESS is not set
+# CONFIG_PATA_EFAR is not set
+# CONFIG_ATA_GENERIC is not set
+# CONFIG_PATA_HPT366 is not set
+# CONFIG_PATA_HPT37X is not set
+# CONFIG_PATA_HPT3X2N is not set
+# CONFIG_PATA_HPT3X3 is not set
+# CONFIG_PATA_IT821X is not set
+# CONFIG_PATA_IT8213 is not set
+# CONFIG_PATA_JMICRON is not set
+# CONFIG_PATA_TRIFLEX is not set
+# CONFIG_PATA_MARVELL is not set
+# CONFIG_PATA_MPIIX is not set
+# CONFIG_PATA_OLDPIIX is not set
+# CONFIG_PATA_NETCELL is not set
+# CONFIG_PATA_NINJA32 is not set
+# CONFIG_PATA_NS87410 is not set
+# CONFIG_PATA_NS87415 is not set
+# CONFIG_PATA_OPTI is not set
+# CONFIG_PATA_OPTIDMA is not set
+CONFIG_PATA_PCMCIA=m
+# CONFIG_PATA_PDC_OLD is not set
+# CONFIG_PATA_RADISYS is not set
+# CONFIG_PATA_RZ1000 is not set
+# CONFIG_PATA_SC1200 is not set
+# CONFIG_PATA_SERVERWORKS is not set
+# CONFIG_PATA_PDC2027X is not set
+# CONFIG_PATA_SIL680 is not set
+# CONFIG_PATA_SIS is not set
+# CONFIG_PATA_VIA is not set
+# CONFIG_PATA_WINBOND is not set
+# CONFIG_PATA_PLATFORM is not set
+# CONFIG_PATA_SCH is not set
+# CONFIG_MD is not set
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+
+#
+# Enable only one of the two stacks, unless you know what you are doing
+#
+# CONFIG_FIREWIRE is not set
+# CONFIG_IEEE1394 is not set
+# CONFIG_I2O is not set
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_VETH is not set
+# CONFIG_ARCNET is not set
+# CONFIG_PHYLIB is not set
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_AX88796 is not set
+# CONFIG_HAPPYMEAL is not set
+# CONFIG_SUNGEM is not set
+# CONFIG_CASSINI is not set
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_SMC91X is not set
+CONFIG_DM9000=y
+CONFIG_DM9000_DEBUGLEVEL=1
+# CONFIG_DM9000_FORCE_SIMPLE_PHY_POLL is not set
+# CONFIG_SMC911X is not set
+# CONFIG_NET_TULIP is not set
+# CONFIG_HP100 is not set
+# CONFIG_IBM_NEW_EMAC_ZMII is not set
+# CONFIG_IBM_NEW_EMAC_RGMII is not set
+# CONFIG_IBM_NEW_EMAC_TAH is not set
+# CONFIG_IBM_NEW_EMAC_EMAC4 is not set
+CONFIG_NET_PCI=y
+# CONFIG_PCNET32 is not set
+# CONFIG_AMD8111_ETH is not set
+# CONFIG_ADAPTEC_STARFIRE is not set
+# CONFIG_B44 is not set
+# CONFIG_FORCEDETH is not set
+# CONFIG_EEPRO100 is not set
+# CONFIG_E100 is not set
+# CONFIG_FEALNX is not set
+# CONFIG_NATSEMI is not set
+# CONFIG_NE2K_PCI is not set
+# CONFIG_8139CP is not set
+CONFIG_8139TOO=y
+# CONFIG_8139TOO_PIO is not set
+# CONFIG_8139TOO_TUNE_TWISTER is not set
+# CONFIG_8139TOO_8129 is not set
+# CONFIG_8139_OLD_RX_RESET is not set
+# CONFIG_R6040 is not set
+# CONFIG_SIS900 is not set
+# CONFIG_EPIC100 is not set
+# CONFIG_SUNDANCE is not set
+# CONFIG_TLAN is not set
+# CONFIG_VIA_RHINE is not set
+# CONFIG_SC92031 is not set
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
+# CONFIG_TR is not set
+
+#
+# Wireless LAN
+#
+# CONFIG_WLAN_PRE80211 is not set
+CONFIG_WLAN_80211=y
+# CONFIG_PCMCIA_RAYCS is not set
+# CONFIG_IPW2100 is not set
+# CONFIG_IPW2200 is not set
+CONFIG_LIBERTAS=m
+# CONFIG_LIBERTAS_USB is not set
+# CONFIG_LIBERTAS_CS is not set
+CONFIG_LIBERTAS_SDIO=m
+# CONFIG_LIBERTAS_DEBUG is not set
+# CONFIG_HERMES is not set
+# CONFIG_ATMEL is not set
+# CONFIG_AIRO_CS is not set
+# CONFIG_PCMCIA_WL3501 is not set
+# CONFIG_PRISM54 is not set
+# CONFIG_USB_ZD1201 is not set
+# CONFIG_USB_NET_RNDIS_WLAN is not set
+# CONFIG_IWLWIFI_LEDS is not set
+# CONFIG_HOSTAP is not set
+
+#
+# USB Network Adapters
+#
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_USBNET is not set
+# CONFIG_NET_PCMCIA is not set
+# CONFIG_WAN is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+CONFIG_PPP=m
+CONFIG_PPP_MULTILINK=y
+CONFIG_PPP_FILTER=y
+CONFIG_PPP_ASYNC=m
+# CONFIG_PPP_SYNC_TTY is not set
+CONFIG_PPP_DEFLATE=m
+CONFIG_PPP_BSDCOMP=m
+# CONFIG_PPP_MPPE is not set
+# CONFIG_PPPOE is not set
+# CONFIG_PPPOL2TP is not set
+# CONFIG_SLIP is not set
+CONFIG_SLHC=m
+# CONFIG_NET_FC is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_ISDN is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_EVBUG is not set
+# CONFIG_INPUT_APMPOWER is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+CONFIG_KEYBOARD_ATKBD=y
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_KEYBOARD_STOWAWAY is not set
+CONFIG_KEYBOARD_PXA27x=m
+# CONFIG_KEYBOARD_GPIO is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+CONFIG_INPUT_TOUCHSCREEN=y
+# CONFIG_TOUCHSCREEN_FUJITSU is not set
+# CONFIG_TOUCHSCREEN_GUNZE is not set
+# CONFIG_TOUCHSCREEN_ELO is not set
+# CONFIG_TOUCHSCREEN_MTOUCH is not set
+# CONFIG_TOUCHSCREEN_INEXIO is not set
+# CONFIG_TOUCHSCREEN_MK712 is not set
+# CONFIG_TOUCHSCREEN_PENMOUNT is not set
+# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set
+# CONFIG_TOUCHSCREEN_TOUCHWIN is not set
+CONFIG_TOUCHSCREEN_WM97XX=m
+# CONFIG_TOUCHSCREEN_WM9705 is not set
+CONFIG_TOUCHSCREEN_WM9712=y
+# CONFIG_TOUCHSCREEN_WM9713 is not set
+# CONFIG_TOUCHSCREEN_WM97XX_MAINSTONE is not set
+# CONFIG_TOUCHSCREEN_USB_COMPOSITE is not set
+# CONFIG_TOUCHSCREEN_TOUCHIT213 is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+# CONFIG_SERIO_SERPORT is not set
+# CONFIG_SERIO_PCIPS2 is not set
+CONFIG_SERIO_LIBPS2=y
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_CONSOLE_TRANSLATIONS=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
+CONFIG_DEVKMEM=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+# CONFIG_NOZOMI is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_PXA=y
+CONFIG_SERIAL_PXA_CONSOLE=y
+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=16
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_HW_RANDOM is not set
+# CONFIG_NVRAM is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+
+#
+# PCMCIA character devices
+#
+# CONFIG_SYNCLINK_CS is not set
+# CONFIG_CARDMAN_4000 is not set
+# CONFIG_CARDMAN_4040 is not set
+# CONFIG_IPWIRELESS is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+CONFIG_DEVPORT=y
+CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_CHARDEV=m
+CONFIG_I2C_HELPER_AUTO=y
+
+#
+# I2C Hardware Bus support
+#
+
+#
+# PC SMBus host controller drivers
+#
+# 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_ISCH is not set
+# CONFIG_I2C_PIIX4 is not set
+# CONFIG_I2C_NFORCE2 is not set
+# CONFIG_I2C_SIS5595 is not set
+# CONFIG_I2C_SIS630 is not set
+# CONFIG_I2C_SIS96X is not set
+# CONFIG_I2C_VIA is not set
+# CONFIG_I2C_VIAPRO is not set
+
+#
+# I2C system bus drivers (mostly embedded / system-on-chip)
+#
+# CONFIG_I2C_GPIO is not set
+# CONFIG_I2C_OCORES is not set
+CONFIG_I2C_PXA=y
+# CONFIG_I2C_PXA_SLAVE is not set
+# CONFIG_I2C_SIMTEC is not set
+
+#
+# External I2C/SMBus adapter drivers
+#
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_TAOS_EVM is not set
+# CONFIG_I2C_TINY_USB is not set
+
+#
+# Graphics adapter I2C/DDC channel drivers
+#
+# CONFIG_I2C_VOODOO3 is not set
+
+#
+# Other I2C/SMBus bus drivers
+#
+# CONFIG_I2C_PCA_PLATFORM is not set
+# CONFIG_I2C_STUB is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_DS1682 is not set
+# CONFIG_AT24 is not set
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_PCF8575 is not set
+# CONFIG_SENSORS_PCA9539 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_TPS65010 is not set
+# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_SENSORS_TSL2550 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
+# CONFIG_SPI is not set
+CONFIG_ARCH_REQUIRE_GPIOLIB=y
+CONFIG_GPIOLIB=y
+# CONFIG_DEBUG_GPIO is not set
+# CONFIG_GPIO_SYSFS is not set
+
+#
+# I2C GPIO expanders:
+#
+# CONFIG_GPIO_MAX732X is not set
+# CONFIG_GPIO_PCA953X is not set
+# CONFIG_GPIO_PCF857X is not set
+
+#
+# PCI GPIO expanders:
+#
+# CONFIG_GPIO_BT8XX is not set
+
+#
+# SPI GPIO expanders:
+#
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+# CONFIG_HWMON is not set
+# CONFIG_THERMAL is not set
+# CONFIG_THERMAL_HWMON is not set
+# CONFIG_WATCHDOG is not set
+
+#
+# Sonics Silicon Backplane
+#
+CONFIG_SSB_POSSIBLE=y
+# CONFIG_SSB is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_CORE is not set
+# CONFIG_MFD_SM501 is not set
+# CONFIG_MFD_ASIC3 is not set
+# CONFIG_HTC_EGPIO is not set
+# CONFIG_HTC_PASIC3 is not set
+# CONFIG_UCB1400_CORE is not set
+# CONFIG_MFD_TMIO is not set
+# CONFIG_MFD_T7L66XB is not set
+# CONFIG_MFD_TC6387XB is not set
+# CONFIG_MFD_TC6393XB is not set
+
+#
+# Multimedia devices
+#
+
+#
+# Multimedia core support
+#
+# CONFIG_VIDEO_DEV is not set
+# CONFIG_DVB_CORE is not set
+# CONFIG_VIDEO_MEDIA is not set
+
+#
+# Multimedia drivers
+#
+# CONFIG_DAB is not set
+
+#
+# Graphics support
+#
+# CONFIG_DRM is not set
+# CONFIG_VGASTATE is not set
+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
+CONFIG_FB=y
+# CONFIG_FIRMWARE_EDID is not set
+# CONFIG_FB_DDC is not set
+CONFIG_FB_CFB_FILLRECT=y
+CONFIG_FB_CFB_COPYAREA=y
+CONFIG_FB_CFB_IMAGEBLIT=y
+# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
+# CONFIG_FB_SYS_FILLRECT is not set
+# CONFIG_FB_SYS_COPYAREA is not set
+# CONFIG_FB_SYS_IMAGEBLIT is not set
+# CONFIG_FB_FOREIGN_ENDIAN is not set
+# CONFIG_FB_SYS_FOPS is not set
+# CONFIG_FB_SVGALIB is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+
+#
+# Frame buffer hardware drivers
+#
+# CONFIG_FB_CIRRUS is not set
+# CONFIG_FB_PM2 is not set
+# CONFIG_FB_CYBER2000 is not set
+# CONFIG_FB_ASILIANT is not set
+# CONFIG_FB_IMSTT is not set
+# CONFIG_FB_S1D13XXX is not set
+# CONFIG_FB_NVIDIA is not set
+# CONFIG_FB_RIVA is not set
+# CONFIG_FB_MATROX is not set
+# CONFIG_FB_RADEON is not set
+# CONFIG_FB_ATY128 is not set
+# CONFIG_FB_ATY is not set
+# CONFIG_FB_S3 is not set
+# CONFIG_FB_SAVAGE is not set
+# CONFIG_FB_SIS is not set
+# CONFIG_FB_NEOMAGIC is not set
+# CONFIG_FB_KYRO is not set
+# CONFIG_FB_3DFX is not set
+# CONFIG_FB_VOODOO1 is not set
+# CONFIG_FB_VT8623 is not set
+# CONFIG_FB_TRIDENT is not set
+# CONFIG_FB_ARK is not set
+# CONFIG_FB_PM3 is not set
+# CONFIG_FB_CARMINE is not set
+CONFIG_FB_PXA=y
+# CONFIG_FB_PXA_SMARTPANEL is not set
+CONFIG_FB_PXA_PARAMETERS=y
+CONFIG_FB_MBX=m
+# CONFIG_FB_W100 is not set
+# CONFIG_FB_VIRTUAL is not set
+# CONFIG_FB_METRONOME is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set
+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
+# CONFIG_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+CONFIG_LOGO=y
+CONFIG_LOGO_LINUX_MONO=y
+CONFIG_LOGO_LINUX_VGA16=y
+CONFIG_LOGO_LINUX_CLUT224=y
+CONFIG_SOUND=m
+CONFIG_SND=m
+CONFIG_SND_TIMER=m
+CONFIG_SND_PCM=m
+# CONFIG_SND_SEQUENCER is not set
+CONFIG_SND_OSSEMUL=y
+CONFIG_SND_MIXER_OSS=m
+CONFIG_SND_PCM_OSS=m
+CONFIG_SND_PCM_OSS_PLUGINS=y
+# CONFIG_SND_DYNAMIC_MINORS is not set
+CONFIG_SND_SUPPORT_OLD_API=y
+CONFIG_SND_VERBOSE_PROCFS=y
+# CONFIG_SND_VERBOSE_PRINTK is not set
+# CONFIG_SND_DEBUG is not set
+CONFIG_SND_VMASTER=y
+CONFIG_SND_AC97_CODEC=m
+CONFIG_SND_DRIVERS=y
+# CONFIG_SND_DUMMY is not set
+# CONFIG_SND_MTPAV is not set
+# CONFIG_SND_SERIAL_U16550 is not set
+# CONFIG_SND_MPU401 is not set
+# CONFIG_SND_AC97_POWER_SAVE is not set
+CONFIG_SND_PCI=y
+# CONFIG_SND_AD1889 is not set
+# CONFIG_SND_ALS300 is not set
+# CONFIG_SND_ALI5451 is not set
+# CONFIG_SND_ATIIXP is not set
+# CONFIG_SND_ATIIXP_MODEM is not set
+# CONFIG_SND_AU8810 is not set
+# CONFIG_SND_AU8820 is not set
+# CONFIG_SND_AU8830 is not set
+# CONFIG_SND_AW2 is not set
+# CONFIG_SND_AZT3328 is not set
+# CONFIG_SND_BT87X is not set
+# CONFIG_SND_CA0106 is not set
+# CONFIG_SND_CMIPCI is not set
+# CONFIG_SND_OXYGEN is not set
+# CONFIG_SND_CS4281 is not set
+# CONFIG_SND_CS46XX is not set
+# CONFIG_SND_DARLA20 is not set
+# CONFIG_SND_GINA20 is not set
+# CONFIG_SND_LAYLA20 is not set
+# CONFIG_SND_DARLA24 is not set
+# CONFIG_SND_GINA24 is not set
+# CONFIG_SND_LAYLA24 is not set
+# CONFIG_SND_MONA is not set
+# CONFIG_SND_MIA is not set
+# CONFIG_SND_ECHO3G is not set
+# CONFIG_SND_INDIGO is not set
+# CONFIG_SND_INDIGOIO is not set
+# CONFIG_SND_INDIGODJ is not set
+# CONFIG_SND_EMU10K1 is not set
+# CONFIG_SND_EMU10K1X is not set
+# CONFIG_SND_ENS1370 is not set
+# CONFIG_SND_ENS1371 is not set
+# CONFIG_SND_ES1938 is not set
+# CONFIG_SND_ES1968 is not set
+# CONFIG_SND_FM801 is not set
+# CONFIG_SND_HDA_INTEL is not set
+# CONFIG_SND_HDSP is not set
+# CONFIG_SND_HDSPM is not set
+# CONFIG_SND_HIFIER is not set
+# CONFIG_SND_ICE1712 is not set
+# CONFIG_SND_ICE1724 is not set
+# CONFIG_SND_INTEL8X0 is not set
+# CONFIG_SND_INTEL8X0M is not set
+# CONFIG_SND_KORG1212 is not set
+# CONFIG_SND_MAESTRO3 is not set
+# CONFIG_SND_MIXART is not set
+# CONFIG_SND_NM256 is not set
+# CONFIG_SND_PCXHR is not set
+# CONFIG_SND_RIPTIDE is not set
+# CONFIG_SND_RME32 is not set
+# CONFIG_SND_RME96 is not set
+# CONFIG_SND_RME9652 is not set
+# CONFIG_SND_SONICVIBES is not set
+# CONFIG_SND_TRIDENT is not set
+# CONFIG_SND_VIA82XX is not set
+# CONFIG_SND_VIA82XX_MODEM is not set
+# CONFIG_SND_VIRTUOSO is not set
+# CONFIG_SND_VX222 is not set
+# CONFIG_SND_YMFPCI is not set
+CONFIG_SND_ARM=y
+CONFIG_SND_PXA2XX_PCM=m
+CONFIG_SND_PXA2XX_AC97=m
+CONFIG_SND_USB=y
+# CONFIG_SND_USB_AUDIO is not set
+# CONFIG_SND_USB_CAIAQ is not set
+CONFIG_SND_PCMCIA=y
+# CONFIG_SND_VXPOCKET is not set
+# CONFIG_SND_PDAUDIOCF is not set
+# CONFIG_SND_SOC is not set
+# CONFIG_SOUND_PRIME is not set
+CONFIG_AC97_BUS=m
+CONFIG_HID_SUPPORT=y
+CONFIG_HID=y
+CONFIG_HID_DEBUG=y
+# CONFIG_HIDRAW is not set
+
+#
+# USB Input Devices
+#
+CONFIG_USB_HID=y
+# CONFIG_USB_HIDINPUT_POWERBOOK is not set
+# CONFIG_HID_FF is not set
+# CONFIG_USB_HIDDEV is not set
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+CONFIG_USB_ARCH_HAS_EHCI=y
+CONFIG_USB=y
+# CONFIG_USB_DEBUG is not set
+# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+# CONFIG_USB_DEVICE_CLASS is not set
+# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_SUSPEND is not set
+# CONFIG_USB_OTG is not set
+# CONFIG_USB_OTG_WHITELIST is not set
+# CONFIG_USB_OTG_BLACKLIST_HUB is not set
+CONFIG_USB_MON=y
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_C67X00_HCD is not set
+# CONFIG_USB_EHCI_HCD is not set
+# CONFIG_USB_ISP116X_HCD is not set
+# CONFIG_USB_ISP1760_HCD is not set
+CONFIG_USB_OHCI_HCD=y
+# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set
+# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
+# CONFIG_USB_UHCI_HCD is not set
+# CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_R8A66597_HCD is not set
+# CONFIG_USB_MUSB_HDRC is not set
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+# CONFIG_USB_WDM is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# may also be needed; see USB_STORAGE Help for more information
+#
+CONFIG_USB_STORAGE=y
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_ISD200 is not set
+# CONFIG_USB_STORAGE_DPCM is not set
+# CONFIG_USB_STORAGE_USBAT is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_STORAGE_ALAUDA is not set
+# CONFIG_USB_STORAGE_ONETOUCH is not set
+# CONFIG_USB_STORAGE_KARMA is not set
+# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set
+# CONFIG_USB_LIBUSUAL is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+
+#
+# USB port drivers
+#
+# CONFIG_USB_SERIAL is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_ADUTUX is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_BERRY_CHARGE is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_PHIDGET is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_FTDI_ELAN is not set
+# CONFIG_USB_APPLEDISPLAY is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_IOWARRIOR is not set
+# CONFIG_USB_TEST is not set
+# CONFIG_USB_ISIGHTFW is not set
+# CONFIG_USB_GADGET is not set
+CONFIG_MMC=m
+# CONFIG_MMC_DEBUG is not set
+# CONFIG_MMC_UNSAFE_RESUME is not set
+
+#
+# MMC/SD Card Drivers
+#
+CONFIG_MMC_BLOCK=m
+CONFIG_MMC_BLOCK_BOUNCE=y
+# CONFIG_SDIO_UART is not set
+# CONFIG_MMC_TEST is not set
+
+#
+# MMC/SD Host Controller Drivers
+#
+CONFIG_MMC_PXA=m
+# CONFIG_MMC_SDHCI is not set
+# CONFIG_MMC_TIFM_SD is not set
+# CONFIG_MMC_SDRICOH_CS is not set
+# CONFIG_MEMSTICK is not set
+# CONFIG_ACCESSIBILITY is not set
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+
+#
+# LED drivers
+#
+# CONFIG_LEDS_PCA9532 is not set
+# CONFIG_LEDS_GPIO is not set
+CONFIG_LEDS_CM_X270=y
+# CONFIG_LEDS_PCA955X is not set
+
+#
+# LED Triggers
+#
+CONFIG_LEDS_TRIGGERS=y
+# CONFIG_LEDS_TRIGGER_TIMER is not set
+CONFIG_LEDS_TRIGGER_HEARTBEAT=y
+# CONFIG_LEDS_TRIGGER_DEFAULT_ON is not set
+CONFIG_RTC_LIB=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+# CONFIG_RTC_DEBUG is not set
+
+#
+# RTC interfaces
+#
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_DEV=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+# CONFIG_RTC_DRV_TEST is not set
+
+#
+# I2C RTC drivers
+#
+# CONFIG_RTC_DRV_DS1307 is not set
+# CONFIG_RTC_DRV_DS1374 is not set
+# CONFIG_RTC_DRV_DS1672 is not set
+# CONFIG_RTC_DRV_MAX6900 is not set
+# CONFIG_RTC_DRV_RS5C372 is not set
+# CONFIG_RTC_DRV_ISL1208 is not set
+# CONFIG_RTC_DRV_X1205 is not set
+# CONFIG_RTC_DRV_PCF8563 is not set
+# CONFIG_RTC_DRV_PCF8583 is not set
+# CONFIG_RTC_DRV_M41T80 is not set
+# CONFIG_RTC_DRV_S35390A is not set
+# CONFIG_RTC_DRV_FM3130 is not set
+
+#
+# SPI RTC drivers
+#
+
+#
+# Platform RTC drivers
+#
+# CONFIG_RTC_DRV_CMOS is not set
+# CONFIG_RTC_DRV_DS1511 is not set
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_STK17TA8 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_M48T59 is not set
+CONFIG_RTC_DRV_V3020=y
+
+#
+# on-CPU RTC drivers
+#
+CONFIG_RTC_DRV_SA1100=y
+# CONFIG_DMADEVICES is not set
+
+#
+# Voltage and Current regulators
+#
+# CONFIG_REGULATOR is not set
+# CONFIG_REGULATOR_FIXED_VOLTAGE is not set
+# CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set
+# CONFIG_REGULATOR_BQ24022 is not set
+# CONFIG_UIO is not set
+
+#
+# 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_EXT4DEV_FS is not set
+CONFIG_JBD=y
+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_DNOTIFY=y
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+# 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_FAT_FS=m
+# CONFIG_MSDOS_FS is not set
+CONFIG_VFAT_FS=m
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+# 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_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_FS_WBUF_VERIFY is not set
+CONFIG_JFFS2_SUMMARY=y
+# CONFIG_JFFS2_FS_XATTR is not set
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+# CONFIG_JFFS2_LZO is not set
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_OMFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+CONFIG_NETWORK_FILESYSTEMS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+# CONFIG_NFS_V4 is not set
+CONFIG_ROOT_NFS=y
+# CONFIG_NFSD is not set
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+CONFIG_CIFS=m
+# CONFIG_CIFS_STATS is not set
+# CONFIG_CIFS_WEAK_PW_HASH is not set
+# CONFIG_CIFS_XATTR is not set
+# CONFIG_CIFS_DEBUG2 is not set
+# CONFIG_CIFS_EXPERIMENTAL is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_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
+# CONFIG_SYSV68_PARTITION is not set
+CONFIG_NLS=m
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=m
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+CONFIG_NLS_ISO8859_1=m
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+CONFIG_NLS_UTF8=m
+# CONFIG_DLM is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_FRAME_WARN=0
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
+# CONFIG_DETECT_SOFTLOCKUP is not set
+# CONFIG_SCHED_DEBUG is not set
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_TIMER_STATS is not set
+# CONFIG_DEBUG_OBJECTS is not set
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_KOBJECT is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_WRITECOUNT is not set
+# CONFIG_DEBUG_MEMORY_INIT is not set
+# CONFIG_DEBUG_LIST is not set
+# CONFIG_DEBUG_SG is not set
+CONFIG_FRAME_POINTER=y
+# CONFIG_BOOT_PRINTK_DELAY is not set
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_BACKTRACE_SELF_TEST is not set
+# CONFIG_FAULT_INJECTION is not set
+# CONFIG_LATENCYTOP is not set
+CONFIG_SYSCTL_SYSCALL_CHECK=y
+CONFIG_HAVE_FTRACE=y
+CONFIG_HAVE_DYNAMIC_FTRACE=y
+# CONFIG_FTRACE is not set
+# CONFIG_IRQSOFF_TRACER is not set
+# CONFIG_SCHED_TRACER is not set
+# CONFIG_CONTEXT_SWITCH_TRACER is not set
+# CONFIG_SAMPLES is not set
+CONFIG_HAVE_ARCH_KGDB=y
+# CONFIG_KGDB is not set
+CONFIG_DEBUG_USER=y
+CONFIG_DEBUG_ERRORS=y
+# CONFIG_DEBUG_STACK_USAGE is not set
+CONFIG_DEBUG_LL=y
+# CONFIG_DEBUG_ICEDCC is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+# CONFIG_SECURITY_FILE_CAPABILITIES is not set
+CONFIG_CRYPTO=y
+
+#
+# Crypto core or helper
+#
+# CONFIG_CRYPTO_MANAGER is not set
+# CONFIG_CRYPTO_GF128MUL is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_CRYPTD is not set
+# CONFIG_CRYPTO_AUTHENC is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Authenticated Encryption with Associated Data
+#
+# CONFIG_CRYPTO_CCM is not set
+# CONFIG_CRYPTO_GCM is not set
+# CONFIG_CRYPTO_SEQIV is not set
+
+#
+# Block modes
+#
+# CONFIG_CRYPTO_CBC is not set
+# CONFIG_CRYPTO_CTR is not set
+# CONFIG_CRYPTO_CTS is not set
+# CONFIG_CRYPTO_ECB is not set
+# CONFIG_CRYPTO_LRW is not set
+# CONFIG_CRYPTO_PCBC is not set
+# CONFIG_CRYPTO_XTS is not set
+
+#
+# Hash modes
+#
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_XCBC is not set
+
+#
+# Digest
+#
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_MD4 is not set
+# CONFIG_CRYPTO_MD5 is not set
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_RMD128 is not set
+# CONFIG_CRYPTO_RMD160 is not set
+# CONFIG_CRYPTO_RMD256 is not set
+# CONFIG_CRYPTO_RMD320 is not set
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_WP512 is not set
+
+#
+# Ciphers
+#
+# CONFIG_CRYPTO_AES is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_CAMELLIA is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_DES is not set
+# CONFIG_CRYPTO_FCRYPT is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_SALSA20 is not set
+# CONFIG_CRYPTO_SEED is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+
+#
+# Compression
+#
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_LZO is not set
+# CONFIG_CRYPTO_HW is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+# CONFIG_GENERIC_FIND_FIRST_BIT is not set
+# CONFIG_GENERIC_FIND_NEXT_BIT is not set
+CONFIG_CRC_CCITT=m
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_T10DIF is not set
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
diff --git a/arch/arm/include/asm/bug.h b/arch/arm/include/asm/bug.h
index 7b62351..4d88425 100644
--- a/arch/arm/include/asm/bug.h
+++ b/arch/arm/include/asm/bug.h
@@ -12,7 +12,7 @@
 #else
 
 /* this just causes an oops */
-#define BUG()		(*(int *)0 = 0)
+#define BUG()		do { *(int *)0 = 0; } while (1)
 
 #endif
 
diff --git a/arch/arm/include/asm/cacheflush.h b/arch/arm/include/asm/cacheflush.h
index 9073d9c..de6c59f 100644
--- a/arch/arm/include/asm/cacheflush.h
+++ b/arch/arm/include/asm/cacheflush.h
@@ -444,94 +444,4 @@
 	dmac_inv_range(start, start + size);
 }
 
-#define __cacheid_present(val)			(val != read_cpuid(CPUID_ID))
-#define __cacheid_type_v7(val)			((val & (7 << 29)) == (4 << 29))
-
-#define __cacheid_vivt_prev7(val)		((val & (15 << 25)) != (14 << 25))
-#define __cacheid_vipt_prev7(val)		((val & (15 << 25)) == (14 << 25))
-#define __cacheid_vipt_nonaliasing_prev7(val)	((val & (15 << 25 | 1 << 23)) == (14 << 25))
-#define __cacheid_vipt_aliasing_prev7(val)	((val & (15 << 25 | 1 << 23)) == (14 << 25 | 1 << 23))
-
-#define __cacheid_vivt(val)			(__cacheid_type_v7(val) ? 0 : __cacheid_vivt_prev7(val))
-#define __cacheid_vipt(val)			(__cacheid_type_v7(val) ? 1 : __cacheid_vipt_prev7(val))
-#define __cacheid_vipt_nonaliasing(val)		(__cacheid_type_v7(val) ? 1 : __cacheid_vipt_nonaliasing_prev7(val))
-#define __cacheid_vipt_aliasing(val)		(__cacheid_type_v7(val) ? 0 : __cacheid_vipt_aliasing_prev7(val))
-#define __cacheid_vivt_asid_tagged_instr(val)	(__cacheid_type_v7(val) ? ((val & (3 << 14)) == (1 << 14)) : 0)
-
-#if defined(CONFIG_CPU_CACHE_VIVT) && !defined(CONFIG_CPU_CACHE_VIPT)
-/*
- * VIVT caches only
- */
-#define cache_is_vivt()			1
-#define cache_is_vipt()			0
-#define cache_is_vipt_nonaliasing()	0
-#define cache_is_vipt_aliasing()	0
-#define icache_is_vivt_asid_tagged()	0
-
-#elif !defined(CONFIG_CPU_CACHE_VIVT) && defined(CONFIG_CPU_CACHE_VIPT)
-/*
- * VIPT caches only
- */
-#define cache_is_vivt()			0
-#define cache_is_vipt()			1
-#define cache_is_vipt_nonaliasing()					\
-	({								\
-		unsigned int __val = read_cpuid(CPUID_CACHETYPE);	\
-		__cacheid_vipt_nonaliasing(__val);			\
-	})
-
-#define cache_is_vipt_aliasing()					\
-	({								\
-		unsigned int __val = read_cpuid(CPUID_CACHETYPE);	\
-		__cacheid_vipt_aliasing(__val);				\
-	})
-
-#define icache_is_vivt_asid_tagged()					\
-	({								\
-		unsigned int __val = read_cpuid(CPUID_CACHETYPE);	\
-		__cacheid_vivt_asid_tagged_instr(__val);		\
-	})
-
-#else
-/*
- * VIVT or VIPT caches.  Note that this is unreliable since ARM926
- * and V6 CPUs satisfy the "(val & (15 << 25)) == (14 << 25)" test.
- * There's no way to tell from the CacheType register what type (!)
- * the cache is.
- */
-#define cache_is_vivt()							\
-	({								\
-		unsigned int __val = read_cpuid(CPUID_CACHETYPE);	\
-		(!__cacheid_present(__val)) || __cacheid_vivt(__val);	\
-	})
-		
-#define cache_is_vipt()							\
-	({								\
-		unsigned int __val = read_cpuid(CPUID_CACHETYPE);	\
-		__cacheid_present(__val) && __cacheid_vipt(__val);	\
-	})
-
-#define cache_is_vipt_nonaliasing()					\
-	({								\
-		unsigned int __val = read_cpuid(CPUID_CACHETYPE);	\
-		__cacheid_present(__val) &&				\
-		 __cacheid_vipt_nonaliasing(__val);			\
-	})
-
-#define cache_is_vipt_aliasing()					\
-	({								\
-		unsigned int __val = read_cpuid(CPUID_CACHETYPE);	\
-		__cacheid_present(__val) &&				\
-		 __cacheid_vipt_aliasing(__val);			\
-	})
-
-#define icache_is_vivt_asid_tagged()					\
-	({								\
-		unsigned int __val = read_cpuid(CPUID_CACHETYPE);	\
-		__cacheid_present(__val) &&				\
-		 __cacheid_vivt_asid_tagged_instr(__val);		\
-	})
-
-#endif
-
 #endif
diff --git a/arch/arm/include/asm/cachetype.h b/arch/arm/include/asm/cachetype.h
new file mode 100644
index 0000000..d3a4c2c
--- /dev/null
+++ b/arch/arm/include/asm/cachetype.h
@@ -0,0 +1,52 @@
+#ifndef __ASM_ARM_CACHETYPE_H
+#define __ASM_ARM_CACHETYPE_H
+
+#define CACHEID_VIVT			(1 << 0)
+#define CACHEID_VIPT_NONALIASING	(1 << 1)
+#define CACHEID_VIPT_ALIASING		(1 << 2)
+#define CACHEID_VIPT			(CACHEID_VIPT_ALIASING|CACHEID_VIPT_NONALIASING)
+#define CACHEID_ASID_TAGGED		(1 << 3)
+
+extern unsigned int cacheid;
+
+#define cache_is_vivt()			cacheid_is(CACHEID_VIVT)
+#define cache_is_vipt()			cacheid_is(CACHEID_VIPT)
+#define cache_is_vipt_nonaliasing()	cacheid_is(CACHEID_VIPT_NONALIASING)
+#define cache_is_vipt_aliasing()	cacheid_is(CACHEID_VIPT_ALIASING)
+#define icache_is_vivt_asid_tagged()	cacheid_is(CACHEID_ASID_TAGGED)
+
+/*
+ * __LINUX_ARM_ARCH__ is the minimum supported CPU architecture
+ * Mask out support which will never be present on newer CPUs.
+ * - v6+ is never VIVT
+ * - v7+ VIPT never aliases
+ */
+#if __LINUX_ARM_ARCH__ >= 7
+#define __CACHEID_ARCH_MIN	(CACHEID_VIPT_NONALIASING | CACHEID_ASID_TAGGED)
+#elif __LINUX_ARM_ARCH__ >= 6
+#define	__CACHEID_ARCH_MIN	(~CACHEID_VIVT)
+#else
+#define __CACHEID_ARCH_MIN	(~0)
+#endif
+
+/*
+ * Mask out support which isn't configured
+ */
+#if defined(CONFIG_CPU_CACHE_VIVT) && !defined(CONFIG_CPU_CACHE_VIPT)
+#define __CACHEID_ALWAYS	(CACHEID_VIVT)
+#define __CACHEID_NEVER		(~CACHEID_VIVT)
+#elif !defined(CONFIG_CPU_CACHE_VIVT) && defined(CONFIG_CPU_CACHE_VIPT)
+#define __CACHEID_ALWAYS	(0)
+#define __CACHEID_NEVER		(CACHEID_VIVT)
+#else
+#define __CACHEID_ALWAYS	(0)
+#define __CACHEID_NEVER		(0)
+#endif
+
+static inline unsigned int __attribute__((pure)) cacheid_is(unsigned int mask)
+{
+	return (__CACHEID_ALWAYS & mask) |
+	       (~__CACHEID_NEVER & __CACHEID_ARCH_MIN & mask & cacheid);
+}
+
+#endif
diff --git a/arch/arm/include/asm/cnt32_to_63.h b/arch/arm/include/asm/cnt32_to_63.h
deleted file mode 100644
index 480c873..0000000
--- a/arch/arm/include/asm/cnt32_to_63.h
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- *  include/asm/cnt32_to_63.h -- extend a 32-bit counter to 63 bits
- *
- *  Author:	Nicolas Pitre
- *  Created:	December 3, 2006
- *  Copyright:	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 version 2
- * as published by the Free Software Foundation.
- */
-
-#ifndef __INCLUDE_CNT32_TO_63_H__
-#define __INCLUDE_CNT32_TO_63_H__
-
-#include <linux/compiler.h>
-#include <asm/types.h>
-#include <asm/byteorder.h>
-
-/*
- * Prototype: u64 cnt32_to_63(u32 cnt)
- * Many hardware clock counters are only 32 bits wide and therefore have
- * a relatively short period making wrap-arounds rather frequent.  This
- * is a problem when implementing sched_clock() for example, where a 64-bit
- * non-wrapping monotonic value is expected to be returned.
- *
- * To overcome that limitation, let's extend a 32-bit counter to 63 bits
- * in a completely lock free fashion. Bits 0 to 31 of the clock are provided
- * by the hardware while bits 32 to 62 are stored in memory.  The top bit in
- * memory is used to synchronize with the hardware clock half-period.  When
- * the top bit of both counters (hardware and in memory) differ then the
- * memory is updated with a new value, incrementing it when the hardware
- * counter wraps around.
- *
- * Because a word store in memory is atomic then the incremented value will
- * always be in synch with the top bit indicating to any potential concurrent
- * reader if the value in memory is up to date or not with regards to the
- * needed increment.  And any race in updating the value in memory is harmless
- * as the same value would simply be stored more than once.
- *
- * The only restriction for the algorithm to work properly is that this
- * code must be executed at least once per each half period of the 32-bit
- * counter to properly update the state bit in memory. This is usually not a
- * problem in practice, but if it is then a kernel timer could be scheduled
- * to manage for this code to be executed often enough.
- *
- * Note that the top bit (bit 63) in the returned value should be considered
- * as garbage.  It is not cleared here because callers are likely to use a
- * multiplier on the returned value which can get rid of the top bit
- * implicitly by making the multiplier even, therefore saving on a runtime
- * clear-bit instruction. Otherwise caller must remember to clear the top
- * bit explicitly.
- */
-
-/* this is used only to give gcc a clue about good code generation */
-typedef union {
-	struct {
-#if defined(__LITTLE_ENDIAN)
-		u32 lo, hi;
-#elif defined(__BIG_ENDIAN)
-		u32 hi, lo;
-#endif
-	};
-	u64 val;
-} cnt32_to_63_t;
-
-#define cnt32_to_63(cnt_lo) \
-({ \
-	static volatile u32 __m_cnt_hi = 0; \
-	cnt32_to_63_t __x; \
-	__x.hi = __m_cnt_hi; \
-	__x.lo = (cnt_lo); \
- 	if (unlikely((s32)(__x.hi ^ __x.lo) < 0)) \
-		__m_cnt_hi = __x.hi = (__x.hi ^ 0x80000000) + (__x.hi >> 31); \
-	__x.val; \
-})
-
-#endif
diff --git a/arch/arm/include/asm/cputype.h b/arch/arm/include/asm/cputype.h
new file mode 100644
index 0000000..7b9d27e
--- /dev/null
+++ b/arch/arm/include/asm/cputype.h
@@ -0,0 +1,64 @@
+#ifndef __ASM_ARM_CPUTYPE_H
+#define __ASM_ARM_CPUTYPE_H
+
+#include <linux/stringify.h>
+
+#define CPUID_ID	0
+#define CPUID_CACHETYPE	1
+#define CPUID_TCM	2
+#define CPUID_TLBTYPE	3
+
+#ifdef CONFIG_CPU_CP15
+#define read_cpuid(reg)							\
+	({								\
+		unsigned int __val;					\
+		asm("mrc	p15, 0, %0, c0, c0, " __stringify(reg)	\
+		    : "=r" (__val)					\
+		    :							\
+		    : "cc");						\
+		__val;							\
+	})
+#else
+extern unsigned int processor_id;
+#define read_cpuid(reg) (processor_id)
+#endif
+
+/*
+ * The CPU ID never changes at run time, so we might as well tell the
+ * compiler that it's constant.  Use this function to read the CPU ID
+ * rather than directly reading processor_id or read_cpuid() directly.
+ */
+static inline unsigned int __attribute_const__ read_cpuid_id(void)
+{
+	return read_cpuid(CPUID_ID);
+}
+
+static inline unsigned int __attribute_const__ read_cpuid_cachetype(void)
+{
+	return read_cpuid(CPUID_CACHETYPE);
+}
+
+/*
+ * Intel's XScale3 core supports some v6 features (supersections, L2)
+ * but advertises itself as v5 as it does not support the v6 ISA.  For
+ * this reason, we need a way to explicitly test for this type of CPU.
+ */
+#ifndef CONFIG_CPU_XSC3
+#define cpu_is_xsc3()	0
+#else
+static inline int cpu_is_xsc3(void)
+{
+	if ((read_cpuid_id() & 0xffffe000) == 0x69056000)
+		return 1;
+
+	return 0;
+}
+#endif
+
+#if !defined(CONFIG_CPU_XSCALE) && !defined(CONFIG_CPU_XSC3)
+#define	cpu_is_xscale()	0
+#else
+#define	cpu_is_xscale()	1
+#endif
+
+#endif
diff --git a/arch/arm/include/asm/dma-mapping.h b/arch/arm/include/asm/dma-mapping.h
index 7b95d20..1cb8602 100644
--- a/arch/arm/include/asm/dma-mapping.h
+++ b/arch/arm/include/asm/dma-mapping.h
@@ -104,15 +104,14 @@
  * Dummy noncoherent implementation.  We don't provide a dma_cache_sync
  * function so drivers using this API are highlighted with build warnings.
  */
-static inline void *
-dma_alloc_noncoherent(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp)
+static inline void *dma_alloc_noncoherent(struct device *dev, size_t size,
+		dma_addr_t *handle, gfp_t gfp)
 {
 	return NULL;
 }
 
-static inline void
-dma_free_noncoherent(struct device *dev, size_t size, void *cpu_addr,
-		     dma_addr_t handle)
+static inline void dma_free_noncoherent(struct device *dev, size_t size,
+		void *cpu_addr, dma_addr_t handle)
 {
 }
 
@@ -127,8 +126,7 @@
  * return the CPU-viewed address, and sets @handle to be the
  * device-viewed address.
  */
-extern void *
-dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp);
+extern void *dma_alloc_coherent(struct device *, size_t, dma_addr_t *, gfp_t);
 
 /**
  * dma_free_coherent - free memory allocated by dma_alloc_coherent
@@ -143,9 +141,7 @@
  * References to memory and mappings associated with cpu_addr/handle
  * during and after this call executing are illegal.
  */
-extern void
-dma_free_coherent(struct device *dev, size_t size, void *cpu_addr,
-		  dma_addr_t handle);
+extern void dma_free_coherent(struct device *, size_t, void *, dma_addr_t);
 
 /**
  * dma_mmap_coherent - map a coherent DMA allocation into user space
@@ -159,8 +155,8 @@
  * into user space.  The coherent DMA buffer must not be freed by the
  * driver until the user space mapping has been released.
  */
-int dma_mmap_coherent(struct device *dev, struct vm_area_struct *vma,
-		      void *cpu_addr, dma_addr_t handle, size_t size);
+int dma_mmap_coherent(struct device *, struct vm_area_struct *,
+		void *, dma_addr_t, size_t);
 
 
 /**
@@ -174,282 +170,16 @@
  * return the CPU-viewed address, and sets @handle to be the
  * device-viewed address.
  */
-extern void *
-dma_alloc_writecombine(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp);
+extern void *dma_alloc_writecombine(struct device *, size_t, dma_addr_t *,
+		gfp_t);
 
 #define dma_free_writecombine(dev,size,cpu_addr,handle) \
 	dma_free_coherent(dev,size,cpu_addr,handle)
 
-int dma_mmap_writecombine(struct device *dev, struct vm_area_struct *vma,
-			  void *cpu_addr, dma_addr_t handle, size_t size);
+int dma_mmap_writecombine(struct device *, struct vm_area_struct *,
+		void *, dma_addr_t, size_t);
 
 
-/**
- * dma_map_single - map a single buffer for streaming DMA
- * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
- * @cpu_addr: CPU direct mapped address of buffer
- * @size: size of buffer to map
- * @dir: DMA transfer direction
- *
- * Ensure that any data held in the cache is appropriately discarded
- * or written back.
- *
- * The device owns this memory once this call has completed.  The CPU
- * can regain ownership by calling dma_unmap_single() or
- * dma_sync_single_for_cpu().
- */
-#ifndef CONFIG_DMABOUNCE
-static inline dma_addr_t
-dma_map_single(struct device *dev, void *cpu_addr, size_t size,
-	       enum dma_data_direction dir)
-{
-	if (!arch_is_coherent())
-		dma_cache_maint(cpu_addr, size, dir);
-
-	return virt_to_dma(dev, cpu_addr);
-}
-#else
-extern dma_addr_t dma_map_single(struct device *,void *, size_t, enum dma_data_direction);
-#endif
-
-/**
- * dma_map_page - map a portion of a page for streaming DMA
- * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
- * @page: page that buffer resides in
- * @offset: offset into page for start of buffer
- * @size: size of buffer to map
- * @dir: DMA transfer direction
- *
- * Ensure that any data held in the cache is appropriately discarded
- * or written back.
- *
- * The device owns this memory once this call has completed.  The CPU
- * can regain ownership by calling dma_unmap_page() or
- * dma_sync_single_for_cpu().
- */
-static inline dma_addr_t
-dma_map_page(struct device *dev, struct page *page,
-	     unsigned long offset, size_t size,
-	     enum dma_data_direction dir)
-{
-	return dma_map_single(dev, page_address(page) + offset, size, dir);
-}
-
-/**
- * dma_unmap_single - unmap a single buffer previously mapped
- * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
- * @handle: DMA address of buffer
- * @size: size of buffer to map
- * @dir: DMA transfer direction
- *
- * Unmap a single streaming mode DMA translation.  The handle and size
- * must match what was provided in the previous dma_map_single() call.
- * All other usages are undefined.
- *
- * After this call, reads by the CPU to the buffer are guaranteed to see
- * whatever the device wrote there.
- */
-#ifndef CONFIG_DMABOUNCE
-static inline void
-dma_unmap_single(struct device *dev, dma_addr_t handle, size_t size,
-		 enum dma_data_direction dir)
-{
-	/* nothing to do */
-}
-#else
-extern void dma_unmap_single(struct device *, dma_addr_t, size_t, enum dma_data_direction);
-#endif
-
-/**
- * dma_unmap_page - unmap a buffer previously mapped through dma_map_page()
- * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
- * @handle: DMA address of buffer
- * @size: size of buffer to map
- * @dir: DMA transfer direction
- *
- * Unmap a single streaming mode DMA translation.  The handle and size
- * must match what was provided in the previous dma_map_single() call.
- * All other usages are undefined.
- *
- * After this call, reads by the CPU to the buffer are guaranteed to see
- * whatever the device wrote there.
- */
-static inline void
-dma_unmap_page(struct device *dev, dma_addr_t handle, size_t size,
-	       enum dma_data_direction dir)
-{
-	dma_unmap_single(dev, handle, size, dir);
-}
-
-/**
- * dma_map_sg - map a set of SG buffers for streaming mode DMA
- * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
- * @sg: list of buffers
- * @nents: number of buffers to map
- * @dir: DMA transfer direction
- *
- * Map a set of buffers described by scatterlist in streaming
- * mode for DMA.  This is the scatter-gather version of the
- * above dma_map_single interface.  Here the scatter gather list
- * elements are each tagged with the appropriate dma address
- * and length.  They are obtained via sg_dma_{address,length}(SG).
- *
- * NOTE: An implementation may be able to use a smaller number of
- *       DMA address/length pairs than there are SG table elements.
- *       (for example via virtual mapping capabilities)
- *       The routine returns the number of addr/length pairs actually
- *       used, at most nents.
- *
- * Device ownership issues as mentioned above for dma_map_single are
- * the same here.
- */
-#ifndef CONFIG_DMABOUNCE
-static inline int
-dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
-	   enum dma_data_direction dir)
-{
-	int i;
-
-	for (i = 0; i < nents; i++, sg++) {
-		char *virt;
-
-		sg->dma_address = page_to_dma(dev, sg_page(sg)) + sg->offset;
-		virt = sg_virt(sg);
-
-		if (!arch_is_coherent())
-			dma_cache_maint(virt, sg->length, dir);
-	}
-
-	return nents;
-}
-#else
-extern int dma_map_sg(struct device *, struct scatterlist *, int, enum dma_data_direction);
-#endif
-
-/**
- * dma_unmap_sg - unmap a set of SG buffers mapped by dma_map_sg
- * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
- * @sg: list of buffers
- * @nents: number of buffers to map
- * @dir: DMA transfer direction
- *
- * Unmap a set of streaming mode DMA translations.
- * Again, CPU read rules concerning calls here are the same as for
- * dma_unmap_single() above.
- */
-#ifndef CONFIG_DMABOUNCE
-static inline void
-dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nents,
-	     enum dma_data_direction dir)
-{
-
-	/* nothing to do */
-}
-#else
-extern void dma_unmap_sg(struct device *, struct scatterlist *, int, enum dma_data_direction);
-#endif
-
-
-/**
- * dma_sync_single_range_for_cpu
- * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
- * @handle: DMA address of buffer
- * @offset: offset of region to start sync
- * @size: size of region to sync
- * @dir: DMA transfer direction (same as passed to dma_map_single)
- *
- * Make physical memory consistent for a single streaming mode DMA
- * translation after a transfer.
- *
- * If you perform a dma_map_single() but wish to interrogate the
- * buffer using the cpu, yet do not wish to teardown the PCI dma
- * mapping, you must call this function before doing so.  At the
- * next point you give the PCI dma address back to the card, you
- * must first the perform a dma_sync_for_device, and then the
- * device again owns the buffer.
- */
-#ifndef CONFIG_DMABOUNCE
-static inline void
-dma_sync_single_range_for_cpu(struct device *dev, dma_addr_t handle,
-			      unsigned long offset, size_t size,
-			      enum dma_data_direction dir)
-{
-	if (!arch_is_coherent())
-		dma_cache_maint(dma_to_virt(dev, handle) + offset, size, dir);
-}
-
-static inline void
-dma_sync_single_range_for_device(struct device *dev, dma_addr_t handle,
-				 unsigned long offset, size_t size,
-				 enum dma_data_direction dir)
-{
-	if (!arch_is_coherent())
-		dma_cache_maint(dma_to_virt(dev, handle) + offset, size, dir);
-}
-#else
-extern void dma_sync_single_range_for_cpu(struct device *, dma_addr_t, unsigned long, size_t, enum dma_data_direction);
-extern void dma_sync_single_range_for_device(struct device *, dma_addr_t, unsigned long, size_t, enum dma_data_direction);
-#endif
-
-static inline void
-dma_sync_single_for_cpu(struct device *dev, dma_addr_t handle, size_t size,
-			enum dma_data_direction dir)
-{
-	dma_sync_single_range_for_cpu(dev, handle, 0, size, dir);
-}
-
-static inline void
-dma_sync_single_for_device(struct device *dev, dma_addr_t handle, size_t size,
-			   enum dma_data_direction dir)
-{
-	dma_sync_single_range_for_device(dev, handle, 0, size, dir);
-}
-
-
-/**
- * dma_sync_sg_for_cpu
- * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
- * @sg: list of buffers
- * @nents: number of buffers to map
- * @dir: DMA transfer direction
- *
- * Make physical memory consistent for a set of streaming
- * mode DMA translations after a transfer.
- *
- * The same as dma_sync_single_for_* but for a scatter-gather list,
- * same rules and usage.
- */
-#ifndef CONFIG_DMABOUNCE
-static inline void
-dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nents,
-		    enum dma_data_direction dir)
-{
-	int i;
-
-	for (i = 0; i < nents; i++, sg++) {
-		char *virt = sg_virt(sg);
-		if (!arch_is_coherent())
-			dma_cache_maint(virt, sg->length, dir);
-	}
-}
-
-static inline void
-dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, int nents,
-		       enum dma_data_direction dir)
-{
-	int i;
-
-	for (i = 0; i < nents; i++, sg++) {
-		char *virt = sg_virt(sg);
-		if (!arch_is_coherent())
-			dma_cache_maint(virt, sg->length, dir);
-	}
-}
-#else
-extern void dma_sync_sg_for_cpu(struct device*, struct scatterlist*, int, enum dma_data_direction);
-extern void dma_sync_sg_for_device(struct device*, struct scatterlist*, int, enum dma_data_direction);
-#endif
-
 #ifdef CONFIG_DMABOUNCE
 /*
  * For SA-1111, IXP425, and ADI systems  the dma-mapping functions are "magic"
@@ -475,7 +205,8 @@
  * appropriate DMA pools for the device.
  *
  */
-extern int dmabounce_register_dev(struct device *, unsigned long, unsigned long);
+extern int dmabounce_register_dev(struct device *, unsigned long,
+		unsigned long);
 
 /**
  * dmabounce_unregister_dev
@@ -506,7 +237,184 @@
  *
  */
 extern int dma_needs_bounce(struct device*, dma_addr_t, size_t);
+
+/*
+ * The DMA API, implemented by dmabounce.c.  See below for descriptions.
+ */
+extern dma_addr_t dma_map_single(struct device *, void *, size_t,
+		enum dma_data_direction);
+extern dma_addr_t dma_map_page(struct device *, struct page *,
+		unsigned long, size_t, enum dma_data_direction);
+extern void dma_unmap_single(struct device *, dma_addr_t, size_t,
+		enum dma_data_direction);
+
+/*
+ * Private functions
+ */
+int dmabounce_sync_for_cpu(struct device *, dma_addr_t, unsigned long,
+		size_t, enum dma_data_direction);
+int dmabounce_sync_for_device(struct device *, dma_addr_t, unsigned long,
+		size_t, enum dma_data_direction);
+#else
+#define dmabounce_sync_for_cpu(dev,dma,off,sz,dir)	(1)
+#define dmabounce_sync_for_device(dev,dma,off,sz,dir)	(1)
+
+
+/**
+ * dma_map_single - map a single buffer for streaming DMA
+ * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
+ * @cpu_addr: CPU direct mapped address of buffer
+ * @size: size of buffer to map
+ * @dir: DMA transfer direction
+ *
+ * Ensure that any data held in the cache is appropriately discarded
+ * or written back.
+ *
+ * The device owns this memory once this call has completed.  The CPU
+ * can regain ownership by calling dma_unmap_single() or
+ * dma_sync_single_for_cpu().
+ */
+static inline dma_addr_t dma_map_single(struct device *dev, void *cpu_addr,
+		size_t size, enum dma_data_direction dir)
+{
+	BUG_ON(!valid_dma_direction(dir));
+
+	if (!arch_is_coherent())
+		dma_cache_maint(cpu_addr, size, dir);
+
+	return virt_to_dma(dev, cpu_addr);
+}
+
+/**
+ * dma_map_page - map a portion of a page for streaming DMA
+ * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
+ * @page: page that buffer resides in
+ * @offset: offset into page for start of buffer
+ * @size: size of buffer to map
+ * @dir: DMA transfer direction
+ *
+ * Ensure that any data held in the cache is appropriately discarded
+ * or written back.
+ *
+ * The device owns this memory once this call has completed.  The CPU
+ * can regain ownership by calling dma_unmap_page().
+ */
+static inline dma_addr_t dma_map_page(struct device *dev, struct page *page,
+	     unsigned long offset, size_t size, enum dma_data_direction dir)
+{
+	BUG_ON(!valid_dma_direction(dir));
+
+	if (!arch_is_coherent())
+		dma_cache_maint(page_address(page) + offset, size, dir);
+
+	return page_to_dma(dev, page) + offset;
+}
+
+/**
+ * dma_unmap_single - unmap a single buffer previously mapped
+ * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
+ * @handle: DMA address of buffer
+ * @size: size of buffer (same as passed to dma_map_single)
+ * @dir: DMA transfer direction (same as passed to dma_map_single)
+ *
+ * Unmap a single streaming mode DMA translation.  The handle and size
+ * must match what was provided in the previous dma_map_single() call.
+ * All other usages are undefined.
+ *
+ * After this call, reads by the CPU to the buffer are guaranteed to see
+ * whatever the device wrote there.
+ */
+static inline void dma_unmap_single(struct device *dev, dma_addr_t handle,
+		size_t size, enum dma_data_direction dir)
+{
+	/* nothing to do */
+}
 #endif /* CONFIG_DMABOUNCE */
 
+/**
+ * dma_unmap_page - unmap a buffer previously mapped through dma_map_page()
+ * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
+ * @handle: DMA address of buffer
+ * @size: size of buffer (same as passed to dma_map_page)
+ * @dir: DMA transfer direction (same as passed to dma_map_page)
+ *
+ * Unmap a page streaming mode DMA translation.  The handle and size
+ * must match what was provided in the previous dma_map_page() call.
+ * All other usages are undefined.
+ *
+ * After this call, reads by the CPU to the buffer are guaranteed to see
+ * whatever the device wrote there.
+ */
+static inline void dma_unmap_page(struct device *dev, dma_addr_t handle,
+		size_t size, enum dma_data_direction dir)
+{
+	dma_unmap_single(dev, handle, size, dir);
+}
+
+/**
+ * dma_sync_single_range_for_cpu
+ * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
+ * @handle: DMA address of buffer
+ * @offset: offset of region to start sync
+ * @size: size of region to sync
+ * @dir: DMA transfer direction (same as passed to dma_map_single)
+ *
+ * Make physical memory consistent for a single streaming mode DMA
+ * translation after a transfer.
+ *
+ * If you perform a dma_map_single() but wish to interrogate the
+ * buffer using the cpu, yet do not wish to teardown the PCI dma
+ * mapping, you must call this function before doing so.  At the
+ * next point you give the PCI dma address back to the card, you
+ * must first the perform a dma_sync_for_device, and then the
+ * device again owns the buffer.
+ */
+static inline void dma_sync_single_range_for_cpu(struct device *dev,
+		dma_addr_t handle, unsigned long offset, size_t size,
+		enum dma_data_direction dir)
+{
+	BUG_ON(!valid_dma_direction(dir));
+
+	dmabounce_sync_for_cpu(dev, handle, offset, size, dir);
+}
+
+static inline void dma_sync_single_range_for_device(struct device *dev,
+		dma_addr_t handle, unsigned long offset, size_t size,
+		enum dma_data_direction dir)
+{
+	BUG_ON(!valid_dma_direction(dir));
+
+	if (!dmabounce_sync_for_device(dev, handle, offset, size, dir))
+		return;
+
+	if (!arch_is_coherent())
+		dma_cache_maint(dma_to_virt(dev, handle) + offset, size, dir);
+}
+
+static inline void dma_sync_single_for_cpu(struct device *dev,
+		dma_addr_t handle, size_t size, enum dma_data_direction dir)
+{
+	dma_sync_single_range_for_cpu(dev, handle, 0, size, dir);
+}
+
+static inline void dma_sync_single_for_device(struct device *dev,
+		dma_addr_t handle, size_t size, enum dma_data_direction dir)
+{
+	dma_sync_single_range_for_device(dev, handle, 0, size, dir);
+}
+
+/*
+ * The scatter list versions of the above methods.
+ */
+extern int dma_map_sg(struct device *, struct scatterlist *, int,
+		enum dma_data_direction);
+extern void dma_unmap_sg(struct device *, struct scatterlist *, int,
+		enum dma_data_direction);
+extern void dma_sync_sg_for_cpu(struct device *, struct scatterlist *, int,
+		enum dma_data_direction);
+extern void dma_sync_sg_for_device(struct device *, struct scatterlist *, int,
+		enum dma_data_direction);
+
+
 #endif /* __KERNEL__ */
 #endif
diff --git a/arch/arm/include/asm/elf.h b/arch/arm/include/asm/elf.h
index 4ca7516..5be0169 100644
--- a/arch/arm/include/asm/elf.h
+++ b/arch/arm/include/asm/elf.h
@@ -3,7 +3,6 @@
 
 #include <asm/hwcap.h>
 
-#ifndef __ASSEMBLY__
 /*
  * ELF register definitions..
  */
@@ -17,12 +16,34 @@
 typedef elf_greg_t elf_gregset_t[ELF_NGREG];
 
 typedef struct user_fp elf_fpregset_t;
-#endif
 
 #define EM_ARM	40
-#define EF_ARM_APCS26 0x08
-#define EF_ARM_SOFT_FLOAT 0x200
-#define EF_ARM_EABI_MASK 0xFF000000
+
+#define EF_ARM_EABI_MASK	0xff000000
+#define EF_ARM_EABI_UNKNOWN	0x00000000
+#define EF_ARM_EABI_VER1	0x01000000
+#define EF_ARM_EABI_VER2	0x02000000
+#define EF_ARM_EABI_VER3	0x03000000
+#define EF_ARM_EABI_VER4	0x04000000
+#define EF_ARM_EABI_VER5	0x05000000
+
+#define EF_ARM_BE8		0x00800000	/* ABI 4,5 */
+#define EF_ARM_LE8		0x00400000	/* ABI 4,5 */
+#define EF_ARM_MAVERICK_FLOAT	0x00000800	/* ABI 0 */
+#define EF_ARM_VFP_FLOAT	0x00000400	/* ABI 0 */
+#define EF_ARM_SOFT_FLOAT	0x00000200	/* ABI 0 */
+#define EF_ARM_OLD_ABI		0x00000100	/* ABI 0 */
+#define EF_ARM_NEW_ABI		0x00000080	/* ABI 0 */
+#define EF_ARM_ALIGN8		0x00000040	/* ABI 0 */
+#define EF_ARM_PIC		0x00000020	/* ABI 0 */
+#define EF_ARM_MAPSYMSFIRST	0x00000010	/* ABI 2 */
+#define EF_ARM_APCS_FLOAT	0x00000010	/* ABI 0, floats in fp regs */
+#define EF_ARM_DYNSYMSUSESEGIDX	0x00000008	/* ABI 2 */
+#define EF_ARM_APCS_26		0x00000008	/* ABI 0 */
+#define EF_ARM_SYMSARESORTED	0x00000004	/* ABI 1,2 */
+#define EF_ARM_INTERWORK	0x00000004	/* ABI 0 */
+#define EF_ARM_HASENTRY		0x00000002	/* All */
+#define EF_ARM_RELEXEC		0x00000001	/* All */
 
 #define R_ARM_NONE	0
 #define R_ARM_PC24	1
@@ -41,7 +62,6 @@
 #endif
 #define ELF_ARCH	EM_ARM
 
-#ifndef __ASSEMBLY__
 /*
  * This yields a string that ld.so will use to load implementation
  * specific libraries for optimization.  This is more specific in
@@ -59,25 +79,17 @@
 #define ELF_PLATFORM	(elf_platform)
 
 extern char elf_platform[];
-#endif
+
+struct elf32_hdr;
 
 /*
  * This is used to ensure we don't load something for the wrong architecture.
  */
-#define elf_check_arch(x) ((x)->e_machine == EM_ARM && ELF_PROC_OK(x))
+extern int elf_check_arch(const struct elf32_hdr *);
+#define elf_check_arch elf_check_arch
 
-/*
- * 32-bit code is always OK.  Some cpus can do 26-bit, some can't.
- */
-#define ELF_PROC_OK(x)	(ELF_THUMB_OK(x) && ELF_26BIT_OK(x))
-
-#define ELF_THUMB_OK(x) \
-	((elf_hwcap & HWCAP_THUMB && ((x)->e_entry & 1) == 1) || \
-	 ((x)->e_entry & 3) == 0)
-
-#define ELF_26BIT_OK(x) \
-	((elf_hwcap & HWCAP_26BIT && (x)->e_flags & EF_ARM_APCS26) || \
-	  ((x)->e_flags & EF_ARM_APCS26) == 0)
+extern int arm_elf_read_implies_exec(const struct elf32_hdr *, int);
+#define elf_read_implies_exec(ex,stk) arm_elf_read_implies_exec(&(ex), stk)
 
 #define USE_ELF_CORE_DUMP
 #define ELF_EXEC_PAGESIZE	4096
@@ -94,23 +106,7 @@
    have no such handler.  */
 #define ELF_PLAT_INIT(_r, load_addr)	(_r)->ARM_r0 = 0
 
-/*
- * Since the FPA coprocessor uses CP1 and CP2, and iWMMXt uses CP0
- * and CP1, we only enable access to the iWMMXt coprocessor if the
- * binary is EABI or softfloat (and thus, guaranteed not to use
- * FPA instructions.)
- */
-#define SET_PERSONALITY(ex, ibcs2)					\
-	do {								\
-		if ((ex).e_flags & EF_ARM_APCS26) {			\
-			set_personality(PER_LINUX);			\
-		} else {						\
-			set_personality(PER_LINUX_32BIT);		\
-			if (elf_hwcap & HWCAP_IWMMXT && (ex).e_flags & (EF_ARM_EABI_MASK | EF_ARM_SOFT_FLOAT)) \
-				set_thread_flag(TIF_USING_IWMMXT);	\
-			else						\
-				clear_thread_flag(TIF_USING_IWMMXT);	\
-		}							\
-	} while (0)
+extern void elf_set_personality(const struct elf32_hdr *);
+#define SET_PERSONALITY(ex, ibcs2)	elf_set_personality(&(ex))
 
 #endif
diff --git a/arch/arm/include/asm/futex.h b/arch/arm/include/asm/futex.h
index 6a332a9..9ee743b 100644
--- a/arch/arm/include/asm/futex.h
+++ b/arch/arm/include/asm/futex.h
@@ -1,6 +1,124 @@
-#ifndef _ASM_FUTEX_H
-#define _ASM_FUTEX_H
+#ifndef _ASM_ARM_FUTEX_H
+#define _ASM_ARM_FUTEX_H
+
+#ifdef __KERNEL__
+
+#ifdef CONFIG_SMP
 
 #include <asm-generic/futex.h>
 
-#endif
+#else /* !SMP, we can work around lack of atomic ops by disabling preemption */
+
+#include <linux/futex.h>
+#include <linux/preempt.h>
+#include <linux/uaccess.h>
+#include <asm/errno.h>
+
+#define __futex_atomic_op(insn, ret, oldval, uaddr, oparg)	\
+	__asm__ __volatile__(					\
+	"1:	ldrt	%1, [%2]\n"				\
+	"	" insn "\n"					\
+	"2:	strt	%0, [%2]\n"				\
+	"	mov	%0, #0\n"				\
+	"3:\n"							\
+	"	.section __ex_table,\"a\"\n"			\
+	"	.align	3\n"					\
+	"	.long	1b, 4f, 2b, 4f\n"			\
+	"	.previous\n"					\
+	"	.section .fixup,\"ax\"\n"			\
+	"4:	mov	%0, %4\n"				\
+	"	b	3b\n"					\
+	"	.previous"					\
+	: "=&r" (ret), "=&r" (oldval)				\
+	: "r" (uaddr), "r" (oparg), "Ir" (-EFAULT)		\
+	: "cc", "memory")
+
+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;
+
+	pagefault_disable();	/* implies preempt_disable() */
+
+	switch (op) {
+	case FUTEX_OP_SET:
+		__futex_atomic_op("mov	%0, %3", ret, oldval, uaddr, oparg);
+		break;
+	case FUTEX_OP_ADD:
+		__futex_atomic_op("add	%0, %1, %3", ret, oldval, uaddr, oparg);
+		break;
+	case FUTEX_OP_OR:
+		__futex_atomic_op("orr	%0, %1, %3", ret, oldval, uaddr, oparg);
+		break;
+	case FUTEX_OP_ANDN:
+		__futex_atomic_op("and	%0, %1, %3", ret, oldval, uaddr, ~oparg);
+		break;
+	case FUTEX_OP_XOR:
+		__futex_atomic_op("eor	%0, %1, %3", ret, oldval, uaddr, oparg);
+		break;
+	default:
+		ret = -ENOSYS;
+	}
+
+	pagefault_enable();	/* subsumes preempt_enable() */
+
+	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;
+}
+
+static inline int
+futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
+{
+	int val;
+
+	if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
+		return -EFAULT;
+
+	pagefault_disable();	/* implies preempt_disable() */
+
+	__asm__ __volatile__("@futex_atomic_cmpxchg_inatomic\n"
+	"1:	ldrt	%0, [%3]\n"
+	"	teq	%0, %1\n"
+	"2:	streqt	%2, [%3]\n"
+	"3:\n"
+	"	.section __ex_table,\"a\"\n"
+	"	.align	3\n"
+	"	.long	1b, 4f, 2b, 4f\n"
+	"	.previous\n"
+	"	.section .fixup,\"ax\"\n"
+	"4:	mov	%0, %4\n"
+	"	b	3b\n"
+	"	.previous"
+	: "=&r" (val)
+	: "r" (oldval), "r" (newval), "r" (uaddr), "Ir" (-EFAULT)
+	: "cc", "memory");
+
+	pagefault_enable();	/* subsumes preempt_enable() */
+
+	return val;
+}
+
+#endif /* !SMP */
+
+#endif /* __KERNEL__ */
+#endif /* _ASM_ARM_FUTEX_H */
diff --git a/arch/arm/include/asm/io.h b/arch/arm/include/asm/io.h
index 71934856..a809445 100644
--- a/arch/arm/include/asm/io.h
+++ b/arch/arm/include/asm/io.h
@@ -60,10 +60,9 @@
 #define MT_DEVICE		0
 #define MT_DEVICE_NONSHARED	1
 #define MT_DEVICE_CACHED	2
-#define MT_DEVICE_IXP2000	3
-#define MT_DEVICE_WC		4
+#define MT_DEVICE_WC		3
 /*
- * types 5 onwards can be found in asm/mach/map.h and are undefined
+ * types 4 onwards can be found in asm/mach/map.h and are undefined
  * for ioremap
  */
 
diff --git a/arch/arm/include/asm/irq.h b/arch/arm/include/asm/irq.h
index d678609..a0009aa 100644
--- a/arch/arm/include/asm/irq.h
+++ b/arch/arm/include/asm/irq.h
@@ -22,6 +22,10 @@
 #ifndef __ASSEMBLY__
 struct irqaction;
 extern void migrate_irqs(void);
+
+extern void asm_do_IRQ(unsigned int, struct pt_regs *);
+void init_IRQ(void);
+
 #endif
 
 #endif
diff --git a/arch/arm/include/asm/kprobes.h b/arch/arm/include/asm/kprobes.h
index a5d0d99..bb8a19b 100644
--- a/arch/arm/include/asm/kprobes.h
+++ b/arch/arm/include/asm/kprobes.h
@@ -61,7 +61,6 @@
 void arch_remove_kprobe(struct kprobe *);
 void kretprobe_trampoline(void);
 
-int kprobe_trap_handler(struct pt_regs *regs, unsigned int instr);
 int kprobe_fault_handler(struct pt_regs *regs, unsigned int fsr);
 int kprobe_exceptions_notify(struct notifier_block *self,
 			     unsigned long val, void *data);
diff --git a/arch/arm/include/asm/mach/map.h b/arch/arm/include/asm/mach/map.h
index 9eb936e..cb1139a 100644
--- a/arch/arm/include/asm/mach/map.h
+++ b/arch/arm/include/asm/mach/map.h
@@ -18,16 +18,13 @@
 	unsigned int type;
 };
 
-/* types 0-4 are defined in asm/io.h */
-#define MT_CACHECLEAN		5
-#define MT_MINICLEAN		6
-#define MT_LOW_VECTORS		7
-#define MT_HIGH_VECTORS		8
-#define MT_MEMORY		9
-#define MT_ROM			10
-
-#define MT_NONSHARED_DEVICE	MT_DEVICE_NONSHARED
-#define MT_IXP2000_DEVICE	MT_DEVICE_IXP2000
+/* types 0-3 are defined in asm/io.h */
+#define MT_CACHECLEAN		4
+#define MT_MINICLEAN		5
+#define MT_LOW_VECTORS		6
+#define MT_HIGH_VECTORS		7
+#define MT_MEMORY		8
+#define MT_ROM			9
 
 #ifdef CONFIG_MMU
 extern void iotable_init(struct map_desc *, int);
diff --git a/arch/arm/include/asm/mach/udc_pxa2xx.h b/arch/arm/include/asm/mach/udc_pxa2xx.h
index 270902c..f3eabf1 100644
--- a/arch/arm/include/asm/mach/udc_pxa2xx.h
+++ b/arch/arm/include/asm/mach/udc_pxa2xx.h
@@ -18,8 +18,7 @@
 	/* Boards following the design guidelines in the developer's manual,
 	 * with on-chip GPIOs not Lubbock's weird hardware, can have a sane
 	 * VBUS IRQ and omit the methods above.  Store the GPIO number
-	 * here; for GPIO 0, also mask in one of the pxa_gpio_mode() bits.
-	 * Note that sometimes the signals go through inverters...
+	 * here.  Note that sometimes the signals go through inverters...
 	 */
 	bool	gpio_vbus_inverted;
 	u16	gpio_vbus;			/* high == vbus present */
diff --git a/arch/arm/include/asm/mc146818rtc.h b/arch/arm/include/asm/mc146818rtc.h
index e1ca48a..6b884d2 100644
--- a/arch/arm/include/asm/mc146818rtc.h
+++ b/arch/arm/include/asm/mc146818rtc.h
@@ -4,8 +4,8 @@
 #ifndef _ASM_MC146818RTC_H
 #define _ASM_MC146818RTC_H
 
+#include <linux/io.h>
 #include <mach/irqs.h>
-#include <asm/io.h>
 
 #ifndef RTC_PORT
 #define RTC_PORT(x)	(0x70 + (x))
diff --git a/arch/arm/include/asm/memory.h b/arch/arm/include/asm/memory.h
index bf7c737..809ff9a 100644
--- a/arch/arm/include/asm/memory.h
+++ b/arch/arm/include/asm/memory.h
@@ -13,30 +13,27 @@
 #ifndef __ASM_ARM_MEMORY_H
 #define __ASM_ARM_MEMORY_H
 
+#include <linux/compiler.h>
+#include <linux/const.h>
+#include <mach/memory.h>
+#include <asm/sizes.h>
+
 /*
  * Allow for constants defined here to be used from assembly code
  * by prepending the UL suffix only with actual C code compilation.
  */
-#ifndef __ASSEMBLY__
-#define UL(x) (x##UL)
-#else
-#define UL(x) (x)
-#endif
-
-#include <linux/compiler.h>
-#include <mach/memory.h>
-#include <asm/sizes.h>
+#define UL(x) _AC(x, UL)
 
 #ifdef CONFIG_MMU
 
-#ifndef TASK_SIZE
 /*
+ * PAGE_OFFSET - the virtual address of the start of the kernel image
  * TASK_SIZE - the maximum size of a user space task.
  * TASK_UNMAPPED_BASE - the lower boundary of the mmap VM area
  */
-#define TASK_SIZE		UL(0xbf000000)
-#define TASK_UNMAPPED_BASE	UL(0x40000000)
-#endif
+#define PAGE_OFFSET		UL(CONFIG_PAGE_OFFSET)
+#define TASK_SIZE		(UL(CONFIG_PAGE_OFFSET) - UL(0x01000000))
+#define TASK_UNMAPPED_BASE	(UL(CONFIG_PAGE_OFFSET) / 3)
 
 /*
  * The maximum size of a 26-bit user space task.
@@ -44,13 +41,6 @@
 #define TASK_SIZE_26		UL(0x04000000)
 
 /*
- * Page offset: 3GB
- */
-#ifndef PAGE_OFFSET
-#define PAGE_OFFSET		UL(0xc0000000)
-#endif
-
-/*
  * The module space lives between the addresses given by TASK_SIZE
  * and PAGE_OFFSET - it must be within 32MB of the kernel text.
  */
@@ -147,17 +137,11 @@
 
 #ifndef arch_adjust_zones
 #define arch_adjust_zones(node,size,holes) do { } while (0)
+#elif !defined(CONFIG_ZONE_DMA)
+#error "custom arch_adjust_zones() requires CONFIG_ZONE_DMA"
 #endif
 
 /*
- * Amount of memory reserved for the vmalloc() area, and minimum
- * address for vmalloc mappings.
- */
-extern unsigned long vmalloc_reserve;
-
-#define VMALLOC_MIN		(void *)(VMALLOC_END - vmalloc_reserve)
-
-/*
  * PFNs are used to describe any physical page; this means
  * PFN 0 == physical address 0.
  *
diff --git a/arch/arm/include/asm/mmu_context.h b/arch/arm/include/asm/mmu_context.h
index a301e44..0559f37 100644
--- a/arch/arm/include/asm/mmu_context.h
+++ b/arch/arm/include/asm/mmu_context.h
@@ -15,6 +15,7 @@
 
 #include <linux/compiler.h>
 #include <asm/cacheflush.h>
+#include <asm/cachetype.h>
 #include <asm/proc-fns.h>
 #include <asm-generic/mm_hooks.h>
 
diff --git a/arch/arm/include/asm/page.h b/arch/arm/include/asm/page.h
index cf2e268..bed1c0a 100644
--- a/arch/arm/include/asm/page.h
+++ b/arch/arm/include/asm/page.h
@@ -184,8 +184,9 @@
 
 #endif /* !__ASSEMBLY__ */
 
-#define VM_DATA_DEFAULT_FLAGS	(VM_READ | VM_WRITE | VM_EXEC | \
-				 VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
+#define VM_DATA_DEFAULT_FLAGS \
+	(((current->personality & READ_IMPLIES_EXEC) ? VM_EXEC : 0) | \
+	 VM_READ | VM_WRITE | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
 
 /*
  * With EABI on ARMv5 and above we must have 64-bit aligned slab pointers.
diff --git a/arch/arm/include/asm/pgtable.h b/arch/arm/include/asm/pgtable.h
index 8e21ef1..110295c 100644
--- a/arch/arm/include/asm/pgtable.h
+++ b/arch/arm/include/asm/pgtable.h
@@ -164,14 +164,30 @@
 #define L_PTE_PRESENT		(1 << 0)
 #define L_PTE_FILE		(1 << 1)	/* only when !PRESENT */
 #define L_PTE_YOUNG		(1 << 1)
-#define L_PTE_BUFFERABLE	(1 << 2)	/* matches PTE */
-#define L_PTE_CACHEABLE		(1 << 3)	/* matches PTE */
-#define L_PTE_USER		(1 << 4)
-#define L_PTE_WRITE		(1 << 5)
-#define L_PTE_EXEC		(1 << 6)
-#define L_PTE_DIRTY		(1 << 7)
+#define L_PTE_BUFFERABLE	(1 << 2)	/* obsolete, matches PTE */
+#define L_PTE_CACHEABLE		(1 << 3)	/* obsolete, matches PTE */
+#define L_PTE_DIRTY		(1 << 6)
+#define L_PTE_WRITE		(1 << 7)
+#define L_PTE_USER		(1 << 8)
+#define L_PTE_EXEC		(1 << 9)
 #define L_PTE_SHARED		(1 << 10)	/* shared(v6), coherent(xsc3) */
 
+/*
+ * These are the memory types, defined to be compatible with
+ * pre-ARMv6 CPUs cacheable and bufferable bits:   XXCB
+ */
+#define L_PTE_MT_UNCACHED	(0x00 << 2)	/* 0000 */
+#define L_PTE_MT_BUFFERABLE	(0x01 << 2)	/* 0001 */
+#define L_PTE_MT_WRITETHROUGH	(0x02 << 2)	/* 0010 */
+#define L_PTE_MT_WRITEBACK	(0x03 << 2)	/* 0011 */
+#define L_PTE_MT_MINICACHE	(0x06 << 2)	/* 0110 (sa1100, xscale) */
+#define L_PTE_MT_WRITEALLOC	(0x07 << 2)	/* 0111 */
+#define L_PTE_MT_DEV_SHARED	(0x04 << 2)	/* 0100 */
+#define L_PTE_MT_DEV_NONSHARED	(0x0c << 2)	/* 1100 */
+#define L_PTE_MT_DEV_WC		(0x09 << 2)	/* 1001 */
+#define L_PTE_MT_DEV_CACHED	(0x0b << 2)	/* 1011 */
+#define L_PTE_MT_MASK		(0x0f << 2)
+
 #ifndef __ASSEMBLY__
 
 /*
@@ -180,23 +196,30 @@
  * as well as any architecture dependent bits like global/ASID and SMP
  * shared mapping bits.
  */
-#define _L_PTE_DEFAULT	L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_CACHEABLE | L_PTE_BUFFERABLE
-#define _L_PTE_READ	L_PTE_USER | L_PTE_EXEC
+#define _L_PTE_DEFAULT	L_PTE_PRESENT | L_PTE_YOUNG
 
 extern pgprot_t		pgprot_user;
 extern pgprot_t		pgprot_kernel;
 
-#define PAGE_NONE	pgprot_user
-#define PAGE_COPY	__pgprot(pgprot_val(pgprot_user) | _L_PTE_READ)
-#define PAGE_SHARED	__pgprot(pgprot_val(pgprot_user) | _L_PTE_READ | \
-				 L_PTE_WRITE)
-#define PAGE_READONLY	__pgprot(pgprot_val(pgprot_user) | _L_PTE_READ)
-#define PAGE_KERNEL	pgprot_kernel
+#define _MOD_PROT(p, b)	__pgprot(pgprot_val(p) | (b))
 
-#define __PAGE_NONE	__pgprot(_L_PTE_DEFAULT)
-#define __PAGE_COPY	__pgprot(_L_PTE_DEFAULT | _L_PTE_READ)
-#define __PAGE_SHARED	__pgprot(_L_PTE_DEFAULT | _L_PTE_READ | L_PTE_WRITE)
-#define __PAGE_READONLY	__pgprot(_L_PTE_DEFAULT | _L_PTE_READ)
+#define PAGE_NONE		pgprot_user
+#define PAGE_SHARED		_MOD_PROT(pgprot_user, L_PTE_USER | L_PTE_WRITE)
+#define PAGE_SHARED_EXEC	_MOD_PROT(pgprot_user, L_PTE_USER | L_PTE_WRITE | L_PTE_EXEC)
+#define PAGE_COPY		_MOD_PROT(pgprot_user, L_PTE_USER)
+#define PAGE_COPY_EXEC		_MOD_PROT(pgprot_user, L_PTE_USER | L_PTE_EXEC)
+#define PAGE_READONLY		_MOD_PROT(pgprot_user, L_PTE_USER)
+#define PAGE_READONLY_EXEC	_MOD_PROT(pgprot_user, L_PTE_USER | L_PTE_EXEC)
+#define PAGE_KERNEL		pgprot_kernel
+#define PAGE_KERNEL_EXEC	_MOD_PROT(pgprot_kernel, L_PTE_EXEC)
+
+#define __PAGE_NONE		__pgprot(_L_PTE_DEFAULT)
+#define __PAGE_SHARED		__pgprot(_L_PTE_DEFAULT | L_PTE_USER | L_PTE_WRITE)
+#define __PAGE_SHARED_EXEC	__pgprot(_L_PTE_DEFAULT | L_PTE_USER | L_PTE_WRITE | L_PTE_EXEC)
+#define __PAGE_COPY		__pgprot(_L_PTE_DEFAULT | L_PTE_USER)
+#define __PAGE_COPY_EXEC	__pgprot(_L_PTE_DEFAULT | L_PTE_USER | L_PTE_EXEC)
+#define __PAGE_READONLY		__pgprot(_L_PTE_DEFAULT | L_PTE_USER)
+#define __PAGE_READONLY_EXEC	__pgprot(_L_PTE_DEFAULT | L_PTE_USER | L_PTE_EXEC)
 
 #endif /* __ASSEMBLY__ */
 
@@ -212,19 +235,19 @@
 #define __P001  __PAGE_READONLY
 #define __P010  __PAGE_COPY
 #define __P011  __PAGE_COPY
-#define __P100  __PAGE_READONLY
-#define __P101  __PAGE_READONLY
-#define __P110  __PAGE_COPY
-#define __P111  __PAGE_COPY
+#define __P100  __PAGE_READONLY_EXEC
+#define __P101  __PAGE_READONLY_EXEC
+#define __P110  __PAGE_COPY_EXEC
+#define __P111  __PAGE_COPY_EXEC
 
 #define __S000  __PAGE_NONE
 #define __S001  __PAGE_READONLY
 #define __S010  __PAGE_SHARED
 #define __S011  __PAGE_SHARED
-#define __S100  __PAGE_READONLY
-#define __S101  __PAGE_READONLY
-#define __S110  __PAGE_SHARED
-#define __S111  __PAGE_SHARED
+#define __S100  __PAGE_READONLY_EXEC
+#define __S101  __PAGE_READONLY_EXEC
+#define __S110  __PAGE_SHARED_EXEC
+#define __S111  __PAGE_SHARED_EXEC
 
 #ifndef __ASSEMBLY__
 /*
@@ -286,8 +309,10 @@
 /*
  * Mark the prot value as uncacheable and unbufferable.
  */
-#define pgprot_noncached(prot)	__pgprot(pgprot_val(prot) & ~(L_PTE_CACHEABLE | L_PTE_BUFFERABLE))
-#define pgprot_writecombine(prot) __pgprot(pgprot_val(prot) & ~L_PTE_CACHEABLE)
+#define pgprot_noncached(prot) \
+	__pgprot((pgprot_val(prot) & ~L_PTE_MT_MASK) | L_PTE_MT_UNCACHED)
+#define pgprot_writecombine(prot) \
+	__pgprot((pgprot_val(prot) & ~L_PTE_MT_MASK) | L_PTE_MT_BUFFERABLE)
 
 #define pmd_none(pmd)		(!pmd_val(pmd))
 #define pmd_present(pmd)	(pmd_val(pmd))
@@ -320,11 +345,6 @@
 #define pmd_page(pmd) virt_to_page(__va(pmd_val(pmd)))
 
 /*
- * Permanent address of a page. We never have highmem, so this is trivial.
- */
-#define pages_to_mb(x)		((x) >> (20 - PAGE_SHIFT))
-
-/*
  * Conversion functions: convert a page and protection to a page entry,
  * and a page entry and page directory to the page they refer to.
  */
diff --git a/arch/arm/include/asm/ptrace.h b/arch/arm/include/asm/ptrace.h
index b415c0e..7319261 100644
--- a/arch/arm/include/asm/ptrace.h
+++ b/arch/arm/include/asm/ptrace.h
@@ -54,7 +54,6 @@
 #define PSR_C_BIT	0x20000000
 #define PSR_Z_BIT	0x40000000
 #define PSR_N_BIT	0x80000000
-#define PCMASK		0
 
 /*
  * Groups of PSR bits
@@ -139,11 +138,7 @@
 	return 0;
 }
 
-#define pc_pointer(v) \
-	((v) & ~PCMASK)
-
-#define instruction_pointer(regs) \
-	(pc_pointer((regs)->ARM_pc))
+#define instruction_pointer(regs)	(regs)->ARM_pc
 
 #ifdef CONFIG_SMP
 extern unsigned long profile_pc(struct pt_regs *regs);
diff --git a/arch/arm/include/asm/setup.h b/arch/arm/include/asm/setup.h
index 7bbf105..a65413b 100644
--- a/arch/arm/include/asm/setup.h
+++ b/arch/arm/include/asm/setup.h
@@ -209,6 +209,17 @@
 	struct membank bank[NR_BANKS];
 };
 
+#define for_each_nodebank(iter,mi,no)			\
+	for (iter = 0; iter < mi->nr_banks; iter++)	\
+		if (mi->bank[iter].node == no)
+
+#define bank_pfn_start(bank)	__phys_to_pfn((bank)->start)
+#define bank_pfn_end(bank)	__phys_to_pfn((bank)->start + (bank)->size)
+#define bank_pfn_size(bank)	((bank)->size >> PAGE_SHIFT)
+#define bank_phys_start(bank)	(bank)->start
+#define bank_phys_end(bank)	((bank)->start + (bank)->size)
+#define bank_phys_size(bank)	(bank)->size
+
 /*
  * Early command line parameters.
  */
diff --git a/arch/arm/include/asm/sparsemem.h b/arch/arm/include/asm/sparsemem.h
index 2771581..0009861 100644
--- a/arch/arm/include/asm/sparsemem.h
+++ b/arch/arm/include/asm/sparsemem.h
@@ -3,8 +3,22 @@
 
 #include <asm/memory.h>
 
-#define MAX_PHYSADDR_BITS	32
-#define MAX_PHYSMEM_BITS	32
-#define SECTION_SIZE_BITS	NODE_MEM_SIZE_BITS
+/*
+ * Two definitions are required for sparsemem:
+ *
+ * MAX_PHYSMEM_BITS: The number of physical address bits required
+ *   to address the last byte of memory.
+ *
+ * SECTION_SIZE_BITS: The number of physical address bits to cover
+ *   the maximum amount of memory in a section.
+ *
+ * Eg, if you have 2 banks of up to 64MB at 0x80000000, 0x84000000,
+ * then MAX_PHYSMEM_BITS is 32, SECTION_SIZE_BITS is 26.
+ *
+ * Define these in your mach/memory.h.
+ */
+#if !defined(SECTION_SIZE_BITS) || !defined(MAX_PHYSMEM_BITS)
+#error Sparsemem is not supported on this platform
+#endif
 
 #endif
diff --git a/arch/arm/include/asm/statfs.h b/arch/arm/include/asm/statfs.h
index a02e6a8..079447c 100644
--- a/arch/arm/include/asm/statfs.h
+++ b/arch/arm/include/asm/statfs.h
@@ -1,42 +1,12 @@
 #ifndef _ASMARM_STATFS_H
 #define _ASMARM_STATFS_H
 
-#ifndef __KERNEL_STRICT_NAMES
-# include <linux/types.h>
-typedef __kernel_fsid_t	fsid_t;
-#endif
-
-struct statfs {
-	__u32 f_type;
-	__u32 f_bsize;
-	__u32 f_blocks;
-	__u32 f_bfree;
-	__u32 f_bavail;
-	__u32 f_files;
-	__u32 f_ffree;
-	__kernel_fsid_t f_fsid;
-	__u32 f_namelen;
-	__u32 f_frsize;
-	__u32 f_spare[5];
-};
-
 /*
  * With EABI there is 4 bytes of padding added to this structure.
  * Let's pack it so the padding goes away to simplify dual ABI support.
  * Note that user space does NOT have to pack this structure.
  */
-struct statfs64 {
-	__u32 f_type;
-	__u32 f_bsize;
-	__u64 f_blocks;
-	__u64 f_bfree;
-	__u64 f_bavail;
-	__u64 f_files;
-	__u64 f_ffree;
-	__kernel_fsid_t f_fsid;
-	__u32 f_namelen;
-	__u32 f_frsize;
-	__u32 f_spare[5];
-} __attribute__ ((packed,aligned(4)));
+#define ARCH_PACK_STATFS64 __attribute__((packed,aligned(4)))
 
+#include <asm-generic/statfs.h>
 #endif
diff --git a/arch/arm/include/asm/system.h b/arch/arm/include/asm/system.h
index 514af79..7aad784 100644
--- a/arch/arm/include/asm/system.h
+++ b/arch/arm/include/asm/system.h
@@ -43,11 +43,6 @@
 #define CR_XP	(1 << 23)	/* Extended page tables			*/
 #define CR_VE	(1 << 24)	/* Vectored interrupts			*/
 
-#define CPUID_ID	0
-#define CPUID_CACHETYPE	1
-#define CPUID_TCM	2
-#define CPUID_TLBTYPE	3
-
 /*
  * This is used to ensure the compiler did actually allocate the register we
  * asked it for some inline assembly sequences.  Apparently we can't trust
@@ -61,36 +56,8 @@
 #ifndef __ASSEMBLY__
 
 #include <linux/linkage.h>
-#include <linux/stringify.h>
 #include <linux/irqflags.h>
 
-#ifdef CONFIG_CPU_CP15
-#define read_cpuid(reg)							\
-	({								\
-		unsigned int __val;					\
-		asm("mrc	p15, 0, %0, c0, c0, " __stringify(reg)	\
-		    : "=r" (__val)					\
-		    :							\
-		    : "cc");						\
-		__val;							\
-	})
-#else
-extern unsigned int processor_id;
-#define read_cpuid(reg) (processor_id)
-#endif
-
-/*
- * The CPU ID never changes at run time, so we might as well tell the
- * compiler that it's constant.  Use this function to read the CPU ID
- * rather than directly reading processor_id or read_cpuid() directly.
- */
-static inline unsigned int read_cpuid_id(void) __attribute_const__;
-
-static inline unsigned int read_cpuid_id(void)
-{
-	return read_cpuid(CPUID_ID);
-}
-
 #define __exception	__attribute__((section(".exception.text")))
 
 struct thread_info;
@@ -131,31 +98,6 @@
 void arm_machine_restart(char mode);
 extern void (*arm_pm_restart)(char str);
 
-/*
- * Intel's XScale3 core supports some v6 features (supersections, L2)
- * but advertises itself as v5 as it does not support the v6 ISA.  For
- * this reason, we need a way to explicitly test for this type of CPU.
- */
-#ifndef CONFIG_CPU_XSC3
-#define cpu_is_xsc3()	0
-#else
-static inline int cpu_is_xsc3(void)
-{
-	extern unsigned int processor_id;
-
-	if ((processor_id & 0xffffe000) == 0x69056000)
-		return 1;
-
-	return 0;
-}
-#endif
-
-#if !defined(CONFIG_CPU_XSCALE) && !defined(CONFIG_CPU_XSC3)
-#define	cpu_is_xscale()	0
-#else
-#define	cpu_is_xscale()	1
-#endif
-
 #define UDBG_UNDEFINED	(1 << 0)
 #define UDBG_SYSCALL	(1 << 1)
 #define UDBG_BADABORT	(1 << 2)
diff --git a/arch/arm/include/asm/thread_info.h b/arch/arm/include/asm/thread_info.h
index e56fa48..68b9ec8 100644
--- a/arch/arm/include/asm/thread_info.h
+++ b/arch/arm/include/asm/thread_info.h
@@ -98,7 +98,7 @@
 }
 
 #define thread_saved_pc(tsk)	\
-	((unsigned long)(pc_pointer(task_thread_info(tsk)->cpu_context.pc)))
+	((unsigned long)(task_thread_info(tsk)->cpu_context.pc))
 #define thread_saved_fp(tsk)	\
 	((unsigned long)(task_thread_info(tsk)->cpu_context.fp))
 
diff --git a/arch/arm/include/asm/uaccess.h b/arch/arm/include/asm/uaccess.h
index d0f51ff..e98ec60 100644
--- a/arch/arm/include/asm/uaccess.h
+++ b/arch/arm/include/asm/uaccess.h
@@ -225,7 +225,7 @@
 
 #define __get_user_asm_byte(x,addr,err)				\
 	__asm__ __volatile__(					\
-	"1:	ldrbt	%1,[%2],#0\n"				\
+	"1:	ldrbt	%1,[%2]\n"				\
 	"2:\n"							\
 	"	.section .fixup,\"ax\"\n"			\
 	"	.align	2\n"					\
@@ -261,7 +261,7 @@
 
 #define __get_user_asm_word(x,addr,err)				\
 	__asm__ __volatile__(					\
-	"1:	ldrt	%1,[%2],#0\n"				\
+	"1:	ldrt	%1,[%2]\n"				\
 	"2:\n"							\
 	"	.section .fixup,\"ax\"\n"			\
 	"	.align	2\n"					\
@@ -306,7 +306,7 @@
 
 #define __put_user_asm_byte(x,__pu_addr,err)			\
 	__asm__ __volatile__(					\
-	"1:	strbt	%1,[%2],#0\n"				\
+	"1:	strbt	%1,[%2]\n"				\
 	"2:\n"							\
 	"	.section .fixup,\"ax\"\n"			\
 	"	.align	2\n"					\
@@ -339,7 +339,7 @@
 
 #define __put_user_asm_word(x,__pu_addr,err)			\
 	__asm__ __volatile__(					\
-	"1:	strt	%1,[%2],#0\n"				\
+	"1:	strt	%1,[%2]\n"				\
 	"2:\n"							\
 	"	.section .fixup,\"ax\"\n"			\
 	"	.align	2\n"					\
@@ -365,7 +365,7 @@
 #define __put_user_asm_dword(x,__pu_addr,err)			\
 	__asm__ __volatile__(					\
 	"1:	strt	" __reg_oper1 ", [%1], #4\n"		\
-	"2:	strt	" __reg_oper0 ", [%1], #0\n"		\
+	"2:	strt	" __reg_oper0 ", [%1]\n"		\
 	"3:\n"							\
 	"	.section .fixup,\"ax\"\n"			\
 	"	.align	2\n"					\
diff --git a/arch/arm/include/asm/vga.h b/arch/arm/include/asm/vga.h
index 6a3cd2a2..250a4dd 100644
--- a/arch/arm/include/asm/vga.h
+++ b/arch/arm/include/asm/vga.h
@@ -1,8 +1,8 @@
 #ifndef ASMARM_VGA_H
 #define ASMARM_VGA_H
 
+#include <linux/io.h>
 #include <mach/hardware.h>
-#include <asm/io.h>
 
 #define VGA_MAP_MEM(x,s)	(PCIMEM_BASE + (x))
 
diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile
index 1d296fc..4305345 100644
--- a/arch/arm/kernel/Makefile
+++ b/arch/arm/kernel/Makefile
@@ -10,7 +10,7 @@
 
 # Object file lists.
 
-obj-y		:= compat.o entry-armv.o entry-common.o irq.o \
+obj-y		:= compat.o elf.o entry-armv.o entry-common.o irq.o \
 		   process.o ptrace.o setup.o signal.o \
 		   sys_arm.o stacktrace.o time.o traps.o
 
diff --git a/arch/arm/kernel/armksyms.c b/arch/arm/kernel/armksyms.c
index cc7b246..2357b1c 100644
--- a/arch/arm/kernel/armksyms.c
+++ b/arch/arm/kernel/armksyms.c
@@ -13,11 +13,11 @@
 #include <linux/delay.h>
 #include <linux/in6.h>
 #include <linux/syscalls.h>
+#include <linux/uaccess.h>
+#include <linux/io.h>
 
 #include <asm/checksum.h>
-#include <asm/io.h>
 #include <asm/system.h>
-#include <asm/uaccess.h>
 #include <asm/ftrace.h>
 
 /*
diff --git a/arch/arm/kernel/bios32.c b/arch/arm/kernel/bios32.c
index e574754..17a59b6 100644
--- a/arch/arm/kernel/bios32.c
+++ b/arch/arm/kernel/bios32.c
@@ -10,8 +10,8 @@
 #include <linux/pci.h>
 #include <linux/slab.h>
 #include <linux/init.h>
+#include <linux/io.h>
 
-#include <asm/io.h>
 #include <asm/mach-types.h>
 #include <asm/mach/pci.h>
 
diff --git a/arch/arm/kernel/crunch.c b/arch/arm/kernel/crunch.c
index 3b6a1c2..99995c2 100644
--- a/arch/arm/kernel/crunch.c
+++ b/arch/arm/kernel/crunch.c
@@ -15,9 +15,9 @@
 #include <linux/signal.h>
 #include <linux/sched.h>
 #include <linux/init.h>
+#include <linux/io.h>
 #include <mach/ep93xx-regs.h>
 #include <asm/thread_notify.h>
-#include <asm/io.h>
 
 struct crunch_state *crunch_owner;
 
diff --git a/arch/arm/kernel/debug.S b/arch/arm/kernel/debug.S
index 9550ff0..f53c582 100644
--- a/arch/arm/kernel/debug.S
+++ b/arch/arm/kernel/debug.S
@@ -89,10 +89,12 @@
 ENTRY(printhex8)
 		mov	r1, #8
 		b	printhex
+ENDPROC(printhex8)
 
 ENTRY(printhex4)
 		mov	r1, #4
 		b	printhex
+ENDPROC(printhex4)
 
 ENTRY(printhex2)
 		mov	r1, #2
@@ -110,6 +112,7 @@
 		bne	1b
 		mov	r0, r2
 		b	printascii
+ENDPROC(printhex2)
 
 		.ltorg
 
@@ -127,11 +130,13 @@
 		teqne	r1, #0
 		bne	1b
 		mov	pc, lr
+ENDPROC(printascii)
 
 ENTRY(printch)
 		addruart r3
 		mov	r1, r0
 		mov	r0, #0
 		b	1b
+ENDPROC(printch)
 
 hexbuf:		.space 16
diff --git a/arch/arm/kernel/dma-isa.c b/arch/arm/kernel/dma-isa.c
index 2f080a3..4a3a504 100644
--- a/arch/arm/kernel/dma-isa.c
+++ b/arch/arm/kernel/dma-isa.c
@@ -19,10 +19,9 @@
 #include <linux/ioport.h>
 #include <linux/init.h>
 #include <linux/dma-mapping.h>
+#include <linux/io.h>
 
 #include <asm/dma.h>
-#include <asm/io.h>
-
 #include <asm/mach/dma.h>
 
 #define ISA_DMA_MODE_READ	0x44
diff --git a/arch/arm/kernel/dma.c b/arch/arm/kernel/dma.c
index ba99a20..d006085 100644
--- a/arch/arm/kernel/dma.c
+++ b/arch/arm/kernel/dma.c
@@ -26,23 +26,6 @@
 static dma_t dma_chan[MAX_DMA_CHANNELS];
 
 /*
- * Get dma list for /proc/dma
- */
-int get_dma_list(char *buf)
-{
-	dma_t *dma;
-	char *p = buf;
-	int i;
-
-	for (i = 0, dma = dma_chan; i < MAX_DMA_CHANNELS; i++, dma++)
-		if (dma->lock)
-			p += sprintf(p, "%2d: %14s %s\n", i,
-				     dma->d_ops->type, dma->device_id);
-
-	return p - buf;
-}
-
-/*
  * Request DMA channel
  *
  * On certain platforms, we have to allocate an interrupt as well...
diff --git a/arch/arm/kernel/ecard.c b/arch/arm/kernel/ecard.c
index 7a50575..60c079d 100644
--- a/arch/arm/kernel/ecard.c
+++ b/arch/arm/kernel/ecard.c
@@ -587,8 +587,7 @@
 			pending = ecard_default_ops.irqpending(ec);
 
 		if (pending) {
-			struct irq_desc *d = irq_desc + ec->irq;
-			desc_handle_irq(ec->irq, d);
+			generic_handle_irq(ec->irq);
 			called ++;
 		}
 	}
@@ -622,7 +621,6 @@
 		ecard_t *ec = slot_to_ecard(slot);
 
 		if (ec->claimed) {
-			struct irq_desc *d = irq_desc + ec->irq;
 			/*
 			 * this ugly code is so that we can operate a
 			 * prioritorising system:
@@ -635,7 +633,7 @@
 			 * Serial cards should go in 0/1, ethernet/scsi in 2/3
 			 * otherwise you will lose serial data at high speeds!
 			 */
-			desc_handle_irq(ec->irq, d);
+			generic_handle_irq(ec->irq);
 		} else {
 			printk(KERN_WARNING "card%d: interrupt from unclaimed "
 			       "card???\n", slot);
diff --git a/arch/arm/kernel/elf.c b/arch/arm/kernel/elf.c
new file mode 100644
index 0000000..513f332
--- /dev/null
+++ b/arch/arm/kernel/elf.c
@@ -0,0 +1,79 @@
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/personality.h>
+#include <linux/binfmts.h>
+#include <linux/elf.h>
+
+int elf_check_arch(const struct elf32_hdr *x)
+{
+	unsigned int eflags;
+
+	/* Make sure it's an ARM executable */
+	if (x->e_machine != EM_ARM)
+		return 0;
+
+	/* Make sure the entry address is reasonable */
+	if (x->e_entry & 1) {
+		if (!(elf_hwcap & HWCAP_THUMB))
+			return 0;
+	} else if (x->e_entry & 3)
+		return 0;
+
+	eflags = x->e_flags;
+	if ((eflags & EF_ARM_EABI_MASK) == EF_ARM_EABI_UNKNOWN) {
+		/* APCS26 is only allowed if the CPU supports it */
+		if ((eflags & EF_ARM_APCS_26) && !(elf_hwcap & HWCAP_26BIT))
+			return 0;
+
+		/* VFP requires the supporting code */
+		if ((eflags & EF_ARM_VFP_FLOAT) && !(elf_hwcap & HWCAP_VFP))
+			return 0;
+	}
+	return 1;
+}
+EXPORT_SYMBOL(elf_check_arch);
+
+void elf_set_personality(const struct elf32_hdr *x)
+{
+	unsigned int eflags = x->e_flags;
+	unsigned int personality = PER_LINUX_32BIT;
+
+	/*
+	 * APCS-26 is only valid for OABI executables
+	 */
+	if ((eflags & EF_ARM_EABI_MASK) == EF_ARM_EABI_UNKNOWN) {
+		if (eflags & EF_ARM_APCS_26)
+			personality = PER_LINUX;
+	}
+
+	set_personality(personality);
+
+	/*
+	 * Since the FPA coprocessor uses CP1 and CP2, and iWMMXt uses CP0
+	 * and CP1, we only enable access to the iWMMXt coprocessor if the
+	 * binary is EABI or softfloat (and thus, guaranteed not to use
+	 * FPA instructions.)
+	 */
+	if (elf_hwcap & HWCAP_IWMMXT &&
+	    eflags & (EF_ARM_EABI_MASK | EF_ARM_SOFT_FLOAT)) {
+		set_thread_flag(TIF_USING_IWMMXT);
+	} else {
+		clear_thread_flag(TIF_USING_IWMMXT);
+	}
+}
+EXPORT_SYMBOL(elf_set_personality);
+
+/*
+ * Set READ_IMPLIES_EXEC if:
+ *  - the binary requires an executable stack
+ *  - we're running on a CPU which doesn't support NX.
+ */
+int arm_elf_read_implies_exec(const struct elf32_hdr *x, int executable_stack)
+{
+	if (executable_stack != EXSTACK_ENABLE_X)
+		return 1;
+	if (cpu_architecture() <= CPU_ARCH_ARMv6)
+		return 1;
+	return 0;
+}
+EXPORT_SYMBOL(arm_elf_read_implies_exec);
diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S
index 617e509..77b0474 100644
--- a/arch/arm/kernel/entry-armv.S
+++ b/arch/arm/kernel/entry-armv.S
@@ -76,14 +76,17 @@
 __pabt_invalid:
 	inv_entry BAD_PREFETCH
 	b	common_invalid
+ENDPROC(__pabt_invalid)
 
 __dabt_invalid:
 	inv_entry BAD_DATA
 	b	common_invalid
+ENDPROC(__dabt_invalid)
 
 __irq_invalid:
 	inv_entry BAD_IRQ
 	b	common_invalid
+ENDPROC(__irq_invalid)
 
 __und_invalid:
 	inv_entry BAD_UNDEFINSTR
@@ -107,6 +110,7 @@
 
 	mov	r0, sp
 	b	bad_mode
+ENDPROC(__und_invalid)
 
 /*
  * SVC mode handlers
@@ -192,6 +196,7 @@
 	ldr	r0, [sp, #S_PSR]
 	msr	spsr_cxsf, r0
 	ldmia	sp, {r0 - pc}^			@ load r0 - pc, cpsr
+ENDPROC(__dabt_svc)
 
 	.align	5
 __irq_svc:
@@ -223,6 +228,7 @@
 	bleq	trace_hardirqs_on
 #endif
 	ldmia	sp, {r0 - pc}^			@ load r0 - pc, cpsr
+ENDPROC(__irq_svc)
 
 	.ltorg
 
@@ -272,6 +278,7 @@
 	ldr	lr, [sp, #S_PSR]		@ Get SVC cpsr
 	msr	spsr_cxsf, lr
 	ldmia	sp, {r0 - pc}^			@ Restore SVC registers
+ENDPROC(__und_svc)
 
 	.align	5
 __pabt_svc:
@@ -313,6 +320,7 @@
 	ldr	r0, [sp, #S_PSR]
 	msr	spsr_cxsf, r0
 	ldmia	sp, {r0 - pc}^			@ load r0 - pc, cpsr
+ENDPROC(__pabt_svc)
 
 	.align	5
 .LCcralign:
@@ -412,6 +420,7 @@
 	mov	r2, sp
 	adr	lr, ret_from_exception
 	b	do_DataAbort
+ENDPROC(__dabt_usr)
 
 	.align	5
 __irq_usr:
@@ -441,6 +450,7 @@
 
 	mov	why, #0
 	b	ret_to_user
+ENDPROC(__irq_usr)
 
 	.ltorg
 
@@ -474,6 +484,7 @@
 #else
 	b	__und_usr_unknown
 #endif
+ENDPROC(__und_usr)
 
 	@
 	@ fallthrough to call_fpe
@@ -642,6 +653,7 @@
 	mov	r0, sp
 	adr	lr, ret_from_exception
 	b	do_undefinstr
+ENDPROC(__und_usr_unknown)
 
 	.align	5
 __pabt_usr:
@@ -666,6 +678,8 @@
 	get_thread_info tsk
 	mov	why, #0
 	b	ret_to_user
+ENDPROC(__pabt_usr)
+ENDPROC(ret_from_exception)
 
 /*
  * Register switch for ARMv3 and ARMv4 processors
@@ -702,6 +716,7 @@
 	bl	atomic_notifier_call_chain
 	mov	r0, r5
 	ldmia	r4, {r4 - sl, fp, sp, pc}	@ Load all regs saved previously
+ENDPROC(__switch_to)
 
 	__INIT
 
@@ -1029,6 +1044,7 @@
 	mov	r0, sp
 	ldr	lr, [pc, lr, lsl #2]
 	movs	pc, lr			@ branch to handler in SVC mode
+ENDPROC(vector_\name)
 	.endm
 
 	.globl	__stubs_start
diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S
index 060d7e2..3aa14dc 100644
--- a/arch/arm/kernel/entry-common.S
+++ b/arch/arm/kernel/entry-common.S
@@ -77,6 +77,7 @@
 	mov	r0, r0
 	add	sp, sp, #S_FRAME_SIZE - S_PC
 	movs	pc, lr				@ return & move spsr_svc into cpsr
+ENDPROC(ret_to_user)
 
 /*
  * This is how we return from a fork.
@@ -92,7 +93,7 @@
 	mov	r0, #1				@ trace exit [IP = 1]
 	bl	syscall_trace
 	b	ret_slow_syscall
-	
+ENDPROC(ret_from_fork)
 
 	.equ NR_syscalls,0
 #define CALL(x) .equ NR_syscalls,NR_syscalls+1
@@ -269,6 +270,7 @@
 	eor	r0, scno, #__NR_SYSCALL_BASE	@ put OS number back
 	bcs	arm_syscall	
 	b	sys_ni_syscall			@ not private func
+ENDPROC(vector_swi)
 
 	/*
 	 * This is the really slow path.  We're going to be doing
@@ -326,7 +328,6 @@
  */
 @ r0 = syscall number
 @ r8 = syscall table
-		.type	sys_syscall, #function
 sys_syscall:
 		bic	scno, r0, #__NR_OABI_SYSCALL_BASE
 		cmp	scno, #__NR_syscall - __NR_SYSCALL_BASE
@@ -338,53 +339,65 @@
 		movlo	r3, r4
 		ldrlo	pc, [tbl, scno, lsl #2]
 		b	sys_ni_syscall
+ENDPROC(sys_syscall)
 
 sys_fork_wrapper:
 		add	r0, sp, #S_OFF
 		b	sys_fork
+ENDPROC(sys_fork_wrapper)
 
 sys_vfork_wrapper:
 		add	r0, sp, #S_OFF
 		b	sys_vfork
+ENDPROC(sys_vfork_wrapper)
 
 sys_execve_wrapper:
 		add	r3, sp, #S_OFF
 		b	sys_execve
+ENDPROC(sys_execve_wrapper)
 
 sys_clone_wrapper:
 		add	ip, sp, #S_OFF
 		str	ip, [sp, #4]
 		b	sys_clone
+ENDPROC(sys_clone_wrapper)
 
 sys_sigsuspend_wrapper:
 		add	r3, sp, #S_OFF
 		b	sys_sigsuspend
+ENDPROC(sys_sigsuspend_wrapper)
 
 sys_rt_sigsuspend_wrapper:
 		add	r2, sp, #S_OFF
 		b	sys_rt_sigsuspend
+ENDPROC(sys_rt_sigsuspend_wrapper)
 
 sys_sigreturn_wrapper:
 		add	r0, sp, #S_OFF
 		b	sys_sigreturn
+ENDPROC(sys_sigreturn_wrapper)
 
 sys_rt_sigreturn_wrapper:
 		add	r0, sp, #S_OFF
 		b	sys_rt_sigreturn
+ENDPROC(sys_rt_sigreturn_wrapper)
 
 sys_sigaltstack_wrapper:
 		ldr	r2, [sp, #S_OFF + S_SP]
 		b	do_sigaltstack
+ENDPROC(sys_sigaltstack_wrapper)
 
 sys_statfs64_wrapper:
 		teq	r1, #88
 		moveq	r1, #84
 		b	sys_statfs64
+ENDPROC(sys_statfs64_wrapper)
 
 sys_fstatfs64_wrapper:
 		teq	r1, #88
 		moveq	r1, #84
 		b	sys_fstatfs64
+ENDPROC(sys_fstatfs64_wrapper)
 
 /*
  * Note: off_4k (r5) is always units of 4K.  If we can't do the requested
@@ -402,11 +415,14 @@
 		str	r5, [sp, #4]
 		b	do_mmap2
 #endif
+ENDPROC(sys_mmap2)
 
 ENTRY(pabort_ifar)
 		mrc	p15, 0, r0, cr6, cr0, 2
 ENTRY(pabort_noifar)
 		mov	pc, lr
+ENDPROC(pabort_ifar)
+ENDPROC(pabort_noifar)
 
 #ifdef CONFIG_OABI_COMPAT
 
@@ -417,26 +433,31 @@
 sys_oabi_pread64:
 		stmia	sp, {r3, r4}
 		b	sys_pread64
+ENDPROC(sys_oabi_pread64)
 
 sys_oabi_pwrite64:
 		stmia	sp, {r3, r4}
 		b	sys_pwrite64
+ENDPROC(sys_oabi_pwrite64)
 
 sys_oabi_truncate64:
 		mov	r3, r2
 		mov	r2, r1
 		b	sys_truncate64
+ENDPROC(sys_oabi_truncate64)
 
 sys_oabi_ftruncate64:
 		mov	r3, r2
 		mov	r2, r1
 		b	sys_ftruncate64
+ENDPROC(sys_oabi_ftruncate64)
 
 sys_oabi_readahead:
 		str	r3, [sp]
 		mov	r3, r2
 		mov	r2, r1
 		b	sys_readahead
+ENDPROC(sys_oabi_readahead)
 
 /*
  * Let's declare a second syscall table for old ABI binaries
diff --git a/arch/arm/kernel/fiq.c b/arch/arm/kernel/fiq.c
index e8e9034..36f81d9 100644
--- a/arch/arm/kernel/fiq.c
+++ b/arch/arm/kernel/fiq.c
@@ -45,7 +45,6 @@
 #include <asm/fiq.h>
 #include <asm/irq.h>
 #include <asm/system.h>
-#include <asm/uaccess.h>
 
 static unsigned long no_fiq_insn;
 
diff --git a/arch/arm/kernel/head-common.S b/arch/arm/kernel/head-common.S
index 1c3c6ea..bde52df 100644
--- a/arch/arm/kernel/head-common.S
+++ b/arch/arm/kernel/head-common.S
@@ -36,7 +36,6 @@
  *  r2  = atags pointer
  *  r9  = processor ID
  */
-	.type	__mmap_switched, %function
 __mmap_switched:
 	adr	r3, __switch_data + 4
 
@@ -59,6 +58,7 @@
 	bic	r4, r0, #CR_A			@ Clear 'A' bit
 	stmia	r7, {r0, r4}			@ Save control register values
 	b	start_kernel
+ENDPROC(__mmap_switched)
 
 /*
  * Exception handling.  Something went wrong and we can't proceed.  We
@@ -69,8 +69,6 @@
  * and hope for the best (useful if bootloader fails to pass a proper
  * machine ID for example).
  */
-
-	.type	__error_p, %function
 __error_p:
 #ifdef CONFIG_DEBUG_LL
 	adr	r0, str_p1
@@ -84,8 +82,8 @@
 str_p2:	.asciz	").\n"
 	.align
 #endif
+ENDPROC(__error_p)
 
-	.type	__error_a, %function
 __error_a:
 #ifdef CONFIG_DEBUG_LL
 	mov	r4, r1				@ preserve machine ID
@@ -115,13 +113,14 @@
 	adr	r0, str_a3
 	bl	printascii
 	b	__error
+ENDPROC(__error_a)
+
 str_a1:	.asciz	"\nError: unrecognized/unsupported machine ID (r1 = 0x"
 str_a2:	.asciz	").\n\nAvailable machine support:\n\nID (hex)\tNAME\n"
 str_a3:	.asciz	"\nPlease check your kernel config and/or bootloader.\n"
 	.align
 #endif
 
-	.type	__error, %function
 __error:
 #ifdef CONFIG_ARCH_RPC
 /*
@@ -138,6 +137,7 @@
 #endif
 1:	mov	r0, r0
 	b	1b
+ENDPROC(__error)
 
 
 /*
@@ -153,7 +153,6 @@
  *	r5 = proc_info pointer in physical address space
  *	r9 = cpuid (preserved)
  */
-	.type	__lookup_processor_type, %function
 __lookup_processor_type:
 	adr	r3, 3f
 	ldmda	r3, {r5 - r7}
@@ -169,6 +168,7 @@
 	blo	1b
 	mov	r5, #0				@ unknown processor
 2:	mov	pc, lr
+ENDPROC(__lookup_processor_type)
 
 /*
  * This provides a C-API version of the above function.
@@ -179,6 +179,7 @@
 	bl	__lookup_processor_type
 	mov	r0, r5
 	ldmfd	sp!, {r4 - r7, r9, pc}
+ENDPROC(lookup_processor_type)
 
 /*
  * Look in <asm/procinfo.h> and arch/arm/kernel/arch.[ch] for
@@ -201,7 +202,6 @@
  *  r3, r4, r6 corrupted
  *  r5 = mach_info pointer in physical address space
  */
-	.type	__lookup_machine_type, %function
 __lookup_machine_type:
 	adr	r3, 3b
 	ldmia	r3, {r4, r5, r6}
@@ -216,6 +216,7 @@
 	blo	1b
 	mov	r5, #0				@ unknown machine
 2:	mov	pc, lr
+ENDPROC(__lookup_machine_type)
 
 /*
  * This provides a C-API version of the above function.
@@ -226,6 +227,7 @@
 	bl	__lookup_machine_type
 	mov	r0, r5
 	ldmfd	sp!, {r4 - r6, pc}
+ENDPROC(lookup_machine_type)
 
 /* Determine validity of the r2 atags pointer.  The heuristic requires
  * that the pointer be aligned, in the first 16k of physical RAM and
@@ -239,8 +241,6 @@
  *  r2 either valid atags pointer, or zero
  *  r5, r6 corrupted
  */
-
-	.type	__vet_atags, %function
 __vet_atags:
 	tst	r2, #0x3			@ aligned?
 	bne	1f
@@ -257,3 +257,4 @@
 
 1:	mov	r2, #0
 	mov	pc, lr
+ENDPROC(__vet_atags)
diff --git a/arch/arm/kernel/head-nommu.S b/arch/arm/kernel/head-nommu.S
index 27329bd..cc87e17 100644
--- a/arch/arm/kernel/head-nommu.S
+++ b/arch/arm/kernel/head-nommu.S
@@ -33,7 +33,6 @@
  *
  */
 	.section ".text.head", "ax"
-	.type	stext, %function
 ENTRY(stext)
 	msr	cpsr_c, #PSR_F_BIT | PSR_I_BIT | SVC_MODE @ ensure svc mode
 						@ and irqs disabled
@@ -53,11 +52,11 @@
 						@ the initialization is done
 	adr	lr, __after_proc_init		@ return (PIC) address
 	add	pc, r10, #PROCINFO_INITFUNC
+ENDPROC(stext)
 
 /*
  * Set the Control Register and Read the process ID.
  */
-	.type	__after_proc_init, %function
 __after_proc_init:
 #ifdef CONFIG_CPU_CP15
 	mrc	p15, 0, r0, c1, c0, 0		@ read control reg
@@ -85,6 +84,7 @@
 
 	mov	pc, r13				@ clear the BSS and jump
 						@ to start_kernel
+ENDPROC(__after_proc_init)
 	.ltorg
 
 #include "head-common.S"
diff --git a/arch/arm/kernel/head.S b/arch/arm/kernel/head.S
index bff4c6e..21e17dc 100644
--- a/arch/arm/kernel/head.S
+++ b/arch/arm/kernel/head.S
@@ -75,7 +75,6 @@
  * circumstances, zImage) is for.
  */
 	.section ".text.head", "ax"
-	.type	stext, %function
 ENTRY(stext)
 	msr	cpsr_c, #PSR_F_BIT | PSR_I_BIT | SVC_MODE @ ensure svc mode
 						@ and irqs disabled
@@ -100,9 +99,9 @@
 						@ mmu has been enabled
 	adr	lr, __enable_mmu		@ return (PIC) address
 	add	pc, r10, #PROCINFO_INITFUNC
+ENDPROC(stext)
 
 #if defined(CONFIG_SMP)
-	.type   secondary_startup, #function
 ENTRY(secondary_startup)
 	/*
 	 * Common entry point for secondary CPUs.
@@ -128,6 +127,7 @@
 	adr	lr, __enable_mmu		@ return address
 	add	pc, r10, #PROCINFO_INITFUNC	@ initialise processor
 						@ (return control reg)
+ENDPROC(secondary_startup)
 
 	/*
 	 * r6  = &secondary_data
@@ -136,6 +136,7 @@
 	ldr	sp, [r7, #4]			@ get secondary_data.stack
 	mov	fp, #0
 	b	secondary_start_kernel
+ENDPROC(__secondary_switched)
 
 	.type	__secondary_data, %object
 __secondary_data:
@@ -151,7 +152,6 @@
  * this is just loading the page table pointer and domain access
  * registers.
  */
-	.type	__enable_mmu, %function
 __enable_mmu:
 #ifdef CONFIG_ALIGNMENT_TRAP
 	orr	r0, r0, #CR_A
@@ -174,6 +174,7 @@
 	mcr	p15, 0, r5, c3, c0, 0		@ load domain access register
 	mcr	p15, 0, r4, c2, c0, 0		@ load page table pointer
 	b	__turn_mmu_on
+ENDPROC(__enable_mmu)
 
 /*
  * Enable the MMU.  This completely changes the structure of the visible
@@ -187,7 +188,6 @@
  * other registers depend on the function called upon completion
  */
 	.align	5
-	.type	__turn_mmu_on, %function
 __turn_mmu_on:
 	mov	r0, r0
 	mcr	p15, 0, r0, c1, c0, 0		@ write control reg
@@ -195,7 +195,7 @@
 	mov	r3, r3
 	mov	r3, r3
 	mov	pc, r13
-
+ENDPROC(__turn_mmu_on)
 
 
 /*
@@ -211,7 +211,6 @@
  *  r0, r3, r6, r7 corrupted
  *  r4 = physical page table address
  */
-	.type	__create_page_tables, %function
 __create_page_tables:
 	pgtbl	r4				@ page table address
 
@@ -325,6 +324,7 @@
 #endif
 #endif
 	mov	pc, lr
+ENDPROC(__create_page_tables)
 	.ltorg
 
 #include "head-common.S"
diff --git a/arch/arm/kernel/init_task.c b/arch/arm/kernel/init_task.c
index 8b8c9d3..0bbf806 100644
--- a/arch/arm/kernel/init_task.c
+++ b/arch/arm/kernel/init_task.c
@@ -8,8 +8,8 @@
 #include <linux/init.h>
 #include <linux/init_task.h>
 #include <linux/mqueue.h>
+#include <linux/uaccess.h>
 
-#include <asm/uaccess.h>
 #include <asm/pgtable.h>
 
 static struct fs_struct init_fs = INIT_FS;
diff --git a/arch/arm/kernel/io.c b/arch/arm/kernel/io.c
index 1f6822d..f447030 100644
--- a/arch/arm/kernel/io.c
+++ b/arch/arm/kernel/io.c
@@ -1,7 +1,6 @@
 #include <linux/module.h>
 #include <linux/types.h>
-
-#include <asm/io.h>
+#include <linux/io.h>
 
 /*
  * Copy data from IO memory space to "real" memory space.
diff --git a/arch/arm/kernel/irq.c b/arch/arm/kernel/irq.c
index f88efb1..2f3eb79 100644
--- a/arch/arm/kernel/irq.c
+++ b/arch/arm/kernel/irq.c
@@ -112,18 +112,17 @@
 asmlinkage void __exception asm_do_IRQ(unsigned int irq, struct pt_regs *regs)
 {
 	struct pt_regs *old_regs = set_irq_regs(regs);
-	struct irq_desc *desc = irq_desc + irq;
+
+	irq_enter();
 
 	/*
 	 * Some hardware gives randomly wrong interrupts.  Rather
 	 * than crashing, do something sensible.
 	 */
 	if (irq >= NR_IRQS)
-		desc = &bad_irq_desc;
-
-	irq_enter();
-
-	desc_handle_irq(irq, desc);
+		handle_bad_irq(irq, &bad_irq_desc);
+	else
+		generic_handle_irq(irq);
 
 	/* AT91 specific workaround */
 	irq_finish(irq);
diff --git a/arch/arm/kernel/kgdb.c b/arch/arm/kernel/kgdb.c
index aaffaec..ba8ccfe 100644
--- a/arch/arm/kernel/kgdb.c
+++ b/arch/arm/kernel/kgdb.c
@@ -111,8 +111,6 @@
 	case 'D':
 	case 'k':
 	case 'c':
-		kgdb_contthread = NULL;
-
 		/*
 		 * Try to read optional parameter, pc unchanged if no parm.
 		 * If this was a compiled breakpoint, we need to move
diff --git a/arch/arm/kernel/kprobes-decode.c b/arch/arm/kernel/kprobes-decode.c
index b4565bb..da1f949 100644
--- a/arch/arm/kernel/kprobes-decode.c
+++ b/arch/arm/kernel/kprobes-decode.c
@@ -488,7 +488,7 @@
 
 	if (!ubit)
 		addr -= reg_count;
-	addr += (!pbit ^ !ubit);
+	addr += (!pbit == !ubit);
 
 	reg_bit_vector = insn & 0xffff;
 	while (reg_bit_vector) {
@@ -503,7 +503,7 @@
 	if (wbit) {
 		if (!ubit)
 			addr -= reg_count;
-		addr -= (!pbit ^ !ubit);
+		addr -= (!pbit == !ubit);
 		regs->uregs[rn] = (long)addr;
 	}
 }
diff --git a/arch/arm/kernel/kprobes.c b/arch/arm/kernel/kprobes.c
index d28513f1..3f9abe0 100644
--- a/arch/arm/kernel/kprobes.c
+++ b/arch/arm/kernel/kprobes.c
@@ -200,9 +200,12 @@
 	}
 }
 
-int kprobe_trap_handler(struct pt_regs *regs, unsigned int instr)
+static int __kprobes kprobe_trap_handler(struct pt_regs *regs, unsigned int instr)
 {
+	unsigned long flags;
+	local_irq_save(flags);
 	kprobe_handler(regs);
+	local_irq_restore(flags);
 	return 0;
 }
 
diff --git a/arch/arm/kernel/machine_kexec.c b/arch/arm/kernel/machine_kexec.c
index fae5beb..440dc62 100644
--- a/arch/arm/kernel/machine_kexec.c
+++ b/arch/arm/kernel/machine_kexec.c
@@ -6,10 +6,10 @@
 #include <linux/kexec.h>
 #include <linux/delay.h>
 #include <linux/reboot.h>
+#include <linux/io.h>
 #include <asm/pgtable.h>
 #include <asm/pgalloc.h>
 #include <asm/mmu_context.h>
-#include <asm/io.h>
 #include <asm/cacheflush.h>
 #include <asm/mach-types.h>
 
diff --git a/arch/arm/kernel/module.c b/arch/arm/kernel/module.c
index a68259a..9203ba7 100644
--- a/arch/arm/kernel/module.c
+++ b/arch/arm/kernel/module.c
@@ -47,7 +47,7 @@
 	if (!area)
 		return NULL;
 
-	return __vmalloc_area(area, GFP_KERNEL, PAGE_KERNEL);
+	return __vmalloc_area(area, GFP_KERNEL, PAGE_KERNEL_EXEC);
 }
 #else /* CONFIG_MMU */
 void *module_alloc(unsigned long size)
diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c
index 3fd8823..d3ea6fa 100644
--- a/arch/arm/kernel/process.c
+++ b/arch/arm/kernel/process.c
@@ -28,12 +28,12 @@
 #include <linux/pm.h>
 #include <linux/tick.h>
 #include <linux/utsname.h>
+#include <linux/uaccess.h>
 
 #include <asm/leds.h>
 #include <asm/processor.h>
 #include <asm/system.h>
 #include <asm/thread_notify.h>
-#include <asm/uaccess.h>
 #include <asm/mach/time.h>
 
 static const char *processor_modes[] = {
@@ -267,35 +267,6 @@
 	__backtrace();
 }
 
-void show_fpregs(struct user_fp *regs)
-{
-	int i;
-
-	for (i = 0; i < 8; i++) {
-		unsigned long *p;
-		char type;
-
-		p = (unsigned long *)(regs->fpregs + i);
-
-		switch (regs->ftype[i]) {
-			case 1: type = 'f'; break;
-			case 2: type = 'd'; break;
-			case 3: type = 'e'; break;
-			default: type = '?'; break;
-		}
-		if (regs->init_flag)
-			type = '?';
-
-		printk("  f%d(%c): %08lx %08lx %08lx%c",
-			i, type, p[0], p[1], p[2], i & 1 ? '\n' : ' ');
-	}
-			
-
-	printk("FPSR: %08lx FPCR: %08lx\n",
-		(unsigned long)regs->fpsr,
-		(unsigned long)regs->fpcr);
-}
-
 /*
  * Free current thread data structures etc..
  */
@@ -414,7 +385,7 @@
 	do {
 		if (fp < stack_start || fp > stack_end)
 			return 0;
-		lr = pc_pointer (((unsigned long *)fp)[-1]);
+		lr = ((unsigned long *)fp)[-1];
 		if (!in_sched_functions(lr))
 			return lr;
 		fp = *(unsigned long *) (fp - 12);
diff --git a/arch/arm/kernel/ptrace.c b/arch/arm/kernel/ptrace.c
index 4b05dc5..df653ea 100644
--- a/arch/arm/kernel/ptrace.c
+++ b/arch/arm/kernel/ptrace.c
@@ -18,8 +18,8 @@
 #include <linux/security.h>
 #include <linux/init.h>
 #include <linux/signal.h>
+#include <linux/uaccess.h>
 
-#include <asm/uaccess.h>
 #include <asm/pgtable.h>
 #include <asm/system.h>
 #include <asm/traps.h>
@@ -126,7 +126,7 @@
 
 	val = get_user_reg(child, reg);
 	if (reg == 15)
-		val = pc_pointer(val + 8);
+		val += 8;
 
 	return val;
 }
@@ -278,8 +278,7 @@
 				else
 					base -= aluop2;
 			}
-			if (read_u32(child, base, &alt) == 0)
-				alt = pc_pointer(alt);
+			read_u32(child, base, &alt);
 		}
 		break;
 
@@ -305,8 +304,7 @@
 
 			base = ptrace_getrn(child, insn);
 
-			if (read_u32(child, base + nr_regs, &alt) == 0)
-				alt = pc_pointer(alt);
+			read_u32(child, base + nr_regs, &alt);
 			break;
 		}
 		break;
diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c
index 2ca7038..1f1eecc 100644
--- a/arch/arm/kernel/setup.c
+++ b/arch/arm/kernel/setup.c
@@ -26,11 +26,13 @@
 #include <linux/fs.h>
 
 #include <asm/cpu.h>
+#include <asm/cputype.h>
 #include <asm/elf.h>
 #include <asm/procinfo.h>
 #include <asm/setup.h>
 #include <asm/mach-types.h>
 #include <asm/cacheflush.h>
+#include <asm/cachetype.h>
 #include <asm/tlbflush.h>
 
 #include <asm/mach/arch.h>
@@ -59,13 +61,14 @@
 
 extern void paging_init(struct meminfo *, struct machine_desc *desc);
 extern void reboot_setup(char *str);
-extern int root_mountflags;
-extern void _stext, _text, _etext, __data_start, _edata, _end;
+extern void _text, _etext, __data_start, _edata, _end;
 
 unsigned int processor_id;
 EXPORT_SYMBOL(processor_id);
 unsigned int __machine_arch_type;
 EXPORT_SYMBOL(__machine_arch_type);
+unsigned int cacheid;
+EXPORT_SYMBOL(cacheid);
 
 unsigned int __atags_pointer __initdata;
 
@@ -81,8 +84,6 @@
 unsigned int elf_hwcap;
 EXPORT_SYMBOL(elf_hwcap);
 
-unsigned long __initdata vmalloc_reserve = 128 << 20;
-
 
 #ifdef MULTI_CPU
 struct processor processor;
@@ -111,9 +112,6 @@
 char elf_platform[ELF_PLATFORM_SIZE];
 EXPORT_SYMBOL(elf_platform);
 
-unsigned long phys_initrd_start __initdata = 0;
-unsigned long phys_initrd_size __initdata = 0;
-
 static struct meminfo meminfo __initdata = { 0, };
 static const char *cpu_name;
 static const char *machine_name;
@@ -178,63 +176,6 @@
 #define lp1 io_res[1]
 #define lp2 io_res[2]
 
-static const char *cache_types[16] = {
-	"write-through",
-	"write-back",
-	"write-back",
-	"undefined 3",
-	"undefined 4",
-	"undefined 5",
-	"write-back",
-	"write-back",
-	"undefined 8",
-	"undefined 9",
-	"undefined 10",
-	"undefined 11",
-	"undefined 12",
-	"undefined 13",
-	"write-back",
-	"undefined 15",
-};
-
-static const char *cache_clean[16] = {
-	"not required",
-	"read-block",
-	"cp15 c7 ops",
-	"undefined 3",
-	"undefined 4",
-	"undefined 5",
-	"cp15 c7 ops",
-	"cp15 c7 ops",
-	"undefined 8",
-	"undefined 9",
-	"undefined 10",
-	"undefined 11",
-	"undefined 12",
-	"undefined 13",
-	"cp15 c7 ops",
-	"undefined 15",
-};
-
-static const char *cache_lockdown[16] = {
-	"not supported",
-	"not supported",
-	"not supported",
-	"undefined 3",
-	"undefined 4",
-	"undefined 5",
-	"format A",
-	"format B",
-	"undefined 8",
-	"undefined 9",
-	"undefined 10",
-	"undefined 11",
-	"undefined 12",
-	"undefined 13",
-	"format C",
-	"undefined 15",
-};
-
 static const char *proc_arch[] = {
 	"undefined/unknown",
 	"3",
@@ -255,61 +196,19 @@
 	"?(17)",
 };
 
-#define CACHE_TYPE(x)	(((x) >> 25) & 15)
-#define CACHE_S(x)	((x) & (1 << 24))
-#define CACHE_DSIZE(x)	(((x) >> 12) & 4095)	/* only if S=1 */
-#define CACHE_ISIZE(x)	((x) & 4095)
-
-#define CACHE_SIZE(y)	(((y) >> 6) & 7)
-#define CACHE_ASSOC(y)	(((y) >> 3) & 7)
-#define CACHE_M(y)	((y) & (1 << 2))
-#define CACHE_LINE(y)	((y) & 3)
-
-static inline void dump_cache(const char *prefix, int cpu, unsigned int cache)
-{
-	unsigned int mult = 2 + (CACHE_M(cache) ? 1 : 0);
-
-	printk("CPU%u: %s: %d bytes, associativity %d, %d byte lines, %d sets\n",
-		cpu, prefix,
-		mult << (8 + CACHE_SIZE(cache)),
-		(mult << CACHE_ASSOC(cache)) >> 1,
-		8 << CACHE_LINE(cache),
-		1 << (6 + CACHE_SIZE(cache) - CACHE_ASSOC(cache) -
-			CACHE_LINE(cache)));
-}
-
-static void __init dump_cpu_info(int cpu)
-{
-	unsigned int info = read_cpuid(CPUID_CACHETYPE);
-
-	if (info != processor_id) {
-		printk("CPU%u: D %s %s cache\n", cpu, cache_is_vivt() ? "VIVT" : "VIPT",
-		       cache_types[CACHE_TYPE(info)]);
-		if (CACHE_S(info)) {
-			dump_cache("I cache", cpu, CACHE_ISIZE(info));
-			dump_cache("D cache", cpu, CACHE_DSIZE(info));
-		} else {
-			dump_cache("cache", cpu, CACHE_ISIZE(info));
-		}
-	}
-
-	if (arch_is_coherent())
-		printk("Cache coherency enabled\n");
-}
-
 int cpu_architecture(void)
 {
 	int cpu_arch;
 
-	if ((processor_id & 0x0008f000) == 0) {
+	if ((read_cpuid_id() & 0x0008f000) == 0) {
 		cpu_arch = CPU_ARCH_UNKNOWN;
-	} else if ((processor_id & 0x0008f000) == 0x00007000) {
-		cpu_arch = (processor_id & (1 << 23)) ? CPU_ARCH_ARMv4T : CPU_ARCH_ARMv3;
-	} else if ((processor_id & 0x00080000) == 0x00000000) {
-		cpu_arch = (processor_id >> 16) & 7;
+	} else if ((read_cpuid_id() & 0x0008f000) == 0x00007000) {
+		cpu_arch = (read_cpuid_id() & (1 << 23)) ? CPU_ARCH_ARMv4T : CPU_ARCH_ARMv3;
+	} else if ((read_cpuid_id() & 0x00080000) == 0x00000000) {
+		cpu_arch = (read_cpuid_id() >> 16) & 7;
 		if (cpu_arch)
 			cpu_arch += CPU_ARCH_ARMv3;
-	} else if ((processor_id & 0x000f0000) == 0x000f0000) {
+	} else if ((read_cpuid_id() & 0x000f0000) == 0x000f0000) {
 		unsigned int mmfr0;
 
 		/* Revised CPUID format. Read the Memory Model Feature
@@ -330,6 +229,34 @@
 	return cpu_arch;
 }
 
+static void __init cacheid_init(void)
+{
+	unsigned int cachetype = read_cpuid_cachetype();
+	unsigned int arch = cpu_architecture();
+
+	if (arch >= CPU_ARCH_ARMv7) {
+		cacheid = CACHEID_VIPT_NONALIASING;
+		if ((cachetype & (3 << 14)) == 1 << 14)
+			cacheid |= CACHEID_ASID_TAGGED;
+	} else if (arch >= CPU_ARCH_ARMv6) {
+		if (cachetype & (1 << 23))
+			cacheid = CACHEID_VIPT_ALIASING;
+		else
+			cacheid = CACHEID_VIPT_NONALIASING;
+	} else {
+		cacheid = CACHEID_VIVT;
+	}
+
+	printk("CPU: %s data cache, %s instruction cache\n",
+		cache_is_vivt() ? "VIVT" :
+		cache_is_vipt_aliasing() ? "VIPT aliasing" :
+		cache_is_vipt_nonaliasing() ? "VIPT nonaliasing" : "unknown",
+		cache_is_vivt() ? "VIVT" :
+		icache_is_vivt_asid_tagged() ? "VIVT ASID tagged" :
+		cache_is_vipt_aliasing() ? "VIPT aliasing" :
+		cache_is_vipt_nonaliasing() ? "VIPT nonaliasing" : "unknown");
+}
+
 /*
  * These functions re-use the assembly code in head.S, which
  * already provide the required functionality.
@@ -346,10 +273,10 @@
 	 * types.  The linker builds this table for us from the
 	 * entries in arch/arm/mm/proc-*.S
 	 */
-	list = lookup_processor_type(processor_id);
+	list = lookup_processor_type(read_cpuid_id());
 	if (!list) {
 		printk("CPU configuration botched (ID %08x), unable "
-		       "to continue.\n", processor_id);
+		       "to continue.\n", read_cpuid_id());
 		while (1);
 	}
 
@@ -369,7 +296,7 @@
 #endif
 
 	printk("CPU: %s [%08x] revision %d (ARMv%s), cr=%08lx\n",
-	       cpu_name, processor_id, (int)processor_id & 15,
+	       cpu_name, read_cpuid_id(), read_cpuid_id() & 15,
 	       proc_arch[cpu_architecture()], cr_alignment);
 
 	sprintf(init_utsname()->machine, "%s%c", list->arch_name, ENDIANNESS);
@@ -379,14 +306,14 @@
 	elf_hwcap &= ~HWCAP_THUMB;
 #endif
 
+	cacheid_init();
 	cpu_proc_init();
 }
 
 /*
  * cpu_init - initialise one CPU.
  *
- * cpu_init dumps the cache information, initialises SMP specific
- * information, and sets up the per-CPU stacks.
+ * cpu_init sets up the per-CPU stacks.
  */
 void cpu_init(void)
 {
@@ -398,9 +325,6 @@
 		BUG();
 	}
 
-	if (system_state == SYSTEM_BOOTING)
-		dump_cpu_info(cpu);
-
 	/*
 	 * setup stacks for re-entrant exception handlers
 	 */
@@ -443,20 +367,6 @@
 	return list;
 }
 
-static void __init early_initrd(char **p)
-{
-	unsigned long start, size;
-
-	start = memparse(*p, p);
-	if (**p == ',') {
-		size = memparse((*p) + 1, p);
-
-		phys_initrd_start = start;
-		phys_initrd_size = size;
-	}
-}
-__early_param("initrd=", early_initrd);
-
 static void __init arm_add_memory(unsigned long start, unsigned long size)
 {
 	struct membank *bank;
@@ -503,17 +413,6 @@
 __early_param("mem=", early_mem);
 
 /*
- * vmalloc=size forces the vmalloc area to be exactly 'size'
- * bytes. This can be used to increase (or decrease) the vmalloc
- * area - the default is 128m.
- */
-static void __init early_vmalloc(char **arg)
-{
-	vmalloc_reserve = memparse(*arg, arg);
-}
-__early_param("vmalloc=", early_vmalloc);
-
-/*
  * Initial parsing of the command line.
  */
 static void __init parse_cmdline(char **cmdline_p, char *from)
@@ -527,12 +426,12 @@
 			struct early_params *p;
 
 			for (p = &__early_begin; p < &__early_end; p++) {
-				int len = strlen(p->arg);
+				int arglen = strlen(p->arg);
 
-				if (memcmp(from, p->arg, len) == 0) {
+				if (memcmp(from, p->arg, arglen) == 0) {
 					if (to != command_line)
 						to -= 1;
-					from += len;
+					from += arglen;
 					p->fn(&from);
 
 					while (*from != ' ' && *from != '\0')
@@ -579,18 +478,13 @@
 	kernel_data.end     = virt_to_phys(&_end - 1);
 
 	for (i = 0; i < mi->nr_banks; i++) {
-		unsigned long virt_start, virt_end;
-
 		if (mi->bank[i].size == 0)
 			continue;
 
-		virt_start = __phys_to_virt(mi->bank[i].start);
-		virt_end   = virt_start + mi->bank[i].size - 1;
-
 		res = alloc_bootmem_low(sizeof(*res));
 		res->name  = "System RAM";
-		res->start = __virt_to_phys(virt_start);
-		res->end   = __virt_to_phys(virt_end);
+		res->start = mi->bank[i].start;
+		res->end   = mi->bank[i].start + mi->bank[i].size - 1;
 		res->flags = IORESOURCE_MEM | IORESOURCE_BUSY;
 
 		request_resource(&iomem_resource, res);
@@ -694,26 +588,6 @@
 
 __tagtable(ATAG_RAMDISK, parse_tag_ramdisk);
 
-static int __init parse_tag_initrd(const struct tag *tag)
-{
-	printk(KERN_WARNING "ATAG_INITRD is deprecated; "
-		"please update your bootloader.\n");
-	phys_initrd_start = __virt_to_phys(tag->u.initrd.start);
-	phys_initrd_size = tag->u.initrd.size;
-	return 0;
-}
-
-__tagtable(ATAG_INITRD, parse_tag_initrd);
-
-static int __init parse_tag_initrd2(const struct tag *tag)
-{
-	phys_initrd_start = tag->u.initrd.start;
-	phys_initrd_size = tag->u.initrd.size;
-	return 0;
-}
-
-__tagtable(ATAG_INITRD2, parse_tag_initrd2);
-
 static int __init parse_tag_serialnr(const struct tag *tag)
 {
 	system_serial_low = tag->u.serialnr.low;
@@ -901,28 +775,12 @@
 	NULL
 };
 
-static void
-c_show_cache(struct seq_file *m, const char *type, unsigned int cache)
-{
-	unsigned int mult = 2 + (CACHE_M(cache) ? 1 : 0);
-
-	seq_printf(m, "%s size\t\t: %d\n"
-		      "%s assoc\t\t: %d\n"
-		      "%s line length\t: %d\n"
-		      "%s sets\t\t: %d\n",
-		type, mult << (8 + CACHE_SIZE(cache)),
-		type, (mult << CACHE_ASSOC(cache)) >> 1,
-		type, 8 << CACHE_LINE(cache),
-		type, 1 << (6 + CACHE_SIZE(cache) - CACHE_ASSOC(cache) -
-			    CACHE_LINE(cache)));
-}
-
 static int c_show(struct seq_file *m, void *v)
 {
 	int i;
 
 	seq_printf(m, "Processor\t: %s rev %d (%s)\n",
-		   cpu_name, (int)processor_id & 15, elf_platform);
+		   cpu_name, read_cpuid_id() & 15, elf_platform);
 
 #if defined(CONFIG_SMP)
 	for_each_online_cpu(i) {
@@ -949,47 +807,26 @@
 		if (elf_hwcap & (1 << i))
 			seq_printf(m, "%s ", hwcap_str[i]);
 
-	seq_printf(m, "\nCPU implementer\t: 0x%02x\n", processor_id >> 24);
+	seq_printf(m, "\nCPU implementer\t: 0x%02x\n", read_cpuid_id() >> 24);
 	seq_printf(m, "CPU architecture: %s\n", proc_arch[cpu_architecture()]);
 
-	if ((processor_id & 0x0008f000) == 0x00000000) {
+	if ((read_cpuid_id() & 0x0008f000) == 0x00000000) {
 		/* pre-ARM7 */
-		seq_printf(m, "CPU part\t: %07x\n", processor_id >> 4);
+		seq_printf(m, "CPU part\t: %07x\n", read_cpuid_id() >> 4);
 	} else {
-		if ((processor_id & 0x0008f000) == 0x00007000) {
+		if ((read_cpuid_id() & 0x0008f000) == 0x00007000) {
 			/* ARM7 */
 			seq_printf(m, "CPU variant\t: 0x%02x\n",
-				   (processor_id >> 16) & 127);
+				   (read_cpuid_id() >> 16) & 127);
 		} else {
 			/* post-ARM7 */
 			seq_printf(m, "CPU variant\t: 0x%x\n",
-				   (processor_id >> 20) & 15);
+				   (read_cpuid_id() >> 20) & 15);
 		}
 		seq_printf(m, "CPU part\t: 0x%03x\n",
-			   (processor_id >> 4) & 0xfff);
+			   (read_cpuid_id() >> 4) & 0xfff);
 	}
-	seq_printf(m, "CPU revision\t: %d\n", processor_id & 15);
-
-	{
-		unsigned int cache_info = read_cpuid(CPUID_CACHETYPE);
-		if (cache_info != processor_id) {
-			seq_printf(m, "Cache type\t: %s\n"
-				      "Cache clean\t: %s\n"
-				      "Cache lockdown\t: %s\n"
-				      "Cache format\t: %s\n",
-				   cache_types[CACHE_TYPE(cache_info)],
-				   cache_clean[CACHE_TYPE(cache_info)],
-				   cache_lockdown[CACHE_TYPE(cache_info)],
-				   CACHE_S(cache_info) ? "Harvard" : "Unified");
-
-			if (CACHE_S(cache_info)) {
-				c_show_cache(m, "I", CACHE_ISIZE(cache_info));
-				c_show_cache(m, "D", CACHE_DSIZE(cache_info));
-			} else {
-				c_show_cache(m, "Cache", CACHE_ISIZE(cache_info));
-			}
-		}
-	}
+	seq_printf(m, "CPU revision\t: %d\n", read_cpuid_id() & 15);
 
 	seq_puts(m, "\n");
 
diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c
index ef2f86a..80b8b5c 100644
--- a/arch/arm/kernel/signal.c
+++ b/arch/arm/kernel/signal.c
@@ -11,11 +11,11 @@
 #include <linux/signal.h>
 #include <linux/personality.h>
 #include <linux/freezer.h>
+#include <linux/uaccess.h>
 
 #include <asm/elf.h>
 #include <asm/cacheflush.h>
 #include <asm/ucontext.h>
-#include <asm/uaccess.h>
 #include <asm/unistd.h>
 
 #include "ptrace.h"
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index e9842f6..e42a749 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -277,6 +277,7 @@
 	/*
 	 * Enable local interrupts.
 	 */
+	notify_cpu_starting(cpu);
 	local_irq_enable();
 	local_fiq_enable();
 
diff --git a/arch/arm/kernel/sys_arm.c b/arch/arm/kernel/sys_arm.c
index 0128687..b3ec641 100644
--- a/arch/arm/kernel/sys_arm.c
+++ b/arch/arm/kernel/sys_arm.c
@@ -27,8 +27,7 @@
 #include <linux/file.h>
 #include <linux/utsname.h>
 #include <linux/ipc.h>
-
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
 
 extern unsigned long do_mremap(unsigned long addr, unsigned long old_len,
 			       unsigned long new_len, unsigned long flags,
diff --git a/arch/arm/kernel/sys_oabi-compat.c b/arch/arm/kernel/sys_oabi-compat.c
index 96ab5f5..42623db 100644
--- a/arch/arm/kernel/sys_oabi-compat.c
+++ b/arch/arm/kernel/sys_oabi-compat.c
@@ -82,7 +82,7 @@
 #include <linux/socket.h>
 #include <linux/net.h>
 #include <linux/ipc.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
 
 struct oldabi_stat64 {
 	unsigned long long st_dev;
diff --git a/arch/arm/kernel/time.c b/arch/arm/kernel/time.c
index 368d171..c68b44a 100644
--- a/arch/arm/kernel/time.c
+++ b/arch/arm/kernel/time.c
@@ -59,7 +59,7 @@
 
 	if (in_lock_functions(pc)) {
 		fp = regs->ARM_fp;
-		pc = pc_pointer(((unsigned long *)fp)[-1]);
+		pc = ((unsigned long *)fp)[-1];
 	}
 
 	return pc;
diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c
index 872f1f8..57e6874 100644
--- a/arch/arm/kernel/traps.c
+++ b/arch/arm/kernel/traps.c
@@ -19,15 +19,13 @@
 #include <linux/kallsyms.h>
 #include <linux/delay.h>
 #include <linux/init.h>
-#include <linux/kprobes.h>
+#include <linux/uaccess.h>
 
 #include <asm/atomic.h>
 #include <asm/cacheflush.h>
 #include <asm/system.h>
-#include <asm/uaccess.h>
 #include <asm/unistd.h>
 #include <asm/traps.h>
-#include <asm/io.h>
 
 #include "ptrace.h"
 #include "signal.h"
@@ -69,7 +67,8 @@
  */
 static int verify_stack(unsigned long sp)
 {
-	if (sp < PAGE_OFFSET || (sp > (unsigned long)high_memory && high_memory != 0))
+	if (sp < PAGE_OFFSET ||
+	    (sp > (unsigned long)high_memory && high_memory != NULL))
 		return -EFAULT;
 
 	return 0;
@@ -328,17 +327,6 @@
 		get_user(instr, (u32 __user *)pc);
 	}
 
-#ifdef CONFIG_KPROBES
-	/*
-	 * It is possible to have recursive kprobes, so we can't call
-	 * the kprobe trap handler with the undef_lock held.
-	 */
-	if (instr == KPROBE_BREAKPOINT_INSTRUCTION && !user_mode(regs)) {
-		kprobe_trap_handler(regs, instr);
-		return;
-	}
-#endif
-
 	if (call_undef_hook(regs, instr) == 0)
 		return;
 
diff --git a/arch/arm/kernel/xscale-cp0.c b/arch/arm/kernel/xscale-cp0.c
index 180000b..17127db 100644
--- a/arch/arm/kernel/xscale-cp0.c
+++ b/arch/arm/kernel/xscale-cp0.c
@@ -14,8 +14,8 @@
 #include <linux/signal.h>
 #include <linux/sched.h>
 #include <linux/init.h>
+#include <linux/io.h>
 #include <asm/thread_notify.h>
-#include <asm/io.h>
 
 static inline void dsp_save_state(u32 *state)
 {
diff --git a/arch/arm/lib/ashldi3.S b/arch/arm/lib/ashldi3.S
index 55e57a1c..1154d92 100644
--- a/arch/arm/lib/ashldi3.S
+++ b/arch/arm/lib/ashldi3.S
@@ -47,3 +47,5 @@
 	mov	al, al, lsl r2
 	mov	pc, lr
 
+ENDPROC(__ashldi3)
+ENDPROC(__aeabi_llsl)
diff --git a/arch/arm/lib/ashrdi3.S b/arch/arm/lib/ashrdi3.S
index 0b31398..9f8b355 100644
--- a/arch/arm/lib/ashrdi3.S
+++ b/arch/arm/lib/ashrdi3.S
@@ -47,3 +47,5 @@
 	mov	ah, ah, asr r2
 	mov	pc, lr
 
+ENDPROC(__ashrdi3)
+ENDPROC(__aeabi_lasr)
diff --git a/arch/arm/lib/backtrace.S b/arch/arm/lib/backtrace.S
index 84dc890..b0951d0 100644
--- a/arch/arm/lib/backtrace.S
+++ b/arch/arm/lib/backtrace.S
@@ -30,6 +30,8 @@
 
 #if !defined(CONFIG_FRAME_POINTER) || !defined(CONFIG_PRINTK)
 		mov	pc, lr
+ENDPROC(__backtrace)
+ENDPROC(c_backtrace)
 #else
 		stmfd	sp!, {r4 - r8, lr}	@ Save an extra register so we have a location...
 		movs	frame, r0		@ if frame pointer is zero
@@ -103,6 +105,8 @@
 		mov	r1, frame
 		bl	printk
 no_frame:	ldmfd	sp!, {r4 - r8, pc}
+ENDPROC(__backtrace)
+ENDPROC(c_backtrace)
 		
 		.section __ex_table,"a"
 		.align	3
diff --git a/arch/arm/lib/changebit.S b/arch/arm/lib/changebit.S
index 389567c..80f3115 100644
--- a/arch/arm/lib/changebit.S
+++ b/arch/arm/lib/changebit.S
@@ -19,3 +19,5 @@
 		eor	r0, r0, #0x18		@ big endian byte ordering
 ENTRY(_change_bit_le)
 	bitop	eor
+ENDPROC(_change_bit_be)
+ENDPROC(_change_bit_le)
diff --git a/arch/arm/lib/clear_user.S b/arch/arm/lib/clear_user.S
index ecb28dc..4d6bc71 100644
--- a/arch/arm/lib/clear_user.S
+++ b/arch/arm/lib/clear_user.S
@@ -41,9 +41,10 @@
 USER(		strnebt	r2, [r0], #1)
 USER(		strnebt	r2, [r0], #1)
 		tst	r1, #1			@ x1 x0 x1 x0 x1 x0 x1
-USER(		strnebt	r2, [r0], #1)
+USER(		strnebt	r2, [r0])
 		mov	r0, #0
 		ldmfd	sp!, {r1, pc}
+ENDPROC(__clear_user)
 
 		.section .fixup,"ax"
 		.align	0
diff --git a/arch/arm/lib/clearbit.S b/arch/arm/lib/clearbit.S
index 3475165..1a63e43 100644
--- a/arch/arm/lib/clearbit.S
+++ b/arch/arm/lib/clearbit.S
@@ -20,3 +20,5 @@
 		eor	r0, r0, #0x18		@ big endian byte ordering
 ENTRY(_clear_bit_le)
 	bitop	bic
+ENDPROC(_clear_bit_be)
+ENDPROC(_clear_bit_le)
diff --git a/arch/arm/lib/copy_from_user.S b/arch/arm/lib/copy_from_user.S
index 6b7363c..56799a1 100644
--- a/arch/arm/lib/copy_from_user.S
+++ b/arch/arm/lib/copy_from_user.S
@@ -87,6 +87,8 @@
 
 #include "copy_template.S"
 
+ENDPROC(__copy_from_user)
+
 	.section .fixup,"ax"
 	.align 0
 	copy_abort_preamble
diff --git a/arch/arm/lib/copy_page.S b/arch/arm/lib/copy_page.S
index 666c99c..6ae04db 100644
--- a/arch/arm/lib/copy_page.S
+++ b/arch/arm/lib/copy_page.S
@@ -44,3 +44,4 @@
 	PLD(	ldmeqia r1!, {r3, r4, ip, lr}	)
 	PLD(	beq	2b			)
 		ldmfd	sp!, {r4, pc}			@	3
+ENDPROC(copy_page)
diff --git a/arch/arm/lib/copy_to_user.S b/arch/arm/lib/copy_to_user.S
index 5224d94..22f968b 100644
--- a/arch/arm/lib/copy_to_user.S
+++ b/arch/arm/lib/copy_to_user.S
@@ -90,6 +90,8 @@
 
 #include "copy_template.S"
 
+ENDPROC(__copy_to_user)
+
 	.section .fixup,"ax"
 	.align 0
 	copy_abort_preamble
diff --git a/arch/arm/lib/csumipv6.S b/arch/arm/lib/csumipv6.S
index 9621469..3ac6ef0 100644
--- a/arch/arm/lib/csumipv6.S
+++ b/arch/arm/lib/csumipv6.S
@@ -29,4 +29,5 @@
 		adcs	r0, r0, r2
 		adcs	r0, r0, #0
 		ldmfd	sp!, {pc}
+ENDPROC(__csum_ipv6_magic)
 
diff --git a/arch/arm/lib/csumpartial.S b/arch/arm/lib/csumpartial.S
index a78dae5..31d3cb3 100644
--- a/arch/arm/lib/csumpartial.S
+++ b/arch/arm/lib/csumpartial.S
@@ -139,3 +139,4 @@
 		tst	len, #0x1c
 		bne	4b
 		b	.Lless4
+ENDPROC(csum_partial)
diff --git a/arch/arm/lib/csumpartialcopy.S b/arch/arm/lib/csumpartialcopy.S
index 21effe0..d03fc71 100644
--- a/arch/arm/lib/csumpartialcopy.S
+++ b/arch/arm/lib/csumpartialcopy.S
@@ -18,13 +18,11 @@
  */
 
 		.macro	save_regs
-		mov	ip, sp
-		stmfd	sp!, {r1, r4 - r8, fp, ip, lr, pc}
-		sub	fp, ip, #4
+		stmfd	sp!, {r1, r4 - r8, lr}
 		.endm
 
 		.macro	load_regs
-		ldmfd	sp, {r1, r4 - r8, fp, sp, pc}
+		ldmfd	sp!, {r1, r4 - r8, pc}
 		.endm
 
 		.macro	load1b, reg1
@@ -50,5 +48,6 @@
 		.endm
 
 #define FN_ENTRY	ENTRY(csum_partial_copy_nocheck)
+#define FN_EXIT		ENDPROC(csum_partial_copy_nocheck)
 
 #include "csumpartialcopygeneric.S"
diff --git a/arch/arm/lib/csumpartialcopygeneric.S b/arch/arm/lib/csumpartialcopygeneric.S
index c50e8f5..d620a5f 100644
--- a/arch/arm/lib/csumpartialcopygeneric.S
+++ b/arch/arm/lib/csumpartialcopygeneric.S
@@ -329,3 +329,4 @@
 		adcs	sum, sum, r4, push #24
 		mov	r5, r4, get_byte_1
 		b	.Lexit
+FN_EXIT
diff --git a/arch/arm/lib/csumpartialcopyuser.S b/arch/arm/lib/csumpartialcopyuser.S
index c3b93e2..14677fb 100644
--- a/arch/arm/lib/csumpartialcopyuser.S
+++ b/arch/arm/lib/csumpartialcopyuser.S
@@ -18,13 +18,11 @@
 		.text
 
 		.macro	save_regs
-		mov	ip, sp
-		stmfd	sp!, {r1 - r2, r4 - r8, fp, ip, lr, pc}
-		sub	fp, ip, #4
+		stmfd	sp!, {r1, r2, r4 - r8, lr}
 		.endm
 
 		.macro	load_regs
-		ldmfd	sp, {r1, r2, r4-r8, fp, sp, pc}
+		ldmfd	sp!, {r1, r2, r4 - r8, pc}
 		.endm
 
 		.macro	load1b,	reg1
@@ -82,6 +80,7 @@
  */
 
 #define FN_ENTRY	ENTRY(csum_partial_copy_from_user)
+#define FN_EXIT		ENDPROC(csum_partial_copy_from_user)
 
 #include "csumpartialcopygeneric.S"
 
diff --git a/arch/arm/lib/delay.S b/arch/arm/lib/delay.S
index 930a702..8d6a876 100644
--- a/arch/arm/lib/delay.S
+++ b/arch/arm/lib/delay.S
@@ -60,3 +60,6 @@
 #endif
 		bhi	__delay
 		mov	pc, lr
+ENDPROC(__udelay)
+ENDPROC(__const_udelay)
+ENDPROC(__delay)
diff --git a/arch/arm/lib/div64.S b/arch/arm/lib/div64.S
index 58eef66..1425e78 100644
--- a/arch/arm/lib/div64.S
+++ b/arch/arm/lib/div64.S
@@ -198,3 +198,4 @@
 	mov	xh, #0
 	ldr	pc, [sp], #8
 
+ENDPROC(__do_div64)
diff --git a/arch/arm/lib/findbit.S b/arch/arm/lib/findbit.S
index a5ca024..8c4defc 100644
--- a/arch/arm/lib/findbit.S
+++ b/arch/arm/lib/findbit.S
@@ -33,6 +33,7 @@
 		blo	1b
 3:		mov	r0, r1			@ no free bits
 		mov	pc, lr
+ENDPROC(_find_first_zero_bit_le)
 
 /*
  * Purpose  : Find next 'zero' bit
@@ -50,6 +51,7 @@
 		orr	r2, r2, #7		@ if zero, then no bits here
 		add	r2, r2, #1		@ align bit pointer
 		b	2b			@ loop for next bit
+ENDPROC(_find_next_zero_bit_le)
 
 /*
  * Purpose  : Find a 'one' bit
@@ -67,6 +69,7 @@
 		blo	1b
 3:		mov	r0, r1			@ no free bits
 		mov	pc, lr
+ENDPROC(_find_first_bit_le)
 
 /*
  * Purpose  : Find next 'one' bit
@@ -83,6 +86,7 @@
 		orr	r2, r2, #7		@ if zero, then no bits here
 		add	r2, r2, #1		@ align bit pointer
 		b	2b			@ loop for next bit
+ENDPROC(_find_next_bit_le)
 
 #ifdef __ARMEB__
 
@@ -99,6 +103,7 @@
 		blo	1b
 3:		mov	r0, r1			@ no free bits
 		mov	pc, lr
+ENDPROC(_find_first_zero_bit_be)
 
 ENTRY(_find_next_zero_bit_be)
 		teq	r1, #0
@@ -113,6 +118,7 @@
 		orr	r2, r2, #7		@ if zero, then no bits here
 		add	r2, r2, #1		@ align bit pointer
 		b	2b			@ loop for next bit
+ENDPROC(_find_next_zero_bit_be)
 
 ENTRY(_find_first_bit_be)
 		teq	r1, #0
@@ -127,6 +133,7 @@
 		blo	1b
 3:		mov	r0, r1			@ no free bits
 		mov	pc, lr
+ENDPROC(_find_first_bit_be)
 
 ENTRY(_find_next_bit_be)
 		teq	r1, #0
@@ -140,6 +147,7 @@
 		orr	r2, r2, #7		@ if zero, then no bits here
 		add	r2, r2, #1		@ align bit pointer
 		b	2b			@ loop for next bit
+ENDPROC(_find_next_bit_be)
 
 #endif
 
diff --git a/arch/arm/lib/getuser.S b/arch/arm/lib/getuser.S
index 2034d4d..6763088 100644
--- a/arch/arm/lib/getuser.S
+++ b/arch/arm/lib/getuser.S
@@ -26,16 +26,16 @@
  * Note that ADDR_LIMIT is either 0 or 0xc0000000.
  * Note also that it is intended that __get_user_bad is not global.
  */
+#include <linux/linkage.h>
 #include <asm/errno.h>
 
-	.global	__get_user_1
-__get_user_1:
+ENTRY(__get_user_1)
 1:	ldrbt	r2, [r0]
 	mov	r0, #0
 	mov	pc, lr
+ENDPROC(__get_user_1)
 
-	.global	__get_user_2
-__get_user_2:
+ENTRY(__get_user_2)
 2:	ldrbt	r2, [r0], #1
 3:	ldrbt	r3, [r0]
 #ifndef __ARMEB__
@@ -45,17 +45,19 @@
 #endif
 	mov	r0, #0
 	mov	pc, lr
+ENDPROC(__get_user_2)
 
-	.global	__get_user_4
-__get_user_4:
+ENTRY(__get_user_4)
 4:	ldrt	r2, [r0]
 	mov	r0, #0
 	mov	pc, lr
+ENDPROC(__get_user_4)
 
 __get_user_bad:
 	mov	r2, #0
 	mov	r0, #-EFAULT
 	mov	pc, lr
+ENDPROC(__get_user_bad)
 
 .section __ex_table, "a"
 	.long	1b, __get_user_bad
diff --git a/arch/arm/lib/io-readsb.S b/arch/arm/lib/io-readsb.S
index fb966ad..9f42389 100644
--- a/arch/arm/lib/io-readsb.S
+++ b/arch/arm/lib/io-readsb.S
@@ -120,3 +120,4 @@
 		strgtb	r3, [r1]
 
 		ldmfd	sp!, {r4 - r6, pc}
+ENDPROC(__raw_readsb)
diff --git a/arch/arm/lib/io-readsl.S b/arch/arm/lib/io-readsl.S
index 75a9121..5fb97e7 100644
--- a/arch/arm/lib/io-readsl.S
+++ b/arch/arm/lib/io-readsl.S
@@ -76,3 +76,4 @@
 8:		mov	r3, ip, get_byte_0
 		strb	r3, [r1, #0]
 		mov	pc, lr
+ENDPROC(__raw_readsl)
diff --git a/arch/arm/lib/io-readsw-armv4.S b/arch/arm/lib/io-readsw-armv4.S
index 4db1c5f..1f393d4 100644
--- a/arch/arm/lib/io-readsw-armv4.S
+++ b/arch/arm/lib/io-readsw-armv4.S
@@ -128,3 +128,4 @@
    _BE_ONLY_(	movne	ip, ip, lsr #24		)
 		strneb	ip, [r1]
 		ldmfd	sp!, {r4, pc}
+ENDPROC(__raw_readsw)
diff --git a/arch/arm/lib/io-writesb.S b/arch/arm/lib/io-writesb.S
index 7eba2b6..68b92f4 100644
--- a/arch/arm/lib/io-writesb.S
+++ b/arch/arm/lib/io-writesb.S
@@ -91,3 +91,4 @@
 		strgtb	r3, [r0]
 
 		ldmfd	sp!, {r4, r5, pc}
+ENDPROC(__raw_writesb)
diff --git a/arch/arm/lib/io-writesl.S b/arch/arm/lib/io-writesl.S
index f8f14dd..8d3b781 100644
--- a/arch/arm/lib/io-writesl.S
+++ b/arch/arm/lib/io-writesl.S
@@ -64,3 +64,4 @@
 		str	ip, [r0]
 		bne	6b
 		mov	pc, lr
+ENDPROC(__raw_writesl)
diff --git a/arch/arm/lib/io-writesw-armv4.S b/arch/arm/lib/io-writesw-armv4.S
index c8e85bd..d658561 100644
--- a/arch/arm/lib/io-writesw-armv4.S
+++ b/arch/arm/lib/io-writesw-armv4.S
@@ -94,3 +94,4 @@
 3:		movne	ip, r3, lsr #8
 		strneh	ip, [r0]
 		mov	pc, lr
+ENDPROC(__raw_writesw)
diff --git a/arch/arm/lib/lib1funcs.S b/arch/arm/lib/lib1funcs.S
index 4e492f4..67964bc 100644
--- a/arch/arm/lib/lib1funcs.S
+++ b/arch/arm/lib/lib1funcs.S
@@ -230,6 +230,8 @@
 	mov	r0, r0, lsr r2
 	mov	pc, lr
 
+ENDPROC(__udivsi3)
+ENDPROC(__aeabi_uidiv)
 
 ENTRY(__umodsi3)
 
@@ -245,6 +247,7 @@
 
 	mov	pc, lr
 
+ENDPROC(__umodsi3)
 
 ENTRY(__divsi3)
 ENTRY(__aeabi_idiv)
@@ -284,6 +287,8 @@
 	rsbmi	r0, r0, #0
 	mov	pc, lr
 
+ENDPROC(__divsi3)
+ENDPROC(__aeabi_idiv)
 
 ENTRY(__modsi3)
 
@@ -305,6 +310,8 @@
 	rsbmi	r0, r0, #0
 	mov	pc, lr
 
+ENDPROC(__modsi3)
+
 #ifdef CONFIG_AEABI
 
 ENTRY(__aeabi_uidivmod)
@@ -316,6 +323,8 @@
 	sub	r1, r1, r3
 	mov	pc, lr
 
+ENDPROC(__aeabi_uidivmod)
+
 ENTRY(__aeabi_idivmod)
 
 	stmfd	sp!, {r0, r1, ip, lr}
@@ -325,6 +334,8 @@
 	sub	r1, r1, r3
 	mov	pc, lr
 
+ENDPROC(__aeabi_idivmod)
+
 #endif
 
 Ldiv0:
diff --git a/arch/arm/lib/lshrdi3.S b/arch/arm/lib/lshrdi3.S
index a86dbdd..99ea338 100644
--- a/arch/arm/lib/lshrdi3.S
+++ b/arch/arm/lib/lshrdi3.S
@@ -47,3 +47,5 @@
 	mov	ah, ah, lsr r2
 	mov	pc, lr
 
+ENDPROC(__lshrdi3)
+ENDPROC(__aeabi_llsr)
diff --git a/arch/arm/lib/memchr.S b/arch/arm/lib/memchr.S
index e7ab1ea..1da8699 100644
--- a/arch/arm/lib/memchr.S
+++ b/arch/arm/lib/memchr.S
@@ -23,3 +23,4 @@
 	sub	r0, r0, #1
 2:	movne	r0, #0
 	mov	pc, lr
+ENDPROC(memchr)
diff --git a/arch/arm/lib/memcpy.S b/arch/arm/lib/memcpy.S
index 7e71d67..e0d0026 100644
--- a/arch/arm/lib/memcpy.S
+++ b/arch/arm/lib/memcpy.S
@@ -57,3 +57,4 @@
 
 #include "copy_template.S"
 
+ENDPROC(memcpy)
diff --git a/arch/arm/lib/memmove.S b/arch/arm/lib/memmove.S
index 2e301b7..1254918 100644
--- a/arch/arm/lib/memmove.S
+++ b/arch/arm/lib/memmove.S
@@ -196,3 +196,4 @@
 
 18:		backward_copy_shift	push=24	pull=8
 
+ENDPROC(memmove)
diff --git a/arch/arm/lib/memset.S b/arch/arm/lib/memset.S
index b477d4a..761eefa 100644
--- a/arch/arm/lib/memset.S
+++ b/arch/arm/lib/memset.S
@@ -124,3 +124,4 @@
 	tst	r2, #1
 	strneb	r1, [r0], #1
 	mov	pc, lr
+ENDPROC(memset)
diff --git a/arch/arm/lib/memzero.S b/arch/arm/lib/memzero.S
index b8f79d8..3fbdef5 100644
--- a/arch/arm/lib/memzero.S
+++ b/arch/arm/lib/memzero.S
@@ -122,3 +122,4 @@
 	tst	r1, #1			@ 1 a byte left over
 	strneb	r2, [r0], #1		@ 1
 	mov	pc, lr			@ 1
+ENDPROC(__memzero)
diff --git a/arch/arm/lib/muldi3.S b/arch/arm/lib/muldi3.S
index d89c606..36c91b4 100644
--- a/arch/arm/lib/muldi3.S
+++ b/arch/arm/lib/muldi3.S
@@ -43,3 +43,5 @@
 	adc	xh, xh, ip, lsr #16
 	mov	pc, lr
 
+ENDPROC(__muldi3)
+ENDPROC(__aeabi_lmul)
diff --git a/arch/arm/lib/putuser.S b/arch/arm/lib/putuser.S
index 08ec7df..864f3c1 100644
--- a/arch/arm/lib/putuser.S
+++ b/arch/arm/lib/putuser.S
@@ -26,16 +26,16 @@
  * Note that ADDR_LIMIT is either 0 or 0xc0000000
  * Note also that it is intended that __put_user_bad is not global.
  */
+#include <linux/linkage.h>
 #include <asm/errno.h>
 
-	.global	__put_user_1
-__put_user_1:
+ENTRY(__put_user_1)
 1:	strbt	r2, [r0]
 	mov	r0, #0
 	mov	pc, lr
+ENDPROC(__put_user_1)
 
-	.global	__put_user_2
-__put_user_2:
+ENTRY(__put_user_2)
 	mov	ip, r2, lsr #8
 #ifndef __ARMEB__
 2:	strbt	r2, [r0], #1
@@ -46,23 +46,25 @@
 #endif
 	mov	r0, #0
 	mov	pc, lr
+ENDPROC(__put_user_2)
 
-	.global	__put_user_4
-__put_user_4:
+ENTRY(__put_user_4)
 4:	strt	r2, [r0]
 	mov	r0, #0
 	mov	pc, lr
+ENDPROC(__put_user_4)
 
-	.global	__put_user_8
-__put_user_8:
+ENTRY(__put_user_8)
 5:	strt	r2, [r0], #4
 6:	strt	r3, [r0]
 	mov	r0, #0
 	mov	pc, lr
+ENDPROC(__put_user_8)
 
 __put_user_bad:
 	mov	r0, #-EFAULT
 	mov	pc, lr
+ENDPROC(__put_user_bad)
 
 .section __ex_table, "a"
 	.long	1b, __put_user_bad
diff --git a/arch/arm/lib/setbit.S b/arch/arm/lib/setbit.S
index 83bc23d..1dd7176 100644
--- a/arch/arm/lib/setbit.S
+++ b/arch/arm/lib/setbit.S
@@ -20,3 +20,5 @@
 		eor	r0, r0, #0x18		@ big endian byte ordering
 ENTRY(_set_bit_le)
 	bitop	orr
+ENDPROC(_set_bit_be)
+ENDPROC(_set_bit_le)
diff --git a/arch/arm/lib/sha1.S b/arch/arm/lib/sha1.S
index 67c2bf4..a16fb20 100644
--- a/arch/arm/lib/sha1.S
+++ b/arch/arm/lib/sha1.S
@@ -185,6 +185,8 @@
 
 	ldmfd	sp!, {r4 - r8, pc}
 
+ENDPROC(sha_transform)
+
 .L_sha_K:
 	.word	0x5a827999, 0x6ed9eba1, 0x8f1bbcdc, 0xca62c1d6
 
@@ -204,3 +206,4 @@
 	stmia	r0, {r1, r2, r3, ip, lr}
 	ldr	pc, [sp], #4
 
+ENDPROC(sha_init)
diff --git a/arch/arm/lib/strchr.S b/arch/arm/lib/strchr.S
index 9f18d6f..d8f2a1c 100644
--- a/arch/arm/lib/strchr.S
+++ b/arch/arm/lib/strchr.S
@@ -24,3 +24,4 @@
 		movne	r0, #0
 		subeq	r0, r0, #1
 		mov	pc, lr
+ENDPROC(strchr)
diff --git a/arch/arm/lib/strncpy_from_user.S b/arch/arm/lib/strncpy_from_user.S
index 36e3741..330373c 100644
--- a/arch/arm/lib/strncpy_from_user.S
+++ b/arch/arm/lib/strncpy_from_user.S
@@ -31,6 +31,7 @@
 	sub	r1, r1, #1	@ take NUL character out of count
 2:	sub	r0, r1, ip
 	mov	pc, lr
+ENDPROC(__strncpy_from_user)
 
 	.section .fixup,"ax"
 	.align	0
diff --git a/arch/arm/lib/strnlen_user.S b/arch/arm/lib/strnlen_user.S
index 18d8fa4..90bb9d0 100644
--- a/arch/arm/lib/strnlen_user.S
+++ b/arch/arm/lib/strnlen_user.S
@@ -31,6 +31,7 @@
 	add	r0, r0, #1
 2:	sub	r0, r0, r2
 	mov	pc, lr
+ENDPROC(__strnlen_user)
 
 	.section .fixup,"ax"
 	.align	0
diff --git a/arch/arm/lib/strrchr.S b/arch/arm/lib/strrchr.S
index 538df22..302f20c 100644
--- a/arch/arm/lib/strrchr.S
+++ b/arch/arm/lib/strrchr.S
@@ -23,3 +23,4 @@
 		bne	1b
 		mov	r0, r3
 		mov	pc, lr
+ENDPROC(strrchr)
diff --git a/arch/arm/lib/testchangebit.S b/arch/arm/lib/testchangebit.S
index b25dcd2..5c98dc5 100644
--- a/arch/arm/lib/testchangebit.S
+++ b/arch/arm/lib/testchangebit.S
@@ -16,3 +16,5 @@
 		eor	r0, r0, #0x18		@ big endian byte ordering
 ENTRY(_test_and_change_bit_le)
 	testop	eor, strb
+ENDPROC(_test_and_change_bit_be)
+ENDPROC(_test_and_change_bit_le)
diff --git a/arch/arm/lib/testclearbit.S b/arch/arm/lib/testclearbit.S
index 2dcc4b1..543d709 100644
--- a/arch/arm/lib/testclearbit.S
+++ b/arch/arm/lib/testclearbit.S
@@ -16,3 +16,5 @@
 		eor	r0, r0, #0x18		@ big endian byte ordering
 ENTRY(_test_and_clear_bit_le)
 	testop	bicne, strneb
+ENDPROC(_test_and_clear_bit_be)
+ENDPROC(_test_and_clear_bit_le)
diff --git a/arch/arm/lib/testsetbit.S b/arch/arm/lib/testsetbit.S
index 9011c96..0b3f390 100644
--- a/arch/arm/lib/testsetbit.S
+++ b/arch/arm/lib/testsetbit.S
@@ -16,3 +16,5 @@
 		eor	r0, r0, #0x18		@ big endian byte ordering
 ENTRY(_test_and_set_bit_le)
 	testop	orreq, streqb
+ENDPROC(_test_and_set_bit_be)
+ENDPROC(_test_and_set_bit_le)
diff --git a/arch/arm/lib/uaccess.S b/arch/arm/lib/uaccess.S
index b48bd6d..ffdd274 100644
--- a/arch/arm/lib/uaccess.S
+++ b/arch/arm/lib/uaccess.S
@@ -277,6 +277,7 @@
 		ldrgtb	r3, [r1], #0
 USER(		strgtbt	r3, [r0], #1)			@ May fault
 		b	.Lc2u_finished
+ENDPROC(__copy_to_user)
 
 		.section .fixup,"ax"
 		.align	0
@@ -542,6 +543,7 @@
 USER(		ldrgtbt	r3, [r1], #1)			@ May fault
 		strgtb	r3, [r0], #1
 		b	.Lcfu_finished
+ENDPROC(__copy_from_user)
 
 		.section .fixup,"ax"
 		.align	0
diff --git a/arch/arm/lib/ucmpdi2.S b/arch/arm/lib/ucmpdi2.S
index f76de07..f0df6a91 100644
--- a/arch/arm/lib/ucmpdi2.S
+++ b/arch/arm/lib/ucmpdi2.S
@@ -33,6 +33,8 @@
 	movhi	r0, #2
 	mov	pc, lr
 
+ENDPROC(__ucmpdi2)
+
 #ifdef CONFIG_AEABI
 
 ENTRY(__aeabi_ulcmp)
@@ -44,5 +46,7 @@
 	movhi	r0, #1
 	mov	pc, lr
 
+ENDPROC(__aeabi_ulcmp)
+
 #endif
 
diff --git a/arch/arm/mach-at91/Kconfig b/arch/arm/mach-at91/Kconfig
index a048b92..5aafb2e 100644
--- a/arch/arm/mach-at91/Kconfig
+++ b/arch/arm/mach-at91/Kconfig
@@ -175,6 +175,15 @@
 	  Select this if you are using Olimex's SAM9-L9260 board based on the Atmel AT91SAM9260.
 	  <http://www.olimex.com/dev/sam9-L9260.html>
 
+config MACH_AFEB9260
+	bool "Custom afeb9260 board v1"
+	depends on ARCH_AT91SAM9260
+	help
+	  Select this if you are using custom afeb9260 board based on
+	  open hardware design. Select this for revision 1 of the board.
+	  <svn://194.85.238.22/home/users/george/svn/arm9eb>
+	  <http://groups.google.com/group/arm9fpga-evolution-board>
+
 config MACH_USB_A9260
 	bool "CALAO USB-A9260"
 	depends on ARCH_AT91SAM9260
@@ -314,6 +323,19 @@
 	  Select this if you need to program one or more of the PCK0..PCK3
 	  programmable clock outputs.
 
+config AT91_SLOW_CLOCK
+	bool "Suspend-to-RAM disables main oscillator"
+	depends on SUSPEND
+	help
+	  Select this if you want Suspend-to-RAM to save the most power
+	  possible (without powering off the CPU) by disabling the PLLs
+	  and main oscillator so that only the 32 KiHz clock is available.
+
+	  When only that slow-clock is available, some peripherals lose
+	  functionality.  Many can't issue wakeup events unless faster
+	  clocks are available.  Some lose their operating state and
+	  need to be completely re-initialized.
+
 config AT91_TIMER_HZ
        int "Kernel HZ (jiffies per second)"
        range 32 1024
diff --git a/arch/arm/mach-at91/Makefile b/arch/arm/mach-at91/Makefile
index 7d641f9..cca612d 100644
--- a/arch/arm/mach-at91/Makefile
+++ b/arch/arm/mach-at91/Makefile
@@ -39,6 +39,7 @@
 obj-$(CONFIG_MACH_SAM9_L9260)	+= board-sam9-l9260.o
 obj-$(CONFIG_MACH_USB_A9260)	+= board-usb-a9260.o
 obj-$(CONFIG_MACH_QIL_A9260)	+= board-qil-a9260.o
+obj-$(CONFIG_MACH_AFEB9260)	+= board-afeb-9260v1.o
 
 # AT91SAM9261 board-specific support
 obj-$(CONFIG_MACH_AT91SAM9261EK) += board-sam9261ek.o
@@ -64,6 +65,7 @@
 
 # Power Management
 obj-$(CONFIG_PM)		+= pm.o
+obj-$(CONFIG_AT91_SLOW_CLOCK)	+= pm_slowclock.o
 
 ifeq ($(CONFIG_PM_DEBUG),y)
 CFLAGS_pm.o += -DDEBUG
diff --git a/arch/arm/mach-at91/at91cap9.c b/arch/arm/mach-at91/at91cap9.c
index 638948c..0fc0ada 100644
--- a/arch/arm/mach-at91/at91cap9.c
+++ b/arch/arm/mach-at91/at91cap9.c
@@ -141,8 +141,8 @@
 	.pmc_mask	= 1 << AT91CAP9_ID_TCB,
 	.type		= CLK_TYPE_PERIPHERAL,
 };
-static struct clk pwmc_clk = {
-	.name		= "pwmc_clk",
+static struct clk pwm_clk = {
+	.name		= "pwm_clk",
 	.pmc_mask	= 1 << AT91CAP9_ID_PWMC,
 	.type		= CLK_TYPE_PERIPHERAL,
 };
@@ -207,7 +207,7 @@
 	&ssc1_clk,
 	&ac97_clk,
 	&tcb_clk,
-	&pwmc_clk,
+	&pwm_clk,
 	&macb_clk,
 	&aestdes_clk,
 	&adc_clk,
diff --git a/arch/arm/mach-at91/at91cap9_devices.c b/arch/arm/mach-at91/at91cap9_devices.c
index abb4aac..5ebd427 100644
--- a/arch/arm/mach-at91/at91cap9_devices.c
+++ b/arch/arm/mach-at91/at91cap9_devices.c
@@ -719,6 +719,60 @@
 
 
 /* --------------------------------------------------------------------
+ *  PWM
+ * --------------------------------------------------------------------*/
+
+#if defined(CONFIG_ATMEL_PWM)
+static u32 pwm_mask;
+
+static struct resource pwm_resources[] = {
+	[0] = {
+		.start	= AT91CAP9_BASE_PWMC,
+		.end	= AT91CAP9_BASE_PWMC + SZ_16K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= AT91CAP9_ID_PWMC,
+		.end	= AT91CAP9_ID_PWMC,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device at91cap9_pwm0_device = {
+	.name	= "atmel_pwm",
+	.id	= -1,
+	.dev	= {
+		.platform_data		= &pwm_mask,
+	},
+	.resource	= pwm_resources,
+	.num_resources	= ARRAY_SIZE(pwm_resources),
+};
+
+void __init at91_add_device_pwm(u32 mask)
+{
+	if (mask & (1 << AT91_PWM0))
+		at91_set_A_periph(AT91_PIN_PB19, 1);	/* enable PWM0 */
+
+	if (mask & (1 << AT91_PWM1))
+		at91_set_B_periph(AT91_PIN_PB8, 1);	/* enable PWM1 */
+
+	if (mask & (1 << AT91_PWM2))
+		at91_set_B_periph(AT91_PIN_PC29, 1);	/* enable PWM2 */
+
+	if (mask & (1 << AT91_PWM3))
+		at91_set_B_periph(AT91_PIN_PA11, 1);	/* enable PWM3 */
+
+	pwm_mask = mask;
+
+	platform_device_register(&at91cap9_pwm0_device);
+}
+#else
+void __init at91_add_device_pwm(u32 mask) {}
+#endif
+
+
+
+/* --------------------------------------------------------------------
  *  AC97
  * -------------------------------------------------------------------- */
 
diff --git a/arch/arm/mach-at91/at91sam9263.c b/arch/arm/mach-at91/at91sam9263.c
index 80bfab5..ada4b67 100644
--- a/arch/arm/mach-at91/at91sam9263.c
+++ b/arch/arm/mach-at91/at91sam9263.c
@@ -129,8 +129,8 @@
 	.pmc_mask	= 1 << AT91SAM9263_ID_TCB,
 	.type		= CLK_TYPE_PERIPHERAL,
 };
-static struct clk pwmc_clk = {
-	.name		= "pwmc_clk",
+static struct clk pwm_clk = {
+	.name		= "pwm_clk",
 	.pmc_mask	= 1 << AT91SAM9263_ID_PWMC,
 	.type		= CLK_TYPE_PERIPHERAL,
 };
@@ -187,7 +187,7 @@
 	&ssc1_clk,
 	&ac97_clk,
 	&tcb_clk,
-	&pwmc_clk,
+	&pwm_clk,
 	&macb_clk,
 	&twodge_clk,
 	&udc_clk,
diff --git a/arch/arm/mach-at91/at91sam9263_devices.c b/arch/arm/mach-at91/at91sam9263_devices.c
index c93992f..8b88408 100644
--- a/arch/arm/mach-at91/at91sam9263_devices.c
+++ b/arch/arm/mach-at91/at91sam9263_devices.c
@@ -886,6 +886,59 @@
 
 
 /* --------------------------------------------------------------------
+ *  PWM
+ * --------------------------------------------------------------------*/
+
+#if defined(CONFIG_ATMEL_PWM)
+static u32 pwm_mask;
+
+static struct resource pwm_resources[] = {
+	[0] = {
+		.start	= AT91SAM9263_BASE_PWMC,
+		.end	= AT91SAM9263_BASE_PWMC + SZ_16K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= AT91SAM9263_ID_PWMC,
+		.end	= AT91SAM9263_ID_PWMC,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device at91sam9263_pwm0_device = {
+	.name	= "atmel_pwm",
+	.id	= -1,
+	.dev	= {
+		.platform_data		= &pwm_mask,
+	},
+	.resource	= pwm_resources,
+	.num_resources	= ARRAY_SIZE(pwm_resources),
+};
+
+void __init at91_add_device_pwm(u32 mask)
+{
+	if (mask & (1 << AT91_PWM0))
+		at91_set_B_periph(AT91_PIN_PB7, 1);	/* enable PWM0 */
+
+	if (mask & (1 << AT91_PWM1))
+		at91_set_B_periph(AT91_PIN_PB8, 1);	/* enable PWM1 */
+
+	if (mask & (1 << AT91_PWM2))
+		at91_set_B_periph(AT91_PIN_PC29, 1);	/* enable PWM2 */
+
+	if (mask & (1 << AT91_PWM3))
+		at91_set_B_periph(AT91_PIN_PB29, 1);	/* enable PWM3 */
+
+	pwm_mask = mask;
+
+	platform_device_register(&at91sam9263_pwm0_device);
+}
+#else
+void __init at91_add_device_pwm(u32 mask) {}
+#endif
+
+
+/* --------------------------------------------------------------------
  *  SSC -- Synchronous Serial Controller
  * -------------------------------------------------------------------- */
 
diff --git a/arch/arm/mach-at91/at91sam9rl.c b/arch/arm/mach-at91/at91sam9rl.c
index 556bddf..252e954 100644
--- a/arch/arm/mach-at91/at91sam9rl.c
+++ b/arch/arm/mach-at91/at91sam9rl.c
@@ -131,8 +131,8 @@
 	.pmc_mask	= 1 << AT91SAM9RL_ID_TC2,
 	.type		= CLK_TYPE_PERIPHERAL,
 };
-static struct clk pwmc_clk = {
-	.name		= "pwmc_clk",
+static struct clk pwm_clk = {
+	.name		= "pwm_clk",
 	.pmc_mask	= 1 << AT91SAM9RL_ID_PWMC,
 	.type		= CLK_TYPE_PERIPHERAL,
 };
@@ -180,7 +180,7 @@
 	&tc0_clk,
 	&tc1_clk,
 	&tc2_clk,
-	&pwmc_clk,
+	&pwm_clk,
 	&tsc_clk,
 	&dma_clk,
 	&udphs_clk,
diff --git a/arch/arm/mach-at91/at91sam9rl_devices.c b/arch/arm/mach-at91/at91sam9rl_devices.c
index 6208863..87deb1e 100644
--- a/arch/arm/mach-at91/at91sam9rl_devices.c
+++ b/arch/arm/mach-at91/at91sam9rl_devices.c
@@ -527,6 +527,51 @@
 
 
 /* --------------------------------------------------------------------
+ *  Touchscreen
+ * -------------------------------------------------------------------- */
+
+#if defined(CONFIG_TOUCHSCREEN_ATMEL_TSADCC) || defined(CONFIG_TOUCHSCREEN_ATMEL_TSADCC_MODULE)
+static u64 tsadcc_dmamask = DMA_BIT_MASK(32);
+
+static struct resource tsadcc_resources[] = {
+	[0] = {
+		.start	= AT91SAM9RL_BASE_TSC,
+		.end	= AT91SAM9RL_BASE_TSC + SZ_16K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= AT91SAM9RL_ID_TSC,
+		.end	= AT91SAM9RL_ID_TSC,
+		.flags	= IORESOURCE_IRQ,
+	}
+};
+
+static struct platform_device at91sam9rl_tsadcc_device = {
+	.name		= "atmel_tsadcc",
+	.id		= -1,
+	.dev		= {
+				.dma_mask		= &tsadcc_dmamask,
+				.coherent_dma_mask	= DMA_BIT_MASK(32),
+	},
+	.resource	= tsadcc_resources,
+	.num_resources	= ARRAY_SIZE(tsadcc_resources),
+};
+
+void __init at91_add_device_tsadcc(void)
+{
+	at91_set_A_periph(AT91_PIN_PA17, 0);	/* AD0_XR */
+	at91_set_A_periph(AT91_PIN_PA18, 0);	/* AD1_XL */
+	at91_set_A_periph(AT91_PIN_PA19, 0);	/* AD2_YT */
+	at91_set_A_periph(AT91_PIN_PA20, 0);	/* AD3_TB */
+
+	platform_device_register(&at91sam9rl_tsadcc_device);
+}
+#else
+void __init at91_add_device_tsadcc(void) {}
+#endif
+
+
+/* --------------------------------------------------------------------
  *  RTC
  * -------------------------------------------------------------------- */
 
@@ -592,6 +637,59 @@
 
 
 /* --------------------------------------------------------------------
+ *  PWM
+ * --------------------------------------------------------------------*/
+
+#if defined(CONFIG_ATMEL_PWM)
+static u32 pwm_mask;
+
+static struct resource pwm_resources[] = {
+	[0] = {
+		.start	= AT91SAM9RL_BASE_PWMC,
+		.end	= AT91SAM9RL_BASE_PWMC + SZ_16K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= AT91SAM9RL_ID_PWMC,
+		.end	= AT91SAM9RL_ID_PWMC,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device at91sam9rl_pwm0_device = {
+	.name	= "atmel_pwm",
+	.id	= -1,
+	.dev	= {
+		.platform_data		= &pwm_mask,
+	},
+	.resource	= pwm_resources,
+	.num_resources	= ARRAY_SIZE(pwm_resources),
+};
+
+void __init at91_add_device_pwm(u32 mask)
+{
+	if (mask & (1 << AT91_PWM0))
+		at91_set_B_periph(AT91_PIN_PB8, 1);	/* enable PWM0 */
+
+	if (mask & (1 << AT91_PWM1))
+		at91_set_B_periph(AT91_PIN_PB9, 1);	/* enable PWM1 */
+
+	if (mask & (1 << AT91_PWM2))
+		at91_set_B_periph(AT91_PIN_PD5, 1);	/* enable PWM2 */
+
+	if (mask & (1 << AT91_PWM3))
+		at91_set_B_periph(AT91_PIN_PD8, 1);	/* enable PWM3 */
+
+	pwm_mask = mask;
+
+	platform_device_register(&at91sam9rl_pwm0_device);
+}
+#else
+void __init at91_add_device_pwm(u32 mask) {}
+#endif
+
+
+/* --------------------------------------------------------------------
  *  SSC -- Synchronous Serial Controller
  * -------------------------------------------------------------------- */
 
diff --git a/arch/arm/mach-at91/at91x40_time.c b/arch/arm/mach-at91/at91x40_time.c
index 869b5e2..dfff289 100644
--- a/arch/arm/mach-at91/at91x40_time.c
+++ b/arch/arm/mach-at91/at91x40_time.c
@@ -23,8 +23,8 @@
 #include <linux/interrupt.h>
 #include <linux/irq.h>
 #include <linux/time.h>
+#include <linux/io.h>
 #include <mach/hardware.h>
-#include <asm/io.h>
 #include <asm/mach/time.h>
 #include <mach/at91_tc.h>
 
diff --git a/arch/arm/mach-at91/board-afeb-9260v1.c b/arch/arm/mach-at91/board-afeb-9260v1.c
new file mode 100644
index 0000000..9c040c7
--- /dev/null
+++ b/arch/arm/mach-at91/board-afeb-9260v1.c
@@ -0,0 +1,210 @@
+/*
+ * linux/arch/arm/mach-at91/board-afeb-9260v1.c
+ *
+ *  Copyright (C) 2005 SAN People
+ *  Copyright (C) 2006 Atmel
+ *  Copyright (C) 2008 Sergey Lapin
+ *
+ * A custom board designed as open hardware; PCBs and various information
+ * is available at http://groups.google.com/group/arm9fpga-evolution-board/
+ * Subversion repository: svn://194.85.238.22/home/users/george/svn/arm9eb
+ *
+ * This program is free software; you can redistribute it and/or 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/types.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+#include <linux/clk.h>
+#include <linux/dma-mapping.h>
+
+#include <mach/hardware.h>
+#include <asm/setup.h>
+#include <asm/mach-types.h>
+#include <asm/irq.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/irq.h>
+
+#include <mach/board.h>
+#include <mach/gpio.h>
+
+#include "generic.h"
+
+
+static void __init afeb9260_map_io(void)
+{
+	/* Initialize processor: 18.432 MHz crystal */
+	at91sam9260_initialize(18432000);
+
+	/* DGBU on ttyS0. (Rx & Tx only) */
+	at91_register_uart(0, 0, 0);
+
+	/* USART0 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
+	at91_register_uart(AT91SAM9260_ID_US0, 1,
+			     ATMEL_UART_CTS | ATMEL_UART_RTS
+			   | ATMEL_UART_DTR | ATMEL_UART_DSR
+			   | ATMEL_UART_DCD | ATMEL_UART_RI);
+
+	/* USART1 on ttyS2. (Rx, Tx, RTS, CTS) */
+	at91_register_uart(AT91SAM9260_ID_US1, 2,
+			ATMEL_UART_CTS | ATMEL_UART_RTS);
+
+	/* set serial console to ttyS0 (ie, DBGU) */
+	at91_set_serial_console(0);
+}
+
+static void __init afeb9260_init_irq(void)
+{
+	at91sam9260_init_interrupts(NULL);
+}
+
+
+/*
+ * USB Host port
+ */
+static struct at91_usbh_data __initdata afeb9260_usbh_data = {
+	.ports		= 1,
+};
+
+/*
+ * USB Device port
+ */
+static struct at91_udc_data __initdata afeb9260_udc_data = {
+	.vbus_pin	= AT91_PIN_PC5,
+	.pullup_pin	= 0,		/* pull-up driven by UDC */
+};
+
+
+
+/*
+ * SPI devices.
+ */
+static struct spi_board_info afeb9260_spi_devices[] = {
+	{	/* DataFlash chip */
+		.modalias	= "mtd_dataflash",
+		.chip_select	= 1,
+		.max_speed_hz	= 15 * 1000 * 1000,
+		.bus_num	= 0,
+	},
+};
+
+
+/*
+ * MACB Ethernet device
+ */
+static struct at91_eth_data __initdata afeb9260_macb_data = {
+	.phy_irq_pin	= AT91_PIN_PA9,
+	.is_rmii	= 0,
+};
+
+
+/*
+ * NAND flash
+ */
+static struct mtd_partition __initdata afeb9260_nand_partition[] = {
+	{
+		.name	= "bootloader",
+		.offset	= 0,
+		.size	= (640 * SZ_1K),
+	},
+	{
+		.name	= "kernel",
+		.offset	= MTDPART_OFS_NXTBLK,
+		.size	= SZ_2M,
+	},
+	{
+		.name	= "rootfs",
+		.offset	= MTDPART_OFS_NXTBLK,
+		.size	= MTDPART_SIZ_FULL,
+	},
+};
+
+static struct mtd_partition * __init nand_partitions(int size, int *num_partitions)
+{
+	*num_partitions = ARRAY_SIZE(afeb9260_nand_partition);
+	return afeb9260_nand_partition;
+}
+
+static struct atmel_nand_data __initdata afeb9260_nand_data = {
+	.ale		= 21,
+	.cle		= 22,
+	.rdy_pin	= AT91_PIN_PC13,
+	.enable_pin	= AT91_PIN_PC14,
+	.partition_info	= nand_partitions,
+	.bus_width_16	= 0,
+};
+
+
+/*
+ * MCI (SD/MMC)
+ */
+static struct at91_mmc_data __initdata afeb9260_mmc_data = {
+	.slot_b		= 1,
+	.wire4		= 1,
+};
+
+
+
+static struct i2c_board_info __initdata afeb9260_i2c_devices[] = {
+	{
+		I2C_BOARD_INFO("fm3130", 0x68),
+		I2C_BOARD_INFO("24c64", 0x50),
+	},
+};
+
+static void __init afeb9260_board_init(void)
+{
+	/* Serial */
+	at91_add_device_serial();
+	/* USB Host */
+	at91_add_device_usbh(&afeb9260_usbh_data);
+	/* USB Device */
+	at91_add_device_udc(&afeb9260_udc_data);
+	/* SPI */
+	at91_add_device_spi(afeb9260_spi_devices,
+			ARRAY_SIZE(afeb9260_spi_devices));
+	/* NAND */
+	at91_add_device_nand(&afeb9260_nand_data);
+	/* Ethernet */
+	at91_add_device_eth(&afeb9260_macb_data);
+
+	/* Standard function's pin assignments are not
+	 * appropriate for us and generic code provide
+	 * no API to configure these pins any other way */
+	at91_set_B_periph(AT91_PIN_PA10, 0);	/* ETX2 */
+	at91_set_B_periph(AT91_PIN_PA11, 0);	/* ETX3 */
+	/* MMC */
+	at91_add_device_mmc(0, &afeb9260_mmc_data);
+	/* I2C */
+	at91_add_device_i2c(afeb9260_i2c_devices,
+			ARRAY_SIZE(afeb9260_i2c_devices));
+}
+
+MACHINE_START(AFEB9260, "Custom afeb9260 board")
+	/* Maintainer: Sergey Lapin <slapin@ossfans.org> */
+	.phys_io	= AT91_BASE_SYS,
+	.io_pg_offst	= (AT91_VA_BASE_SYS >> 18) & 0xfffc,
+	.boot_params	= AT91_SDRAM_BASE + 0x100,
+	.timer		= &at91sam926x_timer,
+	.map_io		= afeb9260_map_io,
+	.init_irq	= afeb9260_init_irq,
+	.init_machine	= afeb9260_board_init,
+MACHINE_END
+
diff --git a/arch/arm/mach-at91/board-cap9adk.c b/arch/arm/mach-at91/board-cap9adk.c
index 1961995..201b893 100644
--- a/arch/arm/mach-at91/board-cap9adk.c
+++ b/arch/arm/mach-at91/board-cap9adk.c
@@ -214,7 +214,7 @@
 };
 
 #define NOR_BASE	AT91_CHIPSELECT_0
-#define NOR_SIZE	0x800000
+#define NOR_SIZE	SZ_8M
 
 static struct resource nor_flash_resources[] = {
 	{
diff --git a/arch/arm/mach-at91/board-carmeva.c b/arch/arm/mach-at91/board-carmeva.c
index afa1ff0..db1f954 100644
--- a/arch/arm/mach-at91/board-carmeva.c
+++ b/arch/arm/mach-at91/board-carmeva.c
@@ -25,7 +25,6 @@
 #include <linux/module.h>
 #include <linux/platform_device.h>
 
-#include <mach/hardware.h>
 #include <asm/setup.h>
 #include <asm/mach-types.h>
 #include <asm/irq.h>
@@ -34,6 +33,7 @@
 #include <asm/mach/map.h>
 #include <asm/mach/irq.h>
 
+#include <mach/hardware.h>
 #include <mach/board.h>
 #include <mach/gpio.h>
 
@@ -114,6 +114,30 @@
 	},
 };
 
+static struct gpio_led carmeva_leds[] = {
+	{ /* "user led 1", LED9 */
+		.name			= "led9",
+		.gpio			= AT91_PIN_PA21,
+		.active_low		= 1,
+		.default_trigger	= "heartbeat",
+	},
+	{ /* "user led 2", LED10 */
+		.name			= "led10",
+		.gpio			= AT91_PIN_PA25,
+		.active_low		= 1,
+	},
+	{ /* "user led 3", LED11 */
+		.name			= "led11",
+		.gpio			= AT91_PIN_PA26,
+		.active_low		= 1,
+	},
+	{ /* "user led 4", LED12 */
+		.name			= "led12",
+		.gpio			= AT91_PIN_PA18,
+		.active_low		= 1,
+	}
+};
+
 static void __init carmeva_board_init(void)
 {
 	/* Serial */
@@ -132,6 +156,8 @@
 //	at91_add_device_cf(&carmeva_cf_data);
 	/* MMC */
 	at91_add_device_mmc(0, &carmeva_mmc_data);
+	/* LEDs */
+	at91_gpio_leds(carmeva_leds, ARRAY_SIZE(carmeva_leds));
 }
 
 MACHINE_START(CARMEVA, "Carmeva")
diff --git a/arch/arm/mach-at91/board-csb337.c b/arch/arm/mach-at91/board-csb337.c
index cb7c9a8..fea2529 100644
--- a/arch/arm/mach-at91/board-csb337.c
+++ b/arch/arm/mach-at91/board-csb337.c
@@ -28,7 +28,6 @@
 #include <linux/input.h>
 #include <linux/gpio_keys.h>
 
-#include <mach/hardware.h>
 #include <asm/setup.h>
 #include <asm/mach-types.h>
 #include <asm/irq.h>
@@ -37,6 +36,7 @@
 #include <asm/mach/map.h>
 #include <asm/mach/irq.h>
 
+#include <mach/hardware.h>
 #include <mach/board.h>
 #include <mach/gpio.h>
 
@@ -114,7 +114,7 @@
 };
 
 #define CSB_FLASH_BASE	AT91_CHIPSELECT_0
-#define CSB_FLASH_SIZE	0x800000
+#define CSB_FLASH_SIZE	SZ_8M
 
 static struct mtd_partition csb_flash_partitions[] = {
 	{
@@ -193,11 +193,11 @@
 
 static void __init csb300_add_device_buttons(void)
 {
-	at91_set_gpio_input(AT91_PIN_PB29, 0);	/* sw0 */
+	at91_set_gpio_input(AT91_PIN_PB29, 1);	/* sw0 */
 	at91_set_deglitch(AT91_PIN_PB29, 1);
-	at91_set_gpio_input(AT91_PIN_PB28, 0);	/* sw1 */
+	at91_set_gpio_input(AT91_PIN_PB28, 1);	/* sw1 */
 	at91_set_deglitch(AT91_PIN_PB28, 1);
-	at91_set_gpio_input(AT91_PIN_PA21, 0);	/* sw2 */
+	at91_set_gpio_input(AT91_PIN_PA21, 1);	/* sw2 */
 	at91_set_deglitch(AT91_PIN_PA21, 1);
 
 	platform_device_register(&csb300_button_device);
@@ -224,7 +224,7 @@
 		.gpio			= AT91_PIN_PB0,
 		.active_low		= 1,
 		.default_trigger	= "ide-disk",
-	},
+	}
 };
 
 
diff --git a/arch/arm/mach-at91/board-csb637.c b/arch/arm/mach-at91/board-csb637.c
index 8db8bd8..cfa3f04 100644
--- a/arch/arm/mach-at91/board-csb637.c
+++ b/arch/arm/mach-at91/board-csb637.c
@@ -25,7 +25,6 @@
 #include <linux/platform_device.h>
 #include <linux/mtd/physmap.h>
 
-#include <mach/hardware.h>
 #include <asm/setup.h>
 #include <asm/mach-types.h>
 #include <asm/irq.h>
@@ -34,6 +33,7 @@
 #include <asm/mach/map.h>
 #include <asm/mach/irq.h>
 
+#include <mach/hardware.h>
 #include <mach/board.h>
 #include <mach/gpio.h>
 
@@ -72,7 +72,7 @@
 };
 
 #define CSB_FLASH_BASE	AT91_CHIPSELECT_0
-#define CSB_FLASH_SIZE	0x1000000
+#define CSB_FLASH_SIZE	SZ_16M
 
 static struct mtd_partition csb_flash_partitions[] = {
 	{
diff --git a/arch/arm/mach-at91/board-dk.c b/arch/arm/mach-at91/board-dk.c
index 43e1aa7..0fd0f5b 100644
--- a/arch/arm/mach-at91/board-dk.c
+++ b/arch/arm/mach-at91/board-dk.c
@@ -29,7 +29,6 @@
 #include <linux/spi/spi.h>
 #include <linux/mtd/physmap.h>
 
-#include <mach/hardware.h>
 #include <asm/setup.h>
 #include <asm/mach-types.h>
 #include <asm/irq.h>
@@ -38,6 +37,7 @@
 #include <asm/mach/map.h>
 #include <asm/mach/irq.h>
 
+#include <mach/hardware.h>
 #include <mach/board.h>
 #include <mach/gpio.h>
 #include <mach/at91rm9200_mc.h>
@@ -157,7 +157,7 @@
 };
 
 #define DK_FLASH_BASE	AT91_CHIPSELECT_0
-#define DK_FLASH_SIZE	0x200000
+#define DK_FLASH_SIZE	SZ_2M
 
 static struct physmap_flash_data dk_flash_data = {
 	.width		= 2,
diff --git a/arch/arm/mach-at91/board-ecbat91.c b/arch/arm/mach-at91/board-ecbat91.c
index bfeee8a2..1d69908 100644
--- a/arch/arm/mach-at91/board-ecbat91.c
+++ b/arch/arm/mach-at91/board-ecbat91.c
@@ -86,7 +86,7 @@
 	{	/* 0x8400 */
 		.name	= "Darrell-loader",
 		.offset	= 0,
-		.size	= 12* 1056,
+		.size	= 12 * 1056,
 	},
 	{
 		.name	= "U-boot",
diff --git a/arch/arm/mach-at91/board-ek.c b/arch/arm/mach-at91/board-ek.c
index 60626e7..4cdfaac 100644
--- a/arch/arm/mach-at91/board-ek.c
+++ b/arch/arm/mach-at91/board-ek.c
@@ -29,7 +29,6 @@
 #include <linux/spi/spi.h>
 #include <linux/mtd/physmap.h>
 
-#include <mach/hardware.h>
 #include <asm/setup.h>
 #include <asm/mach-types.h>
 #include <asm/irq.h>
@@ -38,6 +37,7 @@
 #include <asm/mach/map.h>
 #include <asm/mach/irq.h>
 
+#include <mach/hardware.h>
 #include <mach/board.h>
 #include <mach/gpio.h>
 #include <mach/at91rm9200_mc.h>
@@ -116,7 +116,7 @@
 };
 
 #define EK_FLASH_BASE	AT91_CHIPSELECT_0
-#define EK_FLASH_SIZE	0x200000
+#define EK_FLASH_SIZE	SZ_2M
 
 static struct physmap_flash_data ek_flash_data = {
 	.width		= 2,
diff --git a/arch/arm/mach-at91/board-picotux200.c b/arch/arm/mach-at91/board-picotux200.c
index dbc912d..859727e 100644
--- a/arch/arm/mach-at91/board-picotux200.c
+++ b/arch/arm/mach-at91/board-picotux200.c
@@ -105,7 +105,7 @@
 // };
 
 #define PICOTUX200_FLASH_BASE	AT91_CHIPSELECT_0
-#define PICOTUX200_FLASH_SIZE	0x400000
+#define PICOTUX200_FLASH_SIZE	SZ_4M
 
 static struct physmap_flash_data picotux200_flash_data = {
 	.width	= 2,
diff --git a/arch/arm/mach-at91/board-qil-a9260.c b/arch/arm/mach-at91/board-qil-a9260.c
index 4c28413..cfb4571 100644
--- a/arch/arm/mach-at91/board-qil-a9260.c
+++ b/arch/arm/mach-at91/board-qil-a9260.c
@@ -30,7 +30,6 @@
 #include <linux/input.h>
 #include <linux/clk.h>
 
-#include <mach/hardware.h>
 #include <asm/setup.h>
 #include <asm/mach-types.h>
 #include <asm/irq.h>
@@ -39,6 +38,7 @@
 #include <asm/mach/map.h>
 #include <asm/mach/irq.h>
 
+#include <mach/hardware.h>
 #include <mach/board.h>
 #include <mach/gpio.h>
 #include <mach/at91_shdwc.h>
@@ -119,18 +119,18 @@
 static struct mtd_partition __initdata ek_nand_partition[] = {
 	{
 		.name	= "Uboot & Kernel",
-		.offset	= 0x00000000,
-		.size	= 16 * 1024 * 1024,
+		.offset	= 0,
+		.size	= SZ_16M,
 	},
 	{
 		.name	= "Root FS",
-		.offset	= 0x01000000,
-		.size	= 120 * 1024 * 1024,
+		.offset	= MTDPART_OFS_NXTBLK,
+		.size	= 120 * SZ_1M,
 	},
 	{
 		.name	= "FS",
-		.offset	= 0x08800000,
-		.size	= 120 * 1024 * 1024,
+		.offset	= MTDPART_OFS_NXTBLK,
+		.size	= 120 * SZ_1M,
 	},
 };
 
diff --git a/arch/arm/mach-at91/board-sam9-l9260.c b/arch/arm/mach-at91/board-sam9-l9260.c
index e4910cb..99bb4cc 100644
--- a/arch/arm/mach-at91/board-sam9-l9260.c
+++ b/arch/arm/mach-at91/board-sam9-l9260.c
@@ -126,11 +126,11 @@
 	{
 		.name	= "Bootloader Area",
 		.offset	= 0,
-		.size	= 10 * 1024 * 1024,
+		.size	= 10 * SZ_1M,
 	},
 	{
 		.name	= "User Area",
-		.offset	= 10 * 1024 * 1024,
+		.offset	= MTDPART_OFS_NXTBLK,
 		.size	= MTDPART_SIZ_FULL,
 	},
 };
diff --git a/arch/arm/mach-at91/board-sam9260ek.c b/arch/arm/mach-at91/board-sam9260ek.c
index cb20e70..b49eb6e 100644
--- a/arch/arm/mach-at91/board-sam9260ek.c
+++ b/arch/arm/mach-at91/board-sam9260ek.c
@@ -27,8 +27,10 @@
 #include <linux/spi/spi.h>
 #include <linux/spi/at73c213.h>
 #include <linux/clk.h>
+#include <linux/i2c/at24.h>
+#include <linux/gpio_keys.h>
+#include <linux/input.h>
 
-#include <mach/hardware.h>
 #include <asm/setup.h>
 #include <asm/mach-types.h>
 #include <asm/irq.h>
@@ -37,6 +39,7 @@
 #include <asm/mach/map.h>
 #include <asm/mach/irq.h>
 
+#include <mach/hardware.h>
 #include <mach/board.h>
 #include <mach/gpio.h>
 
@@ -163,11 +166,11 @@
 	{
 		.name	= "Partition 1",
 		.offset	= 0,
-		.size	= 256 * 1024,
+		.size	= SZ_256K,
 	},
 	{
 		.name	= "Partition 2",
-		.offset	= 256 * 1024,
+		.offset	= MTDPART_OFS_NXTBLK,
 		.size	= MTDPART_SIZ_FULL,
 	},
 };
@@ -222,6 +225,73 @@
 	}
 };
 
+/*
+ * I2C devices
+ */
+static struct at24_platform_data at24c512 = {
+	.byte_len	= SZ_512K / 8,
+	.page_size	= 128,
+	.flags		= AT24_FLAG_ADDR16,
+};
+
+static struct i2c_board_info __initdata ek_i2c_devices[] = {
+	{
+		I2C_BOARD_INFO("24c512", 0x50),
+		.platform_data = &at24c512,
+	},
+	/* more devices can be added using expansion connectors */
+};
+
+
+/*
+ * GPIO Buttons
+ */
+#if defined(CONFIG_KEYBOARD_GPIO) || defined(CONFIG_KEYBOARD_GPIO_MODULE)
+static struct gpio_keys_button ek_buttons[] = {
+	{
+		.gpio		= AT91_PIN_PA30,
+		.code		= BTN_3,
+		.desc		= "Button 3",
+		.active_low	= 1,
+		.wakeup		= 1,
+	},
+	{
+		.gpio		= AT91_PIN_PA31,
+		.code		= BTN_4,
+		.desc		= "Button 4",
+		.active_low	= 1,
+		.wakeup		= 1,
+	}
+};
+
+static struct gpio_keys_platform_data ek_button_data = {
+	.buttons	= ek_buttons,
+	.nbuttons	= ARRAY_SIZE(ek_buttons),
+};
+
+static struct platform_device ek_button_device = {
+	.name		= "gpio-keys",
+	.id		= -1,
+	.num_resources	= 0,
+	.dev		= {
+		.platform_data	= &ek_button_data,
+	}
+};
+
+static void __init ek_add_device_buttons(void)
+{
+	at91_set_gpio_input(AT91_PIN_PA30, 1);	/* btn3 */
+	at91_set_deglitch(AT91_PIN_PA30, 1);
+	at91_set_gpio_input(AT91_PIN_PA31, 1);	/* btn4 */
+	at91_set_deglitch(AT91_PIN_PA31, 1);
+
+	platform_device_register(&ek_button_device);
+}
+#else
+static void __init ek_add_device_buttons(void) {}
+#endif
+
+
 static void __init ek_board_init(void)
 {
 	/* Serial */
@@ -239,12 +309,14 @@
 	/* MMC */
 	at91_add_device_mmc(0, &ek_mmc_data);
 	/* I2C */
-	at91_add_device_i2c(NULL, 0);
+	at91_add_device_i2c(ek_i2c_devices, ARRAY_SIZE(ek_i2c_devices));
 	/* SSC (to AT73C213) */
 	at73c213_set_clk(&at73c213_data);
 	at91_add_device_ssc(AT91SAM9260_ID_SSC, ATMEL_SSC_TX);
 	/* LEDs */
 	at91_gpio_leds(ek_leds, ARRAY_SIZE(ek_leds));
+	/* Push Buttons */
+	ek_add_device_buttons();
 }
 
 MACHINE_START(AT91SAM9260EK, "Atmel AT91SAM9260-EK")
diff --git a/arch/arm/mach-at91/board-sam9261ek.c b/arch/arm/mach-at91/board-sam9261ek.c
index 1a9963b8..4977409 100644
--- a/arch/arm/mach-at91/board-sam9261ek.c
+++ b/arch/arm/mach-at91/board-sam9261ek.c
@@ -35,7 +35,6 @@
 
 #include <video/atmel_lcdc.h>
 
-#include <mach/hardware.h>
 #include <asm/setup.h>
 #include <asm/mach-types.h>
 #include <asm/irq.h>
@@ -44,6 +43,7 @@
 #include <asm/mach/map.h>
 #include <asm/mach/irq.h>
 
+#include <mach/hardware.h>
 #include <mach/board.h>
 #include <mach/gpio.h>
 #include <mach/at91sam9_smc.h>
@@ -168,11 +168,11 @@
 	{
 		.name	= "Partition 1",
 		.offset	= 0,
-		.size	= 256 * 1024,
+		.size	= SZ_256K,
 	},
 	{
 		.name	= "Partition 2",
-		.offset	= 256 * 1024 ,
+		.offset	= MTDPART_OFS_NXTBLK,
 		.size	= MTDPART_SIZ_FULL,
 	},
 };
@@ -435,24 +435,28 @@
 		.code		= BTN_0,
 		.desc		= "Button 0",
 		.active_low	= 1,
+		.wakeup		= 1,
 	},
 	{
 		.gpio		= AT91_PIN_PA26,
 		.code		= BTN_1,
 		.desc		= "Button 1",
 		.active_low	= 1,
+		.wakeup		= 1,
 	},
 	{
 		.gpio		= AT91_PIN_PA25,
 		.code		= BTN_2,
 		.desc		= "Button 2",
 		.active_low	= 1,
+		.wakeup		= 1,
 	},
 	{
 		.gpio		= AT91_PIN_PA24,
 		.code		= BTN_3,
 		.desc		= "Button 3",
 		.active_low	= 1,
+		.wakeup		= 1,
 	}
 };
 
@@ -472,13 +476,13 @@
 
 static void __init ek_add_device_buttons(void)
 {
-	at91_set_gpio_input(AT91_PIN_PA27, 0);	/* btn0 */
+	at91_set_gpio_input(AT91_PIN_PA27, 1);	/* btn0 */
 	at91_set_deglitch(AT91_PIN_PA27, 1);
-	at91_set_gpio_input(AT91_PIN_PA26, 0);	/* btn1 */
+	at91_set_gpio_input(AT91_PIN_PA26, 1);	/* btn1 */
 	at91_set_deglitch(AT91_PIN_PA26, 1);
-	at91_set_gpio_input(AT91_PIN_PA25, 0);	/* btn2 */
+	at91_set_gpio_input(AT91_PIN_PA25, 1);	/* btn2 */
 	at91_set_deglitch(AT91_PIN_PA25, 1);
-	at91_set_gpio_input(AT91_PIN_PA24, 0);	/* btn3 */
+	at91_set_gpio_input(AT91_PIN_PA24, 1);	/* btn3 */
 	at91_set_deglitch(AT91_PIN_PA24, 1);
 
 	platform_device_register(&ek_button_device);
diff --git a/arch/arm/mach-at91/board-sam9263ek.c b/arch/arm/mach-at91/board-sam9263ek.c
index b1d1196..8354015 100644
--- a/arch/arm/mach-at91/board-sam9263ek.c
+++ b/arch/arm/mach-at91/board-sam9263ek.c
@@ -26,13 +26,14 @@
 #include <linux/platform_device.h>
 #include <linux/spi/spi.h>
 #include <linux/spi/ads7846.h>
+#include <linux/i2c/at24.h>
 #include <linux/fb.h>
 #include <linux/gpio_keys.h>
 #include <linux/input.h>
+#include <linux/leds.h>
 
 #include <video/atmel_lcdc.h>
 
-#include <mach/hardware.h>
 #include <asm/setup.h>
 #include <asm/mach-types.h>
 #include <asm/irq.h>
@@ -41,6 +42,7 @@
 #include <asm/mach/map.h>
 #include <asm/mach/irq.h>
 
+#include <mach/hardware.h>
 #include <mach/board.h>
 #include <mach/gpio.h>
 #include <mach/at91sam9_smc.h>
@@ -172,11 +174,11 @@
 	{
 		.name	= "Partition 1",
 		.offset	= 0,
-		.size	= 64 * 1024 * 1024,
+		.size	= SZ_64M,
 	},
 	{
 		.name	= "Partition 2",
-		.offset	= 64 * 1024 * 1024,
+		.offset	= MTDPART_OFS_NXTBLK,
 		.size	= MTDPART_SIZ_FULL,
 	},
 };
@@ -203,12 +205,30 @@
 
 
 /*
+ * I2C devices
+ */
+static struct at24_platform_data at24c512 = {
+	.byte_len	= SZ_512K / 8,
+	.page_size	= 128,
+	.flags		= AT24_FLAG_ADDR16,
+};
+
+
+static struct i2c_board_info __initdata ek_i2c_devices[] = {
+	{
+		I2C_BOARD_INFO("24c512", 0x50),
+		.platform_data = &at24c512,
+	},
+	/* more devices can be added using expansion connectors */
+};
+
+/*
  * LCD Controller
  */
 #if defined(CONFIG_FB_ATMEL) || defined(CONFIG_FB_ATMEL_MODULE)
 static struct fb_videomode at91_tft_vga_modes[] = {
 	{
-	        .name           = "TX09D50VM1CCA @ 60",
+		.name		= "TX09D50VM1CCA @ 60",
 		.refresh	= 60,
 		.xres		= 240,		.yres		= 320,
 		.pixclock	= KHZ2PICOS(4965),
@@ -224,7 +244,7 @@
 
 static struct fb_monspecs at91fb_default_monspecs = {
 	.manufacturer	= "HIT",
-	.monitor        = "TX09D70VM1CCA",
+	.monitor	= "TX09D70VM1CCA",
 
 	.modedb		= at91_tft_vga_modes,
 	.modedb_len	= ARRAY_SIZE(at91_tft_vga_modes),
@@ -235,7 +255,7 @@
 };
 
 #define AT91SAM9263_DEFAULT_LCDCON2 	(ATMEL_LCDC_MEMOR_LITTLE \
-					| ATMEL_LCDC_DISTYPE_TFT    \
+					| ATMEL_LCDC_DISTYPE_TFT \
 					| ATMEL_LCDC_CLKMOD_ALWAYSACTIVE)
 
 static void at91_lcdc_power_control(int on)
@@ -277,7 +297,7 @@
 		.active_low	= 1,
 		.desc		= "right_click",
 		.wakeup		= 1,
-	},
+	}
 };
 
 static struct gpio_keys_platform_data ek_button_data = {
@@ -296,9 +316,9 @@
 
 static void __init ek_add_device_buttons(void)
 {
-	at91_set_GPIO_periph(AT91_PIN_PC5, 0);	/* left button */
+	at91_set_GPIO_periph(AT91_PIN_PC5, 1);	/* left button */
 	at91_set_deglitch(AT91_PIN_PC5, 1);
-	at91_set_GPIO_periph(AT91_PIN_PC4, 0);	/* right button */
+	at91_set_GPIO_periph(AT91_PIN_PC4, 1);	/* right button */
 	at91_set_deglitch(AT91_PIN_PC4, 1);
 
 	platform_device_register(&ek_button_device);
@@ -320,25 +340,32 @@
  * LEDs ... these could all be PWM-driven, for variable brightness
  */
 static struct gpio_led ek_leds[] = {
-	{	/* "left" led, green, userled1, pwm1 */
-		.name			= "ds1",
-		.gpio			= AT91_PIN_PB8,
-		.active_low		= 1,
-		.default_trigger	= "mmc0",
-	},
-	{	/* "right" led, green, userled2, pwm2 */
+	{	/* "right" led, green, userled2 (could be driven by pwm2) */
 		.name			= "ds2",
 		.gpio			= AT91_PIN_PC29,
 		.active_low		= 1,
 		.default_trigger	= "nand-disk",
 	},
-	{	/* "power" led, yellow, pwm0 */
+	{	/* "power" led, yellow (could be driven by pwm0) */
 		.name			= "ds3",
 		.gpio			= AT91_PIN_PB7,
 		.default_trigger	= "heartbeat",
 	}
 };
 
+/*
+ * PWM Leds
+ */
+static struct gpio_led ek_pwm_led[] = {
+	/* For now only DS1 is PWM-driven (by pwm1) */
+	{
+		.name			= "ds1",
+		.gpio			= 1,	/* is PWM channel number */
+		.active_low		= 1,
+		.default_trigger	= "none",
+	}
+};
+
 
 static void __init ek_board_init(void)
 {
@@ -360,7 +387,7 @@
 	/* NAND */
 	at91_add_device_nand(&ek_nand_data);
 	/* I2C */
-	at91_add_device_i2c(NULL, 0);
+	at91_add_device_i2c(ek_i2c_devices, ARRAY_SIZE(ek_i2c_devices));
 	/* LCD Controller */
 	at91_add_device_lcdc(&ek_lcdc_data);
 	/* Push Buttons */
@@ -369,6 +396,7 @@
 	at91_add_device_ac97(&ek_ac97_data);
 	/* LEDs */
 	at91_gpio_leds(ek_leds, ARRAY_SIZE(ek_leds));
+	at91_pwm_leds(ek_pwm_led, ARRAY_SIZE(ek_pwm_led));
 }
 
 MACHINE_START(AT91SAM9263EK, "Atmel AT91SAM9263-EK")
diff --git a/arch/arm/mach-at91/board-sam9g20ek.c b/arch/arm/mach-at91/board-sam9g20ek.c
index d4eba5c..b588ead 100644
--- a/arch/arm/mach-at91/board-sam9g20ek.c
+++ b/arch/arm/mach-at91/board-sam9g20ek.c
@@ -122,16 +122,16 @@
 	{
 		.name   = "Bootstrap",
 		.offset = 0,
-		.size   = 4 * 1024 * 1024,
+		.size   = 4 * SZ_1M,
 	},
 	{
 		.name	= "Partition 1",
-		.offset	= 4 * 1024 * 1024,
-		.size	= 60 * 1024 * 1024,
+		.offset	= MTDPART_OFS_NXTBLK,
+		.size	= 60 * SZ_1M,
 	},
 	{
 		.name	= "Partition 2",
-		.offset	= 64 * 1024 * 1024,
+		.offset	= MTDPART_OFS_NXTBLK,
 		.size	= MTDPART_SIZ_FULL,
 	},
 };
diff --git a/arch/arm/mach-at91/board-sam9rlek.c b/arch/arm/mach-at91/board-sam9rlek.c
index c6dce49..2708518 100644
--- a/arch/arm/mach-at91/board-sam9rlek.c
+++ b/arch/arm/mach-at91/board-sam9rlek.c
@@ -18,7 +18,6 @@
 
 #include <video/atmel_lcdc.h>
 
-#include <mach/hardware.h>
 #include <asm/setup.h>
 #include <asm/mach-types.h>
 #include <asm/irq.h>
@@ -27,6 +26,7 @@
 #include <asm/mach/map.h>
 #include <asm/mach/irq.h>
 
+#include <mach/hardware.h>
 #include <mach/board.h>
 #include <mach/gpio.h>
 #include <mach/at91sam9_smc.h>
@@ -81,11 +81,11 @@
 	{
 		.name	= "Partition 1",
 		.offset	= 0,
-		.size	= 256 * 1024,
+		.size	= SZ_256K,
 	},
 	{
 		.name	= "Partition 2",
-		.offset	= 256 * 1024 ,
+		.offset	= MTDPART_OFS_NXTBLK,
 		.size	= MTDPART_SIZ_FULL,
 	},
 };
@@ -195,6 +195,8 @@
 	at91_add_device_mmc(0, &ek_mmc_data);
 	/* LCD Controller */
 	at91_add_device_lcdc(&ek_lcdc_data);
+	/* Touch Screen Controller */
+	at91_add_device_tsadcc();
 }
 
 MACHINE_START(AT91SAM9RLEK, "Atmel AT91SAM9RL-EK")
diff --git a/arch/arm/mach-at91/board-usb-a9260.c b/arch/arm/mach-at91/board-usb-a9260.c
index f9d0b65..7c35035 100644
--- a/arch/arm/mach-at91/board-usb-a9260.c
+++ b/arch/arm/mach-at91/board-usb-a9260.c
@@ -30,7 +30,6 @@
 #include <linux/input.h>
 #include <linux/clk.h>
 
-#include <mach/hardware.h>
 #include <asm/setup.h>
 #include <asm/mach-types.h>
 #include <asm/irq.h>
@@ -39,6 +38,7 @@
 #include <asm/mach/map.h>
 #include <asm/mach/irq.h>
 
+#include <mach/hardware.h>
 #include <mach/board.h>
 #include <mach/gpio.h>
 #include <mach/at91_shdwc.h>
@@ -93,18 +93,18 @@
 static struct mtd_partition __initdata ek_nand_partition[] = {
 	{
 		.name	= "Uboot & Kernel",
-		.offset	= 0x00000000,
-		.size	= 16 * 1024 * 1024,
+		.offset	= 0,
+		.size	= SZ_16M,
 	},
 	{
 		.name	= "Root FS",
-		.offset	= 0x01000000,
-		.size	= 120 * 1024 * 1024,
+		.offset	= MTDPART_OFS_NXTBLK,
+		.size	= 120 * SZ_1M,
 	},
 	{
 		.name	= "FS",
-		.offset	= 0x08800000,
-		.size	= 120 * 1024 * 1024,
+		.offset	= MTDPART_OFS_NXTBLK,
+		.size	= 120 * SZ_1M,
 	}
 };
 
diff --git a/arch/arm/mach-at91/board-usb-a9263.c b/arch/arm/mach-at91/board-usb-a9263.c
index 673e5c2..391b566 100644
--- a/arch/arm/mach-at91/board-usb-a9263.c
+++ b/arch/arm/mach-at91/board-usb-a9263.c
@@ -29,7 +29,6 @@
 #include <linux/gpio_keys.h>
 #include <linux/input.h>
 
-#include <mach/hardware.h>
 #include <asm/setup.h>
 #include <asm/mach-types.h>
 #include <asm/irq.h>
@@ -38,6 +37,7 @@
 #include <asm/mach/map.h>
 #include <asm/mach/irq.h>
 
+#include <mach/hardware.h>
 #include <mach/board.h>
 #include <mach/gpio.h>
 #include <mach/at91_shdwc.h>
@@ -106,18 +106,18 @@
 static struct mtd_partition __initdata ek_nand_partition[] = {
 	{
 		.name	= "Linux Kernel",
-		.offset	= 0x00000000,
-		.size	= 16 * 1024 * 1024,
+		.offset	= 0,
+		.size	= SZ_16M,
 	},
 	{
 		.name	= "Root FS",
-		.offset	= 0x01000000,
-		.size	= 120 * 1024 * 1024,
+		.offset	= MTDPART_OFS_NXTBLK,
+		.size	= 120 * SZ_1M,
 	},
 	{
 		.name	= "FS",
-		.offset	= 0x08800000,
-		.size	= 120 * 1024 * 1024,
+		.offset	= MTDPART_OFS_NXTBLK,
+		.size	= 120 * SZ_1M,
 	}
 };
 
diff --git a/arch/arm/mach-at91/board-yl-9200.c b/arch/arm/mach-at91/board-yl-9200.c
index 36b380a..e22bf05 100644
--- a/arch/arm/mach-at91/board-yl-9200.c
+++ b/arch/arm/mach-at91/board-yl-9200.c
@@ -33,7 +33,6 @@
 #include <linux/gpio_keys.h>
 #include <linux/input.h>
 
-#include <mach/hardware.h>
 #include <asm/setup.h>
 #include <asm/mach-types.h>
 #include <asm/irq.h>
@@ -42,6 +41,7 @@
 #include <asm/mach/map.h>
 #include <asm/mach/irq.h>
 
+#include <mach/hardware.h>
 #include <mach/board.h>
 #include <mach/gpio.h>
 #include <mach/at91rm9200_mc.h>
@@ -150,27 +150,27 @@
 	{
 		.name	= "AT91 NAND partition 1, boot",
 		.offset	= 0,
-		.size	= 1 * SZ_256K
+		.size	= SZ_256K
 	},
 	{
 		.name	= "AT91 NAND partition 2, kernel",
-		.offset	= 1 * SZ_256K,
-		.size	= 2 * SZ_1M - 1 * SZ_256K
+		.offset	= MTDPART_OFS_NXTBLK,
+		.size	= (2 * SZ_1M) - SZ_256K
 	},
 	{
 		.name	= "AT91 NAND partition 3, filesystem",
-		.offset	= 2 * SZ_1M,
+		.offset	= MTDPART_OFS_NXTBLK,
 		.size	= 14 * SZ_1M
 	},
 	{
 		.name	= "AT91 NAND partition 4, storage",
-		.offset	= 16 * SZ_1M,
-		.size	= 16 * SZ_1M
+		.offset	= MTDPART_OFS_NXTBLK,
+		.size	= SZ_16M
 	},
 	{
 		.name	= "AT91 NAND partition 5, ext-fs",
-		.offset	= 32 * SZ_1M,
-		.size	= 32 * SZ_1M
+		.offset	= MTDPART_OFS_NXTBLK,
+		.size	= SZ_32M
 	}
 };
 
@@ -193,24 +193,24 @@
  * NOR Flash
  */
 #define YL9200_FLASH_BASE	AT91_CHIPSELECT_0
-#define YL9200_FLASH_SIZE	0x1000000
+#define YL9200_FLASH_SIZE	SZ_16M
 
 static struct mtd_partition yl9200_flash_partitions[] = {
 	{
 		.name		= "Bootloader",
-		.size		= 0x00040000,
 		.offset		= 0,
+		.size		= SZ_256K,
 		.mask_flags	= MTD_WRITEABLE,	/* force read-only */
 	},
 	{
 		.name		= "Kernel",
-		.size		= 0x001C0000,
-		.offset		= 0x00040000,
+		.offset		= MTDPART_OFS_NXTBLK,
+		.size		= (2 * SZ_1M) - SZ_256K
 	},
 	{
 		.name		= "Filesystem",
-		.size		= MTDPART_SIZ_FULL,
-		.offset		= 0x00200000
+		.offset		= MTDPART_OFS_NXTBLK,
+		.size		= MTDPART_SIZ_FULL
 	}
 };
 
@@ -390,10 +390,6 @@
 #if defined(CONFIG_FB_S1D135XX) || defined(CONFIG_FB_S1D13XXX_MODULE)
 #include <video/s1d13xxxfb.h>
 
-#define AT91_FB_REG_BASE	0x80000000L
-#define AT91_FB_REG_SIZE	0x200
-#define AT91_FB_VMEM_BASE	0x80200000L
-#define AT91_FB_VMEM_SIZE	0x200000L
 
 static void __init yl9200_init_video(void)
 {
@@ -516,29 +512,33 @@
 	{S1DREG_COM_DISP_MODE,		0x01},	/* Display Mode Register, LCD only*/
 };
 
-static u64 s1dfb_dmamask = DMA_BIT_MASK(32);
-
 static struct s1d13xxxfb_pdata yl9200_s1dfb_pdata = {
 	.initregs		= yl9200_s1dfb_initregs,
 	.initregssize		= ARRAY_SIZE(yl9200_s1dfb_initregs),
 	.platform_init_video	= yl9200_init_video,
 };
 
+#define YL9200_FB_REG_BASE	AT91_CHIPSELECT_7
+#define YL9200_FB_VMEM_BASE	YL9200_FB_REG_BASE + SZ_2M
+#define YL9200_FB_VMEM_SIZE	SZ_2M
+
 static struct resource yl9200_s1dfb_resource[] = {
 	[0] = {	/* video mem */
 		.name	= "s1d13xxxfb memory",
-		.start	= AT91_FB_VMEM_BASE,
-		.end	= AT91_FB_VMEM_BASE + AT91_FB_VMEM_SIZE -1,
+		.start	= YL9200_FB_VMEM_BASE,
+		.end	= YL9200_FB_VMEM_BASE + YL9200_FB_VMEM_SIZE -1,
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {	/* video registers */
 		.name	= "s1d13xxxfb registers",
-		.start	= AT91_FB_REG_BASE,
-		.end	= AT91_FB_REG_BASE + AT91_FB_REG_SIZE -1,
+		.start	= YL9200_FB_REG_BASE,
+		.end	= YL9200_FB_REG_BASE + SZ_512 -1,
 		.flags	= IORESOURCE_MEM,
 	},
 };
 
+static u64 s1dfb_dmamask = DMA_BIT_MASK(32);
+
 static struct platform_device yl9200_s1dfb_device = {
 	.name		= "s1d13806fb",
 	.id		= -1,
diff --git a/arch/arm/mach-at91/clock.c b/arch/arm/mach-at91/clock.c
index f5c2847..e434510 100644
--- a/arch/arm/mach-at91/clock.c
+++ b/arch/arm/mach-at91/clock.c
@@ -22,8 +22,7 @@
 #include <linux/spinlock.h>
 #include <linux/delay.h>
 #include <linux/clk.h>
-
-#include <asm/io.h>
+#include <linux/io.h>
 
 #include <mach/hardware.h>
 #include <mach/at91_pmc.h>
diff --git a/arch/arm/mach-at91/gpio.c b/arch/arm/mach-at91/gpio.c
index 8392d5b..7e5ebb5 100644
--- a/arch/arm/mach-at91/gpio.c
+++ b/arch/arm/mach-at91/gpio.c
@@ -18,8 +18,8 @@
 #include <linux/kernel.h>
 #include <linux/list.h>
 #include <linux/module.h>
+#include <linux/io.h>
 
-#include <asm/io.h>
 #include <mach/hardware.h>
 #include <mach/at91_pio.h>
 #include <mach/gpio.h>
@@ -404,7 +404,6 @@
 		}
 
 		pin = bank->chipbase;
-		gpio = &irq_desc[pin];
 
 		while (isr) {
 			if (isr & 1) {
@@ -417,7 +416,7 @@
 					gpio_irq_mask(pin);
 				}
 				else
-					desc_handle_irq(pin, gpio);
+					generic_handle_irq(pin);
 			}
 			pin++;
 			gpio++;
diff --git a/arch/arm/mach-at91/include/mach/at91_pit.h b/arch/arm/mach-at91/include/mach/at91_pit.h
index 0448ac3..974d0bd 100644
--- a/arch/arm/mach-at91/include/mach/at91_pit.h
+++ b/arch/arm/mach-at91/include/mach/at91_pit.h
@@ -1,6 +1,9 @@
 /*
  * arch/arm/mach-at91/include/mach/at91_pit.h
  *
+ * Copyright (C) 2007 Andrew Victor
+ * Copyright (C) 2007 Atmel Corporation.
+ *
  * Periodic Interval Timer (PIT) - System peripherals regsters.
  * Based on AT91SAM9261 datasheet revision D.
  *
diff --git a/arch/arm/mach-at91/include/mach/at91_rstc.h b/arch/arm/mach-at91/include/mach/at91_rstc.h
index 7cd1b39..cbd2bf0 100644
--- a/arch/arm/mach-at91/include/mach/at91_rstc.h
+++ b/arch/arm/mach-at91/include/mach/at91_rstc.h
@@ -1,6 +1,9 @@
 /*
  * arch/arm/mach-at91/include/mach/at91_rstc.h
  *
+ * Copyright (C) 2007 Andrew Victor
+ * Copyright (C) 2007 Atmel Corporation.
+ *
  * Reset Controller (RSTC) - System peripherals regsters.
  * Based on AT91SAM9261 datasheet revision D.
  *
diff --git a/arch/arm/mach-at91/include/mach/at91_rtt.h b/arch/arm/mach-at91/include/mach/at91_rtt.h
index 71782e5..7ec75de 100644
--- a/arch/arm/mach-at91/include/mach/at91_rtt.h
+++ b/arch/arm/mach-at91/include/mach/at91_rtt.h
@@ -1,6 +1,9 @@
 /*
  * arch/arm/mach-at91/include/mach/at91_rtt.h
  *
+ * Copyright (C) 2007 Andrew Victor
+ * Copyright (C) 2007 Atmel Corporation.
+ *
  * Real-time Timer (RTT) - System peripherals regsters.
  * Based on AT91SAM9261 datasheet revision D.
  *
diff --git a/arch/arm/mach-at91/include/mach/at91_shdwc.h b/arch/arm/mach-at91/include/mach/at91_shdwc.h
index 60be5ae..c4ce07e 100644
--- a/arch/arm/mach-at91/include/mach/at91_shdwc.h
+++ b/arch/arm/mach-at91/include/mach/at91_shdwc.h
@@ -1,6 +1,9 @@
 /*
  * arch/arm/mach-at91/include/mach/at91_shdwc.h
  *
+ * Copyright (C) 2007 Andrew Victor
+ * Copyright (C) 2007 Atmel Corporation.
+ *
  * Shutdown Controller (SHDWC) - System peripherals regsters.
  * Based on AT91SAM9261 datasheet revision D.
  *
diff --git a/arch/arm/mach-at91/include/mach/at91_wdt.h b/arch/arm/mach-at91/include/mach/at91_wdt.h
index 973b452..fecc2e9 100644
--- a/arch/arm/mach-at91/include/mach/at91_wdt.h
+++ b/arch/arm/mach-at91/include/mach/at91_wdt.h
@@ -1,6 +1,9 @@
 /*
  * arch/arm/mach-at91/include/mach/at91_wdt.h
  *
+ * Copyright (C) 2007 Andrew Victor
+ * Copyright (C) 2007 Atmel Corporation.
+ *
  * Watchdog Timer (WDT) - System peripherals regsters.
  * Based on AT91SAM9261 datasheet revision D.
  *
diff --git a/arch/arm/mach-at91/include/mach/at91cap9_ddrsdr.h b/arch/arm/mach-at91/include/mach/at91cap9_ddrsdr.h
index bca878f..1499b1c 100644
--- a/arch/arm/mach-at91/include/mach/at91cap9_ddrsdr.h
+++ b/arch/arm/mach-at91/include/mach/at91cap9_ddrsdr.h
@@ -1,6 +1,8 @@
 /*
  * arch/arm/mach-at91/include/mach/at91cap9_ddrsdr.h
  *
+ *  (C) 2008 Andrew Victor
+ *
  * DDR/SDR Controller (DDRSDRC) - System peripherals registers.
  * Based on AT91CAP9 datasheet revision B.
  *
diff --git a/arch/arm/mach-at91/include/mach/at91sam9260_matrix.h b/arch/arm/mach-at91/include/mach/at91sam9260_matrix.h
index f027de5..020f02e 100644
--- a/arch/arm/mach-at91/include/mach/at91sam9260_matrix.h
+++ b/arch/arm/mach-at91/include/mach/at91sam9260_matrix.h
@@ -1,6 +1,8 @@
 /*
  * arch/arm/mach-at91/include/mach/at91sam9260_matrix.h
  *
+ *  Copyright (C) 2007 Atmel Corporation.
+ *
  * Memory Controllers (MATRIX, EBI) - System peripherals registers.
  * Based on AT91SAM9260 datasheet revision B.
  *
diff --git a/arch/arm/mach-at91/include/mach/at91sam9261_matrix.h b/arch/arm/mach-at91/include/mach/at91sam9261_matrix.h
index db62b1f1..69c6501 100644
--- a/arch/arm/mach-at91/include/mach/at91sam9261_matrix.h
+++ b/arch/arm/mach-at91/include/mach/at91sam9261_matrix.h
@@ -1,6 +1,8 @@
 /*
  * arch/arm/mach-at91/include/mach/at91sam9261_matrix.h
  *
+ *  Copyright (C) 2007 Atmel Corporation.
+ *
  * Memory Controllers (MATRIX, EBI) - System peripherals registers.
  * Based on AT91SAM9261 datasheet revision D.
  *
diff --git a/arch/arm/mach-at91/include/mach/at91sam9_sdramc.h b/arch/arm/mach-at91/include/mach/at91sam9_sdramc.h
index 1921181..b726038 100644
--- a/arch/arm/mach-at91/include/mach/at91sam9_sdramc.h
+++ b/arch/arm/mach-at91/include/mach/at91sam9_sdramc.h
@@ -1,6 +1,9 @@
 /*
  * arch/arm/mach-at91/include/mach/at91sam9_sdramc.h
  *
+ * Copyright (C) 2007 Andrew Victor
+ * Copyright (C) 2007 Atmel Corporation.
+ *
  * SDRAM Controllers (SDRAMC) - System peripherals registers.
  * Based on AT91SAM9261 datasheet revision D.
  *
diff --git a/arch/arm/mach-at91/include/mach/at91sam9_smc.h b/arch/arm/mach-at91/include/mach/at91sam9_smc.h
index ec6ad13..57de620 100644
--- a/arch/arm/mach-at91/include/mach/at91sam9_smc.h
+++ b/arch/arm/mach-at91/include/mach/at91sam9_smc.h
@@ -1,6 +1,9 @@
 /*
  * arch/arm/mach-at91/include/mach/at91sam9_smc.h
  *
+ * Copyright (C) 2007 Andrew Victor
+ * Copyright (C) 2007 Atmel Corporation.
+ *
  * Static Memory Controllers (SMC) - System peripherals registers.
  * Based on AT91SAM9261 datasheet revision D.
  *
diff --git a/arch/arm/mach-at91/include/mach/board.h b/arch/arm/mach-at91/include/mach/board.h
index acd60f2..fb51f0e 100644
--- a/arch/arm/mach-at91/include/mach/board.h
+++ b/arch/arm/mach-at91/include/mach/board.h
@@ -133,6 +133,16 @@
 extern void __init at91_add_device_serial(void);
 
 /*
+ * PWM
+ */
+#define AT91_PWM0	0
+#define AT91_PWM1	1
+#define AT91_PWM2	2
+#define AT91_PWM3	3
+
+extern void __init at91_add_device_pwm(u32 mask);
+
+/*
  * SSC -- accessed through ssc_request(id).  Drivers don't bind to SSC
  * platform devices.  Their SSC ID is part of their configuration data,
  * along with information about which SSC signals they should use.
@@ -162,9 +172,13 @@
  /* ISI */
 extern void __init at91_add_device_isi(void);
 
+ /* Touchscreen Controller */
+extern void __init at91_add_device_tsadcc(void);
+
  /* LEDs */
 extern void __init at91_init_leds(u8 cpu_led, u8 timer_led);
 extern void __init at91_gpio_leds(struct gpio_led *leds, int nr);
+extern void __init at91_pwm_leds(struct gpio_led *leds, int nr);
 
 /* FIXME: this needs a better location, but gets stuff building again */
 extern int at91_suspend_entering_slow_clock(void);
diff --git a/arch/arm/mach-at91/include/mach/irqs.h b/arch/arm/mach-at91/include/mach/irqs.h
index bda29ccb..36bd55f 100644
--- a/arch/arm/mach-at91/include/mach/irqs.h
+++ b/arch/arm/mach-at91/include/mach/irqs.h
@@ -21,7 +21,7 @@
 #ifndef __ASM_ARCH_IRQS_H
 #define __ASM_ARCH_IRQS_H
 
-#include <asm/io.h>
+#include <linux/io.h>
 #include <mach/at91_aic.h>
 
 #define NR_AIC_IRQS 32
diff --git a/arch/arm/mach-at91/include/mach/uncompress.h b/arch/arm/mach-at91/include/mach/uncompress.h
index 0410d54..18bdcde 100644
--- a/arch/arm/mach-at91/include/mach/uncompress.h
+++ b/arch/arm/mach-at91/include/mach/uncompress.h
@@ -21,7 +21,7 @@
 #ifndef __ASM_ARCH_UNCOMPRESS_H
 #define __ASM_ARCH_UNCOMPRESS_H
 
-#include <asm/io.h>
+#include <linux/io.h>
 #include <linux/atmel_serial.h>
 
 #if defined(CONFIG_AT91_EARLY_DBGU)
diff --git a/arch/arm/mach-at91/leds.c b/arch/arm/mach-at91/leds.c
index fec03c5..0415a839 100644
--- a/arch/arm/mach-at91/leds.c
+++ b/arch/arm/mach-at91/leds.c
@@ -12,6 +12,7 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/init.h>
+#include <linux/platform_device.h>
 
 #include <mach/board.h>
 #include <mach/gpio.h>
@@ -21,15 +22,13 @@
 
 #if defined(CONFIG_NEW_LEDS)
 
-#include <linux/platform_device.h>
-
 /*
  * New cross-platform LED support.
  */
 
 static struct gpio_led_platform_data led_data;
 
-static struct platform_device at91_leds = {
+static struct platform_device at91_gpio_leds_device = {
 	.name			= "leds-gpio",
 	.id			= -1,
 	.dev.platform_data	= &led_data,
@@ -47,7 +46,7 @@
 
 	led_data.leds = leds;
 	led_data.num_leds = nr;
-	platform_device_register(&at91_leds);
+	platform_device_register(&at91_gpio_leds_device);
 }
 
 #else
@@ -57,6 +56,44 @@
 
 /* ------------------------------------------------------------------------- */
 
+#if defined (CONFIG_LEDS_ATMEL_PWM)
+
+/*
+ * PWM Leds
+ */
+
+static struct gpio_led_platform_data pwm_led_data;
+
+static struct platform_device at91_pwm_leds_device = {
+	.name			= "leds-atmel-pwm",
+	.id			= -1,
+	.dev.platform_data	= &pwm_led_data,
+};
+
+void __init at91_pwm_leds(struct gpio_led *leds, int nr)
+{
+	int i;
+	u32 pwm_mask = 0;
+
+	if (!nr)
+		return;
+
+	for (i = 0; i < nr; i++)
+		pwm_mask |= (1 << leds[i].gpio);
+
+	pwm_led_data.leds = leds;
+	pwm_led_data.num_leds = nr;
+
+	at91_add_device_pwm(pwm_mask);
+	platform_device_register(&at91_pwm_leds_device);
+}
+#else
+void __init at91_pwm_leds(struct gpio_led *leds, int nr){}
+#endif
+
+
+/* ------------------------------------------------------------------------- */
+
 #if defined(CONFIG_LEDS)
 
 #include <asm/leds.h>
diff --git a/arch/arm/mach-at91/pm.c b/arch/arm/mach-at91/pm.c
index ec2fe4c..9bb4f04 100644
--- a/arch/arm/mach-at91/pm.c
+++ b/arch/arm/mach-at91/pm.c
@@ -17,8 +17,8 @@
 #include <linux/sysfs.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
+#include <linux/io.h>
 
-#include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/atomic.h>
 #include <asm/mach/time.h>
diff --git a/arch/arm/mach-at91/pm_slowclock.S b/arch/arm/mach-at91/pm_slowclock.S
new file mode 100644
index 0000000..987fab3
--- /dev/null
+++ b/arch/arm/mach-at91/pm_slowclock.S
@@ -0,0 +1,283 @@
+/*
+ * arch/arm/mach-at91/pm_slow_clock.S
+ *
+ *  Copyright (C) 2006 Savin Zlobec
+ *
+ * AT91SAM9 support:
+ *  Copyright (C) 2007 Anti Sullin <anti.sullin@artecdesign.ee
+ *
+ * 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/linkage.h>
+#include <mach/hardware.h>
+#include <mach/at91_pmc.h>
+
+#ifdef CONFIG_ARCH_AT91RM9200
+#include <mach/at91rm9200_mc.h>
+#elif defined(CONFIG_ARCH_AT91CAP9)
+#include <mach/at91cap9_ddrsdr.h>
+#else
+#include <mach/at91sam9_sdramc.h>
+#endif
+
+
+#ifdef CONFIG_ARCH_AT91SAM9263
+/*
+ * FIXME either or both the SDRAM controllers (EB0, EB1) might be in use;
+ * handle those cases both here and in the Suspend-To-RAM support.
+ */
+#define AT91_SDRAMC	AT91_SDRAMC0
+#warning Assuming EB1 SDRAM controller is *NOT* used
+#endif
+
+/*
+ * When SLOWDOWN_MASTER_CLOCK is defined we will also slow down the Master
+ * clock during suspend by adjusting its prescalar and divisor.
+ * NOTE: This hasn't been shown to be stable on SAM9s; and on the RM9200 there
+ *       are errata regarding adjusting the prescalar and divisor.
+ */
+#undef SLOWDOWN_MASTER_CLOCK
+
+#define MCKRDY_TIMEOUT		1000
+#define MOSCRDY_TIMEOUT 	1000
+#define PLLALOCK_TIMEOUT	1000
+#define PLLBLOCK_TIMEOUT	1000
+
+
+/*
+ * Wait until master clock is ready (after switching master clock source)
+ */
+	.macro wait_mckrdy
+	mov	r4, #MCKRDY_TIMEOUT
+1:	sub	r4, r4, #1
+	cmp	r4, #0
+	beq	2f
+	ldr	r3, [r1, #(AT91_PMC_SR - AT91_PMC)]
+	tst	r3, #AT91_PMC_MCKRDY
+	beq	1b
+2:
+	.endm
+
+/*
+ * Wait until master oscillator has stabilized.
+ */
+	.macro wait_moscrdy
+	mov	r4, #MOSCRDY_TIMEOUT
+1:	sub	r4, r4, #1
+	cmp	r4, #0
+	beq	2f
+	ldr	r3, [r1, #(AT91_PMC_SR - AT91_PMC)]
+	tst	r3, #AT91_PMC_MOSCS
+	beq	1b
+2:
+	.endm
+
+/*
+ * Wait until PLLA has locked.
+ */
+	.macro wait_pllalock
+	mov	r4, #PLLALOCK_TIMEOUT
+1:	sub	r4, r4, #1
+	cmp	r4, #0
+	beq	2f
+	ldr	r3, [r1, #(AT91_PMC_SR - AT91_PMC)]
+	tst	r3, #AT91_PMC_LOCKA
+	beq	1b
+2:
+	.endm
+
+/*
+ * Wait until PLLB has locked.
+ */
+	.macro wait_pllblock
+	mov	r4, #PLLBLOCK_TIMEOUT
+1:	sub	r4, r4, #1
+	cmp	r4, #0
+	beq	2f
+	ldr	r3, [r1, #(AT91_PMC_SR - AT91_PMC)]
+	tst	r3, #AT91_PMC_LOCKB
+	beq	1b
+2:
+	.endm
+
+	.text
+
+ENTRY(at91_slow_clock)
+	/* Save registers on stack */
+	stmfd	sp!, {r0 - r12, lr}
+
+	/*
+	 * Register usage:
+	 *  R1 = Base address of AT91_PMC
+	 *  R2 = Base address of AT91_SDRAMC (or AT91_SYS on AT91RM9200)
+	 *  R3 = temporary register
+	 *  R4 = temporary register
+	 */
+	ldr	r1, .at91_va_base_pmc
+	ldr	r2, .at91_va_base_sdramc
+
+	/* Drain write buffer */
+	mcr	p15, 0, r0, c7, c10, 4
+
+#ifdef CONFIG_ARCH_AT91RM9200
+	/* Put SDRAM in self-refresh mode */
+	mov	r3, #1
+	str	r3, [r2, #AT91_SDRAMC_SRR]
+#elif defined(CONFIG_ARCH_AT91CAP9)
+	/* Enable SDRAM self-refresh mode */
+	ldr	r3, [r2, #AT91_DDRSDRC_LPR - AT91_DDRSDRC]
+	str	r3, .saved_sam9_lpr
+
+	mov	r3, #AT91_DDRSDRC_LPCB_SELF_REFRESH
+	str	r3, [r2, #AT91_DDRSDRC_LPR - AT91_DDRSDRC]
+#else
+	/* Enable SDRAM self-refresh mode */
+	ldr	r3, [r2, #AT91_SDRAMC_LPR - AT91_SDRAMC]
+	str	r3, .saved_sam9_lpr
+
+	mov	r3, #AT91_SDRAMC_LPCB_SELF_REFRESH
+	str	r3, [r2, #AT91_SDRAMC_LPR - AT91_SDRAMC]
+#endif
+
+	/* Save Master clock setting */
+	ldr	r3, [r1, #(AT91_PMC_MCKR - AT91_PMC)]
+	str	r3, .saved_mckr
+
+	/*
+	 * Set the Master clock source to slow clock
+	 */
+	bic	r3, r3, #AT91_PMC_CSS
+	str	r3, [r1, #(AT91_PMC_MCKR - AT91_PMC)]
+
+	wait_mckrdy
+
+#ifdef SLOWDOWN_MASTER_CLOCK
+	/*
+	 * Set the Master Clock PRES and MDIV fields.
+	 *
+	 * See AT91RM9200 errata #27 and #28 for details.
+	 */
+	mov	r3, #0
+	str	r3, [r1, #(AT91_PMC_MCKR - AT91_PMC)]
+
+	wait_mckrdy
+#endif
+
+	/* Save PLLA setting and disable it */
+	ldr	r3, [r1, #(AT91_CKGR_PLLAR - AT91_PMC)]
+	str	r3, .saved_pllar
+
+	mov	r3, #AT91_PMC_PLLCOUNT
+	orr	r3, r3, #(1 << 29)		/* bit 29 always set */
+	str	r3, [r1, #(AT91_CKGR_PLLAR - AT91_PMC)]
+
+	wait_pllalock
+
+	/* Save PLLB setting and disable it */
+	ldr	r3, [r1, #(AT91_CKGR_PLLBR - AT91_PMC)]
+	str	r3, .saved_pllbr
+
+	mov	r3, #AT91_PMC_PLLCOUNT
+	str	r3, [r1, #(AT91_CKGR_PLLBR - AT91_PMC)]
+
+	wait_pllblock
+
+	/* Turn off the main oscillator */
+	ldr	r3, [r1, #(AT91_CKGR_MOR - AT91_PMC)]
+	bic	r3, r3, #AT91_PMC_MOSCEN
+	str	r3, [r1, #(AT91_CKGR_MOR - AT91_PMC)]
+
+	/* Wait for interrupt */
+	mcr	p15, 0, r0, c7, c0, 4
+
+	/* Turn on the main oscillator */
+	ldr	r3, [r1, #(AT91_CKGR_MOR - AT91_PMC)]
+	orr	r3, r3, #AT91_PMC_MOSCEN
+	str	r3, [r1, #(AT91_CKGR_MOR - AT91_PMC)]
+
+	wait_moscrdy
+
+	/* Restore PLLB setting */
+	ldr	r3, .saved_pllbr
+	str	r3, [r1, #(AT91_CKGR_PLLBR - AT91_PMC)]
+
+	wait_pllblock
+
+	/* Restore PLLA setting */
+	ldr	r3, .saved_pllar
+	str	r3, [r1, #(AT91_CKGR_PLLAR - AT91_PMC)]
+
+	wait_pllalock
+
+#ifdef SLOWDOWN_MASTER_CLOCK
+	/*
+	 * First set PRES if it was not 0,
+	 * than set CSS and MDIV fields.
+	 *
+	 * See AT91RM9200 errata #27 and #28 for details.
+	 */
+	ldr	r3, .saved_mckr
+	tst	r3, #AT91_PMC_PRES
+	beq	2f
+	and	r3, r3, #AT91_PMC_PRES
+	str	r3, [r1, #(AT91_PMC_MCKR - AT91_PMC)]
+
+	wait_mckrdy
+#endif
+
+	/*
+	 * Restore master clock setting
+	 */
+2:	ldr	r3, .saved_mckr
+	str	r3, [r1, #(AT91_PMC_MCKR - AT91_PMC)]
+
+	wait_mckrdy
+
+#ifdef CONFIG_ARCH_AT91RM9200
+	/* Do nothing - self-refresh is automatically disabled. */
+#elif defined(CONFIG_ARCH_AT91CAP9)
+	/* Restore LPR on AT91CAP9 */
+	ldr	r3, .saved_sam9_lpr
+	str	r3, [r2, #AT91_DDRSDRC_LPR - AT91_DDRSDRC]
+#else
+	/* Restore LPR on AT91SAM9 */
+	ldr	r3, .saved_sam9_lpr
+	str	r3, [r2, #AT91_SDRAMC_LPR - AT91_SDRAMC]
+#endif
+
+	/* Restore registers, and return */
+	ldmfd	sp!, {r0 - r12, pc}
+
+
+.saved_mckr:
+	.word 0
+
+.saved_pllar:
+	.word 0
+
+.saved_pllbr:
+	.word 0
+
+.saved_sam9_lpr:
+	.word 0
+
+.at91_va_base_pmc:
+	.word AT91_VA_BASE_SYS + AT91_PMC
+
+#ifdef CONFIG_ARCH_AT91RM9200
+.at91_va_base_sdramc:
+	.word AT91_VA_BASE_SYS
+#elif defined(CONFIG_ARCH_AT91CAP9)
+.at91_va_base_sdramc:
+	.word AT91_VA_BASE_SYS + AT91_DDRSDRC
+#else
+.at91_va_base_sdramc:
+	.word AT91_VA_BASE_SYS + AT91_SDRAMC
+#endif
+
+ENTRY(at91_slow_clock_sz)
+	.word .-at91_slow_clock
diff --git a/arch/arm/mach-clps711x/autcpu12.c b/arch/arm/mach-clps711x/autcpu12.c
index 474616d..5f18ecc 100644
--- a/arch/arm/mach-clps711x/autcpu12.c
+++ b/arch/arm/mach-clps711x/autcpu12.c
@@ -22,10 +22,10 @@
 #include <linux/types.h>
 #include <linux/string.h>
 #include <linux/mm.h>
+#include <linux/io.h>
 
 #include <mach/hardware.h>
 #include <asm/sizes.h>
-#include <asm/io.h>
 #include <asm/setup.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
diff --git a/arch/arm/mach-clps711x/cdb89712.c b/arch/arm/mach-clps711x/cdb89712.c
index aa02aa5..71a80b5 100644
--- a/arch/arm/mach-clps711x/cdb89712.c
+++ b/arch/arm/mach-clps711x/cdb89712.c
@@ -22,9 +22,9 @@
 #include <linux/types.h>
 #include <linux/string.h>
 #include <linux/mm.h>
+#include <linux/io.h>
 
 #include <mach/hardware.h>
-#include <asm/io.h>
 #include <asm/pgtable.h>
 #include <asm/page.h>
 #include <asm/setup.h>
diff --git a/arch/arm/mach-clps711x/include/mach/system.h b/arch/arm/mach-clps711x/include/mach/system.h
index a8eade4..24e9615 100644
--- a/arch/arm/mach-clps711x/include/mach/system.h
+++ b/arch/arm/mach-clps711x/include/mach/system.h
@@ -20,9 +20,9 @@
 #ifndef __ASM_ARCH_SYSTEM_H
 #define __ASM_ARCH_SYSTEM_H
 
+#include <linux/io.h>
 #include <mach/hardware.h>
 #include <asm/hardware/clps7111.h>
-#include <asm/io.h>
 
 static inline void arch_idle(void)
 {
diff --git a/arch/arm/mach-clps711x/irq.c b/arch/arm/mach-clps711x/irq.c
index 38623cf..9a12d85 100644
--- a/arch/arm/mach-clps711x/irq.c
+++ b/arch/arm/mach-clps711x/irq.c
@@ -19,10 +19,10 @@
  */
 #include <linux/init.h>
 #include <linux/list.h>
+#include <linux/io.h>
 
 #include <asm/mach/irq.h>
 #include <mach/hardware.h>
-#include <asm/io.h>
 #include <asm/irq.h>
 
 #include <asm/hardware/clps7111.h>
diff --git a/arch/arm/mach-clps711x/p720t-leds.c b/arch/arm/mach-clps711x/p720t-leds.c
index 262c3c3..1512144 100644
--- a/arch/arm/mach-clps711x/p720t-leds.c
+++ b/arch/arm/mach-clps711x/p720t-leds.c
@@ -21,9 +21,9 @@
  */
 #include <linux/kernel.h>
 #include <linux/init.h>
+#include <linux/io.h>
 
 #include <mach/hardware.h>
-#include <asm/io.h>
 #include <asm/leds.h>
 #include <asm/system.h>
 #include <asm/mach-types.h>
diff --git a/arch/arm/mach-clps711x/p720t.c b/arch/arm/mach-clps711x/p720t.c
index f51f97d..0d94a30 100644
--- a/arch/arm/mach-clps711x/p720t.c
+++ b/arch/arm/mach-clps711x/p720t.c
@@ -22,9 +22,9 @@
 #include <linux/types.h>
 #include <linux/string.h>
 #include <linux/mm.h>
+#include <linux/io.h>
 
 #include <mach/hardware.h>
-#include <asm/io.h>
 #include <asm/pgtable.h>
 #include <asm/page.h>
 #include <asm/setup.h>
diff --git a/arch/arm/mach-clps711x/time.c b/arch/arm/mach-clps711x/time.c
index ef1fcd1..d581ef0 100644
--- a/arch/arm/mach-clps711x/time.c
+++ b/arch/arm/mach-clps711x/time.c
@@ -21,11 +21,11 @@
 #include <linux/interrupt.h>
 #include <linux/irq.h>
 #include <linux/sched.h>
+#include <linux/io.h>
 
 #include <mach/hardware.h>
 #include <asm/irq.h>
 #include <asm/leds.h>
-#include <asm/io.h>
 #include <asm/hardware/clps7111.h>
 
 #include <asm/mach/time.h>
diff --git a/arch/arm/mach-clps7500/core.c b/arch/arm/mach-clps7500/core.c
index cc1b821..c3a33b8 100644
--- a/arch/arm/mach-clps7500/core.c
+++ b/arch/arm/mach-clps7500/core.c
@@ -15,6 +15,7 @@
 #include <linux/init.h>
 #include <linux/device.h>
 #include <linux/serial_8250.h>
+#include <linux/io.h>
 
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
@@ -23,7 +24,6 @@
 
 #include <mach/hardware.h>
 #include <asm/hardware/iomd.h>
-#include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/mach-types.h>
 
diff --git a/arch/arm/mach-clps7500/include/mach/irq.h b/arch/arm/mach-clps7500/include/mach/irq.h
index e8da3c5..d02fcf2 100644
--- a/arch/arm/mach-clps7500/include/mach/irq.h
+++ b/arch/arm/mach-clps7500/include/mach/irq.h
@@ -10,8 +10,8 @@
  *   11-08-1999	PJB	Created ARM7500 version, derived from RiscPC code
  */
 
+#include <linux/io.h>
 #include <asm/hardware/iomd.h>
-#include <asm/io.h>
 
 static inline int fixup_irq(unsigned int irq)
 {
diff --git a/arch/arm/mach-clps7500/include/mach/memory.h b/arch/arm/mach-clps7500/include/mach/memory.h
index 3326aa9..87b32db 100644
--- a/arch/arm/mach-clps7500/include/mach/memory.h
+++ b/arch/arm/mach-clps7500/include/mach/memory.h
@@ -32,4 +32,12 @@
 #define FLUSH_BASE_PHYS		0x00000000
 #define FLUSH_BASE		0xdf000000
 
+/*
+ * Sparsemem support.  Each section is a maximum of 64MB.  The sections
+ * are offset by 128MB and can cover 128MB, so that gives us a maximum
+ * of 29 physmem bits.
+ */
+#define MAX_PHYSMEM_BITS	29
+#define SECTION_SIZE_BITS	26
+
 #endif
diff --git a/arch/arm/mach-clps7500/include/mach/system.h b/arch/arm/mach-clps7500/include/mach/system.h
index 624fc28..6d325fb 100644
--- a/arch/arm/mach-clps7500/include/mach/system.h
+++ b/arch/arm/mach-clps7500/include/mach/system.h
@@ -6,8 +6,8 @@
 #ifndef __ASM_ARCH_SYSTEM_H
 #define __ASM_ARCH_SYSTEM_H
 
+#include <linux/io.h>
 #include <asm/hardware/iomd.h>
-#include <asm/io.h>
 
 static inline void arch_idle(void)
 {
diff --git a/arch/arm/mach-davinci/Makefile b/arch/arm/mach-davinci/Makefile
index 99ac2e5..4dc4585 100644
--- a/arch/arm/mach-davinci/Makefile
+++ b/arch/arm/mach-davinci/Makefile
@@ -5,7 +5,7 @@
 
 # Common objects
 obj-y 			:= time.o irq.o clock.o serial.o io.o id.o psc.o \
-			   gpio.o mux.o
+			   gpio.o mux.o devices.o usb.o
 
 # Board specific
 obj-$(CONFIG_MACH_DAVINCI_EVM)  += board-evm.o
diff --git a/arch/arm/mach-davinci/board-evm.c b/arch/arm/mach-davinci/board-evm.c
index 1343557..a957d23 100644
--- a/arch/arm/mach-davinci/board-evm.c
+++ b/arch/arm/mach-davinci/board-evm.c
@@ -13,20 +13,28 @@
 #include <linux/init.h>
 #include <linux/dma-mapping.h>
 #include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <linux/leds.h>
+
+#include <linux/i2c.h>
+#include <linux/i2c/pcf857x.h>
+#include <linux/i2c/at24.h>
+
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
 #include <linux/mtd/physmap.h>
+#include <linux/io.h>
 
 #include <asm/setup.h>
-#include <asm/io.h>
 #include <asm/mach-types.h>
-#include <mach/hardware.h>
 
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
 #include <asm/mach/flash.h>
 
+#include <mach/hardware.h>
 #include <mach/common.h>
+#include <mach/i2c.h>
 
 /* other misc. init functions */
 void __init davinci_psc_init(void);
@@ -34,10 +42,10 @@
 void __init davinci_map_common_io(void);
 void __init davinci_init_common_hw(void);
 
-/* NOR Flash base address set to CS0 by default */
-#define NOR_FLASH_PHYS 0x02000000
+#if defined(CONFIG_MTD_PHYSMAP) || \
+    defined(CONFIG_MTD_PHYSMAP_MODULE)
 
-static struct mtd_partition davinci_evm_partitions[] = {
+static struct mtd_partition davinci_evm_norflash_partitions[] = {
 	/* bootloader (U-Boot, etc) in first 4 sectors */
 	{
 		.name		= "bootloader",
@@ -68,32 +76,323 @@
 	}
 };
 
-static struct physmap_flash_data davinci_evm_flash_data = {
+static struct physmap_flash_data davinci_evm_norflash_data = {
 	.width		= 2,
-	.parts		= davinci_evm_partitions,
-	.nr_parts	= ARRAY_SIZE(davinci_evm_partitions),
+	.parts		= davinci_evm_norflash_partitions,
+	.nr_parts	= ARRAY_SIZE(davinci_evm_norflash_partitions),
 };
 
 /* NOTE: CFI probe will correctly detect flash part as 32M, but EMIF
  * limits addresses to 16M, so using addresses past 16M will wrap */
-static struct resource davinci_evm_flash_resource = {
-	.start		= NOR_FLASH_PHYS,
-	.end		= NOR_FLASH_PHYS + SZ_16M - 1,
+static struct resource davinci_evm_norflash_resource = {
+	.start		= DAVINCI_ASYNC_EMIF_DATA_CE0_BASE,
+	.end		= DAVINCI_ASYNC_EMIF_DATA_CE0_BASE + SZ_16M - 1,
 	.flags		= IORESOURCE_MEM,
 };
 
-static struct platform_device davinci_evm_flash_device = {
+static struct platform_device davinci_evm_norflash_device = {
 	.name		= "physmap-flash",
 	.id		= 0,
 	.dev		= {
-		.platform_data	= &davinci_evm_flash_data,
+		.platform_data	= &davinci_evm_norflash_data,
 	},
 	.num_resources	= 1,
-	.resource	= &davinci_evm_flash_resource,
+	.resource	= &davinci_evm_norflash_resource,
 };
 
+#endif
+
+#if defined(CONFIG_BLK_DEV_PALMCHIP_BK3710) || \
+    defined(CONFIG_BLK_DEV_PALMCHIP_BK3710_MODULE)
+
+static struct resource ide_resources[] = {
+	{
+		.start          = DAVINCI_CFC_ATA_BASE,
+		.end            = DAVINCI_CFC_ATA_BASE + 0x7ff,
+		.flags          = IORESOURCE_MEM,
+	},
+	{
+		.start          = IRQ_IDE,
+		.end            = IRQ_IDE,
+		.flags          = IORESOURCE_IRQ,
+	},
+};
+
+static u64 ide_dma_mask = DMA_32BIT_MASK;
+
+static struct platform_device ide_dev = {
+	.name           = "palm_bk3710",
+	.id             = -1,
+	.resource       = ide_resources,
+	.num_resources  = ARRAY_SIZE(ide_resources),
+	.dev = {
+		.dma_mask		= &ide_dma_mask,
+		.coherent_dma_mask      = DMA_32BIT_MASK,
+	},
+};
+
+#endif
+
+/*----------------------------------------------------------------------*/
+
+/*
+ * I2C GPIO expanders
+ */
+
+#define PCF_Uxx_BASE(x)	(DAVINCI_N_GPIO + ((x) * 8))
+
+
+/* U2 -- LEDs */
+
+static struct gpio_led evm_leds[] = {
+	{ .name = "DS8", .active_low = 1,
+		.default_trigger = "heartbeat", },
+	{ .name = "DS7", .active_low = 1, },
+	{ .name = "DS6", .active_low = 1, },
+	{ .name = "DS5", .active_low = 1, },
+	{ .name = "DS4", .active_low = 1, },
+	{ .name = "DS3", .active_low = 1, },
+	{ .name = "DS2", .active_low = 1,
+		.default_trigger = "mmc0", },
+	{ .name = "DS1", .active_low = 1,
+		.default_trigger = "ide-disk", },
+};
+
+static const struct gpio_led_platform_data evm_led_data = {
+	.num_leds	= ARRAY_SIZE(evm_leds),
+	.leds		= evm_leds,
+};
+
+static struct platform_device *evm_led_dev;
+
+static int
+evm_led_setup(struct i2c_client *client, int gpio, unsigned ngpio, void *c)
+{
+	struct gpio_led *leds = evm_leds;
+	int status;
+
+	while (ngpio--) {
+		leds->gpio = gpio++;
+		leds++;
+	}
+
+	/* what an extremely annoying way to be forced to handle
+	 * device unregistration ...
+	 */
+	evm_led_dev = platform_device_alloc("leds-gpio", 0);
+	platform_device_add_data(evm_led_dev,
+			&evm_led_data, sizeof evm_led_data);
+
+	evm_led_dev->dev.parent = &client->dev;
+	status = platform_device_add(evm_led_dev);
+	if (status < 0) {
+		platform_device_put(evm_led_dev);
+		evm_led_dev = NULL;
+	}
+	return status;
+}
+
+static int
+evm_led_teardown(struct i2c_client *client, int gpio, unsigned ngpio, void *c)
+{
+	if (evm_led_dev) {
+		platform_device_unregister(evm_led_dev);
+		evm_led_dev = NULL;
+	}
+	return 0;
+}
+
+static struct pcf857x_platform_data pcf_data_u2 = {
+	.gpio_base	= PCF_Uxx_BASE(0),
+	.setup		= evm_led_setup,
+	.teardown	= evm_led_teardown,
+};
+
+
+/* U18 - A/V clock generator and user switch */
+
+static int sw_gpio;
+
+static ssize_t
+sw_show(struct device *d, struct device_attribute *a, char *buf)
+{
+	char *s = gpio_get_value_cansleep(sw_gpio) ? "on\n" : "off\n";
+
+	strcpy(buf, s);
+	return strlen(s);
+}
+
+static DEVICE_ATTR(user_sw, S_IRUGO, sw_show, NULL);
+
+static int
+evm_u18_setup(struct i2c_client *client, int gpio, unsigned ngpio, void *c)
+{
+	int	status;
+
+	/* export dip switch option */
+	sw_gpio = gpio + 7;
+	status = gpio_request(sw_gpio, "user_sw");
+	if (status == 0)
+		status = gpio_direction_input(sw_gpio);
+	if (status == 0)
+		status = device_create_file(&client->dev, &dev_attr_user_sw);
+	else
+		gpio_free(sw_gpio);
+	if (status != 0)
+		sw_gpio = -EINVAL;
+
+	/* audio PLL:  48 kHz (vs 44.1 or 32), single rate (vs double) */
+	gpio_request(gpio + 3, "pll_fs2");
+	gpio_direction_output(gpio + 3, 0);
+
+	gpio_request(gpio + 2, "pll_fs1");
+	gpio_direction_output(gpio + 2, 0);
+
+	gpio_request(gpio + 1, "pll_sr");
+	gpio_direction_output(gpio + 1, 0);
+
+	return 0;
+}
+
+static int
+evm_u18_teardown(struct i2c_client *client, int gpio, unsigned ngpio, void *c)
+{
+	gpio_free(gpio + 1);
+	gpio_free(gpio + 2);
+	gpio_free(gpio + 3);
+
+	if (sw_gpio > 0) {
+		device_remove_file(&client->dev, &dev_attr_user_sw);
+		gpio_free(sw_gpio);
+	}
+	return 0;
+}
+
+static struct pcf857x_platform_data pcf_data_u18 = {
+	.gpio_base	= PCF_Uxx_BASE(1),
+	.n_latch	= (1 << 3) | (1 << 2) | (1 << 1),
+	.setup		= evm_u18_setup,
+	.teardown	= evm_u18_teardown,
+};
+
+
+/* U35 - various I/O signals used to manage USB, CF, ATA, etc */
+
+static int
+evm_u35_setup(struct i2c_client *client, int gpio, unsigned ngpio, void *c)
+{
+	/* p0 = nDRV_VBUS (initial:  don't supply it) */
+	gpio_request(gpio + 0, "nDRV_VBUS");
+	gpio_direction_output(gpio + 0, 1);
+
+	/* p1 = VDDIMX_EN */
+	gpio_request(gpio + 1, "VDDIMX_EN");
+	gpio_direction_output(gpio + 1, 1);
+
+	/* p2 = VLYNQ_EN */
+	gpio_request(gpio + 2, "VLYNQ_EN");
+	gpio_direction_output(gpio + 2, 1);
+
+	/* p3 = n3V3_CF_RESET (initial: stay in reset) */
+	gpio_request(gpio + 3, "nCF_RESET");
+	gpio_direction_output(gpio + 3, 0);
+
+	/* (p4 unused) */
+
+	/* p5 = 1V8_WLAN_RESET (initial: stay in reset) */
+	gpio_request(gpio + 5, "WLAN_RESET");
+	gpio_direction_output(gpio + 5, 1);
+
+	/* p6 = nATA_SEL (initial: select) */
+	gpio_request(gpio + 6, "nATA_SEL");
+	gpio_direction_output(gpio + 6, 0);
+
+	/* p7 = nCF_SEL (initial: deselect) */
+	gpio_request(gpio + 7, "nCF_SEL");
+	gpio_direction_output(gpio + 7, 1);
+
+	return 0;
+}
+
+static int
+evm_u35_teardown(struct i2c_client *client, int gpio, unsigned ngpio, void *c)
+{
+	gpio_free(gpio + 7);
+	gpio_free(gpio + 6);
+	gpio_free(gpio + 5);
+	gpio_free(gpio + 3);
+	gpio_free(gpio + 2);
+	gpio_free(gpio + 1);
+	gpio_free(gpio + 0);
+	return 0;
+}
+
+static struct pcf857x_platform_data pcf_data_u35 = {
+	.gpio_base	= PCF_Uxx_BASE(2),
+	.setup		= evm_u35_setup,
+	.teardown	= evm_u35_teardown,
+};
+
+/*----------------------------------------------------------------------*/
+
+/* Most of this EEPROM is unused, but U-Boot uses some data:
+ *  - 0x7f00, 6 bytes Ethernet Address
+ *  - 0x0039, 1 byte NTSC vs PAL (bit 0x80 == PAL)
+ *  - ... newer boards may have more
+ */
+static struct at24_platform_data eeprom_info = {
+	.byte_len	= (256*1024) / 8,
+	.page_size	= 64,
+	.flags		= AT24_FLAG_ADDR16,
+};
+
+static struct i2c_board_info __initdata i2c_info[] =  {
+	{
+		I2C_BOARD_INFO("pcf8574", 0x38),
+		.platform_data	= &pcf_data_u2,
+	},
+	{
+		I2C_BOARD_INFO("pcf8574", 0x39),
+		.platform_data	= &pcf_data_u18,
+	},
+	{
+		I2C_BOARD_INFO("pcf8574", 0x3a),
+		.platform_data	= &pcf_data_u35,
+	},
+	{
+		I2C_BOARD_INFO("24c256", 0x50),
+		.platform_data	= &eeprom_info,
+	},
+	/* ALSO:
+	 * - tvl320aic33 audio codec (0x1b)
+	 * - msp430 microcontroller (0x23)
+	 * - tvp5146 video decoder (0x5d)
+	 */
+};
+
+/* The msp430 uses a slow bitbanged I2C implementation (ergo 20 KHz),
+ * which requires 100 usec of idle bus after i2c writes sent to it.
+ */
+static struct davinci_i2c_platform_data i2c_pdata = {
+	.bus_freq	= 20 /* kHz */,
+	.bus_delay	= 100 /* usec */,
+};
+
+static void __init evm_init_i2c(void)
+{
+	davinci_init_i2c(&i2c_pdata);
+	i2c_register_board_info(1, i2c_info, ARRAY_SIZE(i2c_info));
+}
+
 static struct platform_device *davinci_evm_devices[] __initdata = {
-	&davinci_evm_flash_device,
+#if defined(CONFIG_MTD_PHYSMAP) || \
+    defined(CONFIG_MTD_PHYSMAP_MODULE)
+	&davinci_evm_norflash_device,
+#endif
+#if defined(CONFIG_BLK_DEV_PALMCHIP_BK3710) || \
+    defined(CONFIG_BLK_DEV_PALMCHIP_BK3710_MODULE)
+	&ide_dev,
+#endif
 };
 
 static void __init
@@ -106,13 +405,21 @@
 {
 	davinci_psc_init();
 
-#if defined(CONFIG_BLK_DEV_DAVINCI) || defined(CONFIG_BLK_DEV_DAVINCI_MODULE)
+#if defined(CONFIG_BLK_DEV_PALMCHIP_BK3710) || \
+    defined(CONFIG_BLK_DEV_PALMCHIP_BK3710_MODULE)
+#if defined(CONFIG_MTD_PHYSMAP) || \
+    defined(CONFIG_MTD_PHYSMAP_MODULE)
 	printk(KERN_WARNING "WARNING: both IDE and NOR flash are enabled, "
 	       "but share pins.\n\t Disable IDE for NOR support.\n");
 #endif
+#endif
 
 	platform_add_devices(davinci_evm_devices,
 			     ARRAY_SIZE(davinci_evm_devices));
+	evm_init_i2c();
+
+	/* irlml6401 sustains over 3A, switches 5V in under 8 msec */
+	setup_usb(500, 8);
 }
 
 static __init void davinci_evm_irq_init(void)
@@ -124,7 +431,7 @@
 MACHINE_START(DAVINCI_EVM, "DaVinci EVM")
 	/* Maintainer: MontaVista Software <source@mvista.com> */
 	.phys_io      = IO_PHYS,
-	.io_pg_offst  = (io_p2v(IO_PHYS) >> 18) & 0xfffc,
+	.io_pg_offst  = (__IO_ADDRESS(IO_PHYS) >> 18) & 0xfffc,
 	.boot_params  = (DAVINCI_DDR_BASE + 0x100),
 	.map_io	      = davinci_evm_map_io,
 	.init_irq     = davinci_evm_irq_init,
diff --git a/arch/arm/mach-davinci/clock.c b/arch/arm/mach-davinci/clock.c
index d46c69b..28f6dbc 100644
--- a/arch/arm/mach-davinci/clock.c
+++ b/arch/arm/mach-davinci/clock.c
@@ -16,9 +16,9 @@
 #include <linux/err.h>
 #include <linux/mutex.h>
 #include <linux/platform_device.h>
+#include <linux/io.h>
 
 #include <mach/hardware.h>
-#include <asm/io.h>
 
 #include <mach/psc.h>
 #include "clock.h"
diff --git a/arch/arm/mach-davinci/devices.c b/arch/arm/mach-davinci/devices.c
new file mode 100644
index 0000000..3d4b1de
--- /dev/null
+++ b/arch/arm/mach-davinci/devices.c
@@ -0,0 +1,48 @@
+/*
+ * mach-davinci/devices.c
+ *
+ * DaVinci platform device setup/initialization
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <linux/io.h>
+
+#include <asm/mach/map.h>
+
+#include <mach/hardware.h>
+#include <mach/i2c.h>
+
+static struct resource i2c_resources[] = {
+	{
+		.start		= DAVINCI_I2C_BASE,
+		.end		= DAVINCI_I2C_BASE + 0x40,
+		.flags		= IORESOURCE_MEM,
+	},
+	{
+		.start		= IRQ_I2C,
+		.flags		= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device davinci_i2c_device = {
+	.name           = "i2c_davinci",
+	.id             = 1,
+	.num_resources	= ARRAY_SIZE(i2c_resources),
+	.resource	= i2c_resources,
+};
+
+void __init davinci_init_i2c(struct davinci_i2c_platform_data *pdata)
+{
+	davinci_i2c_device.dev.platform_data = pdata;
+	(void) platform_device_register(&davinci_i2c_device);
+}
+
diff --git a/arch/arm/mach-davinci/gpio.c b/arch/arm/mach-davinci/gpio.c
index c9cb4f0..b49e9d0 100644
--- a/arch/arm/mach-davinci/gpio.c
+++ b/arch/arm/mach-davinci/gpio.c
@@ -1,7 +1,7 @@
 /*
  * TI DaVinci GPIO Support
  *
- * Copyright (c) 2006 David Brownell
+ * Copyright (c) 2006-2007 David Brownell
  * Copyright (c) 2007, MontaVista Software, Inc. <source@mvista.com>
  *
  * This program is free software; you can redistribute it and/or modify
@@ -26,63 +26,23 @@
 
 #include <asm/mach/irq.h>
 
+
 static DEFINE_SPINLOCK(gpio_lock);
-static DECLARE_BITMAP(gpio_in_use, DAVINCI_N_GPIO);
 
-int gpio_request(unsigned gpio, const char *tag)
-{
-	if (gpio >= DAVINCI_N_GPIO)
-		return -EINVAL;
+struct davinci_gpio {
+	struct gpio_chip	chip;
+	struct gpio_controller	*__iomem regs;
+};
 
-	if (test_and_set_bit(gpio, gpio_in_use))
-		return -EBUSY;
+static struct davinci_gpio chips[DIV_ROUND_UP(DAVINCI_N_GPIO, 32)];
 
-	return 0;
-}
-EXPORT_SYMBOL(gpio_request);
-
-void gpio_free(unsigned gpio)
-{
-	if (gpio >= DAVINCI_N_GPIO)
-		return;
-
-	clear_bit(gpio, gpio_in_use);
-}
-EXPORT_SYMBOL(gpio_free);
 
 /* create a non-inlined version */
-static struct gpio_controller *__iomem gpio2controller(unsigned gpio)
+static struct gpio_controller *__iomem __init gpio2controller(unsigned gpio)
 {
 	return __gpio_to_controller(gpio);
 }
 
-/*
- * Assuming the pin is muxed as a gpio output, set its output value.
- */
-void __gpio_set(unsigned gpio, int value)
-{
-	struct gpio_controller *__iomem g = gpio2controller(gpio);
-
-	__raw_writel(__gpio_mask(gpio), value ? &g->set_data : &g->clr_data);
-}
-EXPORT_SYMBOL(__gpio_set);
-
-
-/*
- * Read the pin's value (works even if it's set up as output);
- * returns zero/nonzero.
- *
- * Note that changes are synched to the GPIO clock, so reading values back
- * right after you've set them may give old values.
- */
-int __gpio_get(unsigned gpio)
-{
-	struct gpio_controller *__iomem g = gpio2controller(gpio);
-
-	return !!(__gpio_mask(gpio) & __raw_readl(&g->in_data));
-}
-EXPORT_SYMBOL(__gpio_get);
-
 
 /*--------------------------------------------------------------------------*/
 
@@ -91,36 +51,45 @@
  * needed, and enable the GPIO clock.
  */
 
-int gpio_direction_input(unsigned gpio)
+static int davinci_direction_in(struct gpio_chip *chip, unsigned offset)
 {
-	struct gpio_controller *__iomem g = gpio2controller(gpio);
+	struct davinci_gpio *d = container_of(chip, struct davinci_gpio, chip);
+	struct gpio_controller *__iomem g = d->regs;
 	u32 temp;
-	u32 mask;
-
-	if (!g)
-		return -EINVAL;
 
 	spin_lock(&gpio_lock);
-	mask = __gpio_mask(gpio);
 	temp = __raw_readl(&g->dir);
-	temp |= mask;
+	temp |= (1 << offset);
 	__raw_writel(temp, &g->dir);
 	spin_unlock(&gpio_lock);
+
 	return 0;
 }
-EXPORT_SYMBOL(gpio_direction_input);
 
-int gpio_direction_output(unsigned gpio, int value)
+/*
+ * Read the pin's value (works even if it's set up as output);
+ * returns zero/nonzero.
+ *
+ * Note that changes are synched to the GPIO clock, so reading values back
+ * right after you've set them may give old values.
+ */
+static int davinci_gpio_get(struct gpio_chip *chip, unsigned offset)
 {
-	struct gpio_controller *__iomem g = gpio2controller(gpio);
-	u32 temp;
-	u32 mask;
+	struct davinci_gpio *d = container_of(chip, struct davinci_gpio, chip);
+	struct gpio_controller *__iomem g = d->regs;
 
-	if (!g)
-		return -EINVAL;
+	return (1 << offset) & __raw_readl(&g->in_data);
+}
+
+static int
+davinci_direction_out(struct gpio_chip *chip, unsigned offset, int value)
+{
+	struct davinci_gpio *d = container_of(chip, struct davinci_gpio, chip);
+	struct gpio_controller *__iomem g = d->regs;
+	u32 temp;
+	u32 mask = 1 << offset;
 
 	spin_lock(&gpio_lock);
-	mask = __gpio_mask(gpio);
 	temp = __raw_readl(&g->dir);
 	temp &= ~mask;
 	__raw_writel(mask, value ? &g->set_data : &g->clr_data);
@@ -128,9 +97,49 @@
 	spin_unlock(&gpio_lock);
 	return 0;
 }
-EXPORT_SYMBOL(gpio_direction_output);
 
 /*
+ * Assuming the pin is muxed as a gpio output, set its output value.
+ */
+static void
+davinci_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
+{
+	struct davinci_gpio *d = container_of(chip, struct davinci_gpio, chip);
+	struct gpio_controller *__iomem g = d->regs;
+
+	__raw_writel((1 << offset), value ? &g->set_data : &g->clr_data);
+}
+
+static int __init davinci_gpio_setup(void)
+{
+	int i, base;
+
+	for (i = 0, base = 0;
+			i < ARRAY_SIZE(chips);
+			i++, base += 32) {
+		chips[i].chip.label = "DaVinci";
+
+		chips[i].chip.direction_input = davinci_direction_in;
+		chips[i].chip.get = davinci_gpio_get;
+		chips[i].chip.direction_output = davinci_direction_out;
+		chips[i].chip.set = davinci_gpio_set;
+
+		chips[i].chip.base = base;
+		chips[i].chip.ngpio = DAVINCI_N_GPIO - base;
+		if (chips[i].chip.ngpio > 32)
+			chips[i].chip.ngpio = 32;
+
+		chips[i].regs = gpio2controller(base);
+
+		gpiochip_add(&chips[i].chip);
+	}
+
+	return 0;
+}
+pure_initcall(davinci_gpio_setup);
+
+/*--------------------------------------------------------------------------*/
+/*
  * We expect irqs will normally be set up as input pins, but they can also be
  * used as output pins ... which is convenient for testing.
  *
@@ -201,7 +210,6 @@
 	desc->chip->ack(irq);
 	while (1) {
 		u32		status;
-		struct irq_desc	*gpio;
 		int		n;
 		int		res;
 
@@ -215,12 +223,10 @@
 
 		/* now demux them to the right lowlevel handler */
 		n = (int)get_irq_data(irq);
-		gpio = &irq_desc[n];
 		while (status) {
 			res = ffs(status);
 			n += res;
-			gpio += res;
-			desc_handle_irq(n - 1, gpio - 1);
+			generic_handle_irq(n - 1);
 			status >>= res;
 		}
 	}
diff --git a/arch/arm/mach-davinci/id.c b/arch/arm/mach-davinci/id.c
index 70608f7..bf067d6 100644
--- a/arch/arm/mach-davinci/id.c
+++ b/arch/arm/mach-davinci/id.c
@@ -13,8 +13,7 @@
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
-
-#include <asm/io.h>
+#include <linux/io.h>
 
 #define JTAG_ID_BASE		0x01c40028
 
diff --git a/arch/arm/mach-davinci/include/mach/common.h b/arch/arm/mach-davinci/include/mach/common.h
index a97dfbb..4b522e5 100644
--- a/arch/arm/mach-davinci/include/mach/common.h
+++ b/arch/arm/mach-davinci/include/mach/common.h
@@ -16,4 +16,7 @@
 
 extern struct sys_timer davinci_timer;
 
+/* parameters describe VBUS sourcing for host mode */
+extern void setup_usb(unsigned mA, unsigned potpgt_msec);
+
 #endif /* __ARCH_ARM_MACH_DAVINCI_COMMON_H */
diff --git a/arch/arm/mach-davinci/include/mach/gpio.h b/arch/arm/mach-davinci/include/mach/gpio.h
index ec151cc..b3a2961 100644
--- a/arch/arm/mach-davinci/include/mach/gpio.h
+++ b/arch/arm/mach-davinci/include/mach/gpio.h
@@ -14,6 +14,7 @@
 #define	__DAVINCI_GPIO_H
 
 #include <linux/io.h>
+#include <asm-generic/gpio.h>
 #include <mach/hardware.h>
 
 /*
@@ -27,13 +28,16 @@
  * need to pay attention to PINMUX0 and PINMUX1 to be sure those pins are
  * used as gpios, not with other peripherals.
  *
- * GPIOs are numbered 0..(DAVINCI_N_GPIO-1).  For documentation, and maybe
- * for later updates, code should write GPIO(N) or:
+ * On-chip GPIOs are numbered 0..(DAVINCI_N_GPIO-1).  For documentation,
+ * and maybe for later updates, code should write GPIO(N) or:
  *  - GPIOV18(N) for 1.8V pins, N in 0..53; same as GPIO(0)..GPIO(53)
  *  - GPIOV33(N) for 3.3V pins, N in 0..17; same as GPIO(54)..GPIO(70)
  *
  * For GPIO IRQs use gpio_to_irq(GPIO(N)) or gpio_to_irq(GPIOV33(N)) etc
  * for now, that's != GPIO(N)
+ *
+ * GPIOs can also be on external chips, numbered after the ones built-in
+ * to the DaVinci chip.  For now, they won't be usable as IRQ sources.
  */
 #define	GPIO(X)		(X)		/* 0 <= X <= 70 */
 #define	GPIOV18(X)	(X)		/* 1.8V i/o; 0 <= X <= 53 */
@@ -67,11 +71,11 @@
 	void *__iomem ptr;
 
 	if (gpio < 32)
-		ptr = (void *__iomem)IO_ADDRESS(DAVINCI_GPIO_BASE + 0x10);
+		ptr = IO_ADDRESS(DAVINCI_GPIO_BASE + 0x10);
 	else if (gpio < 64)
-		ptr = (void *__iomem)IO_ADDRESS(DAVINCI_GPIO_BASE + 0x38);
+		ptr = IO_ADDRESS(DAVINCI_GPIO_BASE + 0x38);
 	else if (gpio < DAVINCI_N_GPIO)
-		ptr = (void *__iomem)IO_ADDRESS(DAVINCI_GPIO_BASE + 0x60);
+		ptr = IO_ADDRESS(DAVINCI_GPIO_BASE + 0x60);
 	else
 		ptr = NULL;
 	return ptr;
@@ -83,25 +87,17 @@
 }
 
 /* The get/set/clear functions will inline when called with constant
- * parameters, for low-overhead bitbanging.  Illegal constant parameters
- * cause link-time errors.
+ * parameters referencing built-in GPIOs, for low-overhead bitbanging.
  *
- * Otherwise, calls with variable parameters use outlined functions.
+ * Otherwise, calls with variable parameters or referencing external
+ * GPIOs (e.g. on GPIO expander chips) use outlined functions.
  */
-extern int __error_inval_gpio(void);
-
-extern void __gpio_set(unsigned gpio, int value);
-extern int __gpio_get(unsigned gpio);
-
 static inline void gpio_set_value(unsigned gpio, int value)
 {
-	if (__builtin_constant_p(value)) {
+	if (__builtin_constant_p(value) && gpio < DAVINCI_N_GPIO) {
 		struct gpio_controller	*__iomem g;
 		u32			mask;
 
-		if (gpio >= DAVINCI_N_GPIO)
-			__error_inval_gpio();
-
 		g = __gpio_to_controller(gpio);
 		mask = __gpio_mask(gpio);
 		if (value)
@@ -111,48 +107,47 @@
 		return;
 	}
 
-	__gpio_set(gpio, value);
+	__gpio_set_value(gpio, value);
 }
 
 /* Returns zero or nonzero; works for gpios configured as inputs OR
- * as outputs.
+ * as outputs, at least for built-in GPIOs.
  *
- * NOTE: changes in reported values are synchronized to the GPIO clock.
- * This is most easily seen after calling gpio_set_value() and then immediatly
- * gpio_get_value(), where the gpio_get_value() would return the old value
- * until the GPIO clock ticks and the new value gets latched.
+ * NOTE: for built-in GPIOs, changes in reported values are synchronized
+ * to the GPIO clock.  This is easily seen after calling gpio_set_value()
+ * and then immediately gpio_get_value(), where the gpio_get_value() will
+ * return the old value until the GPIO clock ticks and the new value gets
+ * latched.
  */
-
 static inline int gpio_get_value(unsigned gpio)
 {
-	struct gpio_controller *__iomem g;
+	struct gpio_controller	*__iomem g;
 
-	if (!__builtin_constant_p(gpio))
-		return __gpio_get(gpio);
-
-	if (gpio >= DAVINCI_N_GPIO)
-		return __error_inval_gpio();
+	if (!__builtin_constant_p(gpio) || gpio >= DAVINCI_N_GPIO)
+		return __gpio_get_value(gpio);
 
 	g = __gpio_to_controller(gpio);
-	return !!(__gpio_mask(gpio) & __raw_readl(&g->in_data));
+	return __gpio_mask(gpio) & __raw_readl(&g->in_data);
 }
 
-/* powerup default direction is IN */
-extern int gpio_direction_input(unsigned gpio);
-extern int gpio_direction_output(unsigned gpio, int value);
-
-#include <asm-generic/gpio.h>	/* cansleep wrappers */
-
-extern int gpio_request(unsigned gpio, const char *tag);
-extern void gpio_free(unsigned gpio);
+static inline int gpio_cansleep(unsigned gpio)
+{
+	if (__builtin_constant_p(gpio) && gpio < DAVINCI_N_GPIO)
+		return 0;
+	else
+		return __gpio_cansleep(gpio);
+}
 
 static inline int gpio_to_irq(unsigned gpio)
 {
+	if (gpio >= DAVINCI_N_GPIO)
+		return -EINVAL;
 	return DAVINCI_N_AINTC_IRQ + gpio;
 }
 
 static inline int irq_to_gpio(unsigned irq)
 {
+	/* caller guarantees gpio_to_irq() succeeded */
 	return irq - DAVINCI_N_AINTC_IRQ;
 }
 
diff --git a/arch/arm/mach-davinci/include/mach/i2c.h b/arch/arm/mach-davinci/include/mach/i2c.h
index e2f5416..c248e9b 100644
--- a/arch/arm/mach-davinci/include/mach/i2c.h
+++ b/arch/arm/mach-davinci/include/mach/i2c.h
@@ -14,8 +14,11 @@
 
 /* All frequencies are expressed in kHz */
 struct davinci_i2c_platform_data {
-	unsigned int	bus_freq;	/* standard bus frequency */
-	unsigned int	bus_delay;	/* transaction delay */
+	unsigned int	bus_freq;	/* standard bus frequency (kHz) */
+	unsigned int	bus_delay;	/* post-transaction delay (usec) */
 };
 
+/* for board setup code */
+void davinci_init_i2c(struct davinci_i2c_platform_data *);
+
 #endif /* __ASM_ARCH_I2C_H */
diff --git a/arch/arm/mach-davinci/include/mach/io.h b/arch/arm/mach-davinci/include/mach/io.h
index e7accb9..b78ee91 100644
--- a/arch/arm/mach-davinci/include/mach/io.h
+++ b/arch/arm/mach-davinci/include/mach/io.h
@@ -22,9 +22,8 @@
 #define IO_OFFSET	0xfd000000 /* Virtual IO = 0xfec00000 */
 #define IO_SIZE		0x00400000
 #define IO_VIRT		(IO_PHYS + IO_OFFSET)
-#define io_p2v(pa)	((pa) + IO_OFFSET)
 #define io_v2p(va)	((va) - IO_OFFSET)
-#define IO_ADDRESS(x)	io_p2v(x)
+#define __IO_ADDRESS(x)	((x) + IO_OFFSET)
 
 /*
  * We don't actually have real ISA nor PCI buses, but there is so many
@@ -35,7 +34,12 @@
 #define __mem_pci(a)		(a)
 #define __mem_isa(a)		(a)
 
-#ifndef __ASSEMBLER__
+#define IO_ADDRESS(pa)          IOMEM(__IO_ADDRESS(pa))
+
+#ifdef __ASSEMBLER__
+#define IOMEM(x)                x
+#else
+#define IOMEM(x)                ((void __force __iomem *)(x))
 
 /*
  * Functions to access the DaVinci IO region
@@ -46,34 +50,13 @@
  *	 - DO NOT use hardcoded virtual addresses to allow changing the
  *	   IO address space again if needed
  */
-#define davinci_readb(a)	(*(volatile unsigned char  *)IO_ADDRESS(a))
-#define davinci_readw(a)	(*(volatile unsigned short *)IO_ADDRESS(a))
-#define davinci_readl(a)	(*(volatile unsigned int   *)IO_ADDRESS(a))
+#define davinci_readb(a)	__raw_readb(IO_ADDRESS(a))
+#define davinci_readw(a)	__raw_readw(IO_ADDRESS(a))
+#define davinci_readl(a)	__raw_readl(IO_ADDRESS(a))
 
-#define davinci_writeb(v,a)	(*(volatile unsigned char  *)IO_ADDRESS(a) = (v))
-#define davinci_writew(v,a)	(*(volatile unsigned short *)IO_ADDRESS(a) = (v))
-#define davinci_writel(v,a)	(*(volatile unsigned int   *)IO_ADDRESS(a) = (v))
-
-/* 16 bit uses LDRH/STRH, base +/- offset_8 */
-typedef struct { volatile u16 offset[256]; } __regbase16;
-#define __REGV16(vaddr)		((__regbase16 *)((vaddr)&~0xff)) \
-					->offset[((vaddr)&0xff)>>1]
-#define __REG16(paddr)          __REGV16(io_p2v(paddr))
-
-/* 8/32 bit uses LDR/STR, base +/- offset_12 */
-typedef struct { volatile u8 offset[4096]; } __regbase8;
-#define __REGV8(vaddr)		((__regbase8  *)((vaddr)&~4095)) \
-					->offset[((vaddr)&4095)>>0]
-#define __REG8(paddr)		__REGV8(io_p2v(paddr))
-
-typedef struct { volatile u32 offset[4096]; } __regbase32;
-#define __REGV32(vaddr)		((__regbase32 *)((vaddr)&~4095)) \
-					->offset[((vaddr)&4095)>>2]
-
-#define __REG(paddr)		__REGV32(io_p2v(paddr))
-#else
-
-#define __REG(x)	(*((volatile unsigned long *)io_p2v(x)))
+#define davinci_writeb(v, a)	__raw_writeb(v, IO_ADDRESS(a))
+#define davinci_writew(v, a)	__raw_writew(v, IO_ADDRESS(a))
+#define davinci_writel(v, a)	__raw_writel(v, IO_ADDRESS(a))
 
 #endif /* __ASSEMBLER__ */
 #endif /* __ASM_ARCH_IO_H */
diff --git a/arch/arm/mach-davinci/include/mach/system.h b/arch/arm/mach-davinci/include/mach/system.h
index 84ff77a..17ca41d 100644
--- a/arch/arm/mach-davinci/include/mach/system.h
+++ b/arch/arm/mach-davinci/include/mach/system.h
@@ -11,7 +11,7 @@
 #ifndef __ASM_ARCH_SYSTEM_H
 #define __ASM_ARCH_SYSTEM_H
 
-#include <asm/io.h>
+#include <linux/io.h>
 #include <mach/hardware.h>
 
 extern void davinci_watchdog_reset(void);
diff --git a/arch/arm/mach-davinci/io.c b/arch/arm/mach-davinci/io.c
index 5bb66b6..299515f 100644
--- a/arch/arm/mach-davinci/io.c
+++ b/arch/arm/mach-davinci/io.c
@@ -11,9 +11,9 @@
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
+#include <linux/io.h>
 
 #include <asm/tlb.h>
-#include <asm/io.h>
 #include <asm/memory.h>
 
 #include <asm/mach/map.h>
diff --git a/arch/arm/mach-davinci/irq.c b/arch/arm/mach-davinci/irq.c
index 12ca9f2..38021af 100644
--- a/arch/arm/mach-davinci/irq.c
+++ b/arch/arm/mach-davinci/irq.c
@@ -22,9 +22,9 @@
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/irq.h>
+#include <linux/io.h>
 
 #include <mach/hardware.h>
-#include <asm/io.h>
 #include <asm/mach/irq.h>
 
 #define IRQ_BIT(irq)		((irq) & 0x1f)
diff --git a/arch/arm/mach-davinci/psc.c b/arch/arm/mach-davinci/psc.c
index 720c48b..58754f0 100644
--- a/arch/arm/mach-davinci/psc.c
+++ b/arch/arm/mach-davinci/psc.c
@@ -21,8 +21,8 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/init.h>
+#include <linux/io.h>
 
-#include <asm/io.h>
 #include <mach/hardware.h>
 #include <mach/psc.h>
 #include <mach/mux.h>
@@ -70,9 +70,6 @@
 {
 	u32 epcpr, ptcmd, ptstat, pdstat, pdctl1, mdstat, mdctl, mdstat_mask;
 
-	if (id < 0)
-		return;
-
 	mdctl = davinci_readl(DAVINCI_PWR_SLEEP_CNTRL_BASE + MDCTL + 4 * id);
 	if (enable)
 		mdctl |= 0x00000003;	/* Enable Module */
diff --git a/arch/arm/mach-davinci/serial.c b/arch/arm/mach-davinci/serial.c
index caf101e..3010f99 100644
--- a/arch/arm/mach-davinci/serial.c
+++ b/arch/arm/mach-davinci/serial.c
@@ -26,8 +26,8 @@
 #include <linux/platform_device.h>
 #include <linux/delay.h>
 #include <linux/clk.h>
+#include <linux/io.h>
 
-#include <asm/io.h>
 #include <asm/irq.h>
 #include <mach/hardware.h>
 #include <mach/serial.h>
diff --git a/arch/arm/mach-davinci/time.c b/arch/arm/mach-davinci/time.c
index 206e80d..3b9a296 100644
--- a/arch/arm/mach-davinci/time.c
+++ b/arch/arm/mach-davinci/time.c
@@ -15,8 +15,8 @@
 #include <linux/clocksource.h>
 #include <linux/clockchips.h>
 #include <linux/spinlock.h>
+#include <linux/io.h>
 
-#include <asm/io.h>
 #include <mach/hardware.h>
 #include <asm/system.h>
 #include <asm/irq.h>
diff --git a/arch/arm/mach-davinci/usb.c b/arch/arm/mach-davinci/usb.c
new file mode 100644
index 0000000..fe182a8
--- /dev/null
+++ b/arch/arm/mach-davinci/usb.c
@@ -0,0 +1,116 @@
+/*
+ * USB
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+
+#include <linux/usb/musb.h>
+#include <linux/usb/otg.h>
+
+#include <mach/common.h>
+#include <mach/hardware.h>
+
+#if defined(CONFIG_USB_MUSB_HDRC) || defined(CONFIG_USB_MUSB_HDRC_MODULE)
+static struct musb_hdrc_eps_bits musb_eps[] = {
+	{ "ep1_tx", 8, },
+	{ "ep1_rx", 8, },
+	{ "ep2_tx", 8, },
+	{ "ep2_rx", 8, },
+	{ "ep3_tx", 5, },
+	{ "ep3_rx", 5, },
+	{ "ep4_tx", 5, },
+	{ "ep4_rx", 5, },
+};
+
+static struct musb_hdrc_config musb_config = {
+	.multipoint	= true,
+	.dyn_fifo	= true,
+	.soft_con	= true,
+	.dma		= true,
+
+	.num_eps	= 5,
+	.dma_channels	= 8,
+	.ram_bits	= 10,
+	.eps_bits	= musb_eps,
+};
+
+static struct musb_hdrc_platform_data usb_data = {
+#if defined(CONFIG_USB_MUSB_OTG)
+	/* OTG requires a Mini-AB connector */
+	.mode           = MUSB_OTG,
+#elif defined(CONFIG_USB_MUSB_PERIPHERAL)
+	.mode           = MUSB_PERIPHERAL,
+#elif defined(CONFIG_USB_MUSB_HOST)
+	.mode           = MUSB_HOST,
+#endif
+	.config		= &musb_config,
+};
+
+static struct resource usb_resources[] = {
+	{
+		/* physical address */
+		.start          = DAVINCI_USB_OTG_BASE,
+		.end            = DAVINCI_USB_OTG_BASE + 0x5ff,
+		.flags          = IORESOURCE_MEM,
+	},
+	{
+		.start          = IRQ_USBINT,
+		.flags          = IORESOURCE_IRQ,
+	},
+};
+
+static u64 usb_dmamask = DMA_32BIT_MASK;
+
+static struct platform_device usb_dev = {
+	.name           = "musb_hdrc",
+	.id             = -1,
+	.dev = {
+		.platform_data		= &usb_data,
+		.dma_mask		= &usb_dmamask,
+		.coherent_dma_mask      = DMA_32BIT_MASK,
+	},
+	.resource       = usb_resources,
+	.num_resources  = ARRAY_SIZE(usb_resources),
+};
+
+#ifdef CONFIG_USB_MUSB_OTG
+
+static struct otg_transceiver *xceiv;
+
+struct otg_transceiver *otg_get_transceiver(void)
+{
+	if (xceiv)
+		get_device(xceiv->dev);
+	return xceiv;
+}
+EXPORT_SYMBOL(otg_get_transceiver);
+
+int otg_set_transceiver(struct otg_transceiver *x)
+{
+	if (xceiv && x)
+		return -EBUSY;
+	xceiv = x;
+	return 0;
+}
+EXPORT_SYMBOL(otg_set_transceiver);
+
+#endif
+
+void __init setup_usb(unsigned mA, unsigned potpgt_msec)
+{
+	usb_data.power = mA / 2;
+	usb_data.potpgt = potpgt_msec / 2;
+	platform_device_register(&usb_dev);
+}
+
+#else
+
+void __init setup_usb(unsigned mA, unsigned potpgt_msec)
+{
+}
+
+#endif  /* CONFIG_USB_MUSB_HDRC */
+
diff --git a/arch/arm/mach-ebsa110/core.c b/arch/arm/mach-ebsa110/core.c
index 65cc7c2..c7bc7fb 100644
--- a/arch/arm/mach-ebsa110/core.c
+++ b/arch/arm/mach-ebsa110/core.c
@@ -14,10 +14,10 @@
 #include <linux/interrupt.h>
 #include <linux/serial_8250.h>
 #include <linux/init.h>
+#include <linux/io.h>
 
 #include <mach/hardware.h>
 #include <asm/irq.h>
-#include <asm/io.h>
 #include <asm/setup.h>
 #include <asm/mach-types.h>
 #include <asm/pgtable.h>
diff --git a/arch/arm/mach-ebsa110/io.c b/arch/arm/mach-ebsa110/io.c
index 53748f5..c52e304 100644
--- a/arch/arm/mach-ebsa110/io.c
+++ b/arch/arm/mach-ebsa110/io.c
@@ -23,9 +23,9 @@
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/types.h>
+#include <linux/io.h>
 
 #include <mach/hardware.h>
-#include <asm/io.h>
 #include <asm/page.h>
 
 static void __iomem *__isamem_convert_addr(const volatile void __iomem *addr)
diff --git a/arch/arm/mach-ep93xx/Kconfig b/arch/arm/mach-ep93xx/Kconfig
index ea8549b..5a1b8c0 100644
--- a/arch/arm/mach-ep93xx/Kconfig
+++ b/arch/arm/mach-ep93xx/Kconfig
@@ -88,6 +88,20 @@
 	  Say 'Y' here if you want your kernel to support the
 	  Technologic Systems TS-72xx board.
 
+choice
+	prompt "Select a UART for early kernel messages"
+
+config EP93XX_EARLY_UART1
+	bool "UART1"
+
+config EP93XX_EARLY_UART2
+	bool "UART2"
+
+config EP93XX_EARLY_UART3
+	bool "UART3"
+
+endchoice
+
 endmenu
 
 endif
diff --git a/arch/arm/mach-ep93xx/adssphere.c b/arch/arm/mach-ep93xx/adssphere.c
index aa1fb35..561db73 100644
--- a/arch/arm/mach-ep93xx/adssphere.c
+++ b/arch/arm/mach-ep93xx/adssphere.c
@@ -18,7 +18,7 @@
 #include <linux/ioport.h>
 #include <linux/mtd/physmap.h>
 #include <linux/platform_device.h>
-#include <asm/io.h>
+#include <linux/io.h>
 #include <mach/hardware.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
@@ -47,36 +47,12 @@
 	.phy_id		= 1,
 };
 
-static struct resource adssphere_eth_resource[] = {
-	{
-		.start	= EP93XX_ETHERNET_PHYS_BASE,
-		.end	= EP93XX_ETHERNET_PHYS_BASE + 0xffff,
-		.flags	= IORESOURCE_MEM,
-	}, {
-		.start	= IRQ_EP93XX_ETHERNET,
-		.end	= IRQ_EP93XX_ETHERNET,
-		.flags	= IORESOURCE_IRQ,
-	}
-};
-
-static struct platform_device adssphere_eth_device = {
-	.name		= "ep93xx-eth",
-	.id		= -1,
-	.dev		= {
-		.platform_data	= &adssphere_eth_data,
-	},
-	.num_resources	= 2,
-	.resource	= adssphere_eth_resource,
-};
-
 static void __init adssphere_init_machine(void)
 {
 	ep93xx_init_devices();
 	platform_device_register(&adssphere_flash);
 
-	memcpy(adssphere_eth_data.dev_addr,
-		(void *)(EP93XX_ETHERNET_BASE + 0x50), 6);
-	platform_device_register(&adssphere_eth_device);
+	ep93xx_register_eth(&adssphere_eth_data, 1);
 }
 
 MACHINE_START(ADSSPHERE, "ADS Sphere board")
diff --git a/arch/arm/mach-ep93xx/clock.c b/arch/arm/mach-ep93xx/clock.c
index 6062e47..8c9f249 100644
--- a/arch/arm/mach-ep93xx/clock.c
+++ b/arch/arm/mach-ep93xx/clock.c
@@ -15,9 +15,9 @@
 #include <linux/err.h>
 #include <linux/module.h>
 #include <linux/string.h>
+#include <linux/io.h>
 #include <asm/div64.h>
 #include <mach/hardware.h>
-#include <asm/io.h>
 
 struct clk {
 	char		*name;
diff --git a/arch/arm/mach-ep93xx/core.c b/arch/arm/mach-ep93xx/core.c
index f99f436..de53f0b 100644
--- a/arch/arm/mach-ep93xx/core.c
+++ b/arch/arm/mach-ep93xx/core.c
@@ -32,6 +32,7 @@
 #include <linux/termios.h>
 #include <linux/amba/bus.h>
 #include <linux/amba/serial.h>
+#include <linux/io.h>
 
 #include <asm/types.h>
 #include <asm/setup.h>
@@ -41,7 +42,6 @@
 #include <asm/system.h>
 #include <asm/tlbflush.h>
 #include <asm/pgtable.h>
-#include <asm/io.h>
 
 #include <asm/mach/map.h>
 #include <asm/mach/time.h>
@@ -157,7 +157,7 @@
 static const u8 int_type1_register_offset[3]	= { 0x90, 0xac, 0x4c };
 static const u8 int_type2_register_offset[3]	= { 0x94, 0xb0, 0x50 };
 static const u8 eoi_register_offset[3]		= { 0x98, 0xb4, 0x54 };
-static const u8 int_en_register_offset[3]	= { 0x9c, 0xb8, 0x5c };
+static const u8 int_en_register_offset[3]	= { 0x9c, 0xb8, 0x58 };
 
 void ep93xx_gpio_update_int_params(unsigned port)
 {
@@ -192,8 +192,7 @@
 	for (i = 0; i < 8; i++) {
 		if (status & (1 << i)) {
 			int gpio_irq = gpio_to_irq(EP93XX_GPIO_LINE_A(0)) + i;
-			desc = irq_desc + gpio_irq;
-			desc_handle_irq(gpio_irq, desc);
+			generic_handle_irq(gpio_irq);
 		}
 	}
 
@@ -202,7 +201,7 @@
 		if (status & (1 << i)) {
 			int gpio_irq = gpio_to_irq(EP93XX_GPIO_LINE_B(0)) + i;
 			desc = irq_desc + gpio_irq;
-			desc_handle_irq(gpio_irq, desc);
+			generic_handle_irq(gpio_irq);
 		}
 	}
 }
@@ -217,7 +216,7 @@
 	int port_f_idx = ((irq + 1) & 7) ^ 4; /* {19..22,47..50} -> {0..7} */
 	int gpio_irq = gpio_to_irq(EP93XX_GPIO_LINE_F(0)) + port_f_idx;
 
-	desc_handle_irq(gpio_irq, irq_desc + gpio_irq);
+	generic_handle_irq(gpio_irq);
 }
 
 static void ep93xx_gpio_irq_ack(unsigned int irq)
@@ -461,6 +460,41 @@
 	.resource	= ep93xx_ohci_resources,
 };
 
+static struct ep93xx_eth_data ep93xx_eth_data;
+
+static struct resource ep93xx_eth_resource[] = {
+	{
+		.start	= EP93XX_ETHERNET_PHYS_BASE,
+		.end	= EP93XX_ETHERNET_PHYS_BASE + 0xffff,
+		.flags	= IORESOURCE_MEM,
+	}, {
+		.start	= IRQ_EP93XX_ETHERNET,
+		.end	= IRQ_EP93XX_ETHERNET,
+		.flags	= IORESOURCE_IRQ,
+	}
+};
+
+static struct platform_device ep93xx_eth_device = {
+	.name		= "ep93xx-eth",
+	.id		= -1,
+	.dev		= {
+		.platform_data	= &ep93xx_eth_data,
+	},
+	.num_resources	= ARRAY_SIZE(ep93xx_eth_resource),
+	.resource	= ep93xx_eth_resource,
+};
+
+void __init ep93xx_register_eth(struct ep93xx_eth_data *data, int copy_addr)
+{
+	if (copy_addr) {
+		memcpy(data->dev_addr,
+			(void *)(EP93XX_ETHERNET_BASE + 0x50), 6);
+	}
+
+	ep93xx_eth_data = *data;
+	platform_device_register(&ep93xx_eth_device);
+}
+
 extern void ep93xx_gpio_init(void);
 
 void __init ep93xx_init_devices(void)
diff --git a/arch/arm/mach-ep93xx/edb9302.c b/arch/arm/mach-ep93xx/edb9302.c
index 97550c0..e4add5b 100644
--- a/arch/arm/mach-ep93xx/edb9302.c
+++ b/arch/arm/mach-ep93xx/edb9302.c
@@ -18,7 +18,7 @@
 #include <linux/ioport.h>
 #include <linux/mtd/physmap.h>
 #include <linux/platform_device.h>
-#include <asm/io.h>
+#include <linux/io.h>
 #include <mach/hardware.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
@@ -43,10 +43,16 @@
 	.resource	= &edb9302_flash_resource,
 };
 
+static struct ep93xx_eth_data edb9302_eth_data = {
+	.phy_id		= 1,
+};
+
 static void __init edb9302_init_machine(void)
 {
 	ep93xx_init_devices();
 	platform_device_register(&edb9302_flash);
+
+	ep93xx_register_eth(&edb9302_eth_data, 1);
 }
 
 MACHINE_START(EDB9302, "Cirrus Logic EDB9302 Evaluation Board")
diff --git a/arch/arm/mach-ep93xx/edb9302a.c b/arch/arm/mach-ep93xx/edb9302a.c
index 99b01d4..02c4405 100644
--- a/arch/arm/mach-ep93xx/edb9302a.c
+++ b/arch/arm/mach-ep93xx/edb9302a.c
@@ -18,7 +18,7 @@
 #include <linux/ioport.h>
 #include <linux/mtd/physmap.h>
 #include <linux/platform_device.h>
-#include <asm/io.h>
+#include <linux/io.h>
 #include <mach/hardware.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
@@ -47,36 +47,12 @@
 	.phy_id			= 1,
 };
 
-static struct resource edb9302a_eth_resource[] = {
-	{
-		.start	= EP93XX_ETHERNET_PHYS_BASE,
-		.end	= EP93XX_ETHERNET_PHYS_BASE + 0xffff,
-		.flags	= IORESOURCE_MEM,
-	}, {
-		.start	= IRQ_EP93XX_ETHERNET,
-		.end	= IRQ_EP93XX_ETHERNET,
-		.flags	= IORESOURCE_IRQ,
-	}
-};
-
-static struct platform_device edb9302a_eth_device = {
-	.name		= "ep93xx-eth",
-	.id		= -1,
-	.dev		= {
-		.platform_data	= &edb9302a_eth_data,
-	},
-	.num_resources	= 2,
-	.resource	= edb9302a_eth_resource,
-};
-
 static void __init edb9302a_init_machine(void)
 {
 	ep93xx_init_devices();
 	platform_device_register(&edb9302a_flash);
 
-	memcpy(edb9302a_eth_data.dev_addr,
-		(void *)(EP93XX_ETHERNET_BASE + 0x50), 6);
-	platform_device_register(&edb9302a_eth_device);
+	ep93xx_register_eth(&edb9302a_eth_data, 1);
 }
 
 MACHINE_START(EDB9302A, "Cirrus Logic EDB9302A Evaluation Board")
diff --git a/arch/arm/mach-ep93xx/edb9307.c b/arch/arm/mach-ep93xx/edb9307.c
index 9fb72d0..040edbd 100644
--- a/arch/arm/mach-ep93xx/edb9307.c
+++ b/arch/arm/mach-ep93xx/edb9307.c
@@ -18,7 +18,7 @@
 #include <linux/ioport.h>
 #include <linux/mtd/physmap.h>
 #include <linux/platform_device.h>
-#include <asm/io.h>
+#include <linux/io.h>
 #include <mach/hardware.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
@@ -47,36 +47,12 @@
 	.phy_id			= 1,
 };
 
-static struct resource edb9307_eth_resource[] = {
-	{
-		.start	= EP93XX_ETHERNET_PHYS_BASE,
-		.end	= EP93XX_ETHERNET_PHYS_BASE + 0xffff,
-		.flags	= IORESOURCE_MEM,
-	}, {
-		.start	= IRQ_EP93XX_ETHERNET,
-		.end	= IRQ_EP93XX_ETHERNET,
-		.flags	= IORESOURCE_IRQ,
-	}
-};
-
-static struct platform_device edb9307_eth_device = {
-	.name		= "ep93xx-eth",
-	.id		= -1,
-	.dev		= {
-		.platform_data	= &edb9307_eth_data,
-	},
-	.num_resources	= 2,
-	.resource	= edb9307_eth_resource,
-};
-
 static void __init edb9307_init_machine(void)
 {
 	ep93xx_init_devices();
 	platform_device_register(&edb9307_flash);
 
-	memcpy(edb9307_eth_data.dev_addr,
-		(void *)(EP93XX_ETHERNET_BASE + 0x50), 6);
-	platform_device_register(&edb9307_eth_device);
+	ep93xx_register_eth(&edb9307_eth_data, 1);
 }
 
 MACHINE_START(EDB9307, "Cirrus Logic EDB9307 Evaluation Board")
diff --git a/arch/arm/mach-ep93xx/edb9312.c b/arch/arm/mach-ep93xx/edb9312.c
index 87267a5..6853e30 100644
--- a/arch/arm/mach-ep93xx/edb9312.c
+++ b/arch/arm/mach-ep93xx/edb9312.c
@@ -19,7 +19,7 @@
 #include <linux/ioport.h>
 #include <linux/mtd/physmap.h>
 #include <linux/platform_device.h>
-#include <asm/io.h>
+#include <linux/io.h>
 #include <mach/hardware.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
@@ -44,10 +44,16 @@
 	.resource	= &edb9312_flash_resource,
 };
 
+static struct ep93xx_eth_data edb9312_eth_data = {
+	.phy_id			= 1,
+};
+
 static void __init edb9312_init_machine(void)
 {
 	ep93xx_init_devices();
 	platform_device_register(&edb9312_flash);
+
+	ep93xx_register_eth(&edb9312_eth_data, 1);
 }
 
 MACHINE_START(EDB9312, "Cirrus Logic EDB9312 Evaluation Board")
diff --git a/arch/arm/mach-ep93xx/edb9315.c b/arch/arm/mach-ep93xx/edb9315.c
index 7e37395..9469b35 100644
--- a/arch/arm/mach-ep93xx/edb9315.c
+++ b/arch/arm/mach-ep93xx/edb9315.c
@@ -18,7 +18,7 @@
 #include <linux/ioport.h>
 #include <linux/mtd/physmap.h>
 #include <linux/platform_device.h>
-#include <asm/io.h>
+#include <linux/io.h>
 #include <mach/hardware.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
@@ -43,10 +43,16 @@
 	.resource	= &edb9315_flash_resource,
 };
 
+static struct ep93xx_eth_data edb9315_eth_data = {
+	.phy_id			= 1,
+};
+
 static void __init edb9315_init_machine(void)
 {
 	ep93xx_init_devices();
 	platform_device_register(&edb9315_flash);
+
+	ep93xx_register_eth(&edb9315_eth_data, 1);
 }
 
 MACHINE_START(EDB9315, "Cirrus Logic EDB9315 Evaluation Board")
diff --git a/arch/arm/mach-ep93xx/edb9315a.c b/arch/arm/mach-ep93xx/edb9315a.c
index 08a7c9b..584457c 100644
--- a/arch/arm/mach-ep93xx/edb9315a.c
+++ b/arch/arm/mach-ep93xx/edb9315a.c
@@ -18,7 +18,7 @@
 #include <linux/ioport.h>
 #include <linux/mtd/physmap.h>
 #include <linux/platform_device.h>
-#include <asm/io.h>
+#include <linux/io.h>
 #include <mach/hardware.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
@@ -47,36 +47,12 @@
 	.phy_id			= 1,
 };
 
-static struct resource edb9315a_eth_resource[] = {
-	{
-		.start	= EP93XX_ETHERNET_PHYS_BASE,
-		.end	= EP93XX_ETHERNET_PHYS_BASE + 0xffff,
-		.flags	= IORESOURCE_MEM,
-	}, {
-		.start	= IRQ_EP93XX_ETHERNET,
-		.end	= IRQ_EP93XX_ETHERNET,
-		.flags	= IORESOURCE_IRQ,
-	}
-};
-
-static struct platform_device edb9315a_eth_device = {
-	.name		= "ep93xx-eth",
-	.id		= -1,
-	.dev		= {
-		.platform_data	= &edb9315a_eth_data,
-	},
-	.num_resources	= 2,
-	.resource	= edb9315a_eth_resource,
-};
-
 static void __init edb9315a_init_machine(void)
 {
 	ep93xx_init_devices();
 	platform_device_register(&edb9315a_flash);
 
-	memcpy(edb9315a_eth_data.dev_addr,
-		(void *)(EP93XX_ETHERNET_BASE + 0x50), 6);
-	platform_device_register(&edb9315a_eth_device);
+	ep93xx_register_eth(&edb9315a_eth_data, 1);
 }
 
 MACHINE_START(EDB9315A, "Cirrus Logic EDB9315A Evaluation Board")
diff --git a/arch/arm/mach-ep93xx/gesbc9312.c b/arch/arm/mach-ep93xx/gesbc9312.c
index 9b41ec1..035b24e 100644
--- a/arch/arm/mach-ep93xx/gesbc9312.c
+++ b/arch/arm/mach-ep93xx/gesbc9312.c
@@ -18,7 +18,7 @@
 #include <linux/ioport.h>
 #include <linux/mtd/physmap.h>
 #include <linux/platform_device.h>
-#include <asm/io.h>
+#include <linux/io.h>
 #include <mach/hardware.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
@@ -44,36 +44,15 @@
 };
 
 static struct ep93xx_eth_data gesbc9312_eth_data = {
-	.phy_id			= 1,
-};
-
-static struct resource gesbc9312_eth_resource[] = {
-	{
-		.start	= EP93XX_ETHERNET_PHYS_BASE,
-		.end	= EP93XX_ETHERNET_PHYS_BASE + 0xffff,
-		.flags	= IORESOURCE_MEM,
-	}, {
-		.start	= IRQ_EP93XX_ETHERNET,
-		.end	= IRQ_EP93XX_ETHERNET,
-		.flags	= IORESOURCE_IRQ,
-	}
-};
-
-static struct platform_device gesbc9312_eth_device = {
-	.name		= "ep93xx-eth",
-	.id		= -1,
-	.dev		= {
-		.platform_data	= &gesbc9312_eth_data,
-	},
-	.num_resources	= 2,
-	.resource	= gesbc9312_eth_resource,
+	.phy_id		= 1,
 };
 
 static void __init gesbc9312_init_machine(void)
 {
 	ep93xx_init_devices();
 	platform_device_register(&gesbc9312_flash);
-	platform_device_register(&gesbc9312_eth_device);
+
+	ep93xx_register_eth(&gesbc9312_eth_data, 0);
 }
 
 MACHINE_START(GESBC9312, "Glomation GESBC-9312-sx")
diff --git a/arch/arm/mach-ep93xx/gpio.c b/arch/arm/mach-ep93xx/gpio.c
index 0f3fb87..482cf3d 100644
--- a/arch/arm/mach-ep93xx/gpio.c
+++ b/arch/arm/mach-ep93xx/gpio.c
@@ -16,9 +16,9 @@
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/seq_file.h>
+#include <linux/io.h>
 
 #include <mach/ep93xx-regs.h>
-#include <asm/io.h>
 #include <asm/gpio.h>
 
 struct ep93xx_gpio_chip {
@@ -141,10 +141,10 @@
 static struct ep93xx_gpio_chip ep93xx_gpio_banks[] = {
 	EP93XX_GPIO_BANK("A", 0x00, 0x10, 0),
 	EP93XX_GPIO_BANK("B", 0x04, 0x14, 8),
-	EP93XX_GPIO_BANK("C", 0x30, 0x34, 40),
+	EP93XX_GPIO_BANK("C", 0x08, 0x18, 40),
 	EP93XX_GPIO_BANK("D", 0x0c, 0x1c, 24),
 	EP93XX_GPIO_BANK("E", 0x20, 0x24, 32),
-	EP93XX_GPIO_BANK("F", 0x08, 0x18, 16),
+	EP93XX_GPIO_BANK("F", 0x30, 0x34, 16),
 	EP93XX_GPIO_BANK("G", 0x38, 0x3c, 48),
 	EP93XX_GPIO_BANK("H", 0x40, 0x44, 56),
 };
diff --git a/arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h b/arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h
index 9f4458c..22d6c9a 100644
--- a/arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h
+++ b/arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h
@@ -6,6 +6,40 @@
 #define __ASM_ARCH_EP93XX_REGS_H
 
 /*
+ * EP93xx Physical Memory Map:
+ *
+ * The ASDO pin is sampled at system reset to select a synchronous or
+ * asynchronous boot configuration.  When ASDO is "1" (i.e. pulled-up)
+ * the synchronous boot mode is selected.  When ASDO is "0" (i.e
+ * pulled-down) the asynchronous boot mode is selected.
+ *
+ * In synchronous boot mode nSDCE3 is decoded starting at physical address
+ * 0x00000000 and nCS0 is decoded starting at 0xf0000000.  For asynchronous
+ * boot mode they are swapped with nCS0 decoded at 0x00000000 ann nSDCE3
+ * decoded at 0xf0000000.
+ *
+ * There is known errata for the EP93xx dealing with External Memory
+ * Configurations.  Please refer to "AN273: EP93xx Silicon Rev E Design
+ * Guidelines" for more information.  This document can be found at:
+ *
+ *	http://www.cirrus.com/en/pubs/appNote/AN273REV4.pdf
+ */
+
+#define EP93XX_CS0_PHYS_BASE_ASYNC	0x00000000	/* ASDO Pin = 0 */
+#define EP93XX_SDCE3_PHYS_BASE_SYNC	0x00000000	/* ASDO Pin = 1 */
+#define EP93XX_CS1_PHYS_BASE		0x10000000
+#define EP93XX_CS2_PHYS_BASE		0x20000000
+#define EP93XX_CS3_PHYS_BASE		0x30000000
+#define EP93XX_PCMCIA_PHYS_BASE		0x40000000
+#define EP93XX_CS6_PHYS_BASE		0x60000000
+#define EP93XX_CS7_PHYS_BASE		0x70000000
+#define EP93XX_SDCE0_PHYS_BASE		0xc0000000
+#define EP93XX_SDCE1_PHYS_BASE		0xd0000000
+#define EP93XX_SDCE2_PHYS_BASE		0xe0000000
+#define EP93XX_SDCE3_PHYS_BASE_ASYNC	0xf0000000	/* ASDO Pin = 0 */
+#define EP93XX_CS0_PHYS_BASE_SYNC	0xf0000000	/* ASDO Pin = 1 */
+
+/*
  * EP93xx linux memory map:
  *
  * virt		phys		size
diff --git a/arch/arm/mach-ep93xx/include/mach/platform.h b/arch/arm/mach-ep93xx/include/mach/platform.h
index b5c1824..db2489d 100644
--- a/arch/arm/mach-ep93xx/include/mach/platform.h
+++ b/arch/arm/mach-ep93xx/include/mach/platform.h
@@ -4,17 +4,17 @@
 
 #ifndef __ASSEMBLY__
 
-void ep93xx_map_io(void);
-void ep93xx_init_irq(void);
-void ep93xx_init_time(unsigned long);
-void ep93xx_init_devices(void);
-extern struct sys_timer ep93xx_timer;
-
 struct ep93xx_eth_data
 {
 	unsigned char	dev_addr[6];
 	unsigned char	phy_id;
 };
 
+void ep93xx_map_io(void);
+void ep93xx_init_irq(void);
+void ep93xx_init_time(unsigned long);
+void ep93xx_register_eth(struct ep93xx_eth_data *data, int copy_addr);
+void ep93xx_init_devices(void);
+extern struct sys_timer ep93xx_timer;
 
 #endif
diff --git a/arch/arm/mach-ep93xx/include/mach/ts72xx.h b/arch/arm/mach-ep93xx/include/mach/ts72xx.h
index 30b318a..34ddec0 100644
--- a/arch/arm/mach-ep93xx/include/mach/ts72xx.h
+++ b/arch/arm/mach-ep93xx/include/mach/ts72xx.h
@@ -70,7 +70,7 @@
 
 
 #ifndef __ASSEMBLY__
-#include <asm/io.h>
+#include <linux/io.h>
 
 static inline int board_is_ts7200(void)
 {
diff --git a/arch/arm/mach-ep93xx/include/mach/uncompress.h b/arch/arm/mach-ep93xx/include/mach/uncompress.h
index 1fd2f17..16026c2 100644
--- a/arch/arm/mach-ep93xx/include/mach/uncompress.h
+++ b/arch/arm/mach-ep93xx/include/mach/uncompress.h
@@ -31,10 +31,19 @@
 	*((volatile unsigned int *)ptr) = value;
 }
 
+#if defined(CONFIG_EP93XX_EARLY_UART1)
+#define UART_BASE		EP93XX_UART1_PHYS_BASE
+#elif defined(CONFIG_EP93XX_EARLY_UART2)
+#define UART_BASE		EP93XX_UART2_PHYS_BASE
+#elif defined(CONFIG_EP93XX_EARLY_UART3)
+#define UART_BASE		EP93XX_UART3_PHYS_BASE
+#else
+#define UART_BASE		EP93XX_UART1_PHYS_BASE
+#endif
 
-#define PHYS_UART1_DATA		0x808c0000
-#define PHYS_UART1_FLAG		0x808c0018
-#define UART1_FLAG_TXFF		0x20
+#define PHYS_UART_DATA		(UART_BASE + 0x00)
+#define PHYS_UART_FLAG		(UART_BASE + 0x18)
+#define UART_FLAG_TXFF		0x20
 
 static inline void putc(int c)
 {
@@ -42,11 +51,11 @@
 
 	for (i = 0; i < 1000; i++) {
 		/* Transmit fifo not full?  */
-		if (!(__raw_readb(PHYS_UART1_FLAG) & UART1_FLAG_TXFF))
+		if (!(__raw_readb(PHYS_UART_FLAG) & UART_FLAG_TXFF))
 			break;
 	}
 
-	__raw_writeb(c, PHYS_UART1_DATA);
+	__raw_writeb(c, PHYS_UART_DATA);
 }
 
 static inline void flush(void)
diff --git a/arch/arm/mach-ep93xx/micro9.c b/arch/arm/mach-ep93xx/micro9.c
index de047a5..c219723 100644
--- a/arch/arm/mach-ep93xx/micro9.c
+++ b/arch/arm/mach-ep93xx/micro9.c
@@ -16,10 +16,9 @@
 #include <linux/mm.h>
 #include <linux/platform_device.h>
 #include <linux/sched.h>
-
+#include <linux/io.h>
 #include <linux/mtd/physmap.h>
 
-#include <asm/io.h>
 #include <mach/hardware.h>
 
 #include <asm/mach/arch.h>
@@ -29,38 +28,9 @@
        .phy_id                 = 0x1f,
 };
 
-static struct resource micro9_eth_resource[] = {
-       {
-               .start  = EP93XX_ETHERNET_PHYS_BASE,
-               .end    = EP93XX_ETHERNET_PHYS_BASE + 0xffff,
-               .flags  = IORESOURCE_MEM,
-       }, {
-               .start  = IRQ_EP93XX_ETHERNET,
-               .end    = IRQ_EP93XX_ETHERNET,
-               .flags  = IORESOURCE_IRQ,
-       }
-};
-
-static struct platform_device micro9_eth_device = {
-       .name           = "ep93xx-eth",
-       .id             = -1,
-       .dev            = {
-               .platform_data  = &micro9_eth_data,
-       },
-       .num_resources = ARRAY_SIZE(micro9_eth_resource),
-       .resource       = micro9_eth_resource,
-};
-
-static void __init micro9_eth_init(void)
-{
-       memcpy(micro9_eth_data.dev_addr,
-               (void *)(EP93XX_ETHERNET_BASE + 0x50), 6);
-       platform_device_register(&micro9_eth_device);
-}
-
 static void __init micro9_init(void)
 {
-       micro9_eth_init();
+	ep93xx_register_eth(&micro9_eth_data, 1);
 }
 
 /*
diff --git a/arch/arm/mach-ep93xx/ts72xx.c b/arch/arm/mach-ep93xx/ts72xx.c
index c3cbff1..b4aa4c0 100644
--- a/arch/arm/mach-ep93xx/ts72xx.c
+++ b/arch/arm/mach-ep93xx/ts72xx.c
@@ -19,7 +19,7 @@
 #include <linux/mtd/physmap.h>
 #include <linux/platform_device.h>
 #include <linux/m48t86.h>
-#include <asm/io.h>
+#include <linux/io.h>
 #include <mach/hardware.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
@@ -161,28 +161,6 @@
 	.phy_id			= 1,
 };
 
-static struct resource ts72xx_eth_resource[] = {
-	{
-		.start	= EP93XX_ETHERNET_PHYS_BASE,
-		.end	= EP93XX_ETHERNET_PHYS_BASE + 0xffff,
-		.flags	= IORESOURCE_MEM,
-	}, {
-		.start	= IRQ_EP93XX_ETHERNET,
-		.end	= IRQ_EP93XX_ETHERNET,
-		.flags	= IORESOURCE_IRQ,
-	}
-};
-
-static struct platform_device ts72xx_eth_device = {
-	.name		= "ep93xx-eth",
-	.id		= -1,
-	.dev		= {
-		.platform_data	= &ts72xx_eth_data,
-	},
-	.num_resources	= 2,
-	.resource	= ts72xx_eth_resource,
-};
-
 static void __init ts72xx_init_machine(void)
 {
 	ep93xx_init_devices();
@@ -190,9 +168,7 @@
 		platform_device_register(&ts72xx_flash);
 	platform_device_register(&ts72xx_rtc_device);
 
-	memcpy(ts72xx_eth_data.dev_addr,
-		(void *)(EP93XX_ETHERNET_BASE + 0x50), 6);
-	platform_device_register(&ts72xx_eth_device);
+	ep93xx_register_eth(&ts72xx_eth_data, 1);
 }
 
 MACHINE_START(TS72XX, "Technologic Systems TS-72xx SBC")
diff --git a/arch/arm/mach-footbridge/cats-hw.c b/arch/arm/mach-footbridge/cats-hw.c
index c261472..6a5b437 100644
--- a/arch/arm/mach-footbridge/cats-hw.c
+++ b/arch/arm/mach-footbridge/cats-hw.c
@@ -9,9 +9,9 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/screen_info.h>
+#include <linux/io.h>
 
 #include <asm/hardware/dec21285.h>
-#include <asm/io.h>
 #include <asm/mach-types.h>
 #include <asm/setup.h>
 
diff --git a/arch/arm/mach-footbridge/common.c b/arch/arm/mach-footbridge/common.c
index b08ab50..818014e 100644
--- a/arch/arm/mach-footbridge/common.c
+++ b/arch/arm/mach-footbridge/common.c
@@ -13,11 +13,11 @@
 #include <linux/ioport.h>
 #include <linux/list.h>
 #include <linux/init.h>
+#include <linux/io.h>
  
 #include <asm/pgtable.h>
 #include <asm/page.h>
 #include <asm/irq.h>
-#include <asm/io.h>
 #include <asm/mach-types.h>
 #include <asm/setup.h>
 #include <asm/hardware/dec21285.h>
diff --git a/arch/arm/mach-footbridge/dc21285.c b/arch/arm/mach-footbridge/dc21285.c
index d0dc51e..d4c1e52 100644
--- a/arch/arm/mach-footbridge/dc21285.c
+++ b/arch/arm/mach-footbridge/dc21285.c
@@ -16,8 +16,8 @@
 #include <linux/init.h>
 #include <linux/ioport.h>
 #include <linux/irq.h>
+#include <linux/io.h>
 
-#include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/system.h>
 #include <asm/mach/pci.h>
diff --git a/arch/arm/mach-footbridge/dma.c b/arch/arm/mach-footbridge/dma.c
index 1f9b09b..b653e9c 100644
--- a/arch/arm/mach-footbridge/dma.c
+++ b/arch/arm/mach-footbridge/dma.c
@@ -11,9 +11,9 @@
  *			ISA DMA controllers.
  */
 #include <linux/init.h>
+#include <linux/io.h>
 
 #include <asm/dma.h>
-#include <asm/io.h>
 #include <asm/scatterlist.h>
 
 #include <asm/mach/dma.h>
diff --git a/arch/arm/mach-footbridge/include/mach/memory.h b/arch/arm/mach-footbridge/include/mach/memory.h
index e9cae99..6ae2f1a 100644
--- a/arch/arm/mach-footbridge/include/mach/memory.h
+++ b/arch/arm/mach-footbridge/include/mach/memory.h
@@ -42,10 +42,6 @@
 
 #endif
 
-/* Task size and page offset at 3GB */
-#define TASK_SIZE		UL(0xbf000000)
-#define PAGE_OFFSET		UL(0xc0000000)
-
 /*
  * Cache flushing area.
  */
@@ -56,12 +52,6 @@
  */
 #define PHYS_OFFSET		UL(0x00000000)
 
-/*
- * This decides where the kernel will search for a free chunk of vm
- * space during mmap's.
- */
-#define TASK_UNMAPPED_BASE ((TASK_SIZE + 0x01000000) / 3)
-
 #define FLUSH_BASE_PHYS		0x50000000
 
 #endif
diff --git a/arch/arm/mach-footbridge/include/mach/system.h b/arch/arm/mach-footbridge/include/mach/system.h
index 01c9f40..2db7f36 100644
--- a/arch/arm/mach-footbridge/include/mach/system.h
+++ b/arch/arm/mach-footbridge/include/mach/system.h
@@ -7,8 +7,8 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  */
+#include <linux/io.h>
 #include <asm/hardware/dec21285.h>
-#include <asm/io.h>
 #include <mach/hardware.h>
 #include <asm/leds.h>
 #include <asm/mach-types.h>
diff --git a/arch/arm/mach-footbridge/isa-irq.c b/arch/arm/mach-footbridge/isa-irq.c
index 7132e52..54fec9a 100644
--- a/arch/arm/mach-footbridge/isa-irq.c
+++ b/arch/arm/mach-footbridge/isa-irq.c
@@ -18,13 +18,13 @@
 #include <linux/interrupt.h>
 #include <linux/list.h>
 #include <linux/init.h>
+#include <linux/io.h>
 
 #include <asm/mach/irq.h>
 
 #include <mach/hardware.h>
 #include <asm/hardware/dec21285.h>
 #include <asm/irq.h>
-#include <asm/io.h>
 #include <asm/mach-types.h>
 
 static void isa_mask_pic_lo_irq(unsigned int irq)
@@ -94,8 +94,7 @@
 		return;
 	}
 
-	desc = irq_desc + isa_irq;
-	desc_handle_irq(isa_irq, desc);
+	generic_handle_irq(isa_irq);
 }
 
 static struct irqaction irq_cascade = {
diff --git a/arch/arm/mach-footbridge/isa-timer.c b/arch/arm/mach-footbridge/isa-timer.c
index a764e01..0c83900 100644
--- a/arch/arm/mach-footbridge/isa-timer.c
+++ b/arch/arm/mach-footbridge/isa-timer.c
@@ -7,8 +7,8 @@
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/irq.h>
+#include <linux/io.h>
 
-#include <asm/io.h>
 #include <asm/irq.h>
 
 #include <asm/mach/time.h>
diff --git a/arch/arm/mach-footbridge/netwinder-hw.c b/arch/arm/mach-footbridge/netwinder-hw.c
index a1f381c..00b0ddc 100644
--- a/arch/arm/mach-footbridge/netwinder-hw.c
+++ b/arch/arm/mach-footbridge/netwinder-hw.c
@@ -10,9 +10,9 @@
 #include <linux/kernel.h>
 #include <linux/delay.h>
 #include <linux/init.h>
+#include <linux/io.h>
 
 #include <asm/hardware/dec21285.h>
-#include <asm/io.h>
 #include <asm/leds.h>
 #include <asm/mach-types.h>
 #include <asm/setup.h>
diff --git a/arch/arm/mach-footbridge/time.c b/arch/arm/mach-footbridge/time.c
index 004819e..cd1b54f 100644
--- a/arch/arm/mach-footbridge/time.c
+++ b/arch/arm/mach-footbridge/time.c
@@ -22,9 +22,9 @@
 #include <linux/sched.h>
 #include <linux/mc146818rtc.h>
 #include <linux/bcd.h>
+#include <linux/io.h>
 
 #include <mach/hardware.h>
-#include <asm/io.h>
 
 #include <asm/mach/time.h>
 #include "common.h"
diff --git a/arch/arm/mach-h720x/common.c b/arch/arm/mach-h720x/common.c
index b5f9741..7a26148 100644
--- a/arch/arm/mach-h720x/common.c
+++ b/arch/arm/mach-h720x/common.c
@@ -18,11 +18,11 @@
 #include <linux/mman.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
+#include <linux/io.h>
 
 #include <asm/page.h>
 #include <asm/pgtable.h>
 #include <asm/dma.h>
-#include <asm/io.h>
 #include <mach/hardware.h>
 #include <asm/irq.h>
 #include <asm/mach/irq.h>
@@ -104,14 +104,12 @@
                  struct irq_desc *desc)
 {
 	IRQDBG("%s irq: %d\n", __func__, irq);
-	desc = irq_desc + irq;
 	while (mask) {
 		if (mask & 1) {
 			IRQDBG("handling irq %d\n", irq);
-			desc_handle_irq(irq, desc);
+			generic_handle_irq(irq);
 		}
 		irq++;
-		desc++;
 		mask >>= 1;
 	}
 }
diff --git a/arch/arm/mach-h720x/cpu-h7202.c b/arch/arm/mach-h720x/cpu-h7202.c
index 53e1f62..fd33a19 100644
--- a/arch/arm/mach-h720x/cpu-h7202.c
+++ b/arch/arm/mach-h720x/cpu-h7202.c
@@ -120,12 +120,10 @@
 
 	mask >>= 1;
 	irq = IRQ_TIMER1;
-	desc = irq_desc + irq;
 	while (mask) {
 		if (mask & 1)
-			desc_handle_irq(irq, desc);
+			generic_handle_irq(irq);
 		irq++;
-		desc++;
 		mask >>= 1;
 	}
 }
diff --git a/arch/arm/mach-imx/clock.c b/arch/arm/mach-imx/clock.c
index 4b4230d..7ec60fc 100644
--- a/arch/arm/mach-imx/clock.c
+++ b/arch/arm/mach-imx/clock.c
@@ -21,8 +21,8 @@
 #include <linux/list.h>
 #include <linux/math64.h>
 #include <linux/err.h>
+#include <linux/io.h>
 
-#include <asm/io.h>
 #include <mach/imx-regs.h>
 
 /*
diff --git a/arch/arm/mach-imx/include/mach/irqs.h b/arch/arm/mach-imx/include/mach/irqs.h
index eb8d5bd..67812c5a 100644
--- a/arch/arm/mach-imx/include/mach/irqs.h
+++ b/arch/arm/mach-imx/include/mach/irqs.h
@@ -111,6 +111,11 @@
 /* decode irq number to use with IMR(x), ISR(x) and friends */
 #define IRQ_TO_REG(irq) ((irq - IMX_IRQS) >> 5)
 
+/* all normal IRQs can be FIQs */
+#define FIQ_START	0
+/* switch betwean IRQ and FIQ */
+extern int imx_set_irq_fiq(unsigned int irq, unsigned int type);
+
 #define NR_IRQS (IRQ_GPIOD(32) + 1)
 #define IRQ_GPIO(x)
 #endif
diff --git a/arch/arm/mach-imx/irq.c b/arch/arm/mach-imx/irq.c
index 798f221..531b95d 100644
--- a/arch/arm/mach-imx/irq.c
+++ b/arch/arm/mach-imx/irq.c
@@ -26,20 +26,17 @@
 #include <linux/init.h>
 #include <linux/list.h>
 #include <linux/timer.h>
+#include <linux/io.h>
 
 #include <mach/hardware.h>
 #include <asm/irq.h>
-#include <asm/io.h>
 
 #include <asm/mach/irq.h>
 
 /*
  *
  * We simply use the ENABLE DISABLE registers inside of the IMX
- * to turn on/off specific interrupts.  FIXME- We should
- * also add support for the accelerated interrupt controller
- * by putting offets to irq jump code in the appropriate
- * places.
+ * to turn on/off specific interrupts.
  *
  */
 
@@ -102,6 +99,28 @@
 	__raw_writel(irq, IMX_AITC_INTENNUM);
 }
 
+#ifdef CONFIG_FIQ
+int imx_set_irq_fiq(unsigned int irq, unsigned int type)
+{
+	unsigned int irqt;
+
+	if (irq >= IMX_IRQS)
+		return -EINVAL;
+
+	if (irq < IMX_IRQS / 2) {
+		irqt = __raw_readl(IMX_AITC_INTTYPEL) & ~(1 << irq);
+		__raw_writel(irqt | (!!type << irq), IMX_AITC_INTTYPEL);
+	} else {
+		irq -= IMX_IRQS / 2;
+		irqt = __raw_readl(IMX_AITC_INTTYPEH) & ~(1 << irq);
+		__raw_writel(irqt | (!!type << irq), IMX_AITC_INTTYPEH);
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(imx_set_irq_fiq);
+#endif /* CONFIG_FIQ */
+
 static int
 imx_gpio_irq_type(unsigned int _irq, unsigned int type)
 {
@@ -182,14 +201,12 @@
 imx_gpio_handler(unsigned int mask, unsigned int irq,
                  struct irq_desc *desc)
 {
-	desc = irq_desc + irq;
 	while (mask) {
 		if (mask & 1) {
 			DEBUG_IRQ("handling irq %d\n", irq);
-			desc_handle_irq(irq, desc);
+			generic_handle_irq(irq);
 		}
 		irq++;
-		desc++;
 		mask >>= 1;
 	}
 }
@@ -286,4 +303,9 @@
 
 	/* Release masking of interrupts according to priority */
 	__raw_writel(-1, IMX_AITC_NIMASK);
+
+#ifdef CONFIG_FIQ
+	/* Initialize FIQ */
+	init_FIQ();
+#endif
 }
diff --git a/arch/arm/mach-imx/leds-mx1ads.c b/arch/arm/mach-imx/leds-mx1ads.c
index af81621..1d48f27 100644
--- a/arch/arm/mach-imx/leds-mx1ads.c
+++ b/arch/arm/mach-imx/leds-mx1ads.c
@@ -13,9 +13,9 @@
 
 #include <linux/kernel.h>
 #include <linux/init.h>
+#include <linux/io.h>
 #include <mach/hardware.h>
 #include <asm/system.h>
-#include <asm/io.h>
 #include <asm/leds.h>
 #include "leds.h"
 
diff --git a/arch/arm/mach-imx/time.c b/arch/arm/mach-imx/time.c
index 08be387..a11765f 100644
--- a/arch/arm/mach-imx/time.c
+++ b/arch/arm/mach-imx/time.c
@@ -18,9 +18,9 @@
 #include <linux/clocksource.h>
 #include <linux/clockchips.h>
 #include <linux/clk.h>
+#include <linux/io.h>
 
 #include <mach/hardware.h>
-#include <asm/io.h>
 #include <asm/leds.h>
 #include <asm/irq.h>
 #include <asm/mach/time.h>
diff --git a/arch/arm/mach-integrator/core.c b/arch/arm/mach-integrator/core.c
index 8bacf6d4..595b739 100644
--- a/arch/arm/mach-integrator/core.c
+++ b/arch/arm/mach-integrator/core.c
@@ -19,10 +19,10 @@
 #include <linux/termios.h>
 #include <linux/amba/bus.h>
 #include <linux/amba/serial.h>
+#include <linux/io.h>
 
 #include <mach/hardware.h>
 #include <asm/irq.h>
-#include <asm/io.h>
 #include <asm/hardware/arm_timer.h>
 #include <mach/cm.h>
 #include <asm/system.h>
diff --git a/arch/arm/mach-integrator/cpu.c b/arch/arm/mach-integrator/cpu.c
index 7c49d55..e4f72d2 100644
--- a/arch/arm/mach-integrator/cpu.c
+++ b/arch/arm/mach-integrator/cpu.c
@@ -17,9 +17,9 @@
 #include <linux/sched.h>
 #include <linux/smp.h>
 #include <linux/init.h>
+#include <linux/io.h>
 
 #include <mach/hardware.h>
-#include <asm/io.h>
 #include <asm/mach-types.h>
 #include <asm/hardware/icst525.h>
 
diff --git a/arch/arm/mach-integrator/impd1.c b/arch/arm/mach-integrator/impd1.c
index 3c8383d..172299a 100644
--- a/arch/arm/mach-integrator/impd1.c
+++ b/arch/arm/mach-integrator/impd1.c
@@ -20,8 +20,8 @@
 #include <linux/mm.h>
 #include <linux/amba/bus.h>
 #include <linux/amba/clcd.h>
+#include <linux/io.h>
 
-#include <asm/io.h>
 #include <asm/hardware/icst525.h>
 #include <mach/lm.h>
 #include <mach/impd1.h>
diff --git a/arch/arm/mach-integrator/integrator_ap.c b/arch/arm/mach-integrator/integrator_ap.c
index 6e472b5..8138a7e 100644
--- a/arch/arm/mach-integrator/integrator_ap.c
+++ b/arch/arm/mach-integrator/integrator_ap.c
@@ -27,9 +27,9 @@
 #include <linux/sysdev.h>
 #include <linux/amba/bus.h>
 #include <linux/amba/kmi.h>
+#include <linux/io.h>
 
 #include <mach/hardware.h>
-#include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/setup.h>
 #include <asm/param.h>		/* HZ */
diff --git a/arch/arm/mach-integrator/integrator_cp.c b/arch/arm/mach-integrator/integrator_cp.c
index 6b99e9c..88026cc 100644
--- a/arch/arm/mach-integrator/integrator_cp.c
+++ b/arch/arm/mach-integrator/integrator_cp.c
@@ -19,9 +19,9 @@
 #include <linux/amba/bus.h>
 #include <linux/amba/kmi.h>
 #include <linux/amba/clcd.h>
+#include <linux/io.h>
 
 #include <mach/hardware.h>
-#include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/setup.h>
 #include <asm/mach-types.h>
@@ -217,8 +217,7 @@
 
 		irq += IRQ_SIC_START;
 
-		desc = irq_desc + irq;
-		desc_handle_irq(irq, desc);
+		generic_handle_irq(irq);
 	} while (status);
 }
 
diff --git a/arch/arm/mach-integrator/leds.c b/arch/arm/mach-integrator/leds.c
index 7bc6881..8dcc823 100644
--- a/arch/arm/mach-integrator/leds.c
+++ b/arch/arm/mach-integrator/leds.c
@@ -24,9 +24,9 @@
 #include <linux/init.h>
 #include <linux/smp.h>
 #include <linux/spinlock.h>
+#include <linux/io.h>
 
 #include <mach/hardware.h>
-#include <asm/io.h>
 #include <asm/leds.h>
 #include <asm/system.h>
 #include <asm/mach-types.h>
diff --git a/arch/arm/mach-integrator/pci_v3.c b/arch/arm/mach-integrator/pci_v3.c
index 9f2b1ea..f1d72b2 100644
--- a/arch/arm/mach-integrator/pci_v3.c
+++ b/arch/arm/mach-integrator/pci_v3.c
@@ -27,9 +27,9 @@
 #include <linux/interrupt.h>
 #include <linux/spinlock.h>
 #include <linux/init.h>
+#include <linux/io.h>
 
 #include <mach/hardware.h>
-#include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/system.h>
 #include <asm/mach/pci.h>
diff --git a/arch/arm/mach-iop13xx/include/mach/memory.h b/arch/arm/mach-iop13xx/include/mach/memory.h
index e8b59d8..b82602d 100644
--- a/arch/arm/mach-iop13xx/include/mach/memory.h
+++ b/arch/arm/mach-iop13xx/include/mach/memory.h
@@ -7,9 +7,6 @@
  * Physical DRAM offset.
  */
 #define PHYS_OFFSET	UL(0x00000000)
-#define TASK_SIZE  	UL(0x3f000000)
-#define PAGE_OFFSET	UL(0x40000000)
-#define TASK_UNMAPPED_BASE ((TASK_SIZE + 0x01000000) / 3)
 
 #ifndef __ASSEMBLY__
 
@@ -29,32 +26,52 @@
 
 /* RAM has 1:1 mapping on the PCIe/x Busses */
 #define __virt_to_bus(x)	(__virt_to_phys(x))
-#define __bus_to_virt(x)    (__phys_to_virt(x))
+#define __bus_to_virt(x)	(__phys_to_virt(x))
 
-#define virt_to_lbus(x) 					   \
-(( ((void*)(x) >= (void*)IOP13XX_PMMR_V_START) &&		   \
-((void*)(x) < (void*)IOP13XX_PMMR_V_END) ) ? 			   \
-((x) - IOP13XX_PMMR_VIRT_MEM_BASE + IOP13XX_PMMR_PHYS_MEM_BASE) : \
-((x) - PAGE_OFFSET + PHYS_OFFSET))
+static inline dma_addr_t __virt_to_lbus(unsigned long x)
+{
+	return x + IOP13XX_PMMR_PHYS_MEM_BASE - IOP13XX_PMMR_VIRT_MEM_BASE;
+}
 
-#define lbus_to_virt(x)                                            \
-(( ((x) >= IOP13XX_PMMR_P_START) && ((x) < IOP13XX_PMMR_P_END) ) ? \
-((x) - IOP13XX_PMMR_PHYS_MEM_BASE + IOP13XX_PMMR_VIRT_MEM_BASE ) : \
-((x) - PHYS_OFFSET + PAGE_OFFSET))
+static inline unsigned long __lbus_to_virt(dma_addr_t x)
+{
+	return x + IOP13XX_PMMR_VIRT_MEM_BASE - IOP13XX_PMMR_PHYS_MEM_BASE;
+}
+
+#define __is_lbus_dma(a)				\
+	((a) >= IOP13XX_PMMR_P_START && (a) < IOP13XX_PMMR_P_END)
+
+#define __is_lbus_virt(a)				\
+	((a) >= IOP13XX_PMMR_V_START && (a) < IOP13XX_PMMR_V_END)
 
 /* Device is an lbus device if it is on the platform bus of the IOP13XX */
-#define is_lbus_device(dev) (dev &&\
-			     (strncmp(dev->bus->name, "platform", 8) == 0))
+#define is_lbus_device(dev) 				\
+	(dev && strncmp(dev->bus->name, "platform", 8) == 0)
+
+#define __arch_dma_to_virt(dev, addr)					\
+	({								\
+		unsigned long __virt;					\
+		dma_addr_t __dma = addr;				\
+		if (is_lbus_device(dev) && __is_lbus_dma(__dma))	\
+			__virt = __lbus_to_virt(__dma);			\
+		else							\
+			__virt = __bus_to_virt(__dma);			\
+		(void *)__virt;						\
+	})
+
+#define __arch_virt_to_dma(dev, addr)					\
+	({								\
+		unsigned long __virt = (unsigned long)addr;		\
+		dma_addr_t __dma;					\
+		if (is_lbus_device(dev) && __is_lbus_virt(__virt))	\
+			__dma = __virt_to_lbus(__virt);			\
+		else							\
+			__dma = __virt_to_bus(__virt);			\
+		__dma;							\
+	})
 
 #define __arch_page_to_dma(dev, page)					\
-({is_lbus_device(dev) ? (dma_addr_t)virt_to_lbus(page_address(page)) : \
-(dma_addr_t)__virt_to_bus(page_address(page));})
-
-#define __arch_dma_to_virt(dev, addr) \
-({is_lbus_device(dev) ? lbus_to_virt(addr) : __bus_to_virt(addr);})
-
-#define __arch_virt_to_dma(dev, addr) \
-({is_lbus_device(dev) ? virt_to_lbus(addr) : __virt_to_bus(addr);})
+	__arch_virt_to_dma(dev, page_address(page))
 
 #endif /* CONFIG_ARCH_IOP13XX */
 #endif /* !ASSEMBLY */
diff --git a/arch/arm/mach-iop13xx/include/mach/pci.h b/arch/arm/mach-iop13xx/include/mach/pci.h
index 17b5515..59f42b5 100644
--- a/arch/arm/mach-iop13xx/include/mach/pci.h
+++ b/arch/arm/mach-iop13xx/include/mach/pci.h
@@ -1,7 +1,7 @@
 #ifndef _IOP13XX_PCI_H_
 #define _IOP13XX_PCI_H_
+#include <linux/io.h>
 #include <mach/irqs.h>
-#include <asm/io.h>
 
 struct pci_sys_data;
 struct hw_pci;
diff --git a/arch/arm/mach-iop13xx/io.c b/arch/arm/mach-iop13xx/io.c
index 26cfa31..5295809 100644
--- a/arch/arm/mach-iop13xx/io.c
+++ b/arch/arm/mach-iop13xx/io.c
@@ -18,8 +18,8 @@
  */
 #include <linux/kernel.h>
 #include <linux/module.h>
+#include <linux/io.h>
 #include <mach/hardware.h>
-#include <asm/io.h>
 
 void * __iomem __iop13xx_io(unsigned long io_addr)
 {
diff --git a/arch/arm/mach-iop13xx/msi.c b/arch/arm/mach-iop13xx/msi.c
index 63ef1124c..f34b0ed 100644
--- a/arch/arm/mach-iop13xx/msi.c
+++ b/arch/arm/mach-iop13xx/msi.c
@@ -110,8 +110,7 @@
 		do {
 			j = find_first_bit(&status, 32);
 			(write_imipr[i])(1 << j); /* write back to clear bit */
-			desc = irq_desc + IRQ_IOP13XX_MSI_0 + j + (32*i);
-			desc_handle_irq(IRQ_IOP13XX_MSI_0 + j + (32*i),	desc);
+			generic_handle_irq(IRQ_IOP13XX_MSI_0 + j + (32*i));
 			status = (read_imipr[i])();
 		} while (status);
 	}
diff --git a/arch/arm/mach-iop13xx/setup.c b/arch/arm/mach-iop13xx/setup.c
index b17ccc8..cfd4d2e 100644
--- a/arch/arm/mach-iop13xx/setup.c
+++ b/arch/arm/mach-iop13xx/setup.c
@@ -18,13 +18,13 @@
  */
 
 #include <linux/serial_8250.h>
+#include <linux/io.h>
 #ifdef CONFIG_MTD_PHYSMAP
 #include <linux/mtd/physmap.h>
 #endif
 #include <asm/mach/map.h>
 #include <mach/hardware.h>
 #include <asm/irq.h>
-#include <asm/io.h>
 #include <asm/hardware/iop_adma.h>
 
 #define IOP13XX_UART_XTAL 33334000
diff --git a/arch/arm/mach-iop13xx/tpmi.c b/arch/arm/mach-iop13xx/tpmi.c
index 2476347..c6af1e1 100644
--- a/arch/arm/mach-iop13xx/tpmi.c
+++ b/arch/arm/mach-iop13xx/tpmi.c
@@ -21,7 +21,7 @@
 #include <linux/init.h>
 #include <linux/platform_device.h>
 #include <linux/dma-mapping.h>
-#include <asm/io.h>
+#include <linux/io.h>
 #include <asm/irq.h>
 #include <asm/sizes.h>
 
diff --git a/arch/arm/mach-iop32x/glantank.c b/arch/arm/mach-iop32x/glantank.c
index 45d6127..a9c2dfd 100644
--- a/arch/arm/mach-iop32x/glantank.c
+++ b/arch/arm/mach-iop32x/glantank.c
@@ -25,8 +25,8 @@
 #include <linux/mtd/physmap.h>
 #include <linux/i2c.h>
 #include <linux/platform_device.h>
+#include <linux/io.h>
 #include <mach/hardware.h>
-#include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
diff --git a/arch/arm/mach-iop32x/iq31244.c b/arch/arm/mach-iop32x/iq31244.c
index 082818aa..dd1cd99 100644
--- a/arch/arm/mach-iop32x/iq31244.c
+++ b/arch/arm/mach-iop32x/iq31244.c
@@ -26,8 +26,9 @@
 #include <linux/serial_8250.h>
 #include <linux/mtd/physmap.h>
 #include <linux/platform_device.h>
+#include <linux/io.h>
 #include <mach/hardware.h>
-#include <asm/io.h>
+#include <asm/cputype.h>
 #include <asm/irq.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
@@ -49,8 +50,7 @@
 
 static int is_80219(void)
 {
-	extern int processor_id;
-	return !!((processor_id & 0xffffffe0) == 0x69052e20);
+	return !!((read_cpuid_id() & 0xffffffe0) == 0x69052e20);
 }
 
 static int is_ep80219(void)
diff --git a/arch/arm/mach-iop32x/iq80321.c b/arch/arm/mach-iop32x/iq80321.c
index d735539..fbe2779 100644
--- a/arch/arm/mach-iop32x/iq80321.c
+++ b/arch/arm/mach-iop32x/iq80321.c
@@ -23,8 +23,8 @@
 #include <linux/serial_8250.h>
 #include <linux/mtd/physmap.h>
 #include <linux/platform_device.h>
+#include <linux/io.h>
 #include <mach/hardware.h>
-#include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
diff --git a/arch/arm/mach-iop32x/n2100.c b/arch/arm/mach-iop32x/n2100.c
index 3173f9c..d2e4278 100644
--- a/arch/arm/mach-iop32x/n2100.c
+++ b/arch/arm/mach-iop32x/n2100.c
@@ -30,8 +30,8 @@
 #include <linux/i2c.h>
 #include <linux/platform_device.h>
 #include <linux/reboot.h>
+#include <linux/io.h>
 #include <mach/hardware.h>
-#include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
diff --git a/arch/arm/mach-iop33x/iq80331.c b/arch/arm/mach-iop33x/iq80331.c
index c7d99f9..d51e10c 100644
--- a/arch/arm/mach-iop33x/iq80331.c
+++ b/arch/arm/mach-iop33x/iq80331.c
@@ -22,8 +22,8 @@
 #include <linux/serial_8250.h>
 #include <linux/mtd/physmap.h>
 #include <linux/platform_device.h>
+#include <linux/io.h>
 #include <mach/hardware.h>
-#include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
diff --git a/arch/arm/mach-iop33x/iq80332.c b/arch/arm/mach-iop33x/iq80332.c
index af616c5..92fb44c 100644
--- a/arch/arm/mach-iop33x/iq80332.c
+++ b/arch/arm/mach-iop33x/iq80332.c
@@ -22,8 +22,8 @@
 #include <linux/serial_8250.h>
 #include <linux/mtd/physmap.h>
 #include <linux/platform_device.h>
+#include <linux/io.h>
 #include <mach/hardware.h>
-#include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
diff --git a/arch/arm/mach-iop33x/uart.c b/arch/arm/mach-iop33x/uart.c
index 8c21870..cdae24e 100644
--- a/arch/arm/mach-iop33x/uart.c
+++ b/arch/arm/mach-iop33x/uart.c
@@ -17,7 +17,7 @@
 #include <linux/serial.h>
 #include <linux/tty.h>
 #include <linux/serial_8250.h>
-#include <asm/io.h>
+#include <linux/io.h>
 #include <asm/pgtable.h>
 #include <asm/page.h>
 #include <asm/mach/map.h>
diff --git a/arch/arm/mach-ixp2000/core.c b/arch/arm/mach-ixp2000/core.c
index a6a4f93..babb225 100644
--- a/arch/arm/mach-ixp2000/core.c
+++ b/arch/arm/mach-ixp2000/core.c
@@ -84,64 +84,57 @@
 		.virtual	= IXP2000_CAP_VIRT_BASE,
 		.pfn		= __phys_to_pfn(IXP2000_CAP_PHYS_BASE),
 		.length		= IXP2000_CAP_SIZE,
-		.type		= MT_DEVICE_IXP2000,
+		.type		= MT_DEVICE,
 	}, {
 		.virtual	= IXP2000_INTCTL_VIRT_BASE,
 		.pfn		= __phys_to_pfn(IXP2000_INTCTL_PHYS_BASE),
 		.length		= IXP2000_INTCTL_SIZE,
-		.type		= MT_DEVICE_IXP2000,
+		.type		= MT_DEVICE,
 	}, {
 		.virtual	= IXP2000_PCI_CREG_VIRT_BASE,
 		.pfn		= __phys_to_pfn(IXP2000_PCI_CREG_PHYS_BASE),
 		.length		= IXP2000_PCI_CREG_SIZE,
-		.type		= MT_DEVICE_IXP2000,
+		.type		= MT_DEVICE,
 	}, {
 		.virtual	= IXP2000_PCI_CSR_VIRT_BASE,
 		.pfn		= __phys_to_pfn(IXP2000_PCI_CSR_PHYS_BASE),
 		.length		= IXP2000_PCI_CSR_SIZE,
-		.type		= MT_DEVICE_IXP2000,
+		.type		= MT_DEVICE,
 	}, {
 		.virtual	= IXP2000_MSF_VIRT_BASE,
 		.pfn		= __phys_to_pfn(IXP2000_MSF_PHYS_BASE),
 		.length		= IXP2000_MSF_SIZE,
-		.type		= MT_DEVICE_IXP2000,
+		.type		= MT_DEVICE,
 	}, {
 		.virtual	= IXP2000_SCRATCH_RING_VIRT_BASE,
 		.pfn		= __phys_to_pfn(IXP2000_SCRATCH_RING_PHYS_BASE),
 		.length		= IXP2000_SCRATCH_RING_SIZE,
-		.type		= MT_DEVICE_IXP2000,
+		.type		= MT_DEVICE,
 	}, {
 		.virtual	= IXP2000_SRAM0_VIRT_BASE,
 		.pfn		= __phys_to_pfn(IXP2000_SRAM0_PHYS_BASE),
 		.length		= IXP2000_SRAM0_SIZE,
-		.type		= MT_DEVICE_IXP2000,
+		.type		= MT_DEVICE,
 	}, {
 		.virtual	= IXP2000_PCI_IO_VIRT_BASE,
 		.pfn		= __phys_to_pfn(IXP2000_PCI_IO_PHYS_BASE),
 		.length		= IXP2000_PCI_IO_SIZE,
-		.type		= MT_DEVICE_IXP2000,
+		.type		= MT_DEVICE,
 	}, {
 		.virtual	= IXP2000_PCI_CFG0_VIRT_BASE,
 		.pfn		= __phys_to_pfn(IXP2000_PCI_CFG0_PHYS_BASE),
 		.length		= IXP2000_PCI_CFG0_SIZE,
-		.type		= MT_DEVICE_IXP2000,
+		.type		= MT_DEVICE,
 	}, {
 		.virtual	= IXP2000_PCI_CFG1_VIRT_BASE,
 		.pfn		= __phys_to_pfn(IXP2000_PCI_CFG1_PHYS_BASE),
 		.length		= IXP2000_PCI_CFG1_SIZE,
-		.type		= MT_DEVICE_IXP2000,
+		.type		= MT_DEVICE,
 	}
 };
 
 void __init ixp2000_map_io(void)
 {
-	/*
-	 * On IXP2400 CPUs we need to use MT_DEVICE_IXP2000 so that
-	 * XCB=101 (to avoid triggering erratum #66), and given that
-	 * this mode speeds up I/O accesses and we have write buffer
-	 * flushes in the right places anyway, it doesn't hurt to use
-	 * XCB=101 for all IXP2000s.
-	 */
 	iotable_init(ixp2000_io_desc, ARRAY_SIZE(ixp2000_io_desc));
 
 	/* Set slowport to 8-bit mode.  */
@@ -311,8 +304,7 @@
 		   
 	for (i = 0; i <= 7; i++) {
 		if (status & (1<<i)) {
-			desc = irq_desc + i + IRQ_IXP2000_GPIO0;
-			desc_handle_irq(i + IRQ_IXP2000_GPIO0, desc);
+			generic_handle_irq(i + IRQ_IXP2000_GPIO0);
 		}
 	}
 }
@@ -404,8 +396,7 @@
 
 	for(i = 31; i >= 0; i--) {
 		if(status & (1 << i)) {
-			desc = irq_desc + IRQ_IXP2000_DRAM0_MIN_ERR + i;
-			desc_handle_irq(IRQ_IXP2000_DRAM0_MIN_ERR + i, desc);
+			generic_handle_irq(IRQ_IXP2000_DRAM0_MIN_ERR + i);
 		}
 	}
 }
diff --git a/arch/arm/mach-ixp2000/enp2611.c b/arch/arm/mach-ixp2000/enp2611.c
index c62ed65..c84dfac 100644
--- a/arch/arm/mach-ixp2000/enp2611.c
+++ b/arch/arm/mach-ixp2000/enp2611.c
@@ -32,8 +32,8 @@
 #include <linux/tty.h>
 #include <linux/serial_core.h>
 #include <linux/platform_device.h>
+#include <linux/io.h>
 
-#include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/pgtable.h>
 #include <asm/page.h>
@@ -70,17 +70,17 @@
 		.virtual	= ENP2611_CALEB_VIRT_BASE,
 		.pfn		= __phys_to_pfn(ENP2611_CALEB_PHYS_BASE),
 		.length		= ENP2611_CALEB_SIZE,
-		.type		= MT_DEVICE_IXP2000,
+		.type		= MT_DEVICE,
 	}, {
 		.virtual	= ENP2611_PM3386_0_VIRT_BASE,
 		.pfn		= __phys_to_pfn(ENP2611_PM3386_0_PHYS_BASE),
 		.length		= ENP2611_PM3386_0_SIZE,
-		.type		= MT_DEVICE_IXP2000,
+		.type		= MT_DEVICE,
 	}, {
 		.virtual	= ENP2611_PM3386_1_VIRT_BASE,
 		.pfn		= __phys_to_pfn(ENP2611_PM3386_1_PHYS_BASE),
 		.length		= ENP2611_PM3386_1_SIZE,
-		.type		= MT_DEVICE_IXP2000,
+		.type		= MT_DEVICE,
 	}
 };
 
diff --git a/arch/arm/mach-ixp2000/include/mach/ixp2000-regs.h b/arch/arm/mach-ixp2000/include/mach/ixp2000-regs.h
index 19d8037..822f63f 100644
--- a/arch/arm/mach-ixp2000/include/mach/ixp2000-regs.h
+++ b/arch/arm/mach-ixp2000/include/mach/ixp2000-regs.h
@@ -41,13 +41,7 @@
  * Most of the registers are clumped in 4K regions spread throughout
  * the 0xc0000000 -> 0xc0100000 address range, but we just map in
  * the whole range using a single 1 MB section instead of small
- * 4K pages.  This has two advantages for us:
- *
- * 1) We use only one TLB entry for large number of on-chip I/O devices.
- *
- * 2) We can easily set the Section attributes to XCB=101 on the IXP2400
- *    as required per erratum #66.  We accomplish this by using a
- *    new MT_IXP2000_DEVICE memory type with the bits set as required.
+ * 4K pages.
  *
  * CAP stands for CSR Access Proxy.
  *
diff --git a/arch/arm/mach-ixp2000/ixdp2400.c b/arch/arm/mach-ixp2000/ixdp2400.c
index c673b9e..4467c42 100644
--- a/arch/arm/mach-ixp2000/ixdp2400.c
+++ b/arch/arm/mach-ixp2000/ixdp2400.c
@@ -25,8 +25,8 @@
 #include <linux/ioport.h>
 #include <linux/slab.h>
 #include <linux/delay.h>
+#include <linux/io.h>
 
-#include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/pgtable.h>
 #include <asm/page.h>
diff --git a/arch/arm/mach-ixp2000/ixdp2800.c b/arch/arm/mach-ixp2000/ixdp2800.c
index 6715b50..94f68ba 100644
--- a/arch/arm/mach-ixp2000/ixdp2800.c
+++ b/arch/arm/mach-ixp2000/ixdp2800.c
@@ -25,8 +25,8 @@
 #include <linux/ioport.h>
 #include <linux/slab.h>
 #include <linux/delay.h>
+#include <linux/io.h>
 
-#include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/pgtable.h>
 #include <asm/page.h>
diff --git a/arch/arm/mach-ixp2000/ixdp2x00.c b/arch/arm/mach-ixp2000/ixdp2x00.c
index 5a781fd..b0653a8 100644
--- a/arch/arm/mach-ixp2000/ixdp2x00.c
+++ b/arch/arm/mach-ixp2000/ixdp2x00.c
@@ -25,8 +25,8 @@
 #include <linux/ioport.h>
 #include <linux/slab.h>
 #include <linux/delay.h>
+#include <linux/io.h>
 
-#include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/pgtable.h>
 #include <asm/page.h>
@@ -129,10 +129,8 @@
 
 	for(i = 0; i < board_irq_count; i++) {
 		if(ex_interrupt & (1 << i))  {
-			struct irq_desc *cpld_desc;
 			int cpld_irq = IXP2000_BOARD_IRQ(0) + i;
-			cpld_desc = irq_desc + cpld_irq;
-			desc_handle_irq(cpld_irq, cpld_desc);
+			generic_handle_irq(cpld_irq);
 		}
 	}
 
diff --git a/arch/arm/mach-ixp2000/ixdp2x01.c b/arch/arm/mach-ixp2000/ixdp2x01.c
index 78a2341..4a12327a0 100644
--- a/arch/arm/mach-ixp2000/ixdp2x01.c
+++ b/arch/arm/mach-ixp2000/ixdp2x01.c
@@ -30,8 +30,8 @@
 #include <linux/serial_core.h>
 #include <linux/platform_device.h>
 #include <linux/serial_8250.h>
+#include <linux/io.h>
 
-#include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/pgtable.h>
 #include <asm/page.h>
@@ -79,10 +79,8 @@
 
 	for (i = 0; i < IXP2000_BOARD_IRQS; i++) {
 		if (ex_interrupt & (1 << i)) {
-			struct irq_desc *cpld_desc;
 			int cpld_irq = IXP2000_BOARD_IRQ(0) + i;
-			cpld_desc = irq_desc + cpld_irq;
-			desc_handle_irq(cpld_irq, cpld_desc);
+			generic_handle_irq(cpld_irq);
 		}
 	}
 
diff --git a/arch/arm/mach-ixp2000/pci.c b/arch/arm/mach-ixp2000/pci.c
index 03d916f..60e9fd0 100644
--- a/arch/arm/mach-ixp2000/pci.c
+++ b/arch/arm/mach-ixp2000/pci.c
@@ -24,8 +24,8 @@
 #include <linux/ioport.h>
 #include <linux/slab.h>
 #include <linux/delay.h>
+#include <linux/io.h>
 
-#include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/system.h>
 #include <mach/hardware.h>
diff --git a/arch/arm/mach-ixp23xx/core.c b/arch/arm/mach-ixp23xx/core.c
index 68b4ac5..aa4c442 100644
--- a/arch/arm/mach-ixp23xx/core.c
+++ b/arch/arm/mach-ixp23xx/core.c
@@ -253,7 +253,6 @@
 {
 	u32 pci_interrupt;
 	unsigned int irqno;
-	struct irq_desc *int_desc;
 
 	pci_interrupt = *IXP23XX_PCI_XSCALE_INT_STATUS;
 
@@ -268,8 +267,7 @@
 		BUG();
 	}
 
-	int_desc = irq_desc + irqno;
-	desc_handle_irq(irqno, int_desc);
+	generic_handle_irq(irqno);
 
 	desc->chip->unmask(irq);
 }
diff --git a/arch/arm/mach-ixp23xx/ixdp2351.c b/arch/arm/mach-ixp23xx/ixdp2351.c
index b6e0bfa..f1b124a 100644
--- a/arch/arm/mach-ixp23xx/ixdp2351.c
+++ b/arch/arm/mach-ixp23xx/ixdp2351.c
@@ -68,11 +68,9 @@
 
 	for (i = 0; i < IXDP2351_INTA_IRQ_NUM; i++) {
 		if (ex_interrupt & (1 << i)) {
-			struct irq_desc *cpld_desc;
 			int cpld_irq =
 				IXP23XX_MACH_IRQ(IXDP2351_INTA_IRQ_BASE + i);
-			cpld_desc = irq_desc + cpld_irq;
-			desc_handle_irq(cpld_irq, cpld_desc);
+			generic_handle_irq(cpld_irq);
 		}
 	}
 
@@ -105,11 +103,9 @@
 
 	for (i = 0; i < IXDP2351_INTB_IRQ_NUM; i++) {
 		if (ex_interrupt & (1 << i)) {
-			struct irq_desc *cpld_desc;
 			int cpld_irq =
 				IXP23XX_MACH_IRQ(IXDP2351_INTB_IRQ_BASE + i);
-			cpld_desc = irq_desc + cpld_irq;
-			desc_handle_irq(cpld_irq, cpld_desc);
+			generic_handle_irq(cpld_irq);
 		}
 	}
 
diff --git a/arch/arm/mach-ixp23xx/pci.c b/arch/arm/mach-ixp23xx/pci.c
index 701d60a..59022be 100644
--- a/arch/arm/mach-ixp23xx/pci.c
+++ b/arch/arm/mach-ixp23xx/pci.c
@@ -25,8 +25,8 @@
 #include <linux/ioport.h>
 #include <linux/slab.h>
 #include <linux/delay.h>
+#include <linux/io.h>
 
-#include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/sizes.h>
 #include <asm/system.h>
diff --git a/arch/arm/mach-ixp4xx/common-pci.c b/arch/arm/mach-ixp4xx/common-pci.c
index 192538a..d816c51 100644
--- a/arch/arm/mach-ixp4xx/common-pci.c
+++ b/arch/arm/mach-ixp4xx/common-pci.c
@@ -25,9 +25,10 @@
 #include <linux/slab.h>
 #include <linux/delay.h>
 #include <linux/device.h>
+#include <linux/io.h>
 #include <asm/dma-mapping.h>
 
-#include <asm/io.h>
+#include <asm/cputype.h>
 #include <asm/irq.h>
 #include <asm/sizes.h>
 #include <asm/system.h>
@@ -366,15 +367,13 @@
 
 void __init ixp4xx_pci_preinit(void)
 {  
-	unsigned long processor_id;
-
-	asm("mrc p15, 0, %0, cr0, cr0, 0;" : "=r"(processor_id) :);
+	unsigned long cpuid = read_cpuid_id();
 
 	/*
 	 * Determine which PCI read method to use.
 	 * Rev 0 IXP425 requires workaround.
 	 */
-	if (!(processor_id & 0xf) && cpu_is_ixp42x()) {
+	if (!(cpuid & 0xf) && cpu_is_ixp42x()) {
 		printk("PCI: IXP42x A0 silicon detected - "
 			"PCI Non-Prefetch Workaround Enabled\n");
 		ixp4xx_pci_read = ixp4xx_pci_read_errata;
diff --git a/arch/arm/mach-ixp4xx/common.c b/arch/arm/mach-ixp4xx/common.c
index 58bd284..7766f46 100644
--- a/arch/arm/mach-ixp4xx/common.c
+++ b/arch/arm/mach-ixp4xx/common.c
@@ -28,11 +28,11 @@
 #include <linux/timex.h>
 #include <linux/clocksource.h>
 #include <linux/clockchips.h>
+#include <linux/io.h>
 
 #include <mach/udc.h>
 #include <mach/hardware.h>
 #include <asm/uaccess.h>
-#include <asm/io.h>
 #include <asm/pgtable.h>
 #include <asm/page.h>
 #include <asm/irq.h>
diff --git a/arch/arm/mach-ixp4xx/fsg-setup.c b/arch/arm/mach-ixp4xx/fsg-setup.c
index 501dfdc..e7c6386 100644
--- a/arch/arm/mach-ixp4xx/fsg-setup.c
+++ b/arch/arm/mach-ixp4xx/fsg-setup.c
@@ -23,11 +23,11 @@
 #include <linux/reboot.h>
 #include <linux/i2c.h>
 #include <linux/i2c-gpio.h>
+#include <linux/io.h>
 
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/flash.h>
-#include <asm/io.h>
 #include <asm/gpio.h>
 
 static struct flash_platform_data fsg_flash_data = {
diff --git a/arch/arm/mach-ixp4xx/include/mach/cpu.h b/arch/arm/mach-ixp4xx/include/mach/cpu.h
index ff8aa23..51bd69c 100644
--- a/arch/arm/mach-ixp4xx/include/mach/cpu.h
+++ b/arch/arm/mach-ixp4xx/include/mach/cpu.h
@@ -14,18 +14,19 @@
 #ifndef __ASM_ARCH_CPU_H__
 #define __ASM_ARCH_CPU_H__
 
-extern unsigned int processor_id;
+#include <asm/cputype.h>
+
 /* Processor id value in CP15 Register 0 */
 #define IXP425_PROCESSOR_ID_VALUE	0x690541c0
 #define IXP435_PROCESSOR_ID_VALUE	0x69054040
 #define IXP465_PROCESSOR_ID_VALUE	0x69054200
 #define IXP4XX_PROCESSOR_ID_MASK	0xfffffff0
 
-#define cpu_is_ixp42x()	((processor_id & IXP4XX_PROCESSOR_ID_MASK) == \
+#define cpu_is_ixp42x()	((read_cpuid_id() & IXP4XX_PROCESSOR_ID_MASK) == \
 			  IXP425_PROCESSOR_ID_VALUE)
-#define cpu_is_ixp43x()	((processor_id & IXP4XX_PROCESSOR_ID_MASK) == \
+#define cpu_is_ixp43x()	((read_cpuid_id() & IXP4XX_PROCESSOR_ID_MASK) == \
 			  IXP435_PROCESSOR_ID_VALUE)
-#define cpu_is_ixp46x()	((processor_id & IXP4XX_PROCESSOR_ID_MASK) == \
+#define cpu_is_ixp46x()	((read_cpuid_id() & IXP4XX_PROCESSOR_ID_MASK) == \
 			  IXP465_PROCESSOR_ID_VALUE)
 
 static inline u32 ixp4xx_read_feature_bits(void)
diff --git a/arch/arm/mach-ixp4xx/ixdp425-setup.c b/arch/arm/mach-ixp4xx/ixdp425-setup.c
index 9b2d2ec..f4a0c1b 100644
--- a/arch/arm/mach-ixp4xx/ixdp425-setup.c
+++ b/arch/arm/mach-ixp4xx/ixdp425-setup.c
@@ -20,6 +20,7 @@
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/nand.h>
 #include <linux/mtd/partitions.h>
+#include <linux/delay.h>
 
 #include <asm/types.h>
 #include <asm/setup.h>
@@ -29,7 +30,6 @@
 #include <asm/irq.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/flash.h>
-#include <asm/delay.h>
 
 static struct flash_platform_data ixdp425_flash_data = {
 	.map_name	= "cfi_probe",
diff --git a/arch/arm/mach-ixp4xx/nas100d-setup.c b/arch/arm/mach-ixp4xx/nas100d-setup.c
index 84b5e62..0acd95e 100644
--- a/arch/arm/mach-ixp4xx/nas100d-setup.c
+++ b/arch/arm/mach-ixp4xx/nas100d-setup.c
@@ -28,11 +28,11 @@
 #include <linux/reboot.h>
 #include <linux/i2c.h>
 #include <linux/i2c-gpio.h>
+#include <linux/io.h>
 
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/flash.h>
-#include <asm/io.h>
 #include <asm/gpio.h>
 
 static struct flash_platform_data nas100d_flash_data = {
diff --git a/arch/arm/mach-ixp4xx/nslu2-setup.c b/arch/arm/mach-ixp4xx/nslu2-setup.c
index a48a665..bc9d920 100644
--- a/arch/arm/mach-ixp4xx/nslu2-setup.c
+++ b/arch/arm/mach-ixp4xx/nslu2-setup.c
@@ -25,12 +25,12 @@
 #include <linux/reboot.h>
 #include <linux/i2c.h>
 #include <linux/i2c-gpio.h>
+#include <linux/io.h>
 
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/flash.h>
 #include <asm/mach/time.h>
-#include <asm/io.h>
 #include <asm/gpio.h>
 
 static struct flash_platform_data nslu2_flash_data = {
diff --git a/arch/arm/mach-kirkwood/addr-map.c b/arch/arm/mach-kirkwood/addr-map.c
index c79f492..5db4f0b 100644
--- a/arch/arm/mach-kirkwood/addr-map.c
+++ b/arch/arm/mach-kirkwood/addr-map.c
@@ -48,6 +48,7 @@
 
 
 struct mbus_dram_target_info kirkwood_mbus_dram_info;
+static int __initdata win_alloc_count;
 
 static int __init cpu_win_can_remap(int win)
 {
@@ -111,6 +112,8 @@
 	setup_cpu_win(2, KIRKWOOD_NAND_MEM_PHYS_BASE, KIRKWOOD_NAND_MEM_SIZE,
 		      TARGET_DEV_BUS, ATTR_DEV_NAND, -1);
 
+	win_alloc_count = 3;
+
 	/*
 	 * Setup MBUS dram target info.
 	 */
@@ -137,3 +140,8 @@
 	}
 	kirkwood_mbus_dram_info.num_cs = cs;
 }
+
+void __init kirkwood_setup_sram_win(u32 base, u32 size)
+{
+	setup_cpu_win(win_alloc_count++, base, size, 0x03, 0x00, -1);
+}
diff --git a/arch/arm/mach-kirkwood/common.c b/arch/arm/mach-kirkwood/common.c
index 189f16f..85cad05 100644
--- a/arch/arm/mach-kirkwood/common.c
+++ b/arch/arm/mach-kirkwood/common.c
@@ -98,7 +98,6 @@
  * GE00
  ****************************************************************************/
 struct mv643xx_eth_shared_platform_data kirkwood_ge00_shared_data = {
-	.t_clk		= KIRKWOOD_TCLK,
 	.dram		= &kirkwood_mbus_dram_info,
 };
 
@@ -108,6 +107,11 @@
 		.start	= GE00_PHYS_BASE + 0x2000,
 		.end	= GE00_PHYS_BASE + 0x3fff,
 		.flags	= IORESOURCE_MEM,
+	}, {
+		.name	= "ge00 err irq",
+		.start	= IRQ_KIRKWOOD_GE00_ERR,
+		.end	= IRQ_KIRKWOOD_GE00_ERR,
+		.flags	= IORESOURCE_IRQ,
 	},
 };
 
@@ -117,7 +121,7 @@
 	.dev		= {
 		.platform_data	= &kirkwood_ge00_shared_data,
 	},
-	.num_resources	= 1,
+	.num_resources	= ARRAY_SIZE(kirkwood_ge00_shared_resources),
 	.resource	= kirkwood_ge00_shared_resources,
 };
 
@@ -201,7 +205,6 @@
  * SPI
  ****************************************************************************/
 static struct orion_spi_info kirkwood_spi_plat_data = {
-	.tclk		= KIRKWOOD_TCLK,
 };
 
 static struct resource kirkwood_spi_resources[] = {
@@ -239,7 +242,7 @@
 		.flags		= UPF_SKIP_TEST | UPF_BOOT_AUTOCONF,
 		.iotype		= UPIO_MEM,
 		.regshift	= 2,
-		.uartclk	= KIRKWOOD_TCLK,
+		.uartclk	= 0,
 	}, {
 	},
 };
@@ -283,7 +286,7 @@
 		.flags		= UPF_SKIP_TEST | UPF_BOOT_AUTOCONF,
 		.iotype		= UPIO_MEM,
 		.regshift	= 2,
-		.uartclk	= KIRKWOOD_TCLK,
+		.uartclk	= 0,
 	}, {
 	},
 };
@@ -525,9 +528,23 @@
 /*****************************************************************************
  * Time handling
  ****************************************************************************/
+int kirkwood_tclk;
+
+int __init kirkwood_find_tclk(void)
+{
+	u32 dev, rev;
+
+	kirkwood_pcie_id(&dev, &rev);
+	if (dev == MV88F6281_DEV_ID && rev == MV88F6281_REV_A0)
+		return 200000000;
+
+	return 166666667;
+}
+
 static void kirkwood_timer_init(void)
 {
-	orion_time_init(IRQ_KIRKWOOD_BRIDGE, KIRKWOOD_TCLK);
+	kirkwood_tclk = kirkwood_find_tclk();
+	orion_time_init(IRQ_KIRKWOOD_BRIDGE, kirkwood_tclk);
 }
 
 struct sys_timer kirkwood_timer = {
@@ -538,33 +555,62 @@
 /*****************************************************************************
  * General
  ****************************************************************************/
+/*
+ * Identify device ID and revision.
+ */
 static char * __init kirkwood_id(void)
 {
-	switch (readl(DEVICE_ID) & 0x3) {
-	case 0:
-		return "88F6180";
-	case 1:
-		return "88F6192";
-	case 2:
-		return "88F6281";
-	}
+	u32 dev, rev;
 
-	return "unknown 88F6000 variant";
+	kirkwood_pcie_id(&dev, &rev);
+
+	if (dev == MV88F6281_DEV_ID) {
+		if (rev == MV88F6281_REV_Z0)
+			return "MV88F6281-Z0";
+		else if (rev == MV88F6281_REV_A0)
+			return "MV88F6281-A0";
+		else
+			return "MV88F6281-Rev-Unsupported";
+	} else if (dev == MV88F6192_DEV_ID) {
+		if (rev == MV88F6192_REV_Z0)
+			return "MV88F6192-Z0";
+		else if (rev == MV88F6192_REV_A0)
+			return "MV88F6192-A0";
+		else
+			return "MV88F6192-Rev-Unsupported";
+	} else if (dev == MV88F6180_DEV_ID) {
+		if (rev == MV88F6180_REV_A0)
+			return "MV88F6180-Rev-A0";
+		else
+			return "MV88F6180-Rev-Unsupported";
+	} else {
+		return "Device-Unknown";
+	}
 }
 
-static int __init is_l2_writethrough(void)
+static void __init kirkwood_l2_init(void)
 {
-	return !!(readl(L2_CONFIG_REG) & L2_WRITETHROUGH);
+#ifdef CONFIG_CACHE_FEROCEON_L2_WRITETHROUGH
+	writel(readl(L2_CONFIG_REG) | L2_WRITETHROUGH, L2_CONFIG_REG);
+	feroceon_l2_init(1);
+#else
+	writel(readl(L2_CONFIG_REG) & ~L2_WRITETHROUGH, L2_CONFIG_REG);
+	feroceon_l2_init(0);
+#endif
 }
 
 void __init kirkwood_init(void)
 {
 	printk(KERN_INFO "Kirkwood: %s, TCLK=%d.\n",
-		kirkwood_id(), KIRKWOOD_TCLK);
+		kirkwood_id(), kirkwood_tclk);
+	kirkwood_ge00_shared_data.t_clk = kirkwood_tclk;
+	kirkwood_spi_plat_data.tclk = kirkwood_tclk;
+	kirkwood_uart0_data[0].uartclk = kirkwood_tclk;
+	kirkwood_uart1_data[0].uartclk = kirkwood_tclk;
 
 	kirkwood_setup_cpu_mbus();
 
 #ifdef CONFIG_CACHE_FEROCEON_L2
-	feroceon_l2_init(is_l2_writethrough());
+	kirkwood_l2_init();
 #endif
 }
diff --git a/arch/arm/mach-kirkwood/common.h b/arch/arm/mach-kirkwood/common.h
index 69cd113..8fa0f6a 100644
--- a/arch/arm/mach-kirkwood/common.h
+++ b/arch/arm/mach-kirkwood/common.h
@@ -23,10 +23,9 @@
 
 extern struct mbus_dram_target_info kirkwood_mbus_dram_info;
 void kirkwood_setup_cpu_mbus(void);
-void kirkwood_setup_pcie_io_win(int window, u32 base, u32 size,
-				int maj, int min);
-void kirkwood_setup_pcie_mem_win(int window, u32 base, u32 size,
-				 int maj, int min);
+void kirkwood_setup_sram_win(u32 base, u32 size);
+
+void kirkwood_pcie_id(u32 *dev, u32 *rev);
 
 void kirkwood_ehci_init(void);
 void kirkwood_ge00_init(struct mv643xx_eth_platform_data *eth_data);
diff --git a/arch/arm/mach-kirkwood/db88f6281-bp-setup.c b/arch/arm/mach-kirkwood/db88f6281-bp-setup.c
index 610fb24..a14c294 100644
--- a/arch/arm/mach-kirkwood/db88f6281-bp-setup.c
+++ b/arch/arm/mach-kirkwood/db88f6281-bp-setup.c
@@ -25,7 +25,7 @@
 #include "common.h"
 
 static struct mv643xx_eth_platform_data db88f6281_ge00_data = {
-	.phy_addr	= 8,
+	.phy_addr	= MV643XX_ETH_PHY_ADDR(8),
 };
 
 static struct mv_sata_platform_data db88f6281_sata_data = {
@@ -44,7 +44,6 @@
 	kirkwood_rtc_init();
 	kirkwood_sata_init(&db88f6281_sata_data);
 	kirkwood_uart0_init();
-	kirkwood_uart1_init();
 }
 
 static int __init db88f6281_pci_init(void)
diff --git a/arch/arm/mach-kirkwood/include/mach/irqs.h b/arch/arm/mach-kirkwood/include/mach/irqs.h
index 6fd0583..ffab89f 100644
--- a/arch/arm/mach-kirkwood/include/mach/irqs.h
+++ b/arch/arm/mach-kirkwood/include/mach/irqs.h
@@ -50,6 +50,7 @@
 #define IRQ_KIRKWOOD_GPIO_HIGH_0_7	39
 #define IRQ_KIRKWOOD_GPIO_HIGH_8_15	40
 #define IRQ_KIRKWOOD_GPIO_HIGH_16_23	41
+#define IRQ_KIRKWOOD_GE00_ERR	46
 
 /*
  * KIRKWOOD General Purpose Pins
diff --git a/arch/arm/mach-kirkwood/include/mach/kirkwood.h b/arch/arm/mach-kirkwood/include/mach/kirkwood.h
index 5c69992..eae4240 100644
--- a/arch/arm/mach-kirkwood/include/mach/kirkwood.h
+++ b/arch/arm/mach-kirkwood/include/mach/kirkwood.h
@@ -68,6 +68,20 @@
 #define   L2_WRITETHROUGH	0x00000010
 
 /*
+ * Supported devices and revisions.
+ */
+#define MV88F6281_DEV_ID	0x6281
+#define MV88F6281_REV_Z0	0
+#define MV88F6281_REV_A0	2
+
+#define MV88F6192_DEV_ID	0x6192
+#define MV88F6192_REV_Z0	0
+#define MV88F6192_REV_A0	2
+
+#define MV88F6180_DEV_ID	0x6180
+#define MV88F6180_REV_A0	2
+
+/*
  * Register Map
  */
 #define DDR_VIRT_BASE		(KIRKWOOD_REGS_VIRT_BASE | 0x00000)
diff --git a/arch/arm/mach-kirkwood/include/mach/timex.h b/arch/arm/mach-kirkwood/include/mach/timex.h
index f77ef4a..c923cd1 100644
--- a/arch/arm/mach-kirkwood/include/mach/timex.h
+++ b/arch/arm/mach-kirkwood/include/mach/timex.h
@@ -8,4 +8,3 @@
 
 #define CLOCK_TICK_RATE		(100 * HZ)
 
-#define KIRKWOOD_TCLK		166666667
diff --git a/arch/arm/mach-kirkwood/pcie.c b/arch/arm/mach-kirkwood/pcie.c
index 2195fa3..f6b08f2 100644
--- a/arch/arm/mach-kirkwood/pcie.c
+++ b/arch/arm/mach-kirkwood/pcie.c
@@ -18,6 +18,12 @@
 
 #define PCIE_BASE	((void __iomem *)PCIE_VIRT_BASE)
 
+void __init kirkwood_pcie_id(u32 *dev, u32 *rev)
+{
+	*dev = orion_pcie_dev_id(PCIE_BASE);
+	*rev = orion_pcie_rev(PCIE_BASE);
+}
+
 static int pcie_valid_config(int bus, int dev)
 {
 	/*
diff --git a/arch/arm/mach-kirkwood/rd88f6192-nas-setup.c b/arch/arm/mach-kirkwood/rd88f6192-nas-setup.c
index a3012d4..b1d1a87a 100644
--- a/arch/arm/mach-kirkwood/rd88f6192-nas-setup.c
+++ b/arch/arm/mach-kirkwood/rd88f6192-nas-setup.c
@@ -30,7 +30,7 @@
 #define RD88F6192_GPIO_USB_VBUS		10
 
 static struct mv643xx_eth_platform_data rd88f6192_ge00_data = {
-	.phy_addr	= 8,
+	.phy_addr	= MV643XX_ETH_PHY_ADDR(8),
 };
 
 static struct mv_sata_platform_data rd88f6192_sata_data = {
diff --git a/arch/arm/mach-kirkwood/rd88f6281-setup.c b/arch/arm/mach-kirkwood/rd88f6281-setup.c
index d96487a0..f785093 100644
--- a/arch/arm/mach-kirkwood/rd88f6281-setup.c
+++ b/arch/arm/mach-kirkwood/rd88f6281-setup.c
@@ -69,7 +69,7 @@
 };
 
 static struct mv643xx_eth_platform_data rd88f6281_ge00_data = {
-	.phy_addr	= -1,
+	.phy_addr	= MV643XX_ETH_PHY_NONE,
 	.speed		= SPEED_1000,
 	.duplex		= DUPLEX_FULL,
 };
@@ -90,7 +90,6 @@
 	kirkwood_rtc_init();
 	kirkwood_sata_init(&rd88f6281_sata_data);
 	kirkwood_uart0_init();
-	kirkwood_uart1_init();
 
 	platform_device_register(&rd88f6281_nand_flash);
 }
diff --git a/arch/arm/mach-ks8695/cpu.c b/arch/arm/mach-ks8695/cpu.c
index c6c08e8..7f3f240 100644
--- a/arch/arm/mach-ks8695/cpu.c
+++ b/arch/arm/mach-ks8695/cpu.c
@@ -24,9 +24,9 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/init.h>
+#include <linux/io.h>
 
 #include <mach/hardware.h>
-#include <asm/io.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
 
diff --git a/arch/arm/mach-ks8695/gpio.c b/arch/arm/mach-ks8695/gpio.c
index 3624e65..9aecf0c 100644
--- a/arch/arm/mach-ks8695/gpio.c
+++ b/arch/arm/mach-ks8695/gpio.c
@@ -23,8 +23,8 @@
 #include <linux/debugfs.h>
 #include <linux/seq_file.h>
 #include <linux/module.h>
+#include <linux/io.h>
 
-#include <asm/io.h>
 #include <mach/hardware.h>
 #include <asm/mach/irq.h>
 
@@ -72,7 +72,7 @@
 
 	/* set pin as input */
 	x = __raw_readl(KS8695_GPIO_VA + KS8695_IOPM);
-	x &= ~IOPM_(pin);
+	x &= ~IOPM(pin);
 	__raw_writel(x, KS8695_GPIO_VA + KS8695_IOPM);
 
 	local_irq_restore(flags);
@@ -108,7 +108,7 @@
 
 	/* set pin as input */
 	x = __raw_readl(KS8695_GPIO_VA + KS8695_IOPM);
-	x &= ~IOPM_(pin);
+	x &= ~IOPM(pin);
 	__raw_writel(x, KS8695_GPIO_VA + KS8695_IOPM);
 
 	local_irq_restore(flags);
@@ -136,14 +136,14 @@
 	/* set line state */
 	x = __raw_readl(KS8695_GPIO_VA + KS8695_IOPD);
 	if (state)
-		x |= (1 << pin);
+		x |= IOPD(pin);
 	else
-		x &= ~(1 << pin);
+		x &= ~IOPD(pin);
 	__raw_writel(x, KS8695_GPIO_VA + KS8695_IOPD);
 
 	/* set pin as output */
 	x = __raw_readl(KS8695_GPIO_VA + KS8695_IOPM);
-	x |= IOPM_(pin);
+	x |= IOPM(pin);
 	__raw_writel(x, KS8695_GPIO_VA + KS8695_IOPM);
 
 	local_irq_restore(flags);
@@ -168,9 +168,9 @@
 	/* set output line state */
 	x = __raw_readl(KS8695_GPIO_VA + KS8695_IOPD);
 	if (state)
-		x |= (1 << pin);
+		x |= IOPD(pin);
 	else
-		x &= ~(1 << pin);
+		x &= ~IOPD(pin);
 	__raw_writel(x, KS8695_GPIO_VA + KS8695_IOPD);
 
 	local_irq_restore(flags);
@@ -189,7 +189,7 @@
 		return -EINVAL;
 
 	x = __raw_readl(KS8695_GPIO_VA + KS8695_IOPD);
-	return (x & (1 << pin)) != 0;
+	return (x & IOPD(pin)) != 0;
 }
 EXPORT_SYMBOL(gpio_get_value);
 
@@ -240,7 +240,7 @@
 	for (i = KS8695_GPIO_0; i <= KS8695_GPIO_15 ; i++) {
 		seq_printf(s, "%i:\t", i);
 
-		seq_printf(s, "%s\t", (mode & IOPM_(i)) ? "Output" : "Input");
+		seq_printf(s, "%s\t", (mode & IOPM(i)) ? "Output" : "Input");
 
 		if (i <= KS8695_GPIO_3) {
 			if (ctrl & enable[i]) {
@@ -273,7 +273,7 @@
 
 		seq_printf(s, "\t");
 
-		seq_printf(s, "%i\n", (data & IOPD_(i)) ? 1 : 0);
+		seq_printf(s, "%i\n", (data & IOPD(i)) ? 1 : 0);
 	}
 	return 0;
 }
diff --git a/arch/arm/mach-ks8695/include/mach/memory.h b/arch/arm/mach-ks8695/include/mach/memory.h
index dadbe66..8fbc4c7 100644
--- a/arch/arm/mach-ks8695/include/mach/memory.h
+++ b/arch/arm/mach-ks8695/include/mach/memory.h
@@ -31,8 +31,8 @@
 /* Platform-bus mapping */
 extern struct bus_type platform_bus_type;
 #define is_lbus_device(dev)		(dev && dev->bus == &platform_bus_type)
-#define __arch_dma_to_virt(dev, x)	({ is_lbus_device(dev) ? \
-					__phys_to_virt(x) : __bus_to_virt(x); })
+#define __arch_dma_to_virt(dev, x)	({ (void *) (is_lbus_device(dev) ? \
+					__phys_to_virt(x) : __bus_to_virt(x)); })
 #define __arch_virt_to_dma(dev, x)	({ is_lbus_device(dev) ? \
 					(dma_addr_t)__virt_to_phys(x) : (dma_addr_t)__virt_to_bus(x); })
 #define __arch_page_to_dma(dev, x)	__arch_virt_to_dma(dev, page_address(x))
diff --git a/arch/arm/mach-ks8695/include/mach/regs-gpio.h b/arch/arm/mach-ks8695/include/mach/regs-gpio.h
index 0df6fe6..90614a7 100644
--- a/arch/arm/mach-ks8695/include/mach/regs-gpio.h
+++ b/arch/arm/mach-ks8695/include/mach/regs-gpio.h
@@ -24,7 +24,7 @@
 
 
 /* Port Mode Register */
-#define IOPM_(x)		(1 << (x))	/* Mode for GPIO Pin x */
+#define IOPM(x)			(1 << (x))	/* Mode for GPIO Pin x */
 
 /* Port Control Register */
 #define IOPC_IOTIM1EN		(1 << 17)	/* GPIO Pin for Timer1 Enable */
@@ -50,6 +50,6 @@
 #define IOPC_TM_EDGE		(6)		/* Both Edge Detection */
 
 /* Port Data Register */
-#define IOPD_(x)		(1 << (x))	/* Signal Level of GPIO Pin x */
+#define IOPD(x)			(1 << (x))	/* Signal Level of GPIO Pin x */
 
 #endif
diff --git a/arch/arm/mach-ks8695/include/mach/regs-lan.h b/arch/arm/mach-ks8695/include/mach/regs-lan.h
index 9ef4099..82c5f37 100644
--- a/arch/arm/mach-ks8695/include/mach/regs-lan.h
+++ b/arch/arm/mach-ks8695/include/mach/regs-lan.h
@@ -29,8 +29,8 @@
 #define KS8695_LRDLB		(0x14)		/* Receive Descriptor List Base Address */
 #define KS8695_LMAL		(0x18)		/* MAC Station Address Low */
 #define KS8695_LMAH		(0x1c)		/* MAC Station Address High */
-#define KS8695_LMAAL_(n)	(0x80 + ((n)*8))	/* MAC Additional Station Address (0..15) Low */
-#define KS8695_LMAAH_(n)	(0x84 + ((n)*8))	/* MAC Additional Station Address (0..15) High */
+#define KS8695_LMAAL(n)		(0x80 + ((n)*8))	/* MAC Additional Station Address (0..15) Low */
+#define KS8695_LMAAH(n)		(0x84 + ((n)*8))	/* MAC Additional Station Address (0..15) High */
 
 
 /* DMA Transmit Control Register */
diff --git a/arch/arm/mach-ks8695/include/mach/regs-wan.h b/arch/arm/mach-ks8695/include/mach/regs-wan.h
index eb494ec..c475bed 100644
--- a/arch/arm/mach-ks8695/include/mach/regs-wan.h
+++ b/arch/arm/mach-ks8695/include/mach/regs-wan.h
@@ -29,8 +29,8 @@
 #define KS8695_WRDLB		(0x14)		/* Receive Descriptor List Base Address */
 #define KS8695_WMAL		(0x18)		/* MAC Station Address Low */
 #define KS8695_WMAH		(0x1c)		/* MAC Station Address High */
-#define KS8695_WMAAL_(n)	(0x80 + ((n)*8))	/* MAC Additional Station Address (0..15) Low */
-#define KS8695_WMAAH_(n)	(0x84 + ((n)*8))	/* MAC Additional Station Address (0..15) High */
+#define KS8695_WMAAL(n)		(0x80 + ((n)*8))	/* MAC Additional Station Address (0..15) Low */
+#define KS8695_WMAAH(n)		(0x84 + ((n)*8))	/* MAC Additional Station Address (0..15) High */
 
 
 /* DMA Transmit Control Register */
diff --git a/arch/arm/mach-ks8695/include/mach/system.h b/arch/arm/mach-ks8695/include/mach/system.h
index 2a6f918..5a9b032 100644
--- a/arch/arm/mach-ks8695/include/mach/system.h
+++ b/arch/arm/mach-ks8695/include/mach/system.h
@@ -14,7 +14,7 @@
 #ifndef __ASM_ARCH_SYSTEM_H
 #define __ASM_ARCH_SYSTEM_H
 
-#include <asm/io.h>
+#include <linux/io.h>
 #include <mach/regs-timer.h>
 
 static void arch_idle(void)
diff --git a/arch/arm/mach-ks8695/include/mach/uncompress.h b/arch/arm/mach-ks8695/include/mach/uncompress.h
index 0eee37a..9495cb4 100644
--- a/arch/arm/mach-ks8695/include/mach/uncompress.h
+++ b/arch/arm/mach-ks8695/include/mach/uncompress.h
@@ -14,7 +14,7 @@
 #ifndef __ASM_ARCH_UNCOMPRESS_H
 #define __ASM_ARCH_UNCOMPRESS_H
 
-#include <asm/io.h>
+#include <linux/io.h>
 #include <mach/regs-uart.h>
 
 static void putc(char c)
diff --git a/arch/arm/mach-ks8695/irq.c b/arch/arm/mach-ks8695/irq.c
index e5e71f4..e375c1d 100644
--- a/arch/arm/mach-ks8695/irq.c
+++ b/arch/arm/mach-ks8695/irq.c
@@ -24,10 +24,10 @@
 #include <linux/interrupt.h>
 #include <linux/ioport.h>
 #include <linux/sysdev.h>
+#include <linux/io.h>
 
 #include <mach/hardware.h>
 #include <asm/irq.h>
-#include <asm/io.h>
 
 #include <asm/mach/irq.h>
 
diff --git a/arch/arm/mach-ks8695/pci.c b/arch/arm/mach-ks8695/pci.c
index 1746c67..f5ebcc0 100644
--- a/arch/arm/mach-ks8695/pci.c
+++ b/arch/arm/mach-ks8695/pci.c
@@ -27,8 +27,8 @@
 #include <linux/init.h>
 #include <linux/irq.h>
 #include <linux/delay.h>
+#include <linux/io.h>
 
-#include <asm/io.h>
 #include <asm/signal.h>
 #include <asm/mach/pci.h>
 #include <mach/hardware.h>
@@ -141,7 +141,7 @@
 	.write	= ks8695_pci_writeconfig,
 };
 
-static struct pci_bus *ks8695_pci_scan_bus(int nr, struct pci_sys_data *sys)
+static struct pci_bus* __init ks8695_pci_scan_bus(int nr, struct pci_sys_data *sys)
 {
 	return pci_scan_bus(sys->busnr, &ks8695_pci_ops, sys);
 }
diff --git a/arch/arm/mach-ks8695/time.c b/arch/arm/mach-ks8695/time.c
index 940888d..69c072c 100644
--- a/arch/arm/mach-ks8695/time.c
+++ b/arch/arm/mach-ks8695/time.c
@@ -24,8 +24,8 @@
 #include <linux/irq.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
+#include <linux/io.h>
 
-#include <asm/io.h>
 #include <asm/mach/time.h>
 
 #include <mach/regs-timer.h>
diff --git a/arch/arm/mach-lh7a40x/Kconfig b/arch/arm/mach-lh7a40x/Kconfig
index 6f4c6a1..9be7466 100644
--- a/arch/arm/mach-lh7a40x/Kconfig
+++ b/arch/arm/mach-lh7a40x/Kconfig
@@ -40,23 +40,22 @@
 	bool
 
 config LH7A40X_CONTIGMEM
-	bool "Disable NUMA Support"
-	depends on ARCH_LH7A40X
+	bool "Disable NUMA/SparseMEM Support"
 	help
 	  Say Y here if your bootloader sets the SROMLL bit(s) in
 	  the SDRAM controller, organizing memory as a contiguous
-	  array.  This option will disable CONFIG_DISCONTIGMEM and
-          force the kernel to manage all memory in one node.
+	  array.  This option will disable sparse memory support
+          and force the kernel to manage all memory in one node.
 
-	  Setting this option incorrectly may prevent the kernel from
-	  booting.  It is OK to leave it N.
+	  Setting this option incorrectly may prevent the kernel
+	  from booting.  It is OK to leave it N.
 
 	  For more information, consult
 	    <file:Documentation/arm/Sharp-LH/SDRAM>.
 
 config LH7A40X_ONE_BANK_PER_NODE
 	bool "Optimize NUMA Node Tables for Size"
-	depends on ARCH_LH7A40X && !LH7A40X_CONTIGMEM
+	depends on !LH7A40X_CONTIGMEM
 	help
 	  Say Y here to produce compact memory node tables.  By
 	  default pairs of adjacent physical RAM banks are managed
diff --git a/arch/arm/mach-lh7a40x/arch-kev7a400.c b/arch/arm/mach-lh7a40x/arch-kev7a400.c
index 551b972..3d7bd50 100644
--- a/arch/arm/mach-lh7a40x/arch-kev7a400.c
+++ b/arch/arm/mach-lh7a40x/arch-kev7a400.c
@@ -77,7 +77,7 @@
 	irq = IRQ_KEV7A400_CPLD;
 	for (; mask; mask >>= 1, ++irq)
 		if (mask & 1)
-			desc_handle_irq(irq, desc);
+			generic_handle_irq(irq);
 }
 
 void __init lh7a40x_init_board_irq (void)
diff --git a/arch/arm/mach-lh7a40x/arch-lpd7a40x.c b/arch/arm/mach-lh7a40x/arch-lpd7a40x.c
index e373fb8..cb15e5d 100644
--- a/arch/arm/mach-lh7a40x/arch-lpd7a40x.c
+++ b/arch/arm/mach-lh7a40x/arch-lpd7a40x.c
@@ -214,11 +214,11 @@
 	desc->chip->ack (irq);
 
 	if ((mask & (1<<0)) == 0)	/* WLAN */
-		IRQ_DISPATCH (IRQ_LPD7A40X_ETH_INT);
+		generic_handle_irq(IRQ_LPD7A40X_ETH_INT);
 
 #if defined (IRQ_TOUCH)
 	if ((mask & (1<<1)) == 0)	/* Touch */
-		IRQ_DISPATCH (IRQ_TOUCH);
+		generic_handle_irq(IRQ_TOUCH);
 #endif
 
 	desc->chip->unmask (irq); /* Level-triggered need this */
diff --git a/arch/arm/mach-lh7a40x/common.h b/arch/arm/mach-lh7a40x/common.h
index 0ca20c6..6ed3f6b 100644
--- a/arch/arm/mach-lh7a40x/common.h
+++ b/arch/arm/mach-lh7a40x/common.h
@@ -15,4 +15,3 @@
 extern void lh7a40x_clcd_init (void);
 extern void lh7a40x_init_board_irq (void);
 
-#define IRQ_DISPATCH(irq) desc_handle_irq((irq),(irq_desc + irq))
diff --git a/arch/arm/mach-lh7a40x/include/mach/memory.h b/arch/arm/mach-lh7a40x/include/mach/memory.h
index f7107b4..1da14ff 100644
--- a/arch/arm/mach-lh7a40x/include/mach/memory.h
+++ b/arch/arm/mach-lh7a40x/include/mach/memory.h
@@ -73,4 +73,10 @@
 
 #endif
 
+/*
+ * Sparsemem version of the above
+ */
+#define MAX_PHYSMEM_BITS	32
+#define SECTION_SIZE_BITS	24
+
 #endif
diff --git a/arch/arm/mach-lh7a40x/irq-lpd7a40x.c b/arch/arm/mach-lh7a40x/irq-lpd7a40x.c
index 0d5063eb..fd033bb 100644
--- a/arch/arm/mach-lh7a40x/irq-lpd7a40x.c
+++ b/arch/arm/mach-lh7a40x/irq-lpd7a40x.c
@@ -63,10 +63,10 @@
 	desc->chip->ack (irq);
 
 	if ((mask & 0x1) == 0)	/* WLAN */
-		IRQ_DISPATCH (IRQ_LPD7A40X_ETH_INT);
+		generic_handle_irq(IRQ_LPD7A40X_ETH_INT);
 
 	if ((mask & 0x2) == 0)	/* Touch */
-		IRQ_DISPATCH (IRQ_LPD7A400_TS);
+		generic_handle_irq(IRQ_LPD7A400_TS);
 
 	desc->chip->unmask (irq); /* Level-triggered need this */
 }
diff --git a/arch/arm/mach-lh7a40x/ssp-cpld.c b/arch/arm/mach-lh7a40x/ssp-cpld.c
index 51fbef9..2901d49 100644
--- a/arch/arm/mach-lh7a40x/ssp-cpld.c
+++ b/arch/arm/mach-lh7a40x/ssp-cpld.c
@@ -43,8 +43,8 @@
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/spinlock.h>
+#include <linux/io.h>
 
-#include <asm/io.h>
 #include <asm/irq.h>
 #include <mach/hardware.h>
 
diff --git a/arch/arm/mach-lh7a40x/time.c b/arch/arm/mach-lh7a40x/time.c
index 7fe9e06..4601e425 100644
--- a/arch/arm/mach-lh7a40x/time.c
+++ b/arch/arm/mach-lh7a40x/time.c
@@ -13,9 +13,9 @@
 #include <linux/interrupt.h>
 #include <linux/irq.h>
 #include <linux/time.h>
+#include <linux/io.h>
 
 #include <mach/hardware.h>
-#include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/leds.h>
 
diff --git a/arch/arm/mach-loki/addr-map.c b/arch/arm/mach-loki/addr-map.c
index 70ca56b..0332d8f 100644
--- a/arch/arm/mach-loki/addr-map.c
+++ b/arch/arm/mach-loki/addr-map.c
@@ -11,8 +11,8 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/mbus.h>
+#include <linux/io.h>
 #include <mach/hardware.h>
-#include <asm/io.h>
 #include "common.h"
 
 /*
diff --git a/arch/arm/mach-loki/irq.c b/arch/arm/mach-loki/irq.c
index 5a48793..e1f9733 100644
--- a/arch/arm/mach-loki/irq.c
+++ b/arch/arm/mach-loki/irq.c
@@ -11,7 +11,7 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/irq.h>
-#include <asm/io.h>
+#include <linux/io.h>
 #include <plat/irq.h>
 #include "common.h"
 
diff --git a/arch/arm/mach-loki/lb88rc8480-setup.c b/arch/arm/mach-loki/lb88rc8480-setup.c
index 2cc9ac9..85f9c12 100644
--- a/arch/arm/mach-loki/lb88rc8480-setup.c
+++ b/arch/arm/mach-loki/lb88rc8480-setup.c
@@ -67,7 +67,7 @@
 };
 
 static struct mv643xx_eth_platform_data lb88rc8480_ge0_data = {
-	.phy_addr	= 1,
+	.phy_addr	= MV643XX_ETH_PHY_ADDR(1),
 	.mac_addr	= { 0x00, 0x50, 0x43, 0x11, 0x22, 0x33 },
 };
 
diff --git a/arch/arm/mach-msm/board-halibut.c b/arch/arm/mach-msm/board-halibut.c
index 995afc4a..a242591 100644
--- a/arch/arm/mach-msm/board-halibut.c
+++ b/arch/arm/mach-msm/board-halibut.c
@@ -18,6 +18,8 @@
 #include <linux/init.h>
 #include <linux/platform_device.h>
 #include <linux/input.h>
+#include <linux/io.h>
+#include <linux/delay.h>
 
 #include <mach/hardware.h>
 #include <asm/mach-types.h>
@@ -28,9 +30,6 @@
 #include <mach/board.h>
 #include <mach/msm_iomap.h>
 
-#include <asm/io.h>
-#include <asm/delay.h>
-
 #include <linux/mtd/nand.h>
 #include <linux/mtd/partitions.h>
 
diff --git a/arch/arm/mach-msm/common.c b/arch/arm/mach-msm/common.c
index 3a51136..604f8ad 100644
--- a/arch/arm/mach-msm/common.c
+++ b/arch/arm/mach-msm/common.c
@@ -19,9 +19,9 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/platform_device.h>
+#include <linux/io.h>
 
 #include <asm/mach/flash.h>
-#include <asm/io.h>
 
 #include <asm/setup.h>
 
diff --git a/arch/arm/mach-msm/dma.c b/arch/arm/mach-msm/dma.c
index 9de0826..0c8f252 100644
--- a/arch/arm/mach-msm/dma.c
+++ b/arch/arm/mach-msm/dma.c
@@ -13,7 +13,7 @@
  *
  */
 
-#include <asm/io.h>
+#include <linux/io.h>
 #include <linux/interrupt.h>
 #include <mach/dma.h>
 
diff --git a/arch/arm/mach-msm/io.c b/arch/arm/mach-msm/io.c
index 5976200..7999e4b 100644
--- a/arch/arm/mach-msm/io.c
+++ b/arch/arm/mach-msm/io.c
@@ -18,9 +18,9 @@
 
 #include <linux/kernel.h>
 #include <linux/init.h>
+#include <linux/io.h>
 
 #include <mach/hardware.h>
-#include <asm/io.h>
 #include <asm/page.h>
 #include <mach/msm_iomap.h>
 #include <asm/mach/map.h>
diff --git a/arch/arm/mach-msm/irq.c b/arch/arm/mach-msm/irq.c
index 66901ba..04b8d18 100644
--- a/arch/arm/mach-msm/irq.c
+++ b/arch/arm/mach-msm/irq.c
@@ -19,11 +19,10 @@
 #include <linux/interrupt.h>
 #include <linux/ptrace.h>
 #include <linux/timer.h>
-
 #include <linux/irq.h>
-#include <mach/hardware.h>
+#include <linux/io.h>
 
-#include <asm/io.h>
+#include <mach/hardware.h>
 
 #include <mach/msm_iomap.h>
 
diff --git a/arch/arm/mach-msm/timer.c b/arch/arm/mach-msm/timer.c
index 9f02d7d..2bffe9b 100644
--- a/arch/arm/mach-msm/timer.c
+++ b/arch/arm/mach-msm/timer.c
@@ -20,12 +20,11 @@
 #include <linux/clk.h>
 #include <linux/clockchips.h>
 #include <linux/delay.h>
+#include <linux/io.h>
 
 #include <asm/mach/time.h>
 #include <mach/msm_iomap.h>
 
-#include <asm/io.h>
-
 #define MSM_DGT_BASE (MSM_GPT_BASE + 0x10)
 #define MSM_DGT_SHIFT (5)
 
diff --git a/arch/arm/mach-mv78xx0/addr-map.c b/arch/arm/mach-mv78xx0/addr-map.c
index 4004b67..311d5b0 100644
--- a/arch/arm/mach-mv78xx0/addr-map.c
+++ b/arch/arm/mach-mv78xx0/addr-map.c
@@ -11,7 +11,7 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/mbus.h>
-#include <asm/io.h>
+#include <linux/io.h>
 #include "common.h"
 
 /*
diff --git a/arch/arm/mach-mv78xx0/common.c b/arch/arm/mach-mv78xx0/common.c
index 953a26c..238a2f8 100644
--- a/arch/arm/mach-mv78xx0/common.c
+++ b/arch/arm/mach-mv78xx0/common.c
@@ -285,6 +285,11 @@
 		.start	= GE00_PHYS_BASE + 0x2000,
 		.end	= GE00_PHYS_BASE + 0x3fff,
 		.flags	= IORESOURCE_MEM,
+	}, {
+		.name	= "ge err irq",
+		.start	= IRQ_MV78XX0_GE_ERR,
+		.end	= IRQ_MV78XX0_GE_ERR,
+		.flags	= IORESOURCE_IRQ,
 	},
 };
 
@@ -294,7 +299,7 @@
 	.dev		= {
 		.platform_data	= &mv78xx0_ge00_shared_data,
 	},
-	.num_resources	= 1,
+	.num_resources	= ARRAY_SIZE(mv78xx0_ge00_shared_resources),
 	.resource	= mv78xx0_ge00_shared_resources,
 };
 
@@ -330,6 +335,7 @@
 struct mv643xx_eth_shared_platform_data mv78xx0_ge01_shared_data = {
 	.t_clk		= 0,
 	.dram		= &mv78xx0_mbus_dram_info,
+	.shared_smi	= &mv78xx0_ge00_shared,
 };
 
 static struct resource mv78xx0_ge01_shared_resources[] = {
@@ -370,7 +376,6 @@
 void __init mv78xx0_ge01_init(struct mv643xx_eth_platform_data *eth_data)
 {
 	eth_data->shared = &mv78xx0_ge01_shared;
-	eth_data->shared_smi = &mv78xx0_ge00_shared;
 	mv78xx0_ge01.dev.platform_data = eth_data;
 
 	platform_device_register(&mv78xx0_ge01_shared);
@@ -384,6 +389,7 @@
 struct mv643xx_eth_shared_platform_data mv78xx0_ge10_shared_data = {
 	.t_clk		= 0,
 	.dram		= &mv78xx0_mbus_dram_info,
+	.shared_smi	= &mv78xx0_ge00_shared,
 };
 
 static struct resource mv78xx0_ge10_shared_resources[] = {
@@ -424,7 +430,6 @@
 void __init mv78xx0_ge10_init(struct mv643xx_eth_platform_data *eth_data)
 {
 	eth_data->shared = &mv78xx0_ge10_shared;
-	eth_data->shared_smi = &mv78xx0_ge00_shared;
 	mv78xx0_ge10.dev.platform_data = eth_data;
 
 	platform_device_register(&mv78xx0_ge10_shared);
@@ -438,6 +443,7 @@
 struct mv643xx_eth_shared_platform_data mv78xx0_ge11_shared_data = {
 	.t_clk		= 0,
 	.dram		= &mv78xx0_mbus_dram_info,
+	.shared_smi	= &mv78xx0_ge00_shared,
 };
 
 static struct resource mv78xx0_ge11_shared_resources[] = {
@@ -478,7 +484,6 @@
 void __init mv78xx0_ge11_init(struct mv643xx_eth_platform_data *eth_data)
 {
 	eth_data->shared = &mv78xx0_ge11_shared;
-	eth_data->shared_smi = &mv78xx0_ge00_shared;
 	mv78xx0_ge11.dev.platform_data = eth_data;
 
 	platform_device_register(&mv78xx0_ge11_shared);
diff --git a/arch/arm/mach-mv78xx0/db78x00-bp-setup.c b/arch/arm/mach-mv78xx0/db78x00-bp-setup.c
index a2d0c97..49f434c 100644
--- a/arch/arm/mach-mv78xx0/db78x00-bp-setup.c
+++ b/arch/arm/mach-mv78xx0/db78x00-bp-setup.c
@@ -19,19 +19,19 @@
 #include "common.h"
 
 static struct mv643xx_eth_platform_data db78x00_ge00_data = {
-	.phy_addr	= 8,
+	.phy_addr	= MV643XX_ETH_PHY_ADDR(8),
 };
 
 static struct mv643xx_eth_platform_data db78x00_ge01_data = {
-	.phy_addr	= 9,
+	.phy_addr	= MV643XX_ETH_PHY_ADDR(9),
 };
 
 static struct mv643xx_eth_platform_data db78x00_ge10_data = {
-	.phy_addr	= -1,
+	.phy_addr	= MV643XX_ETH_PHY_NONE,
 };
 
 static struct mv643xx_eth_platform_data db78x00_ge11_data = {
-	.phy_addr	= -1,
+	.phy_addr	= MV643XX_ETH_PHY_NONE,
 };
 
 static struct mv_sata_platform_data db78x00_sata_data = {
diff --git a/arch/arm/mach-mv78xx0/include/mach/entry-macro.S b/arch/arm/mach-mv78xx0/include/mach/entry-macro.S
index ed4a46b..fbfb269 100644
--- a/arch/arm/mach-mv78xx0/include/mach/entry-macro.S
+++ b/arch/arm/mach-mv78xx0/include/mach/entry-macro.S
@@ -26,14 +26,22 @@
 	ldr	\tmp, [\base, #IRQ_MASK_LOW_OFF]
 	mov	\irqnr, #31
 	ands	\irqstat, \irqstat, \tmp
+	bne	1001f
 
 	@ if no low interrupts set, check high interrupts
-	ldreq	\irqstat, [\base, #IRQ_CAUSE_HIGH_OFF]
-	ldreq	\tmp, [\base, #IRQ_MASK_HIGH_OFF]
-	moveq	\irqnr, #63
-	andeqs	\irqstat, \irqstat, \tmp
+	ldr	\irqstat, [\base, #IRQ_CAUSE_HIGH_OFF]
+	ldr	\tmp, [\base, #IRQ_MASK_HIGH_OFF]
+	mov	\irqnr, #63
+	ands	\irqstat, \irqstat, \tmp
+	bne	1001f
+
+	@ if no high interrupts set, check error interrupts
+	ldr	\irqstat, [\base, #IRQ_CAUSE_ERR_OFF]
+	ldr	\tmp, [\base, #IRQ_MASK_ERR_OFF]
+	mov	\irqnr, #95
+	ands	\irqstat, \irqstat, \tmp
 
 	@ find first active interrupt source
-	clzne	\irqstat, \irqstat
+1001:	clzne	\irqstat, \irqstat
 	subne	\irqnr, \irqnr, \irqstat
 	.endm
diff --git a/arch/arm/mach-mv78xx0/include/mach/irqs.h b/arch/arm/mach-mv78xx0/include/mach/irqs.h
index 995d7fb..bebc330 100644
--- a/arch/arm/mach-mv78xx0/include/mach/irqs.h
+++ b/arch/arm/mach-mv78xx0/include/mach/irqs.h
@@ -80,9 +80,14 @@
 #define IRQ_MV78XX0_DB_OUT	61
 
 /*
+ * MV78xx0 Error Interrupt Controller
+ */
+#define IRQ_MV78XX0_GE_ERR	70
+
+/*
  * MV78XX0 General Purpose Pins
  */
-#define IRQ_MV78XX0_GPIO_START	64
+#define IRQ_MV78XX0_GPIO_START	96
 #define NR_GPIO_IRQS		GPIO_MAX
 
 #define NR_IRQS			(IRQ_MV78XX0_GPIO_START + NR_GPIO_IRQS)
diff --git a/arch/arm/mach-mv78xx0/include/mach/mv78xx0.h b/arch/arm/mach-mv78xx0/include/mach/mv78xx0.h
index ad66417..ee9c559 100644
--- a/arch/arm/mach-mv78xx0/include/mach/mv78xx0.h
+++ b/arch/arm/mach-mv78xx0/include/mach/mv78xx0.h
@@ -71,8 +71,10 @@
 #define   BRIDGE_INT_TIMER1	0x0004
 #define   BRIDGE_INT_TIMER1_CLR	(~0x0004)
 #define  IRQ_VIRT_BASE		(BRIDGE_VIRT_BASE | 0x0200)
+#define   IRQ_CAUSE_ERR_OFF	0x0000
 #define   IRQ_CAUSE_LOW_OFF	0x0004
 #define   IRQ_CAUSE_HIGH_OFF	0x0008
+#define   IRQ_MASK_ERR_OFF	0x000c
 #define   IRQ_MASK_LOW_OFF	0x0010
 #define   IRQ_MASK_HIGH_OFF	0x0014
 #define  TIMER_VIRT_BASE	(BRIDGE_VIRT_BASE | 0x0300)
diff --git a/arch/arm/mach-mv78xx0/irq.c b/arch/arm/mach-mv78xx0/irq.c
index 28248d3..503e5d1 100644
--- a/arch/arm/mach-mv78xx0/irq.c
+++ b/arch/arm/mach-mv78xx0/irq.c
@@ -19,4 +19,5 @@
 {
 	orion_irq_init(0, (void __iomem *)(IRQ_VIRT_BASE + IRQ_MASK_LOW_OFF));
 	orion_irq_init(32, (void __iomem *)(IRQ_VIRT_BASE + IRQ_MASK_HIGH_OFF));
+	orion_irq_init(64, (void __iomem *)(IRQ_VIRT_BASE + IRQ_MASK_ERR_OFF));
 }
diff --git a/arch/arm/mach-mx2/devices.h b/arch/arm/mach-mx2/devices.h
new file mode 100644
index 0000000..c77a4b8
--- /dev/null
+++ b/arch/arm/mach-mx2/devices.h
@@ -0,0 +1,15 @@
+
+extern struct platform_device mxc_gpt1;
+extern struct platform_device mxc_gpt2;
+extern struct platform_device mxc_gpt3;
+extern struct platform_device mxc_gpt4;
+extern struct platform_device mxc_gpt5;
+extern struct platform_device mxc_wdt;
+extern struct platform_device mxc_irda_device;
+extern struct platform_device mxc_uart_device0;
+extern struct platform_device mxc_uart_device1;
+extern struct platform_device mxc_uart_device2;
+extern struct platform_device mxc_uart_device3;
+extern struct platform_device mxc_uart_device4;
+extern struct platform_device mxc_uart_device5;
+
diff --git a/arch/arm/mach-mx2/mx27ads.c b/arch/arm/mach-mx2/mx27ads.c
index 4ce56ef..56e22d3 100644
--- a/arch/arm/mach-mx2/mx27ads.c
+++ b/arch/arm/mach-mx2/mx27ads.c
@@ -34,6 +34,8 @@
 #include <mach/iomux-mx1-mx2.h>
 #include <mach/board-mx27ads.h>
 
+#include "devices.h"
+
 /* ADS's NOR flash */
 static struct physmap_flash_data mx27ads_flash_data = {
 	.width = 2,
@@ -251,12 +253,14 @@
 
 static void __init mx27ads_board_init(void)
 {
-	int i;
-
 	gpio_fec_active();
 
-	for (i = 0; i < 6; i++)
-		imx_init_uart(i, &uart_pdata[i]);
+	mxc_register_device(&mxc_uart_device0, &uart_pdata[0]);
+	mxc_register_device(&mxc_uart_device1, &uart_pdata[1]);
+	mxc_register_device(&mxc_uart_device2, &uart_pdata[2]);
+	mxc_register_device(&mxc_uart_device3, &uart_pdata[3]);
+	mxc_register_device(&mxc_uart_device4, &uart_pdata[4]);
+	mxc_register_device(&mxc_uart_device5, &uart_pdata[5]);
 
 	platform_add_devices(platform_devices, ARRAY_SIZE(platform_devices));
 }
diff --git a/arch/arm/mach-mx2/pcm038.c b/arch/arm/mach-mx2/pcm038.c
index 1028f45..7f55746 100644
--- a/arch/arm/mach-mx2/pcm038.c
+++ b/arch/arm/mach-mx2/pcm038.c
@@ -28,6 +28,8 @@
 #include <mach/imx-uart.h>
 #include <mach/board-pcm038.h>
 
+#include "devices.h"
+
 /*
  * Phytec's phyCORE-i.MX27 comes with 32MiB flash,
  * 16 bit width
@@ -170,11 +172,11 @@
 
 static void __init pcm038_init(void)
 {
-	int i;
 	gpio_fec_active();
 
-	for (i = 0; i < 3; i++)
-		imx_init_uart(i, &uart_pdata[i]);
+	mxc_register_device(&mxc_uart_device0, &uart_pdata[0]);
+	mxc_register_device(&mxc_uart_device1, &uart_pdata[1]);
+	mxc_register_device(&mxc_uart_device2, &uart_pdata[2]);
 
 	platform_add_devices(platform_devices, ARRAY_SIZE(platform_devices));
 
diff --git a/arch/arm/mach-mx2/serial.c b/arch/arm/mach-mx2/serial.c
index e31fd44..16debc2 100644
--- a/arch/arm/mach-mx2/serial.c
+++ b/arch/arm/mach-mx2/serial.c
@@ -35,7 +35,7 @@
 	},
 };
 
-static struct platform_device mxc_uart_device0 = {
+struct platform_device mxc_uart_device0 = {
 	.name = "imx-uart",
 	.id = 0,
 	.resource = uart0,
@@ -54,7 +54,7 @@
 	},
 };
 
-static struct platform_device mxc_uart_device1 = {
+struct platform_device mxc_uart_device1 = {
 	.name = "imx-uart",
 	.id = 1,
 	.resource = uart1,
@@ -73,7 +73,7 @@
 	},
 };
 
-static struct platform_device mxc_uart_device2 = {
+struct platform_device mxc_uart_device2 = {
 	.name = "imx-uart",
 	.id = 2,
 	.resource = uart2,
@@ -92,7 +92,7 @@
 	},
 };
 
-static struct platform_device mxc_uart_device3 = {
+struct platform_device mxc_uart_device3 = {
 	.name = "imx-uart",
 	.id = 3,
 	.resource = uart3,
@@ -111,7 +111,7 @@
 	},
 };
 
-static struct platform_device mxc_uart_device4 = {
+struct platform_device mxc_uart_device4 = {
 	.name = "imx-uart",
 	.id = 4,
 	.resource = uart4,
@@ -130,48 +130,9 @@
 	},
 };
 
-static struct platform_device mxc_uart_device5 = {
+struct platform_device mxc_uart_device5 = {
 	.name = "imx-uart",
 	.id = 5,
 	.resource = uart5,
 	.num_resources = ARRAY_SIZE(uart5),
 };
-
-/*
- * Register only those UARTs that physically exists
- */
-int __init imx_init_uart(int uart_no, struct imxuart_platform_data *pdata)
-{
-	switch (uart_no) {
-	case 0:
-		mxc_uart_device0.dev.platform_data = pdata;
-		platform_device_register(&mxc_uart_device0);
-		break;
-	case 1:
-		mxc_uart_device1.dev.platform_data = pdata;
-		platform_device_register(&mxc_uart_device1);
-		break;
-#ifndef CONFIG_MXC_IRDA
-	case 2:
-		mxc_uart_device2.dev.platform_data = pdata;
-		platform_device_register(&mxc_uart_device2);
-		break;
-#endif
-	case 3:
-		mxc_uart_device3.dev.platform_data = pdata;
-		platform_device_register(&mxc_uart_device3);
-		break;
-	case 4:
-		mxc_uart_device4.dev.platform_data = pdata;
-		platform_device_register(&mxc_uart_device4);
-		break;
-	case 5:
-		mxc_uart_device5.dev.platform_data = pdata;
-		platform_device_register(&mxc_uart_device5);
-		break;
-	default:
-		return -ENODEV;
-	}
-
-	return 0;
-}
diff --git a/arch/arm/mach-mx3/devices.c b/arch/arm/mach-mx3/devices.c
index e08c6a8..a6bdcc0 100644
--- a/arch/arm/mach-mx3/devices.c
+++ b/arch/arm/mach-mx3/devices.c
@@ -36,7 +36,7 @@
 	},
 };
 
-static struct platform_device mxc_uart_device0 = {
+struct platform_device mxc_uart_device0 = {
 	.name = "imx-uart",
 	.id = 0,
 	.resource = uart0,
@@ -55,7 +55,7 @@
 	},
 };
 
-static struct platform_device mxc_uart_device1 = {
+struct platform_device mxc_uart_device1 = {
 	.name = "imx-uart",
 	.id = 1,
 	.resource = uart1,
@@ -74,7 +74,7 @@
 	},
 };
 
-static struct platform_device mxc_uart_device2 = {
+struct platform_device mxc_uart_device2 = {
 	.name = "imx-uart",
 	.id = 2,
 	.resource = uart2,
@@ -93,7 +93,7 @@
 	},
 };
 
-static struct platform_device mxc_uart_device3 = {
+struct platform_device mxc_uart_device3 = {
 	.name = "imx-uart",
 	.id = 3,
 	.resource = uart3,
@@ -112,46 +112,13 @@
 	},
 };
 
-static struct platform_device mxc_uart_device4 = {
+struct platform_device mxc_uart_device4 = {
 	.name = "imx-uart",
 	.id = 4,
 	.resource = uart4,
 	.num_resources = ARRAY_SIZE(uart4),
 };
 
-/*
- * Register only those UARTs that physically exist
- */
-int __init imx_init_uart(int uart_no, struct imxuart_platform_data *pdata)
-{
-	switch (uart_no) {
-	case 0:
-		mxc_uart_device0.dev.platform_data = pdata;
-		platform_device_register(&mxc_uart_device0);
-		break;
-	case 1:
-		mxc_uart_device1.dev.platform_data = pdata;
-		platform_device_register(&mxc_uart_device1);
-		break;
-	case 2:
-		mxc_uart_device2.dev.platform_data = pdata;
-		platform_device_register(&mxc_uart_device2);
-		break;
-	case 3:
-		mxc_uart_device3.dev.platform_data = pdata;
-		platform_device_register(&mxc_uart_device3);
-		break;
-	case 4:
-		mxc_uart_device4.dev.platform_data = pdata;
-		platform_device_register(&mxc_uart_device4);
-		break;
-	default:
-		return -ENODEV;
-	}
-
-	return 0;
-}
-
 /* GPIO port description */
 static struct mxc_gpio_port imx_gpio_ports[] = {
 	[0] = {
diff --git a/arch/arm/mach-mx3/devices.h b/arch/arm/mach-mx3/devices.h
new file mode 100644
index 0000000..4dc03f9
--- /dev/null
+++ b/arch/arm/mach-mx3/devices.h
@@ -0,0 +1,6 @@
+
+extern struct platform_device mxc_uart_device0;
+extern struct platform_device mxc_uart_device1;
+extern struct platform_device mxc_uart_device2;
+extern struct platform_device mxc_uart_device3;
+extern struct platform_device mxc_uart_device4;
diff --git a/arch/arm/mach-mx3/iomux.c b/arch/arm/mach-mx3/iomux.c
index 3dda1fe..6e664be 100644
--- a/arch/arm/mach-mx3/iomux.c
+++ b/arch/arm/mach-mx3/iomux.c
@@ -43,7 +43,8 @@
  */
 int mxc_iomux_mode(unsigned int pin_mode)
 {
-	u32 reg, field, l, mode, ret = 0;
+	u32 field, l, mode, ret = 0;
+	void __iomem *reg;
 
 	reg = IOMUXSW_MUX_CTL + (pin_mode & IOMUX_REG_MASK);
 	field = pin_mode & 0x3;
@@ -70,7 +71,8 @@
  */
 void mxc_iomux_set_pad(enum iomux_pins pin, u32 config)
 {
-	u32 reg, field, l;
+	u32 field, l;
+	void __iomem *reg;
 
 	reg = IOMUXSW_PAD_CTL + (pin + 2) / 3;
 	field = (pin + 2) % 3;
diff --git a/arch/arm/mach-mx3/mm.c b/arch/arm/mach-mx3/mm.c
index 30d842b..0589b5c 100644
--- a/arch/arm/mach-mx3/mm.c
+++ b/arch/arm/mach-mx3/mm.c
@@ -49,7 +49,7 @@
 		.virtual	= AVIC_BASE_ADDR_VIRT,
 		.pfn		= __phys_to_pfn(AVIC_BASE_ADDR),
 		.length		= AVIC_SIZE,
-		.type		= MT_NONSHARED_DEVICE
+		.type		= MT_DEVICE_NONSHARED
 	},
 };
 
diff --git a/arch/arm/mach-mx3/mx31ads.c b/arch/arm/mach-mx3/mx31ads.c
index 60fb4e0..1be4a39 100644
--- a/arch/arm/mach-mx3/mx31ads.c
+++ b/arch/arm/mach-mx3/mx31ads.c
@@ -22,6 +22,7 @@
 #include <linux/init.h>
 #include <linux/clk.h>
 #include <linux/serial_8250.h>
+#include <linux/irq.h>
 
 #include <mach/hardware.h>
 #include <asm/mach-types.h>
@@ -31,6 +32,8 @@
 #include <asm/mach/map.h>
 #include <mach/common.h>
 #include <mach/board-mx31ads.h>
+#include <mach/imx-uart.h>
+#include <mach/iomux-mx3.h>
 
 /*!
  * @file mx31ads.c
@@ -84,6 +87,108 @@
 }
 #endif
 
+#if defined(CONFIG_SERIAL_IMX) || defined(CONFIG_SERIAL_IMX_MODULE)
+static struct imxuart_platform_data uart_pdata = {
+	.flags = IMXUART_HAVE_RTSCTS,
+};
+
+static inline void mxc_init_imx_uart(void)
+{
+	mxc_iomux_mode(MX31_PIN_CTS1__CTS1);
+	mxc_iomux_mode(MX31_PIN_RTS1__RTS1);
+	mxc_iomux_mode(MX31_PIN_TXD1__TXD1);
+	mxc_iomux_mode(MX31_PIN_RXD1__RXD1);
+
+	mxc_register_device(&mxc_uart_device0, &uart_pdata);
+}
+#else /* !SERIAL_IMX */
+static inline void mxc_init_imx_uart(void)
+{
+}
+#endif /* !SERIAL_IMX */
+
+static void mx31ads_expio_irq_handler(u32 irq, struct irq_desc *desc)
+{
+	u32 imr_val;
+	u32 int_valid;
+	u32 expio_irq;
+
+	imr_val = __raw_readw(PBC_INTMASK_SET_REG);
+	int_valid = __raw_readw(PBC_INTSTATUS_REG) & imr_val;
+
+	expio_irq = MXC_EXP_IO_BASE;
+	for (; int_valid != 0; int_valid >>= 1, expio_irq++) {
+		if ((int_valid & 1) == 0)
+			continue;
+
+		generic_handle_irq(expio_irq);
+	}
+}
+
+/*
+ * Disable an expio pin's interrupt by setting the bit in the imr.
+ * @param irq           an expio virtual irq number
+ */
+static void expio_mask_irq(u32 irq)
+{
+	u32 expio = MXC_IRQ_TO_EXPIO(irq);
+	/* mask the interrupt */
+	__raw_writew(1 << expio, PBC_INTMASK_CLEAR_REG);
+	__raw_readw(PBC_INTMASK_CLEAR_REG);
+}
+
+/*
+ * Acknowledge an expanded io pin's interrupt by clearing the bit in the isr.
+ * @param irq           an expanded io virtual irq number
+ */
+static void expio_ack_irq(u32 irq)
+{
+	u32 expio = MXC_IRQ_TO_EXPIO(irq);
+	/* clear the interrupt status */
+	__raw_writew(1 << expio, PBC_INTSTATUS_REG);
+}
+
+/*
+ * Enable a expio pin's interrupt by clearing the bit in the imr.
+ * @param irq           a expio virtual irq number
+ */
+static void expio_unmask_irq(u32 irq)
+{
+	u32 expio = MXC_IRQ_TO_EXPIO(irq);
+	/* unmask the interrupt */
+	__raw_writew(1 << expio, PBC_INTMASK_SET_REG);
+}
+
+static struct irq_chip expio_irq_chip = {
+	.ack = expio_ack_irq,
+	.mask = expio_mask_irq,
+	.unmask = expio_unmask_irq,
+};
+
+static void __init mx31ads_init_expio(void)
+{
+	int i;
+
+	printk(KERN_INFO "MX31ADS EXPIO(CPLD) hardware\n");
+
+	/*
+	 * Configure INT line as GPIO input
+	 */
+	mxc_iomux_mode(IOMUX_MODE(MX31_PIN_GPIO1_4, IOMUX_CONFIG_GPIO));
+
+	/* disable the interrupt and clear the status */
+	__raw_writew(0xFFFF, PBC_INTMASK_CLEAR_REG);
+	__raw_writew(0xFFFF, PBC_INTSTATUS_REG);
+	for (i = MXC_EXP_IO_BASE; i < (MXC_EXP_IO_BASE + MXC_MAX_EXP_IO_LINES);
+	     i++) {
+		set_irq_chip(i, &expio_irq_chip);
+		set_irq_handler(i, handle_level_irq);
+		set_irq_flags(i, IRQF_VALID);
+	}
+	set_irq_type(EXPIO_PARENT_INT, IRQ_TYPE_LEVEL_HIGH);
+	set_irq_chained_handler(EXPIO_PARENT_INT, mx31ads_expio_irq_handler);
+}
+
 /*!
  * This structure defines static mappings for the i.MX31ADS board.
  */
@@ -92,17 +197,17 @@
 		.virtual	= AIPS1_BASE_ADDR_VIRT,
 		.pfn		= __phys_to_pfn(AIPS1_BASE_ADDR),
 		.length		= AIPS1_SIZE,
-		.type		= MT_NONSHARED_DEVICE
+		.type		= MT_DEVICE_NONSHARED
 	}, {
 		.virtual	= SPBA0_BASE_ADDR_VIRT,
 		.pfn		= __phys_to_pfn(SPBA0_BASE_ADDR),
 		.length		= SPBA0_SIZE,
-		.type		= MT_NONSHARED_DEVICE
+		.type		= MT_DEVICE_NONSHARED
 	}, {
 		.virtual	= AIPS2_BASE_ADDR_VIRT,
 		.pfn		= __phys_to_pfn(AIPS2_BASE_ADDR),
 		.length		= AIPS2_SIZE,
-		.type		= MT_NONSHARED_DEVICE
+		.type		= MT_DEVICE_NONSHARED
 	}, {
 		.virtual	= CS4_BASE_ADDR_VIRT,
 		.pfn		= __phys_to_pfn(CS4_BASE_ADDR),
@@ -120,12 +225,19 @@
 	iotable_init(mx31ads_io_desc, ARRAY_SIZE(mx31ads_io_desc));
 }
 
+void __init mx31ads_init_irq(void)
+{
+	mxc_init_irq();
+	mx31ads_init_expio();
+}
+
 /*!
  * Board specific initialization.
  */
 static void __init mxc_board_init(void)
 {
 	mxc_init_extuart();
+	mxc_init_imx_uart();
 }
 
 static void __init mx31ads_timer_init(void)
@@ -148,7 +260,7 @@
 	.io_pg_offst	= ((AIPS1_BASE_ADDR_VIRT) >> 18) & 0xfffc,
 	.boot_params    = PHYS_OFFSET + 0x100,
 	.map_io         = mx31ads_map_io,
-	.init_irq       = mxc_init_irq,
+	.init_irq       = mx31ads_init_irq,
 	.init_machine   = mxc_board_init,
 	.timer          = &mx31ads_timer,
 MACHINE_END
diff --git a/arch/arm/mach-mx3/mx31lite.c b/arch/arm/mach-mx3/mx31lite.c
index d363a6e..c434400 100644
--- a/arch/arm/mach-mx3/mx31lite.c
+++ b/arch/arm/mach-mx3/mx31lite.c
@@ -45,17 +45,17 @@
 		.virtual = AIPS1_BASE_ADDR_VIRT,
 		.pfn = __phys_to_pfn(AIPS1_BASE_ADDR),
 		.length = AIPS1_SIZE,
-		.type = MT_NONSHARED_DEVICE
+		.type = MT_DEVICE_NONSHARED
 	}, {
 		.virtual = SPBA0_BASE_ADDR_VIRT,
 		.pfn = __phys_to_pfn(SPBA0_BASE_ADDR),
 		.length = SPBA0_SIZE,
-		.type = MT_NONSHARED_DEVICE
+		.type = MT_DEVICE_NONSHARED
 	}, {
 		.virtual = AIPS2_BASE_ADDR_VIRT,
 		.pfn = __phys_to_pfn(AIPS2_BASE_ADDR),
 		.length = AIPS2_SIZE,
-		.type = MT_NONSHARED_DEVICE
+		.type = MT_DEVICE_NONSHARED
 	}, {
 		.virtual = CS4_BASE_ADDR_VIRT,
 		.pfn = __phys_to_pfn(CS4_BASE_ADDR),
diff --git a/arch/arm/mach-mx3/pcm037.c b/arch/arm/mach-mx3/pcm037.c
index df8582a..11fda95 100644
--- a/arch/arm/mach-mx3/pcm037.c
+++ b/arch/arm/mach-mx3/pcm037.c
@@ -33,6 +33,8 @@
 #include <mach/iomux-mx3.h>
 #include <mach/board-pcm037.h>
 
+#include "devices.h"
+
 static struct physmap_flash_data pcm037_flash_data = {
 	.width  = 2,
 };
@@ -73,12 +75,12 @@
 	mxc_iomux_mode(MX31_PIN_TXD1__TXD1);
 	mxc_iomux_mode(MX31_PIN_RXD1__RXD1);
 
-	imx_init_uart(0, &uart_pdata);
+	mxc_register_device(&mxc_uart_device0, &uart_pdata);
 
 	mxc_iomux_mode(MX31_PIN_CSPI3_MOSI__RXD3);
 	mxc_iomux_mode(MX31_PIN_CSPI3_MISO__TXD3);
 
-	imx_init_uart(2, &uart_pdata);
+	mxc_register_device(&mxc_uart_device2, &uart_pdata);
 }
 
 /*
diff --git a/arch/arm/mach-netx/generic.c b/arch/arm/mach-netx/generic.c
index 1b40483..79df60c 100644
--- a/arch/arm/mach-netx/generic.c
+++ b/arch/arm/mach-netx/generic.c
@@ -22,10 +22,10 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
+#include <linux/io.h>
 #include <mach/hardware.h>
 #include <asm/mach/map.h>
 #include <asm/hardware/vic.h>
-#include <asm/io.h>
 #include <mach/netx-regs.h>
 #include <asm/mach/irq.h>
 
@@ -77,15 +77,12 @@
 	stat = ((readl(NETX_DPMAS_INT_EN) &
 		readl(NETX_DPMAS_INT_STAT)) >> 24) & 0x1f;
 
-	desc = irq_desc + NETX_IRQ_HIF_CHAINED(0);
-
 	while (stat) {
 		if (stat & 1) {
 			DEBUG_IRQ("handling irq %d\n", irq);
-			desc_handle_irq(irq, desc);
+			generic_handle_irq(irq);
 		}
 		irq++;
-		desc++;
 		stat >>= 1;
 	}
 }
diff --git a/arch/arm/mach-netx/include/mach/system.h b/arch/arm/mach-netx/include/mach/system.h
index 27d8ef8..6c1023b 100644
--- a/arch/arm/mach-netx/include/mach/system.h
+++ b/arch/arm/mach-netx/include/mach/system.h
@@ -19,7 +19,7 @@
 #ifndef __ASM_ARCH_SYSTEM_H
 #define __ASM_ARCH_SYSTEM_H
 
-#include <asm/io.h>
+#include <linux/io.h>
 #include <mach/hardware.h>
 #include "netx-regs.h"
 
diff --git a/arch/arm/mach-netx/pfifo.c b/arch/arm/mach-netx/pfifo.c
index 19ae0a7..0398494 100644
--- a/arch/arm/mach-netx/pfifo.c
+++ b/arch/arm/mach-netx/pfifo.c
@@ -20,8 +20,8 @@
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/mutex.h>
+#include <linux/io.h>
 
-#include <asm/io.h>
 #include <mach/hardware.h>
 #include <mach/netx-regs.h>
 #include <mach/pfifo.h>
diff --git a/arch/arm/mach-netx/time.c b/arch/arm/mach-netx/time.c
index ac8e5bf..7c540c1 100644
--- a/arch/arm/mach-netx/time.c
+++ b/arch/arm/mach-netx/time.c
@@ -21,9 +21,9 @@
 #include <linux/interrupt.h>
 #include <linux/irq.h>
 #include <linux/clocksource.h>
+#include <linux/io.h>
 
 #include <mach/hardware.h>
-#include <asm/io.h>
 #include <asm/mach/time.h>
 #include <mach/netx-regs.h>
 
diff --git a/arch/arm/mach-netx/xc.c b/arch/arm/mach-netx/xc.c
index 04c34e8..32eabf5 100644
--- a/arch/arm/mach-netx/xc.c
+++ b/arch/arm/mach-netx/xc.c
@@ -21,8 +21,8 @@
 #include <linux/device.h>
 #include <linux/firmware.h>
 #include <linux/mutex.h>
+#include <linux/io.h>
 
-#include <asm/io.h>
 #include <mach/hardware.h>
 #include <mach/netx-regs.h>
 
diff --git a/arch/arm/mach-ns9xxx/board-a9m9750dev.c b/arch/arm/mach-ns9xxx/board-a9m9750dev.c
index a22a608..b45bb3b 100644
--- a/arch/arm/mach-ns9xxx/board-a9m9750dev.c
+++ b/arch/arm/mach-ns9xxx/board-a9m9750dev.c
@@ -86,13 +86,10 @@
 
 	while (stat != 0) {
 		int irqno = fls(stat) - 1;
-		struct irq_desc *fpgadesc;
 
 		stat &= ~(1 << irqno);
 
-		fpgadesc = irq_desc + FPGA_IRQ(irqno);
-
-		desc_handle_irq(FPGA_IRQ(irqno), fpgadesc);
+		generic_handle_irq(FPGA_IRQ(irqno));
 	}
 
 	desc->chip->unmask(irq);
diff --git a/arch/arm/mach-ns9xxx/gpio.c b/arch/arm/mach-ns9xxx/gpio.c
index 804c300..5241e6a 100644
--- a/arch/arm/mach-ns9xxx/gpio.c
+++ b/arch/arm/mach-ns9xxx/gpio.c
@@ -12,13 +12,13 @@
 #include <linux/init.h>
 #include <linux/spinlock.h>
 #include <linux/module.h>
+#include <linux/bitops.h>
 
 #include <mach/gpio.h>
 #include <mach/processor.h>
 #include <mach/processor-ns9360.h>
 #include <asm/bug.h>
 #include <asm/types.h>
-#include <asm/bitops.h>
 
 #include "gpio-ns9360.h"
 
diff --git a/arch/arm/mach-ns9xxx/include/mach/uncompress.h b/arch/arm/mach-ns9xxx/include/mach/uncompress.h
index 5dbc3c5..1b12d32 100644
--- a/arch/arm/mach-ns9xxx/include/mach/uncompress.h
+++ b/arch/arm/mach-ns9xxx/include/mach/uncompress.h
@@ -11,7 +11,7 @@
 #ifndef __ASM_ARCH_UNCOMPRESS_H
 #define __ASM_ARCH_UNCOMPRESS_H
 
-#include <asm/io.h>
+#include <linux/io.h>
 
 #define __REG(x)	((void __iomem __force *)(x))
 
diff --git a/arch/arm/mach-ns9xxx/irq.c b/arch/arm/mach-ns9xxx/irq.c
index 38260d5..22e0eb6 100644
--- a/arch/arm/mach-ns9xxx/irq.c
+++ b/arch/arm/mach-ns9xxx/irq.c
@@ -10,7 +10,7 @@
  */
 #include <linux/interrupt.h>
 #include <linux/kernel_stat.h>
-#include <asm/io.h>
+#include <linux/io.h>
 #include <asm/mach/irq.h>
 #include <mach/regs-sys-common.h>
 #include <mach/irqs.h>
diff --git a/arch/arm/mach-omap1/board-h3.c b/arch/arm/mach-omap1/board-h3.c
index 2ced6d9..adfcd7b 100644
--- a/arch/arm/mach-omap1/board-h3.c
+++ b/arch/arm/mach-omap1/board-h3.c
@@ -476,6 +476,10 @@
 		I2C_BOARD_INFO("tps65013", 0x48),
                /* .irq         = OMAP_GPIO_IRQ(??), */
        },
+	{
+		I2C_BOARD_INFO("isp1301_omap", 0x2d),
+		.irq		= OMAP_GPIO_IRQ(14),
+	},
 };
 
 static struct omap_gpio_switch h3_gpio_switches[] __initdata = {
diff --git a/arch/arm/mach-omap1/board-voiceblue.c b/arch/arm/mach-omap1/board-voiceblue.c
index 213b487..45a0131 100644
--- a/arch/arm/mach-omap1/board-voiceblue.c
+++ b/arch/arm/mach-omap1/board-voiceblue.c
@@ -21,6 +21,7 @@
 #include <linux/reboot.h>
 #include <linux/serial_8250.h>
 #include <linux/serial_reg.h>
+#include <linux/irq.h>
 
 #include <mach/hardware.h>
 #include <asm/mach-types.h>
diff --git a/arch/arm/mach-omap1/clock.c b/arch/arm/mach-omap1/clock.c
index 5965cf0..478c2c9 100644
--- a/arch/arm/mach-omap1/clock.c
+++ b/arch/arm/mach-omap1/clock.c
@@ -17,8 +17,8 @@
 #include <linux/errno.h>
 #include <linux/err.h>
 #include <linux/clk.h>
+#include <linux/io.h>
 
-#include <asm/io.h>
 #include <asm/mach-types.h>
 
 #include <mach/cpu.h>
diff --git a/arch/arm/mach-omap1/devices.c b/arch/arm/mach-omap1/devices.c
index ab708d4..99982d3 100644
--- a/arch/arm/mach-omap1/devices.c
+++ b/arch/arm/mach-omap1/devices.c
@@ -13,9 +13,9 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/platform_device.h>
+#include <linux/io.h>
 
 #include <mach/hardware.h>
-#include <asm/io.h>
 #include <asm/mach/map.h>
 
 #include <mach/tc.h>
diff --git a/arch/arm/mach-omap1/fpga.c b/arch/arm/mach-omap1/fpga.c
index 4449d86..0499538 100644
--- a/arch/arm/mach-omap1/fpga.c
+++ b/arch/arm/mach-omap1/fpga.c
@@ -21,9 +21,9 @@
 #include <linux/kernel.h>
 #include <linux/device.h>
 #include <linux/errno.h>
+#include <linux/io.h>
 
 #include <mach/hardware.h>
-#include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/mach/irq.h>
 
@@ -86,7 +86,6 @@
 
 void innovator_fpga_IRQ_demux(unsigned int irq, struct irq_desc *desc)
 {
-	struct irq_desc *d;
 	u32 stat;
 	int fpga_irq;
 
@@ -99,8 +98,7 @@
 	     (fpga_irq < OMAP_FPGA_IRQ_END) && stat;
 	     fpga_irq++, stat >>= 1) {
 		if (stat & 1) {
-			d = irq_desc + fpga_irq;
-			desc_handle_irq(fpga_irq, d);
+			generic_handle_irq(fpga_irq);
 		}
 	}
 }
diff --git a/arch/arm/mach-omap1/id.c b/arch/arm/mach-omap1/id.c
index da13c3e..13083d7 100644
--- a/arch/arm/mach-omap1/id.c
+++ b/arch/arm/mach-omap1/id.c
@@ -14,8 +14,7 @@
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
-
-#include <asm/io.h>
+#include <linux/io.h>
 
 #define OMAP_DIE_ID_0		0xfffe1800
 #define OMAP_DIE_ID_1		0xfffe1804
diff --git a/arch/arm/mach-omap1/io.c b/arch/arm/mach-omap1/io.c
index 2b9750b..b3bd8ca 100644
--- a/arch/arm/mach-omap1/io.c
+++ b/arch/arm/mach-omap1/io.c
@@ -11,10 +11,10 @@
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
+#include <linux/io.h>
 
 #include <asm/tlb.h>
 #include <asm/mach/map.h>
-#include <asm/io.h>
 #include <mach/mux.h>
 #include <mach/tc.h>
 
diff --git a/arch/arm/mach-omap1/irq.c b/arch/arm/mach-omap1/irq.c
index 0ec6c1ec..9ad5197 100644
--- a/arch/arm/mach-omap1/irq.c
+++ b/arch/arm/mach-omap1/irq.c
@@ -40,6 +40,7 @@
 #include <linux/module.h>
 #include <linux/sched.h>
 #include <linux/interrupt.h>
+#include <linux/io.h>
 
 #include <mach/hardware.h>
 #include <asm/irq.h>
@@ -47,8 +48,6 @@
 #include <mach/gpio.h>
 #include <mach/cpu.h>
 
-#include <asm/io.h>
-
 #define IRQ_BANK(irq) ((irq) >> 5)
 #define IRQ_BIT(irq)  ((irq) & 0x1f)
 
diff --git a/arch/arm/mach-omap1/leds-h2p2-debug.c b/arch/arm/mach-omap1/leds-h2p2-debug.c
index 610f51f..71fe2cc 100644
--- a/arch/arm/mach-omap1/leds-h2p2-debug.c
+++ b/arch/arm/mach-omap1/leds-h2p2-debug.c
@@ -12,8 +12,8 @@
 #include <linux/init.h>
 #include <linux/kernel_stat.h>
 #include <linux/sched.h>
+#include <linux/io.h>
 
-#include <asm/io.h>
 #include <mach/hardware.h>
 #include <asm/leds.h>
 #include <asm/system.h>
diff --git a/arch/arm/mach-omap1/mailbox.c b/arch/arm/mach-omap1/mailbox.c
index af44eab..59abbf3 100644
--- a/arch/arm/mach-omap1/mailbox.c
+++ b/arch/arm/mach-omap1/mailbox.c
@@ -13,9 +13,9 @@
 #include <linux/resource.h>
 #include <linux/interrupt.h>
 #include <linux/platform_device.h>
+#include <linux/io.h>
 #include <mach/mailbox.h>
 #include <mach/irqs.h>
-#include <asm/io.h>
 
 #define MAILBOX_ARM2DSP1		0x00
 #define MAILBOX_ARM2DSP1b		0x04
diff --git a/arch/arm/mach-omap1/mux.c b/arch/arm/mach-omap1/mux.c
index 898516e..062c905 100644
--- a/arch/arm/mach-omap1/mux.c
+++ b/arch/arm/mach-omap1/mux.c
@@ -24,10 +24,11 @@
  */
 #include <linux/module.h>
 #include <linux/init.h>
-#include <asm/system.h>
-#include <asm/io.h>
+#include <linux/io.h>
 #include <linux/spinlock.h>
 
+#include <asm/system.h>
+
 #include <mach/mux.h>
 
 #ifdef CONFIG_OMAP_MUX
diff --git a/arch/arm/mach-omap1/pm.c b/arch/arm/mach-omap1/pm.c
index 63c4ea1..770d256 100644
--- a/arch/arm/mach-omap1/pm.c
+++ b/arch/arm/mach-omap1/pm.c
@@ -41,8 +41,8 @@
 #include <linux/interrupt.h>
 #include <linux/sysfs.h>
 #include <linux/module.h>
+#include <linux/io.h>
 
-#include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/atomic.h>
 #include <asm/mach/time.h>
diff --git a/arch/arm/mach-omap1/serial.c b/arch/arm/mach-omap1/serial.c
index 0e25a99..aefc967 100644
--- a/arch/arm/mach-omap1/serial.c
+++ b/arch/arm/mach-omap1/serial.c
@@ -18,8 +18,8 @@
 #include <linux/serial_8250.h>
 #include <linux/serial_reg.h>
 #include <linux/clk.h>
+#include <linux/io.h>
 
-#include <asm/io.h>
 #include <asm/mach-types.h>
 
 #include <mach/board.h>
diff --git a/arch/arm/mach-omap1/time.c b/arch/arm/mach-omap1/time.c
index e547085..2cf7e32 100644
--- a/arch/arm/mach-omap1/time.c
+++ b/arch/arm/mach-omap1/time.c
@@ -43,10 +43,10 @@
 #include <linux/err.h>
 #include <linux/clocksource.h>
 #include <linux/clockchips.h>
+#include <linux/io.h>
 
 #include <asm/system.h>
 #include <mach/hardware.h>
-#include <asm/io.h>
 #include <asm/leds.h>
 #include <asm/irq.h>
 #include <asm/mach/irq.h>
diff --git a/arch/arm/mach-omap1/timer32k.c b/arch/arm/mach-omap1/timer32k.c
index e677601..705367e 100644
--- a/arch/arm/mach-omap1/timer32k.c
+++ b/arch/arm/mach-omap1/timer32k.c
@@ -44,10 +44,10 @@
 #include <linux/clk.h>
 #include <linux/clocksource.h>
 #include <linux/clockchips.h>
+#include <linux/io.h>
 
 #include <asm/system.h>
 #include <mach/hardware.h>
-#include <asm/io.h>
 #include <asm/leds.h>
 #include <asm/irq.h>
 #include <asm/mach/irq.h>
diff --git a/arch/arm/mach-omap2/board-2430sdp.c b/arch/arm/mach-omap2/board-2430sdp.c
index b72ca13..24688ef 100644
--- a/arch/arm/mach-omap2/board-2430sdp.c
+++ b/arch/arm/mach-omap2/board-2430sdp.c
@@ -21,6 +21,7 @@
 #include <linux/delay.h>
 #include <linux/err.h>
 #include <linux/clk.h>
+#include <linux/io.h>
 
 #include <mach/hardware.h>
 #include <asm/mach-types.h>
@@ -34,8 +35,6 @@
 #include <mach/common.h>
 #include <mach/gpmc.h>
 
-#include <asm/io.h>
-
 
 #define	SDP2430_FLASH_CS	0
 #define	SDP2430_SMC91X_CS	5
diff --git a/arch/arm/mach-omap2/board-h4.c b/arch/arm/mach-omap2/board-h4.c
index 9e2624c..2fef2c8 100644
--- a/arch/arm/mach-omap2/board-h4.c
+++ b/arch/arm/mach-omap2/board-h4.c
@@ -18,9 +18,11 @@
 #include <linux/mtd/partitions.h>
 #include <linux/delay.h>
 #include <linux/workqueue.h>
+#include <linux/i2c.h>
 #include <linux/input.h>
 #include <linux/err.h>
 #include <linux/clk.h>
+#include <linux/io.h>
 
 #include <mach/hardware.h>
 #include <asm/mach-types.h>
@@ -41,8 +43,6 @@
 #include <mach/dma.h>
 #include <mach/gpmc.h>
 
-#include <asm/io.h>
-
 #define H4_FLASH_CS	0
 #define H4_SMC91X_CS	1
 
@@ -392,6 +392,13 @@
 	{ OMAP_TAG_LCD,		&h4_lcd_config },
 };
 
+static struct i2c_board_info __initdata h4_i2c_board_info[] = {
+	{
+		I2C_BOARD_INFO("isp1301_omap", 0x2d),
+		.irq		= OMAP_GPIO_IRQ(125),
+	},
+};
+
 static void __init omap_h4_init(void)
 {
 	/*
@@ -412,6 +419,9 @@
 	}
 #endif
 
+	i2c_register_board_info(1, h4_i2c_board_info,
+			ARRAY_SIZE(h4_i2c_board_info));
+
 	platform_add_devices(h4_devices, ARRAY_SIZE(h4_devices));
 	omap_board_config = h4_config;
 	omap_board_config_size = ARRAY_SIZE(h4_config);
diff --git a/arch/arm/mach-omap2/clock.c b/arch/arm/mach-omap2/clock.c
index 1d891e4..97cde3d3 100644
--- a/arch/arm/mach-omap2/clock.c
+++ b/arch/arm/mach-omap2/clock.c
@@ -21,9 +21,8 @@
 #include <linux/errno.h>
 #include <linux/delay.h>
 #include <linux/clk.h>
-#include <asm/bitops.h>
-
-#include <asm/io.h>
+#include <linux/io.h>
+#include <linux/bitops.h>
 
 #include <mach/clock.h>
 #include <mach/sram.h>
diff --git a/arch/arm/mach-omap2/clock24xx.c b/arch/arm/mach-omap2/clock24xx.c
index 295e671..d382eb0 100644
--- a/arch/arm/mach-omap2/clock24xx.c
+++ b/arch/arm/mach-omap2/clock24xx.c
@@ -24,14 +24,13 @@
 #include <linux/errno.h>
 #include <linux/delay.h>
 #include <linux/clk.h>
-
 #include <linux/io.h>
 #include <linux/cpufreq.h>
+#include <linux/bitops.h>
 
 #include <mach/clock.h>
 #include <mach/sram.h>
 #include <asm/div64.h>
-#include <asm/bitops.h>
 
 #include "memory.h"
 #include "clock.h"
diff --git a/arch/arm/mach-omap2/clock34xx.c b/arch/arm/mach-omap2/clock34xx.c
index 3ff7495..e5b475f 100644
--- a/arch/arm/mach-omap2/clock34xx.c
+++ b/arch/arm/mach-omap2/clock34xx.c
@@ -25,11 +25,11 @@
 #include <linux/clk.h>
 #include <linux/io.h>
 #include <linux/limits.h>
+#include <linux/bitops.h>
 
 #include <mach/clock.h>
 #include <mach/sram.h>
 #include <asm/div64.h>
-#include <asm/bitops.h>
 
 #include "memory.h"
 #include "clock.h"
diff --git a/arch/arm/mach-omap2/devices.c b/arch/arm/mach-omap2/devices.c
index 7a7f025..2ee954a 100644
--- a/arch/arm/mach-omap2/devices.c
+++ b/arch/arm/mach-omap2/devices.c
@@ -13,9 +13,9 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/platform_device.h>
+#include <linux/io.h>
 
 #include <mach/hardware.h>
-#include <asm/io.h>
 #include <asm/mach-types.h>
 #include <asm/mach/map.h>
 
diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c
index f51d69b..af1081a 100644
--- a/arch/arm/mach-omap2/gpmc.c
+++ b/arch/arm/mach-omap2/gpmc.c
@@ -15,8 +15,8 @@
 #include <linux/clk.h>
 #include <linux/ioport.h>
 #include <linux/spinlock.h>
+#include <linux/io.h>
 
-#include <asm/io.h>
 #include <asm/mach-types.h>
 #include <mach/gpmc.h>
 
diff --git a/arch/arm/mach-omap2/id.c b/arch/arm/mach-omap2/id.c
index a5d4526..209177c 100644
--- a/arch/arm/mach-omap2/id.c
+++ b/arch/arm/mach-omap2/id.c
@@ -14,8 +14,9 @@
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
+#include <linux/io.h>
 
-#include <asm/io.h>
+#include <asm/cputype.h>
 
 #include <mach/control.h>
 #include <mach/cpu.h>
diff --git a/arch/arm/mach-omap2/io.c b/arch/arm/mach-omap2/io.c
index 987351f..7c3d628 100644
--- a/arch/arm/mach-omap2/io.c
+++ b/arch/arm/mach-omap2/io.c
@@ -15,9 +15,9 @@
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
+#include <linux/io.h>
 
 #include <asm/tlb.h>
-#include <asm/io.h>
 
 #include <asm/mach/map.h>
 
diff --git a/arch/arm/mach-omap2/irq.c b/arch/arm/mach-omap2/irq.c
index 9ef15b3..196a956 100644
--- a/arch/arm/mach-omap2/irq.c
+++ b/arch/arm/mach-omap2/irq.c
@@ -13,10 +13,10 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
+#include <linux/io.h>
 #include <mach/hardware.h>
 #include <asm/mach/irq.h>
 #include <asm/irq.h>
-#include <asm/io.h>
 
 #define INTC_REVISION	0x0000
 #define INTC_SYSCONFIG	0x0010
diff --git a/arch/arm/mach-omap2/mailbox.c b/arch/arm/mach-omap2/mailbox.c
index a480b96..32b7af3 100644
--- a/arch/arm/mach-omap2/mailbox.c
+++ b/arch/arm/mach-omap2/mailbox.c
@@ -14,9 +14,9 @@
 #include <linux/clk.h>
 #include <linux/err.h>
 #include <linux/platform_device.h>
+#include <linux/io.h>
 #include <mach/mailbox.h>
 #include <mach/irqs.h>
-#include <asm/io.h>
 
 #define MAILBOX_REVISION		0x00
 #define MAILBOX_SYSCONFIG		0x10
diff --git a/arch/arm/mach-omap2/memory.c b/arch/arm/mach-omap2/memory.c
index 6b49cc9..ab1462b 100644
--- a/arch/arm/mach-omap2/memory.c
+++ b/arch/arm/mach-omap2/memory.c
@@ -21,8 +21,7 @@
 #include <linux/errno.h>
 #include <linux/delay.h>
 #include <linux/clk.h>
-
-#include <asm/io.h>
+#include <linux/io.h>
 
 #include <mach/common.h>
 #include <mach/clock.h>
diff --git a/arch/arm/mach-omap2/mux.c b/arch/arm/mach-omap2/mux.c
index 443d07f..6b7d672 100644
--- a/arch/arm/mach-omap2/mux.c
+++ b/arch/arm/mach-omap2/mux.c
@@ -25,10 +25,11 @@
  */
 #include <linux/module.h>
 #include <linux/init.h>
-#include <asm/system.h>
-#include <asm/io.h>
+#include <linux/io.h>
 #include <linux/spinlock.h>
 
+#include <asm/system.h>
+
 #include <mach/control.h>
 #include <mach/mux.h>
 
diff --git a/arch/arm/mach-omap2/pm.c b/arch/arm/mach-omap2/pm.c
index 8671e10..55361c1 100644
--- a/arch/arm/mach-omap2/pm.c
+++ b/arch/arm/mach-omap2/pm.c
@@ -24,8 +24,8 @@
 #include <linux/module.h>
 #include <linux/delay.h>
 #include <linux/clk.h>
+#include <linux/io.h>
 
-#include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/atomic.h>
 #include <asm/mach/time.h>
diff --git a/arch/arm/mach-omap2/serial.c b/arch/arm/mach-omap2/serial.c
index adc8a26a..7d9444a 100644
--- a/arch/arm/mach-omap2/serial.c
+++ b/arch/arm/mach-omap2/serial.c
@@ -17,8 +17,7 @@
 #include <linux/serial_8250.h>
 #include <linux/serial_reg.h>
 #include <linux/clk.h>
-
-#include <asm/io.h>
+#include <linux/io.h>
 
 #include <mach/common.h>
 #include <mach/board.h>
diff --git a/arch/arm/mach-orion5x/Kconfig b/arch/arm/mach-orion5x/Kconfig
index ddcd41b..f59a8d0 100644
--- a/arch/arm/mach-orion5x/Kconfig
+++ b/arch/arm/mach-orion5x/Kconfig
@@ -36,6 +36,12 @@
 	  Say 'Y' here if you want your kernel to support the
 	  QNAP TS-109/TS-209 platform.
 
+config MACH_TERASTATION_PRO2
+	bool "Buffalo Terastation Pro II/Live"
+	help
+	  Say 'Y' here if you want your kernel to support the
+	  Buffalo Terastation Pro II/Live platform.
+
 config MACH_LINKSTATION_PRO
 	bool "Buffalo Linkstation Pro/Live"
 	select I2C_BOARDINFO
@@ -44,6 +50,13 @@
 	  Buffalo Linkstation Pro/Live platform. Both v1 and
 	  v2 devices are supported.
 
+config MACH_LINKSTATION_MINI
+	bool "Buffalo Linkstation Mini"
+	select I2C_BOARDINFO
+	help
+	  Say 'Y' here if you want your kernel to support the
+	  Buffalo Linkstation Mini platform.
+
 config MACH_TS409
 	bool "QNAP TS-409"
 	help
@@ -68,6 +81,13 @@
 	  Say 'Y' here if you want your kernel to support the
 	  HP Media Vault mv2120 or mv5100.
 
+config MACH_EDMINI_V2
+	bool "LaCie Ethernet Disk mini V2"
+	select I2C_BOARDINFO
+	help
+	  Say 'Y' here if you want your kernel to support the
+	  LaCie Ethernet Disk mini V2.
+
 config MACH_MSS2
 	bool "Maxtor Shared Storage II"
 	help
@@ -92,6 +112,12 @@
 	  Say 'Y' here if you want your kernel to support the
 	  Marvell Orion-VoIP FXO (88F5181L) RD.
 
+config MACH_RD88F6183AP_GE
+	bool "Marvell Orion-1-90 AP GE Reference Design"
+	help
+	  Say 'Y' here if you want your kernel to support the
+	  Marvell Orion-1-90 (88F6183) AP GE RD.
+
 endmenu
 
 endif
diff --git a/arch/arm/mach-orion5x/Makefile b/arch/arm/mach-orion5x/Makefile
index fcc48a8..3d4a1bc 100644
--- a/arch/arm/mach-orion5x/Makefile
+++ b/arch/arm/mach-orion5x/Makefile
@@ -2,14 +2,18 @@
 obj-$(CONFIG_MACH_DB88F5281)	+= db88f5281-setup.o
 obj-$(CONFIG_MACH_RD88F5182)	+= rd88f5182-setup.o
 obj-$(CONFIG_MACH_KUROBOX_PRO)	+= kurobox_pro-setup.o
+obj-$(CONFIG_MACH_TERASTATION_PRO2)	+= terastation_pro2-setup.o
 obj-$(CONFIG_MACH_LINKSTATION_PRO) += kurobox_pro-setup.o
+obj-$(CONFIG_MACH_LINKSTATION_MINI) += lsmini-setup.o
 obj-$(CONFIG_MACH_DNS323)	+= dns323-setup.o
 obj-$(CONFIG_MACH_TS209)	+= ts209-setup.o tsx09-common.o
 obj-$(CONFIG_MACH_TS409)	+= ts409-setup.o tsx09-common.o
 obj-$(CONFIG_MACH_WRT350N_V2)	+= wrt350n-v2-setup.o
 obj-$(CONFIG_MACH_TS78XX)	+= ts78xx-setup.o
 obj-$(CONFIG_MACH_MV2120)	+= mv2120-setup.o
+obj-$(CONFIG_MACH_EDMINI_V2)	+= edmini_v2-setup.o
 obj-$(CONFIG_MACH_MSS2)		+= mss2-setup.o
 obj-$(CONFIG_MACH_WNR854T)	+= wnr854t-setup.o
 obj-$(CONFIG_MACH_RD88F5181L_GE)	+= rd88f5181l-ge-setup.o
 obj-$(CONFIG_MACH_RD88F5181L_FXO)	+= rd88f5181l-fxo-setup.o
+obj-$(CONFIG_MACH_RD88F6183AP_GE)	+= rd88f6183ap-ge-setup.o
diff --git a/arch/arm/mach-orion5x/addr-map.c b/arch/arm/mach-orion5x/addr-map.c
index bea3797..719957e 100644
--- a/arch/arm/mach-orion5x/addr-map.c
+++ b/arch/arm/mach-orion5x/addr-map.c
@@ -13,8 +13,8 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/mbus.h>
+#include <linux/io.h>
 #include <mach/hardware.h>
-#include <asm/io.h>
 #include "common.h"
 
 /*
diff --git a/arch/arm/mach-orion5x/common.c b/arch/arm/mach-orion5x/common.c
index 7b11e55..9625ef5 100644
--- a/arch/arm/mach-orion5x/common.c
+++ b/arch/arm/mach-orion5x/common.c
@@ -18,6 +18,7 @@
 #include <linux/mv643xx_eth.h>
 #include <linux/mv643xx_i2c.h>
 #include <linux/ata_platform.h>
+#include <linux/spi/orion_spi.h>
 #include <asm/page.h>
 #include <asm/setup.h>
 #include <asm/timex.h>
@@ -146,7 +147,6 @@
  ****************************************************************************/
 struct mv643xx_eth_shared_platform_data orion5x_eth_shared_data = {
 	.dram		= &orion5x_mbus_dram_info,
-	.t_clk		= ORION5X_TCLK,
 };
 
 static struct resource orion5x_eth_shared_resources[] = {
@@ -154,6 +154,10 @@
 		.start	= ORION5X_ETH_PHYS_BASE + 0x2000,
 		.end	= ORION5X_ETH_PHYS_BASE + 0x3fff,
 		.flags	= IORESOURCE_MEM,
+	}, {
+		.start	= IRQ_ORION5X_ETH_ERR,
+		.end	= IRQ_ORION5X_ETH_ERR,
+		.flags	= IORESOURCE_IRQ,
 	},
 };
 
@@ -163,7 +167,7 @@
 	.dev		= {
 		.platform_data	= &orion5x_eth_shared_data,
 	},
-	.num_resources	= 1,
+	.num_resources	= ARRAY_SIZE(orion5x_eth_shared_resources),
 	.resource	= orion5x_eth_shared_resources,
 };
 
@@ -268,6 +272,38 @@
 
 
 /*****************************************************************************
+ * SPI
+ ****************************************************************************/
+static struct orion_spi_info orion5x_spi_plat_data = {
+	.tclk		= 0,
+};
+
+static struct resource orion5x_spi_resources[] = {
+	{
+		.name	= "spi base",
+		.start	= SPI_PHYS_BASE,
+		.end	= SPI_PHYS_BASE + 0x1f,
+		.flags	= IORESOURCE_MEM,
+	},
+};
+
+static struct platform_device orion5x_spi = {
+	.name		= "orion_spi",
+	.id		= 0,
+	.dev		= {
+		.platform_data	= &orion5x_spi_plat_data,
+	},
+	.num_resources	= ARRAY_SIZE(orion5x_spi_resources),
+	.resource	= orion5x_spi_resources,
+};
+
+void __init orion5x_spi_init()
+{
+	platform_device_register(&orion5x_spi);
+}
+
+
+/*****************************************************************************
  * UART0
  ****************************************************************************/
 static struct plat_serial8250_port orion5x_uart0_data[] = {
@@ -278,7 +314,7 @@
 		.flags		= UPF_SKIP_TEST | UPF_BOOT_AUTOCONF,
 		.iotype		= UPIO_MEM,
 		.regshift	= 2,
-		.uartclk	= ORION5X_TCLK,
+		.uartclk	= 0,
 	}, {
 	},
 };
@@ -322,7 +358,7 @@
 		.flags		= UPF_SKIP_TEST | UPF_BOOT_AUTOCONF,
 		.iotype		= UPIO_MEM,
 		.regshift	= 2,
-		.uartclk	= ORION5X_TCLK,
+		.uartclk	= 0,
 	}, {
 	},
 };
@@ -455,9 +491,24 @@
 /*****************************************************************************
  * Time handling
  ****************************************************************************/
+int orion5x_tclk;
+
+int __init orion5x_find_tclk(void)
+{
+	u32 dev, rev;
+
+	orion5x_pcie_id(&dev, &rev);
+	if (dev == MV88F6183_DEV_ID &&
+	    (readl(MPP_RESET_SAMPLE) & 0x00000200) == 0)
+		return 133333333;
+
+	return 166666667;
+}
+
 static void orion5x_timer_init(void)
 {
-	orion_time_init(IRQ_ORION5X_BRIDGE, ORION5X_TCLK);
+	orion5x_tclk = orion5x_find_tclk();
+	orion_time_init(IRQ_ORION5X_BRIDGE, orion5x_tclk);
 }
 
 struct sys_timer orion5x_timer = {
@@ -499,6 +550,12 @@
 		} else {
 			*dev_name = "MV88F5181(L)-Rev-Unsupported";
 		}
+	} else if (*dev == MV88F6183_DEV_ID) {
+		if (*rev == MV88F6183_REV_B0) {
+			*dev_name = "MV88F6183-Rev-B0";
+		} else {
+			*dev_name = "MV88F6183-Rev-Unsupported";
+		}
 	} else {
 		*dev_name = "Device-Unknown";
 	}
@@ -510,7 +567,12 @@
 	u32 dev, rev;
 
 	orion5x_id(&dev, &rev, &dev_name);
-	printk(KERN_INFO "Orion ID: %s. TCLK=%d.\n", dev_name, ORION5X_TCLK);
+	printk(KERN_INFO "Orion ID: %s. TCLK=%d.\n", dev_name, orion5x_tclk);
+
+	orion5x_eth_shared_data.t_clk = orion5x_tclk;
+	orion5x_spi_plat_data.tclk = orion5x_tclk;
+	orion5x_uart0_data[0].uartclk = orion5x_tclk;
+	orion5x_uart1_data[0].uartclk = orion5x_tclk;
 
 	/*
 	 * Setup Orion address map
diff --git a/arch/arm/mach-orion5x/common.h b/arch/arm/mach-orion5x/common.h
index 0bd1955..1f8b2da 100644
--- a/arch/arm/mach-orion5x/common.h
+++ b/arch/arm/mach-orion5x/common.h
@@ -10,6 +10,7 @@
 void orion5x_map_io(void);
 void orion5x_init_irq(void);
 void orion5x_init(void);
+extern int orion5x_tclk;
 extern struct sys_timer orion5x_timer;
 
 /*
@@ -30,6 +31,7 @@
 void orion5x_eth_init(struct mv643xx_eth_platform_data *eth_data);
 void orion5x_i2c_init(void);
 void orion5x_sata_init(struct mv_sata_platform_data *sata_data);
+void orion5x_spi_init(void);
 void orion5x_uart0_init(void);
 void orion5x_uart1_init(void);
 void orion5x_xor_init(void);
diff --git a/arch/arm/mach-orion5x/db88f5281-setup.c b/arch/arm/mach-orion5x/db88f5281-setup.c
index ff13e90..d318bea 100644
--- a/arch/arm/mach-orion5x/db88f5281-setup.c
+++ b/arch/arm/mach-orion5x/db88f5281-setup.c
@@ -285,7 +285,7 @@
  * Ethernet
  ****************************************************************************/
 static struct mv643xx_eth_platform_data db88f5281_eth_data = {
-	.phy_addr	= 8,
+	.phy_addr	= MV643XX_ETH_PHY_ADDR(8),
 };
 
 /*****************************************************************************
diff --git a/arch/arm/mach-orion5x/dns323-setup.c b/arch/arm/mach-orion5x/dns323-setup.c
index b38c65c..3e66098 100644
--- a/arch/arm/mach-orion5x/dns323-setup.c
+++ b/arch/arm/mach-orion5x/dns323-setup.c
@@ -79,7 +79,7 @@
  */
 
 static struct mv643xx_eth_platform_data dns323_eth_data = {
-	.phy_addr = 8,
+	.phy_addr = MV643XX_ETH_PHY_ADDR(8),
 };
 
 /****************************************************************************
diff --git a/arch/arm/mach-orion5x/edmini_v2-setup.c b/arch/arm/mach-orion5x/edmini_v2-setup.c
new file mode 100644
index 0000000..b24ee0c
--- /dev/null
+++ b/arch/arm/mach-orion5x/edmini_v2-setup.c
@@ -0,0 +1,262 @@
+/*
+ * arch/arm/mach-orion5x/edmini_v2-setup.c
+ *
+ * LaCie Ethernet Disk mini V2 Setup
+ *
+ * Copyright (C) 2008 Christopher Moore <moore@free.fr>
+ * Copyright (C) 2008 Albert Aribaud <albert.aribaud@free.fr>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+/*
+ * TODO: add Orion USB device port init when kernel.org support is added.
+ * TODO: add flash write support: see below.
+ * TODO: add power-off support.
+ * TODO: add I2C EEPROM support.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/pci.h>
+#include <linux/irq.h>
+#include <linux/mtd/physmap.h>
+#include <linux/mv643xx_eth.h>
+#include <linux/leds.h>
+#include <linux/gpio_keys.h>
+#include <linux/input.h>
+#include <linux/i2c.h>
+#include <linux/ata_platform.h>
+#include <linux/gpio.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/pci.h>
+#include <mach/orion5x.h>
+#include "common.h"
+#include "mpp.h"
+
+/*****************************************************************************
+ * EDMINI_V2 Info
+ ****************************************************************************/
+
+/*
+ * 512KB NOR flash Device bus boot chip select
+ */
+
+#define EDMINI_V2_NOR_BOOT_BASE		0xfff80000
+#define EDMINI_V2_NOR_BOOT_SIZE		SZ_512K
+
+/*****************************************************************************
+ * 512KB NOR Flash on BOOT Device
+ ****************************************************************************/
+
+/*
+ * Currently the MTD code does not recognize the MX29LV400CBCT as a bottom
+ * -type device. This could cause risks of accidentally erasing critical
+ * flash sectors. We thus define a single, write-protected partition covering
+ * the whole flash.
+ * TODO: once the flash part TOP/BOTTOM detection issue is sorted out in the MTD
+ * code, break this into at least three partitions: 'u-boot code', 'u-boot
+ * environment' and 'whatever is left'.
+ */
+
+static struct mtd_partition edmini_v2_partitions[] = {
+	{
+		.name		= "Full512kb",
+		.size		= 0x00080000,
+		.offset		= 0x00000000,
+		.mask_flags	= MTD_WRITEABLE,
+	},
+};
+
+static struct physmap_flash_data edmini_v2_nor_flash_data = {
+	.width		= 1,
+	.parts		= edmini_v2_partitions,
+	.nr_parts	= ARRAY_SIZE(edmini_v2_partitions),
+};
+
+static struct resource edmini_v2_nor_flash_resource = {
+	.flags			= IORESOURCE_MEM,
+	.start			= EDMINI_V2_NOR_BOOT_BASE,
+	.end			= EDMINI_V2_NOR_BOOT_BASE
+		+ EDMINI_V2_NOR_BOOT_SIZE - 1,
+};
+
+static struct platform_device edmini_v2_nor_flash = {
+	.name			= "physmap-flash",
+	.id			= 0,
+	.dev		= {
+		.platform_data	= &edmini_v2_nor_flash_data,
+	},
+	.num_resources		= 1,
+	.resource		= &edmini_v2_nor_flash_resource,
+};
+
+/*****************************************************************************
+ * Ethernet
+ ****************************************************************************/
+
+static struct mv643xx_eth_platform_data edmini_v2_eth_data = {
+	.phy_addr	= 8,
+};
+
+/*****************************************************************************
+ * RTC 5C372a on I2C bus
+ ****************************************************************************/
+
+#define EDMINIV2_RTC_GPIO	3
+
+static struct i2c_board_info __initdata edmini_v2_i2c_rtc = {
+	I2C_BOARD_INFO("rs5c372a", 0x32),
+	.irq = 0,
+};
+
+/*****************************************************************************
+ * Sata
+ ****************************************************************************/
+
+static struct mv_sata_platform_data edmini_v2_sata_data = {
+	.n_ports	= 2,
+};
+
+/*****************************************************************************
+ * GPIO LED (simple - doesn't use hardware blinking support)
+ ****************************************************************************/
+
+#define EDMINI_V2_GPIO_LED_POWER	16
+
+static struct gpio_led edmini_v2_leds[] = {
+	{
+		.name = "power:blue",
+		.gpio = EDMINI_V2_GPIO_LED_POWER,
+		.active_low = 1,
+	},
+};
+
+static struct gpio_led_platform_data edmini_v2_led_data = {
+	.num_leds = ARRAY_SIZE(edmini_v2_leds),
+	.leds = edmini_v2_leds,
+};
+
+static struct platform_device edmini_v2_gpio_leds = {
+	.name           = "leds-gpio",
+	.id             = -1,
+	.dev            = {
+		.platform_data  = &edmini_v2_led_data,
+	},
+};
+
+/****************************************************************************
+ * GPIO key
+ ****************************************************************************/
+
+#define EDMINI_V2_GPIO_KEY_POWER	18
+
+static struct gpio_keys_button edmini_v2_buttons[] = {
+	{
+		.code		= KEY_POWER,
+		.gpio		= EDMINI_V2_GPIO_KEY_POWER,
+		.desc		= "Power Button",
+		.active_low	= 0,
+	},
+};
+
+static struct gpio_keys_platform_data edmini_v2_button_data = {
+	.buttons	= edmini_v2_buttons,
+	.nbuttons	= ARRAY_SIZE(edmini_v2_buttons),
+};
+
+static struct platform_device edmini_v2_gpio_buttons = {
+	.name		= "gpio-keys",
+	.id		= -1,
+	.dev		= {
+		.platform_data	= &edmini_v2_button_data,
+	},
+};
+
+/*****************************************************************************
+ * General Setup
+ ****************************************************************************/
+static struct orion5x_mpp_mode edminiv2_mpp_modes[] __initdata = {
+	{  0, MPP_UNUSED },
+	{  1, MPP_UNUSED },
+	{  2, MPP_UNUSED },
+	{  3, MPP_GPIO },	/* RTC interrupt */
+	{  4, MPP_UNUSED },
+	{  5, MPP_UNUSED },
+	{  6, MPP_UNUSED },
+	{  7, MPP_UNUSED },
+	{  8, MPP_UNUSED },
+	{  9, MPP_UNUSED },
+	{ 10, MPP_UNUSED },
+	{ 11, MPP_UNUSED },
+	{ 12, MPP_SATA_LED },	/* SATA 0 presence */
+	{ 13, MPP_SATA_LED },	/* SATA 1 presence */
+	{ 14, MPP_SATA_LED },	/* SATA 0 active */
+	{ 15, MPP_SATA_LED },	/* SATA 1 active */
+	/* 16: Power LED control (0 = On, 1 = Off) */
+	{ 16, MPP_GPIO },
+	/* 17: Power LED control select (0 = CPLD, 1 = GPIO16) */
+	{ 17, MPP_GPIO },
+	/* 18: Power button status (0 = Released, 1 = Pressed) */
+	{ 18, MPP_GPIO },
+	{ 19, MPP_UNUSED },
+	{ -1 }
+};
+
+static void __init edmini_v2_init(void)
+{
+	/*
+	 * Setup basic Orion functions. Need to be called early.
+	 */
+	orion5x_init();
+
+	orion5x_mpp_conf(edminiv2_mpp_modes);
+
+	/*
+	 * Configure peripherals.
+	 */
+	orion5x_ehci0_init();
+	orion5x_eth_init(&edmini_v2_eth_data);
+	orion5x_i2c_init();
+	orion5x_sata_init(&edmini_v2_sata_data);
+	orion5x_uart0_init();
+
+	orion5x_setup_dev_boot_win(EDMINI_V2_NOR_BOOT_BASE,
+				EDMINI_V2_NOR_BOOT_SIZE);
+	platform_device_register(&edmini_v2_nor_flash);
+	platform_device_register(&edmini_v2_gpio_leds);
+	platform_device_register(&edmini_v2_gpio_buttons);
+
+	pr_notice("edmini_v2: USB device port, flash write and power-off "
+		  "are not yet supported.\n");
+
+	/* Get RTC IRQ and register the chip */
+	if (gpio_request(EDMINIV2_RTC_GPIO, "rtc") == 0) {
+		if (gpio_direction_input(EDMINIV2_RTC_GPIO) == 0)
+			edmini_v2_i2c_rtc.irq = gpio_to_irq(EDMINIV2_RTC_GPIO);
+		else
+			gpio_free(EDMINIV2_RTC_GPIO);
+	}
+
+	if (edmini_v2_i2c_rtc.irq == 0)
+		pr_warning("edmini_v2: failed to get RTC IRQ\n");
+
+	i2c_register_board_info(0, &edmini_v2_i2c_rtc, 1);
+}
+
+/* Warning: LaCie use a wrong mach-type (0x20e=526) in their bootloader. */
+MACHINE_START(EDMINI_V2, "LaCie Ethernet Disk mini V2")
+	/* Maintainer: Christopher Moore <moore@free.fr> */
+	.phys_io	= ORION5X_REGS_PHYS_BASE,
+	.io_pg_offst	= ((ORION5X_REGS_VIRT_BASE) >> 18) & 0xFFFC,
+	.boot_params	= 0x00000100,
+	.init_machine	= edmini_v2_init,
+	.map_io		= orion5x_map_io,
+	.init_irq	= orion5x_init_irq,
+	.timer		= &orion5x_timer,
+	.fixup		= tag_fixup_mem32,
+MACHINE_END
diff --git a/arch/arm/mach-orion5x/gpio.c b/arch/arm/mach-orion5x/gpio.c
index cd8a16f..fc41986 100644
--- a/arch/arm/mach-orion5x/gpio.c
+++ b/arch/arm/mach-orion5x/gpio.c
@@ -15,8 +15,8 @@
 #include <linux/module.h>
 #include <linux/spinlock.h>
 #include <linux/bitops.h>
+#include <linux/io.h>
 #include <asm/gpio.h>
-#include <asm/io.h>
 #include <mach/orion5x.h>
 #include "common.h"
 
diff --git a/arch/arm/mach-orion5x/include/mach/orion5x.h b/arch/arm/mach-orion5x/include/mach/orion5x.h
index 61eb74a..9f5ce1c 100644
--- a/arch/arm/mach-orion5x/include/mach/orion5x.h
+++ b/arch/arm/mach-orion5x/include/mach/orion5x.h
@@ -2,7 +2,7 @@
  * arch/arm/mach-orion5x/include/mach/orion5x.h
  *
  * Generic definitions of Orion SoC flavors:
- *  Orion-1, Orion-VoIP, Orion-NAS, and Orion-2.
+ *  Orion-1, Orion-VoIP, Orion-NAS, Orion-2, and Orion-1-90.
  *
  * Maintainer: Tzachi Perelstein <tzachi@marvell.com>
  *
@@ -76,6 +76,9 @@
 #define MV88F5281_REV_D0	4
 #define MV88F5281_REV_D1	5
 #define MV88F5281_REV_D2	6
+/* Orion-1-90 (88F6183) */
+#define MV88F6183_DEV_ID	0x6183
+#define MV88F6183_REV_B0	3
 
 /*******************************************************************************
  * Orion Registers Map
@@ -86,6 +89,7 @@
 #define ORION5X_DEV_BUS_PHYS_BASE	(ORION5X_REGS_PHYS_BASE | 0x10000)
 #define ORION5X_DEV_BUS_VIRT_BASE	(ORION5X_REGS_VIRT_BASE | 0x10000)
 #define ORION5X_DEV_BUS_REG(x)		(ORION5X_DEV_BUS_VIRT_BASE | (x))
+#define  SPI_PHYS_BASE			(ORION5X_DEV_BUS_PHYS_BASE | 0x0600)
 #define  I2C_PHYS_BASE			(ORION5X_DEV_BUS_PHYS_BASE | 0x1000)
 #define  UART0_PHYS_BASE		(ORION5X_DEV_BUS_PHYS_BASE | 0x2000)
 #define  UART0_VIRT_BASE		(ORION5X_DEV_BUS_VIRT_BASE | 0x2000)
@@ -153,9 +157,11 @@
 #define CPU_CONF		ORION5X_BRIDGE_REG(0x100)
 #define CPU_CTRL		ORION5X_BRIDGE_REG(0x104)
 #define CPU_RESET_MASK		ORION5X_BRIDGE_REG(0x108)
+#define  WDT_RESET		0x0002
 #define CPU_SOFT_RESET		ORION5X_BRIDGE_REG(0x10c)
 #define POWER_MNG_CTRL_REG	ORION5X_BRIDGE_REG(0x11C)
 #define BRIDGE_CAUSE		ORION5X_BRIDGE_REG(0x110)
+#define  WDT_INT_REQ		0x0008
 #define BRIDGE_MASK		ORION5X_BRIDGE_REG(0x114)
 #define  BRIDGE_INT_TIMER0	0x0002
 #define  BRIDGE_INT_TIMER1	0x0004
diff --git a/arch/arm/mach-orion5x/include/mach/timex.h b/arch/arm/mach-orion5x/include/mach/timex.h
index e82e44d..4c69820 100644
--- a/arch/arm/mach-orion5x/include/mach/timex.h
+++ b/arch/arm/mach-orion5x/include/mach/timex.h
@@ -9,5 +9,3 @@
  */
 
 #define CLOCK_TICK_RATE		(100 * HZ)
-
-#define ORION5X_TCLK		166666667
diff --git a/arch/arm/mach-orion5x/irq.c b/arch/arm/mach-orion5x/irq.c
index 2545ff9..632a36f 100644
--- a/arch/arm/mach-orion5x/irq.c
+++ b/arch/arm/mach-orion5x/irq.c
@@ -13,8 +13,8 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/irq.h>
+#include <linux/io.h>
 #include <asm/gpio.h>
-#include <asm/io.h>
 #include <mach/orion5x.h>
 #include <plat/irq.h>
 #include "common.h"
@@ -162,7 +162,7 @@
 				polarity ^= 1 << pin;
 				writel(polarity, GPIO_IN_POL);
 			}
-			desc_handle_irq(irq, desc);
+			generic_handle_irq(irq);
 		}
 	}
 }
diff --git a/arch/arm/mach-orion5x/kurobox_pro-setup.c b/arch/arm/mach-orion5x/kurobox_pro-setup.c
index e321ec3..dfbb68d 100644
--- a/arch/arm/mach-orion5x/kurobox_pro-setup.c
+++ b/arch/arm/mach-orion5x/kurobox_pro-setup.c
@@ -161,7 +161,7 @@
  ****************************************************************************/
 
 static struct mv643xx_eth_platform_data kurobox_pro_eth_data = {
-	.phy_addr	= 8,
+	.phy_addr	= MV643XX_ETH_PHY_ADDR(8),
 };
 
 /*****************************************************************************
@@ -293,7 +293,7 @@
 	const unsigned char shutdownwait[]	= {0x00, 0x0c};
 	const unsigned char poweroff[]		= {0x00, 0x06};
 	/* 38400 baud divisor */
-	const unsigned divisor = ((ORION5X_TCLK + (8 * 38400)) / (16 * 38400));
+	const unsigned divisor = ((orion5x_tclk + (8 * 38400)) / (16 * 38400));
 
 	pr_info("%s: triggering power-off...\n", __func__);
 
diff --git a/arch/arm/mach-orion5x/lsmini-setup.c b/arch/arm/mach-orion5x/lsmini-setup.c
new file mode 100644
index 0000000..e0c43b8
--- /dev/null
+++ b/arch/arm/mach-orion5x/lsmini-setup.c
@@ -0,0 +1,279 @@
+/*
+ * arch/arm/mach-orion5x/lsmini-setup.c
+ *
+ * Maintainer: Alexey Kopytko <alexey@kopytko.ru>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/pci.h>
+#include <linux/mtd/physmap.h>
+#include <linux/mv643xx_eth.h>
+#include <linux/leds.h>
+#include <linux/gpio_keys.h>
+#include <linux/input.h>
+#include <linux/i2c.h>
+#include <linux/ata_platform.h>
+#include <asm/mach-types.h>
+#include <linux/gpio.h>
+#include <asm/mach/arch.h>
+#include "common.h"
+#include "mpp.h"
+#include "include/mach/system.h"
+
+/*****************************************************************************
+ * Linkstation Mini Info
+ ****************************************************************************/
+
+/*
+ * 256K NOR flash Device bus boot chip select
+ */
+
+#define LSMINI_NOR_BOOT_BASE	0xf4000000
+#define LSMINI_NOR_BOOT_SIZE	SZ_256K
+
+/*****************************************************************************
+ * 256KB NOR Flash on BOOT Device
+ ****************************************************************************/
+
+static struct physmap_flash_data lsmini_nor_flash_data = {
+	.width		= 1,
+};
+
+static struct resource lsmini_nor_flash_resource = {
+	.flags	= IORESOURCE_MEM,
+	.start	= LSMINI_NOR_BOOT_BASE,
+	.end	= LSMINI_NOR_BOOT_BASE + LSMINI_NOR_BOOT_SIZE - 1,
+};
+
+static struct platform_device lsmini_nor_flash = {
+	.name			= "physmap-flash",
+	.id			= 0,
+	.dev		= {
+		.platform_data	= &lsmini_nor_flash_data,
+	},
+	.num_resources		= 1,
+	.resource		= &lsmini_nor_flash_resource,
+};
+
+/*****************************************************************************
+ * Ethernet
+ ****************************************************************************/
+
+static struct mv643xx_eth_platform_data lsmini_eth_data = {
+	.phy_addr	= 8,
+};
+
+/*****************************************************************************
+ * RTC 5C372a on I2C bus
+ ****************************************************************************/
+
+static struct i2c_board_info __initdata lsmini_i2c_rtc = {
+	I2C_BOARD_INFO("rs5c372a", 0x32),
+};
+
+/*****************************************************************************
+ * LEDs attached to GPIO
+ ****************************************************************************/
+
+#define LSMINI_GPIO_LED_ALARM	2
+#define LSMINI_GPIO_LED_INFO	3
+#define LSMINI_GPIO_LED_FUNC	9
+#define LSMINI_GPIO_LED_PWR	14
+
+static struct gpio_led lsmini_led_pins[] = {
+	{
+		.name	   = "alarm:red",
+		.gpio	   = LSMINI_GPIO_LED_ALARM,
+		.active_low     = 1,
+	}, {
+		.name	   = "info:amber",
+		.gpio	   = LSMINI_GPIO_LED_INFO,
+		.active_low     = 1,
+	}, {
+		.name	   = "func:blue:top",
+		.gpio	   = LSMINI_GPIO_LED_FUNC,
+		.active_low     = 1,
+	}, {
+		.name	   = "power:blue:bottom",
+		.gpio	   = LSMINI_GPIO_LED_PWR,
+	},
+};
+
+static struct gpio_led_platform_data lsmini_led_data = {
+	.leds	   = lsmini_led_pins,
+	.num_leds       = ARRAY_SIZE(lsmini_led_pins),
+};
+
+static struct platform_device lsmini_leds = {
+	.name   = "leds-gpio",
+	.id     = -1,
+	.dev    = {
+		.platform_data  = &lsmini_led_data,
+	},
+};
+
+/****************************************************************************
+ * GPIO Attached Keys
+ ****************************************************************************/
+
+#define LSMINI_GPIO_KEY_FUNC       15
+#define LSMINI_GPIO_KEY_POWER	   18
+#define LSMINI_GPIO_KEY_AUTOPOWER 17
+
+#define LSMINI_SW_POWER		0x00
+#define LSMINI_SW_AUTOPOWER	0x01
+
+static struct gpio_keys_button lsmini_buttons[] = {
+	{
+		.code	   = KEY_OPTION,
+		.gpio	   = LSMINI_GPIO_KEY_FUNC,
+		.desc	   = "Function Button",
+		.active_low     = 1,
+	}, {
+		.type		= EV_SW,
+		.code	   = LSMINI_SW_POWER,
+		.gpio	   = LSMINI_GPIO_KEY_POWER,
+		.desc	   = "Power-on Switch",
+		.active_low     = 1,
+	}, {
+		.type		= EV_SW,
+		.code	   = LSMINI_SW_AUTOPOWER,
+		.gpio	   = LSMINI_GPIO_KEY_AUTOPOWER,
+		.desc	   = "Power-auto Switch",
+		.active_low     = 1,
+	},
+};
+
+static struct gpio_keys_platform_data lsmini_button_data = {
+	.buttons	= lsmini_buttons,
+	.nbuttons       = ARRAY_SIZE(lsmini_buttons),
+};
+
+static struct platform_device lsmini_button_device = {
+	.name	   = "gpio-keys",
+	.id	     = -1,
+	.num_resources  = 0,
+	.dev	    = {
+		.platform_data  = &lsmini_button_data,
+	},
+};
+
+
+/*****************************************************************************
+ * SATA
+ ****************************************************************************/
+static struct mv_sata_platform_data lsmini_sata_data = {
+	.n_ports	= 2,
+};
+
+
+/*****************************************************************************
+ * Linkstation Mini specific power off method: reboot
+ ****************************************************************************/
+/*
+ * On the Linkstation Mini, the shutdown process is following:
+ * - Userland monitors key events until the power switch goes to off position
+ * - The board reboots
+ * - U-boot starts and goes into an idle mode waiting for the user
+ *   to move the switch to ON position
+ */
+
+static void lsmini_power_off(void)
+{
+	arch_reset(0);
+}
+
+
+/*****************************************************************************
+ * General Setup
+ ****************************************************************************/
+
+#define LSMINI_GPIO_USB_POWER	16
+#define LSMINI_GPIO_AUTO_POWER	17
+#define LSMINI_GPIO_POWER	18
+
+#define LSMINI_GPIO_HDD_POWER0	1
+#define LSMINI_GPIO_HDD_POWER1	19
+
+static struct orion5x_mpp_mode lsmini_mpp_modes[] __initdata = {
+	{  0, MPP_UNUSED }, /* LED_RESERVE1 (unused) */
+	{  1, MPP_GPIO }, /* HDD_PWR */
+	{  2, MPP_GPIO }, /* LED_ALARM */
+	{  3, MPP_GPIO }, /* LED_INFO */
+	{  4, MPP_UNUSED },
+	{  5, MPP_UNUSED },
+	{  6, MPP_UNUSED },
+	{  7, MPP_UNUSED },
+	{  8, MPP_UNUSED },
+	{  9, MPP_GPIO }, /* LED_FUNC */
+	{ 10, MPP_UNUSED },
+	{ 11, MPP_UNUSED }, /* LED_ETH (dummy) */
+	{ 12, MPP_UNUSED },
+	{ 13, MPP_UNUSED },
+	{ 14, MPP_GPIO }, /* LED_PWR */
+	{ 15, MPP_GPIO }, /* FUNC */
+	{ 16, MPP_GPIO }, /* USB_PWR */
+	{ 17, MPP_GPIO }, /* AUTO_POWER */
+	{ 18, MPP_GPIO }, /* POWER */
+	{ 19, MPP_GPIO }, /* HDD_PWR1 */
+	{ -1 },
+};
+
+static void __init lsmini_init(void)
+{
+	/*
+	 * Setup basic Orion functions. Need to be called early.
+	 */
+	orion5x_init();
+
+	orion5x_mpp_conf(lsmini_mpp_modes);
+
+	/*
+	 * Configure peripherals.
+	 */
+	orion5x_ehci0_init();
+	orion5x_ehci1_init();
+	orion5x_eth_init(&lsmini_eth_data);
+	orion5x_i2c_init();
+	orion5x_sata_init(&lsmini_sata_data);
+	orion5x_uart0_init();
+	orion5x_xor_init();
+
+	orion5x_setup_dev_boot_win(LSMINI_NOR_BOOT_BASE,
+				   LSMINI_NOR_BOOT_SIZE);
+	platform_device_register(&lsmini_nor_flash);
+
+	platform_device_register(&lsmini_button_device);
+
+	platform_device_register(&lsmini_leds);
+
+	i2c_register_board_info(0, &lsmini_i2c_rtc, 1);
+
+	/* enable USB power */
+	gpio_set_value(LSMINI_GPIO_USB_POWER, 1);
+
+	/* register power-off method */
+	pm_power_off = lsmini_power_off;
+
+	pr_info("%s: finished\n", __func__);
+}
+
+#ifdef CONFIG_MACH_LINKSTATION_MINI
+MACHINE_START(LINKSTATION_MINI, "Buffalo Linkstation Mini")
+	/* Maintainer: Alexey Kopytko <alexey@kopytko.ru> */
+	.phys_io	= ORION5X_REGS_PHYS_BASE,
+	.io_pg_offst	= ((ORION5X_REGS_VIRT_BASE) >> 18) & 0xFFFC,
+	.boot_params	= 0x00000100,
+	.init_machine	= lsmini_init,
+	.map_io		= orion5x_map_io,
+	.init_irq	= orion5x_init_irq,
+	.timer		= &orion5x_timer,
+	.fixup		= tag_fixup_mem32,
+MACHINE_END
+#endif
diff --git a/arch/arm/mach-orion5x/mpp.c b/arch/arm/mach-orion5x/mpp.c
index c04ab0e..640ea2a 100644
--- a/arch/arm/mach-orion5x/mpp.c
+++ b/arch/arm/mach-orion5x/mpp.c
@@ -11,8 +11,8 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/mbus.h>
+#include <linux/io.h>
 #include <mach/hardware.h>
-#include <asm/io.h>
 #include "common.h"
 #include "mpp.h"
 
diff --git a/arch/arm/mach-orion5x/mss2-setup.c b/arch/arm/mach-orion5x/mss2-setup.c
index 53ff189..68acca9 100644
--- a/arch/arm/mach-orion5x/mss2-setup.c
+++ b/arch/arm/mach-orion5x/mss2-setup.c
@@ -109,7 +109,7 @@
  ****************************************************************************/
 
 static struct mv643xx_eth_platform_data mss2_eth_data = {
-	.phy_addr	= 8,
+	.phy_addr	= MV643XX_ETH_PHY_ADDR(8),
 };
 
 /*****************************************************************************
diff --git a/arch/arm/mach-orion5x/mv2120-setup.c b/arch/arm/mach-orion5x/mv2120-setup.c
index 978d4d5..97c9ccb 100644
--- a/arch/arm/mach-orion5x/mv2120-setup.c
+++ b/arch/arm/mach-orion5x/mv2120-setup.c
@@ -39,7 +39,7 @@
  * Ethernet
  ****************************************************************************/
 static struct mv643xx_eth_platform_data mv2120_eth_data = {
-	.phy_addr	= 8,
+	.phy_addr	= MV643XX_ETH_PHY_ADDR(8),
 };
 
 static struct mv_sata_platform_data mv2120_sata_data = {
diff --git a/arch/arm/mach-orion5x/rd88f5181l-fxo-setup.c b/arch/arm/mach-orion5x/rd88f5181l-fxo-setup.c
index e72fe1e..500cdada 100644
--- a/arch/arm/mach-orion5x/rd88f5181l-fxo-setup.c
+++ b/arch/arm/mach-orion5x/rd88f5181l-fxo-setup.c
@@ -88,7 +88,7 @@
 };
 
 static struct mv643xx_eth_platform_data rd88f5181l_fxo_eth_data = {
-	.phy_addr	= -1,
+	.phy_addr	= MV643XX_ETH_PHY_NONE,
 	.speed		= SPEED_1000,
 	.duplex		= DUPLEX_FULL,
 };
diff --git a/arch/arm/mach-orion5x/rd88f5181l-ge-setup.c b/arch/arm/mach-orion5x/rd88f5181l-ge-setup.c
index a1fe325..ebde814 100644
--- a/arch/arm/mach-orion5x/rd88f5181l-ge-setup.c
+++ b/arch/arm/mach-orion5x/rd88f5181l-ge-setup.c
@@ -89,7 +89,7 @@
 };
 
 static struct mv643xx_eth_platform_data rd88f5181l_ge_eth_data = {
-	.phy_addr	= -1,
+	.phy_addr	= MV643XX_ETH_PHY_NONE,
 	.speed		= SPEED_1000,
 	.duplex		= DUPLEX_FULL,
 };
diff --git a/arch/arm/mach-orion5x/rd88f5182-setup.c b/arch/arm/mach-orion5x/rd88f5182-setup.c
index 4c3bcd7..a04f9e4 100644
--- a/arch/arm/mach-orion5x/rd88f5182-setup.c
+++ b/arch/arm/mach-orion5x/rd88f5182-setup.c
@@ -221,7 +221,7 @@
  ****************************************************************************/
 
 static struct mv643xx_eth_platform_data rd88f5182_eth_data = {
-	.phy_addr	= 8,
+	.phy_addr	= MV643XX_ETH_PHY_ADDR(8),
 };
 
 /*****************************************************************************
diff --git a/arch/arm/mach-orion5x/rd88f6183ap-ge-setup.c b/arch/arm/mach-orion5x/rd88f6183ap-ge-setup.c
new file mode 100644
index 0000000..40e0495
--- /dev/null
+++ b/arch/arm/mach-orion5x/rd88f6183ap-ge-setup.c
@@ -0,0 +1,117 @@
+/*
+ * arch/arm/mach-orion5x/rd88f6183-ap-ge-setup.c
+ *
+ * Marvell Orion-1-90 AP GE Reference Design Setup
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/pci.h>
+#include <linux/irq.h>
+#include <linux/mtd/physmap.h>
+#include <linux/mv643xx_eth.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/orion_spi.h>
+#include <linux/spi/flash.h>
+#include <linux/ethtool.h>
+#include <asm/mach-types.h>
+#include <asm/gpio.h>
+#include <asm/leds.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/pci.h>
+#include <mach/orion5x.h>
+#include "common.h"
+#include "mpp.h"
+
+static struct mv643xx_eth_platform_data rd88f6183ap_ge_eth_data = {
+	.phy_addr	= -1,
+	.speed		= SPEED_1000,
+	.duplex		= DUPLEX_FULL,
+};
+
+static struct mtd_partition rd88f6183ap_ge_partitions[] = {
+	{
+		.name	= "kernel",
+		.offset	= 0x00000000,
+		.size	= 0x00200000,
+	}, {
+		.name	= "rootfs",
+		.offset	= 0x00200000,
+		.size	= 0x00500000,
+	}, {
+		.name	= "nvram",
+		.offset	= 0x00700000,
+		.size	= 0x00080000,
+	},
+};
+
+static struct flash_platform_data rd88f6183ap_ge_spi_slave_data = {
+	.type		= "m25p64",
+	.nr_parts	= ARRAY_SIZE(rd88f6183ap_ge_partitions),
+	.parts		= rd88f6183ap_ge_partitions,
+};
+
+static struct spi_board_info __initdata rd88f6183ap_ge_spi_slave_info[] = {
+	{
+		.modalias	= "m25p80",
+		.platform_data	= &rd88f6183ap_ge_spi_slave_data,
+		.irq		= NO_IRQ,
+		.max_speed_hz	= 20000000,
+		.bus_num	= 0,
+		.chip_select	= 0,
+	},
+};
+
+static void __init rd88f6183ap_ge_init(void)
+{
+	/*
+	 * Setup basic Orion functions. Need to be called early.
+	 */
+	orion5x_init();
+
+	/*
+	 * Configure peripherals.
+	 */
+	orion5x_ehci0_init();
+	orion5x_eth_init(&rd88f6183ap_ge_eth_data);
+	spi_register_board_info(rd88f6183ap_ge_spi_slave_info,
+				ARRAY_SIZE(rd88f6183ap_ge_spi_slave_info));
+	orion5x_spi_init();
+	orion5x_uart0_init();
+}
+
+static struct hw_pci rd88f6183ap_ge_pci __initdata = {
+	.nr_controllers	= 2,
+	.swizzle	= pci_std_swizzle,
+	.setup		= orion5x_pci_sys_setup,
+	.scan		= orion5x_pci_sys_scan_bus,
+	.map_irq	= orion5x_pci_map_irq,
+};
+
+static int __init rd88f6183ap_ge_pci_init(void)
+{
+	if (machine_is_rd88f6183ap_ge()) {
+		orion5x_pci_disable();
+		pci_common_init(&rd88f6183ap_ge_pci);
+	}
+
+	return 0;
+}
+subsys_initcall(rd88f6183ap_ge_pci_init);
+
+MACHINE_START(RD88F6183AP_GE, "Marvell Orion-1-90 AP GE Reference Design")
+	/* Maintainer: Lennert Buytenhek <buytenh@marvell.com> */
+	.phys_io	= ORION5X_REGS_PHYS_BASE,
+	.io_pg_offst	= ((ORION5X_REGS_VIRT_BASE) >> 18) & 0xFFFC,
+	.boot_params	= 0x00000100,
+	.init_machine	= rd88f6183ap_ge_init,
+	.map_io		= orion5x_map_io,
+	.init_irq	= orion5x_init_irq,
+	.timer		= &orion5x_timer,
+	.fixup		= tag_fixup_mem32,
+MACHINE_END
diff --git a/arch/arm/mach-orion5x/terastation_pro2-setup.c b/arch/arm/mach-orion5x/terastation_pro2-setup.c
new file mode 100644
index 0000000..0b101d7d
--- /dev/null
+++ b/arch/arm/mach-orion5x/terastation_pro2-setup.c
@@ -0,0 +1,369 @@
+/*
+ * Buffalo Terastation Pro II/Live Board Setup
+ *
+ * Maintainer: Sylver Bruneau <sylver.bruneau@googlemail.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/platform_device.h>
+#include <linux/pci.h>
+#include <linux/irq.h>
+#include <linux/delay.h>
+#include <linux/mtd/physmap.h>
+#include <linux/mv643xx_eth.h>
+#include <linux/i2c.h>
+#include <linux/serial_reg.h>
+#include <asm/mach-types.h>
+#include <asm/gpio.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/pci.h>
+#include <mach/orion5x.h>
+#include "common.h"
+#include "mpp.h"
+
+/*****************************************************************************
+ * Terastation Pro 2/Live Info
+ ****************************************************************************/
+
+/*
+ * Terastation Pro 2 hardware :
+ * - Marvell 88F5281-D0
+ * - Marvell 88SX6042 SATA controller (PCI)
+ * - Marvell 88E1118 Gigabit Ethernet PHY
+ * - 256KB NOR flash
+ * - 128MB of DDR RAM
+ * - PCIe port (not equipped)
+ */
+
+/*
+ * 256K NOR flash Device bus boot chip select
+ */
+
+#define TSP2_NOR_BOOT_BASE	0xf4000000
+#define TSP2_NOR_BOOT_SIZE	SZ_256K
+
+/*****************************************************************************
+ * 256KB NOR Flash on BOOT Device
+ ****************************************************************************/
+
+static struct physmap_flash_data tsp2_nor_flash_data = {
+	.width    = 1,
+};
+
+static struct resource tsp2_nor_flash_resource = {
+	.flags = IORESOURCE_MEM,
+	.start = TSP2_NOR_BOOT_BASE,
+	.end   = TSP2_NOR_BOOT_BASE + TSP2_NOR_BOOT_SIZE - 1,
+};
+
+static struct platform_device tsp2_nor_flash = {
+	.name          = "physmap-flash",
+	.id            = 0,
+	.dev           = {
+		.platform_data	= &tsp2_nor_flash_data,
+	},
+	.num_resources = 1,
+	.resource      = &tsp2_nor_flash_resource,
+};
+
+/*****************************************************************************
+ * PCI
+ ****************************************************************************/
+#define TSP2_PCI_SLOT0_OFFS		7
+#define TSP2_PCI_SLOT0_IRQ_PIN		11
+
+void __init tsp2_pci_preinit(void)
+{
+	int pin;
+
+	/*
+	 * Configure PCI GPIO IRQ pins
+	 */
+	pin = TSP2_PCI_SLOT0_IRQ_PIN;
+	if (gpio_request(pin, "PCI Int1") == 0) {
+		if (gpio_direction_input(pin) == 0) {
+			set_irq_type(gpio_to_irq(pin), IRQ_TYPE_LEVEL_LOW);
+		} else {
+			printk(KERN_ERR "tsp2_pci_preinit failed "
+					"to set_irq_type pin %d\n", pin);
+			gpio_free(pin);
+		}
+	} else {
+		printk(KERN_ERR "tsp2_pci_preinit failed to "
+				"gpio_request %d\n", pin);
+	}
+}
+
+static int __init tsp2_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+{
+	int irq;
+
+	/*
+	 * Check for devices with hard-wired IRQs.
+	 */
+	irq = orion5x_pci_map_irq(dev, slot, pin);
+	if (irq != -1)
+		return irq;
+
+	/*
+	 * PCI IRQs are connected via GPIOs.
+	 */
+	if (slot == TSP2_PCI_SLOT0_OFFS)
+		return gpio_to_irq(TSP2_PCI_SLOT0_IRQ_PIN);
+
+	return -1;
+}
+
+static struct hw_pci tsp2_pci __initdata = {
+	.nr_controllers = 2,
+	.preinit        = tsp2_pci_preinit,
+	.swizzle        = pci_std_swizzle,
+	.setup          = orion5x_pci_sys_setup,
+	.scan           = orion5x_pci_sys_scan_bus,
+	.map_irq        = tsp2_pci_map_irq,
+};
+
+static int __init tsp2_pci_init(void)
+{
+	if (machine_is_terastation_pro2())
+		pci_common_init(&tsp2_pci);
+
+	return 0;
+}
+
+subsys_initcall(tsp2_pci_init);
+
+/*****************************************************************************
+ * Ethernet
+ ****************************************************************************/
+
+static struct mv643xx_eth_platform_data tsp2_eth_data = {
+	.phy_addr	= 0,
+};
+
+/*****************************************************************************
+ * RTC 5C372a on I2C bus
+ ****************************************************************************/
+
+#define TSP2_RTC_GPIO	9
+
+static struct i2c_board_info __initdata tsp2_i2c_rtc = {
+	I2C_BOARD_INFO("rs5c372a", 0x32),
+};
+
+/*****************************************************************************
+ * Terastation Pro II specific power off method via UART1-attached
+ * microcontroller
+ ****************************************************************************/
+
+#define UART1_REG(x)	(UART1_VIRT_BASE + ((UART_##x) << 2))
+
+static int tsp2_miconread(unsigned char *buf, int count)
+{
+	int i;
+	int timeout;
+
+	for (i = 0; i < count; i++) {
+		timeout = 10;
+
+		while (!(readl(UART1_REG(LSR)) & UART_LSR_DR)) {
+			if (--timeout == 0)
+				break;
+			udelay(1000);
+		}
+
+		if (timeout == 0)
+			break;
+		buf[i] = readl(UART1_REG(RX));
+	}
+
+	/* return read bytes */
+	return i;
+}
+
+static int tsp2_miconwrite(const unsigned char *buf, int count)
+{
+	int i = 0;
+
+	while (count--) {
+		while (!(readl(UART1_REG(LSR)) & UART_LSR_THRE))
+			barrier();
+		writel(buf[i++], UART1_REG(TX));
+	}
+
+	return 0;
+}
+
+static int tsp2_miconsend(const unsigned char *data, int count)
+{
+	int i;
+	unsigned char checksum = 0;
+	unsigned char recv_buf[40];
+	unsigned char send_buf[40];
+	unsigned char correct_ack[3];
+	int retry = 2;
+
+	/* Generate checksum */
+	for (i = 0; i < count; i++)
+		checksum -=  data[i];
+
+	do {
+		/* Send data */
+		tsp2_miconwrite(data, count);
+
+		/* send checksum */
+		tsp2_miconwrite(&checksum, 1);
+
+		if (tsp2_miconread(recv_buf, sizeof(recv_buf)) <= 3) {
+			printk(KERN_ERR ">%s: receive failed.\n", __func__);
+
+			/* send preamble to clear the receive buffer */
+			memset(&send_buf, 0xff, sizeof(send_buf));
+			tsp2_miconwrite(send_buf, sizeof(send_buf));
+
+			/* make dummy reads */
+			mdelay(100);
+			tsp2_miconread(recv_buf, sizeof(recv_buf));
+		} else {
+			/* Generate expected ack */
+			correct_ack[0] = 0x01;
+			correct_ack[1] = data[1];
+			correct_ack[2] = 0x00;
+
+			/* checksum Check */
+			if ((recv_buf[0] + recv_buf[1] + recv_buf[2] +
+			     recv_buf[3]) & 0xFF) {
+				printk(KERN_ERR ">%s: Checksum Error : "
+					"Received data[%02x, %02x, %02x, %02x]"
+					"\n", __func__, recv_buf[0],
+					recv_buf[1], recv_buf[2], recv_buf[3]);
+			} else {
+				/* Check Received Data */
+				if (correct_ack[0] == recv_buf[0] &&
+				    correct_ack[1] == recv_buf[1] &&
+				    correct_ack[2] == recv_buf[2]) {
+					/* Interval for next command */
+					mdelay(10);
+
+					/* Receive ACK */
+					return 0;
+				}
+			}
+			/* Received NAK or illegal Data */
+			printk(KERN_ERR ">%s: Error : NAK or Illegal Data "
+					"Received\n", __func__);
+		}
+	} while (retry--);
+
+	/* Interval for next command */
+	mdelay(10);
+
+	return -1;
+}
+
+static void tsp2_power_off(void)
+{
+	const unsigned char watchdogkill[]	= {0x01, 0x35, 0x00};
+	const unsigned char shutdownwait[]	= {0x00, 0x0c};
+	const unsigned char poweroff[]		= {0x00, 0x06};
+	/* 38400 baud divisor */
+	const unsigned divisor = ((orion5x_tclk + (8 * 38400)) / (16 * 38400));
+
+	pr_info("%s: triggering power-off...\n", __func__);
+
+	/* hijack uart1 and reset into sane state (38400,8n1,even parity) */
+	writel(0x83, UART1_REG(LCR));
+	writel(divisor & 0xff, UART1_REG(DLL));
+	writel((divisor >> 8) & 0xff, UART1_REG(DLM));
+	writel(0x1b, UART1_REG(LCR));
+	writel(0x00, UART1_REG(IER));
+	writel(0x07, UART1_REG(FCR));
+	writel(0x00, UART1_REG(MCR));
+
+	/* Send the commands to shutdown the Terastation Pro II */
+	tsp2_miconsend(watchdogkill, sizeof(watchdogkill)) ;
+	tsp2_miconsend(shutdownwait, sizeof(shutdownwait)) ;
+	tsp2_miconsend(poweroff, sizeof(poweroff));
+}
+
+/*****************************************************************************
+ * General Setup
+ ****************************************************************************/
+static struct orion5x_mpp_mode tsp2_mpp_modes[] __initdata = {
+	{  0, MPP_PCIE_RST_OUTn },
+	{  1, MPP_UNUSED },
+	{  2, MPP_UNUSED },
+	{  3, MPP_UNUSED },
+	{  4, MPP_NAND },		/* BOOT NAND Flash REn */
+	{  5, MPP_NAND },		/* BOOT NAND Flash WEn */
+	{  6, MPP_NAND },		/* BOOT NAND Flash HREn[0] */
+	{  7, MPP_NAND },		/* BOOT NAND Flash WEn[0] */
+	{  8, MPP_GPIO },		/* MICON int */
+	{  9, MPP_GPIO },		/* RTC int */
+	{ 10, MPP_UNUSED },
+	{ 11, MPP_GPIO },		/* PCI Int A */
+	{ 12, MPP_UNUSED },
+	{ 13, MPP_GPIO },		/* UPS on UART0 enable */
+	{ 14, MPP_GPIO },		/* UPS low battery detection */
+	{ 15, MPP_UNUSED },
+	{ 16, MPP_UART },		/* UART1 RXD */
+	{ 17, MPP_UART },		/* UART1 TXD */
+	{ 18, MPP_UART },		/* UART1 CTSn */
+	{ 19, MPP_UART },		/* UART1 RTSn */
+	{ -1 },
+};
+
+static void __init tsp2_init(void)
+{
+	/*
+	 * Setup basic Orion functions. Need to be called early.
+	 */
+	orion5x_init();
+
+	orion5x_mpp_conf(tsp2_mpp_modes);
+
+	/*
+	 * Configure peripherals.
+	 */
+	orion5x_setup_dev_boot_win(TSP2_NOR_BOOT_BASE,
+				   TSP2_NOR_BOOT_SIZE);
+	platform_device_register(&tsp2_nor_flash);
+
+	orion5x_ehci0_init();
+	orion5x_eth_init(&tsp2_eth_data);
+	orion5x_i2c_init();
+	orion5x_uart0_init();
+	orion5x_uart1_init();
+
+	/* Get RTC IRQ and register the chip */
+	if (gpio_request(TSP2_RTC_GPIO, "rtc") == 0) {
+		if (gpio_direction_input(TSP2_RTC_GPIO) == 0)
+			tsp2_i2c_rtc.irq = gpio_to_irq(TSP2_RTC_GPIO);
+		else
+			gpio_free(TSP2_RTC_GPIO);
+	}
+	if (tsp2_i2c_rtc.irq == 0)
+		pr_warning("tsp2_init: failed to get RTC IRQ\n");
+	i2c_register_board_info(0, &tsp2_i2c_rtc, 1);
+
+	/* register Terastation Pro II specific power-off method */
+	pm_power_off = tsp2_power_off;
+}
+
+MACHINE_START(TERASTATION_PRO2, "Buffalo Terastation Pro II/Live")
+	/* Maintainer:  Sylver Bruneau <sylver.bruneau@googlemail.com> */
+	.phys_io	= ORION5X_REGS_PHYS_BASE,
+	.io_pg_offst	= ((ORION5X_REGS_VIRT_BASE) >> 18) & 0xFFFC,
+	.boot_params	= 0x00000100,
+	.init_machine	= tsp2_init,
+	.map_io		= orion5x_map_io,
+	.init_irq	= orion5x_init_irq,
+	.timer		= &orion5x_timer,
+	.fixup		= tag_fixup_mem32,
+MACHINE_END
diff --git a/arch/arm/mach-orion5x/ts78xx-setup.c b/arch/arm/mach-orion5x/ts78xx-setup.c
index ae0a5dc..1368e9f 100644
--- a/arch/arm/mach-orion5x/ts78xx-setup.c
+++ b/arch/arm/mach-orion5x/ts78xx-setup.c
@@ -103,8 +103,7 @@
  * Ethernet
  ****************************************************************************/
 static struct mv643xx_eth_platform_data ts78xx_eth_data = {
-	.phy_addr	= 0,
-	.force_phy_addr = 1,
+	.phy_addr	= MV643XX_ETH_PHY_ADDR(0),
 };
 
 /*****************************************************************************
diff --git a/arch/arm/mach-orion5x/tsx09-common.c b/arch/arm/mach-orion5x/tsx09-common.c
index 83feac3..c9abb8f 100644
--- a/arch/arm/mach-orion5x/tsx09-common.c
+++ b/arch/arm/mach-orion5x/tsx09-common.c
@@ -16,6 +16,7 @@
 #include <linux/timex.h>
 #include <linux/serial_reg.h>
 #include "tsx09-common.h"
+#include "common.h"
 
 /*****************************************************************************
  * QNAP TS-x09 specific power off method via UART1-attached PIC
@@ -26,7 +27,7 @@
 void qnap_tsx09_power_off(void)
 {
 	/* 19200 baud divisor */
-	const unsigned divisor = ((ORION5X_TCLK + (8 * 19200)) / (16 * 19200));
+	const unsigned divisor = ((orion5x_tclk + (8 * 19200)) / (16 * 19200));
 
 	pr_info("%s: triggering power-off...\n", __func__);
 
@@ -48,7 +49,7 @@
  ****************************************************************************/
 
 struct mv643xx_eth_platform_data qnap_tsx09_eth_data = {
-	.phy_addr	= 8,
+	.phy_addr	= MV643XX_ETH_PHY_ADDR(8),
 };
 
 static int __init qnap_tsx09_parse_hex_nibble(char n)
diff --git a/arch/arm/mach-orion5x/wnr854t-setup.c b/arch/arm/mach-orion5x/wnr854t-setup.c
index b6bc43e..7ddc22c 100644
--- a/arch/arm/mach-orion5x/wnr854t-setup.c
+++ b/arch/arm/mach-orion5x/wnr854t-setup.c
@@ -92,7 +92,7 @@
 };
 
 static struct mv643xx_eth_platform_data wnr854t_eth_data = {
-	.phy_addr	= -1,
+	.phy_addr	= MV643XX_ETH_PHY_NONE,
 	.speed		= SPEED_1000,
 	.duplex		= DUPLEX_FULL,
 };
diff --git a/arch/arm/mach-orion5x/wrt350n-v2-setup.c b/arch/arm/mach-orion5x/wrt350n-v2-setup.c
index b10da17..9a4fd52 100644
--- a/arch/arm/mach-orion5x/wrt350n-v2-setup.c
+++ b/arch/arm/mach-orion5x/wrt350n-v2-setup.c
@@ -100,7 +100,7 @@
 };
 
 static struct mv643xx_eth_platform_data wrt350n_v2_eth_data = {
-	.phy_addr	= -1,
+	.phy_addr	= MV643XX_ETH_PHY_NONE,
 	.speed		= SPEED_1000,
 	.duplex		= DUPLEX_FULL,
 };
diff --git a/arch/arm/mach-pnx4008/clock.c b/arch/arm/mach-pnx4008/clock.c
index 24d036a..898c0e8 100644
--- a/arch/arm/mach-pnx4008/clock.c
+++ b/arch/arm/mach-pnx4008/clock.c
@@ -20,9 +20,9 @@
 #include <linux/device.h>
 #include <linux/err.h>
 #include <linux/delay.h>
+#include <linux/io.h>
 
 #include <mach/hardware.h>
-#include <asm/io.h>
 
 #include <mach/clock.h>
 #include "clock.h"
diff --git a/arch/arm/mach-pnx4008/core.c b/arch/arm/mach-pnx4008/core.c
index 3ba46ed..45734bb 100644
--- a/arch/arm/mach-pnx4008/core.c
+++ b/arch/arm/mach-pnx4008/core.c
@@ -25,9 +25,9 @@
 #include <linux/serial_8250.h>
 #include <linux/device.h>
 #include <linux/spi/spi.h>
+#include <linux/io.h>
 
 #include <mach/hardware.h>
-#include <asm/io.h>
 #include <asm/setup.h>
 #include <asm/mach-types.h>
 #include <asm/pgtable.h>
diff --git a/arch/arm/mach-pnx4008/dma.c b/arch/arm/mach-pnx4008/dma.c
index 833c56be..ac2f70e 100644
--- a/arch/arm/mach-pnx4008/dma.c
+++ b/arch/arm/mach-pnx4008/dma.c
@@ -21,12 +21,12 @@
 #include <linux/err.h>
 #include <linux/dma-mapping.h>
 #include <linux/clk.h>
+#include <linux/io.h>
 
 #include <asm/system.h>
 #include <mach/hardware.h>
 #include <asm/dma.h>
 #include <asm/dma-mapping.h>
-#include <asm/io.h>
 #include <asm/mach/dma.h>
 #include <mach/clock.h>
 
diff --git a/arch/arm/mach-pnx4008/gpio.c b/arch/arm/mach-pnx4008/gpio.c
index fb51f72..015cc21 100644
--- a/arch/arm/mach-pnx4008/gpio.c
+++ b/arch/arm/mach-pnx4008/gpio.c
@@ -17,7 +17,7 @@
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
-#include <asm/io.h>
+#include <linux/io.h>
 #include <mach/platform.h>
 #include <mach/gpio.h>
 
diff --git a/arch/arm/mach-pnx4008/include/mach/system.h b/arch/arm/mach-pnx4008/include/mach/system.h
index 8985a4622..e12e7ab 100644
--- a/arch/arm/mach-pnx4008/include/mach/system.h
+++ b/arch/arm/mach-pnx4008/include/mach/system.h
@@ -21,8 +21,8 @@
 #ifndef __ASM_ARCH_SYSTEM_H
 #define __ASM_ARCH_SYSTEM_H
 
+#include <linux/io.h>
 #include <mach/hardware.h>
-#include <asm/io.h>
 #include <mach/platform.h>
 
 static void arch_idle(void)
diff --git a/arch/arm/mach-pnx4008/include/mach/timex.h b/arch/arm/mach-pnx4008/include/mach/timex.h
index 956fbd8e..5ff0196 100644
--- a/arch/arm/mach-pnx4008/include/mach/timex.h
+++ b/arch/arm/mach-pnx4008/include/mach/timex.h
@@ -14,8 +14,8 @@
 #ifndef __PNX4008_TIMEX_H
 #define __PNX4008_TIMEX_H
 
+#include <linux/io.h>
 #include <mach/hardware.h>
-#include <asm/io.h>
 
 #define CLOCK_TICK_RATE		1000000
 
diff --git a/arch/arm/mach-pnx4008/irq.c b/arch/arm/mach-pnx4008/irq.c
index 5c4f55a..a9ce02b 100644
--- a/arch/arm/mach-pnx4008/irq.c
+++ b/arch/arm/mach-pnx4008/irq.c
@@ -23,8 +23,8 @@
 #include <linux/ioport.h>
 #include <linux/device.h>
 #include <linux/irq.h>
+#include <linux/io.h>
 #include <mach/hardware.h>
-#include <asm/io.h>
 #include <asm/setup.h>
 #include <asm/pgtable.h>
 #include <asm/page.h>
diff --git a/arch/arm/mach-pnx4008/pm.c b/arch/arm/mach-pnx4008/pm.c
index f970906d..b3d8d53 100644
--- a/arch/arm/mach-pnx4008/pm.c
+++ b/arch/arm/mach-pnx4008/pm.c
@@ -18,8 +18,8 @@
 #include <linux/suspend.h>
 #include <linux/delay.h>
 #include <linux/clk.h>
+#include <linux/io.h>
 
-#include <asm/io.h>
 #include <asm/cacheflush.h>
 #include <mach/pm.h>
 #include <mach/clock.h>
diff --git a/arch/arm/mach-pnx4008/serial.c b/arch/arm/mach-pnx4008/serial.c
index 9be84bb..f40961e 100644
--- a/arch/arm/mach-pnx4008/serial.c
+++ b/arch/arm/mach-pnx4008/serial.c
@@ -12,8 +12,7 @@
 
 #include <linux/kernel.h>
 #include <linux/types.h>
-
-#include <asm/io.h>
+#include <linux/io.h>
 
 #include <mach/platform.h>
 #include <mach/hardware.h>
diff --git a/arch/arm/mach-pnx4008/time.c b/arch/arm/mach-pnx4008/time.c
index 1809752..fc0ba18 100644
--- a/arch/arm/mach-pnx4008/time.c
+++ b/arch/arm/mach-pnx4008/time.c
@@ -22,10 +22,10 @@
 #include <linux/time.h>
 #include <linux/timex.h>
 #include <linux/irq.h>
+#include <linux/io.h>
 
 #include <asm/system.h>
 #include <mach/hardware.h>
-#include <asm/io.h>
 #include <asm/leds.h>
 #include <asm/mach/time.h>
 #include <asm/errno.h>
diff --git a/arch/arm/mach-pxa/Kconfig b/arch/arm/mach-pxa/Kconfig
index e8ee7ec..f27f6b3 100644
--- a/arch/arm/mach-pxa/Kconfig
+++ b/arch/arm/mach-pxa/Kconfig
@@ -38,16 +38,23 @@
 	bool "Intel DBPXA250 Development Platform"
 	select PXA25x
 	select SA1111
+	select PXA_HAVE_BOARD_IRQS
 
 config MACH_LOGICPD_PXA270
 	bool "LogicPD PXA270 Card Engine Development Platform"
 	select PXA27x
 	select HAVE_PWM
+	select PXA_HAVE_BOARD_IRQS
 
 config MACH_MAINSTONE
 	bool "Intel HCDDBBVA0 Development Platform"
 	select PXA27x
 	select HAVE_PWM
+	select PXA_HAVE_BOARD_IRQS
+
+config MACH_MP900C
+	bool "Nec Mobilepro 900/c"
+	select PXA25x
 
 config ARCH_PXA_IDP
 	bool "Accelent Xscale IDP"
@@ -114,10 +121,21 @@
 	bool "Enable Sharp SL-6000x (Tosa) Support"
 	depends on PXA_SHARPSL
 	select PXA25x
+	select PXA_HAVE_BOARD_IRQS
+
+config ARCH_VIPER
+	bool "Arcom/Eurotech VIPER SBC"
+	select PXA25x
+	select ISA
+	select I2C_GPIO
+	select HAVE_PWM
+	select PXA_HAVE_BOARD_IRQS
+	select PXA_HAVE_ISA_IRQS
 
 config ARCH_PXA_ESERIES
 	bool "PXA based Toshiba e-series PDAs"
 	select PXA25x
+	select PXA_HAVE_BOARD_IRQS
 
 config MACH_E330
 	bool "Toshiba e330"
@@ -170,13 +188,41 @@
 	  Say Y here if you intend to run this kernel on a Toshiba
 	  e800 family PDA.
 
+config TRIZEPS_PXA
+	bool "PXA based Keith und Koep Trizeps DIMM-Modules"
+
 config MACH_TRIZEPS4
 	bool "Keith und Koep Trizeps4 DIMM-Module"
+	depends on TRIZEPS_PXA
+	select TRIZEPS_PCMCIA
 	select PXA27x
 
-config MACH_TRIZEPS4_CONXS
+config MACH_TRIZEPS4WL
+	bool "Keith und Koep Trizeps4-WL DIMM-Module"
+	depends on TRIZEPS_PXA
+	select TRIZEPS_PCMCIA
+	select PXA27x
+	select PXA_SSP
+
+choice
+	prompt "Select base board for Trizeps module"
+	depends on TRIZEPS_PXA
+
+config MACH_TRIZEPS_CONXS
 	bool "ConXS Eval Board"
-	depends on MACH_TRIZEPS4
+
+config MACH_TRIZEPS_UCONXS
+	bool "uConXS Eval Board"
+
+config MACH_TRIZEPS_ANY
+	bool "another Board"
+
+endchoice
+
+config TRIZEPS_PCMCIA
+	bool
+	help
+	  Enable PCMCIA support for Trizeps modules
 
 config MACH_EM_X270
 	bool "CompuLab EM-x270 platform"
@@ -189,6 +235,7 @@
 config MACH_ZYLONITE
 	bool "PXA3xx Development Platform (aka Zylonite)"
 	select PXA3xx
+	select PXA_SSP
 	select HAVE_PWM
 
 config MACH_LITTLETON
@@ -207,20 +254,42 @@
 	select PXA930
 
 config MACH_ARMCORE
-	bool "CompuLab CM-X270 modules"
+	bool "CompuLab CM-X255/CM-X270 modules"
 	select PXA27x
 	select IWMMXT
+	select ZONE_DMA if PCI
+	select PXA25x
+	select PXA_SSP
+
+config MACH_CM_X300
+	bool "CompuLab CM-X300 modules"
+	select PXA3xx
+	select CPU_PXA300
 
 config MACH_MAGICIAN
 	bool "Enable HTC Magician Support"
 	select PXA27x
 	select IWMMXT
+	select PXA_HAVE_BOARD_IRQS
+
+config MACH_MIOA701
+	bool "Mitac Mio A701 Support"
+	select PXA27x
+	select IWMMXT
+	select LEDS_GPIO
+	select HAVE_PWM
+	select GPIO_SYSFS
+	help
+	  Say Y here if you intend to run this kernel on a
+	  MIO A701. Currently there is only basic support
+	  for this PDA.
 
 config MACH_PCM027
 	bool "Phytec phyCORE-PXA270 CPU module (PCM-027)"
 	select PXA27x
 	select IWMMXT
 	select PXA_SSP
+	select PXA_HAVE_BOARD_IRQS
 
 config ARCH_PXA_PALM
 	bool "PXA based Palm PDAs"
@@ -236,6 +305,16 @@
 	  Say Y here if you intend to run this kernel on a Palm T|X
 	  handheld computer.
 
+config MACH_PALMZ72
+	bool "Palm Zire 72"
+	default y
+	depends on ARCH_PXA_PALM
+	select PXA27x
+	select IWMMXT
+	help
+	  Say Y here if you intend to run this kernel on Palm Zire 72
+	  handheld computer.
+
 config MACH_PCM990_BASEBOARD
 	bool "PHYTEC PCM-990 development board"
 	select HAVE_PWM
@@ -256,6 +335,9 @@
 
 endchoice
 
+config MACH_AM200EPD
+	depends on MACH_GUMSTIX_F
+	bool "Enable AM200EPD board support"
 
 config PXA_EZX
 	bool "Motorola EZX Platform"
@@ -343,4 +425,10 @@
 	  This is a simple driver that is able to control
 	  the state of built in bluetooth chip on tosa.
 
+config PXA_HAVE_BOARD_IRQS
+	bool
+
+config PXA_HAVE_ISA_IRQS
+	bool
+
 endif
diff --git a/arch/arm/mach-pxa/Makefile b/arch/arm/mach-pxa/Makefile
index 99ecbe7..d31c997 100644
--- a/arch/arm/mach-pxa/Makefile
+++ b/arch/arm/mach-pxa/Makefile
@@ -6,7 +6,12 @@
 obj-y				+= clock.o devices.o generic.o irq.o dma.o \
 				   time.o gpio.o reset.o
 obj-$(CONFIG_PM)		+= pm.o sleep.o standby.o
-obj-$(CONFIG_CPU_FREQ)		+= cpu-pxa.o
+
+ifeq ($(CONFIG_CPU_FREQ),y)
+obj-$(CONFIG_PXA25x)		+= cpufreq-pxa2xx.o
+obj-$(CONFIG_PXA27x)		+= cpufreq-pxa2xx.o
+obj-$(CONFIG_PXA3xx)		+= cpufreq-pxa3xx.o
+endif
 
 # Generic drivers that other drivers may depend upon
 obj-$(CONFIG_PXA_SSP)		+= ssp.o
@@ -22,27 +27,33 @@
 
 # Specific board support
 obj-$(CONFIG_ARCH_GUMSTIX)	+= gumstix.o
+obj-$(CONFIG_MACH_AM200EPD)	+= am200epd.o
 obj-$(CONFIG_ARCH_LUBBOCK)	+= lubbock.o
 obj-$(CONFIG_MACH_LOGICPD_PXA270) += lpd270.o
 obj-$(CONFIG_MACH_MAINSTONE)	+= mainstone.o
+obj-$(CONFIG_MACH_MP900C)	+= mp900.o
 obj-$(CONFIG_ARCH_PXA_IDP)	+= idp.o
 obj-$(CONFIG_MACH_TRIZEPS4)	+= trizeps4.o
 obj-$(CONFIG_MACH_COLIBRI)	+= colibri.o
-obj-$(CONFIG_PXA_SHARP_C7xx)	+= corgi.o corgi_ssp.o corgi_lcd.o sharpsl_pm.o corgi_pm.o
-obj-$(CONFIG_PXA_SHARP_Cxx00)	+= spitz.o corgi_ssp.o corgi_lcd.o sharpsl_pm.o spitz_pm.o
-obj-$(CONFIG_MACH_AKITA)	+= akita-ioexp.o
-obj-$(CONFIG_MACH_POODLE)	+= poodle.o corgi_ssp.o
+obj-$(CONFIG_PXA_SHARP_C7xx)	+= corgi.o sharpsl_pm.o corgi_pm.o
+obj-$(CONFIG_PXA_SHARP_Cxx00)	+= spitz.o sharpsl_pm.o spitz_pm.o
+obj-$(CONFIG_MACH_POODLE)	+= poodle.o
 obj-$(CONFIG_MACH_PCM027)	+= pcm027.o
 obj-$(CONFIG_MACH_PCM990_BASEBOARD)	+= pcm990-baseboard.o
 obj-$(CONFIG_MACH_TOSA)		+= tosa.o
 obj-$(CONFIG_MACH_EM_X270)	+= em-x270.o
 obj-$(CONFIG_MACH_MAGICIAN)	+= magician.o
-obj-$(CONFIG_ARCH_PXA_ESERIES)	+= eseries.o eseries_udc.o
-obj-$(CONFIG_MACH_E740)		+= e740_lcd.o
-obj-$(CONFIG_MACH_E750)		+= e750_lcd.o
-obj-$(CONFIG_MACH_E400)		+= e400_lcd.o
-obj-$(CONFIG_MACH_E800)		+= e800_lcd.o
+obj-$(CONFIG_MACH_MIOA701)	+= mioa701.o mioa701_bootresume.o
+obj-$(CONFIG_ARCH_PXA_ESERIES)	+= eseries.o
+obj-$(CONFIG_MACH_E330)		+= e330.o
+obj-$(CONFIG_MACH_E350)		+= e350.o
+obj-$(CONFIG_MACH_E740)		+= e740.o
+obj-$(CONFIG_MACH_E750)		+= e750.o
+obj-$(CONFIG_MACH_E400)		+= e400.o
+obj-$(CONFIG_MACH_E800)		+= e800.o
 obj-$(CONFIG_MACH_PALMTX)	+= palmtx.o
+obj-$(CONFIG_MACH_PALMZ72)	+= palmz72.o
+obj-$(CONFIG_ARCH_VIPER)	+= viper.o
 
 ifeq ($(CONFIG_MACH_ZYLONITE),y)
   obj-y				+= zylonite.o
@@ -53,7 +64,8 @@
 obj-$(CONFIG_MACH_TAVOREVB)	+= tavorevb.o
 obj-$(CONFIG_MACH_SAAR)		+= saar.o
 
-obj-$(CONFIG_MACH_ARMCORE)      += cm-x270.o
+obj-$(CONFIG_MACH_ARMCORE)      += cm-x2xx.o cm-x255.o cm-x270.o
+obj-$(CONFIG_MACH_CM_X300)      += cm-x300.o
 obj-$(CONFIG_PXA_EZX)           += ezx.o
 
 # Support for blinky lights
@@ -61,12 +73,11 @@
 led-$(CONFIG_ARCH_LUBBOCK)	+= leds-lubbock.o
 led-$(CONFIG_MACH_MAINSTONE)	+= leds-mainstone.o
 led-$(CONFIG_ARCH_PXA_IDP)	+= leds-idp.o
-led-$(CONFIG_MACH_TRIZEPS4)	+= leds-trizeps4.o
 
 obj-$(CONFIG_LEDS)		+= $(led-y)
 
 ifeq ($(CONFIG_PCI),y)
-obj-$(CONFIG_MACH_ARMCORE) += cm-x270-pci.o
+obj-$(CONFIG_MACH_ARMCORE) += cm-x2xx-pci.o
 endif
 
 obj-$(CONFIG_TOSA_BT)		+= tosa-bt.o
diff --git a/arch/arm/mach-pxa/akita-ioexp.c b/arch/arm/mach-pxa/akita-ioexp.c
deleted file mode 100644
index 5c67b18..0000000
--- a/arch/arm/mach-pxa/akita-ioexp.c
+++ /dev/null
@@ -1,222 +0,0 @@
-/*
- * Support for the Extra GPIOs on the Sharp SL-C1000 (Akita)
- * (uses a Maxim MAX7310 8 Port IO Expander)
- *
- * Copyright 2005 Openedhand Ltd.
- *
- * Author: Richard Purdie <richard@openedhand.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/kernel.h>
-#include <linux/init.h>
-#include <linux/platform_device.h>
-#include <linux/module.h>
-#include <linux/i2c.h>
-#include <linux/slab.h>
-#include <linux/workqueue.h>
-#include <mach/akita.h>
-
-/* MAX7310 Regiser Map */
-#define MAX7310_INPUT    0x00
-#define MAX7310_OUTPUT   0x01
-#define MAX7310_POLINV   0x02
-#define MAX7310_IODIR    0x03 /* 1 = Input, 0 = Output */
-#define MAX7310_TIMEOUT  0x04
-
-/* Addresses to scan */
-static const unsigned short normal_i2c[] = { 0x18, I2C_CLIENT_END };
-
-/* I2C Magic */
-I2C_CLIENT_INSMOD;
-
-static int max7310_write(struct i2c_client *client, int address, int data);
-static struct i2c_client max7310_template;
-static void akita_ioexp_work(struct work_struct *private_);
-
-static struct device *akita_ioexp_device;
-static unsigned char ioexp_output_value = AKITA_IOEXP_IO_OUT;
-DECLARE_WORK(akita_ioexp, akita_ioexp_work);
-
-
-/*
- * MAX7310 Access
- */
-static int max7310_config(struct device *dev, int iomode, int polarity)
-{
-	int ret;
-	struct i2c_client *client = to_i2c_client(dev);
-
-	ret = max7310_write(client, MAX7310_POLINV, polarity);
-	if (ret < 0)
-		return ret;
-	ret = max7310_write(client, MAX7310_IODIR, iomode);
-	return ret;
-}
-
-static int max7310_set_ouputs(struct device *dev, int outputs)
-{
-	struct i2c_client *client = to_i2c_client(dev);
-
-	return max7310_write(client, MAX7310_OUTPUT, outputs);
-}
-
-/*
- * I2C Functions
- */
-static int max7310_write(struct i2c_client *client, int address, int value)
-{
-	u8 data[2];
-
-	data[0] = address & 0xff;
-	data[1] = value & 0xff;
-
-	if (i2c_master_send(client, data, 2) == 2)
-		return 0;
-	return -1;
-}
-
-static int max7310_detect(struct i2c_adapter *adapter, int address, int kind)
-{
-	struct i2c_client *new_client;
-	int err;
-
-	if (!(new_client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL)))
-		return -ENOMEM;
-
-	max7310_template.adapter = adapter;
-	max7310_template.addr = address;
-
-	memcpy(new_client, &max7310_template, sizeof(struct i2c_client));
-
-	if ((err = i2c_attach_client(new_client))) {
-		kfree(new_client);
-		return err;
-	}
-
-	max7310_config(&new_client->dev, AKITA_IOEXP_IO_DIR, 0);
-	akita_ioexp_device = &new_client->dev;
-	schedule_work(&akita_ioexp);
-
-	return 0;
-}
-
-static int max7310_attach_adapter(struct i2c_adapter *adapter)
-{
-	return i2c_probe(adapter, &addr_data, max7310_detect);
-}
-
-static int max7310_detach_client(struct i2c_client *client)
-{
-	int err;
-
-	akita_ioexp_device = NULL;
-
-	if ((err = i2c_detach_client(client)))
-		return err;
-
-	kfree(client);
-	return 0;
-}
-
-static struct i2c_driver max7310_i2c_driver = {
-	.driver = {
-		.name	= "akita-max7310",
-	},
-	.id		= I2C_DRIVERID_AKITAIOEXP,
-	.attach_adapter	= max7310_attach_adapter,
-	.detach_client	= max7310_detach_client,
-};
-
-static struct i2c_client max7310_template = {
-	name:   "akita-max7310",
-	driver: &max7310_i2c_driver,
-};
-
-void akita_set_ioexp(struct device *dev, unsigned char bit)
-{
-	ioexp_output_value |= bit;
-
-	if (akita_ioexp_device)
-		schedule_work(&akita_ioexp);
-	return;
-}
-
-void akita_reset_ioexp(struct device *dev, unsigned char bit)
-{
-	ioexp_output_value &= ~bit;
-
-	if (akita_ioexp_device)
-		schedule_work(&akita_ioexp);
-	return;
-}
-
-EXPORT_SYMBOL(akita_set_ioexp);
-EXPORT_SYMBOL(akita_reset_ioexp);
-
-static void akita_ioexp_work(struct work_struct *private_)
-{
-	if (akita_ioexp_device)
-		max7310_set_ouputs(akita_ioexp_device, ioexp_output_value);
-}
-
-
-#ifdef CONFIG_PM
-static int akita_ioexp_suspend(struct platform_device *pdev, pm_message_t state)
-{
-	flush_scheduled_work();
-	return 0;
-}
-
-static int akita_ioexp_resume(struct platform_device *pdev)
-{
-	schedule_work(&akita_ioexp);
-	return 0;
-}
-#else
-#define akita_ioexp_suspend NULL
-#define akita_ioexp_resume NULL
-#endif
-
-static int __init akita_ioexp_probe(struct platform_device *pdev)
-{
-	return i2c_add_driver(&max7310_i2c_driver);
-}
-
-static int akita_ioexp_remove(struct platform_device *pdev)
-{
-	i2c_del_driver(&max7310_i2c_driver);
-	return 0;
-}
-
-static struct platform_driver akita_ioexp_driver = {
-	.probe		= akita_ioexp_probe,
-	.remove		= akita_ioexp_remove,
-	.suspend	= akita_ioexp_suspend,
-	.resume		= akita_ioexp_resume,
-	.driver		= {
-		.name	= "akita-ioexp",
-	},
-};
-
-static int __init akita_ioexp_init(void)
-{
-	return platform_driver_register(&akita_ioexp_driver);
-}
-
-static void __exit akita_ioexp_exit(void)
-{
-	platform_driver_unregister(&akita_ioexp_driver);
-}
-
-MODULE_AUTHOR("Richard Purdie <rpurdie@openedhand.com>");
-MODULE_DESCRIPTION("Akita IO-Expander driver");
-MODULE_LICENSE("GPL");
-
-fs_initcall(akita_ioexp_init);
-module_exit(akita_ioexp_exit);
-
diff --git a/arch/arm/mach-pxa/am200epd.c b/arch/arm/mach-pxa/am200epd.c
new file mode 100644
index 0000000..b965085
--- /dev/null
+++ b/arch/arm/mach-pxa/am200epd.c
@@ -0,0 +1,374 @@
+/*
+ * am200epd.c -- Platform device for AM200 EPD kit
+ *
+ * Copyright (C) 2008, Jaya Kumar
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file COPYING in the main directory of this archive for
+ * more details.
+ *
+ * Layout is based on skeletonfb.c by James Simmons and Geert Uytterhoeven.
+ *
+ * This work was made possible by help and equipment support from E-Ink
+ * Corporation. http://support.eink.com/community
+ *
+ * This driver is written to be used with the Metronome display controller.
+ * on the AM200 EPD prototype kit/development kit with an E-Ink 800x600
+ * Vizplex EPD on a Gumstix board using the Lyre interface board.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/irq.h>
+#include <linux/gpio.h>
+
+#include <mach/pxafb.h>
+
+#include <video/metronomefb.h>
+
+static unsigned int panel_type = 6;
+static struct platform_device *am200_device;
+static struct metronome_board am200_board;
+
+static struct pxafb_mode_info am200_fb_mode_9inch7 = {
+	.pixclock	= 40000,
+	.xres		= 1200,
+	.yres		= 842,
+	.bpp		= 16,
+	.hsync_len	= 2,
+	.left_margin	= 2,
+	.right_margin	= 2,
+	.vsync_len	= 1,
+	.upper_margin	= 2,
+	.lower_margin	= 25,
+	.sync		= FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+};
+
+static struct pxafb_mode_info am200_fb_mode_8inch = {
+	.pixclock	= 40000,
+	.xres		= 1088,
+	.yres		= 791,
+	.bpp		= 16,
+	.hsync_len	= 28,
+	.left_margin	= 8,
+	.right_margin	= 30,
+	.vsync_len	= 8,
+	.upper_margin	= 10,
+	.lower_margin	= 8,
+	.sync		= FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+};
+
+static struct pxafb_mode_info am200_fb_mode_6inch = {
+	.pixclock	= 40189,
+	.xres		= 832,
+	.yres		= 622,
+	.bpp		= 16,
+	.hsync_len	= 28,
+	.left_margin	= 34,
+	.right_margin	= 34,
+	.vsync_len	= 25,
+	.upper_margin	= 0,
+	.lower_margin	= 2,
+	.sync		= FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+};
+
+static struct pxafb_mach_info am200_fb_info = {
+	.modes		= &am200_fb_mode_6inch,
+	.num_modes	= 1,
+	.lcd_conn	= LCD_TYPE_COLOR_TFT | LCD_PCLK_EDGE_FALL |
+			  LCD_AC_BIAS_FREQ(24),
+};
+
+/* register offsets for gpio control */
+#define LED_GPIO_PIN 51
+#define STDBY_GPIO_PIN 48
+#define RST_GPIO_PIN 49
+#define RDY_GPIO_PIN 32
+#define ERR_GPIO_PIN 17
+#define PCBPWR_GPIO_PIN 16
+static int gpios[] = { LED_GPIO_PIN , STDBY_GPIO_PIN , RST_GPIO_PIN,
+			RDY_GPIO_PIN, ERR_GPIO_PIN, PCBPWR_GPIO_PIN };
+static char *gpio_names[] = { "LED" , "STDBY" , "RST", "RDY", "ERR", "PCBPWR" };
+
+static int am200_init_gpio_regs(struct metronomefb_par *par)
+{
+	int i;
+	int err;
+
+	for (i = 0; i < ARRAY_SIZE(gpios); i++) {
+		err = gpio_request(gpios[i], gpio_names[i]);
+		if (err) {
+			dev_err(&am200_device->dev, "failed requesting "
+				"gpio %s, err=%d\n", gpio_names[i], err);
+			goto err_req_gpio;
+		}
+	}
+
+	gpio_direction_output(LED_GPIO_PIN, 0);
+	gpio_direction_output(STDBY_GPIO_PIN, 0);
+	gpio_direction_output(RST_GPIO_PIN, 0);
+
+	gpio_direction_input(RDY_GPIO_PIN);
+	gpio_direction_input(ERR_GPIO_PIN);
+
+	gpio_direction_output(PCBPWR_GPIO_PIN, 0);
+
+	return 0;
+
+err_req_gpio:
+	while (i > 0)
+		gpio_free(gpios[i--]);
+
+	return err;
+}
+
+static void am200_cleanup(struct metronomefb_par *par)
+{
+	int i;
+
+	free_irq(IRQ_GPIO(RDY_GPIO_PIN), par);
+
+	for (i = 0; i < ARRAY_SIZE(gpios); i++)
+		gpio_free(gpios[i]);
+}
+
+static int am200_share_video_mem(struct fb_info *info)
+{
+	/* rough check if this is our desired fb and not something else */
+	if ((info->var.xres != am200_fb_info.modes->xres)
+		|| (info->var.yres != am200_fb_info.modes->yres))
+		return 0;
+
+	/* we've now been notified that we have our new fb */
+	am200_board.metromem = info->screen_base;
+	am200_board.host_fbinfo = info;
+
+	/* try to refcount host drv since we are the consumer after this */
+	if (!try_module_get(info->fbops->owner))
+		return -ENODEV;
+
+	return 0;
+}
+
+static int am200_unshare_video_mem(struct fb_info *info)
+{
+	dev_dbg(&am200_device->dev, "ENTER %s\n", __func__);
+
+	if (info != am200_board.host_fbinfo)
+		return 0;
+
+	module_put(am200_board.host_fbinfo->fbops->owner);
+	return 0;
+}
+
+static int am200_fb_notifier_callback(struct notifier_block *self,
+				 unsigned long event, void *data)
+{
+	struct fb_event *evdata = data;
+	struct fb_info *info = evdata->info;
+
+	dev_dbg(&am200_device->dev, "ENTER %s\n", __func__);
+
+	if (event == FB_EVENT_FB_REGISTERED)
+		return am200_share_video_mem(info);
+	else if (event == FB_EVENT_FB_UNREGISTERED)
+		return am200_unshare_video_mem(info);
+
+	return 0;
+}
+
+static struct notifier_block am200_fb_notif = {
+	.notifier_call = am200_fb_notifier_callback,
+};
+
+/* this gets called as part of our init. these steps must be done now so
+ * that we can use set_pxa_fb_info */
+static void __init am200_presetup_fb(void)
+{
+	int fw;
+	int fh;
+	int padding_size;
+	int totalsize;
+
+	switch (panel_type) {
+	case 6:
+		am200_fb_info.modes = &am200_fb_mode_6inch;
+		break;
+	case 8:
+		am200_fb_info.modes = &am200_fb_mode_8inch;
+		break;
+	case 97:
+		am200_fb_info.modes = &am200_fb_mode_9inch7;
+		break;
+	default:
+		dev_err(&am200_device->dev, "invalid panel_type selection,"
+						" setting to 6\n");
+		am200_fb_info.modes = &am200_fb_mode_6inch;
+		break;
+	}
+
+	/* the frame buffer is divided as follows:
+	command | CRC | padding
+	16kb waveform data | CRC | padding
+	image data | CRC
+	*/
+
+	fw = am200_fb_info.modes->xres;
+	fh = am200_fb_info.modes->yres;
+
+	/* waveform must be 16k + 2 for checksum */
+	am200_board.wfm_size = roundup(16*1024 + 2, fw);
+
+	padding_size = PAGE_SIZE + (4 * fw);
+
+	/* total is 1 cmd , 1 wfm, padding and image */
+	totalsize = fw + am200_board.wfm_size + padding_size + (fw*fh);
+
+	/* save this off because we're manipulating fw after this and
+	 * we'll need it when we're ready to setup the framebuffer */
+	am200_board.fw = fw;
+	am200_board.fh = fh;
+
+	/* the reason we do this adjustment is because we want to acquire
+	 * more framebuffer memory without imposing custom awareness on the
+	 * underlying pxafb driver */
+	am200_fb_info.modes->yres = DIV_ROUND_UP(totalsize, fw);
+
+	/* we divide since we told the LCD controller we're 16bpp */
+	am200_fb_info.modes->xres /= 2;
+
+	set_pxa_fb_info(&am200_fb_info);
+
+}
+
+/* this gets called by metronomefb as part of its init, in our case, we
+ * have already completed initial framebuffer init in presetup_fb so we
+ * can just setup the fb access pointers */
+static int am200_setup_fb(struct metronomefb_par *par)
+{
+	int fw;
+	int fh;
+
+	fw = am200_board.fw;
+	fh = am200_board.fh;
+
+	/* metromem was set up by the notifier in share_video_mem so now
+	 * we can use its value to calculate the other entries */
+	par->metromem_cmd = (struct metromem_cmd *) am200_board.metromem;
+	par->metromem_wfm = am200_board.metromem + fw;
+	par->metromem_img = par->metromem_wfm + am200_board.wfm_size;
+	par->metromem_img_csum = (u16 *) (par->metromem_img + (fw * fh));
+	par->metromem_dma = am200_board.host_fbinfo->fix.smem_start;
+
+	return 0;
+}
+
+static int am200_get_panel_type(void)
+{
+	return panel_type;
+}
+
+static irqreturn_t am200_handle_irq(int irq, void *dev_id)
+{
+	struct metronomefb_par *par = dev_id;
+
+	wake_up_interruptible(&par->waitq);
+	return IRQ_HANDLED;
+}
+
+static int am200_setup_irq(struct fb_info *info)
+{
+	int ret;
+
+	ret = request_irq(IRQ_GPIO(RDY_GPIO_PIN), am200_handle_irq,
+				IRQF_DISABLED|IRQF_TRIGGER_FALLING,
+				"AM200", info->par);
+	if (ret)
+		dev_err(&am200_device->dev, "request_irq failed: %d\n", ret);
+
+	return ret;
+}
+
+static void am200_set_rst(struct metronomefb_par *par, int state)
+{
+	gpio_set_value(RST_GPIO_PIN, state);
+}
+
+static void am200_set_stdby(struct metronomefb_par *par, int state)
+{
+	gpio_set_value(STDBY_GPIO_PIN, state);
+}
+
+static int am200_wait_event(struct metronomefb_par *par)
+{
+	return wait_event_timeout(par->waitq, gpio_get_value(RDY_GPIO_PIN), HZ);
+}
+
+static int am200_wait_event_intr(struct metronomefb_par *par)
+{
+	return wait_event_interruptible_timeout(par->waitq,
+					gpio_get_value(RDY_GPIO_PIN), HZ);
+}
+
+static struct metronome_board am200_board = {
+	.owner			= THIS_MODULE,
+	.setup_irq		= am200_setup_irq,
+	.setup_io		= am200_init_gpio_regs,
+	.setup_fb		= am200_setup_fb,
+	.set_rst		= am200_set_rst,
+	.set_stdby		= am200_set_stdby,
+	.met_wait_event		= am200_wait_event,
+	.met_wait_event_intr	= am200_wait_event_intr,
+	.get_panel_type		= am200_get_panel_type,
+	.cleanup		= am200_cleanup,
+};
+
+static int __init am200_init(void)
+{
+	int ret;
+
+	/* before anything else, we request notification for any fb
+	 * creation events */
+	fb_register_client(&am200_fb_notif);
+
+	/* request our platform independent driver */
+	request_module("metronomefb");
+
+	am200_device = platform_device_alloc("metronomefb", -1);
+	if (!am200_device)
+		return -ENOMEM;
+
+	/* the am200_board that will be seen by metronomefb is a copy */
+	platform_device_add_data(am200_device, &am200_board,
+					sizeof(am200_board));
+
+	/* this _add binds metronomefb to am200. metronomefb refcounts am200 */
+	ret = platform_device_add(am200_device);
+
+	if (ret) {
+		platform_device_put(am200_device);
+		fb_unregister_client(&am200_fb_notif);
+		return ret;
+	}
+
+	am200_presetup_fb();
+
+	return 0;
+}
+
+module_param(panel_type, uint, 0);
+MODULE_PARM_DESC(panel_type, "Select the panel type: 6, 8, 97");
+
+module_init(am200_init);
+
+MODULE_DESCRIPTION("board driver for am200 metronome epd kit");
+MODULE_AUTHOR("Jaya Kumar");
+MODULE_LICENSE("GPL");
diff --git a/arch/arm/mach-pxa/cm-x255.c b/arch/arm/mach-pxa/cm-x255.c
new file mode 100644
index 0000000..83a4cdf
--- /dev/null
+++ b/arch/arm/mach-pxa/cm-x255.c
@@ -0,0 +1,258 @@
+/*
+ * linux/arch/arm/mach-pxa/cm-x255.c
+ *
+ * Copyright (C) 2007, 2008 CompuLab, Ltd.
+ * Mike Rapoport <mike@compulab.co.il>
+ *
+ * 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/platform_device.h>
+#include <linux/irq.h>
+#include <linux/gpio.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/physmap.h>
+#include <linux/mtd/nand-gpio.h>
+
+#include <linux/spi/spi.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach-types.h>
+#include <asm/mach/map.h>
+
+#include <mach/pxa2xx-regs.h>
+#include <mach/mfp-pxa25x.h>
+#include <mach/pxa2xx_spi.h>
+#include <mach/bitfield.h>
+
+#include "generic.h"
+
+#define GPIO_NAND_CS	(5)
+#define GPIO_NAND_ALE	(4)
+#define GPIO_NAND_CLE	(3)
+#define GPIO_NAND_RB	(10)
+
+static unsigned long cmx255_pin_config[] = {
+	/* AC'97 */
+	GPIO28_AC97_BITCLK,
+	GPIO29_AC97_SDATA_IN_0,
+	GPIO30_AC97_SDATA_OUT,
+	GPIO31_AC97_SYNC,
+
+	/* BTUART */
+	GPIO42_BTUART_RXD,
+	GPIO43_BTUART_TXD,
+	GPIO44_BTUART_CTS,
+	GPIO45_BTUART_RTS,
+
+	/* STUART */
+	GPIO46_STUART_RXD,
+	GPIO47_STUART_TXD,
+
+	/* LCD */
+	GPIO58_LCD_LDD_0,
+	GPIO59_LCD_LDD_1,
+	GPIO60_LCD_LDD_2,
+	GPIO61_LCD_LDD_3,
+	GPIO62_LCD_LDD_4,
+	GPIO63_LCD_LDD_5,
+	GPIO64_LCD_LDD_6,
+	GPIO65_LCD_LDD_7,
+	GPIO66_LCD_LDD_8,
+	GPIO67_LCD_LDD_9,
+	GPIO68_LCD_LDD_10,
+	GPIO69_LCD_LDD_11,
+	GPIO70_LCD_LDD_12,
+	GPIO71_LCD_LDD_13,
+	GPIO72_LCD_LDD_14,
+	GPIO73_LCD_LDD_15,
+	GPIO74_LCD_FCLK,
+	GPIO75_LCD_LCLK,
+	GPIO76_LCD_PCLK,
+	GPIO77_LCD_BIAS,
+
+	/* SSP1 */
+	GPIO23_SSP1_SCLK,
+	GPIO24_SSP1_SFRM,
+	GPIO25_SSP1_TXD,
+	GPIO26_SSP1_RXD,
+
+	/* SSP2 */
+	GPIO81_SSP2_CLK_OUT,
+	GPIO82_SSP2_FRM_OUT,
+	GPIO83_SSP2_TXD,
+	GPIO84_SSP2_RXD,
+
+	/* PC Card */
+	GPIO48_nPOE,
+	GPIO49_nPWE,
+	GPIO50_nPIOR,
+	GPIO51_nPIOW,
+	GPIO52_nPCE_1,
+	GPIO53_nPCE_2,
+	GPIO54_nPSKTSEL,
+	GPIO55_nPREG,
+	GPIO56_nPWAIT,
+	GPIO57_nIOIS16,
+
+	/* SDRAM and local bus */
+	GPIO15_nCS_1,
+	GPIO78_nCS_2,
+	GPIO79_nCS_3,
+	GPIO80_nCS_4,
+	GPIO33_nCS_5,
+	GPIO18_RDY,
+
+	/* GPIO */
+	GPIO0_GPIO	| WAKEUP_ON_EDGE_BOTH,
+	GPIO9_GPIO,				/* PC card reset */
+
+	/* NAND controls */
+	GPIO5_GPIO	| MFP_LPM_DRIVE_HIGH,	/* NAND CE# */
+	GPIO4_GPIO	| MFP_LPM_DRIVE_LOW,	/* NAND ALE */
+	GPIO3_GPIO	| MFP_LPM_DRIVE_LOW,	/* NAND CLE */
+	GPIO10_GPIO,				/* NAND Ready/Busy */
+
+	/* interrupts */
+	GPIO22_GPIO,	/* DM9000 interrupt */
+};
+
+#if defined(CONFIG_SPI_PXA2XX)
+static struct pxa2xx_spi_master pxa_ssp_master_info = {
+	.num_chipselect	= 1,
+};
+
+static struct spi_board_info spi_board_info[] __initdata = {
+	[0] = {
+		.modalias	= "rtc-max6902",
+		.max_speed_hz	= 1000000,
+		.bus_num	= 1,
+		.chip_select	= 0,
+	},
+};
+
+static void __init cmx255_init_rtc(void)
+{
+	pxa2xx_set_spi_info(1, &pxa_ssp_master_info);
+	spi_register_board_info(ARRAY_AND_SIZE(spi_board_info));
+}
+#else
+static inline void cmx255_init_rtc(void) {}
+#endif
+
+#if defined(CONFIG_MTD_PHYSMAP) || defined(CONFIG_MTD_PHYSMAP_MODULE)
+static struct mtd_partition cmx255_nor_partitions[] = {
+	{
+		.name		= "ARMmon",
+		.size		= 0x00030000,
+		.offset		= 0,
+		.mask_flags	= MTD_WRITEABLE  /* force read-only */
+	} , {
+		.name		= "ARMmon setup block",
+		.size		= 0x00010000,
+		.offset		= MTDPART_OFS_APPEND,
+		.mask_flags	= MTD_WRITEABLE  /* force read-only */
+	} , {
+		.name		= "kernel",
+		.size		= 0x00160000,
+		.offset		= MTDPART_OFS_APPEND,
+	} , {
+		.name		= "ramdisk",
+		.size		= MTDPART_SIZ_FULL,
+		.offset		= MTDPART_OFS_APPEND
+	}
+};
+
+static struct physmap_flash_data cmx255_nor_flash_data[] = {
+	{
+		.width		= 2,	/* bankwidth in bytes */
+		.parts		= cmx255_nor_partitions,
+		.nr_parts	= ARRAY_SIZE(cmx255_nor_partitions)
+	}
+};
+
+static struct resource cmx255_nor_resource = {
+	.start	= PXA_CS0_PHYS,
+	.end	= PXA_CS0_PHYS + SZ_8M - 1,
+	.flags	= IORESOURCE_MEM,
+};
+
+static struct platform_device cmx255_nor = {
+	.name	= "physmap-flash",
+	.id	= -1,
+	.dev	= {
+		.platform_data = cmx255_nor_flash_data,
+	},
+	.resource = &cmx255_nor_resource,
+	.num_resources = 1,
+};
+
+static void __init cmx255_init_nor(void)
+{
+	platform_device_register(&cmx255_nor);
+}
+#else
+static inline void cmx255_init_nor(void) {}
+#endif
+
+#if defined(CONFIG_MTD_NAND_GPIO) || defined(CONFIG_MTD_NAND_GPIO_MODULE)
+static struct resource cmx255_nand_resource[] = {
+	[0] = {
+		.start = PXA_CS1_PHYS,
+		.end   = PXA_CS1_PHYS + 11,
+		.flags = IORESOURCE_MEM,
+	},
+	[1] = {
+		.start = PXA_CS5_PHYS,
+		.end   = PXA_CS5_PHYS + 3,
+		.flags = IORESOURCE_MEM,
+	},
+};
+
+static struct mtd_partition cmx255_nand_parts[] = {
+	[0] = {
+		.name	= "cmx255-nand",
+		.size	= MTDPART_SIZ_FULL,
+		.offset	= 0,
+	},
+};
+
+static struct gpio_nand_platdata cmx255_nand_platdata = {
+	.gpio_nce = GPIO_NAND_CS,
+	.gpio_cle = GPIO_NAND_CLE,
+	.gpio_ale = GPIO_NAND_ALE,
+	.gpio_rdy = GPIO_NAND_RB,
+	.gpio_nwp = -1,
+	.parts = cmx255_nand_parts,
+	.num_parts = ARRAY_SIZE(cmx255_nand_parts),
+	.chip_delay = 25,
+};
+
+static struct platform_device cmx255_nand = {
+	.name		= "gpio-nand",
+	.num_resources	= ARRAY_SIZE(cmx255_nand_resource),
+	.resource	= cmx255_nand_resource,
+	.id		= -1,
+	.dev		= {
+		.platform_data = &cmx255_nand_platdata,
+	}
+};
+
+static void __init cmx255_init_nand(void)
+{
+	platform_device_register(&cmx255_nand);
+}
+#else
+static inline void cmx255_init_nand(void) {}
+#endif
+
+void __init cmx255_init(void)
+{
+	pxa2xx_mfp_config(ARRAY_AND_SIZE(cmx255_pin_config));
+
+	cmx255_init_rtc();
+	cmx255_init_nor();
+	cmx255_init_nand();
+}
diff --git a/arch/arm/mach-pxa/cm-x270-pci.c b/arch/arm/mach-pxa/cm-x270-pci.c
deleted file mode 100644
index 2d5bcea..0000000
--- a/arch/arm/mach-pxa/cm-x270-pci.c
+++ /dev/null
@@ -1,220 +0,0 @@
-/*
- * linux/arch/arm/mach-pxa/cm-x270-pci.c
- *
- * PCI bios-type initialisation for PCI machines
- *
- * Bits taken from various places.
- *
- * Copyright (C) 2007, 2008 Compulab, Ltd.
- * Mike Rapoport <mike@compulab.co.il>
- *
- * 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/kernel.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/device.h>
-#include <linux/platform_device.h>
-#include <linux/irq.h>
-#include <linux/gpio.h>
-
-#include <asm/mach/pci.h>
-#include <mach/pxa-regs.h>
-#include <asm/mach-types.h>
-
-#include <asm/hardware/it8152.h>
-
-unsigned long it8152_base_address;
-static int cmx270_it8152_irq_gpio;
-
-/*
- * Only first 64MB of memory can be accessed via PCI.
- * We use GFP_DMA to allocate safe buffers to do map/unmap.
- * This is really ugly and we need a better way of specifying
- * DMA-capable regions of memory.
- */
-void __init cmx270_pci_adjust_zones(int node, unsigned long *zone_size,
-	unsigned long *zhole_size)
-{
-	unsigned int sz = SZ_64M >> PAGE_SHIFT;
-
-	if (machine_is_armcore()) {
-		pr_info("Adjusting zones for CM-X270\n");
-
-		/*
-		 * Only adjust if > 64M on current system
-		 */
-		if (node || (zone_size[0] <= sz))
-			return;
-
-		zone_size[1] = zone_size[0] - sz;
-		zone_size[0] = sz;
-		zhole_size[1] = zhole_size[0];
-		zhole_size[0] = 0;
-	}
-}
-
-static void cmx270_it8152_irq_demux(unsigned int irq, struct irq_desc *desc)
-{
-	/* clear our parent irq */
-	GEDR(cmx270_it8152_irq_gpio) = GPIO_bit(cmx270_it8152_irq_gpio);
-
-	it8152_irq_demux(irq, desc);
-}
-
-void __cmx270_pci_init_irq(int irq_gpio)
-{
-	it8152_init_irq();
-
-	cmx270_it8152_irq_gpio = irq_gpio;
-
-	set_irq_type(gpio_to_irq(irq_gpio), IRQ_TYPE_EDGE_RISING);
-
-	set_irq_chained_handler(gpio_to_irq(irq_gpio), cmx270_it8152_irq_demux);
-}
-
-#ifdef CONFIG_PM
-static unsigned long sleep_save_ite[10];
-
-void __cmx270_pci_suspend(void)
-{
-	/* save ITE state */
-	sleep_save_ite[0] = __raw_readl(IT8152_INTC_PDCNIMR);
-	sleep_save_ite[1] = __raw_readl(IT8152_INTC_LPCNIMR);
-	sleep_save_ite[2] = __raw_readl(IT8152_INTC_LPNIAR);
-
-	/* Clear ITE IRQ's */
-	__raw_writel((0), IT8152_INTC_PDCNIRR);
-	__raw_writel((0), IT8152_INTC_LPCNIRR);
-}
-
-void __cmx270_pci_resume(void)
-{
-	/* restore IT8152 state */
-	__raw_writel((sleep_save_ite[0]), IT8152_INTC_PDCNIMR);
-	__raw_writel((sleep_save_ite[1]), IT8152_INTC_LPCNIMR);
-	__raw_writel((sleep_save_ite[2]), IT8152_INTC_LPNIAR);
-}
-#else
-void cmx270_pci_suspend(void) {}
-void cmx270_pci_resume(void) {}
-#endif
-
-/* PCI IRQ mapping*/
-static int __init cmx270_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
-{
-	int irq;
-
-	dev_dbg(&dev->dev, "%s: slot=%x, pin=%x\n", __func__, slot, pin);
-
-	irq = it8152_pci_map_irq(dev, slot, pin);
-	if (irq)
-		return irq;
-
-	/*
-	  Here comes the ugly part. The routing is baseboard specific,
-	  but defining a platform for each possible base of CM-X270 is
-	  unrealistic. Here we keep mapping for ATXBase and SB-X270.
-	*/
-	/* ATXBASE PCI slot */
-	if (slot == 7)
-		return IT8152_PCI_INTA;
-
-	/* ATXBase/SB-x270 CardBus */
-	if (slot == 8 || slot == 0)
-		return IT8152_PCI_INTB;
-
-	/* ATXBase Ethernet */
-	if (slot == 9)
-		return IT8152_PCI_INTA;
-
-	/* SB-x270 Ethernet */
-	if (slot == 16)
-		return IT8152_PCI_INTA;
-
-	/* PC104+ interrupt routing */
-	if ((slot == 17) || (slot == 19))
-		return IT8152_PCI_INTA;
-	if ((slot == 18) || (slot == 20))
-		return IT8152_PCI_INTB;
-
-	return(0);
-}
-
-static void cmx270_pci_preinit(void)
-{
-	pr_info("Initializing CM-X270 PCI subsystem\n");
-
-	__raw_writel(0x800, IT8152_PCI_CFG_ADDR);
-	if (__raw_readl(IT8152_PCI_CFG_DATA) == 0x81521283) {
-		pr_info("PCI Bridge found.\n");
-
-		/* set PCI I/O base at 0 */
-		writel(0x848, IT8152_PCI_CFG_ADDR);
-		writel(0, IT8152_PCI_CFG_DATA);
-
-		/* set PCI memory base at 0 */
-		writel(0x840, IT8152_PCI_CFG_ADDR);
-		writel(0, IT8152_PCI_CFG_DATA);
-
-		writel(0x20, IT8152_GPIO_GPDR);
-
-		/* CardBus Controller on ATXbase baseboard */
-		writel(0x4000, IT8152_PCI_CFG_ADDR);
-		if (readl(IT8152_PCI_CFG_DATA) == 0xAC51104C) {
-			pr_info("CardBus Bridge found.\n");
-
-			/* Configure socket 0 */
-			writel(0x408C, IT8152_PCI_CFG_ADDR);
-			writel(0x1022, IT8152_PCI_CFG_DATA);
-
-			writel(0x4080, IT8152_PCI_CFG_ADDR);
-			writel(0x3844d060, IT8152_PCI_CFG_DATA);
-
-			writel(0x4090, IT8152_PCI_CFG_ADDR);
-			writel(((readl(IT8152_PCI_CFG_DATA) & 0xffff) |
-				0x60440000),
-			       IT8152_PCI_CFG_DATA);
-
-			writel(0x4018, IT8152_PCI_CFG_ADDR);
-			writel(0xb0000000, IT8152_PCI_CFG_DATA);
-
-			/* Configure socket 1 */
-			writel(0x418C, IT8152_PCI_CFG_ADDR);
-			writel(0x1022, IT8152_PCI_CFG_DATA);
-
-			writel(0x4180, IT8152_PCI_CFG_ADDR);
-			writel(0x3844d060, IT8152_PCI_CFG_DATA);
-
-			writel(0x4190, IT8152_PCI_CFG_ADDR);
-			writel(((readl(IT8152_PCI_CFG_DATA) & 0xffff) |
-				0x60440000),
-			       IT8152_PCI_CFG_DATA);
-
-			writel(0x4118, IT8152_PCI_CFG_ADDR);
-			writel(0xb0000000, IT8152_PCI_CFG_DATA);
-		}
-	}
-}
-
-static struct hw_pci cmx270_pci __initdata = {
-	.swizzle	= pci_std_swizzle,
-	.map_irq	= cmx270_pci_map_irq,
-	.nr_controllers	= 1,
-	.setup		= it8152_pci_setup,
-	.scan		= it8152_pci_scan_bus,
-	.preinit	= cmx270_pci_preinit,
-};
-
-static int __init cmx270_init_pci(void)
-{
-	if (machine_is_armcore())
-		pci_common_init(&cmx270_pci);
-
-	return 0;
-}
-
-subsys_initcall(cmx270_init_pci);
diff --git a/arch/arm/mach-pxa/cm-x270-pci.h b/arch/arm/mach-pxa/cm-x270-pci.h
deleted file mode 100644
index 48f532f..0000000
--- a/arch/arm/mach-pxa/cm-x270-pci.h
+++ /dev/null
@@ -1,13 +0,0 @@
-extern void __cmx270_pci_init_irq(int irq_gpio);
-extern void __cmx270_pci_suspend(void);
-extern void __cmx270_pci_resume(void);
-
-#ifdef CONFIG_PCI
-#define cmx270_pci_init_irq(x) __cmx270_pci_init_irq(x)
-#define cmx270_pci_suspend(x) __cmx270_pci_suspend(x)
-#define cmx270_pci_resume(x) __cmx270_pci_resume(x)
-#else
-#define cmx270_pci_init_irq(x) do {} while (0)
-#define cmx270_pci_suspend(x) do {} while (0)
-#define cmx270_pci_resume(x) do {} while (0)
-#endif
diff --git a/arch/arm/mach-pxa/cm-x270.c b/arch/arm/mach-pxa/cm-x270.c
index af003a2..a82dad1 100644
--- a/arch/arm/mach-pxa/cm-x270.c
+++ b/arch/arm/mach-pxa/cm-x270.c
@@ -14,46 +14,22 @@
 #include <linux/irq.h>
 #include <linux/gpio.h>
 
-#include <linux/dm9000.h>
 #include <linux/rtc-v3020.h>
 #include <video/mbxfb.h>
-#include <linux/leds.h>
 
-#include <asm/mach/arch.h>
-#include <asm/mach-types.h>
-#include <asm/mach/map.h>
-
-#include <mach/pxa2xx-regs.h>
 #include <mach/mfp-pxa27x.h>
-#include <mach/pxa-regs.h>
-#include <mach/audio.h>
-#include <mach/pxafb.h>
 #include <mach/ohci.h>
 #include <mach/mmc.h>
-#include <mach/bitfield.h>
-
-#include <asm/hardware/it8152.h>
 
 #include "generic.h"
-#include "cm-x270-pci.h"
 
-/* virtual addresses for statically mapped regions */
-#define CMX270_VIRT_BASE	(0xe8000000)
-#define CMX270_IT8152_VIRT	(CMX270_VIRT_BASE)
-
+/* physical address if local-bus attached devices */
 #define RTC_PHYS_BASE		(PXA_CS1_PHYS + (5 << 22))
-#define DM9000_PHYS_BASE	(PXA_CS1_PHYS + (6 << 22))
 
 /* GPIO IRQ usage */
-#define GPIO10_ETHIRQ		(10)
-#define GPIO22_IT8152_IRQ	(22)
 #define GPIO83_MMC_IRQ		(83)
-#define GPIO95_GFXIRQ		(95)
 
-#define CMX270_ETHIRQ		IRQ_GPIO(GPIO10_ETHIRQ)
-#define CMX270_IT8152_IRQ	IRQ_GPIO(GPIO22_IT8152_IRQ)
 #define CMX270_MMC_IRQ		IRQ_GPIO(GPIO83_MMC_IRQ)
-#define CMX270_GFXIRQ		IRQ_GPIO(GPIO95_GFXIRQ)
 
 /* MMC power enable */
 #define GPIO105_MMC_POWER	(105)
@@ -157,62 +133,6 @@
 	GPIO83_GPIO,	/* MMC card detect */
 };
 
-#if defined(CONFIG_DM9000) || defined(CONFIG_DM9000_MODULE)
-static struct resource cmx270_dm9000_resource[] = {
-	[0] = {
-		.start = DM9000_PHYS_BASE,
-		.end   = DM9000_PHYS_BASE + 4,
-		.flags = IORESOURCE_MEM,
-	},
-	[1] = {
-		.start = DM9000_PHYS_BASE + 8,
-		.end   = DM9000_PHYS_BASE + 8 + 500,
-		.flags = IORESOURCE_MEM,
-	},
-	[2] = {
-		.start = CMX270_ETHIRQ,
-		.end   = CMX270_ETHIRQ,
-		.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE,
-	}
-};
-
-static struct dm9000_plat_data cmx270_dm9000_platdata = {
-	.flags		= DM9000_PLATF_32BITONLY,
-};
-
-static struct platform_device cmx270_dm9000_device = {
-	.name		= "dm9000",
-	.id		= 0,
-	.num_resources	= ARRAY_SIZE(cmx270_dm9000_resource),
-	.resource	= cmx270_dm9000_resource,
-	.dev		= {
-		.platform_data = &cmx270_dm9000_platdata,
-	}
-};
-
-static void __init cmx270_init_dm9000(void)
-{
-	platform_device_register(&cmx270_dm9000_device);
-}
-#else
-static inline void cmx270_init_dm9000(void) {}
-#endif
-
-/* UCB1400 touchscreen controller */
-#if defined(CONFIG_TOUCHSCREEN_UCB1400) || defined(CONFIG_TOUCHSCREEN_UCB1400_MODULE)
-static struct platform_device cmx270_ts_device = {
-	.name		= "ucb1400_ts",
-	.id		= -1,
-};
-
-static void __init cmx270_init_touchscreen(void)
-{
-	platform_device_register(&cmx270_ts_device);
-}
-#else
-static inline void cmx270_init_touchscreen(void) {}
-#endif
-
 /* V3020 RTC */
 #if defined(CONFIG_RTC_DRV_V3020) || defined(CONFIG_RTC_DRV_V3020_MODULE)
 static struct resource cmx270_v3020_resource[] = {
@@ -242,45 +162,7 @@
 	platform_device_register(&cmx270_rtc_device);
 }
 #else
-static inline void cmx270_init_rtc(void) {}
-#endif
-
-/* CM-X270 LEDs */
-#if defined(CONFIG_LEDS_GPIO) || defined(CONFIG_LEDS_GPIO_MODULE)
-static struct gpio_led cmx270_leds[] = {
-	[0] = {
-		.name = "cm-x270:red",
-		.default_trigger = "nand-disk",
-		.gpio = 93,
-		.active_low = 1,
-	},
-	[1] = {
-		.name = "cm-x270:green",
-		.default_trigger = "heartbeat",
-		.gpio = 94,
-		.active_low = 1,
-	},
-};
-
-static struct gpio_led_platform_data cmx270_gpio_led_pdata = {
-	.num_leds = ARRAY_SIZE(cmx270_leds),
-	.leds = cmx270_leds,
-};
-
-static struct platform_device cmx270_led_device = {
-	.name		= "leds-gpio",
-	.id		= -1,
-	.dev		= {
-		.platform_data = &cmx270_gpio_led_pdata,
-	},
-};
-
-static void __init cmx270_init_leds(void)
-{
-	platform_device_register(&cmx270_led_device);
-}
-#else
-static inline void cmx270_init_leds(void) {}
+static inline void cmx2xx_init_rtc(void) {}
 #endif
 
 /* 2700G graphics */
@@ -373,238 +255,11 @@
 static inline void cmx270_init_2700G(void) {}
 #endif
 
-#if defined(CONFIG_FB_PXA) || defined(CONFIG_FB_PXA_MODULE)
-/*
-  Display definitions
-  keep these for backwards compatibility, although symbolic names (as
-  e.g. in lpd270.c) looks better
-*/
-#define MTYPE_STN320x240	0
-#define MTYPE_TFT640x480	1
-#define MTYPE_CRT640x480	2
-#define MTYPE_CRT800x600	3
-#define MTYPE_TFT320x240	6
-#define MTYPE_STN640x480	7
-
-static struct pxafb_mode_info generic_stn_320x240_mode = {
-	.pixclock	= 76923,
-	.bpp		= 8,
-	.xres		= 320,
-	.yres		= 240,
-	.hsync_len	= 3,
-	.vsync_len	= 2,
-	.left_margin	= 3,
-	.upper_margin	= 0,
-	.right_margin	= 3,
-	.lower_margin	= 0,
-	.sync		= (FB_SYNC_HOR_HIGH_ACT |
-			   FB_SYNC_VERT_HIGH_ACT),
-	.cmap_greyscale = 0,
-};
-
-static struct pxafb_mach_info generic_stn_320x240 = {
-	.modes		= &generic_stn_320x240_mode,
-	.num_modes	= 1,
-	.lccr0		= 0,
-	.lccr3		= (LCCR3_PixClkDiv(0x03) |
-			   LCCR3_Acb(0xff) |
-			   LCCR3_PCP),
-	.cmap_inverse	= 0,
-	.cmap_static	= 0,
-};
-
-static struct pxafb_mode_info generic_tft_640x480_mode = {
-	.pixclock	= 38461,
-	.bpp		= 8,
-	.xres		= 640,
-	.yres		= 480,
-	.hsync_len	= 60,
-	.vsync_len	= 2,
-	.left_margin	= 70,
-	.upper_margin	= 10,
-	.right_margin	= 70,
-	.lower_margin	= 5,
-	.sync		= 0,
-	.cmap_greyscale = 0,
-};
-
-static struct pxafb_mach_info generic_tft_640x480 = {
-	.modes		= &generic_tft_640x480_mode,
-	.num_modes	= 1,
-	.lccr0		= (LCCR0_PAS),
-	.lccr3		= (LCCR3_PixClkDiv(0x01) |
-			   LCCR3_Acb(0xff) |
-			   LCCR3_PCP),
-	.cmap_inverse	= 0,
-	.cmap_static	= 0,
-};
-
-static struct pxafb_mode_info generic_crt_640x480_mode = {
-	.pixclock	= 38461,
-	.bpp		= 8,
-	.xres		= 640,
-	.yres		= 480,
-	.hsync_len	= 63,
-	.vsync_len	= 2,
-	.left_margin	= 81,
-	.upper_margin	= 33,
-	.right_margin	= 16,
-	.lower_margin	= 10,
-	.sync		= (FB_SYNC_HOR_HIGH_ACT |
-			   FB_SYNC_VERT_HIGH_ACT),
-	.cmap_greyscale = 0,
-};
-
-static struct pxafb_mach_info generic_crt_640x480 = {
-	.modes		= &generic_crt_640x480_mode,
-	.num_modes	= 1,
-	.lccr0		= (LCCR0_PAS),
-	.lccr3		= (LCCR3_PixClkDiv(0x01) |
-			   LCCR3_Acb(0xff)),
-	.cmap_inverse	= 0,
-	.cmap_static	= 0,
-};
-
-static struct pxafb_mode_info generic_crt_800x600_mode = {
-	.pixclock	= 28846,
-	.bpp		= 8,
-	.xres		= 800,
-	.yres	  	= 600,
-	.hsync_len	= 63,
-	.vsync_len	= 2,
-	.left_margin	= 26,
-	.upper_margin	= 21,
-	.right_margin	= 26,
-	.lower_margin	= 11,
-	.sync		= (FB_SYNC_HOR_HIGH_ACT |
-			   FB_SYNC_VERT_HIGH_ACT),
-	.cmap_greyscale = 0,
-};
-
-static struct pxafb_mach_info generic_crt_800x600 = {
-	.modes		= &generic_crt_800x600_mode,
-	.num_modes	= 1,
-	.lccr0		= (LCCR0_PAS),
-	.lccr3		= (LCCR3_PixClkDiv(0x02) |
-			   LCCR3_Acb(0xff)),
-	.cmap_inverse	= 0,
-	.cmap_static	= 0,
-};
-
-static struct pxafb_mode_info generic_tft_320x240_mode = {
-	.pixclock	= 134615,
-	.bpp		= 16,
-	.xres		= 320,
-	.yres		= 240,
-	.hsync_len	= 63,
-	.vsync_len	= 7,
-	.left_margin	= 75,
-	.upper_margin	= 0,
-	.right_margin	= 15,
-	.lower_margin	= 15,
-	.sync		= 0,
-	.cmap_greyscale = 0,
-};
-
-static struct pxafb_mach_info generic_tft_320x240 = {
-	.modes		= &generic_tft_320x240_mode,
-	.num_modes	= 1,
-	.lccr0		= (LCCR0_PAS),
-	.lccr3		= (LCCR3_PixClkDiv(0x06) |
-			   LCCR3_Acb(0xff) |
-			   LCCR3_PCP),
-	.cmap_inverse	= 0,
-	.cmap_static	= 0,
-};
-
-static struct pxafb_mode_info generic_stn_640x480_mode = {
-	.pixclock	= 57692,
-	.bpp		= 8,
-	.xres		= 640,
-	.yres		= 480,
-	.hsync_len	= 4,
-	.vsync_len	= 2,
-	.left_margin	= 10,
-	.upper_margin	= 5,
-	.right_margin	= 10,
-	.lower_margin	= 5,
-	.sync		= (FB_SYNC_HOR_HIGH_ACT |
-			   FB_SYNC_VERT_HIGH_ACT),
-	.cmap_greyscale = 0,
-};
-
-static struct pxafb_mach_info generic_stn_640x480 = {
-	.modes		= &generic_stn_640x480_mode,
-	.num_modes	= 1,
-	.lccr0		= 0,
-	.lccr3		= (LCCR3_PixClkDiv(0x02) |
-			   LCCR3_Acb(0xff)),
-	.cmap_inverse	= 0,
-	.cmap_static	= 0,
-};
-
-static struct pxafb_mach_info *cmx270_display = &generic_crt_640x480;
-
-static int __init cmx270_set_display(char *str)
-{
-	int disp_type = simple_strtol(str, NULL, 0);
-	switch (disp_type) {
-	case MTYPE_STN320x240:
-		cmx270_display = &generic_stn_320x240;
-		break;
-	case MTYPE_TFT640x480:
-		cmx270_display = &generic_tft_640x480;
-		break;
-	case MTYPE_CRT640x480:
-		cmx270_display = &generic_crt_640x480;
-		break;
-	case MTYPE_CRT800x600:
-		cmx270_display = &generic_crt_800x600;
-		break;
-	case MTYPE_TFT320x240:
-		cmx270_display = &generic_tft_320x240;
-		break;
-	case MTYPE_STN640x480:
-		cmx270_display = &generic_stn_640x480;
-		break;
-	default: /* fallback to CRT 640x480 */
-		cmx270_display = &generic_crt_640x480;
-		break;
-	}
-	return 1;
-}
-
-/*
-   This should be done really early to get proper configuration for
-   frame buffer.
-   Indeed, pxafb parameters can be used istead, but CM-X270 bootloader
-   has limitied line length for kernel command line, and also it will
-   break compatibitlty with proprietary releases already in field.
-*/
-__setup("monitor=", cmx270_set_display);
-
-static void __init cmx270_init_display(void)
-{
-	set_pxa_fb_info(cmx270_display);
-}
-#else
-static inline void cmx270_init_display(void) {}
-#endif
-
 /* PXA27x OHCI controller setup */
 #if defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE)
-static int cmx270_ohci_init(struct device *dev)
-{
-	/* Set the Power Control Polarity Low */
-	UHCHR = (UHCHR | UHCHR_PCPL) &
-		~(UHCHR_SSEP1 | UHCHR_SSEP2 | UHCHR_SSE);
-
-	return 0;
-}
-
 static struct pxaohci_platform_data cmx270_ohci_platform_data = {
 	.port_mode	= PMM_PERPORT_MODE,
-	.init		= cmx270_ohci_init,
+	.flags		= ENABLE_PORT1 | ENABLE_PORT2 | POWER_CONTROL_LOW,
 };
 
 static void __init cmx270_init_ohci(void)
@@ -676,131 +331,12 @@
 static inline void cmx270_init_mmc(void) {}
 #endif
 
-#ifdef CONFIG_PM
-static unsigned long sleep_save_msc[10];
-
-static int cmx270_suspend(struct sys_device *dev, pm_message_t state)
+void __init cmx270_init(void)
 {
-	cmx270_pci_suspend();
-
-	/* save MSC registers */
-	sleep_save_msc[0] = MSC0;
-	sleep_save_msc[1] = MSC1;
-	sleep_save_msc[2] = MSC2;
-
-	/* setup power saving mode registers */
-	PCFR = 0x0;
-	PSLR = 0xff400000;
-	PMCR  = 0x00000005;
-	PWER  = 0x80000000;
-	PFER  = 0x00000000;
-	PRER  = 0x00000000;
-	PGSR0 = 0xC0018800;
-	PGSR1 = 0x004F0002;
-	PGSR2 = 0x6021C000;
-	PGSR3 = 0x00020000;
-
-	return 0;
-}
-
-static int cmx270_resume(struct sys_device *dev)
-{
-	cmx270_pci_resume();
-
-	/* restore MSC registers */
-	MSC0 = sleep_save_msc[0];
-	MSC1 = sleep_save_msc[1];
-	MSC2 = sleep_save_msc[2];
-
-	return 0;
-}
-
-static struct sysdev_class cmx270_pm_sysclass = {
-	.name = "pm",
-	.resume = cmx270_resume,
-	.suspend = cmx270_suspend,
-};
-
-static struct sys_device cmx270_pm_device = {
-	.cls = &cmx270_pm_sysclass,
-};
-
-static int __init cmx270_pm_init(void)
-{
-	int error;
-	error = sysdev_class_register(&cmx270_pm_sysclass);
-	if (error == 0)
-		error = sysdev_register(&cmx270_pm_device);
-	return error;
-}
-#else
-static int __init cmx270_pm_init(void) { return 0; }
-#endif
-
-#if defined(CONFIG_SND_PXA2XX_AC97) || defined(CONFIG_SND_PXA2XX_AC97_MODULE)
-static void __init cmx270_init_ac97(void)
-{
-	pxa_set_ac97_info(NULL);
-}
-#else
-static inline void cmx270_init_ac97(void) {}
-#endif
-
-static void __init cmx270_init(void)
-{
-	cmx270_pm_init();
-
 	pxa2xx_mfp_config(ARRAY_AND_SIZE(cmx270_pin_config));
 
-	cmx270_init_dm9000();
 	cmx270_init_rtc();
-	cmx270_init_display();
 	cmx270_init_mmc();
 	cmx270_init_ohci();
-	cmx270_init_ac97();
-	cmx270_init_touchscreen();
-	cmx270_init_leds();
 	cmx270_init_2700G();
 }
-
-static void __init cmx270_init_irq(void)
-{
-	pxa27x_init_irq();
-
-	cmx270_pci_init_irq(GPIO22_IT8152_IRQ);
-}
-
-#ifdef CONFIG_PCI
-/* Map PCI companion statically */
-static struct map_desc cmx270_io_desc[] __initdata = {
-	[0] = { /* PCI bridge */
-		.virtual	= CMX270_IT8152_VIRT,
-		.pfn		= __phys_to_pfn(PXA_CS4_PHYS),
-		.length		= SZ_64M,
-		.type		= MT_DEVICE
-	},
-};
-
-static void __init cmx270_map_io(void)
-{
-	pxa_map_io();
-	iotable_init(cmx270_io_desc, ARRAY_SIZE(cmx270_io_desc));
-
-	it8152_base_address = CMX270_IT8152_VIRT;
-}
-#else
-static void __init cmx270_map_io(void)
-{
-	pxa_map_io();
-}
-#endif
-
-MACHINE_START(ARMCORE, "Compulab CM-x270")
-	.boot_params	= 0xa0000100,
-	.phys_io	= 0x40000000,
-	.io_pg_offst	= (io_p2v(0x40000000) >> 18) & 0xfffc,
-	.map_io		= cmx270_map_io,
-	.init_irq	= cmx270_init_irq,
-	.timer		= &pxa_timer,
-	.init_machine	= cmx270_init,
-MACHINE_END
diff --git a/arch/arm/mach-pxa/cm-x2xx-pci.c b/arch/arm/mach-pxa/cm-x2xx-pci.c
new file mode 100644
index 0000000..3156b25
--- /dev/null
+++ b/arch/arm/mach-pxa/cm-x2xx-pci.c
@@ -0,0 +1,224 @@
+/*
+ * linux/arch/arm/mach-pxa/cm-x2xx-pci.c
+ *
+ * PCI bios-type initialisation for PCI machines
+ *
+ * Bits taken from various places.
+ *
+ * Copyright (C) 2007, 2008 Compulab, Ltd.
+ * Mike Rapoport <mike@compulab.co.il>
+ *
+ * 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/kernel.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/irq.h>
+#include <linux/gpio.h>
+
+#include <asm/mach/pci.h>
+#include <mach/pxa-regs.h>
+#include <asm/mach-types.h>
+
+#include <asm/hardware/it8152.h>
+
+unsigned long it8152_base_address;
+static int cmx2xx_it8152_irq_gpio;
+
+/*
+ * Only first 64MB of memory can be accessed via PCI.
+ * We use GFP_DMA to allocate safe buffers to do map/unmap.
+ * This is really ugly and we need a better way of specifying
+ * DMA-capable regions of memory.
+ */
+void __init cmx2xx_pci_adjust_zones(int node, unsigned long *zone_size,
+	unsigned long *zhole_size)
+{
+	unsigned int sz = SZ_64M >> PAGE_SHIFT;
+
+	if (machine_is_armcore()) {
+		pr_info("Adjusting zones for CM-X2XX\n");
+
+		/*
+		 * Only adjust if > 64M on current system
+		 */
+		if (node || (zone_size[0] <= sz))
+			return;
+
+		zone_size[1] = zone_size[0] - sz;
+		zone_size[0] = sz;
+		zhole_size[1] = zhole_size[0];
+		zhole_size[0] = 0;
+	}
+}
+
+static void cmx2xx_it8152_irq_demux(unsigned int irq, struct irq_desc *desc)
+{
+	/* clear our parent irq */
+	GEDR(cmx2xx_it8152_irq_gpio) = GPIO_bit(cmx2xx_it8152_irq_gpio);
+
+	it8152_irq_demux(irq, desc);
+}
+
+void __cmx2xx_pci_init_irq(int irq_gpio)
+{
+	it8152_init_irq();
+
+	cmx2xx_it8152_irq_gpio = irq_gpio;
+
+	set_irq_type(gpio_to_irq(irq_gpio), IRQ_TYPE_EDGE_RISING);
+
+	set_irq_chained_handler(gpio_to_irq(irq_gpio), cmx2xx_it8152_irq_demux);
+}
+
+#ifdef CONFIG_PM
+static unsigned long sleep_save_ite[10];
+
+void __cmx2xx_pci_suspend(void)
+{
+	/* save ITE state */
+	sleep_save_ite[0] = __raw_readl(IT8152_INTC_PDCNIMR);
+	sleep_save_ite[1] = __raw_readl(IT8152_INTC_LPCNIMR);
+	sleep_save_ite[2] = __raw_readl(IT8152_INTC_LPNIAR);
+
+	/* Clear ITE IRQ's */
+	__raw_writel((0), IT8152_INTC_PDCNIRR);
+	__raw_writel((0), IT8152_INTC_LPCNIRR);
+}
+
+void __cmx2xx_pci_resume(void)
+{
+	/* restore IT8152 state */
+	__raw_writel((sleep_save_ite[0]), IT8152_INTC_PDCNIMR);
+	__raw_writel((sleep_save_ite[1]), IT8152_INTC_LPCNIMR);
+	__raw_writel((sleep_save_ite[2]), IT8152_INTC_LPNIAR);
+}
+#else
+void cmx2xx_pci_suspend(void) {}
+void cmx2xx_pci_resume(void) {}
+#endif
+
+/* PCI IRQ mapping*/
+static int __init cmx2xx_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+{
+	int irq;
+
+	dev_dbg(&dev->dev, "%s: slot=%x, pin=%x\n", __func__, slot, pin);
+
+	irq = it8152_pci_map_irq(dev, slot, pin);
+	if (irq)
+		return irq;
+
+	/*
+	  Here comes the ugly part. The routing is baseboard specific,
+	  but defining a platform for each possible base of CM-X2XX is
+	  unrealistic. Here we keep mapping for ATXBase and SB-X2XX.
+	*/
+	/* ATXBASE PCI slot */
+	if (slot == 7)
+		return IT8152_PCI_INTA;
+
+	/* ATXBase/SB-X2XX CardBus */
+	if (slot == 8 || slot == 0)
+		return IT8152_PCI_INTB;
+
+	/* ATXBase Ethernet */
+	if (slot == 9)
+		return IT8152_PCI_INTA;
+
+	/* CM-x255 Onboard Ethernet */
+	if (slot == 15)
+		return IT8152_PCI_INTC;
+
+	/* SB-x2xx Ethernet */
+	if (slot == 16)
+		return IT8152_PCI_INTA;
+
+	/* PC104+ interrupt routing */
+	if ((slot == 17) || (slot == 19))
+		return IT8152_PCI_INTA;
+	if ((slot == 18) || (slot == 20))
+		return IT8152_PCI_INTB;
+
+	return(0);
+}
+
+static void cmx2xx_pci_preinit(void)
+{
+	pr_info("Initializing CM-X2XX PCI subsystem\n");
+
+	__raw_writel(0x800, IT8152_PCI_CFG_ADDR);
+	if (__raw_readl(IT8152_PCI_CFG_DATA) == 0x81521283) {
+		pr_info("PCI Bridge found.\n");
+
+		/* set PCI I/O base at 0 */
+		writel(0x848, IT8152_PCI_CFG_ADDR);
+		writel(0, IT8152_PCI_CFG_DATA);
+
+		/* set PCI memory base at 0 */
+		writel(0x840, IT8152_PCI_CFG_ADDR);
+		writel(0, IT8152_PCI_CFG_DATA);
+
+		writel(0x20, IT8152_GPIO_GPDR);
+
+		/* CardBus Controller on ATXbase baseboard */
+		writel(0x4000, IT8152_PCI_CFG_ADDR);
+		if (readl(IT8152_PCI_CFG_DATA) == 0xAC51104C) {
+			pr_info("CardBus Bridge found.\n");
+
+			/* Configure socket 0 */
+			writel(0x408C, IT8152_PCI_CFG_ADDR);
+			writel(0x1022, IT8152_PCI_CFG_DATA);
+
+			writel(0x4080, IT8152_PCI_CFG_ADDR);
+			writel(0x3844d060, IT8152_PCI_CFG_DATA);
+
+			writel(0x4090, IT8152_PCI_CFG_ADDR);
+			writel(((readl(IT8152_PCI_CFG_DATA) & 0xffff) |
+				0x60440000),
+			       IT8152_PCI_CFG_DATA);
+
+			writel(0x4018, IT8152_PCI_CFG_ADDR);
+			writel(0xb0000000, IT8152_PCI_CFG_DATA);
+
+			/* Configure socket 1 */
+			writel(0x418C, IT8152_PCI_CFG_ADDR);
+			writel(0x1022, IT8152_PCI_CFG_DATA);
+
+			writel(0x4180, IT8152_PCI_CFG_ADDR);
+			writel(0x3844d060, IT8152_PCI_CFG_DATA);
+
+			writel(0x4190, IT8152_PCI_CFG_ADDR);
+			writel(((readl(IT8152_PCI_CFG_DATA) & 0xffff) |
+				0x60440000),
+			       IT8152_PCI_CFG_DATA);
+
+			writel(0x4118, IT8152_PCI_CFG_ADDR);
+			writel(0xb0000000, IT8152_PCI_CFG_DATA);
+		}
+	}
+}
+
+static struct hw_pci cmx2xx_pci __initdata = {
+	.swizzle	= pci_std_swizzle,
+	.map_irq	= cmx2xx_pci_map_irq,
+	.nr_controllers	= 1,
+	.setup		= it8152_pci_setup,
+	.scan		= it8152_pci_scan_bus,
+	.preinit	= cmx2xx_pci_preinit,
+};
+
+static int __init cmx2xx_init_pci(void)
+{
+	if (machine_is_armcore())
+		pci_common_init(&cmx2xx_pci);
+
+	return 0;
+}
+
+subsys_initcall(cmx2xx_init_pci);
diff --git a/arch/arm/mach-pxa/cm-x2xx-pci.h b/arch/arm/mach-pxa/cm-x2xx-pci.h
new file mode 100644
index 0000000..e24aad2
--- /dev/null
+++ b/arch/arm/mach-pxa/cm-x2xx-pci.h
@@ -0,0 +1,13 @@
+extern void __cmx2xx_pci_init_irq(int irq_gpio);
+extern void __cmx2xx_pci_suspend(void);
+extern void __cmx2xx_pci_resume(void);
+
+#ifdef CONFIG_PCI
+#define cmx2xx_pci_init_irq(x) __cmx2xx_pci_init_irq(x)
+#define cmx2xx_pci_suspend(x) __cmx2xx_pci_suspend(x)
+#define cmx2xx_pci_resume(x) __cmx2xx_pci_resume(x)
+#else
+#define cmx2xx_pci_init_irq(x) do {} while (0)
+#define cmx2xx_pci_suspend(x) do {} while (0)
+#define cmx2xx_pci_resume(x) do {} while (0)
+#endif
diff --git a/arch/arm/mach-pxa/cm-x2xx.c b/arch/arm/mach-pxa/cm-x2xx.c
new file mode 100644
index 0000000..0b3ce3b
--- /dev/null
+++ b/arch/arm/mach-pxa/cm-x2xx.c
@@ -0,0 +1,531 @@
+/*
+ * linux/arch/arm/mach-pxa/cm-x2xx.c
+ *
+ * Copyright (C) 2008 CompuLab, Ltd.
+ * Mike Rapoport <mike@compulab.co.il>
+ *
+ * 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/platform_device.h>
+#include <linux/sysdev.h>
+#include <linux/irq.h>
+#include <linux/gpio.h>
+
+#include <linux/dm9000.h>
+#include <linux/leds.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach-types.h>
+#include <asm/mach/map.h>
+
+#include <mach/pxa2xx-regs.h>
+#include <mach/mfp-pxa27x.h>
+#include <mach/pxa-regs.h>
+#include <mach/audio.h>
+#include <mach/pxafb.h>
+
+#include <asm/hardware/it8152.h>
+
+#include "generic.h"
+#include "cm-x2xx-pci.h"
+
+extern void cmx255_init(void);
+extern void cmx270_init(void);
+
+/* virtual addresses for statically mapped regions */
+#define CMX2XX_VIRT_BASE	(0xe8000000)
+#define CMX2XX_IT8152_VIRT	(CMX2XX_VIRT_BASE)
+
+/* physical address if local-bus attached devices */
+#define CMX255_DM9000_PHYS_BASE (PXA_CS1_PHYS + (8 << 22))
+#define CMX270_DM9000_PHYS_BASE	(PXA_CS1_PHYS + (6 << 22))
+
+/* leds */
+#define CMX255_GPIO_RED		(27)
+#define CMX255_GPIO_GREEN	(32)
+#define CMX270_GPIO_RED		(93)
+#define CMX270_GPIO_GREEN	(94)
+
+/* GPIO IRQ usage */
+#define GPIO22_ETHIRQ		(22)
+#define GPIO10_ETHIRQ		(10)
+#define CMX255_GPIO_IT8152_IRQ	(0)
+#define CMX270_GPIO_IT8152_IRQ	(22)
+
+#define CMX255_ETHIRQ		IRQ_GPIO(GPIO22_ETHIRQ)
+#define CMX270_ETHIRQ		IRQ_GPIO(GPIO10_ETHIRQ)
+
+#if defined(CONFIG_DM9000) || defined(CONFIG_DM9000_MODULE)
+static struct resource cmx255_dm9000_resource[] = {
+	[0] = {
+		.start = CMX255_DM9000_PHYS_BASE,
+		.end   = CMX255_DM9000_PHYS_BASE + 3,
+		.flags = IORESOURCE_MEM,
+	},
+	[1] = {
+		.start = CMX255_DM9000_PHYS_BASE + 4,
+		.end   = CMX255_DM9000_PHYS_BASE + 4 + 500,
+		.flags = IORESOURCE_MEM,
+	},
+	[2] = {
+		.start = CMX255_ETHIRQ,
+		.end   = CMX255_ETHIRQ,
+		.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE,
+	}
+};
+
+static struct resource cmx270_dm9000_resource[] = {
+	[0] = {
+		.start = CMX270_DM9000_PHYS_BASE,
+		.end   = CMX270_DM9000_PHYS_BASE + 3,
+		.flags = IORESOURCE_MEM,
+	},
+	[1] = {
+		.start = CMX270_DM9000_PHYS_BASE + 8,
+		.end   = CMX270_DM9000_PHYS_BASE + 8 + 500,
+		.flags = IORESOURCE_MEM,
+	},
+	[2] = {
+		.start = CMX270_ETHIRQ,
+		.end   = CMX270_ETHIRQ,
+		.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE,
+	}
+};
+
+static struct dm9000_plat_data cmx270_dm9000_platdata = {
+	.flags		= DM9000_PLATF_32BITONLY,
+};
+
+static struct platform_device cmx2xx_dm9000_device = {
+	.name		= "dm9000",
+	.id		= 0,
+	.num_resources	= ARRAY_SIZE(cmx270_dm9000_resource),
+	.dev		= {
+		.platform_data = &cmx270_dm9000_platdata,
+	}
+};
+
+static void __init cmx2xx_init_dm9000(void)
+{
+	if (cpu_is_pxa25x())
+		cmx2xx_dm9000_device.resource = cmx255_dm9000_resource;
+	else
+		cmx2xx_dm9000_device.resource = cmx270_dm9000_resource;
+	platform_device_register(&cmx2xx_dm9000_device);
+}
+#else
+static inline void cmx2xx_init_dm9000(void) {}
+#endif
+
+/* UCB1400 touchscreen controller */
+#if defined(CONFIG_TOUCHSCREEN_UCB1400) || defined(CONFIG_TOUCHSCREEN_UCB1400_MODULE)
+static struct platform_device cmx2xx_ts_device = {
+	.name		= "ucb1400_ts",
+	.id		= -1,
+};
+
+static void __init cmx2xx_init_touchscreen(void)
+{
+	platform_device_register(&cmx2xx_ts_device);
+}
+#else
+static inline void cmx2xx_init_touchscreen(void) {}
+#endif
+
+/* CM-X270 LEDs */
+#if defined(CONFIG_LEDS_GPIO) || defined(CONFIG_LEDS_GPIO_MODULE)
+static struct gpio_led cmx2xx_leds[] = {
+	[0] = {
+		.name = "cm-x2xx:red",
+		.default_trigger = "nand-disk",
+		.active_low = 1,
+	},
+	[1] = {
+		.name = "cm-x2xx:green",
+		.default_trigger = "heartbeat",
+		.active_low = 1,
+	},
+};
+
+static struct gpio_led_platform_data cmx2xx_gpio_led_pdata = {
+	.num_leds = ARRAY_SIZE(cmx2xx_leds),
+	.leds = cmx2xx_leds,
+};
+
+static struct platform_device cmx2xx_led_device = {
+	.name		= "leds-gpio",
+	.id		= -1,
+	.dev		= {
+		.platform_data = &cmx2xx_gpio_led_pdata,
+	},
+};
+
+static void __init cmx2xx_init_leds(void)
+{
+	if (cpu_is_pxa25x()) {
+		cmx2xx_leds[0].gpio = CMX255_GPIO_RED;
+		cmx2xx_leds[1].gpio = CMX255_GPIO_GREEN;
+	} else {
+		cmx2xx_leds[0].gpio = CMX270_GPIO_RED;
+		cmx2xx_leds[1].gpio = CMX270_GPIO_GREEN;
+	}
+	platform_device_register(&cmx2xx_led_device);
+}
+#else
+static inline void cmx2xx_init_leds(void) {}
+#endif
+
+#if defined(CONFIG_FB_PXA) || defined(CONFIG_FB_PXA_MODULE)
+/*
+  Display definitions
+  keep these for backwards compatibility, although symbolic names (as
+  e.g. in lpd270.c) looks better
+*/
+#define MTYPE_STN320x240	0
+#define MTYPE_TFT640x480	1
+#define MTYPE_CRT640x480	2
+#define MTYPE_CRT800x600	3
+#define MTYPE_TFT320x240	6
+#define MTYPE_STN640x480	7
+
+static struct pxafb_mode_info generic_stn_320x240_mode = {
+	.pixclock	= 76923,
+	.bpp		= 8,
+	.xres		= 320,
+	.yres		= 240,
+	.hsync_len	= 3,
+	.vsync_len	= 2,
+	.left_margin	= 3,
+	.upper_margin	= 0,
+	.right_margin	= 3,
+	.lower_margin	= 0,
+	.sync		= (FB_SYNC_HOR_HIGH_ACT |
+			   FB_SYNC_VERT_HIGH_ACT),
+	.cmap_greyscale = 0,
+};
+
+static struct pxafb_mach_info generic_stn_320x240 = {
+	.modes		= &generic_stn_320x240_mode,
+	.num_modes	= 1,
+	.lccr0		= 0,
+	.lccr3		= (LCCR3_PixClkDiv(0x03) |
+			   LCCR3_Acb(0xff) |
+			   LCCR3_PCP),
+	.cmap_inverse	= 0,
+	.cmap_static	= 0,
+};
+
+static struct pxafb_mode_info generic_tft_640x480_mode = {
+	.pixclock	= 38461,
+	.bpp		= 8,
+	.xres		= 640,
+	.yres		= 480,
+	.hsync_len	= 60,
+	.vsync_len	= 2,
+	.left_margin	= 70,
+	.upper_margin	= 10,
+	.right_margin	= 70,
+	.lower_margin	= 5,
+	.sync		= 0,
+	.cmap_greyscale = 0,
+};
+
+static struct pxafb_mach_info generic_tft_640x480 = {
+	.modes		= &generic_tft_640x480_mode,
+	.num_modes	= 1,
+	.lccr0		= (LCCR0_PAS),
+	.lccr3		= (LCCR3_PixClkDiv(0x01) |
+			   LCCR3_Acb(0xff) |
+			   LCCR3_PCP),
+	.cmap_inverse	= 0,
+	.cmap_static	= 0,
+};
+
+static struct pxafb_mode_info generic_crt_640x480_mode = {
+	.pixclock	= 38461,
+	.bpp		= 8,
+	.xres		= 640,
+	.yres		= 480,
+	.hsync_len	= 63,
+	.vsync_len	= 2,
+	.left_margin	= 81,
+	.upper_margin	= 33,
+	.right_margin	= 16,
+	.lower_margin	= 10,
+	.sync		= (FB_SYNC_HOR_HIGH_ACT |
+			   FB_SYNC_VERT_HIGH_ACT),
+	.cmap_greyscale = 0,
+};
+
+static struct pxafb_mach_info generic_crt_640x480 = {
+	.modes		= &generic_crt_640x480_mode,
+	.num_modes	= 1,
+	.lccr0		= (LCCR0_PAS),
+	.lccr3		= (LCCR3_PixClkDiv(0x01) |
+			   LCCR3_Acb(0xff)),
+	.cmap_inverse	= 0,
+	.cmap_static	= 0,
+};
+
+static struct pxafb_mode_info generic_crt_800x600_mode = {
+	.pixclock	= 28846,
+	.bpp		= 8,
+	.xres		= 800,
+	.yres	  	= 600,
+	.hsync_len	= 63,
+	.vsync_len	= 2,
+	.left_margin	= 26,
+	.upper_margin	= 21,
+	.right_margin	= 26,
+	.lower_margin	= 11,
+	.sync		= (FB_SYNC_HOR_HIGH_ACT |
+			   FB_SYNC_VERT_HIGH_ACT),
+	.cmap_greyscale = 0,
+};
+
+static struct pxafb_mach_info generic_crt_800x600 = {
+	.modes		= &generic_crt_800x600_mode,
+	.num_modes	= 1,
+	.lccr0		= (LCCR0_PAS),
+	.lccr3		= (LCCR3_PixClkDiv(0x02) |
+			   LCCR3_Acb(0xff)),
+	.cmap_inverse	= 0,
+	.cmap_static	= 0,
+};
+
+static struct pxafb_mode_info generic_tft_320x240_mode = {
+	.pixclock	= 134615,
+	.bpp		= 16,
+	.xres		= 320,
+	.yres		= 240,
+	.hsync_len	= 63,
+	.vsync_len	= 7,
+	.left_margin	= 75,
+	.upper_margin	= 0,
+	.right_margin	= 15,
+	.lower_margin	= 15,
+	.sync		= 0,
+	.cmap_greyscale = 0,
+};
+
+static struct pxafb_mach_info generic_tft_320x240 = {
+	.modes		= &generic_tft_320x240_mode,
+	.num_modes	= 1,
+	.lccr0		= (LCCR0_PAS),
+	.lccr3		= (LCCR3_PixClkDiv(0x06) |
+			   LCCR3_Acb(0xff) |
+			   LCCR3_PCP),
+	.cmap_inverse	= 0,
+	.cmap_static	= 0,
+};
+
+static struct pxafb_mode_info generic_stn_640x480_mode = {
+	.pixclock	= 57692,
+	.bpp		= 8,
+	.xres		= 640,
+	.yres		= 480,
+	.hsync_len	= 4,
+	.vsync_len	= 2,
+	.left_margin	= 10,
+	.upper_margin	= 5,
+	.right_margin	= 10,
+	.lower_margin	= 5,
+	.sync		= (FB_SYNC_HOR_HIGH_ACT |
+			   FB_SYNC_VERT_HIGH_ACT),
+	.cmap_greyscale = 0,
+};
+
+static struct pxafb_mach_info generic_stn_640x480 = {
+	.modes		= &generic_stn_640x480_mode,
+	.num_modes	= 1,
+	.lccr0		= 0,
+	.lccr3		= (LCCR3_PixClkDiv(0x02) |
+			   LCCR3_Acb(0xff)),
+	.cmap_inverse	= 0,
+	.cmap_static	= 0,
+};
+
+static struct pxafb_mach_info *cmx2xx_display = &generic_crt_640x480;
+
+static int __init cmx2xx_set_display(char *str)
+{
+	int disp_type = simple_strtol(str, NULL, 0);
+	switch (disp_type) {
+	case MTYPE_STN320x240:
+		cmx2xx_display = &generic_stn_320x240;
+		break;
+	case MTYPE_TFT640x480:
+		cmx2xx_display = &generic_tft_640x480;
+		break;
+	case MTYPE_CRT640x480:
+		cmx2xx_display = &generic_crt_640x480;
+		break;
+	case MTYPE_CRT800x600:
+		cmx2xx_display = &generic_crt_800x600;
+		break;
+	case MTYPE_TFT320x240:
+		cmx2xx_display = &generic_tft_320x240;
+		break;
+	case MTYPE_STN640x480:
+		cmx2xx_display = &generic_stn_640x480;
+		break;
+	default: /* fallback to CRT 640x480 */
+		cmx2xx_display = &generic_crt_640x480;
+		break;
+	}
+	return 1;
+}
+
+/*
+   This should be done really early to get proper configuration for
+   frame buffer.
+   Indeed, pxafb parameters can be used istead, but CM-X2XX bootloader
+   has limitied line length for kernel command line, and also it will
+   break compatibitlty with proprietary releases already in field.
+*/
+__setup("monitor=", cmx2xx_set_display);
+
+static void __init cmx2xx_init_display(void)
+{
+	set_pxa_fb_info(cmx2xx_display);
+}
+#else
+static inline void cmx2xx_init_display(void) {}
+#endif
+
+#ifdef CONFIG_PM
+static unsigned long sleep_save_msc[10];
+
+static int cmx2xx_suspend(struct sys_device *dev, pm_message_t state)
+{
+	cmx2xx_pci_suspend();
+
+	/* save MSC registers */
+	sleep_save_msc[0] = MSC0;
+	sleep_save_msc[1] = MSC1;
+	sleep_save_msc[2] = MSC2;
+
+	/* setup power saving mode registers */
+	PCFR = 0x0;
+	PSLR = 0xff400000;
+	PMCR  = 0x00000005;
+	PWER  = 0x80000000;
+	PFER  = 0x00000000;
+	PRER  = 0x00000000;
+	PGSR0 = 0xC0018800;
+	PGSR1 = 0x004F0002;
+	PGSR2 = 0x6021C000;
+	PGSR3 = 0x00020000;
+
+	return 0;
+}
+
+static int cmx2xx_resume(struct sys_device *dev)
+{
+	cmx2xx_pci_resume();
+
+	/* restore MSC registers */
+	MSC0 = sleep_save_msc[0];
+	MSC1 = sleep_save_msc[1];
+	MSC2 = sleep_save_msc[2];
+
+	return 0;
+}
+
+static struct sysdev_class cmx2xx_pm_sysclass = {
+	.name = "pm",
+	.resume = cmx2xx_resume,
+	.suspend = cmx2xx_suspend,
+};
+
+static struct sys_device cmx2xx_pm_device = {
+	.cls = &cmx2xx_pm_sysclass,
+};
+
+static int __init cmx2xx_pm_init(void)
+{
+	int error;
+	error = sysdev_class_register(&cmx2xx_pm_sysclass);
+	if (error == 0)
+		error = sysdev_register(&cmx2xx_pm_device);
+	return error;
+}
+#else
+static int __init cmx2xx_pm_init(void) { return 0; }
+#endif
+
+#if defined(CONFIG_SND_PXA2XX_AC97) || defined(CONFIG_SND_PXA2XX_AC97_MODULE)
+static void __init cmx2xx_init_ac97(void)
+{
+	pxa_set_ac97_info(NULL);
+}
+#else
+static inline void cmx2xx_init_ac97(void) {}
+#endif
+
+static void __init cmx2xx_init(void)
+{
+	cmx2xx_pm_init();
+
+	if (cpu_is_pxa25x())
+		cmx255_init();
+	else
+		cmx270_init();
+
+	cmx2xx_init_dm9000();
+	cmx2xx_init_display();
+	cmx2xx_init_ac97();
+	cmx2xx_init_touchscreen();
+	cmx2xx_init_leds();
+}
+
+static void __init cmx2xx_init_irq(void)
+{
+	pxa27x_init_irq();
+
+	if (cpu_is_pxa25x()) {
+		pxa25x_init_irq();
+		cmx2xx_pci_init_irq(CMX255_GPIO_IT8152_IRQ);
+	} else {
+		pxa27x_init_irq();
+		cmx2xx_pci_init_irq(CMX270_GPIO_IT8152_IRQ);
+	}
+}
+
+#ifdef CONFIG_PCI
+/* Map PCI companion statically */
+static struct map_desc cmx2xx_io_desc[] __initdata = {
+	[0] = { /* PCI bridge */
+		.virtual	= CMX2XX_IT8152_VIRT,
+		.pfn		= __phys_to_pfn(PXA_CS4_PHYS),
+		.length		= SZ_64M,
+		.type		= MT_DEVICE
+	},
+};
+
+static void __init cmx2xx_map_io(void)
+{
+	pxa_map_io();
+	iotable_init(cmx2xx_io_desc, ARRAY_SIZE(cmx2xx_io_desc));
+
+	it8152_base_address = CMX2XX_IT8152_VIRT;
+}
+#else
+static void __init cmx2xx_map_io(void)
+{
+	pxa_map_io();
+}
+#endif
+
+MACHINE_START(ARMCORE, "Compulab CM-X2XX")
+	.boot_params	= 0xa0000100,
+	.phys_io	= 0x40000000,
+	.io_pg_offst	= (io_p2v(0x40000000) >> 18) & 0xfffc,
+	.map_io		= cmx2xx_map_io,
+	.init_irq	= cmx2xx_init_irq,
+	.timer		= &pxa_timer,
+	.init_machine	= cmx2xx_init,
+MACHINE_END
diff --git a/arch/arm/mach-pxa/cm-x300.c b/arch/arm/mach-pxa/cm-x300.c
new file mode 100644
index 0000000..deb46cd
--- /dev/null
+++ b/arch/arm/mach-pxa/cm-x300.c
@@ -0,0 +1,465 @@
+/*
+ * linux/arch/arm/mach-pxa/cm-x300.c
+ *
+ * Support for the CompuLab CM-X300 modules
+ *
+ * Copyright (C) 2008 CompuLab Ltd.
+ *
+ * Mike Rapoport <mike@compulab.co.il>
+ *
+ * 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/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+
+#include <linux/gpio.h>
+#include <linux/dm9000.h>
+#include <linux/leds.h>
+
+#include <linux/i2c.h>
+#include <linux/i2c/pca953x.h>
+
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+
+#include <mach/mfp-pxa300.h>
+
+#include <mach/hardware.h>
+#include <mach/gpio.h>
+#include <mach/pxafb.h>
+#include <mach/mmc.h>
+#include <mach/ohci.h>
+#include <mach/i2c.h>
+#include <mach/pxa3xx_nand.h>
+
+#include <asm/mach/map.h>
+
+#include "generic.h"
+
+#define CM_X300_ETH_PHYS	0x08000010
+
+#define GPIO82_MMC2_IRQ		(82)
+#define GPIO85_MMC2_WP		(85)
+
+#define	CM_X300_MMC2_IRQ	IRQ_GPIO(GPIO82_MMC2_IRQ)
+
+static mfp_cfg_t cm_x300_mfp_cfg[] __initdata = {
+	/* LCD */
+	GPIO54_LCD_LDD_0,
+	GPIO55_LCD_LDD_1,
+	GPIO56_LCD_LDD_2,
+	GPIO57_LCD_LDD_3,
+	GPIO58_LCD_LDD_4,
+	GPIO59_LCD_LDD_5,
+	GPIO60_LCD_LDD_6,
+	GPIO61_LCD_LDD_7,
+	GPIO62_LCD_LDD_8,
+	GPIO63_LCD_LDD_9,
+	GPIO64_LCD_LDD_10,
+	GPIO65_LCD_LDD_11,
+	GPIO66_LCD_LDD_12,
+	GPIO67_LCD_LDD_13,
+	GPIO68_LCD_LDD_14,
+	GPIO69_LCD_LDD_15,
+	GPIO72_LCD_FCLK,
+	GPIO73_LCD_LCLK,
+	GPIO74_LCD_PCLK,
+	GPIO75_LCD_BIAS,
+
+	/* BTUART */
+	GPIO111_UART2_RTS,
+	GPIO112_UART2_RXD | MFP_LPM_EDGE_FALL,
+	GPIO113_UART2_TXD,
+	GPIO114_UART2_CTS | MFP_LPM_EDGE_BOTH,
+
+	/* STUART */
+	GPIO109_UART3_TXD,
+	GPIO110_UART3_RXD | MFP_LPM_EDGE_FALL,
+
+	/* AC97 */
+	GPIO23_AC97_nACRESET,
+	GPIO24_AC97_SYSCLK,
+	GPIO29_AC97_BITCLK,
+	GPIO25_AC97_SDATA_IN_0,
+	GPIO27_AC97_SDATA_OUT,
+	GPIO28_AC97_SYNC,
+
+	/* Keypad */
+	GPIO115_KP_MKIN_0 | MFP_LPM_EDGE_BOTH,
+	GPIO116_KP_MKIN_1 | MFP_LPM_EDGE_BOTH,
+	GPIO117_KP_MKIN_2 | MFP_LPM_EDGE_BOTH,
+	GPIO118_KP_MKIN_3 | MFP_LPM_EDGE_BOTH,
+	GPIO119_KP_MKIN_4 | MFP_LPM_EDGE_BOTH,
+	GPIO120_KP_MKIN_5 | MFP_LPM_EDGE_BOTH,
+	GPIO2_2_KP_MKIN_6 | MFP_LPM_EDGE_BOTH,
+	GPIO3_2_KP_MKIN_7 | MFP_LPM_EDGE_BOTH,
+	GPIO121_KP_MKOUT_0,
+	GPIO122_KP_MKOUT_1,
+	GPIO123_KP_MKOUT_2,
+	GPIO124_KP_MKOUT_3,
+	GPIO125_KP_MKOUT_4,
+	GPIO4_2_KP_MKOUT_5,
+
+	/* MMC1 */
+	GPIO3_MMC1_DAT0,
+	GPIO4_MMC1_DAT1 | MFP_LPM_EDGE_BOTH,
+	GPIO5_MMC1_DAT2,
+	GPIO6_MMC1_DAT3,
+	GPIO7_MMC1_CLK,
+	GPIO8_MMC1_CMD,	/* CMD0 for slot 0 */
+
+	/* MMC2 */
+	GPIO9_MMC2_DAT0,
+	GPIO10_MMC2_DAT1 | MFP_LPM_EDGE_BOTH,
+	GPIO11_MMC2_DAT2,
+	GPIO12_MMC2_DAT3,
+	GPIO13_MMC2_CLK,
+	GPIO14_MMC2_CMD,
+
+	/* FFUART */
+	GPIO30_UART1_RXD | MFP_LPM_EDGE_FALL,
+	GPIO31_UART1_TXD,
+	GPIO32_UART1_CTS,
+	GPIO37_UART1_RTS,
+	GPIO33_UART1_DCD,
+	GPIO34_UART1_DSR | MFP_LPM_EDGE_FALL,
+	GPIO35_UART1_RI,
+	GPIO36_UART1_DTR,
+
+	/* GPIOs */
+	GPIO79_GPIO,			/* LED */
+	GPIO82_GPIO | MFP_PULL_HIGH,	/* MMC CD */
+	GPIO85_GPIO,			/* MMC WP */
+	GPIO99_GPIO,			/* Ethernet IRQ */
+};
+
+#if defined(CONFIG_DM9000) || defined(CONFIG_DM9000_MODULE)
+static struct resource dm9000_resources[] = {
+	[0] = {
+		.start	= CM_X300_ETH_PHYS,
+		.end	= CM_X300_ETH_PHYS + 0x3,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= CM_X300_ETH_PHYS + 0x4,
+		.end	= CM_X300_ETH_PHYS + 0x4 + 500,
+		.flags	= IORESOURCE_MEM,
+	},
+	[2] = {
+		.start	= IRQ_GPIO(mfp_to_gpio(MFP_PIN_GPIO99)),
+		.end	= IRQ_GPIO(mfp_to_gpio(MFP_PIN_GPIO99)),
+		.flags	= IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE,
+	}
+};
+
+static struct dm9000_plat_data cm_x300_dm9000_platdata = {
+	.flags		= DM9000_PLATF_16BITONLY,
+};
+
+static struct platform_device dm9000_device = {
+	.name		= "dm9000",
+	.id		= 0,
+	.num_resources	= ARRAY_SIZE(dm9000_resources),
+	.resource	= dm9000_resources,
+	.dev		= {
+		.platform_data = &cm_x300_dm9000_platdata,
+	}
+
+};
+
+static void __init cm_x300_init_dm9000(void)
+{
+	platform_device_register(&dm9000_device);
+}
+#else
+static inline void cm_x300_init_dm9000(void) {}
+#endif
+
+#if defined(CONFIG_FB_PXA) || defined(CONFIG_FB_PXA_MODULE)
+static struct pxafb_mode_info cm_x300_lcd_modes[] = {
+	[0] = {
+		.pixclock	= 38000,
+		.bpp		= 16,
+		.xres		= 480,
+		.yres		= 640,
+		.hsync_len	= 8,
+		.vsync_len	= 2,
+		.left_margin	= 8,
+		.upper_margin	= 0,
+		.right_margin	= 24,
+		.lower_margin	= 4,
+		.cmap_greyscale	= 0,
+	},
+	[1] = {
+		.pixclock	= 153800,
+		.bpp		= 16,
+		.xres		= 240,
+		.yres		= 320,
+		.hsync_len	= 8,
+		.vsync_len	= 2,
+		.left_margin	= 8,
+		.upper_margin	= 2,
+		.right_margin	= 88,
+		.lower_margin	= 2,
+		.cmap_greyscale	= 0,
+	},
+};
+
+static struct pxafb_mach_info cm_x300_lcd = {
+	.modes			= cm_x300_lcd_modes,
+	.num_modes		= 2,
+	.lcd_conn		= LCD_COLOR_TFT_16BPP | LCD_PCLK_EDGE_FALL,
+};
+
+static void __init cm_x300_init_lcd(void)
+{
+	set_pxa_fb_info(&cm_x300_lcd);
+}
+#else
+static inline void cm_x300_init_lcd(void) {}
+#endif
+
+#if defined(CONFIG_MTD_NAND_PXA3xx) || defined(CONFIG_MTD_NAND_PXA3xx_MODULE)
+static struct mtd_partition cm_x300_nand_partitions[] = {
+	[0] = {
+		.name        = "OBM",
+		.offset      = 0,
+		.size        = SZ_256K,
+		.mask_flags  = MTD_WRITEABLE, /* force read-only */
+	},
+	[1] = {
+		.name        = "U-Boot",
+		.offset      = MTDPART_OFS_APPEND,
+		.size        = SZ_256K,
+		.mask_flags  = MTD_WRITEABLE, /* force read-only */
+	},
+	[2] = {
+		.name        = "Environment",
+		.offset      = MTDPART_OFS_APPEND,
+		.size        = SZ_256K,
+	},
+	[3] = {
+		.name        = "reserved",
+		.offset      = MTDPART_OFS_APPEND,
+		.size        = SZ_256K + SZ_1M,
+		.mask_flags  = MTD_WRITEABLE, /* force read-only */
+	},
+	[4] = {
+		.name        = "kernel",
+		.offset      = MTDPART_OFS_APPEND,
+		.size        = SZ_4M,
+	},
+	[5] = {
+		.name        = "fs",
+		.offset      = MTDPART_OFS_APPEND,
+		.size        = MTDPART_SIZ_FULL,
+	},
+};
+
+static struct pxa3xx_nand_platform_data cm_x300_nand_info = {
+	.enable_arbiter	= 1,
+	.parts		= cm_x300_nand_partitions,
+	.nr_parts	= ARRAY_SIZE(cm_x300_nand_partitions),
+};
+
+static void __init cm_x300_init_nand(void)
+{
+	pxa3xx_set_nand_info(&cm_x300_nand_info);
+}
+#else
+static inline void cm_x300_init_nand(void) {}
+#endif
+
+#if defined(CONFIG_MMC) || defined(CONFIG_MMC_MODULE)
+/* The first MMC slot of CM-X300 is hardwired to Libertas card and has
+   no detection/ro pins */
+static int cm_x300_mci_init(struct device *dev,
+			    irq_handler_t cm_x300_detect_int,
+			    void *data)
+{
+	return 0;
+}
+
+static void cm_x300_mci_exit(struct device *dev, void *data)
+{
+}
+
+static struct pxamci_platform_data cm_x300_mci_platform_data = {
+	.detect_delay	= 20,
+	.ocr_mask	= MMC_VDD_32_33|MMC_VDD_33_34,
+	.init 		= cm_x300_mci_init,
+	.exit		= cm_x300_mci_exit,
+};
+
+static int cm_x300_mci2_ro(struct device *dev)
+{
+	return gpio_get_value(GPIO85_MMC2_WP);
+}
+
+static int cm_x300_mci2_init(struct device *dev,
+			     irq_handler_t cm_x300_detect_int,
+			     void *data)
+{
+	int err;
+
+	/*
+	 * setup GPIO for CM-X300 MMC controller
+	 */
+	err = gpio_request(GPIO82_MMC2_IRQ, "mmc card detect");
+	if (err)
+		goto err_request_cd;
+	gpio_direction_input(GPIO82_MMC2_IRQ);
+
+	err = gpio_request(GPIO85_MMC2_WP, "mmc write protect");
+	if (err)
+		goto err_request_wp;
+	gpio_direction_input(GPIO85_MMC2_WP);
+
+	err = request_irq(CM_X300_MMC2_IRQ, cm_x300_detect_int,
+			  IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+			  "MMC card detect", data);
+	if (err) {
+		printk(KERN_ERR "%s: MMC/SD/SDIO: "
+				"can't request card detect IRQ\n", __func__);
+		goto err_request_irq;
+	}
+
+	return 0;
+
+err_request_irq:
+	gpio_free(GPIO85_MMC2_WP);
+err_request_wp:
+	gpio_free(GPIO82_MMC2_IRQ);
+err_request_cd:
+	return err;
+}
+
+static void cm_x300_mci2_exit(struct device *dev, void *data)
+{
+	free_irq(CM_X300_MMC2_IRQ, data);
+	gpio_free(GPIO82_MMC2_IRQ);
+	gpio_free(GPIO85_MMC2_WP);
+}
+
+static struct pxamci_platform_data cm_x300_mci2_platform_data = {
+	.detect_delay	= 20,
+	.ocr_mask	= MMC_VDD_32_33|MMC_VDD_33_34,
+	.init 		= cm_x300_mci2_init,
+	.exit		= cm_x300_mci2_exit,
+	.get_ro		= cm_x300_mci2_ro,
+};
+
+static void __init cm_x300_init_mmc(void)
+{
+	pxa_set_mci_info(&cm_x300_mci_platform_data);
+	pxa3xx_set_mci2_info(&cm_x300_mci2_platform_data);
+}
+#else
+static inline void cm_x300_init_mmc(void) {}
+#endif
+
+#if defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE)
+static struct pxaohci_platform_data cm_x300_ohci_platform_data = {
+	.port_mode	= PMM_PERPORT_MODE,
+	.flags		= ENABLE_PORT1 | ENABLE_PORT2 | POWER_CONTROL_LOW,
+};
+
+static void __init cm_x300_init_ohci(void)
+{
+	pxa_set_ohci_info(&cm_x300_ohci_platform_data);
+}
+#else
+static inline void cm_x300_init_ohci(void) {}
+#endif
+
+#if defined(CONFIG_LEDS_GPIO) || defined(CONFIG_LEDS_GPIO_MODULE)
+static struct gpio_led cm_x300_leds[] = {
+	[0] = {
+		.name = "cm-x300:green",
+		.default_trigger = "heartbeat",
+		.gpio = 79,
+		.active_low = 1,
+	},
+};
+
+static struct gpio_led_platform_data cm_x300_gpio_led_pdata = {
+	.num_leds = ARRAY_SIZE(cm_x300_leds),
+	.leds = cm_x300_leds,
+};
+
+static struct platform_device cm_x300_led_device = {
+	.name		= "leds-gpio",
+	.id		= -1,
+	.dev		= {
+		.platform_data = &cm_x300_gpio_led_pdata,
+	},
+};
+
+static void __init cm_x300_init_leds(void)
+{
+	platform_device_register(&cm_x300_led_device);
+}
+#else
+static inline void cm_x300_init_leds(void) {}
+#endif
+
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+/* PCA9555 */
+static struct pca953x_platform_data cm_x300_gpio_ext_pdata_0 = {
+	.gpio_base = 128,
+};
+
+static struct pca953x_platform_data cm_x300_gpio_ext_pdata_1 = {
+	.gpio_base = 144,
+};
+
+static struct i2c_board_info cm_x300_gpio_ext_info[] = {
+	[0] = {
+		I2C_BOARD_INFO("pca9555", 0x24),
+		.platform_data = &cm_x300_gpio_ext_pdata_0,
+	},
+	[1] = {
+		I2C_BOARD_INFO("pca9555", 0x25),
+		.platform_data = &cm_x300_gpio_ext_pdata_1,
+	},
+};
+
+static void __init cm_x300_init_i2c(void)
+{
+	pxa_set_i2c_info(NULL);
+	i2c_register_board_info(0, cm_x300_gpio_ext_info,
+				ARRAY_SIZE(cm_x300_gpio_ext_info));
+}
+#else
+static inline void cm_x300_init_i2c(void) {}
+#endif
+
+static void __init cm_x300_init(void)
+{
+	/* board-processor specific GPIO initialization */
+	pxa3xx_mfp_config(ARRAY_AND_SIZE(cm_x300_mfp_cfg));
+
+	cm_x300_init_dm9000();
+	cm_x300_init_lcd();
+	cm_x300_init_ohci();
+	cm_x300_init_mmc();
+	cm_x300_init_nand();
+	cm_x300_init_leds();
+	cm_x300_init_i2c();
+}
+
+MACHINE_START(CM_X300, "CM-X300 module")
+	.phys_io	= 0x40000000,
+	.boot_params	= 0xa0000100,
+	.io_pg_offst	= (io_p2v(0x40000000) >> 18) & 0xfffc,
+	.map_io		= pxa_map_io,
+	.init_irq	= pxa3xx_init_irq,
+	.timer		= &pxa_timer,
+	.init_machine	= cm_x300_init,
+MACHINE_END
diff --git a/arch/arm/mach-pxa/colibri.c b/arch/arm/mach-pxa/colibri.c
index abce13c..e847362 100644
--- a/arch/arm/mach-pxa/colibri.c
+++ b/arch/arm/mach-pxa/colibri.c
@@ -29,12 +29,17 @@
 #include <asm/mach/irq.h>
 #include <asm/mach/flash.h>
 #include <mach/pxa-regs.h>
-#include <mach/pxa2xx-gpio.h>
+#include <mach/mfp-pxa27x.h>
 #include <mach/colibri.h>
 
 #include "generic.h"
 #include "devices.h"
 
+static unsigned long colibri_pin_config[] __initdata = {
+	GPIO78_nCS_2,	/* Ethernet CS */
+	GPIO114_GPIO,	/* Ethernet IRQ */
+};
+
 /*
  * Flash
  */
@@ -116,9 +121,7 @@
 
 static void __init colibri_init(void)
 {
-	/* DM9000 LAN */
-	pxa_gpio_mode(GPIO78_nCS_2_MD);
-	pxa_gpio_mode(GPIO_DM9000 | GPIO_IN);
+	pxa2xx_mfp_config(ARRAY_AND_SIZE(colibri_pin_config));
 
 	platform_add_devices(colibri_devices, ARRAY_SIZE(colibri_devices));
 }
diff --git a/arch/arm/mach-pxa/corgi.c b/arch/arm/mach-pxa/corgi.c
index e703a8d..65558d6 100644
--- a/arch/arm/mach-pxa/corgi.c
+++ b/arch/arm/mach-pxa/corgi.c
@@ -20,7 +20,12 @@
 #include <linux/interrupt.h>
 #include <linux/mmc/host.h>
 #include <linux/pm.h>
+#include <linux/gpio.h>
 #include <linux/backlight.h>
+#include <linux/io.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/ads7846.h>
+#include <linux/spi/corgi_lcd.h>
 #include <video/w100fb.h>
 
 #include <asm/setup.h>
@@ -28,7 +33,6 @@
 #include <asm/mach-types.h>
 #include <mach/hardware.h>
 #include <asm/irq.h>
-#include <asm/io.h>
 #include <asm/system.h>
 
 #include <asm/mach/arch.h>
@@ -37,11 +41,12 @@
 
 #include <mach/pxa-regs.h>
 #include <mach/pxa2xx-regs.h>
-#include <mach/pxa2xx-gpio.h>
+#include <mach/mfp-pxa25x.h>
 #include <mach/i2c.h>
 #include <mach/irda.h>
 #include <mach/mmc.h>
 #include <mach/udc.h>
+#include <mach/pxa2xx_spi.h>
 #include <mach/corgi.h>
 #include <mach/sharpsl.h>
 
@@ -52,6 +57,61 @@
 #include "devices.h"
 #include "sharpsl.h"
 
+static unsigned long corgi_pin_config[] __initdata = {
+	/* Static Memory I/O */
+	GPIO78_nCS_2,	/* w100fb */
+	GPIO80_nCS_4,	/* scoop */
+
+	/* SSP1 */
+	GPIO23_SSP1_SCLK,
+	GPIO25_SSP1_TXD,
+	GPIO26_SSP1_RXD,
+	GPIO24_GPIO,	/* CORGI_GPIO_ADS7846_CS - SFRM as chip select */
+
+	/* I2S */
+	GPIO28_I2S_BITCLK_OUT,
+	GPIO29_I2S_SDATA_IN,
+	GPIO30_I2S_SDATA_OUT,
+	GPIO31_I2S_SYNC,
+	GPIO32_I2S_SYSCLK,
+
+	/* Infra-Red */
+	GPIO47_FICP_TXD,
+	GPIO46_FICP_RXD,
+
+	/* FFUART */
+	GPIO40_FFUART_DTR,
+	GPIO41_FFUART_RTS,
+	GPIO39_FFUART_TXD,
+	GPIO37_FFUART_DSR,
+	GPIO34_FFUART_RXD,
+	GPIO35_FFUART_CTS,
+
+	/* PC Card */
+	GPIO48_nPOE,
+	GPIO49_nPWE,
+	GPIO50_nPIOR,
+	GPIO51_nPIOW,
+	GPIO52_nPCE_1,
+	GPIO53_nPCE_2,
+	GPIO54_nPSKTSEL,
+	GPIO55_nPREG,
+	GPIO56_nPWAIT,
+	GPIO57_nIOIS16,
+
+	/* MMC */
+	GPIO6_MMC_CLK,
+	GPIO8_MMC_CS0,
+
+	/* GPIO */
+	GPIO9_GPIO,	/* CORGI_GPIO_nSD_DETECT */
+	GPIO7_GPIO,	/* CORGI_GPIO_nSD_WP */
+	GPIO33_GPIO,	/* CORGI_GPIO_SD_PWR */
+	GPIO22_GPIO,	/* CORGI_GPIO_IR_ON */
+	GPIO44_GPIO,	/* CORGI_GPIO_HSYNC */
+
+	GPIO1_GPIO | WAKEUP_ON_EDGE_RISE,
+};
 
 /*
  * Corgi SCOOP Device
@@ -67,6 +127,7 @@
 static struct scoop_config corgi_scoop_setup = {
 	.io_dir 	= CORGI_SCOOP_IO_DIR,
 	.io_out		= CORGI_SCOOP_IO_OUT,
+	.gpio_base	= CORGI_SCOOP_GPIO_BASE,
 };
 
 struct platform_device corgiscoop_device = {
@@ -79,27 +140,6 @@
 	.resource	= corgi_scoop_resources,
 };
 
-static void corgi_pcmcia_init(void)
-{
-	/* Setup default state of GPIO outputs
-	   before we enable them as outputs. */
-	GPSR(GPIO48_nPOE) = GPIO_bit(GPIO48_nPOE) |
-		GPIO_bit(GPIO49_nPWE) | GPIO_bit(GPIO50_nPIOR) |
-		GPIO_bit(GPIO51_nPIOW) | GPIO_bit(GPIO52_nPCE_1) |
-		GPIO_bit(GPIO53_nPCE_2);
-
-	pxa_gpio_mode(GPIO48_nPOE_MD);
-	pxa_gpio_mode(GPIO49_nPWE_MD);
-	pxa_gpio_mode(GPIO50_nPIOR_MD);
-	pxa_gpio_mode(GPIO51_nPIOW_MD);
-	pxa_gpio_mode(GPIO55_nPREG_MD);
-	pxa_gpio_mode(GPIO56_nPWAIT_MD);
-	pxa_gpio_mode(GPIO57_nIOIS16_MD);
-	pxa_gpio_mode(GPIO52_nPCE_1_MD);
-	pxa_gpio_mode(GPIO53_nPCE_2_MD);
-	pxa_gpio_mode(GPIO54_pSKTSEL_MD);
-}
-
 static struct scoop_pcmcia_dev corgi_pcmcia_scoop[] = {
 {
 	.dev        = &corgiscoop_device.dev,
@@ -112,58 +152,10 @@
 static struct scoop_pcmcia_config corgi_pcmcia_config = {
 	.devs         = &corgi_pcmcia_scoop[0],
 	.num_devs     = 1,
-	.pcmcia_init  = corgi_pcmcia_init,
 };
 
 EXPORT_SYMBOL(corgiscoop_device);
 
-
-/*
- * Corgi SSP Device
- *
- * Set the parent as the scoop device because a lot of SSP devices
- * also use scoop functions and this makes the power up/down order
- * work correctly.
- */
-struct platform_device corgissp_device = {
-	.name		= "corgi-ssp",
-	.dev		= {
- 		.parent = &corgiscoop_device.dev,
-	},
-	.id		= -1,
-};
-
-struct corgissp_machinfo corgi_ssp_machinfo = {
-	.port		= 1,
-	.cs_lcdcon	= CORGI_GPIO_LCDCON_CS,
-	.cs_ads7846	= CORGI_GPIO_ADS7846_CS,
-	.cs_max1111	= CORGI_GPIO_MAX1111_CS,
-	.clk_lcdcon	= 76,
-	.clk_ads7846	= 2,
-	.clk_max1111	= 8,
-};
-
-
-/*
- * LCD/Framebuffer
- */
-static void w100_lcdtg_suspend(struct w100fb_par *par)
-{
-	corgi_lcdtg_suspend();
-}
-
-static void w100_lcdtg_init(struct w100fb_par *par)
-{
-	corgi_lcdtg_hw_init(par->xres);
-}
-
-
-static struct w100_tg_info corgi_lcdtg_info = {
-	.change  = w100_lcdtg_init,
-	.suspend = w100_lcdtg_suspend,
-	.resume  = w100_lcdtg_init,
-};
-
 static struct w100_mem_info corgi_fb_mem = {
 	.ext_cntl          = 0x00040003,
 	.sdram_mode_reg    = 0x00650021,
@@ -242,7 +234,6 @@
 };
 
 static struct w100fb_mach_info corgi_fb_info = {
-	.tg         = &corgi_lcdtg_info,
 	.init_mode  = INIT_MODE_ROTATED,
 	.mem        = &corgi_fb_mem,
 	.regs       = &corgi_fb_regs,
@@ -268,60 +259,10 @@
 	.resource	= corgi_fb_resources,
 	.dev            = {
 		.platform_data = &corgi_fb_info,
-		.parent = &corgissp_device.dev,
 	},
 
 };
 
-
-/*
- * Corgi Backlight Device
- */
-static void corgi_bl_kick_battery(void)
-{
-	void (*kick_batt)(void);
-
-	kick_batt = symbol_get(sharpsl_battery_kick);
-	if (kick_batt) {
-		kick_batt();
-		symbol_put(sharpsl_battery_kick);
-	}
-}
-
-static void corgi_bl_set_intensity(int intensity)
-{
-	if (intensity > 0x10)
-		intensity += 0x10;
-
-	/* Bits 0-4 are accessed via the SSP interface */
-	corgi_ssp_blduty_set(intensity & 0x1f);
-
-	/* Bit 5 is via SCOOP */
-	if (intensity & 0x0020)
-		set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_BACKLIGHT_CONT);
-	else
-		reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_BACKLIGHT_CONT);
-}
-
-static struct generic_bl_info corgi_bl_machinfo = {
-	.name = "corgi-bl",
-	.max_intensity = 0x2f,
-	.default_intensity = 0x1f,
-	.limit_mask = 0x0b,
-	.set_bl_intensity = corgi_bl_set_intensity,
-	.kick_battery = corgi_bl_kick_battery,
-};
-
-static struct platform_device corgibl_device = {
-	.name		= "generic-bl",
-	.dev		= {
- 		.parent = &corgifb_device.dev,
-		.platform_data	= &corgi_bl_machinfo,
-	},
-	.id		= -1,
-};
-
-
 /*
  * Corgi Keyboard Device
  */
@@ -330,75 +271,35 @@
 	.id		= -1,
 };
 
-
 /*
  * Corgi LEDs
  */
+static struct gpio_led corgi_gpio_leds[] = {
+	{
+		.name			= "corgi:amber:charge",
+		.default_trigger	= "sharpsl-charge",
+		.gpio			= CORGI_GPIO_LED_ORANGE,
+	},
+	{
+		.name			= "corgi:green:mail",
+		.default_trigger	= "nand-disk",
+		.gpio			= CORGI_GPIO_LED_GREEN,
+	},
+};
+
+static struct gpio_led_platform_data corgi_gpio_leds_info = {
+	.leds		= corgi_gpio_leds,
+	.num_leds	= ARRAY_SIZE(corgi_gpio_leds),
+};
+
 static struct platform_device corgiled_device = {
-	.name		= "corgi-led",
+	.name		= "leds-gpio",
 	.id		= -1,
-};
-
-
-/*
- * Corgi Touch Screen Device
- */
-static unsigned long (*get_hsync_invperiod)(struct device *dev);
-
-static void inline sharpsl_wait_sync(int gpio)
-{
-	while((GPLR(gpio) & GPIO_bit(gpio)) == 0);
-	while((GPLR(gpio) & GPIO_bit(gpio)) != 0);
-}
-
-static unsigned long corgi_get_hsync_invperiod(void)
-{
-	if (!get_hsync_invperiod)
-		get_hsync_invperiod = symbol_get(w100fb_get_hsynclen);
-	if (!get_hsync_invperiod)
-		return 0;
-
-	return get_hsync_invperiod(&corgifb_device.dev);
-}
-
-static void corgi_put_hsync(void)
-{
-	if (get_hsync_invperiod)
-		symbol_put(w100fb_get_hsynclen);
-	get_hsync_invperiod = NULL;
-}
-
-static void corgi_wait_hsync(void)
-{
-	sharpsl_wait_sync(CORGI_GPIO_HSYNC);
-}
-
-static struct resource corgits_resources[] = {
-	[0] = {
-		.start		= CORGI_IRQ_GPIO_TP_INT,
-		.end		= CORGI_IRQ_GPIO_TP_INT,
-		.flags		= IORESOURCE_IRQ,
-	},
-};
-
-static struct corgits_machinfo  corgi_ts_machinfo = {
-	.get_hsync_invperiod = corgi_get_hsync_invperiod,
-	.put_hsync           = corgi_put_hsync,
-	.wait_hsync          = corgi_wait_hsync,
-};
-
-static struct platform_device corgits_device = {
-	.name		= "corgi-ts",
 	.dev		= {
- 		.parent = &corgissp_device.dev,
-		.platform_data	= &corgi_ts_machinfo,
+		.platform_data = &corgi_gpio_leds_info,
 	},
-	.id		= -1,
-	.num_resources	= ARRAY_SIZE(corgits_resources),
-	.resource	= corgits_resources,
 };
 
-
 /*
  * MMC/SD Device
  *
@@ -411,20 +312,42 @@
 {
 	int err;
 
-	/* setup GPIO for PXA25x MMC controller	*/
-	pxa_gpio_mode(GPIO6_MMCCLK_MD);
-	pxa_gpio_mode(GPIO8_MMCCS0_MD);
-	pxa_gpio_mode(CORGI_GPIO_nSD_DETECT | GPIO_IN);
-	pxa_gpio_mode(CORGI_GPIO_SD_PWR | GPIO_OUT);
+	err = gpio_request(CORGI_GPIO_nSD_DETECT, "nSD_DETECT");
+	if (err)
+		goto err_out;
+
+	err = gpio_request(CORGI_GPIO_nSD_WP, "nSD_WP");
+	if (err)
+		goto err_free_1;
+
+	err = gpio_request(CORGI_GPIO_SD_PWR, "SD_PWR");
+	if (err)
+		goto err_free_2;
+
+	gpio_direction_input(CORGI_GPIO_nSD_DETECT);
+	gpio_direction_input(CORGI_GPIO_nSD_WP);
+	gpio_direction_output(CORGI_GPIO_SD_PWR, 0);
 
 	corgi_mci_platform_data.detect_delay = msecs_to_jiffies(250);
 
 	err = request_irq(CORGI_IRQ_GPIO_nSD_DETECT, corgi_detect_int,
-			  IRQF_DISABLED | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
-			  "MMC card detect", data);
-	if (err)
-		printk(KERN_ERR "corgi_mci_init: MMC/SD: can't request MMC card detect IRQ\n");
+				IRQF_DISABLED | IRQF_TRIGGER_RISING |
+				IRQF_TRIGGER_FALLING,
+				"MMC card detect", data);
+	if (err) {
+		pr_err("%s: MMC/SD: can't request MMC card detect IRQ\n",
+				__func__);
+		goto err_free_3;
+	}
+	return 0;
 
+err_free_3:
+	gpio_free(CORGI_GPIO_SD_PWR);
+err_free_2:
+	gpio_free(CORGI_GPIO_nSD_WP);
+err_free_1:
+	gpio_free(CORGI_GPIO_nSD_DETECT);
+err_out:
 	return err;
 }
 
@@ -432,20 +355,20 @@
 {
 	struct pxamci_platform_data* p_d = dev->platform_data;
 
-	if (( 1 << vdd) & p_d->ocr_mask)
-		GPSR1 = GPIO_bit(CORGI_GPIO_SD_PWR);
-	else
-		GPCR1 = GPIO_bit(CORGI_GPIO_SD_PWR);
+	gpio_set_value(CORGI_GPIO_SD_PWR, ((1 << vdd) & p_d->ocr_mask));
 }
 
 static int corgi_mci_get_ro(struct device *dev)
 {
-	return GPLR(CORGI_GPIO_nSD_WP) & GPIO_bit(CORGI_GPIO_nSD_WP);
+	return gpio_get_value(CORGI_GPIO_nSD_WP);
 }
 
 static void corgi_mci_exit(struct device *dev, void *data)
 {
 	free_irq(CORGI_IRQ_GPIO_nSD_DETECT, data);
+	gpio_free(CORGI_GPIO_SD_PWR);
+	gpio_free(CORGI_GPIO_nSD_WP);
+	gpio_free(CORGI_GPIO_nSD_DETECT);
 }
 
 static struct pxamci_platform_data corgi_mci_platform_data = {
@@ -462,16 +385,32 @@
  */
 static void corgi_irda_transceiver_mode(struct device *dev, int mode)
 {
-	if (mode & IR_OFF)
-		GPSR(CORGI_GPIO_IR_ON) = GPIO_bit(CORGI_GPIO_IR_ON);
-	else
-		GPCR(CORGI_GPIO_IR_ON) = GPIO_bit(CORGI_GPIO_IR_ON);
+	gpio_set_value(CORGI_GPIO_IR_ON, mode & IR_OFF);
 	pxa2xx_transceiver_mode(dev, mode);
 }
 
+static int corgi_irda_startup(struct device *dev)
+{
+	int err;
+
+	err = gpio_request(CORGI_GPIO_IR_ON, "IR_ON");
+	if (err)
+		return err;
+
+	gpio_direction_output(CORGI_GPIO_IR_ON, 1);
+	return 0;
+}
+
+static void corgi_irda_shutdown(struct device *dev)
+{
+	gpio_free(CORGI_GPIO_IR_ON);
+}
+
 static struct pxaficp_platform_data corgi_ficp_platform_data = {
-	.transceiver_cap  = IR_SIRMODE | IR_OFF,
-	.transceiver_mode = corgi_irda_transceiver_mode,
+	.transceiver_cap	= IR_SIRMODE | IR_OFF,
+	.transceiver_mode	= corgi_irda_transceiver_mode,
+	.startup		= corgi_irda_startup,
+	.shutdown		= corgi_irda_shutdown,
 };
 
 
@@ -483,14 +422,129 @@
 	.gpio_pullup		= CORGI_GPIO_USB_PULLUP,
 };
 
+#if defined(CONFIG_SPI_PXA2XX) || defined(CONFIG_SPI_PXA2XX_MASTER)
+static struct pxa2xx_spi_master corgi_spi_info = {
+	.num_chipselect	= 3,
+};
+
+static struct ads7846_platform_data corgi_ads7846_info = {
+	.model			= 7846,
+	.vref_delay_usecs	= 100,
+	.x_plate_ohms		= 419,
+	.y_plate_ohms		= 486,
+	.gpio_pendown		= CORGI_GPIO_TP_INT,
+};
+
+static void corgi_ads7846_cs(u32 command)
+{
+	gpio_set_value(CORGI_GPIO_ADS7846_CS, !(command == PXA2XX_CS_ASSERT));
+}
+
+static struct pxa2xx_spi_chip corgi_ads7846_chip = {
+	.cs_control	= corgi_ads7846_cs,
+};
+
+static void corgi_bl_kick_battery(void)
+{
+	void (*kick_batt)(void);
+
+	kick_batt = symbol_get(sharpsl_battery_kick);
+	if (kick_batt) {
+		kick_batt();
+		symbol_put(sharpsl_battery_kick);
+	}
+}
+
+static struct corgi_lcd_platform_data corgi_lcdcon_info = {
+	.init_mode		= CORGI_LCD_MODE_VGA,
+	.max_intensity		= 0x2f,
+	.default_intensity	= 0x1f,
+	.limit_mask		= 0x0b,
+	.gpio_backlight_cont	= CORGI_GPIO_BACKLIGHT_CONT,
+	.gpio_backlight_on	= -1,
+	.kick_battery		= corgi_bl_kick_battery,
+};
+
+static void corgi_lcdcon_cs(u32 command)
+{
+	gpio_set_value(CORGI_GPIO_LCDCON_CS, !(command == PXA2XX_CS_ASSERT));
+}
+
+static struct pxa2xx_spi_chip corgi_lcdcon_chip = {
+	.cs_control	= corgi_lcdcon_cs,
+};
+
+static void corgi_max1111_cs(u32 command)
+{
+	gpio_set_value(CORGI_GPIO_MAX1111_CS, !(command == PXA2XX_CS_ASSERT));
+}
+
+static struct pxa2xx_spi_chip corgi_max1111_chip = {
+	.cs_control	= corgi_max1111_cs,
+};
+
+static struct spi_board_info corgi_spi_devices[] = {
+	{
+		.modalias	= "ads7846",
+		.max_speed_hz	= 1200000,
+		.bus_num	= 1,
+		.chip_select	= 0,
+		.platform_data	= &corgi_ads7846_info,
+		.controller_data= &corgi_ads7846_chip,
+		.irq		= gpio_to_irq(CORGI_GPIO_TP_INT),
+	}, {
+		.modalias	= "corgi-lcd",
+		.max_speed_hz	= 50000,
+		.bus_num	= 1,
+		.chip_select	= 1,
+		.platform_data	= &corgi_lcdcon_info,
+		.controller_data= &corgi_lcdcon_chip,
+	}, {
+		.modalias	= "max1111",
+		.max_speed_hz	= 450000,
+		.bus_num	= 1,
+		.chip_select	= 2,
+		.controller_data= &corgi_max1111_chip,
+	},
+};
+
+static void __init corgi_init_spi(void)
+{
+	int err;
+
+	err = gpio_request(CORGI_GPIO_ADS7846_CS, "ADS7846_CS");
+	if (err)
+		return;
+
+	err = gpio_request(CORGI_GPIO_LCDCON_CS, "LCDCON_CS");
+	if (err)
+		goto err_free_1;
+
+	err = gpio_request(CORGI_GPIO_MAX1111_CS, "MAX1111_CS");
+	if (err)
+		goto err_free_2;
+
+	gpio_direction_output(CORGI_GPIO_ADS7846_CS, 1);
+	gpio_direction_output(CORGI_GPIO_LCDCON_CS, 1);
+	gpio_direction_output(CORGI_GPIO_MAX1111_CS, 1);
+
+	pxa2xx_set_spi_info(1, &corgi_spi_info);
+	spi_register_board_info(ARRAY_AND_SIZE(corgi_spi_devices));
+	return;
+
+err_free_2:
+	gpio_free(CORGI_GPIO_LCDCON_CS);
+err_free_1:
+	gpio_free(CORGI_GPIO_ADS7846_CS);
+}
+#else
+static inline void corgi_init_spi(void) {}
+#endif
 
 static struct platform_device *devices[] __initdata = {
 	&corgiscoop_device,
-	&corgissp_device,
 	&corgifb_device,
 	&corgikbd_device,
-	&corgibl_device,
-	&corgits_device,
 	&corgiled_device,
 };
 
@@ -498,7 +552,8 @@
 {
 	if (!machine_is_corgi())
 		/* Green LED off tells the bootloader to halt */
-		reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_LED_GREEN);
+		gpio_set_value(CORGI_GPIO_LED_GREEN, 0);
+
 	arm_machine_restart('h');
 }
 
@@ -506,7 +561,8 @@
 {
 	if (!machine_is_corgi())
 		/* Green LED on tells the bootloader to reboot */
-		set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_LED_GREEN);
+		gpio_set_value(CORGI_GPIO_LED_GREEN, 1);
+
 	arm_machine_restart('h');
 }
 
@@ -515,20 +571,12 @@
 	pm_power_off = corgi_poweroff;
 	arm_pm_restart = corgi_restart;
 
-	/* setup sleep mode values */
-	PWER  = 0x00000002;
-	PFER  = 0x00000000;
-	PRER  = 0x00000002;
-	PGSR0 = 0x0158C000;
-	PGSR1 = 0x00FF0080;
-	PGSR2 = 0x0001C004;
 	/* Stop 3.6MHz and drive HIGH to PCMCIA and CS */
 	PCFR |= PCFR_OPDE;
 
-	corgi_ssp_set_machinfo(&corgi_ssp_machinfo);
+	pxa2xx_mfp_config(ARRAY_AND_SIZE(corgi_pin_config));
 
-	pxa_gpio_mode(CORGI_GPIO_IR_ON | GPIO_OUT);
-	pxa_gpio_mode(CORGI_GPIO_HSYNC | GPIO_IN);
+	corgi_init_spi();
 
  	pxa_set_udc_info(&udc_info);
 	pxa_set_mci_info(&corgi_mci_platform_data);
diff --git a/arch/arm/mach-pxa/corgi_lcd.c b/arch/arm/mach-pxa/corgi_lcd.c
deleted file mode 100644
index 311baf1..0000000
--- a/arch/arm/mach-pxa/corgi_lcd.c
+++ /dev/null
@@ -1,290 +0,0 @@
-/*
- * linux/arch/arm/mach-pxa/corgi_lcd.c
- *
- * Corgi/Spitz LCD Specific Code
- *
- * Copyright (C) 2005 Richard Purdie
- *
- * Connectivity:
- *   Corgi - LCD to ATI Imageon w100 (Wallaby)
- *   Spitz - LCD to PXA Framebuffer
- *
- * 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/delay.h>
-#include <linux/kernel.h>
-#include <linux/platform_device.h>
-#include <linux/module.h>
-#include <linux/string.h>
-#include <mach/akita.h>
-#include <mach/corgi.h>
-#include <mach/hardware.h>
-#include <mach/pxa-regs.h>
-#include <mach/sharpsl.h>
-#include <mach/spitz.h>
-#include <asm/hardware/scoop.h>
-#include <asm/mach/sharpsl_param.h>
-#include "generic.h"
-
-/* Register Addresses */
-#define RESCTL_ADRS     0x00
-#define PHACTRL_ADRS    0x01
-#define DUTYCTRL_ADRS   0x02
-#define POWERREG0_ADRS  0x03
-#define POWERREG1_ADRS  0x04
-#define GPOR3_ADRS      0x05
-#define PICTRL_ADRS     0x06
-#define POLCTRL_ADRS    0x07
-
-/* Register Bit Definitions */
-#define RESCTL_QVGA     0x01
-#define RESCTL_VGA      0x00
-
-#define POWER1_VW_ON    0x01  /* VW Supply FET ON */
-#define POWER1_GVSS_ON  0x02  /* GVSS(-8V) Power Supply ON */
-#define POWER1_VDD_ON   0x04  /* VDD(8V),SVSS(-4V) Power Supply ON */
-
-#define POWER1_VW_OFF   0x00  /* VW Supply FET OFF */
-#define POWER1_GVSS_OFF 0x00  /* GVSS(-8V) Power Supply OFF */
-#define POWER1_VDD_OFF  0x00  /* VDD(8V),SVSS(-4V) Power Supply OFF */
-
-#define POWER0_COM_DCLK 0x01  /* COM Voltage DC Bias DAC Serial Data Clock */
-#define POWER0_COM_DOUT 0x02  /* COM Voltage DC Bias DAC Serial Data Out */
-#define POWER0_DAC_ON   0x04  /* DAC Power Supply ON */
-#define POWER0_COM_ON   0x08  /* COM Power Supply ON */
-#define POWER0_VCC5_ON  0x10  /* VCC5 Power Supply ON */
-
-#define POWER0_DAC_OFF  0x00  /* DAC Power Supply OFF */
-#define POWER0_COM_OFF  0x00  /* COM Power Supply OFF */
-#define POWER0_VCC5_OFF 0x00  /* VCC5 Power Supply OFF */
-
-#define PICTRL_INIT_STATE      0x01
-#define PICTRL_INIOFF          0x02
-#define PICTRL_POWER_DOWN      0x04
-#define PICTRL_COM_SIGNAL_OFF  0x08
-#define PICTRL_DAC_SIGNAL_OFF  0x10
-
-#define POLCTRL_SYNC_POL_FALL  0x01
-#define POLCTRL_EN_POL_FALL    0x02
-#define POLCTRL_DATA_POL_FALL  0x04
-#define POLCTRL_SYNC_ACT_H     0x08
-#define POLCTRL_EN_ACT_L       0x10
-
-#define POLCTRL_SYNC_POL_RISE  0x00
-#define POLCTRL_EN_POL_RISE    0x00
-#define POLCTRL_DATA_POL_RISE  0x00
-#define POLCTRL_SYNC_ACT_L     0x00
-#define POLCTRL_EN_ACT_H       0x00
-
-#define PHACTRL_PHASE_MANUAL   0x01
-#define DEFAULT_PHAD_QVGA     (9)
-#define DEFAULT_COMADJ        (125)
-
-/*
- * This is only a psuedo I2C interface. We can't use the standard kernel
- * routines as the interface is write only. We just assume the data is acked...
- */
-static void lcdtg_ssp_i2c_send(u8 data)
-{
-	corgi_ssp_lcdtg_send(POWERREG0_ADRS, data);
-	udelay(10);
-}
-
-static void lcdtg_i2c_send_bit(u8 data)
-{
-	lcdtg_ssp_i2c_send(data);
-	lcdtg_ssp_i2c_send(data | POWER0_COM_DCLK);
-	lcdtg_ssp_i2c_send(data);
-}
-
-static void lcdtg_i2c_send_start(u8 base)
-{
-	lcdtg_ssp_i2c_send(base | POWER0_COM_DCLK | POWER0_COM_DOUT);
-	lcdtg_ssp_i2c_send(base | POWER0_COM_DCLK);
-	lcdtg_ssp_i2c_send(base);
-}
-
-static void lcdtg_i2c_send_stop(u8 base)
-{
-	lcdtg_ssp_i2c_send(base);
-	lcdtg_ssp_i2c_send(base | POWER0_COM_DCLK);
-	lcdtg_ssp_i2c_send(base | POWER0_COM_DCLK | POWER0_COM_DOUT);
-}
-
-static void lcdtg_i2c_send_byte(u8 base, u8 data)
-{
-	int i;
-	for (i = 0; i < 8; i++) {
-		if (data & 0x80)
-			lcdtg_i2c_send_bit(base | POWER0_COM_DOUT);
-		else
-			lcdtg_i2c_send_bit(base);
-		data <<= 1;
-	}
-}
-
-static void lcdtg_i2c_wait_ack(u8 base)
-{
-	lcdtg_i2c_send_bit(base);
-}
-
-static void lcdtg_set_common_voltage(u8 base_data, u8 data)
-{
-	/* Set Common Voltage to M62332FP via I2C */
-	lcdtg_i2c_send_start(base_data);
-	lcdtg_i2c_send_byte(base_data, 0x9c);
-	lcdtg_i2c_wait_ack(base_data);
-	lcdtg_i2c_send_byte(base_data, 0x00);
-	lcdtg_i2c_wait_ack(base_data);
-	lcdtg_i2c_send_byte(base_data, data);
-	lcdtg_i2c_wait_ack(base_data);
-	lcdtg_i2c_send_stop(base_data);
-}
-
-/* Set Phase Adjust */
-static void lcdtg_set_phadadj(int mode)
-{
-	int adj;
-	switch(mode) {
-		case 480:
-		case 640:
-			/* Setting for VGA */
-			adj = sharpsl_param.phadadj;
-			if (adj < 0) {
-				adj = PHACTRL_PHASE_MANUAL;
-			} else {
-				adj = ((adj & 0x0f) << 1) | PHACTRL_PHASE_MANUAL;
-			}
-			break;
-		case 240:
-		case 320:
-		default:
-			/* Setting for QVGA */
-			adj = (DEFAULT_PHAD_QVGA << 1) | PHACTRL_PHASE_MANUAL;
-			break;
-	}
-
-	corgi_ssp_lcdtg_send(PHACTRL_ADRS, adj);
-}
-
-static int lcd_inited;
-
-void corgi_lcdtg_hw_init(int mode)
-{
-	if (!lcd_inited) {
-		int comadj;
-
-		/* Initialize Internal Logic & Port */
-		corgi_ssp_lcdtg_send(PICTRL_ADRS, PICTRL_POWER_DOWN | PICTRL_INIOFF | PICTRL_INIT_STATE
-	  			| PICTRL_COM_SIGNAL_OFF | PICTRL_DAC_SIGNAL_OFF);
-
-		corgi_ssp_lcdtg_send(POWERREG0_ADRS, POWER0_COM_DCLK | POWER0_COM_DOUT | POWER0_DAC_OFF
-				| POWER0_COM_OFF | POWER0_VCC5_OFF);
-
-		corgi_ssp_lcdtg_send(POWERREG1_ADRS, POWER1_VW_OFF | POWER1_GVSS_OFF | POWER1_VDD_OFF);
-
-		/* VDD(+8V), SVSS(-4V) ON */
-		corgi_ssp_lcdtg_send(POWERREG1_ADRS, POWER1_VW_OFF | POWER1_GVSS_OFF | POWER1_VDD_ON);
-		mdelay(3);
-
-		/* DAC ON */
-		corgi_ssp_lcdtg_send(POWERREG0_ADRS, POWER0_COM_DCLK | POWER0_COM_DOUT | POWER0_DAC_ON
-				| POWER0_COM_OFF | POWER0_VCC5_OFF);
-
-		/* INIB = H, INI = L  */
-		/* PICTL[0] = H , PICTL[1] = PICTL[2] = PICTL[4] = L */
-		corgi_ssp_lcdtg_send(PICTRL_ADRS, PICTRL_INIT_STATE | PICTRL_COM_SIGNAL_OFF);
-
-		/* Set Common Voltage */
-		comadj = sharpsl_param.comadj;
-		if (comadj < 0)
-			comadj = DEFAULT_COMADJ;
-		lcdtg_set_common_voltage((POWER0_DAC_ON | POWER0_COM_OFF | POWER0_VCC5_OFF), comadj);
-
-		/* VCC5 ON, DAC ON */
-		corgi_ssp_lcdtg_send(POWERREG0_ADRS, POWER0_COM_DCLK | POWER0_COM_DOUT | POWER0_DAC_ON |
-				POWER0_COM_OFF | POWER0_VCC5_ON);
-
-		/* GVSS(-8V) ON, VDD ON */
-		corgi_ssp_lcdtg_send(POWERREG1_ADRS, POWER1_VW_OFF | POWER1_GVSS_ON | POWER1_VDD_ON);
-		mdelay(2);
-
-		/* COM SIGNAL ON (PICTL[3] = L) */
-		corgi_ssp_lcdtg_send(PICTRL_ADRS, PICTRL_INIT_STATE);
-
-		/* COM ON, DAC ON, VCC5_ON */
-		corgi_ssp_lcdtg_send(POWERREG0_ADRS, POWER0_COM_DCLK | POWER0_COM_DOUT | POWER0_DAC_ON
-				| POWER0_COM_ON | POWER0_VCC5_ON);
-
-		/* VW ON, GVSS ON, VDD ON */
-		corgi_ssp_lcdtg_send(POWERREG1_ADRS, POWER1_VW_ON | POWER1_GVSS_ON | POWER1_VDD_ON);
-
-		/* Signals output enable */
-		corgi_ssp_lcdtg_send(PICTRL_ADRS, 0);
-
-		/* Set Phase Adjust */
-		lcdtg_set_phadadj(mode);
-
-		/* Initialize for Input Signals from ATI */
-		corgi_ssp_lcdtg_send(POLCTRL_ADRS, POLCTRL_SYNC_POL_RISE | POLCTRL_EN_POL_RISE
-				| POLCTRL_DATA_POL_RISE | POLCTRL_SYNC_ACT_L | POLCTRL_EN_ACT_H);
-		udelay(1000);
-
-		lcd_inited=1;
-	} else {
-		lcdtg_set_phadadj(mode);
-	}
-
-	switch(mode) {
-		case 480:
-		case 640:
-			/* Set Lcd Resolution (VGA) */
-			corgi_ssp_lcdtg_send(RESCTL_ADRS, RESCTL_VGA);
-			break;
-		case 240:
-		case 320:
-		default:
-			/* Set Lcd Resolution (QVGA) */
-			corgi_ssp_lcdtg_send(RESCTL_ADRS, RESCTL_QVGA);
-			break;
-	}
-}
-
-void corgi_lcdtg_suspend(void)
-{
-	/* 60Hz x 2 frame = 16.7msec x 2 = 33.4 msec */
-	mdelay(34);
-
-	/* (1)VW OFF */
-	corgi_ssp_lcdtg_send(POWERREG1_ADRS, POWER1_VW_OFF | POWER1_GVSS_ON | POWER1_VDD_ON);
-
-	/* (2)COM OFF */
-	corgi_ssp_lcdtg_send(PICTRL_ADRS, PICTRL_COM_SIGNAL_OFF);
-	corgi_ssp_lcdtg_send(POWERREG0_ADRS, POWER0_DAC_ON | POWER0_COM_OFF | POWER0_VCC5_ON);
-
-	/* (3)Set Common Voltage Bias 0V */
-	lcdtg_set_common_voltage(POWER0_DAC_ON | POWER0_COM_OFF | POWER0_VCC5_ON, 0);
-
-	/* (4)GVSS OFF */
-	corgi_ssp_lcdtg_send(POWERREG1_ADRS, POWER1_VW_OFF | POWER1_GVSS_OFF | POWER1_VDD_ON);
-
-	/* (5)VCC5 OFF */
-	corgi_ssp_lcdtg_send(POWERREG0_ADRS, POWER0_DAC_ON | POWER0_COM_OFF | POWER0_VCC5_OFF);
-
-	/* (6)Set PDWN, INIOFF, DACOFF */
-	corgi_ssp_lcdtg_send(PICTRL_ADRS, PICTRL_INIOFF | PICTRL_DAC_SIGNAL_OFF |
-			PICTRL_POWER_DOWN | PICTRL_COM_SIGNAL_OFF);
-
-	/* (7)DAC OFF */
-	corgi_ssp_lcdtg_send(POWERREG0_ADRS, POWER0_DAC_OFF | POWER0_COM_OFF | POWER0_VCC5_OFF);
-
-	/* (8)VDD OFF */
-	corgi_ssp_lcdtg_send(POWERREG1_ADRS, POWER1_VW_OFF | POWER1_GVSS_OFF | POWER1_VDD_OFF);
-
-	lcd_inited = 0;
-}
-
diff --git a/arch/arm/mach-pxa/corgi_pm.c b/arch/arm/mach-pxa/corgi_pm.c
index 35bbfcc..eb7d6c9 100644
--- a/arch/arm/mach-pxa/corgi_pm.c
+++ b/arch/arm/mach-pxa/corgi_pm.c
@@ -21,7 +21,6 @@
 #include <asm/irq.h>
 #include <asm/mach-types.h>
 #include <mach/hardware.h>
-#include <asm/hardware/scoop.h>
 
 #include <mach/sharpsl.h>
 #include <mach/corgi.h>
diff --git a/arch/arm/mach-pxa/corgi_ssp.c b/arch/arm/mach-pxa/corgi_ssp.c
deleted file mode 100644
index 8e2f221..0000000
--- a/arch/arm/mach-pxa/corgi_ssp.c
+++ /dev/null
@@ -1,276 +0,0 @@
-/*
- *  SSP control code for Sharp Corgi devices
- *
- *  Copyright (c) 2004-2005 Richard Purdie
- *
- *  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/init.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include <linux/platform_device.h>
-#include <mach/hardware.h>
-#include <asm/mach-types.h>
-
-#include <mach/ssp.h>
-#include <mach/pxa-regs.h>
-#include <mach/pxa2xx-gpio.h>
-#include <mach/regs-ssp.h>
-#include "sharpsl.h"
-
-static DEFINE_SPINLOCK(corgi_ssp_lock);
-static struct ssp_dev corgi_ssp_dev;
-static struct ssp_state corgi_ssp_state;
-static struct corgissp_machinfo *ssp_machinfo;
-
-/*
- * There are three devices connected to the SSP interface:
- *   1. A touchscreen controller (TI ADS7846 compatible)
- *   2. An LCD controller (with some Backlight functionality)
- *   3. A battery monitoring IC (Maxim MAX1111)
- *
- * Each device uses a different speed/mode of communication.
- *
- * The touchscreen is very sensitive and the most frequently used
- * so the port is left configured for this.
- *
- * Devices are selected using Chip Selects on GPIOs.
- */
-
-/*
- *  ADS7846 Routines
- */
-unsigned long corgi_ssp_ads7846_putget(ulong data)
-{
-	unsigned long flag;
-	u32 ret = 0;
-
-	spin_lock_irqsave(&corgi_ssp_lock, flag);
-	if (ssp_machinfo->cs_ads7846 >= 0)
-		GPCR(ssp_machinfo->cs_ads7846) = GPIO_bit(ssp_machinfo->cs_ads7846);
-
-	ssp_write_word(&corgi_ssp_dev,data);
- 	ssp_read_word(&corgi_ssp_dev, &ret);
-
-	if (ssp_machinfo->cs_ads7846 >= 0)
-		GPSR(ssp_machinfo->cs_ads7846) = GPIO_bit(ssp_machinfo->cs_ads7846);
-	spin_unlock_irqrestore(&corgi_ssp_lock, flag);
-
-	return ret;
-}
-
-/*
- * NOTE: These functions should always be called in interrupt context
- * and use the _lock and _unlock functions. They are very time sensitive.
- */
-void corgi_ssp_ads7846_lock(void)
-{
-	spin_lock(&corgi_ssp_lock);
-	if (ssp_machinfo->cs_ads7846 >= 0)
-		GPCR(ssp_machinfo->cs_ads7846) = GPIO_bit(ssp_machinfo->cs_ads7846);
-}
-
-void corgi_ssp_ads7846_unlock(void)
-{
-	if (ssp_machinfo->cs_ads7846 >= 0)
-		GPSR(ssp_machinfo->cs_ads7846) = GPIO_bit(ssp_machinfo->cs_ads7846);
-	spin_unlock(&corgi_ssp_lock);
-}
-
-void corgi_ssp_ads7846_put(ulong data)
-{
-	ssp_write_word(&corgi_ssp_dev,data);
-}
-
-unsigned long corgi_ssp_ads7846_get(void)
-{
-	u32 ret = 0;
-	ssp_read_word(&corgi_ssp_dev, &ret);
-	return ret;
-}
-
-EXPORT_SYMBOL(corgi_ssp_ads7846_putget);
-EXPORT_SYMBOL(corgi_ssp_ads7846_lock);
-EXPORT_SYMBOL(corgi_ssp_ads7846_unlock);
-EXPORT_SYMBOL(corgi_ssp_ads7846_put);
-EXPORT_SYMBOL(corgi_ssp_ads7846_get);
-
-
-/*
- *  LCD/Backlight Routines
- */
-unsigned long corgi_ssp_dac_put(ulong data)
-{
-	unsigned long flag, sscr1 = SSCR1_SPH;
-	u32 tmp;
-
-	spin_lock_irqsave(&corgi_ssp_lock, flag);
-
-	if (machine_is_spitz() || machine_is_akita() || machine_is_borzoi())
-		sscr1 = 0;
-
-	ssp_disable(&corgi_ssp_dev);
-	ssp_config(&corgi_ssp_dev, (SSCR0_Motorola | (SSCR0_DSS & 0x07 )), sscr1, 0, SSCR0_SerClkDiv(ssp_machinfo->clk_lcdcon));
-	ssp_enable(&corgi_ssp_dev);
-
-	if (ssp_machinfo->cs_lcdcon >= 0)
-		GPCR(ssp_machinfo->cs_lcdcon) = GPIO_bit(ssp_machinfo->cs_lcdcon);
-	ssp_write_word(&corgi_ssp_dev,data);
-	/* Read null data back from device to prevent SSP overflow */
-	ssp_read_word(&corgi_ssp_dev, &tmp);
-	if (ssp_machinfo->cs_lcdcon >= 0)
-		GPSR(ssp_machinfo->cs_lcdcon) = GPIO_bit(ssp_machinfo->cs_lcdcon);
-
-	ssp_disable(&corgi_ssp_dev);
-	ssp_config(&corgi_ssp_dev, (SSCR0_National | (SSCR0_DSS & 0x0b )), 0, 0, SSCR0_SerClkDiv(ssp_machinfo->clk_ads7846));
-	ssp_enable(&corgi_ssp_dev);
-
-	spin_unlock_irqrestore(&corgi_ssp_lock, flag);
-
-	return 0;
-}
-
-void corgi_ssp_lcdtg_send(u8 adrs, u8 data)
-{
-	corgi_ssp_dac_put(((adrs & 0x07) << 5) | (data & 0x1f));
-}
-
-void corgi_ssp_blduty_set(int duty)
-{
-	corgi_ssp_lcdtg_send(0x02,duty);
-}
-
-EXPORT_SYMBOL(corgi_ssp_lcdtg_send);
-EXPORT_SYMBOL(corgi_ssp_blduty_set);
-
-/*
- *  Max1111 Routines
- */
-int corgi_ssp_max1111_get(ulong data)
-{
-	unsigned long flag;
-	long voltage = 0, voltage1 = 0, voltage2 = 0;
-
-	spin_lock_irqsave(&corgi_ssp_lock, flag);
-	if (ssp_machinfo->cs_max1111 >= 0)
-		GPCR(ssp_machinfo->cs_max1111) = GPIO_bit(ssp_machinfo->cs_max1111);
-	ssp_disable(&corgi_ssp_dev);
-	ssp_config(&corgi_ssp_dev, (SSCR0_Motorola | (SSCR0_DSS & 0x07 )), 0, 0, SSCR0_SerClkDiv(ssp_machinfo->clk_max1111));
-	ssp_enable(&corgi_ssp_dev);
-
-	udelay(1);
-
-	/* TB1/RB1 */
-	ssp_write_word(&corgi_ssp_dev,data);
-	ssp_read_word(&corgi_ssp_dev, (u32*)&voltage1); /* null read */
-
-	/* TB12/RB2 */
-	ssp_write_word(&corgi_ssp_dev,0);
-	ssp_read_word(&corgi_ssp_dev, (u32*)&voltage1);
-
-	/* TB13/RB3*/
-	ssp_write_word(&corgi_ssp_dev,0);
-	ssp_read_word(&corgi_ssp_dev, (u32*)&voltage2);
-
-	ssp_disable(&corgi_ssp_dev);
-	ssp_config(&corgi_ssp_dev, (SSCR0_National | (SSCR0_DSS & 0x0b )), 0, 0, SSCR0_SerClkDiv(ssp_machinfo->clk_ads7846));
-	ssp_enable(&corgi_ssp_dev);
-	if (ssp_machinfo->cs_max1111 >= 0)
-		GPSR(ssp_machinfo->cs_max1111) = GPIO_bit(ssp_machinfo->cs_max1111);
-	spin_unlock_irqrestore(&corgi_ssp_lock, flag);
-
-	if (voltage1 & 0xc0 || voltage2 & 0x3f)
-		voltage = -1;
-	else
-		voltage = ((voltage1 << 2) & 0xfc) | ((voltage2 >> 6) & 0x03);
-
-	return voltage;
-}
-
-EXPORT_SYMBOL(corgi_ssp_max1111_get);
-
-/*
- *  Support Routines
- */
-
-void __init corgi_ssp_set_machinfo(struct corgissp_machinfo *machinfo)
-{
-	ssp_machinfo = machinfo;
-}
-
-static int __init corgi_ssp_probe(struct platform_device *dev)
-{
-	int ret;
-
-	/* Chip Select - Disable All */
-	if (ssp_machinfo->cs_lcdcon >= 0)
-		pxa_gpio_mode(ssp_machinfo->cs_lcdcon  | GPIO_OUT | GPIO_DFLT_HIGH);
-	if (ssp_machinfo->cs_max1111 >= 0)
-	        pxa_gpio_mode(ssp_machinfo->cs_max1111 | GPIO_OUT | GPIO_DFLT_HIGH);
-	if (ssp_machinfo->cs_ads7846 >= 0)
-        	pxa_gpio_mode(ssp_machinfo->cs_ads7846 | GPIO_OUT | GPIO_DFLT_HIGH);
-
-	ret = ssp_init(&corgi_ssp_dev, ssp_machinfo->port, 0);
-
-	if (ret)
-		printk(KERN_ERR "Unable to register SSP handler!\n");
-	else {
-		ssp_disable(&corgi_ssp_dev);
-		ssp_config(&corgi_ssp_dev, (SSCR0_National | (SSCR0_DSS & 0x0b )), 0, 0, SSCR0_SerClkDiv(ssp_machinfo->clk_ads7846));
-		ssp_enable(&corgi_ssp_dev);
-	}
-
-	return ret;
-}
-
-static int corgi_ssp_remove(struct platform_device *dev)
-{
-	ssp_exit(&corgi_ssp_dev);
-	return 0;
-}
-
-static int corgi_ssp_suspend(struct platform_device *dev, pm_message_t state)
-{
-	ssp_flush(&corgi_ssp_dev);
-	ssp_save_state(&corgi_ssp_dev,&corgi_ssp_state);
-
-	return 0;
-}
-
-static int corgi_ssp_resume(struct platform_device *dev)
-{
-	if (ssp_machinfo->cs_lcdcon >= 0)
-		GPSR(ssp_machinfo->cs_lcdcon) = GPIO_bit(ssp_machinfo->cs_lcdcon);  /* High - Disable LCD Control/Timing Gen */
-	if (ssp_machinfo->cs_max1111 >= 0)
-		GPSR(ssp_machinfo->cs_max1111) = GPIO_bit(ssp_machinfo->cs_max1111); /* High - Disable MAX1111*/
-	if (ssp_machinfo->cs_ads7846 >= 0)
-		GPSR(ssp_machinfo->cs_ads7846) = GPIO_bit(ssp_machinfo->cs_ads7846); /* High - Disable ADS7846*/
-	ssp_restore_state(&corgi_ssp_dev,&corgi_ssp_state);
-	ssp_enable(&corgi_ssp_dev);
-
-	return 0;
-}
-
-static struct platform_driver corgissp_driver = {
-	.probe		= corgi_ssp_probe,
-	.remove		= corgi_ssp_remove,
-	.suspend	= corgi_ssp_suspend,
-	.resume		= corgi_ssp_resume,
-	.driver		= {
-		.name	= "corgi-ssp",
-	},
-};
-
-int __init corgi_ssp_init(void)
-{
-	return platform_driver_register(&corgissp_driver);
-}
-
-arch_initcall(corgi_ssp_init);
diff --git a/arch/arm/mach-pxa/cpu-pxa.c b/arch/arm/mach-pxa/cpu-pxa.c
deleted file mode 100644
index 6f5569b..0000000
--- a/arch/arm/mach-pxa/cpu-pxa.c
+++ /dev/null
@@ -1,410 +0,0 @@
-/*
- *  linux/arch/arm/mach-pxa/cpu-pxa.c
- *
- *  Copyright (C) 2002,2003 Intrinsyc Software
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- *
- * History:
- *   31-Jul-2002 : Initial version [FB]
- *   29-Jan-2003 : added PXA255 support [FB]
- *   20-Apr-2003 : ported to v2.5 (Dustin McIntire, Sensoria Corp.)
- *
- * Note:
- *   This driver may change the memory bus clock rate, but will not do any
- *   platform specific access timing changes... for example if you have flash
- *   memory connected to CS0, you will need to register a platform specific
- *   notifier which will adjust the memory access strobes to maintain a
- *   minimum strobe width.
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/sched.h>
-#include <linux/init.h>
-#include <linux/cpufreq.h>
-
-#include <mach/hardware.h>
-#include <mach/pxa-regs.h>
-#include <mach/pxa2xx-regs.h>
-
-#ifdef DEBUG
-static unsigned int freq_debug;
-module_param(freq_debug, uint, 0);
-MODULE_PARM_DESC(freq_debug, "Set the debug messages to on=1/off=0");
-#else
-#define freq_debug  0
-#endif
-
-static unsigned int pxa27x_maxfreq;
-module_param(pxa27x_maxfreq, uint, 0);
-MODULE_PARM_DESC(pxa27x_maxfreq, "Set the pxa27x maxfreq in MHz"
-		 "(typically 624=>pxa270, 416=>pxa271, 520=>pxa272)");
-
-typedef struct {
-	unsigned int khz;
-	unsigned int membus;
-	unsigned int cccr;
-	unsigned int div2;
-	unsigned int cclkcfg;
-} pxa_freqs_t;
-
-/* Define the refresh period in mSec for the SDRAM and the number of rows */
-#define SDRAM_TREF	64	/* standard 64ms SDRAM */
-#define SDRAM_ROWS	4096	/* 64MB=8192 32MB=4096 */
-
-#define CCLKCFG_TURBO		0x1
-#define CCLKCFG_FCS		0x2
-#define CCLKCFG_HALFTURBO	0x4
-#define CCLKCFG_FASTBUS		0x8
-#define MDREFR_DB2_MASK		(MDREFR_K2DB2 | MDREFR_K1DB2)
-#define MDREFR_DRI_MASK		0xFFF
-
-/*
- * PXA255 definitions
- */
-/* Use the run mode frequencies for the CPUFREQ_POLICY_PERFORMANCE policy */
-#define CCLKCFG			CCLKCFG_TURBO | CCLKCFG_FCS
-
-static pxa_freqs_t pxa255_run_freqs[] =
-{
-	/* CPU   MEMBUS  CCCR  DIV2 CCLKCFG	   run  turbo PXbus SDRAM */
-	{ 99500,  99500, 0x121, 1,  CCLKCFG},	/*  99,   99,   50,   50  */
-	{132700, 132700, 0x123, 1,  CCLKCFG},	/* 133,  133,   66,   66  */
-	{199100,  99500, 0x141, 0,  CCLKCFG},	/* 199,  199,   99,   99  */
-	{265400, 132700, 0x143, 1,  CCLKCFG},	/* 265,  265,  133,   66  */
-	{331800, 165900, 0x145, 1,  CCLKCFG},	/* 331,  331,  166,   83  */
-	{398100,  99500, 0x161, 0,  CCLKCFG},	/* 398,  398,  196,   99  */
-};
-
-/* Use the turbo mode frequencies for the CPUFREQ_POLICY_POWERSAVE policy */
-static pxa_freqs_t pxa255_turbo_freqs[] =
-{
-	/* CPU   MEMBUS  CCCR  DIV2 CCLKCFG	   run  turbo PXbus SDRAM */
-	{ 99500, 99500,  0x121, 1,  CCLKCFG},	/*  99,   99,   50,   50  */
-	{199100, 99500,  0x221, 0,  CCLKCFG},	/*  99,  199,   50,   99  */
-	{298500, 99500,  0x321, 0,  CCLKCFG},	/*  99,  287,   50,   99  */
-	{298600, 99500,  0x1c1, 0,  CCLKCFG},	/* 199,  287,   99,   99  */
-	{398100, 99500,  0x241, 0,  CCLKCFG},	/* 199,  398,   99,   99  */
-};
-
-#define NUM_PXA25x_RUN_FREQS ARRAY_SIZE(pxa255_run_freqs)
-#define NUM_PXA25x_TURBO_FREQS ARRAY_SIZE(pxa255_turbo_freqs)
-
-static struct cpufreq_frequency_table
-	pxa255_run_freq_table[NUM_PXA25x_RUN_FREQS+1];
-static struct cpufreq_frequency_table
-	pxa255_turbo_freq_table[NUM_PXA25x_TURBO_FREQS+1];
-
-/*
- * PXA270 definitions
- *
- * For the PXA27x:
- * Control variables are A, L, 2N for CCCR; B, HT, T for CLKCFG.
- *
- * A = 0 => memory controller clock from table 3-7,
- * A = 1 => memory controller clock = system bus clock
- * Run mode frequency	= 13 MHz * L
- * Turbo mode frequency = 13 MHz * L * N
- * System bus frequency = 13 MHz * L / (B + 1)
- *
- * In CCCR:
- * A = 1
- * L = 16	  oscillator to run mode ratio
- * 2N = 6	  2 * (turbo mode to run mode ratio)
- *
- * In CCLKCFG:
- * B = 1	  Fast bus mode
- * HT = 0	  Half-Turbo mode
- * T = 1	  Turbo mode
- *
- * For now, just support some of the combinations in table 3-7 of
- * PXA27x Processor Family Developer's Manual to simplify frequency
- * change sequences.
- */
-#define PXA27x_CCCR(A, L, N2) (A << 25 | N2 << 7 | L)
-#define CCLKCFG2(B, HT, T) \
-  (CCLKCFG_FCS | \
-   ((B)  ? CCLKCFG_FASTBUS : 0) | \
-   ((HT) ? CCLKCFG_HALFTURBO : 0) | \
-   ((T)  ? CCLKCFG_TURBO : 0))
-
-static pxa_freqs_t pxa27x_freqs[] = {
-	{104000, 104000, PXA27x_CCCR(1,	 8, 2), 0, CCLKCFG2(1, 0, 1)},
-	{156000, 104000, PXA27x_CCCR(1,	 8, 6), 0, CCLKCFG2(1, 1, 1)},
-	{208000, 208000, PXA27x_CCCR(0, 16, 2), 1, CCLKCFG2(0, 0, 1)},
-	{312000, 208000, PXA27x_CCCR(1, 16, 3), 1, CCLKCFG2(1, 0, 1)},
-	{416000, 208000, PXA27x_CCCR(1, 16, 4), 1, CCLKCFG2(1, 0, 1)},
-	{520000, 208000, PXA27x_CCCR(1, 16, 5), 1, CCLKCFG2(1, 0, 1)},
-	{624000, 208000, PXA27x_CCCR(1, 16, 6), 1, CCLKCFG2(1, 0, 1)}
-};
-
-#define NUM_PXA27x_FREQS ARRAY_SIZE(pxa27x_freqs)
-static struct cpufreq_frequency_table
-	pxa27x_freq_table[NUM_PXA27x_FREQS+1];
-
-extern unsigned get_clk_frequency_khz(int info);
-
-static void find_freq_tables(struct cpufreq_policy *policy,
-			     struct cpufreq_frequency_table **freq_table,
-			     pxa_freqs_t **pxa_freqs)
-{
-	if (cpu_is_pxa25x()) {
-		if (policy->policy == CPUFREQ_POLICY_PERFORMANCE) {
-			*pxa_freqs = pxa255_run_freqs;
-			*freq_table = pxa255_run_freq_table;
-		} else if (policy->policy == CPUFREQ_POLICY_POWERSAVE) {
-			*pxa_freqs = pxa255_turbo_freqs;
-			*freq_table = pxa255_turbo_freq_table;
-		} else {
-			printk("CPU PXA: Unknown policy found. "
-			       "Using CPUFREQ_POLICY_PERFORMANCE\n");
-			*pxa_freqs = pxa255_run_freqs;
-			*freq_table = pxa255_run_freq_table;
-		}
-	}
-	if (cpu_is_pxa27x()) {
-		*pxa_freqs = pxa27x_freqs;
-		*freq_table = pxa27x_freq_table;
-	}
-}
-
-static void pxa27x_guess_max_freq(void)
-{
-	if (!pxa27x_maxfreq) {
-		pxa27x_maxfreq = 416000;
-		printk(KERN_INFO "PXA CPU 27x max frequency not defined "
-		       "(pxa27x_maxfreq), assuming pxa271 with %dkHz maxfreq\n",
-		       pxa27x_maxfreq);
-	} else {
-		pxa27x_maxfreq *= 1000;
-	}
-}
-
-static u32 mdrefr_dri(unsigned int freq)
-{
-	u32 dri = 0;
-
-	if (cpu_is_pxa25x())
-		dri = ((freq * SDRAM_TREF) / (SDRAM_ROWS * 32));
-	if (cpu_is_pxa27x())
-		dri = ((freq * SDRAM_TREF) / (SDRAM_ROWS - 31)) / 32;
-	return dri;
-}
-
-/* find a valid frequency point */
-static int pxa_verify_policy(struct cpufreq_policy *policy)
-{
-	struct cpufreq_frequency_table *pxa_freqs_table;
-	pxa_freqs_t *pxa_freqs;
-	int ret;
-
-	find_freq_tables(policy, &pxa_freqs_table, &pxa_freqs);
-	ret = cpufreq_frequency_table_verify(policy, pxa_freqs_table);
-
-	if (freq_debug)
-		pr_debug("Verified CPU policy: %dKhz min to %dKhz max\n",
-			 policy->min, policy->max);
-
-	return ret;
-}
-
-static unsigned int pxa_cpufreq_get(unsigned int cpu)
-{
-	return get_clk_frequency_khz(0);
-}
-
-static int pxa_set_target(struct cpufreq_policy *policy,
-			  unsigned int target_freq,
-			  unsigned int relation)
-{
-	struct cpufreq_frequency_table *pxa_freqs_table;
-	pxa_freqs_t *pxa_freq_settings;
-	struct cpufreq_freqs freqs;
-	unsigned int idx;
-	unsigned long flags;
-	unsigned int new_freq_cpu, new_freq_mem;
-	unsigned int unused, preset_mdrefr, postset_mdrefr, cclkcfg;
-
-	/* Get the current policy */
-	find_freq_tables(policy, &pxa_freqs_table, &pxa_freq_settings);
-
-	/* Lookup the next frequency */
-	if (cpufreq_frequency_table_target(policy, pxa_freqs_table,
-					   target_freq, relation, &idx)) {
-		return -EINVAL;
-	}
-
-	new_freq_cpu = pxa_freq_settings[idx].khz;
-	new_freq_mem = pxa_freq_settings[idx].membus;
-	freqs.old = policy->cur;
-	freqs.new = new_freq_cpu;
-	freqs.cpu = policy->cpu;
-
-	if (freq_debug)
-		pr_debug(KERN_INFO "Changing CPU frequency to %d Mhz, "
-			 "(SDRAM %d Mhz)\n",
-			 freqs.new / 1000, (pxa_freq_settings[idx].div2) ?
-			 (new_freq_mem / 2000) : (new_freq_mem / 1000));
-
-	/*
-	 * Tell everyone what we're about to do...
-	 * you should add a notify client with any platform specific
-	 * Vcc changing capability
-	 */
-	cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
-
-	/* Calculate the next MDREFR.  If we're slowing down the SDRAM clock
-	 * we need to preset the smaller DRI before the change.	 If we're
-	 * speeding up we need to set the larger DRI value after the change.
-	 */
-	preset_mdrefr = postset_mdrefr = MDREFR;
-	if ((MDREFR & MDREFR_DRI_MASK) > mdrefr_dri(new_freq_mem)) {
-		preset_mdrefr = (preset_mdrefr & ~MDREFR_DRI_MASK);
-		preset_mdrefr |= mdrefr_dri(new_freq_mem);
-	}
-	postset_mdrefr =
-		(postset_mdrefr & ~MDREFR_DRI_MASK) | mdrefr_dri(new_freq_mem);
-
-	/* If we're dividing the memory clock by two for the SDRAM clock, this
-	 * must be set prior to the change.  Clearing the divide must be done
-	 * after the change.
-	 */
-	if (pxa_freq_settings[idx].div2) {
-		preset_mdrefr  |= MDREFR_DB2_MASK;
-		postset_mdrefr |= MDREFR_DB2_MASK;
-	} else {
-		postset_mdrefr &= ~MDREFR_DB2_MASK;
-	}
-
-	local_irq_save(flags);
-
-	/* Set new the CCCR and prepare CCLKCFG */
-	CCCR = pxa_freq_settings[idx].cccr;
-	cclkcfg = pxa_freq_settings[idx].cclkcfg;
-
-	asm volatile("							\n\
-		ldr	r4, [%1]		/* load MDREFR */	\n\
-		b	2f						\n\
-		.align	5						\n\
-1:									\n\
-		str	%3, [%1]		/* preset the MDREFR */	\n\
-		mcr	p14, 0, %2, c6, c0, 0	/* set CCLKCFG[FCS] */	\n\
-		str	%4, [%1]		/* postset the MDREFR */ \n\
-									\n\
-		b	3f						\n\
-2:		b	1b						\n\
-3:		nop							\n\
-	  "
-		     : "=&r" (unused)
-		     : "r" (&MDREFR), "r" (cclkcfg),
-		       "r" (preset_mdrefr), "r" (postset_mdrefr)
-		     : "r4", "r5");
-	local_irq_restore(flags);
-
-	/*
-	 * Tell everyone what we've just done...
-	 * you should add a notify client with any platform specific
-	 * SDRAM refresh timer adjustments
-	 */
-	cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
-
-	return 0;
-}
-
-static __init int pxa_cpufreq_init(struct cpufreq_policy *policy)
-{
-	int i;
-	unsigned int freq;
-
-	/* try to guess pxa27x cpu */
-	if (cpu_is_pxa27x())
-		pxa27x_guess_max_freq();
-
-	/* set default policy and cpuinfo */
-	policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
-	if (cpu_is_pxa25x())
-		policy->policy = CPUFREQ_POLICY_PERFORMANCE;
-	policy->cpuinfo.transition_latency = 1000; /* FIXME: 1 ms, assumed */
-	policy->cur = get_clk_frequency_khz(0);	   /* current freq */
-	policy->min = policy->max = policy->cur;
-
-	/* Generate pxa25x the run cpufreq_frequency_table struct */
-	for (i = 0; i < NUM_PXA25x_RUN_FREQS; i++) {
-		pxa255_run_freq_table[i].frequency = pxa255_run_freqs[i].khz;
-		pxa255_run_freq_table[i].index = i;
-	}
-	pxa255_run_freq_table[i].frequency = CPUFREQ_TABLE_END;
-
-	/* Generate pxa25x the turbo cpufreq_frequency_table struct */
-	for (i = 0; i < NUM_PXA25x_TURBO_FREQS; i++) {
-		pxa255_turbo_freq_table[i].frequency =
-			pxa255_turbo_freqs[i].khz;
-		pxa255_turbo_freq_table[i].index = i;
-	}
-	pxa255_turbo_freq_table[i].frequency = CPUFREQ_TABLE_END;
-
-	/* Generate the pxa27x cpufreq_frequency_table struct */
-	for (i = 0; i < NUM_PXA27x_FREQS; i++) {
-		freq = pxa27x_freqs[i].khz;
-		if (freq > pxa27x_maxfreq)
-			break;
-		pxa27x_freq_table[i].frequency = freq;
-		pxa27x_freq_table[i].index = i;
-	}
-	pxa27x_freq_table[i].frequency = CPUFREQ_TABLE_END;
-
-	/*
-	 * Set the policy's minimum and maximum frequencies from the tables
-	 * just constructed.  This sets cpuinfo.mxx_freq, min and max.
-	 */
-	if (cpu_is_pxa25x())
-		cpufreq_frequency_table_cpuinfo(policy, pxa255_run_freq_table);
-	else if (cpu_is_pxa27x())
-		cpufreq_frequency_table_cpuinfo(policy, pxa27x_freq_table);
-
-	printk(KERN_INFO "PXA CPU frequency change support initialized\n");
-
-	return 0;
-}
-
-static struct cpufreq_driver pxa_cpufreq_driver = {
-	.verify	= pxa_verify_policy,
-	.target	= pxa_set_target,
-	.init	= pxa_cpufreq_init,
-	.get	= pxa_cpufreq_get,
-	.name	= "PXA2xx",
-};
-
-static int __init pxa_cpu_init(void)
-{
-	int ret = -ENODEV;
-	if (cpu_is_pxa25x() || cpu_is_pxa27x())
-		ret = cpufreq_register_driver(&pxa_cpufreq_driver);
-	return ret;
-}
-
-static void __exit pxa_cpu_exit(void)
-{
-	cpufreq_unregister_driver(&pxa_cpufreq_driver);
-}
-
-
-MODULE_AUTHOR("Intrinsyc Software Inc.");
-MODULE_DESCRIPTION("CPU frequency changing driver for the PXA architecture");
-MODULE_LICENSE("GPL");
-module_init(pxa_cpu_init);
-module_exit(pxa_cpu_exit);
diff --git a/arch/arm/mach-pxa/cpufreq-pxa2xx.c b/arch/arm/mach-pxa/cpufreq-pxa2xx.c
new file mode 100644
index 0000000..d82528e
--- /dev/null
+++ b/arch/arm/mach-pxa/cpufreq-pxa2xx.c
@@ -0,0 +1,410 @@
+/*
+ *  linux/arch/arm/mach-pxa/cpufreq-pxa2xx.c
+ *
+ *  Copyright (C) 2002,2003 Intrinsyc Software
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * History:
+ *   31-Jul-2002 : Initial version [FB]
+ *   29-Jan-2003 : added PXA255 support [FB]
+ *   20-Apr-2003 : ported to v2.5 (Dustin McIntire, Sensoria Corp.)
+ *
+ * Note:
+ *   This driver may change the memory bus clock rate, but will not do any
+ *   platform specific access timing changes... for example if you have flash
+ *   memory connected to CS0, you will need to register a platform specific
+ *   notifier which will adjust the memory access strobes to maintain a
+ *   minimum strobe width.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/cpufreq.h>
+
+#include <mach/hardware.h>
+#include <mach/pxa-regs.h>
+#include <mach/pxa2xx-regs.h>
+
+#ifdef DEBUG
+static unsigned int freq_debug;
+module_param(freq_debug, uint, 0);
+MODULE_PARM_DESC(freq_debug, "Set the debug messages to on=1/off=0");
+#else
+#define freq_debug  0
+#endif
+
+static unsigned int pxa27x_maxfreq;
+module_param(pxa27x_maxfreq, uint, 0);
+MODULE_PARM_DESC(pxa27x_maxfreq, "Set the pxa27x maxfreq in MHz"
+		 "(typically 624=>pxa270, 416=>pxa271, 520=>pxa272)");
+
+typedef struct {
+	unsigned int khz;
+	unsigned int membus;
+	unsigned int cccr;
+	unsigned int div2;
+	unsigned int cclkcfg;
+} pxa_freqs_t;
+
+/* Define the refresh period in mSec for the SDRAM and the number of rows */
+#define SDRAM_TREF	64	/* standard 64ms SDRAM */
+#define SDRAM_ROWS	4096	/* 64MB=8192 32MB=4096 */
+
+#define CCLKCFG_TURBO		0x1
+#define CCLKCFG_FCS		0x2
+#define CCLKCFG_HALFTURBO	0x4
+#define CCLKCFG_FASTBUS		0x8
+#define MDREFR_DB2_MASK		(MDREFR_K2DB2 | MDREFR_K1DB2)
+#define MDREFR_DRI_MASK		0xFFF
+
+/*
+ * PXA255 definitions
+ */
+/* Use the run mode frequencies for the CPUFREQ_POLICY_PERFORMANCE policy */
+#define CCLKCFG			CCLKCFG_TURBO | CCLKCFG_FCS
+
+static pxa_freqs_t pxa255_run_freqs[] =
+{
+	/* CPU   MEMBUS  CCCR  DIV2 CCLKCFG	   run  turbo PXbus SDRAM */
+	{ 99500,  99500, 0x121, 1,  CCLKCFG},	/*  99,   99,   50,   50  */
+	{132700, 132700, 0x123, 1,  CCLKCFG},	/* 133,  133,   66,   66  */
+	{199100,  99500, 0x141, 0,  CCLKCFG},	/* 199,  199,   99,   99  */
+	{265400, 132700, 0x143, 1,  CCLKCFG},	/* 265,  265,  133,   66  */
+	{331800, 165900, 0x145, 1,  CCLKCFG},	/* 331,  331,  166,   83  */
+	{398100,  99500, 0x161, 0,  CCLKCFG},	/* 398,  398,  196,   99  */
+};
+
+/* Use the turbo mode frequencies for the CPUFREQ_POLICY_POWERSAVE policy */
+static pxa_freqs_t pxa255_turbo_freqs[] =
+{
+	/* CPU   MEMBUS  CCCR  DIV2 CCLKCFG	   run  turbo PXbus SDRAM */
+	{ 99500, 99500,  0x121, 1,  CCLKCFG},	/*  99,   99,   50,   50  */
+	{199100, 99500,  0x221, 0,  CCLKCFG},	/*  99,  199,   50,   99  */
+	{298500, 99500,  0x321, 0,  CCLKCFG},	/*  99,  287,   50,   99  */
+	{298600, 99500,  0x1c1, 0,  CCLKCFG},	/* 199,  287,   99,   99  */
+	{398100, 99500,  0x241, 0,  CCLKCFG},	/* 199,  398,   99,   99  */
+};
+
+#define NUM_PXA25x_RUN_FREQS ARRAY_SIZE(pxa255_run_freqs)
+#define NUM_PXA25x_TURBO_FREQS ARRAY_SIZE(pxa255_turbo_freqs)
+
+static struct cpufreq_frequency_table
+	pxa255_run_freq_table[NUM_PXA25x_RUN_FREQS+1];
+static struct cpufreq_frequency_table
+	pxa255_turbo_freq_table[NUM_PXA25x_TURBO_FREQS+1];
+
+/*
+ * PXA270 definitions
+ *
+ * For the PXA27x:
+ * Control variables are A, L, 2N for CCCR; B, HT, T for CLKCFG.
+ *
+ * A = 0 => memory controller clock from table 3-7,
+ * A = 1 => memory controller clock = system bus clock
+ * Run mode frequency	= 13 MHz * L
+ * Turbo mode frequency = 13 MHz * L * N
+ * System bus frequency = 13 MHz * L / (B + 1)
+ *
+ * In CCCR:
+ * A = 1
+ * L = 16	  oscillator to run mode ratio
+ * 2N = 6	  2 * (turbo mode to run mode ratio)
+ *
+ * In CCLKCFG:
+ * B = 1	  Fast bus mode
+ * HT = 0	  Half-Turbo mode
+ * T = 1	  Turbo mode
+ *
+ * For now, just support some of the combinations in table 3-7 of
+ * PXA27x Processor Family Developer's Manual to simplify frequency
+ * change sequences.
+ */
+#define PXA27x_CCCR(A, L, N2) (A << 25 | N2 << 7 | L)
+#define CCLKCFG2(B, HT, T) \
+  (CCLKCFG_FCS | \
+   ((B)  ? CCLKCFG_FASTBUS : 0) | \
+   ((HT) ? CCLKCFG_HALFTURBO : 0) | \
+   ((T)  ? CCLKCFG_TURBO : 0))
+
+static pxa_freqs_t pxa27x_freqs[] = {
+	{104000, 104000, PXA27x_CCCR(1,	 8, 2), 0, CCLKCFG2(1, 0, 1)},
+	{156000, 104000, PXA27x_CCCR(1,	 8, 6), 0, CCLKCFG2(1, 1, 1)},
+	{208000, 208000, PXA27x_CCCR(0, 16, 2), 1, CCLKCFG2(0, 0, 1)},
+	{312000, 208000, PXA27x_CCCR(1, 16, 3), 1, CCLKCFG2(1, 0, 1)},
+	{416000, 208000, PXA27x_CCCR(1, 16, 4), 1, CCLKCFG2(1, 0, 1)},
+	{520000, 208000, PXA27x_CCCR(1, 16, 5), 1, CCLKCFG2(1, 0, 1)},
+	{624000, 208000, PXA27x_CCCR(1, 16, 6), 1, CCLKCFG2(1, 0, 1)}
+};
+
+#define NUM_PXA27x_FREQS ARRAY_SIZE(pxa27x_freqs)
+static struct cpufreq_frequency_table
+	pxa27x_freq_table[NUM_PXA27x_FREQS+1];
+
+extern unsigned get_clk_frequency_khz(int info);
+
+static void find_freq_tables(struct cpufreq_policy *policy,
+			     struct cpufreq_frequency_table **freq_table,
+			     pxa_freqs_t **pxa_freqs)
+{
+	if (cpu_is_pxa25x()) {
+		if (policy->policy == CPUFREQ_POLICY_PERFORMANCE) {
+			*pxa_freqs = pxa255_run_freqs;
+			*freq_table = pxa255_run_freq_table;
+		} else if (policy->policy == CPUFREQ_POLICY_POWERSAVE) {
+			*pxa_freqs = pxa255_turbo_freqs;
+			*freq_table = pxa255_turbo_freq_table;
+		} else {
+			printk("CPU PXA: Unknown policy found. "
+			       "Using CPUFREQ_POLICY_PERFORMANCE\n");
+			*pxa_freqs = pxa255_run_freqs;
+			*freq_table = pxa255_run_freq_table;
+		}
+	}
+	if (cpu_is_pxa27x()) {
+		*pxa_freqs = pxa27x_freqs;
+		*freq_table = pxa27x_freq_table;
+	}
+}
+
+static void pxa27x_guess_max_freq(void)
+{
+	if (!pxa27x_maxfreq) {
+		pxa27x_maxfreq = 416000;
+		printk(KERN_INFO "PXA CPU 27x max frequency not defined "
+		       "(pxa27x_maxfreq), assuming pxa271 with %dkHz maxfreq\n",
+		       pxa27x_maxfreq);
+	} else {
+		pxa27x_maxfreq *= 1000;
+	}
+}
+
+static u32 mdrefr_dri(unsigned int freq)
+{
+	u32 dri = 0;
+
+	if (cpu_is_pxa25x())
+		dri = ((freq * SDRAM_TREF) / (SDRAM_ROWS * 32));
+	if (cpu_is_pxa27x())
+		dri = ((freq * SDRAM_TREF) / (SDRAM_ROWS - 31)) / 32;
+	return dri;
+}
+
+/* find a valid frequency point */
+static int pxa_verify_policy(struct cpufreq_policy *policy)
+{
+	struct cpufreq_frequency_table *pxa_freqs_table;
+	pxa_freqs_t *pxa_freqs;
+	int ret;
+
+	find_freq_tables(policy, &pxa_freqs_table, &pxa_freqs);
+	ret = cpufreq_frequency_table_verify(policy, pxa_freqs_table);
+
+	if (freq_debug)
+		pr_debug("Verified CPU policy: %dKhz min to %dKhz max\n",
+			 policy->min, policy->max);
+
+	return ret;
+}
+
+static unsigned int pxa_cpufreq_get(unsigned int cpu)
+{
+	return get_clk_frequency_khz(0);
+}
+
+static int pxa_set_target(struct cpufreq_policy *policy,
+			  unsigned int target_freq,
+			  unsigned int relation)
+{
+	struct cpufreq_frequency_table *pxa_freqs_table;
+	pxa_freqs_t *pxa_freq_settings;
+	struct cpufreq_freqs freqs;
+	unsigned int idx;
+	unsigned long flags;
+	unsigned int new_freq_cpu, new_freq_mem;
+	unsigned int unused, preset_mdrefr, postset_mdrefr, cclkcfg;
+
+	/* Get the current policy */
+	find_freq_tables(policy, &pxa_freqs_table, &pxa_freq_settings);
+
+	/* Lookup the next frequency */
+	if (cpufreq_frequency_table_target(policy, pxa_freqs_table,
+					   target_freq, relation, &idx)) {
+		return -EINVAL;
+	}
+
+	new_freq_cpu = pxa_freq_settings[idx].khz;
+	new_freq_mem = pxa_freq_settings[idx].membus;
+	freqs.old = policy->cur;
+	freqs.new = new_freq_cpu;
+	freqs.cpu = policy->cpu;
+
+	if (freq_debug)
+		pr_debug(KERN_INFO "Changing CPU frequency to %d Mhz, "
+			 "(SDRAM %d Mhz)\n",
+			 freqs.new / 1000, (pxa_freq_settings[idx].div2) ?
+			 (new_freq_mem / 2000) : (new_freq_mem / 1000));
+
+	/*
+	 * Tell everyone what we're about to do...
+	 * you should add a notify client with any platform specific
+	 * Vcc changing capability
+	 */
+	cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+
+	/* Calculate the next MDREFR.  If we're slowing down the SDRAM clock
+	 * we need to preset the smaller DRI before the change.	 If we're
+	 * speeding up we need to set the larger DRI value after the change.
+	 */
+	preset_mdrefr = postset_mdrefr = MDREFR;
+	if ((MDREFR & MDREFR_DRI_MASK) > mdrefr_dri(new_freq_mem)) {
+		preset_mdrefr = (preset_mdrefr & ~MDREFR_DRI_MASK);
+		preset_mdrefr |= mdrefr_dri(new_freq_mem);
+	}
+	postset_mdrefr =
+		(postset_mdrefr & ~MDREFR_DRI_MASK) | mdrefr_dri(new_freq_mem);
+
+	/* If we're dividing the memory clock by two for the SDRAM clock, this
+	 * must be set prior to the change.  Clearing the divide must be done
+	 * after the change.
+	 */
+	if (pxa_freq_settings[idx].div2) {
+		preset_mdrefr  |= MDREFR_DB2_MASK;
+		postset_mdrefr |= MDREFR_DB2_MASK;
+	} else {
+		postset_mdrefr &= ~MDREFR_DB2_MASK;
+	}
+
+	local_irq_save(flags);
+
+	/* Set new the CCCR and prepare CCLKCFG */
+	CCCR = pxa_freq_settings[idx].cccr;
+	cclkcfg = pxa_freq_settings[idx].cclkcfg;
+
+	asm volatile("							\n\
+		ldr	r4, [%1]		/* load MDREFR */	\n\
+		b	2f						\n\
+		.align	5						\n\
+1:									\n\
+		str	%3, [%1]		/* preset the MDREFR */	\n\
+		mcr	p14, 0, %2, c6, c0, 0	/* set CCLKCFG[FCS] */	\n\
+		str	%4, [%1]		/* postset the MDREFR */ \n\
+									\n\
+		b	3f						\n\
+2:		b	1b						\n\
+3:		nop							\n\
+	  "
+		     : "=&r" (unused)
+		     : "r" (&MDREFR), "r" (cclkcfg),
+		       "r" (preset_mdrefr), "r" (postset_mdrefr)
+		     : "r4", "r5");
+	local_irq_restore(flags);
+
+	/*
+	 * Tell everyone what we've just done...
+	 * you should add a notify client with any platform specific
+	 * SDRAM refresh timer adjustments
+	 */
+	cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+
+	return 0;
+}
+
+static __init int pxa_cpufreq_init(struct cpufreq_policy *policy)
+{
+	int i;
+	unsigned int freq;
+
+	/* try to guess pxa27x cpu */
+	if (cpu_is_pxa27x())
+		pxa27x_guess_max_freq();
+
+	/* set default policy and cpuinfo */
+	policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
+	if (cpu_is_pxa25x())
+		policy->policy = CPUFREQ_POLICY_PERFORMANCE;
+	policy->cpuinfo.transition_latency = 1000; /* FIXME: 1 ms, assumed */
+	policy->cur = get_clk_frequency_khz(0);	   /* current freq */
+	policy->min = policy->max = policy->cur;
+
+	/* Generate pxa25x the run cpufreq_frequency_table struct */
+	for (i = 0; i < NUM_PXA25x_RUN_FREQS; i++) {
+		pxa255_run_freq_table[i].frequency = pxa255_run_freqs[i].khz;
+		pxa255_run_freq_table[i].index = i;
+	}
+	pxa255_run_freq_table[i].frequency = CPUFREQ_TABLE_END;
+
+	/* Generate pxa25x the turbo cpufreq_frequency_table struct */
+	for (i = 0; i < NUM_PXA25x_TURBO_FREQS; i++) {
+		pxa255_turbo_freq_table[i].frequency =
+			pxa255_turbo_freqs[i].khz;
+		pxa255_turbo_freq_table[i].index = i;
+	}
+	pxa255_turbo_freq_table[i].frequency = CPUFREQ_TABLE_END;
+
+	/* Generate the pxa27x cpufreq_frequency_table struct */
+	for (i = 0; i < NUM_PXA27x_FREQS; i++) {
+		freq = pxa27x_freqs[i].khz;
+		if (freq > pxa27x_maxfreq)
+			break;
+		pxa27x_freq_table[i].frequency = freq;
+		pxa27x_freq_table[i].index = i;
+	}
+	pxa27x_freq_table[i].frequency = CPUFREQ_TABLE_END;
+
+	/*
+	 * Set the policy's minimum and maximum frequencies from the tables
+	 * just constructed.  This sets cpuinfo.mxx_freq, min and max.
+	 */
+	if (cpu_is_pxa25x())
+		cpufreq_frequency_table_cpuinfo(policy, pxa255_run_freq_table);
+	else if (cpu_is_pxa27x())
+		cpufreq_frequency_table_cpuinfo(policy, pxa27x_freq_table);
+
+	printk(KERN_INFO "PXA CPU frequency change support initialized\n");
+
+	return 0;
+}
+
+static struct cpufreq_driver pxa_cpufreq_driver = {
+	.verify	= pxa_verify_policy,
+	.target	= pxa_set_target,
+	.init	= pxa_cpufreq_init,
+	.get	= pxa_cpufreq_get,
+	.name	= "PXA2xx",
+};
+
+static int __init pxa_cpu_init(void)
+{
+	int ret = -ENODEV;
+	if (cpu_is_pxa25x() || cpu_is_pxa27x())
+		ret = cpufreq_register_driver(&pxa_cpufreq_driver);
+	return ret;
+}
+
+static void __exit pxa_cpu_exit(void)
+{
+	cpufreq_unregister_driver(&pxa_cpufreq_driver);
+}
+
+
+MODULE_AUTHOR("Intrinsyc Software Inc.");
+MODULE_DESCRIPTION("CPU frequency changing driver for the PXA architecture");
+MODULE_LICENSE("GPL");
+module_init(pxa_cpu_init);
+module_exit(pxa_cpu_exit);
diff --git a/arch/arm/mach-pxa/cpufreq-pxa3xx.c b/arch/arm/mach-pxa/cpufreq-pxa3xx.c
new file mode 100644
index 0000000..1ea0c9c
--- /dev/null
+++ b/arch/arm/mach-pxa/cpufreq-pxa3xx.c
@@ -0,0 +1,258 @@
+/*
+ * linux/arch/arm/mach-pxa/cpufreq-pxa3xx.c
+ *
+ * Copyright (C) 2008 Marvell International Ltd.
+ *
+ * This program is free software; you can redistribute it and/or 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/module.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/cpufreq.h>
+
+#include <mach/hardware.h>
+#include <mach/pxa-regs.h>
+#include <mach/pxa3xx-regs.h>
+
+#include "generic.h"
+
+#define HSS_104M	(0)
+#define HSS_156M	(1)
+#define HSS_208M	(2)
+#define HSS_312M	(3)
+
+#define SMCFS_78M	(0)
+#define SMCFS_104M	(2)
+#define SMCFS_208M	(5)
+
+#define SFLFS_104M	(0)
+#define SFLFS_156M	(1)
+#define SFLFS_208M	(2)
+#define SFLFS_312M	(3)
+
+#define XSPCLK_156M	(0)
+#define XSPCLK_NONE	(3)
+
+#define DMCFS_26M	(0)
+#define DMCFS_260M	(3)
+
+struct pxa3xx_freq_info {
+	unsigned int cpufreq_mhz;
+	unsigned int core_xl : 5;
+	unsigned int core_xn : 3;
+	unsigned int hss : 2;
+	unsigned int dmcfs : 2;
+	unsigned int smcfs : 3;
+	unsigned int sflfs : 2;
+	unsigned int df_clkdiv : 3;
+
+	int	vcc_core;	/* in mV */
+	int	vcc_sram;	/* in mV */
+};
+
+#define OP(cpufreq, _xl, _xn, _hss, _dmc, _smc, _sfl, _dfi, vcore, vsram) \
+{									\
+	.cpufreq_mhz	= cpufreq,					\
+	.core_xl	= _xl,						\
+	.core_xn	= _xn,						\
+	.hss		= HSS_##_hss##M,				\
+	.dmcfs		= DMCFS_##_dmc##M,				\
+	.smcfs		= SMCFS_##_smc##M,				\
+	.sflfs		= SFLFS_##_sfl##M,				\
+	.df_clkdiv	= _dfi,						\
+	.vcc_core	= vcore,					\
+	.vcc_sram	= vsram,					\
+}
+
+static struct pxa3xx_freq_info pxa300_freqs[] = {
+	/*  CPU XL XN  HSS DMEM SMEM SRAM DFI VCC_CORE VCC_SRAM */
+	OP(104,  8, 1, 104, 260,  78, 104, 3, 1000, 1100), /* 104MHz */
+	OP(208, 16, 1, 104, 260, 104, 156, 2, 1000, 1100), /* 208MHz */
+	OP(416, 16, 2, 156, 260, 104, 208, 2, 1100, 1200), /* 416MHz */
+	OP(624, 24, 2, 208, 260, 208, 312, 3, 1375, 1400), /* 624MHz */
+};
+
+static struct pxa3xx_freq_info pxa320_freqs[] = {
+	/*  CPU XL XN  HSS DMEM SMEM SRAM DFI VCC_CORE VCC_SRAM */
+	OP(104,  8, 1, 104, 260,  78, 104, 3, 1000, 1100), /* 104MHz */
+	OP(208, 16, 1, 104, 260, 104, 156, 2, 1000, 1100), /* 208MHz */
+	OP(416, 16, 2, 156, 260, 104, 208, 2, 1100, 1200), /* 416MHz */
+	OP(624, 24, 2, 208, 260, 208, 312, 3, 1375, 1400), /* 624MHz */
+	OP(806, 31, 2, 208, 260, 208, 312, 3, 1400, 1400), /* 806MHz */
+};
+
+static unsigned int pxa3xx_freqs_num;
+static struct pxa3xx_freq_info *pxa3xx_freqs;
+static struct cpufreq_frequency_table *pxa3xx_freqs_table;
+
+static int setup_freqs_table(struct cpufreq_policy *policy,
+			     struct pxa3xx_freq_info *freqs, int num)
+{
+	struct cpufreq_frequency_table *table;
+	int i;
+
+	table = kzalloc((num + 1) * sizeof(*table), GFP_KERNEL);
+	if (table == NULL)
+		return -ENOMEM;
+
+	for (i = 0; i < num; i++) {
+		table[i].index = i;
+		table[i].frequency = freqs[i].cpufreq_mhz * 1000;
+	}
+	table[num].frequency = i;
+	table[num].frequency = CPUFREQ_TABLE_END;
+
+	pxa3xx_freqs = freqs;
+	pxa3xx_freqs_num = num;
+	pxa3xx_freqs_table = table;
+
+	return cpufreq_frequency_table_cpuinfo(policy, table);
+}
+
+static void __update_core_freq(struct pxa3xx_freq_info *info)
+{
+	uint32_t mask = ACCR_XN_MASK | ACCR_XL_MASK;
+	uint32_t accr = ACCR;
+	uint32_t xclkcfg;
+
+	accr &= ~(ACCR_XN_MASK | ACCR_XL_MASK | ACCR_XSPCLK_MASK);
+	accr |= ACCR_XN(info->core_xn) | ACCR_XL(info->core_xl);
+
+	/* No clock until core PLL is re-locked */
+	accr |= ACCR_XSPCLK(XSPCLK_NONE);
+
+	xclkcfg = (info->core_xn == 2) ? 0x3 : 0x2;	/* turbo bit */
+
+	ACCR = accr;
+	__asm__("mcr p14, 0, %0, c6, c0, 0\n" : : "r"(xclkcfg));
+
+	while ((ACSR & mask) != (accr & mask))
+		cpu_relax();
+}
+
+static void __update_bus_freq(struct pxa3xx_freq_info *info)
+{
+	uint32_t mask;
+	uint32_t accr = ACCR;
+
+	mask = ACCR_SMCFS_MASK | ACCR_SFLFS_MASK | ACCR_HSS_MASK |
+		ACCR_DMCFS_MASK;
+
+	accr &= ~mask;
+	accr |= ACCR_SMCFS(info->smcfs) | ACCR_SFLFS(info->sflfs) |
+		ACCR_HSS(info->hss) | ACCR_DMCFS(info->dmcfs);
+
+	ACCR = accr;
+
+	while ((ACSR & mask) != (accr & mask))
+		cpu_relax();
+}
+
+static int pxa3xx_cpufreq_verify(struct cpufreq_policy *policy)
+{
+	return cpufreq_frequency_table_verify(policy, pxa3xx_freqs_table);
+}
+
+static unsigned int pxa3xx_cpufreq_get(unsigned int cpu)
+{
+	return get_clk_frequency_khz(0);
+}
+
+static int pxa3xx_cpufreq_set(struct cpufreq_policy *policy,
+			      unsigned int target_freq,
+			      unsigned int relation)
+{
+	struct pxa3xx_freq_info *next;
+	struct cpufreq_freqs freqs;
+	unsigned long flags;
+	int idx;
+
+	if (policy->cpu != 0)
+		return -EINVAL;
+
+	/* Lookup the next frequency */
+	if (cpufreq_frequency_table_target(policy, pxa3xx_freqs_table,
+				target_freq, relation, &idx))
+		return -EINVAL;
+
+	next = &pxa3xx_freqs[idx];
+
+	freqs.old = policy->cur;
+	freqs.new = next->cpufreq_mhz * 1000;
+	freqs.cpu = policy->cpu;
+
+	pr_debug("CPU frequency from %d MHz to %d MHz%s\n",
+			freqs.old / 1000, freqs.new / 1000,
+			(freqs.old == freqs.new) ? " (skipped)" : "");
+
+	if (freqs.old == target_freq)
+		return 0;
+
+	cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+
+	local_irq_save(flags);
+	__update_core_freq(next);
+	__update_bus_freq(next);
+	local_irq_restore(flags);
+
+	cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+
+	return 0;
+}
+
+static __init int pxa3xx_cpufreq_init(struct cpufreq_policy *policy)
+{
+	int ret = -EINVAL;
+
+	/* set default policy and cpuinfo */
+	policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
+	policy->cpuinfo.min_freq = 104000;
+	policy->cpuinfo.max_freq = (cpu_is_pxa320()) ? 806000 : 624000;
+	policy->cpuinfo.transition_latency = 1000; /* FIXME: 1 ms, assumed */
+	policy->cur = policy->min = policy->max = get_clk_frequency_khz(0);
+
+	if (cpu_is_pxa300() || cpu_is_pxa310())
+		ret = setup_freqs_table(policy, ARRAY_AND_SIZE(pxa300_freqs));
+
+	if (cpu_is_pxa320())
+		ret = setup_freqs_table(policy, ARRAY_AND_SIZE(pxa320_freqs));
+
+	if (ret) {
+		pr_err("failed to setup frequency table\n");
+		return ret;
+	}
+
+	pr_info("CPUFREQ support for PXA3xx initialized\n");
+	return 0;
+}
+
+static struct cpufreq_driver pxa3xx_cpufreq_driver = {
+	.verify		= pxa3xx_cpufreq_verify,
+	.target		= pxa3xx_cpufreq_set,
+	.init		= pxa3xx_cpufreq_init,
+	.get		= pxa3xx_cpufreq_get,
+	.name		= "pxa3xx-cpufreq",
+};
+
+static int __init cpufreq_init(void)
+{
+	if (cpu_is_pxa3xx())
+		return cpufreq_register_driver(&pxa3xx_cpufreq_driver);
+
+	return 0;
+}
+module_init(cpufreq_init);
+
+static void __exit cpufreq_exit(void)
+{
+	cpufreq_unregister_driver(&pxa3xx_cpufreq_driver);
+}
+module_exit(cpufreq_exit);
+
+MODULE_DESCRIPTION("CPU frequency scaling driver for PXA3xx");
+MODULE_LICENSE("GPL");
diff --git a/arch/arm/mach-pxa/devices.h b/arch/arm/mach-pxa/devices.h
index 887c738..bb04af4 100644
--- a/arch/arm/mach-pxa/devices.h
+++ b/arch/arm/mach-pxa/devices.h
@@ -32,5 +32,6 @@
 extern struct platform_device pxa27x_device_pwm1;
 
 extern struct platform_device pxa3xx_device_nand;
+extern struct platform_device pxa3xx_device_i2c_power;
 
 void __init pxa_register_device(struct platform_device *dev, void *data);
diff --git a/arch/arm/mach-pxa/e330.c b/arch/arm/mach-pxa/e330.c
new file mode 100644
index 0000000..d488ede
--- /dev/null
+++ b/arch/arm/mach-pxa/e330.c
@@ -0,0 +1,43 @@
+/*
+ * Hardware definitions for the Toshiba eseries PDAs
+ *
+ * Copyright (c) 2003 Ian Molton <spyro@f2s.com>
+ *
+ * This file is licensed under
+ * the terms of the GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+
+#include <asm/setup.h>
+#include <asm/mach/arch.h>
+#include <asm/mach-types.h>
+
+#include <mach/mfp-pxa25x.h>
+#include <mach/hardware.h>
+#include <mach/udc.h>
+
+#include "generic.h"
+#include "eseries.h"
+
+static void __init e330_init(void)
+{
+	pxa_set_udc_info(&e7xx_udc_mach_info);
+}
+
+MACHINE_START(E330, "Toshiba e330")
+	/* Maintainer: Ian Molton (spyro@f2s.com) */
+	.phys_io	= 0x40000000,
+	.io_pg_offst	= (io_p2v(0x40000000) >> 18) & 0xfffc,
+	.boot_params	= 0xa0000100,
+	.map_io		= pxa_map_io,
+	.init_irq	= pxa25x_init_irq,
+	.fixup		= eseries_fixup,
+	.init_machine	= e330_init,
+	.timer		= &pxa_timer,
+MACHINE_END
+
diff --git a/arch/arm/mach-pxa/e350.c b/arch/arm/mach-pxa/e350.c
new file mode 100644
index 0000000..8ecbc54
--- /dev/null
+++ b/arch/arm/mach-pxa/e350.c
@@ -0,0 +1,43 @@
+/*
+ * Hardware definitions for the Toshiba eseries PDAs
+ *
+ * Copyright (c) 2003 Ian Molton <spyro@f2s.com>
+ *
+ * This file is licensed under
+ * the terms of the GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+
+#include <asm/setup.h>
+#include <asm/mach/arch.h>
+#include <asm/mach-types.h>
+
+#include <mach/mfp-pxa25x.h>
+#include <mach/hardware.h>
+#include <mach/udc.h>
+
+#include "generic.h"
+#include "eseries.h"
+
+static void __init e350_init(void)
+{
+	pxa_set_udc_info(&e7xx_udc_mach_info);
+}
+
+MACHINE_START(E350, "Toshiba e350")
+	/* Maintainer: Ian Molton (spyro@f2s.com) */
+	.phys_io	= 0x40000000,
+	.io_pg_offst	= (io_p2v(0x40000000) >> 18) & 0xfffc,
+	.boot_params	= 0xa0000100,
+	.map_io		= pxa_map_io,
+	.init_irq	= pxa25x_init_irq,
+	.fixup		= eseries_fixup,
+	.init_machine	= e350_init,
+	.timer		= &pxa_timer,
+MACHINE_END
+
diff --git a/arch/arm/mach-pxa/e400.c b/arch/arm/mach-pxa/e400.c
new file mode 100644
index 0000000..544bbaa
--- /dev/null
+++ b/arch/arm/mach-pxa/e400.c
@@ -0,0 +1,94 @@
+/*
+ * Hardware definitions for the Toshiba eseries PDAs
+ *
+ * Copyright (c) 2003 Ian Molton <spyro@f2s.com>
+ *
+ * This file is licensed under
+ * the terms of the GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+
+#include <asm/setup.h>
+#include <asm/mach/arch.h>
+#include <asm/mach-types.h>
+
+#include <mach/pxa-regs.h>
+#include <mach/mfp-pxa25x.h>
+#include <mach/hardware.h>
+
+#include <mach/pxafb.h>
+#include <mach/udc.h>
+
+#include "generic.h"
+#include "eseries.h"
+
+/* ------------------------ E400 LCD definitions ------------------------ */
+
+static struct pxafb_mode_info e400_pxafb_mode_info = {
+	.pixclock       = 140703,
+	.xres           = 240,
+	.yres           = 320,
+	.bpp            = 16,
+	.hsync_len      = 4,
+	.left_margin    = 28,
+	.right_margin   = 8,
+	.vsync_len      = 3,
+	.upper_margin   = 5,
+	.lower_margin   = 6,
+	.sync           = 0,
+};
+
+static struct pxafb_mach_info e400_pxafb_mach_info = {
+	.modes          = &e400_pxafb_mode_info,
+	.num_modes      = 1,
+	.lccr0          = LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
+	.lccr3          = 0,
+	.pxafb_backlight_power  = NULL,
+};
+
+/* ------------------------ E400 MFP config ----------------------------- */
+
+static unsigned long e400_pin_config[] __initdata = {
+	/* Chip selects */
+	GPIO15_nCS_1,   /* CS1 - Flash */
+	GPIO80_nCS_4,   /* CS4 - TMIO */
+
+	/* Clocks */
+	GPIO12_32KHz,
+
+	/* BTUART */
+	GPIO42_BTUART_RXD,
+	GPIO43_BTUART_TXD,
+	GPIO44_BTUART_CTS,
+	GPIO45_GPIO, /* Used by TMIO for #SUSPEND */
+
+	/* wakeup */
+	GPIO0_GPIO | WAKEUP_ON_EDGE_RISE,
+};
+
+/* ---------------------------------------------------------------------- */
+
+static void __init e400_init(void)
+{
+	pxa2xx_mfp_config(ARRAY_AND_SIZE(e400_pin_config));
+	set_pxa_fb_info(&e400_pxafb_mach_info);
+	pxa_set_udc_info(&e7xx_udc_mach_info);
+}
+
+MACHINE_START(E400, "Toshiba e400")
+	/* Maintainer: Ian Molton (spyro@f2s.com) */
+	.phys_io	= 0x40000000,
+	.io_pg_offst	= (io_p2v(0x40000000) >> 18) & 0xfffc,
+	.boot_params	= 0xa0000100,
+	.map_io		= pxa_map_io,
+	.init_irq	= pxa25x_init_irq,
+	.fixup		= eseries_fixup,
+	.init_machine	= e400_init,
+	.timer		= &pxa_timer,
+MACHINE_END
+
diff --git a/arch/arm/mach-pxa/e400_lcd.c b/arch/arm/mach-pxa/e400_lcd.c
deleted file mode 100644
index 2638841..0000000
--- a/arch/arm/mach-pxa/e400_lcd.c
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * e400_lcd.c
- *
- * (c) 2005 Ian Molton <spyro@f2s.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/kernel.h>
-#include <linux/init.h>
-#include <linux/module.h>
-
-#include <asm/mach-types.h>
-#include <mach/pxa-regs.h>
-#include <mach/pxafb.h>
-
-static struct pxafb_mode_info e400_pxafb_mode_info = {
-	.pixclock       = 140703,
-	.xres           = 240,
-	.yres           = 320,
-	.bpp            = 16,
-	.hsync_len      = 4,
-	.left_margin    = 28,
-	.right_margin   = 8,
-	.vsync_len      = 3,
-	.upper_margin   = 5,
-	.lower_margin   = 6,
-	.sync           = 0,
-};
-
-static struct pxafb_mach_info e400_pxafb_mach_info = {
-	.modes          = &e400_pxafb_mode_info,
-	.num_modes      = 1,
-	.lccr0          = LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
-	.lccr3          = 0,
-	.pxafb_backlight_power  = NULL,
-};
-
-static int __init e400_lcd_init(void)
-{
-	if (!machine_is_e400())
-		return -ENODEV;
-
-	set_pxa_fb_info(&e400_pxafb_mach_info);
-	return 0;
-}
-
-module_init(e400_lcd_init);
-
-MODULE_AUTHOR("Ian Molton <spyro@f2s.com>");
-MODULE_DESCRIPTION("e400 lcd driver");
-MODULE_LICENSE("GPLv2");
-
diff --git a/arch/arm/mach-pxa/e740.c b/arch/arm/mach-pxa/e740.c
new file mode 100644
index 0000000..c57a15b
--- /dev/null
+++ b/arch/arm/mach-pxa/e740.c
@@ -0,0 +1,169 @@
+/*
+ * Hardware definitions for the Toshiba eseries PDAs
+ *
+ * Copyright (c) 2003 Ian Molton <spyro@f2s.com>
+ *
+ * This file is licensed under
+ * the terms of the GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/fb.h>
+
+#include <video/w100fb.h>
+
+#include <asm/setup.h>
+#include <asm/mach/arch.h>
+#include <asm/mach-types.h>
+
+#include <mach/mfp-pxa25x.h>
+#include <mach/hardware.h>
+#include <mach/udc.h>
+
+#include "generic.h"
+#include "eseries.h"
+
+
+/* ------------------------ e740 video support --------------------------- */
+
+static struct w100_gen_regs e740_lcd_regs = {
+	.lcd_format =            0x00008023,
+	.lcdd_cntl1 =            0x0f000000,
+	.lcdd_cntl2 =            0x0003ffff,
+	.genlcd_cntl1 =          0x00ffff03,
+	.genlcd_cntl2 =          0x003c0f03,
+	.genlcd_cntl3 =          0x000143aa,
+};
+
+static struct w100_mode e740_lcd_mode = {
+	.xres            = 240,
+	.yres            = 320,
+	.left_margin     = 20,
+	.right_margin    = 28,
+	.upper_margin    = 9,
+	.lower_margin    = 8,
+	.crtc_ss         = 0x80140013,
+	.crtc_ls         = 0x81150110,
+	.crtc_gs         = 0x80050005,
+	.crtc_vpos_gs    = 0x000a0009,
+	.crtc_rev        = 0x0040010a,
+	.crtc_dclk       = 0xa906000a,
+	.crtc_gclk       = 0x80050108,
+	.crtc_goe        = 0x80050108,
+	.pll_freq        = 57,
+	.pixclk_divider         = 4,
+	.pixclk_divider_rotated = 4,
+	.pixclk_src     = CLK_SRC_XTAL,
+	.sysclk_divider  = 1,
+	.sysclk_src     = CLK_SRC_PLL,
+	.crtc_ps1_active =       0x41060010,
+};
+
+static struct w100_gpio_regs e740_w100_gpio_info = {
+	.init_data1 = 0x21002103,
+	.gpio_dir1  = 0xffffdeff,
+	.gpio_oe1   = 0x03c00643,
+	.init_data2 = 0x003f003f,
+	.gpio_dir2  = 0xffffffff,
+	.gpio_oe2   = 0x000000ff,
+};
+
+static struct w100fb_mach_info e740_fb_info = {
+	.modelist   = &e740_lcd_mode,
+	.num_modes  = 1,
+	.regs       = &e740_lcd_regs,
+	.gpio       = &e740_w100_gpio_info,
+	.xtal_freq = 14318000,
+	.xtal_dbl   = 1,
+};
+
+static struct resource e740_fb_resources[] = {
+	[0] = {
+		.start          = 0x0c000000,
+		.end            = 0x0cffffff,
+		.flags          = IORESOURCE_MEM,
+	},
+};
+
+static struct platform_device e740_fb_device = {
+	.name           = "w100fb",
+	.id             = -1,
+	.dev            = {
+		.platform_data  = &e740_fb_info,
+	},
+	.num_resources  = ARRAY_SIZE(e740_fb_resources),
+	.resource       = e740_fb_resources,
+};
+
+/* --------------------------- MFP Pin config -------------------------- */
+
+static unsigned long e740_pin_config[] __initdata = {
+	/* Chip selects */
+	GPIO15_nCS_1,   /* CS1 - Flash */
+	GPIO79_nCS_3,   /* CS3 - IMAGEON */
+	GPIO80_nCS_4,   /* CS4 - TMIO */
+
+	/* Clocks */
+	GPIO12_32KHz,
+
+	/* BTUART */
+	GPIO42_BTUART_RXD,
+	GPIO43_BTUART_TXD,
+	GPIO44_BTUART_CTS,
+	GPIO45_GPIO, /* Used by TMIO for #SUSPEND */
+
+	/* PC Card */
+	GPIO8_GPIO,   /* CD0 */
+	GPIO44_GPIO,  /* CD1 */
+	GPIO11_GPIO,  /* IRQ0 */
+	GPIO6_GPIO,   /* IRQ1 */
+	GPIO27_GPIO,  /* RST0 */
+	GPIO24_GPIO,  /* RST1 */
+	GPIO20_GPIO,  /* PWR0 */
+	GPIO23_GPIO,  /* PWR1 */
+	GPIO48_nPOE,
+	GPIO49_nPWE,
+	GPIO50_nPIOR,
+	GPIO51_nPIOW,
+	GPIO52_nPCE_1,
+	GPIO53_nPCE_2,
+	GPIO54_nPSKTSEL,
+	GPIO55_nPREG,
+	GPIO56_nPWAIT,
+	GPIO57_nIOIS16,
+
+	/* wakeup */
+	GPIO0_GPIO | WAKEUP_ON_EDGE_RISE,
+};
+
+/* ----------------------------------------------------------------------- */
+
+static struct platform_device *devices[] __initdata = {
+	&e740_fb_device,
+};
+
+static void __init e740_init(void)
+{
+	pxa2xx_mfp_config(ARRAY_AND_SIZE(e740_pin_config));
+	platform_add_devices(devices, ARRAY_SIZE(devices));
+	pxa_set_udc_info(&e7xx_udc_mach_info);
+}
+
+MACHINE_START(E740, "Toshiba e740")
+	/* Maintainer: Ian Molton (spyro@f2s.com) */
+	.phys_io	= 0x40000000,
+	.io_pg_offst	= (io_p2v(0x40000000) >> 18) & 0xfffc,
+	.boot_params	= 0xa0000100,
+	.map_io		= pxa_map_io,
+	.init_irq	= pxa25x_init_irq,
+	.fixup		= eseries_fixup,
+	.init_machine	= e740_init,
+	.timer		= &pxa_timer,
+MACHINE_END
+
diff --git a/arch/arm/mach-pxa/e740_lcd.c b/arch/arm/mach-pxa/e740_lcd.c
deleted file mode 100644
index 26bd599..0000000
--- a/arch/arm/mach-pxa/e740_lcd.c
+++ /dev/null
@@ -1,123 +0,0 @@
-/* e740_lcd.c
- *
- * This file contains the definitions for the LCD timings and functions
- * to control the LCD power / frontlighting via the w100fb driver.
- *
- * (c) 2005 Ian Molton <spyro@f2s.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/device.h>
-#include <linux/fb.h>
-#include <linux/err.h>
-#include <linux/platform_device.h>
-
-#include <asm/mach-types.h>
-
-#include <video/w100fb.h>
-
-/*
-**potential** shutdown routine - to be investigated
-devmem2 0x0c010528 w 0xff3fff00
-devmem2 0x0c010190 w 0x7FFF8000
-devmem2 0x0c0101b0 w 0x00FF0000
-devmem2 0x0c01008c w 0x00000000
-devmem2 0x0c010080 w 0x000000bf
-devmem2 0x0c010098 w 0x00000015
-devmem2 0x0c010088 w 0x4b000204
-devmem2 0x0c010098 w 0x0000001d
-*/
-
-static struct w100_gen_regs e740_lcd_regs = {
-	.lcd_format =            0x00008023,
-	.lcdd_cntl1 =            0x0f000000,
-	.lcdd_cntl2 =            0x0003ffff,
-	.genlcd_cntl1 =          0x00ffff03,
-	.genlcd_cntl2 =          0x003c0f03,
-	.genlcd_cntl3 =          0x000143aa,
-};
-
-static struct w100_mode e740_lcd_mode = {
-	.xres            = 240,
-	.yres            = 320,
-	.left_margin     = 20,
-	.right_margin    = 28,
-	.upper_margin    = 9,
-	.lower_margin    = 8,
-	.crtc_ss         = 0x80140013,
-	.crtc_ls         = 0x81150110,
-	.crtc_gs         = 0x80050005,
-	.crtc_vpos_gs    = 0x000a0009,
-	.crtc_rev        = 0x0040010a,
-	.crtc_dclk       = 0xa906000a,
-	.crtc_gclk       = 0x80050108,
-	.crtc_goe        = 0x80050108,
-	.pll_freq        = 57,
-	.pixclk_divider         = 4,
-	.pixclk_divider_rotated = 4,
-	.pixclk_src     = CLK_SRC_XTAL,
-	.sysclk_divider  = 1,
-	.sysclk_src     = CLK_SRC_PLL,
-	.crtc_ps1_active =       0x41060010,
-};
-
-
-static struct w100_gpio_regs e740_w100_gpio_info = {
-	.init_data1 = 0x21002103,
-	.gpio_dir1  = 0xffffdeff,
-	.gpio_oe1   = 0x03c00643,
-	.init_data2 = 0x003f003f,
-	.gpio_dir2  = 0xffffffff,
-	.gpio_oe2   = 0x000000ff,
-};
-
-static struct w100fb_mach_info e740_fb_info = {
-	.modelist   = &e740_lcd_mode,
-	.num_modes  = 1,
-	.regs       = &e740_lcd_regs,
-	.gpio       = &e740_w100_gpio_info,
-	.xtal_freq = 14318000,
-	.xtal_dbl   = 1,
-};
-
-static struct resource e740_fb_resources[] = {
-	[0] = {
-		.start          = 0x0c000000,
-		.end            = 0x0cffffff,
-		.flags          = IORESOURCE_MEM,
-	},
-};
-
-/* ----------------------- device declarations -------------------------- */
-
-
-static struct platform_device e740_fb_device = {
-	.name           = "w100fb",
-	.id             = -1,
-	.dev            = {
-		.platform_data  = &e740_fb_info,
-	},
-	.num_resources  = ARRAY_SIZE(e740_fb_resources),
-	.resource       = e740_fb_resources,
-};
-
-static int e740_lcd_init(void)
-{
-	int ret;
-
-	if (!machine_is_e740())
-		return -ENODEV;
-
-	return platform_device_register(&e740_fb_device);
-}
-
-module_init(e740_lcd_init);
-
-MODULE_AUTHOR("Ian Molton <spyro@f2s.com>");
-MODULE_DESCRIPTION("e740 lcd driver");
-MODULE_LICENSE("GPLv2");
diff --git a/arch/arm/mach-pxa/e750.c b/arch/arm/mach-pxa/e750.c
new file mode 100644
index 0000000..640e738
--- /dev/null
+++ b/arch/arm/mach-pxa/e750.c
@@ -0,0 +1,126 @@
+/*
+ * Hardware definitions for the Toshiba eseries PDAs
+ *
+ * Copyright (c) 2003 Ian Molton <spyro@f2s.com>
+ *
+ * This file is licensed under
+ * the terms of the GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/fb.h>
+
+#include <video/w100fb.h>
+
+#include <asm/setup.h>
+#include <asm/mach/arch.h>
+#include <asm/mach-types.h>
+
+#include <mach/mfp-pxa25x.h>
+#include <mach/hardware.h>
+#include <mach/udc.h>
+
+#include "generic.h"
+#include "eseries.h"
+
+/* ---------------------- E750 LCD definitions -------------------- */
+
+static struct w100_gen_regs e750_lcd_regs = {
+	.lcd_format =            0x00008003,
+	.lcdd_cntl1 =            0x00000000,
+	.lcdd_cntl2 =            0x0003ffff,
+	.genlcd_cntl1 =          0x00fff003,
+	.genlcd_cntl2 =          0x003c0f03,
+	.genlcd_cntl3 =          0x000143aa,
+};
+
+static struct w100_mode e750_lcd_mode = {
+	.xres            = 240,
+	.yres            = 320,
+	.left_margin     = 21,
+	.right_margin    = 22,
+	.upper_margin    = 5,
+	.lower_margin    = 4,
+	.crtc_ss         = 0x80150014,
+	.crtc_ls         = 0x8014000d,
+	.crtc_gs         = 0xc1000005,
+	.crtc_vpos_gs    = 0x00020147,
+	.crtc_rev        = 0x0040010a,
+	.crtc_dclk       = 0xa1700030,
+	.crtc_gclk       = 0x80cc0015,
+	.crtc_goe        = 0x80cc0015,
+	.crtc_ps1_active = 0x61060017,
+	.pll_freq        = 57,
+	.pixclk_divider         = 4,
+	.pixclk_divider_rotated = 4,
+	.pixclk_src     = CLK_SRC_XTAL,
+	.sysclk_divider  = 1,
+	.sysclk_src     = CLK_SRC_PLL,
+};
+
+static struct w100_gpio_regs e750_w100_gpio_info = {
+	.init_data1 = 0x01192f1b,
+	.gpio_dir1  = 0xd5ffdeff,
+	.gpio_oe1   = 0x000020bf,
+	.init_data2 = 0x010f010f,
+	.gpio_dir2  = 0xffffffff,
+	.gpio_oe2   = 0x000001cf,
+};
+
+static struct w100fb_mach_info e750_fb_info = {
+	.modelist   = &e750_lcd_mode,
+	.num_modes  = 1,
+	.regs       = &e750_lcd_regs,
+	.gpio       = &e750_w100_gpio_info,
+	.xtal_freq  = 14318000,
+	.xtal_dbl   = 1,
+};
+
+static struct resource e750_fb_resources[] = {
+	[0] = {
+		.start          = 0x0c000000,
+		.end            = 0x0cffffff,
+		.flags          = IORESOURCE_MEM,
+	},
+};
+
+static struct platform_device e750_fb_device = {
+	.name           = "w100fb",
+	.id             = -1,
+	.dev            = {
+		.platform_data  = &e750_fb_info,
+	},
+	.num_resources  = ARRAY_SIZE(e750_fb_resources),
+	.resource       = e750_fb_resources,
+};
+
+/* ----------------------------------------------------------------------- */
+
+static struct platform_device *devices[] __initdata = {
+	&e750_fb_device,
+};
+
+static void __init e750_init(void)
+{
+	platform_add_devices(devices, ARRAY_SIZE(devices));
+	pxa_set_udc_info(&e7xx_udc_mach_info);
+}
+
+MACHINE_START(E750, "Toshiba e750")
+	/* Maintainer: Ian Molton (spyro@f2s.com) */
+	.phys_io	= 0x40000000,
+	.io_pg_offst	= (io_p2v(0x40000000) >> 18) & 0xfffc,
+	.boot_params	= 0xa0000100,
+	.map_io		= pxa_map_io,
+	.init_irq	= pxa25x_init_irq,
+	.fixup		= eseries_fixup,
+	.init_machine	= e750_init,
+	.timer		= &pxa_timer,
+MACHINE_END
+
diff --git a/arch/arm/mach-pxa/e750_lcd.c b/arch/arm/mach-pxa/e750_lcd.c
deleted file mode 100644
index 75edc3b..0000000
--- a/arch/arm/mach-pxa/e750_lcd.c
+++ /dev/null
@@ -1,109 +0,0 @@
-/* e750_lcd.c
- *
- * This file contains the definitions for the LCD timings and functions
- * to control the LCD power / frontlighting via the w100fb driver.
- *
- * (c) 2005 Ian Molton <spyro@f2s.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/device.h>
-#include <linux/fb.h>
-#include <linux/err.h>
-#include <linux/platform_device.h>
-
-#include <asm/mach-types.h>
-
-#include <video/w100fb.h>
-
-static struct w100_gen_regs e750_lcd_regs = {
-	.lcd_format =            0x00008003,
-	.lcdd_cntl1 =            0x00000000,
-	.lcdd_cntl2 =            0x0003ffff,
-	.genlcd_cntl1 =          0x00fff003,
-	.genlcd_cntl2 =          0x003c0f03,
-	.genlcd_cntl3 =          0x000143aa,
-};
-
-static struct w100_mode e750_lcd_mode = {
-	.xres            = 240,
-	.yres            = 320,
-	.left_margin     = 21,
-	.right_margin    = 22,
-	.upper_margin    = 5,
-	.lower_margin    = 4,
-	.crtc_ss         = 0x80150014,
-	.crtc_ls         = 0x8014000d,
-	.crtc_gs         = 0xc1000005,
-	.crtc_vpos_gs    = 0x00020147,
-	.crtc_rev        = 0x0040010a,
-	.crtc_dclk       = 0xa1700030,
-	.crtc_gclk       = 0x80cc0015,
-	.crtc_goe        = 0x80cc0015,
-	.crtc_ps1_active = 0x61060017,
-	.pll_freq        = 57,
-	.pixclk_divider         = 4,
-	.pixclk_divider_rotated = 4,
-	.pixclk_src     = CLK_SRC_XTAL,
-	.sysclk_divider  = 1,
-	.sysclk_src     = CLK_SRC_PLL,
-};
-
-
-static struct w100_gpio_regs e750_w100_gpio_info = {
-	.init_data1 = 0x01192f1b,
-	.gpio_dir1  = 0xd5ffdeff,
-	.gpio_oe1   = 0x000020bf,
-	.init_data2 = 0x010f010f,
-	.gpio_dir2  = 0xffffffff,
-	.gpio_oe2   = 0x000001cf,
-};
-
-static struct w100fb_mach_info e750_fb_info = {
-	.modelist   = &e750_lcd_mode,
-	.num_modes  = 1,
-	.regs       = &e750_lcd_regs,
-	.gpio       = &e750_w100_gpio_info,
-	.xtal_freq  = 14318000,
-	.xtal_dbl   = 1,
-};
-
-static struct resource e750_fb_resources[] = {
-	[0] = {
-		.start          = 0x0c000000,
-		.end            = 0x0cffffff,
-		.flags          = IORESOURCE_MEM,
-	},
-};
-
-/* ----------------------- device declarations -------------------------- */
-
-
-static struct platform_device e750_fb_device = {
-	.name           = "w100fb",
-	.id             = -1,
-	.dev            = {
-		.platform_data  = &e750_fb_info,
-	},
-	.num_resources  = ARRAY_SIZE(e750_fb_resources),
-	.resource       = e750_fb_resources,
-};
-
-static int e750_lcd_init(void)
-{
-	if (!machine_is_e750())
-		return -ENODEV;
-
-	return platform_device_register(&e750_fb_device);
-}
-
-module_init(e750_lcd_init);
-
-MODULE_AUTHOR("Ian Molton <spyro@f2s.com>");
-MODULE_DESCRIPTION("e750 lcd driver");
-MODULE_LICENSE("GPLv2");
diff --git a/arch/arm/mach-pxa/e800.c b/arch/arm/mach-pxa/e800.c
new file mode 100644
index 0000000..a293e09
--- /dev/null
+++ b/arch/arm/mach-pxa/e800.c
@@ -0,0 +1,186 @@
+/*
+ * Hardware definitions for the Toshiba eseries PDAs
+ *
+ * Copyright (c) 2003 Ian Molton <spyro@f2s.com>
+ *
+ * This file is licensed under
+ * the terms of the GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/fb.h>
+
+#include <video/w100fb.h>
+
+#include <asm/setup.h>
+#include <asm/mach/arch.h>
+#include <asm/mach-types.h>
+
+#include <mach/mfp-pxa25x.h>
+#include <mach/hardware.h>
+#include <mach/eseries-gpio.h>
+#include <mach/udc.h>
+
+#include "generic.h"
+#include "eseries.h"
+
+/* ------------------------ e800 LCD definitions ------------------------- */
+
+static struct w100_gen_regs e800_lcd_regs = {
+	.lcd_format =            0x00008003,
+	.lcdd_cntl1 =            0x02a00000,
+	.lcdd_cntl2 =            0x0003ffff,
+	.genlcd_cntl1 =          0x000ff2a3,
+	.genlcd_cntl2 =          0x000002a3,
+	.genlcd_cntl3 =          0x000102aa,
+};
+
+static struct w100_mode e800_lcd_mode[2] = {
+	[0] = {
+		.xres            = 480,
+		.yres            = 640,
+		.left_margin     = 52,
+		.right_margin    = 148,
+		.upper_margin    = 2,
+		.lower_margin    = 6,
+		.crtc_ss         = 0x80350034,
+		.crtc_ls         = 0x802b0026,
+		.crtc_gs         = 0x80160016,
+		.crtc_vpos_gs    = 0x00020003,
+		.crtc_rev        = 0x0040001d,
+		.crtc_dclk       = 0xe0000000,
+		.crtc_gclk       = 0x82a50049,
+		.crtc_goe        = 0x80ee001c,
+		.crtc_ps1_active = 0x00000000,
+		.pll_freq        = 128,
+		.pixclk_divider         = 4,
+		.pixclk_divider_rotated = 6,
+		.pixclk_src     = CLK_SRC_PLL,
+		.sysclk_divider  = 0,
+		.sysclk_src     = CLK_SRC_PLL,
+	},
+	[1] = {
+		.xres            = 240,
+		.yres            = 320,
+		.left_margin     = 15,
+		.right_margin    = 88,
+		.upper_margin    = 0,
+		.lower_margin    = 7,
+		.crtc_ss         = 0xd010000f,
+		.crtc_ls         = 0x80070003,
+		.crtc_gs         = 0x80000000,
+		.crtc_vpos_gs    = 0x01460147,
+		.crtc_rev        = 0x00400003,
+		.crtc_dclk       = 0xa1700030,
+		.crtc_gclk       = 0x814b0008,
+		.crtc_goe        = 0x80cc0015,
+		.crtc_ps1_active = 0x00000000,
+		.pll_freq        = 100,
+		.pixclk_divider         = 6, /* Wince uses 14 which gives a */
+		.pixclk_divider_rotated = 6, /* 7MHz Pclk. We use a 14MHz one */
+		.pixclk_src     = CLK_SRC_PLL,
+		.sysclk_divider  = 0,
+		.sysclk_src     = CLK_SRC_PLL,
+	}
+};
+
+
+static struct w100_gpio_regs e800_w100_gpio_info = {
+	.init_data1 = 0xc13fc019,
+	.gpio_dir1  = 0x3e40df7f,
+	.gpio_oe1   = 0x003c3000,
+	.init_data2 = 0x00000000,
+	.gpio_dir2  = 0x00000000,
+	.gpio_oe2   = 0x00000000,
+};
+
+static struct w100_mem_info e800_w100_mem_info = {
+	.ext_cntl        = 0x09640011,
+	.sdram_mode_reg  = 0x00600021,
+	.ext_timing_cntl = 0x10001545,
+	.io_cntl         = 0x7ddd7333,
+	.size            = 0x1fffff,
+};
+
+static void e800_tg_change(struct w100fb_par *par)
+{
+	unsigned long tmp;
+
+	tmp = w100fb_gpio_read(W100_GPIO_PORT_A);
+	if (par->mode->xres == 480)
+		tmp |= 0x100;
+	else
+		tmp &= ~0x100;
+	w100fb_gpio_write(W100_GPIO_PORT_A, tmp);
+}
+
+static struct w100_tg_info e800_tg_info = {
+	.change = e800_tg_change,
+};
+
+static struct w100fb_mach_info e800_fb_info = {
+	.modelist   = e800_lcd_mode,
+	.num_modes  = 2,
+	.regs       = &e800_lcd_regs,
+	.gpio       = &e800_w100_gpio_info,
+	.mem        = &e800_w100_mem_info,
+	.tg         = &e800_tg_info,
+	.xtal_freq  = 16000000,
+};
+
+static struct resource e800_fb_resources[] = {
+	[0] = {
+		.start          = 0x0c000000,
+		.end            = 0x0cffffff,
+		.flags          = IORESOURCE_MEM,
+	},
+};
+
+static struct platform_device e800_fb_device = {
+	.name           = "w100fb",
+	.id             = -1,
+	.dev            = {
+		.platform_data  = &e800_fb_info,
+	},
+	.num_resources  = ARRAY_SIZE(e800_fb_resources),
+	.resource       = e800_fb_resources,
+};
+
+/* --------------------------- UDC definitions --------------------------- */
+
+static struct pxa2xx_udc_mach_info e800_udc_mach_info = {
+	.gpio_vbus   = GPIO_E800_USB_DISC,
+	.gpio_pullup = GPIO_E800_USB_PULLUP,
+	.gpio_pullup_inverted = 1
+};
+
+/* ----------------------------------------------------------------------- */
+
+static struct platform_device *devices[] __initdata = {
+	&e800_fb_device,
+};
+
+static void __init e800_init(void)
+{
+	platform_add_devices(devices, ARRAY_SIZE(devices));
+	pxa_set_udc_info(&e800_udc_mach_info);
+}
+
+MACHINE_START(E800, "Toshiba e800")
+	/* Maintainer: Ian Molton (spyro@f2s.com) */
+	.phys_io	= 0x40000000,
+	.io_pg_offst	= (io_p2v(0x40000000) >> 18) & 0xfffc,
+	.boot_params	= 0xa0000100,
+	.map_io		= pxa_map_io,
+	.init_irq	= pxa25x_init_irq,
+	.fixup		= eseries_fixup,
+	.init_machine	= e800_init,
+	.timer		= &pxa_timer,
+MACHINE_END
+
diff --git a/arch/arm/mach-pxa/e800_lcd.c b/arch/arm/mach-pxa/e800_lcd.c
deleted file mode 100644
index e6aeab0e..0000000
--- a/arch/arm/mach-pxa/e800_lcd.c
+++ /dev/null
@@ -1,159 +0,0 @@
-/* e800_lcd.c
- *
- * This file contains the definitions for the LCD timings and functions
- * to control the LCD power / frontlighting via the w100fb driver.
- *
- * (c) 2005 Ian Molton <spyro@f2s.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/device.h>
-#include <linux/fb.h>
-#include <linux/err.h>
-#include <linux/platform_device.h>
-
-#include <asm/mach-types.h>
-
-#include <video/w100fb.h>
-
-static struct w100_gen_regs e800_lcd_regs = {
-	.lcd_format =            0x00008003,
-	.lcdd_cntl1 =            0x02a00000,
-	.lcdd_cntl2 =            0x0003ffff,
-	.genlcd_cntl1 =          0x000ff2a3,
-	.genlcd_cntl2 =          0x000002a3,
-	.genlcd_cntl3 =          0x000102aa,
-};
-
-static struct w100_mode e800_lcd_mode[2] = {
-	[0] = {
-		.xres            = 480,
-		.yres            = 640,
-		.left_margin     = 52,
-		.right_margin    = 148,
-		.upper_margin    = 2,
-		.lower_margin    = 6,
-		.crtc_ss         = 0x80350034,
-		.crtc_ls         = 0x802b0026,
-		.crtc_gs         = 0x80160016,
-		.crtc_vpos_gs    = 0x00020003,
-		.crtc_rev        = 0x0040001d,
-		.crtc_dclk       = 0xe0000000,
-		.crtc_gclk       = 0x82a50049,
-		.crtc_goe        = 0x80ee001c,
-		.crtc_ps1_active = 0x00000000,
-		.pll_freq        = 128,
-		.pixclk_divider         = 4,
-		.pixclk_divider_rotated = 6,
-		.pixclk_src     = CLK_SRC_PLL,
-		.sysclk_divider  = 0,
-		.sysclk_src     = CLK_SRC_PLL,
-	},
-	[1] = {
-		.xres            = 240,
-		.yres            = 320,
-		.left_margin     = 15,
-		.right_margin    = 88,
-		.upper_margin    = 0,
-		.lower_margin    = 7,
-		.crtc_ss         = 0xd010000f,
-		.crtc_ls         = 0x80070003,
-		.crtc_gs         = 0x80000000,
-		.crtc_vpos_gs    = 0x01460147,
-		.crtc_rev        = 0x00400003,
-		.crtc_dclk       = 0xa1700030,
-		.crtc_gclk       = 0x814b0008,
-		.crtc_goe        = 0x80cc0015,
-		.crtc_ps1_active = 0x00000000,
-		.pll_freq        = 100,
-		.pixclk_divider         = 6, /* Wince uses 14 which gives a 7MHz pclk. */
-		.pixclk_divider_rotated = 6, /* we want a 14MHz one (much nicer to look at) */
-		.pixclk_src     = CLK_SRC_PLL,
-		.sysclk_divider  = 0,
-		.sysclk_src     = CLK_SRC_PLL,
-	}
-};
-
-
-static struct w100_gpio_regs e800_w100_gpio_info = {
-	.init_data1 = 0xc13fc019,
-	.gpio_dir1  = 0x3e40df7f,
-	.gpio_oe1   = 0x003c3000,
-	.init_data2 = 0x00000000,
-	.gpio_dir2  = 0x00000000,
-	.gpio_oe2   = 0x00000000,
-};
-
-static struct w100_mem_info e800_w100_mem_info = {
-	.ext_cntl        = 0x09640011,
-	.sdram_mode_reg  = 0x00600021,
-	.ext_timing_cntl = 0x10001545,
-	.io_cntl         = 0x7ddd7333,
-	.size            = 0x1fffff,
-};
-
-static void e800_tg_change(struct w100fb_par *par)
-{
-	unsigned long tmp;
-
-	tmp = w100fb_gpio_read(W100_GPIO_PORT_A);
-	if (par->mode->xres == 480)
-		tmp |= 0x100;
-	else
-		tmp &= ~0x100;
-	w100fb_gpio_write(W100_GPIO_PORT_A, tmp);
-}
-
-static struct w100_tg_info e800_tg_info = {
-	.change = e800_tg_change,
-};
-
-static struct w100fb_mach_info e800_fb_info = {
-	.modelist   = e800_lcd_mode,
-	.num_modes  = 2,
-	.regs       = &e800_lcd_regs,
-	.gpio       = &e800_w100_gpio_info,
-	.mem        = &e800_w100_mem_info,
-	.tg         = &e800_tg_info,
-	.xtal_freq  = 16000000,
-};
-
-static struct resource e800_fb_resources[] = {
-	[0] = {
-		.start          = 0x0c000000,
-		.end            = 0x0cffffff,
-		.flags          = IORESOURCE_MEM,
-	},
-};
-
-/* ----------------------- device declarations -------------------------- */
-
-
-static struct platform_device e800_fb_device = {
-	.name           = "w100fb",
-	.id             = -1,
-	.dev            = {
-		.platform_data  = &e800_fb_info,
-	},
-	.num_resources  = ARRAY_SIZE(e800_fb_resources),
-	.resource       = e800_fb_resources,
-};
-
-static int e800_lcd_init(void)
-{
-	if (!machine_is_e800())
-		return -ENODEV;
-
-	return platform_device_register(&e800_fb_device);
-}
-
-module_init(e800_lcd_init);
-
-MODULE_AUTHOR("Ian Molton <spyro@f2s.com>");
-MODULE_DESCRIPTION("e800 lcd driver");
-MODULE_LICENSE("GPLv2");
diff --git a/arch/arm/mach-pxa/em-x270.c b/arch/arm/mach-pxa/em-x270.c
index 7a0a681..f5ed803 100644
--- a/arch/arm/mach-pxa/em-x270.c
+++ b/arch/arm/mach-pxa/em-x270.c
@@ -373,10 +373,6 @@
 #if defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE)
 static int em_x270_ohci_init(struct device *dev)
 {
-	/* Set the Power Control Polarity Low */
-	UHCHR = (UHCHR | UHCHR_PCPL) &
-		~(UHCHR_SSEP1 | UHCHR_SSEP2 | UHCHR_SSE);
-
 	/* enable port 2 transiever */
 	UP2OCR = UP2OCR_HXS | UP2OCR_HXOE;
 
@@ -385,6 +381,7 @@
 
 static struct pxaohci_platform_data em_x270_ohci_platform_data = {
 	.port_mode	= PMM_PERPORT_MODE,
+	.flags		= ENABLE_PORT1 | ENABLE_PORT2 | POWER_CONTROL_LOW,
 	.init		= em_x270_ohci_init,
 };
 
diff --git a/arch/arm/mach-pxa/eseries.c b/arch/arm/mach-pxa/eseries.c
index 001a252..d28849b 100644
--- a/arch/arm/mach-pxa/eseries.c
+++ b/arch/arm/mach-pxa/eseries.c
@@ -19,68 +19,13 @@
 
 #include <mach/mfp-pxa25x.h>
 #include <mach/hardware.h>
+#include <mach/eseries-gpio.h>
+#include <mach/udc.h>
 
 #include "generic.h"
 
-static unsigned long e740_pin_config[] __initdata = {
-	/* Chip selects */
-	GPIO15_nCS_1,   /* CS1 - Flash */
-	GPIO79_nCS_3,   /* CS3 - IMAGEON */
-	GPIO80_nCS_4,   /* CS4 - TMIO */
-
-	/* Clocks */
-	GPIO12_32KHz,
-
-	/* BTUART */
-	GPIO42_BTUART_RXD,
-	GPIO43_BTUART_TXD,
-	GPIO44_BTUART_CTS,
-	GPIO45_GPIO, /* Used by TMIO for #SUSPEND */
-
-	/* PC Card */
-	GPIO8_GPIO,   /* CD0 */
-	GPIO44_GPIO,  /* CD1 */
-	GPIO11_GPIO,  /* IRQ0 */
-	GPIO6_GPIO,   /* IRQ1 */
-	GPIO27_GPIO,  /* RST0 */
-	GPIO24_GPIO,  /* RST1 */
-	GPIO20_GPIO,  /* PWR0 */
-	GPIO23_GPIO,  /* PWR1 */
-	GPIO48_nPOE,
-	GPIO49_nPWE,
-	GPIO50_nPIOR,
-	GPIO51_nPIOW,
-	GPIO52_nPCE_1,
-	GPIO53_nPCE_2,
-	GPIO54_nPSKTSEL,
-	GPIO55_nPREG,
-	GPIO56_nPWAIT,
-	GPIO57_nIOIS16,
-
-	/* wakeup */
-	GPIO0_GPIO | WAKEUP_ON_EDGE_RISE,
-};
-
-static unsigned long e400_pin_config[] __initdata = {
-	/* Chip selects */
-	GPIO15_nCS_1,   /* CS1 - Flash */
-	GPIO80_nCS_4,   /* CS4 - TMIO */
-
-	/* Clocks */
-	GPIO12_32KHz,
-
-	/* BTUART */
-	GPIO42_BTUART_RXD,
-	GPIO43_BTUART_TXD,
-	GPIO44_BTUART_CTS,
-	GPIO45_GPIO, /* Used by TMIO for #SUSPEND */
-
-	/* wakeup */
-	GPIO0_GPIO | WAKEUP_ON_EDGE_RISE,
-};
-
 /* Only e800 has 128MB RAM */
-static void __init eseries_fixup(struct machine_desc *desc,
+void __init eseries_fixup(struct machine_desc *desc,
 	struct tag *tags, char **cmdline, struct meminfo *mi)
 {
 	mi->nr_banks=1;
@@ -92,95 +37,9 @@
 		mi->bank[0].size = (64*1024*1024);
 }
 
-static void __init e740_init(void)
-{
-	pxa2xx_mfp_config(ARRAY_AND_SIZE(e740_pin_config));
-}
-
-static void __init e400_init(void)
-{
-	pxa2xx_mfp_config(ARRAY_AND_SIZE(e400_pin_config));
-}
-
-/* e-series machine definitions */
-
-#ifdef CONFIG_MACH_E330
-MACHINE_START(E330, "Toshiba e330")
-	/* Maintainer: Ian Molton (spyro@f2s.com) */
-	.phys_io	= 0x40000000,
-	.io_pg_offst	= (io_p2v(0x40000000) >> 18) & 0xfffc,
-	.boot_params	= 0xa0000100,
-	.map_io		= pxa_map_io,
-	.init_irq	= pxa25x_init_irq,
-	.fixup		= eseries_fixup,
-	.timer		= &pxa_timer,
-MACHINE_END
-#endif
-
-#ifdef CONFIG_MACH_E350
-MACHINE_START(E350, "Toshiba e350")
-	/* Maintainer: Ian Molton (spyro@f2s.com) */
-	.phys_io	= 0x40000000,
-	.io_pg_offst	= (io_p2v(0x40000000) >> 18) & 0xfffc,
-	.boot_params	= 0xa0000100,
-	.map_io		= pxa_map_io,
-	.init_irq	= pxa25x_init_irq,
-	.fixup		= eseries_fixup,
-	.timer		= &pxa_timer,
-MACHINE_END
-#endif
-
-#ifdef CONFIG_MACH_E740
-MACHINE_START(E740, "Toshiba e740")
-	/* Maintainer: Ian Molton (spyro@f2s.com) */
-	.phys_io	= 0x40000000,
-	.io_pg_offst	= (io_p2v(0x40000000) >> 18) & 0xfffc,
-	.boot_params	= 0xa0000100,
-	.map_io		= pxa_map_io,
-	.init_irq	= pxa25x_init_irq,
-	.fixup		= eseries_fixup,
-	.init_machine	= e740_init,
-	.timer		= &pxa_timer,
-MACHINE_END
-#endif
-
-#ifdef CONFIG_MACH_E750
-MACHINE_START(E750, "Toshiba e750")
-	/* Maintainer: Ian Molton (spyro@f2s.com) */
-	.phys_io	= 0x40000000,
-	.io_pg_offst	= (io_p2v(0x40000000) >> 18) & 0xfffc,
-	.boot_params	= 0xa0000100,
-	.map_io		= pxa_map_io,
-	.init_irq	= pxa25x_init_irq,
-	.fixup		= eseries_fixup,
-	.timer		= &pxa_timer,
-MACHINE_END
-#endif
-
-#ifdef CONFIG_MACH_E400
-MACHINE_START(E400, "Toshiba e400")
-	/* Maintainer: Ian Molton (spyro@f2s.com) */
-	.phys_io	= 0x40000000,
-	.io_pg_offst	= (io_p2v(0x40000000) >> 18) & 0xfffc,
-	.boot_params	= 0xa0000100,
-	.map_io		= pxa_map_io,
-	.init_irq	= pxa25x_init_irq,
-	.fixup		= eseries_fixup,
-	.init_machine	= e400_init,
-	.timer		= &pxa_timer,
-MACHINE_END
-#endif
-
-#ifdef CONFIG_MACH_E800
-MACHINE_START(E800, "Toshiba e800")
-	/* Maintainer: Ian Molton (spyro@f2s.com) */
-	.phys_io	= 0x40000000,
-	.io_pg_offst	= (io_p2v(0x40000000) >> 18) & 0xfffc,
-	.boot_params	= 0xa0000100,
-	.map_io		= pxa_map_io,
-	.init_irq	= pxa25x_init_irq,
-	.fixup		= eseries_fixup,
-	.timer		= &pxa_timer,
-MACHINE_END
-#endif
+struct pxa2xx_udc_mach_info e7xx_udc_mach_info = {
+	.gpio_vbus   = GPIO_E7XX_USB_DISC,
+	.gpio_pullup = GPIO_E7XX_USB_PULLUP,
+	.gpio_pullup_inverted = 1
+};
 
diff --git a/arch/arm/mach-pxa/eseries.h b/arch/arm/mach-pxa/eseries.h
new file mode 100644
index 0000000..a83f88d
--- /dev/null
+++ b/arch/arm/mach-pxa/eseries.h
@@ -0,0 +1,4 @@
+void __init eseries_fixup(struct machine_desc *desc,
+	struct tag *tags, char **cmdline, struct meminfo *mi);
+
+extern struct pxa2xx_udc_mach_info e7xx_udc_mach_info;
diff --git a/arch/arm/mach-pxa/eseries_udc.c b/arch/arm/mach-pxa/eseries_udc.c
deleted file mode 100644
index d622c04..0000000
--- a/arch/arm/mach-pxa/eseries_udc.c
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * UDC functions for the Toshiba e-series PDAs
- *
- * Copyright (c) Ian Molton 2003
- *
- * This file is licensed under
- * the terms of the GNU General Public License version 2. This program
- * is licensed "as is" without any warranty of any kind, whether express
- * or implied.
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/device.h>
-
-#include <mach/udc.h>
-#include <mach/eseries-gpio.h>
-#include <mach/hardware.h>
-#include <mach/pxa-regs.h>
-#include <asm/mach/arch.h>
-#include <asm/mach-types.h>
-#include <asm/mach/map.h>
-#include <asm/domain.h>
-
-/* local PXA generic code */
-#include "generic.h"
-
-static struct pxa2xx_udc_mach_info e7xx_udc_mach_info = {
-	.gpio_vbus   = GPIO_E7XX_USB_DISC,
-	.gpio_pullup = GPIO_E7XX_USB_PULLUP,
-	.gpio_pullup_inverted = 1
-};
-
-static struct pxa2xx_udc_mach_info e800_udc_mach_info = {
-	.gpio_vbus   = GPIO_E800_USB_DISC,
-	.gpio_pullup = GPIO_E800_USB_PULLUP,
-	.gpio_pullup_inverted = 1
-};
-
-static int __init eseries_udc_init(void)
-{
-	if (machine_is_e330() || machine_is_e350() ||
-	    machine_is_e740() || machine_is_e750() ||
-	    machine_is_e400())
-		pxa_set_udc_info(&e7xx_udc_mach_info);
-	else if (machine_is_e800())
-		pxa_set_udc_info(&e800_udc_mach_info);
-
-	return 0;
-}
-
-module_init(eseries_udc_init);
-
-MODULE_AUTHOR("Ian Molton <spyro@f2s.com>");
-MODULE_DESCRIPTION("eseries UDC support");
-MODULE_LICENSE("GPLv2");
diff --git a/arch/arm/mach-pxa/generic.c b/arch/arm/mach-pxa/generic.c
index ceaed00..85ed0b3 100644
--- a/arch/arm/mach-pxa/generic.c
+++ b/arch/arm/mach-pxa/generic.c
@@ -46,7 +46,7 @@
  */
 unsigned int get_clk_frequency_khz(int info)
 {
-	if (cpu_is_pxa21x() || cpu_is_pxa25x())
+	if (cpu_is_pxa25x())
 		return pxa25x_get_clk_frequency_khz(info);
 	else if (cpu_is_pxa27x())
 		return pxa27x_get_clk_frequency_khz(info);
@@ -60,7 +60,7 @@
  */
 unsigned int get_memclk_frequency_10khz(void)
 {
-	if (cpu_is_pxa21x() || cpu_is_pxa25x())
+	if (cpu_is_pxa25x())
 		return pxa25x_get_memclk_frequency_10khz();
 	else if (cpu_is_pxa27x())
 		return pxa27x_get_memclk_frequency_10khz();
@@ -88,11 +88,6 @@
 		.pfn		= __phys_to_pfn(0x48000000),
 		.length		= 0x00200000,
 		.type		= MT_DEVICE
-	}, {	/* USB host */
-		.virtual	=  0xf8000000,
-		.pfn		= __phys_to_pfn(0x4c000000),
-		.length		= 0x00100000,
-		.type		= MT_DEVICE
 	}, {	/* Camera */
 		.virtual	=  0xfa000000,
 		.pfn		= __phys_to_pfn(0x50000000),
diff --git a/arch/arm/mach-pxa/generic.h b/arch/arm/mach-pxa/generic.h
index 041c048..dc876a8 100644
--- a/arch/arm/mach-pxa/generic.h
+++ b/arch/arm/mach-pxa/generic.h
@@ -65,4 +65,5 @@
 
 extern struct sysdev_class pxa_irq_sysclass;
 extern struct sysdev_class pxa_gpio_sysclass;
+extern struct sysdev_class pxa2xx_mfp_sysclass;
 extern struct sysdev_class pxa3xx_mfp_sysclass;
diff --git a/arch/arm/mach-pxa/gpio.c b/arch/arm/mach-pxa/gpio.c
index 07acc1b..14930cf 100644
--- a/arch/arm/mach-pxa/gpio.c
+++ b/arch/arm/mach-pxa/gpio.c
@@ -16,10 +16,10 @@
 #include <linux/module.h>
 #include <linux/irq.h>
 #include <linux/sysdev.h>
+#include <linux/io.h>
 
 #include <asm/gpio.h>
 #include <mach/hardware.h>
-#include <asm/io.h>
 #include <mach/pxa-regs.h>
 #include <mach/pxa2xx-gpio.h>
 
@@ -275,7 +275,7 @@
 			loop = 1;
 
 			n = PXA_GPIO_IRQ_BASE + bit;
-			desc_handle_irq(n, irq_desc + n);
+			generic_handle_irq(n);
 
 			bit = find_next_bit(gedr, GEDR_BITS, bit + 1);
 		}
diff --git a/arch/arm/mach-pxa/gumstix.c b/arch/arm/mach-pxa/gumstix.c
index c009247..d8962a0 100644
--- a/arch/arm/mach-pxa/gumstix.c
+++ b/arch/arm/mach-pxa/gumstix.c
@@ -20,8 +20,12 @@
 #include <linux/init.h>
 #include <linux/platform_device.h>
 #include <linux/interrupt.h>
+#include <linux/delay.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
+#include <linux/gpio.h>
+#include <linux/err.h>
+#include <linux/clk.h>
 
 #include <asm/setup.h>
 #include <asm/memory.h>
@@ -40,7 +44,7 @@
 
 #include <mach/pxa-regs.h>
 #include <mach/pxa2xx-regs.h>
-#include <mach/pxa2xx-gpio.h>
+#include <mach/mfp-pxa25x.h>
 
 #include "generic.h"
 
@@ -85,21 +89,8 @@
 };
 
 #ifdef CONFIG_MMC_PXA
-static struct pxamci_platform_data gumstix_mci_platform_data;
-
-static int gumstix_mci_init(struct device *dev, irq_handler_t detect_int,
-				void *data)
-{
-	pxa_gpio_mode(GPIO6_MMCCLK_MD);
-	pxa_gpio_mode(GPIO53_MMCCLK_MD);
-	pxa_gpio_mode(GPIO8_MMCCS0_MD);
-
-	return 0;
-}
-
 static struct pxamci_platform_data gumstix_mci_platform_data = {
 	.ocr_mask	= MMC_VDD_32_33|MMC_VDD_33_34,
-	.init		= gumstix_mci_init,
 };
 
 static void __init gumstix_mmc_init(void)
@@ -109,11 +100,11 @@
 #else
 static void __init gumstix_mmc_init(void)
 {
-	printk(KERN_INFO "Gumstix mmc disabled\n");
+	pr_debug("Gumstix mmc disabled\n");
 }
 #endif
 
-#ifdef CONFIG_USB_GADGET_PXA2XX
+#ifdef CONFIG_USB_GADGET_PXA25X
 static struct pxa2xx_udc_mach_info gumstix_udc_info __initdata = {
 	.gpio_vbus		= GPIO_GUMSTIX_USB_GPIOn,
 	.gpio_pullup		= GPIO_GUMSTIX_USB_GPIOx,
@@ -126,12 +117,87 @@
 #else
 static void gumstix_udc_init(void)
 {
-	printk(KERN_INFO "Gumstix udc is disabled\n");
+	pr_debug("Gumstix udc is disabled\n");
 }
 #endif
 
+#ifdef CONFIG_BT
+/* Normally, the bootloader would have enabled this 32kHz clock but many
+** boards still have u-boot 1.1.4 so we check if it has been turned on and
+** if not, we turn it on with a warning message. */
+static void gumstix_setup_bt_clock(void)
+{
+	int timeout = 500;
+
+	if (!(OSCC & OSCC_OOK))
+		pr_warning("32kHz clock was not on. Bootloader may need to "
+				"be updated\n");
+	else
+		return;
+
+	OSCC |= OSCC_OON;
+	do {
+		if (OSCC & OSCC_OOK)
+			break;
+		udelay(1);
+	} while (--timeout);
+	if (!timeout)
+		pr_err("Failed to start 32kHz clock\n");
+}
+
+static void __init gumstix_bluetooth_init(void)
+{
+	int err;
+
+	gumstix_setup_bt_clock();
+
+	err = gpio_request(GPIO_GUMSTIX_BTRESET, "BTRST");
+	if (err) {
+		pr_err("gumstix: failed request gpio for bluetooth reset\n");
+		return;
+	}
+
+	err = gpio_direction_output(GPIO_GUMSTIX_BTRESET, 1);
+	if (err) {
+		pr_err("gumstix: can't reset bluetooth\n");
+		return;
+	}
+	gpio_set_value(GPIO_GUMSTIX_BTRESET, 0);
+	udelay(100);
+	gpio_set_value(GPIO_GUMSTIX_BTRESET, 1);
+}
+#else
+static void gumstix_bluetooth_init(void)
+{
+	pr_debug("Gumstix Bluetooth is disabled\n");
+}
+#endif
+
+static unsigned long gumstix_pin_config[] __initdata = {
+	GPIO12_32KHz,
+	/* BTUART */
+	GPIO42_HWUART_RXD,
+	GPIO43_HWUART_TXD,
+	GPIO44_HWUART_CTS,
+	GPIO45_HWUART_RTS,
+	/* MMC */
+	GPIO6_MMC_CLK,
+	GPIO53_MMC_CLK,
+	GPIO8_MMC_CS0,
+	/* these are used by AM200EPD */
+	GPIO51_GPIO,
+	GPIO49_GPIO,
+	GPIO48_GPIO,
+	GPIO32_GPIO,
+	GPIO17_GPIO,
+	GPIO16_GPIO,
+};
+
 static void __init gumstix_init(void)
 {
+	pxa2xx_mfp_config(ARRAY_AND_SIZE(gumstix_pin_config));
+
+	gumstix_bluetooth_init();
 	gumstix_udc_init();
 	gumstix_mmc_init();
 	(void) platform_add_devices(devices, ARRAY_SIZE(devices));
diff --git a/arch/arm/mach-pxa/idp.c b/arch/arm/mach-pxa/idp.c
index 5aa0270..013b15b 100644
--- a/arch/arm/mach-pxa/idp.c
+++ b/arch/arm/mach-pxa/idp.c
@@ -32,7 +32,7 @@
 #include <asm/mach/map.h>
 
 #include <mach/pxa-regs.h>
-#include <mach/pxa2xx-gpio.h>
+#include <mach/mfp-pxa25x.h>
 #include <mach/idp.h>
 #include <mach/pxafb.h>
 #include <mach/bitfield.h>
@@ -46,6 +46,47 @@
  * - Ethernet interrupt
  */
 
+static unsigned long idp_pin_config[] __initdata = {
+	/* LCD */
+	GPIO58_LCD_LDD_0,
+	GPIO59_LCD_LDD_1,
+	GPIO60_LCD_LDD_2,
+	GPIO61_LCD_LDD_3,
+	GPIO62_LCD_LDD_4,
+	GPIO63_LCD_LDD_5,
+	GPIO64_LCD_LDD_6,
+	GPIO65_LCD_LDD_7,
+	GPIO66_LCD_LDD_8,
+	GPIO67_LCD_LDD_9,
+	GPIO68_LCD_LDD_10,
+	GPIO69_LCD_LDD_11,
+	GPIO70_LCD_LDD_12,
+	GPIO71_LCD_LDD_13,
+	GPIO72_LCD_LDD_14,
+	GPIO73_LCD_LDD_15,
+	GPIO74_LCD_FCLK,
+	GPIO75_LCD_LCLK,
+	GPIO76_LCD_PCLK,
+
+	/* BTUART */
+	GPIO42_BTUART_RXD,
+	GPIO43_BTUART_TXD,
+	GPIO44_BTUART_CTS,
+	GPIO45_BTUART_RTS,
+
+	/* STUART */
+	GPIO46_STUART_RXD,
+	GPIO47_STUART_TXD,
+
+	/* MMC */
+	GPIO6_MMC_CLK,
+	GPIO8_MMC_CS0,
+
+	/* Ethernet */
+	GPIO33_nCS_5,	/* Ethernet CS */
+	GPIO4_GPIO,	/* Ethernet IRQ */
+};
+
 static struct resource smc91x_resources[] = {
 	[0] = {
 		.start	= (IDP_ETH_PHYS + 0x300),
@@ -121,44 +162,28 @@
 	.num_modes      = 1,
 	.cmap_inverse	= 0,
 	.cmap_static	= 0,
-	.lccr0		= LCCR0_SDS,
-	.lccr3		= LCCR3_PCP | LCCR3_Acb(255),
+	.lcd_conn	= LCD_COLOR_DSTN_16BPP | LCD_PCLK_EDGE_FALL |
+			  LCD_AC_BIAS_FREQ(255),
 	.pxafb_backlight_power = &idp_backlight_power,
 	.pxafb_lcd_power = &idp_lcd_power
 };
 
-static int idp_mci_init(struct device *dev, irq_handler_t idp_detect_int, void *data)
-{
-	/* setup GPIO for PXA25x MMC controller	*/
-	pxa_gpio_mode(GPIO6_MMCCLK_MD);
-	pxa_gpio_mode(GPIO8_MMCCS0_MD);
-
-	return 0;
-}
-
 static struct pxamci_platform_data idp_mci_platform_data = {
 	.ocr_mask	= MMC_VDD_32_33|MMC_VDD_33_34,
-	.init 		= idp_mci_init,
 };
 
 static void __init idp_init(void)
 {
 	printk("idp_init()\n");
 
+	pxa2xx_mfp_config(ARRAY_AND_SIZE(idp_pin_config));
+
 	platform_device_register(&smc91x_device);
 	//platform_device_register(&mst_audio_device);
 	set_pxa_fb_info(&sharp_lm8v31);
 	pxa_set_mci_info(&idp_mci_platform_data);
 }
 
-static void __init idp_init_irq(void)
-{
-
-	pxa25x_init_irq();
-
-	set_irq_type(TOUCH_PANEL_IRQ, TOUCH_PANEL_IRQ_EDGE);
-}
-
 static struct map_desc idp_io_desc[] __initdata = {
   	{
 		.virtual	=  IDP_COREVOLT_VIRT,
@@ -177,15 +202,6 @@
 {
 	pxa_map_io();
 	iotable_init(idp_io_desc, ARRAY_SIZE(idp_io_desc));
-
-	// serial ports 2 & 3
-	pxa_gpio_mode(GPIO42_BTRXD_MD);
-	pxa_gpio_mode(GPIO43_BTTXD_MD);
-	pxa_gpio_mode(GPIO44_BTCTS_MD);
-	pxa_gpio_mode(GPIO45_BTRTS_MD);
-	pxa_gpio_mode(GPIO46_STRXD_MD);
-	pxa_gpio_mode(GPIO47_STTXD_MD);
-
 }
 
 
@@ -194,7 +210,7 @@
 	.phys_io	= 0x40000000,
 	.io_pg_offst	= (io_p2v(0x40000000) >> 18) & 0xfffc,
 	.map_io		= idp_map_io,
-	.init_irq	= idp_init_irq,
+	.init_irq	= pxa25x_init_irq,
 	.timer		= &pxa_timer,
 	.init_machine	= idp_init,
 MACHINE_END
diff --git a/arch/arm/mach-pxa/include/mach/akita.h b/arch/arm/mach-pxa/include/mach/akita.h
deleted file mode 100644
index 5d8cc1d..0000000
--- a/arch/arm/mach-pxa/include/mach/akita.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Hardware specific definitions for SL-C1000 (Akita)
- *
- * Copyright (c) 2005 Richard Purdie
- *
- * 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.
- *
- */
-
-/* Akita IO Expander GPIOs */
-
-#define AKITA_IOEXP_RESERVED_7      (1 << 7)
-#define AKITA_IOEXP_IR_ON           (1 << 6)
-#define AKITA_IOEXP_AKIN_PULLUP     (1 << 5)
-#define AKITA_IOEXP_BACKLIGHT_CONT  (1 << 4)
-#define AKITA_IOEXP_BACKLIGHT_ON    (1 << 3)
-#define AKITA_IOEXP_MIC_BIAS        (1 << 2)
-#define AKITA_IOEXP_RESERVED_1      (1 << 1)
-#define AKITA_IOEXP_RESERVED_0      (1 << 0)
-
-/* Direction Bitfield  0=output  1=input */
-#define AKITA_IOEXP_IO_DIR	0
-/* Default Values */
-#define AKITA_IOEXP_IO_OUT	(AKITA_IOEXP_IR_ON | AKITA_IOEXP_AKIN_PULLUP)
-
-extern struct platform_device akitaioexp_device;
-
-void akita_set_ioexp(struct device *dev, unsigned char bitmask);
-void akita_reset_ioexp(struct device *dev, unsigned char bitmask);
-
diff --git a/arch/arm/mach-pxa/include/mach/camera.h b/arch/arm/mach-pxa/include/mach/camera.h
index 39516ce..31abe6d 100644
--- a/arch/arm/mach-pxa/include/mach/camera.h
+++ b/arch/arm/mach-pxa/include/mach/camera.h
@@ -36,8 +36,6 @@
 
 struct pxacamera_platform_data {
 	int (*init)(struct device *);
-	int (*power)(struct device *, int);
-	int (*reset)(struct device *, int);
 
 	unsigned long flags;
 	unsigned long mclk_10khz;
diff --git a/arch/arm/mach-pxa/include/mach/corgi.h b/arch/arm/mach-pxa/include/mach/corgi.h
index bf85650..585970e 100644
--- a/arch/arm/mach-pxa/include/mach/corgi.h
+++ b/arch/arm/mach-pxa/include/mach/corgi.h
@@ -98,12 +98,21 @@
 			CORGI_SCP_MIC_BIAS )
 #define CORGI_SCOOP_IO_OUT	( CORGI_SCP_MUTE_L | CORGI_SCP_MUTE_R )
 
+#define CORGI_SCOOP_GPIO_BASE		(NR_BUILTIN_GPIO)
+#define CORGI_GPIO_LED_GREEN		(CORGI_SCOOP_GPIO_BASE + 0)
+#define CORGI_GPIO_SWA			(CORGI_SCOOP_GPIO_BASE + 1)  /* Hinge Switch A */
+#define CORGI_GPIO_SWB			(CORGI_SCOOP_GPIO_BASE + 2)  /* Hinge Switch B */
+#define CORGI_GPIO_MUTE_L		(CORGI_SCOOP_GPIO_BASE + 3)
+#define CORGI_GPIO_MUTE_R		(CORGI_SCOOP_GPIO_BASE + 4)
+#define CORGI_GPIO_AKIN_PULLUP		(CORGI_SCOOP_GPIO_BASE + 5)
+#define CORGI_GPIO_APM_ON		(CORGI_SCOOP_GPIO_BASE + 6)
+#define CORGI_GPIO_BACKLIGHT_CONT	(CORGI_SCOOP_GPIO_BASE + 7)
+#define CORGI_GPIO_MIC_BIAS		(CORGI_SCOOP_GPIO_BASE + 8)
 
 /*
  * Shared data structures
  */
 extern struct platform_device corgiscoop_device;
-extern struct platform_device corgissp_device;
 
 #endif /* __ASM_ARCH_CORGI_H  */
 
diff --git a/arch/arm/mach-pxa/include/mach/entry-macro.S b/arch/arm/mach-pxa/include/mach/entry-macro.S
index de16c12..f6b4bf3 100644
--- a/arch/arm/mach-pxa/include/mach/entry-macro.S
+++ b/arch/arm/mach-pxa/include/mach/entry-macro.S
@@ -41,7 +41,7 @@
 		and	\irqstat, \irqstat, \irqnr
 		clz	\irqnr, \irqstat
 		rsb	\irqnr, \irqnr, #31
-		add	\irqnr, \irqnr, #32
+		add	\irqnr, \irqnr, #(32 + PXA_IRQ(0))
 		b	1001f
 1003:
 		mrc	p6, 0, \irqstat, c0, c0, 0	@ ICIP
@@ -52,6 +52,6 @@
 		rsb	\irqstat, \irqnr, #0
 		and	\irqstat, \irqstat, \irqnr
 		clz	\irqnr, \irqstat
-		rsb	\irqnr, \irqnr, #31
+		rsb	\irqnr, \irqnr, #(31 + PXA_IRQ(0))
 1001:
 		.endm
diff --git a/arch/arm/mach-pxa/include/mach/hardware.h b/arch/arm/mach-pxa/include/mach/hardware.h
index e89df4d..a582a6d 100644
--- a/arch/arm/mach-pxa/include/mach/hardware.h
+++ b/arch/arm/mach-pxa/include/mach/hardware.h
@@ -62,26 +62,74 @@
 
 #ifndef __ASSEMBLY__
 
+#include <asm/cputype.h>
+
+/*
+ *   CPU     Stepping     CPU_ID         JTAG_ID
+ *
+ *  PXA210	B0	0x69052922	0x2926C013
+ *  PXA210	B1	0x69052923	0x3926C013
+ *  PXA210	B2	0x69052924	0x4926C013
+ *  PXA210	C0	0x69052D25	0x5926C013
+ *
+ *  PXA250	A0	0x69052100	0x09264013
+ *  PXA250	A1	0x69052101	0x19264013
+ *  PXA250	B0	0x69052902	0x29264013
+ *  PXA250	B1	0x69052903	0x39264013
+ *  PXA250	B2	0x69052904	0x49264013
+ *  PXA250	C0	0x69052D05	0x59264013
+ *
+ *  PXA255	A0	0x69052D06	0x69264013
+ *
+ *  PXA26x	A0	0x69052903	0x39264013
+ *  PXA26x	B0	0x69052D05	0x59264013
+ *
+ *  PXA27x	A0	0x69054110	0x09265013
+ *  PXA27x	A1	0x69054111	0x19265013
+ *  PXA27x	B0	0x69054112	0x29265013
+ *  PXA27x	B1	0x69054113	0x39265013
+ *  PXA27x	C0	0x69054114	0x49265013
+ *  PXA27x	C5	0x69054117	0x79265013
+ *
+ *  PXA30x	A0	0x69056880	0x0E648013
+ *  PXA30x	A1	0x69056881	0x1E648013
+ *  PXA31x	A0	0x69056890	0x0E649013
+ *  PXA31x	A1	0x69056891	0x1E649013
+ *  PXA31x	A2	0x69056892	0x2E649013
+ *  PXA32x	B1	0x69056825	0x5E642013
+ *  PXA32x	B2	0x69056826	0x6E642013
+ *
+ *  PXA930	B0	0x69056835	0x5E643013
+ *  PXA930	B1	0x69056837	0x7E643013
+ *  PXA930	B2	0x69056838	0x8E643013
+ */
 #ifdef CONFIG_PXA25x
-#define __cpu_is_pxa21x(id)				\
+#define __cpu_is_pxa210(id)				\
 	({						\
-		unsigned int _id = (id) >> 4 & 0xf3f;	\
-		_id == 0x212;				\
+		unsigned int _id = (id) & 0xf3f0;	\
+		_id == 0x2120;				\
 	})
 
-#define __cpu_is_pxa255(id)                             \
-	({                                              \
-		unsigned int _id = (id) >> 4 & 0xfff;   \
-		_id == 0x2d0;                           \
-	 })
+#define __cpu_is_pxa250(id)				\
+	({						\
+		unsigned int _id = (id) & 0xf3ff;	\
+		_id <= 0x2105;				\
+	})
+
+#define __cpu_is_pxa255(id)				\
+	({						\
+		unsigned int _id = (id) & 0xffff;	\
+		_id == 0x2d06;				\
+	})
 
 #define __cpu_is_pxa25x(id)				\
 	({						\
-		unsigned int _id = (id) >> 4 & 0xfff;	\
-		_id == 0x2d0 || _id == 0x290;		\
+		unsigned int _id = (id) & 0xf300;	\
+		_id == 0x2100;				\
 	})
 #else
-#define __cpu_is_pxa21x(id)	(0)
+#define __cpu_is_pxa210(id)	(0)
+#define __cpu_is_pxa250(id)	(0)
 #define __cpu_is_pxa255(id)	(0)
 #define __cpu_is_pxa25x(id)	(0)
 #endif
@@ -136,9 +184,14 @@
 #define __cpu_is_pxa930(id)	(0)
 #endif
 
-#define cpu_is_pxa21x()					\
+#define cpu_is_pxa210()					\
 	({						\
-		__cpu_is_pxa21x(read_cpuid_id());	\
+		__cpu_is_pxa210(read_cpuid_id());	\
+	})
+
+#define cpu_is_pxa250()					\
+	({						\
+		__cpu_is_pxa250(read_cpuid_id());	\
 	})
 
 #define cpu_is_pxa255()                                 \
@@ -151,6 +204,8 @@
 		__cpu_is_pxa25x(read_cpuid_id());	\
 	})
 
+extern int cpu_is_pxa26x(void);
+
 #define cpu_is_pxa27x()					\
 	({						\
 		__cpu_is_pxa27x(read_cpuid_id());	\
diff --git a/arch/arm/mach-pxa/include/mach/i2c.h b/arch/arm/mach-pxa/include/mach/i2c.h
index 80596b0..1a9f65e 100644
--- a/arch/arm/mach-pxa/include/mach/i2c.h
+++ b/arch/arm/mach-pxa/include/mach/i2c.h
@@ -65,13 +65,18 @@
 	unsigned int		slave_addr;
 	struct i2c_slave_client	*slave;
 	unsigned int		class;
-	int			use_pio;
+	unsigned int		use_pio :1;
+	unsigned int		fast_mode :1;
 };
 
 extern void pxa_set_i2c_info(struct i2c_pxa_platform_data *info);
 
 #ifdef CONFIG_PXA27x
-extern void pxa_set_i2c_power_info(struct i2c_pxa_platform_data *info);
+extern void pxa27x_set_i2c_power_info(struct i2c_pxa_platform_data *info);
+#endif
+
+#ifdef CONFIG_PXA3xx
+extern void pxa3xx_set_i2c_power_info(struct i2c_pxa_platform_data *info);
 #endif
 
 #endif
diff --git a/arch/arm/mach-pxa/include/mach/irqs.h b/arch/arm/mach-pxa/include/mach/irqs.h
index 108b5db..9c163e1 100644
--- a/arch/arm/mach-pxa/include/mach/irqs.h
+++ b/arch/arm/mach-pxa/include/mach/irqs.h
@@ -11,7 +11,14 @@
  */
 
 
-#define PXA_IRQ(x)	(x)
+#ifdef CONFIG_PXA_HAVE_ISA_IRQS
+#define PXA_ISA_IRQ(x)	(x)
+#define PXA_ISA_IRQ_NUM	(16)
+#else
+#define PXA_ISA_IRQ_NUM	(0)
+#endif
+
+#define PXA_IRQ(x)	(PXA_ISA_IRQ_NUM + (x))
 
 #if defined(CONFIG_PXA27x) || defined(CONFIG_PXA3xx)
 #define IRQ_SSP3	PXA_IRQ(0)	/* SSP3 service request */
@@ -73,7 +80,7 @@
 #define IRQ_MMC3	PXA_IRQ(55)	/* MMC3 Controller (PXA310) */
 #endif
 
-#define PXA_GPIO_IRQ_BASE	(64)
+#define PXA_GPIO_IRQ_BASE	PXA_IRQ(64)
 #define PXA_GPIO_IRQ_NUM	(128)
 
 #define GPIO_2_x_TO_IRQ(x)	(PXA_GPIO_IRQ_BASE + (x))
@@ -178,13 +185,7 @@
 #define NR_IRQS			(IRQ_S1_BVD1_STSCHG + 1)
 #elif defined(CONFIG_SHARP_LOCOMO)
 #define NR_IRQS			(IRQ_LOCOMO_SPI_TEND + 1)
-#elif defined(CONFIG_ARCH_LUBBOCK) || \
-      defined(CONFIG_MACH_LOGICPD_PXA270) || \
-      defined(CONFIG_MACH_TOSA) || \
-      defined(CONFIG_MACH_MAINSTONE) || \
-      defined(CONFIG_MACH_PCM027) || \
-      defined(CONFIG_ARCH_PXA_ESERIES) || \
-      defined(CONFIG_MACH_MAGICIAN)
+#elif defined(CONFIG_PXA_HAVE_BOARD_IRQS)
 #define NR_IRQS			(IRQ_BOARD_END)
 #elif defined(CONFIG_MACH_ZYLONITE)
 #define NR_IRQS			(IRQ_BOARD_START + 32)
diff --git a/arch/arm/mach-pxa/include/mach/littleton.h b/arch/arm/mach-pxa/include/mach/littleton.h
index 79d209b..5c4e320 100644
--- a/arch/arm/mach-pxa/include/mach/littleton.h
+++ b/arch/arm/mach-pxa/include/mach/littleton.h
@@ -3,4 +3,6 @@
 
 #define LITTLETON_ETH_PHYS	0x30000000
 
+#define LITTLETON_GPIO_LCD_CS	(17)
+
 #endif /* __ASM_ARCH_ZYLONITE_H */
diff --git a/arch/arm/mach-pxa/include/mach/memory.h b/arch/arm/mach-pxa/include/mach/memory.h
index 552eb7f..59aef89 100644
--- a/arch/arm/mach-pxa/include/mach/memory.h
+++ b/arch/arm/mach-pxa/include/mach/memory.h
@@ -40,11 +40,11 @@
 #define NODE_MEM_SIZE_BITS	26
 
 #if !defined(__ASSEMBLY__) && defined(CONFIG_MACH_ARMCORE) && defined(CONFIG_PCI)
-void cmx270_pci_adjust_zones(int node, unsigned long *size,
+void cmx2xx_pci_adjust_zones(int node, unsigned long *size,
 			     unsigned long *holes);
 
 #define arch_adjust_zones(node, size, holes) \
-	cmx270_pci_adjust_zones(node, size, holes)
+	cmx2xx_pci_adjust_zones(node, size, holes)
 
 #define ISA_DMA_THRESHOLD	(PHYS_OFFSET + SZ_64M - 1)
 #endif
diff --git a/arch/arm/mach-pxa/include/mach/mfp-pxa25x.h b/arch/arm/mach-pxa/include/mach/mfp-pxa25x.h
index 6c8e722..617cab2 100644
--- a/arch/arm/mach-pxa/include/mach/mfp-pxa25x.h
+++ b/arch/arm/mach-pxa/include/mach/mfp-pxa25x.h
@@ -17,7 +17,7 @@
 
 /* Crystal and Clock Signals */
 #define GPIO10_RTCCLK		MFP_CFG_OUT(GPIO10, AF1, DRIVE_LOW)
-#define GPIO70_RTC_CLK		MFP_CFG_OUT(GPIO70, AF1, DRIVE_LOW)
+#define GPIO70_RTCCLK		MFP_CFG_OUT(GPIO70, AF1, DRIVE_LOW)
 #define GPIO7_48MHz		MFP_CFG_OUT(GPIO7,  AF1, DRIVE_LOW)
 #define GPIO11_3_6MHz		MFP_CFG_OUT(GPIO11, AF1, DRIVE_LOW)
 #define GPIO71_3_6MHz		MFP_CFG_OUT(GPIO71, AF1, DRIVE_LOW)
@@ -156,6 +156,6 @@
 #define GPIO74_LCD_FCLK		MFP_CFG_OUT(GPIO74, AF2, DRIVE_LOW)
 #define GPIO75_LCD_LCLK		MFP_CFG_OUT(GPIO75, AF2, DRIVE_LOW)
 #define GPIO76_LCD_PCLK		MFP_CFG_OUT(GPIO76, AF2, DRIVE_LOW)
-#define GPIO77_LCD_ACBIAS	MFP_CFG_OUT(GPIO77, AF2, DRIVE_LOW)
+#define GPIO77_LCD_BIAS		MFP_CFG_OUT(GPIO77, AF2, DRIVE_LOW)
 
 #endif /* __ASM_ARCH_MFP_PXA25X_H */
diff --git a/arch/arm/mach-pxa/include/mach/mfp-pxa320.h b/arch/arm/mach-pxa/include/mach/mfp-pxa320.h
index 7499051..67f8385 100644
--- a/arch/arm/mach-pxa/include/mach/mfp-pxa320.h
+++ b/arch/arm/mach-pxa/include/mach/mfp-pxa320.h
@@ -257,10 +257,10 @@
 #define GPIO38_SSP2_RXD		MFP_CFG(GPIO38, AF2)
 #define GPIO38_SSP2_TXD		MFP_CFG(GPIO38, AF5)
 
-#define GPIO69_SSP3_SCLK	MFP_CFG(GPIO69, AF2, DS08X, FLOAT)
-#define GPIO70_SSP3_FRM		MFP_CFG(GPIO70, AF2, DS08X, DRIVE_LOW)
-#define GPIO89_SSP3_SCLK	MFP_CFG(GPIO89, AF1, DS08X, FLOAT)
-#define GPIO90_SSP3_FRM		MFP_CFG(GPIO90, AF1, DS08X, DRIVE_LOW)
+#define GPIO69_SSP3_SCLK	MFP_CFG_X(GPIO69, AF2, DS08X, FLOAT)
+#define GPIO70_SSP3_FRM		MFP_CFG_X(GPIO70, AF2, DS08X, DRIVE_LOW)
+#define GPIO89_SSP3_SCLK	MFP_CFG_X(GPIO89, AF1, DS08X, FLOAT)
+#define GPIO90_SSP3_FRM		MFP_CFG_X(GPIO90, AF1, DS08X, DRIVE_LOW)
 #define GPIO71_SSP3_RXD		MFP_CFG_X(GPIO71, AF5, DS08X, FLOAT)
 #define GPIO71_SSP3_TXD		MFP_CFG_X(GPIO71, AF2, DS08X, DRIVE_LOW)
 #define GPIO72_SSP3_RXD		MFP_CFG_X(GPIO72, AF2, DS08X, FLOAT)
diff --git a/arch/arm/mach-pxa/include/mach/mfp.h b/arch/arm/mach-pxa/include/mach/mfp.h
index 8769567..4821850 100644
--- a/arch/arm/mach-pxa/include/mach/mfp.h
+++ b/arch/arm/mach-pxa/include/mach/mfp.h
@@ -274,12 +274,13 @@
 #define MFP_DS_MASK		(0x7 << 13)
 #define MFP_DS(x)		(((x) >> 13) & 0x7)
 
-#define MFP_LPM_INPUT		(0x0 << 16)
+#define MFP_LPM_DEFAULT		(0x0 << 16)
 #define MFP_LPM_DRIVE_LOW	(0x1 << 16)
 #define MFP_LPM_DRIVE_HIGH	(0x2 << 16)
 #define MFP_LPM_PULL_LOW	(0x3 << 16)
 #define MFP_LPM_PULL_HIGH	(0x4 << 16)
 #define MFP_LPM_FLOAT		(0x5 << 16)
+#define MFP_LPM_INPUT		(0x6 << 16)
 #define MFP_LPM_STATE_MASK	(0x7 << 16)
 #define MFP_LPM_STATE(x)	(((x) >> 16) & 0x7)
 
@@ -297,7 +298,7 @@
 #define MFP_PULL_MASK		(0x3 << 21)
 #define MFP_PULL(x)		(((x) >> 21) & 0x3)
 
-#define MFP_CFG_DEFAULT		(MFP_AF0 | MFP_DS03X | MFP_LPM_INPUT |\
+#define MFP_CFG_DEFAULT		(MFP_AF0 | MFP_DS03X | MFP_LPM_DEFAULT |\
 				 MFP_LPM_EDGE_NONE | MFP_PULL_NONE)
 
 #define MFP_CFG(pin, af)		\
diff --git a/arch/arm/mach-pxa/include/mach/mioa701.h b/arch/arm/mach-pxa/include/mach/mioa701.h
new file mode 100644
index 0000000..8483cb5
--- /dev/null
+++ b/arch/arm/mach-pxa/include/mach/mioa701.h
@@ -0,0 +1,67 @@
+#ifndef _MIOA701_H_
+#define _MIOA701_H_
+
+#define MIO_CFG_IN(pin, af)		\
+	((MFP_CFG_DEFAULT & ~(MFP_AF_MASK | MFP_DIR_MASK)) |\
+	 (MFP_PIN(pin) | MFP_##af | MFP_DIR_IN))
+
+#define MIO_CFG_OUT(pin, af, state)	\
+	((MFP_CFG_DEFAULT & ~(MFP_AF_MASK | MFP_DIR_MASK | MFP_LPM_STATE_MASK)) |\
+	 (MFP_PIN(pin) | MFP_##af | MFP_DIR_OUT | MFP_LPM_##state))
+
+/* Global GPIOs */
+#define GPIO9_CHARGE_nEN			9
+#define GPIO18_POWEROFF				18
+#define GPIO87_LCD_POWER			87
+
+/* USB */
+#define GPIO13_USB_DETECT			13
+#define GPIO22_USB_ENABLE			22
+
+/* SDIO bits */
+#define GPIO78_SDIO_RO				78
+#define GPIO15_SDIO_INSERT			15
+#define GPIO91_SDIO_EN				91
+
+/* Bluetooth */
+#define GPIO83_BT_ON				83
+
+/* GPS */
+#define GPIO23_GPS_UNKNOWN1			23
+#define GPIO26_GPS_ON				26
+#define GPIO27_GPS_RESET			27
+#define GPIO106_GPS_UNKNOWN2			106
+#define GPIO107_GPS_UNKNOWN3			107
+
+/* GSM */
+#define GPIO24_GSM_MOD_RESET_CMD		24
+#define GPIO88_GSM_nMOD_ON_CMD			88
+#define GPIO90_GSM_nMOD_OFF_CMD			90
+#define GPIO114_GSM_nMOD_DTE_UART_STATE 	114
+#define GPIO25_GSM_MOD_ON_STATE			25
+#define GPIO113_GSM_EVENT			113
+
+/* SOUND */
+#define GPIO12_HPJACK_INSERT			12
+
+/* LEDS */
+#define GPIO10_LED_nCharging			10
+#define GPIO97_LED_nBlue			97
+#define GPIO98_LED_nOrange			98
+#define GPIO82_LED_nVibra			82
+#define GPIO115_LED_nKeyboard			115
+
+/* Keyboard */
+#define GPIO0_KEY_POWER				0
+#define GPIO93_KEY_VOLUME_UP			93
+#define GPIO94_KEY_VOLUME_DOWN			94
+
+extern struct input_dev *mioa701_evdev;
+extern void mioa701_gpio_lpm_set(unsigned long mfp_pin);
+
+/* Assembler externals mioa701_bootresume.S */
+extern u32 mioa701_bootstrap;
+extern u32 mioa701_jumpaddr;
+extern u32 mioa701_bootstrap_lg;
+
+#endif /* _MIOA701_H */
diff --git a/arch/arm/mach-pxa/include/mach/ohci.h b/arch/arm/mach-pxa/include/mach/ohci.h
index e848a47..95b6e2a 100644
--- a/arch/arm/mach-pxa/include/mach/ohci.h
+++ b/arch/arm/mach-pxa/include/mach/ohci.h
@@ -7,6 +7,22 @@
 	int (*init)(struct device *);
 	void (*exit)(struct device *);
 
+	unsigned long flags;
+#define ENABLE_PORT1		(1 << 0)
+#define ENABLE_PORT2		(1 << 1)
+#define ENABLE_PORT3		(1 << 2)
+#define ENABLE_PORT_ALL		(ENABLE_PORT1 | ENABLE_PORT2 | ENABLE_PORT3)
+
+#define POWER_SENSE_LOW		(1 << 3)
+#define POWER_CONTROL_LOW	(1 << 4)
+#define NO_OC_PROTECTION	(1 << 5)
+#define OC_MODE_GLOBAL		(0 << 6)
+#define OC_MODE_PERPORT		(1 << 6)
+
+	int power_on_delay;	/* Power On to Power Good time - in ms
+				 * HCD must wait for this duration before
+				 * accessing a powered on port
+				 */
 	int port_mode;
 #define PMM_NPS_MODE           1
 #define PMM_GLOBAL_MODE        2
diff --git a/arch/arm/mach-pxa/include/mach/palmz72.h b/arch/arm/mach-pxa/include/mach/palmz72.h
new file mode 100644
index 0000000..5032307
--- /dev/null
+++ b/arch/arm/mach-pxa/include/mach/palmz72.h
@@ -0,0 +1,80 @@
+/*
+ * GPIOs and interrupts for Palm Zire72 Handheld Computer
+ *
+ * Authors:	Alex Osborne <bobofdoom@gmail.com>
+ *		Jan Herman <2hp@seznam.cz>
+ *		Sergey Lapin <slapin@ossfans.org>
+ *
+ * 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 _INCLUDE_PALMZ72_H_
+#define _INCLUDE_PALMZ72_H_
+
+/* Power and control */
+#define GPIO_NR_PALMZ72_GPIO_RESET		1
+#define GPIO_NR_PALMZ72_POWER_DETECT		0
+
+/* SD/MMC */
+#define GPIO_NR_PALMZ72_SD_DETECT_N		14
+#define GPIO_NR_PALMZ72_SD_POWER_N		98
+#define GPIO_NR_PALMZ72_SD_RO 115
+
+/* Touchscreen */
+#define GPIO_NR_PALMZ72_WM9712_IRQ		27
+
+/* IRDA -  disable GPIO connected to SD pin of tranceiver (TFBS4710?) ? */
+#define GPIO_NR_PALMZ72_IR_DISABLE		49
+
+/* USB */
+#define GPIO_NR_PALMZ72_USB_DETECT_N		15
+#define GPIO_NR_PALMZ72_USB_POWER		95
+#define GPIO_NR_PALMZ72_USB_PULLUP		12
+
+/* LCD/Backlight */
+#define GPIO_NR_PALMZ72_BL_POWER		20
+#define GPIO_NR_PALMZ72_LCD_POWER		96
+
+/* LED */
+#define GPIO_NR_PALMZ72_LED_GREEN		88
+
+/* Bluetooth */
+#define GPIO_NR_PALMZ72_BT_POWER		17
+#define GPIO_NR_PALMZ72_BT_RESET		83
+
+/** Initial values **/
+
+/* Battery */
+#define PALMZ72_BAT_MAX_VOLTAGE		4000	/* 4.00v current voltage */
+#define PALMZ72_BAT_MIN_VOLTAGE		3550	/* 3.55v critical voltage */
+#define PALMZ72_BAT_MAX_CURRENT		0	/* unknokn */
+#define PALMZ72_BAT_MIN_CURRENT		0	/* unknown */
+#define PALMZ72_BAT_MAX_CHARGE		1	/* unknown */
+#define PALMZ72_BAT_MIN_CHARGE		1	/* unknown */
+#define PALMZ72_MAX_LIFE_MINS		360	/* on-life in minutes */
+
+/* Backlight */
+#define PALMZ72_MAX_INTENSITY		0xFE
+#define PALMZ72_DEFAULT_INTENSITY	0x7E
+#define PALMZ72_LIMIT_MASK		0x7F
+#define PALMZ72_PRESCALER		0x3F
+#define PALMZ72_PERIOD_NS		3500
+
+#ifdef CONFIG_PM
+struct palmz72_resume_info {
+	u32 magic0;		/* 0x0 */
+	u32 magic1;		/* 0x4 */
+	u32 resume_addr;	/* 0x8 */
+	u32 pad[11];		/* 0xc..0x37 */
+	u32 arm_control;	/* 0x38 */
+	u32 aux_control;	/* 0x3c */
+	u32 ttb;		/* 0x40 */
+	u32 domain_access;	/* 0x44 */
+	u32 process_id;		/* 0x48 */
+};
+#endif
+#endif
+
diff --git a/arch/arm/mach-pxa/include/mach/pm.h b/arch/arm/mach-pxa/include/mach/pm.h
index 261e5bc..8334246 100644
--- a/arch/arm/mach-pxa/include/mach/pm.h
+++ b/arch/arm/mach-pxa/include/mach/pm.h
@@ -15,6 +15,8 @@
 	void	(*restore)(unsigned long *);
 	int	(*valid)(suspend_state_t state);
 	void	(*enter)(suspend_state_t state);
+	int	(*prepare)(void);
+	void	(*finish)(void);
 };
 
 extern struct pxa_cpu_pm_fns *pxa_cpu_pm_fns;
diff --git a/arch/arm/mach-pxa/include/mach/poodle.h b/arch/arm/mach-pxa/include/mach/poodle.h
index 67debc4..0b3e6d0 100644
--- a/arch/arm/mach-pxa/include/mach/poodle.h
+++ b/arch/arm/mach-pxa/include/mach/poodle.h
@@ -23,6 +23,7 @@
 #define POODLE_GPIO_AC_IN		(1)
 #define POODLE_GPIO_CO			16
 #define POODLE_GPIO_TP_INT		(5)
+#define POODLE_GPIO_TP_CS		(24)
 #define POODLE_GPIO_WAKEUP		(11)	/* change battery */
 #define POODLE_GPIO_GA_INT		(10)
 #define POODLE_GPIO_IR_ON		(22)
@@ -70,6 +71,14 @@
 #define POODLE_SCOOP_IO_DIR	( POODLE_SCOOP_VPEN | POODLE_SCOOP_HS_OUT )
 #define POODLE_SCOOP_IO_OUT	( 0 )
 
+#define POODLE_SCOOP_GPIO_BASE	(NR_BUILTIN_GPIO)
+#define POODLE_GPIO_CHARGE_ON	(POODLE_SCOOP_GPIO_BASE + 0)
+#define POODLE_GPIO_CP401	(POODLE_SCOOP_GPIO_BASE + 2)
+#define POODLE_GPIO_VPEN	(POODLE_SCOOP_GPIO_BASE + 7)
+#define POODLE_GPIO_L_PCLK	(POODLE_SCOOP_GPIO_BASE + 9)
+#define POODLE_GPIO_L_LCLK	(POODLE_SCOOP_GPIO_BASE + 10)
+#define POODLE_GPIO_HS_OUT	(POODLE_SCOOP_GPIO_BASE + 11)
+
 #define POODLE_LOCOMO_GPIO_AMP_ON      LOCOMO_GPIO(8)
 #define POODLE_LOCOMO_GPIO_MUTE_L      LOCOMO_GPIO(10)
 #define POODLE_LOCOMO_GPIO_MUTE_R      LOCOMO_GPIO(11)
diff --git a/arch/arm/mach-pxa/include/mach/pxa-regs.h b/arch/arm/mach-pxa/include/mach/pxa-regs.h
index 12288ca..15295d9 100644
--- a/arch/arm/mach-pxa/include/mach/pxa-regs.h
+++ b/arch/arm/mach-pxa/include/mach/pxa-regs.h
@@ -69,30 +69,18 @@
 /*
  * DMA Controller
  */
-
-#define DCSR0		__REG(0x40000000)  /* DMA Control / Status Register for Channel 0 */
-#define DCSR1		__REG(0x40000004)  /* DMA Control / Status Register for Channel 1 */
-#define DCSR2		__REG(0x40000008)  /* DMA Control / Status Register for Channel 2 */
-#define DCSR3		__REG(0x4000000c)  /* DMA Control / Status Register for Channel 3 */
-#define DCSR4		__REG(0x40000010)  /* DMA Control / Status Register for Channel 4 */
-#define DCSR5		__REG(0x40000014)  /* DMA Control / Status Register for Channel 5 */
-#define DCSR6		__REG(0x40000018)  /* DMA Control / Status Register for Channel 6 */
-#define DCSR7		__REG(0x4000001c)  /* DMA Control / Status Register for Channel 7 */
-#define DCSR8		__REG(0x40000020)  /* DMA Control / Status Register for Channel 8 */
-#define DCSR9		__REG(0x40000024)  /* DMA Control / Status Register for Channel 9 */
-#define DCSR10		__REG(0x40000028)  /* DMA Control / Status Register for Channel 10 */
-#define DCSR11		__REG(0x4000002c)  /* DMA Control / Status Register for Channel 11 */
-#define DCSR12		__REG(0x40000030)  /* DMA Control / Status Register for Channel 12 */
-#define DCSR13		__REG(0x40000034)  /* DMA Control / Status Register for Channel 13 */
-#define DCSR14		__REG(0x40000038)  /* DMA Control / Status Register for Channel 14 */
-#define DCSR15		__REG(0x4000003c)  /* DMA Control / Status Register for Channel 15 */
-
 #define DCSR(x)		__REG2(0x40000000, (x) << 2)
 
 #define DCSR_RUN	(1 << 31)	/* Run Bit (read / write) */
 #define DCSR_NODESC	(1 << 30)	/* No-Descriptor Fetch (read / write) */
 #define DCSR_STOPIRQEN	(1 << 29)	/* Stop Interrupt Enable (read / write) */
-#ifdef CONFIG_PXA27x
+#define DCSR_REQPEND	(1 << 8)	/* Request Pending (read-only) */
+#define DCSR_STOPSTATE	(1 << 3)	/* Stop State (read-only) */
+#define DCSR_ENDINTR	(1 << 2)	/* End Interrupt (read / write) */
+#define DCSR_STARTINTR	(1 << 1)	/* Start Interrupt (read / write) */
+#define DCSR_BUSERR	(1 << 0)	/* Bus Error Interrupt (read / write) */
+
+#if defined(CONFIG_PXA27x) || defined(CONFIG_PXA3xx)
 #define DCSR_EORIRQEN	(1 << 28)       /* End of Receive Interrupt Enable (R/W) */
 #define DCSR_EORJMPEN	(1 << 27)       /* Jump to next descriptor on EOR */
 #define DCSR_EORSTOPEN	(1 << 26)       /* STOP on an EOR */
@@ -101,11 +89,6 @@
 #define DCSR_CMPST	(1 << 10)       /* The Descriptor Compare Status */
 #define DCSR_EORINTR	(1 << 9)        /* The end of Receive */
 #endif
-#define DCSR_REQPEND	(1 << 8)	/* Request Pending (read-only) */
-#define DCSR_STOPSTATE	(1 << 3)	/* Stop State (read-only) */
-#define DCSR_ENDINTR	(1 << 2)	/* End Interrupt (read / write) */
-#define DCSR_STARTINTR	(1 << 1)	/* Start Interrupt (read / write) */
-#define DCSR_BUSERR	(1 << 0)	/* Bus Error Interrupt (read / write) */
 
 #define DALGN		__REG(0x400000a0)  /* DMA Alignment Register */
 #define DINT		__REG(0x400000f0)  /* DMA Interrupt Register */
@@ -114,145 +97,9 @@
 			&__REG2(0x40000100, ((n) & 0x3f) << 2) : \
 			&__REG2(0x40001100, ((n) & 0x3f) << 2)))
 
-#define DRCMR0		__REG(0x40000100)  /* Request to Channel Map Register for DREQ 0 */
-#define DRCMR1		__REG(0x40000104)  /* Request to Channel Map Register for DREQ 1 */
-#define DRCMR2		__REG(0x40000108)  /* Request to Channel Map Register for I2S receive Request */
-#define DRCMR3		__REG(0x4000010c)  /* Request to Channel Map Register for I2S transmit Request */
-#define DRCMR4		__REG(0x40000110)  /* Request to Channel Map Register for BTUART receive Request */
-#define DRCMR5		__REG(0x40000114)  /* Request to Channel Map Register for BTUART transmit Request. */
-#define DRCMR6		__REG(0x40000118)  /* Request to Channel Map Register for FFUART receive Request */
-#define DRCMR7		__REG(0x4000011c)  /* Request to Channel Map Register for FFUART transmit Request */
-#define DRCMR8		__REG(0x40000120)  /* Request to Channel Map Register for AC97 microphone Request */
-#define DRCMR9		__REG(0x40000124)  /* Request to Channel Map Register for AC97 modem receive Request */
-#define DRCMR10		__REG(0x40000128)  /* Request to Channel Map Register for AC97 modem transmit Request */
-#define DRCMR11		__REG(0x4000012c)  /* Request to Channel Map Register for AC97 audio receive Request */
-#define DRCMR12		__REG(0x40000130)  /* Request to Channel Map Register for AC97 audio transmit Request */
-#define DRCMR13		__REG(0x40000134)  /* Request to Channel Map Register for SSP receive Request */
-#define DRCMR14		__REG(0x40000138)  /* Request to Channel Map Register for SSP transmit Request */
-#define DRCMR15		__REG(0x4000013c)  /* Request to Channel Map Register for SSP2 receive Request */
-#define DRCMR16		__REG(0x40000140)  /* Request to Channel Map Register for SSP2 transmit Request */
-#define DRCMR17		__REG(0x40000144)  /* Request to Channel Map Register for ICP receive Request */
-#define DRCMR18		__REG(0x40000148)  /* Request to Channel Map Register for ICP transmit Request */
-#define DRCMR19		__REG(0x4000014c)  /* Request to Channel Map Register for STUART receive Request */
-#define DRCMR20		__REG(0x40000150)  /* Request to Channel Map Register for STUART transmit Request */
-#define DRCMR21		__REG(0x40000154)  /* Request to Channel Map Register for MMC receive Request */
-#define DRCMR22		__REG(0x40000158)  /* Request to Channel Map Register for MMC transmit Request */
-#define DRCMR23		__REG(0x4000015c)  /* Reserved */
-#define DRCMR24		__REG(0x40000160)  /* Reserved */
-#define DRCMR25		__REG(0x40000164)  /* Request to Channel Map Register for USB endpoint 1 Request */
-#define DRCMR26		__REG(0x40000168)  /* Request to Channel Map Register for USB endpoint 2 Request */
-#define DRCMR27		__REG(0x4000016C)  /* Request to Channel Map Register for USB endpoint 3 Request */
-#define DRCMR28		__REG(0x40000170)  /* Request to Channel Map Register for USB endpoint 4 Request */
-#define DRCMR29		__REG(0x40000174)  /* Reserved */
-#define DRCMR30		__REG(0x40000178)  /* Request to Channel Map Register for USB endpoint 6 Request */
-#define DRCMR31		__REG(0x4000017C)  /* Request to Channel Map Register for USB endpoint 7 Request */
-#define DRCMR32		__REG(0x40000180)  /* Request to Channel Map Register for USB endpoint 8 Request */
-#define DRCMR33		__REG(0x40000184)  /* Request to Channel Map Register for USB endpoint 9 Request */
-#define DRCMR34		__REG(0x40000188)  /* Reserved */
-#define DRCMR35		__REG(0x4000018C)  /* Request to Channel Map Register for USB endpoint 11 Request */
-#define DRCMR36		__REG(0x40000190)  /* Request to Channel Map Register for USB endpoint 12 Request */
-#define DRCMR37		__REG(0x40000194)  /* Request to Channel Map Register for USB endpoint 13 Request */
-#define DRCMR38		__REG(0x40000198)  /* Request to Channel Map Register for USB endpoint 14 Request */
-#define DRCMR39		__REG(0x4000019C)  /* Reserved */
-#define DRCMR66		__REG(0x40001108)  /* Request to Channel Map Register for SSP3 receive Request */
-#define DRCMR67		__REG(0x4000110C)  /* Request to Channel Map Register for SSP3 transmit Request */
-#define DRCMR68		__REG(0x40001110)  /* Request to Channel Map Register for Camera FIFO 0 Request */
-#define DRCMR69		__REG(0x40001114)  /* Request to Channel Map Register for Camera FIFO 1 Request */
-#define DRCMR70		__REG(0x40001118)  /* Request to Channel Map Register for Camera FIFO 2 Request */
-
-#define DRCMRRXSADR	DRCMR2
-#define DRCMRTXSADR	DRCMR3
-#define DRCMRRXBTRBR	DRCMR4
-#define DRCMRTXBTTHR	DRCMR5
-#define DRCMRRXFFRBR	DRCMR6
-#define DRCMRTXFFTHR	DRCMR7
-#define DRCMRRXMCDR	DRCMR8
-#define DRCMRRXMODR	DRCMR9
-#define DRCMRTXMODR	DRCMR10
-#define DRCMRRXPCDR	DRCMR11
-#define DRCMRTXPCDR	DRCMR12
-#define DRCMRRXSSDR	DRCMR13
-#define DRCMRTXSSDR	DRCMR14
-#define DRCMRRXSS2DR   DRCMR15
-#define DRCMRTXSS2DR   DRCMR16
-#define DRCMRRXICDR	DRCMR17
-#define DRCMRTXICDR	DRCMR18
-#define DRCMRRXSTRBR	DRCMR19
-#define DRCMRTXSTTHR	DRCMR20
-#define DRCMRRXMMC	DRCMR21
-#define DRCMRTXMMC	DRCMR22
-#define DRCMRRXSS3DR   DRCMR66
-#define DRCMRTXSS3DR   DRCMR67
-#define DRCMRUDC(x)	DRCMR((x) + 24)
-
 #define DRCMR_MAPVLD	(1 << 7)	/* Map Valid (read / write) */
 #define DRCMR_CHLNUM	0x1f		/* mask for Channel Number (read / write) */
 
-#define DDADR0		__REG(0x40000200)  /* DMA Descriptor Address Register Channel 0 */
-#define DSADR0		__REG(0x40000204)  /* DMA Source Address Register Channel 0 */
-#define DTADR0		__REG(0x40000208)  /* DMA Target Address Register Channel 0 */
-#define DCMD0		__REG(0x4000020c)  /* DMA Command Address Register Channel 0 */
-#define DDADR1		__REG(0x40000210)  /* DMA Descriptor Address Register Channel 1 */
-#define DSADR1		__REG(0x40000214)  /* DMA Source Address Register Channel 1 */
-#define DTADR1		__REG(0x40000218)  /* DMA Target Address Register Channel 1 */
-#define DCMD1		__REG(0x4000021c)  /* DMA Command Address Register Channel 1 */
-#define DDADR2		__REG(0x40000220)  /* DMA Descriptor Address Register Channel 2 */
-#define DSADR2		__REG(0x40000224)  /* DMA Source Address Register Channel 2 */
-#define DTADR2		__REG(0x40000228)  /* DMA Target Address Register Channel 2 */
-#define DCMD2		__REG(0x4000022c)  /* DMA Command Address Register Channel 2 */
-#define DDADR3		__REG(0x40000230)  /* DMA Descriptor Address Register Channel 3 */
-#define DSADR3		__REG(0x40000234)  /* DMA Source Address Register Channel 3 */
-#define DTADR3		__REG(0x40000238)  /* DMA Target Address Register Channel 3 */
-#define DCMD3		__REG(0x4000023c)  /* DMA Command Address Register Channel 3 */
-#define DDADR4		__REG(0x40000240)  /* DMA Descriptor Address Register Channel 4 */
-#define DSADR4		__REG(0x40000244)  /* DMA Source Address Register Channel 4 */
-#define DTADR4		__REG(0x40000248)  /* DMA Target Address Register Channel 4 */
-#define DCMD4		__REG(0x4000024c)  /* DMA Command Address Register Channel 4 */
-#define DDADR5		__REG(0x40000250)  /* DMA Descriptor Address Register Channel 5 */
-#define DSADR5		__REG(0x40000254)  /* DMA Source Address Register Channel 5 */
-#define DTADR5		__REG(0x40000258)  /* DMA Target Address Register Channel 5 */
-#define DCMD5		__REG(0x4000025c)  /* DMA Command Address Register Channel 5 */
-#define DDADR6		__REG(0x40000260)  /* DMA Descriptor Address Register Channel 6 */
-#define DSADR6		__REG(0x40000264)  /* DMA Source Address Register Channel 6 */
-#define DTADR6		__REG(0x40000268)  /* DMA Target Address Register Channel 6 */
-#define DCMD6		__REG(0x4000026c)  /* DMA Command Address Register Channel 6 */
-#define DDADR7		__REG(0x40000270)  /* DMA Descriptor Address Register Channel 7 */
-#define DSADR7		__REG(0x40000274)  /* DMA Source Address Register Channel 7 */
-#define DTADR7		__REG(0x40000278)  /* DMA Target Address Register Channel 7 */
-#define DCMD7		__REG(0x4000027c)  /* DMA Command Address Register Channel 7 */
-#define DDADR8		__REG(0x40000280)  /* DMA Descriptor Address Register Channel 8 */
-#define DSADR8		__REG(0x40000284)  /* DMA Source Address Register Channel 8 */
-#define DTADR8		__REG(0x40000288)  /* DMA Target Address Register Channel 8 */
-#define DCMD8		__REG(0x4000028c)  /* DMA Command Address Register Channel 8 */
-#define DDADR9		__REG(0x40000290)  /* DMA Descriptor Address Register Channel 9 */
-#define DSADR9		__REG(0x40000294)  /* DMA Source Address Register Channel 9 */
-#define DTADR9		__REG(0x40000298)  /* DMA Target Address Register Channel 9 */
-#define DCMD9		__REG(0x4000029c)  /* DMA Command Address Register Channel 9 */
-#define DDADR10		__REG(0x400002a0)  /* DMA Descriptor Address Register Channel 10 */
-#define DSADR10		__REG(0x400002a4)  /* DMA Source Address Register Channel 10 */
-#define DTADR10		__REG(0x400002a8)  /* DMA Target Address Register Channel 10 */
-#define DCMD10		__REG(0x400002ac)  /* DMA Command Address Register Channel 10 */
-#define DDADR11		__REG(0x400002b0)  /* DMA Descriptor Address Register Channel 11 */
-#define DSADR11		__REG(0x400002b4)  /* DMA Source Address Register Channel 11 */
-#define DTADR11		__REG(0x400002b8)  /* DMA Target Address Register Channel 11 */
-#define DCMD11		__REG(0x400002bc)  /* DMA Command Address Register Channel 11 */
-#define DDADR12		__REG(0x400002c0)  /* DMA Descriptor Address Register Channel 12 */
-#define DSADR12		__REG(0x400002c4)  /* DMA Source Address Register Channel 12 */
-#define DTADR12		__REG(0x400002c8)  /* DMA Target Address Register Channel 12 */
-#define DCMD12		__REG(0x400002cc)  /* DMA Command Address Register Channel 12 */
-#define DDADR13		__REG(0x400002d0)  /* DMA Descriptor Address Register Channel 13 */
-#define DSADR13		__REG(0x400002d4)  /* DMA Source Address Register Channel 13 */
-#define DTADR13		__REG(0x400002d8)  /* DMA Target Address Register Channel 13 */
-#define DCMD13		__REG(0x400002dc)  /* DMA Command Address Register Channel 13 */
-#define DDADR14		__REG(0x400002e0)  /* DMA Descriptor Address Register Channel 14 */
-#define DSADR14		__REG(0x400002e4)  /* DMA Source Address Register Channel 14 */
-#define DTADR14		__REG(0x400002e8)  /* DMA Target Address Register Channel 14 */
-#define DCMD14		__REG(0x400002ec)  /* DMA Command Address Register Channel 14 */
-#define DDADR15		__REG(0x400002f0)  /* DMA Descriptor Address Register Channel 15 */
-#define DSADR15		__REG(0x400002f4)  /* DMA Source Address Register Channel 15 */
-#define DTADR15		__REG(0x400002f8)  /* DMA Target Address Register Channel 15 */
-#define DCMD15		__REG(0x400002fc)  /* DMA Command Address Register Channel 15 */
-
 #define DDADR(x)	__REG2(0x40000200, (x) << 4)
 #define DSADR(x)	__REG2(0x40000204, (x) << 4)
 #define DTADR(x)	__REG2(0x40000208, (x) << 4)
@@ -418,91 +265,13 @@
 
 
 /*
- * I2C registers
+ * I2C registers - moved into drivers/i2c/busses/i2c-pxa.c
  */
 
-#define IBMR		__REG(0x40301680)  /* I2C Bus Monitor Register - IBMR */
-#define IDBR		__REG(0x40301688)  /* I2C Data Buffer Register - IDBR */
-#define ICR		__REG(0x40301690)  /* I2C Control Register - ICR */
-#define ISR		__REG(0x40301698)  /* I2C Status Register - ISR */
-#define ISAR		__REG(0x403016A0)  /* I2C Slave Address Register - ISAR */
-
-#define PWRIBMR    __REG(0x40f00180)  /* Power I2C Bus Monitor Register-IBMR */
-#define PWRIDBR    __REG(0x40f00188)  /* Power I2C Data Buffer Register-IDBR */
-#define PWRICR __REG(0x40f00190)  /* Power I2C Control Register - ICR */
-#define PWRISR __REG(0x40f00198)  /* Power I2C Status Register - ISR */
-#define PWRISAR    __REG(0x40f001A0)  /*Power I2C Slave Address Register-ISAR */
-
-#define ICR_START	(1 << 0)	   /* start bit */
-#define ICR_STOP	(1 << 1)	   /* stop bit */
-#define ICR_ACKNAK	(1 << 2)	   /* send ACK(0) or NAK(1) */
-#define ICR_TB		(1 << 3)	   /* transfer byte bit */
-#define ICR_MA		(1 << 4)	   /* master abort */
-#define ICR_SCLE	(1 << 5)	   /* master clock enable */
-#define ICR_IUE		(1 << 6)	   /* unit enable */
-#define ICR_GCD		(1 << 7)	   /* general call disable */
-#define ICR_ITEIE	(1 << 8)	   /* enable tx interrupts */
-#define ICR_IRFIE	(1 << 9)	   /* enable rx interrupts */
-#define ICR_BEIE	(1 << 10)	   /* enable bus error ints */
-#define ICR_SSDIE	(1 << 11)	   /* slave STOP detected int enable */
-#define ICR_ALDIE	(1 << 12)	   /* enable arbitration interrupt */
-#define ICR_SADIE	(1 << 13)	   /* slave address detected int enable */
-#define ICR_UR		(1 << 14)	   /* unit reset */
-
-#define ISR_RWM		(1 << 0)	   /* read/write mode */
-#define ISR_ACKNAK	(1 << 1)	   /* ack/nak status */
-#define ISR_UB		(1 << 2)	   /* unit busy */
-#define ISR_IBB		(1 << 3)	   /* bus busy */
-#define ISR_SSD		(1 << 4)	   /* slave stop detected */
-#define ISR_ALD		(1 << 5)	   /* arbitration loss detected */
-#define ISR_ITE		(1 << 6)	   /* tx buffer empty */
-#define ISR_IRF		(1 << 7)	   /* rx buffer full */
-#define ISR_GCAD	(1 << 8)	   /* general call address detected */
-#define ISR_SAD		(1 << 9)	   /* slave address detected */
-#define ISR_BED		(1 << 10)	   /* bus error no ACK/NAK */
-
-
 /*
- * Serial Audio Controller
+ * Serial Audio Controller - moved into sound/soc/pxa/pxa2xx-i2s.c
  */
 
-#define SACR0		__REG(0x40400000)  /* Global Control Register */
-#define SACR1		__REG(0x40400004)  /* Serial Audio I 2 S/MSB-Justified Control Register */
-#define SASR0		__REG(0x4040000C)  /* Serial Audio I 2 S/MSB-Justified Interface and FIFO Status Register */
-#define SAIMR		__REG(0x40400014)  /* Serial Audio Interrupt Mask Register */
-#define SAICR		__REG(0x40400018)  /* Serial Audio Interrupt Clear Register */
-#define SADIV		__REG(0x40400060)  /* Audio Clock Divider Register. */
-#define SADR		__REG(0x40400080)  /* Serial Audio Data Register (TX and RX FIFO access Register). */
-
-#define SACR0_RFTH(x)	((x) << 12)	/* Rx FIFO Interrupt or DMA Trigger Threshold */
-#define SACR0_TFTH(x)	((x) << 8)	/* Tx FIFO Interrupt or DMA Trigger Threshold */
-#define SACR0_STRF	(1 << 5)	/* FIFO Select for EFWR Special Function */
-#define SACR0_EFWR	(1 << 4)	/* Enable EFWR Function  */
-#define SACR0_RST	(1 << 3)	/* FIFO, i2s Register Reset */
-#define SACR0_BCKD	(1 << 2) 	/* Bit Clock Direction */
-#define SACR0_ENB	(1 << 0)	/* Enable I2S Link */
-#define SACR1_ENLBF	(1 << 5)	/* Enable Loopback */
-#define SACR1_DRPL	(1 << 4) 	/* Disable Replaying Function */
-#define SACR1_DREC	(1 << 3)	/* Disable Recording Function */
-#define SACR1_AMSL	(1 << 0)	/* Specify Alternate Mode */
-
-#define SASR0_I2SOFF	(1 << 7)	/* Controller Status */
-#define SASR0_ROR	(1 << 6)	/* Rx FIFO Overrun */
-#define SASR0_TUR	(1 << 5)	/* Tx FIFO Underrun */
-#define SASR0_RFS	(1 << 4)	/* Rx FIFO Service Request */
-#define SASR0_TFS	(1 << 3)	/* Tx FIFO Service Request */
-#define SASR0_BSY	(1 << 2)	/* I2S Busy */
-#define SASR0_RNE	(1 << 1)	/* Rx FIFO Not Empty */
-#define SASR0_TNF	(1 << 0) 	/* Tx FIFO Not Empty */
-
-#define SAICR_ROR	(1 << 6)	/* Clear Rx FIFO Overrun Interrupt */
-#define SAICR_TUR	(1 << 5)	/* Clear Tx FIFO Underrun Interrupt */
-
-#define SAIMR_ROR	(1 << 6)	/* Enable Rx FIFO Overrun Condition Interrupt */
-#define SAIMR_TUR	(1 << 5)	/* Enable Tx FIFO Underrun Condition Interrupt */
-#define SAIMR_RFS	(1 << 4)	/* Enable Rx FIFO Service Interrupt */
-#define SAIMR_TFS	(1 << 3)	/* Enable Tx FIFO Service Interrupt */
-
 /*
  * AC97 Controller registers
  */
@@ -989,77 +758,6 @@
 
 #endif
 
-#if defined(CONFIG_PXA27x) || defined(CONFIG_PXA3xx)
-/*
- * UHC: USB Host Controller (OHCI-like) register definitions
- */
-#define UHC_BASE_PHYS	(0x4C000000)
-#define UHCREV		__REG(0x4C000000) /* UHC HCI Spec Revision */
-#define UHCHCON		__REG(0x4C000004) /* UHC Host Control Register */
-#define UHCCOMS		__REG(0x4C000008) /* UHC Command Status Register */
-#define UHCINTS		__REG(0x4C00000C) /* UHC Interrupt Status Register */
-#define UHCINTE		__REG(0x4C000010) /* UHC Interrupt Enable */
-#define UHCINTD		__REG(0x4C000014) /* UHC Interrupt Disable */
-#define UHCHCCA		__REG(0x4C000018) /* UHC Host Controller Comm. Area */
-#define UHCPCED		__REG(0x4C00001C) /* UHC Period Current Endpt Descr */
-#define UHCCHED		__REG(0x4C000020) /* UHC Control Head Endpt Descr */
-#define UHCCCED		__REG(0x4C000024) /* UHC Control Current Endpt Descr */
-#define UHCBHED		__REG(0x4C000028) /* UHC Bulk Head Endpt Descr */
-#define UHCBCED		__REG(0x4C00002C) /* UHC Bulk Current Endpt Descr */
-#define UHCDHEAD	__REG(0x4C000030) /* UHC Done Head */
-#define UHCFMI		__REG(0x4C000034) /* UHC Frame Interval */
-#define UHCFMR		__REG(0x4C000038) /* UHC Frame Remaining */
-#define UHCFMN		__REG(0x4C00003C) /* UHC Frame Number */
-#define UHCPERS		__REG(0x4C000040) /* UHC Periodic Start */
-#define UHCLS		__REG(0x4C000044) /* UHC Low Speed Threshold */
-
-#define UHCRHDA		__REG(0x4C000048) /* UHC Root Hub Descriptor A */
-#define UHCRHDA_NOCP	(1 << 12)	/* No over current protection */
-
-#define UHCRHDB		__REG(0x4C00004C) /* UHC Root Hub Descriptor B */
-#define UHCRHS		__REG(0x4C000050) /* UHC Root Hub Status */
-#define UHCRHPS1	__REG(0x4C000054) /* UHC Root Hub Port 1 Status */
-#define UHCRHPS2	__REG(0x4C000058) /* UHC Root Hub Port 2 Status */
-#define UHCRHPS3	__REG(0x4C00005C) /* UHC Root Hub Port 3 Status */
-
-#define UHCSTAT		__REG(0x4C000060) /* UHC Status Register */
-#define UHCSTAT_UPS3	(1 << 16)	/* USB Power Sense Port3 */
-#define UHCSTAT_SBMAI	(1 << 15)	/* System Bus Master Abort Interrupt*/
-#define UHCSTAT_SBTAI	(1 << 14)	/* System Bus Target Abort Interrupt*/
-#define UHCSTAT_UPRI	(1 << 13)	/* USB Port Resume Interrupt */
-#define UHCSTAT_UPS2	(1 << 12)	/* USB Power Sense Port 2 */
-#define UHCSTAT_UPS1	(1 << 11)	/* USB Power Sense Port 1 */
-#define UHCSTAT_HTA	(1 << 10)	/* HCI Target Abort */
-#define UHCSTAT_HBA	(1 << 8)	/* HCI Buffer Active */
-#define UHCSTAT_RWUE	(1 << 7)	/* HCI Remote Wake Up Event */
-
-#define UHCHR           __REG(0x4C000064) /* UHC Reset Register */
-#define UHCHR_SSEP3	(1 << 11)	/* Sleep Standby Enable for Port3 */
-#define UHCHR_SSEP2	(1 << 10)	/* Sleep Standby Enable for Port2 */
-#define UHCHR_SSEP1	(1 << 9)	/* Sleep Standby Enable for Port1 */
-#define UHCHR_PCPL	(1 << 7)	/* Power control polarity low */
-#define UHCHR_PSPL	(1 << 6)	/* Power sense polarity low */
-#define UHCHR_SSE	(1 << 5)	/* Sleep Standby Enable */
-#define UHCHR_UIT	(1 << 4)	/* USB Interrupt Test */
-#define UHCHR_SSDC	(1 << 3)	/* Simulation Scale Down Clock */
-#define UHCHR_CGR	(1 << 2)	/* Clock Generation Reset */
-#define UHCHR_FHR	(1 << 1)	/* Force Host Controller Reset */
-#define UHCHR_FSBIR	(1 << 0)	/* Force System Bus Iface Reset */
-
-#define UHCHIE          __REG(0x4C000068) /* UHC Interrupt Enable Register*/
-#define UHCHIE_UPS3IE	(1 << 14)	/* Power Sense Port3 IntEn */
-#define UHCHIE_UPRIE	(1 << 13)	/* Port Resume IntEn */
-#define UHCHIE_UPS2IE	(1 << 12)	/* Power Sense Port2 IntEn */
-#define UHCHIE_UPS1IE	(1 << 11)	/* Power Sense Port1 IntEn */
-#define UHCHIE_TAIE	(1 << 10)	/* HCI Interface Transfer Abort
-					   Interrupt Enable*/
-#define UHCHIE_HBAIE	(1 << 8)	/* HCI Buffer Active IntEn */
-#define UHCHIE_RWIE	(1 << 7)	/* Remote Wake-up IntEn */
-
-#define UHCHIT          __REG(0x4C00006C) /* UHC Interrupt Test register */
-
-#endif /* CONFIG_PXA27x || CONFIG_PXA3xx */
-
 /* PWRMODE register M field values */
 
 #define PWRMODE_IDLE		0x1
diff --git a/arch/arm/mach-pxa/include/mach/pxa3xx-regs.h b/arch/arm/mach-pxa/include/mach/pxa3xx-regs.h
index 39eb683..b1fcd10 100644
--- a/arch/arm/mach-pxa/include/mach/pxa3xx-regs.h
+++ b/arch/arm/mach-pxa/include/mach/pxa3xx-regs.h
@@ -131,6 +131,28 @@
 #define CKENB		__REG(0x41340010)	/* B Clock Enable Register */
 #define AC97_DIV	__REG(0x41340014)	/* AC97 clock divisor value register */
 
+#define ACCR_XPDIS		(1 << 31)	/* Core PLL Output Disable */
+#define ACCR_SPDIS		(1 << 30)	/* System PLL Output Disable */
+#define ACCR_D0CS		(1 << 26)	/* D0 Mode Clock Select */
+#define ACCR_PCCE		(1 << 11)	/* Power Mode Change Clock Enable */
+#define ACCR_DDR_D0CS		(1 << 7)	/* DDR SDRAM clock frequency in D0CS (PXA31x only) */
+
+#define ACCR_SMCFS_MASK		(0x7 << 23)	/* Static Memory Controller Frequency Select */
+#define ACCR_SFLFS_MASK		(0x3 << 18)	/* Frequency Select for Internal Memory Controller */
+#define ACCR_XSPCLK_MASK	(0x3 << 16)	/* Core Frequency during Frequency Change */
+#define ACCR_HSS_MASK		(0x3 << 14)	/* System Bus-Clock Frequency Select */
+#define ACCR_DMCFS_MASK		(0x3 << 12)	/* Dynamic Memory Controller Clock Frequency Select */
+#define ACCR_XN_MASK		(0x7 << 8)	/* Core PLL Turbo-Mode-to-Run-Mode Ratio */
+#define ACCR_XL_MASK		(0x1f)		/* Core PLL Run-Mode-to-Oscillator Ratio */
+
+#define ACCR_SMCFS(x)		(((x) & 0x7) << 23)
+#define ACCR_SFLFS(x)		(((x) & 0x3) << 18)
+#define ACCR_XSPCLK(x)		(((x) & 0x3) << 16)
+#define ACCR_HSS(x)		(((x) & 0x3) << 14)
+#define ACCR_DMCFS(x)		(((x) & 0x3) << 12)
+#define ACCR_XN(x)		(((x) & 0x7) << 8)
+#define ACCR_XL(x)		((x) & 0x1f)
+
 /*
  * Clock Enable Bit
  */
diff --git a/arch/arm/mach-pxa/include/mach/reset.h b/arch/arm/mach-pxa/include/mach/reset.h
index 9489a48..7b8842c 100644
--- a/arch/arm/mach-pxa/include/mach/reset.h
+++ b/arch/arm/mach-pxa/include/mach/reset.h
@@ -10,9 +10,12 @@
 extern unsigned int reset_status;
 extern void clear_reset_status(unsigned int mask);
 
-/*
- * register GPIO as reset generator
+/**
+ * init_gpio_reset() - register GPIO as reset generator
+ *
+ * @gpio - gpio nr
+ * @output - set gpio as out/low instead of input during normal work
  */
-extern int init_gpio_reset(int gpio);
+extern int init_gpio_reset(int gpio, int output);
 
 #endif /* __ASM_ARCH_RESET_H */
diff --git a/arch/arm/mach-pxa/include/mach/spitz.h b/arch/arm/mach-pxa/include/mach/spitz.h
index bd14365..31ac26b 100644
--- a/arch/arm/mach-pxa/include/mach/spitz.h
+++ b/arch/arm/mach-pxa/include/mach/spitz.h
@@ -16,6 +16,7 @@
 #endif
 
 #include <linux/fb.h>
+#include <linux/gpio.h>
 
 /* Spitz/Akita GPIOs */
 
@@ -100,13 +101,24 @@
 #define SPITZ_SCP_JK_A          SCOOP_GPCR_PA18  /* Low */
 #define SPITZ_SCP_ADC_TEMP_ON   SCOOP_GPCR_PA19  /* Low */
 
-#define SPITZ_SCP_IO_DIR      (SPITZ_SCP_LED_GREEN | SPITZ_SCP_JK_B | SPITZ_SCP_CHRG_ON | \
-                               SPITZ_SCP_MUTE_L | SPITZ_SCP_MUTE_R | SPITZ_SCP_LED_ORANGE | \
+#define SPITZ_SCP_IO_DIR      (SPITZ_SCP_JK_B | SPITZ_SCP_CHRG_ON | \
+                               SPITZ_SCP_MUTE_L | SPITZ_SCP_MUTE_R | \
                                SPITZ_SCP_CF_POWER | SPITZ_SCP_JK_A | SPITZ_SCP_ADC_TEMP_ON)
 #define SPITZ_SCP_IO_OUT      (SPITZ_SCP_CHRG_ON | SPITZ_SCP_MUTE_L | SPITZ_SCP_MUTE_R)
 #define SPITZ_SCP_SUS_CLR     (SPITZ_SCP_MUTE_L | SPITZ_SCP_MUTE_R | SPITZ_SCP_JK_A | SPITZ_SCP_ADC_TEMP_ON)
 #define SPITZ_SCP_SUS_SET     0
 
+#define SPITZ_SCP_GPIO_BASE	(NR_BUILTIN_GPIO)
+#define SPITZ_GPIO_LED_GREEN	(SPITZ_SCP_GPIO_BASE + 0)
+#define SPITZ_GPIO_JK_B		(SPITZ_SCP_GPIO_BASE + 1)
+#define SPITZ_GPIO_CHRG_ON	(SPITZ_SCP_GPIO_BASE + 2)
+#define SPITZ_GPIO_MUTE_L	(SPITZ_SCP_GPIO_BASE + 3)
+#define SPITZ_GPIO_MUTE_R	(SPITZ_SCP_GPIO_BASE + 4)
+#define SPITZ_GPIO_CF_POWER	(SPITZ_SCP_GPIO_BASE + 5)
+#define SPITZ_GPIO_LED_ORANGE	(SPITZ_SCP_GPIO_BASE + 6)
+#define SPITZ_GPIO_JK_A		(SPITZ_SCP_GPIO_BASE + 7)
+#define SPITZ_GPIO_ADC_TEMP_ON	(SPITZ_SCP_GPIO_BASE + 8)
+
 /* Spitz Scoop Device (No. 2) GPIOs */
 /* Suspend States in comments */
 #define SPITZ_SCP2_IR_ON           SCOOP_GPCR_PA11  /* High */
@@ -119,15 +131,36 @@
 #define SPITZ_SCP2_BACKLIGHT_ON    SCOOP_GPCR_PA18  /* Low */
 #define SPITZ_SCP2_MIC_BIAS        SCOOP_GPCR_PA19  /* Low */
 
-#define SPITZ_SCP2_IO_DIR (SPITZ_SCP2_IR_ON | SPITZ_SCP2_AKIN_PULLUP | SPITZ_SCP2_RESERVED_1 | \
+#define SPITZ_SCP2_IO_DIR (SPITZ_SCP2_AKIN_PULLUP | SPITZ_SCP2_RESERVED_1 | \
                            SPITZ_SCP2_RESERVED_2 | SPITZ_SCP2_RESERVED_3 | SPITZ_SCP2_RESERVED_4 | \
                            SPITZ_SCP2_BACKLIGHT_CONT | SPITZ_SCP2_BACKLIGHT_ON | SPITZ_SCP2_MIC_BIAS)
 
-#define SPITZ_SCP2_IO_OUT   (SPITZ_SCP2_IR_ON | SPITZ_SCP2_AKIN_PULLUP | SPITZ_SCP2_RESERVED_1)
+#define SPITZ_SCP2_IO_OUT   (SPITZ_SCP2_AKIN_PULLUP | SPITZ_SCP2_RESERVED_1)
 #define SPITZ_SCP2_SUS_CLR  (SPITZ_SCP2_RESERVED_2 | SPITZ_SCP2_RESERVED_3 | SPITZ_SCP2_RESERVED_4 | \
                              SPITZ_SCP2_BACKLIGHT_CONT | SPITZ_SCP2_BACKLIGHT_ON | SPITZ_SCP2_MIC_BIAS)
 #define SPITZ_SCP2_SUS_SET  (SPITZ_SCP2_IR_ON | SPITZ_SCP2_RESERVED_1)
 
+#define SPITZ_SCP2_GPIO_BASE		(NR_BUILTIN_GPIO + 12)
+#define SPITZ_GPIO_IR_ON		(SPITZ_SCP2_GPIO_BASE + 0)
+#define SPITZ_GPIO_AKIN_PULLUP		(SPITZ_SCP2_GPIO_BASE + 1
+#define SPITZ_GPIO_RESERVED_1		(SPITZ_SCP2_GPIO_BASE + 2)
+#define SPITZ_GPIO_RESERVED_2		(SPITZ_SCP2_GPIO_BASE + 3)
+#define SPITZ_GPIO_RESERVED_3		(SPITZ_SCP2_GPIO_BASE + 4)
+#define SPITZ_GPIO_RESERVED_4		(SPITZ_SCP2_GPIO_BASE + 5)
+#define SPITZ_GPIO_BACKLIGHT_CONT	(SPITZ_SCP2_GPIO_BASE + 6)
+#define SPITZ_GPIO_BACKLIGHT_ON		(SPITZ_SCP2_GPIO_BASE + 7)
+#define SPITZ_GPIO_MIC_BIAS		(SPITZ_SCP2_GPIO_BASE + 8)
+
+/* Akita IO Expander GPIOs */
+#define AKITA_IOEXP_GPIO_BASE		(NR_BUILTIN_GPIO + 12)
+#define AKITA_GPIO_RESERVED_0		(AKITA_IOEXP_GPIO_BASE + 0)
+#define AKITA_GPIO_RESERVED_1		(AKITA_IOEXP_GPIO_BASE + 1)
+#define AKITA_GPIO_MIC_BIAS		(AKITA_IOEXP_GPIO_BASE + 2)
+#define AKITA_GPIO_BACKLIGHT_ON		(AKITA_IOEXP_GPIO_BASE + 3)
+#define AKITA_GPIO_BACKLIGHT_CONT	(AKITA_IOEXP_GPIO_BASE + 4)
+#define AKITA_GPIO_AKIN_PULLUP		(AKITA_IOEXP_GPIO_BASE + 5)
+#define AKITA_GPIO_IR_ON		(AKITA_IOEXP_GPIO_BASE + 6)
+#define AKITA_GPIO_RESERVED_7		(AKITA_IOEXP_GPIO_BASE + 7)
 
 /* Spitz IRQ Definitions */
 
@@ -154,5 +187,4 @@
  */
 extern struct platform_device spitzscoop_device;
 extern struct platform_device spitzscoop2_device;
-extern struct platform_device spitzssp_device;
 extern struct sharpsl_charger_machinfo spitz_pm_machinfo;
diff --git a/arch/arm/mach-pxa/include/mach/ssp.h b/arch/arm/mach-pxa/include/mach/ssp.h
index a012882..cb5cb76 100644
--- a/arch/arm/mach-pxa/include/mach/ssp.h
+++ b/arch/arm/mach-pxa/include/mach/ssp.h
@@ -20,6 +20,7 @@
 #define __ASM_ARCH_SSP_H
 
 #include <linux/list.h>
+#include <linux/io.h>
 
 enum pxa_ssp_type {
 	SSP_UNDEFINED = 0,
@@ -78,6 +79,29 @@
 int ssp_config(struct ssp_dev *dev, u32 mode, u32 flags, u32 psp_flags, u32 speed);
 void ssp_exit(struct ssp_dev *dev);
 
+/**
+ * ssp_write_reg - Write to a SSP register
+ *
+ * @dev: SSP device to access
+ * @reg: Register to write to
+ * @val: Value to be written.
+ */
+static inline void ssp_write_reg(struct ssp_device *dev, u32 reg, u32 val)
+{
+	__raw_writel(val, dev->mmio_base + reg);
+}
+
+/**
+ * ssp_read_reg - Read from a SSP register
+ *
+ * @dev: SSP device to access
+ * @reg: Register to read from
+ */
+static inline u32 ssp_read_reg(struct ssp_device *dev, u32 reg)
+{
+	return __raw_readl(dev->mmio_base + reg);
+}
+
 struct ssp_device *ssp_request(int port, const char *label);
 void ssp_free(struct ssp_device *);
 #endif /* __ASM_ARCH_SSP_H */
diff --git a/arch/arm/mach-pxa/include/mach/trizeps4.h b/arch/arm/mach-pxa/include/mach/trizeps4.h
index 641d0ec..903e1a2 100644
--- a/arch/arm/mach-pxa/include/mach/trizeps4.h
+++ b/arch/arm/mach-pxa/include/mach/trizeps4.h
@@ -17,11 +17,16 @@
 #define TRIZEPS4_PIC_PHYS	(PXA_CS3_PHYS)	/* Logic chip on ConXS-Board */
 #define TRIZEPS4_SDRAM_BASE	0xa0000000      /* SDRAM region */
 
-#define TRIZEPS4_CFSR_PHYS	(PXA_CS3_PHYS)			/* Logic chip on ConXS-Board CSFR register */
-#define TRIZEPS4_BOCR_PHYS	(PXA_CS3_PHYS+0x02000000)	/* Logic chip on ConXS-Board BOCR register */
-#define TRIZEPS4_IRCR_PHYS	(PXA_CS3_PHYS+0x02400000)	/* Logic chip on ConXS-Board IRCR register*/
-#define TRIZEPS4_UPSR_PHYS	(PXA_CS3_PHYS+0x02800000)	/* Logic chip on ConXS-Board UPSR register*/
-#define TRIZEPS4_DICR_PHYS	(PXA_CS3_PHYS+0x03800000)	/* Logic chip on ConXS-Board DICR register*/
+				/* Logic on ConXS-board CSFR register*/
+#define TRIZEPS4_CFSR_PHYS	(PXA_CS3_PHYS)
+				/* Logic on ConXS-board BOCR register*/
+#define TRIZEPS4_BOCR_PHYS	(PXA_CS3_PHYS+0x02000000)
+				/* Logic on ConXS-board IRCR register*/
+#define TRIZEPS4_IRCR_PHYS	(PXA_CS3_PHYS+0x02400000)
+				/* Logic on ConXS-board UPSR register*/
+#define TRIZEPS4_UPSR_PHYS	(PXA_CS3_PHYS+0x02800000)
+				/* Logic on ConXS-board DICR register*/
+#define TRIZEPS4_DICR_PHYS	(PXA_CS3_PHYS+0x03800000)
 
 /* virtual memory regions */
 #define TRIZEPS4_DISK_VIRT	0xF0000000	/* Disk On Chip region */
@@ -54,6 +59,15 @@
 #define GPIO_MMC_DET		12
 #define TRIZEPS4_MMC_IRQ	IRQ_GPIO(GPIO_MMC_DET)
 
+/* DOC NAND chip */
+#define GPIO_DOC_LOCK           94
+#define GPIO_DOC_IRQ            93
+#define TRIZEPS4_DOC_IRQ        IRQ_GPIO(GPIO_DOC_IRQ)
+
+/* SPI interface */
+#define GPIO_SPI                53
+#define TRIZEPS4_SPI_IRQ        IRQ_GPIO(GPIO_SPI)
+
 /* LEDS using tx2 / rx2 */
 #define GPIO_SYS_BUSY_LED	46
 #define GPIO_HEARTBEAT_LED	47
@@ -62,24 +76,66 @@
 #define GPIO_PIC		0
 #define TRIZEPS4_PIC_IRQ	IRQ_GPIO(GPIO_PIC)
 
-#define CFSR_P2V(x)		((x) - TRIZEPS4_CFSR_PHYS + TRIZEPS4_CFSR_VIRT)
-#define CFSR_V2P(x)		((x) - TRIZEPS4_CFSR_VIRT + TRIZEPS4_CFSR_PHYS)
+#ifdef CONFIG_MACH_TRIZEPS_CONXS
+/* for CONXS base board define these registers */
+#define CFSR_P2V(x)	((x) - TRIZEPS4_CFSR_PHYS + TRIZEPS4_CFSR_VIRT)
+#define CFSR_V2P(x)	((x) - TRIZEPS4_CFSR_VIRT + TRIZEPS4_CFSR_PHYS)
 
-#define BCR_P2V(x)		((x) - TRIZEPS4_BOCR_PHYS + TRIZEPS4_BOCR_VIRT)
-#define BCR_V2P(x)		((x) - TRIZEPS4_BOCR_VIRT + TRIZEPS4_BOCR_PHYS)
+#define BCR_P2V(x)	((x) - TRIZEPS4_BOCR_PHYS + TRIZEPS4_BOCR_VIRT)
+#define BCR_V2P(x)	((x) - TRIZEPS4_BOCR_VIRT + TRIZEPS4_BOCR_PHYS)
 
-#define DCR_P2V(x)		((x) - TRIZEPS4_DICR_PHYS + TRIZEPS4_DICR_VIRT)
-#define DCR_V2P(x)		((x) - TRIZEPS4_DICR_VIRT + TRIZEPS4_DICR_PHYS)
+#define DCR_P2V(x)	((x) - TRIZEPS4_DICR_PHYS + TRIZEPS4_DICR_VIRT)
+#define DCR_V2P(x)	((x) - TRIZEPS4_DICR_VIRT + TRIZEPS4_DICR_PHYS)
+
+#define IRCR_P2V(x)	((x) - TRIZEPS4_IRCR_PHYS + TRIZEPS4_IRCR_VIRT)
+#define IRCR_V2P(x)	((x) - TRIZEPS4_IRCR_VIRT + TRIZEPS4_IRCR_PHYS)
 
 #ifndef __ASSEMBLY__
-#define ConXS_CFSR		(*((volatile unsigned short *)CFSR_P2V(0x0C000000)))
-#define ConXS_BCR		(*((volatile unsigned short *)BCR_P2V(0x0E000000)))
-#define ConXS_DCR		(*((volatile unsigned short *)DCR_P2V(0x0F800000)))
+static inline unsigned short CFSR_readw(void)
+{
+	/* [Compact Flash Status Register] is read only */
+	return *((unsigned short *)CFSR_P2V(0x0C000000));
+}
+static inline void BCR_writew(unsigned short value)
+{
+	/* [Board Control Regsiter] is write only */
+	*((unsigned short *)BCR_P2V(0x0E000000)) = value;
+}
+static inline void DCR_writew(unsigned short value)
+{
+	/* [Display Control Register] is write only */
+	*((unsigned short *)DCR_P2V(0x0E000000)) = value;
+}
+static inline void IRCR_writew(unsigned short value)
+{
+	/* [InfraRed data Control Register] is write only */
+	*((unsigned short *)IRCR_P2V(0x0E000000)) = value;
+}
 #else
 #define ConXS_CFSR		CFSR_P2V(0x0C000000)
 #define ConXS_BCR		BCR_P2V(0x0E000000)
 #define ConXS_DCR		DCR_P2V(0x0F800000)
+#define ConXS_IRCR		IRCR_P2V(0x0F800000)
 #endif
+#else
+/* for whatever baseboard define function registers */
+static inline unsigned short CFSR_readw(void)
+{
+	return 0;
+}
+static inline void BCR_writew(unsigned short value)
+{
+	;
+}
+static inline void DCR_writew(unsigned short value)
+{
+	;
+}
+static inline void IRCR_writew(unsigned short value)
+{
+	;
+}
+#endif	/* CONFIG_MACH_TRIZEPS_CONXS */
 
 #define ConXS_CFSR_BVD_MASK	0x0003
 #define ConXS_CFSR_BVD1		(1 << 0)
diff --git a/arch/arm/mach-pxa/include/mach/viper.h b/arch/arm/mach-pxa/include/mach/viper.h
new file mode 100644
index 0000000..10988c2
--- /dev/null
+++ b/arch/arm/mach-pxa/include/mach/viper.h
@@ -0,0 +1,96 @@
+/*
+ * arch/arm/mach-pxa/include/mach/viper.h
+ *
+ * Author:	Ian Campbell
+ * Created:	Feb 03, 2003
+ * Copyright:	Arcom Control Systems.
+ *
+ * Maintained by Marc Zyngier <maz@misterjones.org>
+ *			      <marc.zyngier@altran.com>
+ *
+ * Created based on lubbock.h:
+ *  Author:	Nicolas Pitre
+ *  Created:	Jun 15, 2001
+ *  Copyright:	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 version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef ARCH_VIPER_H
+#define ARCH_VIPER_H
+
+#define VIPER_BOOT_PHYS		PXA_CS0_PHYS
+#define VIPER_FLASH_PHYS	PXA_CS1_PHYS
+#define VIPER_ETH_PHYS		PXA_CS2_PHYS
+#define VIPER_USB_PHYS		PXA_CS3_PHYS
+#define VIPER_ETH_DATA_PHYS	PXA_CS4_PHYS
+#define VIPER_CPLD_PHYS		PXA_CS5_PHYS
+
+#define VIPER_CPLD_BASE		(0xf0000000)
+#define VIPER_PC104IO_BASE	(0xf1000000)
+#define VIPER_USB_BASE		(0xf1800000)
+
+#define VIPER_ETH_GPIO		(0)
+#define VIPER_CPLD_GPIO		(1)
+#define VIPER_USB_GPIO		(2)
+#define VIPER_UARTA_GPIO	(4)
+#define VIPER_UARTB_GPIO	(3)
+#define VIPER_CF_CD_GPIO	(32)
+#define VIPER_CF_RDY_GPIO	(8)
+#define VIPER_BCKLIGHT_EN_GPIO	(9)
+#define VIPER_LCD_EN_GPIO	(10)
+#define VIPER_PSU_DATA_GPIO	(6)
+#define VIPER_PSU_CLK_GPIO	(11)
+#define VIPER_UART_SHDN_GPIO	(12)
+#define VIPER_BRIGHTNESS_GPIO	(16)
+#define VIPER_PSU_nCS_LD_GPIO	(19)
+#define VIPER_UPS_GPIO		(20)
+#define VIPER_CF_POWER_GPIO	(82)
+#define VIPER_TPM_I2C_SDA_GPIO	(26)
+#define VIPER_TPM_I2C_SCL_GPIO	(27)
+#define VIPER_RTC_I2C_SDA_GPIO	(83)
+#define VIPER_RTC_I2C_SCL_GPIO	(84)
+
+#define VIPER_CPLD_P2V(x)	((x) - VIPER_CPLD_PHYS + VIPER_CPLD_BASE)
+#define VIPER_CPLD_V2P(x)	((x) - VIPER_CPLD_BASE + VIPER_CPLD_PHYS)
+
+#ifndef __ASSEMBLY__
+#  define __VIPER_CPLD_REG(x)	(*((volatile u16 *)VIPER_CPLD_P2V(x)))
+#endif
+
+/* board level registers in the CPLD: (offsets from CPLD_BASE) ... */
+
+/* ... Physical addresses */
+#define _VIPER_LO_IRQ_STATUS	(VIPER_CPLD_PHYS + 0x100000)
+#define _VIPER_ICR_PHYS		(VIPER_CPLD_PHYS + 0x100002)
+#define _VIPER_HI_IRQ_STATUS	(VIPER_CPLD_PHYS + 0x100004)
+#define _VIPER_VERSION_PHYS	(VIPER_CPLD_PHYS + 0x100006)
+#define VIPER_UARTA_PHYS	(VIPER_CPLD_PHYS + 0x300010)
+#define VIPER_UARTB_PHYS	(VIPER_CPLD_PHYS + 0x300000)
+#define _VIPER_SRAM_BASE	(VIPER_CPLD_PHYS + 0x800000)
+
+/* ... Virtual addresses */
+#define VIPER_LO_IRQ_STATUS	__VIPER_CPLD_REG(_VIPER_LO_IRQ_STATUS)
+#define VIPER_HI_IRQ_STATUS	__VIPER_CPLD_REG(_VIPER_HI_IRQ_STATUS)
+#define VIPER_VERSION		__VIPER_CPLD_REG(_VIPER_VERSION_PHYS)
+#define VIPER_ICR		__VIPER_CPLD_REG(_VIPER_ICR_PHYS)
+
+/* Decode VIPER_VERSION register */
+#define VIPER_CPLD_REVISION(x)	(((x) >> 5) & 0x7)
+#define VIPER_BOARD_VERSION(x)	(((x) >> 3) & 0x3)
+#define VIPER_BOARD_ISSUE(x)	(((x) >> 0) & 0x7)
+
+/* Interrupt and Configuration Register (VIPER_ICR) */
+/* This is a write only register. Only CF_RST is used under Linux */
+
+extern void viper_cf_rst(int state);
+
+#define VIPER_ICR_RETRIG	(1 << 0)
+#define VIPER_ICR_AUTO_CLR	(1 << 1)
+#define VIPER_ICR_R_DIS		(1 << 2)
+#define VIPER_ICR_CF_RST	(1 << 3)
+
+#endif
+
diff --git a/arch/arm/mach-pxa/irq.c b/arch/arm/mach-pxa/irq.c
index 5e95c53..fa69c3a 100644
--- a/arch/arm/mach-pxa/irq.c
+++ b/arch/arm/mach-pxa/irq.c
@@ -57,7 +57,7 @@
 
 	pxa_internal_irq_nr = irq_nr;
 
-	for (irq = 0; irq < irq_nr; irq += 32) {
+	for (irq = PXA_IRQ(0); irq < PXA_IRQ(irq_nr); irq += 32) {
 		_ICMR(irq) = 0;	/* disable all IRQs */
 		_ICLR(irq) = 0;	/* all IRQs are IRQ, not FIQ */
 	}
diff --git a/arch/arm/mach-pxa/leds-trizeps4.c b/arch/arm/mach-pxa/leds-trizeps4.c
deleted file mode 100644
index 3bc2900..0000000
--- a/arch/arm/mach-pxa/leds-trizeps4.c
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- * linux/arch/arm/mach-pxa/leds-trizeps4.c
- *
- *  Author:	Jürgen Schindele
- *  Created:	20 02, 2006
- *  Copyright:	Jürgen Schindele
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/init.h>
-
-#include <mach/hardware.h>
-#include <asm/system.h>
-#include <asm/types.h>
-#include <asm/leds.h>
-
-#include <mach/pxa-regs.h>
-#include <mach/pxa2xx-gpio.h>
-#include <mach/trizeps4.h>
-
-#include "leds.h"
-
-#define LED_STATE_ENABLED	1
-#define LED_STATE_CLAIMED	2
-
-#define SYS_BUSY		0x01
-#define HEARTBEAT		0x02
-#define BLINK			0x04
-
-static unsigned int led_state;
-static unsigned int hw_led_state;
-
-void trizeps4_leds_event(led_event_t evt)
-{
-	unsigned long flags;
-
-	local_irq_save(flags);
-
-	switch (evt) {
-	case led_start:
-		hw_led_state = 0;
-		pxa_gpio_mode( GPIO_SYS_BUSY_LED  | GPIO_OUT);		/* LED1 */
-		pxa_gpio_mode( GPIO_HEARTBEAT_LED | GPIO_OUT);		/* LED2 */
-		led_state = LED_STATE_ENABLED;
-		break;
-
-	case led_stop:
-		led_state &= ~LED_STATE_ENABLED;
-		break;
-
-	case led_claim:
-		led_state |= LED_STATE_CLAIMED;
-		hw_led_state = 0;
-		break;
-
-	case led_release:
-		led_state &= ~LED_STATE_CLAIMED;
-		hw_led_state = 0;
-		break;
-
-#ifdef CONFIG_LEDS_TIMER
-	case led_timer:
-		hw_led_state ^= HEARTBEAT;
-		break;
-#endif
-
-#ifdef CONFIG_LEDS_CPU
-	case led_idle_start:
-		hw_led_state &= ~SYS_BUSY;
-		break;
-
-	case led_idle_end:
-		hw_led_state |= SYS_BUSY;
-		break;
-#endif
-
-	case led_halted:
-		break;
-
-	case led_green_on:
-		hw_led_state |= BLINK;
-		break;
-
-	case led_green_off:
-		hw_led_state &= ~BLINK;
-		break;
-
-	case led_amber_on:
-		break;
-
-	case led_amber_off:
-		break;
-
-	case led_red_on:
-		break;
-
-	case led_red_off:
-		break;
-
-	default:
-		break;
-	}
-
-	if  (led_state & LED_STATE_ENABLED) {
-		switch (hw_led_state) {
-			case 0:
-				GPSR(GPIO_SYS_BUSY_LED)  |= GPIO_bit(GPIO_SYS_BUSY_LED);
-				GPSR(GPIO_HEARTBEAT_LED) |= GPIO_bit(GPIO_HEARTBEAT_LED);
-				break;
-			case 1:
-				GPCR(GPIO_SYS_BUSY_LED)  |= GPIO_bit(GPIO_SYS_BUSY_LED);
-				GPSR(GPIO_HEARTBEAT_LED) |= GPIO_bit(GPIO_HEARTBEAT_LED);
-				break;
-			case 2:
-				GPSR(GPIO_SYS_BUSY_LED)  |= GPIO_bit(GPIO_SYS_BUSY_LED);
-				GPCR(GPIO_HEARTBEAT_LED) |= GPIO_bit(GPIO_HEARTBEAT_LED);
-				break;
-			case 3:
-				GPCR(GPIO_SYS_BUSY_LED)  |= GPIO_bit(GPIO_SYS_BUSY_LED);
-				GPCR(GPIO_HEARTBEAT_LED) |= GPIO_bit(GPIO_HEARTBEAT_LED);
-				break;
-		}
-	}
-	else {
-		/* turn all off */
-		GPSR(GPIO_SYS_BUSY_LED)  |= GPIO_bit(GPIO_SYS_BUSY_LED);
-		GPSR(GPIO_HEARTBEAT_LED) |= GPIO_bit(GPIO_HEARTBEAT_LED);
-	}
-
-	local_irq_restore(flags);
-}
diff --git a/arch/arm/mach-pxa/leds.c b/arch/arm/mach-pxa/leds.c
index e13eb84..bbe4d5f 100644
--- a/arch/arm/mach-pxa/leds.c
+++ b/arch/arm/mach-pxa/leds.c
@@ -24,8 +24,6 @@
 		leds_event = mainstone_leds_event;
 	if (machine_is_pxa_idp())
 		leds_event = idp_leds_event;
-	if (machine_is_trizeps4())
-		leds_event = trizeps4_leds_event;
 
 	leds_event(led_start);
 	return 0;
diff --git a/arch/arm/mach-pxa/littleton.c b/arch/arm/mach-pxa/littleton.c
index 58f3402..b4d00ab 100644
--- a/arch/arm/mach-pxa/littleton.c
+++ b/arch/arm/mach-pxa/littleton.c
@@ -20,6 +20,7 @@
 #include <linux/delay.h>
 #include <linux/platform_device.h>
 #include <linux/clk.h>
+#include <linux/spi/spi.h>
 #include <linux/smc91x.h>
 
 #include <asm/types.h>
@@ -38,6 +39,7 @@
 #include <mach/gpio.h>
 #include <mach/pxafb.h>
 #include <mach/ssp.h>
+#include <mach/pxa2xx_spi.h>
 #include <mach/pxa27x_keypad.h>
 #include <mach/pxa3xx_nand.h>
 #include <mach/littleton.h>
@@ -72,8 +74,8 @@
 
 	/* SSP2 */
 	GPIO25_SSP2_SCLK,
-	GPIO17_SSP2_FRM,
 	GPIO27_SSP2_TXD,
+	GPIO17_GPIO,	/* SFRM as chip-select */
 
 	/* Debug Ethernet */
 	GPIO90_GPIO,
@@ -123,160 +125,6 @@
 };
 
 #if defined(CONFIG_FB_PXA) || defined(CONFIG_FB_PXA_MODULE)
-/* use bit 30, 31 as the indicator of command parameter number */
-#define CMD0(x)		((0x00000000) | ((x) << 9))
-#define CMD1(x, x1)	((0x40000000) | ((x) << 9) | 0x100 | (x1))
-#define CMD2(x, x1, x2)	((0x80000000) | ((x) << 18) | 0x20000 |\
-			 ((x1) << 9) | 0x100 | (x2))
-
-static uint32_t lcd_panel_reset[] = {
-	CMD0(0x1), /* reset */
-	CMD0(0x0), /* nop */
-	CMD0(0x0), /* nop */
-	CMD0(0x0), /* nop */
-};
-
-static uint32_t lcd_panel_on[] = {
-	CMD0(0x29),		/* Display ON */
-	CMD2(0xB8, 0xFF, 0xF9),	/* Output Control */
-	CMD0(0x11),		/* Sleep out */
-	CMD1(0xB0, 0x16),	/* Wake */
-};
-
-static uint32_t lcd_panel_off[] = {
-	CMD0(0x28),		/* Display OFF */
-	CMD2(0xB8, 0x80, 0x02),	/* Output Control */
-	CMD0(0x10),		/* Sleep in */
-	CMD1(0xB0, 0x00),	/* Deep stand by in */
-};
-
-static uint32_t lcd_vga_pass_through[] = {
-	CMD1(0xB0, 0x16),
-	CMD1(0xBC, 0x80),
-	CMD1(0xE1, 0x00),
-	CMD1(0x36, 0x50),
-	CMD1(0x3B, 0x00),
-};
-
-static uint32_t lcd_qvga_pass_through[] = {
-	CMD1(0xB0, 0x16),
-	CMD1(0xBC, 0x81),
-	CMD1(0xE1, 0x00),
-	CMD1(0x36, 0x50),
-	CMD1(0x3B, 0x22),
-};
-
-static uint32_t lcd_vga_transfer[] = {
-	CMD1(0xcf, 0x02), 	/* Blanking period control (1) */
-	CMD2(0xd0, 0x08, 0x04),	/* Blanking period control (2) */
-	CMD1(0xd1, 0x01),	/* CKV timing control on/off */
-	CMD2(0xd2, 0x14, 0x00),	/* CKV 1,2 timing control */
-	CMD2(0xd3, 0x1a, 0x0f),	/* OEV timing control */
-	CMD2(0xd4, 0x1f, 0xaf),	/* ASW timing control (1) */
-	CMD1(0xd5, 0x14),	/* ASW timing control (2) */
-	CMD0(0x21),		/* Invert for normally black display */
-	CMD0(0x29),		/* Display on */
-};
-
-static uint32_t lcd_qvga_transfer[] = {
-	CMD1(0xd6, 0x02),	/* Blanking period control (1) */
-	CMD2(0xd7, 0x08, 0x04),	/* Blanking period control (2) */
-	CMD1(0xd8, 0x01),	/* CKV timing control on/off */
-	CMD2(0xd9, 0x00, 0x08),	/* CKV 1,2 timing control */
-	CMD2(0xde, 0x05, 0x0a),	/* OEV timing control */
-	CMD2(0xdf, 0x0a, 0x19),	/* ASW timing control (1) */
-	CMD1(0xe0, 0x0a),	/* ASW timing control (2) */
-	CMD0(0x21),		/* Invert for normally black display */
-	CMD0(0x29),		/* Display on */
-};
-
-static uint32_t lcd_panel_config[] = {
-	CMD2(0xb8, 0xff, 0xf9),	/* Output control */
-	CMD0(0x11),		/* sleep out */
-	CMD1(0xba, 0x01),	/* Display mode (1) */
-	CMD1(0xbb, 0x00),	/* Display mode (2) */
-	CMD1(0x3a, 0x60),	/* Display mode 18-bit RGB */
-	CMD1(0xbf, 0x10),	/* Drive system change control */
-	CMD1(0xb1, 0x56),	/* Booster operation setup */
-	CMD1(0xb2, 0x33),	/* Booster mode setup */
-	CMD1(0xb3, 0x11),	/* Booster frequency setup */
-	CMD1(0xb4, 0x02),	/* Op amp/system clock */
-	CMD1(0xb5, 0x35),	/* VCS voltage */
-	CMD1(0xb6, 0x40),	/* VCOM voltage */
-	CMD1(0xb7, 0x03),	/* External display signal */
-	CMD1(0xbd, 0x00),	/* ASW slew rate */
-	CMD1(0xbe, 0x00),	/* Dummy data for QuadData operation */
-	CMD1(0xc0, 0x11),	/* Sleep out FR count (A) */
-	CMD1(0xc1, 0x11),	/* Sleep out FR count (B) */
-	CMD1(0xc2, 0x11),	/* Sleep out FR count (C) */
-	CMD2(0xc3, 0x20, 0x40),	/* Sleep out FR count (D) */
-	CMD2(0xc4, 0x60, 0xc0),	/* Sleep out FR count (E) */
-	CMD2(0xc5, 0x10, 0x20),	/* Sleep out FR count (F) */
-	CMD1(0xc6, 0xc0),	/* Sleep out FR count (G) */
-	CMD2(0xc7, 0x33, 0x43),	/* Gamma 1 fine tuning (1) */
-	CMD1(0xc8, 0x44),	/* Gamma 1 fine tuning (2) */
-	CMD1(0xc9, 0x33),	/* Gamma 1 inclination adjustment */
-	CMD1(0xca, 0x00),	/* Gamma 1 blue offset adjustment */
-	CMD2(0xec, 0x01, 0xf0),	/* Horizontal clock cycles */
-};
-
-static void ssp_reconfig(struct ssp_dev *dev, int nparam)
-{
-	static int last_nparam = -1;
-
-	/* check if it is necessary to re-config SSP */
-	if (nparam == last_nparam)
-		return;
-
-	ssp_disable(dev);
-	ssp_config(dev, (nparam == 2) ? 0x0010058a : 0x00100581, 0x18, 0, 0);
-
-	last_nparam = nparam;
-}
-
-static void ssp_send_cmd(uint32_t *cmd, int num)
-{
-	static int ssp_initialized;
-	static struct ssp_dev ssp2;
-
-	int i;
-
-	if (!ssp_initialized) {
-		ssp_init(&ssp2, 2, SSP_NO_IRQ);
-		ssp_initialized = 1;
-	}
-
-	clk_enable(ssp2.ssp->clk);
-	for (i = 0; i < num; i++, cmd++) {
-		ssp_reconfig(&ssp2, (*cmd >> 30) & 0x3);
-		ssp_write_word(&ssp2, *cmd & 0x3fffffff);
-
-		/* FIXME: ssp_flush() is mandatory here to work */
-		ssp_flush(&ssp2);
-	}
-	clk_disable(ssp2.ssp->clk);
-}
-
-static void littleton_lcd_power(int on, struct fb_var_screeninfo *var)
-{
-	if (on) {
-		ssp_send_cmd(ARRAY_AND_SIZE(lcd_panel_on));
-		ssp_send_cmd(ARRAY_AND_SIZE(lcd_panel_reset));
-		if (var->xres > 240) {
-			/* VGA */
-			ssp_send_cmd(ARRAY_AND_SIZE(lcd_vga_pass_through));
-			ssp_send_cmd(ARRAY_AND_SIZE(lcd_panel_config));
-			ssp_send_cmd(ARRAY_AND_SIZE(lcd_vga_transfer));
-		} else {
-			/* QVGA */
-			ssp_send_cmd(ARRAY_AND_SIZE(lcd_qvga_pass_through));
-			ssp_send_cmd(ARRAY_AND_SIZE(lcd_panel_config));
-			ssp_send_cmd(ARRAY_AND_SIZE(lcd_qvga_transfer));
-		}
-	} else
-		ssp_send_cmd(ARRAY_AND_SIZE(lcd_panel_off));
-}
-
 static struct pxafb_mode_info tpo_tdo24mtea1_modes[] = {
 	[0] = {
 		/* VGA */
@@ -312,7 +160,6 @@
 	.modes			= tpo_tdo24mtea1_modes,
 	.num_modes		= 2,
 	.lcd_conn		= LCD_COLOR_TFT_16BPP,
-	.pxafb_lcd_power	= littleton_lcd_power,
 };
 
 static void littleton_init_lcd(void)
@@ -323,6 +170,51 @@
 static inline void littleton_init_lcd(void) {};
 #endif /* CONFIG_FB_PXA || CONFIG_FB_PXA_MODULE */
 
+#if defined(CONFIG_SPI_PXA2XX) || defined(CONFIG_SPI_PXA2XX_MODULE)
+static struct pxa2xx_spi_master littleton_spi_info = {
+	.num_chipselect		= 1,
+};
+
+static void littleton_tdo24m_cs(u32 cmd)
+{
+	gpio_set_value(LITTLETON_GPIO_LCD_CS, !(cmd == PXA2XX_CS_ASSERT));
+}
+
+static struct pxa2xx_spi_chip littleton_tdo24m_chip = {
+	.rx_threshold	= 1,
+	.tx_threshold	= 1,
+	.cs_control	= littleton_tdo24m_cs,
+};
+
+static struct spi_board_info littleton_spi_devices[] __initdata = {
+	{
+		.modalias	= "tdo24m",
+		.max_speed_hz	= 1000000,
+		.bus_num	= 2,
+		.chip_select	= 0,
+		.controller_data= &littleton_tdo24m_chip,
+	},
+};
+
+static void __init littleton_init_spi(void)
+{
+	int err;
+
+	err = gpio_request(LITTLETON_GPIO_LCD_CS, "LCD_CS");
+	if (err) {
+		pr_warning("failed to request GPIO for LCS CS\n");
+		return;
+	}
+
+	gpio_direction_output(LITTLETON_GPIO_LCD_CS, 1);
+
+	pxa2xx_set_spi_info(2, &littleton_spi_info);
+	spi_register_board_info(ARRAY_AND_SIZE(littleton_spi_devices));
+}
+#else
+static inline void littleton_init_spi(void) {}
+#endif
+
 #if defined(CONFIG_KEYBOARD_PXA27x) || defined(CONFIG_KEYBOARD_PXA27x_MODULE)
 static unsigned int littleton_matrix_key_map[] = {
 	/* KEY(row, col, key_code) */
@@ -433,6 +325,7 @@
 	 */
 	platform_device_register(&smc91x_device);
 
+	littleton_init_spi();
 	littleton_init_lcd();
 	littleton_init_keypad();
 	littleton_init_nand();
diff --git a/arch/arm/mach-pxa/lpd270.c b/arch/arm/mach-pxa/lpd270.c
index b703894..de3f67d 100644
--- a/arch/arm/mach-pxa/lpd270.c
+++ b/arch/arm/mach-pxa/lpd270.c
@@ -40,7 +40,7 @@
 
 #include <mach/pxa-regs.h>
 #include <mach/pxa2xx-regs.h>
-#include <mach/pxa2xx-gpio.h>
+#include <mach/mfp-pxa27x.h>
 #include <mach/lpd270.h>
 #include <mach/audio.h>
 #include <mach/pxafb.h>
@@ -51,6 +51,43 @@
 #include "generic.h"
 #include "devices.h"
 
+static unsigned long lpd270_pin_config[] __initdata = {
+	/* Chip Selects */
+	GPIO15_nCS_1,	/* Mainboard Flash */
+	GPIO78_nCS_2,	/* CPLD + Ethernet */
+
+	/* LCD - 16bpp Active TFT */
+	GPIO58_LCD_LDD_0,
+	GPIO59_LCD_LDD_1,
+	GPIO60_LCD_LDD_2,
+	GPIO61_LCD_LDD_3,
+	GPIO62_LCD_LDD_4,
+	GPIO63_LCD_LDD_5,
+	GPIO64_LCD_LDD_6,
+	GPIO65_LCD_LDD_7,
+	GPIO66_LCD_LDD_8,
+	GPIO67_LCD_LDD_9,
+	GPIO68_LCD_LDD_10,
+	GPIO69_LCD_LDD_11,
+	GPIO70_LCD_LDD_12,
+	GPIO71_LCD_LDD_13,
+	GPIO72_LCD_LDD_14,
+	GPIO73_LCD_LDD_15,
+	GPIO74_LCD_FCLK,
+	GPIO75_LCD_LCLK,
+	GPIO76_LCD_PCLK,
+	GPIO77_LCD_BIAS,
+	GPIO16_PWM0_OUT,	/* Backlight */
+
+	/* USB Host */
+	GPIO88_USBH1_PWR,
+	GPIO89_USBH1_PEN,
+
+	/* AC97 */
+	GPIO45_AC97_SYSCLK,
+
+	GPIO1_GPIO | WAKEUP_ON_EDGE_BOTH,
+};
 
 static unsigned int lpd270_irq_enabled;
 
@@ -88,8 +125,7 @@
 		GEDR(0) = GPIO_bit(0);  /* clear useless edge notification */
 		if (likely(pending)) {
 			irq = LPD270_IRQ(0) + __ffs(pending);
-			desc = irq_desc + irq;
-			desc_handle_irq(irq, desc);
+			generic_handle_irq(irq);
 
 			pending = __raw_readw(LPD270_INT_STATUS) &
 						lpd270_irq_enabled;
@@ -265,8 +301,8 @@
 static struct pxafb_mach_info sharp_lq057q3dc02 = {
 	.modes			= &sharp_lq057q3dc02_mode,
 	.num_modes		= 1,
-	.lccr0			= 0x07800080,
-	.lccr3			= 0x00400000,
+	.lcd_conn		= LCD_COLOR_TFT_16BPP | LCD_PCLK_EDGE_FALL |
+				  LCD_ALTERNATE_MAPPING,
 };
 
 /* 12.1" TFT SVGA (LoLo display number 2) */
@@ -287,8 +323,8 @@
 static struct pxafb_mach_info sharp_lq121s1dg31 = {
 	.modes			= &sharp_lq121s1dg31_mode,
 	.num_modes		= 1,
-	.lccr0			= 0x07800080,
-	.lccr3			= 0x00400000,
+	.lcd_conn		= LCD_COLOR_TFT_16BPP | LCD_PCLK_EDGE_FALL |
+				  LCD_ALTERNATE_MAPPING,
 };
 
 /* 3.6" TFT QVGA (LoLo display number 3) */
@@ -309,8 +345,8 @@
 static struct pxafb_mach_info sharp_lq036q1da01 = {
 	.modes			= &sharp_lq036q1da01_mode,
 	.num_modes		= 1,
-	.lccr0			= 0x07800080,
-	.lccr3			= 0x00400000,
+	.lcd_conn		= LCD_COLOR_TFT_16BPP | LCD_PCLK_EDGE_FALL |
+				  LCD_ALTERNATE_MAPPING,
 };
 
 /* 6.4" TFT VGA (LoLo display number 5) */
@@ -331,8 +367,8 @@
 static struct pxafb_mach_info sharp_lq64d343 = {
 	.modes			= &sharp_lq64d343_mode,
 	.num_modes		= 1,
-	.lccr0			= 0x07800080,
-	.lccr3			= 0x00400000,
+	.lcd_conn		= LCD_COLOR_TFT_16BPP | LCD_PCLK_EDGE_FALL |
+				  LCD_ALTERNATE_MAPPING,
 };
 
 /* 10.4" TFT VGA (LoLo display number 7) */
@@ -353,8 +389,8 @@
 static struct pxafb_mach_info sharp_lq10d368 = {
 	.modes			= &sharp_lq10d368_mode,
 	.num_modes		= 1,
-	.lccr0			= 0x07800080,
-	.lccr3			= 0x00400000,
+	.lcd_conn		= LCD_COLOR_TFT_16BPP | LCD_PCLK_EDGE_FALL |
+				  LCD_ALTERNATE_MAPPING,
 };
 
 /* 3.5" TFT QVGA (LoLo display number 8) */
@@ -375,8 +411,8 @@
 static struct pxafb_mach_info sharp_lq035q7db02_20 = {
 	.modes			= &sharp_lq035q7db02_20_mode,
 	.num_modes		= 1,
-	.lccr0			= 0x07800080,
-	.lccr3			= 0x00400000,
+	.lcd_conn		= LCD_COLOR_TFT_16BPP | LCD_PCLK_EDGE_FALL |
+				  LCD_ALTERNATE_MAPPING,
 };
 
 static struct pxafb_mach_info *lpd270_lcd_to_use;
@@ -411,27 +447,15 @@
 	&lpd270_flash_device[1],
 };
 
-static int lpd270_ohci_init(struct device *dev)
-{
-	/* setup Port1 GPIO pin. */
-	pxa_gpio_mode(88 | GPIO_ALT_FN_1_IN);	/* USBHPWR1 */
-	pxa_gpio_mode(89 | GPIO_ALT_FN_2_OUT);	/* USBHPEN1 */
-
-	/* Set the Power Control Polarity Low and Power Sense
-	   Polarity Low to active low. */
-	UHCHR = (UHCHR | UHCHR_PCPL | UHCHR_PSPL) &
-		~(UHCHR_SSEP1 | UHCHR_SSEP2 | UHCHR_SSEP3 | UHCHR_SSE);
-
-	return 0;
-}
-
 static struct pxaohci_platform_data lpd270_ohci_platform_data = {
 	.port_mode	= PMM_PERPORT_MODE,
-	.init		= lpd270_ohci_init,
+	.flags		= ENABLE_PORT_ALL | POWER_CONTROL_LOW | POWER_SENSE_LOW,
 };
 
 static void __init lpd270_init(void)
 {
+	pxa2xx_mfp_config(ARRAY_AND_SIZE(lpd270_pin_config));
+
 	lpd270_flash_data[0].width = (BOOT_DEF & 1) ? 2 : 4;
 	lpd270_flash_data[1].width = 4;
 
@@ -442,12 +466,6 @@
 	 */
 	ARB_CNTRL = ARB_CORE_PARK | 0x234;
 
-	/*
-	 * On LogicPD PXA270, we route AC97_SYSCLK via GPIO45.
-	 */
-	pxa_gpio_mode(GPIO45_SYSCLK_AC97_MD);
-	pxa_gpio_mode(GPIO16_PWM0_MD);
-
 	platform_add_devices(platform_devices, ARRAY_SIZE(platform_devices));
 
 	pxa_set_ac97_info(NULL);
@@ -473,15 +491,6 @@
 	pxa_map_io();
 	iotable_init(lpd270_io_desc, ARRAY_SIZE(lpd270_io_desc));
 
-	/* initialize sleep mode regs (wake-up sources, etc) */
-	PGSR0 = 0x00008800;
-	PGSR1 = 0x00000002;
-	PGSR2 = 0x0001FC00;
-	PGSR3 = 0x00001F81;
-	PWER  = 0xC0000002;
-	PRER  = 0x00000002;
-	PFER  = 0x00000002;
-
 	/* for use I SRAM as framebuffer.  */
 	PSLR |= 0x00000F04;
 	PCFR  = 0x00000066;
diff --git a/arch/arm/mach-pxa/lubbock.c b/arch/arm/mach-pxa/lubbock.c
index 4ffdff2..bff7043 100644
--- a/arch/arm/mach-pxa/lubbock.c
+++ b/arch/arm/mach-pxa/lubbock.c
@@ -57,13 +57,36 @@
 
 static unsigned long lubbock_pin_config[] __initdata = {
 	GPIO15_nCS_1,	/* CS1 - Flash */
+	GPIO78_nCS_2,	/* CS2 - Baseboard FGPA */
 	GPIO79_nCS_3,	/* CS3 - SMC ethernet */
+	GPIO80_nCS_4,	/* CS4 - SA1111 */
 
 	/* SSP data pins */
 	GPIO23_SSP1_SCLK,
 	GPIO25_SSP1_TXD,
 	GPIO26_SSP1_RXD,
 
+	/* LCD - 16bpp DSTN */
+	GPIO58_LCD_LDD_0,
+	GPIO59_LCD_LDD_1,
+	GPIO60_LCD_LDD_2,
+	GPIO61_LCD_LDD_3,
+	GPIO62_LCD_LDD_4,
+	GPIO63_LCD_LDD_5,
+	GPIO64_LCD_LDD_6,
+	GPIO65_LCD_LDD_7,
+	GPIO66_LCD_LDD_8,
+	GPIO67_LCD_LDD_9,
+	GPIO68_LCD_LDD_10,
+	GPIO69_LCD_LDD_11,
+	GPIO70_LCD_LDD_12,
+	GPIO71_LCD_LDD_13,
+	GPIO72_LCD_LDD_14,
+	GPIO73_LCD_LDD_15,
+	GPIO74_LCD_FCLK,
+	GPIO75_LCD_LCLK,
+	GPIO76_LCD_PCLK,
+
 	/* BTUART */
 	GPIO42_BTUART_RXD,
 	GPIO43_BTUART_TXD,
@@ -132,8 +155,7 @@
 		GEDR(0) = GPIO_bit(0);	/* clear our parent irq */
 		if (likely(pending)) {
 			irq = LUBBOCK_IRQ(0) + __ffs(pending);
-			desc = irq_desc + irq;
-			desc_handle_irq(irq, desc);
+			generic_handle_irq(irq);
 		}
 		pending = LUB_IRQ_SET_CLR & lubbock_irq_enabled;
 	} while (pending);
diff --git a/arch/arm/mach-pxa/magician.c b/arch/arm/mach-pxa/magician.c
index 143f28a..519138b 100644
--- a/arch/arm/mach-pxa/magician.c
+++ b/arch/arm/mach-pxa/magician.c
@@ -409,7 +409,7 @@
  * LEDs
  */
 
-struct gpio_led gpio_leds[] = {
+static struct gpio_led gpio_leds[] = {
 	{
 		.name = "magician::vibra",
 		.default_trigger = "none",
@@ -669,18 +669,10 @@
  * USB OHCI
  */
 
-static int magician_ohci_init(struct device *dev)
-{
-	UHCHR = (UHCHR | UHCHR_SSEP2 | UHCHR_PCPL | UHCHR_CGR) &
-	    ~(UHCHR_SSEP1 | UHCHR_SSEP3 | UHCHR_SSE);
-
-	return 0;
-}
-
 static struct pxaohci_platform_data magician_ohci_info = {
-	.port_mode    = PMM_PERPORT_MODE,
-	.init         = magician_ohci_init,
-	.power_budget = 0,
+	.port_mode	= PMM_PERPORT_MODE,
+	.flags		= ENABLE_PORT1 | ENABLE_PORT3 | POWER_CONTROL_LOW,
+	.power_budget	= 0,
 };
 
 
diff --git a/arch/arm/mach-pxa/mainstone.c b/arch/arm/mach-pxa/mainstone.c
index d44af76..f2c7ad8 100644
--- a/arch/arm/mach-pxa/mainstone.c
+++ b/arch/arm/mach-pxa/mainstone.c
@@ -162,8 +162,7 @@
 		GEDR(0) = GPIO_bit(0);  /* clear useless edge notification */
 		if (likely(pending)) {
 			irq = MAINSTONE_IRQ(0) + __ffs(pending);
-			desc = irq_desc + irq;
-			desc_handle_irq(irq, desc);
+			generic_handle_irq(irq);
 		}
 		pending = MST_INTSETCLR & mainstone_irq_enabled;
 	} while (pending);
@@ -508,19 +507,9 @@
 	&mst_gpio_keys_device,
 };
 
-static int mainstone_ohci_init(struct device *dev)
-{
-	/* Set the Power Control Polarity Low and Power Sense
-	   Polarity Low to active low. */
-	UHCHR = (UHCHR | UHCHR_PCPL | UHCHR_PSPL) &
-		~(UHCHR_SSEP1 | UHCHR_SSEP2 | UHCHR_SSEP3 | UHCHR_SSE);
-
-	return 0;
-}
-
 static struct pxaohci_platform_data mainstone_ohci_platform_data = {
 	.port_mode	= PMM_PERPORT_MODE,
-	.init		= mainstone_ohci_init,
+	.flags		= ENABLE_PORT_ALL | POWER_CONTROL_LOW | POWER_SENSE_LOW,
 };
 
 #if defined(CONFIG_KEYBOARD_PXA27x) || defined(CONFIG_KEYBOARD_PXA27x_MODULE)
diff --git a/arch/arm/mach-pxa/mfp-pxa2xx.c b/arch/arm/mach-pxa/mfp-pxa2xx.c
index 925575f..2061c00 100644
--- a/arch/arm/mach-pxa/mfp-pxa2xx.c
+++ b/arch/arm/mach-pxa/mfp-pxa2xx.c
@@ -25,7 +25,12 @@
 
 #include "generic.h"
 
-#define PGSR(x)		__REG2(0x40F00020, ((x) & 0x60) >> 3)
+#define gpio_to_bank(gpio)	((gpio) >> 5)
+
+#define PGSR(x)		__REG2(0x40F00020, (x) << 2)
+#define __GAFR(u, x)	__REG2((u) ? 0x40E00058 : 0x40E00054, (x) << 3)
+#define GAFR_L(x)	__GAFR(0, x)
+#define GAFR_U(x)	__GAFR(1, x)
 
 #define PWER_WE35	(1 << 24)
 
@@ -38,49 +43,59 @@
 };
 
 static struct gpio_desc gpio_desc[MFP_PIN_GPIO127 + 1];
+static int gpio_nr;
 
-static int __mfp_config_lpm(unsigned gpio, unsigned long lpm)
-{
-	unsigned mask = GPIO_bit(gpio);
-
-	/* low power state */
-	switch (lpm) {
-	case MFP_LPM_DRIVE_HIGH:
-		PGSR(gpio) |= mask;
-		break;
-	case MFP_LPM_DRIVE_LOW:
-		PGSR(gpio) &= ~mask;
-		break;
-	case MFP_LPM_INPUT:
-		break;
-	default:
-		pr_warning("%s: invalid low power state for GPIO%d\n",
-				__func__, gpio);
-		return -EINVAL;
-	}
-	return 0;
-}
+static unsigned long gpdr_lpm[4];
 
 static int __mfp_config_gpio(unsigned gpio, unsigned long c)
 {
 	unsigned long gafr, mask = GPIO_bit(gpio);
-	int fn;
+	int bank = gpio_to_bank(gpio);
+	int uorl = !!(gpio & 0x10); /* GAFRx_U or GAFRx_L ? */
+	int shft = (gpio & 0xf) << 1;
+	int fn = MFP_AF(c);
+	int dir = c & MFP_DIR_OUT;
 
-	fn = MFP_AF(c);
 	if (fn > 3)
 		return -EINVAL;
 
-	/* alternate function and direction */
-	gafr = GAFR(gpio) & ~(0x3 << ((gpio & 0xf) * 2));
-	GAFR(gpio) = gafr |  (fn  << ((gpio & 0xf) * 2));
+	/* alternate function and direction at run-time */
+	gafr = (uorl == 0) ? GAFR_L(bank) : GAFR_U(bank);
+	gafr = (gafr & ~(0x3 << shft)) | (fn << shft);
 
-	if (c & MFP_DIR_OUT)
+	if (uorl == 0)
+		GAFR_L(bank) = gafr;
+	else
+		GAFR_U(bank) = gafr;
+
+	if (dir == MFP_DIR_OUT)
 		GPDR(gpio) |= mask;
 	else
 		GPDR(gpio) &= ~mask;
 
-	if (__mfp_config_lpm(gpio, c & MFP_LPM_STATE_MASK))
-		return -EINVAL;
+	/* alternate function and direction at low power mode */
+	switch (c & MFP_LPM_STATE_MASK) {
+	case MFP_LPM_DRIVE_HIGH:
+		PGSR(bank) |= mask;
+		dir = MFP_DIR_OUT;
+		break;
+	case MFP_LPM_DRIVE_LOW:
+		PGSR(bank) &= ~mask;
+		dir = MFP_DIR_OUT;
+		break;
+	case MFP_LPM_DEFAULT:
+		break;
+	default:
+		/* warning and fall through, treat as MFP_LPM_DEFAULT */
+		pr_warning("%s: GPIO%d: unsupported low power mode\n",
+				__func__, gpio);
+		break;
+	}
+
+	if (dir == MFP_DIR_OUT)
+		gpdr_lpm[bank] |= mask;
+	else
+		gpdr_lpm[bank] &= ~mask;
 
 	/* give early warning if MFP_LPM_CAN_WAKEUP is set on the
 	 * configurations of those pins not able to wakeup
@@ -91,7 +106,7 @@
 		return -EINVAL;
 	}
 
-	if ((c & MFP_LPM_CAN_WAKEUP) && (c & MFP_DIR_OUT)) {
+	if ((c & MFP_LPM_CAN_WAKEUP) && (dir == MFP_DIR_OUT)) {
 		pr_warning("%s: output GPIO%d unable to wakeup\n",
 				__func__, gpio);
 		return -EINVAL;
@@ -135,7 +150,7 @@
 
 void pxa2xx_mfp_set_lpm(int mfp, unsigned long lpm)
 {
-	unsigned long flags;
+	unsigned long flags, c;
 	int gpio;
 
 	gpio = __mfp_validate(mfp);
@@ -143,7 +158,11 @@
 		return;
 
 	local_irq_save(flags);
-	__mfp_config_lpm(gpio, lpm);
+
+	c = gpio_desc[gpio].config;
+	c = (c & ~MFP_LPM_STATE_MASK) | lpm;
+	__mfp_config_gpio(gpio, c);
+
 	local_irq_restore(flags);
 }
 
@@ -187,23 +206,22 @@
 }
 
 #ifdef CONFIG_PXA25x
-static int __init pxa25x_mfp_init(void)
+static void __init pxa25x_mfp_init(void)
 {
 	int i;
 
-	if (cpu_is_pxa25x()) {
-		for (i = 0; i <= 84; i++)
-			gpio_desc[i].valid = 1;
+	for (i = 0; i <= 84; i++)
+		gpio_desc[i].valid = 1;
 
-		for (i = 0; i <= 15; i++) {
-			gpio_desc[i].can_wakeup = 1;
-			gpio_desc[i].mask = GPIO_bit(i);
-		}
+	for (i = 0; i <= 15; i++) {
+		gpio_desc[i].can_wakeup = 1;
+		gpio_desc[i].mask = GPIO_bit(i);
 	}
 
-	return 0;
+	gpio_nr = 85;
 }
-postcore_initcall(pxa25x_mfp_init);
+#else
+static inline void pxa25x_mfp_init(void) {}
 #endif /* CONFIG_PXA25x */
 
 #ifdef CONFIG_PXA27x
@@ -233,45 +251,106 @@
 	return 0;
 }
 
-static int __init pxa27x_mfp_init(void)
+static void __init pxa27x_mfp_init(void)
 {
 	int i, gpio;
 
-	if (cpu_is_pxa27x()) {
-		for (i = 0; i <= 120; i++) {
-			/* skip GPIO2, 5, 6, 7, 8, they are not
-			 * valid pins allow configuration
-			 */
-			if (i == 2 || i == 5 || i == 6 ||
-			    i == 7 || i == 8)
-				continue;
+	for (i = 0; i <= 120; i++) {
+		/* skip GPIO2, 5, 6, 7, 8, they are not
+		 * valid pins allow configuration
+		 */
+		if (i == 2 || i == 5 || i == 6 || i == 7 || i == 8)
+			continue;
 
-			gpio_desc[i].valid = 1;
-		}
-
-		/* Keypad GPIOs */
-		for (i = 0; i < ARRAY_SIZE(pxa27x_pkwr_gpio); i++) {
-			gpio = pxa27x_pkwr_gpio[i];
-			gpio_desc[gpio].can_wakeup = 1;
-			gpio_desc[gpio].keypad_gpio = 1;
-			gpio_desc[gpio].mask = 1 << i;
-		}
-
-		/* Overwrite GPIO13 as a PWER wakeup source */
-		for (i = 0; i <= 15; i++) {
-			/* skip GPIO2, 5, 6, 7, 8 */
-			if (GPIO_bit(i) & 0x1e4)
-				continue;
-
-			gpio_desc[i].can_wakeup = 1;
-			gpio_desc[i].mask = GPIO_bit(i);
-		}
-
-		gpio_desc[35].can_wakeup = 1;
-		gpio_desc[35].mask = PWER_WE35;
+		gpio_desc[i].valid = 1;
 	}
 
+	/* Keypad GPIOs */
+	for (i = 0; i < ARRAY_SIZE(pxa27x_pkwr_gpio); i++) {
+		gpio = pxa27x_pkwr_gpio[i];
+		gpio_desc[gpio].can_wakeup = 1;
+		gpio_desc[gpio].keypad_gpio = 1;
+		gpio_desc[gpio].mask = 1 << i;
+	}
+
+	/* Overwrite GPIO13 as a PWER wakeup source */
+	for (i = 0; i <= 15; i++) {
+		/* skip GPIO2, 5, 6, 7, 8 */
+		if (GPIO_bit(i) & 0x1e4)
+			continue;
+
+		gpio_desc[i].can_wakeup = 1;
+		gpio_desc[i].mask = GPIO_bit(i);
+	}
+
+	gpio_desc[35].can_wakeup = 1;
+	gpio_desc[35].mask = PWER_WE35;
+
+	gpio_nr = 121;
+}
+#else
+static inline void pxa27x_mfp_init(void) {}
+#endif /* CONFIG_PXA27x */
+
+#ifdef CONFIG_PM
+static unsigned long saved_gafr[2][4];
+static unsigned long saved_gpdr[4];
+
+static int pxa2xx_mfp_suspend(struct sys_device *d, pm_message_t state)
+{
+	int i;
+
+	for (i = 0; i <= gpio_to_bank(gpio_nr); i++) {
+
+		saved_gafr[0][i] = GAFR_L(i);
+		saved_gafr[1][i] = GAFR_U(i);
+		saved_gpdr[i] = GPDR(i * 32);
+
+		GPDR(i * 32) = gpdr_lpm[i];
+	}
 	return 0;
 }
-postcore_initcall(pxa27x_mfp_init);
-#endif /* CONFIG_PXA27x */
+
+static int pxa2xx_mfp_resume(struct sys_device *d)
+{
+	int i;
+
+	for (i = 0; i <= gpio_to_bank(gpio_nr); i++) {
+		GAFR_L(i) = saved_gafr[0][i];
+		GAFR_U(i) = saved_gafr[1][i];
+		GPDR(i * 32) = saved_gpdr[i];
+	}
+	PSSR = PSSR_RDH | PSSR_PH;
+	return 0;
+}
+#else
+#define pxa2xx_mfp_suspend	NULL
+#define pxa2xx_mfp_resume	NULL
+#endif
+
+struct sysdev_class pxa2xx_mfp_sysclass = {
+	.name		= "mfp",
+	.suspend	= pxa2xx_mfp_suspend,
+	.resume		= pxa2xx_mfp_resume,
+};
+
+static int __init pxa2xx_mfp_init(void)
+{
+	int i;
+
+	if (!cpu_is_pxa2xx())
+		return 0;
+
+	if (cpu_is_pxa25x())
+		pxa25x_mfp_init();
+
+	if (cpu_is_pxa27x())
+		pxa27x_mfp_init();
+
+	/* initialize gafr_run[], pgsr_lpm[] from existing values */
+	for (i = 0; i <= gpio_to_bank(gpio_nr); i++)
+		gpdr_lpm[i] = GPDR(i * 32);
+
+	return sysdev_class_register(&pxa2xx_mfp_sysclass);
+}
+postcore_initcall(pxa2xx_mfp_init);
diff --git a/arch/arm/mach-pxa/mioa701.c b/arch/arm/mach-pxa/mioa701.c
new file mode 100644
index 0000000..0842c53
--- /dev/null
+++ b/arch/arm/mach-pxa/mioa701.c
@@ -0,0 +1,905 @@
+/*
+ * Handles the Mitac Mio A701 Board
+ *
+ * Copyright (C) 2008 Robert Jarzmik
+ *
+ * This program is free software; you can redistribute it and/or 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/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/sysdev.h>
+#include <linux/input.h>
+#include <linux/delay.h>
+#include <linux/gpio_keys.h>
+#include <linux/pwm_backlight.h>
+#include <linux/rtc.h>
+#include <linux/leds.h>
+#include <linux/gpio.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/pda_power.h>
+#include <linux/power_supply.h>
+#include <linux/wm97xx.h>
+#include <linux/mtd/physmap.h>
+
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <mach/mfp-pxa27x.h>
+#include <mach/pxa27x_keypad.h>
+#include <mach/pxafb.h>
+#include <mach/pxa2xx-regs.h>
+#include <mach/mmc.h>
+#include <mach/udc.h>
+#include <mach/pxa27x-udc.h>
+
+#include <mach/mioa701.h>
+
+#include "generic.h"
+#include "devices.h"
+
+static unsigned long mioa701_pin_config[] = {
+	/* Mio global */
+	MIO_CFG_OUT(GPIO9_CHARGE_nEN, AF0, DRIVE_LOW),
+	MIO_CFG_OUT(GPIO18_POWEROFF, AF0, DRIVE_LOW),
+	MFP_CFG_OUT(GPIO3, AF0, DRIVE_HIGH),
+	MFP_CFG_OUT(GPIO4, AF0, DRIVE_HIGH),
+
+	/* Backlight PWM 0 */
+	GPIO16_PWM0_OUT,
+
+	/* MMC */
+	GPIO32_MMC_CLK,
+	GPIO92_MMC_DAT_0,
+	GPIO109_MMC_DAT_1,
+	GPIO110_MMC_DAT_2,
+	GPIO111_MMC_DAT_3,
+	GPIO112_MMC_CMD,
+	MIO_CFG_IN(GPIO78_SDIO_RO, AF0),
+	MIO_CFG_IN(GPIO15_SDIO_INSERT, AF0),
+	MIO_CFG_OUT(GPIO91_SDIO_EN, AF0, DRIVE_LOW),
+
+	/* USB */
+	MIO_CFG_IN(GPIO13_USB_DETECT, AF0),
+	MIO_CFG_OUT(GPIO22_USB_ENABLE, AF0, DRIVE_LOW),
+
+	/* LCD */
+	GPIO58_LCD_LDD_0,
+	GPIO59_LCD_LDD_1,
+	GPIO60_LCD_LDD_2,
+	GPIO61_LCD_LDD_3,
+	GPIO62_LCD_LDD_4,
+	GPIO63_LCD_LDD_5,
+	GPIO64_LCD_LDD_6,
+	GPIO65_LCD_LDD_7,
+	GPIO66_LCD_LDD_8,
+	GPIO67_LCD_LDD_9,
+	GPIO68_LCD_LDD_10,
+	GPIO69_LCD_LDD_11,
+	GPIO70_LCD_LDD_12,
+	GPIO71_LCD_LDD_13,
+	GPIO72_LCD_LDD_14,
+	GPIO73_LCD_LDD_15,
+	GPIO74_LCD_FCLK,
+	GPIO75_LCD_LCLK,
+	GPIO76_LCD_PCLK,
+
+	/* Bluetooth */
+	GPIO44_BTUART_CTS,
+	GPIO42_BTUART_RXD,
+	GPIO45_BTUART_RTS,
+	GPIO43_BTUART_TXD,
+	MIO_CFG_OUT(GPIO83_BT_ON, AF0, DRIVE_LOW),
+
+	/* GPS */
+	MIO_CFG_OUT(GPIO23_GPS_UNKNOWN1, AF0, DRIVE_LOW),
+	MIO_CFG_OUT(GPIO26_GPS_ON, AF0, DRIVE_LOW),
+	MIO_CFG_OUT(GPIO27_GPS_RESET, AF0, DRIVE_LOW),
+	MIO_CFG_OUT(GPIO106_GPS_UNKNOWN2, AF0, DRIVE_LOW),
+	MIO_CFG_OUT(GPIO107_GPS_UNKNOWN3, AF0, DRIVE_LOW),
+	GPIO46_STUART_RXD,
+	GPIO47_STUART_TXD,
+
+	/* GSM */
+	MIO_CFG_OUT(GPIO24_GSM_MOD_RESET_CMD, AF0, DRIVE_LOW),
+	MIO_CFG_OUT(GPIO88_GSM_nMOD_ON_CMD, AF0, DRIVE_HIGH),
+	MIO_CFG_OUT(GPIO90_GSM_nMOD_OFF_CMD, AF0, DRIVE_HIGH),
+	MIO_CFG_OUT(GPIO114_GSM_nMOD_DTE_UART_STATE, AF0, DRIVE_HIGH),
+	MIO_CFG_IN(GPIO25_GSM_MOD_ON_STATE, AF0),
+	MIO_CFG_IN(GPIO113_GSM_EVENT, AF0) | WAKEUP_ON_EDGE_BOTH,
+	GPIO34_FFUART_RXD,
+	GPIO35_FFUART_CTS,
+	GPIO36_FFUART_DCD,
+	GPIO37_FFUART_DSR,
+	GPIO39_FFUART_TXD,
+	GPIO40_FFUART_DTR,
+	GPIO41_FFUART_RTS,
+
+	/* Sound */
+	GPIO89_AC97_SYSCLK,
+	MIO_CFG_IN(GPIO12_HPJACK_INSERT, AF0),
+
+	/* Leds */
+	MIO_CFG_OUT(GPIO10_LED_nCharging, AF0, DRIVE_HIGH),
+	MIO_CFG_OUT(GPIO97_LED_nBlue, AF0, DRIVE_HIGH),
+	MIO_CFG_OUT(GPIO98_LED_nOrange, AF0, DRIVE_HIGH),
+	MIO_CFG_OUT(GPIO82_LED_nVibra, AF0, DRIVE_HIGH),
+	MIO_CFG_OUT(GPIO115_LED_nKeyboard, AF0, DRIVE_HIGH),
+
+	/* Keyboard */
+	MIO_CFG_IN(GPIO0_KEY_POWER, AF0) | WAKEUP_ON_EDGE_BOTH,
+	MIO_CFG_IN(GPIO93_KEY_VOLUME_UP, AF0),
+	MIO_CFG_IN(GPIO94_KEY_VOLUME_DOWN, AF0),
+	GPIO100_KP_MKIN_0,
+	GPIO101_KP_MKIN_1,
+	GPIO102_KP_MKIN_2,
+	GPIO103_KP_MKOUT_0,
+	GPIO104_KP_MKOUT_1,
+	GPIO105_KP_MKOUT_2,
+
+	/* Unknown */
+	MFP_CFG_IN(GPIO14, AF0),
+	MFP_CFG_IN(GPIO20, AF0),
+	MFP_CFG_IN(GPIO21, AF0),
+	MFP_CFG_IN(GPIO33, AF0),
+	MFP_CFG_OUT(GPIO49, AF0, DRIVE_HIGH),
+	MFP_CFG_OUT(GPIO57, AF0, DRIVE_HIGH),
+	MFP_CFG_OUT(GPIO77, AF0, DRIVE_HIGH),
+	MFP_CFG_IN(GPIO80, AF0),
+	MFP_CFG_OUT(GPIO86, AF0, DRIVE_HIGH),
+	MFP_CFG_IN(GPIO96, AF0),
+	MFP_CFG_OUT(GPIO116, AF0, DRIVE_HIGH),
+};
+
+#define MIO_GPIO_IN(num, _desc) \
+	{ .gpio = (num), .dir = 0, .desc = (_desc) }
+#define MIO_GPIO_OUT(num, _init, _desc) \
+	{ .gpio = (num), .dir = 1, .init = (_init), .desc = (_desc) }
+struct gpio_ress {
+	unsigned gpio : 8;
+	unsigned dir : 1;
+	unsigned init : 1;
+	char *desc;
+};
+
+static int mio_gpio_request(struct gpio_ress *gpios, int size)
+{
+	int i, rc = 0;
+	int gpio;
+	int dir;
+
+	for (i = 0; (!rc) && (i < size); i++) {
+		gpio = gpios[i].gpio;
+		dir = gpios[i].dir;
+		rc = gpio_request(gpio, gpios[i].desc);
+		if (rc) {
+			printk(KERN_ERR "Error requesting GPIO %d(%s) : %d\n",
+			       gpio, gpios[i].desc, rc);
+			continue;
+		}
+		if (dir)
+			gpio_direction_output(gpio, gpios[i].init);
+		else
+			gpio_direction_input(gpio);
+	}
+	while ((rc) && (--i >= 0))
+		gpio_free(gpios[i].gpio);
+	return rc;
+}
+
+static void mio_gpio_free(struct gpio_ress *gpios, int size)
+{
+	int i;
+
+	for (i = 0; i < size; i++)
+		gpio_free(gpios[i].gpio);
+}
+
+/* LCD Screen and Backlight */
+static struct platform_pwm_backlight_data mioa701_backlight_data = {
+	.pwm_id		= 0,
+	.max_brightness	= 100,
+	.dft_brightness	= 50,
+	.pwm_period_ns	= 4000 * 1024,	/* Fl = 250kHz */
+};
+
+/*
+ * LTM0305A776C LCD panel timings
+ *
+ * see:
+ *  - the LTM0305A776C datasheet,
+ *  - and the PXA27x Programmers' manual
+ */
+static struct pxafb_mode_info mioa701_ltm0305a776c = {
+	.pixclock		= 220000,	/* CLK=4.545 MHz */
+	.xres			= 240,
+	.yres			= 320,
+	.bpp			= 16,
+	.hsync_len		= 4,
+	.vsync_len		= 2,
+	.left_margin		= 6,
+	.right_margin		= 4,
+	.upper_margin		= 5,
+	.lower_margin		= 3,
+};
+
+static void mioa701_lcd_power(int on, struct fb_var_screeninfo *si)
+{
+	gpio_set_value(GPIO87_LCD_POWER, on);
+}
+
+static struct pxafb_mach_info mioa701_pxafb_info = {
+	.modes			= &mioa701_ltm0305a776c,
+	.num_modes		= 1,
+	.lcd_conn		= LCD_COLOR_TFT_16BPP | LCD_PCLK_EDGE_FALL,
+	.pxafb_lcd_power	= mioa701_lcd_power,
+};
+
+/*
+ * Keyboard configuration
+ */
+static unsigned int mioa701_matrix_keys[] = {
+	KEY(0, 0, KEY_UP),
+	KEY(0, 1, KEY_RIGHT),
+	KEY(0, 2, KEY_MEDIA),
+	KEY(1, 0, KEY_DOWN),
+	KEY(1, 1, KEY_ENTER),
+	KEY(1, 2, KEY_CONNECT),	/* GPS key */
+	KEY(2, 0, KEY_LEFT),
+	KEY(2, 1, KEY_PHONE),	/* Phone Green key */
+	KEY(2, 2, KEY_CAMERA)	/* Camera key */
+};
+static struct pxa27x_keypad_platform_data mioa701_keypad_info = {
+	.matrix_key_rows = 3,
+	.matrix_key_cols = 3,
+	.matrix_key_map = mioa701_matrix_keys,
+	.matrix_key_map_size = ARRAY_SIZE(mioa701_matrix_keys),
+};
+
+/*
+ * GPIO Key Configuration
+ */
+#define MIO_KEY(key, _gpio, _desc, _wakeup) \
+	{ .code = (key), .gpio = (_gpio), .active_low = 0, \
+	.desc = (_desc), .type = EV_KEY, .wakeup = (_wakeup) }
+static struct gpio_keys_button mioa701_button_table[] = {
+	MIO_KEY(KEY_EXIT, GPIO0_KEY_POWER, "Power button", 1),
+	MIO_KEY(KEY_VOLUMEUP, GPIO93_KEY_VOLUME_UP, "Volume up", 0),
+	MIO_KEY(KEY_VOLUMEDOWN, GPIO94_KEY_VOLUME_DOWN, "Volume down", 0),
+	MIO_KEY(KEY_HP, GPIO12_HPJACK_INSERT, "HP jack detect", 0)
+};
+
+static struct gpio_keys_platform_data mioa701_gpio_keys_data = {
+	.buttons  = mioa701_button_table,
+	.nbuttons = ARRAY_SIZE(mioa701_button_table),
+};
+
+/*
+ * Leds and vibrator
+ */
+#define ONE_LED(_gpio, _name) \
+{ .gpio = (_gpio), .name = (_name), .active_low = true }
+static struct gpio_led gpio_leds[] = {
+	ONE_LED(GPIO10_LED_nCharging, "mioa701:charging"),
+	ONE_LED(GPIO97_LED_nBlue, "mioa701:blue"),
+	ONE_LED(GPIO98_LED_nOrange, "mioa701:orange"),
+	ONE_LED(GPIO82_LED_nVibra, "mioa701:vibra"),
+	ONE_LED(GPIO115_LED_nKeyboard, "mioa701:keyboard")
+};
+
+static struct gpio_led_platform_data gpio_led_info = {
+	.leds = gpio_leds,
+	.num_leds = ARRAY_SIZE(gpio_leds),
+};
+
+/*
+ * GSM Sagem XS200 chip
+ *
+ * GSM handling was purged from kernel. For history, this is the way to go :
+ *   - init : GPIO24_GSM_MOD_RESET_CMD = 0, GPIO114_GSM_nMOD_DTE_UART_STATE = 1
+ *            GPIO88_GSM_nMOD_ON_CMD = 1, GPIO90_GSM_nMOD_OFF_CMD = 1
+ *   - reset : GPIO24_GSM_MOD_RESET_CMD = 1, msleep(100),
+ *             GPIO24_GSM_MOD_RESET_CMD = 0
+ *   - turn on  : GPIO88_GSM_nMOD_ON_CMD = 0, msleep(1000),
+ *                GPIO88_GSM_nMOD_ON_CMD = 1
+ *   - turn off : GPIO90_GSM_nMOD_OFF_CMD = 0, msleep(1000),
+ *                GPIO90_GSM_nMOD_OFF_CMD = 1
+ */
+static int is_gsm_on(void)
+{
+	int is_on;
+
+	is_on = !!gpio_get_value(GPIO25_GSM_MOD_ON_STATE);
+	return is_on;
+}
+
+irqreturn_t gsm_on_irq(int irq, void *p)
+{
+	printk(KERN_DEBUG "Mioa701: GSM status changed to %s\n",
+	       is_gsm_on() ? "on" : "off");
+	return IRQ_HANDLED;
+}
+
+struct gpio_ress gsm_gpios[] = {
+	MIO_GPIO_IN(GPIO25_GSM_MOD_ON_STATE, "GSM state"),
+	MIO_GPIO_IN(GPIO113_GSM_EVENT, "GSM event"),
+};
+
+static int __init gsm_init(void)
+{
+	int rc;
+
+	rc = mio_gpio_request(ARRAY_AND_SIZE(gsm_gpios));
+	if (rc)
+		goto err_gpio;
+	rc = request_irq(gpio_to_irq(GPIO25_GSM_MOD_ON_STATE), gsm_on_irq,
+			 IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+			 "GSM XS200 Power Irq", NULL);
+	if (rc)
+		goto err_irq;
+
+	gpio_set_wake(GPIO113_GSM_EVENT, 1);
+	return 0;
+
+err_irq:
+	printk(KERN_ERR "Mioa701: Can't request GSM_ON irq\n");
+	mio_gpio_free(ARRAY_AND_SIZE(gsm_gpios));
+err_gpio:
+	printk(KERN_ERR "Mioa701: gsm not available\n");
+	return rc;
+}
+
+static void gsm_exit(void)
+{
+	free_irq(gpio_to_irq(GPIO25_GSM_MOD_ON_STATE), NULL);
+	mio_gpio_free(ARRAY_AND_SIZE(gsm_gpios));
+}
+
+/*
+ * Bluetooth BRF6150 chip
+ *
+ * BT handling was purged from kernel. For history, this is the way to go :
+ * - turn on  : GPIO83_BT_ON = 1
+ * - turn off : GPIO83_BT_ON = 0
+ */
+
+/*
+ * GPS Sirf Star III chip
+ *
+ * GPS handling was purged from kernel. For history, this is the way to go :
+ * - init : GPIO23_GPS_UNKNOWN1 = 1, GPIO26_GPS_ON = 0, GPIO27_GPS_RESET = 0
+ *          GPIO106_GPS_UNKNOWN2 = 0, GPIO107_GPS_UNKNOWN3 = 0
+ * - turn on  : GPIO27_GPS_RESET = 1, GPIO26_GPS_ON = 1
+ * - turn off : GPIO26_GPS_ON = 0, GPIO27_GPS_RESET = 0
+ */
+
+/*
+ * USB UDC
+ */
+static void udc_power_command(int cmd)
+{
+	switch (cmd) {
+	case PXA2XX_UDC_CMD_DISCONNECT:
+		gpio_set_value(GPIO22_USB_ENABLE, 0);
+		break;
+	case PXA2XX_UDC_CMD_CONNECT:
+		gpio_set_value(GPIO22_USB_ENABLE, 1);
+		break;
+	default:
+		printk(KERN_INFO "udc_control: unknown command (0x%x)!\n", cmd);
+		break;
+	}
+}
+
+static int is_usb_connected(void)
+{
+	return !!gpio_get_value(GPIO13_USB_DETECT);
+}
+
+static struct pxa2xx_udc_mach_info mioa701_udc_info = {
+	.udc_is_connected = is_usb_connected,
+	.udc_command	  = udc_power_command,
+};
+
+struct gpio_ress udc_gpios[] = {
+	MIO_GPIO_OUT(GPIO22_USB_ENABLE, 0, "USB Vbus enable")
+};
+
+static int __init udc_init(void)
+{
+	pxa_set_udc_info(&mioa701_udc_info);
+	return mio_gpio_request(ARRAY_AND_SIZE(udc_gpios));
+}
+
+static void udc_exit(void)
+{
+	mio_gpio_free(ARRAY_AND_SIZE(udc_gpios));
+}
+
+/*
+ * SDIO/MMC Card controller
+ */
+static void mci_setpower(struct device *dev, unsigned int vdd)
+{
+	struct pxamci_platform_data *p_d = dev->platform_data;
+
+	if ((1 << vdd) & p_d->ocr_mask)
+		gpio_set_value(GPIO91_SDIO_EN, 1);	/* enable SDIO power */
+	else
+		gpio_set_value(GPIO91_SDIO_EN, 0);	/* disable SDIO power */
+}
+
+static int mci_get_ro(struct device *dev)
+{
+	return gpio_get_value(GPIO78_SDIO_RO);
+}
+
+struct gpio_ress mci_gpios[] = {
+	MIO_GPIO_IN(GPIO78_SDIO_RO, 	"SDIO readonly detect"),
+	MIO_GPIO_IN(GPIO15_SDIO_INSERT,	"SDIO insertion detect"),
+	MIO_GPIO_OUT(GPIO91_SDIO_EN, 0,	"SDIO power enable")
+};
+
+static void mci_exit(struct device *dev, void *data)
+{
+	mio_gpio_free(ARRAY_AND_SIZE(mci_gpios));
+	free_irq(gpio_to_irq(GPIO15_SDIO_INSERT), data);
+}
+
+static struct pxamci_platform_data mioa701_mci_info;
+
+/**
+ * The card detect interrupt isn't debounced so we delay it by 250ms
+ * to give the card a chance to fully insert/eject.
+ */
+static int mci_init(struct device *dev, irq_handler_t detect_int, void *data)
+{
+	int rc;
+	int irq = gpio_to_irq(GPIO15_SDIO_INSERT);
+
+	rc = mio_gpio_request(ARRAY_AND_SIZE(mci_gpios));
+	if (rc)
+		goto err_gpio;
+	/* enable RE/FE interrupt on card insertion and removal */
+	rc = request_irq(irq, detect_int,
+			 IRQF_DISABLED | IRQF_TRIGGER_RISING |
+			 IRQF_TRIGGER_FALLING,
+			 "MMC card detect", data);
+	if (rc)
+		goto err_irq;
+
+	mioa701_mci_info.detect_delay = msecs_to_jiffies(250);
+	return 0;
+
+err_irq:
+	dev_err(dev, "mioa701_mci_init: MMC/SD:"
+		" can't request MMC card detect IRQ\n");
+	mio_gpio_free(ARRAY_AND_SIZE(mci_gpios));
+err_gpio:
+	return rc;
+}
+
+static struct pxamci_platform_data mioa701_mci_info = {
+	.ocr_mask = MMC_VDD_32_33 | MMC_VDD_33_34,
+	.init	  = mci_init,
+	.get_ro	  = mci_get_ro,
+	.setpower = mci_setpower,
+	.exit	  = mci_exit,
+};
+
+/* FlashRAM */
+static struct resource strataflash_resource = {
+	.start = PXA_CS0_PHYS,
+	.end   = PXA_CS0_PHYS + SZ_64M - 1,
+	.flags = IORESOURCE_MEM,
+};
+
+static struct physmap_flash_data strataflash_data = {
+	.width = 2,
+	/* .set_vpp = mioa701_set_vpp, */
+};
+
+static struct platform_device strataflash = {
+	.name	       = "physmap-flash",
+	.id	       = -1,
+	.resource      = &strataflash_resource,
+	.num_resources = 1,
+	.dev = {
+		.platform_data = &strataflash_data,
+	},
+};
+
+/*
+ * Suspend/Resume bootstrap management
+ *
+ * MIO A701 reboot sequence is highly ROM dependant. From the one dissassembled,
+ * this sequence is as follows :
+ *   - disables interrupts
+ *   - initialize SDRAM (self refresh RAM into active RAM)
+ *   - initialize GPIOs (depends on value at 0xa020b020)
+ *   - initialize coprossessors
+ *   - if edge detect on PWR_SCL(GPIO3), then proceed to cold start
+ *   - or if value at 0xa020b000 not equal to 0x0f0f0f0f, proceed to cold start
+ *   - else do a resume, ie. jump to addr 0xa0100000
+ */
+#define RESUME_ENABLE_ADDR	0xa020b000
+#define RESUME_ENABLE_VAL	0x0f0f0f0f
+#define RESUME_BT_ADDR		0xa020b020
+#define RESUME_UNKNOWN_ADDR	0xa020b024
+#define RESUME_VECTOR_ADDR	0xa0100000
+#define BOOTSTRAP_WORDS		mioa701_bootstrap_lg/4
+
+static u32 *save_buffer;
+
+static void install_bootstrap(void)
+{
+	int i;
+	u32 *rom_bootstrap  = phys_to_virt(RESUME_VECTOR_ADDR);
+	u32 *src = &mioa701_bootstrap;
+
+	for (i = 0; i < BOOTSTRAP_WORDS; i++)
+		rom_bootstrap[i] = src[i];
+}
+
+
+static int mioa701_sys_suspend(struct sys_device *sysdev, pm_message_t state)
+{
+	int i = 0, is_bt_on;
+	u32 *mem_resume_vector	= phys_to_virt(RESUME_VECTOR_ADDR);
+	u32 *mem_resume_enabler = phys_to_virt(RESUME_ENABLE_ADDR);
+	u32 *mem_resume_bt	= phys_to_virt(RESUME_BT_ADDR);
+	u32 *mem_resume_unknown	= phys_to_virt(RESUME_UNKNOWN_ADDR);
+
+	/* Devices prepare suspend */
+	is_bt_on = gpio_get_value(GPIO83_BT_ON);
+	pxa2xx_mfp_set_lpm(GPIO83_BT_ON,
+			   is_bt_on ? MFP_LPM_DRIVE_HIGH : MFP_LPM_DRIVE_LOW);
+
+	for (i = 0; i < BOOTSTRAP_WORDS; i++)
+		save_buffer[i] = mem_resume_vector[i];
+	save_buffer[i++] = *mem_resume_enabler;
+	save_buffer[i++] = *mem_resume_bt;
+	save_buffer[i++] = *mem_resume_unknown;
+
+	*mem_resume_enabler = RESUME_ENABLE_VAL;
+	*mem_resume_bt	    = is_bt_on;
+
+	install_bootstrap();
+	return 0;
+}
+
+static int mioa701_sys_resume(struct sys_device *sysdev)
+{
+	int i = 0;
+	u32 *mem_resume_vector	= phys_to_virt(RESUME_VECTOR_ADDR);
+	u32 *mem_resume_enabler = phys_to_virt(RESUME_ENABLE_ADDR);
+	u32 *mem_resume_bt	= phys_to_virt(RESUME_BT_ADDR);
+	u32 *mem_resume_unknown	= phys_to_virt(RESUME_UNKNOWN_ADDR);
+
+	for (i = 0; i < BOOTSTRAP_WORDS; i++)
+		mem_resume_vector[i] = save_buffer[i];
+	*mem_resume_enabler = save_buffer[i++];
+	*mem_resume_bt	    = save_buffer[i++];
+	*mem_resume_unknown = save_buffer[i++];
+
+	return 0;
+}
+
+static struct sysdev_class mioa701_sysclass = {
+	.name = "mioa701",
+};
+
+static struct sys_device sysdev_bootstrap = {
+	.cls		= &mioa701_sysclass,
+};
+
+static struct sysdev_driver driver_bootstrap = {
+	.suspend	= &mioa701_sys_suspend,
+	.resume		= &mioa701_sys_resume,
+};
+
+static int __init bootstrap_init(void)
+{
+	int rc;
+	int save_size = mioa701_bootstrap_lg + (sizeof(u32) * 3);
+
+	rc = sysdev_class_register(&mioa701_sysclass);
+	if (rc) {
+		printk(KERN_ERR "Failed registering mioa701 sys class\n");
+		return -ENODEV;
+	}
+	rc = sysdev_register(&sysdev_bootstrap);
+	if (rc) {
+		printk(KERN_ERR "Failed registering mioa701 sys device\n");
+		return -ENODEV;
+	}
+	rc = sysdev_driver_register(&mioa701_sysclass, &driver_bootstrap);
+	if (rc) {
+		printk(KERN_ERR "Failed registering PMU sys driver\n");
+		return -ENODEV;
+	}
+
+	save_buffer = kmalloc(save_size, GFP_KERNEL);
+	if (!save_buffer)
+		return -ENOMEM;
+	printk(KERN_INFO "MioA701: allocated %d bytes for bootstrap\n",
+	       save_size);
+	return 0;
+}
+
+static void bootstrap_exit(void)
+{
+	kfree(save_buffer);
+	sysdev_driver_unregister(&mioa701_sysclass, &driver_bootstrap);
+	sysdev_unregister(&sysdev_bootstrap);
+	sysdev_class_unregister(&mioa701_sysclass);
+
+	printk(KERN_CRIT "Unregistering mioa701 suspend will hang next"
+	       "resume !!!\n");
+}
+
+/*
+ * Power Supply
+ */
+static char *supplicants[] = {
+	"mioa701_battery"
+};
+
+static void mioa701_set_charge(int flags)
+{
+	gpio_set_value(GPIO9_CHARGE_nEN, !flags);
+}
+
+static struct pda_power_pdata power_pdata = {
+	.is_ac_online	= is_usb_connected,
+	.set_charge = mioa701_set_charge,
+	.supplied_to = supplicants,
+	.num_supplicants = ARRAY_SIZE(supplicants),
+};
+
+static struct resource power_resources[] = {
+	[0] = {
+		.name	= "ac",
+		.start	= gpio_to_irq(GPIO13_USB_DETECT),
+		.end	= gpio_to_irq(GPIO13_USB_DETECT),
+		.flags	= IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE |
+		IORESOURCE_IRQ_LOWEDGE,
+	},
+};
+
+static struct platform_device power_dev = {
+	.name		= "pda-power",
+	.id		= -1,
+	.resource	= power_resources,
+	.num_resources	= ARRAY_SIZE(power_resources),
+	.dev = {
+		.platform_data	= &power_pdata,
+	},
+};
+
+#if defined(CONFIG_PDA_POWER) && defined(CONFIG_TOUCHSCREEN_WM97XX)
+static struct wm97xx *battery_wm;
+
+static enum power_supply_property battery_props[] = {
+	POWER_SUPPLY_PROP_STATUS,
+	POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
+	POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
+	POWER_SUPPLY_PROP_VOLTAGE_NOW,
+	POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,	/* Necessary for apm */
+};
+
+static int get_battery_voltage(void)
+{
+	int adc = -1;
+
+	if (battery_wm)
+		adc = wm97xx_read_aux_adc(battery_wm, WM97XX_AUX_ID1);
+	return adc;
+}
+
+static int get_battery_status(struct power_supply *b)
+{
+	int status;
+
+	if (is_usb_connected())
+		status = POWER_SUPPLY_STATUS_CHARGING;
+	else
+		status = POWER_SUPPLY_STATUS_DISCHARGING;
+
+	return status;
+}
+
+static int get_property(struct power_supply *b,
+			enum power_supply_property psp,
+			union power_supply_propval *val)
+{
+	int rc = 0;
+
+	switch (psp) {
+	case POWER_SUPPLY_PROP_STATUS:
+		val->intval = get_battery_status(b);
+		break;
+	case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
+		val->intval = 0xfd0;
+		break;
+	case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
+		val->intval = 0xc00;
+		break;
+	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+		val->intval = get_battery_voltage();
+		break;
+	case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
+		val->intval = 100;
+		break;
+	default:
+		val->intval = -1;
+		rc = -1;
+	}
+
+	return rc;
+};
+
+static struct power_supply battery_ps = {
+	.name = "mioa701_battery",
+	.type = POWER_SUPPLY_TYPE_BATTERY,
+	.get_property = get_property,
+	.properties = battery_props,
+	.num_properties = ARRAY_SIZE(battery_props),
+};
+
+static int battery_probe(struct platform_device *pdev)
+{
+	struct wm97xx *wm = platform_get_drvdata(pdev);
+	int rc;
+
+	battery_wm = wm;
+
+	rc = power_supply_register(NULL, &battery_ps);
+	if (rc)
+		dev_err(&pdev->dev,
+		"Could not register mioa701 battery -> %d\n", rc);
+	return rc;
+}
+
+static int battery_remove(struct platform_device *pdev)
+{
+	battery_wm = NULL;
+	return 0;
+}
+
+static struct platform_driver mioa701_battery_driver = {
+	.driver = {
+		.name = "wm97xx-battery",
+	},
+	.probe = battery_probe,
+	.remove = battery_remove
+};
+
+static int __init mioa701_battery_init(void)
+{
+	int rc;
+
+	rc = platform_driver_register(&mioa701_battery_driver);
+	if (rc)
+		printk(KERN_ERR "Could not register mioa701 battery driver\n");
+	return rc;
+}
+
+#else
+static int __init mioa701_battery_init(void)
+{
+	return 0;
+}
+#endif
+
+/*
+ * Mio global
+ */
+
+/* Devices */
+#define MIO_PARENT_DEV(var, strname, tparent, pdata)	\
+static struct platform_device var = {			\
+	.name		= strname,			\
+	.id		= -1,				\
+	.dev		= {				\
+		.platform_data = pdata,			\
+		.parent	= tparent,			\
+	},						\
+};
+#define MIO_SIMPLE_DEV(var, strname, pdata)	\
+	MIO_PARENT_DEV(var, strname, NULL, pdata)
+
+MIO_SIMPLE_DEV(mioa701_gpio_keys, "gpio-keys",	    &mioa701_gpio_keys_data)
+MIO_PARENT_DEV(mioa701_backlight, "pwm-backlight",  &pxa27x_device_pwm0.dev,
+		&mioa701_backlight_data);
+MIO_SIMPLE_DEV(mioa701_led,	  "leds-gpio",	    &gpio_led_info)
+MIO_SIMPLE_DEV(pxa2xx_pcm,	  "pxa2xx-pcm",	    NULL)
+MIO_SIMPLE_DEV(pxa2xx_ac97,	  "pxa2xx-ac97",    NULL)
+MIO_PARENT_DEV(mio_wm9713_codec,  "wm9713-codec",   &pxa2xx_ac97.dev, NULL)
+MIO_SIMPLE_DEV(mioa701_sound,	  "mioa701-wm9713", NULL)
+MIO_SIMPLE_DEV(mioa701_board,	  "mioa701-board",  NULL)
+
+static struct platform_device *devices[] __initdata = {
+	&mioa701_gpio_keys,
+	&mioa701_backlight,
+	&mioa701_led,
+	&pxa2xx_pcm,
+	&pxa2xx_ac97,
+	&mio_wm9713_codec,
+	&mioa701_sound,
+	&power_dev,
+	&strataflash,
+	&mioa701_board
+};
+
+static void mioa701_machine_exit(void);
+
+static void mioa701_poweroff(void)
+{
+	mioa701_machine_exit();
+	gpio_set_value(GPIO18_POWEROFF, 1);
+}
+
+static void mioa701_restart(char c)
+{
+	mioa701_machine_exit();
+	arm_machine_restart(c);
+}
+
+struct gpio_ress global_gpios[] = {
+	MIO_GPIO_OUT(GPIO9_CHARGE_nEN, 1, "Charger enable"),
+	MIO_GPIO_OUT(GPIO18_POWEROFF, 0, "Power Off"),
+	MIO_GPIO_OUT(GPIO87_LCD_POWER, 0, "LCD Power")
+};
+
+static void __init mioa701_machine_init(void)
+{
+	PSLR  = 0xff100000; /* SYSDEL=125ms, PWRDEL=125ms, PSLR_SL_ROD=1 */
+	PCFR = PCFR_DC_EN | PCFR_GPR_EN | PCFR_OPDE;
+	RTTR = 32768 - 1; /* Reset crazy WinCE value */
+	UP2OCR = UP2OCR_HXOE;
+
+	pxa2xx_mfp_config(ARRAY_AND_SIZE(mioa701_pin_config));
+	mio_gpio_request(ARRAY_AND_SIZE(global_gpios));
+	bootstrap_init();
+	set_pxa_fb_info(&mioa701_pxafb_info);
+	pxa_set_mci_info(&mioa701_mci_info);
+	pxa_set_keypad_info(&mioa701_keypad_info);
+	udc_init();
+	pm_power_off = mioa701_poweroff;
+	arm_pm_restart = mioa701_restart;
+	platform_add_devices(devices, ARRAY_SIZE(devices));
+	gsm_init();
+	mioa701_battery_init();
+}
+
+static void mioa701_machine_exit(void)
+{
+	udc_exit();
+	bootstrap_exit();
+	gsm_exit();
+}
+
+MACHINE_START(MIOA701, "MIO A701")
+	.phys_io	= 0x40000000,
+	.io_pg_offst	= (io_p2v(0x40000000) >> 18) & 0xfffc,
+	.boot_params	= 0xa0000100,
+	.map_io		= &pxa_map_io,
+	.init_irq	= &pxa27x_init_irq,
+	.init_machine	= mioa701_machine_init,
+	.timer		= &pxa_timer,
+MACHINE_END
diff --git a/arch/arm/mach-pxa/mioa701_bootresume.S b/arch/arm/mach-pxa/mioa701_bootresume.S
new file mode 100644
index 0000000..a647693
--- /dev/null
+++ b/arch/arm/mach-pxa/mioa701_bootresume.S
@@ -0,0 +1,36 @@
+/* Bootloader to resume MIO A701
+ *
+ * 2007-1-12 Robert Jarzmik
+ *
+ * This code is licenced under the GPLv2.
+*/
+
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+
+/*
+ * Note: Yes, part of the following code is located into the .data section.
+ *       This is to allow jumpaddr to be accessed with a relative load
+ *       while we can't rely on any MMU translation.  We could have put
+ *       sleep_save_sp in the .text section as well, but some setups might
+ *       insist on it to be truly read-only.
+ */
+	.data
+ENTRY(mioa701_bootstrap)
+0:
+	b	1f
+ENTRY(mioa701_jumpaddr)
+	.word	0x40f00008		@ PSPR in no-MMU mode
+1:
+	mov	r0,     #0xa0000000	@ Don't suppose memory access works
+	orr	r0, r0, #0x00200000	@ even if it's supposed to
+	mov	r1, #0
+	str	r1, [r0]		@ Early disable resume for next boot
+	ldr	r0, mioa701_jumpaddr	@ (Murphy's Law)
+	ldr	r0, [r0]
+	mov	pc, r0
+2:
+
+ENTRY(mioa701_bootstrap_lg)
+	.data
+	.word	2b-0b
diff --git a/arch/arm/mach-pxa/mp900.c b/arch/arm/mach-pxa/mp900.c
new file mode 100644
index 0000000..8a73814
--- /dev/null
+++ b/arch/arm/mach-pxa/mp900.c
@@ -0,0 +1,100 @@
+/*
+ *  linux/arch/arm/mach-pxa/mp900.c
+ *
+ *  Support for the NEC MobilePro900/C platform
+ *
+ *  Based on mach-pxa/gumstix.c
+ *
+ *  2007, 2008 Kristoffer Ericson <kristoffer.ericson@gmail.com>
+ *  2007, 2008 Michael Petchkovsky <mkpetch@internode.on.net>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/types.h>
+#include <linux/usb/isp116x.h>
+
+#include <mach/hardware.h>
+#include <mach/pxa-regs.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include "generic.h"
+
+static void isp116x_pfm_delay(struct device *dev, int delay)
+{
+
+	/* 400Mhz PXA2 = 2.5ns / instruction */
+
+	int cyc = delay / 10;
+
+	/* 4 Instructions = 4 x 2.5ns = 10ns */
+	__asm__ volatile ("0:\n"
+		"subs %0, %1, #1\n"
+		"bge 0b\n"
+		:"=r" (cyc)
+		:"0"(cyc)
+	);
+}
+
+static struct isp116x_platform_data isp116x_pfm_data = {
+	.remote_wakeup_enable = 1,
+	.delay = isp116x_pfm_delay,
+};
+
+static struct resource isp116x_pfm_resources[] = {
+	[0] =	{
+		.start	= 0x0d000000,
+		.end	= 0x0d000000 + 1,
+		.flags	= IORESOURCE_MEM,
+		},
+	[1] =	{
+		.start  = 0x0d000000 + 4,
+		.end	= 0x0d000000 + 5,
+		.flags  = IORESOURCE_MEM,
+		},
+	[2] =	{
+		.start	= 61,
+		.end	= 61,
+		.flags	= IORESOURCE_IRQ,
+		},
+};
+
+static struct platform_device mp900c_dummy_device = {
+	.name		= "mp900c_dummy",
+	.id		= -1,
+};
+
+static struct platform_device mp900c_usb = {
+	.name		= "isp116x-hcd",
+	.num_resources	= ARRAY_SIZE(isp116x_pfm_resources),
+	.resource	= isp116x_pfm_resources,
+	.dev.platform_data = &isp116x_pfm_data,
+};
+
+static struct platform_device *devices[] __initdata = {
+	&mp900c_dummy_device,
+	&mp900c_usb,
+};
+
+static void __init mp900c_init(void)
+{
+	printk(KERN_INFO "MobilePro 900/C machine init\n");
+	platform_add_devices(devices, ARRAY_SIZE(devices));
+}
+
+/* Maintainer - Michael Petchkovsky <mkpetch@internode.on.net> */
+MACHINE_START(NEC_MP900, "MobilePro900/C")
+	.phys_io	= 0x40000000,
+	.boot_params	= 0xa0220100,
+	.io_pg_offst	= (io_p2v(0x40000000) >> 18) & 0xfffc,
+	.timer		= &pxa_timer,
+	.map_io		= pxa_map_io,
+	.init_irq	= pxa25x_init_irq,
+	.init_machine	= mp900c_init,
+MACHINE_END
+
diff --git a/arch/arm/mach-pxa/palmtx.c b/arch/arm/mach-pxa/palmtx.c
index fe924a2..4447711 100644
--- a/arch/arm/mach-pxa/palmtx.c
+++ b/arch/arm/mach-pxa/palmtx.c
@@ -25,6 +25,8 @@
 #include <linux/pda_power.h>
 #include <linux/pwm_backlight.h>
 #include <linux/gpio.h>
+#include <linux/wm97xx_batt.h>
+#include <linux/power_supply.h>
 
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
@@ -340,6 +342,23 @@
 };
 
 /******************************************************************************
+ * WM97xx battery
+ ******************************************************************************/
+static struct wm97xx_batt_info wm97xx_batt_pdata = {
+	.batt_aux	= WM97XX_AUX_ID3,
+	.temp_aux	= WM97XX_AUX_ID2,
+	.charge_gpio	= -1,
+	.max_voltage	= PALMTX_BAT_MAX_VOLTAGE,
+	.min_voltage	= PALMTX_BAT_MIN_VOLTAGE,
+	.batt_mult	= 1000,
+	.batt_div	= 414,
+	.temp_mult	= 1,
+	.temp_div	= 1,
+	.batt_tech	= POWER_SUPPLY_TECHNOLOGY_LIPO,
+	.batt_name	= "main-batt",
+};
+
+/******************************************************************************
  * Framebuffer
  ******************************************************************************/
 static struct pxafb_mode_info palmtx_lcd_modes[] = {
@@ -401,6 +420,7 @@
 	pxa_set_ac97_info(NULL);
 	pxa_set_ficp_info(&palmtx_ficp_platform_data);
 	pxa_set_keypad_info(&palmtx_keypad_platform_data);
+	wm97xx_bat_set_pdata(&wm97xx_batt_pdata);
 
 	platform_add_devices(devices, ARRAY_SIZE(devices));
 }
diff --git a/arch/arm/mach-pxa/palmz72.c b/arch/arm/mach-pxa/palmz72.c
new file mode 100644
index 0000000..2f730da
--- /dev/null
+++ b/arch/arm/mach-pxa/palmz72.c
@@ -0,0 +1,554 @@
+/*
+ * Hardware definitions for Palm Zire72
+ *
+ * Authors:
+ *	Vladimir "Farcaller" Pouzanov <farcaller@gmail.com>
+ *	Sergey Lapin <slapin@ossfans.org>
+ *	Alex Osborne <bobofdoom@gmail.com>
+ *	Jan Herman <2hp@seznam.cz>
+ *
+ * Rewrite for mainline:
+ *	Marek Vasut <marek.vasut@gmail.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.
+ *
+ * (find more info at www.hackndev.com)
+ *
+ */
+
+#include <linux/platform_device.h>
+#include <linux/sysdev.h>
+#include <linux/delay.h>
+#include <linux/irq.h>
+#include <linux/gpio_keys.h>
+#include <linux/input.h>
+#include <linux/pda_power.h>
+#include <linux/pwm_backlight.h>
+#include <linux/gpio.h>
+#include <linux/power_supply.h>
+
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+
+#include <mach/audio.h>
+#include <mach/palmz72.h>
+#include <mach/mmc.h>
+#include <mach/pxafb.h>
+#include <mach/pxa-regs.h>
+#include <mach/pxa2xx-regs.h>
+#include <mach/mfp-pxa27x.h>
+#include <mach/irda.h>
+#include <mach/pxa27x_keypad.h>
+#include <mach/udc.h>
+#include <mach/pm.h>
+
+#include "generic.h"
+#include "devices.h"
+
+/******************************************************************************
+ * Pin configuration
+ ******************************************************************************/
+static unsigned long palmz72_pin_config[] __initdata = {
+	/* MMC */
+	GPIO32_MMC_CLK,
+	GPIO92_MMC_DAT_0,
+	GPIO109_MMC_DAT_1,
+	GPIO110_MMC_DAT_2,
+	GPIO111_MMC_DAT_3,
+	GPIO112_MMC_CMD,
+	GPIO14_GPIO,	/* SD detect */
+	GPIO115_GPIO,	/* SD RO */
+	GPIO98_GPIO,	/* SD power */
+
+	/* AC97 */
+	GPIO28_AC97_BITCLK,
+	GPIO29_AC97_SDATA_IN_0,
+	GPIO30_AC97_SDATA_OUT,
+	GPIO31_AC97_SYNC,
+
+	/* IrDA */
+	GPIO49_GPIO,	/* ir disable */
+	GPIO46_FICP_RXD,
+	GPIO47_FICP_TXD,
+
+	/* PWM */
+	GPIO16_PWM0_OUT,
+
+	/* USB */
+	GPIO15_GPIO,	/* usb detect */
+	GPIO12_GPIO,	/* usb pullup */
+	GPIO95_GPIO,	/* usb power */
+
+	/* Matrix keypad */
+	GPIO100_KP_MKIN_0	| WAKEUP_ON_LEVEL_HIGH,
+	GPIO101_KP_MKIN_1	| WAKEUP_ON_LEVEL_HIGH,
+	GPIO102_KP_MKIN_2	| WAKEUP_ON_LEVEL_HIGH,
+	GPIO97_KP_MKIN_3	| WAKEUP_ON_LEVEL_HIGH,
+	GPIO103_KP_MKOUT_0,
+	GPIO104_KP_MKOUT_1,
+	GPIO105_KP_MKOUT_2,
+
+	/* LCD */
+	GPIO58_LCD_LDD_0,
+	GPIO59_LCD_LDD_1,
+	GPIO60_LCD_LDD_2,
+	GPIO61_LCD_LDD_3,
+	GPIO62_LCD_LDD_4,
+	GPIO63_LCD_LDD_5,
+	GPIO64_LCD_LDD_6,
+	GPIO65_LCD_LDD_7,
+	GPIO66_LCD_LDD_8,
+	GPIO67_LCD_LDD_9,
+	GPIO68_LCD_LDD_10,
+	GPIO69_LCD_LDD_11,
+	GPIO70_LCD_LDD_12,
+	GPIO71_LCD_LDD_13,
+	GPIO72_LCD_LDD_14,
+	GPIO73_LCD_LDD_15,
+	GPIO74_LCD_FCLK,
+	GPIO75_LCD_LCLK,
+	GPIO76_LCD_PCLK,
+	GPIO77_LCD_BIAS,
+	GPIO20_GPIO,	/* bl power */
+	GPIO21_GPIO,	/* LCD border switch */
+	GPIO22_GPIO,	/* LCD border color */
+	GPIO96_GPIO,	/* lcd power */
+
+	/* Misc. */
+	GPIO0_GPIO	| WAKEUP_ON_LEVEL_HIGH,	/* power detect */
+	GPIO88_GPIO,				/* green led */
+	GPIO27_GPIO,				/* WM9712 IRQ */
+};
+
+/******************************************************************************
+ * SD/MMC card controller
+ ******************************************************************************/
+static int palmz72_mci_init(struct device *dev,
+				irq_handler_t palmz72_detect_int, void *data)
+{
+	int err = 0;
+
+	/* Setup an interrupt for detecting card insert/remove events */
+	err = gpio_request(GPIO_NR_PALMZ72_SD_DETECT_N, "SD IRQ");
+	if (err)
+		goto err;
+	err = gpio_direction_input(GPIO_NR_PALMZ72_SD_DETECT_N);
+	if (err)
+		goto err2;
+	err = request_irq(gpio_to_irq(GPIO_NR_PALMZ72_SD_DETECT_N),
+			palmz72_detect_int, IRQF_DISABLED | IRQF_SAMPLE_RANDOM |
+			IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
+			"SD/MMC card detect", data);
+	if (err) {
+		printk(KERN_ERR "%s: cannot request SD/MMC card detect IRQ\n",
+				__func__);
+		goto err2;
+	}
+
+	/* SD_POWER is not actually power, but it is more like chip
+	 * select, i.e. it is inverted */
+
+	err = gpio_request(GPIO_NR_PALMZ72_SD_POWER_N, "SD_POWER");
+	if (err)
+		goto err3;
+	err = gpio_direction_output(GPIO_NR_PALMZ72_SD_POWER_N, 0);
+	if (err)
+		goto err4;
+	err = gpio_request(GPIO_NR_PALMZ72_SD_RO, "SD_RO");
+	if (err)
+		goto err4;
+	err = gpio_direction_input(GPIO_NR_PALMZ72_SD_RO);
+	if (err)
+		goto err5;
+
+	printk(KERN_DEBUG "%s: irq registered\n", __func__);
+
+	return 0;
+
+err5:
+	gpio_free(GPIO_NR_PALMZ72_SD_RO);
+err4:
+	gpio_free(GPIO_NR_PALMZ72_SD_POWER_N);
+err3:
+	free_irq(gpio_to_irq(GPIO_NR_PALMZ72_SD_DETECT_N), data);
+err2:
+	gpio_free(GPIO_NR_PALMZ72_SD_DETECT_N);
+err:
+	return err;
+}
+
+static void palmz72_mci_exit(struct device *dev, void *data)
+{
+	gpio_free(GPIO_NR_PALMZ72_SD_POWER_N);
+	free_irq(gpio_to_irq(GPIO_NR_PALMZ72_SD_DETECT_N), data);
+	gpio_free(GPIO_NR_PALMZ72_SD_DETECT_N);
+	gpio_free(GPIO_NR_PALMZ72_SD_RO);
+}
+
+static void palmz72_mci_power(struct device *dev, unsigned int vdd)
+{
+	struct pxamci_platform_data *p_d = dev->platform_data;
+	if (p_d->ocr_mask & (1 << vdd))
+		gpio_set_value(GPIO_NR_PALMZ72_SD_POWER_N, 0);
+	else
+		gpio_set_value(GPIO_NR_PALMZ72_SD_POWER_N, 1);
+}
+
+static int palmz72_mci_ro(struct device *dev)
+{
+	return gpio_get_value(GPIO_NR_PALMZ72_SD_RO);
+}
+
+static struct pxamci_platform_data palmz72_mci_platform_data = {
+	.ocr_mask	= MMC_VDD_32_33 | MMC_VDD_33_34,
+	.setpower	= palmz72_mci_power,
+	.get_ro		= palmz72_mci_ro,
+	.init 		= palmz72_mci_init,
+	.exit		= palmz72_mci_exit,
+};
+
+/******************************************************************************
+ * GPIO keyboard
+ ******************************************************************************/
+static unsigned int palmz72_matrix_keys[] = {
+	KEY(0, 0, KEY_POWER),
+	KEY(0, 1, KEY_F1),
+	KEY(0, 2, KEY_ENTER),
+
+	KEY(1, 0, KEY_F2),
+	KEY(1, 1, KEY_F3),
+	KEY(1, 2, KEY_F4),
+
+	KEY(2, 0, KEY_UP),
+	KEY(2, 2, KEY_DOWN),
+
+	KEY(3, 0, KEY_RIGHT),
+	KEY(3, 2, KEY_LEFT),
+};
+
+static struct pxa27x_keypad_platform_data palmz72_keypad_platform_data = {
+	.matrix_key_rows	= 4,
+	.matrix_key_cols	= 3,
+	.matrix_key_map		= palmz72_matrix_keys,
+	.matrix_key_map_size	= ARRAY_SIZE(palmz72_matrix_keys),
+
+	.debounce_interval	= 30,
+};
+
+/******************************************************************************
+ * Backlight
+ ******************************************************************************/
+static int palmz72_backlight_init(struct device *dev)
+{
+	int ret;
+
+	ret = gpio_request(GPIO_NR_PALMZ72_BL_POWER, "BL POWER");
+	if (ret)
+		goto err;
+	ret = gpio_direction_output(GPIO_NR_PALMZ72_BL_POWER, 0);
+	if (ret)
+		goto err2;
+	ret = gpio_request(GPIO_NR_PALMZ72_LCD_POWER, "LCD POWER");
+	if (ret)
+		goto err2;
+	ret = gpio_direction_output(GPIO_NR_PALMZ72_LCD_POWER, 0);
+	if (ret)
+		goto err3;
+
+	return 0;
+err3:
+	gpio_free(GPIO_NR_PALMZ72_LCD_POWER);
+err2:
+	gpio_free(GPIO_NR_PALMZ72_BL_POWER);
+err:
+	return ret;
+}
+
+static int palmz72_backlight_notify(int brightness)
+{
+	gpio_set_value(GPIO_NR_PALMZ72_BL_POWER, brightness);
+	gpio_set_value(GPIO_NR_PALMZ72_LCD_POWER, brightness);
+	return brightness;
+}
+
+static void palmz72_backlight_exit(struct device *dev)
+{
+	gpio_free(GPIO_NR_PALMZ72_BL_POWER);
+	gpio_free(GPIO_NR_PALMZ72_LCD_POWER);
+}
+
+static struct platform_pwm_backlight_data palmz72_backlight_data = {
+	.pwm_id		= 0,
+	.max_brightness	= PALMZ72_MAX_INTENSITY,
+	.dft_brightness	= PALMZ72_MAX_INTENSITY,
+	.pwm_period_ns	= PALMZ72_PERIOD_NS,
+	.init		= palmz72_backlight_init,
+	.notify		= palmz72_backlight_notify,
+	.exit		= palmz72_backlight_exit,
+};
+
+static struct platform_device palmz72_backlight = {
+	.name	= "pwm-backlight",
+	.dev	= {
+		.parent		= &pxa27x_device_pwm0.dev,
+		.platform_data	= &palmz72_backlight_data,
+	},
+};
+
+/******************************************************************************
+ * IrDA
+ ******************************************************************************/
+static int palmz72_irda_startup(struct device *dev)
+{
+	int err;
+	err = gpio_request(GPIO_NR_PALMZ72_IR_DISABLE, "IR DISABLE");
+	if (err)
+		goto err;
+	err = gpio_direction_output(GPIO_NR_PALMZ72_IR_DISABLE, 1);
+	if (err)
+		gpio_free(GPIO_NR_PALMZ72_IR_DISABLE);
+err:
+	return err;
+}
+
+static void palmz72_irda_shutdown(struct device *dev)
+{
+	gpio_free(GPIO_NR_PALMZ72_IR_DISABLE);
+}
+
+static void palmz72_irda_transceiver_mode(struct device *dev, int mode)
+{
+	gpio_set_value(GPIO_NR_PALMZ72_IR_DISABLE, mode & IR_OFF);
+	pxa2xx_transceiver_mode(dev, mode);
+}
+
+static struct pxaficp_platform_data palmz72_ficp_platform_data = {
+	.startup		= palmz72_irda_startup,
+	.shutdown		= palmz72_irda_shutdown,
+	.transceiver_cap	= IR_SIRMODE | IR_OFF,
+	.transceiver_mode	= palmz72_irda_transceiver_mode,
+};
+
+/******************************************************************************
+ * LEDs
+ ******************************************************************************/
+static struct gpio_led gpio_leds[] = {
+	{
+		.name			= "palmz72:green:led",
+		.default_trigger	= "none",
+		.gpio			= GPIO_NR_PALMZ72_LED_GREEN,
+	},
+};
+
+static struct gpio_led_platform_data gpio_led_info = {
+	.leds		= gpio_leds,
+	.num_leds	= ARRAY_SIZE(gpio_leds),
+};
+
+static struct platform_device palmz72_leds = {
+	.name	= "leds-gpio",
+	.id	= -1,
+	.dev	= {
+		.platform_data	= &gpio_led_info,
+	}
+};
+
+/******************************************************************************
+ * Power supply
+ ******************************************************************************/
+static int power_supply_init(struct device *dev)
+{
+	int ret;
+
+	ret = gpio_request(GPIO_NR_PALMZ72_POWER_DETECT, "CABLE_STATE_AC");
+	if (ret)
+		goto err1;
+	ret = gpio_direction_input(GPIO_NR_PALMZ72_POWER_DETECT);
+	if (ret)
+		goto err2;
+
+	ret = gpio_request(GPIO_NR_PALMZ72_USB_DETECT_N, "CABLE_STATE_USB");
+	if (ret)
+		goto err2;
+	ret = gpio_direction_input(GPIO_NR_PALMZ72_USB_DETECT_N);
+	if (ret)
+		goto err3;
+
+	return 0;
+err3:
+	gpio_free(GPIO_NR_PALMZ72_USB_DETECT_N);
+err2:
+	gpio_free(GPIO_NR_PALMZ72_POWER_DETECT);
+err1:
+	return ret;
+}
+
+static int palmz72_is_ac_online(void)
+{
+	return gpio_get_value(GPIO_NR_PALMZ72_POWER_DETECT);
+}
+
+static int palmz72_is_usb_online(void)
+{
+	return !gpio_get_value(GPIO_NR_PALMZ72_USB_DETECT_N);
+}
+
+static void power_supply_exit(struct device *dev)
+{
+	gpio_free(GPIO_NR_PALMZ72_USB_DETECT_N);
+	gpio_free(GPIO_NR_PALMZ72_POWER_DETECT);
+}
+
+static char *palmz72_supplicants[] = {
+	"main-battery",
+};
+
+static struct pda_power_pdata power_supply_info = {
+	.init            = power_supply_init,
+	.is_ac_online    = palmz72_is_ac_online,
+	.is_usb_online   = palmz72_is_usb_online,
+	.exit            = power_supply_exit,
+	.supplied_to     = palmz72_supplicants,
+	.num_supplicants = ARRAY_SIZE(palmz72_supplicants),
+};
+
+static struct platform_device power_supply = {
+	.name = "pda-power",
+	.id   = -1,
+	.dev  = {
+		.platform_data = &power_supply_info,
+	},
+};
+
+/******************************************************************************
+ * Framebuffer
+ ******************************************************************************/
+static struct pxafb_mode_info palmz72_lcd_modes[] = {
+{
+	.pixclock	= 115384,
+	.xres		= 320,
+	.yres		= 320,
+	.bpp		= 16,
+
+	.left_margin	= 27,
+	.right_margin	= 7,
+	.upper_margin	= 7,
+	.lower_margin	= 8,
+
+	.hsync_len	= 6,
+	.vsync_len	= 1,
+},
+};
+
+static struct pxafb_mach_info palmz72_lcd_screen = {
+	.modes		= palmz72_lcd_modes,
+	.num_modes	= ARRAY_SIZE(palmz72_lcd_modes),
+	.lcd_conn	= LCD_COLOR_TFT_16BPP | LCD_PCLK_EDGE_FALL,
+};
+
+#ifdef CONFIG_PM
+
+/* We have some black magic here
+ * PalmOS ROM on recover expects special struct physical address
+ * to be transferred via PSPR. Using this struct PalmOS restores
+ * its state after sleep. As for Linux, we need to setup it the
+ * same way. More than that, PalmOS ROM changes some values in memory.
+ * For now only one location is found, which needs special treatment.
+ * Thanks to Alex Osborne, Andrzej Zaborowski, and lots of other people
+ * for reading backtraces for me :)
+ */
+
+#define PALMZ72_SAVE_DWORD ((unsigned long *)0xc0000050)
+
+static struct palmz72_resume_info palmz72_resume_info = {
+	.magic0 = 0xb4e6,
+	.magic1 = 1,
+
+	/* reset state, MMU off etc */
+	.arm_control = 0,
+	.aux_control = 0,
+	.ttb = 0,
+	.domain_access = 0,
+	.process_id = 0,
+};
+
+static unsigned long store_ptr;
+
+/* sys_device for Palm Zire 72 PM */
+
+static int palmz72_pm_suspend(struct sys_device *dev, pm_message_t msg)
+{
+	/* setup the resume_info struct for the original bootloader */
+	palmz72_resume_info.resume_addr = (u32) pxa_cpu_resume;
+
+	/* Storing memory touched by ROM */
+	store_ptr = *PALMZ72_SAVE_DWORD;
+
+	/* Setting PSPR to a proper value */
+	PSPR = virt_to_phys(&palmz72_resume_info);
+
+	return 0;
+}
+
+static int palmz72_pm_resume(struct sys_device *dev)
+{
+	*PALMZ72_SAVE_DWORD = store_ptr;
+	return 0;
+}
+
+static struct sysdev_class palmz72_pm_sysclass = {
+	.name = "palmz72_pm",
+	.suspend = palmz72_pm_suspend,
+	.resume = palmz72_pm_resume,
+};
+
+static struct sys_device palmz72_pm_device = {
+	.cls = &palmz72_pm_sysclass,
+};
+
+static int __init palmz72_pm_init(void)
+{
+	int ret = -ENODEV;
+	if (machine_is_palmz72()) {
+		ret = sysdev_class_register(&palmz72_pm_sysclass);
+		if (ret == 0)
+			ret = sysdev_register(&palmz72_pm_device);
+	}
+	return ret;
+}
+
+device_initcall(palmz72_pm_init);
+#endif
+
+/******************************************************************************
+ * Machine init
+ ******************************************************************************/
+static struct platform_device *devices[] __initdata = {
+	&palmz72_backlight,
+	&palmz72_leds,
+	&power_supply,
+};
+
+static void __init palmz72_init(void)
+{
+	pxa2xx_mfp_config(ARRAY_AND_SIZE(palmz72_pin_config));
+	set_pxa_fb_info(&palmz72_lcd_screen);
+	pxa_set_mci_info(&palmz72_mci_platform_data);
+	pxa_set_ac97_info(NULL);
+	pxa_set_ficp_info(&palmz72_ficp_platform_data);
+	pxa_set_keypad_info(&palmz72_keypad_platform_data);
+	platform_add_devices(devices, ARRAY_SIZE(devices));
+}
+
+MACHINE_START(PALMZ72, "Palm Zire72")
+	.phys_io	= 0x40000000,
+	.io_pg_offst	= io_p2v(0x40000000),
+	.boot_params	= 0xa0000100,
+	.map_io		= pxa_map_io,
+	.init_irq	= pxa27x_init_irq,
+	.timer		= &pxa_timer,
+	.init_machine	= palmz72_init
+MACHINE_END
diff --git a/arch/arm/mach-pxa/pcm027.c b/arch/arm/mach-pxa/pcm027.c
index 730b9f6..36135a0 100644
--- a/arch/arm/mach-pxa/pcm027.c
+++ b/arch/arm/mach-pxa/pcm027.c
@@ -31,7 +31,7 @@
 #include <asm/mach/arch.h>
 #include <mach/hardware.h>
 #include <mach/pxa-regs.h>
-#include <mach/pxa2xx-gpio.h>
+#include <mach/mfp-pxa27x.h>
 #include <mach/pxa2xx-regs.h>
 #include <mach/pxa2xx_spi.h>
 #include <mach/pcm027.h>
@@ -86,6 +86,28 @@
  * *) CPU internal use only
  */
 
+static unsigned long pcm027_pin_config[] __initdata = {
+	/* Chip Selects */
+	GPIO20_nSDCS_2,
+	GPIO21_nSDCS_3,
+	GPIO15_nCS_1,
+	GPIO78_nCS_2,
+	GPIO80_nCS_4,
+	GPIO33_nCS_5,	/* Ethernet */
+
+	/* I2C */
+	GPIO117_I2C_SCL,
+	GPIO118_I2C_SDA,
+
+	/* GPIO */
+	GPIO52_GPIO,	/* IRQ from network controller */
+#ifdef CONFIG_LEDS_GPIO
+	GPIO90_GPIO,	/* PCM027_LED_CPU */
+	GPIO91_GPIO,	/* PCM027_LED_HEART_BEAT */
+#endif
+	GPIO114_GPIO,	/* IRQ from CAN controller */
+};
+
 /*
  * SMC91x network controller specific stuff
  */
@@ -206,13 +228,9 @@
 	 */
 	ARB_CNTRL = ARB_CORE_PARK | 0x234;
 
-	platform_add_devices(devices, ARRAY_SIZE(devices));
+	pxa2xx_mfp_config(pcm027_pin_config, ARRAY_SIZE(pcm027_pin_config));
 
-	/* LEDs (on demand only) */
-#ifdef CONFIG_LEDS_GPIO
-	pxa_gpio_mode(PCM027_LED_CPU | GPIO_OUT);
-	pxa_gpio_mode(PCM027_LED_HEARD_BEAT | GPIO_OUT);
-#endif /* CONFIG_LEDS_GPIO */
+	platform_add_devices(devices, ARRAY_SIZE(devices));
 
 	/* at last call the baseboard to initialize itself */
 #ifdef CONFIG_MACH_PCM990_BASEBOARD
diff --git a/arch/arm/mach-pxa/pcm990-baseboard.c b/arch/arm/mach-pxa/pcm990-baseboard.c
index 420c9b3..f601425 100644
--- a/arch/arm/mach-pxa/pcm990-baseboard.c
+++ b/arch/arm/mach-pxa/pcm990-baseboard.c
@@ -262,8 +262,7 @@
 					GPIO_bit(PCM990_CTRL_INT_IRQ_GPIO);
 		if (likely(pending)) {
 			irq = PCM027_IRQ(0) + __ffs(pending);
-			desc = irq_desc + irq;
-			desc_handle_irq(irq, desc);
+			generic_handle_irq(irq);
 		}
 		pending = (~PCM990_INTSETCLR) & pcm990_irq_enabled;
 	} while (pending);
@@ -328,36 +327,10 @@
 	.exit		= pcm990_mci_exit,
 };
 
-/*
- * init OHCI hardware to work with
- *
- * Note: Only USB port 1 (host only) is connected
- *
- * GPIO88 (USBHPWR#1): overcurrent in, overcurrent when low
- * GPIO89 (USBHPEN#1): power-on out, on when low
- */
-static int pcm990_ohci_init(struct device *dev)
-{
-	/*
-	 * disable USB port 2 and 3
-	 * power sense is active low
-	 */
-	UHCHR = ((UHCHR) | UHCHR_PCPL | UHCHR_PSPL | UHCHR_SSEP2 |
-				UHCHR_SSEP3) & ~(UHCHR_SSEP1 | UHCHR_SSE);
-	/*
-	 * wait 10ms after Power on
-	 * overcurrent per port
-	 * power switch per port
-	 */
-	UHCRHDA = (5<<24) | (1<<11) | (1<<8);	/* FIXME: Required? */
-
-	return 0;
-}
-
 static struct pxaohci_platform_data pcm990_ohci_platform_data = {
 	.port_mode	= PMM_PERPORT_MODE,
-	.init		= pcm990_ohci_init,
-	.exit		= NULL,
+	.flags		= ENABLE_PORT1 | POWER_CONTROL_LOW | POWER_SENSE_LOW,
+	.power_on_delay	= 10,
 };
 
 /*
diff --git a/arch/arm/mach-pxa/pm.c b/arch/arm/mach-pxa/pm.c
index 1b539e6..164eb0b 100644
--- a/arch/arm/mach-pxa/pm.c
+++ b/arch/arm/mach-pxa/pm.c
@@ -86,9 +86,27 @@
 	return -EINVAL;
 }
 
+static int pxa_pm_prepare(void)
+{
+	int ret = 0;
+
+	if (pxa_cpu_pm_fns && pxa_cpu_pm_fns->prepare)
+		ret = pxa_cpu_pm_fns->prepare();
+
+	return ret;
+}
+
+static void pxa_pm_finish(void)
+{
+	if (pxa_cpu_pm_fns && pxa_cpu_pm_fns->finish)
+		pxa_cpu_pm_fns->finish();
+}
+
 static struct platform_suspend_ops pxa_pm_ops = {
 	.valid		= pxa_pm_valid,
 	.enter		= pxa_pm_enter,
+	.prepare	= pxa_pm_prepare,
+	.finish		= pxa_pm_finish,
 };
 
 static int __init pxa_pm_init(void)
diff --git a/arch/arm/mach-pxa/poodle.c b/arch/arm/mach-pxa/poodle.c
index 3f5f484..2e3bd8b 100644
--- a/arch/arm/mach-pxa/poodle.c
+++ b/arch/arm/mach-pxa/poodle.c
@@ -20,6 +20,9 @@
 #include <linux/fb.h>
 #include <linux/pm.h>
 #include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/ads7846.h>
 
 #include <mach/hardware.h>
 #include <asm/mach-types.h>
@@ -33,7 +36,7 @@
 
 #include <mach/pxa-regs.h>
 #include <mach/pxa2xx-regs.h>
-#include <mach/pxa2xx-gpio.h>
+#include <mach/mfp-pxa25x.h>
 #include <mach/mmc.h>
 #include <mach/udc.h>
 #include <mach/i2c.h>
@@ -42,6 +45,7 @@
 #include <mach/pxafb.h>
 #include <mach/sharpsl.h>
 #include <mach/ssp.h>
+#include <mach/pxa2xx_spi.h>
 
 #include <asm/hardware/scoop.h>
 #include <asm/hardware/locomo.h>
@@ -51,6 +55,88 @@
 #include "devices.h"
 #include "sharpsl.h"
 
+static unsigned long poodle_pin_config[] __initdata = {
+	/* I/O */
+	GPIO79_nCS_3,
+	GPIO80_nCS_4,
+	GPIO18_RDY,
+
+	/* Clock */
+	GPIO12_32KHz,
+
+	/* SSP1 */
+	GPIO23_SSP1_SCLK,
+	GPIO25_SSP1_TXD,
+	GPIO26_SSP1_RXD,
+	GPIO24_GPIO,	/* POODLE_GPIO_TP_CS - SFRM as chip select */
+
+	/* I2S */
+	GPIO28_I2S_BITCLK_OUT,
+	GPIO29_I2S_SDATA_IN,
+	GPIO30_I2S_SDATA_OUT,
+	GPIO31_I2S_SYNC,
+	GPIO32_I2S_SYSCLK,
+
+	/* Infra-Red */
+	GPIO47_FICP_TXD,
+	GPIO46_FICP_RXD,
+
+	/* FFUART */
+	GPIO40_FFUART_DTR,
+	GPIO41_FFUART_RTS,
+	GPIO39_FFUART_TXD,
+	GPIO37_FFUART_DSR,
+	GPIO34_FFUART_RXD,
+	GPIO35_FFUART_CTS,
+
+	/* LCD */
+	GPIO58_LCD_LDD_0,
+	GPIO59_LCD_LDD_1,
+	GPIO60_LCD_LDD_2,
+	GPIO61_LCD_LDD_3,
+	GPIO62_LCD_LDD_4,
+	GPIO63_LCD_LDD_5,
+	GPIO64_LCD_LDD_6,
+	GPIO65_LCD_LDD_7,
+	GPIO66_LCD_LDD_8,
+	GPIO67_LCD_LDD_9,
+	GPIO68_LCD_LDD_10,
+	GPIO69_LCD_LDD_11,
+	GPIO70_LCD_LDD_12,
+	GPIO71_LCD_LDD_13,
+	GPIO72_LCD_LDD_14,
+	GPIO73_LCD_LDD_15,
+	GPIO74_LCD_FCLK,
+	GPIO75_LCD_LCLK,
+	GPIO76_LCD_PCLK,
+	GPIO77_LCD_BIAS,
+
+	/* PC Card */
+	GPIO48_nPOE,
+	GPIO49_nPWE,
+	GPIO50_nPIOR,
+	GPIO51_nPIOW,
+	GPIO52_nPCE_1,
+	GPIO53_nPCE_2,
+	GPIO54_nPSKTSEL,
+	GPIO55_nPREG,
+	GPIO56_nPWAIT,
+	GPIO57_nIOIS16,
+
+	/* MMC */
+	GPIO6_MMC_CLK,
+	GPIO8_MMC_CS0,
+
+	/* GPIO */
+	GPIO9_GPIO,	/* POODLE_GPIO_nSD_DETECT */
+	GPIO7_GPIO,	/* POODLE_GPIO_nSD_WP */
+	GPIO3_GPIO,	/* POODLE_GPIO_SD_PWR */
+	GPIO33_GPIO,	/* POODLE_GPIO_SD_PWR1 */
+
+	GPIO20_GPIO,	/* POODLE_GPIO_USB_PULLUP */
+	GPIO22_GPIO,	/* POODLE_GPIO_IR_ON */
+};
+
 static struct resource poodle_scoop_resources[] = {
 	[0] = {
 		.start		= 0x10800000,
@@ -62,6 +148,7 @@
 static struct scoop_config poodle_scoop_setup = {
 	.io_dir		= POODLE_SCOOP_IO_DIR,
 	.io_out		= POODLE_SCOOP_IO_OUT,
+	.gpio_base	= POODLE_SCOOP_GPIO_BASE,
 };
 
 struct platform_device poodle_scoop_device = {
@@ -74,27 +161,6 @@
 	.resource	= poodle_scoop_resources,
 };
 
-static void poodle_pcmcia_init(void)
-{
-	/* Setup default state of GPIO outputs
-	   before we enable them as outputs. */
-	GPSR(GPIO48_nPOE) = GPIO_bit(GPIO48_nPOE) |
-		GPIO_bit(GPIO49_nPWE) | GPIO_bit(GPIO50_nPIOR) |
-		GPIO_bit(GPIO51_nPIOW) | GPIO_bit(GPIO52_nPCE_1) |
-		GPIO_bit(GPIO53_nPCE_2);
-
-	pxa_gpio_mode(GPIO48_nPOE_MD);
-	pxa_gpio_mode(GPIO49_nPWE_MD);
-	pxa_gpio_mode(GPIO50_nPIOR_MD);
-	pxa_gpio_mode(GPIO51_nPIOW_MD);
-	pxa_gpio_mode(GPIO55_nPREG_MD);
-	pxa_gpio_mode(GPIO56_nPWAIT_MD);
-	pxa_gpio_mode(GPIO57_nIOIS16_MD);
-	pxa_gpio_mode(GPIO52_nPCE_1_MD);
-	pxa_gpio_mode(GPIO53_nPCE_2_MD);
-	pxa_gpio_mode(GPIO54_pSKTSEL_MD);
-}
-
 static struct scoop_pcmcia_dev poodle_pcmcia_scoop[] = {
 {
 	.dev        = &poodle_scoop_device.dev,
@@ -107,7 +173,6 @@
 static struct scoop_pcmcia_config poodle_pcmcia_config = {
 	.devs         = &poodle_pcmcia_scoop[0],
 	.num_devs     = 1,
-	.pcmcia_init  = poodle_pcmcia_init,
 };
 
 EXPORT_SYMBOL(poodle_scoop_device);
@@ -136,62 +201,55 @@
 
 EXPORT_SYMBOL(poodle_locomo_device);
 
-/*
- * Poodle SSP Device
- */
-
-struct platform_device poodle_ssp_device = {
-	.name		= "corgi-ssp",
-	.id		= -1,
+#if defined(CONFIG_SPI_PXA2XX) || defined(CONFIG_SPI_PXA2XX_MODULE)
+static struct pxa2xx_spi_master poodle_spi_info = {
+	.num_chipselect	= 1,
 };
 
-struct corgissp_machinfo poodle_ssp_machinfo = {
-	.port		= 1,
-	.cs_lcdcon	= -1,
-	.cs_ads7846	= -1,
-	.cs_max1111	= -1,
-	.clk_lcdcon	= 2,
-	.clk_ads7846	= 36,
-	.clk_max1111	= 2,
+static struct ads7846_platform_data poodle_ads7846_info = {
+	.model			= 7846,
+	.vref_delay_usecs	= 100,
+	.x_plate_ohms		= 419,
+	.y_plate_ohms		= 486,
+	.gpio_pendown		= POODLE_GPIO_TP_INT,
 };
 
+static void ads7846_cs(u32 command)
+{
+	gpio_set_value(POODLE_GPIO_TP_CS, !(command == PXA2XX_CS_ASSERT));
+}
 
-/*
- * Poodle Touch Screen Device
- */
-static struct resource poodlets_resources[] = {
-	[0] = {
-		.start		= POODLE_IRQ_GPIO_TP_INT,
-		.end		= POODLE_IRQ_GPIO_TP_INT,
-		.flags		= IORESOURCE_IRQ,
+static struct pxa2xx_spi_chip poodle_ads7846_chip = {
+	.cs_control		= ads7846_cs,
+};
+
+static struct spi_board_info poodle_spi_devices[] = {
+	{
+		.modalias	= "ads7846",
+		.max_speed_hz	= 10000,
+		.bus_num	= 1,
+		.platform_data	= &poodle_ads7846_info,
+		.controller_data= &poodle_ads7846_chip,
+		.irq		= gpio_to_irq(POODLE_GPIO_TP_INT),
 	},
 };
 
-static unsigned long poodle_get_hsync_invperiod(void)
+static void __init poodle_init_spi(void)
 {
-	return 0;
+	int err;
+
+	err = gpio_request(POODLE_GPIO_TP_CS, "ADS7846_CS");
+	if (err)
+		return;
+
+	gpio_direction_output(POODLE_GPIO_TP_CS, 1);
+
+	pxa2xx_set_spi_info(1, &poodle_spi_info);
+	spi_register_board_info(ARRAY_AND_SIZE(poodle_spi_devices));
 }
-
-static void poodle_null_hsync(void)
-{
-}
-
-static struct corgits_machinfo  poodle_ts_machinfo = {
-	.get_hsync_invperiod	= poodle_get_hsync_invperiod,
-	.put_hsync       	= poodle_null_hsync,
-	.wait_hsync      	= poodle_null_hsync,
-};
-
-static struct platform_device poodle_ts_device = {
-	.name		= "corgi-ts",
-	.dev		= {
-		.platform_data	= &poodle_ts_machinfo,
-	},
-	.id		= -1,
-	.num_resources	= ARRAY_SIZE(poodlets_resources),
-	.resource	= poodlets_resources,
-};
-
+#else
+static inline void poodle_init_spi(void) {}
+#endif
 
 /*
  * MMC/SD Device
@@ -205,22 +263,50 @@
 {
 	int err;
 
-	/* setup GPIO for PXA25x MMC controller	*/
-	pxa_gpio_mode(GPIO6_MMCCLK_MD);
-	pxa_gpio_mode(GPIO8_MMCCS0_MD);
-	pxa_gpio_mode(POODLE_GPIO_nSD_DETECT | GPIO_IN);
-	pxa_gpio_mode(POODLE_GPIO_nSD_WP | GPIO_IN);
-	pxa_gpio_mode(POODLE_GPIO_SD_PWR | GPIO_OUT);
-	pxa_gpio_mode(POODLE_GPIO_SD_PWR1 | GPIO_OUT);
+	err = gpio_request(POODLE_GPIO_nSD_DETECT, "nSD_DETECT");
+	if (err)
+		goto err_out;
+
+	err = gpio_request(POODLE_GPIO_nSD_WP, "nSD_WP");
+	if (err)
+		goto err_free_1;
+
+	err = gpio_request(POODLE_GPIO_SD_PWR, "SD_PWR");
+	if (err)
+		goto err_free_2;
+
+	err = gpio_request(POODLE_GPIO_SD_PWR1, "SD_PWR1");
+	if (err)
+		goto err_free_3;
+
+	gpio_direction_input(POODLE_GPIO_nSD_DETECT);
+	gpio_direction_input(POODLE_GPIO_nSD_WP);
+
+	gpio_direction_output(POODLE_GPIO_SD_PWR, 0);
+	gpio_direction_output(POODLE_GPIO_SD_PWR1, 0);
 
 	poodle_mci_platform_data.detect_delay = msecs_to_jiffies(250);
 
 	err = request_irq(POODLE_IRQ_GPIO_nSD_DETECT, poodle_detect_int,
 			  IRQF_DISABLED | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
 			  "MMC card detect", data);
-	if (err)
-		printk(KERN_ERR "poodle_mci_init: MMC/SD: can't request MMC card detect IRQ\n");
+	if (err) {
+		pr_err("%s: MMC/SD: can't request MMC card detect IRQ\n",
+				__func__);
+		goto err_free_4;
+	}
 
+	return 0;
+
+err_free_4:
+	gpio_free(POODLE_GPIO_SD_PWR1);
+err_free_3:
+	gpio_free(POODLE_GPIO_SD_PWR);
+err_free_2:
+	gpio_free(POODLE_GPIO_nSD_WP);
+err_free_1:
+	gpio_free(POODLE_GPIO_nSD_DETECT);
+err_out:
 	return err;
 }
 
@@ -228,18 +314,19 @@
 {
 	struct pxamci_platform_data* p_d = dev->platform_data;
 
-	if (( 1 << vdd) & p_d->ocr_mask) {
-		GPSR(POODLE_GPIO_SD_PWR) = GPIO_bit(POODLE_GPIO_SD_PWR);
+	if ((1 << vdd) & p_d->ocr_mask) {
+		gpio_set_value(POODLE_GPIO_SD_PWR, 1);
 		mdelay(2);
-		GPSR(POODLE_GPIO_SD_PWR1) = GPIO_bit(POODLE_GPIO_SD_PWR1);
+		gpio_set_value(POODLE_GPIO_SD_PWR1, 1);
 	} else {
-		GPCR(POODLE_GPIO_SD_PWR1) = GPIO_bit(POODLE_GPIO_SD_PWR1);
-		GPCR(POODLE_GPIO_SD_PWR) = GPIO_bit(POODLE_GPIO_SD_PWR);
+		gpio_set_value(POODLE_GPIO_SD_PWR1, 0);
+		gpio_set_value(POODLE_GPIO_SD_PWR, 0);
 	}
 }
 
 static int poodle_mci_get_ro(struct device *dev)
 {
+	return !!gpio_get_value(POODLE_GPIO_nSD_WP);
 	return GPLR(POODLE_GPIO_nSD_WP) & GPIO_bit(POODLE_GPIO_nSD_WP);
 }
 
@@ -247,6 +334,10 @@
 static void poodle_mci_exit(struct device *dev, void *data)
 {
 	free_irq(POODLE_IRQ_GPIO_nSD_DETECT, data);
+	gpio_free(POODLE_GPIO_SD_PWR1);
+	gpio_free(POODLE_GPIO_SD_PWR);
+	gpio_free(POODLE_GPIO_nSD_WP);
+	gpio_free(POODLE_GPIO_nSD_DETECT);
 }
 
 static struct pxamci_platform_data poodle_mci_platform_data = {
@@ -263,38 +354,41 @@
  */
 static void poodle_irda_transceiver_mode(struct device *dev, int mode)
 {
-	if (mode & IR_OFF) {
-		GPSR(POODLE_GPIO_IR_ON) = GPIO_bit(POODLE_GPIO_IR_ON);
-	} else {
-		GPCR(POODLE_GPIO_IR_ON) = GPIO_bit(POODLE_GPIO_IR_ON);
-	}
+	gpio_set_value(POODLE_GPIO_IR_ON, mode & IR_OFF);
 	pxa2xx_transceiver_mode(dev, mode);
 }
 
+static int poodle_irda_startup(struct device *dev)
+{
+	int err;
+
+	err = gpio_request(POODLE_GPIO_IR_ON, "IR_ON");
+	if (err)
+		return err;
+
+	gpio_direction_output(POODLE_GPIO_IR_ON, 1);
+	return 0;
+}
+
+static void poodle_irda_shutdown(struct device *dev)
+{
+	gpio_free(POODLE_GPIO_IR_ON);
+}
+
 static struct pxaficp_platform_data poodle_ficp_platform_data = {
-	.transceiver_cap  = IR_SIRMODE | IR_OFF,
-	.transceiver_mode = poodle_irda_transceiver_mode,
+	.transceiver_cap	= IR_SIRMODE | IR_OFF,
+	.transceiver_mode	= poodle_irda_transceiver_mode,
+	.startup		= poodle_irda_startup,
+	.shutdown		= poodle_irda_shutdown,
 };
 
 
 /*
  * USB Device Controller
  */
-static void poodle_udc_command(int cmd)
-{
-	switch(cmd)	{
-	case PXA2XX_UDC_CMD_CONNECT:
-		GPSR(POODLE_GPIO_USB_PULLUP) = GPIO_bit(POODLE_GPIO_USB_PULLUP);
-		break;
-	case PXA2XX_UDC_CMD_DISCONNECT:
-		GPCR(POODLE_GPIO_USB_PULLUP) = GPIO_bit(POODLE_GPIO_USB_PULLUP);
-		break;
-	}
-}
-
 static struct pxa2xx_udc_mach_info udc_info __initdata = {
 	/* no connect GPIO; poodle can't tell connection status */
-	.udc_command		= poodle_udc_command,
+	.gpio_pullup	= POODLE_GPIO_USB_PULLUP,
 };
 
 
@@ -316,15 +410,12 @@
 static struct pxafb_mach_info poodle_fb_info = {
 	.modes		= &poodle_fb_mode,
 	.num_modes	= 1,
-	.lccr0		= LCCR0_Act | LCCR0_Sngl | LCCR0_Color,
-	.lccr3		= 0,
+	.lcd_conn	= LCD_COLOR_TFT_16BPP,
 };
 
 static struct platform_device *devices[] __initdata = {
 	&poodle_locomo_device,
 	&poodle_scoop_device,
-	&poodle_ssp_device,
-	&poodle_ts_device,
 };
 
 static void poodle_poweroff(void)
@@ -344,59 +435,23 @@
 	pm_power_off = poodle_poweroff;
 	arm_pm_restart = poodle_restart;
 
-	/* setup sleep mode values */
-	PWER  = 0x00000002;
-	PFER  = 0x00000000;
-	PRER  = 0x00000002;
-	PGSR0 = 0x00008000;
-	PGSR1 = 0x003F0202;
-	PGSR2 = 0x0001C000;
 	PCFR |= PCFR_OPDE;
 
-	/* cpu initialize */
-	/* Pgsr Register */
-  	PGSR0 = 0x0146dd80;
-  	PGSR1 = 0x03bf0890;
-  	PGSR2 = 0x0001c000;
-
-	/* Alternate Register */
-  	GAFR0_L = 0x01001000;
-  	GAFR0_U = 0x591a8010;
-  	GAFR1_L = 0x900a8451;
-  	GAFR1_U = 0xaaa5aaaa;
-  	GAFR2_L = 0x8aaaaaaa;
-  	GAFR2_U = 0x00000002;
-
-	/* Direction Register */
-  	GPDR0 = 0xd3f0904c;
-  	GPDR1 = 0xfcffb7d3;
-  	GPDR2 = 0x0001ffff;
-
-	/* Output Register */
-  	GPCR0 = 0x00000000;
-  	GPCR1 = 0x00000000;
-  	GPCR2 = 0x00000000;
-
-  	GPSR0 = 0x00400000;
-  	GPSR1 = 0x00000000;
-        GPSR2 = 0x00000000;
-
-	set_pxa_fb_parent(&poodle_locomo_device.dev);
-	set_pxa_fb_info(&poodle_fb_info);
-	pxa_gpio_mode(POODLE_GPIO_USB_PULLUP | GPIO_OUT);
-	pxa_gpio_mode(POODLE_GPIO_IR_ON | GPIO_OUT);
-	pxa_set_udc_info(&udc_info);
-	pxa_set_mci_info(&poodle_mci_platform_data);
-	pxa_set_ficp_info(&poodle_ficp_platform_data);
-	pxa_set_i2c_info(NULL);
+	pxa2xx_mfp_config(ARRAY_AND_SIZE(poodle_pin_config));
 
 	platform_scoop_config = &poodle_pcmcia_config;
 
 	ret = platform_add_devices(devices, ARRAY_SIZE(devices));
-	if (ret) {
-		printk(KERN_WARNING "poodle: Unable to register LoCoMo device\n");
-	}
-	corgi_ssp_set_machinfo(&poodle_ssp_machinfo);
+	if (ret)
+		pr_warning("poodle: Unable to register LoCoMo device\n");
+
+	set_pxa_fb_parent(&poodle_locomo_device.dev);
+	set_pxa_fb_info(&poodle_fb_info);
+	pxa_set_udc_info(&udc_info);
+	pxa_set_mci_info(&poodle_mci_platform_data);
+	pxa_set_ficp_info(&poodle_ficp_platform_data);
+	pxa_set_i2c_info(NULL);
+	poodle_init_spi();
 }
 
 static void __init fixup_poodle(struct machine_desc *desc,
diff --git a/arch/arm/mach-pxa/pxa25x.c b/arch/arm/mach-pxa/pxa25x.c
index 305452b..25d17a1 100644
--- a/arch/arm/mach-pxa/pxa25x.c
+++ b/arch/arm/mach-pxa/pxa25x.c
@@ -36,6 +36,12 @@
 #include "devices.h"
 #include "clock.h"
 
+int cpu_is_pxa26x(void)
+{
+	return cpu_is_pxa250() && ((BOOT_DEF & 0x8) == 0);
+}
+EXPORT_SYMBOL_GPL(cpu_is_pxa26x);
+
 /*
  * Various clock factors driven by the CCCR register.
  */
@@ -203,48 +209,21 @@
  * More ones like CP and general purpose register values are preserved
  * with the stack pointer in sleep.S.
  */
-enum {	SLEEP_SAVE_PGSR0, SLEEP_SAVE_PGSR1, SLEEP_SAVE_PGSR2,
-
-	SLEEP_SAVE_GAFR0_L, SLEEP_SAVE_GAFR0_U,
-	SLEEP_SAVE_GAFR1_L, SLEEP_SAVE_GAFR1_U,
-	SLEEP_SAVE_GAFR2_L, SLEEP_SAVE_GAFR2_U,
-
+enum {
 	SLEEP_SAVE_PSTR,
-
 	SLEEP_SAVE_CKEN,
-
 	SLEEP_SAVE_COUNT
 };
 
 
 static void pxa25x_cpu_pm_save(unsigned long *sleep_save)
 {
-	SAVE(PGSR0); SAVE(PGSR1); SAVE(PGSR2);
-
-	SAVE(GAFR0_L); SAVE(GAFR0_U);
-	SAVE(GAFR1_L); SAVE(GAFR1_U);
-	SAVE(GAFR2_L); SAVE(GAFR2_U);
-
 	SAVE(CKEN);
 	SAVE(PSTR);
-
-	/* Clear GPIO transition detect bits */
-	GEDR0 = GEDR0; GEDR1 = GEDR1; GEDR2 = GEDR2;
 }
 
 static void pxa25x_cpu_pm_restore(unsigned long *sleep_save)
 {
-	/* ensure not to come back here if it wasn't intended */
-	PSPR = 0;
-
-	/* restore registers */
-	RESTORE(GAFR0_L); RESTORE(GAFR0_U);
-	RESTORE(GAFR1_L); RESTORE(GAFR1_U);
-	RESTORE(GAFR2_L); RESTORE(GAFR2_U);
-	RESTORE(PGSR0); RESTORE(PGSR1); RESTORE(PGSR2);
-
-	PSSR = PSSR_RDH | PSSR_PH;
-
 	RESTORE(CKEN);
 	RESTORE(PSTR);
 }
@@ -256,19 +235,32 @@
 
 	switch (state) {
 	case PM_SUSPEND_MEM:
-		/* set resume return address */
-		PSPR = virt_to_phys(pxa_cpu_resume);
 		pxa25x_cpu_suspend(PWRMODE_SLEEP);
 		break;
 	}
 }
 
+static int pxa25x_cpu_pm_prepare(void)
+{
+	/* set resume return address */
+	PSPR = virt_to_phys(pxa_cpu_resume);
+	return 0;
+}
+
+static void pxa25x_cpu_pm_finish(void)
+{
+	/* ensure not to come back here if it wasn't intended */
+	PSPR = 0;
+}
+
 static struct pxa_cpu_pm_fns pxa25x_cpu_pm_fns = {
 	.save_count	= SLEEP_SAVE_COUNT,
 	.valid		= suspend_valid_only_mem,
 	.save		= pxa25x_cpu_pm_save,
 	.restore	= pxa25x_cpu_pm_restore,
 	.enter		= pxa25x_cpu_pm_enter,
+	.prepare	= pxa25x_cpu_pm_prepare,
+	.finish		= pxa25x_cpu_pm_finish,
 };
 
 static void __init pxa25x_init_pm(void)
@@ -330,6 +322,8 @@
 	{
 		.cls	= &pxa_irq_sysclass,
 	}, {
+		.cls	= &pxa2xx_mfp_sysclass,
+	}, {
 		.cls	= &pxa_gpio_sysclass,
 	},
 };
@@ -338,11 +332,7 @@
 {
 	int i, ret = 0;
 
-	/* Only add HWUART for PXA255/26x; PXA210/250/27x do not have it. */
-	if (cpu_is_pxa255())
-		clks_register(&pxa25x_hwuart_clk, 1);
-
-	if (cpu_is_pxa21x() || cpu_is_pxa25x()) {
+	if (cpu_is_pxa25x()) {
 
 		reset_status = RCSR;
 
@@ -365,9 +355,11 @@
 			return ret;
 	}
 
-	/* Only add HWUART for PXA255/26x; PXA210/250/27x do not have it. */
-	if (cpu_is_pxa255())
+	/* Only add HWUART for PXA255/26x; PXA210/250 do not have it. */
+	if (cpu_is_pxa255() || cpu_is_pxa26x()) {
+		clks_register(&pxa25x_hwuart_clk, 1);
 		ret = platform_device_register(&pxa_device_hwuart);
+	}
 
 	return ret;
 }
diff --git a/arch/arm/mach-pxa/pxa27x.c b/arch/arm/mach-pxa/pxa27x.c
index f9f6a9c..3e4ab22 100644
--- a/arch/arm/mach-pxa/pxa27x.c
+++ b/arch/arm/mach-pxa/pxa27x.c
@@ -34,6 +34,13 @@
 #include "devices.h"
 #include "clock.h"
 
+void pxa27x_clear_otgph(void)
+{
+	if (cpu_is_pxa27x() && (PSSR & PSSR_OTGPH))
+		PSSR |= PSSR_OTGPH;
+}
+EXPORT_SYMBOL(pxa27x_clear_otgph);
+
 /* Crystal clock: 13MHz */
 #define BASE_CLK	13000000
 
@@ -183,36 +190,18 @@
  * More ones like CP and general purpose register values are preserved
  * with the stack pointer in sleep.S.
  */
-enum {	SLEEP_SAVE_PGSR0, SLEEP_SAVE_PGSR1, SLEEP_SAVE_PGSR2, SLEEP_SAVE_PGSR3,
-
-	SLEEP_SAVE_GAFR0_L, SLEEP_SAVE_GAFR0_U,
-	SLEEP_SAVE_GAFR1_L, SLEEP_SAVE_GAFR1_U,
-	SLEEP_SAVE_GAFR2_L, SLEEP_SAVE_GAFR2_U,
-	SLEEP_SAVE_GAFR3_L, SLEEP_SAVE_GAFR3_U,
-
+enum {
 	SLEEP_SAVE_PSTR,
-
 	SLEEP_SAVE_CKEN,
-
 	SLEEP_SAVE_MDREFR,
-	SLEEP_SAVE_PWER, SLEEP_SAVE_PCFR, SLEEP_SAVE_PRER,
-	SLEEP_SAVE_PFER, SLEEP_SAVE_PKWR,
-
+	SLEEP_SAVE_PCFR,
 	SLEEP_SAVE_COUNT
 };
 
 void pxa27x_cpu_pm_save(unsigned long *sleep_save)
 {
-	SAVE(PGSR0); SAVE(PGSR1); SAVE(PGSR2); SAVE(PGSR3);
-
-	SAVE(GAFR0_L); SAVE(GAFR0_U);
-	SAVE(GAFR1_L); SAVE(GAFR1_U);
-	SAVE(GAFR2_L); SAVE(GAFR2_U);
-	SAVE(GAFR3_L); SAVE(GAFR3_U);
-
 	SAVE(MDREFR);
-	SAVE(PWER); SAVE(PCFR); SAVE(PRER);
-	SAVE(PFER); SAVE(PKWR);
+	SAVE(PCFR);
 
 	SAVE(CKEN);
 	SAVE(PSTR);
@@ -220,24 +209,12 @@
 
 void pxa27x_cpu_pm_restore(unsigned long *sleep_save)
 {
-	/* ensure not to come back here if it wasn't intended */
-	PSPR = 0;
-
-	/* restore registers */
-	RESTORE(GAFR0_L); RESTORE(GAFR0_U);
-	RESTORE(GAFR1_L); RESTORE(GAFR1_U);
-	RESTORE(GAFR2_L); RESTORE(GAFR2_U);
-	RESTORE(GAFR3_L); RESTORE(GAFR3_U);
-	RESTORE(PGSR0); RESTORE(PGSR1); RESTORE(PGSR2); RESTORE(PGSR3);
-
 	RESTORE(MDREFR);
-	RESTORE(PWER); RESTORE(PCFR); RESTORE(PRER);
-	RESTORE(PFER); RESTORE(PKWR);
+	RESTORE(PCFR);
 
 	PSSR = PSSR_RDH | PSSR_PH;
 
 	RESTORE(CKEN);
-
 	RESTORE(PSTR);
 }
 
@@ -259,8 +236,6 @@
 		pxa_cpu_standby();
 		break;
 	case PM_SUSPEND_MEM:
-		/* set resume return address */
-		PSPR = virt_to_phys(pxa_cpu_resume);
 		pxa27x_cpu_suspend(PWRMODE_SLEEP);
 		break;
 	}
@@ -271,12 +246,27 @@
 	return state == PM_SUSPEND_MEM || state == PM_SUSPEND_STANDBY;
 }
 
+static int pxa27x_cpu_pm_prepare(void)
+{
+	/* set resume return address */
+	PSPR = virt_to_phys(pxa_cpu_resume);
+	return 0;
+}
+
+static void pxa27x_cpu_pm_finish(void)
+{
+	/* ensure not to come back here if it wasn't intended */
+	PSPR = 0;
+}
+
 static struct pxa_cpu_pm_fns pxa27x_cpu_pm_fns = {
 	.save_count	= SLEEP_SAVE_COUNT,
 	.save		= pxa27x_cpu_pm_save,
 	.restore	= pxa27x_cpu_pm_restore,
 	.valid		= pxa27x_cpu_pm_valid,
 	.enter		= pxa27x_cpu_pm_enter,
+	.prepare	= pxa27x_cpu_pm_prepare,
+	.finish		= pxa27x_cpu_pm_finish,
 };
 
 static void __init pxa27x_init_pm(void)
@@ -349,7 +339,7 @@
 	.num_resources	= ARRAY_SIZE(i2c_power_resources),
 };
 
-void __init pxa_set_i2c_power_info(struct i2c_pxa_platform_data *info)
+void __init pxa27x_set_i2c_power_info(struct i2c_pxa_platform_data *info)
 {
 	local_irq_disable();
 	PCFR |= PCFR_PI2CEN;
@@ -376,6 +366,8 @@
 	{
 		.cls	= &pxa_irq_sysclass,
 	}, {
+		.cls	= &pxa2xx_mfp_sysclass,
+	}, {
 		.cls	= &pxa_gpio_sysclass,
 	},
 };
diff --git a/arch/arm/mach-pxa/pxa3xx.c b/arch/arm/mach-pxa/pxa3xx.c
index 03cbc381..b3cd5d0 100644
--- a/arch/arm/mach-pxa/pxa3xx.c
+++ b/arch/arm/mach-pxa/pxa3xx.c
@@ -203,6 +203,19 @@
 	.disable	= clk_pout_disable,
 };
 
+static void clk_dummy_enable(struct clk *clk)
+{
+}
+
+static void clk_dummy_disable(struct clk *clk)
+{
+}
+
+static const struct clkops clk_dummy_ops = {
+	.enable		= clk_dummy_enable,
+	.disable	= clk_dummy_disable,
+};
+
 static struct clk pxa3xx_clks[] = {
 	{
 		.name           = "CLK_POUT",
@@ -211,6 +224,13 @@
 		.delay          = 70,
 	},
 
+	/* Power I2C clock is always on */
+	{
+		.name		= "I2CCLK",
+		.ops		= &clk_dummy_ops,
+		.dev		= &pxa3xx_device_i2c_power.dev,
+	},
+
 	PXA3xx_CK("LCDCLK",  LCD,    &clk_pxa3xx_hsio_ops, &pxa_device_fb.dev),
 	PXA3xx_CK("CAMCLK",  CAMERA, &clk_pxa3xx_hsio_ops, NULL),
 	PXA3xx_CK("AC97CLK", AC97,   &clk_pxa3xx_ac97_ops, NULL),
@@ -509,6 +529,30 @@
  * device registration specific to PXA3xx.
  */
 
+static struct resource i2c_power_resources[] = {
+	{
+		.start  = 0x40f500c0,
+		.end    = 0x40f500d3,
+		.flags	= IORESOURCE_MEM,
+	}, {
+		.start	= IRQ_PWRI2C,
+		.end	= IRQ_PWRI2C,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device pxa3xx_device_i2c_power = {
+	.name		= "pxa2xx-i2c",
+	.id		= 1,
+	.resource	= i2c_power_resources,
+	.num_resources	= ARRAY_SIZE(i2c_power_resources),
+};
+
+void __init pxa3xx_set_i2c_power_info(struct i2c_pxa_platform_data *info)
+{
+	pxa3xx_device_i2c_power.dev.platform_data = info;
+}
+
 static struct platform_device *devices[] __initdata = {
 /*	&pxa_device_udc,	The UDC driver is PXA25x only */
 	&pxa_device_ffuart,
@@ -522,6 +566,7 @@
 	&pxa3xx_device_ssp4,
 	&pxa27x_device_pwm0,
 	&pxa27x_device_pwm1,
+	&pxa3xx_device_i2c_power,
 };
 
 static struct sys_device pxa3xx_sysdev[] = {
diff --git a/arch/arm/mach-pxa/reset.c b/arch/arm/mach-pxa/reset.c
index 9996c61..1b2af57 100644
--- a/arch/arm/mach-pxa/reset.c
+++ b/arch/arm/mach-pxa/reset.c
@@ -7,7 +7,7 @@
 #include <linux/module.h>
 #include <linux/delay.h>
 #include <linux/gpio.h>
-#include <asm/io.h>
+#include <linux/io.h>
 #include <asm/proc-fns.h>
 
 #include <mach/pxa-regs.h>
@@ -20,7 +20,7 @@
 
 static int reset_gpio = -1;
 
-int init_gpio_reset(int gpio)
+int init_gpio_reset(int gpio, int output)
 {
 	int rc;
 
@@ -30,9 +30,12 @@
 		goto out;
 	}
 
-	rc = gpio_direction_input(gpio);
+	if (output)
+		rc = gpio_direction_output(gpio, 0);
+	else
+		rc = gpio_direction_input(gpio);
 	if (rc) {
-		printk(KERN_ERR "Can't configure reset_gpio for input\n");
+		printk(KERN_ERR "Can't configure reset_gpio\n");
 		gpio_free(gpio);
 		goto out;
 	}
diff --git a/arch/arm/mach-pxa/sharpsl_pm.c b/arch/arm/mach-pxa/sharpsl_pm.c
index e804ae0..15c2f1a 100644
--- a/arch/arm/mach-pxa/sharpsl_pm.c
+++ b/arch/arm/mach-pxa/sharpsl_pm.c
@@ -116,24 +116,20 @@
 	{   0,   0},
 };
 
-/* MAX1111 Commands */
-#define MAXCTRL_PD0      1u << 0
-#define MAXCTRL_PD1      1u << 1
-#define MAXCTRL_SGL      1u << 2
-#define MAXCTRL_UNI      1u << 3
-#define MAXCTRL_SEL_SH   4
-#define MAXCTRL_STR      1u << 7
-
 /*
  * Read MAX1111 ADC
  */
+extern int max1111_read_channel(int);
+
 int sharpsl_pm_pxa_read_max1111(int channel)
 {
 	if (machine_is_tosa()) // Ugly, better move this function into another module
 	    return 0;
 
-	return corgi_ssp_max1111_get((channel << MAXCTRL_SEL_SH) | MAXCTRL_PD0 | MAXCTRL_PD1
-			| MAXCTRL_SGL | MAXCTRL_UNI | MAXCTRL_STR);
+	/* max1111 accepts channels from 0-3, however,
+	 * it is encoded from 0-7 here in the code.
+	 */
+	return max1111_read_channel(channel >> 1);
 }
 
 void sharpsl_pm_pxa_init(void)
diff --git a/arch/arm/mach-pxa/spitz.c b/arch/arm/mach-pxa/spitz.c
index b569f3b..524f656 100644
--- a/arch/arm/mach-pxa/spitz.c
+++ b/arch/arm/mach-pxa/spitz.c
@@ -19,16 +19,23 @@
 #include <linux/major.h>
 #include <linux/fs.h>
 #include <linux/interrupt.h>
+#include <linux/gpio.h>
+#include <linux/leds.h>
 #include <linux/mmc/host.h>
 #include <linux/pm.h>
 #include <linux/backlight.h>
+#include <linux/io.h>
+#include <linux/i2c.h>
+#include <linux/i2c/pca953x.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/ads7846.h>
+#include <linux/spi/corgi_lcd.h>
 
 #include <asm/setup.h>
 #include <asm/memory.h>
 #include <asm/mach-types.h>
 #include <mach/hardware.h>
 #include <asm/irq.h>
-#include <asm/io.h>
 #include <asm/system.h>
 
 #include <asm/mach/arch.h>
@@ -37,7 +44,7 @@
 
 #include <mach/pxa-regs.h>
 #include <mach/pxa2xx-regs.h>
-#include <mach/pxa2xx-gpio.h>
+#include <mach/mfp-pxa27x.h>
 #include <mach/pxa27x-udc.h>
 #include <mach/reset.h>
 #include <mach/i2c.h>
@@ -46,7 +53,7 @@
 #include <mach/ohci.h>
 #include <mach/udc.h>
 #include <mach/pxafb.h>
-#include <mach/akita.h>
+#include <mach/pxa2xx_spi.h>
 #include <mach/spitz.h>
 #include <mach/sharpsl.h>
 
@@ -57,6 +64,66 @@
 #include "devices.h"
 #include "sharpsl.h"
 
+static unsigned long spitz_pin_config[] __initdata = {
+	/* Chip Selects */
+	GPIO78_nCS_2,	/* SCOOP #2 */
+	GPIO80_nCS_4,	/* SCOOP #1 */
+
+	/* LCD - 16bpp Active TFT */
+	GPIO58_LCD_LDD_0,
+	GPIO59_LCD_LDD_1,
+	GPIO60_LCD_LDD_2,
+	GPIO61_LCD_LDD_3,
+	GPIO62_LCD_LDD_4,
+	GPIO63_LCD_LDD_5,
+	GPIO64_LCD_LDD_6,
+	GPIO65_LCD_LDD_7,
+	GPIO66_LCD_LDD_8,
+	GPIO67_LCD_LDD_9,
+	GPIO68_LCD_LDD_10,
+	GPIO69_LCD_LDD_11,
+	GPIO70_LCD_LDD_12,
+	GPIO71_LCD_LDD_13,
+	GPIO72_LCD_LDD_14,
+	GPIO73_LCD_LDD_15,
+	GPIO74_LCD_FCLK,
+	GPIO75_LCD_LCLK,
+	GPIO76_LCD_PCLK,
+
+	/* PC Card */
+	GPIO48_nPOE,
+	GPIO49_nPWE,
+	GPIO50_nPIOR,
+	GPIO51_nPIOW,
+	GPIO85_nPCE_1,
+	GPIO54_nPCE_2,
+	GPIO79_PSKTSEL,
+	GPIO55_nPREG,
+	GPIO56_nPWAIT,
+	GPIO57_nIOIS16,
+
+	/* MMC */
+	GPIO32_MMC_CLK,
+	GPIO112_MMC_CMD,
+	GPIO92_MMC_DAT_0,
+	GPIO109_MMC_DAT_1,
+	GPIO110_MMC_DAT_2,
+	GPIO111_MMC_DAT_3,
+
+	/* GPIOs */
+	GPIO9_GPIO,	/* SPITZ_GPIO_nSD_DETECT */
+	GPIO81_GPIO,	/* SPITZ_GPIO_nSD_WP */
+	GPIO41_GPIO,	/* SPITZ_GPIO_USB_CONNECT */
+	GPIO37_GPIO,	/* SPITZ_GPIO_USB_HOST */
+	GPIO35_GPIO,	/* SPITZ_GPIO_USB_DEVICE */
+	GPIO22_GPIO,	/* SPITZ_GPIO_HSYNC */
+	GPIO94_GPIO,	/* SPITZ_GPIO_CF_CD */
+	GPIO105_GPIO,	/* SPITZ_GPIO_CF_IRQ */
+	GPIO106_GPIO,	/* SPITZ_GPIO_CF2_IRQ */
+
+	GPIO1_GPIO | WAKEUP_ON_EDGE_RISE,
+};
+
 /*
  * Spitz SCOOP Device #1
  */
@@ -69,10 +136,11 @@
 };
 
 static struct scoop_config spitz_scoop_setup = {
-	.io_dir 	= SPITZ_SCP_IO_DIR,
+	.io_dir		= SPITZ_SCP_IO_DIR,
 	.io_out		= SPITZ_SCP_IO_OUT,
-	.suspend_clr = SPITZ_SCP_SUS_CLR,
-	.suspend_set = SPITZ_SCP_SUS_SET,
+	.suspend_clr	= SPITZ_SCP_SUS_CLR,
+	.suspend_set	= SPITZ_SCP_SUS_SET,
+	.gpio_base	= SPITZ_SCP_GPIO_BASE,
 };
 
 struct platform_device spitzscoop_device = {
@@ -97,10 +165,11 @@
 };
 
 static struct scoop_config spitz_scoop2_setup = {
-	.io_dir 	= SPITZ_SCP2_IO_DIR,
+	.io_dir		= SPITZ_SCP2_IO_DIR,
 	.io_out		= SPITZ_SCP2_IO_OUT,
-	.suspend_clr = SPITZ_SCP2_SUS_CLR,
-	.suspend_set = SPITZ_SCP2_SUS_SET,
+	.suspend_clr	= SPITZ_SCP2_SUS_CLR,
+	.suspend_set	= SPITZ_SCP2_SUS_SET,
+	.gpio_base	= SPITZ_SCP2_GPIO_BASE,
 };
 
 struct platform_device spitzscoop2_device = {
@@ -122,7 +191,7 @@
 	unsigned short cpr = read_scoop_reg(&spitzscoop_device.dev, SCOOP_CPR);
 
 	if (new_cpr & 0x0007) {
-	        set_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_CF_POWER);
+		gpio_set_value(SPITZ_GPIO_CF_POWER, 1);
 		if (!(cpr & 0x0002) && !(cpr & 0x0004))
 		        mdelay(5);
 		if (device == SPITZ_PWR_CF)
@@ -138,34 +207,13 @@
 		if (!(cpr & 0x0002) && !(cpr & 0x0004)) {
 			write_scoop_reg(&spitzscoop_device.dev, SCOOP_CPR, 0x0000);
 		        mdelay(1);
-		        reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_CF_POWER);
+			gpio_set_value(SPITZ_GPIO_CF_POWER, 0);
 		} else {
 		        write_scoop_reg(&spitzscoop_device.dev, SCOOP_CPR, cpr | new_cpr);
 		}
 	}
 }
 
-static void spitz_pcmcia_init(void)
-{
-	/* Setup default state of GPIO outputs
-	   before we enable them as outputs. */
-	GPSR(GPIO48_nPOE) = GPIO_bit(GPIO48_nPOE) |
-		GPIO_bit(GPIO49_nPWE) |	GPIO_bit(GPIO50_nPIOR) |
-		GPIO_bit(GPIO51_nPIOW) | GPIO_bit(GPIO54_nPCE_2);
-	GPSR(GPIO85_nPCE_1) = GPIO_bit(GPIO85_nPCE_1);
-
-	pxa_gpio_mode(GPIO48_nPOE_MD);
-	pxa_gpio_mode(GPIO49_nPWE_MD);
-	pxa_gpio_mode(GPIO50_nPIOR_MD);
-	pxa_gpio_mode(GPIO51_nPIOW_MD);
-	pxa_gpio_mode(GPIO55_nPREG_MD);
-	pxa_gpio_mode(GPIO56_nPWAIT_MD);
-	pxa_gpio_mode(GPIO57_nIOIS16_MD);
-	pxa_gpio_mode(GPIO85_nPCE_1_MD);
-	pxa_gpio_mode(GPIO54_nPCE_2_MD);
-	pxa_gpio_mode(GPIO104_pSKTSEL_MD);
-}
-
 static void spitz_pcmcia_pwr(struct device *scoop, unsigned short cpr, int nr)
 {
 	/* Only need to override behaviour for slot 0 */
@@ -191,71 +239,12 @@
 static struct scoop_pcmcia_config spitz_pcmcia_config = {
 	.devs         = &spitz_pcmcia_scoop[0],
 	.num_devs     = 2,
-	.pcmcia_init  = spitz_pcmcia_init,
 	.power_ctrl   = spitz_pcmcia_pwr,
 };
 
 EXPORT_SYMBOL(spitzscoop_device);
 EXPORT_SYMBOL(spitzscoop2_device);
 
-
-/*
- * Spitz SSP Device
- *
- * Set the parent as the scoop device because a lot of SSP devices
- * also use scoop functions and this makes the power up/down order
- * work correctly.
- */
-struct platform_device spitzssp_device = {
-	.name		= "corgi-ssp",
-	.dev		= {
- 		.parent = &spitzscoop_device.dev,
-	},
-	.id		= -1,
-};
-
-struct corgissp_machinfo spitz_ssp_machinfo = {
-	.port		= 2,
-	.cs_lcdcon	= SPITZ_GPIO_LCDCON_CS,
-	.cs_ads7846	= SPITZ_GPIO_ADS7846_CS,
-	.cs_max1111	= SPITZ_GPIO_MAX1111_CS,
-	.clk_lcdcon	= 520,
-	.clk_ads7846	= 14,
-	.clk_max1111	= 56,
-};
-
-
-/*
- * Spitz Backlight Device
- */
-static void spitz_bl_kick_battery(void)
-{
-	void (*kick_batt)(void);
-
-	kick_batt = symbol_get(sharpsl_battery_kick);
-	if (kick_batt) {
-		kick_batt();
-		symbol_put(sharpsl_battery_kick);
-	}
-}
-
-static struct generic_bl_info spitz_bl_machinfo = {
-	.name = "corgi-bl",
-	.default_intensity = 0x1f,
-	.limit_mask = 0x0b,
-	.max_intensity = 0x2f,
-	.kick_battery = spitz_bl_kick_battery,
-};
-
-static struct platform_device spitzbl_device = {
-	.name		= "generic-bl",
-	.dev		= {
- 		.platform_data	= &spitz_bl_machinfo,
-	},
-	.id		= -1,
-};
-
-
 /*
  * Spitz Keyboard Device
  */
@@ -268,88 +257,151 @@
 /*
  * Spitz LEDs
  */
+static struct gpio_led spitz_gpio_leds[] = {
+	{
+		.name			= "spitz:amber:charge",
+		.default_trigger	= "sharpsl-charge",
+		.gpio			= SPITZ_GPIO_LED_ORANGE,
+	},
+	{
+		.name			= "spitz:green:hddactivity",
+		.default_trigger	= "ide-disk",
+		.gpio			= SPITZ_GPIO_LED_GREEN,
+	},
+};
+
+static struct gpio_led_platform_data spitz_gpio_leds_info = {
+	.leds		= spitz_gpio_leds,
+	.num_leds	= ARRAY_SIZE(spitz_gpio_leds),
+};
+
 static struct platform_device spitzled_device = {
-	.name		= "spitz-led",
+	.name		= "leds-gpio",
 	.id		= -1,
-};
-
-/*
- * Spitz Touch Screen Device
- */
-
-static unsigned long (*get_hsync_invperiod)(struct device *dev);
-
-static void inline sharpsl_wait_sync(int gpio)
-{
-	while((GPLR(gpio) & GPIO_bit(gpio)) == 0);
-	while((GPLR(gpio) & GPIO_bit(gpio)) != 0);
-}
-
-static struct device *spitz_pxafb_dev;
-
-static int is_pxafb_device(struct device * dev, void * data)
-{
-	struct platform_device *pdev = container_of(dev, struct platform_device, dev);
-
-	return (strncmp(pdev->name, "pxa2xx-fb", 9) == 0);
-}
-
-static unsigned long spitz_get_hsync_invperiod(void)
-{
-#ifdef CONFIG_FB_PXA
-	if (!spitz_pxafb_dev) {
-		spitz_pxafb_dev = bus_find_device(&platform_bus_type, NULL, NULL, is_pxafb_device);
-		if (!spitz_pxafb_dev)
-			return 0;
-	}
-	if (!get_hsync_invperiod)
-		get_hsync_invperiod = symbol_get(pxafb_get_hsync_time);
-	if (!get_hsync_invperiod)
-#endif
-		return 0;
-
-	return get_hsync_invperiod(spitz_pxafb_dev);
-}
-
-static void spitz_put_hsync(void)
-{
-	put_device(spitz_pxafb_dev);
-	if (get_hsync_invperiod)
-		symbol_put(pxafb_get_hsync_time);
-	spitz_pxafb_dev = NULL;
-	get_hsync_invperiod = NULL;
-}
-
-static void spitz_wait_hsync(void)
-{
-	sharpsl_wait_sync(SPITZ_GPIO_HSYNC);
-}
-
-static struct resource spitzts_resources[] = {
-	[0] = {
-		.start		= SPITZ_IRQ_GPIO_TP_INT,
-		.end		= SPITZ_IRQ_GPIO_TP_INT,
-		.flags		= IORESOURCE_IRQ,
-	},
-};
-
-static struct corgits_machinfo  spitz_ts_machinfo = {
-	.get_hsync_invperiod = spitz_get_hsync_invperiod,
-	.put_hsync           = spitz_put_hsync,
-	.wait_hsync          = spitz_wait_hsync,
-};
-
-static struct platform_device spitzts_device = {
-	.name		= "corgi-ts",
 	.dev		= {
- 		.parent = &spitzssp_device.dev,
-		.platform_data	= &spitz_ts_machinfo,
+		.platform_data = &spitz_gpio_leds_info,
 	},
-	.id		= -1,
-	.num_resources	= ARRAY_SIZE(spitzts_resources),
-	.resource	= spitzts_resources,
 };
 
+#if defined(CONFIG_SPI_PXA2XX) || defined(CONFIG_SPI_PXA2XX_MODULE)
+static struct pxa2xx_spi_master spitz_spi_info = {
+	.num_chipselect	= 3,
+};
+
+static struct ads7846_platform_data spitz_ads7846_info = {
+	.model			= 7846,
+	.vref_delay_usecs	= 100,
+	.x_plate_ohms		= 419,
+	.y_plate_ohms		= 486,
+	.gpio_pendown		= SPITZ_GPIO_TP_INT,
+};
+
+static void spitz_ads7846_cs(u32 command)
+{
+	gpio_set_value(SPITZ_GPIO_ADS7846_CS, !(command == PXA2XX_CS_ASSERT));
+}
+
+static struct pxa2xx_spi_chip spitz_ads7846_chip = {
+	.cs_control		= spitz_ads7846_cs,
+};
+
+static void spitz_bl_kick_battery(void)
+{
+	void (*kick_batt)(void);
+
+	kick_batt = symbol_get(sharpsl_battery_kick);
+	if (kick_batt) {
+		kick_batt();
+		symbol_put(sharpsl_battery_kick);
+	}
+}
+
+static struct corgi_lcd_platform_data spitz_lcdcon_info = {
+	.init_mode		= CORGI_LCD_MODE_VGA,
+	.max_intensity		= 0x2f,
+	.default_intensity	= 0x1f,
+	.limit_mask		= 0x0b,
+	.gpio_backlight_cont	= SPITZ_GPIO_BACKLIGHT_CONT,
+	.gpio_backlight_on	= SPITZ_GPIO_BACKLIGHT_ON,
+	.kick_battery		= spitz_bl_kick_battery,
+};
+
+static void spitz_lcdcon_cs(u32 command)
+{
+	gpio_set_value(SPITZ_GPIO_LCDCON_CS, !(command == PXA2XX_CS_ASSERT));
+}
+
+static struct pxa2xx_spi_chip spitz_lcdcon_chip = {
+	.cs_control	= spitz_lcdcon_cs,
+};
+
+static void spitz_max1111_cs(u32 command)
+{
+	gpio_set_value(SPITZ_GPIO_MAX1111_CS, !(command == PXA2XX_CS_ASSERT));
+}
+
+static struct pxa2xx_spi_chip spitz_max1111_chip = {
+	.cs_control	= spitz_max1111_cs,
+};
+
+static struct spi_board_info spitz_spi_devices[] = {
+	{
+		.modalias	= "ads7846",
+		.max_speed_hz	= 1200000,
+		.bus_num	= 2,
+		.chip_select	= 0,
+		.platform_data	= &spitz_ads7846_info,
+		.controller_data= &spitz_ads7846_chip,
+		.irq		= gpio_to_irq(SPITZ_GPIO_TP_INT),
+	}, {
+		.modalias	= "corgi-lcd",
+		.max_speed_hz	= 50000,
+		.bus_num	= 2,
+		.chip_select	= 1,
+		.platform_data	= &spitz_lcdcon_info,
+		.controller_data= &spitz_lcdcon_chip,
+	}, {
+		.modalias	= "max1111",
+		.max_speed_hz	= 450000,
+		.bus_num	= 2,
+		.chip_select	= 2,
+		.controller_data= &spitz_max1111_chip,
+	},
+};
+
+static void __init spitz_init_spi(void)
+{
+	int err;
+
+	err = gpio_request(SPITZ_GPIO_ADS7846_CS, "ADS7846_CS");
+	if (err)
+		return;
+
+	err = gpio_request(SPITZ_GPIO_LCDCON_CS, "LCDCON_CS");
+	if (err)
+		goto err_free_1;
+
+	err = gpio_request(SPITZ_GPIO_MAX1111_CS, "MAX1111_CS");
+	if (err)
+		goto err_free_2;
+
+	if (machine_is_akita()) {
+		spitz_lcdcon_info.gpio_backlight_cont = AKITA_GPIO_BACKLIGHT_CONT;
+		spitz_lcdcon_info.gpio_backlight_on = AKITA_GPIO_BACKLIGHT_ON;
+	}
+
+	pxa2xx_set_spi_info(2, &spitz_spi_info);
+	spi_register_board_info(ARRAY_AND_SIZE(spitz_spi_devices));
+	return;
+
+err_free_2:
+	gpio_free(SPITZ_GPIO_LCDCON_CS);
+err_free_1:
+	gpio_free(SPITZ_GPIO_ADS7846_CS);
+}
+#else
+static inline void spitz_init_spi(void) {}
+#endif
 
 /*
  * MMC/SD Device
@@ -364,24 +416,35 @@
 {
 	int err;
 
-	/* setup GPIO for PXA27x MMC controller	*/
-	pxa_gpio_mode(GPIO32_MMCCLK_MD);
-	pxa_gpio_mode(GPIO112_MMCCMD_MD);
-	pxa_gpio_mode(GPIO92_MMCDAT0_MD);
-	pxa_gpio_mode(GPIO109_MMCDAT1_MD);
-	pxa_gpio_mode(GPIO110_MMCDAT2_MD);
-	pxa_gpio_mode(GPIO111_MMCDAT3_MD);
-	pxa_gpio_mode(SPITZ_GPIO_nSD_DETECT | GPIO_IN);
-	pxa_gpio_mode(SPITZ_GPIO_nSD_WP | GPIO_IN);
+	err = gpio_request(SPITZ_GPIO_nSD_DETECT, "nSD_DETECT");
+	if (err)
+		goto err_out;
+
+	err = gpio_request(SPITZ_GPIO_nSD_WP, "nSD_WP");
+	if (err)
+		goto err_free_1;
+
+	gpio_direction_input(SPITZ_GPIO_nSD_DETECT);
+	gpio_direction_input(SPITZ_GPIO_nSD_WP);
 
 	spitz_mci_platform_data.detect_delay = msecs_to_jiffies(250);
 
 	err = request_irq(SPITZ_IRQ_GPIO_nSD_DETECT, spitz_detect_int,
-			  IRQF_DISABLED | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+			  IRQF_DISABLED | IRQF_TRIGGER_RISING |
+			  IRQF_TRIGGER_FALLING,
 			  "MMC card detect", data);
-	if (err)
-		printk(KERN_ERR "spitz_mci_init: MMC/SD: can't request MMC card detect IRQ\n");
+	if (err) {
+		pr_err("%s: MMC/SD: can't request MMC card detect IRQ\n",
+				__func__);
+		goto err_free_2;
+	}
+	return 0;
 
+err_free_2:
+	gpio_free(SPITZ_GPIO_nSD_WP);
+err_free_1:
+	gpio_free(SPITZ_GPIO_nSD_DETECT);
+err_out:
 	return err;
 }
 
@@ -397,12 +460,14 @@
 
 static int spitz_mci_get_ro(struct device *dev)
 {
-	return GPLR(SPITZ_GPIO_nSD_WP) & GPIO_bit(SPITZ_GPIO_nSD_WP);
+	return gpio_get_value(SPITZ_GPIO_nSD_WP);
 }
 
 static void spitz_mci_exit(struct device *dev, void *data)
 {
 	free_irq(SPITZ_IRQ_GPIO_nSD_DETECT, data);
+	gpio_free(SPITZ_GPIO_nSD_WP);
+	gpio_free(SPITZ_GPIO_nSD_DETECT);
 }
 
 static struct pxamci_platform_data spitz_mci_platform_data = {
@@ -419,27 +484,24 @@
  */
 static int spitz_ohci_init(struct device *dev)
 {
-	/* Only Port 2 is connected */
-	pxa_gpio_mode(SPITZ_GPIO_USB_CONNECT | GPIO_IN);
-	pxa_gpio_mode(SPITZ_GPIO_USB_HOST | GPIO_OUT);
-	pxa_gpio_mode(SPITZ_GPIO_USB_DEVICE | GPIO_IN);
+	int err;
 
-	/* Setup USB Port 2 Output Control Register */
+	err = gpio_request(SPITZ_GPIO_USB_HOST, "USB_HOST");
+	if (err)
+		return err;
+
+	/* Only Port 2 is connected
+	 * Setup USB Port 2 Output Control Register
+	 */
 	UP2OCR = UP2OCR_HXS | UP2OCR_HXOE | UP2OCR_DPPDE | UP2OCR_DMPDE;
 
-	GPSR(SPITZ_GPIO_USB_HOST) = GPIO_bit(SPITZ_GPIO_USB_HOST);
-
-	UHCHR = (UHCHR) &
-		~(UHCHR_SSEP1 | UHCHR_SSEP2 | UHCHR_SSEP3 | UHCHR_SSE);
-
-	UHCRHDA |= UHCRHDA_NOCP;
-
-	return 0;
+	return gpio_direction_output(SPITZ_GPIO_USB_HOST, 1);
 }
 
 static struct pxaohci_platform_data spitz_ohci_platform_data = {
 	.port_mode	= PMM_NPS_MODE,
 	.init		= spitz_ohci_init,
+	.flags		= ENABLE_PORT_ALL | NO_OC_PROTECTION,
 	.power_budget	= 150,
 };
 
@@ -447,29 +509,50 @@
 /*
  * Irda
  */
+static int spitz_irda_startup(struct device *dev)
+{
+	int rc;
+
+	rc = gpio_request(SPITZ_GPIO_IR_ON, "IrDA on");
+	if (rc)
+		goto err;
+
+	rc = gpio_direction_output(SPITZ_GPIO_IR_ON, 1);
+	if (rc)
+		goto err_dir;
+
+	return 0;
+
+err_dir:
+	gpio_free(SPITZ_GPIO_IR_ON);
+err:
+	return rc;
+}
+
+static void spitz_irda_shutdown(struct device *dev)
+{
+	gpio_free(SPITZ_GPIO_IR_ON);
+}
+
 static void spitz_irda_transceiver_mode(struct device *dev, int mode)
 {
-	if (mode & IR_OFF)
-		set_scoop_gpio(&spitzscoop2_device.dev, SPITZ_SCP2_IR_ON);
-	else
-		reset_scoop_gpio(&spitzscoop2_device.dev, SPITZ_SCP2_IR_ON);
+	gpio_set_value(SPITZ_GPIO_IR_ON, mode & IR_OFF);
 	pxa2xx_transceiver_mode(dev, mode);
 }
 
 #ifdef CONFIG_MACH_AKITA
 static void akita_irda_transceiver_mode(struct device *dev, int mode)
 {
-	if (mode & IR_OFF)
-		akita_set_ioexp(&akitaioexp_device.dev, AKITA_IOEXP_IR_ON);
-	else
-		akita_reset_ioexp(&akitaioexp_device.dev, AKITA_IOEXP_IR_ON);
+	gpio_set_value(AKITA_GPIO_IR_ON, mode & IR_OFF);
 	pxa2xx_transceiver_mode(dev, mode);
 }
 #endif
 
 static struct pxaficp_platform_data spitz_ficp_platform_data = {
-	.transceiver_cap  = IR_SIRMODE | IR_OFF,
-	.transceiver_mode = spitz_irda_transceiver_mode,
+	.transceiver_cap	= IR_SIRMODE | IR_OFF,
+	.transceiver_mode	= spitz_irda_transceiver_mode,
+	.startup		= spitz_irda_startup,
+	.shutdown		= spitz_irda_shutdown,
 };
 
 
@@ -477,14 +560,6 @@
  * Spitz PXA Framebuffer
  */
 
-static void spitz_lcd_power(int on, struct fb_var_screeninfo *var)
-{
-	if (on)
-		corgi_lcdtg_hw_init(var->xres);
-	else
-		corgi_lcdtg_suspend();
-}
-
 static struct pxafb_mode_info spitz_pxafb_modes[] = {
 {
 	.pixclock       = 19231,
@@ -517,18 +592,13 @@
 	.modes          = &spitz_pxafb_modes[0],
 	.num_modes      = 2,
 	.fixed_modes    = 1,
-	.lccr0          = LCCR0_Color | LCCR0_Sngl | LCCR0_Act | LCCR0_LDDALT | LCCR0_OUC | LCCR0_CMDIM | LCCR0_RDSTM,
-	.lccr3          = LCCR3_PixRsEdg | LCCR3_OutEnH,
-	.pxafb_lcd_power = spitz_lcd_power,
+	.lcd_conn	= LCD_COLOR_TFT_16BPP | LCD_ALTERNATE_MAPPING,
 };
 
 
 static struct platform_device *devices[] __initdata = {
 	&spitzscoop_device,
-	&spitzssp_device,
 	&spitzkbd_device,
-	&spitzts_device,
-	&spitzbl_device,
 	&spitzled_device,
 };
 
@@ -548,63 +618,32 @@
 
 static void __init common_init(void)
 {
-	init_gpio_reset(SPITZ_GPIO_ON_RESET);
+	init_gpio_reset(SPITZ_GPIO_ON_RESET, 1);
 	pm_power_off = spitz_poweroff;
 	arm_pm_restart = spitz_restart;
 
 	PMCR = 0x00;
 
-	/* setup sleep mode values */
-	PWER  = 0x00000002;
-	PFER  = 0x00000000;
-	PRER  = 0x00000002;
-	PGSR0 = 0x0158C000;
-	PGSR1 = 0x00FF0080;
-	PGSR2 = 0x0001C004;
-
 	/* Stop 3.6MHz and drive HIGH to PCMCIA and CS */
 	PCFR |= PCFR_OPDE;
 
-	corgi_ssp_set_machinfo(&spitz_ssp_machinfo);
+	pxa2xx_mfp_config(ARRAY_AND_SIZE(spitz_pin_config));
 
-	pxa_gpio_mode(SPITZ_GPIO_HSYNC | GPIO_IN);
+	spitz_init_spi();
 
 	platform_add_devices(devices, ARRAY_SIZE(devices));
 	pxa_set_mci_info(&spitz_mci_platform_data);
 	pxa_set_ohci_info(&spitz_ohci_platform_data);
 	pxa_set_ficp_info(&spitz_ficp_platform_data);
-	set_pxa_fb_parent(&spitzssp_device.dev);
 	set_pxa_fb_info(&spitz_pxafb_info);
 	pxa_set_i2c_info(NULL);
 }
 
 #if defined(CONFIG_MACH_SPITZ) || defined(CONFIG_MACH_BORZOI)
-static void spitz_bl_set_intensity(int intensity)
-{
-	if (intensity > 0x10)
-		intensity += 0x10;
-
-	/* Bits 0-4 are accessed via the SSP interface */
-	corgi_ssp_blduty_set(intensity & 0x1f);
-
-	/* Bit 5 is via SCOOP */
-	if (intensity & 0x0020)
-		reset_scoop_gpio(&spitzscoop2_device.dev, SPITZ_SCP2_BACKLIGHT_CONT);
-	else
-		set_scoop_gpio(&spitzscoop2_device.dev, SPITZ_SCP2_BACKLIGHT_CONT);
-
-	if (intensity)
-		set_scoop_gpio(&spitzscoop2_device.dev, SPITZ_SCP2_BACKLIGHT_ON);
-	else
-		reset_scoop_gpio(&spitzscoop2_device.dev, SPITZ_SCP2_BACKLIGHT_ON);
-}
-
 static void __init spitz_init(void)
 {
 	platform_scoop_config = &spitz_pcmcia_config;
 
-	spitz_bl_machinfo.set_bl_intensity = spitz_bl_set_intensity;
-
 	common_init();
 
 	platform_device_register(&spitzscoop2_device);
@@ -615,32 +654,17 @@
 /*
  * Akita IO Expander
  */
-struct platform_device akitaioexp_device = {
-	.name		= "akita-ioexp",
-	.id		= -1,
+static struct pca953x_platform_data akita_ioexp = {
+	.gpio_base		= AKITA_IOEXP_GPIO_BASE,
 };
 
-EXPORT_SYMBOL_GPL(akitaioexp_device);
-
-static void akita_bl_set_intensity(int intensity)
-{
-	if (intensity > 0x10)
-		intensity += 0x10;
-
-	/* Bits 0-4 are accessed via the SSP interface */
-	corgi_ssp_blduty_set(intensity & 0x1f);
-
-	/* Bit 5 is via IO-Expander */
-	if (intensity & 0x0020)
-		akita_reset_ioexp(&akitaioexp_device.dev, AKITA_IOEXP_BACKLIGHT_CONT);
-	else
-		akita_set_ioexp(&akitaioexp_device.dev, AKITA_IOEXP_BACKLIGHT_CONT);
-
-	if (intensity)
-		akita_set_ioexp(&akitaioexp_device.dev, AKITA_IOEXP_BACKLIGHT_ON);
-	else
-		akita_reset_ioexp(&akitaioexp_device.dev, AKITA_IOEXP_BACKLIGHT_ON);
-}
+static struct i2c_board_info akita_i2c_board_info[] = {
+	{
+		.type		= "max7310",
+		.addr		= 0x18,
+		.platform_data	= &akita_ioexp,
+	},
+};
 
 static void __init akita_init(void)
 {
@@ -649,11 +673,10 @@
 	/* We just pretend the second element of the array doesn't exist */
 	spitz_pcmcia_config.num_devs = 1;
 	platform_scoop_config = &spitz_pcmcia_config;
-	spitz_bl_machinfo.set_bl_intensity = akita_bl_set_intensity;
 
-	platform_device_register(&akitaioexp_device);
+	pxa_set_i2c_info(NULL);
+	i2c_register_board_info(0, ARRAY_AND_SIZE(akita_i2c_board_info));
 
-	spitzscoop_device.dev.parent = &akitaioexp_device.dev;
 	common_init();
 }
 #endif
diff --git a/arch/arm/mach-pxa/spitz_pm.c b/arch/arm/mach-pxa/spitz_pm.c
index 8a40505..53018db 100644
--- a/arch/arm/mach-pxa/spitz_pm.c
+++ b/arch/arm/mach-pxa/spitz_pm.c
@@ -21,7 +21,6 @@
 #include <asm/irq.h>
 #include <asm/mach-types.h>
 #include <mach/hardware.h>
-#include <asm/hardware/scoop.h>
 
 #include <mach/sharpsl.h>
 #include <mach/spitz.h>
@@ -48,44 +47,35 @@
 
 static void spitz_measure_temp(int on)
 {
-	if (on)
-		set_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_ADC_TEMP_ON);
-	else
-		reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_ADC_TEMP_ON);
+	gpio_set_value(SPITZ_GPIO_ADC_TEMP_ON, on);
 }
 
 static void spitz_charge(int on)
 {
 	if (on) {
 		if (sharpsl_pm.flags & SHARPSL_SUSPENDED) {
-			set_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_JK_B);
-			reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_CHRG_ON);
+			gpio_set_value(SPITZ_GPIO_JK_B, 1);
+			gpio_set_value(SPITZ_GPIO_CHRG_ON, 0);
 		} else {
-			reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_JK_B);
-			reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_CHRG_ON);
+			gpio_set_value(SPITZ_GPIO_JK_B, 0);
+			gpio_set_value(SPITZ_GPIO_CHRG_ON, 0);
 		}
 	} else {
-		reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_JK_B);
-		set_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_CHRG_ON);
+		gpio_set_value(SPITZ_GPIO_JK_B, 0);
+		gpio_set_value(SPITZ_GPIO_CHRG_ON, 1);
 	}
 }
 
 static void spitz_discharge(int on)
 {
-	if (on)
-		set_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_JK_A);
-	else
-		reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_JK_A);
+	gpio_set_value(SPITZ_GPIO_JK_A, on);
 }
 
 /* HACK - For unknown reasons, accurate voltage readings are only made with a load
    on the power bus which the green led on spitz provides */
 static void spitz_discharge1(int on)
 {
-	if (on)
-		set_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_LED_GREEN);
-	else
-		reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_LED_GREEN);
+	gpio_set_value(SPITZ_GPIO_LED_GREEN, on);
 }
 
 static void spitz_presuspend(void)
diff --git a/arch/arm/mach-pxa/ssp.c b/arch/arm/mach-pxa/ssp.c
index 9bd93c5..2c31ec7 100644
--- a/arch/arm/mach-pxa/ssp.c
+++ b/arch/arm/mach-pxa/ssp.c
@@ -28,8 +28,8 @@
 #include <linux/clk.h>
 #include <linux/err.h>
 #include <linux/platform_device.h>
+#include <linux/io.h>
 
-#include <asm/io.h>
 #include <asm/irq.h>
 #include <mach/hardware.h>
 #include <mach/ssp.h>
diff --git a/arch/arm/mach-pxa/time.c b/arch/arm/mach-pxa/time.c
index 67e1850..f8a9a62 100644
--- a/arch/arm/mach-pxa/time.c
+++ b/arch/arm/mach-pxa/time.c
@@ -17,9 +17,9 @@
 #include <linux/interrupt.h>
 #include <linux/clockchips.h>
 #include <linux/sched.h>
+#include <linux/cnt32_to_63.h>
 
 #include <asm/div64.h>
-#include <asm/cnt32_to_63.h>
 #include <asm/mach/irq.h>
 #include <asm/mach/time.h>
 #include <mach/pxa-regs.h>
@@ -155,7 +155,7 @@
 	OIER = 0;
 	OSSR = OSSR_M0 | OSSR_M1 | OSSR_M2 | OSSR_M3;
 
-	if (cpu_is_pxa21x() || cpu_is_pxa25x())
+	if (cpu_is_pxa25x())
 		clock_tick_rate = 3686400;
 	else if (machine_is_mainstone())
 		clock_tick_rate = 3249600;
diff --git a/arch/arm/mach-pxa/tosa.c b/arch/arm/mach-pxa/tosa.c
index 9f3ef9e..130e37e 100644
--- a/arch/arm/mach-pxa/tosa.c
+++ b/arch/arm/mach-pxa/tosa.c
@@ -781,7 +781,7 @@
 	gpio_set_wake(MFP_PIN_GPIO1, 1);
 	/* We can't pass to gpio-keys since it will drop the Reset altfunc */
 
-	init_gpio_reset(TOSA_GPIO_ON_RESET);
+	init_gpio_reset(TOSA_GPIO_ON_RESET, 0);
 
 	pm_power_off = tosa_poweroff;
 	arm_pm_restart = tosa_restart;
diff --git a/arch/arm/mach-pxa/trizeps4.c b/arch/arm/mach-pxa/trizeps4.c
index 3ed757e..a13dbf3 100644
--- a/arch/arm/mach-pxa/trizeps4.c
+++ b/arch/arm/mach-pxa/trizeps4.c
@@ -22,8 +22,8 @@
 #include <linux/fb.h>
 #include <linux/ioport.h>
 #include <linux/delay.h>
-#include <linux/serial_8250.h>
-#include <linux/mtd/mtd.h>
+#include <linux/gpio.h>
+#include <linux/dm9000.h>
 #include <linux/mtd/physmap.h>
 #include <linux/mtd/partitions.h>
 
@@ -31,7 +31,6 @@
 #include <asm/setup.h>
 #include <asm/memory.h>
 #include <asm/mach-types.h>
-#include <mach/hardware.h>
 #include <asm/irq.h>
 #include <asm/sizes.h>
 
@@ -40,41 +39,148 @@
 #include <asm/mach/irq.h>
 #include <asm/mach/flash.h>
 
+#include <mach/hardware.h>
 #include <mach/pxa-regs.h>
 #include <mach/pxa2xx-regs.h>
-#include <mach/pxa2xx-gpio.h>
+#include <mach/mfp-pxa27x.h>
+#include <mach/pxa2xx_spi.h>
 #include <mach/trizeps4.h>
 #include <mach/audio.h>
 #include <mach/pxafb.h>
 #include <mach/mmc.h>
 #include <mach/irda.h>
 #include <mach/ohci.h>
+#include <mach/i2c.h>
 
 #include "generic.h"
 #include "devices.h"
 
-/********************************************************************************************
+/*	comment out the following line if you want to use the
+ *	Standard UART from PXA for serial / irda transmission
+ *	and acivate it if you have status leds connected */
+#define STATUS_LEDS_ON_STUART_PINS 1
+
+/*****************************************************************************
+ * MultiFunctionPins of CPU
+ *****************************************************************************/
+static unsigned long trizeps4_pin_config[] __initdata = {
+	/* Chip Selects */
+	GPIO15_nCS_1,		/* DiskOnChip CS */
+	GPIO93_GPIO,		/* TRIZEPS4_DOC_IRQ */
+	GPIO94_GPIO,		/* DOC lock */
+
+	GPIO78_nCS_2,		/* DM9000 CS */
+	GPIO101_GPIO,		/* TRIZEPS4_ETH_IRQ */
+
+	GPIO79_nCS_3,		/* Logic CS */
+	GPIO0_GPIO | WAKEUP_ON_EDGE_RISE,	/* Logic irq */
+
+	/* LCD - 16bpp Active TFT */
+	GPIO58_LCD_LDD_0,
+	GPIO59_LCD_LDD_1,
+	GPIO60_LCD_LDD_2,
+	GPIO61_LCD_LDD_3,
+	GPIO62_LCD_LDD_4,
+	GPIO63_LCD_LDD_5,
+	GPIO64_LCD_LDD_6,
+	GPIO65_LCD_LDD_7,
+	GPIO66_LCD_LDD_8,
+	GPIO67_LCD_LDD_9,
+	GPIO68_LCD_LDD_10,
+	GPIO69_LCD_LDD_11,
+	GPIO70_LCD_LDD_12,
+	GPIO71_LCD_LDD_13,
+	GPIO72_LCD_LDD_14,
+	GPIO73_LCD_LDD_15,
+	GPIO74_LCD_FCLK,
+	GPIO75_LCD_LCLK,
+	GPIO76_LCD_PCLK,
+	GPIO77_LCD_BIAS,
+
+	/* UART */
+	GPIO9_FFUART_CTS,
+	GPIO10_FFUART_DCD,
+	GPIO16_FFUART_TXD,
+	GPIO33_FFUART_DSR,
+	GPIO38_FFUART_RI,
+	GPIO82_FFUART_DTR,
+	GPIO83_FFUART_RTS,
+	GPIO96_FFUART_RXD,
+
+	GPIO42_BTUART_RXD,
+	GPIO43_BTUART_TXD,
+	GPIO44_BTUART_CTS,
+	GPIO45_BTUART_RTS,
+#ifdef STATUS_LEDS_ON_STUART_PINS
+	GPIO46_GPIO,
+	GPIO47_GPIO,
+#else
+	GPIO46_STUART_RXD,
+	GPIO47_STUART_TXD,
+#endif
+	/* PCMCIA */
+	GPIO11_GPIO,			/* TRIZEPS4_CD_IRQ */
+	GPIO13_GPIO,			/* TRIZEPS4_READY_NINT */
+	GPIO48_nPOE,
+	GPIO49_nPWE,
+	GPIO50_nPIOR,
+	GPIO51_nPIOW,
+	GPIO54_nPCE_2,
+	GPIO55_nPREG,
+	GPIO56_nPWAIT,
+	GPIO57_nIOIS16,
+	GPIO102_nPCE_1,
+	GPIO104_PSKTSEL,
+
+	/* MultiMediaCard */
+	GPIO32_MMC_CLK,
+	GPIO92_MMC_DAT_0,
+	GPIO109_MMC_DAT_1,
+	GPIO110_MMC_DAT_2,
+	GPIO111_MMC_DAT_3,
+	GPIO112_MMC_CMD,
+	GPIO12_GPIO,			/* TRIZEPS4_MMC_IRQ */
+
+	/* USB OHCI */
+	GPIO88_USBH1_PWR,		/* USBHPWR1 */
+	GPIO89_USBH1_PEN,		/* USBHPEN1 */
+
+	/* I2C */
+	GPIO117_I2C_SCL,
+	GPIO118_I2C_SDA,
+};
+
+static unsigned long trizeps4wl_pin_config[] __initdata = {
+	/* SSP 2 */
+	GPIO14_SSP2_SFRM,
+	GPIO19_SSP2_SCLK,
+	GPIO53_GPIO,			/* TRIZEPS4_SPI_IRQ */
+	GPIO86_SSP2_RXD,
+	GPIO87_SSP2_TXD,
+};
+
+/****************************************************************************
  * ONBOARD FLASH
- ********************************************************************************************/
+ ****************************************************************************/
 static struct mtd_partition trizeps4_partitions[] = {
 	{
 		.name =		"Bootloader",
 		.offset =	0x00000000,
 		.size =		0x00040000,
 		.mask_flags =	MTD_WRITEABLE  /* force read-only */
-	},{
+	}, {
 		.name =		"Backup",
 		.offset =	0x00040000,
 		.size =		0x00040000,
-	},{
+	}, {
 		.name =		"Image",
 		.offset =	0x00080000,
 		.size =		0x01080000,
-	},{
+	}, {
 		.name =		"IPSM",
 		.offset =	0x01100000,
 		.size =		0x00e00000,
-	},{
+	}, {
 		.name =		"Registry",
 		.offset =	0x01f00000,
 		.size =		MTDPART_SIZ_FULL,
@@ -105,9 +211,9 @@
 	.num_resources = 1,
 };
 
-/********************************************************************************************
+/****************************************************************************
  * DAVICOM DM9000 Ethernet
- ********************************************************************************************/
+ ****************************************************************************/
 static struct resource dm9000_resources[] = {
 	[0] = {
 		.start	= TRIZEPS4_ETH_PHYS+0x300,
@@ -122,67 +228,68 @@
 	[2] = {
 		.start	= TRIZEPS4_ETH_IRQ,
 		.end	= TRIZEPS4_ETH_IRQ,
-		.flags	= (IORESOURCE_IRQ | IRQ_TYPE_EDGE_RISING),
+		.flags	= IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE,
 	},
 };
 
+static struct dm9000_plat_data tri_dm9000_platdata = {
+	.flags		= DM9000_PLATF_32BITONLY,
+};
+
 static struct platform_device dm9000_device = {
 	.name		= "dm9000",
 	.id		= -1,
 	.num_resources	= ARRAY_SIZE(dm9000_resources),
 	.resource	= dm9000_resources,
+	.dev		= {
+		.platform_data = &tri_dm9000_platdata,
+	}
 };
 
-/********************************************************************************************
- * PXA270 serial ports
- ********************************************************************************************/
-static struct plat_serial8250_port tri_serial_ports[] = {
-#ifdef CONFIG_SERIAL_PXA
-	/* this uses the own PXA driver */
+/****************************************************************************
+ * LED's on GPIO pins of PXA
+ ****************************************************************************/
+static struct gpio_led trizeps4_led[] = {
+#ifdef STATUS_LEDS_ON_STUART_PINS
 	{
-		0,
-	},
-#else
-	/* this uses the generic 8520 driver */
-	[0] = {
-		.membase	= (void *)&FFUART,
-		.irq		= IRQ_FFUART,
-		.flags		= UPF_BOOT_AUTOCONF,
-		.iotype		= UPIO_MEM32,
-		.regshift	= 2,
-		.uartclk	= (921600*16),
-	},
-	[1] = {
-		.membase	= (void *)&BTUART,
-		.irq		= IRQ_BTUART,
-		.flags		= UPF_BOOT_AUTOCONF,
-		.iotype		= UPIO_MEM32,
-		.regshift	= 2,
-		.uartclk	= (921600*16),
+		.name = "led0:orange:heartbeat",	/* */
+		.default_trigger = "heartbeat",
+		.gpio = GPIO_HEARTBEAT_LED,
+		.active_low = 1,
 	},
 	{
-		0,
+		.name = "led1:yellow:cpubusy",		/* */
+		.default_trigger = "cpu-busy",
+		.gpio = GPIO_SYS_BUSY_LED,
+		.active_low = 1,
 	},
 #endif
 };
 
-static struct platform_device uart_devices = {
-	.name		= "serial8250",
-	.id		= 0,
+static struct gpio_led_platform_data trizeps4_led_data = {
+	.leds		= trizeps4_led,
+	.num_leds	= ARRAY_SIZE(trizeps4_led),
+};
+
+static struct platform_device leds_devices = {
+	.name		= "leds-gpio",
+	.id		= -1,
 	.dev		= {
-		.platform_data	= tri_serial_ports,
+		.platform_data	= &trizeps4_led_data,
 	},
-	.num_resources	= 0,
-	.resource	= NULL,
 };
 
-static struct platform_device * trizeps4_devices[] __initdata = {
+static struct platform_device *trizeps4_devices[] __initdata = {
 	&flash_device,
-	&uart_devices,
 	&dm9000_device,
+	&leds_devices,
 };
 
-#ifdef CONFIG_MACH_TRIZEPS4_CONXS
+static struct platform_device *trizeps4wl_devices[] __initdata = {
+	&flash_device,
+	&leds_devices,
+};
+
 static short trizeps_conxs_bcr;
 
 /* PCCARD power switching supports only 3,3V */
@@ -192,108 +299,63 @@
 		/* switch power on, put in reset and enable buffers */
 		trizeps_conxs_bcr |= power;
 		trizeps_conxs_bcr |= ConXS_BCR_CF_RESET;
-		trizeps_conxs_bcr &= ~(ConXS_BCR_CF_BUF_EN);
-		ConXS_BCR = trizeps_conxs_bcr;
+		trizeps_conxs_bcr &= ~ConXS_BCR_CF_BUF_EN;
+		BCR_writew(trizeps_conxs_bcr);
 		/* wait a little */
 		udelay(2000);
 		/* take reset away */
-		trizeps_conxs_bcr &= ~(ConXS_BCR_CF_RESET);
-		ConXS_BCR = trizeps_conxs_bcr;
+		trizeps_conxs_bcr &= ~ConXS_BCR_CF_RESET;
+		BCR_writew(trizeps_conxs_bcr);
 		udelay(2000);
 	} else {
 		/* put in reset */
 		trizeps_conxs_bcr |= ConXS_BCR_CF_RESET;
-		ConXS_BCR = trizeps_conxs_bcr;
+		BCR_writew(trizeps_conxs_bcr);
 		udelay(1000);
 		/* switch power off */
-		trizeps_conxs_bcr &= ~(0xf);
-		ConXS_BCR = trizeps_conxs_bcr;
-
+		trizeps_conxs_bcr &= ~0xf;
+		BCR_writew(trizeps_conxs_bcr);
 	}
-	pr_debug("%s: o%s 0x%x\n", __func__, power ? "n": "ff", trizeps_conxs_bcr);
+	pr_debug("%s: o%s 0x%x\n", __func__, power ? "n" : "ff",
+			trizeps_conxs_bcr);
 }
+EXPORT_SYMBOL(board_pcmcia_power);
 
 /* backlight power switching for LCD panel */
 static void board_backlight_power(int on)
 {
-	if (on) {
+	if (on)
 		trizeps_conxs_bcr |= ConXS_BCR_L_DISP;
-	} else {
+	else
 		trizeps_conxs_bcr &= ~ConXS_BCR_L_DISP;
-	}
-	pr_debug("%s: o%s 0x%x\n", __func__, on ? "n" : "ff", trizeps_conxs_bcr);
-	ConXS_BCR = trizeps_conxs_bcr;
+
+	pr_debug("%s: o%s 0x%x\n", __func__, on ? "n" : "ff",
+			trizeps_conxs_bcr);
+	BCR_writew(trizeps_conxs_bcr);
 }
 
-/* Powersupply for MMC/SD cardslot */
-static void board_mci_power(struct device *dev, unsigned int vdd)
-{
-	struct pxamci_platform_data* p_d = dev->platform_data;
+/* a I2C based RTC is known on CONXS board */
+static struct i2c_board_info trizeps4_i2c_devices[] __initdata = {
+	{ I2C_BOARD_INFO("rtc-pcf8593", 0x51) }
+};
 
-	if (( 1 << vdd) & p_d->ocr_mask) {
-		pr_debug("%s: on\n", __func__);
-		/* FIXME fill in values here */
-	} else {
-		pr_debug("%s: off\n", __func__);
-		/* FIXME fill in values here */
-	}
-}
-
-static short trizeps_conxs_ircr;
-
-/* Switch modes and Power for IRDA receiver */
-static void board_irda_mode(struct device *dev, int mode)
-{
-	unsigned long flags;
-
-	local_irq_save(flags);
-	if (mode & IR_SIRMODE) {
-		/* Slow mode */
-		trizeps_conxs_ircr &= ~ConXS_IRCR_MODE;
-	} else if (mode & IR_FIRMODE) {
-		/* Fast mode */
-		trizeps_conxs_ircr |= ConXS_IRCR_MODE;
-	}
-	pxa2xx_transceiver_mode(dev, mode);
-	if (mode & IR_OFF) {
-		trizeps_conxs_ircr |= ConXS_IRCR_SD;
-	} else {
-		trizeps_conxs_ircr &= ~ConXS_IRCR_SD;
-	}
-	/* FIXME write values to register */
-	local_irq_restore(flags);
-}
-
-#else
-/* for other baseboards define dummies */
-void board_pcmcia_power(int power)	{;}
-#define board_backlight_power		NULL
-#define board_mci_power			NULL
-#define board_irda_mode			NULL
-
-#endif		/* CONFIG_MACH_TRIZEPS4_CONXS */
-EXPORT_SYMBOL(board_pcmcia_power);
-
-static int trizeps4_mci_init(struct device *dev, irq_handler_t mci_detect_int, void *data)
+/****************************************************************************
+ * MMC card slot external to module
+ ****************************************************************************/
+static int trizeps4_mci_init(struct device *dev, irq_handler_t mci_detect_int,
+		void *data)
 {
 	int err;
-	/* setup GPIO for PXA27x MMC controller */
-	pxa_gpio_mode(GPIO32_MMCCLK_MD);
-	pxa_gpio_mode(GPIO112_MMCCMD_MD);
-	pxa_gpio_mode(GPIO92_MMCDAT0_MD);
-	pxa_gpio_mode(GPIO109_MMCDAT1_MD);
-	pxa_gpio_mode(GPIO110_MMCDAT2_MD);
-	pxa_gpio_mode(GPIO111_MMCDAT3_MD);
-
-	pxa_gpio_mode(GPIO_MMC_DET | GPIO_IN);
 
 	err = request_irq(TRIZEPS4_MMC_IRQ, mci_detect_int,
-			  IRQF_DISABLED | IRQF_TRIGGER_RISING,
-			  "MMC card detect", data);
-	if (err)
-		printk(KERN_ERR "trizeps4_mci_init: MMC/SD: can't request MMC card detect IRQ\n");
-
-	return err;
+		IRQF_DISABLED | IRQF_TRIGGER_RISING | IRQF_SAMPLE_RANDOM,
+		"MMC card detect", data);
+	if (err) {
+		printk(KERN_ERR "trizeps4_mci_init: MMC/SD: can't request"
+						"MMC card detect IRQ\n");
+		return -1;
+	}
+	return 0;
 }
 
 static void trizeps4_mci_exit(struct device *dev, void *data)
@@ -303,39 +365,69 @@
 
 static struct pxamci_platform_data trizeps4_mci_platform_data = {
 	.ocr_mask	= MMC_VDD_32_33|MMC_VDD_33_34,
+	.detect_delay	= 1,
 	.init 		= trizeps4_mci_init,
 	.exit		= trizeps4_mci_exit,
-	.setpower 	= board_mci_power,
+	.get_ro		= NULL,	/* write-protection not supported */
+	.setpower 	= NULL,	/* power-switching not supported */
 };
 
-static struct pxaficp_platform_data trizeps4_ficp_platform_data = {
-	.transceiver_cap  = IR_SIRMODE | IR_FIRMODE | IR_OFF,
-	.transceiver_mode = board_irda_mode,
-};
+/****************************************************************************
+ * IRDA mode switching on stuart
+ ****************************************************************************/
+#ifndef STATUS_LEDS_ON_STUART_PINS
+static short trizeps_conxs_ircr;
 
-static int trizeps4_ohci_init(struct device *dev)
+static int trizeps4_irda_startup(struct device *dev)
 {
-	/* setup Port1 GPIO pin. */
-	pxa_gpio_mode( 88 | GPIO_ALT_FN_1_IN);	/* USBHPWR1 */
-	pxa_gpio_mode( 89 | GPIO_ALT_FN_2_OUT);	/* USBHPEN1 */
-
-	/* Set the Power Control Polarity Low and Power Sense
-	   Polarity Low to active low. */
-	UHCHR = (UHCHR | UHCHR_PCPL | UHCHR_PSPL) &
-		~(UHCHR_SSEP1 | UHCHR_SSEP2 | UHCHR_SSEP3 | UHCHR_SSE);
-
+	trizeps_conxs_ircr &= ~ConXS_IRCR_SD;
+	IRCR_writew(trizeps_conxs_ircr);
 	return 0;
 }
 
-static void trizeps4_ohci_exit(struct device *dev)
+static void trizeps4_irda_shutdown(struct device *dev)
 {
-	;
+	trizeps_conxs_ircr |= ConXS_IRCR_SD;
+	IRCR_writew(trizeps_conxs_ircr);
 }
 
+static void trizeps4_irda_transceiver_mode(struct device *dev, int mode)
+{
+	unsigned long flags;
+
+	local_irq_save(flags);
+	/* Switch mode */
+	if (mode & IR_SIRMODE)
+		trizeps_conxs_ircr &= ~ConXS_IRCR_MODE;	/* Slow mode */
+	else if (mode & IR_FIRMODE) {
+		trizeps_conxs_ircr |= ConXS_IRCR_MODE;	/* Fast mode */
+
+	/* Switch power */
+	if (mode & IR_OFF)
+		trizeps_conxs_ircr |= ConXS_IRCR_SD;
+	else
+		trizeps_conxs_ircr &= ~ConXS_IRCR_SD;
+
+	IRCR_writew(trizeps_conxs_ircr);
+	local_irq_restore(flags);
+
+	pxa2xx_transceiver_mode(dev, mode);
+}
+
+static struct pxaficp_platform_data trizeps4_ficp_platform_data = {
+	.transceiver_cap	= IR_SIRMODE | IR_FIRMODE | IR_OFF,
+	.transceiver_mode	= trizeps4_irda_transceiver_mode,
+	.startup		= trizeps4_irda_startup,
+	.shutdown		= trizeps4_irda_shutdown,
+};
+#endif
+
+/****************************************************************************
+ * OHCI USB port
+ ****************************************************************************/
 static struct pxaohci_platform_data trizeps4_ohci_platform_data = {
 	.port_mode	= PMM_PERPORT_MODE,
-	.init		= trizeps4_ohci_init,
-	.exit		= trizeps4_ohci_exit,
+	.flags		= ENABLE_PORT_ALL | POWER_CONTROL_LOW | POWER_SENSE_LOW,
 };
 
 static struct map_desc trizeps4_io_desc[] __initdata = {
@@ -372,105 +464,80 @@
 };
 
 static struct pxafb_mode_info sharp_lcd_mode = {
-    .pixclock		= 78000,
-    .xres		= 640,
-    .yres		= 480,
-    .bpp		= 8,
-    .hsync_len		= 4,
-    .left_margin	= 4,
-    .right_margin	= 4,
-    .vsync_len		= 2,
-    .upper_margin	= 0,
-    .lower_margin	= 0,
-    .sync		= FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
-    .cmap_greyscale	= 0,
+	.pixclock	= 78000,
+	.xres		= 640,
+	.yres		= 480,
+	.bpp		= 8,
+	.hsync_len	= 4,
+	.left_margin	= 4,
+	.right_margin	= 4,
+	.vsync_len	= 2,
+	.upper_margin	= 0,
+	.lower_margin	= 0,
+	.sync		= FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+	.cmap_greyscale	= 0,
 };
 
 static struct pxafb_mach_info sharp_lcd = {
-    .modes		= &sharp_lcd_mode,
-    .num_modes	= 1,
-    .cmap_inverse	= 0,
-    .cmap_static	= 0,
-    .lccr0		= LCCR0_Color | LCCR0_Pas | LCCR0_Dual,
-    .lccr3		= 0x0340ff02,
-    .pxafb_backlight_power = board_backlight_power,
+	.modes		= &sharp_lcd_mode,
+	.num_modes	= 1,
+	.lcd_conn	= LCD_COLOR_DSTN_16BPP | LCD_PCLK_EDGE_FALL,
+	.cmap_inverse	= 0,
+	.cmap_static	= 0,
+	.pxafb_backlight_power = board_backlight_power,
 };
 
 static struct pxafb_mode_info toshiba_lcd_mode = {
-    .pixclock		= 39720,
-    .xres		= 640,
-    .yres		= 480,
-    .bpp		= 8,
-    .hsync_len		= 63,
-    .left_margin	= 12,
-    .right_margin	= 12,
-    .vsync_len		= 4,
-    .upper_margin	= 32,
-    .lower_margin	= 10,
-    .sync		= 0,
-    .cmap_greyscale	= 0,
+	.pixclock	= 39720,
+	.xres		= 640,
+	.yres		= 480,
+	.bpp		= 8,
+	.hsync_len	= 63,
+	.left_margin	= 12,
+	.right_margin	= 12,
+	.vsync_len	= 4,
+	.upper_margin	= 32,
+	.lower_margin	= 10,
+	.sync		= 0,
+	.cmap_greyscale	= 0,
 };
 
 static struct pxafb_mach_info toshiba_lcd = {
-    .modes		= &toshiba_lcd_mode,
-    .num_modes	= 1,
-    .cmap_inverse	= 0,
-    .cmap_static	= 0,
-    .lccr0		= LCCR0_Color | LCCR0_Act,
-    .lccr3		= 0x03400002,
-    .pxafb_backlight_power = board_backlight_power,
+	.modes		= &toshiba_lcd_mode,
+	.num_modes	= 1,
+	.lcd_conn	= (LCD_COLOR_TFT_16BPP | LCD_PCLK_EDGE_FALL),
+	.cmap_inverse	= 0,
+	.cmap_static	= 0,
+	.pxafb_backlight_power = board_backlight_power,
 };
 
 static void __init trizeps4_init(void)
 {
-	platform_add_devices(trizeps4_devices, ARRAY_SIZE(trizeps4_devices));
+	pxa2xx_mfp_config(ARRAY_AND_SIZE(trizeps4_pin_config));
+	if (machine_is_trizeps4wl()) {
+		pxa2xx_mfp_config(ARRAY_AND_SIZE(trizeps4wl_pin_config));
+		platform_add_devices(trizeps4wl_devices,
+					ARRAY_SIZE(trizeps4wl_devices));
+	} else {
+		platform_add_devices(trizeps4_devices,
+					ARRAY_SIZE(trizeps4_devices));
+	}
 
-/*	set_pxa_fb_info(&sharp_lcd); */
-	set_pxa_fb_info(&toshiba_lcd);
+	if (0)	/* dont know how to determine LCD */
+		set_pxa_fb_info(&sharp_lcd);
+	else
+		set_pxa_fb_info(&toshiba_lcd);
 
 	pxa_set_mci_info(&trizeps4_mci_platform_data);
+#ifndef STATUS_LEDS_ON_STUART_PINS
 	pxa_set_ficp_info(&trizeps4_ficp_platform_data);
+#endif
 	pxa_set_ohci_info(&trizeps4_ohci_platform_data);
 	pxa_set_ac97_info(NULL);
-}
+	pxa_set_i2c_info(NULL);
+	i2c_register_board_info(0, trizeps4_i2c_devices,
+					ARRAY_SIZE(trizeps4_i2c_devices));
 
-static void __init trizeps4_map_io(void)
-{
-	pxa_map_io();
-	iotable_init(trizeps4_io_desc, ARRAY_SIZE(trizeps4_io_desc));
-
-	/* for DiskOnChip */
-	pxa_gpio_mode(GPIO15_nCS_1_MD);
-
-	/* for off-module PIC on ConXS board */
-	pxa_gpio_mode(GPIO_PIC | GPIO_IN);
-
-	/* UCB1400 irq */
-	pxa_gpio_mode(GPIO_UCB1400 | GPIO_IN);
-
-	/* for DM9000 LAN */
-	pxa_gpio_mode(GPIO78_nCS_2_MD);
-	pxa_gpio_mode(GPIO_DM9000 | GPIO_IN);
-
-	/* for PCMCIA device */
-	pxa_gpio_mode(GPIO_PCD | GPIO_IN);
-	pxa_gpio_mode(GPIO_PRDY | GPIO_IN);
-
-	/* for I2C adapter */
-	pxa_gpio_mode(GPIO117_I2CSCL_MD);
-	pxa_gpio_mode(GPIO118_I2CSDA_MD);
-
-	/* MMC_DET s.o. */
-	pxa_gpio_mode(GPIO_MMC_DET | GPIO_IN);
-
-	/* whats that for ??? */
-	pxa_gpio_mode(GPIO79_nCS_3_MD);
-
-#ifdef CONFIG_LEDS
-	pxa_gpio_mode( GPIO_SYS_BUSY_LED  | GPIO_OUT);		/* LED1 */
-	pxa_gpio_mode( GPIO_HEARTBEAT_LED | GPIO_OUT);		/* LED2 */
-#endif
-#ifdef CONFIG_MACH_TRIZEPS4_CONXS
 #ifdef CONFIG_IDE_PXA_CF
 	/* if boot direct from compact flash dont disable power */
 	trizeps_conxs_bcr = 0x0009;
@@ -478,18 +545,24 @@
 	/* this is the reset value */
 	trizeps_conxs_bcr = 0x00A0;
 #endif
-	ConXS_BCR = trizeps_conxs_bcr;
-#endif
+	BCR_writew(trizeps_conxs_bcr);
+	board_backlight_power(1);
+}
 
-#warning FIXME - accessing PM registers directly is deprecated
-	PWER  = 0x00000002;
-	PFER  = 0x00000000;
-	PRER  = 0x00000002;
-	PGSR0 = 0x0158C000;
-	PGSR1 = 0x00FF0080;
-	PGSR2 = 0x0001C004;
-	/* Stop 3.6MHz and drive HIGH to PCMCIA and CS */
-	PCFR |= PCFR_OPDE;
+static void __init trizeps4_map_io(void)
+{
+	pxa_map_io();
+	iotable_init(trizeps4_io_desc, ARRAY_SIZE(trizeps4_io_desc));
+
+	if ((MSC0 & 0x8) && (BOOT_DEF & 0x1)) {
+		/* if flash is 16 bit wide its a Trizeps4 WL */
+		__machine_arch_type = MACH_TYPE_TRIZEPS4WL;
+		trizeps4_flash_data[0].width = 2;
+	} else {
+		/* if flash is 32 bit wide its a Trizeps4 */
+		__machine_arch_type = MACH_TYPE_TRIZEPS4;
+		trizeps4_flash_data[0].width = 4;
+	}
 }
 
 MACHINE_START(TRIZEPS4, "Keith und Koep Trizeps IV module")
@@ -503,3 +576,13 @@
 	.timer		= &pxa_timer,
 MACHINE_END
 
+MACHINE_START(TRIZEPS4WL, "Keith und Koep Trizeps IV-WL module")
+	/* MAINTAINER("Jürgen Schindele") */
+	.phys_io	= 0x40000000,
+	.io_pg_offst	= (io_p2v(0x40000000) >> 18) & 0xfffc,
+	.boot_params	= TRIZEPS4_SDRAM_BASE + 0x100,
+	.init_machine	= trizeps4_init,
+	.map_io		= trizeps4_map_io,
+	.init_irq	= pxa27x_init_irq,
+	.timer		= &pxa_timer,
+MACHINE_END
diff --git a/arch/arm/mach-pxa/viper.c b/arch/arm/mach-pxa/viper.c
new file mode 100644
index 0000000..d7632f6
--- /dev/null
+++ b/arch/arm/mach-pxa/viper.c
@@ -0,0 +1,951 @@
+/*
+ *  linux/arch/arm/mach-pxa/viper.c
+ *
+ *  Support for the Arcom VIPER SBC.
+ *
+ *  Author:	Ian Campbell
+ *  Created:    Feb 03, 2003
+ *  Copyright:  Arcom Control Systems
+ *
+ *  Maintained by Marc Zyngier <maz@misterjones.org>
+ *                             <marc.zyngier@altran.com>
+ *
+ * Based on lubbock.c:
+ *  Author:	Nicolas Pitre
+ *  Created:	Jun 15, 2001
+ *  Copyright:	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 version 2 as
+ *  published by the Free Software Foundation.
+ */
+
+#include <linux/types.h>
+#include <linux/memory.h>
+#include <linux/cpu.h>
+#include <linux/cpufreq.h>
+#include <linux/delay.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/major.h>
+#include <linux/module.h>
+#include <linux/pm.h>
+#include <linux/sched.h>
+#include <linux/gpio.h>
+#include <linux/i2c-gpio.h>
+#include <linux/serial_8250.h>
+#include <linux/smc91x.h>
+#include <linux/pwm_backlight.h>
+#include <linux/usb/isp116x.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/physmap.h>
+
+#include <mach/pxa-regs.h>
+#include <mach/pxa2xx-regs.h>
+#include <mach/bitfield.h>
+#include <mach/audio.h>
+#include <mach/pxafb.h>
+#include <mach/mfp-pxa25x.h>
+#include <mach/i2c.h>
+#include <mach/viper.h>
+
+#include <asm/setup.h>
+#include <asm/mach-types.h>
+#include <asm/irq.h>
+#include <asm/sizes.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/irq.h>
+
+#include "generic.h"
+#include "devices.h"
+
+static unsigned int icr;
+
+static void viper_icr_set_bit(unsigned int bit)
+{
+	icr |= bit;
+	VIPER_ICR = icr;
+}
+
+static void viper_icr_clear_bit(unsigned int bit)
+{
+	icr &= ~bit;
+	VIPER_ICR = icr;
+}
+
+/* This function is used from the pcmcia module to reset the CF */
+void viper_cf_rst(int state)
+{
+	if (state)
+		viper_icr_set_bit(VIPER_ICR_CF_RST);
+	else
+		viper_icr_clear_bit(VIPER_ICR_CF_RST);
+}
+EXPORT_SYMBOL(viper_cf_rst);
+
+/*
+ * The CPLD version register was not present on VIPER boards prior to
+ * v2i1. On v1 boards where the version register is not present we
+ * will just read back the previous value from the databus.
+ *
+ * Therefore we do two reads. The first time we write 0 to the
+ * (read-only) register before reading and the second time we write
+ * 0xff first. If the two reads do not match or they read back as 0xff
+ * or 0x00 then we have version 1 hardware.
+ */
+static u8 viper_hw_version(void)
+{
+	u8 v1, v2;
+	unsigned long flags;
+
+	local_irq_save(flags);
+
+	VIPER_VERSION = 0;
+	v1 = VIPER_VERSION;
+	VIPER_VERSION = 0xff;
+	v2 = VIPER_VERSION;
+
+	v1 = (v1 != v2 || v1 == 0xff) ? 0 : v1;
+
+	local_irq_restore(flags);
+	return v1;
+}
+
+/* CPU sysdev */
+static int viper_cpu_suspend(struct sys_device *sysdev, pm_message_t state)
+{
+	viper_icr_set_bit(VIPER_ICR_R_DIS);
+	return 0;
+}
+
+static int viper_cpu_resume(struct sys_device *sysdev)
+{
+	viper_icr_clear_bit(VIPER_ICR_R_DIS);
+	return 0;
+}
+
+static struct sysdev_driver viper_cpu_sysdev_driver = {
+	.suspend	= viper_cpu_suspend,
+	.resume		= viper_cpu_resume,
+};
+
+static unsigned int current_voltage_divisor;
+
+/*
+ * If force is not true then step from existing to new divisor. If
+ * force is true then jump straight to the new divisor. Stepping is
+ * used because if the jump in voltage is too large, the VCC can dip
+ * too low and the regulator cuts out.
+ *
+ * force can be used to initialize the divisor to a know state by
+ * setting the value for the current clock speed, since we are already
+ * running at that speed we know the voltage should be pretty close so
+ * the jump won't be too large
+ */
+static void viper_set_core_cpu_voltage(unsigned long khz, int force)
+{
+	int i = 0;
+	unsigned int divisor = 0;
+	const char *v;
+
+	if (khz < 200000) {
+		v = "1.0"; divisor = 0xfff;
+	} else if (khz < 300000) {
+		v = "1.1"; divisor = 0xde5;
+	} else {
+		v = "1.3"; divisor = 0x325;
+	}
+
+	pr_debug("viper: setting CPU core voltage to %sV at %d.%03dMHz\n",
+		 v, (int)khz / 1000, (int)khz % 1000);
+
+#define STEP 0x100
+	do {
+		int step;
+
+		if (force)
+			step = divisor;
+		else if (current_voltage_divisor < divisor - STEP)
+			step = current_voltage_divisor + STEP;
+		else if (current_voltage_divisor > divisor + STEP)
+			step = current_voltage_divisor - STEP;
+		else
+			step = divisor;
+		force = 0;
+
+		gpio_set_value(VIPER_PSU_CLK_GPIO, 0);
+		gpio_set_value(VIPER_PSU_nCS_LD_GPIO, 0);
+
+		for (i = 1 << 11 ; i > 0 ; i >>= 1) {
+			udelay(1);
+
+			gpio_set_value(VIPER_PSU_DATA_GPIO, step & i);
+			udelay(1);
+
+			gpio_set_value(VIPER_PSU_CLK_GPIO, 1);
+			udelay(1);
+
+			gpio_set_value(VIPER_PSU_CLK_GPIO, 0);
+		}
+		udelay(1);
+
+		gpio_set_value(VIPER_PSU_nCS_LD_GPIO, 1);
+		udelay(1);
+
+		gpio_set_value(VIPER_PSU_nCS_LD_GPIO, 0);
+
+		current_voltage_divisor = step;
+	} while (current_voltage_divisor != divisor);
+}
+
+/* Interrupt handling */
+static unsigned long viper_irq_enabled_mask;
+
+static void viper_ack_irq(unsigned int irq)
+{
+	int viper_irq = irq - PXA_ISA_IRQ(0);
+
+	if (viper_irq < 8)
+		VIPER_LO_IRQ_STATUS = 1 << viper_irq;
+	else
+		VIPER_HI_IRQ_STATUS = 1 << (viper_irq - 8);
+}
+
+static void viper_mask_irq(unsigned int irq)
+{
+	viper_irq_enabled_mask &= ~(1 << (irq - PXA_ISA_IRQ(0)));
+}
+
+static void viper_unmask_irq(unsigned int irq)
+{
+	viper_irq_enabled_mask |= (1 << (irq - PXA_ISA_IRQ(0)));
+}
+
+static inline unsigned long viper_irq_pending(void)
+{
+	return (VIPER_HI_IRQ_STATUS << 8 | VIPER_LO_IRQ_STATUS) &
+			viper_irq_enabled_mask;
+}
+
+static void viper_irq_handler(unsigned int irq, struct irq_desc *desc)
+{
+	unsigned long pending;
+
+	pending = viper_irq_pending();
+	do {
+		if (likely(pending)) {
+			irq = PXA_ISA_IRQ(0) + __ffs(pending);
+			generic_handle_irq(irq);
+		}
+		pending = viper_irq_pending();
+	} while (pending);
+}
+
+static struct irq_chip viper_irq_chip = {
+	.name	= "ISA",
+	.ack	= viper_ack_irq,
+	.mask	= viper_mask_irq,
+	.unmask	= viper_unmask_irq
+};
+
+static void __init viper_init_irq(void)
+{
+	const int isa_irqs[] = { 3, 4, 5, 6, 7, 10, 11, 12, 9, 14, 15 };
+	int irq;
+	int isa_irq;
+
+	pxa25x_init_irq();
+
+	/* setup ISA IRQs */
+	for (irq = 0; irq < ARRAY_SIZE(isa_irqs); irq++) {
+		isa_irq = isa_irqs[irq];
+		set_irq_chip(isa_irq, &viper_irq_chip);
+		set_irq_handler(isa_irq, handle_edge_irq);
+		set_irq_flags(isa_irq, IRQF_VALID | IRQF_PROBE);
+	}
+
+	set_irq_chained_handler(gpio_to_irq(VIPER_CPLD_GPIO),
+				viper_irq_handler);
+	set_irq_type(gpio_to_irq(VIPER_CPLD_GPIO), IRQ_TYPE_EDGE_BOTH);
+
+#ifndef CONFIG_SERIAL_PXA
+	/*
+	 * 8250 doesn't support IRQ_TYPE being passed as part
+	 * of the plat_serial8250_port structure...
+	 */
+	set_irq_type(gpio_to_irq(VIPER_UARTA_GPIO), IRQ_TYPE_EDGE_RISING);
+	set_irq_type(gpio_to_irq(VIPER_UARTB_GPIO), IRQ_TYPE_EDGE_RISING);
+#endif
+}
+
+/* Flat Panel */
+static struct pxafb_mode_info fb_mode_info[] = {
+	{
+		.pixclock	= 157500,
+
+		.xres		= 320,
+		.yres		= 240,
+
+		.bpp		= 16,
+
+		.hsync_len	= 63,
+		.left_margin	= 7,
+		.right_margin	= 13,
+
+		.vsync_len	= 20,
+		.upper_margin	= 0,
+		.lower_margin	= 0,
+
+		.sync		= 0,
+	},
+};
+
+static struct pxafb_mach_info fb_info = {
+	.modes			= fb_mode_info,
+	.num_modes		= 1,
+	.lcd_conn		= LCD_COLOR_TFT_16BPP | LCD_PCLK_EDGE_FALL,
+};
+
+static int viper_backlight_init(struct device *dev)
+{
+	int ret;
+
+	/* GPIO9 and 10 control FB backlight. Initialise to off */
+	ret = gpio_request(VIPER_BCKLIGHT_EN_GPIO, "Backlight");
+	if (ret)
+		goto err_request_bckl;
+
+	ret = gpio_request(VIPER_LCD_EN_GPIO, "LCD");
+	if (ret)
+		goto err_request_lcd;
+
+	ret = gpio_direction_output(VIPER_BCKLIGHT_EN_GPIO, 0);
+	if (ret)
+		goto err_dir;
+
+	ret = gpio_direction_output(VIPER_LCD_EN_GPIO, 0);
+	if (ret)
+		goto err_dir;
+
+	return 0;
+
+err_dir:
+	gpio_free(VIPER_LCD_EN_GPIO);
+err_request_lcd:
+	gpio_free(VIPER_BCKLIGHT_EN_GPIO);
+err_request_bckl:
+	dev_err(dev, "Failed to setup LCD GPIOs\n");
+
+	return ret;
+}
+
+static int viper_backlight_notify(int brightness)
+{
+	gpio_set_value(VIPER_LCD_EN_GPIO, !!brightness);
+	gpio_set_value(VIPER_BCKLIGHT_EN_GPIO, !!brightness);
+
+	return brightness;
+}
+
+static void viper_backlight_exit(struct device *dev)
+{
+	gpio_free(VIPER_LCD_EN_GPIO);
+	gpio_free(VIPER_BCKLIGHT_EN_GPIO);
+}
+
+static struct platform_pwm_backlight_data viper_backlight_data = {
+	.pwm_id		= 0,
+	.max_brightness	= 100,
+	.dft_brightness	= 100,
+	.pwm_period_ns	= 1000000,
+	.init		= viper_backlight_init,
+	.notify		= viper_backlight_notify,
+	.exit		= viper_backlight_exit,
+};
+
+static struct platform_device viper_backlight_device = {
+	.name		= "pwm-backlight",
+	.dev		= {
+		.parent		= &pxa25x_device_pwm0.dev,
+		.platform_data	= &viper_backlight_data,
+	},
+};
+
+/* Ethernet */
+static struct resource smc91x_resources[] = {
+	[0] = {
+		.name	= "smc91x-regs",
+		.start  = VIPER_ETH_PHYS + 0x300,
+		.end    = VIPER_ETH_PHYS + 0x30f,
+		.flags  = IORESOURCE_MEM,
+	},
+	[1] = {
+		.start  = gpio_to_irq(VIPER_ETH_GPIO),
+		.end    = gpio_to_irq(VIPER_ETH_GPIO),
+		.flags  = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE,
+	},
+	[2] = {
+		.name	= "smc91x-data32",
+		.start  = VIPER_ETH_DATA_PHYS,
+		.end    = VIPER_ETH_DATA_PHYS + 3,
+		.flags  = IORESOURCE_MEM,
+	},
+};
+
+static struct smc91x_platdata viper_smc91x_info = {
+	.flags	= SMC91X_USE_16BIT | SMC91X_NOWAIT,
+	.leda	= RPC_LED_100_10,
+	.ledb	= RPC_LED_TX_RX,
+};
+
+static struct platform_device smc91x_device = {
+	.name		= "smc91x",
+	.id		= -1,
+	.num_resources  = ARRAY_SIZE(smc91x_resources),
+	.resource       = smc91x_resources,
+	.dev		= {
+		.platform_data	= &viper_smc91x_info,
+	},
+};
+
+/* i2c */
+static struct i2c_gpio_platform_data i2c_bus_data = {
+	.sda_pin = VIPER_RTC_I2C_SDA_GPIO,
+	.scl_pin = VIPER_RTC_I2C_SCL_GPIO,
+	.udelay  = 10,
+	.timeout = 100,
+};
+
+static struct platform_device i2c_bus_device = {
+	.name		= "i2c-gpio",
+	.id		= 1, /* pxa2xx-i2c is bus 0, so start at 1 */
+	.dev = {
+		.platform_data = &i2c_bus_data,
+	}
+};
+
+static struct i2c_board_info __initdata viper_i2c_devices[] = {
+	{
+		I2C_BOARD_INFO("ds1338", 0x68),
+	},
+};
+
+/*
+ * Serial configuration:
+ * You can either have the standard PXA ports driven by the PXA driver,
+ * or all the ports (PXA + 16850) driven by the 8250 driver.
+ * Choose your poison.
+ */
+
+static struct resource viper_serial_resources[] = {
+#ifndef CONFIG_SERIAL_PXA
+	{
+		.start	= 0x40100000,
+		.end	= 0x4010001f,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= 0x40200000,
+		.end	= 0x4020001f,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= 0x40700000,
+		.end	= 0x4070001f,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= VIPER_UARTA_PHYS,
+		.end	= VIPER_UARTA_PHYS + 0xf,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= VIPER_UARTB_PHYS,
+		.end	= VIPER_UARTB_PHYS + 0xf,
+		.flags	= IORESOURCE_MEM,
+	},
+#else
+	{
+		0,
+	},
+#endif
+};
+
+static struct plat_serial8250_port serial_platform_data[] = {
+#ifndef CONFIG_SERIAL_PXA
+	/* Internal UARTs */
+	{
+		.membase	= (void *)&FFUART,
+		.mapbase	= __PREG(FFUART),
+		.irq		= IRQ_FFUART,
+		.uartclk	= 921600 * 16,
+		.regshift	= 2,
+		.flags		= UPF_BOOT_AUTOCONF | UPF_SKIP_TEST,
+		.iotype		= UPIO_MEM,
+	},
+	{
+		.membase	= (void *)&BTUART,
+		.mapbase	= __PREG(BTUART),
+		.irq		= IRQ_BTUART,
+		.uartclk	= 921600 * 16,
+		.regshift	= 2,
+		.flags		= UPF_BOOT_AUTOCONF | UPF_SKIP_TEST,
+		.iotype		= UPIO_MEM,
+	},
+	{
+		.membase	= (void *)&STUART,
+		.mapbase	= __PREG(STUART),
+		.irq		= IRQ_STUART,
+		.uartclk	= 921600 * 16,
+		.regshift	= 2,
+		.flags		= UPF_BOOT_AUTOCONF | UPF_SKIP_TEST,
+		.iotype		= UPIO_MEM,
+	},
+	/* External UARTs */
+	{
+		.mapbase	= VIPER_UARTA_PHYS,
+		.irq		= gpio_to_irq(VIPER_UARTA_GPIO),
+		.uartclk	= 1843200,
+		.regshift	= 1,
+		.iotype		= UPIO_MEM,
+		.flags		= UPF_BOOT_AUTOCONF | UPF_IOREMAP |
+				  UPF_SKIP_TEST,
+	},
+	{
+		.mapbase	= VIPER_UARTB_PHYS,
+		.irq		= gpio_to_irq(VIPER_UARTB_GPIO),
+		.uartclk	= 1843200,
+		.regshift	= 1,
+		.iotype		= UPIO_MEM,
+		.flags		= UPF_BOOT_AUTOCONF | UPF_IOREMAP |
+				  UPF_SKIP_TEST,
+	},
+#endif
+	{ },
+};
+
+static struct platform_device serial_device = {
+	.name			= "serial8250",
+	.id			= 0,
+	.dev			= {
+		.platform_data	= serial_platform_data,
+	},
+	.num_resources		= ARRAY_SIZE(viper_serial_resources),
+	.resource		= viper_serial_resources,
+};
+
+/* USB */
+static void isp116x_delay(struct device *dev, int delay)
+{
+	ndelay(delay);
+}
+
+static struct resource isp116x_resources[] = {
+	[0] = { /* DATA */
+		.start  = VIPER_USB_PHYS + 0,
+		.end    = VIPER_USB_PHYS + 1,
+		.flags  = IORESOURCE_MEM,
+	},
+	[1] = { /* ADDR */
+		.start  = VIPER_USB_PHYS + 2,
+		.end    = VIPER_USB_PHYS + 3,
+		.flags  = IORESOURCE_MEM,
+	},
+	[2] = {
+		.start  = gpio_to_irq(VIPER_USB_GPIO),
+		.end    = gpio_to_irq(VIPER_USB_GPIO),
+		.flags  = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE,
+	},
+};
+
+/* (DataBusWidth16|AnalogOCEnable|DREQOutputPolarity|DownstreamPort15KRSel ) */
+static struct isp116x_platform_data isp116x_platform_data = {
+	/* Enable internal resistors on downstream ports */
+	.sel15Kres		= 1,
+	/* On-chip overcurrent protection */
+	.oc_enable		= 1,
+	/* INT output polarity */
+	.int_act_high		= 1,
+	/* INT edge or level triggered */
+	.int_edge_triggered	= 0,
+
+	/* WAKEUP pin connected - NOT SUPPORTED  */
+	/* .remote_wakeup_connected = 0, */
+	/* Wakeup by devices on usb bus enabled */
+	.remote_wakeup_enable	= 0,
+	.delay			= isp116x_delay,
+};
+
+static struct platform_device isp116x_device = {
+	.name			= "isp116x-hcd",
+	.id			= -1,
+	.num_resources  	= ARRAY_SIZE(isp116x_resources),
+	.resource       	= isp116x_resources,
+	.dev			= {
+		.platform_data	= &isp116x_platform_data,
+	},
+
+};
+
+/* MTD */
+static struct resource mtd_resources[] = {
+	[0] = {	/* RedBoot config + filesystem flash */
+		.start	= VIPER_FLASH_PHYS,
+		.end	= VIPER_FLASH_PHYS + SZ_32M - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {	/* Boot flash */
+		.start	= VIPER_BOOT_PHYS,
+		.end	= VIPER_BOOT_PHYS + SZ_1M - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	[2] = { /*
+		 * SRAM size is actually 256KB, 8bits, with a sparse mapping
+		 * (each byte is on a 16bit boundary).
+		 */
+		.start	= _VIPER_SRAM_BASE,
+		.end	= _VIPER_SRAM_BASE + SZ_512K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+};
+
+static struct mtd_partition viper_boot_flash_partition = {
+	.name		= "RedBoot",
+	.size		= SZ_1M,
+	.offset		= 0,
+	.mask_flags	= MTD_WRITEABLE,	/* force R/O */
+};
+
+static struct physmap_flash_data viper_flash_data[] = {
+	[0] = {
+		.width		= 2,
+		.parts		= NULL,
+		.nr_parts	= 0,
+	},
+	[1] = {
+		.width		= 2,
+		.parts		= &viper_boot_flash_partition,
+		.nr_parts	= 1,
+	},
+};
+
+static struct platform_device viper_mtd_devices[] = {
+	[0] = {
+		.name		= "physmap-flash",
+		.id		= 0,
+		.dev		= {
+			.platform_data	= &viper_flash_data[0],
+		},
+		.resource	= &mtd_resources[0],
+		.num_resources	= 1,
+	},
+	[1] = {
+		.name		= "physmap-flash",
+		.id		= 1,
+		.dev		= {
+			.platform_data	= &viper_flash_data[1],
+		},
+		.resource	= &mtd_resources[1],
+		.num_resources	= 1,
+	},
+};
+
+static struct platform_device *viper_devs[] __initdata = {
+	&smc91x_device,
+	&i2c_bus_device,
+	&serial_device,
+	&isp116x_device,
+	&viper_mtd_devices[0],
+	&viper_mtd_devices[1],
+	&viper_backlight_device,
+};
+
+static mfp_cfg_t viper_pin_config[] __initdata = {
+	/* Chip selects */
+	GPIO15_nCS_1,
+	GPIO78_nCS_2,
+	GPIO79_nCS_3,
+	GPIO80_nCS_4,
+	GPIO33_nCS_5,
+
+	/* FP Backlight */
+	GPIO9_GPIO, 				/* VIPER_BCKLIGHT_EN_GPIO */
+	GPIO10_GPIO,				/* VIPER_LCD_EN_GPIO */
+	GPIO16_PWM0_OUT,
+
+	/* Ethernet PHY Ready */
+	GPIO18_RDY,
+
+	/* Serial shutdown */
+	GPIO12_GPIO | MFP_LPM_DRIVE_HIGH,	/* VIPER_UART_SHDN_GPIO */
+
+	/* Compact-Flash / PC104 */
+	GPIO48_nPOE,
+	GPIO49_nPWE,
+	GPIO50_nPIOR,
+	GPIO51_nPIOW,
+	GPIO52_nPCE_1,
+	GPIO53_nPCE_2,
+	GPIO54_nPSKTSEL,
+	GPIO55_nPREG,
+	GPIO56_nPWAIT,
+	GPIO57_nIOIS16,
+	GPIO8_GPIO,				/* VIPER_CF_RDY_GPIO */
+	GPIO32_GPIO,				/* VIPER_CF_CD_GPIO */
+	GPIO82_GPIO,				/* VIPER_CF_POWER_GPIO */
+
+	/* Integrated UPS control */
+	GPIO20_GPIO,				/* VIPER_UPS_GPIO */
+
+	/* Vcc regulator control */
+	GPIO6_GPIO,				/* VIPER_PSU_DATA_GPIO */
+	GPIO11_GPIO,				/* VIPER_PSU_CLK_GPIO */
+	GPIO19_GPIO,				/* VIPER_PSU_nCS_LD_GPIO */
+
+	/* i2c busses */
+	GPIO26_GPIO,				/* VIPER_TPM_I2C_SDA_GPIO */
+	GPIO27_GPIO,				/* VIPER_TPM_I2C_SCL_GPIO */
+	GPIO83_GPIO,				/* VIPER_RTC_I2C_SDA_GPIO */
+	GPIO84_GPIO,				/* VIPER_RTC_I2C_SCL_GPIO */
+
+	/* PC/104 Interrupt */
+	GPIO1_GPIO | WAKEUP_ON_EDGE_RISE,	/* VIPER_CPLD_GPIO */
+};
+
+static unsigned long viper_tpm;
+
+static int __init viper_tpm_setup(char *str)
+{
+	strict_strtoul(str, 10, &viper_tpm);
+	return 1;
+}
+
+__setup("tpm=", viper_tpm_setup);
+
+static void __init viper_tpm_init(void)
+{
+	struct platform_device *tpm_device;
+	struct i2c_gpio_platform_data i2c_tpm_data = {
+		.sda_pin = VIPER_TPM_I2C_SDA_GPIO,
+		.scl_pin = VIPER_TPM_I2C_SCL_GPIO,
+		.udelay  = 10,
+		.timeout = 100,
+	};
+	char *errstr;
+
+	/* Allocate TPM i2c bus if requested */
+	if (!viper_tpm)
+		return;
+
+	tpm_device = platform_device_alloc("i2c-gpio", 2);
+	if (tpm_device) {
+		if (!platform_device_add_data(tpm_device,
+					      &i2c_tpm_data,
+					      sizeof(i2c_tpm_data))) {
+			if (platform_device_add(tpm_device)) {
+				errstr = "register TPM i2c bus";
+				goto error_free_tpm;
+			}
+		} else {
+			errstr = "allocate TPM i2c bus data";
+			goto error_free_tpm;
+		}
+	} else {
+		errstr = "allocate TPM i2c device";
+		goto error_tpm;
+	}
+
+	return;
+
+error_free_tpm:
+	kfree(tpm_device);
+error_tpm:
+	pr_err("viper: Couldn't %s, giving up\n", errstr);
+}
+
+static void __init viper_init_vcore_gpios(void)
+{
+	if (gpio_request(VIPER_PSU_DATA_GPIO, "PSU data"))
+		goto err_request_data;
+
+	if (gpio_request(VIPER_PSU_CLK_GPIO, "PSU clock"))
+		goto err_request_clk;
+
+	if (gpio_request(VIPER_PSU_nCS_LD_GPIO, "PSU cs"))
+		goto err_request_cs;
+
+	if (gpio_direction_output(VIPER_PSU_DATA_GPIO, 0) ||
+	    gpio_direction_output(VIPER_PSU_CLK_GPIO, 0) ||
+	    gpio_direction_output(VIPER_PSU_nCS_LD_GPIO, 0))
+		goto err_dir;
+
+	/* c/should assume redboot set the correct level ??? */
+	viper_set_core_cpu_voltage(get_clk_frequency_khz(0), 1);
+
+	return;
+
+err_dir:
+	gpio_free(VIPER_PSU_nCS_LD_GPIO);
+err_request_cs:
+	gpio_free(VIPER_PSU_CLK_GPIO);
+err_request_clk:
+	gpio_free(VIPER_PSU_DATA_GPIO);
+err_request_data:
+	pr_err("viper: Failed to setup vcore control GPIOs\n");
+}
+
+static void __init viper_init_serial_gpio(void)
+{
+	if (gpio_request(VIPER_UART_SHDN_GPIO, "UARTs shutdown"))
+		goto err_request;
+
+	if (gpio_direction_output(VIPER_UART_SHDN_GPIO, 0))
+		goto err_dir;
+
+	return;
+
+err_dir:
+	gpio_free(VIPER_UART_SHDN_GPIO);
+err_request:
+	pr_err("viper: Failed to setup UART shutdown GPIO\n");
+}
+
+#ifdef CONFIG_CPU_FREQ
+static int viper_cpufreq_notifier(struct notifier_block *nb,
+				  unsigned long val, void *data)
+{
+	struct cpufreq_freqs *freq = data;
+
+	/* TODO: Adjust timings??? */
+
+	switch (val) {
+	case CPUFREQ_PRECHANGE:
+		if (freq->old < freq->new) {
+			/* we are getting faster so raise the voltage
+			 * before we change freq */
+			viper_set_core_cpu_voltage(freq->new, 0);
+		}
+		break;
+	case CPUFREQ_POSTCHANGE:
+		if (freq->old > freq->new) {
+			/* we are slowing down so drop the power
+			 * after we change freq */
+			viper_set_core_cpu_voltage(freq->new, 0);
+		}
+		break;
+	case CPUFREQ_RESUMECHANGE:
+		viper_set_core_cpu_voltage(freq->new, 0);
+		break;
+	default:
+		/* ignore */
+		break;
+	}
+
+	return 0;
+}
+
+static struct notifier_block viper_cpufreq_notifier_block = {
+	.notifier_call  = viper_cpufreq_notifier
+};
+
+static void __init viper_init_cpufreq(void)
+{
+	if (cpufreq_register_notifier(&viper_cpufreq_notifier_block,
+				      CPUFREQ_TRANSITION_NOTIFIER))
+		pr_err("viper: Failed to setup cpufreq notifier\n");
+}
+#else
+static inline void viper_init_cpufreq(void) {}
+#endif
+
+static void viper_power_off(void)
+{
+	pr_notice("Shutting off UPS\n");
+	gpio_set_value(VIPER_UPS_GPIO, 1);
+	/* Spin to death... */
+	while (1);
+}
+
+static void __init viper_init(void)
+{
+	u8 version;
+
+	pm_power_off = viper_power_off;
+
+	pxa2xx_mfp_config(ARRAY_AND_SIZE(viper_pin_config));
+
+	/* Wake-up serial console */
+	viper_init_serial_gpio();
+
+	set_pxa_fb_info(&fb_info);
+
+	/* v1 hardware cannot use the datacs line */
+	version = viper_hw_version();
+	if (version == 0)
+		smc91x_device.num_resources--;
+
+	pxa_set_i2c_info(NULL);
+	platform_add_devices(viper_devs, ARRAY_SIZE(viper_devs));
+
+	viper_init_vcore_gpios();
+	viper_init_cpufreq();
+
+	sysdev_driver_register(&cpu_sysdev_class, &viper_cpu_sysdev_driver);
+
+	if (version) {
+		pr_info("viper: hardware v%di%d detected. "
+			"CPLD revision %d.\n",
+			VIPER_BOARD_VERSION(version),
+			VIPER_BOARD_ISSUE(version),
+			VIPER_CPLD_REVISION(version));
+		system_rev = (VIPER_BOARD_VERSION(version) << 8) |
+			     (VIPER_BOARD_ISSUE(version) << 4) |
+			     VIPER_CPLD_REVISION(version);
+	} else {
+		pr_info("viper: No version register.\n");
+	}
+
+	i2c_register_board_info(1, ARRAY_AND_SIZE(viper_i2c_devices));
+
+	viper_tpm_init();
+	pxa_set_ac97_info(NULL);
+}
+
+static struct map_desc viper_io_desc[] __initdata = {
+	{
+		.virtual = VIPER_CPLD_BASE,
+		.pfn     = __phys_to_pfn(VIPER_CPLD_PHYS),
+		.length  = 0x00300000,
+		.type    = MT_DEVICE,
+	},
+	{
+		.virtual = VIPER_PC104IO_BASE,
+		.pfn     = __phys_to_pfn(_PCMCIA1IO),
+		.length  = 0x00800000,
+		.type    = MT_DEVICE,
+	},
+};
+
+static void __init viper_map_io(void)
+{
+	pxa_map_io();
+
+	iotable_init(viper_io_desc, ARRAY_SIZE(viper_io_desc));
+
+	PCFR |= PCFR_OPDE;
+}
+
+MACHINE_START(VIPER, "Arcom/Eurotech VIPER SBC")
+	/* Maintainer: Marc Zyngier <maz@misterjones.org> */
+	.phys_io	= 0x40000000,
+	.io_pg_offst	= (io_p2v(0x40000000) >> 18) & 0xfffc,
+	.boot_params	= 0xa0000100,
+	.map_io		= viper_map_io,
+	.init_irq	= viper_init_irq,
+	.timer          = &pxa_timer,
+	.init_machine	= viper_init,
+MACHINE_END
diff --git a/arch/arm/mach-pxa/zylonite.c b/arch/arm/mach-pxa/zylonite.c
index 0cb65b5..8138044 100644
--- a/arch/arm/mach-pxa/zylonite.c
+++ b/arch/arm/mach-pxa/zylonite.c
@@ -29,6 +29,7 @@
 #include <mach/pxafb.h>
 #include <mach/zylonite.h>
 #include <mach/mmc.h>
+#include <mach/ohci.h>
 #include <mach/pxa27x_keypad.h>
 #include <mach/pxa3xx_nand.h>
 
@@ -423,6 +424,21 @@
 static inline void zylonite_init_nand(void) {}
 #endif /* CONFIG_MTD_NAND_PXA3xx || CONFIG_MTD_NAND_PXA3xx_MODULE */
 
+#if defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE)
+static struct pxaohci_platform_data zylonite_ohci_info = {
+	.port_mode	= PMM_PERPORT_MODE,
+	.flags		= ENABLE_PORT1 | ENABLE_PORT2 |
+			  POWER_CONTROL_LOW | POWER_SENSE_LOW,
+};
+
+static void __init zylonite_init_ohci(void)
+{
+	pxa_set_ohci_info(&zylonite_ohci_info);
+}
+#else
+static inline void zylonite_init_ohci(void) {}
+#endif /* CONFIG_USB_OHCI_HCD || CONFIG_USB_OHCI_HCD_MODULE */
+
 static void __init zylonite_init(void)
 {
 	/* board-processor specific initialization */
@@ -443,6 +459,7 @@
 	zylonite_init_keypad();
 	zylonite_init_nand();
 	zylonite_init_leds();
+	zylonite_init_ohci();
 }
 
 MACHINE_START(ZYLONITE, "PXA3xx Platform Development Kit (aka Zylonite)")
diff --git a/arch/arm/mach-pxa/zylonite_pxa300.c b/arch/arm/mach-pxa/zylonite_pxa300.c
index 095f5c6..4653888 100644
--- a/arch/arm/mach-pxa/zylonite_pxa300.c
+++ b/arch/arm/mach-pxa/zylonite_pxa300.c
@@ -73,6 +73,12 @@
 	GPIO27_AC97_SDATA_OUT,
 	GPIO28_AC97_SYNC,
 
+	/* SSP3 */
+	GPIO91_SSP3_SCLK,
+	GPIO92_SSP3_FRM,
+	GPIO93_SSP3_TXD,
+	GPIO94_SSP3_RXD,
+
 	/* WM9713 IRQ */
 	GPIO26_GPIO,
 
@@ -113,6 +119,10 @@
 	GPIO13_MMC2_CLK,
 	GPIO14_MMC2_CMD,
 
+	/* USB Host */
+	GPIO0_2_USBH_PEN,
+	GPIO1_2_USBH_PWR,
+
 	/* Standard I2C */
 	GPIO21_I2C_SCL,
 	GPIO22_I2C_SDA,
@@ -209,7 +219,7 @@
 	},
 };
 
-struct i2c_board_info zylonite_i2c_board_info[] = {
+static struct i2c_board_info zylonite_i2c_board_info[] = {
 	{
 		.type		= "pca9539",
 		.addr		= 0x74,
diff --git a/arch/arm/mach-pxa/zylonite_pxa320.c b/arch/arm/mach-pxa/zylonite_pxa320.c
index 9879d7d..0f24474 100644
--- a/arch/arm/mach-pxa/zylonite_pxa320.c
+++ b/arch/arm/mach-pxa/zylonite_pxa320.c
@@ -69,6 +69,12 @@
 	GPIO39_AC97_BITCLK,
 	GPIO40_AC97_nACRESET,
 
+	/* SSP3 */
+	GPIO89_SSP3_SCLK,
+	GPIO90_SSP3_FRM,
+	GPIO91_SSP3_TXD,
+	GPIO92_SSP3_RXD,
+
 	/* WM9713 IRQ */
 	GPIO15_GPIO,
 
@@ -117,6 +123,10 @@
 	GPIO28_MMC2_CLK,
 	GPIO29_MMC2_CMD,
 
+	/* USB Host */
+	GPIO2_2_USBH_PEN,
+	GPIO3_2_USBH_PWR,
+
 	/* Debug LEDs */
 	GPIO1_2_GPIO | MFP_LPM_DRIVE_HIGH,
 	GPIO4_2_GPIO | MFP_LPM_DRIVE_HIGH,
diff --git a/arch/arm/mach-realview/core.c b/arch/arm/mach-realview/core.c
index 4f9c84a..2f04d54 100644
--- a/arch/arm/mach-realview/core.c
+++ b/arch/arm/mach-realview/core.c
@@ -27,10 +27,10 @@
 #include <linux/amba/clcd.h>
 #include <linux/clocksource.h>
 #include <linux/clockchips.h>
+#include <linux/io.h>
 
 #include <asm/system.h>
 #include <mach/hardware.h>
-#include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/leds.h>
 #include <asm/hardware/arm_timer.h>
diff --git a/arch/arm/mach-realview/core.h b/arch/arm/mach-realview/core.h
index 33dbbb4..3cea92c 100644
--- a/arch/arm/mach-realview/core.h
+++ b/arch/arm/mach-realview/core.h
@@ -23,9 +23,9 @@
 #define __ASM_ARCH_REALVIEW_H
 
 #include <linux/amba/bus.h>
+#include <linux/io.h>
 
 #include <asm/leds.h>
-#include <asm/io.h>
 
 #define AMBA_DEVICE(name,busid,base,plat)			\
 static struct amba_device name##_device = {			\
diff --git a/arch/arm/mach-realview/include/mach/system.h b/arch/arm/mach-realview/include/mach/system.h
index 4d3c8f3..a2f61c7 100644
--- a/arch/arm/mach-realview/include/mach/system.h
+++ b/arch/arm/mach-realview/include/mach/system.h
@@ -21,8 +21,8 @@
 #ifndef __ASM_ARCH_SYSTEM_H
 #define __ASM_ARCH_SYSTEM_H
 
+#include <linux/io.h>
 #include <mach/hardware.h>
-#include <asm/io.h>
 #include <mach/platform.h>
 
 static inline void arch_idle(void)
diff --git a/arch/arm/mach-realview/localtimer.c b/arch/arm/mach-realview/localtimer.c
index 82fa1f2..44d178c 100644
--- a/arch/arm/mach-realview/localtimer.c
+++ b/arch/arm/mach-realview/localtimer.c
@@ -17,11 +17,11 @@
 #include <linux/percpu.h>
 #include <linux/clockchips.h>
 #include <linux/irq.h>
+#include <linux/io.h>
 
 #include <asm/hardware/arm_twd.h>
 #include <asm/hardware/gic.h>
 #include <mach/hardware.h>
-#include <asm/io.h>
 #include <asm/irq.h>
 
 static DEFINE_PER_CPU(struct clock_event_device, local_clockevent);
diff --git a/arch/arm/mach-realview/platsmp.c b/arch/arm/mach-realview/platsmp.c
index 1907d22..e102aeb 100644
--- a/arch/arm/mach-realview/platsmp.c
+++ b/arch/arm/mach-realview/platsmp.c
@@ -13,10 +13,10 @@
 #include <linux/delay.h>
 #include <linux/device.h>
 #include <linux/smp.h>
+#include <linux/io.h>
 
 #include <asm/cacheflush.h>
 #include <mach/hardware.h>
-#include <asm/io.h>
 #include <asm/mach-types.h>
 
 #include <mach/board-eb.h>
diff --git a/arch/arm/mach-realview/realview_eb.c b/arch/arm/mach-realview/realview_eb.c
index 19a9968..eb829eb 100644
--- a/arch/arm/mach-realview/realview_eb.c
+++ b/arch/arm/mach-realview/realview_eb.c
@@ -23,9 +23,9 @@
 #include <linux/platform_device.h>
 #include <linux/sysdev.h>
 #include <linux/amba/bus.h>
+#include <linux/io.h>
 
 #include <mach/hardware.h>
-#include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/leds.h>
 #include <asm/mach-types.h>
diff --git a/arch/arm/mach-realview/realview_pb1176.c b/arch/arm/mach-realview/realview_pb1176.c
index 0986cbd..cccdb3e 100644
--- a/arch/arm/mach-realview/realview_pb1176.c
+++ b/arch/arm/mach-realview/realview_pb1176.c
@@ -23,9 +23,9 @@
 #include <linux/platform_device.h>
 #include <linux/sysdev.h>
 #include <linux/amba/bus.h>
+#include <linux/io.h>
 
 #include <mach/hardware.h>
-#include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/leds.h>
 #include <asm/mach-types.h>
diff --git a/arch/arm/mach-realview/realview_pb11mp.c b/arch/arm/mach-realview/realview_pb11mp.c
index f4e7135..8b86314 100644
--- a/arch/arm/mach-realview/realview_pb11mp.c
+++ b/arch/arm/mach-realview/realview_pb11mp.c
@@ -23,9 +23,9 @@
 #include <linux/platform_device.h>
 #include <linux/sysdev.h>
 #include <linux/amba/bus.h>
+#include <linux/io.h>
 
 #include <mach/hardware.h>
-#include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/leds.h>
 #include <asm/mach-types.h>
diff --git a/arch/arm/mach-rpc/dma.c b/arch/arm/mach-rpc/dma.c
index 4b19fe4..7958a30 100644
--- a/arch/arm/mach-rpc/dma.c
+++ b/arch/arm/mach-rpc/dma.c
@@ -14,11 +14,11 @@
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/dma-mapping.h>
+#include <linux/io.h>
 
 #include <asm/page.h>
 #include <asm/dma.h>
 #include <asm/fiq.h>
-#include <asm/io.h>
 #include <asm/irq.h>
 #include <mach/hardware.h>
 #include <asm/uaccess.h>
diff --git a/arch/arm/mach-rpc/include/mach/memory.h b/arch/arm/mach-rpc/include/mach/memory.h
index 05425d5..9bf7e43 100644
--- a/arch/arm/mach-rpc/include/mach/memory.h
+++ b/arch/arm/mach-rpc/include/mach/memory.h
@@ -36,4 +36,12 @@
 #define FLUSH_BASE_PHYS		0x00000000
 #define FLUSH_BASE		0xdf000000
 
+/*
+ * Sparsemem support.  Each section is a maximum of 64MB.  The sections
+ * are offset by 128MB and can cover 128MB, so that gives us a maximum
+ * of 29 physmem bits.
+ */
+#define MAX_PHYSMEM_BITS	29
+#define SECTION_SIZE_BITS	26
+
 #endif
diff --git a/arch/arm/mach-rpc/include/mach/system.h b/arch/arm/mach-rpc/include/mach/system.h
index 54d6e3f..bd7268ba 100644
--- a/arch/arm/mach-rpc/include/mach/system.h
+++ b/arch/arm/mach-rpc/include/mach/system.h
@@ -7,9 +7,9 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  */
+#include <linux/io.h>
 #include <mach/hardware.h>
 #include <asm/hardware/iomd.h>
-#include <asm/io.h>
 
 static inline void arch_idle(void)
 {
diff --git a/arch/arm/mach-rpc/include/mach/uncompress.h b/arch/arm/mach-rpc/include/mach/uncompress.h
index baa9c866..d586236 100644
--- a/arch/arm/mach-rpc/include/mach/uncompress.h
+++ b/arch/arm/mach-rpc/include/mach/uncompress.h
@@ -9,8 +9,8 @@
  */
 #define VIDMEM ((char *)SCREEN_START)
  
+#include <linux/io.h>
 #include <mach/hardware.h>
-#include <asm/io.h>
 #include <asm/setup.h>
 #include <asm/page.h>
 
diff --git a/arch/arm/mach-rpc/irq.c b/arch/arm/mach-rpc/irq.c
index 7a02962..9dd15d6 100644
--- a/arch/arm/mach-rpc/irq.c
+++ b/arch/arm/mach-rpc/irq.c
@@ -1,10 +1,10 @@
 #include <linux/init.h>
 #include <linux/list.h>
+#include <linux/io.h>
 
 #include <asm/mach/irq.h>
 #include <asm/hardware/iomd.h>
 #include <asm/irq.h>
-#include <asm/io.h>
 
 static void iomd_ack_irq_a(unsigned int irq)
 {
diff --git a/arch/arm/mach-rpc/riscpc.c b/arch/arm/mach-rpc/riscpc.c
index ce8470fea..e88d417 100644
--- a/arch/arm/mach-rpc/riscpc.c
+++ b/arch/arm/mach-rpc/riscpc.c
@@ -18,9 +18,9 @@
 #include <linux/device.h>
 #include <linux/serial_8250.h>
 #include <linux/ata_platform.h>
+#include <linux/io.h>
 
 #include <asm/elf.h>
-#include <asm/io.h>
 #include <asm/mach-types.h>
 #include <mach/hardware.h>
 #include <asm/page.h>
diff --git a/arch/arm/mach-s3c2400/gpio.c b/arch/arm/mach-s3c2400/gpio.c
index 148d0dd..7a7ed417 100644
--- a/arch/arm/mach-s3c2400/gpio.c
+++ b/arch/arm/mach-s3c2400/gpio.c
@@ -24,10 +24,10 @@
 #include <linux/module.h>
 #include <linux/interrupt.h>
 #include <linux/ioport.h>
+#include <linux/io.h>
 
 #include <mach/hardware.h>
 #include <asm/irq.h>
-#include <asm/io.h>
 
 #include <mach/regs-gpio.h>
 
diff --git a/arch/arm/mach-s3c2410/bast-irq.c b/arch/arm/mach-s3c2410/bast-irq.c
index c66021b..7573800 100644
--- a/arch/arm/mach-s3c2410/bast-irq.c
+++ b/arch/arm/mach-s3c2410/bast-irq.c
@@ -25,12 +25,12 @@
 #include <linux/module.h>
 #include <linux/ioport.h>
 #include <linux/sysdev.h>
+#include <linux/io.h>
 
 #include <asm/mach-types.h>
 
 #include <mach/hardware.h>
 #include <asm/irq.h>
-#include <asm/io.h>
 
 #include <asm/mach/irq.h>
 
@@ -130,8 +130,7 @@
 		for (i = 0; stat != 0; i++, stat >>= 1) {
 			if (stat & 1) {
 				irqno = bast_pc104_irqs[i];
-				desc = irq_desc + irqno;
-				desc_handle_irq(irqno, desc);
+				generic_handle_irq(irqno);
 			}
 		}
 	}
diff --git a/arch/arm/mach-s3c2410/clock.c b/arch/arm/mach-s3c2410/clock.c
index 1322851..fef646c 100644
--- a/arch/arm/mach-s3c2410/clock.c
+++ b/arch/arm/mach-s3c2410/clock.c
@@ -31,11 +31,11 @@
 #include <linux/mutex.h>
 #include <linux/delay.h>
 #include <linux/serial_core.h>
+#include <linux/io.h>
 
 #include <asm/mach/map.h>
 
 #include <mach/hardware.h>
-#include <asm/io.h>
 
 #include <asm/plat-s3c/regs-serial.h>
 #include <mach/regs-clock.h>
diff --git a/arch/arm/mach-s3c2410/gpio.c b/arch/arm/mach-s3c2410/gpio.c
index c6eefb1..36a3132 100644
--- a/arch/arm/mach-s3c2410/gpio.c
+++ b/arch/arm/mach-s3c2410/gpio.c
@@ -25,10 +25,10 @@
 #include <linux/module.h>
 #include <linux/interrupt.h>
 #include <linux/ioport.h>
+#include <linux/io.h>
 
 #include <mach/hardware.h>
 #include <asm/irq.h>
-#include <asm/io.h>
 
 #include <mach/regs-gpio.h>
 
diff --git a/arch/arm/mach-s3c2410/include/mach/system-reset.h b/arch/arm/mach-s3c2410/include/mach/system-reset.h
index ec2defe..43535a0 100644
--- a/arch/arm/mach-s3c2410/include/mach/system-reset.h
+++ b/arch/arm/mach-s3c2410/include/mach/system-reset.h
@@ -11,7 +11,7 @@
 */
 
 #include <mach/hardware.h>
-#include <asm/io.h>
+#include <linux/io.h>
 
 #include <asm/plat-s3c/regs-watchdog.h>
 #include <mach/regs-clock.h>
diff --git a/arch/arm/mach-s3c2410/include/mach/system.h b/arch/arm/mach-s3c2410/include/mach/system.h
index e9f676b..a8cbca6 100644
--- a/arch/arm/mach-s3c2410/include/mach/system.h
+++ b/arch/arm/mach-s3c2410/include/mach/system.h
@@ -10,8 +10,8 @@
  * published by the Free Software Foundation.
 */
 
+#include <linux/io.h>
 #include <mach/hardware.h>
-#include <asm/io.h>
 
 #include <mach/map.h>
 #include <mach/idle.h>
diff --git a/arch/arm/mach-s3c2410/mach-amlm5900.c b/arch/arm/mach-s3c2410/mach-amlm5900.c
index f0de3c2..527f88a 100644
--- a/arch/arm/mach-s3c2410/mach-amlm5900.c
+++ b/arch/arm/mach-s3c2410/mach-amlm5900.c
@@ -36,6 +36,7 @@
 #include <linux/platform_device.h>
 #include <linux/proc_fs.h>
 #include <linux/serial_core.h>
+#include <linux/io.h>
 
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
@@ -43,7 +44,6 @@
 #include <asm/mach/flash.h>
 
 #include <mach/hardware.h>
-#include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/mach-types.h>
 #include <mach/fb.h>
diff --git a/arch/arm/mach-s3c2410/mach-bast.c b/arch/arm/mach-s3c2410/mach-bast.c
index 24c6334..e4368e6 100644
--- a/arch/arm/mach-s3c2410/mach-bast.c
+++ b/arch/arm/mach-s3c2410/mach-bast.c
@@ -22,6 +22,7 @@
 #include <linux/dm9000.h>
 #include <linux/ata_platform.h>
 #include <linux/i2c.h>
+#include <linux/io.h>
 
 #include <net/ax88796.h>
 
@@ -34,7 +35,6 @@
 #include <mach/bast-cpld.h>
 
 #include <mach/hardware.h>
-#include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/mach-types.h>
 
diff --git a/arch/arm/mach-s3c2410/mach-h1940.c b/arch/arm/mach-s3c2410/mach-h1940.c
index e35933a..85e710f 100644
--- a/arch/arm/mach-s3c2410/mach-h1940.c
+++ b/arch/arm/mach-s3c2410/mach-h1940.c
@@ -20,13 +20,13 @@
 #include <linux/sysdev.h>
 #include <linux/serial_core.h>
 #include <linux/platform_device.h>
+#include <linux/io.h>
 
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
 #include <asm/mach/irq.h>
 
 #include <mach/hardware.h>
-#include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/mach-types.h>
 
diff --git a/arch/arm/mach-s3c2410/mach-n30.c b/arch/arm/mach-s3c2410/mach-n30.c
index 80fe2ed..3ece2d0 100644
--- a/arch/arm/mach-s3c2410/mach-n30.c
+++ b/arch/arm/mach-s3c2410/mach-n30.c
@@ -25,9 +25,9 @@
 #include <linux/platform_device.h>
 #include <linux/serial_core.h>
 #include <linux/timer.h>
+#include <linux/io.h>
 
 #include <mach/hardware.h>
-#include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/mach-types.h>
 
diff --git a/arch/arm/mach-s3c2410/mach-otom.c b/arch/arm/mach-s3c2410/mach-otom.c
index 606ee15..c4dfe3e 100644
--- a/arch/arm/mach-s3c2410/mach-otom.c
+++ b/arch/arm/mach-s3c2410/mach-otom.c
@@ -17,6 +17,7 @@
 #include <linux/init.h>
 #include <linux/serial_core.h>
 #include <linux/platform_device.h>
+#include <linux/io.h>
 
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
@@ -25,7 +26,6 @@
 #include <mach/otom-map.h>
 
 #include <mach/hardware.h>
-#include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/mach-types.h>
 
diff --git a/arch/arm/mach-s3c2410/mach-qt2410.c b/arch/arm/mach-s3c2410/mach-qt2410.c
index 7d34844..97c1319 100644
--- a/arch/arm/mach-s3c2410/mach-qt2410.c
+++ b/arch/arm/mach-s3c2410/mach-qt2410.c
@@ -32,7 +32,7 @@
 #include <linux/serial_core.h>
 #include <linux/spi/spi.h>
 #include <linux/spi/spi_bitbang.h>
-
+#include <linux/io.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/nand.h>
 #include <linux/mtd/nand_ecc.h>
@@ -43,7 +43,6 @@
 #include <asm/mach/irq.h>
 
 #include <mach/hardware.h>
-#include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/mach-types.h>
 
diff --git a/arch/arm/mach-s3c2410/mach-smdk2410.c b/arch/arm/mach-s3c2410/mach-smdk2410.c
index b88939d..d49e58a 100644
--- a/arch/arm/mach-s3c2410/mach-smdk2410.c
+++ b/arch/arm/mach-s3c2410/mach-smdk2410.c
@@ -36,13 +36,13 @@
 #include <linux/init.h>
 #include <linux/serial_core.h>
 #include <linux/platform_device.h>
+#include <linux/io.h>
 
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
 #include <asm/mach/irq.h>
 
 #include <mach/hardware.h>
-#include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/mach-types.h>
 
diff --git a/arch/arm/mach-s3c2410/mach-tct_hammer.c b/arch/arm/mach-s3c2410/mach-tct_hammer.c
index ec87306..cc2e79f 100644
--- a/arch/arm/mach-s3c2410/mach-tct_hammer.c
+++ b/arch/arm/mach-s3c2410/mach-tct_hammer.c
@@ -33,6 +33,7 @@
 #include <linux/device.h>
 #include <linux/platform_device.h>
 #include <linux/serial_core.h>
+#include <linux/io.h>
 
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
@@ -40,7 +41,6 @@
 #include <asm/mach/flash.h>
 
 #include <mach/hardware.h>
-#include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/mach-types.h>
 
diff --git a/arch/arm/mach-s3c2410/mach-vr1000.c b/arch/arm/mach-s3c2410/mach-vr1000.c
index fbc0213..ed3acb0 100644
--- a/arch/arm/mach-s3c2410/mach-vr1000.c
+++ b/arch/arm/mach-s3c2410/mach-vr1000.c
@@ -25,6 +25,7 @@
 #include <linux/tty.h>
 #include <linux/serial_8250.h>
 #include <linux/serial_reg.h>
+#include <linux/io.h>
 
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
@@ -36,7 +37,6 @@
 #include <mach/vr1000-cpld.h>
 
 #include <mach/hardware.h>
-#include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/mach-types.h>
 
diff --git a/arch/arm/mach-s3c2410/pm.c b/arch/arm/mach-s3c2410/pm.c
index ba43ff9..733f8a2 100644
--- a/arch/arm/mach-s3c2410/pm.c
+++ b/arch/arm/mach-s3c2410/pm.c
@@ -25,9 +25,9 @@
 #include <linux/errno.h>
 #include <linux/time.h>
 #include <linux/sysdev.h>
+#include <linux/io.h>
 
 #include <mach/hardware.h>
-#include <asm/io.h>
 
 #include <asm/mach-types.h>
 
diff --git a/arch/arm/mach-s3c2410/s3c2410.c b/arch/arm/mach-s3c2410/s3c2410.c
index 5d977f9..b1e658c 100644
--- a/arch/arm/mach-s3c2410/s3c2410.c
+++ b/arch/arm/mach-s3c2410/s3c2410.c
@@ -19,13 +19,13 @@
 #include <linux/sysdev.h>
 #include <linux/serial_core.h>
 #include <linux/platform_device.h>
+#include <linux/io.h>
 
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
 #include <asm/mach/irq.h>
 
 #include <mach/hardware.h>
-#include <asm/io.h>
 #include <asm/irq.h>
 
 #include <mach/regs-clock.h>
diff --git a/arch/arm/mach-s3c2410/usb-simtec.c b/arch/arm/mach-s3c2410/usb-simtec.c
index 4dacf8a..eb6fc0b 100644
--- a/arch/arm/mach-s3c2410/usb-simtec.c
+++ b/arch/arm/mach-s3c2410/usb-simtec.c
@@ -21,6 +21,7 @@
 #include <linux/timer.h>
 #include <linux/init.h>
 #include <linux/device.h>
+#include <linux/io.h>
 
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
@@ -32,7 +33,6 @@
 #include <mach/regs-gpio.h>
 
 #include <mach/hardware.h>
-#include <asm/io.h>
 #include <asm/irq.h>
 
 #include <asm/plat-s3c24xx/devs.h>
diff --git a/arch/arm/mach-s3c2412/clock.c b/arch/arm/mach-s3c2412/clock.c
index af4b2ce..5fbaac6 100644
--- a/arch/arm/mach-s3c2412/clock.c
+++ b/arch/arm/mach-s3c2412/clock.c
@@ -31,11 +31,11 @@
 #include <linux/mutex.h>
 #include <linux/delay.h>
 #include <linux/serial_core.h>
+#include <linux/io.h>
 
 #include <asm/mach/map.h>
 
 #include <mach/hardware.h>
-#include <asm/io.h>
 
 #include <asm/plat-s3c/regs-serial.h>
 #include <mach/regs-clock.h>
diff --git a/arch/arm/mach-s3c2412/dma.c b/arch/arm/mach-s3c2412/dma.c
index 22fc04a..dcfff6b 100644
--- a/arch/arm/mach-s3c2412/dma.c
+++ b/arch/arm/mach-s3c2412/dma.c
@@ -16,10 +16,10 @@
 #include <linux/init.h>
 #include <linux/sysdev.h>
 #include <linux/serial_core.h>
+#include <linux/io.h>
 
 #include <asm/dma.h>
 #include <mach/dma.h>
-#include <asm/io.h>
 
 #include <asm/plat-s3c24xx/dma.h>
 #include <asm/plat-s3c24xx/cpu.h>
diff --git a/arch/arm/mach-s3c2412/irq.c b/arch/arm/mach-s3c2412/irq.c
index ac62b79..41720f2 100644
--- a/arch/arm/mach-s3c2412/irq.c
+++ b/arch/arm/mach-s3c2412/irq.c
@@ -24,10 +24,10 @@
 #include <linux/interrupt.h>
 #include <linux/ioport.h>
 #include <linux/sysdev.h>
+#include <linux/io.h>
 
 #include <mach/hardware.h>
 #include <asm/irq.h>
-#include <asm/io.h>
 
 #include <asm/mach/irq.h>
 
@@ -123,10 +123,10 @@
 	subsrc  &= ~submsk;
 
 	if (subsrc & INTBIT(IRQ_S3C2412_SDI))
-		desc_handle_irq(IRQ_S3C2412_SDI, irq_desc + IRQ_S3C2412_SDI);
+		generic_handle_irq(IRQ_S3C2412_SDI);
 
 	if (subsrc & INTBIT(IRQ_S3C2412_CF))
-		desc_handle_irq(IRQ_S3C2412_CF, irq_desc + IRQ_S3C2412_CF);
+		generic_handle_irq(IRQ_S3C2412_CF);
 }
 
 #define INTMSK_CFSDI	(1UL << (IRQ_S3C2412_CFSDI - IRQ_EINT0))
diff --git a/arch/arm/mach-s3c2412/mach-smdk2413.c b/arch/arm/mach-s3c2412/mach-smdk2413.c
index 80affb1..8f8d911 100644
--- a/arch/arm/mach-s3c2412/mach-smdk2413.c
+++ b/arch/arm/mach-s3c2412/mach-smdk2413.c
@@ -19,6 +19,7 @@
 #include <linux/init.h>
 #include <linux/serial_core.h>
 #include <linux/platform_device.h>
+#include <linux/io.h>
 
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
@@ -27,7 +28,6 @@
 #include <mach/hardware.h>
 #include <asm/hardware/iomd.h>
 #include <asm/setup.h>
-#include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/mach-types.h>
 
diff --git a/arch/arm/mach-s3c2412/mach-vstms.c b/arch/arm/mach-s3c2412/mach-vstms.c
index 7a08b37..bb9bf63 100644
--- a/arch/arm/mach-s3c2412/mach-vstms.c
+++ b/arch/arm/mach-s3c2412/mach-vstms.c
@@ -17,7 +17,7 @@
 #include <linux/init.h>
 #include <linux/serial_core.h>
 #include <linux/platform_device.h>
-
+#include <linux/io.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/nand.h>
 #include <linux/mtd/nand_ecc.h>
@@ -29,7 +29,6 @@
 
 #include <mach/hardware.h>
 #include <asm/setup.h>
-#include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/mach-types.h>
 
diff --git a/arch/arm/mach-s3c2412/pm.c b/arch/arm/mach-s3c2412/pm.c
index 737523a..9540ef7 100644
--- a/arch/arm/mach-s3c2412/pm.c
+++ b/arch/arm/mach-s3c2412/pm.c
@@ -18,9 +18,9 @@
 #include <linux/init.h>
 #include <linux/sysdev.h>
 #include <linux/platform_device.h>
+#include <linux/io.h>
 
 #include <mach/hardware.h>
-#include <asm/io.h>
 #include <asm/irq.h>
 
 #include <mach/regs-power.h>
diff --git a/arch/arm/mach-s3c2412/s3c2412.c b/arch/arm/mach-s3c2412/s3c2412.c
index d278010..42440fc 100644
--- a/arch/arm/mach-s3c2412/s3c2412.c
+++ b/arch/arm/mach-s3c2412/s3c2412.c
@@ -20,6 +20,7 @@
 #include <linux/sysdev.h>
 #include <linux/serial_core.h>
 #include <linux/platform_device.h>
+#include <linux/io.h>
 
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
@@ -27,7 +28,6 @@
 
 #include <mach/hardware.h>
 #include <asm/proc-fns.h>
-#include <asm/io.h>
 #include <asm/irq.h>
 
 #include <mach/reset.h>
diff --git a/arch/arm/mach-s3c2440/clock.c b/arch/arm/mach-s3c2440/clock.c
index 95567e6..40503a6 100644
--- a/arch/arm/mach-s3c2440/clock.c
+++ b/arch/arm/mach-s3c2440/clock.c
@@ -33,11 +33,11 @@
 #include <linux/ioport.h>
 #include <linux/mutex.h>
 #include <linux/clk.h>
+#include <linux/io.h>
 
 #include <mach/hardware.h>
 #include <asm/atomic.h>
 #include <asm/irq.h>
-#include <asm/io.h>
 
 #include <mach/regs-clock.h>
 
diff --git a/arch/arm/mach-s3c2440/dsc.c b/arch/arm/mach-s3c2440/dsc.c
index c0c6743..4f7d06b 100644
--- a/arch/arm/mach-s3c2440/dsc.c
+++ b/arch/arm/mach-s3c2440/dsc.c
@@ -15,13 +15,13 @@
 #include <linux/interrupt.h>
 #include <linux/init.h>
 #include <linux/module.h>
+#include <linux/io.h>
 
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
 #include <asm/mach/irq.h>
 
 #include <mach/hardware.h>
-#include <asm/io.h>
 #include <asm/irq.h>
 
 #include <mach/regs-gpio.h>
diff --git a/arch/arm/mach-s3c2440/irq.c b/arch/arm/mach-s3c2440/irq.c
index 276b823..33e3ede 100644
--- a/arch/arm/mach-s3c2440/irq.c
+++ b/arch/arm/mach-s3c2440/irq.c
@@ -24,10 +24,10 @@
 #include <linux/interrupt.h>
 #include <linux/ioport.h>
 #include <linux/sysdev.h>
+#include <linux/io.h>
 
 #include <mach/hardware.h>
 #include <asm/irq.h>
-#include <asm/io.h>
 
 #include <asm/mach/irq.h>
 
@@ -44,7 +44,6 @@
 				  struct irq_desc *desc)
 {
 	unsigned int subsrc, submsk;
-	struct irq_desc *mydesc;
 
 	/* read the current pending interrupts, and the mask
 	 * for what it is available */
@@ -58,12 +57,10 @@
 
 	if (subsrc != 0) {
 		if (subsrc & 1) {
-			mydesc = irq_desc + IRQ_S3C2440_WDT;
-			desc_handle_irq(IRQ_S3C2440_WDT, mydesc);
+			generic_handle_irq(IRQ_S3C2440_WDT);
 		}
 		if (subsrc & 2) {
-			mydesc = irq_desc + IRQ_S3C2440_AC97;
-			desc_handle_irq(IRQ_S3C2440_AC97, mydesc);
+			generic_handle_irq(IRQ_S3C2440_AC97);
 		}
 	}
 }
diff --git a/arch/arm/mach-s3c2440/mach-anubis.c b/arch/arm/mach-s3c2440/mach-anubis.c
index 441f4bc..19eb0e52 100644
--- a/arch/arm/mach-s3c2440/mach-anubis.c
+++ b/arch/arm/mach-s3c2440/mach-anubis.c
@@ -19,7 +19,7 @@
 #include <linux/platform_device.h>
 #include <linux/ata_platform.h>
 #include <linux/i2c.h>
-
+#include <linux/io.h>
 #include <linux/sm501.h>
 #include <linux/sm501-regs.h>
 
@@ -32,7 +32,6 @@
 #include <mach/anubis-cpld.h>
 
 #include <mach/hardware.h>
-#include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/mach-types.h>
 
diff --git a/arch/arm/mach-s3c2440/mach-nexcoder.c b/arch/arm/mach-s3c2440/mach-nexcoder.c
index 1a5e702..49e828d 100644
--- a/arch/arm/mach-s3c2440/mach-nexcoder.c
+++ b/arch/arm/mach-s3c2440/mach-nexcoder.c
@@ -21,6 +21,7 @@
 #include <linux/string.h>
 #include <linux/serial_core.h>
 #include <linux/platform_device.h>
+#include <linux/io.h>
 
 #include <linux/mtd/map.h>
 
@@ -30,7 +31,6 @@
 
 #include <asm/setup.h>
 #include <mach/hardware.h>
-#include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/mach-types.h>
 
diff --git a/arch/arm/mach-s3c2440/mach-osiris.c b/arch/arm/mach-s3c2440/mach-osiris.c
index 8b83f93..85144aa 100644
--- a/arch/arm/mach-s3c2440/mach-osiris.c
+++ b/arch/arm/mach-s3c2440/mach-osiris.c
@@ -20,6 +20,7 @@
 #include <linux/serial_core.h>
 #include <linux/clk.h>
 #include <linux/i2c.h>
+#include <linux/io.h>
 
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
@@ -29,7 +30,6 @@
 #include <mach/osiris-cpld.h>
 
 #include <mach/hardware.h>
-#include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/mach-types.h>
 
diff --git a/arch/arm/mach-s3c2440/mach-rx3715.c b/arch/arm/mach-s3c2440/mach-rx3715.c
index e0b07e6..a4c6904 100644
--- a/arch/arm/mach-s3c2440/mach-rx3715.c
+++ b/arch/arm/mach-s3c2440/mach-rx3715.c
@@ -23,7 +23,7 @@
 #include <linux/platform_device.h>
 #include <linux/serial_core.h>
 #include <linux/serial.h>
-
+#include <linux/io.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/nand.h>
 #include <linux/mtd/nand_ecc.h>
@@ -34,7 +34,6 @@
 #include <asm/mach/irq.h>
 
 #include <mach/hardware.h>
-#include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/mach-types.h>
 
diff --git a/arch/arm/mach-s3c2440/mach-smdk2440.c b/arch/arm/mach-s3c2440/mach-smdk2440.c
index 327c8f3..7ac60b8 100644
--- a/arch/arm/mach-s3c2440/mach-smdk2440.c
+++ b/arch/arm/mach-s3c2440/mach-smdk2440.c
@@ -21,13 +21,13 @@
 #include <linux/init.h>
 #include <linux/serial_core.h>
 #include <linux/platform_device.h>
+#include <linux/io.h>
 
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
 #include <asm/mach/irq.h>
 
 #include <mach/hardware.h>
-#include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/mach-types.h>
 
diff --git a/arch/arm/mach-s3c2440/s3c2440.c b/arch/arm/mach-s3c2440/s3c2440.c
index d6b9a92..c81cdb3 100644
--- a/arch/arm/mach-s3c2440/s3c2440.c
+++ b/arch/arm/mach-s3c2440/s3c2440.c
@@ -20,13 +20,13 @@
 #include <linux/serial_core.h>
 #include <linux/sysdev.h>
 #include <linux/clk.h>
+#include <linux/io.h>
 
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
 #include <asm/mach/irq.h>
 
 #include <mach/hardware.h>
-#include <asm/io.h>
 #include <asm/irq.h>
 
 #include <asm/plat-s3c24xx/s3c2440.h>
diff --git a/arch/arm/mach-s3c2442/clock.c b/arch/arm/mach-s3c2442/clock.c
index 569b5c3..18f2ce4 100644
--- a/arch/arm/mach-s3c2442/clock.c
+++ b/arch/arm/mach-s3c2442/clock.c
@@ -33,11 +33,11 @@
 #include <linux/ioport.h>
 #include <linux/mutex.h>
 #include <linux/clk.h>
+#include <linux/io.h>
 
 #include <mach/hardware.h>
 #include <asm/atomic.h>
 #include <asm/irq.h>
-#include <asm/io.h>
 
 #include <mach/regs-clock.h>
 
diff --git a/arch/arm/mach-s3c2443/clock.c b/arch/arm/mach-s3c2443/clock.c
index 6a8d7cc..603b5ea 100644
--- a/arch/arm/mach-s3c2443/clock.c
+++ b/arch/arm/mach-s3c2443/clock.c
@@ -31,11 +31,11 @@
 #include <linux/mutex.h>
 #include <linux/delay.h>
 #include <linux/serial_core.h>
+#include <linux/io.h>
 
 #include <asm/mach/map.h>
 
 #include <mach/hardware.h>
-#include <asm/io.h>
 
 #include <mach/regs-s3c2443-clock.h>
 
diff --git a/arch/arm/mach-s3c2443/dma.c b/arch/arm/mach-s3c2443/dma.c
index c1ff03a..5d9ee77 100644
--- a/arch/arm/mach-s3c2443/dma.c
+++ b/arch/arm/mach-s3c2443/dma.c
@@ -16,10 +16,10 @@
 #include <linux/init.h>
 #include <linux/sysdev.h>
 #include <linux/serial_core.h>
+#include <linux/io.h>
 
 #include <asm/dma.h>
 #include <mach/dma.h>
-#include <asm/io.h>
 
 #include <asm/plat-s3c24xx/dma.h>
 #include <asm/plat-s3c24xx/cpu.h>
diff --git a/arch/arm/mach-s3c2443/irq.c b/arch/arm/mach-s3c2443/irq.c
index 9674de7..e44341d 100644
--- a/arch/arm/mach-s3c2443/irq.c
+++ b/arch/arm/mach-s3c2443/irq.c
@@ -24,10 +24,10 @@
 #include <linux/interrupt.h>
 #include <linux/ioport.h>
 #include <linux/sysdev.h>
+#include <linux/io.h>
 
 #include <mach/hardware.h>
 #include <asm/irq.h>
-#include <asm/io.h>
 
 #include <asm/mach/irq.h>
 
@@ -44,7 +44,6 @@
 {
 	unsigned int subsrc, submsk;
 	unsigned int end;
-	struct irq_desc *mydesc;
 
 	/* read the current pending interrupts, and the mask
 	 * for what it is available */
@@ -57,13 +56,11 @@
 	subsrc  &= (1 << len)-1;
 
 	end = len + irq;
-	mydesc = irq_desc + irq;
 
 	for (; irq < end && subsrc; irq++) {
 		if (subsrc & 1)
-			desc_handle_irq(irq, mydesc);
+			generic_handle_irq(irq);
 
-		mydesc++;
 		subsrc >>= 1;
 	}
 }
diff --git a/arch/arm/mach-s3c2443/mach-smdk2443.c b/arch/arm/mach-s3c2443/mach-smdk2443.c
index e3c0d58..f0d119d 100644
--- a/arch/arm/mach-s3c2443/mach-smdk2443.c
+++ b/arch/arm/mach-s3c2443/mach-smdk2443.c
@@ -21,13 +21,13 @@
 #include <linux/init.h>
 #include <linux/serial_core.h>
 #include <linux/platform_device.h>
+#include <linux/io.h>
 
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
 #include <asm/mach/irq.h>
 
 #include <mach/hardware.h>
-#include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/mach-types.h>
 
diff --git a/arch/arm/mach-s3c2443/s3c2443.c b/arch/arm/mach-s3c2443/s3c2443.c
index 37793f9..c973b68 100644
--- a/arch/arm/mach-s3c2443/s3c2443.c
+++ b/arch/arm/mach-s3c2443/s3c2443.c
@@ -20,13 +20,13 @@
 #include <linux/serial_core.h>
 #include <linux/sysdev.h>
 #include <linux/clk.h>
+#include <linux/io.h>
 
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
 #include <asm/mach/irq.h>
 
 #include <mach/hardware.h>
-#include <asm/io.h>
 #include <asm/irq.h>
 
 #include <mach/regs-s3c2443-clock.h>
diff --git a/arch/arm/mach-sa1100/badge4.c b/arch/arm/mach-sa1100/badge4.c
index 3efefbd..ab5883b 100644
--- a/arch/arm/mach-sa1100/badge4.c
+++ b/arch/arm/mach-sa1100/badge4.c
@@ -95,19 +95,19 @@
  *   One-hundred-twenty-seven 32 KiW Main Blocks (8128 Ki b)
  */
 static struct mtd_partition badge4_partitions[] = {
-        {
-                .name           = "BLOB boot loader",
-                .offset         = 0,
-                .size           = 0x0000A000
-        }, {
-                .name           = "params",
-                .offset         = MTDPART_OFS_APPEND,
-                .size           = 0x00006000
-        }, {
-                .name           = "root",
-                .offset         = MTDPART_OFS_APPEND,
-                .size           = MTDPART_SIZ_FULL
-        }
+	{
+		.name	= "BLOB boot loader",
+		.offset	= 0,
+		.size	= 0x0000A000
+	}, {
+		.name	= "params",
+		.offset	= MTDPART_OFS_APPEND,
+		.size	= 0x00006000
+	}, {
+		.name	= "root",
+		.offset	= MTDPART_OFS_APPEND,
+		.size	= MTDPART_SIZ_FULL
+	}
 };
 
 static struct flash_platform_data badge4_flash_data = {
@@ -126,7 +126,7 @@
 
 static int __init five_v_on_setup(char *ignore)
 {
-        five_v_on = 1;
+	five_v_on = 1;
 	return 1;
 }
 __setup("five_v_on", five_v_on_setup);
@@ -171,15 +171,15 @@
 	GPCR  = BADGE4_GPIO_TESTPT_J7;
 	GPDR |= BADGE4_GPIO_TESTPT_J7;
 
- 	/* 5V supply rail. */
- 	GPCR  = BADGE4_GPIO_PCMEN5V;		/* initially off */
-  	GPDR |= BADGE4_GPIO_PCMEN5V;
+	/* 5V supply rail. */
+	GPCR  = BADGE4_GPIO_PCMEN5V;		/* initially off */
+	GPDR |= BADGE4_GPIO_PCMEN5V;
 
 	/* CPLD sdram type inputs; set up by blob */
 	//GPDR |= (BADGE4_GPIO_SDTYP1 | BADGE4_GPIO_SDTYP0);
 	printk(KERN_DEBUG __FILE__ ": SDRAM CPLD typ1=%d typ0=%d\n",
-	       !!(GPLR & BADGE4_GPIO_SDTYP1),
-	       !!(GPLR & BADGE4_GPIO_SDTYP0));
+		!!(GPLR & BADGE4_GPIO_SDTYP1),
+		!!(GPLR & BADGE4_GPIO_SDTYP0));
 
 	/* SA1111 reset pin; set up by blob */
 	//GPSR  = BADGE4_GPIO_SA1111_NRST;
@@ -205,8 +205,8 @@
 	ret = badge4_sa1111_init();
 	if (ret < 0)
 		printk(KERN_ERR
-		       "%s: SA-1111 initialization failed (%d)\n",
-		       __func__, ret);
+			"%s: SA-1111 initialization failed (%d)\n",
+			__func__, ret);
 
 
 	/* maybe turn on 5v0 from the start */
@@ -254,7 +254,7 @@
 
 
 static struct map_desc badge4_io_desc[] __initdata = {
-  	{	/* SRAM  bank 1 */
+	{	/* SRAM  bank 1 */
 		.virtual	= 0xf1000000,
 		.pfn		= __phys_to_pfn(0x08000000),
 		.length		= 0x00100000,
diff --git a/arch/arm/mach-sa1100/cpu-sa1100.c b/arch/arm/mach-sa1100/cpu-sa1100.c
index da3a898..f7fa0347 100644
--- a/arch/arm/mach-sa1100/cpu-sa1100.c
+++ b/arch/arm/mach-sa1100/cpu-sa1100.c
@@ -88,6 +88,8 @@
 #include <linux/init.h>
 #include <linux/cpufreq.h>
 
+#include <asm/cputype.h>
+
 #include <mach/hardware.h>
 
 #include "generic.h"
@@ -240,7 +242,7 @@
 
 static int __init sa1100_dram_init(void)
 {
- 	if ((processor_id & CPU_SA1100_MASK) == CPU_SA1100_ID)
+	if (cpu_is_sa1100())
 		return cpufreq_register_driver(&sa1100_driver);
 	else
 		return -ENODEV;
diff --git a/arch/arm/mach-sa1100/cpu-sa1110.c b/arch/arm/mach-sa1100/cpu-sa1110.c
index 029dbfb..3e4fb21 100644
--- a/arch/arm/mach-sa1100/cpu-sa1110.c
+++ b/arch/arm/mach-sa1100/cpu-sa1110.c
@@ -23,10 +23,11 @@
 #include <linux/cpufreq.h>
 #include <linux/delay.h>
 #include <linux/init.h>
+#include <linux/io.h>
 
 #include <mach/hardware.h>
+#include <asm/cputype.h>
 #include <asm/mach-types.h>
-#include <asm/io.h>
 #include <asm/system.h>
 
 #include "generic.h"
diff --git a/arch/arm/mach-sa1100/generic.c b/arch/arm/mach-sa1100/generic.c
index 1362994..c1fbd5b 100644
--- a/arch/arm/mach-sa1100/generic.c
+++ b/arch/arm/mach-sa1100/generic.c
@@ -18,9 +18,9 @@
 #include <linux/ioport.h>
 #include <linux/sched.h>	/* just for sched_clock() - funny that */
 #include <linux/platform_device.h>
+#include <linux/cnt32_to_63.h>
 
 #include <asm/div64.h>
-#include <asm/cnt32_to_63.h>
 #include <mach/hardware.h>
 #include <asm/system.h>
 #include <asm/pgtable.h>
@@ -42,7 +42,7 @@
 static const unsigned short cclk_frequency_100khz[NR_FREQS] = {
 	 590,	/*  59.0 MHz */
 	 737,	/*  73.7 MHz */
-	 885, 	/*  88.5 MHz */
+	 885,	/*  88.5 MHz */
 	1032,	/* 103.2 MHz */
 	1180,	/* 118.0 MHz */
 	1327,	/* 132.7 MHz */
@@ -52,10 +52,10 @@
 	1917,	/* 191.7 MHz */
 	2064,	/* 206.4 MHz */
 	2212,	/* 221.2 MHz */
-	2359,   /* 235.9 MHz */
-	2507,   /* 250.7 MHz */
-	2654,   /* 265.4 MHz */
-	2802    /* 280.2 MHz */
+	2359,	/* 235.9 MHz */
+	2507,	/* 250.7 MHz */
+	2654,	/* 265.4 MHz */
+	2802	/* 280.2 MHz */
 };
 
 #if defined(CONFIG_CPU_FREQ_SA1100) || defined(CONFIG_CPU_FREQ_SA1110)
@@ -113,7 +113,7 @@
 #else
 /*
  * We still need to provide this so building without cpufreq works.
- */ 
+ */
 unsigned int cpufreq_get(unsigned int cpu)
 {
 	return cclk_frequency_100khz[PPCR & 0xf] * 100;
@@ -389,7 +389,7 @@
  */
 
 static struct map_desc standard_io_desc[] __initdata = {
-  	{	/* PCM */
+	{	/* PCM */
 		.virtual	=  0xf8000000,
 		.pfn		= __phys_to_pfn(0x80000000),
 		.length		= 0x00100000,
diff --git a/arch/arm/mach-sa1100/include/mach/SA-1100.h b/arch/arm/mach-sa1100/include/mach/SA-1100.h
index 62aaf04..4f7ea01 100644
--- a/arch/arm/mach-sa1100/include/mach/SA-1100.h
+++ b/arch/arm/mach-sa1100/include/mach/SA-1100.h
@@ -2054,19 +2054,3 @@
                 	        	/* active display mode)            */
 #define LCCR3_OutEnH	(LCCR3_OEP*0)	/*  Output Enable active High      */
 #define LCCR3_OutEnL	(LCCR3_OEP*1)	/*  Output Enable active Low       */
-
-#ifndef __ASSEMBLY__
-extern unsigned int processor_id;
-#endif
-
-#define CPU_REVISION	(processor_id & 15)
-#define CPU_SA1110_A0	(0)
-#define CPU_SA1110_B0	(4)
-#define CPU_SA1110_B1	(5)
-#define CPU_SA1110_B2	(6)
-#define CPU_SA1110_B4	(8)
-
-#define CPU_SA1100_ID	(0x4401a110)
-#define CPU_SA1100_MASK	(0xfffffff0)
-#define CPU_SA1110_ID	(0x6901b110)
-#define CPU_SA1110_MASK	(0xfffffff0)
diff --git a/arch/arm/mach-sa1100/include/mach/hardware.h b/arch/arm/mach-sa1100/include/mach/hardware.h
index 5976435..b70846c 100644
--- a/arch/arm/mach-sa1100/include/mach/hardware.h
+++ b/arch/arm/mach-sa1100/include/mach/hardware.h
@@ -36,8 +36,26 @@
 #define io_v2p( x )             \
    ( (((x)&0x00ffffff) | (((x)&(0x30000000>>VIO_SHIFT))<<VIO_SHIFT)) + PIO_START )
 
+#define CPU_SA1110_A0	(0)
+#define CPU_SA1110_B0	(4)
+#define CPU_SA1110_B1	(5)
+#define CPU_SA1110_B2	(6)
+#define CPU_SA1110_B4	(8)
+
+#define CPU_SA1100_ID	(0x4401a110)
+#define CPU_SA1100_MASK	(0xfffffff0)
+#define CPU_SA1110_ID	(0x6901b110)
+#define CPU_SA1110_MASK	(0xfffffff0)
+
 #ifndef __ASSEMBLY__
 
+#include <asm/cputype.h>
+
+#define CPU_REVISION	(read_cpuid_id() & 15)
+
+#define cpu_is_sa1100()	((read_cpuid_id() & CPU_SA1100_MASK) == CPU_SA1100_ID)
+#define cpu_is_sa1110()	((read_cpuid_id() & CPU_SA1110_MASK) == CPU_SA1110_ID)
+
 # define __REG(x)	(*((volatile unsigned long *)io_p2v(x)))
 # define __PREG(x)	(io_v2p((unsigned long)&(x)))
 
diff --git a/arch/arm/mach-sa1100/include/mach/jornada720.h b/arch/arm/mach-sa1100/include/mach/jornada720.h
index bc12085..cc6b4bf 100644
--- a/arch/arm/mach-sa1100/include/mach/jornada720.h
+++ b/arch/arm/mach-sa1100/include/mach/jornada720.h
@@ -1,10 +1,10 @@
 /*
  * arch/arm/mach-sa1100/include/mach/jornada720.h
  *
- * This file contains SSP/MCU communication definitions for HP Jornada 710/720/728
+ * SSP/MCU communication definitions for HP Jornada 710/720/728
  *
- * Copyright (C) 2007 Kristoffer Ericson <Kristoffer.Ericson@gmail.com>
- *  Copyright (C) 2000 John Ankcorn <jca@lcs.mit.edu>
+ * Copyright 2007,2008 Kristoffer Ericson <Kristoffer.Ericson@gmail.com>
+ *  Copyright 2000 John Ankcorn <jca@lcs.mit.edu>
  *
  * 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
@@ -25,3 +25,8 @@
 #define PWMOFF			0xDF
 #define TXDUMMY			0x11
 #define ERRORCODE		0x00
+
+extern void jornada_ssp_start(void);
+extern void jornada_ssp_end(void);
+extern int jornada_ssp_inout(u8 byte);
+extern int jornada_ssp_byte(u8 byte);
diff --git a/arch/arm/mach-sa1100/include/mach/memory.h b/arch/arm/mach-sa1100/include/mach/memory.h
index 29f639e..1c127b6 100644
--- a/arch/arm/mach-sa1100/include/mach/memory.h
+++ b/arch/arm/mach-sa1100/include/mach/memory.h
@@ -40,23 +40,21 @@
 #define __bus_to_virt(x)	 __phys_to_virt(x)
 
 /*
- * Because of the wide memory address space between physical RAM banks on the 
- * SA1100, it's much convenient to use Linux's NUMA support to implement our 
- * memory map representation.  Assuming all memory nodes have equal access 
+ * Because of the wide memory address space between physical RAM banks on the
+ * SA1100, it's much convenient to use Linux's SparseMEM support to implement
+ * our memory map representation.  Assuming all memory nodes have equal access
  * characteristics, we then have generic discontiguous memory support.
  *
- * Of course, all this isn't mandatory for SA1100 implementations with only
- * one used memory bank.  For those, simply undefine CONFIG_DISCONTIGMEM.
- *
- * The nodes are matched with the physical memory bank addresses which are 
- * incidentally the same as virtual addresses.
+ * The sparsemem banks are matched with the physical memory bank addresses
+ * which are incidentally the same as virtual addresses.
  * 
  * 	node 0:  0xc0000000 - 0xc7ffffff
  * 	node 1:  0xc8000000 - 0xcfffffff
  * 	node 2:  0xd0000000 - 0xd7ffffff
  * 	node 3:  0xd8000000 - 0xdfffffff
  */
-#define NODE_MEM_SIZE_BITS	27
+#define MAX_PHYSMEM_BITS	32
+#define SECTION_SIZE_BITS	27
 
 /*
  * Cache flushing area - SA1100 zero bank
diff --git a/arch/arm/mach-sa1100/irq.c b/arch/arm/mach-sa1100/irq.c
index 86369a8..3093d46 100644
--- a/arch/arm/mach-sa1100/irq.c
+++ b/arch/arm/mach-sa1100/irq.c
@@ -122,14 +122,12 @@
 		GEDR = mask;
 
 		irq = IRQ_GPIO11;
-		desc = irq_desc + irq;
 		mask >>= 11;
 		do {
 			if (mask & 1)
-				desc_handle_irq(irq, desc);
+				generic_handle_irq(irq);
 			mask >>= 1;
 			irq++;
-			desc++;
 		} while (mask);
 
 		mask = GEDR & 0xfffff800;
diff --git a/arch/arm/mach-sa1100/jornada720_ssp.c b/arch/arm/mach-sa1100/jornada720_ssp.c
index 06ea7ab..28cf369 100644
--- a/arch/arm/mach-sa1100/jornada720_ssp.c
+++ b/arch/arm/mach-sa1100/jornada720_ssp.c
@@ -21,8 +21,8 @@
 #include <linux/slab.h>
 
 #include <mach/hardware.h>
-#include <asm/hardware/ssp.h>
 #include <mach/jornada720.h>
+#include <asm/hardware/ssp.h>
 
 static DEFINE_SPINLOCK(jornada_ssp_lock);
 static unsigned long jornada_ssp_flags;
@@ -109,12 +109,12 @@
  * jornada_ssp_start - enable mcu
  *
  */
-int jornada_ssp_start()
+void jornada_ssp_start(void)
 {
 	spin_lock_irqsave(&jornada_ssp_lock, jornada_ssp_flags);
 	GPCR = GPIO_GPIO25;
 	udelay(50);
-	return 0;
+	return;
 };
 EXPORT_SYMBOL(jornada_ssp_start);
 
@@ -122,11 +122,11 @@
  * jornada_ssp_end - disable mcu and turn off lock
  *
  */
-int jornada_ssp_end()
+void jornada_ssp_end(void)
 {
 	GPSR = GPIO_GPIO25;
 	spin_unlock_irqrestore(&jornada_ssp_lock, jornada_ssp_flags);
-	return 0;
+	return;
 };
 EXPORT_SYMBOL(jornada_ssp_end);
 
diff --git a/arch/arm/mach-sa1100/neponset.c b/arch/arm/mach-sa1100/neponset.c
index 4856a6b..6ccd175 100644
--- a/arch/arm/mach-sa1100/neponset.c
+++ b/arch/arm/mach-sa1100/neponset.c
@@ -33,8 +33,6 @@
 	unsigned int irr;
 
 	while (1) {
-		struct irq_desc *d;
-
 		/*
 		 * Acknowledge the parent IRQ.
 		 */
@@ -67,21 +65,18 @@
 			desc->chip->ack(irq);
 
 			if (irr & IRR_ETHERNET) {
-				d = irq_desc + IRQ_NEPONSET_SMC9196;
-				desc_handle_irq(IRQ_NEPONSET_SMC9196, d);
+				generic_handle_irq(IRQ_NEPONSET_SMC9196);
 			}
 
 			if (irr & IRR_USAR) {
-				d = irq_desc + IRQ_NEPONSET_USAR;
-				desc_handle_irq(IRQ_NEPONSET_USAR, d);
+				generic_handle_irq(IRQ_NEPONSET_USAR);
 			}
 
 			desc->chip->unmask(irq);
 		}
 
 		if (irr & IRR_SA1111) {
-			d = irq_desc + IRQ_NEPONSET_SA1111;
-			desc_handle_irq(IRQ_NEPONSET_SA1111, d);
+			generic_handle_irq(IRQ_NEPONSET_SA1111);
 		}
 	}
 }
diff --git a/arch/arm/mach-sa1100/pleb.c b/arch/arm/mach-sa1100/pleb.c
index 83be1c6..e45d3a1 100644
--- a/arch/arm/mach-sa1100/pleb.c
+++ b/arch/arm/mach-sa1100/pleb.c
@@ -8,11 +8,10 @@
 #include <linux/ioport.h>
 #include <linux/platform_device.h>
 #include <linux/irq.h>
-
+#include <linux/io.h>
 #include <linux/mtd/partitions.h>
 
 #include <mach/hardware.h>
-#include <asm/io.h>
 #include <asm/setup.h>
 #include <asm/mach-types.h>
 
@@ -39,8 +38,8 @@
 
 static struct resource smc91x_resources[] = {
 	[0] = {
-		.start	=  PLEB_ETH0_P,
-		.end	=  PLEB_ETH0_P | 0x03ffffff,
+		.start	= PLEB_ETH0_P,
+		.end	= PLEB_ETH0_P | 0x03ffffff,
 		.flags	= IORESOURCE_MEM,
 	},
 #if 0 /* Autoprobe instead, to get rising/falling edge characteristic right */
@@ -87,15 +86,15 @@
 static struct mtd_partition pleb_partitions[] = {
 	{
 		.name		= "blob",
-		.offset 	= 0,
+		.offset		= 0,
 		.size		= 0x00020000,
 	}, {
 		.name		= "kernel",
-		.offset 	= MTDPART_OFS_APPEND,
+		.offset		= MTDPART_OFS_APPEND,
 		.size		= 0x000e0000,
 	}, {
 		.name		= "rootfs",
-		.offset 	= MTDPART_OFS_APPEND,
+		.offset		= MTDPART_OFS_APPEND,
 		.size		= 0x00300000,
 	}
 };
diff --git a/arch/arm/mach-sa1100/simpad.c b/arch/arm/mach-sa1100/simpad.c
index 8dd6353..3c74534 100644
--- a/arch/arm/mach-sa1100/simpad.c
+++ b/arch/arm/mach-sa1100/simpad.c
@@ -12,6 +12,7 @@
 #include <linux/platform_device.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
+#include <linux/io.h>
 
 #include <asm/irq.h>
 #include <mach/hardware.h>
@@ -27,7 +28,6 @@
 
 #include <linux/serial_core.h>
 #include <linux/ioport.h>
-#include <asm/io.h>
 
 #include "generic.h"
 
diff --git a/arch/arm/mach-sa1100/ssp.c b/arch/arm/mach-sa1100/ssp.c
index 641f361..b20ff93 100644
--- a/arch/arm/mach-sa1100/ssp.c
+++ b/arch/arm/mach-sa1100/ssp.c
@@ -17,8 +17,8 @@
 #include <linux/interrupt.h>
 #include <linux/ioport.h>
 #include <linux/init.h>
+#include <linux/io.h>
 
-#include <asm/io.h>
 #include <asm/irq.h>
 #include <mach/hardware.h>
 #include <asm/hardware/ssp.h>
diff --git a/arch/arm/mach-shark/core.c b/arch/arm/mach-shark/core.c
index 09d9f33..a9400d9 100644
--- a/arch/arm/mach-shark/core.c
+++ b/arch/arm/mach-shark/core.c
@@ -9,10 +9,10 @@
 #include <linux/irq.h>
 #include <linux/sched.h>
 #include <linux/serial_8250.h>
+#include <linux/io.h>
 
 #include <asm/setup.h>
 #include <asm/mach-types.h>
-#include <asm/io.h>
 #include <asm/leds.h>
 #include <asm/param.h>
 
diff --git a/arch/arm/mach-shark/include/mach/system.h b/arch/arm/mach-shark/include/mach/system.h
index 85aceef..e45bd73 100644
--- a/arch/arm/mach-shark/include/mach/system.h
+++ b/arch/arm/mach-shark/include/mach/system.h
@@ -6,7 +6,7 @@
 #ifndef __ASM_ARCH_SYSTEM_H
 #define __ASM_ARCH_SYSTEM_H
 
-#include <asm/io.h>
+#include <linux/io.h>
 
 static void arch_reset(char mode)
 {
diff --git a/arch/arm/mach-shark/irq.c b/arch/arm/mach-shark/irq.c
index 44b0811..c04eb6a 100644
--- a/arch/arm/mach-shark/irq.c
+++ b/arch/arm/mach-shark/irq.c
@@ -11,9 +11,9 @@
 #include <linux/init.h>
 #include <linux/fs.h>
 #include <linux/interrupt.h>
+#include <linux/io.h>
 
 #include <asm/irq.h>
-#include <asm/io.h>
 #include <asm/mach/irq.h>
 
 /*
diff --git a/arch/arm/mach-shark/leds.c b/arch/arm/mach-shark/leds.c
index b189647..8bd8d6b 100644
--- a/arch/arm/mach-shark/leds.c
+++ b/arch/arm/mach-shark/leds.c
@@ -20,10 +20,10 @@
 #include <linux/init.h>
 #include <linux/spinlock.h>
 #include <linux/ioport.h>
+#include <linux/io.h>
 
 #include <mach/hardware.h>
 #include <asm/leds.h>
-#include <asm/io.h>
 #include <asm/system.h>
 
 #define LED_STATE_ENABLED	1
diff --git a/arch/arm/mach-versatile/core.c b/arch/arm/mach-versatile/core.c
index d75e795..565e0ba 100644
--- a/arch/arm/mach-versatile/core.c
+++ b/arch/arm/mach-versatile/core.c
@@ -28,11 +28,11 @@
 #include <linux/amba/clcd.h>
 #include <linux/clocksource.h>
 #include <linux/clockchips.h>
+#include <linux/cnt32_to_63.h>
+#include <linux/io.h>
 
-#include <asm/cnt32_to_63.h>
 #include <asm/system.h>
 #include <mach/hardware.h>
-#include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/leds.h>
 #include <asm/hardware/arm_timer.h>
@@ -95,8 +95,7 @@
 
 		irq += IRQ_SIC_START;
 
-		desc = irq_desc + irq;
-		desc_handle_irq(irq, desc);
+		generic_handle_irq(irq);
 	} while (status);
 }
 
diff --git a/arch/arm/mach-versatile/include/mach/system.h b/arch/arm/mach-versatile/include/mach/system.h
index 91fa559..c59e610 100644
--- a/arch/arm/mach-versatile/include/mach/system.h
+++ b/arch/arm/mach-versatile/include/mach/system.h
@@ -21,8 +21,8 @@
 #ifndef __ASM_ARCH_SYSTEM_H
 #define __ASM_ARCH_SYSTEM_H
 
+#include <linux/io.h>
 #include <mach/hardware.h>
-#include <asm/io.h>
 #include <mach/platform.h>
 
 static inline void arch_idle(void)
diff --git a/arch/arm/mach-versatile/pci.c b/arch/arm/mach-versatile/pci.c
index 36f23f8..7161ba2 100644
--- a/arch/arm/mach-versatile/pci.c
+++ b/arch/arm/mach-versatile/pci.c
@@ -21,9 +21,9 @@
 #include <linux/interrupt.h>
 #include <linux/spinlock.h>
 #include <linux/init.h>
+#include <linux/io.h>
 
 #include <mach/hardware.h>
-#include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/system.h>
 #include <asm/mach/pci.h>
diff --git a/arch/arm/mach-versatile/versatile_ab.c b/arch/arm/mach-versatile/versatile_ab.c
index 76375c6..bb8ec77 100644
--- a/arch/arm/mach-versatile/versatile_ab.c
+++ b/arch/arm/mach-versatile/versatile_ab.c
@@ -23,9 +23,9 @@
 #include <linux/device.h>
 #include <linux/sysdev.h>
 #include <linux/amba/bus.h>
+#include <linux/io.h>
 
 #include <mach/hardware.h>
-#include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/mach-types.h>
 
diff --git a/arch/arm/mach-versatile/versatile_pb.c b/arch/arm/mach-versatile/versatile_pb.c
index 1725f01..aa051c0 100644
--- a/arch/arm/mach-versatile/versatile_pb.c
+++ b/arch/arm/mach-versatile/versatile_pb.c
@@ -23,9 +23,9 @@
 #include <linux/device.h>
 #include <linux/sysdev.h>
 #include <linux/amba/bus.h>
+#include <linux/io.h>
 
 #include <mach/hardware.h>
-#include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/mach-types.h>
 
diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig
index ed15f87..330814d 100644
--- a/arch/arm/mm/Kconfig
+++ b/arch/arm/mm/Kconfig
@@ -735,6 +735,14 @@
 	help
 	  This option enables the Feroceon L2 cache controller.
 
+config CACHE_FEROCEON_L2_WRITETHROUGH
+	bool "Force Feroceon L2 cache write through"
+	depends on CACHE_FEROCEON_L2
+	default n
+	help
+	  Say Y here to use the Feroceon L2 cache in writethrough mode.
+	  Unless you specifically require this, say N for writeback mode.
+
 config CACHE_L2X0
 	bool "Enable the L2x0 outer cache controller"
 	depends on REALVIEW_EB_ARM11MP || MACH_REALVIEW_PB11MP || MACH_REALVIEW_PB1176
diff --git a/arch/arm/mm/Makefile b/arch/arm/mm/Makefile
index 2e27a8c..480f78a 100644
--- a/arch/arm/mm/Makefile
+++ b/arch/arm/mm/Makefile
@@ -2,7 +2,7 @@
 # Makefile for the linux arm-specific parts of the memory manager.
 #
 
-obj-y				:= consistent.o extable.o fault.o init.o \
+obj-y				:= dma-mapping.o extable.o fault.o init.o \
 				   iomap.o
 
 obj-$(CONFIG_MMU)		+= fault-armv.o flush.o ioremap.o mmap.o \
diff --git a/arch/arm/mm/abort-ev7.S b/arch/arm/mm/abort-ev7.S
index eb90bce..2e6dc04 100644
--- a/arch/arm/mm/abort-ev7.S
+++ b/arch/arm/mm/abort-ev7.S
@@ -30,3 +30,4 @@
 	 * New designs should not need to patch up faults.
 	 */
 	mov	pc, lr
+ENDPROC(v7_early_abort)
diff --git a/arch/arm/mm/abort-nommu.S b/arch/arm/mm/abort-nommu.S
index a7cc7f9e..625e580 100644
--- a/arch/arm/mm/abort-nommu.S
+++ b/arch/arm/mm/abort-nommu.S
@@ -17,3 +17,4 @@
 	mov	r0, #0				@ clear r0, r1 (no FSR/FAR)
 	mov	r1, #0
 	mov	pc, lr
+ENDPROC(nommu_early_abort)
diff --git a/arch/arm/mm/alignment.c b/arch/arm/mm/alignment.c
index e162cca..133e65d 100644
--- a/arch/arm/mm/alignment.c
+++ b/arch/arm/mm/alignment.c
@@ -17,8 +17,8 @@
 #include <linux/string.h>
 #include <linux/proc_fs.h>
 #include <linux/init.h>
+#include <linux/uaccess.h>
 
-#include <asm/uaccess.h>
 #include <asm/unaligned.h>
 
 #include "fault.h"
diff --git a/arch/arm/mm/cache-feroceon-l2.c b/arch/arm/mm/cache-feroceon-l2.c
index 7b5a25d..13cdae8 100644
--- a/arch/arm/mm/cache-feroceon-l2.c
+++ b/arch/arm/mm/cache-feroceon-l2.c
@@ -48,11 +48,12 @@
 	 * L2 is PIPT and range operations only do a TLB lookup on
 	 * the start address.
 	 */
-	BUG_ON((start ^ end) & ~(PAGE_SIZE - 1));
+	BUG_ON((start ^ end) >> PAGE_SHIFT);
 
 	raw_local_irq_save(flags);
-	__asm__("mcr p15, 1, %0, c15, c9, 4" : : "r" (start));
-	__asm__("mcr p15, 1, %0, c15, c9, 5" : : "r" (end));
+	__asm__("mcr p15, 1, %0, c15, c9, 4\n\t"
+		"mcr p15, 1, %1, c15, c9, 5"
+		: : "r" (start), "r" (end));
 	raw_local_irq_restore(flags);
 }
 
@@ -80,11 +81,12 @@
 	 * L2 is PIPT and range operations only do a TLB lookup on
 	 * the start address.
 	 */
-	BUG_ON((start ^ end) & ~(PAGE_SIZE - 1));
+	BUG_ON((start ^ end) >> PAGE_SHIFT);
 
 	raw_local_irq_save(flags);
-	__asm__("mcr p15, 1, %0, c15, c11, 4" : : "r" (start));
-	__asm__("mcr p15, 1, %0, c15, c11, 5" : : "r" (end));
+	__asm__("mcr p15, 1, %0, c15, c11, 4\n\t"
+		"mcr p15, 1, %1, c15, c11, 5"
+		: : "r" (start), "r" (end));
 	raw_local_irq_restore(flags);
 }
 
@@ -205,7 +207,7 @@
  * time.  These are necessary because the L2 cache can only be enabled
  * or disabled while the L1 Dcache and Icache are both disabled.
  */
-static void __init invalidate_and_disable_dcache(void)
+static int __init flush_and_disable_dcache(void)
 {
 	u32 cr;
 
@@ -217,7 +219,9 @@
 		flush_cache_all();
 		set_cr(cr & ~CR_C);
 		raw_local_irq_restore(flags);
+		return 1;
 	}
+	return 0;
 }
 
 static void __init enable_dcache(void)
@@ -225,18 +229,17 @@
 	u32 cr;
 
 	cr = get_cr();
-	if (!(cr & CR_C))
-		set_cr(cr | CR_C);
+	set_cr(cr | CR_C);
 }
 
 static void __init __invalidate_icache(void)
 {
 	int dummy;
 
-	__asm__ __volatile__("mcr p15, 0, %0, c7, c5, 0\n" : "=r" (dummy));
+	__asm__ __volatile__("mcr p15, 0, %0, c7, c5, 0" : "=r" (dummy));
 }
 
-static void __init invalidate_and_disable_icache(void)
+static int __init invalidate_and_disable_icache(void)
 {
 	u32 cr;
 
@@ -244,7 +247,9 @@
 	if (cr & CR_I) {
 		set_cr(cr & ~CR_I);
 		__invalidate_icache();
+		return 1;
 	}
+	return 0;
 }
 
 static void __init enable_icache(void)
@@ -252,8 +257,7 @@
 	u32 cr;
 
 	cr = get_cr();
-	if (!(cr & CR_I))
-		set_cr(cr | CR_I);
+	set_cr(cr | CR_I);
 }
 
 static inline u32 read_extra_features(void)
@@ -291,13 +295,17 @@
 
 	u = read_extra_features();
 	if (!(u & 0x00400000)) {
+		int i, d;
+
 		printk(KERN_INFO "Feroceon L2: Enabling L2\n");
 
-		invalidate_and_disable_dcache();
-		invalidate_and_disable_icache();
+		d = flush_and_disable_dcache();
+		i = invalidate_and_disable_icache();
 		write_extra_features(u | 0x00400000);
-		enable_icache();
-		enable_dcache();
+		if (i)
+			enable_icache();
+		if (d)
+			enable_dcache();
 	}
 }
 
diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c
index 76b800a..b480f1d 100644
--- a/arch/arm/mm/cache-l2x0.c
+++ b/arch/arm/mm/cache-l2x0.c
@@ -18,9 +18,9 @@
  */
 #include <linux/init.h>
 #include <linux/spinlock.h>
+#include <linux/io.h>
 
 #include <asm/cacheflush.h>
-#include <asm/io.h>
 #include <asm/hardware/cache-l2x0.h>
 
 #define CACHE_LINE_SIZE		32
diff --git a/arch/arm/mm/cache-v7.S b/arch/arm/mm/cache-v7.S
index 35ffc4d..d19c2be 100644
--- a/arch/arm/mm/cache-v7.S
+++ b/arch/arm/mm/cache-v7.S
@@ -66,6 +66,7 @@
 	mcr	p15, 2, r10, c0, c0, 0		@ select current cache level in cssr
 	isb
 	mov	pc, lr
+ENDPROC(v7_flush_dcache_all)
 
 /*
  *	v7_flush_cache_all()
@@ -85,6 +86,7 @@
 	mcr	p15, 0, r0, c7, c5, 0		@ I+BTB cache invalidate
 	ldmfd	sp!, {r4-r5, r7, r9-r11, lr}
 	mov	pc, lr
+ENDPROC(v7_flush_kern_cache_all)
 
 /*
  *	v7_flush_cache_all()
@@ -110,6 +112,8 @@
  */
 ENTRY(v7_flush_user_cache_range)
 	mov	pc, lr
+ENDPROC(v7_flush_user_cache_all)
+ENDPROC(v7_flush_user_cache_range)
 
 /*
  *	v7_coherent_kern_range(start,end)
@@ -155,6 +159,8 @@
 	dsb
 	isb
 	mov	pc, lr
+ENDPROC(v7_coherent_kern_range)
+ENDPROC(v7_coherent_user_range)
 
 /*
  *	v7_flush_kern_dcache_page(kaddr)
@@ -174,6 +180,7 @@
 	blo	1b
 	dsb
 	mov	pc, lr
+ENDPROC(v7_flush_kern_dcache_page)
 
 /*
  *	v7_dma_inv_range(start,end)
@@ -202,6 +209,7 @@
 	blo	1b
 	dsb
 	mov	pc, lr
+ENDPROC(v7_dma_inv_range)
 
 /*
  *	v7_dma_clean_range(start,end)
@@ -219,6 +227,7 @@
 	blo	1b
 	dsb
 	mov	pc, lr
+ENDPROC(v7_dma_clean_range)
 
 /*
  *	v7_dma_flush_range(start,end)
@@ -236,6 +245,7 @@
 	blo	1b
 	dsb
 	mov	pc, lr
+ENDPROC(v7_dma_flush_range)
 
 	__INITDATA
 
diff --git a/arch/arm/mm/cache-xsc3l2.c b/arch/arm/mm/cache-xsc3l2.c
index 158bd96..10b1bae 100644
--- a/arch/arm/mm/cache-xsc3l2.c
+++ b/arch/arm/mm/cache-xsc3l2.c
@@ -18,10 +18,11 @@
  */
 #include <linux/init.h>
 #include <linux/spinlock.h>
+#include <linux/io.h>
 
 #include <asm/system.h>
+#include <asm/cputype.h>
 #include <asm/cacheflush.h>
-#include <asm/io.h>
 
 #define CR_L2	(1 << 26)
 
diff --git a/arch/arm/mm/consistent.c b/arch/arm/mm/consistent.c
deleted file mode 100644
index db7b3e3..0000000
--- a/arch/arm/mm/consistent.c
+++ /dev/null
@@ -1,514 +0,0 @@
-/*
- *  linux/arch/arm/mm/consistent.c
- *
- *  Copyright (C) 2000-2004 Russell King
- *
- * 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.
- *
- *  DMA uncached mapping support.
- */
-#include <linux/module.h>
-#include <linux/mm.h>
-#include <linux/slab.h>
-#include <linux/errno.h>
-#include <linux/list.h>
-#include <linux/init.h>
-#include <linux/device.h>
-#include <linux/dma-mapping.h>
-
-#include <asm/memory.h>
-#include <asm/cacheflush.h>
-#include <asm/tlbflush.h>
-#include <asm/sizes.h>
-
-/* Sanity check size */
-#if (CONSISTENT_DMA_SIZE % SZ_2M)
-#error "CONSISTENT_DMA_SIZE must be multiple of 2MiB"
-#endif
-
-#define CONSISTENT_END	(0xffe00000)
-#define CONSISTENT_BASE	(CONSISTENT_END - CONSISTENT_DMA_SIZE)
-
-#define CONSISTENT_OFFSET(x)	(((unsigned long)(x) - CONSISTENT_BASE) >> PAGE_SHIFT)
-#define CONSISTENT_PTE_INDEX(x) (((unsigned long)(x) - CONSISTENT_BASE) >> PGDIR_SHIFT)
-#define NUM_CONSISTENT_PTES (CONSISTENT_DMA_SIZE >> PGDIR_SHIFT)
-
-
-/*
- * These are the page tables (2MB each) covering uncached, DMA consistent allocations
- */
-static pte_t *consistent_pte[NUM_CONSISTENT_PTES];
-static DEFINE_SPINLOCK(consistent_lock);
-
-/*
- * VM region handling support.
- *
- * This should become something generic, handling VM region allocations for
- * vmalloc and similar (ioremap, module space, etc).
- *
- * I envisage vmalloc()'s supporting vm_struct becoming:
- *
- *  struct vm_struct {
- *    struct vm_region	region;
- *    unsigned long	flags;
- *    struct page	**pages;
- *    unsigned int	nr_pages;
- *    unsigned long	phys_addr;
- *  };
- *
- * get_vm_area() would then call vm_region_alloc with an appropriate
- * struct vm_region head (eg):
- *
- *  struct vm_region vmalloc_head = {
- *	.vm_list	= LIST_HEAD_INIT(vmalloc_head.vm_list),
- *	.vm_start	= VMALLOC_START,
- *	.vm_end		= VMALLOC_END,
- *  };
- *
- * However, vmalloc_head.vm_start is variable (typically, it is dependent on
- * the amount of RAM found at boot time.)  I would imagine that get_vm_area()
- * would have to initialise this each time prior to calling vm_region_alloc().
- */
-struct vm_region {
-	struct list_head	vm_list;
-	unsigned long		vm_start;
-	unsigned long		vm_end;
-	struct page		*vm_pages;
-	int			vm_active;
-};
-
-static struct vm_region consistent_head = {
-	.vm_list	= LIST_HEAD_INIT(consistent_head.vm_list),
-	.vm_start	= CONSISTENT_BASE,
-	.vm_end		= CONSISTENT_END,
-};
-
-static struct vm_region *
-vm_region_alloc(struct vm_region *head, size_t size, gfp_t gfp)
-{
-	unsigned long addr = head->vm_start, end = head->vm_end - size;
-	unsigned long flags;
-	struct vm_region *c, *new;
-
-	new = kmalloc(sizeof(struct vm_region), gfp);
-	if (!new)
-		goto out;
-
-	spin_lock_irqsave(&consistent_lock, flags);
-
-	list_for_each_entry(c, &head->vm_list, vm_list) {
-		if ((addr + size) < addr)
-			goto nospc;
-		if ((addr + size) <= c->vm_start)
-			goto found;
-		addr = c->vm_end;
-		if (addr > end)
-			goto nospc;
-	}
-
- found:
-	/*
-	 * Insert this entry _before_ the one we found.
-	 */
-	list_add_tail(&new->vm_list, &c->vm_list);
-	new->vm_start = addr;
-	new->vm_end = addr + size;
-	new->vm_active = 1;
-
-	spin_unlock_irqrestore(&consistent_lock, flags);
-	return new;
-
- nospc:
-	spin_unlock_irqrestore(&consistent_lock, flags);
-	kfree(new);
- out:
-	return NULL;
-}
-
-static struct vm_region *vm_region_find(struct vm_region *head, unsigned long addr)
-{
-	struct vm_region *c;
-	
-	list_for_each_entry(c, &head->vm_list, vm_list) {
-		if (c->vm_active && c->vm_start == addr)
-			goto out;
-	}
-	c = NULL;
- out:
-	return c;
-}
-
-#ifdef CONFIG_HUGETLB_PAGE
-#error ARM Coherent DMA allocator does not (yet) support huge TLB
-#endif
-
-static void *
-__dma_alloc(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp,
-	    pgprot_t prot)
-{
-	struct page *page;
-	struct vm_region *c;
-	unsigned long order;
-	u64 mask = ISA_DMA_THRESHOLD, limit;
-
-	if (!consistent_pte[0]) {
-		printk(KERN_ERR "%s: not initialised\n", __func__);
-		dump_stack();
-		return NULL;
-	}
-
-	if (dev) {
-		mask = dev->coherent_dma_mask;
-
-		/*
-		 * Sanity check the DMA mask - it must be non-zero, and
-		 * must be able to be satisfied by a DMA allocation.
-		 */
-		if (mask == 0) {
-			dev_warn(dev, "coherent DMA mask is unset\n");
-			goto no_page;
-		}
-
-		if ((~mask) & ISA_DMA_THRESHOLD) {
-			dev_warn(dev, "coherent DMA mask %#llx is smaller "
-				 "than system GFP_DMA mask %#llx\n",
-				 mask, (unsigned long long)ISA_DMA_THRESHOLD);
-			goto no_page;
-		}
-	}
-
-	/*
-	 * Sanity check the allocation size.
-	 */
-	size = PAGE_ALIGN(size);
-	limit = (mask + 1) & ~mask;
-	if ((limit && size >= limit) ||
-	    size >= (CONSISTENT_END - CONSISTENT_BASE)) {
-		printk(KERN_WARNING "coherent allocation too big "
-		       "(requested %#x mask %#llx)\n", size, mask);
-		goto no_page;
-	}
-
-	order = get_order(size);
-
-	if (mask != 0xffffffff)
-		gfp |= GFP_DMA;
-
-	page = alloc_pages(gfp, order);
-	if (!page)
-		goto no_page;
-
-	/*
-	 * Invalidate any data that might be lurking in the
-	 * kernel direct-mapped region for device DMA.
-	 */
-	{
-		void *ptr = page_address(page);
-		memset(ptr, 0, size);
-		dmac_flush_range(ptr, ptr + size);
-		outer_flush_range(__pa(ptr), __pa(ptr) + size);
-	}
-
-	/*
-	 * Allocate a virtual address in the consistent mapping region.
-	 */
-	c = vm_region_alloc(&consistent_head, size,
-			    gfp & ~(__GFP_DMA | __GFP_HIGHMEM));
-	if (c) {
-		pte_t *pte;
-		struct page *end = page + (1 << order);
-		int idx = CONSISTENT_PTE_INDEX(c->vm_start);
-		u32 off = CONSISTENT_OFFSET(c->vm_start) & (PTRS_PER_PTE-1);
-
-		pte = consistent_pte[idx] + off;
-		c->vm_pages = page;
-
-		split_page(page, order);
-
-		/*
-		 * Set the "dma handle"
-		 */
-		*handle = page_to_dma(dev, page);
-
-		do {
-			BUG_ON(!pte_none(*pte));
-
-			/*
-			 * x86 does not mark the pages reserved...
-			 */
-			SetPageReserved(page);
-			set_pte_ext(pte, mk_pte(page, prot), 0);
-			page++;
-			pte++;
-			off++;
-			if (off >= PTRS_PER_PTE) {
-				off = 0;
-				pte = consistent_pte[++idx];
-			}
-		} while (size -= PAGE_SIZE);
-
-		/*
-		 * Free the otherwise unused pages.
-		 */
-		while (page < end) {
-			__free_page(page);
-			page++;
-		}
-
-		return (void *)c->vm_start;
-	}
-
-	if (page)
-		__free_pages(page, order);
- no_page:
-	*handle = ~0;
-	return NULL;
-}
-
-/*
- * Allocate DMA-coherent memory space and return both the kernel remapped
- * virtual and bus address for that space.
- */
-void *
-dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp)
-{
-	void *memory;
-
-	if (dma_alloc_from_coherent(dev, size, handle, &memory))
-		return memory;
-
-	if (arch_is_coherent()) {
-		void *virt;
-
-		virt = kmalloc(size, gfp);
-		if (!virt)
-			return NULL;
-		*handle =  virt_to_dma(dev, virt);
-
-		return virt;
-	}
-
-	return __dma_alloc(dev, size, handle, gfp,
-			   pgprot_noncached(pgprot_kernel));
-}
-EXPORT_SYMBOL(dma_alloc_coherent);
-
-/*
- * Allocate a writecombining region, in much the same way as
- * dma_alloc_coherent above.
- */
-void *
-dma_alloc_writecombine(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp)
-{
-	return __dma_alloc(dev, size, handle, gfp,
-			   pgprot_writecombine(pgprot_kernel));
-}
-EXPORT_SYMBOL(dma_alloc_writecombine);
-
-static int dma_mmap(struct device *dev, struct vm_area_struct *vma,
-		    void *cpu_addr, dma_addr_t dma_addr, size_t size)
-{
-	unsigned long flags, user_size, kern_size;
-	struct vm_region *c;
-	int ret = -ENXIO;
-
-	user_size = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
-
-	spin_lock_irqsave(&consistent_lock, flags);
-	c = vm_region_find(&consistent_head, (unsigned long)cpu_addr);
-	spin_unlock_irqrestore(&consistent_lock, flags);
-
-	if (c) {
-		unsigned long off = vma->vm_pgoff;
-
-		kern_size = (c->vm_end - c->vm_start) >> PAGE_SHIFT;
-
-		if (off < kern_size &&
-		    user_size <= (kern_size - off)) {
-			ret = remap_pfn_range(vma, vma->vm_start,
-					      page_to_pfn(c->vm_pages) + off,
-					      user_size << PAGE_SHIFT,
-					      vma->vm_page_prot);
-		}
-	}
-
-	return ret;
-}
-
-int dma_mmap_coherent(struct device *dev, struct vm_area_struct *vma,
-		      void *cpu_addr, dma_addr_t dma_addr, size_t size)
-{
-	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
-	return dma_mmap(dev, vma, cpu_addr, dma_addr, size);
-}
-EXPORT_SYMBOL(dma_mmap_coherent);
-
-int dma_mmap_writecombine(struct device *dev, struct vm_area_struct *vma,
-			  void *cpu_addr, dma_addr_t dma_addr, size_t size)
-{
-	vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
-	return dma_mmap(dev, vma, cpu_addr, dma_addr, size);
-}
-EXPORT_SYMBOL(dma_mmap_writecombine);
-
-/*
- * free a page as defined by the above mapping.
- * Must not be called with IRQs disabled.
- */
-void dma_free_coherent(struct device *dev, size_t size, void *cpu_addr, dma_addr_t handle)
-{
-	struct vm_region *c;
-	unsigned long flags, addr;
-	pte_t *ptep;
-	int idx;
-	u32 off;
-
-	WARN_ON(irqs_disabled());
-
-	if (dma_release_from_coherent(dev, get_order(size), cpu_addr))
-		return;
-
-	if (arch_is_coherent()) {
-		kfree(cpu_addr);
-		return;
-	}
-
-	size = PAGE_ALIGN(size);
-
-	spin_lock_irqsave(&consistent_lock, flags);
-	c = vm_region_find(&consistent_head, (unsigned long)cpu_addr);
-	if (!c)
-		goto no_area;
-
-	c->vm_active = 0;
-	spin_unlock_irqrestore(&consistent_lock, flags);
-
-	if ((c->vm_end - c->vm_start) != size) {
-		printk(KERN_ERR "%s: freeing wrong coherent size (%ld != %d)\n",
-		       __func__, c->vm_end - c->vm_start, size);
-		dump_stack();
-		size = c->vm_end - c->vm_start;
-	}
-
-	idx = CONSISTENT_PTE_INDEX(c->vm_start);
-	off = CONSISTENT_OFFSET(c->vm_start) & (PTRS_PER_PTE-1);
-	ptep = consistent_pte[idx] + off;
-	addr = c->vm_start;
-	do {
-		pte_t pte = ptep_get_and_clear(&init_mm, addr, ptep);
-		unsigned long pfn;
-
-		ptep++;
-		addr += PAGE_SIZE;
-		off++;
-		if (off >= PTRS_PER_PTE) {
-			off = 0;
-			ptep = consistent_pte[++idx];
-		}
-
-		if (!pte_none(pte) && pte_present(pte)) {
-			pfn = pte_pfn(pte);
-
-			if (pfn_valid(pfn)) {
-				struct page *page = pfn_to_page(pfn);
-
-				/*
-				 * x86 does not mark the pages reserved...
-				 */
-				ClearPageReserved(page);
-
-				__free_page(page);
-				continue;
-			}
-		}
-
-		printk(KERN_CRIT "%s: bad page in kernel page table\n",
-		       __func__);
-	} while (size -= PAGE_SIZE);
-
-	flush_tlb_kernel_range(c->vm_start, c->vm_end);
-
-	spin_lock_irqsave(&consistent_lock, flags);
-	list_del(&c->vm_list);
-	spin_unlock_irqrestore(&consistent_lock, flags);
-
-	kfree(c);
-	return;
-
- no_area:
-	spin_unlock_irqrestore(&consistent_lock, flags);
-	printk(KERN_ERR "%s: trying to free invalid coherent area: %p\n",
-	       __func__, cpu_addr);
-	dump_stack();
-}
-EXPORT_SYMBOL(dma_free_coherent);
-
-/*
- * Initialise the consistent memory allocation.
- */
-static int __init consistent_init(void)
-{
-	pgd_t *pgd;
-	pmd_t *pmd;
-	pte_t *pte;
-	int ret = 0, i = 0;
-	u32 base = CONSISTENT_BASE;
-
-	do {
-		pgd = pgd_offset(&init_mm, base);
-		pmd = pmd_alloc(&init_mm, pgd, base);
-		if (!pmd) {
-			printk(KERN_ERR "%s: no pmd tables\n", __func__);
-			ret = -ENOMEM;
-			break;
-		}
-		WARN_ON(!pmd_none(*pmd));
-
-		pte = pte_alloc_kernel(pmd, base);
-		if (!pte) {
-			printk(KERN_ERR "%s: no pte tables\n", __func__);
-			ret = -ENOMEM;
-			break;
-		}
-
-		consistent_pte[i++] = pte;
-		base += (1 << PGDIR_SHIFT);
-	} while (base < CONSISTENT_END);
-
-	return ret;
-}
-
-core_initcall(consistent_init);
-
-/*
- * Make an area consistent for devices.
- * Note: Drivers should NOT use this function directly, as it will break
- * platforms with CONFIG_DMABOUNCE.
- * Use the driver DMA support - see dma-mapping.h (dma_sync_*)
- */
-void dma_cache_maint(const void *start, size_t size, int direction)
-{
-	const void *end = start + size;
-
-	BUG_ON(!virt_addr_valid(start) || !virt_addr_valid(end - 1));
-
-	switch (direction) {
-	case DMA_FROM_DEVICE:		/* invalidate only */
-		dmac_inv_range(start, end);
-		outer_inv_range(__pa(start), __pa(end));
-		break;
-	case DMA_TO_DEVICE:		/* writeback only */
-		dmac_clean_range(start, end);
-		outer_clean_range(__pa(start), __pa(end));
-		break;
-	case DMA_BIDIRECTIONAL:		/* writeback and invalidate */
-		dmac_flush_range(start, end);
-		outer_flush_range(__pa(start), __pa(end));
-		break;
-	default:
-		BUG();
-	}
-}
-EXPORT_SYMBOL(dma_cache_maint);
diff --git a/arch/arm/mm/copypage-v4mc.c b/arch/arm/mm/copypage-v4mc.c
index ded0e96..8d33e25 100644
--- a/arch/arm/mm/copypage-v4mc.c
+++ b/arch/arm/mm/copypage-v4mc.c
@@ -28,7 +28,7 @@
  * specific hacks for copying pages efficiently.
  */
 #define minicache_pgprot __pgprot(L_PTE_PRESENT | L_PTE_YOUNG | \
-				  L_PTE_CACHEABLE)
+				  L_PTE_MT_MINICACHE)
 
 static DEFINE_SPINLOCK(minicache_lock);
 
diff --git a/arch/arm/mm/copypage-v6.c b/arch/arm/mm/copypage-v6.c
index 3adb792..0e21c07 100644
--- a/arch/arm/mm/copypage-v6.c
+++ b/arch/arm/mm/copypage-v6.c
@@ -16,6 +16,7 @@
 #include <asm/shmparam.h>
 #include <asm/tlbflush.h>
 #include <asm/cacheflush.h>
+#include <asm/cachetype.h>
 
 #include "mm.h"
 
diff --git a/arch/arm/mm/copypage-xscale.c b/arch/arm/mm/copypage-xscale.c
index 2e455f8..bad4933 100644
--- a/arch/arm/mm/copypage-xscale.c
+++ b/arch/arm/mm/copypage-xscale.c
@@ -30,7 +30,7 @@
 #define COPYPAGE_MINICACHE	0xffff8000
 
 #define minicache_pgprot __pgprot(L_PTE_PRESENT | L_PTE_YOUNG | \
-				  L_PTE_CACHEABLE)
+				  L_PTE_MT_MINICACHE)
 
 static DEFINE_SPINLOCK(minicache_lock);
 
diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c
new file mode 100644
index 0000000..6796001
--- /dev/null
+++ b/arch/arm/mm/dma-mapping.c
@@ -0,0 +1,616 @@
+/*
+ *  linux/arch/arm/mm/dma-mapping.c
+ *
+ *  Copyright (C) 2000-2004 Russell King
+ *
+ * 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.
+ *
+ *  DMA uncached mapping support.
+ */
+#include <linux/module.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/list.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+
+#include <asm/memory.h>
+#include <asm/cacheflush.h>
+#include <asm/tlbflush.h>
+#include <asm/sizes.h>
+
+/* Sanity check size */
+#if (CONSISTENT_DMA_SIZE % SZ_2M)
+#error "CONSISTENT_DMA_SIZE must be multiple of 2MiB"
+#endif
+
+#define CONSISTENT_END	(0xffe00000)
+#define CONSISTENT_BASE	(CONSISTENT_END - CONSISTENT_DMA_SIZE)
+
+#define CONSISTENT_OFFSET(x)	(((unsigned long)(x) - CONSISTENT_BASE) >> PAGE_SHIFT)
+#define CONSISTENT_PTE_INDEX(x) (((unsigned long)(x) - CONSISTENT_BASE) >> PGDIR_SHIFT)
+#define NUM_CONSISTENT_PTES (CONSISTENT_DMA_SIZE >> PGDIR_SHIFT)
+
+
+/*
+ * These are the page tables (2MB each) covering uncached, DMA consistent allocations
+ */
+static pte_t *consistent_pte[NUM_CONSISTENT_PTES];
+static DEFINE_SPINLOCK(consistent_lock);
+
+/*
+ * VM region handling support.
+ *
+ * This should become something generic, handling VM region allocations for
+ * vmalloc and similar (ioremap, module space, etc).
+ *
+ * I envisage vmalloc()'s supporting vm_struct becoming:
+ *
+ *  struct vm_struct {
+ *    struct vm_region	region;
+ *    unsigned long	flags;
+ *    struct page	**pages;
+ *    unsigned int	nr_pages;
+ *    unsigned long	phys_addr;
+ *  };
+ *
+ * get_vm_area() would then call vm_region_alloc with an appropriate
+ * struct vm_region head (eg):
+ *
+ *  struct vm_region vmalloc_head = {
+ *	.vm_list	= LIST_HEAD_INIT(vmalloc_head.vm_list),
+ *	.vm_start	= VMALLOC_START,
+ *	.vm_end		= VMALLOC_END,
+ *  };
+ *
+ * However, vmalloc_head.vm_start is variable (typically, it is dependent on
+ * the amount of RAM found at boot time.)  I would imagine that get_vm_area()
+ * would have to initialise this each time prior to calling vm_region_alloc().
+ */
+struct vm_region {
+	struct list_head	vm_list;
+	unsigned long		vm_start;
+	unsigned long		vm_end;
+	struct page		*vm_pages;
+	int			vm_active;
+};
+
+static struct vm_region consistent_head = {
+	.vm_list	= LIST_HEAD_INIT(consistent_head.vm_list),
+	.vm_start	= CONSISTENT_BASE,
+	.vm_end		= CONSISTENT_END,
+};
+
+static struct vm_region *
+vm_region_alloc(struct vm_region *head, size_t size, gfp_t gfp)
+{
+	unsigned long addr = head->vm_start, end = head->vm_end - size;
+	unsigned long flags;
+	struct vm_region *c, *new;
+
+	new = kmalloc(sizeof(struct vm_region), gfp);
+	if (!new)
+		goto out;
+
+	spin_lock_irqsave(&consistent_lock, flags);
+
+	list_for_each_entry(c, &head->vm_list, vm_list) {
+		if ((addr + size) < addr)
+			goto nospc;
+		if ((addr + size) <= c->vm_start)
+			goto found;
+		addr = c->vm_end;
+		if (addr > end)
+			goto nospc;
+	}
+
+ found:
+	/*
+	 * Insert this entry _before_ the one we found.
+	 */
+	list_add_tail(&new->vm_list, &c->vm_list);
+	new->vm_start = addr;
+	new->vm_end = addr + size;
+	new->vm_active = 1;
+
+	spin_unlock_irqrestore(&consistent_lock, flags);
+	return new;
+
+ nospc:
+	spin_unlock_irqrestore(&consistent_lock, flags);
+	kfree(new);
+ out:
+	return NULL;
+}
+
+static struct vm_region *vm_region_find(struct vm_region *head, unsigned long addr)
+{
+	struct vm_region *c;
+	
+	list_for_each_entry(c, &head->vm_list, vm_list) {
+		if (c->vm_active && c->vm_start == addr)
+			goto out;
+	}
+	c = NULL;
+ out:
+	return c;
+}
+
+#ifdef CONFIG_HUGETLB_PAGE
+#error ARM Coherent DMA allocator does not (yet) support huge TLB
+#endif
+
+static void *
+__dma_alloc(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp,
+	    pgprot_t prot)
+{
+	struct page *page;
+	struct vm_region *c;
+	unsigned long order;
+	u64 mask = ISA_DMA_THRESHOLD, limit;
+
+	if (!consistent_pte[0]) {
+		printk(KERN_ERR "%s: not initialised\n", __func__);
+		dump_stack();
+		return NULL;
+	}
+
+	if (dev) {
+		mask = dev->coherent_dma_mask;
+
+		/*
+		 * Sanity check the DMA mask - it must be non-zero, and
+		 * must be able to be satisfied by a DMA allocation.
+		 */
+		if (mask == 0) {
+			dev_warn(dev, "coherent DMA mask is unset\n");
+			goto no_page;
+		}
+
+		if ((~mask) & ISA_DMA_THRESHOLD) {
+			dev_warn(dev, "coherent DMA mask %#llx is smaller "
+				 "than system GFP_DMA mask %#llx\n",
+				 mask, (unsigned long long)ISA_DMA_THRESHOLD);
+			goto no_page;
+		}
+	}
+
+	/*
+	 * Sanity check the allocation size.
+	 */
+	size = PAGE_ALIGN(size);
+	limit = (mask + 1) & ~mask;
+	if ((limit && size >= limit) ||
+	    size >= (CONSISTENT_END - CONSISTENT_BASE)) {
+		printk(KERN_WARNING "coherent allocation too big "
+		       "(requested %#x mask %#llx)\n", size, mask);
+		goto no_page;
+	}
+
+	order = get_order(size);
+
+	if (mask != 0xffffffff)
+		gfp |= GFP_DMA;
+
+	page = alloc_pages(gfp, order);
+	if (!page)
+		goto no_page;
+
+	/*
+	 * Invalidate any data that might be lurking in the
+	 * kernel direct-mapped region for device DMA.
+	 */
+	{
+		void *ptr = page_address(page);
+		memset(ptr, 0, size);
+		dmac_flush_range(ptr, ptr + size);
+		outer_flush_range(__pa(ptr), __pa(ptr) + size);
+	}
+
+	/*
+	 * Allocate a virtual address in the consistent mapping region.
+	 */
+	c = vm_region_alloc(&consistent_head, size,
+			    gfp & ~(__GFP_DMA | __GFP_HIGHMEM));
+	if (c) {
+		pte_t *pte;
+		struct page *end = page + (1 << order);
+		int idx = CONSISTENT_PTE_INDEX(c->vm_start);
+		u32 off = CONSISTENT_OFFSET(c->vm_start) & (PTRS_PER_PTE-1);
+
+		pte = consistent_pte[idx] + off;
+		c->vm_pages = page;
+
+		split_page(page, order);
+
+		/*
+		 * Set the "dma handle"
+		 */
+		*handle = page_to_dma(dev, page);
+
+		do {
+			BUG_ON(!pte_none(*pte));
+
+			/*
+			 * x86 does not mark the pages reserved...
+			 */
+			SetPageReserved(page);
+			set_pte_ext(pte, mk_pte(page, prot), 0);
+			page++;
+			pte++;
+			off++;
+			if (off >= PTRS_PER_PTE) {
+				off = 0;
+				pte = consistent_pte[++idx];
+			}
+		} while (size -= PAGE_SIZE);
+
+		/*
+		 * Free the otherwise unused pages.
+		 */
+		while (page < end) {
+			__free_page(page);
+			page++;
+		}
+
+		return (void *)c->vm_start;
+	}
+
+	if (page)
+		__free_pages(page, order);
+ no_page:
+	*handle = ~0;
+	return NULL;
+}
+
+/*
+ * Allocate DMA-coherent memory space and return both the kernel remapped
+ * virtual and bus address for that space.
+ */
+void *
+dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp)
+{
+	void *memory;
+
+	if (dma_alloc_from_coherent(dev, size, handle, &memory))
+		return memory;
+
+	if (arch_is_coherent()) {
+		void *virt;
+
+		virt = kmalloc(size, gfp);
+		if (!virt)
+			return NULL;
+		*handle =  virt_to_dma(dev, virt);
+
+		return virt;
+	}
+
+	return __dma_alloc(dev, size, handle, gfp,
+			   pgprot_noncached(pgprot_kernel));
+}
+EXPORT_SYMBOL(dma_alloc_coherent);
+
+/*
+ * Allocate a writecombining region, in much the same way as
+ * dma_alloc_coherent above.
+ */
+void *
+dma_alloc_writecombine(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp)
+{
+	return __dma_alloc(dev, size, handle, gfp,
+			   pgprot_writecombine(pgprot_kernel));
+}
+EXPORT_SYMBOL(dma_alloc_writecombine);
+
+static int dma_mmap(struct device *dev, struct vm_area_struct *vma,
+		    void *cpu_addr, dma_addr_t dma_addr, size_t size)
+{
+	unsigned long flags, user_size, kern_size;
+	struct vm_region *c;
+	int ret = -ENXIO;
+
+	user_size = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
+
+	spin_lock_irqsave(&consistent_lock, flags);
+	c = vm_region_find(&consistent_head, (unsigned long)cpu_addr);
+	spin_unlock_irqrestore(&consistent_lock, flags);
+
+	if (c) {
+		unsigned long off = vma->vm_pgoff;
+
+		kern_size = (c->vm_end - c->vm_start) >> PAGE_SHIFT;
+
+		if (off < kern_size &&
+		    user_size <= (kern_size - off)) {
+			ret = remap_pfn_range(vma, vma->vm_start,
+					      page_to_pfn(c->vm_pages) + off,
+					      user_size << PAGE_SHIFT,
+					      vma->vm_page_prot);
+		}
+	}
+
+	return ret;
+}
+
+int dma_mmap_coherent(struct device *dev, struct vm_area_struct *vma,
+		      void *cpu_addr, dma_addr_t dma_addr, size_t size)
+{
+	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+	return dma_mmap(dev, vma, cpu_addr, dma_addr, size);
+}
+EXPORT_SYMBOL(dma_mmap_coherent);
+
+int dma_mmap_writecombine(struct device *dev, struct vm_area_struct *vma,
+			  void *cpu_addr, dma_addr_t dma_addr, size_t size)
+{
+	vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
+	return dma_mmap(dev, vma, cpu_addr, dma_addr, size);
+}
+EXPORT_SYMBOL(dma_mmap_writecombine);
+
+/*
+ * free a page as defined by the above mapping.
+ * Must not be called with IRQs disabled.
+ */
+void dma_free_coherent(struct device *dev, size_t size, void *cpu_addr, dma_addr_t handle)
+{
+	struct vm_region *c;
+	unsigned long flags, addr;
+	pte_t *ptep;
+	int idx;
+	u32 off;
+
+	WARN_ON(irqs_disabled());
+
+	if (dma_release_from_coherent(dev, get_order(size), cpu_addr))
+		return;
+
+	if (arch_is_coherent()) {
+		kfree(cpu_addr);
+		return;
+	}
+
+	size = PAGE_ALIGN(size);
+
+	spin_lock_irqsave(&consistent_lock, flags);
+	c = vm_region_find(&consistent_head, (unsigned long)cpu_addr);
+	if (!c)
+		goto no_area;
+
+	c->vm_active = 0;
+	spin_unlock_irqrestore(&consistent_lock, flags);
+
+	if ((c->vm_end - c->vm_start) != size) {
+		printk(KERN_ERR "%s: freeing wrong coherent size (%ld != %d)\n",
+		       __func__, c->vm_end - c->vm_start, size);
+		dump_stack();
+		size = c->vm_end - c->vm_start;
+	}
+
+	idx = CONSISTENT_PTE_INDEX(c->vm_start);
+	off = CONSISTENT_OFFSET(c->vm_start) & (PTRS_PER_PTE-1);
+	ptep = consistent_pte[idx] + off;
+	addr = c->vm_start;
+	do {
+		pte_t pte = ptep_get_and_clear(&init_mm, addr, ptep);
+		unsigned long pfn;
+
+		ptep++;
+		addr += PAGE_SIZE;
+		off++;
+		if (off >= PTRS_PER_PTE) {
+			off = 0;
+			ptep = consistent_pte[++idx];
+		}
+
+		if (!pte_none(pte) && pte_present(pte)) {
+			pfn = pte_pfn(pte);
+
+			if (pfn_valid(pfn)) {
+				struct page *page = pfn_to_page(pfn);
+
+				/*
+				 * x86 does not mark the pages reserved...
+				 */
+				ClearPageReserved(page);
+
+				__free_page(page);
+				continue;
+			}
+		}
+
+		printk(KERN_CRIT "%s: bad page in kernel page table\n",
+		       __func__);
+	} while (size -= PAGE_SIZE);
+
+	flush_tlb_kernel_range(c->vm_start, c->vm_end);
+
+	spin_lock_irqsave(&consistent_lock, flags);
+	list_del(&c->vm_list);
+	spin_unlock_irqrestore(&consistent_lock, flags);
+
+	kfree(c);
+	return;
+
+ no_area:
+	spin_unlock_irqrestore(&consistent_lock, flags);
+	printk(KERN_ERR "%s: trying to free invalid coherent area: %p\n",
+	       __func__, cpu_addr);
+	dump_stack();
+}
+EXPORT_SYMBOL(dma_free_coherent);
+
+/*
+ * Initialise the consistent memory allocation.
+ */
+static int __init consistent_init(void)
+{
+	pgd_t *pgd;
+	pmd_t *pmd;
+	pte_t *pte;
+	int ret = 0, i = 0;
+	u32 base = CONSISTENT_BASE;
+
+	do {
+		pgd = pgd_offset(&init_mm, base);
+		pmd = pmd_alloc(&init_mm, pgd, base);
+		if (!pmd) {
+			printk(KERN_ERR "%s: no pmd tables\n", __func__);
+			ret = -ENOMEM;
+			break;
+		}
+		WARN_ON(!pmd_none(*pmd));
+
+		pte = pte_alloc_kernel(pmd, base);
+		if (!pte) {
+			printk(KERN_ERR "%s: no pte tables\n", __func__);
+			ret = -ENOMEM;
+			break;
+		}
+
+		consistent_pte[i++] = pte;
+		base += (1 << PGDIR_SHIFT);
+	} while (base < CONSISTENT_END);
+
+	return ret;
+}
+
+core_initcall(consistent_init);
+
+/*
+ * Make an area consistent for devices.
+ * Note: Drivers should NOT use this function directly, as it will break
+ * platforms with CONFIG_DMABOUNCE.
+ * Use the driver DMA support - see dma-mapping.h (dma_sync_*)
+ */
+void dma_cache_maint(const void *start, size_t size, int direction)
+{
+	const void *end = start + size;
+
+	BUG_ON(!virt_addr_valid(start) || !virt_addr_valid(end - 1));
+
+	switch (direction) {
+	case DMA_FROM_DEVICE:		/* invalidate only */
+		dmac_inv_range(start, end);
+		outer_inv_range(__pa(start), __pa(end));
+		break;
+	case DMA_TO_DEVICE:		/* writeback only */
+		dmac_clean_range(start, end);
+		outer_clean_range(__pa(start), __pa(end));
+		break;
+	case DMA_BIDIRECTIONAL:		/* writeback and invalidate */
+		dmac_flush_range(start, end);
+		outer_flush_range(__pa(start), __pa(end));
+		break;
+	default:
+		BUG();
+	}
+}
+EXPORT_SYMBOL(dma_cache_maint);
+
+/**
+ * dma_map_sg - map a set of SG buffers for streaming mode DMA
+ * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
+ * @sg: list of buffers
+ * @nents: number of buffers to map
+ * @dir: DMA transfer direction
+ *
+ * Map a set of buffers described by scatterlist in streaming mode for DMA.
+ * This is the scatter-gather version of the dma_map_single interface.
+ * Here the scatter gather list elements are each tagged with the
+ * appropriate dma address and length.  They are obtained via
+ * sg_dma_{address,length}.
+ *
+ * Device ownership issues as mentioned for dma_map_single are the same
+ * here.
+ */
+int dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
+		enum dma_data_direction dir)
+{
+	struct scatterlist *s;
+	int i, j;
+
+	for_each_sg(sg, s, nents, i) {
+		s->dma_address = dma_map_page(dev, sg_page(s), s->offset,
+						s->length, dir);
+		if (dma_mapping_error(dev, s->dma_address))
+			goto bad_mapping;
+	}
+	return nents;
+
+ bad_mapping:
+	for_each_sg(sg, s, i, j)
+		dma_unmap_page(dev, sg_dma_address(s), sg_dma_len(s), dir);
+	return 0;
+}
+EXPORT_SYMBOL(dma_map_sg);
+
+/**
+ * dma_unmap_sg - unmap a set of SG buffers mapped by dma_map_sg
+ * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
+ * @sg: list of buffers
+ * @nents: number of buffers to unmap (returned from dma_map_sg)
+ * @dir: DMA transfer direction (same as was passed to dma_map_sg)
+ *
+ * Unmap a set of streaming mode DMA translations.  Again, CPU access
+ * rules concerning calls here are the same as for dma_unmap_single().
+ */
+void dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nents,
+		enum dma_data_direction dir)
+{
+	struct scatterlist *s;
+	int i;
+
+	for_each_sg(sg, s, nents, i)
+		dma_unmap_page(dev, sg_dma_address(s), sg_dma_len(s), dir);
+}
+EXPORT_SYMBOL(dma_unmap_sg);
+
+/**
+ * dma_sync_sg_for_cpu
+ * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
+ * @sg: list of buffers
+ * @nents: number of buffers to map (returned from dma_map_sg)
+ * @dir: DMA transfer direction (same as was passed to dma_map_sg)
+ */
+void dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg,
+			int nents, enum dma_data_direction dir)
+{
+	struct scatterlist *s;
+	int i;
+
+	for_each_sg(sg, s, nents, i) {
+		dmabounce_sync_for_cpu(dev, sg_dma_address(s), 0,
+					sg_dma_len(s), dir);
+	}
+}
+EXPORT_SYMBOL(dma_sync_sg_for_cpu);
+
+/**
+ * dma_sync_sg_for_device
+ * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
+ * @sg: list of buffers
+ * @nents: number of buffers to map (returned from dma_map_sg)
+ * @dir: DMA transfer direction (same as was passed to dma_map_sg)
+ */
+void dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg,
+			int nents, enum dma_data_direction dir)
+{
+	struct scatterlist *s;
+	int i;
+
+	for_each_sg(sg, s, nents, i) {
+		if (!dmabounce_sync_for_device(dev, sg_dma_address(s), 0,
+					sg_dma_len(s), dir))
+			continue;
+
+		if (!arch_is_coherent())
+			dma_cache_maint(sg_virt(s), s->length, dir);
+	}
+}
+EXPORT_SYMBOL(dma_sync_sg_for_device);
diff --git a/arch/arm/mm/extable.c b/arch/arm/mm/extable.c
index 9592c3e..9d28562 100644
--- a/arch/arm/mm/extable.c
+++ b/arch/arm/mm/extable.c
@@ -2,7 +2,7 @@
  *  linux/arch/arm/mm/extable.c
  */
 #include <linux/module.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
 
 int fixup_exception(struct pt_regs *regs)
 {
diff --git a/arch/arm/mm/fault-armv.c b/arch/arm/mm/fault-armv.c
index a8ec97b..81d0b87 100644
--- a/arch/arm/mm/fault-armv.c
+++ b/arch/arm/mm/fault-armv.c
@@ -17,11 +17,13 @@
 #include <linux/init.h>
 #include <linux/pagemap.h>
 
+#include <asm/bugs.h>
 #include <asm/cacheflush.h>
+#include <asm/cachetype.h>
 #include <asm/pgtable.h>
 #include <asm/tlbflush.h>
 
-static unsigned long shared_pte_mask = L_PTE_CACHEABLE;
+static unsigned long shared_pte_mask = L_PTE_MT_BUFFERABLE;
 
 /*
  * We take the easy way out of this problem - we make the
@@ -63,9 +65,10 @@
 	 * If this page isn't present, or is already setup to
 	 * fault (ie, is old), we can safely ignore any issues.
 	 */
-	if (ret && pte_val(entry) & shared_pte_mask) {
+	if (ret && (pte_val(entry) & L_PTE_MT_MASK) != shared_pte_mask) {
 		flush_cache_page(vma, address, pte_pfn(entry));
-		pte_val(entry) &= ~shared_pte_mask;
+		pte_val(entry) &= ~L_PTE_MT_MASK;
+		pte_val(entry) |= shared_pte_mask;
 		set_pte_at(vma->vm_mm, address, pte, entry);
 		flush_tlb_page(vma, address);
 	}
@@ -197,7 +200,7 @@
 		unsigned long *p1, *p2;
 		pgprot_t prot = __pgprot(L_PTE_PRESENT|L_PTE_YOUNG|
 					 L_PTE_DIRTY|L_PTE_WRITE|
-					 L_PTE_BUFFERABLE);
+					 L_PTE_MT_BUFFERABLE);
 
 		p1 = vmap(&page, 1, VM_IOREMAP, prot);
 		p2 = vmap(&page, 1, VM_IOREMAP, prot);
@@ -218,7 +221,7 @@
 
 	if (v) {
 		printk("failed, %s\n", reason);
-		shared_pte_mask |= L_PTE_BUFFERABLE;
+		shared_pte_mask = L_PTE_MT_UNCACHED;
 	} else {
 		printk("ok\n");
 	}
diff --git a/arch/arm/mm/fault.c b/arch/arm/mm/fault.c
index 28ad7ab..2df8d9f 100644
--- a/arch/arm/mm/fault.c
+++ b/arch/arm/mm/fault.c
@@ -13,11 +13,11 @@
 #include <linux/mm.h>
 #include <linux/init.h>
 #include <linux/kprobes.h>
+#include <linux/uaccess.h>
 
 #include <asm/system.h>
 #include <asm/pgtable.h>
 #include <asm/tlbflush.h>
-#include <asm/uaccess.h>
 
 #include "fault.h"
 
@@ -72,9 +72,8 @@
 		}
 
 		pmd = pmd_offset(pgd, addr);
-#if PTRS_PER_PMD != 1
-		printk(", *pmd=%08lx", pmd_val(*pmd));
-#endif
+		if (PTRS_PER_PMD != 1)
+			printk(", *pmd=%08lx", pmd_val(*pmd));
 
 		if (pmd_none(*pmd))
 			break;
diff --git a/arch/arm/mm/flush.c b/arch/arm/mm/flush.c
index 029ee65..0fa9bf3 100644
--- a/arch/arm/mm/flush.c
+++ b/arch/arm/mm/flush.c
@@ -12,6 +12,7 @@
 #include <linux/pagemap.h>
 
 #include <asm/cacheflush.h>
+#include <asm/cachetype.h>
 #include <asm/system.h>
 #include <asm/tlbflush.h>
 
diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c
index 30a69d6..82c4b42 100644
--- a/arch/arm/mm/init.c
+++ b/arch/arm/mm/init.c
@@ -26,9 +26,42 @@
 
 #include "mm.h"
 
-extern void _text, _etext, __data_start, _end, __init_begin, __init_end;
-extern unsigned long phys_initrd_start;
-extern unsigned long phys_initrd_size;
+static unsigned long phys_initrd_start __initdata = 0;
+static unsigned long phys_initrd_size __initdata = 0;
+
+static void __init early_initrd(char **p)
+{
+	unsigned long start, size;
+
+	start = memparse(*p, p);
+	if (**p == ',') {
+		size = memparse((*p) + 1, p);
+
+		phys_initrd_start = start;
+		phys_initrd_size = size;
+	}
+}
+__early_param("initrd=", early_initrd);
+
+static int __init parse_tag_initrd(const struct tag *tag)
+{
+	printk(KERN_WARNING "ATAG_INITRD is deprecated; "
+		"please update your bootloader.\n");
+	phys_initrd_start = __virt_to_phys(tag->u.initrd.start);
+	phys_initrd_size = tag->u.initrd.size;
+	return 0;
+}
+
+__tagtable(ATAG_INITRD, parse_tag_initrd);
+
+static int __init parse_tag_initrd2(const struct tag *tag)
+{
+	phys_initrd_start = tag->u.initrd.start;
+	phys_initrd_size = tag->u.initrd.size;
+	return 0;
+}
+
+__tagtable(ATAG_INITRD2, parse_tag_initrd2);
 
 /*
  * This is used to pass memory configuration data from paging_init
@@ -36,10 +69,6 @@
  */
 static struct meminfo meminfo = { 0, };
 
-#define for_each_nodebank(iter,mi,no)			\
-	for (iter = 0; iter < mi->nr_banks; iter++)	\
-		if (mi->bank[iter].node == no)
-
 void show_mem(void)
 {
 	int free = 0, total = 0, reserved = 0;
@@ -50,14 +79,15 @@
 	show_free_areas();
 	for_each_online_node(node) {
 		pg_data_t *n = NODE_DATA(node);
-		struct page *map = n->node_mem_map - n->node_start_pfn;
+		struct page *map = pgdat_page_nr(n, 0) - n->node_start_pfn;
 
 		for_each_nodebank (i,mi,node) {
+			struct membank *bank = &mi->bank[i];
 			unsigned int pfn1, pfn2;
 			struct page *page, *end;
 
-			pfn1 = __phys_to_pfn(mi->bank[i].start);
-			pfn2 = __phys_to_pfn(mi->bank[i].size + mi->bank[i].start);
+			pfn1 = bank_pfn_start(bank);
+			pfn2 = bank_pfn_end(bank);
 
 			page = map + pfn1;
 			end  = map + pfn2;
@@ -96,17 +126,17 @@
 static unsigned int __init
 find_bootmap_pfn(int node, struct meminfo *mi, unsigned int bootmap_pages)
 {
-	unsigned int start_pfn, bank, bootmap_pfn;
+	unsigned int start_pfn, i, bootmap_pfn;
 
 	start_pfn   = PAGE_ALIGN(__pa(&_end)) >> PAGE_SHIFT;
 	bootmap_pfn = 0;
 
-	for_each_nodebank(bank, mi, node) {
+	for_each_nodebank(i, mi, node) {
+		struct membank *bank = &mi->bank[i];
 		unsigned int start, end;
 
-		start = mi->bank[bank].start >> PAGE_SHIFT;
-		end   = (mi->bank[bank].size +
-			 mi->bank[bank].start) >> PAGE_SHIFT;
+		start = bank_pfn_start(bank);
+		end   = bank_pfn_end(bank);
 
 		if (end < start_pfn)
 			continue;
@@ -145,13 +175,10 @@
 		initrd_node = -1;
 
 		for (i = 0; i < mi->nr_banks; i++) {
-			unsigned long bank_end;
-
-			bank_end = mi->bank[i].start + mi->bank[i].size;
-
-			if (mi->bank[i].start <= phys_initrd_start &&
-			    end <= bank_end)
-				initrd_node = mi->bank[i].node;
+			struct membank *bank = &mi->bank[i];
+			if (bank_phys_start(bank) <= phys_initrd_start &&
+			    end <= bank_phys_end(bank))
+				initrd_node = bank->node;
 		}
 	}
 
@@ -171,19 +198,17 @@
 #ifdef CONFIG_MMU
 	struct map_desc map;
 
-	map.pfn = __phys_to_pfn(bank->start);
-	map.virtual = __phys_to_virt(bank->start);
-	map.length = bank->size;
+	map.pfn = bank_pfn_start(bank);
+	map.virtual = __phys_to_virt(bank_phys_start(bank));
+	map.length = bank_phys_size(bank);
 	map.type = MT_MEMORY;
 
 	create_mapping(&map);
 #endif
 }
 
-static unsigned long __init
-bootmem_init_node(int node, int initrd_node, struct meminfo *mi)
+static unsigned long __init bootmem_init_node(int node, struct meminfo *mi)
 {
-	unsigned long zone_size[MAX_NR_ZONES], zhole_size[MAX_NR_ZONES];
 	unsigned long start_pfn, end_pfn, boot_pfn;
 	unsigned int boot_pages;
 	pg_data_t *pgdat;
@@ -199,8 +224,8 @@
 		struct membank *bank = &mi->bank[i];
 		unsigned long start, end;
 
-		start = bank->start >> PAGE_SHIFT;
-		end = (bank->start + bank->size) >> PAGE_SHIFT;
+		start = bank_pfn_start(bank);
+		end = bank_pfn_end(bank);
 
 		if (start_pfn > start)
 			start_pfn = start;
@@ -230,8 +255,11 @@
 	pgdat = NODE_DATA(node);
 	init_bootmem_node(pgdat, boot_pfn, start_pfn, end_pfn);
 
-	for_each_nodebank(i, mi, node)
-		free_bootmem_node(pgdat, mi->bank[i].start, mi->bank[i].size);
+	for_each_nodebank(i, mi, node) {
+		struct membank *bank = &mi->bank[i];
+		free_bootmem_node(pgdat, bank_phys_start(bank), bank_phys_size(bank));
+		memory_present(node, bank_pfn_start(bank), bank_pfn_end(bank));
+	}
 
 	/*
 	 * Reserve the bootmem bitmap for this node.
@@ -239,31 +267,39 @@
 	reserve_bootmem_node(pgdat, boot_pfn << PAGE_SHIFT,
 			     boot_pages << PAGE_SHIFT, BOOTMEM_DEFAULT);
 
-	/*
-	 * Reserve any special node zero regions.
-	 */
-	if (node == 0)
-		reserve_node_zero(pgdat);
+	return end_pfn;
+}
 
+static void __init bootmem_reserve_initrd(int node)
+{
 #ifdef CONFIG_BLK_DEV_INITRD
-	/*
-	 * If the initrd is in this node, reserve its memory.
-	 */
-	if (node == initrd_node) {
-		int res = reserve_bootmem_node(pgdat, phys_initrd_start,
-				     phys_initrd_size, BOOTMEM_EXCLUSIVE);
+	pg_data_t *pgdat = NODE_DATA(node);
+	int res;
 
-		if (res == 0) {
-			initrd_start = __phys_to_virt(phys_initrd_start);
-			initrd_end = initrd_start + phys_initrd_size;
-		} else {
-			printk(KERN_ERR
-				"INITRD: 0x%08lx+0x%08lx overlaps in-use "
-				"memory region - disabling initrd\n",
-				phys_initrd_start, phys_initrd_size);
-		}
+	res = reserve_bootmem_node(pgdat, phys_initrd_start,
+			     phys_initrd_size, BOOTMEM_EXCLUSIVE);
+
+	if (res == 0) {
+		initrd_start = __phys_to_virt(phys_initrd_start);
+		initrd_end = initrd_start + phys_initrd_size;
+	} else {
+		printk(KERN_ERR
+			"INITRD: 0x%08lx+0x%08lx overlaps in-use "
+			"memory region - disabling initrd\n",
+			phys_initrd_start, phys_initrd_size);
 	}
 #endif
+}
+
+static void __init bootmem_free_node(int node, struct meminfo *mi)
+{
+	unsigned long zone_size[MAX_NR_ZONES], zhole_size[MAX_NR_ZONES];
+	unsigned long start_pfn, end_pfn;
+	pg_data_t *pgdat = NODE_DATA(node);
+	int i;
+
+	start_pfn = pgdat->bdata->node_min_pfn;
+	end_pfn = pgdat->bdata->node_low_pfn;
 
 	/*
 	 * initialise the zones within this node.
@@ -284,7 +320,7 @@
 	 */
 	zhole_size[0] = zone_size[0];
 	for_each_nodebank(i, mi, node)
-		zhole_size[0] -= mi->bank[i].size >> PAGE_SHIFT;
+		zhole_size[0] -= bank_pfn_size(&mi->bank[i]);
 
 	/*
 	 * Adjust the sizes according to any special requirements for
@@ -293,21 +329,12 @@
 	arch_adjust_zones(node, zone_size, zhole_size);
 
 	free_area_init_node(node, zone_size, start_pfn, zhole_size);
-
-	return end_pfn;
 }
 
 void __init bootmem_init(struct meminfo *mi)
 {
 	unsigned long memend_pfn = 0;
-	int node, initrd_node, i;
-
-	/*
-	 * Invalidate the node number for empty or invalid memory banks
-	 */
-	for (i = 0; i < mi->nr_banks; i++)
-		if (mi->bank[i].size == 0 || mi->bank[i].node >= MAX_NUMNODES)
-			mi->bank[i].node = -1;
+	int node, initrd_node;
 
 	memcpy(&meminfo, mi, sizeof(meminfo));
 
@@ -320,9 +347,19 @@
 	 * Run through each node initialising the bootmem allocator.
 	 */
 	for_each_node(node) {
-		unsigned long end_pfn;
+		unsigned long end_pfn = bootmem_init_node(node, mi);
 
-		end_pfn = bootmem_init_node(node, initrd_node, mi);
+		/*
+		 * Reserve any special node zero regions.
+		 */
+		if (node == 0)
+			reserve_node_zero(NODE_DATA(node));
+
+		/*
+		 * If the initrd is in this node, reserve its memory.
+		 */
+		if (node == initrd_node)
+			bootmem_reserve_initrd(node);
 
 		/*
 		 * Remember the highest memory PFN.
@@ -331,6 +368,19 @@
 			memend_pfn = end_pfn;
 	}
 
+	/*
+	 * sparse_init() needs the bootmem allocator up and running.
+	 */
+	sparse_init();
+
+	/*
+	 * Now free memory in each node - free_area_init_node needs
+	 * the sparse mem_map arrays initialized by sparse_init()
+	 * for memmap_init_zone(), otherwise all PFNs are invalid.
+	 */
+	for_each_node(node)
+		bootmem_free_node(node, mi);
+
 	high_memory = __va(memend_pfn << PAGE_SHIFT);
 
 	/*
@@ -401,7 +451,9 @@
 	 * information on the command line.
 	 */
 	for_each_nodebank(i, mi, node) {
-		bank_start = mi->bank[i].start >> PAGE_SHIFT;
+		struct membank *bank = &mi->bank[i];
+
+		bank_start = bank_pfn_start(bank);
 		if (bank_start < prev_bank_end) {
 			printk(KERN_ERR "MEM: unordered memory banks.  "
 				"Not freeing memmap.\n");
@@ -415,8 +467,7 @@
 		if (prev_bank_end && prev_bank_end != bank_start)
 			free_memmap(node, prev_bank_end, bank_start);
 
-		prev_bank_end = (mi->bank[i].start +
-				 mi->bank[i].size) >> PAGE_SHIFT;
+		prev_bank_end = bank_pfn_end(bank);
 	}
 }
 
@@ -461,8 +512,8 @@
 
 	num_physpages = 0;
 	for (i = 0; i < meminfo.nr_banks; i++) {
-		num_physpages += meminfo.bank[i].size >> PAGE_SHIFT;
-		printk(" %ldMB", meminfo.bank[i].size >> 20);
+		num_physpages += bank_pfn_size(&meminfo.bank[i]);
+		printk(" %ldMB", bank_phys_size(&meminfo.bank[i]) >> 20);
 	}
 
 	printk(" = %luMB total\n", num_physpages >> (20 - PAGE_SHIFT));
diff --git a/arch/arm/mm/iomap.c b/arch/arm/mm/iomap.c
index 7429f8c..ffad039 100644
--- a/arch/arm/mm/iomap.c
+++ b/arch/arm/mm/iomap.c
@@ -7,8 +7,7 @@
 #include <linux/module.h>
 #include <linux/pci.h>
 #include <linux/ioport.h>
-
-#include <asm/io.h>
+#include <linux/io.h>
 
 #ifdef __io
 void __iomem *ioport_map(unsigned long port, unsigned int nr)
diff --git a/arch/arm/mm/ioremap.c b/arch/arm/mm/ioremap.c
index b81dbf9..18373f7 100644
--- a/arch/arm/mm/ioremap.c
+++ b/arch/arm/mm/ioremap.c
@@ -24,9 +24,10 @@
 #include <linux/errno.h>
 #include <linux/mm.h>
 #include <linux/vmalloc.h>
+#include <linux/io.h>
 
+#include <asm/cputype.h>
 #include <asm/cacheflush.h>
-#include <asm/io.h>
 #include <asm/mmu_context.h>
 #include <asm/pgalloc.h>
 #include <asm/tlbflush.h>
@@ -55,8 +56,7 @@
 		if (!pte_none(*pte))
 			goto bad;
 
-		set_pte_ext(pte, pfn_pte(phys_addr >> PAGE_SHIFT, prot),
-			    type->prot_pte_ext);
+		set_pte_ext(pte, pfn_pte(phys_addr >> PAGE_SHIFT, prot), 0);
 		phys_addr += PAGE_SIZE;
 	} while (pte++, addr += PAGE_SIZE, addr != end);
 	return 0;
@@ -332,15 +332,14 @@
 }
 EXPORT_SYMBOL(__arm_ioremap);
 
-void __iounmap(volatile void __iomem *addr)
+void __iounmap(volatile void __iomem *io_addr)
 {
+	void *addr = (void *)(PAGE_MASK & (unsigned long)io_addr);
 #ifndef CONFIG_SMP
 	struct vm_struct **p, *tmp;
 #endif
 	unsigned int section_mapping = 0;
 
-	addr = (volatile void __iomem *)(PAGE_MASK & (unsigned long)addr);
-
 #ifndef CONFIG_SMP
 	/*
 	 * If this is a section based mapping we need to handle it
@@ -351,7 +350,7 @@
 	 */
 	write_lock(&vmlist_lock);
 	for (p = &vmlist ; (tmp = *p) ; p = &tmp->next) {
-		if((tmp->flags & VM_IOREMAP) && (tmp->addr == addr)) {
+		if ((tmp->flags & VM_IOREMAP) && (tmp->addr == addr)) {
 			if (tmp->flags & VM_ARM_SECTION_MAPPING) {
 				*p = tmp->next;
 				unmap_area_sections((unsigned long)tmp->addr,
@@ -366,6 +365,6 @@
 #endif
 
 	if (!section_mapping)
-		vunmap((void __force *)addr);
+		vunmap(addr);
 }
 EXPORT_SYMBOL(__iounmap);
diff --git a/arch/arm/mm/mm.h b/arch/arm/mm/mm.h
index 7647c59..5d9f539 100644
--- a/arch/arm/mm/mm.h
+++ b/arch/arm/mm/mm.h
@@ -18,7 +18,6 @@
 
 struct mem_type {
 	unsigned int prot_pte;
-	unsigned int prot_pte_ext;
 	unsigned int prot_l1;
 	unsigned int prot_sect;
 	unsigned int domain;
@@ -35,3 +34,5 @@
 void __init create_mapping(struct map_desc *md);
 void __init bootmem_init(struct meminfo *mi);
 void reserve_node_zero(struct pglist_data *pgdat);
+
+extern void _text, _stext, _etext, __data_start, _end, __init_begin, __init_end;
diff --git a/arch/arm/mm/mmap.c b/arch/arm/mm/mmap.c
index 3f6dc40..5358fcc 100644
--- a/arch/arm/mm/mmap.c
+++ b/arch/arm/mm/mmap.c
@@ -6,6 +6,8 @@
 #include <linux/mman.h>
 #include <linux/shm.h>
 #include <linux/sched.h>
+#include <linux/io.h>
+#include <asm/cputype.h>
 #include <asm/system.h>
 
 #define COLOUR_ALIGN(addr,pgoff)		\
@@ -37,8 +39,8 @@
 	 * caches alias.  This is indicated by bits 9 and 21 of the
 	 * cache type register.
 	 */
-	cache_type = read_cpuid(CPUID_CACHETYPE);
-	if (cache_type != read_cpuid(CPUID_ID)) {
+	cache_type = read_cpuid_cachetype();
+	if (cache_type != read_cpuid_id()) {
 		aliasing = (cache_type | cache_type >> 12) & (1 << 11);
 		if (aliasing)
 			do_align = filp || flags & MAP_SHARED;
diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c
index a713e40..8ba7540 100644
--- a/arch/arm/mm/mmu.c
+++ b/arch/arm/mm/mmu.c
@@ -15,6 +15,7 @@
 #include <linux/mman.h>
 #include <linux/nodemask.h>
 
+#include <asm/cputype.h>
 #include <asm/mach-types.h>
 #include <asm/setup.h>
 #include <asm/sizes.h>
@@ -27,9 +28,6 @@
 
 DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
 
-extern void _stext, _etext, __data_start, _end;
-extern pgd_t swapper_pg_dir[PTRS_PER_PGD];
-
 /*
  * empty_zero_page is a special page that is used for
  * zero-initialized data and COW.
@@ -68,27 +66,27 @@
 		.policy		= "uncached",
 		.cr_mask	= CR_W|CR_C,
 		.pmd		= PMD_SECT_UNCACHED,
-		.pte		= 0,
+		.pte		= L_PTE_MT_UNCACHED,
 	}, {
 		.policy		= "buffered",
 		.cr_mask	= CR_C,
 		.pmd		= PMD_SECT_BUFFERED,
-		.pte		= PTE_BUFFERABLE,
+		.pte		= L_PTE_MT_BUFFERABLE,
 	}, {
 		.policy		= "writethrough",
 		.cr_mask	= 0,
 		.pmd		= PMD_SECT_WT,
-		.pte		= PTE_CACHEABLE,
+		.pte		= L_PTE_MT_WRITETHROUGH,
 	}, {
 		.policy		= "writeback",
 		.cr_mask	= 0,
 		.pmd		= PMD_SECT_WB,
-		.pte		= PTE_BUFFERABLE|PTE_CACHEABLE,
+		.pte		= L_PTE_MT_WRITEBACK,
 	}, {
 		.policy		= "writealloc",
 		.cr_mask	= 0,
 		.pmd		= PMD_SECT_WBWA,
-		.pte		= PTE_BUFFERABLE|PTE_CACHEABLE,
+		.pte		= L_PTE_MT_WRITEALLOC,
 	}
 };
 
@@ -186,35 +184,28 @@
 
 static struct mem_type mem_types[] = {
 	[MT_DEVICE] = {		  /* Strongly ordered / ARMv6 shared device */
-		.prot_pte	= PROT_PTE_DEVICE,
+		.prot_pte	= PROT_PTE_DEVICE | L_PTE_MT_DEV_SHARED |
+				  L_PTE_SHARED,
 		.prot_l1	= PMD_TYPE_TABLE,
 		.prot_sect	= PROT_SECT_DEVICE | PMD_SECT_UNCACHED,
 		.domain		= DOMAIN_IO,
 	},
 	[MT_DEVICE_NONSHARED] = { /* ARMv6 non-shared device */
-		.prot_pte	= PROT_PTE_DEVICE,
-		.prot_pte_ext	= PTE_EXT_TEX(2),
+		.prot_pte	= PROT_PTE_DEVICE | L_PTE_MT_DEV_NONSHARED,
 		.prot_l1	= PMD_TYPE_TABLE,
 		.prot_sect	= PROT_SECT_DEVICE | PMD_SECT_TEX(2),
 		.domain		= DOMAIN_IO,
 	},
 	[MT_DEVICE_CACHED] = {	  /* ioremap_cached */
-		.prot_pte	= PROT_PTE_DEVICE | L_PTE_CACHEABLE | L_PTE_BUFFERABLE,
+		.prot_pte	= PROT_PTE_DEVICE | L_PTE_MT_DEV_CACHED,
 		.prot_l1	= PMD_TYPE_TABLE,
 		.prot_sect	= PROT_SECT_DEVICE | PMD_SECT_WB,
 		.domain		= DOMAIN_IO,
 	},	
-	[MT_DEVICE_IXP2000] = {	  /* IXP2400 requires XCB=101 for on-chip I/O */
-		.prot_pte	= PROT_PTE_DEVICE,
-		.prot_l1	= PMD_TYPE_TABLE,
-		.prot_sect	= PROT_SECT_DEVICE | PMD_SECT_BUFFERABLE |
-				  PMD_SECT_TEX(1),
-		.domain		= DOMAIN_IO,
-	},
 	[MT_DEVICE_WC] = {	/* ioremap_wc */
-		.prot_pte	= PROT_PTE_DEVICE,
+		.prot_pte	= PROT_PTE_DEVICE | L_PTE_MT_DEV_WC,
 		.prot_l1	= PMD_TYPE_TABLE,
-		.prot_sect	= PROT_SECT_DEVICE,
+		.prot_sect	= PROT_SECT_DEVICE | PMD_SECT_BUFFERABLE,
 		.domain		= DOMAIN_IO,
 	},
 	[MT_CACHECLEAN] = {
@@ -259,7 +250,7 @@
 {
 	struct cachepolicy *cp;
 	unsigned int cr = get_cr();
-	unsigned int user_pgprot, kern_pgprot;
+	unsigned int user_pgprot, kern_pgprot, vecs_pgprot;
 	int cpu_arch = cpu_architecture();
 	int i;
 
@@ -277,6 +268,9 @@
 			cachepolicy = CPOLICY_WRITEBACK;
 		ecc_mask = 0;
 	}
+#ifdef CONFIG_SMP
+	cachepolicy = CPOLICY_WRITEALLOC;
+#endif
 
 	/*
 	 * On non-Xscale3 ARMv5-and-older systems, use CB=01
@@ -285,11 +279,8 @@
 	 * in xsc3 parlance, Uncached Normal in ARMv6 parlance).
 	 */
 	if (cpu_is_xsc3() || cpu_arch >= CPU_ARCH_ARMv6) {
-		mem_types[MT_DEVICE_WC].prot_pte_ext |= PTE_EXT_TEX(1);
 		mem_types[MT_DEVICE_WC].prot_sect |= PMD_SECT_TEX(1);
-	} else {
-		mem_types[MT_DEVICE_WC].prot_pte |= L_PTE_BUFFERABLE;
-		mem_types[MT_DEVICE_WC].prot_sect |= PMD_SECT_BUFFERABLE;
+		mem_types[MT_DEVICE_WC].prot_sect &= ~PMD_SECT_BUFFERABLE;
 	}
 
 	/*
@@ -312,7 +303,15 @@
 	}
 
 	cp = &cache_policies[cachepolicy];
-	kern_pgprot = user_pgprot = cp->pte;
+	vecs_pgprot = kern_pgprot = user_pgprot = cp->pte;
+
+#ifndef CONFIG_SMP
+	/*
+	 * Only use write-through for non-SMP systems
+	 */
+	if (cpu_arch >= CPU_ARCH_ARMv5 && cachepolicy > CPOLICY_WRITETHROUGH)
+		vecs_pgprot = cache_policies[CPOLICY_WRITETHROUGH].pte;
+#endif
 
 	/*
 	 * Enable CPU-specific coherency if supported.
@@ -340,7 +339,6 @@
 		/*
 		 * Mark the device area as "shared device"
 		 */
-		mem_types[MT_DEVICE].prot_pte |= L_PTE_BUFFERABLE;
 		mem_types[MT_DEVICE].prot_sect |= PMD_SECT_BUFFERED;
 
 #ifdef CONFIG_SMP
@@ -349,30 +347,21 @@
 		 */
 		user_pgprot |= L_PTE_SHARED;
 		kern_pgprot |= L_PTE_SHARED;
+		vecs_pgprot |= L_PTE_SHARED;
 		mem_types[MT_MEMORY].prot_sect |= PMD_SECT_S;
 #endif
 	}
 
 	for (i = 0; i < 16; i++) {
 		unsigned long v = pgprot_val(protection_map[i]);
-		v = (v & ~(L_PTE_BUFFERABLE|L_PTE_CACHEABLE)) | user_pgprot;
-		protection_map[i] = __pgprot(v);
+		protection_map[i] = __pgprot(v | user_pgprot);
 	}
 
-	mem_types[MT_LOW_VECTORS].prot_pte |= kern_pgprot;
-	mem_types[MT_HIGH_VECTORS].prot_pte |= kern_pgprot;
+	mem_types[MT_LOW_VECTORS].prot_pte |= vecs_pgprot;
+	mem_types[MT_HIGH_VECTORS].prot_pte |= vecs_pgprot;
 
-	if (cpu_arch >= CPU_ARCH_ARMv5) {
-#ifndef CONFIG_SMP
-		/*
-		 * Only use write-through for non-SMP systems
-		 */
-		mem_types[MT_LOW_VECTORS].prot_pte &= ~L_PTE_BUFFERABLE;
-		mem_types[MT_HIGH_VECTORS].prot_pte &= ~L_PTE_BUFFERABLE;
-#endif
-	} else {
+	if (cpu_arch < CPU_ARCH_ARMv5)
 		mem_types[MT_MINICLEAN].prot_sect &= ~PMD_SECT_TEX(1);
-	}
 
 	pgprot_user   = __pgprot(L_PTE_PRESENT | L_PTE_YOUNG | user_pgprot);
 	pgprot_kernel = __pgprot(L_PTE_PRESENT | L_PTE_YOUNG |
@@ -420,8 +409,7 @@
 
 	pte = pte_offset_kernel(pmd, addr);
 	do {
-		set_pte_ext(pte, pfn_pte(pfn, __pgprot(type->prot_pte)),
-			    type->prot_pte_ext);
+		set_pte_ext(pte, pfn_pte(pfn, __pgprot(type->prot_pte)), 0);
 		pfn++;
 	} while (pte++, addr += PAGE_SIZE, addr != end);
 }
@@ -588,12 +576,35 @@
 		create_mapping(io_desc + i);
 }
 
+static unsigned long __initdata vmalloc_reserve = SZ_128M;
+
+/*
+ * vmalloc=size forces the vmalloc area to be exactly 'size'
+ * bytes. This can be used to increase (or decrease) the vmalloc
+ * area - the default is 128m.
+ */
+static void __init early_vmalloc(char **arg)
+{
+	vmalloc_reserve = memparse(*arg, arg);
+
+	if (vmalloc_reserve < SZ_16M) {
+		vmalloc_reserve = SZ_16M;
+		printk(KERN_WARNING
+			"vmalloc area too small, limiting to %luMB\n",
+			vmalloc_reserve >> 20);
+	}
+}
+__early_param("vmalloc=", early_vmalloc);
+
+#define VMALLOC_MIN	(void *)(VMALLOC_END - vmalloc_reserve)
+
 static int __init check_membank_valid(struct membank *mb)
 {
 	/*
-	 * Check whether this memory region has non-zero size.
+	 * Check whether this memory region has non-zero size or
+	 * invalid node number.
 	 */
-	if (mb->size == 0)
+	if (mb->size == 0 || mb->node >= MAX_NUMNODES)
 		return 0;
 
 	/*
@@ -627,8 +638,7 @@
 
 static void __init sanity_check_meminfo(struct meminfo *mi)
 {
-	int i;
-	int j;
+	int i, j;
 
 	for (i = 0, j = 0; i < mi->nr_banks; i++) {
 		if (check_membank_valid(&mi->bank[i]))
diff --git a/arch/arm/mm/nommu.c b/arch/arm/mm/nommu.c
index 63c62fd..07b62b2 100644
--- a/arch/arm/mm/nommu.c
+++ b/arch/arm/mm/nommu.c
@@ -7,16 +7,14 @@
 #include <linux/mm.h>
 #include <linux/pagemap.h>
 #include <linux/bootmem.h>
+#include <linux/io.h>
 
 #include <asm/cacheflush.h>
-#include <asm/io.h>
 #include <asm/page.h>
 #include <asm/mach/arch.h>
 
 #include "mm.h"
 
-extern void _stext, __data_start, _end;
-
 /*
  * Reserve the various regions of node 0
  */
@@ -43,12 +41,26 @@
 			BOOTMEM_DEFAULT);
 }
 
+static void __init sanity_check_meminfo(struct meminfo *mi)
+{
+	int i, j;
+
+	for (i = 0, j = 0; i < mi->nr_banks; i++) {
+		struct membank *mb = &mi->bank[i];
+
+		if (mb->size != 0 && mb->node < MAX_NUMNODES)
+			mi->bank[j++] = mi->bank[i];
+	}
+	mi->nr_banks = j;
+}
+
 /*
  * paging_init() sets up the page tables, initialises the zone memory
  * maps, and sets up the zero page, bad page and bad page tables.
  */
 void __init paging_init(struct meminfo *mi, struct machine_desc *mdesc)
 {
+	sanity_check_meminfo(mi);
 	bootmem_init(mi);
 }
 
diff --git a/arch/arm/mm/proc-arm1020.S b/arch/arm/mm/proc-arm1020.S
index 5673f4d..b5551bf 100644
--- a/arch/arm/mm/proc-arm1020.S
+++ b/arch/arm/mm/proc-arm1020.S
@@ -29,7 +29,7 @@
 #include <linux/init.h>
 #include <asm/assembler.h>
 #include <asm/asm-offsets.h>
-#include <asm/elf.h>
+#include <asm/hwcap.h>
 #include <asm/pgtable-hwdef.h>
 #include <asm/pgtable.h>
 #include <asm/ptrace.h>
@@ -399,29 +399,7 @@
 	.align	5
 ENTRY(cpu_arm1020_set_pte_ext)
 #ifdef CONFIG_MMU
-	str	r1, [r0], #-2048		@ linux version
-
-	eor	r1, r1, #L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_WRITE | L_PTE_DIRTY
-
-	bic	r2, r1, #PTE_SMALL_AP_MASK
-	bic	r2, r2, #PTE_TYPE_MASK
-	orr	r2, r2, #PTE_TYPE_SMALL
-
-	tst	r1, #L_PTE_USER			@ User?
-	orrne	r2, r2, #PTE_SMALL_AP_URO_SRW
-
-	tst	r1, #L_PTE_WRITE | L_PTE_DIRTY	@ Write and Dirty?
-	orreq	r2, r2, #PTE_SMALL_AP_UNO_SRW
-
-	tst	r1, #L_PTE_PRESENT | L_PTE_YOUNG	@ Present and Young?
-	movne	r2, #0
-
-#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH
-	eor	r3, r1, #0x0a			@ C & small page?
-	tst	r3, #0x0b
-	biceq	r2, r2, #4
-#endif
-	str	r2, [r0]			@ hardware version
+	armv3_set_pte_ext
 	mov	r0, r0
 #ifndef CONFIG_CPU_DCACHE_DISABLE
 	mcr	p15, 0, r0, c7, c10, 4
diff --git a/arch/arm/mm/proc-arm1020e.S b/arch/arm/mm/proc-arm1020e.S
index 4343fdb..8bc6740 100644
--- a/arch/arm/mm/proc-arm1020e.S
+++ b/arch/arm/mm/proc-arm1020e.S
@@ -29,7 +29,7 @@
 #include <linux/init.h>
 #include <asm/assembler.h>
 #include <asm/asm-offsets.h>
-#include <asm/elf.h>
+#include <asm/hwcap.h>
 #include <asm/pgtable-hwdef.h>
 #include <asm/pgtable.h>
 #include <asm/ptrace.h>
@@ -383,29 +383,7 @@
 	.align	5
 ENTRY(cpu_arm1020e_set_pte_ext)
 #ifdef CONFIG_MMU
-	str	r1, [r0], #-2048		@ linux version
-
-	eor	r1, r1, #L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_WRITE | L_PTE_DIRTY
-
-	bic	r2, r1, #PTE_SMALL_AP_MASK
-	bic	r2, r2, #PTE_TYPE_MASK
-	orr	r2, r2, #PTE_TYPE_SMALL
-
-	tst	r1, #L_PTE_USER			@ User?
-	orrne	r2, r2, #PTE_SMALL_AP_URO_SRW
-
-	tst	r1, #L_PTE_WRITE | L_PTE_DIRTY	@ Write and Dirty?
-	orreq	r2, r2, #PTE_SMALL_AP_UNO_SRW
-
-	tst	r1, #L_PTE_PRESENT | L_PTE_YOUNG	@ Present and Young?
-	movne	r2, #0
-
-#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH
-	eor	r3, r1, #0x0a			@ C & small page?
-	tst	r3, #0x0b
-	biceq	r2, r2, #4
-#endif
-	str	r2, [r0]			@ hardware version
+	armv3_set_pte_ext
 	mov	r0, r0
 #ifndef CONFIG_CPU_DCACHE_DISABLE
 	mcr	p15, 0, r0, c7, c10, 1		@ clean D entry
diff --git a/arch/arm/mm/proc-arm1022.S b/arch/arm/mm/proc-arm1022.S
index 2a4ea16..2cd03e6 100644
--- a/arch/arm/mm/proc-arm1022.S
+++ b/arch/arm/mm/proc-arm1022.S
@@ -18,7 +18,7 @@
 #include <linux/init.h>
 #include <asm/assembler.h>
 #include <asm/asm-offsets.h>
-#include <asm/elf.h>
+#include <asm/hwcap.h>
 #include <asm/pgtable-hwdef.h>
 #include <asm/pgtable.h>
 #include <asm/ptrace.h>
@@ -365,29 +365,7 @@
 	.align	5
 ENTRY(cpu_arm1022_set_pte_ext)
 #ifdef CONFIG_MMU
-	str	r1, [r0], #-2048		@ linux version
-
-	eor	r1, r1, #L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_WRITE | L_PTE_DIRTY
-
-	bic	r2, r1, #PTE_SMALL_AP_MASK
-	bic	r2, r2, #PTE_TYPE_MASK
-	orr	r2, r2, #PTE_TYPE_SMALL
-
-	tst	r1, #L_PTE_USER			@ User?
-	orrne	r2, r2, #PTE_SMALL_AP_URO_SRW
-
-	tst	r1, #L_PTE_WRITE | L_PTE_DIRTY	@ Write and Dirty?
-	orreq	r2, r2, #PTE_SMALL_AP_UNO_SRW
-
-	tst	r1, #L_PTE_PRESENT | L_PTE_YOUNG	@ Present and Young?
-	movne	r2, #0
-
-#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH
-	eor	r3, r1, #0x0a			@ C & small page?
-	tst	r3, #0x0b
-	biceq	r2, r2, #4
-#endif
-	str	r2, [r0]			@ hardware version
+	armv3_set_pte_ext
 	mov	r0, r0
 #ifndef CONFIG_CPU_DCACHE_DISABLE
 	mcr	p15, 0, r0, c7, c10, 1		@ clean D entry
diff --git a/arch/arm/mm/proc-arm1026.S b/arch/arm/mm/proc-arm1026.S
index 77a1bab..ad961a8 100644
--- a/arch/arm/mm/proc-arm1026.S
+++ b/arch/arm/mm/proc-arm1026.S
@@ -18,7 +18,7 @@
 #include <linux/init.h>
 #include <asm/assembler.h>
 #include <asm/asm-offsets.h>
-#include <asm/elf.h>
+#include <asm/hwcap.h>
 #include <asm/pgtable-hwdef.h>
 #include <asm/pgtable.h>
 #include <asm/ptrace.h>
@@ -354,29 +354,7 @@
 	.align	5
 ENTRY(cpu_arm1026_set_pte_ext)
 #ifdef CONFIG_MMU
-	str	r1, [r0], #-2048		@ linux version
-
-	eor	r1, r1, #L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_WRITE | L_PTE_DIRTY
-
-	bic	r2, r1, #PTE_SMALL_AP_MASK
-	bic	r2, r2, #PTE_TYPE_MASK
-	orr	r2, r2, #PTE_TYPE_SMALL
-
-	tst	r1, #L_PTE_USER			@ User?
-	orrne	r2, r2, #PTE_SMALL_AP_URO_SRW
-
-	tst	r1, #L_PTE_WRITE | L_PTE_DIRTY	@ Write and Dirty?
-	orreq	r2, r2, #PTE_SMALL_AP_UNO_SRW
-
-	tst	r1, #L_PTE_PRESENT | L_PTE_YOUNG	@ Present and Young?
-	movne	r2, #0
-
-#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH
-	eor	r3, r1, #0x0a			@ C & small page?
-	tst	r3, #0x0b
-	biceq	r2, r2, #4
-#endif
-	str	r2, [r0]			@ hardware version
+	armv3_set_pte_ext
 	mov	r0, r0
 #ifndef CONFIG_CPU_DCACHE_DISABLE
 	mcr	p15, 0, r0, c7, c10, 1		@ clean D entry
diff --git a/arch/arm/mm/proc-arm6_7.S b/arch/arm/mm/proc-arm6_7.S
index c371fc8..80d6e1d 100644
--- a/arch/arm/mm/proc-arm6_7.S
+++ b/arch/arm/mm/proc-arm6_7.S
@@ -15,11 +15,13 @@
 #include <linux/init.h>
 #include <asm/assembler.h>
 #include <asm/asm-offsets.h>
-#include <asm/elf.h>
+#include <asm/hwcap.h>
 #include <asm/pgtable-hwdef.h>
 #include <asm/pgtable.h>
 #include <asm/ptrace.h>
 
+#include "proc-macros.S"
+
 ENTRY(cpu_arm6_dcache_clean_area)
 ENTRY(cpu_arm7_dcache_clean_area)
 		mov	pc, lr
@@ -214,30 +216,13 @@
  *	   : r1 = value to set
  * Purpose : Set a PTE and flush it out of any WB cache
  */
-		.align	5
+	.align	5
 ENTRY(cpu_arm6_set_pte_ext)
 ENTRY(cpu_arm7_set_pte_ext)
 #ifdef CONFIG_MMU
-		str	r1, [r0], #-2048		@ linux version
-
-		eor	r1, r1, #L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_WRITE | L_PTE_DIRTY
-
-		bic	r2, r1, #PTE_SMALL_AP_MASK
-		bic	r2, r2, #PTE_TYPE_MASK
-		orr	r2, r2, #PTE_TYPE_SMALL
-
-		tst	r1, #L_PTE_USER			@ User?
-		orrne	r2, r2, #PTE_SMALL_AP_URO_SRW
-
-		tst	r1, #L_PTE_WRITE | L_PTE_DIRTY	@ Write and Dirty?
-		orreq	r2, r2, #PTE_SMALL_AP_UNO_SRW
-
-		tst	r1, #L_PTE_PRESENT | L_PTE_YOUNG	@ Present and Young
-		movne	r2, #0
-
-		str	r2, [r0]			@ hardware version
+	armv3_set_pte_ext wc_disable=0
 #endif /* CONFIG_MMU */
-		mov	pc, lr
+	mov	pc, lr
 
 /*
  * Function: _arm6_7_reset
diff --git a/arch/arm/mm/proc-arm720.S b/arch/arm/mm/proc-arm720.S
index eda733d..85ae186 100644
--- a/arch/arm/mm/proc-arm720.S
+++ b/arch/arm/mm/proc-arm720.S
@@ -36,7 +36,7 @@
 #include <linux/init.h>
 #include <asm/assembler.h>
 #include <asm/asm-offsets.h>
-#include <asm/elf.h>
+#include <asm/hwcap.h>
 #include <asm/pgtable-hwdef.h>
 #include <asm/pgtable.h>
 #include <asm/ptrace.h>
@@ -93,29 +93,12 @@
  *	   : r1 = value to set
  * Purpose : Set a PTE and flush it out of any WB cache
  */
-		.align	5
+	.align	5
 ENTRY(cpu_arm720_set_pte_ext)
 #ifdef CONFIG_MMU
-		str	r1, [r0], #-2048		@ linux version
-
-		eor	r1, r1, #L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_WRITE | L_PTE_DIRTY
-
-		bic	r2, r1, #PTE_SMALL_AP_MASK
-		bic	r2, r2, #PTE_TYPE_MASK
-		orr	r2, r2, #PTE_TYPE_SMALL
-
-		tst	r1, #L_PTE_USER			@ User?
-		orrne	r2, r2, #PTE_SMALL_AP_URO_SRW
-
-		tst	r1, #L_PTE_WRITE | L_PTE_DIRTY	@ Write and Dirty?
-		orreq	r2, r2, #PTE_SMALL_AP_UNO_SRW
-
-		tst	r1, #L_PTE_PRESENT | L_PTE_YOUNG	@ Present and Young
-		movne	r2, #0
-
-		str	r2, [r0]			@ hardware version
+	armv3_set_pte_ext wc_disable=0
 #endif
-		mov	pc, lr
+	mov	pc, lr
 
 /*
  * Function: arm720_reset
diff --git a/arch/arm/mm/proc-arm740.S b/arch/arm/mm/proc-arm740.S
index 3a57376..4f95bee 100644
--- a/arch/arm/mm/proc-arm740.S
+++ b/arch/arm/mm/proc-arm740.S
@@ -12,7 +12,7 @@
 #include <linux/init.h>
 #include <asm/assembler.h>
 #include <asm/asm-offsets.h>
-#include <asm/elf.h>
+#include <asm/hwcap.h>
 #include <asm/pgtable-hwdef.h>
 #include <asm/pgtable.h>
 #include <asm/ptrace.h>
diff --git a/arch/arm/mm/proc-arm7tdmi.S b/arch/arm/mm/proc-arm7tdmi.S
index 7b3ecde..93e05fa 100644
--- a/arch/arm/mm/proc-arm7tdmi.S
+++ b/arch/arm/mm/proc-arm7tdmi.S
@@ -12,7 +12,7 @@
 #include <linux/init.h>
 #include <asm/assembler.h>
 #include <asm/asm-offsets.h>
-#include <asm/elf.h>
+#include <asm/hwcap.h>
 #include <asm/pgtable-hwdef.h>
 #include <asm/pgtable.h>
 #include <asm/ptrace.h>
diff --git a/arch/arm/mm/proc-arm920.S b/arch/arm/mm/proc-arm920.S
index 28cdb06..914d688 100644
--- a/arch/arm/mm/proc-arm920.S
+++ b/arch/arm/mm/proc-arm920.S
@@ -28,7 +28,7 @@
 #include <linux/linkage.h>
 #include <linux/init.h>
 #include <asm/assembler.h>
-#include <asm/elf.h>
+#include <asm/hwcap.h>
 #include <asm/pgtable-hwdef.h>
 #include <asm/pgtable.h>
 #include <asm/page.h>
@@ -351,33 +351,11 @@
 	.align	5
 ENTRY(cpu_arm920_set_pte_ext)
 #ifdef CONFIG_MMU
-	str	r1, [r0], #-2048		@ linux version
-
-	eor	r1, r1, #L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_WRITE | L_PTE_DIRTY
-
-	bic	r2, r1, #PTE_SMALL_AP_MASK
-	bic	r2, r2, #PTE_TYPE_MASK
-	orr	r2, r2, #PTE_TYPE_SMALL
-
-	tst	r1, #L_PTE_USER			@ User?
-	orrne	r2, r2, #PTE_SMALL_AP_URO_SRW
-
-	tst	r1, #L_PTE_WRITE | L_PTE_DIRTY	@ Write and Dirty?
-	orreq	r2, r2, #PTE_SMALL_AP_UNO_SRW
-
-	tst	r1, #L_PTE_PRESENT | L_PTE_YOUNG	@ Present and Young?
-	movne	r2, #0
-
-#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH
-	eor	r3, r2, #0x0a			@ C & small page?
-	tst	r3, #0x0b
-	biceq	r2, r2, #4
-#endif
-	str	r2, [r0]			@ hardware version
+	armv3_set_pte_ext
 	mov	r0, r0
 	mcr	p15, 0, r0, c7, c10, 1		@ clean D entry
 	mcr	p15, 0, r0, c7, c10, 4		@ drain WB
-#endif /* CONFIG_MMU */
+#endif
 	mov	pc, lr
 
 	__INIT
diff --git a/arch/arm/mm/proc-arm922.S b/arch/arm/mm/proc-arm922.S
index 94ddcb4..51c9c98 100644
--- a/arch/arm/mm/proc-arm922.S
+++ b/arch/arm/mm/proc-arm922.S
@@ -29,7 +29,7 @@
 #include <linux/linkage.h>
 #include <linux/init.h>
 #include <asm/assembler.h>
-#include <asm/elf.h>
+#include <asm/hwcap.h>
 #include <asm/pgtable-hwdef.h>
 #include <asm/pgtable.h>
 #include <asm/page.h>
@@ -355,29 +355,7 @@
 	.align	5
 ENTRY(cpu_arm922_set_pte_ext)
 #ifdef CONFIG_MMU
-	str	r1, [r0], #-2048		@ linux version
-
-	eor	r1, r1, #L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_WRITE | L_PTE_DIRTY
-
-	bic	r2, r1, #PTE_SMALL_AP_MASK
-	bic	r2, r2, #PTE_TYPE_MASK
-	orr	r2, r2, #PTE_TYPE_SMALL
-
-	tst	r1, #L_PTE_USER			@ User?
-	orrne	r2, r2, #PTE_SMALL_AP_URO_SRW
-
-	tst	r1, #L_PTE_WRITE | L_PTE_DIRTY	@ Write and Dirty?
-	orreq	r2, r2, #PTE_SMALL_AP_UNO_SRW
-
-	tst	r1, #L_PTE_PRESENT | L_PTE_YOUNG	@ Present and Young?
-	movne	r2, #0
-
-#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH
-	eor	r3, r2, #0x0a			@ C & small page?
-	tst	r3, #0x0b
-	biceq	r2, r2, #4
-#endif
-	str	r2, [r0]			@ hardware version
+	armv3_set_pte_ext
 	mov	r0, r0
 	mcr	p15, 0, r0, c7, c10, 1		@ clean D entry
 	mcr	p15, 0, r0, c7, c10, 4		@ drain WB
diff --git a/arch/arm/mm/proc-arm925.S b/arch/arm/mm/proc-arm925.S
index d045812..2724526 100644
--- a/arch/arm/mm/proc-arm925.S
+++ b/arch/arm/mm/proc-arm925.S
@@ -52,7 +52,7 @@
 #include <linux/linkage.h>
 #include <linux/init.h>
 #include <asm/assembler.h>
-#include <asm/elf.h>
+#include <asm/hwcap.h>
 #include <asm/pgtable-hwdef.h>
 #include <asm/pgtable.h>
 #include <asm/page.h>
@@ -398,29 +398,7 @@
 	.align	5
 ENTRY(cpu_arm925_set_pte_ext)
 #ifdef CONFIG_MMU
-	str	r1, [r0], #-2048		@ linux version
-
-	eor	r1, r1, #L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_WRITE | L_PTE_DIRTY
-
-	bic	r2, r1, #PTE_SMALL_AP_MASK
-	bic	r2, r2, #PTE_TYPE_MASK
-	orr	r2, r2, #PTE_TYPE_SMALL
-
-	tst	r1, #L_PTE_USER			@ User?
-	orrne	r2, r2, #PTE_SMALL_AP_URO_SRW
-
-	tst	r1, #L_PTE_WRITE | L_PTE_DIRTY	@ Write and Dirty?
-	orreq	r2, r2, #PTE_SMALL_AP_UNO_SRW
-
-	tst	r1, #L_PTE_PRESENT | L_PTE_YOUNG	@ Present and Young?
-	movne	r2, #0
-
-#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH
-	eor	r3, r2, #0x0a			@ C & small page?
-	tst	r3, #0x0b
-	biceq	r2, r2, #4
-#endif
-	str	r2, [r0]			@ hardware version
+	armv3_set_pte_ext
 	mov	r0, r0
 #ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
 	mcr	p15, 0, r0, c7, c10, 1		@ clean D entry
diff --git a/arch/arm/mm/proc-arm926.S b/arch/arm/mm/proc-arm926.S
index 4cd3316..5446693 100644
--- a/arch/arm/mm/proc-arm926.S
+++ b/arch/arm/mm/proc-arm926.S
@@ -28,7 +28,7 @@
 #include <linux/linkage.h>
 #include <linux/init.h>
 #include <asm/assembler.h>
-#include <asm/elf.h>
+#include <asm/hwcap.h>
 #include <asm/pgtable-hwdef.h>
 #include <asm/pgtable.h>
 #include <asm/page.h>
@@ -359,29 +359,7 @@
 	.align	5
 ENTRY(cpu_arm926_set_pte_ext)
 #ifdef CONFIG_MMU
-	str	r1, [r0], #-2048		@ linux version
-
-	eor	r1, r1, #L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_WRITE | L_PTE_DIRTY
-
-	bic	r2, r1, #PTE_SMALL_AP_MASK
-	bic	r2, r2, #PTE_TYPE_MASK
-	orr	r2, r2, #PTE_TYPE_SMALL
-
-	tst	r1, #L_PTE_USER			@ User?
-	orrne	r2, r2, #PTE_SMALL_AP_URO_SRW
-
-	tst	r1, #L_PTE_WRITE | L_PTE_DIRTY	@ Write and Dirty?
-	orreq	r2, r2, #PTE_SMALL_AP_UNO_SRW
-
-	tst	r1, #L_PTE_PRESENT | L_PTE_YOUNG	@ Present and Young?
-	movne	r2, #0
-
-#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH
-	eor	r3, r2, #0x0a			@ C & small page?
-	tst	r3, #0x0b
-	biceq	r2, r2, #4
-#endif
-	str	r2, [r0]			@ hardware version
+	armv3_set_pte_ext
 	mov	r0, r0
 #ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
 	mcr	p15, 0, r0, c7, c10, 1		@ clean D entry
diff --git a/arch/arm/mm/proc-arm940.S b/arch/arm/mm/proc-arm940.S
index 551244d..f595117 100644
--- a/arch/arm/mm/proc-arm940.S
+++ b/arch/arm/mm/proc-arm940.S
@@ -11,7 +11,7 @@
 #include <linux/linkage.h>
 #include <linux/init.h>
 #include <asm/assembler.h>
-#include <asm/elf.h>
+#include <asm/hwcap.h>
 #include <asm/pgtable-hwdef.h>
 #include <asm/pgtable.h>
 #include <asm/ptrace.h>
diff --git a/arch/arm/mm/proc-arm946.S b/arch/arm/mm/proc-arm946.S
index 6168c61..e03f6ff 100644
--- a/arch/arm/mm/proc-arm946.S
+++ b/arch/arm/mm/proc-arm946.S
@@ -13,7 +13,7 @@
 #include <linux/linkage.h>
 #include <linux/init.h>
 #include <asm/assembler.h>
-#include <asm/elf.h>
+#include <asm/hwcap.h>
 #include <asm/pgtable-hwdef.h>
 #include <asm/pgtable.h>
 #include <asm/ptrace.h>
diff --git a/arch/arm/mm/proc-arm9tdmi.S b/arch/arm/mm/proc-arm9tdmi.S
index c85c1f5..be6c11d 100644
--- a/arch/arm/mm/proc-arm9tdmi.S
+++ b/arch/arm/mm/proc-arm9tdmi.S
@@ -12,7 +12,7 @@
 #include <linux/init.h>
 #include <asm/assembler.h>
 #include <asm/asm-offsets.h>
-#include <asm/elf.h>
+#include <asm/hwcap.h>
 #include <asm/pgtable-hwdef.h>
 #include <asm/pgtable.h>
 #include <asm/ptrace.h>
diff --git a/arch/arm/mm/proc-feroceon.S b/arch/arm/mm/proc-feroceon.S
index f2e5884..0fe1f8f 100644
--- a/arch/arm/mm/proc-feroceon.S
+++ b/arch/arm/mm/proc-feroceon.S
@@ -22,7 +22,7 @@
 #include <linux/linkage.h>
 #include <linux/init.h>
 #include <asm/assembler.h>
-#include <asm/elf.h>
+#include <asm/hwcap.h>
 #include <asm/pgtable-hwdef.h>
 #include <asm/pgtable.h>
 #include <asm/page.h>
@@ -80,7 +80,8 @@
 	msr	cpsr_c, ip
 	bl	feroceon_flush_kern_cache_all
 
-#if defined(CONFIG_CACHE_FEROCEON_L2) && !defined(CONFIG_L2_CACHE_WRITETHROUGH)
+#if defined(CONFIG_CACHE_FEROCEON_L2) && \
+	!defined(CONFIG_CACHE_FEROCEON_L2_WRITETHROUGH)
 	mov	r0, #0
 	mcr	p15, 1, r0, c15, c9, 0		@ clean L2
 	mcr	p15, 0, r0, c7, c10, 4		@ drain WB
@@ -389,7 +390,8 @@
 
 	.align	5
 ENTRY(cpu_feroceon_dcache_clean_area)
-#if defined(CONFIG_CACHE_FEROCEON_L2) && !defined(CONFIG_L2_CACHE_WRITETHROUGH)
+#if defined(CONFIG_CACHE_FEROCEON_L2) && \
+	!defined(CONFIG_CACHE_FEROCEON_L2_WRITETHROUGH)
 	mov	r2, r0
 	mov	r3, r1
 #endif
@@ -397,7 +399,8 @@
 	add	r0, r0, #CACHE_DLINESIZE
 	subs	r1, r1, #CACHE_DLINESIZE
 	bhi	1b
-#if defined(CONFIG_CACHE_FEROCEON_L2) && !defined(CONFIG_L2_CACHE_WRITETHROUGH)
+#if defined(CONFIG_CACHE_FEROCEON_L2) && \
+	!defined(CONFIG_CACHE_FEROCEON_L2_WRITETHROUGH)
 1:	mcr	p15, 1, r2, c15, c9, 1		@ clean L2 entry
 	add	r2, r2, #CACHE_DLINESIZE
 	subs	r3, r3, #CACHE_DLINESIZE
@@ -446,27 +449,11 @@
 	.align	5
 ENTRY(cpu_feroceon_set_pte_ext)
 #ifdef CONFIG_MMU
-	str	r1, [r0], #-2048		@ linux version
-
-	eor	r1, r1, #L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_WRITE | L_PTE_DIRTY
-
-	bic	r2, r1, #PTE_SMALL_AP_MASK
-	bic	r2, r2, #PTE_TYPE_MASK
-	orr	r2, r2, #PTE_TYPE_SMALL
-
-	tst	r1, #L_PTE_USER			@ User?
-	orrne	r2, r2, #PTE_SMALL_AP_URO_SRW
-
-	tst	r1, #L_PTE_WRITE | L_PTE_DIRTY	@ Write and Dirty?
-	orreq	r2, r2, #PTE_SMALL_AP_UNO_SRW
-
-	tst	r1, #L_PTE_PRESENT | L_PTE_YOUNG	@ Present and Young?
-	movne	r2, #0
-
-	str	r2, [r0]			@ hardware version
+	armv3_set_pte_ext wc_disable=0
 	mov	r0, r0
 	mcr	p15, 0, r0, c7, c10, 1		@ clean D entry
-#if defined(CONFIG_CACHE_FEROCEON_L2) && !defined(CONFIG_L2_CACHE_WRITETHROUGH)
+#if defined(CONFIG_CACHE_FEROCEON_L2) && \
+	!defined(CONFIG_CACHE_FEROCEON_L2_WRITETHROUGH)
 	mcr	p15, 1, r0, c15, c9, 1		@ clean L2 entry
 #endif
 	mcr	p15, 0, r0, c7, c10, 4		@ drain WB
diff --git a/arch/arm/mm/proc-macros.S b/arch/arm/mm/proc-macros.S
index b131500..54b1f72 100644
--- a/arch/arm/mm/proc-macros.S
+++ b/arch/arm/mm/proc-macros.S
@@ -71,3 +71,173 @@
 	mov	\reg, #16			@ size offset
 	mov	\reg, \reg, lsl \tmp		@ actual cache line size
 	.endm
+
+
+/*
+ * Sanity check the PTE configuration for the code below - which makes
+ * certain assumptions about how these bits are layed out.
+ */
+#if L_PTE_SHARED != PTE_EXT_SHARED
+#error PTE shared bit mismatch
+#endif
+#if L_PTE_BUFFERABLE != PTE_BUFFERABLE
+#error PTE bufferable bit mismatch
+#endif
+#if L_PTE_CACHEABLE != PTE_CACHEABLE
+#error PTE cacheable bit mismatch
+#endif
+#if (L_PTE_EXEC+L_PTE_USER+L_PTE_WRITE+L_PTE_DIRTY+L_PTE_YOUNG+\
+     L_PTE_FILE+L_PTE_PRESENT) > L_PTE_SHARED
+#error Invalid Linux PTE bit settings
+#endif
+
+/*
+ * The ARMv6 and ARMv7 set_pte_ext translation function.
+ *
+ * Permission translation:
+ *  YUWD  APX AP1 AP0	SVC	User
+ *  0xxx   0   0   0	no acc	no acc
+ *  100x   1   0   1	r/o	no acc
+ *  10x0   1   0   1	r/o	no acc
+ *  1011   0   0   1	r/w	no acc
+ *  110x   0   1   0	r/w	r/o
+ *  11x0   0   1   0	r/w	r/o
+ *  1111   0   1   1	r/w	r/w
+ */
+	.macro	armv6_mt_table pfx
+\pfx\()_mt_table:
+	.long	0x00						@ L_PTE_MT_UNCACHED
+	.long	PTE_EXT_TEX(1)					@ L_PTE_MT_BUFFERABLE
+	.long	PTE_CACHEABLE					@ L_PTE_MT_WRITETHROUGH
+	.long	PTE_CACHEABLE | PTE_BUFFERABLE			@ L_PTE_MT_WRITEBACK
+	.long	PTE_BUFFERABLE					@ L_PTE_MT_DEV_SHARED
+	.long	0x00						@ unused
+	.long	0x00						@ L_PTE_MT_MINICACHE (not present)
+	.long	PTE_EXT_TEX(1) | PTE_CACHEABLE | PTE_BUFFERABLE	@ L_PTE_MT_WRITEALLOC
+	.long	0x00						@ unused
+	.long	PTE_EXT_TEX(1)					@ L_PTE_MT_DEV_WC
+	.long	0x00						@ unused
+	.long	PTE_CACHEABLE | PTE_BUFFERABLE			@ L_PTE_MT_DEV_CACHED
+	.long	PTE_EXT_TEX(2)					@ L_PTE_MT_DEV_NONSHARED
+	.long	0x00						@ unused
+	.long	0x00						@ unused
+	.long	0x00						@ unused
+	.endm
+
+	.macro	armv6_set_pte_ext pfx
+	str	r1, [r0], #-2048		@ linux version
+
+	bic	r3, r1, #0x000003fc
+	bic	r3, r3, #PTE_TYPE_MASK
+	orr	r3, r3, r2
+	orr	r3, r3, #PTE_EXT_AP0 | 2
+
+	adr	ip, \pfx\()_mt_table
+	and	r2, r1, #L_PTE_MT_MASK
+	ldr	r2, [ip, r2]
+
+	tst	r1, #L_PTE_WRITE
+	tstne	r1, #L_PTE_DIRTY
+	orreq	r3, r3, #PTE_EXT_APX
+
+	tst	r1, #L_PTE_USER
+	orrne	r3, r3, #PTE_EXT_AP1
+	tstne	r3, #PTE_EXT_APX
+	bicne	r3, r3, #PTE_EXT_APX | PTE_EXT_AP0
+
+	tst	r1, #L_PTE_EXEC
+	orreq	r3, r3, #PTE_EXT_XN
+
+	orr	r3, r3, r2
+
+	tst	r1, #L_PTE_YOUNG
+	tstne	r1, #L_PTE_PRESENT
+	moveq	r3, #0
+
+	str	r3, [r0]
+	mcr	p15, 0, r0, c7, c10, 1		@ flush_pte
+	.endm
+
+
+/*
+ * The ARMv3, ARMv4 and ARMv5 set_pte_ext translation function,
+ * covering most CPUs except Xscale and Xscale 3.
+ *
+ * Permission translation:
+ *  YUWD   AP	SVC	User
+ *  0xxx  0x00	no acc	no acc
+ *  100x  0x00	r/o	no acc
+ *  10x0  0x00	r/o	no acc
+ *  1011  0x55	r/w	no acc
+ *  110x  0xaa	r/w	r/o
+ *  11x0  0xaa	r/w	r/o
+ *  1111  0xff	r/w	r/w
+ */
+	.macro	armv3_set_pte_ext wc_disable=1
+	str	r1, [r0], #-2048		@ linux version
+
+	eor	r3, r1, #L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_WRITE | L_PTE_DIRTY
+
+	bic	r2, r1, #PTE_SMALL_AP_MASK	@ keep C, B bits
+	bic	r2, r2, #PTE_TYPE_MASK
+	orr	r2, r2, #PTE_TYPE_SMALL
+
+	tst	r3, #L_PTE_USER			@ user?
+	orrne	r2, r2, #PTE_SMALL_AP_URO_SRW
+
+	tst	r3, #L_PTE_WRITE | L_PTE_DIRTY	@ write and dirty?
+	orreq	r2, r2, #PTE_SMALL_AP_UNO_SRW
+
+	tst	r3, #L_PTE_PRESENT | L_PTE_YOUNG	@ present and young?
+	movne	r2, #0
+
+	.if	\wc_disable
+#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH
+	tst	r2, #PTE_CACHEABLE
+	bicne	r2, r2, #PTE_BUFFERABLE
+#endif
+	.endif
+	str	r2, [r0]			@ hardware version
+	.endm
+
+
+/*
+ * Xscale set_pte_ext translation, split into two halves to cope
+ * with work-arounds.  r3 must be preserved by code between these
+ * two macros.
+ *
+ * Permission translation:
+ *  YUWD  AP	SVC	User
+ *  0xxx  00	no acc	no acc
+ *  100x  00	r/o	no acc
+ *  10x0  00	r/o	no acc
+ *  1011  01	r/w	no acc
+ *  110x  10	r/w	r/o
+ *  11x0  10	r/w	r/o
+ *  1111  11	r/w	r/w
+ */
+	.macro	xscale_set_pte_ext_prologue
+	str	r1, [r0], #-2048		@ linux version
+
+	eor	r3, r1, #L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_WRITE | L_PTE_DIRTY
+
+	bic	r2, r1, #PTE_SMALL_AP_MASK	@ keep C, B bits
+	orr	r2, r2, #PTE_TYPE_EXT		@ extended page
+
+	tst	r3, #L_PTE_USER			@ user?
+	orrne	r2, r2, #PTE_EXT_AP_URO_SRW	@ yes -> user r/o, system r/w
+
+	tst	r3, #L_PTE_WRITE | L_PTE_DIRTY	@ write and dirty?
+	orreq	r2, r2, #PTE_EXT_AP_UNO_SRW	@ yes -> user n/a, system r/w
+						@ combined with user -> user r/w
+	.endm
+
+	.macro	xscale_set_pte_ext_epilogue
+	tst	r3, #L_PTE_PRESENT | L_PTE_YOUNG	@ present and young?
+	movne	r2, #0				@ no -> fault
+
+	str	r2, [r0]			@ hardware version
+	mov	ip, #0
+	mcr	p15, 0, r0, c7, c10, 1		@ clean L1 D line
+	mcr	p15, 0, ip, c7, c10, 4		@ data write barrier
+	.endm
diff --git a/arch/arm/mm/proc-sa110.S b/arch/arm/mm/proc-sa110.S
index bbe1057..90a7e52 100644
--- a/arch/arm/mm/proc-sa110.S
+++ b/arch/arm/mm/proc-sa110.S
@@ -17,7 +17,7 @@
 #include <linux/init.h>
 #include <asm/assembler.h>
 #include <asm/asm-offsets.h>
-#include <asm/elf.h>
+#include <asm/hwcap.h>
 #include <mach/hardware.h>
 #include <asm/pgtable-hwdef.h>
 #include <asm/pgtable.h>
@@ -153,24 +153,7 @@
 	.align	5
 ENTRY(cpu_sa110_set_pte_ext)
 #ifdef CONFIG_MMU
-	str	r1, [r0], #-2048		@ linux version
-
-	eor	r1, r1, #L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_WRITE | L_PTE_DIRTY
-
-	bic	r2, r1, #PTE_SMALL_AP_MASK
-	bic	r2, r2, #PTE_TYPE_MASK
-	orr	r2, r2, #PTE_TYPE_SMALL
-
-	tst	r1, #L_PTE_USER			@ User?
-	orrne	r2, r2, #PTE_SMALL_AP_URO_SRW
-
-	tst	r1, #L_PTE_WRITE | L_PTE_DIRTY	@ Write and Dirty?
-	orreq	r2, r2, #PTE_SMALL_AP_UNO_SRW
-
-	tst	r1, #L_PTE_PRESENT | L_PTE_YOUNG	@ Present and Young?
-	movne	r2, #0
-
-	str	r2, [r0]			@ hardware version
+	armv3_set_pte_ext wc_disable=0
 	mov	r0, r0
 	mcr	p15, 0, r0, c7, c10, 1		@ clean D entry
 	mcr	p15, 0, r0, c7, c10, 4		@ drain WB
diff --git a/arch/arm/mm/proc-sa1100.S b/arch/arm/mm/proc-sa1100.S
index 871ba01..451e2d9 100644
--- a/arch/arm/mm/proc-sa1100.S
+++ b/arch/arm/mm/proc-sa1100.S
@@ -22,7 +22,7 @@
 #include <linux/init.h>
 #include <asm/assembler.h>
 #include <asm/asm-offsets.h>
-#include <asm/elf.h>
+#include <asm/hwcap.h>
 #include <mach/hardware.h>
 #include <asm/pgtable-hwdef.h>
 #include <asm/pgtable.h>
@@ -166,24 +166,7 @@
 	.align	5
 ENTRY(cpu_sa1100_set_pte_ext)
 #ifdef CONFIG_MMU
-	str	r1, [r0], #-2048		@ linux version
-
-	eor	r1, r1, #L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_WRITE | L_PTE_DIRTY
-
-	bic	r2, r1, #PTE_SMALL_AP_MASK
-	bic	r2, r2, #PTE_TYPE_MASK
-	orr	r2, r2, #PTE_TYPE_SMALL
-
-	tst	r1, #L_PTE_USER			@ User?
-	orrne	r2, r2, #PTE_SMALL_AP_URO_SRW
-
-	tst	r1, #L_PTE_WRITE | L_PTE_DIRTY	@ Write and Dirty?
-	orreq	r2, r2, #PTE_SMALL_AP_UNO_SRW
-
-	tst	r1, #L_PTE_PRESENT | L_PTE_YOUNG	@ Present and Young?
-	movne	r2, #0
-
-	str	r2, [r0]			@ hardware version
+	armv3_set_pte_ext wc_disable=0
 	mov	r0, r0
 	mcr	p15, 0, r0, c7, c10, 1		@ clean D entry
 	mcr	p15, 0, r0, c7, c10, 4		@ drain WB
diff --git a/arch/arm/mm/proc-v6.S b/arch/arm/mm/proc-v6.S
index 5702ec5..294943b 100644
--- a/arch/arm/mm/proc-v6.S
+++ b/arch/arm/mm/proc-v6.S
@@ -13,7 +13,7 @@
 #include <linux/linkage.h>
 #include <asm/assembler.h>
 #include <asm/asm-offsets.h>
-#include <asm/elf.h>
+#include <asm/hwcap.h>
 #include <asm/pgtable-hwdef.h>
 #include <asm/pgtable.h>
 
@@ -114,46 +114,12 @@
  *		  (hardware version is stored at -1024 bytes)
  *	- pte   - PTE value to store
  *	- ext	- value for extended PTE bits
- *
- *	Permissions:
- *	  YUWD  APX AP1 AP0	SVC	User
- *	  0xxx   0   0   0	no acc	no acc
- *	  100x   1   0   1	r/o	no acc
- *	  10x0   1   0   1	r/o	no acc
- *	  1011   0   0   1	r/w	no acc
- *	  110x   0   1   0	r/w	r/o
- *	  11x0   0   1   0	r/w	r/o
- *	  1111   0   1   1	r/w	r/w
  */
+	armv6_mt_table cpu_v6
+
 ENTRY(cpu_v6_set_pte_ext)
 #ifdef CONFIG_MMU
-	str	r1, [r0], #-2048		@ linux version
-
-	bic	r3, r1, #0x000003f0
-	bic	r3, r3, #0x00000003
-	orr	r3, r3, r2
-	orr	r3, r3, #PTE_EXT_AP0 | 2
-
-	tst	r1, #L_PTE_WRITE
-	tstne	r1, #L_PTE_DIRTY
-	orreq	r3, r3, #PTE_EXT_APX
-
-	tst	r1, #L_PTE_USER
-	orrne	r3, r3, #PTE_EXT_AP1
-	tstne	r3, #PTE_EXT_APX
-	bicne	r3, r3, #PTE_EXT_APX | PTE_EXT_AP0
-
-	tst	r1, #L_PTE_YOUNG
-	biceq	r3, r3, #PTE_EXT_APX | PTE_EXT_AP_MASK
-
-	tst	r1, #L_PTE_EXEC
-	orreq	r3, r3, #PTE_EXT_XN
-
-	tst	r1, #L_PTE_PRESENT
-	moveq	r3, #0
-
-	str	r3, [r0]
-	mcr	p15, 0, r0, c7, c10, 1 @ flush_pte
+	armv6_set_pte_ext cpu_v6
 #endif
 	mov	pc, lr
 
diff --git a/arch/arm/mm/proc-v7.S b/arch/arm/mm/proc-v7.S
index b49f9a4..34e4240 100644
--- a/arch/arm/mm/proc-v7.S
+++ b/arch/arm/mm/proc-v7.S
@@ -12,7 +12,7 @@
 #include <linux/linkage.h>
 #include <asm/assembler.h>
 #include <asm/asm-offsets.h>
-#include <asm/elf.h>
+#include <asm/hwcap.h>
 #include <asm/pgtable-hwdef.h>
 #include <asm/pgtable.h>
 
@@ -25,9 +25,11 @@
 
 ENTRY(cpu_v7_proc_init)
 	mov	pc, lr
+ENDPROC(cpu_v7_proc_init)
 
 ENTRY(cpu_v7_proc_fin)
 	mov	pc, lr
+ENDPROC(cpu_v7_proc_fin)
 
 /*
  *	cpu_v7_reset(loc)
@@ -43,6 +45,7 @@
 	.align	5
 ENTRY(cpu_v7_reset)
 	mov	pc, r0
+ENDPROC(cpu_v7_reset)
 
 /*
  *	cpu_v7_do_idle()
@@ -52,8 +55,9 @@
  *	IRQs are already disabled.
  */
 ENTRY(cpu_v7_do_idle)
-	.long	0xe320f003			@ ARM V7 WFI instruction
+	wfi
 	mov	pc, lr
+ENDPROC(cpu_v7_do_idle)
 
 ENTRY(cpu_v7_dcache_clean_area)
 #ifndef TLB_CAN_READ_FROM_L1_CACHE
@@ -65,6 +69,7 @@
 	dsb
 #endif
 	mov	pc, lr
+ENDPROC(cpu_v7_dcache_clean_area)
 
 /*
  *	cpu_v7_switch_mm(pgd_phys, tsk)
@@ -89,6 +94,7 @@
 	isb
 #endif
 	mov	pc, lr
+ENDPROC(cpu_v7_switch_mm)
 
 /*
  *	cpu_v7_set_pte_ext(ptep, pte)
@@ -99,26 +105,19 @@
  *		  (hardware version is stored at -1024 bytes)
  *	- pte   - PTE value to store
  *	- ext	- value for extended PTE bits
- *
- *	Permissions:
- *	  YUWD  APX AP1 AP0	SVC	User
- *	  0xxx   0   0   0	no acc	no acc
- *	  100x   1   0   1	r/o	no acc
- *	  10x0   1   0   1	r/o	no acc
- *	  1011   0   0   1	r/w	no acc
- *	  110x   0   1   0	r/w	r/o
- *	  11x0   0   1   0	r/w	r/o
- *	  1111   0   1   1	r/w	r/w
  */
 ENTRY(cpu_v7_set_pte_ext)
 #ifdef CONFIG_MMU
 	str	r1, [r0], #-2048		@ linux version
 
 	bic	r3, r1, #0x000003f0
-	bic	r3, r3, #0x00000003
+	bic	r3, r3, #PTE_TYPE_MASK
 	orr	r3, r3, r2
 	orr	r3, r3, #PTE_EXT_AP0 | 2
 
+	tst	r2, #1 << 4
+	orrne	r3, r3, #PTE_EXT_TEX(1)
+
 	tst	r1, #L_PTE_WRITE
 	tstne	r1, #L_PTE_DIRTY
 	orreq	r3, r3, #PTE_EXT_APX
@@ -128,19 +127,18 @@
 	tstne	r3, #PTE_EXT_APX
 	bicne	r3, r3, #PTE_EXT_APX | PTE_EXT_AP0
 
-	tst	r1, #L_PTE_YOUNG
-	biceq	r3, r3, #PTE_EXT_APX | PTE_EXT_AP_MASK
-
 	tst	r1, #L_PTE_EXEC
 	orreq	r3, r3, #PTE_EXT_XN
 
-	tst	r1, #L_PTE_PRESENT
+	tst	r1, #L_PTE_YOUNG
+	tstne	r1, #L_PTE_PRESENT
 	moveq	r3, #0
 
 	str	r3, [r0]
 	mcr	p15, 0, r0, c7, c10, 1		@ flush_pte
 #endif
 	mov	pc, lr
+ENDPROC(cpu_v7_set_pte_ext)
 
 cpu_v7_name:
 	.ascii	"ARMv7 Processor"
@@ -182,12 +180,17 @@
 	mov	r10, #0x1f			@ domains 0, 1 = manager
 	mcr	p15, 0, r10, c3, c0, 0		@ load domain access register
 #endif
+	ldr	r5, =0x40e040e0
+	ldr	r6, =0xff0aa1a8
+	mcr	p15, 0, r5, c10, c2, 0		@ write PRRR
+	mcr	p15, 0, r6, c10, c2, 1		@ write NMRR
 	adr	r5, v7_crval
 	ldmia	r5, {r5, r6}
    	mrc	p15, 0, r0, c1, c0, 0		@ read control register
 	bic	r0, r0, r5			@ clear bits them
 	orr	r0, r0, r6			@ set them
 	mov	pc, lr				@ return to head.S:__ret
+ENDPROC(__v7_setup)
 
 	/*
 	 *         V X F   I D LR
@@ -197,7 +200,7 @@
 	 */
 	.type	v7_crval, #object
 v7_crval:
-	crval	clear=0x0120c302, mmuset=0x00c0387d, ucset=0x00c0187c
+	crval	clear=0x0120c302, mmuset=0x10c0387d, ucset=0x00c0187c
 
 __v7_setup_stack:
 	.space	4 * 11				@ 11 registers
diff --git a/arch/arm/mm/proc-xsc3.S b/arch/arm/mm/proc-xsc3.S
index 7bd9e71..04dc8b6 100644
--- a/arch/arm/mm/proc-xsc3.S
+++ b/arch/arm/mm/proc-xsc3.S
@@ -27,7 +27,7 @@
 #include <linux/linkage.h>
 #include <linux/init.h>
 #include <asm/assembler.h>
-#include <asm/elf.h>
+#include <asm/hwcap.h>
 #include <mach/hardware.h>
 #include <asm/pgtable.h>
 #include <asm/pgtable-hwdef.h>
@@ -345,38 +345,38 @@
  * cpu_xsc3_set_pte_ext(ptep, pte, ext)
  *
  * Set a PTE and flush it out
- *
  */
+cpu_xsc3_mt_table:
+	.long	0x00						@ L_PTE_MT_UNCACHED
+	.long	PTE_EXT_TEX(1)					@ L_PTE_MT_BUFFERABLE
+	.long	PTE_CACHEABLE					@ L_PTE_MT_WRITETHROUGH
+	.long	PTE_CACHEABLE | PTE_BUFFERABLE			@ L_PTE_MT_WRITEBACK
+	.long	PTE_EXT_TEX(1) | PTE_BUFFERABLE			@ L_PTE_MT_DEV_SHARED
+	.long	0x00						@ unused
+	.long	0x00						@ L_PTE_MT_MINICACHE (not present)
+	.long	PTE_EXT_TEX(5) | PTE_CACHEABLE | PTE_BUFFERABLE	@ L_PTE_MT_WRITEALLOC (not present?)
+	.long	0x00						@ unused
+	.long	PTE_EXT_TEX(1)					@ L_PTE_MT_DEV_WC
+	.long	0x00						@ unused
+	.long	PTE_CACHEABLE | PTE_BUFFERABLE			@ L_PTE_MT_DEV_CACHED
+	.long	PTE_EXT_TEX(2)					@ L_PTE_MT_DEV_NONSHARED
+	.long	0x00						@ unused
+	.long	0x00						@ unused
+	.long	0x00						@ unused
+
 	.align	5
 ENTRY(cpu_xsc3_set_pte_ext)
-	str	r1, [r0], #-2048		@ linux version
+	xscale_set_pte_ext_prologue
 
-	bic	r2, r1, #0xff0			@ keep C, B bits
-	orr	r2, r2, #PTE_TYPE_EXT		@ extended page
 	tst	r1, #L_PTE_SHARED		@ shared?
-	orrne	r2, r2, #0x200
+	and	r1, r1, #L_PTE_MT_MASK
+	adr	ip, cpu_xsc3_mt_table
+	ldr	ip, [ip, r1]
+	orrne	r2, r2, #PTE_EXT_COHERENT	@ interlock: mask in coherent bit
+	bic	r2, r2, #0x0c			@ clear old C,B bits
+	orr	r2, r2, ip
 
-	eor	r3, r1, #L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_WRITE | L_PTE_DIRTY
-
-	tst	r3, #L_PTE_USER			@ user?
-	orrne	r2, r2, #PTE_EXT_AP_URO_SRW	@ yes -> user r/o, system r/w
-
-	tst	r3, #L_PTE_WRITE | L_PTE_DIRTY	@ write and dirty?
-	orreq	r2, r2, #PTE_EXT_AP_UNO_SRW	@ yes -> user n/a, system r/w
-						@ combined with user -> user r/w
-
-	@ If it's cacheable, it needs to be in L2 also.
-	eor	ip, r1, #L_PTE_CACHEABLE
-	tst	ip, #L_PTE_CACHEABLE
-	orreq	r2, r2, #PTE_EXT_TEX(0x5)
-
-	tst	r3, #L_PTE_PRESENT | L_PTE_YOUNG	@ present and young?
-	movne	r2, #0				@ no -> fault
-
-	str	r2, [r0]			@ hardware version
-	mov	ip, #0
-	mcr	p15, 0, r0, c7, c10, 1		@ clean L1 D line
-	mcr	p15, 0, ip, c7, c10, 4		@ data write barrier
+	xscale_set_pte_ext_epilogue
 	mov	pc, lr
 
 	.ltorg
diff --git a/arch/arm/mm/proc-xscale.S b/arch/arm/mm/proc-xscale.S
index 2dd8527..0cce37b 100644
--- a/arch/arm/mm/proc-xscale.S
+++ b/arch/arm/mm/proc-xscale.S
@@ -23,7 +23,7 @@
 #include <linux/linkage.h>
 #include <linux/init.h>
 #include <asm/assembler.h>
-#include <asm/elf.h>
+#include <asm/hwcap.h>
 #include <asm/pgtable.h>
 #include <asm/pgtable-hwdef.h>
 #include <asm/page.h>
@@ -406,8 +406,6 @@
 
 /* =============================== PageTable ============================== */
 
-#define PTE_CACHE_WRITE_ALLOCATE 0
-
 /*
  * cpu_xscale_switch_mm(pgd)
  *
@@ -431,56 +429,42 @@
  *
  * Errata 40: must set memory to write-through for user read-only pages.
  */
+cpu_xscale_mt_table:
+	.long	0x00						@ L_PTE_MT_UNCACHED
+	.long	PTE_BUFFERABLE					@ L_PTE_MT_BUFFERABLE
+	.long	PTE_CACHEABLE					@ L_PTE_MT_WRITETHROUGH
+	.long	PTE_CACHEABLE | PTE_BUFFERABLE			@ L_PTE_MT_WRITEBACK
+	.long	PTE_EXT_TEX(1) | PTE_BUFFERABLE			@ L_PTE_MT_DEV_SHARED
+	.long	0x00						@ unused
+	.long	PTE_EXT_TEX(1) | PTE_CACHEABLE			@ L_PTE_MT_MINICACHE
+	.long	PTE_EXT_TEX(1) | PTE_CACHEABLE | PTE_BUFFERABLE	@ L_PTE_MT_WRITEALLOC
+	.long	0x00						@ unused
+	.long	PTE_BUFFERABLE					@ L_PTE_MT_DEV_WC
+	.long	0x00						@ unused
+	.long	PTE_CACHEABLE | PTE_BUFFERABLE			@ L_PTE_MT_DEV_CACHED
+	.long	0x00						@ L_PTE_MT_DEV_NONSHARED
+	.long	0x00						@ unused
+	.long	0x00						@ unused
+	.long	0x00						@ unused
+
 	.align	5
 ENTRY(cpu_xscale_set_pte_ext)
-	str	r1, [r0], #-2048		@ linux version
-
-	bic	r2, r1, #0xff0
-	orr	r2, r2, #PTE_TYPE_EXT		@ extended page
-
-	eor	r3, r1, #L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_WRITE | L_PTE_DIRTY
-
-	tst	r3, #L_PTE_USER			@ User?
-	orrne	r2, r2, #PTE_EXT_AP_URO_SRW	@ yes -> user r/o, system r/w
-
-	tst	r3, #L_PTE_WRITE | L_PTE_DIRTY	@ Write and Dirty?
-	orreq	r2, r2, #PTE_EXT_AP_UNO_SRW	@ yes -> user n/a, system r/w
-						@ combined with user -> user r/w
+	xscale_set_pte_ext_prologue
 
 	@
-	@ Handle the X bit.  We want to set this bit for the minicache
-	@ (U = E = B = W = 0, C = 1) or when write allocate is enabled,
-	@ and we have a writeable, cacheable region.  If we ignore the
-	@ U and E bits, we can allow user space to use the minicache as
-	@ well.
+	@ Erratum 40: must set memory to write-through for user read-only pages
 	@
-	@  X = (C & ~W & ~B) | (C & W & B & write_allocate)
-	@
-	eor	ip, r1, #L_PTE_CACHEABLE
-	tst	ip, #L_PTE_CACHEABLE | L_PTE_WRITE | L_PTE_BUFFERABLE
-#if PTE_CACHE_WRITE_ALLOCATE
-	eorne	ip, r1, #L_PTE_CACHEABLE | L_PTE_WRITE | L_PTE_BUFFERABLE
-	tstne	ip, #L_PTE_CACHEABLE | L_PTE_WRITE | L_PTE_BUFFERABLE
-#endif
-	orreq	r2, r2, #PTE_EXT_TEX(1)
+	and	ip, r1, #(L_PTE_MT_MASK | L_PTE_USER | L_PTE_WRITE) & ~(4 << 2)
+	teq	ip, #L_PTE_MT_WRITEBACK | L_PTE_USER
 
-	@
-	@ Erratum 40: The B bit must be cleared for a user read-only
-	@ cacheable page.
-	@
-	@  B = B & ~(U & C & ~W)
-	@
-	and	ip, r1, #L_PTE_USER | L_PTE_WRITE | L_PTE_CACHEABLE
-	teq	ip, #L_PTE_USER | L_PTE_CACHEABLE
-	biceq	r2, r2, #PTE_BUFFERABLE
+	moveq	r1, #L_PTE_MT_WRITETHROUGH
+	and	r1, r1, #L_PTE_MT_MASK
+	adr	ip, cpu_xscale_mt_table
+	ldr	ip, [ip, r1]
+	bic	r2, r2, #0x0c
+	orr	r2, r2, ip
 
-	tst	r3, #L_PTE_PRESENT | L_PTE_YOUNG	@ Present and Young?
-	movne	r2, #0				@ no -> fault
-
-	str	r2, [r0]			@ hardware version
-	mov	ip, #0
-	mcr	p15, 0, r0, c7, c10, 1		@ Clean D cache line
-	mcr	p15, 0, ip, c7, c10, 4		@ Drain Write (& Fill) Buffer
+	xscale_set_pte_ext_epilogue
 	mov	pc, lr
 
 
diff --git a/arch/arm/mm/tlb-v7.S b/arch/arm/mm/tlb-v7.S
index b56dda8..24ba510 100644
--- a/arch/arm/mm/tlb-v7.S
+++ b/arch/arm/mm/tlb-v7.S
@@ -51,6 +51,7 @@
 	mcr	p15, 0, ip, c7, c5, 6		@ flush BTAC/BTB
 	dsb
 	mov	pc, lr
+ENDPROC(v7wbi_flush_user_tlb_range)
 
 /*
  *	v7wbi_flush_kern_tlb_range(start,end)
@@ -77,6 +78,7 @@
 	dsb
 	isb
 	mov	pc, lr
+ENDPROC(v7wbi_flush_kern_tlb_range)
 
 	.section ".text.init", #alloc, #execinstr
 
diff --git a/arch/arm/nwfpe/fpa11_cpdt.c b/arch/arm/nwfpe/fpa11_cpdt.c
index 79f8e67..d31c49f 100644
--- a/arch/arm/nwfpe/fpa11_cpdt.c
+++ b/arch/arm/nwfpe/fpa11_cpdt.c
@@ -26,7 +26,7 @@
 #include "fpmodule.h"
 #include "fpmodule.inl"
 
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
 
 static inline void loadSingle(const unsigned int Fn, const unsigned int __user *pMem)
 {
diff --git a/arch/arm/oprofile/Makefile b/arch/arm/oprofile/Makefile
index e61d0cc..88e31f5 100644
--- a/arch/arm/oprofile/Makefile
+++ b/arch/arm/oprofile/Makefile
@@ -11,3 +11,4 @@
 oprofile-$(CONFIG_OPROFILE_ARM11_CORE)	+= op_model_arm11_core.o
 oprofile-$(CONFIG_OPROFILE_ARMV6)	+= op_model_v6.o
 oprofile-$(CONFIG_OPROFILE_MPCORE)	+= op_model_mpcore.o
+oprofile-$(CONFIG_OPROFILE_ARMV7)	+= op_model_v7.o
diff --git a/arch/arm/oprofile/backtrace.c b/arch/arm/oprofile/backtrace.c
index f5ebf30..cefc21c 100644
--- a/arch/arm/oprofile/backtrace.c
+++ b/arch/arm/oprofile/backtrace.c
@@ -16,8 +16,8 @@
 #include <linux/oprofile.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
+#include <linux/uaccess.h>
 #include <asm/ptrace.h>
-#include <asm/uaccess.h>
 
 #include "../kernel/stacktrace.h"
 
diff --git a/arch/arm/oprofile/common.c b/arch/arm/oprofile/common.c
index 0a5cf3a..3fcd752 100644
--- a/arch/arm/oprofile/common.c
+++ b/arch/arm/oprofile/common.c
@@ -145,6 +145,10 @@
 	spec = &op_mpcore_spec;
 #endif
 
+#ifdef CONFIG_OPROFILE_ARMV7
+	spec = &op_armv7_spec;
+#endif
+
 	if (spec) {
 		ret = spec->init();
 		if (ret < 0)
diff --git a/arch/arm/oprofile/op_arm_model.h b/arch/arm/oprofile/op_arm_model.h
index 4899c62..8c4e4f6 100644
--- a/arch/arm/oprofile/op_arm_model.h
+++ b/arch/arm/oprofile/op_arm_model.h
@@ -26,6 +26,7 @@
 
 extern struct op_arm_model_spec op_armv6_spec;
 extern struct op_arm_model_spec op_mpcore_spec;
+extern struct op_arm_model_spec op_armv7_spec;
 
 extern void arm_backtrace(struct pt_regs * const regs, unsigned int depth);
 
diff --git a/arch/arm/oprofile/op_model_mpcore.c b/arch/arm/oprofile/op_model_mpcore.c
index 92db6e0..4de366e 100644
--- a/arch/arm/oprofile/op_model_mpcore.c
+++ b/arch/arm/oprofile/op_model_mpcore.c
@@ -36,8 +36,8 @@
 #include <linux/oprofile.h>
 #include <linux/interrupt.h>
 #include <linux/smp.h>
+#include <linux/io.h>
 
-#include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/mach/irq.h>
 #include <mach/hardware.h>
diff --git a/arch/arm/oprofile/op_model_v7.c b/arch/arm/oprofile/op_model_v7.c
new file mode 100644
index 0000000..f20295f
--- /dev/null
+++ b/arch/arm/oprofile/op_model_v7.c
@@ -0,0 +1,411 @@
+/**
+ * op_model_v7.c
+ * ARM V7 (Cortex A8) Event Monitor Driver
+ *
+ * Copyright 2008 Jean Pihet <jpihet@mvista.com>
+ * Copyright 2004 ARM SMP Development Team
+ *
+ * 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/types.h>
+#include <linux/errno.h>
+#include <linux/oprofile.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/smp.h>
+
+#include "op_counter.h"
+#include "op_arm_model.h"
+#include "op_model_v7.h"
+
+/* #define DEBUG */
+
+
+/*
+ * ARM V7 PMNC support
+ */
+
+static u32 cnt_en[CNTMAX];
+
+static inline void armv7_pmnc_write(u32 val)
+{
+	val &= PMNC_MASK;
+	asm volatile("mcr p15, 0, %0, c9, c12, 0" : : "r" (val));
+}
+
+static inline u32 armv7_pmnc_read(void)
+{
+	u32 val;
+
+	asm volatile("mrc p15, 0, %0, c9, c12, 0" : "=r" (val));
+	return val;
+}
+
+static inline u32 armv7_pmnc_enable_counter(unsigned int cnt)
+{
+	u32 val;
+
+	if (cnt >= CNTMAX) {
+		printk(KERN_ERR "oprofile: CPU%u enabling wrong PMNC counter"
+			" %d\n", smp_processor_id(), cnt);
+		return -1;
+	}
+
+	if (cnt == CCNT)
+		val = CNTENS_C;
+	else
+		val = (1 << (cnt - CNT0));
+
+	val &= CNTENS_MASK;
+	asm volatile("mcr p15, 0, %0, c9, c12, 1" : : "r" (val));
+
+	return cnt;
+}
+
+static inline u32 armv7_pmnc_disable_counter(unsigned int cnt)
+{
+	u32 val;
+
+	if (cnt >= CNTMAX) {
+		printk(KERN_ERR "oprofile: CPU%u disabling wrong PMNC counter"
+			" %d\n", smp_processor_id(), cnt);
+		return -1;
+	}
+
+	if (cnt == CCNT)
+		val = CNTENC_C;
+	else
+		val = (1 << (cnt - CNT0));
+
+	val &= CNTENC_MASK;
+	asm volatile("mcr p15, 0, %0, c9, c12, 2" : : "r" (val));
+
+	return cnt;
+}
+
+static inline u32 armv7_pmnc_enable_intens(unsigned int cnt)
+{
+	u32 val;
+
+	if (cnt >= CNTMAX) {
+		printk(KERN_ERR "oprofile: CPU%u enabling wrong PMNC counter"
+			" interrupt enable %d\n", smp_processor_id(), cnt);
+		return -1;
+	}
+
+	if (cnt == CCNT)
+		val = INTENS_C;
+	else
+		val = (1 << (cnt - CNT0));
+
+	val &= INTENS_MASK;
+	asm volatile("mcr p15, 0, %0, c9, c14, 1" : : "r" (val));
+
+	return cnt;
+}
+
+static inline u32 armv7_pmnc_getreset_flags(void)
+{
+	u32 val;
+
+	/* Read */
+	asm volatile("mrc p15, 0, %0, c9, c12, 3" : "=r" (val));
+
+	/* Write to clear flags */
+	val &= FLAG_MASK;
+	asm volatile("mcr p15, 0, %0, c9, c12, 3" : : "r" (val));
+
+	return val;
+}
+
+static inline int armv7_pmnc_select_counter(unsigned int cnt)
+{
+	u32 val;
+
+	if ((cnt == CCNT) || (cnt >= CNTMAX)) {
+		printk(KERN_ERR "oprofile: CPU%u selecting wrong PMNC counteri"
+			" %d\n", smp_processor_id(), cnt);
+		return -1;
+	}
+
+	val = (cnt - CNT0) & SELECT_MASK;
+	asm volatile("mcr p15, 0, %0, c9, c12, 5" : : "r" (val));
+
+	return cnt;
+}
+
+static inline void armv7_pmnc_write_evtsel(unsigned int cnt, u32 val)
+{
+	if (armv7_pmnc_select_counter(cnt) == cnt) {
+		val &= EVTSEL_MASK;
+		asm volatile("mcr p15, 0, %0, c9, c13, 1" : : "r" (val));
+	}
+}
+
+static void armv7_pmnc_reset_counter(unsigned int cnt)
+{
+	u32 cpu_cnt = CPU_COUNTER(smp_processor_id(), cnt);
+	u32 val = -(u32)counter_config[cpu_cnt].count;
+
+	switch (cnt) {
+	case CCNT:
+		armv7_pmnc_disable_counter(cnt);
+
+		asm volatile("mcr p15, 0, %0, c9, c13, 0" : : "r" (val));
+
+		if (cnt_en[cnt] != 0)
+		    armv7_pmnc_enable_counter(cnt);
+
+		break;
+
+	case CNT0:
+	case CNT1:
+	case CNT2:
+	case CNT3:
+		armv7_pmnc_disable_counter(cnt);
+
+		if (armv7_pmnc_select_counter(cnt) == cnt)
+		    asm volatile("mcr p15, 0, %0, c9, c13, 2" : : "r" (val));
+
+		if (cnt_en[cnt] != 0)
+		    armv7_pmnc_enable_counter(cnt);
+
+		break;
+
+	default:
+		printk(KERN_ERR "oprofile: CPU%u resetting wrong PMNC counter"
+			" %d\n", smp_processor_id(), cnt);
+		break;
+	}
+}
+
+int armv7_setup_pmnc(void)
+{
+	unsigned int cnt;
+
+	if (armv7_pmnc_read() & PMNC_E) {
+		printk(KERN_ERR "oprofile: CPU%u PMNC still enabled when setup"
+			" new event counter.\n", smp_processor_id());
+		return -EBUSY;
+	}
+
+	/*
+	 * Initialize & Reset PMNC: C bit, D bit and P bit.
+	 *  Note: Using a slower count for CCNT (D bit: divide by 64) results
+	 *   in a more stable system
+	 */
+	armv7_pmnc_write(PMNC_P | PMNC_C | PMNC_D);
+
+
+	for (cnt = CCNT; cnt < CNTMAX; cnt++) {
+		unsigned long event;
+		u32 cpu_cnt = CPU_COUNTER(smp_processor_id(), cnt);
+
+		/*
+		 * Disable counter
+		 */
+		armv7_pmnc_disable_counter(cnt);
+		cnt_en[cnt] = 0;
+
+		if (!counter_config[cpu_cnt].enabled)
+			continue;
+
+		event = counter_config[cpu_cnt].event & 255;
+
+		/*
+		 * Set event (if destined for PMNx counters)
+		 * We don't need to set the event if it's a cycle count
+		 */
+		if (cnt != CCNT)
+			armv7_pmnc_write_evtsel(cnt, event);
+
+		/*
+		 * Enable interrupt for this counter
+		 */
+		armv7_pmnc_enable_intens(cnt);
+
+		/*
+		 * Reset counter
+		 */
+		armv7_pmnc_reset_counter(cnt);
+
+		/*
+		 * Enable counter
+		 */
+		armv7_pmnc_enable_counter(cnt);
+		cnt_en[cnt] = 1;
+	}
+
+	return 0;
+}
+
+static inline void armv7_start_pmnc(void)
+{
+	armv7_pmnc_write(armv7_pmnc_read() | PMNC_E);
+}
+
+static inline void armv7_stop_pmnc(void)
+{
+	armv7_pmnc_write(armv7_pmnc_read() & ~PMNC_E);
+}
+
+/*
+ * CPU counters' IRQ handler (one IRQ per CPU)
+ */
+static irqreturn_t armv7_pmnc_interrupt(int irq, void *arg)
+{
+	struct pt_regs *regs = get_irq_regs();
+	unsigned int cnt;
+	u32 flags;
+
+
+	/*
+	 * Stop IRQ generation
+	 */
+	armv7_stop_pmnc();
+
+	/*
+	 * Get and reset overflow status flags
+	 */
+	flags = armv7_pmnc_getreset_flags();
+
+	/*
+	 * Cycle counter
+	 */
+	if (flags & FLAG_C) {
+		u32 cpu_cnt = CPU_COUNTER(smp_processor_id(), CCNT);
+		armv7_pmnc_reset_counter(CCNT);
+		oprofile_add_sample(regs, cpu_cnt);
+	}
+
+	/*
+	 * PMNC counters 0:3
+	 */
+	for (cnt = CNT0; cnt < CNTMAX; cnt++) {
+		if (flags & (1 << (cnt - CNT0))) {
+			u32 cpu_cnt = CPU_COUNTER(smp_processor_id(), cnt);
+			armv7_pmnc_reset_counter(cnt);
+			oprofile_add_sample(regs, cpu_cnt);
+		}
+	}
+
+	/*
+	 * Allow IRQ generation
+	 */
+	armv7_start_pmnc();
+
+	return IRQ_HANDLED;
+}
+
+int armv7_request_interrupts(int *irqs, int nr)
+{
+	unsigned int i;
+	int ret = 0;
+
+	for (i = 0; i < nr; i++) {
+		ret = request_irq(irqs[i], armv7_pmnc_interrupt,
+				IRQF_DISABLED, "CP15 PMNC", NULL);
+		if (ret != 0) {
+			printk(KERN_ERR "oprofile: unable to request IRQ%u"
+				" for ARMv7\n",
+			       irqs[i]);
+			break;
+		}
+	}
+
+	if (i != nr)
+		while (i-- != 0)
+			free_irq(irqs[i], NULL);
+
+	return ret;
+}
+
+void armv7_release_interrupts(int *irqs, int nr)
+{
+	unsigned int i;
+
+	for (i = 0; i < nr; i++)
+		free_irq(irqs[i], NULL);
+}
+
+#ifdef DEBUG
+static void armv7_pmnc_dump_regs(void)
+{
+	u32 val;
+	unsigned int cnt;
+
+	printk(KERN_INFO "PMNC registers dump:\n");
+
+	asm volatile("mrc p15, 0, %0, c9, c12, 0" : "=r" (val));
+	printk(KERN_INFO "PMNC  =0x%08x\n", val);
+
+	asm volatile("mrc p15, 0, %0, c9, c12, 1" : "=r" (val));
+	printk(KERN_INFO "CNTENS=0x%08x\n", val);
+
+	asm volatile("mrc p15, 0, %0, c9, c14, 1" : "=r" (val));
+	printk(KERN_INFO "INTENS=0x%08x\n", val);
+
+	asm volatile("mrc p15, 0, %0, c9, c12, 3" : "=r" (val));
+	printk(KERN_INFO "FLAGS =0x%08x\n", val);
+
+	asm volatile("mrc p15, 0, %0, c9, c12, 5" : "=r" (val));
+	printk(KERN_INFO "SELECT=0x%08x\n", val);
+
+	asm volatile("mrc p15, 0, %0, c9, c13, 0" : "=r" (val));
+	printk(KERN_INFO "CCNT  =0x%08x\n", val);
+
+	for (cnt = CNT0; cnt < CNTMAX; cnt++) {
+		armv7_pmnc_select_counter(cnt);
+		asm volatile("mrc p15, 0, %0, c9, c13, 2" : "=r" (val));
+		printk(KERN_INFO "CNT[%d] count =0x%08x\n", cnt-CNT0, val);
+		asm volatile("mrc p15, 0, %0, c9, c13, 1" : "=r" (val));
+		printk(KERN_INFO "CNT[%d] evtsel=0x%08x\n", cnt-CNT0, val);
+	}
+}
+#endif
+
+
+static int irqs[] = {
+#ifdef CONFIG_ARCH_OMAP3
+	INT_34XX_BENCH_MPU_EMUL,
+#endif
+};
+
+static void armv7_pmnc_stop(void)
+{
+#ifdef DEBUG
+	armv7_pmnc_dump_regs();
+#endif
+	armv7_stop_pmnc();
+	armv7_release_interrupts(irqs, ARRAY_SIZE(irqs));
+}
+
+static int armv7_pmnc_start(void)
+{
+	int ret;
+
+#ifdef DEBUG
+	armv7_pmnc_dump_regs();
+#endif
+	ret = armv7_request_interrupts(irqs, ARRAY_SIZE(irqs));
+	if (ret >= 0)
+		armv7_start_pmnc();
+
+	return ret;
+}
+
+static int armv7_detect_pmnc(void)
+{
+	return 0;
+}
+
+struct op_arm_model_spec op_armv7_spec = {
+	.init		= armv7_detect_pmnc,
+	.num_counters	= 5,
+	.setup_ctrs	= armv7_setup_pmnc,
+	.start		= armv7_pmnc_start,
+	.stop		= armv7_pmnc_stop,
+	.name		= "arm/armv7",
+};
diff --git a/arch/arm/oprofile/op_model_v7.h b/arch/arm/oprofile/op_model_v7.h
new file mode 100644
index 0000000..0e19bcc
--- /dev/null
+++ b/arch/arm/oprofile/op_model_v7.h
@@ -0,0 +1,103 @@
+/**
+ * op_model_v7.h
+ * ARM v7 (Cortex A8) Event Monitor Driver
+ *
+ * Copyright 2008 Jean Pihet <jpihet@mvista.com>
+ * Copyright 2004 ARM SMP Development Team
+ * Copyright 2000-2004 Deepak Saxena <dsaxena@mvista.com>
+ * Copyright 2000-2004 MontaVista Software Inc
+ * Copyright 2004 Dave Jiang <dave.jiang@intel.com>
+ * Copyright 2004 Intel Corporation
+ * Copyright 2004 Zwane Mwaikambo <zwane@arm.linux.org.uk>
+ * Copyright 2004 Oprofile Authors
+ *
+ * Read the file COPYING
+ *
+ * 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 OP_MODEL_V7_H
+#define OP_MODEL_V7_H
+
+/*
+ * Per-CPU PMNC: config reg
+ */
+#define PMNC_E		(1 << 0)	/* Enable all counters */
+#define PMNC_P		(1 << 1)	/* Reset all counters */
+#define PMNC_C		(1 << 2)	/* Cycle counter reset */
+#define PMNC_D		(1 << 3)	/* CCNT counts every 64th cpu cycle */
+#define PMNC_X		(1 << 4)	/* Export to ETM */
+#define PMNC_DP		(1 << 5)	/* Disable CCNT if non-invasive debug*/
+#define	PMNC_MASK	0x3f		/* Mask for writable bits */
+
+/*
+ * Available counters
+ */
+#define CCNT 		0
+#define CNT0 		1
+#define CNT1 		2
+#define CNT2 		3
+#define CNT3 		4
+#define CNTMAX 		5
+
+#define CPU_COUNTER(cpu, counter)	((cpu) * CNTMAX + (counter))
+
+/*
+ * CNTENS: counters enable reg
+ */
+#define CNTENS_P0	(1 << 0)
+#define CNTENS_P1	(1 << 1)
+#define CNTENS_P2	(1 << 2)
+#define CNTENS_P3	(1 << 3)
+#define CNTENS_C	(1 << 31)
+#define	CNTENS_MASK	0x8000000f	/* Mask for writable bits */
+
+/*
+ * CNTENC: counters disable reg
+ */
+#define CNTENC_P0	(1 << 0)
+#define CNTENC_P1	(1 << 1)
+#define CNTENC_P2	(1 << 2)
+#define CNTENC_P3	(1 << 3)
+#define CNTENC_C	(1 << 31)
+#define	CNTENC_MASK	0x8000000f	/* Mask for writable bits */
+
+/*
+ * INTENS: counters overflow interrupt enable reg
+ */
+#define INTENS_P0	(1 << 0)
+#define INTENS_P1	(1 << 1)
+#define INTENS_P2	(1 << 2)
+#define INTENS_P3	(1 << 3)
+#define INTENS_C	(1 << 31)
+#define	INTENS_MASK	0x8000000f	/* Mask for writable bits */
+
+/*
+ * EVTSEL: Event selection reg
+ */
+#define	EVTSEL_MASK	0x7f		/* Mask for writable bits */
+
+/*
+ * SELECT: Counter selection reg
+ */
+#define	SELECT_MASK	0x1f		/* Mask for writable bits */
+
+/*
+ * FLAG: counters overflow flag status reg
+ */
+#define FLAG_P0		(1 << 0)
+#define FLAG_P1		(1 << 1)
+#define FLAG_P2		(1 << 2)
+#define FLAG_P3		(1 << 3)
+#define FLAG_C		(1 << 31)
+#define	FLAG_MASK	0x8000000f	/* Mask for writable bits */
+
+
+int armv7_setup_pmu(void);
+int armv7_start_pmu(void);
+int armv7_stop_pmu(void);
+int armv7_request_interrupts(int *, int);
+void armv7_release_interrupts(int *, int);
+
+#endif
diff --git a/arch/arm/oprofile/op_model_xscale.c b/arch/arm/oprofile/op_model_xscale.c
index 7c3289c..724ab9c 100644
--- a/arch/arm/oprofile/op_model_xscale.c
+++ b/arch/arm/oprofile/op_model_xscale.c
@@ -22,7 +22,7 @@
 #include <linux/interrupt.h>
 #include <linux/irq.h>
 
-#include <asm/system.h>
+#include <asm/cputype.h>
 
 #include "op_counter.h"
 #include "op_arm_model.h"
diff --git a/arch/arm/plat-iop/i2c.c b/arch/arm/plat-iop/i2c.c
index 6dcbcc4..4efe392 100644
--- a/arch/arm/plat-iop/i2c.c
+++ b/arch/arm/plat-iop/i2c.c
@@ -18,7 +18,7 @@
 #include <linux/serial.h>
 #include <linux/tty.h>
 #include <linux/serial_core.h>
-#include <asm/io.h>
+#include <linux/io.h>
 #include <asm/pgtable.h>
 #include <asm/page.h>
 #include <asm/mach/map.h>
diff --git a/arch/arm/plat-iop/io.c b/arch/arm/plat-iop/io.c
index 39dcfb4..ed0bbec 100644
--- a/arch/arm/plat-iop/io.c
+++ b/arch/arm/plat-iop/io.c
@@ -18,8 +18,8 @@
  */
 #include <linux/kernel.h>
 #include <linux/module.h>
+#include <linux/io.h>
 #include <mach/hardware.h>
-#include <asm/io.h>
 
 void * __iomem __iop3xx_ioremap(unsigned long cookie, size_t size,
 	unsigned int mtype)
diff --git a/arch/arm/plat-iop/pci.c b/arch/arm/plat-iop/pci.c
index 54708bf..77fa7cc 100644
--- a/arch/arm/plat-iop/pci.c
+++ b/arch/arm/plat-iop/pci.c
@@ -17,7 +17,7 @@
 #include <linux/mm.h>
 #include <linux/init.h>
 #include <linux/ioport.h>
-#include <asm/io.h>
+#include <linux/io.h>
 #include <asm/irq.h>
 #include <asm/signal.h>
 #include <asm/system.h>
diff --git a/arch/arm/plat-iop/time.c b/arch/arm/plat-iop/time.c
index c53fefb..3695bbe 100644
--- a/arch/arm/plat-iop/time.c
+++ b/arch/arm/plat-iop/time.c
@@ -18,8 +18,8 @@
 #include <linux/time.h>
 #include <linux/init.h>
 #include <linux/timex.h>
+#include <linux/io.h>
 #include <mach/hardware.h>
-#include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/uaccess.h>
 #include <asm/mach/irq.h>
diff --git a/arch/arm/plat-mxc/Kconfig b/arch/arm/plat-mxc/Kconfig
index e14eaad..b2a7e3f 100644
--- a/arch/arm/plat-mxc/Kconfig
+++ b/arch/arm/plat-mxc/Kconfig
@@ -23,4 +23,15 @@
 
 endmenu
 
+config MXC_IRQ_PRIOR
+	bool "Use IRQ priority"
+	depends on ARCH_MXC
+	help
+	  Select this if you want to use prioritized IRQ handling.
+	  This feature prevents higher priority ISR to be interrupted
+	  by lower priority IRQ even IRQF_DISABLED flag is not set.
+	  This may be useful in embedded applications, where are strong
+	  requirements for timing.
+	  Say N here, unless you have a specialized requirement.
+
 endif
diff --git a/arch/arm/plat-mxc/Makefile b/arch/arm/plat-mxc/Makefile
index db66e9a..067556f 100644
--- a/arch/arm/plat-mxc/Makefile
+++ b/arch/arm/plat-mxc/Makefile
@@ -3,6 +3,6 @@
 #
 
 # Common support
-obj-y := irq.o clock.o gpio.o time.o
+obj-y := irq.o clock.o gpio.o time.o devices.o
 
-obj-$(CONFIG_ARCH_MX2) += iomux-mx1-mx2.o
+obj-$(CONFIG_ARCH_MX2) += iomux-mx1-mx2.o dma-mx1-mx2.o
diff --git a/arch/arm/plat-mxc/devices.c b/arch/arm/plat-mxc/devices.c
new file mode 100644
index 0000000..c667482
--- /dev/null
+++ b/arch/arm/plat-mxc/devices.c
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2008 Sascha Hauer, kernel@pengutronix.de
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA  02110-1301, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+
+int __init mxc_register_device(struct platform_device *pdev, void *data)
+{
+	int ret;
+
+	pdev->dev.platform_data = data;
+
+	ret = platform_device_register(pdev);
+	if (ret)
+		pr_debug("Unable to register platform device '%s': %d\n",
+			 pdev->name, ret);
+
+	return ret;
+}
+
diff --git a/arch/arm/plat-mxc/dma-mx1-mx2.c b/arch/arm/plat-mxc/dma-mx1-mx2.c
new file mode 100644
index 0000000..b296f19
--- /dev/null
+++ b/arch/arm/plat-mxc/dma-mx1-mx2.c
@@ -0,0 +1,840 @@
+/*
+ *  linux/arch/arm/plat-mxc/dma-mx1-mx2.c
+ *
+ *  i.MX DMA registration and IRQ dispatching
+ *
+ * Copyright 2006 Pavel Pisa <pisa@cmp.felk.cvut.cz>
+ * Copyright 2008 Juergen Beisert, <kernel@pengutronix.de>
+ * Copyright 2008 Sascha Hauer, <s.hauer@pengutronix.de>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/errno.h>
+#include <linux/clk.h>
+#include <linux/scatterlist.h>
+#include <linux/io.h>
+
+#include <asm/system.h>
+#include <asm/irq.h>
+#include <mach/hardware.h>
+#include <asm/dma.h>
+#include <mach/dma-mx1-mx2.h>
+
+#define DMA_DCR     0x00		/* Control Register */
+#define DMA_DISR    0x04		/* Interrupt status Register */
+#define DMA_DIMR    0x08		/* Interrupt mask Register */
+#define DMA_DBTOSR  0x0c		/* Burst timeout status Register */
+#define DMA_DRTOSR  0x10		/* Request timeout Register */
+#define DMA_DSESR   0x14		/* Transfer Error Status Register */
+#define DMA_DBOSR   0x18		/* Buffer overflow status Register */
+#define DMA_DBTOCR  0x1c		/* Burst timeout control Register */
+#define DMA_WSRA    0x40		/* W-Size Register A */
+#define DMA_XSRA    0x44		/* X-Size Register A */
+#define DMA_YSRA    0x48		/* Y-Size Register A */
+#define DMA_WSRB    0x4c		/* W-Size Register B */
+#define DMA_XSRB    0x50		/* X-Size Register B */
+#define DMA_YSRB    0x54		/* Y-Size Register B */
+#define DMA_SAR(x)  (0x80 + ((x) << 6))	/* Source Address Registers */
+#define DMA_DAR(x)  (0x84 + ((x) << 6))	/* Destination Address Registers */
+#define DMA_CNTR(x) (0x88 + ((x) << 6))	/* Count Registers */
+#define DMA_CCR(x)  (0x8c + ((x) << 6))	/* Control Registers */
+#define DMA_RSSR(x) (0x90 + ((x) << 6))	/* Request source select Registers */
+#define DMA_BLR(x)  (0x94 + ((x) << 6))	/* Burst length Registers */
+#define DMA_RTOR(x) (0x98 + ((x) << 6))	/* Request timeout Registers */
+#define DMA_BUCR(x) (0x98 + ((x) << 6))	/* Bus Utilization Registers */
+#define DMA_CCNR(x) (0x9C + ((x) << 6))	/* Channel counter Registers */
+
+#define DCR_DRST           (1<<1)
+#define DCR_DEN            (1<<0)
+#define DBTOCR_EN          (1<<15)
+#define DBTOCR_CNT(x)      ((x) & 0x7fff)
+#define CNTR_CNT(x)        ((x) & 0xffffff)
+#define CCR_ACRPT          (1<<14)
+#define CCR_DMOD_LINEAR    (0x0 << 12)
+#define CCR_DMOD_2D        (0x1 << 12)
+#define CCR_DMOD_FIFO      (0x2 << 12)
+#define CCR_DMOD_EOBFIFO   (0x3 << 12)
+#define CCR_SMOD_LINEAR    (0x0 << 10)
+#define CCR_SMOD_2D        (0x1 << 10)
+#define CCR_SMOD_FIFO      (0x2 << 10)
+#define CCR_SMOD_EOBFIFO   (0x3 << 10)
+#define CCR_MDIR_DEC       (1<<9)
+#define CCR_MSEL_B         (1<<8)
+#define CCR_DSIZ_32        (0x0 << 6)
+#define CCR_DSIZ_8         (0x1 << 6)
+#define CCR_DSIZ_16        (0x2 << 6)
+#define CCR_SSIZ_32        (0x0 << 4)
+#define CCR_SSIZ_8         (0x1 << 4)
+#define CCR_SSIZ_16        (0x2 << 4)
+#define CCR_REN            (1<<3)
+#define CCR_RPT            (1<<2)
+#define CCR_FRC            (1<<1)
+#define CCR_CEN            (1<<0)
+#define RTOR_EN            (1<<15)
+#define RTOR_CLK           (1<<14)
+#define RTOR_PSC           (1<<13)
+
+/*
+ * struct imx_dma_channel - i.MX specific DMA extension
+ * @name: name specified by DMA client
+ * @irq_handler: client callback for end of transfer
+ * @err_handler: client callback for error condition
+ * @data: clients context data for callbacks
+ * @dma_mode: direction of the transfer %DMA_MODE_READ or %DMA_MODE_WRITE
+ * @sg: pointer to the actual read/written chunk for scatter-gather emulation
+ * @resbytes: total residual number of bytes to transfer
+ *            (it can be lower or same as sum of SG mapped chunk sizes)
+ * @sgcount: number of chunks to be read/written
+ *
+ * Structure is used for IMX DMA processing. It would be probably good
+ * @struct dma_struct in the future for external interfacing and use
+ * @struct imx_dma_channel only as extension to it.
+ */
+
+struct imx_dma_channel {
+	const char *name;
+	void (*irq_handler) (int, void *);
+	void (*err_handler) (int, void *, int errcode);
+	void (*prog_handler) (int, void *, struct scatterlist *);
+	void *data;
+	dmamode_t  dma_mode;
+	struct scatterlist *sg;
+	unsigned int resbytes;
+	int dma_num;
+
+	int in_use;
+
+	u32 ccr_from_device;
+	u32 ccr_to_device;
+
+	struct timer_list watchdog;
+
+	int hw_chaining;
+};
+
+static struct imx_dma_channel imx_dma_channels[IMX_DMA_CHANNELS];
+
+static struct clk *dma_clk;
+
+static int imx_dma_hw_chain(struct imx_dma_channel *imxdma)
+{
+	if (cpu_is_mx27())
+		return imxdma->hw_chaining;
+	else
+		return 0;
+}
+
+
+/*
+ * imx_dma_sg_next - prepare next chunk for scatter-gather DMA emulation
+ */
+static inline int imx_dma_sg_next(int channel, struct scatterlist *sg)
+{
+	struct imx_dma_channel *imxdma = &imx_dma_channels[channel];
+	unsigned long now;
+
+	if (!imxdma->name) {
+		printk(KERN_CRIT "%s: called for  not allocated channel %d\n",
+		       __func__, channel);
+		return 0;
+	}
+
+	now = min(imxdma->resbytes, sg->length);
+	imxdma->resbytes -= now;
+
+	if ((imxdma->dma_mode & DMA_MODE_MASK) == DMA_MODE_READ)
+		__raw_writel(sg->dma_address, DMA_BASE + DMA_DAR(channel));
+	else
+		__raw_writel(sg->dma_address, DMA_BASE + DMA_SAR(channel));
+
+	__raw_writel(now, DMA_BASE + DMA_CNTR(channel));
+
+	pr_debug("imxdma%d: next sg chunk dst 0x%08x, src 0x%08x, "
+		"size 0x%08x\n", channel,
+		 __raw_readl(DMA_BASE + DMA_DAR(channel)),
+		 __raw_readl(DMA_BASE + DMA_SAR(channel)),
+		 __raw_readl(DMA_BASE + DMA_CNTR(channel)));
+
+	return now;
+}
+
+/**
+ * imx_dma_setup_single - setup i.MX DMA channel for linear memory to/from
+ * device transfer
+ *
+ * @channel: i.MX DMA channel number
+ * @dma_address: the DMA/physical memory address of the linear data block
+ *		to transfer
+ * @dma_length: length of the data block in bytes
+ * @dev_addr: physical device port address
+ * @dmamode: DMA transfer mode, %DMA_MODE_READ from the device to the memory
+ *           or %DMA_MODE_WRITE from memory to the device
+ *
+ * Return value: if incorrect parameters are provided -%EINVAL.
+ *		Zero indicates success.
+ */
+int
+imx_dma_setup_single(int channel, dma_addr_t dma_address,
+		     unsigned int dma_length, unsigned int dev_addr,
+		     dmamode_t dmamode)
+{
+	struct imx_dma_channel *imxdma = &imx_dma_channels[channel];
+
+	imxdma->sg = NULL;
+	imxdma->dma_mode = dmamode;
+
+	if (!dma_address) {
+		printk(KERN_ERR "imxdma%d: imx_dma_setup_single null address\n",
+		       channel);
+		return -EINVAL;
+	}
+
+	if (!dma_length) {
+		printk(KERN_ERR "imxdma%d: imx_dma_setup_single zero length\n",
+		       channel);
+		return -EINVAL;
+	}
+
+	if ((dmamode & DMA_MODE_MASK) == DMA_MODE_READ) {
+		pr_debug("imxdma%d: %s dma_addressg=0x%08x dma_length=%d "
+			"dev_addr=0x%08x for read\n",
+			channel, __func__, (unsigned int)dma_address,
+			dma_length, dev_addr);
+
+		__raw_writel(dev_addr, DMA_BASE + DMA_SAR(channel));
+		__raw_writel(dma_address, DMA_BASE + DMA_DAR(channel));
+		__raw_writel(imxdma->ccr_from_device,
+				DMA_BASE + DMA_CCR(channel));
+	} else if ((dmamode & DMA_MODE_MASK) == DMA_MODE_WRITE) {
+		pr_debug("imxdma%d: %s dma_addressg=0x%08x dma_length=%d "
+			"dev_addr=0x%08x for write\n",
+			channel, __func__, (unsigned int)dma_address,
+			dma_length, dev_addr);
+
+		__raw_writel(dma_address, DMA_BASE + DMA_SAR(channel));
+		__raw_writel(dev_addr, DMA_BASE + DMA_DAR(channel));
+		__raw_writel(imxdma->ccr_to_device,
+				DMA_BASE + DMA_CCR(channel));
+	} else {
+		printk(KERN_ERR "imxdma%d: imx_dma_setup_single bad dmamode\n",
+		       channel);
+		return -EINVAL;
+	}
+
+	__raw_writel(dma_length, DMA_BASE + DMA_CNTR(channel));
+
+	return 0;
+}
+EXPORT_SYMBOL(imx_dma_setup_single);
+
+/**
+ * imx_dma_setup_sg - setup i.MX DMA channel SG list to/from device transfer
+ * @channel: i.MX DMA channel number
+ * @sg: pointer to the scatter-gather list/vector
+ * @sgcount: scatter-gather list hungs count
+ * @dma_length: total length of the transfer request in bytes
+ * @dev_addr: physical device port address
+ * @dmamode: DMA transfer mode, %DMA_MODE_READ from the device to the memory
+ *           or %DMA_MODE_WRITE from memory to the device
+ *
+ * The function sets up DMA channel state and registers to be ready for
+ * transfer specified by provided parameters. The scatter-gather emulation
+ * is set up according to the parameters.
+ *
+ * The full preparation of the transfer requires setup of more register
+ * by the caller before imx_dma_enable() can be called.
+ *
+ * %BLR(channel) holds transfer burst length in bytes, 0 means 64 bytes
+ *
+ * %RSSR(channel) has to be set to the DMA request line source %DMA_REQ_xxx
+ *
+ * %CCR(channel) has to specify transfer parameters, the next settings is
+ * typical for linear or simple scatter-gather transfers if %DMA_MODE_READ is
+ * specified
+ *
+ * %CCR_DMOD_LINEAR | %CCR_DSIZ_32 | %CCR_SMOD_FIFO | %CCR_SSIZ_x
+ *
+ * The typical setup for %DMA_MODE_WRITE is specified by next options
+ * combination
+ *
+ * %CCR_SMOD_LINEAR | %CCR_SSIZ_32 | %CCR_DMOD_FIFO | %CCR_DSIZ_x
+ *
+ * Be careful here and do not mistakenly mix source and target device
+ * port sizes constants, they are really different:
+ * %CCR_SSIZ_8, %CCR_SSIZ_16, %CCR_SSIZ_32,
+ * %CCR_DSIZ_8, %CCR_DSIZ_16, %CCR_DSIZ_32
+ *
+ * Return value: if incorrect parameters are provided -%EINVAL.
+ * Zero indicates success.
+ */
+int
+imx_dma_setup_sg(int channel,
+		 struct scatterlist *sg, unsigned int sgcount,
+		 unsigned int dma_length, unsigned int dev_addr,
+		 dmamode_t dmamode)
+{
+	struct imx_dma_channel *imxdma = &imx_dma_channels[channel];
+
+	if (imxdma->in_use)
+		return -EBUSY;
+
+	imxdma->sg = sg;
+	imxdma->dma_mode = dmamode;
+	imxdma->resbytes = dma_length;
+
+	if (!sg || !sgcount) {
+		printk(KERN_ERR "imxdma%d: imx_dma_setup_sg epty sg list\n",
+		       channel);
+		return -EINVAL;
+	}
+
+	if (!sg->length) {
+		printk(KERN_ERR "imxdma%d: imx_dma_setup_sg zero length\n",
+		       channel);
+		return -EINVAL;
+	}
+
+	if ((dmamode & DMA_MODE_MASK) == DMA_MODE_READ) {
+		pr_debug("imxdma%d: %s sg=%p sgcount=%d total length=%d "
+			"dev_addr=0x%08x for read\n",
+			channel, __func__, sg, sgcount, dma_length, dev_addr);
+
+		__raw_writel(dev_addr, DMA_BASE + DMA_SAR(channel));
+		__raw_writel(imxdma->ccr_from_device,
+				DMA_BASE + DMA_CCR(channel));
+	} else if ((dmamode & DMA_MODE_MASK) == DMA_MODE_WRITE) {
+		pr_debug("imxdma%d: %s sg=%p sgcount=%d total length=%d "
+			"dev_addr=0x%08x for write\n",
+			channel, __func__, sg, sgcount, dma_length, dev_addr);
+
+		__raw_writel(dev_addr, DMA_BASE + DMA_DAR(channel));
+		__raw_writel(imxdma->ccr_to_device,
+				DMA_BASE + DMA_CCR(channel));
+	} else {
+		printk(KERN_ERR "imxdma%d: imx_dma_setup_sg bad dmamode\n",
+		       channel);
+		return -EINVAL;
+	}
+
+	imx_dma_sg_next(channel, sg);
+
+	return 0;
+}
+EXPORT_SYMBOL(imx_dma_setup_sg);
+
+int
+imx_dma_config_channel(int channel, unsigned int config_port,
+	unsigned int config_mem, unsigned int dmareq, int hw_chaining)
+{
+	struct imx_dma_channel *imxdma = &imx_dma_channels[channel];
+	u32 dreq = 0;
+
+	imxdma->hw_chaining = 0;
+
+	if (hw_chaining) {
+		imxdma->hw_chaining = 1;
+		if (!imx_dma_hw_chain(imxdma))
+			return -EINVAL;
+	}
+
+	if (dmareq)
+		dreq = CCR_REN;
+
+	imxdma->ccr_from_device = config_port | (config_mem << 2) | dreq;
+	imxdma->ccr_to_device = config_mem | (config_port << 2) | dreq;
+
+	__raw_writel(dmareq, DMA_BASE + DMA_RSSR(channel));
+
+	return 0;
+}
+EXPORT_SYMBOL(imx_dma_config_channel);
+
+void imx_dma_config_burstlen(int channel, unsigned int burstlen)
+{
+	__raw_writel(burstlen, DMA_BASE + DMA_BLR(channel));
+}
+EXPORT_SYMBOL(imx_dma_config_burstlen);
+
+/**
+ * imx_dma_setup_handlers - setup i.MX DMA channel end and error notification
+ * handlers
+ * @channel: i.MX DMA channel number
+ * @irq_handler: the pointer to the function called if the transfer
+ *		ends successfully
+ * @err_handler: the pointer to the function called if the premature
+ *		end caused by error occurs
+ * @data: user specified value to be passed to the handlers
+ */
+int
+imx_dma_setup_handlers(int channel,
+		       void (*irq_handler) (int, void *),
+		       void (*err_handler) (int, void *, int),
+		       void *data)
+{
+	struct imx_dma_channel *imxdma = &imx_dma_channels[channel];
+	unsigned long flags;
+
+	if (!imxdma->name) {
+		printk(KERN_CRIT "%s: called for  not allocated channel %d\n",
+		       __func__, channel);
+		return -ENODEV;
+	}
+
+	local_irq_save(flags);
+	__raw_writel(1 << channel, DMA_BASE + DMA_DISR);
+	imxdma->irq_handler = irq_handler;
+	imxdma->err_handler = err_handler;
+	imxdma->data = data;
+	local_irq_restore(flags);
+	return 0;
+}
+EXPORT_SYMBOL(imx_dma_setup_handlers);
+
+/**
+ * imx_dma_setup_progression_handler - setup i.MX DMA channel progression
+ * handlers
+ * @channel: i.MX DMA channel number
+ * @prog_handler: the pointer to the function called if the transfer progresses
+ */
+int
+imx_dma_setup_progression_handler(int channel,
+			void (*prog_handler) (int, void*, struct scatterlist*))
+{
+	struct imx_dma_channel *imxdma = &imx_dma_channels[channel];
+	unsigned long flags;
+
+	if (!imxdma->name) {
+		printk(KERN_CRIT "%s: called for  not allocated channel %d\n",
+		       __func__, channel);
+		return -ENODEV;
+	}
+
+	local_irq_save(flags);
+	imxdma->prog_handler = prog_handler;
+	local_irq_restore(flags);
+	return 0;
+}
+EXPORT_SYMBOL(imx_dma_setup_progression_handler);
+
+/**
+ * imx_dma_enable - function to start i.MX DMA channel operation
+ * @channel: i.MX DMA channel number
+ *
+ * The channel has to be allocated by driver through imx_dma_request()
+ * or imx_dma_request_by_prio() function.
+ * The transfer parameters has to be set to the channel registers through
+ * call of the imx_dma_setup_single() or imx_dma_setup_sg() function
+ * and registers %BLR(channel), %RSSR(channel) and %CCR(channel) has to
+ * be set prior this function call by the channel user.
+ */
+void imx_dma_enable(int channel)
+{
+	struct imx_dma_channel *imxdma = &imx_dma_channels[channel];
+	unsigned long flags;
+
+	pr_debug("imxdma%d: imx_dma_enable\n", channel);
+
+	if (!imxdma->name) {
+		printk(KERN_CRIT "%s: called for  not allocated channel %d\n",
+		       __func__, channel);
+		return;
+	}
+
+	if (imxdma->in_use)
+		return;
+
+	local_irq_save(flags);
+
+	__raw_writel(1 << channel, DMA_BASE + DMA_DISR);
+	__raw_writel(__raw_readl(DMA_BASE + DMA_DIMR) & ~(1 << channel),
+		DMA_BASE + DMA_DIMR);
+	__raw_writel(__raw_readl(DMA_BASE + DMA_CCR(channel)) | CCR_CEN |
+		CCR_ACRPT,
+		DMA_BASE + DMA_CCR(channel));
+
+#ifdef CONFIG_ARCH_MX2
+	if (imxdma->sg && imx_dma_hw_chain(imxdma)) {
+		imxdma->sg = sg_next(imxdma->sg);
+		if (imxdma->sg) {
+			u32 tmp;
+			imx_dma_sg_next(channel, imxdma->sg);
+			tmp = __raw_readl(DMA_BASE + DMA_CCR(channel));
+			__raw_writel(tmp | CCR_RPT | CCR_ACRPT,
+				DMA_BASE + DMA_CCR(channel));
+		}
+	}
+#endif
+	imxdma->in_use = 1;
+
+	local_irq_restore(flags);
+}
+EXPORT_SYMBOL(imx_dma_enable);
+
+/**
+ * imx_dma_disable - stop, finish i.MX DMA channel operatin
+ * @channel: i.MX DMA channel number
+ */
+void imx_dma_disable(int channel)
+{
+	struct imx_dma_channel *imxdma = &imx_dma_channels[channel];
+	unsigned long flags;
+
+	pr_debug("imxdma%d: imx_dma_disable\n", channel);
+
+	if (imx_dma_hw_chain(imxdma))
+		del_timer(&imxdma->watchdog);
+
+	local_irq_save(flags);
+	__raw_writel(__raw_readl(DMA_BASE + DMA_DIMR) | (1 << channel),
+		DMA_BASE + DMA_DIMR);
+	__raw_writel(__raw_readl(DMA_BASE + DMA_CCR(channel)) & ~CCR_CEN,
+		DMA_BASE + DMA_CCR(channel));
+	__raw_writel(1 << channel, DMA_BASE + DMA_DISR);
+	imxdma->in_use = 0;
+	local_irq_restore(flags);
+}
+EXPORT_SYMBOL(imx_dma_disable);
+
+static void imx_dma_watchdog(unsigned long chno)
+{
+	struct imx_dma_channel *imxdma = &imx_dma_channels[chno];
+
+	__raw_writel(0, DMA_BASE + DMA_CCR(chno));
+	imxdma->in_use = 0;
+	imxdma->sg = NULL;
+
+	if (imxdma->err_handler)
+		imxdma->err_handler(chno, imxdma->data, IMX_DMA_ERR_TIMEOUT);
+}
+
+static irqreturn_t dma_err_handler(int irq, void *dev_id)
+{
+	int i, disr;
+	struct imx_dma_channel *imxdma;
+	unsigned int err_mask;
+	int errcode;
+
+	disr = __raw_readl(DMA_BASE + DMA_DISR);
+
+	err_mask = __raw_readl(DMA_BASE + DMA_DBTOSR) |
+		   __raw_readl(DMA_BASE + DMA_DRTOSR) |
+		   __raw_readl(DMA_BASE + DMA_DSESR)  |
+		   __raw_readl(DMA_BASE + DMA_DBOSR);
+
+	if (!err_mask)
+		return IRQ_HANDLED;
+
+	__raw_writel(disr & err_mask, DMA_BASE + DMA_DISR);
+
+	for (i = 0; i < IMX_DMA_CHANNELS; i++) {
+		if (!(err_mask & (1 << i)))
+			continue;
+		imxdma = &imx_dma_channels[i];
+		errcode = 0;
+
+		if (__raw_readl(DMA_BASE + DMA_DBTOSR) & (1 << i)) {
+			__raw_writel(1 << i, DMA_BASE + DMA_DBTOSR);
+			errcode |= IMX_DMA_ERR_BURST;
+		}
+		if (__raw_readl(DMA_BASE + DMA_DRTOSR) & (1 << i)) {
+			__raw_writel(1 << i, DMA_BASE + DMA_DRTOSR);
+			errcode |= IMX_DMA_ERR_REQUEST;
+		}
+		if (__raw_readl(DMA_BASE + DMA_DSESR) & (1 << i)) {
+			__raw_writel(1 << i, DMA_BASE + DMA_DSESR);
+			errcode |= IMX_DMA_ERR_TRANSFER;
+		}
+		if (__raw_readl(DMA_BASE + DMA_DBOSR) & (1 << i)) {
+			__raw_writel(1 << i, DMA_BASE + DMA_DBOSR);
+			errcode |= IMX_DMA_ERR_BUFFER;
+		}
+		if (imxdma->name && imxdma->err_handler) {
+			imxdma->err_handler(i, imxdma->data, errcode);
+			continue;
+		}
+
+		imx_dma_channels[i].sg = NULL;
+
+		printk(KERN_WARNING
+		       "DMA timeout on channel %d (%s) -%s%s%s%s\n",
+		       i, imxdma->name,
+		       errcode & IMX_DMA_ERR_BURST ?    " burst" : "",
+		       errcode & IMX_DMA_ERR_REQUEST ?  " request" : "",
+		       errcode & IMX_DMA_ERR_TRANSFER ? " transfer" : "",
+		       errcode & IMX_DMA_ERR_BUFFER ?   " buffer" : "");
+	}
+	return IRQ_HANDLED;
+}
+
+static void dma_irq_handle_channel(int chno)
+{
+	struct imx_dma_channel *imxdma = &imx_dma_channels[chno];
+
+	if (!imxdma->name) {
+		/*
+		 * IRQ for an unregistered DMA channel:
+		 * let's clear the interrupts and disable it.
+		 */
+		printk(KERN_WARNING
+		       "spurious IRQ for DMA channel %d\n", chno);
+		return;
+	}
+
+	if (imxdma->sg) {
+		u32 tmp;
+		struct scatterlist *current_sg = imxdma->sg;
+		imxdma->sg = sg_next(imxdma->sg);
+
+		if (imxdma->sg) {
+			imx_dma_sg_next(chno, imxdma->sg);
+
+			tmp = __raw_readl(DMA_BASE + DMA_CCR(chno));
+
+			if (imx_dma_hw_chain(imxdma)) {
+				/* FIXME: The timeout should probably be
+				 * configurable
+				 */
+				mod_timer(&imxdma->watchdog,
+					jiffies + msecs_to_jiffies(500));
+
+				tmp |= CCR_CEN | CCR_RPT | CCR_ACRPT;
+				__raw_writel(tmp, DMA_BASE +
+						DMA_CCR(chno));
+			} else {
+				__raw_writel(tmp & ~CCR_CEN, DMA_BASE +
+						DMA_CCR(chno));
+				tmp |= CCR_CEN;
+			}
+
+			__raw_writel(tmp, DMA_BASE + DMA_CCR(chno));
+
+			if (imxdma->prog_handler)
+				imxdma->prog_handler(chno, imxdma->data,
+						current_sg);
+
+			return;
+		}
+
+		if (imx_dma_hw_chain(imxdma)) {
+			del_timer(&imxdma->watchdog);
+			return;
+		}
+	}
+
+	__raw_writel(0, DMA_BASE + DMA_CCR(chno));
+	imxdma->in_use = 0;
+	if (imxdma->irq_handler)
+		imxdma->irq_handler(chno, imxdma->data);
+}
+
+static irqreturn_t dma_irq_handler(int irq, void *dev_id)
+{
+	int i, disr;
+
+#ifdef CONFIG_ARCH_MX2
+	dma_err_handler(irq, dev_id);
+#endif
+
+	disr = __raw_readl(DMA_BASE + DMA_DISR);
+
+	pr_debug("imxdma: dma_irq_handler called, disr=0x%08x\n",
+		     disr);
+
+	__raw_writel(disr, DMA_BASE + DMA_DISR);
+	for (i = 0; i < IMX_DMA_CHANNELS; i++) {
+		if (disr & (1 << i))
+			dma_irq_handle_channel(i);
+	}
+
+	return IRQ_HANDLED;
+}
+
+/**
+ * imx_dma_request - request/allocate specified channel number
+ * @channel: i.MX DMA channel number
+ * @name: the driver/caller own non-%NULL identification
+ */
+int imx_dma_request(int channel, const char *name)
+{
+	struct imx_dma_channel *imxdma = &imx_dma_channels[channel];
+	unsigned long flags;
+	int ret;
+
+	/* basic sanity checks */
+	if (!name)
+		return -EINVAL;
+
+	if (channel >= IMX_DMA_CHANNELS) {
+		printk(KERN_CRIT "%s: called for  non-existed channel %d\n",
+		       __func__, channel);
+		return -EINVAL;
+	}
+
+	local_irq_save(flags);
+	if (imxdma->name) {
+		local_irq_restore(flags);
+		return -EBUSY;
+	}
+
+#ifdef CONFIG_ARCH_MX2
+	ret = request_irq(MXC_INT_DMACH0 + channel, dma_irq_handler, 0, "DMA",
+			NULL);
+	if (ret) {
+		printk(KERN_CRIT "Can't register IRQ %d for DMA channel %d\n",
+				MXC_INT_DMACH0 + channel, channel);
+		return ret;
+	}
+	init_timer(&imxdma->watchdog);
+	imxdma->watchdog.function = &imx_dma_watchdog;
+	imxdma->watchdog.data = channel;
+#endif
+
+	imxdma->name = name;
+	imxdma->irq_handler = NULL;
+	imxdma->err_handler = NULL;
+	imxdma->data = NULL;
+	imxdma->sg = NULL;
+
+	local_irq_restore(flags);
+	return 0;
+}
+EXPORT_SYMBOL(imx_dma_request);
+
+/**
+ * imx_dma_free - release previously acquired channel
+ * @channel: i.MX DMA channel number
+ */
+void imx_dma_free(int channel)
+{
+	unsigned long flags;
+	struct imx_dma_channel *imxdma = &imx_dma_channels[channel];
+
+	if (!imxdma->name) {
+		printk(KERN_CRIT
+		       "%s: trying to free free channel %d\n",
+		       __func__, channel);
+		return;
+	}
+
+	local_irq_save(flags);
+	/* Disable interrupts */
+	__raw_writel(__raw_readl(DMA_BASE + DMA_DIMR) | (1 << channel),
+		DMA_BASE + DMA_DIMR);
+	__raw_writel(__raw_readl(DMA_BASE + DMA_CCR(channel)) & ~CCR_CEN,
+		DMA_BASE + DMA_CCR(channel));
+	imxdma->name = NULL;
+
+#ifdef CONFIG_ARCH_MX2
+	free_irq(MXC_INT_DMACH0 + channel, NULL);
+#endif
+
+	local_irq_restore(flags);
+}
+EXPORT_SYMBOL(imx_dma_free);
+
+/**
+ * imx_dma_request_by_prio - find and request some of free channels best
+ * suiting requested priority
+ * @channel: i.MX DMA channel number
+ * @name: the driver/caller own non-%NULL identification
+ *
+ * This function tries to find a free channel in the specified priority group
+ * This function tries to find a free channel in the specified priority group
+ * if the priority cannot be achieved it tries to look for free channel
+ * in the higher and then even lower priority groups.
+ *
+ * Return value: If there is no free channel to allocate, -%ENODEV is returned.
+ *               On successful allocation channel is returned.
+ */
+int imx_dma_request_by_prio(const char *name, enum imx_dma_prio prio)
+{
+	int i;
+	int best;
+
+	switch (prio) {
+	case (DMA_PRIO_HIGH):
+		best = 8;
+		break;
+	case (DMA_PRIO_MEDIUM):
+		best = 4;
+		break;
+	case (DMA_PRIO_LOW):
+	default:
+		best = 0;
+		break;
+	}
+
+	for (i = best; i < IMX_DMA_CHANNELS; i++)
+		if (!imx_dma_request(i, name))
+			return i;
+
+	for (i = best - 1; i >= 0; i--)
+		if (!imx_dma_request(i, name))
+			return i;
+
+	printk(KERN_ERR "%s: no free DMA channel found\n", __func__);
+
+	return -ENODEV;
+}
+EXPORT_SYMBOL(imx_dma_request_by_prio);
+
+static int __init imx_dma_init(void)
+{
+	int ret = 0;
+	int i;
+
+	dma_clk = clk_get(NULL, "dma_clk");
+	clk_enable(dma_clk);
+
+	/* reset DMA module */
+	__raw_writel(DCR_DRST, DMA_BASE + DMA_DCR);
+
+#ifdef CONFIG_ARCH_MX1
+	ret = request_irq(DMA_INT, dma_irq_handler, 0, "DMA", NULL);
+	if (ret) {
+		printk(KERN_CRIT "Wow!  Can't register IRQ for DMA\n");
+		return ret;
+	}
+
+	ret = request_irq(DMA_ERR, dma_err_handler, 0, "DMA", NULL);
+	if (ret) {
+		printk(KERN_CRIT "Wow!  Can't register ERRIRQ for DMA\n");
+		free_irq(DMA_INT, NULL);
+		return ret;
+	}
+#endif
+	/* enable DMA module */
+	__raw_writel(DCR_DEN, DMA_BASE + DMA_DCR);
+
+	/* clear all interrupts */
+	__raw_writel((1 << IMX_DMA_CHANNELS) - 1, DMA_BASE + DMA_DISR);
+
+	/* disable interrupts */
+	__raw_writel((1 << IMX_DMA_CHANNELS) - 1, DMA_BASE + DMA_DIMR);
+
+	for (i = 0; i < IMX_DMA_CHANNELS; i++) {
+		imx_dma_channels[i].sg = NULL;
+		imx_dma_channels[i].dma_num = i;
+	}
+
+	return ret;
+}
+
+arch_initcall(imx_dma_init);
diff --git a/arch/arm/plat-mxc/include/mach/board-mx31ads.h b/arch/arm/plat-mxc/include/mach/board-mx31ads.h
index 1bc6fb0..745b488 100644
--- a/arch/arm/plat-mxc/include/mach/board-mx31ads.h
+++ b/arch/arm/plat-mxc/include/mach/board-mx31ads.h
@@ -90,6 +90,9 @@
 #define PBC_INTMASK_CLEAR_REG	(PBC_INTMASK_CLEAR + PBC_BASE_ADDRESS)
 #define EXPIO_PARENT_INT	IOMUX_TO_IRQ(MX31_PIN_GPIO1_4)
 
+#define MXC_EXP_IO_BASE		(MXC_MAX_INT_LINES + MXC_MAX_GPIO_LINES)
+#define MXC_IRQ_TO_EXPIO(irq)	((irq) - MXC_EXP_IO_BASE)
+
 #define EXPIO_INT_LOW_BAT	(MXC_EXP_IO_BASE + 0)
 #define EXPIO_INT_PB_IRQ	(MXC_EXP_IO_BASE + 1)
 #define EXPIO_INT_OTG_FS_OVR	(MXC_EXP_IO_BASE + 2)
diff --git a/arch/arm/plat-mxc/include/mach/clock.h b/arch/arm/plat-mxc/include/mach/clock.h
index 24caa2b..d21f78e 100644
--- a/arch/arm/plat-mxc/include/mach/clock.h
+++ b/arch/arm/plat-mxc/include/mach/clock.h
@@ -39,7 +39,7 @@
 	/* Register bit position for clock's enable/disable control. */
 	u8 enable_shift;
 	/* Register address for clock's enable/disable control. */
-	u32 enable_reg;
+	void __iomem *enable_reg;
 	u32 flags;
 	/* get the current clock rate (always a fresh value) */
 	unsigned long (*get_rate) (struct clk *);
diff --git a/arch/arm/plat-mxc/include/mach/common.h b/arch/arm/plat-mxc/include/mach/common.h
index a6d2e24..6350287 100644
--- a/arch/arm/plat-mxc/include/mach/common.h
+++ b/arch/arm/plat-mxc/include/mach/common.h
@@ -11,10 +11,13 @@
 #ifndef __ASM_ARCH_MXC_COMMON_H__
 #define __ASM_ARCH_MXC_COMMON_H__
 
+struct platform_device;
+
 extern void mxc_map_io(void);
 extern void mxc_init_irq(void);
 extern void mxc_timer_init(const char *clk_timer);
 extern int mxc_clocks_init(unsigned long fref);
 extern int mxc_register_gpios(void);
+extern int mxc_register_device(struct platform_device *pdev, void *data);
 
 #endif
diff --git a/arch/arm/plat-mxc/include/mach/dma-mx1-mx2.h b/arch/arm/plat-mxc/include/mach/dma-mx1-mx2.h
new file mode 100644
index 0000000..e85fd94
--- /dev/null
+++ b/arch/arm/plat-mxc/include/mach/dma-mx1-mx2.h
@@ -0,0 +1,89 @@
+/*
+ *  linux/arch/arm/plat-mxc/include/mach/dma-mx1-mx2.h
+ *
+ *  i.MX DMA registration and IRQ dispatching
+ *
+ * Copyright 2006 Pavel Pisa <pisa@cmp.felk.cvut.cz>
+ * Copyright 2008 Juergen Beisert, <kernel@pengutronix.de>
+ * Copyright 2008 Sascha Hauer, <s.hauer@pengutronix.de>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ */
+
+#include <asm/dma.h>
+
+#ifndef __ASM_ARCH_MXC_DMA_H
+#define __ASM_ARCH_MXC_DMA_H
+
+#define IMX_DMA_CHANNELS  16
+
+#define DMA_BASE IO_ADDRESS(DMA_BASE_ADDR)
+
+#define IMX_DMA_MEMSIZE_32	(0 << 4)
+#define IMX_DMA_MEMSIZE_8	(1 << 4)
+#define IMX_DMA_MEMSIZE_16	(2 << 4)
+#define IMX_DMA_TYPE_LINEAR	(0 << 10)
+#define IMX_DMA_TYPE_2D		(1 << 10)
+#define IMX_DMA_TYPE_FIFO	(2 << 10)
+
+#define IMX_DMA_ERR_BURST     (1 << 0)
+#define IMX_DMA_ERR_REQUEST   (1 << 1)
+#define IMX_DMA_ERR_TRANSFER  (1 << 2)
+#define IMX_DMA_ERR_BUFFER    (1 << 3)
+#define IMX_DMA_ERR_TIMEOUT   (1 << 4)
+
+int
+imx_dma_config_channel(int channel, unsigned int config_port,
+	unsigned int config_mem, unsigned int dmareq, int hw_chaining);
+
+void
+imx_dma_config_burstlen(int channel, unsigned int burstlen);
+
+int
+imx_dma_setup_single(int channel, dma_addr_t dma_address,
+		unsigned int dma_length, unsigned int dev_addr,
+		dmamode_t dmamode);
+
+int
+imx_dma_setup_sg(int channel, struct scatterlist *sg,
+		unsigned int sgcount, unsigned int dma_length,
+		unsigned int dev_addr, dmamode_t dmamode);
+
+int
+imx_dma_setup_handlers(int channel,
+		void (*irq_handler) (int, void *),
+		void (*err_handler) (int, void *, int), void *data);
+
+int
+imx_dma_setup_progression_handler(int channel,
+		void (*prog_handler) (int, void*, struct scatterlist*));
+
+void imx_dma_enable(int channel);
+
+void imx_dma_disable(int channel);
+
+int imx_dma_request(int channel, const char *name);
+
+void imx_dma_free(int channel);
+
+enum imx_dma_prio {
+	DMA_PRIO_HIGH = 0,
+	DMA_PRIO_MEDIUM = 1,
+	DMA_PRIO_LOW = 2
+};
+
+int imx_dma_request_by_prio(const char *name, enum imx_dma_prio prio);
+
+#endif	/* _ASM_ARCH_MXC_DMA_H */
diff --git a/arch/arm/plat-mxc/include/mach/entry-macro.S b/arch/arm/plat-mxc/include/mach/entry-macro.S
index b542433..1163202 100644
--- a/arch/arm/plat-mxc/include/mach/entry-macro.S
+++ b/arch/arm/plat-mxc/include/mach/entry-macro.S
@@ -9,11 +9,17 @@
  * published by the Free Software Foundation.
  */
 
+#define AVIC_NIMASK	0x04
+
 	@ this macro disables fast irq (not implemented)
 	.macro	disable_fiq
 	.endm
 
 	.macro  get_irqnr_preamble, base, tmp
+	ldr	\base, =AVIC_IO_ADDRESS(AVIC_BASE_ADDR)
+#ifdef CONFIG_MXC_IRQ_PRIOR
+	ldr	r4, [\base, #AVIC_NIMASK]
+#endif
 	.endm
 
 	.macro  arch_ret_to_user, tmp1, tmp2
@@ -23,7 +29,6 @@
 	@ and returns its number in irqnr
 	@ and returns if an interrupt occured in irqstat
 	.macro	get_irqnr_and_base, irqnr, irqstat, base, tmp
-	ldr	\base, =AVIC_IO_ADDRESS(AVIC_BASE_ADDR)
 	@ Load offset & priority of the highest priority
 	@ interrupt pending from AVIC_NIVECSR
 	ldr	\irqstat, [\base, #0x40]
@@ -32,6 +37,11 @@
 	mov	\irqnr, \irqstat, asr #16
 	@ set zero flag if IRQ + 1 == 0
 	adds	\tmp, \irqnr, #1
+#ifdef CONFIG_MXC_IRQ_PRIOR
+	bicne	\tmp, \irqstat, #0xFFFFFFE0
+	strne	\tmp, [\base, #AVIC_NIMASK]
+	streq	r4, [\base, #AVIC_NIMASK]
+#endif
 	.endm
 
 	@ irq priority table (not used)
diff --git a/arch/arm/plat-mxc/include/mach/iomux-mx1-mx2.h b/arch/arm/plat-mxc/include/mach/iomux-mx1-mx2.h
index 076d37b..3d09bfd 100644
--- a/arch/arm/plat-mxc/include/mach/iomux-mx1-mx2.h
+++ b/arch/arm/plat-mxc/include/mach/iomux-mx1-mx2.h
@@ -247,6 +247,11 @@
 #endif
 
 #ifdef CONFIG_ARCH_MX2
+#define PA0_PF_USBH2_CLK	(GPIO_PORTA | GPIO_PF | 0)
+#define PA1_PF_USBH2_DIR	(GPIO_PORTA | GPIO_PF | 1)
+#define PA2_PF_USBH2_DATA7	(GPIO_PORTA | GPIO_PF | 2)
+#define PA3_PF_USBH2_NXT	(GPIO_PORTA | GPIO_PF | 3)
+#define PA4_PF_USBH2_STP	(GPIO_PORTA | GPIO_PF | 4)
 #define PA5_PF_LSCLK		(GPIO_PORTA | GPIO_OUT | GPIO_PF | 5)
 #define PA6_PF_LD0		(GPIO_PORTA | GPIO_OUT | GPIO_PF | 6)
 #define PA7_PF_LD1		(GPIO_PORTA | GPIO_OUT | GPIO_PF | 7)
@@ -294,6 +299,16 @@
 #define PB20_AF_UART5_CTS	(GPIO_PORTB | GPIO_OUT | GPIO_AF | 20)
 #define PB21_PF_CSI_HSYNC	(GPIO_PORTB | GPIO_OUT | GPIO_PF | 21)
 #define PB21_AF_UART5_RTS	(GPIO_PORTB | GPIO_IN  | GPIO_AF | 21)
+#define PB22_PF_USBH1_SUSP	(GPIO_PORTB | GPIO_PF | 22)
+#define PB23_PF_USB_PWR		(GPIO_PORTB | GPIO_PF | 23)
+#define PB24_PF_USB_OC_B	(GPIO_PORTB | GPIO_PF | 24)
+#define PB25_PF_USBH1_RCV	(GPIO_PORTB | GPIO_PF | 25)
+#define PB26_PF_USBH1_FS	(GPIO_PORTB | GPIO_PF | 26)
+#define PB27_PF_USBH1_OE_B	(GPIO_PORTB | GPIO_PF | 27)
+#define PB28_PF_USBH1_TXDM	(GPIO_PORTB | GPIO_PF | 28)
+#define PB29_PF_USBH1_TXDP	(GPIO_PORTB | GPIO_PF | 29)
+#define PB30_PF_USBH1_RXDM	(GPIO_PORTB | GPIO_PF | 30)
+#define PB31_PF_USBH1_RXDP	(GPIO_PORTB | GPIO_PF | 31)
 #define PB26_AF_UART4_RTS	(GPIO_PORTB | GPIO_IN  | GPIO_PF | 26)
 #define PB28_AF_UART4_TXD	(GPIO_PORTB | GPIO_OUT | GPIO_AF | 28)
 #define PB29_AF_UART4_CTS	(GPIO_PORTB | GPIO_OUT | GPIO_AF | 29)
@@ -335,8 +350,15 @@
 #define PD16_AIN_FEC_TX_ER	(GPIO_PORTD | GPIO_OUT | GPIO_AIN | 16)
 #define PD17_PF_I2C_DATA	(GPIO_PORTD | GPIO_OUT | GPIO_PF | 17)
 #define PD18_PF_I2C_CLK		(GPIO_PORTD | GPIO_OUT | GPIO_PF | 18)
+#define PD19_AF_USBH2_DATA4	(GPIO_PORTD | GPIO_AF | 19)
+#define PD20_AF_USBH2_DATA3	(GPIO_PORTD | GPIO_AF | 20)
+#define PD21_AF_USBH2_DATA6	(GPIO_PORTD | GPIO_AF | 21)
+#define PD22_AF_USBH2_DATA0	(GPIO_PORTD | GPIO_AF | 22)
+#define PD23_AF_USBH2_DATA2	(GPIO_PORTD | GPIO_AF | 23)
+#define PD24_AF_USBH2_DATA1	(GPIO_PORTD | GPIO_AF | 24)
 #define PD25_PF_CSPI1_RDY	(GPIO_PORTD | GPIO_OUT | GPIO_PF  | 25)
 #define PD26_PF_CSPI1_SS2	(GPIO_PORTD | GPIO_OUT | GPIO_PF  | 26)
+#define PD26_AF_USBH2_DATA5     (GPIO_PORTD | GPIO_AF | 26)
 #define PD27_PF_CSPI1_SS1	(GPIO_PORTD | GPIO_OUT | GPIO_PF  | 27)
 #define PD28_PF_CSPI1_SS0	(GPIO_PORTD | GPIO_OUT | GPIO_PF  | 28)
 #define PD29_PF_CSPI1_SCLK	(GPIO_PORTD | GPIO_OUT | GPIO_PF  | 29)
@@ -355,6 +377,8 @@
 #define PE13_PF_UART1_RXD	(GPIO_PORTE | GPIO_IN  | GPIO_PF | 13)
 #define PE14_PF_UART1_CTS	(GPIO_PORTE | GPIO_OUT | GPIO_PF | 14)
 #define PE15_PF_UART1_RTS	(GPIO_PORTE | GPIO_IN  | GPIO_PF | 15)
+#define PE16_AF_RTCK		(GPIO_PORTE | GPIO_OUT | GPIO_AF | 16)
+#define PE16_PF_RTCK		(GPIO_PORTE | GPIO_OUT | GPIO_PF | 16)
 #define PE18_AF_CSPI3_MISO	(GPIO_PORTE | GPIO_IN  | GPIO_AF | 18)
 #define PE21_AF_CSPI3_SS	(GPIO_PORTE | GPIO_OUT | GPIO_AF | 21)
 #define PE22_AF_CSPI3_MOSI	(GPIO_PORTE | GPIO_OUT | GPIO_AF | 22)
diff --git a/arch/arm/plat-mxc/include/mach/iomux-mx3.h b/arch/arm/plat-mxc/include/mach/iomux-mx3.h
index 7509e76..c9f39c2 100644
--- a/arch/arm/plat-mxc/include/mach/iomux-mx3.h
+++ b/arch/arm/plat-mxc/include/mach/iomux-mx3.h
@@ -491,6 +491,26 @@
 #define MX31_PIN_RTS1__RTS1		IOMUX_MODE(MX31_PIN_RTS1, IOMUX_CONFIG_FUNC)
 #define MX31_PIN_TXD1__TXD1		IOMUX_MODE(MX31_PIN_TXD1, IOMUX_CONFIG_FUNC)
 #define MX31_PIN_RXD1__RXD1		IOMUX_MODE(MX31_PIN_RXD1, IOMUX_CONFIG_FUNC)
+#define MX31_PIN_CSPI1_MOSI__MOSI	IOMUX_MODE(MX31_PIN_CSPI1_MOSI, IOMUX_CONFIG_FUNC)
+#define MX31_PIN_CSPI1_MISO__MISO	IOMUX_MODE(MX31_PIN_CSPI1_MISO, IOMUX_CONFIG_FUNC)
+#define MX31_PIN_CSPI1_SCLK__SCLK	IOMUX_MODE(MX31_PIN_CSPI1_SCLK, IOMUX_CONFIG_FUNC)
+#define MX31_PIN_CSPI1_SPI_RDY__SPI_RDY	IOMUX_MODE(MX31_PIN_CSPI1_SPI_RDY, IOMUX_CONFIG_FUNC)
+#define MX31_PIN_CSPI1_SS0__SS0		IOMUX_MODE(MX31_PIN_CSPI1_SS0, IOMUX_CONFIG_FUNC)
+#define MX31_PIN_CSPI1_SS1__SS1		IOMUX_MODE(MX31_PIN_CSPI1_SS1, IOMUX_CONFIG_FUNC)
+#define MX31_PIN_CSPI1_SS2__SS2		IOMUX_MODE(MX31_PIN_CSPI1_SS2, IOMUX_CONFIG_FUNC)
+#define MX31_PIN_CSPI2_MOSI__MOSI	IOMUX_MODE(MX31_PIN_CSPI2_MOSI, IOMUX_CONFIG_FUNC)
+#define MX31_PIN_CSPI2_MISO__MISO	IOMUX_MODE(MX31_PIN_CSPI2_MISO, IOMUX_CONFIG_FUNC)
+#define MX31_PIN_CSPI2_SCLK__SCLK	IOMUX_MODE(MX31_PIN_CSPI2_SCLK, IOMUX_CONFIG_FUNC)
+#define MX31_PIN_CSPI2_SPI_RDY__SPI_RDY	IOMUX_MODE(MX31_PIN_CSPI2_SPI_RDY, IOMUX_CONFIG_FUNC)
+#define MX31_PIN_CSPI2_SS0__SS0		IOMUX_MODE(MX31_PIN_CSPI2_SS0, IOMUX_CONFIG_FUNC)
+#define MX31_PIN_CSPI2_SS1__SS1		IOMUX_MODE(MX31_PIN_CSPI2_SS1, IOMUX_CONFIG_FUNC)
+#define MX31_PIN_CSPI2_SS2__SS2		IOMUX_MODE(MX31_PIN_CSPI2_SS2, IOMUX_CONFIG_FUNC)
+#define MX31_PIN_CSPI3_MOSI__MOSI	IOMUX_MODE(MX31_PIN_CSPI3_MOSI, IOMUX_CONFIG_FUNC)
+#define MX31_PIN_CSPI3_MISO__MISO	IOMUX_MODE(MX31_PIN_CSPI3_MISO, IOMUX_CONFIG_FUNC)
+#define MX31_PIN_CSPI3_SCLK__SCLK	IOMUX_MODE(MX31_PIN_CSPI3_SCLK, IOMUX_CONFIG_FUNC)
+#define MX31_PIN_CSPI3_SPI_RDY__SPI_RDY	IOMUX_MODE(MX31_PIN_CSPI3_SPI_RDY, IOMUX_CONFIG_FUNC)
+/*XXX: The SS0, SS1, SS2, SS3 lines of spi3 are multiplexed by cspi2_ss0, cspi2_ss1, cspi1_ss0
+ * cspi1_ss1*/
 
 /*
  * This function configures the pad value for a IOMUX pin.
diff --git a/arch/arm/plat-mxc/include/mach/irqs.h b/arch/arm/plat-mxc/include/mach/irqs.h
index 228c4f6..b55bba3 100644
--- a/arch/arm/plat-mxc/include/mach/irqs.h
+++ b/arch/arm/plat-mxc/include/mach/irqs.h
@@ -12,5 +12,6 @@
 #define __ASM_ARCH_MXC_IRQS_H__
 
 #include <mach/hardware.h>
+extern void imx_irq_set_priority(unsigned char irq, unsigned char prio);
 
 #endif /* __ASM_ARCH_MXC_IRQS_H__ */
diff --git a/arch/arm/plat-mxc/include/mach/mx27.h b/arch/arm/plat-mxc/include/mach/mx27.h
index 212ecc2..a86db64 100644
--- a/arch/arm/plat-mxc/include/mach/mx27.h
+++ b/arch/arm/plat-mxc/include/mach/mx27.h
@@ -128,6 +128,7 @@
  * it returns 0xDEADBEEF
  */
 #define IO_ADDRESS(x)   \
+	(void __iomem *) \
 	(((x >= AIPI_BASE_ADDR) && (x < (AIPI_BASE_ADDR + AIPI_SIZE))) ? \
 		AIPI_IO_ADDRESS(x) : \
 	((x >= SAHB1_BASE_ADDR) && (x < (SAHB1_BASE_ADDR + SAHB1_SIZE))) ? \
diff --git a/arch/arm/plat-mxc/include/mach/mx31.h b/arch/arm/plat-mxc/include/mach/mx31.h
index a7373e4..0536f89 100644
--- a/arch/arm/plat-mxc/include/mach/mx31.h
+++ b/arch/arm/plat-mxc/include/mach/mx31.h
@@ -198,6 +198,7 @@
  * it returns 0xDEADBEEF
  */
 #define IO_ADDRESS(x)   \
+	(void __iomem *) \
 	(((x >= IRAM_BASE_ADDR) && (x < (IRAM_BASE_ADDR + IRAM_SIZE))) ? IRAM_IO_ADDRESS(x):\
 	((x >= L2CC_BASE_ADDR) && (x < (L2CC_BASE_ADDR + L2CC_SIZE))) ? L2CC_IO_ADDRESS(x):\
 	((x >= AIPS1_BASE_ADDR) && (x < (AIPS1_BASE_ADDR + AIPS1_SIZE))) ? AIPS1_IO_ADDRESS(x):\
diff --git a/arch/arm/plat-mxc/include/mach/mxc.h b/arch/arm/plat-mxc/include/mach/mxc.h
index 332eda4..f6caab0 100644
--- a/arch/arm/plat-mxc/include/mach/mxc.h
+++ b/arch/arm/plat-mxc/include/mach/mxc.h
@@ -33,4 +33,10 @@
 # define cpu_is_mx27() (0)
 #endif
 
+#if defined(CONFIG_ARCH_MX3) || defined(CONFIG_ARCH_MX2)
+#define CSCR_U(n) (IO_ADDRESS(WEIM_BASE_ADDR) + n * 0x10)
+#define CSCR_L(n) (IO_ADDRESS(WEIM_BASE_ADDR) + n * 0x10 + 0x4)
+#define CSCR_A(n) (IO_ADDRESS(WEIM_BASE_ADDR) + n * 0x10 + 0x8)
+#endif
+
 #endif /*  __ASM_ARCH_MXC_H__ */
diff --git a/arch/arm/plat-mxc/irq.c b/arch/arm/plat-mxc/irq.c
index 1053b66..d862c9e 100644
--- a/arch/arm/plat-mxc/irq.c
+++ b/arch/arm/plat-mxc/irq.c
@@ -18,7 +18,7 @@
  */
 
 #include <linux/irq.h>
-#include <asm/io.h>
+#include <linux/io.h>
 #include <mach/common.h>
 
 #define AVIC_BASE		IO_ADDRESS(AVIC_BASE_ADDR)
@@ -30,14 +30,7 @@
 #define AVIC_INTENABLEL		(AVIC_BASE + 0x14)	/* int enable reg low */
 #define AVIC_INTTYPEH		(AVIC_BASE + 0x18)	/* int type reg high */
 #define AVIC_INTTYPEL		(AVIC_BASE + 0x1C)	/* int type reg low */
-#define AVIC_NIPRIORITY7	(AVIC_BASE + 0x20)	/* norm int priority lvl7 */
-#define AVIC_NIPRIORITY6	(AVIC_BASE + 0x24)	/* norm int priority lvl6 */
-#define AVIC_NIPRIORITY5	(AVIC_BASE + 0x28)	/* norm int priority lvl5 */
-#define AVIC_NIPRIORITY4	(AVIC_BASE + 0x2C)	/* norm int priority lvl4 */
-#define AVIC_NIPRIORITY3	(AVIC_BASE + 0x30)	/* norm int priority lvl3 */
-#define AVIC_NIPRIORITY2	(AVIC_BASE + 0x34)	/* norm int priority lvl2 */
-#define AVIC_NIPRIORITY1	(AVIC_BASE + 0x38)	/* norm int priority lvl1 */
-#define AVIC_NIPRIORITY0	(AVIC_BASE + 0x3C)	/* norm int priority lvl0 */
+#define AVIC_NIPRIORITY(x)	(AVIC_BASE + (0x20 + 4 * (7 - (x)))) /* int priority */
 #define AVIC_NIVECSR		(AVIC_BASE + 0x40)	/* norm int vector/status */
 #define AVIC_FIVECSR		(AVIC_BASE + 0x44)	/* fast int vector/status */
 #define AVIC_INTSRCH		(AVIC_BASE + 0x48)	/* int source reg high */
@@ -54,6 +47,24 @@
 #define IIM_PROD_REV_SH		3
 #define IIM_PROD_REV_LEN	5
 
+#ifdef CONFIG_MXC_IRQ_PRIOR
+void imx_irq_set_priority(unsigned char irq, unsigned char prio)
+{
+	unsigned int temp;
+	unsigned int mask = 0x0F << irq % 8 * 4;
+
+	if (irq > 63)
+		return;
+
+	temp = __raw_readl(AVIC_NIPRIORITY(irq / 8));
+	temp &= ~mask;
+	temp |= prio & mask;
+
+	__raw_writel(temp, AVIC_NIPRIORITY(irq / 8));
+}
+EXPORT_SYMBOL(imx_irq_set_priority);
+#endif
+
 /* Disable interrupt number "irq" in the AVIC */
 static void mxc_mask_irq(unsigned int irq)
 {
@@ -101,10 +112,9 @@
 		set_irq_flags(i, IRQF_VALID);
 	}
 
-	/* Set WDOG2's interrupt the highest priority level (bit 28-31) */
-	reg = __raw_readl(AVIC_NIPRIORITY6);
-	reg |= (0xF << 28);
-	__raw_writel(reg, AVIC_NIPRIORITY6);
+	/* Set default priority value (0) for all IRQ's */
+	for (i = 0; i < 8; i++)
+		__raw_writel(0, AVIC_NIPRIORITY(i));
 
 	/* init architectures chained interrupt handler */
 	mxc_register_gpios();
diff --git a/arch/arm/plat-omap/clock.c b/arch/arm/plat-omap/clock.c
index 197974d..bf6a10c 100644
--- a/arch/arm/plat-omap/clock.c
+++ b/arch/arm/plat-omap/clock.c
@@ -22,8 +22,7 @@
 #include <linux/platform_device.h>
 #include <linux/cpufreq.h>
 #include <linux/debugfs.h>
-
-#include <asm/io.h>
+#include <linux/io.h>
 
 #include <mach/clock.h>
 
diff --git a/arch/arm/plat-omap/common.c b/arch/arm/plat-omap/common.c
index f4dff42..8bdf0ea 100644
--- a/arch/arm/plat-omap/common.c
+++ b/arch/arm/plat-omap/common.c
@@ -18,12 +18,12 @@
 #include <linux/serial_8250.h>
 #include <linux/serial_reg.h>
 #include <linux/clk.h>
+#include <linux/io.h>
 
 #include <mach/hardware.h>
 #include <asm/system.h>
 #include <asm/pgtable.h>
 #include <asm/mach/map.h>
-#include <asm/io.h>
 #include <asm/setup.h>
 
 #include <mach/common.h>
diff --git a/arch/arm/plat-omap/cpu-omap.c b/arch/arm/plat-omap/cpu-omap.c
index ae1de30..b269024 100644
--- a/arch/arm/plat-omap/cpu-omap.c
+++ b/arch/arm/plat-omap/cpu-omap.c
@@ -20,9 +20,9 @@
 #include <linux/init.h>
 #include <linux/err.h>
 #include <linux/clk.h>
+#include <linux/io.h>
 
 #include <mach/hardware.h>
-#include <asm/io.h>
 #include <asm/system.h>
 
 #define VERY_HI_RATE	900000000
diff --git a/arch/arm/plat-omap/debug-devices.c b/arch/arm/plat-omap/debug-devices.c
index 5b73bb2..e31154b 100644
--- a/arch/arm/plat-omap/debug-devices.c
+++ b/arch/arm/plat-omap/debug-devices.c
@@ -12,9 +12,9 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/platform_device.h>
+#include <linux/io.h>
 
 #include <mach/hardware.h>
-#include <asm/io.h>
 
 #include <mach/board.h>
 #include <mach/gpio.h>
diff --git a/arch/arm/plat-omap/debug-leds.c b/arch/arm/plat-omap/debug-leds.c
index 9422dee..2f4c0ca 100644
--- a/arch/arm/plat-omap/debug-leds.c
+++ b/arch/arm/plat-omap/debug-leds.c
@@ -11,8 +11,8 @@
 #include <linux/init.h>
 #include <linux/platform_device.h>
 #include <linux/leds.h>
+#include <linux/io.h>
 
-#include <asm/io.h>
 #include <mach/hardware.h>
 #include <asm/leds.h>
 #include <asm/system.h>
diff --git a/arch/arm/plat-omap/devices.c b/arch/arm/plat-omap/devices.c
index bc1cf30..97187fa 100644
--- a/arch/arm/plat-omap/devices.c
+++ b/arch/arm/plat-omap/devices.c
@@ -13,9 +13,9 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/platform_device.h>
+#include <linux/io.h>
 
 #include <mach/hardware.h>
-#include <asm/io.h>
 #include <asm/mach-types.h>
 #include <asm/mach/map.h>
 
@@ -316,19 +316,6 @@
 				omap_cfg_reg(MMC_DAT3);
 			}
 		}
-#if defined(CONFIG_ARCH_OMAP2420)
-		if (mmc_conf->mmc[0].internal_clock) {
-			/*
-			 * Use internal loop-back in MMC/SDIO
-			 * Module Input Clock selection
-			 */
-			if (cpu_is_omap24xx()) {
-				u32 v = omap_ctrl_readl(OMAP2_CONTROL_DEVCONF0);
-				v |= (1 << 24); /* not used in 243x */
-				omap_ctrl_writel(v, OMAP2_CONTROL_DEVCONF0);
-			}
-		}
-#endif
 	}
 
 #ifdef	CONFIG_ARCH_OMAP16XX
@@ -454,16 +441,8 @@
 
 #if	defined(CONFIG_OMAP_WATCHDOG) || defined(CONFIG_OMAP_WATCHDOG_MODULE)
 
-#ifdef CONFIG_ARCH_OMAP24XX
-#define	OMAP_WDT_BASE		0x48022000
-#else
-#define	OMAP_WDT_BASE		0xfffeb000
-#endif
-
 static struct resource wdt_resources[] = {
 	{
-		.start		= OMAP_WDT_BASE,
-		.end		= OMAP_WDT_BASE + 0x4f,
 		.flags		= IORESOURCE_MEM,
 	},
 };
@@ -477,6 +456,19 @@
 
 static void omap_init_wdt(void)
 {
+	if (cpu_is_omap16xx())
+		wdt_resources[0].start = 0xfffeb000;
+	else if (cpu_is_omap2420())
+		wdt_resources[0].start = 0x48022000; /* WDT2 */
+	else if (cpu_is_omap2430())
+		wdt_resources[0].start = 0x49016000; /* WDT2 */
+	else if (cpu_is_omap343x())
+		wdt_resources[0].start = 0x48314000; /* WDT2 */
+	else
+		return;
+
+	wdt_resources[0].end = wdt_resources[0].start + 0x4f;
+
 	(void) platform_device_register(&omap_wdt_device);
 }
 #else
diff --git a/arch/arm/plat-omap/dmtimer.c b/arch/arm/plat-omap/dmtimer.c
index 743a4ab..606fcff 100644
--- a/arch/arm/plat-omap/dmtimer.c
+++ b/arch/arm/plat-omap/dmtimer.c
@@ -32,9 +32,9 @@
 #include <linux/list.h>
 #include <linux/clk.h>
 #include <linux/delay.h>
+#include <linux/io.h>
 #include <mach/hardware.h>
 #include <mach/dmtimer.h>
-#include <asm/io.h>
 #include <mach/irqs.h>
 
 /* register offsets */
diff --git a/arch/arm/plat-omap/fb.c b/arch/arm/plat-omap/fb.c
index 17a92a3..ce6b4ba 100644
--- a/arch/arm/plat-omap/fb.c
+++ b/arch/arm/plat-omap/fb.c
@@ -27,9 +27,9 @@
 #include <linux/init.h>
 #include <linux/platform_device.h>
 #include <linux/bootmem.h>
+#include <linux/io.h>
 
 #include <mach/hardware.h>
-#include <asm/io.h>
 #include <asm/mach/map.h>
 
 #include <mach/board.h>
diff --git a/arch/arm/plat-omap/gpio.c b/arch/arm/plat-omap/gpio.c
index 9e1341e..5935ae4 100644
--- a/arch/arm/plat-omap/gpio.c
+++ b/arch/arm/plat-omap/gpio.c
@@ -17,6 +17,7 @@
 #include <linux/sysdev.h>
 #include <linux/err.h>
 #include <linux/clk.h>
+#include <linux/io.h>
 
 #include <mach/hardware.h>
 #include <asm/irq.h>
@@ -24,8 +25,6 @@
 #include <mach/gpio.h>
 #include <asm/mach/irq.h>
 
-#include <asm/io.h>
-
 /*
  * OMAP1510 GPIO registers
  */
@@ -1051,13 +1050,10 @@
 
 		gpio_irq = bank->virtual_irq_start;
 		for (; isr != 0; isr >>= 1, gpio_irq++) {
-			struct irq_desc *d;
-
 			if (!(isr & 1))
 				continue;
-			d = irq_desc + gpio_irq;
 
-			desc_handle_irq(gpio_irq, d);
+			generic_handle_irq(gpio_irq);
 		}
 	}
 	/* if bank has any level sensitive GPIO pin interrupt
diff --git a/arch/arm/plat-omap/include/mach/gpio.h b/arch/arm/plat-omap/include/mach/gpio.h
index 94ce278..8c71e28 100644
--- a/arch/arm/plat-omap/include/mach/gpio.h
+++ b/arch/arm/plat-omap/include/mach/gpio.h
@@ -26,8 +26,8 @@
 #ifndef __ASM_ARCH_OMAP_GPIO_H
 #define __ASM_ARCH_OMAP_GPIO_H
 
+#include <linux/io.h>
 #include <mach/irqs.h>
-#include <asm/io.h>
 
 #define OMAP_MPUIO_BASE			(void __iomem *)0xfffb5000
 
diff --git a/arch/arm/plat-omap/include/mach/irqs.h b/arch/arm/plat-omap/include/mach/irqs.h
index 17248bb..62aa7df 100644
--- a/arch/arm/plat-omap/include/mach/irqs.h
+++ b/arch/arm/plat-omap/include/mach/irqs.h
@@ -280,6 +280,8 @@
 #define INT_24XX_USB_IRQ_OTG	80
 #define INT_24XX_MMC_IRQ	83
 
+#define	INT_34XX_BENCH_MPU_EMUL	3
+
 /* Max. 128 level 2 IRQs (OMAP1610), 192 GPIOs (OMAP730) and
  * 16 MPUIO lines */
 #define OMAP_MAX_GPIO_LINES	192
diff --git a/arch/arm/plat-omap/include/mach/mtd-xip.h b/arch/arm/plat-omap/include/mach/mtd-xip.h
index 5cee7e1..39b591f 100644
--- a/arch/arm/plat-omap/include/mach/mtd-xip.h
+++ b/arch/arm/plat-omap/include/mach/mtd-xip.h
@@ -3,7 +3,7 @@
  *
  * Do not include this file directly. It's included from linux/mtd/xip.h
  *
- * Author: Vladimir Barinov <vbarinov@ru.mvista.com>
+ * Author: Vladimir Barinov <vbarinov@embeddedalley.com>
  *
  * (c) 2005 MontaVista Software, Inc.  This file is licensed under the
  * terms of the GNU General Public License version 2.  This program is
diff --git a/arch/arm/plat-omap/mailbox.c b/arch/arm/plat-omap/mailbox.c
index 1d7aec1..b52ce05 100644
--- a/arch/arm/plat-omap/mailbox.c
+++ b/arch/arm/plat-omap/mailbox.c
@@ -30,7 +30,7 @@
 #include <linux/blkdev.h>
 #include <linux/err.h>
 #include <linux/delay.h>
-#include <asm/io.h>
+#include <linux/io.h>
 #include <mach/mailbox.h>
 #include "mailbox.h"
 
diff --git a/arch/arm/plat-omap/mux.c b/arch/arm/plat-omap/mux.c
index 847df20..80b040f 100644
--- a/arch/arm/plat-omap/mux.c
+++ b/arch/arm/plat-omap/mux.c
@@ -25,8 +25,8 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
+#include <linux/io.h>
 #include <asm/system.h>
-#include <asm/io.h>
 #include <linux/spinlock.h>
 #include <mach/mux.h>
 
diff --git a/arch/arm/plat-omap/ocpi.c b/arch/arm/plat-omap/ocpi.c
index 8bdbf97..ebe0c73 100644
--- a/arch/arm/plat-omap/ocpi.c
+++ b/arch/arm/plat-omap/ocpi.c
@@ -31,8 +31,8 @@
 #include <linux/spinlock.h>
 #include <linux/err.h>
 #include <linux/clk.h>
+#include <linux/io.h>
 
-#include <asm/io.h>
 #include <mach/hardware.h>
 
 #define OCPI_BASE		0xfffec320
diff --git a/arch/arm/plat-omap/sram.c b/arch/arm/plat-omap/sram.c
index ac67eeb..e0003e0 100644
--- a/arch/arm/plat-omap/sram.c
+++ b/arch/arm/plat-omap/sram.c
@@ -15,9 +15,9 @@
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
+#include <linux/io.h>
 
 #include <asm/tlb.h>
-#include <asm/io.h>
 #include <asm/cacheflush.h>
 
 #include <asm/mach/map.h>
diff --git a/arch/arm/plat-omap/usb.c b/arch/arm/plat-omap/usb.c
index 777485e..67ca1e2 100644
--- a/arch/arm/plat-omap/usb.c
+++ b/arch/arm/plat-omap/usb.c
@@ -27,8 +27,8 @@
 #include <linux/init.h>
 #include <linux/platform_device.h>
 #include <linux/usb/otg.h>
+#include <linux/io.h>
 
-#include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/system.h>
 #include <mach/hardware.h>
diff --git a/arch/arm/plat-s3c24xx/clock.c b/arch/arm/plat-s3c24xx/clock.c
index 54d4b8e..4005413 100644
--- a/arch/arm/plat-s3c24xx/clock.c
+++ b/arch/arm/plat-s3c24xx/clock.c
@@ -39,10 +39,10 @@
 #include <linux/clk.h>
 #include <linux/mutex.h>
 #include <linux/delay.h>
+#include <linux/io.h>
 
 #include <mach/hardware.h>
 #include <asm/irq.h>
-#include <asm/io.h>
 
 #include <mach/regs-clock.h>
 #include <mach/regs-gpio.h>
diff --git a/arch/arm/plat-s3c24xx/common-smdk.c b/arch/arm/plat-s3c24xx/common-smdk.c
index 1863a1b..d528f46 100644
--- a/arch/arm/plat-s3c24xx/common-smdk.c
+++ b/arch/arm/plat-s3c24xx/common-smdk.c
@@ -25,6 +25,7 @@
 #include <linux/mtd/nand.h>
 #include <linux/mtd/nand_ecc.h>
 #include <linux/mtd/partitions.h>
+#include <linux/io.h>
 
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
@@ -32,7 +33,6 @@
 
 #include <asm/mach-types.h>
 #include <mach/hardware.h>
-#include <asm/io.h>
 #include <asm/irq.h>
 
 #include <mach/regs-gpio.h>
diff --git a/arch/arm/plat-s3c24xx/cpu.c b/arch/arm/plat-s3c24xx/cpu.c
index 89ce60e..9c607bb 100644
--- a/arch/arm/plat-s3c24xx/cpu.c
+++ b/arch/arm/plat-s3c24xx/cpu.c
@@ -29,11 +29,11 @@
 #include <linux/serial_core.h>
 #include <linux/platform_device.h>
 #include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/delay.h>
 
 #include <mach/hardware.h>
 #include <asm/irq.h>
-#include <asm/io.h>
-#include <asm/delay.h>
 #include <asm/cacheflush.h>
 
 #include <asm/mach/arch.h>
diff --git a/arch/arm/plat-s3c24xx/devs.c b/arch/arm/plat-s3c24xx/devs.c
index d6fb765..6b13b54 100644
--- a/arch/arm/plat-s3c24xx/devs.c
+++ b/arch/arm/plat-s3c24xx/devs.c
@@ -19,13 +19,13 @@
 #include <linux/init.h>
 #include <linux/serial_core.h>
 #include <linux/platform_device.h>
+#include <linux/io.h>
 
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
 #include <asm/mach/irq.h>
 #include <mach/fb.h>
 #include <mach/hardware.h>
-#include <asm/io.h>
 #include <asm/irq.h>
 
 #include <asm/plat-s3c/regs-serial.h>
diff --git a/arch/arm/plat-s3c24xx/dma.c b/arch/arm/plat-s3c24xx/dma.c
index 08c2aaf..d634446 100644
--- a/arch/arm/plat-s3c24xx/dma.c
+++ b/arch/arm/plat-s3c24xx/dma.c
@@ -26,11 +26,11 @@
 #include <linux/slab.h>
 #include <linux/errno.h>
 #include <linux/delay.h>
+#include <linux/io.h>
 
 #include <asm/system.h>
 #include <asm/irq.h>
 #include <mach/hardware.h>
-#include <asm/io.h>
 #include <asm/dma.h>
 
 #include <asm/mach/dma.h>
diff --git a/arch/arm/plat-s3c24xx/gpio.c b/arch/arm/plat-s3c24xx/gpio.c
index dd27334..4a899c2 100644
--- a/arch/arm/plat-s3c24xx/gpio.c
+++ b/arch/arm/plat-s3c24xx/gpio.c
@@ -26,10 +26,10 @@
 #include <linux/module.h>
 #include <linux/interrupt.h>
 #include <linux/ioport.h>
+#include <linux/io.h>
 
 #include <mach/hardware.h>
 #include <asm/irq.h>
-#include <asm/io.h>
 
 #include <mach/regs-gpio.h>
 
diff --git a/arch/arm/plat-s3c24xx/irq.c b/arch/arm/plat-s3c24xx/irq.c
index 36cefe1..590fc5a 100644
--- a/arch/arm/plat-s3c24xx/irq.c
+++ b/arch/arm/plat-s3c24xx/irq.c
@@ -55,10 +55,10 @@
 #include <linux/interrupt.h>
 #include <linux/ioport.h>
 #include <linux/sysdev.h>
+#include <linux/io.h>
 
 #include <mach/hardware.h>
 #include <asm/irq.h>
-#include <asm/io.h>
 
 #include <asm/mach/irq.h>
 
@@ -468,7 +468,6 @@
 {
 	unsigned int subsrc, submsk;
 	unsigned int offset = 9;
-	struct irq_desc *mydesc;
 
 	/* read the current pending interrupts, and the mask
 	 * for what it is available */
@@ -482,12 +481,10 @@
 
 	if (subsrc != 0) {
 		if (subsrc & 1) {
-			mydesc = irq_desc + IRQ_TC;
-			desc_handle_irq(IRQ_TC, mydesc);
+			generic_handle_irq(IRQ_TC);
 		}
 		if (subsrc & 2) {
-			mydesc = irq_desc + IRQ_ADC;
-			desc_handle_irq(IRQ_ADC, mydesc);
+			generic_handle_irq(IRQ_ADC);
 		}
 	}
 }
@@ -496,7 +493,6 @@
 {
 	unsigned int subsrc, submsk;
 	unsigned int offset = start - IRQ_S3CUART_RX0;
-	struct irq_desc *desc;
 
 	/* read the current pending interrupts, and the mask
 	 * for what it is available */
@@ -512,20 +508,14 @@
 	subsrc &= 7;
 
 	if (subsrc != 0) {
-		desc = irq_desc + start;
-
 		if (subsrc & 1)
-			desc_handle_irq(start, desc);
-
-		desc++;
+			generic_handle_irq(start);
 
 		if (subsrc & 2)
-			desc_handle_irq(start+1, desc);
-
-		desc++;
+			generic_handle_irq(start+1);
 
 		if (subsrc & 4)
-			desc_handle_irq(start+2, desc);
+			generic_handle_irq(start+2);
 	}
 }
 
@@ -572,7 +562,7 @@
 		eintpnd &= ~(1<<irq);
 
 		irq += (IRQ_EINT4 - 4);
-		desc_handle_irq(irq, irq_desc + irq);
+		generic_handle_irq(irq);
 	}
 
 }
@@ -595,7 +585,7 @@
 
 		irq += (IRQ_EINT4 - 4);
 
-		desc_handle_irq(irq, irq_desc + irq);
+		generic_handle_irq(irq);
 	}
 }
 
diff --git a/arch/arm/plat-s3c24xx/pm-simtec.c b/arch/arm/plat-s3c24xx/pm-simtec.c
index e670501..0a074d3 100644
--- a/arch/arm/plat-s3c24xx/pm-simtec.c
+++ b/arch/arm/plat-s3c24xx/pm-simtec.c
@@ -20,12 +20,12 @@
 #include <linux/init.h>
 #include <linux/sysdev.h>
 #include <linux/device.h>
+#include <linux/io.h>
 
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
 
 #include <mach/hardware.h>
-#include <asm/io.h>
 
 #include <mach/map.h>
 #include <mach/regs-gpio.h>
diff --git a/arch/arm/plat-s3c24xx/pm.c b/arch/arm/plat-s3c24xx/pm.c
index fc4b731..d3934b1 100644
--- a/arch/arm/plat-s3c24xx/pm.c
+++ b/arch/arm/plat-s3c24xx/pm.c
@@ -35,10 +35,10 @@
 #include <linux/ioport.h>
 #include <linux/delay.h>
 #include <linux/serial_core.h>
+#include <linux/io.h>
 
 #include <asm/cacheflush.h>
 #include <mach/hardware.h>
-#include <asm/io.h>
 
 #include <asm/plat-s3c/regs-serial.h>
 #include <mach/regs-clock.h>
diff --git a/arch/arm/plat-s3c24xx/s3c244x-clock.c b/arch/arm/plat-s3c24xx/s3c244x-clock.c
index 8a5fffd..119647a 100644
--- a/arch/arm/plat-s3c24xx/s3c244x-clock.c
+++ b/arch/arm/plat-s3c24xx/s3c244x-clock.c
@@ -33,11 +33,11 @@
 #include <linux/ioport.h>
 #include <linux/mutex.h>
 #include <linux/clk.h>
+#include <linux/io.h>
 
 #include <mach/hardware.h>
 #include <asm/atomic.h>
 #include <asm/irq.h>
-#include <asm/io.h>
 
 #include <mach/regs-clock.h>
 
diff --git a/arch/arm/plat-s3c24xx/s3c244x-irq.c b/arch/arm/plat-s3c24xx/s3c244x-irq.c
index f3dc38c..0601c5f 100644
--- a/arch/arm/plat-s3c24xx/s3c244x-irq.c
+++ b/arch/arm/plat-s3c24xx/s3c244x-irq.c
@@ -24,10 +24,10 @@
 #include <linux/interrupt.h>
 #include <linux/ioport.h>
 #include <linux/sysdev.h>
+#include <linux/io.h>
 
 #include <mach/hardware.h>
 #include <asm/irq.h>
-#include <asm/io.h>
 
 #include <asm/mach/irq.h>
 
@@ -44,7 +44,6 @@
 			      struct irq_desc *desc)
 {
 	unsigned int subsrc, submsk;
-	struct irq_desc *mydesc;
 
 	/* read the current pending interrupts, and the mask
 	 * for what it is available */
@@ -58,12 +57,10 @@
 
 	if (subsrc != 0) {
 		if (subsrc & 1) {
-			mydesc = irq_desc + IRQ_S3C2440_CAM_C;
-			desc_handle_irq(IRQ_S3C2440_CAM_C, mydesc);
+			generic_handle_irq(IRQ_S3C2440_CAM_C);
 		}
 		if (subsrc & 2) {
-			mydesc = irq_desc + IRQ_S3C2440_CAM_P;
-			desc_handle_irq(IRQ_S3C2440_CAM_P, mydesc);
+			generic_handle_irq(IRQ_S3C2440_CAM_P);
 		}
 	}
 }
diff --git a/arch/arm/plat-s3c24xx/s3c244x.c b/arch/arm/plat-s3c24xx/s3c244x.c
index 281b480..146863a 100644
--- a/arch/arm/plat-s3c24xx/s3c244x.c
+++ b/arch/arm/plat-s3c24xx/s3c244x.c
@@ -20,13 +20,13 @@
 #include <linux/platform_device.h>
 #include <linux/sysdev.h>
 #include <linux/clk.h>
+#include <linux/io.h>
 
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
 #include <asm/mach/irq.h>
 
 #include <mach/hardware.h>
-#include <asm/io.h>
 #include <asm/irq.h>
 
 #include <mach/regs-clock.h>
diff --git a/arch/arm/plat-s3c24xx/time.c b/arch/arm/plat-s3c24xx/time.c
index b471a21..64bfa19 100644
--- a/arch/arm/plat-s3c24xx/time.c
+++ b/arch/arm/plat-s3c24xx/time.c
@@ -25,12 +25,12 @@
 #include <linux/irq.h>
 #include <linux/err.h>
 #include <linux/clk.h>
+#include <linux/io.h>
 
 #include <asm/system.h>
 #include <asm/leds.h>
 #include <asm/mach-types.h>
 
-#include <asm/io.h>
 #include <asm/irq.h>
 #include <mach/map.h>
 #include <asm/plat-s3c/regs-timer.h>
diff --git a/arch/arm/tools/mach-types b/arch/arm/tools/mach-types
index 56281c0..43aa202 100644
--- a/arch/arm/tools/mach-types
+++ b/arch/arm/tools/mach-types
@@ -12,7 +12,7 @@
 #
 #   http://www.arm.linux.org.uk/developer/machines/?action=new
 #
-# Last update: Wed Aug 13 21:56:02 2008
+# Last update: Thu Sep 25 10:10:50 2008
 #
 # machine_is_xxx	CONFIG_xxxx		MACH_TYPE_xxx		number
 #
@@ -1810,7 +1810,7 @@
 pilz_pmi5		MACH_PILZ_PMI5		PILZ_PMI5		1820
 jade			MACH_JADE		JADE			1821
 ks8695_softplc		MACH_KS8695_SOFTPLC	KS8695_SOFTPLC		1822
-gprisc3			MACH_GPRISC4		GPRISC4			1823
+gprisc3			MACH_GPRISC3		GPRISC3			1823
 stamp9260		MACH_STAMP9260		STAMP9260		1824
 smdk6430		MACH_SMDK6430		SMDK6430		1825
 smdkc100		MACH_SMDKC100		SMDKC100		1826
@@ -1859,5 +1859,43 @@
 ginza			MACH_GINZA		GINZA			1869
 a636n			MACH_A636N		A636N			1870
 imx27ipcam		MACH_IMX27IPCAM		IMX27IPCAM		1871
-nenoc			MACH_NEMOC		NEMOC			1872
+nemoc			MACH_NEMOC		NEMOC			1872
 geneva			MACH_GENEVA		GENEVA			1873
+htcpharos		MACH_HTCPHAROS		HTCPHAROS		1874
+neonc			MACH_NEONC		NEONC			1875
+nas7100			MACH_NAS7100		NAS7100			1876
+teuphone		MACH_TEUPHONE		TEUPHONE		1877
+annax_eth2		MACH_ANNAX_ETH2		ANNAX_ETH2		1878
+csb733			MACH_CSB733		CSB733			1879
+bk3			MACH_BK3		BK3			1880
+omap_em32		MACH_OMAP_EM32		OMAP_EM32		1881
+et9261cp		MACH_ET9261CP		ET9261CP		1882
+jasperc			MACH_JASPERC		JASPERC			1883
+issi_arm9		MACH_ISSI_ARM9		ISSI_ARM9		1884
+ued			MACH_UED		UED			1885
+esiblade		MACH_ESIBLADE		ESIBLADE		1886
+eye02			MACH_EYE02		EYE02			1887
+imx27kbd		MACH_IMX27KBD		IMX27KBD		1888
+sst61vc010_fpga		MACH_SST61VC010_FPGA	SST61VC010_FPGA		1889
+kixvp435		MACH_KIXVP435		KIXVP435		1890
+kixnp435		MACH_KIXNP435		KIXNP435		1891
+africa			MACH_AFRICA		AFRICA			1892
+nh233			MACH_NH233		NH233			1893
+rd88f6183ap_ge		MACH_RD88F6183AP_GE	RD88F6183AP_GE		1894
+bcm4760			MACH_BCM4760		BCM4760			1895
+eddy_v2			MACH_EDDY_V2		EDDY_V2			1896
+realview_pba8		MACH_REALVIEW_PBA8	REALVIEW_PBA8		1897
+hid_a7			MACH_HID_A7		HID_A7			1898
+hero			MACH_HERO		HERO			1899
+omap_poseidon		MACH_OMAP_POSEIDON	OMAP_POSEIDON		1900
+realview_pbx		MACH_REALVIEW_PBX	REALVIEW_PBX		1901
+micro9s			MACH_MICRO9S		MICRO9S			1902
+mako			MACH_MAKO		MAKO			1903
+xdaflame		MACH_XDAFLAME		XDAFLAME		1904
+phidget_sbc2		MACH_PHIDGET_SBC2	PHIDGET_SBC2		1905
+limestone		MACH_LIMESTONE		LIMESTONE		1906
+iprobe_c32		MACH_IPROBE_C32		IPROBE_C32		1907
+rut100			MACH_RUT100		RUT100			1908
+asusp535		MACH_ASUSP535		ASUSP535		1909
+htcraphael		MACH_HTCRAPHAEL		HTCRAPHAEL		1910
+sygdg1			MACH_SYGDG1		SYGDG1			1911
diff --git a/arch/arm/vfp/entry.S b/arch/arm/vfp/entry.S
index 806ce26..ba592a9 100644
--- a/arch/arm/vfp/entry.S
+++ b/arch/arm/vfp/entry.S
@@ -21,13 +21,13 @@
 #include <asm/assembler.h>
 #include <asm/vfpmacros.h>
 
-	.globl	do_vfp
-do_vfp:
+ENTRY(do_vfp)
 	enable_irq
  	ldr	r4, .LCvfp
 	ldr	r11, [r10, #TI_CPU]	@ CPU number
 	add	r10, r10, #TI_VFPSTATE	@ r10 = workspace
 	ldr	pc, [r4]		@ call VFP entry point
+ENDPROC(do_vfp)
 
 ENTRY(vfp_null_entry)
 	mov	pc, lr
@@ -40,11 +40,11 @@
 @ failure to the VFP initialisation code.
 
 	__INIT
-	.globl	vfp_testing_entry
-vfp_testing_entry:
+ENTRY(vfp_testing_entry)
 	ldr	r0, VFP_arch_address
 	str	r5, [r0]		@ known non-zero value
 	mov	pc, r9			@ we have handled the fault
+ENDPROC(vfp_testing_entry)
 
 VFP_arch_address:
 	.word	VFP_arch
diff --git a/arch/arm/vfp/vfphw.S b/arch/arm/vfp/vfphw.S
index 353f9e5..a62dcf7 100644
--- a/arch/arm/vfp/vfphw.S
+++ b/arch/arm/vfp/vfphw.S
@@ -68,8 +68,7 @@
 @  r11 = CPU number
 @  lr  = failure return
 
-	.globl	vfp_support_entry
-vfp_support_entry:
+ENTRY(vfp_support_entry)
 	DBGSTR3	"instr %08x pc %08x state %p", r0, r2, r10
 
 	VFPFMRX	r1, FPEXC		@ Is the VFP enabled?
@@ -165,11 +164,10 @@
 					@ code will raise an exception if
 					@ required. If not, the user code will
 					@ retry the faulted instruction
+ENDPROC(vfp_support_entry)
 
 #ifdef CONFIG_SMP
-	.globl	vfp_save_state
-	.type	vfp_save_state, %function
-vfp_save_state:
+ENTRY(vfp_save_state)
 	@ Save the current VFP state
 	@ r0 - save location
 	@ r1 - FPEXC
@@ -182,13 +180,13 @@
 	VFPFMRX	r12, FPINST2, NE	@ FPINST2 if needed (and present)
 	stmia	r0, {r1, r2, r3, r12}	@ save FPEXC, FPSCR, FPINST, FPINST2
 	mov	pc, lr
+ENDPROC(vfp_save_state)
 #endif
 
 last_VFP_context_address:
 	.word	last_VFP_context
 
-	.globl	vfp_get_float
-vfp_get_float:
+ENTRY(vfp_get_float)
 	add	pc, pc, r0, lsl #3
 	mov	r0, r0
 	.irp	dr,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
@@ -197,9 +195,9 @@
 	mrc	p10, 0, r0, c\dr, c0, 4	@ fmrs	r0, s1
 	mov	pc, lr
 	.endr
+ENDPROC(vfp_get_float)
 
-	.globl	vfp_put_float
-vfp_put_float:
+ENTRY(vfp_put_float)
 	add	pc, pc, r1, lsl #3
 	mov	r0, r0
 	.irp	dr,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
@@ -208,9 +206,9 @@
 	mcr	p10, 0, r0, c\dr, c0, 4	@ fmsr	r0, s1
 	mov	pc, lr
 	.endr
+ENDPROC(vfp_put_float)
 
-	.globl	vfp_get_double
-vfp_get_double:
+ENTRY(vfp_get_double)
 	add	pc, pc, r0, lsl #3
 	mov	r0, r0
 	.irp	dr,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
@@ -229,9 +227,9 @@
 	mov	r0, #0
 	mov	r1, #0
 	mov	pc, lr
+ENDPROC(vfp_get_double)
 
-	.globl	vfp_put_double
-vfp_put_double:
+ENTRY(vfp_put_double)
 	add	pc, pc, r2, lsl #3
 	mov	r0, r0
 	.irp	dr,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
@@ -245,3 +243,4 @@
 	mov	pc, lr
 	.endr
 #endif
+ENDPROC(vfp_put_double)
diff --git a/arch/avr32/boards/atngw100/setup.c b/arch/avr32/boards/atngw100/setup.c
index b8286f1ce..6c54580 100644
--- a/arch/avr32/boards/atngw100/setup.c
+++ b/arch/avr32/boards/atngw100/setup.c
@@ -9,6 +9,7 @@
  */
 #include <linux/clk.h>
 #include <linux/etherdevice.h>
+#include <linux/gpio.h>
 #include <linux/irq.h>
 #include <linux/i2c.h>
 #include <linux/i2c-gpio.h>
@@ -53,8 +54,11 @@
 };
 
 static struct mci_platform_data __initdata mci0_data = {
-	.detect_pin	= GPIO_PIN_PC(25),
-	.wp_pin		= GPIO_PIN_PE(0),
+	.slot[0] = {
+		.bus_width	= 4,
+		.detect_pin	= GPIO_PIN_PC(25),
+		.wp_pin		= GPIO_PIN_PE(0),
+	},
 };
 
 /*
@@ -190,7 +194,7 @@
 	 * PB28/EXTINT3 doesn't; it should be SMBALERT# (for PMBus),
 	 * but it's not available off-board.
 	 */
-	at32_select_periph(GPIO_PIN_PB(28), 0, AT32_GPIOF_PULLUP);
+	at32_select_periph(GPIO_PIOB_BASE, 1 << 28, 0, AT32_GPIOF_PULLUP);
 	at32_select_gpio(i2c_gpio_data.sda_pin,
 		AT32_GPIOF_MULTIDRV | AT32_GPIOF_OUTPUT | AT32_GPIOF_HIGH);
 	at32_select_gpio(i2c_gpio_data.scl_pin,
@@ -204,6 +208,15 @@
 
 static int __init atngw100_arch_init(void)
 {
+	/* PB30 is the otherwise unused jumper on the mainboard, with an
+	 * external pullup; the jumper grounds it.  Use it however you
+	 * like, including letting U-Boot or Linux tweak boot sequences.
+	 */
+	at32_select_gpio(GPIO_PIN_PB(30), 0);
+	gpio_request(GPIO_PIN_PB(30), "j15");
+	gpio_direction_input(GPIO_PIN_PB(30));
+	gpio_export(GPIO_PIN_PB(30), false);
+
 	/* set_irq_type() after the arch_initcall for EIC has run, and
 	 * before the I2C subsystem could try using this IRQ.
 	 */
diff --git a/arch/avr32/boards/atstk1000/atstk1002.c b/arch/avr32/boards/atstk1000/atstk1002.c
index ee4c292..29e5b51 100644
--- a/arch/avr32/boards/atstk1000/atstk1002.c
+++ b/arch/avr32/boards/atstk1000/atstk1002.c
@@ -232,7 +232,7 @@
 		goto err_set_clk;
 	}
 
-	at32_select_periph(GPIO_PIN_PA(30), GPIO_PERIPH_A, 0);
+	at32_select_periph(GPIO_PIOA_BASE, (1 << 30), GPIO_PERIPH_A, 0);
 	at73c213_data.dac_clk = gclk;
 
 err_set_clk:
@@ -264,16 +264,20 @@
 
 #ifndef CONFIG_BOARD_ATSTK100X_SW2_CUSTOM
 
+static struct mci_platform_data __initdata mci0_data = {
+	.slot[0] = {
+		.bus_width	= 4,
+
 /* MMC card detect requires MACB0 *NOT* be used */
 #ifdef CONFIG_BOARD_ATSTK1002_SW6_CUSTOM
-static struct mci_platform_data __initdata mci0_data = {
-	.detect_pin	= GPIO_PIN_PC(14),	/* gpio30/sdcd */
-	.wp_pin		= GPIO_PIN_PC(15),	/* gpio31/sdwp */
-};
-#define MCI_PDATA	&mci0_data
+		.detect_pin	= GPIO_PIN_PC(14), /* gpio30/sdcd */
+		.wp_pin		= GPIO_PIN_PC(15), /* gpio31/sdwp */
 #else
-#define MCI_PDATA	NULL
+		.detect_pin	= -ENODEV,
+		.wp_pin		= -ENODEV,
 #endif	/* SW6 for sd{cd,wp} routing */
+	},
+};
 
 #endif	/* SW2 for MMC signal routing */
 
@@ -325,14 +329,15 @@
 #ifdef CONFIG_BOARD_ATSTK100X_SPI1
 	at32_add_device_spi(1, spi1_board_info, ARRAY_SIZE(spi1_board_info));
 #endif
-#ifndef CONFIG_BOARD_ATSTK1002_SW2_CUSTOM
-	at32_add_device_mci(0, MCI_PDATA);
+#ifndef CONFIG_BOARD_ATSTK100X_SW2_CUSTOM
+	at32_add_device_mci(0, &mci0_data);
 #endif
 #ifdef CONFIG_BOARD_ATSTK1002_SW5_CUSTOM
 	set_hw_addr(at32_add_device_eth(1, &eth_data[1]));
 #else
 	at32_add_device_lcdc(0, &atstk1000_lcdc_data,
-			     fbmem_start, fbmem_size, 0);
+			     fbmem_start, fbmem_size,
+			     ATMEL_LCDC_PRI_24BIT | ATMEL_LCDC_PRI_CONTROL);
 #endif
 	at32_add_device_usba(0, NULL);
 #ifndef CONFIG_BOARD_ATSTK100X_SW3_CUSTOM
diff --git a/arch/avr32/boards/atstk1000/atstk1003.c b/arch/avr32/boards/atstk1000/atstk1003.c
index 0cf6641..be089d7f 100644
--- a/arch/avr32/boards/atstk1000/atstk1003.c
+++ b/arch/avr32/boards/atstk1000/atstk1003.c
@@ -19,6 +19,7 @@
 #include <linux/spi/spi.h>
 
 #include <asm/setup.h>
+#include <asm/atmel-mci.h>
 
 #include <mach/at32ap700x.h>
 #include <mach/board.h>
@@ -66,6 +67,16 @@
 } };
 #endif
 
+#ifndef CONFIG_BOARD_ATSTK100X_SW2_CUSTOM
+static struct mci_platform_data __initdata mci0_data = {
+	.slot[0] = {
+		.bus_width	= 4,
+		.detect_pin	= -ENODEV,
+		.wp_pin		= -ENODEV,
+	},
+};
+#endif
+
 #ifdef CONFIG_BOARD_ATSTK1000_EXTDAC
 static void __init atstk1003_setup_extdac(void)
 {
@@ -84,7 +95,7 @@
 		goto err_set_clk;
 	}
 
-	at32_select_periph(GPIO_PIN_PA(30), GPIO_PERIPH_A, 0);
+	at32_select_periph(GPIO_PIOA_BASE, (1 << 30), GPIO_PERIPH_A, 0);
 	at73c213_data.dac_clk = gclk;
 
 err_set_clk:
@@ -154,7 +165,7 @@
 	at32_add_device_spi(1, spi1_board_info, ARRAY_SIZE(spi1_board_info));
 #endif
 #ifndef CONFIG_BOARD_ATSTK100X_SW2_CUSTOM
-	at32_add_device_mci(0, NULL);
+	at32_add_device_mci(0, &mci0_data);
 #endif
 	at32_add_device_usba(0, NULL);
 #ifndef CONFIG_BOARD_ATSTK100X_SW3_CUSTOM
diff --git a/arch/avr32/boards/atstk1000/atstk1004.c b/arch/avr32/boards/atstk1000/atstk1004.c
index 50a5273..248ef23 100644
--- a/arch/avr32/boards/atstk1000/atstk1004.c
+++ b/arch/avr32/boards/atstk1000/atstk1004.c
@@ -21,6 +21,7 @@
 #include <video/atmel_lcdc.h>
 
 #include <asm/setup.h>
+#include <asm/atmel-mci.h>
 
 #include <mach/at32ap700x.h>
 #include <mach/board.h>
@@ -71,6 +72,16 @@
 } };
 #endif
 
+#ifndef CONFIG_BOARD_ATSTK100X_SW2_CUSTOM
+static struct mci_platform_data __initdata mci0_data = {
+	.slot[0] = {
+		.bus_width	= 4,
+		.detect_pin	= -ENODEV,
+		.wp_pin		= -ENODEV,
+	},
+};
+#endif
+
 #ifdef CONFIG_BOARD_ATSTK1000_EXTDAC
 static void __init atstk1004_setup_extdac(void)
 {
@@ -89,7 +100,7 @@
 		goto err_set_clk;
 	}
 
-	at32_select_periph(GPIO_PIN_PA(30), GPIO_PERIPH_A, 0);
+	at32_select_periph(GPIO_PIOA_BASE, (1 << 30), GPIO_PERIPH_A, 0);
 	at73c213_data.dac_clk = gclk;
 
 err_set_clk:
@@ -137,10 +148,11 @@
 	at32_add_device_spi(1, spi1_board_info, ARRAY_SIZE(spi1_board_info));
 #endif
 #ifndef CONFIG_BOARD_ATSTK100X_SW2_CUSTOM
-	at32_add_device_mci(0, NULL);
+	at32_add_device_mci(0, &mci0_data);
 #endif
 	at32_add_device_lcdc(0, &atstk1000_lcdc_data,
-			     fbmem_start, fbmem_size, 0);
+			     fbmem_start, fbmem_size,
+			     ATMEL_LCDC_PRI_24BIT | ATMEL_LCDC_PRI_CONTROL);
 	at32_add_device_usba(0, NULL);
 #ifndef CONFIG_BOARD_ATSTK100X_SW3_CUSTOM
 	at32_add_device_ssc(0, ATMEL_SSC_TX);
diff --git a/arch/avr32/boot/images/.gitignore b/arch/avr32/boot/images/.gitignore
new file mode 100644
index 0000000..64ea9d0
--- /dev/null
+++ b/arch/avr32/boot/images/.gitignore
@@ -0,0 +1,4 @@
+uImage
+uImage.srec
+vmlinux.cso
+sfdwarf.log
diff --git a/arch/avr32/include/asm/a.out.h b/arch/avr32/include/asm/a.out.h
deleted file mode 100644
index e46375a3..0000000
--- a/arch/avr32/include/asm/a.out.h
+++ /dev/null
@@ -1,20 +0,0 @@
-#ifndef __ASM_AVR32_A_OUT_H
-#define __ASM_AVR32_A_OUT_H
-
-struct exec
-{
-  unsigned long a_info;		/* Use macros N_MAGIC, etc for access */
-  unsigned a_text;		/* length of text, in bytes */
-  unsigned a_data;		/* length of data, in bytes */
-  unsigned a_bss;		/* length of uninitialized data area for file, in bytes */
-  unsigned a_syms;		/* length of symbol table data in file, in bytes */
-  unsigned a_entry;		/* start address */
-  unsigned a_trsize;		/* length of relocation info for text, in bytes */
-  unsigned a_drsize;		/* length of relocation info for data, in bytes */
-};
-
-#define N_TRSIZE(a)	((a).a_trsize)
-#define N_DRSIZE(a)	((a).a_drsize)
-#define N_SYMSIZE(a)	((a).a_syms)
-
-#endif /* __ASM_AVR32_A_OUT_H */
diff --git a/arch/avr32/include/asm/atmel-mci.h b/arch/avr32/include/asm/atmel-mci.h
index c2ea6e1..59f3fad 100644
--- a/arch/avr32/include/asm/atmel-mci.h
+++ b/arch/avr32/include/asm/atmel-mci.h
@@ -1,9 +1,39 @@
 #ifndef __ASM_AVR32_ATMEL_MCI_H
 #define __ASM_AVR32_ATMEL_MCI_H
 
-struct mci_platform_data {
+#define ATMEL_MCI_MAX_NR_SLOTS	2
+
+struct dma_slave;
+
+/**
+ * struct mci_slot_pdata - board-specific per-slot configuration
+ * @bus_width: Number of data lines wired up the slot
+ * @detect_pin: GPIO pin wired to the card detect switch
+ * @wp_pin: GPIO pin wired to the write protect sensor
+ *
+ * If a given slot is not present on the board, @bus_width should be
+ * set to 0. The other fields are ignored in this case.
+ *
+ * Any pins that aren't available should be set to a negative value.
+ *
+ * Note that support for multiple slots is experimental -- some cards
+ * might get upset if we don't get the clock management exactly right.
+ * But in most cases, it should work just fine.
+ */
+struct mci_slot_pdata {
+	unsigned int		bus_width;
 	int			detect_pin;
 	int			wp_pin;
 };
 
+/**
+ * struct mci_platform_data - board-specific MMC/SDcard configuration
+ * @dma_slave: DMA slave interface to use in data transfers, or NULL.
+ * @slot: Per-slot configuration data.
+ */
+struct mci_platform_data {
+	struct dma_slave	*dma_slave;
+	struct mci_slot_pdata	slot[ATMEL_MCI_MAX_NR_SLOTS];
+};
+
 #endif /* __ASM_AVR32_ATMEL_MCI_H */
diff --git a/arch/avr32/include/asm/byteorder.h b/arch/avr32/include/asm/byteorder.h
index d77b48b..8e3af02 100644
--- a/arch/avr32/include/asm/byteorder.h
+++ b/arch/avr32/include/asm/byteorder.h
@@ -7,6 +7,9 @@
 #include <asm/types.h>
 #include <linux/compiler.h>
 
+#define __BIG_ENDIAN
+#define __SWAB_64_THRU_32__
+
 #ifdef __CHECKER__
 extern unsigned long __builtin_bswap_32(unsigned long x);
 extern unsigned short __builtin_bswap_16(unsigned short x);
@@ -17,15 +20,18 @@
  * the result.
  */
 #if !(__GNUC__ == 4 && __GNUC_MINOR__ < 2)
-#define __arch__swab32(x) __builtin_bswap_32(x)
-#define __arch__swab16(x) __builtin_bswap_16(x)
+static inline __attribute_const__ __u16 __arch_swab16(__u16 val)
+{
+	return __builtin_bswap_16(val);
+}
+#define __arch_swab16 __arch_swab16
+
+static inline __attribute_const__ __u32 __arch_swab32(__u32 val)
+{
+	return __builtin_bswap_32(val);
+}
+#define __arch_swab32 __arch_swab32
 #endif
 
-#if !defined(__STRICT_ANSI__) || defined(__KERNEL__)
-# define __BYTEORDER_HAS_U64__
-# define __SWAB_64_THRU_32__
-#endif
-
-#include <linux/byteorder/big_endian.h>
-
+#include <linux/byteorder.h>
 #endif /* __ASM_AVR32_BYTEORDER_H */
diff --git a/arch/avr32/include/asm/io.h b/arch/avr32/include/asm/io.h
index a520f77..22c97ef 100644
--- a/arch/avr32/include/asm/io.h
+++ b/arch/avr32/include/asm/io.h
@@ -160,6 +160,14 @@
 #define readw_relaxed			readw
 #define readl_relaxed			readl
 
+#define readb_be			__raw_readb
+#define readw_be			__raw_readw
+#define readl_be			__raw_readl
+
+#define writeb_be			__raw_writeb
+#define writew_be			__raw_writew
+#define writel_be			__raw_writel
+
 #define __BUILD_MEMORY_STRING(bwl, type)				\
 static inline void writes##bwl(volatile void __iomem *addr,		\
 			       const void *data, unsigned int count)	\
diff --git a/arch/avr32/kernel/.gitignore b/arch/avr32/kernel/.gitignore
new file mode 100644
index 0000000..c5f676c
--- /dev/null
+++ b/arch/avr32/kernel/.gitignore
@@ -0,0 +1 @@
+vmlinux.lds
diff --git a/arch/avr32/kernel/avr32_ksyms.c b/arch/avr32/kernel/avr32_ksyms.c
index 84a7d44..11e310c 100644
--- a/arch/avr32/kernel/avr32_ksyms.c
+++ b/arch/avr32/kernel/avr32_ksyms.c
@@ -58,6 +58,7 @@
 EXPORT_SYMBOL(find_next_zero_bit);
 EXPORT_SYMBOL(find_first_bit);
 EXPORT_SYMBOL(find_next_bit);
+EXPORT_SYMBOL(generic_find_next_le_bit);
 EXPORT_SYMBOL(generic_find_next_zero_le_bit);
 
 /* I/O primitives (lib/io-*.S) */
diff --git a/arch/avr32/kernel/process.c b/arch/avr32/kernel/process.c
index 2c08ac9..134d530 100644
--- a/arch/avr32/kernel/process.c
+++ b/arch/avr32/kernel/process.c
@@ -9,6 +9,7 @@
 #include <linux/module.h>
 #include <linux/kallsyms.h>
 #include <linux/fs.h>
+#include <linux/pm.h>
 #include <linux/ptrace.h>
 #include <linux/reboot.h>
 #include <linux/tick.h>
@@ -20,7 +21,7 @@
 
 #include <mach/pm.h>
 
-void (*pm_power_off)(void) = NULL;
+void (*pm_power_off)(void);
 EXPORT_SYMBOL(pm_power_off);
 
 /*
diff --git a/arch/avr32/kernel/setup.c b/arch/avr32/kernel/setup.c
index d8e623c..5c70839 100644
--- a/arch/avr32/kernel/setup.c
+++ b/arch/avr32/kernel/setup.c
@@ -283,6 +283,25 @@
 }
 early_param("fbmem", early_parse_fbmem);
 
+/*
+ * Pick out the memory size.  We look for mem=size@start,
+ * where start and size are "size[KkMmGg]"
+ */
+static int __init early_mem(char *p)
+{
+	resource_size_t size, start;
+
+	start = system_ram->start;
+	size  = memparse(p, &p);
+	if (*p == '@')
+		start = memparse(p + 1, &p);
+
+	system_ram->start = start;
+	system_ram->end = system_ram->start + size - 1;
+	return 0;
+}
+early_param("mem", early_mem);
+
 static int __init parse_tag_core(struct tag *tag)
 {
 	if (tag->hdr.size > 2) {
diff --git a/arch/avr32/kernel/syscall-stubs.S b/arch/avr32/kernel/syscall-stubs.S
index 890286a..673178e 100644
--- a/arch/avr32/kernel/syscall-stubs.S
+++ b/arch/avr32/kernel/syscall-stubs.S
@@ -109,3 +109,12 @@
 	rcall	sys_epoll_pwait
 	sub	sp, -4
 	popm	pc
+
+	.global __sys_sync_file_range
+	.type	__sys_sync_file_range,@function
+__sys_sync_file_range:
+	pushm	lr
+	st.w	--sp, ARG6
+	rcall	sys_sync_file_range
+	sub	sp, -4
+	popm	pc
diff --git a/arch/avr32/kernel/syscall_table.S b/arch/avr32/kernel/syscall_table.S
index 478bda4..7ee0057 100644
--- a/arch/avr32/kernel/syscall_table.S
+++ b/arch/avr32/kernel/syscall_table.S
@@ -275,7 +275,7 @@
 	.long	sys_set_robust_list
 	.long	sys_get_robust_list	/* 260 */
 	.long	__sys_splice
-	.long	sys_sync_file_range
+	.long	__sys_sync_file_range
 	.long	sys_tee
 	.long	sys_vmsplice
 	.long	__sys_epoll_pwait	/* 265 */
diff --git a/arch/avr32/kernel/traps.c b/arch/avr32/kernel/traps.c
index b835c4c..0d98737 100644
--- a/arch/avr32/kernel/traps.c
+++ b/arch/avr32/kernel/traps.c
@@ -116,15 +116,15 @@
 	switch (ret) {
 	case NOTIFY_OK:
 	case NOTIFY_STOP:
-		return;
+		break;
 	case NOTIFY_BAD:
 		die("Fatal Non-Maskable Interrupt", regs, SIGINT);
 	default:
+		printk(KERN_ALERT "Got NMI, but nobody cared. Disabling...\n");
+		nmi_disable();
 		break;
 	}
-
-	printk(KERN_ALERT "Got NMI, but nobody cared. Disabling...\n");
-	nmi_disable();
+	nmi_exit();
 }
 
 asmlinkage void do_critical_exception(unsigned long ecr, struct pt_regs *regs)
diff --git a/arch/avr32/lib/findbit.S b/arch/avr32/lib/findbit.S
index c6b91de..997b33b 100644
--- a/arch/avr32/lib/findbit.S
+++ b/arch/avr32/lib/findbit.S
@@ -123,6 +123,36 @@
 	brgt	1b
 	retal	r11
 
+ENTRY(generic_find_next_le_bit)
+	lsr	r8, r10, 5
+	sub	r9, r11, r10
+	retle	r11
+
+	lsl	r8, 2
+	add	r12, r8
+	andl	r10, 31, COH
+	breq	1f
+
+	/* offset is not word-aligned. Handle the first (32 - r10) bits */
+	ldswp.w	r8, r12[0]
+	sub	r12, -4
+	lsr	r8, r8, r10
+	brne	.L_found
+
+	/* r9 = r9 - (32 - r10) = r9 + r10 - 32 */
+	add	r9, r10
+	sub	r9, 32
+	retle	r11
+
+	/* Main loop. offset must be word-aligned */
+1:	ldswp.w	r8, r12[0]
+	cp.w	r8, 0
+	brne	.L_found
+	sub	r12, -4
+	sub	r9, 32
+	brgt	1b
+	retal	r11
+
 ENTRY(generic_find_next_zero_le_bit)
 	lsr	r8, r10, 5
 	sub	r9, r11, r10
diff --git a/arch/avr32/mach-at32ap/at32ap700x.c b/arch/avr32/mach-at32ap/at32ap700x.c
index e01dbe4..813b684 100644
--- a/arch/avr32/mach-at32ap/at32ap700x.c
+++ b/arch/avr32/mach-at32ap/at32ap700x.c
@@ -82,8 +82,9 @@
 	.num_resources	= ARRAY_SIZE(_name##_id##_resource),	\
 }
 
-#define select_peripheral(pin, periph, flags)			\
-	at32_select_periph(GPIO_PIN_##pin, GPIO_##periph, flags)
+#define select_peripheral(port, pin_mask, periph, flags)	\
+	at32_select_periph(GPIO_##port##_BASE, pin_mask,	\
+			   GPIO_##periph, flags)
 
 #define DEV_CLK(_name, devname, bus, _index)			\
 static struct clk devname##_##_name = {				\
@@ -871,6 +872,7 @@
 struct platform_device *__init at32_add_device_psif(unsigned int id)
 {
 	struct platform_device *pdev;
+	u32 pin_mask;
 
 	if (!(id == 0 || id == 1))
 		return NULL;
@@ -881,20 +883,22 @@
 
 	switch (id) {
 	case 0:
+		pin_mask  = (1 << 8) | (1 << 9); /* CLOCK & DATA */
+
 		if (platform_device_add_resources(pdev, atmel_psif0_resource,
 					ARRAY_SIZE(atmel_psif0_resource)))
 			goto err_add_resources;
 		atmel_psif0_pclk.dev = &pdev->dev;
-		select_peripheral(PA(8), PERIPH_A, 0); /* CLOCK */
-		select_peripheral(PA(9), PERIPH_A, 0); /* DATA  */
+		select_peripheral(PIOA, pin_mask, PERIPH_A, 0);
 		break;
 	case 1:
+		pin_mask  = (1 << 11) | (1 << 12); /* CLOCK & DATA */
+
 		if (platform_device_add_resources(pdev, atmel_psif1_resource,
 					ARRAY_SIZE(atmel_psif1_resource)))
 			goto err_add_resources;
 		atmel_psif1_pclk.dev = &pdev->dev;
-		select_peripheral(PB(11), PERIPH_A, 0); /* CLOCK */
-		select_peripheral(PB(12), PERIPH_A, 0); /* DATA  */
+		select_peripheral(PIOB, pin_mask, PERIPH_A, 0);
 		break;
 	default:
 		return NULL;
@@ -958,26 +962,30 @@
 
 static inline void configure_usart0_pins(void)
 {
-	select_peripheral(PA(8),  PERIPH_B, 0);	/* RXD	*/
-	select_peripheral(PA(9),  PERIPH_B, 0);	/* TXD	*/
+	u32 pin_mask = (1 << 8) | (1 << 9); /* RXD & TXD */
+
+	select_peripheral(PIOA, pin_mask, PERIPH_B, 0);
 }
 
 static inline void configure_usart1_pins(void)
 {
-	select_peripheral(PA(17), PERIPH_A, 0);	/* RXD	*/
-	select_peripheral(PA(18), PERIPH_A, 0);	/* TXD	*/
+	u32 pin_mask = (1 << 17) | (1 << 18); /* RXD & TXD */
+
+	select_peripheral(PIOA, pin_mask, PERIPH_A, 0);
 }
 
 static inline void configure_usart2_pins(void)
 {
-	select_peripheral(PB(26), PERIPH_B, 0);	/* RXD	*/
-	select_peripheral(PB(27), PERIPH_B, 0);	/* TXD	*/
+	u32 pin_mask = (1 << 26) | (1 << 27); /* RXD & TXD */
+
+	select_peripheral(PIOB, pin_mask, PERIPH_B, 0);
 }
 
 static inline void configure_usart3_pins(void)
 {
-	select_peripheral(PB(18), PERIPH_B, 0);	/* RXD	*/
-	select_peripheral(PB(17), PERIPH_B, 0);	/* TXD	*/
+	u32 pin_mask = (1 << 18) | (1 << 17); /* RXD & TXD */
+
+	select_peripheral(PIOB, pin_mask, PERIPH_B, 0);
 }
 
 static struct platform_device *__initdata at32_usarts[4];
@@ -1057,59 +1065,69 @@
 at32_add_device_eth(unsigned int id, struct eth_platform_data *data)
 {
 	struct platform_device *pdev;
+	u32 pin_mask;
 
 	switch (id) {
 	case 0:
 		pdev = &macb0_device;
 
-		select_peripheral(PC(3),  PERIPH_A, 0);	/* TXD0	*/
-		select_peripheral(PC(4),  PERIPH_A, 0);	/* TXD1	*/
-		select_peripheral(PC(7),  PERIPH_A, 0);	/* TXEN	*/
-		select_peripheral(PC(8),  PERIPH_A, 0);	/* TXCK */
-		select_peripheral(PC(9),  PERIPH_A, 0);	/* RXD0	*/
-		select_peripheral(PC(10), PERIPH_A, 0);	/* RXD1	*/
-		select_peripheral(PC(13), PERIPH_A, 0);	/* RXER	*/
-		select_peripheral(PC(15), PERIPH_A, 0);	/* RXDV	*/
-		select_peripheral(PC(16), PERIPH_A, 0);	/* MDC	*/
-		select_peripheral(PC(17), PERIPH_A, 0);	/* MDIO	*/
+		pin_mask  = (1 << 3);	/* TXD0 */
+		pin_mask |= (1 << 4);	/* TXD1 */
+		pin_mask |= (1 << 7);	/* TXEN */
+		pin_mask |= (1 << 8);	/* TXCK */
+		pin_mask |= (1 << 9);	/* RXD0 */
+		pin_mask |= (1 << 10);	/* RXD1 */
+		pin_mask |= (1 << 13);	/* RXER */
+		pin_mask |= (1 << 15);	/* RXDV */
+		pin_mask |= (1 << 16);	/* MDC  */
+		pin_mask |= (1 << 17);	/* MDIO */
 
 		if (!data->is_rmii) {
-			select_peripheral(PC(0),  PERIPH_A, 0);	/* COL	*/
-			select_peripheral(PC(1),  PERIPH_A, 0);	/* CRS	*/
-			select_peripheral(PC(2),  PERIPH_A, 0);	/* TXER	*/
-			select_peripheral(PC(5),  PERIPH_A, 0);	/* TXD2	*/
-			select_peripheral(PC(6),  PERIPH_A, 0);	/* TXD3 */
-			select_peripheral(PC(11), PERIPH_A, 0);	/* RXD2	*/
-			select_peripheral(PC(12), PERIPH_A, 0);	/* RXD3	*/
-			select_peripheral(PC(14), PERIPH_A, 0);	/* RXCK	*/
-			select_peripheral(PC(18), PERIPH_A, 0);	/* SPD	*/
+			pin_mask |= (1 << 0);	/* COL  */
+			pin_mask |= (1 << 1);	/* CRS  */
+			pin_mask |= (1 << 2);	/* TXER */
+			pin_mask |= (1 << 5);	/* TXD2 */
+			pin_mask |= (1 << 6);	/* TXD3 */
+			pin_mask |= (1 << 11);	/* RXD2 */
+			pin_mask |= (1 << 12);	/* RXD3 */
+			pin_mask |= (1 << 14);	/* RXCK */
+			pin_mask |= (1 << 18);	/* SPD  */
 		}
+
+		select_peripheral(PIOC, pin_mask, PERIPH_A, 0);
+
 		break;
 
 	case 1:
 		pdev = &macb1_device;
 
-		select_peripheral(PD(13), PERIPH_B, 0);		/* TXD0	*/
-		select_peripheral(PD(14), PERIPH_B, 0);		/* TXD1	*/
-		select_peripheral(PD(11), PERIPH_B, 0);		/* TXEN	*/
-		select_peripheral(PD(12), PERIPH_B, 0);		/* TXCK */
-		select_peripheral(PD(10), PERIPH_B, 0);		/* RXD0	*/
-		select_peripheral(PD(6),  PERIPH_B, 0);		/* RXD1	*/
-		select_peripheral(PD(5),  PERIPH_B, 0);		/* RXER	*/
-		select_peripheral(PD(4),  PERIPH_B, 0);		/* RXDV	*/
-		select_peripheral(PD(3),  PERIPH_B, 0);		/* MDC	*/
-		select_peripheral(PD(2),  PERIPH_B, 0);		/* MDIO	*/
+		pin_mask  = (1 << 13);	/* TXD0 */
+		pin_mask |= (1 << 14);	/* TXD1 */
+		pin_mask |= (1 << 11);	/* TXEN */
+		pin_mask |= (1 << 12);	/* TXCK */
+		pin_mask |= (1 << 10);	/* RXD0 */
+		pin_mask |= (1 << 6);	/* RXD1 */
+		pin_mask |= (1 << 5);	/* RXER */
+		pin_mask |= (1 << 4);	/* RXDV */
+		pin_mask |= (1 << 3);	/* MDC  */
+		pin_mask |= (1 << 2);	/* MDIO */
+
+		if (!data->is_rmii)
+			pin_mask |= (1 << 15);	/* SPD  */
+
+		select_peripheral(PIOD, pin_mask, PERIPH_B, 0);
 
 		if (!data->is_rmii) {
-			select_peripheral(PC(19), PERIPH_B, 0);	/* COL	*/
-			select_peripheral(PC(23), PERIPH_B, 0);	/* CRS	*/
-			select_peripheral(PC(26), PERIPH_B, 0);	/* TXER	*/
-			select_peripheral(PC(27), PERIPH_B, 0);	/* TXD2	*/
-			select_peripheral(PC(28), PERIPH_B, 0);	/* TXD3 */
-			select_peripheral(PC(29), PERIPH_B, 0);	/* RXD2	*/
-			select_peripheral(PC(30), PERIPH_B, 0);	/* RXD3	*/
-			select_peripheral(PC(24), PERIPH_B, 0);	/* RXCK	*/
-			select_peripheral(PD(15), PERIPH_B, 0);	/* SPD	*/
+			pin_mask  = (1 << 19);	/* COL  */
+			pin_mask |= (1 << 23);	/* CRS  */
+			pin_mask |= (1 << 26);	/* TXER */
+			pin_mask |= (1 << 27);	/* TXD2 */
+			pin_mask |= (1 << 28);	/* TXD3 */
+			pin_mask |= (1 << 29);	/* RXD2 */
+			pin_mask |= (1 << 30);	/* RXD3 */
+			pin_mask |= (1 << 24);	/* RXCK */
+
+			select_peripheral(PIOC, pin_mask, PERIPH_B, 0);
 		}
 		break;
 
@@ -1177,23 +1195,28 @@
 		{ GPIO_PIN_PB(2), GPIO_PIN_PB(3),
 		  GPIO_PIN_PB(4), GPIO_PIN_PA(27), };
 	struct platform_device *pdev;
+	u32 pin_mask;
 
 	switch (id) {
 	case 0:
 		pdev = &atmel_spi0_device;
+		pin_mask  = (1 << 1) | (1 << 2);	/* MOSI & SCK */
+
 		/* pullup MISO so a level is always defined */
-		select_peripheral(PA(0),  PERIPH_A, AT32_GPIOF_PULLUP);
-		select_peripheral(PA(1),  PERIPH_A, 0);	/* MOSI	 */
-		select_peripheral(PA(2),  PERIPH_A, 0);	/* SCK	 */
+		select_peripheral(PIOA, (1 << 0), PERIPH_A, AT32_GPIOF_PULLUP);
+		select_peripheral(PIOA, pin_mask, PERIPH_A, 0);
+
 		at32_spi_setup_slaves(0, b, n, spi0_pins);
 		break;
 
 	case 1:
 		pdev = &atmel_spi1_device;
+		pin_mask  = (1 << 1) | (1 << 5);	/* MOSI */
+
 		/* pullup MISO so a level is always defined */
-		select_peripheral(PB(0),  PERIPH_B, AT32_GPIOF_PULLUP);
-		select_peripheral(PB(1),  PERIPH_B, 0);	/* MOSI  */
-		select_peripheral(PB(5),  PERIPH_B, 0);	/* SCK   */
+		select_peripheral(PIOB, (1 << 0), PERIPH_B, AT32_GPIOF_PULLUP);
+		select_peripheral(PIOB, pin_mask, PERIPH_B, 0);
+
 		at32_spi_setup_slaves(1, b, n, spi1_pins);
 		break;
 
@@ -1226,6 +1249,7 @@
 						    unsigned int n)
 {
 	struct platform_device *pdev;
+	u32 pin_mask;
 
 	if (id != 0)
 		return NULL;
@@ -1238,8 +1262,9 @@
 				ARRAY_SIZE(atmel_twi0_resource)))
 		goto err_add_resources;
 
-	select_peripheral(PA(6),  PERIPH_A, 0);	/* SDA	*/
-	select_peripheral(PA(7),  PERIPH_A, 0);	/* SDL	*/
+	pin_mask  = (1 << 6) | (1 << 7);	/* SDA & SDL */
+
+	select_peripheral(PIOA, pin_mask, PERIPH_A, 0);
 
 	atmel_twi0_pclk.dev = &pdev->dev;
 
@@ -1272,10 +1297,16 @@
 struct platform_device *__init
 at32_add_device_mci(unsigned int id, struct mci_platform_data *data)
 {
-	struct mci_platform_data	_data;
 	struct platform_device		*pdev;
+	struct dw_dma_slave		*dws;
+	u32				pioa_mask;
+	u32				piob_mask;
 
-	if (id != 0)
+	if (id != 0 || !data)
+		return NULL;
+
+	/* Must have at least one usable slot */
+	if (!data->slot[0].bus_width && !data->slot[1].bus_width)
 		return NULL;
 
 	pdev = platform_device_alloc("atmel_mci", id);
@@ -1286,28 +1317,80 @@
 				ARRAY_SIZE(atmel_mci0_resource)))
 		goto fail;
 
-	if (!data) {
-		data = &_data;
-		memset(data, -1, sizeof(struct mci_platform_data));
-		data->detect_pin = GPIO_PIN_NONE;
-		data->wp_pin = GPIO_PIN_NONE;
-	}
+	if (data->dma_slave)
+		dws = kmemdup(to_dw_dma_slave(data->dma_slave),
+				sizeof(struct dw_dma_slave), GFP_KERNEL);
+	else
+		dws = kzalloc(sizeof(struct dw_dma_slave), GFP_KERNEL);
+
+	dws->slave.dev = &pdev->dev;
+	dws->slave.dma_dev = &dw_dmac0_device.dev;
+	dws->slave.reg_width = DMA_SLAVE_WIDTH_32BIT;
+	dws->cfg_hi = (DWC_CFGH_SRC_PER(0)
+				| DWC_CFGH_DST_PER(1));
+	dws->cfg_lo &= ~(DWC_CFGL_HS_DST_POL
+				| DWC_CFGL_HS_SRC_POL);
+
+	data->dma_slave = &dws->slave;
 
 	if (platform_device_add_data(pdev, data,
 				sizeof(struct mci_platform_data)))
 		goto fail;
 
-	select_peripheral(PA(10), PERIPH_A, 0);	/* CLK	 */
-	select_peripheral(PA(11), PERIPH_A, 0);	/* CMD	 */
-	select_peripheral(PA(12), PERIPH_A, 0);	/* DATA0 */
-	select_peripheral(PA(13), PERIPH_A, 0);	/* DATA1 */
-	select_peripheral(PA(14), PERIPH_A, 0);	/* DATA2 */
-	select_peripheral(PA(15), PERIPH_A, 0);	/* DATA3 */
+	/* CLK line is common to both slots */
+	pioa_mask = 1 << 10;
 
-	if (gpio_is_valid(data->detect_pin))
-		at32_select_gpio(data->detect_pin, 0);
-	if (gpio_is_valid(data->wp_pin))
-		at32_select_gpio(data->wp_pin, 0);
+	switch (data->slot[0].bus_width) {
+	case 4:
+		pioa_mask |= 1 << 13;		/* DATA1 */
+		pioa_mask |= 1 << 14;		/* DATA2 */
+		pioa_mask |= 1 << 15;		/* DATA3 */
+		/* fall through */
+	case 1:
+		pioa_mask |= 1 << 11;		/* CMD	 */
+		pioa_mask |= 1 << 12;		/* DATA0 */
+
+		if (gpio_is_valid(data->slot[0].detect_pin))
+			at32_select_gpio(data->slot[0].detect_pin, 0);
+		if (gpio_is_valid(data->slot[0].wp_pin))
+			at32_select_gpio(data->slot[0].wp_pin, 0);
+		break;
+	case 0:
+		/* Slot is unused */
+		break;
+	default:
+		goto fail;
+	}
+
+	select_peripheral(PIOA, pioa_mask, PERIPH_A, 0);
+	piob_mask = 0;
+
+	switch (data->slot[1].bus_width) {
+	case 4:
+		piob_mask |= 1 <<  8;		/* DATA1 */
+		piob_mask |= 1 <<  9;		/* DATA2 */
+		piob_mask |= 1 << 10;		/* DATA3 */
+		/* fall through */
+	case 1:
+		piob_mask |= 1 <<  6;		/* CMD	 */
+		piob_mask |= 1 <<  7;		/* DATA0 */
+		select_peripheral(PIOB, piob_mask, PERIPH_B, 0);
+
+		if (gpio_is_valid(data->slot[1].detect_pin))
+			at32_select_gpio(data->slot[1].detect_pin, 0);
+		if (gpio_is_valid(data->slot[1].wp_pin))
+			at32_select_gpio(data->slot[1].wp_pin, 0);
+		break;
+	case 0:
+		/* Slot is unused */
+		break;
+	default:
+		if (!data->slot[0].bus_width)
+			goto fail;
+
+		data->slot[1].bus_width = 0;
+		break;
+	}
 
 	atmel_mci0_pclk.dev = &pdev->dev;
 
@@ -1353,13 +1436,14 @@
 struct platform_device *__init
 at32_add_device_lcdc(unsigned int id, struct atmel_lcdfb_info *data,
 		     unsigned long fbmem_start, unsigned long fbmem_len,
-		     unsigned int pin_config)
+		     u64 pin_mask)
 {
 	struct platform_device *pdev;
 	struct atmel_lcdfb_info *info;
 	struct fb_monspecs *monspecs;
 	struct fb_videomode *modedb;
 	unsigned int modedb_size;
+	u32 portc_mask, portd_mask, porte_mask;
 
 	/*
 	 * Do a deep copy of the fb data, monspecs and modedb. Make
@@ -1381,76 +1465,21 @@
 	case 0:
 		pdev = &atmel_lcdfb0_device;
 
-		switch (pin_config) {
-		case 0:
-			select_peripheral(PC(19), PERIPH_A, 0);	/* CC	  */
-			select_peripheral(PC(20), PERIPH_A, 0);	/* HSYNC  */
-			select_peripheral(PC(21), PERIPH_A, 0);	/* PCLK	  */
-			select_peripheral(PC(22), PERIPH_A, 0);	/* VSYNC  */
-			select_peripheral(PC(23), PERIPH_A, 0);	/* DVAL	  */
-			select_peripheral(PC(24), PERIPH_A, 0);	/* MODE	  */
-			select_peripheral(PC(25), PERIPH_A, 0);	/* PWR	  */
-			select_peripheral(PC(26), PERIPH_A, 0);	/* DATA0  */
-			select_peripheral(PC(27), PERIPH_A, 0);	/* DATA1  */
-			select_peripheral(PC(28), PERIPH_A, 0);	/* DATA2  */
-			select_peripheral(PC(29), PERIPH_A, 0);	/* DATA3  */
-			select_peripheral(PC(30), PERIPH_A, 0);	/* DATA4  */
-			select_peripheral(PC(31), PERIPH_A, 0);	/* DATA5  */
-			select_peripheral(PD(0),  PERIPH_A, 0);	/* DATA6  */
-			select_peripheral(PD(1),  PERIPH_A, 0);	/* DATA7  */
-			select_peripheral(PD(2),  PERIPH_A, 0);	/* DATA8  */
-			select_peripheral(PD(3),  PERIPH_A, 0);	/* DATA9  */
-			select_peripheral(PD(4),  PERIPH_A, 0);	/* DATA10 */
-			select_peripheral(PD(5),  PERIPH_A, 0);	/* DATA11 */
-			select_peripheral(PD(6),  PERIPH_A, 0);	/* DATA12 */
-			select_peripheral(PD(7),  PERIPH_A, 0);	/* DATA13 */
-			select_peripheral(PD(8),  PERIPH_A, 0);	/* DATA14 */
-			select_peripheral(PD(9),  PERIPH_A, 0);	/* DATA15 */
-			select_peripheral(PD(10), PERIPH_A, 0);	/* DATA16 */
-			select_peripheral(PD(11), PERIPH_A, 0);	/* DATA17 */
-			select_peripheral(PD(12), PERIPH_A, 0);	/* DATA18 */
-			select_peripheral(PD(13), PERIPH_A, 0);	/* DATA19 */
-			select_peripheral(PD(14), PERIPH_A, 0);	/* DATA20 */
-			select_peripheral(PD(15), PERIPH_A, 0);	/* DATA21 */
-			select_peripheral(PD(16), PERIPH_A, 0);	/* DATA22 */
-			select_peripheral(PD(17), PERIPH_A, 0);	/* DATA23 */
-			break;
-		case 1:
-			select_peripheral(PE(0),  PERIPH_B, 0);	/* CC	  */
-			select_peripheral(PC(20), PERIPH_A, 0);	/* HSYNC  */
-			select_peripheral(PC(21), PERIPH_A, 0);	/* PCLK	  */
-			select_peripheral(PC(22), PERIPH_A, 0);	/* VSYNC  */
-			select_peripheral(PE(1),  PERIPH_B, 0);	/* DVAL	  */
-			select_peripheral(PE(2),  PERIPH_B, 0);	/* MODE	  */
-			select_peripheral(PC(25), PERIPH_A, 0);	/* PWR	  */
-			select_peripheral(PE(3),  PERIPH_B, 0);	/* DATA0  */
-			select_peripheral(PE(4),  PERIPH_B, 0);	/* DATA1  */
-			select_peripheral(PE(5),  PERIPH_B, 0);	/* DATA2  */
-			select_peripheral(PE(6),  PERIPH_B, 0);	/* DATA3  */
-			select_peripheral(PE(7),  PERIPH_B, 0);	/* DATA4  */
-			select_peripheral(PC(31), PERIPH_A, 0);	/* DATA5  */
-			select_peripheral(PD(0),  PERIPH_A, 0);	/* DATA6  */
-			select_peripheral(PD(1),  PERIPH_A, 0);	/* DATA7  */
-			select_peripheral(PE(8),  PERIPH_B, 0);	/* DATA8  */
-			select_peripheral(PE(9),  PERIPH_B, 0);	/* DATA9  */
-			select_peripheral(PE(10), PERIPH_B, 0);	/* DATA10 */
-			select_peripheral(PE(11), PERIPH_B, 0);	/* DATA11 */
-			select_peripheral(PE(12), PERIPH_B, 0);	/* DATA12 */
-			select_peripheral(PD(7),  PERIPH_A, 0);	/* DATA13 */
-			select_peripheral(PD(8),  PERIPH_A, 0);	/* DATA14 */
-			select_peripheral(PD(9),  PERIPH_A, 0);	/* DATA15 */
-			select_peripheral(PE(13), PERIPH_B, 0);	/* DATA16 */
-			select_peripheral(PE(14), PERIPH_B, 0);	/* DATA17 */
-			select_peripheral(PE(15), PERIPH_B, 0);	/* DATA18 */
-			select_peripheral(PE(16), PERIPH_B, 0);	/* DATA19 */
-			select_peripheral(PE(17), PERIPH_B, 0);	/* DATA20 */
-			select_peripheral(PE(18), PERIPH_B, 0);	/* DATA21 */
-			select_peripheral(PD(16), PERIPH_A, 0);	/* DATA22 */
-			select_peripheral(PD(17), PERIPH_A, 0);	/* DATA23 */
-			break;
-		default:
-			goto err_invalid_id;
-		}
+		if (pin_mask == 0ULL)
+			/* Default to "full" lcdc control signals and 24bit */
+			pin_mask = ATMEL_LCDC_PRI_24BIT | ATMEL_LCDC_PRI_CONTROL;
+
+		/* LCDC on port C */
+		portc_mask = (pin_mask & 0xfff80000) >> 19;
+		select_peripheral(PIOC, portc_mask, PERIPH_A, 0);
+
+		/* LCDC on port D */
+		portd_mask = pin_mask & 0x0003ffff;
+		select_peripheral(PIOD, portd_mask, PERIPH_A, 0);
+
+		/* LCDC on port E */
+		porte_mask = (pin_mask >> 32) & 0x0007ffff;
+		select_peripheral(PIOE, porte_mask, PERIPH_B, 0);
 
 		clk_set_parent(&atmel_lcdfb0_pixclk, &pll0);
 		clk_set_rate(&atmel_lcdfb0_pixclk, clk_get_rate(&pll0));
@@ -1499,6 +1528,7 @@
 struct platform_device *__init at32_add_device_pwm(u32 mask)
 {
 	struct platform_device *pdev;
+	u32 pin_mask;
 
 	if (!mask)
 		return NULL;
@@ -1514,14 +1544,21 @@
 	if (platform_device_add_data(pdev, &mask, sizeof(mask)))
 		goto out_free_pdev;
 
+	pin_mask = 0;
 	if (mask & (1 << 0))
-		select_peripheral(PA(28), PERIPH_A, 0);
+		pin_mask |= (1 << 28);
 	if (mask & (1 << 1))
-		select_peripheral(PA(29), PERIPH_A, 0);
+		pin_mask |= (1 << 29);
+	if (pin_mask > 0)
+		select_peripheral(PIOA, pin_mask, PERIPH_A, 0);
+
+	pin_mask = 0;
 	if (mask & (1 << 2))
-		select_peripheral(PA(21), PERIPH_B, 0);
+		pin_mask |= (1 << 21);
 	if (mask & (1 << 3))
-		select_peripheral(PA(22), PERIPH_B, 0);
+		pin_mask |= (1 << 22);
+	if (pin_mask > 0)
+		select_peripheral(PIOA, pin_mask, PERIPH_B, 0);
 
 	atmel_pwm0_mck.dev = &pdev->dev;
 
@@ -1562,52 +1599,65 @@
 at32_add_device_ssc(unsigned int id, unsigned int flags)
 {
 	struct platform_device *pdev;
+	u32 pin_mask = 0;
 
 	switch (id) {
 	case 0:
 		pdev = &ssc0_device;
 		if (flags & ATMEL_SSC_RF)
-			select_peripheral(PA(21), PERIPH_A, 0);	/* RF */
+			pin_mask |= (1 << 21);	/* RF */
 		if (flags & ATMEL_SSC_RK)
-			select_peripheral(PA(22), PERIPH_A, 0);	/* RK */
+			pin_mask |= (1 << 22);	/* RK */
 		if (flags & ATMEL_SSC_TK)
-			select_peripheral(PA(23), PERIPH_A, 0);	/* TK */
+			pin_mask |= (1 << 23);	/* TK */
 		if (flags & ATMEL_SSC_TF)
-			select_peripheral(PA(24), PERIPH_A, 0);	/* TF */
+			pin_mask |= (1 << 24);	/* TF */
 		if (flags & ATMEL_SSC_TD)
-			select_peripheral(PA(25), PERIPH_A, 0);	/* TD */
+			pin_mask |= (1 << 25);	/* TD */
 		if (flags & ATMEL_SSC_RD)
-			select_peripheral(PA(26), PERIPH_A, 0);	/* RD */
+			pin_mask |= (1 << 26);	/* RD */
+
+		if (pin_mask > 0)
+			select_peripheral(PIOA, pin_mask, PERIPH_A, 0);
+
 		break;
 	case 1:
 		pdev = &ssc1_device;
 		if (flags & ATMEL_SSC_RF)
-			select_peripheral(PA(0), PERIPH_B, 0);	/* RF */
+			pin_mask |= (1 << 0);	/* RF */
 		if (flags & ATMEL_SSC_RK)
-			select_peripheral(PA(1), PERIPH_B, 0);	/* RK */
+			pin_mask |= (1 << 1);	/* RK */
 		if (flags & ATMEL_SSC_TK)
-			select_peripheral(PA(2), PERIPH_B, 0);	/* TK */
+			pin_mask |= (1 << 2);	/* TK */
 		if (flags & ATMEL_SSC_TF)
-			select_peripheral(PA(3), PERIPH_B, 0);	/* TF */
+			pin_mask |= (1 << 3);	/* TF */
 		if (flags & ATMEL_SSC_TD)
-			select_peripheral(PA(4), PERIPH_B, 0);	/* TD */
+			pin_mask |= (1 << 4);	/* TD */
 		if (flags & ATMEL_SSC_RD)
-			select_peripheral(PA(5), PERIPH_B, 0);	/* RD */
+			pin_mask |= (1 << 5);	/* RD */
+
+		if (pin_mask > 0)
+			select_peripheral(PIOA, pin_mask, PERIPH_B, 0);
+
 		break;
 	case 2:
 		pdev = &ssc2_device;
 		if (flags & ATMEL_SSC_TD)
-			select_peripheral(PB(13), PERIPH_A, 0);	/* TD */
+			pin_mask |= (1 << 13);	/* TD */
 		if (flags & ATMEL_SSC_RD)
-			select_peripheral(PB(14), PERIPH_A, 0);	/* RD */
+			pin_mask |= (1 << 14);	/* RD */
 		if (flags & ATMEL_SSC_TK)
-			select_peripheral(PB(15), PERIPH_A, 0);	/* TK */
+			pin_mask |= (1 << 15);	/* TK */
 		if (flags & ATMEL_SSC_TF)
-			select_peripheral(PB(16), PERIPH_A, 0);	/* TF */
+			pin_mask |= (1 << 16);	/* TF */
 		if (flags & ATMEL_SSC_RF)
-			select_peripheral(PB(17), PERIPH_A, 0);	/* RF */
+			pin_mask |= (1 << 17);	/* RF */
 		if (flags & ATMEL_SSC_RK)
-			select_peripheral(PB(18), PERIPH_A, 0);	/* RK */
+			pin_mask |= (1 << 18);	/* RK */
+
+		if (pin_mask > 0)
+			select_peripheral(PIOB, pin_mask, PERIPH_A, 0);
+
 		break;
 	default:
 		return NULL;
@@ -1745,14 +1795,15 @@
 		unsigned int cs, unsigned int extint)
 {
 	static unsigned int extint_pin_map[4] __initdata = {
-		GPIO_PIN_PB(25),
-		GPIO_PIN_PB(26),
-		GPIO_PIN_PB(27),
-		GPIO_PIN_PB(28),
+		(1 << 25),
+		(1 << 26),
+		(1 << 27),
+		(1 << 28),
 	};
 	static bool common_pins_initialized __initdata = false;
 	unsigned int extint_pin;
 	int ret;
+	u32 pin_mask;
 
 	if (extint >= ARRAY_SIZE(extint_pin_map))
 		return -EINVAL;
@@ -1766,7 +1817,8 @@
 		if (ret)
 			return ret;
 
-		select_peripheral(PE(21), PERIPH_A, 0); /* NCS4   -> OE_N  */
+		/* NCS4   -> OE_N  */
+		select_peripheral(PIOE, (1 << 21), PERIPH_A, 0);
 		hmatrix_sfr_set_bits(HMATRIX_SLAVE_EBI, HMATRIX_EBI_CF0_ENABLE);
 		break;
 	case 5:
@@ -1776,7 +1828,8 @@
 		if (ret)
 			return ret;
 
-		select_peripheral(PE(22), PERIPH_A, 0); /* NCS5   -> OE_N  */
+		/* NCS5   -> OE_N  */
+		select_peripheral(PIOE, (1 << 22), PERIPH_A, 0);
 		hmatrix_sfr_set_bits(HMATRIX_SLAVE_EBI, HMATRIX_EBI_CF1_ENABLE);
 		break;
 	default:
@@ -1784,14 +1837,17 @@
 	}
 
 	if (!common_pins_initialized) {
-		select_peripheral(PE(19), PERIPH_A, 0);	/* CFCE1  -> CS0_N */
-		select_peripheral(PE(20), PERIPH_A, 0);	/* CFCE2  -> CS1_N */
-		select_peripheral(PE(23), PERIPH_A, 0); /* CFRNW  -> DIR   */
-		select_peripheral(PE(24), PERIPH_A, 0); /* NWAIT  <- IORDY */
+		pin_mask  = (1 << 19);	/* CFCE1  -> CS0_N */
+		pin_mask |= (1 << 20);	/* CFCE2  -> CS1_N */
+		pin_mask |= (1 << 23);	/* CFRNW  -> DIR   */
+		pin_mask |= (1 << 24);	/* NWAIT  <- IORDY */
+
+		select_peripheral(PIOE, pin_mask, PERIPH_A, 0);
+
 		common_pins_initialized = true;
 	}
 
-	at32_select_periph(extint_pin, GPIO_PERIPH_A, AT32_GPIOF_DEGLITCH);
+	select_peripheral(PIOB, extint_pin, PERIPH_A, AT32_GPIOF_DEGLITCH);
 
 	pdev->resource[1].start = EIM_IRQ_BASE + extint;
 	pdev->resource[1].end = pdev->resource[1].start;
@@ -1930,6 +1986,7 @@
 {
 	struct platform_device *pdev;
 	struct ac97c_platform_data _data;
+	u32 pin_mask;
 
 	if (id != 0)
 		return NULL;
@@ -1956,10 +2013,10 @@
 				sizeof(struct ac97c_platform_data)))
 		goto fail;
 
-	select_peripheral(PB(20), PERIPH_B, 0);	/* SDO	*/
-	select_peripheral(PB(21), PERIPH_B, 0);	/* SYNC	*/
-	select_peripheral(PB(22), PERIPH_B, 0);	/* SCLK	*/
-	select_peripheral(PB(23), PERIPH_B, 0);	/* SDI	*/
+	pin_mask  = (1 << 20) | (1 << 21);	/* SDO & SYNC */
+	pin_mask |= (1 << 22) | (1 << 23);	/* SCLK & SDI */
+
+	select_peripheral(PIOB, pin_mask, PERIPH_B, 0);
 
 	/* TODO: gpio_is_valid(data->reset_pin) with kernel 2.6.26. */
 	if (data->reset_pin != GPIO_PIN_NONE)
@@ -2001,6 +2058,7 @@
 struct platform_device *__init at32_add_device_abdac(unsigned int id)
 {
 	struct platform_device *pdev;
+	u32 pin_mask;
 
 	if (id != 0)
 		return NULL;
@@ -2013,10 +2071,10 @@
 				ARRAY_SIZE(abdac0_resource)))
 		goto err_add_resources;
 
-	select_peripheral(PB(20), PERIPH_A, 0);	/* DATA1	*/
-	select_peripheral(PB(21), PERIPH_A, 0);	/* DATA0	*/
-	select_peripheral(PB(22), PERIPH_A, 0);	/* DATAN1	*/
-	select_peripheral(PB(23), PERIPH_A, 0);	/* DATAN0	*/
+	pin_mask  = (1 << 20) | (1 << 22);	/* DATA1 & DATAN1 */
+	pin_mask |= (1 << 21) | (1 << 23);	/* DATA0 & DATAN0 */
+
+	select_peripheral(PIOB, pin_mask, PERIPH_A, 0);
 
 	abdac0_pclk.dev = &pdev->dev;
 	abdac0_sample_clk.dev = &pdev->dev;
@@ -2073,7 +2131,7 @@
 	.index		= 4,
 };
 
-struct clk *at32_clock_list[] = {
+static __initdata struct clk *init_clocks[] = {
 	&osc32k,
 	&osc0,
 	&osc1,
@@ -2137,7 +2195,6 @@
 	&gclk3,
 	&gclk4,
 };
-unsigned int at32_nr_clocks = ARRAY_SIZE(at32_clock_list);
 
 void __init setup_platform(void)
 {
@@ -2168,14 +2225,19 @@
 	genclk_init_parent(&abdac0_sample_clk);
 
 	/*
-	 * Turn on all clocks that have at least one user already, and
-	 * turn off everything else. We only do this for module
-	 * clocks, and even though it isn't particularly pretty to
-	 * check the address of the mode function, it should do the
-	 * trick...
+	 * Build initial dynamic clock list by registering all clocks
+	 * from the array.
+	 * At the same time, turn on all clocks that have at least one
+	 * user already, and turn off everything else. We only do this
+	 * for module clocks, and even though it isn't particularly
+	 * pretty to  check the address of the mode function, it should
+	 * do the trick...
 	 */
-	for (i = 0; i < ARRAY_SIZE(at32_clock_list); i++) {
-		struct clk *clk = at32_clock_list[i];
+	for (i = 0; i < ARRAY_SIZE(init_clocks); i++) {
+		struct clk *clk = init_clocks[i];
+
+		/* first, register clock */
+		at32_clk_register(clk);
 
 		if (clk->users == 0)
 			continue;
diff --git a/arch/avr32/mach-at32ap/clock.c b/arch/avr32/mach-at32ap/clock.c
index 6c27dda..138a00a 100644
--- a/arch/avr32/mach-at32ap/clock.c
+++ b/arch/avr32/mach-at32ap/clock.c
@@ -15,24 +15,40 @@
 #include <linux/err.h>
 #include <linux/device.h>
 #include <linux/string.h>
+#include <linux/list.h>
 
 #include <mach/chip.h>
 
 #include "clock.h"
 
+/* at32 clock list */
+static LIST_HEAD(at32_clock_list);
+
 static DEFINE_SPINLOCK(clk_lock);
+static DEFINE_SPINLOCK(clk_list_lock);
+
+void at32_clk_register(struct clk *clk)
+{
+	spin_lock(&clk_list_lock);
+	/* add the new item to the end of the list */
+	list_add_tail(&clk->list, &at32_clock_list);
+	spin_unlock(&clk_list_lock);
+}
 
 struct clk *clk_get(struct device *dev, const char *id)
 {
-	int i;
+	struct clk *clk;
 
-	for (i = 0; i < at32_nr_clocks; i++) {
-		struct clk *clk = at32_clock_list[i];
+	spin_lock(&clk_list_lock);
 
-		if (clk->dev == dev && strcmp(id, clk->name) == 0)
+	list_for_each_entry(clk, &at32_clock_list, list) {
+		if (clk->dev == dev && strcmp(id, clk->name) == 0) {
+			spin_unlock(&clk_list_lock);
 			return clk;
+		}
 	}
 
+	spin_unlock(&clk_list_lock);
 	return ERR_PTR(-ENOENT);
 }
 EXPORT_SYMBOL(clk_get);
@@ -203,8 +219,8 @@
 
 	/* cost of this scan is small, but not linear... */
 	r->nest = nest + NEST_DELTA;
-	for (i = 3; i < at32_nr_clocks; i++) {
-		clk = at32_clock_list[i];
+
+	list_for_each_entry(clk, &at32_clock_list, list) {
 		if (clk->parent == parent)
 			dump_clock(clk, r);
 	}
@@ -215,6 +231,7 @@
 {
 	struct clkinf	r;
 	int		i;
+	struct clk 	*clk;
 
 	/* show all the power manager registers */
 	seq_printf(s, "MCCTRL  = %8x\n", pm_readl(MCCTRL));
@@ -234,14 +251,25 @@
 
 	seq_printf(s, "\n");
 
-	/* show clock tree as derived from the three oscillators
-	 * we "know" are at the head of the list
-	 */
 	r.s = s;
 	r.nest = 0;
-	dump_clock(at32_clock_list[0], &r);
-	dump_clock(at32_clock_list[1], &r);
-	dump_clock(at32_clock_list[2], &r);
+	/* protected from changes on the list while dumping */
+	spin_lock(&clk_list_lock);
+
+	/* show clock tree as derived from the three oscillators */
+	clk = clk_get(NULL, "osc32k");
+	dump_clock(clk, &r);
+	clk_put(clk);
+
+	clk = clk_get(NULL, "osc0");
+	dump_clock(clk, &r);
+	clk_put(clk);
+
+	clk = clk_get(NULL, "osc1");
+	dump_clock(clk, &r);
+	clk_put(clk);
+
+	spin_unlock(&clk_list_lock);
 
 	return 0;
 }
diff --git a/arch/avr32/mach-at32ap/clock.h b/arch/avr32/mach-at32ap/clock.h
index bb8e1f2..623bf0e 100644
--- a/arch/avr32/mach-at32ap/clock.h
+++ b/arch/avr32/mach-at32ap/clock.h
@@ -12,8 +12,13 @@
  * published by the Free Software Foundation.
  */
 #include <linux/clk.h>
+#include <linux/list.h>
+
+
+void at32_clk_register(struct clk *clk);
 
 struct clk {
+	struct list_head list;		/* linking element */
 	const char	*name;		/* Clock name/function */
 	struct device	*dev;		/* Device the clock is used by */
 	struct clk	*parent;	/* Parent clock, if any */
@@ -25,6 +30,3 @@
 	u16		users;		/* Enabled if non-zero */
 	u16		index;		/* Sibling index */
 };
-
-extern struct clk *at32_clock_list[];
-extern unsigned int at32_nr_clocks;
diff --git a/arch/avr32/mach-at32ap/include/mach/at32ap700x.h b/arch/avr32/mach-at32ap/include/mach/at32ap700x.h
index 1e9852d..a77d372 100644
--- a/arch/avr32/mach-at32ap/include/mach/at32ap700x.h
+++ b/arch/avr32/mach-at32ap/include/mach/at32ap700x.h
@@ -83,4 +83,132 @@
 #define HMATRIX_BASE	0xfff00800
 #define SDRAMC_BASE	0xfff03800
 
+/* LCDC on port C */
+#define ATMEL_LCDC_PC_CC	(1ULL << 19)
+#define ATMEL_LCDC_PC_HSYNC	(1ULL << 20)
+#define ATMEL_LCDC_PC_PCLK	(1ULL << 21)
+#define ATMEL_LCDC_PC_VSYNC	(1ULL << 22)
+#define ATMEL_LCDC_PC_DVAL	(1ULL << 23)
+#define ATMEL_LCDC_PC_MODE	(1ULL << 24)
+#define ATMEL_LCDC_PC_PWR	(1ULL << 25)
+#define ATMEL_LCDC_PC_DATA0	(1ULL << 26)
+#define ATMEL_LCDC_PC_DATA1	(1ULL << 27)
+#define ATMEL_LCDC_PC_DATA2	(1ULL << 28)
+#define ATMEL_LCDC_PC_DATA3	(1ULL << 29)
+#define ATMEL_LCDC_PC_DATA4	(1ULL << 30)
+#define ATMEL_LCDC_PC_DATA5	(1ULL << 31)
+
+/* LCDC on port D */
+#define ATMEL_LCDC_PD_DATA6	(1ULL << 0)
+#define ATMEL_LCDC_PD_DATA7	(1ULL << 1)
+#define ATMEL_LCDC_PD_DATA8	(1ULL << 2)
+#define ATMEL_LCDC_PD_DATA9	(1ULL << 3)
+#define ATMEL_LCDC_PD_DATA10	(1ULL << 4)
+#define ATMEL_LCDC_PD_DATA11	(1ULL << 5)
+#define ATMEL_LCDC_PD_DATA12	(1ULL << 6)
+#define ATMEL_LCDC_PD_DATA13	(1ULL << 7)
+#define ATMEL_LCDC_PD_DATA14	(1ULL << 8)
+#define ATMEL_LCDC_PD_DATA15	(1ULL << 9)
+#define ATMEL_LCDC_PD_DATA16	(1ULL << 10)
+#define ATMEL_LCDC_PD_DATA17	(1ULL << 11)
+#define ATMEL_LCDC_PD_DATA18	(1ULL << 12)
+#define ATMEL_LCDC_PD_DATA19	(1ULL << 13)
+#define ATMEL_LCDC_PD_DATA20	(1ULL << 14)
+#define ATMEL_LCDC_PD_DATA21	(1ULL << 15)
+#define ATMEL_LCDC_PD_DATA22	(1ULL << 16)
+#define ATMEL_LCDC_PD_DATA23	(1ULL << 17)
+
+/* LCDC on port E */
+#define ATMEL_LCDC_PE_CC	(1ULL << (32 + 0))
+#define ATMEL_LCDC_PE_DVAL	(1ULL << (32 + 1))
+#define ATMEL_LCDC_PE_MODE	(1ULL << (32 + 2))
+#define ATMEL_LCDC_PE_DATA0	(1ULL << (32 + 3))
+#define ATMEL_LCDC_PE_DATA1	(1ULL << (32 + 4))
+#define ATMEL_LCDC_PE_DATA2	(1ULL << (32 + 5))
+#define ATMEL_LCDC_PE_DATA3	(1ULL << (32 + 6))
+#define ATMEL_LCDC_PE_DATA4	(1ULL << (32 + 7))
+#define ATMEL_LCDC_PE_DATA8	(1ULL << (32 + 8))
+#define ATMEL_LCDC_PE_DATA9	(1ULL << (32 + 9))
+#define ATMEL_LCDC_PE_DATA10	(1ULL << (32 + 10))
+#define ATMEL_LCDC_PE_DATA11	(1ULL << (32 + 11))
+#define ATMEL_LCDC_PE_DATA12	(1ULL << (32 + 12))
+#define ATMEL_LCDC_PE_DATA16	(1ULL << (32 + 13))
+#define ATMEL_LCDC_PE_DATA17	(1ULL << (32 + 14))
+#define ATMEL_LCDC_PE_DATA18	(1ULL << (32 + 15))
+#define ATMEL_LCDC_PE_DATA19	(1ULL << (32 + 16))
+#define ATMEL_LCDC_PE_DATA20	(1ULL << (32 + 17))
+#define ATMEL_LCDC_PE_DATA21	(1ULL << (32 + 18))
+
+
+#define ATMEL_LCDC(PORT, PIN)	(ATMEL_LCDC_##PORT##_##PIN)
+
+
+#define ATMEL_LCDC_PRI_24B_DATA	(					\
+		ATMEL_LCDC(PC, DATA0)  | ATMEL_LCDC(PC, DATA1)  |	\
+		ATMEL_LCDC(PC, DATA2)  | ATMEL_LCDC(PC, DATA3)  |	\
+		ATMEL_LCDC(PC, DATA4)  | ATMEL_LCDC(PC, DATA5)  |	\
+		ATMEL_LCDC(PD, DATA6)  | ATMEL_LCDC(PD, DATA7)  |	\
+		ATMEL_LCDC(PD, DATA8)  | ATMEL_LCDC(PD, DATA9)  |	\
+		ATMEL_LCDC(PD, DATA10) | ATMEL_LCDC(PD, DATA11) |	\
+		ATMEL_LCDC(PD, DATA12) | ATMEL_LCDC(PD, DATA13) |	\
+		ATMEL_LCDC(PD, DATA14) | ATMEL_LCDC(PD, DATA15) |	\
+		ATMEL_LCDC(PD, DATA16) | ATMEL_LCDC(PD, DATA17) |	\
+		ATMEL_LCDC(PD, DATA18) | ATMEL_LCDC(PD, DATA19) |	\
+		ATMEL_LCDC(PD, DATA20) | ATMEL_LCDC(PD, DATA21) |	\
+		ATMEL_LCDC(PD, DATA22) | ATMEL_LCDC(PD, DATA23))
+
+#define ATMEL_LCDC_ALT_24B_DATA (					\
+		ATMEL_LCDC(PE, DATA0)  | ATMEL_LCDC(PE, DATA1)  |	\
+		ATMEL_LCDC(PE, DATA2)  | ATMEL_LCDC(PE, DATA3)  |	\
+		ATMEL_LCDC(PE, DATA4)  | ATMEL_LCDC(PC, DATA5)  |	\
+		ATMEL_LCDC(PD, DATA6)  | ATMEL_LCDC(PD, DATA7)  |	\
+		ATMEL_LCDC(PE, DATA8)  | ATMEL_LCDC(PE, DATA9)  |	\
+		ATMEL_LCDC(PE, DATA10) | ATMEL_LCDC(PE, DATA11) |	\
+		ATMEL_LCDC(PE, DATA12) | ATMEL_LCDC(PD, DATA13) |	\
+		ATMEL_LCDC(PD, DATA14) | ATMEL_LCDC(PD, DATA15) |	\
+		ATMEL_LCDC(PE, DATA16) | ATMEL_LCDC(PE, DATA17) |	\
+		ATMEL_LCDC(PE, DATA18) | ATMEL_LCDC(PE, DATA19) |	\
+		ATMEL_LCDC(PE, DATA20) | ATMEL_LCDC(PE, DATA21) |	\
+		ATMEL_LCDC(PD, DATA22) | ATMEL_LCDC(PD, DATA23))
+
+#define ATMEL_LCDC_PRI_15B_DATA (					\
+		ATMEL_LCDC(PC, DATA0)  | ATMEL_LCDC(PC, DATA1)  |	\
+		ATMEL_LCDC(PC, DATA2)  | ATMEL_LCDC(PC, DATA3)  |	\
+		ATMEL_LCDC(PC, DATA4)  | ATMEL_LCDC(PC, DATA5)  |	\
+		ATMEL_LCDC(PD, DATA8)  | ATMEL_LCDC(PD, DATA9)  |	\
+		ATMEL_LCDC(PD, DATA10) | ATMEL_LCDC(PD, DATA11) |	\
+		ATMEL_LCDC(PD, DATA12) | ATMEL_LCDC(PD, DATA16) |	\
+		ATMEL_LCDC(PD, DATA17) | ATMEL_LCDC(PD, DATA18) |	\
+		ATMEL_LCDC(PD, DATA19) | ATMEL_LCDC(PD, DATA20))
+
+#define ATMEL_LCDC_ALT_15B_DATA	(					\
+		ATMEL_LCDC(PE, DATA0)  | ATMEL_LCDC(PE, DATA1)  |	\
+		ATMEL_LCDC(PE, DATA2)  | ATMEL_LCDC(PE, DATA3)  |	\
+		ATMEL_LCDC(PE, DATA4)  | ATMEL_LCDC(PC, DATA5)  |	\
+		ATMEL_LCDC(PE, DATA8)  | ATMEL_LCDC(PE, DATA9)  |	\
+		ATMEL_LCDC(PE, DATA10) | ATMEL_LCDC(PE, DATA11) |	\
+		ATMEL_LCDC(PE, DATA12) | ATMEL_LCDC(PE, DATA16) |	\
+		ATMEL_LCDC(PE, DATA17) | ATMEL_LCDC(PE, DATA18) |	\
+		ATMEL_LCDC(PE, DATA19) | ATMEL_LCDC(PE, DATA20))
+
+#define ATMEL_LCDC_PRI_CONTROL (					\
+		ATMEL_LCDC(PC, CC)   | ATMEL_LCDC(PC, DVAL) |		\
+		ATMEL_LCDC(PC, MODE) | ATMEL_LCDC(PC, PWR))
+
+#define ATMEL_LCDC_ALT_CONTROL (					\
+		ATMEL_LCDC(PE, CC)   | ATMEL_LCDC(PE, DVAL) |		\
+		ATMEL_LCDC(PE, MODE) | ATMEL_LCDC(PC, PWR))
+
+#define ATMEL_LCDC_CONTROL (						\
+		ATMEL_LCDC(PC, HSYNC) | ATMEL_LCDC(PC, VSYNC) |		\
+		ATMEL_LCDC(PC, PCLK))
+
+#define ATMEL_LCDC_PRI_24BIT	(ATMEL_LCDC_CONTROL | ATMEL_LCDC_PRI_24B_DATA)
+
+#define ATMEL_LCDC_ALT_24BIT	(ATMEL_LCDC_CONTROL | ATMEL_LCDC_ALT_24B_DATA)
+
+#define ATMEL_LCDC_PRI_15BIT	(ATMEL_LCDC_CONTROL | ATMEL_LCDC_PRI_15B_DATA)
+
+#define ATMEL_LCDC_ALT_15BIT	(ATMEL_LCDC_CONTROL | ATMEL_LCDC_ALT_15B_DATA)
+
 #endif /* __ASM_ARCH_AT32AP700X_H__ */
diff --git a/arch/avr32/mach-at32ap/include/mach/board.h b/arch/avr32/mach-at32ap/include/mach/board.h
index e60e907..c48386d 100644
--- a/arch/avr32/mach-at32ap/include/mach/board.h
+++ b/arch/avr32/mach-at32ap/include/mach/board.h
@@ -43,7 +43,7 @@
 struct platform_device *
 at32_add_device_lcdc(unsigned int id, struct atmel_lcdfb_info *data,
 		     unsigned long fbmem_start, unsigned long fbmem_len,
-		     unsigned int pin_config);
+		     u64 pin_mask);
 
 struct usba_platform_data;
 struct platform_device *
diff --git a/arch/avr32/mach-at32ap/include/mach/io.h b/arch/avr32/mach-at32ap/include/mach/io.h
index 4ec6abc..22ea79b 100644
--- a/arch/avr32/mach-at32ap/include/mach/io.h
+++ b/arch/avr32/mach-at32ap/include/mach/io.h
@@ -1,8 +1,7 @@
 #ifndef __ASM_AVR32_ARCH_AT32AP_IO_H
 #define __ASM_AVR32_ARCH_AT32AP_IO_H
 
-/* For "bizarre" halfword swapping */
-#include <linux/byteorder/swabb.h>
+#include <linux/swab.h>
 
 #if defined(CONFIG_AP700X_32_BIT_SMC)
 # define __swizzle_addr_b(addr)	(addr ^ 3UL)
diff --git a/arch/avr32/mach-at32ap/include/mach/portmux.h b/arch/avr32/mach-at32ap/include/mach/portmux.h
index b1abe6b..21c7937 100644
--- a/arch/avr32/mach-at32ap/include/mach/portmux.h
+++ b/arch/avr32/mach-at32ap/include/mach/portmux.h
@@ -21,9 +21,10 @@
 #define AT32_GPIOF_DEGLITCH	0x00000008	/* (IN) Filter glitches */
 #define AT32_GPIOF_MULTIDRV	0x00000010	/* Enable multidriver option */
 
-void at32_select_periph(unsigned int pin, unsigned int periph,
-			unsigned long flags);
+void at32_select_periph(unsigned int port, unsigned int pin,
+			unsigned int periph, unsigned long flags);
 void at32_select_gpio(unsigned int pin, unsigned long flags);
+void at32_deselect_pin(unsigned int pin);
 void at32_reserve_pin(unsigned int pin);
 
 #endif /* __ASM_ARCH_PORTMUX_H__ */
diff --git a/arch/avr32/mach-at32ap/pdc.c b/arch/avr32/mach-at32ap/pdc.c
index 1040bda..61ab15a 100644
--- a/arch/avr32/mach-at32ap/pdc.c
+++ b/arch/avr32/mach-at32ap/pdc.c
@@ -35,7 +35,6 @@
 }
 
 static struct platform_driver pdc_driver = {
-	.probe		= pdc_probe,
 	.driver		= {
 		.name	= "pdc",
 	},
@@ -43,6 +42,6 @@
 
 static int __init pdc_init(void)
 {
-	return platform_driver_register(&pdc_driver);
+	return platform_driver_probe(&pdc_driver, pdc_probe);
 }
 arch_initcall(pdc_init);
diff --git a/arch/avr32/mach-at32ap/pio.c b/arch/avr32/mach-at32ap/pio.c
index 405ee6b..ed81a8b 100644
--- a/arch/avr32/mach-at32ap/pio.c
+++ b/arch/avr32/mach-at32ap/pio.c
@@ -50,35 +50,48 @@
 }
 
 /* Pin multiplexing API */
+static DEFINE_SPINLOCK(pio_lock);
 
-void __init at32_select_periph(unsigned int pin, unsigned int periph,
-			       unsigned long flags)
+void __init at32_select_periph(unsigned int port, u32 pin_mask,
+			       unsigned int periph, unsigned long flags)
 {
 	struct pio_device *pio;
-	unsigned int pin_index = pin & 0x1f;
-	u32 mask = 1 << pin_index;
 
-	pio = gpio_to_pio(pin);
+	/* assign and verify pio */
+	pio = gpio_to_pio(port);
 	if (unlikely(!pio)) {
-		printk("pio: invalid pin %u\n", pin);
+		printk(KERN_WARNING "pio: invalid port %u\n", port);
 		goto fail;
 	}
 
-	if (unlikely(test_and_set_bit(pin_index, &pio->pinmux_mask)
-			 || gpiochip_is_requested(&pio->chip, pin_index))) {
-		printk("%s: pin %u is busy\n", pio->name, pin_index);
+	/* Test if any of the requested pins is already muxed */
+	spin_lock(&pio_lock);
+	if (unlikely(pio->pinmux_mask & pin_mask)) {
+		printk(KERN_WARNING "%s: pin(s) busy (requested 0x%x, busy 0x%x)\n",
+		       pio->name, pin_mask, pio->pinmux_mask & pin_mask);
+		spin_unlock(&pio_lock);
 		goto fail;
 	}
 
-	pio_writel(pio, PUER, mask);
+	pio->pinmux_mask |= pin_mask;
+
+	/* enable pull ups */
+	pio_writel(pio, PUER, pin_mask);
+
+	/* select either peripheral A or B */
 	if (periph)
-		pio_writel(pio, BSR, mask);
+		pio_writel(pio, BSR, pin_mask);
 	else
-		pio_writel(pio, ASR, mask);
+		pio_writel(pio, ASR, pin_mask);
 
-	pio_writel(pio, PDR, mask);
+	/* enable peripheral control */
+	pio_writel(pio, PDR, pin_mask);
+
+	/* Disable pull ups if not requested. */
 	if (!(flags & AT32_GPIOF_PULLUP))
-		pio_writel(pio, PUDR, mask);
+		pio_writel(pio, PUDR, pin_mask);
+
+	spin_unlock(&pio_lock);
 
 	return;
 
@@ -134,6 +147,25 @@
 	dump_stack();
 }
 
+/*
+ * Undo a previous pin reservation. Will not affect the hardware
+ * configuration.
+ */
+void at32_deselect_pin(unsigned int pin)
+{
+	struct pio_device *pio;
+	unsigned int pin_index = pin & 0x1f;
+
+	pio = gpio_to_pio(pin);
+	if (unlikely(!pio)) {
+		printk("pio: invalid pin %u\n", pin);
+		dump_stack();
+		return;
+	}
+
+	clear_bit(pin_index, &pio->pinmux_mask);
+}
+
 /* Reserve a pin, preventing anyone else from changing its configuration. */
 void __init at32_reserve_pin(unsigned int pin)
 {
@@ -382,7 +414,6 @@
 }
 
 static struct platform_driver pio_driver = {
-	.probe		= pio_probe,
 	.driver		= {
 		.name		= "pio",
 	},
@@ -390,7 +421,7 @@
 
 static int __init pio_init(void)
 {
-	return platform_driver_register(&pio_driver);
+	return platform_driver_probe(&pio_driver, pio_probe);
 }
 postcore_initcall(pio_init);
 
diff --git a/arch/avr32/oprofile/Makefile b/arch/avr32/oprofile/Makefile
index 1fe81c3..e0eb520 100644
--- a/arch/avr32/oprofile/Makefile
+++ b/arch/avr32/oprofile/Makefile
@@ -5,4 +5,4 @@
 				event_buffer.o oprofile_files.o		\
 				oprofilefs.o oprofile_stats.o		\
 				timer_int.o)
-oprofile-y		+= op_model_avr32.o
+oprofile-y		+= op_model_avr32.o backtrace.o
diff --git a/arch/avr32/oprofile/backtrace.c b/arch/avr32/oprofile/backtrace.c
new file mode 100644
index 0000000..75d9ad6
--- /dev/null
+++ b/arch/avr32/oprofile/backtrace.c
@@ -0,0 +1,81 @@
+/*
+ * AVR32 specific backtracing code for oprofile
+ *
+ * Copyright 2008 Weinmann GmbH
+ *
+ * Author: Nikolaus Voss <n.voss@weinmann.de>
+ *
+ * Based on i386 oprofile backtrace code by John Levon and David Smith
+ *
+ * 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/oprofile.h>
+#include <linux/sched.h>
+#include <linux/uaccess.h>
+
+/* The first two words of each frame on the stack look like this if we have
+ * frame pointers */
+struct frame_head {
+	unsigned long lr;
+	struct frame_head *fp;
+};
+
+/* copied from arch/avr32/kernel/process.c */
+static inline int valid_stack_ptr(struct thread_info *tinfo, unsigned long p)
+{
+	return (p > (unsigned long)tinfo)
+		&& (p < (unsigned long)tinfo + THREAD_SIZE - 3);
+}
+
+/* copied from arch/x86/oprofile/backtrace.c */
+static struct frame_head *dump_user_backtrace(struct frame_head *head)
+{
+	struct frame_head bufhead[2];
+
+	/* Also check accessibility of one struct frame_head beyond */
+	if (!access_ok(VERIFY_READ, head, sizeof(bufhead)))
+		return NULL;
+	if (__copy_from_user_inatomic(bufhead, head, sizeof(bufhead)))
+		return NULL;
+
+	oprofile_add_trace(bufhead[0].lr);
+
+	/* frame pointers should strictly progress back up the stack
+	 * (towards higher addresses) */
+	if (bufhead[0].fp <= head)
+		return NULL;
+
+	return bufhead[0].fp;
+}
+
+void avr32_backtrace(struct pt_regs * const regs, unsigned int depth)
+{
+	/* Get first frame pointer */
+	struct frame_head *head = (struct frame_head *)(regs->r7);
+
+	if (!user_mode(regs)) {
+#ifdef CONFIG_FRAME_POINTER
+		/*
+		 * Traverse the kernel stack from frame to frame up to
+		 * "depth" steps.
+		 */
+		while (depth-- && valid_stack_ptr(task_thread_info(current),
+						  (unsigned long)head)) {
+			oprofile_add_trace(head->lr);
+			if (head->fp <= head)
+				break;
+			head = head->fp;
+		}
+#endif
+	} else {
+		/* Assume we have frame pointers in user mode process */
+		while (depth-- && head)
+			head = dump_user_backtrace(head);
+	}
+}
+
+
diff --git a/arch/avr32/oprofile/op_model_avr32.c b/arch/avr32/oprofile/op_model_avr32.c
index df42325..a3e9b3c 100644
--- a/arch/avr32/oprofile/op_model_avr32.c
+++ b/arch/avr32/oprofile/op_model_avr32.c
@@ -22,6 +22,8 @@
 #define AVR32_PERFCTR_IRQ_GROUP	0
 #define AVR32_PERFCTR_IRQ_LINE	1
 
+void avr32_backtrace(struct pt_regs * const regs, unsigned int depth);
+
 enum { PCCNT, PCNT0, PCNT1, NR_counter };
 
 struct avr32_perf_counter {
@@ -223,6 +225,8 @@
 	memcpy(ops, &avr32_perf_counter_ops,
 			sizeof(struct oprofile_operations));
 
+	ops->backtrace = avr32_backtrace;
+
 	printk(KERN_INFO "oprofile: using AVR32 performance monitoring.\n");
 
 	return 0;
diff --git a/arch/blackfin/Kconfig b/arch/blackfin/Kconfig
index 4154ff1..8102c79 100644
--- a/arch/blackfin/Kconfig
+++ b/arch/blackfin/Kconfig
@@ -162,16 +162,28 @@
 config BF561
 	bool "BF561"
 	help
-	  Not Supported Yet - Work in progress - BF561 Processor Support.
+	  BF561 Processor Support.
 
 endchoice
 
+config BF_REV_MIN
+	int
+	default 0 if (BF52x || BF54x)
+	default 2 if (BF537 || BF536 || BF534)
+	default 3 if (BF561 ||BF533 || BF532 || BF531)
+
+config BF_REV_MAX
+	int
+	default 2 if (BF52x || BF54x)
+	default 3 if (BF537 || BF536 || BF534)
+	default 5 if (BF561)
+	default 6 if (BF533 || BF532 || BF531)
+
 choice
 	prompt "Silicon Rev"
-	default BF_REV_0_1 if BF527
-	default BF_REV_0_2 if BF537
-	default BF_REV_0_3 if BF533
-	default BF_REV_0_0 if BF549
+	default BF_REV_0_1 if (BF52x || BF54x)
+	default BF_REV_0_2 if (BF534 || BF536 || BF537)
+	default BF_REV_0_3 if (BF531 || BF532 || BF533 || BF561)
 
 config BF_REV_0_0
 	bool "0.0"
@@ -183,7 +195,7 @@
 
 config BF_REV_0_2
 	bool "0.2"
-	depends on (BF537 || BF536 || BF534)
+	depends on (BF52x || BF537 || BF536 || BF534 || BF54x)
 
 config BF_REV_0_3
 	bool "0.3"
@@ -197,6 +209,10 @@
 	bool "0.5"
 	depends on (BF561 || BF533 || BF532 || BF531)
 
+config BF_REV_0_6
+	bool "0.6"
+	depends on (BF533 || BF532 || BF531)
+
 config BF_REV_ANY
 	bool "any"
 
@@ -249,7 +265,7 @@
 
 config MEM_MT48LC32M16A2TG_75
 	bool
-	depends on (BFIN527_EZKIT || BFIN532_IP0X || BLACKSTAMP)
+	depends on (BFIN527_EZKIT || BFIN532_IP0X || BLACKSTAMP || BFIN526_EZBRD)
 	default y
 
 source "arch/blackfin/mach-bf527/Kconfig"
@@ -286,13 +302,20 @@
 	  memory region is used to capture NULL pointer references as well
 	  as some core kernel functions.
 
+config ROM_BASE
+	hex "Kernel ROM Base"
+	default "0x20040000"
+	range 0x20000000 0x20400000 if !(BF54x || BF561)
+	range 0x20000000 0x30000000 if (BF54x || BF561)
+	help
+
 comment "Clock/PLL Setup"
 
 config CLKIN_HZ
 	int "Frequency of the crystal on the board in Hz"
 	default "11059200" if BFIN533_STAMP
 	default "27000000" if BFIN533_EZKIT
-	default "25000000" if (BFIN537_STAMP || BFIN527_EZKIT || H8606_HVSISTEMAS || BLACKSTAMP)
+	default "25000000" if (BFIN537_STAMP || BFIN527_EZKIT || H8606_HVSISTEMAS || BLACKSTAMP || BFIN526_EZBRD)
 	default "30000000" if BFIN561_EZKIT
 	default "24576000" if PNAV10
 	default "10000000" if BFIN532_IP0X
@@ -332,7 +355,7 @@
 	default "22" if BFIN533_BLUETECHNIX_CM
 	default "20" if (BFIN537_BLUETECHNIX_CM || BFIN527_BLUETECHNIX_CM || BFIN561_BLUETECHNIX_CM)
 	default "20" if BFIN561_EZKIT
-	default "16" if (H8606_HVSISTEMAS || BLACKSTAMP)
+	default "16" if (H8606_HVSISTEMAS || BLACKSTAMP || BFIN526_EZBRD)
 	help
 	  This controls the frequency of the on-chip PLL. This can be between 1 and 64.
 	  PLL Frequency = (Crystal Frequency) * (this setting)
@@ -368,14 +391,6 @@
 	  This can be between 1 and 15
 	  System Clock = (PLL frequency) / (this setting)
 
-config MAX_MEM_SIZE
-	int "Max SDRAM Memory Size in MBytes"
-	depends on !MPU
-	default 512
-	help
-	  This is the max memory size that the kernel will create CPLB
-	  tables for.  Your system will not be able to handle any more.
-
 choice
 	prompt "DDR SDRAM Chip Type"
 	depends on BFIN_KERNEL_CLOCK
@@ -389,6 +404,14 @@
 	bool "MT46V32M16_5B"
 endchoice
 
+config MAX_MEM_SIZE
+	int "Max SDRAM Memory Size in MBytes"
+	depends on !MPU
+	default 512
+	help
+	  This is the max memory size that the kernel will create CPLB
+	  tables for.  Your system will not be able to handle any more.
+
 #
 # Max & Min Speeds for various Chips
 #
@@ -455,8 +478,6 @@
 
 source kernel/time/Kconfig
 
-comment "Memory Setup"
-
 comment "Misc"
 
 choice
@@ -622,6 +643,15 @@
 	  If enabled, the CPLB Switch Tables are linked
 	  into L1 data memory. (less latency)
 
+config APP_STACK_L1
+	bool "Support locating application stack in L1 Scratch Memory"
+	default y
+	help
+	  If enabled the application stack can be located in L1
+	  scratch memory (less latency).
+
+	  Currently only works with FLAT binaries.
+
 comment "Speed Optimizations"
 config BFIN_INS_LOWOVERHEAD
 	bool "ins[bwl] low overhead, higher interrupt latency"
@@ -755,6 +785,13 @@
 
 endchoice
 
+config BFIN_L2_CACHEABLE
+	bool "Cache L2 SRAM"
+	depends on (BFIN_DCACHE || BFIN_ICACHE) && (BF54x || BF561)
+	default n
+	help
+	  Select to make L2 SRAM cacheable in L1 data and instruction cache.
+
 config MPU
 	bool "Enable the memory protection unit (EXPERIMENTAL)"
 	default n
diff --git a/arch/blackfin/Kconfig.debug b/arch/blackfin/Kconfig.debug
index c468624..3ad2598 100644
--- a/arch/blackfin/Kconfig.debug
+++ b/arch/blackfin/Kconfig.debug
@@ -2,6 +2,22 @@
 
 source "lib/Kconfig.debug"
 
+config HAVE_ARCH_KGDB
+       def_bool y
+
+config DEBUG_VERBOSE
+	bool "Verbose fault messages"
+	default y
+	select PRINTK
+	help
+	  When a program crashes due to an exception, or the kernel detects
+	  an internal error, the kernel can print a not so brief message
+	  explaining what the problem was. This debugging information is
+	  useful to developers and kernel hackers when tracking down problems,
+	  but mostly meaningless to other people. This is always helpful for
+	  debugging but serves no purpose on a production system.
+	  Most people should say N here.
+
 config DEBUG_MMRS
 	bool "Generate Blackfin MMR tree"
 	select DEBUG_FS
@@ -22,6 +38,44 @@
 	  hardware error interrupts and need to know where they are coming
 	  from.
 
+config DEBUG_DOUBLEFAULT
+	bool "Debug Double Faults"
+	default n
+	help
+	  If an exception is caused while executing code within the exception
+	  handler, the NMI handler, the reset vector, or in emulator mode,
+	  a double fault occurs. On the Blackfin, this is a unrecoverable
+	  event. You have two options:
+	  - RESET exactly when double fault occurs. The excepting
+	    instruction address is stored in RETX, where the next kernel
+	    boot will print it out.
+	  - Print debug message. This is much more error prone, although
+	    easier to handle. It is error prone since:
+	    - The excepting instruction is not committed.
+	    - All writebacks from the instruction are prevented.
+	    - The generated exception is not taken.
+	    - The EXCAUSE field is updated with an unrecoverable event
+	    The only way to check this is to see if EXCAUSE contains the
+	    unrecoverable event value at every exception return. By selecting
+	    this option, you are skipping over the faulting instruction, and 
+	    hoping things stay together enough to print out a debug message.
+
+	  This does add a little kernel code, but is the only method to debug
+	  double faults - if unsure say "Y"
+
+choice
+	prompt "Double Fault Failure Method"
+	default DEBUG_DOUBLEFAULT_PRINT
+	depends on DEBUG_DOUBLEFAULT
+
+config DEBUG_DOUBLEFAULT_PRINT
+	bool "Print"
+
+config DEBUG_DOUBLEFAULT_RESET
+	bool "Reset"
+
+endchoice
+
 config DEBUG_ICACHE_CHECK
 	bool "Check Instruction cache coherency"
 	depends on DEBUG_KERNEL
@@ -143,6 +197,7 @@
 config EARLY_PRINTK
 	bool "Early printk" 
 	default n
+	select SERIAL_CORE_CONSOLE
 	help
 	  This option enables special console drivers which allow the kernel
 	  to print messages very early in the bootup process.
diff --git a/arch/blackfin/Makefile b/arch/blackfin/Makefile
index eac0533..6bf5097 100644
--- a/arch/blackfin/Makefile
+++ b/arch/blackfin/Makefile
@@ -67,6 +67,7 @@
 rev-$(CONFIG_BF_REV_0_3)  := 0.3
 rev-$(CONFIG_BF_REV_0_4)  := 0.4
 rev-$(CONFIG_BF_REV_0_5)  := 0.5
+rev-$(CONFIG_BF_REV_0_6)  := 0.6
 rev-$(CONFIG_BF_REV_NONE) := none
 rev-$(CONFIG_BF_REV_ANY)  := any
 
diff --git a/arch/blackfin/configs/BF526-EZBRD_defconfig b/arch/blackfin/configs/BF526-EZBRD_defconfig
new file mode 100644
index 0000000..c33bf6f
--- /dev/null
+++ b/arch/blackfin/configs/BF526-EZBRD_defconfig
@@ -0,0 +1,1427 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.26.3
+# Thu Aug 28 16:49:53 2008
+#
+# CONFIG_MMU is not set
+# CONFIG_FPU is not set
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
+CONFIG_BLACKFIN=y
+CONFIG_ZONE_DMA=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_GENERIC_GPIO=y
+CONFIG_FORCE_MAX_ZONEORDER=14
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=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=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_CGROUPS is not set
+# CONFIG_GROUP_SCHED is not set
+CONFIG_SYSFS_DEPRECATED=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+# CONFIG_RELAY is not set
+# CONFIG_NAMESPACES is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SYSCTL=y
+CONFIG_EMBEDDED=y
+CONFIG_UID16=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_SYSCTL_SYSCALL_CHECK=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_COMPAT_BRK=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_ANON_INODES=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
+# CONFIG_PROFILING is not set
+# CONFIG_MARKERS is not set
+CONFIG_HAVE_OPROFILE=y
+# CONFIG_HAVE_KPROBES is not set
+# CONFIG_HAVE_KRETPROBES is not set
+# CONFIG_HAVE_DMA_ATTRS is not set
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+CONFIG_TINY_SHMEM=y
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+# CONFIG_MODULE_FORCE_LOAD is not set
+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=y
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+# CONFIG_BLK_DEV_BSG is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+# CONFIG_IOSCHED_AS is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
+# CONFIG_DEFAULT_AS is not set
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+CONFIG_DEFAULT_NOOP=y
+CONFIG_DEFAULT_IOSCHED="noop"
+CONFIG_CLASSIC_RCU=y
+# CONFIG_PREEMPT_NONE is not set
+CONFIG_PREEMPT_VOLUNTARY=y
+# CONFIG_PREEMPT is not set
+
+#
+# Blackfin Processor Options
+#
+
+#
+# Processor and Board Settings
+#
+# CONFIG_BF522 is not set
+# CONFIG_BF523 is not set
+# CONFIG_BF524 is not set
+# CONFIG_BF525 is not set
+CONFIG_BF526=y
+# CONFIG_BF527 is not set
+# CONFIG_BF531 is not set
+# CONFIG_BF532 is not set
+# CONFIG_BF533 is not set
+# CONFIG_BF534 is not set
+# CONFIG_BF536 is not set
+# CONFIG_BF537 is not set
+# CONFIG_BF542 is not set
+# CONFIG_BF544 is not set
+# CONFIG_BF547 is not set
+# CONFIG_BF548 is not set
+# CONFIG_BF549 is not set
+# CONFIG_BF561 is not set
+CONFIG_BF_REV_0_0=y
+# CONFIG_BF_REV_0_1 is not set
+# CONFIG_BF_REV_0_2 is not set
+# CONFIG_BF_REV_0_3 is not set
+# CONFIG_BF_REV_0_4 is not set
+# CONFIG_BF_REV_0_5 is not set
+# CONFIG_BF_REV_ANY is not set
+# CONFIG_BF_REV_NONE is not set
+CONFIG_BF52x=y
+CONFIG_MEM_MT48LC32M16A2TG_75=y
+# CONFIG_BFIN527_EZKIT is not set
+# CONFIG_BFIN527_BLUETECHNIX_CM is not set
+CONFIG_BFIN526_EZBRD=y
+
+#
+# BF527 Specific Configuration
+#
+
+#
+# Alternative Multiplexing Scheme
+#
+# CONFIG_BF527_SPORT0_PORTF is not set
+CONFIG_BF527_SPORT0_PORTG=y
+CONFIG_BF527_SPORT0_TSCLK_PG10=y
+# CONFIG_BF527_SPORT0_TSCLK_PG14 is not set
+CONFIG_BF527_UART1_PORTF=y
+# CONFIG_BF527_UART1_PORTG is not set
+# CONFIG_BF527_NAND_D_PORTF is not set
+CONFIG_BF527_NAND_D_PORTH=y
+
+#
+# Interrupt Priority Assignment
+#
+
+#
+# Priority
+#
+CONFIG_IRQ_PLL_WAKEUP=7
+CONFIG_IRQ_DMA0_ERROR=7
+CONFIG_IRQ_DMAR0_BLK=7
+CONFIG_IRQ_DMAR1_BLK=7
+CONFIG_IRQ_DMAR0_OVR=7
+CONFIG_IRQ_DMAR1_OVR=7
+CONFIG_IRQ_PPI_ERROR=7
+CONFIG_IRQ_MAC_ERROR=7
+CONFIG_IRQ_SPORT0_ERROR=7
+CONFIG_IRQ_SPORT1_ERROR=7
+CONFIG_IRQ_UART0_ERROR=7
+CONFIG_IRQ_UART1_ERROR=7
+CONFIG_IRQ_RTC=8
+CONFIG_IRQ_PPI=8
+CONFIG_IRQ_SPORT0_RX=9
+CONFIG_IRQ_SPORT0_TX=9
+CONFIG_IRQ_SPORT1_RX=9
+CONFIG_IRQ_SPORT1_TX=9
+CONFIG_IRQ_TWI=10
+CONFIG_IRQ_SPI=10
+CONFIG_IRQ_UART0_RX=10
+CONFIG_IRQ_UART0_TX=10
+CONFIG_IRQ_UART1_RX=10
+CONFIG_IRQ_UART1_TX=10
+CONFIG_IRQ_OPTSEC=11
+CONFIG_IRQ_CNT=11
+CONFIG_IRQ_MAC_RX=11
+CONFIG_IRQ_PORTH_INTA=11
+CONFIG_IRQ_MAC_TX=11
+CONFIG_IRQ_PORTH_INTB=11
+CONFIG_IRQ_TMR0=12
+CONFIG_IRQ_TMR1=12
+CONFIG_IRQ_TMR2=12
+CONFIG_IRQ_TMR3=12
+CONFIG_IRQ_TMR4=12
+CONFIG_IRQ_TMR5=12
+CONFIG_IRQ_TMR6=12
+CONFIG_IRQ_TMR7=12
+CONFIG_IRQ_PORTG_INTA=12
+CONFIG_IRQ_PORTG_INTB=12
+CONFIG_IRQ_MEM_DMA0=13
+CONFIG_IRQ_MEM_DMA1=13
+CONFIG_IRQ_WATCH=13
+CONFIG_IRQ_PORTF_INTA=13
+CONFIG_IRQ_PORTF_INTB=13
+CONFIG_IRQ_SPI_ERROR=7
+CONFIG_IRQ_NFC_ERROR=7
+CONFIG_IRQ_HDMA_ERROR=7
+CONFIG_IRQ_HDMA=7
+CONFIG_IRQ_USB_EINT=10
+CONFIG_IRQ_USB_INT0=11
+CONFIG_IRQ_USB_INT1=11
+CONFIG_IRQ_USB_INT2=11
+CONFIG_IRQ_USB_DMA=11
+
+#
+# Board customizations
+#
+# CONFIG_CMDLINE_BOOL is not set
+CONFIG_BOOT_LOAD=0x1000
+
+#
+# Clock/PLL Setup
+#
+CONFIG_CLKIN_HZ=25000000
+# CONFIG_BFIN_KERNEL_CLOCK is not set
+CONFIG_MAX_MEM_SIZE=512
+CONFIG_MAX_VCO_HZ=400000000
+CONFIG_MIN_VCO_HZ=50000000
+CONFIG_MAX_SCLK_HZ=133333333
+CONFIG_MIN_SCLK_HZ=27000000
+
+#
+# Kernel Timer/Scheduler
+#
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_300 is not set
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=250
+# CONFIG_SCHED_HRTICK is not set
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+# CONFIG_CYCLES_CLOCKSOURCE is not set
+# CONFIG_TICK_ONESHOT is not set
+# CONFIG_NO_HZ is not set
+# CONFIG_HIGH_RES_TIMERS is not set
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+
+#
+# Memory Setup
+#
+
+#
+# Misc
+#
+CONFIG_BFIN_SCRATCH_REG_RETN=y
+# CONFIG_BFIN_SCRATCH_REG_RETE is not set
+# CONFIG_BFIN_SCRATCH_REG_CYCLES is not set
+
+#
+# Blackfin Kernel Optimizations
+#
+
+#
+# Memory Optimizations
+#
+CONFIG_I_ENTRY_L1=y
+CONFIG_EXCPT_IRQ_SYSC_L1=y
+CONFIG_DO_IRQ_L1=y
+CONFIG_CORE_TIMER_IRQ_L1=y
+CONFIG_IDLE_L1=y
+# CONFIG_SCHEDULE_L1 is not set
+CONFIG_ARITHMETIC_OPS_L1=y
+CONFIG_ACCESS_OK_L1=y
+# CONFIG_MEMSET_L1 is not set
+# CONFIG_MEMCPY_L1 is not set
+# CONFIG_SYS_BFIN_SPINLOCK_L1 is not set
+# CONFIG_IP_CHECKSUM_L1 is not set
+CONFIG_CACHELINE_ALIGNED_L1=y
+# CONFIG_SYSCALL_TAB_L1 is not set
+# CONFIG_CPLB_SWITCH_TAB_L1 is not set
+
+#
+# Speed Optimizations
+#
+CONFIG_BFIN_INS_LOWOVERHEAD=y
+CONFIG_RAMKERNEL=y
+# CONFIG_ROMKERNEL is not set
+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_SPARSEMEM_VMEMMAP_ENABLE is not set
+CONFIG_PAGEFLAGS_EXTENDED=y
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_RESOURCES_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=1
+CONFIG_VIRT_TO_BUS=y
+CONFIG_BFIN_GPTIMERS=y
+CONFIG_BFIN_DMA_5XX=y
+# CONFIG_DMA_UNCACHED_4M is not set
+# CONFIG_DMA_UNCACHED_2M is not set
+CONFIG_DMA_UNCACHED_1M=y
+# CONFIG_DMA_UNCACHED_NONE is not set
+
+#
+# Cache Support
+#
+CONFIG_BFIN_ICACHE=y
+CONFIG_BFIN_DCACHE=y
+# CONFIG_BFIN_DCACHE_BANKA is not set
+# CONFIG_BFIN_ICACHE_LOCK is not set
+CONFIG_BFIN_WB=y
+# CONFIG_BFIN_WT is not set
+# CONFIG_MPU is not set
+
+#
+# Asynchonous Memory Configuration
+#
+
+#
+# EBIU_AMGCTL Global Control
+#
+CONFIG_C_AMCKEN=y
+CONFIG_C_CDPRIO=y
+# CONFIG_C_AMBEN is not set
+# CONFIG_C_AMBEN_B0 is not set
+# CONFIG_C_AMBEN_B0_B1 is not set
+# CONFIG_C_AMBEN_B0_B1_B2 is not set
+CONFIG_C_AMBEN_ALL=y
+
+#
+# EBIU_AMBCTL Control
+#
+CONFIG_BANK_0=0x7BB0
+CONFIG_BANK_1=0x5554
+CONFIG_BANK_2=0x7BB0
+CONFIG_BANK_3=0xFFC0
+
+#
+# Bus options (PCI, PCMCIA, EISA, MCA, ISA)
+#
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+# CONFIG_PCCARD is not set
+
+#
+# Executable file formats
+#
+CONFIG_BINFMT_ELF_FDPIC=y
+CONFIG_BINFMT_FLAT=y
+CONFIG_BINFMT_ZFLAT=y
+# CONFIG_BINFMT_SHARED_FLAT is not set
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Power management options
+#
+# CONFIG_PM is not set
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+# CONFIG_PM_WAKEUP_BY_GPIO is not set
+
+#
+# CPU Frequency scaling
+#
+# CONFIG_CPU_FREQ is not set
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
+# CONFIG_XFRM_STATISTICS is not set
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+# CONFIG_IP_PNP_DHCP is not set
+# CONFIG_IP_PNP_BOOTP is not set
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+CONFIG_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_XFRM_MODE_BEET=y
+# CONFIG_INET_LRO is not set
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_NETLABEL is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# 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
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_CAN is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+
+#
+# Wireless
+#
+# CONFIG_CFG80211 is not set
+# CONFIG_WIRELESS_EXT is not set
+# CONFIG_MAC80211 is not set
+# CONFIG_IEEE80211 is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_CONNECTOR is not set
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+# CONFIG_MTD_CMDLINE_PARTS is not set
+# CONFIG_MTD_AR7_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=m
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+# CONFIG_MTD_OOPS is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+# CONFIG_MTD_CFI is not set
+CONFIG_MTD_JEDECPROBE=m
+CONFIG_MTD_GEN_PROBE=m
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_CFI_INTELEXT is not set
+# CONFIG_MTD_CFI_AMDSTD is not set
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_RAM=y
+CONFIG_MTD_ROM=m
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+CONFIG_MTD_COMPLEX_MAPPINGS=y
+# CONFIG_MTD_PHYSMAP is not set
+# CONFIG_MTD_GPIO_ADDR is not set
+# CONFIG_MTD_UCLINUX is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_DATAFLASH is not set
+# CONFIG_MTD_M25P80 is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+CONFIG_MTD_NAND=m
+# CONFIG_MTD_NAND_VERIFY_WRITE is not set
+# CONFIG_MTD_NAND_ECC_SMC is not set
+# CONFIG_MTD_NAND_MUSEUM_IDS is not set
+CONFIG_MTD_NAND_BFIN=m
+CONFIG_BFIN_NAND_BASE=0x20212000
+CONFIG_BFIN_NAND_CLE=2
+CONFIG_BFIN_NAND_ALE=1
+CONFIG_BFIN_NAND_READY=3
+CONFIG_MTD_NAND_IDS=m
+# CONFIG_MTD_NAND_BF5XX is not set
+# CONFIG_MTD_NAND_DISKONCHIP is not set
+# CONFIG_MTD_NAND_NANDSIM is not set
+# CONFIG_MTD_NAND_PLATFORM is not set
+# CONFIG_MTD_ALAUDA is not set
+# CONFIG_MTD_ONENAND is not set
+
+#
+# UBI - Unsorted block images
+#
+# CONFIG_MTD_UBI is not set
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_DEV_COW_COMMON is not set
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_UB is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=4096
+# CONFIG_BLK_DEV_XIP is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+CONFIG_MISC_DEVICES=y
+# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_ENCLOSURE_SERVICES is not set
+CONFIG_HAVE_IDE=y
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+# CONFIG_SCSI is not set
+# CONFIG_SCSI_DMA is not set
+# CONFIG_SCSI_NETLINK is not set
+# CONFIG_ATA is not set
+# CONFIG_MD is not set
+CONFIG_NETDEVICES=y
+# CONFIG_NETDEVICES_MULTIQUEUE is not set
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_VETH is not set
+CONFIG_PHYLIB=y
+
+#
+# MII PHY device drivers
+#
+# CONFIG_MARVELL_PHY is not set
+# CONFIG_DAVICOM_PHY is not set
+# CONFIG_QSEMI_PHY is not set
+# CONFIG_LXT_PHY is not set
+# CONFIG_CICADA_PHY is not set
+# CONFIG_VITESSE_PHY is not set
+# CONFIG_SMSC_PHY is not set
+# CONFIG_BROADCOM_PHY is not set
+# CONFIG_ICPLUS_PHY is not set
+# CONFIG_REALTEK_PHY is not set
+# CONFIG_FIXED_PHY is not set
+# CONFIG_MDIO_BITBANG is not set
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+CONFIG_BFIN_MAC=y
+CONFIG_BFIN_TX_DESC_NUM=10
+CONFIG_BFIN_RX_DESC_NUM=20
+CONFIG_BFIN_MAC_RMII=y
+# CONFIG_SMC91X is not set
+# CONFIG_SMSC911X is not set
+# CONFIG_DM9000 is not set
+# CONFIG_ENC28J60 is not set
+# CONFIG_IBM_NEW_EMAC_ZMII is not set
+# CONFIG_IBM_NEW_EMAC_RGMII is not set
+# CONFIG_IBM_NEW_EMAC_TAH is not set
+# CONFIG_IBM_NEW_EMAC_EMAC4 is not set
+# CONFIG_B44 is not set
+CONFIG_NETDEV_1000=y
+# CONFIG_E1000E_ENABLED is not set
+# CONFIG_AX88180 is not set
+CONFIG_NETDEV_10000=y
+
+#
+# Wireless LAN
+#
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
+# CONFIG_IWLWIFI_LEDS is not set
+
+#
+# USB Network Adapters
+#
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_USBNET is not set
+# CONFIG_WAN is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_ISDN is not set
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+
+#
+# Userland interfaces
+#
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV 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_TABLET is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+CONFIG_INPUT_MISC=y
+# CONFIG_INPUT_ATI_REMOTE is not set
+# CONFIG_INPUT_ATI_REMOTE2 is not set
+# CONFIG_INPUT_KEYSPAN_REMOTE is not set
+# CONFIG_INPUT_POWERMATE is not set
+# CONFIG_INPUT_YEALINK is not set
+# CONFIG_INPUT_UINPUT is not set
+# CONFIG_TWI_KEYPAD is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+# CONFIG_AD9960 is not set
+# CONFIG_SPI_ADC_BF533 is not set
+# CONFIG_BF5xx_PPIFCD is not set
+# CONFIG_BFIN_SIMPLE_TIMER is not set
+# CONFIG_BF5xx_PPI is not set
+# CONFIG_BFIN_SPORT is not set
+# CONFIG_BFIN_TIMER_LATENCY is not set
+# CONFIG_TWI_LCD is not set
+CONFIG_SIMPLE_GPIO=m
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
+CONFIG_DEVKMEM=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_BFIN=y
+CONFIG_SERIAL_BFIN_CONSOLE=y
+CONFIG_SERIAL_BFIN_DMA=y
+# CONFIG_SERIAL_BFIN_PIO is not set
+# CONFIG_SERIAL_BFIN_UART0 is not set
+CONFIG_SERIAL_BFIN_UART1=y
+# CONFIG_BFIN_UART1_CTSRTS is not set
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_BFIN_SPORT is not set
+CONFIG_UNIX98_PTYS=y
+# CONFIG_LEGACY_PTYS is not set
+CONFIG_BFIN_OTP=y
+# CONFIG_BFIN_OTP_WRITE_ENABLE is not set
+
+#
+# CAN, the car bus and industrial fieldbus
+#
+# CONFIG_CAN4LINUX is not set
+# CONFIG_IPMI_HANDLER is not set
+CONFIG_HW_RANDOM=y
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_CHARDEV=m
+CONFIG_I2C_HELPER_AUTO=y
+
+#
+# I2C Hardware Bus support
+#
+CONFIG_I2C_BLACKFIN_TWI=y
+CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ=50
+# CONFIG_I2C_GPIO is not set
+# CONFIG_I2C_OCORES is not set
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_SIMTEC is not set
+# CONFIG_I2C_TAOS_EVM is not set
+# CONFIG_I2C_STUB is not set
+# CONFIG_I2C_TINY_USB is not set
+# CONFIG_I2C_PCA_PLATFORM is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_DS1682 is not set
+# CONFIG_SENSORS_AD5252 is not set
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_PCF8575 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_SENSORS_TSL2550 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
+CONFIG_SPI=y
+CONFIG_SPI_MASTER=y
+
+#
+# SPI Master Controller Drivers
+#
+CONFIG_SPI_BFIN=y
+# CONFIG_SPI_BITBANG is not set
+
+#
+# SPI Protocol Masters
+#
+# CONFIG_SPI_AT25 is not set
+# CONFIG_SPI_SPIDEV is not set
+# CONFIG_SPI_TLE62X0 is not set
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_SENSORS_AD7418 is not set
+# CONFIG_SENSORS_ADM1021 is not set
+# CONFIG_SENSORS_ADM1025 is not set
+# CONFIG_SENSORS_ADM1026 is not set
+# CONFIG_SENSORS_ADM1029 is not set
+# CONFIG_SENSORS_ADM1031 is not set
+# CONFIG_SENSORS_ADM9240 is not set
+# CONFIG_SENSORS_ADT7470 is not set
+# CONFIG_SENSORS_ADT7473 is not set
+# CONFIG_SENSORS_ATXP1 is not set
+# CONFIG_SENSORS_DS1621 is not set
+# CONFIG_SENSORS_F71805F is not set
+# CONFIG_SENSORS_F71882FG is not set
+# CONFIG_SENSORS_F75375S 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_LM70 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_LM93 is not set
+# CONFIG_SENSORS_MAX1619 is not set
+# CONFIG_SENSORS_MAX6650 is not set
+# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_PC87427 is not set
+# CONFIG_SENSORS_DME1737 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47M192 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_ADS7828 is not set
+# CONFIG_SENSORS_THMC50 is not set
+# CONFIG_SENSORS_VT1211 is not set
+# CONFIG_SENSORS_W83781D is not set
+# CONFIG_SENSORS_W83791D is not set
+# CONFIG_SENSORS_W83792D is not set
+# CONFIG_SENSORS_W83793 is not set
+# CONFIG_SENSORS_W83L785TS is not set
+# CONFIG_SENSORS_W83L786NG is not set
+# CONFIG_SENSORS_W83627HF is not set
+# CONFIG_SENSORS_W83627EHF is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
+# CONFIG_THERMAL is not set
+# CONFIG_THERMAL_HWMON is not set
+CONFIG_WATCHDOG=y
+# CONFIG_WATCHDOG_NOWAYOUT is not set
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+CONFIG_BFIN_WDT=y
+
+#
+# USB-based Watchdog Cards
+#
+# CONFIG_USBPCWATCHDOG is not set
+
+#
+# Sonics Silicon Backplane
+#
+CONFIG_SSB_POSSIBLE=y
+# CONFIG_SSB is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_SM501 is not set
+# CONFIG_HTC_PASIC3 is not set
+
+#
+# Multimedia devices
+#
+
+#
+# Multimedia core support
+#
+# CONFIG_VIDEO_DEV is not set
+# CONFIG_DVB_CORE is not set
+# CONFIG_VIDEO_MEDIA is not set
+
+#
+# Multimedia drivers
+#
+# CONFIG_DAB is not set
+
+#
+# Graphics support
+#
+# CONFIG_VGASTATE is not set
+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
+# CONFIG_FB is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+
+#
+# Console display driver support
+#
+CONFIG_DUMMY_CONSOLE=y
+
+#
+# Sound
+#
+CONFIG_SOUND=m
+
+#
+# Advanced Linux Sound Architecture
+#
+CONFIG_SND=m
+CONFIG_SND_TIMER=m
+CONFIG_SND_PCM=m
+# CONFIG_SND_SEQUENCER is not set
+CONFIG_SND_OSSEMUL=y
+CONFIG_SND_MIXER_OSS=m
+CONFIG_SND_PCM_OSS=m
+CONFIG_SND_PCM_OSS_PLUGINS=y
+# CONFIG_SND_DYNAMIC_MINORS is not set
+CONFIG_SND_SUPPORT_OLD_API=y
+CONFIG_SND_VERBOSE_PROCFS=y
+# CONFIG_SND_VERBOSE_PRINTK is not set
+# CONFIG_SND_DEBUG is not set
+
+#
+# Generic devices
+#
+# CONFIG_SND_DUMMY is not set
+# CONFIG_SND_MTPAV is not set
+# CONFIG_SND_SERIAL_U16550 is not set
+# CONFIG_SND_MPU401 is not set
+
+#
+# SPI devices
+#
+
+#
+# ALSA Blackfin devices
+#
+# CONFIG_SND_BLACKFIN_AD1836 is not set
+# CONFIG_SND_BFIN_AD73311 is not set
+# CONFIG_SND_BFIN_AD73322 is not set
+
+#
+# USB devices
+#
+# CONFIG_SND_USB_AUDIO is not set
+# CONFIG_SND_USB_CAIAQ is not set
+
+#
+# System on Chip audio support
+#
+CONFIG_SND_SOC=m
+CONFIG_SND_BF5XX_I2S=m
+CONFIG_SND_BF5XX_SOC_SSM2602=m
+# CONFIG_SND_BF5XX_AC97 is not set
+CONFIG_SND_BF5XX_SOC_SPORT=m
+CONFIG_SND_BF5XX_SOC_I2S=m
+CONFIG_SND_BF5XX_SPORT_NUM=0
+
+#
+# ALSA SoC audio for Freescale SOCs
+#
+
+#
+# SoC Audio for the Texas Instruments OMAP
+#
+CONFIG_SND_SOC_SSM2602=m
+
+#
+# Open Sound System
+#
+# CONFIG_SOUND_PRIME is not set
+CONFIG_HID_SUPPORT=y
+CONFIG_HID=y
+# CONFIG_HID_DEBUG is not set
+# CONFIG_HIDRAW is not set
+
+#
+# USB Input Devices
+#
+CONFIG_USB_HID=y
+# CONFIG_USB_HIDINPUT_POWERBOOK is not set
+# CONFIG_HID_FF is not set
+# CONFIG_USB_HIDDEV is not set
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_ARCH_HAS_HCD=y
+# CONFIG_USB_ARCH_HAS_OHCI is not set
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+CONFIG_USB=y
+# CONFIG_USB_DEBUG is not set
+# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set
+
+#
+# Miscellaneous USB options
+#
+# CONFIG_USB_DEVICEFS is not set
+CONFIG_USB_DEVICE_CLASS=y
+# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_OTG is not set
+# CONFIG_USB_OTG_WHITELIST is not set
+CONFIG_USB_OTG_BLACKLIST_HUB=y
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_C67X00_HCD is not set
+# CONFIG_USB_ISP116X_HCD is not set
+# CONFIG_USB_ISP1760_HCD is not set
+# CONFIG_USB_ISP1362_HCD is not set
+# CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_R8A66597_HCD is not set
+CONFIG_USB_MUSB_HDRC=y
+CONFIG_USB_MUSB_SOC=y
+
+#
+# Blackfin high speed USB support
+#
+CONFIG_USB_MUSB_HOST=y
+# CONFIG_USB_MUSB_PERIPHERAL is not set
+# CONFIG_USB_MUSB_OTG is not set
+CONFIG_USB_MUSB_HDRC_HCD=y
+CONFIG_MUSB_PIO_ONLY=y
+CONFIG_USB_MUSB_LOGLEVEL=0
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+# CONFIG_USB_WDM is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# may also be needed; see USB_STORAGE Help for more information
+#
+# CONFIG_USB_LIBUSUAL is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+CONFIG_USB_MON=y
+
+#
+# USB port drivers
+#
+# CONFIG_USB_SERIAL is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_ADUTUX is not set
+# CONFIG_USB_AUERSWALD is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_BERRY_CHARGE is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_PHIDGET is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_FTDI_ELAN is not set
+# CONFIG_USB_APPLEDISPLAY is not set
+# CONFIG_USB_SISUSBVGA is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_IOWARRIOR is not set
+# CONFIG_USB_ISIGHTFW is not set
+# CONFIG_USB_GADGET is not set
+# CONFIG_MMC is not set
+# CONFIG_MEMSTICK is not set
+# CONFIG_NEW_LEDS is not set
+# CONFIG_ACCESSIBILITY is not set
+CONFIG_RTC_LIB=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+# CONFIG_RTC_DEBUG is not set
+
+#
+# RTC interfaces
+#
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_DEV=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+# CONFIG_RTC_DRV_TEST is not set
+
+#
+# I2C RTC drivers
+#
+# CONFIG_RTC_DRV_DS1307 is not set
+# CONFIG_RTC_DRV_DS1374 is not set
+# CONFIG_RTC_DRV_DS1672 is not set
+# CONFIG_RTC_DRV_MAX6900 is not set
+# CONFIG_RTC_DRV_RS5C372 is not set
+# CONFIG_RTC_DRV_ISL1208 is not set
+# CONFIG_RTC_DRV_X1205 is not set
+# CONFIG_RTC_DRV_PCF8563 is not set
+# CONFIG_RTC_DRV_PCF8583 is not set
+# CONFIG_RTC_DRV_M41T80 is not set
+# CONFIG_RTC_DRV_S35390A is not set
+# CONFIG_RTC_DRV_FM3130 is not set
+
+#
+# SPI RTC drivers
+#
+# CONFIG_RTC_DRV_MAX6902 is not set
+# CONFIG_RTC_DRV_R9701 is not set
+# CONFIG_RTC_DRV_RS5C348 is not set
+
+#
+# Platform RTC drivers
+#
+# CONFIG_RTC_DRV_DS1511 is not set
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_STK17TA8 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_M48T59 is not set
+# CONFIG_RTC_DRV_V3020 is not set
+
+#
+# on-CPU RTC drivers
+#
+CONFIG_RTC_DRV_BFIN=y
+# CONFIG_UIO is not set
+
+#
+# File systems
+#
+# CONFIG_EXT2_FS is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_EXT4DEV_FS is not set
+# 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_DNOTIFY is not set
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+# 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_SYSCTL=y
+CONFIG_SYSFS=y
+# CONFIG_TMPFS is not set
+# CONFIG_HUGETLB_PAGE is not set
+# 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_YAFFS_FS=m
+CONFIG_YAFFS_YAFFS1=y
+# CONFIG_YAFFS_9BYTE_TAGS is not set
+# CONFIG_YAFFS_DOES_ECC is not set
+CONFIG_YAFFS_YAFFS2=y
+CONFIG_YAFFS_AUTO_YAFFS2=y
+# CONFIG_YAFFS_DISABLE_LAZY_LOAD is not set
+# CONFIG_YAFFS_DISABLE_WIDE_TNODES is not set
+# CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED is not set
+CONFIG_YAFFS_SHORT_NAMES_IN_RAM=y
+CONFIG_JFFS2_FS=m
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_FS_WBUF_VERIFY is not set
+# CONFIG_JFFS2_SUMMARY is not set
+# CONFIG_JFFS2_FS_XATTR is not set
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+# CONFIG_JFFS2_LZO is not set
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+CONFIG_NETWORK_FILESYSTEMS=y
+CONFIG_NFS_FS=m
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFSD is not set
+CONFIG_LOCKD=m
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=m
+# CONFIG_SUNRPC_BIND34 is not set
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+CONFIG_SMB_FS=m
+# CONFIG_SMB_NLS_DEFAULT is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+CONFIG_NLS=m
+CONFIG_NLS_DEFAULT="iso8859-1"
+# CONFIG_NLS_CODEPAGE_437 is not set
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+# CONFIG_NLS_ISO8859_1 is not set
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+# CONFIG_DLM is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_FRAME_WARN=1024
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+CONFIG_DEBUG_FS=y
+# CONFIG_HEADERS_CHECK is not set
+# CONFIG_DEBUG_KERNEL is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_SAMPLES is not set
+CONFIG_DEBUG_MMRS=y
+CONFIG_DEBUG_HUNT_FOR_ZERO=y
+CONFIG_DEBUG_BFIN_HWTRACE_ON=y
+CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_OFF=y
+# CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_ONE is not set
+# CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_TWO is not set
+CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION=0
+# CONFIG_DEBUG_BFIN_HWTRACE_EXPAND is not set
+# CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE is not set
+CONFIG_EARLY_PRINTK=y
+CONFIG_CPLB_INFO=y
+CONFIG_ACCESS_CHECK=y
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+CONFIG_SECURITY=y
+# CONFIG_SECURITY_NETWORK is not set
+# CONFIG_SECURITY_CAPABILITIES is not set
+# CONFIG_SECURITY_ROOTPLUG is not set
+CONFIG_SECURITY_DEFAULT_MMAP_MIN_ADDR=0
+CONFIG_CRYPTO=y
+
+#
+# Crypto core or helper
+#
+# CONFIG_CRYPTO_MANAGER is not set
+# CONFIG_CRYPTO_GF128MUL is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_CRYPTD is not set
+# CONFIG_CRYPTO_AUTHENC is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Authenticated Encryption with Associated Data
+#
+# CONFIG_CRYPTO_CCM is not set
+# CONFIG_CRYPTO_GCM is not set
+# CONFIG_CRYPTO_SEQIV is not set
+
+#
+# Block modes
+#
+# CONFIG_CRYPTO_CBC is not set
+# CONFIG_CRYPTO_CTR is not set
+# CONFIG_CRYPTO_CTS is not set
+# CONFIG_CRYPTO_ECB is not set
+# CONFIG_CRYPTO_LRW is not set
+# CONFIG_CRYPTO_PCBC is not set
+# CONFIG_CRYPTO_XTS is not set
+
+#
+# Hash modes
+#
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_XCBC is not set
+
+#
+# Digest
+#
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_MD4 is not set
+# CONFIG_CRYPTO_MD5 is not set
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_WP512 is not set
+
+#
+# Ciphers
+#
+# CONFIG_CRYPTO_AES is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_CAMELLIA is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_DES is not set
+# CONFIG_CRYPTO_FCRYPT is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_SALSA20 is not set
+# CONFIG_CRYPTO_SEED is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+
+#
+# Compression
+#
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_LZO is not set
+CONFIG_CRYPTO_HW=y
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+# CONFIG_GENERIC_FIND_FIRST_BIT is not set
+CONFIG_CRC_CCITT=m
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=m
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
diff --git a/arch/blackfin/configs/H8606_defconfig b/arch/blackfin/configs/H8606_defconfig
index ba0bee9..1fc31f1 100644
--- a/arch/blackfin/configs/H8606_defconfig
+++ b/arch/blackfin/configs/H8606_defconfig
@@ -1,6 +1,6 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.22.12
+# Linux kernel version: 2.6.22.14
 #
 # CONFIG_MMU is not set
 # CONFIG_FPU is not set
@@ -192,7 +192,7 @@
 # CONFIG_BFIN_KERNEL_CLOCK is not set
 CONFIG_MAX_VCO_HZ=400000000
 CONFIG_MIN_VCO_HZ=50000000
-CONFIG_MAX_SCLK_HZ=133000000
+CONFIG_MAX_SCLK_HZ=133333333
 CONFIG_MIN_SCLK_HZ=27000000
 
 #
@@ -516,7 +516,7 @@
 #
 # CONFIG_MTD_DATAFLASH is not set
 CONFIG_MTD_M25P80=y
-CONFIG_M25PXX_USE_FAST_READ=y
+# CONFIG_M25PXX_USE_FAST_READ is not set
 # CONFIG_MTD_SLRAM is not set
 # CONFIG_MTD_PHRAM is not set
 # CONFIG_MTD_MTDRAM is not set
@@ -635,25 +635,25 @@
 # CONFIG_INPUT_MOUSEDEV is not set
 # CONFIG_INPUT_JOYDEV is not set
 # CONFIG_INPUT_TSDEV is not set
-CONFIG_INPUT_EVDEV=m
+CONFIG_INPUT_EVDEV=y
 # CONFIG_INPUT_EVBUG is not set
 
 #
 # Input Device Drivers
 #
-# CONFIG_INPUT_KEYBOARD is not set
+CONFIG_INPUT_KEYBOARD=y
+# CONFIG_KEYBOARD_ATKBD is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_KEYBOARD_STOWAWAY is not set
+CONFIG_KEYBOARD_GPIO=y
 # CONFIG_INPUT_MOUSE is not set
 # CONFIG_INPUT_JOYSTICK is not set
 # CONFIG_INPUT_TABLET is not set
 # CONFIG_INPUT_TOUCHSCREEN is not set
-CONFIG_INPUT_MISC=y
-# CONFIG_INPUT_ATI_REMOTE is not set
-# CONFIG_INPUT_ATI_REMOTE2 is not set
-# CONFIG_INPUT_KEYSPAN_REMOTE is not set
-# CONFIG_INPUT_POWERMATE is not set
-# CONFIG_INPUT_YEALINK is not set
-# CONFIG_INPUT_UINPUT is not set
-# CONFIG_BF53X_PFBUTTONS is not set
+# CONFIG_INPUT_MISC is not set
 
 #
 # Hardware I/O ports
@@ -681,7 +681,15 @@
 #
 # Serial drivers
 #
-# CONFIG_SERIAL_8250 is not set
+CONFIG_SERIAL_8250=y
+# CONFIG_SERIAL_8250_CONSOLE is not set
+CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+CONFIG_SERIAL_8250_EXTENDED=y
+# CONFIG_SERIAL_8250_MANY_PORTS is not set
+CONFIG_SERIAL_8250_SHARE_IRQ=y
+# CONFIG_SERIAL_8250_DETECT_IRQ is not set
+# CONFIG_SERIAL_8250_RSA is not set
 
 #
 # Non-8250 serial port support
diff --git a/arch/blackfin/include/asm/a.out.h b/arch/blackfin/include/asm/a.out.h
deleted file mode 100644
index 6c3d652..0000000
--- a/arch/blackfin/include/asm/a.out.h
+++ /dev/null
@@ -1,19 +0,0 @@
-#ifndef __BFIN_A_OUT_H__
-#define __BFIN_A_OUT_H__
-
-struct exec {
-	unsigned long a_info;	/* Use macros N_MAGIC, etc for access */
-	unsigned a_text;	/* length of text, in bytes */
-	unsigned a_data;	/* length of data, in bytes */
-	unsigned a_bss;		/* length of uninitialized data area for file, in bytes */
-	unsigned a_syms;	/* length of symbol table data in file, in bytes */
-	unsigned a_entry;	/* start address */
-	unsigned a_trsize;	/* length of relocation info for text, in bytes */
-	unsigned a_drsize;	/* length of relocation info for data, in bytes */
-};
-
-#define N_TRSIZE(a)	((a).a_trsize)
-#define N_DRSIZE(a)	((a).a_drsize)
-#define N_SYMSIZE(a)	((a).a_syms)
-
-#endif				/* __BFIN_A_OUT_H__ */
diff --git a/arch/blackfin/include/asm/bfin-global.h b/arch/blackfin/include/asm/bfin-global.h
index 7ba70de..56dcb0a 100644
--- a/arch/blackfin/include/asm/bfin-global.h
+++ b/arch/blackfin/include/asm/bfin-global.h
@@ -63,7 +63,6 @@
 extern void init_exception_vectors(void);
 extern void program_IAR(void);
 
-extern void bfin_reset(void);
 extern asmlinkage void lower_to_irq14(void);
 extern asmlinkage void bfin_return_from_exception(void);
 extern asmlinkage void evt14_softirq(void);
@@ -92,6 +91,8 @@
 extern void *sram_alloc_with_lsl(size_t, unsigned long);
 extern int sram_free_with_lsl(const void*);
 
+extern void *isram_memcpy(void *dest, const void *src, size_t n);
+
 extern const char bfin_board_name[];
 
 extern unsigned long bfin_sic_iwr[];
@@ -104,7 +105,7 @@
 	_stext_l2[], _etext_l2[], _sdata_l2[], _edata_l2[], _sbss_l2[],
 	_ebss_l2[], _l2_lma_start[];
 
-/* only used when CONFIG_MTD_UCLINUX */
+/* only used when MTD_UCLINUX */
 extern unsigned long memory_mtd_start, memory_mtd_end, mtd_size;
 
 #ifdef CONFIG_BFIN_ICACHE_LOCK
diff --git a/arch/blackfin/include/asm/bfrom.h b/arch/blackfin/include/asm/bfrom.h
new file mode 100644
index 0000000..cfe8024
--- /dev/null
+++ b/arch/blackfin/include/asm/bfrom.h
@@ -0,0 +1,85 @@
+/* Blackfin on-chip ROM API
+ *
+ * Copyright 2008 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#ifndef __BFROM_H__
+#define __BFROM_H__
+
+#include <linux/types.h>
+
+/* Possible syscontrol action flags */
+#define SYSCTRL_READ        0x00000000    /* read registers */
+#define SYSCTRL_WRITE       0x00000001    /* write registers */
+#define SYSCTRL_SYSRESET    0x00000002    /* perform system reset */
+#define SYSCTRL_CORERESET   0x00000004    /* perform core reset */
+#define SYSCTRL_SOFTRESET   0x00000006    /* perform core and system reset */
+#define SYSCTRL_VRCTL       0x00000010    /* read/write VR_CTL register */
+#define SYSCTRL_EXTVOLTAGE  0x00000020    /* VDDINT supplied externally */
+#define SYSCTRL_INTVOLTAGE  0x00000000    /* VDDINT generated by on-chip regulator */
+#define SYSCTRL_OTPVOLTAGE  0x00000040    /* For Factory Purposes Only */
+#define SYSCTRL_PLLCTL      0x00000100    /* read/write PLL_CTL register */
+#define SYSCTRL_PLLDIV      0x00000200    /* read/write PLL_DIV register */
+#define SYSCTRL_LOCKCNT     0x00000400    /* read/write PLL_LOCKCNT register */
+#define SYSCTRL_PLLSTAT     0x00000800    /* read/write PLL_STAT register */
+
+typedef struct ADI_SYSCTRL_VALUES {
+	uint16_t uwVrCtl;
+	uint16_t uwPllCtl;
+	uint16_t uwPllDiv;
+	uint16_t uwPllLockCnt;
+	uint16_t uwPllStat;
+} ADI_SYSCTRL_VALUES;
+
+static uint32_t (* const bfrom_SysControl)(uint32_t action_flags, ADI_SYSCTRL_VALUES *power_settings, void *reserved) = (void *)0xEF000038;
+
+/* We need a dedicated function since we need to screw with the stack pointer
+ * when resetting.  The on-chip ROM will save/restore registers on the stack
+ * when doing a system reset, so the stack cannot be outside of the chip.
+ */
+__attribute__((__noreturn__))
+static inline void bfrom_SoftReset(void *new_stack)
+{
+	while (1)
+		__asm__ __volatile__(
+			"sp = %[stack];"
+			"jump (%[bfrom_syscontrol]);"
+			: : [bfrom_syscontrol] "p"(bfrom_SysControl),
+				"q0"(SYSCTRL_SOFTRESET),
+				"q1"(0),
+				"q2"(NULL),
+				[stack] "p"(new_stack)
+		);
+}
+
+/* OTP Functions */
+static uint32_t (* const bfrom_OtpCommand)(uint32_t command, uint32_t value) = (void *)0xEF000018;
+static uint32_t (* const bfrom_OtpRead)(uint32_t page, uint32_t flags, uint64_t *page_content) = (void *)0xEF00001A;
+static uint32_t (* const bfrom_OtpWrite)(uint32_t page, uint32_t flags, uint64_t *page_content) = (void *)0xEF00001C;
+
+/* otp command: defines for "command" */
+#define OTP_INIT                 0x00000001
+#define OTP_CLOSE                0x00000002
+
+/* otp read/write: defines for "flags" */
+#define OTP_LOWER_HALF           0x00000000 /* select upper/lower 64-bit half (bit 0) */
+#define OTP_UPPER_HALF           0x00000001
+#define OTP_NO_ECC               0x00000010 /* do not use ECC */
+#define OTP_LOCK                 0x00000020 /* sets page protection bit for page */
+#define OTP_CHECK_FOR_PREV_WRITE 0x00000080
+
+/* Return values for all functions */
+#define OTP_SUCCESS          0x00000000
+#define OTP_MASTER_ERROR     0x001
+#define OTP_WRITE_ERROR      0x003
+#define OTP_READ_ERROR       0x005
+#define OTP_ACC_VIO_ERROR    0x009
+#define OTP_DATA_MULT_ERROR  0x011
+#define OTP_ECC_MULT_ERROR   0x021
+#define OTP_PREV_WR_ERROR    0x041
+#define OTP_DATA_SB_WARN     0x100
+#define OTP_ECC_SB_WARN      0x200
+
+#endif
diff --git a/arch/blackfin/include/asm/cacheflush.h b/arch/blackfin/include/asm/cacheflush.h
index d81a775..5ef9e35 100644
--- a/arch/blackfin/include/asm/cacheflush.h
+++ b/arch/blackfin/include/asm/cacheflush.h
@@ -30,8 +30,6 @@
 #ifndef _BLACKFIN_CACHEFLUSH_H
 #define _BLACKFIN_CACHEFLUSH_H
 
-#include <asm/cplb.h>
-
 extern void blackfin_icache_dcache_flush_range(unsigned int, unsigned int);
 extern void blackfin_icache_flush_range(unsigned int, unsigned int);
 extern void blackfin_dcache_flush_range(unsigned int, unsigned int);
diff --git a/arch/blackfin/include/asm/cplb.h b/arch/blackfin/include/asm/cplb.h
index 05d6f05..9e8b403 100644
--- a/arch/blackfin/include/asm/cplb.h
+++ b/arch/blackfin/include/asm/cplb.h
@@ -55,7 +55,13 @@
 #endif
 
 #define L1_DMEMORY       (CPLB_LOCK | CPLB_COMMON)
-#define L2_MEMORY        (CPLB_COMMON)
+#ifdef CONFIG_BFIN_L2_CACHEABLE
+#define L2_IMEMORY        (SDRAM_IGENERIC)
+#define L2_DMEMORY        (SDRAM_DGENERIC)
+#else
+#define L2_IMEMORY        (CPLB_COMMON)
+#define L2_DMEMORY        (CPLB_COMMON)
+#endif
 #define SDRAM_DNON_CHBL  (CPLB_COMMON)
 #define SDRAM_EBIU       (CPLB_COMMON)
 #define SDRAM_OOPS       (CPLB_VALID | ANOMALY_05000158_WORKAROUND | CPLB_LOCK | CPLB_DIRTY)
diff --git a/arch/blackfin/include/asm/cplbinit.h b/arch/blackfin/include/asm/cplbinit.h
index 0eb1c1b..d179b74 100644
--- a/arch/blackfin/include/asm/cplbinit.h
+++ b/arch/blackfin/include/asm/cplbinit.h
@@ -90,6 +90,20 @@
 extern unsigned long reserved_mem_dcache_on;
 extern unsigned long reserved_mem_icache_on;
 
-extern void generate_cpl_tables(void);
+extern void generate_cplb_tables(void);
+
+static inline int bfin_addr_dcachable(unsigned long addr)
+{
+#ifdef CONFIG_BFIN_DCACHE
+	if (addr < (_ramend - DMA_UNCACHED_REGION))
+		return 1;
+#endif
+
+	if (reserved_mem_dcache_on &&
+		addr >= _ramend && addr < physical_mem_end)
+		return 1;
+
+	return 0;
+}
 
 #endif
diff --git a/arch/blackfin/include/asm/cpumask.h b/arch/blackfin/include/asm/cpumask.h
deleted file mode 100644
index b20a8e9..0000000
--- a/arch/blackfin/include/asm/cpumask.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef _ASM_BLACKFIN_CPUMASK_H
-#define _ASM_BLACKFIN_CPUMASK_H
-
-#include <asm-generic/cpumask.h>
-
-#endif				/* _ASM_BLACKFIN_CPUMASK_H */
diff --git a/arch/blackfin/include/asm/dma-mapping.h b/arch/blackfin/include/asm/dma-mapping.h
index 1a13c2f..ede748d 100644
--- a/arch/blackfin/include/asm/dma-mapping.h
+++ b/arch/blackfin/include/asm/dma-mapping.h
@@ -80,4 +80,15 @@
 extern void dma_unmap_sg(struct device *dev, struct scatterlist *sg,
 		      int nhwentries, enum dma_data_direction direction);
 
+static inline void dma_sync_single_for_cpu(struct device *dev,
+					dma_addr_t handle, size_t size,
+					enum dma_data_direction dir)
+{
+}
+
+static inline void dma_sync_single_for_device(struct device *dev,
+					dma_addr_t handle, size_t size,
+					enum dma_data_direction dir)
+{
+}
 #endif				/* _BLACKFIN_DMA_MAPPING_H */
diff --git a/arch/blackfin/include/asm/kgdb.h b/arch/blackfin/include/asm/kgdb.h
index 0f73847..26ebac6 100644
--- a/arch/blackfin/include/asm/kgdb.h
+++ b/arch/blackfin/include/asm/kgdb.h
@@ -124,9 +124,16 @@
 /* Number of bytes of registers.  */
 #define NUMREGBYTES BFIN_NUM_REGS*4
 
-#define BREAKPOINT() asm("   EXCPT 2;");
-#define BREAK_INSTR_SIZE       2
-#define HW_BREAKPOINT_NUM		6
+static inline void arch_kgdb_breakpoint(void)
+{
+	asm("   EXCPT 2;");
+}
+#define BREAK_INSTR_SIZE	2
+#define CACHE_FLUSH_IS_SAFE	1
+#define HW_INST_WATCHPOINT_NUM	6
+#define HW_WATCHPOINT_NUM	8
+#define TYPE_INST_WATCHPOINT	0
+#define TYPE_DATA_WATCHPOINT	1
 
 /* Instruction watchpoint address control register bits mask */
 #define WPPWR		0x1
@@ -163,10 +170,11 @@
 #define WPDAEN1		0x8
 #define WPDCNTEN0	0x10
 #define WPDCNTEN1	0x20
+
 #define WPDSRC0		0xc0
-#define WPDACC0		0x300
+#define WPDACC0_OFFSET	8
 #define WPDSRC1		0xc00
-#define WPDACC1		0x3000
+#define WPDACC1_OFFSET	12
 
 /* Watchpoint status register bits mask */
 #define STATIA0		0x1
@@ -178,7 +186,4 @@
 #define STATDA0		0x40
 #define STATDA1		0x80
 
-extern void kgdb_print(const char *fmt, ...);
-extern void init_kgdb_uart(void);
-
 #endif
diff --git a/arch/blackfin/include/asm/mmu_context.h b/arch/blackfin/include/asm/mmu_context.h
index 8529552..35593dd 100644
--- a/arch/blackfin/include/asm/mmu_context.h
+++ b/arch/blackfin/include/asm/mmu_context.h
@@ -45,49 +45,12 @@
 extern int l1sram_free(const void*);
 extern void *l1sram_alloc_max(void*);
 
-static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk)
-{
-}
-
-/* Called when creating a new context during fork() or execve().  */
-static inline int
-init_new_context(struct task_struct *tsk, struct mm_struct *mm)
-{
-#ifdef CONFIG_MPU
-	unsigned long p = __get_free_pages(GFP_KERNEL, page_mask_order);
-	mm->context.page_rwx_mask = (unsigned long *)p;
-	memset(mm->context.page_rwx_mask, 0,
-	       page_mask_nelts * 3 * sizeof(long));
-#endif
-	return 0;
-}
-
 static inline void free_l1stack(void)
 {
 	nr_l1stack_tasks--;
 	if (nr_l1stack_tasks == 0)
 		l1sram_free(l1_stack_base);
 }
-static inline void destroy_context(struct mm_struct *mm)
-{
-	struct sram_list_struct *tmp;
-
-	if (current_l1_stack_save == mm->context.l1_stack_save)
-		current_l1_stack_save = NULL;
-	if (mm->context.l1_stack_save)
-		free_l1stack();
-
-	while ((tmp = mm->context.sram_list)) {
-		mm->context.sram_list = tmp->next;
-		sram_free(tmp->addr);
-		kfree(tmp);
-	}
-#ifdef CONFIG_MPU
-	if (current_rwx_mask == mm->context.page_rwx_mask)
-		current_rwx_mask = NULL;
-	free_pages((unsigned long)mm->context.page_rwx_mask, page_mask_order);
-#endif
-}
 
 static inline unsigned long
 alloc_l1stack(unsigned long length, unsigned long *stack_base)
@@ -134,6 +97,7 @@
 	}
 #endif
 
+#ifdef CONFIG_APP_STACK_L1
 	/* L1 stack switching.  */
 	if (!next_mm->context.l1_stack_save)
 		return;
@@ -144,6 +108,7 @@
 	}
 	current_l1_stack_save = next_mm->context.l1_stack_save;
 	memcpy(l1_stack_base, current_l1_stack_save, l1_stack_len);
+#endif
 }
 
 #ifdef CONFIG_MPU
@@ -180,4 +145,44 @@
 }
 #endif
 
+static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk)
+{
+}
+
+/* Called when creating a new context during fork() or execve().  */
+static inline int
+init_new_context(struct task_struct *tsk, struct mm_struct *mm)
+{
+#ifdef CONFIG_MPU
+	unsigned long p = __get_free_pages(GFP_KERNEL, page_mask_order);
+	mm->context.page_rwx_mask = (unsigned long *)p;
+	memset(mm->context.page_rwx_mask, 0,
+	       page_mask_nelts * 3 * sizeof(long));
+#endif
+	return 0;
+}
+
+static inline void destroy_context(struct mm_struct *mm)
+{
+	struct sram_list_struct *tmp;
+
+#ifdef CONFIG_APP_STACK_L1
+	if (current_l1_stack_save == mm->context.l1_stack_save)
+		current_l1_stack_save = 0;
+	if (mm->context.l1_stack_save)
+		free_l1stack();
+#endif
+
+	while ((tmp = mm->context.sram_list)) {
+		mm->context.sram_list = tmp->next;
+		sram_free(tmp->addr);
+		kfree(tmp);
+	}
+#ifdef CONFIG_MPU
+	if (current_rwx_mask == mm->context.page_rwx_mask)
+		current_rwx_mask = NULL;
+	free_pages((unsigned long)mm->context.page_rwx_mask, page_mask_order);
+#endif
+}
+
 #endif
diff --git a/arch/blackfin/include/asm/processor.h b/arch/blackfin/include/asm/processor.h
index 6f3995b..e3e9b41 100644
--- a/arch/blackfin/include/asm/processor.h
+++ b/arch/blackfin/include/asm/processor.h
@@ -134,6 +134,12 @@
 	return revid;
 }
 
+static inline uint16_t __pure bfin_cpuid(void)
+{
+	return (bfin_read_CHIPID() & CHIPID_FAMILY) >> 12;
+
+}
+
 static inline uint32_t __pure bfin_compiled_revid(void)
 {
 #if defined(CONFIG_BF_REV_0_0)
diff --git a/arch/blackfin/include/asm/ptrace.h b/arch/blackfin/include/asm/ptrace.h
index a45a80e..e3f086d 100644
--- a/arch/blackfin/include/asm/ptrace.h
+++ b/arch/blackfin/include/asm/ptrace.h
@@ -158,6 +158,8 @@
 #define PT_SEQSTAT 8
 #define PT_IPEND 4
 
+#define PT_ORIG_R0 208
+#define PT_ORIG_P0 212
 #define PT_SYSCFG 216
 #define PT_TEXT_ADDR 220
 #define PT_TEXT_END_ADDR 224
diff --git a/arch/blackfin/include/asm/traps.h b/arch/blackfin/include/asm/traps.h
index f0e5f94..34f7295 100644
--- a/arch/blackfin/include/asm/traps.h
+++ b/arch/blackfin/include/asm/traps.h
@@ -59,6 +59,9 @@
 	level "   or a 16-bit register is accessed with a 32-bit instruction.\n"
 #define HWC_x3(level) \
 	"External Memory Addressing Error\n"
+#define EXC_0x04(level) \
+	"Unimplmented exception occured\n" \
+	level " - Maybe you forgot to install a custom exception handler?\n"
 #define HWC_x12(level) \
 	"Performance Monitor Overflow\n"
 #define HWC_x18(level) \
@@ -84,7 +87,7 @@
 	level "   a particular processor implementation.\n"
 #define EXC_0x22(level) \
 	"Illegal instruction combination\n" \
-	level " - See section for multi-issue rules in the ADSP-BF53x Blackfin\n" \
+	level " - See section for multi-issue rules in the Blackfin\n" \
 	level "   Processor Instruction Set Reference.\n"
 #define EXC_0x23(level) \
 	"Data access CPLB protection violation\n" \
diff --git a/arch/blackfin/kernel/asm-offsets.c b/arch/blackfin/kernel/asm-offsets.c
index 881afe9..9bb85dd 100644
--- a/arch/blackfin/kernel/asm-offsets.c
+++ b/arch/blackfin/kernel/asm-offsets.c
@@ -60,6 +60,7 @@
 	DEFINE(KERNEL_STACK_SIZE, THREAD_SIZE);
 
 	/* offsets into the pt_regs */
+	DEFINE(PT_ORIG_R0, offsetof(struct pt_regs, orig_r0));
 	DEFINE(PT_ORIG_P0, offsetof(struct pt_regs, orig_p0));
 	DEFINE(PT_ORIG_PC, offsetof(struct pt_regs, orig_pc));
 	DEFINE(PT_R0, offsetof(struct pt_regs, r0));
diff --git a/arch/blackfin/kernel/bfin_dma_5xx.c b/arch/blackfin/kernel/bfin_dma_5xx.c
index 93229b3..339293d 100644
--- a/arch/blackfin/kernel/bfin_dma_5xx.c
+++ b/arch/blackfin/kernel/bfin_dma_5xx.c
@@ -117,15 +117,14 @@
 
 #ifdef CONFIG_BF54x
 	if (channel >= CH_UART2_RX && channel <= CH_UART3_TX) {
-		if (strncmp(device_id, "BFIN_UART", 9) == 0) {
-			dma_ch[channel].regs->peripheral_map &= 0x0FFF;
-			dma_ch[channel].regs->peripheral_map |=
+		unsigned int per_map;
+		per_map = dma_ch[channel].regs->peripheral_map & 0xFFF;
+		if (strncmp(device_id, "BFIN_UART", 9) == 0)
+			dma_ch[channel].regs->peripheral_map = per_map |
 				((channel - CH_UART2_RX + 0xC)<<12);
-		} else {
-			dma_ch[channel].regs->peripheral_map &= 0x0FFF;
-			dma_ch[channel].regs->peripheral_map |=
+		else
+			dma_ch[channel].regs->peripheral_map = per_map |
 				((channel - CH_UART2_RX + 0x6)<<12);
-		}
 	}
 #endif
 
diff --git a/arch/blackfin/kernel/bfin_gpio.c b/arch/blackfin/kernel/bfin_gpio.c
index ecbd141..6e08f42 100644
--- a/arch/blackfin/kernel/bfin_gpio.c
+++ b/arch/blackfin/kernel/bfin_gpio.c
@@ -231,14 +231,14 @@
 }
 #endif
 
-void gpio_error(unsigned gpio)
+static void gpio_error(unsigned gpio)
 {
 	printk(KERN_ERR "bfin-gpio: GPIO %d wasn't requested!\n", gpio);
 }
 
 static void set_label(unsigned short ident, const char *label)
 {
-	if (label && str_ident) {
+	if (label) {
 		strncpy(str_ident[ident].name, label,
 			 RESOURCE_LABEL_SIZE);
 		str_ident[ident].name[RESOURCE_LABEL_SIZE - 1] = 0;
@@ -247,9 +247,6 @@
 
 static char *get_label(unsigned short ident)
 {
-	if (!str_ident)
-		return "UNKNOWN";
-
 	return (*str_ident[ident].name ? str_ident[ident].name : "UNKNOWN");
 }
 
@@ -260,7 +257,7 @@
 		printk(KERN_ERR "Please provide none-null label\n");
 	}
 
-	if (label && str_ident)
+	if (label)
 		return strncmp(str_ident[ident].name,
 				 label, strlen(label));
 	else
diff --git a/arch/blackfin/kernel/cplb-mpu/cplbinit.c b/arch/blackfin/kernel/cplb-mpu/cplbinit.c
index 4806010..55af729 100644
--- a/arch/blackfin/kernel/cplb-mpu/cplbinit.c
+++ b/arch/blackfin/kernel/cplb-mpu/cplbinit.c
@@ -36,7 +36,7 @@
 int first_switched_icplb, first_switched_dcplb;
 int first_mask_dcplb;
 
-void __init generate_cpl_tables(void)
+void __init generate_cplb_tables(void)
 {
 	int i_d, i_i;
 	unsigned long addr;
@@ -83,8 +83,18 @@
 	dcplb_tbl[i_d].addr = L1_DATA_A_START;
 	dcplb_tbl[i_d++].data = L1_DMEMORY | PAGE_SIZE_4MB;
 #endif
+#if L1_CODE_LENGTH > 0
 	icplb_tbl[i_i].addr = L1_CODE_START;
 	icplb_tbl[i_i++].data = L1_IMEMORY | PAGE_SIZE_4MB;
+#endif
+
+	/* Cover L2 memory */
+#if L2_LENGTH > 0
+	dcplb_tbl[i_d].addr = L2_START;
+	dcplb_tbl[i_d++].data = L2_DMEMORY | PAGE_SIZE_1MB;
+	icplb_tbl[i_i].addr = L2_START;
+	icplb_tbl[i_i++].data = L2_IMEMORY | PAGE_SIZE_1MB;
+#endif
 
 	first_mask_dcplb = i_d;
 	first_switched_dcplb = i_d + (1 << page_mask_order);
diff --git a/arch/blackfin/kernel/cplb-mpu/cplbmgr.c b/arch/blackfin/kernel/cplb-mpu/cplbmgr.c
index 99f2831..5094677 100644
--- a/arch/blackfin/kernel/cplb-mpu/cplbmgr.c
+++ b/arch/blackfin/kernel/cplb-mpu/cplbmgr.c
@@ -322,9 +322,11 @@
 void flush_switched_cplbs(void)
 {
 	int i;
+	unsigned long flags;
 
 	nr_cplb_flush++;
 
+	local_irq_save(flags);
 	disable_icplb();
 	for (i = first_switched_icplb; i < MAX_CPLBS; i++) {
 		icplb_tbl[i].data = 0;
@@ -338,6 +340,8 @@
 		bfin_write32(DCPLB_DATA0 + i * 4, 0);
 	}
 	enable_dcplb();
+	local_irq_restore(flags);
+
 }
 
 void set_mask_dcplbs(unsigned long *masks)
@@ -345,10 +349,15 @@
 	int i;
 	unsigned long addr = (unsigned long)masks;
 	unsigned long d_data;
-	current_rwx_mask = masks;
+	unsigned long flags;
 
-	if (!masks)
+	if (!masks) {
+		current_rwx_mask = masks;
 		return;
+	}
+
+	local_irq_save(flags);
+	current_rwx_mask = masks;
 
 	d_data = CPLB_SUPV_WR | CPLB_VALID | CPLB_DIRTY | PAGE_SIZE_4KB;
 #ifdef CONFIG_BFIN_DCACHE
@@ -367,4 +376,5 @@
 		addr += PAGE_SIZE;
 	}
 	enable_dcplb();
+	local_irq_restore(flags);
 }
diff --git a/arch/blackfin/kernel/cplb-nompu/cplbinit.c b/arch/blackfin/kernel/cplb-nompu/cplbinit.c
index 728f708..301252e 100644
--- a/arch/blackfin/kernel/cplb-nompu/cplbinit.c
+++ b/arch/blackfin/kernel/cplb-nompu/cplbinit.c
@@ -168,8 +168,8 @@
 		.end = L2_START + L2_LENGTH,
 		.psize = SIZE_1M,
 		.attr = SWITCH_T | I_CPLB | D_CPLB,
-		.i_conf = L2_MEMORY,
-		.d_conf = L2_MEMORY,
+		.i_conf = L2_IMEMORY,
+		.d_conf = L2_DMEMORY,
 		.valid = (L2_LENGTH > 0),
 		.name = "L2 Memory",
 	},
@@ -308,7 +308,7 @@
 	}
 }
 
-void __init generate_cpl_tables(void)
+void __init generate_cplb_tables(void)
 {
 
 	u16 i, j, process;
diff --git a/arch/blackfin/kernel/early_printk.c b/arch/blackfin/kernel/early_printk.c
index 60f67f9..1f4e3d2 100644
--- a/arch/blackfin/kernel/early_printk.c
+++ b/arch/blackfin/kernel/early_printk.c
@@ -35,6 +35,9 @@
 extern struct console *bfin_earlyserial_init(unsigned int port,
 						unsigned int cflag);
 #endif
+#ifdef CONFIG_BFIN_JTAG_COMM
+extern struct console *bfin_jc_early_init(void);
+#endif
 
 static struct console *early_console;
 
@@ -142,6 +145,15 @@
 		early_console = earlyserial_init(buf);
 	}
 #endif
+
+#ifdef CONFIG_BFIN_JTAG_COMM
+	/* Check for Blackfin JTAG */
+	if (!strncmp(buf, "jtag", 4)) {
+		buf += 4;
+		early_console = bfin_jc_early_init();
+	}
+#endif
+
 #ifdef CONFIG_FB
 		/* TODO: add framebuffer console support */
 #endif
diff --git a/arch/blackfin/kernel/kgdb.c b/arch/blackfin/kernel/kgdb.c
index a1f9641..b795a20 100644
--- a/arch/blackfin/kernel/kgdb.c
+++ b/arch/blackfin/kernel/kgdb.c
@@ -1,32 +1,9 @@
 /*
- * File:         arch/blackfin/kernel/kgdb.c
- * Based on:
- * Author:       Sonic Zhang
+ * arch/blackfin/kernel/kgdb.c - Blackfin kgdb pieces
  *
- * Created:
- * Description:
+ * Copyright 2005-2008 Analog Devices Inc.
  *
- * Rev:          $Id: kgdb_bfin_linux-2.6.x.patch 4934 2007-02-13 09:32:11Z sonicz $
- *
- * Modified:
- *               Copyright 2005-2006 Analog Devices Inc.
- *
- * Bugs:         Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see the file COPYING, or write
- * to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ * Licensed under the GPL-2 or later.
  */
 
 #include <linux/string.h>
@@ -39,24 +16,29 @@
 #include <linux/kgdb.h>
 #include <linux/console.h>
 #include <linux/init.h>
-#include <linux/debugger.h>
 #include <linux/errno.h>
 #include <linux/irq.h>
+#include <linux/uaccess.h>
 #include <asm/system.h>
 #include <asm/traps.h>
 #include <asm/blackfin.h>
+#include <asm/dma.h>
 
 /* Put the error code here just in case the user cares.  */
-int gdb_bf533errcode;
+int gdb_bfin_errcode;
 /* Likewise, the vector number here (since GDB only gets the signal
    number through the usual means, and that's not very specific).  */
-int gdb_bf533vector = -1;
+int gdb_bfin_vector = -1;
 
 #if KGDB_MAX_NO_CPUS != 8
 #error change the definition of slavecpulocks
 #endif
 
-void regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs)
+#ifdef CONFIG_BFIN_WDT
+# error "Please unselect blackfin watchdog driver before build KGDB."
+#endif
+
+void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs)
 {
 	gdb_regs[BFIN_R0] = regs->r0;
 	gdb_regs[BFIN_R1] = regs->r1;
@@ -133,7 +115,7 @@
 	gdb_regs[BFIN_SEQSTAT] = p->thread.seqstat;
 }
 
-void gdb_regs_to_regs(unsigned long *gdb_regs, struct pt_regs *regs)
+void gdb_regs_to_pt_regs(unsigned long *gdb_regs, struct pt_regs *regs)
 {
 	regs->r0 = gdb_regs[BFIN_R0];
 	regs->r1 = gdb_regs[BFIN_R1];
@@ -199,171 +181,208 @@
 	unsigned int dataacc:2;
 	unsigned short count;
 	unsigned int addr;
-} breakinfo[HW_BREAKPOINT_NUM];
+} breakinfo[HW_WATCHPOINT_NUM];
 
-int kgdb_arch_init(void)
-{
-	debugger_step = 0;
-
-	kgdb_remove_all_hw_break();
-	return 0;
-}
-
-int kgdb_set_hw_break(unsigned long addr)
+int bfin_set_hw_break(unsigned long addr, int len, enum kgdb_bptype type)
 {
 	int breakno;
-	for (breakno = 0; breakno < HW_BREAKPOINT_NUM; breakno++)
-		if (!breakinfo[breakno].occupied) {
+	int bfin_type;
+	int dataacc = 0;
+
+	switch (type) {
+	case BP_HARDWARE_BREAKPOINT:
+		bfin_type = TYPE_INST_WATCHPOINT;
+		break;
+	case BP_WRITE_WATCHPOINT:
+		dataacc = 1;
+		bfin_type = TYPE_DATA_WATCHPOINT;
+		break;
+	case BP_READ_WATCHPOINT:
+		dataacc = 2;
+		bfin_type = TYPE_DATA_WATCHPOINT;
+		break;
+	case BP_ACCESS_WATCHPOINT:
+		dataacc = 3;
+		bfin_type = TYPE_DATA_WATCHPOINT;
+		break;
+	default:
+		return -ENOSPC;
+	}
+
+	/* Becasue hardware data watchpoint impelemented in current
+	 * Blackfin can not trigger an exception event as the hardware
+	 * instrction watchpoint does, we ignaore all data watch point here.
+	 * They can be turned on easily after future blackfin design
+	 * supports this feature.
+	 */
+	for (breakno = 0; breakno < HW_INST_WATCHPOINT_NUM; breakno++)
+		if (bfin_type == breakinfo[breakno].type
+			&& !breakinfo[breakno].occupied) {
 			breakinfo[breakno].occupied = 1;
 			breakinfo[breakno].enabled = 1;
-			breakinfo[breakno].type = 1;
 			breakinfo[breakno].addr = addr;
+			breakinfo[breakno].dataacc = dataacc;
+			breakinfo[breakno].count = 0;
 			return 0;
 		}
 
 	return -ENOSPC;
 }
 
-int kgdb_remove_hw_break(unsigned long addr)
+int bfin_remove_hw_break(unsigned long addr, int len, enum kgdb_bptype type)
 {
 	int breakno;
-	for (breakno = 0; breakno < HW_BREAKPOINT_NUM; breakno++)
-		if (breakinfo[breakno].addr == addr)
-			memset(&(breakinfo[breakno]), 0, sizeof(struct hw_breakpoint));
+	int bfin_type;
+
+	switch (type) {
+	case BP_HARDWARE_BREAKPOINT:
+		bfin_type = TYPE_INST_WATCHPOINT;
+		break;
+	case BP_WRITE_WATCHPOINT:
+	case BP_READ_WATCHPOINT:
+	case BP_ACCESS_WATCHPOINT:
+		bfin_type = TYPE_DATA_WATCHPOINT;
+		break;
+	default:
+		return 0;
+	}
+	for (breakno = 0; breakno < HW_WATCHPOINT_NUM; breakno++)
+		if (bfin_type == breakinfo[breakno].type
+			&& breakinfo[breakno].occupied
+			&& breakinfo[breakno].addr == addr) {
+			breakinfo[breakno].occupied = 0;
+			breakinfo[breakno].enabled = 0;
+		}
 
 	return 0;
 }
 
-void kgdb_remove_all_hw_break(void)
-{
-	memset(breakinfo, 0, sizeof(struct hw_breakpoint)*8);
-}
-
-/*
-void kgdb_show_info(void)
-{
-	printk(KERN_DEBUG "hwd: wpia0=0x%x, wpiacnt0=%d, wpiactl=0x%x, wpstat=0x%x\n",
-		bfin_read_WPIA0(), bfin_read_WPIACNT0(),
-		bfin_read_WPIACTL(), bfin_read_WPSTAT());
-}
-*/
-
-void kgdb_correct_hw_break(void)
+void bfin_remove_all_hw_break(void)
 {
 	int breakno;
-	int correctit;
-	uint32_t wpdactl = bfin_read_WPDACTL();
 
-	correctit = 0;
-	for (breakno = 0; breakno < HW_BREAKPOINT_NUM; breakno++) {
-		if (breakinfo[breakno].type == 1) {
+	memset(breakinfo, 0, sizeof(struct hw_breakpoint)*HW_WATCHPOINT_NUM);
+
+	for (breakno = 0; breakno < HW_INST_WATCHPOINT_NUM; breakno++)
+		breakinfo[breakno].type = TYPE_INST_WATCHPOINT;
+	for (; breakno < HW_WATCHPOINT_NUM; breakno++)
+		breakinfo[breakno].type = TYPE_DATA_WATCHPOINT;
+}
+
+void bfin_correct_hw_break(void)
+{
+	int breakno;
+	unsigned int wpiactl = 0;
+	unsigned int wpdactl = 0;
+	int enable_wp = 0;
+
+	for (breakno = 0; breakno < HW_WATCHPOINT_NUM; breakno++)
+		if (breakinfo[breakno].enabled) {
+			enable_wp = 1;
+
 			switch (breakno) {
 			case 0:
-				if (breakinfo[breakno].enabled && !(wpdactl & WPIAEN0)) {
-					correctit = 1;
-					wpdactl &= ~(WPIREN01|EMUSW0);
-					wpdactl |= WPIAEN0|WPICNTEN0;
-					bfin_write_WPIA0(breakinfo[breakno].addr);
-					bfin_write_WPIACNT0(breakinfo[breakno].skip);
-				} else if (!breakinfo[breakno].enabled && (wpdactl & WPIAEN0)) {
-					correctit = 1;
-					wpdactl &= ~WPIAEN0;
-				}
+				wpiactl |= WPIAEN0|WPICNTEN0;
+				bfin_write_WPIA0(breakinfo[breakno].addr);
+				bfin_write_WPIACNT0(breakinfo[breakno].count
+					+ breakinfo->skip);
 				break;
-
 			case 1:
-				if (breakinfo[breakno].enabled && !(wpdactl & WPIAEN1)) {
-					correctit = 1;
-					wpdactl &= ~(WPIREN01|EMUSW1);
-					wpdactl |= WPIAEN1|WPICNTEN1;
-					bfin_write_WPIA1(breakinfo[breakno].addr);
-					bfin_write_WPIACNT1(breakinfo[breakno].skip);
-				} else if (!breakinfo[breakno].enabled && (wpdactl & WPIAEN1)) {
-					correctit = 1;
-					wpdactl &= ~WPIAEN1;
-				}
+				wpiactl |= WPIAEN1|WPICNTEN1;
+				bfin_write_WPIA1(breakinfo[breakno].addr);
+				bfin_write_WPIACNT1(breakinfo[breakno].count
+					+ breakinfo->skip);
 				break;
-
 			case 2:
-				if (breakinfo[breakno].enabled && !(wpdactl & WPIAEN2)) {
-					correctit = 1;
-					wpdactl &= ~(WPIREN23|EMUSW2);
-					wpdactl |= WPIAEN2|WPICNTEN2;
-					bfin_write_WPIA2(breakinfo[breakno].addr);
-					bfin_write_WPIACNT2(breakinfo[breakno].skip);
-				} else if (!breakinfo[breakno].enabled && (wpdactl & WPIAEN2)) {
-					correctit = 1;
-					wpdactl &= ~WPIAEN2;
-				}
+				wpiactl |= WPIAEN2|WPICNTEN2;
+				bfin_write_WPIA2(breakinfo[breakno].addr);
+				bfin_write_WPIACNT2(breakinfo[breakno].count
+					+ breakinfo->skip);
 				break;
-
 			case 3:
-				if (breakinfo[breakno].enabled && !(wpdactl & WPIAEN3)) {
-					correctit = 1;
-					wpdactl &= ~(WPIREN23|EMUSW3);
-					wpdactl |= WPIAEN3|WPICNTEN3;
-					bfin_write_WPIA3(breakinfo[breakno].addr);
-					bfin_write_WPIACNT3(breakinfo[breakno].skip);
-				} else if (!breakinfo[breakno].enabled && (wpdactl & WPIAEN3)) {
-					correctit = 1;
-					wpdactl &= ~WPIAEN3;
-				}
+				wpiactl |= WPIAEN3|WPICNTEN3;
+				bfin_write_WPIA3(breakinfo[breakno].addr);
+				bfin_write_WPIACNT3(breakinfo[breakno].count
+					+ breakinfo->skip);
 				break;
 			case 4:
-				if (breakinfo[breakno].enabled && !(wpdactl & WPIAEN4)) {
-					correctit = 1;
-					wpdactl &= ~(WPIREN45|EMUSW4);
-					wpdactl |= WPIAEN4|WPICNTEN4;
-					bfin_write_WPIA4(breakinfo[breakno].addr);
-					bfin_write_WPIACNT4(breakinfo[breakno].skip);
-				} else if (!breakinfo[breakno].enabled && (wpdactl & WPIAEN4)) {
-					correctit = 1;
-					wpdactl &= ~WPIAEN4;
-				}
+				wpiactl |= WPIAEN4|WPICNTEN4;
+				bfin_write_WPIA4(breakinfo[breakno].addr);
+				bfin_write_WPIACNT4(breakinfo[breakno].count
+					+ breakinfo->skip);
 				break;
 			case 5:
-				if (breakinfo[breakno].enabled && !(wpdactl & WPIAEN5)) {
-					correctit = 1;
-					wpdactl &= ~(WPIREN45|EMUSW5);
-					wpdactl |= WPIAEN5|WPICNTEN5;
-					bfin_write_WPIA5(breakinfo[breakno].addr);
-					bfin_write_WPIACNT5(breakinfo[breakno].skip);
-				} else if (!breakinfo[breakno].enabled && (wpdactl & WPIAEN5)) {
-					correctit = 1;
-					wpdactl &= ~WPIAEN5;
-				}
+				wpiactl |= WPIAEN5|WPICNTEN5;
+				bfin_write_WPIA5(breakinfo[breakno].addr);
+				bfin_write_WPIACNT5(breakinfo[breakno].count
+					+ breakinfo->skip);
+				break;
+			case 6:
+				wpdactl |= WPDAEN0|WPDCNTEN0|WPDSRC0;
+				wpdactl |= breakinfo[breakno].dataacc
+					<< WPDACC0_OFFSET;
+				bfin_write_WPDA0(breakinfo[breakno].addr);
+				bfin_write_WPDACNT0(breakinfo[breakno].count
+					+ breakinfo->skip);
+				break;
+			case 7:
+				wpdactl |= WPDAEN1|WPDCNTEN1|WPDSRC1;
+				wpdactl |= breakinfo[breakno].dataacc
+					<< WPDACC1_OFFSET;
+				bfin_write_WPDA1(breakinfo[breakno].addr);
+				bfin_write_WPDACNT1(breakinfo[breakno].count
+					+ breakinfo->skip);
 				break;
 			}
 		}
-	}
-	if (correctit) {
-		wpdactl &= ~WPAND;
-		wpdactl |= WPPWR;
-		/*printk("correct_hw_break: wpdactl=0x%x\n", wpdactl);*/
+
+	/* Should enable WPPWR bit first before set any other
+	 * WPIACTL and WPDACTL bits */
+	if (enable_wp) {
+		bfin_write_WPIACTL(WPPWR);
+		CSYNC();
+		bfin_write_WPIACTL(wpiactl|WPPWR);
 		bfin_write_WPDACTL(wpdactl);
 		CSYNC();
-		/*kgdb_show_info();*/
 	}
 }
 
 void kgdb_disable_hw_debug(struct pt_regs *regs)
 {
 	/* Disable hardware debugging while we are in kgdb */
-	bfin_write_WPIACTL(bfin_read_WPIACTL() & ~0x1);
+	bfin_write_WPIACTL(0);
+	bfin_write_WPDACTL(0);
 	CSYNC();
 }
 
-void kgdb_post_master_code(struct pt_regs *regs, int eVector, int err_code)
+#ifdef CONFIG_SMP
+void kgdb_passive_cpu_callback(void *info)
 {
-	/* Master processor is completely in the debugger */
-	gdb_bf533vector = eVector;
-	gdb_bf533errcode = err_code;
+	kgdb_nmicallback(raw_smp_processor_id(), get_irq_regs());
 }
 
-int kgdb_arch_handle_exception(int exceptionVector, int signo,
+void kgdb_roundup_cpus(unsigned long flags)
+{
+	smp_call_function(kgdb_passive_cpu_callback, NULL, 0, 0);
+}
+
+void kgdb_roundup_cpu(int cpu, unsigned long flags)
+{
+	smp_call_function_single(cpu, kgdb_passive_cpu_callback, NULL, 0, 0);
+}
+#endif
+
+void kgdb_post_primary_code(struct pt_regs *regs, int eVector, int err_code)
+{
+	/* Master processor is completely in the debugger */
+	gdb_bfin_vector = eVector;
+	gdb_bfin_errcode = err_code;
+}
+
+int kgdb_arch_handle_exception(int vector, int signo,
 			       int err_code, char *remcom_in_buffer,
 			       char *remcom_out_buffer,
-			       struct pt_regs *linux_regs)
+			       struct pt_regs *regs)
 {
 	long addr;
 	long breakno;
@@ -385,44 +404,40 @@
 		/* try to read optional parameter, pc unchanged if no parm */
 		ptr = &remcom_in_buffer[1];
 		if (kgdb_hex2long(&ptr, &addr)) {
-			linux_regs->retx = addr;
+			regs->retx = addr;
 		}
-		newPC = linux_regs->retx;
+		newPC = regs->retx;
 
 		/* clear the trace bit */
-		linux_regs->syscfg &= 0xfffffffe;
+		regs->syscfg &= 0xfffffffe;
 
 		/* set the trace bit if we're stepping */
 		if (remcom_in_buffer[0] == 's') {
-			linux_regs->syscfg |= 0x1;
-			debugger_step = linux_regs->ipend;
-			debugger_step >>= 6;
-			for (i = 10; i > 0; i--, debugger_step >>= 1)
-				if (debugger_step & 1)
+			regs->syscfg |= 0x1;
+			kgdb_single_step = regs->ipend;
+			kgdb_single_step >>= 6;
+			for (i = 10; i > 0; i--, kgdb_single_step >>= 1)
+				if (kgdb_single_step & 1)
 					break;
 			/* i indicate event priority of current stopped instruction
 			 * user space instruction is 0, IVG15 is 1, IVTMR is 10.
-			 * debugger_step > 0 means in single step mode
+			 * kgdb_single_step > 0 means in single step mode
 			 */
-			debugger_step = i + 1;
-		} else {
-			debugger_step = 0;
+			kgdb_single_step = i + 1;
 		}
 
-		wp_status = bfin_read_WPSTAT();
-		CSYNC();
-
-		if (exceptionVector == VEC_WATCH) {
-			for (breakno = 0; breakno < 6; ++breakno) {
+		if (vector == VEC_WATCH) {
+			wp_status = bfin_read_WPSTAT();
+			for (breakno = 0; breakno < HW_WATCHPOINT_NUM; breakno++) {
 				if (wp_status & (1 << breakno)) {
 					breakinfo->skip = 1;
 					break;
 				}
 			}
+			bfin_write_WPSTAT(0);
 		}
-		kgdb_correct_hw_break();
 
-		bfin_write_WPSTAT(0);
+		bfin_correct_hw_break();
 
 		return 0;
 	}			/* switch */
@@ -431,5 +446,385 @@
 
 struct kgdb_arch arch_kgdb_ops = {
 	.gdb_bpt_instr = {0xa1},
+#ifdef CONFIG_SMP
+	.flags = KGDB_HW_BREAKPOINT|KGDB_THR_PROC_SWAP,
+#else
 	.flags = KGDB_HW_BREAKPOINT,
+#endif
+	.set_hw_breakpoint = bfin_set_hw_break,
+	.remove_hw_breakpoint = bfin_remove_hw_break,
+	.remove_all_hw_break = bfin_remove_all_hw_break,
+	.correct_hw_break = bfin_correct_hw_break,
 };
+
+static int hex(char ch)
+{
+	if ((ch >= 'a') && (ch <= 'f'))
+		return ch - 'a' + 10;
+	if ((ch >= '0') && (ch <= '9'))
+		return ch - '0';
+	if ((ch >= 'A') && (ch <= 'F'))
+		return ch - 'A' + 10;
+	return -1;
+}
+
+static int validate_memory_access_address(unsigned long addr, int size)
+{
+	int cpu = raw_smp_processor_id();
+
+	if (size < 0)
+		return EFAULT;
+	if (addr >= 0x1000 && (addr + size) <= physical_mem_end)
+		return 0;
+	if (addr >= SYSMMR_BASE)
+		return 0;
+	if (addr >= ASYNC_BANK0_BASE
+	   && addr + size <= ASYNC_BANK3_BASE + ASYNC_BANK3_SIZE)
+		return 0;
+	if (cpu == 0) {
+		if (addr >= L1_SCRATCH_START
+		   && (addr + size <= L1_SCRATCH_START + L1_SCRATCH_LENGTH))
+			return 0;
+#if L1_CODE_LENGTH != 0
+		if (addr >= L1_CODE_START
+		   && (addr + size <= L1_CODE_START + L1_CODE_LENGTH))
+			return 0;
+#endif
+#if L1_DATA_A_LENGTH != 0
+		if (addr >= L1_DATA_A_START
+		   && (addr + size <= L1_DATA_A_START + L1_DATA_A_LENGTH))
+			return 0;
+#endif
+#if L1_DATA_B_LENGTH != 0
+		if (addr >= L1_DATA_B_START
+		   && (addr + size <= L1_DATA_B_START + L1_DATA_B_LENGTH))
+			return 0;
+#endif
+#ifdef CONFIG_SMP
+	} else if (cpu == 1) {
+		if (addr >= COREB_L1_SCRATCH_START
+		   && (addr + size <= COREB_L1_SCRATCH_START
+		   + L1_SCRATCH_LENGTH))
+			return 0;
+# if L1_CODE_LENGTH != 0
+		if (addr >= COREB_L1_CODE_START
+		   && (addr + size <= COREB_L1_CODE_START + L1_CODE_LENGTH))
+			return 0;
+# endif
+# if L1_DATA_A_LENGTH != 0
+		if (addr >= COREB_L1_DATA_A_START
+		   && (addr + size <= COREB_L1_DATA_A_START + L1_DATA_A_LENGTH))
+			return 0;
+# endif
+# if L1_DATA_B_LENGTH != 0
+		if (addr >= COREB_L1_DATA_B_START
+		   && (addr + size <= COREB_L1_DATA_B_START + L1_DATA_B_LENGTH))
+			return 0;
+# endif
+#endif
+	}
+
+#if L2_LENGTH != 0
+	if (addr >= L2_START
+	   && addr + size <= L2_START + L2_LENGTH)
+		return 0;
+#endif
+
+	return EFAULT;
+}
+
+/*
+ * Convert the memory pointed to by mem into hex, placing result in buf.
+ * Return a pointer to the last char put in buf (null). May return an error.
+ */
+int kgdb_mem2hex(char *mem, char *buf, int count)
+{
+	char *tmp;
+	int err = 0;
+	unsigned char *pch;
+	unsigned short mmr16;
+	unsigned long mmr32;
+	int cpu = raw_smp_processor_id();
+
+	if (validate_memory_access_address((unsigned long)mem, count))
+		return EFAULT;
+
+	/*
+	 * We use the upper half of buf as an intermediate buffer for the
+	 * raw memory copy.  Hex conversion will work against this one.
+	 */
+	tmp = buf + count;
+
+	if ((unsigned int)mem >= SYSMMR_BASE) { /*access MMR registers*/
+		switch (count) {
+		case 2:
+			if ((unsigned int)mem % 2 == 0) {
+				mmr16 = *(unsigned short *)mem;
+				pch = (unsigned char *)&mmr16;
+				*tmp++ = *pch++;
+				*tmp++ = *pch++;
+				tmp -= 2;
+			} else
+				err = EFAULT;
+			break;
+		case 4:
+			if ((unsigned int)mem % 4 == 0) {
+				mmr32 = *(unsigned long *)mem;
+				pch = (unsigned char *)&mmr32;
+				*tmp++ = *pch++;
+				*tmp++ = *pch++;
+				*tmp++ = *pch++;
+				*tmp++ = *pch++;
+				tmp -= 4;
+			} else
+				err = EFAULT;
+			break;
+		default:
+			err = EFAULT;
+		}
+	} else if (cpu == 0 && (unsigned int)mem >= L1_CODE_START &&
+		(unsigned int)(mem + count) <= L1_CODE_START + L1_CODE_LENGTH
+#ifdef CONFIG_SMP
+		|| cpu == 1 && (unsigned int)mem >= COREB_L1_CODE_START &&
+		(unsigned int)(mem + count) <=
+		COREB_L1_CODE_START + L1_CODE_LENGTH
+#endif
+		) {
+		/* access L1 instruction SRAM*/
+		if (dma_memcpy(tmp, mem, count) == NULL)
+			err = EFAULT;
+	} else
+		err = probe_kernel_read(tmp, mem, count);
+
+	if (!err) {
+		while (count > 0) {
+			buf = pack_hex_byte(buf, *tmp);
+			tmp++;
+			count--;
+		}
+
+		*buf = 0;
+	}
+
+	return err;
+}
+
+/*
+ * Copy the binary array pointed to by buf into mem.  Fix $, #, and
+ * 0x7d escaped with 0x7d.  Return a pointer to the character after
+ * the last byte written.
+ */
+int kgdb_ebin2mem(char *buf, char *mem, int count)
+{
+	char *tmp_old;
+	char *tmp_new;
+	unsigned short *mmr16;
+	unsigned long *mmr32;
+	int err = 0;
+	int size = 0;
+	int cpu = raw_smp_processor_id();
+
+	tmp_old = tmp_new = buf;
+
+	while (count-- > 0) {
+		if (*tmp_old == 0x7d)
+			*tmp_new = *(++tmp_old) ^ 0x20;
+		else
+			*tmp_new = *tmp_old;
+		tmp_new++;
+		tmp_old++;
+		size++;
+	}
+
+	if (validate_memory_access_address((unsigned long)mem, size))
+		return EFAULT;
+
+	if ((unsigned int)mem >= SYSMMR_BASE) { /*access MMR registers*/
+		switch (size) {
+		case 2:
+			if ((unsigned int)mem % 2 == 0) {
+				mmr16 = (unsigned short *)buf;
+				*(unsigned short *)mem = *mmr16;
+			} else
+				return EFAULT;
+			break;
+		case 4:
+			if ((unsigned int)mem % 4 == 0) {
+				mmr32 = (unsigned long *)buf;
+				*(unsigned long *)mem = *mmr32;
+			} else
+				return EFAULT;
+			break;
+		default:
+			return EFAULT;
+		}
+	} else if (cpu == 0 && (unsigned int)mem >= L1_CODE_START &&
+		(unsigned int)(mem + count) < L1_CODE_START + L1_CODE_LENGTH
+#ifdef CONFIG_SMP
+		|| cpu == 1 && (unsigned int)mem >= COREB_L1_CODE_START &&
+		(unsigned int)(mem + count) <=
+		COREB_L1_CODE_START + L1_CODE_LENGTH
+#endif
+		) {
+		/* access L1 instruction SRAM */
+		if (dma_memcpy(mem, buf, size) == NULL)
+			err = EFAULT;
+	} else
+		err = probe_kernel_write(mem, buf, size);
+
+	return err;
+}
+
+/*
+ * Convert the hex array pointed to by buf into binary to be placed in mem.
+ * Return a pointer to the character AFTER the last byte written.
+ * May return an error.
+ */
+int kgdb_hex2mem(char *buf, char *mem, int count)
+{
+	char *tmp_raw;
+	char *tmp_hex;
+	unsigned short *mmr16;
+	unsigned long *mmr32;
+	int cpu = raw_smp_processor_id();
+
+	if (validate_memory_access_address((unsigned long)mem, count))
+		return EFAULT;
+
+	/*
+	 * We use the upper half of buf as an intermediate buffer for the
+	 * raw memory that is converted from hex.
+	 */
+	tmp_raw = buf + count * 2;
+
+	tmp_hex = tmp_raw - 1;
+	while (tmp_hex >= buf) {
+		tmp_raw--;
+		*tmp_raw = hex(*tmp_hex--);
+		*tmp_raw |= hex(*tmp_hex--) << 4;
+	}
+
+	if ((unsigned int)mem >= SYSMMR_BASE) { /*access MMR registers*/
+		switch (count) {
+		case 2:
+			if ((unsigned int)mem % 2 == 0) {
+				mmr16 = (unsigned short *)tmp_raw;
+				*(unsigned short *)mem = *mmr16;
+			} else
+				return EFAULT;
+			break;
+		case 4:
+			if ((unsigned int)mem % 4 == 0) {
+				mmr32 = (unsigned long *)tmp_raw;
+				*(unsigned long *)mem = *mmr32;
+			} else
+				return EFAULT;
+			break;
+		default:
+			return EFAULT;
+		}
+	} else if (cpu == 0 && (unsigned int)mem >= L1_CODE_START &&
+		(unsigned int)(mem + count) <= L1_CODE_START + L1_CODE_LENGTH
+#ifdef CONFIG_SMP
+		|| cpu == 1 && (unsigned int)mem >= COREB_L1_CODE_START &&
+		(unsigned int)(mem + count) <=
+		COREB_L1_CODE_START + L1_CODE_LENGTH
+#endif
+		) {
+		/* access L1 instruction SRAM */
+		if (dma_memcpy(mem, tmp_raw, count) == NULL)
+			return EFAULT;
+	} else
+		return probe_kernel_write(mem, tmp_raw, count);
+	return 0;
+}
+
+int kgdb_validate_break_address(unsigned long addr)
+{
+	int cpu = raw_smp_processor_id();
+
+	if (addr >= 0x1000 && (addr + BREAK_INSTR_SIZE) <= physical_mem_end)
+		return 0;
+	if (addr >= ASYNC_BANK0_BASE
+	   && addr + BREAK_INSTR_SIZE <= ASYNC_BANK3_BASE + ASYNC_BANK3_BASE)
+		return 0;
+#if L1_CODE_LENGTH != 0
+	if (cpu == 0 && addr >= L1_CODE_START
+	   && addr + BREAK_INSTR_SIZE <= L1_CODE_START + L1_CODE_LENGTH)
+		return 0;
+# ifdef CONFIG_SMP
+	else if (cpu == 1 && addr >= COREB_L1_CODE_START
+	   && addr + BREAK_INSTR_SIZE <= COREB_L1_CODE_START + L1_CODE_LENGTH)
+		return 0;
+# endif
+#endif
+#if L2_LENGTH != 0
+	if (addr >= L2_START
+	   && addr + BREAK_INSTR_SIZE <= L2_START + L2_LENGTH)
+		return 0;
+#endif
+
+	return EFAULT;
+}
+
+int kgdb_arch_set_breakpoint(unsigned long addr, char *saved_instr)
+{
+	int err;
+	int cpu = raw_smp_processor_id();
+
+	if ((cpu == 0 && (unsigned int)addr >= L1_CODE_START
+		&& (unsigned int)(addr + BREAK_INSTR_SIZE)
+		< L1_CODE_START + L1_CODE_LENGTH)
+#ifdef CONFIG_SMP
+		|| (cpu == 1 && (unsigned int)addr >= COREB_L1_CODE_START
+		&& (unsigned int)(addr + BREAK_INSTR_SIZE)
+		< COREB_L1_CODE_START + L1_CODE_LENGTH)
+#endif
+		) {
+		/* access L1 instruction SRAM */
+		if (dma_memcpy(saved_instr, (void *)addr, BREAK_INSTR_SIZE)
+			== NULL)
+			return -EFAULT;
+
+		if (dma_memcpy((void *)addr, arch_kgdb_ops.gdb_bpt_instr,
+			BREAK_INSTR_SIZE) == NULL)
+			return -EFAULT;
+
+		return 0;
+	} else {
+		err = probe_kernel_read(saved_instr, (char *)addr,
+			BREAK_INSTR_SIZE);
+		if (err)
+			return err;
+
+		return probe_kernel_write((char *)addr,
+			arch_kgdb_ops.gdb_bpt_instr, BREAK_INSTR_SIZE);
+	}
+}
+
+int kgdb_arch_remove_breakpoint(unsigned long addr, char *bundle)
+{
+	if ((unsigned int)addr >= L1_CODE_START &&
+		(unsigned int)(addr + BREAK_INSTR_SIZE) <
+			L1_CODE_START + L1_CODE_LENGTH) {
+		/* access L1 instruction SRAM */
+		if (dma_memcpy((void *)addr, bundle, BREAK_INSTR_SIZE) == NULL)
+			return -EFAULT;
+
+		return 0;
+	} else
+		return probe_kernel_write((char *)addr,
+				(char *)bundle, BREAK_INSTR_SIZE);
+}
+
+int kgdb_arch_init(void)
+{
+	kgdb_single_step = 0;
+
+	bfin_remove_all_hw_break();
+	return 0;
+}
+
+void kgdb_arch_exit(void)
+{
+}
diff --git a/arch/blackfin/kernel/ptrace.c b/arch/blackfin/kernel/ptrace.c
index bf1a51d..140bf00 100644
--- a/arch/blackfin/kernel/ptrace.c
+++ b/arch/blackfin/kernel/ptrace.c
@@ -46,7 +46,6 @@
 #include <asm/dma.h>
 #include <asm/fixed_code.h>
 
-#define MAX_SHARED_LIBS 3
 #define TEXT_OFFSET 0
 /*
  * does not yet catch signals sent when the child dies.
@@ -161,21 +160,32 @@
 	struct vm_list_struct *vml;
 	struct sram_list_struct *sraml;
 
+	/* overflow */
+	if (start + len < start)
+		return -EIO;
+
 	for (vml = child->mm->context.vmlist; vml; vml = vml->next)
-		if (start >= vml->vma->vm_start && start + len <= vml->vma->vm_end)
+		if (start >= vml->vma->vm_start && start + len < vml->vma->vm_end)
 			return 0;
 
 	for (sraml = child->mm->context.sram_list; sraml; sraml = sraml->next)
 		if (start >= (unsigned long)sraml->addr
-		    && start + len <= (unsigned long)sraml->addr + sraml->length)
+		    && start + len < (unsigned long)sraml->addr + sraml->length)
 			return 0;
 
-	if (start >= FIXED_CODE_START && start + len <= FIXED_CODE_END)
+	if (start >= FIXED_CODE_START && start + len < FIXED_CODE_END)
 		return 0;
 
 	return -EIO;
 }
 
+void ptrace_enable(struct task_struct *child)
+{
+	unsigned long tmp;
+	tmp = get_reg(child, PT_SYSCFG) | (TRACE_BITS);
+	put_reg(child, PT_SYSCFG, tmp);
+}
+
 /*
  * Called by kernel/ptrace.c when detaching..
  *
@@ -192,14 +202,12 @@
 long arch_ptrace(struct task_struct *child, long request, long addr, long data)
 {
 	int ret;
-	int add = 0;
 	unsigned long __user *datap = (unsigned long __user *)data;
 
 	switch (request) {
 		/* when I and D space are separate, these will need to be fixed. */
 	case PTRACE_PEEKDATA:
 		pr_debug("ptrace: PEEKDATA\n");
-		add = MAX_SHARED_LIBS * 4;	/* space between text and data */
 		/* fall through */
 	case PTRACE_PEEKTEXT:	/* read word at location addr. */
 		{
@@ -207,40 +215,35 @@
 			int copied;
 
 			ret = -EIO;
-			pr_debug("ptrace: PEEKTEXT at addr 0x%08lx + add %d %ld\n", addr, add,
-			         sizeof(data));
-			if (is_user_addr_valid(child, addr + add, sizeof(tmp)) < 0)
+			pr_debug("ptrace: PEEKTEXT at addr 0x%08lx + %ld\n", addr, sizeof(data));
+			if (is_user_addr_valid(child, addr, sizeof(tmp)) < 0)
 				break;
 			pr_debug("ptrace: user address is valid\n");
 
-#if L1_CODE_LENGTH != 0
-			if (addr + add >= L1_CODE_START
-			    && addr + add + sizeof(tmp) <= L1_CODE_START + L1_CODE_LENGTH) {
-				safe_dma_memcpy (&tmp, (const void *)(addr + add), sizeof(tmp));
+			if (L1_CODE_LENGTH != 0 && addr >= L1_CODE_START
+			    && addr + sizeof(tmp) <= L1_CODE_START + L1_CODE_LENGTH) {
+				safe_dma_memcpy (&tmp, (const void *)(addr), sizeof(tmp));
 				copied = sizeof(tmp);
-			} else
-#endif
-#if L1_DATA_A_LENGTH != 0
-			if (addr + add >= L1_DATA_A_START
-			    && addr + add + sizeof(tmp) <= L1_DATA_A_START + L1_DATA_A_LENGTH) {
-				memcpy(&tmp, (const void *)(addr + add), sizeof(tmp));
+
+			} else if (L1_DATA_A_LENGTH != 0 && addr >= L1_DATA_A_START
+			    && addr + sizeof(tmp) <= L1_DATA_A_START + L1_DATA_A_LENGTH) {
+				memcpy(&tmp, (const void *)(addr), sizeof(tmp));
 				copied = sizeof(tmp);
-			} else
-#endif
-#if L1_DATA_B_LENGTH != 0
-			if (addr + add >= L1_DATA_B_START
-			    && addr + add + sizeof(tmp) <= L1_DATA_B_START + L1_DATA_B_LENGTH) {
-				memcpy(&tmp, (const void *)(addr + add), sizeof(tmp));
+
+			} else if (L1_DATA_B_LENGTH != 0 && addr >= L1_DATA_B_START
+			    && addr + sizeof(tmp) <= L1_DATA_B_START + L1_DATA_B_LENGTH) {
+				memcpy(&tmp, (const void *)(addr), sizeof(tmp));
 				copied = sizeof(tmp);
-			} else
-#endif
-			if (addr + add >= FIXED_CODE_START
-			    && addr + add + sizeof(tmp) <= FIXED_CODE_END) {
-				memcpy(&tmp, (const void *)(addr + add), sizeof(tmp));
+
+			} else if (addr >= FIXED_CODE_START
+			    && addr + sizeof(tmp) <= FIXED_CODE_END) {
+				memcpy(&tmp, (const void *)(addr), sizeof(tmp));
 				copied = sizeof(tmp);
+
 			} else
-				copied = access_process_vm(child, addr + add, &tmp,
+				copied = access_process_vm(child, addr, &tmp,
 							   sizeof(tmp), 0);
+
 			pr_debug("ptrace: copied size %d [0x%08lx]\n", copied, tmp);
 			if (copied != sizeof(tmp))
 				break;
@@ -284,47 +287,43 @@
 
 		/* when I and D space are separate, this will have to be fixed. */
 	case PTRACE_POKEDATA:
-		printk(KERN_NOTICE "ptrace: PTRACE_PEEKDATA\n");
+		pr_debug("ptrace: PTRACE_PEEKDATA\n");
 		/* fall through */
 	case PTRACE_POKETEXT:	/* write the word at location addr. */
 		{
 			int copied;
 
 			ret = -EIO;
-			pr_debug("ptrace: POKETEXT at addr 0x%08lx + add %d %ld bytes %lx\n",
-			         addr, add, sizeof(data), data);
-			if (is_user_addr_valid(child, addr + add, sizeof(data)) < 0)
+			pr_debug("ptrace: POKETEXT at addr 0x%08lx + %ld bytes %lx\n",
+			         addr, sizeof(data), data);
+			if (is_user_addr_valid(child, addr, sizeof(data)) < 0)
 				break;
 			pr_debug("ptrace: user address is valid\n");
 
-#if L1_CODE_LENGTH != 0
-			if (addr + add >= L1_CODE_START
-			    && addr + add + sizeof(data) <= L1_CODE_START + L1_CODE_LENGTH) {
-				safe_dma_memcpy ((void *)(addr + add), &data, sizeof(data));
+			if (L1_CODE_LENGTH != 0 && addr >= L1_CODE_START
+			    && addr + sizeof(data) <= L1_CODE_START + L1_CODE_LENGTH) {
+				safe_dma_memcpy ((void *)(addr), &data, sizeof(data));
 				copied = sizeof(data);
-			} else
-#endif
-#if L1_DATA_A_LENGTH != 0
-			if (addr + add >= L1_DATA_A_START
-			    && addr + add + sizeof(data) <= L1_DATA_A_START + L1_DATA_A_LENGTH) {
-				memcpy((void *)(addr + add), &data, sizeof(data));
+
+			} else if (L1_DATA_A_LENGTH != 0 && addr >= L1_DATA_A_START
+			    && addr + sizeof(data) <= L1_DATA_A_START + L1_DATA_A_LENGTH) {
+				memcpy((void *)(addr), &data, sizeof(data));
 				copied = sizeof(data);
-			} else
-#endif
-#if L1_DATA_B_LENGTH != 0
-			if (addr + add >= L1_DATA_B_START
-			    && addr + add + sizeof(data) <= L1_DATA_B_START + L1_DATA_B_LENGTH) {
-				memcpy((void *)(addr + add), &data, sizeof(data));
+
+			} else if (L1_DATA_B_LENGTH != 0 && addr >= L1_DATA_B_START
+			    && addr + sizeof(data) <= L1_DATA_B_START + L1_DATA_B_LENGTH) {
+				memcpy((void *)(addr), &data, sizeof(data));
 				copied = sizeof(data);
-			} else
-#endif
-			if (addr + add >= FIXED_CODE_START
-			    && addr + add + sizeof(data) <= FIXED_CODE_END) {
-				memcpy((void *)(addr + add), &data, sizeof(data));
+
+			} else if (addr >= FIXED_CODE_START
+			    && addr + sizeof(data) <= FIXED_CODE_END) {
+				memcpy((void *)(addr), &data, sizeof(data));
 				copied = sizeof(data);
+
 			} else
-				copied = access_process_vm(child, addr + add, &data,
+				copied = access_process_vm(child, addr, &data,
 							   sizeof(data), 1);
+
 			pr_debug("ptrace: copied size %d\n", copied);
 			if (copied != sizeof(data))
 				break;
@@ -351,29 +350,22 @@
 		break;
 
 	case PTRACE_SYSCALL:	/* continue and stop at next (return from) syscall */
-	case PTRACE_CONT:
-		{		/* restart after signal. */
-			long tmp;
+	case PTRACE_CONT:	/* restart after signal. */
+		pr_debug("ptrace: syscall/cont\n");
 
-			pr_debug("ptrace_cont\n");
-
-			ret = -EIO;
-			if (!valid_signal(data))
-				break;
-			if (request == PTRACE_SYSCALL)
-				set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
-			else
-				clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
-
-			child->exit_code = data;
-			/* make sure the single step bit is not set. */
-			tmp = get_reg(child, PT_SYSCFG) & ~(TRACE_BITS);
-			put_reg(child, PT_SYSCFG, tmp);
-			pr_debug("before wake_up_process\n");
-			wake_up_process(child);
-			ret = 0;
+		ret = -EIO;
+		if (!valid_signal(data))
 			break;
-		}
+		if (request == PTRACE_SYSCALL)
+			set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
+		else
+			clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
+		child->exit_code = data;
+		ptrace_disable(child);
+		pr_debug("ptrace: before wake_up_process\n");
+		wake_up_process(child);
+		ret = 0;
+		break;
 
 	/*
 	 * make the child exit.  Best I can do is send it a sigkill.
@@ -381,55 +373,37 @@
 	 * exit.
 	 */
 	case PTRACE_KILL:
-		{
-			long tmp;
-			ret = 0;
-			if (child->exit_state == EXIT_ZOMBIE)	/* already dead */
-				break;
-			child->exit_code = SIGKILL;
-			/* make sure the single step bit is not set. */
-			tmp = get_reg(child, PT_SYSCFG) & ~(TRACE_BITS);
-			put_reg(child, PT_SYSCFG, tmp);
-			wake_up_process(child);
+		ret = 0;
+		if (child->exit_state == EXIT_ZOMBIE)	/* already dead */
 			break;
-		}
+		child->exit_code = SIGKILL;
+		ptrace_disable(child);
+		wake_up_process(child);
+		break;
 
-	case PTRACE_SINGLESTEP:
-		{		/* set the trap flag. */
-			long tmp;
-
-			pr_debug("single step\n");
-			ret = -EIO;
-			if (!valid_signal(data))
-				break;
-			clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
-
-			tmp = get_reg(child, PT_SYSCFG) | (TRACE_BITS);
-			put_reg(child, PT_SYSCFG, tmp);
-
-			child->exit_code = data;
-			/* give it a chance to run. */
-			wake_up_process(child);
-			ret = 0;
+	case PTRACE_SINGLESTEP:	/* set the trap flag. */
+		pr_debug("ptrace: single step\n");
+		ret = -EIO;
+		if (!valid_signal(data))
 			break;
-		}
+		clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
+		ptrace_enable(child);
+		child->exit_code = data;
+		wake_up_process(child);
+		ret = 0;
+		break;
 
 	case PTRACE_GETREGS:
-		{
-
-			/* Get all gp regs from the child. */
-			ret = ptrace_getregs(child, datap);
-			break;
-		}
+		/* Get all gp regs from the child. */
+		ret = ptrace_getregs(child, datap);
+		break;
 
 	case PTRACE_SETREGS:
-		{
-			printk(KERN_NOTICE
-			       "ptrace: SETREGS: **** NOT IMPLEMENTED ***\n");
-			/* Set all gp regs in the child. */
-			ret = 0;
-			break;
-		}
+		printk(KERN_WARNING "ptrace: SETREGS: **** NOT IMPLEMENTED ***\n");
+		/* Set all gp regs in the child. */
+		ret = 0;
+		break;
+
 	default:
 		ret = ptrace_request(child, request, addr, data);
 		break;
@@ -440,7 +414,6 @@
 
 asmlinkage void syscall_trace(void)
 {
-
 	if (!test_thread_flag(TIF_SYSCALL_TRACE))
 		return;
 
diff --git a/arch/blackfin/kernel/reboot.c b/arch/blackfin/kernel/reboot.c
index 367e2dc..ae97ca4 100644
--- a/arch/blackfin/kernel/reboot.c
+++ b/arch/blackfin/kernel/reboot.c
@@ -10,6 +10,7 @@
 #include <asm/bfin-global.h>
 #include <asm/reboot.h>
 #include <asm/system.h>
+#include <asm/bfrom.h>
 
 /* A system soft reset makes external memory unusable so force
  * this function into L1.  We use the compiler ssync here rather
@@ -20,7 +21,7 @@
  * the core reset.
  */
 __attribute__((l1_text))
-void bfin_reset(void)
+static void bfin_reset(void)
 {
 	/* Wait for completion of "system" events such as cache line
 	 * line fills so that we avoid infinite stalls later on as
@@ -34,15 +35,15 @@
 		bfin_write_SWRST(0x7);
 
 		/* Due to the way reset is handled in the hardware, we need
-		 * to delay for 7 SCLKS.  The only reliable way to do this is
-		 * to calculate the CCLK/SCLK ratio and multiply 7.  For now,
+		 * to delay for 10 SCLKS.  The only reliable way to do this is
+		 * to calculate the CCLK/SCLK ratio and multiply 10.  For now,
 		 * we'll assume worse case which is a 1:15 ratio.
 		 */
 		asm(
 			"LSETUP (1f, 1f) LC0 = %0\n"
 			"1: nop;"
 			:
-			: "a" (15 * 7)
+			: "a" (15 * 10)
 			: "LC0", "LB0", "LT0"
 		);
 
@@ -74,7 +75,14 @@
 {
 	native_machine_restart(cmd);
 	local_irq_disable();
-	bfin_reset();
+	if (ANOMALY_05000353 || ANOMALY_05000386)
+		bfin_reset();
+	else
+		/* the bootrom checks to see how it was reset and will
+		 * automatically perform a software reset for us when
+		 * it starts executing boot
+		 */
+		asm("raise 1;");
 }
 
 __attribute__((weak))
diff --git a/arch/blackfin/kernel/setup.c b/arch/blackfin/kernel/setup.c
index 7a82d10..7f35d10 100644
--- a/arch/blackfin/kernel/setup.c
+++ b/arch/blackfin/kernel/setup.c
@@ -42,6 +42,7 @@
 EXPORT_SYMBOL(memory_end);
 EXPORT_SYMBOL(physical_mem_end);
 EXPORT_SYMBOL(_ramend);
+EXPORT_SYMBOL(reserved_mem_dcache_on);
 
 #ifdef CONFIG_MTD_UCLINUX
 unsigned long memory_mtd_end, memory_mtd_start, mtd_size;
@@ -52,7 +53,8 @@
 #endif
 
 char __initdata command_line[COMMAND_LINE_SIZE];
-unsigned int __initdata *__retx;
+void __initdata *init_retx, *init_saved_retx, *init_saved_seqstat,
+	*init_saved_icplb_fault_addr, *init_saved_dcplb_fault_addr;
 
 /* boot memmap, for parsing "memmap=" */
 #define BFIN_MEMMAP_MAX		128 /* number of entries in bfin_memmap */
@@ -77,10 +79,10 @@
 static struct bfin_memmap_entry *overlap_list[BFIN_MEMMAP_MAX] __initdata;
 static struct bfin_memmap_entry new_map[BFIN_MEMMAP_MAX] __initdata;
 
-void __init bf53x_cache_init(void)
+void __init bfin_cache_init(void)
 {
 #if defined(CONFIG_BFIN_DCACHE) || defined(CONFIG_BFIN_ICACHE)
-	generate_cpl_tables();
+	generate_cplb_tables();
 #endif
 
 #ifdef CONFIG_BFIN_ICACHE
@@ -100,7 +102,7 @@
 #endif
 }
 
-void __init bf53x_relocate_l1_mem(void)
+void __init bfin_relocate_l1_mem(void)
 {
 	unsigned long l1_code_length;
 	unsigned long l1_data_a_length;
@@ -410,7 +412,7 @@
  *  [_rambase, _ramstart]:		kernel image
  *  [memory_start, memory_end]:		dynamic memory managed by kernel
  *  [memory_end, _ramend]:		reserved memory
- *  	[meory_mtd_start(memory_end),
+ *  	[memory_mtd_start(memory_end),
  *  		memory_mtd_start + mtd_size]:	rootfs (if any)
  *	[_ramend - DMA_UNCACHED_REGION,
  *		_ramend]:			uncached DMA region
@@ -782,16 +784,25 @@
 
 	_bfin_swrst = bfin_read_SWRST();
 
-	/* If we double fault, reset the system - otherwise we hang forever */
-	bfin_write_SWRST(DOUBLE_FAULT);
+#ifdef CONFIG_DEBUG_DOUBLEFAULT_PRINT
+	bfin_write_SWRST(_bfin_swrst & ~DOUBLE_FAULT);
+#endif
+#ifdef CONFIG_DEBUG_DOUBLEFAULT_RESET
+	bfin_write_SWRST(_bfin_swrst | DOUBLE_FAULT);
+#endif
 
-	if (_bfin_swrst & RESET_DOUBLE)
-		/*
-		 * don't decode the address, since you don't know if this
-		 * kernel's symbol map is the same as the crashing kernel
-		 */
-		printk(KERN_INFO "Recovering from Double Fault event at %pF\n", __retx);
-	else if (_bfin_swrst & RESET_WDOG)
+	if (_bfin_swrst & RESET_DOUBLE) {
+		printk(KERN_EMERG "Recovering from DOUBLE FAULT event\n");
+#ifdef CONFIG_DEBUG_DOUBLEFAULT
+		/* We assume the crashing kernel, and the current symbol table match */
+		printk(KERN_EMERG " While handling exception (EXCAUSE = 0x%x) at %pF\n",
+			(int)init_saved_seqstat & SEQSTAT_EXCAUSE, init_saved_retx);
+		printk(KERN_NOTICE "   DCPLB_FAULT_ADDR: %pF\n", init_saved_dcplb_fault_addr);
+		printk(KERN_NOTICE "   ICPLB_FAULT_ADDR: %pF\n", init_saved_icplb_fault_addr);
+#endif
+		printk(KERN_NOTICE " The instruction at %pF caused a double exception\n",
+			init_retx);
+	} else if (_bfin_swrst & RESET_WDOG)
 		printk(KERN_INFO "Recovering from Watchdog event\n");
 	else if (_bfin_swrst & RESET_SOFTWARE)
 		printk(KERN_NOTICE "Reset caused by Software reset\n");
@@ -803,17 +814,24 @@
 		printk(KERN_INFO "Compiled for ADSP-%s Rev none\n", CPU);
 	else
 		printk(KERN_INFO "Compiled for ADSP-%s Rev 0.%d\n", CPU, bfin_compiled_revid());
-	if (bfin_revid() != bfin_compiled_revid()) {
-		if (bfin_compiled_revid() == -1)
-			printk(KERN_ERR "Warning: Compiled for Rev none, but running on Rev %d\n",
-			       bfin_revid());
-		else if (bfin_compiled_revid() != 0xffff)
-			printk(KERN_ERR "Warning: Compiled for Rev %d, but running on Rev %d\n",
-			       bfin_compiled_revid(), bfin_revid());
+
+	if (unlikely(CPUID != bfin_cpuid()))
+		printk(KERN_ERR "ERROR: Not running on ADSP-%s: unknown CPUID 0x%04x Rev 0.%d\n",
+			CPU, bfin_cpuid(), bfin_revid());
+	else {
+		if (bfin_revid() != bfin_compiled_revid()) {
+			if (bfin_compiled_revid() == -1)
+				printk(KERN_ERR "Warning: Compiled for Rev none, but running on Rev %d\n",
+				       bfin_revid());
+			else if (bfin_compiled_revid() != 0xffff)
+				printk(KERN_ERR "Warning: Compiled for Rev %d, but running on Rev %d\n",
+				       bfin_compiled_revid(), bfin_revid());
+		}
+		if (bfin_revid() <= CONFIG_BF_REV_MIN || bfin_revid() > CONFIG_BF_REV_MAX)
+			printk(KERN_ERR "Warning: Unsupported Chip Revision ADSP-%s Rev 0.%d detected\n",
+			       CPU, bfin_revid());
 	}
-	if (bfin_revid() < SUPPORTED_REVID)
-		printk(KERN_ERR "Warning: Unsupported Chip Revision ADSP-%s Rev 0.%d detected\n",
-		       CPU, bfin_revid());
+
 	printk(KERN_INFO "Blackfin Linux support by http://blackfin.uclinux.org/\n");
 
 	printk(KERN_INFO "Processor Speed: %lu MHz core clock and %lu MHz System Clock\n",
@@ -850,7 +868,7 @@
 		!= SAFE_USER_INSTRUCTION - FIXED_CODE_START);
 
 	init_exception_vectors();
-	bf53x_cache_init();
+	bfin_cache_init();
 }
 
 static int __init topology_init(void)
@@ -986,13 +1004,18 @@
 	}
 
 	seq_printf(m, "processor\t: %d\n"
-		"vendor_id\t: %s\n"
-		"cpu family\t: 0x%x\n"
-		"model name\t: ADSP-%s %lu(MHz CCLK) %lu(MHz SCLK) (%s)\n"
+		"vendor_id\t: %s\n",
+		*(unsigned int *)v,
+		vendor);
+
+	if (CPUID == bfin_cpuid())
+		seq_printf(m, "cpu family\t: 0x%04x\n", CPUID);
+	else
+		seq_printf(m, "cpu family\t: Compiled for:0x%04x, running on:0x%04x\n",
+			CPUID, bfin_cpuid());
+
+	seq_printf(m, "model name\t: ADSP-%s %lu(MHz CCLK) %lu(MHz SCLK) (%s)\n"
 		"stepping\t: %d\n",
-		0,
-		vendor,
-		(bfin_read_CHIPID() & CHIPID_FAMILY),
 		cpu, cclk/1000000, sclk/1000000,
 #ifdef CONFIG_MPU
 		"mpu on",
@@ -1038,7 +1061,7 @@
 	if ((bfin_read_DMEM_CONTROL() & (ENDCPLB | DMC_ENABLE)) != (ENDCPLB | DMC_ENABLE))
 		dcache_size = 0;
 
-	if ((bfin_read_IMEM_CONTROL() & (IMC | ENICPLB)) == (IMC | ENICPLB))
+	if ((bfin_read_IMEM_CONTROL() & (IMC | ENICPLB)) != (IMC | ENICPLB))
 		icache_size = 0;
 
 	seq_printf(m, "cache size\t: %d KB(L1 icache) "
@@ -1127,12 +1150,18 @@
 
 static void *c_start(struct seq_file *m, loff_t *pos)
 {
-	return *pos < NR_CPUS ? ((void *)0x12345678) : NULL;
+	if (*pos == 0)
+		*pos = first_cpu(cpu_online_map);
+	if (*pos >= num_online_cpus())
+		return NULL;
+
+	return pos;
 }
 
 static void *c_next(struct seq_file *m, void *v, loff_t *pos)
 {
-	++*pos;
+	*pos = next_cpu(*pos, cpu_online_map);
+
 	return c_start(m, pos);
 }
 
diff --git a/arch/blackfin/kernel/traps.c b/arch/blackfin/kernel/traps.c
index 9a9d508..1aa2c78 100644
--- a/arch/blackfin/kernel/traps.c
+++ b/arch/blackfin/kernel/traps.c
@@ -34,20 +34,19 @@
 #include <linux/fs.h>
 #include <asm/traps.h>
 #include <asm/cacheflush.h>
+#include <asm/cplb.h>
 #include <asm/blackfin.h>
 #include <asm/irq_handler.h>
 #include <linux/irq.h>
 #include <asm/trace.h>
 #include <asm/fixed_code.h>
-#include <asm/dma.h>
 
 #ifdef CONFIG_KGDB
-# include <linux/debugger.h>
 # include <linux/kgdb.h>
 
 # define CHK_DEBUGGER_TRAP() \
 	do { \
-		CHK_DEBUGGER(trapnr, sig, info.si_code, fp, ); \
+		kgdb_handle_exception(trapnr, sig, info.si_code, fp); \
 	} while (0)
 # define CHK_DEBUGGER_TRAP_MAYBE() \
 	do { \
@@ -59,6 +58,15 @@
 # define CHK_DEBUGGER_TRAP_MAYBE() do { } while (0)
 #endif
 
+
+#ifdef CONFIG_VERBOSE_DEBUG
+#define verbose_printk(fmt, arg...) \
+	printk(fmt, ##arg)
+#else
+#define verbose_printk(fmt, arg...) \
+	({ if (0) printk(fmt, ##arg); 0; })
+#endif
+
 /* Initiate the event table handler */
 void __init trap_init(void)
 {
@@ -67,10 +75,19 @@
 	CSYNC();
 }
 
-unsigned long saved_icplb_fault_addr, saved_dcplb_fault_addr;
+/*
+ * Used to save the RETX, SEQSTAT, I/D CPLB FAULT ADDR
+ * values across the transition from exception to IRQ5.
+ * We put these in L1, so they are going to be in a valid
+ * location during exception context
+ */
+__attribute__((l1_data))
+unsigned long saved_retx, saved_seqstat,
+	saved_icplb_fault_addr, saved_dcplb_fault_addr;
 
 static void decode_address(char *buf, unsigned long address)
 {
+#ifdef CONFIG_DEBUG_VERBOSE
 	struct vm_list_struct *vml;
 	struct task_struct *p;
 	struct mm_struct *mm;
@@ -178,16 +195,39 @@
 
 done:
 	write_unlock_irqrestore(&tasklist_lock, flags);
+#else
+	sprintf(buf, " ");
+#endif
 }
 
 asmlinkage void double_fault_c(struct pt_regs *fp)
 {
 	console_verbose();
 	oops_in_progress = 1;
+#ifdef CONFIG_DEBUG_VERBOSE
 	printk(KERN_EMERG "\n" KERN_EMERG "Double Fault\n");
-	dump_bfin_process(fp);
-	dump_bfin_mem(fp);
-	show_regs(fp);
+#ifdef CONFIG_DEBUG_DOUBLEFAULT_PRINT
+	if (((long)fp->seqstat &  SEQSTAT_EXCAUSE) == VEC_UNCOV) {
+		char buf[150];
+		decode_address(buf, saved_retx);
+		printk(KERN_EMERG "While handling exception (EXCAUSE = 0x%x) at %s:\n",
+			(int)saved_seqstat & SEQSTAT_EXCAUSE, buf);
+		decode_address(buf, saved_dcplb_fault_addr);
+		printk(KERN_NOTICE "   DCPLB_FAULT_ADDR: %s\n", buf);
+		decode_address(buf, saved_icplb_fault_addr);
+		printk(KERN_NOTICE "   ICPLB_FAULT_ADDR: %s\n", buf);
+
+		decode_address(buf, fp->retx);
+		printk(KERN_NOTICE "The instruction at %s caused a double exception\n",
+			buf);
+	} else
+#endif
+	{
+		dump_bfin_process(fp);
+		dump_bfin_mem(fp);
+		show_regs(fp);
+	}
+#endif
 	panic("Double Fault - unrecoverable event\n");
 
 }
@@ -259,34 +299,42 @@
 			return;
 		else
 			break;
-#ifdef CONFIG_KGDB
-	case VEC_EXCPT02 :		 /* gdb connection */
-		info.si_code = TRAP_ILLTRAP;
-		sig = SIGTRAP;
-		CHK_DEBUGGER_TRAP();
-		return;
-#else
-	/* 0x02 - User Defined, Caught by default */
-#endif
 	/* 0x03 - User Defined, userspace stack overflow */
 	case VEC_EXCPT03:
 		info.si_code = SEGV_STACKFLOW;
 		sig = SIGSEGV;
-		printk(KERN_NOTICE EXC_0x03(KERN_NOTICE));
-		CHK_DEBUGGER_TRAP();
+		verbose_printk(KERN_NOTICE EXC_0x03(KERN_NOTICE));
+		CHK_DEBUGGER_TRAP_MAYBE();
 		break;
-	/* 0x04 - User Defined, Caught by default */
-	/* 0x05 - User Defined, Caught by default */
-	/* 0x06 - User Defined, Caught by default */
-	/* 0x07 - User Defined, Caught by default */
-	/* 0x08 - User Defined, Caught by default */
-	/* 0x09 - User Defined, Caught by default */
-	/* 0x0A - User Defined, Caught by default */
-	/* 0x0B - User Defined, Caught by default */
-	/* 0x0C - User Defined, Caught by default */
-	/* 0x0D - User Defined, Caught by default */
-	/* 0x0E - User Defined, Caught by default */
-	/* 0x0F - User Defined, Caught by default */
+	/* 0x02 - KGDB initial connection and break signal trap */
+	case VEC_EXCPT02:
+#ifdef CONFIG_KGDB
+		info.si_code = TRAP_ILLTRAP;
+		sig = SIGTRAP;
+		CHK_DEBUGGER_TRAP();
+		return;
+#endif
+	/* 0x04 - User Defined */
+	/* 0x05 - User Defined */
+	/* 0x06 - User Defined */
+	/* 0x07 - User Defined */
+	/* 0x08 - User Defined */
+	/* 0x09 - User Defined */
+	/* 0x0A - User Defined */
+	/* 0x0B - User Defined */
+	/* 0x0C - User Defined */
+	/* 0x0D - User Defined */
+	/* 0x0E - User Defined */
+	/* 0x0F - User Defined */
+	/* If we got here, it is most likely that someone was trying to use a
+	 * custom exception handler, and it is not actually installed properly
+	 */
+	case VEC_EXCPT04 ... VEC_EXCPT15:
+		info.si_code = ILL_ILLPARAOP;
+		sig = SIGILL;
+		verbose_printk(KERN_NOTICE EXC_0x04(KERN_NOTICE));
+		CHK_DEBUGGER_TRAP_MAYBE();
+		break;
 	/* 0x10 HW Single step, handled here */
 	case VEC_STEP:
 		info.si_code = TRAP_STEP;
@@ -301,8 +349,8 @@
 	case VEC_OVFLOW:
 		info.si_code = TRAP_TRACEFLOW;
 		sig = SIGTRAP;
-		printk(KERN_NOTICE EXC_0x11(KERN_NOTICE));
-		CHK_DEBUGGER_TRAP();
+		verbose_printk(KERN_NOTICE EXC_0x11(KERN_NOTICE));
+		CHK_DEBUGGER_TRAP_MAYBE();
 		break;
 	/* 0x12 - Reserved, Caught by default */
 	/* 0x13 - Reserved, Caught by default */
@@ -323,44 +371,43 @@
 	case VEC_UNDEF_I:
 		info.si_code = ILL_ILLOPC;
 		sig = SIGILL;
-		printk(KERN_NOTICE EXC_0x21(KERN_NOTICE));
-		CHK_DEBUGGER_TRAP();
+		verbose_printk(KERN_NOTICE EXC_0x21(KERN_NOTICE));
+		CHK_DEBUGGER_TRAP_MAYBE();
 		break;
 	/* 0x22 - Illegal Instruction Combination, handled here */
 	case VEC_ILGAL_I:
 		info.si_code = ILL_ILLPARAOP;
 		sig = SIGILL;
-		printk(KERN_NOTICE EXC_0x22(KERN_NOTICE));
-		CHK_DEBUGGER_TRAP();
+		verbose_printk(KERN_NOTICE EXC_0x22(KERN_NOTICE));
+		CHK_DEBUGGER_TRAP_MAYBE();
 		break;
 	/* 0x23 - Data CPLB protection violation, handled here */
 	case VEC_CPLB_VL:
 		info.si_code = ILL_CPLB_VI;
 		sig = SIGBUS;
-		printk(KERN_NOTICE EXC_0x23(KERN_NOTICE));
-		CHK_DEBUGGER_TRAP();
+		verbose_printk(KERN_NOTICE EXC_0x23(KERN_NOTICE));
+		CHK_DEBUGGER_TRAP_MAYBE();
 		break;
 	/* 0x24 - Data access misaligned, handled here */
 	case VEC_MISALI_D:
 		info.si_code = BUS_ADRALN;
 		sig = SIGBUS;
-		printk(KERN_NOTICE EXC_0x24(KERN_NOTICE));
-		CHK_DEBUGGER_TRAP();
+		verbose_printk(KERN_NOTICE EXC_0x24(KERN_NOTICE));
+		CHK_DEBUGGER_TRAP_MAYBE();
 		break;
 	/* 0x25 - Unrecoverable Event, handled here */
 	case VEC_UNCOV:
 		info.si_code = ILL_ILLEXCPT;
 		sig = SIGILL;
-		printk(KERN_NOTICE EXC_0x25(KERN_NOTICE));
-		CHK_DEBUGGER_TRAP();
+		verbose_printk(KERN_NOTICE EXC_0x25(KERN_NOTICE));
+		CHK_DEBUGGER_TRAP_MAYBE();
 		break;
 	/* 0x26 - Data CPLB Miss, normal case is handled in _cplb_hdr,
 		error case is handled here */
 	case VEC_CPLB_M:
 		info.si_code = BUS_ADRALN;
 		sig = SIGBUS;
-		printk(KERN_NOTICE EXC_0x26(KERN_NOTICE));
-		CHK_DEBUGGER_TRAP();
+		verbose_printk(KERN_NOTICE EXC_0x26(KERN_NOTICE));
 		break;
 	/* 0x27 - Data CPLB Multiple Hits - Linux Trap Zero, handled here */
 	case VEC_CPLB_MHIT:
@@ -368,11 +415,11 @@
 		sig = SIGSEGV;
 #ifdef CONFIG_DEBUG_HUNT_FOR_ZERO
 		if (saved_dcplb_fault_addr < FIXED_CODE_START)
-			printk(KERN_NOTICE "NULL pointer access\n");
+			verbose_printk(KERN_NOTICE "NULL pointer access\n");
 		else
 #endif
-			printk(KERN_NOTICE EXC_0x27(KERN_NOTICE));
-		CHK_DEBUGGER_TRAP();
+			verbose_printk(KERN_NOTICE EXC_0x27(KERN_NOTICE));
+		CHK_DEBUGGER_TRAP_MAYBE();
 		break;
 	/* 0x28 - Emulation Watchpoint, handled here */
 	case VEC_WATCH:
@@ -390,8 +437,8 @@
 	case VEC_ISTRU_VL:      /* ADSP-BF535 only (MH) */
 		info.si_code = BUS_OPFETCH;
 		sig = SIGBUS;
-		printk(KERN_NOTICE "BF535: VEC_ISTRU_VL\n");
-		CHK_DEBUGGER_TRAP();
+		verbose_printk(KERN_NOTICE "BF535: VEC_ISTRU_VL\n");
+		CHK_DEBUGGER_TRAP_MAYBE();
 		break;
 #else
 	/* 0x29 - Reserved, Caught by default */
@@ -400,22 +447,21 @@
 	case VEC_MISALI_I:
 		info.si_code = BUS_ADRALN;
 		sig = SIGBUS;
-		printk(KERN_NOTICE EXC_0x2A(KERN_NOTICE));
-		CHK_DEBUGGER_TRAP();
+		verbose_printk(KERN_NOTICE EXC_0x2A(KERN_NOTICE));
+		CHK_DEBUGGER_TRAP_MAYBE();
 		break;
 	/* 0x2B - Instruction CPLB protection violation, handled here */
 	case VEC_CPLB_I_VL:
 		info.si_code = ILL_CPLB_VI;
 		sig = SIGBUS;
-		printk(KERN_NOTICE EXC_0x2B(KERN_NOTICE));
-		CHK_DEBUGGER_TRAP();
+		verbose_printk(KERN_NOTICE EXC_0x2B(KERN_NOTICE));
+		CHK_DEBUGGER_TRAP_MAYBE();
 		break;
 	/* 0x2C - Instruction CPLB miss, handled in _cplb_hdr */
 	case VEC_CPLB_I_M:
 		info.si_code = ILL_CPLB_MISS;
 		sig = SIGBUS;
-		printk(KERN_NOTICE EXC_0x2C(KERN_NOTICE));
-		CHK_DEBUGGER_TRAP();
+		verbose_printk(KERN_NOTICE EXC_0x2C(KERN_NOTICE));
 		break;
 	/* 0x2D - Instruction CPLB Multiple Hits, handled here */
 	case VEC_CPLB_I_MHIT:
@@ -423,18 +469,18 @@
 		sig = SIGSEGV;
 #ifdef CONFIG_DEBUG_HUNT_FOR_ZERO
 		if (saved_icplb_fault_addr < FIXED_CODE_START)
-			printk(KERN_NOTICE "Jump to NULL address\n");
+			verbose_printk(KERN_NOTICE "Jump to NULL address\n");
 		else
 #endif
-			printk(KERN_NOTICE EXC_0x2D(KERN_NOTICE));
-		CHK_DEBUGGER_TRAP();
+			verbose_printk(KERN_NOTICE EXC_0x2D(KERN_NOTICE));
+		CHK_DEBUGGER_TRAP_MAYBE();
 		break;
 	/* 0x2E - Illegal use of Supervisor Resource, handled here */
 	case VEC_ILL_RES:
 		info.si_code = ILL_PRVOPC;
 		sig = SIGILL;
-		printk(KERN_NOTICE EXC_0x2E(KERN_NOTICE));
-		CHK_DEBUGGER_TRAP();
+		verbose_printk(KERN_NOTICE EXC_0x2E(KERN_NOTICE));
+		CHK_DEBUGGER_TRAP_MAYBE();
 		break;
 	/* 0x2F - Reserved, Caught by default */
 	/* 0x30 - Reserved, Caught by default */
@@ -461,17 +507,17 @@
 		case (SEQSTAT_HWERRCAUSE_SYSTEM_MMR):
 			info.si_code = BUS_ADRALN;
 			sig = SIGBUS;
-			printk(KERN_NOTICE HWC_x2(KERN_NOTICE));
+			verbose_printk(KERN_NOTICE HWC_x2(KERN_NOTICE));
 			break;
 		/* External Memory Addressing Error */
 		case (SEQSTAT_HWERRCAUSE_EXTERN_ADDR):
 			info.si_code = BUS_ADRERR;
 			sig = SIGBUS;
-			printk(KERN_NOTICE HWC_x3(KERN_NOTICE));
+			verbose_printk(KERN_NOTICE HWC_x3(KERN_NOTICE));
 			break;
 		/* Performance Monitor Overflow */
 		case (SEQSTAT_HWERRCAUSE_PERF_FLOW):
-			printk(KERN_NOTICE HWC_x12(KERN_NOTICE));
+			verbose_printk(KERN_NOTICE HWC_x12(KERN_NOTICE));
 			break;
 		/* RAISE 5 instruction */
 		case (SEQSTAT_HWERRCAUSE_RAISE_5):
@@ -481,21 +527,25 @@
 			printk(KERN_NOTICE HWC_default(KERN_NOTICE));
 			break;
 		}
-		CHK_DEBUGGER_TRAP();
+		CHK_DEBUGGER_TRAP_MAYBE();
 		break;
+	/*
+	 * We should be handling all known exception types above,
+	 * if we get here we hit a reserved one, so panic
+	 */
 	default:
-		info.si_code = TRAP_ILLTRAP;
-		sig = SIGTRAP;
-		printk(KERN_EMERG "Caught Unhandled Exception, code = %08lx\n",
+		oops_in_progress = 1;
+		info.si_code = ILL_ILLPARAOP;
+		sig = SIGILL;
+		verbose_printk(KERN_EMERG "Caught Unhandled Exception, code = %08lx\n",
 			(fp->seqstat & SEQSTAT_EXCAUSE));
-		CHK_DEBUGGER_TRAP();
+		CHK_DEBUGGER_TRAP_MAYBE();
 		break;
 	}
 
 	BUG_ON(sig == 0);
 
 	if (sig != SIGTRAP) {
-		unsigned long *stack;
 		dump_bfin_process(fp);
 		dump_bfin_mem(fp);
 		show_regs(fp);
@@ -503,7 +553,7 @@
 		/* Print out the trace buffer if it makes sense */
 #ifndef CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE
 		if (trapnr == VEC_CPLB_I_M || trapnr == VEC_CPLB_M)
-			printk(KERN_NOTICE "No trace since you do not have "
+			verbose_printk(KERN_NOTICE "No trace since you do not have "
 				"CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE enabled\n"
 				KERN_NOTICE "\n");
 		else
@@ -512,20 +562,22 @@
 
 		if (oops_in_progress) {
 			/* Dump the current kernel stack */
-			printk(KERN_NOTICE "\n" KERN_NOTICE "Kernel Stack\n");
+			verbose_printk(KERN_NOTICE "\n" KERN_NOTICE "Kernel Stack\n");
 			show_stack(current, NULL);
-
 			print_modules();
 #ifndef CONFIG_ACCESS_CHECK
-			printk(KERN_EMERG "Please turn on "
+			verbose_printk(KERN_EMERG "Please turn on "
 			       "CONFIG_ACCESS_CHECK\n");
 #endif
 			panic("Kernel exception");
 		} else {
+#ifdef CONFIG_VERBOSE_DEBUG
+			unsigned long *stack;
 			/* Dump the user space stack */
 			stack = (unsigned long *)rdusp();
-			printk(KERN_NOTICE "Userspace Stack\n");
+			verbose_printk(KERN_NOTICE "Userspace Stack\n");
 			show_stack(NULL, stack);
+#endif
 		}
 	}
 
@@ -546,7 +598,7 @@
  * Similar to get_user, do some address checking, then dereference
  * Return true on sucess, false on bad address
  */
-bool get_instruction(unsigned short *val, unsigned short *address)
+static bool get_instruction(unsigned short *val, unsigned short *address)
 {
 
 	unsigned long addr;
@@ -592,7 +644,7 @@
 
 #if L1_CODE_LENGTH != 0
 	if (addr >= L1_CODE_START && (addr + 2) <= (L1_CODE_START + L1_CODE_LENGTH)) {
-		dma_memcpy(val, address, 2);
+		isram_memcpy(val, address, 2);
 		return true;
 	}
 #endif
@@ -607,45 +659,48 @@
  * These are the normal instructions which cause change of flow, which
  * would be at the source of the trace buffer
  */
-void decode_instruction(unsigned short *address)
+#ifdef CONFIG_DEBUG_VERBOSE
+static void decode_instruction(unsigned short *address)
 {
 	unsigned short opcode;
 
 	if (get_instruction(&opcode, address)) {
 		if (opcode == 0x0010)
-			printk("RTS");
+			verbose_printk("RTS");
 		else if (opcode == 0x0011)
-			printk("RTI");
+			verbose_printk("RTI");
 		else if (opcode == 0x0012)
-			printk("RTX");
+			verbose_printk("RTX");
 		else if (opcode >= 0x0050 && opcode <= 0x0057)
-			printk("JUMP (P%i)", opcode & 7);
+			verbose_printk("JUMP (P%i)", opcode & 7);
 		else if (opcode >= 0x0060 && opcode <= 0x0067)
-			printk("CALL (P%i)", opcode & 7);
+			verbose_printk("CALL (P%i)", opcode & 7);
 		else if (opcode >= 0x0070 && opcode <= 0x0077)
-			printk("CALL (PC+P%i)", opcode & 7);
+			verbose_printk("CALL (PC+P%i)", opcode & 7);
 		else if (opcode >= 0x0080 && opcode <= 0x0087)
-			printk("JUMP (PC+P%i)", opcode & 7);
+			verbose_printk("JUMP (PC+P%i)", opcode & 7);
 		else if ((opcode >= 0x1000 && opcode <= 0x13FF) || (opcode >= 0x1800 && opcode <= 0x1BFF))
-			printk("IF !CC JUMP");
+			verbose_printk("IF !CC JUMP");
 		else if ((opcode >= 0x1400 && opcode <= 0x17ff) || (opcode >= 0x1c00 && opcode <= 0x1fff))
-			printk("IF CC JUMP");
+			verbose_printk("IF CC JUMP");
 		else if (opcode >= 0x2000 && opcode <= 0x2fff)
-			printk("JUMP.S");
+			verbose_printk("JUMP.S");
 		else if (opcode >= 0xe080 && opcode <= 0xe0ff)
-			printk("LSETUP");
+			verbose_printk("LSETUP");
 		else if (opcode >= 0xe200 && opcode <= 0xe2ff)
-			printk("JUMP.L");
+			verbose_printk("JUMP.L");
 		else if (opcode >= 0xe300 && opcode <= 0xe3ff)
-			printk("CALL pcrel");
+			verbose_printk("CALL pcrel");
 		else
-			printk("0x%04x", opcode);
+			verbose_printk("0x%04x", opcode);
 	}
 
 }
+#endif
 
 void dump_bfin_trace_buffer(void)
 {
+#ifdef CONFIG_DEBUG_VERBOSE
 #ifdef CONFIG_DEBUG_BFIN_HWTRACE_ON
 	int tflags, i = 0;
 	char buf[150];
@@ -701,6 +756,7 @@
 
 	trace_buffer_restore(tflags);
 #endif
+#endif
 }
 EXPORT_SYMBOL(dump_bfin_trace_buffer);
 
@@ -708,7 +764,7 @@
  * Checks to see if the address pointed to is either a
  * 16-bit CALL instruction, or a 32-bit CALL instruction
  */
-bool is_bfin_call(unsigned short *addr)
+static bool is_bfin_call(unsigned short *addr)
 {
 	unsigned short opcode = 0, *ins_addr;
 	ins_addr = (unsigned short *)addr;
@@ -730,8 +786,10 @@
 	return false;
 
 }
+
 void show_stack(struct task_struct *task, unsigned long *stack)
 {
+#ifdef CONFIG_PRINTK
 	unsigned int *addr, *endstack, *fp = 0, *frame;
 	unsigned short *ins_addr;
 	char buf[150];
@@ -756,8 +814,10 @@
 	} else
 		endstack = (unsigned int *)PAGE_ALIGN((unsigned int)stack);
 
+	printk(KERN_NOTICE "Stack info:\n");
 	decode_address(buf, (unsigned int)stack);
-	printk(KERN_NOTICE "Stack info:\n" KERN_NOTICE " SP: [0x%p] %s\n", stack, buf);
+	printk(KERN_NOTICE " SP: [0x%p] %s\n", stack, buf);
+
 	addr = (unsigned int *)((unsigned int)stack & ~0x3F);
 
 	/* First thing is to look for a frame pointer */
@@ -848,7 +908,7 @@
 		if (!j)
 			printk("\n");
 	}
-
+#endif
 }
 
 void dump_stack(void)
@@ -866,38 +926,39 @@
 
 void dump_bfin_process(struct pt_regs *fp)
 {
+#ifdef CONFIG_DEBUG_VERBOSE
 	/* We should be able to look at fp->ipend, but we don't push it on the
 	 * stack all the time, so do this until we fix that */
 	unsigned int context = bfin_read_IPEND();
 
 	if (oops_in_progress)
-		printk(KERN_EMERG "Kernel OOPS in progress\n");
+		verbose_printk(KERN_EMERG "Kernel OOPS in progress\n");
 
 	if (context & 0x0020 && (fp->seqstat & SEQSTAT_EXCAUSE) == VEC_HWERR)
-		printk(KERN_NOTICE "HW Error context\n");
+		verbose_printk(KERN_NOTICE "HW Error context\n");
 	else if (context & 0x0020)
-		printk(KERN_NOTICE "Deferred Exception context\n");
+		verbose_printk(KERN_NOTICE "Deferred Exception context\n");
 	else if (context & 0x3FC0)
-		printk(KERN_NOTICE "Interrupt context\n");
+		verbose_printk(KERN_NOTICE "Interrupt context\n");
 	else if (context & 0x4000)
-		printk(KERN_NOTICE "Deferred Interrupt context\n");
+		verbose_printk(KERN_NOTICE "Deferred Interrupt context\n");
 	else if (context & 0x8000)
-		printk(KERN_NOTICE "Kernel process context\n");
+		verbose_printk(KERN_NOTICE "Kernel process context\n");
 
 	/* Because we are crashing, and pointers could be bad, we check things
 	 * pretty closely before we use them
 	 */
 	if ((unsigned long)current >= FIXED_CODE_START &&
 	    !((unsigned long)current & 0x3) && current->pid) {
-		printk(KERN_NOTICE "CURRENT PROCESS:\n");
+		verbose_printk(KERN_NOTICE "CURRENT PROCESS:\n");
 		if (current->comm >= (char *)FIXED_CODE_START)
-			printk(KERN_NOTICE "COMM=%s PID=%d\n",
+			verbose_printk(KERN_NOTICE "COMM=%s PID=%d\n",
 				current->comm, current->pid);
 		else
-			printk(KERN_NOTICE "COMM= invalid\n");
+			verbose_printk(KERN_NOTICE "COMM= invalid\n");
 
 		if (!((unsigned long)current->mm & 0x3) && (unsigned long)current->mm >= FIXED_CODE_START)
-			printk(KERN_NOTICE  "TEXT = 0x%p-0x%p        DATA = 0x%p-0x%p\n"
+			verbose_printk(KERN_NOTICE  "TEXT = 0x%p-0x%p        DATA = 0x%p-0x%p\n"
 				KERN_NOTICE " BSS = 0x%p-0x%p  USER-STACK = 0x%p\n"
 				KERN_NOTICE "\n",
 				(void *)current->mm->start_code,
@@ -908,38 +969,40 @@
 				(void *)current->mm->brk,
 				(void *)current->mm->start_stack);
 		else
-			printk(KERN_NOTICE "invalid mm\n");
+			verbose_printk(KERN_NOTICE "invalid mm\n");
 	} else
-		printk(KERN_NOTICE "\n" KERN_NOTICE
+		verbose_printk(KERN_NOTICE "\n" KERN_NOTICE
 		     "No Valid process in current context\n");
+#endif
 }
 
 void dump_bfin_mem(struct pt_regs *fp)
 {
+#ifdef CONFIG_DEBUG_VERBOSE
 	unsigned short *addr, *erraddr, val = 0, err = 0;
 	char sti = 0, buf[6];
 
 	erraddr = (void *)fp->pc;
 
-	printk(KERN_NOTICE "return address: [0x%p]; contents of:", erraddr);
+	verbose_printk(KERN_NOTICE "return address: [0x%p]; contents of:", erraddr);
 
 	for (addr = (unsigned short *)((unsigned long)erraddr & ~0xF) - 0x10;
 	     addr < (unsigned short *)((unsigned long)erraddr & ~0xF) + 0x10;
 	     addr++) {
 		if (!((unsigned long)addr & 0xF))
-			printk("\n" KERN_NOTICE "0x%p: ", addr);
+			verbose_printk("\n" KERN_NOTICE "0x%p: ", addr);
 
-		if (get_instruction(&val, addr)) {
+		if (!get_instruction(&val, addr)) {
 				val = 0;
 				sprintf(buf, "????");
 		} else
 			sprintf(buf, "%04x", val);
 
 		if (addr == erraddr) {
-			printk("[%s]", buf);
+			verbose_printk("[%s]", buf);
 			err = val;
 		} else
-			printk(" %s ", buf);
+			verbose_printk(" %s ", buf);
 
 		/* Do any previous instructions turn on interrupts? */
 		if (addr <= erraddr &&				/* in the past */
@@ -948,14 +1011,14 @@
 			sti = 1;
 	}
 
-	printk("\n");
+	verbose_printk("\n");
 
 	/* Hardware error interrupts can be deferred */
 	if (unlikely(sti && (fp->seqstat & SEQSTAT_EXCAUSE) == VEC_HWERR &&
 	    oops_in_progress)){
-		printk(KERN_NOTICE "Looks like this was a deferred error - sorry\n");
+		verbose_printk(KERN_NOTICE "Looks like this was a deferred error - sorry\n");
 #ifndef CONFIG_DEBUG_HWERR
-		printk(KERN_NOTICE "The remaining message may be meaningless\n"
+		verbose_printk(KERN_NOTICE "The remaining message may be meaningless\n"
 			KERN_NOTICE "You should enable CONFIG_DEBUG_HWERR to get a"
 			 " better idea where it came from\n");
 #else
@@ -969,34 +1032,47 @@
 			/* And the last RETI points to the current userspace context */
 			if ((fp + 1)->pc >= current->mm->start_code &&
 			    (fp + 1)->pc <= current->mm->end_code) {
-				printk(KERN_NOTICE "It might be better to look around here : \n");
-				printk(KERN_NOTICE "-------------------------------------------\n");
+				verbose_printk(KERN_NOTICE "It might be better to look around here : \n");
+				verbose_printk(KERN_NOTICE "-------------------------------------------\n");
 				show_regs(fp + 1);
-				printk(KERN_NOTICE "-------------------------------------------\n");
+				verbose_printk(KERN_NOTICE "-------------------------------------------\n");
 			}
 		}
 #endif
 	}
+#endif
 }
 
 void show_regs(struct pt_regs *fp)
 {
+#ifdef CONFIG_DEBUG_VERBOSE
 	char buf [150];
 	struct irqaction *action;
 	unsigned int i;
 	unsigned long flags;
 
-	printk(KERN_NOTICE "\n" KERN_NOTICE "SEQUENCER STATUS:\t\t%s\n", print_tainted());
-	printk(KERN_NOTICE " SEQSTAT: %08lx  IPEND: %04lx  SYSCFG: %04lx\n",
+	verbose_printk(KERN_NOTICE "\n" KERN_NOTICE "SEQUENCER STATUS:\t\t%s\n", print_tainted());
+	verbose_printk(KERN_NOTICE " SEQSTAT: %08lx  IPEND: %04lx  SYSCFG: %04lx\n",
 		(long)fp->seqstat, fp->ipend, fp->syscfg);
-	printk(KERN_NOTICE "  HWERRCAUSE: 0x%lx\n",
-		(fp->seqstat & SEQSTAT_HWERRCAUSE) >> 14);
-	printk(KERN_NOTICE "  EXCAUSE   : 0x%lx\n",
+	if ((fp->seqstat & SEQSTAT_EXCAUSE) == VEC_HWERR) {
+		verbose_printk(KERN_NOTICE "  HWERRCAUSE: 0x%lx\n",
+			(fp->seqstat & SEQSTAT_HWERRCAUSE) >> 14);
+#ifdef EBIU_ERRMST
+		/* If the error was from the EBIU, print it out */
+		if (bfin_read_EBIU_ERRMST() & CORE_ERROR) {
+			verbose_printk(KERN_NOTICE "  EBIU Error Reason  : 0x%04x\n",
+				bfin_read_EBIU_ERRMST());
+			verbose_printk(KERN_NOTICE "  EBIU Error Address : 0x%08x\n",
+				bfin_read_EBIU_ERRADD());
+		}
+#endif
+	}
+	verbose_printk(KERN_NOTICE "  EXCAUSE   : 0x%lx\n",
 		fp->seqstat & SEQSTAT_EXCAUSE);
 	for (i = 6; i <= 15 ; i++) {
 		if (fp->ipend & (1 << i)) {
 			decode_address(buf, bfin_read32(EVT0 + 4*i));
-			printk(KERN_NOTICE "  physical IVG%i asserted : %s\n", i, buf);
+			verbose_printk(KERN_NOTICE "  physical IVG%i asserted : %s\n", i, buf);
 		}
 	}
 
@@ -1009,64 +1085,65 @@
 				goto unlock;
 
 			decode_address(buf, (unsigned int)action->handler);
-			printk(KERN_NOTICE "  logical irq %3d mapped  : %s", i, buf);
+			verbose_printk(KERN_NOTICE "  logical irq %3d mapped  : %s", i, buf);
 			for (action = action->next; action; action = action->next) {
 				decode_address(buf, (unsigned int)action->handler);
-				printk(", %s", buf);
+				verbose_printk(", %s", buf);
 			}
-			printk("\n");
+			verbose_printk("\n");
 unlock:
 			spin_unlock_irqrestore(&irq_desc[i].lock, flags);
 		}
 	}
 
 	decode_address(buf, fp->rete);
-	printk(KERN_NOTICE " RETE: %s\n", buf);
+	verbose_printk(KERN_NOTICE " RETE: %s\n", buf);
 	decode_address(buf, fp->retn);
-	printk(KERN_NOTICE " RETN: %s\n", buf);
+	verbose_printk(KERN_NOTICE " RETN: %s\n", buf);
 	decode_address(buf, fp->retx);
-	printk(KERN_NOTICE " RETX: %s\n", buf);
+	verbose_printk(KERN_NOTICE " RETX: %s\n", buf);
 	decode_address(buf, fp->rets);
-	printk(KERN_NOTICE " RETS: %s\n", buf);
+	verbose_printk(KERN_NOTICE " RETS: %s\n", buf);
 	decode_address(buf, fp->pc);
-	printk(KERN_NOTICE " PC  : %s\n", buf);
+	verbose_printk(KERN_NOTICE " PC  : %s\n", buf);
 
 	if (((long)fp->seqstat &  SEQSTAT_EXCAUSE) &&
 	    (((long)fp->seqstat & SEQSTAT_EXCAUSE) != VEC_HWERR)) {
 		decode_address(buf, saved_dcplb_fault_addr);
-		printk(KERN_NOTICE "DCPLB_FAULT_ADDR: %s\n", buf);
+		verbose_printk(KERN_NOTICE "DCPLB_FAULT_ADDR: %s\n", buf);
 		decode_address(buf, saved_icplb_fault_addr);
-		printk(KERN_NOTICE "ICPLB_FAULT_ADDR: %s\n", buf);
+		verbose_printk(KERN_NOTICE "ICPLB_FAULT_ADDR: %s\n", buf);
 	}
 
-	printk(KERN_NOTICE "\n" KERN_NOTICE "PROCESSOR STATE:\n");
-	printk(KERN_NOTICE " R0 : %08lx    R1 : %08lx    R2 : %08lx    R3 : %08lx\n",
+	verbose_printk(KERN_NOTICE "\n" KERN_NOTICE "PROCESSOR STATE:\n");
+	verbose_printk(KERN_NOTICE " R0 : %08lx    R1 : %08lx    R2 : %08lx    R3 : %08lx\n",
 		fp->r0, fp->r1, fp->r2, fp->r3);
-	printk(KERN_NOTICE " R4 : %08lx    R5 : %08lx    R6 : %08lx    R7 : %08lx\n",
+	verbose_printk(KERN_NOTICE " R4 : %08lx    R5 : %08lx    R6 : %08lx    R7 : %08lx\n",
 		fp->r4, fp->r5, fp->r6, fp->r7);
-	printk(KERN_NOTICE " P0 : %08lx    P1 : %08lx    P2 : %08lx    P3 : %08lx\n",
+	verbose_printk(KERN_NOTICE " P0 : %08lx    P1 : %08lx    P2 : %08lx    P3 : %08lx\n",
 		fp->p0, fp->p1, fp->p2, fp->p3);
-	printk(KERN_NOTICE " P4 : %08lx    P5 : %08lx    FP : %08lx    SP : %08lx\n",
+	verbose_printk(KERN_NOTICE " P4 : %08lx    P5 : %08lx    FP : %08lx    SP : %08lx\n",
 		fp->p4, fp->p5, fp->fp, (long)fp);
-	printk(KERN_NOTICE " LB0: %08lx    LT0: %08lx    LC0: %08lx\n",
+	verbose_printk(KERN_NOTICE " LB0: %08lx    LT0: %08lx    LC0: %08lx\n",
 		fp->lb0, fp->lt0, fp->lc0);
-	printk(KERN_NOTICE " LB1: %08lx    LT1: %08lx    LC1: %08lx\n",
+	verbose_printk(KERN_NOTICE " LB1: %08lx    LT1: %08lx    LC1: %08lx\n",
 		fp->lb1, fp->lt1, fp->lc1);
-	printk(KERN_NOTICE " B0 : %08lx    L0 : %08lx    M0 : %08lx    I0 : %08lx\n",
+	verbose_printk(KERN_NOTICE " B0 : %08lx    L0 : %08lx    M0 : %08lx    I0 : %08lx\n",
 		fp->b0, fp->l0, fp->m0, fp->i0);
-	printk(KERN_NOTICE " B1 : %08lx    L1 : %08lx    M1 : %08lx    I1 : %08lx\n",
+	verbose_printk(KERN_NOTICE " B1 : %08lx    L1 : %08lx    M1 : %08lx    I1 : %08lx\n",
 		fp->b1, fp->l1, fp->m1, fp->i1);
-	printk(KERN_NOTICE " B2 : %08lx    L2 : %08lx    M2 : %08lx    I2 : %08lx\n",
+	verbose_printk(KERN_NOTICE " B2 : %08lx    L2 : %08lx    M2 : %08lx    I2 : %08lx\n",
 		fp->b2, fp->l2, fp->m2, fp->i2);
-	printk(KERN_NOTICE " B3 : %08lx    L3 : %08lx    M3 : %08lx    I3 : %08lx\n",
+	verbose_printk(KERN_NOTICE " B3 : %08lx    L3 : %08lx    M3 : %08lx    I3 : %08lx\n",
 		fp->b3, fp->l3, fp->m3, fp->i3);
-	printk(KERN_NOTICE "A0.w: %08lx   A0.x: %08lx   A1.w: %08lx   A1.x: %08lx\n",
+	verbose_printk(KERN_NOTICE "A0.w: %08lx   A0.x: %08lx   A1.w: %08lx   A1.x: %08lx\n",
 		fp->a0w, fp->a0x, fp->a1w, fp->a1x);
 
-	printk(KERN_NOTICE "USP : %08lx  ASTAT: %08lx\n",
+	verbose_printk(KERN_NOTICE "USP : %08lx  ASTAT: %08lx\n",
 		rdusp(), fp->astat);
 
-	printk(KERN_NOTICE "\n");
+	verbose_printk(KERN_NOTICE "\n");
+#endif
 }
 
 #ifdef CONFIG_SYS_BFIN_SPINLOCK_L1
diff --git a/arch/blackfin/mach-bf527/boards/Kconfig b/arch/blackfin/mach-bf527/boards/Kconfig
index 8bf9e58..df224d0 100644
--- a/arch/blackfin/mach-bf527/boards/Kconfig
+++ b/arch/blackfin/mach-bf527/boards/Kconfig
@@ -14,4 +14,9 @@
 	help
 	  CM-BF527 support for EVAL- and DEV-Board.
 
+config BFIN526_EZBRD
+	bool "BF526-EZBRD"
+	help
+	  BF526-EZBRD/EZKIT Lite board support.
+
 endchoice
diff --git a/arch/blackfin/mach-bf527/boards/Makefile b/arch/blackfin/mach-bf527/boards/Makefile
index 7ba7d25..eb6ed33 100644
--- a/arch/blackfin/mach-bf527/boards/Makefile
+++ b/arch/blackfin/mach-bf527/boards/Makefile
@@ -4,3 +4,4 @@
 
 obj-$(CONFIG_BFIN527_EZKIT)            += ezkit.o
 obj-$(CONFIG_BFIN527_BLUETECHNIX_CM)   += cm_bf527.o
+obj-$(CONFIG_BFIN526_EZBRD)            += ezbrd.o
diff --git a/arch/blackfin/mach-bf527/boards/cm_bf527.c b/arch/blackfin/mach-bf527/boards/cm_bf527.c
index d22bc77..9ea440b 100644
--- a/arch/blackfin/mach-bf527/boards/cm_bf527.c
+++ b/arch/blackfin/mach-bf527/boards/cm_bf527.c
@@ -43,10 +43,7 @@
 #include <linux/irq.h>
 #include <linux/interrupt.h>
 #include <linux/usb/sl811.h>
-#if defined(CONFIG_USB_MUSB_HDRC) || defined(CONFIG_USB_MUSB_HDRC_MODULE)
 #include <linux/usb/musb.h>
-#endif
-#include <asm/cplb.h>
 #include <asm/dma.h>
 #include <asm/bfin5xx_spi.h>
 #include <asm/reboot.h>
@@ -130,6 +127,16 @@
 	},
 };
 
+static struct musb_hdrc_config musb_config = {
+	.multipoint	= 0,
+	.dyn_fifo	= 0,
+	.soft_con	= 1,
+	.dma		= 1,
+	.num_eps	= 7,
+	.dma_channels	= 7,
+	.gpio_vrsel	= GPIO_PF11,
+};
+
 static struct musb_hdrc_platform_data musb_plat = {
 #if defined(CONFIG_USB_MUSB_OTG)
 	.mode		= MUSB_OTG,
@@ -138,7 +145,7 @@
 #elif defined(CONFIG_USB_GADGET_MUSB_HDRC)
 	.mode		= MUSB_PERIPHERAL,
 #endif
-	.multipoint	= 0,
+	.config		= &musb_config,
 };
 
 static u64 musb_dmamask = ~(u32)0;
@@ -201,7 +208,7 @@
 	{
 		.name = "linux kernel(nand)",
 		.offset = 0,
-		.size = 4 * SIZE_1M,
+		.size = 4 * 1024 * 1024,
 	},
 	{
 		.name = "file system(nand)",
diff --git a/arch/blackfin/mach-bf527/boards/ezbrd.c b/arch/blackfin/mach-bf527/boards/ezbrd.c
new file mode 100644
index 0000000..36c87b6
--- /dev/null
+++ b/arch/blackfin/mach-bf527/boards/ezbrd.c
@@ -0,0 +1,734 @@
+/*
+ * File:         arch/blackfin/mach-bf527/boards/ezbrd.c
+ * Based on:     arch/blackfin/mach-bf537/boards/stamp.c
+ * Author:       Aidan Williams <aidan@nicta.com.au>
+ *
+ * Created:
+ * Description:
+ *
+ * Modified:
+ *               Copyright 2005 National ICT Australia (NICTA)
+ *               Copyright 2004-2008 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.org/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/physmap.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/flash.h>
+
+#include <linux/i2c.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/usb/musb.h>
+#include <asm/dma.h>
+#include <asm/bfin5xx_spi.h>
+#include <asm/reboot.h>
+#include <asm/nand.h>
+#include <asm/portmux.h>
+#include <asm/dpmc.h>
+#include <linux/spi/ad7877.h>
+
+/*
+ * Name the Board for the /proc/cpuinfo
+ */
+const char bfin_board_name[] = "BF526-EZBRD";
+
+/*
+ *  Driver needs to know address, irq and flag pin.
+ */
+
+#if defined(CONFIG_USB_MUSB_HDRC) || defined(CONFIG_USB_MUSB_HDRC_MODULE)
+static struct resource musb_resources[] = {
+	[0] = {
+		.start	= 0xffc03800,
+		.end	= 0xffc03cff,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {	/* general IRQ */
+		.start	= IRQ_USB_INT0,
+		.end	= IRQ_USB_INT0,
+		.flags	= IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
+	},
+	[2] = {	/* DMA IRQ */
+		.start	= IRQ_USB_DMA,
+		.end	= IRQ_USB_DMA,
+		.flags	= IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
+	},
+};
+
+static struct musb_hdrc_config musb_config = {
+	.multipoint	= 0,
+	.dyn_fifo	= 0,
+	.soft_con	= 1,
+	.dma		= 1,
+	.num_eps	= 7,
+	.dma_channels	= 7,
+	.gpio_vrsel	= GPIO_PG13,
+};
+
+static struct musb_hdrc_platform_data musb_plat = {
+#if defined(CONFIG_USB_MUSB_OTG)
+	.mode		= MUSB_OTG,
+#elif defined(CONFIG_USB_MUSB_HDRC_HCD)
+	.mode		= MUSB_HOST,
+#elif defined(CONFIG_USB_GADGET_MUSB_HDRC)
+	.mode		= MUSB_PERIPHERAL,
+#endif
+	.config		= &musb_config,
+};
+
+static u64 musb_dmamask = ~(u32)0;
+
+static struct platform_device musb_device = {
+	.name		= "musb_hdrc",
+	.id		= 0,
+	.dev = {
+		.dma_mask		= &musb_dmamask,
+		.coherent_dma_mask	= 0xffffffff,
+		.platform_data		= &musb_plat,
+	},
+	.num_resources	= ARRAY_SIZE(musb_resources),
+	.resource	= musb_resources,
+};
+#endif
+
+#if defined(CONFIG_MTD_PHYSMAP) || defined(CONFIG_MTD_PHYSMAP_MODULE)
+static struct mtd_partition ezbrd_partitions[] = {
+	{
+		.name       = "bootloader(nor)",
+		.size       = 0x40000,
+		.offset     = 0,
+	}, {
+		.name       = "linux kernel(nor)",
+		.size       = 0x1C0000,
+		.offset     = MTDPART_OFS_APPEND,
+	}, {
+		.name       = "file system(nor)",
+		.size       = MTDPART_SIZ_FULL,
+		.offset     = MTDPART_OFS_APPEND,
+	}
+};
+
+static struct physmap_flash_data ezbrd_flash_data = {
+	.width      = 2,
+	.parts      = ezbrd_partitions,
+	.nr_parts   = ARRAY_SIZE(ezbrd_partitions),
+};
+
+static struct resource ezbrd_flash_resource = {
+	.start = 0x20000000,
+	.end   = 0x203fffff,
+	.flags = IORESOURCE_MEM,
+};
+
+static struct platform_device ezbrd_flash_device = {
+	.name          = "physmap-flash",
+	.id            = 0,
+	.dev = {
+		.platform_data = &ezbrd_flash_data,
+	},
+	.num_resources = 1,
+	.resource      = &ezbrd_flash_resource,
+};
+#endif
+
+#if defined(CONFIG_MTD_NAND_BF5XX) || defined(CONFIG_MTD_NAND_BF5XX_MODULE)
+static struct mtd_partition partition_info[] = {
+	{
+		.name = "linux kernel(nand)",
+		.offset = 0,
+		.size = 4 * 1024 * 1024,
+	},
+	{
+		.name = "file system(nand)",
+		.offset = MTDPART_OFS_APPEND,
+		.size = MTDPART_SIZ_FULL,
+	},
+};
+
+static struct bf5xx_nand_platform bf5xx_nand_platform = {
+	.page_size = NFC_PG_SIZE_256,
+	.data_width = NFC_NWIDTH_8,
+	.partitions = partition_info,
+	.nr_partitions = ARRAY_SIZE(partition_info),
+	.rd_dly = 3,
+	.wr_dly = 3,
+};
+
+static struct resource bf5xx_nand_resources[] = {
+	{
+		.start = NFC_CTL,
+		.end = NFC_DATA_RD + 2,
+		.flags = IORESOURCE_MEM,
+	},
+	{
+		.start = CH_NFC,
+		.end = CH_NFC,
+		.flags = IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device bf5xx_nand_device = {
+	.name = "bf5xx-nand",
+	.id = 0,
+	.num_resources = ARRAY_SIZE(bf5xx_nand_resources),
+	.resource = bf5xx_nand_resources,
+	.dev = {
+		.platform_data = &bf5xx_nand_platform,
+	},
+};
+#endif
+
+#if defined(CONFIG_RTC_DRV_BFIN) || defined(CONFIG_RTC_DRV_BFIN_MODULE)
+static struct platform_device rtc_device = {
+	.name = "rtc-bfin",
+	.id   = -1,
+};
+#endif
+
+
+#if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE)
+static struct platform_device bfin_mac_device = {
+	.name = "bfin_mac",
+};
+#endif
+
+#if defined(CONFIG_MTD_M25P80) \
+	|| defined(CONFIG_MTD_M25P80_MODULE)
+static struct mtd_partition bfin_spi_flash_partitions[] = {
+	{
+		.name = "bootloader(spi)",
+		.size = 0x00040000,
+		.offset = 0,
+		.mask_flags = MTD_CAP_ROM
+	}, {
+		.name = "linux kernel(spi)",
+		.size = MTDPART_SIZ_FULL,
+		.offset = MTDPART_OFS_APPEND,
+	}
+};
+
+static struct flash_platform_data bfin_spi_flash_data = {
+	.name = "m25p80",
+	.parts = bfin_spi_flash_partitions,
+	.nr_parts = ARRAY_SIZE(bfin_spi_flash_partitions),
+	.type = "m25p16",
+};
+
+/* SPI flash chip (m25p64) */
+static struct bfin5xx_spi_chip spi_flash_chip_info = {
+	.enable_dma = 0,         /* use dma transfer with this chip*/
+	.bits_per_word = 8,
+};
+#endif
+
+#if defined(CONFIG_SPI_ADC_BF533) \
+	|| defined(CONFIG_SPI_ADC_BF533_MODULE)
+/* SPI ADC chip */
+static struct bfin5xx_spi_chip spi_adc_chip_info = {
+	.enable_dma = 1,         /* use dma transfer with this chip*/
+	.bits_per_word = 16,
+};
+#endif
+
+#if defined(CONFIG_SPI_MMC) || defined(CONFIG_SPI_MMC_MODULE)
+static struct bfin5xx_spi_chip spi_mmc_chip_info = {
+	.enable_dma = 1,
+	.bits_per_word = 8,
+};
+#endif
+
+#if defined(CONFIG_PBX)
+static struct bfin5xx_spi_chip spi_si3xxx_chip_info = {
+	.ctl_reg	= 0x4, /* send zero */
+	.enable_dma	= 0,
+	.bits_per_word	= 8,
+	.cs_change_per_word = 1,
+};
+#endif
+
+#if defined(CONFIG_TOUCHSCREEN_AD7877) || defined(CONFIG_TOUCHSCREEN_AD7877_MODULE)
+static struct bfin5xx_spi_chip spi_ad7877_chip_info = {
+	.enable_dma = 0,
+	.bits_per_word = 16,
+};
+
+static const struct ad7877_platform_data bfin_ad7877_ts_info = {
+	.model			= 7877,
+	.vref_delay_usecs	= 50,	/* internal, no capacitor */
+	.x_plate_ohms		= 419,
+	.y_plate_ohms		= 486,
+	.pressure_max		= 1000,
+	.pressure_min		= 0,
+	.stopacq_polarity 	= 1,
+	.first_conversion_delay = 3,
+	.acquisition_time 	= 1,
+	.averaging 		= 1,
+	.pen_down_acc_interval 	= 1,
+};
+#endif
+
+#if defined(CONFIG_SND_SOC_WM8731) || defined(CONFIG_SND_SOC_WM8731_MODULE) \
+	 && defined(CONFIG_SND_SOC_WM8731_SPI)
+static struct bfin5xx_spi_chip spi_wm8731_chip_info = {
+	.enable_dma = 0,
+	.bits_per_word = 16,
+};
+#endif
+
+#if defined(CONFIG_SPI_SPIDEV) || defined(CONFIG_SPI_SPIDEV_MODULE)
+static struct bfin5xx_spi_chip spidev_chip_info = {
+	.enable_dma = 0,
+	.bits_per_word = 8,
+};
+#endif
+
+#if defined(CONFIG_FB_BFIN_LQ035Q1) || defined(CONFIG_FB_BFIN_LQ035Q1_MODULE)
+static struct bfin5xx_spi_chip lq035q1_spi_chip_info = {
+	.enable_dma = 0,
+	.bits_per_word = 8,
+};
+#endif
+
+static struct spi_board_info bfin_spi_board_info[] __initdata = {
+#if defined(CONFIG_MTD_M25P80) \
+	|| defined(CONFIG_MTD_M25P80_MODULE)
+	{
+		/* the modalias must be the same as spi device driver name */
+		.modalias = "m25p80", /* Name of spi_driver for this device */
+		.max_speed_hz = 25000000,     /* max spi clock (SCK) speed in HZ */
+		.bus_num = 0, /* Framework bus number */
+		.chip_select = 1, /* Framework chip select. On STAMP537 it is SPISSEL1*/
+		.platform_data = &bfin_spi_flash_data,
+		.controller_data = &spi_flash_chip_info,
+		.mode = SPI_MODE_3,
+	},
+#endif
+
+#if defined(CONFIG_SPI_ADC_BF533) \
+	|| defined(CONFIG_SPI_ADC_BF533_MODULE)
+	{
+		.modalias = "bfin_spi_adc", /* Name of spi_driver for this device */
+		.max_speed_hz = 6250000,     /* max spi clock (SCK) speed in HZ */
+		.bus_num = 0, /* Framework bus number */
+		.chip_select = 1, /* Framework chip select. */
+		.platform_data = NULL, /* No spi_driver specific config */
+		.controller_data = &spi_adc_chip_info,
+	},
+#endif
+
+#if defined(CONFIG_SPI_MMC) || defined(CONFIG_SPI_MMC_MODULE)
+	{
+		.modalias = "spi_mmc_dummy",
+		.max_speed_hz = 25000000,     /* max spi clock (SCK) speed in HZ */
+		.bus_num = 0,
+		.chip_select = 0,
+		.platform_data = NULL,
+		.controller_data = &spi_mmc_chip_info,
+		.mode = SPI_MODE_3,
+	},
+	{
+		.modalias = "spi_mmc",
+		.max_speed_hz = 25000000,     /* max spi clock (SCK) speed in HZ */
+		.bus_num = 0,
+		.chip_select = CONFIG_SPI_MMC_CS_CHAN,
+		.platform_data = NULL,
+		.controller_data = &spi_mmc_chip_info,
+		.mode = SPI_MODE_3,
+	},
+#endif
+#if defined(CONFIG_PBX)
+	{
+		.modalias = "fxs-spi",
+		.max_speed_hz = 12500000,     /* max spi clock (SCK) speed in HZ */
+		.bus_num = 0,
+		.chip_select = 8 - CONFIG_J11_JUMPER,
+		.controller_data = &spi_si3xxx_chip_info,
+		.mode = SPI_MODE_3,
+	},
+	{
+		.modalias = "fxo-spi",
+		.max_speed_hz = 12500000,     /* max spi clock (SCK) speed in HZ */
+		.bus_num = 0,
+		.chip_select = 8 - CONFIG_J19_JUMPER,
+		.controller_data = &spi_si3xxx_chip_info,
+		.mode = SPI_MODE_3,
+	},
+#endif
+#if defined(CONFIG_TOUCHSCREEN_AD7877) || defined(CONFIG_TOUCHSCREEN_AD7877_MODULE)
+	{
+		.modalias		= "ad7877",
+		.platform_data		= &bfin_ad7877_ts_info,
+		.irq			= IRQ_PF8,
+		.max_speed_hz	= 12500000,     /* max spi clock (SCK) speed in HZ */
+		.bus_num	= 0,
+		.chip_select  = 2,
+		.controller_data = &spi_ad7877_chip_info,
+	},
+#endif
+#if defined(CONFIG_SND_SOC_WM8731) || defined(CONFIG_SND_SOC_WM8731_MODULE) \
+	 && defined(CONFIG_SND_SOC_WM8731_SPI)
+	{
+		.modalias	= "wm8731",
+		.max_speed_hz	= 3125000,     /* max spi clock (SCK) speed in HZ */
+		.bus_num	= 0,
+		.chip_select    = 5,
+		.controller_data = &spi_wm8731_chip_info,
+		.mode = SPI_MODE_0,
+	},
+#endif
+#if defined(CONFIG_SPI_SPIDEV) || defined(CONFIG_SPI_SPIDEV_MODULE)
+	{
+		.modalias = "spidev",
+		.max_speed_hz = 3125000,     /* max spi clock (SCK) speed in HZ */
+		.bus_num = 0,
+		.chip_select = 1,
+		.controller_data = &spidev_chip_info,
+	},
+#endif
+#if defined(CONFIG_FB_BFIN_LQ035Q1) || defined(CONFIG_FB_BFIN_LQ035Q1_MODULE)
+	{
+		.modalias = "bfin-lq035q1-spi",
+		.max_speed_hz = 20000000,     /* max spi clock (SCK) speed in HZ */
+		.bus_num = 0,
+		.chip_select = 1,
+		.controller_data = &lq035q1_spi_chip_info,
+		.mode = SPI_CPHA | SPI_CPOL,
+	},
+#endif
+};
+
+#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+/* SPI controller data */
+static struct bfin5xx_spi_master bfin_spi0_info = {
+	.num_chipselect = 8,
+	.enable_dma = 1,  /* master has the ability to do dma transfer */
+	.pin_req = {P_SPI0_SCK, P_SPI0_MISO, P_SPI0_MOSI, 0},
+};
+
+/* SPI (0) */
+static struct resource bfin_spi0_resource[] = {
+	[0] = {
+		.start = SPI0_REGBASE,
+		.end   = SPI0_REGBASE + 0xFF,
+		.flags = IORESOURCE_MEM,
+		},
+	[1] = {
+		.start = CH_SPI,
+		.end   = CH_SPI,
+		.flags = IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device bfin_spi0_device = {
+	.name = "bfin-spi",
+	.id = 0, /* Bus number */
+	.num_resources = ARRAY_SIZE(bfin_spi0_resource),
+	.resource = bfin_spi0_resource,
+	.dev = {
+		.platform_data = &bfin_spi0_info, /* Passed to driver */
+	},
+};
+#endif  /* spi master and devices */
+
+#if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
+static struct resource bfin_uart_resources[] = {
+#ifdef CONFIG_SERIAL_BFIN_UART0
+	{
+		.start = 0xFFC00400,
+		.end = 0xFFC004FF,
+		.flags = IORESOURCE_MEM,
+	},
+#endif
+#ifdef CONFIG_SERIAL_BFIN_UART1
+	{
+		.start = 0xFFC02000,
+		.end = 0xFFC020FF,
+		.flags = IORESOURCE_MEM,
+	},
+#endif
+};
+
+static struct platform_device bfin_uart_device = {
+	.name = "bfin-uart",
+	.id = 1,
+	.num_resources = ARRAY_SIZE(bfin_uart_resources),
+	.resource = bfin_uart_resources,
+};
+#endif
+
+#if defined(CONFIG_BFIN_SIR) || defined(CONFIG_BFIN_SIR_MODULE)
+static struct resource bfin_sir_resources[] = {
+#ifdef CONFIG_BFIN_SIR0
+	{
+		.start = 0xFFC00400,
+		.end = 0xFFC004FF,
+		.flags = IORESOURCE_MEM,
+	},
+#endif
+#ifdef CONFIG_BFIN_SIR1
+	{
+		.start = 0xFFC02000,
+		.end = 0xFFC020FF,
+		.flags = IORESOURCE_MEM,
+	},
+#endif
+};
+
+static struct platform_device bfin_sir_device = {
+	.name = "bfin_sir",
+	.id = 0,
+	.num_resources = ARRAY_SIZE(bfin_sir_resources),
+	.resource = bfin_sir_resources,
+};
+#endif
+
+#if defined(CONFIG_I2C_BLACKFIN_TWI) || defined(CONFIG_I2C_BLACKFIN_TWI_MODULE)
+static struct resource bfin_twi0_resource[] = {
+	[0] = {
+		.start = TWI0_REGBASE,
+		.end   = TWI0_REGBASE,
+		.flags = IORESOURCE_MEM,
+	},
+	[1] = {
+		.start = IRQ_TWI,
+		.end   = IRQ_TWI,
+		.flags = IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device i2c_bfin_twi_device = {
+	.name = "i2c-bfin-twi",
+	.id = 0,
+	.num_resources = ARRAY_SIZE(bfin_twi0_resource),
+	.resource = bfin_twi0_resource,
+};
+#endif
+
+#ifdef CONFIG_I2C_BOARDINFO
+static struct i2c_board_info __initdata bfin_i2c_board_info[] = {
+#if defined(CONFIG_TWI_LCD) || defined(CONFIG_TWI_LCD_MODULE)
+	{
+		I2C_BOARD_INFO("pcf8574_lcd", 0x22),
+	},
+#endif
+#if defined(CONFIG_TWI_KEYPAD) || defined(CONFIG_TWI_KEYPAD_MODULE)
+	{
+		I2C_BOARD_INFO("pcf8574_keypad", 0x27),
+		.irq = IRQ_PF8,
+	},
+#endif
+};
+#endif
+
+#if defined(CONFIG_SERIAL_BFIN_SPORT) || defined(CONFIG_SERIAL_BFIN_SPORT_MODULE)
+static struct platform_device bfin_sport0_uart_device = {
+	.name = "bfin-sport-uart",
+	.id = 0,
+};
+
+static struct platform_device bfin_sport1_uart_device = {
+	.name = "bfin-sport-uart",
+	.id = 1,
+};
+#endif
+
+#if defined(CONFIG_KEYBOARD_GPIO) || defined(CONFIG_KEYBOARD_GPIO_MODULE)
+#include <linux/input.h>
+#include <linux/gpio_keys.h>
+
+static struct gpio_keys_button bfin_gpio_keys_table[] = {
+	{BTN_0, GPIO_PG0, 1, "gpio-keys: BTN0"},
+	{BTN_1, GPIO_PG13, 1, "gpio-keys: BTN1"},
+};
+
+static struct gpio_keys_platform_data bfin_gpio_keys_data = {
+	.buttons        = bfin_gpio_keys_table,
+	.nbuttons       = ARRAY_SIZE(bfin_gpio_keys_table),
+};
+
+static struct platform_device bfin_device_gpiokeys = {
+	.name      = "gpio-keys",
+	.dev = {
+		.platform_data = &bfin_gpio_keys_data,
+	},
+};
+#endif
+
+static struct resource bfin_gpios_resources = {
+	.start = 0,
+	.end   = MAX_BLACKFIN_GPIOS - 1,
+	.flags = IORESOURCE_IRQ,
+};
+
+static struct platform_device bfin_gpios_device = {
+	.name = "simple-gpio",
+	.id = -1,
+	.num_resources = 1,
+	.resource = &bfin_gpios_resources,
+};
+
+static const unsigned int cclk_vlev_datasheet[] =
+{
+	VRPAIR(VLEV_100, 400000000),
+	VRPAIR(VLEV_105, 426000000),
+	VRPAIR(VLEV_110, 500000000),
+	VRPAIR(VLEV_115, 533000000),
+	VRPAIR(VLEV_120, 600000000),
+};
+
+static struct bfin_dpmc_platform_data bfin_dmpc_vreg_data = {
+	.tuple_tab = cclk_vlev_datasheet,
+	.tabsize = ARRAY_SIZE(cclk_vlev_datasheet),
+	.vr_settling_time = 25 /* us */,
+};
+
+static struct platform_device bfin_dpmc = {
+	.name = "bfin dpmc",
+	.dev = {
+		.platform_data = &bfin_dmpc_vreg_data,
+	},
+};
+
+#if defined(CONFIG_FB_BFIN_LQ035Q1) || defined(CONFIG_FB_BFIN_LQ035Q1_MODULE)
+#include <asm/bfin-lq035q1.h>
+
+static struct bfin_lq035q1fb_disp_info bfin_lq035q1_data = {
+	.mode = 	LQ035_NORM | LQ035_RGB | LQ035_RL | LQ035_TB,
+	.use_bl = 	1,
+	.gpio_bl =	GPIO_PG12,
+};
+
+static struct resource bfin_lq035q1_resources[] = {
+	{
+		.start = IRQ_PPI_ERROR,
+		.end = IRQ_PPI_ERROR,
+		.flags = IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device bfin_lq035q1_device = {
+	.name		= "bfin-lq035q1",
+	.id		= -1,
+	.num_resources 	= ARRAY_SIZE(bfin_lq035q1_resources),
+	.resource 	= bfin_lq035q1_resources,
+	.dev		= {
+		.platform_data = &bfin_lq035q1_data,
+	},
+};
+#endif
+
+static struct platform_device *stamp_devices[] __initdata = {
+
+	&bfin_dpmc,
+
+#if defined(CONFIG_MTD_NAND_BF5XX) || defined(CONFIG_MTD_NAND_BF5XX_MODULE)
+	&bf5xx_nand_device,
+#endif
+
+#if defined(CONFIG_RTC_DRV_BFIN) || defined(CONFIG_RTC_DRV_BFIN_MODULE)
+	&rtc_device,
+#endif
+
+#if defined(CONFIG_USB_MUSB_HDRC) || defined(CONFIG_USB_MUSB_HDRC_MODULE)
+	&musb_device,
+#endif
+
+#if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE)
+	&bfin_mac_device,
+#endif
+
+#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+	&bfin_spi0_device,
+#endif
+
+#if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
+	&bfin_uart_device,
+#endif
+
+#if defined(CONFIG_FB_BFIN_LQ035Q1) || defined(CONFIG_FB_BFIN_LQ035Q1_MODULE)
+	&bfin_lq035q1_device,
+#endif
+
+#if defined(CONFIG_BFIN_SIR) || defined(CONFIG_BFIN_SIR_MODULE)
+	&bfin_sir_device,
+#endif
+
+#if defined(CONFIG_I2C_BLACKFIN_TWI) || defined(CONFIG_I2C_BLACKFIN_TWI_MODULE)
+	&i2c_bfin_twi_device,
+#endif
+
+#if defined(CONFIG_SERIAL_BFIN_SPORT) || defined(CONFIG_SERIAL_BFIN_SPORT_MODULE)
+	&bfin_sport0_uart_device,
+	&bfin_sport1_uart_device,
+#endif
+
+#if defined(CONFIG_KEYBOARD_GPIO) || defined(CONFIG_KEYBOARD_GPIO_MODULE)
+	&bfin_device_gpiokeys,
+#endif
+
+#if defined(CONFIG_MTD_PHYSMAP) || defined(CONFIG_MTD_PHYSMAP_MODULE)
+	&ezbrd_flash_device,
+#endif
+
+	&bfin_gpios_device,
+};
+
+static int __init stamp_init(void)
+{
+	printk(KERN_INFO "%s(): registering device resources\n", __func__);
+
+#ifdef CONFIG_I2C_BOARDINFO
+	i2c_register_board_info(0, bfin_i2c_board_info,
+				ARRAY_SIZE(bfin_i2c_board_info));
+#endif
+
+	platform_add_devices(stamp_devices, ARRAY_SIZE(stamp_devices));
+	spi_register_board_info(bfin_spi_board_info, ARRAY_SIZE(bfin_spi_board_info));
+	return 0;
+}
+
+arch_initcall(stamp_init);
+
+void native_machine_restart(char *cmd)
+{
+	/* workaround reboot hang when booting from SPI */
+	if ((bfin_read_SYSCR() & 0x7) == 0x3)
+		bfin_gpio_reset_spi0_ssel1();
+}
+
+void bfin_get_ether_addr(char *addr)
+{
+	/* the MAC is stored in OTP memory page 0xDF */
+	u32 ret;
+	u64 otp_mac;
+	u32 (*otp_read)(u32 page, u32 flags, u64 *page_content) = (void *)0xEF00001A;
+
+	ret = otp_read(0xDF, 0x00, &otp_mac);
+	if (!(ret & 0x1)) {
+		char *otp_mac_p = (char *)&otp_mac;
+		for (ret = 0; ret < 6; ++ret)
+			addr[ret] = otp_mac_p[5 - ret];
+	}
+}
+EXPORT_SYMBOL(bfin_get_ether_addr);
diff --git a/arch/blackfin/mach-bf527/boards/ezkit.c b/arch/blackfin/mach-bf527/boards/ezkit.c
index 762f754..8ee2b74 100644
--- a/arch/blackfin/mach-bf527/boards/ezkit.c
+++ b/arch/blackfin/mach-bf527/boards/ezkit.c
@@ -42,10 +42,7 @@
 #include <linux/irq.h>
 #include <linux/interrupt.h>
 #include <linux/usb/sl811.h>
-#if defined(CONFIG_USB_MUSB_HDRC) || defined(CONFIG_USB_MUSB_HDRC_MODULE)
 #include <linux/usb/musb.h>
-#endif
-#include <asm/cplb.h>
 #include <asm/dma.h>
 #include <asm/bfin5xx_spi.h>
 #include <asm/reboot.h>
@@ -129,6 +126,16 @@
 	},
 };
 
+static struct musb_hdrc_config musb_config = {
+	.multipoint	= 0,
+	.dyn_fifo	= 0,
+	.soft_con	= 1,
+	.dma		= 1,
+	.num_eps	= 7,
+	.dma_channels	= 7,
+	.gpio_vrsel	= GPIO_PG13,
+};
+
 static struct musb_hdrc_platform_data musb_plat = {
 #if defined(CONFIG_USB_MUSB_OTG)
 	.mode		= MUSB_OTG,
@@ -137,7 +144,7 @@
 #elif defined(CONFIG_USB_GADGET_MUSB_HDRC)
 	.mode		= MUSB_PERIPHERAL,
 #endif
-	.multipoint	= 0,
+	.config		= &musb_config,
 };
 
 static u64 musb_dmamask = ~(u32)0;
@@ -218,7 +225,7 @@
 	{
 		.name = "linux kernel(nand)",
 		.offset = 0,
-		.size = 4 * SIZE_1M,
+		.size = 4 * 1024 * 1024,
 	},
 	{
 		.name = "file system(nand)",
@@ -846,6 +853,38 @@
 };
 #endif
 
+#if defined(CONFIG_JOYSTICK_BFIN_ROTARY) || defined(CONFIG_JOYSTICK_BFIN_ROTARY_MODULE)
+#include <linux/input.h>
+#include <asm/bfin_rotary.h>
+
+static struct bfin_rotary_platform_data bfin_rotary_data = {
+	/*.rotary_up_key     = KEY_UP,*/
+	/*.rotary_down_key   = KEY_DOWN,*/
+	.rotary_rel_code   = REL_WHEEL,
+	.rotary_button_key = KEY_ENTER,
+	.debounce	   = 10,	/* 0..17 */
+	.mode		   = ROT_QUAD_ENC | ROT_DEBE,
+};
+
+static struct resource bfin_rotary_resources[] = {
+	{
+		.start = IRQ_CNT,
+		.end = IRQ_CNT,
+		.flags = IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device bfin_rotary_device = {
+	.name		= "bfin-rotary",
+	.id		= -1,
+	.num_resources 	= ARRAY_SIZE(bfin_rotary_resources),
+	.resource 	= bfin_rotary_resources,
+	.dev		= {
+		.platform_data = &bfin_rotary_data,
+	},
+};
+#endif
+
 static struct resource bfin_gpios_resources = {
 	.start = 0,
 	.end   = MAX_BLACKFIN_GPIOS - 1,
@@ -962,6 +1001,10 @@
 	&bfin_device_gpiokeys,
 #endif
 
+#if defined(CONFIG_JOYSTICK_BFIN_ROTARY) || defined(CONFIG_JOYSTICK_BFIN_ROTARY_MODULE)
+	&bfin_rotary_device,
+#endif
+
 #if defined(CONFIG_MTD_PHYSMAP) || defined(CONFIG_MTD_PHYSMAP_MODULE)
 	&ezkit_flash_device,
 #endif
diff --git a/arch/blackfin/mach-bf527/head.S b/arch/blackfin/mach-bf527/head.S
index 28c4861..6588170 100644
--- a/arch/blackfin/mach-bf527/head.S
+++ b/arch/blackfin/mach-bf527/head.S
@@ -87,6 +87,9 @@
 	r1 = PLL_BYPASS;                 /* Bypass the PLL?                 */
 	r1 = r1 << 8;                    /* Shift it over                   */
 	r0 = r1 | r0;                    /* add them all together           */
+#ifdef ANOMALY_05000265
+	r0 = BITSET(r0, 15);             /* Add 250 mV of hysteresis to SPORT input pins */
+#endif
 
 	p0.h = hi(PLL_CTL);
 	p0.l = lo(PLL_CTL);              /* Load the address                */
diff --git a/arch/blackfin/mach-bf527/include/mach/anomaly.h b/arch/blackfin/mach-bf527/include/mach/anomaly.h
index b7b166f..62373e6 100644
--- a/arch/blackfin/mach-bf527/include/mach/anomaly.h
+++ b/arch/blackfin/mach-bf527/include/mach/anomaly.h
@@ -7,12 +7,24 @@
  */
 
 /* This file shoule be up to date with:
- *  - Revision C, 01/25/2008; ADSP-BF527 Blackfin Processor Anomaly List
+ *  - Revision B, 08/12/2008; ADSP-BF526 Blackfin Processor Anomaly List
+ *  - Revision E, 08/18/2008; ADSP-BF527 Blackfin Processor Anomaly List
  */
 
 #ifndef _MACH_ANOMALY_H_
 #define _MACH_ANOMALY_H_
 
+#if defined(__ADSPBF522__) || defined(__ADSPBF524__) || defined(__ADSPBF526__)
+# define ANOMALY_BF526 1
+#else
+# define ANOMALY_BF526 0
+#endif
+#if defined(__ADSPBF523__) || defined(__ADSPBF525__) || defined(__ADSPBF527__)
+# define ANOMALY_BF527 1
+#else
+# define ANOMALY_BF527 0
+#endif
+
 /* Multi-Issue Instruction with dsp32shiftimm in slot1 and P-reg Store in slot2 Not Supported */
 #define ANOMALY_05000074 (1)
 /* DMA_RUN Bit Is Not Valid after a Peripheral Receive Channel DMA Stops */
@@ -23,68 +35,124 @@
 #define ANOMALY_05000245 (1)
 /* Sensitivity To Noise with Slow Input Edge Rates on External SPORT TX and RX Clocks */
 #define ANOMALY_05000265 (1)
-/* New Feature: EMAC TX DMA Word Alignment */
-#define ANOMALY_05000285 (1)
+/* False Hardware Errors Caused by Fetches at the Boundary of Reserved Memory */
+#define ANOMALY_05000310 (1)
 /* Errors when SSYNC, CSYNC, or Loads to LT, LB and LC Registers Are Interrupted */
-#define ANOMALY_05000312 (1)
+#define ANOMALY_05000312 (ANOMALY_BF527)
+/* PPI Is Level-Sensitive on First Transfer In Single Frame Sync Modes */
+#define ANOMALY_05000313 (__SILICON_REVISION__ < 2)
 /* Incorrect Access of OTP_STATUS During otp_write() Function */
-#define ANOMALY_05000328 (1)
+#define ANOMALY_05000328 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
 /* Disallowed Configuration Prevents Subsequent Allowed Configuration on Host DMA Port */
-#define ANOMALY_05000337 (1)
+#define ANOMALY_05000337 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
 /* Ethernet MAC MDIO Reads Do Not Meet IEEE Specification */
-#define ANOMALY_05000341 (1)
+#define ANOMALY_05000341 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
 /* TWI May Not Operate Correctly Under Certain Signal Termination Conditions */
-#define ANOMALY_05000342 (1)
+#define ANOMALY_05000342 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
 /* USB Calibration Value Is Not Initialized */
-#define ANOMALY_05000346 (1)
+#define ANOMALY_05000346 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
+/* USB Calibration Value to use */
+#define ANOMALY_05000346_value 0xE510
 /* Preboot Routine Incorrectly Alters Reset Value of USB Register */
-#define ANOMALY_05000347 (1)
+#define ANOMALY_05000347 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
 /* Security Features Are Not Functional */
-#define ANOMALY_05000348 (__SILICON_REVISION__ < 1)
+#define ANOMALY_05000348 (ANOMALY_BF527 && __SILICON_REVISION__ < 1)
+/* bfrom_SysControl() Firmware Function Performs Improper System Reset */
+#define ANOMALY_05000353 (ANOMALY_BF526)
 /* Regulator Programming Blocked when Hibernate Wakeup Source Remains Active */
-#define ANOMALY_05000355 (1)
+#define ANOMALY_05000355 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
 /* Serial Port (SPORT) Multichannel Transmit Failure when Channel 0 Is Disabled */
-#define ANOMALY_05000357 (1)
+#define ANOMALY_05000357 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
 /* Incorrect Revision Number in DSPID Register */
-#define ANOMALY_05000364 (__SILICON_REVISION__ > 0)
+#define ANOMALY_05000364 (ANOMALY_BF527 && __SILICON_REVISION__ == 1)
 /* PPI Underflow Error Goes Undetected in ITU-R 656 Mode */
 #define ANOMALY_05000366 (1)
-/* New Feature: Higher Default CCLK Rate */
-#define ANOMALY_05000368 (1)
+/* Incorrect Default CSEL Value in PLL_DIV */
+#define ANOMALY_05000368 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
 /* Possible RETS Register Corruption when Subroutine Is under 5 Cycles in Duration */
-#define ANOMALY_05000371 (1)
+#define ANOMALY_05000371 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
 /* Authentication Fails To Initiate */
-#define ANOMALY_05000376 (__SILICON_REVISION__ > 0)
+#define ANOMALY_05000376 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
 /* Data Read From L3 Memory by USB DMA May be Corrupted */
-#define ANOMALY_05000380 (1)
-/* USB Full-speed Mode not Fully Tested */
-#define ANOMALY_05000381 (1)
-/* New Feature: Boot from OTP Memory */
-#define ANOMALY_05000385 (1)
-/* New Feature: bfrom_SysControl() Routine */
-#define ANOMALY_05000386 (1)
-/* New Feature: Programmable Preboot Settings */
-#define ANOMALY_05000387 (1)
+#define ANOMALY_05000380 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
+/* 8-Bit NAND Flash Boot Mode Not Functional */
+#define ANOMALY_05000382 (__SILICON_REVISION__ < 2)
+/* Host Must Not Read Back During Host DMA Boot */
+#define ANOMALY_05000384 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
+/* Boot from OTP Memory Not Functional */
+#define ANOMALY_05000385 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
+/* bfrom_SysControl() Firmware Routine Not Functional */
+#define ANOMALY_05000386 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
+/* Programmable Preboot Settings Not Functional */
+#define ANOMALY_05000387 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
+/* CRC32 Checksum Support Not Functional */
+#define ANOMALY_05000388 (__SILICON_REVISION__ < 2)
 /* Reset Vector Must Not Be in SDRAM Memory Space */
-#define ANOMALY_05000389 (1)
-/* New Feature: pTempCurrent Added to ADI_BOOT_DATA Structure */
-#define ANOMALY_05000392 (1)
-/* New Feature: dTempByteCount Value Increased in ADI_BOOT_DATA Structure */
-#define ANOMALY_05000393 (1)
-/* New Feature: Log Buffer Functionality */
-#define ANOMALY_05000394 (1)
-/* New Feature: Hook Routine Functionality */
-#define ANOMALY_05000395 (1)
-/* New Feature: Header Indirect Bit */
-#define ANOMALY_05000396 (1)
-/* New Feature: BK_ONES, BK_ZEROS, and BK_DATECODE Constants */
-#define ANOMALY_05000397 (1)
-/* New Feature: SWRESET, DFRESET and WDRESET Bits Added to SYSCR Register */
-#define ANOMALY_05000398 (1)
-/* New Feature: BCODE_NOBOOT Added to BCODE Field of SYSCR Register */
-#define ANOMALY_05000399 (1)
+#define ANOMALY_05000389 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
+/* pTempCurrent Not Present in ADI_BOOT_DATA Structure */
+#define ANOMALY_05000392 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
+/* Deprecated Value of dTempByteCount in ADI_BOOT_DATA Structure */
+#define ANOMALY_05000393 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
+/* Log Buffer Not Functional */
+#define ANOMALY_05000394 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
+/* Hook Routine Not Functional */
+#define ANOMALY_05000395 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
+/* Header Indirect Bit Not Functional */
+#define ANOMALY_05000396 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
+/* BK_ONES, BK_ZEROS, and BK_DATECODE Constants Not Functional */
+#define ANOMALY_05000397 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
+/* SWRESET, DFRESET and WDRESET Bits in the SYSCR Register Not Functional */
+#define ANOMALY_05000398 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
+/* BCODE_NOBOOT in BCODE Field of SYSCR Register Not Functional */
+#define ANOMALY_05000399 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
 /* PPI Data Signals D0 and D8 do not Tristate After Disabling PPI */
-#define ANOMALY_05000401 (1)
+#define ANOMALY_05000401 (__SILICON_REVISION__ < 2)
+/* Level-Sensitive External GPIO Wakeups May Cause Indefinite Stall */
+#define ANOMALY_05000403 (__SILICON_REVISION__ < 2)
+/* Lockbox SESR Disallows Certain User Interrupts */
+#define ANOMALY_05000404 (__SILICON_REVISION__ < 2)
+/* Lockbox SESR Firmware Does Not Save/Restore Full Context */
+#define ANOMALY_05000405 (1)
+/* Lockbox SESR Firmware Arguments Are Not Retained After First Initialization */
+#define ANOMALY_05000407 (__SILICON_REVISION__ < 2)
+/* Lockbox Firmware Memory Cleanup Routine Does not Clear Registers */
+#define ANOMALY_05000408 (1)
+/* Lockbox firmware leaves MDMA0 channel enabled */
+#define ANOMALY_05000409 (__SILICON_REVISION__ < 2)
+/* Incorrect Default Internal Voltage Regulator Setting */
+#define ANOMALY_05000410 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
+/* bfrom_SysControl() Firmware Function Cannot be Used to Enter Power Saving Modes */
+#define ANOMALY_05000411 (__SILICON_REVISION__ < 2)
+/* OTP_CHECK_FOR_PREV_WRITE Bit is Not Functional in bfrom_OtpWrite() API */
+#define ANOMALY_05000414 (__SILICON_REVISION__ < 2)
+/* DEB2_URGENT Bit Not Functional */
+#define ANOMALY_05000415 (__SILICON_REVISION__ < 2)
+/* Speculative Fetches Can Cause Undesired External FIFO Operations */
+#define ANOMALY_05000416 (1)
+/* SPORT0 Ignores External TSCLK0 on PG14 When TMR6 is an Output */
+#define ANOMALY_05000417 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
+/* tSFSPE and tHFSPE Do Not Meet Data Sheet Specifications */
+#define ANOMALY_05000418 (__SILICON_REVISION__ < 2)
+/* USB PLL_STABLE Bit May Not Accurately Reflect the USB PLL's Status */
+#define ANOMALY_05000420 (__SILICON_REVISION__ < 2)
+/* TWI Fall Time (Tof) May Violate the Minimum I2C Specification */
+#define ANOMALY_05000421 (1)
+/* TWI Input Capacitance (Ci) May Violate the Maximum I2C Specification */
+#define ANOMALY_05000422 (ANOMALY_BF527 && __SILICON_REVISION__ > 1)
+/* Certain Ethernet Frames With Errors are Misclassified in RMII Mode */
+#define ANOMALY_05000423 (__SILICON_REVISION__ < 2)
+/* Internal Voltage Regulator Not Trimmed */
+#define ANOMALY_05000424 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
+/* Multichannel SPORT Channel Misalignment Under Specific Configuration */
+#define ANOMALY_05000425 (__SILICON_REVISION__ < 2)
+/* Speculative Fetches of Indirect-Pointer Instructions Can Cause Spurious Hardware Errors */
+#define ANOMALY_05000426 (1)
+/* WB_EDGE Bit in NFC_IRQSTAT Incorrectly Reflects Buffer Status Instead of IRQ Status */
+#define ANOMALY_05000429 (__SILICON_REVISION__ < 2)
+/* Software System Reset Corrupts PLL_LOCKCNT Register */
+#define ANOMALY_05000430 (ANOMALY_BF527 && __SILICON_REVISION__ > 1)
+/* bfrom_SysControl() Does Not Clear SIC_IWR1 Before Executing PLL Programming Sequence */
+#define ANOMALY_05000432 (ANOMALY_BF526)
 
 /* Anomalies that don't exist on this proc */
 #define ANOMALY_05000125 (0)
@@ -97,6 +165,8 @@
 #define ANOMALY_05000263 (0)
 #define ANOMALY_05000266 (0)
 #define ANOMALY_05000273 (0)
+#define ANOMALY_05000285 (0)
+#define ANOMALY_05000307 (0)
 #define ANOMALY_05000311 (0)
 #define ANOMALY_05000323 (0)
 #define ANOMALY_05000363 (0)
diff --git a/arch/blackfin/mach-bf527/include/mach/bf527.h b/arch/blackfin/mach-bf527/include/mach/bf527.h
index 056eb4b..144f08d 100644
--- a/arch/blackfin/mach-bf527/include/mach/bf527.h
+++ b/arch/blackfin/mach-bf527/include/mach/bf527.h
@@ -30,8 +30,6 @@
 #ifndef __MACH_BF527_H__
 #define __MACH_BF527_H__
 
-#define SUPPORTED_REVID 2
-
 #define OFFSET_(x) ((x) & 0x0000FFFF)
 
 /*some misc defines*/
@@ -112,16 +110,31 @@
 
 #ifdef CONFIG_BF527
 #define CPU "BF527"
+#define CPUID 0x27e4
+#endif
+#ifdef CONFIG_BF526
+#define CPU "BF526"
+#define CPUID 0x27e4
 #endif
 #ifdef CONFIG_BF525
 #define CPU "BF525"
+#define CPUID 0x27e4
+#endif
+#ifdef CONFIG_BF524
+#define CPU "BF524"
+#define CPUID 0x27e4
+#endif
+#ifdef CONFIG_BF523
+#define CPU "BF523"
+#define CPUID 0x27e4
 #endif
 #ifdef CONFIG_BF522
 #define CPU "BF522"
+#define CPUID 0x27e4
 #endif
+
 #ifndef CPU
-#define	CPU "UNKNOWN"
-#define CPUID 0x0
+#error Unknown CPU type - This kernel doesn't seem to be configured properly
 #endif
 
 #endif				/* __MACH_BF527_H__  */
diff --git a/arch/blackfin/mach-bf527/include/mach/bfin_serial_5xx.h b/arch/blackfin/mach-bf527/include/mach/bfin_serial_5xx.h
index 2526b6e..75722d6 100644
--- a/arch/blackfin/mach-bf527/include/mach/bfin_serial_5xx.h
+++ b/arch/blackfin/mach-bf527/include/mach/bfin_serial_5xx.h
@@ -78,6 +78,9 @@
 #  define CONFIG_UART1_RTS_PIN -1
 # endif
 #endif
+
+#define BFIN_UART_TX_FIFO_SIZE	2
+
 /*
  * The pin configuration is different from schematic
  */
@@ -119,7 +122,6 @@
 	bfin_write16(uart->port.membase + OFFSET_LSR, -1);
 }
 
-struct bfin_serial_port bfin_serial_ports[BFIN_UART_NR_PORTS];
 struct bfin_serial_res {
 	unsigned long uart_base_addr;
 	int uart_irq;
@@ -164,8 +166,6 @@
 #endif
 };
 
-int nr_ports = ARRAY_SIZE(bfin_serial_resource);
-
 #define DRIVER_NAME "bfin-uart"
 
 static void bfin_serial_hw_init(struct bfin_serial_port *uart)
diff --git a/arch/blackfin/mach-bf527/include/mach/defBF52x_base.h b/arch/blackfin/mach-bf527/include/mach/defBF52x_base.h
index 6ac2ed7..68b55d0 100644
--- a/arch/blackfin/mach-bf527/include/mach/defBF52x_base.h
+++ b/arch/blackfin/mach-bf527/include/mach/defBF52x_base.h
@@ -1840,6 +1840,33 @@
 
 #define                 DPRESCALE  0xf        /* Load Counter Register */
 
+/* CNT_COMMAND bit field options */
+
+#define W1LCNT_ZERO   0x0001   /* write 1 to load CNT_COUNTER with zero */
+#define W1LCNT_MIN    0x0004   /* write 1 to load CNT_COUNTER from CNT_MIN */
+#define W1LCNT_MAX    0x0008   /* write 1 to load CNT_COUNTER from CNT_MAX */
+
+#define W1LMIN_ZERO   0x0010   /* write 1 to load CNT_MIN with zero */
+#define W1LMIN_CNT    0x0020   /* write 1 to load CNT_MIN from CNT_COUNTER */
+#define W1LMIN_MAX    0x0080   /* write 1 to load CNT_MIN from CNT_MAX */
+
+#define W1LMAX_ZERO   0x0100   /* write 1 to load CNT_MAX with zero */
+#define W1LMAX_CNT    0x0200   /* write 1 to load CNT_MAX from CNT_COUNTER */
+#define W1LMAX_MIN    0x0400   /* write 1 to load CNT_MAX from CNT_MIN */
+
+/* CNT_CONFIG bit field options */
+
+#define CNTMODE_QUADENC  0x0000  /* quadrature encoder mode */
+#define CNTMODE_BINENC   0x0100  /* binary encoder mode */
+#define CNTMODE_UDCNT    0x0200  /* up/down counter mode */
+#define CNTMODE_DIRCNT   0x0400  /* direction counter mode */
+#define CNTMODE_DIRTMR   0x0500  /* direction timer mode */
+
+#define BNDMODE_COMP     0x0000  /* boundary compare mode */
+#define BNDMODE_ZERO     0x1000  /* boundary compare and zero mode */
+#define BNDMODE_CAPT     0x2000  /* boundary capture mode */
+#define BNDMODE_AEXT     0x3000  /* boundary auto-extend mode */
+
 /* Bit masks for OTP_CONTROL */
 
 #define                FUSE_FADDR  0x1ff      /* OTP/Fuse Address */
diff --git a/arch/blackfin/mach-bf527/include/mach/portmux.h b/arch/blackfin/mach-bf527/include/mach/portmux.h
index ae4d205..7f6da2c3 100644
--- a/arch/blackfin/mach-bf527/include/mach/portmux.h
+++ b/arch/blackfin/mach-bf527/include/mach/portmux.h
@@ -67,6 +67,10 @@
 #define P_UART1_RX	(P_DEFINED | P_IDENT(GPIO_PG13) | P_FUNCT(1))
 #endif
 
+#define P_CNT_CZM	(P_DEFINED | P_IDENT(GPIO_PF11) | P_FUNCT(3))
+#define P_CNT_CDG	(P_DEFINED | P_IDENT(GPIO_PF12) | P_FUNCT(3))
+#define P_CNT_CUD	(P_DEFINED | P_IDENT(GPIO_PF13) | P_FUNCT(3))
+
 #define P_HWAIT		(P_DONTCARE)
 
 #define P_SPI0_SS	(P_DEFINED | P_IDENT(GPIO_PG1) | P_FUNCT(0))
diff --git a/arch/blackfin/mach-bf533/boards/H8606.c b/arch/blackfin/mach-bf533/boards/H8606.c
index c66a68f..72ac3ac 100644
--- a/arch/blackfin/mach-bf533/boards/H8606.c
+++ b/arch/blackfin/mach-bf533/boards/H8606.c
@@ -9,7 +9,7 @@
  * Modified:
  *               Copyright 2005 National ICT Australia (NICTA)
  *               Copyright 2004-2006 Analog Devices Inc
- *		 Copyright 2007 HV Sistemas S.L.
+ *		 Copyright 2007,2008 HV Sistemas S.L.
  *
  * Bugs:         Enter bugs at http://blackfin.uclinux.org/
  *
@@ -64,18 +64,18 @@
 static struct resource dm9000_resources[] = {
 	[0] = {
 		.start	= 0x20300000,
-		.end	= 0x20300000 + 1,
+		.end	= 0x20300002,
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= 0x20300000 + 4,
-		.end	= 0x20300000 + 5,
+		.start	= 0x20300004,
+		.end	= 0x20300006,
 		.flags	= IORESOURCE_MEM,
 	},
 	[2] = {
 		.start	= IRQ_PF10,
 		.end	= IRQ_PF10,
-		.flags	= (IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE),
+		.flags	= (IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE | IRQF_SHARED | IRQF_TRIGGER_HIGH),
 	},
 };
 
@@ -140,18 +140,22 @@
 #if defined(CONFIG_MTD_M25P80) || defined(CONFIG_MTD_M25P80_MODULE)
 static struct mtd_partition bfin_spi_flash_partitions[] = {
 	{
-		.name = "bootloader(spi)",
-		.size = 0x00060000,
+		.name = "bootloader (spi)",
+		.size = 0x40000,
 		.offset = 0,
 		.mask_flags = MTD_CAP_ROM
 	}, {
-		.name = "linux kernel(spi)",
-		.size = 0x100000,
-		.offset = 0x60000
+		.name = "fpga (spi)",
+		.size =   0x30000,
+		.offset = 0x40000
 	}, {
-		.name = "file system(spi)",
-		.size = 0x6a0000,
-		.offset = 0x00160000,
+		.name = "linux kernel (spi)",
+		.size =   0x150000,
+		.offset =  0x70000
+	}, {
+		.name = "jffs2 root file system (spi)",
+		.size =   0x640000,
+		.offset = 0x1c0000,
 	}
 };
 
@@ -340,7 +344,7 @@
 
 static struct plat_serial8250_port serial8250_platform_data [] = {
 	{
-		.membase = 0x20200000,
+		.membase = (void *)0x20200000,
 		.mapbase = 0x20200000,
 		.irq = IRQ_PF8,
 		.flags = UPF_BOOT_AUTOCONF | UART_CONFIG_TYPE,
@@ -348,7 +352,7 @@
 		.regshift = 1,
 		.uartclk = 66666667,
 	}, {
-		.membase = 0x20200010,
+		.membase = (void *)0x20200010,
 		.mapbase = 0x20200010,
 		.irq = IRQ_PF8,
 		.flags = UPF_BOOT_AUTOCONF | UART_CONFIG_TYPE,
diff --git a/arch/blackfin/mach-bf533/head.S b/arch/blackfin/mach-bf533/head.S
index 01b2b7e..619685b 100644
--- a/arch/blackfin/mach-bf533/head.S
+++ b/arch/blackfin/mach-bf533/head.S
@@ -78,6 +78,9 @@
 	r1 = PLL_BYPASS;                 /* Bypass the PLL?                 */
 	r1 = r1 << 8;                    /* Shift it over                   */
 	r0 = r1 | r0;                    /* add them all together           */
+#ifdef ANOMALY_05000265
+	r0 = BITSET(r0, 15);             /* Add 250 mV of hysteresis to SPORT input pins */
+#endif
 
 	p0.h = hi(PLL_CTL);
 	p0.l = lo(PLL_CTL);              /* Load the address                */
diff --git a/arch/blackfin/mach-bf533/include/mach/anomaly.h b/arch/blackfin/mach-bf533/include/mach/anomaly.h
index 8f7ea11..f544fc5 100644
--- a/arch/blackfin/mach-bf533/include/mach/anomaly.h
+++ b/arch/blackfin/mach-bf533/include/mach/anomaly.h
@@ -7,7 +7,7 @@
  */
 
 /* This file shoule be up to date with:
- *  - Revision C, 02/08/2008; ADSP-BF531/BF532/BF533 Blackfin Processor Anomaly List
+ *  - Revision D, 06/18/2008; ADSP-BF531/BF532/BF533 Blackfin Processor Anomaly List
  */
 
 #ifndef _MACH_ANOMALY_H_
@@ -97,11 +97,11 @@
 /* UART STB Bit Incorrectly Affects Receiver Setting */
 #define ANOMALY_05000231 (__SILICON_REVISION__ < 5)
 /* PPI_FS3 Is Not Driven in 2 or 3 Internal Frame Sync Transmit Modes */
-#define ANOMALY_05000233 (__SILICON_REVISION__ < 4)
+#define ANOMALY_05000233 (__SILICON_REVISION__ < 6)
 /* Incorrect Revision Number in DSPID Register */
 #define ANOMALY_05000234 (__SILICON_REVISION__ == 4)
 /* DF Bit in PLL_CTL Register Does Not Respond to Hardware Reset */
-#define ANOMALY_05000242 (__SILICON_REVISION__ < 4)
+#define ANOMALY_05000242 (__SILICON_REVISION__ < 5)
 /* If I-Cache Is On, CSYNC/SSYNC/IDLE Around Change of Control Causes Failures */
 #define ANOMALY_05000244 (__SILICON_REVISION__ < 5)
 /* Spurious Hardware Error from an Access in the Shadow of a Conditional Branch */
@@ -131,7 +131,7 @@
 /* CSYNC/SSYNC/IDLE Causes Infinite Stall in Penultimate Instruction in Hardware Loop */
 #define ANOMALY_05000264 (__SILICON_REVISION__ < 5)
 /* Sensitivity To Noise with Slow Input Edge Rates on External SPORT TX and RX Clocks */
-#define ANOMALY_05000265 (__SILICON_REVISION__ < 5)
+#define ANOMALY_05000265 (1)
 /* High I/O Activity Causes Output Voltage of Internal Voltage Regulator (Vddint) to Increase */
 #define ANOMALY_05000269 (__SILICON_REVISION__ < 5)
 /* High I/O Activity Causes Output Voltage of Internal Voltage Regulator (Vddint) to Decrease */
@@ -141,56 +141,59 @@
 /* Certain Data Cache Writethrough Modes Fail for Vddint <= 0.9V */
 #define ANOMALY_05000272 (1)
 /* Writes to Synchronous SDRAM Memory May Be Lost */
-#define ANOMALY_05000273 (1)
+#define ANOMALY_05000273 (__SILICON_REVISION__ < 6)
 /* Timing Requirements Change for External Frame Sync PPI Modes with Non-Zero PPI_DELAY */
 #define ANOMALY_05000276 (1)
 /* Writes to an I/O Data Register One SCLK Cycle after an Edge Is Detected May Clear Interrupt */
-#define ANOMALY_05000277 (1)
+#define ANOMALY_05000277 (__SILICON_REVISION__ < 6)
 /* Disabling Peripherals with DMA Running May Cause DMA System Instability */
-#define ANOMALY_05000278 (1)
+#define ANOMALY_05000278 (__SILICON_REVISION__ < 6)
 /* False Hardware Error Exception When ISR Context Is Not Restored */
-#define ANOMALY_05000281 (1)
+#define ANOMALY_05000281 (__SILICON_REVISION__ < 6)
 /* Memory DMA Corruption with 32-Bit Data and Traffic Control */
-#define ANOMALY_05000282 (1)
+#define ANOMALY_05000282 (__SILICON_REVISION__ < 6)
 /* System MMR Write Is Stalled Indefinitely When Killed in a Particular Stage */
-#define ANOMALY_05000283 (1)
+#define ANOMALY_05000283 (__SILICON_REVISION__ < 6)
 /* SPORTs May Receive Bad Data If FIFOs Fill Up */
-#define ANOMALY_05000288 (1)
+#define ANOMALY_05000288 (__SILICON_REVISION__ < 6)
 /* Memory-To-Memory DMA Source/Destination Descriptors Must Be in Same Memory Space */
-#define ANOMALY_05000301 (1)
+#define ANOMALY_05000301 (__SILICON_REVISION__ < 6)
 /* SSYNCs After Writes To DMA MMR Registers May Not Be Handled Correctly */
 #define ANOMALY_05000302 (__SILICON_REVISION__ < 5)
 /* New Feature: Additional Hysteresis on SPORT Input Pins (Not Available On Older Silicon) */
 #define ANOMALY_05000305 (__SILICON_REVISION__ < 5)
 /* New Feature: Additional PPI Frame Sync Sampling Options (Not Available On Older Silicon) */
 #define ANOMALY_05000306 (__SILICON_REVISION__ < 5)
+/* SCKELOW Bit Does Not Maintain State Through Hibernate */
+#define ANOMALY_05000307 (1)
 /* False Hardware Errors Caused by Fetches at the Boundary of Reserved Memory */
 #define ANOMALY_05000310 (1)
 /* Erroneous Flag (GPIO) Pin Operations under Specific Sequences */
-#define ANOMALY_05000311 (1)
+#define ANOMALY_05000311 (__SILICON_REVISION__ < 6)
 /* Errors When SSYNC, CSYNC, or Loads to LT, LB and LC Registers Are Interrupted */
-#define ANOMALY_05000312 (1)
+#define ANOMALY_05000312 (__SILICON_REVISION__ < 6)
 /* PPI Is Level-Sensitive on First Transfer */
-#define ANOMALY_05000313 (1)
+#define ANOMALY_05000313 (__SILICON_REVISION__ < 6)
 /* Killed System MMR Write Completes Erroneously On Next System MMR Access */
-#define ANOMALY_05000315 (1)
+#define ANOMALY_05000315 (__SILICON_REVISION__ < 6)
 /* Internal Voltage Regulator Values of 1.05V, 1.10V and 1.15V Not Allowed for LQFP Packages */
-#define ANOMALY_05000319 (ANOMALY_BF531 || ANOMALY_BF532)
+#define ANOMALY_05000319 ((ANOMALY_BF531 || ANOMALY_BF532) && __SILICON_REVISION__ < 6)
 /* Serial Port (SPORT) Multichannel Transmit Failure when Channel 0 Is Disabled */
-#define ANOMALY_05000357 (1)
+#define ANOMALY_05000357 (__SILICON_REVISION__ < 6)
 /* UART Break Signal Issues */
 #define ANOMALY_05000363 (__SILICON_REVISION__ < 5)
 /* PPI Underflow Error Goes Undetected in ITU-R 656 Mode */
 #define ANOMALY_05000366 (1)
 /* Possible RETS Register Corruption when Subroutine Is under 5 Cycles in Duration */
-#define ANOMALY_05000371 (1)
+#define ANOMALY_05000371 (__SILICON_REVISION__ < 6)
 /* PPI Does Not Start Properly In Specific Mode */
-#define ANOMALY_05000400 (__SILICON_REVISION__ >= 5)
+#define ANOMALY_05000400 (__SILICON_REVISION__ == 5)
 /* SSYNC Stalls Processor when Executed from Non-Cacheable Memory */
-#define ANOMALY_05000402 (__SILICON_REVISION__ >= 5)
+#define ANOMALY_05000402 (__SILICON_REVISION__ == 5)
 /* Level-Sensitive External GPIO Wakeups May Cause Indefinite Stall */
 #define ANOMALY_05000403 (1)
-
+/* Speculative Fetches Can Cause Undesired External FIFO Operations */
+#define ANOMALY_05000416 (1)
 
 /* These anomalies have been "phased" out of analog.com anomaly sheets and are
  * here to show running on older silicon just isn't feasible.
@@ -268,5 +271,7 @@
 /* Anomalies that don't exist on this proc */
 #define ANOMALY_05000266 (0)
 #define ANOMALY_05000323 (0)
+#define ANOMALY_05000353 (1)
+#define ANOMALY_05000386 (1)
 
 #endif
diff --git a/arch/blackfin/mach-bf533/include/mach/bf533.h b/arch/blackfin/mach-bf533/include/mach/bf533.h
index 12a4169..dfc8c1a 100644
--- a/arch/blackfin/mach-bf533/include/mach/bf533.h
+++ b/arch/blackfin/mach-bf533/include/mach/bf533.h
@@ -30,8 +30,6 @@
 #ifndef __MACH_BF533_H__
 #define __MACH_BF533_H__
 
-#define SUPPORTED_REVID 2
-
 #define OFFSET_(x) ((x) & 0x0000FFFF)
 
 /*some misc defines*/
@@ -143,19 +141,19 @@
 
 #ifdef CONFIG_BF533
 #define CPU "BF533"
-#define CPUID 0x027a5000
+#define CPUID 0x27a5
 #endif
 #ifdef CONFIG_BF532
 #define CPU "BF532"
-#define CPUID 0x0275A000
+#define CPUID 0x275A
 #endif
 #ifdef CONFIG_BF531
 #define CPU "BF531"
-#define CPUID 0x027a5000
+#define CPUID 0x27a5
 #endif
+
 #ifndef CPU
-#define	CPU "UNKNOWN"
-#define CPUID 0x0
+#error Unknown CPU type - This kernel doesn't seem to be configured properly
 #endif
 
 #endif				/* __MACH_BF533_H__  */
diff --git a/arch/blackfin/mach-bf533/include/mach/bfin_serial_5xx.h b/arch/blackfin/mach-bf533/include/mach/bfin_serial_5xx.h
index ebf592b..34ab0e4 100644
--- a/arch/blackfin/mach-bf533/include/mach/bfin_serial_5xx.h
+++ b/arch/blackfin/mach-bf533/include/mach/bfin_serial_5xx.h
@@ -69,6 +69,8 @@
 # endif
 #endif
 
+#define BFIN_UART_TX_FIFO_SIZE	2
+
 struct bfin_serial_port {
         struct uart_port        port;
         unsigned int            old_status;
@@ -83,7 +85,7 @@
 	unsigned int		rx_dma_channel;
 	struct work_struct	tx_dma_workqueue;
 #else
-# if ANOMALY_05000230
+# if ANOMALY_05000363
 	unsigned int anomaly_threshold;
 # endif
 #endif
@@ -111,7 +113,6 @@
 	bfin_write16(uart->port.membase + OFFSET_LSR, -1);
 }
 
-struct bfin_serial_port bfin_serial_ports[BFIN_UART_NR_PORTS];
 struct bfin_serial_res {
 	unsigned long	uart_base_addr;
 	int		uart_irq;
@@ -142,7 +143,6 @@
 
 #define DRIVER_NAME "bfin-uart"
 
-int nr_ports = BFIN_UART_NR_PORTS;
 static void bfin_serial_hw_init(struct bfin_serial_port *uart)
 {
 
diff --git a/arch/blackfin/mach-bf537/boards/stamp.c b/arch/blackfin/mach-bf537/boards/stamp.c
index 8482d22..dc5a308 100644
--- a/arch/blackfin/mach-bf537/boards/stamp.c
+++ b/arch/blackfin/mach-bf537/boards/stamp.c
@@ -51,7 +51,6 @@
 #include <asm/reboot.h>
 #include <asm/portmux.h>
 #include <asm/dpmc.h>
-#include <linux/spi/ad7877.h>
 
 /*
  * Name the Board for the /proc/cpuinfo
@@ -555,6 +554,7 @@
 #endif
 
 #if defined(CONFIG_TOUCHSCREEN_AD7877) || defined(CONFIG_TOUCHSCREEN_AD7877_MODULE)
+#include <linux/spi/ad7877.h>
 static struct bfin5xx_spi_chip spi_ad7877_chip_info = {
 	.enable_dma = 0,
 	.bits_per_word = 16,
@@ -575,6 +575,28 @@
 };
 #endif
 
+#if defined(CONFIG_TOUCHSCREEN_AD7879) || defined(CONFIG_TOUCHSCREEN_AD7879_MODULE)
+#include <linux/spi/ad7879.h>
+static struct bfin5xx_spi_chip spi_ad7879_chip_info = {
+	.enable_dma = 0,
+	.bits_per_word = 16,
+};
+
+static const struct ad7879_platform_data bfin_ad7879_ts_info = {
+	.model			= 7879,	/* Model = AD7879 */
+	.x_plate_ohms		= 620,	/* 620 Ohm from the touch datasheet */
+	.pressure_max		= 10000,
+	.pressure_min		= 0,
+	.first_conversion_delay = 3,	/* wait 512us before do a first conversion */
+	.acquisition_time 	= 1,	/* 4us acquisition time per sample */
+	.median			= 2,	/* do 8 measurements */
+	.averaging 		= 1,	/* take the average of 4 middle samples */
+	.pen_down_acc_interval 	= 255,	/* 9.4 ms */
+	.gpio_output		= 1,	/* configure AUX/VBAT/GPIO as GPIO output */
+	.gpio_default 		= 1,	/* During initialization set GPIO = HIGH */
+};
+#endif
+
 #if defined(CONFIG_SPI_SPIDEV) || defined(CONFIG_SPI_SPIDEV_MODULE)
 static struct bfin5xx_spi_chip spidev_chip_info = {
 	.enable_dma = 0,
@@ -582,6 +604,13 @@
 };
 #endif
 
+#if defined(CONFIG_FB_BFIN_LQ035Q1) || defined(CONFIG_FB_BFIN_LQ035Q1_MODULE)
+static struct bfin5xx_spi_chip lq035q1_spi_chip_info = {
+	.enable_dma	= 0,
+	.bits_per_word	= 8,
+};
+#endif
+
 #if defined(CONFIG_MTD_DATAFLASH) \
 	|| defined(CONFIG_MTD_DATAFLASH_MODULE)
 
@@ -721,6 +750,18 @@
 		.controller_data = &spi_ad7877_chip_info,
 	},
 #endif
+#if defined(CONFIG_TOUCHSCREEN_AD7879) || defined(CONFIG_TOUCHSCREEN_AD7879_MODULE)
+	{
+		.modalias = "ad7879",
+		.platform_data = &bfin_ad7879_ts_info,
+		.irq = IRQ_PF7,
+		.max_speed_hz = 5000000,     /* max spi clock (SCK) speed in HZ */
+		.bus_num = 0,
+		.chip_select = 1,
+		.controller_data = &spi_ad7879_chip_info,
+		.mode = SPI_CPHA | SPI_CPOL,
+	},
+#endif
 #if defined(CONFIG_SPI_SPIDEV) || defined(CONFIG_SPI_SPIDEV_MODULE)
 	{
 		.modalias = "spidev",
@@ -730,6 +771,16 @@
 		.controller_data = &spidev_chip_info,
 	},
 #endif
+#if defined(CONFIG_FB_BFIN_LQ035Q1) || defined(CONFIG_FB_BFIN_LQ035Q1_MODULE)
+	{
+		.modalias = "bfin-lq035q1-spi",
+		.max_speed_hz = 20000000,     /* max spi clock (SCK) speed in HZ */
+		.bus_num = 0,
+		.chip_select = 2,
+		.controller_data = &lq035q1_spi_chip_info,
+		.mode = SPI_CPHA | SPI_CPOL,
+	},
+#endif
 };
 
 #if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
@@ -777,6 +828,34 @@
 };
 #endif
 
+#if defined(CONFIG_FB_BFIN_LQ035Q1) || defined(CONFIG_FB_BFIN_LQ035Q1_MODULE)
+#include <asm/bfin-lq035q1.h>
+
+static struct bfin_lq035q1fb_disp_info bfin_lq035q1_data = {
+	.mode = 	LQ035_NORM | LQ035_RGB | LQ035_RL | LQ035_TB,
+	.use_bl = 	0,	/* let something else control the LCD Blacklight */
+	.gpio_bl =	GPIO_PF7,
+};
+
+static struct resource bfin_lq035q1_resources[] = {
+	{
+		.start = IRQ_PPI_ERROR,
+		.end = IRQ_PPI_ERROR,
+		.flags = IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device bfin_lq035q1_device = {
+	.name		= "bfin-lq035q1",
+	.id		= -1,
+	.num_resources 	= ARRAY_SIZE(bfin_lq035q1_resources),
+	.resource 	= bfin_lq035q1_resources,
+	.dev		= {
+		.platform_data = &bfin_lq035q1_data,
+	},
+};
+#endif
+
 #if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
 static struct resource bfin_uart_resources[] = {
 #ifdef CONFIG_SERIAL_BFIN_UART0
@@ -997,6 +1076,10 @@
 	&bfin_fb_device,
 #endif
 
+#if defined(CONFIG_FB_BFIN_LQ035Q1) || defined(CONFIG_FB_BFIN_LQ035Q1_MODULE)
+	&bfin_lq035q1_device,
+#endif
+
 #if defined(CONFIG_FB_BFIN_7393) || defined(CONFIG_FB_BFIN_7393_MODULE)
 	&bfin_fb_adv7393_device,
 #endif
diff --git a/arch/blackfin/mach-bf537/head.S b/arch/blackfin/mach-bf537/head.S
index 12eb5cc..559a7ee 100644
--- a/arch/blackfin/mach-bf537/head.S
+++ b/arch/blackfin/mach-bf537/head.S
@@ -87,6 +87,9 @@
 	r1 = PLL_BYPASS;                 /* Bypass the PLL?                 */
 	r1 = r1 << 8;                    /* Shift it over                   */
 	r0 = r1 | r0;                    /* add them all together           */
+#ifdef ANOMALY_05000265
+	r0 = BITSET(r0, 15);             /* Add 250 mV of hysteresis to SPORT input pins */
+#endif
 
 	p0.h = hi(PLL_CTL);
 	p0.l = lo(PLL_CTL);              /* Load the address                */
diff --git a/arch/blackfin/mach-bf537/include/mach/anomaly.h b/arch/blackfin/mach-bf537/include/mach/anomaly.h
index 8460ab9..c689924 100644
--- a/arch/blackfin/mach-bf537/include/mach/anomaly.h
+++ b/arch/blackfin/mach-bf537/include/mach/anomaly.h
@@ -158,6 +158,8 @@
 #define ANOMALY_05000266 (0)
 #define ANOMALY_05000311 (0)
 #define ANOMALY_05000323 (0)
+#define ANOMALY_05000353 (1)
 #define ANOMALY_05000363 (0)
+#define ANOMALY_05000386 (1)
 
 #endif
diff --git a/arch/blackfin/mach-bf537/include/mach/bf537.h b/arch/blackfin/mach-bf537/include/mach/bf537.h
index cfe2a22..24d5c9d 100644
--- a/arch/blackfin/mach-bf537/include/mach/bf537.h
+++ b/arch/blackfin/mach-bf537/include/mach/bf537.h
@@ -30,8 +30,6 @@
 #ifndef __MACH_BF537_H__
 #define __MACH_BF537_H__
 
-#define SUPPORTED_REVID 2
-
 /* Masks for generic ERROR IRQ demultiplexing used in int-priority-sc.c */
 
 #define SPI_ERR_MASK (TXCOL | RBSY | MODF | TXE)	/* SPI_STAT */
@@ -123,19 +121,19 @@
 
 #ifdef CONFIG_BF537
 #define CPU "BF537"
-#define CPUID 0x027c8000
+#define CPUID 0x27c8
 #endif
 #ifdef CONFIG_BF536
 #define CPU "BF536"
-#define CPUID 0x027c8000
+#define CPUID 0x27c8
 #endif
 #ifdef CONFIG_BF534
 #define CPU "BF534"
-#define CPUID 0x027c6000
+#define CPUID 0x27c6
 #endif
+
 #ifndef CPU
-#define	CPU "UNKNOWN"
-#define CPUID 0x0
+#error Unknown CPU type - This kernel doesn't seem to be configured properly
 #endif
 
 #endif				/* __MACH_BF537_H__  */
diff --git a/arch/blackfin/mach-bf537/include/mach/bfin_serial_5xx.h b/arch/blackfin/mach-bf537/include/mach/bfin_serial_5xx.h
index 1bf56ff..b3f87e1 100644
--- a/arch/blackfin/mach-bf537/include/mach/bfin_serial_5xx.h
+++ b/arch/blackfin/mach-bf537/include/mach/bfin_serial_5xx.h
@@ -78,6 +78,9 @@
 #  define CONFIG_UART1_RTS_PIN -1
 # endif
 #endif
+
+#define BFIN_UART_TX_FIFO_SIZE	2
+
 /*
  * The pin configuration is different from schematic
  */
@@ -119,7 +122,6 @@
 	bfin_write16(uart->port.membase + OFFSET_LSR, -1);
 }
 
-struct bfin_serial_port bfin_serial_ports[BFIN_UART_NR_PORTS];
 struct bfin_serial_res {
 	unsigned long	uart_base_addr;
 	int		uart_irq;
@@ -164,8 +166,6 @@
 #endif
 };
 
-int nr_ports = ARRAY_SIZE(bfin_serial_resource);
-
 #define DRIVER_NAME "bfin-uart"
 
 static void bfin_serial_hw_init(struct bfin_serial_port *uart)
diff --git a/arch/blackfin/mach-bf548/boards/cm_bf548.c b/arch/blackfin/mach-bf548/boards/cm_bf548.c
index ce934ee..24192aa 100644
--- a/arch/blackfin/mach-bf548/boards/cm_bf548.c
+++ b/arch/blackfin/mach-bf548/boards/cm_bf548.c
@@ -36,11 +36,8 @@
 #include <linux/spi/flash.h>
 #include <linux/irq.h>
 #include <linux/interrupt.h>
-#if defined(CONFIG_USB_MUSB_HDRC) || defined(CONFIG_USB_MUSB_HDRC_MODULE)
 #include <linux/usb/musb.h>
-#endif
 #include <asm/bfin5xx_spi.h>
-#include <asm/cplb.h>
 #include <asm/dma.h>
 #include <asm/gpio.h>
 #include <asm/nand.h>
@@ -175,6 +172,7 @@
 	{
 		.start = 0xFFC03100,
 		.end = 0xFFC031FF,
+		.flags = IORESOURCE_MEM,
 	},
 #endif
 };
@@ -268,6 +266,16 @@
 	},
 };
 
+static struct musb_hdrc_config musb_config = {
+	.multipoint	= 0,
+	.dyn_fifo	= 0,
+	.soft_con	= 1,
+	.dma		= 1,
+	.num_eps	= 7,
+	.dma_channels	= 7,
+	.gpio_vrsel	= GPIO_PH6,
+};
+
 static struct musb_hdrc_platform_data musb_plat = {
 #if defined(CONFIG_USB_MUSB_OTG)
 	.mode		= MUSB_OTG,
@@ -276,7 +284,7 @@
 #elif defined(CONFIG_USB_GADGET_MUSB_HDRC)
 	.mode		= MUSB_PERIPHERAL,
 #endif
-	.multipoint	= 0,
+	.config		= &musb_config,
 };
 
 static u64 musb_dmamask = ~(u32)0;
@@ -321,12 +329,12 @@
 	{
 		.name = "linux kernel(nand)",
 		.offset = 0,
-		.size = 4 * SIZE_1M,
+		.size = 4 * 1024 * 1024,
 	},
 	{
 		.name = "file system(nand)",
-		.offset = 4 * SIZE_1M,
-		.size = (256 - 4) * SIZE_1M,
+		.offset = 4 * 1024 * 1024,
+		.size = (256 - 4) * 1024 * 1024,
 	},
 };
 
diff --git a/arch/blackfin/mach-bf548/boards/ezkit.c b/arch/blackfin/mach-bf548/boards/ezkit.c
index 3935769..5288187 100644
--- a/arch/blackfin/mach-bf548/boards/ezkit.c
+++ b/arch/blackfin/mach-bf548/boards/ezkit.c
@@ -38,11 +38,8 @@
 #include <linux/irq.h>
 #include <linux/i2c.h>
 #include <linux/interrupt.h>
-#if defined(CONFIG_USB_MUSB_HDRC) || defined(CONFIG_USB_MUSB_HDRC_MODULE)
 #include <linux/usb/musb.h>
-#endif
 #include <asm/bfin5xx_spi.h>
-#include <asm/cplb.h>
 #include <asm/dma.h>
 #include <asm/gpio.h>
 #include <asm/nand.h>
@@ -186,6 +183,37 @@
 };
 #endif
 
+#if defined(CONFIG_JOYSTICK_BFIN_ROTARY) || defined(CONFIG_JOYSTICK_BFIN_ROTARY_MODULE)
+#include <asm/bfin_rotary.h>
+
+static struct bfin_rotary_platform_data bfin_rotary_data = {
+	/*.rotary_up_key     = KEY_UP,*/
+	/*.rotary_down_key   = KEY_DOWN,*/
+	.rotary_rel_code   = REL_WHEEL,
+	.rotary_button_key = KEY_ENTER,
+	.debounce	   = 10,	/* 0..17 */
+	.mode		   = ROT_QUAD_ENC | ROT_DEBE,
+};
+
+static struct resource bfin_rotary_resources[] = {
+	{
+		.start = IRQ_CNT,
+		.end = IRQ_CNT,
+		.flags = IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device bfin_rotary_device = {
+	.name		= "bfin-rotary",
+	.id		= -1,
+	.num_resources 	= ARRAY_SIZE(bfin_rotary_resources),
+	.resource 	= bfin_rotary_resources,
+	.dev		= {
+		.platform_data = &bfin_rotary_data,
+	},
+};
+#endif
+
 #if defined(CONFIG_RTC_DRV_BFIN) || defined(CONFIG_RTC_DRV_BFIN_MODULE)
 static struct platform_device rtc_device = {
 	.name = "rtc-bfin",
@@ -314,6 +342,16 @@
 	},
 };
 
+static struct musb_hdrc_config musb_config = {
+	.multipoint	= 0,
+	.dyn_fifo	= 0,
+	.soft_con	= 1,
+	.dma		= 1,
+	.num_eps	= 7,
+	.dma_channels	= 7,
+	.gpio_vrsel	= GPIO_PE7,
+};
+
 static struct musb_hdrc_platform_data musb_plat = {
 #if defined(CONFIG_USB_MUSB_OTG)
 	.mode		= MUSB_OTG,
@@ -322,7 +360,7 @@
 #elif defined(CONFIG_USB_GADGET_MUSB_HDRC)
 	.mode		= MUSB_PERIPHERAL,
 #endif
-	.multipoint	= 0,
+	.config		= &musb_config,
 };
 
 static u64 musb_dmamask = ~(u32)0;
@@ -367,7 +405,7 @@
 	{
 		.name = "linux kernel(nand)",
 		.offset = 0,
-		.size = 4 * SIZE_1M,
+		.size = 4 * 1024 * 1024,
 	},
 	{
 		.name = "file system(nand)",
@@ -424,7 +462,7 @@
 		.offset     = 0,
 	}, {
 		.name       = "linux kernel(nor)",
-		.size       = 0x1C0000,
+		.size       = 0x400000,
 		.offset     = MTDPART_OFS_APPEND,
 	}, {
 		.name       = "file system(nor)",
@@ -441,7 +479,7 @@
 
 static struct resource ezkit_flash_resource = {
 	.start = 0x20000000,
-	.end   = 0x20ffffff,
+	.end   = 0x21ffffff,
 	.flags = IORESOURCE_MEM,
 };
 
@@ -551,7 +589,7 @@
 {
 	.modalias		= "ad7877",
 	.platform_data		= &bfin_ad7877_ts_info,
-	.irq			= IRQ_PJ11,
+	.irq			= IRQ_PJ11,	/* newer boards (Rev 1.4+) use IRQ_PB4 */
 	.max_speed_hz		= 12500000,     /* max spi clock (SCK) speed in HZ */
 	.bus_num		= 0,
 	.chip_select  		= 2,
@@ -810,6 +848,10 @@
 	&bf54x_kpad_device,
 #endif
 
+#if defined(CONFIG_JOYSTICK_BFIN_ROTARY) || defined(CONFIG_JOYSTICK_BFIN_ROTARY_MODULE)
+	&bfin_rotary_device,
+#endif
+
 #if defined(CONFIG_I2C_BLACKFIN_TWI) || defined(CONFIG_I2C_BLACKFIN_TWI_MODULE)
 	&i2c_bfin_twi0_device,
 #if !defined(CONFIG_BF542)
diff --git a/arch/blackfin/mach-bf548/head.S b/arch/blackfin/mach-bf548/head.S
index 4d5cfea..051b05c 100644
--- a/arch/blackfin/mach-bf548/head.S
+++ b/arch/blackfin/mach-bf548/head.S
@@ -73,25 +73,19 @@
 	w[p0] = r0.l;
 	ssync;
 
-#if defined(CONFIG_BF54x)
+	/* enable self refresh via SRREQ */
 	P2.H = hi(EBIU_RSTCTL);
 	P2.L = lo(EBIU_RSTCTL);
 	R0 = [P2];
 	BITSET (R0, 3);
-#else
-	P2.H = hi(EBIU_SDGCTL);
-	P2.L = lo(EBIU_SDGCTL);
-	R0 = [P2];
-	BITSET (R0, 24);
-#endif
 	[P2] = R0;
 	SSYNC;
-#if defined(CONFIG_BF54x)
+
+	/* wait for SRACK bit to be set */
 .LSRR_MODE:
 	R0 = [P2];
 	CC = BITTST(R0, 4);
 	if !CC JUMP .LSRR_MODE;
-#endif
 
 	r0 = CONFIG_VCO_MULT & 63;       /* Load the VCO multiplier         */
 	r0 = r0 << 9;                    /* Shift it over,                  */
@@ -100,6 +94,9 @@
 	r1 = PLL_BYPASS;                 /* Bypass the PLL?                 */
 	r1 = r1 << 8;                    /* Shift it over                   */
 	r0 = r1 | r0;                    /* add them all together           */
+#ifdef ANOMALY_05000265
+	r0 = BITSET(r0, 15);             /* Add 250 mV of hysteresis to SPORT input pins */
+#endif
 
 	p0.h = hi(PLL_CTL);
 	p0.l = lo(PLL_CTL);              /* Load the address                */
@@ -123,7 +120,7 @@
 	w[p0] = r0.l;
 	ssync;
 
-#if defined(CONFIG_BF54x)
+	/* disable self refresh by clearing SRREQ */
 	P2.H = hi(EBIU_RSTCTL);
 	P2.L = lo(EBIU_RSTCTL);
 	R0 = [P2];
@@ -155,41 +152,6 @@
 	r0.h = hi(mem_DDRCTL2);
 	[p0] = r0;
 	ssync;
-#else
-	p0.l = lo(EBIU_SDRRC);
-	p0.h = hi(EBIU_SDRRC);
-	r0 = mem_SDRRC;
-	w[p0] = r0.l;
-	ssync;
-
-	p0.l = LO(EBIU_SDBCTL);
-	p0.h = HI(EBIU_SDBCTL);     /* SDRAM Memory Bank Control Register */
-	r0 = mem_SDBCTL;
-	w[p0] = r0.l;
-	ssync;
-
-	P2.H = hi(EBIU_SDGCTL);
-	P2.L = lo(EBIU_SDGCTL);
-	R0 = [P2];
-	BITCLR (R0, 24);
-	p0.h = hi(EBIU_SDSTAT);
-	p0.l = lo(EBIU_SDSTAT);
-	r2.l = w[p0];
-	cc = bittst(r2,3);
-	if !cc jump .Lskip;
-	NOP;
-	BITSET (R0, 23);
-.Lskip:
-	[P2] = R0;
-	SSYNC;
-
-	R0.L = lo(mem_SDGCTL);
-	R0.H = hi(mem_SDGCTL);
-	R1 = [p2];
-	R1 = R1 | R0;
-	[P2] = R1;
-	SSYNC;
-#endif
 
 	RTS;
 ENDPROC(_start_dma_code)
diff --git a/arch/blackfin/mach-bf548/include/mach/anomaly.h b/arch/blackfin/mach-bf548/include/mach/anomaly.h
index 3ad5965..816b092 100644
--- a/arch/blackfin/mach-bf548/include/mach/anomaly.h
+++ b/arch/blackfin/mach-bf548/include/mach/anomaly.h
@@ -2,18 +2,18 @@
  * File: include/asm-blackfin/mach-bf548/anomaly.h
  * Bugs: Enter bugs at http://blackfin.uclinux.org/
  *
- * Copyright (C) 2004-2007 Analog Devices Inc.
+ * Copyright (C) 2004-2008 Analog Devices Inc.
  * Licensed under the GPL-2 or later.
  */
 
 /* This file shoule be up to date with:
- *  - Revision E, 11/28/2007; ADSP-BF542/BF544/BF547/BF548/BF549 Blackfin Processor Anomaly List
+ *  - Revision G, 08/07/2008; ADSP-BF542/BF544/BF547/BF548/BF549 Blackfin Processor Anomaly List
  */
 
 #ifndef _MACH_ANOMALY_H_
 #define _MACH_ANOMALY_H_
 
-/* Multi-Issue Instruction with dsp32shiftimm in slot1 and P-reg Store in slot 2 Not Supported */
+/* Multi-Issue Instruction with dsp32shiftimm in slot1 and P-reg Store in slot2 Not Supported */
 #define ANOMALY_05000074 (1)
 /* DMA_RUN Bit Is Not Valid after a Peripheral Receive Channel DMA Stops */
 #define ANOMALY_05000119 (1)
@@ -36,14 +36,14 @@
 /* TWI Slave Boot Mode Is Not Functional */
 #define ANOMALY_05000324 (__SILICON_REVISION__ < 1)
 /* External FIFO Boot Mode Is Not Functional */
-#define ANOMALY_05000325 (__SILICON_REVISION__ < 1)
+#define ANOMALY_05000325 (__SILICON_REVISION__ < 2)
 /* Data Lost When Core and DMA Accesses Are Made to the USB FIFO Simultaneously */
 #define ANOMALY_05000327 (__SILICON_REVISION__ < 1)
 /* Incorrect Access of OTP_STATUS During otp_write() Function */
 #define ANOMALY_05000328 (__SILICON_REVISION__ < 1)
 /* Synchronous Burst Flash Boot Mode Is Not Functional */
 #define ANOMALY_05000329 (__SILICON_REVISION__ < 1)
-/* Host DMA Boot Mode Is Not Functional */
+/* Host DMA Boot Modes Are Not Functional */
 #define ANOMALY_05000330 (__SILICON_REVISION__ < 1)
 /* Inadequate Timing Margins on DDR DQS to DQ and DQM Skew */
 #define ANOMALY_05000334 (__SILICON_REVISION__ < 1)
@@ -61,26 +61,102 @@
 #define ANOMALY_05000344 (__SILICON_REVISION__ < 1)
 /* USB Calibration Value Is Not Intialized */
 #define ANOMALY_05000346 (__SILICON_REVISION__ < 1)
-/* Boot ROM Kernel Incorrectly Alters Reset Value of USB Register */
+/* USB Calibration Value to use */
+#define ANOMALY_05000346_value 0x5411
+/* Preboot Routine Incorrectly Alters Reset Value of USB Register */
 #define ANOMALY_05000347 (__SILICON_REVISION__ < 1)
 /* Data Lost when Core Reads SDH Data FIFO */
 #define ANOMALY_05000349 (__SILICON_REVISION__ < 1)
 /* PLL Status Register Is Inaccurate */
 #define ANOMALY_05000351 (__SILICON_REVISION__ < 1)
+/* bfrom_SysControl() Firmware Function Performs Improper System Reset */
+#define ANOMALY_05000353 (__SILICON_REVISION__ < 2)
+/* Regulator Programming Blocked when Hibernate Wakeup Source Remains Active */
+#define ANOMALY_05000355 (__SILICON_REVISION__ < 1)
+/* System Stalled During A Core Access To AMC While A Core Access To NFC FIFO Is Required */
+#define ANOMALY_05000356 (__SILICON_REVISION__ < 1)
 /* Serial Port (SPORT) Multichannel Transmit Failure when Channel 0 Is Disabled */
 #define ANOMALY_05000357 (1)
 /* External Memory Read Access Hangs Core With PLL Bypass */
 #define ANOMALY_05000360 (1)
 /* DMAs that Go Urgent during Tight Core Writes to External Memory Are Blocked */
 #define ANOMALY_05000365 (1)
+/* WURESET Bit In SYSCR Register Does Not Properly Indicate Hibernate Wake-Up */
+#define ANOMALY_05000367 (__SILICON_REVISION__ < 1)
 /* Addressing Conflict between Boot ROM and Asynchronous Memory */
 #define ANOMALY_05000369 (1)
+/* Default PLL MSEL and SSEL Settings Can Cause 400MHz Product To Violate Specifications */
+#define ANOMALY_05000370 (__SILICON_REVISION__ < 1)
 /* Possible RETS Register Corruption when Subroutine Is under 5 Cycles in Duration */
-#define ANOMALY_05000371 (1)
+#define ANOMALY_05000371 (__SILICON_REVISION__ < 2)
+/* USB DP/DM Data Pins May Lose State When Entering Hibernate */
+#define ANOMALY_05000372 (__SILICON_REVISION__ < 1)
 /* Mobile DDR Operation Not Functional */
 #define ANOMALY_05000377 (1)
 /* Security/Authentication Speedpath Causes Authentication To Fail To Initiate */
-#define ANOMALY_05000378 (1)
+#define ANOMALY_05000378 (__SILICON_REVISION__ < 2)
+/* 16-Bit NAND FLASH Boot Mode Is Not Functional */
+#define ANOMALY_05000379 (1)
+/* 8-Bit NAND Flash Boot Mode Not Functional */
+#define ANOMALY_05000382 (__SILICON_REVISION__ < 1)
+/* Some ATAPI Modes Are Not Functional */
+#define ANOMALY_05000383 (1)
+/* Boot from OTP Memory Not Functional */
+#define ANOMALY_05000385 (__SILICON_REVISION__ < 1)
+/* bfrom_SysControl() Firmware Routine Not Functional */
+#define ANOMALY_05000386 (__SILICON_REVISION__ < 1)
+/* Programmable Preboot Settings Not Functional */
+#define ANOMALY_05000387 (__SILICON_REVISION__ < 1)
+/* CRC32 Checksum Support Not Functional */
+#define ANOMALY_05000388 (__SILICON_REVISION__ < 1)
+/* Reset Vector Must Not Be in SDRAM Memory Space */
+#define ANOMALY_05000389 (__SILICON_REVISION__ < 1)
+/* Changed Meaning of BCODE Field in SYSCR Register */
+#define ANOMALY_05000390 (__SILICON_REVISION__ < 1)
+/* Repeated Boot from Page-Mode or Burst-Mode Flash Memory May Fail */
+#define ANOMALY_05000391 (__SILICON_REVISION__ < 1)
+/* pTempCurrent Not Present in ADI_BOOT_DATA Structure */
+#define ANOMALY_05000392 (__SILICON_REVISION__ < 1)
+/* Deprecated Value of dTempByteCount in ADI_BOOT_DATA Structure */
+#define ANOMALY_05000393 (__SILICON_REVISION__ < 1)
+/* Log Buffer Not Functional */
+#define ANOMALY_05000394 (__SILICON_REVISION__ < 1)
+/* Hook Routine Not Functional */
+#define ANOMALY_05000395 (__SILICON_REVISION__ < 1)
+/* Header Indirect Bit Not Functional */
+#define ANOMALY_05000396 (__SILICON_REVISION__ < 1)
+/* BK_ONES, BK_ZEROS, and BK_DATECODE Constants Not Functional */
+#define ANOMALY_05000397 (__SILICON_REVISION__ < 1)
+/* Lockbox SESR Disallows Certain User Interrupts */
+#define ANOMALY_05000404 (__SILICON_REVISION__ < 2)
+/* Lockbox SESR Firmware Does Not Save/Restore Full Context */
+#define ANOMALY_05000405 (1)
+/* Lockbox SESR Argument Checking Does Not Check L2 Memory Protection Range */
+#define ANOMALY_05000406 (__SILICON_REVISION__ < 2)
+/* Lockbox SESR Firmware Arguments Are Not Retained After First Initialization */
+#define ANOMALY_05000407 (__SILICON_REVISION__ < 2)
+/* Lockbox Firmware Memory Cleanup Routine Does not Clear Registers */
+#define ANOMALY_05000408 (1)
+/* Lockbox firmware leaves MDMA0 channel enabled */
+#define ANOMALY_05000409 (__SILICON_REVISION__ < 2)
+/* bfrom_SysControl() Firmware Function Cannot be Used to Enter Power Saving Modes */
+#define ANOMALY_05000411 (__SILICON_REVISION__ < 2)
+/* NAND Boot Mode Not Compatible With Some NAND Flash Devices */
+#define ANOMALY_05000413 (__SILICON_REVISION__ < 2)
+/* OTP_CHECK_FOR_PREV_WRITE Bit is Not Functional in bfrom_OtpWrite() API */
+#define ANOMALY_05000414 (__SILICON_REVISION__ < 2)
+/* Speculative Fetches Can Cause Undesired External FIFO Operations */
+#define ANOMALY_05000416 (1)
+/* Multichannel SPORT Channel Misalignment Under Specific Configuration */
+#define ANOMALY_05000425 (1)
+/* Speculative Fetches of Indirect-Pointer Instructions Can Cause Spurious Hardware Errors */
+#define ANOMALY_05000426 (1)
+/* CORE_EPPI_PRIO bit and SYS_EPPI_PRIO bit in the HMDMA1_CONTROL register are not functional */
+#define ANOMALY_05000427 (__SILICON_REVISION__ < 2)
+/* WB_EDGE Bit in NFC_IRQSTAT Incorrectly Behaves as a Buffer Status Bit Instead of an IRQ Status Bit */
+#define ANOMALY_05000429 (__SILICON_REVISION__ < 2)
+/* Software System Reset Corrupts PLL_LOCKCNT Register */
+#define ANOMALY_05000430 (__SILICON_REVISION__ >= 2)
 
 /* Anomalies that don't exist on this proc */
 #define ANOMALY_05000125 (0)
@@ -93,6 +169,7 @@
 #define ANOMALY_05000263 (0)
 #define ANOMALY_05000266 (0)
 #define ANOMALY_05000273 (0)
+#define ANOMALY_05000307 (0)
 #define ANOMALY_05000311 (0)
 #define ANOMALY_05000323 (0)
 #define ANOMALY_05000363 (0)
diff --git a/arch/blackfin/mach-bf548/include/mach/bf548.h b/arch/blackfin/mach-bf548/include/mach/bf548.h
index e748588..49f9b40 100644
--- a/arch/blackfin/mach-bf548/include/mach/bf548.h
+++ b/arch/blackfin/mach-bf548/include/mach/bf548.h
@@ -30,8 +30,6 @@
 #ifndef __MACH_BF548_H__
 #define __MACH_BF548_H__
 
-#define SUPPORTED_REVID 0
-
 #define OFFSET_(x) ((x) & 0x0000FFFF)
 
 /*some misc defines*/
@@ -108,20 +106,23 @@
 
 #if defined(CONFIG_BF542)
 # define CPU   "BF542"
-# define CPUID 0x027c8000
+# define CPUID 0x27de
 #elif defined(CONFIG_BF544)
-# define CPU "BF544"
-# define CPUID 0x027c8000
+# define CPU   "BF544"
+# define CPUID 0x27de
 #elif defined(CONFIG_BF547)
-# define CPU "BF547"
+# define CPU   "BF547"
+# define CPUID 0x27de
 #elif defined(CONFIG_BF548)
-# define CPU "BF548"
-# define CPUID 0x027c6000
+# define CPU   "BF548"
+# define CPUID 0x27de
 #elif defined(CONFIG_BF549)
-# define CPU "BF549"
-#else
-# define CPU "UNKNOWN"
-# define CPUID 0x0
+# define CPU   "BF549"
+# define CPUID 0x27de
+#endif
+
+#ifndef CPU
+#error Unknown CPU type - This kernel doesn't seem to be configured properly
 #endif
 
 #endif	/* __MACH_BF48_H__  */
diff --git a/arch/blackfin/mach-bf548/include/mach/bfin_serial_5xx.h b/arch/blackfin/mach-bf548/include/mach/bfin_serial_5xx.h
index 5e29446..e4cf35e 100644
--- a/arch/blackfin/mach-bf548/include/mach/bfin_serial_5xx.h
+++ b/arch/blackfin/mach-bf548/include/mach/bfin_serial_5xx.h
@@ -82,6 +82,9 @@
 #  define CONFIG_UART1_RTS_PIN -1
 # endif
 #endif
+
+#define BFIN_UART_TX_FIFO_SIZE	2
+
 /*
  * The pin configuration is different from schematic
  */
@@ -105,7 +108,6 @@
 #endif
 };
 
-struct bfin_serial_port bfin_serial_ports[BFIN_UART_NR_PORTS];
 struct bfin_serial_res {
 	unsigned long	uart_base_addr;
 	int		uart_irq;
@@ -170,8 +172,6 @@
 #endif
 };
 
-int nr_ports = ARRAY_SIZE(bfin_serial_resource);
-
 #define DRIVER_NAME "bfin-uart"
 
 static void bfin_serial_hw_init(struct bfin_serial_port *uart)
diff --git a/arch/blackfin/mach-bf548/include/mach/mem_map.h b/arch/blackfin/mach-bf548/include/mach/mem_map.h
index f99f47b..a222842 100644
--- a/arch/blackfin/mach-bf548/include/mach/mem_map.h
+++ b/arch/blackfin/mach-bf548/include/mach/mem_map.h
@@ -94,13 +94,13 @@
 #endif /*CONFIG_BFIN_DCACHE*/
 
 /* Level 2 Memory */
-#if !defined(CONFIG_BF542)
-# define L2_START          0xFEB00000
-# if defined(CONFIG_BF544)
-#  define L2_LENGTH        0x10000
-# else
-#  define L2_LENGTH        0x20000
-# endif
+#define L2_START            0xFEB00000
+#if defined(CONFIG_BF542)
+# define L2_LENGTH          0
+#elif defined(CONFIG_BF544)
+# define L2_LENGTH          0x10000
+#else
+# define L2_LENGTH          0x20000
 #endif
 
 /* Scratch Pad Memory */
diff --git a/arch/blackfin/mach-bf561/head.S b/arch/blackfin/mach-bf561/head.S
index 75ea6a9..0b28137 100644
--- a/arch/blackfin/mach-bf561/head.S
+++ b/arch/blackfin/mach-bf561/head.S
@@ -77,6 +77,9 @@
 	r1 = PLL_BYPASS;                 /* Bypass the PLL?                 */
 	r1 = r1 << 8;                    /* Shift it over                   */
 	r0 = r1 | r0;                    /* add them all together           */
+#ifdef ANOMALY_05000265
+	r0 = BITSET(r0, 15);             /* Add 250 mV of hysteresis to SPORT input pins */
+#endif
 
 	p0.h = hi(PLL_CTL);
 	p0.l = lo(PLL_CTL);              /* Load the address                */
diff --git a/arch/blackfin/mach-bf561/include/mach/anomaly.h b/arch/blackfin/mach-bf561/include/mach/anomaly.h
index 5c5d7d7..22990df 100644
--- a/arch/blackfin/mach-bf561/include/mach/anomaly.h
+++ b/arch/blackfin/mach-bf561/include/mach/anomaly.h
@@ -270,5 +270,7 @@
 #define ANOMALY_05000183 (0)
 #define ANOMALY_05000273 (0)
 #define ANOMALY_05000311 (0)
+#define ANOMALY_05000353 (1)
+#define ANOMALY_05000386 (1)
 
 #endif
diff --git a/arch/blackfin/mach-bf561/include/mach/bf561.h b/arch/blackfin/mach-bf561/include/mach/bf561.h
index 3ef9e5f..18b1b3a 100644
--- a/arch/blackfin/mach-bf561/include/mach/bf561.h
+++ b/arch/blackfin/mach-bf561/include/mach/bf561.h
@@ -30,8 +30,6 @@
 #ifndef __MACH_BF561_H__
 #define __MACH_BF561_H__
 
-#define SUPPORTED_REVID		0x3
-
 #define OFFSET_(x) ((x) & 0x0000FFFF)
 
 /*some misc defines*/
@@ -213,11 +211,11 @@
 
 #ifdef CONFIG_BF561
 #define CPU "BF561"
-#define CPUID 0x027bb000
+#define CPUID 0x27bb
 #endif
+
 #ifndef CPU
-#define CPU "UNKNOWN"
-#define CPUID 0x0
+#error Unknown CPU type - This kernel doesn't seem to be configured properly
 #endif
 
 #endif				/* __MACH_BF561_H__  */
diff --git a/arch/blackfin/mach-bf561/include/mach/bfin_serial_5xx.h b/arch/blackfin/mach-bf561/include/mach/bfin_serial_5xx.h
index 8aa0278..f532726 100644
--- a/arch/blackfin/mach-bf561/include/mach/bfin_serial_5xx.h
+++ b/arch/blackfin/mach-bf561/include/mach/bfin_serial_5xx.h
@@ -69,6 +69,8 @@
 # endif
 #endif
 
+#define BFIN_UART_TX_FIFO_SIZE	2
+
 struct bfin_serial_port {
         struct uart_port        port;
         unsigned int            old_status;
@@ -83,7 +85,7 @@
 	unsigned int		rx_dma_channel;
 	struct work_struct	tx_dma_workqueue;
 #else
-# if ANOMALY_05000230
+# if ANOMALY_05000363
 	unsigned int anomaly_threshold;
 # endif
 #endif
@@ -111,7 +113,6 @@
 	bfin_write16(uart->port.membase + OFFSET_LSR, -1);
 }
 
-struct bfin_serial_port bfin_serial_ports[BFIN_UART_NR_PORTS];
 struct bfin_serial_res {
 	unsigned long	uart_base_addr;
 	int		uart_irq;
@@ -142,7 +143,6 @@
 
 #define DRIVER_NAME "bfin-uart"
 
-int nr_ports = BFIN_UART_NR_PORTS;
 static void bfin_serial_hw_init(struct bfin_serial_port *uart)
 {
 
diff --git a/arch/blackfin/mach-bf561/include/mach/mem_map.h b/arch/blackfin/mach-bf561/include/mach/mem_map.h
index c26d848..f1d4c06 100644
--- a/arch/blackfin/mach-bf561/include/mach/mem_map.h
+++ b/arch/blackfin/mach-bf561/include/mach/mem_map.h
@@ -35,9 +35,16 @@
 /* Memory Map for ADSP-BF561 processors */
 
 #ifdef CONFIG_BF561
-#define L1_CODE_START     0xFFA00000
-#define L1_DATA_A_START     0xFF800000
-#define L1_DATA_B_START     0xFF900000
+#define COREA_L1_CODE_START       0xFFA00000
+#define COREA_L1_DATA_A_START     0xFF800000
+#define COREA_L1_DATA_B_START     0xFF900000
+#define COREB_L1_CODE_START       0xFF600000
+#define COREB_L1_DATA_A_START     0xFF400000
+#define COREB_L1_DATA_B_START     0xFF500000
+
+#define L1_CODE_START       COREA_L1_CODE_START
+#define L1_DATA_A_START     COREA_L1_DATA_A_START
+#define L1_DATA_B_START     COREA_L1_DATA_B_START
 
 #define L1_CODE_LENGTH      0x4000
 
@@ -72,7 +79,10 @@
 
 /* Scratch Pad Memory */
 
-#define L1_SCRATCH_START	0xFFB00000
+#define COREA_L1_SCRATCH_START	0xFFB00000
+#define COREB_L1_SCRATCH_START	0xFF700000
+
+#define L1_SCRATCH_START	COREA_L1_SCRATCH_START
 #define L1_SCRATCH_LENGTH	0x1000
 
 #endif				/* _MEM_MAP_533_H_ */
diff --git a/arch/blackfin/mach-common/entry.S b/arch/blackfin/mach-common/entry.S
index 847c172..c13fa8d 100644
--- a/arch/blackfin/mach-common/entry.S
+++ b/arch/blackfin/mach-common/entry.S
@@ -129,6 +129,18 @@
 #else
 	call __cplb_hdr;
 #endif
+
+#ifdef CONFIG_DEBUG_DOUBLEFAULT
+	/* While we were processing this, did we double fault? */
+	r7 = SEQSTAT;           /* reason code is in bit 5:0 */
+	r6.l = lo(SEQSTAT_EXCAUSE);
+	r6.h = hi(SEQSTAT_EXCAUSE);
+	r7 = r7 & r6;
+	r6 = 0x25;
+	CC = R7 == R6;
+	if CC JUMP _double_fault;
+#endif
+
 	DEBUG_HWTRACE_RESTORE(p5, r7)
 	RESTORE_ALL_SYS
 	SP = EX_SCRATCH_REG;
@@ -136,11 +148,8 @@
 ENDPROC(_ex_icplb_miss)
 
 ENTRY(_ex_syscall)
-	(R7:6,P5:4) = [sp++];
-	ASTAT = [sp++];
 	raise 15;		/* invoked by TRAP #0, for sys call */
-	sp = EX_SCRATCH_REG;
-	rtx
+	jump.s _bfin_return_from_exception;
 ENDPROC(_ex_syscall)
 
 ENTRY(_ex_soft_bp)
@@ -181,8 +190,8 @@
 	if cc jump .Lfind_priority_done;
 	jump.s .Lfind_priority_start;
 .Lfind_priority_done:
-	p4.l = _debugger_step;
-	p4.h = _debugger_step;
+	p4.l = _kgdb_single_step;
+	p4.h = _kgdb_single_step;
 	r6 = [p4];
 	cc = r6 == 0;
 	if cc jump .Ldo_single_step;
@@ -250,6 +259,29 @@
 	R7=LC1;
 	LC1=R7;
 #endif
+
+#ifdef CONFIG_DEBUG_DOUBLEFAULT
+	/* While we were processing the current exception,
+	 * did we cause another, and double fault?
+	 */
+	r7 = SEQSTAT;           /* reason code is in bit 5:0 */
+	r6.l = lo(SEQSTAT_EXCAUSE);
+	r6.h = hi(SEQSTAT_EXCAUSE);
+	r7 = r7 & r6;
+	r6 = 0x25;
+	CC = R7 == R6;
+	if CC JUMP _double_fault;
+
+	/* Did we cause a HW error? */
+	p5.l = lo(ILAT);
+	p5.h = hi(ILAT);
+	r6 = [p5];
+	r7 = 0x20;		/* Did I just cause anther HW error? */
+	r7 = r7 & r1;
+	CC = R7 == R6;
+	if CC JUMP _double_fault;
+#endif
+
 	(R7:6,P5:4) = [sp++];
 	ASTAT = [sp++];
 	sp = EX_SCRATCH_REG;
@@ -292,6 +324,14 @@
 	[p4] = p5;
 	csync;
 
+#ifndef CONFIG_DEBUG_DOUBLEFAULT
+	/*
+	 * Save these registers, as they are only valid in exception context
+	 *  (where we are now - as soon as we defer to IRQ5, they can change)
+	 * DCPLB_STATUS and ICPLB_STATUS are also only valid in EVT3,
+	 * but they are not very interesting, so don't save them
+	 */
+
 	p4.l = lo(DCPLB_FAULT_ADDR);
 	p4.h = hi(DCPLB_FAULT_ADDR);
 	r7 = [p4];
@@ -304,12 +344,11 @@
 	p5.l = _saved_icplb_fault_addr;
 	[p5] = r7;
 
-	p4.l = _excpt_saved_stuff;
-	p4.h = _excpt_saved_stuff;
-
 	r6 = retx;
+	p4.l = _saved_retx;
+	p4.h = _saved_retx;
 	[p4] = r6;
-
+#endif
 	r6 = SYSCFG;
 	[p4 + 4] = r6;
 	BITCLR(r6, 0);
@@ -327,59 +366,56 @@
 	r6 = 0x3f;
 	sti r6;
 
-	(R7:6,P5:4) = [sp++];
-	ASTAT = [sp++];
-	SP = EX_SCRATCH_REG;
 	raise 5;
-	rtx;
+	jump.s _bfin_return_from_exception;
 ENDPROC(_ex_trap_c)
 
 /* We just realized we got an exception, while we were processing a different
  * exception. This is a unrecoverable event, so crash
  */
 ENTRY(_double_fault)
-        /* Turn caches & protection off, to ensure we don't get any more
-         * double exceptions
-         */
+	/* Turn caches & protection off, to ensure we don't get any more
+	 * double exceptions
+	 */
 
-        P4.L = LO(IMEM_CONTROL);
-        P4.H = HI(IMEM_CONTROL);
+	P4.L = LO(IMEM_CONTROL);
+	P4.H = HI(IMEM_CONTROL);
 
-        R5 = [P4];              /* Control Register*/
-        BITCLR(R5,ENICPLB_P);
-        SSYNC;          /* SSYNC required before writing to IMEM_CONTROL. */
-        .align 8;
-        [P4] = R5;
-        SSYNC;
+	R5 = [P4];              /* Control Register*/
+	BITCLR(R5,ENICPLB_P);
+	SSYNC;          /* SSYNC required before writing to IMEM_CONTROL. */
+	.align 8;
+	[P4] = R5;
+	SSYNC;
 
-        P4.L = LO(DMEM_CONTROL);
-        P4.H = HI(DMEM_CONTROL);
-        R5 = [P4];
-        BITCLR(R5,ENDCPLB_P);
-        SSYNC;          /* SSYNC required before writing to DMEM_CONTROL. */
-        .align 8;
-        [P4] = R5;
-        SSYNC;
+	P4.L = LO(DMEM_CONTROL);
+	P4.H = HI(DMEM_CONTROL);
+	R5 = [P4];
+	BITCLR(R5,ENDCPLB_P);
+	SSYNC;          /* SSYNC required before writing to DMEM_CONTROL. */
+	.align 8;
+	[P4] = R5;
+	SSYNC;
 
-        /* Fix up the stack */
-        (R7:6,P5:4) = [sp++];
-        ASTAT = [sp++];
-        SP = EX_SCRATCH_REG;
+	/* Fix up the stack */
+	(R7:6,P5:4) = [sp++];
+	ASTAT = [sp++];
+	SP = EX_SCRATCH_REG;
 
-        /* We should be out of the exception stack, and back down into
-         * kernel or user space stack
-         */
-        SAVE_ALL_SYS
+	/* We should be out of the exception stack, and back down into
+	 * kernel or user space stack
+	 */
+	SAVE_ALL_SYS
 
 	/* The dumping functions expect the return address in the RETI
 	 * slot.  */
 	r6 = retx;
 	[sp + PT_PC] = r6;
 
-        r0 = sp;        /* stack frame pt_regs pointer argument ==> r0 */
-        SP += -12;
-        call _double_fault_c;
-        SP += 12;
+	r0 = sp;        /* stack frame pt_regs pointer argument ==> r0 */
+	SP += -12;
+	call _double_fault_c;
+	SP += 12;
 .L_double_fault_panic:
         JUMP .L_double_fault_panic
 
@@ -388,8 +424,8 @@
 ENTRY(_exception_to_level5)
 	SAVE_ALL_SYS
 
-	p4.l = _excpt_saved_stuff;
-	p4.h = _excpt_saved_stuff;
+	p4.l = _saved_retx;
+	p4.h = _saved_retx;
 	r6 = [p4];
 	[sp + PT_PC] = r6;
 
@@ -420,6 +456,17 @@
 	call _trap_c;
 	SP += 12;
 
+#ifdef CONFIG_DEBUG_DOUBLEFAULT
+	/* Grab ILAT */
+	p2.l = lo(ILAT);
+	p2.h = hi(ILAT);
+	r0 = [p2];
+	r1 = 0x20;  /* Did I just cause anther HW error? */
+	r0 = r0 & r1;
+	CC = R0 == R1;
+	if CC JUMP _double_fault;
+#endif
+
 	call _ret_from_exception;
 	RESTORE_ALL_SYS
 	rti;
@@ -436,7 +483,48 @@
 	/* Try to deal with syscalls quickly.  */
 	[--sp] = ASTAT;
 	[--sp] = (R7:6,P5:4);
+
+#if ANOMALY_05000283 || ANOMALY_05000315
+	cc = r7 == r7;
+	p5.h = HI(CHIPID);
+	p5.l = LO(CHIPID);
+	if cc jump 1f;
+	r7.l = W[p5];
+1:
+#endif
+
+#ifdef CONFIG_DEBUG_DOUBLEFAULT
+	/*
+	 * Save these registers, as they are only valid in exception context
+	 * (where we are now - as soon as we defer to IRQ5, they can change)
+	 * DCPLB_STATUS and ICPLB_STATUS are also only valid in EVT3,
+	 * but they are not very interesting, so don't save them
+	 */
+
+	p4.l = lo(DCPLB_FAULT_ADDR);
+	p4.h = hi(DCPLB_FAULT_ADDR);
+	r7 = [p4];
+	p5.h = _saved_dcplb_fault_addr;
+	p5.l = _saved_dcplb_fault_addr;
+	[p5] = r7;
+
+	r7 = [p4 + (ICPLB_FAULT_ADDR - DCPLB_FAULT_ADDR)];
+	p5.h = _saved_icplb_fault_addr;
+	p5.l = _saved_icplb_fault_addr;
+	[p5] = r7;
+
+	p4.l = _saved_retx;
+	p4.h = _saved_retx;
+	r6 = retx;
+	[p4] = r6;
+
 	r7 = SEQSTAT;		/* reason code is in bit 5:0 */
+	p4.l = _saved_seqstat;
+	p4.h = _saved_seqstat;
+	[p4] = r7;
+#else
+	r7 = SEQSTAT;           /* reason code is in bit 5:0 */
+#endif
 	r6.l = lo(SEQSTAT_EXCAUSE);
 	r6.h = hi(SEQSTAT_EXCAUSE);
 	r7 = r7 & r6;
@@ -616,6 +704,9 @@
 	rts;
 ENDPROC(_system_call)
 
+/* Do not mark as ENTRY() to avoid error in assembler ...
+ * this symbol need not be global anyways, so ...
+ */
 _sys_trace:
 	call _syscall_trace;
 
@@ -941,6 +1032,15 @@
 	SAVE_ALL_SYS
 	trace_buffer_stop(p0,r0);
 
+#if ANOMALY_05000283 || ANOMALY_05000315
+	cc = r5 == r5;
+	p4.h = HI(CHIPID);
+	p4.l = LO(CHIPID);
+	if cc jump 1f;
+	r5.l = W[p4];
+1:
+#endif
+
 	/* Turn caches off, to ensure we don't get double exceptions */
 
 	P4.L = LO(IMEM_CONTROL);
@@ -992,7 +1092,12 @@
 	 */
 	.long _ex_syscall       /* 0x00 - User Defined - Linux Syscall */
 	.long _ex_soft_bp       /* 0x01 - User Defined - Software breakpoint */
+#ifdef	CONFIG_KGDB
+	.long _ex_trap_c	/* 0x02 - User Defined - KGDB initial connection
+							 and break signal trap */
+#else
 	.long _ex_replaceable   /* 0x02 - User Defined */
+#endif
 	.long _ex_trap_c        /* 0x03 - User Defined - userspace stack overflow */
 	.long _ex_trap_c        /* 0x04 - User Defined - dump trace buffer */
 	.long _ex_replaceable   /* 0x05 - User Defined */
@@ -1432,15 +1537,7 @@
 	.rept NR_syscalls-(.-_sys_call_table)/4
 	.long _sys_ni_syscall
 	.endr
-
-	/*
-	 * Used to save the real RETX, IMASK and SYSCFG when temporarily
-	 * storing safe values across the transition from exception to IRQ5.
-	 */
-_excpt_saved_stuff:
-	.long 0;
-	.long 0;
-	.long 0;
+END(_sys_call_table)
 
 _exception_stack:
 	.rept 1024
diff --git a/arch/blackfin/mach-common/head.S b/arch/blackfin/mach-common/head.S
index 191b4e9..3069df5 100644
--- a/arch/blackfin/mach-common/head.S
+++ b/arch/blackfin/mach-common/head.S
@@ -68,6 +68,16 @@
 	M2 = r0;
 	M3 = r0;
 
+	/*
+	 * Clear ITEST_COMMAND and DTEST_COMMAND registers,
+	 * Leaving these as non-zero can confuse the emulator
+	 */
+	p0.L = LO(DTEST_COMMAND);
+	p0.H = HI(DTEST_COMMAND);
+	[p0] = R0;
+	[p0 + (ITEST_COMMAND - DTEST_COMMAND)] = R0;
+	CSYNC;
+
 	trace_buffer_init(p0,r0);
 	P0 = R1;
 	R0 = R1;
@@ -90,12 +100,46 @@
 	[p0] = R0;
 	SSYNC;
 
-	/* Save RETX, in case of doublefault */
-	p0.l = ___retx;
-	p0.h = ___retx;
+	/* in case of double faults, save a few things */
+	p0.l = _init_retx;
+	p0.h = _init_retx;
 	R0 = RETX;
 	[P0] = R0;
 
+#ifdef CONFIG_DEBUG_DOUBLEFAULT
+	/* Only save these if we are storing them,
+	 * This happens here, since L1 gets clobbered
+	 * below
+	 */
+	p0.l = _saved_retx;
+	p0.h = _saved_retx;
+	p1.l = _init_saved_retx;
+	p1.h = _init_saved_retx;
+	r0 = [p0];
+	[p1] = r0;
+
+	p0.l = _saved_dcplb_fault_addr;
+	p0.h = _saved_dcplb_fault_addr;
+	p1.l = _init_saved_dcplb_fault_addr;
+	p1.h = _init_saved_dcplb_fault_addr;
+	r0 = [p0];
+	[p1] = r0;
+
+	p0.l = _saved_icplb_fault_addr;
+	p0.h = _saved_icplb_fault_addr;
+	p1.l = _init_saved_icplb_fault_addr;
+	p1.h = _init_saved_icplb_fault_addr;
+	r0 = [p0];
+	[p1] = r0;
+
+	p0.l = _saved_seqstat;
+	p0.h = _saved_seqstat;
+	p1.l = _init_saved_seqstat;
+	p1.h = _init_saved_seqstat;
+	r0 = [p0];
+	[p1] = r0;
+#endif
+
 	/* Initialize stack pointer */
 	sp.l = lo(INITIAL_STACK);
 	sp.h = hi(INITIAL_STACK);
@@ -107,7 +151,7 @@
 #endif
 
 	/* Put The Code for PLL Programming and SDRAM Programming in L1 ISRAM */
-	call _bf53x_relocate_l1_mem;
+	call _bfin_relocate_l1_mem;
 #ifdef CONFIG_BFIN_KERNEL_CLOCK
 	call _start_dma_code;
 #endif
diff --git a/arch/blackfin/mach-common/interrupt.S b/arch/blackfin/mach-common/interrupt.S
index b27e59d..4a2ec7a 100644
--- a/arch/blackfin/mach-common/interrupt.S
+++ b/arch/blackfin/mach-common/interrupt.S
@@ -143,7 +143,7 @@
 	fp = 0;
 #endif
 
-#if ANOMALY_05000283
+#if ANOMALY_05000283 || ANOMALY_05000315
 	cc = r7 == r7;
 	p5.h = HI(CHIPID);
 	p5.l = LO(CHIPID);
@@ -179,7 +179,16 @@
 	call _trap_c;
 	SP += 12;
 
+#ifdef EBIU_ERRMST
+	/* make sure EBIU_ERRMST is clear */
+	p0.l = LO(EBIU_ERRMST);
+	p0.h = HI(EBIU_ERRMST);
+	r0.l = (CORE_ERROR | CORE_MERROR);
+	w[p0] = r0.l;
+#endif
+
 	call _ret_from_exception;
+
 .Lcommon_restore_all_sys:
 	RESTORE_ALL_SYS
 	rti;
diff --git a/arch/blackfin/mach-common/ints-priority.c b/arch/blackfin/mach-common/ints-priority.c
index 5fa53672..34e8a72 100644
--- a/arch/blackfin/mach-common/ints-priority.c
+++ b/arch/blackfin/mach-common/ints-priority.c
@@ -243,12 +243,14 @@
 #endif
 
 static struct irq_chip bfin_core_irqchip = {
+	.name = "CORE",
 	.ack = bfin_ack_noop,
 	.mask = bfin_core_mask_irq,
 	.unmask = bfin_core_unmask_irq,
 };
 
 static struct irq_chip bfin_internal_irqchip = {
+	.name = "INTN",
 	.ack = bfin_ack_noop,
 	.mask = bfin_internal_mask_irq,
 	.unmask = bfin_internal_unmask_irq,
@@ -278,6 +280,7 @@
 }
 
 static struct irq_chip bfin_generic_error_irqchip = {
+	.name = "ERROR",
 	.ack = bfin_ack_noop,
 	.mask_ack = bfin_generic_error_mask_irq,
 	.mask = bfin_generic_error_mask_irq,
@@ -361,6 +364,14 @@
 }
 #endif				/* BF537_GENERIC_ERROR_INT_DEMUX */
 
+static inline void bfin_set_irq_handler(unsigned irq, irq_flow_handler_t handle)
+{
+	struct irq_desc *desc = irq_desc + irq;
+	/* May not call generic set_irq_handler() due to spinlock
+	   recursion. */
+	desc->handle_irq = handle;
+}
+
 #if !defined(CONFIG_BF54x)
 
 static unsigned short gpio_enabled[gpio_bank(MAX_BLACKFIN_GPIOS)];
@@ -473,9 +484,9 @@
 	SSYNC();
 
 	if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING))
-		set_irq_handler(irq, handle_edge_irq);
+		bfin_set_irq_handler(irq, handle_edge_irq);
 	else
-		set_irq_handler(irq, handle_level_irq);
+		bfin_set_irq_handler(irq, handle_level_irq);
 
 	return 0;
 }
@@ -495,6 +506,7 @@
 #endif
 
 static struct irq_chip bfin_gpio_irqchip = {
+	.name = "GPIO",
 	.ack = bfin_gpio_ack_irq,
 	.mask = bfin_gpio_mask_irq,
 	.mask_ack = bfin_gpio_mask_ack_irq,
@@ -804,10 +816,10 @@
 
 	if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) {
 		pint[bank]->edge_set = pintbit;
-		set_irq_handler(irq, handle_edge_irq);
+		bfin_set_irq_handler(irq, handle_edge_irq);
 	} else {
 		pint[bank]->edge_clear = pintbit;
-		set_irq_handler(irq, handle_level_irq);
+		bfin_set_irq_handler(irq, handle_level_irq);
 	}
 
 	SSYNC();
@@ -884,6 +896,7 @@
 #endif
 
 static struct irq_chip bfin_gpio_irqchip = {
+	.name = "GPIO",
 	.ack = bfin_gpio_ack_irq,
 	.mask = bfin_gpio_mask_irq,
 	.mask_ack = bfin_gpio_mask_ack_irq,
@@ -1136,8 +1149,4 @@
 		vec = ivg->irqno;
 	}
 	asm_do_IRQ(vec, fp);
-
-#ifdef CONFIG_KGDB
-	kgdb_process_breakpoint();
-#endif
 }
diff --git a/arch/blackfin/mm/Makefile b/arch/blackfin/mm/Makefile
index 2a7202c..d489f89 100644
--- a/arch/blackfin/mm/Makefile
+++ b/arch/blackfin/mm/Makefile
@@ -2,4 +2,4 @@
 # arch/blackfin/mm/Makefile
 #
 
-obj-y := blackfin_sram.o init.o
+obj-y := sram-alloc.o isram-driver.o init.o
diff --git a/arch/blackfin/mm/blackfin_sram.c b/arch/blackfin/mm/blackfin_sram.c
deleted file mode 100644
index 4f5e887..0000000
--- a/arch/blackfin/mm/blackfin_sram.c
+++ /dev/null
@@ -1,806 +0,0 @@
-/*
- * File:         arch/blackfin/mm/blackfin_sram.c
- * Based on:
- * Author:
- *
- * Created:
- * Description:  SRAM driver for Blackfin ADSP-BF5xx
- *
- * Modified:
- *               Copyright 2004-2007 Analog Devices Inc.
- *
- * Bugs:         Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see the file COPYING, or write
- * to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/miscdevice.h>
-#include <linux/ioport.h>
-#include <linux/fcntl.h>
-#include <linux/init.h>
-#include <linux/poll.h>
-#include <linux/proc_fs.h>
-#include <linux/spinlock.h>
-#include <linux/rtc.h>
-#include <asm/blackfin.h>
-#include "blackfin_sram.h"
-
-static spinlock_t l1sram_lock, l1_data_sram_lock, l1_inst_sram_lock;
-static spinlock_t l2_sram_lock;
-
-/* the data structure for L1 scratchpad and DATA SRAM */
-struct sram_piece {
-	void *paddr;
-	int size;
-	pid_t pid;
-	struct sram_piece *next;
-};
-
-static struct sram_piece free_l1_ssram_head, used_l1_ssram_head;
-
-#if L1_DATA_A_LENGTH != 0
-static struct sram_piece free_l1_data_A_sram_head, used_l1_data_A_sram_head;
-#endif
-
-#if L1_DATA_B_LENGTH != 0
-static struct sram_piece free_l1_data_B_sram_head, used_l1_data_B_sram_head;
-#endif
-
-#if L1_CODE_LENGTH != 0
-static struct sram_piece free_l1_inst_sram_head, used_l1_inst_sram_head;
-#endif
-
-#if L2_LENGTH != 0
-static struct sram_piece free_l2_sram_head, used_l2_sram_head;
-#endif
-
-static struct kmem_cache *sram_piece_cache;
-
-/* L1 Scratchpad SRAM initialization function */
-static void __init l1sram_init(void)
-{
-	free_l1_ssram_head.next =
-		kmem_cache_alloc(sram_piece_cache, GFP_KERNEL);
-	if (!free_l1_ssram_head.next) {
-		printk(KERN_INFO"Fail to initialize Scratchpad data SRAM.\n");
-		return;
-	}
-
-	free_l1_ssram_head.next->paddr = (void *)L1_SCRATCH_START;
-	free_l1_ssram_head.next->size = L1_SCRATCH_LENGTH;
-	free_l1_ssram_head.next->pid = 0;
-	free_l1_ssram_head.next->next = NULL;
-
-	used_l1_ssram_head.next = NULL;
-
-	/* mutex initialize */
-	spin_lock_init(&l1sram_lock);
-
-	printk(KERN_INFO "Blackfin Scratchpad data SRAM: %d KB\n",
-	       L1_SCRATCH_LENGTH >> 10);
-}
-
-static void __init l1_data_sram_init(void)
-{
-#if L1_DATA_A_LENGTH != 0
-	free_l1_data_A_sram_head.next =
-		kmem_cache_alloc(sram_piece_cache, GFP_KERNEL);
-	if (!free_l1_data_A_sram_head.next) {
-		printk(KERN_INFO"Fail to initialize L1 Data A SRAM.\n");
-		return;
-	}
-
-	free_l1_data_A_sram_head.next->paddr =
-		(void *)L1_DATA_A_START + (_ebss_l1 - _sdata_l1);
-	free_l1_data_A_sram_head.next->size =
-		L1_DATA_A_LENGTH - (_ebss_l1 - _sdata_l1);
-	free_l1_data_A_sram_head.next->pid = 0;
-	free_l1_data_A_sram_head.next->next = NULL;
-
-	used_l1_data_A_sram_head.next = NULL;
-
-	printk(KERN_INFO "Blackfin L1 Data A SRAM: %d KB (%d KB free)\n",
-		L1_DATA_A_LENGTH >> 10,
-		free_l1_data_A_sram_head.next->size >> 10);
-#endif
-#if L1_DATA_B_LENGTH != 0
-	free_l1_data_B_sram_head.next =
-		kmem_cache_alloc(sram_piece_cache, GFP_KERNEL);
-	if (!free_l1_data_B_sram_head.next) {
-		printk(KERN_INFO"Fail to initialize L1 Data B SRAM.\n");
-		return;
-	}
-
-	free_l1_data_B_sram_head.next->paddr =
-		(void *)L1_DATA_B_START + (_ebss_b_l1 - _sdata_b_l1);
-	free_l1_data_B_sram_head.next->size =
-		L1_DATA_B_LENGTH - (_ebss_b_l1 - _sdata_b_l1);
-	free_l1_data_B_sram_head.next->pid = 0;
-	free_l1_data_B_sram_head.next->next = NULL;
-
-	used_l1_data_B_sram_head.next = NULL;
-
-	printk(KERN_INFO "Blackfin L1 Data B SRAM: %d KB (%d KB free)\n",
-		L1_DATA_B_LENGTH >> 10,
-		free_l1_data_B_sram_head.next->size >> 10);
-#endif
-
-	/* mutex initialize */
-	spin_lock_init(&l1_data_sram_lock);
-}
-
-static void __init l1_inst_sram_init(void)
-{
-#if L1_CODE_LENGTH != 0
-	free_l1_inst_sram_head.next =
-		kmem_cache_alloc(sram_piece_cache, GFP_KERNEL);
-	if (!free_l1_inst_sram_head.next) {
-		printk(KERN_INFO"Fail to initialize L1 Instruction SRAM.\n");
-		return;
-	}
-
-	free_l1_inst_sram_head.next->paddr =
-		(void *)L1_CODE_START + (_etext_l1 - _stext_l1);
-	free_l1_inst_sram_head.next->size =
-		L1_CODE_LENGTH - (_etext_l1 - _stext_l1);
-	free_l1_inst_sram_head.next->pid = 0;
-	free_l1_inst_sram_head.next->next = NULL;
-
-	used_l1_inst_sram_head.next = NULL;
-
-	printk(KERN_INFO "Blackfin L1 Instruction SRAM: %d KB (%d KB free)\n",
-		L1_CODE_LENGTH >> 10,
-		free_l1_inst_sram_head.next->size >> 10);
-#endif
-
-	/* mutex initialize */
-	spin_lock_init(&l1_inst_sram_lock);
-}
-
-static void __init l2_sram_init(void)
-{
-#if L2_LENGTH != 0
-	free_l2_sram_head.next =
-		kmem_cache_alloc(sram_piece_cache, GFP_KERNEL);
-	if (!free_l2_sram_head.next) {
-		printk(KERN_INFO"Fail to initialize L2 SRAM.\n");
-		return;
-	}
-
-	free_l2_sram_head.next->paddr = (void *)L2_START +
-		(_etext_l2 - _stext_l2) + (_edata_l2 - _sdata_l2);
-	free_l2_sram_head.next->size = L2_LENGTH -
-		(_etext_l2 - _stext_l2) + (_edata_l2 - _sdata_l2);
-	free_l2_sram_head.next->pid = 0;
-	free_l2_sram_head.next->next = NULL;
-
-	used_l2_sram_head.next = NULL;
-
-	printk(KERN_INFO "Blackfin L2 SRAM: %d KB (%d KB free)\n",
-		L2_LENGTH >> 10,
-		free_l2_sram_head.next->size >> 10);
-#endif
-
-	/* mutex initialize */
-	spin_lock_init(&l2_sram_lock);
-}
-void __init bfin_sram_init(void)
-{
-	sram_piece_cache = kmem_cache_create("sram_piece_cache",
-				sizeof(struct sram_piece),
-				0, SLAB_PANIC, NULL);
-
-	l1sram_init();
-	l1_data_sram_init();
-	l1_inst_sram_init();
-	l2_sram_init();
-}
-
-/* SRAM allocate function */
-static void *_sram_alloc(size_t size, struct sram_piece *pfree_head,
-		struct sram_piece *pused_head)
-{
-	struct sram_piece *pslot, *plast, *pavail;
-
-	if (size <= 0 || !pfree_head || !pused_head)
-		return NULL;
-
-	/* Align the size */
-	size = (size + 3) & ~3;
-
-	pslot = pfree_head->next;
-	plast = pfree_head;
-
-	/* search an available piece slot */
-	while (pslot != NULL && size > pslot->size) {
-		plast = pslot;
-		pslot = pslot->next;
-	}
-
-	if (!pslot)
-		return NULL;
-
-	if (pslot->size == size) {
-		plast->next = pslot->next;
-		pavail = pslot;
-	} else {
-		pavail = kmem_cache_alloc(sram_piece_cache, GFP_KERNEL);
-
-		if (!pavail)
-			return NULL;
-
-		pavail->paddr = pslot->paddr;
-		pavail->size = size;
-		pslot->paddr += size;
-		pslot->size -= size;
-	}
-
-	pavail->pid = current->pid;
-
-	pslot = pused_head->next;
-	plast = pused_head;
-
-	/* insert new piece into used piece list !!! */
-	while (pslot != NULL && pavail->paddr < pslot->paddr) {
-		plast = pslot;
-		pslot = pslot->next;
-	}
-
-	pavail->next = pslot;
-	plast->next = pavail;
-
-	return pavail->paddr;
-}
-
-/* Allocate the largest available block.  */
-static void *_sram_alloc_max(struct sram_piece *pfree_head,
-				struct sram_piece *pused_head,
-				unsigned long *psize)
-{
-	struct sram_piece *pslot, *pmax;
-
-	if (!pfree_head || !pused_head)
-		return NULL;
-
-	pmax = pslot = pfree_head->next;
-
-	/* search an available piece slot */
-	while (pslot != NULL) {
-		if (pslot->size > pmax->size)
-			pmax = pslot;
-		pslot = pslot->next;
-	}
-
-	if (!pmax)
-		return NULL;
-
-	*psize = pmax->size;
-
-	return _sram_alloc(*psize, pfree_head, pused_head);
-}
-
-/* SRAM free function */
-static int _sram_free(const void *addr,
-			struct sram_piece *pfree_head,
-			struct sram_piece *pused_head)
-{
-	struct sram_piece *pslot, *plast, *pavail;
-
-	if (!pfree_head || !pused_head)
-		return -1;
-
-	/* search the relevant memory slot */
-	pslot = pused_head->next;
-	plast = pused_head;
-
-	/* search an available piece slot */
-	while (pslot != NULL && pslot->paddr != addr) {
-		plast = pslot;
-		pslot = pslot->next;
-	}
-
-	if (!pslot)
-		return -1;
-
-	plast->next = pslot->next;
-	pavail = pslot;
-	pavail->pid = 0;
-
-	/* insert free pieces back to the free list */
-	pslot = pfree_head->next;
-	plast = pfree_head;
-
-	while (pslot != NULL && addr > pslot->paddr) {
-		plast = pslot;
-		pslot = pslot->next;
-	}
-
-	if (plast != pfree_head && plast->paddr + plast->size == pavail->paddr) {
-		plast->size += pavail->size;
-		kmem_cache_free(sram_piece_cache, pavail);
-	} else {
-		pavail->next = plast->next;
-		plast->next = pavail;
-		plast = pavail;
-	}
-
-	if (pslot && plast->paddr + plast->size == pslot->paddr) {
-		plast->size += pslot->size;
-		plast->next = pslot->next;
-		kmem_cache_free(sram_piece_cache, pslot);
-	}
-
-	return 0;
-}
-
-int sram_free(const void *addr)
-{
-	if (0) {}
-#if L1_CODE_LENGTH != 0
-	else if (addr >= (void *)L1_CODE_START
-		 && addr < (void *)(L1_CODE_START + L1_CODE_LENGTH))
-		return l1_inst_sram_free(addr);
-#endif
-#if L1_DATA_A_LENGTH != 0
-	else if (addr >= (void *)L1_DATA_A_START
-		 && addr < (void *)(L1_DATA_A_START + L1_DATA_A_LENGTH))
-		return l1_data_A_sram_free(addr);
-#endif
-#if L1_DATA_B_LENGTH != 0
-	else if (addr >= (void *)L1_DATA_B_START
-		 && addr < (void *)(L1_DATA_B_START + L1_DATA_B_LENGTH))
-		return l1_data_B_sram_free(addr);
-#endif
-#if L2_LENGTH != 0
-	else if (addr >= (void *)L2_START
-		 && addr < (void *)(L2_START + L2_LENGTH))
-		return l2_sram_free(addr);
-#endif
-	else
-		return -1;
-}
-EXPORT_SYMBOL(sram_free);
-
-void *l1_data_A_sram_alloc(size_t size)
-{
-	unsigned long flags;
-	void *addr = NULL;
-
-	/* add mutex operation */
-	spin_lock_irqsave(&l1_data_sram_lock, flags);
-
-#if L1_DATA_A_LENGTH != 0
-	addr = _sram_alloc(size, &free_l1_data_A_sram_head,
-			&used_l1_data_A_sram_head);
-#endif
-
-	/* add mutex operation */
-	spin_unlock_irqrestore(&l1_data_sram_lock, flags);
-
-	pr_debug("Allocated address in l1_data_A_sram_alloc is 0x%lx+0x%lx\n",
-		 (long unsigned int)addr, size);
-
-	return addr;
-}
-EXPORT_SYMBOL(l1_data_A_sram_alloc);
-
-int l1_data_A_sram_free(const void *addr)
-{
-	unsigned long flags;
-	int ret;
-
-	/* add mutex operation */
-	spin_lock_irqsave(&l1_data_sram_lock, flags);
-
-#if L1_DATA_A_LENGTH != 0
-	ret = _sram_free(addr, &free_l1_data_A_sram_head,
-			&used_l1_data_A_sram_head);
-#else
-	ret = -1;
-#endif
-
-	/* add mutex operation */
-	spin_unlock_irqrestore(&l1_data_sram_lock, flags);
-
-	return ret;
-}
-EXPORT_SYMBOL(l1_data_A_sram_free);
-
-void *l1_data_B_sram_alloc(size_t size)
-{
-#if L1_DATA_B_LENGTH != 0
-	unsigned long flags;
-	void *addr;
-
-	/* add mutex operation */
-	spin_lock_irqsave(&l1_data_sram_lock, flags);
-
-	addr = _sram_alloc(size, &free_l1_data_B_sram_head,
-			&used_l1_data_B_sram_head);
-
-	/* add mutex operation */
-	spin_unlock_irqrestore(&l1_data_sram_lock, flags);
-
-	pr_debug("Allocated address in l1_data_B_sram_alloc is 0x%lx+0x%lx\n",
-		 (long unsigned int)addr, size);
-
-	return addr;
-#else
-	return NULL;
-#endif
-}
-EXPORT_SYMBOL(l1_data_B_sram_alloc);
-
-int l1_data_B_sram_free(const void *addr)
-{
-#if L1_DATA_B_LENGTH != 0
-	unsigned long flags;
-	int ret;
-
-	/* add mutex operation */
-	spin_lock_irqsave(&l1_data_sram_lock, flags);
-
-	ret = _sram_free(addr, &free_l1_data_B_sram_head,
-			&used_l1_data_B_sram_head);
-
-	/* add mutex operation */
-	spin_unlock_irqrestore(&l1_data_sram_lock, flags);
-
-	return ret;
-#else
-	return -1;
-#endif
-}
-EXPORT_SYMBOL(l1_data_B_sram_free);
-
-void *l1_data_sram_alloc(size_t size)
-{
-	void *addr = l1_data_A_sram_alloc(size);
-
-	if (!addr)
-		addr = l1_data_B_sram_alloc(size);
-
-	return addr;
-}
-EXPORT_SYMBOL(l1_data_sram_alloc);
-
-void *l1_data_sram_zalloc(size_t size)
-{
-	void *addr = l1_data_sram_alloc(size);
-
-	if (addr)
-		memset(addr, 0x00, size);
-
-	return addr;
-}
-EXPORT_SYMBOL(l1_data_sram_zalloc);
-
-int l1_data_sram_free(const void *addr)
-{
-	int ret;
-	ret = l1_data_A_sram_free(addr);
-	if (ret == -1)
-		ret = l1_data_B_sram_free(addr);
-	return ret;
-}
-EXPORT_SYMBOL(l1_data_sram_free);
-
-void *l1_inst_sram_alloc(size_t size)
-{
-#if L1_CODE_LENGTH != 0
-	unsigned long flags;
-	void *addr;
-
-	/* add mutex operation */
-	spin_lock_irqsave(&l1_inst_sram_lock, flags);
-
-	addr = _sram_alloc(size, &free_l1_inst_sram_head,
-			&used_l1_inst_sram_head);
-
-	/* add mutex operation */
-	spin_unlock_irqrestore(&l1_inst_sram_lock, flags);
-
-	pr_debug("Allocated address in l1_inst_sram_alloc is 0x%lx+0x%lx\n",
-		 (long unsigned int)addr, size);
-
-	return addr;
-#else
-	return NULL;
-#endif
-}
-EXPORT_SYMBOL(l1_inst_sram_alloc);
-
-int l1_inst_sram_free(const void *addr)
-{
-#if L1_CODE_LENGTH != 0
-	unsigned long flags;
-	int ret;
-
-	/* add mutex operation */
-	spin_lock_irqsave(&l1_inst_sram_lock, flags);
-
-	ret = _sram_free(addr, &free_l1_inst_sram_head,
-			&used_l1_inst_sram_head);
-
-	/* add mutex operation */
-	spin_unlock_irqrestore(&l1_inst_sram_lock, flags);
-
-	return ret;
-#else
-	return -1;
-#endif
-}
-EXPORT_SYMBOL(l1_inst_sram_free);
-
-/* L1 Scratchpad memory allocate function */
-void *l1sram_alloc(size_t size)
-{
-	unsigned long flags;
-	void *addr;
-
-	/* add mutex operation */
-	spin_lock_irqsave(&l1sram_lock, flags);
-
-	addr = _sram_alloc(size, &free_l1_ssram_head,
-			&used_l1_ssram_head);
-
-	/* add mutex operation */
-	spin_unlock_irqrestore(&l1sram_lock, flags);
-
-	return addr;
-}
-
-/* L1 Scratchpad memory allocate function */
-void *l1sram_alloc_max(size_t *psize)
-{
-	unsigned long flags;
-	void *addr;
-
-	/* add mutex operation */
-	spin_lock_irqsave(&l1sram_lock, flags);
-
-	addr = _sram_alloc_max(&free_l1_ssram_head,
-			&used_l1_ssram_head, psize);
-
-	/* add mutex operation */
-	spin_unlock_irqrestore(&l1sram_lock, flags);
-
-	return addr;
-}
-
-/* L1 Scratchpad memory free function */
-int l1sram_free(const void *addr)
-{
-	unsigned long flags;
-	int ret;
-
-	/* add mutex operation */
-	spin_lock_irqsave(&l1sram_lock, flags);
-
-	ret = _sram_free(addr, &free_l1_ssram_head,
-			&used_l1_ssram_head);
-
-	/* add mutex operation */
-	spin_unlock_irqrestore(&l1sram_lock, flags);
-
-	return ret;
-}
-
-void *l2_sram_alloc(size_t size)
-{
-#if L2_LENGTH != 0
-	unsigned long flags;
-	void *addr;
-
-	/* add mutex operation */
-	spin_lock_irqsave(&l2_sram_lock, flags);
-
-	addr = _sram_alloc(size, &free_l2_sram_head,
-			&used_l2_sram_head);
-
-	/* add mutex operation */
-	spin_unlock_irqrestore(&l2_sram_lock, flags);
-
-	pr_debug("Allocated address in l2_sram_alloc is 0x%lx+0x%lx\n",
-		 (long unsigned int)addr, size);
-
-	return addr;
-#else
-	return NULL;
-#endif
-}
-EXPORT_SYMBOL(l2_sram_alloc);
-
-void *l2_sram_zalloc(size_t size)
-{
-	void *addr = l2_sram_alloc(size);
-
-	if (addr)
-		memset(addr, 0x00, size);
-
-	return addr;
-}
-EXPORT_SYMBOL(l2_sram_zalloc);
-
-int l2_sram_free(const void *addr)
-{
-#if L2_LENGTH != 0
-	unsigned long flags;
-	int ret;
-
-	/* add mutex operation */
-	spin_lock_irqsave(&l2_sram_lock, flags);
-
-	ret = _sram_free(addr, &free_l2_sram_head,
-			&used_l2_sram_head);
-
-	/* add mutex operation */
-	spin_unlock_irqrestore(&l2_sram_lock, flags);
-
-	return ret;
-#else
-	return -1;
-#endif
-}
-EXPORT_SYMBOL(l2_sram_free);
-
-int sram_free_with_lsl(const void *addr)
-{
-	struct sram_list_struct *lsl, **tmp;
-	struct mm_struct *mm = current->mm;
-
-	for (tmp = &mm->context.sram_list; *tmp; tmp = &(*tmp)->next)
-		if ((*tmp)->addr == addr)
-			goto found;
-	return -1;
-found:
-	lsl = *tmp;
-	sram_free(addr);
-	*tmp = lsl->next;
-	kfree(lsl);
-
-	return 0;
-}
-EXPORT_SYMBOL(sram_free_with_lsl);
-
-void *sram_alloc_with_lsl(size_t size, unsigned long flags)
-{
-	void *addr = NULL;
-	struct sram_list_struct *lsl = NULL;
-	struct mm_struct *mm = current->mm;
-
-	lsl = kzalloc(sizeof(struct sram_list_struct), GFP_KERNEL);
-	if (!lsl)
-		return NULL;
-
-	if (flags & L1_INST_SRAM)
-		addr = l1_inst_sram_alloc(size);
-
-	if (addr == NULL && (flags & L1_DATA_A_SRAM))
-		addr = l1_data_A_sram_alloc(size);
-
-	if (addr == NULL && (flags & L1_DATA_B_SRAM))
-		addr = l1_data_B_sram_alloc(size);
-
-	if (addr == NULL && (flags & L2_SRAM))
-		addr = l2_sram_alloc(size);
-
-	if (addr == NULL) {
-		kfree(lsl);
-		return NULL;
-	}
-	lsl->addr = addr;
-	lsl->length = size;
-	lsl->next = mm->context.sram_list;
-	mm->context.sram_list = lsl;
-	return addr;
-}
-EXPORT_SYMBOL(sram_alloc_with_lsl);
-
-#ifdef CONFIG_PROC_FS
-/* Once we get a real allocator, we'll throw all of this away.
- * Until then, we need some sort of visibility into the L1 alloc.
- */
-/* Need to keep line of output the same.  Currently, that is 44 bytes
- * (including newline).
- */
-static int _sram_proc_read(char *buf, int *len, int count, const char *desc,
-		struct sram_piece *pfree_head,
-		struct sram_piece *pused_head)
-{
-	struct sram_piece *pslot;
-
-	if (!pfree_head || !pused_head)
-		return -1;
-
-	*len += sprintf(&buf[*len], "--- SRAM %-14s Size   PID State     \n", desc);
-
-	/* search the relevant memory slot */
-	pslot = pused_head->next;
-
-	while (pslot != NULL) {
-		*len += sprintf(&buf[*len], "%p-%p %10i %5i %-10s\n",
-			pslot->paddr, pslot->paddr + pslot->size,
-			pslot->size, pslot->pid, "ALLOCATED");
-
-		pslot = pslot->next;
-	}
-
-	pslot = pfree_head->next;
-
-	while (pslot != NULL) {
-		*len += sprintf(&buf[*len], "%p-%p %10i %5i %-10s\n",
-			pslot->paddr, pslot->paddr + pslot->size,
-			pslot->size, pslot->pid, "FREE");
-
-		pslot = pslot->next;
-	}
-
-	return 0;
-}
-static int sram_proc_read(char *buf, char **start, off_t offset, int count,
-		int *eof, void *data)
-{
-	int len = 0;
-
-	if (_sram_proc_read(buf, &len, count, "Scratchpad",
-			&free_l1_ssram_head, &used_l1_ssram_head))
-		goto not_done;
-#if L1_DATA_A_LENGTH != 0
-	if (_sram_proc_read(buf, &len, count, "L1 Data A",
-			&free_l1_data_A_sram_head,
-			&used_l1_data_A_sram_head))
-		goto not_done;
-#endif
-#if L1_DATA_B_LENGTH != 0
-	if (_sram_proc_read(buf, &len, count, "L1 Data B",
-			&free_l1_data_B_sram_head,
-			&used_l1_data_B_sram_head))
-		goto not_done;
-#endif
-#if L1_CODE_LENGTH != 0
-	if (_sram_proc_read(buf, &len, count, "L1 Instruction",
-			&free_l1_inst_sram_head, &used_l1_inst_sram_head))
-		goto not_done;
-#endif
-#if L2_LENGTH != 0
-	if (_sram_proc_read(buf, &len, count, "L2",
-			&free_l2_sram_head, &used_l2_sram_head))
-		goto not_done;
-#endif
-
-	*eof = 1;
- not_done:
-	return len;
-}
-
-static int __init sram_proc_init(void)
-{
-	struct proc_dir_entry *ptr;
-	ptr = create_proc_entry("sram", S_IFREG | S_IRUGO, NULL);
-	if (!ptr) {
-		printk(KERN_WARNING "unable to create /proc/sram\n");
-		return -1;
-	}
-	ptr->owner = THIS_MODULE;
-	ptr->read_proc = sram_proc_read;
-	return 0;
-}
-late_initcall(sram_proc_init);
-#endif
diff --git a/arch/blackfin/mm/isram-driver.c b/arch/blackfin/mm/isram-driver.c
new file mode 100644
index 0000000..22913e7
--- /dev/null
+++ b/arch/blackfin/mm/isram-driver.c
@@ -0,0 +1,201 @@
+/*
+ * Description: Instruction SRAM accessor functions for the Blackfin
+ *
+ * Copyright 2008 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/spinlock.h>
+#include <linux/sched.h>
+
+#include <asm/blackfin.h>
+
+/*
+ * IMPORTANT WARNING ABOUT THESE FUNCTIONS
+ *
+ * The emulator will not function correctly if a write command is left in
+ * ITEST_COMMAND or DTEST_COMMAND AND access to cache memory is needed by
+ * the emulator. To avoid such problems, ensure that both ITEST_COMMAND
+ * and DTEST_COMMAND are zero when exiting these functions.
+ */
+
+
+/*
+ * On the Blackfin, L1 instruction sram (which operates at core speeds) can not
+ * be accessed by a normal core load, so we need to go through a few hoops to
+ * read/write it.
+ * To try to make it easier - we export a memcpy interface, where either src or
+ * dest can be in this special L1 memory area.
+ * The low level read/write functions should not be exposed to the rest of the
+ * kernel, since they operate on 64-bit data, and need specific address alignment
+ */
+
+static DEFINE_SPINLOCK(dtest_lock);
+
+/* Takes a void pointer */
+#define IADDR2DTEST(x) \
+	({ unsigned long __addr = (unsigned long)(x); \
+		(__addr & 0x47F8)        | /* address bits 14 & 10:3 */ \
+		(__addr & 0x0800) << 15  | /* address bit  11        */ \
+		(__addr  & 0x3000) << 4  | /* address bits 13:12     */ \
+		(__addr  & 0x8000) << 8  | /* address bit  15        */ \
+		(0x1000004);               /* isram access           */ \
+	})
+
+/* Takes a pointer, and returns the offset (in bits) which things should be shifted */
+#define ADDR2OFFSET(x) ((((unsigned long)(x)) & 0x7) * 8)
+
+/* Takes a pointer, determines if it is the last byte in the isram 64-bit data type */
+#define ADDR2LAST(x) ((((unsigned long)x) & 0x7) == 0x7)
+
+static void isram_write(const void *addr, uint64_t data)
+{
+	uint32_t cmd;
+	unsigned long flags;
+
+	if (addr >= (void *)(L1_CODE_START + L1_CODE_LENGTH))
+		return;
+
+	cmd = IADDR2DTEST(addr) | 1;             /* write */
+
+	/*
+	 * Writes to DTEST_DATA[0:1] need to be atomic with write to DTEST_COMMAND
+	 * While in exception context - atomicity is guaranteed or double fault
+	 */
+	spin_lock_irqsave(&dtest_lock, flags);
+
+	bfin_write_DTEST_DATA0(data & 0xFFFFFFFF);
+	bfin_write_DTEST_DATA1(data >> 32);
+
+	/* use the builtin, since interrupts are already turned off */
+	__builtin_bfin_csync();
+	bfin_write_DTEST_COMMAND(cmd);
+	__builtin_bfin_csync();
+
+	bfin_write_DTEST_COMMAND(0);
+	__builtin_bfin_csync();
+
+	spin_unlock_irqrestore(&dtest_lock, flags);
+}
+
+static uint64_t isram_read(const void *addr)
+{
+	uint32_t cmd;
+	unsigned long flags;
+	uint64_t ret;
+
+	if (addr > (void *)(L1_CODE_START + L1_CODE_LENGTH))
+		return 0;
+
+	cmd = IADDR2DTEST(addr) | 0;              /* read */
+
+	/*
+	 * Reads of DTEST_DATA[0:1] need to be atomic with write to DTEST_COMMAND
+	 * While in exception context - atomicity is guaranteed or double fault
+	 */
+	spin_lock_irqsave(&dtest_lock, flags);
+	/* use the builtin, since interrupts are already turned off */
+	__builtin_bfin_csync();
+	bfin_write_DTEST_COMMAND(cmd);
+	__builtin_bfin_csync();
+	ret = bfin_read_DTEST_DATA0() | ((uint64_t)bfin_read_DTEST_DATA1() << 32);
+
+	bfin_write_DTEST_COMMAND(0);
+	__builtin_bfin_csync();
+	spin_unlock_irqrestore(&dtest_lock, flags);
+
+	return ret;
+}
+
+static bool isram_check_addr(const void *addr, size_t n)
+{
+	if ((addr >= (void *)L1_CODE_START) &&
+	    (addr < (void *)(L1_CODE_START + L1_CODE_LENGTH))) {
+		if ((addr + n) >= (void *)(L1_CODE_START + L1_CODE_LENGTH)) {
+			show_stack(NULL, NULL);
+			printk(KERN_ERR "isram_memcpy: copy involving %p length "
+					"(%zu) too long\n", addr, n);
+		}
+		return true;
+	}
+	return false;
+}
+
+/*
+ * The isram_memcpy() function copies n bytes from memory area src to memory area dest.
+ * The isram_memcpy() function returns a pointer to dest.
+ * Either dest or src can be in L1 instruction sram.
+ */
+void *isram_memcpy(void *dest, const void *src, size_t n)
+{
+	uint64_t data_in = 0, data_out = 0;
+	size_t count;
+	bool dest_in_l1, src_in_l1, need_data, put_data;
+	unsigned char byte, *src_byte, *dest_byte;
+
+	src_byte = (unsigned char *)src;
+	dest_byte = (unsigned char *)dest;
+
+	dest_in_l1 = isram_check_addr(dest, n);
+	src_in_l1 = isram_check_addr(src, n);
+
+	need_data = true;
+	put_data = true;
+	for (count = 0; count < n; count++) {
+		if (src_in_l1) {
+			if (need_data) {
+				data_in = isram_read(src + count);
+				need_data = false;
+			}
+
+			if (ADDR2LAST(src + count))
+				need_data = true;
+
+			byte = (unsigned char)((data_in >> ADDR2OFFSET(src + count)) & 0xff);
+
+		} else {
+			/* src is in L2 or L3 - so just dereference*/
+			byte = src_byte[count];
+		}
+
+		if (dest_in_l1) {
+			if (put_data) {
+				data_out = isram_read(dest + count);
+				put_data = false;
+			}
+
+			data_out &= ~((uint64_t)0xff << ADDR2OFFSET(dest + count));
+			data_out |= ((uint64_t)byte << ADDR2OFFSET(dest + count));
+
+			if (ADDR2LAST(dest + count)) {
+				put_data = true;
+				isram_write(dest + count, data_out);
+			}
+		} else {
+			/* dest in L2 or L3 - so just dereference */
+			dest_byte[count] = byte;
+		}
+	}
+
+	/* make sure we dump the last byte if necessary */
+	if (dest_in_l1 && !put_data)
+		isram_write(dest + count, data_out);
+
+	return dest;
+}
+EXPORT_SYMBOL(isram_memcpy);
+
diff --git a/arch/blackfin/mm/sram-alloc.c b/arch/blackfin/mm/sram-alloc.c
new file mode 100644
index 0000000..0f1ca69
--- /dev/null
+++ b/arch/blackfin/mm/sram-alloc.c
@@ -0,0 +1,809 @@
+/*
+ * File:         arch/blackfin/mm/sram-alloc.c
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description:  SRAM allocator for Blackfin L1 and L2 memory
+ *
+ * Modified:
+ *               Copyright 2004-2008 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.org/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/miscdevice.h>
+#include <linux/ioport.h>
+#include <linux/fcntl.h>
+#include <linux/init.h>
+#include <linux/poll.h>
+#include <linux/proc_fs.h>
+#include <linux/spinlock.h>
+#include <linux/rtc.h>
+#include <asm/blackfin.h>
+#include "blackfin_sram.h"
+
+static spinlock_t l1sram_lock, l1_data_sram_lock, l1_inst_sram_lock;
+static spinlock_t l2_sram_lock;
+
+/* the data structure for L1 scratchpad and DATA SRAM */
+struct sram_piece {
+	void *paddr;
+	int size;
+	pid_t pid;
+	struct sram_piece *next;
+};
+
+static struct sram_piece free_l1_ssram_head, used_l1_ssram_head;
+
+#if L1_DATA_A_LENGTH != 0
+static struct sram_piece free_l1_data_A_sram_head, used_l1_data_A_sram_head;
+#endif
+
+#if L1_DATA_B_LENGTH != 0
+static struct sram_piece free_l1_data_B_sram_head, used_l1_data_B_sram_head;
+#endif
+
+#if L1_CODE_LENGTH != 0
+static struct sram_piece free_l1_inst_sram_head, used_l1_inst_sram_head;
+#endif
+
+#if L2_LENGTH != 0
+static struct sram_piece free_l2_sram_head, used_l2_sram_head;
+#endif
+
+static struct kmem_cache *sram_piece_cache;
+
+/* L1 Scratchpad SRAM initialization function */
+static void __init l1sram_init(void)
+{
+	free_l1_ssram_head.next =
+		kmem_cache_alloc(sram_piece_cache, GFP_KERNEL);
+	if (!free_l1_ssram_head.next) {
+		printk(KERN_INFO "Failed to initialize Scratchpad data SRAM\n");
+		return;
+	}
+
+	free_l1_ssram_head.next->paddr = (void *)L1_SCRATCH_START;
+	free_l1_ssram_head.next->size = L1_SCRATCH_LENGTH;
+	free_l1_ssram_head.next->pid = 0;
+	free_l1_ssram_head.next->next = NULL;
+
+	used_l1_ssram_head.next = NULL;
+
+	/* mutex initialize */
+	spin_lock_init(&l1sram_lock);
+
+	printk(KERN_INFO "Blackfin Scratchpad data SRAM: %d KB\n",
+	       L1_SCRATCH_LENGTH >> 10);
+}
+
+static void __init l1_data_sram_init(void)
+{
+#if L1_DATA_A_LENGTH != 0
+	free_l1_data_A_sram_head.next =
+		kmem_cache_alloc(sram_piece_cache, GFP_KERNEL);
+	if (!free_l1_data_A_sram_head.next) {
+		printk(KERN_INFO "Failed to initialize L1 Data A SRAM\n");
+		return;
+	}
+
+	free_l1_data_A_sram_head.next->paddr =
+		(void *)L1_DATA_A_START + (_ebss_l1 - _sdata_l1);
+	free_l1_data_A_sram_head.next->size =
+		L1_DATA_A_LENGTH - (_ebss_l1 - _sdata_l1);
+	free_l1_data_A_sram_head.next->pid = 0;
+	free_l1_data_A_sram_head.next->next = NULL;
+
+	used_l1_data_A_sram_head.next = NULL;
+
+	printk(KERN_INFO "Blackfin L1 Data A SRAM: %d KB (%d KB free)\n",
+		L1_DATA_A_LENGTH >> 10,
+		free_l1_data_A_sram_head.next->size >> 10);
+#endif
+#if L1_DATA_B_LENGTH != 0
+	free_l1_data_B_sram_head.next =
+		kmem_cache_alloc(sram_piece_cache, GFP_KERNEL);
+	if (!free_l1_data_B_sram_head.next) {
+		printk(KERN_INFO "Failed to initialize L1 Data B SRAM\n");
+		return;
+	}
+
+	free_l1_data_B_sram_head.next->paddr =
+		(void *)L1_DATA_B_START + (_ebss_b_l1 - _sdata_b_l1);
+	free_l1_data_B_sram_head.next->size =
+		L1_DATA_B_LENGTH - (_ebss_b_l1 - _sdata_b_l1);
+	free_l1_data_B_sram_head.next->pid = 0;
+	free_l1_data_B_sram_head.next->next = NULL;
+
+	used_l1_data_B_sram_head.next = NULL;
+
+	printk(KERN_INFO "Blackfin L1 Data B SRAM: %d KB (%d KB free)\n",
+		L1_DATA_B_LENGTH >> 10,
+		free_l1_data_B_sram_head.next->size >> 10);
+#endif
+
+	/* mutex initialize */
+	spin_lock_init(&l1_data_sram_lock);
+}
+
+static void __init l1_inst_sram_init(void)
+{
+#if L1_CODE_LENGTH != 0
+	free_l1_inst_sram_head.next =
+		kmem_cache_alloc(sram_piece_cache, GFP_KERNEL);
+	if (!free_l1_inst_sram_head.next) {
+		printk(KERN_INFO "Failed to initialize L1 Instruction SRAM\n");
+		return;
+	}
+
+	free_l1_inst_sram_head.next->paddr =
+		(void *)L1_CODE_START + (_etext_l1 - _stext_l1);
+	free_l1_inst_sram_head.next->size =
+		L1_CODE_LENGTH - (_etext_l1 - _stext_l1);
+	free_l1_inst_sram_head.next->pid = 0;
+	free_l1_inst_sram_head.next->next = NULL;
+
+	used_l1_inst_sram_head.next = NULL;
+
+	printk(KERN_INFO "Blackfin L1 Instruction SRAM: %d KB (%d KB free)\n",
+		L1_CODE_LENGTH >> 10,
+		free_l1_inst_sram_head.next->size >> 10);
+#endif
+
+	/* mutex initialize */
+	spin_lock_init(&l1_inst_sram_lock);
+}
+
+static void __init l2_sram_init(void)
+{
+#if L2_LENGTH != 0
+	free_l2_sram_head.next =
+		kmem_cache_alloc(sram_piece_cache, GFP_KERNEL);
+	if (!free_l2_sram_head.next) {
+		printk(KERN_INFO "Failed to initialize L2 SRAM\n");
+		return;
+	}
+
+	free_l2_sram_head.next->paddr = (void *)L2_START +
+		(_etext_l2 - _stext_l2) + (_edata_l2 - _sdata_l2);
+	free_l2_sram_head.next->size = L2_LENGTH -
+		(_etext_l2 - _stext_l2) + (_edata_l2 - _sdata_l2);
+	free_l2_sram_head.next->pid = 0;
+	free_l2_sram_head.next->next = NULL;
+
+	used_l2_sram_head.next = NULL;
+
+	printk(KERN_INFO "Blackfin L2 SRAM: %d KB (%d KB free)\n",
+		L2_LENGTH >> 10,
+		free_l2_sram_head.next->size >> 10);
+#endif
+
+	/* mutex initialize */
+	spin_lock_init(&l2_sram_lock);
+}
+void __init bfin_sram_init(void)
+{
+	sram_piece_cache = kmem_cache_create("sram_piece_cache",
+				sizeof(struct sram_piece),
+				0, SLAB_PANIC, NULL);
+
+	l1sram_init();
+	l1_data_sram_init();
+	l1_inst_sram_init();
+	l2_sram_init();
+}
+
+/* SRAM allocate function */
+static void *_sram_alloc(size_t size, struct sram_piece *pfree_head,
+		struct sram_piece *pused_head)
+{
+	struct sram_piece *pslot, *plast, *pavail;
+
+	if (size <= 0 || !pfree_head || !pused_head)
+		return NULL;
+
+	/* Align the size */
+	size = (size + 3) & ~3;
+
+	pslot = pfree_head->next;
+	plast = pfree_head;
+
+	/* search an available piece slot */
+	while (pslot != NULL && size > pslot->size) {
+		plast = pslot;
+		pslot = pslot->next;
+	}
+
+	if (!pslot)
+		return NULL;
+
+	if (pslot->size == size) {
+		plast->next = pslot->next;
+		pavail = pslot;
+	} else {
+		pavail = kmem_cache_alloc(sram_piece_cache, GFP_KERNEL);
+
+		if (!pavail)
+			return NULL;
+
+		pavail->paddr = pslot->paddr;
+		pavail->size = size;
+		pslot->paddr += size;
+		pslot->size -= size;
+	}
+
+	pavail->pid = current->pid;
+
+	pslot = pused_head->next;
+	plast = pused_head;
+
+	/* insert new piece into used piece list !!! */
+	while (pslot != NULL && pavail->paddr < pslot->paddr) {
+		plast = pslot;
+		pslot = pslot->next;
+	}
+
+	pavail->next = pslot;
+	plast->next = pavail;
+
+	return pavail->paddr;
+}
+
+/* Allocate the largest available block.  */
+static void *_sram_alloc_max(struct sram_piece *pfree_head,
+				struct sram_piece *pused_head,
+				unsigned long *psize)
+{
+	struct sram_piece *pslot, *pmax;
+
+	if (!pfree_head || !pused_head)
+		return NULL;
+
+	pmax = pslot = pfree_head->next;
+
+	/* search an available piece slot */
+	while (pslot != NULL) {
+		if (pslot->size > pmax->size)
+			pmax = pslot;
+		pslot = pslot->next;
+	}
+
+	if (!pmax)
+		return NULL;
+
+	*psize = pmax->size;
+
+	return _sram_alloc(*psize, pfree_head, pused_head);
+}
+
+/* SRAM free function */
+static int _sram_free(const void *addr,
+			struct sram_piece *pfree_head,
+			struct sram_piece *pused_head)
+{
+	struct sram_piece *pslot, *plast, *pavail;
+
+	if (!pfree_head || !pused_head)
+		return -1;
+
+	/* search the relevant memory slot */
+	pslot = pused_head->next;
+	plast = pused_head;
+
+	/* search an available piece slot */
+	while (pslot != NULL && pslot->paddr != addr) {
+		plast = pslot;
+		pslot = pslot->next;
+	}
+
+	if (!pslot)
+		return -1;
+
+	plast->next = pslot->next;
+	pavail = pslot;
+	pavail->pid = 0;
+
+	/* insert free pieces back to the free list */
+	pslot = pfree_head->next;
+	plast = pfree_head;
+
+	while (pslot != NULL && addr > pslot->paddr) {
+		plast = pslot;
+		pslot = pslot->next;
+	}
+
+	if (plast != pfree_head && plast->paddr + plast->size == pavail->paddr) {
+		plast->size += pavail->size;
+		kmem_cache_free(sram_piece_cache, pavail);
+	} else {
+		pavail->next = plast->next;
+		plast->next = pavail;
+		plast = pavail;
+	}
+
+	if (pslot && plast->paddr + plast->size == pslot->paddr) {
+		plast->size += pslot->size;
+		plast->next = pslot->next;
+		kmem_cache_free(sram_piece_cache, pslot);
+	}
+
+	return 0;
+}
+
+int sram_free(const void *addr)
+{
+
+#if L1_CODE_LENGTH != 0
+	if (addr >= (void *)L1_CODE_START
+		 && addr < (void *)(L1_CODE_START + L1_CODE_LENGTH))
+		return l1_inst_sram_free(addr);
+	else
+#endif
+#if L1_DATA_A_LENGTH != 0
+	if (addr >= (void *)L1_DATA_A_START
+		 && addr < (void *)(L1_DATA_A_START + L1_DATA_A_LENGTH))
+		return l1_data_A_sram_free(addr);
+	else
+#endif
+#if L1_DATA_B_LENGTH != 0
+	if (addr >= (void *)L1_DATA_B_START
+		 && addr < (void *)(L1_DATA_B_START + L1_DATA_B_LENGTH))
+		return l1_data_B_sram_free(addr);
+	else
+#endif
+#if L2_LENGTH != 0
+	if (addr >= (void *)L2_START
+		 && addr < (void *)(L2_START + L2_LENGTH))
+		return l2_sram_free(addr);
+	else
+#endif
+		return -1;
+}
+EXPORT_SYMBOL(sram_free);
+
+void *l1_data_A_sram_alloc(size_t size)
+{
+	unsigned long flags;
+	void *addr = NULL;
+
+	/* add mutex operation */
+	spin_lock_irqsave(&l1_data_sram_lock, flags);
+
+#if L1_DATA_A_LENGTH != 0
+	addr = _sram_alloc(size, &free_l1_data_A_sram_head,
+			&used_l1_data_A_sram_head);
+#endif
+
+	/* add mutex operation */
+	spin_unlock_irqrestore(&l1_data_sram_lock, flags);
+
+	pr_debug("Allocated address in l1_data_A_sram_alloc is 0x%lx+0x%lx\n",
+		 (long unsigned int)addr, size);
+
+	return addr;
+}
+EXPORT_SYMBOL(l1_data_A_sram_alloc);
+
+int l1_data_A_sram_free(const void *addr)
+{
+	unsigned long flags;
+	int ret;
+
+	/* add mutex operation */
+	spin_lock_irqsave(&l1_data_sram_lock, flags);
+
+#if L1_DATA_A_LENGTH != 0
+	ret = _sram_free(addr, &free_l1_data_A_sram_head,
+			&used_l1_data_A_sram_head);
+#else
+	ret = -1;
+#endif
+
+	/* add mutex operation */
+	spin_unlock_irqrestore(&l1_data_sram_lock, flags);
+
+	return ret;
+}
+EXPORT_SYMBOL(l1_data_A_sram_free);
+
+void *l1_data_B_sram_alloc(size_t size)
+{
+#if L1_DATA_B_LENGTH != 0
+	unsigned long flags;
+	void *addr;
+
+	/* add mutex operation */
+	spin_lock_irqsave(&l1_data_sram_lock, flags);
+
+	addr = _sram_alloc(size, &free_l1_data_B_sram_head,
+			&used_l1_data_B_sram_head);
+
+	/* add mutex operation */
+	spin_unlock_irqrestore(&l1_data_sram_lock, flags);
+
+	pr_debug("Allocated address in l1_data_B_sram_alloc is 0x%lx+0x%lx\n",
+		 (long unsigned int)addr, size);
+
+	return addr;
+#else
+	return NULL;
+#endif
+}
+EXPORT_SYMBOL(l1_data_B_sram_alloc);
+
+int l1_data_B_sram_free(const void *addr)
+{
+#if L1_DATA_B_LENGTH != 0
+	unsigned long flags;
+	int ret;
+
+	/* add mutex operation */
+	spin_lock_irqsave(&l1_data_sram_lock, flags);
+
+	ret = _sram_free(addr, &free_l1_data_B_sram_head,
+			&used_l1_data_B_sram_head);
+
+	/* add mutex operation */
+	spin_unlock_irqrestore(&l1_data_sram_lock, flags);
+
+	return ret;
+#else
+	return -1;
+#endif
+}
+EXPORT_SYMBOL(l1_data_B_sram_free);
+
+void *l1_data_sram_alloc(size_t size)
+{
+	void *addr = l1_data_A_sram_alloc(size);
+
+	if (!addr)
+		addr = l1_data_B_sram_alloc(size);
+
+	return addr;
+}
+EXPORT_SYMBOL(l1_data_sram_alloc);
+
+void *l1_data_sram_zalloc(size_t size)
+{
+	void *addr = l1_data_sram_alloc(size);
+
+	if (addr)
+		memset(addr, 0x00, size);
+
+	return addr;
+}
+EXPORT_SYMBOL(l1_data_sram_zalloc);
+
+int l1_data_sram_free(const void *addr)
+{
+	int ret;
+	ret = l1_data_A_sram_free(addr);
+	if (ret == -1)
+		ret = l1_data_B_sram_free(addr);
+	return ret;
+}
+EXPORT_SYMBOL(l1_data_sram_free);
+
+void *l1_inst_sram_alloc(size_t size)
+{
+#if L1_CODE_LENGTH != 0
+	unsigned long flags;
+	void *addr;
+
+	/* add mutex operation */
+	spin_lock_irqsave(&l1_inst_sram_lock, flags);
+
+	addr = _sram_alloc(size, &free_l1_inst_sram_head,
+			&used_l1_inst_sram_head);
+
+	/* add mutex operation */
+	spin_unlock_irqrestore(&l1_inst_sram_lock, flags);
+
+	pr_debug("Allocated address in l1_inst_sram_alloc is 0x%lx+0x%lx\n",
+		 (long unsigned int)addr, size);
+
+	return addr;
+#else
+	return NULL;
+#endif
+}
+EXPORT_SYMBOL(l1_inst_sram_alloc);
+
+int l1_inst_sram_free(const void *addr)
+{
+#if L1_CODE_LENGTH != 0
+	unsigned long flags;
+	int ret;
+
+	/* add mutex operation */
+	spin_lock_irqsave(&l1_inst_sram_lock, flags);
+
+	ret = _sram_free(addr, &free_l1_inst_sram_head,
+			&used_l1_inst_sram_head);
+
+	/* add mutex operation */
+	spin_unlock_irqrestore(&l1_inst_sram_lock, flags);
+
+	return ret;
+#else
+	return -1;
+#endif
+}
+EXPORT_SYMBOL(l1_inst_sram_free);
+
+/* L1 Scratchpad memory allocate function */
+void *l1sram_alloc(size_t size)
+{
+	unsigned long flags;
+	void *addr;
+
+	/* add mutex operation */
+	spin_lock_irqsave(&l1sram_lock, flags);
+
+	addr = _sram_alloc(size, &free_l1_ssram_head,
+			&used_l1_ssram_head);
+
+	/* add mutex operation */
+	spin_unlock_irqrestore(&l1sram_lock, flags);
+
+	return addr;
+}
+
+/* L1 Scratchpad memory allocate function */
+void *l1sram_alloc_max(size_t *psize)
+{
+	unsigned long flags;
+	void *addr;
+
+	/* add mutex operation */
+	spin_lock_irqsave(&l1sram_lock, flags);
+
+	addr = _sram_alloc_max(&free_l1_ssram_head,
+			&used_l1_ssram_head, psize);
+
+	/* add mutex operation */
+	spin_unlock_irqrestore(&l1sram_lock, flags);
+
+	return addr;
+}
+
+/* L1 Scratchpad memory free function */
+int l1sram_free(const void *addr)
+{
+	unsigned long flags;
+	int ret;
+
+	/* add mutex operation */
+	spin_lock_irqsave(&l1sram_lock, flags);
+
+	ret = _sram_free(addr, &free_l1_ssram_head,
+			&used_l1_ssram_head);
+
+	/* add mutex operation */
+	spin_unlock_irqrestore(&l1sram_lock, flags);
+
+	return ret;
+}
+
+void *l2_sram_alloc(size_t size)
+{
+#if L2_LENGTH != 0
+	unsigned long flags;
+	void *addr;
+
+	/* add mutex operation */
+	spin_lock_irqsave(&l2_sram_lock, flags);
+
+	addr = _sram_alloc(size, &free_l2_sram_head,
+			&used_l2_sram_head);
+
+	/* add mutex operation */
+	spin_unlock_irqrestore(&l2_sram_lock, flags);
+
+	pr_debug("Allocated address in l2_sram_alloc is 0x%lx+0x%lx\n",
+		 (long unsigned int)addr, size);
+
+	return addr;
+#else
+	return NULL;
+#endif
+}
+EXPORT_SYMBOL(l2_sram_alloc);
+
+void *l2_sram_zalloc(size_t size)
+{
+	void *addr = l2_sram_alloc(size);
+
+	if (addr)
+		memset(addr, 0x00, size);
+
+	return addr;
+}
+EXPORT_SYMBOL(l2_sram_zalloc);
+
+int l2_sram_free(const void *addr)
+{
+#if L2_LENGTH != 0
+	unsigned long flags;
+	int ret;
+
+	/* add mutex operation */
+	spin_lock_irqsave(&l2_sram_lock, flags);
+
+	ret = _sram_free(addr, &free_l2_sram_head,
+			&used_l2_sram_head);
+
+	/* add mutex operation */
+	spin_unlock_irqrestore(&l2_sram_lock, flags);
+
+	return ret;
+#else
+	return -1;
+#endif
+}
+EXPORT_SYMBOL(l2_sram_free);
+
+int sram_free_with_lsl(const void *addr)
+{
+	struct sram_list_struct *lsl, **tmp;
+	struct mm_struct *mm = current->mm;
+
+	for (tmp = &mm->context.sram_list; *tmp; tmp = &(*tmp)->next)
+		if ((*tmp)->addr == addr)
+			goto found;
+	return -1;
+found:
+	lsl = *tmp;
+	sram_free(addr);
+	*tmp = lsl->next;
+	kfree(lsl);
+
+	return 0;
+}
+EXPORT_SYMBOL(sram_free_with_lsl);
+
+void *sram_alloc_with_lsl(size_t size, unsigned long flags)
+{
+	void *addr = NULL;
+	struct sram_list_struct *lsl = NULL;
+	struct mm_struct *mm = current->mm;
+
+	lsl = kzalloc(sizeof(struct sram_list_struct), GFP_KERNEL);
+	if (!lsl)
+		return NULL;
+
+	if (flags & L1_INST_SRAM)
+		addr = l1_inst_sram_alloc(size);
+
+	if (addr == NULL && (flags & L1_DATA_A_SRAM))
+		addr = l1_data_A_sram_alloc(size);
+
+	if (addr == NULL && (flags & L1_DATA_B_SRAM))
+		addr = l1_data_B_sram_alloc(size);
+
+	if (addr == NULL && (flags & L2_SRAM))
+		addr = l2_sram_alloc(size);
+
+	if (addr == NULL) {
+		kfree(lsl);
+		return NULL;
+	}
+	lsl->addr = addr;
+	lsl->length = size;
+	lsl->next = mm->context.sram_list;
+	mm->context.sram_list = lsl;
+	return addr;
+}
+EXPORT_SYMBOL(sram_alloc_with_lsl);
+
+#ifdef CONFIG_PROC_FS
+/* Once we get a real allocator, we'll throw all of this away.
+ * Until then, we need some sort of visibility into the L1 alloc.
+ */
+/* Need to keep line of output the same.  Currently, that is 44 bytes
+ * (including newline).
+ */
+static int _sram_proc_read(char *buf, int *len, int count, const char *desc,
+		struct sram_piece *pfree_head,
+		struct sram_piece *pused_head)
+{
+	struct sram_piece *pslot;
+
+	if (!pfree_head || !pused_head)
+		return -1;
+
+	*len += sprintf(&buf[*len], "--- SRAM %-14s Size   PID State     \n", desc);
+
+	/* search the relevant memory slot */
+	pslot = pused_head->next;
+
+	while (pslot != NULL) {
+		*len += sprintf(&buf[*len], "%p-%p %10i %5i %-10s\n",
+			pslot->paddr, pslot->paddr + pslot->size,
+			pslot->size, pslot->pid, "ALLOCATED");
+
+		pslot = pslot->next;
+	}
+
+	pslot = pfree_head->next;
+
+	while (pslot != NULL) {
+		*len += sprintf(&buf[*len], "%p-%p %10i %5i %-10s\n",
+			pslot->paddr, pslot->paddr + pslot->size,
+			pslot->size, pslot->pid, "FREE");
+
+		pslot = pslot->next;
+	}
+
+	return 0;
+}
+static int sram_proc_read(char *buf, char **start, off_t offset, int count,
+		int *eof, void *data)
+{
+	int len = 0;
+
+	if (_sram_proc_read(buf, &len, count, "Scratchpad",
+			&free_l1_ssram_head, &used_l1_ssram_head))
+		goto not_done;
+#if L1_DATA_A_LENGTH != 0
+	if (_sram_proc_read(buf, &len, count, "L1 Data A",
+			&free_l1_data_A_sram_head,
+			&used_l1_data_A_sram_head))
+		goto not_done;
+#endif
+#if L1_DATA_B_LENGTH != 0
+	if (_sram_proc_read(buf, &len, count, "L1 Data B",
+			&free_l1_data_B_sram_head,
+			&used_l1_data_B_sram_head))
+		goto not_done;
+#endif
+#if L1_CODE_LENGTH != 0
+	if (_sram_proc_read(buf, &len, count, "L1 Instruction",
+			&free_l1_inst_sram_head, &used_l1_inst_sram_head))
+		goto not_done;
+#endif
+#if L2_LENGTH != 0
+	if (_sram_proc_read(buf, &len, count, "L2",
+			&free_l2_sram_head, &used_l2_sram_head))
+		goto not_done;
+#endif
+
+	*eof = 1;
+ not_done:
+	return len;
+}
+
+static int __init sram_proc_init(void)
+{
+	struct proc_dir_entry *ptr;
+	ptr = create_proc_entry("sram", S_IFREG | S_IRUGO, NULL);
+	if (!ptr) {
+		printk(KERN_WARNING "unable to create /proc/sram\n");
+		return -1;
+	}
+	ptr->owner = THIS_MODULE;
+	ptr->read_proc = sram_proc_read;
+	return 0;
+}
+late_initcall(sram_proc_init);
+#endif
diff --git a/arch/cris/arch-v10/boot/tools/build.c b/arch/cris/arch-v10/boot/tools/build.c
index 2f9bbb2..c8adef3 100644
--- a/arch/cris/arch-v10/boot/tools/build.c
+++ b/arch/cris/arch-v10/boot/tools/build.c
@@ -30,7 +30,6 @@
 #include <sys/sysmacros.h>
 #include <unistd.h>	/* contains read/write */
 #include <fcntl.h>
-#include <linux/a.out.h>
 #include <errno.h>
 
 #define MINIX_HEADER 32
diff --git a/arch/cris/arch-v32/kernel/smp.c b/arch/cris/arch-v32/kernel/smp.c
index 952a24b..52e16c6 100644
--- a/arch/cris/arch-v32/kernel/smp.c
+++ b/arch/cris/arch-v32/kernel/smp.c
@@ -178,6 +178,7 @@
 	unmask_irq(IPI_INTR_VECT);
 	unmask_irq(TIMER0_INTR_VECT);
 	preempt_disable();
+	notify_cpu_starting(cpu);
 	local_irq_enable();
 
 	cpu_set(cpu, cpu_online_map);
diff --git a/arch/h8300/Kconfig b/arch/h8300/Kconfig
index 396ab05..107cb5b 100644
--- a/arch/h8300/Kconfig
+++ b/arch/h8300/Kconfig
@@ -66,9 +66,6 @@
 	bool
 	default y
 
-config ARCH_SUPPORTS_AOUT
-	def_bool y
-
 config NO_IOPORT
 	def_bool y
 
diff --git a/arch/h8300/include/asm/a.out.h b/arch/h8300/include/asm/a.out.h
deleted file mode 100644
index ded780f..0000000
--- a/arch/h8300/include/asm/a.out.h
+++ /dev/null
@@ -1,20 +0,0 @@
-#ifndef __H8300_A_OUT_H__
-#define __H8300_A_OUT_H__
-
-struct exec
-{
-  unsigned long a_info;		/* Use macros N_MAGIC, etc for access */
-  unsigned a_text;		/* length of text, in bytes */
-  unsigned a_data;		/* length of data, in bytes */
-  unsigned a_bss;		/* length of uninitialized data area for file, in bytes */
-  unsigned a_syms;		/* length of symbol table data in file, in bytes */
-  unsigned a_entry;		/* start address */
-  unsigned a_trsize;		/* length of relocation info for text, in bytes */
-  unsigned a_drsize;		/* length of relocation info for data, in bytes */
-};
-
-#define N_TRSIZE(a)	((a).a_trsize)
-#define N_DRSIZE(a)	((a).a_drsize)
-#define N_SYMSIZE(a)	((a).a_syms)
-
-#endif /* __H8300_A_OUT_H__ */
diff --git a/arch/h8300/kernel/process.c b/arch/h8300/kernel/process.c
index dfbe7ab..a8ef654 100644
--- a/arch/h8300/kernel/process.c
+++ b/arch/h8300/kernel/process.c
@@ -34,7 +34,6 @@
 #include <linux/ptrace.h>
 #include <linux/slab.h>
 #include <linux/user.h>
-#include <linux/a.out.h>
 #include <linux/interrupt.h>
 #include <linux/reboot.h>
 #include <linux/fs.h>
diff --git a/arch/ia64/include/asm/a.out.h b/arch/ia64/include/asm/a.out.h
deleted file mode 100644
index 193dcfb..0000000
--- a/arch/ia64/include/asm/a.out.h
+++ /dev/null
@@ -1,32 +0,0 @@
-#ifndef _ASM_IA64_A_OUT_H
-#define _ASM_IA64_A_OUT_H
-
-/*
- * No a.out format has been (or should be) defined so this file is
- * just a dummy that allows us to get binfmt_elf compiled.  It
- * probably would be better to clean up binfmt_elf.c so it does not
- * necessarily depend on there being a.out support.
- *
- * Modified 1998-2002
- *	David Mosberger-Tang <davidm@hpl.hp.com>, Hewlett-Packard Co.
- */
-
-#include <linux/types.h>
-
-struct exec {
-	unsigned long a_info;
-	unsigned long a_text;
-	unsigned long a_data;
-	unsigned long a_bss;
-	unsigned long a_entry;
-};
-
-#define N_TXTADDR(x)	0
-#define N_DATADDR(x)	0
-#define N_BSSADDR(x)	0
-#define N_DRSIZE(x)	0
-#define N_TRSIZE(x)	0
-#define N_SYMSIZE(x)	0
-#define N_TXTOFF(x)	0
-
-#endif /* _ASM_IA64_A_OUT_H */
diff --git a/arch/ia64/include/asm/dma-mapping.h b/arch/ia64/include/asm/dma-mapping.h
index 9f0df9b..06ff1ba 100644
--- a/arch/ia64/include/asm/dma-mapping.h
+++ b/arch/ia64/include/asm/dma-mapping.h
@@ -8,7 +8,9 @@
 #include <asm/machvec.h>
 #include <linux/scatterlist.h>
 
-#define dma_alloc_coherent	platform_dma_alloc_coherent
+#define dma_alloc_coherent(dev, size, handle, gfp)	\
+	platform_dma_alloc_coherent(dev, size, handle, (gfp) | GFP_DMA)
+
 /* coherent mem. is cheap */
 static inline void *
 dma_alloc_noncoherent(struct device *dev, size_t size, dma_addr_t *dma_handle,
diff --git a/arch/ia64/include/asm/sections.h b/arch/ia64/include/asm/sections.h
index f667998..1a873b3 100644
--- a/arch/ia64/include/asm/sections.h
+++ b/arch/ia64/include/asm/sections.h
@@ -11,6 +11,9 @@
 #include <asm-generic/sections.h>
 
 extern char __per_cpu_start[], __per_cpu_end[], __phys_per_cpu_start[];
+#ifdef	CONFIG_SMP
+extern char __cpu0_per_cpu[];
+#endif
 extern char __start___vtop_patchlist[], __end___vtop_patchlist[];
 extern char __start___rse_patchlist[], __end___rse_patchlist[];
 extern char __start___mckinley_e9_bundles[], __end___mckinley_e9_bundles[];
diff --git a/arch/ia64/include/asm/siginfo.h b/arch/ia64/include/asm/siginfo.h
index 9294e4b..118d429 100644
--- a/arch/ia64/include/asm/siginfo.h
+++ b/arch/ia64/include/asm/siginfo.h
@@ -113,11 +113,6 @@
 #undef NSIGSEGV
 #define NSIGSEGV	3
 
-/*
- * SIGTRAP si_codes
- */
-#define TRAP_BRANCH	(__SI_FAULT|3)	/* process taken branch trap */
-#define TRAP_HWBKPT	(__SI_FAULT|4)	/* hardware breakpoint or watchpoint */
 #undef NSIGTRAP
 #define NSIGTRAP	4
 
diff --git a/arch/ia64/include/asm/statfs.h b/arch/ia64/include/asm/statfs.h
index 8110979..1e58966 100644
--- a/arch/ia64/include/asm/statfs.h
+++ b/arch/ia64/include/asm/statfs.h
@@ -8,55 +8,13 @@
  *	David Mosberger-Tang <davidm@hpl.hp.com>, Hewlett-Packard Co
  */
 
-#ifndef __KERNEL_STRICT_NAMES
-# include <linux/types.h>
-typedef __kernel_fsid_t	fsid_t;
-#endif
-
 /*
- * This is ugly --- we're already 64-bit, so just duplicate the definitions
+ * We need compat_statfs64 to be packed, because the i386 ABI won't
+ * add padding at the end to bring it to a multiple of 8 bytes, but
+ * the IA64 ABI will.
  */
-struct statfs {
-	long f_type;
-	long f_bsize;
-	long f_blocks;
-	long f_bfree;
-	long f_bavail;
-	long f_files;
-	long f_ffree;
-	__kernel_fsid_t f_fsid;
-	long f_namelen;
-	long f_frsize;
-	long f_spare[5];
-};
+#define ARCH_PACK_COMPAT_STATFS64 __attribute__((packed,aligned(4)))
 
-
-struct statfs64 {
-	long f_type;
-	long f_bsize;
-	long f_blocks;
-	long f_bfree;
-	long f_bavail;
-	long f_files;
-	long f_ffree;
-	__kernel_fsid_t f_fsid;
-	long f_namelen;
-	long f_frsize;
-	long f_spare[5];
-};
-
-struct compat_statfs64 {
-	__u32 f_type;
-	__u32 f_bsize;
-	__u64 f_blocks;
-	__u64 f_bfree;
-	__u64 f_bavail;
-	__u64 f_files;
-	__u64 f_ffree;
-	__kernel_fsid_t f_fsid;
-	__u32 f_namelen;
-	__u32 f_frsize;
-	__u32 f_spare[5];
-} __attribute__((packed));
+#include <asm-generic/statfs.h>
 
 #endif /* _ASM_IA64_STATFS_H */
diff --git a/arch/ia64/kernel/efi.c b/arch/ia64/kernel/efi.c
index d45f215..51b75ce 100644
--- a/arch/ia64/kernel/efi.c
+++ b/arch/ia64/kernel/efi.c
@@ -1232,9 +1232,10 @@
 				if (md->attribute & EFI_MEMORY_WP) {
 					name = "System ROM";
 					flags |= IORESOURCE_READONLY;
-				} else {
+				} else if (md->attribute == EFI_MEMORY_UC)
+					name = "Uncached RAM";
+				else
 					name = "System RAM";
-				}
 				break;
 
 			case EFI_ACPI_MEMORY_NVS:
diff --git a/arch/ia64/kernel/head.S b/arch/ia64/kernel/head.S
index 8bdea8e..66e491d 100644
--- a/arch/ia64/kernel/head.S
+++ b/arch/ia64/kernel/head.S
@@ -367,16 +367,17 @@
 	;;
 #else
 (isAP)	br.few 2f
-	mov r20=r19
-	sub r19=r19,r18
+	movl r20=__cpu0_per_cpu
 	;;
 	shr.u r18=r18,3
 1:
-	ld8 r21=[r20],8;;
-	st8[r19]=r21,8
+	ld8 r21=[r19],8;;
+	st8[r20]=r21,8
 	adds r18=-1,r18;;
 	cmp4.lt p7,p6=0,r18
 (p7)	br.cond.dptk.few 1b
+	mov r19=r20
+	;;
 2:
 #endif
 	tpa r19=r19
diff --git a/arch/ia64/kernel/setup.c b/arch/ia64/kernel/setup.c
index c27d5b2..de636b2 100644
--- a/arch/ia64/kernel/setup.c
+++ b/arch/ia64/kernel/setup.c
@@ -616,7 +616,9 @@
 		ia64_mca_init();
 
 	platform_setup(cmdline_p);
+#ifndef CONFIG_IA64_HP_SIM
 	check_sal_cache_flush();
+#endif
 	paging_init();
 }
 
diff --git a/arch/ia64/kernel/smpboot.c b/arch/ia64/kernel/smpboot.c
index d8f05e5..1dcbb85 100644
--- a/arch/ia64/kernel/smpboot.c
+++ b/arch/ia64/kernel/smpboot.c
@@ -401,6 +401,7 @@
 	spin_lock(&vector_lock);
 	/* Setup the per cpu irq handling data structures */
 	__setup_vector_irq(cpuid);
+	notify_cpu_starting(cpuid);
 	cpu_set(cpuid, cpu_online_map);
 	per_cpu(cpu_state, cpuid) = CPU_ONLINE;
 	spin_unlock(&vector_lock);
diff --git a/arch/ia64/kernel/vmlinux.lds.S b/arch/ia64/kernel/vmlinux.lds.S
index de71da8..10a7d47e 100644
--- a/arch/ia64/kernel/vmlinux.lds.S
+++ b/arch/ia64/kernel/vmlinux.lds.S
@@ -215,9 +215,6 @@
   /* Per-cpu data: */
   percpu : { } :percpu
   . = ALIGN(PERCPU_PAGE_SIZE);
-#ifdef	CONFIG_SMP
-  . = . + PERCPU_PAGE_SIZE;	/* cpu0 per-cpu space */
-#endif
   __phys_per_cpu_start = .;
   .data.percpu PERCPU_ADDR : AT(__phys_per_cpu_start - LOAD_OFFSET)
 	{
@@ -233,6 +230,11 @@
   data : { } :data
   .data : AT(ADDR(.data) - LOAD_OFFSET)
 	{
+#ifdef	CONFIG_SMP
+  . = ALIGN(PERCPU_PAGE_SIZE);
+		__cpu0_per_cpu = .;
+  . = . + PERCPU_PAGE_SIZE;	/* cpu0 per-cpu space */
+#endif
 		DATA_DATA
 		*(.data1)
 		*(.gnu.linkonce.d*)
diff --git a/arch/ia64/kvm/kvm-ia64.c b/arch/ia64/kvm/kvm-ia64.c
index 7a37d06..cd0d1a7 100644
--- a/arch/ia64/kvm/kvm-ia64.c
+++ b/arch/ia64/kvm/kvm-ia64.c
@@ -38,6 +38,7 @@
 #include <asm/cacheflush.h>
 #include <asm/div64.h>
 #include <asm/tlb.h>
+#include <asm/elf.h>
 
 #include "misc.h"
 #include "vti.h"
@@ -61,12 +62,6 @@
 	{ NULL }
 };
 
-
-struct fdesc{
-    unsigned long ip;
-    unsigned long gp;
-};
-
 static void kvm_flush_icache(unsigned long start, unsigned long len)
 {
 	int l;
diff --git a/arch/ia64/mm/contig.c b/arch/ia64/mm/contig.c
index e566ff4..0ee085e 100644
--- a/arch/ia64/mm/contig.c
+++ b/arch/ia64/mm/contig.c
@@ -163,7 +163,7 @@
 	 * get_zeroed_page().
 	 */
 	if (first_time) {
-		void *cpu0_data = __phys_per_cpu_start - PERCPU_PAGE_SIZE;
+		void *cpu0_data = __cpu0_per_cpu;
 
 		first_time=0;
 
diff --git a/arch/ia64/mm/discontig.c b/arch/ia64/mm/discontig.c
index 78026aa..d8c5fcd 100644
--- a/arch/ia64/mm/discontig.c
+++ b/arch/ia64/mm/discontig.c
@@ -144,7 +144,7 @@
 
 	for_each_possible_early_cpu(cpu) {
 		if (cpu == 0) {
-			void *cpu0_data = __phys_per_cpu_start - PERCPU_PAGE_SIZE;
+			void *cpu0_data = __cpu0_per_cpu;
 			__per_cpu_offset[cpu] = (char*)cpu0_data -
 				__per_cpu_start;
 		} else if (node == node_cpuid[cpu].nid) {
diff --git a/arch/ia64/mm/init.c b/arch/ia64/mm/init.c
index 200100e..f482a90 100644
--- a/arch/ia64/mm/init.c
+++ b/arch/ia64/mm/init.c
@@ -21,7 +21,6 @@
 #include <linux/bitops.h>
 #include <linux/kexec.h>
 
-#include <asm/a.out.h>
 #include <asm/dma.h>
 #include <asm/ia32.h>
 #include <asm/io.h>
diff --git a/arch/m32r/Kconfig b/arch/m32r/Kconfig
index a5f864c..00289c1 100644
--- a/arch/m32r/Kconfig
+++ b/arch/m32r/Kconfig
@@ -36,9 +36,6 @@
 config NO_DMA
 	def_bool y
 
-config ARCH_SUPPORTS_AOUT
-	def_bool y
-
 config HZ
 	int
 	default 100
@@ -216,10 +213,6 @@
 	default "01000000" if PLAT_M32104UT
 	default "00800000" if PLAT_OAKS32R
 
-config NOHIGHMEM
-	bool
-	default y
-
 config ARCH_DISCONTIGMEM_ENABLE
 	bool "Internal RAM Support"
 	depends on CHIP_M32700 || CHIP_M32102 || CHIP_VDEC2 || CHIP_OPSP || CHIP_M32104
@@ -410,11 +403,7 @@
 source "drivers/pci/Kconfig"
 
 config ISA
-	bool "ISA support"
-	help
-	  Find out whether you have ISA slots on your motherboard.  ISA is the
-	  name of a bus system, i.e. the way the CPU talks to the other stuff
-	  inside your box.  If you have ISA, say Y, otherwise N.
+	bool
 
 source "drivers/pcmcia/Kconfig"
 
diff --git a/arch/m32r/kernel/entry.S b/arch/m32r/kernel/entry.S
index d4eaa2f..612d35b 100644
--- a/arch/m32r/kernel/entry.S
+++ b/arch/m32r/kernel/entry.S
@@ -143,7 +143,7 @@
 	and3	r4, r4, #0x8000		; check BSM bit
 #endif
 	beqz	r4, resume_kernel
-ENTRY(resume_userspace)
+resume_userspace:
 	DISABLE_INTERRUPTS(r4)		; make sure we don't miss an interrupt
 					; setting need_resched or sigpending
 					; between sampling and the iret
diff --git a/arch/m32r/kernel/head.S b/arch/m32r/kernel/head.S
index dab7436..4018077 100644
--- a/arch/m32r/kernel/head.S
+++ b/arch/m32r/kernel/head.S
@@ -29,7 +29,6 @@
 	.global _end
 ENTRY(stext)
 ENTRY(_stext)
-ENTRY(startup_32)
 	/* Setup up the stack pointer */
 	LDIMM	(r0, spi_stack_top)
 	LDIMM	(r1, spu_stack_top)
diff --git a/arch/m32r/kernel/irq.c b/arch/m32r/kernel/irq.c
index d0c5b0b..2aeae46 100644
--- a/arch/m32r/kernel/irq.c
+++ b/arch/m32r/kernel/irq.c
@@ -22,9 +22,6 @@
 #include <linux/module.h>
 #include <asm/uaccess.h>
 
-atomic_t irq_err_count;
-atomic_t irq_mis_count;
-
 /*
  * Generic, controller-independent functions:
  */
@@ -63,9 +60,6 @@
 		seq_putc(p, '\n');
 skip:
 		spin_unlock_irqrestore(&irq_desc[i].lock, flags);
-	} else if (i == NR_IRQS) {
-		seq_printf(p, "ERR: %10u\n", atomic_read(&irq_err_count));
-		seq_printf(p, "MIS: %10u\n", atomic_read(&irq_mis_count));
 	}
 	return 0;
 }
diff --git a/arch/m32r/kernel/m32r_ksyms.c b/arch/m32r/kernel/m32r_ksyms.c
index 16bcb18..22624b5 100644
--- a/arch/m32r/kernel/m32r_ksyms.c
+++ b/arch/m32r/kernel/m32r_ksyms.c
@@ -14,6 +14,7 @@
 #include <asm/delay.h>
 #include <asm/irq.h>
 #include <asm/tlbflush.h>
+#include <asm/pgtable.h>
 
 /* platform dependent support */
 EXPORT_SYMBOL(boot_cpu_data);
@@ -65,6 +66,7 @@
 EXPORT_SYMBOL(copy_page);
 EXPORT_SYMBOL(clear_page);
 EXPORT_SYMBOL(strlen);
+EXPORT_SYMBOL(empty_zero_page);
 
 EXPORT_SYMBOL(_inb);
 EXPORT_SYMBOL(_inw);
diff --git a/arch/m32r/kernel/process.c b/arch/m32r/kernel/process.c
index a689e29..5be4faa 100644
--- a/arch/m32r/kernel/process.c
+++ b/arch/m32r/kernel/process.c
@@ -35,8 +35,6 @@
 
 #include <linux/err.h>
 
-static int hlt_counter=0;
-
 /*
  * Return saved PC of a blocked thread.
  */
@@ -48,31 +46,16 @@
 /*
  * Powermanagement idle function, if any..
  */
-void (*pm_idle)(void) = NULL;
-EXPORT_SYMBOL(pm_idle);
+static void (*pm_idle)(void) = NULL;
 
 void (*pm_power_off)(void) = NULL;
 EXPORT_SYMBOL(pm_power_off);
 
-void disable_hlt(void)
-{
-	hlt_counter++;
-}
-
-EXPORT_SYMBOL(disable_hlt);
-
-void enable_hlt(void)
-{
-	hlt_counter--;
-}
-
-EXPORT_SYMBOL(enable_hlt);
-
 /*
  * We use this is we don't have any better
  * idle routine..
  */
-void default_idle(void)
+static void default_idle(void)
 {
 	/* M32R_FIXME: Please use "cpu_sleep" mode.  */
 	cpu_relax();
@@ -260,15 +243,6 @@
 	return 0;
 }
 
-/*
- * Capture the user space registers if the task is not running (in user space)
- */
-int dump_task_regs(struct task_struct *tsk, elf_gregset_t *regs)
-{
-	/* M32R_FIXME */
-	return 1;
-}
-
 asmlinkage int sys_fork(unsigned long r0, unsigned long r1, unsigned long r2,
 	unsigned long r3, unsigned long r4, unsigned long r5, unsigned long r6,
 	struct pt_regs regs)
diff --git a/arch/m32r/kernel/smp.c b/arch/m32r/kernel/smp.c
index 7577f97..929e5c9d 100644
--- a/arch/m32r/kernel/smp.c
+++ b/arch/m32r/kernel/smp.c
@@ -84,7 +84,7 @@
 void smp_ipi_timer_interrupt(struct pt_regs *);
 void smp_local_timer_interrupt(void);
 
-void send_IPI_allbutself(int, int);
+static void send_IPI_allbutself(int, int);
 static void send_IPI_mask(cpumask_t, int, int);
 unsigned long send_IPI_mask_phys(cpumask_t, int, int);
 
@@ -722,7 +722,7 @@
  * ---------- --- --------------------------------------------------------
  *
  *==========================================================================*/
-void send_IPI_allbutself(int ipi_num, int try)
+static void send_IPI_allbutself(int ipi_num, int try)
 {
 	cpumask_t cpumask;
 
diff --git a/arch/m32r/kernel/smpboot.c b/arch/m32r/kernel/smpboot.c
index 2c03ac1..fc29948 100644
--- a/arch/m32r/kernel/smpboot.c
+++ b/arch/m32r/kernel/smpboot.c
@@ -498,6 +498,8 @@
 {
 	int cpu_id = smp_processor_id();
 
+	notify_cpu_starting(cpu_id);
+
 	local_irq_enable();
 
 	/* Get our bogomips. */
diff --git a/arch/m32r/kernel/time.c b/arch/m32r/kernel/time.c
index 994cc15..6ea0177 100644
--- a/arch/m32r/kernel/time.c
+++ b/arch/m32r/kernel/time.c
@@ -34,7 +34,6 @@
 #include <asm/hw_irq.h>
 
 #ifdef CONFIG_SMP
-extern void send_IPI_allbutself(int, int);
 extern void smp_local_timer_interrupt(void);
 #endif
 
@@ -188,7 +187,7 @@
  * timer_interrupt() needs to keep up the real-time clock,
  * as well as call the "do_timer()" routine every clocktick
  */
-irqreturn_t timer_interrupt(int irq, void *dev_id)
+static irqreturn_t timer_interrupt(int irq, void *dev_id)
 {
 #ifndef CONFIG_SMP
 	profile_tick(CPU_PROFILING);
@@ -228,7 +227,7 @@
 	return IRQ_HANDLED;
 }
 
-struct irqaction irq0 = {
+static struct irqaction irq0 = {
 	.handler = timer_interrupt,
 	.flags = IRQF_DISABLED,
 	.mask = CPU_MASK_NONE,
diff --git a/arch/m32r/kernel/traps.c b/arch/m32r/kernel/traps.c
index 46159a4..03b14e5 100644
--- a/arch/m32r/kernel/traps.c
+++ b/arch/m32r/kernel/traps.c
@@ -61,7 +61,7 @@
 	((unsigned long)func - (unsigned long)eit_vector - entry*4)/4 \
 	+ 0xff000000UL
 
-void	set_eit_vector_entries(void)
+static void set_eit_vector_entries(void)
 {
 	extern void default_eit_handler(void);
 	extern void system_call(void);
@@ -121,9 +121,9 @@
 	cpu_init();
 }
 
-int kstack_depth_to_print = 24;
+static int kstack_depth_to_print = 24;
 
-void show_trace(struct task_struct *task, unsigned long *stack)
+static void show_trace(struct task_struct *task, unsigned long *stack)
 {
 	unsigned long addr;
 
@@ -224,7 +224,7 @@
 	printk("\n");
 }
 
-DEFINE_SPINLOCK(die_lock);
+static DEFINE_SPINLOCK(die_lock);
 
 void die(const char * str, struct pt_regs * regs, long err)
 {
diff --git a/arch/m32r/lib/delay.c b/arch/m32r/lib/delay.c
index 59bfc34..ced549b 100644
--- a/arch/m32r/lib/delay.c
+++ b/arch/m32r/lib/delay.c
@@ -6,6 +6,7 @@
  */
 
 #include <linux/param.h>
+#include <linux/module.h>
 #ifdef CONFIG_SMP
 #include <linux/sched.h>
 #include <asm/current.h>
@@ -121,3 +122,4 @@
 {
 	__const_udelay(nsecs * 0x00005);  /* 2**32 / 1000000000 (rounded up) */
 }
+EXPORT_SYMBOL(__ndelay);
diff --git a/arch/m32r/mm/discontig.c b/arch/m32r/mm/discontig.c
index cbc3c4c..7daf897 100644
--- a/arch/m32r/mm/discontig.c
+++ b/arch/m32r/mm/discontig.c
@@ -111,9 +111,9 @@
 				initrd_start, INITRD_SIZE);
 		} else {
 			printk("initrd extends beyond end of memory "
-				"(0x%08lx > 0x%08lx)\ndisabling initrd\n",
+				"(0x%08lx > 0x%08llx)\ndisabling initrd\n",
 				INITRD_START + INITRD_SIZE,
-				PFN_PHYS(max_low_pfn));
+			        (unsigned long long)PFN_PHYS(max_low_pfn));
 
 			initrd_start = 0;
 		}
diff --git a/arch/m68k/Kconfig b/arch/m68k/Kconfig
index 8c5e1de..677c93a 100644
--- a/arch/m68k/Kconfig
+++ b/arch/m68k/Kconfig
@@ -5,6 +5,7 @@
 config M68K
 	bool
 	default y
+	select HAVE_AOUT
 	select HAVE_IDE
 
 config MMU
@@ -53,9 +54,6 @@
 config NO_DMA
 	def_bool SUN3
 
-config ARCH_SUPPORTS_AOUT
-	def_bool y
-
 config HZ
 	int
 	default 100
@@ -107,21 +105,9 @@
 	  To compile this driver as modules, choose M here: the
 	  modules will be called pcmcia_core and ds.
 
-config SUN3
-	bool "Sun3 support"
-	select M68020
-	select MMU_SUN3 if MMU
-	help
-	  This option enables support for the Sun 3 series of workstations
-	  (3/50, 3/60, 3/1xx, 3/2xx systems). Enabling this option requires
-	  that all other hardware types must be disabled, as Sun 3 kernels
-	  are incompatible with all other m68k targets (including Sun 3x!).
-
-	  If you don't want to compile a kernel exclusively for a Sun 3, say N.
-
 config AMIGA
 	bool "Amiga support"
-	depends on !MMU_SUN3
+	select MMU_MOTOROLA if MMU
 	help
 	  This option enables support for the Amiga series of computers. If
 	  you plan to use this kernel on an Amiga, say Y here and browse the
@@ -129,33 +115,16 @@
 
 config ATARI
 	bool "Atari support"
-	depends on !MMU_SUN3
+	select MMU_MOTOROLA if MMU
 	help
 	  This option enables support for the 68000-based Atari series of
 	  computers (including the TT, Falcon and Medusa). If you plan to use
 	  this kernel on an Atari, say Y here and browse the material
 	  available in <file:Documentation/m68k>; otherwise say N.
 
-config HADES
-	bool "Hades support"
-	depends on ATARI && BROKEN
-	help
-	  This option enables support for the Hades Atari clone. If you plan
-	  to use this kernel on a Hades, say Y here; otherwise say N.
-
-config PCI
-	bool
-	depends on HADES
-	default y
-	help
-	  Find out whether you have a PCI motherboard. PCI is the name of a
-	  bus system, i.e. the way the CPU talks to the other stuff inside
-	  your box. Other bus systems are ISA, EISA, MicroChannel (MCA) or
-	  VESA. If you have PCI, say Y, otherwise N.
-
 config MAC
 	bool "Macintosh support"
-	depends on !MMU_SUN3
+	select MMU_MOTOROLA if MMU
 	help
 	  This option enables support for the Apple Macintosh series of
 	  computers (yes, there is experimental support now, at least for part
@@ -176,14 +145,14 @@
 
 config APOLLO
 	bool "Apollo support"
-	depends on !MMU_SUN3
+	select MMU_MOTOROLA if MMU
 	help
 	  Say Y here if you want to run Linux on an MC680x0-based Apollo
 	  Domain workstation such as the DN3500.
 
 config VME
 	bool "VME (Motorola and BVM) support"
-	depends on !MMU_SUN3
+	select MMU_MOTOROLA if MMU
 	help
 	  Say Y here if you want to build a kernel for a 680x0 based VME
 	  board.  Boards currently supported include Motorola boards MVME147,
@@ -220,7 +189,7 @@
 
 config HP300
 	bool "HP9000/300 and HP9000/400 support"
-	depends on !MMU_SUN3
+	select MMU_MOTOROLA if MMU
 	help
 	  This option enables support for the HP9000/300 and HP9000/400 series
 	  of workstations. Support for these machines is still somewhat
@@ -239,7 +208,7 @@
 
 config SUN3X
 	bool "Sun3x support"
-	depends on !MMU_SUN3
+	select MMU_MOTOROLA if MMU
 	select M68030
 	help
 	  This option enables support for the Sun 3x series of workstations.
@@ -252,7 +221,7 @@
 
 config Q40
 	bool "Q40/Q60 support"
-	depends on !MMU_SUN3
+	select MMU_MOTOROLA if MMU
 	help
 	  The Q40 is a Motorola 68040-based successor to the Sinclair QL
 	  manufactured in Germany.  There is an official Q40 home page at
@@ -260,6 +229,19 @@
 	  Q60. Select your CPU below.  For 68LC060 don't forget to enable FPU
 	  emulation.
 
+config SUN3
+	bool "Sun3 support"
+	depends on !MMU_MOTOROLA
+	select MMU_SUN3 if MMU
+	select M68020
+	help
+	  This option enables support for the Sun 3 series of workstations
+	  (3/50, 3/60, 3/1xx, 3/2xx systems). Enabling this option requires
+	  that all other hardware types must be disabled, as Sun 3 kernels
+	  are incompatible with all other m68k targets (including Sun 3x!).
+
+	  If you don't want to compile a kernel exclusively for a Sun 3, say N.
+
 comment "Processor type"
 
 config M68020
@@ -297,10 +279,10 @@
 config MMU_MOTOROLA
 	bool
 	depends on MMU && !MMU_SUN3
-	default y
 
 config MMU_SUN3
 	bool
+	depends on MMU && !MMU_MOTOROLA
 
 config M68KFPU_EMU
 	bool "Math emulation support (EXPERIMENTAL)"
diff --git a/arch/m68k/amiga/config.c b/arch/m68k/amiga/config.c
index df679d9..0a3f9e8 100644
--- a/arch/m68k/amiga/config.c
+++ b/arch/m68k/amiga/config.c
@@ -24,6 +24,7 @@
 #include <linux/interrupt.h>
 #include <linux/zorro.h>
 #include <linux/module.h>
+#include <linux/keyboard.h>
 
 #include <asm/bootinfo.h>
 #include <asm/setup.h>
@@ -984,3 +985,11 @@
 
 	return len;
 }
+
+/*
+ * The Amiga keyboard driver needs key_maps, but we cannot export it in
+ * drivers/char/defkeymap.c, as it is autogenerated
+ */
+#ifdef CONFIG_HW_CONSOLE
+EXPORT_SYMBOL_GPL(key_maps);
+#endif
diff --git a/arch/m68k/atari/Makefile b/arch/m68k/atari/Makefile
index 2cd905e..0cac723 100644
--- a/arch/m68k/atari/Makefile
+++ b/arch/m68k/atari/Makefile
@@ -5,7 +5,4 @@
 obj-y		:= config.o time.o debug.o ataints.o stdma.o \
 			atasound.o stram.o
 
-ifeq ($(CONFIG_PCI),y)
-obj-$(CONFIG_HADES)	+= hades-pci.o
-endif
 obj-$(CONFIG_ATARI_KBD_CORE)	+= atakeyb.o
diff --git a/arch/m68k/atari/ataints.c b/arch/m68k/atari/ataints.c
index b45593a..dba4afa 100644
--- a/arch/m68k/atari/ataints.c
+++ b/arch/m68k/atari/ataints.c
@@ -407,10 +407,8 @@
 		 * gets overruns)
 		 */
 
-		if (!MACH_IS_HADES) {
-			vectors[VEC_INT2] = falcon_hblhandler;
-			vectors[VEC_INT4] = falcon_hblhandler;
-		}
+		vectors[VEC_INT2] = falcon_hblhandler;
+		vectors[VEC_INT4] = falcon_hblhandler;
 	}
 
 	if (ATARIHW_PRESENT(PCM_8BIT) && ATARIHW_PRESENT(MICROWIRE)) {
diff --git a/arch/m68k/atari/atakeyb.c b/arch/m68k/atari/atakeyb.c
index bb959fb..c038b7c 100644
--- a/arch/m68k/atari/atakeyb.c
+++ b/arch/m68k/atari/atakeyb.c
@@ -635,15 +635,3 @@
 	return 0;
 }
 EXPORT_SYMBOL_GPL(atari_keyb_init);
-
-int atari_kbd_translate(unsigned char keycode, unsigned char *keycodep, char raw_mode)
-{
-#ifdef CONFIG_MAGIC_SYSRQ
-	/* ALT+HELP pressed? */
-	if ((keycode == 98) && ((shift_state & 0xff) == 8))
-		*keycodep = 0xff;
-	else
-#endif
-		*keycodep = keycode;
-	return 1;
-}
diff --git a/arch/m68k/atari/config.c b/arch/m68k/atari/config.c
index 5945e15..af03185 100644
--- a/arch/m68k/atari/config.c
+++ b/arch/m68k/atari/config.c
@@ -231,7 +231,7 @@
 	 */
 
 	printk("Atari hardware found: ");
-	if (MACH_IS_MEDUSA || MACH_IS_HADES) {
+	if (MACH_IS_MEDUSA) {
 		/* There's no Atari video hardware on the Medusa, but all the
 		 * addresses below generate a DTACK so no bus error occurs! */
 	} else if (hwreg_present(f030_xreg)) {
@@ -269,10 +269,6 @@
 		ATARIHW_SET(SCSI_DMA);
 		printk("TT_SCSI_DMA ");
 	}
-	if (!MACH_IS_HADES && hwreg_present(&st_dma.dma_hi)) {
-		ATARIHW_SET(STND_DMA);
-		printk("STND_DMA ");
-	}
 	/*
 	 * The ST-DMA address registers aren't readable
 	 * on all Medusas, so the test below may fail
@@ -294,12 +290,11 @@
 		ATARIHW_SET(YM_2149);
 		printk("YM2149 ");
 	}
-	if (!MACH_IS_MEDUSA && !MACH_IS_HADES &&
-		hwreg_present(&tt_dmasnd.ctrl)) {
+	if (!MACH_IS_MEDUSA && hwreg_present(&tt_dmasnd.ctrl)) {
 		ATARIHW_SET(PCM_8BIT);
 		printk("PCM ");
 	}
-	if (!MACH_IS_HADES && hwreg_present(&falcon_codec.unused5)) {
+	if (hwreg_present(&falcon_codec.unused5)) {
 		ATARIHW_SET(CODEC);
 		printk("CODEC ");
 	}
@@ -313,7 +308,7 @@
 	    (tt_scc_dma.dma_ctrl = 0x01, (tt_scc_dma.dma_ctrl & 1) == 1) &&
 	    (tt_scc_dma.dma_ctrl = 0x00, (tt_scc_dma.dma_ctrl & 1) == 0)
 #else
-	    !MACH_IS_MEDUSA && !MACH_IS_HADES
+	    !MACH_IS_MEDUSA
 #endif
 	    ) {
 		ATARIHW_SET(SCC_DMA);
@@ -327,10 +322,7 @@
 		ATARIHW_SET(ST_ESCC);
 		printk("ST_ESCC ");
 	}
-	if (MACH_IS_HADES) {
-		ATARIHW_SET(VME);
-		printk("VME ");
-	} else if (hwreg_present(&tt_scu.sys_mask)) {
+	if (hwreg_present(&tt_scu.sys_mask)) {
 		ATARIHW_SET(SCU);
 		/* Assume a VME bus if there's a SCU */
 		ATARIHW_SET(VME);
@@ -340,7 +332,7 @@
 		ATARIHW_SET(ANALOG_JOY);
 		printk("ANALOG_JOY ");
 	}
-	if (!MACH_IS_HADES && hwreg_present(blitter.halftone)) {
+	if (hwreg_present(blitter.halftone)) {
 		ATARIHW_SET(BLITTER);
 		printk("BLITTER ");
 	}
@@ -349,8 +341,7 @@
 		printk("IDE ");
 	}
 #if 1 /* This maybe wrong */
-	if (!MACH_IS_MEDUSA && !MACH_IS_HADES &&
-	    hwreg_present(&tt_microwire.data) &&
+	if (!MACH_IS_MEDUSA && hwreg_present(&tt_microwire.data) &&
 	    hwreg_present(&tt_microwire.mask) &&
 	    (tt_microwire.mask = 0x7ff,
 	     udelay(1),
@@ -369,19 +360,18 @@
 		mach_hwclk = atari_tt_hwclk;
 		mach_set_clock_mmss = atari_tt_set_clock_mmss;
 	}
-	if (!MACH_IS_HADES && hwreg_present(&mste_rtc.sec_ones)) {
+	if (hwreg_present(&mste_rtc.sec_ones)) {
 		ATARIHW_SET(MSTE_CLK);
 		printk("MSTE_CLK ");
 		mach_hwclk = atari_mste_hwclk;
 		mach_set_clock_mmss = atari_mste_set_clock_mmss;
 	}
-	if (!MACH_IS_MEDUSA && !MACH_IS_HADES &&
-	    hwreg_present(&dma_wd.fdc_speed) &&
+	if (!MACH_IS_MEDUSA && hwreg_present(&dma_wd.fdc_speed) &&
 	    hwreg_write(&dma_wd.fdc_speed, 0)) {
 		ATARIHW_SET(FDCSPEED);
 		printk("FDC_SPEED ");
 	}
-	if (!MACH_IS_HADES && !ATARIHW_PRESENT(ST_SCSI)) {
+	if (!ATARIHW_PRESENT(ST_SCSI)) {
 		ATARIHW_SET(ACSI);
 		printk("ACSI ");
 	}
@@ -449,7 +439,7 @@
 	 * 0xFFxxxxxx -> 0x00xxxxxx, so that the first 16MB is accessible
 	 * in the last 16MB of the address space.
 	 */
-	tos_version = (MACH_IS_MEDUSA || MACH_IS_HADES) ?
+	tos_version = (MACH_IS_MEDUSA) ?
 			0xfff : *(unsigned short *)0xff000002;
 	atari_rtc_year_offset = (tos_version < 0x306) ? 70 : 68;
 }
@@ -511,8 +501,7 @@
 	 * On the Medusa, phys. 0x4 may contain garbage because it's no
 	 * ROM.  See above for explanation why we cannot use PTOV(4).
 	 */
-	reset_addr = MACH_IS_HADES ? 0x7fe00030 :
-		     MACH_IS_MEDUSA || MACH_IS_AB40 ? 0xe00030 :
+	reset_addr = MACH_IS_MEDUSA || MACH_IS_AB40 ? 0xe00030 :
 		     *(unsigned long *) 0xff000004;
 
 	/* reset ACIA for switch off OverScan, if it's active */
@@ -606,8 +595,6 @@
 		if (MACH_IS_MEDUSA)
 			/* Medusa has TT _MCH cookie */
 			strcat(model, "Medusa");
-		else if (MACH_IS_HADES)
-			strcat(model, "Hades");
 		else
 			strcat(model, "TT");
 		break;
diff --git a/arch/m68k/atari/hades-pci.c b/arch/m68k/atari/hades-pci.c
deleted file mode 100644
index 2bbabc0..0000000
--- a/arch/m68k/atari/hades-pci.c
+++ /dev/null
@@ -1,440 +0,0 @@
-/*
- * hades-pci.c - Hardware specific PCI BIOS functions the Hades Atari clone.
- *
- * Written by Wout Klaren.
- */
-
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <asm/io.h>
-
-#if 0
-# define DBG_DEVS(args)		printk args
-#else
-# define DBG_DEVS(args)
-#endif
-
-#if defined(CONFIG_PCI) && defined(CONFIG_HADES)
-
-#include <linux/slab.h>
-#include <linux/mm.h>
-#include <linux/pci.h>
-
-#include <asm/atarihw.h>
-#include <asm/atariints.h>
-#include <asm/byteorder.h>
-#include <asm/pci.h>
-
-#define HADES_MEM_BASE		0x80000000
-#define HADES_MEM_SIZE		0x20000000
-#define HADES_CONFIG_BASE	0xA0000000
-#define HADES_CONFIG_SIZE	0x10000000
-#define HADES_IO_BASE		0xB0000000
-#define HADES_IO_SIZE		0x10000000
-#define HADES_VIRT_IO_SIZE	0x00010000	/* Only 64k is remapped and actually used. */
-
-#define N_SLOTS				4			/* Number of PCI slots. */
-
-static const char pci_mem_name[] = "PCI memory space";
-static const char pci_io_name[] = "PCI I/O space";
-static const char pci_config_name[] = "PCI config space";
-
-static struct resource config_space = {
-    .name = pci_config_name,
-    .start = HADES_CONFIG_BASE,
-    .end = HADES_CONFIG_BASE + HADES_CONFIG_SIZE - 1
-};
-static struct resource io_space = {
-    .name = pci_io_name,
-    .start = HADES_IO_BASE,
-    .end = HADES_IO_BASE + HADES_IO_SIZE - 1
-};
-
-static const unsigned long pci_conf_base_phys[] = {
-    0xA0080000, 0xA0040000, 0xA0020000, 0xA0010000
-};
-static unsigned long pci_conf_base_virt[N_SLOTS];
-static unsigned long pci_io_base_virt;
-
-/*
- * static void *mk_conf_addr(unsigned char bus, unsigned char device_fn,
- *			     unsigned char where)
- *
- * Calculate the address of the PCI configuration area of the given
- * device.
- *
- * BUG: boards with multiple functions are probably not correctly
- * supported.
- */
-
-static void *mk_conf_addr(struct pci_dev *dev, int where)
-{
-	int device = dev->devfn >> 3, function = dev->devfn & 7;
-	void *result;
-
-	DBG_DEVS(("mk_conf_addr(bus=%d ,device_fn=0x%x, where=0x%x, pci_addr=0x%p)\n",
-		  dev->bus->number, dev->devfn, where, pci_addr));
-
-	if (device > 3)
-	{
-		DBG_DEVS(("mk_conf_addr: device (%d) > 3, returning NULL\n", device));
-		return NULL;
-	}
-
-	if (dev->bus->number != 0)
-	{
-		DBG_DEVS(("mk_conf_addr: bus (%d) > 0, returning NULL\n", device));
-		return NULL;
-	}
-
-	result = (void *) (pci_conf_base_virt[device] | (function << 8) | (where));
-	DBG_DEVS(("mk_conf_addr: returning pci_addr 0x%lx\n", (unsigned long) result));
-	return result;
-}
-
-static int hades_read_config_byte(struct pci_dev *dev, int where, u8 *value)
-{
-	volatile unsigned char *pci_addr;
-
-	*value = 0xff;
-
-	if ((pci_addr = (unsigned char *) mk_conf_addr(dev, where)) == NULL)
-		return PCIBIOS_DEVICE_NOT_FOUND;
-
-	*value = *pci_addr;
-
-	return PCIBIOS_SUCCESSFUL;
-}
-
-static int hades_read_config_word(struct pci_dev *dev, int where, u16 *value)
-{
-	volatile unsigned short *pci_addr;
-
-	*value = 0xffff;
-
-	if (where & 0x1)
-		return PCIBIOS_BAD_REGISTER_NUMBER;
-
-	if ((pci_addr = (unsigned short *) mk_conf_addr(dev, where)) == NULL)
-		return PCIBIOS_DEVICE_NOT_FOUND;
-
-	*value = le16_to_cpu(*pci_addr);
-
-	return PCIBIOS_SUCCESSFUL;
-}
-
-static int hades_read_config_dword(struct pci_dev *dev, int where, u32 *value)
-{
-	volatile unsigned int *pci_addr;
-	unsigned char header_type;
-	int result;
-
-	*value = 0xffffffff;
-
-	if (where & 0x3)
-		return PCIBIOS_BAD_REGISTER_NUMBER;
-
-	if ((pci_addr = (unsigned int *) mk_conf_addr(dev, where)) == NULL)
-		return PCIBIOS_DEVICE_NOT_FOUND;
-
-	*value = le32_to_cpu(*pci_addr);
-
-	/*
-	 * Check if the value is an address on the bus. If true, add the
-	 * base address of the PCI memory or PCI I/O area on the Hades.
-	 */
-
-	if ((result = hades_read_config_byte(dev, PCI_HEADER_TYPE,
-					     &header_type)) != PCIBIOS_SUCCESSFUL)
-		return result;
-
-	if (((where >= PCI_BASE_ADDRESS_0) && (where <= PCI_BASE_ADDRESS_1)) ||
-	    ((header_type != PCI_HEADER_TYPE_BRIDGE) && ((where >= PCI_BASE_ADDRESS_2) &&
-							 (where <= PCI_BASE_ADDRESS_5))))
-	{
-		if ((*value & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO)
-		{
-			/*
-			 * Base address register that contains an I/O address. If the
-			 * address is valid on the Hades (0 <= *value < HADES_VIRT_IO_SIZE),
-			 * add 'pci_io_base_virt' to the value.
-			 */
-
-			if (*value < HADES_VIRT_IO_SIZE)
-				*value += pci_io_base_virt;
-		}
-		else
-		{
-			/*
-			 * Base address register that contains an memory address. If the
-			 * address is valid on the Hades (0 <= *value < HADES_MEM_SIZE),
-			 * add HADES_MEM_BASE to the value.
-			 */
-
-			if (*value == 0)
-			{
-				/*
-				 * Base address is 0. Test if this base
-				 * address register is used.
-				 */
-
-				*pci_addr = 0xffffffff;
-				if (*pci_addr != 0)
-				{
-					*pci_addr = *value;
-					if (*value < HADES_MEM_SIZE)
-						*value += HADES_MEM_BASE;
-				}
-			}
-			else
-			{
-				if (*value < HADES_MEM_SIZE)
-					*value += HADES_MEM_BASE;
-			}
-		}
-	}
-
-	return PCIBIOS_SUCCESSFUL;
-}
-
-static int hades_write_config_byte(struct pci_dev *dev, int where, u8 value)
-{
-	volatile unsigned char *pci_addr;
-
-	if ((pci_addr = (unsigned char *) mk_conf_addr(dev, where)) == NULL)
-		return PCIBIOS_DEVICE_NOT_FOUND;
-
-	*pci_addr = value;
-
-	return PCIBIOS_SUCCESSFUL;
-}
-
-static int hades_write_config_word(struct pci_dev *dev, int where, u16 value)
-{
-	volatile unsigned short *pci_addr;
-
-	if ((pci_addr = (unsigned short *) mk_conf_addr(dev, where)) == NULL)
-		return PCIBIOS_DEVICE_NOT_FOUND;
-
-	*pci_addr = cpu_to_le16(value);
-
-	return PCIBIOS_SUCCESSFUL;
-}
-
-static int hades_write_config_dword(struct pci_dev *dev, int where, u32 value)
-{
-	volatile unsigned int *pci_addr;
-	unsigned char header_type;
-	int result;
-
-	if ((pci_addr = (unsigned int *) mk_conf_addr(dev, where)) == NULL)
-		return PCIBIOS_DEVICE_NOT_FOUND;
-
-	/*
-	 * Check if the value is an address on the bus. If true, subtract the
-	 * base address of the PCI memory or PCI I/O area on the Hades.
-	 */
-
-	if ((result = hades_read_config_byte(dev, PCI_HEADER_TYPE,
-					     &header_type)) != PCIBIOS_SUCCESSFUL)
-		return result;
-
-	if (((where >= PCI_BASE_ADDRESS_0) && (where <= PCI_BASE_ADDRESS_1)) ||
-	    ((header_type != PCI_HEADER_TYPE_BRIDGE) && ((where >= PCI_BASE_ADDRESS_2) &&
-							 (where <= PCI_BASE_ADDRESS_5))))
-	{
-		if ((value & PCI_BASE_ADDRESS_SPACE) ==
-		    PCI_BASE_ADDRESS_SPACE_IO)
-		{
-			/*
-			 * I/O address. Check if the address is valid address on
-			 * the Hades (pci_io_base_virt <= value < pci_io_base_virt +
-			 * HADES_VIRT_IO_SIZE) or if the value is 0xffffffff. If not
-			 * true do not write the base address register. If it is a
-			 * valid base address subtract 'pci_io_base_virt' from the value.
-			 */
-
-			if ((value >= pci_io_base_virt) && (value < (pci_io_base_virt +
-														 HADES_VIRT_IO_SIZE)))
-				value -= pci_io_base_virt;
-			else
-			{
-				if (value != 0xffffffff)
-					return PCIBIOS_SET_FAILED;
-			}
-		}
-		else
-		{
-			/*
-			 * Memory address. Check if the address is valid address on
-			 * the Hades (HADES_MEM_BASE <= value < HADES_MEM_BASE + HADES_MEM_SIZE) or
-			 * if the value is 0xffffffff. If not true do not write
-			 * the base address register. If it is a valid base address
-			 * subtract HADES_MEM_BASE from the value.
-			 */
-
-			if ((value >= HADES_MEM_BASE) && (value < (HADES_MEM_BASE + HADES_MEM_SIZE)))
-				value -= HADES_MEM_BASE;
-			else
-			{
-				if (value != 0xffffffff)
-					return PCIBIOS_SET_FAILED;
-			}
-		}
-	}
-
-	*pci_addr = cpu_to_le32(value);
-
-	return PCIBIOS_SUCCESSFUL;
-}
-
-/*
- * static inline void hades_fixup(void)
- *
- * Assign IRQ numbers as used by Linux to the interrupt pins
- * of the PCI cards.
- */
-
-static void __init hades_fixup(int pci_modify)
-{
-	char irq_tab[4] = {
-		[0] = IRQ_TT_MFP_IO0,		/* Slot 0. */
-		[1] = IRQ_TT_MFP_IO1,		/* Slot 1. */
-		[2] = IRQ_TT_MFP_SCC,		/* Slot 2. */
-		[3] = IRQ_TT_MFP_SCSIDMA	/* Slot 3. */
-	};
-	struct pci_dev *dev = NULL;
-	unsigned char slot;
-
-	/*
-	 * Go through all devices, fixing up irqs as we see fit:
-	 */
-
-	while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL)
-	{
-		if (dev->class >> 16 != PCI_BASE_CLASS_BRIDGE)
-		{
-			slot = PCI_SLOT(dev->devfn);	/* Determine slot number. */
-			dev->irq = irq_tab[slot];
-			if (pci_modify)
-				pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
-		}
-	}
-}
-
-/*
- * static void hades_conf_device(struct pci_dev *dev)
- *
- * Machine dependent Configure the given device.
- *
- * Parameters:
- *
- * dev		- the pci device.
- */
-
-static void __init hades_conf_device(struct pci_dev *dev)
-{
-	pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, 0);
-}
-
-static struct pci_ops hades_pci_ops = {
-	.read_byte =	hades_read_config_byte,
-	.read_word =	hades_read_config_word,
-	.read_dword =	hades_read_config_dword,
-	.write_byte =	hades_write_config_byte,
-	.write_word =	hades_write_config_word,
-	.write_dword =	hades_write_config_dword
-};
-
-/*
- * struct pci_bus_info *init_hades_pci(void)
- *
- * Machine specific initialisation:
- *
- * - Allocate and initialise a 'pci_bus_info' structure
- * - Initialise hardware
- *
- * Result: pointer to 'pci_bus_info' structure.
- */
-
-struct pci_bus_info * __init init_hades_pci(void)
-{
-	struct pci_bus_info *bus;
-	int i;
-
-	/*
-	 * Remap I/O and configuration space.
-	 */
-
-	pci_io_base_virt = (unsigned long) ioremap(HADES_IO_BASE, HADES_VIRT_IO_SIZE);
-
-	for (i = 0; i < N_SLOTS; i++)
-		pci_conf_base_virt[i] = (unsigned long) ioremap(pci_conf_base_phys[i], 0x10000);
-
-	/*
-	 * Allocate memory for bus info structure.
-	 */
-
-	bus = kzalloc(sizeof(struct pci_bus_info), GFP_KERNEL);
-	if (unlikely(!bus))
-		goto iounmap_base_virt;
-
-	/*
-	 * Claim resources. The m68k has no separate I/O space, both
-	 * PCI memory space and PCI I/O space are in memory space. Therefore
-	 * the I/O resources are requested in memory space as well.
-	 */
-
-	if (unlikely(request_resource(&iomem_resource, &config_space) != 0))
-		goto free_bus;
-
-	if (unlikely(request_resource(&iomem_resource, &io_space) != 0))
-		goto release_config_space;
-
-	bus->mem_space.start = HADES_MEM_BASE;
-	bus->mem_space.end = HADES_MEM_BASE + HADES_MEM_SIZE - 1;
-	bus->mem_space.name = pci_mem_name;
-#if 1
-	if (unlikely(request_resource(&iomem_resource, &bus->mem_space) != 0))
-		goto release_io_space;
-#endif
-	bus->io_space.start = pci_io_base_virt;
-	bus->io_space.end = pci_io_base_virt + HADES_VIRT_IO_SIZE - 1;
-	bus->io_space.name = pci_io_name;
-#if 1
-	if (unlikely(request_resource(&ioport_resource, &bus->io_space) != 0))
-		goto release_bus_mem_space;
-#endif
-	/*
-	 * Set hardware dependent functions.
-	 */
-
-	bus->m68k_pci_ops = &hades_pci_ops;
-	bus->fixup = hades_fixup;
-	bus->conf_device = hades_conf_device;
-
-	/*
-	 * Select high to low edge for PCI interrupts.
-	 */
-
-	tt_mfp.active_edge &= ~0x27;
-
-	return bus;
-
-release_bus_mem_space:
-	release_resource(&bus->mem_space);
-release_io_space:
-	release_resource(&io_space);
-release_config_space:
-	release_resource(&config_space);
-free_bus:
-	kfree(bus);
-iounmap_base_virt:
-	iounmap((void *)pci_io_base_virt);
-
-	for (i = 0; i < N_SLOTS; i++)
-		iounmap((void *)pci_conf_base_virt[i]);
-
-	return NULL;
-}
-#endif
diff --git a/arch/m68k/atari/time.c b/arch/m68k/atari/time.c
index e0d3c8b..1edde27 100644
--- a/arch/m68k/atari/time.c
+++ b/arch/m68k/atari/time.c
@@ -20,6 +20,9 @@
 
 #include <asm/atariints.h>
 
+DEFINE_SPINLOCK(rtc_lock);
+EXPORT_SYMBOL_GPL(rtc_lock);
+
 void __init
 atari_sched_init(irq_handler_t timer_routine)
 {
@@ -191,13 +194,14 @@
         }
 
         if (!(ctrl & RTC_DM_BINARY)) {
-            BIN_TO_BCD(sec);
-            BIN_TO_BCD(min);
-            BIN_TO_BCD(hour);
-            BIN_TO_BCD(day);
-            BIN_TO_BCD(mon);
-            BIN_TO_BCD(year);
-            if (wday >= 0) BIN_TO_BCD(wday);
+	    sec = bin2bcd(sec);
+	    min = bin2bcd(min);
+	    hour = bin2bcd(hour);
+	    day = bin2bcd(day);
+	    mon = bin2bcd(mon);
+	    year = bin2bcd(year);
+	    if (wday >= 0)
+		wday = bin2bcd(wday);
         }
     }
 
@@ -252,13 +256,13 @@
 	}
 
 	if (!(ctrl & RTC_DM_BINARY)) {
-            BCD_TO_BIN(sec);
-            BCD_TO_BIN(min);
-            BCD_TO_BIN(hour);
-            BCD_TO_BIN(day);
-            BCD_TO_BIN(mon);
-            BCD_TO_BIN(year);
-            BCD_TO_BIN(wday);
+	    sec = bcd2bin(sec);
+	    min = bcd2bin(min);
+	    hour = bcd2bin(hour);
+	    day = bcd2bin(day);
+	    mon = bcd2bin(mon);
+	    year = bcd2bin(year);
+	    wday = bcd2bin(wday);
         }
 
         if (!(ctrl & RTC_24H)) {
@@ -318,7 +322,7 @@
 
     rtc_minutes = RTC_READ (RTC_MINUTES);
     if (!(save_control & RTC_DM_BINARY))
-        BCD_TO_BIN (rtc_minutes);
+	rtc_minutes = bcd2bin(rtc_minutes);
 
     /* Since we're only adjusting minutes and seconds, don't interfere
        with hour overflow.  This avoids messing with unknown time zones
@@ -329,8 +333,8 @@
         {
             if (!(save_control & RTC_DM_BINARY))
                 {
-                    BIN_TO_BCD (real_seconds);
-                    BIN_TO_BCD (real_minutes);
+		    real_seconds = bin2bcd(real_seconds);
+		    real_minutes = bin2bcd(real_minutes);
                 }
             RTC_WRITE (RTC_SECONDS, real_seconds);
             RTC_WRITE (RTC_MINUTES, real_minutes);
diff --git a/arch/m68k/bvme6000/config.c b/arch/m68k/bvme6000/config.c
index 9433a88..65c9204 100644
--- a/arch/m68k/bvme6000/config.c
+++ b/arch/m68k/bvme6000/config.c
@@ -25,6 +25,7 @@
 #include <linux/genhd.h>
 #include <linux/rtc.h>
 #include <linux/interrupt.h>
+#include <linux/bcd.h>
 
 #include <asm/bootinfo.h>
 #include <asm/system.h>
@@ -46,9 +47,6 @@
 extern void bvme6000_waitbut(void);
 void bvme6000_set_vectors (void);
 
-static unsigned char bcd2bin (unsigned char b);
-static unsigned char bin2bcd (unsigned char b);
-
 /* Save tick handler routine pointer, will point to do_timer() in
  * kernel/sched.c, called via bvme6000_process_int() */
 
@@ -264,17 +262,6 @@
     return v;
 }
 
-static unsigned char bcd2bin (unsigned char b)
-{
-	return ((b>>4)*10 + (b&15));
-}
-
-static unsigned char bin2bcd (unsigned char b)
-{
-	return (((b/10)*16) + (b%10));
-}
-
-
 /*
  * Looks like op is non-zero for setting the clock, and zero for
  * reading the clock.
diff --git a/arch/m68k/bvme6000/rtc.c b/arch/m68k/bvme6000/rtc.c
index e8ac3f7..808c901 100644
--- a/arch/m68k/bvme6000/rtc.c
+++ b/arch/m68k/bvme6000/rtc.c
@@ -57,16 +57,16 @@
 		rtc->msr = 0x40;
 		memset(&wtime, 0, sizeof(struct rtc_time));
 		do {
-			wtime.tm_sec =  BCD2BIN(rtc->bcd_sec);
-			wtime.tm_min =  BCD2BIN(rtc->bcd_min);
-			wtime.tm_hour = BCD2BIN(rtc->bcd_hr);
-			wtime.tm_mday =  BCD2BIN(rtc->bcd_dom);
-			wtime.tm_mon =  BCD2BIN(rtc->bcd_mth)-1;
-			wtime.tm_year = BCD2BIN(rtc->bcd_year);
+			wtime.tm_sec =  bcd2bin(rtc->bcd_sec);
+			wtime.tm_min =  bcd2bin(rtc->bcd_min);
+			wtime.tm_hour = bcd2bin(rtc->bcd_hr);
+			wtime.tm_mday =  bcd2bin(rtc->bcd_dom);
+			wtime.tm_mon =  bcd2bin(rtc->bcd_mth)-1;
+			wtime.tm_year = bcd2bin(rtc->bcd_year);
 			if (wtime.tm_year < 70)
 				wtime.tm_year += 100;
-			wtime.tm_wday = BCD2BIN(rtc->bcd_dow)-1;
-		} while (wtime.tm_sec != BCD2BIN(rtc->bcd_sec));
+			wtime.tm_wday = bcd2bin(rtc->bcd_dow)-1;
+		} while (wtime.tm_sec != bcd2bin(rtc->bcd_sec));
 		rtc->msr = msr;
 		local_irq_restore(flags);
 		return copy_to_user(argp, &wtime, sizeof wtime) ?
@@ -114,14 +114,14 @@
 
 		rtc->t0cr_rtmr = yrs%4;
 		rtc->bcd_tenms = 0;
-		rtc->bcd_sec   = BIN2BCD(sec);
-		rtc->bcd_min   = BIN2BCD(min);
-		rtc->bcd_hr    = BIN2BCD(hrs);
-		rtc->bcd_dom   = BIN2BCD(day);
-		rtc->bcd_mth   = BIN2BCD(mon);
-		rtc->bcd_year  = BIN2BCD(yrs%100);
+		rtc->bcd_sec   = bin2bcd(sec);
+		rtc->bcd_min   = bin2bcd(min);
+		rtc->bcd_hr    = bin2bcd(hrs);
+		rtc->bcd_dom   = bin2bcd(day);
+		rtc->bcd_mth   = bin2bcd(mon);
+		rtc->bcd_year  = bin2bcd(yrs%100);
 		if (rtc_tm.tm_wday >= 0)
-			rtc->bcd_dow = BIN2BCD(rtc_tm.tm_wday+1);
+			rtc->bcd_dow = bin2bcd(rtc_tm.tm_wday+1);
 		rtc->t0cr_rtmr = yrs%4 | 0x08;
 
 		rtc->msr = msr;
diff --git a/arch/m68k/kernel/Makefile b/arch/m68k/kernel/Makefile
index 3a7f622..55d5d6b 100644
--- a/arch/m68k/kernel/Makefile
+++ b/arch/m68k/kernel/Makefile
@@ -14,5 +14,4 @@
 
 devres-y = ../../../kernel/irq/devres.o
 
-obj-$(CONFIG_PCI)	+= bios32.o
 obj-y$(CONFIG_MMU_SUN3) += dma.o	# no, it's not a typo
diff --git a/arch/m68k/kernel/bios32.c b/arch/m68k/kernel/bios32.c
deleted file mode 100644
index af170c2b..0000000
--- a/arch/m68k/kernel/bios32.c
+++ /dev/null
@@ -1,514 +0,0 @@
-/*
- * bios32.c - PCI BIOS functions for m68k systems.
- *
- * Written by Wout Klaren.
- *
- * Based on the DEC Alpha bios32.c by Dave Rusling and David Mosberger.
- */
-
-#include <linux/init.h>
-#include <linux/kernel.h>
-
-#if 0
-# define DBG_DEVS(args)		printk args
-#else
-# define DBG_DEVS(args)
-#endif
-
-#ifdef CONFIG_PCI
-
-/*
- * PCI support for Linux/m68k. Currently only the Hades is supported.
- *
- * The support for PCI bridges in the DEC Alpha version has
- * been removed in this version.
- */
-
-#include <linux/pci.h>
-#include <linux/slab.h>
-#include <linux/mm.h>
-
-#include <asm/io.h>
-#include <asm/pci.h>
-#include <asm/uaccess.h>
-
-#define KB		1024
-#define MB		(1024*KB)
-#define GB		(1024*MB)
-
-#define MAJOR_REV	0
-#define MINOR_REV	5
-
-/*
- * Align VAL to ALIGN, which must be a power of two.
- */
-
-#define ALIGN(val,align)	(((val) + ((align) - 1)) & ~((align) - 1))
-
-/*
- * Offsets relative to the I/O and memory base addresses from where resources
- * are allocated.
- */
-
-#define IO_ALLOC_OFFSET		0x00004000
-#define MEM_ALLOC_OFFSET	0x04000000
-
-/*
- * Declarations of hardware specific initialisation functions.
- */
-
-extern struct pci_bus_info *init_hades_pci(void);
-
-/*
- * Bus info structure of the PCI bus. A pointer to this structure is
- * put in the sysdata member of the pci_bus structure.
- */
-
-static struct pci_bus_info *bus_info;
-
-static int pci_modify = 1;		/* If set, layout the PCI bus ourself. */
-static int skip_vga;			/* If set do not modify base addresses
-					   of vga cards.*/
-static int disable_pci_burst;		/* If set do not allow PCI bursts. */
-
-static unsigned int io_base;
-static unsigned int mem_base;
-
-/*
- * static void disable_dev(struct pci_dev *dev)
- *
- * Disable PCI device DEV so that it does not respond to I/O or memory
- * accesses.
- *
- * Parameters:
- *
- * dev	- device to disable.
- */
-
-static void __init disable_dev(struct pci_dev *dev)
-{
-	unsigned short cmd;
-
-	if (((dev->class >> 8 == PCI_CLASS_NOT_DEFINED_VGA) ||
-	     (dev->class >> 8 == PCI_CLASS_DISPLAY_VGA) ||
-	     (dev->class >> 8 == PCI_CLASS_DISPLAY_XGA)) && skip_vga)
-		return;
-
-	pci_read_config_word(dev, PCI_COMMAND, &cmd);
-
-	cmd &= (~PCI_COMMAND_IO & ~PCI_COMMAND_MEMORY & ~PCI_COMMAND_MASTER);
-	pci_write_config_word(dev, PCI_COMMAND, cmd);
-}
-
-/*
- * static void layout_dev(struct pci_dev *dev)
- *
- * Layout memory and I/O for a device.
- *
- * Parameters:
- *
- * device	- device to layout memory and I/O for.
- */
-
-static void __init layout_dev(struct pci_dev *dev)
-{
-	unsigned short cmd;
-	unsigned int base, mask, size, reg;
-	unsigned int alignto;
-	int i;
-
-	/*
-	 * Skip video cards if requested.
-	 */
-
-	if (((dev->class >> 8 == PCI_CLASS_NOT_DEFINED_VGA) ||
-	     (dev->class >> 8 == PCI_CLASS_DISPLAY_VGA) ||
-	     (dev->class >> 8 == PCI_CLASS_DISPLAY_XGA)) && skip_vga)
-		return;
-
-	pci_read_config_word(dev, PCI_COMMAND, &cmd);
-
-	for (reg = PCI_BASE_ADDRESS_0, i = 0; reg <= PCI_BASE_ADDRESS_5; reg += 4, i++)
-	{
-		/*
-		 * Figure out how much space and of what type this
-		 * device wants.
-		 */
-
-		pci_write_config_dword(dev, reg, 0xffffffff);
-		pci_read_config_dword(dev, reg, &base);
-
-		if (!base)
-		{
-			/* this base-address register is unused */
-			dev->resource[i].start = 0;
-			dev->resource[i].end = 0;
-			dev->resource[i].flags = 0;
-			continue;
-		}
-
-		/*
-		 * We've read the base address register back after
-		 * writing all ones and so now we must decode it.
-		 */
-
-		if (base & PCI_BASE_ADDRESS_SPACE_IO)
-		{
-			/*
-			 * I/O space base address register.
-			 */
-
-			cmd |= PCI_COMMAND_IO;
-
-			base &= PCI_BASE_ADDRESS_IO_MASK;
-			mask = (~base << 1) | 0x1;
-			size = (mask & base) & 0xffffffff;
-
-			/*
-			 * Align to multiple of size of minimum base.
-			 */
-
-			alignto = max_t(unsigned int, 0x040, size);
-			base = ALIGN(io_base, alignto);
-			io_base = base + size;
-			pci_write_config_dword(dev, reg, base | PCI_BASE_ADDRESS_SPACE_IO);
-
-			dev->resource[i].start = base;
-			dev->resource[i].end = dev->resource[i].start + size - 1;
-			dev->resource[i].flags = IORESOURCE_IO | PCI_BASE_ADDRESS_SPACE_IO;
-
-			DBG_DEVS(("layout_dev: IO address: %lX\n", base));
-		}
-		else
-		{
-			unsigned int type;
-
-			/*
-			 * Memory space base address register.
-			 */
-
-			cmd |= PCI_COMMAND_MEMORY;
-			type = base & PCI_BASE_ADDRESS_MEM_TYPE_MASK;
-			base &= PCI_BASE_ADDRESS_MEM_MASK;
-			mask = (~base << 1) | 0x1;
-			size = (mask & base) & 0xffffffff;
-			switch (type)
-			{
-			case PCI_BASE_ADDRESS_MEM_TYPE_32:
-			case PCI_BASE_ADDRESS_MEM_TYPE_64:
-				break;
-
-			case PCI_BASE_ADDRESS_MEM_TYPE_1M:
-				printk("bios32 WARNING: slot %d, function %d "
-				       "requests memory below 1MB---don't "
-				       "know how to do that.\n",
-				       PCI_SLOT(dev->devfn),
-				       PCI_FUNC(dev->devfn));
-				continue;
-			}
-
-			/*
-			 * Align to multiple of size of minimum base.
-			 */
-
-			alignto = max_t(unsigned int, 0x1000, size);
-			base = ALIGN(mem_base, alignto);
-			mem_base = base + size;
-			pci_write_config_dword(dev, reg, base);
-
-			dev->resource[i].start = base;
-			dev->resource[i].end = dev->resource[i].start + size - 1;
-			dev->resource[i].flags = IORESOURCE_MEM;
-
-			if (type == PCI_BASE_ADDRESS_MEM_TYPE_64)
-			{
-				/*
-				 * 64-bit address, set the highest 32 bits
-				 * to zero.
-				 */
-
-				reg += 4;
-				pci_write_config_dword(dev, reg, 0);
-
-				i++;
-				dev->resource[i].start = 0;
-				dev->resource[i].end = 0;
-				dev->resource[i].flags = 0;
-			}
-		}
-	}
-
-	/*
-	 * Enable device:
-	 */
-
-	if (dev->class >> 8 == PCI_CLASS_NOT_DEFINED ||
-	    dev->class >> 8 == PCI_CLASS_NOT_DEFINED_VGA ||
-	    dev->class >> 8 == PCI_CLASS_DISPLAY_VGA ||
-	    dev->class >> 8 == PCI_CLASS_DISPLAY_XGA)
-	{
-		/*
-		 * All of these (may) have I/O scattered all around
-		 * and may not use i/o-base address registers at all.
-		 * So we just have to always enable I/O to these
-		 * devices.
-		 */
-		cmd |= PCI_COMMAND_IO;
-	}
-
-	pci_write_config_word(dev, PCI_COMMAND, cmd | PCI_COMMAND_MASTER);
-
-	pci_write_config_byte(dev, PCI_LATENCY_TIMER, (disable_pci_burst) ? 0 : 32);
-
-	if (bus_info != NULL)
-		bus_info->conf_device(dev);	/* Machine dependent configuration. */
-
-	DBG_DEVS(("layout_dev: bus %d  slot 0x%x  VID 0x%x  DID 0x%x  class 0x%x\n",
-		  dev->bus->number, PCI_SLOT(dev->devfn), dev->vendor, dev->device, dev->class));
-}
-
-/*
- * static void layout_bus(struct pci_bus *bus)
- *
- * Layout memory and I/O for all devices on the given bus.
- *
- * Parameters:
- *
- * bus	- bus.
- */
-
-static void __init layout_bus(struct pci_bus *bus)
-{
-	unsigned int bio, bmem;
-	struct pci_dev *dev;
-
-	DBG_DEVS(("layout_bus: starting bus %d\n", bus->number));
-
-	if (!bus->devices && !bus->children)
-		return;
-
-	/*
-	 * Align the current bases on appropriate boundaries (4K for
-	 * IO and 1MB for memory).
-	 */
-
-	bio = io_base = ALIGN(io_base, 4*KB);
-	bmem = mem_base = ALIGN(mem_base, 1*MB);
-
-	/*
-	 * PCI devices might have been setup by a PCI BIOS emulation
-	 * running under TOS. In these cases there is a
-	 * window during which two devices may have an overlapping
-	 * address range. To avoid this causing trouble, we first
-	 * turn off the I/O and memory address decoders for all PCI
-	 * devices.  They'll be re-enabled only once all address
-	 * decoders are programmed consistently.
-	 */
-
-	DBG_DEVS(("layout_bus: disable_dev for bus %d\n", bus->number));
-
-	for (dev = bus->devices; dev; dev = dev->sibling)
-	{
-		if ((dev->class >> 16 != PCI_BASE_CLASS_BRIDGE) ||
-		    (dev->class >> 8 == PCI_CLASS_BRIDGE_PCMCIA))
-			disable_dev(dev);
-	}
-
-	/*
-	 * Allocate space to each device:
-	 */
-
-	DBG_DEVS(("layout_bus: starting bus %d devices\n", bus->number));
-
-	for (dev = bus->devices; dev; dev = dev->sibling)
-	{
-		if ((dev->class >> 16 != PCI_BASE_CLASS_BRIDGE) ||
-		    (dev->class >> 8 == PCI_CLASS_BRIDGE_PCMCIA))
-			layout_dev(dev);
-	}
-
-	DBG_DEVS(("layout_bus: bus %d finished\n", bus->number));
-}
-
-/*
- * static void pcibios_fixup(void)
- *
- * Layout memory and I/O of all devices on the PCI bus if 'pci_modify' is
- * true. This might be necessary because not every m68k machine with a PCI
- * bus has a PCI BIOS. This function should be called right after
- * pci_scan_bus() in pcibios_init().
- */
-
-static void __init pcibios_fixup(void)
-{
-	if (pci_modify)
-	{
-		/*
-		 * Set base addresses for allocation of I/O and memory space.
-		 */
-
-		io_base = bus_info->io_space.start + IO_ALLOC_OFFSET;
-		mem_base = bus_info->mem_space.start + MEM_ALLOC_OFFSET;
-
-		/*
-		 * Scan the tree, allocating PCI memory and I/O space.
-		 */
-
-		layout_bus(pci_bus_b(pci_root.next));
-	}
-
-	/*
-	 * Fix interrupt assignments, etc.
-	 */
-
-	bus_info->fixup(pci_modify);
-}
-
-/*
- * static void pcibios_claim_resources(struct pci_bus *bus)
- *
- * Claim all resources that are assigned to devices on the given bus.
- *
- * Parameters:
- *
- * bus	- bus.
- */
-
-static void __init pcibios_claim_resources(struct pci_bus *bus)
-{
-	struct pci_dev *dev;
-	int i;
-
-	while (bus)
-	{
-		for (dev = bus->devices; (dev != NULL); dev = dev->sibling)
-		{
-			for (i = 0; i < PCI_NUM_RESOURCES; i++)
-			{
-				struct resource *r = &dev->resource[i];
-				struct resource *pr;
-				struct pci_bus_info *bus_info = (struct pci_bus_info *) dev->sysdata;
-
-				if ((r->start == 0) || (r->parent != NULL))
-					continue;
-#if 1
-				if (r->flags & IORESOURCE_IO)
-					pr = &bus_info->io_space;
-				else
-					pr = &bus_info->mem_space;
-#else
-				if (r->flags & IORESOURCE_IO)
-					pr = &ioport_resource;
-				else
-					pr = &iomem_resource;
-#endif
-				if (request_resource(pr, r) < 0)
-				{
-					printk(KERN_ERR "PCI: Address space collision on region %d of device %s\n", i, dev->name);
-				}
-			}
-		}
-
-		if (bus->children)
-			pcibios_claim_resources(bus->children);
-
-		bus = bus->next;
-	}
-}
-
-/*
- * int pcibios_assign_resource(struct pci_dev *dev, int i)
- *
- * Assign a new address to a PCI resource.
- *
- * Parameters:
- *
- * dev	- device.
- * i	- resource.
- *
- * Result: 0 if successful.
- */
-
-int __init pcibios_assign_resource(struct pci_dev *dev, int i)
-{
-	struct resource *r = &dev->resource[i];
-	struct resource *pr = pci_find_parent_resource(dev, r);
-	unsigned long size = r->end + 1;
-
-	if (!pr)
-		return -EINVAL;
-
-	if (r->flags & IORESOURCE_IO)
-	{
-		if (size > 0x100)
-			return -EFBIG;
-
-		if (allocate_resource(pr, r, size, bus_info->io_space.start +
-				      IO_ALLOC_OFFSET,  bus_info->io_space.end, 1024))
-			return -EBUSY;
-	}
-	else
-	{
-		if (allocate_resource(pr, r, size, bus_info->mem_space.start +
-				      MEM_ALLOC_OFFSET, bus_info->mem_space.end, size))
-			return -EBUSY;
-	}
-
-	if (i < 6)
-		pci_write_config_dword(dev, PCI_BASE_ADDRESS_0 + 4 * i, r->start);
-
-	return 0;
-}
-
-void __init pcibios_fixup_bus(struct pci_bus *bus)
-{
-	struct pci_dev *dev;
-	void *sysdata;
-
-	sysdata = (bus->parent) ? bus->parent->sysdata : bus->sysdata;
-
-	for (dev = bus->devices; (dev != NULL); dev = dev->sibling)
-		dev->sysdata = sysdata;
-}
-
-void __init pcibios_init(void)
-{
-	printk("Linux/m68k PCI BIOS32 revision %x.%02x\n", MAJOR_REV, MINOR_REV);
-
-	bus_info = NULL;
-#ifdef CONFIG_HADES
-	if (MACH_IS_HADES)
-		bus_info = init_hades_pci();
-#endif
-	if (bus_info != NULL)
-	{
-		printk("PCI: Probing PCI hardware\n");
-		pci_scan_bus(0, bus_info->m68k_pci_ops, bus_info);
-		pcibios_fixup();
-		pcibios_claim_resources(pci_root);
-	}
-	else
-		printk("PCI: No PCI bus detected\n");
-}
-
-char * __init pcibios_setup(char *str)
-{
-	if (!strcmp(str, "nomodify"))
-	{
-		pci_modify = 0;
-		return NULL;
-	}
-	else if (!strcmp(str, "skipvga"))
-	{
-		skip_vga = 1;
-		return NULL;
-	}
-	else if (!strcmp(str, "noburst"))
-	{
-		disable_pci_burst = 1;
-		return NULL;
-	}
-
-	return str;
-}
-#endif /* CONFIG_PCI */
diff --git a/arch/m68k/kernel/dma.c b/arch/m68k/kernel/dma.c
index 6f8c080..2bb4245 100644
--- a/arch/m68k/kernel/dma.c
+++ b/arch/m68k/kernel/dma.c
@@ -66,8 +66,8 @@
 }
 EXPORT_SYMBOL(dma_free_coherent);
 
-inline void dma_sync_single_for_device(struct device *dev, dma_addr_t handle, size_t size,
-				       enum dma_data_direction dir)
+void dma_sync_single_for_device(struct device *dev, dma_addr_t handle,
+				size_t size, enum dma_data_direction dir)
 {
 	switch (dir) {
 	case DMA_TO_DEVICE:
diff --git a/arch/m68k/kernel/ints.c b/arch/m68k/kernel/ints.c
index ded7dd2..7e8a0d3 100644
--- a/arch/m68k/kernel/ints.c
+++ b/arch/m68k/kernel/ints.c
@@ -429,8 +429,9 @@
 	return 0;
 }
 
+#ifdef CONFIG_PROC_FS
 void init_irq_proc(void)
 {
 	/* Insert /proc/irq driver here */
 }
-
+#endif
diff --git a/arch/m68k/kernel/process.c b/arch/m68k/kernel/process.c
index 7888cdf..3042c2b 100644
--- a/arch/m68k/kernel/process.c
+++ b/arch/m68k/kernel/process.c
@@ -78,7 +78,7 @@
 static void default_idle(void)
 {
 	if (!need_resched())
-#if defined(MACH_ATARI_ONLY) && !defined(CONFIG_HADES)
+#if defined(MACH_ATARI_ONLY)
 		/* block out HSYNC on the atari (falcon) */
 		__asm__("stop #0x2200" : : : "cc");
 #else
diff --git a/arch/m68k/kernel/traps.c b/arch/m68k/kernel/traps.c
index 75b8340..6d813de 100644
--- a/arch/m68k/kernel/traps.c
+++ b/arch/m68k/kernel/traps.c
@@ -883,8 +883,7 @@
 			if (i % 5 == 0)
 				printk("\n       ");
 #endif
-			printk(" [<%08lx>]", addr);
-			print_symbol(" %s\n", addr);
+			printk(" [<%08lx>] %pS\n", addr, (void *)addr);
 			i++;
 		}
 	}
@@ -900,10 +899,8 @@
 	int i;
 
 	print_modules();
-	printk("PC: [<%08lx>]",regs->pc);
-	print_symbol(" %s", regs->pc);
-	printk("\nSR: %04x  SP: %p  a2: %08lx\n",
-	       regs->sr, regs, regs->a2);
+	printk("PC: [<%08lx>] %pS\n", regs->pc, (void *)regs->pc);
+	printk("SR: %04x  SP: %p  a2: %08lx\n", regs->sr, regs, regs->a2);
 	printk("d0: %08lx    d1: %08lx    d2: %08lx    d3: %08lx\n",
 	       regs->d0, regs->d1, regs->d2, regs->d3);
 	printk("d4: %08lx    d5: %08lx    a0: %08lx    a1: %08lx\n",
diff --git a/arch/m68k/kernel/vmlinux-std.lds b/arch/m68k/kernel/vmlinux-std.lds
index 99b0784..f846d4e 100644
--- a/arch/m68k/kernel/vmlinux-std.lds
+++ b/arch/m68k/kernel/vmlinux-std.lds
@@ -34,10 +34,10 @@
 	CONSTRUCTORS
 	}
 
-  .bss : { *(.bss) }		/* BSS */
-
   . = ALIGN(16);
-  .data.cacheline_aligned : { *(.data.cacheline_aligned) } :data
+  .data.cacheline_aligned : { *(.data.cacheline_aligned) }
+
+  .bss : { *(.bss) }		/* BSS */
 
   _edata = .;			/* End of data section */
 
@@ -48,7 +48,7 @@
 	_sinittext = .;
 	INIT_TEXT
 	_einittext = .;
-  }
+  } :data
   .init.data : { INIT_DATA }
   . = ALIGN(16);
   __setup_start = .;
@@ -74,6 +74,7 @@
   .init.ramfs : { *(.init.ramfs) }
   __initramfs_end = .;
 #endif
+  NOTES
   . = ALIGN(8192);
   __init_end = .;
 
diff --git a/arch/m68k/mm/kmap.c b/arch/m68k/mm/kmap.c
index 46b7d60..df620ac 100644
--- a/arch/m68k/mm/kmap.c
+++ b/arch/m68k/mm/kmap.c
@@ -66,8 +66,10 @@
 	for (p = &iolist; (tmp = *p) ; p = &tmp->next) {
 		if (size + addr < (unsigned long)tmp->addr)
 			break;
-		if (addr > KMAP_END-size)
+		if (addr > KMAP_END-size) {
+			kfree(area);
 			return NULL;
+		}
 		addr = tmp->size + (unsigned long)tmp->addr;
 	}
 	area->addr = (void *)addr;
diff --git a/arch/m68k/mvme16x/rtc.c b/arch/m68k/mvme16x/rtc.c
index 432a9f1..cea5e3e 100644
--- a/arch/m68k/mvme16x/rtc.c
+++ b/arch/m68k/mvme16x/rtc.c
@@ -52,15 +52,15 @@
 		/* Ensure clock and real-time-mode-register are accessible */
 		rtc->ctrl = RTC_READ;
 		memset(&wtime, 0, sizeof(struct rtc_time));
-		wtime.tm_sec =  BCD2BIN(rtc->bcd_sec);
-		wtime.tm_min =  BCD2BIN(rtc->bcd_min);
-		wtime.tm_hour = BCD2BIN(rtc->bcd_hr);
-		wtime.tm_mday =  BCD2BIN(rtc->bcd_dom);
-		wtime.tm_mon =  BCD2BIN(rtc->bcd_mth)-1;
-		wtime.tm_year = BCD2BIN(rtc->bcd_year);
+		wtime.tm_sec =  bcd2bin(rtc->bcd_sec);
+		wtime.tm_min =  bcd2bin(rtc->bcd_min);
+		wtime.tm_hour = bcd2bin(rtc->bcd_hr);
+		wtime.tm_mday =  bcd2bin(rtc->bcd_dom);
+		wtime.tm_mon =  bcd2bin(rtc->bcd_mth)-1;
+		wtime.tm_year = bcd2bin(rtc->bcd_year);
 		if (wtime.tm_year < 70)
 			wtime.tm_year += 100;
-		wtime.tm_wday = BCD2BIN(rtc->bcd_dow)-1;
+		wtime.tm_wday = bcd2bin(rtc->bcd_dow)-1;
 		rtc->ctrl = 0;
 		local_irq_restore(flags);
 		return copy_to_user(argp, &wtime, sizeof wtime) ?
@@ -104,12 +104,12 @@
 		local_irq_save(flags);
 		rtc->ctrl     = RTC_WRITE;
 
-		rtc->bcd_sec  = BIN2BCD(sec);
-		rtc->bcd_min  = BIN2BCD(min);
-		rtc->bcd_hr   = BIN2BCD(hrs);
-		rtc->bcd_dom  = BIN2BCD(day);
-		rtc->bcd_mth  = BIN2BCD(mon);
-		rtc->bcd_year = BIN2BCD(yrs%100);
+		rtc->bcd_sec  = bin2bcd(sec);
+		rtc->bcd_min  = bin2bcd(min);
+		rtc->bcd_hr   = bin2bcd(hrs);
+		rtc->bcd_dom  = bin2bcd(day);
+		rtc->bcd_mth  = bin2bcd(mon);
+		rtc->bcd_year = bin2bcd(yrs%100);
 
 		rtc->ctrl     = 0;
 		local_irq_restore(flags);
diff --git a/arch/m68k/q40/config.c b/arch/m68k/q40/config.c
index be9de2f..9c7eefa 100644
--- a/arch/m68k/q40/config.c
+++ b/arch/m68k/q40/config.c
@@ -23,6 +23,7 @@
 #include <linux/serial_reg.h>
 #include <linux/rtc.h>
 #include <linux/vt_kern.h>
+#include <linux/bcd.h>
 
 #include <asm/io.h>
 #include <asm/rtc.h>
@@ -216,17 +217,6 @@
 }
 
 
-static inline unsigned char bcd2bin(unsigned char b)
-{
-	return (b >> 4) * 10 + (b & 15);
-}
-
-static inline unsigned char bin2bcd(unsigned char b)
-{
-	return (b / 10) * 16 + (b % 10);
-}
-
-
 static unsigned long q40_gettimeoffset(void)
 {
 	return 5000 * (ql_ticks != 0);
diff --git a/arch/m68k/sun3x/time.c b/arch/m68k/sun3x/time.c
index f5eaafb..536a04a 100644
--- a/arch/m68k/sun3x/time.c
+++ b/arch/m68k/sun3x/time.c
@@ -47,23 +47,23 @@
 
 	if(set) {
 		h->csr |= C_WRITE;
-		h->sec = BIN2BCD(t->tm_sec);
-		h->min = BIN2BCD(t->tm_min);
-		h->hour = BIN2BCD(t->tm_hour);
-		h->wday = BIN2BCD(t->tm_wday);
-		h->mday = BIN2BCD(t->tm_mday);
-		h->month = BIN2BCD(t->tm_mon);
-		h->year = BIN2BCD(t->tm_year);
+		h->sec = bin2bcd(t->tm_sec);
+		h->min = bin2bcd(t->tm_min);
+		h->hour = bin2bcd(t->tm_hour);
+		h->wday = bin2bcd(t->tm_wday);
+		h->mday = bin2bcd(t->tm_mday);
+		h->month = bin2bcd(t->tm_mon);
+		h->year = bin2bcd(t->tm_year);
 		h->csr &= ~C_WRITE;
 	} else {
 		h->csr |= C_READ;
-		t->tm_sec = BCD2BIN(h->sec);
-		t->tm_min = BCD2BIN(h->min);
-		t->tm_hour = BCD2BIN(h->hour);
-		t->tm_wday = BCD2BIN(h->wday);
-		t->tm_mday = BCD2BIN(h->mday);
-		t->tm_mon = BCD2BIN(h->month);
-		t->tm_year = BCD2BIN(h->year);
+		t->tm_sec = bcd2bin(h->sec);
+		t->tm_min = bcd2bin(h->min);
+		t->tm_hour = bcd2bin(h->hour);
+		t->tm_wday = bcd2bin(h->wday);
+		t->tm_mday = bcd2bin(h->mday);
+		t->tm_mon = bcd2bin(h->month);
+		t->tm_year = bcd2bin(h->year);
 		h->csr &= ~C_READ;
 	}
 
diff --git a/arch/m68knommu/Kconfig b/arch/m68knommu/Kconfig
index 2e7515e..0a89983 100644
--- a/arch/m68knommu/Kconfig
+++ b/arch/m68knommu/Kconfig
@@ -73,9 +73,6 @@
 config NO_IOPORT
 	def_bool y
 
-config ARCH_SUPPORTS_AOUT
-	def_bool y
-
 source "init/Kconfig"
 
 menu "Processor type and features"
diff --git a/arch/m68knommu/include/asm/a.out.h b/arch/m68knommu/include/asm/a.out.h
deleted file mode 100644
index ce18ef9..0000000
--- a/arch/m68knommu/include/asm/a.out.h
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-m68k/a.out.h>
diff --git a/arch/m68knommu/kernel/process.c b/arch/m68knommu/kernel/process.c
index 47502d5..3f2d774 100644
--- a/arch/m68knommu/kernel/process.c
+++ b/arch/m68knommu/kernel/process.c
@@ -25,7 +25,6 @@
 #include <linux/ptrace.h>
 #include <linux/slab.h>
 #include <linux/user.h>
-#include <linux/a.out.h>
 #include <linux/interrupt.h>
 #include <linux/reboot.h>
 #include <linux/fs.h>
diff --git a/arch/m68knommu/kernel/traps.c b/arch/m68knommu/kernel/traps.c
index 46f8f9d..5d5d56b 100644
--- a/arch/m68knommu/kernel/traps.c
+++ b/arch/m68knommu/kernel/traps.c
@@ -22,7 +22,6 @@
 #include <linux/mm.h>
 #include <linux/module.h>
 #include <linux/types.h>
-#include <linux/a.out.h>
 #include <linux/user.h>
 #include <linux/string.h>
 #include <linux/linkage.h>
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index 49896a2..cd5fbf6 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -211,6 +211,7 @@
 	select SYS_SUPPORTS_64BIT_KERNEL
 	select SYS_SUPPORTS_BIG_ENDIAN
 	select SYS_SUPPORTS_LITTLE_ENDIAN
+	select SYS_SUPPORTS_MIPS_CMP if BROKEN	# because SYNC_R4K is broken
 	select SYS_SUPPORTS_MULTITHREADING
 	select SYS_SUPPORTS_SMARTMIPS
 	help
@@ -567,7 +568,7 @@
 	select SYS_SUPPORTS_LITTLE_ENDIAN
 	select SWAP_IO_SPACE
 	select BOOT_RAW
-	select GENERIC_GPIO
+	select ARCH_REQUIRE_GPIOLIB
 	help
 	  Support the Mikrotik(tm) RouterBoard 532 series,
 	  based on the IDT RC32434 SoC.
@@ -597,7 +598,7 @@
 
 endchoice
 
-source "arch/mips/au1000/Kconfig"
+source "arch/mips/alchemy/Kconfig"
 source "arch/mips/basler/excite/Kconfig"
 source "arch/mips/jazz/Kconfig"
 source "arch/mips/lasat/Kconfig"
@@ -609,11 +610,6 @@
 
 endmenu
 
-config GENERIC_LOCKBREAK
-	bool
-	default y
-	depends on SMP && PREEMPT
-
 config RWSEM_GENERIC_SPINLOCK
 	bool
 	default y
@@ -1272,6 +1268,13 @@
 config CPU_SUPPORTS_64BIT_KERNEL
 	bool
 
+#
+# Set to y for ptrace access to watch registers.
+#
+config HARDWARE_WATCHPOINTS
+       bool
+       default y if CPU_MIPS32 || CPU_MIPS64
+
 menu "Kernel type"
 
 choice
@@ -1403,7 +1406,6 @@
 	depends on CPU_MIPS32_R2
 	#depends on CPU_MIPS64_R2		# once there is hardware ...
 	depends on SYS_SUPPORTS_MULTITHREADING
-	select GENERIC_CLOCKEVENTS_BROADCAST
 	select CPU_MIPSR2_IRQ_VI
 	select CPU_MIPSR2_IRQ_EI
 	select MIPS_MT
@@ -1451,32 +1453,17 @@
 	  Includes a loader for loading an elf relocatable object
 	  onto another VPE and running it.
 
-config MIPS_MT_SMTC_INSTANT_REPLAY
-	bool "Low-latency Dispatch of Deferred SMTC IPIs"
-	depends on MIPS_MT_SMTC && !PREEMPT
-	default y
-	help
-	  SMTC pseudo-interrupts between TCs are deferred and queued
-	  if the target TC is interrupt-inhibited (IXMT). In the first
-	  SMTC prototypes, these queued IPIs were serviced on return
-	  to user mode, or on entry into the kernel idle loop. The
-	  INSTANT_REPLAY option dispatches them as part of local_irq_restore()
-	  processing, which adds runtime overhead (hence the option to turn
-	  it off), but ensures that IPIs are handled promptly even under
-	  heavy I/O interrupt load.
-
 config MIPS_MT_SMTC_IM_BACKSTOP
 	bool "Use per-TC register bits as backstop for inhibited IM bits"
 	depends on MIPS_MT_SMTC
-	default y
+	default n
 	help
 	  To support multiple TC microthreads acting as "CPUs" within
 	  a VPE, VPE-wide interrupt mask bits must be specially manipulated
 	  during interrupt handling. To support legacy drivers and interrupt
 	  controller management code, SMTC has a "backstop" to track and
 	  if necessary restore the interrupt mask. This has some performance
-	  impact on interrupt service overhead. Disable it only if you know
-	  what you are doing.
+	  impact on interrupt service overhead.
 
 config MIPS_MT_SMTC_IRQAFF
 	bool "Support IRQ affinity API"
@@ -1486,10 +1473,8 @@
 	  Enables SMP IRQ affinity API (/proc/irq/*/smp_affinity, etc.)
 	  for SMTC Linux kernel. Requires platform support, of which
 	  an example can be found in the MIPS kernel i8259 and Malta
-	  platform code.  It is recommended that MIPS_MT_SMTC_INSTANT_REPLAY
-	  be enabled if MIPS_MT_SMTC_IRQAFF is used. Adds overhead to
-	  interrupt dispatch, and should be used only if you know what
-	  you are doing.
+	  platform code.  Adds some overhead to interrupt dispatch, and
+	  should be used only if you know what you are doing.
 
 config MIPS_VPE_LOADER_TOM
 	bool "Load VPE program into memory hidden from linux"
@@ -1517,6 +1502,18 @@
 	  "exit" syscall notifying other kernel modules the SP program is
 	  exiting.  You probably want to say yes here.
 
+config MIPS_CMP
+	bool "MIPS CMP framework support"
+	depends on SYS_SUPPORTS_MIPS_CMP
+	select SYNC_R4K if BROKEN
+	select SYS_SUPPORTS_SMP
+	select SYS_SUPPORTS_SCHED_SMT if SMP
+	select WEAK_ORDERING
+	default n
+	help
+	  This is a placeholder option for the GCMP work. It will need to
+	  be handled differently...
+
 config SB1_PASS_1_WORKAROUNDS
 	bool
 	depends on CPU_SB1_PASS_1
@@ -1693,6 +1690,9 @@
 config SMP_UP
 	bool
 
+config SYS_SUPPORTS_MIPS_CMP
+	bool
+
 config SYS_SUPPORTS_SMP
 	bool
 
@@ -1740,17 +1740,6 @@
 	  performance should round up your number of processors to the next
 	  power of two.
 
-config MIPS_CMP
-	bool "MIPS CMP framework support"
-	depends on SMP
-	select SYNC_R4K
-	select SYS_SUPPORTS_SCHED_SMT
-	select WEAK_ORDERING
-	default n
-	help
-	  This is a placeholder option for the GCMP work. It will need to
-	  be handled differently...
-
 source "kernel/time/Kconfig"
 
 #
diff --git a/arch/mips/Makefile b/arch/mips/Makefile
index 9aab51ca..7f39fd8 100644
--- a/arch/mips/Makefile
+++ b/arch/mips/Makefile
@@ -170,123 +170,123 @@
 # Acer PICA 61, Mips Magnum 4000 and Olivetti M700.
 #
 core-$(CONFIG_MACH_JAZZ)	+= arch/mips/jazz/
-cflags-$(CONFIG_MACH_JAZZ)	+= -Iinclude/asm-mips/mach-jazz
+cflags-$(CONFIG_MACH_JAZZ)	+= -I$(srctree)/arch/mips/include/asm/mach-jazz
 load-$(CONFIG_MACH_JAZZ)	+= 0xffffffff80080000
 
 #
 # Common Alchemy Au1x00 stuff
 #
-core-$(CONFIG_SOC_AU1X00)	+= arch/mips/au1000/common/
-cflags-$(CONFIG_SOC_AU1X00)	+= -Iinclude/asm-mips/mach-au1x00
+core-$(CONFIG_SOC_AU1X00)	+= arch/mips/alchemy/common/
+cflags-$(CONFIG_SOC_AU1X00)	+= -I$(srctree)/arch/mips/include/asm/mach-au1x00
 
 #
 # AMD Alchemy Pb1000 eval board
 #
-libs-$(CONFIG_MIPS_PB1000)	+= arch/mips/au1000/pb1000/
-cflags-$(CONFIG_MIPS_PB1000)	+= -Iinclude/asm-mips/mach-pb1x00
+libs-$(CONFIG_MIPS_PB1000)	+= arch/mips/alchemy/pb1000/
+cflags-$(CONFIG_MIPS_PB1000)	+= -I$(srctree)/arch/mips/include/asm/mach-pb1x00
 load-$(CONFIG_MIPS_PB1000)	+= 0xffffffff80100000
 
 #
 # AMD Alchemy Pb1100 eval board
 #
-libs-$(CONFIG_MIPS_PB1100)	+= arch/mips/au1000/pb1100/
-cflags-$(CONFIG_MIPS_PB1100)	+= -Iinclude/asm-mips/mach-pb1x00
+libs-$(CONFIG_MIPS_PB1100)	+= arch/mips/alchemy/pb1100/
+cflags-$(CONFIG_MIPS_PB1100)	+= -I$(srctree)/arch/mips/include/asm/mach-pb1x00
 load-$(CONFIG_MIPS_PB1100)	+= 0xffffffff80100000
 
 #
 # AMD Alchemy Pb1500 eval board
 #
-libs-$(CONFIG_MIPS_PB1500)	+= arch/mips/au1000/pb1500/
-cflags-$(CONFIG_MIPS_PB1500)	+= -Iinclude/asm-mips/mach-pb1x00
+libs-$(CONFIG_MIPS_PB1500)	+= arch/mips/alchemy/pb1500/
+cflags-$(CONFIG_MIPS_PB1500)	+= -I$(srctree)/arch/mips/include/asm/mach-pb1x00
 load-$(CONFIG_MIPS_PB1500)	+= 0xffffffff80100000
 
 #
 # AMD Alchemy Pb1550 eval board
 #
-libs-$(CONFIG_MIPS_PB1550)	+= arch/mips/au1000/pb1550/
-cflags-$(CONFIG_MIPS_PB1550)	+= -Iinclude/asm-mips/mach-pb1x00
+libs-$(CONFIG_MIPS_PB1550)	+= arch/mips/alchemy/pb1550/
+cflags-$(CONFIG_MIPS_PB1550)	+= -I$(srctree)/arch/mips/include/asm/mach-pb1x00
 load-$(CONFIG_MIPS_PB1550)	+= 0xffffffff80100000
 
 #
 # AMD Alchemy Pb1200 eval board
 #
-libs-$(CONFIG_MIPS_PB1200)	+= arch/mips/au1000/pb1200/
-cflags-$(CONFIG_MIPS_PB1200)	+= -Iinclude/asm-mips/mach-pb1x00
+libs-$(CONFIG_MIPS_PB1200)	+= arch/mips/alchemy/pb1200/
+cflags-$(CONFIG_MIPS_PB1200)	+= -I$(srctree)/arch/mips/include/asm/mach-pb1x00
 load-$(CONFIG_MIPS_PB1200)	+= 0xffffffff80100000
 
 #
 # AMD Alchemy Db1000 eval board
 #
-libs-$(CONFIG_MIPS_DB1000)	+= arch/mips/au1000/db1x00/
-cflags-$(CONFIG_MIPS_DB1000)	+= -Iinclude/asm-mips/mach-db1x00
+libs-$(CONFIG_MIPS_DB1000)	+= arch/mips/alchemy/db1x00/
+cflags-$(CONFIG_MIPS_DB1000)	+= -I$(srctree)/arch/mips/include/asm/mach-db1x00
 load-$(CONFIG_MIPS_DB1000)	+= 0xffffffff80100000
 
 #
 # AMD Alchemy Db1100 eval board
 #
-libs-$(CONFIG_MIPS_DB1100)	+= arch/mips/au1000/db1x00/
-cflags-$(CONFIG_MIPS_DB1100)	+= -Iinclude/asm-mips/mach-db1x00
+libs-$(CONFIG_MIPS_DB1100)	+= arch/mips/alchemy/db1x00/
+cflags-$(CONFIG_MIPS_DB1100)	+= -I$(srctree)/arch/mips/include/asm/mach-db1x00
 load-$(CONFIG_MIPS_DB1100)	+= 0xffffffff80100000
 
 #
 # AMD Alchemy Db1500 eval board
 #
-libs-$(CONFIG_MIPS_DB1500)	+= arch/mips/au1000/db1x00/
-cflags-$(CONFIG_MIPS_DB1500)	+= -Iinclude/asm-mips/mach-db1x00
+libs-$(CONFIG_MIPS_DB1500)	+= arch/mips/alchemy/db1x00/
+cflags-$(CONFIG_MIPS_DB1500)	+= -I$(srctree)/arch/mips/include/asm/mach-db1x00
 load-$(CONFIG_MIPS_DB1500)	+= 0xffffffff80100000
 
 #
 # AMD Alchemy Db1550 eval board
 #
-libs-$(CONFIG_MIPS_DB1550)	+= arch/mips/au1000/db1x00/
-cflags-$(CONFIG_MIPS_DB1550)	+= -Iinclude/asm-mips/mach-db1x00
+libs-$(CONFIG_MIPS_DB1550)	+= arch/mips/alchemy/db1x00/
+cflags-$(CONFIG_MIPS_DB1550)	+= -I$(srctree)/arch/mips/include/asm/mach-db1x00
 load-$(CONFIG_MIPS_DB1550)	+= 0xffffffff80100000
 
 #
 # AMD Alchemy Db1200 eval board
 #
-libs-$(CONFIG_MIPS_DB1200)	+= arch/mips/au1000/pb1200/
-cflags-$(CONFIG_MIPS_DB1200)	+= -Iinclude/asm-mips/mach-db1x00
+libs-$(CONFIG_MIPS_DB1200)	+= arch/mips/alchemy/pb1200/
+cflags-$(CONFIG_MIPS_DB1200)	+= -I$(srctree)/arch/mips/include/asm/mach-db1x00
 load-$(CONFIG_MIPS_DB1200)	+= 0xffffffff80100000
 
 #
 # AMD Alchemy Bosporus eval board
 #
-libs-$(CONFIG_MIPS_BOSPORUS)	+= arch/mips/au1000/db1x00/
-cflags-$(CONFIG_MIPS_BOSPORUS)	+= -Iinclude/asm-mips/mach-db1x00
+libs-$(CONFIG_MIPS_BOSPORUS)	+= arch/mips/alchemy/db1x00/
+cflags-$(CONFIG_MIPS_BOSPORUS)	+= -I$(srctree)/arch/mips/include/asm/mach-db1x00
 load-$(CONFIG_MIPS_BOSPORUS)	+= 0xffffffff80100000
 
 #
 # AMD Alchemy Mirage eval board
 #
-libs-$(CONFIG_MIPS_MIRAGE)	+= arch/mips/au1000/db1x00/
-cflags-$(CONFIG_MIPS_MIRAGE)	+= -Iinclude/asm-mips/mach-db1x00
+libs-$(CONFIG_MIPS_MIRAGE)	+= arch/mips/alchemy/db1x00/
+cflags-$(CONFIG_MIPS_MIRAGE)	+= -I$(srctree)/arch/mips/include/asm/mach-db1x00
 load-$(CONFIG_MIPS_MIRAGE)	+= 0xffffffff80100000
 
 #
 # 4G-Systems eval board
 #
-libs-$(CONFIG_MIPS_MTX1)	+= arch/mips/au1000/mtx-1/
+libs-$(CONFIG_MIPS_MTX1)	+= arch/mips/alchemy/mtx-1/
 load-$(CONFIG_MIPS_MTX1)	+= 0xffffffff80100000
 
 #
 # MyCable eval board
 #
-libs-$(CONFIG_MIPS_XXS1500)	+= arch/mips/au1000/xxs1500/
+libs-$(CONFIG_MIPS_XXS1500)	+= arch/mips/alchemy/xxs1500/
 load-$(CONFIG_MIPS_XXS1500)	+= 0xffffffff80100000
 
 #
 # Cobalt Server
 #
 core-$(CONFIG_MIPS_COBALT)	+= arch/mips/cobalt/
-cflags-$(CONFIG_MIPS_COBALT)	+= -Iinclude/asm-mips/mach-cobalt
+cflags-$(CONFIG_MIPS_COBALT)	+= -I$(srctree)/arch/mips/include/asm/mach-cobalt
 load-$(CONFIG_MIPS_COBALT)	+= 0xffffffff80080000
 
 #
 # DECstation family
 #
 core-$(CONFIG_MACH_DECSTATION)	+= arch/mips/dec/
-cflags-$(CONFIG_MACH_DECSTATION)+= -Iinclude/asm-mips/mach-dec
+cflags-$(CONFIG_MACH_DECSTATION)+= -I$(srctree)/arch/mips/include/asm/mach-dec
 libs-$(CONFIG_MACH_DECSTATION)	+= arch/mips/dec/prom/
 load-$(CONFIG_MACH_DECSTATION)	+= 0xffffffff80040000
 
@@ -294,7 +294,7 @@
 # Wind River PPMC Board (4KC + GT64120)
 #
 core-$(CONFIG_WR_PPMC)		+= arch/mips/gt64120/wrppmc/
-cflags-$(CONFIG_WR_PPMC)		+= -Iinclude/asm-mips/mach-wrppmc
+cflags-$(CONFIG_WR_PPMC)		+= -I$(srctree)/arch/mips/include/asm/mach-wrppmc
 load-$(CONFIG_WR_PPMC)		+= 0xffffffff80100000
 
 #
@@ -302,13 +302,13 @@
 #
 core-$(CONFIG_LEMOTE_FULONG) +=arch/mips/lemote/lm2e/
 load-$(CONFIG_LEMOTE_FULONG) +=0xffffffff80100000
-cflags-$(CONFIG_LEMOTE_FULONG) += -Iinclude/asm-mips/mach-lemote
+cflags-$(CONFIG_LEMOTE_FULONG) += -I$(srctree)/arch/mips/include/asm/mach-lemote
 
 #
 # MIPS Malta board
 #
 core-$(CONFIG_MIPS_MALTA)	+= arch/mips/mti-malta/
-cflags-$(CONFIG_MIPS_MALTA)	+= -Iinclude/asm-mips/mach-malta
+cflags-$(CONFIG_MIPS_MALTA)	+= -I$(srctree)/arch/mips/include/asm/mach-malta
 load-$(CONFIG_MIPS_MALTA)	+= 0xffffffff80100000
 all-$(CONFIG_MIPS_MALTA)	:= vmlinux.bin
 
@@ -316,14 +316,14 @@
 # MIPS SIM
 #
 core-$(CONFIG_MIPS_SIM)		+= arch/mips/mipssim/
-cflags-$(CONFIG_MIPS_SIM)	+= -Iinclude/asm-mips/mach-mipssim
+cflags-$(CONFIG_MIPS_SIM)	+= -I$(srctree)/arch/mips/include/asm/mach-mipssim
 load-$(CONFIG_MIPS_SIM)		+= 0x80100000
 
 #
 # PMC-Sierra MSP SOCs
 #
 core-$(CONFIG_PMC_MSP)		+= arch/mips/pmc-sierra/msp71xx/
-cflags-$(CONFIG_PMC_MSP)	+= -Iinclude/asm-mips/pmc-sierra/msp71xx \
+cflags-$(CONFIG_PMC_MSP)	+= -I$(srctree)/arch/mips/include/asm/pmc-sierra/msp71xx \
 					-mno-branch-likely
 load-$(CONFIG_PMC_MSP)		+= 0xffffffff80100000
 
@@ -331,28 +331,28 @@
 # PMC-Sierra Yosemite
 #
 core-$(CONFIG_PMC_YOSEMITE)	+= arch/mips/pmc-sierra/yosemite/
-cflags-$(CONFIG_PMC_YOSEMITE)	+= -Iinclude/asm-mips/mach-yosemite
+cflags-$(CONFIG_PMC_YOSEMITE)	+= -I$(srctree)/arch/mips/include/asm/mach-yosemite
 load-$(CONFIG_PMC_YOSEMITE)	+= 0xffffffff80100000
 
 #
 # Basler eXcite
 #
 core-$(CONFIG_BASLER_EXCITE)	+= arch/mips/basler/excite/
-cflags-$(CONFIG_BASLER_EXCITE)	+= -Iinclude/asm-mips/mach-excite
+cflags-$(CONFIG_BASLER_EXCITE)	+= -I$(srctree)/arch/mips/include/asm/mach-excite
 load-$(CONFIG_BASLER_EXCITE)	+= 0x80100000
 
 #
 # LASAT platforms
 #
 core-$(CONFIG_LASAT)		+= arch/mips/lasat/
-cflags-$(CONFIG_LASAT)		+= -Iinclude/asm-mips/mach-lasat
+cflags-$(CONFIG_LASAT)		+= -I$(srctree)/arch/mips/include/asm/mach-lasat
 load-$(CONFIG_LASAT)		+= 0xffffffff80000000
 
 #
 # Common VR41xx
 #
 core-$(CONFIG_MACH_VR41XX)	+= arch/mips/vr41xx/common/
-cflags-$(CONFIG_MACH_VR41XX)	+= -Iinclude/asm-mips/mach-vr41xx
+cflags-$(CONFIG_MACH_VR41XX)	+= -I$(srctree)/arch/mips/include/asm/mach-vr41xx
 
 #
 # ZAO Networks Capcella (VR4131)
@@ -385,13 +385,13 @@
 # Common NXP PNX8550
 #
 core-$(CONFIG_SOC_PNX8550)	+= arch/mips/nxp/pnx8550/common/
-cflags-$(CONFIG_SOC_PNX8550)	+= -Iinclude/asm-mips/mach-pnx8550
+cflags-$(CONFIG_SOC_PNX8550)	+= -I$(srctree)/arch/mips/include/asm/mach-pnx8550
 
 #
 # NXP PNX8550 JBS board
 #
 libs-$(CONFIG_PNX8550_JBS)	+= arch/mips/nxp/pnx8550/jbs/
-#cflags-$(CONFIG_PNX8550_JBS)	+= -Iinclude/asm-mips/mach-pnx8550
+#cflags-$(CONFIG_PNX8550_JBS)	+= -I$(srctree)/arch/mips/include/asm/mach-pnx8550
 load-$(CONFIG_PNX8550_JBS)	+= 0xffffffff80060000
 
 # NXP PNX8550 STB810 board
@@ -402,7 +402,7 @@
 # NEC EMMA2RH boards
 #
 core-$(CONFIG_EMMA2RH)          += arch/mips/emma2rh/common/
-cflags-$(CONFIG_EMMA2RH)        += -Iinclude/asm-mips/mach-emma2rh
+cflags-$(CONFIG_EMMA2RH)        += -I$(srctree)/arch/mips/include/asm/mach-emma2rh
 
 # NEC EMMA2RH Mark-eins
 core-$(CONFIG_MARKEINS)         += arch/mips/emma2rh/markeins/
@@ -418,7 +418,7 @@
 # address by 8kb.
 #
 core-$(CONFIG_SGI_IP22)		+= arch/mips/sgi-ip22/
-cflags-$(CONFIG_SGI_IP22)	+= -Iinclude/asm-mips/mach-ip22
+cflags-$(CONFIG_SGI_IP22)	+= -I$(srctree)/arch/mips/include/asm/mach-ip22
 ifdef CONFIG_32BIT
 load-$(CONFIG_SGI_IP22)		+= 0xffffffff88002000
 endif
@@ -435,7 +435,7 @@
 #
 ifdef CONFIG_SGI_IP27
 core-$(CONFIG_SGI_IP27)		+= arch/mips/sgi-ip27/
-cflags-$(CONFIG_SGI_IP27)	+= -Iinclude/asm-mips/mach-ip27
+cflags-$(CONFIG_SGI_IP27)	+= -I$(srctree)/arch/mips/include/asm/mach-ip27
 ifdef CONFIG_MAPPED_KERNEL
 load-$(CONFIG_SGI_IP27)		+= 0xc00000004001c000
 OBJCOPYFLAGS			:= --change-addresses=0x3fffffff80000000
@@ -460,7 +460,7 @@
   endif
 endif
 core-$(CONFIG_SGI_IP28)		+= arch/mips/sgi-ip22/
-cflags-$(CONFIG_SGI_IP28)	+= -mr10k-cache-barrier=1 -Iinclude/asm-mips/mach-ip28
+cflags-$(CONFIG_SGI_IP28)	+= -mr10k-cache-barrier=1 -I$(srctree)/arch/mips/include/asm/mach-ip28
 load-$(CONFIG_SGI_IP28)		+= 0xa800000020004000
 
 #
@@ -472,7 +472,7 @@
 # will break.
 #
 core-$(CONFIG_SGI_IP32)		+= arch/mips/sgi-ip32/
-cflags-$(CONFIG_SGI_IP32)	+= -Iinclude/asm-mips/mach-ip32
+cflags-$(CONFIG_SGI_IP32)	+= -I$(srctree)/arch/mips/include/asm/mach-ip32
 load-$(CONFIG_SGI_IP32)		+= 0xffffffff80004000
 
 #
@@ -484,22 +484,22 @@
 #
 core-$(CONFIG_SIBYTE_BCM112X)	+= arch/mips/sibyte/sb1250/
 core-$(CONFIG_SIBYTE_BCM112X)	+= arch/mips/sibyte/common/
-cflags-$(CONFIG_SIBYTE_BCM112X)	+= -Iinclude/asm-mips/mach-sibyte \
+cflags-$(CONFIG_SIBYTE_BCM112X)	+= -I$(srctree)/arch/mips/include/asm/mach-sibyte \
 			-DSIBYTE_HDR_FEATURES=SIBYTE_HDR_FMASK_1250_112x_ALL
 
 core-$(CONFIG_SIBYTE_SB1250)	+= arch/mips/sibyte/sb1250/
 core-$(CONFIG_SIBYTE_SB1250)	+= arch/mips/sibyte/common/
-cflags-$(CONFIG_SIBYTE_SB1250)	+= -Iinclude/asm-mips/mach-sibyte \
+cflags-$(CONFIG_SIBYTE_SB1250)	+= -I$(srctree)/arch/mips/include/asm/mach-sibyte \
 			-DSIBYTE_HDR_FEATURES=SIBYTE_HDR_FMASK_1250_112x_ALL
 
 core-$(CONFIG_SIBYTE_BCM1x55)	+= arch/mips/sibyte/bcm1480/
 core-$(CONFIG_SIBYTE_BCM1x55)	+= arch/mips/sibyte/common/
-cflags-$(CONFIG_SIBYTE_BCM1x55)	+= -Iinclude/asm-mips/mach-sibyte \
+cflags-$(CONFIG_SIBYTE_BCM1x55)	+= -I$(srctree)/arch/mips/include/asm/mach-sibyte \
 			-DSIBYTE_HDR_FEATURES=SIBYTE_HDR_FMASK_1480_ALL
 
 core-$(CONFIG_SIBYTE_BCM1x80)	+= arch/mips/sibyte/bcm1480/
 core-$(CONFIG_SIBYTE_BCM1x80)	+= arch/mips/sibyte/common/
-cflags-$(CONFIG_SIBYTE_BCM1x80)	+= -Iinclude/asm-mips/mach-sibyte \
+cflags-$(CONFIG_SIBYTE_BCM1x80)	+= -I$(srctree)/arch/mips/include/asm/mach-sibyte \
 			-DSIBYTE_HDR_FEATURES=SIBYTE_HDR_FMASK_1480_ALL
 
 #
@@ -529,14 +529,14 @@
 # Broadcom BCM47XX boards
 #
 core-$(CONFIG_BCM47XX)		+= arch/mips/bcm47xx/
-cflags-$(CONFIG_BCM47XX)	+= -Iinclude/asm-mips/mach-bcm47xx
+cflags-$(CONFIG_BCM47XX)	+= -I$(srctree)/arch/mips/include/asm/mach-bcm47xx
 load-$(CONFIG_BCM47XX)		:= 0xffffffff80001000
 
 #
 # SNI RM
 #
 core-$(CONFIG_SNI_RM)		+= arch/mips/sni/
-cflags-$(CONFIG_SNI_RM)		+= -Iinclude/asm-mips/mach-rm
+cflags-$(CONFIG_SNI_RM)		+= -I$(srctree)/arch/mips/include/asm/mach-rm
 ifdef CONFIG_CPU_LITTLE_ENDIAN
 load-$(CONFIG_SNI_RM)		+= 0xffffffff80600000
 else
@@ -548,10 +548,10 @@
 # Common TXx9
 #
 core-$(CONFIG_MACH_TX39XX)	+= arch/mips/txx9/generic/
-cflags-$(CONFIG_MACH_TX39XX) += -Iinclude/asm-mips/mach-tx39xx
+cflags-$(CONFIG_MACH_TX39XX) += -I$(srctree)/arch/mips/include/asm/mach-tx39xx
 load-$(CONFIG_MACH_TX39XX)	+= 0xffffffff80050000
 core-$(CONFIG_MACH_TX49XX)	+= arch/mips/txx9/generic/
-cflags-$(CONFIG_MACH_TX49XX) += -Iinclude/asm-mips/mach-tx49xx
+cflags-$(CONFIG_MACH_TX49XX) += -I$(srctree)/arch/mips/include/asm/mach-tx49xx
 load-$(CONFIG_MACH_TX49XX)	+= 0xffffffff80100000
 
 #
@@ -563,21 +563,17 @@
 # Routerboard 532 board
 #
 core-$(CONFIG_MIKROTIK_RB532)	+= arch/mips/rb532/
-cflags-$(CONFIG_MIKROTIK_RB532) += -Iinclude/asm-mips/mach-rc32434
+cflags-$(CONFIG_MIKROTIK_RB532) += -I$(srctree)/arch/mips/include/asm/mach-rc32434
 load-$(CONFIG_MIKROTIK_RB532)	+= 0xffffffff80101000
 
 #
-# Toshiba RBTX4927 board or
-# Toshiba RBTX4937 board
+# Toshiba RBTX49XX boards
 #
 core-$(CONFIG_TOSHIBA_RBTX4927)	+= arch/mips/txx9/rbtx4927/
-
-#
-# Toshiba RBTX4938 board
-#
 core-$(CONFIG_TOSHIBA_RBTX4938) += arch/mips/txx9/rbtx4938/
+core-$(CONFIG_TOSHIBA_RBTX4939) += arch/mips/txx9/rbtx4939/
 
-cflags-y			+= -Iinclude/asm-mips/mach-generic
+cflags-y			+= -I$(srctree)/arch/mips/include/asm/mach-generic
 drivers-$(CONFIG_PCI)		+= arch/mips/pci/
 
 ifdef CONFIG_32BIT
diff --git a/arch/mips/au1000/Kconfig b/arch/mips/alchemy/Kconfig
similarity index 100%
rename from arch/mips/au1000/Kconfig
rename to arch/mips/alchemy/Kconfig
diff --git a/arch/mips/au1000/common/Makefile b/arch/mips/alchemy/common/Makefile
similarity index 100%
rename from arch/mips/au1000/common/Makefile
rename to arch/mips/alchemy/common/Makefile
diff --git a/arch/mips/au1000/common/au1xxx_irqmap.c b/arch/mips/alchemy/common/au1xxx_irqmap.c
similarity index 100%
rename from arch/mips/au1000/common/au1xxx_irqmap.c
rename to arch/mips/alchemy/common/au1xxx_irqmap.c
diff --git a/arch/mips/au1000/common/clocks.c b/arch/mips/alchemy/common/clocks.c
similarity index 100%
rename from arch/mips/au1000/common/clocks.c
rename to arch/mips/alchemy/common/clocks.c
diff --git a/arch/mips/au1000/common/cputable.c b/arch/mips/alchemy/common/cputable.c
similarity index 100%
rename from arch/mips/au1000/common/cputable.c
rename to arch/mips/alchemy/common/cputable.c
diff --git a/arch/mips/au1000/common/dbdma.c b/arch/mips/alchemy/common/dbdma.c
similarity index 100%
rename from arch/mips/au1000/common/dbdma.c
rename to arch/mips/alchemy/common/dbdma.c
diff --git a/arch/mips/au1000/common/dma.c b/arch/mips/alchemy/common/dma.c
similarity index 100%
rename from arch/mips/au1000/common/dma.c
rename to arch/mips/alchemy/common/dma.c
diff --git a/arch/mips/alchemy/common/gpio.c b/arch/mips/alchemy/common/gpio.c
new file mode 100644
index 0000000..e660ddd
--- /dev/null
+++ b/arch/mips/alchemy/common/gpio.c
@@ -0,0 +1,148 @@
+/*
+ *  Copyright (C) 2007, OpenWrt.org, Florian Fainelli <florian@openwrt.org>
+ *  	Architecture specific GPIO support
+ *
+ *  This program is free software; you can redistribute	 it and/or modify it
+ *  under  the terms of	 the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the	License, or (at your
+ *  option) any later version.
+ *
+ *  THIS  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.
+ *
+ *  Notes :
+ * 	au1000 SoC have only one GPIO line : GPIO1
+ * 	others have a second one : GPIO2
+ */
+
+#include <linux/module.h>
+
+#include <asm/mach-au1x00/au1000.h>
+#include <asm/gpio.h>
+
+#define gpio1 sys
+#if !defined(CONFIG_SOC_AU1000)
+
+static struct au1x00_gpio2 *const gpio2 = (struct au1x00_gpio2 *) GPIO2_BASE;
+#define GPIO2_OUTPUT_ENABLE_MASK 	0x00010000
+
+static int au1xxx_gpio2_read(unsigned gpio)
+{
+	gpio -= AU1XXX_GPIO_BASE;
+	return ((gpio2->pinstate >> gpio) & 0x01);
+}
+
+static void au1xxx_gpio2_write(unsigned gpio, int value)
+{
+	gpio -= AU1XXX_GPIO_BASE;
+
+	gpio2->output = (GPIO2_OUTPUT_ENABLE_MASK << gpio) | ((!!value) << gpio);
+}
+
+static int au1xxx_gpio2_direction_input(unsigned gpio)
+{
+	gpio -= AU1XXX_GPIO_BASE;
+	gpio2->dir &= ~(0x01 << gpio);
+	return 0;
+}
+
+static int au1xxx_gpio2_direction_output(unsigned gpio, int value)
+{
+	gpio -= AU1XXX_GPIO_BASE;
+	gpio2->dir |= 0x01 << gpio;
+	gpio2->output = (GPIO2_OUTPUT_ENABLE_MASK << gpio) | ((!!value) << gpio);
+	return 0;
+}
+
+#endif /* !defined(CONFIG_SOC_AU1000) */
+
+static int au1xxx_gpio1_read(unsigned gpio)
+{
+	return (gpio1->pinstaterd >> gpio) & 0x01;
+}
+
+static void au1xxx_gpio1_write(unsigned gpio, int value)
+{
+	if (value)
+		gpio1->outputset = (0x01 << gpio);
+	else
+		/* Output a zero */
+		gpio1->outputclr = (0x01 << gpio);
+}
+
+static int au1xxx_gpio1_direction_input(unsigned gpio)
+{
+	gpio1->pininputen = (0x01 << gpio);
+	return 0;
+}
+
+static int au1xxx_gpio1_direction_output(unsigned gpio, int value)
+{
+	gpio1->trioutclr = (0x01 & gpio);
+	au1xxx_gpio1_write(gpio, value);
+	return 0;
+}
+
+int au1xxx_gpio_get_value(unsigned gpio)
+{
+	if (gpio >= AU1XXX_GPIO_BASE)
+#if defined(CONFIG_SOC_AU1000)
+		return 0;
+#else
+		return au1xxx_gpio2_read(gpio);
+#endif
+	else
+		return au1xxx_gpio1_read(gpio);
+}
+EXPORT_SYMBOL(au1xxx_gpio_get_value);
+
+void au1xxx_gpio_set_value(unsigned gpio, int value)
+{
+	if (gpio >= AU1XXX_GPIO_BASE)
+#if defined(CONFIG_SOC_AU1000)
+		;
+#else
+		au1xxx_gpio2_write(gpio, value);
+#endif
+	else
+		au1xxx_gpio1_write(gpio, value);
+}
+EXPORT_SYMBOL(au1xxx_gpio_set_value);
+
+int au1xxx_gpio_direction_input(unsigned gpio)
+{
+	if (gpio >= AU1XXX_GPIO_BASE)
+#if defined(CONFIG_SOC_AU1000)
+		return -ENODEV;
+#else
+		return au1xxx_gpio2_direction_input(gpio);
+#endif
+
+	return au1xxx_gpio1_direction_input(gpio);
+}
+EXPORT_SYMBOL(au1xxx_gpio_direction_input);
+
+int au1xxx_gpio_direction_output(unsigned gpio, int value)
+{
+	if (gpio >= AU1XXX_GPIO_BASE)
+#if defined(CONFIG_SOC_AU1000)
+		return -ENODEV;
+#else
+		return au1xxx_gpio2_direction_output(gpio, value);
+#endif
+
+	return au1xxx_gpio1_direction_output(gpio, value);
+}
+EXPORT_SYMBOL(au1xxx_gpio_direction_output);
diff --git a/arch/mips/au1000/common/irq.c b/arch/mips/alchemy/common/irq.c
similarity index 100%
rename from arch/mips/au1000/common/irq.c
rename to arch/mips/alchemy/common/irq.c
diff --git a/arch/mips/au1000/common/pci.c b/arch/mips/alchemy/common/pci.c
similarity index 100%
rename from arch/mips/au1000/common/pci.c
rename to arch/mips/alchemy/common/pci.c
diff --git a/arch/mips/au1000/common/platform.c b/arch/mips/alchemy/common/platform.c
similarity index 100%
rename from arch/mips/au1000/common/platform.c
rename to arch/mips/alchemy/common/platform.c
diff --git a/arch/mips/au1000/common/power.c b/arch/mips/alchemy/common/power.c
similarity index 100%
rename from arch/mips/au1000/common/power.c
rename to arch/mips/alchemy/common/power.c
diff --git a/arch/mips/au1000/common/prom.c b/arch/mips/alchemy/common/prom.c
similarity index 100%
rename from arch/mips/au1000/common/prom.c
rename to arch/mips/alchemy/common/prom.c
diff --git a/arch/mips/au1000/common/puts.c b/arch/mips/alchemy/common/puts.c
similarity index 100%
rename from arch/mips/au1000/common/puts.c
rename to arch/mips/alchemy/common/puts.c
diff --git a/arch/mips/au1000/common/reset.c b/arch/mips/alchemy/common/reset.c
similarity index 100%
rename from arch/mips/au1000/common/reset.c
rename to arch/mips/alchemy/common/reset.c
diff --git a/arch/mips/au1000/common/setup.c b/arch/mips/alchemy/common/setup.c
similarity index 100%
rename from arch/mips/au1000/common/setup.c
rename to arch/mips/alchemy/common/setup.c
diff --git a/arch/mips/alchemy/common/sleeper.S b/arch/mips/alchemy/common/sleeper.S
new file mode 100644
index 0000000..3006e27
--- /dev/null
+++ b/arch/mips/alchemy/common/sleeper.S
@@ -0,0 +1,154 @@
+/*
+ * Copyright 2002 Embedded Edge, LLC
+ * Author: dan@embeddededge.com
+ *
+ * Sleep helper for Au1xxx sleep mode.
+ *
+ * This program is free software; you can redistribute	it and/or 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/asm.h>
+#include <asm/mipsregs.h>
+#include <asm/regdef.h>
+#include <asm/stackframe.h>
+
+	.text
+	.set	macro
+	.set	noat
+	.align	5
+
+/* Save all of the processor general registers and go to sleep.
+ * A wakeup condition will get us back here to restore the registers.
+ */
+LEAF(save_and_sleep)
+
+	subu	sp, PT_SIZE
+	sw	$1, PT_R1(sp)
+	sw	$2, PT_R2(sp)
+	sw	$3, PT_R3(sp)
+	sw	$4, PT_R4(sp)
+	sw	$5, PT_R5(sp)
+	sw	$6, PT_R6(sp)
+	sw	$7, PT_R7(sp)
+	sw	$8, PT_R8(sp)
+	sw	$9, PT_R9(sp)
+	sw	$10, PT_R10(sp)
+	sw	$11, PT_R11(sp)
+	sw	$12, PT_R12(sp)
+	sw	$13, PT_R13(sp)
+	sw	$14, PT_R14(sp)
+	sw	$15, PT_R15(sp)
+	sw	$16, PT_R16(sp)
+	sw	$17, PT_R17(sp)
+	sw	$18, PT_R18(sp)
+	sw	$19, PT_R19(sp)
+	sw	$20, PT_R20(sp)
+	sw	$21, PT_R21(sp)
+	sw	$22, PT_R22(sp)
+	sw	$23, PT_R23(sp)
+	sw	$24, PT_R24(sp)
+	sw	$25, PT_R25(sp)
+	sw	$26, PT_R26(sp)
+	sw	$27, PT_R27(sp)
+	sw	$28, PT_R28(sp)
+	sw	$29, PT_R29(sp)
+	sw	$30, PT_R30(sp)
+	sw	$31, PT_R31(sp)
+	mfc0	k0, CP0_STATUS
+	sw	k0, 0x20(sp)
+	mfc0	k0, CP0_CONTEXT
+	sw	k0, 0x1c(sp)
+	mfc0	k0, CP0_PAGEMASK
+	sw	k0, 0x18(sp)
+	mfc0	k0, CP0_CONFIG
+	sw	k0, 0x14(sp)
+
+	/* Now set up the scratch registers so the boot rom will
+	 * return to this point upon wakeup.
+	 */
+	la	k0, 1f
+	lui	k1, 0xb190
+	ori	k1, 0x18
+	sw	sp, 0(k1)
+	ori 	k1, 0x1c
+	sw	k0, 0(k1)
+
+/* Put SDRAM into self refresh.  Preload instructions into cache,
+ * issue a precharge, then auto refresh, then sleep commands to it.
+ */
+	la	t0, sdsleep
+	.set	mips3
+	cache	0x14, 0(t0)
+	cache	0x14, 32(t0)
+	cache	0x14, 64(t0)
+	cache	0x14, 96(t0)
+	.set	mips0
+
+sdsleep:
+	lui 	k0, 0xb400
+	sw	zero, 0x001c(k0)	/* Precharge */
+	sw	zero, 0x0020(k0)	/* Auto refresh */
+	sw	zero, 0x0030(k0)	/* SDRAM sleep */
+	sync
+
+	lui 	k1, 0xb190
+	sw	zero, 0x0078(k1)	/* get ready  to sleep */
+	sync
+	sw	zero, 0x007c(k1)	/* Put processor to sleep */
+	sync
+
+	/* This is where we return upon wakeup.
+	 * Reload all of the registers and return.
+	 */
+1:	nop
+	lw	k0, 0x20(sp)
+	mtc0	k0, CP0_STATUS
+	lw	k0, 0x1c(sp)
+	mtc0	k0, CP0_CONTEXT
+	lw	k0, 0x18(sp)
+	mtc0	k0, CP0_PAGEMASK
+	lw	k0, 0x14(sp)
+	mtc0	k0, CP0_CONFIG
+
+	/* We need to catch the ealry Alchemy SOCs with
+	 * the write-only Config[OD] bit and set it back to one...
+	 */
+	jal	au1x00_fixup_config_od
+	lw	$1, PT_R1(sp)
+	lw	$2, PT_R2(sp)
+	lw	$3, PT_R3(sp)
+	lw	$4, PT_R4(sp)
+	lw	$5, PT_R5(sp)
+	lw	$6, PT_R6(sp)
+	lw	$7, PT_R7(sp)
+	lw	$8, PT_R8(sp)
+	lw	$9, PT_R9(sp)
+	lw	$10, PT_R10(sp)
+	lw	$11, PT_R11(sp)
+	lw	$12, PT_R12(sp)
+	lw	$13, PT_R13(sp)
+	lw	$14, PT_R14(sp)
+	lw	$15, PT_R15(sp)
+	lw	$16, PT_R16(sp)
+	lw	$17, PT_R17(sp)
+	lw	$18, PT_R18(sp)
+	lw	$19, PT_R19(sp)
+	lw	$20, PT_R20(sp)
+	lw	$21, PT_R21(sp)
+	lw	$22, PT_R22(sp)
+	lw	$23, PT_R23(sp)
+	lw	$24, PT_R24(sp)
+	lw	$25, PT_R25(sp)
+	lw	$26, PT_R26(sp)
+	lw	$27, PT_R27(sp)
+	lw	$28, PT_R28(sp)
+	lw	$29, PT_R29(sp)
+	lw	$30, PT_R30(sp)
+	lw	$31, PT_R31(sp)
+	addiu	sp, PT_SIZE
+
+	jr	ra
+END(save_and_sleep)
diff --git a/arch/mips/au1000/common/time.c b/arch/mips/alchemy/common/time.c
similarity index 100%
rename from arch/mips/au1000/common/time.c
rename to arch/mips/alchemy/common/time.c
diff --git a/arch/mips/au1000/db1x00/Makefile b/arch/mips/alchemy/db1x00/Makefile
similarity index 100%
rename from arch/mips/au1000/db1x00/Makefile
rename to arch/mips/alchemy/db1x00/Makefile
diff --git a/arch/mips/au1000/db1x00/board_setup.c b/arch/mips/alchemy/db1x00/board_setup.c
similarity index 100%
rename from arch/mips/au1000/db1x00/board_setup.c
rename to arch/mips/alchemy/db1x00/board_setup.c
diff --git a/arch/mips/au1000/db1x00/init.c b/arch/mips/alchemy/db1x00/init.c
similarity index 100%
rename from arch/mips/au1000/db1x00/init.c
rename to arch/mips/alchemy/db1x00/init.c
diff --git a/arch/mips/au1000/db1x00/irqmap.c b/arch/mips/alchemy/db1x00/irqmap.c
similarity index 100%
rename from arch/mips/au1000/db1x00/irqmap.c
rename to arch/mips/alchemy/db1x00/irqmap.c
diff --git a/arch/mips/au1000/mtx-1/Makefile b/arch/mips/alchemy/mtx-1/Makefile
similarity index 100%
rename from arch/mips/au1000/mtx-1/Makefile
rename to arch/mips/alchemy/mtx-1/Makefile
diff --git a/arch/mips/au1000/mtx-1/board_setup.c b/arch/mips/alchemy/mtx-1/board_setup.c
similarity index 100%
rename from arch/mips/au1000/mtx-1/board_setup.c
rename to arch/mips/alchemy/mtx-1/board_setup.c
diff --git a/arch/mips/au1000/mtx-1/init.c b/arch/mips/alchemy/mtx-1/init.c
similarity index 100%
rename from arch/mips/au1000/mtx-1/init.c
rename to arch/mips/alchemy/mtx-1/init.c
diff --git a/arch/mips/au1000/mtx-1/irqmap.c b/arch/mips/alchemy/mtx-1/irqmap.c
similarity index 100%
rename from arch/mips/au1000/mtx-1/irqmap.c
rename to arch/mips/alchemy/mtx-1/irqmap.c
diff --git a/arch/mips/au1000/mtx-1/platform.c b/arch/mips/alchemy/mtx-1/platform.c
similarity index 100%
rename from arch/mips/au1000/mtx-1/platform.c
rename to arch/mips/alchemy/mtx-1/platform.c
diff --git a/arch/mips/au1000/pb1000/Makefile b/arch/mips/alchemy/pb1000/Makefile
similarity index 100%
rename from arch/mips/au1000/pb1000/Makefile
rename to arch/mips/alchemy/pb1000/Makefile
diff --git a/arch/mips/au1000/pb1000/board_setup.c b/arch/mips/alchemy/pb1000/board_setup.c
similarity index 100%
rename from arch/mips/au1000/pb1000/board_setup.c
rename to arch/mips/alchemy/pb1000/board_setup.c
diff --git a/arch/mips/au1000/pb1000/init.c b/arch/mips/alchemy/pb1000/init.c
similarity index 100%
rename from arch/mips/au1000/pb1000/init.c
rename to arch/mips/alchemy/pb1000/init.c
diff --git a/arch/mips/au1000/pb1000/irqmap.c b/arch/mips/alchemy/pb1000/irqmap.c
similarity index 100%
rename from arch/mips/au1000/pb1000/irqmap.c
rename to arch/mips/alchemy/pb1000/irqmap.c
diff --git a/arch/mips/au1000/pb1100/Makefile b/arch/mips/alchemy/pb1100/Makefile
similarity index 100%
rename from arch/mips/au1000/pb1100/Makefile
rename to arch/mips/alchemy/pb1100/Makefile
diff --git a/arch/mips/au1000/pb1100/board_setup.c b/arch/mips/alchemy/pb1100/board_setup.c
similarity index 100%
rename from arch/mips/au1000/pb1100/board_setup.c
rename to arch/mips/alchemy/pb1100/board_setup.c
diff --git a/arch/mips/au1000/pb1100/init.c b/arch/mips/alchemy/pb1100/init.c
similarity index 100%
rename from arch/mips/au1000/pb1100/init.c
rename to arch/mips/alchemy/pb1100/init.c
diff --git a/arch/mips/au1000/pb1100/irqmap.c b/arch/mips/alchemy/pb1100/irqmap.c
similarity index 100%
rename from arch/mips/au1000/pb1100/irqmap.c
rename to arch/mips/alchemy/pb1100/irqmap.c
diff --git a/arch/mips/au1000/pb1200/Makefile b/arch/mips/alchemy/pb1200/Makefile
similarity index 100%
rename from arch/mips/au1000/pb1200/Makefile
rename to arch/mips/alchemy/pb1200/Makefile
diff --git a/arch/mips/au1000/pb1200/board_setup.c b/arch/mips/alchemy/pb1200/board_setup.c
similarity index 100%
rename from arch/mips/au1000/pb1200/board_setup.c
rename to arch/mips/alchemy/pb1200/board_setup.c
diff --git a/arch/mips/au1000/pb1200/init.c b/arch/mips/alchemy/pb1200/init.c
similarity index 100%
rename from arch/mips/au1000/pb1200/init.c
rename to arch/mips/alchemy/pb1200/init.c
diff --git a/arch/mips/au1000/pb1200/irqmap.c b/arch/mips/alchemy/pb1200/irqmap.c
similarity index 100%
rename from arch/mips/au1000/pb1200/irqmap.c
rename to arch/mips/alchemy/pb1200/irqmap.c
diff --git a/arch/mips/au1000/pb1200/platform.c b/arch/mips/alchemy/pb1200/platform.c
similarity index 100%
rename from arch/mips/au1000/pb1200/platform.c
rename to arch/mips/alchemy/pb1200/platform.c
diff --git a/arch/mips/au1000/pb1500/Makefile b/arch/mips/alchemy/pb1500/Makefile
similarity index 100%
rename from arch/mips/au1000/pb1500/Makefile
rename to arch/mips/alchemy/pb1500/Makefile
diff --git a/arch/mips/au1000/pb1500/board_setup.c b/arch/mips/alchemy/pb1500/board_setup.c
similarity index 100%
rename from arch/mips/au1000/pb1500/board_setup.c
rename to arch/mips/alchemy/pb1500/board_setup.c
diff --git a/arch/mips/au1000/pb1500/init.c b/arch/mips/alchemy/pb1500/init.c
similarity index 100%
rename from arch/mips/au1000/pb1500/init.c
rename to arch/mips/alchemy/pb1500/init.c
diff --git a/arch/mips/au1000/pb1500/irqmap.c b/arch/mips/alchemy/pb1500/irqmap.c
similarity index 100%
rename from arch/mips/au1000/pb1500/irqmap.c
rename to arch/mips/alchemy/pb1500/irqmap.c
diff --git a/arch/mips/au1000/pb1550/Makefile b/arch/mips/alchemy/pb1550/Makefile
similarity index 100%
rename from arch/mips/au1000/pb1550/Makefile
rename to arch/mips/alchemy/pb1550/Makefile
diff --git a/arch/mips/au1000/pb1550/board_setup.c b/arch/mips/alchemy/pb1550/board_setup.c
similarity index 100%
rename from arch/mips/au1000/pb1550/board_setup.c
rename to arch/mips/alchemy/pb1550/board_setup.c
diff --git a/arch/mips/au1000/pb1550/init.c b/arch/mips/alchemy/pb1550/init.c
similarity index 100%
rename from arch/mips/au1000/pb1550/init.c
rename to arch/mips/alchemy/pb1550/init.c
diff --git a/arch/mips/au1000/pb1550/irqmap.c b/arch/mips/alchemy/pb1550/irqmap.c
similarity index 100%
rename from arch/mips/au1000/pb1550/irqmap.c
rename to arch/mips/alchemy/pb1550/irqmap.c
diff --git a/arch/mips/au1000/xxs1500/Makefile b/arch/mips/alchemy/xxs1500/Makefile
similarity index 100%
rename from arch/mips/au1000/xxs1500/Makefile
rename to arch/mips/alchemy/xxs1500/Makefile
diff --git a/arch/mips/au1000/xxs1500/board_setup.c b/arch/mips/alchemy/xxs1500/board_setup.c
similarity index 100%
rename from arch/mips/au1000/xxs1500/board_setup.c
rename to arch/mips/alchemy/xxs1500/board_setup.c
diff --git a/arch/mips/au1000/xxs1500/init.c b/arch/mips/alchemy/xxs1500/init.c
similarity index 100%
rename from arch/mips/au1000/xxs1500/init.c
rename to arch/mips/alchemy/xxs1500/init.c
diff --git a/arch/mips/au1000/xxs1500/irqmap.c b/arch/mips/alchemy/xxs1500/irqmap.c
similarity index 100%
rename from arch/mips/au1000/xxs1500/irqmap.c
rename to arch/mips/alchemy/xxs1500/irqmap.c
diff --git a/arch/mips/au1000/common/gpio.c b/arch/mips/au1000/common/gpio.c
deleted file mode 100644
index b485d94..0000000
--- a/arch/mips/au1000/common/gpio.c
+++ /dev/null
@@ -1,146 +0,0 @@
-/*
- *  Copyright (C) 2007, OpenWrt.org, Florian Fainelli <florian@openwrt.org>
- *  	Architecture specific GPIO support
- *
- *  This program is free software; you can redistribute	 it and/or modify it
- *  under  the terms of	 the GNU General  Public License as published by the
- *  Free Software Foundation;  either version 2 of the	License, or (at your
- *  option) any later version.
- *
- *  THIS  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.
- *
- *  Notes :
- * 	au1000 SoC have only one GPIO line : GPIO1
- * 	others have a second one : GPIO2
- */
-
-#include <linux/module.h>
-
-#include <asm/mach-au1x00/au1000.h>
-#include <asm/gpio.h>
-
-#define gpio1 sys
-#if !defined(CONFIG_SOC_AU1000)
-
-static struct au1x00_gpio2 *const gpio2 = (struct au1x00_gpio2 *) GPIO2_BASE;
-#define GPIO2_OUTPUT_ENABLE_MASK 	0x00010000
-
-static int au1xxx_gpio2_read(unsigned gpio)
-{
-	gpio -= AU1XXX_GPIO_BASE;
-	return ((gpio2->pinstate >> gpio) & 0x01);
-}
-
-static void au1xxx_gpio2_write(unsigned gpio, int value)
-{
-	gpio -= AU1XXX_GPIO_BASE;
-
-	gpio2->output = (GPIO2_OUTPUT_ENABLE_MASK << gpio) | (value << gpio);
-}
-
-static int au1xxx_gpio2_direction_input(unsigned gpio)
-{
-	gpio -= AU1XXX_GPIO_BASE;
-	gpio2->dir &= ~(0x01 << gpio);
-	return 0;
-}
-
-static int au1xxx_gpio2_direction_output(unsigned gpio, int value)
-{
-	gpio -= AU1XXX_GPIO_BASE;
-	gpio2->dir = (0x01 << gpio) | (value << gpio);
-	return 0;
-}
-
-#endif /* !defined(CONFIG_SOC_AU1000) */
-
-static int au1xxx_gpio1_read(unsigned gpio)
-{
-	return (gpio1->pinstaterd >> gpio) & 0x01;
-}
-
-static void au1xxx_gpio1_write(unsigned gpio, int value)
-{
-	if (value)
-		gpio1->outputset = (0x01 << gpio);
-	else
-		/* Output a zero */
-		gpio1->outputclr = (0x01 << gpio);
-}
-
-static int au1xxx_gpio1_direction_input(unsigned gpio)
-{
-	gpio1->pininputen = (0x01 << gpio);
-	return 0;
-}
-
-static int au1xxx_gpio1_direction_output(unsigned gpio, int value)
-{
-	gpio1->trioutclr = (0x01 & gpio);
-	return 0;
-}
-
-int au1xxx_gpio_get_value(unsigned gpio)
-{
-	if (gpio >= AU1XXX_GPIO_BASE)
-#if defined(CONFIG_SOC_AU1000)
-		return 0;
-#else
-		return au1xxx_gpio2_read(gpio);
-#endif
-	else
-		return au1xxx_gpio1_read(gpio);
-}
-EXPORT_SYMBOL(au1xxx_gpio_get_value);
-
-void au1xxx_gpio_set_value(unsigned gpio, int value)
-{
-	if (gpio >= AU1XXX_GPIO_BASE)
-#if defined(CONFIG_SOC_AU1000)
-		;
-#else
-		au1xxx_gpio2_write(gpio, value);
-#endif
-	else
-		au1xxx_gpio1_write(gpio, value);
-}
-EXPORT_SYMBOL(au1xxx_gpio_set_value);
-
-int au1xxx_gpio_direction_input(unsigned gpio)
-{
-	if (gpio >= AU1XXX_GPIO_BASE)
-#if defined(CONFIG_SOC_AU1000)
-		return -ENODEV;
-#else
-		return au1xxx_gpio2_direction_input(gpio);
-#endif
-
-	return au1xxx_gpio1_direction_input(gpio);
-}
-EXPORT_SYMBOL(au1xxx_gpio_direction_input);
-
-int au1xxx_gpio_direction_output(unsigned gpio, int value)
-{
-	if (gpio >= AU1XXX_GPIO_BASE)
-#if defined(CONFIG_SOC_AU1000)
-		return -ENODEV;
-#else
-		return au1xxx_gpio2_direction_output(gpio, value);
-#endif
-
-	return au1xxx_gpio1_direction_output(gpio, value);
-}
-EXPORT_SYMBOL(au1xxx_gpio_direction_output);
diff --git a/arch/mips/au1000/common/sleeper.S b/arch/mips/au1000/common/sleeper.S
deleted file mode 100644
index 4b3cf02..0000000
--- a/arch/mips/au1000/common/sleeper.S
+++ /dev/null
@@ -1,154 +0,0 @@
-/*
- * Copyright 2002 Embedded Edge, LLC
- * Author: dan@embeddededge.com
- *
- * Sleep helper for Au1xxx sleep mode.
- *
- * This program is free software; you can redistribute	it and/or 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/asm.h>
-#include <asm/mipsregs.h>
-#include <asm/regdef.h>
-#include <asm/stackframe.h>
-
-	.text
-	.set	macro
-	.set	noat
-	.align	5
-
-/* Save all of the processor general registers and go to sleep.
- * A wakeup condition will get us back here to restore the registers.
- */
-LEAF(save_and_sleep)
-
-	subu	sp, PT_SIZE
-	sw	$1, PT_R1(sp)
-	sw	$2, PT_R2(sp)
-	sw	$3, PT_R3(sp)
-	sw	$4, PT_R4(sp)
-	sw	$5, PT_R5(sp)
-	sw	$6, PT_R6(sp)
-	sw	$7, PT_R7(sp)
-	sw	$8, PT_R8(sp)
-	sw	$9, PT_R9(sp)
-	sw	$10, PT_R10(sp)
-	sw	$11, PT_R11(sp)
-	sw	$12, PT_R12(sp)
-	sw	$13, PT_R13(sp)
-	sw	$14, PT_R14(sp)
-	sw	$15, PT_R15(sp)
-	sw	$16, PT_R16(sp)
-	sw	$17, PT_R17(sp)
-	sw	$18, PT_R18(sp)
-	sw	$19, PT_R19(sp)
-	sw	$20, PT_R20(sp)
-	sw	$21, PT_R21(sp)
-	sw	$22, PT_R22(sp)
-	sw	$23, PT_R23(sp)
-	sw	$24, PT_R24(sp)
-	sw	$25, PT_R25(sp)
-	sw	$26, PT_R26(sp)
-	sw	$27, PT_R27(sp)
-	sw	$28, PT_R28(sp)
-	sw	$29, PT_R29(sp)
-	sw	$30, PT_R30(sp)
-	sw	$31, PT_R31(sp)
-	mfc0	k0, CP0_STATUS
-	sw	k0, 0x20(sp)
-	mfc0	k0, CP0_CONTEXT
-	sw	k0, 0x1c(sp)
-	mfc0	k0, CP0_PAGEMASK
-	sw	k0, 0x18(sp)
-	mfc0	k0, CP0_CONFIG
-	sw	k0, 0x14(sp)
-
-	/* Now set up the scratch registers so the boot rom will
-	 * return to this point upon wakeup.
-	 */
-	la	k0, 1f
-	lui	k1, 0xb190
-	ori	k1, 0x18
-	sw	sp, 0(k1)
-	ori 	k1, 0x1c
-	sw	k0, 0(k1)
-
-/* Put SDRAM into self refresh.  Preload instructions into cache,
- * issue a precharge, then auto refresh, then sleep commands to it.
- */
- 	la	t0, sdsleep
-	.set	mips3
- 	cache	0x14, 0(t0)
- 	cache	0x14, 32(t0)
- 	cache	0x14, 64(t0)
- 	cache	0x14, 96(t0)
-	.set	mips0
-
-sdsleep:
-	lui 	k0, 0xb400
-	sw	zero, 0x001c(k0)	/* Precharge */
-	sw	zero, 0x0020(k0)	/* Auto refresh */
-	sw	zero, 0x0030(k0)	/* SDRAM sleep */
-	sync
-
-	lui 	k1, 0xb190
-	sw	zero, 0x0078(k1)	/* get ready  to sleep */
-	sync
-	sw	zero, 0x007c(k1)	/* Put processor to sleep */
-	sync
-
-	/* This is where we return upon wakeup.
-	 * Reload all of the registers and return.
-	 */
-1:	nop
-	lw	k0, 0x20(sp)
-	mtc0	k0, CP0_STATUS
-	lw	k0, 0x1c(sp)
-	mtc0	k0, CP0_CONTEXT
-	lw	k0, 0x18(sp)
-	mtc0	k0, CP0_PAGEMASK
-	lw	k0, 0x14(sp)
-	mtc0	k0, CP0_CONFIG
-
-	/* We need to catch the ealry Alchemy SOCs with
-	 * the write-only Config[OD] bit and set it back to one...
-	 */
-	jal	au1x00_fixup_config_od
-	lw	$1, PT_R1(sp)
-	lw	$2, PT_R2(sp)
-	lw	$3, PT_R3(sp)
-	lw	$4, PT_R4(sp)
-	lw	$5, PT_R5(sp)
-	lw	$6, PT_R6(sp)
-	lw	$7, PT_R7(sp)
-	lw	$8, PT_R8(sp)
-	lw	$9, PT_R9(sp)
-	lw	$10, PT_R10(sp)
-	lw	$11, PT_R11(sp)
-	lw	$12, PT_R12(sp)
-	lw	$13, PT_R13(sp)
-	lw	$14, PT_R14(sp)
-	lw	$15, PT_R15(sp)
-	lw	$16, PT_R16(sp)
-	lw	$17, PT_R17(sp)
-	lw	$18, PT_R18(sp)
-	lw	$19, PT_R19(sp)
-	lw	$20, PT_R20(sp)
-	lw	$21, PT_R21(sp)
-	lw	$22, PT_R22(sp)
-	lw	$23, PT_R23(sp)
-	lw	$24, PT_R24(sp)
-	lw	$25, PT_R25(sp)
-	lw	$26, PT_R26(sp)
-	lw	$27, PT_R27(sp)
-	lw	$28, PT_R28(sp)
-	lw	$29, PT_R29(sp)
-	lw	$30, PT_R30(sp)
-	lw	$31, PT_R31(sp)
-	addiu	sp, PT_SIZE
-
-	jr	ra
-END(save_and_sleep)
diff --git a/include/asm-mips/Kbuild b/arch/mips/include/asm/Kbuild
similarity index 100%
rename from include/asm-mips/Kbuild
rename to arch/mips/include/asm/Kbuild
diff --git a/include/asm-mips/abi.h b/arch/mips/include/asm/abi.h
similarity index 100%
rename from include/asm-mips/abi.h
rename to arch/mips/include/asm/abi.h
diff --git a/include/asm-mips/addrspace.h b/arch/mips/include/asm/addrspace.h
similarity index 100%
rename from include/asm-mips/addrspace.h
rename to arch/mips/include/asm/addrspace.h
diff --git a/include/asm-mips/asm.h b/arch/mips/include/asm/asm.h
similarity index 100%
rename from include/asm-mips/asm.h
rename to arch/mips/include/asm/asm.h
diff --git a/include/asm-mips/asmmacro-32.h b/arch/mips/include/asm/asmmacro-32.h
similarity index 100%
rename from include/asm-mips/asmmacro-32.h
rename to arch/mips/include/asm/asmmacro-32.h
diff --git a/include/asm-mips/asmmacro-64.h b/arch/mips/include/asm/asmmacro-64.h
similarity index 100%
rename from include/asm-mips/asmmacro-64.h
rename to arch/mips/include/asm/asmmacro-64.h
diff --git a/include/asm-mips/asmmacro.h b/arch/mips/include/asm/asmmacro.h
similarity index 100%
rename from include/asm-mips/asmmacro.h
rename to arch/mips/include/asm/asmmacro.h
diff --git a/include/asm-mips/atomic.h b/arch/mips/include/asm/atomic.h
similarity index 100%
rename from include/asm-mips/atomic.h
rename to arch/mips/include/asm/atomic.h
diff --git a/include/asm-mips/auxvec.h b/arch/mips/include/asm/auxvec.h
similarity index 100%
rename from include/asm-mips/auxvec.h
rename to arch/mips/include/asm/auxvec.h
diff --git a/include/asm-mips/barrier.h b/arch/mips/include/asm/barrier.h
similarity index 100%
rename from include/asm-mips/barrier.h
rename to arch/mips/include/asm/barrier.h
diff --git a/include/asm-mips/bcache.h b/arch/mips/include/asm/bcache.h
similarity index 100%
rename from include/asm-mips/bcache.h
rename to arch/mips/include/asm/bcache.h
diff --git a/include/asm-mips/bitops.h b/arch/mips/include/asm/bitops.h
similarity index 100%
rename from include/asm-mips/bitops.h
rename to arch/mips/include/asm/bitops.h
diff --git a/include/asm-mips/bootinfo.h b/arch/mips/include/asm/bootinfo.h
similarity index 100%
rename from include/asm-mips/bootinfo.h
rename to arch/mips/include/asm/bootinfo.h
diff --git a/include/asm-mips/branch.h b/arch/mips/include/asm/branch.h
similarity index 100%
rename from include/asm-mips/branch.h
rename to arch/mips/include/asm/branch.h
diff --git a/include/asm-mips/break.h b/arch/mips/include/asm/break.h
similarity index 100%
rename from include/asm-mips/break.h
rename to arch/mips/include/asm/break.h
diff --git a/include/asm-mips/bug.h b/arch/mips/include/asm/bug.h
similarity index 100%
rename from include/asm-mips/bug.h
rename to arch/mips/include/asm/bug.h
diff --git a/include/asm-mips/bugs.h b/arch/mips/include/asm/bugs.h
similarity index 100%
rename from include/asm-mips/bugs.h
rename to arch/mips/include/asm/bugs.h
diff --git a/include/asm-mips/byteorder.h b/arch/mips/include/asm/byteorder.h
similarity index 100%
rename from include/asm-mips/byteorder.h
rename to arch/mips/include/asm/byteorder.h
diff --git a/include/asm-mips/cache.h b/arch/mips/include/asm/cache.h
similarity index 100%
rename from include/asm-mips/cache.h
rename to arch/mips/include/asm/cache.h
diff --git a/include/asm-mips/cachectl.h b/arch/mips/include/asm/cachectl.h
similarity index 100%
rename from include/asm-mips/cachectl.h
rename to arch/mips/include/asm/cachectl.h
diff --git a/include/asm-mips/cacheflush.h b/arch/mips/include/asm/cacheflush.h
similarity index 100%
rename from include/asm-mips/cacheflush.h
rename to arch/mips/include/asm/cacheflush.h
diff --git a/include/asm-mips/cacheops.h b/arch/mips/include/asm/cacheops.h
similarity index 100%
rename from include/asm-mips/cacheops.h
rename to arch/mips/include/asm/cacheops.h
diff --git a/include/asm-mips/checksum.h b/arch/mips/include/asm/checksum.h
similarity index 100%
rename from include/asm-mips/checksum.h
rename to arch/mips/include/asm/checksum.h
diff --git a/include/asm-mips/cmp.h b/arch/mips/include/asm/cmp.h
similarity index 100%
rename from include/asm-mips/cmp.h
rename to arch/mips/include/asm/cmp.h
diff --git a/include/asm-mips/cmpxchg.h b/arch/mips/include/asm/cmpxchg.h
similarity index 100%
rename from include/asm-mips/cmpxchg.h
rename to arch/mips/include/asm/cmpxchg.h
diff --git a/include/asm-mips/compat-signal.h b/arch/mips/include/asm/compat-signal.h
similarity index 100%
rename from include/asm-mips/compat-signal.h
rename to arch/mips/include/asm/compat-signal.h
diff --git a/include/asm-mips/compat.h b/arch/mips/include/asm/compat.h
similarity index 100%
rename from include/asm-mips/compat.h
rename to arch/mips/include/asm/compat.h
diff --git a/include/asm-mips/compiler.h b/arch/mips/include/asm/compiler.h
similarity index 100%
rename from include/asm-mips/compiler.h
rename to arch/mips/include/asm/compiler.h
diff --git a/include/asm-mips/cpu-features.h b/arch/mips/include/asm/cpu-features.h
similarity index 100%
rename from include/asm-mips/cpu-features.h
rename to arch/mips/include/asm/cpu-features.h
diff --git a/arch/mips/include/asm/cpu-info.h b/arch/mips/include/asm/cpu-info.h
new file mode 100644
index 0000000..744cd8f
--- /dev/null
+++ b/arch/mips/include/asm/cpu-info.h
@@ -0,0 +1,90 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 1994 Waldorf GMBH
+ * Copyright (C) 1995, 1996, 1997, 1998, 1999, 2001, 2002, 2003 Ralf Baechle
+ * Copyright (C) 1996 Paul M. Antoine
+ * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
+ * Copyright (C) 2004  Maciej W. Rozycki
+ */
+#ifndef __ASM_CPU_INFO_H
+#define __ASM_CPU_INFO_H
+
+#include <linux/types.h>
+
+#include <asm/cache.h>
+
+/*
+ * Descriptor for a cache
+ */
+struct cache_desc {
+	unsigned int waysize;	/* Bytes per way */
+	unsigned short sets;	/* Number of lines per set */
+	unsigned char ways;	/* Number of ways */
+	unsigned char linesz;	/* Size of line in bytes */
+	unsigned char waybit;	/* Bits to select in a cache set */
+	unsigned char flags;	/* Flags describing cache properties */
+};
+
+/*
+ * Flag definitions
+ */
+#define MIPS_CACHE_NOT_PRESENT	0x00000001
+#define MIPS_CACHE_VTAG		0x00000002	/* Virtually tagged cache */
+#define MIPS_CACHE_ALIASES	0x00000004	/* Cache could have aliases */
+#define MIPS_CACHE_IC_F_DC	0x00000008	/* Ic can refill from D-cache */
+#define MIPS_IC_SNOOPS_REMOTE	0x00000010	/* Ic snoops remote stores */
+#define MIPS_CACHE_PINDEX	0x00000020	/* Physically indexed cache */
+
+struct cpuinfo_mips {
+	unsigned long		udelay_val;
+	unsigned long		asid_cache;
+
+	/*
+	 * Capability and feature descriptor structure for MIPS CPU
+	 */
+	unsigned long		options;
+	unsigned long		ases;
+	unsigned int		processor_id;
+	unsigned int		fpu_id;
+	unsigned int		cputype;
+	int			isa_level;
+	int			tlbsize;
+	struct cache_desc	icache;	/* Primary I-cache */
+	struct cache_desc	dcache;	/* Primary D or combined I/D cache */
+	struct cache_desc	scache;	/* Secondary cache */
+	struct cache_desc	tcache;	/* Tertiary/split secondary cache */
+	int			srsets;	/* Shadow register sets */
+	int			core;	/* physical core number */
+#if defined(CONFIG_MIPS_MT_SMP) || defined(CONFIG_MIPS_MT_SMTC)
+	/*
+	 * In the MIPS MT "SMTC" model, each TC is considered
+	 * to be a "CPU" for the purposes of scheduling, but
+	 * exception resources, ASID spaces, etc, are common
+	 * to all TCs within the same VPE.
+	 */
+	int			vpe_id;  /* Virtual Processor number */
+#endif
+#ifdef CONFIG_MIPS_MT_SMTC
+	int			tc_id;   /* Thread Context number */
+#endif
+	void 			*data;	/* Additional data */
+	unsigned int		watch_reg_count;   /* Number that exist */
+	unsigned int		watch_reg_use_cnt; /* Usable by ptrace */
+#define NUM_WATCH_REGS 4
+	u16			watch_reg_masks[NUM_WATCH_REGS];
+} __attribute__((aligned(SMP_CACHE_BYTES)));
+
+extern struct cpuinfo_mips cpu_data[];
+#define current_cpu_data cpu_data[smp_processor_id()]
+#define raw_current_cpu_data cpu_data[raw_smp_processor_id()]
+
+extern void cpu_probe(void);
+extern void cpu_report(void);
+
+extern const char *__cpu_name[];
+#define cpu_name_string()	__cpu_name[smp_processor_id()]
+
+#endif /* __ASM_CPU_INFO_H */
diff --git a/include/asm-mips/cpu.h b/arch/mips/include/asm/cpu.h
similarity index 100%
rename from include/asm-mips/cpu.h
rename to arch/mips/include/asm/cpu.h
diff --git a/include/asm-mips/cputime.h b/arch/mips/include/asm/cputime.h
similarity index 100%
rename from include/asm-mips/cputime.h
rename to arch/mips/include/asm/cputime.h
diff --git a/include/asm-mips/current.h b/arch/mips/include/asm/current.h
similarity index 100%
rename from include/asm-mips/current.h
rename to arch/mips/include/asm/current.h
diff --git a/include/asm-mips/debug.h b/arch/mips/include/asm/debug.h
similarity index 100%
rename from include/asm-mips/debug.h
rename to arch/mips/include/asm/debug.h
diff --git a/include/asm-mips/dec/ecc.h b/arch/mips/include/asm/dec/ecc.h
similarity index 100%
rename from include/asm-mips/dec/ecc.h
rename to arch/mips/include/asm/dec/ecc.h
diff --git a/include/asm-mips/dec/interrupts.h b/arch/mips/include/asm/dec/interrupts.h
similarity index 100%
rename from include/asm-mips/dec/interrupts.h
rename to arch/mips/include/asm/dec/interrupts.h
diff --git a/include/asm-mips/dec/ioasic.h b/arch/mips/include/asm/dec/ioasic.h
similarity index 100%
rename from include/asm-mips/dec/ioasic.h
rename to arch/mips/include/asm/dec/ioasic.h
diff --git a/include/asm-mips/dec/ioasic_addrs.h b/arch/mips/include/asm/dec/ioasic_addrs.h
similarity index 100%
rename from include/asm-mips/dec/ioasic_addrs.h
rename to arch/mips/include/asm/dec/ioasic_addrs.h
diff --git a/include/asm-mips/dec/ioasic_ints.h b/arch/mips/include/asm/dec/ioasic_ints.h
similarity index 100%
rename from include/asm-mips/dec/ioasic_ints.h
rename to arch/mips/include/asm/dec/ioasic_ints.h
diff --git a/include/asm-mips/dec/kn01.h b/arch/mips/include/asm/dec/kn01.h
similarity index 100%
rename from include/asm-mips/dec/kn01.h
rename to arch/mips/include/asm/dec/kn01.h
diff --git a/include/asm-mips/dec/kn02.h b/arch/mips/include/asm/dec/kn02.h
similarity index 100%
rename from include/asm-mips/dec/kn02.h
rename to arch/mips/include/asm/dec/kn02.h
diff --git a/include/asm-mips/dec/kn02ba.h b/arch/mips/include/asm/dec/kn02ba.h
similarity index 100%
rename from include/asm-mips/dec/kn02ba.h
rename to arch/mips/include/asm/dec/kn02ba.h
diff --git a/include/asm-mips/dec/kn02ca.h b/arch/mips/include/asm/dec/kn02ca.h
similarity index 100%
rename from include/asm-mips/dec/kn02ca.h
rename to arch/mips/include/asm/dec/kn02ca.h
diff --git a/include/asm-mips/dec/kn02xa.h b/arch/mips/include/asm/dec/kn02xa.h
similarity index 100%
rename from include/asm-mips/dec/kn02xa.h
rename to arch/mips/include/asm/dec/kn02xa.h
diff --git a/include/asm-mips/dec/kn03.h b/arch/mips/include/asm/dec/kn03.h
similarity index 100%
rename from include/asm-mips/dec/kn03.h
rename to arch/mips/include/asm/dec/kn03.h
diff --git a/include/asm-mips/dec/kn05.h b/arch/mips/include/asm/dec/kn05.h
similarity index 100%
rename from include/asm-mips/dec/kn05.h
rename to arch/mips/include/asm/dec/kn05.h
diff --git a/include/asm-mips/dec/kn230.h b/arch/mips/include/asm/dec/kn230.h
similarity index 100%
rename from include/asm-mips/dec/kn230.h
rename to arch/mips/include/asm/dec/kn230.h
diff --git a/include/asm-mips/dec/machtype.h b/arch/mips/include/asm/dec/machtype.h
similarity index 100%
rename from include/asm-mips/dec/machtype.h
rename to arch/mips/include/asm/dec/machtype.h
diff --git a/include/asm-mips/dec/prom.h b/arch/mips/include/asm/dec/prom.h
similarity index 100%
rename from include/asm-mips/dec/prom.h
rename to arch/mips/include/asm/dec/prom.h
diff --git a/include/asm-mips/dec/system.h b/arch/mips/include/asm/dec/system.h
similarity index 100%
rename from include/asm-mips/dec/system.h
rename to arch/mips/include/asm/dec/system.h
diff --git a/include/asm-mips/delay.h b/arch/mips/include/asm/delay.h
similarity index 100%
rename from include/asm-mips/delay.h
rename to arch/mips/include/asm/delay.h
diff --git a/include/asm-mips/device.h b/arch/mips/include/asm/device.h
similarity index 100%
rename from include/asm-mips/device.h
rename to arch/mips/include/asm/device.h
diff --git a/include/asm-mips/div64.h b/arch/mips/include/asm/div64.h
similarity index 100%
rename from include/asm-mips/div64.h
rename to arch/mips/include/asm/div64.h
diff --git a/include/asm-mips/dma-mapping.h b/arch/mips/include/asm/dma-mapping.h
similarity index 100%
rename from include/asm-mips/dma-mapping.h
rename to arch/mips/include/asm/dma-mapping.h
diff --git a/include/asm-mips/dma.h b/arch/mips/include/asm/dma.h
similarity index 100%
rename from include/asm-mips/dma.h
rename to arch/mips/include/asm/dma.h
diff --git a/include/asm-mips/ds1286.h b/arch/mips/include/asm/ds1286.h
similarity index 100%
rename from include/asm-mips/ds1286.h
rename to arch/mips/include/asm/ds1286.h
diff --git a/include/asm-mips/ds1287.h b/arch/mips/include/asm/ds1287.h
similarity index 100%
rename from include/asm-mips/ds1287.h
rename to arch/mips/include/asm/ds1287.h
diff --git a/include/asm-mips/dsp.h b/arch/mips/include/asm/dsp.h
similarity index 100%
rename from include/asm-mips/dsp.h
rename to arch/mips/include/asm/dsp.h
diff --git a/include/asm-mips/edac.h b/arch/mips/include/asm/edac.h
similarity index 100%
rename from include/asm-mips/edac.h
rename to arch/mips/include/asm/edac.h
diff --git a/include/asm-mips/elf.h b/arch/mips/include/asm/elf.h
similarity index 100%
rename from include/asm-mips/elf.h
rename to arch/mips/include/asm/elf.h
diff --git a/include/asm-mips/emergency-restart.h b/arch/mips/include/asm/emergency-restart.h
similarity index 100%
rename from include/asm-mips/emergency-restart.h
rename to arch/mips/include/asm/emergency-restart.h
diff --git a/include/asm-mips/emma2rh/emma2rh.h b/arch/mips/include/asm/emma2rh/emma2rh.h
similarity index 100%
rename from include/asm-mips/emma2rh/emma2rh.h
rename to arch/mips/include/asm/emma2rh/emma2rh.h
diff --git a/include/asm-mips/emma2rh/markeins.h b/arch/mips/include/asm/emma2rh/markeins.h
similarity index 100%
rename from include/asm-mips/emma2rh/markeins.h
rename to arch/mips/include/asm/emma2rh/markeins.h
diff --git a/include/asm-mips/errno.h b/arch/mips/include/asm/errno.h
similarity index 100%
rename from include/asm-mips/errno.h
rename to arch/mips/include/asm/errno.h
diff --git a/include/asm-mips/fb.h b/arch/mips/include/asm/fb.h
similarity index 100%
rename from include/asm-mips/fb.h
rename to arch/mips/include/asm/fb.h
diff --git a/include/asm-mips/fcntl.h b/arch/mips/include/asm/fcntl.h
similarity index 100%
rename from include/asm-mips/fcntl.h
rename to arch/mips/include/asm/fcntl.h
diff --git a/include/asm-mips/fixmap.h b/arch/mips/include/asm/fixmap.h
similarity index 100%
rename from include/asm-mips/fixmap.h
rename to arch/mips/include/asm/fixmap.h
diff --git a/include/asm-mips/floppy.h b/arch/mips/include/asm/floppy.h
similarity index 100%
rename from include/asm-mips/floppy.h
rename to arch/mips/include/asm/floppy.h
diff --git a/include/asm-mips/fpregdef.h b/arch/mips/include/asm/fpregdef.h
similarity index 100%
rename from include/asm-mips/fpregdef.h
rename to arch/mips/include/asm/fpregdef.h
diff --git a/include/asm-mips/fpu.h b/arch/mips/include/asm/fpu.h
similarity index 100%
rename from include/asm-mips/fpu.h
rename to arch/mips/include/asm/fpu.h
diff --git a/include/asm-mips/fpu_emulator.h b/arch/mips/include/asm/fpu_emulator.h
similarity index 100%
rename from include/asm-mips/fpu_emulator.h
rename to arch/mips/include/asm/fpu_emulator.h
diff --git a/include/asm-mips/futex.h b/arch/mips/include/asm/futex.h
similarity index 100%
rename from include/asm-mips/futex.h
rename to arch/mips/include/asm/futex.h
diff --git a/include/asm-mips/fw/arc/hinv.h b/arch/mips/include/asm/fw/arc/hinv.h
similarity index 100%
rename from include/asm-mips/fw/arc/hinv.h
rename to arch/mips/include/asm/fw/arc/hinv.h
diff --git a/include/asm-mips/fw/arc/types.h b/arch/mips/include/asm/fw/arc/types.h
similarity index 100%
rename from include/asm-mips/fw/arc/types.h
rename to arch/mips/include/asm/fw/arc/types.h
diff --git a/include/asm-mips/fw/cfe/cfe_api.h b/arch/mips/include/asm/fw/cfe/cfe_api.h
similarity index 100%
rename from include/asm-mips/fw/cfe/cfe_api.h
rename to arch/mips/include/asm/fw/cfe/cfe_api.h
diff --git a/include/asm-mips/fw/cfe/cfe_error.h b/arch/mips/include/asm/fw/cfe/cfe_error.h
similarity index 100%
rename from include/asm-mips/fw/cfe/cfe_error.h
rename to arch/mips/include/asm/fw/cfe/cfe_error.h
diff --git a/include/asm-mips/gcmpregs.h b/arch/mips/include/asm/gcmpregs.h
similarity index 100%
rename from include/asm-mips/gcmpregs.h
rename to arch/mips/include/asm/gcmpregs.h
diff --git a/include/asm-mips/gic.h b/arch/mips/include/asm/gic.h
similarity index 100%
rename from include/asm-mips/gic.h
rename to arch/mips/include/asm/gic.h
diff --git a/include/asm-mips/gpio.h b/arch/mips/include/asm/gpio.h
similarity index 100%
rename from include/asm-mips/gpio.h
rename to arch/mips/include/asm/gpio.h
diff --git a/include/asm-mips/gt64120.h b/arch/mips/include/asm/gt64120.h
similarity index 100%
rename from include/asm-mips/gt64120.h
rename to arch/mips/include/asm/gt64120.h
diff --git a/include/asm-mips/hardirq.h b/arch/mips/include/asm/hardirq.h
similarity index 100%
rename from include/asm-mips/hardirq.h
rename to arch/mips/include/asm/hardirq.h
diff --git a/include/asm-mips/hazards.h b/arch/mips/include/asm/hazards.h
similarity index 100%
rename from include/asm-mips/hazards.h
rename to arch/mips/include/asm/hazards.h
diff --git a/include/asm-mips/highmem.h b/arch/mips/include/asm/highmem.h
similarity index 100%
rename from include/asm-mips/highmem.h
rename to arch/mips/include/asm/highmem.h
diff --git a/include/asm-mips/hw_irq.h b/arch/mips/include/asm/hw_irq.h
similarity index 100%
rename from include/asm-mips/hw_irq.h
rename to arch/mips/include/asm/hw_irq.h
diff --git a/include/asm-mips/i8253.h b/arch/mips/include/asm/i8253.h
similarity index 100%
rename from include/asm-mips/i8253.h
rename to arch/mips/include/asm/i8253.h
diff --git a/include/asm-mips/i8259.h b/arch/mips/include/asm/i8259.h
similarity index 100%
rename from include/asm-mips/i8259.h
rename to arch/mips/include/asm/i8259.h
diff --git a/include/asm-mips/ide.h b/arch/mips/include/asm/ide.h
similarity index 100%
rename from include/asm-mips/ide.h
rename to arch/mips/include/asm/ide.h
diff --git a/include/asm-mips/inst.h b/arch/mips/include/asm/inst.h
similarity index 100%
rename from include/asm-mips/inst.h
rename to arch/mips/include/asm/inst.h
diff --git a/include/asm-mips/io.h b/arch/mips/include/asm/io.h
similarity index 100%
rename from include/asm-mips/io.h
rename to arch/mips/include/asm/io.h
diff --git a/include/asm-mips/ioctl.h b/arch/mips/include/asm/ioctl.h
similarity index 100%
rename from include/asm-mips/ioctl.h
rename to arch/mips/include/asm/ioctl.h
diff --git a/include/asm-mips/ioctls.h b/arch/mips/include/asm/ioctls.h
similarity index 100%
rename from include/asm-mips/ioctls.h
rename to arch/mips/include/asm/ioctls.h
diff --git a/include/asm-mips/ip32/crime.h b/arch/mips/include/asm/ip32/crime.h
similarity index 100%
rename from include/asm-mips/ip32/crime.h
rename to arch/mips/include/asm/ip32/crime.h
diff --git a/include/asm-mips/ip32/ip32_ints.h b/arch/mips/include/asm/ip32/ip32_ints.h
similarity index 100%
rename from include/asm-mips/ip32/ip32_ints.h
rename to arch/mips/include/asm/ip32/ip32_ints.h
diff --git a/include/asm-mips/ip32/mace.h b/arch/mips/include/asm/ip32/mace.h
similarity index 100%
rename from include/asm-mips/ip32/mace.h
rename to arch/mips/include/asm/ip32/mace.h
diff --git a/include/asm-mips/ipcbuf.h b/arch/mips/include/asm/ipcbuf.h
similarity index 100%
rename from include/asm-mips/ipcbuf.h
rename to arch/mips/include/asm/ipcbuf.h
diff --git a/include/asm-mips/irq.h b/arch/mips/include/asm/irq.h
similarity index 100%
rename from include/asm-mips/irq.h
rename to arch/mips/include/asm/irq.h
diff --git a/include/asm-mips/irq_cpu.h b/arch/mips/include/asm/irq_cpu.h
similarity index 100%
rename from include/asm-mips/irq_cpu.h
rename to arch/mips/include/asm/irq_cpu.h
diff --git a/include/asm-mips/irq_gt641xx.h b/arch/mips/include/asm/irq_gt641xx.h
similarity index 100%
rename from include/asm-mips/irq_gt641xx.h
rename to arch/mips/include/asm/irq_gt641xx.h
diff --git a/include/asm-mips/irq_regs.h b/arch/mips/include/asm/irq_regs.h
similarity index 100%
rename from include/asm-mips/irq_regs.h
rename to arch/mips/include/asm/irq_regs.h
diff --git a/arch/mips/include/asm/irqflags.h b/arch/mips/include/asm/irqflags.h
new file mode 100644
index 0000000..701ec0b
--- /dev/null
+++ b/arch/mips/include/asm/irqflags.h
@@ -0,0 +1,283 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 1994, 95, 96, 97, 98, 99, 2003 by Ralf Baechle
+ * Copyright (C) 1996 by Paul M. Antoine
+ * Copyright (C) 1999 Silicon Graphics
+ * Copyright (C) 2000 MIPS Technologies, Inc.
+ */
+#ifndef _ASM_IRQFLAGS_H
+#define _ASM_IRQFLAGS_H
+
+#ifndef __ASSEMBLY__
+
+#include <linux/compiler.h>
+#include <asm/hazards.h>
+
+__asm__(
+	"	.macro	raw_local_irq_enable				\n"
+	"	.set	push						\n"
+	"	.set	reorder						\n"
+	"	.set	noat						\n"
+#ifdef CONFIG_MIPS_MT_SMTC
+	"	mfc0	$1, $2, 1	# SMTC - clear TCStatus.IXMT	\n"
+	"	ori	$1, 0x400					\n"
+	"	xori	$1, 0x400					\n"
+	"	mtc0	$1, $2, 1					\n"
+#elif defined(CONFIG_CPU_MIPSR2)
+	"	ei							\n"
+#else
+	"	mfc0	$1,$12						\n"
+	"	ori	$1,0x1f						\n"
+	"	xori	$1,0x1e						\n"
+	"	mtc0	$1,$12						\n"
+#endif
+	"	irq_enable_hazard					\n"
+	"	.set	pop						\n"
+	"	.endm");
+
+extern void smtc_ipi_replay(void);
+
+static inline void raw_local_irq_enable(void)
+{
+#ifdef CONFIG_MIPS_MT_SMTC
+	/*
+	 * SMTC kernel needs to do a software replay of queued
+	 * IPIs, at the cost of call overhead on each local_irq_enable()
+	 */
+	smtc_ipi_replay();
+#endif
+	__asm__ __volatile__(
+		"raw_local_irq_enable"
+		: /* no outputs */
+		: /* no inputs */
+		: "memory");
+}
+
+
+/*
+ * For cli() we have to insert nops to make sure that the new value
+ * has actually arrived in the status register before the end of this
+ * macro.
+ * R4000/R4400 need three nops, the R4600 two nops and the R10000 needs
+ * no nops at all.
+ */
+/*
+ * For TX49, operating only IE bit is not enough.
+ *
+ * If mfc0 $12 follows store and the mfc0 is last instruction of a
+ * page and fetching the next instruction causes TLB miss, the result
+ * of the mfc0 might wrongly contain EXL bit.
+ *
+ * ERT-TX49H2-027, ERT-TX49H3-012, ERT-TX49HL3-006, ERT-TX49H4-008
+ *
+ * Workaround: mask EXL bit of the result or place a nop before mfc0.
+ */
+__asm__(
+	"	.macro	raw_local_irq_disable\n"
+	"	.set	push						\n"
+	"	.set	noat						\n"
+#ifdef CONFIG_MIPS_MT_SMTC
+	"	mfc0	$1, $2, 1					\n"
+	"	ori	$1, 0x400					\n"
+	"	.set	noreorder					\n"
+	"	mtc0	$1, $2, 1					\n"
+#elif defined(CONFIG_CPU_MIPSR2)
+	"	di							\n"
+#else
+	"	mfc0	$1,$12						\n"
+	"	ori	$1,0x1f						\n"
+	"	xori	$1,0x1f						\n"
+	"	.set	noreorder					\n"
+	"	mtc0	$1,$12						\n"
+#endif
+	"	irq_disable_hazard					\n"
+	"	.set	pop						\n"
+	"	.endm							\n");
+
+static inline void raw_local_irq_disable(void)
+{
+	__asm__ __volatile__(
+		"raw_local_irq_disable"
+		: /* no outputs */
+		: /* no inputs */
+		: "memory");
+}
+
+__asm__(
+	"	.macro	raw_local_save_flags flags			\n"
+	"	.set	push						\n"
+	"	.set	reorder						\n"
+#ifdef CONFIG_MIPS_MT_SMTC
+	"	mfc0	\\flags, $2, 1					\n"
+#else
+	"	mfc0	\\flags, $12					\n"
+#endif
+	"	.set	pop						\n"
+	"	.endm							\n");
+
+#define raw_local_save_flags(x)						\
+__asm__ __volatile__(							\
+	"raw_local_save_flags %0"					\
+	: "=r" (x))
+
+__asm__(
+	"	.macro	raw_local_irq_save result			\n"
+	"	.set	push						\n"
+	"	.set	reorder						\n"
+	"	.set	noat						\n"
+#ifdef CONFIG_MIPS_MT_SMTC
+	"	mfc0	\\result, $2, 1					\n"
+	"	ori	$1, \\result, 0x400				\n"
+	"	.set	noreorder					\n"
+	"	mtc0	$1, $2, 1					\n"
+	"	andi	\\result, \\result, 0x400			\n"
+#elif defined(CONFIG_CPU_MIPSR2)
+	"	di	\\result					\n"
+	"	andi	\\result, 1					\n"
+#else
+	"	mfc0	\\result, $12					\n"
+	"	ori	$1, \\result, 0x1f				\n"
+	"	xori	$1, 0x1f					\n"
+	"	.set	noreorder					\n"
+	"	mtc0	$1, $12						\n"
+#endif
+	"	irq_disable_hazard					\n"
+	"	.set	pop						\n"
+	"	.endm							\n");
+
+#define raw_local_irq_save(x)						\
+__asm__ __volatile__(							\
+	"raw_local_irq_save\t%0"					\
+	: "=r" (x)							\
+	: /* no inputs */						\
+	: "memory")
+
+__asm__(
+	"	.macro	raw_local_irq_restore flags			\n"
+	"	.set	push						\n"
+	"	.set	noreorder					\n"
+	"	.set	noat						\n"
+#ifdef CONFIG_MIPS_MT_SMTC
+	"mfc0	$1, $2, 1						\n"
+	"andi	\\flags, 0x400						\n"
+	"ori	$1, 0x400						\n"
+	"xori	$1, 0x400						\n"
+	"or	\\flags, $1						\n"
+	"mtc0	\\flags, $2, 1						\n"
+#elif defined(CONFIG_CPU_MIPSR2) && defined(CONFIG_IRQ_CPU)
+	/*
+	 * Slow, but doesn't suffer from a relativly unlikely race
+	 * condition we're having since days 1.
+	 */
+	"	beqz	\\flags, 1f					\n"
+	"	 di							\n"
+	"	ei							\n"
+	"1:								\n"
+#elif defined(CONFIG_CPU_MIPSR2)
+	/*
+	 * Fast, dangerous.  Life is fun, life is good.
+	 */
+	"	mfc0	$1, $12						\n"
+	"	ins	$1, \\flags, 0, 1				\n"
+	"	mtc0	$1, $12						\n"
+#else
+	"	mfc0	$1, $12						\n"
+	"	andi	\\flags, 1					\n"
+	"	ori	$1, 0x1f					\n"
+	"	xori	$1, 0x1f					\n"
+	"	or	\\flags, $1					\n"
+	"	mtc0	\\flags, $12					\n"
+#endif
+	"	irq_disable_hazard					\n"
+	"	.set	pop						\n"
+	"	.endm							\n");
+
+
+static inline void raw_local_irq_restore(unsigned long flags)
+{
+	unsigned long __tmp1;
+
+#ifdef CONFIG_MIPS_MT_SMTC
+	/*
+	 * SMTC kernel needs to do a software replay of queued
+	 * IPIs, at the cost of branch and call overhead on each
+	 * local_irq_restore()
+	 */
+	if (unlikely(!(flags & 0x0400)))
+		smtc_ipi_replay();
+#endif
+
+	__asm__ __volatile__(
+		"raw_local_irq_restore\t%0"
+		: "=r" (__tmp1)
+		: "0" (flags)
+		: "memory");
+}
+
+static inline void __raw_local_irq_restore(unsigned long flags)
+{
+	unsigned long __tmp1;
+
+	__asm__ __volatile__(
+		"raw_local_irq_restore\t%0"
+		: "=r" (__tmp1)
+		: "0" (flags)
+		: "memory");
+}
+
+static inline int raw_irqs_disabled_flags(unsigned long flags)
+{
+#ifdef CONFIG_MIPS_MT_SMTC
+	/*
+	 * SMTC model uses TCStatus.IXMT to disable interrupts for a thread/CPU
+	 */
+	return flags & 0x400;
+#else
+	return !(flags & 1);
+#endif
+}
+
+#endif
+
+/*
+ * Do the CPU's IRQ-state tracing from assembly code.
+ */
+#ifdef CONFIG_TRACE_IRQFLAGS
+/* Reload some registers clobbered by trace_hardirqs_on */
+#ifdef CONFIG_64BIT
+# define TRACE_IRQS_RELOAD_REGS						\
+	LONG_L	$11, PT_R11(sp);					\
+	LONG_L	$10, PT_R10(sp);					\
+	LONG_L	$9, PT_R9(sp);						\
+	LONG_L	$8, PT_R8(sp);						\
+	LONG_L	$7, PT_R7(sp);						\
+	LONG_L	$6, PT_R6(sp);						\
+	LONG_L	$5, PT_R5(sp);						\
+	LONG_L	$4, PT_R4(sp);						\
+	LONG_L	$2, PT_R2(sp)
+#else
+# define TRACE_IRQS_RELOAD_REGS						\
+	LONG_L	$7, PT_R7(sp);						\
+	LONG_L	$6, PT_R6(sp);						\
+	LONG_L	$5, PT_R5(sp);						\
+	LONG_L	$4, PT_R4(sp);						\
+	LONG_L	$2, PT_R2(sp)
+#endif
+# define TRACE_IRQS_ON							\
+	CLI;	/* make sure trace_hardirqs_on() is called in kernel level */ \
+	jal	trace_hardirqs_on
+# define TRACE_IRQS_ON_RELOAD						\
+	TRACE_IRQS_ON;							\
+	TRACE_IRQS_RELOAD_REGS
+# define TRACE_IRQS_OFF							\
+	jal	trace_hardirqs_off
+#else
+# define TRACE_IRQS_ON
+# define TRACE_IRQS_ON_RELOAD
+# define TRACE_IRQS_OFF
+#endif
+
+#endif /* _ASM_IRQFLAGS_H */
diff --git a/include/asm-mips/isadep.h b/arch/mips/include/asm/isadep.h
similarity index 100%
rename from include/asm-mips/isadep.h
rename to arch/mips/include/asm/isadep.h
diff --git a/include/asm-mips/jazz.h b/arch/mips/include/asm/jazz.h
similarity index 100%
rename from include/asm-mips/jazz.h
rename to arch/mips/include/asm/jazz.h
diff --git a/include/asm-mips/jazzdma.h b/arch/mips/include/asm/jazzdma.h
similarity index 100%
rename from include/asm-mips/jazzdma.h
rename to arch/mips/include/asm/jazzdma.h
diff --git a/include/asm-mips/kdebug.h b/arch/mips/include/asm/kdebug.h
similarity index 100%
rename from include/asm-mips/kdebug.h
rename to arch/mips/include/asm/kdebug.h
diff --git a/include/asm-mips/kexec.h b/arch/mips/include/asm/kexec.h
similarity index 100%
rename from include/asm-mips/kexec.h
rename to arch/mips/include/asm/kexec.h
diff --git a/include/asm-mips/kgdb.h b/arch/mips/include/asm/kgdb.h
similarity index 100%
rename from include/asm-mips/kgdb.h
rename to arch/mips/include/asm/kgdb.h
diff --git a/include/asm-mips/kmap_types.h b/arch/mips/include/asm/kmap_types.h
similarity index 100%
rename from include/asm-mips/kmap_types.h
rename to arch/mips/include/asm/kmap_types.h
diff --git a/include/asm-mips/kspd.h b/arch/mips/include/asm/kspd.h
similarity index 100%
rename from include/asm-mips/kspd.h
rename to arch/mips/include/asm/kspd.h
diff --git a/include/asm-mips/lasat/ds1603.h b/arch/mips/include/asm/lasat/ds1603.h
similarity index 100%
rename from include/asm-mips/lasat/ds1603.h
rename to arch/mips/include/asm/lasat/ds1603.h
diff --git a/include/asm-mips/lasat/eeprom.h b/arch/mips/include/asm/lasat/eeprom.h
similarity index 100%
rename from include/asm-mips/lasat/eeprom.h
rename to arch/mips/include/asm/lasat/eeprom.h
diff --git a/include/asm-mips/lasat/head.h b/arch/mips/include/asm/lasat/head.h
similarity index 100%
rename from include/asm-mips/lasat/head.h
rename to arch/mips/include/asm/lasat/head.h
diff --git a/include/asm-mips/lasat/lasat.h b/arch/mips/include/asm/lasat/lasat.h
similarity index 100%
rename from include/asm-mips/lasat/lasat.h
rename to arch/mips/include/asm/lasat/lasat.h
diff --git a/include/asm-mips/lasat/lasatint.h b/arch/mips/include/asm/lasat/lasatint.h
similarity index 100%
rename from include/asm-mips/lasat/lasatint.h
rename to arch/mips/include/asm/lasat/lasatint.h
diff --git a/include/asm-mips/lasat/picvue.h b/arch/mips/include/asm/lasat/picvue.h
similarity index 100%
rename from include/asm-mips/lasat/picvue.h
rename to arch/mips/include/asm/lasat/picvue.h
diff --git a/include/asm-mips/lasat/serial.h b/arch/mips/include/asm/lasat/serial.h
similarity index 100%
rename from include/asm-mips/lasat/serial.h
rename to arch/mips/include/asm/lasat/serial.h
diff --git a/include/asm-mips/linkage.h b/arch/mips/include/asm/linkage.h
similarity index 100%
rename from include/asm-mips/linkage.h
rename to arch/mips/include/asm/linkage.h
diff --git a/include/asm-mips/local.h b/arch/mips/include/asm/local.h
similarity index 100%
rename from include/asm-mips/local.h
rename to arch/mips/include/asm/local.h
diff --git a/include/asm-mips/m48t35.h b/arch/mips/include/asm/m48t35.h
similarity index 100%
rename from include/asm-mips/m48t35.h
rename to arch/mips/include/asm/m48t35.h
diff --git a/include/asm-mips/m48t37.h b/arch/mips/include/asm/m48t37.h
similarity index 100%
rename from include/asm-mips/m48t37.h
rename to arch/mips/include/asm/m48t37.h
diff --git a/include/asm-mips/mach-au1x00/au1000.h b/arch/mips/include/asm/mach-au1x00/au1000.h
similarity index 100%
rename from include/asm-mips/mach-au1x00/au1000.h
rename to arch/mips/include/asm/mach-au1x00/au1000.h
diff --git a/include/asm-mips/mach-au1x00/au1000_dma.h b/arch/mips/include/asm/mach-au1x00/au1000_dma.h
similarity index 100%
rename from include/asm-mips/mach-au1x00/au1000_dma.h
rename to arch/mips/include/asm/mach-au1x00/au1000_dma.h
diff --git a/include/asm-mips/mach-au1x00/au1000_gpio.h b/arch/mips/include/asm/mach-au1x00/au1000_gpio.h
similarity index 100%
rename from include/asm-mips/mach-au1x00/au1000_gpio.h
rename to arch/mips/include/asm/mach-au1x00/au1000_gpio.h
diff --git a/include/asm-mips/mach-au1x00/au1100_mmc.h b/arch/mips/include/asm/mach-au1x00/au1100_mmc.h
similarity index 100%
rename from include/asm-mips/mach-au1x00/au1100_mmc.h
rename to arch/mips/include/asm/mach-au1x00/au1100_mmc.h
diff --git a/include/asm-mips/mach-au1x00/au1550_spi.h b/arch/mips/include/asm/mach-au1x00/au1550_spi.h
similarity index 100%
rename from include/asm-mips/mach-au1x00/au1550_spi.h
rename to arch/mips/include/asm/mach-au1x00/au1550_spi.h
diff --git a/include/asm-mips/mach-au1x00/au1xxx.h b/arch/mips/include/asm/mach-au1x00/au1xxx.h
similarity index 100%
rename from include/asm-mips/mach-au1x00/au1xxx.h
rename to arch/mips/include/asm/mach-au1x00/au1xxx.h
diff --git a/include/asm-mips/mach-au1x00/au1xxx_dbdma.h b/arch/mips/include/asm/mach-au1x00/au1xxx_dbdma.h
similarity index 100%
rename from include/asm-mips/mach-au1x00/au1xxx_dbdma.h
rename to arch/mips/include/asm/mach-au1x00/au1xxx_dbdma.h
diff --git a/include/asm-mips/mach-au1x00/au1xxx_ide.h b/arch/mips/include/asm/mach-au1x00/au1xxx_ide.h
similarity index 100%
rename from include/asm-mips/mach-au1x00/au1xxx_ide.h
rename to arch/mips/include/asm/mach-au1x00/au1xxx_ide.h
diff --git a/include/asm-mips/mach-au1x00/au1xxx_psc.h b/arch/mips/include/asm/mach-au1x00/au1xxx_psc.h
similarity index 100%
rename from include/asm-mips/mach-au1x00/au1xxx_psc.h
rename to arch/mips/include/asm/mach-au1x00/au1xxx_psc.h
diff --git a/include/asm-mips/mach-au1x00/gpio.h b/arch/mips/include/asm/mach-au1x00/gpio.h
similarity index 100%
rename from include/asm-mips/mach-au1x00/gpio.h
rename to arch/mips/include/asm/mach-au1x00/gpio.h
diff --git a/include/asm-mips/mach-au1x00/ioremap.h b/arch/mips/include/asm/mach-au1x00/ioremap.h
similarity index 100%
rename from include/asm-mips/mach-au1x00/ioremap.h
rename to arch/mips/include/asm/mach-au1x00/ioremap.h
diff --git a/include/asm-mips/mach-au1x00/prom.h b/arch/mips/include/asm/mach-au1x00/prom.h
similarity index 100%
rename from include/asm-mips/mach-au1x00/prom.h
rename to arch/mips/include/asm/mach-au1x00/prom.h
diff --git a/include/asm-mips/mach-au1x00/war.h b/arch/mips/include/asm/mach-au1x00/war.h
similarity index 100%
rename from include/asm-mips/mach-au1x00/war.h
rename to arch/mips/include/asm/mach-au1x00/war.h
diff --git a/include/asm-mips/mach-bcm47xx/bcm47xx.h b/arch/mips/include/asm/mach-bcm47xx/bcm47xx.h
similarity index 100%
rename from include/asm-mips/mach-bcm47xx/bcm47xx.h
rename to arch/mips/include/asm/mach-bcm47xx/bcm47xx.h
diff --git a/include/asm-mips/mach-bcm47xx/gpio.h b/arch/mips/include/asm/mach-bcm47xx/gpio.h
similarity index 100%
rename from include/asm-mips/mach-bcm47xx/gpio.h
rename to arch/mips/include/asm/mach-bcm47xx/gpio.h
diff --git a/include/asm-mips/mach-bcm47xx/war.h b/arch/mips/include/asm/mach-bcm47xx/war.h
similarity index 100%
rename from include/asm-mips/mach-bcm47xx/war.h
rename to arch/mips/include/asm/mach-bcm47xx/war.h
diff --git a/include/asm-mips/mach-cobalt/cobalt.h b/arch/mips/include/asm/mach-cobalt/cobalt.h
similarity index 100%
rename from include/asm-mips/mach-cobalt/cobalt.h
rename to arch/mips/include/asm/mach-cobalt/cobalt.h
diff --git a/include/asm-mips/mach-cobalt/cpu-feature-overrides.h b/arch/mips/include/asm/mach-cobalt/cpu-feature-overrides.h
similarity index 100%
rename from include/asm-mips/mach-cobalt/cpu-feature-overrides.h
rename to arch/mips/include/asm/mach-cobalt/cpu-feature-overrides.h
diff --git a/include/asm-mips/mach-cobalt/irq.h b/arch/mips/include/asm/mach-cobalt/irq.h
similarity index 100%
rename from include/asm-mips/mach-cobalt/irq.h
rename to arch/mips/include/asm/mach-cobalt/irq.h
diff --git a/include/asm-mips/mach-cobalt/mach-gt64120.h b/arch/mips/include/asm/mach-cobalt/mach-gt64120.h
similarity index 100%
rename from include/asm-mips/mach-cobalt/mach-gt64120.h
rename to arch/mips/include/asm/mach-cobalt/mach-gt64120.h
diff --git a/include/asm-mips/mach-cobalt/war.h b/arch/mips/include/asm/mach-cobalt/war.h
similarity index 100%
rename from include/asm-mips/mach-cobalt/war.h
rename to arch/mips/include/asm/mach-cobalt/war.h
diff --git a/include/asm-mips/mach-db1x00/db1200.h b/arch/mips/include/asm/mach-db1x00/db1200.h
similarity index 100%
rename from include/asm-mips/mach-db1x00/db1200.h
rename to arch/mips/include/asm/mach-db1x00/db1200.h
diff --git a/include/asm-mips/mach-db1x00/db1x00.h b/arch/mips/include/asm/mach-db1x00/db1x00.h
similarity index 100%
rename from include/asm-mips/mach-db1x00/db1x00.h
rename to arch/mips/include/asm/mach-db1x00/db1x00.h
diff --git a/include/asm-mips/mach-dec/mc146818rtc.h b/arch/mips/include/asm/mach-dec/mc146818rtc.h
similarity index 100%
rename from include/asm-mips/mach-dec/mc146818rtc.h
rename to arch/mips/include/asm/mach-dec/mc146818rtc.h
diff --git a/include/asm-mips/mach-dec/war.h b/arch/mips/include/asm/mach-dec/war.h
similarity index 100%
rename from include/asm-mips/mach-dec/war.h
rename to arch/mips/include/asm/mach-dec/war.h
diff --git a/include/asm-mips/mach-emma2rh/irq.h b/arch/mips/include/asm/mach-emma2rh/irq.h
similarity index 100%
rename from include/asm-mips/mach-emma2rh/irq.h
rename to arch/mips/include/asm/mach-emma2rh/irq.h
diff --git a/include/asm-mips/mach-emma2rh/war.h b/arch/mips/include/asm/mach-emma2rh/war.h
similarity index 100%
rename from include/asm-mips/mach-emma2rh/war.h
rename to arch/mips/include/asm/mach-emma2rh/war.h
diff --git a/include/asm-mips/mach-excite/cpu-feature-overrides.h b/arch/mips/include/asm/mach-excite/cpu-feature-overrides.h
similarity index 100%
rename from include/asm-mips/mach-excite/cpu-feature-overrides.h
rename to arch/mips/include/asm/mach-excite/cpu-feature-overrides.h
diff --git a/include/asm-mips/mach-excite/excite.h b/arch/mips/include/asm/mach-excite/excite.h
similarity index 100%
rename from include/asm-mips/mach-excite/excite.h
rename to arch/mips/include/asm/mach-excite/excite.h
diff --git a/include/asm-mips/mach-excite/excite_fpga.h b/arch/mips/include/asm/mach-excite/excite_fpga.h
similarity index 100%
rename from include/asm-mips/mach-excite/excite_fpga.h
rename to arch/mips/include/asm/mach-excite/excite_fpga.h
diff --git a/include/asm-mips/mach-excite/excite_nandflash.h b/arch/mips/include/asm/mach-excite/excite_nandflash.h
similarity index 100%
rename from include/asm-mips/mach-excite/excite_nandflash.h
rename to arch/mips/include/asm/mach-excite/excite_nandflash.h
diff --git a/include/asm-mips/mach-excite/rm9k_eth.h b/arch/mips/include/asm/mach-excite/rm9k_eth.h
similarity index 100%
rename from include/asm-mips/mach-excite/rm9k_eth.h
rename to arch/mips/include/asm/mach-excite/rm9k_eth.h
diff --git a/include/asm-mips/mach-excite/rm9k_wdt.h b/arch/mips/include/asm/mach-excite/rm9k_wdt.h
similarity index 100%
rename from include/asm-mips/mach-excite/rm9k_wdt.h
rename to arch/mips/include/asm/mach-excite/rm9k_wdt.h
diff --git a/include/asm-mips/mach-excite/rm9k_xicap.h b/arch/mips/include/asm/mach-excite/rm9k_xicap.h
similarity index 100%
rename from include/asm-mips/mach-excite/rm9k_xicap.h
rename to arch/mips/include/asm/mach-excite/rm9k_xicap.h
diff --git a/include/asm-mips/mach-excite/war.h b/arch/mips/include/asm/mach-excite/war.h
similarity index 100%
rename from include/asm-mips/mach-excite/war.h
rename to arch/mips/include/asm/mach-excite/war.h
diff --git a/include/asm-mips/mach-generic/cpu-feature-overrides.h b/arch/mips/include/asm/mach-generic/cpu-feature-overrides.h
similarity index 100%
rename from include/asm-mips/mach-generic/cpu-feature-overrides.h
rename to arch/mips/include/asm/mach-generic/cpu-feature-overrides.h
diff --git a/include/asm-mips/mach-generic/dma-coherence.h b/arch/mips/include/asm/mach-generic/dma-coherence.h
similarity index 100%
rename from include/asm-mips/mach-generic/dma-coherence.h
rename to arch/mips/include/asm/mach-generic/dma-coherence.h
diff --git a/include/asm-mips/mach-generic/floppy.h b/arch/mips/include/asm/mach-generic/floppy.h
similarity index 100%
rename from include/asm-mips/mach-generic/floppy.h
rename to arch/mips/include/asm/mach-generic/floppy.h
diff --git a/include/asm-mips/mach-generic/gpio.h b/arch/mips/include/asm/mach-generic/gpio.h
similarity index 100%
rename from include/asm-mips/mach-generic/gpio.h
rename to arch/mips/include/asm/mach-generic/gpio.h
diff --git a/arch/mips/include/asm/mach-generic/ide.h b/arch/mips/include/asm/mach-generic/ide.h
new file mode 100644
index 0000000..9c93a5b
--- /dev/null
+++ b/arch/mips/include/asm/mach-generic/ide.h
@@ -0,0 +1,138 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 1994-1996  Linus Torvalds & authors
+ *
+ * Copied from i386; many of the especially older MIPS or ISA-based platforms
+ * are basically identical.  Using this file probably implies i8259 PIC
+ * support in a system but the very least interrupt numbers 0 - 15 need to
+ * be put aside for legacy devices.
+ */
+#ifndef __ASM_MACH_GENERIC_IDE_H
+#define __ASM_MACH_GENERIC_IDE_H
+
+#ifdef __KERNEL__
+
+#include <linux/pci.h>
+#include <linux/stddef.h>
+#include <asm/processor.h>
+
+/* MIPS port and memory-mapped I/O string operations.  */
+static inline void __ide_flush_prologue(void)
+{
+#ifdef CONFIG_SMP
+	if (cpu_has_dc_aliases)
+		preempt_disable();
+#endif
+}
+
+static inline void __ide_flush_epilogue(void)
+{
+#ifdef CONFIG_SMP
+	if (cpu_has_dc_aliases)
+		preempt_enable();
+#endif
+}
+
+static inline void __ide_flush_dcache_range(unsigned long addr, unsigned long size)
+{
+	if (cpu_has_dc_aliases) {
+		unsigned long end = addr + size;
+
+		while (addr < end) {
+			local_flush_data_cache_page((void *)addr);
+			addr += PAGE_SIZE;
+		}
+	}
+}
+
+/*
+ * insw() and gang might be called with interrupts disabled, so we can't
+ * send IPIs for flushing due to the potencial of deadlocks, see the comment
+ * above smp_call_function() in arch/mips/kernel/smp.c.  We work around the
+ * problem by disabling preemption so we know we actually perform the flush
+ * on the processor that actually has the lines to be flushed which hopefully
+ * is even better for performance anyway.
+ */
+static inline void __ide_insw(unsigned long port, void *addr,
+	unsigned int count)
+{
+	__ide_flush_prologue();
+	insw(port, addr, count);
+	__ide_flush_dcache_range((unsigned long)addr, count * 2);
+	__ide_flush_epilogue();
+}
+
+static inline void __ide_insl(unsigned long port, void *addr, unsigned int count)
+{
+	__ide_flush_prologue();
+	insl(port, addr, count);
+	__ide_flush_dcache_range((unsigned long)addr, count * 4);
+	__ide_flush_epilogue();
+}
+
+static inline void __ide_outsw(unsigned long port, const void *addr,
+	unsigned long count)
+{
+	__ide_flush_prologue();
+	outsw(port, addr, count);
+	__ide_flush_dcache_range((unsigned long)addr, count * 2);
+	__ide_flush_epilogue();
+}
+
+static inline void __ide_outsl(unsigned long port, const void *addr,
+	unsigned long count)
+{
+	__ide_flush_prologue();
+	outsl(port, addr, count);
+	__ide_flush_dcache_range((unsigned long)addr, count * 4);
+	__ide_flush_epilogue();
+}
+
+static inline void __ide_mm_insw(void __iomem *port, void *addr, u32 count)
+{
+	__ide_flush_prologue();
+	readsw(port, addr, count);
+	__ide_flush_dcache_range((unsigned long)addr, count * 2);
+	__ide_flush_epilogue();
+}
+
+static inline void __ide_mm_insl(void __iomem *port, void *addr, u32 count)
+{
+	__ide_flush_prologue();
+	readsl(port, addr, count);
+	__ide_flush_dcache_range((unsigned long)addr, count * 4);
+	__ide_flush_epilogue();
+}
+
+static inline void __ide_mm_outsw(void __iomem *port, void *addr, u32 count)
+{
+	__ide_flush_prologue();
+	writesw(port, addr, count);
+	__ide_flush_dcache_range((unsigned long)addr, count * 2);
+	__ide_flush_epilogue();
+}
+
+static inline void __ide_mm_outsl(void __iomem * port, void *addr, u32 count)
+{
+	__ide_flush_prologue();
+	writesl(port, addr, count);
+	__ide_flush_dcache_range((unsigned long)addr, count * 4);
+	__ide_flush_epilogue();
+}
+
+/* ide_insw calls insw, not __ide_insw.  Why? */
+#undef insw
+#undef insl
+#undef outsw
+#undef outsl
+#define insw(port, addr, count) __ide_insw(port, addr, count)
+#define insl(port, addr, count) __ide_insl(port, addr, count)
+#define outsw(port, addr, count) __ide_outsw(port, addr, count)
+#define outsl(port, addr, count) __ide_outsl(port, addr, count)
+
+#endif /* __KERNEL__ */
+
+#endif /* __ASM_MACH_GENERIC_IDE_H */
diff --git a/include/asm-mips/mach-generic/ioremap.h b/arch/mips/include/asm/mach-generic/ioremap.h
similarity index 100%
rename from include/asm-mips/mach-generic/ioremap.h
rename to arch/mips/include/asm/mach-generic/ioremap.h
diff --git a/include/asm-mips/mach-generic/irq.h b/arch/mips/include/asm/mach-generic/irq.h
similarity index 100%
rename from include/asm-mips/mach-generic/irq.h
rename to arch/mips/include/asm/mach-generic/irq.h
diff --git a/include/asm-mips/mach-generic/kernel-entry-init.h b/arch/mips/include/asm/mach-generic/kernel-entry-init.h
similarity index 100%
rename from include/asm-mips/mach-generic/kernel-entry-init.h
rename to arch/mips/include/asm/mach-generic/kernel-entry-init.h
diff --git a/include/asm-mips/mach-generic/kmalloc.h b/arch/mips/include/asm/mach-generic/kmalloc.h
similarity index 100%
rename from include/asm-mips/mach-generic/kmalloc.h
rename to arch/mips/include/asm/mach-generic/kmalloc.h
diff --git a/include/asm-mips/mach-generic/mangle-port.h b/arch/mips/include/asm/mach-generic/mangle-port.h
similarity index 100%
rename from include/asm-mips/mach-generic/mangle-port.h
rename to arch/mips/include/asm/mach-generic/mangle-port.h
diff --git a/include/asm-mips/mach-generic/mc146818rtc.h b/arch/mips/include/asm/mach-generic/mc146818rtc.h
similarity index 100%
rename from include/asm-mips/mach-generic/mc146818rtc.h
rename to arch/mips/include/asm/mach-generic/mc146818rtc.h
diff --git a/include/asm-mips/mach-generic/spaces.h b/arch/mips/include/asm/mach-generic/spaces.h
similarity index 100%
rename from include/asm-mips/mach-generic/spaces.h
rename to arch/mips/include/asm/mach-generic/spaces.h
diff --git a/include/asm-mips/mach-generic/topology.h b/arch/mips/include/asm/mach-generic/topology.h
similarity index 100%
rename from include/asm-mips/mach-generic/topology.h
rename to arch/mips/include/asm/mach-generic/topology.h
diff --git a/include/asm-mips/mach-ip22/cpu-feature-overrides.h b/arch/mips/include/asm/mach-ip22/cpu-feature-overrides.h
similarity index 100%
rename from include/asm-mips/mach-ip22/cpu-feature-overrides.h
rename to arch/mips/include/asm/mach-ip22/cpu-feature-overrides.h
diff --git a/include/asm-mips/mach-ip22/ds1286.h b/arch/mips/include/asm/mach-ip22/ds1286.h
similarity index 100%
rename from include/asm-mips/mach-ip22/ds1286.h
rename to arch/mips/include/asm/mach-ip22/ds1286.h
diff --git a/include/asm-mips/mach-ip22/spaces.h b/arch/mips/include/asm/mach-ip22/spaces.h
similarity index 100%
rename from include/asm-mips/mach-ip22/spaces.h
rename to arch/mips/include/asm/mach-ip22/spaces.h
diff --git a/include/asm-mips/mach-ip22/war.h b/arch/mips/include/asm/mach-ip22/war.h
similarity index 100%
rename from include/asm-mips/mach-ip22/war.h
rename to arch/mips/include/asm/mach-ip22/war.h
diff --git a/include/asm-mips/mach-ip27/cpu-feature-overrides.h b/arch/mips/include/asm/mach-ip27/cpu-feature-overrides.h
similarity index 100%
rename from include/asm-mips/mach-ip27/cpu-feature-overrides.h
rename to arch/mips/include/asm/mach-ip27/cpu-feature-overrides.h
diff --git a/include/asm-mips/mach-ip27/dma-coherence.h b/arch/mips/include/asm/mach-ip27/dma-coherence.h
similarity index 100%
rename from include/asm-mips/mach-ip27/dma-coherence.h
rename to arch/mips/include/asm/mach-ip27/dma-coherence.h
diff --git a/include/asm-mips/mach-ip27/irq.h b/arch/mips/include/asm/mach-ip27/irq.h
similarity index 100%
rename from include/asm-mips/mach-ip27/irq.h
rename to arch/mips/include/asm/mach-ip27/irq.h
diff --git a/include/asm-mips/mach-ip27/kernel-entry-init.h b/arch/mips/include/asm/mach-ip27/kernel-entry-init.h
similarity index 100%
rename from include/asm-mips/mach-ip27/kernel-entry-init.h
rename to arch/mips/include/asm/mach-ip27/kernel-entry-init.h
diff --git a/include/asm-mips/mach-ip27/kmalloc.h b/arch/mips/include/asm/mach-ip27/kmalloc.h
similarity index 100%
rename from include/asm-mips/mach-ip27/kmalloc.h
rename to arch/mips/include/asm/mach-ip27/kmalloc.h
diff --git a/include/asm-mips/mach-ip27/mangle-port.h b/arch/mips/include/asm/mach-ip27/mangle-port.h
similarity index 100%
rename from include/asm-mips/mach-ip27/mangle-port.h
rename to arch/mips/include/asm/mach-ip27/mangle-port.h
diff --git a/include/asm-mips/mach-ip27/mmzone.h b/arch/mips/include/asm/mach-ip27/mmzone.h
similarity index 100%
rename from include/asm-mips/mach-ip27/mmzone.h
rename to arch/mips/include/asm/mach-ip27/mmzone.h
diff --git a/include/asm-mips/mach-ip27/spaces.h b/arch/mips/include/asm/mach-ip27/spaces.h
similarity index 100%
rename from include/asm-mips/mach-ip27/spaces.h
rename to arch/mips/include/asm/mach-ip27/spaces.h
diff --git a/include/asm-mips/mach-ip27/topology.h b/arch/mips/include/asm/mach-ip27/topology.h
similarity index 100%
rename from include/asm-mips/mach-ip27/topology.h
rename to arch/mips/include/asm/mach-ip27/topology.h
diff --git a/include/asm-mips/mach-ip27/war.h b/arch/mips/include/asm/mach-ip27/war.h
similarity index 100%
rename from include/asm-mips/mach-ip27/war.h
rename to arch/mips/include/asm/mach-ip27/war.h
diff --git a/include/asm-mips/mach-ip28/cpu-feature-overrides.h b/arch/mips/include/asm/mach-ip28/cpu-feature-overrides.h
similarity index 100%
rename from include/asm-mips/mach-ip28/cpu-feature-overrides.h
rename to arch/mips/include/asm/mach-ip28/cpu-feature-overrides.h
diff --git a/include/asm-mips/mach-ip28/ds1286.h b/arch/mips/include/asm/mach-ip28/ds1286.h
similarity index 100%
rename from include/asm-mips/mach-ip28/ds1286.h
rename to arch/mips/include/asm/mach-ip28/ds1286.h
diff --git a/include/asm-mips/mach-ip28/spaces.h b/arch/mips/include/asm/mach-ip28/spaces.h
similarity index 100%
rename from include/asm-mips/mach-ip28/spaces.h
rename to arch/mips/include/asm/mach-ip28/spaces.h
diff --git a/include/asm-mips/mach-ip28/war.h b/arch/mips/include/asm/mach-ip28/war.h
similarity index 100%
rename from include/asm-mips/mach-ip28/war.h
rename to arch/mips/include/asm/mach-ip28/war.h
diff --git a/include/asm-mips/mach-ip32/cpu-feature-overrides.h b/arch/mips/include/asm/mach-ip32/cpu-feature-overrides.h
similarity index 100%
rename from include/asm-mips/mach-ip32/cpu-feature-overrides.h
rename to arch/mips/include/asm/mach-ip32/cpu-feature-overrides.h
diff --git a/include/asm-mips/mach-ip32/dma-coherence.h b/arch/mips/include/asm/mach-ip32/dma-coherence.h
similarity index 100%
rename from include/asm-mips/mach-ip32/dma-coherence.h
rename to arch/mips/include/asm/mach-ip32/dma-coherence.h
diff --git a/include/asm-mips/mach-ip32/kmalloc.h b/arch/mips/include/asm/mach-ip32/kmalloc.h
similarity index 100%
rename from include/asm-mips/mach-ip32/kmalloc.h
rename to arch/mips/include/asm/mach-ip32/kmalloc.h
diff --git a/include/asm-mips/mach-ip32/mangle-port.h b/arch/mips/include/asm/mach-ip32/mangle-port.h
similarity index 100%
rename from include/asm-mips/mach-ip32/mangle-port.h
rename to arch/mips/include/asm/mach-ip32/mangle-port.h
diff --git a/include/asm-mips/mach-ip32/mc146818rtc.h b/arch/mips/include/asm/mach-ip32/mc146818rtc.h
similarity index 100%
rename from include/asm-mips/mach-ip32/mc146818rtc.h
rename to arch/mips/include/asm/mach-ip32/mc146818rtc.h
diff --git a/include/asm-mips/mach-ip32/war.h b/arch/mips/include/asm/mach-ip32/war.h
similarity index 100%
rename from include/asm-mips/mach-ip32/war.h
rename to arch/mips/include/asm/mach-ip32/war.h
diff --git a/include/asm-mips/mach-jazz/dma-coherence.h b/arch/mips/include/asm/mach-jazz/dma-coherence.h
similarity index 100%
rename from include/asm-mips/mach-jazz/dma-coherence.h
rename to arch/mips/include/asm/mach-jazz/dma-coherence.h
diff --git a/include/asm-mips/mach-jazz/floppy.h b/arch/mips/include/asm/mach-jazz/floppy.h
similarity index 100%
rename from include/asm-mips/mach-jazz/floppy.h
rename to arch/mips/include/asm/mach-jazz/floppy.h
diff --git a/include/asm-mips/mach-jazz/mc146818rtc.h b/arch/mips/include/asm/mach-jazz/mc146818rtc.h
similarity index 100%
rename from include/asm-mips/mach-jazz/mc146818rtc.h
rename to arch/mips/include/asm/mach-jazz/mc146818rtc.h
diff --git a/include/asm-mips/mach-jazz/war.h b/arch/mips/include/asm/mach-jazz/war.h
similarity index 100%
rename from include/asm-mips/mach-jazz/war.h
rename to arch/mips/include/asm/mach-jazz/war.h
diff --git a/include/asm-mips/mach-lasat/irq.h b/arch/mips/include/asm/mach-lasat/irq.h
similarity index 100%
rename from include/asm-mips/mach-lasat/irq.h
rename to arch/mips/include/asm/mach-lasat/irq.h
diff --git a/include/asm-mips/mach-lasat/mach-gt64120.h b/arch/mips/include/asm/mach-lasat/mach-gt64120.h
similarity index 100%
rename from include/asm-mips/mach-lasat/mach-gt64120.h
rename to arch/mips/include/asm/mach-lasat/mach-gt64120.h
diff --git a/include/asm-mips/mach-lasat/war.h b/arch/mips/include/asm/mach-lasat/war.h
similarity index 100%
rename from include/asm-mips/mach-lasat/war.h
rename to arch/mips/include/asm/mach-lasat/war.h
diff --git a/include/asm-mips/mach-lemote/dma-coherence.h b/arch/mips/include/asm/mach-lemote/dma-coherence.h
similarity index 100%
rename from include/asm-mips/mach-lemote/dma-coherence.h
rename to arch/mips/include/asm/mach-lemote/dma-coherence.h
diff --git a/include/asm-mips/mach-lemote/mc146818rtc.h b/arch/mips/include/asm/mach-lemote/mc146818rtc.h
similarity index 100%
rename from include/asm-mips/mach-lemote/mc146818rtc.h
rename to arch/mips/include/asm/mach-lemote/mc146818rtc.h
diff --git a/include/asm-mips/mach-lemote/war.h b/arch/mips/include/asm/mach-lemote/war.h
similarity index 100%
rename from include/asm-mips/mach-lemote/war.h
rename to arch/mips/include/asm/mach-lemote/war.h
diff --git a/include/asm-mips/mach-malta/cpu-feature-overrides.h b/arch/mips/include/asm/mach-malta/cpu-feature-overrides.h
similarity index 100%
rename from include/asm-mips/mach-malta/cpu-feature-overrides.h
rename to arch/mips/include/asm/mach-malta/cpu-feature-overrides.h
diff --git a/include/asm-mips/mach-malta/irq.h b/arch/mips/include/asm/mach-malta/irq.h
similarity index 100%
rename from include/asm-mips/mach-malta/irq.h
rename to arch/mips/include/asm/mach-malta/irq.h
diff --git a/include/asm-mips/mach-malta/kernel-entry-init.h b/arch/mips/include/asm/mach-malta/kernel-entry-init.h
similarity index 100%
rename from include/asm-mips/mach-malta/kernel-entry-init.h
rename to arch/mips/include/asm/mach-malta/kernel-entry-init.h
diff --git a/include/asm-mips/mach-malta/mach-gt64120.h b/arch/mips/include/asm/mach-malta/mach-gt64120.h
similarity index 100%
rename from include/asm-mips/mach-malta/mach-gt64120.h
rename to arch/mips/include/asm/mach-malta/mach-gt64120.h
diff --git a/include/asm-mips/mach-malta/mc146818rtc.h b/arch/mips/include/asm/mach-malta/mc146818rtc.h
similarity index 100%
rename from include/asm-mips/mach-malta/mc146818rtc.h
rename to arch/mips/include/asm/mach-malta/mc146818rtc.h
diff --git a/include/asm-mips/mach-malta/war.h b/arch/mips/include/asm/mach-malta/war.h
similarity index 100%
rename from include/asm-mips/mach-malta/war.h
rename to arch/mips/include/asm/mach-malta/war.h
diff --git a/include/asm-mips/mach-mipssim/cpu-feature-overrides.h b/arch/mips/include/asm/mach-mipssim/cpu-feature-overrides.h
similarity index 100%
rename from include/asm-mips/mach-mipssim/cpu-feature-overrides.h
rename to arch/mips/include/asm/mach-mipssim/cpu-feature-overrides.h
diff --git a/include/asm-mips/mach-mipssim/war.h b/arch/mips/include/asm/mach-mipssim/war.h
similarity index 100%
rename from include/asm-mips/mach-mipssim/war.h
rename to arch/mips/include/asm/mach-mipssim/war.h
diff --git a/include/asm-mips/mach-pb1x00/mc146818rtc.h b/arch/mips/include/asm/mach-pb1x00/mc146818rtc.h
similarity index 100%
rename from include/asm-mips/mach-pb1x00/mc146818rtc.h
rename to arch/mips/include/asm/mach-pb1x00/mc146818rtc.h
diff --git a/include/asm-mips/mach-pb1x00/pb1000.h b/arch/mips/include/asm/mach-pb1x00/pb1000.h
similarity index 100%
rename from include/asm-mips/mach-pb1x00/pb1000.h
rename to arch/mips/include/asm/mach-pb1x00/pb1000.h
diff --git a/include/asm-mips/mach-pb1x00/pb1100.h b/arch/mips/include/asm/mach-pb1x00/pb1100.h
similarity index 100%
rename from include/asm-mips/mach-pb1x00/pb1100.h
rename to arch/mips/include/asm/mach-pb1x00/pb1100.h
diff --git a/include/asm-mips/mach-pb1x00/pb1200.h b/arch/mips/include/asm/mach-pb1x00/pb1200.h
similarity index 100%
rename from include/asm-mips/mach-pb1x00/pb1200.h
rename to arch/mips/include/asm/mach-pb1x00/pb1200.h
diff --git a/include/asm-mips/mach-pb1x00/pb1500.h b/arch/mips/include/asm/mach-pb1x00/pb1500.h
similarity index 100%
rename from include/asm-mips/mach-pb1x00/pb1500.h
rename to arch/mips/include/asm/mach-pb1x00/pb1500.h
diff --git a/include/asm-mips/mach-pb1x00/pb1550.h b/arch/mips/include/asm/mach-pb1x00/pb1550.h
similarity index 100%
rename from include/asm-mips/mach-pb1x00/pb1550.h
rename to arch/mips/include/asm/mach-pb1x00/pb1550.h
diff --git a/include/asm-mips/mach-pnx8550/cm.h b/arch/mips/include/asm/mach-pnx8550/cm.h
similarity index 100%
rename from include/asm-mips/mach-pnx8550/cm.h
rename to arch/mips/include/asm/mach-pnx8550/cm.h
diff --git a/include/asm-mips/mach-pnx8550/glb.h b/arch/mips/include/asm/mach-pnx8550/glb.h
similarity index 100%
rename from include/asm-mips/mach-pnx8550/glb.h
rename to arch/mips/include/asm/mach-pnx8550/glb.h
diff --git a/include/asm-mips/mach-pnx8550/int.h b/arch/mips/include/asm/mach-pnx8550/int.h
similarity index 100%
rename from include/asm-mips/mach-pnx8550/int.h
rename to arch/mips/include/asm/mach-pnx8550/int.h
diff --git a/include/asm-mips/mach-pnx8550/kernel-entry-init.h b/arch/mips/include/asm/mach-pnx8550/kernel-entry-init.h
similarity index 100%
rename from include/asm-mips/mach-pnx8550/kernel-entry-init.h
rename to arch/mips/include/asm/mach-pnx8550/kernel-entry-init.h
diff --git a/include/asm-mips/mach-pnx8550/nand.h b/arch/mips/include/asm/mach-pnx8550/nand.h
similarity index 100%
rename from include/asm-mips/mach-pnx8550/nand.h
rename to arch/mips/include/asm/mach-pnx8550/nand.h
diff --git a/include/asm-mips/mach-pnx8550/pci.h b/arch/mips/include/asm/mach-pnx8550/pci.h
similarity index 100%
rename from include/asm-mips/mach-pnx8550/pci.h
rename to arch/mips/include/asm/mach-pnx8550/pci.h
diff --git a/include/asm-mips/mach-pnx8550/uart.h b/arch/mips/include/asm/mach-pnx8550/uart.h
similarity index 100%
rename from include/asm-mips/mach-pnx8550/uart.h
rename to arch/mips/include/asm/mach-pnx8550/uart.h
diff --git a/include/asm-mips/mach-pnx8550/usb.h b/arch/mips/include/asm/mach-pnx8550/usb.h
similarity index 100%
rename from include/asm-mips/mach-pnx8550/usb.h
rename to arch/mips/include/asm/mach-pnx8550/usb.h
diff --git a/include/asm-mips/mach-pnx8550/war.h b/arch/mips/include/asm/mach-pnx8550/war.h
similarity index 100%
rename from include/asm-mips/mach-pnx8550/war.h
rename to arch/mips/include/asm/mach-pnx8550/war.h
diff --git a/include/asm-mips/mach-rc32434/cpu-feature-overrides.h b/arch/mips/include/asm/mach-rc32434/cpu-feature-overrides.h
similarity index 100%
rename from include/asm-mips/mach-rc32434/cpu-feature-overrides.h
rename to arch/mips/include/asm/mach-rc32434/cpu-feature-overrides.h
diff --git a/include/asm-mips/mach-rc32434/ddr.h b/arch/mips/include/asm/mach-rc32434/ddr.h
similarity index 100%
rename from include/asm-mips/mach-rc32434/ddr.h
rename to arch/mips/include/asm/mach-rc32434/ddr.h
diff --git a/include/asm-mips/mach-rc32434/dma.h b/arch/mips/include/asm/mach-rc32434/dma.h
similarity index 100%
rename from include/asm-mips/mach-rc32434/dma.h
rename to arch/mips/include/asm/mach-rc32434/dma.h
diff --git a/include/asm-mips/mach-rc32434/dma_v.h b/arch/mips/include/asm/mach-rc32434/dma_v.h
similarity index 100%
rename from include/asm-mips/mach-rc32434/dma_v.h
rename to arch/mips/include/asm/mach-rc32434/dma_v.h
diff --git a/include/asm-mips/mach-rc32434/eth.h b/arch/mips/include/asm/mach-rc32434/eth.h
similarity index 100%
rename from include/asm-mips/mach-rc32434/eth.h
rename to arch/mips/include/asm/mach-rc32434/eth.h
diff --git a/arch/mips/include/asm/mach-rc32434/gpio.h b/arch/mips/include/asm/mach-rc32434/gpio.h
new file mode 100644
index 0000000..c8e554e
--- /dev/null
+++ b/arch/mips/include/asm/mach-rc32434/gpio.h
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2002 Integrated Device Technology, Inc.
+ *	All rights reserved.
+ *
+ * GPIO register definition.
+ *
+ * Author : ryan.holmQVist@idt.com
+ * Date   : 20011005
+ * Copyright (C) 2001, 2002 Ryan Holm <ryan.holmQVist@idt.com>
+ * Copyright (C) 2008 Florian Fainelli <florian@openwrt.org>
+ */
+
+#ifndef _RC32434_GPIO_H_
+#define _RC32434_GPIO_H_
+
+#include <linux/types.h>
+#include <asm-generic/gpio.h>
+
+#define NR_BUILTIN_GPIO		32
+
+#define gpio_get_value	__gpio_get_value
+#define gpio_set_value	__gpio_set_value
+#define gpio_cansleep	__gpio_cansleep
+
+#define gpio_to_irq(gpio)	(8 + 4 * 32 + gpio)
+#define irq_to_gpio(irq)	(irq - (8 + 4 * 32))
+
+struct rb532_gpio_reg {
+	u32   gpiofunc;   /* GPIO Function Register
+			   * gpiofunc[x]==0 bit = gpio
+			   * func[x]==1  bit = altfunc
+			   */
+	u32   gpiocfg;	  /* GPIO Configuration Register
+			   * gpiocfg[x]==0 bit = input
+			   * gpiocfg[x]==1 bit = output
+			   */
+	u32   gpiod;	  /* GPIO Data Register
+			   * gpiod[x] read/write gpio pinX status
+			   */
+	u32   gpioilevel; /* GPIO Interrupt Status Register
+			   * interrupt level (see gpioistat)
+			   */
+	u32   gpioistat;  /* Gpio Interrupt Status Register
+			   * istat[x] = (gpiod[x] == level[x])
+			   * cleared in ISR (STICKY bits)
+			   */
+	u32   gpionmien;  /* GPIO Non-maskable Interrupt Enable Register */
+};
+
+/* UART GPIO signals */
+#define RC32434_UART0_SOUT	(1 << 0)
+#define RC32434_UART0_SIN	(1 << 1)
+#define RC32434_UART0_RTS	(1 << 2)
+#define RC32434_UART0_CTS	(1 << 3)
+
+/* M & P bus GPIO signals */
+#define RC32434_MP_BIT_22	(1 << 4)
+#define RC32434_MP_BIT_23	(1 << 5)
+#define RC32434_MP_BIT_24	(1 << 6)
+#define RC32434_MP_BIT_25	(1 << 7)
+
+/* CPU GPIO signals */
+#define RC32434_CPU_GPIO	(1 << 8)
+
+/* Reserved GPIO signals */
+#define RC32434_AF_SPARE_6	(1 << 9)
+#define RC32434_AF_SPARE_4	(1 << 10)
+#define RC32434_AF_SPARE_3	(1 << 11)
+#define RC32434_AF_SPARE_2	(1 << 12)
+
+/* PCI messaging unit */
+#define RC32434_PCI_MSU_GPIO	(1 << 13)
+
+/* NAND GPIO signals */
+#define GPIO_RDY		8
+#define GPIO_WPX	9
+#define GPIO_ALE		10
+#define GPIO_CLE		11
+
+/* Compact Flash GPIO pin */
+#define CF_GPIO_NUM		13
+
+extern void set_434_reg(unsigned reg_offs, unsigned bit, unsigned len, unsigned val);
+extern unsigned get_434_reg(unsigned reg_offs);
+extern void set_latch_u5(unsigned char or_mask, unsigned char nand_mask);
+extern unsigned char get_latch_u5(void);
+
+#endif /* _RC32434_GPIO_H_ */
diff --git a/include/asm-mips/mach-rc32434/integ.h b/arch/mips/include/asm/mach-rc32434/integ.h
similarity index 100%
rename from include/asm-mips/mach-rc32434/integ.h
rename to arch/mips/include/asm/mach-rc32434/integ.h
diff --git a/arch/mips/include/asm/mach-rc32434/irq.h b/arch/mips/include/asm/mach-rc32434/irq.h
new file mode 100644
index 0000000..56738d8
--- /dev/null
+++ b/arch/mips/include/asm/mach-rc32434/irq.h
@@ -0,0 +1,33 @@
+#ifndef __ASM_RC32434_IRQ_H
+#define __ASM_RC32434_IRQ_H
+
+#define NR_IRQS	256
+
+#include <asm/mach-generic/irq.h>
+#include <asm/mach-rc32434/rb.h>
+
+/* Interrupt Controller */
+#define IC_GROUP0_PEND		(REGBASE + 0x38000)
+#define IC_GROUP0_MASK		(REGBASE + 0x38008)
+#define IC_GROUP_OFFSET		0x0C
+
+#define NUM_INTR_GROUPS		5
+
+/* 16550 UARTs */
+#define GROUP0_IRQ_BASE		8	/* GRP2 IRQ numbers start here */
+					/* GRP3 IRQ numbers start here */
+#define GROUP1_IRQ_BASE		(GROUP0_IRQ_BASE + 32)
+					/* GRP4 IRQ numbers start here */
+#define GROUP2_IRQ_BASE		(GROUP1_IRQ_BASE + 32)
+					/* GRP5 IRQ numbers start here */
+#define GROUP3_IRQ_BASE		(GROUP2_IRQ_BASE + 32)
+#define GROUP4_IRQ_BASE		(GROUP3_IRQ_BASE + 32)
+
+#define UART0_IRQ		(GROUP3_IRQ_BASE + 0)
+
+#define ETH0_DMA_RX_IRQ   	(GROUP1_IRQ_BASE + 0)
+#define ETH0_DMA_TX_IRQ   	(GROUP1_IRQ_BASE + 1)
+#define ETH0_RX_OVR_IRQ   	(GROUP3_IRQ_BASE + 9)
+#define ETH0_TX_UND_IRQ   	(GROUP3_IRQ_BASE + 10)
+
+#endif  /* __ASM_RC32434_IRQ_H */
diff --git a/include/asm-mips/mach-rc32434/pci.h b/arch/mips/include/asm/mach-rc32434/pci.h
similarity index 100%
rename from include/asm-mips/mach-rc32434/pci.h
rename to arch/mips/include/asm/mach-rc32434/pci.h
diff --git a/arch/mips/include/asm/mach-rc32434/prom.h b/arch/mips/include/asm/mach-rc32434/prom.h
new file mode 100644
index 0000000..660707f
--- /dev/null
+++ b/arch/mips/include/asm/mach-rc32434/prom.h
@@ -0,0 +1,40 @@
+/*
+ *  Definitions for the PROM
+ *
+ *  Copyright 2002 Ryan Holm <ryan.holmQVist@idt.com>
+ *  Copyright 2008 Florian Fainelli <florian@openwrt.org>
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ *  THIS  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.
+ *
+ */
+
+#define PROM_ENTRY(x)		(0xbfc00000 + ((x) * 8))
+
+#define SR_NMI			0x00180000
+#define SERIAL_SPEED_ENTRY	0x00000001
+
+#define FREQ_TAG		"HZ="
+#define KMAC_TAG		"kmac="
+#define MEM_TAG			"mem="
+#define BOARD_TAG		"board="
+
+#define BOARD_RB532		"500"
+#define BOARD_RB532A		"500r5"
diff --git a/arch/mips/include/asm/mach-rc32434/rb.h b/arch/mips/include/asm/mach-rc32434/rb.h
new file mode 100644
index 0000000..79e8ef6
--- /dev/null
+++ b/arch/mips/include/asm/mach-rc32434/rb.h
@@ -0,0 +1,84 @@
+/*
+ *  This program is free software; you can redistribute it and/or 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.
+ *
+ *  Copyright (C) 2004 IDT Inc.
+ *  Copyright (C) 2006 Felix Fietkau <nbd@openwrt.org>
+ */
+#ifndef __ASM_RC32434_RB_H
+#define __ASM_RC32434_RB_H
+
+#include <linux/genhd.h>
+
+#define REGBASE		0x18000000
+#define IDT434_REG_BASE	((volatile void *) KSEG1ADDR(REGBASE))
+#define UART0BASE	0x58000
+#define RST		(1 << 15)
+#define DEV0BASE	0x010000
+#define DEV0MASK	0x010004
+#define DEV0C		0x010008
+#define DEV0T		0x01000C
+#define DEV1BASE	0x010010
+#define DEV1MASK	0x010014
+#define DEV1C		0x010018
+#define DEV1TC		0x01001C
+#define DEV2BASE	0x010020
+#define DEV2MASK	0x010024
+#define DEV2C		0x010028
+#define DEV2TC		0x01002C
+#define DEV3BASE	0x010030
+#define DEV3MASK	0x010034
+#define DEV3C		0x010038
+#define DEV3TC		0x01003C
+#define BTCS		0x010040
+#define BTCOMPARE	0x010044
+#define GPIOBASE	0x050000
+#define GPIOCFG		0x050004
+#define GPIOD		0x050008
+#define GPIOILEVEL	0x05000C
+#define GPIOISTAT	0x050010
+#define GPIONMIEN	0x050014
+#define IMASK6		0x038038
+#define LO_WPX		(1 << 0)
+#define LO_ALE		(1 << 1)
+#define LO_CLE		(1 << 2)
+#define LO_CEX		(1 << 3)
+#define LO_FOFF		(1 << 5)
+#define LO_SPICS	(1 << 6)
+#define LO_ULED		(1 << 7)
+
+#define BIT_TO_MASK(x)	(1 << x)
+
+struct dev_reg {
+	u32	base;
+	u32	mask;
+	u32	ctl;
+	u32	timing;
+};
+
+struct korina_device {
+	char *name;
+	unsigned char mac[6];
+	struct net_device *dev;
+};
+
+struct cf_device {
+	int gpio_pin;
+	void *dev;
+	struct gendisk *gd;
+};
+
+struct mpmc_device {
+	unsigned char	state;
+	spinlock_t	lock;
+	void __iomem 	*base;
+};
+
+#endif  /* __ASM_RC32434_RB_H */
diff --git a/arch/mips/include/asm/mach-rc32434/rc32434.h b/arch/mips/include/asm/mach-rc32434/rc32434.h
new file mode 100644
index 0000000..fce25d4
--- /dev/null
+++ b/arch/mips/include/asm/mach-rc32434/rc32434.h
@@ -0,0 +1,19 @@
+/*
+ * Definitions for IDT RC323434 CPU.
+ */
+
+#ifndef _ASM_RC32434_RC32434_H_
+#define _ASM_RC32434_RC32434_H_
+
+#include <linux/delay.h>
+#include <linux/io.h>
+
+#define IDT_CLOCK_MULT		2
+
+/* cpu pipeline flush */
+static inline void rc32434_sync(void)
+{
+	__asm__ volatile ("sync");
+}
+
+#endif  /* _ASM_RC32434_RC32434_H_ */
diff --git a/include/asm-mips/mach-rc32434/timer.h b/arch/mips/include/asm/mach-rc32434/timer.h
similarity index 100%
rename from include/asm-mips/mach-rc32434/timer.h
rename to arch/mips/include/asm/mach-rc32434/timer.h
diff --git a/include/asm-mips/mach-rc32434/war.h b/arch/mips/include/asm/mach-rc32434/war.h
similarity index 100%
rename from include/asm-mips/mach-rc32434/war.h
rename to arch/mips/include/asm/mach-rc32434/war.h
diff --git a/include/asm-mips/mach-rm/cpu-feature-overrides.h b/arch/mips/include/asm/mach-rm/cpu-feature-overrides.h
similarity index 100%
rename from include/asm-mips/mach-rm/cpu-feature-overrides.h
rename to arch/mips/include/asm/mach-rm/cpu-feature-overrides.h
diff --git a/include/asm-mips/mach-rm/mc146818rtc.h b/arch/mips/include/asm/mach-rm/mc146818rtc.h
similarity index 100%
rename from include/asm-mips/mach-rm/mc146818rtc.h
rename to arch/mips/include/asm/mach-rm/mc146818rtc.h
diff --git a/include/asm-mips/mach-rm/war.h b/arch/mips/include/asm/mach-rm/war.h
similarity index 100%
rename from include/asm-mips/mach-rm/war.h
rename to arch/mips/include/asm/mach-rm/war.h
diff --git a/include/asm-mips/mach-sibyte/cpu-feature-overrides.h b/arch/mips/include/asm/mach-sibyte/cpu-feature-overrides.h
similarity index 100%
rename from include/asm-mips/mach-sibyte/cpu-feature-overrides.h
rename to arch/mips/include/asm/mach-sibyte/cpu-feature-overrides.h
diff --git a/include/asm-mips/mach-sibyte/war.h b/arch/mips/include/asm/mach-sibyte/war.h
similarity index 100%
rename from include/asm-mips/mach-sibyte/war.h
rename to arch/mips/include/asm/mach-sibyte/war.h
diff --git a/include/asm-mips/mach-tx39xx/ioremap.h b/arch/mips/include/asm/mach-tx39xx/ioremap.h
similarity index 100%
rename from include/asm-mips/mach-tx39xx/ioremap.h
rename to arch/mips/include/asm/mach-tx39xx/ioremap.h
diff --git a/include/asm-mips/mach-tx39xx/mangle-port.h b/arch/mips/include/asm/mach-tx39xx/mangle-port.h
similarity index 100%
rename from include/asm-mips/mach-tx39xx/mangle-port.h
rename to arch/mips/include/asm/mach-tx39xx/mangle-port.h
diff --git a/include/asm-mips/mach-tx39xx/war.h b/arch/mips/include/asm/mach-tx39xx/war.h
similarity index 100%
rename from include/asm-mips/mach-tx39xx/war.h
rename to arch/mips/include/asm/mach-tx39xx/war.h
diff --git a/include/asm-mips/mach-tx49xx/cpu-feature-overrides.h b/arch/mips/include/asm/mach-tx49xx/cpu-feature-overrides.h
similarity index 100%
rename from include/asm-mips/mach-tx49xx/cpu-feature-overrides.h
rename to arch/mips/include/asm/mach-tx49xx/cpu-feature-overrides.h
diff --git a/include/asm-mips/mach-tx49xx/ioremap.h b/arch/mips/include/asm/mach-tx49xx/ioremap.h
similarity index 100%
rename from include/asm-mips/mach-tx49xx/ioremap.h
rename to arch/mips/include/asm/mach-tx49xx/ioremap.h
diff --git a/include/asm-mips/mach-tx49xx/kmalloc.h b/arch/mips/include/asm/mach-tx49xx/kmalloc.h
similarity index 100%
rename from include/asm-mips/mach-tx49xx/kmalloc.h
rename to arch/mips/include/asm/mach-tx49xx/kmalloc.h
diff --git a/include/asm-mips/mach-tx49xx/war.h b/arch/mips/include/asm/mach-tx49xx/war.h
similarity index 100%
rename from include/asm-mips/mach-tx49xx/war.h
rename to arch/mips/include/asm/mach-tx49xx/war.h
diff --git a/include/asm-mips/mach-vr41xx/irq.h b/arch/mips/include/asm/mach-vr41xx/irq.h
similarity index 100%
rename from include/asm-mips/mach-vr41xx/irq.h
rename to arch/mips/include/asm/mach-vr41xx/irq.h
diff --git a/include/asm-mips/mach-vr41xx/war.h b/arch/mips/include/asm/mach-vr41xx/war.h
similarity index 100%
rename from include/asm-mips/mach-vr41xx/war.h
rename to arch/mips/include/asm/mach-vr41xx/war.h
diff --git a/include/asm-mips/mach-wrppmc/mach-gt64120.h b/arch/mips/include/asm/mach-wrppmc/mach-gt64120.h
similarity index 100%
rename from include/asm-mips/mach-wrppmc/mach-gt64120.h
rename to arch/mips/include/asm/mach-wrppmc/mach-gt64120.h
diff --git a/include/asm-mips/mach-wrppmc/war.h b/arch/mips/include/asm/mach-wrppmc/war.h
similarity index 100%
rename from include/asm-mips/mach-wrppmc/war.h
rename to arch/mips/include/asm/mach-wrppmc/war.h
diff --git a/include/asm-mips/mach-yosemite/cpu-feature-overrides.h b/arch/mips/include/asm/mach-yosemite/cpu-feature-overrides.h
similarity index 100%
rename from include/asm-mips/mach-yosemite/cpu-feature-overrides.h
rename to arch/mips/include/asm/mach-yosemite/cpu-feature-overrides.h
diff --git a/include/asm-mips/mach-yosemite/war.h b/arch/mips/include/asm/mach-yosemite/war.h
similarity index 100%
rename from include/asm-mips/mach-yosemite/war.h
rename to arch/mips/include/asm/mach-yosemite/war.h
diff --git a/include/asm-mips/mc146818-time.h b/arch/mips/include/asm/mc146818-time.h
similarity index 100%
rename from include/asm-mips/mc146818-time.h
rename to arch/mips/include/asm/mc146818-time.h
diff --git a/include/asm-mips/mc146818rtc.h b/arch/mips/include/asm/mc146818rtc.h
similarity index 100%
rename from include/asm-mips/mc146818rtc.h
rename to arch/mips/include/asm/mc146818rtc.h
diff --git a/include/asm-mips/mips-boards/bonito64.h b/arch/mips/include/asm/mips-boards/bonito64.h
similarity index 100%
rename from include/asm-mips/mips-boards/bonito64.h
rename to arch/mips/include/asm/mips-boards/bonito64.h
diff --git a/include/asm-mips/mips-boards/generic.h b/arch/mips/include/asm/mips-boards/generic.h
similarity index 100%
rename from include/asm-mips/mips-boards/generic.h
rename to arch/mips/include/asm/mips-boards/generic.h
diff --git a/include/asm-mips/mips-boards/launch.h b/arch/mips/include/asm/mips-boards/launch.h
similarity index 100%
rename from include/asm-mips/mips-boards/launch.h
rename to arch/mips/include/asm/mips-boards/launch.h
diff --git a/include/asm-mips/mips-boards/malta.h b/arch/mips/include/asm/mips-boards/malta.h
similarity index 100%
rename from include/asm-mips/mips-boards/malta.h
rename to arch/mips/include/asm/mips-boards/malta.h
diff --git a/include/asm-mips/mips-boards/maltaint.h b/arch/mips/include/asm/mips-boards/maltaint.h
similarity index 100%
rename from include/asm-mips/mips-boards/maltaint.h
rename to arch/mips/include/asm/mips-boards/maltaint.h
diff --git a/include/asm-mips/mips-boards/msc01_pci.h b/arch/mips/include/asm/mips-boards/msc01_pci.h
similarity index 100%
rename from include/asm-mips/mips-boards/msc01_pci.h
rename to arch/mips/include/asm/mips-boards/msc01_pci.h
diff --git a/include/asm-mips/mips-boards/piix4.h b/arch/mips/include/asm/mips-boards/piix4.h
similarity index 100%
rename from include/asm-mips/mips-boards/piix4.h
rename to arch/mips/include/asm/mips-boards/piix4.h
diff --git a/include/asm-mips/mips-boards/prom.h b/arch/mips/include/asm/mips-boards/prom.h
similarity index 100%
rename from include/asm-mips/mips-boards/prom.h
rename to arch/mips/include/asm/mips-boards/prom.h
diff --git a/include/asm-mips/mips-boards/sim.h b/arch/mips/include/asm/mips-boards/sim.h
similarity index 100%
rename from include/asm-mips/mips-boards/sim.h
rename to arch/mips/include/asm/mips-boards/sim.h
diff --git a/include/asm-mips/mips-boards/simint.h b/arch/mips/include/asm/mips-boards/simint.h
similarity index 100%
rename from include/asm-mips/mips-boards/simint.h
rename to arch/mips/include/asm/mips-boards/simint.h
diff --git a/include/asm-mips/mips_mt.h b/arch/mips/include/asm/mips_mt.h
similarity index 100%
rename from include/asm-mips/mips_mt.h
rename to arch/mips/include/asm/mips_mt.h
diff --git a/include/asm-mips/mipsmtregs.h b/arch/mips/include/asm/mipsmtregs.h
similarity index 100%
rename from include/asm-mips/mipsmtregs.h
rename to arch/mips/include/asm/mipsmtregs.h
diff --git a/include/asm-mips/mipsprom.h b/arch/mips/include/asm/mipsprom.h
similarity index 100%
rename from include/asm-mips/mipsprom.h
rename to arch/mips/include/asm/mipsprom.h
diff --git a/arch/mips/include/asm/mipsregs.h b/arch/mips/include/asm/mipsregs.h
new file mode 100644
index 0000000..9798660
--- /dev/null
+++ b/arch/mips/include/asm/mipsregs.h
@@ -0,0 +1,1526 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 1994, 1995, 1996, 1997, 2000, 2001 by Ralf Baechle
+ * Copyright (C) 2000 Silicon Graphics, Inc.
+ * Modified for further R[236]000 support by Paul M. Antoine, 1996.
+ * Kevin D. Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com
+ * Copyright (C) 2000, 07 MIPS Technologies, Inc.
+ * Copyright (C) 2003, 2004  Maciej W. Rozycki
+ */
+#ifndef _ASM_MIPSREGS_H
+#define _ASM_MIPSREGS_H
+
+#include <linux/linkage.h>
+#include <asm/hazards.h>
+#include <asm/war.h>
+
+/*
+ * The following macros are especially useful for __asm__
+ * inline assembler.
+ */
+#ifndef __STR
+#define __STR(x) #x
+#endif
+#ifndef STR
+#define STR(x) __STR(x)
+#endif
+
+/*
+ *  Configure language
+ */
+#ifdef __ASSEMBLY__
+#define _ULCAST_
+#else
+#define _ULCAST_ (unsigned long)
+#endif
+
+/*
+ * Coprocessor 0 register names
+ */
+#define CP0_INDEX $0
+#define CP0_RANDOM $1
+#define CP0_ENTRYLO0 $2
+#define CP0_ENTRYLO1 $3
+#define CP0_CONF $3
+#define CP0_CONTEXT $4
+#define CP0_PAGEMASK $5
+#define CP0_WIRED $6
+#define CP0_INFO $7
+#define CP0_BADVADDR $8
+#define CP0_COUNT $9
+#define CP0_ENTRYHI $10
+#define CP0_COMPARE $11
+#define CP0_STATUS $12
+#define CP0_CAUSE $13
+#define CP0_EPC $14
+#define CP0_PRID $15
+#define CP0_CONFIG $16
+#define CP0_LLADDR $17
+#define CP0_WATCHLO $18
+#define CP0_WATCHHI $19
+#define CP0_XCONTEXT $20
+#define CP0_FRAMEMASK $21
+#define CP0_DIAGNOSTIC $22
+#define CP0_DEBUG $23
+#define CP0_DEPC $24
+#define CP0_PERFORMANCE $25
+#define CP0_ECC $26
+#define CP0_CACHEERR $27
+#define CP0_TAGLO $28
+#define CP0_TAGHI $29
+#define CP0_ERROREPC $30
+#define CP0_DESAVE $31
+
+/*
+ * R4640/R4650 cp0 register names.  These registers are listed
+ * here only for completeness; without MMU these CPUs are not useable
+ * by Linux.  A future ELKS port might take make Linux run on them
+ * though ...
+ */
+#define CP0_IBASE $0
+#define CP0_IBOUND $1
+#define CP0_DBASE $2
+#define CP0_DBOUND $3
+#define CP0_CALG $17
+#define CP0_IWATCH $18
+#define CP0_DWATCH $19
+
+/*
+ * Coprocessor 0 Set 1 register names
+ */
+#define CP0_S1_DERRADDR0  $26
+#define CP0_S1_DERRADDR1  $27
+#define CP0_S1_INTCONTROL $20
+
+/*
+ * Coprocessor 0 Set 2 register names
+ */
+#define CP0_S2_SRSCTL	  $12	/* MIPSR2 */
+
+/*
+ * Coprocessor 0 Set 3 register names
+ */
+#define CP0_S3_SRSMAP	  $12	/* MIPSR2 */
+
+/*
+ *  TX39 Series
+ */
+#define CP0_TX39_CACHE	$7
+
+/*
+ * Coprocessor 1 (FPU) register names
+ */
+#define CP1_REVISION   $0
+#define CP1_STATUS     $31
+
+/*
+ * FPU Status Register Values
+ */
+/*
+ * Status Register Values
+ */
+
+#define FPU_CSR_FLUSH   0x01000000      /* flush denormalised results to 0 */
+#define FPU_CSR_COND    0x00800000      /* $fcc0 */
+#define FPU_CSR_COND0   0x00800000      /* $fcc0 */
+#define FPU_CSR_COND1   0x02000000      /* $fcc1 */
+#define FPU_CSR_COND2   0x04000000      /* $fcc2 */
+#define FPU_CSR_COND3   0x08000000      /* $fcc3 */
+#define FPU_CSR_COND4   0x10000000      /* $fcc4 */
+#define FPU_CSR_COND5   0x20000000      /* $fcc5 */
+#define FPU_CSR_COND6   0x40000000      /* $fcc6 */
+#define FPU_CSR_COND7   0x80000000      /* $fcc7 */
+
+/*
+ * X the exception cause indicator
+ * E the exception enable
+ * S the sticky/flag bit
+*/
+#define FPU_CSR_ALL_X   0x0003f000
+#define FPU_CSR_UNI_X   0x00020000
+#define FPU_CSR_INV_X   0x00010000
+#define FPU_CSR_DIV_X   0x00008000
+#define FPU_CSR_OVF_X   0x00004000
+#define FPU_CSR_UDF_X   0x00002000
+#define FPU_CSR_INE_X   0x00001000
+
+#define FPU_CSR_ALL_E   0x00000f80
+#define FPU_CSR_INV_E   0x00000800
+#define FPU_CSR_DIV_E   0x00000400
+#define FPU_CSR_OVF_E   0x00000200
+#define FPU_CSR_UDF_E   0x00000100
+#define FPU_CSR_INE_E   0x00000080
+
+#define FPU_CSR_ALL_S   0x0000007c
+#define FPU_CSR_INV_S   0x00000040
+#define FPU_CSR_DIV_S   0x00000020
+#define FPU_CSR_OVF_S   0x00000010
+#define FPU_CSR_UDF_S   0x00000008
+#define FPU_CSR_INE_S   0x00000004
+
+/* rounding mode */
+#define FPU_CSR_RN      0x0     /* nearest */
+#define FPU_CSR_RZ      0x1     /* towards zero */
+#define FPU_CSR_RU      0x2     /* towards +Infinity */
+#define FPU_CSR_RD      0x3     /* towards -Infinity */
+
+
+/*
+ * Values for PageMask register
+ */
+#ifdef CONFIG_CPU_VR41XX
+
+/* Why doesn't stupidity hurt ... */
+
+#define PM_1K		0x00000000
+#define PM_4K		0x00001800
+#define PM_16K		0x00007800
+#define PM_64K		0x0001f800
+#define PM_256K		0x0007f800
+
+#else
+
+#define PM_4K		0x00000000
+#define PM_16K		0x00006000
+#define PM_64K		0x0001e000
+#define PM_256K		0x0007e000
+#define PM_1M		0x001fe000
+#define PM_4M		0x007fe000
+#define PM_16M		0x01ffe000
+#define PM_64M		0x07ffe000
+#define PM_256M		0x1fffe000
+
+#endif
+
+/*
+ * Default page size for a given kernel configuration
+ */
+#ifdef CONFIG_PAGE_SIZE_4KB
+#define PM_DEFAULT_MASK	PM_4K
+#elif defined(CONFIG_PAGE_SIZE_16KB)
+#define PM_DEFAULT_MASK	PM_16K
+#elif defined(CONFIG_PAGE_SIZE_64KB)
+#define PM_DEFAULT_MASK	PM_64K
+#else
+#error Bad page size configuration!
+#endif
+
+
+/*
+ * Values used for computation of new tlb entries
+ */
+#define PL_4K		12
+#define PL_16K		14
+#define PL_64K		16
+#define PL_256K		18
+#define PL_1M		20
+#define PL_4M		22
+#define PL_16M		24
+#define PL_64M		26
+#define PL_256M		28
+
+/*
+ * R4x00 interrupt enable / cause bits
+ */
+#define IE_SW0          (_ULCAST_(1) <<  8)
+#define IE_SW1          (_ULCAST_(1) <<  9)
+#define IE_IRQ0         (_ULCAST_(1) << 10)
+#define IE_IRQ1         (_ULCAST_(1) << 11)
+#define IE_IRQ2         (_ULCAST_(1) << 12)
+#define IE_IRQ3         (_ULCAST_(1) << 13)
+#define IE_IRQ4         (_ULCAST_(1) << 14)
+#define IE_IRQ5         (_ULCAST_(1) << 15)
+
+/*
+ * R4x00 interrupt cause bits
+ */
+#define C_SW0           (_ULCAST_(1) <<  8)
+#define C_SW1           (_ULCAST_(1) <<  9)
+#define C_IRQ0          (_ULCAST_(1) << 10)
+#define C_IRQ1          (_ULCAST_(1) << 11)
+#define C_IRQ2          (_ULCAST_(1) << 12)
+#define C_IRQ3          (_ULCAST_(1) << 13)
+#define C_IRQ4          (_ULCAST_(1) << 14)
+#define C_IRQ5          (_ULCAST_(1) << 15)
+
+/*
+ * Bitfields in the R4xx0 cp0 status register
+ */
+#define ST0_IE			0x00000001
+#define ST0_EXL			0x00000002
+#define ST0_ERL			0x00000004
+#define ST0_KSU			0x00000018
+#  define KSU_USER		0x00000010
+#  define KSU_SUPERVISOR	0x00000008
+#  define KSU_KERNEL		0x00000000
+#define ST0_UX			0x00000020
+#define ST0_SX			0x00000040
+#define ST0_KX 			0x00000080
+#define ST0_DE			0x00010000
+#define ST0_CE			0x00020000
+
+/*
+ * Setting c0_status.co enables Hit_Writeback and Hit_Writeback_Invalidate
+ * cacheops in userspace.  This bit exists only on RM7000 and RM9000
+ * processors.
+ */
+#define ST0_CO			0x08000000
+
+/*
+ * Bitfields in the R[23]000 cp0 status register.
+ */
+#define ST0_IEC                 0x00000001
+#define ST0_KUC			0x00000002
+#define ST0_IEP			0x00000004
+#define ST0_KUP			0x00000008
+#define ST0_IEO			0x00000010
+#define ST0_KUO			0x00000020
+/* bits 6 & 7 are reserved on R[23]000 */
+#define ST0_ISC			0x00010000
+#define ST0_SWC			0x00020000
+#define ST0_CM			0x00080000
+
+/*
+ * Bits specific to the R4640/R4650
+ */
+#define ST0_UM			(_ULCAST_(1) <<  4)
+#define ST0_IL			(_ULCAST_(1) << 23)
+#define ST0_DL			(_ULCAST_(1) << 24)
+
+/*
+ * Enable the MIPS MDMX and DSP ASEs
+ */
+#define ST0_MX			0x01000000
+
+/*
+ * Bitfields in the TX39 family CP0 Configuration Register 3
+ */
+#define TX39_CONF_ICS_SHIFT	19
+#define TX39_CONF_ICS_MASK	0x00380000
+#define TX39_CONF_ICS_1KB 	0x00000000
+#define TX39_CONF_ICS_2KB 	0x00080000
+#define TX39_CONF_ICS_4KB 	0x00100000
+#define TX39_CONF_ICS_8KB 	0x00180000
+#define TX39_CONF_ICS_16KB 	0x00200000
+
+#define TX39_CONF_DCS_SHIFT	16
+#define TX39_CONF_DCS_MASK	0x00070000
+#define TX39_CONF_DCS_1KB 	0x00000000
+#define TX39_CONF_DCS_2KB 	0x00010000
+#define TX39_CONF_DCS_4KB 	0x00020000
+#define TX39_CONF_DCS_8KB 	0x00030000
+#define TX39_CONF_DCS_16KB 	0x00040000
+
+#define TX39_CONF_CWFON 	0x00004000
+#define TX39_CONF_WBON  	0x00002000
+#define TX39_CONF_RF_SHIFT	10
+#define TX39_CONF_RF_MASK	0x00000c00
+#define TX39_CONF_DOZE		0x00000200
+#define TX39_CONF_HALT		0x00000100
+#define TX39_CONF_LOCK		0x00000080
+#define TX39_CONF_ICE		0x00000020
+#define TX39_CONF_DCE		0x00000010
+#define TX39_CONF_IRSIZE_SHIFT	2
+#define TX39_CONF_IRSIZE_MASK	0x0000000c
+#define TX39_CONF_DRSIZE_SHIFT	0
+#define TX39_CONF_DRSIZE_MASK	0x00000003
+
+/*
+ * Status register bits available in all MIPS CPUs.
+ */
+#define ST0_IM			0x0000ff00
+#define  STATUSB_IP0		8
+#define  STATUSF_IP0		(_ULCAST_(1) <<  8)
+#define  STATUSB_IP1		9
+#define  STATUSF_IP1		(_ULCAST_(1) <<  9)
+#define  STATUSB_IP2		10
+#define  STATUSF_IP2		(_ULCAST_(1) << 10)
+#define  STATUSB_IP3		11
+#define  STATUSF_IP3		(_ULCAST_(1) << 11)
+#define  STATUSB_IP4		12
+#define  STATUSF_IP4		(_ULCAST_(1) << 12)
+#define  STATUSB_IP5		13
+#define  STATUSF_IP5		(_ULCAST_(1) << 13)
+#define  STATUSB_IP6		14
+#define  STATUSF_IP6		(_ULCAST_(1) << 14)
+#define  STATUSB_IP7		15
+#define  STATUSF_IP7		(_ULCAST_(1) << 15)
+#define  STATUSB_IP8		0
+#define  STATUSF_IP8		(_ULCAST_(1) <<  0)
+#define  STATUSB_IP9		1
+#define  STATUSF_IP9		(_ULCAST_(1) <<  1)
+#define  STATUSB_IP10		2
+#define  STATUSF_IP10		(_ULCAST_(1) <<  2)
+#define  STATUSB_IP11		3
+#define  STATUSF_IP11		(_ULCAST_(1) <<  3)
+#define  STATUSB_IP12		4
+#define  STATUSF_IP12		(_ULCAST_(1) <<  4)
+#define  STATUSB_IP13		5
+#define  STATUSF_IP13		(_ULCAST_(1) <<  5)
+#define  STATUSB_IP14		6
+#define  STATUSF_IP14		(_ULCAST_(1) <<  6)
+#define  STATUSB_IP15		7
+#define  STATUSF_IP15		(_ULCAST_(1) <<  7)
+#define ST0_CH			0x00040000
+#define ST0_SR			0x00100000
+#define ST0_TS			0x00200000
+#define ST0_BEV			0x00400000
+#define ST0_RE			0x02000000
+#define ST0_FR			0x04000000
+#define ST0_CU			0xf0000000
+#define ST0_CU0			0x10000000
+#define ST0_CU1			0x20000000
+#define ST0_CU2			0x40000000
+#define ST0_CU3			0x80000000
+#define ST0_XX			0x80000000	/* MIPS IV naming */
+
+/*
+ * Bitfields and bit numbers in the coprocessor 0 cause register.
+ *
+ * Refer to your MIPS R4xx0 manual, chapter 5 for explanation.
+ */
+#define  CAUSEB_EXCCODE		2
+#define  CAUSEF_EXCCODE		(_ULCAST_(31)  <<  2)
+#define  CAUSEB_IP		8
+#define  CAUSEF_IP		(_ULCAST_(255) <<  8)
+#define  CAUSEB_IP0		8
+#define  CAUSEF_IP0		(_ULCAST_(1)   <<  8)
+#define  CAUSEB_IP1		9
+#define  CAUSEF_IP1		(_ULCAST_(1)   <<  9)
+#define  CAUSEB_IP2		10
+#define  CAUSEF_IP2		(_ULCAST_(1)   << 10)
+#define  CAUSEB_IP3		11
+#define  CAUSEF_IP3		(_ULCAST_(1)   << 11)
+#define  CAUSEB_IP4		12
+#define  CAUSEF_IP4		(_ULCAST_(1)   << 12)
+#define  CAUSEB_IP5		13
+#define  CAUSEF_IP5		(_ULCAST_(1)   << 13)
+#define  CAUSEB_IP6		14
+#define  CAUSEF_IP6		(_ULCAST_(1)   << 14)
+#define  CAUSEB_IP7		15
+#define  CAUSEF_IP7		(_ULCAST_(1)   << 15)
+#define  CAUSEB_IV		23
+#define  CAUSEF_IV		(_ULCAST_(1)   << 23)
+#define  CAUSEB_CE		28
+#define  CAUSEF_CE		(_ULCAST_(3)   << 28)
+#define  CAUSEB_BD		31
+#define  CAUSEF_BD		(_ULCAST_(1)   << 31)
+
+/*
+ * Bits in the coprocessor 0 config register.
+ */
+/* Generic bits.  */
+#define CONF_CM_CACHABLE_NO_WA		0
+#define CONF_CM_CACHABLE_WA		1
+#define CONF_CM_UNCACHED		2
+#define CONF_CM_CACHABLE_NONCOHERENT	3
+#define CONF_CM_CACHABLE_CE		4
+#define CONF_CM_CACHABLE_COW		5
+#define CONF_CM_CACHABLE_CUW		6
+#define CONF_CM_CACHABLE_ACCELERATED	7
+#define CONF_CM_CMASK			7
+#define CONF_BE			(_ULCAST_(1) << 15)
+
+/* Bits common to various processors.  */
+#define CONF_CU			(_ULCAST_(1) <<  3)
+#define CONF_DB			(_ULCAST_(1) <<  4)
+#define CONF_IB			(_ULCAST_(1) <<  5)
+#define CONF_DC			(_ULCAST_(7) <<  6)
+#define CONF_IC			(_ULCAST_(7) <<  9)
+#define CONF_EB			(_ULCAST_(1) << 13)
+#define CONF_EM			(_ULCAST_(1) << 14)
+#define CONF_SM			(_ULCAST_(1) << 16)
+#define CONF_SC			(_ULCAST_(1) << 17)
+#define CONF_EW			(_ULCAST_(3) << 18)
+#define CONF_EP			(_ULCAST_(15)<< 24)
+#define CONF_EC			(_ULCAST_(7) << 28)
+#define CONF_CM			(_ULCAST_(1) << 31)
+
+/* Bits specific to the R4xx0.  */
+#define R4K_CONF_SW		(_ULCAST_(1) << 20)
+#define R4K_CONF_SS		(_ULCAST_(1) << 21)
+#define R4K_CONF_SB		(_ULCAST_(3) << 22)
+
+/* Bits specific to the R5000.  */
+#define R5K_CONF_SE		(_ULCAST_(1) << 12)
+#define R5K_CONF_SS		(_ULCAST_(3) << 20)
+
+/* Bits specific to the RM7000.  */
+#define RM7K_CONF_SE		(_ULCAST_(1) <<  3)
+#define RM7K_CONF_TE		(_ULCAST_(1) << 12)
+#define RM7K_CONF_CLK		(_ULCAST_(1) << 16)
+#define RM7K_CONF_TC		(_ULCAST_(1) << 17)
+#define RM7K_CONF_SI		(_ULCAST_(3) << 20)
+#define RM7K_CONF_SC		(_ULCAST_(1) << 31)
+
+/* Bits specific to the R10000.  */
+#define R10K_CONF_DN		(_ULCAST_(3) <<  3)
+#define R10K_CONF_CT		(_ULCAST_(1) <<  5)
+#define R10K_CONF_PE		(_ULCAST_(1) <<  6)
+#define R10K_CONF_PM		(_ULCAST_(3) <<  7)
+#define R10K_CONF_EC		(_ULCAST_(15)<<  9)
+#define R10K_CONF_SB		(_ULCAST_(1) << 13)
+#define R10K_CONF_SK		(_ULCAST_(1) << 14)
+#define R10K_CONF_SS		(_ULCAST_(7) << 16)
+#define R10K_CONF_SC		(_ULCAST_(7) << 19)
+#define R10K_CONF_DC		(_ULCAST_(7) << 26)
+#define R10K_CONF_IC		(_ULCAST_(7) << 29)
+
+/* Bits specific to the VR41xx.  */
+#define VR41_CONF_CS		(_ULCAST_(1) << 12)
+#define VR41_CONF_P4K		(_ULCAST_(1) << 13)
+#define VR41_CONF_BP		(_ULCAST_(1) << 16)
+#define VR41_CONF_M16		(_ULCAST_(1) << 20)
+#define VR41_CONF_AD		(_ULCAST_(1) << 23)
+
+/* Bits specific to the R30xx.  */
+#define R30XX_CONF_FDM		(_ULCAST_(1) << 19)
+#define R30XX_CONF_REV		(_ULCAST_(1) << 22)
+#define R30XX_CONF_AC		(_ULCAST_(1) << 23)
+#define R30XX_CONF_RF		(_ULCAST_(1) << 24)
+#define R30XX_CONF_HALT		(_ULCAST_(1) << 25)
+#define R30XX_CONF_FPINT	(_ULCAST_(7) << 26)
+#define R30XX_CONF_DBR		(_ULCAST_(1) << 29)
+#define R30XX_CONF_SB		(_ULCAST_(1) << 30)
+#define R30XX_CONF_LOCK		(_ULCAST_(1) << 31)
+
+/* Bits specific to the TX49.  */
+#define TX49_CONF_DC		(_ULCAST_(1) << 16)
+#define TX49_CONF_IC		(_ULCAST_(1) << 17)  /* conflict with CONF_SC */
+#define TX49_CONF_HALT		(_ULCAST_(1) << 18)
+#define TX49_CONF_CWFON		(_ULCAST_(1) << 27)
+
+/* Bits specific to the MIPS32/64 PRA.  */
+#define MIPS_CONF_MT		(_ULCAST_(7) <<  7)
+#define MIPS_CONF_AR		(_ULCAST_(7) << 10)
+#define MIPS_CONF_AT		(_ULCAST_(3) << 13)
+#define MIPS_CONF_M		(_ULCAST_(1) << 31)
+
+/*
+ * Bits in the MIPS32/64 PRA coprocessor 0 config registers 1 and above.
+ */
+#define MIPS_CONF1_FP		(_ULCAST_(1) <<  0)
+#define MIPS_CONF1_EP		(_ULCAST_(1) <<  1)
+#define MIPS_CONF1_CA		(_ULCAST_(1) <<  2)
+#define MIPS_CONF1_WR		(_ULCAST_(1) <<  3)
+#define MIPS_CONF1_PC		(_ULCAST_(1) <<  4)
+#define MIPS_CONF1_MD		(_ULCAST_(1) <<  5)
+#define MIPS_CONF1_C2		(_ULCAST_(1) <<  6)
+#define MIPS_CONF1_DA		(_ULCAST_(7) <<  7)
+#define MIPS_CONF1_DL		(_ULCAST_(7) << 10)
+#define MIPS_CONF1_DS		(_ULCAST_(7) << 13)
+#define MIPS_CONF1_IA		(_ULCAST_(7) << 16)
+#define MIPS_CONF1_IL		(_ULCAST_(7) << 19)
+#define MIPS_CONF1_IS		(_ULCAST_(7) << 22)
+#define MIPS_CONF1_TLBS		(_ULCAST_(63)<< 25)
+
+#define MIPS_CONF2_SA		(_ULCAST_(15)<<  0)
+#define MIPS_CONF2_SL		(_ULCAST_(15)<<  4)
+#define MIPS_CONF2_SS		(_ULCAST_(15)<<  8)
+#define MIPS_CONF2_SU		(_ULCAST_(15)<< 12)
+#define MIPS_CONF2_TA		(_ULCAST_(15)<< 16)
+#define MIPS_CONF2_TL		(_ULCAST_(15)<< 20)
+#define MIPS_CONF2_TS		(_ULCAST_(15)<< 24)
+#define MIPS_CONF2_TU		(_ULCAST_(7) << 28)
+
+#define MIPS_CONF3_TL		(_ULCAST_(1) <<  0)
+#define MIPS_CONF3_SM		(_ULCAST_(1) <<  1)
+#define MIPS_CONF3_MT		(_ULCAST_(1) <<  2)
+#define MIPS_CONF3_SP		(_ULCAST_(1) <<  4)
+#define MIPS_CONF3_VINT		(_ULCAST_(1) <<  5)
+#define MIPS_CONF3_VEIC		(_ULCAST_(1) <<  6)
+#define MIPS_CONF3_LPA		(_ULCAST_(1) <<  7)
+#define MIPS_CONF3_DSP		(_ULCAST_(1) << 10)
+#define MIPS_CONF3_ULRI		(_ULCAST_(1) << 13)
+
+#define MIPS_CONF7_WII		(_ULCAST_(1) << 31)
+
+#define MIPS_CONF7_RPS		(_ULCAST_(1) << 2)
+
+
+/*
+ * Bits in the MIPS32/64 coprocessor 1 (FPU) revision register.
+ */
+#define MIPS_FPIR_S		(_ULCAST_(1) << 16)
+#define MIPS_FPIR_D		(_ULCAST_(1) << 17)
+#define MIPS_FPIR_PS		(_ULCAST_(1) << 18)
+#define MIPS_FPIR_3D		(_ULCAST_(1) << 19)
+#define MIPS_FPIR_W		(_ULCAST_(1) << 20)
+#define MIPS_FPIR_L		(_ULCAST_(1) << 21)
+#define MIPS_FPIR_F64		(_ULCAST_(1) << 22)
+
+#ifndef __ASSEMBLY__
+
+/*
+ * Functions to access the R10000 performance counters.  These are basically
+ * mfc0 and mtc0 instructions from and to coprocessor register with a 5-bit
+ * performance counter number encoded into bits 1 ... 5 of the instruction.
+ * Only performance counters 0 to 1 actually exist, so for a non-R10000 aware
+ * disassembler these will look like an access to sel 0 or 1.
+ */
+#define read_r10k_perf_cntr(counter)				\
+({								\
+	unsigned int __res;					\
+	__asm__ __volatile__(					\
+	"mfpc\t%0, %1"						\
+        : "=r" (__res)						\
+	: "i" (counter));					\
+								\
+        __res;							\
+})
+
+#define write_r10k_perf_cntr(counter,val)                       \
+do {								\
+	__asm__ __volatile__(					\
+	"mtpc\t%0, %1"						\
+	:							\
+	: "r" (val), "i" (counter));				\
+} while (0)
+
+#define read_r10k_perf_event(counter)				\
+({								\
+	unsigned int __res;					\
+	__asm__ __volatile__(					\
+	"mfps\t%0, %1"						\
+        : "=r" (__res)						\
+	: "i" (counter));					\
+								\
+        __res;							\
+})
+
+#define write_r10k_perf_cntl(counter,val)                       \
+do {								\
+	__asm__ __volatile__(					\
+	"mtps\t%0, %1"						\
+	:							\
+	: "r" (val), "i" (counter));				\
+} while (0)
+
+
+/*
+ * Macros to access the system control coprocessor
+ */
+
+#define __read_32bit_c0_register(source, sel)				\
+({ int __res;								\
+	if (sel == 0)							\
+		__asm__ __volatile__(					\
+			"mfc0\t%0, " #source "\n\t"			\
+			: "=r" (__res));				\
+	else								\
+		__asm__ __volatile__(					\
+			".set\tmips32\n\t"				\
+			"mfc0\t%0, " #source ", " #sel "\n\t"		\
+			".set\tmips0\n\t"				\
+			: "=r" (__res));				\
+	__res;								\
+})
+
+#define __read_64bit_c0_register(source, sel)				\
+({ unsigned long long __res;						\
+	if (sizeof(unsigned long) == 4)					\
+		__res = __read_64bit_c0_split(source, sel);		\
+	else if (sel == 0)						\
+		__asm__ __volatile__(					\
+			".set\tmips3\n\t"				\
+			"dmfc0\t%0, " #source "\n\t"			\
+			".set\tmips0"					\
+			: "=r" (__res));				\
+	else								\
+		__asm__ __volatile__(					\
+			".set\tmips64\n\t"				\
+			"dmfc0\t%0, " #source ", " #sel "\n\t"		\
+			".set\tmips0"					\
+			: "=r" (__res));				\
+	__res;								\
+})
+
+#define __write_32bit_c0_register(register, sel, value)			\
+do {									\
+	if (sel == 0)							\
+		__asm__ __volatile__(					\
+			"mtc0\t%z0, " #register "\n\t"			\
+			: : "Jr" ((unsigned int)(value)));		\
+	else								\
+		__asm__ __volatile__(					\
+			".set\tmips32\n\t"				\
+			"mtc0\t%z0, " #register ", " #sel "\n\t"	\
+			".set\tmips0"					\
+			: : "Jr" ((unsigned int)(value)));		\
+} while (0)
+
+#define __write_64bit_c0_register(register, sel, value)			\
+do {									\
+	if (sizeof(unsigned long) == 4)					\
+		__write_64bit_c0_split(register, sel, value);		\
+	else if (sel == 0)						\
+		__asm__ __volatile__(					\
+			".set\tmips3\n\t"				\
+			"dmtc0\t%z0, " #register "\n\t"			\
+			".set\tmips0"					\
+			: : "Jr" (value));				\
+	else								\
+		__asm__ __volatile__(					\
+			".set\tmips64\n\t"				\
+			"dmtc0\t%z0, " #register ", " #sel "\n\t"	\
+			".set\tmips0"					\
+			: : "Jr" (value));				\
+} while (0)
+
+#define __read_ulong_c0_register(reg, sel)				\
+	((sizeof(unsigned long) == 4) ?					\
+	(unsigned long) __read_32bit_c0_register(reg, sel) :		\
+	(unsigned long) __read_64bit_c0_register(reg, sel))
+
+#define __write_ulong_c0_register(reg, sel, val)			\
+do {									\
+	if (sizeof(unsigned long) == 4)					\
+		__write_32bit_c0_register(reg, sel, val);		\
+	else								\
+		__write_64bit_c0_register(reg, sel, val);		\
+} while (0)
+
+/*
+ * On RM7000/RM9000 these are uses to access cop0 set 1 registers
+ */
+#define __read_32bit_c0_ctrl_register(source)				\
+({ int __res;								\
+	__asm__ __volatile__(						\
+		"cfc0\t%0, " #source "\n\t"				\
+		: "=r" (__res));					\
+	__res;								\
+})
+
+#define __write_32bit_c0_ctrl_register(register, value)			\
+do {									\
+	__asm__ __volatile__(						\
+		"ctc0\t%z0, " #register "\n\t"				\
+		: : "Jr" ((unsigned int)(value)));			\
+} while (0)
+
+/*
+ * These versions are only needed for systems with more than 38 bits of
+ * physical address space running the 32-bit kernel.  That's none atm :-)
+ */
+#define __read_64bit_c0_split(source, sel)				\
+({									\
+	unsigned long long __val;					\
+	unsigned long __flags;						\
+									\
+	local_irq_save(__flags);					\
+	if (sel == 0)							\
+		__asm__ __volatile__(					\
+			".set\tmips64\n\t"				\
+			"dmfc0\t%M0, " #source "\n\t"			\
+			"dsll\t%L0, %M0, 32\n\t"			\
+			"dsrl\t%M0, %M0, 32\n\t"			\
+			"dsrl\t%L0, %L0, 32\n\t"			\
+			".set\tmips0"					\
+			: "=r" (__val));				\
+	else								\
+		__asm__ __volatile__(					\
+			".set\tmips64\n\t"				\
+			"dmfc0\t%M0, " #source ", " #sel "\n\t"		\
+			"dsll\t%L0, %M0, 32\n\t"			\
+			"dsrl\t%M0, %M0, 32\n\t"			\
+			"dsrl\t%L0, %L0, 32\n\t"			\
+			".set\tmips0"					\
+			: "=r" (__val));				\
+	local_irq_restore(__flags);					\
+									\
+	__val;								\
+})
+
+#define __write_64bit_c0_split(source, sel, val)			\
+do {									\
+	unsigned long __flags;						\
+									\
+	local_irq_save(__flags);					\
+	if (sel == 0)							\
+		__asm__ __volatile__(					\
+			".set\tmips64\n\t"				\
+			"dsll\t%L0, %L0, 32\n\t"			\
+			"dsrl\t%L0, %L0, 32\n\t"			\
+			"dsll\t%M0, %M0, 32\n\t"			\
+			"or\t%L0, %L0, %M0\n\t"				\
+			"dmtc0\t%L0, " #source "\n\t"			\
+			".set\tmips0"					\
+			: : "r" (val));					\
+	else								\
+		__asm__ __volatile__(					\
+			".set\tmips64\n\t"				\
+			"dsll\t%L0, %L0, 32\n\t"			\
+			"dsrl\t%L0, %L0, 32\n\t"			\
+			"dsll\t%M0, %M0, 32\n\t"			\
+			"or\t%L0, %L0, %M0\n\t"				\
+			"dmtc0\t%L0, " #source ", " #sel "\n\t"		\
+			".set\tmips0"					\
+			: : "r" (val));					\
+	local_irq_restore(__flags);					\
+} while (0)
+
+#define read_c0_index()		__read_32bit_c0_register($0, 0)
+#define write_c0_index(val)	__write_32bit_c0_register($0, 0, val)
+
+#define read_c0_random()	__read_32bit_c0_register($1, 0)
+#define write_c0_random(val)	__write_32bit_c0_register($1, 0, val)
+
+#define read_c0_entrylo0()	__read_ulong_c0_register($2, 0)
+#define write_c0_entrylo0(val)	__write_ulong_c0_register($2, 0, val)
+
+#define read_c0_entrylo1()	__read_ulong_c0_register($3, 0)
+#define write_c0_entrylo1(val)	__write_ulong_c0_register($3, 0, val)
+
+#define read_c0_conf()		__read_32bit_c0_register($3, 0)
+#define write_c0_conf(val)	__write_32bit_c0_register($3, 0, val)
+
+#define read_c0_context()	__read_ulong_c0_register($4, 0)
+#define write_c0_context(val)	__write_ulong_c0_register($4, 0, val)
+
+#define read_c0_userlocal()	__read_ulong_c0_register($4, 2)
+#define write_c0_userlocal(val)	__write_ulong_c0_register($4, 2, val)
+
+#define read_c0_pagemask()	__read_32bit_c0_register($5, 0)
+#define write_c0_pagemask(val)	__write_32bit_c0_register($5, 0, val)
+
+#define read_c0_wired()		__read_32bit_c0_register($6, 0)
+#define write_c0_wired(val)	__write_32bit_c0_register($6, 0, val)
+
+#define read_c0_info()		__read_32bit_c0_register($7, 0)
+
+#define read_c0_cache()		__read_32bit_c0_register($7, 0)	/* TX39xx */
+#define write_c0_cache(val)	__write_32bit_c0_register($7, 0, val)
+
+#define read_c0_badvaddr()	__read_ulong_c0_register($8, 0)
+#define write_c0_badvaddr(val)	__write_ulong_c0_register($8, 0, val)
+
+#define read_c0_count()		__read_32bit_c0_register($9, 0)
+#define write_c0_count(val)	__write_32bit_c0_register($9, 0, val)
+
+#define read_c0_count2()	__read_32bit_c0_register($9, 6) /* pnx8550 */
+#define write_c0_count2(val)	__write_32bit_c0_register($9, 6, val)
+
+#define read_c0_count3()	__read_32bit_c0_register($9, 7) /* pnx8550 */
+#define write_c0_count3(val)	__write_32bit_c0_register($9, 7, val)
+
+#define read_c0_entryhi()	__read_ulong_c0_register($10, 0)
+#define write_c0_entryhi(val)	__write_ulong_c0_register($10, 0, val)
+
+#define read_c0_compare()	__read_32bit_c0_register($11, 0)
+#define write_c0_compare(val)	__write_32bit_c0_register($11, 0, val)
+
+#define read_c0_compare2()	__read_32bit_c0_register($11, 6) /* pnx8550 */
+#define write_c0_compare2(val)	__write_32bit_c0_register($11, 6, val)
+
+#define read_c0_compare3()	__read_32bit_c0_register($11, 7) /* pnx8550 */
+#define write_c0_compare3(val)	__write_32bit_c0_register($11, 7, val)
+
+#define read_c0_status()	__read_32bit_c0_register($12, 0)
+#ifdef CONFIG_MIPS_MT_SMTC
+#define write_c0_status(val)						\
+do {									\
+	__write_32bit_c0_register($12, 0, val);				\
+	__ehb();							\
+} while (0)
+#else
+/*
+ * Legacy non-SMTC code, which may be hazardous
+ * but which might not support EHB
+ */
+#define write_c0_status(val)	__write_32bit_c0_register($12, 0, val)
+#endif /* CONFIG_MIPS_MT_SMTC */
+
+#define read_c0_cause()		__read_32bit_c0_register($13, 0)
+#define write_c0_cause(val)	__write_32bit_c0_register($13, 0, val)
+
+#define read_c0_epc()		__read_ulong_c0_register($14, 0)
+#define write_c0_epc(val)	__write_ulong_c0_register($14, 0, val)
+
+#define read_c0_prid()		__read_32bit_c0_register($15, 0)
+
+#define read_c0_config()	__read_32bit_c0_register($16, 0)
+#define read_c0_config1()	__read_32bit_c0_register($16, 1)
+#define read_c0_config2()	__read_32bit_c0_register($16, 2)
+#define read_c0_config3()	__read_32bit_c0_register($16, 3)
+#define read_c0_config4()	__read_32bit_c0_register($16, 4)
+#define read_c0_config5()	__read_32bit_c0_register($16, 5)
+#define read_c0_config6()	__read_32bit_c0_register($16, 6)
+#define read_c0_config7()	__read_32bit_c0_register($16, 7)
+#define write_c0_config(val)	__write_32bit_c0_register($16, 0, val)
+#define write_c0_config1(val)	__write_32bit_c0_register($16, 1, val)
+#define write_c0_config2(val)	__write_32bit_c0_register($16, 2, val)
+#define write_c0_config3(val)	__write_32bit_c0_register($16, 3, val)
+#define write_c0_config4(val)	__write_32bit_c0_register($16, 4, val)
+#define write_c0_config5(val)	__write_32bit_c0_register($16, 5, val)
+#define write_c0_config6(val)	__write_32bit_c0_register($16, 6, val)
+#define write_c0_config7(val)	__write_32bit_c0_register($16, 7, val)
+
+/*
+ * The WatchLo register.  There may be upto 8 of them.
+ */
+#define read_c0_watchlo0()	__read_ulong_c0_register($18, 0)
+#define read_c0_watchlo1()	__read_ulong_c0_register($18, 1)
+#define read_c0_watchlo2()	__read_ulong_c0_register($18, 2)
+#define read_c0_watchlo3()	__read_ulong_c0_register($18, 3)
+#define read_c0_watchlo4()	__read_ulong_c0_register($18, 4)
+#define read_c0_watchlo5()	__read_ulong_c0_register($18, 5)
+#define read_c0_watchlo6()	__read_ulong_c0_register($18, 6)
+#define read_c0_watchlo7()	__read_ulong_c0_register($18, 7)
+#define write_c0_watchlo0(val)	__write_ulong_c0_register($18, 0, val)
+#define write_c0_watchlo1(val)	__write_ulong_c0_register($18, 1, val)
+#define write_c0_watchlo2(val)	__write_ulong_c0_register($18, 2, val)
+#define write_c0_watchlo3(val)	__write_ulong_c0_register($18, 3, val)
+#define write_c0_watchlo4(val)	__write_ulong_c0_register($18, 4, val)
+#define write_c0_watchlo5(val)	__write_ulong_c0_register($18, 5, val)
+#define write_c0_watchlo6(val)	__write_ulong_c0_register($18, 6, val)
+#define write_c0_watchlo7(val)	__write_ulong_c0_register($18, 7, val)
+
+/*
+ * The WatchHi register.  There may be upto 8 of them.
+ */
+#define read_c0_watchhi0()	__read_32bit_c0_register($19, 0)
+#define read_c0_watchhi1()	__read_32bit_c0_register($19, 1)
+#define read_c0_watchhi2()	__read_32bit_c0_register($19, 2)
+#define read_c0_watchhi3()	__read_32bit_c0_register($19, 3)
+#define read_c0_watchhi4()	__read_32bit_c0_register($19, 4)
+#define read_c0_watchhi5()	__read_32bit_c0_register($19, 5)
+#define read_c0_watchhi6()	__read_32bit_c0_register($19, 6)
+#define read_c0_watchhi7()	__read_32bit_c0_register($19, 7)
+
+#define write_c0_watchhi0(val)	__write_32bit_c0_register($19, 0, val)
+#define write_c0_watchhi1(val)	__write_32bit_c0_register($19, 1, val)
+#define write_c0_watchhi2(val)	__write_32bit_c0_register($19, 2, val)
+#define write_c0_watchhi3(val)	__write_32bit_c0_register($19, 3, val)
+#define write_c0_watchhi4(val)	__write_32bit_c0_register($19, 4, val)
+#define write_c0_watchhi5(val)	__write_32bit_c0_register($19, 5, val)
+#define write_c0_watchhi6(val)	__write_32bit_c0_register($19, 6, val)
+#define write_c0_watchhi7(val)	__write_32bit_c0_register($19, 7, val)
+
+#define read_c0_xcontext()	__read_ulong_c0_register($20, 0)
+#define write_c0_xcontext(val)	__write_ulong_c0_register($20, 0, val)
+
+#define read_c0_intcontrol()	__read_32bit_c0_ctrl_register($20)
+#define write_c0_intcontrol(val) __write_32bit_c0_ctrl_register($20, val)
+
+#define read_c0_framemask()	__read_32bit_c0_register($21, 0)
+#define write_c0_framemask(val)	__write_32bit_c0_register($21, 0, val)
+
+/* RM9000 PerfControl performance counter control register */
+#define read_c0_perfcontrol()	__read_32bit_c0_register($22, 0)
+#define write_c0_perfcontrol(val) __write_32bit_c0_register($22, 0, val)
+
+#define read_c0_diag()		__read_32bit_c0_register($22, 0)
+#define write_c0_diag(val)	__write_32bit_c0_register($22, 0, val)
+
+#define read_c0_diag1()		__read_32bit_c0_register($22, 1)
+#define write_c0_diag1(val)	__write_32bit_c0_register($22, 1, val)
+
+#define read_c0_diag2()		__read_32bit_c0_register($22, 2)
+#define write_c0_diag2(val)	__write_32bit_c0_register($22, 2, val)
+
+#define read_c0_diag3()		__read_32bit_c0_register($22, 3)
+#define write_c0_diag3(val)	__write_32bit_c0_register($22, 3, val)
+
+#define read_c0_diag4()		__read_32bit_c0_register($22, 4)
+#define write_c0_diag4(val)	__write_32bit_c0_register($22, 4, val)
+
+#define read_c0_diag5()		__read_32bit_c0_register($22, 5)
+#define write_c0_diag5(val)	__write_32bit_c0_register($22, 5, val)
+
+#define read_c0_debug()		__read_32bit_c0_register($23, 0)
+#define write_c0_debug(val)	__write_32bit_c0_register($23, 0, val)
+
+#define read_c0_depc()		__read_ulong_c0_register($24, 0)
+#define write_c0_depc(val)	__write_ulong_c0_register($24, 0, val)
+
+/*
+ * MIPS32 / MIPS64 performance counters
+ */
+#define read_c0_perfctrl0()	__read_32bit_c0_register($25, 0)
+#define write_c0_perfctrl0(val)	__write_32bit_c0_register($25, 0, val)
+#define read_c0_perfcntr0()	__read_32bit_c0_register($25, 1)
+#define write_c0_perfcntr0(val)	__write_32bit_c0_register($25, 1, val)
+#define read_c0_perfctrl1()	__read_32bit_c0_register($25, 2)
+#define write_c0_perfctrl1(val)	__write_32bit_c0_register($25, 2, val)
+#define read_c0_perfcntr1()	__read_32bit_c0_register($25, 3)
+#define write_c0_perfcntr1(val)	__write_32bit_c0_register($25, 3, val)
+#define read_c0_perfctrl2()	__read_32bit_c0_register($25, 4)
+#define write_c0_perfctrl2(val)	__write_32bit_c0_register($25, 4, val)
+#define read_c0_perfcntr2()	__read_32bit_c0_register($25, 5)
+#define write_c0_perfcntr2(val)	__write_32bit_c0_register($25, 5, val)
+#define read_c0_perfctrl3()	__read_32bit_c0_register($25, 6)
+#define write_c0_perfctrl3(val)	__write_32bit_c0_register($25, 6, val)
+#define read_c0_perfcntr3()	__read_32bit_c0_register($25, 7)
+#define write_c0_perfcntr3(val)	__write_32bit_c0_register($25, 7, val)
+
+/* RM9000 PerfCount performance counter register */
+#define read_c0_perfcount()	__read_64bit_c0_register($25, 0)
+#define write_c0_perfcount(val)	__write_64bit_c0_register($25, 0, val)
+
+#define read_c0_ecc()		__read_32bit_c0_register($26, 0)
+#define write_c0_ecc(val)	__write_32bit_c0_register($26, 0, val)
+
+#define read_c0_derraddr0()	__read_ulong_c0_register($26, 1)
+#define write_c0_derraddr0(val)	__write_ulong_c0_register($26, 1, val)
+
+#define read_c0_cacheerr()	__read_32bit_c0_register($27, 0)
+
+#define read_c0_derraddr1()	__read_ulong_c0_register($27, 1)
+#define write_c0_derraddr1(val)	__write_ulong_c0_register($27, 1, val)
+
+#define read_c0_taglo()		__read_32bit_c0_register($28, 0)
+#define write_c0_taglo(val)	__write_32bit_c0_register($28, 0, val)
+
+#define read_c0_dtaglo()	__read_32bit_c0_register($28, 2)
+#define write_c0_dtaglo(val)	__write_32bit_c0_register($28, 2, val)
+
+#define read_c0_taghi()		__read_32bit_c0_register($29, 0)
+#define write_c0_taghi(val)	__write_32bit_c0_register($29, 0, val)
+
+#define read_c0_errorepc()	__read_ulong_c0_register($30, 0)
+#define write_c0_errorepc(val)	__write_ulong_c0_register($30, 0, val)
+
+/* MIPSR2 */
+#define read_c0_hwrena()	__read_32bit_c0_register($7, 0)
+#define write_c0_hwrena(val)	__write_32bit_c0_register($7, 0, val)
+
+#define read_c0_intctl()	__read_32bit_c0_register($12, 1)
+#define write_c0_intctl(val)	__write_32bit_c0_register($12, 1, val)
+
+#define read_c0_srsctl()	__read_32bit_c0_register($12, 2)
+#define write_c0_srsctl(val)	__write_32bit_c0_register($12, 2, val)
+
+#define read_c0_srsmap()	__read_32bit_c0_register($12, 3)
+#define write_c0_srsmap(val)	__write_32bit_c0_register($12, 3, val)
+
+#define read_c0_ebase()		__read_32bit_c0_register($15, 1)
+#define write_c0_ebase(val)	__write_32bit_c0_register($15, 1, val)
+
+/*
+ * Macros to access the floating point coprocessor control registers
+ */
+#define read_32bit_cp1_register(source)                         \
+({ int __res;                                                   \
+	__asm__ __volatile__(                                   \
+	".set\tpush\n\t"					\
+	".set\treorder\n\t"					\
+        "cfc1\t%0,"STR(source)"\n\t"                            \
+	".set\tpop"						\
+        : "=r" (__res));                                        \
+        __res;})
+
+#define rddsp(mask)							\
+({									\
+	unsigned int __res;						\
+									\
+	__asm__ __volatile__(						\
+	"	.set	push				\n"		\
+	"	.set	noat				\n"		\
+	"	# rddsp $1, %x1				\n"		\
+	"	.word	0x7c000cb8 | (%x1 << 16)	\n"		\
+	"	move	%0, $1				\n"		\
+	"	.set	pop				\n"		\
+	: "=r" (__res)							\
+	: "i" (mask));							\
+	__res;								\
+})
+
+#define wrdsp(val, mask)						\
+do {									\
+	__asm__ __volatile__(						\
+	"	.set	push					\n"	\
+	"	.set	noat					\n"	\
+	"	move	$1, %0					\n"	\
+	"	# wrdsp $1, %x1					\n"	\
+	"	.word	0x7c2004f8 | (%x1 << 11)		\n"	\
+	"	.set	pop					\n"	\
+        :								\
+	: "r" (val), "i" (mask));					\
+} while (0)
+
+#if 0	/* Need DSP ASE capable assembler ... */
+#define mflo0() ({ long mflo0; __asm__("mflo %0, $ac0" : "=r" (mflo0)); mflo0;})
+#define mflo1() ({ long mflo1; __asm__("mflo %0, $ac1" : "=r" (mflo1)); mflo1;})
+#define mflo2() ({ long mflo2; __asm__("mflo %0, $ac2" : "=r" (mflo2)); mflo2;})
+#define mflo3() ({ long mflo3; __asm__("mflo %0, $ac3" : "=r" (mflo3)); mflo3;})
+
+#define mfhi0() ({ long mfhi0; __asm__("mfhi %0, $ac0" : "=r" (mfhi0)); mfhi0;})
+#define mfhi1() ({ long mfhi1; __asm__("mfhi %0, $ac1" : "=r" (mfhi1)); mfhi1;})
+#define mfhi2() ({ long mfhi2; __asm__("mfhi %0, $ac2" : "=r" (mfhi2)); mfhi2;})
+#define mfhi3() ({ long mfhi3; __asm__("mfhi %0, $ac3" : "=r" (mfhi3)); mfhi3;})
+
+#define mtlo0(x) __asm__("mtlo %0, $ac0" ::"r" (x))
+#define mtlo1(x) __asm__("mtlo %0, $ac1" ::"r" (x))
+#define mtlo2(x) __asm__("mtlo %0, $ac2" ::"r" (x))
+#define mtlo3(x) __asm__("mtlo %0, $ac3" ::"r" (x))
+
+#define mthi0(x) __asm__("mthi %0, $ac0" ::"r" (x))
+#define mthi1(x) __asm__("mthi %0, $ac1" ::"r" (x))
+#define mthi2(x) __asm__("mthi %0, $ac2" ::"r" (x))
+#define mthi3(x) __asm__("mthi %0, $ac3" ::"r" (x))
+
+#else
+
+#define mfhi0()								\
+({									\
+	unsigned long __treg;						\
+									\
+	__asm__ __volatile__(						\
+	"	.set	push			\n"			\
+	"	.set	noat			\n"			\
+	"	# mfhi	%0, $ac0		\n"			\
+	"	.word	0x00000810		\n"			\
+	"	move	%0, $1			\n"			\
+	"	.set	pop			\n"			\
+	: "=r" (__treg));						\
+	__treg;								\
+})
+
+#define mfhi1()								\
+({									\
+	unsigned long __treg;						\
+									\
+	__asm__ __volatile__(						\
+	"	.set	push			\n"			\
+	"	.set	noat			\n"			\
+	"	# mfhi	%0, $ac1		\n"			\
+	"	.word	0x00200810		\n"			\
+	"	move	%0, $1			\n"			\
+	"	.set	pop			\n"			\
+	: "=r" (__treg));						\
+	__treg;								\
+})
+
+#define mfhi2()								\
+({									\
+	unsigned long __treg;						\
+									\
+	__asm__ __volatile__(						\
+	"	.set	push			\n"			\
+	"	.set	noat			\n"			\
+	"	# mfhi	%0, $ac2		\n"			\
+	"	.word	0x00400810		\n"			\
+	"	move	%0, $1			\n"			\
+	"	.set	pop			\n"			\
+	: "=r" (__treg));						\
+	__treg;								\
+})
+
+#define mfhi3()								\
+({									\
+	unsigned long __treg;						\
+									\
+	__asm__ __volatile__(						\
+	"	.set	push			\n"			\
+	"	.set	noat			\n"			\
+	"	# mfhi	%0, $ac3		\n"			\
+	"	.word	0x00600810		\n"			\
+	"	move	%0, $1			\n"			\
+	"	.set	pop			\n"			\
+	: "=r" (__treg));						\
+	__treg;								\
+})
+
+#define mflo0()								\
+({									\
+	unsigned long __treg;						\
+									\
+	__asm__ __volatile__(						\
+	"	.set	push			\n"			\
+	"	.set	noat			\n"			\
+	"	# mflo	%0, $ac0		\n"			\
+	"	.word	0x00000812		\n"			\
+	"	move	%0, $1			\n"			\
+	"	.set	pop			\n"			\
+	: "=r" (__treg));						\
+	__treg;								\
+})
+
+#define mflo1()								\
+({									\
+	unsigned long __treg;						\
+									\
+	__asm__ __volatile__(						\
+	"	.set	push			\n"			\
+	"	.set	noat			\n"			\
+	"	# mflo	%0, $ac1		\n"			\
+	"	.word	0x00200812		\n"			\
+	"	move	%0, $1			\n"			\
+	"	.set	pop			\n"			\
+	: "=r" (__treg));						\
+	__treg;								\
+})
+
+#define mflo2()								\
+({									\
+	unsigned long __treg;						\
+									\
+	__asm__ __volatile__(						\
+	"	.set	push			\n"			\
+	"	.set	noat			\n"			\
+	"	# mflo	%0, $ac2		\n"			\
+	"	.word	0x00400812		\n"			\
+	"	move	%0, $1			\n"			\
+	"	.set	pop			\n"			\
+	: "=r" (__treg));						\
+	__treg;								\
+})
+
+#define mflo3()								\
+({									\
+	unsigned long __treg;						\
+									\
+	__asm__ __volatile__(						\
+	"	.set	push			\n"			\
+	"	.set	noat			\n"			\
+	"	# mflo	%0, $ac3		\n"			\
+	"	.word	0x00600812		\n"			\
+	"	move	%0, $1			\n"			\
+	"	.set	pop			\n"			\
+	: "=r" (__treg));						\
+	__treg;								\
+})
+
+#define mthi0(x)							\
+do {									\
+	__asm__ __volatile__(						\
+	"	.set	push					\n"	\
+	"	.set	noat					\n"	\
+	"	move	$1, %0					\n"	\
+	"	# mthi	$1, $ac0				\n"	\
+	"	.word	0x00200011				\n"	\
+	"	.set	pop					\n"	\
+	:								\
+	: "r" (x));							\
+} while (0)
+
+#define mthi1(x)							\
+do {									\
+	__asm__ __volatile__(						\
+	"	.set	push					\n"	\
+	"	.set	noat					\n"	\
+	"	move	$1, %0					\n"	\
+	"	# mthi	$1, $ac1				\n"	\
+	"	.word	0x00200811				\n"	\
+	"	.set	pop					\n"	\
+	:								\
+	: "r" (x));							\
+} while (0)
+
+#define mthi2(x)							\
+do {									\
+	__asm__ __volatile__(						\
+	"	.set	push					\n"	\
+	"	.set	noat					\n"	\
+	"	move	$1, %0					\n"	\
+	"	# mthi	$1, $ac2				\n"	\
+	"	.word	0x00201011				\n"	\
+	"	.set	pop					\n"	\
+	:								\
+	: "r" (x));							\
+} while (0)
+
+#define mthi3(x)							\
+do {									\
+	__asm__ __volatile__(						\
+	"	.set	push					\n"	\
+	"	.set	noat					\n"	\
+	"	move	$1, %0					\n"	\
+	"	# mthi	$1, $ac3				\n"	\
+	"	.word	0x00201811				\n"	\
+	"	.set	pop					\n"	\
+	:								\
+	: "r" (x));							\
+} while (0)
+
+#define mtlo0(x)							\
+do {									\
+	__asm__ __volatile__(						\
+	"	.set	push					\n"	\
+	"	.set	noat					\n"	\
+	"	move	$1, %0					\n"	\
+	"	# mtlo	$1, $ac0				\n"	\
+	"	.word	0x00200013				\n"	\
+	"	.set	pop					\n"	\
+	:								\
+	: "r" (x));							\
+} while (0)
+
+#define mtlo1(x)							\
+do {									\
+	__asm__ __volatile__(						\
+	"	.set	push					\n"	\
+	"	.set	noat					\n"	\
+	"	move	$1, %0					\n"	\
+	"	# mtlo	$1, $ac1				\n"	\
+	"	.word	0x00200813				\n"	\
+	"	.set	pop					\n"	\
+	:								\
+	: "r" (x));							\
+} while (0)
+
+#define mtlo2(x)							\
+do {									\
+	__asm__ __volatile__(						\
+	"	.set	push					\n"	\
+	"	.set	noat					\n"	\
+	"	move	$1, %0					\n"	\
+	"	# mtlo	$1, $ac2				\n"	\
+	"	.word	0x00201013				\n"	\
+	"	.set	pop					\n"	\
+	:								\
+	: "r" (x));							\
+} while (0)
+
+#define mtlo3(x)							\
+do {									\
+	__asm__ __volatile__(						\
+	"	.set	push					\n"	\
+	"	.set	noat					\n"	\
+	"	move	$1, %0					\n"	\
+	"	# mtlo	$1, $ac3				\n"	\
+	"	.word	0x00201813				\n"	\
+	"	.set	pop					\n"	\
+	:								\
+	: "r" (x));							\
+} while (0)
+
+#endif
+
+/*
+ * TLB operations.
+ *
+ * It is responsibility of the caller to take care of any TLB hazards.
+ */
+static inline void tlb_probe(void)
+{
+	__asm__ __volatile__(
+		".set noreorder\n\t"
+		"tlbp\n\t"
+		".set reorder");
+}
+
+static inline void tlb_read(void)
+{
+#if MIPS34K_MISSED_ITLB_WAR
+	int res = 0;
+
+	__asm__ __volatile__(
+	"	.set	push					\n"
+	"	.set	noreorder				\n"
+	"	.set	noat					\n"
+	"	.set	mips32r2				\n"
+	"	.word	0x41610001		# dvpe $1	\n"
+	"	move	%0, $1					\n"
+	"	ehb						\n"
+	"	.set	pop					\n"
+	: "=r" (res));
+
+	instruction_hazard();
+#endif
+
+	__asm__ __volatile__(
+		".set noreorder\n\t"
+		"tlbr\n\t"
+		".set reorder");
+
+#if MIPS34K_MISSED_ITLB_WAR
+	if ((res & _ULCAST_(1)))
+		__asm__ __volatile__(
+		"	.set	push				\n"
+		"	.set	noreorder			\n"
+		"	.set	noat				\n"
+		"	.set	mips32r2			\n"
+		"	.word	0x41600021	# evpe		\n"
+		"	ehb					\n"
+		"	.set	pop				\n");
+#endif
+}
+
+static inline void tlb_write_indexed(void)
+{
+	__asm__ __volatile__(
+		".set noreorder\n\t"
+		"tlbwi\n\t"
+		".set reorder");
+}
+
+static inline void tlb_write_random(void)
+{
+	__asm__ __volatile__(
+		".set noreorder\n\t"
+		"tlbwr\n\t"
+		".set reorder");
+}
+
+/*
+ * Manipulate bits in a c0 register.
+ */
+#ifndef CONFIG_MIPS_MT_SMTC
+/*
+ * SMTC Linux requires shutting-down microthread scheduling
+ * during CP0 register read-modify-write sequences.
+ */
+#define __BUILD_SET_C0(name)					\
+static inline unsigned int					\
+set_c0_##name(unsigned int set)					\
+{								\
+	unsigned int res;					\
+								\
+	res = read_c0_##name();					\
+	res |= set;						\
+	write_c0_##name(res);					\
+								\
+	return res;						\
+}								\
+								\
+static inline unsigned int					\
+clear_c0_##name(unsigned int clear)				\
+{								\
+	unsigned int res;					\
+								\
+	res = read_c0_##name();					\
+	res &= ~clear;						\
+	write_c0_##name(res);					\
+								\
+	return res;						\
+}								\
+								\
+static inline unsigned int					\
+change_c0_##name(unsigned int change, unsigned int new)		\
+{								\
+	unsigned int res;					\
+								\
+	res = read_c0_##name();					\
+	res &= ~change;						\
+	res |= (new & change);					\
+	write_c0_##name(res);					\
+								\
+	return res;						\
+}
+
+#else /* SMTC versions that manage MT scheduling */
+
+#include <linux/irqflags.h>
+
+/*
+ * This is a duplicate of dmt() in mipsmtregs.h to avoid problems with
+ * header file recursion.
+ */
+static inline unsigned int __dmt(void)
+{
+	int res;
+
+	__asm__ __volatile__(
+	"	.set	push						\n"
+	"	.set	mips32r2					\n"
+	"	.set	noat						\n"
+	"	.word	0x41610BC1			# dmt $1	\n"
+	"	ehb							\n"
+	"	move	%0, $1						\n"
+	"	.set	pop						\n"
+	: "=r" (res));
+
+	instruction_hazard();
+
+	return res;
+}
+
+#define __VPECONTROL_TE_SHIFT	15
+#define __VPECONTROL_TE		(1UL << __VPECONTROL_TE_SHIFT)
+
+#define __EMT_ENABLE		__VPECONTROL_TE
+
+static inline void __emt(unsigned int previous)
+{
+	if ((previous & __EMT_ENABLE))
+		__asm__ __volatile__(
+		"	.set	mips32r2				\n"
+		"	.word	0x41600be1		# emt		\n"
+		"	ehb						\n"
+		"	.set	mips0					\n");
+}
+
+static inline void __ehb(void)
+{
+	__asm__ __volatile__(
+	"	.set	mips32r2					\n"
+	"	ehb							\n"		"	.set	mips0						\n");
+}
+
+/*
+ * Note that local_irq_save/restore affect TC-specific IXMT state,
+ * not Status.IE as in non-SMTC kernel.
+ */
+
+#define __BUILD_SET_C0(name)					\
+static inline unsigned int					\
+set_c0_##name(unsigned int set)					\
+{								\
+	unsigned int res;					\
+	unsigned int omt;					\
+	unsigned long flags;					\
+								\
+	local_irq_save(flags);					\
+	omt = __dmt();						\
+	res = read_c0_##name();					\
+	res |= set;						\
+	write_c0_##name(res);					\
+	__emt(omt);						\
+	local_irq_restore(flags);				\
+								\
+	return res;						\
+}								\
+								\
+static inline unsigned int					\
+clear_c0_##name(unsigned int clear)				\
+{								\
+	unsigned int res;					\
+	unsigned int omt;					\
+	unsigned long flags;					\
+								\
+	local_irq_save(flags);					\
+	omt = __dmt();						\
+	res = read_c0_##name();					\
+	res &= ~clear;						\
+	write_c0_##name(res);					\
+	__emt(omt);						\
+	local_irq_restore(flags);				\
+								\
+	return res;						\
+}								\
+								\
+static inline unsigned int					\
+change_c0_##name(unsigned int change, unsigned int new)		\
+{								\
+	unsigned int res;					\
+	unsigned int omt;					\
+	unsigned long flags;					\
+								\
+	local_irq_save(flags);					\
+								\
+	omt = __dmt();						\
+	res = read_c0_##name();					\
+	res &= ~change;						\
+	res |= (new & change);					\
+	write_c0_##name(res);					\
+	__emt(omt);						\
+	local_irq_restore(flags);				\
+								\
+	return res;						\
+}
+#endif
+
+__BUILD_SET_C0(status)
+__BUILD_SET_C0(cause)
+__BUILD_SET_C0(config)
+__BUILD_SET_C0(intcontrol)
+__BUILD_SET_C0(intctl)
+__BUILD_SET_C0(srsmap)
+
+#endif /* !__ASSEMBLY__ */
+
+#endif /* _ASM_MIPSREGS_H */
diff --git a/include/asm-mips/mman.h b/arch/mips/include/asm/mman.h
similarity index 100%
rename from include/asm-mips/mman.h
rename to arch/mips/include/asm/mman.h
diff --git a/include/asm-mips/mmu.h b/arch/mips/include/asm/mmu.h
similarity index 100%
rename from include/asm-mips/mmu.h
rename to arch/mips/include/asm/mmu.h
diff --git a/arch/mips/include/asm/mmu_context.h b/arch/mips/include/asm/mmu_context.h
new file mode 100644
index 0000000..d7f3eb0
--- /dev/null
+++ b/arch/mips/include/asm/mmu_context.h
@@ -0,0 +1,297 @@
+/*
+ * Switch a MMU context.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 1996, 1997, 1998, 1999 by Ralf Baechle
+ * Copyright (C) 1999 Silicon Graphics, Inc.
+ */
+#ifndef _ASM_MMU_CONTEXT_H
+#define _ASM_MMU_CONTEXT_H
+
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <asm/cacheflush.h>
+#include <asm/tlbflush.h>
+#ifdef CONFIG_MIPS_MT_SMTC
+#include <asm/mipsmtregs.h>
+#include <asm/smtc.h>
+#endif /* SMTC */
+#include <asm-generic/mm_hooks.h>
+
+/*
+ * For the fast tlb miss handlers, we keep a per cpu array of pointers
+ * to the current pgd for each processor. Also, the proc. id is stuffed
+ * into the context register.
+ */
+extern unsigned long pgd_current[];
+
+#define TLBMISS_HANDLER_SETUP_PGD(pgd) \
+	pgd_current[smp_processor_id()] = (unsigned long)(pgd)
+
+#ifdef CONFIG_32BIT
+#define TLBMISS_HANDLER_SETUP()						\
+	write_c0_context((unsigned long) smp_processor_id() << 25);	\
+	TLBMISS_HANDLER_SETUP_PGD(swapper_pg_dir)
+#endif
+#ifdef CONFIG_64BIT
+#define TLBMISS_HANDLER_SETUP()						\
+	write_c0_context((unsigned long) smp_processor_id() << 26);	\
+	TLBMISS_HANDLER_SETUP_PGD(swapper_pg_dir)
+#endif
+
+#if defined(CONFIG_CPU_R3000) || defined(CONFIG_CPU_TX39XX)
+
+#define ASID_INC	0x40
+#define ASID_MASK	0xfc0
+
+#elif defined(CONFIG_CPU_R8000)
+
+#define ASID_INC	0x10
+#define ASID_MASK	0xff0
+
+#elif defined(CONFIG_CPU_RM9000)
+
+#define ASID_INC	0x1
+#define ASID_MASK	0xfff
+
+/* SMTC/34K debug hack - but maybe we'll keep it */
+#elif defined(CONFIG_MIPS_MT_SMTC)
+
+#define ASID_INC	0x1
+extern unsigned long smtc_asid_mask;
+#define ASID_MASK	(smtc_asid_mask)
+#define	HW_ASID_MASK	0xff
+/* End SMTC/34K debug hack */
+#else /* FIXME: not correct for R6000 */
+
+#define ASID_INC	0x1
+#define ASID_MASK	0xff
+
+#endif
+
+#define cpu_context(cpu, mm)	((mm)->context[cpu])
+#define cpu_asid(cpu, mm)	(cpu_context((cpu), (mm)) & ASID_MASK)
+#define asid_cache(cpu)		(cpu_data[cpu].asid_cache)
+
+static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk)
+{
+}
+
+/*
+ *  All unused by hardware upper bits will be considered
+ *  as a software asid extension.
+ */
+#define ASID_VERSION_MASK  ((unsigned long)~(ASID_MASK|(ASID_MASK-1)))
+#define ASID_FIRST_VERSION ((unsigned long)(~ASID_VERSION_MASK) + 1)
+
+#ifndef CONFIG_MIPS_MT_SMTC
+/* Normal, classic MIPS get_new_mmu_context */
+static inline void
+get_new_mmu_context(struct mm_struct *mm, unsigned long cpu)
+{
+	unsigned long asid = asid_cache(cpu);
+
+	if (! ((asid += ASID_INC) & ASID_MASK) ) {
+		if (cpu_has_vtag_icache)
+			flush_icache_all();
+		local_flush_tlb_all();	/* start new asid cycle */
+		if (!asid)		/* fix version if needed */
+			asid = ASID_FIRST_VERSION;
+	}
+	cpu_context(cpu, mm) = asid_cache(cpu) = asid;
+}
+
+#else /* CONFIG_MIPS_MT_SMTC */
+
+#define get_new_mmu_context(mm, cpu) smtc_get_new_mmu_context((mm), (cpu))
+
+#endif /* CONFIG_MIPS_MT_SMTC */
+
+/*
+ * Initialize the context related info for a new mm_struct
+ * instance.
+ */
+static inline int
+init_new_context(struct task_struct *tsk, struct mm_struct *mm)
+{
+	int i;
+
+	for_each_online_cpu(i)
+		cpu_context(i, mm) = 0;
+
+	return 0;
+}
+
+static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
+                             struct task_struct *tsk)
+{
+	unsigned int cpu = smp_processor_id();
+	unsigned long flags;
+#ifdef CONFIG_MIPS_MT_SMTC
+	unsigned long oldasid;
+	unsigned long mtflags;
+	int mytlb = (smtc_status & SMTC_TLB_SHARED) ? 0 : cpu_data[cpu].vpe_id;
+	local_irq_save(flags);
+	mtflags = dvpe();
+#else /* Not SMTC */
+	local_irq_save(flags);
+#endif /* CONFIG_MIPS_MT_SMTC */
+
+	/* Check if our ASID is of an older version and thus invalid */
+	if ((cpu_context(cpu, next) ^ asid_cache(cpu)) & ASID_VERSION_MASK)
+		get_new_mmu_context(next, cpu);
+#ifdef CONFIG_MIPS_MT_SMTC
+	/*
+	 * If the EntryHi ASID being replaced happens to be
+	 * the value flagged at ASID recycling time as having
+	 * an extended life, clear the bit showing it being
+	 * in use by this "CPU", and if that's the last bit,
+	 * free up the ASID value for use and flush any old
+	 * instances of it from the TLB.
+	 */
+	oldasid = (read_c0_entryhi() & ASID_MASK);
+	if(smtc_live_asid[mytlb][oldasid]) {
+		smtc_live_asid[mytlb][oldasid] &= ~(0x1 << cpu);
+		if(smtc_live_asid[mytlb][oldasid] == 0)
+			smtc_flush_tlb_asid(oldasid);
+	}
+	/*
+	 * Tread softly on EntryHi, and so long as we support
+	 * having ASID_MASK smaller than the hardware maximum,
+	 * make sure no "soft" bits become "hard"...
+	 */
+	write_c0_entryhi((read_c0_entryhi() & ~HW_ASID_MASK)
+			| (cpu_context(cpu, next) & ASID_MASK));
+	ehb(); /* Make sure it propagates to TCStatus */
+	evpe(mtflags);
+#else
+	write_c0_entryhi(cpu_context(cpu, next));
+#endif /* CONFIG_MIPS_MT_SMTC */
+	TLBMISS_HANDLER_SETUP_PGD(next->pgd);
+
+	/*
+	 * Mark current->active_mm as not "active" anymore.
+	 * We don't want to mislead possible IPI tlb flush routines.
+	 */
+	cpu_clear(cpu, prev->cpu_vm_mask);
+	cpu_set(cpu, next->cpu_vm_mask);
+
+	local_irq_restore(flags);
+}
+
+/*
+ * Destroy context related info for an mm_struct that is about
+ * to be put to rest.
+ */
+static inline void destroy_context(struct mm_struct *mm)
+{
+}
+
+#define deactivate_mm(tsk, mm)	do { } while (0)
+
+/*
+ * After we have set current->mm to a new value, this activates
+ * the context for the new mm so we see the new mappings.
+ */
+static inline void
+activate_mm(struct mm_struct *prev, struct mm_struct *next)
+{
+	unsigned long flags;
+	unsigned int cpu = smp_processor_id();
+
+#ifdef CONFIG_MIPS_MT_SMTC
+	unsigned long oldasid;
+	unsigned long mtflags;
+	int mytlb = (smtc_status & SMTC_TLB_SHARED) ? 0 : cpu_data[cpu].vpe_id;
+#endif /* CONFIG_MIPS_MT_SMTC */
+
+	local_irq_save(flags);
+
+	/* Unconditionally get a new ASID.  */
+	get_new_mmu_context(next, cpu);
+
+#ifdef CONFIG_MIPS_MT_SMTC
+	/* See comments for similar code above */
+	mtflags = dvpe();
+	oldasid = read_c0_entryhi() & ASID_MASK;
+	if(smtc_live_asid[mytlb][oldasid]) {
+		smtc_live_asid[mytlb][oldasid] &= ~(0x1 << cpu);
+		if(smtc_live_asid[mytlb][oldasid] == 0)
+			 smtc_flush_tlb_asid(oldasid);
+	}
+	/* See comments for similar code above */
+	write_c0_entryhi((read_c0_entryhi() & ~HW_ASID_MASK) |
+	                 (cpu_context(cpu, next) & ASID_MASK));
+	ehb(); /* Make sure it propagates to TCStatus */
+	evpe(mtflags);
+#else
+	write_c0_entryhi(cpu_context(cpu, next));
+#endif /* CONFIG_MIPS_MT_SMTC */
+	TLBMISS_HANDLER_SETUP_PGD(next->pgd);
+
+	/* mark mmu ownership change */
+	cpu_clear(cpu, prev->cpu_vm_mask);
+	cpu_set(cpu, next->cpu_vm_mask);
+
+	local_irq_restore(flags);
+}
+
+/*
+ * If mm is currently active_mm, we can't really drop it.  Instead,
+ * we will get a new one for it.
+ */
+static inline void
+drop_mmu_context(struct mm_struct *mm, unsigned cpu)
+{
+	unsigned long flags;
+#ifdef CONFIG_MIPS_MT_SMTC
+	unsigned long oldasid;
+	/* Can't use spinlock because called from TLB flush within DVPE */
+	unsigned int prevvpe;
+	int mytlb = (smtc_status & SMTC_TLB_SHARED) ? 0 : cpu_data[cpu].vpe_id;
+#endif /* CONFIG_MIPS_MT_SMTC */
+
+	local_irq_save(flags);
+
+	if (cpu_isset(cpu, mm->cpu_vm_mask))  {
+		get_new_mmu_context(mm, cpu);
+#ifdef CONFIG_MIPS_MT_SMTC
+		/* See comments for similar code above */
+		prevvpe = dvpe();
+		oldasid = (read_c0_entryhi() & ASID_MASK);
+		if (smtc_live_asid[mytlb][oldasid]) {
+			smtc_live_asid[mytlb][oldasid] &= ~(0x1 << cpu);
+			if(smtc_live_asid[mytlb][oldasid] == 0)
+				smtc_flush_tlb_asid(oldasid);
+		}
+		/* See comments for similar code above */
+		write_c0_entryhi((read_c0_entryhi() & ~HW_ASID_MASK)
+				| cpu_asid(cpu, mm));
+		ehb(); /* Make sure it propagates to TCStatus */
+		evpe(prevvpe);
+#else /* not CONFIG_MIPS_MT_SMTC */
+		write_c0_entryhi(cpu_asid(cpu, mm));
+#endif /* CONFIG_MIPS_MT_SMTC */
+	} else {
+		/* will get a new context next time */
+#ifndef CONFIG_MIPS_MT_SMTC
+		cpu_context(cpu, mm) = 0;
+#else /* SMTC */
+		int i;
+
+		/* SMTC shares the TLB (and ASIDs) across VPEs */
+		for_each_online_cpu(i) {
+		    if((smtc_status & SMTC_TLB_SHARED)
+		    || (cpu_data[i].vpe_id == cpu_data[cpu].vpe_id))
+			cpu_context(i, mm) = 0;
+		}
+#endif /* CONFIG_MIPS_MT_SMTC */
+	}
+	local_irq_restore(flags);
+}
+
+#endif /* _ASM_MMU_CONTEXT_H */
diff --git a/include/asm-mips/mmzone.h b/arch/mips/include/asm/mmzone.h
similarity index 100%
rename from include/asm-mips/mmzone.h
rename to arch/mips/include/asm/mmzone.h
diff --git a/include/asm-mips/module.h b/arch/mips/include/asm/module.h
similarity index 100%
rename from include/asm-mips/module.h
rename to arch/mips/include/asm/module.h
diff --git a/include/asm-mips/msc01_ic.h b/arch/mips/include/asm/msc01_ic.h
similarity index 100%
rename from include/asm-mips/msc01_ic.h
rename to arch/mips/include/asm/msc01_ic.h
diff --git a/include/asm-mips/msgbuf.h b/arch/mips/include/asm/msgbuf.h
similarity index 100%
rename from include/asm-mips/msgbuf.h
rename to arch/mips/include/asm/msgbuf.h
diff --git a/include/asm-mips/mutex.h b/arch/mips/include/asm/mutex.h
similarity index 100%
rename from include/asm-mips/mutex.h
rename to arch/mips/include/asm/mutex.h
diff --git a/include/asm-mips/nile4.h b/arch/mips/include/asm/nile4.h
similarity index 100%
rename from include/asm-mips/nile4.h
rename to arch/mips/include/asm/nile4.h
diff --git a/include/asm-mips/paccess.h b/arch/mips/include/asm/paccess.h
similarity index 100%
rename from include/asm-mips/paccess.h
rename to arch/mips/include/asm/paccess.h
diff --git a/include/asm-mips/page.h b/arch/mips/include/asm/page.h
similarity index 100%
rename from include/asm-mips/page.h
rename to arch/mips/include/asm/page.h
diff --git a/include/asm-mips/param.h b/arch/mips/include/asm/param.h
similarity index 100%
rename from include/asm-mips/param.h
rename to arch/mips/include/asm/param.h
diff --git a/include/asm-mips/parport.h b/arch/mips/include/asm/parport.h
similarity index 100%
rename from include/asm-mips/parport.h
rename to arch/mips/include/asm/parport.h
diff --git a/include/asm-mips/pci.h b/arch/mips/include/asm/pci.h
similarity index 100%
rename from include/asm-mips/pci.h
rename to arch/mips/include/asm/pci.h
diff --git a/include/asm-mips/pci/bridge.h b/arch/mips/include/asm/pci/bridge.h
similarity index 100%
rename from include/asm-mips/pci/bridge.h
rename to arch/mips/include/asm/pci/bridge.h
diff --git a/include/asm-mips/percpu.h b/arch/mips/include/asm/percpu.h
similarity index 100%
rename from include/asm-mips/percpu.h
rename to arch/mips/include/asm/percpu.h
diff --git a/include/asm-mips/pgalloc.h b/arch/mips/include/asm/pgalloc.h
similarity index 100%
rename from include/asm-mips/pgalloc.h
rename to arch/mips/include/asm/pgalloc.h
diff --git a/arch/mips/include/asm/pgtable-32.h b/arch/mips/include/asm/pgtable-32.h
new file mode 100644
index 0000000..55813d6
--- /dev/null
+++ b/arch/mips/include/asm/pgtable-32.h
@@ -0,0 +1,234 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 1994, 95, 96, 97, 98, 99, 2000, 2003 Ralf Baechle
+ * Copyright (C) 1999, 2000, 2001 Silicon Graphics, Inc.
+ */
+#ifndef _ASM_PGTABLE_32_H
+#define _ASM_PGTABLE_32_H
+
+#include <asm/addrspace.h>
+#include <asm/page.h>
+
+#include <linux/linkage.h>
+#include <asm/cachectl.h>
+#include <asm/fixmap.h>
+
+#include <asm-generic/pgtable-nopmd.h>
+
+/*
+ * - add_wired_entry() add a fixed TLB entry, and move wired register
+ */
+extern void add_wired_entry(unsigned long entrylo0, unsigned long entrylo1,
+			       unsigned long entryhi, unsigned long pagemask);
+
+/*
+ * - add_temporary_entry() add a temporary TLB entry. We use TLB entries
+ *	starting at the top and working down. This is for populating the
+ *	TLB before trap_init() puts the TLB miss handler in place. It
+ *	should be used only for entries matching the actual page tables,
+ *	to prevent inconsistencies.
+ */
+extern int add_temporary_entry(unsigned long entrylo0, unsigned long entrylo1,
+			       unsigned long entryhi, unsigned long pagemask);
+
+
+/* Basically we have the same two-level (which is the logical three level
+ * Linux page table layout folded) page tables as the i386.  Some day
+ * when we have proper page coloring support we can have a 1% quicker
+ * tlb refill handling mechanism, but for now it is a bit slower but
+ * works even with the cache aliasing problem the R4k and above have.
+ */
+
+/* PGDIR_SHIFT determines what a third-level page table entry can map */
+#define PGDIR_SHIFT	(2 * PAGE_SHIFT + PTE_ORDER - PTE_T_LOG2)
+#define PGDIR_SIZE	(1UL << PGDIR_SHIFT)
+#define PGDIR_MASK	(~(PGDIR_SIZE-1))
+
+/*
+ * Entries per page directory level: we use two-level, so
+ * we don't really have any PUD/PMD directory physically.
+ */
+#define __PGD_ORDER	(32 - 3 * PAGE_SHIFT + PGD_T_LOG2 + PTE_T_LOG2)
+#define PGD_ORDER	(__PGD_ORDER >= 0 ? __PGD_ORDER : 0)
+#define PUD_ORDER	aieeee_attempt_to_allocate_pud
+#define PMD_ORDER	1
+#define PTE_ORDER	0
+
+#define PTRS_PER_PGD	(USER_PTRS_PER_PGD * 2)
+#define PTRS_PER_PTE	((PAGE_SIZE << PTE_ORDER) / sizeof(pte_t))
+
+#define USER_PTRS_PER_PGD	(0x80000000UL/PGDIR_SIZE)
+#define FIRST_USER_ADDRESS	0
+
+#define VMALLOC_START     MAP_BASE
+
+#define PKMAP_BASE		(0xfe000000UL)
+
+#ifdef CONFIG_HIGHMEM
+# define VMALLOC_END	(PKMAP_BASE-2*PAGE_SIZE)
+#else
+# define VMALLOC_END	(FIXADDR_START-2*PAGE_SIZE)
+#endif
+
+#ifdef CONFIG_64BIT_PHYS_ADDR
+#define pte_ERROR(e) \
+	printk("%s:%d: bad pte %016Lx.\n", __FILE__, __LINE__, pte_val(e))
+#else
+#define pte_ERROR(e) \
+	printk("%s:%d: bad pte %08lx.\n", __FILE__, __LINE__, pte_val(e))
+#endif
+#define pgd_ERROR(e) \
+	printk("%s:%d: bad pgd %08lx.\n", __FILE__, __LINE__, pgd_val(e))
+
+extern void load_pgd(unsigned long pg_dir);
+
+extern pte_t invalid_pte_table[PAGE_SIZE/sizeof(pte_t)];
+
+/*
+ * Empty pgd/pmd entries point to the invalid_pte_table.
+ */
+static inline int pmd_none(pmd_t pmd)
+{
+	return pmd_val(pmd) == (unsigned long) invalid_pte_table;
+}
+
+#define pmd_bad(pmd)		(pmd_val(pmd) & ~PAGE_MASK)
+
+static inline int pmd_present(pmd_t pmd)
+{
+	return pmd_val(pmd) != (unsigned long) invalid_pte_table;
+}
+
+static inline void pmd_clear(pmd_t *pmdp)
+{
+	pmd_val(*pmdp) = ((unsigned long) invalid_pte_table);
+}
+
+#if defined(CONFIG_64BIT_PHYS_ADDR) && defined(CONFIG_CPU_MIPS32)
+#define pte_page(x)		pfn_to_page(pte_pfn(x))
+#define pte_pfn(x)		((unsigned long)((x).pte_high >> 6))
+static inline pte_t
+pfn_pte(unsigned long pfn, pgprot_t prot)
+{
+	pte_t pte;
+	pte.pte_high = (pfn << 6) | (pgprot_val(prot) & 0x3f);
+	pte.pte_low = pgprot_val(prot);
+	return pte;
+}
+
+#else
+
+#define pte_page(x)		pfn_to_page(pte_pfn(x))
+
+#ifdef CONFIG_CPU_VR41XX
+#define pte_pfn(x)		((unsigned long)((x).pte >> (PAGE_SHIFT + 2)))
+#define pfn_pte(pfn, prot)	__pte(((pfn) << (PAGE_SHIFT + 2)) | pgprot_val(prot))
+#else
+#define pte_pfn(x)		((unsigned long)((x).pte >> PAGE_SHIFT))
+#define pfn_pte(pfn, prot)	__pte(((unsigned long long)(pfn) << PAGE_SHIFT) | pgprot_val(prot))
+#endif
+#endif /* defined(CONFIG_64BIT_PHYS_ADDR) && defined(CONFIG_CPU_MIPS32) */
+
+#define __pgd_offset(address)	pgd_index(address)
+#define __pud_offset(address)	(((address) >> PUD_SHIFT) & (PTRS_PER_PUD-1))
+#define __pmd_offset(address)	(((address) >> PMD_SHIFT) & (PTRS_PER_PMD-1))
+
+/* to find an entry in a kernel page-table-directory */
+#define pgd_offset_k(address) pgd_offset(&init_mm, address)
+
+#define pgd_index(address)	(((address) >> PGDIR_SHIFT) & (PTRS_PER_PGD-1))
+
+/* to find an entry in a page-table-directory */
+#define pgd_offset(mm, addr)	((mm)->pgd + pgd_index(addr))
+
+/* Find an entry in the third-level page table.. */
+#define __pte_offset(address)						\
+	(((address) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1))
+#define pte_offset(dir, address)					\
+	((pte_t *) pmd_page_vaddr(*(dir)) + __pte_offset(address))
+#define pte_offset_kernel(dir, address)					\
+	((pte_t *) pmd_page_vaddr(*(dir)) + __pte_offset(address))
+
+#define pte_offset_map(dir, address)                                    \
+	((pte_t *)page_address(pmd_page(*(dir))) + __pte_offset(address))
+#define pte_offset_map_nested(dir, address)                             \
+	((pte_t *)page_address(pmd_page(*(dir))) + __pte_offset(address))
+#define pte_unmap(pte) ((void)(pte))
+#define pte_unmap_nested(pte) ((void)(pte))
+
+#if defined(CONFIG_CPU_R3000) || defined(CONFIG_CPU_TX39XX)
+
+/* Swap entries must have VALID bit cleared. */
+#define __swp_type(x)		(((x).val >> 10) & 0x1f)
+#define __swp_offset(x)		((x).val >> 15)
+#define __swp_entry(type,offset)	\
+	((swp_entry_t) { ((type) << 10) | ((offset) << 15) })
+
+/*
+ * Bits 0, 4, 8, and 9 are taken, split up 28 bits of offset into this range:
+ */
+#define PTE_FILE_MAX_BITS	28
+
+#define pte_to_pgoff(_pte)	((((_pte).pte >> 1 ) & 0x07) | \
+				 (((_pte).pte >> 2 ) & 0x38) | \
+				 (((_pte).pte >> 10) <<  6 ))
+
+#define pgoff_to_pte(off)	((pte_t) { (((off) & 0x07) << 1 ) | \
+					   (((off) & 0x38) << 2 ) | \
+					   (((off) >>  6 ) << 10) | \
+					   _PAGE_FILE })
+
+#else
+
+/* Swap entries must have VALID and GLOBAL bits cleared. */
+#if defined(CONFIG_64BIT_PHYS_ADDR) && defined(CONFIG_CPU_MIPS32)
+#define __swp_type(x)		(((x).val >> 2) & 0x1f)
+#define __swp_offset(x) 	 ((x).val >> 7)
+#define __swp_entry(type,offset)	\
+		((swp_entry_t)  { ((type) << 2) | ((offset) << 7) })
+#else
+#define __swp_type(x)		(((x).val >> 8) & 0x1f)
+#define __swp_offset(x) 	 ((x).val >> 13)
+#define __swp_entry(type,offset)	\
+		((swp_entry_t)  { ((type) << 8) | ((offset) << 13) })
+#endif /* defined(CONFIG_64BIT_PHYS_ADDR) && defined(CONFIG_CPU_MIPS32) */
+
+#if defined(CONFIG_64BIT_PHYS_ADDR) && defined(CONFIG_CPU_MIPS32)
+/*
+ * Bits 0 and 1 of pte_high are taken, use the rest for the page offset...
+ */
+#define PTE_FILE_MAX_BITS	30
+
+#define pte_to_pgoff(_pte)	((_pte).pte_high >> 2)
+#define pgoff_to_pte(off) 	((pte_t) { _PAGE_FILE, (off) << 2 })
+
+#else
+/*
+ * Bits 0, 4, 6, and 7 are taken, split up 28 bits of offset into this range:
+ */
+#define PTE_FILE_MAX_BITS	28
+
+#define pte_to_pgoff(_pte)	((((_pte).pte >> 1) & 0x7) | \
+				 (((_pte).pte >> 2) & 0x8) | \
+				 (((_pte).pte >> 8) <<  4))
+
+#define pgoff_to_pte(off)	((pte_t) { (((off) & 0x7) << 1) | \
+					   (((off) & 0x8) << 2) | \
+					   (((off) >>  4) << 8) | \
+					   _PAGE_FILE })
+#endif
+
+#endif
+
+#if defined(CONFIG_64BIT_PHYS_ADDR) && defined(CONFIG_CPU_MIPS32)
+#define __pte_to_swp_entry(pte) ((swp_entry_t) { (pte).pte_high })
+#define __swp_entry_to_pte(x)	((pte_t) { 0, (x).val })
+#else
+#define __pte_to_swp_entry(pte)	((swp_entry_t) { pte_val(pte) })
+#define __swp_entry_to_pte(x)	((pte_t) { (x).val })
+#endif
+
+#endif /* _ASM_PGTABLE_32_H */
diff --git a/include/asm-mips/pgtable-64.h b/arch/mips/include/asm/pgtable-64.h
similarity index 100%
rename from include/asm-mips/pgtable-64.h
rename to arch/mips/include/asm/pgtable-64.h
diff --git a/include/asm-mips/pgtable-bits.h b/arch/mips/include/asm/pgtable-bits.h
similarity index 100%
rename from include/asm-mips/pgtable-bits.h
rename to arch/mips/include/asm/pgtable-bits.h
diff --git a/include/asm-mips/pgtable.h b/arch/mips/include/asm/pgtable.h
similarity index 100%
rename from include/asm-mips/pgtable.h
rename to arch/mips/include/asm/pgtable.h
diff --git a/arch/mips/include/asm/pmc-sierra/msp71xx/gpio.h b/arch/mips/include/asm/pmc-sierra/msp71xx/gpio.h
new file mode 100644
index 0000000..ebdbab9
--- /dev/null
+++ b/arch/mips/include/asm/pmc-sierra/msp71xx/gpio.h
@@ -0,0 +1,46 @@
+/*
+ * include/asm-mips/pmc-sierra/msp71xx/gpio.h
+ *
+ * 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.
+ *
+ * @author Patrick Glass <patrickglass@gmail.com>
+ */
+
+#ifndef __PMC_MSP71XX_GPIO_H
+#define __PMC_MSP71XX_GPIO_H
+
+/* Max number of gpio's is 28 on chip plus 3 banks of I2C IO Expanders */
+#define ARCH_NR_GPIOS (28 + (3 * 8))
+
+/* new generic GPIO API - see Documentation/gpio.txt */
+#include <asm-generic/gpio.h>
+
+#define gpio_get_value	__gpio_get_value
+#define gpio_set_value	__gpio_set_value
+#define gpio_cansleep	__gpio_cansleep
+
+/* Setup calls for the gpio and gpio extended */
+extern void msp71xx_init_gpio(void);
+extern void msp71xx_init_gpio_extended(void);
+extern int msp71xx_set_output_drive(unsigned gpio, int value);
+
+/* Custom output drive functionss */
+static inline int gpio_set_output_drive(unsigned gpio, int value)
+{
+	return msp71xx_set_output_drive(gpio, value);
+}
+
+/* IRQ's are not supported for gpio lines */
+static inline int gpio_to_irq(unsigned gpio)
+{
+	return -EINVAL;
+}
+
+static inline int irq_to_gpio(unsigned irq)
+{
+	return -EINVAL;
+}
+
+#endif /* __PMC_MSP71XX_GPIO_H */
diff --git a/include/asm-mips/pmc-sierra/msp71xx/msp_cic_int.h b/arch/mips/include/asm/pmc-sierra/msp71xx/msp_cic_int.h
similarity index 100%
rename from include/asm-mips/pmc-sierra/msp71xx/msp_cic_int.h
rename to arch/mips/include/asm/pmc-sierra/msp71xx/msp_cic_int.h
diff --git a/include/asm-mips/pmc-sierra/msp71xx/msp_int.h b/arch/mips/include/asm/pmc-sierra/msp71xx/msp_int.h
similarity index 100%
rename from include/asm-mips/pmc-sierra/msp71xx/msp_int.h
rename to arch/mips/include/asm/pmc-sierra/msp71xx/msp_int.h
diff --git a/include/asm-mips/pmc-sierra/msp71xx/msp_pci.h b/arch/mips/include/asm/pmc-sierra/msp71xx/msp_pci.h
similarity index 100%
rename from include/asm-mips/pmc-sierra/msp71xx/msp_pci.h
rename to arch/mips/include/asm/pmc-sierra/msp71xx/msp_pci.h
diff --git a/include/asm-mips/pmc-sierra/msp71xx/msp_prom.h b/arch/mips/include/asm/pmc-sierra/msp71xx/msp_prom.h
similarity index 100%
rename from include/asm-mips/pmc-sierra/msp71xx/msp_prom.h
rename to arch/mips/include/asm/pmc-sierra/msp71xx/msp_prom.h
diff --git a/include/asm-mips/pmc-sierra/msp71xx/msp_regops.h b/arch/mips/include/asm/pmc-sierra/msp71xx/msp_regops.h
similarity index 100%
rename from include/asm-mips/pmc-sierra/msp71xx/msp_regops.h
rename to arch/mips/include/asm/pmc-sierra/msp71xx/msp_regops.h
diff --git a/include/asm-mips/pmc-sierra/msp71xx/msp_regs.h b/arch/mips/include/asm/pmc-sierra/msp71xx/msp_regs.h
similarity index 100%
rename from include/asm-mips/pmc-sierra/msp71xx/msp_regs.h
rename to arch/mips/include/asm/pmc-sierra/msp71xx/msp_regs.h
diff --git a/include/asm-mips/pmc-sierra/msp71xx/msp_slp_int.h b/arch/mips/include/asm/pmc-sierra/msp71xx/msp_slp_int.h
similarity index 100%
rename from include/asm-mips/pmc-sierra/msp71xx/msp_slp_int.h
rename to arch/mips/include/asm/pmc-sierra/msp71xx/msp_slp_int.h
diff --git a/include/asm-mips/pmc-sierra/msp71xx/war.h b/arch/mips/include/asm/pmc-sierra/msp71xx/war.h
similarity index 100%
rename from include/asm-mips/pmc-sierra/msp71xx/war.h
rename to arch/mips/include/asm/pmc-sierra/msp71xx/war.h
diff --git a/include/asm-mips/pmon.h b/arch/mips/include/asm/pmon.h
similarity index 100%
rename from include/asm-mips/pmon.h
rename to arch/mips/include/asm/pmon.h
diff --git a/include/asm-mips/poll.h b/arch/mips/include/asm/poll.h
similarity index 100%
rename from include/asm-mips/poll.h
rename to arch/mips/include/asm/poll.h
diff --git a/include/asm-mips/posix_types.h b/arch/mips/include/asm/posix_types.h
similarity index 100%
rename from include/asm-mips/posix_types.h
rename to arch/mips/include/asm/posix_types.h
diff --git a/include/asm-mips/prefetch.h b/arch/mips/include/asm/prefetch.h
similarity index 100%
rename from include/asm-mips/prefetch.h
rename to arch/mips/include/asm/prefetch.h
diff --git a/arch/mips/include/asm/processor.h b/arch/mips/include/asm/processor.h
new file mode 100644
index 0000000..18ee58e
--- /dev/null
+++ b/arch/mips/include/asm/processor.h
@@ -0,0 +1,283 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 1994 Waldorf GMBH
+ * Copyright (C) 1995, 1996, 1997, 1998, 1999, 2001, 2002, 2003 Ralf Baechle
+ * Copyright (C) 1996 Paul M. Antoine
+ * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
+ */
+#ifndef _ASM_PROCESSOR_H
+#define _ASM_PROCESSOR_H
+
+#include <linux/cpumask.h>
+#include <linux/threads.h>
+
+#include <asm/cachectl.h>
+#include <asm/cpu.h>
+#include <asm/cpu-info.h>
+#include <asm/mipsregs.h>
+#include <asm/prefetch.h>
+#include <asm/system.h>
+
+/*
+ * Return current * instruction pointer ("program counter").
+ */
+#define current_text_addr() ({ __label__ _l; _l: &&_l;})
+
+/*
+ * System setup and hardware flags..
+ */
+extern void (*cpu_wait)(void);
+
+extern unsigned int vced_count, vcei_count;
+
+#ifdef CONFIG_32BIT
+/*
+ * User space process size: 2GB. This is hardcoded into a few places,
+ * so don't change it unless you know what you are doing.
+ */
+#define TASK_SIZE	0x7fff8000UL
+#define STACK_TOP	TASK_SIZE
+
+/*
+ * This decides where the kernel will search for a free chunk of vm
+ * space during mmap's.
+ */
+#define TASK_UNMAPPED_BASE	((TASK_SIZE / 3) & ~(PAGE_SIZE))
+#endif
+
+#ifdef CONFIG_64BIT
+/*
+ * User space process size: 1TB. This is hardcoded into a few places,
+ * so don't change it unless you know what you are doing.  TASK_SIZE
+ * is limited to 1TB by the R4000 architecture; R10000 and better can
+ * support 16TB; the architectural reserve for future expansion is
+ * 8192EB ...
+ */
+#define TASK_SIZE32	0x7fff8000UL
+#define TASK_SIZE	0x10000000000UL
+#define STACK_TOP	\
+      (test_thread_flag(TIF_32BIT_ADDR) ? TASK_SIZE32 : TASK_SIZE)
+
+/*
+ * This decides where the kernel will search for a free chunk of vm
+ * space during mmap's.
+ */
+#define TASK_UNMAPPED_BASE						\
+	(test_thread_flag(TIF_32BIT_ADDR) ?				\
+		PAGE_ALIGN(TASK_SIZE32 / 3) : PAGE_ALIGN(TASK_SIZE / 3))
+#define TASK_SIZE_OF(tsk)						\
+	(test_tsk_thread_flag(tsk, TIF_32BIT_ADDR) ? TASK_SIZE32 : TASK_SIZE)
+#endif
+
+#ifdef __KERNEL__
+#define STACK_TOP_MAX	TASK_SIZE
+#endif
+
+#define NUM_FPU_REGS	32
+
+typedef __u64 fpureg_t;
+
+/*
+ * It would be nice to add some more fields for emulator statistics, but there
+ * are a number of fixed offsets in offset.h and elsewhere that would have to
+ * be recalculated by hand.  So the additional information will be private to
+ * the FPU emulator for now.  See asm-mips/fpu_emulator.h.
+ */
+
+struct mips_fpu_struct {
+	fpureg_t	fpr[NUM_FPU_REGS];
+	unsigned int	fcr31;
+};
+
+#define NUM_DSP_REGS   6
+
+typedef __u32 dspreg_t;
+
+struct mips_dsp_state {
+	dspreg_t        dspr[NUM_DSP_REGS];
+	unsigned int    dspcontrol;
+};
+
+#define INIT_CPUMASK { \
+	{0,} \
+}
+
+struct mips3264_watch_reg_state {
+	/* The width of watchlo is 32 in a 32 bit kernel and 64 in a
+	   64 bit kernel.  We use unsigned long as it has the same
+	   property. */
+	unsigned long watchlo[NUM_WATCH_REGS];
+	/* Only the mask and IRW bits from watchhi. */
+	u16 watchhi[NUM_WATCH_REGS];
+};
+
+union mips_watch_reg_state {
+	struct mips3264_watch_reg_state mips3264;
+};
+
+typedef struct {
+	unsigned long seg;
+} mm_segment_t;
+
+#define ARCH_MIN_TASKALIGN	8
+
+struct mips_abi;
+
+/*
+ * If you change thread_struct remember to change the #defines below too!
+ */
+struct thread_struct {
+	/* Saved main processor registers. */
+	unsigned long reg16;
+	unsigned long reg17, reg18, reg19, reg20, reg21, reg22, reg23;
+	unsigned long reg29, reg30, reg31;
+
+	/* Saved cp0 stuff. */
+	unsigned long cp0_status;
+
+	/* Saved fpu/fpu emulator stuff. */
+	struct mips_fpu_struct fpu;
+#ifdef CONFIG_MIPS_MT_FPAFF
+	/* Emulated instruction count */
+	unsigned long emulated_fp;
+	/* Saved per-thread scheduler affinity mask */
+	cpumask_t user_cpus_allowed;
+#endif /* CONFIG_MIPS_MT_FPAFF */
+
+	/* Saved state of the DSP ASE, if available. */
+	struct mips_dsp_state dsp;
+
+	/* Saved watch register state, if available. */
+	union mips_watch_reg_state watch;
+
+	/* Other stuff associated with the thread. */
+	unsigned long cp0_badvaddr;	/* Last user fault */
+	unsigned long cp0_baduaddr;	/* Last kernel fault accessing USEG */
+	unsigned long error_code;
+	unsigned long trap_no;
+	unsigned long irix_trampoline;  /* Wheee... */
+	unsigned long irix_oldctx;
+	struct mips_abi *abi;
+};
+
+#ifdef CONFIG_MIPS_MT_FPAFF
+#define FPAFF_INIT						\
+	.emulated_fp			= 0,			\
+	.user_cpus_allowed		= INIT_CPUMASK,
+#else
+#define FPAFF_INIT
+#endif /* CONFIG_MIPS_MT_FPAFF */
+
+#define INIT_THREAD  {						\
+        /*							\
+         * Saved main processor registers			\
+         */							\
+	.reg16			= 0,				\
+	.reg17			= 0,				\
+	.reg18			= 0,				\
+	.reg19			= 0,				\
+	.reg20			= 0,				\
+	.reg21			= 0,				\
+	.reg22			= 0,				\
+	.reg23			= 0,				\
+	.reg29			= 0,				\
+	.reg30			= 0,				\
+	.reg31			= 0,				\
+	/*							\
+	 * Saved cp0 stuff					\
+	 */							\
+	.cp0_status		= 0,				\
+	/*							\
+	 * Saved FPU/FPU emulator stuff				\
+	 */							\
+	.fpu			= {				\
+		.fpr		= {0,},				\
+		.fcr31		= 0,				\
+	},							\
+	/*							\
+	 * FPU affinity state (null if not FPAFF)		\
+	 */							\
+	FPAFF_INIT						\
+	/*							\
+	 * Saved DSP stuff					\
+	 */							\
+	.dsp			= {				\
+		.dspr		= {0, },			\
+		.dspcontrol	= 0,				\
+	},							\
+	/*							\
+	 * saved watch register stuff				\
+	 */							\
+	.watch = {{{0,},},},					\
+	/*							\
+	 * Other stuff associated with the process		\
+	 */							\
+	.cp0_badvaddr		= 0,				\
+	.cp0_baduaddr		= 0,				\
+	.error_code		= 0,				\
+	.trap_no		= 0,				\
+	.irix_trampoline	= 0,				\
+	.irix_oldctx		= 0,				\
+}
+
+struct task_struct;
+
+/* Free all resources held by a thread. */
+#define release_thread(thread) do { } while(0)
+
+/* Prepare to copy thread state - unlazy all lazy status */
+#define prepare_to_copy(tsk)	do { } while (0)
+
+extern long kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
+
+extern unsigned long thread_saved_pc(struct task_struct *tsk);
+
+/*
+ * Do necessary setup to start up a newly executed thread.
+ */
+extern void start_thread(struct pt_regs * regs, unsigned long pc, unsigned long sp);
+
+unsigned long get_wchan(struct task_struct *p);
+
+#define __KSTK_TOS(tsk) ((unsigned long)task_stack_page(tsk) + THREAD_SIZE - 32)
+#define task_pt_regs(tsk) ((struct pt_regs *)__KSTK_TOS(tsk) - 1)
+#define KSTK_EIP(tsk) (task_pt_regs(tsk)->cp0_epc)
+#define KSTK_ESP(tsk) (task_pt_regs(tsk)->regs[29])
+#define KSTK_STATUS(tsk) (task_pt_regs(tsk)->cp0_status)
+
+#define cpu_relax()	barrier()
+
+/*
+ * Return_address is a replacement for __builtin_return_address(count)
+ * which on certain architectures cannot reasonably be implemented in GCC
+ * (MIPS, Alpha) or is unuseable with -fomit-frame-pointer (i386).
+ * Note that __builtin_return_address(x>=1) is forbidden because GCC
+ * aborts compilation on some CPUs.  It's simply not possible to unwind
+ * some CPU's stackframes.
+ *
+ * __builtin_return_address works only for non-leaf functions.  We avoid the
+ * overhead of a function call by forcing the compiler to save the return
+ * address register on the stack.
+ */
+#define return_address() ({__asm__ __volatile__("":::"$31");__builtin_return_address(0);})
+
+#ifdef CONFIG_CPU_HAS_PREFETCH
+
+#define ARCH_HAS_PREFETCH
+
+static inline void prefetch(const void *addr)
+{
+	__asm__ __volatile__(
+	"	.set	mips4		\n"
+	"	pref	%0, (%1)	\n"
+	"	.set	mips0		\n"
+	:
+	: "i" (Pref_Load), "r" (addr));
+}
+
+#endif
+
+#endif /* _ASM_PROCESSOR_H */
diff --git a/arch/mips/include/asm/ptrace.h b/arch/mips/include/asm/ptrace.h
new file mode 100644
index 0000000..9c22571
--- /dev/null
+++ b/arch/mips/include/asm/ptrace.h
@@ -0,0 +1,154 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 1994, 95, 96, 97, 98, 99, 2000 by Ralf Baechle
+ * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
+ */
+#ifndef _ASM_PTRACE_H
+#define _ASM_PTRACE_H
+
+#ifdef CONFIG_64BIT
+#define __ARCH_WANT_COMPAT_SYS_PTRACE
+#endif
+
+/* 0 - 31 are integer registers, 32 - 63 are fp registers.  */
+#define FPR_BASE	32
+#define PC		64
+#define CAUSE		65
+#define BADVADDR	66
+#define MMHI		67
+#define MMLO		68
+#define FPC_CSR		69
+#define FPC_EIR		70
+#define DSP_BASE	71		/* 3 more hi / lo register pairs */
+#define DSP_CONTROL	77
+#define ACX		78
+
+/*
+ * This struct defines the way the registers are stored on the stack during a
+ * system call/exception. As usual the registers k0/k1 aren't being saved.
+ */
+struct pt_regs {
+#ifdef CONFIG_32BIT
+	/* Pad bytes for argument save space on the stack. */
+	unsigned long pad0[6];
+#endif
+
+	/* Saved main processor registers. */
+	unsigned long regs[32];
+
+	/* Saved special registers. */
+	unsigned long cp0_status;
+	unsigned long hi;
+	unsigned long lo;
+#ifdef CONFIG_CPU_HAS_SMARTMIPS
+	unsigned long acx;
+#endif
+	unsigned long cp0_badvaddr;
+	unsigned long cp0_cause;
+	unsigned long cp0_epc;
+#ifdef CONFIG_MIPS_MT_SMTC
+	unsigned long cp0_tcstatus;
+#endif /* CONFIG_MIPS_MT_SMTC */
+} __attribute__ ((aligned (8)));
+
+/* Arbitrarily choose the same ptrace numbers as used by the Sparc code. */
+#define PTRACE_GETREGS		12
+#define PTRACE_SETREGS		13
+#define PTRACE_GETFPREGS		14
+#define PTRACE_SETFPREGS		15
+/* #define PTRACE_GETFPXREGS		18 */
+/* #define PTRACE_SETFPXREGS		19 */
+
+#define PTRACE_OLDSETOPTIONS	21
+
+#define PTRACE_GET_THREAD_AREA	25
+#define PTRACE_SET_THREAD_AREA	26
+
+/* Calls to trace a 64bit program from a 32bit program.  */
+#define PTRACE_PEEKTEXT_3264	0xc0
+#define PTRACE_PEEKDATA_3264	0xc1
+#define PTRACE_POKETEXT_3264	0xc2
+#define PTRACE_POKEDATA_3264	0xc3
+#define PTRACE_GET_THREAD_AREA_3264	0xc4
+
+/* Read and write watchpoint registers.  */
+enum pt_watch_style {
+	pt_watch_style_mips32,
+	pt_watch_style_mips64
+};
+struct mips32_watch_regs {
+	uint32_t watchlo[8];
+	/* Lower 16 bits of watchhi. */
+	uint16_t watchhi[8];
+	/* Valid mask and I R W bits.
+	 * bit 0 -- 1 if W bit is usable.
+	 * bit 1 -- 1 if R bit is usable.
+	 * bit 2 -- 1 if I bit is usable.
+	 * bits 3 - 11 -- Valid watchhi mask bits.
+	 */
+	uint16_t watch_masks[8];
+	/* The number of valid watch register pairs.  */
+	uint32_t num_valid;
+} __attribute__((aligned(8)));
+
+struct mips64_watch_regs {
+	uint64_t watchlo[8];
+	uint16_t watchhi[8];
+	uint16_t watch_masks[8];
+	uint32_t num_valid;
+} __attribute__((aligned(8)));
+
+struct pt_watch_regs {
+	enum pt_watch_style style;
+	union {
+		struct mips32_watch_regs mips32;
+		struct mips32_watch_regs mips64;
+	};
+};
+
+#define PTRACE_GET_WATCH_REGS	0xd0
+#define PTRACE_SET_WATCH_REGS	0xd1
+
+#ifdef __KERNEL__
+
+#include <linux/compiler.h>
+#include <linux/linkage.h>
+#include <asm/isadep.h>
+
+struct task_struct;
+
+extern int ptrace_getregs(struct task_struct *child, __s64 __user *data);
+extern int ptrace_setregs(struct task_struct *child, __s64 __user *data);
+
+extern int ptrace_getfpregs(struct task_struct *child, __u32 __user *data);
+extern int ptrace_setfpregs(struct task_struct *child, __u32 __user *data);
+
+extern int ptrace_get_watch_regs(struct task_struct *child,
+	struct pt_watch_regs __user *addr);
+extern int ptrace_set_watch_regs(struct task_struct *child,
+	struct pt_watch_regs __user *addr);
+
+/*
+ * Does the process account for user or for system time?
+ */
+#define user_mode(regs) (((regs)->cp0_status & KU_MASK) == KU_USER)
+
+#define instruction_pointer(regs) ((regs)->cp0_epc)
+#define profile_pc(regs) instruction_pointer(regs)
+
+extern asmlinkage void do_syscall_trace(struct pt_regs *regs, int entryexit);
+
+extern NORET_TYPE void die(const char *, const struct pt_regs *) ATTRIB_NORET;
+
+static inline void die_if_kernel(const char *str, const struct pt_regs *regs)
+{
+	if (unlikely(!user_mode(regs)))
+		die(str, regs);
+}
+
+#endif
+
+#endif /* _ASM_PTRACE_H */
diff --git a/include/asm-mips/r4k-timer.h b/arch/mips/include/asm/r4k-timer.h
similarity index 100%
rename from include/asm-mips/r4k-timer.h
rename to arch/mips/include/asm/r4k-timer.h
diff --git a/include/asm-mips/r4kcache.h b/arch/mips/include/asm/r4kcache.h
similarity index 100%
rename from include/asm-mips/r4kcache.h
rename to arch/mips/include/asm/r4kcache.h
diff --git a/include/asm-mips/reboot.h b/arch/mips/include/asm/reboot.h
similarity index 100%
rename from include/asm-mips/reboot.h
rename to arch/mips/include/asm/reboot.h
diff --git a/include/asm-mips/reg.h b/arch/mips/include/asm/reg.h
similarity index 100%
rename from include/asm-mips/reg.h
rename to arch/mips/include/asm/reg.h
diff --git a/include/asm-mips/regdef.h b/arch/mips/include/asm/regdef.h
similarity index 100%
rename from include/asm-mips/regdef.h
rename to arch/mips/include/asm/regdef.h
diff --git a/include/asm-mips/resource.h b/arch/mips/include/asm/resource.h
similarity index 100%
rename from include/asm-mips/resource.h
rename to arch/mips/include/asm/resource.h
diff --git a/include/asm-mips/rm9k-ocd.h b/arch/mips/include/asm/rm9k-ocd.h
similarity index 100%
rename from include/asm-mips/rm9k-ocd.h
rename to arch/mips/include/asm/rm9k-ocd.h
diff --git a/include/asm-mips/rtlx.h b/arch/mips/include/asm/rtlx.h
similarity index 100%
rename from include/asm-mips/rtlx.h
rename to arch/mips/include/asm/rtlx.h
diff --git a/include/asm-mips/scatterlist.h b/arch/mips/include/asm/scatterlist.h
similarity index 100%
rename from include/asm-mips/scatterlist.h
rename to arch/mips/include/asm/scatterlist.h
diff --git a/include/asm-mips/seccomp.h b/arch/mips/include/asm/seccomp.h
similarity index 100%
rename from include/asm-mips/seccomp.h
rename to arch/mips/include/asm/seccomp.h
diff --git a/include/asm-mips/sections.h b/arch/mips/include/asm/sections.h
similarity index 100%
rename from include/asm-mips/sections.h
rename to arch/mips/include/asm/sections.h
diff --git a/include/asm-mips/segment.h b/arch/mips/include/asm/segment.h
similarity index 100%
rename from include/asm-mips/segment.h
rename to arch/mips/include/asm/segment.h
diff --git a/include/asm-mips/sembuf.h b/arch/mips/include/asm/sembuf.h
similarity index 100%
rename from include/asm-mips/sembuf.h
rename to arch/mips/include/asm/sembuf.h
diff --git a/include/asm-mips/serial.h b/arch/mips/include/asm/serial.h
similarity index 100%
rename from include/asm-mips/serial.h
rename to arch/mips/include/asm/serial.h
diff --git a/include/asm-mips/setup.h b/arch/mips/include/asm/setup.h
similarity index 100%
rename from include/asm-mips/setup.h
rename to arch/mips/include/asm/setup.h
diff --git a/include/asm-mips/sgi/gio.h b/arch/mips/include/asm/sgi/gio.h
similarity index 100%
rename from include/asm-mips/sgi/gio.h
rename to arch/mips/include/asm/sgi/gio.h
diff --git a/include/asm-mips/sgi/hpc3.h b/arch/mips/include/asm/sgi/hpc3.h
similarity index 100%
rename from include/asm-mips/sgi/hpc3.h
rename to arch/mips/include/asm/sgi/hpc3.h
diff --git a/include/asm-mips/sgi/ioc.h b/arch/mips/include/asm/sgi/ioc.h
similarity index 100%
rename from include/asm-mips/sgi/ioc.h
rename to arch/mips/include/asm/sgi/ioc.h
diff --git a/include/asm-mips/sgi/ip22.h b/arch/mips/include/asm/sgi/ip22.h
similarity index 100%
rename from include/asm-mips/sgi/ip22.h
rename to arch/mips/include/asm/sgi/ip22.h
diff --git a/include/asm-mips/sgi/mc.h b/arch/mips/include/asm/sgi/mc.h
similarity index 100%
rename from include/asm-mips/sgi/mc.h
rename to arch/mips/include/asm/sgi/mc.h
diff --git a/include/asm-mips/sgi/pi1.h b/arch/mips/include/asm/sgi/pi1.h
similarity index 100%
rename from include/asm-mips/sgi/pi1.h
rename to arch/mips/include/asm/sgi/pi1.h
diff --git a/include/asm-mips/sgi/seeq.h b/arch/mips/include/asm/sgi/seeq.h
similarity index 100%
rename from include/asm-mips/sgi/seeq.h
rename to arch/mips/include/asm/sgi/seeq.h
diff --git a/include/asm-mips/sgi/sgi.h b/arch/mips/include/asm/sgi/sgi.h
similarity index 100%
rename from include/asm-mips/sgi/sgi.h
rename to arch/mips/include/asm/sgi/sgi.h
diff --git a/include/asm-mips/sgi/wd.h b/arch/mips/include/asm/sgi/wd.h
similarity index 100%
rename from include/asm-mips/sgi/wd.h
rename to arch/mips/include/asm/sgi/wd.h
diff --git a/include/asm-mips/sgialib.h b/arch/mips/include/asm/sgialib.h
similarity index 100%
rename from include/asm-mips/sgialib.h
rename to arch/mips/include/asm/sgialib.h
diff --git a/include/asm-mips/sgiarcs.h b/arch/mips/include/asm/sgiarcs.h
similarity index 100%
rename from include/asm-mips/sgiarcs.h
rename to arch/mips/include/asm/sgiarcs.h
diff --git a/include/asm-mips/sgidefs.h b/arch/mips/include/asm/sgidefs.h
similarity index 100%
rename from include/asm-mips/sgidefs.h
rename to arch/mips/include/asm/sgidefs.h
diff --git a/include/asm-mips/shmbuf.h b/arch/mips/include/asm/shmbuf.h
similarity index 100%
rename from include/asm-mips/shmbuf.h
rename to arch/mips/include/asm/shmbuf.h
diff --git a/include/asm-mips/shmparam.h b/arch/mips/include/asm/shmparam.h
similarity index 100%
rename from include/asm-mips/shmparam.h
rename to arch/mips/include/asm/shmparam.h
diff --git a/include/asm-mips/sibyte/bcm1480_int.h b/arch/mips/include/asm/sibyte/bcm1480_int.h
similarity index 100%
rename from include/asm-mips/sibyte/bcm1480_int.h
rename to arch/mips/include/asm/sibyte/bcm1480_int.h
diff --git a/include/asm-mips/sibyte/bcm1480_l2c.h b/arch/mips/include/asm/sibyte/bcm1480_l2c.h
similarity index 100%
rename from include/asm-mips/sibyte/bcm1480_l2c.h
rename to arch/mips/include/asm/sibyte/bcm1480_l2c.h
diff --git a/include/asm-mips/sibyte/bcm1480_mc.h b/arch/mips/include/asm/sibyte/bcm1480_mc.h
similarity index 100%
rename from include/asm-mips/sibyte/bcm1480_mc.h
rename to arch/mips/include/asm/sibyte/bcm1480_mc.h
diff --git a/include/asm-mips/sibyte/bcm1480_regs.h b/arch/mips/include/asm/sibyte/bcm1480_regs.h
similarity index 100%
rename from include/asm-mips/sibyte/bcm1480_regs.h
rename to arch/mips/include/asm/sibyte/bcm1480_regs.h
diff --git a/include/asm-mips/sibyte/bcm1480_scd.h b/arch/mips/include/asm/sibyte/bcm1480_scd.h
similarity index 100%
rename from include/asm-mips/sibyte/bcm1480_scd.h
rename to arch/mips/include/asm/sibyte/bcm1480_scd.h
diff --git a/include/asm-mips/sibyte/bigsur.h b/arch/mips/include/asm/sibyte/bigsur.h
similarity index 100%
rename from include/asm-mips/sibyte/bigsur.h
rename to arch/mips/include/asm/sibyte/bigsur.h
diff --git a/include/asm-mips/sibyte/board.h b/arch/mips/include/asm/sibyte/board.h
similarity index 100%
rename from include/asm-mips/sibyte/board.h
rename to arch/mips/include/asm/sibyte/board.h
diff --git a/include/asm-mips/sibyte/carmel.h b/arch/mips/include/asm/sibyte/carmel.h
similarity index 100%
rename from include/asm-mips/sibyte/carmel.h
rename to arch/mips/include/asm/sibyte/carmel.h
diff --git a/include/asm-mips/sibyte/sb1250.h b/arch/mips/include/asm/sibyte/sb1250.h
similarity index 100%
rename from include/asm-mips/sibyte/sb1250.h
rename to arch/mips/include/asm/sibyte/sb1250.h
diff --git a/include/asm-mips/sibyte/sb1250_defs.h b/arch/mips/include/asm/sibyte/sb1250_defs.h
similarity index 100%
rename from include/asm-mips/sibyte/sb1250_defs.h
rename to arch/mips/include/asm/sibyte/sb1250_defs.h
diff --git a/include/asm-mips/sibyte/sb1250_dma.h b/arch/mips/include/asm/sibyte/sb1250_dma.h
similarity index 100%
rename from include/asm-mips/sibyte/sb1250_dma.h
rename to arch/mips/include/asm/sibyte/sb1250_dma.h
diff --git a/include/asm-mips/sibyte/sb1250_genbus.h b/arch/mips/include/asm/sibyte/sb1250_genbus.h
similarity index 100%
rename from include/asm-mips/sibyte/sb1250_genbus.h
rename to arch/mips/include/asm/sibyte/sb1250_genbus.h
diff --git a/include/asm-mips/sibyte/sb1250_int.h b/arch/mips/include/asm/sibyte/sb1250_int.h
similarity index 100%
rename from include/asm-mips/sibyte/sb1250_int.h
rename to arch/mips/include/asm/sibyte/sb1250_int.h
diff --git a/include/asm-mips/sibyte/sb1250_l2c.h b/arch/mips/include/asm/sibyte/sb1250_l2c.h
similarity index 100%
rename from include/asm-mips/sibyte/sb1250_l2c.h
rename to arch/mips/include/asm/sibyte/sb1250_l2c.h
diff --git a/include/asm-mips/sibyte/sb1250_ldt.h b/arch/mips/include/asm/sibyte/sb1250_ldt.h
similarity index 100%
rename from include/asm-mips/sibyte/sb1250_ldt.h
rename to arch/mips/include/asm/sibyte/sb1250_ldt.h
diff --git a/include/asm-mips/sibyte/sb1250_mac.h b/arch/mips/include/asm/sibyte/sb1250_mac.h
similarity index 100%
rename from include/asm-mips/sibyte/sb1250_mac.h
rename to arch/mips/include/asm/sibyte/sb1250_mac.h
diff --git a/include/asm-mips/sibyte/sb1250_mc.h b/arch/mips/include/asm/sibyte/sb1250_mc.h
similarity index 100%
rename from include/asm-mips/sibyte/sb1250_mc.h
rename to arch/mips/include/asm/sibyte/sb1250_mc.h
diff --git a/include/asm-mips/sibyte/sb1250_regs.h b/arch/mips/include/asm/sibyte/sb1250_regs.h
similarity index 100%
rename from include/asm-mips/sibyte/sb1250_regs.h
rename to arch/mips/include/asm/sibyte/sb1250_regs.h
diff --git a/include/asm-mips/sibyte/sb1250_scd.h b/arch/mips/include/asm/sibyte/sb1250_scd.h
similarity index 100%
rename from include/asm-mips/sibyte/sb1250_scd.h
rename to arch/mips/include/asm/sibyte/sb1250_scd.h
diff --git a/include/asm-mips/sibyte/sb1250_smbus.h b/arch/mips/include/asm/sibyte/sb1250_smbus.h
similarity index 100%
rename from include/asm-mips/sibyte/sb1250_smbus.h
rename to arch/mips/include/asm/sibyte/sb1250_smbus.h
diff --git a/include/asm-mips/sibyte/sb1250_syncser.h b/arch/mips/include/asm/sibyte/sb1250_syncser.h
similarity index 100%
rename from include/asm-mips/sibyte/sb1250_syncser.h
rename to arch/mips/include/asm/sibyte/sb1250_syncser.h
diff --git a/include/asm-mips/sibyte/sb1250_uart.h b/arch/mips/include/asm/sibyte/sb1250_uart.h
similarity index 100%
rename from include/asm-mips/sibyte/sb1250_uart.h
rename to arch/mips/include/asm/sibyte/sb1250_uart.h
diff --git a/include/asm-mips/sibyte/sentosa.h b/arch/mips/include/asm/sibyte/sentosa.h
similarity index 100%
rename from include/asm-mips/sibyte/sentosa.h
rename to arch/mips/include/asm/sibyte/sentosa.h
diff --git a/include/asm-mips/sibyte/swarm.h b/arch/mips/include/asm/sibyte/swarm.h
similarity index 100%
rename from include/asm-mips/sibyte/swarm.h
rename to arch/mips/include/asm/sibyte/swarm.h
diff --git a/include/asm-mips/sigcontext.h b/arch/mips/include/asm/sigcontext.h
similarity index 100%
rename from include/asm-mips/sigcontext.h
rename to arch/mips/include/asm/sigcontext.h
diff --git a/include/asm-mips/siginfo.h b/arch/mips/include/asm/siginfo.h
similarity index 100%
rename from include/asm-mips/siginfo.h
rename to arch/mips/include/asm/siginfo.h
diff --git a/include/asm-mips/signal.h b/arch/mips/include/asm/signal.h
similarity index 100%
rename from include/asm-mips/signal.h
rename to arch/mips/include/asm/signal.h
diff --git a/include/asm-mips/sim.h b/arch/mips/include/asm/sim.h
similarity index 100%
rename from include/asm-mips/sim.h
rename to arch/mips/include/asm/sim.h
diff --git a/include/asm-mips/smp-ops.h b/arch/mips/include/asm/smp-ops.h
similarity index 100%
rename from include/asm-mips/smp-ops.h
rename to arch/mips/include/asm/smp-ops.h
diff --git a/include/asm-mips/smp.h b/arch/mips/include/asm/smp.h
similarity index 100%
rename from include/asm-mips/smp.h
rename to arch/mips/include/asm/smp.h
diff --git a/arch/mips/include/asm/smtc.h b/arch/mips/include/asm/smtc.h
new file mode 100644
index 0000000..ea60bf0
--- /dev/null
+++ b/arch/mips/include/asm/smtc.h
@@ -0,0 +1,71 @@
+#ifndef _ASM_SMTC_MT_H
+#define _ASM_SMTC_MT_H
+
+/*
+ * Definitions for SMTC multitasking on MIPS MT cores
+ */
+
+#include <asm/mips_mt.h>
+#include <asm/smtc_ipi.h>
+
+/*
+ * System-wide SMTC status information
+ */
+
+extern unsigned int smtc_status;
+
+#define SMTC_TLB_SHARED	0x00000001
+#define SMTC_MTC_ACTIVE	0x00000002
+
+/*
+ * TLB/ASID Management information
+ */
+
+#define MAX_SMTC_TLBS 2
+#define MAX_SMTC_ASIDS 256
+#if NR_CPUS <= 8
+typedef char asiduse;
+#else
+#if NR_CPUS <= 16
+typedef short asiduse;
+#else
+typedef long asiduse;
+#endif
+#endif
+
+extern asiduse smtc_live_asid[MAX_SMTC_TLBS][MAX_SMTC_ASIDS];
+
+struct mm_struct;
+struct task_struct;
+
+void smtc_get_new_mmu_context(struct mm_struct *mm, unsigned long cpu);
+void self_ipi(struct smtc_ipi *);
+void smtc_flush_tlb_asid(unsigned long asid);
+extern int smtc_build_cpu_map(int startslot);
+extern void smtc_prepare_cpus(int cpus);
+extern void smtc_smp_finish(void);
+extern void smtc_boot_secondary(int cpu, struct task_struct *t);
+extern void smtc_cpus_done(void);
+
+
+/*
+ * Sharing the TLB between multiple VPEs means that the
+ * "random" index selection function is not allowed to
+ * select the current value of the Index register. To
+ * avoid additional TLB pressure, the Index registers
+ * are "parked" with an non-Valid value.
+ */
+
+#define PARKED_INDEX	((unsigned int)0x80000000)
+
+/*
+ * Define low-level interrupt mask for IPIs, if necessary.
+ * By default, use SW interrupt 1, which requires no external
+ * hardware support, but which works only for single-core
+ * MIPS MT systems.
+ */
+#ifndef MIPS_CPU_IPI_IRQ
+#define MIPS_CPU_IPI_IRQ 1
+#endif
+
+#endif /*  _ASM_SMTC_MT_H */
diff --git a/include/asm-mips/smtc_ipi.h b/arch/mips/include/asm/smtc_ipi.h
similarity index 100%
rename from include/asm-mips/smtc_ipi.h
rename to arch/mips/include/asm/smtc_ipi.h
diff --git a/include/asm-mips/smtc_proc.h b/arch/mips/include/asm/smtc_proc.h
similarity index 100%
rename from include/asm-mips/smtc_proc.h
rename to arch/mips/include/asm/smtc_proc.h
diff --git a/include/asm-mips/smvp.h b/arch/mips/include/asm/smvp.h
similarity index 100%
rename from include/asm-mips/smvp.h
rename to arch/mips/include/asm/smvp.h
diff --git a/include/asm-mips/sn/addrs.h b/arch/mips/include/asm/sn/addrs.h
similarity index 100%
rename from include/asm-mips/sn/addrs.h
rename to arch/mips/include/asm/sn/addrs.h
diff --git a/include/asm-mips/sn/agent.h b/arch/mips/include/asm/sn/agent.h
similarity index 100%
rename from include/asm-mips/sn/agent.h
rename to arch/mips/include/asm/sn/agent.h
diff --git a/include/asm-mips/sn/arch.h b/arch/mips/include/asm/sn/arch.h
similarity index 100%
rename from include/asm-mips/sn/arch.h
rename to arch/mips/include/asm/sn/arch.h
diff --git a/include/asm-mips/sn/fru.h b/arch/mips/include/asm/sn/fru.h
similarity index 100%
rename from include/asm-mips/sn/fru.h
rename to arch/mips/include/asm/sn/fru.h
diff --git a/include/asm-mips/sn/gda.h b/arch/mips/include/asm/sn/gda.h
similarity index 100%
rename from include/asm-mips/sn/gda.h
rename to arch/mips/include/asm/sn/gda.h
diff --git a/include/asm-mips/sn/hub.h b/arch/mips/include/asm/sn/hub.h
similarity index 100%
rename from include/asm-mips/sn/hub.h
rename to arch/mips/include/asm/sn/hub.h
diff --git a/include/asm-mips/sn/intr.h b/arch/mips/include/asm/sn/intr.h
similarity index 100%
rename from include/asm-mips/sn/intr.h
rename to arch/mips/include/asm/sn/intr.h
diff --git a/include/asm-mips/sn/io.h b/arch/mips/include/asm/sn/io.h
similarity index 100%
rename from include/asm-mips/sn/io.h
rename to arch/mips/include/asm/sn/io.h
diff --git a/include/asm-mips/sn/ioc3.h b/arch/mips/include/asm/sn/ioc3.h
similarity index 100%
rename from include/asm-mips/sn/ioc3.h
rename to arch/mips/include/asm/sn/ioc3.h
diff --git a/arch/mips/include/asm/sn/klconfig.h b/arch/mips/include/asm/sn/klconfig.h
new file mode 100644
index 0000000..09e590d
--- /dev/null
+++ b/arch/mips/include/asm/sn/klconfig.h
@@ -0,0 +1,898 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Derived from IRIX <sys/SN/klconfig.h>.
+ *
+ * Copyright (C) 1992 - 1997, 1999, 2000 Silicon Graphics, Inc.
+ * Copyright (C) 1999, 2000 by Ralf Baechle
+ */
+#ifndef	_ASM_SN_KLCONFIG_H
+#define	_ASM_SN_KLCONFIG_H
+
+/*
+ * The KLCONFIG structures store info about the various BOARDs found
+ * during Hardware Discovery. In addition, it stores info about the
+ * components found on the BOARDs.
+ */
+
+/*
+ * WARNING:
+ *	Certain assembly language routines (notably xxxxx.s) in the IP27PROM
+ *	will depend on the format of the data structures in this file.  In
+ *      most cases, rearranging the fields can seriously break things.
+ *      Adding fields in the beginning or middle can also break things.
+ *      Add fields if necessary, to the end of a struct in such a way
+ *      that offsets of existing fields do not change.
+ */
+
+#include <linux/types.h>
+#include <asm/sn/types.h>
+
+#if defined(CONFIG_SGI_IP27)
+
+#include <asm/sn/sn0/addrs.h>
+//#include <sys/SN/router.h>
+// XXX Stolen from <sys/SN/router.h>:
+#define MAX_ROUTER_PORTS (6)    /* Max. number of ports on a router */
+#include <asm/sn/fru.h>
+//#include <sys/graph.h>
+//#include <sys/xtalk/xbow.h>
+
+#elif defined(CONFIG_SGI_IP35)
+
+#include <asm/sn/sn1/addrs.h>
+#include <sys/sn/router.h>
+#include <sys/graph.h>
+#include <asm/xtalk/xbow.h>
+
+#endif /* !CONFIG_SGI_IP27 && !CONFIG_SGI_IP35 */
+
+#if defined(CONFIG_SGI_IP27) || defined(CONFIG_SGI_IP35)
+#include <asm/sn/agent.h>
+#include <asm/fw/arc/types.h>
+#include <asm/fw/arc/hinv.h>
+#if defined(CONFIG_SGI_IP35)
+// The hack file has to be before vector and after sn0_fru....
+#include <asm/hack.h>
+#include <asm/sn/vector.h>
+#include <asm/xtalk/xtalk.h>
+#endif /* CONFIG_SGI_IP35 */
+#endif /* CONFIG_SGI_IP27 || CONFIG_SGI_IP35 */
+
+typedef u64  nic_t;
+
+#define KLCFGINFO_MAGIC	0xbeedbabe
+
+typedef s32 klconf_off_t;
+
+/*
+ * Some IMPORTANT OFFSETS. These are the offsets on all NODES.
+ */
+#define	MAX_MODULE_ID		255
+#define SIZE_PAD		4096 /* 4k padding for structures */
+/*
+ * 1 NODE brd, 2 Router brd (1 8p, 1 meta), 6 Widgets,
+ * 2 Midplanes assuming no pci card cages
+ */
+#define MAX_SLOTS_PER_NODE	(1 + 2 + 6 + 2)
+
+/* XXX if each node is guranteed to have some memory */
+
+#define MAX_PCI_DEVS		8
+
+/* lboard_t->brd_flags fields */
+/* All bits in this field are currently used. Try the pad fields if
+   you need more flag bits */
+
+#define ENABLE_BOARD 		0x01
+#define FAILED_BOARD  		0x02
+#define DUPLICATE_BOARD 	0x04    /* Boards like midplanes/routers which
+					   are discovered twice. Use one of them */
+#define VISITED_BOARD		0x08	/* Used for compact hub numbering. */
+#define LOCAL_MASTER_IO6	0x10 	/* master io6 for that node */
+#define GLOBAL_MASTER_IO6	0x20
+#define THIRD_NIC_PRESENT 	0x40  	/* for future use */
+#define SECOND_NIC_PRESENT 	0x80 	/* addons like MIO are present */
+
+/* klinfo->flags fields */
+
+#define KLINFO_ENABLE 		0x01    /* This component is enabled */
+#define KLINFO_FAILED   	0x02 	/* This component failed */
+#define KLINFO_DEVICE   	0x04 	/* This component is a device */
+#define KLINFO_VISITED  	0x08 	/* This component has been visited */
+#define KLINFO_CONTROLLER   	0x10 	/* This component is a device controller */
+#define KLINFO_INSTALL   	0x20  	/* Install a driver */
+#define	KLINFO_HEADLESS		0x40	/* Headless (or hubless) component */
+#define IS_CONSOLE_IOC3(i)	((((klinfo_t *)i)->flags) & KLINFO_INSTALL)
+
+#define GB2		0x80000000
+
+#define MAX_RSV_PTRS	32
+
+/* Structures to manage various data storage areas */
+/* The numbers must be contiguous since the array index i
+   is used in the code to allocate various areas.
+*/
+
+#define BOARD_STRUCT 		0
+#define COMPONENT_STRUCT 	1
+#define ERRINFO_STRUCT 		2
+#define KLMALLOC_TYPE_MAX 	(ERRINFO_STRUCT + 1)
+#define DEVICE_STRUCT 		3
+
+
+typedef struct console_s {
+	unsigned long 	uart_base;
+	unsigned long 	config_base;
+	unsigned long 	memory_base;
+	short		baud;
+	short		flag;
+	int		type;
+	nasid_t		nasid;
+	char		wid;
+	char 		npci;
+	nic_t		baseio_nic;
+} console_t;
+
+typedef struct klc_malloc_hdr {
+        klconf_off_t km_base;
+        klconf_off_t km_limit;
+        klconf_off_t km_current;
+} klc_malloc_hdr_t;
+
+/* Functions/macros needed to use this structure */
+
+typedef struct kl_config_hdr {
+	u64		ch_magic;	/* set this to KLCFGINFO_MAGIC */
+	u32		ch_version;    /* structure version number */
+	klconf_off_t	ch_malloc_hdr_off; /* offset of ch_malloc_hdr */
+	klconf_off_t	ch_cons_off;       /* offset of ch_cons */
+	klconf_off_t	ch_board_info;	/* the link list of boards */
+	console_t	ch_cons_info;	/* address info of the console */
+	klc_malloc_hdr_t ch_malloc_hdr[KLMALLOC_TYPE_MAX];
+	confidence_t	ch_sw_belief;	/* confidence that software is bad*/
+	confidence_t	ch_sn0net_belief; /* confidence that sn0net is bad */
+} kl_config_hdr_t;
+
+
+#define KL_CONFIG_HDR(_nasid) 	((kl_config_hdr_t *)(KLCONFIG_ADDR(_nasid)))
+#define KL_CONFIG_INFO_OFFSET(_nasid)					\
+        (KL_CONFIG_HDR(_nasid)->ch_board_info)
+#define KL_CONFIG_INFO_SET_OFFSET(_nasid, _off)				\
+        (KL_CONFIG_HDR(_nasid)->ch_board_info = (_off))
+
+#define KL_CONFIG_INFO(_nasid) 						\
+        (lboard_t *)((KL_CONFIG_HDR(_nasid)->ch_board_info) ?		\
+	 NODE_OFFSET_TO_K1((_nasid), KL_CONFIG_HDR(_nasid)->ch_board_info) : \
+	 0)
+#define KL_CONFIG_MAGIC(_nasid)		(KL_CONFIG_HDR(_nasid)->ch_magic)
+
+#define KL_CONFIG_CHECK_MAGIC(_nasid)					\
+        (KL_CONFIG_HDR(_nasid)->ch_magic == KLCFGINFO_MAGIC)
+
+#define KL_CONFIG_HDR_INIT_MAGIC(_nasid)	\
+                  (KL_CONFIG_HDR(_nasid)->ch_magic = KLCFGINFO_MAGIC)
+
+/* --- New Macros for the changed kl_config_hdr_t structure --- */
+
+#define PTR_CH_MALLOC_HDR(_k)   ((klc_malloc_hdr_t *)\
+			((unsigned long)_k + (_k->ch_malloc_hdr_off)))
+
+#define KL_CONFIG_CH_MALLOC_HDR(_n)   PTR_CH_MALLOC_HDR(KL_CONFIG_HDR(_n))
+
+#define PTR_CH_CONS_INFO(_k)	((console_t *)\
+			((unsigned long)_k + (_k->ch_cons_off)))
+
+#define KL_CONFIG_CH_CONS_INFO(_n)   PTR_CH_CONS_INFO(KL_CONFIG_HDR(_n))
+
+/* ------------------------------------------------------------- */
+
+#define KL_CONFIG_INFO_START(_nasid)	\
+        (klconf_off_t)(KLCONFIG_OFFSET(_nasid) + sizeof(kl_config_hdr_t))
+
+#define KL_CONFIG_BOARD_NASID(_brd)	((_brd)->brd_nasid)
+#define KL_CONFIG_BOARD_SET_NEXT(_brd, _off)	((_brd)->brd_next = (_off))
+
+#define KL_CONFIG_DUPLICATE_BOARD(_brd)	((_brd)->brd_flags & DUPLICATE_BOARD)
+
+#define XBOW_PORT_TYPE_HUB(_xbowp, _link) 	\
+               ((_xbowp)->xbow_port_info[(_link) - BASE_XBOW_PORT].port_flag & XBOW_PORT_HUB)
+#define XBOW_PORT_TYPE_IO(_xbowp, _link) 	\
+               ((_xbowp)->xbow_port_info[(_link) - BASE_XBOW_PORT].port_flag & XBOW_PORT_IO)
+
+#define XBOW_PORT_IS_ENABLED(_xbowp, _link) 	\
+               ((_xbowp)->xbow_port_info[(_link) - BASE_XBOW_PORT].port_flag & XBOW_PORT_ENABLE)
+#define XBOW_PORT_NASID(_xbowp, _link) 	\
+               ((_xbowp)->xbow_port_info[(_link) - BASE_XBOW_PORT].port_nasid)
+
+#define XBOW_PORT_IO     0x1
+#define XBOW_PORT_HUB    0x2
+#define XBOW_PORT_ENABLE 0x4
+
+#define	SN0_PORT_FENCE_SHFT	0
+#define	SN0_PORT_FENCE_MASK	(1 << SN0_PORT_FENCE_SHFT)
+
+/*
+ * The KLCONFIG area is organized as a LINKED LIST of BOARDs. A BOARD
+ * can be either 'LOCAL' or 'REMOTE'. LOCAL means it is attached to
+ * the LOCAL/current NODE. REMOTE means it is attached to a different
+ * node.(TBD - Need a way to treat ROUTER boards.)
+ *
+ * There are 2 different structures to represent these boards -
+ * lboard - Local board, rboard - remote board. These 2 structures
+ * can be arbitrarily mixed in the LINKED LIST of BOARDs. (Refer
+ * Figure below). The first byte of the rboard or lboard structure
+ * is used to find out its type - no unions are used.
+ * If it is a lboard, then the config info of this board will be found
+ * on the local node. (LOCAL NODE BASE + offset value gives pointer to
+ * the structure.
+ * If it is a rboard, the local structure contains the node number
+ * and the offset of the beginning of the LINKED LIST on the remote node.
+ * The details of the hardware on a remote node can be built locally,
+ * if required, by reading the LINKED LIST on the remote node and
+ * ignoring all the rboards on that node.
+ *
+ * The local node uses the REMOTE NODE NUMBER + OFFSET to point to the
+ * First board info on the remote node. The remote node list is
+ * traversed as the local list, using the REMOTE BASE ADDRESS and not
+ * the local base address and ignoring all rboard values.
+ *
+ *
+ KLCONFIG
+
+ +------------+      +------------+      +------------+      +------------+
+ |  lboard    |  +-->|   lboard   |  +-->|   rboard   |  +-->|   lboard   |
+ +------------+  |   +------------+  |   +------------+  |   +------------+
+ | board info |  |   | board info |  |   |errinfo,bptr|  |   | board info |
+ +------------+  |   +------------+  |   +------------+  |   +------------+
+ | offset     |--+   |  offset    |--+   |  offset    |--+   |offset=NULL |
+ +------------+      +------------+      +------------+      +------------+
+
+
+ +------------+
+ | board info |
+ +------------+       +--------------------------------+
+ | compt 1    |------>| type, rev, diaginfo, size ...  |  (CPU)
+ +------------+       +--------------------------------+
+ | compt 2    |--+
+ +------------+  |    +--------------------------------+
+ |  ...       |  +--->| type, rev, diaginfo, size ...  |  (MEM_BANK)
+ +------------+       +--------------------------------+
+ | errinfo    |--+
+ +------------+  |    +--------------------------------+
+                 +--->|r/l brd errinfo,compt err flags |
+                      +--------------------------------+
+
+ *
+ * Each BOARD consists of COMPONENTs and the BOARD structure has
+ * pointers (offsets) to its COMPONENT structure.
+ * The COMPONENT structure has version info, size and speed info, revision,
+ * error info and the NIC info. This structure can accommodate any
+ * BOARD with arbitrary COMPONENT composition.
+ *
+ * The ERRORINFO part of each BOARD has error information
+ * that describes errors about the BOARD itself. It also has flags to
+ * indicate the COMPONENT(s) on the board that have errors. The error
+ * information specific to the COMPONENT is present in the respective
+ * COMPONENT structure.
+ *
+ * The ERRORINFO structure is also treated like a COMPONENT, ie. the
+ * BOARD has pointers(offset) to the ERRORINFO structure. The rboard
+ * structure also has a pointer to the ERRORINFO structure. This is
+ * the place to store ERRORINFO about a REMOTE NODE, if the HUB on
+ * that NODE is not working or if the REMOTE MEMORY is BAD. In cases where
+ * only the CPU of the REMOTE NODE is disabled, the ERRORINFO pointer can
+ * be a NODE NUMBER, REMOTE OFFSET combination, pointing to error info
+ * which is present on the REMOTE NODE.(TBD)
+ * REMOTE ERRINFO can be stored on any of the nearest nodes
+ * or on all the nearest nodes.(TBD)
+ * Like BOARD structures, REMOTE ERRINFO structures can be built locally
+ * using the rboard errinfo pointer.
+ *
+ * In order to get useful information from this Data organization, a set of
+ * interface routines are provided (TBD). The important thing to remember while
+ * manipulating the structures, is that, the NODE number information should
+ * be used. If the NODE is non-zero (remote) then each offset should
+ * be added to the REMOTE BASE ADDR else it should be added to the LOCAL BASE ADDR.
+ * This includes offsets for BOARDS, COMPONENTS and ERRORINFO.
+ *
+ * Note that these structures do not provide much info about connectivity.
+ * That info will be part of HWGRAPH, which is an extension of the cfg_t
+ * data structure. (ref IP27prom/cfg.h) It has to be extended to include
+ * the IO part of the Network(TBD).
+ *
+ * The data structures below define the above concepts.
+ */
+
+/*
+ * Values for CPU types
+ */
+#define KL_CPU_R4000		0x1	/* Standard R4000 */
+#define KL_CPU_TFP		0x2	/* TFP processor */
+#define	KL_CPU_R10000		0x3	/* R10000 (T5) */
+#define KL_CPU_NONE		(-1)	/* no cpu present in slot */
+
+/*
+ * IP27 BOARD classes
+ */
+
+#define KLCLASS_MASK	0xf0
+#define KLCLASS_NONE	0x00
+#define KLCLASS_NODE	0x10             /* CPU, Memory and HUB board */
+#define KLCLASS_CPU	KLCLASS_NODE
+#define KLCLASS_IO	0x20             /* BaseIO, 4 ch SCSI, ethernet, FDDI
+					    and the non-graphics widget boards */
+#define KLCLASS_ROUTER	0x30             /* Router board */
+#define KLCLASS_MIDPLANE 0x40            /* We need to treat this as a board
+                                            so that we can record error info */
+#define KLCLASS_GFX	0x50		/* graphics boards */
+
+#define KLCLASS_PSEUDO_GFX	0x60	/* HDTV type cards that use a gfx
+					 * hw ifc to xtalk and are not gfx
+					 * class for sw purposes */
+
+#define KLCLASS_MAX	7		/* Bump this if a new CLASS is added */
+#define KLTYPE_MAX	10		/* Bump this if a new CLASS is added */
+
+#define KLCLASS_UNKNOWN	0xf0
+
+#define KLCLASS(_x) ((_x) & KLCLASS_MASK)
+
+/*
+ * IP27 board types
+ */
+
+#define KLTYPE_MASK	0x0f
+#define KLTYPE_NONE	0x00
+#define KLTYPE_EMPTY	0x00
+
+#define KLTYPE_WEIRDCPU (KLCLASS_CPU | 0x0)
+#define KLTYPE_IP27	(KLCLASS_CPU | 0x1) /* 2 CPUs(R10K) per board */
+
+#define KLTYPE_WEIRDIO	(KLCLASS_IO  | 0x0)
+#define KLTYPE_BASEIO	(KLCLASS_IO  | 0x1) /* IOC3, SuperIO, Bridge, SCSI */
+#define KLTYPE_IO6	KLTYPE_BASEIO       /* Additional name */
+#define KLTYPE_4CHSCSI	(KLCLASS_IO  | 0x2)
+#define KLTYPE_MSCSI	KLTYPE_4CHSCSI      /* Additional name */
+#define KLTYPE_ETHERNET	(KLCLASS_IO  | 0x3)
+#define KLTYPE_MENET	KLTYPE_ETHERNET     /* Additional name */
+#define KLTYPE_FDDI  	(KLCLASS_IO  | 0x4)
+#define KLTYPE_UNUSED	(KLCLASS_IO  | 0x5) /* XXX UNUSED */
+#define KLTYPE_HAROLD   (KLCLASS_IO  | 0x6) /* PCI SHOE BOX */
+#define KLTYPE_PCI	KLTYPE_HAROLD
+#define KLTYPE_VME      (KLCLASS_IO  | 0x7) /* Any 3rd party VME card */
+#define KLTYPE_MIO   	(KLCLASS_IO  | 0x8)
+#define KLTYPE_FC    	(KLCLASS_IO  | 0x9)
+#define KLTYPE_LINC    	(KLCLASS_IO  | 0xA)
+#define KLTYPE_TPU    	(KLCLASS_IO  | 0xB) /* Tensor Processing Unit */
+#define KLTYPE_GSN_A   	(KLCLASS_IO  | 0xC) /* Main GSN board */
+#define KLTYPE_GSN_B   	(KLCLASS_IO  | 0xD) /* Auxiliary GSN board */
+
+#define KLTYPE_GFX	(KLCLASS_GFX | 0x0) /* unknown graphics type */
+#define KLTYPE_GFX_KONA (KLCLASS_GFX | 0x1) /* KONA graphics on IP27 */
+#define KLTYPE_GFX_MGRA (KLCLASS_GFX | 0x3) /* MGRAS graphics on IP27 */
+
+#define KLTYPE_WEIRDROUTER (KLCLASS_ROUTER | 0x0)
+#define KLTYPE_ROUTER     (KLCLASS_ROUTER | 0x1)
+#define KLTYPE_ROUTER2    KLTYPE_ROUTER		/* Obsolete! */
+#define KLTYPE_NULL_ROUTER (KLCLASS_ROUTER | 0x2)
+#define KLTYPE_META_ROUTER (KLCLASS_ROUTER | 0x3)
+
+#define KLTYPE_WEIRDMIDPLANE (KLCLASS_MIDPLANE | 0x0)
+#define KLTYPE_MIDPLANE8  (KLCLASS_MIDPLANE | 0x1) /* 8 slot backplane */
+#define KLTYPE_MIDPLANE    KLTYPE_MIDPLANE8
+#define KLTYPE_PBRICK_XBOW	(KLCLASS_MIDPLANE | 0x2)
+
+#define KLTYPE_IOBRICK		(KLCLASS_IOBRICK | 0x0)
+#define KLTYPE_IBRICK		(KLCLASS_IOBRICK | 0x1)
+#define KLTYPE_PBRICK		(KLCLASS_IOBRICK | 0x2)
+#define KLTYPE_XBRICK		(KLCLASS_IOBRICK | 0x3)
+
+#define KLTYPE_PBRICK_BRIDGE	KLTYPE_PBRICK
+
+/* The value of type should be more than 8 so that hinv prints
+ * out the board name from the NIC string. For values less than
+ * 8 the name of the board needs to be hard coded in a few places.
+ * When bringup started nic names had not standardized and so we
+ * had to hard code. (For people interested in history.)
+ */
+#define KLTYPE_XTHD   	(KLCLASS_PSEUDO_GFX | 0x9)
+
+#define KLTYPE_UNKNOWN	(KLCLASS_UNKNOWN | 0xf)
+
+#define KLTYPE(_x) 	((_x) & KLTYPE_MASK)
+#define IS_MIO_PRESENT(l)	((l->brd_type == KLTYPE_BASEIO) && \
+				 (l->brd_flags & SECOND_NIC_PRESENT))
+#define IS_MIO_IOC3(l, n)	(IS_MIO_PRESENT(l) && (n > 2))
+
+/*
+ * board structures
+ */
+
+#define MAX_COMPTS_PER_BRD 24
+
+#define LOCAL_BOARD 1
+#define REMOTE_BOARD 2
+
+#define LBOARD_STRUCT_VERSION 	2
+
+typedef struct lboard_s {
+	klconf_off_t 	brd_next;         /* Next BOARD */
+	unsigned char 	struct_type;      /* type of structure, local or remote */
+	unsigned char 	brd_type;         /* type+class */
+	unsigned char 	brd_sversion;     /* version of this structure */
+        unsigned char 	brd_brevision;    /* board revision */
+        unsigned char 	brd_promver;      /* board prom version, if any */
+	unsigned char 	brd_flags;        /* Enabled, Disabled etc */
+	unsigned char 	brd_slot;         /* slot number */
+	unsigned short	brd_debugsw;      /* Debug switches */
+	moduleid_t	brd_module;       /* module to which it belongs */
+	partid_t 	brd_partition;    /* Partition number */
+        unsigned short 	brd_diagval;      /* diagnostic value */
+        unsigned short 	brd_diagparm;     /* diagnostic parameter */
+        unsigned char 	brd_inventory;    /* inventory history */
+        unsigned char 	brd_numcompts;    /* Number of components */
+        nic_t         	brd_nic;          /* Number in CAN */
+	nasid_t		brd_nasid;        /* passed parameter */
+	klconf_off_t 	brd_compts[MAX_COMPTS_PER_BRD]; /* pointers to COMPONENTS */
+	klconf_off_t 	brd_errinfo;      /* Board's error information */
+	struct lboard_s *brd_parent;	  /* Logical parent for this brd */
+	vertex_hdl_t	brd_graph_link;   /* vertex hdl to connect extern compts */
+	confidence_t	brd_confidence;	  /* confidence that the board is bad */
+	nasid_t		brd_owner;        /* who owns this board */
+	unsigned char 	brd_nic_flags;    /* To handle 8 more NICs */
+	char		brd_name[32];
+} lboard_t;
+
+
+/*
+ *	Make sure we pass back the calias space address for local boards.
+ *	klconfig board traversal and error structure extraction defines.
+ */
+
+#define BOARD_SLOT(_brd)	((_brd)->brd_slot)
+
+#define KLCF_CLASS(_brd)	KLCLASS((_brd)->brd_type)
+#define KLCF_TYPE(_brd)		KLTYPE((_brd)->brd_type)
+#define KLCF_REMOTE(_brd)  	(((_brd)->struct_type & LOCAL_BOARD) ? 0 : 1)
+#define KLCF_NUM_COMPS(_brd)	((_brd)->brd_numcompts)
+#define KLCF_MODULE_ID(_brd)	((_brd)->brd_module)
+
+#define KLCF_NEXT(_brd) 	\
+        ((_brd)->brd_next ? 	\
+	 (lboard_t *)(NODE_OFFSET_TO_K1(NASID_GET(_brd), (_brd)->brd_next)):\
+	 NULL)
+#define KLCF_COMP(_brd, _ndx)   \
+                (klinfo_t *)(NODE_OFFSET_TO_K1(NASID_GET(_brd),	\
+					       (_brd)->brd_compts[(_ndx)]))
+
+#define KLCF_COMP_ERROR(_brd, _comp)	\
+               (NODE_OFFSET_TO_K1(NASID_GET(_brd), (_comp)->errinfo))
+
+#define KLCF_COMP_TYPE(_comp)	((_comp)->struct_type)
+#define KLCF_BRIDGE_W_ID(_comp)	((_comp)->physid)	/* Widget ID */
+
+
+
+/*
+ * Generic info structure. This stores common info about a
+ * component.
+ */
+
+typedef struct klinfo_s {                  /* Generic info */
+        unsigned char   struct_type;       /* type of this structure */
+        unsigned char   struct_version;    /* version of this structure */
+        unsigned char   flags;            /* Enabled, disabled etc */
+        unsigned char   revision;         /* component revision */
+        unsigned short  diagval;          /* result of diagnostics */
+        unsigned short  diagparm;         /* diagnostic parameter */
+        unsigned char   inventory;        /* previous inventory status */
+	nic_t 		nic;              /* MUst be aligned properly */
+        unsigned char   physid;           /* physical id of component */
+        unsigned int    virtid;           /* virtual id as seen by system */
+	unsigned char	widid;	          /* Widget id - if applicable */
+	nasid_t		nasid;            /* node number - from parent */
+	char		pad1;		  /* pad out structure. */
+	char		pad2;		  /* pad out structure. */
+	COMPONENT	*arcs_compt;      /* ptr to the arcs struct for ease*/
+        klconf_off_t	errinfo;          /* component specific errors */
+        unsigned short  pad3;             /* pci fields have moved over to */
+        unsigned short  pad4;             /* klbri_t */
+} klinfo_t ;
+
+#define KLCONFIG_INFO_ENABLED(_i)	((_i)->flags & KLINFO_ENABLE)
+/*
+ * Component structures.
+ * Following are the currently identified components:
+ * 	CPU, HUB, MEM_BANK,
+ * 	XBOW(consists of 16 WIDGETs, each of which can be HUB or GRAPHICS or BRIDGE)
+ * 	BRIDGE, IOC3, SuperIO, SCSI, FDDI
+ * 	ROUTER
+ * 	GRAPHICS
+ */
+#define KLSTRUCT_UNKNOWN	0
+#define KLSTRUCT_CPU  		1
+#define KLSTRUCT_HUB  		2
+#define KLSTRUCT_MEMBNK 	3
+#define KLSTRUCT_XBOW 		4
+#define KLSTRUCT_BRI 		5
+#define KLSTRUCT_IOC3 		6
+#define KLSTRUCT_PCI 		7
+#define KLSTRUCT_VME 		8
+#define KLSTRUCT_ROU		9
+#define KLSTRUCT_GFX 		10
+#define KLSTRUCT_SCSI 		11
+#define KLSTRUCT_FDDI 		12
+#define KLSTRUCT_MIO 		13
+#define KLSTRUCT_DISK 		14
+#define KLSTRUCT_TAPE 		15
+#define KLSTRUCT_CDROM 		16
+#define KLSTRUCT_HUB_UART 	17
+#define KLSTRUCT_IOC3ENET 	18
+#define KLSTRUCT_IOC3UART 	19
+#define KLSTRUCT_UNUSED		20 /* XXX UNUSED */
+#define KLSTRUCT_IOC3PCKM       21
+#define KLSTRUCT_RAD        	22
+#define KLSTRUCT_HUB_TTY        23
+#define KLSTRUCT_IOC3_TTY 	24
+
+/* Early Access IO proms are compatible
+   only with KLSTRUCT values upto 24. */
+
+#define KLSTRUCT_FIBERCHANNEL 	25
+#define KLSTRUCT_MOD_SERIAL_NUM 26
+#define KLSTRUCT_IOC3MS         27
+#define KLSTRUCT_TPU            28
+#define KLSTRUCT_GSN_A          29
+#define KLSTRUCT_GSN_B          30
+#define KLSTRUCT_XTHD           31
+
+/*
+ * These are the indices of various components within a lboard structure.
+ */
+
+#define IP27_CPU0_INDEX 0
+#define IP27_CPU1_INDEX 1
+#define IP27_HUB_INDEX 2
+#define IP27_MEM_INDEX 3
+
+#define BASEIO_BRIDGE_INDEX 0
+#define BASEIO_IOC3_INDEX 1
+#define BASEIO_SCSI1_INDEX 2
+#define BASEIO_SCSI2_INDEX 3
+
+#define MIDPLANE_XBOW_INDEX 0
+#define ROUTER_COMPONENT_INDEX 0
+
+#define CH4SCSI_BRIDGE_INDEX 0
+
+/* Info holders for various hardware components */
+
+typedef u64 *pci_t;
+typedef u64 *vmeb_t;
+typedef u64 *vmed_t;
+typedef u64 *fddi_t;
+typedef u64 *scsi_t;
+typedef u64 *mio_t;
+typedef u64 *graphics_t;
+typedef u64 *router_t;
+
+/*
+ * The port info in ip27_cfg area translates to a lboart_t in the
+ * KLCONFIG area. But since KLCONFIG does not use pointers, lboart_t
+ * is stored in terms of a nasid and a offset from start of KLCONFIG
+ * area  on that nasid.
+ */
+typedef struct klport_s {
+	nasid_t		port_nasid;
+	unsigned char	port_flag;
+	klconf_off_t	port_offset;
+} klport_t;
+
+typedef struct klcpu_s {                          /* CPU */
+	klinfo_t 	cpu_info;
+	unsigned short 	cpu_prid;	/* Processor PRID value */
+	unsigned short 	cpu_fpirr;	/* FPU IRR value */
+	unsigned short 	cpu_speed;	/* Speed in MHZ */
+	unsigned short 	cpu_scachesz;	/* secondary cache size in MB */
+	unsigned short 	cpu_scachespeed;/* secondary cache speed in MHz */
+} klcpu_t ;
+
+#define CPU_STRUCT_VERSION   2
+
+typedef struct klhub_s {			/* HUB */
+	klinfo_t 	hub_info;
+	unsigned int 		hub_flags;		/* PCFG_HUB_xxx flags */
+	klport_t	hub_port;		/* hub is connected to this */
+	nic_t		hub_box_nic;		/* nic of containing box */
+	klconf_off_t	hub_mfg_nic;		/* MFG NIC string */
+	u64		hub_speed;		/* Speed of hub in HZ */
+} klhub_t ;
+
+typedef struct klhub_uart_s {			/* HUB */
+	klinfo_t 	hubuart_info;
+	unsigned int 		hubuart_flags;		/* PCFG_HUB_xxx flags */
+	nic_t		hubuart_box_nic;	/* nic of containing box */
+} klhub_uart_t ;
+
+#define MEMORY_STRUCT_VERSION   2
+
+typedef struct klmembnk_s {			/* MEMORY BANK */
+	klinfo_t 	membnk_info;
+	short 		membnk_memsz;		/* Total memory in megabytes */
+	short		membnk_dimm_select; /* bank to physical addr mapping*/
+	short		membnk_bnksz[MD_MEM_BANKS]; /* Memory bank sizes */
+	short		membnk_attr;
+} klmembnk_t ;
+
+#define KLCONFIG_MEMBNK_SIZE(_info, _bank)	\
+                            ((_info)->membnk_bnksz[(_bank)])
+
+
+#define MEMBNK_PREMIUM 1
+#define KLCONFIG_MEMBNK_PREMIUM(_info, _bank)	\
+                            ((_info)->membnk_attr & (MEMBNK_PREMIUM << (_bank)))
+
+#define MAX_SERIAL_NUM_SIZE 10
+
+typedef struct klmod_serial_num_s {
+      klinfo_t        snum_info;
+      union {
+              char snum_str[MAX_SERIAL_NUM_SIZE];
+              unsigned long long       snum_int;
+      } snum;
+} klmod_serial_num_t;
+
+/* Macros needed to access serial number structure in lboard_t.
+   Hard coded values are necessary since we cannot treat
+   serial number struct as a component without losing compatibility
+   between prom versions. */
+
+#define GET_SNUM_COMP(_l) 	((klmod_serial_num_t *)\
+				KLCF_COMP(_l, _l->brd_numcompts))
+
+#define MAX_XBOW_LINKS 16
+
+typedef struct klxbow_s {                          /* XBOW */
+	klinfo_t 	xbow_info ;
+	klport_t	xbow_port_info[MAX_XBOW_LINKS] ; /* Module number */
+        int		xbow_master_hub_link;
+        /* type of brd connected+component struct ptr+flags */
+} klxbow_t ;
+
+#define MAX_PCI_SLOTS 8
+
+typedef struct klpci_device_s {
+	s32	pci_device_id;	/* 32 bits of vendor/device ID. */
+	s32	pci_device_pad;	/* 32 bits of padding. */
+} klpci_device_t;
+
+#define BRIDGE_STRUCT_VERSION	2
+
+typedef struct klbri_s {                          /* BRIDGE */
+	klinfo_t 	bri_info ;
+	unsigned char	bri_eprominfo ;    /* IO6prom connected to bridge */
+	unsigned char	bri_bustype ;      /* PCI/VME BUS bridge/GIO */
+	pci_t    	pci_specific  ;    /* PCI Board config info */
+	klpci_device_t	bri_devices[MAX_PCI_DEVS] ;	/* PCI IDs */
+	klconf_off_t	bri_mfg_nic ;
+} klbri_t ;
+
+#define MAX_IOC3_TTY	2
+
+typedef struct klioc3_s {                          /* IOC3 */
+	klinfo_t 	ioc3_info ;
+	unsigned char	ioc3_ssram ;        /* Info about ssram */
+	unsigned char	ioc3_nvram ;        /* Info about nvram */
+	klinfo_t	ioc3_superio ;      /* Info about superio */
+	klconf_off_t	ioc3_tty_off ;
+	klinfo_t	ioc3_enet ;
+	klconf_off_t	ioc3_enet_off ;
+	klconf_off_t	ioc3_kbd_off ;
+} klioc3_t ;
+
+#define MAX_VME_SLOTS 8
+
+typedef struct klvmeb_s {                          /* VME BRIDGE - PCI CTLR */
+	klinfo_t 	vmeb_info ;
+	vmeb_t		vmeb_specific ;
+	klconf_off_t   	vmeb_brdinfo[MAX_VME_SLOTS]   ;    /* VME Board config info */
+} klvmeb_t ;
+
+typedef struct klvmed_s {                          /* VME DEVICE - VME BOARD */
+	klinfo_t	vmed_info ;
+	vmed_t		vmed_specific ;
+	klconf_off_t   	vmed_brdinfo[MAX_VME_SLOTS]   ;    /* VME Board config info */
+} klvmed_t ;
+
+#define ROUTER_VECTOR_VERS	2
+
+/* XXX - Don't we need the number of ports here?!? */
+typedef struct klrou_s {                          /* ROUTER */
+	klinfo_t 	rou_info ;
+	unsigned int		rou_flags ;           /* PCFG_ROUTER_xxx flags */
+	nic_t		rou_box_nic ;         /* nic of the containing module */
+	klport_t 	rou_port[MAX_ROUTER_PORTS + 1] ; /* array index 1 to 6 */
+	klconf_off_t	rou_mfg_nic ;     /* MFG NIC string */
+	u64	rou_vector;	  /* vector from master node */
+} klrou_t ;
+
+/*
+ *  Graphics Controller/Device
+ *
+ *  (IP27/IO6) Prom versions 6.13 (and 6.5.1 kernels) and earlier
+ *  used a couple different structures to store graphics information.
+ *  For compatibility reasons, the newer data structure preserves some
+ *  of the layout so that fields that are used in the old versions remain
+ *  in the same place (with the same info).  Determination of what version
+ *  of this structure we have is done by checking the cookie field.
+ */
+#define KLGFX_COOKIE	0x0c0de000
+
+typedef struct klgfx_s {		/* GRAPHICS Device */
+	klinfo_t 	gfx_info;
+	klconf_off_t    old_gndevs;	/* for compatibility with older proms */
+	klconf_off_t    old_gdoff0;	/* for compatibility with older proms */
+	unsigned int		cookie;		/* for compatibility with older proms */
+	unsigned int		moduleslot;
+	struct klgfx_s	*gfx_next_pipe;
+	graphics_t	gfx_specific;
+	klconf_off_t    pad0;		/* for compatibility with older proms */
+	klconf_off_t    gfx_mfg_nic;
+} klgfx_t;
+
+typedef struct klxthd_s {
+	klinfo_t 	xthd_info ;
+	klconf_off_t	xthd_mfg_nic ;        /* MFG NIC string */
+} klxthd_t ;
+
+typedef struct kltpu_s {                     /* TPU board */
+	klinfo_t 	tpu_info ;
+	klconf_off_t	tpu_mfg_nic ;        /* MFG NIC string */
+} kltpu_t ;
+
+typedef struct klgsn_s {                     /* GSN board */
+	klinfo_t 	gsn_info ;
+	klconf_off_t	gsn_mfg_nic ;        /* MFG NIC string */
+} klgsn_t ;
+
+#define MAX_SCSI_DEVS 16
+
+/*
+ * NOTE: THis is the max sized kl* structure and is used in klmalloc.c
+ * to allocate space of type COMPONENT. Make sure that if the size of
+ * any other component struct becomes more than this, then redefine
+ * that as the size to be klmalloced.
+ */
+
+typedef struct klscsi_s {                          /* SCSI Controller */
+	klinfo_t 	scsi_info ;
+	scsi_t       	scsi_specific   ;
+	unsigned char 	scsi_numdevs ;
+	klconf_off_t	scsi_devinfo[MAX_SCSI_DEVS] ;
+} klscsi_t ;
+
+typedef struct klscdev_s {                          /* SCSI device */
+	klinfo_t 	scdev_info ;
+	struct scsidisk_data *scdev_cfg ; /* driver fills up this */
+} klscdev_t ;
+
+typedef struct klttydev_s {                          /* TTY device */
+	klinfo_t 	ttydev_info ;
+	struct terminal_data *ttydev_cfg ; /* driver fills up this */
+} klttydev_t ;
+
+typedef struct klenetdev_s {                          /* ENET device */
+	klinfo_t 	enetdev_info ;
+	struct net_data *enetdev_cfg ; /* driver fills up this */
+} klenetdev_t ;
+
+typedef struct klkbddev_s {                          /* KBD device */
+	klinfo_t 	kbddev_info ;
+	struct keyboard_data *kbddev_cfg ; /* driver fills up this */
+} klkbddev_t ;
+
+typedef struct klmsdev_s {                          /* mouse device */
+        klinfo_t        msdev_info ;
+        void 		*msdev_cfg ;
+} klmsdev_t ;
+
+#define MAX_FDDI_DEVS 10 /* XXX Is this true */
+
+typedef struct klfddi_s {                          /* FDDI */
+	klinfo_t 	fddi_info ;
+	fddi_t        	fddi_specific ;
+	klconf_off_t	fddi_devinfo[MAX_FDDI_DEVS] ;
+} klfddi_t ;
+
+typedef struct klmio_s {                          /* MIO */
+	klinfo_t 	mio_info ;
+	mio_t       	mio_specific   ;
+} klmio_t ;
+
+
+typedef union klcomp_s {
+	klcpu_t		kc_cpu;
+	klhub_t		kc_hub;
+	klmembnk_t 	kc_mem;
+	klxbow_t  	kc_xbow;
+	klbri_t		kc_bri;
+	klioc3_t	kc_ioc3;
+	klvmeb_t	kc_vmeb;
+	klvmed_t	kc_vmed;
+	klrou_t		kc_rou;
+	klgfx_t		kc_gfx;
+	klscsi_t	kc_scsi;
+	klscdev_t	kc_scsi_dev;
+	klfddi_t	kc_fddi;
+	klmio_t		kc_mio;
+	klmod_serial_num_t kc_snum ;
+} klcomp_t;
+
+typedef union kldev_s {      /* for device structure allocation */
+	klscdev_t	kc_scsi_dev ;
+	klttydev_t	kc_tty_dev ;
+	klenetdev_t	kc_enet_dev ;
+	klkbddev_t 	kc_kbd_dev ;
+} kldev_t ;
+
+/* Data structure interface routines. TBD */
+
+/* Include launch info in this file itself? TBD */
+
+/*
+ * TBD - Can the ARCS and device driver related info also be included in the
+ * KLCONFIG area. On the IO4PROM, prom device driver info is part of cfgnode_t
+ * structure, viz private to the IO4prom.
+ */
+
+/*
+ * TBD - Allocation issues.
+ *
+ * Do we need to Mark off sepatate heaps for lboard_t, rboard_t, component,
+ * errinfo and allocate from them, or have a single heap and allocate all
+ * structures from it. Debug is easier in the former method since we can
+ * dump all similar structs in one command, but there will be lots of holes,
+ * in memory and max limits are needed for number of structures.
+ * Another way to make it organized, is to have a union of all components
+ * and allocate a aligned chunk of memory greater than the biggest
+ * component.
+ */
+
+typedef union {
+	lboard_t *lbinfo ;
+} biptr_t ;
+
+
+#define BRI_PER_XBOW 6
+#define PCI_PER_BRI  8
+#define DEV_PER_PCI  16
+
+
+/* Virtual dipswitch values (starting from switch "7"): */
+
+#define VDS_NOGFX		0x8000	/* Don't enable gfx and autoboot */
+#define VDS_NOMP		0x100	/* Don't start slave processors */
+#define VDS_MANUMODE		0x80	/* Manufacturing mode */
+#define VDS_NOARB		0x40	/* No bootmaster arbitration */
+#define VDS_PODMODE		0x20	/* Go straight to POD mode */
+#define VDS_NO_DIAGS		0x10	/* Don't run any diags after BM arb */
+#define VDS_DEFAULTS		0x08	/* Use default environment values */
+#define VDS_NOMEMCLEAR		0x04	/* Don't run mem cfg code */
+#define VDS_2ND_IO4		0x02	/* Boot from the second IO4 */
+#define VDS_DEBUG_PROM		0x01	/* Print PROM debugging messages */
+
+/* external declarations of Linux kernel functions. */
+
+extern lboard_t *find_lboard(lboard_t *start, unsigned char type);
+extern klinfo_t *find_component(lboard_t *brd, klinfo_t *kli, unsigned char type);
+extern klinfo_t *find_first_component(lboard_t *brd, unsigned char type);
+extern klcpu_t *nasid_slice_to_cpuinfo(nasid_t, int);
+extern lboard_t *find_lboard_class(lboard_t *start, unsigned char brd_class);
+
+
+extern klcpu_t *sn_get_cpuinfo(cpuid_t cpu);
+
+#endif /* _ASM_SN_KLCONFIG_H */
diff --git a/include/asm-mips/sn/kldir.h b/arch/mips/include/asm/sn/kldir.h
similarity index 100%
rename from include/asm-mips/sn/kldir.h
rename to arch/mips/include/asm/sn/kldir.h
diff --git a/include/asm-mips/sn/klkernvars.h b/arch/mips/include/asm/sn/klkernvars.h
similarity index 100%
rename from include/asm-mips/sn/klkernvars.h
rename to arch/mips/include/asm/sn/klkernvars.h
diff --git a/include/asm-mips/sn/launch.h b/arch/mips/include/asm/sn/launch.h
similarity index 100%
rename from include/asm-mips/sn/launch.h
rename to arch/mips/include/asm/sn/launch.h
diff --git a/arch/mips/include/asm/sn/mapped_kernel.h b/arch/mips/include/asm/sn/mapped_kernel.h
new file mode 100644
index 0000000..721496a
--- /dev/null
+++ b/arch/mips/include/asm/sn/mapped_kernel.h
@@ -0,0 +1,54 @@
+/*
+ * File created by Kanoj Sarcar 06/06/00.
+ * Copyright 2000 Silicon Graphics, Inc.
+ */
+#ifndef __ASM_SN_MAPPED_KERNEL_H
+#define __ASM_SN_MAPPED_KERNEL_H
+
+#include <linux/mmzone.h>
+
+/*
+ * Note on how mapped kernels work: the text and data section is
+ * compiled at cksseg segment (LOADADDR = 0xc001c000), and the
+ * init/setup/data section gets a 16M virtual address bump in the
+ * ld.script file (so that tlblo0 and tlblo1 maps the sections).
+ * The vmlinux.64 section addresses are put in the xkseg range
+ * using the change-addresses makefile option. Use elfdump -of
+ * on IRIX to see where the sections go. The Origin loader loads
+ * the two sections contiguously in physical memory. The loader
+ * sets the entry point into kernel_entry using a xkphys address,
+ * but instead of using 0xa800000001160000, it uses the address
+ * 0xa800000000160000, which is where it physically loaded that
+ * code. So no jumps can be done before we have switched to using
+ * cksseg addresses.
+ */
+#include <asm/addrspace.h>
+
+#define REP_BASE	CAC_BASE
+
+#ifdef CONFIG_MAPPED_KERNEL
+
+#define MAPPED_ADDR_RO_TO_PHYS(x)	(x - REP_BASE)
+#define MAPPED_ADDR_RW_TO_PHYS(x)	(x - REP_BASE - 16777216)
+
+#define MAPPED_KERN_RO_PHYSBASE(n) (hub_data(n)->kern_vars.kv_ro_baseaddr)
+#define MAPPED_KERN_RW_PHYSBASE(n) (hub_data(n)->kern_vars.kv_rw_baseaddr)
+
+#define MAPPED_KERN_RO_TO_PHYS(x) \
+				((unsigned long)MAPPED_ADDR_RO_TO_PHYS(x) | \
+				MAPPED_KERN_RO_PHYSBASE(get_compact_nodeid()))
+#define MAPPED_KERN_RW_TO_PHYS(x) \
+				((unsigned long)MAPPED_ADDR_RW_TO_PHYS(x) | \
+				MAPPED_KERN_RW_PHYSBASE(get_compact_nodeid()))
+
+#else /* CONFIG_MAPPED_KERNEL */
+
+#define MAPPED_KERN_RO_TO_PHYS(x)	(x - REP_BASE)
+#define MAPPED_KERN_RW_TO_PHYS(x)	(x - REP_BASE)
+
+#endif /* CONFIG_MAPPED_KERNEL */
+
+#define MAPPED_KERN_RO_TO_K0(x)	PHYS_TO_K0(MAPPED_KERN_RO_TO_PHYS(x))
+#define MAPPED_KERN_RW_TO_K0(x)	PHYS_TO_K0(MAPPED_KERN_RW_TO_PHYS(x))
+
+#endif /* __ASM_SN_MAPPED_KERNEL_H  */
diff --git a/include/asm-mips/sn/nmi.h b/arch/mips/include/asm/sn/nmi.h
similarity index 100%
rename from include/asm-mips/sn/nmi.h
rename to arch/mips/include/asm/sn/nmi.h
diff --git a/include/asm-mips/sn/sn0/addrs.h b/arch/mips/include/asm/sn/sn0/addrs.h
similarity index 100%
rename from include/asm-mips/sn/sn0/addrs.h
rename to arch/mips/include/asm/sn/sn0/addrs.h
diff --git a/include/asm-mips/sn/sn0/arch.h b/arch/mips/include/asm/sn/sn0/arch.h
similarity index 100%
rename from include/asm-mips/sn/sn0/arch.h
rename to arch/mips/include/asm/sn/sn0/arch.h
diff --git a/include/asm-mips/sn/sn0/hub.h b/arch/mips/include/asm/sn/sn0/hub.h
similarity index 100%
rename from include/asm-mips/sn/sn0/hub.h
rename to arch/mips/include/asm/sn/sn0/hub.h
diff --git a/arch/mips/include/asm/sn/sn0/hubio.h b/arch/mips/include/asm/sn/sn0/hubio.h
new file mode 100644
index 0000000..d0c29d4
--- /dev/null
+++ b/arch/mips/include/asm/sn/sn0/hubio.h
@@ -0,0 +1,972 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Derived from IRIX <sys/SN/SN0/hubio.h>, Revision 1.80.
+ *
+ * Copyright (C) 1992 - 1997, 1999 Silicon Graphics, Inc.
+ * Copyright (C) 1999 by Ralf Baechle
+ */
+#ifndef	_ASM_SGI_SN_SN0_HUBIO_H
+#define	_ASM_SGI_SN_SN0_HUBIO_H
+
+/*
+ * Hub I/O interface registers
+ *
+ * All registers in this file are subject to change until Hub chip tapeout.
+ * In general, the longer software name should be used when available.
+ */
+
+/*
+ * Slightly friendlier names for some common registers.
+ * The hardware definitions follow.
+ */
+#define IIO_WIDGET		IIO_WID      /* Widget identification */
+#define IIO_WIDGET_STAT		IIO_WSTAT    /* Widget status register */
+#define IIO_WIDGET_CTRL		IIO_WCR	     /* Widget control register */
+#define IIO_WIDGET_TOUT		IIO_WRTO     /* Widget request timeout */
+#define IIO_WIDGET_FLUSH	IIO_WTFR     /* Widget target flush */
+#define IIO_PROTECT		IIO_ILAPR    /* IO interface protection */
+#define IIO_PROTECT_OVRRD	IIO_ILAPO    /* IO protect override */
+#define IIO_OUTWIDGET_ACCESS	IIO_IOWA     /* Outbound widget access */
+#define IIO_INWIDGET_ACCESS	IIO_IIWA     /* Inbound widget access */
+#define IIO_INDEV_ERR_MASK	IIO_IIDEM    /* Inbound device error mask */
+#define IIO_LLP_CSR		IIO_ILCSR    /* LLP control and status */
+#define IIO_LLP_LOG		IIO_ILLR     /* LLP log */
+#define IIO_XTALKCC_TOUT	IIO_IXCC     /* Xtalk credit count timeout*/
+#define IIO_XTALKTT_TOUT	IIO_IXTT     /* Xtalk tail timeout */
+#define IIO_IO_ERR_CLR		IIO_IECLR    /* IO error clear */
+#define IIO_BTE_CRB_CNT         IIO_IBCN     /* IO BTE CRB count */
+
+#define IIO_LLP_CSR_IS_UP		0x00002000
+#define	IIO_LLP_CSR_LLP_STAT_MASK	0x00003000
+#define	IIO_LLP_CSR_LLP_STAT_SHFT	12
+
+/* key to IIO_PROTECT_OVRRD */
+#define IIO_PROTECT_OVRRD_KEY	0x53474972756c6573ull	/* "SGIrules" */
+
+/* BTE register names */
+#define IIO_BTE_STAT_0		IIO_IBLS_0   /* Also BTE length/status 0 */
+#define IIO_BTE_SRC_0		IIO_IBSA_0   /* Also BTE source address  0 */
+#define IIO_BTE_DEST_0		IIO_IBDA_0   /* Also BTE dest. address 0 */
+#define IIO_BTE_CTRL_0		IIO_IBCT_0   /* Also BTE control/terminate 0 */
+#define IIO_BTE_NOTIFY_0 	IIO_IBNA_0   /* Also BTE notification 0 */
+#define IIO_BTE_INT_0		IIO_IBIA_0   /* Also BTE interrupt 0 */
+#define IIO_BTE_OFF_0		0	     /* Base offset from BTE 0 regs. */
+#define IIO_BTE_OFF_1	IIO_IBLS_1 - IIO_IBLS_0 /* Offset from base to BTE 1 */
+
+/* BTE register offsets from base */
+#define BTEOFF_STAT		0
+#define BTEOFF_SRC		(IIO_BTE_SRC_0 - IIO_BTE_STAT_0)
+#define BTEOFF_DEST		(IIO_BTE_DEST_0 - IIO_BTE_STAT_0)
+#define BTEOFF_CTRL		(IIO_BTE_CTRL_0 - IIO_BTE_STAT_0)
+#define BTEOFF_NOTIFY		(IIO_BTE_NOTIFY_0 - IIO_BTE_STAT_0)
+#define BTEOFF_INT		(IIO_BTE_INT_0 - IIO_BTE_STAT_0)
+
+
+/*
+ * The following definitions use the names defined in the IO interface
+ * document for ease of reference.  When possible, software should
+ * generally use the longer but clearer names defined above.
+ */
+
+#define IIO_BASE	0x400000
+#define IIO_BASE_BTE0	0x410000
+#define IIO_BASE_BTE1	0x420000
+#define IIO_BASE_PERF	0x430000
+#define IIO_PERF_CNT	0x430008
+
+#define IO_PERF_SETS	32
+
+#define IIO_WID		0x400000	/* Widget identification */
+#define IIO_WSTAT	0x400008	/* Widget status */
+#define IIO_WCR		0x400020	/* Widget control */
+
+#define	IIO_WSTAT_ECRAZY	(1ULL << 32)	/* Hub gone crazy */
+#define	IIO_WSTAT_TXRETRY	(1ULL << 9)	/* Hub Tx Retry timeout */
+#define	IIO_WSTAT_TXRETRY_MASK	(0x7F)
+#define	IIO_WSTAT_TXRETRY_SHFT	(16)
+#define	IIO_WSTAT_TXRETRY_CNT(w)	(((w) >> IIO_WSTAT_TXRETRY_SHFT) & \
+					  IIO_WSTAT_TXRETRY_MASK)
+
+#define IIO_ILAPR	0x400100	/* Local Access Protection */
+#define IIO_ILAPO	0x400108	/* Protection override */
+#define IIO_IOWA	0x400110	/* outbound widget access */
+#define IIO_IIWA	0x400118	/* inbound widget access */
+#define IIO_IIDEM	0x400120	/* Inbound Device Error Mask */
+#define IIO_ILCSR	0x400128	/* LLP control and status */
+#define IIO_ILLR	0x400130	/* LLP Log */
+#define IIO_IIDSR	0x400138	/* Interrupt destination */
+
+#define IIO_IIBUSERR	0x1400208	/* Reads here cause a bus error. */
+
+/* IO Interrupt Destination Register */
+#define IIO_IIDSR_SENT_SHIFT	28
+#define IIO_IIDSR_SENT_MASK	0x10000000
+#define IIO_IIDSR_ENB_SHIFT	24
+#define IIO_IIDSR_ENB_MASK	0x01000000
+#define IIO_IIDSR_NODE_SHIFT	8
+#define IIO_IIDSR_NODE_MASK	0x0000ff00
+#define IIO_IIDSR_LVL_SHIFT	0
+#define IIO_IIDSR_LVL_MASK	0x0000003f
+
+
+/* GFX Flow Control Node/Widget Register */
+#define IIO_IGFX_0	0x400140	/* gfx node/widget register 0 */
+#define IIO_IGFX_1	0x400148	/* gfx node/widget register 1 */
+#define IIO_IGFX_W_NUM_BITS	4	/* size of widget num field */
+#define IIO_IGFX_W_NUM_MASK	((1<<IIO_IGFX_W_NUM_BITS)-1)
+#define IIO_IGFX_W_NUM_SHIFT	0
+#define IIO_IGFX_N_NUM_BITS	9	/* size of node num field */
+#define IIO_IGFX_N_NUM_MASK	((1<<IIO_IGFX_N_NUM_BITS)-1)
+#define IIO_IGFX_N_NUM_SHIFT	4
+#define IIO_IGFX_P_NUM_BITS	1	/* size of processor num field */
+#define IIO_IGFX_P_NUM_MASK	((1<<IIO_IGFX_P_NUM_BITS)-1)
+#define IIO_IGFX_P_NUM_SHIFT	16
+#define IIO_IGFX_VLD_BITS	1	/* size of valid field */
+#define IIO_IGFX_VLD_MASK	((1<<IIO_IGFX_VLD_BITS)-1)
+#define IIO_IGFX_VLD_SHIFT	20
+#define IIO_IGFX_INIT(widget, node, cpu, valid)				(\
+	(((widget) & IIO_IGFX_W_NUM_MASK) << IIO_IGFX_W_NUM_SHIFT) |	 \
+	(((node)   & IIO_IGFX_N_NUM_MASK) << IIO_IGFX_N_NUM_SHIFT) |	 \
+	(((cpu)    & IIO_IGFX_P_NUM_MASK) << IIO_IGFX_P_NUM_SHIFT) |	 \
+	(((valid)  & IIO_IGFX_VLD_MASK)   << IIO_IGFX_VLD_SHIFT)	 )
+
+/* Scratch registers (not all bits available) */
+#define IIO_SCRATCH_REG0	0x400150
+#define	IIO_SCRATCH_REG1	0x400158
+#define IIO_SCRATCH_MASK	0x0000000f00f11fff
+
+#define IIO_SCRATCH_BIT0_0	0x0000000800000000
+#define IIO_SCRATCH_BIT0_1	0x0000000400000000
+#define IIO_SCRATCH_BIT0_2	0x0000000200000000
+#define IIO_SCRATCH_BIT0_3	0x0000000100000000
+#define IIO_SCRATCH_BIT0_4	0x0000000000800000
+#define IIO_SCRATCH_BIT0_5	0x0000000000400000
+#define IIO_SCRATCH_BIT0_6	0x0000000000200000
+#define IIO_SCRATCH_BIT0_7	0x0000000000100000
+#define IIO_SCRATCH_BIT0_8	0x0000000000010000
+#define IIO_SCRATCH_BIT0_9	0x0000000000001000
+#define IIO_SCRATCH_BIT0_R	0x0000000000000fff
+
+/* IO Translation Table Entries */
+#define IIO_NUM_ITTES	7		/* ITTEs numbered 0..6 */
+					/* Hw manuals number them 1..7! */
+
+/*
+ * As a permanent workaround for a bug in the PI side of the hub, we've
+ * redefined big window 7 as small window 0.
+ */
+#define HUB_NUM_BIG_WINDOW	IIO_NUM_ITTES - 1
+
+/*
+ * Use the top big window as a surrogate for the first small window
+ */
+#define SWIN0_BIGWIN		HUB_NUM_BIG_WINDOW
+
+#define ILCSR_WARM_RESET	0x100
+/*
+ * The IO LLP control status register and widget control register
+ */
+#ifndef __ASSEMBLY__
+
+typedef union hubii_wid_u {
+	u64	wid_reg_value;
+	struct {
+		u64 	wid_rsvd: 	32,	/* unused */
+			wid_rev_num:	 4,	/* revision number */
+			wid_part_num:	16,	/* the widget type: hub=c101 */
+			wid_mfg_num:	11,	/* Manufacturer id (IBM) */
+			wid_rsvd1:	 1;	/* Reserved */
+        } wid_fields_s;
+} hubii_wid_t;
+
+
+typedef union hubii_wcr_u {
+	u64	wcr_reg_value;
+	struct {
+		u64 	wcr_rsvd: 	41,	/* unused */
+			wcr_e_thresh:	 5,	/* elasticity threshold */
+			wcr_dir_con:	 1,	/* widget direct connect */
+			wcr_f_bad_pkt:	 1,	/* Force bad llp pkt enable */
+			wcr_xbar_crd:	 3,	/* LLP crossbar credit */
+			wcr_rsvd1:	 8,	/* Reserved */
+			wcr_tag_mode:    1,	/* Tag mode */
+			wcr_widget_id:	 4;	/* LLP crossbar credit */
+        } wcr_fields_s;
+} hubii_wcr_t;
+
+#define	iwcr_dir_con	wcr_fields_s.wcr_dir_con
+
+typedef union hubii_wstat_u {
+	u64      reg_value;
+	struct {
+		u64	rsvd1:		31,
+			crazy:		 1,	/* Crazy bit		*/
+			rsvd2:		 8,
+			llp_tx_cnt:	 8, 	/* LLP Xmit retry counter */
+			rsvd3:		 6,
+			tx_max_rtry:	 1,	/* LLP Retry Timeout Signal */
+			rsvd4:		 2,
+			xt_tail_to:	 1,	/* Xtalk Tail Timeout	*/
+			xt_crd_to:	 1,	/* Xtalk Credit Timeout	*/
+			pending:	 4;	/* Pending Requests	*/
+	} wstat_fields_s;
+} hubii_wstat_t;
+
+
+typedef union hubii_ilcsr_u {
+	u64	icsr_reg_value;
+	struct {
+		u64 	icsr_rsvd: 	22,	/* unused */
+			icsr_max_burst:	10,	/* max burst */
+                        icsr_rsvd4:	 6,	/* reserved */
+			icsr_max_retry:	10,	/* max retry */
+                        icsr_rsvd3:	 2,	/* reserved */
+                        icsr_lnk_stat:	 2,	/* link status */
+                        icsr_bm8:	 1,	/* Bit mode 8 */
+                        icsr_llp_en:	 1,	/* LLP enable bit */
+			icsr_rsvd2:	 1,     /* reserver */
+                        icsr_wrm_reset:	 1,	/* Warm reset bit */
+			icsr_rsvd1:	 2,	/* Data ready offset */
+                        icsr_null_to:	 6;	/* Null timeout   */
+
+        } icsr_fields_s;
+} hubii_ilcsr_t;
+
+
+typedef union hubii_iowa_u {
+	u64	iowa_reg_value;
+	struct {
+		u64 	iowa_rsvd: 	48,	/* unused */
+			iowa_wxoac:	 8,	/* xtalk widget access bits */
+			iowa_rsvd1:	 7,	/* xtalk widget access bits */
+			iowa_w0oac:	 1;	/* xtalk widget access bits */
+        } iowa_fields_s;
+} hubii_iowa_t;
+
+typedef union hubii_iiwa_u {
+	u64	iiwa_reg_value;
+	struct {
+		u64 	iiwa_rsvd: 	48,	/* unused */
+			iiwa_wxiac:	 8,	/* hub wid access bits */
+			iiwa_rsvd1:	 7,	/* reserved */
+			iiwa_w0iac:	 1;	/* hub wid0 access */
+        } iiwa_fields_s;
+} hubii_iiwa_t;
+
+typedef union	hubii_illr_u {
+	u64	illr_reg_value;
+	struct {
+		u64 	illr_rsvd: 	32,	/* unused */
+			illr_cb_cnt:	16,	/* checkbit error count */
+			illr_sn_cnt:	16;	/* sequence number count */
+        } illr_fields_s;
+} hubii_illr_t;
+
+/* The structures below are defined to extract and modify the ii
+performance registers */
+
+/* io_perf_sel allows the caller to specify what tests will be
+   performed */
+typedef union io_perf_sel {
+	u64 perf_sel_reg;
+	struct {
+		u64 	perf_rsvd  : 48,
+			perf_icct  :  8,
+			perf_ippr1 :  4,
+			perf_ippr0 :  4;
+	} perf_sel_bits;
+} io_perf_sel_t;
+
+/* io_perf_cnt is to extract the count from the hub registers. Due to
+   hardware problems there is only one counter, not two. */
+
+typedef union io_perf_cnt {
+	u64	perf_cnt;
+	struct {
+		u64	perf_rsvd1 : 32,
+			perf_rsvd2 : 12,
+			perf_cnt   : 20;
+	} perf_cnt_bits;
+} io_perf_cnt_t;
+
+#endif /* !__ASSEMBLY__ */
+
+
+#define LNK_STAT_WORKING	0x2
+
+#define IIO_LLP_CB_MAX	0xffff
+#define IIO_LLP_SN_MAX	0xffff
+
+/* IO PRB Entries */
+#define	IIO_NUM_IPRBS	(9)
+#define IIO_IOPRB_0	0x400198	/* PRB entry 0 */
+#define IIO_IOPRB_8	0x4001a0	/* PRB entry 8 */
+#define IIO_IOPRB_9	0x4001a8	/* PRB entry 9 */
+#define IIO_IOPRB_A	0x4001b0	/* PRB entry a */
+#define IIO_IOPRB_B	0x4001b8	/* PRB entry b */
+#define IIO_IOPRB_C	0x4001c0	/* PRB entry c */
+#define IIO_IOPRB_D	0x4001c8	/* PRB entry d */
+#define IIO_IOPRB_E	0x4001d0	/* PRB entry e */
+#define IIO_IOPRB_F	0x4001d8	/* PRB entry f */
+
+
+#define IIO_IXCC	0x4001e0	/* Crosstalk credit count timeout */
+#define IIO_IXTCC	IIO_IXCC
+#define IIO_IMEM	0x4001e8	/* Miscellaneous Enable Mask */
+#define IIO_IXTT	0x4001f0	/* Crosstalk tail timeout */
+#define IIO_IECLR	0x4001f8	/* IO error clear */
+#define IIO_IBCN        0x400200        /* IO BTE CRB count */
+
+/*
+ * IIO_IMEM Register fields.
+ */
+#define IIO_IMEM_W0ESD  0x1             /* Widget 0 shut down due to error */
+#define IIO_IMEM_B0ESD  (1 << 4)        /* BTE 0 shut down due to error */
+#define IIO_IMEM_B1ESD  (1 << 8)        /* BTE 1 Shut down due to error */
+
+/* PIO Read address Table Entries */
+#define IIO_IPCA	0x400300	/* PRB Counter adjust */
+#define IIO_NUM_PRTES	8		/* Total number of PRB table entries */
+#define IIO_PRTE_0	0x400308	/* PIO Read address table entry 0 */
+#define IIO_PRTE(_x)	(IIO_PRTE_0 + (8 * (_x)))
+#define	IIO_WIDPRTE(x)	IIO_PRTE(((x) - 8)) /* widget ID to its PRTE num */
+#define IIO_IPDR	0x400388	/* PIO table entry deallocation */
+#define IIO_ICDR	0x400390	/* CRB Entry Deallocation */
+#define IIO_IFDR	0x400398	/* IOQ FIFO Depth */
+#define IIO_IIAP	0x4003a0	/* IIQ Arbitration Parameters */
+#define IIO_IMMR	IIO_IIAP
+#define IIO_ICMR	0x4003a8	/* CRB Management Register */
+#define IIO_ICCR	0x4003b0	/* CRB Control Register */
+#define IIO_ICTO	0x4003b8	/* CRB Time Out Register */
+#define IIO_ICTP	0x4003c0	/* CRB Time Out Prescalar */
+
+
+/*
+ * ICMR register fields
+ */
+#define IIO_ICMR_PC_VLD_SHFT	36
+#define IIO_ICMR_PC_VLD_MASK	(0x7fffUL << IIO_ICMR_PC_VLD_SHFT)
+
+#define IIO_ICMR_CRB_VLD_SHFT	20
+#define IIO_ICMR_CRB_VLD_MASK	(0x7fffUL << IIO_ICMR_CRB_VLD_SHFT)
+
+#define IIO_ICMR_FC_CNT_SHFT	16
+#define IIO_ICMR_FC_CNT_MASK	(0xf << IIO_ICMR_FC_CNT_SHFT)
+
+#define IIO_ICMR_C_CNT_SHFT	4
+#define IIO_ICMR_C_CNT_MASK	(0xf << IIO_ICMR_C_CNT_SHFT)
+
+#define IIO_ICMR_P_CNT_SHFT	0
+#define IIO_ICMR_P_CNT_MASK	(0xf << IIO_ICMR_P_CNT_SHFT)
+
+#define IIO_ICMR_PRECISE	(1UL << 52)
+#define IIO_ICMR_CLR_RPPD	(1UL << 13)
+#define IIO_ICMR_CLR_RQPD	(1UL << 12)
+
+/*
+ * IIO PIO Deallocation register field masks : (IIO_IPDR)
+ */
+#define	IIO_IPDR_PND	(1 << 4)
+
+/*
+ * IIO CRB deallocation register field masks: (IIO_ICDR)
+ */
+#define	IIO_ICDR_PND	(1 << 4)
+
+/*
+ * IIO CRB control register Fields: IIO_ICCR
+ */
+#define	IIO_ICCR_PENDING	(0x10000)
+#define	IIO_ICCR_CMD_MASK	(0xFF)
+#define	IIO_ICCR_CMD_SHFT	(7)
+#define	IIO_ICCR_CMD_NOP	(0x0)	/* No Op */
+#define	IIO_ICCR_CMD_WAKE	(0x100) /* Reactivate CRB entry and process */
+#define	IIO_ICCR_CMD_TIMEOUT	(0x200)	/* Make CRB timeout & mark invalid */
+#define	IIO_ICCR_CMD_EJECT	(0x400)	/* Contents of entry written to memory
+					 * via a WB
+					 */
+#define	IIO_ICCR_CMD_FLUSH	(0x800)
+
+/*
+ * CRB manipulation macros
+ *	The CRB macros are slightly complicated, since there are up to
+ * 	four registers associated with each CRB entry.
+ */
+#define IIO_NUM_CRBS		15	/* Number of CRBs */
+#define IIO_NUM_NORMAL_CRBS     12	/* Number of regular CRB entries */
+#define IIO_NUM_PC_CRBS 	4	/* Number of partial cache CRBs */
+#define IIO_ICRB_OFFSET		8
+#define IIO_ICRB_0		0x400400
+/* XXX - This is now tuneable:
+	#define IIO_FIRST_PC_ENTRY 12
+ */
+
+#define IIO_ICRB_A(_x)	(IIO_ICRB_0 + (4 * IIO_ICRB_OFFSET * (_x)))
+#define IIO_ICRB_B(_x)  (IIO_ICRB_A(_x) + 1*IIO_ICRB_OFFSET)
+#define IIO_ICRB_C(_x)	(IIO_ICRB_A(_x) + 2*IIO_ICRB_OFFSET)
+#define IIO_ICRB_D(_x)  (IIO_ICRB_A(_x) + 3*IIO_ICRB_OFFSET)
+
+/* XXX - IBUE register coming for Hub 2 */
+
+/*
+ *
+ * CRB Register description.
+ *
+ * WARNING * WARNING * WARNING * WARNING * WARNING * WARNING * WARNING
+ * WARNING * WARNING * WARNING * WARNING * WARNING * WARNING * WARNING
+ * WARNING * WARNING * WARNING * WARNING * WARNING * WARNING * WARNING
+ * WARNING * WARNING * WARNING * WARNING * WARNING * WARNING * WARNING
+ * WARNING * WARNING * WARNING * WARNING * WARNING * WARNING * WARNING
+ *
+ * Many of the fields in CRB are status bits used by hardware
+ * for implementation of the protocol. It's very dangerous to
+ * mess around with the CRB registers.
+ *
+ * It's OK to read the CRB registers and try to make sense out of the
+ * fields in CRB.
+ *
+ * Updating CRB requires all activities in Hub IIO to be quiesced.
+ * otherwise, a write to CRB could corrupt other CRB entries.
+ * CRBs are here only as a back door peek to hub IIO's status.
+ * Quiescing implies  no dmas no PIOs
+ * either directly from the cpu or from sn0net.
+ * this is not something that can be done easily. So, AVOID updating
+ * CRBs.
+ */
+
+/*
+ * Fields in CRB Register A
+ */
+#ifndef __ASSEMBLY__
+typedef union icrba_u {
+	u64	reg_value;
+	struct {
+		u64 	resvd: 	6,
+			stall_bte0: 1,	/* Stall BTE 0 */
+			stall_bte1: 1,	/* Stall BTE 1 */
+			error:	1,	/* CRB has an error	*/
+			ecode:	3,	/* Error Code 		*/
+			lnetuce: 1,	/* SN0net Uncorrectable error */
+			mark:	1,	/* CRB Has been marked 	*/
+			xerr:	1,	/* Error bit set in xtalk header */
+			sidn:	4,	/* SIDN field from xtalk	*/
+			tnum: 	5,	/* TNUM field in xtalk		*/
+			addr:	38,	/* Address of request	*/
+			valid:	1,	/* Valid status		*/
+			iow:	1;	/* IO Write operation	*/
+	} icrba_fields_s;
+} icrba_t;
+
+/* This is an alternate typedef for the HUB1 CRB A in order to allow
+   runtime selection of the format based on the REV_ID field of the
+   NI_STATUS_REV_ID register. */
+typedef union h1_icrba_u {
+	u64	reg_value;
+
+	struct {
+		u64 	resvd: 	6,
+			unused:	1,	/* Unused but RW!!	*/
+			error:	1,	/* CRB has an error	*/
+			ecode:	4,	/* Error Code 		*/
+			lnetuce: 1,	/* SN0net Uncorrectable error */
+			mark:	1,	/* CRB Has been marked 	*/
+			xerr:	1,	/* Error bit set in xtalk header */
+			sidn:	4,	/* SIDN field from xtalk	*/
+			tnum: 	5,	/* TNUM field in xtalk		*/
+			addr:	38,	/* Address of request	*/
+			valid:	1,	/* Valid status		*/
+			iow:	1;	/* IO Write operation	*/
+	} h1_icrba_fields_s;
+} h1_icrba_t;
+
+/* XXX - Is this still right?  Check the spec. */
+#define ICRBN_A_CERR_SHFT	54
+#define ICRBN_A_ERR_MASK	0x3ff
+
+#endif /* !__ASSEMBLY__ */
+
+#define	IIO_ICRB_ADDR_SHFT	2	/* Shift to get proper address */
+
+/*
+ * values for "ecode" field
+ */
+#define	IIO_ICRB_ECODE_DERR	0	/* Directory error due to IIO access */
+#define	IIO_ICRB_ECODE_PERR	1	/* Poison error on IO access */
+#define	IIO_ICRB_ECODE_WERR	2	/* Write error by IIO access
+					 * e.g. WINV to a Read only line.
+					 */
+#define	IIO_ICRB_ECODE_AERR	3	/* Access error caused by IIO access */
+#define	IIO_ICRB_ECODE_PWERR	4	/* Error on partial write	*/
+#define	IIO_ICRB_ECODE_PRERR	5	/* Error on partial read	*/
+#define	IIO_ICRB_ECODE_TOUT	6	/* CRB timeout before deallocating */
+#define	IIO_ICRB_ECODE_XTERR	7	/* Incoming xtalk pkt had error bit */
+
+
+
+/*
+ * Fields in CRB Register B
+ */
+#ifndef __ASSEMBLY__
+typedef union icrbb_u {
+	u64	reg_value;
+	struct {
+	    u64	rsvd1:	5,
+		btenum:	1,	/* BTE to which entry belongs to */
+		cohtrans: 1,	/* Coherent transaction	*/
+		xtsize:	2,	/* Xtalk operation size
+				 * 0: Double Word
+				 * 1: 32 Bytes.
+				 * 2: 128 Bytes,
+				 * 3: Reserved.
+				 */
+		srcnode: 9,	/* Source Node ID		*/
+		srcinit: 2,	/* Source Initiator:
+				 * See below for field values.
+				 */
+		useold:	1,	/* Use OLD command for processing */
+		imsgtype: 2,	/* Incoming message type
+				 * see below for field values
+				 */
+		imsg: 	8,	/* Incoming message 	*/
+		initator: 3,	/* Initiator of original request
+				 * See below for field values.
+				 */
+		reqtype: 5,	/* Identifies type of request
+				 * See below for field values.
+				 */
+		rsvd2:	7,
+		ackcnt:	11,	/* Invalidate ack count	*/
+		resp:	1,	/* data response  given to processor */
+		ack: 	1,	/* indicates data ack received 	*/
+		hold:	1,	/* entry is gathering inval acks */
+		wb_pend:1,	/* waiting for writeback to complete */
+		intvn: 	1,	/* Intervention */
+		stall_ib: 1,	/* Stall Ibuf (from crosstalk) */
+		stall_intr: 1;	/* Stall internal interrupts */
+	} icrbb_field_s;
+} icrbb_t;
+
+/* This is an alternate typedef for the HUB1 CRB B in order to allow
+   runtime selection of the format based on the REV_ID field of the
+   NI_STATUS_REV_ID register. */
+typedef union h1_icrbb_u {
+	u64	reg_value;
+	struct {
+		u64	rsvd1:	5,
+			btenum:	1,	/* BTE to which entry belongs to */
+			cohtrans: 1,	/* Coherent transaction	*/
+			xtsize:	2,	/* Xtalk operation size
+					 * 0: Double Word
+					 * 1: 32 Bytes.
+					 * 2: 128 Bytes,
+					 * 3: Reserved.
+					 */
+			srcnode: 9,	/* Source Node ID		*/
+			srcinit: 2,	/* Source Initiator:
+					 * See below for field values.
+					 */
+			useold:	1,	/* Use OLD command for processing */
+			imsgtype: 2,	/* Incoming message type
+					 * see below for field values
+					 */
+			imsg: 	8,	/* Incoming message 	*/
+			initator: 3,	/* Initiator of original request
+					 * See below for field values.
+					 */
+			rsvd2: 	1,
+			pcache: 1,	/* entry belongs to partial cache */
+			reqtype: 5,	/* Identifies type of request
+					 * See below for field values.
+					 */
+			stl_ib:	1,	/* stall Ibus coming from xtalk	*/
+			stl_intr: 1,	/* Stall internal interrupts */
+			stl_bte0: 1,	/* Stall BTE 0 	*/
+			stl_bte1: 1,	/* Stall BTE 1	*/
+			intrvn:	1,	/* Req was target of intervention */
+			ackcnt:	11,	/* Invalidate ack count	*/
+			resp:	1,	/* data response  given to processor */
+			ack: 	1,	/* indicates data ack received 	*/
+			hold:	1,	/* entry is gathering inval acks */
+			wb_pend:1,	/* waiting for writeback to complete */
+			sleep: 	1,	/* xtalk req sleeping till IO-sync */
+			pnd_reply: 1,	/* replies not issed due to IOQ full */
+			pnd_req: 1;	/* reqs not issued due to IOQ full */
+	} h1_icrbb_field_s;
+} h1_icrbb_t;
+
+
+#define	b_imsgtype	icrbb_field_s.imsgtype
+#define	b_btenum	icrbb_field_s.btenum
+#define	b_cohtrans	icrbb_field_s.cohtrans
+#define	b_xtsize	icrbb_field_s.xtsize
+#define	b_srcnode	icrbb_field_s.srcnode
+#define	b_srcinit	icrbb_field_s.srcinit
+#define	b_imsgtype	icrbb_field_s.imsgtype
+#define	b_imsg		icrbb_field_s.imsg
+#define	b_initiator	icrbb_field_s.initiator
+
+#endif /* !__ASSEMBLY__ */
+
+/*
+ * values for field xtsize
+ */
+#define	IIO_ICRB_XTSIZE_DW	0	/* Xtalk operation size is 8 bytes  */
+#define	IIO_ICRB_XTSIZE_32	1	/* Xtalk operation size is 32 bytes */
+#define	IIO_ICRB_XTSIZE_128	2	/* Xtalk operation size is 128 bytes */
+
+/*
+ * values for field srcinit
+ */
+#define	IIO_ICRB_PROC0		0	/* Source of request is Proc 0 */
+#define	IIO_ICRB_PROC1		1	/* Source of request is Proc 1 */
+#define	IIO_ICRB_GB_REQ		2	/* Source is Guranteed BW request */
+#define	IIO_ICRB_IO_REQ		3	/* Source is Normal IO request	*/
+
+/*
+ * Values for field imsgtype
+ */
+#define	IIO_ICRB_IMSGT_XTALK	0	/* Incoming Meessage from Xtalk	*/
+#define	IIO_ICRB_IMSGT_BTE	1	/* Incoming message from BTE 	*/
+#define	IIO_ICRB_IMSGT_SN0NET	2	/* Incoming message from SN0 net */
+#define	IIO_ICRB_IMSGT_CRB	3	/* Incoming message from CRB ???  */
+
+/*
+ * values for field initiator.
+ */
+#define	IIO_ICRB_INIT_XTALK	0	/* Message originated in xtalk	*/
+#define	IIO_ICRB_INIT_BTE0	0x1	/* Message originated in BTE 0	*/
+#define	IIO_ICRB_INIT_SN0NET	0x2	/* Message originated in SN0net */
+#define	IIO_ICRB_INIT_CRB	0x3	/* Message originated in CRB ? 	*/
+#define	IIO_ICRB_INIT_BTE1	0x5	/* MEssage originated in BTE 1	*/
+
+/*
+ * Values for field reqtype.
+ */
+/* XXX - Need to fix this for Hub 2 */
+#define	IIO_ICRB_REQ_DWRD	0	/* Request type double word	*/
+#define	IIO_ICRB_REQ_QCLRD	1	/* Request is Qrtr Caceh line Rd */
+#define	IIO_ICRB_REQ_BLKRD	2	/* Request is block read	*/
+#define	IIO_ICRB_REQ_RSHU	6	/* Request is BTE block read	*/
+#define	IIO_ICRB_REQ_REXU	7	/* request is BTE Excl Read	*/
+#define	IIO_ICRB_REQ_RDEX	8	/* Request is Read Exclusive	*/
+#define	IIO_ICRB_REQ_WINC	9	/* Request is Write Invalidate 	*/
+#define	IIO_ICRB_REQ_BWINV	10	/* Request is BTE Winv		*/
+#define	IIO_ICRB_REQ_PIORD	11	/* Request is PIO read		*/
+#define	IIO_ICRB_REQ_PIOWR	12	/* Request is PIO Write 	*/
+#define	IIO_ICRB_REQ_PRDM	13	/* Request is Fetch&Op		*/
+#define	IIO_ICRB_REQ_PWRM	14	/* Request is Store &Op		*/
+#define	IIO_ICRB_REQ_PTPWR	15	/* Request is Peer to peer	*/
+#define	IIO_ICRB_REQ_WB		16	/* Request is Write back	*/
+#define	IIO_ICRB_REQ_DEX	17	/* Retained DEX Cache line	*/
+
+/*
+ * Fields in CRB Register C
+ */
+
+#ifndef __ASSEMBLY__
+
+typedef union icrbc_s {
+	u64	reg_value;
+	struct {
+		u64	rsvd:	6,
+			sleep:	1,
+			pricnt: 4,	/* Priority count sent with Read req */
+			pripsc: 4,	/* Priority Pre scalar 	*/
+			bteop:	1,	/* BTE Operation 	*/
+			push_be: 34,	/* Push address Byte enable
+					 * Holds push addr, if CRB is for BTE
+					 * If CRB belongs to Partial cache,
+					 * this contains byte enables bits
+					 * ([47:46] = 0)
+					 */
+			suppl:	11,	/* Supplemental field	*/
+			barrop: 1,	/* Barrier Op bit set in xtalk req */
+			doresp: 1,	/* Xtalk req needs a response 	*/
+			gbr:	1;	/* GBR bit set in xtalk packet 	*/
+	} icrbc_field_s;
+} icrbc_t;
+
+#define	c_pricnt	icrbc_field_s.pricnt
+#define	c_pripsc	icrbc_field_s.pripsc
+#define	c_bteop		icrbc_field_s.bteop
+#define	c_bteaddr	icrbc_field_s.push_be	/* push_be field has 2 names */
+#define c_benable 	icrbc_field_s.push_be	/* push_be field has 2 names */
+#define	c_suppl		icrbc_field_s.suppl
+#define	c_barrop	icrbc_field_s.barrop
+#define	c_doresp	icrbc_field_s.doresp
+#define	c_gbr	icrbc_field_s.gbr
+#endif /* !__ASSEMBLY__ */
+
+/*
+ * Fields in CRB Register D
+ */
+
+#ifndef __ASSEMBLY__
+typedef union icrbd_s {
+	u64	reg_value;
+	struct {
+	    u64	rsvd:	38,
+		toutvld: 1,	/* Timeout in progress for this CRB */
+		ctxtvld: 1,	/* Context field below is valid	*/
+		rsvd2:	1,
+		context: 15, 	/* Bit vector:
+				 * Has a bit set for each CRB entry
+				 * which needs to be deallocated
+				 * before this CRB entry is processed.
+				 * Set only for barrier operations.
+				 */
+		timeout: 8;	/* Timeout Upper 8 bits	*/
+	} icrbd_field_s;
+} icrbd_t;
+
+#define	icrbd_toutvld	icrbd_field_s.toutvld
+#define	icrbd_ctxtvld	icrbd_field_s.ctxtvld
+#define	icrbd_context	icrbd_field_s.context
+
+
+typedef union hubii_ifdr_u {
+	u64	hi_ifdr_value;
+	struct {
+		u64	ifdr_rsvd:	49,
+	                ifdr_maxrp:	 7,
+	                ifdr_rsvd1:	 1,
+			ifdr_maxrq:	 7;
+	} hi_ifdr_fields;
+} hubii_ifdr_t;
+
+#endif /* !__ASSEMBLY__ */
+
+/*
+ * Hardware designed names for the BTE control registers.
+ */
+#define IIO_IBLS_0	0x410000	/* BTE length/status 0 */
+#define IIO_IBSA_0	0x410008	/* BTE source address 0 */
+#define IIO_IBDA_0	0x410010	/* BTE destination address 0 */
+#define IIO_IBCT_0	0x410018	/* BTE control/terminate 0 */
+#define IIO_IBNA_0	0x410020	/* BTE notification address 0 */
+#define IIO_IBNR_0	IIO_IBNA_0
+#define IIO_IBIA_0	0x410028	/* BTE interrupt address 0 */
+
+#define IIO_IBLS_1	0x420000	/* BTE length/status 1 */
+#define IIO_IBSA_1	0x420008	/* BTE source address 1 */
+#define IIO_IBDA_1	0x420010	/* BTE destination address 1 */
+#define IIO_IBCT_1	0x420018	/* BTE control/terminate 1 */
+#define IIO_IBNA_1	0x420020	/* BTE notification address 1 */
+#define IIO_IBNR_1	IIO_IBNA_1
+#define IIO_IBIA_1	0x420028	/* BTE interrupt address 1 */
+
+/*
+ * More miscellaneous registers
+ */
+#define IIO_IPCR	0x430000	/* Performance Control */
+#define IIO_IPPR	0x430008	/* Performance Profiling */
+
+/*
+ * IO Error Clear register bit field definitions
+ */
+#define IECLR_BTE1		(1 << 18)  /* clear bte error 1 ??? */
+#define IECLR_BTE0		(1 << 17)  /* clear bte error 0 ??? */
+#define IECLR_CRAZY		(1 << 16)  /* clear crazy bit in wstat reg */
+#define IECLR_PRB_F		(1 << 15)  /* clear err bit in PRB_F reg */
+#define IECLR_PRB_E		(1 << 14)  /* clear err bit in PRB_E reg */
+#define IECLR_PRB_D		(1 << 13)  /* clear err bit in PRB_D reg */
+#define IECLR_PRB_C		(1 << 12)  /* clear err bit in PRB_C reg */
+#define IECLR_PRB_B		(1 << 11)  /* clear err bit in PRB_B reg */
+#define IECLR_PRB_A		(1 << 10)  /* clear err bit in PRB_A reg */
+#define IECLR_PRB_9		(1 << 9)   /* clear err bit in PRB_9 reg */
+#define IECLR_PRB_8		(1 << 8)   /* clear err bit in PRB_8 reg */
+#define IECLR_PRB_0		(1 << 0)   /* clear err bit in PRB_0 reg */
+
+/*
+ * IO PIO Read Table Entry format
+ */
+
+#ifndef __ASSEMBLY__
+
+typedef union iprte_a {
+	u64	entry;
+	struct {
+	    u64	rsvd1     : 7,  /* Reserved field 		*/
+		valid     : 1,	/* Maps to a timeout entry	*/
+		rsvd2     : 1,
+		srcnode   : 9,	/* Node which did this PIO	*/
+		initiator : 2,	/* If T5A or T5B or IO 		*/
+		rsvd3     : 3,
+		addr      : 38,	/* Physical address of PIO	*/
+		rsvd4     : 3;
+	} iprte_fields;
+} iprte_a_t;
+
+#define	iprte_valid	iprte_fields.valid
+#define	iprte_timeout	iprte_fields.timeout
+#define	iprte_srcnode	iprte_fields.srcnode
+#define	iprte_init	iprte_fields.initiator
+#define	iprte_addr	iprte_fields.addr
+
+#endif /* !__ASSEMBLY__ */
+
+#define	IPRTE_ADDRSHFT	3
+
+/*
+ * Hub IIO PRB Register format.
+ */
+
+#ifndef __ASSEMBLY__
+/*
+ * Note: Fields bnakctr, anakctr, xtalkctrmode, ovflow fields are
+ * "Status" fields, and should only be used in case of clean up after errors.
+ */
+
+typedef union iprb_u {
+	u64	reg_value;
+	struct {
+	    u64	rsvd1:	15,
+		error:	1,	/* Widget rcvd wr resp pkt w/ error */
+		ovflow:	5,	/* Over flow count. perf measurement */
+		fire_and_forget: 1, /* Launch Write without response */
+		mode:	2,	/* Widget operation Mode	*/
+		rsvd2:	2,
+		bnakctr: 14,
+		rsvd3: 	2,
+		anakctr: 14,
+		xtalkctr: 8;
+	} iprb_fields_s;
+} iprb_t;
+
+#define iprb_regval	reg_value
+
+#define	iprb_error	iprb_fields_s.error
+#define	iprb_ovflow	iprb_fields_s.ovflow
+#define	iprb_ff		iprb_fields_s.fire_and_forget
+#define	iprb_mode	iprb_fields_s.mode
+#define	iprb_bnakctr	iprb_fields_s.bnakctr
+#define	iprb_anakctr	iprb_fields_s.anakctr
+#define	iprb_xtalkctr	iprb_fields_s.xtalkctr
+
+#endif /* !__ASSEMBLY__ */
+
+/*
+ * values for mode field in iprb_t.
+ * For details of the meanings of NAK and Accept, refer the PIO flow
+ * document
+ */
+#define	IPRB_MODE_NORMAL	(0)
+#define	IPRB_MODE_COLLECT_A	(1)	/* PRB in collect A mode */
+#define	IPRB_MODE_SERVICE_A	(2)	/* NAK B and Accept A */
+#define	IPRB_MODE_SERVICE_B	(3)	/* NAK A and Accept B */
+
+/*
+ * IO CRB entry C_A to E_A : Partial (cache) CRBS
+ */
+#ifndef __ASSEMBLY__
+typedef union icrbp_a {
+	u64   ip_reg;	    /* the entire register value	*/
+	struct {
+	     u64 error:	1,  /*    63, error occurred		*/
+		ln_uce:	1,  /*    62: uncorrectable memory 	*/
+		ln_ae:	1,  /*    61: protection violation 	*/
+		ln_werr:1,  /*    60: write access error 	*/
+		ln_aerr:1,  /*    59: sn0net: Address error	*/
+		ln_perr:1,  /*    58: sn0net: poison error	*/
+		timeout:1,  /*    57: CRB timed out		*/
+		l_bdpkt:1,  /*    56: truncated pkt on sn0net	*/
+		c_bdpkt:1,  /*    55: truncated pkt on xtalk	*/
+		c_err:	1,  /*    54: incoming xtalk req, err set*/
+		rsvd1: 12,  /* 53-42: reserved			*/
+		valid:	1,  /*    41: Valid status		*/
+		sidn:	4,  /* 40-37: SIDN field of xtalk rqst	*/
+		tnum:	5,  /* 36-32: TNUM of xtalk request	*/
+		bo:	1,  /*    31: barrier op set in xtalk rqst*/
+		resprqd:1,  /*    30: xtalk rqst requires response*/
+		gbr:	1,  /*    29: gbr bit set in xtalk rqst	*/
+		size:	2,  /* 28-27: size of xtalk request	*/
+		excl:	4,  /* 26-23: exclusive bit(s)		*/
+		stall:	3,  /* 22-20: stall (xtalk, bte 0/1)	*/
+		intvn:	1,  /*    19: rqst target of intervention*/
+		resp:	1,  /*    18: Data response given to t5	*/
+		ack:	1,  /*    17: Data ack received.	*/
+		hold:	1,  /*    16: crb gathering invalidate acks*/
+		wb:	1,  /*    15: writeback pending.	*/
+		ack_cnt:11, /* 14-04: counter of invalidate acks*/
+		tscaler:4;  /* 03-00: Timeout prescaler		*/
+	} ip_fmt;
+} icrbp_a_t;
+
+#endif /* !__ASSEMBLY__ */
+
+/*
+ * A couple of defines to go with the above structure.
+ */
+#define ICRBP_A_CERR_SHFT	54
+#define ICRBP_A_ERR_MASK	0x3ff
+
+#ifndef __ASSEMBLY__
+typedef union hubii_idsr {
+	u64 iin_reg;
+	struct {
+		u64 rsvd1 : 35,
+	            isent : 1,
+	            rsvd2 : 3,
+	            ienable: 1,
+	            rsvd  : 7,
+	            node  : 9,
+	            rsvd4 : 1,
+	            level : 7;
+	} iin_fmt;
+} hubii_idsr_t;
+#endif /* !__ASSEMBLY__ */
+
+/*
+ * IO BTE Length/Status (IIO_IBLS) register bit field definitions
+ */
+#define IBLS_BUSY		(0x1 << 20)
+#define IBLS_ERROR_SHFT		16
+#define IBLS_ERROR		(0x1 << IBLS_ERROR_SHFT)
+#define IBLS_LENGTH_MASK	0xffff
+
+/*
+ * IO BTE Control/Terminate register (IBCT) register bit field definitions
+ */
+#define IBCT_POISON		(0x1 << 8)
+#define IBCT_NOTIFY		(0x1 << 4)
+#define IBCT_ZFIL_MODE		(0x1 << 0)
+
+/*
+ * IO BTE Interrupt Address Register (IBIA) register bit field definitions
+ */
+#define IBIA_LEVEL_SHFT		16
+#define IBIA_LEVEL_MASK		(0x7f << IBIA_LEVEL_SHFT)
+#define IBIA_NODE_ID_SHFT	0
+#define IBIA_NODE_ID_MASK	(0x1ff)
+
+/*
+ * Miscellaneous hub constants
+ */
+
+/* Number of widgets supported by hub */
+#define HUB_NUM_WIDGET		9
+#define HUB_WIDGET_ID_MIN	0x8
+#define HUB_WIDGET_ID_MAX	0xf
+
+#define HUB_WIDGET_PART_NUM	0xc101
+#define MAX_HUBS_PER_XBOW	2
+
+/*
+ * Get a hub's widget id from widget control register
+ */
+#define IIO_WCR_WID_GET(nasid)	(REMOTE_HUB_L(nasid, III_WCR) & 0xf)
+#define IIO_WST_ERROR_MASK	(UINT64_CAST 1 << 32) /* Widget status error */
+
+/*
+ * Number of credits Hub widget has while sending req/response to
+ * xbow.
+ * Value of 3 is required by Xbow 1.1
+ * We may be able to increase this to 4 with Xbow 1.2.
+ */
+#define       HUBII_XBOW_CREDIT       3
+#define	      HUBII_XBOW_REV2_CREDIT  4
+
+#endif /* _ASM_SGI_SN_SN0_HUBIO_H */
diff --git a/include/asm-mips/sn/sn0/hubmd.h b/arch/mips/include/asm/sn/sn0/hubmd.h
similarity index 100%
rename from include/asm-mips/sn/sn0/hubmd.h
rename to arch/mips/include/asm/sn/sn0/hubmd.h
diff --git a/include/asm-mips/sn/sn0/hubni.h b/arch/mips/include/asm/sn/sn0/hubni.h
similarity index 100%
rename from include/asm-mips/sn/sn0/hubni.h
rename to arch/mips/include/asm/sn/sn0/hubni.h
diff --git a/include/asm-mips/sn/sn0/hubpi.h b/arch/mips/include/asm/sn/sn0/hubpi.h
similarity index 100%
rename from include/asm-mips/sn/sn0/hubpi.h
rename to arch/mips/include/asm/sn/sn0/hubpi.h
diff --git a/include/asm-mips/sn/sn0/ip27.h b/arch/mips/include/asm/sn/sn0/ip27.h
similarity index 100%
rename from include/asm-mips/sn/sn0/ip27.h
rename to arch/mips/include/asm/sn/sn0/ip27.h
diff --git a/include/asm-mips/sn/sn_private.h b/arch/mips/include/asm/sn/sn_private.h
similarity index 100%
rename from include/asm-mips/sn/sn_private.h
rename to arch/mips/include/asm/sn/sn_private.h
diff --git a/include/asm-mips/sn/types.h b/arch/mips/include/asm/sn/types.h
similarity index 100%
rename from include/asm-mips/sn/types.h
rename to arch/mips/include/asm/sn/types.h
diff --git a/include/asm-mips/sni.h b/arch/mips/include/asm/sni.h
similarity index 100%
rename from include/asm-mips/sni.h
rename to arch/mips/include/asm/sni.h
diff --git a/include/asm-mips/socket.h b/arch/mips/include/asm/socket.h
similarity index 100%
rename from include/asm-mips/socket.h
rename to arch/mips/include/asm/socket.h
diff --git a/include/asm-mips/sockios.h b/arch/mips/include/asm/sockios.h
similarity index 100%
rename from include/asm-mips/sockios.h
rename to arch/mips/include/asm/sockios.h
diff --git a/include/asm-mips/sparsemem.h b/arch/mips/include/asm/sparsemem.h
similarity index 100%
rename from include/asm-mips/sparsemem.h
rename to arch/mips/include/asm/sparsemem.h
diff --git a/arch/mips/include/asm/spinlock.h b/arch/mips/include/asm/spinlock.h
new file mode 100644
index 0000000..5d98a3c
--- /dev/null
+++ b/arch/mips/include/asm/spinlock.h
@@ -0,0 +1,487 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 1999, 2000, 06 Ralf Baechle (ralf@linux-mips.org)
+ * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
+ */
+#ifndef _ASM_SPINLOCK_H
+#define _ASM_SPINLOCK_H
+
+#include <linux/compiler.h>
+
+#include <asm/barrier.h>
+#include <asm/war.h>
+
+/*
+ * Your basic SMP spinlocks, allowing only a single CPU anywhere
+ *
+ * Simple spin lock operations.  There are two variants, one clears IRQ's
+ * on the local processor, one does not.
+ *
+ * These are fair FIFO ticket locks
+ *
+ * (the type definitions are in asm/spinlock_types.h)
+ */
+
+
+/*
+ * Ticket locks are conceptually two parts, one indicating the current head of
+ * the queue, and the other indicating the current tail. The lock is acquired
+ * by atomically noting the tail and incrementing it by one (thus adding
+ * ourself to the queue and noting our position), then waiting until the head
+ * becomes equal to the the initial value of the tail.
+ */
+
+static inline int __raw_spin_is_locked(raw_spinlock_t *lock)
+{
+	unsigned int counters = ACCESS_ONCE(lock->lock);
+
+	return ((counters >> 14) ^ counters) & 0x1fff;
+}
+
+#define __raw_spin_lock_flags(lock, flags) __raw_spin_lock(lock)
+#define __raw_spin_unlock_wait(x) \
+	while (__raw_spin_is_locked(x)) { cpu_relax(); }
+
+static inline int __raw_spin_is_contended(raw_spinlock_t *lock)
+{
+	unsigned int counters = ACCESS_ONCE(lock->lock);
+
+	return (((counters >> 14) - counters) & 0x1fff) > 1;
+}
+
+static inline void __raw_spin_lock(raw_spinlock_t *lock)
+{
+	int my_ticket;
+	int tmp;
+
+	if (R10000_LLSC_WAR) {
+		__asm__ __volatile__ (
+		"	.set push		# __raw_spin_lock	\n"
+		"	.set noreorder					\n"
+		"							\n"
+		"1:	ll	%[ticket], %[ticket_ptr]		\n"
+		"	addiu	%[my_ticket], %[ticket], 0x4000		\n"
+		"	sc	%[my_ticket], %[ticket_ptr]		\n"
+		"	beqzl	%[my_ticket], 1b			\n"
+		"	 nop						\n"
+		"	srl	%[my_ticket], %[ticket], 14		\n"
+		"	andi	%[my_ticket], %[my_ticket], 0x1fff	\n"
+		"	andi	%[ticket], %[ticket], 0x1fff		\n"
+		"	bne	%[ticket], %[my_ticket], 4f		\n"
+		"	 subu	%[ticket], %[my_ticket], %[ticket]	\n"
+		"2:							\n"
+		"	.subsection 2					\n"
+		"4:	andi	%[ticket], %[ticket], 0x1fff		\n"
+		"5:	sll	%[ticket], 5				\n"
+		"							\n"
+		"6:	bnez	%[ticket], 6b				\n"
+		"	 subu	%[ticket], 1				\n"
+		"							\n"
+		"	lw	%[ticket], %[ticket_ptr]		\n"
+		"	andi	%[ticket], %[ticket], 0x1fff		\n"
+		"	beq	%[ticket], %[my_ticket], 2b		\n"
+		"	 subu	%[ticket], %[my_ticket], %[ticket]	\n"
+		"	b	5b					\n"
+		"	 subu	%[ticket], %[ticket], 1			\n"
+		"	.previous					\n"
+		"	.set pop					\n"
+		: [ticket_ptr] "+m" (lock->lock),
+		  [ticket] "=&r" (tmp),
+		  [my_ticket] "=&r" (my_ticket));
+	} else {
+		__asm__ __volatile__ (
+		"	.set push		# __raw_spin_lock	\n"
+		"	.set noreorder					\n"
+		"							\n"
+		"	ll	%[ticket], %[ticket_ptr]		\n"
+		"1:	addiu	%[my_ticket], %[ticket], 0x4000		\n"
+		"	sc	%[my_ticket], %[ticket_ptr]		\n"
+		"	beqz	%[my_ticket], 3f			\n"
+		"	 nop						\n"
+		"	srl	%[my_ticket], %[ticket], 14		\n"
+		"	andi	%[my_ticket], %[my_ticket], 0x1fff	\n"
+		"	andi	%[ticket], %[ticket], 0x1fff		\n"
+		"	bne	%[ticket], %[my_ticket], 4f		\n"
+		"	 subu	%[ticket], %[my_ticket], %[ticket]	\n"
+		"2:							\n"
+		"	.subsection 2					\n"
+		"3:	b	1b					\n"
+		"	 ll	%[ticket], %[ticket_ptr]		\n"
+		"							\n"
+		"4:	andi	%[ticket], %[ticket], 0x1fff		\n"
+		"5:	sll	%[ticket], 5				\n"
+		"							\n"
+		"6:	bnez	%[ticket], 6b				\n"
+		"	 subu	%[ticket], 1				\n"
+		"							\n"
+		"	lw	%[ticket], %[ticket_ptr]		\n"
+		"	andi	%[ticket], %[ticket], 0x1fff		\n"
+		"	beq	%[ticket], %[my_ticket], 2b		\n"
+		"	 subu	%[ticket], %[my_ticket], %[ticket]	\n"
+		"	b	5b					\n"
+		"	 subu	%[ticket], %[ticket], 1			\n"
+		"	.previous					\n"
+		"	.set pop					\n"
+		: [ticket_ptr] "+m" (lock->lock),
+		  [ticket] "=&r" (tmp),
+		  [my_ticket] "=&r" (my_ticket));
+	}
+
+	smp_llsc_mb();
+}
+
+static inline void __raw_spin_unlock(raw_spinlock_t *lock)
+{
+	int tmp;
+
+	smp_llsc_mb();
+
+	if (R10000_LLSC_WAR) {
+		__asm__ __volatile__ (
+		"				# __raw_spin_unlock	\n"
+		"1:	ll	%[ticket], %[ticket_ptr]		\n"
+		"	addiu	%[ticket], %[ticket], 1			\n"
+		"	ori	%[ticket], %[ticket], 0x2000		\n"
+		"	xori	%[ticket], %[ticket], 0x2000		\n"
+		"	sc	%[ticket], %[ticket_ptr]		\n"
+		"	beqzl	%[ticket], 2f				\n"
+		: [ticket_ptr] "+m" (lock->lock),
+		  [ticket] "=&r" (tmp));
+	} else {
+		__asm__ __volatile__ (
+		"	.set push		# __raw_spin_unlock	\n"
+		"	.set noreorder					\n"
+		"							\n"
+		"	ll	%[ticket], %[ticket_ptr]		\n"
+		"1:	addiu	%[ticket], %[ticket], 1			\n"
+		"	ori	%[ticket], %[ticket], 0x2000		\n"
+		"	xori	%[ticket], %[ticket], 0x2000		\n"
+		"	sc	%[ticket], %[ticket_ptr]		\n"
+		"	beqz	%[ticket], 2f				\n"
+		"	 nop						\n"
+		"							\n"
+		"	.subsection 2					\n"
+		"2:	b	1b					\n"
+		"	 ll	%[ticket], %[ticket_ptr]		\n"
+		"	.previous					\n"
+		"	.set pop					\n"
+		: [ticket_ptr] "+m" (lock->lock),
+		  [ticket] "=&r" (tmp));
+	}
+}
+
+static inline unsigned int __raw_spin_trylock(raw_spinlock_t *lock)
+{
+	int tmp, tmp2, tmp3;
+
+	if (R10000_LLSC_WAR) {
+		__asm__ __volatile__ (
+		"	.set push		# __raw_spin_trylock	\n"
+		"	.set noreorder					\n"
+		"							\n"
+		"1:	ll	%[ticket], %[ticket_ptr]		\n"
+		"	srl	%[my_ticket], %[ticket], 14		\n"
+		"	andi	%[my_ticket], %[my_ticket], 0x1fff	\n"
+		"	andi	%[now_serving], %[ticket], 0x1fff	\n"
+		"	bne	%[my_ticket], %[now_serving], 3f	\n"
+		"	 addiu	%[ticket], %[ticket], 0x4000		\n"
+		"	sc	%[ticket], %[ticket_ptr]		\n"
+		"	beqzl	%[ticket], 1b				\n"
+		"	 li	%[ticket], 1				\n"
+		"2:							\n"
+		"	.subsection 2					\n"
+		"3:	b	2b					\n"
+		"	 li	%[ticket], 0				\n"
+		"	.previous					\n"
+		"	.set pop					\n"
+		: [ticket_ptr] "+m" (lock->lock),
+		  [ticket] "=&r" (tmp),
+		  [my_ticket] "=&r" (tmp2),
+		  [now_serving] "=&r" (tmp3));
+	} else {
+		__asm__ __volatile__ (
+		"	.set push		# __raw_spin_trylock	\n"
+		"	.set noreorder					\n"
+		"							\n"
+		"	ll	%[ticket], %[ticket_ptr]		\n"
+		"1:	srl	%[my_ticket], %[ticket], 14		\n"
+		"	andi	%[my_ticket], %[my_ticket], 0x1fff	\n"
+		"	andi	%[now_serving], %[ticket], 0x1fff	\n"
+		"	bne	%[my_ticket], %[now_serving], 3f	\n"
+		"	 addiu	%[ticket], %[ticket], 0x4000		\n"
+		"	sc	%[ticket], %[ticket_ptr]		\n"
+		"	beqz	%[ticket], 4f				\n"
+		"	 li	%[ticket], 1				\n"
+		"2:							\n"
+		"	.subsection 2					\n"
+		"3:	b	2b					\n"
+		"	 li	%[ticket], 0				\n"
+		"4:	b	1b					\n"
+		"	 ll	%[ticket], %[ticket_ptr]		\n"
+		"	.previous					\n"
+		"	.set pop					\n"
+		: [ticket_ptr] "+m" (lock->lock),
+		  [ticket] "=&r" (tmp),
+		  [my_ticket] "=&r" (tmp2),
+		  [now_serving] "=&r" (tmp3));
+	}
+
+	smp_llsc_mb();
+
+	return tmp;
+}
+
+/*
+ * Read-write spinlocks, allowing multiple readers but only one writer.
+ *
+ * NOTE! it is quite common to have readers in interrupts but no interrupt
+ * writers. For those circumstances we can "mix" irq-safe locks - any writer
+ * needs to get a irq-safe write-lock, but readers can get non-irqsafe
+ * read-locks.
+ */
+
+/*
+ * read_can_lock - would read_trylock() succeed?
+ * @lock: the rwlock in question.
+ */
+#define __raw_read_can_lock(rw)	((rw)->lock >= 0)
+
+/*
+ * write_can_lock - would write_trylock() succeed?
+ * @lock: the rwlock in question.
+ */
+#define __raw_write_can_lock(rw)	(!(rw)->lock)
+
+static inline void __raw_read_lock(raw_rwlock_t *rw)
+{
+	unsigned int tmp;
+
+	if (R10000_LLSC_WAR) {
+		__asm__ __volatile__(
+		"	.set	noreorder	# __raw_read_lock	\n"
+		"1:	ll	%1, %2					\n"
+		"	bltz	%1, 1b					\n"
+		"	 addu	%1, 1					\n"
+		"	sc	%1, %0					\n"
+		"	beqzl	%1, 1b					\n"
+		"	 nop						\n"
+		"	.set	reorder					\n"
+		: "=m" (rw->lock), "=&r" (tmp)
+		: "m" (rw->lock)
+		: "memory");
+	} else {
+		__asm__ __volatile__(
+		"	.set	noreorder	# __raw_read_lock	\n"
+		"1:	ll	%1, %2					\n"
+		"	bltz	%1, 2f					\n"
+		"	 addu	%1, 1					\n"
+		"	sc	%1, %0					\n"
+		"	beqz	%1, 1b					\n"
+		"	 nop						\n"
+		"	.subsection 2					\n"
+		"2:	ll	%1, %2					\n"
+		"	bltz	%1, 2b					\n"
+		"	 addu	%1, 1					\n"
+		"	b	1b					\n"
+		"	 nop						\n"
+		"	.previous					\n"
+		"	.set	reorder					\n"
+		: "=m" (rw->lock), "=&r" (tmp)
+		: "m" (rw->lock)
+		: "memory");
+	}
+
+	smp_llsc_mb();
+}
+
+/* Note the use of sub, not subu which will make the kernel die with an
+   overflow exception if we ever try to unlock an rwlock that is already
+   unlocked or is being held by a writer.  */
+static inline void __raw_read_unlock(raw_rwlock_t *rw)
+{
+	unsigned int tmp;
+
+	smp_llsc_mb();
+
+	if (R10000_LLSC_WAR) {
+		__asm__ __volatile__(
+		"1:	ll	%1, %2		# __raw_read_unlock	\n"
+		"	sub	%1, 1					\n"
+		"	sc	%1, %0					\n"
+		"	beqzl	%1, 1b					\n"
+		: "=m" (rw->lock), "=&r" (tmp)
+		: "m" (rw->lock)
+		: "memory");
+	} else {
+		__asm__ __volatile__(
+		"	.set	noreorder	# __raw_read_unlock	\n"
+		"1:	ll	%1, %2					\n"
+		"	sub	%1, 1					\n"
+		"	sc	%1, %0					\n"
+		"	beqz	%1, 2f					\n"
+		"	 nop						\n"
+		"	.subsection 2					\n"
+		"2:	b	1b					\n"
+		"	 nop						\n"
+		"	.previous					\n"
+		"	.set	reorder					\n"
+		: "=m" (rw->lock), "=&r" (tmp)
+		: "m" (rw->lock)
+		: "memory");
+	}
+}
+
+static inline void __raw_write_lock(raw_rwlock_t *rw)
+{
+	unsigned int tmp;
+
+	if (R10000_LLSC_WAR) {
+		__asm__ __volatile__(
+		"	.set	noreorder	# __raw_write_lock	\n"
+		"1:	ll	%1, %2					\n"
+		"	bnez	%1, 1b					\n"
+		"	 lui	%1, 0x8000				\n"
+		"	sc	%1, %0					\n"
+		"	beqzl	%1, 1b					\n"
+		"	 nop						\n"
+		"	.set	reorder					\n"
+		: "=m" (rw->lock), "=&r" (tmp)
+		: "m" (rw->lock)
+		: "memory");
+	} else {
+		__asm__ __volatile__(
+		"	.set	noreorder	# __raw_write_lock	\n"
+		"1:	ll	%1, %2					\n"
+		"	bnez	%1, 2f					\n"
+		"	 lui	%1, 0x8000				\n"
+		"	sc	%1, %0					\n"
+		"	beqz	%1, 2f					\n"
+		"	 nop						\n"
+		"	.subsection 2					\n"
+		"2:	ll	%1, %2					\n"
+		"	bnez	%1, 2b					\n"
+		"	 lui	%1, 0x8000				\n"
+		"	b	1b					\n"
+		"	 nop						\n"
+		"	.previous					\n"
+		"	.set	reorder					\n"
+		: "=m" (rw->lock), "=&r" (tmp)
+		: "m" (rw->lock)
+		: "memory");
+	}
+
+	smp_llsc_mb();
+}
+
+static inline void __raw_write_unlock(raw_rwlock_t *rw)
+{
+	smp_mb();
+
+	__asm__ __volatile__(
+	"				# __raw_write_unlock	\n"
+	"	sw	$0, %0					\n"
+	: "=m" (rw->lock)
+	: "m" (rw->lock)
+	: "memory");
+}
+
+static inline int __raw_read_trylock(raw_rwlock_t *rw)
+{
+	unsigned int tmp;
+	int ret;
+
+	if (R10000_LLSC_WAR) {
+		__asm__ __volatile__(
+		"	.set	noreorder	# __raw_read_trylock	\n"
+		"	li	%2, 0					\n"
+		"1:	ll	%1, %3					\n"
+		"	bltz	%1, 2f					\n"
+		"	 addu	%1, 1					\n"
+		"	sc	%1, %0					\n"
+		"	.set	reorder					\n"
+		"	beqzl	%1, 1b					\n"
+		"	 nop						\n"
+		__WEAK_LLSC_MB
+		"	li	%2, 1					\n"
+		"2:							\n"
+		: "=m" (rw->lock), "=&r" (tmp), "=&r" (ret)
+		: "m" (rw->lock)
+		: "memory");
+	} else {
+		__asm__ __volatile__(
+		"	.set	noreorder	# __raw_read_trylock	\n"
+		"	li	%2, 0					\n"
+		"1:	ll	%1, %3					\n"
+		"	bltz	%1, 2f					\n"
+		"	 addu	%1, 1					\n"
+		"	sc	%1, %0					\n"
+		"	beqz	%1, 1b					\n"
+		"	 nop						\n"
+		"	.set	reorder					\n"
+		__WEAK_LLSC_MB
+		"	li	%2, 1					\n"
+		"2:							\n"
+		: "=m" (rw->lock), "=&r" (tmp), "=&r" (ret)
+		: "m" (rw->lock)
+		: "memory");
+	}
+
+	return ret;
+}
+
+static inline int __raw_write_trylock(raw_rwlock_t *rw)
+{
+	unsigned int tmp;
+	int ret;
+
+	if (R10000_LLSC_WAR) {
+		__asm__ __volatile__(
+		"	.set	noreorder	# __raw_write_trylock	\n"
+		"	li	%2, 0					\n"
+		"1:	ll	%1, %3					\n"
+		"	bnez	%1, 2f					\n"
+		"	 lui	%1, 0x8000				\n"
+		"	sc	%1, %0					\n"
+		"	beqzl	%1, 1b					\n"
+		"	 nop						\n"
+		__WEAK_LLSC_MB
+		"	li	%2, 1					\n"
+		"	.set	reorder					\n"
+		"2:							\n"
+		: "=m" (rw->lock), "=&r" (tmp), "=&r" (ret)
+		: "m" (rw->lock)
+		: "memory");
+	} else {
+		__asm__ __volatile__(
+		"	.set	noreorder	# __raw_write_trylock	\n"
+		"	li	%2, 0					\n"
+		"1:	ll	%1, %3					\n"
+		"	bnez	%1, 2f					\n"
+		"	lui	%1, 0x8000				\n"
+		"	sc	%1, %0					\n"
+		"	beqz	%1, 3f					\n"
+		"	 li	%2, 1					\n"
+		"2:							\n"
+		__WEAK_LLSC_MB
+		"	.subsection 2					\n"
+		"3:	b	1b					\n"
+		"	 li	%2, 0					\n"
+		"	.previous					\n"
+		"	.set	reorder					\n"
+		: "=m" (rw->lock), "=&r" (tmp), "=&r" (ret)
+		: "m" (rw->lock)
+		: "memory");
+	}
+
+	return ret;
+}
+
+
+#define _raw_spin_relax(lock)	cpu_relax()
+#define _raw_read_relax(lock)	cpu_relax()
+#define _raw_write_relax(lock)	cpu_relax()
+
+#endif /* _ASM_SPINLOCK_H */
diff --git a/arch/mips/include/asm/spinlock_types.h b/arch/mips/include/asm/spinlock_types.h
new file mode 100644
index 0000000..adeedaa1
--- /dev/null
+++ b/arch/mips/include/asm/spinlock_types.h
@@ -0,0 +1,25 @@
+#ifndef _ASM_SPINLOCK_TYPES_H
+#define _ASM_SPINLOCK_TYPES_H
+
+#ifndef __LINUX_SPINLOCK_TYPES_H
+# error "please don't include this file directly"
+#endif
+
+typedef struct {
+	/*
+	 * bits  0..13: serving_now
+	 * bits 14    : junk data
+	 * bits 15..28: ticket
+	 */
+	unsigned int lock;
+} raw_spinlock_t;
+
+#define __RAW_SPIN_LOCK_UNLOCKED	{ 0 }
+
+typedef struct {
+	volatile unsigned int lock;
+} raw_rwlock_t;
+
+#define __RAW_RW_LOCK_UNLOCKED		{ 0 }
+
+#endif
diff --git a/arch/mips/include/asm/stackframe.h b/arch/mips/include/asm/stackframe.h
new file mode 100644
index 0000000..4c37c4e5
--- /dev/null
+++ b/arch/mips/include/asm/stackframe.h
@@ -0,0 +1,574 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 1994, 95, 96, 99, 2001 Ralf Baechle
+ * Copyright (C) 1994, 1995, 1996 Paul M. Antoine.
+ * Copyright (C) 1999 Silicon Graphics, Inc.
+ * Copyright (C) 2007  Maciej W. Rozycki
+ */
+#ifndef _ASM_STACKFRAME_H
+#define _ASM_STACKFRAME_H
+
+#include <linux/threads.h>
+
+#include <asm/asm.h>
+#include <asm/asmmacro.h>
+#include <asm/mipsregs.h>
+#include <asm/asm-offsets.h>
+
+/*
+ * For SMTC kernel, global IE should be left set, and interrupts
+ * controlled exclusively via IXMT.
+ */
+#ifdef CONFIG_MIPS_MT_SMTC
+#define STATMASK 0x1e
+#elif defined(CONFIG_CPU_R3000) || defined(CONFIG_CPU_TX39XX)
+#define STATMASK 0x3f
+#else
+#define STATMASK 0x1f
+#endif
+
+#ifdef CONFIG_MIPS_MT_SMTC
+#include <asm/mipsmtregs.h>
+#endif /* CONFIG_MIPS_MT_SMTC */
+
+		.macro	SAVE_AT
+		.set	push
+		.set	noat
+		LONG_S	$1, PT_R1(sp)
+		.set	pop
+		.endm
+
+		.macro	SAVE_TEMP
+#ifdef CONFIG_CPU_HAS_SMARTMIPS
+		mflhxu	v1
+		LONG_S	v1, PT_LO(sp)
+		mflhxu	v1
+		LONG_S	v1, PT_HI(sp)
+		mflhxu	v1
+		LONG_S	v1, PT_ACX(sp)
+#else
+		mfhi	v1
+		LONG_S	v1, PT_HI(sp)
+		mflo	v1
+		LONG_S	v1, PT_LO(sp)
+#endif
+#ifdef CONFIG_32BIT
+		LONG_S	$8, PT_R8(sp)
+		LONG_S	$9, PT_R9(sp)
+#endif
+		LONG_S	$10, PT_R10(sp)
+		LONG_S	$11, PT_R11(sp)
+		LONG_S	$12, PT_R12(sp)
+		LONG_S	$13, PT_R13(sp)
+		LONG_S	$14, PT_R14(sp)
+		LONG_S	$15, PT_R15(sp)
+		LONG_S	$24, PT_R24(sp)
+		.endm
+
+		.macro	SAVE_STATIC
+		LONG_S	$16, PT_R16(sp)
+		LONG_S	$17, PT_R17(sp)
+		LONG_S	$18, PT_R18(sp)
+		LONG_S	$19, PT_R19(sp)
+		LONG_S	$20, PT_R20(sp)
+		LONG_S	$21, PT_R21(sp)
+		LONG_S	$22, PT_R22(sp)
+		LONG_S	$23, PT_R23(sp)
+		LONG_S	$30, PT_R30(sp)
+		.endm
+
+#ifdef CONFIG_SMP
+#ifdef CONFIG_MIPS_MT_SMTC
+#define PTEBASE_SHIFT	19	/* TCBIND */
+#else
+#define PTEBASE_SHIFT	23	/* CONTEXT */
+#endif
+		.macro	get_saved_sp	/* SMP variation */
+#ifdef CONFIG_MIPS_MT_SMTC
+		mfc0	k0, CP0_TCBIND
+#else
+		MFC0	k0, CP0_CONTEXT
+#endif
+#if defined(CONFIG_32BIT) || defined(KBUILD_64BIT_SYM32)
+		lui	k1, %hi(kernelsp)
+#else
+		lui	k1, %highest(kernelsp)
+		daddiu	k1, %higher(kernelsp)
+		dsll	k1, 16
+		daddiu	k1, %hi(kernelsp)
+		dsll	k1, 16
+#endif
+		LONG_SRL	k0, PTEBASE_SHIFT
+		LONG_ADDU	k1, k0
+		LONG_L	k1, %lo(kernelsp)(k1)
+		.endm
+
+		.macro	set_saved_sp stackp temp temp2
+#ifdef CONFIG_MIPS_MT_SMTC
+		mfc0	\temp, CP0_TCBIND
+#else
+		MFC0	\temp, CP0_CONTEXT
+#endif
+		LONG_SRL	\temp, PTEBASE_SHIFT
+		LONG_S	\stackp, kernelsp(\temp)
+		.endm
+#else
+		.macro	get_saved_sp	/* Uniprocessor variation */
+#if defined(CONFIG_32BIT) || defined(KBUILD_64BIT_SYM32)
+		lui	k1, %hi(kernelsp)
+#else
+		lui	k1, %highest(kernelsp)
+		daddiu	k1, %higher(kernelsp)
+		dsll	k1, k1, 16
+		daddiu	k1, %hi(kernelsp)
+		dsll	k1, k1, 16
+#endif
+		LONG_L	k1, %lo(kernelsp)(k1)
+		.endm
+
+		.macro	set_saved_sp stackp temp temp2
+		LONG_S	\stackp, kernelsp
+		.endm
+#endif
+
+		.macro	SAVE_SOME
+		.set	push
+		.set	noat
+		.set	reorder
+		mfc0	k0, CP0_STATUS
+		sll	k0, 3		/* extract cu0 bit */
+		.set	noreorder
+		bltz	k0, 8f
+		 move	k1, sp
+		.set	reorder
+		/* Called from user mode, new stack. */
+		get_saved_sp
+#ifndef CONFIG_CPU_DADDI_WORKAROUNDS
+8:		move	k0, sp
+		PTR_SUBU sp, k1, PT_SIZE
+#else
+		.set	at=k0
+8:		PTR_SUBU k1, PT_SIZE
+		.set	noat
+		move	k0, sp
+		move	sp, k1
+#endif
+		LONG_S	k0, PT_R29(sp)
+		LONG_S	$3, PT_R3(sp)
+		/*
+		 * You might think that you don't need to save $0,
+		 * but the FPU emulator and gdb remote debug stub
+		 * need it to operate correctly
+		 */
+		LONG_S	$0, PT_R0(sp)
+		mfc0	v1, CP0_STATUS
+		LONG_S	$2, PT_R2(sp)
+		LONG_S	v1, PT_STATUS(sp)
+#ifdef CONFIG_MIPS_MT_SMTC
+		/*
+		 * Ideally, these instructions would be shuffled in
+		 * to cover the pipeline delay.
+		 */
+		.set	mips32
+		mfc0	v1, CP0_TCSTATUS
+		.set	mips0
+		LONG_S	v1, PT_TCSTATUS(sp)
+#endif /* CONFIG_MIPS_MT_SMTC */
+		LONG_S	$4, PT_R4(sp)
+		mfc0	v1, CP0_CAUSE
+		LONG_S	$5, PT_R5(sp)
+		LONG_S	v1, PT_CAUSE(sp)
+		LONG_S	$6, PT_R6(sp)
+		MFC0	v1, CP0_EPC
+		LONG_S	$7, PT_R7(sp)
+#ifdef CONFIG_64BIT
+		LONG_S	$8, PT_R8(sp)
+		LONG_S	$9, PT_R9(sp)
+#endif
+		LONG_S	v1, PT_EPC(sp)
+		LONG_S	$25, PT_R25(sp)
+		LONG_S	$28, PT_R28(sp)
+		LONG_S	$31, PT_R31(sp)
+		ori	$28, sp, _THREAD_MASK
+		xori	$28, _THREAD_MASK
+		.set	pop
+		.endm
+
+		.macro	SAVE_ALL
+		SAVE_SOME
+		SAVE_AT
+		SAVE_TEMP
+		SAVE_STATIC
+		.endm
+
+		.macro	RESTORE_AT
+		.set	push
+		.set	noat
+		LONG_L	$1,  PT_R1(sp)
+		.set	pop
+		.endm
+
+		.macro	RESTORE_TEMP
+#ifdef CONFIG_CPU_HAS_SMARTMIPS
+		LONG_L	$24, PT_ACX(sp)
+		mtlhx	$24
+		LONG_L	$24, PT_HI(sp)
+		mtlhx	$24
+		LONG_L	$24, PT_LO(sp)
+		mtlhx	$24
+#else
+		LONG_L	$24, PT_LO(sp)
+		mtlo	$24
+		LONG_L	$24, PT_HI(sp)
+		mthi	$24
+#endif
+#ifdef CONFIG_32BIT
+		LONG_L	$8, PT_R8(sp)
+		LONG_L	$9, PT_R9(sp)
+#endif
+		LONG_L	$10, PT_R10(sp)
+		LONG_L	$11, PT_R11(sp)
+		LONG_L	$12, PT_R12(sp)
+		LONG_L	$13, PT_R13(sp)
+		LONG_L	$14, PT_R14(sp)
+		LONG_L	$15, PT_R15(sp)
+		LONG_L	$24, PT_R24(sp)
+		.endm
+
+		.macro	RESTORE_STATIC
+		LONG_L	$16, PT_R16(sp)
+		LONG_L	$17, PT_R17(sp)
+		LONG_L	$18, PT_R18(sp)
+		LONG_L	$19, PT_R19(sp)
+		LONG_L	$20, PT_R20(sp)
+		LONG_L	$21, PT_R21(sp)
+		LONG_L	$22, PT_R22(sp)
+		LONG_L	$23, PT_R23(sp)
+		LONG_L	$30, PT_R30(sp)
+		.endm
+
+#if defined(CONFIG_CPU_R3000) || defined(CONFIG_CPU_TX39XX)
+
+		.macro	RESTORE_SOME
+		.set	push
+		.set	reorder
+		.set	noat
+		mfc0	a0, CP0_STATUS
+		li	v1, 0xff00
+		ori	a0, STATMASK
+		xori	a0, STATMASK
+		mtc0	a0, CP0_STATUS
+		and	a0, v1
+		LONG_L	v0, PT_STATUS(sp)
+		nor	v1, $0, v1
+		and	v0, v1
+		or	v0, a0
+		mtc0	v0, CP0_STATUS
+		LONG_L	$31, PT_R31(sp)
+		LONG_L	$28, PT_R28(sp)
+		LONG_L	$25, PT_R25(sp)
+		LONG_L	$7,  PT_R7(sp)
+		LONG_L	$6,  PT_R6(sp)
+		LONG_L	$5,  PT_R5(sp)
+		LONG_L	$4,  PT_R4(sp)
+		LONG_L	$3,  PT_R3(sp)
+		LONG_L	$2,  PT_R2(sp)
+		.set	pop
+		.endm
+
+		.macro	RESTORE_SP_AND_RET
+		.set	push
+		.set	noreorder
+		LONG_L	k0, PT_EPC(sp)
+		LONG_L	sp, PT_R29(sp)
+		jr	k0
+		 rfe
+		.set	pop
+		.endm
+
+#else
+		.macro	RESTORE_SOME
+		.set	push
+		.set	reorder
+		.set	noat
+#ifdef CONFIG_MIPS_MT_SMTC
+		.set	mips32r2
+		/*
+		 * We need to make sure the read-modify-write
+		 * of Status below isn't perturbed by an interrupt
+		 * or cross-TC access, so we need to do at least a DMT,
+		 * protected by an interrupt-inhibit. But setting IXMT
+		 * also creates a few-cycle window where an IPI could
+		 * be queued and not be detected before potentially
+		 * returning to a WAIT or user-mode loop. It must be
+		 * replayed.
+		 *
+		 * We're in the middle of a context switch, and
+		 * we can't dispatch it directly without trashing
+		 * some registers, so we'll try to detect this unlikely
+		 * case and program a software interrupt in the VPE,
+		 * as would be done for a cross-VPE IPI.  To accomodate
+		 * the handling of that case, we're doing a DVPE instead
+		 * of just a DMT here to protect against other threads.
+		 * This is a lot of cruft to cover a tiny window.
+		 * If you can find a better design, implement it!
+		 *
+		 */
+		mfc0	v0, CP0_TCSTATUS
+		ori	v0, TCSTATUS_IXMT
+		mtc0	v0, CP0_TCSTATUS
+		_ehb
+		DVPE	5				# dvpe a1
+		jal	mips_ihb
+#endif /* CONFIG_MIPS_MT_SMTC */
+		mfc0	a0, CP0_STATUS
+		ori	a0, STATMASK
+		xori	a0, STATMASK
+		mtc0	a0, CP0_STATUS
+		li	v1, 0xff00
+		and	a0, v1
+		LONG_L	v0, PT_STATUS(sp)
+		nor	v1, $0, v1
+		and	v0, v1
+		or	v0, a0
+		mtc0	v0, CP0_STATUS
+#ifdef CONFIG_MIPS_MT_SMTC
+/*
+ * Only after EXL/ERL have been restored to status can we
+ * restore TCStatus.IXMT.
+ */
+		LONG_L	v1, PT_TCSTATUS(sp)
+		_ehb
+		mfc0	a0, CP0_TCSTATUS
+		andi	v1, TCSTATUS_IXMT
+		bnez	v1, 0f
+
+/*
+ * We'd like to detect any IPIs queued in the tiny window
+ * above and request an software interrupt to service them
+ * when we ERET.
+ *
+ * Computing the offset into the IPIQ array of the executing
+ * TC's IPI queue in-line would be tedious.  We use part of
+ * the TCContext register to hold 16 bits of offset that we
+ * can add in-line to find the queue head.
+ */
+		mfc0	v0, CP0_TCCONTEXT
+		la	a2, IPIQ
+		srl	v0, v0, 16
+		addu	a2, a2, v0
+		LONG_L	v0, 0(a2)
+		beqz	v0, 0f
+/*
+ * If we have a queue, provoke dispatch within the VPE by setting C_SW1
+ */
+		mfc0	v0, CP0_CAUSE
+		ori	v0, v0, C_SW1
+		mtc0	v0, CP0_CAUSE
+0:
+		/*
+		 * This test should really never branch but
+		 * let's be prudent here.  Having atomized
+		 * the shared register modifications, we can
+		 * now EVPE, and must do so before interrupts
+		 * are potentially re-enabled.
+		 */
+		andi	a1, a1, MVPCONTROL_EVP
+		beqz	a1, 1f
+		evpe
+1:
+		/* We know that TCStatua.IXMT should be set from above */
+		xori	a0, a0, TCSTATUS_IXMT
+		or	a0, a0, v1
+		mtc0	a0, CP0_TCSTATUS
+		_ehb
+
+		.set	mips0
+#endif /* CONFIG_MIPS_MT_SMTC */
+		LONG_L	v1, PT_EPC(sp)
+		MTC0	v1, CP0_EPC
+		LONG_L	$31, PT_R31(sp)
+		LONG_L	$28, PT_R28(sp)
+		LONG_L	$25, PT_R25(sp)
+#ifdef CONFIG_64BIT
+		LONG_L	$8, PT_R8(sp)
+		LONG_L	$9, PT_R9(sp)
+#endif
+		LONG_L	$7,  PT_R7(sp)
+		LONG_L	$6,  PT_R6(sp)
+		LONG_L	$5,  PT_R5(sp)
+		LONG_L	$4,  PT_R4(sp)
+		LONG_L	$3,  PT_R3(sp)
+		LONG_L	$2,  PT_R2(sp)
+		.set	pop
+		.endm
+
+		.macro	RESTORE_SP_AND_RET
+		LONG_L	sp, PT_R29(sp)
+		.set	mips3
+		eret
+		.set	mips0
+		.endm
+
+#endif
+
+		.macro	RESTORE_SP
+		LONG_L	sp, PT_R29(sp)
+		.endm
+
+		.macro	RESTORE_ALL
+		RESTORE_TEMP
+		RESTORE_STATIC
+		RESTORE_AT
+		RESTORE_SOME
+		RESTORE_SP
+		.endm
+
+		.macro	RESTORE_ALL_AND_RET
+		RESTORE_TEMP
+		RESTORE_STATIC
+		RESTORE_AT
+		RESTORE_SOME
+		RESTORE_SP_AND_RET
+		.endm
+
+/*
+ * Move to kernel mode and disable interrupts.
+ * Set cp0 enable bit as sign that we're running on the kernel stack
+ */
+		.macro	CLI
+#if !defined(CONFIG_MIPS_MT_SMTC)
+		mfc0	t0, CP0_STATUS
+		li	t1, ST0_CU0 | STATMASK
+		or	t0, t1
+		xori	t0, STATMASK
+		mtc0	t0, CP0_STATUS
+#else /* CONFIG_MIPS_MT_SMTC */
+		/*
+		 * For SMTC, we need to set privilege
+		 * and disable interrupts only for the
+		 * current TC, using the TCStatus register.
+		 */
+		mfc0	t0, CP0_TCSTATUS
+		/* Fortunately CU 0 is in the same place in both registers */
+		/* Set TCU0, TMX, TKSU (for later inversion) and IXMT */
+		li	t1, ST0_CU0 | 0x08001c00
+		or	t0, t1
+		/* Clear TKSU, leave IXMT */
+		xori	t0, 0x00001800
+		mtc0	t0, CP0_TCSTATUS
+		_ehb
+		/* We need to leave the global IE bit set, but clear EXL...*/
+		mfc0	t0, CP0_STATUS
+		ori	t0, ST0_EXL | ST0_ERL
+		xori	t0, ST0_EXL | ST0_ERL
+		mtc0	t0, CP0_STATUS
+#endif /* CONFIG_MIPS_MT_SMTC */
+		irq_disable_hazard
+		.endm
+
+/*
+ * Move to kernel mode and enable interrupts.
+ * Set cp0 enable bit as sign that we're running on the kernel stack
+ */
+		.macro	STI
+#if !defined(CONFIG_MIPS_MT_SMTC)
+		mfc0	t0, CP0_STATUS
+		li	t1, ST0_CU0 | STATMASK
+		or	t0, t1
+		xori	t0, STATMASK & ~1
+		mtc0	t0, CP0_STATUS
+#else /* CONFIG_MIPS_MT_SMTC */
+		/*
+		 * For SMTC, we need to set privilege
+		 * and enable interrupts only for the
+		 * current TC, using the TCStatus register.
+		 */
+		_ehb
+		mfc0	t0, CP0_TCSTATUS
+		/* Fortunately CU 0 is in the same place in both registers */
+		/* Set TCU0, TKSU (for later inversion) and IXMT */
+		li	t1, ST0_CU0 | 0x08001c00
+		or	t0, t1
+		/* Clear TKSU *and* IXMT */
+		xori	t0, 0x00001c00
+		mtc0	t0, CP0_TCSTATUS
+		_ehb
+		/* We need to leave the global IE bit set, but clear EXL...*/
+		mfc0	t0, CP0_STATUS
+		ori	t0, ST0_EXL
+		xori	t0, ST0_EXL
+		mtc0	t0, CP0_STATUS
+		/* irq_enable_hazard below should expand to EHB for 24K/34K cpus */
+#endif /* CONFIG_MIPS_MT_SMTC */
+		irq_enable_hazard
+		.endm
+
+/*
+ * Just move to kernel mode and leave interrupts as they are.  Note
+ * for the R3000 this means copying the previous enable from IEp.
+ * Set cp0 enable bit as sign that we're running on the kernel stack
+ */
+		.macro	KMODE
+#ifdef CONFIG_MIPS_MT_SMTC
+		/*
+		 * This gets baroque in SMTC.  We want to
+		 * protect the non-atomic clearing of EXL
+		 * with DMT/EMT, but we don't want to take
+		 * an interrupt while DMT is still in effect.
+		 */
+
+		/* KMODE gets invoked from both reorder and noreorder code */
+		.set	push
+		.set	mips32r2
+		.set	noreorder
+		mfc0	v0, CP0_TCSTATUS
+		andi	v1, v0, TCSTATUS_IXMT
+		ori	v0, TCSTATUS_IXMT
+		mtc0	v0, CP0_TCSTATUS
+		_ehb
+		DMT	2				# dmt	v0
+		/*
+		 * We don't know a priori if ra is "live"
+		 */
+		move	t0, ra
+		jal	mips_ihb
+		nop	/* delay slot */
+		move	ra, t0
+#endif /* CONFIG_MIPS_MT_SMTC */
+		mfc0	t0, CP0_STATUS
+		li	t1, ST0_CU0 | (STATMASK & ~1)
+#if defined(CONFIG_CPU_R3000) || defined(CONFIG_CPU_TX39XX)
+		andi	t2, t0, ST0_IEP
+		srl	t2, 2
+		or	t0, t2
+#endif
+		or	t0, t1
+		xori	t0, STATMASK & ~1
+		mtc0	t0, CP0_STATUS
+#ifdef CONFIG_MIPS_MT_SMTC
+		_ehb
+		andi	v0, v0, VPECONTROL_TE
+		beqz	v0, 2f
+		nop	/* delay slot */
+		emt
+2:
+		mfc0	v0, CP0_TCSTATUS
+		/* Clear IXMT, then OR in previous value */
+		ori	v0, TCSTATUS_IXMT
+		xori	v0, TCSTATUS_IXMT
+		or	v0, v1, v0
+		mtc0	v0, CP0_TCSTATUS
+		/*
+		 * irq_disable_hazard below should expand to EHB
+		 * on 24K/34K CPUS
+		 */
+		.set pop
+#endif /* CONFIG_MIPS_MT_SMTC */
+		irq_disable_hazard
+		.endm
+
+#endif /* _ASM_STACKFRAME_H */
diff --git a/include/asm-mips/stacktrace.h b/arch/mips/include/asm/stacktrace.h
similarity index 100%
rename from include/asm-mips/stacktrace.h
rename to arch/mips/include/asm/stacktrace.h
diff --git a/include/asm-mips/stat.h b/arch/mips/include/asm/stat.h
similarity index 100%
rename from include/asm-mips/stat.h
rename to arch/mips/include/asm/stat.h
diff --git a/include/asm-mips/statfs.h b/arch/mips/include/asm/statfs.h
similarity index 100%
rename from include/asm-mips/statfs.h
rename to arch/mips/include/asm/statfs.h
diff --git a/include/asm-mips/string.h b/arch/mips/include/asm/string.h
similarity index 100%
rename from include/asm-mips/string.h
rename to arch/mips/include/asm/string.h
diff --git a/include/asm-mips/suspend.h b/arch/mips/include/asm/suspend.h
similarity index 100%
rename from include/asm-mips/suspend.h
rename to arch/mips/include/asm/suspend.h
diff --git a/include/asm-mips/sysmips.h b/arch/mips/include/asm/sysmips.h
similarity index 100%
rename from include/asm-mips/sysmips.h
rename to arch/mips/include/asm/sysmips.h
diff --git a/arch/mips/include/asm/system.h b/arch/mips/include/asm/system.h
new file mode 100644
index 0000000..cd30f83
--- /dev/null
+++ b/arch/mips/include/asm/system.h
@@ -0,0 +1,222 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 1994, 95, 96, 97, 98, 99, 2003, 06 by Ralf Baechle
+ * Copyright (C) 1996 by Paul M. Antoine
+ * Copyright (C) 1999 Silicon Graphics
+ * Kevin D. Kissell, kevink@mips.org and Carsten Langgaard, carstenl@mips.com
+ * Copyright (C) 2000 MIPS Technologies, Inc.
+ */
+#ifndef _ASM_SYSTEM_H
+#define _ASM_SYSTEM_H
+
+#include <linux/types.h>
+#include <linux/irqflags.h>
+
+#include <asm/addrspace.h>
+#include <asm/barrier.h>
+#include <asm/cmpxchg.h>
+#include <asm/cpu-features.h>
+#include <asm/dsp.h>
+#include <asm/watch.h>
+#include <asm/war.h>
+
+
+/*
+ * switch_to(n) should switch tasks to task nr n, first
+ * checking that n isn't the current task, in which case it does nothing.
+ */
+extern asmlinkage void *resume(void *last, void *next, void *next_ti);
+
+struct task_struct;
+
+#ifdef CONFIG_MIPS_MT_FPAFF
+
+/*
+ * Handle the scheduler resume end of FPU affinity management.  We do this
+ * inline to try to keep the overhead down. If we have been forced to run on
+ * a "CPU" with an FPU because of a previous high level of FP computation,
+ * but did not actually use the FPU during the most recent time-slice (CU1
+ * isn't set), we undo the restriction on cpus_allowed.
+ *
+ * We're not calling set_cpus_allowed() here, because we have no need to
+ * force prompt migration - we're already switching the current CPU to a
+ * different thread.
+ */
+
+#define __mips_mt_fpaff_switch_to(prev)					\
+do {									\
+	struct thread_info *__prev_ti = task_thread_info(prev);		\
+									\
+	if (cpu_has_fpu &&						\
+	    test_ti_thread_flag(__prev_ti, TIF_FPUBOUND) &&		\
+	    (!(KSTK_STATUS(prev) & ST0_CU1))) {				\
+		clear_ti_thread_flag(__prev_ti, TIF_FPUBOUND);		\
+		prev->cpus_allowed = prev->thread.user_cpus_allowed;	\
+	}								\
+	next->thread.emulated_fp = 0;					\
+} while(0)
+
+#else
+#define __mips_mt_fpaff_switch_to(prev) do { (void) (prev); } while (0)
+#endif
+
+#define switch_to(prev, next, last)					\
+do {									\
+	__mips_mt_fpaff_switch_to(prev);				\
+	if (cpu_has_dsp)						\
+		__save_dsp(prev);					\
+	(last) = resume(prev, next, task_thread_info(next));		\
+} while (0)
+
+#define finish_arch_switch(prev)					\
+do {									\
+	if (cpu_has_dsp)						\
+		__restore_dsp(current);					\
+	if (cpu_has_userlocal)						\
+		write_c0_userlocal(current_thread_info()->tp_value);	\
+	__restore_watch();						\
+} while (0)
+
+static inline unsigned long __xchg_u32(volatile int * m, unsigned int val)
+{
+	__u32 retval;
+
+	if (cpu_has_llsc && R10000_LLSC_WAR) {
+		unsigned long dummy;
+
+		__asm__ __volatile__(
+		"	.set	mips3					\n"
+		"1:	ll	%0, %3			# xchg_u32	\n"
+		"	.set	mips0					\n"
+		"	move	%2, %z4					\n"
+		"	.set	mips3					\n"
+		"	sc	%2, %1					\n"
+		"	beqzl	%2, 1b					\n"
+		"	.set	mips0					\n"
+		: "=&r" (retval), "=m" (*m), "=&r" (dummy)
+		: "R" (*m), "Jr" (val)
+		: "memory");
+	} else if (cpu_has_llsc) {
+		unsigned long dummy;
+
+		__asm__ __volatile__(
+		"	.set	mips3					\n"
+		"1:	ll	%0, %3			# xchg_u32	\n"
+		"	.set	mips0					\n"
+		"	move	%2, %z4					\n"
+		"	.set	mips3					\n"
+		"	sc	%2, %1					\n"
+		"	beqz	%2, 2f					\n"
+		"	.subsection 2					\n"
+		"2:	b	1b					\n"
+		"	.previous					\n"
+		"	.set	mips0					\n"
+		: "=&r" (retval), "=m" (*m), "=&r" (dummy)
+		: "R" (*m), "Jr" (val)
+		: "memory");
+	} else {
+		unsigned long flags;
+
+		raw_local_irq_save(flags);
+		retval = *m;
+		*m = val;
+		raw_local_irq_restore(flags);	/* implies memory barrier  */
+	}
+
+	smp_llsc_mb();
+
+	return retval;
+}
+
+#ifdef CONFIG_64BIT
+static inline __u64 __xchg_u64(volatile __u64 * m, __u64 val)
+{
+	__u64 retval;
+
+	if (cpu_has_llsc && R10000_LLSC_WAR) {
+		unsigned long dummy;
+
+		__asm__ __volatile__(
+		"	.set	mips3					\n"
+		"1:	lld	%0, %3			# xchg_u64	\n"
+		"	move	%2, %z4					\n"
+		"	scd	%2, %1					\n"
+		"	beqzl	%2, 1b					\n"
+		"	.set	mips0					\n"
+		: "=&r" (retval), "=m" (*m), "=&r" (dummy)
+		: "R" (*m), "Jr" (val)
+		: "memory");
+	} else if (cpu_has_llsc) {
+		unsigned long dummy;
+
+		__asm__ __volatile__(
+		"	.set	mips3					\n"
+		"1:	lld	%0, %3			# xchg_u64	\n"
+		"	move	%2, %z4					\n"
+		"	scd	%2, %1					\n"
+		"	beqz	%2, 2f					\n"
+		"	.subsection 2					\n"
+		"2:	b	1b					\n"
+		"	.previous					\n"
+		"	.set	mips0					\n"
+		: "=&r" (retval), "=m" (*m), "=&r" (dummy)
+		: "R" (*m), "Jr" (val)
+		: "memory");
+	} else {
+		unsigned long flags;
+
+		raw_local_irq_save(flags);
+		retval = *m;
+		*m = val;
+		raw_local_irq_restore(flags);	/* implies memory barrier  */
+	}
+
+	smp_llsc_mb();
+
+	return retval;
+}
+#else
+extern __u64 __xchg_u64_unsupported_on_32bit_kernels(volatile __u64 * m, __u64 val);
+#define __xchg_u64 __xchg_u64_unsupported_on_32bit_kernels
+#endif
+
+/* This function doesn't exist, so you'll get a linker error
+   if something tries to do an invalid xchg().  */
+extern void __xchg_called_with_bad_pointer(void);
+
+static inline unsigned long __xchg(unsigned long x, volatile void * ptr, int size)
+{
+	switch (size) {
+	case 4:
+		return __xchg_u32(ptr, x);
+	case 8:
+		return __xchg_u64(ptr, x);
+	}
+	__xchg_called_with_bad_pointer();
+	return x;
+}
+
+#define xchg(ptr, x) ((__typeof__(*(ptr)))__xchg((unsigned long)(x), (ptr), sizeof(*(ptr))))
+
+extern void set_handler(unsigned long offset, void *addr, unsigned long len);
+extern void set_uncached_handler(unsigned long offset, void *addr, unsigned long len);
+
+typedef void (*vi_handler_t)(void);
+extern void *set_vi_handler(int n, vi_handler_t addr);
+
+extern void *set_except_vector(int n, void *addr);
+extern unsigned long ebase;
+extern void per_cpu_trap_init(void);
+
+/*
+ * See include/asm-ia64/system.h; prevents deadlock on SMP
+ * systems.
+ */
+#define __ARCH_WANT_UNLOCKED_CTXSW
+
+extern unsigned long arch_align_stack(unsigned long sp);
+
+#endif /* _ASM_SYSTEM_H */
diff --git a/include/asm-mips/termbits.h b/arch/mips/include/asm/termbits.h
similarity index 100%
rename from include/asm-mips/termbits.h
rename to arch/mips/include/asm/termbits.h
diff --git a/include/asm-mips/termios.h b/arch/mips/include/asm/termios.h
similarity index 100%
rename from include/asm-mips/termios.h
rename to arch/mips/include/asm/termios.h
diff --git a/arch/mips/include/asm/thread_info.h b/arch/mips/include/asm/thread_info.h
new file mode 100644
index 0000000..3f76de7
--- /dev/null
+++ b/arch/mips/include/asm/thread_info.h
@@ -0,0 +1,153 @@
+/* thread_info.h: MIPS low-level thread information
+ *
+ * Copyright (C) 2002  David Howells (dhowells@redhat.com)
+ * - Incorporating suggestions made by Linus Torvalds and Dave Miller
+ */
+
+#ifndef _ASM_THREAD_INFO_H
+#define _ASM_THREAD_INFO_H
+
+#ifdef __KERNEL__
+
+
+#ifndef __ASSEMBLY__
+
+#include <asm/processor.h>
+
+/*
+ * low level task data that entry.S needs immediate access to
+ * - this struct should fit entirely inside of one cache line
+ * - this struct shares the supervisor stack pages
+ * - if the contents of this structure are changed, the assembly constants
+ *   must also be changed
+ */
+struct thread_info {
+	struct task_struct	*task;		/* main task structure */
+	struct exec_domain	*exec_domain;	/* execution domain */
+	unsigned long		flags;		/* low level flags */
+	unsigned long		tp_value;	/* thread pointer */
+	__u32			cpu;		/* current CPU */
+	int			preempt_count;	/* 0 => preemptable, <0 => BUG */
+
+	mm_segment_t		addr_limit;	/* thread address space:
+						   0-0xBFFFFFFF for user-thead
+						   0-0xFFFFFFFF for kernel-thread
+						*/
+	struct restart_block	restart_block;
+	struct pt_regs		*regs;
+};
+
+/*
+ * macros/functions for gaining access to the thread information structure
+ *
+ * preempt_count needs to be 1 initially, until the scheduler is functional.
+ */
+#define INIT_THREAD_INFO(tsk)			\
+{						\
+	.task		= &tsk,			\
+	.exec_domain	= &default_exec_domain,	\
+	.flags		= _TIF_FIXADE,		\
+	.cpu		= 0,			\
+	.preempt_count	= 1,			\
+	.addr_limit	= KERNEL_DS,		\
+	.restart_block	= {			\
+		.fn = do_no_restart_syscall,	\
+	},					\
+}
+
+#define init_thread_info	(init_thread_union.thread_info)
+#define init_stack		(init_thread_union.stack)
+
+/* How to get the thread information struct from C.  */
+register struct thread_info *__current_thread_info __asm__("$28");
+#define current_thread_info()  __current_thread_info
+
+/* thread information allocation */
+#if defined(CONFIG_PAGE_SIZE_4KB) && defined(CONFIG_32BIT)
+#define THREAD_SIZE_ORDER (1)
+#endif
+#if defined(CONFIG_PAGE_SIZE_4KB) && defined(CONFIG_64BIT)
+#define THREAD_SIZE_ORDER (2)
+#endif
+#ifdef CONFIG_PAGE_SIZE_8KB
+#define THREAD_SIZE_ORDER (1)
+#endif
+#ifdef CONFIG_PAGE_SIZE_16KB
+#define THREAD_SIZE_ORDER (0)
+#endif
+#ifdef CONFIG_PAGE_SIZE_64KB
+#define THREAD_SIZE_ORDER (0)
+#endif
+
+#define THREAD_SIZE (PAGE_SIZE << THREAD_SIZE_ORDER)
+#define THREAD_MASK (THREAD_SIZE - 1UL)
+
+#define __HAVE_ARCH_THREAD_INFO_ALLOCATOR
+
+#ifdef CONFIG_DEBUG_STACK_USAGE
+#define alloc_thread_info(tsk)					\
+({								\
+	struct thread_info *ret;				\
+								\
+	ret = kzalloc(THREAD_SIZE, GFP_KERNEL);			\
+								\
+	ret;							\
+})
+#else
+#define alloc_thread_info(tsk) kmalloc(THREAD_SIZE, GFP_KERNEL)
+#endif
+
+#define free_thread_info(info) kfree(info)
+
+#endif /* !__ASSEMBLY__ */
+
+#define PREEMPT_ACTIVE		0x10000000
+
+/*
+ * thread information flags
+ * - these are process state flags that various assembly files may need to
+ *   access
+ * - pending work-to-be-done flags are in LSW
+ * - other flags in MSW
+ */
+#define TIF_SIGPENDING		1	/* signal pending */
+#define TIF_NEED_RESCHED	2	/* rescheduling necessary */
+#define TIF_SYSCALL_AUDIT	3	/* syscall auditing active */
+#define TIF_SECCOMP		4	/* secure computing */
+#define TIF_RESTORE_SIGMASK	9	/* restore signal mask in do_signal() */
+#define TIF_USEDFPU		16	/* FPU was used by this task this quantum (SMP) */
+#define TIF_POLLING_NRFLAG	17	/* true if poll_idle() is polling TIF_NEED_RESCHED */
+#define TIF_MEMDIE		18
+#define TIF_FREEZE		19
+#define TIF_FIXADE		20	/* Fix address errors in software */
+#define TIF_LOGADE		21	/* Log address errors to syslog */
+#define TIF_32BIT_REGS		22	/* also implies 16/32 fprs */
+#define TIF_32BIT_ADDR		23	/* 32-bit address space (o32/n32) */
+#define TIF_FPUBOUND		24	/* thread bound to FPU-full CPU set */
+#define TIF_LOAD_WATCH		25	/* If set, load watch registers */
+#define TIF_SYSCALL_TRACE	31	/* syscall trace active */
+
+#define _TIF_SYSCALL_TRACE	(1<<TIF_SYSCALL_TRACE)
+#define _TIF_SIGPENDING		(1<<TIF_SIGPENDING)
+#define _TIF_NEED_RESCHED	(1<<TIF_NEED_RESCHED)
+#define _TIF_SYSCALL_AUDIT	(1<<TIF_SYSCALL_AUDIT)
+#define _TIF_SECCOMP		(1<<TIF_SECCOMP)
+#define _TIF_RESTORE_SIGMASK	(1<<TIF_RESTORE_SIGMASK)
+#define _TIF_USEDFPU		(1<<TIF_USEDFPU)
+#define _TIF_POLLING_NRFLAG	(1<<TIF_POLLING_NRFLAG)
+#define _TIF_FREEZE		(1<<TIF_FREEZE)
+#define _TIF_FIXADE		(1<<TIF_FIXADE)
+#define _TIF_LOGADE		(1<<TIF_LOGADE)
+#define _TIF_32BIT_REGS		(1<<TIF_32BIT_REGS)
+#define _TIF_32BIT_ADDR		(1<<TIF_32BIT_ADDR)
+#define _TIF_FPUBOUND		(1<<TIF_FPUBOUND)
+#define _TIF_LOAD_WATCH		(1<<TIF_LOAD_WATCH)
+
+/* work to do on interrupt/exception return */
+#define _TIF_WORK_MASK		(0x0000ffef & ~_TIF_SECCOMP)
+/* work to do on any return to u-space */
+#define _TIF_ALLWORK_MASK	(0x8000ffff & ~_TIF_SECCOMP)
+
+#endif /* __KERNEL__ */
+
+#endif /* _ASM_THREAD_INFO_H */
diff --git a/include/asm-mips/time.h b/arch/mips/include/asm/time.h
similarity index 100%
rename from include/asm-mips/time.h
rename to arch/mips/include/asm/time.h
diff --git a/include/asm-mips/timex.h b/arch/mips/include/asm/timex.h
similarity index 100%
rename from include/asm-mips/timex.h
rename to arch/mips/include/asm/timex.h
diff --git a/include/asm-mips/titan_dep.h b/arch/mips/include/asm/titan_dep.h
similarity index 100%
rename from include/asm-mips/titan_dep.h
rename to arch/mips/include/asm/titan_dep.h
diff --git a/include/asm-mips/tlb.h b/arch/mips/include/asm/tlb.h
similarity index 100%
rename from include/asm-mips/tlb.h
rename to arch/mips/include/asm/tlb.h
diff --git a/include/asm-mips/tlbdebug.h b/arch/mips/include/asm/tlbdebug.h
similarity index 100%
rename from include/asm-mips/tlbdebug.h
rename to arch/mips/include/asm/tlbdebug.h
diff --git a/include/asm-mips/tlbflush.h b/arch/mips/include/asm/tlbflush.h
similarity index 100%
rename from include/asm-mips/tlbflush.h
rename to arch/mips/include/asm/tlbflush.h
diff --git a/include/asm-mips/topology.h b/arch/mips/include/asm/topology.h
similarity index 100%
rename from include/asm-mips/topology.h
rename to arch/mips/include/asm/topology.h
diff --git a/include/asm-mips/traps.h b/arch/mips/include/asm/traps.h
similarity index 100%
rename from include/asm-mips/traps.h
rename to arch/mips/include/asm/traps.h
diff --git a/arch/mips/include/asm/txx9/boards.h b/arch/mips/include/asm/txx9/boards.h
new file mode 100644
index 0000000..cbe9476
--- /dev/null
+++ b/arch/mips/include/asm/txx9/boards.h
@@ -0,0 +1,13 @@
+#ifdef CONFIG_TOSHIBA_JMR3927
+BOARD_VEC(jmr3927_vec)
+#endif
+#ifdef CONFIG_TOSHIBA_RBTX4927
+BOARD_VEC(rbtx4927_vec)
+BOARD_VEC(rbtx4937_vec)
+#endif
+#ifdef CONFIG_TOSHIBA_RBTX4938
+BOARD_VEC(rbtx4938_vec)
+#endif
+#ifdef CONFIG_TOSHIBA_RBTX4939
+BOARD_VEC(rbtx4939_vec)
+#endif
diff --git a/arch/mips/include/asm/txx9/generic.h b/arch/mips/include/asm/txx9/generic.h
new file mode 100644
index 0000000..4316a3e
--- /dev/null
+++ b/arch/mips/include/asm/txx9/generic.h
@@ -0,0 +1,89 @@
+/*
+ * linux/include/asm-mips/txx9/generic.h
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#ifndef __ASM_TXX9_GENERIC_H
+#define __ASM_TXX9_GENERIC_H
+
+#include <linux/init.h>
+#include <linux/ioport.h>	/* for struct resource */
+
+extern struct resource txx9_ce_res[];
+#define TXX9_CE(n)	(unsigned long)(txx9_ce_res[(n)].start)
+extern unsigned int txx9_pcode;
+extern char txx9_pcode_str[8];
+void txx9_reg_res_init(unsigned int pcode, unsigned long base,
+		       unsigned long size);
+
+extern unsigned int txx9_master_clock;
+extern unsigned int txx9_cpu_clock;
+extern unsigned int txx9_gbus_clock;
+#define TXX9_IMCLK	(txx9_gbus_clock / 2)
+
+extern int txx9_ccfg_toeon;
+struct uart_port;
+int early_serial_txx9_setup(struct uart_port *port);
+
+struct pci_dev;
+struct txx9_board_vec {
+	const char *system;
+	void (*prom_init)(void);
+	void (*mem_setup)(void);
+	void (*irq_setup)(void);
+	void (*time_init)(void);
+	void (*arch_init)(void);
+	void (*device_init)(void);
+#ifdef CONFIG_PCI
+	int (*pci_map_irq)(const struct pci_dev *dev, u8 slot, u8 pin);
+#endif
+};
+extern struct txx9_board_vec *txx9_board_vec;
+extern int (*txx9_irq_dispatch)(int pending);
+char *prom_getcmdline(void);
+const char *prom_getenv(const char *name);
+void txx9_wdt_init(unsigned long base);
+void txx9_wdt_now(unsigned long base);
+void txx9_spi_init(int busid, unsigned long base, int irq);
+void txx9_ethaddr_init(unsigned int id, unsigned char *ethaddr);
+void txx9_sio_init(unsigned long baseaddr, int irq,
+		   unsigned int line, unsigned int sclk, int nocts);
+void prom_putchar(char c);
+#ifdef CONFIG_EARLY_PRINTK
+extern void (*txx9_prom_putchar)(char c);
+void txx9_sio_putchar_init(unsigned long baseaddr);
+#else
+static inline void txx9_sio_putchar_init(unsigned long baseaddr)
+{
+}
+#endif
+
+struct physmap_flash_data;
+void txx9_physmap_flash_init(int no, unsigned long addr, unsigned long size,
+			     const struct physmap_flash_data *pdata);
+
+/* 8 bit version of __fls(): find first bit set (returns 0..7) */
+static inline unsigned int __fls8(unsigned char x)
+{
+	int r = 7;
+
+	if (!(x & 0xf0)) {
+		r -= 4;
+		x <<= 4;
+	}
+	if (!(x & 0xc0)) {
+		r -= 2;
+		x <<= 2;
+	}
+	if (!(x & 0x80))
+		r -= 1;
+	return r;
+}
+
+void txx9_iocled_init(unsigned long baseaddr,
+		      int basenum, unsigned int num, int lowactive,
+		      const char *color, char **deftriggers);
+
+#endif /* __ASM_TXX9_GENERIC_H */
diff --git a/include/asm-mips/txx9/jmr3927.h b/arch/mips/include/asm/txx9/jmr3927.h
similarity index 100%
rename from include/asm-mips/txx9/jmr3927.h
rename to arch/mips/include/asm/txx9/jmr3927.h
diff --git a/include/asm-mips/txx9/pci.h b/arch/mips/include/asm/txx9/pci.h
similarity index 100%
rename from include/asm-mips/txx9/pci.h
rename to arch/mips/include/asm/txx9/pci.h
diff --git a/arch/mips/include/asm/txx9/rbtx4927.h b/arch/mips/include/asm/txx9/rbtx4927.h
new file mode 100644
index 0000000..b2adab3
--- /dev/null
+++ b/arch/mips/include/asm/txx9/rbtx4927.h
@@ -0,0 +1,92 @@
+/*
+ * Author: MontaVista Software, Inc.
+ *         source@mvista.com
+ *
+ * Copyright 2001-2002 MontaVista Software Inc.
+ *
+ *  This program is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License as published by the
+ *  Free Software Foundation; either version 2 of the License, or (at your
+ *  option) any later version.
+ *
+ *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ *  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ *  OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ *  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ *  TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ *  USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#ifndef __ASM_TXX9_RBTX4927_H
+#define __ASM_TXX9_RBTX4927_H
+
+#include <asm/txx9/tx4927.h>
+
+#define RBTX4927_PCIMEM		0x08000000
+#define RBTX4927_PCIMEM_SIZE	0x08000000
+#define RBTX4927_PCIIO		0x16000000
+#define RBTX4927_PCIIO_SIZE	0x01000000
+
+#define RBTX4927_LED_ADDR	(IO_BASE + TXX9_CE(2) + 0x00001000)
+#define RBTX4927_IMASK_ADDR	(IO_BASE + TXX9_CE(2) + 0x00002000)
+#define RBTX4927_IMSTAT_ADDR	(IO_BASE + TXX9_CE(2) + 0x00002006)
+#define RBTX4927_SOFTINT_ADDR	(IO_BASE + TXX9_CE(2) + 0x00003000)
+#define RBTX4927_SOFTRESET_ADDR	(IO_BASE + TXX9_CE(2) + 0x0000f000)
+#define RBTX4927_SOFTRESETLOCK_ADDR	(IO_BASE + TXX9_CE(2) + 0x0000f002)
+#define RBTX4927_PCIRESET_ADDR	(IO_BASE + TXX9_CE(2) + 0x0000f006)
+#define RBTX4927_BRAMRTC_BASE	(IO_BASE + TXX9_CE(2) + 0x00010000)
+#define RBTX4927_ETHER_BASE	(IO_BASE + TXX9_CE(2) + 0x00020000)
+
+/* Ethernet port address */
+#define RBTX4927_ETHER_ADDR	(RBTX4927_ETHER_BASE + 0x280)
+
+#define rbtx4927_imask_addr	((__u8 __iomem *)RBTX4927_IMASK_ADDR)
+#define rbtx4927_imstat_addr	((__u8 __iomem *)RBTX4927_IMSTAT_ADDR)
+#define rbtx4927_softint_addr	((__u8 __iomem *)RBTX4927_SOFTINT_ADDR)
+#define rbtx4927_softreset_addr	((__u8 __iomem *)RBTX4927_SOFTRESET_ADDR)
+#define rbtx4927_softresetlock_addr	\
+				((__u8 __iomem *)RBTX4927_SOFTRESETLOCK_ADDR)
+#define rbtx4927_pcireset_addr	((__u8 __iomem *)RBTX4927_PCIRESET_ADDR)
+
+/* bits for ISTAT/IMASK/IMSTAT */
+#define RBTX4927_INTB_PCID	0
+#define RBTX4927_INTB_PCIC	1
+#define RBTX4927_INTB_PCIB	2
+#define RBTX4927_INTB_PCIA	3
+#define RBTX4927_INTF_PCID	(1 << RBTX4927_INTB_PCID)
+#define RBTX4927_INTF_PCIC	(1 << RBTX4927_INTB_PCIC)
+#define RBTX4927_INTF_PCIB	(1 << RBTX4927_INTB_PCIB)
+#define RBTX4927_INTF_PCIA	(1 << RBTX4927_INTB_PCIA)
+
+#define RBTX4927_NR_IRQ_IOC	8	/* IOC */
+
+#define RBTX4927_IRQ_IOC	(TXX9_IRQ_BASE + TX4927_NUM_IR)
+#define RBTX4927_IRQ_IOC_PCID	(RBTX4927_IRQ_IOC + RBTX4927_INTB_PCID)
+#define RBTX4927_IRQ_IOC_PCIC	(RBTX4927_IRQ_IOC + RBTX4927_INTB_PCIC)
+#define RBTX4927_IRQ_IOC_PCIB	(RBTX4927_IRQ_IOC + RBTX4927_INTB_PCIB)
+#define RBTX4927_IRQ_IOC_PCIA	(RBTX4927_IRQ_IOC + RBTX4927_INTB_PCIA)
+
+#define RBTX4927_IRQ_IOCINT	(TXX9_IRQ_BASE + TX4927_IR_INT(1))
+
+#ifdef CONFIG_PCI
+#define RBTX4927_ISA_IO_OFFSET RBTX4927_PCIIO
+#else
+#define RBTX4927_ISA_IO_OFFSET 0
+#endif
+
+#define RBTX4927_RTL_8019_BASE (RBTX4927_ETHER_ADDR - mips_io_port_base)
+#define RBTX4927_RTL_8019_IRQ  (TXX9_IRQ_BASE + TX4927_IR_INT(3))
+
+void rbtx4927_prom_init(void);
+void rbtx4927_irq_setup(void);
+struct pci_dev;
+int rbtx4927_pci_map_irq(const struct pci_dev *dev, u8 slot, u8 pin);
+
+#endif /* __ASM_TXX9_RBTX4927_H */
diff --git a/include/asm-mips/txx9/rbtx4938.h b/arch/mips/include/asm/txx9/rbtx4938.h
similarity index 100%
rename from include/asm-mips/txx9/rbtx4938.h
rename to arch/mips/include/asm/txx9/rbtx4938.h
diff --git a/arch/mips/include/asm/txx9/rbtx4939.h b/arch/mips/include/asm/txx9/rbtx4939.h
new file mode 100644
index 0000000..1acf428
--- /dev/null
+++ b/arch/mips/include/asm/txx9/rbtx4939.h
@@ -0,0 +1,133 @@
+/*
+ * Definitions for RBTX4939
+ *
+ * (C) Copyright TOSHIBA CORPORATION 2005-2006
+ * 2003-2005 (c) MontaVista Software, Inc. This file is licensed under the
+ * terms of the GNU General Public License version 2. This program is
+ * licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ */
+#ifndef __ASM_TXX9_RBTX4939_H
+#define __ASM_TXX9_RBTX4939_H
+
+#include <asm/addrspace.h>
+#include <asm/txx9irq.h>
+#include <asm/txx9/generic.h>
+#include <asm/txx9/tx4939.h>
+
+/* Address map */
+#define RBTX4939_IOC_REG_ADDR	(IO_BASE + TXX9_CE(1) + 0x00000000)
+#define RBTX4939_BOARD_REV_ADDR	(IO_BASE + TXX9_CE(1) + 0x00000000)
+#define RBTX4939_IOC_REV_ADDR	(IO_BASE + TXX9_CE(1) + 0x00000002)
+#define RBTX4939_CONFIG1_ADDR	(IO_BASE + TXX9_CE(1) + 0x00000004)
+#define RBTX4939_CONFIG2_ADDR	(IO_BASE + TXX9_CE(1) + 0x00000006)
+#define RBTX4939_CONFIG3_ADDR	(IO_BASE + TXX9_CE(1) + 0x00000008)
+#define RBTX4939_CONFIG4_ADDR	(IO_BASE + TXX9_CE(1) + 0x0000000a)
+#define RBTX4939_USTAT_ADDR	(IO_BASE + TXX9_CE(1) + 0x00001000)
+#define RBTX4939_UDIPSW_ADDR	(IO_BASE + TXX9_CE(1) + 0x00001002)
+#define RBTX4939_BDIPSW_ADDR	(IO_BASE + TXX9_CE(1) + 0x00001004)
+#define RBTX4939_IEN_ADDR	(IO_BASE + TXX9_CE(1) + 0x00002000)
+#define RBTX4939_IPOL_ADDR	(IO_BASE + TXX9_CE(1) + 0x00002002)
+#define RBTX4939_IFAC1_ADDR	(IO_BASE + TXX9_CE(1) + 0x00002004)
+#define RBTX4939_IFAC2_ADDR	(IO_BASE + TXX9_CE(1) + 0x00002006)
+#define RBTX4939_SOFTINT_ADDR	(IO_BASE + TXX9_CE(1) + 0x00003000)
+#define RBTX4939_ISASTAT_ADDR	(IO_BASE + TXX9_CE(1) + 0x00004000)
+#define RBTX4939_PCISTAT_ADDR	(IO_BASE + TXX9_CE(1) + 0x00004002)
+#define RBTX4939_ROME_ADDR	(IO_BASE + TXX9_CE(1) + 0x00004004)
+#define RBTX4939_SPICS_ADDR	(IO_BASE + TXX9_CE(1) + 0x00004006)
+#define RBTX4939_AUDI_ADDR	(IO_BASE + TXX9_CE(1) + 0x00004008)
+#define RBTX4939_ISAGPIO_ADDR	(IO_BASE + TXX9_CE(1) + 0x0000400a)
+#define RBTX4939_PE1_ADDR	(IO_BASE + TXX9_CE(1) + 0x00005000)
+#define RBTX4939_PE2_ADDR	(IO_BASE + TXX9_CE(1) + 0x00005002)
+#define RBTX4939_PE3_ADDR	(IO_BASE + TXX9_CE(1) + 0x00005004)
+#define RBTX4939_VP_ADDR	(IO_BASE + TXX9_CE(1) + 0x00005006)
+#define RBTX4939_VPRESET_ADDR	(IO_BASE + TXX9_CE(1) + 0x00005008)
+#define RBTX4939_VPSOUT_ADDR	(IO_BASE + TXX9_CE(1) + 0x0000500a)
+#define RBTX4939_VPSIN_ADDR	(IO_BASE + TXX9_CE(1) + 0x0000500c)
+#define RBTX4939_7SEG_ADDR(s, ch)	\
+	(IO_BASE + TXX9_CE(1) + 0x00006000 + (s) * 16 + ((ch) & 3) * 2)
+#define RBTX4939_SOFTRESET_ADDR	(IO_BASE + TXX9_CE(1) + 0x00007000)
+#define RBTX4939_RESETEN_ADDR	(IO_BASE + TXX9_CE(1) + 0x00007002)
+#define RBTX4939_RESETSTAT_ADDR	(IO_BASE + TXX9_CE(1) + 0x00007004)
+#define RBTX4939_ETHER_BASE	(IO_BASE + TXX9_CE(1) + 0x00020000)
+
+/* Ethernet port address */
+#define RBTX4939_ETHER_ADDR	(RBTX4939_ETHER_BASE + 0x300)
+
+/* bits for IEN/IPOL/IFAC */
+#define RBTX4938_INTB_ISA0	0
+#define RBTX4938_INTB_ISA11	1
+#define RBTX4938_INTB_ISA12	2
+#define RBTX4938_INTB_ISA15	3
+#define RBTX4938_INTB_I2S	4
+#define RBTX4938_INTB_SW	5
+#define RBTX4938_INTF_ISA0	(1 << RBTX4938_INTB_ISA0)
+#define RBTX4938_INTF_ISA11	(1 << RBTX4938_INTB_ISA11)
+#define RBTX4938_INTF_ISA12	(1 << RBTX4938_INTB_ISA12)
+#define RBTX4938_INTF_ISA15	(1 << RBTX4938_INTB_ISA15)
+#define RBTX4938_INTF_I2S	(1 << RBTX4938_INTB_I2S)
+#define RBTX4938_INTF_SW	(1 << RBTX4938_INTB_SW)
+
+/* bits for PE1,PE2,PE3 */
+#define RBTX4939_PE1_ATA(ch)	(0x01 << (ch))
+#define RBTX4939_PE1_RMII(ch)	(0x04 << (ch))
+#define RBTX4939_PE2_SIO0	0x01
+#define RBTX4939_PE2_SIO2	0x02
+#define RBTX4939_PE2_SIO3	0x04
+#define RBTX4939_PE2_CIR	0x08
+#define RBTX4939_PE2_SPI	0x10
+#define RBTX4939_PE2_GPIO	0x20
+#define RBTX4939_PE3_VP	0x01
+#define RBTX4939_PE3_VP_P	0x02
+#define RBTX4939_PE3_VP_S	0x04
+
+#define rbtx4939_board_rev_addr	((u8 __iomem *)RBTX4939_BOARD_REV_ADDR)
+#define rbtx4939_ioc_rev_addr	((u8 __iomem *)RBTX4939_IOC_REV_ADDR)
+#define rbtx4939_config1_addr	((u8 __iomem *)RBTX4939_CONFIG1_ADDR)
+#define rbtx4939_config2_addr	((u8 __iomem *)RBTX4939_CONFIG2_ADDR)
+#define rbtx4939_config3_addr	((u8 __iomem *)RBTX4939_CONFIG3_ADDR)
+#define rbtx4939_config4_addr	((u8 __iomem *)RBTX4939_CONFIG4_ADDR)
+#define rbtx4939_ustat_addr	((u8 __iomem *)RBTX4939_USTAT_ADDR)
+#define rbtx4939_udipsw_addr	((u8 __iomem *)RBTX4939_UDIPSW_ADDR)
+#define rbtx4939_bdipsw_addr	((u8 __iomem *)RBTX4939_BDIPSW_ADDR)
+#define rbtx4939_ien_addr	((u8 __iomem *)RBTX4939_IEN_ADDR)
+#define rbtx4939_ipol_addr	((u8 __iomem *)RBTX4939_IPOL_ADDR)
+#define rbtx4939_ifac1_addr	((u8 __iomem *)RBTX4939_IFAC1_ADDR)
+#define rbtx4939_ifac2_addr	((u8 __iomem *)RBTX4939_IFAC2_ADDR)
+#define rbtx4939_softint_addr	((u8 __iomem *)RBTX4939_SOFTINT_ADDR)
+#define rbtx4939_isastat_addr	((u8 __iomem *)RBTX4939_ISASTAT_ADDR)
+#define rbtx4939_pcistat_addr	((u8 __iomem *)RBTX4939_PCISTAT_ADDR)
+#define rbtx4939_rome_addr	((u8 __iomem *)RBTX4939_ROME_ADDR)
+#define rbtx4939_spics_addr	((u8 __iomem *)RBTX4939_SPICS_ADDR)
+#define rbtx4939_audi_addr	((u8 __iomem *)RBTX4939_AUDI_ADDR)
+#define rbtx4939_isagpio_addr	((u8 __iomem *)RBTX4939_ISAGPIO_ADDR)
+#define rbtx4939_pe1_addr	((u8 __iomem *)RBTX4939_PE1_ADDR)
+#define rbtx4939_pe2_addr	((u8 __iomem *)RBTX4939_PE2_ADDR)
+#define rbtx4939_pe3_addr	((u8 __iomem *)RBTX4939_PE3_ADDR)
+#define rbtx4939_vp_addr	((u8 __iomem *)RBTX4939_VP_ADDR)
+#define rbtx4939_vpreset_addr	((u8 __iomem *)RBTX4939_VPRESET_ADDR)
+#define rbtx4939_vpsout_addr	((u8 __iomem *)RBTX4939_VPSOUT_ADDR)
+#define rbtx4939_vpsin_addr	((u8 __iomem *)RBTX4939_VPSIN_ADDR)
+#define rbtx4939_7seg_addr(s, ch) \
+				((u8 __iomem *)RBTX4939_7SEG_ADDR(s, ch))
+#define rbtx4939_softreset_addr	((u8 __iomem *)RBTX4939_SOFTRESET_ADDR)
+#define rbtx4939_reseten_addr	((u8 __iomem *)RBTX4939_RESETEN_ADDR)
+#define rbtx4939_resetstat_addr	((u8 __iomem *)RBTX4939_RESETSTAT_ADDR)
+
+/*
+ * IRQ mappings
+ */
+#define RBTX4939_NR_IRQ_IOC	8
+
+#define RBTX4939_IRQ_IOC	(TXX9_IRQ_BASE + TX4939_NUM_IR)
+#define RBTX4939_IRQ_END	(RBTX4939_IRQ_IOC + RBTX4939_NR_IRQ_IOC)
+
+/* IOC (ISA, etc) */
+#define RBTX4939_IRQ_IOCINT	(TXX9_IRQ_BASE + TX4939_IR_INT(0))
+/* Onboard 10M Ether */
+#define RBTX4939_IRQ_ETHER	(TXX9_IRQ_BASE + TX4939_IR_INT(1))
+
+void rbtx4939_prom_init(void);
+void rbtx4939_irq_setup(void);
+
+#endif /* __ASM_TXX9_RBTX4939_H */
diff --git a/arch/mips/include/asm/txx9/smsc_fdc37m81x.h b/arch/mips/include/asm/txx9/smsc_fdc37m81x.h
new file mode 100644
index 0000000..d1d6332
--- /dev/null
+++ b/arch/mips/include/asm/txx9/smsc_fdc37m81x.h
@@ -0,0 +1,68 @@
+/*
+ * Interface for smsc fdc48m81x Super IO chip
+ *
+ * Author: MontaVista Software, Inc. source@mvista.com
+ *
+ * 2001-2003 (c) MontaVista Software, Inc. This file is licensed under
+ * the terms of the GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ *
+ * Copyright (C) 2004 MontaVista Software Inc.
+ * Manish Lachwani, mlachwani@mvista.com
+ */
+
+#ifndef _SMSC_FDC37M81X_H_
+#define _SMSC_FDC37M81X_H_
+
+/* Common Registers */
+#define SMSC_FDC37M81X_CONFIG_INDEX  0x00
+#define SMSC_FDC37M81X_CONFIG_DATA   0x01
+#define SMSC_FDC37M81X_CONF          0x02
+#define SMSC_FDC37M81X_INDEX         0x03
+#define SMSC_FDC37M81X_DNUM          0x07
+#define SMSC_FDC37M81X_DID           0x20
+#define SMSC_FDC37M81X_DREV          0x21
+#define SMSC_FDC37M81X_PCNT          0x22
+#define SMSC_FDC37M81X_PMGT          0x23
+#define SMSC_FDC37M81X_OSC           0x24
+#define SMSC_FDC37M81X_CONFPA0       0x26
+#define SMSC_FDC37M81X_CONFPA1       0x27
+#define SMSC_FDC37M81X_TEST4         0x2B
+#define SMSC_FDC37M81X_TEST5         0x2C
+#define SMSC_FDC37M81X_TEST1         0x2D
+#define SMSC_FDC37M81X_TEST2         0x2E
+#define SMSC_FDC37M81X_TEST3         0x2F
+
+/* Logical device numbers */
+#define SMSC_FDC37M81X_FDD           0x00
+#define SMSC_FDC37M81X_PARALLEL      0x03
+#define SMSC_FDC37M81X_SERIAL1       0x04
+#define SMSC_FDC37M81X_SERIAL2       0x05
+#define SMSC_FDC37M81X_KBD           0x07
+#define SMSC_FDC37M81X_AUXIO         0x08
+#define SMSC_FDC37M81X_NONE          0xff
+
+/* Logical device Config Registers */
+#define SMSC_FDC37M81X_ACTIVE        0x30
+#define SMSC_FDC37M81X_BASEADDR0     0x60
+#define SMSC_FDC37M81X_BASEADDR1     0x61
+#define SMSC_FDC37M81X_INT           0x70
+#define SMSC_FDC37M81X_INT2          0x72
+#define SMSC_FDC37M81X_LDCR_F0       0xF0
+
+/* Chip Config Values */
+#define SMSC_FDC37M81X_CONFIG_ENTER  0x55
+#define SMSC_FDC37M81X_CONFIG_EXIT   0xaa
+#define SMSC_FDC37M81X_CHIP_ID       0x4d
+
+unsigned long smsc_fdc37m81x_init(unsigned long port);
+
+void smsc_fdc37m81x_config_beg(void);
+
+void smsc_fdc37m81x_config_end(void);
+
+u8 smsc_fdc37m81x_config_get(u8 reg);
+void smsc_fdc37m81x_config_set(u8 reg, u8 val);
+
+#endif
diff --git a/arch/mips/include/asm/txx9/spi.h b/arch/mips/include/asm/txx9/spi.h
new file mode 100644
index 0000000..0d727f3
--- /dev/null
+++ b/arch/mips/include/asm/txx9/spi.h
@@ -0,0 +1,34 @@
+/*
+ * Definitions for TX4937/TX4938 SPI
+ *
+ * Copyright (C) 2000-2001 Toshiba Corporation
+ *
+ * 2003-2005 (c) MontaVista Software, Inc. This file is licensed under the
+ * terms of the GNU General Public License version 2. This program is
+ * licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ *
+ * Support for TX4938 in 2.6 - Manish Lachwani (mlachwani@mvista.com)
+ */
+#ifndef __ASM_TXX9_SPI_H
+#define __ASM_TXX9_SPI_H
+
+#include <linux/errno.h>
+
+#ifdef CONFIG_SPI
+int spi_eeprom_register(int busid, int chipid, int size);
+int spi_eeprom_read(int busid, int chipid,
+		    int address, unsigned char *buf, int len);
+#else
+static inline int spi_eeprom_register(int busid, int chipid, int size)
+{
+	return -ENODEV;
+}
+static inline int spi_eeprom_read(int busid, int chipid,
+				  int address, unsigned char *buf, int len)
+{
+	return -ENODEV;
+}
+#endif
+
+#endif /* __ASM_TXX9_SPI_H */
diff --git a/arch/mips/include/asm/txx9/tx3927.h b/arch/mips/include/asm/txx9/tx3927.h
new file mode 100644
index 0000000..dc30c8d
--- /dev/null
+++ b/arch/mips/include/asm/txx9/tx3927.h
@@ -0,0 +1,341 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2000 Toshiba Corporation
+ */
+#ifndef __ASM_TXX9_TX3927_H
+#define __ASM_TXX9_TX3927_H
+
+#define TX3927_REG_BASE	0xfffe0000UL
+#define TX3927_REG_SIZE	0x00010000
+#define TX3927_SDRAMC_REG	(TX3927_REG_BASE + 0x8000)
+#define TX3927_ROMC_REG		(TX3927_REG_BASE + 0x9000)
+#define TX3927_DMA_REG		(TX3927_REG_BASE + 0xb000)
+#define TX3927_IRC_REG		(TX3927_REG_BASE + 0xc000)
+#define TX3927_PCIC_REG		(TX3927_REG_BASE + 0xd000)
+#define TX3927_CCFG_REG		(TX3927_REG_BASE + 0xe000)
+#define TX3927_NR_TMR	3
+#define TX3927_TMR_REG(ch)	(TX3927_REG_BASE + 0xf000 + (ch) * 0x100)
+#define TX3927_NR_SIO	2
+#define TX3927_SIO_REG(ch)	(TX3927_REG_BASE + 0xf300 + (ch) * 0x100)
+#define TX3927_PIO_REG		(TX3927_REG_BASE + 0xf500)
+
+struct tx3927_sdramc_reg {
+	volatile unsigned long cr[8];
+	volatile unsigned long tr[3];
+	volatile unsigned long cmd;
+	volatile unsigned long smrs[2];
+};
+
+struct tx3927_romc_reg {
+	volatile unsigned long cr[8];
+};
+
+struct tx3927_dma_reg {
+	struct tx3927_dma_ch_reg {
+		volatile unsigned long cha;
+		volatile unsigned long sar;
+		volatile unsigned long dar;
+		volatile unsigned long cntr;
+		volatile unsigned long sair;
+		volatile unsigned long dair;
+		volatile unsigned long ccr;
+		volatile unsigned long csr;
+	} ch[4];
+	volatile unsigned long dbr[8];
+	volatile unsigned long tdhr;
+	volatile unsigned long mcr;
+	volatile unsigned long unused0;
+};
+
+#include <asm/byteorder.h>
+
+#ifdef __BIG_ENDIAN
+#define endian_def_s2(e1, e2)	\
+	volatile unsigned short e1, e2
+#define endian_def_sb2(e1, e2, e3)	\
+	volatile unsigned short e1;volatile unsigned char e2, e3
+#define endian_def_b2s(e1, e2, e3)	\
+	volatile unsigned char e1, e2;volatile unsigned short e3
+#define endian_def_b4(e1, e2, e3, e4)	\
+	volatile unsigned char e1, e2, e3, e4
+#else
+#define endian_def_s2(e1, e2)	\
+	volatile unsigned short e2, e1
+#define endian_def_sb2(e1, e2, e3)	\
+	volatile unsigned char e3, e2;volatile unsigned short e1
+#define endian_def_b2s(e1, e2, e3)	\
+	volatile unsigned short e3;volatile unsigned char e2, e1
+#define endian_def_b4(e1, e2, e3, e4)	\
+	volatile unsigned char e4, e3, e2, e1
+#endif
+
+struct tx3927_pcic_reg {
+	endian_def_s2(did, vid);
+	endian_def_s2(pcistat, pcicmd);
+	endian_def_b4(cc, scc, rpli, rid);
+	endian_def_b4(unused0, ht, mlt, cls);
+	volatile unsigned long ioba;		/* +10 */
+	volatile unsigned long mba;
+	volatile unsigned long unused1[5];
+	endian_def_s2(svid, ssvid);
+	volatile unsigned long unused2;		/* +30 */
+	endian_def_sb2(unused3, unused4, capptr);
+	volatile unsigned long unused5;
+	endian_def_b4(ml, mg, ip, il);
+	volatile unsigned long unused6;		/* +40 */
+	volatile unsigned long istat;
+	volatile unsigned long iim;
+	volatile unsigned long rrt;
+	volatile unsigned long unused7[3];		/* +50 */
+	volatile unsigned long ipbmma;
+	volatile unsigned long ipbioma;		/* +60 */
+	volatile unsigned long ilbmma;
+	volatile unsigned long ilbioma;
+	volatile unsigned long unused8[9];
+	volatile unsigned long tc;		/* +90 */
+	volatile unsigned long tstat;
+	volatile unsigned long tim;
+	volatile unsigned long tccmd;
+	volatile unsigned long pcirrt;		/* +a0 */
+	volatile unsigned long pcirrt_cmd;
+	volatile unsigned long pcirrdt;
+	volatile unsigned long unused9[3];
+	volatile unsigned long tlboap;
+	volatile unsigned long tlbiap;
+	volatile unsigned long tlbmma;		/* +c0 */
+	volatile unsigned long tlbioma;
+	volatile unsigned long sc_msg;
+	volatile unsigned long sc_be;
+	volatile unsigned long tbl;		/* +d0 */
+	volatile unsigned long unused10[3];
+	volatile unsigned long pwmng;		/* +e0 */
+	volatile unsigned long pwmngs;
+	volatile unsigned long unused11[6];
+	volatile unsigned long req_trace;		/* +100 */
+	volatile unsigned long pbapmc;
+	volatile unsigned long pbapms;
+	volatile unsigned long pbapmim;
+	volatile unsigned long bm;		/* +110 */
+	volatile unsigned long cpcibrs;
+	volatile unsigned long cpcibgs;
+	volatile unsigned long pbacs;
+	volatile unsigned long iobas;		/* +120 */
+	volatile unsigned long mbas;
+	volatile unsigned long lbc;
+	volatile unsigned long lbstat;
+	volatile unsigned long lbim;		/* +130 */
+	volatile unsigned long pcistatim;
+	volatile unsigned long ica;
+	volatile unsigned long icd;
+	volatile unsigned long iiadp;		/* +140 */
+	volatile unsigned long iscdp;
+	volatile unsigned long mmas;
+	volatile unsigned long iomas;
+	volatile unsigned long ipciaddr;		/* +150 */
+	volatile unsigned long ipcidata;
+	volatile unsigned long ipcibe;
+};
+
+struct tx3927_ccfg_reg {
+	volatile unsigned long ccfg;
+	volatile unsigned long crir;
+	volatile unsigned long pcfg;
+	volatile unsigned long tear;
+	volatile unsigned long pdcr;
+};
+
+/*
+ * SDRAMC
+ */
+
+/*
+ * ROMC
+ */
+
+/*
+ * DMA
+ */
+/* bits for MCR */
+#define TX3927_DMA_MCR_EIS(ch)	(0x10000000<<(ch))
+#define TX3927_DMA_MCR_DIS(ch)	(0x01000000<<(ch))
+#define TX3927_DMA_MCR_RSFIF	0x00000080
+#define TX3927_DMA_MCR_FIFUM(ch)	(0x00000008<<(ch))
+#define TX3927_DMA_MCR_LE	0x00000004
+#define TX3927_DMA_MCR_RPRT	0x00000002
+#define TX3927_DMA_MCR_MSTEN	0x00000001
+
+/* bits for CCRn */
+#define TX3927_DMA_CCR_DBINH	0x04000000
+#define TX3927_DMA_CCR_SBINH	0x02000000
+#define TX3927_DMA_CCR_CHRST	0x01000000
+#define TX3927_DMA_CCR_RVBYTE	0x00800000
+#define TX3927_DMA_CCR_ACKPOL	0x00400000
+#define TX3927_DMA_CCR_REQPL	0x00200000
+#define TX3927_DMA_CCR_EGREQ	0x00100000
+#define TX3927_DMA_CCR_CHDN	0x00080000
+#define TX3927_DMA_CCR_DNCTL	0x00060000
+#define TX3927_DMA_CCR_EXTRQ	0x00010000
+#define TX3927_DMA_CCR_INTRQD	0x0000e000
+#define TX3927_DMA_CCR_INTENE	0x00001000
+#define TX3927_DMA_CCR_INTENC	0x00000800
+#define TX3927_DMA_CCR_INTENT	0x00000400
+#define TX3927_DMA_CCR_CHNEN	0x00000200
+#define TX3927_DMA_CCR_XFACT	0x00000100
+#define TX3927_DMA_CCR_SNOP	0x00000080
+#define TX3927_DMA_CCR_DSTINC	0x00000040
+#define TX3927_DMA_CCR_SRCINC	0x00000020
+#define TX3927_DMA_CCR_XFSZ(order)	(((order) << 2) & 0x0000001c)
+#define TX3927_DMA_CCR_XFSZ_1W	TX3927_DMA_CCR_XFSZ(2)
+#define TX3927_DMA_CCR_XFSZ_4W	TX3927_DMA_CCR_XFSZ(4)
+#define TX3927_DMA_CCR_XFSZ_8W	TX3927_DMA_CCR_XFSZ(5)
+#define TX3927_DMA_CCR_XFSZ_16W	TX3927_DMA_CCR_XFSZ(6)
+#define TX3927_DMA_CCR_XFSZ_32W	TX3927_DMA_CCR_XFSZ(7)
+#define TX3927_DMA_CCR_MEMIO	0x00000002
+#define TX3927_DMA_CCR_ONEAD	0x00000001
+
+/* bits for CSRn */
+#define TX3927_DMA_CSR_CHNACT	0x00000100
+#define TX3927_DMA_CSR_ABCHC	0x00000080
+#define TX3927_DMA_CSR_NCHNC	0x00000040
+#define TX3927_DMA_CSR_NTRNFC	0x00000020
+#define TX3927_DMA_CSR_EXTDN	0x00000010
+#define TX3927_DMA_CSR_CFERR	0x00000008
+#define TX3927_DMA_CSR_CHERR	0x00000004
+#define TX3927_DMA_CSR_DESERR	0x00000002
+#define TX3927_DMA_CSR_SORERR	0x00000001
+
+/*
+ * IRC
+ */
+#define TX3927_IR_INT0	0
+#define TX3927_IR_INT1	1
+#define TX3927_IR_INT2	2
+#define TX3927_IR_INT3	3
+#define TX3927_IR_INT4	4
+#define TX3927_IR_INT5	5
+#define TX3927_IR_SIO0	6
+#define TX3927_IR_SIO1	7
+#define TX3927_IR_SIO(ch)	(6 + (ch))
+#define TX3927_IR_DMA	8
+#define TX3927_IR_PIO	9
+#define TX3927_IR_PCI	10
+#define TX3927_IR_TMR(ch)	(13 + (ch))
+#define TX3927_NUM_IR	16
+
+/*
+ * PCIC
+ */
+/* bits for PCICMD */
+/* see PCI_COMMAND_XXX in linux/pci.h */
+
+/* bits for PCISTAT */
+/* see PCI_STATUS_XXX in linux/pci.h */
+#define PCI_STATUS_NEW_CAP	0x0010
+
+/* bits for ISTAT/IIM */
+#define TX3927_PCIC_IIM_ALL	0x00001600
+
+/* bits for TC */
+#define TX3927_PCIC_TC_OF16E	0x00000020
+#define TX3927_PCIC_TC_IF8E	0x00000010
+#define TX3927_PCIC_TC_OF8E	0x00000008
+
+/* bits for TSTAT/TIM */
+#define TX3927_PCIC_TIM_ALL	0x0003ffff
+
+/* bits for IOBA/MBA */
+/* see PCI_BASE_ADDRESS_XXX in linux/pci.h */
+
+/* bits for PBAPMC */
+#define TX3927_PCIC_PBAPMC_RPBA	0x00000004
+#define TX3927_PCIC_PBAPMC_PBAEN	0x00000002
+#define TX3927_PCIC_PBAPMC_BMCEN	0x00000001
+
+/* bits for LBSTAT/LBIM */
+#define TX3927_PCIC_LBIM_ALL	0x0000003e
+
+/* bits for PCISTATIM (see also PCI_STATUS_XXX in linux/pci.h */
+#define TX3927_PCIC_PCISTATIM_ALL	0x0000f900
+
+/* bits for LBC */
+#define TX3927_PCIC_LBC_IBSE	0x00004000
+#define TX3927_PCIC_LBC_TIBSE	0x00002000
+#define TX3927_PCIC_LBC_TMFBSE	0x00001000
+#define TX3927_PCIC_LBC_HRST	0x00000800
+#define TX3927_PCIC_LBC_SRST	0x00000400
+#define TX3927_PCIC_LBC_EPCAD	0x00000200
+#define TX3927_PCIC_LBC_MSDSE	0x00000100
+#define TX3927_PCIC_LBC_CRR	0x00000080
+#define TX3927_PCIC_LBC_ILMDE	0x00000040
+#define TX3927_PCIC_LBC_ILIDE	0x00000020
+
+#define TX3927_PCIC_IDSEL_AD_TO_SLOT(ad)	((ad) - 11)
+#define TX3927_PCIC_MAX_DEVNU	TX3927_PCIC_IDSEL_AD_TO_SLOT(32)
+
+/*
+ * CCFG
+ */
+/* CCFG : Chip Configuration */
+#define TX3927_CCFG_TLBOFF	0x00020000
+#define TX3927_CCFG_BEOW	0x00010000
+#define TX3927_CCFG_WR	0x00008000
+#define TX3927_CCFG_TOE	0x00004000
+#define TX3927_CCFG_PCIXARB	0x00002000
+#define TX3927_CCFG_PCI3	0x00001000
+#define TX3927_CCFG_PSNP	0x00000800
+#define TX3927_CCFG_PPRI	0x00000400
+#define TX3927_CCFG_PLLM	0x00000030
+#define TX3927_CCFG_ENDIAN	0x00000004
+#define TX3927_CCFG_HALT	0x00000002
+#define TX3927_CCFG_ACEHOLD	0x00000001
+
+/* PCFG : Pin Configuration */
+#define TX3927_PCFG_SYSCLKEN	0x08000000
+#define TX3927_PCFG_SDRCLKEN_ALL	0x07c00000
+#define TX3927_PCFG_SDRCLKEN(ch)	(0x00400000<<(ch))
+#define TX3927_PCFG_PCICLKEN_ALL	0x003c0000
+#define TX3927_PCFG_PCICLKEN(ch)	(0x00040000<<(ch))
+#define TX3927_PCFG_SELALL	0x0003ffff
+#define TX3927_PCFG_SELCS	0x00020000
+#define TX3927_PCFG_SELDSF	0x00010000
+#define TX3927_PCFG_SELSIOC_ALL	0x0000c000
+#define TX3927_PCFG_SELSIOC(ch)	(0x00004000<<(ch))
+#define TX3927_PCFG_SELSIO_ALL	0x00003000
+#define TX3927_PCFG_SELSIO(ch)	(0x00001000<<(ch))
+#define TX3927_PCFG_SELTMR_ALL	0x00000e00
+#define TX3927_PCFG_SELTMR(ch)	(0x00000200<<(ch))
+#define TX3927_PCFG_SELDONE	0x00000100
+#define TX3927_PCFG_INTDMA_ALL	0x000000f0
+#define TX3927_PCFG_INTDMA(ch)	(0x00000010<<(ch))
+#define TX3927_PCFG_SELDMA_ALL	0x0000000f
+#define TX3927_PCFG_SELDMA(ch)	(0x00000001<<(ch))
+
+#define tx3927_sdramcptr	((struct tx3927_sdramc_reg *)TX3927_SDRAMC_REG)
+#define tx3927_romcptr		((struct tx3927_romc_reg *)TX3927_ROMC_REG)
+#define tx3927_dmaptr		((struct tx3927_dma_reg *)TX3927_DMA_REG)
+#define tx3927_pcicptr		((struct tx3927_pcic_reg *)TX3927_PCIC_REG)
+#define tx3927_ccfgptr		((struct tx3927_ccfg_reg *)TX3927_CCFG_REG)
+#define tx3927_sioptr(ch)	((struct txx927_sio_reg *)TX3927_SIO_REG(ch))
+#define tx3927_pioptr		((struct txx9_pio_reg __iomem *)TX3927_PIO_REG)
+
+#define TX3927_REV_PCODE()	(tx3927_ccfgptr->crir >> 16)
+#define TX3927_ROMC_BA(ch)	(tx3927_romcptr->cr[(ch)] & 0xfff00000)
+#define TX3927_ROMC_SIZE(ch)	\
+	(0x00100000 << ((tx3927_romcptr->cr[(ch)] >> 8) & 0xf))
+#define TX3927_ROMC_WIDTH(ch)	(32 >> ((tx3927_romcptr->cr[(ch)] >> 7) & 0x1))
+
+void tx3927_wdt_init(void);
+void tx3927_setup(void);
+void tx3927_time_init(unsigned int evt_tmrnr, unsigned int src_tmrnr);
+void tx3927_sio_init(unsigned int sclk, unsigned int cts_mask);
+struct pci_controller;
+void tx3927_pcic_setup(struct pci_controller *channel,
+		       unsigned long sdram_size, int extarb);
+void tx3927_setup_pcierr_irq(void);
+void tx3927_irq_init(void);
+void tx3927_mtd_init(int ch);
+
+#endif /* __ASM_TXX9_TX3927_H */
diff --git a/arch/mips/include/asm/txx9/tx4927.h b/arch/mips/include/asm/txx9/tx4927.h
new file mode 100644
index 0000000..7d813f1
--- /dev/null
+++ b/arch/mips/include/asm/txx9/tx4927.h
@@ -0,0 +1,269 @@
+/*
+ * Author: MontaVista Software, Inc.
+ *         source@mvista.com
+ *
+ * Copyright 2001-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.
+ *
+ *  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.
+ */
+#ifndef __ASM_TXX9_TX4927_H
+#define __ASM_TXX9_TX4927_H
+
+#include <linux/types.h>
+#include <linux/io.h>
+#include <asm/txx9irq.h>
+#include <asm/txx9/tx4927pcic.h>
+
+#ifdef CONFIG_64BIT
+#define TX4927_REG_BASE	0xffffffffff1f0000UL
+#else
+#define TX4927_REG_BASE	0xff1f0000UL
+#endif
+#define TX4927_REG_SIZE	0x00010000
+
+#define TX4927_SDRAMC_REG	(TX4927_REG_BASE + 0x8000)
+#define TX4927_EBUSC_REG	(TX4927_REG_BASE + 0x9000)
+#define TX4927_PCIC_REG		(TX4927_REG_BASE + 0xd000)
+#define TX4927_CCFG_REG		(TX4927_REG_BASE + 0xe000)
+#define TX4927_IRC_REG		(TX4927_REG_BASE + 0xf600)
+#define TX4927_NR_TMR	3
+#define TX4927_TMR_REG(ch)	(TX4927_REG_BASE + 0xf000 + (ch) * 0x100)
+#define TX4927_NR_SIO	2
+#define TX4927_SIO_REG(ch)	(TX4927_REG_BASE + 0xf300 + (ch) * 0x100)
+#define TX4927_PIO_REG		(TX4927_REG_BASE + 0xf500)
+
+#define TX4927_IR_ECCERR	0
+#define TX4927_IR_WTOERR	1
+#define TX4927_NUM_IR_INT	6
+#define TX4927_IR_INT(n)	(2 + (n))
+#define TX4927_NUM_IR_SIO	2
+#define TX4927_IR_SIO(n)	(8 + (n))
+#define TX4927_NUM_IR_DMA	4
+#define TX4927_IR_DMA(n)	(10 + (n))
+#define TX4927_IR_PIO		14
+#define TX4927_IR_PDMAC		15
+#define TX4927_IR_PCIC		16
+#define TX4927_NUM_IR_TMR	3
+#define TX4927_IR_TMR(n)	(17 + (n))
+#define TX4927_IR_PCIERR	22
+#define TX4927_IR_PCIPME	23
+#define TX4927_IR_ACLC		24
+#define TX4927_IR_ACLCPME	25
+#define TX4927_NUM_IR	32
+
+#define TX4927_IRC_INT	2	/* IP[2] in Status register */
+
+#define TX4927_NUM_PIO	16
+
+struct tx4927_sdramc_reg {
+	u64 cr[4];
+	u64 unused0[4];
+	u64 tr;
+	u64 unused1[2];
+	u64 cmd;
+};
+
+struct tx4927_ebusc_reg {
+	u64 cr[8];
+};
+
+struct tx4927_ccfg_reg {
+	u64 ccfg;
+	u64 crir;
+	u64 pcfg;
+	u64 toea;
+	u64 clkctr;
+	u64 unused0;
+	u64 garbc;
+	u64 unused1;
+	u64 unused2;
+	u64 ramp;
+};
+
+/*
+ * CCFG
+ */
+/* CCFG : Chip Configuration */
+#define TX4927_CCFG_WDRST	0x0000020000000000ULL
+#define TX4927_CCFG_WDREXEN	0x0000010000000000ULL
+#define TX4927_CCFG_BCFG_MASK	0x000000ff00000000ULL
+#define TX4927_CCFG_TINTDIS	0x01000000
+#define TX4927_CCFG_PCI66	0x00800000
+#define TX4927_CCFG_PCIMODE	0x00400000
+#define TX4927_CCFG_DIVMODE_MASK	0x000e0000
+#define TX4927_CCFG_DIVMODE_8	(0x0 << 17)
+#define TX4927_CCFG_DIVMODE_12	(0x1 << 17)
+#define TX4927_CCFG_DIVMODE_16	(0x2 << 17)
+#define TX4927_CCFG_DIVMODE_10	(0x3 << 17)
+#define TX4927_CCFG_DIVMODE_2	(0x4 << 17)
+#define TX4927_CCFG_DIVMODE_3	(0x5 << 17)
+#define TX4927_CCFG_DIVMODE_4	(0x6 << 17)
+#define TX4927_CCFG_DIVMODE_2_5	(0x7 << 17)
+#define TX4927_CCFG_BEOW	0x00010000
+#define TX4927_CCFG_WR	0x00008000
+#define TX4927_CCFG_TOE	0x00004000
+#define TX4927_CCFG_PCIARB	0x00002000
+#define TX4927_CCFG_PCIDIVMODE_MASK	0x00001800
+#define TX4927_CCFG_PCIDIVMODE_2_5	0x00000000
+#define TX4927_CCFG_PCIDIVMODE_3	0x00000800
+#define TX4927_CCFG_PCIDIVMODE_5	0x00001000
+#define TX4927_CCFG_PCIDIVMODE_6	0x00001800
+#define TX4927_CCFG_SYSSP_MASK	0x000000c0
+#define TX4927_CCFG_ENDIAN	0x00000004
+#define TX4927_CCFG_HALT	0x00000002
+#define TX4927_CCFG_ACEHOLD	0x00000001
+#define TX4927_CCFG_W1CBITS	(TX4927_CCFG_WDRST | TX4927_CCFG_BEOW)
+
+/* PCFG : Pin Configuration */
+#define TX4927_PCFG_SDCLKDLY_MASK	0x30000000
+#define TX4927_PCFG_SDCLKDLY(d)	((d)<<28)
+#define TX4927_PCFG_SYSCLKEN	0x08000000
+#define TX4927_PCFG_SDCLKEN_ALL	0x07800000
+#define TX4927_PCFG_SDCLKEN(ch)	(0x00800000<<(ch))
+#define TX4927_PCFG_PCICLKEN_ALL	0x003f0000
+#define TX4927_PCFG_PCICLKEN(ch)	(0x00010000<<(ch))
+#define TX4927_PCFG_SEL2	0x00000200
+#define TX4927_PCFG_SEL1	0x00000100
+#define TX4927_PCFG_DMASEL_ALL	0x000000ff
+#define TX4927_PCFG_DMASEL0_MASK	0x00000003
+#define TX4927_PCFG_DMASEL1_MASK	0x0000000c
+#define TX4927_PCFG_DMASEL2_MASK	0x00000030
+#define TX4927_PCFG_DMASEL3_MASK	0x000000c0
+#define TX4927_PCFG_DMASEL0_DRQ0	0x00000000
+#define TX4927_PCFG_DMASEL0_SIO1	0x00000001
+#define TX4927_PCFG_DMASEL0_ACL0	0x00000002
+#define TX4927_PCFG_DMASEL0_ACL2	0x00000003
+#define TX4927_PCFG_DMASEL1_DRQ1	0x00000000
+#define TX4927_PCFG_DMASEL1_SIO1	0x00000004
+#define TX4927_PCFG_DMASEL1_ACL1	0x00000008
+#define TX4927_PCFG_DMASEL1_ACL3	0x0000000c
+#define TX4927_PCFG_DMASEL2_DRQ2	0x00000000	/* SEL2=0 */
+#define TX4927_PCFG_DMASEL2_SIO0	0x00000010	/* SEL2=0 */
+#define TX4927_PCFG_DMASEL2_ACL1	0x00000000	/* SEL2=1 */
+#define TX4927_PCFG_DMASEL2_ACL2	0x00000020	/* SEL2=1 */
+#define TX4927_PCFG_DMASEL2_ACL0	0x00000030	/* SEL2=1 */
+#define TX4927_PCFG_DMASEL3_DRQ3	0x00000000
+#define TX4927_PCFG_DMASEL3_SIO0	0x00000040
+#define TX4927_PCFG_DMASEL3_ACL3	0x00000080
+#define TX4927_PCFG_DMASEL3_ACL1	0x000000c0
+
+/* CLKCTR : Clock Control */
+#define TX4927_CLKCTR_ACLCKD	0x02000000
+#define TX4927_CLKCTR_PIOCKD	0x01000000
+#define TX4927_CLKCTR_DMACKD	0x00800000
+#define TX4927_CLKCTR_PCICKD	0x00400000
+#define TX4927_CLKCTR_TM0CKD	0x00100000
+#define TX4927_CLKCTR_TM1CKD	0x00080000
+#define TX4927_CLKCTR_TM2CKD	0x00040000
+#define TX4927_CLKCTR_SIO0CKD	0x00020000
+#define TX4927_CLKCTR_SIO1CKD	0x00010000
+#define TX4927_CLKCTR_ACLRST	0x00000200
+#define TX4927_CLKCTR_PIORST	0x00000100
+#define TX4927_CLKCTR_DMARST	0x00000080
+#define TX4927_CLKCTR_PCIRST	0x00000040
+#define TX4927_CLKCTR_TM0RST	0x00000010
+#define TX4927_CLKCTR_TM1RST	0x00000008
+#define TX4927_CLKCTR_TM2RST	0x00000004
+#define TX4927_CLKCTR_SIO0RST	0x00000002
+#define TX4927_CLKCTR_SIO1RST	0x00000001
+
+#define tx4927_sdramcptr \
+		((struct tx4927_sdramc_reg __iomem *)TX4927_SDRAMC_REG)
+#define tx4927_pcicptr \
+		((struct tx4927_pcic_reg __iomem *)TX4927_PCIC_REG)
+#define tx4927_ccfgptr \
+		((struct tx4927_ccfg_reg __iomem *)TX4927_CCFG_REG)
+#define tx4927_ebuscptr \
+		((struct tx4927_ebusc_reg __iomem *)TX4927_EBUSC_REG)
+#define tx4927_pioptr		((struct txx9_pio_reg __iomem *)TX4927_PIO_REG)
+
+#define TX4927_REV_PCODE()	\
+	((__u32)__raw_readq(&tx4927_ccfgptr->crir) >> 16)
+
+#define TX4927_SDRAMC_CR(ch)	__raw_readq(&tx4927_sdramcptr->cr[(ch)])
+#define TX4927_SDRAMC_BA(ch)	((TX4927_SDRAMC_CR(ch) >> 49) << 21)
+#define TX4927_SDRAMC_SIZE(ch)	\
+	((((TX4927_SDRAMC_CR(ch) >> 33) & 0x7fff) + 1) << 21)
+
+#define TX4927_EBUSC_CR(ch)	__raw_readq(&tx4927_ebuscptr->cr[(ch)])
+#define TX4927_EBUSC_BA(ch)	((TX4927_EBUSC_CR(ch) >> 48) << 20)
+#define TX4927_EBUSC_SIZE(ch)	\
+	(0x00100000 << ((unsigned long)(TX4927_EBUSC_CR(ch) >> 8) & 0xf))
+#define TX4927_EBUSC_WIDTH(ch)	\
+	(64 >> ((__u32)(TX4927_EBUSC_CR(ch) >> 20) & 0x3))
+
+/* utilities */
+static inline void txx9_clear64(__u64 __iomem *adr, __u64 bits)
+{
+#ifdef CONFIG_32BIT
+	unsigned long flags;
+	local_irq_save(flags);
+#endif
+	____raw_writeq(____raw_readq(adr) & ~bits, adr);
+#ifdef CONFIG_32BIT
+	local_irq_restore(flags);
+#endif
+}
+static inline void txx9_set64(__u64 __iomem *adr, __u64 bits)
+{
+#ifdef CONFIG_32BIT
+	unsigned long flags;
+	local_irq_save(flags);
+#endif
+	____raw_writeq(____raw_readq(adr) | bits, adr);
+#ifdef CONFIG_32BIT
+	local_irq_restore(flags);
+#endif
+}
+
+/* These functions are not interrupt safe. */
+static inline void tx4927_ccfg_clear(__u64 bits)
+{
+	____raw_writeq(____raw_readq(&tx4927_ccfgptr->ccfg)
+		       & ~(TX4927_CCFG_W1CBITS | bits),
+		       &tx4927_ccfgptr->ccfg);
+}
+static inline void tx4927_ccfg_set(__u64 bits)
+{
+	____raw_writeq((____raw_readq(&tx4927_ccfgptr->ccfg)
+			& ~TX4927_CCFG_W1CBITS) | bits,
+		       &tx4927_ccfgptr->ccfg);
+}
+static inline void tx4927_ccfg_change(__u64 change, __u64 new)
+{
+	____raw_writeq((____raw_readq(&tx4927_ccfgptr->ccfg)
+			& ~(TX4927_CCFG_W1CBITS | change)) |
+		       new,
+		       &tx4927_ccfgptr->ccfg);
+}
+
+unsigned int tx4927_get_mem_size(void);
+void tx4927_wdt_init(void);
+void tx4927_setup(void);
+void tx4927_time_init(unsigned int tmrnr);
+void tx4927_sio_init(unsigned int sclk, unsigned int cts_mask);
+int tx4927_report_pciclk(void);
+int tx4927_pciclk66_setup(void);
+void tx4927_setup_pcierr_irq(void);
+void tx4927_irq_init(void);
+void tx4927_mtd_init(int ch);
+
+#endif /* __ASM_TXX9_TX4927_H */
diff --git a/include/asm-mips/txx9/tx4927pcic.h b/arch/mips/include/asm/txx9/tx4927pcic.h
similarity index 100%
rename from include/asm-mips/txx9/tx4927pcic.h
rename to arch/mips/include/asm/txx9/tx4927pcic.h
diff --git a/arch/mips/include/asm/txx9/tx4938.h b/arch/mips/include/asm/txx9/tx4938.h
new file mode 100644
index 0000000..989e775
--- /dev/null
+++ b/arch/mips/include/asm/txx9/tx4938.h
@@ -0,0 +1,295 @@
+/*
+ * Definitions for TX4937/TX4938
+ * Copyright (C) 2000-2001 Toshiba Corporation
+ *
+ * 2003-2005 (c) MontaVista Software, Inc. This file is licensed under the
+ * terms of the GNU General Public License version 2. This program is
+ * licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ *
+ * Support for TX4938 in 2.6 - Manish Lachwani (mlachwani@mvista.com)
+ */
+#ifndef __ASM_TXX9_TX4938_H
+#define __ASM_TXX9_TX4938_H
+
+/* some controllers are compatible with 4927 */
+#include <asm/txx9/tx4927.h>
+
+#ifdef CONFIG_64BIT
+#define TX4938_REG_BASE	0xffffffffff1f0000UL /* == TX4937_REG_BASE */
+#else
+#define TX4938_REG_BASE	0xff1f0000UL /* == TX4937_REG_BASE */
+#endif
+#define TX4938_REG_SIZE	0x00010000 /* == TX4937_REG_SIZE */
+
+/* NDFMC, SRAMC, PCIC1, SPIC: TX4938 only */
+#define TX4938_NDFMC_REG	(TX4938_REG_BASE + 0x5000)
+#define TX4938_SRAMC_REG	(TX4938_REG_BASE + 0x6000)
+#define TX4938_PCIC1_REG	(TX4938_REG_BASE + 0x7000)
+#define TX4938_SDRAMC_REG	(TX4938_REG_BASE + 0x8000)
+#define TX4938_EBUSC_REG	(TX4938_REG_BASE + 0x9000)
+#define TX4938_DMA_REG(ch)	(TX4938_REG_BASE + 0xb000 + (ch) * 0x800)
+#define TX4938_PCIC_REG		(TX4938_REG_BASE + 0xd000)
+#define TX4938_CCFG_REG		(TX4938_REG_BASE + 0xe000)
+#define TX4938_NR_TMR	3
+#define TX4938_TMR_REG(ch)	((TX4938_REG_BASE + 0xf000) + (ch) * 0x100)
+#define TX4938_NR_SIO	2
+#define TX4938_SIO_REG(ch)	((TX4938_REG_BASE + 0xf300) + (ch) * 0x100)
+#define TX4938_PIO_REG		(TX4938_REG_BASE + 0xf500)
+#define TX4938_IRC_REG		(TX4938_REG_BASE + 0xf600)
+#define TX4938_ACLC_REG		(TX4938_REG_BASE + 0xf700)
+#define TX4938_SPI_REG		(TX4938_REG_BASE + 0xf800)
+
+struct tx4938_sramc_reg {
+	u64 cr;
+};
+
+struct tx4938_ccfg_reg {
+	u64 ccfg;
+	u64 crir;
+	u64 pcfg;
+	u64 toea;
+	u64 clkctr;
+	u64 unused0;
+	u64 garbc;
+	u64 unused1;
+	u64 unused2;
+	u64 ramp;
+	u64 unused3;
+	u64 jmpadr;
+};
+
+/*
+ * IRC
+ */
+
+#define TX4938_IR_ECCERR	0
+#define TX4938_IR_WTOERR	1
+#define TX4938_NUM_IR_INT	6
+#define TX4938_IR_INT(n)	(2 + (n))
+#define TX4938_NUM_IR_SIO	2
+#define TX4938_IR_SIO(n)	(8 + (n))
+#define TX4938_NUM_IR_DMA	4
+#define TX4938_IR_DMA(ch, n)	((ch ? 27 : 10) + (n)) /* 10-13, 27-30 */
+#define TX4938_IR_PIO	14
+#define TX4938_IR_PDMAC	15
+#define TX4938_IR_PCIC	16
+#define TX4938_NUM_IR_TMR	3
+#define TX4938_IR_TMR(n)	(17 + (n))
+#define TX4938_IR_NDFMC	21
+#define TX4938_IR_PCIERR	22
+#define TX4938_IR_PCIPME	23
+#define TX4938_IR_ACLC	24
+#define TX4938_IR_ACLCPME	25
+#define TX4938_IR_PCIC1	26
+#define TX4938_IR_SPI	31
+#define TX4938_NUM_IR	32
+/* multiplex */
+#define TX4938_IR_ETH0	TX4938_IR_INT(4)
+#define TX4938_IR_ETH1	TX4938_IR_INT(3)
+
+#define TX4938_IRC_INT	2	/* IP[2] in Status register */
+
+#define TX4938_NUM_PIO	16
+
+/*
+ * CCFG
+ */
+/* CCFG : Chip Configuration */
+#define TX4938_CCFG_WDRST	0x0000020000000000ULL
+#define TX4938_CCFG_WDREXEN	0x0000010000000000ULL
+#define TX4938_CCFG_BCFG_MASK	0x000000ff00000000ULL
+#define TX4938_CCFG_TINTDIS	0x01000000
+#define TX4938_CCFG_PCI66	0x00800000
+#define TX4938_CCFG_PCIMODE	0x00400000
+#define TX4938_CCFG_PCI1_66	0x00200000
+#define TX4938_CCFG_DIVMODE_MASK	0x001e0000
+#define TX4938_CCFG_DIVMODE_2	(0x4 << 17)
+#define TX4938_CCFG_DIVMODE_2_5	(0xf << 17)
+#define TX4938_CCFG_DIVMODE_3	(0x5 << 17)
+#define TX4938_CCFG_DIVMODE_4	(0x6 << 17)
+#define TX4938_CCFG_DIVMODE_4_5	(0xd << 17)
+#define TX4938_CCFG_DIVMODE_8	(0x0 << 17)
+#define TX4938_CCFG_DIVMODE_10	(0xb << 17)
+#define TX4938_CCFG_DIVMODE_12	(0x1 << 17)
+#define TX4938_CCFG_DIVMODE_16	(0x2 << 17)
+#define TX4938_CCFG_DIVMODE_18	(0x9 << 17)
+#define TX4938_CCFG_BEOW	0x00010000
+#define TX4938_CCFG_WR	0x00008000
+#define TX4938_CCFG_TOE	0x00004000
+#define TX4938_CCFG_PCIARB	0x00002000
+#define TX4938_CCFG_PCIDIVMODE_MASK	0x00001c00
+#define TX4938_CCFG_PCIDIVMODE_4	(0x1 << 10)
+#define TX4938_CCFG_PCIDIVMODE_4_5	(0x3 << 10)
+#define TX4938_CCFG_PCIDIVMODE_5	(0x5 << 10)
+#define TX4938_CCFG_PCIDIVMODE_5_5	(0x7 << 10)
+#define TX4938_CCFG_PCIDIVMODE_8	(0x0 << 10)
+#define TX4938_CCFG_PCIDIVMODE_9	(0x2 << 10)
+#define TX4938_CCFG_PCIDIVMODE_10	(0x4 << 10)
+#define TX4938_CCFG_PCIDIVMODE_11	(0x6 << 10)
+#define TX4938_CCFG_PCI1DMD	0x00000100
+#define TX4938_CCFG_SYSSP_MASK	0x000000c0
+#define TX4938_CCFG_ENDIAN	0x00000004
+#define TX4938_CCFG_HALT	0x00000002
+#define TX4938_CCFG_ACEHOLD	0x00000001
+
+/* PCFG : Pin Configuration */
+#define TX4938_PCFG_ETH0_SEL	0x8000000000000000ULL
+#define TX4938_PCFG_ETH1_SEL	0x4000000000000000ULL
+#define TX4938_PCFG_ATA_SEL	0x2000000000000000ULL
+#define TX4938_PCFG_ISA_SEL	0x1000000000000000ULL
+#define TX4938_PCFG_SPI_SEL	0x0800000000000000ULL
+#define TX4938_PCFG_NDF_SEL	0x0400000000000000ULL
+#define TX4938_PCFG_SDCLKDLY_MASK	0x30000000
+#define TX4938_PCFG_SDCLKDLY(d)	((d)<<28)
+#define TX4938_PCFG_SYSCLKEN	0x08000000
+#define TX4938_PCFG_SDCLKEN_ALL	0x07800000
+#define TX4938_PCFG_SDCLKEN(ch)	(0x00800000<<(ch))
+#define TX4938_PCFG_PCICLKEN_ALL	0x003f0000
+#define TX4938_PCFG_PCICLKEN(ch)	(0x00010000<<(ch))
+#define TX4938_PCFG_SEL2	0x00000200
+#define TX4938_PCFG_SEL1	0x00000100
+#define TX4938_PCFG_DMASEL_ALL	0x0000000f
+#define TX4938_PCFG_DMASEL0_DRQ0	0x00000000
+#define TX4938_PCFG_DMASEL0_SIO1	0x00000001
+#define TX4938_PCFG_DMASEL1_DRQ1	0x00000000
+#define TX4938_PCFG_DMASEL1_SIO1	0x00000002
+#define TX4938_PCFG_DMASEL2_DRQ2	0x00000000
+#define TX4938_PCFG_DMASEL2_SIO0	0x00000004
+#define TX4938_PCFG_DMASEL3_DRQ3	0x00000000
+#define TX4938_PCFG_DMASEL3_SIO0	0x00000008
+
+/* CLKCTR : Clock Control */
+#define TX4938_CLKCTR_NDFCKD	0x0001000000000000ULL
+#define TX4938_CLKCTR_NDFRST	0x0000000100000000ULL
+#define TX4938_CLKCTR_ETH1CKD	0x80000000
+#define TX4938_CLKCTR_ETH0CKD	0x40000000
+#define TX4938_CLKCTR_SPICKD	0x20000000
+#define TX4938_CLKCTR_SRAMCKD	0x10000000
+#define TX4938_CLKCTR_PCIC1CKD	0x08000000
+#define TX4938_CLKCTR_DMA1CKD	0x04000000
+#define TX4938_CLKCTR_ACLCKD	0x02000000
+#define TX4938_CLKCTR_PIOCKD	0x01000000
+#define TX4938_CLKCTR_DMACKD	0x00800000
+#define TX4938_CLKCTR_PCICKD	0x00400000
+#define TX4938_CLKCTR_TM0CKD	0x00100000
+#define TX4938_CLKCTR_TM1CKD	0x00080000
+#define TX4938_CLKCTR_TM2CKD	0x00040000
+#define TX4938_CLKCTR_SIO0CKD	0x00020000
+#define TX4938_CLKCTR_SIO1CKD	0x00010000
+#define TX4938_CLKCTR_ETH1RST	0x00008000
+#define TX4938_CLKCTR_ETH0RST	0x00004000
+#define TX4938_CLKCTR_SPIRST	0x00002000
+#define TX4938_CLKCTR_SRAMRST	0x00001000
+#define TX4938_CLKCTR_PCIC1RST	0x00000800
+#define TX4938_CLKCTR_DMA1RST	0x00000400
+#define TX4938_CLKCTR_ACLRST	0x00000200
+#define TX4938_CLKCTR_PIORST	0x00000100
+#define TX4938_CLKCTR_DMARST	0x00000080
+#define TX4938_CLKCTR_PCIRST	0x00000040
+#define TX4938_CLKCTR_TM0RST	0x00000010
+#define TX4938_CLKCTR_TM1RST	0x00000008
+#define TX4938_CLKCTR_TM2RST	0x00000004
+#define TX4938_CLKCTR_SIO0RST	0x00000002
+#define TX4938_CLKCTR_SIO1RST	0x00000001
+
+/*
+ * DMA
+ */
+/* bits for MCR */
+#define TX4938_DMA_MCR_EIS(ch)	(0x10000000<<(ch))
+#define TX4938_DMA_MCR_DIS(ch)	(0x01000000<<(ch))
+#define TX4938_DMA_MCR_RSFIF	0x00000080
+#define TX4938_DMA_MCR_FIFUM(ch)	(0x00000008<<(ch))
+#define TX4938_DMA_MCR_RPRT	0x00000002
+#define TX4938_DMA_MCR_MSTEN	0x00000001
+
+/* bits for CCRn */
+#define TX4938_DMA_CCR_IMMCHN	0x20000000
+#define TX4938_DMA_CCR_USEXFSZ	0x10000000
+#define TX4938_DMA_CCR_LE	0x08000000
+#define TX4938_DMA_CCR_DBINH	0x04000000
+#define TX4938_DMA_CCR_SBINH	0x02000000
+#define TX4938_DMA_CCR_CHRST	0x01000000
+#define TX4938_DMA_CCR_RVBYTE	0x00800000
+#define TX4938_DMA_CCR_ACKPOL	0x00400000
+#define TX4938_DMA_CCR_REQPL	0x00200000
+#define TX4938_DMA_CCR_EGREQ	0x00100000
+#define TX4938_DMA_CCR_CHDN	0x00080000
+#define TX4938_DMA_CCR_DNCTL	0x00060000
+#define TX4938_DMA_CCR_EXTRQ	0x00010000
+#define TX4938_DMA_CCR_INTRQD	0x0000e000
+#define TX4938_DMA_CCR_INTENE	0x00001000
+#define TX4938_DMA_CCR_INTENC	0x00000800
+#define TX4938_DMA_CCR_INTENT	0x00000400
+#define TX4938_DMA_CCR_CHNEN	0x00000200
+#define TX4938_DMA_CCR_XFACT	0x00000100
+#define TX4938_DMA_CCR_SMPCHN	0x00000020
+#define TX4938_DMA_CCR_XFSZ(order)	(((order) << 2) & 0x0000001c)
+#define TX4938_DMA_CCR_XFSZ_1W	TX4938_DMA_CCR_XFSZ(2)
+#define TX4938_DMA_CCR_XFSZ_2W	TX4938_DMA_CCR_XFSZ(3)
+#define TX4938_DMA_CCR_XFSZ_4W	TX4938_DMA_CCR_XFSZ(4)
+#define TX4938_DMA_CCR_XFSZ_8W	TX4938_DMA_CCR_XFSZ(5)
+#define TX4938_DMA_CCR_XFSZ_16W	TX4938_DMA_CCR_XFSZ(6)
+#define TX4938_DMA_CCR_XFSZ_32W	TX4938_DMA_CCR_XFSZ(7)
+#define TX4938_DMA_CCR_MEMIO	0x00000002
+#define TX4938_DMA_CCR_SNGAD	0x00000001
+
+/* bits for CSRn */
+#define TX4938_DMA_CSR_CHNEN	0x00000400
+#define TX4938_DMA_CSR_STLXFER	0x00000200
+#define TX4938_DMA_CSR_CHNACT	0x00000100
+#define TX4938_DMA_CSR_ABCHC	0x00000080
+#define TX4938_DMA_CSR_NCHNC	0x00000040
+#define TX4938_DMA_CSR_NTRNFC	0x00000020
+#define TX4938_DMA_CSR_EXTDN	0x00000010
+#define TX4938_DMA_CSR_CFERR	0x00000008
+#define TX4938_DMA_CSR_CHERR	0x00000004
+#define TX4938_DMA_CSR_DESERR	0x00000002
+#define TX4938_DMA_CSR_SORERR	0x00000001
+
+#define tx4938_sdramcptr	tx4927_sdramcptr
+#define tx4938_ebuscptr		tx4927_ebuscptr
+#define tx4938_pcicptr		tx4927_pcicptr
+#define tx4938_pcic1ptr \
+		((struct tx4927_pcic_reg __iomem *)TX4938_PCIC1_REG)
+#define tx4938_ccfgptr \
+		((struct tx4938_ccfg_reg __iomem *)TX4938_CCFG_REG)
+#define tx4938_pioptr		((struct txx9_pio_reg __iomem *)TX4938_PIO_REG)
+#define tx4938_sramcptr \
+		((struct tx4938_sramc_reg __iomem *)TX4938_SRAMC_REG)
+
+
+#define TX4938_REV_PCODE()	\
+	((__u32)__raw_readq(&tx4938_ccfgptr->crir) >> 16)
+
+#define tx4938_ccfg_clear(bits)	tx4927_ccfg_clear(bits)
+#define tx4938_ccfg_set(bits)	tx4927_ccfg_set(bits)
+#define tx4938_ccfg_change(change, new)	tx4927_ccfg_change(change, new)
+
+#define TX4938_SDRAMC_CR(ch)	TX4927_SDRAMC_CR(ch)
+#define TX4938_SDRAMC_BA(ch)	TX4927_SDRAMC_BA(ch)
+#define TX4938_SDRAMC_SIZE(ch)	TX4927_SDRAMC_SIZE(ch)
+
+#define TX4938_EBUSC_CR(ch)	TX4927_EBUSC_CR(ch)
+#define TX4938_EBUSC_BA(ch)	TX4927_EBUSC_BA(ch)
+#define TX4938_EBUSC_SIZE(ch)	TX4927_EBUSC_SIZE(ch)
+#define TX4938_EBUSC_WIDTH(ch)	TX4927_EBUSC_WIDTH(ch)
+
+#define tx4938_get_mem_size() tx4927_get_mem_size()
+void tx4938_wdt_init(void);
+void tx4938_setup(void);
+void tx4938_time_init(unsigned int tmrnr);
+void tx4938_sio_init(unsigned int sclk, unsigned int cts_mask);
+void tx4938_spi_init(int busid);
+void tx4938_ethaddr_init(unsigned char *addr0, unsigned char *addr1);
+int tx4938_report_pciclk(void);
+void tx4938_report_pci1clk(void);
+int tx4938_pciclk66_setup(void);
+struct pci_dev;
+int tx4938_pcic1_map_irq(const struct pci_dev *dev, u8 slot);
+void tx4938_setup_pcierr_irq(void);
+void tx4938_irq_init(void);
+void tx4938_mtd_init(int ch);
+
+#endif
diff --git a/arch/mips/include/asm/txx9/tx4939.h b/arch/mips/include/asm/txx9/tx4939.h
new file mode 100644
index 0000000..88badb4
--- /dev/null
+++ b/arch/mips/include/asm/txx9/tx4939.h
@@ -0,0 +1,545 @@
+/*
+ * Definitions for TX4939
+ *
+ * Copyright (C) 2000-2001,2005-2006 Toshiba Corporation
+ * 2003-2005 (c) MontaVista Software, Inc. This file is licensed under the
+ * terms of the GNU General Public License version 2. This program is
+ * licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ */
+#ifndef __ASM_TXX9_TX4939_H
+#define __ASM_TXX9_TX4939_H
+
+/* some controllers are compatible with 4927/4938 */
+#include <asm/txx9/tx4938.h>
+
+#ifdef CONFIG_64BIT
+#define TX4939_REG_BASE	0xffffffffff1f0000UL /* == TX4938_REG_BASE */
+#else
+#define TX4939_REG_BASE	0xff1f0000UL /* == TX4938_REG_BASE */
+#endif
+#define TX4939_REG_SIZE	0x00010000 /* == TX4938_REG_SIZE */
+
+#define TX4939_ATA_REG(ch)	(TX4939_REG_BASE + 0x3000 + (ch) * 0x1000)
+#define TX4939_NDFMC_REG	(TX4939_REG_BASE + 0x5000)
+#define TX4939_SRAMC_REG	(TX4939_REG_BASE + 0x6000)
+#define TX4939_CRYPTO_REG	(TX4939_REG_BASE + 0x6800)
+#define TX4939_PCIC1_REG	(TX4939_REG_BASE + 0x7000)
+#define TX4939_DDRC_REG		(TX4939_REG_BASE + 0x8000)
+#define TX4939_EBUSC_REG	(TX4939_REG_BASE + 0x9000)
+#define TX4939_VPC_REG		(TX4939_REG_BASE + 0xa000)
+#define TX4939_DMA_REG(ch)	(TX4939_REG_BASE + 0xb000 + (ch) * 0x800)
+#define TX4939_PCIC_REG		(TX4939_REG_BASE + 0xd000)
+#define TX4939_CCFG_REG		(TX4939_REG_BASE + 0xe000)
+#define TX4939_IRC_REG		(TX4939_REG_BASE + 0xe800)
+#define TX4939_NR_TMR	6	/* 0xf000,0xf100,0xf200,0xfd00,0xfe00,0xff00 */
+#define TX4939_TMR_REG(ch)	\
+	(TX4939_REG_BASE + 0xf000 + ((ch) + ((ch) >= 3) * 10) * 0x100)
+#define TX4939_NR_SIO	4	/* 0xf300, 0xf400, 0xf380, 0xf480 */
+#define TX4939_SIO_REG(ch)	\
+	(TX4939_REG_BASE + 0xf300 + (((ch) & 1) << 8) + (((ch) & 2) << 6))
+#define TX4939_ACLC_REG		(TX4939_REG_BASE + 0xf700)
+#define TX4939_SPI_REG		(TX4939_REG_BASE + 0xf800)
+#define TX4939_I2C_REG		(TX4939_REG_BASE + 0xf900)
+#define TX4939_I2S_REG		(TX4939_REG_BASE + 0xfa00)
+#define TX4939_RTC_REG		(TX4939_REG_BASE + 0xfb00)
+#define TX4939_CIR_REG		(TX4939_REG_BASE + 0xfc00)
+
+struct tx4939_le_reg {
+	__u32 r;
+	__u32 unused;
+};
+
+struct tx4939_ddrc_reg {
+	struct tx4939_le_reg ctl[47];
+	__u64 unused0[17];
+	__u64 winen;
+	__u64 win[4];
+};
+
+struct tx4939_ccfg_reg {
+	__u64 ccfg;
+	__u64 crir;
+	__u64 pcfg;
+	__u64 toea;
+	__u64 clkctr;
+	__u64 unused0;
+	__u64 garbc;
+	__u64 unused1[2];
+	__u64 ramp;
+	__u64 unused2[2];
+	__u64 dskwctrl;
+	__u64 mclkosc;
+	__u64 mclkctl;
+	__u64 unused3[17];
+	struct {
+		__u64 mr;
+		__u64 dr;
+	} gpio[2];
+};
+
+struct tx4939_irc_reg {
+	struct tx4939_le_reg den;
+	struct tx4939_le_reg scipb;
+	struct tx4939_le_reg dm[2];
+	struct tx4939_le_reg lvl[16];
+	struct tx4939_le_reg msk;
+	struct tx4939_le_reg edc;
+	struct tx4939_le_reg pnd0;
+	struct tx4939_le_reg cs;
+	struct tx4939_le_reg pnd1;
+	struct tx4939_le_reg dm2[2];
+	struct tx4939_le_reg dbr[2];
+	struct tx4939_le_reg dben;
+	struct tx4939_le_reg unused0[2];
+	struct tx4939_le_reg flag[2];
+	struct tx4939_le_reg pol;
+	struct tx4939_le_reg cnt;
+	struct tx4939_le_reg maskint;
+	struct tx4939_le_reg maskext;
+};
+
+struct tx4939_rtc_reg {
+	__u32 ctl;
+	__u32 adr;
+	__u32 dat;
+	__u32 tbc;
+};
+
+struct tx4939_crypto_reg {
+	struct tx4939_le_reg csr;
+	struct tx4939_le_reg idesptr;
+	struct tx4939_le_reg cdesptr;
+	struct tx4939_le_reg buserr;
+	struct tx4939_le_reg cip_tout;
+	struct tx4939_le_reg cir;
+	union {
+		struct {
+			struct tx4939_le_reg data[8];
+			struct tx4939_le_reg ctrl;
+		} gen;
+		struct {
+			struct {
+				struct tx4939_le_reg l;
+				struct tx4939_le_reg u;
+			} key[3], ini;
+			struct tx4939_le_reg ctrl;
+		} des;
+		struct {
+			struct tx4939_le_reg key[4];
+			struct tx4939_le_reg ini[4];
+			struct tx4939_le_reg ctrl;
+		} aes;
+		struct {
+			struct {
+				struct tx4939_le_reg l;
+				struct tx4939_le_reg u;
+			} cnt;
+			struct tx4939_le_reg ini[5];
+			struct tx4939_le_reg unused;
+			struct tx4939_le_reg ctrl;
+		} hash;
+	} cdr;
+	struct tx4939_le_reg unused0[7];
+	struct tx4939_le_reg rcsr;
+	struct tx4939_le_reg rpr;
+	__u64 rdr;
+	__u64 ror[3];
+	struct tx4939_le_reg unused1[2];
+	struct tx4939_le_reg xorslr;
+	struct tx4939_le_reg xorsur;
+};
+
+struct tx4939_crypto_desc {
+	__u32 src;
+	__u32 dst;
+	__u32 next;
+	__u32 ctrl;
+	__u32 index;
+	__u32 xor;
+};
+
+struct tx4939_vpc_reg {
+	struct tx4939_le_reg csr;
+	struct {
+		struct tx4939_le_reg ctrlA;
+		struct tx4939_le_reg ctrlB;
+		struct tx4939_le_reg idesptr;
+		struct tx4939_le_reg cdesptr;
+	} port[3];
+	struct tx4939_le_reg buserr;
+};
+
+struct tx4939_vpc_desc {
+	__u32 src;
+	__u32 next;
+	__u32 ctrl1;
+	__u32 ctrl2;
+};
+
+/*
+ * IRC
+ */
+#define TX4939_IR_NONE	0
+#define TX4939_IR_DDR	1
+#define TX4939_IR_WTOERR	2
+#define TX4939_NUM_IR_INT	3
+#define TX4939_IR_INT(n)	(3 + (n))
+#define TX4939_NUM_IR_ETH	2
+#define TX4939_IR_ETH(n)	((n) ? 43 : 6)
+#define TX4939_IR_VIDEO	7
+#define TX4939_IR_CIR	8
+#define TX4939_NUM_IR_SIO	4
+#define TX4939_IR_SIO(n)	((n) ? 43 + (n) : 9)	/* 9,44-46 */
+#define TX4939_NUM_IR_DMA	4
+#define TX4939_IR_DMA(ch, n)	(((ch) ? 22 : 10) + (n)) /* 10-13,22-25 */
+#define TX4939_IR_IRC	14
+#define TX4939_IR_PDMAC	15
+#define TX4939_NUM_IR_TMR	6
+#define TX4939_IR_TMR(n)	(((n) >= 3 ? 45 : 16) + (n)) /* 16-18,48-50 */
+#define TX4939_NUM_IR_ATA	2
+#define TX4939_IR_ATA(n)	(19 + (n))
+#define TX4939_IR_ACLC	21
+#define TX4939_IR_CIPHER	26
+#define TX4939_IR_INTA	27
+#define TX4939_IR_INTB	28
+#define TX4939_IR_INTC	29
+#define TX4939_IR_INTD	30
+#define TX4939_IR_I2C	33
+#define TX4939_IR_SPI	34
+#define TX4939_IR_PCIC	35
+#define TX4939_IR_PCIC1	36
+#define TX4939_IR_PCIERR	37
+#define TX4939_IR_PCIPME	38
+#define TX4939_IR_NDFMC	39
+#define TX4939_IR_ACLCPME	40
+#define TX4939_IR_RTC	41
+#define TX4939_IR_RND	42
+#define TX4939_IR_I2S	47
+#define TX4939_NUM_IR	64
+
+#define TX4939_IRC_INT	2	/* IP[2] in Status register */
+
+/*
+ * CCFG
+ */
+/* CCFG : Chip Configuration */
+#define TX4939_CCFG_PCIBOOT	0x0000040000000000ULL
+#define TX4939_CCFG_WDRST	0x0000020000000000ULL
+#define TX4939_CCFG_WDREXEN	0x0000010000000000ULL
+#define TX4939_CCFG_BCFG_MASK	0x000000ff00000000ULL
+#define TX4939_CCFG_GTOT_MASK	0x06000000
+#define TX4939_CCFG_GTOT_4096	0x06000000
+#define TX4939_CCFG_GTOT_2048	0x04000000
+#define TX4939_CCFG_GTOT_1024	0x02000000
+#define TX4939_CCFG_GTOT_512	0x00000000
+#define TX4939_CCFG_TINTDIS	0x01000000
+#define TX4939_CCFG_PCI66	0x00800000
+#define TX4939_CCFG_PCIMODE	0x00400000
+#define TX4939_CCFG_SSCG	0x00100000
+#define TX4939_CCFG_MULCLK_MASK	0x000e0000
+#define TX4939_CCFG_MULCLK_8	(0x7 << 17)
+#define TX4939_CCFG_MULCLK_9	(0x0 << 17)
+#define TX4939_CCFG_MULCLK_10	(0x1 << 17)
+#define TX4939_CCFG_MULCLK_11	(0x2 << 17)
+#define TX4939_CCFG_MULCLK_12	(0x3 << 17)
+#define TX4939_CCFG_MULCLK_13	(0x4 << 17)
+#define TX4939_CCFG_MULCLK_14	(0x5 << 17)
+#define TX4939_CCFG_MULCLK_15	(0x6 << 17)
+#define TX4939_CCFG_BEOW	0x00010000
+#define TX4939_CCFG_WR	0x00008000
+#define TX4939_CCFG_TOE	0x00004000
+#define TX4939_CCFG_PCIARB	0x00002000
+#define TX4939_CCFG_YDIVMODE_MASK	0x00001c00
+#define TX4939_CCFG_YDIVMODE_2	(0x0 << 10)
+#define TX4939_CCFG_YDIVMODE_3	(0x1 << 10)
+#define TX4939_CCFG_YDIVMODE_5	(0x6 << 10)
+#define TX4939_CCFG_YDIVMODE_6	(0x7 << 10)
+#define TX4939_CCFG_PTSEL	0x00000200
+#define TX4939_CCFG_BESEL	0x00000100
+#define TX4939_CCFG_SYSSP_MASK	0x000000c0
+#define TX4939_CCFG_ACKSEL	0x00000020
+#define TX4939_CCFG_ROMW	0x00000010
+#define TX4939_CCFG_ENDIAN	0x00000004
+#define TX4939_CCFG_ARMODE	0x00000002
+#define TX4939_CCFG_ACEHOLD	0x00000001
+
+/* PCFG : Pin Configuration */
+#define TX4939_PCFG_SIO2MODE_MASK	0xc000000000000000ULL
+#define TX4939_PCFG_SIO2MODE_GPIO	0x8000000000000000ULL
+#define TX4939_PCFG_SIO2MODE_SIO2	0x4000000000000000ULL
+#define TX4939_PCFG_SIO2MODE_SIO0	0x0000000000000000ULL
+#define TX4939_PCFG_SPIMODE	0x2000000000000000ULL
+#define TX4939_PCFG_I2CMODE	0x1000000000000000ULL
+#define TX4939_PCFG_I2SMODE_MASK	0x0c00000000000000ULL
+#define TX4939_PCFG_I2SMODE_GPIO	0x0c00000000000000ULL
+#define TX4939_PCFG_I2SMODE_I2S	0x0800000000000000ULL
+#define TX4939_PCFG_I2SMODE_I2S_ALT	0x0400000000000000ULL
+#define TX4939_PCFG_I2SMODE_ACLC	0x0000000000000000ULL
+#define TX4939_PCFG_SIO3MODE	0x0200000000000000ULL
+#define TX4939_PCFG_DMASEL3	0x0004000000000000ULL
+#define TX4939_PCFG_DMASEL3_SIO0	0x0004000000000000ULL
+#define TX4939_PCFG_DMASEL3_NDFC	0x0000000000000000ULL
+#define TX4939_PCFG_VSSMODE	0x0000200000000000ULL
+#define TX4939_PCFG_VPSMODE	0x0000100000000000ULL
+#define TX4939_PCFG_ET1MODE	0x0000080000000000ULL
+#define TX4939_PCFG_ET0MODE	0x0000040000000000ULL
+#define TX4939_PCFG_ATA1MODE	0x0000020000000000ULL
+#define TX4939_PCFG_ATA0MODE	0x0000010000000000ULL
+#define TX4939_PCFG_BP_PLL	0x0000000100000000ULL
+
+#define TX4939_PCFG_SYSCLKEN	0x08000000
+#define TX4939_PCFG_PCICLKEN_ALL	0x000f0000
+#define TX4939_PCFG_PCICLKEN(ch)	(0x00010000<<(ch))
+#define TX4939_PCFG_SPEED1	0x00002000
+#define TX4939_PCFG_SPEED0	0x00001000
+#define TX4939_PCFG_ITMODE	0x00000300
+#define TX4939_PCFG_DMASEL_ALL	(0x00000007 | TX4939_PCFG_DMASEL3)
+#define TX4939_PCFG_DMASEL2	0x00000004
+#define TX4939_PCFG_DMASEL2_DRQ2	0x00000000
+#define TX4939_PCFG_DMASEL2_SIO0	0x00000004
+#define TX4939_PCFG_DMASEL1	0x00000002
+#define TX4939_PCFG_DMASEL1_DRQ1	0x00000000
+#define TX4939_PCFG_DMASEL0	0x00000001
+#define TX4939_PCFG_DMASEL0_DRQ0	0x00000000
+
+/* CLKCTR : Clock Control */
+#define TX4939_CLKCTR_IOSCKD	0x8000000000000000ULL
+#define TX4939_CLKCTR_SYSCKD	0x4000000000000000ULL
+#define TX4939_CLKCTR_TM5CKD	0x2000000000000000ULL
+#define TX4939_CLKCTR_TM4CKD	0x1000000000000000ULL
+#define TX4939_CLKCTR_TM3CKD	0x0800000000000000ULL
+#define TX4939_CLKCTR_CIRCKD	0x0400000000000000ULL
+#define TX4939_CLKCTR_SIO3CKD	0x0200000000000000ULL
+#define TX4939_CLKCTR_SIO2CKD	0x0100000000000000ULL
+#define TX4939_CLKCTR_SIO1CKD	0x0080000000000000ULL
+#define TX4939_CLKCTR_VPCCKD	0x0040000000000000ULL
+#define TX4939_CLKCTR_EPCICKD	0x0020000000000000ULL
+#define TX4939_CLKCTR_ETH1CKD	0x0008000000000000ULL
+#define TX4939_CLKCTR_ATA1CKD	0x0004000000000000ULL
+#define TX4939_CLKCTR_BROMCKD	0x0002000000000000ULL
+#define TX4939_CLKCTR_NDCCKD	0x0001000000000000ULL
+#define TX4939_CLKCTR_I2CCKD	0x0000800000000000ULL
+#define TX4939_CLKCTR_ETH0CKD	0x0000400000000000ULL
+#define TX4939_CLKCTR_SPICKD	0x0000200000000000ULL
+#define TX4939_CLKCTR_SRAMCKD	0x0000100000000000ULL
+#define TX4939_CLKCTR_PCI1CKD	0x0000080000000000ULL
+#define TX4939_CLKCTR_DMA1CKD	0x0000040000000000ULL
+#define TX4939_CLKCTR_ACLCKD	0x0000020000000000ULL
+#define TX4939_CLKCTR_ATA0CKD	0x0000010000000000ULL
+#define TX4939_CLKCTR_DMA0CKD	0x0000008000000000ULL
+#define TX4939_CLKCTR_PCICCKD	0x0000004000000000ULL
+#define TX4939_CLKCTR_I2SCKD	0x0000002000000000ULL
+#define TX4939_CLKCTR_TM0CKD	0x0000001000000000ULL
+#define TX4939_CLKCTR_TM1CKD	0x0000000800000000ULL
+#define TX4939_CLKCTR_TM2CKD	0x0000000400000000ULL
+#define TX4939_CLKCTR_SIO0CKD	0x0000000200000000ULL
+#define TX4939_CLKCTR_CYPCKD	0x0000000100000000ULL
+#define TX4939_CLKCTR_IOSRST	0x80000000
+#define TX4939_CLKCTR_SYSRST	0x40000000
+#define TX4939_CLKCTR_TM5RST	0x20000000
+#define TX4939_CLKCTR_TM4RST	0x10000000
+#define TX4939_CLKCTR_TM3RST	0x08000000
+#define TX4939_CLKCTR_CIRRST	0x04000000
+#define TX4939_CLKCTR_SIO3RST	0x02000000
+#define TX4939_CLKCTR_SIO2RST	0x01000000
+#define TX4939_CLKCTR_SIO1RST	0x00800000
+#define TX4939_CLKCTR_VPCRST	0x00400000
+#define TX4939_CLKCTR_EPCIRST	0x00200000
+#define TX4939_CLKCTR_ETH1RST	0x00080000
+#define TX4939_CLKCTR_ATA1RST	0x00040000
+#define TX4939_CLKCTR_BROMRST	0x00020000
+#define TX4939_CLKCTR_NDCRST	0x00010000
+#define TX4939_CLKCTR_I2CRST	0x00008000
+#define TX4939_CLKCTR_ETH0RST	0x00004000
+#define TX4939_CLKCTR_SPIRST	0x00002000
+#define TX4939_CLKCTR_SRAMRST	0x00001000
+#define TX4939_CLKCTR_PCI1RST	0x00000800
+#define TX4939_CLKCTR_DMA1RST	0x00000400
+#define TX4939_CLKCTR_ACLRST	0x00000200
+#define TX4939_CLKCTR_ATA0RST	0x00000100
+#define TX4939_CLKCTR_DMA0RST	0x00000080
+#define TX4939_CLKCTR_PCICRST	0x00000040
+#define TX4939_CLKCTR_I2SRST	0x00000020
+#define TX4939_CLKCTR_TM0RST	0x00000010
+#define TX4939_CLKCTR_TM1RST	0x00000008
+#define TX4939_CLKCTR_TM2RST	0x00000004
+#define TX4939_CLKCTR_SIO0RST	0x00000002
+#define TX4939_CLKCTR_CYPRST	0x00000001
+
+/*
+ * RTC
+ */
+#define TX4939_RTCCTL_ALME	0x00000080
+#define TX4939_RTCCTL_ALMD	0x00000040
+#define TX4939_RTCCTL_BUSY	0x00000020
+
+#define TX4939_RTCCTL_COMMAND	0x00000007
+#define TX4939_RTCCTL_COMMAND_NOP	0x00000000
+#define TX4939_RTCCTL_COMMAND_GETTIME	0x00000001
+#define TX4939_RTCCTL_COMMAND_SETTIME	0x00000002
+#define TX4939_RTCCTL_COMMAND_GETALARM	0x00000003
+#define TX4939_RTCCTL_COMMAND_SETALARM	0x00000004
+
+#define TX4939_RTCTBC_PM	0x00000080
+#define TX4939_RTCTBC_COMP	0x0000007f
+
+#define TX4939_RTC_REG_RAMSIZE	0x00000100
+#define TX4939_RTC_REG_RWBSIZE	0x00000006
+
+/*
+ * CRYPTO
+ */
+#define TX4939_CRYPTO_CSR_SAESO	0x08000000
+#define TX4939_CRYPTO_CSR_SAESI	0x04000000
+#define TX4939_CRYPTO_CSR_SDESO	0x02000000
+#define TX4939_CRYPTO_CSR_SDESI	0x01000000
+#define TX4939_CRYPTO_CSR_INDXBST_MASK	0x00700000
+#define TX4939_CRYPTO_CSR_INDXBST(n)	((n) << 20)
+#define TX4939_CRYPTO_CSR_TOINT	0x00080000
+#define TX4939_CRYPTO_CSR_DCINT	0x00040000
+#define TX4939_CRYPTO_CSR_GBINT	0x00010000
+#define TX4939_CRYPTO_CSR_INDXAST_MASK	0x0000e000
+#define TX4939_CRYPTO_CSR_INDXAST(n)	((n) << 13)
+#define TX4939_CRYPTO_CSR_CSWAP_MASK	0x00001800
+#define TX4939_CRYPTO_CSR_CSWAP_NONE	0x00000000
+#define TX4939_CRYPTO_CSR_CSWAP_IN	0x00000800
+#define TX4939_CRYPTO_CSR_CSWAP_OUT	0x00001000
+#define TX4939_CRYPTO_CSR_CSWAP_BOTH	0x00001800
+#define TX4939_CRYPTO_CSR_CDIV_MASK	0x00000600
+#define TX4939_CRYPTO_CSR_CDIV_DIV2	0x00000000
+#define TX4939_CRYPTO_CSR_CDIV_DIV1	0x00000200
+#define TX4939_CRYPTO_CSR_CDIV_DIV2ALT	0x00000400
+#define TX4939_CRYPTO_CSR_CDIV_DIV1ALT	0x00000600
+#define TX4939_CRYPTO_CSR_PDINT_MASK	0x000000c0
+#define TX4939_CRYPTO_CSR_PDINT_ALL	0x00000000
+#define TX4939_CRYPTO_CSR_PDINT_END	0x00000040
+#define TX4939_CRYPTO_CSR_PDINT_NEXT	0x00000080
+#define TX4939_CRYPTO_CSR_PDINT_NONE	0x000000c0
+#define TX4939_CRYPTO_CSR_GINTE	0x00000008
+#define TX4939_CRYPTO_CSR_RSTD	0x00000004
+#define TX4939_CRYPTO_CSR_RSTC	0x00000002
+#define TX4939_CRYPTO_CSR_ENCR	0x00000001
+
+/* bits for tx4939_crypto_reg.cdr.gen.ctrl */
+#define TX4939_CRYPTO_CTX_ENGINE_MASK	0x00000003
+#define TX4939_CRYPTO_CTX_ENGINE_DES	0x00000000
+#define TX4939_CRYPTO_CTX_ENGINE_AES	0x00000001
+#define TX4939_CRYPTO_CTX_ENGINE_MD5	0x00000002
+#define TX4939_CRYPTO_CTX_ENGINE_SHA1	0x00000003
+#define TX4939_CRYPTO_CTX_TDMS	0x00000010
+#define TX4939_CRYPTO_CTX_CMS	0x00000020
+#define TX4939_CRYPTO_CTX_DMS	0x00000040
+#define TX4939_CRYPTO_CTX_UPDATE	0x00000080
+
+/* bits for tx4939_crypto_desc.ctrl */
+#define TX4939_CRYPTO_DESC_OB_CNT_MASK	0xffe00000
+#define TX4939_CRYPTO_DESC_OB_CNT(cnt)	((cnt) << 21)
+#define TX4939_CRYPTO_DESC_IB_CNT_MASK	0x001ffc00
+#define TX4939_CRYPTO_DESC_IB_CNT(cnt)	((cnt) << 10)
+#define TX4939_CRYPTO_DESC_START	0x00000200
+#define TX4939_CRYPTO_DESC_END	0x00000100
+#define TX4939_CRYPTO_DESC_XOR	0x00000010
+#define TX4939_CRYPTO_DESC_LAST	0x00000008
+#define TX4939_CRYPTO_DESC_ERR_MASK	0x00000006
+#define TX4939_CRYPTO_DESC_ERR_NONE	0x00000000
+#define TX4939_CRYPTO_DESC_ERR_TOUT	0x00000002
+#define TX4939_CRYPTO_DESC_ERR_DIGEST	0x00000004
+#define TX4939_CRYPTO_DESC_OWN	0x00000001
+
+/* bits for tx4939_crypto_desc.index */
+#define TX4939_CRYPTO_DESC_HASH_IDX_MASK	0x00000070
+#define TX4939_CRYPTO_DESC_HASH_IDX(idx)	((idx) << 4)
+#define TX4939_CRYPTO_DESC_ENCRYPT_IDX_MASK	0x00000007
+#define TX4939_CRYPTO_DESC_ENCRYPT_IDX(idx)	((idx) << 0)
+
+#define TX4939_CRYPTO_NR_SET	6
+
+#define TX4939_CRYPTO_RCSR_INTE	0x00000008
+#define TX4939_CRYPTO_RCSR_RST	0x00000004
+#define TX4939_CRYPTO_RCSR_FIN	0x00000002
+#define TX4939_CRYPTO_RCSR_ST	0x00000001
+
+/*
+ * VPC
+ */
+#define TX4939_VPC_CSR_GBINT	0x00010000
+#define TX4939_VPC_CSR_SWAPO	0x00000020
+#define TX4939_VPC_CSR_SWAPI	0x00000010
+#define TX4939_VPC_CSR_GINTE	0x00000008
+#define TX4939_VPC_CSR_RSTD	0x00000004
+#define TX4939_VPC_CSR_RSTVPC	0x00000002
+
+#define TX4939_VPC_CTRLA_VDPSN	0x00000200
+#define TX4939_VPC_CTRLA_PBUSY	0x00000100
+#define TX4939_VPC_CTRLA_DCINT	0x00000080
+#define TX4939_VPC_CTRLA_UOINT	0x00000040
+#define TX4939_VPC_CTRLA_PDINT_MASK	0x00000030
+#define TX4939_VPC_CTRLA_PDINT_ALL	0x00000000
+#define TX4939_VPC_CTRLA_PDINT_NEXT	0x00000010
+#define TX4939_VPC_CTRLA_PDINT_NONE	0x00000030
+#define TX4939_VPC_CTRLA_VDVLDP	0x00000008
+#define TX4939_VPC_CTRLA_VDMODE	0x00000004
+#define TX4939_VPC_CTRLA_VDFOR	0x00000002
+#define TX4939_VPC_CTRLA_ENVPC	0x00000001
+
+/* bits for tx4939_vpc_desc.ctrl1 */
+#define TX4939_VPC_DESC_CTRL1_ERR_MASK	0x00000006
+#define TX4939_VPC_DESC_CTRL1_OWN	0x00000001
+
+#define tx4939_ddrcptr	((struct tx4939_ddrc_reg __iomem *)TX4939_DDRC_REG)
+#define tx4939_ebuscptr		tx4938_ebuscptr
+#define tx4939_ircptr \
+		((struct tx4939_irc_reg __iomem *)TX4939_IRC_REG)
+#define tx4939_pcicptr		tx4938_pcicptr
+#define tx4939_pcic1ptr		tx4938_pcic1ptr
+#define tx4939_ccfgptr \
+		((struct tx4939_ccfg_reg __iomem *)TX4939_CCFG_REG)
+#define tx4939_sramcptr		tx4938_sramcptr
+#define tx4939_rtcptr \
+		((struct tx4939_rtc_reg __iomem *)TX4939_RTC_REG)
+#define tx4939_cryptoptr \
+		((struct tx4939_crypto_reg __iomem *)TX4939_CRYPTO_REG)
+#define tx4939_vpcptr	((struct tx4939_vpc_reg __iomem *)TX4939_VPC_REG)
+
+#define TX4939_REV_MAJ_MIN()	\
+	((__u32)__raw_readq(&tx4939_ccfgptr->crir) & 0x00ff)
+#define TX4939_REV_PCODE()	\
+	((__u32)__raw_readq(&tx4939_ccfgptr->crir) >> 16)
+#define TX4939_CCFG_BCFG()	\
+	((__u32)((__raw_readq(&tx4939_ccfgptr->ccfg) & TX4939_CCFG_BCFG_MASK) \
+		 >> 32))
+
+#define tx4939_ccfg_clear(bits)	tx4938_ccfg_clear(bits)
+#define tx4939_ccfg_set(bits)	tx4938_ccfg_set(bits)
+#define tx4939_ccfg_change(change, new)	tx4938_ccfg_change(change, new)
+
+#define TX4939_EBUSC_CR(ch)	TX4927_EBUSC_CR(ch)
+#define TX4939_EBUSC_BA(ch)	TX4927_EBUSC_BA(ch)
+#define TX4939_EBUSC_SIZE(ch)	TX4927_EBUSC_SIZE(ch)
+#define TX4939_EBUSC_WIDTH(ch)	\
+	(16 >> ((__u32)(TX4939_EBUSC_CR(ch) >> 20) & 0x1))
+
+/* SCLK0 = MSTCLK * 429/19 * 16/245 / 2  (14.745MHz for MST 20MHz) */
+#define TX4939_SCLK0(mst)	\
+	((((mst) + 245/2) / 245UL * 429 * 16 + 19) / 19 / 2)
+
+void tx4939_wdt_init(void);
+void tx4939_add_memory_regions(void);
+void tx4939_setup(void);
+void tx4939_time_init(unsigned int tmrnr);
+void tx4939_sio_init(unsigned int sclk, unsigned int cts_mask);
+void tx4939_spi_init(int busid);
+void tx4939_ethaddr_init(unsigned char *addr0, unsigned char *addr1);
+int tx4939_report_pciclk(void);
+void tx4939_report_pci1clk(void);
+struct pci_dev;
+int tx4939_pcic1_map_irq(const struct pci_dev *dev, u8 slot);
+int tx4939_pci_map_irq(const struct pci_dev *dev, u8 slot, u8 pin);
+void tx4939_setup_pcierr_irq(void);
+void tx4939_irq_init(void);
+int tx4939_irq(void);
+void tx4939_mtd_init(int ch);
+void tx4939_ata_init(void);
+
+#endif /* __ASM_TXX9_TX4939_H */
diff --git a/include/asm-mips/txx9irq.h b/arch/mips/include/asm/txx9irq.h
similarity index 100%
rename from include/asm-mips/txx9irq.h
rename to arch/mips/include/asm/txx9irq.h
diff --git a/include/asm-mips/txx9pio.h b/arch/mips/include/asm/txx9pio.h
similarity index 100%
rename from include/asm-mips/txx9pio.h
rename to arch/mips/include/asm/txx9pio.h
diff --git a/include/asm-mips/txx9tmr.h b/arch/mips/include/asm/txx9tmr.h
similarity index 100%
rename from include/asm-mips/txx9tmr.h
rename to arch/mips/include/asm/txx9tmr.h
diff --git a/include/asm-mips/types.h b/arch/mips/include/asm/types.h
similarity index 100%
rename from include/asm-mips/types.h
rename to arch/mips/include/asm/types.h
diff --git a/arch/mips/include/asm/uaccess.h b/arch/mips/include/asm/uaccess.h
new file mode 100644
index 0000000..09ff5bb
--- /dev/null
+++ b/arch/mips/include/asm/uaccess.h
@@ -0,0 +1,1114 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 1996, 1997, 1998, 1999, 2000, 03, 04 by Ralf Baechle
+ * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
+ * Copyright (C) 2007  Maciej W. Rozycki
+ */
+#ifndef _ASM_UACCESS_H
+#define _ASM_UACCESS_H
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/thread_info.h>
+
+/*
+ * The fs value determines whether argument validity checking should be
+ * performed or not.  If get_fs() == USER_DS, checking is performed, with
+ * get_fs() == KERNEL_DS, checking is bypassed.
+ *
+ * For historical reasons, these macros are grossly misnamed.
+ */
+#ifdef CONFIG_32BIT
+
+#define __UA_LIMIT	0x80000000UL
+
+#define __UA_ADDR	".word"
+#define __UA_LA		"la"
+#define __UA_ADDU	"addu"
+#define __UA_t0		"$8"
+#define __UA_t1		"$9"
+
+#endif /* CONFIG_32BIT */
+
+#ifdef CONFIG_64BIT
+
+#define __UA_LIMIT	(- TASK_SIZE)
+
+#define __UA_ADDR	".dword"
+#define __UA_LA		"dla"
+#define __UA_ADDU	"daddu"
+#define __UA_t0		"$12"
+#define __UA_t1		"$13"
+
+#endif /* CONFIG_64BIT */
+
+/*
+ * USER_DS is a bitmask that has the bits set that may not be set in a valid
+ * userspace address.  Note that we limit 32-bit userspace to 0x7fff8000 but
+ * the arithmetic we're doing only works if the limit is a power of two, so
+ * we use 0x80000000 here on 32-bit kernels.  If a process passes an invalid
+ * address in this range it's the process's problem, not ours :-)
+ */
+
+#define KERNEL_DS	((mm_segment_t) { 0UL })
+#define USER_DS		((mm_segment_t) { __UA_LIMIT })
+
+#define VERIFY_READ    0
+#define VERIFY_WRITE   1
+
+#define get_ds()	(KERNEL_DS)
+#define get_fs()	(current_thread_info()->addr_limit)
+#define set_fs(x)	(current_thread_info()->addr_limit = (x))
+
+#define segment_eq(a, b)	((a).seg == (b).seg)
+
+
+/*
+ * Is a address valid? This does a straighforward calculation rather
+ * than tests.
+ *
+ * Address valid if:
+ *  - "addr" doesn't have any high-bits set
+ *  - AND "size" doesn't have any high-bits set
+ *  - AND "addr+size" doesn't have any high-bits set
+ *  - OR we are in kernel mode.
+ *
+ * __ua_size() is a trick to avoid runtime checking of positive constant
+ * sizes; for those we already know at compile time that the size is ok.
+ */
+#define __ua_size(size)							\
+	((__builtin_constant_p(size) && (signed long) (size) > 0) ? 0 : (size))
+
+/*
+ * access_ok: - Checks if a user space pointer is valid
+ * @type: Type of access: %VERIFY_READ or %VERIFY_WRITE.  Note that
+ *        %VERIFY_WRITE is a superset of %VERIFY_READ - if it is safe
+ *        to write to a block, it is always safe to read from it.
+ * @addr: User space pointer to start of block to check
+ * @size: Size of block to check
+ *
+ * Context: User context only.  This function may sleep.
+ *
+ * Checks if a pointer to a block of memory in user space is valid.
+ *
+ * Returns true (nonzero) if the memory block may be valid, false (zero)
+ * if it is definitely invalid.
+ *
+ * Note that, depending on architecture, this function probably just
+ * checks that the pointer is in the user space range - after calling
+ * this function, memory access functions may still return -EFAULT.
+ */
+
+#define __access_mask get_fs().seg
+
+#define __access_ok(addr, size, mask)					\
+	(((signed long)((mask) & ((addr) | ((addr) + (size)) | __ua_size(size)))) == 0)
+
+#define access_ok(type, addr, size)					\
+	likely(__access_ok((unsigned long)(addr), (size), __access_mask))
+
+/*
+ * put_user: - Write a simple value into user space.
+ * @x:   Value to copy to user space.
+ * @ptr: Destination address, in user space.
+ *
+ * Context: User context only.  This function may sleep.
+ *
+ * This macro copies a single simple value from kernel space to user
+ * space.  It supports simple types like char and int, but not larger
+ * data types like structures or arrays.
+ *
+ * @ptr must have pointer-to-simple-variable type, and @x must be assignable
+ * to the result of dereferencing @ptr.
+ *
+ * Returns zero on success, or -EFAULT on error.
+ */
+#define put_user(x,ptr)	\
+	__put_user_check((x), (ptr), sizeof(*(ptr)))
+
+/*
+ * get_user: - Get a simple variable from user space.
+ * @x:   Variable to store result.
+ * @ptr: Source address, in user space.
+ *
+ * Context: User context only.  This function may sleep.
+ *
+ * This macro copies a single simple variable from user space to kernel
+ * space.  It supports simple types like char and int, but not larger
+ * data types like structures or arrays.
+ *
+ * @ptr must have pointer-to-simple-variable type, and the result of
+ * dereferencing @ptr must be assignable to @x without a cast.
+ *
+ * Returns zero on success, or -EFAULT on error.
+ * On error, the variable @x is set to zero.
+ */
+#define get_user(x,ptr) \
+	__get_user_check((x), (ptr), sizeof(*(ptr)))
+
+/*
+ * __put_user: - Write a simple value into user space, with less checking.
+ * @x:   Value to copy to user space.
+ * @ptr: Destination address, in user space.
+ *
+ * Context: User context only.  This function may sleep.
+ *
+ * This macro copies a single simple value from kernel space to user
+ * space.  It supports simple types like char and int, but not larger
+ * data types like structures or arrays.
+ *
+ * @ptr must have pointer-to-simple-variable type, and @x must be assignable
+ * to the result of dereferencing @ptr.
+ *
+ * Caller must check the pointer with access_ok() before calling this
+ * function.
+ *
+ * Returns zero on success, or -EFAULT on error.
+ */
+#define __put_user(x,ptr) \
+	__put_user_nocheck((x), (ptr), sizeof(*(ptr)))
+
+/*
+ * __get_user: - Get a simple variable from user space, with less checking.
+ * @x:   Variable to store result.
+ * @ptr: Source address, in user space.
+ *
+ * Context: User context only.  This function may sleep.
+ *
+ * This macro copies a single simple variable from user space to kernel
+ * space.  It supports simple types like char and int, but not larger
+ * data types like structures or arrays.
+ *
+ * @ptr must have pointer-to-simple-variable type, and the result of
+ * dereferencing @ptr must be assignable to @x without a cast.
+ *
+ * Caller must check the pointer with access_ok() before calling this
+ * function.
+ *
+ * Returns zero on success, or -EFAULT on error.
+ * On error, the variable @x is set to zero.
+ */
+#define __get_user(x,ptr) \
+	__get_user_nocheck((x), (ptr), sizeof(*(ptr)))
+
+struct __large_struct { unsigned long buf[100]; };
+#define __m(x) (*(struct __large_struct __user *)(x))
+
+/*
+ * Yuck.  We need two variants, one for 64bit operation and one
+ * for 32 bit mode and old iron.
+ */
+#ifdef CONFIG_32BIT
+#define __GET_USER_DW(val, ptr) __get_user_asm_ll32(val, ptr)
+#endif
+#ifdef CONFIG_64BIT
+#define __GET_USER_DW(val, ptr) __get_user_asm(val, "ld", ptr)
+#endif
+
+extern void __get_user_unknown(void);
+
+#define __get_user_common(val, size, ptr)				\
+do {									\
+	switch (size) {							\
+	case 1: __get_user_asm(val, "lb", ptr); break;			\
+	case 2: __get_user_asm(val, "lh", ptr); break;			\
+	case 4: __get_user_asm(val, "lw", ptr); break;			\
+	case 8: __GET_USER_DW(val, ptr); break;				\
+	default: __get_user_unknown(); break;				\
+	}								\
+} while (0)
+
+#define __get_user_nocheck(x, ptr, size)				\
+({									\
+	int __gu_err;							\
+									\
+	__get_user_common((x), size, ptr);				\
+	__gu_err;							\
+})
+
+#define __get_user_check(x, ptr, size)					\
+({									\
+	int __gu_err = -EFAULT;						\
+	const __typeof__(*(ptr)) __user * __gu_ptr = (ptr);		\
+									\
+	if (likely(access_ok(VERIFY_READ,  __gu_ptr, size)))		\
+		__get_user_common((x), size, __gu_ptr);			\
+									\
+	__gu_err;							\
+})
+
+#define __get_user_asm(val, insn, addr)					\
+{									\
+	long __gu_tmp;							\
+									\
+	__asm__ __volatile__(						\
+	"1:	" insn "	%1, %3				\n"	\
+	"2:							\n"	\
+	"	.section .fixup,\"ax\"				\n"	\
+	"3:	li	%0, %4					\n"	\
+	"	j	2b					\n"	\
+	"	.previous					\n"	\
+	"	.section __ex_table,\"a\"			\n"	\
+	"	"__UA_ADDR "\t1b, 3b				\n"	\
+	"	.previous					\n"	\
+	: "=r" (__gu_err), "=r" (__gu_tmp)				\
+	: "0" (0), "o" (__m(addr)), "i" (-EFAULT));			\
+									\
+	(val) = (__typeof__(*(addr))) __gu_tmp;				\
+}
+
+/*
+ * Get a long long 64 using 32 bit registers.
+ */
+#define __get_user_asm_ll32(val, addr)					\
+{									\
+	union {								\
+		unsigned long long	l;				\
+		__typeof__(*(addr))	t;				\
+	} __gu_tmp;							\
+									\
+	__asm__ __volatile__(						\
+	"1:	lw	%1, (%3)				\n"	\
+	"2:	lw	%D1, 4(%3)				\n"	\
+	"3:	.section	.fixup,\"ax\"			\n"	\
+	"4:	li	%0, %4					\n"	\
+	"	move	%1, $0					\n"	\
+	"	move	%D1, $0					\n"	\
+	"	j	3b					\n"	\
+	"	.previous					\n"	\
+	"	.section	__ex_table,\"a\"		\n"	\
+	"	" __UA_ADDR "	1b, 4b				\n"	\
+	"	" __UA_ADDR "	2b, 4b				\n"	\
+	"	.previous					\n"	\
+	: "=r" (__gu_err), "=&r" (__gu_tmp.l)				\
+	: "0" (0), "r" (addr), "i" (-EFAULT));				\
+									\
+	(val) = __gu_tmp.t;						\
+}
+
+/*
+ * Yuck.  We need two variants, one for 64bit operation and one
+ * for 32 bit mode and old iron.
+ */
+#ifdef CONFIG_32BIT
+#define __PUT_USER_DW(ptr) __put_user_asm_ll32(ptr)
+#endif
+#ifdef CONFIG_64BIT
+#define __PUT_USER_DW(ptr) __put_user_asm("sd", ptr)
+#endif
+
+#define __put_user_nocheck(x, ptr, size)				\
+({									\
+	__typeof__(*(ptr)) __pu_val;					\
+	int __pu_err = 0;						\
+									\
+	__pu_val = (x);							\
+	switch (size) {							\
+	case 1: __put_user_asm("sb", ptr); break;			\
+	case 2: __put_user_asm("sh", ptr); break;			\
+	case 4: __put_user_asm("sw", ptr); break;			\
+	case 8: __PUT_USER_DW(ptr); break;				\
+	default: __put_user_unknown(); break;				\
+	}								\
+	__pu_err;							\
+})
+
+#define __put_user_check(x, ptr, size)					\
+({									\
+	__typeof__(*(ptr)) __user *__pu_addr = (ptr);			\
+	__typeof__(*(ptr)) __pu_val = (x);				\
+	int __pu_err = -EFAULT;						\
+									\
+	if (likely(access_ok(VERIFY_WRITE,  __pu_addr, size))) {	\
+		switch (size) {						\
+		case 1: __put_user_asm("sb", __pu_addr); break;		\
+		case 2: __put_user_asm("sh", __pu_addr); break;		\
+		case 4: __put_user_asm("sw", __pu_addr); break;		\
+		case 8: __PUT_USER_DW(__pu_addr); break;		\
+		default: __put_user_unknown(); break;			\
+		}							\
+	}								\
+	__pu_err;							\
+})
+
+#define __put_user_asm(insn, ptr)					\
+{									\
+	__asm__ __volatile__(						\
+	"1:	" insn "	%z2, %3		# __put_user_asm\n"	\
+	"2:							\n"	\
+	"	.section	.fixup,\"ax\"			\n"	\
+	"3:	li	%0, %4					\n"	\
+	"	j	2b					\n"	\
+	"	.previous					\n"	\
+	"	.section	__ex_table,\"a\"		\n"	\
+	"	" __UA_ADDR "	1b, 3b				\n"	\
+	"	.previous					\n"	\
+	: "=r" (__pu_err)						\
+	: "0" (0), "Jr" (__pu_val), "o" (__m(ptr)),			\
+	  "i" (-EFAULT));						\
+}
+
+#define __put_user_asm_ll32(ptr)					\
+{									\
+	__asm__ __volatile__(						\
+	"1:	sw	%2, (%3)	# __put_user_asm_ll32	\n"	\
+	"2:	sw	%D2, 4(%3)				\n"	\
+	"3:							\n"	\
+	"	.section	.fixup,\"ax\"			\n"	\
+	"4:	li	%0, %4					\n"	\
+	"	j	3b					\n"	\
+	"	.previous					\n"	\
+	"	.section	__ex_table,\"a\"		\n"	\
+	"	" __UA_ADDR "	1b, 4b				\n"	\
+	"	" __UA_ADDR "	2b, 4b				\n"	\
+	"	.previous"						\
+	: "=r" (__pu_err)						\
+	: "0" (0), "r" (__pu_val), "r" (ptr),				\
+	  "i" (-EFAULT));						\
+}
+
+extern void __put_user_unknown(void);
+
+/*
+ * put_user_unaligned: - Write a simple value into user space.
+ * @x:   Value to copy to user space.
+ * @ptr: Destination address, in user space.
+ *
+ * Context: User context only.  This function may sleep.
+ *
+ * This macro copies a single simple value from kernel space to user
+ * space.  It supports simple types like char and int, but not larger
+ * data types like structures or arrays.
+ *
+ * @ptr must have pointer-to-simple-variable type, and @x must be assignable
+ * to the result of dereferencing @ptr.
+ *
+ * Returns zero on success, or -EFAULT on error.
+ */
+#define put_user_unaligned(x,ptr)	\
+	__put_user_unaligned_check((x),(ptr),sizeof(*(ptr)))
+
+/*
+ * get_user_unaligned: - Get a simple variable from user space.
+ * @x:   Variable to store result.
+ * @ptr: Source address, in user space.
+ *
+ * Context: User context only.  This function may sleep.
+ *
+ * This macro copies a single simple variable from user space to kernel
+ * space.  It supports simple types like char and int, but not larger
+ * data types like structures or arrays.
+ *
+ * @ptr must have pointer-to-simple-variable type, and the result of
+ * dereferencing @ptr must be assignable to @x without a cast.
+ *
+ * Returns zero on success, or -EFAULT on error.
+ * On error, the variable @x is set to zero.
+ */
+#define get_user_unaligned(x,ptr) \
+	__get_user_unaligned_check((x),(ptr),sizeof(*(ptr)))
+
+/*
+ * __put_user_unaligned: - Write a simple value into user space, with less checking.
+ * @x:   Value to copy to user space.
+ * @ptr: Destination address, in user space.
+ *
+ * Context: User context only.  This function may sleep.
+ *
+ * This macro copies a single simple value from kernel space to user
+ * space.  It supports simple types like char and int, but not larger
+ * data types like structures or arrays.
+ *
+ * @ptr must have pointer-to-simple-variable type, and @x must be assignable
+ * to the result of dereferencing @ptr.
+ *
+ * Caller must check the pointer with access_ok() before calling this
+ * function.
+ *
+ * Returns zero on success, or -EFAULT on error.
+ */
+#define __put_user_unaligned(x,ptr) \
+	__put_user_unaligned_nocheck((x),(ptr),sizeof(*(ptr)))
+
+/*
+ * __get_user_unaligned: - Get a simple variable from user space, with less checking.
+ * @x:   Variable to store result.
+ * @ptr: Source address, in user space.
+ *
+ * Context: User context only.  This function may sleep.
+ *
+ * This macro copies a single simple variable from user space to kernel
+ * space.  It supports simple types like char and int, but not larger
+ * data types like structures or arrays.
+ *
+ * @ptr must have pointer-to-simple-variable type, and the result of
+ * dereferencing @ptr must be assignable to @x without a cast.
+ *
+ * Caller must check the pointer with access_ok() before calling this
+ * function.
+ *
+ * Returns zero on success, or -EFAULT on error.
+ * On error, the variable @x is set to zero.
+ */
+#define __get_user_unaligned(x,ptr) \
+	__get_user__unalignednocheck((x),(ptr),sizeof(*(ptr)))
+
+/*
+ * Yuck.  We need two variants, one for 64bit operation and one
+ * for 32 bit mode and old iron.
+ */
+#ifdef CONFIG_32BIT
+#define __GET_USER_UNALIGNED_DW(val, ptr)				\
+	__get_user_unaligned_asm_ll32(val, ptr)
+#endif
+#ifdef CONFIG_64BIT
+#define __GET_USER_UNALIGNED_DW(val, ptr)				\
+	__get_user_unaligned_asm(val, "uld", ptr)
+#endif
+
+extern void __get_user_unaligned_unknown(void);
+
+#define __get_user_unaligned_common(val, size, ptr)			\
+do {									\
+	switch (size) {							\
+	case 1: __get_user_asm(val, "lb", ptr); break;			\
+	case 2: __get_user_unaligned_asm(val, "ulh", ptr); break;	\
+	case 4: __get_user_unaligned_asm(val, "ulw", ptr); break;	\
+	case 8: __GET_USER_UNALIGNED_DW(val, ptr); break;		\
+	default: __get_user_unaligned_unknown(); break;			\
+	}								\
+} while (0)
+
+#define __get_user_unaligned_nocheck(x,ptr,size)			\
+({									\
+	int __gu_err;							\
+									\
+	__get_user_unaligned_common((x), size, ptr);			\
+	__gu_err;							\
+})
+
+#define __get_user_unaligned_check(x,ptr,size)				\
+({									\
+	int __gu_err = -EFAULT;						\
+	const __typeof__(*(ptr)) __user * __gu_ptr = (ptr);		\
+									\
+	if (likely(access_ok(VERIFY_READ,  __gu_ptr, size)))		\
+		__get_user_unaligned_common((x), size, __gu_ptr);	\
+									\
+	__gu_err;							\
+})
+
+#define __get_user_unaligned_asm(val, insn, addr)			\
+{									\
+	long __gu_tmp;							\
+									\
+	__asm__ __volatile__(						\
+	"1:	" insn "	%1, %3				\n"	\
+	"2:							\n"	\
+	"	.section .fixup,\"ax\"				\n"	\
+	"3:	li	%0, %4					\n"	\
+	"	j	2b					\n"	\
+	"	.previous					\n"	\
+	"	.section __ex_table,\"a\"			\n"	\
+	"	"__UA_ADDR "\t1b, 3b				\n"	\
+	"	"__UA_ADDR "\t1b + 4, 3b			\n"	\
+	"	.previous					\n"	\
+	: "=r" (__gu_err), "=r" (__gu_tmp)				\
+	: "0" (0), "o" (__m(addr)), "i" (-EFAULT));			\
+									\
+	(val) = (__typeof__(*(addr))) __gu_tmp;				\
+}
+
+/*
+ * Get a long long 64 using 32 bit registers.
+ */
+#define __get_user_unaligned_asm_ll32(val, addr)			\
+{									\
+        unsigned long long __gu_tmp;					\
+									\
+	__asm__ __volatile__(						\
+	"1:	ulw	%1, (%3)				\n"	\
+	"2:	ulw	%D1, 4(%3)				\n"	\
+	"	move	%0, $0					\n"	\
+	"3:	.section	.fixup,\"ax\"			\n"	\
+	"4:	li	%0, %4					\n"	\
+	"	move	%1, $0					\n"	\
+	"	move	%D1, $0					\n"	\
+	"	j	3b					\n"	\
+	"	.previous					\n"	\
+	"	.section	__ex_table,\"a\"		\n"	\
+	"	" __UA_ADDR "	1b, 4b				\n"	\
+	"	" __UA_ADDR "	1b + 4, 4b			\n"	\
+	"	" __UA_ADDR "	2b, 4b				\n"	\
+	"	" __UA_ADDR "	2b + 4, 4b			\n"	\
+	"	.previous					\n"	\
+	: "=r" (__gu_err), "=&r" (__gu_tmp)				\
+	: "0" (0), "r" (addr), "i" (-EFAULT));				\
+	(val) = (__typeof__(*(addr))) __gu_tmp;				\
+}
+
+/*
+ * Yuck.  We need two variants, one for 64bit operation and one
+ * for 32 bit mode and old iron.
+ */
+#ifdef CONFIG_32BIT
+#define __PUT_USER_UNALIGNED_DW(ptr) __put_user_unaligned_asm_ll32(ptr)
+#endif
+#ifdef CONFIG_64BIT
+#define __PUT_USER_UNALIGNED_DW(ptr) __put_user_unaligned_asm("usd", ptr)
+#endif
+
+#define __put_user_unaligned_nocheck(x,ptr,size)			\
+({									\
+	__typeof__(*(ptr)) __pu_val;					\
+	int __pu_err = 0;						\
+									\
+	__pu_val = (x);							\
+	switch (size) {							\
+	case 1: __put_user_asm("sb", ptr); break;			\
+	case 2: __put_user_unaligned_asm("ush", ptr); break;		\
+	case 4: __put_user_unaligned_asm("usw", ptr); break;		\
+	case 8: __PUT_USER_UNALIGNED_DW(ptr); break;			\
+	default: __put_user_unaligned_unknown(); break;			\
+	}								\
+	__pu_err;							\
+})
+
+#define __put_user_unaligned_check(x,ptr,size)				\
+({									\
+	__typeof__(*(ptr)) __user *__pu_addr = (ptr);			\
+	__typeof__(*(ptr)) __pu_val = (x);				\
+	int __pu_err = -EFAULT;						\
+									\
+	if (likely(access_ok(VERIFY_WRITE,  __pu_addr, size))) {	\
+		switch (size) {						\
+		case 1: __put_user_asm("sb", __pu_addr); break;		\
+		case 2: __put_user_unaligned_asm("ush", __pu_addr); break; \
+		case 4: __put_user_unaligned_asm("usw", __pu_addr); break; \
+		case 8: __PUT_USER_UNALGINED_DW(__pu_addr); break;	\
+		default: __put_user_unaligned_unknown(); break;		\
+		}							\
+	}								\
+	__pu_err;							\
+})
+
+#define __put_user_unaligned_asm(insn, ptr)				\
+{									\
+	__asm__ __volatile__(						\
+	"1:	" insn "	%z2, %3		# __put_user_unaligned_asm\n" \
+	"2:							\n"	\
+	"	.section	.fixup,\"ax\"			\n"	\
+	"3:	li	%0, %4					\n"	\
+	"	j	2b					\n"	\
+	"	.previous					\n"	\
+	"	.section	__ex_table,\"a\"		\n"	\
+	"	" __UA_ADDR "	1b, 3b				\n"	\
+	"	.previous					\n"	\
+	: "=r" (__pu_err)						\
+	: "0" (0), "Jr" (__pu_val), "o" (__m(ptr)),			\
+	  "i" (-EFAULT));						\
+}
+
+#define __put_user_unaligned_asm_ll32(ptr)				\
+{									\
+	__asm__ __volatile__(						\
+	"1:	sw	%2, (%3)	# __put_user_unaligned_asm_ll32	\n" \
+	"2:	sw	%D2, 4(%3)				\n"	\
+	"3:							\n"	\
+	"	.section	.fixup,\"ax\"			\n"	\
+	"4:	li	%0, %4					\n"	\
+	"	j	3b					\n"	\
+	"	.previous					\n"	\
+	"	.section	__ex_table,\"a\"		\n"	\
+	"	" __UA_ADDR "	1b, 4b				\n"	\
+	"	" __UA_ADDR "	1b + 4, 4b			\n"	\
+	"	" __UA_ADDR "	2b, 4b				\n"	\
+	"	" __UA_ADDR "	2b + 4, 4b			\n"	\
+	"	.previous"						\
+	: "=r" (__pu_err)						\
+	: "0" (0), "r" (__pu_val), "r" (ptr),				\
+	  "i" (-EFAULT));						\
+}
+
+extern void __put_user_unaligned_unknown(void);
+
+/*
+ * We're generating jump to subroutines which will be outside the range of
+ * jump instructions
+ */
+#ifdef MODULE
+#define __MODULE_JAL(destination)					\
+	".set\tnoat\n\t"						\
+	__UA_LA "\t$1, " #destination "\n\t" 				\
+	"jalr\t$1\n\t"							\
+	".set\tat\n\t"
+#else
+#define __MODULE_JAL(destination)					\
+	"jal\t" #destination "\n\t"
+#endif
+
+#ifndef CONFIG_CPU_DADDI_WORKAROUNDS
+#define DADDI_SCRATCH "$0"
+#else
+#define DADDI_SCRATCH "$3"
+#endif
+
+extern size_t __copy_user(void *__to, const void *__from, size_t __n);
+
+#define __invoke_copy_to_user(to, from, n)				\
+({									\
+	register void __user *__cu_to_r __asm__("$4");			\
+	register const void *__cu_from_r __asm__("$5");			\
+	register long __cu_len_r __asm__("$6");				\
+									\
+	__cu_to_r = (to);						\
+	__cu_from_r = (from);						\
+	__cu_len_r = (n);						\
+	__asm__ __volatile__(						\
+	__MODULE_JAL(__copy_user)					\
+	: "+r" (__cu_to_r), "+r" (__cu_from_r), "+r" (__cu_len_r)	\
+	:								\
+	: "$8", "$9", "$10", "$11", "$12", "$15", "$24", "$31",		\
+	  DADDI_SCRATCH, "memory");					\
+	__cu_len_r;							\
+})
+
+/*
+ * __copy_to_user: - Copy a block of data into user space, with less checking.
+ * @to:   Destination address, in user space.
+ * @from: Source address, in kernel space.
+ * @n:    Number of bytes to copy.
+ *
+ * Context: User context only.  This function may sleep.
+ *
+ * Copy data from kernel space to user space.  Caller must check
+ * the specified block with access_ok() before calling this function.
+ *
+ * Returns number of bytes that could not be copied.
+ * On success, this will be zero.
+ */
+#define __copy_to_user(to, from, n)					\
+({									\
+	void __user *__cu_to;						\
+	const void *__cu_from;						\
+	long __cu_len;							\
+									\
+	might_sleep();							\
+	__cu_to = (to);							\
+	__cu_from = (from);						\
+	__cu_len = (n);							\
+	__cu_len = __invoke_copy_to_user(__cu_to, __cu_from, __cu_len);	\
+	__cu_len;							\
+})
+
+extern size_t __copy_user_inatomic(void *__to, const void *__from, size_t __n);
+
+#define __copy_to_user_inatomic(to, from, n)				\
+({									\
+	void __user *__cu_to;						\
+	const void *__cu_from;						\
+	long __cu_len;							\
+									\
+	__cu_to = (to);							\
+	__cu_from = (from);						\
+	__cu_len = (n);							\
+	__cu_len = __invoke_copy_to_user(__cu_to, __cu_from, __cu_len);	\
+	__cu_len;							\
+})
+
+#define __copy_from_user_inatomic(to, from, n)				\
+({									\
+	void *__cu_to;							\
+	const void __user *__cu_from;					\
+	long __cu_len;							\
+									\
+	__cu_to = (to);							\
+	__cu_from = (from);						\
+	__cu_len = (n);							\
+	__cu_len = __invoke_copy_from_user_inatomic(__cu_to, __cu_from,	\
+	                                            __cu_len);		\
+	__cu_len;							\
+})
+
+/*
+ * copy_to_user: - Copy a block of data into user space.
+ * @to:   Destination address, in user space.
+ * @from: Source address, in kernel space.
+ * @n:    Number of bytes to copy.
+ *
+ * Context: User context only.  This function may sleep.
+ *
+ * Copy data from kernel space to user space.
+ *
+ * Returns number of bytes that could not be copied.
+ * On success, this will be zero.
+ */
+#define copy_to_user(to, from, n)					\
+({									\
+	void __user *__cu_to;						\
+	const void *__cu_from;						\
+	long __cu_len;							\
+									\
+	might_sleep();							\
+	__cu_to = (to);							\
+	__cu_from = (from);						\
+	__cu_len = (n);							\
+	if (access_ok(VERIFY_WRITE, __cu_to, __cu_len))			\
+		__cu_len = __invoke_copy_to_user(__cu_to, __cu_from,	\
+		                                 __cu_len);		\
+	__cu_len;							\
+})
+
+#define __invoke_copy_from_user(to, from, n)				\
+({									\
+	register void *__cu_to_r __asm__("$4");				\
+	register const void __user *__cu_from_r __asm__("$5");		\
+	register long __cu_len_r __asm__("$6");				\
+									\
+	__cu_to_r = (to);						\
+	__cu_from_r = (from);						\
+	__cu_len_r = (n);						\
+	__asm__ __volatile__(						\
+	".set\tnoreorder\n\t"						\
+	__MODULE_JAL(__copy_user)					\
+	".set\tnoat\n\t"						\
+	__UA_ADDU "\t$1, %1, %2\n\t"					\
+	".set\tat\n\t"							\
+	".set\treorder"							\
+	: "+r" (__cu_to_r), "+r" (__cu_from_r), "+r" (__cu_len_r)	\
+	:								\
+	: "$8", "$9", "$10", "$11", "$12", "$15", "$24", "$31",		\
+	  DADDI_SCRATCH, "memory");					\
+	__cu_len_r;							\
+})
+
+#define __invoke_copy_from_user_inatomic(to, from, n)			\
+({									\
+	register void *__cu_to_r __asm__("$4");				\
+	register const void __user *__cu_from_r __asm__("$5");		\
+	register long __cu_len_r __asm__("$6");				\
+									\
+	__cu_to_r = (to);						\
+	__cu_from_r = (from);						\
+	__cu_len_r = (n);						\
+	__asm__ __volatile__(						\
+	".set\tnoreorder\n\t"						\
+	__MODULE_JAL(__copy_user_inatomic)				\
+	".set\tnoat\n\t"						\
+	__UA_ADDU "\t$1, %1, %2\n\t"					\
+	".set\tat\n\t"							\
+	".set\treorder"							\
+	: "+r" (__cu_to_r), "+r" (__cu_from_r), "+r" (__cu_len_r)	\
+	:								\
+	: "$8", "$9", "$10", "$11", "$12", "$15", "$24", "$31",		\
+	  DADDI_SCRATCH, "memory");					\
+	__cu_len_r;							\
+})
+
+/*
+ * __copy_from_user: - Copy a block of data from user space, with less checking.
+ * @to:   Destination address, in kernel space.
+ * @from: Source address, in user space.
+ * @n:    Number of bytes to copy.
+ *
+ * Context: User context only.  This function may sleep.
+ *
+ * Copy data from user space to kernel space.  Caller must check
+ * the specified block with access_ok() before calling this function.
+ *
+ * Returns number of bytes that could not be copied.
+ * On success, this will be zero.
+ *
+ * If some data could not be copied, this function will pad the copied
+ * data to the requested size using zero bytes.
+ */
+#define __copy_from_user(to, from, n)					\
+({									\
+	void *__cu_to;							\
+	const void __user *__cu_from;					\
+	long __cu_len;							\
+									\
+	might_sleep();							\
+	__cu_to = (to);							\
+	__cu_from = (from);						\
+	__cu_len = (n);							\
+	__cu_len = __invoke_copy_from_user(__cu_to, __cu_from,		\
+	                                   __cu_len);			\
+	__cu_len;							\
+})
+
+/*
+ * copy_from_user: - Copy a block of data from user space.
+ * @to:   Destination address, in kernel space.
+ * @from: Source address, in user space.
+ * @n:    Number of bytes to copy.
+ *
+ * Context: User context only.  This function may sleep.
+ *
+ * Copy data from user space to kernel space.
+ *
+ * Returns number of bytes that could not be copied.
+ * On success, this will be zero.
+ *
+ * If some data could not be copied, this function will pad the copied
+ * data to the requested size using zero bytes.
+ */
+#define copy_from_user(to, from, n)					\
+({									\
+	void *__cu_to;							\
+	const void __user *__cu_from;					\
+	long __cu_len;							\
+									\
+	might_sleep();							\
+	__cu_to = (to);							\
+	__cu_from = (from);						\
+	__cu_len = (n);							\
+	if (access_ok(VERIFY_READ, __cu_from, __cu_len))		\
+		__cu_len = __invoke_copy_from_user(__cu_to, __cu_from,	\
+		                                   __cu_len);		\
+	__cu_len;							\
+})
+
+#define __copy_in_user(to, from, n)	__copy_from_user(to, from, n)
+
+#define copy_in_user(to, from, n)					\
+({									\
+	void __user *__cu_to;						\
+	const void __user *__cu_from;					\
+	long __cu_len;							\
+									\
+	might_sleep();							\
+	__cu_to = (to);							\
+	__cu_from = (from);						\
+	__cu_len = (n);							\
+	if (likely(access_ok(VERIFY_READ, __cu_from, __cu_len) &&	\
+	           access_ok(VERIFY_WRITE, __cu_to, __cu_len)))		\
+		__cu_len = __invoke_copy_from_user(__cu_to, __cu_from,	\
+		                                   __cu_len);		\
+	__cu_len;							\
+})
+
+/*
+ * __clear_user: - Zero a block of memory in user space, with less checking.
+ * @to:   Destination address, in user space.
+ * @n:    Number of bytes to zero.
+ *
+ * Zero a block of memory in user space.  Caller must check
+ * the specified block with access_ok() before calling this function.
+ *
+ * Returns number of bytes that could not be cleared.
+ * On success, this will be zero.
+ */
+static inline __kernel_size_t
+__clear_user(void __user *addr, __kernel_size_t size)
+{
+	__kernel_size_t res;
+
+	might_sleep();
+	__asm__ __volatile__(
+		"move\t$4, %1\n\t"
+		"move\t$5, $0\n\t"
+		"move\t$6, %2\n\t"
+		__MODULE_JAL(__bzero)
+		"move\t%0, $6"
+		: "=r" (res)
+		: "r" (addr), "r" (size)
+		: "$4", "$5", "$6", __UA_t0, __UA_t1, "$31");
+
+	return res;
+}
+
+#define clear_user(addr,n)						\
+({									\
+	void __user * __cl_addr = (addr);				\
+	unsigned long __cl_size = (n);					\
+	if (__cl_size && access_ok(VERIFY_WRITE,			\
+		((unsigned long)(__cl_addr)), __cl_size))		\
+		__cl_size = __clear_user(__cl_addr, __cl_size);		\
+	__cl_size;							\
+})
+
+/*
+ * __strncpy_from_user: - Copy a NUL terminated string from userspace, with less checking.
+ * @dst:   Destination address, in kernel space.  This buffer must be at
+ *         least @count bytes long.
+ * @src:   Source address, in user space.
+ * @count: Maximum number of bytes to copy, including the trailing NUL.
+ *
+ * Copies a NUL-terminated string from userspace to kernel space.
+ * Caller must check the specified block with access_ok() before calling
+ * this function.
+ *
+ * On success, returns the length of the string (not including the trailing
+ * NUL).
+ *
+ * If access to userspace fails, returns -EFAULT (some data may have been
+ * copied).
+ *
+ * If @count is smaller than the length of the string, copies @count bytes
+ * and returns @count.
+ */
+static inline long
+__strncpy_from_user(char *__to, const char __user *__from, long __len)
+{
+	long res;
+
+	might_sleep();
+	__asm__ __volatile__(
+		"move\t$4, %1\n\t"
+		"move\t$5, %2\n\t"
+		"move\t$6, %3\n\t"
+		__MODULE_JAL(__strncpy_from_user_nocheck_asm)
+		"move\t%0, $2"
+		: "=r" (res)
+		: "r" (__to), "r" (__from), "r" (__len)
+		: "$2", "$3", "$4", "$5", "$6", __UA_t0, "$31", "memory");
+
+	return res;
+}
+
+/*
+ * strncpy_from_user: - Copy a NUL terminated string from userspace.
+ * @dst:   Destination address, in kernel space.  This buffer must be at
+ *         least @count bytes long.
+ * @src:   Source address, in user space.
+ * @count: Maximum number of bytes to copy, including the trailing NUL.
+ *
+ * Copies a NUL-terminated string from userspace to kernel space.
+ *
+ * On success, returns the length of the string (not including the trailing
+ * NUL).
+ *
+ * If access to userspace fails, returns -EFAULT (some data may have been
+ * copied).
+ *
+ * If @count is smaller than the length of the string, copies @count bytes
+ * and returns @count.
+ */
+static inline long
+strncpy_from_user(char *__to, const char __user *__from, long __len)
+{
+	long res;
+
+	might_sleep();
+	__asm__ __volatile__(
+		"move\t$4, %1\n\t"
+		"move\t$5, %2\n\t"
+		"move\t$6, %3\n\t"
+		__MODULE_JAL(__strncpy_from_user_asm)
+		"move\t%0, $2"
+		: "=r" (res)
+		: "r" (__to), "r" (__from), "r" (__len)
+		: "$2", "$3", "$4", "$5", "$6", __UA_t0, "$31", "memory");
+
+	return res;
+}
+
+/* Returns: 0 if bad, string length+1 (memory size) of string if ok */
+static inline long __strlen_user(const char __user *s)
+{
+	long res;
+
+	might_sleep();
+	__asm__ __volatile__(
+		"move\t$4, %1\n\t"
+		__MODULE_JAL(__strlen_user_nocheck_asm)
+		"move\t%0, $2"
+		: "=r" (res)
+		: "r" (s)
+		: "$2", "$4", __UA_t0, "$31");
+
+	return res;
+}
+
+/*
+ * strlen_user: - Get the size of a string in user space.
+ * @str: The string to measure.
+ *
+ * Context: User context only.  This function may sleep.
+ *
+ * Get the size of a NUL-terminated string in user space.
+ *
+ * Returns the size of the string INCLUDING the terminating NUL.
+ * On exception, returns 0.
+ *
+ * If there is a limit on the length of a valid string, you may wish to
+ * consider using strnlen_user() instead.
+ */
+static inline long strlen_user(const char __user *s)
+{
+	long res;
+
+	might_sleep();
+	__asm__ __volatile__(
+		"move\t$4, %1\n\t"
+		__MODULE_JAL(__strlen_user_asm)
+		"move\t%0, $2"
+		: "=r" (res)
+		: "r" (s)
+		: "$2", "$4", __UA_t0, "$31");
+
+	return res;
+}
+
+/* Returns: 0 if bad, string length+1 (memory size) of string if ok */
+static inline long __strnlen_user(const char __user *s, long n)
+{
+	long res;
+
+	might_sleep();
+	__asm__ __volatile__(
+		"move\t$4, %1\n\t"
+		"move\t$5, %2\n\t"
+		__MODULE_JAL(__strnlen_user_nocheck_asm)
+		"move\t%0, $2"
+		: "=r" (res)
+		: "r" (s), "r" (n)
+		: "$2", "$4", "$5", __UA_t0, "$31");
+
+	return res;
+}
+
+/*
+ * strlen_user: - Get the size of a string in user space.
+ * @str: The string to measure.
+ *
+ * Context: User context only.  This function may sleep.
+ *
+ * Get the size of a NUL-terminated string in user space.
+ *
+ * Returns the size of the string INCLUDING the terminating NUL.
+ * On exception, returns 0.
+ *
+ * If there is a limit on the length of a valid string, you may wish to
+ * consider using strnlen_user() instead.
+ */
+static inline long strnlen_user(const char __user *s, long n)
+{
+	long res;
+
+	might_sleep();
+	__asm__ __volatile__(
+		"move\t$4, %1\n\t"
+		"move\t$5, %2\n\t"
+		__MODULE_JAL(__strnlen_user_asm)
+		"move\t%0, $2"
+		: "=r" (res)
+		: "r" (s), "r" (n)
+		: "$2", "$4", "$5", __UA_t0, "$31");
+
+	return res;
+}
+
+struct exception_table_entry
+{
+	unsigned long insn;
+	unsigned long nextinsn;
+};
+
+extern int fixup_exception(struct pt_regs *regs);
+
+#endif /* _ASM_UACCESS_H */
diff --git a/include/asm-mips/ucontext.h b/arch/mips/include/asm/ucontext.h
similarity index 100%
rename from include/asm-mips/ucontext.h
rename to arch/mips/include/asm/ucontext.h
diff --git a/include/asm-mips/unaligned.h b/arch/mips/include/asm/unaligned.h
similarity index 100%
rename from include/asm-mips/unaligned.h
rename to arch/mips/include/asm/unaligned.h
diff --git a/include/asm-mips/unistd.h b/arch/mips/include/asm/unistd.h
similarity index 100%
rename from include/asm-mips/unistd.h
rename to arch/mips/include/asm/unistd.h
diff --git a/include/asm-mips/user.h b/arch/mips/include/asm/user.h
similarity index 100%
rename from include/asm-mips/user.h
rename to arch/mips/include/asm/user.h
diff --git a/include/asm-mips/vga.h b/arch/mips/include/asm/vga.h
similarity index 100%
rename from include/asm-mips/vga.h
rename to arch/mips/include/asm/vga.h
diff --git a/include/asm-mips/vpe.h b/arch/mips/include/asm/vpe.h
similarity index 100%
rename from include/asm-mips/vpe.h
rename to arch/mips/include/asm/vpe.h
diff --git a/include/asm-mips/vr41xx/capcella.h b/arch/mips/include/asm/vr41xx/capcella.h
similarity index 100%
rename from include/asm-mips/vr41xx/capcella.h
rename to arch/mips/include/asm/vr41xx/capcella.h
diff --git a/include/asm-mips/vr41xx/giu.h b/arch/mips/include/asm/vr41xx/giu.h
similarity index 100%
rename from include/asm-mips/vr41xx/giu.h
rename to arch/mips/include/asm/vr41xx/giu.h
diff --git a/include/asm-mips/vr41xx/irq.h b/arch/mips/include/asm/vr41xx/irq.h
similarity index 100%
rename from include/asm-mips/vr41xx/irq.h
rename to arch/mips/include/asm/vr41xx/irq.h
diff --git a/include/asm-mips/vr41xx/mpc30x.h b/arch/mips/include/asm/vr41xx/mpc30x.h
similarity index 100%
rename from include/asm-mips/vr41xx/mpc30x.h
rename to arch/mips/include/asm/vr41xx/mpc30x.h
diff --git a/include/asm-mips/vr41xx/pci.h b/arch/mips/include/asm/vr41xx/pci.h
similarity index 100%
rename from include/asm-mips/vr41xx/pci.h
rename to arch/mips/include/asm/vr41xx/pci.h
diff --git a/include/asm-mips/vr41xx/siu.h b/arch/mips/include/asm/vr41xx/siu.h
similarity index 100%
rename from include/asm-mips/vr41xx/siu.h
rename to arch/mips/include/asm/vr41xx/siu.h
diff --git a/include/asm-mips/vr41xx/tb0219.h b/arch/mips/include/asm/vr41xx/tb0219.h
similarity index 100%
rename from include/asm-mips/vr41xx/tb0219.h
rename to arch/mips/include/asm/vr41xx/tb0219.h
diff --git a/include/asm-mips/vr41xx/tb0226.h b/arch/mips/include/asm/vr41xx/tb0226.h
similarity index 100%
rename from include/asm-mips/vr41xx/tb0226.h
rename to arch/mips/include/asm/vr41xx/tb0226.h
diff --git a/include/asm-mips/vr41xx/tb0287.h b/arch/mips/include/asm/vr41xx/tb0287.h
similarity index 100%
rename from include/asm-mips/vr41xx/tb0287.h
rename to arch/mips/include/asm/vr41xx/tb0287.h
diff --git a/include/asm-mips/vr41xx/vr41xx.h b/arch/mips/include/asm/vr41xx/vr41xx.h
similarity index 100%
rename from include/asm-mips/vr41xx/vr41xx.h
rename to arch/mips/include/asm/vr41xx/vr41xx.h
diff --git a/include/asm-mips/war.h b/arch/mips/include/asm/war.h
similarity index 100%
rename from include/asm-mips/war.h
rename to arch/mips/include/asm/war.h
diff --git a/arch/mips/include/asm/watch.h b/arch/mips/include/asm/watch.h
new file mode 100644
index 0000000..20126ec
--- /dev/null
+++ b/arch/mips/include/asm/watch.h
@@ -0,0 +1,32 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2008 David Daney
+ */
+#ifndef _ASM_WATCH_H
+#define _ASM_WATCH_H
+
+#include <linux/bitops.h>
+
+#include <asm/mipsregs.h>
+
+void mips_install_watch_registers(void);
+void mips_read_watch_registers(void);
+void mips_clear_watch_registers(void);
+void mips_probe_watch_registers(struct cpuinfo_mips *c);
+
+#ifdef CONFIG_HARDWARE_WATCHPOINTS
+#define __restore_watch() do {						\
+	if (unlikely(test_bit(TIF_LOAD_WATCH,				\
+			      &current_thread_info()->flags))) {	\
+		mips_install_watch_registers();				\
+	}								\
+} while (0)
+
+#else
+#define __restore_watch() do {} while (0)
+#endif
+
+#endif /* _ASM_WATCH_H */
diff --git a/include/asm-mips/wbflush.h b/arch/mips/include/asm/wbflush.h
similarity index 100%
rename from include/asm-mips/wbflush.h
rename to arch/mips/include/asm/wbflush.h
diff --git a/include/asm-mips/xor.h b/arch/mips/include/asm/xor.h
similarity index 100%
rename from include/asm-mips/xor.h
rename to arch/mips/include/asm/xor.h
diff --git a/include/asm-mips/xtalk/xtalk.h b/arch/mips/include/asm/xtalk/xtalk.h
similarity index 100%
rename from include/asm-mips/xtalk/xtalk.h
rename to arch/mips/include/asm/xtalk/xtalk.h
diff --git a/include/asm-mips/xtalk/xwidget.h b/arch/mips/include/asm/xtalk/xwidget.h
similarity index 100%
rename from include/asm-mips/xtalk/xwidget.h
rename to arch/mips/include/asm/xtalk/xwidget.h
diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile
index 706f939..d9da711 100644
--- a/arch/mips/kernel/Makefile
+++ b/arch/mips/kernel/Makefile
@@ -6,10 +6,11 @@
 
 obj-y		+= cpu-probe.o branch.o entry.o genex.o irq.o process.o \
 		   ptrace.o reset.o setup.o signal.o syscall.o \
-		   time.o topology.o traps.o unaligned.o
+		   time.o topology.o traps.o unaligned.o watch.o
 
 obj-$(CONFIG_CEVT_BCM1480)	+= cevt-bcm1480.o
 obj-$(CONFIG_CEVT_R4K)		+= cevt-r4k.o
+obj-$(CONFIG_MIPS_MT_SMTC)	+= cevt-smtc.o
 obj-$(CONFIG_CEVT_DS1287)	+= cevt-ds1287.o
 obj-$(CONFIG_CEVT_GT641XX)	+= cevt-gt641xx.o
 obj-$(CONFIG_CEVT_SB1250)	+= cevt-sb1250.o
diff --git a/arch/mips/kernel/cevt-r4k.c b/arch/mips/kernel/cevt-r4k.c
index 24a2d90..4a4c59f 100644
--- a/arch/mips/kernel/cevt-r4k.c
+++ b/arch/mips/kernel/cevt-r4k.c
@@ -12,6 +12,14 @@
 
 #include <asm/smtc_ipi.h>
 #include <asm/time.h>
+#include <asm/cevt-r4k.h>
+
+/*
+ * The SMTC Kernel for the 34K, 1004K, et. al. replaces several
+ * of these routines with SMTC-specific variants.
+ */
+
+#ifndef CONFIG_MIPS_MT_SMTC
 
 static int mips_next_event(unsigned long delta,
                            struct clock_event_device *evt)
@@ -19,60 +27,27 @@
 	unsigned int cnt;
 	int res;
 
-#ifdef CONFIG_MIPS_MT_SMTC
-	{
-	unsigned long flags, vpflags;
-	local_irq_save(flags);
-	vpflags = dvpe();
-#endif
 	cnt = read_c0_count();
 	cnt += delta;
 	write_c0_compare(cnt);
 	res = ((int)(read_c0_count() - cnt) > 0) ? -ETIME : 0;
-#ifdef CONFIG_MIPS_MT_SMTC
-	evpe(vpflags);
-	local_irq_restore(flags);
-	}
-#endif
 	return res;
 }
 
-static void mips_set_mode(enum clock_event_mode mode,
-                          struct clock_event_device *evt)
+#endif /* CONFIG_MIPS_MT_SMTC */
+
+void mips_set_clock_mode(enum clock_event_mode mode,
+				struct clock_event_device *evt)
 {
 	/* Nothing to do ...  */
 }
 
-static DEFINE_PER_CPU(struct clock_event_device, mips_clockevent_device);
-static int cp0_timer_irq_installed;
+DEFINE_PER_CPU(struct clock_event_device, mips_clockevent_device);
+int cp0_timer_irq_installed;
 
-/*
- * Timer ack for an R4k-compatible timer of a known frequency.
- */
-static void c0_timer_ack(void)
-{
-	write_c0_compare(read_c0_compare());
-}
+#ifndef CONFIG_MIPS_MT_SMTC
 
-/*
- * Possibly handle a performance counter interrupt.
- * Return true if the timer interrupt should not be checked
- */
-static inline int handle_perf_irq(int r2)
-{
-	/*
-	 * The performance counter overflow interrupt may be shared with the
-	 * timer interrupt (cp0_perfcount_irq < 0). If it is and a
-	 * performance counter has overflowed (perf_irq() == IRQ_HANDLED)
-	 * and we can't reliably determine if a counter interrupt has also
-	 * happened (!r2) then don't check for a timer interrupt.
-	 */
-	return (cp0_perfcount_irq < 0) &&
-		perf_irq() == IRQ_HANDLED &&
-		!r2;
-}
-
-static irqreturn_t c0_compare_interrupt(int irq, void *dev_id)
+irqreturn_t c0_compare_interrupt(int irq, void *dev_id)
 {
 	const int r2 = cpu_has_mips_r2;
 	struct clock_event_device *cd;
@@ -93,12 +68,8 @@
 	 * interrupt.  Being the paranoiacs we are we check anyway.
 	 */
 	if (!r2 || (read_c0_cause() & (1 << 30))) {
-		c0_timer_ack();
-#ifdef CONFIG_MIPS_MT_SMTC
-		if (cpu_data[cpu].vpe_id)
-			goto out;
-		cpu = 0;
-#endif
+		/* Clear Count/Compare Interrupt */
+		write_c0_compare(read_c0_compare());
 		cd = &per_cpu(mips_clockevent_device, cpu);
 		cd->event_handler(cd);
 	}
@@ -107,65 +78,16 @@
 	return IRQ_HANDLED;
 }
 
-static struct irqaction c0_compare_irqaction = {
+#endif /* Not CONFIG_MIPS_MT_SMTC */
+
+struct irqaction c0_compare_irqaction = {
 	.handler = c0_compare_interrupt,
-#ifdef CONFIG_MIPS_MT_SMTC
-	.flags = IRQF_DISABLED,
-#else
 	.flags = IRQF_DISABLED | IRQF_PERCPU,
-#endif
 	.name = "timer",
 };
 
-#ifdef CONFIG_MIPS_MT_SMTC
-DEFINE_PER_CPU(struct clock_event_device, smtc_dummy_clockevent_device);
 
-static void smtc_set_mode(enum clock_event_mode mode,
-                          struct clock_event_device *evt)
-{
-}
-
-static void mips_broadcast(cpumask_t mask)
-{
-	unsigned int cpu;
-
-	for_each_cpu_mask(cpu, mask)
-		smtc_send_ipi(cpu, SMTC_CLOCK_TICK, 0);
-}
-
-static void setup_smtc_dummy_clockevent_device(void)
-{
-	//uint64_t mips_freq = mips_hpt_^frequency;
-	unsigned int cpu = smp_processor_id();
-	struct clock_event_device *cd;
-
-	cd = &per_cpu(smtc_dummy_clockevent_device, cpu);
-
-	cd->name		= "SMTC";
-	cd->features		= CLOCK_EVT_FEAT_DUMMY;
-
-	/* Calculate the min / max delta */
-	cd->mult	= 0; //div_sc((unsigned long) mips_freq, NSEC_PER_SEC, 32);
-	cd->shift		= 0; //32;
-	cd->max_delta_ns	= 0; //clockevent_delta2ns(0x7fffffff, cd);
-	cd->min_delta_ns	= 0; //clockevent_delta2ns(0x30, cd);
-
-	cd->rating		= 200;
-	cd->irq			= 17; //-1;
-//	if (cpu)
-//		cd->cpumask	= CPU_MASK_ALL; // cpumask_of_cpu(cpu);
-//	else
-		cd->cpumask	= cpumask_of_cpu(cpu);
-
-	cd->set_mode		= smtc_set_mode;
-
-	cd->broadcast		= mips_broadcast;
-
-	clockevents_register_device(cd);
-}
-#endif
-
-static void mips_event_handler(struct clock_event_device *dev)
+void mips_event_handler(struct clock_event_device *dev)
 {
 }
 
@@ -177,7 +99,23 @@
 	return (read_c0_cause() >> cp0_compare_irq) & 0x100;
 }
 
-static int c0_compare_int_usable(void)
+/*
+ * Compare interrupt can be routed and latched outside the core,
+ * so a single execution hazard barrier may not be enough to give
+ * it time to clear as seen in the Cause register.  4 time the
+ * pipeline depth seems reasonably conservative, and empirically
+ * works better in configurations with high CPU/bus clock ratios.
+ */
+
+#define compare_change_hazard() \
+	do { \
+		irq_disable_hazard(); \
+		irq_disable_hazard(); \
+		irq_disable_hazard(); \
+		irq_disable_hazard(); \
+	} while (0)
+
+int c0_compare_int_usable(void)
 {
 	unsigned int delta;
 	unsigned int cnt;
@@ -187,7 +125,7 @@
 	 */
 	if (c0_compare_int_pending()) {
 		write_c0_compare(read_c0_count());
-		irq_disable_hazard();
+		compare_change_hazard();
 		if (c0_compare_int_pending())
 			return 0;
 	}
@@ -196,7 +134,7 @@
 		cnt = read_c0_count();
 		cnt += delta;
 		write_c0_compare(cnt);
-		irq_disable_hazard();
+		compare_change_hazard();
 		if ((int)(read_c0_count() - cnt) < 0)
 		    break;
 		/* increase delta if the timer was already expired */
@@ -205,11 +143,12 @@
 	while ((int)(read_c0_count() - cnt) <= 0)
 		;	/* Wait for expiry  */
 
+	compare_change_hazard();
 	if (!c0_compare_int_pending())
 		return 0;
 
 	write_c0_compare(read_c0_count());
-	irq_disable_hazard();
+	compare_change_hazard();
 	if (c0_compare_int_pending())
 		return 0;
 
@@ -219,6 +158,8 @@
 	return 1;
 }
 
+#ifndef CONFIG_MIPS_MT_SMTC
+
 int __cpuinit mips_clockevent_init(void)
 {
 	uint64_t mips_freq = mips_hpt_frequency;
@@ -229,17 +170,6 @@
 	if (!cpu_has_counter || !mips_hpt_frequency)
 		return -ENXIO;
 
-#ifdef CONFIG_MIPS_MT_SMTC
-	setup_smtc_dummy_clockevent_device();
-
-	/*
-	 * On SMTC we only register VPE0's compare interrupt as clockevent
-	 * device.
-	 */
-	if (cpu)
-		return 0;
-#endif
-
 	if (!c0_compare_int_usable())
 		return -ENXIO;
 
@@ -265,13 +195,9 @@
 
 	cd->rating		= 300;
 	cd->irq			= irq;
-#ifdef CONFIG_MIPS_MT_SMTC
-	cd->cpumask		= CPU_MASK_ALL;
-#else
 	cd->cpumask		= cpumask_of_cpu(cpu);
-#endif
 	cd->set_next_event	= mips_next_event;
-	cd->set_mode		= mips_set_mode;
+	cd->set_mode		= mips_set_clock_mode;
 	cd->event_handler	= mips_event_handler;
 
 	clockevents_register_device(cd);
@@ -281,12 +207,9 @@
 
 	cp0_timer_irq_installed = 1;
 
-#ifdef CONFIG_MIPS_MT_SMTC
-#define CPUCTR_IMASKBIT (0x100 << cp0_compare_irq)
-	setup_irq_smtc(irq, &c0_compare_irqaction, CPUCTR_IMASKBIT);
-#else
 	setup_irq(irq, &c0_compare_irqaction);
-#endif
 
 	return 0;
 }
+
+#endif /* Not CONFIG_MIPS_MT_SMTC */
diff --git a/arch/mips/kernel/cevt-smtc.c b/arch/mips/kernel/cevt-smtc.c
new file mode 100644
index 0000000..5162fe4
--- /dev/null
+++ b/arch/mips/kernel/cevt-smtc.c
@@ -0,0 +1,321 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2007 MIPS Technologies, Inc.
+ * Copyright (C) 2007 Ralf Baechle <ralf@linux-mips.org>
+ * Copyright (C) 2008 Kevin D. Kissell, Paralogos sarl
+ */
+#include <linux/clockchips.h>
+#include <linux/interrupt.h>
+#include <linux/percpu.h>
+
+#include <asm/smtc_ipi.h>
+#include <asm/time.h>
+#include <asm/cevt-r4k.h>
+
+/*
+ * Variant clock event timer support for SMTC on MIPS 34K, 1004K
+ * or other MIPS MT cores.
+ *
+ * Notes on SMTC Support:
+ *
+ * SMTC has multiple microthread TCs pretending to be Linux CPUs.
+ * But there's only one Count/Compare pair per VPE, and Compare
+ * interrupts are taken opportunisitically by available TCs
+ * bound to the VPE with the Count register.  The new timer
+ * framework provides for global broadcasts, but we really
+ * want VPE-level multicasts for best behavior. So instead
+ * of invoking the high-level clock-event broadcast code,
+ * this version of SMTC support uses the historical SMTC
+ * multicast mechanisms "under the hood", appearing to the
+ * generic clock layer as if the interrupts are per-CPU.
+ *
+ * The approach taken here is to maintain a set of NR_CPUS
+ * virtual timers, and track which "CPU" needs to be alerted
+ * at each event.
+ *
+ * It's unlikely that we'll see a MIPS MT core with more than
+ * 2 VPEs, but we *know* that we won't need to handle more
+ * VPEs than we have "CPUs".  So NCPUs arrays of NCPUs elements
+ * is always going to be overkill, but always going to be enough.
+ */
+
+unsigned long smtc_nexttime[NR_CPUS][NR_CPUS];
+static int smtc_nextinvpe[NR_CPUS];
+
+/*
+ * Timestamps stored are absolute values to be programmed
+ * into Count register.  Valid timestamps will never be zero.
+ * If a Zero Count value is actually calculated, it is converted
+ * to be a 1, which will introduce 1 or two CPU cycles of error
+ * roughly once every four billion events, which at 1000 HZ means
+ * about once every 50 days.  If that's actually a problem, one
+ * could alternate squashing 0 to 1 and to -1.
+ */
+
+#define MAKEVALID(x) (((x) == 0L) ? 1L : (x))
+#define ISVALID(x) ((x) != 0L)
+
+/*
+ * Time comparison is subtle, as it's really truncated
+ * modular arithmetic.
+ */
+
+#define IS_SOONER(a, b, reference) \
+    (((a) - (unsigned long)(reference)) < ((b) - (unsigned long)(reference)))
+
+/*
+ * CATCHUP_INCREMENT, used when the function falls behind the counter.
+ * Could be an increasing function instead of a constant;
+ */
+
+#define CATCHUP_INCREMENT 64
+
+static int mips_next_event(unsigned long delta,
+				struct clock_event_device *evt)
+{
+	unsigned long flags;
+	unsigned int mtflags;
+	unsigned long timestamp, reference, previous;
+	unsigned long nextcomp = 0L;
+	int vpe = current_cpu_data.vpe_id;
+	int cpu = smp_processor_id();
+	local_irq_save(flags);
+	mtflags = dmt();
+
+	/*
+	 * Maintain the per-TC virtual timer
+	 * and program the per-VPE shared Count register
+	 * as appropriate here...
+	 */
+	reference = (unsigned long)read_c0_count();
+	timestamp = MAKEVALID(reference + delta);
+	/*
+	 * To really model the clock, we have to catch the case
+	 * where the current next-in-VPE timestamp is the old
+	 * timestamp for the calling CPE, but the new value is
+	 * in fact later.  In that case, we have to do a full
+	 * scan and discover the new next-in-VPE CPU id and
+	 * timestamp.
+	 */
+	previous = smtc_nexttime[vpe][cpu];
+	if (cpu == smtc_nextinvpe[vpe] && ISVALID(previous)
+	    && IS_SOONER(previous, timestamp, reference)) {
+		int i;
+		int soonest = cpu;
+
+		/*
+		 * Update timestamp array here, so that new
+		 * value gets considered along with those of
+		 * other virtual CPUs on the VPE.
+		 */
+		smtc_nexttime[vpe][cpu] = timestamp;
+		for_each_online_cpu(i) {
+			if (ISVALID(smtc_nexttime[vpe][i])
+			    && IS_SOONER(smtc_nexttime[vpe][i],
+				smtc_nexttime[vpe][soonest], reference)) {
+				    soonest = i;
+			}
+		}
+		smtc_nextinvpe[vpe] = soonest;
+		nextcomp = smtc_nexttime[vpe][soonest];
+	/*
+	 * Otherwise, we don't have to process the whole array rank,
+	 * we just have to see if the event horizon has gotten closer.
+	 */
+	} else {
+		if (!ISVALID(smtc_nexttime[vpe][smtc_nextinvpe[vpe]]) ||
+		    IS_SOONER(timestamp,
+			smtc_nexttime[vpe][smtc_nextinvpe[vpe]], reference)) {
+			    smtc_nextinvpe[vpe] = cpu;
+			    nextcomp = timestamp;
+		}
+		/*
+		 * Since next-in-VPE may me the same as the executing
+		 * virtual CPU, we update the array *after* checking
+		 * its value.
+		 */
+		smtc_nexttime[vpe][cpu] = timestamp;
+	}
+
+	/*
+	 * It may be that, in fact, we don't need to update Compare,
+	 * but if we do, we want to make sure we didn't fall into
+	 * a crack just behind Count.
+	 */
+	if (ISVALID(nextcomp)) {
+		write_c0_compare(nextcomp);
+		ehb();
+		/*
+		 * We never return an error, we just make sure
+		 * that we trigger the handlers as quickly as
+		 * we can if we fell behind.
+		 */
+		while ((nextcomp - (unsigned long)read_c0_count())
+			> (unsigned long)LONG_MAX) {
+			nextcomp += CATCHUP_INCREMENT;
+			write_c0_compare(nextcomp);
+			ehb();
+		}
+	}
+	emt(mtflags);
+	local_irq_restore(flags);
+	return 0;
+}
+
+
+void smtc_distribute_timer(int vpe)
+{
+	unsigned long flags;
+	unsigned int mtflags;
+	int cpu;
+	struct clock_event_device *cd;
+	unsigned long nextstamp = 0L;
+	unsigned long reference;
+
+
+repeat:
+	for_each_online_cpu(cpu) {
+	    /*
+	     * Find virtual CPUs within the current VPE who have
+	     * unserviced timer requests whose time is now past.
+	     */
+	    local_irq_save(flags);
+	    mtflags = dmt();
+	    if (cpu_data[cpu].vpe_id == vpe &&
+		ISVALID(smtc_nexttime[vpe][cpu])) {
+		reference = (unsigned long)read_c0_count();
+		if ((smtc_nexttime[vpe][cpu] - reference)
+			 > (unsigned long)LONG_MAX) {
+			    smtc_nexttime[vpe][cpu] = 0L;
+			    emt(mtflags);
+			    local_irq_restore(flags);
+			    /*
+			     * We don't send IPIs to ourself.
+			     */
+			    if (cpu != smp_processor_id()) {
+				smtc_send_ipi(cpu, SMTC_CLOCK_TICK, 0);
+			    } else {
+				cd = &per_cpu(mips_clockevent_device, cpu);
+				cd->event_handler(cd);
+			    }
+		} else {
+			/* Local to VPE but Valid Time not yet reached. */
+			if (!ISVALID(nextstamp) ||
+			    IS_SOONER(smtc_nexttime[vpe][cpu], nextstamp,
+			    reference)) {
+				smtc_nextinvpe[vpe] = cpu;
+				nextstamp = smtc_nexttime[vpe][cpu];
+			}
+			emt(mtflags);
+			local_irq_restore(flags);
+		}
+	    } else {
+		emt(mtflags);
+		local_irq_restore(flags);
+
+	    }
+	}
+	/* Reprogram for interrupt at next soonest timestamp for VPE */
+	if (ISVALID(nextstamp)) {
+		write_c0_compare(nextstamp);
+		ehb();
+		if ((nextstamp - (unsigned long)read_c0_count())
+			> (unsigned long)LONG_MAX)
+				goto repeat;
+	}
+}
+
+
+irqreturn_t c0_compare_interrupt(int irq, void *dev_id)
+{
+	int cpu = smp_processor_id();
+
+	/* If we're running SMTC, we've got MIPS MT and therefore MIPS32R2 */
+	handle_perf_irq(1);
+
+	if (read_c0_cause() & (1 << 30)) {
+		/* Clear Count/Compare Interrupt */
+		write_c0_compare(read_c0_compare());
+		smtc_distribute_timer(cpu_data[cpu].vpe_id);
+	}
+	return IRQ_HANDLED;
+}
+
+
+int __cpuinit mips_clockevent_init(void)
+{
+	uint64_t mips_freq = mips_hpt_frequency;
+	unsigned int cpu = smp_processor_id();
+	struct clock_event_device *cd;
+	unsigned int irq;
+	int i;
+	int j;
+
+	if (!cpu_has_counter || !mips_hpt_frequency)
+		return -ENXIO;
+	if (cpu == 0) {
+		for (i = 0; i < num_possible_cpus(); i++) {
+			smtc_nextinvpe[i] = 0;
+			for (j = 0; j < num_possible_cpus(); j++)
+				smtc_nexttime[i][j] = 0L;
+		}
+		/*
+		 * SMTC also can't have the usablility test
+		 * run by secondary TCs once Compare is in use.
+		 */
+		if (!c0_compare_int_usable())
+			return -ENXIO;
+	}
+
+	/*
+	 * With vectored interrupts things are getting platform specific.
+	 * get_c0_compare_int is a hook to allow a platform to return the
+	 * interrupt number of it's liking.
+	 */
+	irq = MIPS_CPU_IRQ_BASE + cp0_compare_irq;
+	if (get_c0_compare_int)
+		irq = get_c0_compare_int();
+
+	cd = &per_cpu(mips_clockevent_device, cpu);
+
+	cd->name		= "MIPS";
+	cd->features		= CLOCK_EVT_FEAT_ONESHOT;
+
+	/* Calculate the min / max delta */
+	cd->mult	= div_sc((unsigned long) mips_freq, NSEC_PER_SEC, 32);
+	cd->shift		= 32;
+	cd->max_delta_ns	= clockevent_delta2ns(0x7fffffff, cd);
+	cd->min_delta_ns	= clockevent_delta2ns(0x300, cd);
+
+	cd->rating		= 300;
+	cd->irq			= irq;
+	cd->cpumask		= cpumask_of_cpu(cpu);
+	cd->set_next_event	= mips_next_event;
+	cd->set_mode		= mips_set_clock_mode;
+	cd->event_handler	= mips_event_handler;
+
+	clockevents_register_device(cd);
+
+	/*
+	 * On SMTC we only want to do the data structure
+	 * initialization and IRQ setup once.
+	 */
+	if (cpu)
+		return 0;
+	/*
+	 * And we need the hwmask associated with the c0_compare
+	 * vector to be initialized.
+	 */
+	irq_hwmask[irq] = (0x100 << cp0_compare_irq);
+	if (cp0_timer_irq_installed)
+		return 0;
+
+	cp0_timer_irq_installed = 1;
+
+	setup_irq(irq, &c0_compare_irqaction);
+
+	return 0;
+}
diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c
index 335a6ae..0cf1545 100644
--- a/arch/mips/kernel/cpu-probe.c
+++ b/arch/mips/kernel/cpu-probe.c
@@ -21,6 +21,7 @@
 #include <asm/fpu.h>
 #include <asm/mipsregs.h>
 #include <asm/system.h>
+#include <asm/watch.h>
 
 /*
  * Not all of the MIPS CPUs have the "wait" instruction available. Moreover,
@@ -45,18 +46,7 @@
 	local_irq_enable();
 }
 
-/*
- * There is a race when WAIT instruction executed with interrupt
- * enabled.
- * But it is implementation-dependent wheter the pipelie restarts when
- * a non-enabled interrupt is requested.
- */
-static void r4k_wait(void)
-{
-	__asm__("	.set	mips3			\n"
-		"	wait				\n"
-		"	.set	mips0			\n");
-}
+extern void r4k_wait(void);
 
 /*
  * This variant is preferable as it allows testing need_resched and going to
@@ -65,14 +55,18 @@
  * interrupt is requested" restriction in the MIPS32/MIPS64 architecture makes
  * using this version a gamble.
  */
-static void r4k_wait_irqoff(void)
+void r4k_wait_irqoff(void)
 {
 	local_irq_disable();
 	if (!need_resched())
-		__asm__("	.set	mips3		\n"
+		__asm__("	.set	push		\n"
+			"	.set	mips3		\n"
 			"	wait			\n"
-			"	.set	mips0		\n");
+			"	.set	pop		\n");
 	local_irq_enable();
+	__asm__(" 	.globl __pastwait	\n"
+		"__pastwait:			\n");
+	return;
 }
 
 /*
@@ -128,7 +122,7 @@
 
 __setup("nowait", wait_disable);
 
-static inline void check_wait(void)
+void __init check_wait(void)
 {
 	struct cpuinfo_mips *c = &current_cpu_data;
 
@@ -242,7 +236,6 @@
 
 void __init check_bugs32(void)
 {
-	check_wait();
 	check_errata();
 }
 
@@ -685,6 +678,7 @@
 static inline void cpu_probe_mips(struct cpuinfo_mips *c)
 {
 	decode_configs(c);
+	mips_probe_watch_registers(c);
 	switch (c->processor_id & 0xff00) {
 	case PRID_IMP_4KC:
 		c->cputype = CPU_4KC;
diff --git a/arch/mips/kernel/entry.S b/arch/mips/kernel/entry.S
index e29598a..ffa3310 100644
--- a/arch/mips/kernel/entry.S
+++ b/arch/mips/kernel/entry.S
@@ -79,11 +79,6 @@
 
 FEXPORT(restore_all)			# restore full frame
 #ifdef CONFIG_MIPS_MT_SMTC
-/* Detect and execute deferred IPI "interrupts" */
-	LONG_L	s0, TI_REGS($28)
-	LONG_S	sp, TI_REGS($28)
-	jal	deferred_smtc_ipi
-	LONG_S	s0, TI_REGS($28)
 #ifdef CONFIG_MIPS_MT_SMTC_IM_BACKSTOP
 /* Re-arm any temporarily masked interrupts not explicitly "acked" */
 	mfc0	v0, CP0_TCSTATUS
@@ -112,6 +107,11 @@
 	xor	t0, t0, t3
 	mtc0	t0, CP0_TCCONTEXT
 #endif /* CONFIG_MIPS_MT_SMTC_IM_BACKSTOP */
+/* Detect and execute deferred IPI "interrupts" */
+	LONG_L	s0, TI_REGS($28)
+	LONG_S	sp, TI_REGS($28)
+	jal	deferred_smtc_ipi
+	LONG_S	s0, TI_REGS($28)
 #endif /* CONFIG_MIPS_MT_SMTC */
 	.set	noat
 	RESTORE_TEMP
diff --git a/arch/mips/kernel/genex.S b/arch/mips/kernel/genex.S
index c6ada98..757d48f 100644
--- a/arch/mips/kernel/genex.S
+++ b/arch/mips/kernel/genex.S
@@ -20,6 +20,7 @@
 #include <asm/stackframe.h>
 #include <asm/war.h>
 #include <asm/page.h>
+#include <asm/thread_info.h>
 
 #define PANIC_PIC(msg)					\
 		.set push;				\
@@ -126,7 +127,42 @@
 
 	__FINIT
 
+	.align	5	/* 32 byte rollback region */
+LEAF(r4k_wait)
+	.set	push
+	.set	noreorder
+	/* start of rollback region */
+	LONG_L	t0, TI_FLAGS($28)
+	nop
+	andi	t0, _TIF_NEED_RESCHED
+	bnez	t0, 1f
+	 nop
+	nop
+	nop
+	.set	mips3
+	wait
+	/* end of rollback region (the region size must be power of two) */
+	.set	pop
+1:
+	jr	ra
+	END(r4k_wait)
+
+	.macro	BUILD_ROLLBACK_PROLOGUE handler
+	FEXPORT(rollback_\handler)
+	.set	push
+	.set	noat
+	MFC0	k0, CP0_EPC
+	PTR_LA	k1, r4k_wait
+	ori	k0, 0x1f	/* 32 byte rollback region */
+	xori	k0, 0x1f
+	bne	k0, k1, 9f
+	MTC0	k0, CP0_EPC
+9:
+	.set pop
+	.endm
+
 	.align  5
+BUILD_ROLLBACK_PROLOGUE handle_int
 NESTED(handle_int, PT_SIZE, sp)
 #ifdef CONFIG_TRACE_IRQFLAGS
 	/*
@@ -201,6 +237,7 @@
  * This prototype is copied to ebase + n*IntCtl.VS and patched
  * to invoke the handler
  */
+BUILD_ROLLBACK_PROLOGUE except_vec_vi
 NESTED(except_vec_vi, 0, sp)
 	SAVE_SOME
 	SAVE_AT
@@ -245,8 +282,8 @@
 	and	t0, a0, t1
 #ifdef CONFIG_MIPS_MT_SMTC_IM_BACKSTOP
 	mfc0	t2, CP0_TCCONTEXT
-	or	t0, t0, t2
-	mtc0	t0, CP0_TCCONTEXT
+	or	t2, t0, t2
+	mtc0	t2, CP0_TCCONTEXT
 #endif /* CONFIG_MIPS_MT_SMTC_IM_BACKSTOP */
 	xor	t1, t1, t0
 	mtc0	t1, CP0_STATUS
@@ -416,7 +453,11 @@
 	BUILD_HANDLER tr tr sti silent			/* #13 */
 	BUILD_HANDLER fpe fpe fpe silent		/* #15 */
 	BUILD_HANDLER mdmx mdmx sti silent		/* #22 */
+#ifdef 	CONFIG_HARDWARE_WATCHPOINTS
+	BUILD_HANDLER watch watch sti silent		/* #23 */
+#else
 	BUILD_HANDLER watch watch sti verbose		/* #23 */
+#endif
 	BUILD_HANDLER mcheck mcheck cli verbose		/* #24 */
 	BUILD_HANDLER mt mt sti silent			/* #25 */
 	BUILD_HANDLER dsp dsp sti silent		/* #26 */
diff --git a/arch/mips/kernel/head.S b/arch/mips/kernel/head.S
index 3613645..492a0a8 100644
--- a/arch/mips/kernel/head.S
+++ b/arch/mips/kernel/head.S
@@ -22,6 +22,7 @@
 #include <asm/irqflags.h>
 #include <asm/regdef.h>
 #include <asm/page.h>
+#include <asm/pgtable-bits.h>
 #include <asm/mipsregs.h>
 #include <asm/stackframe.h>
 
diff --git a/arch/mips/kernel/kgdb.c b/arch/mips/kernel/kgdb.c
index 8f6d58e..6e152c8 100644
--- a/arch/mips/kernel/kgdb.c
+++ b/arch/mips/kernel/kgdb.c
@@ -236,8 +236,7 @@
 
 		atomic_set(&kgdb_cpu_doing_single_step, -1);
 		if (remcom_in_buffer[0] == 's')
-			if (kgdb_contthread)
-				atomic_set(&kgdb_cpu_doing_single_step, cpu);
+			atomic_set(&kgdb_cpu_doing_single_step, cpu);
 
 		return 0;
 	}
diff --git a/arch/mips/kernel/mips-mt-fpaff.c b/arch/mips/kernel/mips-mt-fpaff.c
index df4d3f2..dc9eb72 100644
--- a/arch/mips/kernel/mips-mt-fpaff.c
+++ b/arch/mips/kernel/mips-mt-fpaff.c
@@ -159,7 +159,7 @@
 /*
  * FPU Use Factor empirically derived from experiments on 34K
  */
-#define FPUSEFACTOR 333
+#define FPUSEFACTOR 2000
 
 static __init int mt_fp_affinity_init(void)
 {
diff --git a/arch/mips/kernel/proc.c b/arch/mips/kernel/proc.c
index 36f0653..75bb130 100644
--- a/arch/mips/kernel/proc.c
+++ b/arch/mips/kernel/proc.c
@@ -23,6 +23,7 @@
 	unsigned int version = cpu_data[n].processor_id;
 	unsigned int fp_vers = cpu_data[n].fpu_id;
 	char fmt [64];
+	int i;
 
 #ifdef CONFIG_SMP
 	if (!cpu_isset(n, cpu_online_map))
@@ -50,8 +51,16 @@
 	seq_printf(m, "tlb_entries\t\t: %d\n", cpu_data[n].tlbsize);
 	seq_printf(m, "extra interrupt vector\t: %s\n",
 	              cpu_has_divec ? "yes" : "no");
-	seq_printf(m, "hardware watchpoint\t: %s\n",
-	              cpu_has_watch ? "yes" : "no");
+	seq_printf(m, "hardware watchpoint\t: %s",
+		   cpu_has_watch ? "yes, " : "no\n");
+	if (cpu_has_watch) {
+		seq_printf(m, "count: %d, address/irw mask: [",
+			   cpu_data[n].watch_reg_count);
+		for (i = 0; i < cpu_data[n].watch_reg_count; i++)
+			seq_printf(m, "%s0x%04x", i ? ", " : "" ,
+				   cpu_data[n].watch_reg_masks[i]);
+		seq_printf(m, "]\n");
+	}
 	seq_printf(m, "ASEs implemented\t:%s%s%s%s%s%s\n",
 		      cpu_has_mips16 ? " mips16" : "",
 		      cpu_has_mdmx ? " mdmx" : "",
diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c
index b16facd..ca2e402 100644
--- a/arch/mips/kernel/process.c
+++ b/arch/mips/kernel/process.c
@@ -22,7 +22,6 @@
 #include <linux/personality.h>
 #include <linux/sys.h>
 #include <linux/user.h>
-#include <linux/a.out.h>
 #include <linux/init.h>
 #include <linux/completion.h>
 #include <linux/kallsyms.h>
@@ -55,7 +54,7 @@
 	while (1) {
 		tick_nohz_stop_sched_tick(1);
 		while (!need_resched()) {
-#ifdef CONFIG_SMTC_IDLE_HOOK_DEBUG
+#ifdef CONFIG_MIPS_MT_SMTC
 			extern void smtc_idle_loop_hook(void);
 
 			smtc_idle_loop_hook();
@@ -145,17 +144,18 @@
 	 */
 	p->thread.cp0_status = read_c0_status() & ~(ST0_CU2|ST0_CU1);
 	childregs->cp0_status &= ~(ST0_CU2|ST0_CU1);
+
+#ifdef CONFIG_MIPS_MT_SMTC
+	/*
+	 * SMTC restores TCStatus after Status, and the CU bits
+	 * are aliased there.
+	 */
+	childregs->cp0_tcstatus &= ~(ST0_CU2|ST0_CU1);
+#endif
 	clear_tsk_thread_flag(p, TIF_USEDFPU);
 
 #ifdef CONFIG_MIPS_MT_FPAFF
-	/*
-	 * FPU affinity support is cleaner if we track the
-	 * user-visible CPU affinity from the very beginning.
-	 * The generic cpus_allowed mask will already have
-	 * been copied from the parent before copy_thread
-	 * is invoked.
-	 */
-	p->thread.user_cpus_allowed = p->cpus_allowed;
+	clear_tsk_thread_flag(p, TIF_FPUBOUND);
 #endif /* CONFIG_MIPS_MT_FPAFF */
 
 	if (clone_flags & CLONE_SETTLS)
diff --git a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c
index 35234b9..054861c 100644
--- a/arch/mips/kernel/ptrace.c
+++ b/arch/mips/kernel/ptrace.c
@@ -46,7 +46,8 @@
  */
 void ptrace_disable(struct task_struct *child)
 {
-	/* Nothing to do.. */
+	/* Don't load the watchpoint registers for the ex-child. */
+	clear_tsk_thread_flag(child, TIF_LOAD_WATCH);
 }
 
 /*
@@ -167,6 +168,93 @@
 	return 0;
 }
 
+int ptrace_get_watch_regs(struct task_struct *child,
+			  struct pt_watch_regs __user *addr)
+{
+	enum pt_watch_style style;
+	int i;
+
+	if (!cpu_has_watch || current_cpu_data.watch_reg_use_cnt == 0)
+		return -EIO;
+	if (!access_ok(VERIFY_WRITE, addr, sizeof(struct pt_watch_regs)))
+		return -EIO;
+
+#ifdef CONFIG_32BIT
+	style = pt_watch_style_mips32;
+#define WATCH_STYLE mips32
+#else
+	style = pt_watch_style_mips64;
+#define WATCH_STYLE mips64
+#endif
+
+	__put_user(style, &addr->style);
+	__put_user(current_cpu_data.watch_reg_use_cnt,
+		   &addr->WATCH_STYLE.num_valid);
+	for (i = 0; i < current_cpu_data.watch_reg_use_cnt; i++) {
+		__put_user(child->thread.watch.mips3264.watchlo[i],
+			   &addr->WATCH_STYLE.watchlo[i]);
+		__put_user(child->thread.watch.mips3264.watchhi[i] & 0xfff,
+			   &addr->WATCH_STYLE.watchhi[i]);
+		__put_user(current_cpu_data.watch_reg_masks[i],
+			   &addr->WATCH_STYLE.watch_masks[i]);
+	}
+	for (; i < 8; i++) {
+		__put_user(0, &addr->WATCH_STYLE.watchlo[i]);
+		__put_user(0, &addr->WATCH_STYLE.watchhi[i]);
+		__put_user(0, &addr->WATCH_STYLE.watch_masks[i]);
+	}
+
+	return 0;
+}
+
+int ptrace_set_watch_regs(struct task_struct *child,
+			  struct pt_watch_regs __user *addr)
+{
+	int i;
+	int watch_active = 0;
+	unsigned long lt[NUM_WATCH_REGS];
+	u16 ht[NUM_WATCH_REGS];
+
+	if (!cpu_has_watch || current_cpu_data.watch_reg_use_cnt == 0)
+		return -EIO;
+	if (!access_ok(VERIFY_READ, addr, sizeof(struct pt_watch_regs)))
+		return -EIO;
+	/* Check the values. */
+	for (i = 0; i < current_cpu_data.watch_reg_use_cnt; i++) {
+		__get_user(lt[i], &addr->WATCH_STYLE.watchlo[i]);
+#ifdef CONFIG_32BIT
+		if (lt[i] & __UA_LIMIT)
+			return -EINVAL;
+#else
+		if (test_tsk_thread_flag(child, TIF_32BIT_ADDR)) {
+			if (lt[i] & 0xffffffff80000000UL)
+				return -EINVAL;
+		} else {
+			if (lt[i] & __UA_LIMIT)
+				return -EINVAL;
+		}
+#endif
+		__get_user(ht[i], &addr->WATCH_STYLE.watchhi[i]);
+		if (ht[i] & ~0xff8)
+			return -EINVAL;
+	}
+	/* Install them. */
+	for (i = 0; i < current_cpu_data.watch_reg_use_cnt; i++) {
+		if (lt[i] & 7)
+			watch_active = 1;
+		child->thread.watch.mips3264.watchlo[i] = lt[i];
+		/* Set the G bit. */
+		child->thread.watch.mips3264.watchhi[i] = ht[i];
+	}
+
+	if (watch_active)
+		set_tsk_thread_flag(child, TIF_LOAD_WATCH);
+	else
+		clear_tsk_thread_flag(child, TIF_LOAD_WATCH);
+
+	return 0;
+}
+
 long arch_ptrace(struct task_struct *child, long request, long addr, long data)
 {
 	int ret;
@@ -238,7 +326,7 @@
 		case FPC_EIR: {	/* implementation / version register */
 			unsigned int flags;
 #ifdef CONFIG_MIPS_MT_SMTC
-			unsigned int irqflags;
+			unsigned long irqflags;
 			unsigned int mtflags;
 #endif /* CONFIG_MIPS_MT_SMTC */
 
@@ -440,6 +528,16 @@
 				(unsigned long __user *) data);
 		break;
 
+	case PTRACE_GET_WATCH_REGS:
+		ret = ptrace_get_watch_regs(child,
+					(struct pt_watch_regs __user *) addr);
+		break;
+
+	case PTRACE_SET_WATCH_REGS:
+		ret = ptrace_set_watch_regs(child,
+					(struct pt_watch_regs __user *) addr);
+		break;
+
 	default:
 		ret = ptrace_request(child, request, addr, data);
 		break;
diff --git a/arch/mips/kernel/ptrace32.c b/arch/mips/kernel/ptrace32.c
index 76818be..1ca3410 100644
--- a/arch/mips/kernel/ptrace32.c
+++ b/arch/mips/kernel/ptrace32.c
@@ -15,6 +15,7 @@
  * binaries.
  */
 #include <linux/compiler.h>
+#include <linux/compat.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
@@ -36,47 +37,17 @@
 #include <asm/uaccess.h>
 #include <asm/bootinfo.h>
 
-int ptrace_getregs(struct task_struct *child, __s64 __user *data);
-int ptrace_setregs(struct task_struct *child, __s64 __user *data);
-
-int ptrace_getfpregs(struct task_struct *child, __u32 __user *data);
-int ptrace_setfpregs(struct task_struct *child, __u32 __user *data);
-
 /*
  * Tracing a 32-bit process with a 64-bit strace and vice versa will not
  * work.  I don't know how to fix this.
  */
-asmlinkage int sys32_ptrace(int request, int pid, int addr, int data)
+long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
+			compat_ulong_t caddr, compat_ulong_t cdata)
 {
-	struct task_struct *child;
+	int addr = caddr;
+	int data = cdata;
 	int ret;
 
-#if 0
-	printk("ptrace(r=%d,pid=%d,addr=%08lx,data=%08lx)\n",
-	       (int) request, (int) pid, (unsigned long) addr,
-	       (unsigned long) data);
-#endif
-	lock_kernel();
-	if (request == PTRACE_TRACEME) {
-		ret = ptrace_traceme();
-		goto out;
-	}
-
-	child = ptrace_get_task_struct(pid);
-	if (IS_ERR(child)) {
-		ret = PTR_ERR(child);
-		goto out;
-	}
-
-	if (request == PTRACE_ATTACH) {
-		ret = ptrace_attach(child);
-		goto out_tsk;
-	}
-
-	ret = ptrace_check_attach(child, request == PTRACE_KILL);
-	if (ret < 0)
-		goto out_tsk;
-
 	switch (request) {
 	/* when I and D space are separate, these will need to be fixed. */
 	case PTRACE_PEEKTEXT: /* read word at location addr. */
@@ -214,7 +185,7 @@
 			if (!cpu_has_dsp) {
 				tmp = 0;
 				ret = -EIO;
-				goto out_tsk;
+				goto out;
 			}
 			dregs = __get_dsp_regs(child);
 			tmp = (unsigned long) (dregs[addr - DSP_BASE]);
@@ -224,14 +195,14 @@
 			if (!cpu_has_dsp) {
 				tmp = 0;
 				ret = -EIO;
-				goto out_tsk;
+				goto out;
 			}
 			tmp = child->thread.dsp.dspcontrol;
 			break;
 		default:
 			tmp = 0;
 			ret = -EIO;
-			goto out_tsk;
+			goto out;
 		}
 		ret = put_user(tmp, (unsigned __user *) (unsigned long) data);
 		break;
@@ -410,14 +381,20 @@
 				(unsigned long __user *) (unsigned long) data);
 		break;
 
+	case PTRACE_GET_WATCH_REGS:
+		ret = ptrace_get_watch_regs(child,
+			(struct pt_watch_regs __user *) (unsigned long) addr);
+		break;
+
+	case PTRACE_SET_WATCH_REGS:
+		ret = ptrace_set_watch_regs(child,
+			(struct pt_watch_regs __user *) (unsigned long) addr);
+		break;
+
 	default:
 		ret = ptrace_request(child, request, addr, data);
 		break;
 	}
-
-out_tsk:
-	put_task_struct(child);
 out:
-	unlock_kernel();
 	return ret;
 }
diff --git a/arch/mips/kernel/scall64-n32.S b/arch/mips/kernel/scall64-n32.S
index da7f1b6..324c549 100644
--- a/arch/mips/kernel/scall64-n32.S
+++ b/arch/mips/kernel/scall64-n32.S
@@ -219,7 +219,7 @@
 	PTR	compat_sys_getrusage
 	PTR	compat_sys_sysinfo
 	PTR	compat_sys_times
-	PTR	sys32_ptrace
+	PTR	compat_sys_ptrace
 	PTR	sys_getuid			/* 6100 */
 	PTR	sys_syslog
 	PTR	sys_getgid
diff --git a/arch/mips/kernel/scall64-o32.S b/arch/mips/kernel/scall64-o32.S
index d7cd1aa..85fedac 100644
--- a/arch/mips/kernel/scall64-o32.S
+++ b/arch/mips/kernel/scall64-o32.S
@@ -231,7 +231,7 @@
 	PTR	sys_setuid
 	PTR	sys_getuid
 	PTR	compat_sys_stime		/* 4025 */
-	PTR	sys32_ptrace
+	PTR	compat_sys_ptrace
 	PTR	sys_alarm
 	PTR	sys_ni_syscall			/* was sys_fstat */
 	PTR	sys_pause
diff --git a/arch/mips/kernel/signal32.c b/arch/mips/kernel/signal32.c
index 572c610..652709b 100644
--- a/arch/mips/kernel/signal32.c
+++ b/arch/mips/kernel/signal32.c
@@ -482,6 +482,18 @@
 	return err;
 }
 
+int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from)
+{
+	memset(to, 0, sizeof *to);
+
+	if (copy_from_user(to, from, 3*sizeof(int)) ||
+	    copy_from_user(to->_sifields._pad,
+			   from->_sifields._pad, SI_PAD_SIZE32))
+		return -EFAULT;
+
+	return 0;
+}
+
 asmlinkage void sys32_sigreturn(nabi_no_regargs struct pt_regs regs)
 {
 	struct sigframe32 __user *frame;
diff --git a/arch/mips/kernel/smp.c b/arch/mips/kernel/smp.c
index 4410f17..7b59cfb 100644
--- a/arch/mips/kernel/smp.c
+++ b/arch/mips/kernel/smp.c
@@ -121,6 +121,8 @@
 	cpu = smp_processor_id();
 	cpu_data[cpu].udelay_val = loops_per_jiffy;
 
+	notify_cpu_starting(cpu);
+
 	mp_ops->smp_finish();
 	set_cpu_sibling_map(cpu);
 
diff --git a/arch/mips/kernel/smtc.c b/arch/mips/kernel/smtc.c
index a516286..897fb2b 100644
--- a/arch/mips/kernel/smtc.c
+++ b/arch/mips/kernel/smtc.c
@@ -1,4 +1,21 @@
-/* Copyright (C) 2004 Mips Technologies, Inc */
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This 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) 2004 Mips Technologies, Inc
+ * Copyright (C) 2008 Kevin D. Kissell
+ */
 
 #include <linux/clockchips.h>
 #include <linux/kernel.h>
@@ -21,7 +38,6 @@
 #include <asm/time.h>
 #include <asm/addrspace.h>
 #include <asm/smtc.h>
-#include <asm/smtc_ipi.h>
 #include <asm/smtc_proc.h>
 
 /*
@@ -58,11 +74,6 @@
 
 asiduse smtc_live_asid[MAX_SMTC_TLBS][MAX_SMTC_ASIDS];
 
-/*
- * Clock interrupt "latch" buffers, per "CPU"
- */
-
-static atomic_t ipi_timer_latch[NR_CPUS];
 
 /*
  * Number of InterProcessor Interrupt (IPI) message buffers to allocate
@@ -70,7 +81,7 @@
 
 #define IPIBUF_PER_CPU 4
 
-static struct smtc_ipi_q IPIQ[NR_CPUS];
+struct smtc_ipi_q IPIQ[NR_CPUS];
 static struct smtc_ipi_q freeIPIq;
 
 
@@ -282,7 +293,7 @@
  * phys_cpu_present_map and the logical/physical mappings.
  */
 
-int __init mipsmt_build_cpu_map(int start_cpu_slot)
+int __init smtc_build_cpu_map(int start_cpu_slot)
 {
 	int i, ntcs;
 
@@ -325,7 +336,12 @@
 	write_tc_c0_tcstatus((read_tc_c0_tcstatus()
 			& ~(TCSTATUS_TKSU | TCSTATUS_DA | TCSTATUS_IXMT))
 			| TCSTATUS_A);
-	write_tc_c0_tccontext(0);
+	/*
+	 * TCContext gets an offset from the base of the IPIQ array
+	 * to be used in low-level code to detect the presence of
+	 * an active IPI queue
+	 */
+	write_tc_c0_tccontext((sizeof(struct smtc_ipi_q) * cpu) << 16);
 	/* Bind tc to vpe */
 	write_tc_c0_tcbind(vpe);
 	/* In general, all TCs should have the same cpu_data indications */
@@ -336,10 +352,18 @@
 		cpu_data[cpu].options &= ~MIPS_CPU_FPU;
 	cpu_data[cpu].vpe_id = vpe;
 	cpu_data[cpu].tc_id = tc;
+	/* Multi-core SMTC hasn't been tested, but be prepared */
+	cpu_data[cpu].core = (read_vpe_c0_ebase() >> 1) & 0xff;
 }
 
+/*
+ * Tweak to get Count registes in as close a sync as possible.
+ * Value seems good for 34K-class cores.
+ */
 
-void mipsmt_prepare_cpus(void)
+#define CP0_SKEW 8
+
+void smtc_prepare_cpus(int cpus)
 {
 	int i, vpe, tc, ntc, nvpe, tcpervpe[NR_CPUS], slop, cpu;
 	unsigned long flags;
@@ -363,13 +387,13 @@
 		IPIQ[i].head = IPIQ[i].tail = NULL;
 		spin_lock_init(&IPIQ[i].lock);
 		IPIQ[i].depth = 0;
-		atomic_set(&ipi_timer_latch[i], 0);
 	}
 
 	/* cpu_data index starts at zero */
 	cpu = 0;
 	cpu_data[cpu].vpe_id = 0;
 	cpu_data[cpu].tc_id = 0;
+	cpu_data[cpu].core = (read_c0_ebase() >> 1) & 0xff;
 	cpu++;
 
 	/* Report on boot-time options */
@@ -484,7 +508,8 @@
 			write_vpe_c0_compare(0);
 			/* Propagate Config7 */
 			write_vpe_c0_config7(read_c0_config7());
-			write_vpe_c0_count(read_c0_count());
+			write_vpe_c0_count(read_c0_count() + CP0_SKEW);
+			ehb();
 		}
 		/* enable multi-threading within VPE */
 		write_vpe_c0_vpecontrol(read_vpe_c0_vpecontrol() | VPECONTROL_TE);
@@ -556,7 +581,7 @@
 void __cpuinit smtc_boot_secondary(int cpu, struct task_struct *idle)
 {
 	extern u32 kernelsp[NR_CPUS];
-	long flags;
+	unsigned long flags;
 	int mtflags;
 
 	LOCK_MT_PRA();
@@ -585,24 +610,22 @@
 
 void smtc_init_secondary(void)
 {
-	/*
-	 * Start timer on secondary VPEs if necessary.
-	 * plat_timer_setup has already have been invoked by init/main
-	 * on "boot" TC.  Like per_cpu_trap_init() hack, this assumes that
-	 * SMTC init code assigns TCs consdecutively and in ascending order
-	 * to across available VPEs.
-	 */
-	if (((read_c0_tcbind() & TCBIND_CURTC) != 0) &&
-	    ((read_c0_tcbind() & TCBIND_CURVPE)
-	    != cpu_data[smp_processor_id() - 1].vpe_id)){
-		write_c0_compare(read_c0_count() + mips_hpt_frequency/HZ);
-	}
-
 	local_irq_enable();
 }
 
 void smtc_smp_finish(void)
 {
+	int cpu = smp_processor_id();
+
+	/*
+	 * Lowest-numbered CPU per VPE starts a clock tick.
+	 * Like per_cpu_trap_init() hack, this assumes that
+	 * SMTC init code assigns TCs consdecutively and
+	 * in ascending order across available VPEs.
+	 */
+	if (cpu > 0 && (cpu_data[cpu].vpe_id != cpu_data[cpu - 1].vpe_id))
+		write_c0_compare(read_c0_count() + mips_hpt_frequency/HZ);
+
 	printk("TC %d going on-line as CPU %d\n",
 		cpu_data[smp_processor_id()].tc_id, smp_processor_id());
 }
@@ -753,8 +776,10 @@
 {
 	int tcstatus;
 	struct smtc_ipi *pipi;
-	long flags;
+	unsigned long flags;
 	int mtflags;
+	unsigned long tcrestart;
+	extern void r4k_wait_irqoff(void), __pastwait(void);
 
 	if (cpu == smp_processor_id()) {
 		printk("Cannot Send IPI to self!\n");
@@ -771,8 +796,6 @@
 	pipi->arg = (void *)action;
 	pipi->dest = cpu;
 	if (cpu_data[cpu].vpe_id != cpu_data[smp_processor_id()].vpe_id) {
-		if (type == SMTC_CLOCK_TICK)
-			atomic_inc(&ipi_timer_latch[cpu]);
 		/* If not on same VPE, enqueue and send cross-VPE interrupt */
 		smtc_ipi_nq(&IPIQ[cpu], pipi);
 		LOCK_CORE_PRA();
@@ -800,22 +823,29 @@
 
 		if ((tcstatus & TCSTATUS_IXMT) != 0) {
 			/*
-			 * Spin-waiting here can deadlock,
-			 * so we queue the message for the target TC.
+			 * If we're in the the irq-off version of the wait
+			 * loop, we need to force exit from the wait and
+			 * do a direct post of the IPI.
+			 */
+			if (cpu_wait == r4k_wait_irqoff) {
+				tcrestart = read_tc_c0_tcrestart();
+				if (tcrestart >= (unsigned long)r4k_wait_irqoff
+				    && tcrestart < (unsigned long)__pastwait) {
+					write_tc_c0_tcrestart(__pastwait);
+					tcstatus &= ~TCSTATUS_IXMT;
+					write_tc_c0_tcstatus(tcstatus);
+					goto postdirect;
+				}
+			}
+			/*
+			 * Otherwise we queue the message for the target TC
+			 * to pick up when he does a local_irq_restore()
 			 */
 			write_tc_c0_tchalt(0);
 			UNLOCK_CORE_PRA();
-			/* Try to reduce redundant timer interrupt messages */
-			if (type == SMTC_CLOCK_TICK) {
-			    if (atomic_postincrement(&ipi_timer_latch[cpu])!=0){
-				smtc_ipi_nq(&freeIPIq, pipi);
-				return;
-			    }
-			}
 			smtc_ipi_nq(&IPIQ[cpu], pipi);
 		} else {
-			if (type == SMTC_CLOCK_TICK)
-				atomic_inc(&ipi_timer_latch[cpu]);
+postdirect:
 			post_direct_ipi(cpu, pipi);
 			write_tc_c0_tchalt(0);
 			UNLOCK_CORE_PRA();
@@ -883,7 +913,7 @@
 	smp_call_function_interrupt();
 }
 
-DECLARE_PER_CPU(struct clock_event_device, smtc_dummy_clockevent_device);
+DECLARE_PER_CPU(struct clock_event_device, mips_clockevent_device);
 
 void ipi_decode(struct smtc_ipi *pipi)
 {
@@ -891,20 +921,13 @@
 	struct clock_event_device *cd;
 	void *arg_copy = pipi->arg;
 	int type_copy = pipi->type;
-	int ticks;
-
 	smtc_ipi_nq(&freeIPIq, pipi);
 	switch (type_copy) {
 	case SMTC_CLOCK_TICK:
 		irq_enter();
 		kstat_this_cpu.irqs[MIPS_CPU_IRQ_BASE + 1]++;
-		cd = &per_cpu(smtc_dummy_clockevent_device, cpu);
-		ticks = atomic_read(&ipi_timer_latch[cpu]);
-		atomic_sub(ticks, &ipi_timer_latch[cpu]);
-		while (ticks) {
-			cd->event_handler(cd);
-			ticks--;
-		}
+		cd = &per_cpu(mips_clockevent_device, cpu);
+		cd->event_handler(cd);
 		irq_exit();
 		break;
 
@@ -937,24 +960,48 @@
 	}
 }
 
+/*
+ * Similar to smtc_ipi_replay(), but invoked from context restore,
+ * so it reuses the current exception frame rather than set up a
+ * new one with self_ipi.
+ */
+
 void deferred_smtc_ipi(void)
 {
-	struct smtc_ipi *pipi;
-	unsigned long flags;
-/* DEBUG */
-	int q = smp_processor_id();
+	int cpu = smp_processor_id();
 
 	/*
 	 * Test is not atomic, but much faster than a dequeue,
 	 * and the vast majority of invocations will have a null queue.
+	 * If irq_disabled when this was called, then any IPIs queued
+	 * after we test last will be taken on the next irq_enable/restore.
+	 * If interrupts were enabled, then any IPIs added after the
+	 * last test will be taken directly.
 	 */
-	if (IPIQ[q].head != NULL) {
-		while((pipi = smtc_ipi_dq(&IPIQ[q])) != NULL) {
-			/* ipi_decode() should be called with interrupts off */
-			local_irq_save(flags);
+
+	while (IPIQ[cpu].head != NULL) {
+		struct smtc_ipi_q *q = &IPIQ[cpu];
+		struct smtc_ipi *pipi;
+		unsigned long flags;
+
+		/*
+		 * It may be possible we'll come in with interrupts
+		 * already enabled.
+		 */
+		local_irq_save(flags);
+
+		spin_lock(&q->lock);
+		pipi = __smtc_ipi_dq(q);
+		spin_unlock(&q->lock);
+		if (pipi != NULL)
 			ipi_decode(pipi);
-			local_irq_restore(flags);
-		}
+		/*
+		 * The use of the __raw_local restore isn't
+		 * as obviously necessary here as in smtc_ipi_replay(),
+		 * but it's more efficient, given that we're already
+		 * running down the IPI queue.
+		 */
+		__raw_local_irq_restore(flags);
 	}
 }
 
@@ -975,7 +1022,7 @@
 	struct smtc_ipi *pipi;
 	unsigned long tcstatus;
 	int sent;
-	long flags;
+	unsigned long flags;
 	unsigned int mtflags;
 	unsigned int vpflags;
 
@@ -1066,55 +1113,53 @@
 
 /*
  * SMTC-specific hacks invoked from elsewhere in the kernel.
- *
- * smtc_ipi_replay is called from raw_local_irq_restore which is only ever
- * called with interrupts disabled.  We do rely on interrupts being disabled
- * here because using spin_lock_irqsave()/spin_unlock_irqrestore() would
- * result in a recursive call to raw_local_irq_restore().
  */
 
-static void __smtc_ipi_replay(void)
+ /*
+  * smtc_ipi_replay is called from raw_local_irq_restore
+  */
+
+void smtc_ipi_replay(void)
 {
 	unsigned int cpu = smp_processor_id();
 
 	/*
 	 * To the extent that we've ever turned interrupts off,
 	 * we may have accumulated deferred IPIs.  This is subtle.
-	 * If we use the smtc_ipi_qdepth() macro, we'll get an
-	 * exact number - but we'll also disable interrupts
-	 * and create a window of failure where a new IPI gets
-	 * queued after we test the depth but before we re-enable
-	 * interrupts. So long as IXMT never gets set, however,
 	 * we should be OK:  If we pick up something and dispatch
 	 * it here, that's great. If we see nothing, but concurrent
 	 * with this operation, another TC sends us an IPI, IXMT
 	 * is clear, and we'll handle it as a real pseudo-interrupt
-	 * and not a pseudo-pseudo interrupt.
+	 * and not a pseudo-pseudo interrupt.  The important thing
+	 * is to do the last check for queued message *after* the
+	 * re-enabling of interrupts.
 	 */
-	if (IPIQ[cpu].depth > 0) {
-		while (1) {
-			struct smtc_ipi_q *q = &IPIQ[cpu];
-			struct smtc_ipi *pipi;
-			extern void self_ipi(struct smtc_ipi *);
+	while (IPIQ[cpu].head != NULL) {
+		struct smtc_ipi_q *q = &IPIQ[cpu];
+		struct smtc_ipi *pipi;
+		unsigned long flags;
 
-			spin_lock(&q->lock);
-			pipi = __smtc_ipi_dq(q);
-			spin_unlock(&q->lock);
-			if (!pipi)
-				break;
+		/*
+		 * It's just possible we'll come in with interrupts
+		 * already enabled.
+		 */
+		local_irq_save(flags);
 
+		spin_lock(&q->lock);
+		pipi = __smtc_ipi_dq(q);
+		spin_unlock(&q->lock);
+		/*
+		 ** But use a raw restore here to avoid recursion.
+		 */
+		__raw_local_irq_restore(flags);
+
+		if (pipi) {
 			self_ipi(pipi);
 			smtc_cpu_stats[cpu].selfipis++;
 		}
 	}
 }
 
-void smtc_ipi_replay(void)
-{
-	raw_local_irq_disable();
-	__smtc_ipi_replay();
-}
-
 EXPORT_SYMBOL(smtc_ipi_replay);
 
 void smtc_idle_loop_hook(void)
@@ -1193,40 +1238,13 @@
 		}
 	}
 
-	/*
-	 * Now that we limit outstanding timer IPIs, check for hung TC
-	 */
-	for (tc = 0; tc < NR_CPUS; tc++) {
-		/* Don't check ourself - we'll dequeue IPIs just below */
-		if ((tc != smp_processor_id()) &&
-		    atomic_read(&ipi_timer_latch[tc]) > timerq_limit) {
-		    if (clock_hang_reported[tc] == 0) {
-			pdb_msg += sprintf(pdb_msg,
-				"TC %d looks hung with timer latch at %d\n",
-				tc, atomic_read(&ipi_timer_latch[tc]));
-			clock_hang_reported[tc]++;
-			}
-		}
-	}
 	emt(mtflags);
 	local_irq_restore(flags);
 	if (pdb_msg != &id_ho_db_msg[0])
 		printk("CPU%d: %s", smp_processor_id(), id_ho_db_msg);
 #endif /* CONFIG_SMTC_IDLE_HOOK_DEBUG */
 
-	/*
-	 * Replay any accumulated deferred IPIs. If "Instant Replay"
-	 * is in use, there should never be any.
-	 */
-#ifndef CONFIG_MIPS_MT_SMTC_INSTANT_REPLAY
-	{
-		unsigned long flags;
-
-		local_irq_save(flags);
-		__smtc_ipi_replay();
-		local_irq_restore(flags);
-	}
-#endif /* CONFIG_MIPS_MT_SMTC_INSTANT_REPLAY */
+	smtc_ipi_replay();
 }
 
 void smtc_soft_dump(void)
@@ -1242,10 +1260,6 @@
 		printk("%d: %ld\n", i, smtc_cpu_stats[i].selfipis);
 	}
 	smtc_ipi_qdump();
-	printk("Timer IPI Backlogs:\n");
-	for (i=0; i < NR_CPUS; i++) {
-		printk("%d: %d\n", i, atomic_read(&ipi_timer_latch[i]));
-	}
 	printk("%d Recoveries of \"stolen\" FPU\n",
 	       atomic_read(&smtc_fpu_recoveries));
 }
diff --git a/arch/mips/kernel/syscall.c b/arch/mips/kernel/syscall.c
index 343015a..37970d9 100644
--- a/arch/mips/kernel/syscall.c
+++ b/arch/mips/kernel/syscall.c
@@ -7,7 +7,6 @@
  * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
  * Copyright (C) 2001 MIPS Technologies, Inc.
  */
-#include <linux/a.out.h>
 #include <linux/capability.h>
 #include <linux/errno.h>
 #include <linux/linkage.h>
diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c
index 6bee290..80b9e07 100644
--- a/arch/mips/kernel/traps.c
+++ b/arch/mips/kernel/traps.c
@@ -42,10 +42,14 @@
 #include <asm/tlbdebug.h>
 #include <asm/traps.h>
 #include <asm/uaccess.h>
+#include <asm/watch.h>
 #include <asm/mmu_context.h>
 #include <asm/types.h>
 #include <asm/stacktrace.h>
 
+extern void check_wait(void);
+extern asmlinkage void r4k_wait(void);
+extern asmlinkage void rollback_handle_int(void);
 extern asmlinkage void handle_int(void);
 extern asmlinkage void handle_tlbm(void);
 extern asmlinkage void handle_tlbl(void);
@@ -822,8 +826,10 @@
 		if (cpus_intersects(current->cpus_allowed, mt_fpu_cpumask)) {
 			cpumask_t tmask;
 
-			cpus_and(tmask, current->thread.user_cpus_allowed,
-			         mt_fpu_cpumask);
+			current->thread.user_cpus_allowed
+				= current->cpus_allowed;
+			cpus_and(tmask, current->cpus_allowed,
+				mt_fpu_cpumask);
 			set_cpus_allowed(current, tmask);
 			set_thread_flag(TIF_FPUBOUND);
 		}
@@ -907,13 +913,26 @@
 
 asmlinkage void do_watch(struct pt_regs *regs)
 {
+	u32 cause;
+
 	/*
-	 * We use the watch exception where available to detect stack
-	 * overflows.
+	 * Clear WP (bit 22) bit of cause register so we don't loop
+	 * forever.
 	 */
-	dump_tlb_all();
-	show_regs(regs);
-	panic("Caught WATCH exception - probably caused by stack overflow.");
+	cause = read_c0_cause();
+	cause &= ~(1 << 22);
+	write_c0_cause(cause);
+
+	/*
+	 * If the current thread has the watch registers loaded, save
+	 * their values and send SIGTRAP.  Otherwise another thread
+	 * left the registers set, clear them and continue.
+	 */
+	if (test_tsk_thread_flag(current, TIF_LOAD_WATCH)) {
+		mips_read_watch_registers();
+		force_sig(SIGTRAP, current);
+	} else
+		mips_clear_watch_registers();
 }
 
 asmlinkage void do_mcheck(struct pt_regs *regs)
@@ -1251,6 +1270,9 @@
 
 		extern char except_vec_vi, except_vec_vi_lui;
 		extern char except_vec_vi_ori, except_vec_vi_end;
+		extern char rollback_except_vec_vi;
+		char *vec_start = (cpu_wait == r4k_wait) ?
+			&rollback_except_vec_vi : &except_vec_vi;
 #ifdef CONFIG_MIPS_MT_SMTC
 		/*
 		 * We need to provide the SMTC vectored interrupt handler
@@ -1258,11 +1280,11 @@
 		 * Status.IM bit to be masked before going there.
 		 */
 		extern char except_vec_vi_mori;
-		const int mori_offset = &except_vec_vi_mori - &except_vec_vi;
+		const int mori_offset = &except_vec_vi_mori - vec_start;
 #endif /* CONFIG_MIPS_MT_SMTC */
-		const int handler_len = &except_vec_vi_end - &except_vec_vi;
-		const int lui_offset = &except_vec_vi_lui - &except_vec_vi;
-		const int ori_offset = &except_vec_vi_ori - &except_vec_vi;
+		const int handler_len = &except_vec_vi_end - vec_start;
+		const int lui_offset = &except_vec_vi_lui - vec_start;
+		const int ori_offset = &except_vec_vi_ori - vec_start;
 
 		if (handler_len > VECTORSPACING) {
 			/*
@@ -1272,7 +1294,7 @@
 			panic("VECTORSPACING too small");
 		}
 
-		memcpy(b, &except_vec_vi, handler_len);
+		memcpy(b, vec_start, handler_len);
 #ifdef CONFIG_MIPS_MT_SMTC
 		BUG_ON(n > 7);	/* Vector index %d exceeds SMTC maximum. */
 
@@ -1554,6 +1576,10 @@
 	extern char except_vec3_generic, except_vec3_r4000;
 	extern char except_vec4;
 	unsigned long i;
+	int rollback;
+
+	check_wait();
+	rollback = (cpu_wait == r4k_wait);
 
 #if defined(CONFIG_KGDB)
 	if (kgdb_early_setup)
@@ -1618,7 +1644,7 @@
 	if (board_be_init)
 		board_be_init();
 
-	set_except_vector(0, handle_int);
+	set_except_vector(0, rollback ? rollback_handle_int : handle_int);
 	set_except_vector(1, handle_tlbm);
 	set_except_vector(2, handle_tlbl);
 	set_except_vector(3, handle_tlbs);
diff --git a/arch/mips/kernel/vmlinux.lds.S b/arch/mips/kernel/vmlinux.lds.S
index b5470ce..afb119f 100644
--- a/arch/mips/kernel/vmlinux.lds.S
+++ b/arch/mips/kernel/vmlinux.lds.S
@@ -36,6 +36,7 @@
 		SCHED_TEXT
 		LOCK_TEXT
 		KPROBES_TEXT
+		*(.text.*)
 		*(.fixup)
 		*(.gnu.warning)
 	} :text = 0
diff --git a/arch/mips/kernel/watch.c b/arch/mips/kernel/watch.c
new file mode 100644
index 0000000..c154069
--- /dev/null
+++ b/arch/mips/kernel/watch.c
@@ -0,0 +1,188 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2008 David Daney
+ */
+
+#include <linux/sched.h>
+
+#include <asm/processor.h>
+#include <asm/watch.h>
+
+/*
+ * Install the watch registers for the current thread.  A maximum of
+ * four registers are installed although the machine may have more.
+ */
+void mips_install_watch_registers(void)
+{
+	struct mips3264_watch_reg_state *watches =
+		&current->thread.watch.mips3264;
+	switch (current_cpu_data.watch_reg_use_cnt) {
+	default:
+		BUG();
+	case 4:
+		write_c0_watchlo3(watches->watchlo[3]);
+		/* Write 1 to the I, R, and W bits to clear them, and
+		   1 to G so all ASIDs are trapped. */
+		write_c0_watchhi3(0x40000007 | watches->watchhi[3]);
+	case 3:
+		write_c0_watchlo2(watches->watchlo[2]);
+		write_c0_watchhi2(0x40000007 | watches->watchhi[2]);
+	case 2:
+		write_c0_watchlo1(watches->watchlo[1]);
+		write_c0_watchhi1(0x40000007 | watches->watchhi[1]);
+	case 1:
+		write_c0_watchlo0(watches->watchlo[0]);
+		write_c0_watchhi0(0x40000007 | watches->watchhi[0]);
+	}
+}
+
+/*
+ * Read back the watchhi registers so the user space debugger has
+ * access to the I, R, and W bits.  A maximum of four registers are
+ * read although the machine may have more.
+ */
+void mips_read_watch_registers(void)
+{
+	struct mips3264_watch_reg_state *watches =
+		&current->thread.watch.mips3264;
+	switch (current_cpu_data.watch_reg_use_cnt) {
+	default:
+		BUG();
+	case 4:
+		watches->watchhi[3] = (read_c0_watchhi3() & 0x0fff);
+	case 3:
+		watches->watchhi[2] = (read_c0_watchhi2() & 0x0fff);
+	case 2:
+		watches->watchhi[1] = (read_c0_watchhi1() & 0x0fff);
+	case 1:
+		watches->watchhi[0] = (read_c0_watchhi0() & 0x0fff);
+	}
+	if (current_cpu_data.watch_reg_use_cnt == 1 &&
+	    (watches->watchhi[0] & 7) == 0) {
+		/* Pathological case of release 1 architecture that
+		 * doesn't set the condition bits.  We assume that
+		 * since we got here, the watch condition was met and
+		 * signal that the conditions requested in watchlo
+		 * were met.  */
+		watches->watchhi[0] |= (watches->watchlo[0] & 7);
+	}
+ }
+
+/*
+ * Disable all watch registers.  Although only four registers are
+ * installed, all are cleared to eliminate the possibility of endless
+ * looping in the watch handler.
+ */
+void mips_clear_watch_registers(void)
+{
+	switch (current_cpu_data.watch_reg_count) {
+	default:
+		BUG();
+	case 8:
+		write_c0_watchlo7(0);
+	case 7:
+		write_c0_watchlo6(0);
+	case 6:
+		write_c0_watchlo5(0);
+	case 5:
+		write_c0_watchlo4(0);
+	case 4:
+		write_c0_watchlo3(0);
+	case 3:
+		write_c0_watchlo2(0);
+	case 2:
+		write_c0_watchlo1(0);
+	case 1:
+		write_c0_watchlo0(0);
+	}
+}
+
+__cpuinit void mips_probe_watch_registers(struct cpuinfo_mips *c)
+{
+	unsigned int t;
+
+	if ((c->options & MIPS_CPU_WATCH) == 0)
+		return;
+	/*
+	 * Check which of the I,R and W bits are supported, then
+	 * disable the register.
+	 */
+	write_c0_watchlo0(7);
+	t = read_c0_watchlo0();
+	write_c0_watchlo0(0);
+	c->watch_reg_masks[0] = t & 7;
+
+	/* Write the mask bits and read them back to determine which
+	 * can be used. */
+	c->watch_reg_count = 1;
+	c->watch_reg_use_cnt = 1;
+	t = read_c0_watchhi0();
+	write_c0_watchhi0(t | 0xff8);
+	t = read_c0_watchhi0();
+	c->watch_reg_masks[0] |= (t & 0xff8);
+	if ((t & 0x80000000) == 0)
+		return;
+
+	write_c0_watchlo1(7);
+	t = read_c0_watchlo1();
+	write_c0_watchlo1(0);
+	c->watch_reg_masks[1] = t & 7;
+
+	c->watch_reg_count = 2;
+	c->watch_reg_use_cnt = 2;
+	t = read_c0_watchhi1();
+	write_c0_watchhi1(t | 0xff8);
+	t = read_c0_watchhi1();
+	c->watch_reg_masks[1] |= (t & 0xff8);
+	if ((t & 0x80000000) == 0)
+		return;
+
+	write_c0_watchlo2(7);
+	t = read_c0_watchlo2();
+	write_c0_watchlo2(0);
+	c->watch_reg_masks[2] = t & 7;
+
+	c->watch_reg_count = 3;
+	c->watch_reg_use_cnt = 3;
+	t = read_c0_watchhi2();
+	write_c0_watchhi2(t | 0xff8);
+	t = read_c0_watchhi2();
+	c->watch_reg_masks[2] |= (t & 0xff8);
+	if ((t & 0x80000000) == 0)
+		return;
+
+	write_c0_watchlo3(7);
+	t = read_c0_watchlo3();
+	write_c0_watchlo3(0);
+	c->watch_reg_masks[3] = t & 7;
+
+	c->watch_reg_count = 4;
+	c->watch_reg_use_cnt = 4;
+	t = read_c0_watchhi3();
+	write_c0_watchhi3(t | 0xff8);
+	t = read_c0_watchhi3();
+	c->watch_reg_masks[3] |= (t & 0xff8);
+	if ((t & 0x80000000) == 0)
+		return;
+
+	/* We use at most 4, but probe and report up to 8. */
+	c->watch_reg_count = 5;
+	t = read_c0_watchhi4();
+	if ((t & 0x80000000) == 0)
+		return;
+
+	c->watch_reg_count = 6;
+	t = read_c0_watchhi5();
+	if ((t & 0x80000000) == 0)
+		return;
+
+	c->watch_reg_count = 7;
+	t = read_c0_watchhi6();
+	if ((t & 0x80000000) == 0)
+		return;
+
+	c->watch_reg_count = 8;
+}
diff --git a/arch/mips/lib/csum_partial.S b/arch/mips/lib/csum_partial.S
index 8d77841..6b876ca 100644
--- a/arch/mips/lib/csum_partial.S
+++ b/arch/mips/lib/csum_partial.S
@@ -39,12 +39,14 @@
 #ifdef USE_DOUBLE
 
 #define LOAD   ld
+#define LOAD32 lwu
 #define ADD    daddu
 #define NBYTES 8
 
 #else
 
 #define LOAD   lw
+#define LOAD32 lw
 #define ADD    addu
 #define NBYTES 4
 
@@ -53,12 +55,14 @@
 #define UNIT(unit)  ((unit)*NBYTES)
 
 #define ADDC(sum,reg)						\
-	.set	push;						\
-	.set	noat;						\
 	ADD	sum, reg;					\
 	sltu	v1, sum, reg;					\
 	ADD	sum, v1;					\
-	.set	pop
+
+#define ADDC32(sum,reg)						\
+	addu	sum, reg;					\
+	sltu	v1, sum, reg;					\
+	addu	sum, v1;					\
 
 #define CSUM_BIGCHUNK1(src, offset, sum, _t0, _t1, _t2, _t3)	\
 	LOAD	_t0, (offset + UNIT(0))(src);			\
@@ -132,7 +136,7 @@
 	beqz	t8, .Lqword_align
 	 andi	t8, src, 0x8
 
-	lw	t0, 0x00(src)
+	LOAD32	t0, 0x00(src)
 	LONG_SUBU	a1, a1, 0x4
 	ADDC(sum, t0)
 	PTR_ADDU	src, src, 0x4
@@ -211,7 +215,7 @@
 	LONG_SRL	t8, t8, 0x2
 
 .Lend_words:
-	lw	t0, (src)
+	LOAD32	t0, (src)
 	LONG_SUBU	t8, t8, 0x1
 	ADDC(sum, t0)
 	.set	reorder				/* DADDI_WAR */
@@ -230,6 +234,9 @@
 	/* Still a full word to go  */
 	ulw	t1, (src)
 	PTR_ADDIU	src, 4
+#ifdef USE_DOUBLE
+	dsll	t1, t1, 32			/* clear lower 32bit */
+#endif
 	ADDC(sum, t1)
 
 1:	move	t1, zero
@@ -254,8 +261,6 @@
 1:	ADDC(sum, t1)
 
 	/* fold checksum */
-	.set	push
-	.set	noat
 #ifdef USE_DOUBLE
 	dsll32	v1, sum, 0
 	daddu	sum, v1
@@ -263,24 +268,25 @@
 	dsra32	sum, sum, 0
 	addu	sum, v1
 #endif
-	sll	v1, sum, 16
-	addu	sum, v1
-	sltu	v1, sum, v1
-	srl	sum, sum, 16
-	addu	sum, v1
 
 	/* odd buffer alignment? */
-	beqz	t7, 1f
-	 nop
-	sll	v1, sum, 8
+#ifdef CPU_MIPSR2
+	wsbh	v1, sum
+	movn	sum, v1, t7
+#else
+	beqz	t7, 1f			/* odd buffer alignment? */
+	 lui	v1, 0x00ff
+	addu	v1, 0x00ff
+	and	t0, sum, v1
+	sll	t0, t0, 8
 	srl	sum, sum, 8
-	or	sum, v1
-	andi	sum, 0xffff
-	.set	pop
+	and	sum, sum, v1
+	or	sum, sum, t0
 1:
+#endif
 	.set	reorder
 	/* Add the passed partial csum.  */
-	ADDC(sum, a2)
+	ADDC32(sum, a2)
 	jr	ra
 	.set	noreorder
 	END(csum_partial)
@@ -656,8 +662,6 @@
 	ADDC(sum, t2)
 .Ldone:
 	/* fold checksum */
-	.set	push
-	.set	noat
 #ifdef USE_DOUBLE
 	dsll32	v1, sum, 0
 	daddu	sum, v1
@@ -665,23 +669,23 @@
 	dsra32	sum, sum, 0
 	addu	sum, v1
 #endif
-	sll	v1, sum, 16
-	addu	sum, v1
-	sltu	v1, sum, v1
-	srl	sum, sum, 16
-	addu	sum, v1
 
-	/* odd buffer alignment? */
-	beqz	odd, 1f
-	 nop
-	sll	v1, sum, 8
+#ifdef CPU_MIPSR2
+	wsbh	v1, sum
+	movn	sum, v1, odd
+#else
+	beqz	odd, 1f			/* odd buffer alignment? */
+	 lui	v1, 0x00ff
+	addu	v1, 0x00ff
+	and	t0, sum, v1
+	sll	t0, t0, 8
 	srl	sum, sum, 8
-	or	sum, v1
-	andi	sum, 0xffff
-	.set	pop
+	and	sum, sum, v1
+	or	sum, sum, t0
 1:
+#endif
 	.set reorder
-	ADDC(sum, psum)
+	ADDC32(sum, psum)
 	jr	ra
 	.set noreorder
 
diff --git a/arch/mips/mti-malta/Makefile b/arch/mips/mti-malta/Makefile
index 3b7dd72..cef2db8 100644
--- a/arch/mips/mti-malta/Makefile
+++ b/arch/mips/mti-malta/Makefile
@@ -15,6 +15,6 @@
 obj-$(CONFIG_PCI)		+= malta-pci.o
 
 # FIXME FIXME FIXME
-obj-$(CONFIG_MIPS_MT_SMTC)	+= malta_smtc.o
+obj-$(CONFIG_MIPS_MT_SMTC)	+= malta-smtc.o
 
 EXTRA_CFLAGS += -Werror
diff --git a/arch/mips/mti-malta/malta-smtc.c b/arch/mips/mti-malta/malta-smtc.c
index 5ea705e..f84a46a 100644
--- a/arch/mips/mti-malta/malta-smtc.c
+++ b/arch/mips/mti-malta/malta-smtc.c
@@ -84,12 +84,17 @@
 
 static void __init msmtc_smp_setup(void)
 {
-	mipsmt_build_cpu_map(0);
+	/*
+	 * we won't get the definitive value until
+	 * we've run smtc_prepare_cpus later, but
+	 * we would appear to need an upper bound now.
+	 */
+	smp_num_siblings = smtc_build_cpu_map(0);
 }
 
 static void __init msmtc_prepare_cpus(unsigned int max_cpus)
 {
-	mipsmt_prepare_cpus();
+	smtc_prepare_cpus(max_cpus);
 }
 
 struct plat_smp_ops msmtc_smp_ops = {
diff --git a/arch/mips/pci/Makefile b/arch/mips/pci/Makefile
index 15e01ae..b188624 100644
--- a/arch/mips/pci/Makefile
+++ b/arch/mips/pci/Makefile
@@ -15,6 +15,7 @@
 obj-$(CONFIG_PCI_VR41XX)	+= ops-vr41xx.o pci-vr41xx.o
 obj-$(CONFIG_MARKEINS)		+= ops-emma2rh.o pci-emma2rh.o fixup-emma2rh.o
 obj-$(CONFIG_PCI_TX4927)	+= ops-tx4927.o
+obj-$(CONFIG_BCM47XX)		+= pci-bcm47xx.o
 
 #
 # These are still pretty much in the old state, watch, go blind.
@@ -44,6 +45,7 @@
 obj-$(CONFIG_TOSHIBA_JMR3927)	+= fixup-jmr3927.o
 obj-$(CONFIG_SOC_TX4927)	+= pci-tx4927.o
 obj-$(CONFIG_SOC_TX4938)	+= pci-tx4938.o
+obj-$(CONFIG_SOC_TX4939)	+= pci-tx4939.o
 obj-$(CONFIG_TOSHIBA_RBTX4927)	+= fixup-rbtx4927.o
 obj-$(CONFIG_TOSHIBA_RBTX4938)	+= fixup-rbtx4938.o
 obj-$(CONFIG_VICTOR_MPC30X)	+= fixup-mpc30x.o
diff --git a/arch/mips/pci/pci-bcm47xx.c b/arch/mips/pci/pci-bcm47xx.c
new file mode 100644
index 0000000..bea9b6c
--- /dev/null
+++ b/arch/mips/pci/pci-bcm47xx.c
@@ -0,0 +1,60 @@
+/*
+ *  Copyright (C) 2008 Aurelien Jarno <aurelien@aurel32.net>
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ *  THIS  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR IMPLIED
+ *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
+ *  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT, INDIRECT,
+ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
+ *  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ *  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
+ *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *  You should have received a copy of the  GNU General Public License along
+ *  with this program; if not, write  to the Free Software Foundation, Inc.,
+ *  675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/ssb/ssb.h>
+
+int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
+{
+	return 0;
+}
+
+int pcibios_plat_dev_init(struct pci_dev *dev)
+{
+	int res;
+	u8 slot, pin;
+
+	res = ssb_pcibios_plat_dev_init(dev);
+	if (res < 0) {
+		printk(KERN_ALERT "PCI: Failed to init device %s\n",
+		       pci_name(dev));
+		return res;
+	}
+
+	pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
+	slot = PCI_SLOT(dev->devfn);
+	res = ssb_pcibios_map_irq(dev, slot, pin);
+
+	/* IRQ-0 and IRQ-1 are software interrupts. */
+	if (res < 2) {
+		printk(KERN_ALERT "PCI: Failed to map IRQ of device %s\n",
+		       pci_name(dev));
+		return res;
+	}
+
+	dev->irq = res;
+	return 0;
+}
+
diff --git a/arch/mips/pci/pci-ip27.c b/arch/mips/pci/pci-ip27.c
index bd78368..f97ab14 100644
--- a/arch/mips/pci/pci-ip27.c
+++ b/arch/mips/pci/pci-ip27.c
@@ -143,25 +143,47 @@
  */
 int __devinit pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
-	struct bridge_controller *bc = BRIDGE_CONTROLLER(dev->bus);
-	int irq = bc->pci_int[slot];
+	return 0;
+}
 
-	if (irq == -1) {
-		irq = bc->pci_int[slot] = request_bridge_irq(bc);
-		if (irq < 0)
-			panic("Can't allocate interrupt for PCI device %s\n",
-			      pci_name(dev));
+/* Most MIPS systems have straight-forward swizzling needs.  */
+static inline u8 bridge_swizzle(u8 pin, u8 slot)
+{
+	return (((pin - 1) + slot) % 4) + 1;
+}
+
+static inline struct pci_dev *bridge_root_dev(struct pci_dev *dev)
+{
+	while (dev->bus->parent) {
+		/* Move up the chain of bridges. */
+		dev = dev->bus->self;
 	}
 
-	irq_to_bridge[irq] = bc;
-	irq_to_slot[irq] = slot;
-
-	return irq;
+	return dev;
 }
 
 /* Do platform specific device initialization at pci_enable_device() time */
 int pcibios_plat_dev_init(struct pci_dev *dev)
 {
+	struct bridge_controller *bc = BRIDGE_CONTROLLER(dev->bus);
+	struct pci_dev *rdev = bridge_root_dev(dev);
+	int slot = PCI_SLOT(rdev->devfn);
+	int irq;
+
+	irq = bc->pci_int[slot];
+	if (irq == -1) {
+		irq = request_bridge_irq(bc);
+		if (irq < 0)
+			return irq;
+
+		bc->pci_int[slot] = irq;
+	}
+
+	irq_to_bridge[irq] = bc;
+	irq_to_slot[irq] = slot;
+
+	dev->irq = irq;
+
 	return 0;
 }
 
diff --git a/arch/mips/pci/pci-tx4938.c b/arch/mips/pci/pci-tx4938.c
index 60e2c52..1ea257b 100644
--- a/arch/mips/pci/pci-tx4938.c
+++ b/arch/mips/pci/pci-tx4938.c
@@ -114,7 +114,7 @@
 	return pciclk;
 }
 
-int tx4938_pcic1_map_irq(const struct pci_dev *dev, u8 slot)
+int __init tx4938_pcic1_map_irq(const struct pci_dev *dev, u8 slot)
 {
 	if (get_tx4927_pcicptr(dev->bus->sysdata) == tx4938_pcic1ptr) {
 		switch (slot) {
diff --git a/arch/mips/pci/pci-tx4939.c b/arch/mips/pci/pci-tx4939.c
new file mode 100644
index 0000000..5fecf1c
--- /dev/null
+++ b/arch/mips/pci/pci-tx4939.c
@@ -0,0 +1,109 @@
+/*
+ * linux/arch/mips/pci/pci-tx4939.c
+ *
+ * Based on linux/arch/mips/txx9/rbtx4939/setup.c,
+ *	    and RBTX49xx patch from CELF patch archive.
+ *
+ * Copyright 2001, 2003-2005 MontaVista Software Inc.
+ * Copyright (C) 2004 by Ralf Baechle (ralf@linux-mips.org)
+ * (C) Copyright TOSHIBA CORPORATION 2000-2001, 2004-2007
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <asm/txx9/generic.h>
+#include <asm/txx9/tx4939.h>
+
+int __init tx4939_report_pciclk(void)
+{
+	int pciclk = 0;
+
+	pr_info("PCIC --%s PCICLK:",
+		(__raw_readq(&tx4939_ccfgptr->ccfg) & TX4939_CCFG_PCI66) ?
+		" PCI66" : "");
+	if (__raw_readq(&tx4939_ccfgptr->pcfg) & TX4939_PCFG_PCICLKEN_ALL) {
+		pciclk = txx9_master_clock * 20 / 6;
+		if (!(__raw_readq(&tx4939_ccfgptr->ccfg) & TX4939_CCFG_PCI66))
+			pciclk /= 2;
+		printk(KERN_CONT "Internal(%u.%uMHz)",
+		       (pciclk + 50000) / 1000000,
+		       ((pciclk + 50000) / 100000) % 10);
+	} else {
+		printk(KERN_CONT "External");
+		pciclk = -1;
+	}
+	printk(KERN_CONT "\n");
+	return pciclk;
+}
+
+void __init tx4939_report_pci1clk(void)
+{
+	unsigned int pciclk = txx9_master_clock * 20 / 6;
+
+	pr_info("PCIC1 -- PCICLK:%u.%uMHz\n",
+		(pciclk + 50000) / 1000000,
+		((pciclk + 50000) / 100000) % 10);
+}
+
+int __init tx4939_pcic1_map_irq(const struct pci_dev *dev, u8 slot)
+{
+	if (get_tx4927_pcicptr(dev->bus->sysdata) == tx4939_pcic1ptr) {
+		switch (slot) {
+		case TX4927_PCIC_IDSEL_AD_TO_SLOT(31):
+			if (__raw_readq(&tx4939_ccfgptr->pcfg) &
+			    TX4939_PCFG_ET0MODE)
+				return TXX9_IRQ_BASE + TX4939_IR_ETH(0);
+			break;
+		case TX4927_PCIC_IDSEL_AD_TO_SLOT(30):
+			if (__raw_readq(&tx4939_ccfgptr->pcfg) &
+			    TX4939_PCFG_ET1MODE)
+				return TXX9_IRQ_BASE + TX4939_IR_ETH(1);
+			break;
+		}
+		return 0;
+	}
+	return -1;
+}
+
+int __init tx4939_pci_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
+{
+	int irq = tx4939_pcic1_map_irq(dev, slot);
+
+	if (irq >= 0)
+		return irq;
+	irq = pin;
+	/* IRQ rotation */
+	irq--;	/* 0-3 */
+	irq = (irq + 33 - slot) % 4;
+	irq++;	/* 1-4 */
+
+	switch (irq) {
+	case 1:
+		irq = TXX9_IRQ_BASE + TX4939_IR_INTA;
+		break;
+	case 2:
+		irq = TXX9_IRQ_BASE + TX4939_IR_INTB;
+		break;
+	case 3:
+		irq = TXX9_IRQ_BASE + TX4939_IR_INTC;
+		break;
+	case 4:
+		irq = TXX9_IRQ_BASE + TX4939_IR_INTD;
+		break;
+	}
+	return irq;
+}
+
+void __init tx4939_setup_pcierr_irq(void)
+{
+	if (request_irq(TXX9_IRQ_BASE + TX4939_IR_PCIERR,
+			tx4927_pcierr_interrupt,
+			IRQF_DISABLED, "PCI error",
+			(void *)TX4939_PCIC_REG))
+		pr_warning("Failed to request irq for PCIERR\n");
+}
diff --git a/arch/mips/pmc-sierra/msp71xx/Makefile b/arch/mips/pmc-sierra/msp71xx/Makefile
index 4bba79c..e107f79 100644
--- a/arch/mips/pmc-sierra/msp71xx/Makefile
+++ b/arch/mips/pmc-sierra/msp71xx/Makefile
@@ -3,6 +3,7 @@
 #
 obj-y += msp_prom.o msp_setup.o msp_irq.o \
 	 msp_time.o msp_serial.o msp_elb.o
+obj-$(CONFIG_HAVE_GPIO_LIB) += gpio.o gpio_extended.o
 obj-$(CONFIG_PMC_MSP7120_GW) += msp_hwbutton.o
 obj-$(CONFIG_IRQ_MSP_SLP) += msp_irq_slp.o
 obj-$(CONFIG_IRQ_MSP_CIC) += msp_irq_cic.o
diff --git a/arch/mips/pmc-sierra/msp71xx/gpio.c b/arch/mips/pmc-sierra/msp71xx/gpio.c
new file mode 100644
index 0000000..69848c5
--- /dev/null
+++ b/arch/mips/pmc-sierra/msp71xx/gpio.c
@@ -0,0 +1,218 @@
+/*
+ * @file /arch/mips/pmc-sierra/msp71xx/gpio.c
+ *
+ * Generic PMC MSP71xx GPIO handling. These base gpio are controlled by two
+ * types of registers. The data register sets the output level when in output
+ * mode and when in input mode will contain the value at the input. The config
+ * register sets the various modes for each gpio.
+ *
+ * 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.
+ *
+ * @author Patrick Glass <patrickglass@gmail.com>
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/gpio.h>
+#include <linux/spinlock.h>
+#include <linux/io.h>
+
+#define MSP71XX_CFG_OFFSET(gpio)	(4 * (gpio))
+#define CONF_MASK			0x0F
+#define MSP71XX_GPIO_INPUT		0x01
+#define MSP71XX_GPIO_OUTPUT		0x08
+
+#define MSP71XX_GPIO_BASE		0x0B8400000L
+
+#define to_msp71xx_gpio_chip(c) container_of(c, struct msp71xx_gpio_chip, chip)
+
+static spinlock_t gpio_lock;
+
+/*
+ * struct msp71xx_gpio_chip - container for gpio chip and registers
+ * @chip: chip structure for the specified gpio bank
+ * @data_reg: register for reading and writing the gpio pin value
+ * @config_reg: register to set the mode for the gpio pin bank
+ * @out_drive_reg: register to set the output drive mode for the gpio pin bank
+ */
+struct msp71xx_gpio_chip {
+	struct gpio_chip chip;
+	void __iomem *data_reg;
+	void __iomem *config_reg;
+	void __iomem *out_drive_reg;
+};
+
+/*
+ * msp71xx_gpio_get() - return the chip's gpio value
+ * @chip: chip structure which controls the specified gpio
+ * @offset: gpio whose value will be returned
+ *
+ * It will return 0 if gpio value is low and other if high.
+ */
+static int msp71xx_gpio_get(struct gpio_chip *chip, unsigned offset)
+{
+	struct msp71xx_gpio_chip *msp_chip = to_msp71xx_gpio_chip(chip);
+
+	return __raw_readl(msp_chip->data_reg) & (1 << offset);
+}
+
+/*
+ * msp71xx_gpio_set() - set the output value for the gpio
+ * @chip: chip structure who controls the specified gpio
+ * @offset: gpio whose value will be assigned
+ * @value: logic level to assign to the gpio initially
+ *
+ * This will set the gpio bit specified to the desired value. It will set the
+ * gpio pin low if value is 0 otherwise it will be high.
+ */
+static void msp71xx_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
+{
+	struct msp71xx_gpio_chip *msp_chip = to_msp71xx_gpio_chip(chip);
+	unsigned long flags;
+	u32 data;
+
+	spin_lock_irqsave(&gpio_lock, flags);
+
+	data = __raw_readl(msp_chip->data_reg);
+	if (value)
+		data |= (1 << offset);
+	else
+		data &= ~(1 << offset);
+	__raw_writel(data, msp_chip->data_reg);
+
+	spin_unlock_irqrestore(&gpio_lock, flags);
+}
+
+/*
+ * msp71xx_set_gpio_mode() - declare the mode for a gpio
+ * @chip: chip structure which controls the specified gpio
+ * @offset: gpio whose value will be assigned
+ * @mode: desired configuration for the gpio (see datasheet)
+ *
+ * It will set the gpio pin config to the @mode value passed in.
+ */
+static int msp71xx_set_gpio_mode(struct gpio_chip *chip,
+				 unsigned offset, int mode)
+{
+	struct msp71xx_gpio_chip *msp_chip = to_msp71xx_gpio_chip(chip);
+	const unsigned bit_offset = MSP71XX_CFG_OFFSET(offset);
+	unsigned long flags;
+	u32 cfg;
+
+	spin_lock_irqsave(&gpio_lock, flags);
+
+	cfg = __raw_readl(msp_chip->config_reg);
+	cfg &= ~(CONF_MASK << bit_offset);
+	cfg |= (mode << bit_offset);
+	__raw_writel(cfg, msp_chip->config_reg);
+
+	spin_unlock_irqrestore(&gpio_lock, flags);
+
+	return 0;
+}
+
+/*
+ * msp71xx_direction_output() - declare the direction mode for a gpio
+ * @chip: chip structure which controls the specified gpio
+ * @offset: gpio whose value will be assigned
+ * @value: logic level to assign to the gpio initially
+ *
+ * This call will set the mode for the @gpio to output. It will set the
+ * gpio pin low if value is 0 otherwise it will be high.
+ */
+static int msp71xx_direction_output(struct gpio_chip *chip,
+				    unsigned offset, int value)
+{
+	msp71xx_gpio_set(chip, offset, value);
+
+	return msp71xx_set_gpio_mode(chip, offset, MSP71XX_GPIO_OUTPUT);
+}
+
+/*
+ * msp71xx_direction_input() - declare the direction mode for a gpio
+ * @chip: chip structure which controls the specified gpio
+ * @offset: gpio whose to which the value will be assigned
+ *
+ * This call will set the mode for the @gpio to input.
+ */
+static int msp71xx_direction_input(struct gpio_chip *chip, unsigned offset)
+{
+	return msp71xx_set_gpio_mode(chip, offset, MSP71XX_GPIO_INPUT);
+}
+
+/*
+ * msp71xx_set_output_drive() - declare the output drive for the gpio line
+ * @gpio: gpio pin whose output drive you wish to modify
+ * @value: zero for active drain 1 for open drain drive
+ *
+ * This call will set the output drive mode for the @gpio to output.
+ */
+int msp71xx_set_output_drive(unsigned gpio, int value)
+{
+	unsigned long flags;
+	u32 data;
+
+	if (gpio > 15 || gpio < 0)
+		return -EINVAL;
+
+	spin_lock_irqsave(&gpio_lock, flags);
+
+	data = __raw_readl((void __iomem *)(MSP71XX_GPIO_BASE + 0x190));
+	if (value)
+		data |= (1 << gpio);
+	else
+		data &= ~(1 << gpio);
+	__raw_writel(data, (void __iomem *)(MSP71XX_GPIO_BASE + 0x190));
+
+	spin_unlock_irqrestore(&gpio_lock, flags);
+
+	return 0;
+}
+EXPORT_SYMBOL(msp71xx_set_output_drive);
+
+#define MSP71XX_GPIO_BANK(name, dr, cr, base_gpio, num_gpio) \
+{ \
+	.chip = { \
+		.label		  = name, \
+		.direction_input  = msp71xx_direction_input, \
+		.direction_output = msp71xx_direction_output, \
+		.get		  = msp71xx_gpio_get, \
+		.set		  = msp71xx_gpio_set, \
+		.base		  = base_gpio, \
+		.ngpio		  = num_gpio \
+	}, \
+	.data_reg	= (void __iomem *)(MSP71XX_GPIO_BASE + dr), \
+	.config_reg	= (void __iomem *)(MSP71XX_GPIO_BASE + cr), \
+	.out_drive_reg	= (void __iomem *)(MSP71XX_GPIO_BASE + 0x190), \
+}
+
+/*
+ * struct msp71xx_gpio_banks[] - container array of gpio banks
+ * @chip: chip structure for the specified gpio bank
+ * @data_reg: register for reading and writing the gpio pin value
+ * @config_reg: register to set the mode for the gpio pin bank
+ *
+ * This array structure defines the gpio banks for the PMC MIPS Processor.
+ * We specify the bank name, the data register, the config register, base
+ * starting gpio number, and the number of gpios exposed by the bank.
+ */
+static struct msp71xx_gpio_chip msp71xx_gpio_banks[] = {
+
+	MSP71XX_GPIO_BANK("GPIO_1_0", 0x170, 0x180, 0, 2),
+	MSP71XX_GPIO_BANK("GPIO_5_2", 0x174, 0x184, 2, 4),
+	MSP71XX_GPIO_BANK("GPIO_9_6", 0x178, 0x188, 6, 4),
+	MSP71XX_GPIO_BANK("GPIO_15_10", 0x17C, 0x18C, 10, 6),
+};
+
+void __init msp71xx_init_gpio(void)
+{
+	int i;
+
+	spin_lock_init(&gpio_lock);
+
+	for (i = 0; i < ARRAY_SIZE(msp71xx_gpio_banks); i++)
+		gpiochip_add(&msp71xx_gpio_banks[i].chip);
+}
diff --git a/arch/mips/pmc-sierra/msp71xx/gpio_extended.c b/arch/mips/pmc-sierra/msp71xx/gpio_extended.c
new file mode 100644
index 0000000..fc6dbc6
--- /dev/null
+++ b/arch/mips/pmc-sierra/msp71xx/gpio_extended.c
@@ -0,0 +1,148 @@
+/*
+ * @file /arch/mips/pmc-sierra/msp71xx/gpio_extended.c
+ *
+ * Generic PMC MSP71xx EXTENDED (EXD) GPIO handling. The extended gpio is
+ * a set of hardware registers that have no need for explicit locking as
+ * it is handled by unique method of writing individual set/clr bits.
+ *
+ * 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.
+ *
+ * @author Patrick Glass <patrickglass@gmail.com>
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/gpio.h>
+#include <linux/io.h>
+
+#define MSP71XX_DATA_OFFSET(gpio)	(2 * (gpio))
+#define MSP71XX_READ_OFFSET(gpio)	(MSP71XX_DATA_OFFSET(gpio) + 1)
+#define MSP71XX_CFG_OUT_OFFSET(gpio)	(MSP71XX_DATA_OFFSET(gpio) + 16)
+#define MSP71XX_CFG_IN_OFFSET(gpio)	(MSP71XX_CFG_OUT_OFFSET(gpio) + 1)
+
+#define MSP71XX_EXD_GPIO_BASE	0x0BC000000L
+
+#define to_msp71xx_exd_gpio_chip(c) \
+			container_of(c, struct msp71xx_exd_gpio_chip, chip)
+
+/*
+ * struct msp71xx_exd_gpio_chip - container for gpio chip and registers
+ * @chip: chip structure for the specified gpio bank
+ * @reg: register for control and data of gpio pin
+ */
+struct msp71xx_exd_gpio_chip {
+	struct gpio_chip chip;
+	void __iomem *reg;
+};
+
+/*
+ * msp71xx_exd_gpio_get() - return the chip's gpio value
+ * @chip: chip structure which controls the specified gpio
+ * @offset: gpio whose value will be returned
+ *
+ * It will return 0 if gpio value is low and other if high.
+ */
+static int msp71xx_exd_gpio_get(struct gpio_chip *chip, unsigned offset)
+{
+	struct msp71xx_exd_gpio_chip *msp71xx_chip =
+	    to_msp71xx_exd_gpio_chip(chip);
+	const unsigned bit = MSP71XX_READ_OFFSET(offset);
+
+	return __raw_readl(msp71xx_chip->reg) & (1 << bit);
+}
+
+/*
+ * msp71xx_exd_gpio_set() - set the output value for the gpio
+ * @chip: chip structure who controls the specified gpio
+ * @offset: gpio whose value will be assigned
+ * @value: logic level to assign to the gpio initially
+ *
+ * This will set the gpio bit specified to the desired value. It will set the
+ * gpio pin low if value is 0 otherwise it will be high.
+ */
+static void msp71xx_exd_gpio_set(struct gpio_chip *chip,
+				 unsigned offset, int value)
+{
+	struct msp71xx_exd_gpio_chip *msp71xx_chip =
+	    to_msp71xx_exd_gpio_chip(chip);
+	const unsigned bit = MSP71XX_DATA_OFFSET(offset);
+
+	__raw_writel(1 << (bit + (value ? 1 : 0)), msp71xx_chip->reg);
+}
+
+/*
+ * msp71xx_exd_direction_output() - declare the direction mode for a gpio
+ * @chip: chip structure which controls the specified gpio
+ * @offset: gpio whose value will be assigned
+ * @value: logic level to assign to the gpio initially
+ *
+ * This call will set the mode for the @gpio to output. It will set the
+ * gpio pin low if value is 0 otherwise it will be high.
+ */
+static int msp71xx_exd_direction_output(struct gpio_chip *chip,
+					unsigned offset, int value)
+{
+	struct msp71xx_exd_gpio_chip *msp71xx_chip =
+	    to_msp71xx_exd_gpio_chip(chip);
+
+	msp71xx_exd_gpio_set(chip, offset, value);
+	__raw_writel(1 << MSP71XX_CFG_OUT_OFFSET(offset), msp71xx_chip->reg);
+	return 0;
+}
+
+/*
+ * msp71xx_exd_direction_input() - declare the direction mode for a gpio
+ * @chip: chip structure which controls the specified gpio
+ * @offset: gpio whose to which the value will be assigned
+ *
+ * This call will set the mode for the @gpio to input.
+ */
+static int msp71xx_exd_direction_input(struct gpio_chip *chip, unsigned offset)
+{
+	struct msp71xx_exd_gpio_chip *msp71xx_chip =
+	    to_msp71xx_exd_gpio_chip(chip);
+
+	__raw_writel(1 << MSP71XX_CFG_IN_OFFSET(offset), msp71xx_chip->reg);
+	return 0;
+}
+
+#define MSP71XX_EXD_GPIO_BANK(name, exd_reg, base_gpio, num_gpio) \
+{ \
+	.chip = { \
+		.label		  = name, \
+		.direction_input  = msp71xx_exd_direction_input, \
+		.direction_output = msp71xx_exd_direction_output, \
+		.get		  = msp71xx_exd_gpio_get, \
+		.set		  = msp71xx_exd_gpio_set, \
+		.base		  = base_gpio, \
+		.ngpio		  = num_gpio, \
+	}, \
+	.reg	= (void __iomem *)(MSP71XX_EXD_GPIO_BASE + exd_reg), \
+}
+
+/*
+ * struct msp71xx_exd_gpio_banks[] - container array of gpio banks
+ * @chip: chip structure for the specified gpio bank
+ * @reg: register for reading and writing the gpio pin value
+ *
+ * This array structure defines the extended gpio banks for the
+ * PMC MIPS Processor. We specify the bank name, the data/config
+ * register,the base starting gpio number, and the number of
+ * gpios exposed by the bank of gpios.
+ */
+static struct msp71xx_exd_gpio_chip msp71xx_exd_gpio_banks[] = {
+
+	MSP71XX_EXD_GPIO_BANK("GPIO_23_16", 0x188, 16, 8),
+	MSP71XX_EXD_GPIO_BANK("GPIO_27_24", 0x18C, 24, 4),
+};
+
+void __init msp71xx_init_gpio_extended(void)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(msp71xx_exd_gpio_banks); i++)
+		gpiochip_add(&msp71xx_exd_gpio_banks[i].chip);
+}
diff --git a/arch/mips/rb532/devices.c b/arch/mips/rb532/devices.c
index 82ab395..31619c6 100644
--- a/arch/mips/rb532/devices.c
+++ b/arch/mips/rb532/devices.c
@@ -34,21 +34,11 @@
 #include <asm/mach-rc32434/rb.h>
 #include <asm/mach-rc32434/integ.h>
 #include <asm/mach-rc32434/gpio.h>
-
-#define ETH0_DMA_RX_IRQ   	(GROUP1_IRQ_BASE + 0)
-#define ETH0_DMA_TX_IRQ   	(GROUP1_IRQ_BASE + 1)
-#define ETH0_RX_OVR_IRQ   	(GROUP3_IRQ_BASE + 9)
-#define ETH0_TX_UND_IRQ   	(GROUP3_IRQ_BASE + 10)
+#include <asm/mach-rc32434/irq.h>
 
 #define ETH0_RX_DMA_ADDR  (DMA0_BASE_ADDR + 0 * DMA_CHAN_OFFSET)
 #define ETH0_TX_DMA_ADDR  (DMA0_BASE_ADDR + 1 * DMA_CHAN_OFFSET)
 
-/* NAND definitions */
-#define GPIO_RDY (1 << 0x08)
-#define GPIO_WPX (1 << 0x09)
-#define GPIO_ALE (1 << 0x0a)
-#define GPIO_CLE (1 << 0x0b)
-
 static struct resource korina_dev0_res[] = {
 	{
 		.name = "korina_regs",
@@ -94,15 +84,13 @@
 };
 
 static struct platform_device korina_dev0 = {
-	.id = 0,
+	.id = -1,
 	.name = "korina",
 	.dev.platform_data = &korina_dev0_data,
 	.resource = korina_dev0_res,
 	.num_resources = ARRAY_SIZE(korina_dev0_res),
 };
 
-#define CF_GPIO_NUM 13
-
 static struct resource cf_slot0_res[] = {
 	{
 		.name = "cf_membase",
@@ -116,11 +104,11 @@
 };
 
 static struct cf_device cf_slot0_data = {
-	.gpio_pin = 13
+	.gpio_pin = CF_GPIO_NUM
 };
 
 static struct platform_device cf_slot0 = {
-	.id = 0,
+	.id = -1,
 	.name = "pata-rb532-cf",
 	.dev.platform_data = &cf_slot0_data,
 	.resource = cf_slot0_res,
@@ -185,7 +173,7 @@
 
 static struct platform_device rb532_led = {
 	.name = "rb532-led",
-	.id = 0,
+	.id = -1,
 };
 
 static struct gpio_keys_button rb532_gpio_btn[] = {
diff --git a/arch/mips/rb532/gpio.c b/arch/mips/rb532/gpio.c
index 00a1c78..76a7fd9 100644
--- a/arch/mips/rb532/gpio.c
+++ b/arch/mips/rb532/gpio.c
@@ -27,28 +27,31 @@
  */
 
 #include <linux/kernel.h>
-#include <linux/gpio.h>
 #include <linux/init.h>
 #include <linux/types.h>
-#include <linux/pci.h>
 #include <linux/spinlock.h>
-#include <linux/io.h>
 #include <linux/platform_device.h>
-
-#include <asm/addrspace.h>
+#include <linux/gpio.h>
 
 #include <asm/mach-rc32434/rb.h>
+#include <asm/mach-rc32434/gpio.h>
 
-struct rb532_gpio_reg __iomem *rb532_gpio_reg0;
-EXPORT_SYMBOL(rb532_gpio_reg0);
+struct rb532_gpio_chip {
+	struct gpio_chip chip;
+	void __iomem	 *regbase;
+	void		(*set_int_level)(struct gpio_chip *chip, unsigned offset, int value);
+	int		(*get_int_level)(struct gpio_chip *chip, unsigned offset);
+	void		(*set_int_status)(struct gpio_chip *chip, unsigned offset, int value);
+	int		(*get_int_status)(struct gpio_chip *chip, unsigned offset);
+};
 
 struct mpmc_device dev3;
 
 static struct resource rb532_gpio_reg0_res[] = {
 	{
 		.name 	= "gpio_reg0",
-		.start 	= (u32)(IDT434_REG_BASE + GPIOBASE),
-		.end 	= (u32)(IDT434_REG_BASE + GPIOBASE + sizeof(struct rb532_gpio_reg)),
+		.start 	= REGBASE + GPIOBASE,
+		.end 	= REGBASE + GPIOBASE + sizeof(struct rb532_gpio_reg) - 1,
 		.flags 	= IORESOURCE_MEM,
 	}
 };
@@ -56,8 +59,8 @@
 static struct resource rb532_dev3_ctl_res[] = {
 	{
 		.name	= "dev3_ctl",
-		.start	= (u32)(IDT434_REG_BASE + DEV3BASE),
-		.end	= (u32)(IDT434_REG_BASE + DEV3BASE + sizeof(struct dev_reg)),
+		.start	= REGBASE + DEV3BASE,
+		.end	= REGBASE + DEV3BASE + sizeof(struct dev_reg) - 1,
 		.flags	= IORESOURCE_MEM,
 	}
 };
@@ -70,7 +73,7 @@
 
 	spin_lock_irqsave(&dev3.lock, flags);
 
-	data = *(volatile unsigned *) (IDT434_REG_BASE + reg_offs);
+	data = readl(IDT434_REG_BASE + reg_offs);
 	for (i = 0; i != len; ++i) {
 		if (val & (1 << i))
 			data |= (1 << (i + bit));
@@ -108,108 +111,199 @@
 }
 EXPORT_SYMBOL(get_latch_u5);
 
-int rb532_gpio_get_value(unsigned gpio)
+/*
+ * Return GPIO level */
+static int rb532_gpio_get(struct gpio_chip *chip, unsigned offset)
 {
-	return readl(&rb532_gpio_reg0->gpiod) & (1 << gpio);
+	u32			mask = 1 << offset;
+	struct rb532_gpio_chip	*gpch;
+
+	gpch = container_of(chip, struct rb532_gpio_chip, chip);
+	return readl(gpch->regbase + GPIOD) & mask;
 }
-EXPORT_SYMBOL(rb532_gpio_get_value);
 
-void rb532_gpio_set_value(unsigned gpio, int value)
+/*
+ * Set output GPIO level
+ */
+static void rb532_gpio_set(struct gpio_chip *chip,
+				unsigned offset, int value)
 {
-	unsigned tmp;
+	unsigned long		flags;
+	u32			mask = 1 << offset;
+	u32			tmp;
+	struct rb532_gpio_chip	*gpch;
+	void __iomem		*gpvr;
 
-	tmp = readl(&rb532_gpio_reg0->gpiod) & ~(1 << gpio);
+	gpch = container_of(chip, struct rb532_gpio_chip, chip);
+	gpvr = gpch->regbase + GPIOD;
+
+	local_irq_save(flags);
+	tmp = readl(gpvr);
 	if (value)
-		tmp |= 1 << gpio;
-
-	writel(tmp, (void *)&rb532_gpio_reg0->gpiod);
+		tmp |= mask;
+	else
+		tmp &= ~mask;
+	writel(tmp, gpvr);
+	local_irq_restore(flags);
 }
-EXPORT_SYMBOL(rb532_gpio_set_value);
 
-int rb532_gpio_direction_input(unsigned gpio)
+/*
+ * Set GPIO direction to input
+ */
+static int rb532_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
 {
-	writel(readl(&rb532_gpio_reg0->gpiocfg) & ~(1 << gpio),
-	       (void *)&rb532_gpio_reg0->gpiocfg);
+	unsigned long		flags;
+	u32			mask = 1 << offset;
+	u32			value;
+	struct rb532_gpio_chip	*gpch;
+	void __iomem		*gpdr;
+
+	gpch = container_of(chip, struct rb532_gpio_chip, chip);
+	gpdr = gpch->regbase + GPIOCFG;
+
+	local_irq_save(flags);
+	value = readl(gpdr);
+	value &= ~mask;
+	writel(value, gpdr);
+	local_irq_restore(flags);
 
 	return 0;
 }
-EXPORT_SYMBOL(rb532_gpio_direction_input);
 
-int rb532_gpio_direction_output(unsigned gpio, int value)
+/*
+ * Set GPIO direction to output
+ */
+static int rb532_gpio_direction_output(struct gpio_chip *chip,
+					unsigned offset, int value)
 {
-	gpio_set_value(gpio, value);
-	writel(readl(&rb532_gpio_reg0->gpiocfg) | (1 << gpio),
-	       (void *)&rb532_gpio_reg0->gpiocfg);
+	unsigned long		flags;
+	u32			mask = 1 << offset;
+	u32			tmp;
+	struct rb532_gpio_chip	*gpch;
+	void __iomem		*gpdr;
+
+	gpch = container_of(chip, struct rb532_gpio_chip, chip);
+	writel(mask, gpch->regbase + GPIOD);
+	gpdr = gpch->regbase + GPIOCFG;
+
+	local_irq_save(flags);
+	tmp = readl(gpdr);
+	tmp |= mask;
+	writel(tmp, gpdr);
+	local_irq_restore(flags);
 
 	return 0;
 }
-EXPORT_SYMBOL(rb532_gpio_direction_output);
 
-void rb532_gpio_set_int_level(unsigned gpio, int value)
+/*
+ * Set the GPIO interrupt level
+ */
+static void rb532_gpio_set_int_level(struct gpio_chip *chip,
+					unsigned offset, int value)
 {
-	unsigned tmp;
+	unsigned long		flags;
+	u32			mask = 1 << offset;
+	u32			tmp;
+	struct rb532_gpio_chip	*gpch;
+	void __iomem		*gpil;
 
-	tmp = readl(&rb532_gpio_reg0->gpioilevel) & ~(1 << gpio);
+	gpch = container_of(chip, struct rb532_gpio_chip, chip);
+	gpil = gpch->regbase + GPIOILEVEL;
+
+	local_irq_save(flags);
+	tmp = readl(gpil);
 	if (value)
-		tmp |= 1 << gpio;
-	writel(tmp, (void *)&rb532_gpio_reg0->gpioilevel);
+		tmp |= mask;
+	else
+		tmp &= ~mask;
+	writel(tmp, gpil);
+	local_irq_restore(flags);
 }
-EXPORT_SYMBOL(rb532_gpio_set_int_level);
 
-int rb532_gpio_get_int_level(unsigned gpio)
+/*
+ * Get the GPIO interrupt level
+ */
+static int rb532_gpio_get_int_level(struct gpio_chip *chip, unsigned offset)
 {
-	return readl(&rb532_gpio_reg0->gpioilevel) & (1 << gpio);
+	u32			mask = 1 << offset;
+	struct rb532_gpio_chip	*gpch;
+
+	gpch = container_of(chip, struct rb532_gpio_chip, chip);
+	return readl(gpch->regbase + GPIOILEVEL) & mask;
 }
-EXPORT_SYMBOL(rb532_gpio_get_int_level);
 
-void rb532_gpio_set_int_status(unsigned gpio, int value)
+/*
+ * Set the GPIO interrupt status
+ */
+static void rb532_gpio_set_int_status(struct gpio_chip *chip,
+				unsigned offset, int value)
 {
-	unsigned tmp;
+	unsigned long		flags;
+	u32			mask = 1 << offset;
+	u32			tmp;
+	struct rb532_gpio_chip	*gpch;
+	void __iomem		*gpis;
 
-	tmp = readl(&rb532_gpio_reg0->gpioistat);
+	gpch = container_of(chip, struct rb532_gpio_chip, chip);
+	gpis = gpch->regbase + GPIOISTAT;
+
+	local_irq_save(flags);
+	tmp = readl(gpis);
 	if (value)
-		tmp |= 1 << gpio;
-	writel(tmp, (void *)&rb532_gpio_reg0->gpioistat);
+		tmp |= mask;
+	else
+		tmp &= ~mask;
+	writel(tmp, gpis);
+	local_irq_restore(flags);
 }
-EXPORT_SYMBOL(rb532_gpio_set_int_status);
 
-int rb532_gpio_get_int_status(unsigned gpio)
+/*
+ * Get the GPIO interrupt status
+ */
+static int rb532_gpio_get_int_status(struct gpio_chip *chip, unsigned offset)
 {
-	return readl(&rb532_gpio_reg0->gpioistat) & (1 << gpio);
-}
-EXPORT_SYMBOL(rb532_gpio_get_int_status);
+	u32			mask = 1 << offset;
+	struct rb532_gpio_chip	*gpch;
 
-void rb532_gpio_set_func(unsigned gpio, int value)
-{
-	unsigned tmp;
-
-	tmp = readl(&rb532_gpio_reg0->gpiofunc);
-	if (value)
-		tmp |= 1 << gpio;
-	writel(tmp, (void *)&rb532_gpio_reg0->gpiofunc);
+	gpch = container_of(chip, struct rb532_gpio_chip, chip);
+	return readl(gpch->regbase + GPIOISTAT) & mask;
 }
-EXPORT_SYMBOL(rb532_gpio_set_func);
 
-int rb532_gpio_get_func(unsigned gpio)
-{
-	return readl(&rb532_gpio_reg0->gpiofunc) & (1 << gpio);
-}
-EXPORT_SYMBOL(rb532_gpio_get_func);
+static struct rb532_gpio_chip rb532_gpio_chip[] = {
+	[0] = {
+		.chip = {
+			.label			= "gpio0",
+			.direction_input	= rb532_gpio_direction_input,
+			.direction_output	= rb532_gpio_direction_output,
+			.get			= rb532_gpio_get,
+			.set			= rb532_gpio_set,
+			.base			= 0,
+			.ngpio			= 32,
+		},
+		.get_int_level		= rb532_gpio_get_int_level,
+		.set_int_level		= rb532_gpio_set_int_level,
+		.get_int_status		= rb532_gpio_get_int_status,
+		.set_int_status		= rb532_gpio_set_int_status,
+	},
+};
 
 int __init rb532_gpio_init(void)
 {
-	rb532_gpio_reg0 = ioremap_nocache(rb532_gpio_reg0_res[0].start,
-				rb532_gpio_reg0_res[0].end -
-				rb532_gpio_reg0_res[0].start);
+	struct resource *r;
 
-	if (!rb532_gpio_reg0) {
+	r = rb532_gpio_reg0_res;
+	rb532_gpio_chip->regbase = ioremap_nocache(r->start, r->end - r->start);
+
+	if (!rb532_gpio_chip->regbase) {
 		printk(KERN_ERR "rb532: cannot remap GPIO register 0\n");
 		return -ENXIO;
 	}
 
-	dev3.base = ioremap_nocache(rb532_dev3_ctl_res[0].start,
-				rb532_dev3_ctl_res[0].end -
-				rb532_dev3_ctl_res[0].start);
+	/* Register our GPIO chip */
+	gpiochip_add(&rb532_gpio_chip->chip);
+
+	r = rb532_dev3_ctl_res;
+	dev3.base = ioremap_nocache(r->start, r->end - r->start);
 
 	if (!dev3.base) {
 		printk(KERN_ERR "rb532: cannot remap device controller 3\n");
diff --git a/arch/mips/rb532/irq.c b/arch/mips/rb532/irq.c
index c0d0f95..549b46d 100644
--- a/arch/mips/rb532/irq.c
+++ b/arch/mips/rb532/irq.c
@@ -45,7 +45,7 @@
 #include <asm/mipsregs.h>
 #include <asm/system.h>
 
-#include <asm/mach-rc32434/rc32434.h>
+#include <asm/mach-rc32434/irq.h>
 
 struct intr_group {
 	u32 mask;	/* mask of valid bits in pending/mask registers */
diff --git a/arch/mips/rb532/prom.c b/arch/mips/rb532/prom.c
index 1bc0af8..46ca24d 100644
--- a/arch/mips/rb532/prom.c
+++ b/arch/mips/rb532/prom.c
@@ -37,12 +37,8 @@
 #include <asm/mach-rc32434/ddr.h>
 #include <asm/mach-rc32434/prom.h>
 
-extern void __init setup_serial_port(void);
-
 unsigned int idt_cpu_freq = 132000000;
 EXPORT_SYMBOL(idt_cpu_freq);
-unsigned int gpio_bootup_state;
-EXPORT_SYMBOL(gpio_bootup_state);
 
 static struct resource ddr_reg[] = {
 	{
@@ -108,9 +104,6 @@
 				mips_machtype = MACH_MIKROTIK_RB532;
 		}
 
-		if (match_tag(prom_argv[i], GPIO_TAG))
-			gpio_bootup_state = tag2ul(prom_argv[i], GPIO_TAG);
-
 		strcpy(cp, prom_argv[i]);
 		cp += strlen(prom_argv[i]);
 	}
@@ -122,11 +115,6 @@
 		strcpy(cp, arcs_cmdline);
 		cp += strlen(arcs_cmdline);
 	}
-	if (gpio_bootup_state & 0x02)
-		strcpy(cp, GPIO_INIT_NOBUTTON);
-	else
-		strcpy(cp, GPIO_INIT_BUTTON);
-
 	cmd_line[CL_SIZE-1] = '\0';
 
 	strcpy(arcs_cmdline, cmd_line);
diff --git a/arch/mips/rb532/serial.c b/arch/mips/rb532/serial.c
index 1a05b5d..3e0d7ec 100644
--- a/arch/mips/rb532/serial.c
+++ b/arch/mips/rb532/serial.c
@@ -31,16 +31,16 @@
 #include <linux/serial_8250.h>
 
 #include <asm/serial.h>
-#include <asm/mach-rc32434/rc32434.h>
+#include <asm/mach-rc32434/rb.h>
 
 extern unsigned int idt_cpu_freq;
 
 static struct uart_port rb532_uart = {
 	.type = PORT_16550A,
 	.line = 0,
-	.irq = RC32434_UART0_IRQ,
+	.irq = UART0_IRQ,
 	.iotype = UPIO_MEM,
-	.membase = (char *)KSEG1ADDR(RC32434_UART0_BASE),
+	.membase = (char *)KSEG1ADDR(REGBASE + UART0BASE),
 	.regshift = 2
 };
 
diff --git a/arch/mips/rb532/setup.c b/arch/mips/rb532/setup.c
index 7aafa95..50f530f 100644
--- a/arch/mips/rb532/setup.c
+++ b/arch/mips/rb532/setup.c
@@ -9,7 +9,7 @@
 #include <asm/time.h>
 #include <linux/ioport.h>
 
-#include <asm/mach-rc32434/rc32434.h>
+#include <asm/mach-rc32434/rb.h>
 #include <asm/mach-rc32434/pci.h>
 
 struct pci_reg __iomem *pci_reg;
@@ -27,7 +27,7 @@
 static void rb_machine_restart(char *command)
 {
 	/* just jump to the reset vector */
-	writel(0x80000001, (void *)KSEG1ADDR(RC32434_REG_BASE + RC32434_RST));
+	writel(0x80000001, IDT434_REG_BASE + RST);
 	((void (*)(void)) KSEG1ADDR(0x1FC00000u))();
 }
 
diff --git a/arch/mips/sibyte/swarm/Makefile b/arch/mips/sibyte/swarm/Makefile
index f18ba92..7b45f19 100644
--- a/arch/mips/sibyte/swarm/Makefile
+++ b/arch/mips/sibyte/swarm/Makefile
@@ -1,3 +1,4 @@
-obj-y				:= setup.o rtc_xicor1241.o rtc_m41t81.o
+obj-y				:= platform.o setup.o rtc_xicor1241.o \
+				   rtc_m41t81.o
 
 obj-$(CONFIG_I2C_BOARDINFO)	+= swarm-i2c.o
diff --git a/arch/mips/sibyte/swarm/platform.c b/arch/mips/sibyte/swarm/platform.c
new file mode 100644
index 0000000..54847fe
--- /dev/null
+++ b/arch/mips/sibyte/swarm/platform.c
@@ -0,0 +1,85 @@
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/ata_platform.h>
+
+#include <asm/sibyte/board.h>
+#include <asm/sibyte/sb1250_genbus.h>
+#include <asm/sibyte/sb1250_regs.h>
+
+#if defined(CONFIG_SIBYTE_SWARM) || defined(CONFIG_SIBYTE_LITTLESUR)
+
+#define DRV_NAME	"pata-swarm"
+
+#define SWARM_IDE_SHIFT	5
+#define SWARM_IDE_BASE	0x1f0
+#define SWARM_IDE_CTRL	0x3f6
+
+static struct resource swarm_pata_resource[] = {
+	{
+		.name	= "Swarm GenBus IDE",
+		.flags	= IORESOURCE_MEM,
+	}, {
+		.name	= "Swarm GenBus IDE",
+		.flags	= IORESOURCE_MEM,
+	}, {
+		.name	= "Swarm GenBus IDE",
+		.flags	= IORESOURCE_IRQ,
+		.start	= K_INT_GB_IDE,
+		.end	= K_INT_GB_IDE,
+	},
+};
+
+static struct pata_platform_info pata_platform_data = {
+	.ioport_shift	= SWARM_IDE_SHIFT,
+};
+
+static struct platform_device swarm_pata_device = {
+	.name		= "pata_platform",
+	.id		= -1,
+	.resource	= swarm_pata_resource,
+	.num_resources	= ARRAY_SIZE(swarm_pata_resource),
+	.dev  = {
+		.platform_data		= &pata_platform_data,
+		.coherent_dma_mask	= ~0,	/* grumble */
+	},
+};
+
+static int __init swarm_pata_init(void)
+{
+	u8 __iomem *base;
+	phys_t offset, size;
+	struct resource *r;
+
+	if (!SIBYTE_HAVE_IDE)
+		return -ENODEV;
+
+	base = ioremap(A_IO_EXT_BASE, 0x800);
+	offset = __raw_readq(base + R_IO_EXT_REG(R_IO_EXT_START_ADDR, IDE_CS));
+	size = __raw_readq(base + R_IO_EXT_REG(R_IO_EXT_MULT_SIZE, IDE_CS));
+	iounmap(base);
+
+	offset = G_IO_START_ADDR(offset) << S_IO_ADDRBASE;
+	size = (G_IO_MULT_SIZE(size) + 1) << S_IO_REGSIZE;
+	if (offset < A_PHYS_GENBUS || offset >= A_PHYS_GENBUS_END) {
+		pr_info(DRV_NAME ": PATA interface at GenBus disabled\n");
+
+		return -EBUSY;
+	}
+
+	pr_info(DRV_NAME ": PATA interface at GenBus slot %i\n", IDE_CS);
+
+	r = swarm_pata_resource;
+	r[0].start = offset + (SWARM_IDE_BASE << SWARM_IDE_SHIFT);
+	r[0].end   = offset + ((SWARM_IDE_BASE + 8) << SWARM_IDE_SHIFT) - 1;
+	r[1].start = offset + (SWARM_IDE_CTRL << SWARM_IDE_SHIFT);
+	r[1].end   = offset + ((SWARM_IDE_CTRL + 1) << SWARM_IDE_SHIFT) - 1;
+
+	return platform_device_register(&swarm_pata_device);
+}
+
+device_initcall(swarm_pata_init);
+
+#endif /* defined(CONFIG_SIBYTE_SWARM) || defined(CONFIG_SIBYTE_LITTLESUR) */
diff --git a/arch/mips/txx9/Kconfig b/arch/mips/txx9/Kconfig
index 840fe75..17052db 100644
--- a/arch/mips/txx9/Kconfig
+++ b/arch/mips/txx9/Kconfig
@@ -45,6 +45,14 @@
 	  This Toshiba board is based on the TX4938 processor. Say Y here to
 	  support this machine type
 
+config TOSHIBA_RBTX4939
+	bool "Toshiba RBTX4939 bobard"
+	depends on MACH_TX49XX
+	select SOC_TX4939
+	help
+	  This Toshiba board is based on the TX4939 processor. Say Y here to
+	  support this machine type
+
 config SOC_TX3927
 	bool
 	select CEVT_TXX9
@@ -71,6 +79,13 @@
 	select PCI_TX4927
 	select GPIO_TXX9
 
+config SOC_TX4939
+	bool
+	select CEVT_TXX9
+	select HAS_TXX9_SERIAL
+	select HW_HAS_PCI
+	select PCI_TX4927
+
 config TOSHIBA_FPCIB0
 	bool "FPCIB0 Backplane Support"
 	depends on PCI && MACH_TXX9
@@ -94,16 +109,11 @@
 	bool "NAND"
 config TOSHIBA_RBTX4938_MPLEX_ATA
 	bool "ATA"
+config TOSHIBA_RBTX4938_MPLEX_KEEP
+	bool "Keep firmware settings"
 
 endchoice
 
-config TX4938_NAND_BOOT
-	depends on EXPERIMENTAL && TOSHIBA_RBTX4938_MPLEX_NAND
-	bool "NAND Boot Support (EXPERIMENTAL)"
-	help
-	  This is only for Toshiba RBTX4938 reference board, which has NAND IPL.
-	  Select this option if you need to use NAND boot.
-
 endif
 
 config PCI_TX4927
diff --git a/arch/mips/txx9/generic/Makefile b/arch/mips/txx9/generic/Makefile
index 9bb34af..0030d23 100644
--- a/arch/mips/txx9/generic/Makefile
+++ b/arch/mips/txx9/generic/Makefile
@@ -7,6 +7,8 @@
 obj-$(CONFIG_SOC_TX3927)	+= setup_tx3927.o irq_tx3927.o
 obj-$(CONFIG_SOC_TX4927)	+= mem_tx4927.o setup_tx4927.o irq_tx4927.o
 obj-$(CONFIG_SOC_TX4938)	+= mem_tx4927.o setup_tx4938.o irq_tx4938.o
+obj-$(CONFIG_SOC_TX4939)	+= setup_tx4939.o irq_tx4939.o
 obj-$(CONFIG_TOSHIBA_FPCIB0)	+= smsc_fdc37m81x.o
+obj-$(CONFIG_SPI)		+= spi_eeprom.o
 
 EXTRA_CFLAGS += -Werror
diff --git a/arch/mips/txx9/generic/irq_tx4927.c b/arch/mips/txx9/generic/irq_tx4927.c
index cbea1fd..ad2870d 100644
--- a/arch/mips/txx9/generic/irq_tx4927.c
+++ b/arch/mips/txx9/generic/irq_tx4927.c
@@ -30,8 +30,19 @@
 
 void __init tx4927_irq_init(void)
 {
+	int i;
+
 	mips_cpu_irq_init();
 	txx9_irq_init(TX4927_IRC_REG & 0xfffffffffULL);
 	set_irq_chained_handler(MIPS_CPU_IRQ_BASE + TX4927_IRC_INT,
 				handle_simple_irq);
+	/* raise priority for errors, timers, SIO */
+	txx9_irq_set_pri(TX4927_IR_ECCERR, 7);
+	txx9_irq_set_pri(TX4927_IR_WTOERR, 7);
+	txx9_irq_set_pri(TX4927_IR_PCIERR, 7);
+	txx9_irq_set_pri(TX4927_IR_PCIPME, 7);
+	for (i = 0; i < TX4927_NUM_IR_TMR; i++)
+		txx9_irq_set_pri(TX4927_IR_TMR(i), 6);
+	for (i = 0; i < TX4927_NUM_IR_SIO; i++)
+		txx9_irq_set_pri(TX4927_IR_SIO(i), 5);
 }
diff --git a/arch/mips/txx9/generic/irq_tx4938.c b/arch/mips/txx9/generic/irq_tx4938.c
index 6eac684..025ae11 100644
--- a/arch/mips/txx9/generic/irq_tx4938.c
+++ b/arch/mips/txx9/generic/irq_tx4938.c
@@ -18,8 +18,19 @@
 
 void __init tx4938_irq_init(void)
 {
+	int i;
+
 	mips_cpu_irq_init();
 	txx9_irq_init(TX4938_IRC_REG & 0xfffffffffULL);
 	set_irq_chained_handler(MIPS_CPU_IRQ_BASE + TX4938_IRC_INT,
 				handle_simple_irq);
+	/* raise priority for errors, timers, SIO */
+	txx9_irq_set_pri(TX4938_IR_ECCERR, 7);
+	txx9_irq_set_pri(TX4938_IR_WTOERR, 7);
+	txx9_irq_set_pri(TX4938_IR_PCIERR, 7);
+	txx9_irq_set_pri(TX4938_IR_PCIPME, 7);
+	for (i = 0; i < TX4938_NUM_IR_TMR; i++)
+		txx9_irq_set_pri(TX4938_IR_TMR(i), 6);
+	for (i = 0; i < TX4938_NUM_IR_SIO; i++)
+		txx9_irq_set_pri(TX4938_IR_SIO(i), 5);
 }
diff --git a/arch/mips/txx9/generic/irq_tx4939.c b/arch/mips/txx9/generic/irq_tx4939.c
new file mode 100644
index 0000000..013213a8
--- /dev/null
+++ b/arch/mips/txx9/generic/irq_tx4939.c
@@ -0,0 +1,215 @@
+/*
+ * TX4939 irq routines
+ * Based on linux/arch/mips/kernel/irq_txx9.c,
+ *	    and RBTX49xx patch from CELF patch archive.
+ *
+ * Copyright 2001, 2003-2005 MontaVista Software Inc.
+ * Author: MontaVista Software, Inc.
+ *         ahennessy@mvista.com
+ *         source@mvista.com
+ * Copyright (C) 2000-2001,2005-2007 Toshiba Corporation
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+/*
+ * TX4939 defines 64 IRQs.
+ * Similer to irq_txx9.c but different register layouts.
+ */
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/types.h>
+#include <asm/irq_cpu.h>
+#include <asm/txx9irq.h>
+#include <asm/txx9/tx4939.h>
+
+/* IRCER : Int. Control Enable */
+#define TXx9_IRCER_ICE	0x00000001
+
+/* IRCR : Int. Control */
+#define TXx9_IRCR_LOW	0x00000000
+#define TXx9_IRCR_HIGH	0x00000001
+#define TXx9_IRCR_DOWN	0x00000002
+#define TXx9_IRCR_UP	0x00000003
+#define TXx9_IRCR_EDGE(cr)	((cr) & 0x00000002)
+
+/* IRSCR : Int. Status Control */
+#define TXx9_IRSCR_EIClrE	0x00000100
+#define TXx9_IRSCR_EIClr_MASK	0x0000000f
+
+/* IRCSR : Int. Current Status */
+#define TXx9_IRCSR_IF	0x00010000
+
+#define irc_dlevel	0
+#define irc_elevel	1
+
+static struct {
+	unsigned char level;
+	unsigned char mode;
+} tx4939irq[TX4939_NUM_IR] __read_mostly;
+
+static void tx4939_irq_unmask(unsigned int irq)
+{
+	unsigned int irq_nr = irq - TXX9_IRQ_BASE;
+	u32 __iomem *lvlp;
+	int ofs;
+	if (irq_nr < 32) {
+		irq_nr--;
+		lvlp = &tx4939_ircptr->lvl[(irq_nr % 16) / 2].r;
+	} else {
+		irq_nr -= 32;
+		lvlp = &tx4939_ircptr->lvl[8 + (irq_nr % 16) / 2].r;
+	}
+	ofs = (irq_nr & 16) + (irq_nr & 1) * 8;
+	__raw_writel((__raw_readl(lvlp) & ~(0xff << ofs))
+		     | (tx4939irq[irq_nr].level << ofs),
+		     lvlp);
+}
+
+static inline void tx4939_irq_mask(unsigned int irq)
+{
+	unsigned int irq_nr = irq - TXX9_IRQ_BASE;
+	u32 __iomem *lvlp;
+	int ofs;
+	if (irq_nr < 32) {
+		irq_nr--;
+		lvlp = &tx4939_ircptr->lvl[(irq_nr % 16) / 2].r;
+	} else {
+		irq_nr -= 32;
+		lvlp = &tx4939_ircptr->lvl[8 + (irq_nr % 16) / 2].r;
+	}
+	ofs = (irq_nr & 16) + (irq_nr & 1) * 8;
+	__raw_writel((__raw_readl(lvlp) & ~(0xff << ofs))
+		     | (irc_dlevel << ofs),
+		     lvlp);
+	mmiowb();
+}
+
+static void tx4939_irq_mask_ack(unsigned int irq)
+{
+	unsigned int irq_nr = irq - TXX9_IRQ_BASE;
+
+	tx4939_irq_mask(irq);
+	if (TXx9_IRCR_EDGE(tx4939irq[irq_nr].mode)) {
+		irq_nr--;
+		/* clear edge detection */
+		__raw_writel((TXx9_IRSCR_EIClrE | (irq_nr & 0xf))
+			     << (irq_nr & 0x10),
+			     &tx4939_ircptr->edc.r);
+	}
+}
+
+static int tx4939_irq_set_type(unsigned int irq, unsigned int flow_type)
+{
+	unsigned int irq_nr = irq - TXX9_IRQ_BASE;
+	u32 cr;
+	u32 __iomem *crp;
+	int ofs;
+	int mode;
+
+	if (flow_type & IRQF_TRIGGER_PROBE)
+		return 0;
+	switch (flow_type & IRQF_TRIGGER_MASK) {
+	case IRQF_TRIGGER_RISING:
+		mode = TXx9_IRCR_UP;
+		break;
+	case IRQF_TRIGGER_FALLING:
+		mode = TXx9_IRCR_DOWN;
+		break;
+	case IRQF_TRIGGER_HIGH:
+		mode = TXx9_IRCR_HIGH;
+		break;
+	case IRQF_TRIGGER_LOW:
+		mode = TXx9_IRCR_LOW;
+		break;
+	default:
+		return -EINVAL;
+	}
+	if (irq_nr < 32) {
+		irq_nr--;
+		crp = &tx4939_ircptr->dm[(irq_nr & 8) >> 3].r;
+	} else {
+		irq_nr -= 32;
+		crp = &tx4939_ircptr->dm2[((irq_nr & 8) >> 3)].r;
+	}
+	ofs = (((irq_nr & 16) >> 1) | (irq_nr & (8 - 1))) * 2;
+	cr = __raw_readl(crp);
+	cr &= ~(0x3 << ofs);
+	cr |= (mode & 0x3) << ofs;
+	__raw_writel(cr, crp);
+	tx4939irq[irq_nr].mode = mode;
+	return 0;
+}
+
+static struct irq_chip tx4939_irq_chip = {
+	.name		= "TX4939",
+	.ack		= tx4939_irq_mask_ack,
+	.mask		= tx4939_irq_mask,
+	.mask_ack	= tx4939_irq_mask_ack,
+	.unmask		= tx4939_irq_unmask,
+	.set_type	= tx4939_irq_set_type,
+};
+
+static int tx4939_irq_set_pri(int irc_irq, int new_pri)
+{
+	int old_pri;
+
+	if ((unsigned int)irc_irq >= TX4939_NUM_IR)
+		return 0;
+	old_pri = tx4939irq[irc_irq].level;
+	tx4939irq[irc_irq].level = new_pri;
+	return old_pri;
+}
+
+void __init tx4939_irq_init(void)
+{
+	int i;
+
+	mips_cpu_irq_init();
+	/* disable interrupt control */
+	__raw_writel(0, &tx4939_ircptr->den.r);
+	__raw_writel(0, &tx4939_ircptr->maskint.r);
+	__raw_writel(0, &tx4939_ircptr->maskext.r);
+	/* irq_base + 0 is not used */
+	for (i = 1; i < TX4939_NUM_IR; i++) {
+		tx4939irq[i].level = 4; /* middle level */
+		tx4939irq[i].mode = TXx9_IRCR_LOW;
+		set_irq_chip_and_handler(TXX9_IRQ_BASE + i,
+					 &tx4939_irq_chip, handle_level_irq);
+	}
+
+	/* mask all IRC interrupts */
+	__raw_writel(0, &tx4939_ircptr->msk.r);
+	for (i = 0; i < 16; i++)
+		__raw_writel(0, &tx4939_ircptr->lvl[i].r);
+	/* setup IRC interrupt mode (Low Active) */
+	for (i = 0; i < 2; i++)
+		__raw_writel(0, &tx4939_ircptr->dm[i].r);
+	for (i = 0; i < 2; i++)
+		__raw_writel(0, &tx4939_ircptr->dm2[i].r);
+	/* enable interrupt control */
+	__raw_writel(TXx9_IRCER_ICE, &tx4939_ircptr->den.r);
+	__raw_writel(irc_elevel, &tx4939_ircptr->msk.r);
+
+	set_irq_chained_handler(MIPS_CPU_IRQ_BASE + TX4939_IRC_INT,
+				handle_simple_irq);
+
+	/* raise priority for errors, timers, sio */
+	tx4939_irq_set_pri(TX4939_IR_WTOERR, 7);
+	tx4939_irq_set_pri(TX4939_IR_PCIERR, 7);
+	tx4939_irq_set_pri(TX4939_IR_PCIPME, 7);
+	for (i = 0; i < TX4939_NUM_IR_TMR; i++)
+		tx4939_irq_set_pri(TX4939_IR_TMR(i), 6);
+	for (i = 0; i < TX4939_NUM_IR_SIO; i++)
+		tx4939_irq_set_pri(TX4939_IR_SIO(i), 5);
+}
+
+int tx4939_irq(void)
+{
+	u32 csr = __raw_readl(&tx4939_ircptr->cs.r);
+
+	if (likely(!(csr & TXx9_IRCSR_IF)))
+		return TXX9_IRQ_BASE + (csr & (TX4939_NUM_IR - 1));
+	return -1;
+}
diff --git a/arch/mips/txx9/generic/setup.c b/arch/mips/txx9/generic/setup.c
index fe6bee0..5526375 100644
--- a/arch/mips/txx9/generic/setup.c
+++ b/arch/mips/txx9/generic/setup.c
@@ -22,11 +22,16 @@
 #include <linux/gpio.h>
 #include <linux/platform_device.h>
 #include <linux/serial_core.h>
+#include <linux/mtd/physmap.h>
+#include <linux/leds.h>
 #include <asm/bootinfo.h>
 #include <asm/time.h>
 #include <asm/reboot.h>
+#include <asm/r4kcache.h>
+#include <asm/sections.h>
 #include <asm/txx9/generic.h>
 #include <asm/txx9/pci.h>
+#include <asm/txx9tmr.h>
 #ifdef CONFIG_CPU_TX49XX
 #include <asm/txx9/tx4938.h>
 #endif
@@ -67,7 +72,12 @@
 unsigned int txx9_cpu_clock;
 unsigned int txx9_gbus_clock;
 
+#ifdef CONFIG_CPU_TX39XX
+/* don't enable by default - see errata */
+int txx9_ccfg_toeon __initdata;
+#else
 int txx9_ccfg_toeon __initdata = 1;
+#endif
 
 /* Minimum CLK support */
 
@@ -119,39 +129,232 @@
 EXPORT_SYMBOL(irq_to_gpio);
 #endif
 
-extern struct txx9_board_vec jmr3927_vec;
-extern struct txx9_board_vec rbtx4927_vec;
-extern struct txx9_board_vec rbtx4937_vec;
-extern struct txx9_board_vec rbtx4938_vec;
+#define BOARD_VEC(board)	extern struct txx9_board_vec board;
+#include <asm/txx9/boards.h>
+#undef BOARD_VEC
 
 struct txx9_board_vec *txx9_board_vec __initdata;
 static char txx9_system_type[32];
 
-void __init prom_init_cmdline(void)
+static struct txx9_board_vec *board_vecs[] __initdata = {
+#define BOARD_VEC(board)	&board,
+#include <asm/txx9/boards.h>
+#undef BOARD_VEC
+};
+
+static struct txx9_board_vec *__init find_board_byname(const char *name)
+{
+	int i;
+
+	/* search board_vecs table */
+	for (i = 0; i < ARRAY_SIZE(board_vecs); i++) {
+		if (strstr(board_vecs[i]->system, name))
+			return board_vecs[i];
+	}
+	return NULL;
+}
+
+static void __init prom_init_cmdline(void)
 {
 	int argc = (int)fw_arg0;
-	char **argv = (char **)fw_arg1;
+	int *argv32 = (int *)fw_arg1;
 	int i;			/* Always ignore the "-c" at argv[0] */
-#ifdef CONFIG_64BIT
-	char *fixed_argv[32];
-	for (i = 0; i < argc; i++)
-		fixed_argv[i] = (char *)(long)(*((__s32 *)argv + i));
-	argv = fixed_argv;
-#endif
+	char builtin[CL_SIZE];
 
 	/* ignore all built-in args if any f/w args given */
-	if (argc > 1)
-		*arcs_cmdline = '\0';
+	/*
+	 * But if built-in strings was started with '+', append them
+	 * to command line args.  If built-in was started with '-',
+	 * ignore all f/w args.
+	 */
+	builtin[0] = '\0';
+	if (arcs_cmdline[0] == '+')
+		strcpy(builtin, arcs_cmdline + 1);
+	else if (arcs_cmdline[0] == '-') {
+		strcpy(builtin, arcs_cmdline + 1);
+		argc = 0;
+	} else if (argc <= 1)
+		strcpy(builtin, arcs_cmdline);
+	arcs_cmdline[0] = '\0';
 
 	for (i = 1; i < argc; i++) {
+		char *str = (char *)(long)argv32[i];
 		if (i != 1)
 			strcat(arcs_cmdline, " ");
-		strcat(arcs_cmdline, argv[i]);
+		if (strchr(str, ' ')) {
+			strcat(arcs_cmdline, "\"");
+			strcat(arcs_cmdline, str);
+			strcat(arcs_cmdline, "\"");
+		} else
+			strcat(arcs_cmdline, str);
+	}
+	/* append saved builtin args */
+	if (builtin[0]) {
+		if (arcs_cmdline[0])
+			strcat(arcs_cmdline, " ");
+		strcat(arcs_cmdline, builtin);
 	}
 }
 
-void __init prom_init(void)
+static int txx9_ic_disable __initdata;
+static int txx9_dc_disable __initdata;
+
+#if defined(CONFIG_CPU_TX49XX)
+/* flush all cache on very early stage (before 4k_cache_init) */
+static void __init early_flush_dcache(void)
 {
+	unsigned int conf = read_c0_config();
+	unsigned int dc_size = 1 << (12 + ((conf & CONF_DC) >> 6));
+	unsigned int linesz = 32;
+	unsigned long addr, end;
+
+	end = INDEX_BASE + dc_size / 4;
+	/* 4way, waybit=0 */
+	for (addr = INDEX_BASE; addr < end; addr += linesz) {
+		cache_op(Index_Writeback_Inv_D, addr | 0);
+		cache_op(Index_Writeback_Inv_D, addr | 1);
+		cache_op(Index_Writeback_Inv_D, addr | 2);
+		cache_op(Index_Writeback_Inv_D, addr | 3);
+	}
+}
+
+static void __init txx9_cache_fixup(void)
+{
+	unsigned int conf;
+
+	conf = read_c0_config();
+	/* flush and disable */
+	if (txx9_ic_disable) {
+		conf |= TX49_CONF_IC;
+		write_c0_config(conf);
+	}
+	if (txx9_dc_disable) {
+		early_flush_dcache();
+		conf |= TX49_CONF_DC;
+		write_c0_config(conf);
+	}
+
+	/* enable cache */
+	conf = read_c0_config();
+	if (!txx9_ic_disable)
+		conf &= ~TX49_CONF_IC;
+	if (!txx9_dc_disable)
+		conf &= ~TX49_CONF_DC;
+	write_c0_config(conf);
+
+	if (conf & TX49_CONF_IC)
+		pr_info("TX49XX I-Cache disabled.\n");
+	if (conf & TX49_CONF_DC)
+		pr_info("TX49XX D-Cache disabled.\n");
+}
+#elif defined(CONFIG_CPU_TX39XX)
+/* flush all cache on very early stage (before tx39_cache_init) */
+static void __init early_flush_dcache(void)
+{
+	unsigned int conf = read_c0_config();
+	unsigned int dc_size = 1 << (10 + ((conf & TX39_CONF_DCS_MASK) >>
+					   TX39_CONF_DCS_SHIFT));
+	unsigned int linesz = 16;
+	unsigned long addr, end;
+
+	end = INDEX_BASE + dc_size / 2;
+	/* 2way, waybit=0 */
+	for (addr = INDEX_BASE; addr < end; addr += linesz) {
+		cache_op(Index_Writeback_Inv_D, addr | 0);
+		cache_op(Index_Writeback_Inv_D, addr | 1);
+	}
+}
+
+static void __init txx9_cache_fixup(void)
+{
+	unsigned int conf;
+
+	conf = read_c0_config();
+	/* flush and disable */
+	if (txx9_ic_disable) {
+		conf &= ~TX39_CONF_ICE;
+		write_c0_config(conf);
+	}
+	if (txx9_dc_disable) {
+		early_flush_dcache();
+		conf &= ~TX39_CONF_DCE;
+		write_c0_config(conf);
+	}
+
+	/* enable cache */
+	conf = read_c0_config();
+	if (!txx9_ic_disable)
+		conf |= TX39_CONF_ICE;
+	if (!txx9_dc_disable)
+		conf |= TX39_CONF_DCE;
+	write_c0_config(conf);
+
+	if (!(conf & TX39_CONF_ICE))
+		pr_info("TX39XX I-Cache disabled.\n");
+	if (!(conf & TX39_CONF_DCE))
+		pr_info("TX39XX D-Cache disabled.\n");
+}
+#else
+static inline void txx9_cache_fixup(void)
+{
+}
+#endif
+
+static void __init preprocess_cmdline(void)
+{
+	char cmdline[CL_SIZE];
+	char *s;
+
+	strcpy(cmdline, arcs_cmdline);
+	s = cmdline;
+	arcs_cmdline[0] = '\0';
+	while (s && *s) {
+		char *str = strsep(&s, " ");
+		if (strncmp(str, "board=", 6) == 0) {
+			txx9_board_vec = find_board_byname(str + 6);
+			continue;
+		} else if (strncmp(str, "masterclk=", 10) == 0) {
+			unsigned long val;
+			if (strict_strtoul(str + 10, 10, &val) == 0)
+				txx9_master_clock = val;
+			continue;
+		} else if (strcmp(str, "icdisable") == 0) {
+			txx9_ic_disable = 1;
+			continue;
+		} else if (strcmp(str, "dcdisable") == 0) {
+			txx9_dc_disable = 1;
+			continue;
+		} else if (strcmp(str, "toeoff") == 0) {
+			txx9_ccfg_toeon = 0;
+			continue;
+		} else if (strcmp(str, "toeon") == 0) {
+			txx9_ccfg_toeon = 1;
+			continue;
+		}
+		if (arcs_cmdline[0])
+			strcat(arcs_cmdline, " ");
+		strcat(arcs_cmdline, str);
+	}
+
+	txx9_cache_fixup();
+}
+
+static void __init select_board(void)
+{
+	const char *envstr;
+
+	/* first, determine by "board=" argument in preprocess_cmdline() */
+	if (txx9_board_vec)
+		return;
+	/* next, determine by "board" envvar */
+	envstr = prom_getenv("board");
+	if (envstr) {
+		txx9_board_vec = find_board_byname(envstr);
+		if (txx9_board_vec)
+			return;
+	}
+
+	/* select "default" board */
 #ifdef CONFIG_CPU_TX39XX
 	txx9_board_vec = &jmr3927_vec;
 #endif
@@ -170,8 +373,20 @@
 		txx9_board_vec = &rbtx4938_vec;
 		break;
 #endif
+#ifdef CONFIG_TOSHIBA_RBTX4939
+	case 0x4939:
+		txx9_board_vec = &rbtx4939_vec;
+		break;
+#endif
 	}
 #endif
+}
+
+void __init prom_init(void)
+{
+	prom_init_cmdline();
+	preprocess_cmdline();
+	select_board();
 
 	strcpy(txx9_system_type, txx9_board_vec->system);
 
@@ -180,6 +395,11 @@
 
 void __init prom_free_prom_memory(void)
 {
+	unsigned long saddr = PAGE_SIZE;
+	unsigned long eaddr = __pa_symbol(&_text);
+
+	if (saddr < eaddr)
+		free_init_pages("prom memory", saddr, eaddr);
 }
 
 const char *get_system_type(void)
@@ -192,6 +412,21 @@
 	return &(arcs_cmdline[0]);
 }
 
+const char *__init prom_getenv(const char *name)
+{
+	const s32 *str = (const s32 *)fw_arg2;
+
+	if (!str)
+		return NULL;
+	/* YAMON style ("name", "value" pairs) */
+	while (str[0] && str[1]) {
+		if (!strcmp((const char *)(unsigned long)str[0], name))
+			return (const char *)(unsigned long)str[1];
+		str += 2;
+	}
+	return NULL;
+}
+
 static void __noreturn txx9_machine_halt(void)
 {
 	local_irq_disable();
@@ -222,6 +457,20 @@
 	platform_device_register_simple("txx9wdt", -1, &res, 1);
 }
 
+void txx9_wdt_now(unsigned long base)
+{
+	struct txx9_tmr_reg __iomem *tmrptr =
+		ioremap(base, sizeof(struct txx9_tmr_reg));
+	/* disable watch dog timer */
+	__raw_writel(TXx9_TMWTMR_WDIS | TXx9_TMWTMR_TWC, &tmrptr->wtmr);
+	__raw_writel(0, &tmrptr->tcr);
+	/* kick watchdog */
+	__raw_writel(TXx9_TMWTMR_TWIE, &tmrptr->wtmr);
+	__raw_writel(1, &tmrptr->cpra); /* immediate */
+	__raw_writel(TXx9_TMTCR_TCE | TXx9_TMTCR_CCDE | TXx9_TMTCR_TMODE_WDOG,
+		     &tmrptr->tcr);
+}
+
 /* SPI support */
 void __init txx9_spi_init(int busid, unsigned long base, int irq)
 {
@@ -372,3 +621,153 @@
 unsigned long (*__swizzle_addr_b)(unsigned long port) = __swizzle_addr_none;
 EXPORT_SYMBOL(__swizzle_addr_b);
 #endif
+
+void __init txx9_physmap_flash_init(int no, unsigned long addr,
+				    unsigned long size,
+				    const struct physmap_flash_data *pdata)
+{
+#if defined(CONFIG_MTD_PHYSMAP) || defined(CONFIG_MTD_PHYSMAP_MODULE)
+	struct resource res = {
+		.start = addr,
+		.end = addr + size - 1,
+		.flags = IORESOURCE_MEM,
+	};
+	struct platform_device *pdev;
+#ifdef CONFIG_MTD_PARTITIONS
+	static struct mtd_partition parts[2];
+	struct physmap_flash_data pdata_part;
+
+	/* If this area contained boot area, make separate partition */
+	if (pdata->nr_parts == 0 && !pdata->parts &&
+	    addr < 0x1fc00000 && addr + size > 0x1fc00000 &&
+	    !parts[0].name) {
+		parts[0].name = "boot";
+		parts[0].offset = 0x1fc00000 - addr;
+		parts[0].size = addr + size - 0x1fc00000;
+		parts[1].name = "user";
+		parts[1].offset = 0;
+		parts[1].size = 0x1fc00000 - addr;
+		pdata_part = *pdata;
+		pdata_part.nr_parts = ARRAY_SIZE(parts);
+		pdata_part.parts = parts;
+		pdata = &pdata_part;
+	}
+#endif
+	pdev = platform_device_alloc("physmap-flash", no);
+	if (!pdev ||
+	    platform_device_add_resources(pdev, &res, 1) ||
+	    platform_device_add_data(pdev, pdata, sizeof(*pdata)) ||
+	    platform_device_add(pdev))
+		platform_device_put(pdev);
+#endif
+}
+
+#if defined(CONFIG_LEDS_GPIO) || defined(CONFIG_LEDS_GPIO_MODULE)
+static DEFINE_SPINLOCK(txx9_iocled_lock);
+
+#define TXX9_IOCLED_MAXLEDS 8
+
+struct txx9_iocled_data {
+	struct gpio_chip chip;
+	u8 cur_val;
+	void __iomem *mmioaddr;
+	struct gpio_led_platform_data pdata;
+	struct gpio_led leds[TXX9_IOCLED_MAXLEDS];
+	char names[TXX9_IOCLED_MAXLEDS][32];
+};
+
+static int txx9_iocled_get(struct gpio_chip *chip, unsigned int offset)
+{
+	struct txx9_iocled_data *data =
+		container_of(chip, struct txx9_iocled_data, chip);
+	return data->cur_val & (1 << offset);
+}
+
+static void txx9_iocled_set(struct gpio_chip *chip, unsigned int offset,
+			    int value)
+{
+	struct txx9_iocled_data *data =
+		container_of(chip, struct txx9_iocled_data, chip);
+	unsigned long flags;
+	spin_lock_irqsave(&txx9_iocled_lock, flags);
+	if (value)
+		data->cur_val |= 1 << offset;
+	else
+		data->cur_val &= ~(1 << offset);
+	writeb(data->cur_val, data->mmioaddr);
+	mmiowb();
+	spin_unlock_irqrestore(&txx9_iocled_lock, flags);
+}
+
+static int txx9_iocled_dir_in(struct gpio_chip *chip, unsigned int offset)
+{
+	return 0;
+}
+
+static int txx9_iocled_dir_out(struct gpio_chip *chip, unsigned int offset,
+			       int value)
+{
+	txx9_iocled_set(chip, offset, value);
+	return 0;
+}
+
+void __init txx9_iocled_init(unsigned long baseaddr,
+			     int basenum, unsigned int num, int lowactive,
+			     const char *color, char **deftriggers)
+{
+	struct txx9_iocled_data *iocled;
+	struct platform_device *pdev;
+	int i;
+	static char *default_triggers[] __initdata = {
+		"heartbeat",
+		"ide-disk",
+		"nand-disk",
+		NULL,
+	};
+
+	if (!deftriggers)
+		deftriggers = default_triggers;
+	iocled = kzalloc(sizeof(*iocled), GFP_KERNEL);
+	if (!iocled)
+		return;
+	iocled->mmioaddr = ioremap(baseaddr, 1);
+	if (!iocled->mmioaddr)
+		return;
+	iocled->chip.get = txx9_iocled_get;
+	iocled->chip.set = txx9_iocled_set;
+	iocled->chip.direction_input = txx9_iocled_dir_in;
+	iocled->chip.direction_output = txx9_iocled_dir_out;
+	iocled->chip.label = "iocled";
+	iocled->chip.base = basenum;
+	iocled->chip.ngpio = num;
+	if (gpiochip_add(&iocled->chip))
+		return;
+	if (basenum < 0)
+		basenum = iocled->chip.base;
+
+	pdev = platform_device_alloc("leds-gpio", basenum);
+	if (!pdev)
+		return;
+	iocled->pdata.num_leds = num;
+	iocled->pdata.leds = iocled->leds;
+	for (i = 0; i < num; i++) {
+		struct gpio_led *led = &iocled->leds[i];
+		snprintf(iocled->names[i], sizeof(iocled->names[i]),
+			 "iocled:%s:%u", color, i);
+		led->name = iocled->names[i];
+		led->gpio = basenum + i;
+		led->active_low = lowactive;
+		if (deftriggers && *deftriggers)
+			led->default_trigger = *deftriggers++;
+	}
+	pdev->dev.platform_data = &iocled->pdata;
+	if (platform_device_add(pdev))
+		platform_device_put(pdev);
+}
+#else /* CONFIG_LEDS_GPIO */
+void __init txx9_iocled_init(unsigned long baseaddr,
+			     int basenum, unsigned int num, int lowactive,
+			     const char *color, char **deftriggers)
+{
+}
+#endif /* CONFIG_LEDS_GPIO */
diff --git a/arch/mips/txx9/generic/setup_tx3927.c b/arch/mips/txx9/generic/setup_tx3927.c
index 7bd963d..9505d58 100644
--- a/arch/mips/txx9/generic/setup_tx3927.c
+++ b/arch/mips/txx9/generic/setup_tx3927.c
@@ -15,6 +15,7 @@
 #include <linux/delay.h>
 #include <linux/param.h>
 #include <linux/io.h>
+#include <linux/mtd/physmap.h>
 #include <asm/mipsregs.h>
 #include <asm/txx9irq.h>
 #include <asm/txx9tmr.h>
@@ -32,11 +33,6 @@
 	int i;
 	unsigned int conf;
 
-	/* don't enable - see errata */
-	txx9_ccfg_toeon = 0;
-	if (strstr(prom_getcmdline(), "toeon") != NULL)
-		txx9_ccfg_toeon = 1;
-
 	txx9_reg_res_init(TX3927_REV_PCODE(), TX3927_REG_BASE,
 			  TX3927_REG_SIZE);
 
@@ -99,16 +95,14 @@
 	txx9_gpio_init(TX3927_PIO_REG, 0, 16);
 
 	conf = read_c0_conf();
-	if (!(conf & TX39_CONF_ICE))
-		printk(KERN_INFO "TX3927 I-Cache disabled.\n");
-	if (!(conf & TX39_CONF_DCE))
-		printk(KERN_INFO "TX3927 D-Cache disabled.\n");
-	else if (!(conf & TX39_CONF_WBON))
-		printk(KERN_INFO "TX3927 D-Cache WriteThrough.\n");
-	else if (!(conf & TX39_CONF_CWFON))
-		printk(KERN_INFO "TX3927 D-Cache WriteBack.\n");
-	else
-		printk(KERN_INFO "TX3927 D-Cache WriteBack (CWF) .\n");
+	if (conf & TX39_CONF_DCE) {
+		if (!(conf & TX39_CONF_WBON))
+			pr_info("TX3927 D-Cache WriteThrough.\n");
+		else if (!(conf & TX39_CONF_CWFON))
+			pr_info("TX3927 D-Cache WriteBack.\n");
+		else
+			pr_info("TX3927 D-Cache WriteBack (CWF) .\n");
+	}
 }
 
 void __init tx3927_time_init(unsigned int evt_tmrnr, unsigned int src_tmrnr)
@@ -128,3 +122,16 @@
 			      TXX9_IRQ_BASE + TX3927_IR_SIO(i),
 			      i, sclk, (1 << i) & cts_mask);
 }
+
+void __init tx3927_mtd_init(int ch)
+{
+	struct physmap_flash_data pdata = {
+		.width = TX3927_ROMC_WIDTH(ch) / 8,
+	};
+	unsigned long start = txx9_ce_res[ch].start;
+	unsigned long size = txx9_ce_res[ch].end - start + 1;
+
+	if (!(tx3927_romcptr->cr[ch] & 0x8))
+		return;	/* disabled */
+	txx9_physmap_flash_init(ch, start, size, &pdata);
+}
diff --git a/arch/mips/txx9/generic/setup_tx4927.c b/arch/mips/txx9/generic/setup_tx4927.c
index f80d4b7..914e93c 100644
--- a/arch/mips/txx9/generic/setup_tx4927.c
+++ b/arch/mips/txx9/generic/setup_tx4927.c
@@ -14,6 +14,10 @@
 #include <linux/ioport.h>
 #include <linux/delay.h>
 #include <linux/param.h>
+#include <linux/ptrace.h>
+#include <linux/mtd/physmap.h>
+#include <asm/reboot.h>
+#include <asm/traps.h>
 #include <asm/txx9irq.h>
 #include <asm/txx9tmr.h>
 #include <asm/txx9pio.h>
@@ -22,6 +26,10 @@
 
 static void __init tx4927_wdr_init(void)
 {
+	/* report watchdog reset status */
+	if (____raw_readq(&tx4927_ccfgptr->ccfg) & TX4927_CCFG_WDRST)
+		pr_warning("Watchdog reset detected at 0x%lx\n",
+			   read_c0_errorepc());
 	/* clear WatchDogReset (W1C) */
 	tx4927_ccfg_set(TX4927_CCFG_WDRST);
 	/* do reset on watchdog */
@@ -33,6 +41,47 @@
 	txx9_wdt_init(TX4927_TMR_REG(2) & 0xfffffffffULL);
 }
 
+static void tx4927_machine_restart(char *command)
+{
+	local_irq_disable();
+	pr_emerg("Rebooting (with %s watchdog reset)...\n",
+		 (____raw_readq(&tx4927_ccfgptr->ccfg) & TX4927_CCFG_WDREXEN) ?
+		 "external" : "internal");
+	/* clear watchdog status */
+	tx4927_ccfg_set(TX4927_CCFG_WDRST);	/* W1C */
+	txx9_wdt_now(TX4927_TMR_REG(2) & 0xfffffffffULL);
+	while (!(____raw_readq(&tx4927_ccfgptr->ccfg) & TX4927_CCFG_WDRST))
+		;
+	mdelay(10);
+	if (____raw_readq(&tx4927_ccfgptr->ccfg) & TX4927_CCFG_WDREXEN) {
+		pr_emerg("Rebooting (with internal watchdog reset)...\n");
+		/* External WDRST failed.  Do internal watchdog reset */
+		tx4927_ccfg_clear(TX4927_CCFG_WDREXEN);
+	}
+	/* fallback */
+	(*_machine_halt)();
+}
+
+void show_registers(struct pt_regs *regs);
+static int tx4927_be_handler(struct pt_regs *regs, int is_fixup)
+{
+	int data = regs->cp0_cause & 4;
+	console_verbose();
+	pr_err("%cBE exception at %#lx\n", data ? 'D' : 'I', regs->cp0_epc);
+	pr_err("ccfg:%llx, toea:%llx\n",
+	       (unsigned long long)____raw_readq(&tx4927_ccfgptr->ccfg),
+	       (unsigned long long)____raw_readq(&tx4927_ccfgptr->toea));
+#ifdef CONFIG_PCI
+	tx4927_report_pcic_status();
+#endif
+	show_registers(regs);
+	panic("BusError!");
+}
+static void __init tx4927_be_init(void)
+{
+	board_be_handler = tx4927_be_handler;
+}
+
 static struct resource tx4927_sdram_resource[4];
 
 void __init tx4927_setup(void)
@@ -44,6 +93,7 @@
 
 	txx9_reg_res_init(TX4927_REV_PCODE(), TX4927_REG_BASE,
 			  TX4927_REG_SIZE);
+	set_c0_config(TX49_CONF_CWFON);
 
 	/* SDRAMC,EBUSC are configured by PROM */
 	for (i = 0; i < 8; i++) {
@@ -167,6 +217,9 @@
 	txx9_gpio_init(TX4927_PIO_REG & 0xfffffffffULL, 0, TX4927_NUM_PIO);
 	__raw_writel(0, &tx4927_pioptr->maskcpu);
 	__raw_writel(0, &tx4927_pioptr->maskext);
+
+	_machine_restart = tx4927_machine_restart;
+	board_be_init = tx4927_be_init;
 }
 
 void __init tx4927_time_init(unsigned int tmrnr)
@@ -186,3 +239,47 @@
 			      TXX9_IRQ_BASE + TX4927_IR_SIO(i),
 			      i, sclk, (1 << i) & cts_mask);
 }
+
+void __init tx4927_mtd_init(int ch)
+{
+	struct physmap_flash_data pdata = {
+		.width = TX4927_EBUSC_WIDTH(ch) / 8,
+	};
+	unsigned long start = txx9_ce_res[ch].start;
+	unsigned long size = txx9_ce_res[ch].end - start + 1;
+
+	if (!(TX4927_EBUSC_CR(ch) & 0x8))
+		return;	/* disabled */
+	txx9_physmap_flash_init(ch, start, size, &pdata);
+}
+
+static void __init tx4927_stop_unused_modules(void)
+{
+	__u64 pcfg, rst = 0, ckd = 0;
+	char buf[128];
+
+	buf[0] = '\0';
+	local_irq_disable();
+	pcfg = ____raw_readq(&tx4927_ccfgptr->pcfg);
+	if (!(pcfg & TX4927_PCFG_SEL2)) {
+		rst |= TX4927_CLKCTR_ACLRST;
+		ckd |= TX4927_CLKCTR_ACLCKD;
+		strcat(buf, " ACLC");
+	}
+	if (rst | ckd) {
+		txx9_set64(&tx4927_ccfgptr->clkctr, rst);
+		txx9_set64(&tx4927_ccfgptr->clkctr, ckd);
+	}
+	local_irq_enable();
+	if (buf[0])
+		pr_info("%s: stop%s\n", txx9_pcode_str, buf);
+}
+
+static int __init tx4927_late_init(void)
+{
+	if (txx9_pcode != 0x4927)
+		return -ENODEV;
+	tx4927_stop_unused_modules();
+	return 0;
+}
+late_initcall(tx4927_late_init);
diff --git a/arch/mips/txx9/generic/setup_tx4938.c b/arch/mips/txx9/generic/setup_tx4938.c
index f3040b9..af724e5 100644
--- a/arch/mips/txx9/generic/setup_tx4938.c
+++ b/arch/mips/txx9/generic/setup_tx4938.c
@@ -14,6 +14,10 @@
 #include <linux/ioport.h>
 #include <linux/delay.h>
 #include <linux/param.h>
+#include <linux/ptrace.h>
+#include <linux/mtd/physmap.h>
+#include <asm/reboot.h>
+#include <asm/traps.h>
 #include <asm/txx9irq.h>
 #include <asm/txx9tmr.h>
 #include <asm/txx9pio.h>
@@ -22,6 +26,10 @@
 
 static void __init tx4938_wdr_init(void)
 {
+	/* report watchdog reset status */
+	if (____raw_readq(&tx4938_ccfgptr->ccfg) & TX4938_CCFG_WDRST)
+		pr_warning("Watchdog reset detected at 0x%lx\n",
+			   read_c0_errorepc());
 	/* clear WatchDogReset (W1C) */
 	tx4938_ccfg_set(TX4938_CCFG_WDRST);
 	/* do reset on watchdog */
@@ -33,6 +41,47 @@
 	txx9_wdt_init(TX4938_TMR_REG(2) & 0xfffffffffULL);
 }
 
+static void tx4938_machine_restart(char *command)
+{
+	local_irq_disable();
+	pr_emerg("Rebooting (with %s watchdog reset)...\n",
+		 (____raw_readq(&tx4938_ccfgptr->ccfg) & TX4938_CCFG_WDREXEN) ?
+		 "external" : "internal");
+	/* clear watchdog status */
+	tx4938_ccfg_set(TX4938_CCFG_WDRST);	/* W1C */
+	txx9_wdt_now(TX4938_TMR_REG(2) & 0xfffffffffULL);
+	while (!(____raw_readq(&tx4938_ccfgptr->ccfg) & TX4938_CCFG_WDRST))
+		;
+	mdelay(10);
+	if (____raw_readq(&tx4938_ccfgptr->ccfg) & TX4938_CCFG_WDREXEN) {
+		pr_emerg("Rebooting (with internal watchdog reset)...\n");
+		/* External WDRST failed.  Do internal watchdog reset */
+		tx4938_ccfg_clear(TX4938_CCFG_WDREXEN);
+	}
+	/* fallback */
+	(*_machine_halt)();
+}
+
+void show_registers(struct pt_regs *regs);
+static int tx4938_be_handler(struct pt_regs *regs, int is_fixup)
+{
+	int data = regs->cp0_cause & 4;
+	console_verbose();
+	pr_err("%cBE exception at %#lx\n", data ? 'D' : 'I', regs->cp0_epc);
+	pr_err("ccfg:%llx, toea:%llx\n",
+	       (unsigned long long)____raw_readq(&tx4938_ccfgptr->ccfg),
+	       (unsigned long long)____raw_readq(&tx4938_ccfgptr->toea));
+#ifdef CONFIG_PCI
+	tx4927_report_pcic_status();
+#endif
+	show_registers(regs);
+	panic("BusError!");
+}
+static void __init tx4938_be_init(void)
+{
+	board_be_handler = tx4938_be_handler;
+}
+
 static struct resource tx4938_sdram_resource[4];
 static struct resource tx4938_sram_resource;
 
@@ -47,6 +96,7 @@
 
 	txx9_reg_res_init(TX4938_REV_PCODE(), TX4938_REG_BASE,
 			  TX4938_REG_SIZE);
+	set_c0_config(TX49_CONF_CWFON);
 
 	/* SDRAMC,EBUSC are configured by PROM */
 	for (i = 0; i < 8; i++) {
@@ -227,6 +277,9 @@
 				   TX4938_CLKCTR_ETH1CKD);
 		}
 	}
+
+	_machine_restart = tx4938_machine_restart;
+	board_be_init = tx4938_be_init;
 }
 
 void __init tx4938_time_init(unsigned int tmrnr)
@@ -268,3 +321,72 @@
 	if (addr1 && (pcfg & TX4938_PCFG_ETH1_SEL))
 		txx9_ethaddr_init(TXX9_IRQ_BASE + TX4938_IR_ETH1, addr1);
 }
+
+void __init tx4938_mtd_init(int ch)
+{
+	struct physmap_flash_data pdata = {
+		.width = TX4938_EBUSC_WIDTH(ch) / 8,
+	};
+	unsigned long start = txx9_ce_res[ch].start;
+	unsigned long size = txx9_ce_res[ch].end - start + 1;
+
+	if (!(TX4938_EBUSC_CR(ch) & 0x8))
+		return;	/* disabled */
+	txx9_physmap_flash_init(ch, start, size, &pdata);
+}
+
+static void __init tx4938_stop_unused_modules(void)
+{
+	__u64 pcfg, rst = 0, ckd = 0;
+	char buf[128];
+
+	buf[0] = '\0';
+	local_irq_disable();
+	pcfg = ____raw_readq(&tx4938_ccfgptr->pcfg);
+	switch (txx9_pcode) {
+	case 0x4937:
+		if (!(pcfg & TX4938_PCFG_SEL2)) {
+			rst |= TX4938_CLKCTR_ACLRST;
+			ckd |= TX4938_CLKCTR_ACLCKD;
+			strcat(buf, " ACLC");
+		}
+		break;
+	case 0x4938:
+		if (!(pcfg & TX4938_PCFG_SEL2) ||
+		    (pcfg & TX4938_PCFG_ETH0_SEL)) {
+			rst |= TX4938_CLKCTR_ACLRST;
+			ckd |= TX4938_CLKCTR_ACLCKD;
+			strcat(buf, " ACLC");
+		}
+		if ((pcfg &
+		     (TX4938_PCFG_ATA_SEL | TX4938_PCFG_ISA_SEL |
+		      TX4938_PCFG_NDF_SEL))
+		    != TX4938_PCFG_NDF_SEL) {
+			rst |= TX4938_CLKCTR_NDFRST;
+			ckd |= TX4938_CLKCTR_NDFCKD;
+			strcat(buf, " NDFMC");
+		}
+		if (!(pcfg & TX4938_PCFG_SPI_SEL)) {
+			rst |= TX4938_CLKCTR_SPIRST;
+			ckd |= TX4938_CLKCTR_SPICKD;
+			strcat(buf, " SPI");
+		}
+		break;
+	}
+	if (rst | ckd) {
+		txx9_set64(&tx4938_ccfgptr->clkctr, rst);
+		txx9_set64(&tx4938_ccfgptr->clkctr, ckd);
+	}
+	local_irq_enable();
+	if (buf[0])
+		pr_info("%s: stop%s\n", txx9_pcode_str, buf);
+}
+
+static int __init tx4938_late_init(void)
+{
+	if (txx9_pcode != 0x4937 && txx9_pcode != 0x4938)
+		return -ENODEV;
+	tx4938_stop_unused_modules();
+	return 0;
+}
+late_initcall(tx4938_late_init);
diff --git a/arch/mips/txx9/generic/setup_tx4939.c b/arch/mips/txx9/generic/setup_tx4939.c
new file mode 100644
index 0000000..6c0049a
--- /dev/null
+++ b/arch/mips/txx9/generic/setup_tx4939.c
@@ -0,0 +1,506 @@
+/*
+ * TX4939 setup routines
+ * Based on linux/arch/mips/txx9/generic/setup_tx4938.c,
+ *	    and RBTX49xx patch from CELF patch archive.
+ *
+ * 2003-2005 (c) MontaVista Software, Inc.
+ * (C) Copyright TOSHIBA CORPORATION 2000-2001, 2004-2007
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/notifier.h>
+#include <linux/sysdev.h>
+#include <linux/ethtool.h>
+#include <linux/param.h>
+#include <linux/ptrace.h>
+#include <linux/mtd/physmap.h>
+#include <linux/platform_device.h>
+#include <asm/bootinfo.h>
+#include <asm/reboot.h>
+#include <asm/traps.h>
+#include <asm/txx9irq.h>
+#include <asm/txx9tmr.h>
+#include <asm/txx9/generic.h>
+#include <asm/txx9/tx4939.h>
+
+static void __init tx4939_wdr_init(void)
+{
+	/* report watchdog reset status */
+	if (____raw_readq(&tx4939_ccfgptr->ccfg) & TX4939_CCFG_WDRST)
+		pr_warning("Watchdog reset detected at 0x%lx\n",
+			   read_c0_errorepc());
+	/* clear WatchDogReset (W1C) */
+	tx4939_ccfg_set(TX4939_CCFG_WDRST);
+	/* do reset on watchdog */
+	tx4939_ccfg_set(TX4939_CCFG_WR);
+}
+
+void __init tx4939_wdt_init(void)
+{
+	txx9_wdt_init(TX4939_TMR_REG(2) & 0xfffffffffULL);
+}
+
+static void tx4939_machine_restart(char *command)
+{
+	local_irq_disable();
+	pr_emerg("Rebooting (with %s watchdog reset)...\n",
+		 (____raw_readq(&tx4939_ccfgptr->ccfg) & TX4939_CCFG_WDREXEN) ?
+		 "external" : "internal");
+	/* clear watchdog status */
+	tx4939_ccfg_set(TX4939_CCFG_WDRST);	/* W1C */
+	txx9_wdt_now(TX4939_TMR_REG(2) & 0xfffffffffULL);
+	while (!(____raw_readq(&tx4939_ccfgptr->ccfg) & TX4939_CCFG_WDRST))
+		;
+	mdelay(10);
+	if (____raw_readq(&tx4939_ccfgptr->ccfg) & TX4939_CCFG_WDREXEN) {
+		pr_emerg("Rebooting (with internal watchdog reset)...\n");
+		/* External WDRST failed.  Do internal watchdog reset */
+		tx4939_ccfg_clear(TX4939_CCFG_WDREXEN);
+	}
+	/* fallback */
+	(*_machine_halt)();
+}
+
+void show_registers(struct pt_regs *regs);
+static int tx4939_be_handler(struct pt_regs *regs, int is_fixup)
+{
+	int data = regs->cp0_cause & 4;
+	console_verbose();
+	pr_err("%cBE exception at %#lx\n",
+	       data ? 'D' : 'I', regs->cp0_epc);
+	pr_err("ccfg:%llx, toea:%llx\n",
+	       (unsigned long long)____raw_readq(&tx4939_ccfgptr->ccfg),
+	       (unsigned long long)____raw_readq(&tx4939_ccfgptr->toea));
+#ifdef CONFIG_PCI
+	tx4927_report_pcic_status();
+#endif
+	show_registers(regs);
+	panic("BusError!");
+}
+static void __init tx4939_be_init(void)
+{
+	board_be_handler = tx4939_be_handler;
+}
+
+static struct resource tx4939_sdram_resource[4];
+static struct resource tx4939_sram_resource;
+#define TX4939_SRAM_SIZE 0x800
+
+void __init tx4939_add_memory_regions(void)
+{
+	int i;
+	unsigned long start, size;
+	u64 win;
+
+	for (i = 0; i < 4; i++) {
+		if (!((__u32)____raw_readq(&tx4939_ddrcptr->winen) & (1 << i)))
+			continue;
+		win = ____raw_readq(&tx4939_ddrcptr->win[i]);
+		start = (unsigned long)(win >> 48);
+		size = (((unsigned long)(win >> 32) & 0xffff) + 1) - start;
+		add_memory_region(start << 20, size << 20, BOOT_MEM_RAM);
+	}
+}
+
+void __init tx4939_setup(void)
+{
+	int i;
+	__u32 divmode;
+	__u64 pcfg;
+	int cpuclk = 0;
+
+	txx9_reg_res_init(TX4939_REV_PCODE(), TX4939_REG_BASE,
+			  TX4939_REG_SIZE);
+	set_c0_config(TX49_CONF_CWFON);
+
+	/* SDRAMC,EBUSC are configured by PROM */
+	for (i = 0; i < 4; i++) {
+		if (!(TX4939_EBUSC_CR(i) & 0x8))
+			continue;	/* disabled */
+		txx9_ce_res[i].start = (unsigned long)TX4939_EBUSC_BA(i);
+		txx9_ce_res[i].end =
+			txx9_ce_res[i].start + TX4939_EBUSC_SIZE(i) - 1;
+		request_resource(&iomem_resource, &txx9_ce_res[i]);
+	}
+
+	/* clocks */
+	if (txx9_master_clock) {
+		/* calculate cpu_clock from master_clock */
+		divmode = (__u32)____raw_readq(&tx4939_ccfgptr->ccfg) &
+			TX4939_CCFG_MULCLK_MASK;
+		cpuclk = txx9_master_clock * 20 / 2;
+		switch (divmode) {
+		case TX4939_CCFG_MULCLK_8:
+			cpuclk = cpuclk / 3 * 4 /* / 6 *  8 */; break;
+		case TX4939_CCFG_MULCLK_9:
+			cpuclk = cpuclk / 2 * 3 /* / 6 *  9 */; break;
+		case TX4939_CCFG_MULCLK_10:
+			cpuclk = cpuclk / 3 * 5 /* / 6 * 10 */; break;
+		case TX4939_CCFG_MULCLK_11:
+			cpuclk = cpuclk / 6 * 11; break;
+		case TX4939_CCFG_MULCLK_12:
+			cpuclk = cpuclk * 2 /* / 6 * 12 */; break;
+		case TX4939_CCFG_MULCLK_13:
+			cpuclk = cpuclk / 6 * 13; break;
+		case TX4939_CCFG_MULCLK_14:
+			cpuclk = cpuclk / 3 * 7 /* / 6 * 14 */; break;
+		case TX4939_CCFG_MULCLK_15:
+			cpuclk = cpuclk / 2 * 5 /* / 6 * 15 */; break;
+		}
+		txx9_cpu_clock = cpuclk;
+	} else {
+		if (txx9_cpu_clock == 0)
+			txx9_cpu_clock = 400000000;	/* 400MHz */
+		/* calculate master_clock from cpu_clock */
+		cpuclk = txx9_cpu_clock;
+		divmode = (__u32)____raw_readq(&tx4939_ccfgptr->ccfg) &
+			TX4939_CCFG_MULCLK_MASK;
+		switch (divmode) {
+		case TX4939_CCFG_MULCLK_8:
+			txx9_master_clock = cpuclk * 6 / 8; break;
+		case TX4939_CCFG_MULCLK_9:
+			txx9_master_clock = cpuclk * 6 / 9; break;
+		case TX4939_CCFG_MULCLK_10:
+			txx9_master_clock = cpuclk * 6 / 10; break;
+		case TX4939_CCFG_MULCLK_11:
+			txx9_master_clock = cpuclk * 6 / 11; break;
+		case TX4939_CCFG_MULCLK_12:
+			txx9_master_clock = cpuclk * 6 / 12; break;
+		case TX4939_CCFG_MULCLK_13:
+			txx9_master_clock = cpuclk * 6 / 13; break;
+		case TX4939_CCFG_MULCLK_14:
+			txx9_master_clock = cpuclk * 6 / 14; break;
+		case TX4939_CCFG_MULCLK_15:
+			txx9_master_clock = cpuclk * 6 / 15; break;
+		}
+		txx9_master_clock /= 10; /* * 2 / 20 */
+	}
+	/* calculate gbus_clock from cpu_clock */
+	divmode = (__u32)____raw_readq(&tx4939_ccfgptr->ccfg) &
+		TX4939_CCFG_YDIVMODE_MASK;
+	txx9_gbus_clock = txx9_cpu_clock;
+	switch (divmode) {
+	case TX4939_CCFG_YDIVMODE_2:
+		txx9_gbus_clock /= 2; break;
+	case TX4939_CCFG_YDIVMODE_3:
+		txx9_gbus_clock /= 3; break;
+	case TX4939_CCFG_YDIVMODE_5:
+		txx9_gbus_clock /= 5; break;
+	case TX4939_CCFG_YDIVMODE_6:
+		txx9_gbus_clock /= 6; break;
+	}
+	/* change default value to udelay/mdelay take reasonable time */
+	loops_per_jiffy = txx9_cpu_clock / HZ / 2;
+
+	/* CCFG */
+	tx4939_wdr_init();
+	/* clear BusErrorOnWrite flag (W1C) */
+	tx4939_ccfg_set(TX4939_CCFG_WDRST | TX4939_CCFG_BEOW);
+	/* enable Timeout BusError */
+	if (txx9_ccfg_toeon)
+		tx4939_ccfg_set(TX4939_CCFG_TOE);
+
+	/* DMA selection */
+	txx9_clear64(&tx4939_ccfgptr->pcfg, TX4939_PCFG_DMASEL_ALL);
+
+	/* Use external clock for external arbiter */
+	if (!(____raw_readq(&tx4939_ccfgptr->ccfg) & TX4939_CCFG_PCIARB))
+		txx9_clear64(&tx4939_ccfgptr->pcfg, TX4939_PCFG_PCICLKEN_ALL);
+
+	pr_info("%s -- %dMHz(M%dMHz,G%dMHz) CRIR:%08x CCFG:%llx PCFG:%llx\n",
+		txx9_pcode_str,
+		(cpuclk + 500000) / 1000000,
+		(txx9_master_clock + 500000) / 1000000,
+		(txx9_gbus_clock + 500000) / 1000000,
+		(__u32)____raw_readq(&tx4939_ccfgptr->crir),
+		(unsigned long long)____raw_readq(&tx4939_ccfgptr->ccfg),
+		(unsigned long long)____raw_readq(&tx4939_ccfgptr->pcfg));
+
+	pr_info("%s DDRC -- EN:%08x", txx9_pcode_str,
+		(__u32)____raw_readq(&tx4939_ddrcptr->winen));
+	for (i = 0; i < 4; i++) {
+		__u64 win = ____raw_readq(&tx4939_ddrcptr->win[i]);
+		if (!((__u32)____raw_readq(&tx4939_ddrcptr->winen) & (1 << i)))
+			continue;	/* disabled */
+		printk(KERN_CONT " #%d:%016llx", i, (unsigned long long)win);
+		tx4939_sdram_resource[i].name = "DDR SDRAM";
+		tx4939_sdram_resource[i].start =
+			(unsigned long)(win >> 48) << 20;
+		tx4939_sdram_resource[i].end =
+			((((unsigned long)(win >> 32) & 0xffff) + 1) <<
+			 20) - 1;
+		tx4939_sdram_resource[i].flags = IORESOURCE_MEM;
+		request_resource(&iomem_resource, &tx4939_sdram_resource[i]);
+	}
+	printk(KERN_CONT "\n");
+
+	/* SRAM */
+	if (____raw_readq(&tx4939_sramcptr->cr) & 1) {
+		unsigned int size = TX4939_SRAM_SIZE;
+		tx4939_sram_resource.name = "SRAM";
+		tx4939_sram_resource.start =
+			(____raw_readq(&tx4939_sramcptr->cr) >> (39-11))
+			& ~(size - 1);
+		tx4939_sram_resource.end =
+			tx4939_sram_resource.start + TX4939_SRAM_SIZE - 1;
+		tx4939_sram_resource.flags = IORESOURCE_MEM;
+		request_resource(&iomem_resource, &tx4939_sram_resource);
+	}
+
+	/* TMR */
+	/* disable all timers */
+	for (i = 0; i < TX4939_NR_TMR; i++)
+		txx9_tmr_init(TX4939_TMR_REG(i) & 0xfffffffffULL);
+
+	/* DMA */
+	for (i = 0; i < 2; i++)
+		____raw_writeq(TX4938_DMA_MCR_MSTEN,
+			       (void __iomem *)(TX4939_DMA_REG(i) + 0x50));
+
+	/* set PCIC1 reset (required to prevent hangup on BIST) */
+	txx9_set64(&tx4939_ccfgptr->clkctr, TX4939_CLKCTR_PCI1RST);
+	pcfg = ____raw_readq(&tx4939_ccfgptr->pcfg);
+	if (pcfg & (TX4939_PCFG_ET0MODE | TX4939_PCFG_ET1MODE)) {
+		mdelay(1);	/* at least 128 cpu clock */
+		/* clear PCIC1 reset */
+		txx9_clear64(&tx4939_ccfgptr->clkctr, TX4939_CLKCTR_PCI1RST);
+	} else {
+		pr_info("%s: stop PCIC1\n", txx9_pcode_str);
+		/* stop PCIC1 */
+		txx9_set64(&tx4939_ccfgptr->clkctr, TX4939_CLKCTR_PCI1CKD);
+	}
+	if (!(pcfg & TX4939_PCFG_ET0MODE)) {
+		pr_info("%s: stop ETH0\n", txx9_pcode_str);
+		txx9_set64(&tx4939_ccfgptr->clkctr, TX4939_CLKCTR_ETH0RST);
+		txx9_set64(&tx4939_ccfgptr->clkctr, TX4939_CLKCTR_ETH0CKD);
+	}
+	if (!(pcfg & TX4939_PCFG_ET1MODE)) {
+		pr_info("%s: stop ETH1\n", txx9_pcode_str);
+		txx9_set64(&tx4939_ccfgptr->clkctr, TX4939_CLKCTR_ETH1RST);
+		txx9_set64(&tx4939_ccfgptr->clkctr, TX4939_CLKCTR_ETH1CKD);
+	}
+
+	_machine_restart = tx4939_machine_restart;
+	board_be_init = tx4939_be_init;
+}
+
+void __init tx4939_time_init(unsigned int tmrnr)
+{
+	if (____raw_readq(&tx4939_ccfgptr->ccfg) & TX4939_CCFG_TINTDIS)
+		txx9_clockevent_init(TX4939_TMR_REG(tmrnr) & 0xfffffffffULL,
+				     TXX9_IRQ_BASE + TX4939_IR_TMR(tmrnr),
+				     TXX9_IMCLK);
+}
+
+void __init tx4939_sio_init(unsigned int sclk, unsigned int cts_mask)
+{
+	int i;
+	unsigned int ch_mask = 0;
+	__u64 pcfg = __raw_readq(&tx4939_ccfgptr->pcfg);
+
+	cts_mask |= ~1;	/* only SIO0 have RTS/CTS */
+	if ((pcfg & TX4939_PCFG_SIO2MODE_MASK) != TX4939_PCFG_SIO2MODE_SIO0)
+		cts_mask |= 1 << 0; /* disable SIO0 RTS/CTS by PCFG setting */
+	if ((pcfg & TX4939_PCFG_SIO2MODE_MASK) != TX4939_PCFG_SIO2MODE_SIO2)
+		ch_mask |= 1 << 2; /* disable SIO2 by PCFG setting */
+	if (pcfg & TX4939_PCFG_SIO3MODE)
+		ch_mask |= 1 << 3; /* disable SIO3 by PCFG setting */
+	for (i = 0; i < 4; i++) {
+		if ((1 << i) & ch_mask)
+			continue;
+		txx9_sio_init(TX4939_SIO_REG(i) & 0xfffffffffULL,
+			      TXX9_IRQ_BASE + TX4939_IR_SIO(i),
+			      i, sclk, (1 << i) & cts_mask);
+	}
+}
+
+#if defined(CONFIG_TC35815) || defined(CONFIG_TC35815_MODULE)
+static int tx4939_get_eth_speed(struct net_device *dev)
+{
+	struct ethtool_cmd cmd = { ETHTOOL_GSET };
+	int speed = 100;	/* default 100Mbps */
+	int err;
+	if (!dev->ethtool_ops || !dev->ethtool_ops->get_settings)
+		return speed;
+	err = dev->ethtool_ops->get_settings(dev, &cmd);
+	if (err < 0)
+		return speed;
+	speed = cmd.speed == SPEED_100 ? 100 : 10;
+	return speed;
+}
+static int tx4939_netdev_event(struct notifier_block *this,
+			       unsigned long event,
+			       void *ptr)
+{
+	struct net_device *dev = ptr;
+	if (event == NETDEV_CHANGE && netif_carrier_ok(dev)) {
+		__u64 bit = 0;
+		if (dev->irq == TXX9_IRQ_BASE + TX4939_IR_ETH(0))
+			bit = TX4939_PCFG_SPEED0;
+		else if (dev->irq == TXX9_IRQ_BASE + TX4939_IR_ETH(1))
+			bit = TX4939_PCFG_SPEED1;
+		if (bit) {
+			int speed = tx4939_get_eth_speed(dev);
+			if (speed == 100)
+				txx9_set64(&tx4939_ccfgptr->pcfg, bit);
+			else
+				txx9_clear64(&tx4939_ccfgptr->pcfg, bit);
+		}
+	}
+	return NOTIFY_DONE;
+}
+
+static struct notifier_block tx4939_netdev_notifier = {
+	.notifier_call = tx4939_netdev_event,
+	.priority = 1,
+};
+
+void __init tx4939_ethaddr_init(unsigned char *addr0, unsigned char *addr1)
+{
+	u64 pcfg = __raw_readq(&tx4939_ccfgptr->pcfg);
+
+	if (addr0 && (pcfg & TX4939_PCFG_ET0MODE))
+		txx9_ethaddr_init(TXX9_IRQ_BASE + TX4939_IR_ETH(0), addr0);
+	if (addr1 && (pcfg & TX4939_PCFG_ET1MODE))
+		txx9_ethaddr_init(TXX9_IRQ_BASE + TX4939_IR_ETH(1), addr1);
+	register_netdevice_notifier(&tx4939_netdev_notifier);
+}
+#else
+void __init tx4939_ethaddr_init(unsigned char *addr0, unsigned char *addr1)
+{
+}
+#endif
+
+void __init tx4939_mtd_init(int ch)
+{
+	struct physmap_flash_data pdata = {
+		.width = TX4939_EBUSC_WIDTH(ch) / 8,
+	};
+	unsigned long start = txx9_ce_res[ch].start;
+	unsigned long size = txx9_ce_res[ch].end - start + 1;
+
+	if (!(TX4939_EBUSC_CR(ch) & 0x8))
+		return;	/* disabled */
+	txx9_physmap_flash_init(ch, start, size, &pdata);
+}
+
+#define TX4939_ATA_REG_PHYS(ch) (TX4939_ATA_REG(ch) & 0xfffffffffULL)
+void __init tx4939_ata_init(void)
+{
+	static struct resource ata0_res[] = {
+		{
+			.start = TX4939_ATA_REG_PHYS(0),
+			.end = TX4939_ATA_REG_PHYS(0) + 0x1000 - 1,
+			.flags = IORESOURCE_MEM,
+		}, {
+			.start = TXX9_IRQ_BASE + TX4939_IR_ATA(0),
+			.flags = IORESOURCE_IRQ,
+		},
+	};
+	static struct resource ata1_res[] = {
+		{
+			.start = TX4939_ATA_REG_PHYS(1),
+			.end = TX4939_ATA_REG_PHYS(1) + 0x1000 - 1,
+			.flags = IORESOURCE_MEM,
+		}, {
+			.start = TXX9_IRQ_BASE + TX4939_IR_ATA(1),
+			.flags = IORESOURCE_IRQ,
+		},
+	};
+	static struct platform_device ata0_dev = {
+		.name = "tx4939ide",
+		.id = 0,
+		.num_resources = ARRAY_SIZE(ata0_res),
+		.resource = ata0_res,
+	};
+	static struct platform_device ata1_dev = {
+		.name = "tx4939ide",
+		.id = 1,
+		.num_resources = ARRAY_SIZE(ata1_res),
+		.resource = ata1_res,
+	};
+	__u64 pcfg = __raw_readq(&tx4939_ccfgptr->pcfg);
+
+	if (pcfg & TX4939_PCFG_ATA0MODE)
+		platform_device_register(&ata0_dev);
+	if ((pcfg & (TX4939_PCFG_ATA1MODE |
+		     TX4939_PCFG_ET1MODE |
+		     TX4939_PCFG_ET0MODE)) == TX4939_PCFG_ATA1MODE)
+		platform_device_register(&ata1_dev);
+}
+
+static void __init tx4939_stop_unused_modules(void)
+{
+	__u64 pcfg, rst = 0, ckd = 0;
+	char buf[128];
+
+	buf[0] = '\0';
+	local_irq_disable();
+	pcfg = ____raw_readq(&tx4939_ccfgptr->pcfg);
+	if ((pcfg & TX4939_PCFG_I2SMODE_MASK) !=
+	    TX4939_PCFG_I2SMODE_ACLC) {
+		rst |= TX4939_CLKCTR_ACLRST;
+		ckd |= TX4939_CLKCTR_ACLCKD;
+		strcat(buf, " ACLC");
+	}
+	if ((pcfg & TX4939_PCFG_I2SMODE_MASK) !=
+	    TX4939_PCFG_I2SMODE_I2S &&
+	    (pcfg & TX4939_PCFG_I2SMODE_MASK) !=
+	    TX4939_PCFG_I2SMODE_I2S_ALT) {
+		rst |= TX4939_CLKCTR_I2SRST;
+		ckd |= TX4939_CLKCTR_I2SCKD;
+		strcat(buf, " I2S");
+	}
+	if (!(pcfg & TX4939_PCFG_ATA0MODE)) {
+		rst |= TX4939_CLKCTR_ATA0RST;
+		ckd |= TX4939_CLKCTR_ATA0CKD;
+		strcat(buf, " ATA0");
+	}
+	if (!(pcfg & TX4939_PCFG_ATA1MODE)) {
+		rst |= TX4939_CLKCTR_ATA1RST;
+		ckd |= TX4939_CLKCTR_ATA1CKD;
+		strcat(buf, " ATA1");
+	}
+	if (pcfg & TX4939_PCFG_SPIMODE) {
+		rst |= TX4939_CLKCTR_SPIRST;
+		ckd |= TX4939_CLKCTR_SPICKD;
+		strcat(buf, " SPI");
+	}
+	if (!(pcfg & (TX4939_PCFG_VSSMODE | TX4939_PCFG_VPSMODE))) {
+		rst |= TX4939_CLKCTR_VPCRST;
+		ckd |= TX4939_CLKCTR_VPCCKD;
+		strcat(buf, " VPC");
+	}
+	if ((pcfg & TX4939_PCFG_SIO2MODE_MASK) != TX4939_PCFG_SIO2MODE_SIO2) {
+		rst |= TX4939_CLKCTR_SIO2RST;
+		ckd |= TX4939_CLKCTR_SIO2CKD;
+		strcat(buf, " SIO2");
+	}
+	if (pcfg & TX4939_PCFG_SIO3MODE) {
+		rst |= TX4939_CLKCTR_SIO3RST;
+		ckd |= TX4939_CLKCTR_SIO3CKD;
+		strcat(buf, " SIO3");
+	}
+	if (rst | ckd) {
+		txx9_set64(&tx4939_ccfgptr->clkctr, rst);
+		txx9_set64(&tx4939_ccfgptr->clkctr, ckd);
+	}
+	local_irq_enable();
+	if (buf[0])
+		pr_info("%s: stop%s\n", txx9_pcode_str, buf);
+}
+
+static int __init tx4939_late_init(void)
+{
+	if (txx9_pcode != 0x4939)
+		return -ENODEV;
+	tx4939_stop_unused_modules();
+	return 0;
+}
+late_initcall(tx4939_late_init);
diff --git a/arch/mips/txx9/generic/spi_eeprom.c b/arch/mips/txx9/generic/spi_eeprom.c
new file mode 100644
index 0000000..75c3472
--- /dev/null
+++ b/arch/mips/txx9/generic/spi_eeprom.c
@@ -0,0 +1,103 @@
+/*
+ * spi_eeprom.c
+ * Copyright (C) 2000-2001 Toshiba Corporation
+ *
+ * 2003-2005 (c) MontaVista Software, Inc. This file is licensed under the
+ * terms of the GNU General Public License version 2. This program is
+ * licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ *
+ * Support for TX4938 in 2.6 - Manish Lachwani (mlachwani@mvista.com)
+ */
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/eeprom.h>
+#include <asm/txx9/spi.h>
+
+#define AT250X0_PAGE_SIZE	8
+
+/* register board information for at25 driver */
+int __init spi_eeprom_register(int busid, int chipid, int size)
+{
+	struct spi_board_info info = {
+		.modalias = "at25",
+		.max_speed_hz = 1500000,	/* 1.5Mbps */
+		.bus_num = busid,
+		.chip_select = chipid,
+		/* Mode 0: High-Active, Sample-Then-Shift */
+	};
+	struct spi_eeprom *eeprom;
+	eeprom = kzalloc(sizeof(*eeprom), GFP_KERNEL);
+	if (!eeprom)
+		return -ENOMEM;
+	strcpy(eeprom->name, "at250x0");
+	eeprom->byte_len = size;
+	eeprom->page_size = AT250X0_PAGE_SIZE;
+	eeprom->flags = EE_ADDR1;
+	info.platform_data = eeprom;
+	return spi_register_board_info(&info, 1);
+}
+
+/* simple temporary spi driver to provide early access to seeprom. */
+
+static struct read_param {
+	int busid;
+	int chipid;
+	int address;
+	unsigned char *buf;
+	int len;
+} *read_param;
+
+static int __init early_seeprom_probe(struct spi_device *spi)
+{
+	int stat = 0;
+	u8 cmd[2];
+	int len = read_param->len;
+	char *buf = read_param->buf;
+	int address = read_param->address;
+
+	dev_info(&spi->dev, "spiclk %u KHz.\n",
+		 (spi->max_speed_hz + 500) / 1000);
+	if (read_param->busid != spi->master->bus_num ||
+	    read_param->chipid != spi->chip_select)
+		return -ENODEV;
+	while (len > 0) {
+		/* spi_write_then_read can only work with small chunk */
+		int c = len < AT250X0_PAGE_SIZE ? len : AT250X0_PAGE_SIZE;
+		cmd[0] = 0x03;	/* AT25_READ */
+		cmd[1] = address;
+		stat = spi_write_then_read(spi, cmd, sizeof(cmd), buf, c);
+		buf += c;
+		len -= c;
+		address += c;
+	}
+	return stat;
+}
+
+static struct spi_driver early_seeprom_driver __initdata = {
+	.driver = {
+		.name	= "at25",
+		.owner	= THIS_MODULE,
+	},
+	.probe	= early_seeprom_probe,
+};
+
+int __init spi_eeprom_read(int busid, int chipid, int address,
+			   unsigned char *buf, int len)
+{
+	int ret;
+	struct read_param param = {
+		.busid = busid,
+		.chipid = chipid,
+		.address = address,
+		.buf = buf,
+		.len = len
+	};
+
+	read_param = &param;
+	ret = spi_register_driver(&early_seeprom_driver);
+	if (!ret)
+		spi_unregister_driver(&early_seeprom_driver);
+	return ret;
+}
diff --git a/arch/mips/txx9/jmr3927/prom.c b/arch/mips/txx9/jmr3927/prom.c
index 70c4c8e..c899c0c 100644
--- a/arch/mips/txx9/jmr3927/prom.c
+++ b/arch/mips/txx9/jmr3927/prom.c
@@ -47,7 +47,6 @@
 	if ((tx3927_ccfgptr->ccfg & TX3927_CCFG_TLBOFF) == 0)
 		printk(KERN_ERR "TX3927 TLB off\n");
 
-	prom_init_cmdline();
 	add_memory_region(0, JMR3927_SDRAM_SIZE, BOOT_MEM_RAM);
 	txx9_sio_putchar_init(TX3927_SIO_REG(1));
 }
diff --git a/arch/mips/txx9/jmr3927/setup.c b/arch/mips/txx9/jmr3927/setup.c
index 87db41b..25e50a7 100644
--- a/arch/mips/txx9/jmr3927/setup.c
+++ b/arch/mips/txx9/jmr3927/setup.c
@@ -62,7 +62,6 @@
 }
 
 #define DO_WRITE_THROUGH
-#define DO_ENABLE_CACHE
 
 static void jmr3927_board_init(void);
 
@@ -77,11 +76,6 @@
 	/* cache setup */
 	{
 		unsigned int conf;
-#ifdef DO_ENABLE_CACHE
-		int mips_ic_disable = 0, mips_dc_disable = 0;
-#else
-		int mips_ic_disable = 1, mips_dc_disable = 1;
-#endif
 #ifdef DO_WRITE_THROUGH
 		int mips_config_cwfon = 0;
 		int mips_config_wbon = 0;
@@ -91,10 +85,7 @@
 #endif
 
 		conf = read_c0_conf();
-		conf &= ~(TX39_CONF_ICE | TX39_CONF_DCE |
-			  TX39_CONF_WBON | TX39_CONF_CWFON);
-		conf |= mips_ic_disable ? 0 : TX39_CONF_ICE;
-		conf |= mips_dc_disable ? 0 : TX39_CONF_DCE;
+		conf &= ~(TX39_CONF_WBON | TX39_CONF_CWFON);
 		conf |= mips_config_wbon ? TX39_CONF_WBON : 0;
 		conf |= mips_config_cwfon ? TX39_CONF_CWFON : 0;
 
@@ -199,11 +190,25 @@
 	platform_device_register_simple("rtc-ds1742", -1, &res, 1);
 }
 
+static void __init jmr3927_mtd_init(void)
+{
+	int i;
+
+	for (i = 0; i < 2; i++)
+		tx3927_mtd_init(i);
+}
+
 static void __init jmr3927_device_init(void)
 {
+	unsigned long iocled_base = JMR3927_IOC_LED_ADDR - IO_BASE;
+#ifdef __LITTLE_ENDIAN
+	iocled_base |= 1;
+#endif
 	__swizzle_addr_b = jmr3927_swizzle_addr_b;
 	jmr3927_rtc_init();
 	tx3927_wdt_init();
+	jmr3927_mtd_init();
+	txx9_iocled_init(iocled_base, -1, 8, 1, "green", NULL);
 }
 
 struct txx9_board_vec jmr3927_vec __initdata = {
diff --git a/arch/mips/txx9/rbtx4927/irq.c b/arch/mips/txx9/rbtx4927/irq.c
index 00cd523..9c14ebb 100644
--- a/arch/mips/txx9/rbtx4927/irq.c
+++ b/arch/mips/txx9/rbtx4927/irq.c
@@ -133,15 +133,20 @@
 	u8 level3;
 
 	level3 = readb(rbtx4927_imstat_addr) & 0x1f;
-	if (level3)
-		sw_irq = RBTX4927_IRQ_IOC + fls(level3) - 1;
-	return sw_irq;
+	if (unlikely(!level3))
+		return -1;
+	return RBTX4927_IRQ_IOC + __fls8(level3);
 }
 
 static void __init toshiba_rbtx4927_irq_ioc_init(void)
 {
 	int i;
 
+	/* mask all IOC interrupts */
+	writeb(0, rbtx4927_imask_addr);
+	/* clear SoftInt interrupts */
+	writeb(0, rbtx4927_softint_addr);
+
 	for (i = RBTX4927_IRQ_IOC;
 	     i < RBTX4927_IRQ_IOC + RBTX4927_NR_IRQ_IOC; i++)
 		set_irq_chip_and_handler(i, &toshiba_rbtx4927_irq_ioc_type,
diff --git a/arch/mips/txx9/rbtx4927/prom.c b/arch/mips/txx9/rbtx4927/prom.c
index 1dc0a5b..cc97c6a 100644
--- a/arch/mips/txx9/rbtx4927/prom.c
+++ b/arch/mips/txx9/rbtx4927/prom.c
@@ -36,7 +36,6 @@
 
 void __init rbtx4927_prom_init(void)
 {
-	prom_init_cmdline();
 	add_memory_region(0, tx4927_get_mem_size(), BOOT_MEM_RAM);
 	txx9_sio_putchar_init(TX4927_SIO_REG(0) & 0xfffffffffULL);
 }
diff --git a/arch/mips/txx9/rbtx4927/setup.c b/arch/mips/txx9/rbtx4927/setup.c
index 0d39baf..4a74423 100644
--- a/arch/mips/txx9/rbtx4927/setup.c
+++ b/arch/mips/txx9/rbtx4927/setup.c
@@ -48,6 +48,7 @@
 #include <linux/ioport.h>
 #include <linux/platform_device.h>
 #include <linux/delay.h>
+#include <linux/gpio.h>
 #include <asm/io.h>
 #include <asm/reboot.h>
 #include <asm/txx9/generic.h>
@@ -185,14 +186,8 @@
 
 static void __init rbtx4927_mem_setup(void)
 {
-	u32 cp0_config;
 	char *argptr;
 
-	/* enable caches -- HCP5 does this, pmon does not */
-	cp0_config = read_c0_config();
-	cp0_config = cp0_config & ~(TX49_CONF_IC | TX49_CONF_DC);
-	write_c0_config(cp0_config);
-
 	if (TX4927_REV_PCODE() == 0x4927) {
 		rbtx4927_clock_init();
 		tx4927_setup();
@@ -212,6 +207,14 @@
 	set_io_port_base(KSEG1 + RBTX4927_ISA_IO_OFFSET);
 #endif
 
+	/* TX4927-SIO DTR on (PIO[15]) */
+	gpio_request(15, "sio-dtr");
+	gpio_direction_output(15, 1);
+	gpio_request(0, "led");
+	gpio_direction_output(0, 1);
+	gpio_request(1, "led");
+	gpio_direction_output(1, 1);
+
 	tx4927_sio_init(0, 0);
 #ifdef CONFIG_SERIAL_TXX9_CONSOLE
 	argptr = prom_getcmdline();
@@ -304,11 +307,21 @@
 	platform_device_register_simple("ne", -1, res, ARRAY_SIZE(res));
 }
 
+static void __init rbtx4927_mtd_init(void)
+{
+	int i;
+
+	for (i = 0; i < 2; i++)
+		tx4927_mtd_init(i);
+}
+
 static void __init rbtx4927_device_init(void)
 {
 	toshiba_rbtx4927_rtc_init();
 	rbtx4927_ne_init();
 	tx4927_wdt_init();
+	rbtx4927_mtd_init();
+	txx9_iocled_init(RBTX4927_LED_ADDR - IO_BASE, -1, 3, 1, "green", NULL);
 }
 
 struct txx9_board_vec rbtx4927_vec __initdata = {
diff --git a/arch/mips/txx9/rbtx4938/Makefile b/arch/mips/txx9/rbtx4938/Makefile
index 9dcc52a..f3e1f59 100644
--- a/arch/mips/txx9/rbtx4938/Makefile
+++ b/arch/mips/txx9/rbtx4938/Makefile
@@ -1,3 +1,3 @@
-obj-y	+= prom.o setup.o irq.o spi_eeprom.o
+obj-y	+= prom.o setup.o irq.o
 
 EXTRA_CFLAGS += -Werror
diff --git a/arch/mips/txx9/rbtx4938/irq.c b/arch/mips/txx9/rbtx4938/irq.c
index ca2f830..7d21bef 100644
--- a/arch/mips/txx9/rbtx4938/irq.c
+++ b/arch/mips/txx9/rbtx4938/irq.c
@@ -85,10 +85,10 @@
 	u8 level3;
 
 	level3 = readb(rbtx4938_imstat_addr);
-	if (level3)
-		/* must use fls so onboard ATA has priority */
-		sw_irq = RBTX4938_IRQ_IOC + fls(level3) - 1;
-	return sw_irq;
+	if (unlikely(!level3))
+		return -1;
+	/* must use fls so onboard ATA has priority */
+	return RBTX4938_IRQ_IOC + __fls8(level3);
 }
 
 static void __init
diff --git a/arch/mips/txx9/rbtx4938/prom.c b/arch/mips/txx9/rbtx4938/prom.c
index d73123c..bcb4692 100644
--- a/arch/mips/txx9/rbtx4938/prom.c
+++ b/arch/mips/txx9/rbtx4938/prom.c
@@ -18,9 +18,6 @@
 
 void __init rbtx4938_prom_init(void)
 {
-#ifndef CONFIG_TX4938_NAND_BOOT
-	prom_init_cmdline();
-#endif
 	add_memory_region(0, tx4938_get_mem_size(), BOOT_MEM_RAM);
 	txx9_sio_putchar_init(TX4938_SIO_REG(0) & 0xfffffffffULL);
 }
diff --git a/arch/mips/txx9/rbtx4938/setup.c b/arch/mips/txx9/rbtx4938/setup.c
index 9ab48de..e077cc4 100644
--- a/arch/mips/txx9/rbtx4938/setup.c
+++ b/arch/mips/txx9/rbtx4938/setup.c
@@ -15,6 +15,7 @@
 #include <linux/delay.h>
 #include <linux/platform_device.h>
 #include <linux/gpio.h>
+#include <linux/mtd/physmap.h>
 
 #include <asm/reboot.h>
 #include <asm/io.h>
@@ -110,6 +111,7 @@
 #define	SEEPROM2_CS	0	/* IOC */
 #define	SEEPROM3_CS	1	/* IOC */
 #define	SRTC_CS	2	/* IOC */
+#define SPI_BUSNO	0
 
 static int __init rbtx4938_ethaddr_init(void)
 {
@@ -119,7 +121,7 @@
 	int i;
 
 	/* 0-3: "MAC\0", 4-9:eth0, 10-15:eth1, 16:sum */
-	if (spi_eeprom_read(SEEPROM1_CS, 0, dat, sizeof(dat))) {
+	if (spi_eeprom_read(SPI_BUSNO, SEEPROM1_CS, 0, dat, sizeof(dat))) {
 		printk(KERN_ERR "seeprom: read error.\n");
 		return -ENODEV;
 	} else {
@@ -173,23 +175,30 @@
 #endif
 
 #ifdef CONFIG_TOSHIBA_RBTX4938_MPLEX_PIO58_61
-	printk(KERN_INFO "PIOSEL: disabling both ata and nand selection\n");
+	pr_info("PIOSEL: disabling both ATA and NAND selection\n");
 	txx9_clear64(&tx4938_ccfgptr->pcfg,
 		     TX4938_PCFG_NDF_SEL | TX4938_PCFG_ATA_SEL);
 #endif
 
 #ifdef CONFIG_TOSHIBA_RBTX4938_MPLEX_NAND
-	printk(KERN_INFO "PIOSEL: enabling nand selection\n");
+	pr_info("PIOSEL: enabling NAND selection\n");
 	txx9_set64(&tx4938_ccfgptr->pcfg, TX4938_PCFG_NDF_SEL);
 	txx9_clear64(&tx4938_ccfgptr->pcfg, TX4938_PCFG_ATA_SEL);
 #endif
 
 #ifdef CONFIG_TOSHIBA_RBTX4938_MPLEX_ATA
-	printk(KERN_INFO "PIOSEL: enabling ata selection\n");
+	pr_info("PIOSEL: enabling ATA selection\n");
 	txx9_set64(&tx4938_ccfgptr->pcfg, TX4938_PCFG_ATA_SEL);
 	txx9_clear64(&tx4938_ccfgptr->pcfg, TX4938_PCFG_NDF_SEL);
 #endif
 
+#ifdef CONFIG_TOSHIBA_RBTX4938_MPLEX_KEEP
+	pcfg = ____raw_readq(&tx4938_ccfgptr->pcfg);
+	pr_info("PIOSEL: NAND %s, ATA %s\n",
+		(pcfg & TX4938_PCFG_NDF_SEL) ? "enabled" : "disabled",
+		(pcfg & TX4938_PCFG_ATA_SEL) ? "enabled" : "disabled");
+#endif
+
 	rbtx4938_spi_setup();
 	pcfg = ____raw_readq(&tx4938_ccfgptr->pcfg);	/* updated */
 	/* fixup piosel */
@@ -279,9 +288,9 @@
 		.mode = SPI_MODE_1 | SPI_CS_HIGH,
 	};
 	spi_register_board_info(&srtc_info, 1);
-	spi_eeprom_register(SEEPROM1_CS);
-	spi_eeprom_register(16 + SEEPROM2_CS);
-	spi_eeprom_register(16 + SEEPROM3_CS);
+	spi_eeprom_register(SPI_BUSNO, SEEPROM1_CS, 128);
+	spi_eeprom_register(SPI_BUSNO, 16 + SEEPROM2_CS, 128);
+	spi_eeprom_register(SPI_BUSNO, 16 + SEEPROM3_CS, 128);
 	gpio_request(16 + SRTC_CS, "rtc-rs5c348");
 	gpio_direction_output(16 + SRTC_CS, 0);
 	gpio_request(SEEPROM1_CS, "seeprom1");
@@ -290,10 +299,46 @@
 	gpio_direction_output(16 + SEEPROM2_CS, 1);
 	gpio_request(16 + SEEPROM3_CS, "seeprom3");
 	gpio_direction_output(16 + SEEPROM3_CS, 1);
-	tx4938_spi_init(0);
+	tx4938_spi_init(SPI_BUSNO);
 	return 0;
 }
 
+static void __init rbtx4938_mtd_init(void)
+{
+	struct physmap_flash_data pdata = {
+		.width = 4,
+	};
+
+	switch (readb(rbtx4938_bdipsw_addr) & 7) {
+	case 0:
+		/* Boot */
+		txx9_physmap_flash_init(0, 0x1fc00000, 0x400000, &pdata);
+		/* System */
+		txx9_physmap_flash_init(1, 0x1e000000, 0x1000000, &pdata);
+		break;
+	case 1:
+		/* System */
+		txx9_physmap_flash_init(0, 0x1f000000, 0x1000000, &pdata);
+		/* Boot */
+		txx9_physmap_flash_init(1, 0x1ec00000, 0x400000, &pdata);
+		break;
+	case 2:
+		/* Ext */
+		txx9_physmap_flash_init(0, 0x1f000000, 0x1000000, &pdata);
+		/* System */
+		txx9_physmap_flash_init(1, 0x1e000000, 0x1000000, &pdata);
+		/* Boot */
+		txx9_physmap_flash_init(2, 0x1dc00000, 0x400000, &pdata);
+		break;
+	case 3:
+		/* Boot */
+		txx9_physmap_flash_init(1, 0x1bc00000, 0x400000, &pdata);
+		/* System */
+		txx9_physmap_flash_init(2, 0x1a000000, 0x1000000, &pdata);
+		break;
+	}
+}
+
 static void __init rbtx4938_arch_init(void)
 {
 	gpiochip_add(&rbtx4938_spi_gpio_chip);
@@ -306,6 +351,8 @@
 	rbtx4938_ethaddr_init();
 	rbtx4938_ne_init();
 	tx4938_wdt_init();
+	rbtx4938_mtd_init();
+	txx9_iocled_init(RBTX4938_LED_ADDR - IO_BASE, -1, 8, 1, "green", NULL);
 }
 
 struct txx9_board_vec rbtx4938_vec __initdata = {
diff --git a/arch/mips/txx9/rbtx4938/spi_eeprom.c b/arch/mips/txx9/rbtx4938/spi_eeprom.c
deleted file mode 100644
index a7ea8b0..0000000
--- a/arch/mips/txx9/rbtx4938/spi_eeprom.c
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * spi_eeprom.c
- * Copyright (C) 2000-2001 Toshiba Corporation
- *
- * 2003-2005 (c) MontaVista Software, Inc. This file is licensed under the
- * terms of the GNU General Public License version 2. This program is
- * licensed "as is" without any warranty of any kind, whether express
- * or implied.
- *
- * Support for TX4938 in 2.6 - Manish Lachwani (mlachwani@mvista.com)
- */
-#include <linux/init.h>
-#include <linux/device.h>
-#include <linux/spi/spi.h>
-#include <linux/spi/eeprom.h>
-#include <asm/txx9/spi.h>
-
-#define AT250X0_PAGE_SIZE	8
-
-/* register board information for at25 driver */
-int __init spi_eeprom_register(int chipid)
-{
-	static struct spi_eeprom eeprom = {
-		.name = "at250x0",
-		.byte_len = 128,
-		.page_size = AT250X0_PAGE_SIZE,
-		.flags = EE_ADDR1,
-	};
-	struct spi_board_info info = {
-		.modalias = "at25",
-		.max_speed_hz = 1500000,	/* 1.5Mbps */
-		.bus_num = 0,
-		.chip_select = chipid,
-		.platform_data = &eeprom,
-		/* Mode 0: High-Active, Sample-Then-Shift */
-	};
-
-	return spi_register_board_info(&info, 1);
-}
-
-/* simple temporary spi driver to provide early access to seeprom. */
-
-static struct read_param {
-	int chipid;
-	int address;
-	unsigned char *buf;
-	int len;
-} *read_param;
-
-static int __init early_seeprom_probe(struct spi_device *spi)
-{
-	int stat = 0;
-	u8 cmd[2];
-	int len = read_param->len;
-	char *buf = read_param->buf;
-	int address = read_param->address;
-
-	dev_info(&spi->dev, "spiclk %u KHz.\n",
-		 (spi->max_speed_hz + 500) / 1000);
-	if (read_param->chipid != spi->chip_select)
-		return -ENODEV;
-	while (len > 0) {
-		/* spi_write_then_read can only work with small chunk */
-		int c = len < AT250X0_PAGE_SIZE ? len : AT250X0_PAGE_SIZE;
-		cmd[0] = 0x03;	/* AT25_READ */
-		cmd[1] = address;
-		stat = spi_write_then_read(spi, cmd, sizeof(cmd), buf, c);
-		buf += c;
-		len -= c;
-		address += c;
-	}
-	return stat;
-}
-
-static struct spi_driver early_seeprom_driver __initdata = {
-	.driver = {
-		.name	= "at25",
-		.owner	= THIS_MODULE,
-	},
-	.probe	= early_seeprom_probe,
-};
-
-int __init spi_eeprom_read(int chipid, int address,
-			   unsigned char *buf, int len)
-{
-	int ret;
-	struct read_param param = {
-		.chipid = chipid,
-		.address = address,
-		.buf = buf,
-		.len = len
-	};
-
-	read_param = &param;
-	ret = spi_register_driver(&early_seeprom_driver);
-	if (!ret)
-		spi_unregister_driver(&early_seeprom_driver);
-	return ret;
-}
diff --git a/arch/mips/txx9/rbtx4939/Makefile b/arch/mips/txx9/rbtx4939/Makefile
new file mode 100644
index 0000000..3232cd0
--- /dev/null
+++ b/arch/mips/txx9/rbtx4939/Makefile
@@ -0,0 +1,3 @@
+obj-y	 += irq.o setup.o prom.o
+
+EXTRA_CFLAGS += -Werror
diff --git a/arch/mips/txx9/rbtx4939/irq.c b/arch/mips/txx9/rbtx4939/irq.c
new file mode 100644
index 0000000..500cc0a
--- /dev/null
+++ b/arch/mips/txx9/rbtx4939/irq.c
@@ -0,0 +1,96 @@
+/*
+ * Toshiba RBTX4939 interrupt routines
+ * Based on linux/arch/mips/txx9/rbtx4938/irq.c,
+ *	    and RBTX49xx patch from CELF patch archive.
+ *
+ * Copyright (C) 2000-2001,2005-2006 Toshiba Corporation
+ * 2003-2005 (c) MontaVista Software, Inc. This file is licensed under the
+ * terms of the GNU General Public License version 2. This program is
+ * licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ */
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <asm/mipsregs.h>
+#include <asm/txx9/rbtx4939.h>
+
+/*
+ * RBTX4939 IOC controller definition
+ */
+
+static void rbtx4939_ioc_irq_unmask(unsigned int irq)
+{
+	int ioc_nr = irq - RBTX4939_IRQ_IOC;
+
+	writeb(readb(rbtx4939_ien_addr) | (1 << ioc_nr), rbtx4939_ien_addr);
+}
+
+static void rbtx4939_ioc_irq_mask(unsigned int irq)
+{
+	int ioc_nr = irq - RBTX4939_IRQ_IOC;
+
+	writeb(readb(rbtx4939_ien_addr) & ~(1 << ioc_nr), rbtx4939_ien_addr);
+	mmiowb();
+}
+
+static struct irq_chip rbtx4939_ioc_irq_chip = {
+	.name		= "IOC",
+	.ack		= rbtx4939_ioc_irq_mask,
+	.mask		= rbtx4939_ioc_irq_mask,
+	.mask_ack	= rbtx4939_ioc_irq_mask,
+	.unmask		= rbtx4939_ioc_irq_unmask,
+};
+
+
+static inline int rbtx4939_ioc_irqroute(void)
+{
+	unsigned char istat = readb(rbtx4939_ifac2_addr);
+
+	if (unlikely(istat == 0))
+		return -1;
+	return RBTX4939_IRQ_IOC + __fls8(istat);
+}
+
+static int rbtx4939_irq_dispatch(int pending)
+{
+	int irq;
+
+	if (pending & CAUSEF_IP7)
+		return MIPS_CPU_IRQ_BASE + 7;
+	irq = tx4939_irq();
+	if (likely(irq >= 0)) {
+		/* redirect IOC interrupts */
+		switch (irq) {
+		case RBTX4939_IRQ_IOCINT:
+			irq = rbtx4939_ioc_irqroute();
+			break;
+		}
+	} else if (pending & CAUSEF_IP0)
+		irq = MIPS_CPU_IRQ_BASE + 0;
+	else if (pending & CAUSEF_IP1)
+		irq = MIPS_CPU_IRQ_BASE + 1;
+	else
+		irq = -1;
+	return irq;
+}
+
+void __init rbtx4939_irq_setup(void)
+{
+	int i;
+
+	/* mask all IOC interrupts */
+	writeb(0, rbtx4939_ien_addr);
+
+	/* clear SoftInt interrupts */
+	writeb(0, rbtx4939_softint_addr);
+
+	txx9_irq_dispatch = rbtx4939_irq_dispatch;
+
+	tx4939_irq_init();
+	for (i = RBTX4939_IRQ_IOC;
+	     i < RBTX4939_IRQ_IOC + RBTX4939_NR_IRQ_IOC; i++)
+		set_irq_chip_and_handler(i, &rbtx4939_ioc_irq_chip,
+					 handle_level_irq);
+
+	set_irq_chained_handler(RBTX4939_IRQ_IOCINT, handle_simple_irq);
+}
diff --git a/arch/mips/txx9/rbtx4939/prom.c b/arch/mips/txx9/rbtx4939/prom.c
new file mode 100644
index 0000000..bd277ec
--- /dev/null
+++ b/arch/mips/txx9/rbtx4939/prom.c
@@ -0,0 +1,17 @@
+/*
+ * rbtx4939 specific prom routines
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/init.h>
+#include <asm/txx9/generic.h>
+#include <asm/txx9/rbtx4939.h>
+
+void __init rbtx4939_prom_init(void)
+{
+	tx4939_add_memory_regions();
+	txx9_sio_putchar_init(TX4939_SIO_REG(0) & 0xfffffffffULL);
+}
diff --git a/arch/mips/txx9/rbtx4939/setup.c b/arch/mips/txx9/rbtx4939/setup.c
new file mode 100644
index 0000000..9855d7b
--- /dev/null
+++ b/arch/mips/txx9/rbtx4939/setup.c
@@ -0,0 +1,307 @@
+/*
+ * Toshiba RBTX4939 setup routines.
+ * Based on linux/arch/mips/txx9/rbtx4938/setup.c,
+ *	    and RBTX49xx patch from CELF patch archive.
+ *
+ * Copyright (C) 2000-2001,2005-2007 Toshiba Corporation
+ * 2003-2005 (c) MontaVista Software, Inc. This file is licensed under the
+ * terms of the GNU General Public License version 2. This program is
+ * licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/platform_device.h>
+#include <linux/leds.h>
+#include <asm/reboot.h>
+#include <asm/txx9/generic.h>
+#include <asm/txx9/pci.h>
+#include <asm/txx9/rbtx4939.h>
+
+static void rbtx4939_machine_restart(char *command)
+{
+	local_irq_disable();
+	writeb(1, rbtx4939_reseten_addr);
+	writeb(1, rbtx4939_softreset_addr);
+	while (1)
+		;
+}
+
+static void __init rbtx4939_time_init(void)
+{
+	tx4939_time_init(0);
+}
+
+static void __init rbtx4939_pci_setup(void)
+{
+#ifdef CONFIG_PCI
+	int extarb = !(__raw_readq(&tx4939_ccfgptr->ccfg) & TX4939_CCFG_PCIARB);
+	struct pci_controller *c = &txx9_primary_pcic;
+
+	register_pci_controller(c);
+
+	tx4939_report_pciclk();
+	tx4927_pcic_setup(tx4939_pcicptr, c, extarb);
+	if (!(__raw_readq(&tx4939_ccfgptr->pcfg) & TX4939_PCFG_ATA1MODE) &&
+	    (__raw_readq(&tx4939_ccfgptr->pcfg) &
+	     (TX4939_PCFG_ET0MODE | TX4939_PCFG_ET1MODE))) {
+		tx4939_report_pci1clk();
+
+		/* mem:64K(max), io:64K(max) (enough for ETH0,ETH1) */
+		c = txx9_alloc_pci_controller(NULL, 0, 0x10000, 0, 0x10000);
+		register_pci_controller(c);
+		tx4927_pcic_setup(tx4939_pcic1ptr, c, 0);
+	}
+
+	tx4939_setup_pcierr_irq();
+#endif /* CONFIG_PCI */
+}
+
+static unsigned long long default_ebccr[] __initdata = {
+	0x01c0000000007608ULL, /* 64M ROM */
+	0x017f000000007049ULL, /* 1M IOC */
+	0x0180000000408608ULL, /* ISA */
+	0,
+};
+
+static void __init rbtx4939_ebusc_setup(void)
+{
+	int i;
+	unsigned int sp;
+
+	/* use user-configured speed */
+	sp = TX4939_EBUSC_CR(0) & 0x30;
+	default_ebccr[0] |= sp;
+	default_ebccr[1] |= sp;
+	default_ebccr[2] |= sp;
+	/* initialise by myself */
+	for (i = 0; i < ARRAY_SIZE(default_ebccr); i++) {
+		if (default_ebccr[i])
+			____raw_writeq(default_ebccr[i],
+				       &tx4939_ebuscptr->cr[i]);
+		else
+			____raw_writeq(____raw_readq(&tx4939_ebuscptr->cr[i])
+				       & ~8,
+				       &tx4939_ebuscptr->cr[i]);
+	}
+}
+
+static void __init rbtx4939_update_ioc_pen(void)
+{
+	__u64 pcfg = ____raw_readq(&tx4939_ccfgptr->pcfg);
+	__u64 ccfg = ____raw_readq(&tx4939_ccfgptr->ccfg);
+	__u8 pe1 = readb(rbtx4939_pe1_addr);
+	__u8 pe2 = readb(rbtx4939_pe2_addr);
+	__u8 pe3 = readb(rbtx4939_pe3_addr);
+	if (pcfg & TX4939_PCFG_ATA0MODE)
+		pe1 |= RBTX4939_PE1_ATA(0);
+	else
+		pe1 &= ~RBTX4939_PE1_ATA(0);
+	if (pcfg & TX4939_PCFG_ATA1MODE) {
+		pe1 |= RBTX4939_PE1_ATA(1);
+		pe1 &= ~(RBTX4939_PE1_RMII(0) | RBTX4939_PE1_RMII(1));
+	} else {
+		pe1 &= ~RBTX4939_PE1_ATA(1);
+		if (pcfg & TX4939_PCFG_ET0MODE)
+			pe1 |= RBTX4939_PE1_RMII(0);
+		else
+			pe1 &= ~RBTX4939_PE1_RMII(0);
+		if (pcfg & TX4939_PCFG_ET1MODE)
+			pe1 |= RBTX4939_PE1_RMII(1);
+		else
+			pe1 &= ~RBTX4939_PE1_RMII(1);
+	}
+	if (ccfg & TX4939_CCFG_PTSEL)
+		pe3 &= ~(RBTX4939_PE3_VP | RBTX4939_PE3_VP_P |
+			 RBTX4939_PE3_VP_S);
+	else {
+		__u64 vmode = pcfg &
+			(TX4939_PCFG_VSSMODE | TX4939_PCFG_VPSMODE);
+		if (vmode == 0)
+			pe3 &= ~(RBTX4939_PE3_VP | RBTX4939_PE3_VP_P |
+				 RBTX4939_PE3_VP_S);
+		else if (vmode == TX4939_PCFG_VPSMODE) {
+			pe3 |= RBTX4939_PE3_VP_P;
+			pe3 &= ~(RBTX4939_PE3_VP | RBTX4939_PE3_VP_S);
+		} else if (vmode == TX4939_PCFG_VSSMODE) {
+			pe3 |= RBTX4939_PE3_VP | RBTX4939_PE3_VP_S;
+			pe3 &= ~RBTX4939_PE3_VP_P;
+		} else {
+			pe3 |= RBTX4939_PE3_VP | RBTX4939_PE3_VP_P;
+			pe3 &= ~RBTX4939_PE3_VP_S;
+		}
+	}
+	if (pcfg & TX4939_PCFG_SPIMODE) {
+		if (pcfg & TX4939_PCFG_SIO2MODE_GPIO)
+			pe2 &= ~(RBTX4939_PE2_SIO2 | RBTX4939_PE2_SIO0);
+		else {
+			if (pcfg & TX4939_PCFG_SIO2MODE_SIO2) {
+				pe2 |= RBTX4939_PE2_SIO2;
+				pe2 &= ~RBTX4939_PE2_SIO0;
+			} else {
+				pe2 |= RBTX4939_PE2_SIO0;
+				pe2 &= ~RBTX4939_PE2_SIO2;
+			}
+		}
+		if (pcfg & TX4939_PCFG_SIO3MODE)
+			pe2 |= RBTX4939_PE2_SIO3;
+		else
+			pe2 &= ~RBTX4939_PE2_SIO3;
+		pe2 &= ~RBTX4939_PE2_SPI;
+	} else {
+		pe2 |= RBTX4939_PE2_SPI;
+		pe2 &= ~(RBTX4939_PE2_SIO3 | RBTX4939_PE2_SIO2 |
+			 RBTX4939_PE2_SIO0);
+	}
+	if ((pcfg & TX4939_PCFG_I2SMODE_MASK) == TX4939_PCFG_I2SMODE_GPIO)
+		pe2 |= RBTX4939_PE2_GPIO;
+	else
+		pe2 &= ~RBTX4939_PE2_GPIO;
+	writeb(pe1, rbtx4939_pe1_addr);
+	writeb(pe2, rbtx4939_pe2_addr);
+	writeb(pe3, rbtx4939_pe3_addr);
+}
+
+#define RBTX4939_MAX_7SEGLEDS	8
+
+#if defined(CONFIG_LEDS_CLASS) || defined(CONFIG_LEDS_CLASS_MODULE)
+static u8 led_val[RBTX4939_MAX_7SEGLEDS];
+struct rbtx4939_led_data {
+	struct led_classdev cdev;
+	char name[32];
+	unsigned int num;
+};
+
+/* Use "dot" in 7seg LEDs */
+static void rbtx4939_led_brightness_set(struct led_classdev *led_cdev,
+					enum led_brightness value)
+{
+	struct rbtx4939_led_data *led_dat =
+		container_of(led_cdev, struct rbtx4939_led_data, cdev);
+	unsigned int num = led_dat->num;
+	unsigned long flags;
+
+	local_irq_save(flags);
+	led_val[num] = (led_val[num] & 0x7f) | (value ? 0x80 : 0);
+	writeb(led_val[num], rbtx4939_7seg_addr(num / 4, num % 4));
+	local_irq_restore(flags);
+}
+
+static int __init rbtx4939_led_probe(struct platform_device *pdev)
+{
+	struct rbtx4939_led_data *leds_data;
+	int i;
+	static char *default_triggers[] __initdata = {
+		"heartbeat",
+		"ide-disk",
+		"nand-disk",
+	};
+
+	leds_data = kzalloc(sizeof(*leds_data) * RBTX4939_MAX_7SEGLEDS,
+			    GFP_KERNEL);
+	if (!leds_data)
+		return -ENOMEM;
+	for (i = 0; i < RBTX4939_MAX_7SEGLEDS; i++) {
+		int rc;
+		struct rbtx4939_led_data *led_dat = &leds_data[i];
+
+		led_dat->num = i;
+		led_dat->cdev.brightness_set = rbtx4939_led_brightness_set;
+		sprintf(led_dat->name, "rbtx4939:amber:%u", i);
+		led_dat->cdev.name = led_dat->name;
+		if (i < ARRAY_SIZE(default_triggers))
+			led_dat->cdev.default_trigger = default_triggers[i];
+		rc = led_classdev_register(&pdev->dev, &led_dat->cdev);
+		if (rc < 0)
+			return rc;
+		led_dat->cdev.brightness_set(&led_dat->cdev, 0);
+	}
+	return 0;
+
+}
+
+static struct platform_driver rbtx4939_led_driver = {
+	.driver  = {
+		.name = "rbtx4939-led",
+		.owner = THIS_MODULE,
+	},
+};
+
+static void __init rbtx4939_led_setup(void)
+{
+	platform_device_register_simple("rbtx4939-led", -1, NULL, 0);
+	platform_driver_probe(&rbtx4939_led_driver, rbtx4939_led_probe);
+}
+#else
+static inline void rbtx4939_led_setup(void)
+{
+}
+#endif
+
+static void __init rbtx4939_arch_init(void)
+{
+	rbtx4939_pci_setup();
+}
+
+static void __init rbtx4939_device_init(void)
+{
+#if defined(CONFIG_TC35815) || defined(CONFIG_TC35815_MODULE)
+	int i, j;
+	unsigned char ethaddr[2][6];
+	for (i = 0; i < 2; i++) {
+		unsigned long area = CKSEG1 + 0x1fff0000 + (i * 0x10);
+		if (readb(rbtx4939_bdipsw_addr) & 8) {
+			u16 buf[3];
+			area -= 0x03000000;
+			for (j = 0; j < 3; j++)
+				buf[j] = le16_to_cpup((u16 *)(area + j * 2));
+			memcpy(ethaddr[i], buf, 6);
+		} else
+			memcpy(ethaddr[i], (void *)area, 6);
+	}
+	tx4939_ethaddr_init(ethaddr[0], ethaddr[1]);
+#endif
+	rbtx4939_led_setup();
+	tx4939_wdt_init();
+	tx4939_ata_init();
+}
+
+static void __init rbtx4939_setup(void)
+{
+	rbtx4939_ebusc_setup();
+	/* always enable ATA0 */
+	txx9_set64(&tx4939_ccfgptr->pcfg, TX4939_PCFG_ATA0MODE);
+	rbtx4939_update_ioc_pen();
+	if (txx9_master_clock == 0)
+		txx9_master_clock = 20000000;
+	tx4939_setup();
+
+	_machine_restart = rbtx4939_machine_restart;
+
+	pr_info("RBTX4939 (Rev %02x) --- FPGA(Rev %02x) DIPSW:%02x,%02x\n",
+		readb(rbtx4939_board_rev_addr), readb(rbtx4939_ioc_rev_addr),
+		readb(rbtx4939_udipsw_addr), readb(rbtx4939_bdipsw_addr));
+
+#ifdef CONFIG_PCI
+	txx9_alloc_pci_controller(&txx9_primary_pcic, 0, 0, 0, 0);
+	txx9_board_pcibios_setup = tx4927_pcibios_setup;
+#else
+	set_io_port_base(RBTX4939_ETHER_BASE);
+#endif
+
+	tx4939_sio_init(TX4939_SCLK0(txx9_master_clock), 0);
+}
+
+struct txx9_board_vec rbtx4939_vec __initdata = {
+	.system = "Tothiba RBTX4939",
+	.prom_init = rbtx4939_prom_init,
+	.mem_setup = rbtx4939_setup,
+	.irq_setup = rbtx4939_irq_setup,
+	.time_init = rbtx4939_time_init,
+	.device_init = rbtx4939_device_init,
+	.arch_init = rbtx4939_arch_init,
+#ifdef CONFIG_PCI
+	.pci_map_irq = tx4939_pci_map_irq,
+#endif
+};
diff --git a/arch/mips/vr41xx/common/irq.c b/arch/mips/vr41xx/common/irq.c
index cba36a2..92dd1a0 100644
--- a/arch/mips/vr41xx/common/irq.c
+++ b/arch/mips/vr41xx/common/irq.c
@@ -72,6 +72,7 @@
 	cascade = irq_cascade + irq;
 	if (cascade->get_irq != NULL) {
 		unsigned int source_irq = irq;
+		int ret;
 		desc = irq_desc + source_irq;
 		if (desc->chip->mask_ack)
 			desc->chip->mask_ack(source_irq);
@@ -79,8 +80,9 @@
 			desc->chip->mask(source_irq);
 			desc->chip->ack(source_irq);
 		}
-		irq = cascade->get_irq(irq);
-		if (irq < 0)
+		ret = cascade->get_irq(irq);
+		irq = ret;
+		if (ret < 0)
 			atomic_inc(&irq_err_count);
 		else
 			irq_dispatch(irq);
diff --git a/arch/mn10300/Kconfig b/arch/mn10300/Kconfig
index e856218..dd557c9 100644
--- a/arch/mn10300/Kconfig
+++ b/arch/mn10300/Kconfig
@@ -53,9 +53,6 @@
 config ARCH_HAS_ILOG2_U32
 	def_bool y
 
-config ARCH_SUPPORTS_AOUT
-	def_bool n
-
 # Use the generic interrupt handling code in kernel/irq/
 config GENERIC_HARDIRQS
 	def_bool y
diff --git a/arch/mn10300/kernel/irq.c b/arch/mn10300/kernel/irq.c
index 761c434..56c64cc 100644
--- a/arch/mn10300/kernel/irq.c
+++ b/arch/mn10300/kernel/irq.c
@@ -20,22 +20,8 @@
 atomic_t irq_err_count;
 
 /*
- * MN10300 INTC controller operations
+ * MN10300 interrupt controller operations
  */
-static void mn10300_cpupic_disable(unsigned int irq)
-{
-	u16 tmp = GxICR(irq);
-	GxICR(irq) = (tmp & GxICR_LEVEL) | GxICR_DETECT;
-	tmp = GxICR(irq);
-}
-
-static void mn10300_cpupic_enable(unsigned int irq)
-{
-	u16 tmp = GxICR(irq);
-	GxICR(irq) = (tmp & GxICR_LEVEL) | GxICR_ENABLE;
-	tmp = GxICR(irq);
-}
-
 static void mn10300_cpupic_ack(unsigned int irq)
 {
 	u16 tmp;
@@ -60,26 +46,54 @@
 static void mn10300_cpupic_unmask(unsigned int irq)
 {
 	u16 tmp = GxICR(irq);
-	GxICR(irq) = (tmp & GxICR_LEVEL) | GxICR_ENABLE | GxICR_DETECT;
-	tmp = GxICR(irq);
-}
-
-static void mn10300_cpupic_end(unsigned int irq)
-{
-	u16 tmp = GxICR(irq);
 	GxICR(irq) = (tmp & GxICR_LEVEL) | GxICR_ENABLE;
 	tmp = GxICR(irq);
 }
 
-static struct irq_chip mn10300_cpu_pic = {
-	.name		= "cpu",
-	.disable	= mn10300_cpupic_disable,
-	.enable		= mn10300_cpupic_enable,
+static void mn10300_cpupic_unmask_clear(unsigned int irq)
+{
+	/* the MN10300 PIC latches its interrupt request bit, even after the
+	 * device has ceased to assert its interrupt line and the interrupt
+	 * channel has been disabled in the PIC, so for level-triggered
+	 * interrupts we need to clear the request bit when we re-enable */
+	u16 tmp = GxICR(irq);
+	GxICR(irq) = (tmp & GxICR_LEVEL) | GxICR_ENABLE | GxICR_DETECT;
+	tmp = GxICR(irq);
+}
+
+/*
+ * MN10300 PIC level-triggered IRQ handling.
+ *
+ * The PIC has no 'ACK' function per se.  It is possible to clear individual
+ * channel latches, but each latch relatches whether or not the channel is
+ * masked, so we need to clear the latch when we unmask the channel.
+ *
+ * Also for this reason, we don't supply an ack() op (it's unused anyway if
+ * mask_ack() is provided), and mask_ack() just masks.
+ */
+static struct irq_chip mn10300_cpu_pic_level = {
+	.name		= "cpu_l",
+	.disable	= mn10300_cpupic_mask,
+	.enable		= mn10300_cpupic_unmask_clear,
+	.ack		= NULL,
+	.mask		= mn10300_cpupic_mask,
+	.mask_ack	= mn10300_cpupic_mask,
+	.unmask		= mn10300_cpupic_unmask_clear,
+};
+
+/*
+ * MN10300 PIC edge-triggered IRQ handling.
+ *
+ * We use the latch clearing function of the PIC as the 'ACK' function.
+ */
+static struct irq_chip mn10300_cpu_pic_edge = {
+	.name		= "cpu_e",
+	.disable	= mn10300_cpupic_mask,
+	.enable		= mn10300_cpupic_unmask,
 	.ack		= mn10300_cpupic_ack,
 	.mask		= mn10300_cpupic_mask,
 	.mask_ack	= mn10300_cpupic_mask_ack,
 	.unmask		= mn10300_cpupic_unmask,
-	.end		= mn10300_cpupic_end,
 };
 
 /*
@@ -114,7 +128,8 @@
  */
 void set_intr_postackable(int irq)
 {
-	set_irq_handler(irq, handle_level_irq);
+	set_irq_chip_and_handler(irq, &mn10300_cpu_pic_level,
+				 handle_level_irq);
 }
 
 /*
@@ -126,8 +141,12 @@
 
 	for (irq = 0; irq < NR_IRQS; irq++)
 		if (irq_desc[irq].chip == &no_irq_type)
-			set_irq_chip_and_handler(irq, &mn10300_cpu_pic,
-						 handle_edge_irq);
+			/* due to the PIC latching interrupt requests, even
+			 * when the IRQ is disabled, IRQ_PENDING is superfluous
+			 * and we can use handle_level_irq() for edge-triggered
+			 * interrupts */
+			set_irq_chip_and_handler(irq, &mn10300_cpu_pic_edge,
+						 handle_level_irq);
 	unit_init_IRQ();
 }
 
diff --git a/arch/mn10300/kernel/time.c b/arch/mn10300/kernel/time.c
index babb7c2..e460658 100644
--- a/arch/mn10300/kernel/time.c
+++ b/arch/mn10300/kernel/time.c
@@ -1,6 +1,6 @@
 /* MN10300 Low level time management
  *
- * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
+ * Copyright (C) 2007-2008 Red Hat, Inc. All Rights Reserved.
  * Written by David Howells (dhowells@redhat.com)
  * - Derived from arch/i386/kernel/time.c
  *
@@ -16,6 +16,7 @@
 #include <linux/init.h>
 #include <linux/smp.h>
 #include <linux/profile.h>
+#include <linux/cnt32_to_63.h>
 #include <asm/irq.h>
 #include <asm/div64.h>
 #include <asm/processor.h>
@@ -40,27 +41,54 @@
 	.name		= "timer",
 };
 
+static unsigned long sched_clock_multiplier;
+
 /*
  * scheduler clock - returns current time in nanosec units.
  */
 unsigned long long sched_clock(void)
 {
 	union {
-		unsigned long long l;
-		u32 w[2];
-	} quot;
+		unsigned long long ll;
+		unsigned l[2];
+	} tsc64, result;
+	unsigned long tsc, tmp;
+	unsigned product[3]; /* 96-bit intermediate value */
 
-	quot.w[0] = mn10300_last_tsc - get_cycles();
-	quot.w[1] = 1000000000;
+	/* read the TSC value
+	 */
+	tsc = 0 - get_cycles(); /* get_cycles() counts down */
 
-	asm("mulu %2,%3,%0,%1"
-	    : "=r"(quot.w[1]), "=r"(quot.w[0])
-	    : "0"(quot.w[1]), "1"(quot.w[0])
+	/* expand to 64-bits.
+	 * - sched_clock() must be called once a minute or better or the
+	 *   following will go horribly wrong - see cnt32_to_63()
+	 */
+	tsc64.ll = cnt32_to_63(tsc) & 0x7fffffffffffffffULL;
+
+	/* scale the 64-bit TSC value to a nanosecond value via a 96-bit
+	 * intermediate
+	 */
+	asm("mulu	%2,%0,%3,%0	\n"	/* LSW * mult ->  0:%3:%0 */
+	    "mulu	%2,%1,%2,%1	\n"	/* MSW * mult -> %2:%1:0 */
+	    "add	%3,%1		\n"
+	    "addc	0,%2		\n"	/* result in %2:%1:%0 */
+	    : "=r"(product[0]), "=r"(product[1]), "=r"(product[2]), "=r"(tmp)
+	    :  "0"(tsc64.l[0]),  "1"(tsc64.l[1]),  "2"(sched_clock_multiplier)
 	    : "cc");
 
-	do_div(quot.l, MN10300_TSCCLK);
+	result.l[0] = product[1] << 16 | product[0] >> 16;
+	result.l[1] = product[2] << 16 | product[1] >> 16;
 
-	return quot.l;
+	return result.ll;
+}
+
+/*
+ * initialise the scheduler clock
+ */
+static void __init mn10300_sched_clock_init(void)
+{
+	sched_clock_multiplier =
+		__muldiv64u(NSEC_PER_SEC, 1 << 16, MN10300_TSCCLK);
 }
 
 /*
@@ -128,4 +156,6 @@
 	/* start the watchdog timer */
 	watchdog_go();
 #endif
+
+	mn10300_sched_clock_init();
 }
diff --git a/arch/mn10300/unit-asb2303/unit-init.c b/arch/mn10300/unit-asb2303/unit-init.c
index 14b2c81..70e8cb4 100644
--- a/arch/mn10300/unit-asb2303/unit-init.c
+++ b/arch/mn10300/unit-asb2303/unit-init.c
@@ -51,7 +51,7 @@
 		switch (GET_XIRQ_TRIGGER(extnum)) {
 		case XIRQ_TRIGGER_HILEVEL:
 		case XIRQ_TRIGGER_LOWLEVEL:
-			set_irq_handler(XIRQ2IRQ(extnum), handle_level_irq);
+			set_intr_postackable(XIRQ2IRQ(extnum));
 			break;
 		default:
 			break;
diff --git a/arch/mn10300/unit-asb2305/unit-init.c b/arch/mn10300/unit-asb2305/unit-init.c
index 6a35241..72812a9 100644
--- a/arch/mn10300/unit-asb2305/unit-init.c
+++ b/arch/mn10300/unit-asb2305/unit-init.c
@@ -52,7 +52,7 @@
 		switch (GET_XIRQ_TRIGGER(extnum)) {
 		case XIRQ_TRIGGER_HILEVEL:
 		case XIRQ_TRIGGER_LOWLEVEL:
-			set_irq_handler(XIRQ2IRQ(extnum), handle_level_irq);
+			set_intr_postackable(XIRQ2IRQ(extnum));
 			break;
 		default:
 			break;
diff --git a/arch/parisc/Kconfig b/arch/parisc/Kconfig
index a7d4fd35..8313fcc 100644
--- a/arch/parisc/Kconfig
+++ b/arch/parisc/Kconfig
@@ -76,9 +76,6 @@
 	bool
 	default y
 
-config ARCH_SUPPORTS_AOUT
-	def_bool y
-
 # unless you want to implement ACPI on PA-RISC ... ;-)
 config PM
 	bool
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index 587da5e..f5f83ee 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -22,6 +22,9 @@
 config PPC_MERGE
 	def_bool y
 
+config ARCH_PHYS_ADDR_T_64BIT
+       def_bool PPC64 || PHYS_64BIT
+
 config MMU
 	bool
 	default y
diff --git a/arch/powerpc/boot/Makefile b/arch/powerpc/boot/Makefile
index 717a3bc..65d1a84 100644
--- a/arch/powerpc/boot/Makefile
+++ b/arch/powerpc/boot/Makefile
@@ -195,7 +195,7 @@
 image-$(CONFIG_PPC_CHRP)		+= zImage.chrp
 image-$(CONFIG_PPC_EFIKA)		+= zImage.chrp
 image-$(CONFIG_PPC_PMAC)		+= zImage.pmac
-image-$(CONFIG_PPC_HOLLY)		+= zImage.holly
+image-$(CONFIG_PPC_HOLLY)		+= dtbImage.holly
 image-$(CONFIG_PPC_PRPMC2800)		+= dtbImage.prpmc2800
 image-$(CONFIG_PPC_ISERIES)		+= zImage.iseries
 image-$(CONFIG_DEFAULT_UIMAGE)		+= uImage
diff --git a/arch/powerpc/boot/dts/holly.dts b/arch/powerpc/boot/dts/holly.dts
index f87fe7b..c6e11eb 100644
--- a/arch/powerpc/boot/dts/holly.dts
+++ b/arch/powerpc/boot/dts/holly.dts
@@ -133,61 +133,61 @@
 			reg = <0x00007400 0x00000400>;
 			big-endian;
 		};
+	};
 
-		pci@1000 {
-			device_type = "pci";
-			compatible = "tsi109-pci", "tsi108-pci";
-			#interrupt-cells = <1>;
-			#size-cells = <2>;
-			#address-cells = <3>;
-			reg = <0x00001000 0x00001000>;
-			bus-range = <0x0 0x0>;
-			/*----------------------------------------------------+
-			| PCI memory range.
-			| 01 denotes I/O space
-			| 02 denotes 32-bit memory space
-			+----------------------------------------------------*/
-			ranges = <0x02000000 0x00000000 0x40000000 0x40000000 0x00000000 0x10000000
-				  0x01000000 0x00000000 0x00000000 0x7e000000 0x00000000 0x00010000>;
-			clock-frequency = <133333332>;
-			interrupt-parent = <&MPIC>;
+	pci@c0001000 {
+		device_type = "pci";
+		compatible = "tsi109-pci", "tsi108-pci";
+		#interrupt-cells = <1>;
+		#size-cells = <2>;
+		#address-cells = <3>;
+		reg = <0xc0001000 0x00001000>;
+		bus-range = <0x0 0x0>;
+		/*----------------------------------------------------+
+		| PCI memory range.
+		| 01 denotes I/O space
+		| 02 denotes 32-bit memory space
+		+----------------------------------------------------*/
+		ranges = <0x02000000 0x00000000 0x40000000 0x40000000 0x00000000 0x10000000
+			  0x01000000 0x00000000 0x00000000 0x7e000000 0x00000000 0x00010000>;
+		clock-frequency = <133333332>;
+		interrupt-parent = <&MPIC>;
+		interrupts = <0x17 0x2>;
+		interrupt-map-mask = <0xf800 0x0 0x0 0x7>;
+		/*----------------------------------------------------+
+		| The INTA, INTB, INTC, INTD are shared.
+		+----------------------------------------------------*/
+		interrupt-map = <
+			0x800 0x0 0x0 0x1 &RT0 0x24 0x0
+			0x800 0x0 0x0 0x2 &RT0 0x25 0x0
+			0x800 0x0 0x0 0x3 &RT0 0x26 0x0
+			0x800 0x0 0x0 0x4 &RT0 0x27 0x0
+
+			0x1000 0x0 0x0 0x1 &RT0 0x25 0x0
+			0x1000 0x0 0x0 0x2 &RT0 0x26 0x0
+			0x1000 0x0 0x0 0x3 &RT0 0x27 0x0
+			0x1000 0x0 0x0 0x4 &RT0 0x24 0x0
+
+			0x1800 0x0 0x0 0x1 &RT0 0x26 0x0
+			0x1800 0x0 0x0 0x2 &RT0 0x27 0x0
+			0x1800 0x0 0x0 0x3 &RT0 0x24 0x0
+			0x1800 0x0 0x0 0x4 &RT0 0x25 0x0
+
+			0x2000 0x0 0x0 0x1 &RT0 0x27 0x0
+			0x2000 0x0 0x0 0x2 &RT0 0x24 0x0
+			0x2000 0x0 0x0 0x3 &RT0 0x25 0x0
+			0x2000 0x0 0x0 0x4 &RT0 0x26 0x0
+			>;
+
+		RT0: router@1180 {
+			device_type = "pic-router";
+			interrupt-controller;
+			big-endian;
+			clock-frequency = <0>;
+			#address-cells = <0>;
+			#interrupt-cells = <2>;
 			interrupts = <0x17 0x2>;
-			interrupt-map-mask = <0xf800 0x0 0x0 0x7>;
-			/*----------------------------------------------------+
-			| The INTA, INTB, INTC, INTD are shared.
-			+----------------------------------------------------*/
-			interrupt-map = <
-				0x800 0x0 0x0 0x1 &RT0 0x24 0x0
-				0x800 0x0 0x0 0x2 &RT0 0x25 0x0
-				0x800 0x0 0x0 0x3 &RT0 0x26 0x0
-				0x800 0x0 0x0 0x4 &RT0 0x27 0x0
-
-				0x1000 0x0 0x0 0x1 &RT0 0x25 0x0
-				0x1000 0x0 0x0 0x2 &RT0 0x26 0x0
-				0x1000 0x0 0x0 0x3 &RT0 0x27 0x0
-				0x1000 0x0 0x0 0x4 &RT0 0x24 0x0
-
-				0x1800 0x0 0x0 0x1 &RT0 0x26 0x0
-				0x1800 0x0 0x0 0x2 &RT0 0x27 0x0
-				0x1800 0x0 0x0 0x3 &RT0 0x24 0x0
-				0x1800 0x0 0x0 0x4 &RT0 0x25 0x0
-
-				0x2000 0x0 0x0 0x1 &RT0 0x27 0x0
-				0x2000 0x0 0x0 0x2 &RT0 0x24 0x0
-				0x2000 0x0 0x0 0x3 &RT0 0x25 0x0
-				0x2000 0x0 0x0 0x4 &RT0 0x26 0x0
-				>;
-
-			RT0: router@1180 {
- 				device_type = "pic-router";
- 				interrupt-controller;
- 				big-endian;
- 				clock-frequency = <0>;
- 				#address-cells = <0>;
- 				#interrupt-cells = <2>;
- 				interrupts = <0x17 0x2>;
-				interrupt-parent = <&MPIC>;
-			};
+			interrupt-parent = <&MPIC>;
 		};
 	};
 
diff --git a/arch/powerpc/boot/dts/mpc8610_hpcd.dts b/arch/powerpc/boot/dts/mpc8610_hpcd.dts
index 3b3a106..584a4f1 100644
--- a/arch/powerpc/boot/dts/mpc8610_hpcd.dts
+++ b/arch/powerpc/boot/dts/mpc8610_hpcd.dts
@@ -281,7 +281,7 @@
 				cell-index = <0>;
 				reg = <0x0 0x80>;
 				interrupt-parent = <&mpic>;
-				interrupts = <60 2>;
+				interrupts = <76 2>;
 			};
 			dma-channel@1 {
 				compatible = "fsl,mpc8610-dma-channel",
@@ -289,7 +289,7 @@
 				cell-index = <1>;
 				reg = <0x80 0x80>;
 				interrupt-parent = <&mpic>;
-				interrupts = <61 2>;
+				interrupts = <77 2>;
 			};
 			dma-channel@2 {
 				compatible = "fsl,mpc8610-dma-channel",
@@ -297,7 +297,7 @@
 				cell-index = <2>;
 				reg = <0x100 0x80>;
 				interrupt-parent = <&mpic>;
-				interrupts = <62 2>;
+				interrupts = <78 2>;
 			};
 			dma-channel@3 {
 				compatible = "fsl,mpc8610-dma-channel",
@@ -305,7 +305,7 @@
 				cell-index = <3>;
 				reg = <0x180 0x80>;
 				interrupt-parent = <&mpic>;
-				interrupts = <63 2>;
+				interrupts = <79 2>;
 			};
 		};
 
diff --git a/arch/powerpc/include/asm/a.out.h b/arch/powerpc/include/asm/a.out.h
deleted file mode 100644
index 89cead6..0000000
--- a/arch/powerpc/include/asm/a.out.h
+++ /dev/null
@@ -1,20 +0,0 @@
-#ifndef _ASM_POWERPC_A_OUT_H
-#define _ASM_POWERPC_A_OUT_H
-
-struct exec
-{
-	unsigned long a_info;	/* Use macros N_MAGIC, etc for access */
-	unsigned a_text;	/* length of text, in bytes */
-	unsigned a_data;	/* length of data, in bytes */
-	unsigned a_bss;		/* length of uninitialized data area for file, in bytes */
-	unsigned a_syms;	/* length of symbol table data in file, in bytes */
-	unsigned a_entry;	/* start address */
-	unsigned a_trsize;	/* length of relocation info for text, in bytes */
-	unsigned a_drsize;	/* length of relocation info for data, in bytes */
-};
-
-#define N_TRSIZE(a)	((a).a_trsize)
-#define N_DRSIZE(a)	((a).a_drsize)
-#define N_SYMSIZE(a)	((a).a_syms)
-
-#endif /* _ASM_POWERPC_A_OUT_H */
diff --git a/arch/powerpc/include/asm/dcr-regs.h b/arch/powerpc/include/asm/dcr-regs.h
index 29b0ece..f15296c 100644
--- a/arch/powerpc/include/asm/dcr-regs.h
+++ b/arch/powerpc/include/asm/dcr-regs.h
@@ -68,6 +68,10 @@
 #define SDR0_UART3		0x0123
 #define SDR0_CUST0		0x4000
 
+/* SDRs (460EX/460GT) */
+#define SDR0_ETH_CFG		0x4103
+#define SDR0_ETH_CFG_ECS	0x00000100	/* EMAC int clk source */
+
 /*
  * All those DCR register addresses are offsets from the base address
  * for the SRAM0 controller (e.g. 0x20 on 440GX). The base address is
diff --git a/arch/powerpc/include/asm/elf.h b/arch/powerpc/include/asm/elf.h
index 80d1f39..64c6ee2 100644
--- a/arch/powerpc/include/asm/elf.h
+++ b/arch/powerpc/include/asm/elf.h
@@ -409,6 +409,13 @@
 /* Keep this the last entry.  */
 #define R_PPC64_NUM		107
 
+/* There's actually a third entry here, but it's unused */
+struct ppc64_opd_entry
+{
+	unsigned long funcaddr;
+	unsigned long r2;
+};
+
 #ifdef  __KERNEL__
 
 #ifdef CONFIG_SPU_BASE
diff --git a/arch/powerpc/include/asm/sections.h b/arch/powerpc/include/asm/sections.h
index 7710e9e..07956f3 100644
--- a/arch/powerpc/include/asm/sections.h
+++ b/arch/powerpc/include/asm/sections.h
@@ -2,6 +2,8 @@
 #define _ASM_POWERPC_SECTIONS_H
 #ifdef __KERNEL__
 
+#include <linux/elf.h>
+#include <linux/uaccess.h>
 #include <asm-generic/sections.h>
 
 #ifdef __powerpc64__
@@ -17,7 +19,15 @@
 }
 
 #undef dereference_function_descriptor
-void *dereference_function_descriptor(void *);
+static inline void *dereference_function_descriptor(void *ptr)
+{
+	struct ppc64_opd_entry *desc = ptr;
+	void *p;
+
+	if (!probe_kernel_address(&desc->funcaddr, p))
+		ptr = p;
+	return ptr;
+}
 
 #endif
 
diff --git a/arch/powerpc/include/asm/siginfo.h b/arch/powerpc/include/asm/siginfo.h
index 12f1bce..49495b0 100644
--- a/arch/powerpc/include/asm/siginfo.h
+++ b/arch/powerpc/include/asm/siginfo.h
@@ -15,11 +15,6 @@
 
 #include <asm-generic/siginfo.h>
 
-/*
- * SIGTRAP si_codes
- */
-#define TRAP_BRANCH	(__SI_FAULT|3)	/* process taken branch trap */
-#define TRAP_HWBKPT	(__SI_FAULT|4)	/* hardware breakpoint or watchpoint */
 #undef NSIGTRAP
 #define NSIGTRAP	4
 
diff --git a/arch/powerpc/include/asm/statfs.h b/arch/powerpc/include/asm/statfs.h
index 6702402..5244834 100644
--- a/arch/powerpc/include/asm/statfs.h
+++ b/arch/powerpc/include/asm/statfs.h
@@ -1,60 +1,6 @@
 #ifndef _ASM_POWERPC_STATFS_H
 #define _ASM_POWERPC_STATFS_H
 
-/* For ppc32 we just use the generic definitions, not so simple on ppc64 */
-
-#ifndef __powerpc64__
 #include <asm-generic/statfs.h>
-#else
 
-#ifndef __KERNEL_STRICT_NAMES
-#include <linux/types.h>
-typedef __kernel_fsid_t	fsid_t;
-#endif
-
-/*
- * We're already 64-bit, so duplicate the definition
- */
-struct statfs {
-	long f_type;
-	long f_bsize;
-	long f_blocks;
-	long f_bfree;
-	long f_bavail;
-	long f_files;
-	long f_ffree;
-	__kernel_fsid_t f_fsid;
-	long f_namelen;
-	long f_frsize;
-	long f_spare[5];
-};
-
-struct statfs64 {
-	long f_type;
-	long f_bsize;
-	long f_blocks;
-	long f_bfree;
-	long f_bavail;
-	long f_files;
-	long f_ffree;
-	__kernel_fsid_t f_fsid;
-	long f_namelen;
-	long f_frsize;
-	long f_spare[5];
-};
-
-struct compat_statfs64 {
-	__u32 f_type;
-	__u32 f_bsize;
-	__u64 f_blocks;
-	__u64 f_bfree;
-	__u64 f_bavail;
-	__u64 f_files;
-	__u64 f_ffree;
-	__kernel_fsid_t f_fsid;
-	__u32 f_namelen;
-	__u32 f_frsize;
-	__u32 f_spare[5];
-};
-#endif /* ! __powerpc64__ */
 #endif
diff --git a/arch/powerpc/include/asm/types.h b/arch/powerpc/include/asm/types.h
index d3374bc..c646f34 100644
--- a/arch/powerpc/include/asm/types.h
+++ b/arch/powerpc/include/asm/types.h
@@ -48,13 +48,6 @@
 
 typedef __vector128 vector128;
 
-/* Physical address used by some IO functions */
-#if defined(CONFIG_PPC64) || defined(CONFIG_PHYS_64BIT)
-typedef u64 phys_addr_t;
-#else
-typedef u32 phys_addr_t;
-#endif
-
 #ifdef __powerpc64__
 typedef u64 dma_addr_t;
 #else
diff --git a/arch/powerpc/kernel/idle.c b/arch/powerpc/kernel/idle.c
index d308a9f..31982d0 100644
--- a/arch/powerpc/kernel/idle.c
+++ b/arch/powerpc/kernel/idle.c
@@ -34,11 +34,7 @@
 #include <asm/smp.h>
 
 #ifdef CONFIG_HOTPLUG_CPU
-/* this is used for software suspend, and that shuts down
- * CPUs even while the system is still booting... */
-#define cpu_should_die()	(cpu_is_offline(smp_processor_id()) && \
-				   (system_state == SYSTEM_RUNNING     \
-				 || system_state == SYSTEM_BOOTING))
+#define cpu_should_die()	cpu_is_offline(smp_processor_id())
 #else
 #define cpu_should_die()	0
 #endif
diff --git a/arch/powerpc/kernel/kgdb.c b/arch/powerpc/kernel/kgdb.c
index b4fdf2f..fe8f71d 100644
--- a/arch/powerpc/kernel/kgdb.c
+++ b/arch/powerpc/kernel/kgdb.c
@@ -347,9 +347,8 @@
 			linux_regs->msr |= MSR_SE;
 #endif
 			kgdb_single_step = 1;
-			if (kgdb_contthread)
-				atomic_set(&kgdb_cpu_doing_single_step,
-					   raw_smp_processor_id());
+			atomic_set(&kgdb_cpu_doing_single_step,
+				   raw_smp_processor_id());
 		}
 		return 0;
 	}
diff --git a/arch/powerpc/kernel/module_64.c b/arch/powerpc/kernel/module_64.c
index ad79de2..1af2377 100644
--- a/arch/powerpc/kernel/module_64.c
+++ b/arch/powerpc/kernel/module_64.c
@@ -21,9 +21,7 @@
 #include <linux/err.h>
 #include <linux/vmalloc.h>
 #include <linux/bug.h>
-#include <linux/uaccess.h>
 #include <asm/module.h>
-#include <asm/sections.h>
 #include <asm/firmware.h>
 #include <asm/code-patching.h>
 #include <linux/sort.h>
@@ -43,13 +41,6 @@
 #define DEBUGP(fmt , ...)
 #endif
 
-/* There's actually a third entry here, but it's unused */
-struct ppc64_opd_entry
-{
-	unsigned long funcaddr;
-	unsigned long r2;
-};
-
 /* Like PPC32, we need little trampolines to do > 24-bit jumps (into
    the kernel itself).  But on PPC64, these need to be used for every
    jump, actually, to reset r2 (TOC+0x8000). */
@@ -452,13 +443,3 @@
 
 	return 0;
 }
-
-void *dereference_function_descriptor(void *ptr)
-{
-	struct ppc64_opd_entry *desc = ptr;
-	void *p;
-
-	if (!probe_kernel_address(&desc->funcaddr, p))
-		ptr = p;
-	return ptr;
-}
diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c
index 5337ca7..c27b10a 100644
--- a/arch/powerpc/kernel/smp.c
+++ b/arch/powerpc/kernel/smp.c
@@ -453,6 +453,7 @@
 	secondary_cpu_time_init();
 
 	ipi_call_lock();
+	notify_cpu_starting(cpu);
 	cpu_set(cpu, cpu_online_map);
 	/* Update sibling maps */
 	base = cpu_first_thread_in_core(cpu);
diff --git a/arch/powerpc/kernel/softemu8xx.c b/arch/powerpc/kernel/softemu8xx.c
index c906c4b..23c8c5e 100644
--- a/arch/powerpc/kernel/softemu8xx.c
+++ b/arch/powerpc/kernel/softemu8xx.c
@@ -23,7 +23,6 @@
 #include <linux/ptrace.h>
 #include <linux/slab.h>
 #include <linux/user.h>
-#include <linux/a.out.h>
 #include <linux/interrupt.h>
 
 #include <asm/pgtable.h>
diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c
index 81ccb8dd..f5def6c 100644
--- a/arch/powerpc/kernel/traps.c
+++ b/arch/powerpc/kernel/traps.c
@@ -23,7 +23,6 @@
 #include <linux/ptrace.h>
 #include <linux/slab.h>
 #include <linux/user.h>
-#include <linux/a.out.h>
 #include <linux/interrupt.h>
 #include <linux/init.h>
 #include <linux/module.h>
diff --git a/arch/powerpc/platforms/82xx/ep8248e.c b/arch/powerpc/platforms/82xx/ep8248e.c
index d5770fd..0eb6d7f6 100644
--- a/arch/powerpc/platforms/82xx/ep8248e.c
+++ b/arch/powerpc/platforms/82xx/ep8248e.c
@@ -137,7 +137,7 @@
 		bus->irq[i] = -1;
 
 	bus->name = "ep8248e-mdio-bitbang";
-	bus->dev = &ofdev->dev;
+	bus->parent = &ofdev->dev;
 	snprintf(bus->id, MII_BUS_ID_SIZE, "%x", res.start);
 
 	return mdiobus_register(bus);
diff --git a/arch/powerpc/platforms/Kconfig.cputype b/arch/powerpc/platforms/Kconfig.cputype
index 7f65127..be852fd 100644
--- a/arch/powerpc/platforms/Kconfig.cputype
+++ b/arch/powerpc/platforms/Kconfig.cputype
@@ -135,7 +135,6 @@
 config PHYS_64BIT
 	bool 'Large physical address support' if E500
 	depends on 44x || E500
-	select RESOURCES_64BIT
 	default y if 44x
 	---help---
 	  This option enables kernel support for larger than 32-bit physical
diff --git a/arch/powerpc/platforms/cell/spufs/inode.c b/arch/powerpc/platforms/cell/spufs/inode.c
index 690ca7b..2c8b809 100644
--- a/arch/powerpc/platforms/cell/spufs/inode.c
+++ b/arch/powerpc/platforms/cell/spufs/inode.c
@@ -659,7 +659,7 @@
 	Opt_uid, Opt_gid, Opt_mode, Opt_debug, Opt_err,
 };
 
-static match_table_t spufs_tokens = {
+static const match_table_t spufs_tokens = {
 	{ Opt_uid,   "uid=%d" },
 	{ Opt_gid,   "gid=%d" },
 	{ Opt_mode,  "mode=%o" },
diff --git a/arch/powerpc/platforms/chrp/setup.c b/arch/powerpc/platforms/chrp/setup.c
index 1ba7ce5..272d79a 100644
--- a/arch/powerpc/platforms/chrp/setup.c
+++ b/arch/powerpc/platforms/chrp/setup.c
@@ -17,7 +17,6 @@
 #include <linux/ptrace.h>
 #include <linux/slab.h>
 #include <linux/user.h>
-#include <linux/a.out.h>
 #include <linux/tty.h>
 #include <linux/major.h>
 #include <linux/interrupt.h>
diff --git a/arch/powerpc/platforms/fsl_uli1575.c b/arch/powerpc/platforms/fsl_uli1575.c
index ef74a07..8c61996 100644
--- a/arch/powerpc/platforms/fsl_uli1575.c
+++ b/arch/powerpc/platforms/fsl_uli1575.c
@@ -219,11 +219,21 @@
 	int i;
 	u8 *dummy;
 	struct pci_bus *bus = dev->bus;
+	resource_size_t end = 0;
+
+	for (i = PCI_BRIDGE_RESOURCES; i < PCI_BRIDGE_RESOURCES+3; i++) {
+		unsigned long flags = pci_resource_flags(dev, i);
+		if ((flags & (IORESOURCE_MEM|IORESOURCE_PREFETCH)) == IORESOURCE_MEM)
+			end = pci_resource_end(dev, i);
+	}
 
 	for (i = 0; i < PCI_BUS_NUM_RESOURCES; i++) {
 		if ((bus->resource[i]) &&
 			(bus->resource[i]->flags & IORESOURCE_MEM)) {
-			dummy = ioremap(bus->resource[i]->end - 3, 0x4);
+			if (bus->resource[i]->end == end)
+				dummy = ioremap(bus->resource[i]->start, 0x4);
+			else
+				dummy = ioremap(bus->resource[i]->end - 3, 0x4);
 			if (dummy) {
 				in_8(dummy);
 				iounmap(dummy);
diff --git a/arch/powerpc/platforms/maple/setup.c b/arch/powerpc/platforms/maple/setup.c
index 3647147..d4c61c3 100644
--- a/arch/powerpc/platforms/maple/setup.c
+++ b/arch/powerpc/platforms/maple/setup.c
@@ -23,7 +23,6 @@
 #include <linux/ptrace.h>
 #include <linux/slab.h>
 #include <linux/user.h>
-#include <linux/a.out.h>
 #include <linux/tty.h>
 #include <linux/string.h>
 #include <linux/delay.h>
diff --git a/arch/powerpc/platforms/pasemi/gpio_mdio.c b/arch/powerpc/platforms/pasemi/gpio_mdio.c
index ab69554..75cc165 100644
--- a/arch/powerpc/platforms/pasemi/gpio_mdio.c
+++ b/arch/powerpc/platforms/pasemi/gpio_mdio.c
@@ -230,7 +230,7 @@
 	if (!priv)
 		goto out;
 
-	new_bus = kzalloc(sizeof(struct mii_bus), GFP_KERNEL);
+	new_bus = mdiobus_alloc();
 
 	if (!new_bus)
 		goto out_free_priv;
@@ -272,7 +272,7 @@
 	prop = of_get_property(np, "mdio-pin", NULL);
 	priv->mdio_pin = *prop;
 
-	new_bus->dev = dev;
+	new_bus->parent = dev;
 	dev_set_drvdata(dev, new_bus);
 
 	err = mdiobus_register(new_bus);
@@ -306,7 +306,7 @@
 
 	kfree(bus->priv);
 	bus->priv = NULL;
-	kfree(bus);
+	mdiobus_free(bus);
 
 	return 0;
 }
diff --git a/arch/powerpc/platforms/powermac/setup.c b/arch/powerpc/platforms/powermac/setup.c
index 88ccf3a..82c14d2 100644
--- a/arch/powerpc/platforms/powermac/setup.c
+++ b/arch/powerpc/platforms/powermac/setup.c
@@ -33,7 +33,6 @@
 #include <linux/ptrace.h>
 #include <linux/slab.h>
 #include <linux/user.h>
-#include <linux/a.out.h>
 #include <linux/tty.h>
 #include <linux/string.h>
 #include <linux/delay.h>
diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c
index 7b01d67..ec34170 100644
--- a/arch/powerpc/platforms/pseries/setup.c
+++ b/arch/powerpc/platforms/pseries/setup.c
@@ -25,7 +25,6 @@
 #include <linux/unistd.h>
 #include <linux/slab.h>
 #include <linux/user.h>
-#include <linux/a.out.h>
 #include <linux/tty.h>
 #include <linux/major.h>
 #include <linux/interrupt.h>
diff --git a/arch/powerpc/sysdev/mv64x60_dev.c b/arch/powerpc/sysdev/mv64x60_dev.c
index 32e0ad0..b6bd775 100644
--- a/arch/powerpc/sysdev/mv64x60_dev.c
+++ b/arch/powerpc/sysdev/mv64x60_dev.c
@@ -293,10 +293,8 @@
 		return -ENODEV;
 
 	prop = of_get_property(phy, "reg", NULL);
-	if (prop) {
-		pdata.force_phy_addr = 1;
-		pdata.phy_addr = *prop;
-	}
+	if (prop)
+		pdata.phy_addr = MV643XX_ETH_PHY_ADDR(*prop);
 
 	of_node_put(phy);
 
diff --git a/arch/powerpc/sysdev/ppc4xx_pci.c b/arch/powerpc/sysdev/ppc4xx_pci.c
index fb368df..e8a76d9 100644
--- a/arch/powerpc/sysdev/ppc4xx_pci.c
+++ b/arch/powerpc/sysdev/ppc4xx_pci.c
@@ -41,13 +41,10 @@
 #define U64_TO_U32_LOW(val)	((u32)((val) & 0x00000000ffffffffULL))
 #define U64_TO_U32_HIGH(val)	((u32)((val) >> 32))
 
-#ifdef CONFIG_RESOURCES_64BIT
-#define RES_TO_U32_LOW(val)	U64_TO_U32_LOW(val)
-#define RES_TO_U32_HIGH(val)	U64_TO_U32_HIGH(val)
-#else
-#define RES_TO_U32_LOW(val)	(val)
-#define RES_TO_U32_HIGH(val)	(0)
-#endif
+#define RES_TO_U32_LOW(val)	\
+	((sizeof(resource_size_t) > sizeof(u32)) ? U64_TO_U32_LOW(val) : (val))
+#define RES_TO_U32_HIGH(val)	\
+	((sizeof(resource_size_t) > sizeof(u32)) ? U64_TO_U32_HIGH(val) : (0))
 
 static inline int ppc440spe_revA(void)
 {
@@ -145,12 +142,11 @@
 
 		/* Use that */
 		res->start = pci_addr;
-#ifndef CONFIG_RESOURCES_64BIT
 		/* Beware of 32 bits resources */
-		if ((pci_addr + size) > 0x100000000ull)
+		if (sizeof(resource_size_t) == sizeof(u32) &&
+		    (pci_addr + size) > 0x100000000ull)
 			res->end = 0xffffffff;
 		else
-#endif
 			res->end = res->start + size - 1;
 		break;
 	}
diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig
index 8d41908..4c03049 100644
--- a/arch/s390/Kconfig
+++ b/arch/s390/Kconfig
@@ -74,6 +74,7 @@
 	select HAVE_KPROBES
 	select HAVE_KRETPROBES
 	select HAVE_KVM if 64BIT
+	select HAVE_ARCH_TRACEHOOK
 
 source "init/Kconfig"
 
diff --git a/arch/s390/hypfs/inode.c b/arch/s390/hypfs/inode.c
index 7383781..3631380 100644
--- a/arch/s390/hypfs/inode.c
+++ b/arch/s390/hypfs/inode.c
@@ -219,7 +219,7 @@
 
 enum { opt_uid, opt_gid, opt_err };
 
-static match_table_t hypfs_tokens = {
+static const match_table_t hypfs_tokens = {
 	{opt_uid, "uid=%u"},
 	{opt_gid, "gid=%u"},
 	{opt_err, NULL}
diff --git a/arch/s390/include/asm/dasd.h b/arch/s390/include/asm/dasd.h
index 3f002e1..55b2b80 100644
--- a/arch/s390/include/asm/dasd.h
+++ b/arch/s390/include/asm/dasd.h
@@ -3,6 +3,8 @@
  * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
  * Bugreports.to..: <Linux390@de.ibm.com>
  * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
+ * EMC Symmetrix ioctl Copyright EMC Corporation, 2008
+ * Author.........: Nigel Hislop <hislop_nigel@emc.com>
  *
  * This file is the interface of the DASD device driver, which is exported to user space
  * any future changes wrt the API will result in a change of the APIVERSION reported
@@ -202,6 +204,16 @@
 #define DASD_SEQ_PRESTAGE  0x4
 #define DASD_REC_ACCESS    0x5
 
+/*
+ * Perform EMC Symmetrix I/O
+ */
+typedef struct dasd_symmio_parms {
+	unsigned char reserved[8];	/* compat with older releases */
+	unsigned long long psf_data;	/* char * cast to u64 */
+	unsigned long long rssd_result; /* char * cast to u64 */
+	int psf_data_len;
+	int rssd_result_len;
+} __attribute__ ((packed)) dasd_symmio_parms_t;
 
 /********************************************************************************
  * SECTION: Definition of IOCTLs
@@ -247,6 +259,7 @@
 /* Set Attributes (cache operations) */
 #define BIODASDSATTR   _IOW(DASD_IOCTL_LETTER,2,attrib_data_t) 
 
+#define BIODASDSYMMIO  _IOWR(DASD_IOCTL_LETTER, 240, dasd_symmio_parms_t)
 
 #endif				/* DASD_H */
 
diff --git a/arch/s390/include/asm/delay.h b/arch/s390/include/asm/delay.h
index 7835731..a356c95 100644
--- a/arch/s390/include/asm/delay.h
+++ b/arch/s390/include/asm/delay.h
@@ -15,6 +15,7 @@
 #define _S390_DELAY_H
 
 extern void __udelay(unsigned long usecs);
+extern void udelay_simple(unsigned long usecs);
 extern void __delay(unsigned long loops);
 
 #define udelay(n) __udelay(n)
diff --git a/arch/s390/include/asm/pgtable.h b/arch/s390/include/asm/pgtable.h
index 0bdb704..1a928f8 100644
--- a/arch/s390/include/asm/pgtable.h
+++ b/arch/s390/include/asm/pgtable.h
@@ -281,6 +281,9 @@
 #define RCP_GR_BIT	50
 #define RCP_GC_BIT	49
 
+/* User dirty bit for KVM's migration feature */
+#define KVM_UD_BIT	47
+
 #ifndef __s390x__
 
 /* Bits in the segment table address-space-control-element */
@@ -575,12 +578,16 @@
 	unsigned long *pgste = (unsigned long *) (ptep + PTRS_PER_PTE);
 
 	skey = page_get_storage_key(page_to_phys(page));
-	if (skey & _PAGE_CHANGED)
+	if (skey & _PAGE_CHANGED) {
 		set_bit_simple(RCP_GC_BIT, pgste);
+		set_bit_simple(KVM_UD_BIT, pgste);
+	}
 	if (skey & _PAGE_REFERENCED)
 		set_bit_simple(RCP_GR_BIT, pgste);
-	if (test_and_clear_bit_simple(RCP_HC_BIT, pgste))
+	if (test_and_clear_bit_simple(RCP_HC_BIT, pgste)) {
 		SetPageDirty(page);
+		set_bit_simple(KVM_UD_BIT, pgste);
+	}
 	if (test_and_clear_bit_simple(RCP_HR_BIT, pgste))
 		SetPageReferenced(page);
 #endif
@@ -744,6 +751,40 @@
 	return pte;
 }
 
+#ifdef CONFIG_PGSTE
+/*
+ * Get (and clear) the user dirty bit for a PTE.
+ */
+static inline int kvm_s390_test_and_clear_page_dirty(struct mm_struct *mm,
+						     pte_t *ptep)
+{
+	int dirty;
+	unsigned long *pgste;
+	struct page *page;
+	unsigned int skey;
+
+	if (!mm->context.pgstes)
+		return -EINVAL;
+	rcp_lock(ptep);
+	pgste = (unsigned long *) (ptep + PTRS_PER_PTE);
+	page = virt_to_page(pte_val(*ptep));
+	skey = page_get_storage_key(page_to_phys(page));
+	if (skey & _PAGE_CHANGED) {
+		set_bit_simple(RCP_GC_BIT, pgste);
+		set_bit_simple(KVM_UD_BIT, pgste);
+	}
+	if (test_and_clear_bit_simple(RCP_HC_BIT, pgste)) {
+		SetPageDirty(page);
+		set_bit_simple(KVM_UD_BIT, pgste);
+	}
+	dirty = test_and_clear_bit_simple(KVM_UD_BIT, pgste);
+	if (skey & _PAGE_CHANGED)
+		page_clear_dirty(page);
+	rcp_unlock(ptep);
+	return dirty;
+}
+#endif
+
 #define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG
 static inline int ptep_test_and_clear_young(struct vm_area_struct *vma,
 					    unsigned long addr, pte_t *ptep)
diff --git a/arch/s390/include/asm/ptrace.h b/arch/s390/include/asm/ptrace.h
index af2c9ac..a7226f8 100644
--- a/arch/s390/include/asm/ptrace.h
+++ b/arch/s390/include/asm/ptrace.h
@@ -490,6 +490,7 @@
 
 #define user_mode(regs) (((regs)->psw.mask & PSW_MASK_PSTATE) != 0)
 #define instruction_pointer(regs) ((regs)->psw.addr & PSW_ADDR_INSN)
+#define user_stack_pointer(regs)((regs)->gprs[15])
 #define regs_return_value(regs)((regs)->gprs[2])
 #define profile_pc(regs) instruction_pointer(regs)
 extern void show_regs(struct pt_regs * regs);
diff --git a/arch/s390/include/asm/qdio.h b/arch/s390/include/asm/qdio.h
index 6813772..4734c3f 100644
--- a/arch/s390/include/asm/qdio.h
+++ b/arch/s390/include/asm/qdio.h
@@ -299,7 +299,13 @@
 	u8 mbccnt;
 	u16 qdioac2;
 	u64 sch_token;
-	u64:64;
+	u8 mro;
+	u8 mri;
+	u8:8;
+	u8 sbalic;
+	u16:16;
+	u8:8;
+	u8 mmwc;
 } __attribute__ ((packed));
 
 /* params are: ccw_device, qdio_error, queue_number,
diff --git a/arch/s390/include/asm/statfs.h b/arch/s390/include/asm/statfs.h
index 099a455..06cc703 100644
--- a/arch/s390/include/asm/statfs.h
+++ b/arch/s390/include/asm/statfs.h
@@ -12,19 +12,16 @@
 #ifndef __s390x__
 #include <asm-generic/statfs.h>
 #else
+/*
+ * We can't use <asm-generic/statfs.h> because in 64-bit mode
+ * we mix ints of different sizes in our struct statfs.
+ */
 
 #ifndef __KERNEL_STRICT_NAMES
-
 #include <linux/types.h>
-
 typedef __kernel_fsid_t	fsid_t;
-
 #endif
 
-/*
- * This is ugly -- we're already 64-bit clean, so just duplicate the 
- * definitions.
- */
 struct statfs {
 	int  f_type;
 	int  f_bsize;
diff --git a/arch/s390/include/asm/syscall.h b/arch/s390/include/asm/syscall.h
new file mode 100644
index 0000000..6e62397
--- /dev/null
+++ b/arch/s390/include/asm/syscall.h
@@ -0,0 +1,80 @@
+/*
+ * Access to user system call parameters and results
+ *
+ *  Copyright IBM Corp. 2008
+ *  Author(s): Martin Schwidefsky (schwidefsky@de.ibm.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 only)
+ * as published by the Free Software Foundation.
+ */
+
+#ifndef _ASM_SYSCALL_H
+#define _ASM_SYSCALL_H	1
+
+#include <asm/ptrace.h>
+
+static inline long syscall_get_nr(struct task_struct *task,
+				  struct pt_regs *regs)
+{
+	if (regs->trap != __LC_SVC_OLD_PSW)
+		return -1;
+	return regs->gprs[2];
+}
+
+static inline void syscall_rollback(struct task_struct *task,
+				    struct pt_regs *regs)
+{
+	regs->gprs[2] = regs->orig_gpr2;
+}
+
+static inline long syscall_get_error(struct task_struct *task,
+				     struct pt_regs *regs)
+{
+	return (regs->gprs[2] >= -4096UL) ? -regs->gprs[2] : 0;
+}
+
+static inline long syscall_get_return_value(struct task_struct *task,
+					    struct pt_regs *regs)
+{
+	return regs->gprs[2];
+}
+
+static inline void syscall_set_return_value(struct task_struct *task,
+					    struct pt_regs *regs,
+					    int error, long val)
+{
+	regs->gprs[2] = error ? -error : val;
+}
+
+static inline void syscall_get_arguments(struct task_struct *task,
+					 struct pt_regs *regs,
+					 unsigned int i, unsigned int n,
+					 unsigned long *args)
+{
+	BUG_ON(i + n > 6);
+#ifdef CONFIG_COMPAT
+	if (test_tsk_thread_flag(task, TIF_31BIT)) {
+		if (i + n == 6)
+			args[--n] = (u32) regs->args[0];
+		while (n-- > 0)
+			args[n] = (u32) regs->gprs[2 + i + n];
+	}
+#endif
+	if (i + n == 6)
+		args[--n] = regs->args[0];
+	memcpy(args, &regs->gprs[2 + i], n * sizeof(args[0]));
+}
+
+static inline void syscall_set_arguments(struct task_struct *task,
+					 struct pt_regs *regs,
+					 unsigned int i, unsigned int n,
+					 const unsigned long *args)
+{
+	BUG_ON(i + n > 6);
+	if (i + n == 6)
+		regs->args[0] = args[--n];
+	memcpy(&regs->gprs[2 + i], args, n * sizeof(args[0]));
+}
+
+#endif	/* _ASM_SYSCALL_H */
diff --git a/arch/s390/include/asm/thread_info.h b/arch/s390/include/asm/thread_info.h
index 91a8f93..ea40a9d 100644
--- a/arch/s390/include/asm/thread_info.h
+++ b/arch/s390/include/asm/thread_info.h
@@ -86,6 +86,7 @@
  * thread information flags bit numbers
  */
 #define TIF_SYSCALL_TRACE	0	/* syscall trace active */
+#define TIF_NOTIFY_RESUME	1	/* callback before returning to user */
 #define TIF_SIGPENDING		2	/* signal pending */
 #define TIF_NEED_RESCHED	3	/* rescheduling necessary */
 #define TIF_RESTART_SVC		4	/* restart svc with new svc number */
@@ -100,6 +101,7 @@
 #define TIF_RESTORE_SIGMASK	20	/* restore signal mask in do_signal() */
 
 #define _TIF_SYSCALL_TRACE	(1<<TIF_SYSCALL_TRACE)
+#define _TIF_NOTIFY_RESUME	(1<<TIF_NOTIFY_RESUME)
 #define _TIF_RESTORE_SIGMASK	(1<<TIF_RESTORE_SIGMASK)
 #define _TIF_SIGPENDING		(1<<TIF_SIGPENDING)
 #define _TIF_NEED_RESCHED	(1<<TIF_NEED_RESCHED)
diff --git a/arch/s390/kernel/compat_linux.c b/arch/s390/kernel/compat_linux.c
index d7f2222..98e246d 100644
--- a/arch/s390/kernel/compat_linux.c
+++ b/arch/s390/kernel/compat_linux.c
@@ -608,14 +608,6 @@
 	return do_sys_settimeofday(tv ? &kts : NULL, tz ? &ktz : NULL);
 }
 
-/* These are here just in case some old sparc32 binary calls it. */
-asmlinkage long sys32_pause(void)
-{
-	current->state = TASK_INTERRUPTIBLE;
-	schedule();
-	return -ERESTARTNOHAND;
-}
-
 asmlinkage long sys32_pread64(unsigned int fd, char __user *ubuf,
 				size_t count, u32 poshi, u32 poslo)
 {
diff --git a/arch/s390/kernel/compat_linux.h b/arch/s390/kernel/compat_linux.h
index 20723a0..05f8516 100644
--- a/arch/s390/kernel/compat_linux.h
+++ b/arch/s390/kernel/compat_linux.h
@@ -206,7 +206,6 @@
 			struct timezone __user *tz);
 long sys32_settimeofday(struct compat_timeval __user *tv,
 			struct timezone __user *tz);
-long sys32_pause(void);
 long sys32_pread64(unsigned int fd, char __user *ubuf, size_t count,
 		   u32 poshi, u32 poslo);
 long sys32_pwrite64(unsigned int fd, const char __user *ubuf,
diff --git a/arch/s390/kernel/compat_wrapper.S b/arch/s390/kernel/compat_wrapper.S
index 328a20e..ee51ca9 100644
--- a/arch/s390/kernel/compat_wrapper.S
+++ b/arch/s390/kernel/compat_wrapper.S
@@ -128,8 +128,6 @@
 	llgfr	%r2,%r2			# unsigned int
 	jg	sys_alarm		# branch to system call
 
-#sys32_pause_wrapper			# void
-
 	.globl	compat_sys_utime_wrapper
 compat_sys_utime_wrapper:
 	llgtr	%r2,%r2			# char *
diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S
index 708cf9c..ed500ef 100644
--- a/arch/s390/kernel/entry.S
+++ b/arch/s390/kernel/entry.S
@@ -49,9 +49,9 @@
 SP_TRAP      =	STACK_FRAME_OVERHEAD + __PT_TRAP
 SP_SIZE      =	STACK_FRAME_OVERHEAD + __PT_SIZE
 
-_TIF_WORK_SVC = (_TIF_SIGPENDING | _TIF_NEED_RESCHED | \
+_TIF_WORK_SVC = (_TIF_SIGPENDING | _TIF_NOTIFY_RESUME | _TIF_NEED_RESCHED | \
 		 _TIF_MCCK_PENDING | _TIF_RESTART_SVC | _TIF_SINGLE_STEP )
-_TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_NEED_RESCHED | \
+_TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_NOTIFY_RESUME | _TIF_NEED_RESCHED | \
 		 _TIF_MCCK_PENDING)
 
 STACK_SHIFT = PAGE_SHIFT + THREAD_ORDER
@@ -318,6 +318,8 @@
 	bo	BASED(sysc_reschedule)
 	tm	__TI_flags+3(%r9),_TIF_SIGPENDING
 	bnz	BASED(sysc_sigpending)
+	tm	__TI_flags+3(%r9),_TIF_NOTIFY_RESUME
+	bnz	BASED(sysc_notify_resume)
 	tm	__TI_flags+3(%r9),_TIF_RESTART_SVC
 	bo	BASED(sysc_restart)
 	tm	__TI_flags+3(%r9),_TIF_SINGLE_STEP
@@ -356,6 +358,16 @@
 	b	BASED(sysc_work_loop)
 
 #
+# _TIF_NOTIFY_RESUME is set, call do_notify_resume
+#
+sysc_notify_resume:
+	la	%r2,SP_PTREGS(%r15)	# load pt_regs
+	l	%r1,BASED(.Ldo_notify_resume)
+	la	%r14,BASED(sysc_work_loop)
+	br	%r1			# call do_notify_resume
+
+
+#
 # _TIF_RESTART_SVC is set, set up registers and restart svc
 #
 sysc_restart:
@@ -378,20 +390,21 @@
 	br	%r1			# branch to do_single_step
 
 #
-# call trace before and after sys_call
+# call tracehook_report_syscall_entry/tracehook_report_syscall_exit before
+# and after the system call
 #
 sysc_tracesys:
-	l	%r1,BASED(.Ltrace)
+	l	%r1,BASED(.Ltrace_entry)
 	la	%r2,SP_PTREGS(%r15)	# load pt_regs
 	la	%r3,0
 	srl	%r7,2
 	st	%r7,SP_R2(%r15)
 	basr	%r14,%r1
-	clc	SP_R2(4,%r15),BASED(.Lnr_syscalls)
+	cl	%r2,BASED(.Lnr_syscalls)
 	bnl	BASED(sysc_tracenogo)
 	l	%r8,BASED(.Lsysc_table)
-	l	%r7,SP_R2(%r15) 	# strace might have changed the
-	sll	%r7,2			#  system call
+	lr	%r7,%r2
+	sll	%r7,2			# *4
 	l	%r8,0(%r7,%r8)
 sysc_tracego:
 	lm	%r3,%r6,SP_R3(%r15)
@@ -401,9 +414,8 @@
 sysc_tracenogo:
 	tm	__TI_flags+3(%r9),(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT)
 	bz	BASED(sysc_return)
-	l	%r1,BASED(.Ltrace)
+	l	%r1,BASED(.Ltrace_exit)
 	la	%r2,SP_PTREGS(%r15)	# load pt_regs
-	la	%r3,1
 	la	%r14,BASED(sysc_return)
 	br	%r1
 
@@ -666,6 +678,8 @@
 	bo	BASED(io_reschedule)
 	tm	__TI_flags+3(%r9),_TIF_SIGPENDING
 	bnz	BASED(io_sigpending)
+	tm	__TI_flags+3(%r9),_TIF_NOTIFY_RESUME
+	bnz	BASED(io_notify_resume)
 	b	BASED(io_restore)
 io_work_done:
 
@@ -704,6 +718,19 @@
 	TRACE_IRQS_OFF
 	b	BASED(io_work_loop)
 
+#
+# _TIF_SIGPENDING is set, call do_signal
+#
+io_notify_resume:
+	TRACE_IRQS_ON
+	stosm	__SF_EMPTY(%r15),0x03	# reenable interrupts
+	la	%r2,SP_PTREGS(%r15)	# load pt_regs
+	l	%r1,BASED(.Ldo_notify_resume)
+	basr	%r14,%r1		# call do_signal
+	stnsm	__SF_EMPTY(%r15),0xfc	# disable I/O and ext. interrupts
+	TRACE_IRQS_OFF
+	b	BASED(io_work_loop)
+
 /*
  * External interrupt handler routine
  */
@@ -1070,6 +1097,8 @@
 .Ldo_IRQ:	.long	do_IRQ
 .Ldo_extint:	.long	do_extint
 .Ldo_signal:	.long	do_signal
+.Ldo_notify_resume:
+		.long	do_notify_resume
 .Lhandle_per:	.long	do_single_step
 .Ldo_execve:	.long	do_execve
 .Lexecve_tail:	.long	execve_tail
@@ -1079,7 +1108,8 @@
 .Lpreempt_schedule_irq:
 		.long	preempt_schedule_irq
 #endif
-.Ltrace:	.long	syscall_trace
+.Ltrace_entry:	.long	do_syscall_trace_enter
+.Ltrace_exit:	.long	do_syscall_trace_exit
 .Lschedtail:	.long	schedule_tail
 .Lsysc_table:	.long	sys_call_table
 #ifdef CONFIG_TRACE_IRQFLAGS
diff --git a/arch/s390/kernel/entry64.S b/arch/s390/kernel/entry64.S
index fee1017..d7ce150 100644
--- a/arch/s390/kernel/entry64.S
+++ b/arch/s390/kernel/entry64.S
@@ -52,9 +52,9 @@
 STACK_SHIFT = PAGE_SHIFT + THREAD_ORDER
 STACK_SIZE  = 1 << STACK_SHIFT
 
-_TIF_WORK_SVC = (_TIF_SIGPENDING | _TIF_NEED_RESCHED | \
+_TIF_WORK_SVC = (_TIF_SIGPENDING | _TIF_NOTIFY_RESUME | _TIF_NEED_RESCHED | \
 		 _TIF_MCCK_PENDING | _TIF_RESTART_SVC | _TIF_SINGLE_STEP )
-_TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_NEED_RESCHED | \
+_TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_NOTIFY_RESUME | _TIF_NEED_RESCHED | \
 		 _TIF_MCCK_PENDING)
 
 #define BASED(name) name-system_call(%r13)
@@ -310,6 +310,8 @@
 	jo	sysc_reschedule
 	tm	__TI_flags+7(%r9),_TIF_SIGPENDING
 	jnz	sysc_sigpending
+	tm	__TI_flags+7(%r9),_TIF_NOTIFY_RESUME
+	jnz	sysc_notify_resume
 	tm	__TI_flags+7(%r9),_TIF_RESTART_SVC
 	jo	sysc_restart
 	tm	__TI_flags+7(%r9),_TIF_SINGLE_STEP
@@ -345,6 +347,14 @@
 	j	sysc_work_loop
 
 #
+# _TIF_NOTIFY_RESUME is set, call do_notify_resume
+#
+sysc_notify_resume:
+	la	%r2,SP_PTREGS(%r15)	# load pt_regs
+	larl	%r14,sysc_work_loop
+	jg	do_notify_resume	# call do_notify_resume
+
+#
 # _TIF_RESTART_SVC is set, set up registers and restart svc
 #
 sysc_restart:
@@ -367,20 +377,19 @@
 	jg	do_single_step		# branch to do_sigtrap
 
 #
-# call syscall_trace before and after system call
-# special linkage: %r12 contains the return address for trace_svc
+# call tracehook_report_syscall_entry/tracehook_report_syscall_exit before
+# and after the system call
 #
 sysc_tracesys:
 	la	%r2,SP_PTREGS(%r15)	# load pt_regs
 	la	%r3,0
 	srl	%r7,2
 	stg	%r7,SP_R2(%r15)
-	brasl	%r14,syscall_trace
+	brasl	%r14,do_syscall_trace_enter
 	lghi	%r0,NR_syscalls
-	clg	%r0,SP_R2(%r15)
+	clgr	%r0,%r2
 	jnh	sysc_tracenogo
-	lg	%r7,SP_R2(%r15)		# strace might have changed the
-	sll	%r7,2			# system call
+	slag	%r7,%r2,2		# *4
 	lgf	%r8,0(%r7,%r10)
 sysc_tracego:
 	lmg	%r3,%r6,SP_R3(%r15)
@@ -391,9 +400,8 @@
 	tm	__TI_flags+7(%r9),(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT)
 	jz	sysc_return
 	la	%r2,SP_PTREGS(%r15)	# load pt_regs
-	la	%r3,1
 	larl	%r14,sysc_return	# return point is sysc_return
-	jg	syscall_trace
+	jg	do_syscall_trace_exit
 
 #
 # a new process exits the kernel with ret_from_fork
@@ -672,6 +680,8 @@
 	jo	io_reschedule
 	tm	__TI_flags+7(%r9),_TIF_SIGPENDING
 	jnz	io_sigpending
+	tm	__TI_flags+7(%r9),_TIF_NOTIFY_RESUME
+	jnz	io_notify_resume
 	j	io_restore
 io_work_done:
 
@@ -712,6 +722,18 @@
 	TRACE_IRQS_OFF
 	j	io_work_loop
 
+#
+# _TIF_NOTIFY_RESUME or is set, call do_notify_resume
+#
+io_notify_resume:
+	TRACE_IRQS_ON
+	stosm	__SF_EMPTY(%r15),0x03	# reenable interrupts
+	la	%r2,SP_PTREGS(%r15)	# load pt_regs
+	brasl	%r14,do_notify_resume	# call do_notify_resume
+	stnsm	__SF_EMPTY(%r15),0xfc	# disable I/O and ext. interrupts
+	TRACE_IRQS_OFF
+	j	io_work_loop
+
 /*
  * External interrupt handler routine
  */
diff --git a/arch/s390/kernel/ptrace.c b/arch/s390/kernel/ptrace.c
index c8b0828..1f31be1 100644
--- a/arch/s390/kernel/ptrace.c
+++ b/arch/s390/kernel/ptrace.c
@@ -35,6 +35,7 @@
 #include <linux/signal.h>
 #include <linux/elf.h>
 #include <linux/regset.h>
+#include <linux/tracehook.h>
 
 #include <asm/segment.h>
 #include <asm/page.h>
@@ -639,40 +640,44 @@
 }
 #endif
 
-asmlinkage void
-syscall_trace(struct pt_regs *regs, int entryexit)
+asmlinkage long do_syscall_trace_enter(struct pt_regs *regs)
 {
-	if (unlikely(current->audit_context) && entryexit)
-		audit_syscall_exit(AUDITSC_RESULT(regs->gprs[2]), regs->gprs[2]);
-
-	if (!test_thread_flag(TIF_SYSCALL_TRACE))
-		goto out;
-	if (!(current->ptrace & PT_PTRACED))
-		goto out;
-	ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
-				 ? 0x80 : 0));
+	long ret;
 
 	/*
-	 * If the debuffer has set an invalid system call number,
-	 * we prepare to skip the system call restart handling.
+	 * The sysc_tracesys code in entry.S stored the system
+	 * call number to gprs[2].
 	 */
-	if (!entryexit && regs->gprs[2] >= NR_syscalls)
+	ret = regs->gprs[2];
+	if (test_thread_flag(TIF_SYSCALL_TRACE) &&
+	    (tracehook_report_syscall_entry(regs) ||
+	     regs->gprs[2] >= NR_syscalls)) {
+		/*
+		 * Tracing decided this syscall should not happen or the
+		 * debugger stored an invalid system call number. Skip
+		 * the system call and the system call restart handling.
+		 */
 		regs->trap = -1;
-
-	/*
-	 * this isn't the same as continuing with a signal, but it will do
-	 * for normal use.  strace only continues with a signal if the
-	 * stopping signal is not SIGTRAP.  -brl
-	 */
-	if (current->exit_code) {
-		send_sig(current->exit_code, current, 1);
-		current->exit_code = 0;
+		ret = -1;
 	}
- out:
-	if (unlikely(current->audit_context) && !entryexit)
-		audit_syscall_entry(test_thread_flag(TIF_31BIT)?AUDIT_ARCH_S390:AUDIT_ARCH_S390X,
-				    regs->gprs[2], regs->orig_gpr2, regs->gprs[3],
-				    regs->gprs[4], regs->gprs[5]);
+
+	if (unlikely(current->audit_context))
+		audit_syscall_entry(test_thread_flag(TIF_31BIT) ?
+					AUDIT_ARCH_S390 : AUDIT_ARCH_S390X,
+				    regs->gprs[2], regs->orig_gpr2,
+				    regs->gprs[3], regs->gprs[4],
+				    regs->gprs[5]);
+	return ret;
+}
+
+asmlinkage void do_syscall_trace_exit(struct pt_regs *regs)
+{
+	if (unlikely(current->audit_context))
+		audit_syscall_exit(AUDITSC_RESULT(regs->gprs[2]),
+				   regs->gprs[2]);
+
+	if (test_thread_flag(TIF_SYSCALL_TRACE))
+		tracehook_report_syscall_exit(regs, 0);
 }
 
 /*
diff --git a/arch/s390/kernel/signal.c b/arch/s390/kernel/signal.c
index b976820..4f7fc30 100644
--- a/arch/s390/kernel/signal.c
+++ b/arch/s390/kernel/signal.c
@@ -24,6 +24,7 @@
 #include <linux/tty.h>
 #include <linux/personality.h>
 #include <linux/binfmts.h>
+#include <linux/tracehook.h>
 #include <asm/ucontext.h>
 #include <asm/uaccess.h>
 #include <asm/lowcore.h>
@@ -507,6 +508,12 @@
 			 */
 			if (current->thread.per_info.single_step)
 				set_thread_flag(TIF_SINGLE_STEP);
+
+			/*
+			 * Let tracing know that we've done the handler setup.
+			 */
+			tracehook_signal_handler(signr, &info, &ka, regs,
+					 test_thread_flag(TIF_SINGLE_STEP));
 		}
 		return;
 	}
@@ -526,3 +533,9 @@
 		set_thread_flag(TIF_RESTART_SVC);
 	}
 }
+
+void do_notify_resume(struct pt_regs *regs)
+{
+	clear_thread_flag(TIF_NOTIFY_RESUME);
+	tracehook_notify_resume(regs);
+}
diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c
index 00b9b4d..9e8b1f9 100644
--- a/arch/s390/kernel/smp.c
+++ b/arch/s390/kernel/smp.c
@@ -585,6 +585,8 @@
 	/* Enable pfault pseudo page faults on this cpu. */
 	pfault_init();
 
+	/* call cpu notifiers */
+	notify_cpu_starting(smp_processor_id());
 	/* Mark this cpu as online */
 	spin_lock(&call_lock);
 	cpu_set(smp_processor_id(), cpu_online_map);
diff --git a/arch/s390/kernel/syscalls.S b/arch/s390/kernel/syscalls.S
index c66d35e..3ae3039 100644
--- a/arch/s390/kernel/syscalls.S
+++ b/arch/s390/kernel/syscalls.S
@@ -37,7 +37,7 @@
 SYSCALL(sys_ptrace,sys_ptrace,sys32_ptrace_wrapper)
 SYSCALL(sys_alarm,sys_alarm,sys32_alarm_wrapper)
 NI_SYSCALL							/* old fstat syscall */
-SYSCALL(sys_pause,sys_pause,sys32_pause)
+SYSCALL(sys_pause,sys_pause,sys_pause)
 SYSCALL(sys_utime,sys_utime,compat_sys_utime_wrapper)		/* 30 */
 NI_SYSCALL							/* old stty syscall */
 NI_SYSCALL							/* old gtty syscall */
diff --git a/arch/s390/kernel/time.c b/arch/s390/kernel/time.c
index ca114fe..b94e9e3 100644
--- a/arch/s390/kernel/time.c
+++ b/arch/s390/kernel/time.c
@@ -169,6 +169,8 @@
 
 static void clock_comparator_interrupt(__u16 code)
 {
+	if (S390_lowcore.clock_comparator == -1ULL)
+		set_clock_comparator(S390_lowcore.clock_comparator);
 }
 
 static void etr_timing_alert(struct etr_irq_parm *);
@@ -1354,7 +1356,7 @@
 
 	stp_page = alloc_bootmem_pages(PAGE_SIZE);
 	rc = chsc_sstpc(stp_page, STP_OP_CTRL, 0x0000);
-	if (rc == 1)
+	if (rc == 0)
 		set_bit(CLOCK_SYNC_HAS_STP, &clock_sync_flags);
 	else if (stp_online) {
 		printk(KERN_WARNING "Running on non STP capable machine.\n");
diff --git a/arch/s390/lib/delay.c b/arch/s390/lib/delay.c
index fc6ab60..6ccb9fa 100644
--- a/arch/s390/lib/delay.c
+++ b/arch/s390/lib/delay.c
@@ -1,14 +1,9 @@
 /*
- *  arch/s390/lib/delay.c
  *    Precise Delay Loops for S390
  *
- *  S390 version
- *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
- *    Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
- *
- *  Derived from "arch/i386/lib/delay.c"
- *    Copyright (C) 1993 Linus Torvalds
- *    Copyright (C) 1997 Martin Mares <mj@atrey.karlin.mff.cuni.cz>
+ *    Copyright IBM Corp. 1999,2008
+ *    Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>,
+ *		 Heiko Carstens <heiko.carstens@de.ibm.com>,
  */
 
 #include <linux/sched.h>
@@ -29,30 +24,31 @@
 	asm volatile("0: brct %0,0b" : : "d" ((loops/2) + 1));
 }
 
-/*
- * Waits for 'usecs' microseconds using the TOD clock comparator.
- */
-void __udelay(unsigned long usecs)
+static void __udelay_disabled(unsigned long usecs)
 {
-	u64 end, time, old_cc = 0;
-	unsigned long flags, cr0, mask, dummy;
-	int irq_context;
+	unsigned long mask, cr0, cr0_saved;
+	u64 clock_saved;
 
-	irq_context = in_interrupt();
-	if (!irq_context)
-		local_bh_disable();
-	local_irq_save(flags);
-	if (raw_irqs_disabled_flags(flags)) {
-		old_cc = local_tick_disable();
-		S390_lowcore.clock_comparator = -1ULL;
-		__ctl_store(cr0, 0, 0);
-		dummy = (cr0 & 0xffff00e0) | 0x00000800;
-		__ctl_load(dummy , 0, 0);
-		mask = psw_kernel_bits | PSW_MASK_WAIT | PSW_MASK_EXT;
-	} else
-		mask = psw_kernel_bits | PSW_MASK_WAIT |
-			PSW_MASK_EXT | PSW_MASK_IO;
+	clock_saved = local_tick_disable();
+	set_clock_comparator(get_clock() + ((u64) usecs << 12));
+	__ctl_store(cr0_saved, 0, 0);
+	cr0 = (cr0_saved & 0xffff00e0) | 0x00000800;
+	__ctl_load(cr0 , 0, 0);
+	mask = psw_kernel_bits | PSW_MASK_WAIT | PSW_MASK_EXT;
+	trace_hardirqs_on();
+	__load_psw_mask(mask);
+	local_irq_disable();
+	__ctl_load(cr0_saved, 0, 0);
+	local_tick_enable(clock_saved);
+	set_clock_comparator(S390_lowcore.clock_comparator);
+}
 
+static void __udelay_enabled(unsigned long usecs)
+{
+	unsigned long mask;
+	u64 end, time;
+
+	mask = psw_kernel_bits | PSW_MASK_WAIT | PSW_MASK_EXT | PSW_MASK_IO;
 	end = get_clock() + ((u64) usecs << 12);
 	do {
 		time = end < S390_lowcore.clock_comparator ?
@@ -62,13 +58,50 @@
 		__load_psw_mask(mask);
 		local_irq_disable();
 	} while (get_clock() < end);
-
-	if (raw_irqs_disabled_flags(flags)) {
-		__ctl_load(cr0, 0, 0);
-		local_tick_enable(old_cc);
-	}
-	if (!irq_context)
-		_local_bh_enable();
 	set_clock_comparator(S390_lowcore.clock_comparator);
+}
+
+/*
+ * Waits for 'usecs' microseconds using the TOD clock comparator.
+ */
+void __udelay(unsigned long usecs)
+{
+	unsigned long flags;
+
+	preempt_disable();
+	local_irq_save(flags);
+	if (in_irq()) {
+		__udelay_disabled(usecs);
+		goto out;
+	}
+	if (in_softirq()) {
+		if (raw_irqs_disabled_flags(flags))
+			__udelay_disabled(usecs);
+		else
+			__udelay_enabled(usecs);
+		goto out;
+	}
+	if (raw_irqs_disabled_flags(flags)) {
+		local_bh_disable();
+		__udelay_disabled(usecs);
+		_local_bh_enable();
+		goto out;
+	}
+	__udelay_enabled(usecs);
+out:
 	local_irq_restore(flags);
+	preempt_enable();
+}
+
+/*
+ * Simple udelay variant. To be used on startup and reboot
+ * when the interrupt handler isn't working.
+ */
+void udelay_simple(unsigned long usecs)
+{
+	u64 end;
+
+	end = get_clock() + ((u64) usecs << 12);
+	while (get_clock() < end)
+		cpu_relax();
 }
diff --git a/arch/s390/mm/extmem.c b/arch/s390/mm/extmem.c
index f231f5e..580fc64 100644
--- a/arch/s390/mm/extmem.c
+++ b/arch/s390/mm/extmem.c
@@ -43,21 +43,41 @@
 #define DCSS_FINDSEG    0x0c
 #define DCSS_LOADNOLY   0x10
 #define DCSS_SEGEXT     0x18
+#define DCSS_LOADSHRX	0x20
+#define DCSS_LOADNSRX	0x24
+#define DCSS_FINDSEGX	0x2c
+#define DCSS_SEGEXTX	0x38
 #define DCSS_FINDSEGA   0x0c
 
 struct qrange {
-	unsigned int  start; // 3byte start address, 1 byte type
-	unsigned int  end;   // 3byte end address, 1 byte reserved
+	unsigned long  start; /* last byte type */
+	unsigned long  end;   /* last byte reserved */
 };
 
 struct qout64 {
-	int segstart;
-	int segend;
+	unsigned long segstart;
+	unsigned long segend;
 	int segcnt;
 	int segrcnt;
 	struct qrange range[6];
 };
 
+#ifdef CONFIG_64BIT
+struct qrange_old {
+	unsigned int start; /* last byte type */
+	unsigned int end;   /* last byte reserved */
+};
+
+/* output area format for the Diag x'64' old subcode x'18' */
+struct qout64_old {
+	int segstart;
+	int segend;
+	int segcnt;
+	int segrcnt;
+	struct qrange_old range[6];
+};
+#endif
+
 struct qin64 {
 	char qopcode;
 	char rsrv1[3];
@@ -86,6 +106,55 @@
 static LIST_HEAD(dcss_list);
 static char *segtype_string[] = { "SW", "EW", "SR", "ER", "SN", "EN", "SC",
 					"EW/EN-MIXED" };
+static int loadshr_scode, loadnsr_scode, findseg_scode;
+static int segext_scode, purgeseg_scode;
+static int scode_set;
+
+/* set correct Diag x'64' subcodes. */
+static int
+dcss_set_subcodes(void)
+{
+#ifdef CONFIG_64BIT
+	char *name = kmalloc(8 * sizeof(char), GFP_DMA);
+	unsigned long rx, ry;
+	int rc;
+
+	if (name == NULL)
+		return -ENOMEM;
+
+	rx = (unsigned long) name;
+	ry = DCSS_FINDSEGX;
+
+	strcpy(name, "dummy");
+	asm volatile(
+		"	diag	%0,%1,0x64\n"
+		"0:	ipm	%2\n"
+		"	srl	%2,28\n"
+		"	j	2f\n"
+		"1:	la	%2,3\n"
+		"2:\n"
+		EX_TABLE(0b, 1b)
+		: "+d" (rx), "+d" (ry), "=d" (rc) : : "cc");
+
+	kfree(name);
+	/* Diag x'64' new subcodes are supported, set to new subcodes */
+	if (rc != 3) {
+		loadshr_scode = DCSS_LOADSHRX;
+		loadnsr_scode = DCSS_LOADNSRX;
+		purgeseg_scode = DCSS_PURGESEG;
+		findseg_scode = DCSS_FINDSEGX;
+		segext_scode = DCSS_SEGEXTX;
+		return 0;
+	}
+#endif
+	/* Diag x'64' new subcodes are not supported, set to old subcodes */
+	loadshr_scode = DCSS_LOADNOLY;
+	loadnsr_scode = DCSS_LOADNSR;
+	purgeseg_scode = DCSS_PURGESEG;
+	findseg_scode = DCSS_FINDSEG;
+	segext_scode = DCSS_SEGEXT;
+	return 0;
+}
 
 /*
  * Create the 8 bytes, ebcdic VM segment name from
@@ -135,25 +204,45 @@
  * Perform a function on a dcss segment.
  */
 static inline int
-dcss_diag (__u8 func, void *parameter,
+dcss_diag(int *func, void *parameter,
            unsigned long *ret1, unsigned long *ret2)
 {
 	unsigned long rx, ry;
 	int rc;
 
+	if (scode_set == 0) {
+		rc = dcss_set_subcodes();
+		if (rc < 0)
+			return rc;
+		scode_set = 1;
+	}
 	rx = (unsigned long) parameter;
-	ry = (unsigned long) func;
-	asm volatile(
+	ry = (unsigned long) *func;
+
 #ifdef CONFIG_64BIT
-		"	sam31\n"
-		"	diag	%0,%1,0x64\n"
-		"	sam64\n"
+	/* 64-bit Diag x'64' new subcode, keep in 64-bit addressing mode */
+	if (*func > DCSS_SEGEXT)
+		asm volatile(
+			"	diag	%0,%1,0x64\n"
+			"	ipm	%2\n"
+			"	srl	%2,28\n"
+			: "+d" (rx), "+d" (ry), "=d" (rc) : : "cc");
+	/* 31-bit Diag x'64' old subcode, switch to 31-bit addressing mode */
+	else
+		asm volatile(
+			"	sam31\n"
+			"	diag	%0,%1,0x64\n"
+			"	sam64\n"
+			"	ipm	%2\n"
+			"	srl	%2,28\n"
+			: "+d" (rx), "+d" (ry), "=d" (rc) : : "cc");
 #else
+	asm volatile(
 		"	diag	%0,%1,0x64\n"
-#endif
 		"	ipm	%2\n"
 		"	srl	%2,28\n"
 		: "+d" (rx), "+d" (ry), "=d" (rc) : : "cc");
+#endif
 	*ret1 = rx;
 	*ret2 = ry;
 	return rc;
@@ -190,14 +279,45 @@
 	qin->qoutlen = sizeof(struct qout64);
 	memcpy (qin->qname, seg->dcss_name, 8);
 
-	diag_cc = dcss_diag (DCSS_SEGEXT, qin, &dummy, &vmrc);
+	diag_cc = dcss_diag(&segext_scode, qin, &dummy, &vmrc);
 
+	if (diag_cc < 0) {
+		rc = diag_cc;
+		goto out_free;
+	}
 	if (diag_cc > 1) {
 		PRINT_WARN ("segment_type: diag returned error %ld\n", vmrc);
 		rc = dcss_diag_translate_rc (vmrc);
 		goto out_free;
 	}
 
+#ifdef CONFIG_64BIT
+	/* Only old format of output area of Diagnose x'64' is supported,
+	   copy data for the new format. */
+	if (segext_scode == DCSS_SEGEXT) {
+		struct qout64_old *qout_old;
+		qout_old = kzalloc(sizeof(struct qout64_old), GFP_DMA);
+		if (qout_old == NULL) {
+			rc = -ENOMEM;
+			goto out_free;
+		}
+		memcpy(qout_old, qout, sizeof(struct qout64_old));
+		qout->segstart = (unsigned long) qout_old->segstart;
+		qout->segend = (unsigned long) qout_old->segend;
+		qout->segcnt = qout_old->segcnt;
+		qout->segrcnt = qout_old->segrcnt;
+
+		if (qout->segcnt > 6)
+			qout->segrcnt = 6;
+		for (i = 0; i < qout->segrcnt; i++) {
+			qout->range[i].start =
+				(unsigned long) qout_old->range[i].start;
+			qout->range[i].end =
+				(unsigned long) qout_old->range[i].end;
+		}
+		kfree(qout_old);
+	}
+#endif
 	if (qout->segcnt > 6) {
 		rc = -ENOTSUPP;
 		goto out_free;
@@ -269,6 +389,30 @@
 }
 
 /*
+ * check if segment collides with other segments that are currently loaded
+ * returns 1 if this is the case, 0 if no collision was found
+ */
+static int
+segment_overlaps_others (struct dcss_segment *seg)
+{
+	struct list_head *l;
+	struct dcss_segment *tmp;
+
+	BUG_ON(!mutex_is_locked(&dcss_lock));
+	list_for_each(l, &dcss_list) {
+		tmp = list_entry(l, struct dcss_segment, list);
+		if ((tmp->start_addr >> 20) > (seg->end >> 20))
+			continue;
+		if ((tmp->end >> 20) < (seg->start_addr >> 20))
+			continue;
+		if (seg == tmp)
+			continue;
+		return 1;
+	}
+	return 0;
+}
+
+/*
  * real segment loading function, called from segment_load
  */
 static int
@@ -276,7 +420,8 @@
 {
 	struct dcss_segment *seg = kmalloc(sizeof(struct dcss_segment),
 			GFP_DMA);
-	int dcss_command, rc, diag_cc;
+	int rc, diag_cc;
+	unsigned long start_addr, end_addr, dummy;
 
 	if (seg == NULL) {
 		rc = -ENOMEM;
@@ -287,6 +432,13 @@
 	if (rc < 0)
 		goto out_free;
 
+	if (loadshr_scode == DCSS_LOADSHRX) {
+		if (segment_overlaps_others(seg)) {
+			rc = -EBUSY;
+			goto out_free;
+		}
+	}
+
 	rc = vmem_add_mapping(seg->start_addr, seg->end - seg->start_addr + 1);
 
 	if (rc)
@@ -316,20 +468,28 @@
 	}
 
 	if (do_nonshared)
-		dcss_command = DCSS_LOADNSR;
+		diag_cc = dcss_diag(&loadnsr_scode, seg->dcss_name,
+				&start_addr, &end_addr);
 	else
-		dcss_command = DCSS_LOADNOLY;
-
-	diag_cc = dcss_diag(dcss_command, seg->dcss_name,
-			&seg->start_addr, &seg->end);
-	if (diag_cc > 1) {
-		PRINT_WARN ("segment_load: could not load segment %s - "
-				"diag returned error (%ld)\n",name,seg->end);
-		rc = dcss_diag_translate_rc (seg->end);
-		dcss_diag(DCSS_PURGESEG, seg->dcss_name,
-				&seg->start_addr, &seg->end);
+		diag_cc = dcss_diag(&loadshr_scode, seg->dcss_name,
+				&start_addr, &end_addr);
+	if (diag_cc < 0) {
+		dcss_diag(&purgeseg_scode, seg->dcss_name,
+				&dummy, &dummy);
+		rc = diag_cc;
 		goto out_resource;
 	}
+	if (diag_cc > 1) {
+		PRINT_WARN ("segment_load: could not load segment %s - "
+				"diag returned error (%ld)\n",
+				name, end_addr);
+		rc = dcss_diag_translate_rc(end_addr);
+		dcss_diag(&purgeseg_scode, seg->dcss_name,
+				&dummy, &dummy);
+		goto out_resource;
+	}
+	seg->start_addr = start_addr;
+	seg->end = end_addr;
 	seg->do_nonshared = do_nonshared;
 	atomic_set(&seg->ref_count, 1);
 	list_add(&seg->list, &dcss_list);
@@ -423,8 +583,8 @@
 segment_modify_shared (char *name, int do_nonshared)
 {
 	struct dcss_segment *seg;
-	unsigned long dummy;
-	int dcss_command, rc, diag_cc;
+	unsigned long start_addr, end_addr, dummy;
+	int rc, diag_cc;
 
 	mutex_lock(&dcss_lock);
 	seg = segment_by_name (name);
@@ -445,38 +605,51 @@
 		goto out_unlock;
 	}
 	release_resource(seg->res);
-	if (do_nonshared) {
-		dcss_command = DCSS_LOADNSR;
+	if (do_nonshared)
 		seg->res->flags &= ~IORESOURCE_READONLY;
-	} else {
-		dcss_command = DCSS_LOADNOLY;
+	else
 		if (seg->vm_segtype == SEG_TYPE_SR ||
 		    seg->vm_segtype == SEG_TYPE_ER)
 			seg->res->flags |= IORESOURCE_READONLY;
-	}
+
 	if (request_resource(&iomem_resource, seg->res)) {
 		PRINT_WARN("segment_modify_shared: could not reload segment %s"
 			   " - overlapping resources\n", name);
 		rc = -EBUSY;
 		kfree(seg->res);
-		goto out_del;
+		goto out_del_mem;
 	}
-	dcss_diag(DCSS_PURGESEG, seg->dcss_name, &dummy, &dummy);
-	diag_cc = dcss_diag(dcss_command, seg->dcss_name,
-			&seg->start_addr, &seg->end);
+
+	dcss_diag(&purgeseg_scode, seg->dcss_name, &dummy, &dummy);
+	if (do_nonshared)
+		diag_cc = dcss_diag(&loadnsr_scode, seg->dcss_name,
+				&start_addr, &end_addr);
+	else
+		diag_cc = dcss_diag(&loadshr_scode, seg->dcss_name,
+				&start_addr, &end_addr);
+	if (diag_cc < 0) {
+		rc = diag_cc;
+		goto out_del_res;
+	}
 	if (diag_cc > 1) {
 		PRINT_WARN ("segment_modify_shared: could not reload segment %s"
-				" - diag returned error (%ld)\n",name,seg->end);
-		rc = dcss_diag_translate_rc (seg->end);
-		goto out_del;
+				" - diag returned error (%ld)\n",
+				name, end_addr);
+		rc = dcss_diag_translate_rc(end_addr);
+		goto out_del_res;
 	}
+	seg->start_addr = start_addr;
+	seg->end = end_addr;
 	seg->do_nonshared = do_nonshared;
 	rc = 0;
 	goto out_unlock;
- out_del:
+ out_del_res:
+	release_resource(seg->res);
+	kfree(seg->res);
+ out_del_mem:
 	vmem_remove_mapping(seg->start_addr, seg->end - seg->start_addr + 1);
 	list_del(&seg->list);
-	dcss_diag(DCSS_PURGESEG, seg->dcss_name, &dummy, &dummy);
+	dcss_diag(&purgeseg_scode, seg->dcss_name, &dummy, &dummy);
 	kfree(seg);
  out_unlock:
 	mutex_unlock(&dcss_lock);
@@ -510,7 +683,7 @@
 	kfree(seg->res);
 	vmem_remove_mapping(seg->start_addr, seg->end - seg->start_addr + 1);
 	list_del(&seg->list);
-	dcss_diag(DCSS_PURGESEG, seg->dcss_name, &dummy, &dummy);
+	dcss_diag(&purgeseg_scode, seg->dcss_name, &dummy, &dummy);
 	kfree(seg);
 out_unlock:
 	mutex_unlock(&dcss_lock);
@@ -545,7 +718,7 @@
 	endpfn = (seg->end) >> PAGE_SHIFT;
 	sprintf(cmd1, "DEFSEG %s", name);
 	for (i=0; i<seg->segcnt; i++) {
-		sprintf(cmd1+strlen(cmd1), " %X-%X %s",
+		sprintf(cmd1+strlen(cmd1), " %lX-%lX %s",
 			seg->range[i].start >> PAGE_SHIFT,
 			seg->range[i].end >> PAGE_SHIFT,
 			segtype_string[seg->range[i].start & 0xff]);
diff --git a/arch/sh/kernel/smp.c b/arch/sh/kernel/smp.c
index 60c5084..001778f 100644
--- a/arch/sh/kernel/smp.c
+++ b/arch/sh/kernel/smp.c
@@ -82,6 +82,8 @@
 
 	preempt_disable();
 
+	notify_cpu_starting(smp_processor_id());
+
 	local_irq_enable();
 
 	calibrate_delay();
diff --git a/arch/sparc/Kconfig b/arch/sparc/Kconfig
index a214002..97671da 100644
--- a/arch/sparc/Kconfig
+++ b/arch/sparc/Kconfig
@@ -20,6 +20,11 @@
 	bool
 	default y
 
+config GENERIC_GPIO
+	bool
+	help
+	  Generic GPIO API support
+
 config ARCH_NO_VIRT_TO_BUS
 	def_bool y
 
@@ -69,6 +74,9 @@
 	select HAVE_OPROFILE
 	select HAVE_ARCH_KGDB if !SMP
 	select HAVE_ARCH_TRACEHOOK
+	select ARCH_WANT_OPTIONAL_GPIOLIB
+	select RTC_CLASS
+	select RTC_DRV_M48T59
 
 # Identify this as a Sparc32 build
 config SPARC32
@@ -204,17 +212,6 @@
 	  Enable power management and CPU standby features on supported
 	  SPARC platforms.
 
-config SUN4
-	bool "Support for SUN4 machines (disables SUN4[CDM] support)"
-	depends on !SMP
-	default n
-	help
-	  Say Y here if, and only if, your machine is a sun4. Note that
-	  a kernel compiled with this option will run only on sun4.
-	  (And the current version will probably work only on sun4/330.)
-
-if !SUN4
-
 config PCI
 	bool "Support for PCI and PS/2 keyboard/mouse"
 	help
@@ -227,11 +224,6 @@
 
 source "drivers/pci/Kconfig"
 
-endif
-
-config NO_DMA
-	def_bool !PCI
-
 config SUN_OPENPROMFS
 	tristate "Openprom tree appears in /proc/openprom"
 	help
@@ -263,9 +255,7 @@
 
 source "drivers/Kconfig"
 
-if !SUN4
 source "drivers/sbus/char/Kconfig"
-endif
 
 # This one must be before the filesystem configs. -DaveM
 
diff --git a/arch/sparc/include/asm/Kbuild b/arch/sparc/include/asm/Kbuild
index a5f0ce7..2d2769d 100644
--- a/arch/sparc/include/asm/Kbuild
+++ b/arch/sparc/include/asm/Kbuild
@@ -15,14 +15,11 @@
 header-y += signal_64.h
 header-y += stat_32.h
 header-y += stat_64.h
-header-y += statfs_32.h
-header-y += statfs_64.h
 header-y += unistd_32.h
 header-y += unistd_64.h
 
 header-y += apc.h
 header-y += asi.h
-header-y += bpp.h
 header-y += display7seg.h
 header-y += envctrl.h
 header-y += fbio.h
@@ -41,5 +38,4 @@
 header-y += traps.h
 header-y += uctx.h
 header-y += utrap.h
-header-y += vfc_ioctls.h
 header-y += watchdog.h
diff --git a/arch/sparc/include/asm/asmmacro.h b/arch/sparc/include/asm/asmmacro.h
index a619a4d..a995bf8 100644
--- a/arch/sparc/include/asm/asmmacro.h
+++ b/arch/sparc/include/asm/asmmacro.h
@@ -34,12 +34,7 @@
 /* sun4 probably wants half word accesses to ASI_SEGMAP, while sun4c+
    likes byte accesses. These are to avoid ifdef mania. */
 
-#ifdef CONFIG_SUN4
-#define lduXa	lduha
-#define stXa	stha
-#else
 #define lduXa	lduba
 #define stXa	stba
-#endif
 
 #endif /* !(_SPARC_ASMMACRO_H) */
diff --git a/arch/sparc/include/asm/bpp.h b/arch/sparc/include/asm/bpp.h
deleted file mode 100644
index 31f515e..0000000
--- a/arch/sparc/include/asm/bpp.h
+++ /dev/null
@@ -1,73 +0,0 @@
-#ifndef _SPARC_BPP_H
-#define _SPARC_BPP_H
-
-/*
- * Copyright (c) 1995 Picture Elements
- *	Stephen Williams
- *	Gus Baldauf
- *
- * Linux/SPARC port by Peter Zaitcev.
- * Integration into SPARC tree by Tom Dyas.
- */
-
-#include  <linux/ioctl.h>
-
-/*
- * This is a driver that supports IEEE Std 1284-1994 communications
- * with compliant or compatible devices. It will use whatever features
- * the device supports, prefering those that are typically faster.
- *
- * When the device is opened, it is left in COMPATIBILITY mode, and
- * writes work like any printer device. The driver only attempt to
- * negotiate 1284 modes when needed so that plugs can be pulled,
- * switch boxes switched, etc., without disrupting things. It will
- * also leave the device in compatibility mode when closed.
- */
-
-
-
-/*
- * This driver also supplies ioctls to manually manipulate the
- * pins. This is great for testing devices, or writing code to deal
- * with bizzarro-mode of the ACME Special TurboThingy Plus.
- *
- * NOTE: These ioctl currently do not interact well with
- * read/write. Caveat emptor.
- *
- * PUT_PINS allows us to assign the sense of all the pins, including
- * the data pins if being driven by the host. The GET_PINS returns the
- * pins that the peripheral drives, including data if appropriate.
- */
-
-# define BPP_PUT_PINS _IOW('B', 1, int)
-# define BPP_GET_PINS _IOR('B', 2, char) /* that's bogus - should've been _IO */
-# define BPP_PUT_DATA _IOW('B', 3, int)
-# define BPP_GET_DATA _IOR('B', 4, char) /* ditto */
-
-/*
- * Set the data bus to input mode. Disengage the data bin driver and
- * be prepared to read values from the peripheral. If the arg is 0,
- * then revert the bus to output mode.
- */
-# define BPP_SET_INPUT _IOW('B', 5, int)
-
-/*
- * These bits apply to the PUT operation...
- */
-# define BPP_PP_nStrobe   0x0001
-# define BPP_PP_nAutoFd   0x0002
-# define BPP_PP_nInit     0x0004
-# define BPP_PP_nSelectIn 0x0008
-
-/*
- * These apply to the GET operation, which also reads the current value
- * of the previously put values. A bit mask of these will be returned
- * as a bit mask in the return code of the ioctl().
- */
-# define BPP_GP_nAck   0x0100
-# define BPP_GP_Busy   0x0200
-# define BPP_GP_PError 0x0400
-# define BPP_GP_Select 0x0800
-# define BPP_GP_nFault 0x1000
-
-#endif
diff --git a/arch/sparc/include/asm/bugs.h b/arch/sparc/include/asm/bugs.h
index e179bc1..61d86bb 100644
--- a/arch/sparc/include/asm/bugs.h
+++ b/arch/sparc/include/asm/bugs.h
@@ -7,10 +7,6 @@
 #include <asm/cpudata.h>
 #endif
 
-#ifdef CONFIG_SPARC64
-#include <asm/sstate.h>
-#endif
-
 extern unsigned long loops_per_jiffy;
 
 static void __init check_bugs(void)
@@ -18,7 +14,4 @@
 #if defined(CONFIG_SPARC32) && !defined(CONFIG_SMP)
 	cpu_data(0).udelay_val = loops_per_jiffy;
 #endif
-#ifdef CONFIG_SPARC64
-	sstate_running();
-#endif
 }
diff --git a/arch/sparc/include/asm/cpudata_64.h b/arch/sparc/include/asm/cpudata_64.h
index 532975e..7da7c13 100644
--- a/arch/sparc/include/asm/cpudata_64.h
+++ b/arch/sparc/include/asm/cpudata_64.h
@@ -86,7 +86,6 @@
 extern void init_cur_cpu_trap(struct thread_info *);
 extern void setup_tba(void);
 extern int ncpus_probed;
-extern void __init cpu_probe(void);
 extern const struct seq_operations cpuinfo_op;
 
 extern unsigned long real_hard_smp_processor_id(void);
diff --git a/arch/sparc/include/asm/dma-mapping_32.h b/arch/sparc/include/asm/dma-mapping_32.h
index f3a641e..8a57ea0 100644
--- a/arch/sparc/include/asm/dma-mapping_32.h
+++ b/arch/sparc/include/asm/dma-mapping_32.h
@@ -1,11 +1,60 @@
 #ifndef _ASM_SPARC_DMA_MAPPING_H
 #define _ASM_SPARC_DMA_MAPPING_H
 
+#include <linux/types.h>
 
-#ifdef CONFIG_PCI
-#include <asm-generic/dma-mapping.h>
-#else
-#include <asm-generic/dma-mapping-broken.h>
-#endif /* PCI */
+struct device;
+struct scatterlist;
+struct page;
+
+#define DMA_ERROR_CODE	(~(dma_addr_t)0x0)
+
+extern int dma_supported(struct device *dev, u64 mask);
+extern int dma_set_mask(struct device *dev, u64 dma_mask);
+extern void *dma_alloc_coherent(struct device *dev, size_t size,
+				dma_addr_t *dma_handle, gfp_t flag);
+extern void dma_free_coherent(struct device *dev, size_t size,
+			      void *cpu_addr, dma_addr_t dma_handle);
+extern dma_addr_t dma_map_single(struct device *dev, void *cpu_addr,
+				 size_t size,
+				 enum dma_data_direction direction);
+extern void dma_unmap_single(struct device *dev, dma_addr_t dma_addr,
+			     size_t size,
+			     enum dma_data_direction direction);
+extern dma_addr_t dma_map_page(struct device *dev, struct page *page,
+			       unsigned long offset, size_t size,
+			       enum dma_data_direction direction);
+extern void dma_unmap_page(struct device *dev, dma_addr_t dma_address,
+			   size_t size, enum dma_data_direction direction);
+extern int dma_map_sg(struct device *dev, struct scatterlist *sg,
+		      int nents, enum dma_data_direction direction);
+extern void dma_unmap_sg(struct device *dev, struct scatterlist *sg,
+			 int nents, enum dma_data_direction direction);
+extern void dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle,
+				    size_t size,
+				    enum dma_data_direction direction);
+extern void dma_sync_single_for_device(struct device *dev,
+				       dma_addr_t dma_handle,
+				       size_t size,
+				       enum dma_data_direction direction);
+extern void dma_sync_single_range_for_cpu(struct device *dev,
+					  dma_addr_t dma_handle,
+					  unsigned long offset,
+					  size_t size,
+					  enum dma_data_direction direction);
+extern void dma_sync_single_range_for_device(struct device *dev,
+					     dma_addr_t dma_handle,
+					     unsigned long offset, size_t size,
+					     enum dma_data_direction direction);
+extern void dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg,
+				int nelems, enum dma_data_direction direction);
+extern void dma_sync_sg_for_device(struct device *dev,
+				   struct scatterlist *sg, int nelems,
+				   enum dma_data_direction direction);
+extern int dma_mapping_error(struct device *dev, dma_addr_t dma_addr);
+extern int dma_get_cache_alignment(void);
+
+#define dma_alloc_noncoherent	dma_alloc_coherent
+#define dma_free_noncoherent	dma_free_coherent
 
 #endif /* _ASM_SPARC_DMA_MAPPING_H */
diff --git a/arch/sparc/include/asm/dma.h b/arch/sparc/include/asm/dma.h
index aa1d90a..b554927 100644
--- a/arch/sparc/include/asm/dma.h
+++ b/arch/sparc/include/asm/dma.h
@@ -1,8 +1,139 @@
-#ifndef ___ASM_SPARC_DMA_H
-#define ___ASM_SPARC_DMA_H
-#if defined(__sparc__) && defined(__arch64__)
-#include <asm/dma_64.h>
+#ifndef _ASM_SPARC_DMA_H
+#define _ASM_SPARC_DMA_H
+
+/* These are irrelevant for Sparc DMA, but we leave it in so that
+ * things can compile.
+ */
+#define MAX_DMA_CHANNELS 8
+#define DMA_MODE_READ    1
+#define DMA_MODE_WRITE   2
+#define MAX_DMA_ADDRESS  (~0UL)
+
+/* Useful constants */
+#define SIZE_16MB      (16*1024*1024)
+#define SIZE_64K       (64*1024)
+
+/* SBUS DMA controller reg offsets */
+#define DMA_CSR		0x00UL		/* rw  DMA control/status register    0x00   */
+#define DMA_ADDR	0x04UL		/* rw  DMA transfer address register  0x04   */
+#define DMA_COUNT	0x08UL		/* rw  DMA transfer count register    0x08   */
+#define DMA_TEST	0x0cUL		/* rw  DMA test/debug register        0x0c   */
+
+/* Fields in the cond_reg register */
+/* First, the version identification bits */
+#define DMA_DEVICE_ID    0xf0000000        /* Device identification bits */
+#define DMA_VERS0        0x00000000        /* Sunray DMA version */
+#define DMA_ESCV1        0x40000000        /* DMA ESC Version 1 */
+#define DMA_VERS1        0x80000000        /* DMA rev 1 */
+#define DMA_VERS2        0xa0000000        /* DMA rev 2 */
+#define DMA_VERHME       0xb0000000        /* DMA hme gate array */
+#define DMA_VERSPLUS     0x90000000        /* DMA rev 1 PLUS */
+
+#define DMA_HNDL_INTR    0x00000001        /* An IRQ needs to be handled */
+#define DMA_HNDL_ERROR   0x00000002        /* We need to take an error */
+#define DMA_FIFO_ISDRAIN 0x0000000c        /* The DMA FIFO is draining */
+#define DMA_INT_ENAB     0x00000010        /* Turn on interrupts */
+#define DMA_FIFO_INV     0x00000020        /* Invalidate the FIFO */
+#define DMA_ACC_SZ_ERR   0x00000040        /* The access size was bad */
+#define DMA_FIFO_STDRAIN 0x00000040        /* DMA_VERS1 Drain the FIFO */
+#define DMA_RST_SCSI     0x00000080        /* Reset the SCSI controller */
+#define DMA_RST_ENET     DMA_RST_SCSI      /* Reset the ENET controller */
+#define DMA_ST_WRITE     0x00000100        /* write from device to memory */
+#define DMA_ENABLE       0x00000200        /* Fire up DMA, handle requests */
+#define DMA_PEND_READ    0x00000400        /* DMA_VERS1/0/PLUS Pending Read */
+#define DMA_ESC_BURST    0x00000800        /* 1=16byte 0=32byte */
+#define DMA_READ_AHEAD   0x00001800        /* DMA read ahead partial longword */
+#define DMA_DSBL_RD_DRN  0x00001000        /* No EC drain on slave reads */
+#define DMA_BCNT_ENAB    0x00002000        /* If on, use the byte counter */
+#define DMA_TERM_CNTR    0x00004000        /* Terminal counter */
+#define DMA_SCSI_SBUS64  0x00008000        /* HME: Enable 64-bit SBUS mode. */
+#define DMA_CSR_DISAB    0x00010000        /* No FIFO drains during csr */
+#define DMA_SCSI_DISAB   0x00020000        /* No FIFO drains during reg */
+#define DMA_DSBL_WR_INV  0x00020000        /* No EC inval. on slave writes */
+#define DMA_ADD_ENABLE   0x00040000        /* Special ESC DVMA optimization */
+#define DMA_E_BURSTS	 0x000c0000	   /* ENET: SBUS r/w burst mask */
+#define DMA_E_BURST32	 0x00040000	   /* ENET: SBUS 32 byte r/w burst */
+#define DMA_E_BURST16	 0x00000000	   /* ENET: SBUS 16 byte r/w burst */
+#define DMA_BRST_SZ      0x000c0000        /* SCSI: SBUS r/w burst size */
+#define DMA_BRST64       0x000c0000        /* SCSI: 64byte bursts (HME on UltraSparc only) */
+#define DMA_BRST32       0x00040000        /* SCSI: 32byte bursts */
+#define DMA_BRST16       0x00000000        /* SCSI: 16byte bursts */
+#define DMA_BRST0        0x00080000        /* SCSI: no bursts (non-HME gate arrays) */
+#define DMA_ADDR_DISAB   0x00100000        /* No FIFO drains during addr */
+#define DMA_2CLKS        0x00200000        /* Each transfer = 2 clock ticks */
+#define DMA_3CLKS        0x00400000        /* Each transfer = 3 clock ticks */
+#define DMA_EN_ENETAUI   DMA_3CLKS         /* Put lance into AUI-cable mode */
+#define DMA_CNTR_DISAB   0x00800000        /* No IRQ when DMA_TERM_CNTR set */
+#define DMA_AUTO_NADDR   0x01000000        /* Use "auto nxt addr" feature */
+#define DMA_SCSI_ON      0x02000000        /* Enable SCSI dma */
+#define DMA_PARITY_OFF   0x02000000        /* HME: disable parity checking */
+#define DMA_LOADED_ADDR  0x04000000        /* Address has been loaded */
+#define DMA_LOADED_NADDR 0x08000000        /* Next address has been loaded */
+#define DMA_RESET_FAS366 0x08000000        /* HME: Assert RESET to FAS366 */
+
+/* Values describing the burst-size property from the PROM */
+#define DMA_BURST1       0x01
+#define DMA_BURST2       0x02
+#define DMA_BURST4       0x04
+#define DMA_BURST8       0x08
+#define DMA_BURST16      0x10
+#define DMA_BURST32      0x20
+#define DMA_BURST64      0x40
+#define DMA_BURSTBITS    0x7f
+
+/* From PCI */
+
+#ifdef CONFIG_PCI
+extern int isa_dma_bridge_buggy;
 #else
-#include <asm/dma_32.h>
+#define isa_dma_bridge_buggy 	(0)
 #endif
+
+#ifdef CONFIG_SPARC32
+
+/* Routines for data transfer buffers. */
+BTFIXUPDEF_CALL(char *, mmu_lockarea, char *, unsigned long)
+BTFIXUPDEF_CALL(void,   mmu_unlockarea, char *, unsigned long)
+
+#define mmu_lockarea(vaddr,len) BTFIXUP_CALL(mmu_lockarea)(vaddr,len)
+#define mmu_unlockarea(vaddr,len) BTFIXUP_CALL(mmu_unlockarea)(vaddr,len)
+
+struct page;
+struct device;
+struct scatterlist;
+
+/* These are implementations for sbus_map_sg/sbus_unmap_sg... collapse later */
+BTFIXUPDEF_CALL(__u32, mmu_get_scsi_one, struct device *, char *, unsigned long)
+BTFIXUPDEF_CALL(void,  mmu_get_scsi_sgl, struct device *, struct scatterlist *, int)
+BTFIXUPDEF_CALL(void,  mmu_release_scsi_one, struct device *, __u32, unsigned long)
+BTFIXUPDEF_CALL(void,  mmu_release_scsi_sgl, struct device *, struct scatterlist *, int)
+
+#define mmu_get_scsi_one(dev,vaddr,len) BTFIXUP_CALL(mmu_get_scsi_one)(dev,vaddr,len)
+#define mmu_get_scsi_sgl(dev,sg,sz) BTFIXUP_CALL(mmu_get_scsi_sgl)(dev,sg,sz)
+#define mmu_release_scsi_one(dev,vaddr,len) BTFIXUP_CALL(mmu_release_scsi_one)(dev,vaddr,len)
+#define mmu_release_scsi_sgl(dev,sg,sz) BTFIXUP_CALL(mmu_release_scsi_sgl)(dev,sg,sz)
+
+/*
+ * mmu_map/unmap are provided by iommu/iounit; Invalid to call on IIep.
+ *
+ * The mmu_map_dma_area establishes two mappings in one go.
+ * These mappings point to pages normally mapped at 'va' (linear address).
+ * First mapping is for CPU visible address at 'a', uncached.
+ * This is an alias, but it works because it is an uncached mapping.
+ * Second mapping is for device visible address, or "bus" address.
+ * The bus address is returned at '*pba'.
+ *
+ * These functions seem distinct, but are hard to split. On sun4c,
+ * at least for now, 'a' is equal to bus address, and retured in *pba.
+ * On sun4m, page attributes depend on the CPU type, so we have to
+ * know if we are mapping RAM or I/O, so it has to be an additional argument
+ * to a separate mapping function for CPU visible mappings.
+ */
+BTFIXUPDEF_CALL(int, mmu_map_dma_area, struct device *, dma_addr_t *, unsigned long, unsigned long, int len)
+BTFIXUPDEF_CALL(void, mmu_unmap_dma_area, struct device *, unsigned long busa, int len)
+
+#define mmu_map_dma_area(dev,pba,va,a,len) BTFIXUP_CALL(mmu_map_dma_area)(dev,pba,va,a,len)
+#define mmu_unmap_dma_area(dev,ba,len) BTFIXUP_CALL(mmu_unmap_dma_area)(dev,ba,len)
 #endif
+
+#endif /* !(_ASM_SPARC_DMA_H) */
diff --git a/arch/sparc/include/asm/dma_32.h b/arch/sparc/include/asm/dma_32.h
deleted file mode 100644
index cf7189c..0000000
--- a/arch/sparc/include/asm/dma_32.h
+++ /dev/null
@@ -1,288 +0,0 @@
-/* include/asm/dma.h
- *
- * Copyright 1995 (C) David S. Miller (davem@davemloft.net)
- */
-
-#ifndef _ASM_SPARC_DMA_H
-#define _ASM_SPARC_DMA_H
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-
-#include <asm/vac-ops.h>  /* for invalidate's, etc. */
-#include <asm/sbus.h>
-#include <asm/delay.h>
-#include <asm/oplib.h>
-#include <asm/system.h>
-#include <asm/io.h>
-#include <linux/spinlock.h>
-
-struct page;
-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;
-}
-
-static inline void release_dma_lock(unsigned long flags)
-{
-	spin_unlock_irqrestore(&dma_spin_lock, flags);
-}
-
-/* These are irrelevant for Sparc DMA, but we leave it in so that
- * things can compile.
- */
-#define MAX_DMA_CHANNELS 8
-#define MAX_DMA_ADDRESS  (~0UL)
-#define DMA_MODE_READ    1
-#define DMA_MODE_WRITE   2
-
-/* Useful constants */
-#define SIZE_16MB      (16*1024*1024)
-#define SIZE_64K       (64*1024)
-
-/* SBUS DMA controller reg offsets */
-#define DMA_CSR		0x00UL		/* rw  DMA control/status register    0x00   */
-#define DMA_ADDR	0x04UL		/* rw  DMA transfer address register  0x04   */
-#define DMA_COUNT	0x08UL		/* rw  DMA transfer count register    0x08   */
-#define DMA_TEST	0x0cUL		/* rw  DMA test/debug register        0x0c   */
-
-/* DVMA chip revisions */
-enum dvma_rev {
-	dvmarev0,
-	dvmaesc1,
-	dvmarev1,
-	dvmarev2,
-	dvmarev3,
-	dvmarevplus,
-	dvmahme
-};
-
-#define DMA_HASCOUNT(rev)  ((rev)==dvmaesc1)
-
-/* Linux DMA information structure, filled during probe. */
-struct sbus_dma {
-	struct sbus_dma *next;
-	struct sbus_dev *sdev;
-	void __iomem *regs;
-
-	/* Status, misc info */
-	int node;                /* Prom node for this DMA device */
-	int running;             /* Are we doing DMA now? */
-	int allocated;           /* Are we "owned" by anyone yet? */
-
-	/* Transfer information. */
-	unsigned long addr;      /* Start address of current transfer */
-	int nbytes;              /* Size of current transfer */
-	int realbytes;           /* For splitting up large transfers, etc. */
-
-	/* DMA revision */
-	enum dvma_rev revision;
-};
-
-extern struct sbus_dma *dma_chain;
-
-/* Broken hardware... */
-#ifdef CONFIG_SUN4
-/* Have to sort this out. Does rev0 work fine on sun4[cmd] without isbroken?
- * Or is rev0 present only on sun4 boxes? -jj */
-#define DMA_ISBROKEN(dma)    ((dma)->revision == dvmarev0 || (dma)->revision == dvmarev1)
-#else
-#define DMA_ISBROKEN(dma)    ((dma)->revision == dvmarev1)
-#endif
-#define DMA_ISESC1(dma)      ((dma)->revision == dvmaesc1)
-
-/* Main routines in dma.c */
-extern void dvma_init(struct sbus_bus *);
-
-/* Fields in the cond_reg register */
-/* First, the version identification bits */
-#define DMA_DEVICE_ID    0xf0000000        /* Device identification bits */
-#define DMA_VERS0        0x00000000        /* Sunray DMA version */
-#define DMA_ESCV1        0x40000000        /* DMA ESC Version 1 */
-#define DMA_VERS1        0x80000000        /* DMA rev 1 */
-#define DMA_VERS2        0xa0000000        /* DMA rev 2 */
-#define DMA_VERHME       0xb0000000        /* DMA hme gate array */
-#define DMA_VERSPLUS     0x90000000        /* DMA rev 1 PLUS */
-
-#define DMA_HNDL_INTR    0x00000001        /* An IRQ needs to be handled */
-#define DMA_HNDL_ERROR   0x00000002        /* We need to take an error */
-#define DMA_FIFO_ISDRAIN 0x0000000c        /* The DMA FIFO is draining */
-#define DMA_INT_ENAB     0x00000010        /* Turn on interrupts */
-#define DMA_FIFO_INV     0x00000020        /* Invalidate the FIFO */
-#define DMA_ACC_SZ_ERR   0x00000040        /* The access size was bad */
-#define DMA_FIFO_STDRAIN 0x00000040        /* DMA_VERS1 Drain the FIFO */
-#define DMA_RST_SCSI     0x00000080        /* Reset the SCSI controller */
-#define DMA_RST_ENET     DMA_RST_SCSI      /* Reset the ENET controller */
-#define DMA_RST_BPP      DMA_RST_SCSI      /* Reset the BPP controller */
-#define DMA_ST_WRITE     0x00000100        /* write from device to memory */
-#define DMA_ENABLE       0x00000200        /* Fire up DMA, handle requests */
-#define DMA_PEND_READ    0x00000400        /* DMA_VERS1/0/PLUS Pending Read */
-#define DMA_ESC_BURST    0x00000800        /* 1=16byte 0=32byte */
-#define DMA_READ_AHEAD   0x00001800        /* DMA read ahead partial longword */
-#define DMA_DSBL_RD_DRN  0x00001000        /* No EC drain on slave reads */
-#define DMA_BCNT_ENAB    0x00002000        /* If on, use the byte counter */
-#define DMA_TERM_CNTR    0x00004000        /* Terminal counter */
-#define DMA_SCSI_SBUS64  0x00008000        /* HME: Enable 64-bit SBUS mode. */
-#define DMA_CSR_DISAB    0x00010000        /* No FIFO drains during csr */
-#define DMA_SCSI_DISAB   0x00020000        /* No FIFO drains during reg */
-#define DMA_DSBL_WR_INV  0x00020000        /* No EC inval. on slave writes */
-#define DMA_ADD_ENABLE   0x00040000        /* Special ESC DVMA optimization */
-#define DMA_E_BURSTS	 0x000c0000	   /* ENET: SBUS r/w burst mask */
-#define DMA_E_BURST32	 0x00040000	   /* ENET: SBUS 32 byte r/w burst */
-#define DMA_E_BURST16	 0x00000000	   /* ENET: SBUS 16 byte r/w burst */
-#define DMA_BRST_SZ      0x000c0000        /* SCSI: SBUS r/w burst size */
-#define DMA_BRST64       0x00080000        /* SCSI: 64byte bursts (HME on UltraSparc only) */
-#define DMA_BRST32       0x00040000        /* SCSI/BPP: 32byte bursts */
-#define DMA_BRST16       0x00000000        /* SCSI/BPP: 16byte bursts */
-#define DMA_BRST0        0x00080000        /* SCSI: no bursts (non-HME gate arrays) */
-#define DMA_ADDR_DISAB   0x00100000        /* No FIFO drains during addr */
-#define DMA_2CLKS        0x00200000        /* Each transfer = 2 clock ticks */
-#define DMA_3CLKS        0x00400000        /* Each transfer = 3 clock ticks */
-#define DMA_EN_ENETAUI   DMA_3CLKS         /* Put lance into AUI-cable mode */
-#define DMA_CNTR_DISAB   0x00800000        /* No IRQ when DMA_TERM_CNTR set */
-#define DMA_AUTO_NADDR   0x01000000        /* Use "auto nxt addr" feature */
-#define DMA_SCSI_ON      0x02000000        /* Enable SCSI dma */
-#define DMA_BPP_ON       DMA_SCSI_ON       /* Enable BPP dma */
-#define DMA_PARITY_OFF   0x02000000        /* HME: disable parity checking */
-#define DMA_LOADED_ADDR  0x04000000        /* Address has been loaded */
-#define DMA_LOADED_NADDR 0x08000000        /* Next address has been loaded */
-#define DMA_RESET_FAS366 0x08000000        /* HME: Assert RESET to FAS366 */
-
-/* Values describing the burst-size property from the PROM */
-#define DMA_BURST1       0x01
-#define DMA_BURST2       0x02
-#define DMA_BURST4       0x04
-#define DMA_BURST8       0x08
-#define DMA_BURST16      0x10
-#define DMA_BURST32      0x20
-#define DMA_BURST64      0x40
-#define DMA_BURSTBITS    0x7f
-
-/* Determine highest possible final transfer address given a base */
-#define DMA_MAXEND(addr) (0x01000000UL-(((unsigned long)(addr))&0x00ffffffUL))
-
-/* Yes, I hack a lot of elisp in my spare time... */
-#define DMA_ERROR_P(regs)  ((((regs)->cond_reg) & DMA_HNDL_ERROR))
-#define DMA_IRQ_P(regs)    ((((regs)->cond_reg) & (DMA_HNDL_INTR | DMA_HNDL_ERROR)))
-#define DMA_WRITE_P(regs)  ((((regs)->cond_reg) & DMA_ST_WRITE))
-#define DMA_OFF(regs)      ((((regs)->cond_reg) &= (~DMA_ENABLE)))
-#define DMA_INTSOFF(regs)  ((((regs)->cond_reg) &= (~DMA_INT_ENAB)))
-#define DMA_INTSON(regs)   ((((regs)->cond_reg) |= (DMA_INT_ENAB)))
-#define DMA_PUNTFIFO(regs) ((((regs)->cond_reg) |= DMA_FIFO_INV))
-#define DMA_SETSTART(regs, addr)  ((((regs)->st_addr) = (char *) addr))
-#define DMA_BEGINDMA_W(regs) \
-        ((((regs)->cond_reg |= (DMA_ST_WRITE|DMA_ENABLE|DMA_INT_ENAB))))
-#define DMA_BEGINDMA_R(regs) \
-        ((((regs)->cond_reg |= ((DMA_ENABLE|DMA_INT_ENAB)&(~DMA_ST_WRITE)))))
-
-/* For certain DMA chips, we need to disable ints upon irq entry
- * and turn them back on when we are done.  So in any ESP interrupt
- * handler you *must* call DMA_IRQ_ENTRY upon entry and DMA_IRQ_EXIT
- * when leaving the handler.  You have been warned...
- */
-#define DMA_IRQ_ENTRY(dma, dregs) do { \
-        if(DMA_ISBROKEN(dma)) DMA_INTSOFF(dregs); \
-   } while (0)
-
-#define DMA_IRQ_EXIT(dma, dregs) do { \
-	if(DMA_ISBROKEN(dma)) DMA_INTSON(dregs); \
-   } while(0)
-
-#if 0	/* P3 this stuff is inline in ledma.c:init_restart_ledma() */
-/* Pause until counter runs out or BIT isn't set in the DMA condition
- * register.
- */
-static inline void sparc_dma_pause(struct sparc_dma_registers *regs,
-				       unsigned long bit)
-{
-	int ctr = 50000;   /* Let's find some bugs ;) */
-
-	/* Busy wait until the bit is not set any more */
-	while((regs->cond_reg&bit) && (ctr>0)) {
-		ctr--;
-		__delay(5);
-	}
-
-	/* Check for bogus outcome. */
-	if(!ctr)
-		panic("DMA timeout");
-}
-
-/* Reset the friggin' thing... */
-#define DMA_RESET(dma) do { \
-	struct sparc_dma_registers *regs = dma->regs;                      \
-	/* Let the current FIFO drain itself */                            \
-	sparc_dma_pause(regs, (DMA_FIFO_ISDRAIN));                         \
-	/* Reset the logic */                                              \
-	regs->cond_reg |= (DMA_RST_SCSI);     /* assert */                 \
-	__delay(400);                         /* let the bits set ;) */    \
-	regs->cond_reg &= ~(DMA_RST_SCSI);    /* de-assert */              \
-	sparc_dma_enable_interrupts(regs);    /* Re-enable interrupts */   \
-	/* Enable FAST transfers if available */                           \
-	if(dma->revision>dvmarev1) regs->cond_reg |= DMA_3CLKS;            \
-	dma->running = 0;                                                  \
-} while(0)
-#endif
-
-#define for_each_dvma(dma) \
-        for((dma) = dma_chain; (dma); (dma) = (dma)->next)
-
-extern int get_dma_list(char *);
-extern int request_dma(unsigned int, __const__ char *);
-extern void free_dma(unsigned int);
-
-/* From PCI */
-
-#ifdef CONFIG_PCI
-extern int isa_dma_bridge_buggy;
-#else
-#define isa_dma_bridge_buggy	(0)
-#endif
-
-/* Routines for data transfer buffers. */
-BTFIXUPDEF_CALL(char *, mmu_lockarea, char *, unsigned long)
-BTFIXUPDEF_CALL(void,   mmu_unlockarea, char *, unsigned long)
-
-#define mmu_lockarea(vaddr,len) BTFIXUP_CALL(mmu_lockarea)(vaddr,len)
-#define mmu_unlockarea(vaddr,len) BTFIXUP_CALL(mmu_unlockarea)(vaddr,len)
-
-/* These are implementations for sbus_map_sg/sbus_unmap_sg... collapse later */
-BTFIXUPDEF_CALL(__u32, mmu_get_scsi_one, char *, unsigned long, struct sbus_bus *sbus)
-BTFIXUPDEF_CALL(void,  mmu_get_scsi_sgl, struct scatterlist *, int, struct sbus_bus *sbus)
-BTFIXUPDEF_CALL(void,  mmu_release_scsi_one, __u32, unsigned long, struct sbus_bus *sbus)
-BTFIXUPDEF_CALL(void,  mmu_release_scsi_sgl, struct scatterlist *, int, struct sbus_bus *sbus)
-
-#define mmu_get_scsi_one(vaddr,len,sbus) BTFIXUP_CALL(mmu_get_scsi_one)(vaddr,len,sbus)
-#define mmu_get_scsi_sgl(sg,sz,sbus) BTFIXUP_CALL(mmu_get_scsi_sgl)(sg,sz,sbus)
-#define mmu_release_scsi_one(vaddr,len,sbus) BTFIXUP_CALL(mmu_release_scsi_one)(vaddr,len,sbus)
-#define mmu_release_scsi_sgl(sg,sz,sbus) BTFIXUP_CALL(mmu_release_scsi_sgl)(sg,sz,sbus)
-
-/*
- * mmu_map/unmap are provided by iommu/iounit; Invalid to call on IIep.
- *
- * The mmu_map_dma_area establishes two mappings in one go.
- * These mappings point to pages normally mapped at 'va' (linear address).
- * First mapping is for CPU visible address at 'a', uncached.
- * This is an alias, but it works because it is an uncached mapping.
- * Second mapping is for device visible address, or "bus" address.
- * The bus address is returned at '*pba'.
- *
- * These functions seem distinct, but are hard to split. On sun4c,
- * at least for now, 'a' is equal to bus address, and retured in *pba.
- * On sun4m, page attributes depend on the CPU type, so we have to
- * know if we are mapping RAM or I/O, so it has to be an additional argument
- * to a separate mapping function for CPU visible mappings.
- */
-BTFIXUPDEF_CALL(int,  mmu_map_dma_area, dma_addr_t *, unsigned long, unsigned long, int len)
-BTFIXUPDEF_CALL(struct page *, mmu_translate_dvma, unsigned long busa)
-BTFIXUPDEF_CALL(void,  mmu_unmap_dma_area, unsigned long busa, int len)
-
-#define mmu_map_dma_area(pba,va,a,len) BTFIXUP_CALL(mmu_map_dma_area)(pba,va,a,len)
-#define mmu_unmap_dma_area(ba,len) BTFIXUP_CALL(mmu_unmap_dma_area)(ba,len)
-#define mmu_translate_dvma(ba)     BTFIXUP_CALL(mmu_translate_dvma)(ba)
-
-#endif /* !(_ASM_SPARC_DMA_H) */
diff --git a/arch/sparc/include/asm/dma_64.h b/arch/sparc/include/asm/dma_64.h
deleted file mode 100644
index 46a8aec..0000000
--- a/arch/sparc/include/asm/dma_64.h
+++ /dev/null
@@ -1,205 +0,0 @@
-/*
- * include/asm/dma.h
- *
- * Copyright 1996 (C) David S. Miller (davem@caip.rutgers.edu)
- */
-
-#ifndef _ASM_SPARC64_DMA_H
-#define _ASM_SPARC64_DMA_H
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/spinlock.h>
-
-#include <asm/sbus.h>
-#include <asm/delay.h>
-#include <asm/oplib.h>
-
-/* These are irrelevant for Sparc DMA, but we leave it in so that
- * things can compile.
- */
-#define MAX_DMA_CHANNELS 8
-#define DMA_MODE_READ    1
-#define DMA_MODE_WRITE   2
-#define MAX_DMA_ADDRESS  (~0UL)
-
-/* Useful constants */
-#define SIZE_16MB      (16*1024*1024)
-#define SIZE_64K       (64*1024)
-
-/* SBUS DMA controller reg offsets */
-#define DMA_CSR		0x00UL		/* rw  DMA control/status register    0x00   */
-#define DMA_ADDR	0x04UL		/* rw  DMA transfer address register  0x04   */
-#define DMA_COUNT	0x08UL		/* rw  DMA transfer count register    0x08   */
-#define DMA_TEST	0x0cUL		/* rw  DMA test/debug register        0x0c   */
-
-/* DVMA chip revisions */
-enum dvma_rev {
-	dvmarev0,
-	dvmaesc1,
-	dvmarev1,
-	dvmarev2,
-	dvmarev3,
-	dvmarevplus,
-	dvmahme
-};
-
-#define DMA_HASCOUNT(rev)  ((rev)==dvmaesc1)
-
-/* Linux DMA information structure, filled during probe. */
-struct sbus_dma {
-	struct sbus_dma *next;
-	struct sbus_dev *sdev;
-	void __iomem *regs;
-
-	/* Status, misc info */
-	int node;                /* Prom node for this DMA device */
-	int running;             /* Are we doing DMA now? */
-	int allocated;           /* Are we "owned" by anyone yet? */
-
-	/* Transfer information. */
-	u32 addr;                /* Start address of current transfer */
-	int nbytes;              /* Size of current transfer */
-	int realbytes;           /* For splitting up large transfers, etc. */
-
-	/* DMA revision */
-	enum dvma_rev revision;
-};
-
-extern struct sbus_dma *dma_chain;
-
-/* Broken hardware... */
-#define DMA_ISBROKEN(dma)    ((dma)->revision == dvmarev1)
-#define DMA_ISESC1(dma)      ((dma)->revision == dvmaesc1)
-
-/* Main routines in dma.c */
-extern void dvma_init(struct sbus_bus *);
-
-/* Fields in the cond_reg register */
-/* First, the version identification bits */
-#define DMA_DEVICE_ID    0xf0000000        /* Device identification bits */
-#define DMA_VERS0        0x00000000        /* Sunray DMA version */
-#define DMA_ESCV1        0x40000000        /* DMA ESC Version 1 */
-#define DMA_VERS1        0x80000000        /* DMA rev 1 */
-#define DMA_VERS2        0xa0000000        /* DMA rev 2 */
-#define DMA_VERHME       0xb0000000        /* DMA hme gate array */
-#define DMA_VERSPLUS     0x90000000        /* DMA rev 1 PLUS */
-
-#define DMA_HNDL_INTR    0x00000001        /* An IRQ needs to be handled */
-#define DMA_HNDL_ERROR   0x00000002        /* We need to take an error */
-#define DMA_FIFO_ISDRAIN 0x0000000c        /* The DMA FIFO is draining */
-#define DMA_INT_ENAB     0x00000010        /* Turn on interrupts */
-#define DMA_FIFO_INV     0x00000020        /* Invalidate the FIFO */
-#define DMA_ACC_SZ_ERR   0x00000040        /* The access size was bad */
-#define DMA_FIFO_STDRAIN 0x00000040        /* DMA_VERS1 Drain the FIFO */
-#define DMA_RST_SCSI     0x00000080        /* Reset the SCSI controller */
-#define DMA_RST_ENET     DMA_RST_SCSI      /* Reset the ENET controller */
-#define DMA_ST_WRITE     0x00000100        /* write from device to memory */
-#define DMA_ENABLE       0x00000200        /* Fire up DMA, handle requests */
-#define DMA_PEND_READ    0x00000400        /* DMA_VERS1/0/PLUS Pending Read */
-#define DMA_ESC_BURST    0x00000800        /* 1=16byte 0=32byte */
-#define DMA_READ_AHEAD   0x00001800        /* DMA read ahead partial longword */
-#define DMA_DSBL_RD_DRN  0x00001000        /* No EC drain on slave reads */
-#define DMA_BCNT_ENAB    0x00002000        /* If on, use the byte counter */
-#define DMA_TERM_CNTR    0x00004000        /* Terminal counter */
-#define DMA_SCSI_SBUS64  0x00008000        /* HME: Enable 64-bit SBUS mode. */
-#define DMA_CSR_DISAB    0x00010000        /* No FIFO drains during csr */
-#define DMA_SCSI_DISAB   0x00020000        /* No FIFO drains during reg */
-#define DMA_DSBL_WR_INV  0x00020000        /* No EC inval. on slave writes */
-#define DMA_ADD_ENABLE   0x00040000        /* Special ESC DVMA optimization */
-#define DMA_E_BURSTS	 0x000c0000	   /* ENET: SBUS r/w burst mask */
-#define DMA_E_BURST32	 0x00040000	   /* ENET: SBUS 32 byte r/w burst */
-#define DMA_E_BURST16	 0x00000000	   /* ENET: SBUS 16 byte r/w burst */
-#define DMA_BRST_SZ      0x000c0000        /* SCSI: SBUS r/w burst size */
-#define DMA_BRST64       0x000c0000        /* SCSI: 64byte bursts (HME on UltraSparc only) */
-#define DMA_BRST32       0x00040000        /* SCSI: 32byte bursts */
-#define DMA_BRST16       0x00000000        /* SCSI: 16byte bursts */
-#define DMA_BRST0        0x00080000        /* SCSI: no bursts (non-HME gate arrays) */
-#define DMA_ADDR_DISAB   0x00100000        /* No FIFO drains during addr */
-#define DMA_2CLKS        0x00200000        /* Each transfer = 2 clock ticks */
-#define DMA_3CLKS        0x00400000        /* Each transfer = 3 clock ticks */
-#define DMA_EN_ENETAUI   DMA_3CLKS         /* Put lance into AUI-cable mode */
-#define DMA_CNTR_DISAB   0x00800000        /* No IRQ when DMA_TERM_CNTR set */
-#define DMA_AUTO_NADDR   0x01000000        /* Use "auto nxt addr" feature */
-#define DMA_SCSI_ON      0x02000000        /* Enable SCSI dma */
-#define DMA_PARITY_OFF   0x02000000        /* HME: disable parity checking */
-#define DMA_LOADED_ADDR  0x04000000        /* Address has been loaded */
-#define DMA_LOADED_NADDR 0x08000000        /* Next address has been loaded */
-#define DMA_RESET_FAS366 0x08000000        /* HME: Assert RESET to FAS366 */
-
-/* Values describing the burst-size property from the PROM */
-#define DMA_BURST1       0x01
-#define DMA_BURST2       0x02
-#define DMA_BURST4       0x04
-#define DMA_BURST8       0x08
-#define DMA_BURST16      0x10
-#define DMA_BURST32      0x20
-#define DMA_BURST64      0x40
-#define DMA_BURSTBITS    0x7f
-
-/* Determine highest possible final transfer address given a base */
-#define DMA_MAXEND(addr) (0x01000000UL-(((unsigned long)(addr))&0x00ffffffUL))
-
-/* Yes, I hack a lot of elisp in my spare time... */
-#define DMA_ERROR_P(regs)  ((sbus_readl((regs) + DMA_CSR) & DMA_HNDL_ERROR))
-#define DMA_IRQ_P(regs)    ((sbus_readl((regs) + DMA_CSR)) & (DMA_HNDL_INTR | DMA_HNDL_ERROR))
-#define DMA_WRITE_P(regs)  ((sbus_readl((regs) + DMA_CSR) & DMA_ST_WRITE))
-#define DMA_OFF(__regs)		\
-do {	u32 tmp = sbus_readl((__regs) + DMA_CSR); \
-	tmp &= ~DMA_ENABLE; \
-	sbus_writel(tmp, (__regs) + DMA_CSR); \
-} while(0)
-#define DMA_INTSOFF(__regs)	\
-do {	u32 tmp = sbus_readl((__regs) + DMA_CSR); \
-	tmp &= ~DMA_INT_ENAB; \
-	sbus_writel(tmp, (__regs) + DMA_CSR); \
-} while(0)
-#define DMA_INTSON(__regs)	\
-do {	u32 tmp = sbus_readl((__regs) + DMA_CSR); \
-	tmp |= DMA_INT_ENAB; \
-	sbus_writel(tmp, (__regs) + DMA_CSR); \
-} while(0)
-#define DMA_PUNTFIFO(__regs)	\
-do {	u32 tmp = sbus_readl((__regs) + DMA_CSR); \
-	tmp |= DMA_FIFO_INV; \
-	sbus_writel(tmp, (__regs) + DMA_CSR); \
-} while(0)
-#define DMA_SETSTART(__regs, __addr)	\
-	sbus_writel((u32)(__addr), (__regs) + DMA_ADDR);
-#define DMA_BEGINDMA_W(__regs)	\
-do {	u32 tmp = sbus_readl((__regs) + DMA_CSR); \
-	tmp |= (DMA_ST_WRITE|DMA_ENABLE|DMA_INT_ENAB); \
-	sbus_writel(tmp, (__regs) + DMA_CSR); \
-} while(0)
-#define DMA_BEGINDMA_R(__regs)	\
-do {	u32 tmp = sbus_readl((__regs) + DMA_CSR); \
-	tmp |= (DMA_ENABLE|DMA_INT_ENAB); \
-	tmp &= ~DMA_ST_WRITE; \
-	sbus_writel(tmp, (__regs) + DMA_CSR); \
-} while(0)
-
-/* For certain DMA chips, we need to disable ints upon irq entry
- * and turn them back on when we are done.  So in any ESP interrupt
- * handler you *must* call DMA_IRQ_ENTRY upon entry and DMA_IRQ_EXIT
- * when leaving the handler.  You have been warned...
- */
-#define DMA_IRQ_ENTRY(dma, dregs) do { \
-        if(DMA_ISBROKEN(dma)) DMA_INTSOFF(dregs); \
-   } while (0)
-
-#define DMA_IRQ_EXIT(dma, dregs) do { \
-	if(DMA_ISBROKEN(dma)) DMA_INTSON(dregs); \
-   } while(0)
-
-#define for_each_dvma(dma) \
-        for((dma) = dma_chain; (dma); (dma) = (dma)->next)
-
-/* From PCI */
-
-#ifdef CONFIG_PCI
-extern int isa_dma_bridge_buggy;
-#else
-#define isa_dma_bridge_buggy 	(0)
-#endif
-
-#endif /* !(_ASM_SPARC64_DMA_H) */
diff --git a/arch/sparc/include/asm/ebus.h b/arch/sparc/include/asm/ebus.h
deleted file mode 100644
index 83a6d16..0000000
--- a/arch/sparc/include/asm/ebus.h
+++ /dev/null
@@ -1,8 +0,0 @@
-#ifndef ___ASM_SPARC_EBUS_H
-#define ___ASM_SPARC_EBUS_H
-#if defined(__sparc__) && defined(__arch64__)
-#include <asm/ebus_64.h>
-#else
-#include <asm/ebus_32.h>
-#endif
-#endif
diff --git a/arch/sparc/include/asm/ebus_32.h b/arch/sparc/include/asm/ebus_32.h
deleted file mode 100644
index f91f0b2..0000000
--- a/arch/sparc/include/asm/ebus_32.h
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * ebus.h: PCI to Ebus pseudo driver software state.
- *
- * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be)
- *
- * Adopted for sparc by V. Roganov and G. Raiko.
- */
-
-#ifndef __SPARC_EBUS_H
-#define __SPARC_EBUS_H
-
-#ifndef _LINUX_IOPORT_H
-#include <linux/ioport.h>
-#endif
-#include <linux/of_device.h>
-#include <asm/oplib.h>
-#include <asm/prom.h>
-
-struct linux_ebus_child {
-	struct linux_ebus_child		*next;
-	struct linux_ebus_device	*parent;
-	struct linux_ebus		*bus;
-	struct device_node		*prom_node;
-	struct resource			 resource[PROMREG_MAX];
-	int				 num_addrs;
-	unsigned int			 irqs[PROMINTR_MAX];
-	int				 num_irqs;
-};
-
-struct linux_ebus_device {
-	struct of_device		ofdev;
-	struct linux_ebus_device	*next;
-	struct linux_ebus_child		*children;
-	struct linux_ebus		*bus;
-	struct device_node		*prom_node;
-	struct resource			 resource[PROMREG_MAX];
-	int				 num_addrs;
-	unsigned int			 irqs[PROMINTR_MAX];
-	int				 num_irqs;
-};
-#define to_ebus_device(d) container_of(d, struct linux_ebus_device, ofdev.dev)
-
-struct linux_ebus {
-	struct of_device		ofdev;
-	struct linux_ebus		*next;
-	struct linux_ebus_device	*devices;
-	struct linux_pbm_info		*parent;
-	struct pci_dev			*self;
-	struct device_node		*prom_node;
-};
-#define to_ebus(d) container_of(d, struct linux_ebus, ofdev.dev)
-
-struct linux_ebus_dma {
-	unsigned int dcsr;
-	unsigned int dacr;
-	unsigned int dbcr;
-};
-
-#define EBUS_DCSR_INT_PEND	0x00000001
-#define EBUS_DCSR_ERR_PEND	0x00000002
-#define EBUS_DCSR_DRAIN		0x00000004
-#define EBUS_DCSR_INT_EN	0x00000010
-#define EBUS_DCSR_RESET		0x00000080
-#define EBUS_DCSR_WRITE		0x00000100
-#define EBUS_DCSR_EN_DMA	0x00000200
-#define EBUS_DCSR_CYC_PEND	0x00000400
-#define EBUS_DCSR_DIAG_RD_DONE	0x00000800
-#define EBUS_DCSR_DIAG_WR_DONE	0x00001000
-#define EBUS_DCSR_EN_CNT	0x00002000
-#define EBUS_DCSR_TC		0x00004000
-#define EBUS_DCSR_DIS_CSR_DRN	0x00010000
-#define EBUS_DCSR_BURST_SZ_MASK	0x000c0000
-#define EBUS_DCSR_BURST_SZ_1	0x00080000
-#define EBUS_DCSR_BURST_SZ_4	0x00000000
-#define EBUS_DCSR_BURST_SZ_8	0x00040000
-#define EBUS_DCSR_BURST_SZ_16	0x000c0000
-#define EBUS_DCSR_DIAG_EN	0x00100000
-#define EBUS_DCSR_DIS_ERR_PEND	0x00400000
-#define EBUS_DCSR_TCI_DIS	0x00800000
-#define EBUS_DCSR_EN_NEXT	0x01000000
-#define EBUS_DCSR_DMA_ON	0x02000000
-#define EBUS_DCSR_A_LOADED	0x04000000
-#define EBUS_DCSR_NA_LOADED	0x08000000
-#define EBUS_DCSR_DEV_ID_MASK	0xf0000000
-
-extern struct linux_ebus		*ebus_chain;
-
-extern void ebus_init(void);
-
-#define for_each_ebus(bus)						\
-        for((bus) = ebus_chain; (bus); (bus) = (bus)->next)
-
-#define for_each_ebusdev(dev, bus)					\
-        for((dev) = (bus)->devices; (dev); (dev) = (dev)->next)
-
-#define for_each_edevchild(dev, child)					\
-        for((child) = (dev)->children; (child); (child) = (child)->next)
-
-#endif /* !(__SPARC_EBUS_H) */
diff --git a/arch/sparc/include/asm/ebus_64.h b/arch/sparc/include/asm/ebus_64.h
deleted file mode 100644
index 14c6a11..0000000
--- a/arch/sparc/include/asm/ebus_64.h
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * ebus.h: PCI to Ebus pseudo driver software state.
- *
- * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be)
- * Copyright (C) 1999 David S. Miller (davem@redhat.com)
- */
-
-#ifndef __SPARC64_EBUS_H
-#define __SPARC64_EBUS_H
-
-#include <linux/of_device.h>
-
-#include <asm/oplib.h>
-#include <asm/prom.h>
-
-struct linux_ebus_child {
-	struct linux_ebus_child		*next;
-	struct linux_ebus_device	*parent;
-	struct linux_ebus		*bus;
-	struct device_node		*prom_node;
-	struct resource			 resource[PROMREG_MAX];
-	int				 num_addrs;
-	unsigned int			 irqs[PROMINTR_MAX];
-	int				 num_irqs;
-};
-
-struct linux_ebus_device {
-	struct of_device		ofdev;
-	struct linux_ebus_device	*next;
-	struct linux_ebus_child		*children;
-	struct linux_ebus		*bus;
-	struct device_node		*prom_node;
-	struct resource			 resource[PROMREG_MAX];
-	int				 num_addrs;
-	unsigned int			 irqs[PROMINTR_MAX];
-	int				 num_irqs;
-};
-#define to_ebus_device(d) container_of(d, struct linux_ebus_device, ofdev.dev)
-
-struct linux_ebus {
-	struct of_device		ofdev;
-	struct linux_ebus		*next;
-	struct linux_ebus_device	*devices;
-	struct pci_dev			*self;
-	int				 index;
-	int				 is_rio;
-	struct device_node		*prom_node;
-};
-#define to_ebus(d) container_of(d, struct linux_ebus, ofdev.dev)
-
-struct ebus_dma_info {
-	spinlock_t	lock;
-	void __iomem	*regs;
-
-	unsigned int	flags;
-#define EBUS_DMA_FLAG_USE_EBDMA_HANDLER		0x00000001
-#define EBUS_DMA_FLAG_TCI_DISABLE		0x00000002
-
-	/* These are only valid is EBUS_DMA_FLAG_USE_EBDMA_HANDLER is
-	 * set.
-	 */
-	void (*callback)(struct ebus_dma_info *p, int event, void *cookie);
-	void *client_cookie;
-	unsigned int	irq;
-#define EBUS_DMA_EVENT_ERROR	1
-#define EBUS_DMA_EVENT_DMA	2
-#define EBUS_DMA_EVENT_DEVICE	4
-
-	unsigned char	name[64];
-};
-
-extern int ebus_dma_register(struct ebus_dma_info *p);
-extern int ebus_dma_irq_enable(struct ebus_dma_info *p, int on);
-extern void ebus_dma_unregister(struct ebus_dma_info *p);
-extern int ebus_dma_request(struct ebus_dma_info *p, dma_addr_t bus_addr,
-			    size_t len);
-extern void ebus_dma_prepare(struct ebus_dma_info *p, int write);
-extern unsigned int ebus_dma_residue(struct ebus_dma_info *p);
-extern unsigned int ebus_dma_addr(struct ebus_dma_info *p);
-extern void ebus_dma_enable(struct ebus_dma_info *p, int on);
-
-extern struct linux_ebus		*ebus_chain;
-
-extern void ebus_init(void);
-
-#define for_each_ebus(bus)						\
-        for((bus) = ebus_chain; (bus); (bus) = (bus)->next)
-
-#define for_each_ebusdev(dev, bus)					\
-        for((dev) = (bus)->devices; (dev); (dev) = (dev)->next)
-
-#define for_each_edevchild(dev, child)					\
-        for((child) = (dev)->children; (child); (child) = (child)->next)
-
-#endif /* !(__SPARC64_EBUS_H) */
diff --git a/arch/sparc/include/asm/ebus_dma.h b/arch/sparc/include/asm/ebus_dma.h
new file mode 100644
index 0000000..f07a5b5
--- /dev/null
+++ b/arch/sparc/include/asm/ebus_dma.h
@@ -0,0 +1,35 @@
+#ifndef __ASM_SPARC_EBUS_DMA_H
+#define __ASM_SPARC_EBUS_DMA_H
+
+struct ebus_dma_info {
+	spinlock_t	lock;
+	void __iomem	*regs;
+
+	unsigned int	flags;
+#define EBUS_DMA_FLAG_USE_EBDMA_HANDLER		0x00000001
+#define EBUS_DMA_FLAG_TCI_DISABLE		0x00000002
+
+	/* These are only valid is EBUS_DMA_FLAG_USE_EBDMA_HANDLER is
+	 * set.
+	 */
+	void (*callback)(struct ebus_dma_info *p, int event, void *cookie);
+	void *client_cookie;
+	unsigned int	irq;
+#define EBUS_DMA_EVENT_ERROR	1
+#define EBUS_DMA_EVENT_DMA	2
+#define EBUS_DMA_EVENT_DEVICE	4
+
+	unsigned char	name[64];
+};
+
+extern int ebus_dma_register(struct ebus_dma_info *p);
+extern int ebus_dma_irq_enable(struct ebus_dma_info *p, int on);
+extern void ebus_dma_unregister(struct ebus_dma_info *p);
+extern int ebus_dma_request(struct ebus_dma_info *p, dma_addr_t bus_addr,
+			    size_t len);
+extern void ebus_dma_prepare(struct ebus_dma_info *p, int write);
+extern unsigned int ebus_dma_residue(struct ebus_dma_info *p);
+extern unsigned int ebus_dma_addr(struct ebus_dma_info *p);
+extern void ebus_dma_enable(struct ebus_dma_info *p, int on);
+
+#endif /* __ASM_SPARC_EBUS_DMA_H */
diff --git a/arch/sparc/include/asm/elf_32.h b/arch/sparc/include/asm/elf_32.h
index d043f80..b7ab605 100644
--- a/arch/sparc/include/asm/elf_32.h
+++ b/arch/sparc/include/asm/elf_32.h
@@ -105,11 +105,8 @@
 #define ELF_DATA	ELFDATA2MSB
 
 #define USE_ELF_CORE_DUMP
-#ifndef CONFIG_SUN4
+
 #define ELF_EXEC_PAGESIZE	4096
-#else
-#define ELF_EXEC_PAGESIZE	8192
-#endif
 
 
 /* This is the location that an ET_DYN program is loaded if exec'ed.  Typical
@@ -126,7 +123,7 @@
 /* Sun4c has none of the capabilities, most sun4m's have them all.
  * XXX This is gross, set some global variable at boot time. -DaveM
  */
-#define ELF_HWCAP	((ARCH_SUN4C_SUN4) ? 0 : \
+#define ELF_HWCAP	((ARCH_SUN4C) ? 0 : \
 			 (HWCAP_SPARC_FLUSH | HWCAP_SPARC_STBAR | \
 			  HWCAP_SPARC_SWAP | \
 			  ((srmmu_modtype != Cypress && \
diff --git a/arch/sparc/include/asm/fhc.h b/arch/sparc/include/asm/fhc.h
index 788cbc4..57f1b30 100644
--- a/arch/sparc/include/asm/fhc.h
+++ b/arch/sparc/include/asm/fhc.h
@@ -1,5 +1,4 @@
-/*
- * fhc.h: Structures for central/fhc pseudo driver on Sunfire/Starfire/Wildfire.
+/* fhc.h: FHC and Clock board register definitions.
  *
  * Copyright (C) 1997, 1999 David S. Miller (davem@redhat.com)
  */
@@ -7,14 +6,6 @@
 #ifndef _SPARC64_FHC_H
 #define _SPARC64_FHC_H
 
-#include <linux/timer.h>
-
-#include <asm/oplib.h>
-#include <asm/prom.h>
-#include <asm/upa.h>
-
-struct linux_fhc;
-
 /* Clock board register offsets. */
 #define CLOCK_CTRL	0x00UL	/* Main control */
 #define CLOCK_STAT1	0x10UL	/* Status one */
@@ -29,21 +20,7 @@
 #define CLOCK_CTRL_MLED		0x02	/* Mid LED, 1 == on */
 #define CLOCK_CTRL_RLED		0x01	/* RIght LED, 1 == on */
 
-struct linux_central {
-	struct linux_fhc		*child;
-	unsigned long			cfreg;
-	unsigned long			clkregs;
-	unsigned long			clkver;
-	int				slots;
-	struct device_node		*prom_node;
-
-	struct linux_prom_ranges	central_ranges[PROMREG_MAX];
-	int				num_central_ranges;
-};
-
 /* Firehose controller register offsets */
-struct fhc_regs {
-	unsigned long			pregs;	/* FHC internal regs */
 #define FHC_PREGS_ID	0x00UL	/* FHC ID */
 #define  FHC_ID_VERS		0xf0000000 /* Version of this FHC		*/
 #define  FHC_ID_PARTID		0x0ffff000 /* Part ID code (0x0f9f == FHC)	*/
@@ -90,32 +67,14 @@
 #define  FHC_JTAG_CTRL_MENAB	0x80000000 /* Indicates this is JTAG Master	 */
 #define  FHC_JTAG_CTRL_MNONE	0x40000000 /* Indicates no JTAG Master present	 */
 #define FHC_PREGS_JCMD	0x100UL	/* FHC JTAG Command Register */
-	unsigned long			ireg;	/* FHC IGN reg */
 #define FHC_IREG_IGN	0x00UL	/* This FHC's IGN */
-	unsigned long			ffregs;	/* FHC fanfail regs */
 #define FHC_FFREGS_IMAP	0x00UL	/* FHC Fanfail IMAP */
 #define FHC_FFREGS_ICLR	0x10UL	/* FHC Fanfail ICLR */
-	unsigned long			sregs;	/* FHC system regs */
 #define FHC_SREGS_IMAP	0x00UL	/* FHC System IMAP */
 #define FHC_SREGS_ICLR	0x10UL	/* FHC System ICLR */
-	unsigned long			uregs;	/* FHC uart regs */
 #define FHC_UREGS_IMAP	0x00UL	/* FHC Uart IMAP */
 #define FHC_UREGS_ICLR	0x10UL	/* FHC Uart ICLR */
-	unsigned long			tregs;	/* FHC TOD regs */
 #define FHC_TREGS_IMAP	0x00UL	/* FHC TOD IMAP */
 #define FHC_TREGS_ICLR	0x10UL	/* FHC TOD ICLR */
-};
-
-struct linux_fhc {
-	struct linux_fhc		*next;
-	struct linux_central		*parent;	/* NULL if not central FHC */
-	struct fhc_regs			fhc_regs;
-	int				board;
-	int				jtag_master;
-	struct device_node		*prom_node;
-
-	struct linux_prom_ranges	fhc_ranges[PROMREG_MAX];
-	int				num_fhc_ranges;
-};
 
 #endif /* !(_SPARC64_FHC_H) */
diff --git a/arch/sparc/include/asm/floppy_32.h b/arch/sparc/include/asm/floppy_32.h
index ae3f00b..c792830 100644
--- a/arch/sparc/include/asm/floppy_32.h
+++ b/arch/sparc/include/asm/floppy_32.h
@@ -6,6 +6,9 @@
 #ifndef __ASM_SPARC_FLOPPY_H
 #define __ASM_SPARC_FLOPPY_H
 
+#include <linux/of.h>
+#include <linux/of_device.h>
+
 #include <asm/page.h>
 #include <asm/pgtable.h>
 #include <asm/system.h>
@@ -343,7 +346,7 @@
 	r.flags = fd_regs[0].which_io;
 	r.start = fd_regs[0].phys_addr;
 	sun_fdc = (struct sun_flpy_controller *)
-	    sbus_ioremap(&r, 0, fd_regs[0].reg_size, "floppy");
+	    of_ioremap(&r, 0, fd_regs[0].reg_size, "floppy");
 
 	/* Last minute sanity check... */
 	if(sun_fdc->status_82072 == 0xff) {
@@ -385,4 +388,15 @@
 
 #define EXTRA_FLOPPY_PARAMS
 
+static DEFINE_SPINLOCK(dma_spin_lock);
+
+#define claim_dma_lock() \
+({	unsigned long flags; \
+	spin_lock_irqsave(&dma_spin_lock, flags); \
+	flags; \
+})
+
+#define release_dma_lock(__flags) \
+	spin_unlock_irqrestore(&dma_spin_lock, __flags);
+
 #endif /* !(__ASM_SPARC_FLOPPY_H) */
diff --git a/arch/sparc/include/asm/floppy_64.h b/arch/sparc/include/asm/floppy_64.h
index c39db10..36439d6 100644
--- a/arch/sparc/include/asm/floppy_64.h
+++ b/arch/sparc/include/asm/floppy_64.h
@@ -1,6 +1,6 @@
 /* floppy.h: Sparc specific parts of the Floppy driver.
  *
- * Copyright (C) 1996, 2007 David S. Miller (davem@davemloft.net)
+ * Copyright (C) 1996, 2007, 2008 David S. Miller (davem@davemloft.net)
  * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
  *
  * Ultra/PCI support added: Sep 1997  Eddie C. Dost  (ecd@skynet.be)
@@ -9,18 +9,11 @@
 #ifndef __ASM_SPARC64_FLOPPY_H
 #define __ASM_SPARC64_FLOPPY_H
 
-#include <linux/init.h>
-#include <linux/pci.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/dma-mapping.h>
 
-#include <asm/page.h>
-#include <asm/pgtable.h>
-#include <asm/system.h>
-#include <asm/idprom.h>
-#include <asm/oplib.h>
 #include <asm/auxio.h>
-#include <asm/sbus.h>
-#include <asm/irq.h>
-
 
 /*
  * Define this to enable exchanging drive 0 and 1 if only drive 1 is
@@ -50,7 +43,7 @@
 /* You'll only ever find one controller on an Ultra anyways. */
 static struct sun_flpy_controller *sun_fdc = (struct sun_flpy_controller *)-1;
 unsigned long fdc_status;
-static struct sbus_dev *floppy_sdev = NULL;
+static struct of_device *floppy_op = NULL;
 
 struct sun_floppy_ops {
 	unsigned char	(*fd_inb) (unsigned long port);
@@ -291,12 +284,11 @@
 	return 0;
 }
 
-#ifdef CONFIG_PCI
-#include <asm/ebus.h>
+#include <asm/ebus_dma.h>
 #include <asm/ns87303.h>
 
 static struct ebus_dma_info sun_pci_fd_ebus_dma;
-static struct pci_dev *sun_pci_ebus_dev;
+static struct device *sun_floppy_dev;
 static int sun_pci_broken_drive = -1;
 
 struct sun_pci_dma_op {
@@ -377,7 +369,7 @@
 	sun_pci_dma_pending.addr = -1U;
 
 	sun_pci_dma_current.addr =
-		pci_map_single(sun_pci_ebus_dev,
+		dma_map_single(sun_floppy_dev,
 			       sun_pci_dma_current.buf,
 			       sun_pci_dma_current.len,
 			       sun_pci_dma_current.direction);
@@ -394,7 +386,7 @@
 {
 	ebus_dma_enable(&sun_pci_fd_ebus_dma, 0);
 	if (sun_pci_dma_current.addr != -1U)
-		pci_unmap_single(sun_pci_ebus_dev,
+		dma_unmap_single(sun_floppy_dev,
 				 sun_pci_dma_current.addr,
 				 sun_pci_dma_current.len,
 				 sun_pci_dma_current.direction);
@@ -404,9 +396,9 @@
 static void sun_pci_fd_set_dma_mode(int mode)
 {
 	if (mode == DMA_MODE_WRITE)
-		sun_pci_dma_pending.direction = PCI_DMA_TODEVICE;
+		sun_pci_dma_pending.direction = DMA_TO_DEVICE;
 	else
-		sun_pci_dma_pending.direction = PCI_DMA_FROMDEVICE;
+		sun_pci_dma_pending.direction = DMA_FROM_DEVICE;
 
 	ebus_dma_prepare(&sun_pci_fd_ebus_dma, mode != DMA_MODE_WRITE);
 }
@@ -538,80 +530,84 @@
 #undef MSR
 #undef DOR
 
-#endif /* CONFIG_PCI */
-
-#ifdef CONFIG_PCI
-static int __init ebus_fdthree_p(struct linux_ebus_device *edev)
+static int __init ebus_fdthree_p(struct device_node *dp)
 {
-	if (!strcmp(edev->prom_node->name, "fdthree"))
+	if (!strcmp(dp->name, "fdthree"))
 		return 1;
-	if (!strcmp(edev->prom_node->name, "floppy")) {
+	if (!strcmp(dp->name, "floppy")) {
 		const char *compat;
 
-		compat = of_get_property(edev->prom_node,
-					 "compatible", NULL);
+		compat = of_get_property(dp, "compatible", NULL);
 		if (compat && !strcmp(compat, "fdthree"))
 			return 1;
 	}
 	return 0;
 }
-#endif
 
 static unsigned long __init sun_floppy_init(void)
 {
-	char state[128];
-	struct sbus_bus *bus;
-	struct sbus_dev *sdev = NULL;
 	static int initialized = 0;
+	struct device_node *dp;
+	struct of_device *op;
+	const char *prop;
+	char state[128];
 
 	if (initialized)
 		return sun_floppy_types[0];
 	initialized = 1;
 
-	for_all_sbusdev (sdev, bus) {
-		if (!strcmp(sdev->prom_name, "SUNW,fdtwo"))
+	op = NULL;
+
+	for_each_node_by_name(dp, "SUNW,fdtwo") {
+		if (strcmp(dp->parent->name, "sbus"))
+			continue;
+		op = of_find_device_by_node(dp);
+		if (op)
 			break;
 	}
-	if(sdev) {
-		floppy_sdev = sdev;
-		FLOPPY_IRQ = sdev->irqs[0];
+	if (op) {
+		floppy_op = op;
+		FLOPPY_IRQ = op->irqs[0];
 	} else {
-#ifdef CONFIG_PCI
-		struct linux_ebus *ebus;
-		struct linux_ebus_device *edev = NULL;
-		unsigned long config = 0;
+		struct device_node *ebus_dp;
 		void __iomem *auxio_reg;
 		const char *state_prop;
+		unsigned long config;
 
-		for_each_ebus(ebus) {
-			for_each_ebusdev(edev, ebus) {
-				if (ebus_fdthree_p(edev))
-					goto ebus_done;
+		dp = NULL;
+		for_each_node_by_name(ebus_dp, "ebus") {
+			for (dp = ebus_dp->child; dp; dp = dp->sibling) {
+				if (ebus_fdthree_p(dp))
+					goto found_fdthree;
 			}
 		}
-	ebus_done:
-		if (!edev)
+	found_fdthree:
+		if (!dp)
 			return 0;
 
-		state_prop = of_get_property(edev->prom_node, "status", NULL);
+		op = of_find_device_by_node(dp);
+		if (!op)
+			return 0;
+
+		state_prop = of_get_property(op->node, "status", NULL);
 		if (state_prop && !strncmp(state_prop, "disabled", 8))
 			return 0;
 
-		FLOPPY_IRQ = edev->irqs[0];
+		FLOPPY_IRQ = op->irqs[0];
 
 		/* Make sure the high density bit is set, some systems
 		 * (most notably Ultra5/Ultra10) come up with it clear.
 		 */
-		auxio_reg = (void __iomem *) edev->resource[2].start;
+		auxio_reg = (void __iomem *) op->resource[2].start;
 		writel(readl(auxio_reg)|0x2, auxio_reg);
 
-		sun_pci_ebus_dev = ebus->self;
+		sun_floppy_dev = &op->dev;
 
 		spin_lock_init(&sun_pci_fd_ebus_dma.lock);
 
 		/* XXX ioremap */
 		sun_pci_fd_ebus_dma.regs = (void __iomem *)
-			edev->resource[1].start;
+			op->resource[1].start;
 		if (!sun_pci_fd_ebus_dma.regs)
 			return 0;
 
@@ -625,7 +621,7 @@
 			return 0;
 
 		/* XXX ioremap */
-		sun_fdc = (struct sun_flpy_controller *)edev->resource[0].start;
+		sun_fdc = (struct sun_flpy_controller *) op->resource[0].start;
 
 		sun_fdops.fd_inb = sun_pci_fd_inb;
 		sun_fdops.fd_outb = sun_pci_fd_outb;
@@ -662,12 +658,15 @@
 		/*
 		 * Find NS87303 SuperIO config registers (through ecpp).
 		 */
-		for_each_ebus(ebus) {
-			for_each_ebusdev(edev, ebus) {
-				if (!strcmp(edev->prom_node->name, "ecpp")) {
-					config = edev->resource[1].start;
-					goto config_done;
-				}
+		config = 0;
+		for (dp = ebus_dp->child; dp; dp = dp->sibling) {
+			if (!strcmp(dp->name, "ecpp")) {
+				struct of_device *ecpp_op;
+
+				ecpp_op = of_find_device_by_node(dp);
+				if (ecpp_op)
+					config = ecpp_op->resource[1].start;
+				goto config_done;
 			}
 		}
 	config_done:
@@ -716,26 +715,23 @@
 #endif /* PCI_FDC_SWAP_DRIVES */
 
 		return sun_floppy_types[0];
-#else
-		return 0;
-#endif
 	}
-	prom_getproperty(sdev->prom_node, "status", state, sizeof(state));
-	if(!strncmp(state, "disabled", 8))
+	prop = of_get_property(op->node, "status", NULL);
+	if (prop && !strncmp(state, "disabled", 8))
 		return 0;
 
 	/*
-	 * We cannot do sbus_ioremap here: it does request_region,
+	 * We cannot do of_ioremap here: it does request_region,
 	 * which the generic floppy driver tries to do once again.
 	 * But we must use the sdev resource values as they have
 	 * had parent ranges applied.
 	 */
 	sun_fdc = (struct sun_flpy_controller *)
-		(sdev->resource[0].start +
-		 ((sdev->resource[0].flags & 0x1ffUL) << 32UL));
+		(op->resource[0].start +
+		 ((op->resource[0].flags & 0x1ffUL) << 32UL));
 
 	/* Last minute sanity check... */
-	if(sbus_readb(&sun_fdc->status1_82077) == 0xff) {
+	if (sbus_readb(&sun_fdc->status1_82077) == 0xff) {
 		sun_fdc = (struct sun_flpy_controller *)-1;
 		return 0;
 	}
diff --git a/arch/sparc/include/asm/gpio.h b/arch/sparc/include/asm/gpio.h
new file mode 100644
index 0000000..a0e3ac0
--- /dev/null
+++ b/arch/sparc/include/asm/gpio.h
@@ -0,0 +1,36 @@
+#ifndef __ASM_SPARC_GPIO_H
+#define __ASM_SPARC_GPIO_H
+
+#include <linux/errno.h>
+#include <asm-generic/gpio.h>
+
+#ifdef CONFIG_GPIOLIB
+
+static inline int gpio_get_value(unsigned int gpio)
+{
+	return __gpio_get_value(gpio);
+}
+
+static inline void gpio_set_value(unsigned int gpio, int value)
+{
+	__gpio_set_value(gpio, value);
+}
+
+static inline int gpio_cansleep(unsigned int gpio)
+{
+	return __gpio_cansleep(gpio);
+}
+
+static inline int gpio_to_irq(unsigned int gpio)
+{
+	return -ENOSYS;
+}
+
+static inline int irq_to_gpio(unsigned int irq)
+{
+	return -EINVAL;
+}
+
+#endif /* CONFIG_GPIOLIB */
+
+#endif /* __ASM_SPARC_GPIO_H */
diff --git a/arch/sparc/include/asm/io-unit.h b/arch/sparc/include/asm/io-unit.h
index 96823b4..01ab2f6 100644
--- a/arch/sparc/include/asm/io-unit.h
+++ b/arch/sparc/include/asm/io-unit.h
@@ -55,8 +55,4 @@
 #define IOUNIT_BMAPM_START	IOUNIT_BMAP2_END
 #define IOUNIT_BMAPM_END	((IOUNIT_DMA_SIZE - IOUNIT_DVMA_SIZE) >> PAGE_SHIFT)
 
-extern __u32 iounit_map_dma_init(struct sbus_bus *, int);
-#define iounit_map_dma_finish(sbus, addr, len) mmu_release_scsi_one(addr, len, sbus)
-extern __u32 iounit_map_dma_page(__u32, void *, struct sbus_bus *);
-
 #endif /* !(_SPARC_IO_UNIT_H) */
diff --git a/arch/sparc/include/asm/io_32.h b/arch/sparc/include/asm/io_32.h
index 10d7da4..93fe21e 100644
--- a/arch/sparc/include/asm/io_32.h
+++ b/arch/sparc/include/asm/io_32.h
@@ -293,14 +293,6 @@
 extern void pci_iounmap(struct pci_dev *dev, void __iomem *);
 
 /*
- * Bus number may be in res->flags... somewhere.
- */
-extern void __iomem *sbus_ioremap(struct resource *res, unsigned long offset,
-    unsigned long size, char *name);
-extern void sbus_iounmap(volatile void __iomem *vaddr, unsigned long size);
-
-
-/*
  * At the moment, we do not use CMOS_READ anywhere outside of rtc.c,
  * so rtc_port is static in it. This should not change unless a new
  * hardware pops up.
@@ -308,6 +300,17 @@
 #define RTC_PORT(x)   (rtc_port + (x))
 #define RTC_ALWAYS_BCD  0
 
+static inline int sbus_can_dma_64bit(void)
+{
+	return 0; /* actually, sparc_cpu_model==sun4d */
+}
+static inline int sbus_can_burst64(void)
+{
+	return 0; /* actually, sparc_cpu_model==sun4d */
+}
+struct device;
+extern void sbus_set_sbus64(struct device *, int);
+
 #endif
 
 #define __ARCH_HAS_NO_PAGE_ZERO_MAPPED		1
diff --git a/arch/sparc/include/asm/io_64.h b/arch/sparc/include/asm/io_64.h
index 0bff078..4aee21d 100644
--- a/arch/sparc/include/asm/io_64.h
+++ b/arch/sparc/include/asm/io_64.h
@@ -482,18 +482,16 @@
 extern void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long max);
 extern void pci_iounmap(struct pci_dev *dev, void __iomem *);
 
-/* Similarly for SBUS. */
-#define sbus_ioremap(__res, __offset, __size, __name) \
-({	unsigned long __ret; \
-	__ret  = (__res)->start + (((__res)->flags & 0x1ffUL) << 32UL); \
-	__ret += (unsigned long) (__offset); \
-	if (! request_region((__ret), (__size), (__name))) \
-		__ret = 0UL; \
-	(void __iomem *) __ret; \
-})
-
-#define sbus_iounmap(__addr, __size)	\
-	release_region((unsigned long)(__addr), (__size))
+static inline int sbus_can_dma_64bit(void)
+{
+	return 1;
+}
+static inline int sbus_can_burst64(void)
+{
+	return 1;
+}
+struct device;
+extern void sbus_set_sbus64(struct device *, int);
 
 /*
  * Convert a physical pointer to a virtual kernel pointer for /dev/mem
diff --git a/arch/sparc/include/asm/iommu_64.h b/arch/sparc/include/asm/iommu_64.h
index d7b9afc..caf798b 100644
--- a/arch/sparc/include/asm/iommu_64.h
+++ b/arch/sparc/include/asm/iommu_64.h
@@ -48,6 +48,9 @@
 	unsigned long		strbuf_control;
 	unsigned long		strbuf_pflush;
 	unsigned long		strbuf_fsync;
+	unsigned long		strbuf_err_stat;
+	unsigned long		strbuf_tag_diag;
+	unsigned long		strbuf_line_diag;
 	unsigned long		strbuf_ctxflush;
 	unsigned long		strbuf_ctxmatch_base;
 	unsigned long		strbuf_flushflag_pa;
diff --git a/arch/sparc/include/asm/irq_64.h b/arch/sparc/include/asm/irq_64.h
index e3dd930..71673ec 100644
--- a/arch/sparc/include/asm/irq_64.h
+++ b/arch/sparc/include/asm/irq_64.h
@@ -56,7 +56,6 @@
 				    unsigned long imap_base,
 				    unsigned long iclr_base);
 extern void sun4u_destroy_msi(unsigned int virt_irq);
-extern unsigned int sbus_build_irq(void *sbus, unsigned int ino);
 
 extern unsigned char virt_irq_alloc(unsigned int dev_handle,
 				    unsigned int dev_ino);
diff --git a/arch/sparc/include/asm/mc146818rtc_64.h b/arch/sparc/include/asm/mc146818rtc_64.h
index e9c0fcc..7238d17 100644
--- a/arch/sparc/include/asm/mc146818rtc_64.h
+++ b/arch/sparc/include/asm/mc146818rtc_64.h
@@ -7,12 +7,8 @@
 #include <asm/io.h>
 
 #ifndef RTC_PORT
-#ifdef CONFIG_PCI
-extern unsigned long ds1287_regs;
-#else
-#define ds1287_regs (0UL)
-#endif
-#define RTC_PORT(x)	(ds1287_regs + (x))
+extern unsigned long cmos_regs;
+#define RTC_PORT(x)	(cmos_regs + (x))
 #define RTC_ALWAYS_BCD	0
 #endif
 
@@ -29,6 +25,4 @@
 outb_p((val),RTC_PORT(1)); \
 })
 
-#define RTC_IRQ 8
-
 #endif /* __ASM_SPARC64_MC146818RTC_H */
diff --git a/arch/sparc/include/asm/memctrl.h b/arch/sparc/include/asm/memctrl.h
new file mode 100644
index 0000000..4065c56
--- /dev/null
+++ b/arch/sparc/include/asm/memctrl.h
@@ -0,0 +1,9 @@
+#ifndef _SPARC_MEMCTRL_H
+#define _SPARC_MEMCTRL_H
+
+typedef int (*dimm_printer_t)(int synd_code, unsigned long paddr, char *buf, int buflen);
+
+int register_dimm_printer(dimm_printer_t func);
+void unregister_dimm_printer(dimm_printer_t func);
+
+#endif /* _SPARC_MEMCTRL_H */
diff --git a/arch/sparc/include/asm/mostek.h b/arch/sparc/include/asm/mostek.h
deleted file mode 100644
index 433be3e..0000000
--- a/arch/sparc/include/asm/mostek.h
+++ /dev/null
@@ -1,8 +0,0 @@
-#ifndef ___ASM_SPARC_MOSTEK_H
-#define ___ASM_SPARC_MOSTEK_H
-#if defined(__sparc__) && defined(__arch64__)
-#include <asm/mostek_64.h>
-#else
-#include <asm/mostek_32.h>
-#endif
-#endif
diff --git a/arch/sparc/include/asm/mostek_32.h b/arch/sparc/include/asm/mostek_32.h
deleted file mode 100644
index a99590c..0000000
--- a/arch/sparc/include/asm/mostek_32.h
+++ /dev/null
@@ -1,171 +0,0 @@
-/*
- * mostek.h:  Describes the various Mostek time of day clock registers.
- *
- * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
- * Copyright (C) 1996 Thomas K. Dyas (tdyas@eden.rutgers.edu)
- * Added intersil code 05/25/98 Chris Davis (cdavis@cois.on.ca)
- */
-
-#ifndef _SPARC_MOSTEK_H
-#define _SPARC_MOSTEK_H
-
-#include <asm/idprom.h>
-#include <asm/io.h>
-
-/*       M48T02 Register Map (adapted from Sun NVRAM/Hostid FAQ)
- *
- *                             Data
- * Address                                                 Function
- *        Bit 7 Bit 6 Bit 5 Bit 4Bit 3 Bit 2 Bit 1 Bit 0
- *   7ff  -     -     -     -    -     -     -     -       Year 00-99
- *   7fe  0     0     0     -    -     -     -     -      Month 01-12
- *   7fd  0     0     -     -    -     -     -     -       Date 01-31
- *   7fc  0     FT    0     0    0     -     -     -        Day 01-07
- *   7fb  KS    0     -     -    -     -     -     -      Hours 00-23
- *   7fa  0     -     -     -    -     -     -     -    Minutes 00-59
- *   7f9  ST    -     -     -    -     -     -     -    Seconds 00-59
- *   7f8  W     R     S     -    -     -     -     -    Control
- *
- *   * ST is STOP BIT
- *   * W is WRITE BIT
- *   * R is READ BIT
- *   * S is SIGN BIT
- *   * FT is FREQ TEST BIT
- *   * KS is KICK START BIT
- */
-
-/* The Mostek 48t02 real time clock and NVRAM chip. The registers
- * other than the control register are in binary coded decimal. Some
- * control bits also live outside the control register.
- */
-#define mostek_read(_addr)		readb(_addr)
-#define mostek_write(_addr,_val)	writeb(_val, _addr)
-#define MOSTEK_EEPROM		0x0000UL
-#define MOSTEK_IDPROM		0x07d8UL
-#define MOSTEK_CREG		0x07f8UL
-#define MOSTEK_SEC		0x07f9UL
-#define MOSTEK_MIN		0x07faUL
-#define MOSTEK_HOUR		0x07fbUL
-#define MOSTEK_DOW		0x07fcUL
-#define MOSTEK_DOM		0x07fdUL
-#define MOSTEK_MONTH		0x07feUL
-#define MOSTEK_YEAR		0x07ffUL
-
-struct mostek48t02 {
-	volatile char eeprom[2008];	/* This is the eeprom, don't touch! */
-	struct idprom idprom;		/* The idprom lives here. */
-	volatile unsigned char creg;	/* Control register */
-	volatile unsigned char sec;	/* Seconds (0-59) */
-	volatile unsigned char min;	/* Minutes (0-59) */
-	volatile unsigned char hour;	/* Hour (0-23) */
-	volatile unsigned char dow;	/* Day of the week (1-7) */
-	volatile unsigned char dom;	/* Day of the month (1-31) */
-	volatile unsigned char month;	/* Month of year (1-12) */
-	volatile unsigned char year;	/* Year (0-99) */
-};
-
-extern spinlock_t mostek_lock;
-extern void __iomem *mstk48t02_regs;
-
-/* Control register values. */
-#define	MSTK_CREG_WRITE	0x80	/* Must set this before placing values. */
-#define	MSTK_CREG_READ	0x40	/* Stop updates to allow a clean read. */
-#define	MSTK_CREG_SIGN	0x20	/* Slow/speed clock in calibration mode. */
-
-/* Control bits that live in the other registers. */
-#define	MSTK_STOP	0x80	/* Stop the clock oscillator. (sec) */
-#define	MSTK_KICK_START	0x80	/* Kick start the clock chip. (hour) */
-#define MSTK_FREQ_TEST	0x40	/* Frequency test mode. (day) */
-
-#define MSTK_YEAR_ZERO       1968   /* If year reg has zero, it is 1968. */
-#define MSTK_CVT_YEAR(yr)  ((yr) + MSTK_YEAR_ZERO)
-
-/* Masks that define how much space each value takes up. */
-#define	MSTK_SEC_MASK	0x7f
-#define	MSTK_MIN_MASK	0x7f
-#define	MSTK_HOUR_MASK	0x3f
-#define	MSTK_DOW_MASK	0x07
-#define	MSTK_DOM_MASK	0x3f
-#define	MSTK_MONTH_MASK	0x1f
-#define	MSTK_YEAR_MASK	0xffU
-
-/* Binary coded decimal conversion macros. */
-#define MSTK_REGVAL_TO_DECIMAL(x)  (((x) & 0x0F) + 0x0A * ((x) >> 0x04))
-#define MSTK_DECIMAL_TO_REGVAL(x)  ((((x) / 0x0A) << 0x04) + ((x) % 0x0A))
-
-/* Generic register set and get macros for internal use. */
-#define MSTK_GET(regs,var,mask) (MSTK_REGVAL_TO_DECIMAL(((struct mostek48t02 *)regs)->var & MSTK_ ## mask ## _MASK))
-#define MSTK_SET(regs,var,value,mask) do { ((struct mostek48t02 *)regs)->var &= ~(MSTK_ ## mask ## _MASK); ((struct mostek48t02 *)regs)->var |= MSTK_DECIMAL_TO_REGVAL(value) & (MSTK_ ## mask ## _MASK); } while (0)
-
-/* Macros to make register access easier on our fingers. These give you
- * the decimal value of the register requested if applicable. You pass
- * the a pointer to a 'struct mostek48t02'.
- */
-#define	MSTK_REG_CREG(regs)	(((struct mostek48t02 *)regs)->creg)
-#define	MSTK_REG_SEC(regs)	MSTK_GET(regs,sec,SEC)
-#define	MSTK_REG_MIN(regs)	MSTK_GET(regs,min,MIN)
-#define	MSTK_REG_HOUR(regs)	MSTK_GET(regs,hour,HOUR)
-#define	MSTK_REG_DOW(regs)	MSTK_GET(regs,dow,DOW)
-#define	MSTK_REG_DOM(regs)	MSTK_GET(regs,dom,DOM)
-#define	MSTK_REG_MONTH(regs)	MSTK_GET(regs,month,MONTH)
-#define	MSTK_REG_YEAR(regs)	MSTK_GET(regs,year,YEAR)
-
-#define	MSTK_SET_REG_SEC(regs,value)	MSTK_SET(regs,sec,value,SEC)
-#define	MSTK_SET_REG_MIN(regs,value)	MSTK_SET(regs,min,value,MIN)
-#define	MSTK_SET_REG_HOUR(regs,value)	MSTK_SET(regs,hour,value,HOUR)
-#define	MSTK_SET_REG_DOW(regs,value)	MSTK_SET(regs,dow,value,DOW)
-#define	MSTK_SET_REG_DOM(regs,value)	MSTK_SET(regs,dom,value,DOM)
-#define	MSTK_SET_REG_MONTH(regs,value)	MSTK_SET(regs,month,value,MONTH)
-#define	MSTK_SET_REG_YEAR(regs,value)	MSTK_SET(regs,year,value,YEAR)
-
-
-/* The Mostek 48t08 clock chip. Found on Sun4m's I think. It has the
- * same (basically) layout of the 48t02 chip except for the extra
- * NVRAM on board (8 KB against the 48t02's 2 KB).
- */
-struct mostek48t08 {
-	char offset[6*1024];         /* Magic things may be here, who knows? */
-	struct mostek48t02 regs;     /* Here is what we are interested in.   */
-};
-
-#ifdef CONFIG_SUN4
-enum sparc_clock_type {	MSTK48T02, MSTK48T08, \
-INTERSIL, MSTK_INVALID };
-#else
-enum sparc_clock_type {	MSTK48T02, MSTK48T08, \
-MSTK_INVALID };
-#endif
-
-#ifdef CONFIG_SUN4
-/* intersil on a sun 4/260 code  data from harris doc */
-struct intersil_dt {
-        volatile unsigned char int_csec;
-        volatile unsigned char int_hour;
-        volatile unsigned char int_min;
-        volatile unsigned char int_sec;
-        volatile unsigned char int_month;
-        volatile unsigned char int_day;
-        volatile unsigned char int_year;
-        volatile unsigned char int_dow;
-};
-
-struct intersil {
-	struct intersil_dt clk;
-	struct intersil_dt cmp;
-	volatile unsigned char int_intr_reg;
-	volatile unsigned char int_cmd_reg;
-};
-
-#define INTERSIL_STOP        0x0
-#define INTERSIL_START       0x8
-#define INTERSIL_INTR_DISABLE   0x0
-#define INTERSIL_INTR_ENABLE   0x10
-#define INTERSIL_32K		0x0
-#define INTERSIL_NORMAL		0x0
-#define INTERSIL_24H		0x4
-#define INTERSIL_INT_100HZ	0x2
-
-/* end of intersil info */
-#endif
-
-#endif /* !(_SPARC_MOSTEK_H) */
diff --git a/arch/sparc/include/asm/mostek_64.h b/arch/sparc/include/asm/mostek_64.h
deleted file mode 100644
index c5652de..0000000
--- a/arch/sparc/include/asm/mostek_64.h
+++ /dev/null
@@ -1,143 +0,0 @@
-/* mostek.h:  Describes the various Mostek time of day clock registers.
- *
- * Copyright (C) 1995 David S. Miller (davem@davemloft.net)
- * Copyright (C) 1996 Thomas K. Dyas (tdyas@eden.rutgers.edu)
- */
-
-#ifndef _SPARC64_MOSTEK_H
-#define _SPARC64_MOSTEK_H
-
-#include <asm/idprom.h>
-
-/*       M48T02 Register Map (adapted from Sun NVRAM/Hostid FAQ)
- *
- *                             Data
- * Address                                                 Function
- *        Bit 7 Bit 6 Bit 5 Bit 4Bit 3 Bit 2 Bit 1 Bit 0
- *   7ff  -     -     -     -    -     -     -     -       Year 00-99
- *   7fe  0     0     0     -    -     -     -     -      Month 01-12
- *   7fd  0     0     -     -    -     -     -     -       Date 01-31
- *   7fc  0     FT    0     0    0     -     -     -        Day 01-07
- *   7fb  KS    0     -     -    -     -     -     -      Hours 00-23
- *   7fa  0     -     -     -    -     -     -     -    Minutes 00-59
- *   7f9  ST    -     -     -    -     -     -     -    Seconds 00-59
- *   7f8  W     R     S     -    -     -     -     -    Control
- *
- *   * ST is STOP BIT
- *   * W is WRITE BIT
- *   * R is READ BIT
- *   * S is SIGN BIT
- *   * FT is FREQ TEST BIT
- *   * KS is KICK START BIT
- */
-
-/* The Mostek 48t02 real time clock and NVRAM chip. The registers
- * other than the control register are in binary coded decimal. Some
- * control bits also live outside the control register.
- *
- * We now deal with physical addresses for I/O to the chip. -DaveM
- */
-static inline u8 mostek_read(void __iomem *addr)
-{
-	u8 ret;
-
-	__asm__ __volatile__("lduba	[%1] %2, %0"
-			     : "=r" (ret)
-			     : "r" (addr), "i" (ASI_PHYS_BYPASS_EC_E));
-	return ret;
-}
-
-static inline void mostek_write(void __iomem *addr, u8 val)
-{
-	__asm__ __volatile__("stba	%0, [%1] %2"
-			     : /* no outputs */
-			     : "r" (val), "r" (addr), "i" (ASI_PHYS_BYPASS_EC_E));
-}
-
-#define MOSTEK_EEPROM		0x0000UL
-#define MOSTEK_IDPROM		0x07d8UL
-#define MOSTEK_CREG		0x07f8UL
-#define MOSTEK_SEC		0x07f9UL
-#define MOSTEK_MIN		0x07faUL
-#define MOSTEK_HOUR		0x07fbUL
-#define MOSTEK_DOW		0x07fcUL
-#define MOSTEK_DOM		0x07fdUL
-#define MOSTEK_MONTH		0x07feUL
-#define MOSTEK_YEAR		0x07ffUL
-
-extern spinlock_t mostek_lock;
-extern void __iomem *mstk48t02_regs;
-
-/* Control register values. */
-#define	MSTK_CREG_WRITE	0x80	/* Must set this before placing values. */
-#define	MSTK_CREG_READ	0x40	/* Stop updates to allow a clean read. */
-#define	MSTK_CREG_SIGN	0x20	/* Slow/speed clock in calibration mode. */
-
-/* Control bits that live in the other registers. */
-#define	MSTK_STOP	0x80	/* Stop the clock oscillator. (sec) */
-#define	MSTK_KICK_START	0x80	/* Kick start the clock chip. (hour) */
-#define MSTK_FREQ_TEST	0x40	/* Frequency test mode. (day) */
-
-#define MSTK_YEAR_ZERO       1968   /* If year reg has zero, it is 1968. */
-#define MSTK_CVT_YEAR(yr)  ((yr) + MSTK_YEAR_ZERO)
-
-/* Masks that define how much space each value takes up. */
-#define	MSTK_SEC_MASK	0x7f
-#define	MSTK_MIN_MASK	0x7f
-#define	MSTK_HOUR_MASK	0x3f
-#define	MSTK_DOW_MASK	0x07
-#define	MSTK_DOM_MASK	0x3f
-#define	MSTK_MONTH_MASK	0x1f
-#define	MSTK_YEAR_MASK	0xffU
-
-/* Binary coded decimal conversion macros. */
-#define MSTK_REGVAL_TO_DECIMAL(x)  (((x) & 0x0F) + 0x0A * ((x) >> 0x04))
-#define MSTK_DECIMAL_TO_REGVAL(x)  ((((x) / 0x0A) << 0x04) + ((x) % 0x0A))
-
-/* Generic register set and get macros for internal use. */
-#define MSTK_GET(regs,name)	\
-	(MSTK_REGVAL_TO_DECIMAL(mostek_read(regs + MOSTEK_ ## name) & MSTK_ ## name ## _MASK))
-#define MSTK_SET(regs,name,value) \
-do {	u8 __val = mostek_read(regs + MOSTEK_ ## name); \
-	__val &= ~(MSTK_ ## name ## _MASK); \
-	__val |= (MSTK_DECIMAL_TO_REGVAL(value) & \
-		  (MSTK_ ## name ## _MASK)); \
-	mostek_write(regs + MOSTEK_ ## name, __val); \
-} while(0)
-
-/* Macros to make register access easier on our fingers. These give you
- * the decimal value of the register requested if applicable. You pass
- * the a pointer to a 'struct mostek48t02'.
- */
-#define	MSTK_REG_CREG(regs)	(mostek_read((regs) + MOSTEK_CREG))
-#define	MSTK_REG_SEC(regs)	MSTK_GET(regs,SEC)
-#define	MSTK_REG_MIN(regs)	MSTK_GET(regs,MIN)
-#define	MSTK_REG_HOUR(regs)	MSTK_GET(regs,HOUR)
-#define	MSTK_REG_DOW(regs)	MSTK_GET(regs,DOW)
-#define	MSTK_REG_DOM(regs)	MSTK_GET(regs,DOM)
-#define	MSTK_REG_MONTH(regs)	MSTK_GET(regs,MONTH)
-#define	MSTK_REG_YEAR(regs)	MSTK_GET(regs,YEAR)
-
-#define	MSTK_SET_REG_SEC(regs,value)	MSTK_SET(regs,SEC,value)
-#define	MSTK_SET_REG_MIN(regs,value)	MSTK_SET(regs,MIN,value)
-#define	MSTK_SET_REG_HOUR(regs,value)	MSTK_SET(regs,HOUR,value)
-#define	MSTK_SET_REG_DOW(regs,value)	MSTK_SET(regs,DOW,value)
-#define	MSTK_SET_REG_DOM(regs,value)	MSTK_SET(regs,DOM,value)
-#define	MSTK_SET_REG_MONTH(regs,value)	MSTK_SET(regs,MONTH,value)
-#define	MSTK_SET_REG_YEAR(regs,value)	MSTK_SET(regs,YEAR,value)
-
-
-/* The Mostek 48t08 clock chip. Found on Sun4m's I think. It has the
- * same (basically) layout of the 48t02 chip except for the extra
- * NVRAM on board (8 KB against the 48t02's 2 KB).
- */
-#define MOSTEK_48T08_OFFSET	0x0000UL	/* Lower NVRAM portions */
-#define MOSTEK_48T08_48T02	0x1800UL	/* Offset to 48T02 chip */
-
-/* SUN5 systems usually have 48t59 model clock chipsets.  But we keep the older
- * clock chip definitions around just in case.
- */
-#define MOSTEK_48T59_OFFSET	0x0000UL	/* Lower NVRAM portions */
-#define MOSTEK_48T59_48T02	0x1800UL	/* Offset to 48T02 chip */
-
-#endif /* !(_SPARC64_MOSTEK_H) */
diff --git a/arch/sparc/include/asm/obio.h b/arch/sparc/include/asm/obio.h
index 1a7544c..4ade0c8 100644
--- a/arch/sparc/include/asm/obio.h
+++ b/arch/sparc/include/asm/obio.h
@@ -155,17 +155,6 @@
 			      "i" (ASI_M_CTL));
 }
 
-extern unsigned char cpu_leds[32];
-
-static inline void show_leds(int cpuid)
-{
-	cpuid &= 0x1e;
-	__asm__ __volatile__ ("stba %0, [%1] %2" : :
-			      "r" ((cpu_leds[cpuid] << 4) | cpu_leds[cpuid+1]),
-			      "r" (ECSR_BASE(cpuid) | BB_LEDS),
-			      "i" (ASI_M_CTL));
-}
-
 static inline unsigned cc_get_ipen(void)
 {
 	unsigned pending;
diff --git a/arch/sparc/include/asm/of_device.h b/arch/sparc/include/asm/of_device.h
index bba777a..a5d9811 100644
--- a/arch/sparc/include/asm/of_device.h
+++ b/arch/sparc/include/asm/of_device.h
@@ -30,6 +30,8 @@
 extern void __iomem *of_ioremap(struct resource *res, unsigned long offset, unsigned long size, char *name);
 extern void of_iounmap(struct resource *res, void __iomem *base, unsigned long size);
 
+extern void of_propagate_archdata(struct of_device *bus);
+
 /* This is just here during the transition */
 #include <linux/of_platform.h>
 
diff --git a/arch/sparc/include/asm/of_platform.h b/arch/sparc/include/asm/of_platform.h
index 2348ab9..90da990 100644
--- a/arch/sparc/include/asm/of_platform.h
+++ b/arch/sparc/include/asm/of_platform.h
@@ -13,9 +13,6 @@
  *
  */
 
-extern struct bus_type ebus_bus_type;
-extern struct bus_type sbus_bus_type;
-
 #define of_bus_type	of_platform_bus_type	/* for compatibility */
 
 #endif
diff --git a/arch/sparc/include/asm/oplib_32.h b/arch/sparc/include/asm/oplib_32.h
index b2631da..699da05 100644
--- a/arch/sparc/include/asm/oplib_32.h
+++ b/arch/sparc/include/asm/oplib_32.h
@@ -21,7 +21,6 @@
 	PROM_V2,      /* sun4c and early sun4m V2 prom */
 	PROM_V3,      /* sun4m and later, up to sun4d/sun4e machines V3 */
 	PROM_P1275,   /* IEEE compliant ISA based Sun PROM, only sun4u */
-	PROM_SUN4,    /* Old sun4 proms are totally different, but we'll shoehorn it to make it fit */
 };
 
 extern enum prom_major_version prom_vers;
diff --git a/arch/sparc/include/asm/page_32.h b/arch/sparc/include/asm/page_32.h
index cf5fb70..d1806ed 100644
--- a/arch/sparc/include/asm/page_32.h
+++ b/arch/sparc/include/asm/page_32.h
@@ -8,11 +8,8 @@
 #ifndef _SPARC_PAGE_H
 #define _SPARC_PAGE_H
 
-#ifdef CONFIG_SUN4
-#define PAGE_SHIFT   13
-#else
 #define PAGE_SHIFT   12
-#endif
+
 #ifndef __ASSEMBLY__
 /* I have my suspicions... -DaveM */
 #define PAGE_SIZE    (1UL << PAGE_SHIFT)
diff --git a/arch/sparc/include/asm/page_64.h b/arch/sparc/include/asm/page_64.h
index b579b91..4274ed1 100644
--- a/arch/sparc/include/asm/page_64.h
+++ b/arch/sparc/include/asm/page_64.h
@@ -38,6 +38,8 @@
 
 #ifndef __ASSEMBLY__
 
+#define WANT_PAGE_VIRTUAL
+
 extern void _clear_page(void *page);
 #define clear_page(X)	_clear_page((void *)(X))
 struct page;
diff --git a/arch/sparc/include/asm/parport.h b/arch/sparc/include/asm/parport.h
index d983062..dff3f02 100644
--- a/arch/sparc/include/asm/parport.h
+++ b/arch/sparc/include/asm/parport.h
@@ -8,7 +8,7 @@
 
 #include <linux/of_device.h>
 
-#include <asm/ebus.h>
+#include <asm/ebus_dma.h>
 #include <asm/ns87303.h>
 #include <asm/prom.h>
 
@@ -215,7 +215,7 @@
 	return 0;
 }
 
-static struct of_device_id ecpp_match[] = {
+static const struct of_device_id ecpp_match[] = {
 	{
 		.name = "ecpp",
 	},
diff --git a/arch/sparc/include/asm/pci_32.h b/arch/sparc/include/asm/pci_32.h
index 0ee949d..b41c4c1 100644
--- a/arch/sparc/include/asm/pci_32.h
+++ b/arch/sparc/include/asm/pci_32.h
@@ -3,6 +3,8 @@
 
 #ifdef __KERNEL__
 
+#include <linux/dma-mapping.h>
+
 /* Can be used to override the logic in pci_scan_bus for skipping
  * already-configured bus numbers - to be used for buggy BIOSes
  * or architectures with incomplete PCI setup by the loader.
diff --git a/arch/sparc/include/asm/pgtable_32.h b/arch/sparc/include/asm/pgtable_32.h
index 08237fd..e0cabe7 100644
--- a/arch/sparc/include/asm/pgtable_32.h
+++ b/arch/sparc/include/asm/pgtable_32.h
@@ -14,11 +14,7 @@
 #include <linux/spinlock.h>
 #include <linux/swap.h>
 #include <asm/types.h>
-#ifdef CONFIG_SUN4
-#include <asm/pgtsun4.h>
-#else
 #include <asm/pgtsun4c.h>
-#endif
 #include <asm/pgtsrmmu.h>
 #include <asm/vac-ops.h>
 #include <asm/oplib.h>
diff --git a/arch/sparc/include/asm/pgtable_64.h b/arch/sparc/include/asm/pgtable_64.h
index bb9ec2c..b049abf 100644
--- a/arch/sparc/include/asm/pgtable_64.h
+++ b/arch/sparc/include/asm/pgtable_64.h
@@ -770,6 +770,8 @@
 
 extern unsigned long cmdline_memory_size;
 
+extern asmlinkage void do_sparc64_fault(struct pt_regs *regs);
+
 #endif /* !(__ASSEMBLY__) */
 
 #endif /* !(_SPARC64_PGTABLE_H) */
diff --git a/arch/sparc/include/asm/prom.h b/arch/sparc/include/asm/prom.h
index fd55522..900d447 100644
--- a/arch/sparc/include/asm/prom.h
+++ b/arch/sparc/include/asm/prom.h
@@ -18,6 +18,7 @@
  */
 #include <linux/types.h>
 #include <linux/proc_fs.h>
+#include <linux/mutex.h>
 #include <asm/atomic.h>
 
 #define OF_ROOT_NODE_ADDR_CELLS_DEFAULT	2
@@ -73,6 +74,7 @@
 
 extern struct device_node *of_find_node_by_cpuid(int cpuid);
 extern int of_set_property(struct device_node *node, const char *name, void *val, int len);
+extern struct mutex of_set_property_mutex;
 extern int of_getintprop_default(struct device_node *np,
 				 const char *name,
 				 int def);
@@ -94,6 +96,16 @@
 {
 }
 
+/* These routines are here to provide compatibility with how powerpc
+ * handles IRQ mapping for OF device nodes.  We precompute and permanently
+ * register them in the of_device objects, whereas powerpc computes them
+ * on request.
+ */
+extern unsigned int irq_of_parse_and_map(struct device_node *node, int index);
+static inline void irq_dispose_mapping(unsigned int virq)
+{
+}
+
 /*
  * NB:  This is here while we transition from using asm/prom.h
  * to linux/of.h
diff --git a/arch/sparc/include/asm/ptrace_64.h b/arch/sparc/include/asm/ptrace_64.h
index 06e4914..3d3e9c1 100644
--- a/arch/sparc/include/asm/ptrace_64.h
+++ b/arch/sparc/include/asm/ptrace_64.h
@@ -113,6 +113,8 @@
 
 #ifdef __KERNEL__
 
+#include <linux/threads.h>
+
 static inline int pt_regs_trap_type(struct pt_regs *regs)
 {
 	return regs->magic & 0x1ff;
@@ -138,6 +140,7 @@
 	struct thread_info	*thread;
 	unsigned long		pad1;
 };
+extern struct global_reg_snapshot global_reg_snapshot[NR_CPUS];
 
 #define __ARCH_WANT_COMPAT_SYS_PTRACE
 
diff --git a/arch/sparc/include/asm/reboot.h b/arch/sparc/include/asm/reboot.h
deleted file mode 100644
index 3f3f43f..0000000
--- a/arch/sparc/include/asm/reboot.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef _SPARC64_REBOOT_H
-#define _SPARC64_REBOOT_H
-
-extern void machine_alt_power_off(void);
-
-#endif /* _SPARC64_REBOOT_H */
diff --git a/arch/sparc/include/asm/rtc.h b/arch/sparc/include/asm/rtc.h
deleted file mode 100644
index f9ecb1f..0000000
--- a/arch/sparc/include/asm/rtc.h
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * rtc.h: Definitions for access to the Mostek real time clock
- *
- * Copyright (C) 1996 Thomas K. Dyas (tdyas@eden.rutgers.edu)
- */
-
-#ifndef _RTC_H
-#define _RTC_H
-
-#include <linux/ioctl.h>
-
-struct rtc_time
-{
-	int	sec;	/* Seconds (0-59) */
-	int	min;	/* Minutes (0-59) */
-	int	hour;	/* Hour (0-23) */
-	int	dow;	/* Day of the week (1-7) */
-	int	dom;	/* Day of the month (1-31) */
-	int	month;	/* Month of year (1-12) */
-	int	year;	/* Year (0-99) */
-};
-
-#define RTCGET _IOR('p', 20, struct rtc_time)
-#define RTCSET _IOW('p', 21, struct rtc_time)
-
-#endif
diff --git a/arch/sparc/include/asm/sbus.h b/arch/sparc/include/asm/sbus.h
deleted file mode 100644
index f82481a..0000000
--- a/arch/sparc/include/asm/sbus.h
+++ /dev/null
@@ -1,8 +0,0 @@
-#ifndef ___ASM_SPARC_SBUS_H
-#define ___ASM_SPARC_SBUS_H
-#if defined(__sparc__) && defined(__arch64__)
-#include <asm/sbus_64.h>
-#else
-#include <asm/sbus_32.h>
-#endif
-#endif
diff --git a/arch/sparc/include/asm/sbus_32.h b/arch/sparc/include/asm/sbus_32.h
deleted file mode 100644
index a7b4fa2..0000000
--- a/arch/sparc/include/asm/sbus_32.h
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- * sbus.h:  Defines for the Sun SBus.
- *
- * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
- */
-
-#ifndef _SPARC_SBUS_H
-#define _SPARC_SBUS_H
-
-#include <linux/dma-mapping.h>
-#include <linux/ioport.h>
-#include <linux/of_device.h>
-
-#include <asm/oplib.h>
-#include <asm/prom.h>
-#include <asm/scatterlist.h>
-
-/* We scan which devices are on the SBus using the PROM node device
- * tree.  SBus devices are described in two different ways.  You can
- * either get an absolute address at which to access the device, or
- * you can get a SBus 'slot' number and an offset within that slot.
- */
-
-/* The base address at which to calculate device OBIO addresses. */
-#define SUN_SBUS_BVADDR        0xf8000000
-#define SBUS_OFF_MASK          0x01ffffff
-
-/* These routines are used to calculate device address from slot
- * numbers + offsets, and vice versa.
- */
-
-static inline unsigned long sbus_devaddr(int slotnum, unsigned long offset)
-{
-  return (unsigned long) (SUN_SBUS_BVADDR+((slotnum)<<25)+(offset));
-}
-
-static inline int sbus_dev_slot(unsigned long dev_addr)
-{
-  return (int) (((dev_addr)-SUN_SBUS_BVADDR)>>25);
-}
-
-struct sbus_bus;
-
-/* Linux SBUS device tables */
-struct sbus_dev {
-	struct of_device	ofdev;
-	struct sbus_bus		*bus;
-	struct sbus_dev		*next;
-	struct sbus_dev		*child;
-	struct sbus_dev		*parent;
-	int prom_node;
-	char prom_name[64];
-	int slot;
-
-	struct resource resource[PROMREG_MAX];
-
-	struct linux_prom_registers reg_addrs[PROMREG_MAX];
-	int num_registers;
-
-	struct linux_prom_ranges device_ranges[PROMREG_MAX];
-	int num_device_ranges;
-
-	unsigned int irqs[4];
-	int num_irqs;
-};
-#define to_sbus_device(d) container_of(d, struct sbus_dev, ofdev.dev)
-
-/* This struct describes the SBus(s) found on this machine. */
-struct sbus_bus {
-	struct of_device	ofdev;
-	struct sbus_dev		*devices;	/* Link to devices on this SBus */
-	struct sbus_bus		*next;		/* next SBus, if more than one SBus */
-	int			prom_node;	/* PROM device tree node for this SBus */
-	char			prom_name[64];  /* Usually "sbus" or "sbi" */
-	int			clock_freq;
-
-	struct linux_prom_ranges sbus_ranges[PROMREG_MAX];
-	int num_sbus_ranges;
-
-	int devid;
-	int board;
-};
-#define to_sbus(d) container_of(d, struct sbus_bus, ofdev.dev)
-
-extern struct sbus_bus *sbus_root;
-
-static inline int
-sbus_is_slave(struct sbus_dev *dev)
-{
-	/* XXX Have to write this for sun4c's */
-	return 0;
-}
-
-/* Device probing routines could find these handy */
-#define for_each_sbus(bus) \
-        for((bus) = sbus_root; (bus); (bus)=(bus)->next)
-
-#define for_each_sbusdev(device, bus) \
-        for((device) = (bus)->devices; (device); (device)=(device)->next)
-
-#define for_all_sbusdev(device, bus) \
-	for ((bus) = sbus_root; (bus); (bus) = (bus)->next) \
-		for ((device) = (bus)->devices; (device); (device) = (device)->next)
-
-/* Driver DVMA interfaces. */
-#define sbus_can_dma_64bit(sdev)	(0) /* actually, sparc_cpu_model==sun4d */
-#define sbus_can_burst64(sdev)		(0) /* actually, sparc_cpu_model==sun4d */
-extern void sbus_set_sbus64(struct sbus_dev *, int);
-extern void sbus_fill_device_irq(struct sbus_dev *);
-
-/* These yield IOMMU mappings in consistent mode. */
-extern void *sbus_alloc_consistent(struct sbus_dev *, long, u32 *dma_addrp);
-extern void sbus_free_consistent(struct sbus_dev *, long, void *, u32);
-void prom_adjust_ranges(struct linux_prom_ranges *, int,
-			struct linux_prom_ranges *, int);
-
-#define SBUS_DMA_BIDIRECTIONAL	DMA_BIDIRECTIONAL
-#define SBUS_DMA_TODEVICE	DMA_TO_DEVICE
-#define SBUS_DMA_FROMDEVICE	DMA_FROM_DEVICE
-#define	SBUS_DMA_NONE		DMA_NONE
-
-/* All the rest use streaming mode mappings. */
-extern dma_addr_t sbus_map_single(struct sbus_dev *, void *, size_t, int);
-extern void sbus_unmap_single(struct sbus_dev *, dma_addr_t, size_t, int);
-extern int sbus_map_sg(struct sbus_dev *, struct scatterlist *, int, int);
-extern void sbus_unmap_sg(struct sbus_dev *, struct scatterlist *, int, int);
-
-/* Finally, allow explicit synchronization of streamable mappings. */
-extern void sbus_dma_sync_single_for_cpu(struct sbus_dev *, dma_addr_t, size_t, int);
-#define sbus_dma_sync_single sbus_dma_sync_single_for_cpu
-extern void sbus_dma_sync_single_for_device(struct sbus_dev *, dma_addr_t, size_t, int);
-extern void sbus_dma_sync_sg_for_cpu(struct sbus_dev *, struct scatterlist *, int, int);
-#define sbus_dma_sync_sg sbus_dma_sync_sg_for_cpu
-extern void sbus_dma_sync_sg_for_device(struct sbus_dev *, struct scatterlist *, int, int);
-
-/* Eric Brower (ebrower@usa.net)
- * Translate SBus interrupt levels to ino values--
- * this is used when converting sbus "interrupts" OBP
- * node values to "intr" node values, and is platform
- * dependent.  If only we could call OBP with
- * "sbus-intr>cpu (sbint -- ino)" from kernel...
- * See .../drivers/sbus/sbus.c for details.
- */
-BTFIXUPDEF_CALL(unsigned int, sbint_to_irq, struct sbus_dev *sdev, unsigned int)
-#define sbint_to_irq(sdev, sbint) BTFIXUP_CALL(sbint_to_irq)(sdev, sbint)
-
-extern void sbus_arch_bus_ranges_init(struct device_node *, struct sbus_bus *);
-extern void sbus_setup_iommu(struct sbus_bus *, struct device_node *);
-extern void sbus_setup_arch_props(struct sbus_bus *, struct device_node *);
-extern int sbus_arch_preinit(void);
-extern void sbus_arch_postinit(void);
-
-#endif /* !(_SPARC_SBUS_H) */
diff --git a/arch/sparc/include/asm/sbus_64.h b/arch/sparc/include/asm/sbus_64.h
deleted file mode 100644
index b606c14..0000000
--- a/arch/sparc/include/asm/sbus_64.h
+++ /dev/null
@@ -1,190 +0,0 @@
-/* sbus.h: Defines for the Sun SBus.
- *
- * Copyright (C) 1996, 1999, 2007 David S. Miller (davem@davemloft.net)
- */
-
-#ifndef _SPARC64_SBUS_H
-#define _SPARC64_SBUS_H
-
-#include <linux/dma-mapping.h>
-#include <linux/ioport.h>
-#include <linux/of_device.h>
-
-#include <asm/oplib.h>
-#include <asm/prom.h>
-#include <asm/iommu.h>
-#include <asm/scatterlist.h>
-
-/* We scan which devices are on the SBus using the PROM node device
- * tree.  SBus devices are described in two different ways.  You can
- * either get an absolute address at which to access the device, or
- * you can get a SBus 'slot' number and an offset within that slot.
- */
-
-/* The base address at which to calculate device OBIO addresses. */
-#define SUN_SBUS_BVADDR        0x00000000
-#define SBUS_OFF_MASK          0x0fffffff
-
-/* These routines are used to calculate device address from slot
- * numbers + offsets, and vice versa.
- */
-
-static inline unsigned long sbus_devaddr(int slotnum, unsigned long offset)
-{
-  return (unsigned long) (SUN_SBUS_BVADDR+((slotnum)<<28)+(offset));
-}
-
-static inline int sbus_dev_slot(unsigned long dev_addr)
-{
-  return (int) (((dev_addr)-SUN_SBUS_BVADDR)>>28);
-}
-
-struct sbus_bus;
-
-/* Linux SBUS device tables */
-struct sbus_dev {
-	struct of_device	ofdev;
-	struct sbus_bus		*bus;
-	struct sbus_dev		*next;
-	struct sbus_dev		*child;
-	struct sbus_dev		*parent;
-	int prom_node;
-	char prom_name[64];
-	int slot;
-
-	struct resource resource[PROMREG_MAX];
-
-	struct linux_prom_registers reg_addrs[PROMREG_MAX];
-	int num_registers;
-
-	struct linux_prom_ranges device_ranges[PROMREG_MAX];
-	int num_device_ranges;
-
-	unsigned int irqs[4];
-	int num_irqs;
-};
-#define to_sbus_device(d) container_of(d, struct sbus_dev, ofdev.dev)
-
-/* This struct describes the SBus(s) found on this machine. */
-struct sbus_bus {
-	struct of_device	ofdev;
-	struct sbus_dev		*devices;	/* Tree of SBUS devices	*/
-	struct sbus_bus		*next;		/* Next SBUS in system	*/
-	int			prom_node;      /* OBP node of SBUS	*/
-	char			prom_name[64];	/* Usually "sbus" or "sbi" */
-	int			clock_freq;
-
-	struct linux_prom_ranges sbus_ranges[PROMREG_MAX];
-	int num_sbus_ranges;
-
-	int portid;
-};
-#define to_sbus(d) container_of(d, struct sbus_bus, ofdev.dev)
-
-extern struct sbus_bus *sbus_root;
-
-/* Device probing routines could find these handy */
-#define for_each_sbus(bus) \
-        for((bus) = sbus_root; (bus); (bus)=(bus)->next)
-
-#define for_each_sbusdev(device, bus) \
-        for((device) = (bus)->devices; (device); (device)=(device)->next)
-
-#define for_all_sbusdev(device, bus) \
-	for ((bus) = sbus_root; (bus); (bus) = (bus)->next) \
-		for ((device) = (bus)->devices; (device); (device) = (device)->next)
-
-/* Driver DVMA interfaces. */
-#define sbus_can_dma_64bit(sdev)	(1)
-#define sbus_can_burst64(sdev)		(1)
-extern void sbus_set_sbus64(struct sbus_dev *, int);
-extern void sbus_fill_device_irq(struct sbus_dev *);
-
-static inline void *sbus_alloc_consistent(struct sbus_dev *sdev , size_t size,
-					  dma_addr_t *dma_handle)
-{
-	return dma_alloc_coherent(&sdev->ofdev.dev, size,
-				  dma_handle, GFP_ATOMIC);
-}
-
-static inline void sbus_free_consistent(struct sbus_dev *sdev, size_t size,
-					void *vaddr, dma_addr_t dma_handle)
-{
-	return dma_free_coherent(&sdev->ofdev.dev, size, vaddr, dma_handle);
-}
-
-#define SBUS_DMA_BIDIRECTIONAL	DMA_BIDIRECTIONAL
-#define SBUS_DMA_TODEVICE	DMA_TO_DEVICE
-#define SBUS_DMA_FROMDEVICE	DMA_FROM_DEVICE
-#define	SBUS_DMA_NONE		DMA_NONE
-
-/* All the rest use streaming mode mappings. */
-static inline dma_addr_t sbus_map_single(struct sbus_dev *sdev, void *ptr,
-					 size_t size, int direction)
-{
-	return dma_map_single(&sdev->ofdev.dev, ptr, size,
-			      (enum dma_data_direction) direction);
-}
-
-static inline void sbus_unmap_single(struct sbus_dev *sdev,
-				     dma_addr_t dma_addr, size_t size,
-				     int direction)
-{
-	dma_unmap_single(&sdev->ofdev.dev, dma_addr, size,
-			 (enum dma_data_direction) direction);
-}
-
-static inline int sbus_map_sg(struct sbus_dev *sdev, struct scatterlist *sg,
-			      int nents, int direction)
-{
-	return dma_map_sg(&sdev->ofdev.dev, sg, nents,
-			  (enum dma_data_direction) direction);
-}
-
-static inline void sbus_unmap_sg(struct sbus_dev *sdev, struct scatterlist *sg,
-				 int nents, int direction)
-{
-	dma_unmap_sg(&sdev->ofdev.dev, sg, nents,
-		     (enum dma_data_direction) direction);
-}
-
-/* Finally, allow explicit synchronization of streamable mappings. */
-static inline void sbus_dma_sync_single_for_cpu(struct sbus_dev *sdev,
-						dma_addr_t dma_handle,
-						size_t size, int direction)
-{
-	dma_sync_single_for_cpu(&sdev->ofdev.dev, dma_handle, size,
-				(enum dma_data_direction) direction);
-}
-#define sbus_dma_sync_single sbus_dma_sync_single_for_cpu
-
-static inline void sbus_dma_sync_single_for_device(struct sbus_dev *sdev,
-						   dma_addr_t dma_handle,
-						   size_t size, int direction)
-{
-	/* No flushing needed to sync cpu writes to the device.  */
-}
-
-static inline void sbus_dma_sync_sg_for_cpu(struct sbus_dev *sdev,
-					    struct scatterlist *sg,
-					    int nents, int direction)
-{
-	dma_sync_sg_for_cpu(&sdev->ofdev.dev, sg, nents,
-			    (enum dma_data_direction) direction);
-}
-#define sbus_dma_sync_sg sbus_dma_sync_sg_for_cpu
-
-static inline void sbus_dma_sync_sg_for_device(struct sbus_dev *sdev,
-					       struct scatterlist *sg,
-					       int nents, int direction)
-{
-	/* No flushing needed to sync cpu writes to the device.  */
-}
-
-extern void sbus_arch_bus_ranges_init(struct device_node *, struct sbus_bus *);
-extern void sbus_setup_iommu(struct sbus_bus *, struct device_node *);
-extern void sbus_setup_arch_props(struct sbus_bus *, struct device_node *);
-extern int sbus_arch_preinit(void);
-extern void sbus_arch_postinit(void);
-
-#endif /* !(_SPARC64_SBUS_H) */
diff --git a/arch/sparc/include/asm/serial.h b/arch/sparc/include/asm/serial.h
new file mode 100644
index 0000000..f90d61c
--- /dev/null
+++ b/arch/sparc/include/asm/serial.h
@@ -0,0 +1,6 @@
+#ifndef __SPARC_SERIAL_H
+#define __SPARC_SERIAL_H
+
+#define BASE_BAUD ( 1843200 / 16 )
+
+#endif /* __SPARC_SERIAL_H */
diff --git a/arch/sparc/include/asm/spinlock_32.h b/arch/sparc/include/asm/spinlock_32.h
index de2249b..bf2d532 100644
--- a/arch/sparc/include/asm/spinlock_32.h
+++ b/arch/sparc/include/asm/spinlock_32.h
@@ -6,8 +6,6 @@
 #ifndef __SPARC_SPINLOCK_H
 #define __SPARC_SPINLOCK_H
 
-#include <linux/threads.h>	/* For NR_CPUS */
-
 #ifndef __ASSEMBLY__
 
 #include <asm/psr.h>
diff --git a/arch/sparc/include/asm/spinlock_64.h b/arch/sparc/include/asm/spinlock_64.h
index 0006fe9..120cfe4 100644
--- a/arch/sparc/include/asm/spinlock_64.h
+++ b/arch/sparc/include/asm/spinlock_64.h
@@ -6,8 +6,6 @@
 #ifndef __SPARC64_SPINLOCK_H
 #define __SPARC64_SPINLOCK_H
 
-#include <linux/threads.h>	/* For NR_CPUS */
-
 #ifndef __ASSEMBLY__
 
 /* To get debugging spinlocks which detect and catch
diff --git a/arch/sparc/include/asm/sstate.h b/arch/sparc/include/asm/sstate.h
deleted file mode 100644
index a7c35db..0000000
--- a/arch/sparc/include/asm/sstate.h
+++ /dev/null
@@ -1,13 +0,0 @@
-#ifndef _SPARC64_SSTATE_H
-#define _SPARC64_SSTATE_H
-
-extern void sstate_booting(void);
-extern void sstate_running(void);
-extern void sstate_halt(void);
-extern void sstate_poweroff(void);
-extern void sstate_panic(void);
-extern void sstate_reboot(void);
-
-extern void sun4v_sstate_init(void);
-
-#endif /* _SPARC64_SSTATE_H */
diff --git a/arch/sparc/include/asm/starfire.h b/arch/sparc/include/asm/starfire.h
index 07bafd3..d56ce60a 100644
--- a/arch/sparc/include/asm/starfire.h
+++ b/arch/sparc/include/asm/starfire.h
@@ -12,7 +12,6 @@
 extern int this_is_starfire;
 
 extern void check_if_starfire(void);
-extern void starfire_cpu_setup(void);
 extern int starfire_hard_smp_processor_id(void);
 extern void starfire_hookup(int);
 extern unsigned int starfire_translate(unsigned long imap, unsigned int upaid);
diff --git a/arch/sparc/include/asm/statfs.h b/arch/sparc/include/asm/statfs.h
index 5e937a7..55e607a 100644
--- a/arch/sparc/include/asm/statfs.h
+++ b/arch/sparc/include/asm/statfs.h
@@ -1,8 +1,6 @@
 #ifndef ___ASM_SPARC_STATFS_H
 #define ___ASM_SPARC_STATFS_H
-#if defined(__sparc__) && defined(__arch64__)
-#include <asm/statfs_64.h>
-#else
-#include <asm/statfs_32.h>
-#endif
+
+#include <asm-generic/statfs.h>
+
 #endif
diff --git a/arch/sparc/include/asm/statfs_32.h b/arch/sparc/include/asm/statfs_32.h
deleted file mode 100644
index 304520f..0000000
--- a/arch/sparc/include/asm/statfs_32.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef _SPARC_STATFS_H
-#define _SPARC_STATFS_H
-
-#include <asm-generic/statfs.h>
-
-#endif
diff --git a/arch/sparc/include/asm/statfs_64.h b/arch/sparc/include/asm/statfs_64.h
deleted file mode 100644
index 79b3c89..0000000
--- a/arch/sparc/include/asm/statfs_64.h
+++ /dev/null
@@ -1,54 +0,0 @@
-#ifndef _SPARC64_STATFS_H
-#define _SPARC64_STATFS_H
-
-#ifndef __KERNEL_STRICT_NAMES
-
-#include <linux/types.h>
-
-typedef __kernel_fsid_t	fsid_t;
-
-#endif
-
-struct statfs {
-	long f_type;
-	long f_bsize;
-	long f_blocks;
-	long f_bfree;
-	long f_bavail;
-	long f_files;
-	long f_ffree;
-	__kernel_fsid_t f_fsid;
-	long f_namelen;
-	long f_frsize;
-	long f_spare[5];
-};
-
-struct statfs64 {
-	long f_type;
-	long f_bsize;
-	long f_blocks;
-	long f_bfree;
-	long f_bavail;
-	long f_files;
-	long f_ffree;
-	__kernel_fsid_t f_fsid;
-	long f_namelen;
-	long f_frsize;
-	long f_spare[5];
-};
-
-struct compat_statfs64 {
-	__u32 f_type;
-	__u32 f_bsize;
-	__u64 f_blocks;
-	__u64 f_bfree;
-	__u64 f_bavail;
-	__u64 f_files;
-	__u64 f_ffree;
-	__kernel_fsid_t f_fsid;
-	__u32 f_namelen;
-	__u32 f_frsize;
-	__u32 f_spare[5];
-};
-
-#endif
diff --git a/arch/sparc/include/asm/sun4paddr.h b/arch/sparc/include/asm/sun4paddr.h
deleted file mode 100644
index d52985f..0000000
--- a/arch/sparc/include/asm/sun4paddr.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * sun4paddr.h:  Various physical addresses on sun4 machines
- *
- * Copyright (C) 1997 Anton Blanchard (anton@progsoc.uts.edu.au)
- * Copyright (C) 1998 Chris Davis (cdavis@cois.on.ca)
- * 
- * Now supports more sun4's
- */
-
-#ifndef _SPARC_SUN4PADDR_H
-#define _SPARC_SUN4PADDR_H
-
-#define SUN4_IE_PHYSADDR		0xf5000000
-#define SUN4_UNUSED_PHYSADDR		0
-
-/* these work for me */
-#define SUN4_200_MEMREG_PHYSADDR	0xf4000000
-#define SUN4_200_CLOCK_PHYSADDR		0xf3000000
-#define SUN4_200_BWTWO_PHYSADDR		0xfd000000
-#define SUN4_200_ETH_PHYSADDR		0xf6000000
-#define SUN4_200_SI_PHYSADDR		0xff200000
-
-/* these were here before */
-#define SUN4_300_MEMREG_PHYSADDR	0xf4000000
-#define SUN4_300_CLOCK_PHYSADDR		0xf2000000
-#define SUN4_300_TIMER_PHYSADDR		0xef000000
-#define SUN4_300_ETH_PHYSADDR		0xf9000000
-#define SUN4_300_BWTWO_PHYSADDR		0xfb400000
-#define SUN4_300_DMA_PHYSADDR		0xfa001000
-#define SUN4_300_ESP_PHYSADDR		0xfa000000
-
-/* Are these right? */
-#define SUN4_400_MEMREG_PHYSADDR	0xf4000000
-#define SUN4_400_CLOCK_PHYSADDR		0xf2000000
-#define SUN4_400_TIMER_PHYSADDR		0xef000000
-#define SUN4_400_ETH_PHYSADDR		0xf9000000
-#define SUN4_400_BWTWO_PHYSADDR		0xfb400000
-#define SUN4_400_DMA_PHYSADDR		0xfa001000
-#define SUN4_400_ESP_PHYSADDR		0xfa000000
-
-/* 
-	these are the actual values set and used in the code. Unused items set 
-	to SUN_UNUSED_PHYSADDR 
- */
-
-extern int sun4_memreg_physaddr; /* memory register (ecc?) */
-extern int sun4_clock_physaddr;  /* system clock */
-extern int sun4_timer_physaddr;  /* timer, where applicable */
-extern int sun4_eth_physaddr;    /* onboard ethernet (ie/le) */
-extern int sun4_si_physaddr;     /* sun3 scsi adapter */
-extern int sun4_bwtwo_physaddr;  /* onboard bw2 */
-extern int sun4_dma_physaddr;    /* scsi dma */
-extern int sun4_esp_physaddr;    /* esp scsi */
-extern int sun4_ie_physaddr;     /* interrupt enable */
-
-#endif /* !(_SPARC_SUN4PADDR_H) */
diff --git a/arch/sparc/include/asm/sun4prom.h b/arch/sparc/include/asm/sun4prom.h
deleted file mode 100644
index 9c8b4cb..0000000
--- a/arch/sparc/include/asm/sun4prom.h
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * sun4prom.h -- interface to sun4 PROM monitor.  We don't use most of this,
- *               so most of these are just placeholders.
- */
-
-#ifndef _SUN4PROM_H_
-#define _SUN4PROM_H_
-
-/*
- * Although this looks similar to an romvec for a OpenProm machine, it is 
- * actually closer to what was used in the Sun2 and Sun3.
- *
- * V2 entries exist only in version 2 PROMs and later, V3 in version 3 and later.
- * 
- * Many of the function prototypes are guesses.  Some are certainly wrong.
- * Use with care.
- */
-
-typedef struct {
-	char		*initSP;		/* Initial system stack ptr */
-	void		(*startmon)(void);	/* Initial PC for hardware */
-	int		*diagberr;		/* Bus err handler for diags */
-	struct linux_arguments_v0 **bootParam; /* Info for bootstrapped pgm */
- 	unsigned int	*memorysize;		/* Usable memory in bytes */
-	unsigned char	(*getchar)(void);	/* Get char from input device */ 
-	void		(*putchar)(char);	/* Put char to output device */
-	int		(*mayget)(void);	/* Maybe get char, or -1 */
-	int		(*mayput)(int);		/* Maybe put char, or -1 */
-	unsigned char	*echo;			/* Should getchar echo? */
-	unsigned char	*insource;		/* Input source selector */
-	unsigned char	*outsink;		/* Output sink selector */
-	int		(*getkey)(void);	/* Get next key if one exists */
-	void		(*initgetkey)(void);	/* Initialize get key */
-	unsigned int	*translation;		/* Kbd translation selector */
-	unsigned char	*keybid;		/* Keyboard ID byte */
-	int		*screen_x;		/* V2: Screen x pos (r/o) */
-	int		*screen_y;		/* V2: Screen y pos (r/o) */
-	struct keybuf	*keybuf;		/* Up/down keycode buffer */
-	char		*monid;			/* Monitor version ID */
-	void		(*fbwritechar)(char);	/* Write a character to FB */
-	int		*fbAddr;		/* Address of frame buffer */
-	char		**font;			/* Font table for FB */
-	void		(*fbwritestr)(char *);	/* Write string to FB */
-	void		(*reboot)(char *);	/* e.g. reboot("sd()vmlinux") */
-	unsigned char	*linebuf;		/* The line input buffer */
-	unsigned char	**lineptr;		/* Cur pointer into linebuf */
-	int		*linesize;		/* length of line in linebuf */
-	void		(*getline)(char *);	/* Get line from user */
-	unsigned char	(*getnextchar)(void);	/* Get next char from linebuf */
-	unsigned char	(*peeknextchar)(void);	/* Peek at next char */
-	int		*fbthere;		/* =1 if frame buffer there */
-	int		(*getnum)(void);	/* Grab hex num from line */
-	int		(*printf)(char *, ...);	/* See prom_printf() instead */ 
-	void		(*printhex)(int);	/* Format N digits in hex */
-	unsigned char	*leds;			/* RAM copy of LED register */
-	void		(*setLEDs)(unsigned char *);	/* Sets LED's and RAM copy */
-	void		(*NMIaddr)(void *);	/* Addr for level 7 vector */
-	void		(*abortentry)(void);	/* Entry for keyboard abort */
-	int		*nmiclock;		/* Counts up in msec */
-	int		*FBtype;		/* Frame buffer type */
- 	unsigned int	romvecversion;		/* Version number for this romvec */
-	struct globram  *globram;		/* monitor global variables ??? */
-	void *		kbdaddr;		/* Addr of keyboard in use */
-	int		*keyrinit;		/* ms before kbd repeat */
-	unsigned char	*keyrtick; 		/* ms between repetitions */
-	unsigned int	*memoryavail;		/* V1: Main mem usable size */
-	long		*resetaddr;		/* where to jump on a reset */
-	long		*resetmap;		/* pgmap entry for resetaddr */
-	void		(*exittomon)(void);	/* Exit from user program */
-	unsigned char	**memorybitmap;		/* V1: &{0 or &bits} */
-	void		(*setcxsegmap)(int ctxt, char *va, int pmeg);	/* Set seg in any context */
-	void		(**vector_cmd)(void *);	/* V2: Handler for 'v' cmd */
-	unsigned long	*expectedtrapsig;	/* V3: Location of the expected trap signal */
-	unsigned long	*trapvectorbasetable;	/* V3: Address of the trap vector table */
-	int		unused1;
-	int		unused2;
-	int		unused3;
-	int		unused4;
-} linux_sun4_romvec;
-
-extern linux_sun4_romvec *sun4_romvec;
-
-#endif /* _SUN4PROM_H_ */
diff --git a/arch/sparc/include/asm/system_32.h b/arch/sparc/include/asm/system_32.h
index b4b0244..8623fc4 100644
--- a/arch/sparc/include/asm/system_32.h
+++ b/arch/sparc/include/asm/system_32.h
@@ -34,13 +34,7 @@
 
 extern enum sparc_cpu sparc_cpu_model;
 
-#ifndef CONFIG_SUN4
-#define ARCH_SUN4C_SUN4 (sparc_cpu_model==sun4c)
-#define ARCH_SUN4 0
-#else
-#define ARCH_SUN4C_SUN4 1
-#define ARCH_SUN4 1
-#endif
+#define ARCH_SUN4C (sparc_cpu_model==sun4c)
 
 #define SUN4M_NCPUS            4              /* Architectural limit of sun4m. */
 
@@ -55,6 +49,7 @@
 extern void sun_do_break(void);
 extern int serial_console;
 extern int stop_a_enabled;
+extern int scons_pwroff;
 
 static inline int con_is_present(void)
 {
diff --git a/arch/sparc/include/asm/system_64.h b/arch/sparc/include/asm/system_64.h
index db9e742..8759f2a 100644
--- a/arch/sparc/include/asm/system_64.h
+++ b/arch/sparc/include/asm/system_64.h
@@ -26,9 +26,8 @@
 
 #define sparc_cpu_model sun4u
 
-/* This cannot ever be a sun4c nor sun4 :) That's just history. */
-#define ARCH_SUN4C_SUN4 0
-#define ARCH_SUN4 0
+/* This cannot ever be a sun4c :) That's just history. */
+#define ARCH_SUN4C 0
 
 extern char reboot_command[];
 
@@ -118,6 +117,7 @@
 
 extern void sun_do_break(void);
 extern int stop_a_enabled;
+extern int scons_pwroff;
 
 extern void fault_in_user_windows(void);
 extern void synchronize_user_stack(void);
diff --git a/arch/sparc/include/asm/thread_info_32.h b/arch/sparc/include/asm/thread_info_32.h
index cbb892d..29899fd 100644
--- a/arch/sparc/include/asm/thread_info_32.h
+++ b/arch/sparc/include/asm/thread_info_32.h
@@ -80,11 +80,7 @@
 /*
  * thread information allocation
  */
-#if PAGE_SHIFT == 13
-#define THREAD_INFO_ORDER  0
-#else /* PAGE_SHIFT */
 #define THREAD_INFO_ORDER  1
-#endif
 
 #define __HAVE_ARCH_THREAD_INFO_ALLOCATOR
 
diff --git a/arch/sparc/include/asm/timer_32.h b/arch/sparc/include/asm/timer_32.h
index 361e538..2ec030e 100644
--- a/arch/sparc/include/asm/timer_32.h
+++ b/arch/sparc/include/asm/timer_32.h
@@ -9,96 +9,9 @@
 #define _SPARC_TIMER_H
 
 #include <asm/system.h>  /* For SUN4M_NCPUS */
-#include <asm/sun4paddr.h>
 #include <asm/btfixup.h>
 
-/* Timer structures. The interrupt timer has two properties which
- * are the counter (which is handled in do_timer in sched.c) and the limit.
- * This limit is where the timer's counter 'wraps' around. Oddly enough,
- * the sun4c timer when it hits the limit wraps back to 1 and not zero
- * thus when calculating the value at which it will fire a microsecond you
- * must adjust by one.  Thanks SUN for designing such great hardware ;(
- */
-
-/* Note that I am only going to use the timer that interrupts at
- * Sparc IRQ 10.  There is another one available that can fire at
- * IRQ 14. Currently it is left untouched, we keep the PROM's limit
- * register value and let the prom take these interrupts.  This allows
- * L1-A to work.
- */
-
-struct sun4c_timer_info {
-  __volatile__ unsigned int cur_count10;
-  __volatile__ unsigned int timer_limit10;
-  __volatile__ unsigned int cur_count14;
-  __volatile__ unsigned int timer_limit14;
-};
-
-#define SUN4C_TIMER_PHYSADDR   0xf3000000
-#ifdef CONFIG_SUN4
-#define SUN_TIMER_PHYSADDR SUN4_300_TIMER_PHYSADDR
-#else
-#define SUN_TIMER_PHYSADDR SUN4C_TIMER_PHYSADDR
-#endif
-
-/* A sun4m has two blocks of registers which are probably of the same
- * structure. LSI Logic's L64851 is told to _decrement_ from the limit
- * value. Aurora behaves similarly but its limit value is compacted in
- * other fashion (it's wider). Documented fields are defined here.
- */
-
-/* As with the interrupt register, we have two classes of timer registers
- * which are per-cpu and master.  Per-cpu timers only hit that cpu and are
- * only level 14 ticks, master timer hits all cpus and is level 10.
- */
-
-#define SUN4M_PRM_CNT_L       0x80000000
-#define SUN4M_PRM_CNT_LVALUE  0x7FFFFC00
-
-struct sun4m_timer_percpu_info {
-  __volatile__ unsigned int l14_timer_limit;    /* Initial value is 0x009c4000 */
-  __volatile__ unsigned int l14_cur_count;
-
-  /* This register appears to be write only and/or inaccessible
-   * on Uni-Processor sun4m machines.
-   */
-  __volatile__ unsigned int l14_limit_noclear;  /* Data access error is here */
-
-  __volatile__ unsigned int cntrl;            /* =1 after POST on Aurora */
-  __volatile__ unsigned char space[PAGE_SIZE - 16];
-};
-
-struct sun4m_timer_regs {
-	struct sun4m_timer_percpu_info cpu_timers[SUN4M_NCPUS];
-	volatile unsigned int l10_timer_limit;
-	volatile unsigned int l10_cur_count;
-
-	/* Again, this appears to be write only and/or inaccessible
-	 * on uni-processor sun4m machines.
-	 */
-	volatile unsigned int l10_limit_noclear;
-
-	/* This register too, it must be magic. */
-	volatile unsigned int foobar;
-
-	volatile unsigned int cfg;     /* equals zero at boot time... */
-};
-
-#define SUN4D_PRM_CNT_L       0x80000000
-#define SUN4D_PRM_CNT_LVALUE  0x7FFFFC00
-
-struct sun4d_timer_regs {
-	volatile unsigned int l10_timer_limit;
-	volatile unsigned int l10_cur_countx;
-	volatile unsigned int l10_limit_noclear;
-	volatile unsigned int ctrl;
-	volatile unsigned int l10_cur_count;
-};
-
-extern struct sun4d_timer_regs *sun4d_timers;
-
 extern __volatile__ unsigned int *master_l10_counter;
-extern __volatile__ unsigned int *master_l10_limit;
 
 /* FIXME: Make do_[gs]ettimeofday btfixup calls */
 BTFIXUPDEF_CALL(int, bus_do_settimeofday, struct timespec *tv)
diff --git a/arch/sparc/include/asm/vac-ops.h b/arch/sparc/include/asm/vac-ops.h
index d105276..a63e88e 100644
--- a/arch/sparc/include/asm/vac-ops.h
+++ b/arch/sparc/include/asm/vac-ops.h
@@ -76,11 +76,7 @@
  * cacheable bit in the pte's of all such pages.
  */
 
-#ifdef CONFIG_SUN4
-#define S4CVAC_BADBITS     0x0001e000
-#else
 #define S4CVAC_BADBITS    0x0000f000
-#endif
 
 /* The following is true if vaddr1 and vaddr2 would cause
  * a 'bad alias'.
@@ -94,10 +90,7 @@
  */
 struct sun4c_vac_props {
 	unsigned int num_bytes;     /* Size of the cache */
-	unsigned int num_lines;     /* Number of cache lines */
 	unsigned int do_hwflushes;  /* Hardware flushing available? */
-	enum { VAC_NONE, VAC_WRITE_THROUGH,
-	    VAC_WRITE_BACK } type;  /* What type of VAC? */
 	unsigned int linesize;      /* Size of each line in bytes */
 	unsigned int log2lsize;     /* log2(linesize) */
 	unsigned int on;            /* VAC is enabled */
diff --git a/arch/sparc/include/asm/vfc_ioctls.h b/arch/sparc/include/asm/vfc_ioctls.h
deleted file mode 100644
index af8b690..0000000
--- a/arch/sparc/include/asm/vfc_ioctls.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/* Copyright (c) 1996 by Manish Vachharajani */
-
-#ifndef _LINUX_VFC_IOCTLS_H_
-#define	_LINUX_VFC_IOCTLS_H_
-
-	/* IOCTLs */
-#define VFC_IOCTL(a)          (('j' << 8) | a)
-#define VFCGCTRL	(VFC_IOCTL (0))	        /* get vfc attributes */
-#define VFCSCTRL	(VFC_IOCTL (1))  	/* set vfc attributes */
-#define VFCGVID		(VFC_IOCTL (2)) 	/* get video decoder attributes */
-#define VFCSVID		(VFC_IOCTL (3))	        /* set video decoder attributes */
-#define VFCHUE		(VFC_IOCTL (4))   	/* set hue */
-#define VFCPORTCHG	(VFC_IOCTL (5))  	/* change port */
-#define VFCRDINFO	(VFC_IOCTL (6))  	/* read info */
-
-	/* Options for setting the vfc attributes and status */
-#define MEMPRST		0x1	/* reset FIFO ptr. */
-#define CAPTRCMD	0x2	/* start capture and wait */
-#define DIAGMODE	0x3	/* diag mode */
-#define NORMMODE	0x4	/* normal mode */
-#define CAPTRSTR	0x5	/* start capture */
-#define CAPTRWAIT	0x6	/* wait for capture to finish */
-
-
-	/* Options for the decoder */
-#define STD_NTSC	0x1	/* NTSC mode */
-#define STD_PAL		0x2	/* PAL mode */
-#define COLOR_ON	0x3	/* force color ON */
-#define MONO		0x4	/* force color OFF */
-
-	/* Values returned by ioctl 2 */
-
-#define NO_LOCK	        1
-#define NTSC_COLOR	2
-#define NTSC_NOCOLOR    3
-#define PAL_COLOR	4
-#define PAL_NOCOLOR	5
-
-/* Not too sure what this does yet */
-	/* Options for setting Field number */
-#define ODD_FIELD	0x1
-#define EVEN_FIELD	0x0
-#define ACTIVE_ONLY     0x2
-#define NON_ACTIVE	0x0
-
-/* Debug options */
-#define VFC_I2C_SEND 0
-#define VFC_I2C_RECV 1
-
-struct vfc_debug_inout
-{
-	unsigned long addr;
-	unsigned long ret;
-	unsigned long len;
-	unsigned char __user *buffer;
-};
-
-#endif /* _LINUX_VFC_IOCTLS_H_ */
diff --git a/arch/sparc/include/asm/visasm.h b/arch/sparc/include/asm/visasm.h
index de797b9..39ca301 100644
--- a/arch/sparc/include/asm/visasm.h
+++ b/arch/sparc/include/asm/visasm.h
@@ -57,6 +57,7 @@
 "		" : : "i" (FPRS_FEF|FPRS_DU) :
 		"o5", "g1", "g2", "g3", "g7", "cc");
 }
+extern int vis_emul(struct pt_regs *, unsigned int);
 #endif
 
 #endif /* _SPARC64_ASI_H */
diff --git a/arch/sparc/kernel/Makefile b/arch/sparc/kernel/Makefile
index 6e03a2a..2d65820 100644
--- a/arch/sparc/kernel/Makefile
+++ b/arch/sparc/kernel/Makefile
@@ -13,15 +13,13 @@
 	    time.o windows.o cpu.o devices.o \
 	    tadpole.o tick14.o ptrace.o \
 	    unaligned.o una_asm.o muldiv.o \
-	    prom.o of_device.o devres.o
+	    prom.o of_device.o devres.o dma.o
 
 devres-y = ../../../kernel/irq/devres.o
 
 obj-$(CONFIG_PCI) += pcic.o
-obj-$(CONFIG_SUN4) += sun4setup.o
 obj-$(CONFIG_SMP) += trampoline.o smp.o sun4m_smp.o sun4d_smp.o
 obj-$(CONFIG_SUN_AUXIO) += auxio.o
-obj-$(CONFIG_PCI) += ebus.o
 obj-$(CONFIG_SUN_PM) += apc.o pmc.o
 obj-$(CONFIG_MODULES) += module.o sparc_ksyms.o
 obj-$(CONFIG_SPARC_LED) += led.o
diff --git a/arch/sparc/kernel/apc.c b/arch/sparc/kernel/apc.c
index 5267d48..4dd1ba7 100644
--- a/arch/sparc/kernel/apc.c
+++ b/arch/sparc/kernel/apc.c
@@ -12,9 +12,10 @@
 #include <linux/miscdevice.h>
 #include <linux/smp_lock.h>
 #include <linux/pm.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 
 #include <asm/io.h>
-#include <asm/sbus.h>
 #include <asm/oplib.h>
 #include <asm/uaccess.h>
 #include <asm/auxio.h>
@@ -29,11 +30,10 @@
 #define APC_OBPNAME	"power-management"
 #define APC_DEVNAME "apc"
 
-volatile static u8 __iomem *regs; 
-static int apc_regsize;
+static u8 __iomem *regs;
 static int apc_no_idle __initdata = 0;
 
-#define apc_readb(offs)			(sbus_readb(regs+offs))
+#define apc_readb(offs)		(sbus_readb(regs+offs))
 #define apc_writeb(val, offs) 	(sbus_writeb(val, regs+offs))
 
 /* Specify "apc=noidle" on the kernel command line to 
@@ -69,9 +69,9 @@
 #endif
 } 
 
-static inline void apc_free(void)
+static inline void apc_free(struct of_device *op)
 {
-	sbus_iounmap(regs, apc_regsize);
+	of_iounmap(&op->resource[0], regs, resource_size(&op->resource[0]));
 }
 
 static int apc_open(struct inode *inode, struct file *f)
@@ -153,52 +153,56 @@
 
 static struct miscdevice apc_miscdev = { APC_MINOR, APC_DEVNAME, &apc_fops };
 
-static int __init apc_probe(void)
+static int __devinit apc_probe(struct of_device *op,
+			       const struct of_device_id *match)
 {
-	struct sbus_bus *sbus = NULL;
-	struct sbus_dev *sdev = NULL;
-	int iTmp = 0;
+	int err;
 
-	for_each_sbus(sbus) {
-		for_each_sbusdev(sdev, sbus) {
-			if (!strcmp(sdev->prom_name, APC_OBPNAME)) {
-				goto sbus_done;
-			}
-		}
-	}
-
-sbus_done:
-	if (!sdev) {
-		return -ENODEV;
-	}
-
-	apc_regsize = sdev->reg_addrs[0].reg_size;
-	regs = sbus_ioremap(&sdev->resource[0], 0, 
-				   apc_regsize, APC_OBPNAME);
-	if(!regs) {
+	regs = of_ioremap(&op->resource[0], 0,
+			  resource_size(&op->resource[0]), APC_OBPNAME);
+	if (!regs) {
 		printk(KERN_ERR "%s: unable to map registers\n", APC_DEVNAME);
 		return -ENODEV;
 	}
 
-	iTmp = misc_register(&apc_miscdev);
-	if (iTmp != 0) {
+	err = misc_register(&apc_miscdev);
+	if (err) {
 		printk(KERN_ERR "%s: unable to register device\n", APC_DEVNAME);
-		apc_free();
+		apc_free(op);
 		return -ENODEV;
 	}
 
 	/* Assign power management IDLE handler */
-	if(!apc_no_idle)
+	if (!apc_no_idle)
 		pm_idle = apc_swift_idle;	
 
 	printk(KERN_INFO "%s: power management initialized%s\n", 
-		APC_DEVNAME, apc_no_idle ? " (CPU idle disabled)" : "");
+	       APC_DEVNAME, apc_no_idle ? " (CPU idle disabled)" : "");
+
 	return 0;
 }
 
+static struct of_device_id __initdata apc_match[] = {
+	{
+		.name = APC_OBPNAME,
+	},
+	{},
+};
+MODULE_DEVICE_TABLE(of, apc_match);
+
+static struct of_platform_driver apc_driver = {
+	.name		= "apc",
+	.match_table	= apc_match,
+	.probe		= apc_probe,
+};
+
+static int __init apc_init(void)
+{
+	return of_register_driver(&apc_driver, &of_bus_type);
+}
+
 /* This driver is not critical to the boot process
  * and is easiest to ioremap when SBus is already
  * initialized, so we install ourselves thusly:
  */
-__initcall(apc_probe);
-
+__initcall(apc_init);
diff --git a/arch/sparc/kernel/auxio.c b/arch/sparc/kernel/auxio.c
index baf4ed3..09c8572 100644
--- a/arch/sparc/kernel/auxio.c
+++ b/arch/sparc/kernel/auxio.c
@@ -6,6 +6,8 @@
 #include <linux/stddef.h>
 #include <linux/init.h>
 #include <linux/spinlock.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 #include <asm/oplib.h>
 #include <asm/io.h>
 #include <asm/auxio.h>
@@ -59,7 +61,7 @@
 	r.flags = auxregs[0].which_io & 0xF;
 	r.start = auxregs[0].phys_addr;
 	r.end = auxregs[0].phys_addr + auxregs[0].reg_size - 1;
-	auxio_register = sbus_ioremap(&r, 0, auxregs[0].reg_size, "auxio");
+	auxio_register = of_ioremap(&r, 0, auxregs[0].reg_size, "auxio");
 	/* Fix the address on sun4m and sun4c. */
 	if((((unsigned long) auxregs[0].phys_addr) & 3) == 3 ||
 	   sparc_cpu_model == sun4c)
@@ -128,7 +130,7 @@
 	r.flags = regs.which_io & 0xF;
 	r.start = regs.phys_addr;
 	r.end = regs.phys_addr + regs.reg_size - 1;
-	auxio_power_register = (unsigned char *) sbus_ioremap(&r, 0,
+	auxio_power_register = (unsigned char *) of_ioremap(&r, 0,
 	    regs.reg_size, "auxpower");
 
 	/* Display a quick message on the console. */
diff --git a/arch/sparc/kernel/devices.c b/arch/sparc/kernel/devices.c
index b240b88..ad656b0 100644
--- a/arch/sparc/kernel/devices.c
+++ b/arch/sparc/kernel/devices.c
@@ -143,7 +143,7 @@
 #endif
 	clock_stop_probe();
 
-	if (ARCH_SUN4C_SUN4)
+	if (ARCH_SUN4C)
 		sun4c_probe_memerr_reg();
 
 	return;
diff --git a/arch/sparc/kernel/dma.c b/arch/sparc/kernel/dma.c
new file mode 100644
index 0000000..ebc8403
--- /dev/null
+++ b/arch/sparc/kernel/dma.c
@@ -0,0 +1,227 @@
+/* dma.c: PCI and SBUS DMA accessors for 32-bit sparc.
+ *
+ * Copyright (C) 2008 David S. Miller <davem@davemloft.net>
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/dma-mapping.h>
+#include <linux/scatterlist.h>
+#include <linux/mm.h>
+
+#ifdef CONFIG_PCI
+#include <linux/pci.h>
+#endif
+
+#include "dma.h"
+
+int dma_supported(struct device *dev, u64 mask)
+{
+#ifdef CONFIG_PCI
+	if (dev->bus == &pci_bus_type)
+		return pci_dma_supported(to_pci_dev(dev), mask);
+#endif
+	return 0;
+}
+EXPORT_SYMBOL(dma_supported);
+
+int dma_set_mask(struct device *dev, u64 dma_mask)
+{
+#ifdef CONFIG_PCI
+	if (dev->bus == &pci_bus_type)
+		return pci_set_dma_mask(to_pci_dev(dev), dma_mask);
+#endif
+	return -EOPNOTSUPP;
+}
+EXPORT_SYMBOL(dma_set_mask);
+
+void *dma_alloc_coherent(struct device *dev, size_t size,
+			 dma_addr_t *dma_handle, gfp_t flag)
+{
+#ifdef CONFIG_PCI
+	if (dev->bus == &pci_bus_type)
+		return pci_alloc_consistent(to_pci_dev(dev), size, dma_handle);
+#endif
+	return sbus_alloc_consistent(dev, size, dma_handle);
+}
+EXPORT_SYMBOL(dma_alloc_coherent);
+
+void dma_free_coherent(struct device *dev, size_t size,
+		       void *cpu_addr, dma_addr_t dma_handle)
+{
+#ifdef CONFIG_PCI
+	if (dev->bus == &pci_bus_type) {
+		pci_free_consistent(to_pci_dev(dev), size,
+				    cpu_addr, dma_handle);
+		return;
+	}
+#endif
+	sbus_free_consistent(dev, size, cpu_addr, dma_handle);
+}
+EXPORT_SYMBOL(dma_free_coherent);
+
+dma_addr_t dma_map_single(struct device *dev, void *cpu_addr,
+			  size_t size, enum dma_data_direction direction)
+{
+#ifdef CONFIG_PCI
+	if (dev->bus == &pci_bus_type)
+		return pci_map_single(to_pci_dev(dev), cpu_addr,
+				      size, (int)direction);
+#endif
+	return sbus_map_single(dev, cpu_addr, size, (int)direction);
+}
+EXPORT_SYMBOL(dma_map_single);
+
+void dma_unmap_single(struct device *dev, dma_addr_t dma_addr,
+		      size_t size,
+		      enum dma_data_direction direction)
+{
+#ifdef CONFIG_PCI
+	if (dev->bus == &pci_bus_type) {
+		pci_unmap_single(to_pci_dev(dev), dma_addr,
+				 size, (int)direction);
+		return;
+	}
+#endif
+	sbus_unmap_single(dev, dma_addr, size, (int)direction);
+}
+EXPORT_SYMBOL(dma_unmap_single);
+
+dma_addr_t dma_map_page(struct device *dev, struct page *page,
+			unsigned long offset, size_t size,
+			enum dma_data_direction direction)
+{
+#ifdef CONFIG_PCI
+	if (dev->bus == &pci_bus_type)
+		return pci_map_page(to_pci_dev(dev), page, offset,
+				    size, (int)direction);
+#endif
+	return sbus_map_single(dev, page_address(page) + offset,
+			       size, (int)direction);
+}
+EXPORT_SYMBOL(dma_map_page);
+
+void dma_unmap_page(struct device *dev, dma_addr_t dma_address,
+		    size_t size, enum dma_data_direction direction)
+{
+#ifdef CONFIG_PCI
+	if (dev->bus == &pci_bus_type) {
+		pci_unmap_page(to_pci_dev(dev), dma_address,
+			       size, (int)direction);
+		return;
+	}
+#endif
+	sbus_unmap_single(dev, dma_address, size, (int)direction);
+}
+EXPORT_SYMBOL(dma_unmap_page);
+
+int dma_map_sg(struct device *dev, struct scatterlist *sg,
+			     int nents, enum dma_data_direction direction)
+{
+#ifdef CONFIG_PCI
+	if (dev->bus == &pci_bus_type)
+		return pci_map_sg(to_pci_dev(dev), sg, nents, (int)direction);
+#endif
+	return sbus_map_sg(dev, sg, nents, direction);
+}
+EXPORT_SYMBOL(dma_map_sg);
+
+void dma_unmap_sg(struct device *dev, struct scatterlist *sg,
+		  int nents, enum dma_data_direction direction)
+{
+#ifdef CONFIG_PCI
+	if (dev->bus == &pci_bus_type) {
+		pci_unmap_sg(to_pci_dev(dev), sg, nents, (int)direction);
+		return;
+	}
+#endif
+	sbus_unmap_sg(dev, sg, nents, (int)direction);
+}
+EXPORT_SYMBOL(dma_unmap_sg);
+
+void dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle,
+			     size_t size, enum dma_data_direction direction)
+{
+#ifdef CONFIG_PCI
+	if (dev->bus == &pci_bus_type) {
+		pci_dma_sync_single_for_cpu(to_pci_dev(dev), dma_handle,
+					    size, (int)direction);
+		return;
+	}
+#endif
+	sbus_dma_sync_single_for_cpu(dev, dma_handle, size, (int) direction);
+}
+EXPORT_SYMBOL(dma_sync_single_for_cpu);
+
+void dma_sync_single_for_device(struct device *dev, dma_addr_t dma_handle,
+				size_t size, enum dma_data_direction direction)
+{
+#ifdef CONFIG_PCI
+	if (dev->bus == &pci_bus_type) {
+		pci_dma_sync_single_for_device(to_pci_dev(dev), dma_handle,
+					       size, (int)direction);
+		return;
+	}
+#endif
+	sbus_dma_sync_single_for_device(dev, dma_handle, size, (int) direction);
+}
+EXPORT_SYMBOL(dma_sync_single_for_device);
+
+void dma_sync_single_range_for_cpu(struct device *dev,
+				   dma_addr_t dma_handle,
+				   unsigned long offset,
+				   size_t size,
+				   enum dma_data_direction direction)
+{
+	dma_sync_single_for_cpu(dev, dma_handle+offset, size, direction);
+}
+EXPORT_SYMBOL(dma_sync_single_range_for_cpu);
+
+void dma_sync_single_range_for_device(struct device *dev, dma_addr_t dma_handle,
+				      unsigned long offset, size_t size,
+				      enum dma_data_direction direction)
+{
+	dma_sync_single_for_device(dev, dma_handle+offset, size, direction);
+}
+EXPORT_SYMBOL(dma_sync_single_range_for_device);
+
+void dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg,
+			 int nelems, enum dma_data_direction direction)
+{
+#ifdef CONFIG_PCI
+	if (dev->bus == &pci_bus_type) {
+		pci_dma_sync_sg_for_cpu(to_pci_dev(dev), sg,
+					nelems, (int)direction);
+		return;
+	}
+#endif
+	BUG();
+}
+EXPORT_SYMBOL(dma_sync_sg_for_cpu);
+
+void dma_sync_sg_for_device(struct device *dev,
+			    struct scatterlist *sg, int nelems,
+			    enum dma_data_direction direction)
+{
+#ifdef CONFIG_PCI
+	if (dev->bus == &pci_bus_type) {
+		pci_dma_sync_sg_for_device(to_pci_dev(dev), sg,
+					   nelems, (int)direction);
+		return;
+	}
+#endif
+	BUG();
+}
+EXPORT_SYMBOL(dma_sync_sg_for_device);
+
+int dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
+{
+	return (dma_addr == DMA_ERROR_CODE);
+}
+EXPORT_SYMBOL(dma_mapping_error);
+
+int dma_get_cache_alignment(void)
+{
+	return 32;
+}
+EXPORT_SYMBOL(dma_get_cache_alignment);
diff --git a/arch/sparc/kernel/dma.h b/arch/sparc/kernel/dma.h
new file mode 100644
index 0000000..f8d8951
--- /dev/null
+++ b/arch/sparc/kernel/dma.h
@@ -0,0 +1,14 @@
+void *sbus_alloc_consistent(struct device *dev, long len, u32 *dma_addrp);
+void sbus_free_consistent(struct device *dev, long n, void *p, u32 ba);
+dma_addr_t sbus_map_single(struct device *dev, void *va,
+			   size_t len, int direction);
+void sbus_unmap_single(struct device *dev, dma_addr_t ba,
+		       size_t n, int direction);
+int sbus_map_sg(struct device *dev, struct scatterlist *sg,
+		int n, int direction);
+void sbus_unmap_sg(struct device *dev, struct scatterlist *sg,
+		   int n, int direction);
+void sbus_dma_sync_single_for_cpu(struct device *dev, dma_addr_t ba,
+				  size_t size, int direction);
+void sbus_dma_sync_single_for_device(struct device *dev, dma_addr_t ba,
+				     size_t size, int direction);
diff --git a/arch/sparc/kernel/ebus.c b/arch/sparc/kernel/ebus.c
deleted file mode 100644
index 9729423..0000000
--- a/arch/sparc/kernel/ebus.c
+++ /dev/null
@@ -1,393 +0,0 @@
-/*
- * ebus.c: PCI to EBus bridge device.
- *
- * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
- *
- * Adopted for sparc by V. Roganov and G. Raiko.
- * Fixes for different platforms by Pete Zaitcev.
- */
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/string.h>
-
-#include <asm/system.h>
-#include <asm/page.h>
-#include <asm/pbm.h>
-#include <asm/ebus.h>
-#include <asm/io.h>
-#include <asm/oplib.h>
-#include <asm/prom.h>
-#include <asm/bpp.h>
-
-struct linux_ebus *ebus_chain = NULL;
-
-/* We are together with pcic.c under CONFIG_PCI. */
-extern unsigned int pcic_pin_to_irq(unsigned int, const char *name);
-
-/*
- * IRQ Blacklist
- * Here we list PROMs and systems that are known to supply crap as IRQ numbers.
- */
-struct ebus_device_irq {
-	char *name;
-	unsigned int pin;
-};
-
-struct ebus_system_entry {
-	char *esname;
-	struct ebus_device_irq *ipt;
-};
-
-static struct ebus_device_irq je1_1[] = {
-	{ "8042",		 3 },
-	{ "SUNW,CS4231",	 0 },
-	{ "parallel",		 0 },
-	{ "se",			 2 },
-	{ NULL, 0 }
-};
-
-/*
- * Gleb's JE1 supplied reasonable pin numbers, but mine did not (OBP 2.32).
- * Blacklist the sucker... Note that Gleb's system will work.
- */
-static struct ebus_system_entry ebus_blacklist[] = {
-	{ "SUNW,JavaEngine1", je1_1 },
-	{ NULL, NULL }
-};
-
-static struct ebus_device_irq *ebus_blackp = NULL;
-
-/*
- */
-static inline unsigned long ebus_alloc(size_t size)
-{
-	return (unsigned long)kmalloc(size, GFP_ATOMIC);
-}
-
-/*
- */
-static int __init ebus_blacklist_irq(const char *name)
-{
-	struct ebus_device_irq *dp;
-
-	if ((dp = ebus_blackp) != NULL) {
-		for (; dp->name != NULL; dp++) {
-			if (strcmp(name, dp->name) == 0) {
-				return pcic_pin_to_irq(dp->pin, name);
-			}
-		}
-	}
-	return 0;
-}
-
-static void __init fill_ebus_child(struct device_node *dp,
-				   struct linux_ebus_child *dev)
-{
-	const int *regs;
-	const int *irqs;
-	int i, len;
-
-	dev->prom_node = dp;
-	regs = of_get_property(dp, "reg", &len);
-	if (!regs)
-		len = 0;
-	dev->num_addrs = len / sizeof(regs[0]);
-
-	for (i = 0; i < dev->num_addrs; i++) {
-		if (regs[i] >= dev->parent->num_addrs) {
-			prom_printf("UGH: property for %s was %d, need < %d\n",
-				    dev->prom_node->name, len,
-				    dev->parent->num_addrs);
-			panic(__func__);
-		}
-
-		/* XXX resource */
-		dev->resource[i].start =
-			dev->parent->resource[regs[i]].start;
-	}
-
-	for (i = 0; i < PROMINTR_MAX; i++)
-		dev->irqs[i] = PCI_IRQ_NONE;
-
-	if ((dev->irqs[0] = ebus_blacklist_irq(dev->prom_node->name)) != 0) {
-		dev->num_irqs = 1;
-	} else {
-		irqs = of_get_property(dp, "interrupts", &len);
-		if (!irqs) {
-			dev->num_irqs = 0;
-			dev->irqs[0] = 0;
-			if (dev->parent->num_irqs != 0) {
-				dev->num_irqs = 1;
-				dev->irqs[0] = dev->parent->irqs[0];
-			}
-		} else {
-			dev->num_irqs = len / sizeof(irqs[0]);
-			if (irqs[0] == 0 || irqs[0] >= 8) {
-				/*
-				 * XXX Zero is a valid pin number...
-				 * This works as long as Ebus is not wired
-				 * to INTA#.
-				 */
-				printk("EBUS: %s got bad irq %d from PROM\n",
-				       dev->prom_node->name, irqs[0]);
-				dev->num_irqs = 0;
-				dev->irqs[0] = 0;
-			} else {
-				dev->irqs[0] =
-					pcic_pin_to_irq(irqs[0],
-							dev->prom_node->name);
-			}
-		}
-	}
-}
-
-static void __init fill_ebus_device(struct device_node *dp,
-				    struct linux_ebus_device *dev)
-{
-	const struct linux_prom_registers *regs;
-	struct linux_ebus_child *child;
-	struct dev_archdata *sd;
-	const int *irqs;
-	int i, n, len;
-	unsigned long baseaddr;
-
-	dev->prom_node = dp;
-
-	regs = of_get_property(dp, "reg", &len);
-	if (!regs)
-		len = 0;
-	if (len % sizeof(struct linux_prom_registers)) {
-		prom_printf("UGH: proplen for %s was %d, need multiple of %d\n",
-			    dev->prom_node->name, len,
-			    (int)sizeof(struct linux_prom_registers));
-		panic(__func__);
-	}
-	dev->num_addrs = len / sizeof(struct linux_prom_registers);
-
-	for (i = 0; i < dev->num_addrs; i++) {
-		/*
-		 * XXX Collect JE-1 PROM
-		 * 
-		 * Example - JS-E with 3.11:
-		 *  /ebus
-		 *      regs 
-		 *        0x00000000, 0x0, 0x00000000, 0x0, 0x00000000,
-		 *        0x82000010, 0x0, 0xf0000000, 0x0, 0x01000000,
-		 *        0x82000014, 0x0, 0x38800000, 0x0, 0x00800000,
-		 *      ranges
-		 *        0x00, 0x00000000, 0x02000010, 0x0, 0x0, 0x01000000,
-		 *        0x01, 0x01000000, 0x02000014, 0x0, 0x0, 0x00800000,
-		 *  /ebus/8042
-		 *      regs
-		 *        0x00000001, 0x00300060, 0x00000008,
-		 *        0x00000001, 0x00300060, 0x00000008,
-		 */
-		n = regs[i].which_io;
-		if (n >= 4) {
-			/* XXX This is copied from old JE-1 by Gleb. */
-			n = (regs[i].which_io - 0x10) >> 2;
-		} else {
-			;
-		}
-
-/*
- * XXX Now as we have regions, why don't we make an on-demand allocation...
- */
-		dev->resource[i].start = 0;
-		if ((baseaddr = dev->bus->self->resource[n].start +
-		    regs[i].phys_addr) != 0) {
-			/* dev->resource[i].name = dev->prom_name; */
-			if ((baseaddr = (unsigned long) ioremap(baseaddr,
-			    regs[i].reg_size)) == 0) {
-				panic("ebus: unable to remap dev %s",
-				      dev->prom_node->name);
-			}
-		}
-		dev->resource[i].start = baseaddr;	/* XXX Unaligned */
-	}
-
-	for (i = 0; i < PROMINTR_MAX; i++)
-		dev->irqs[i] = PCI_IRQ_NONE;
-
-	if ((dev->irqs[0] = ebus_blacklist_irq(dev->prom_node->name)) != 0) {
-		dev->num_irqs = 1;
-	} else {
-		irqs = of_get_property(dp, "interrupts", &len);
-		if (!irqs) {
-			dev->num_irqs = 0;
-			if ((dev->irqs[0] = dev->bus->self->irq) != 0) {
-				dev->num_irqs = 1;
-/* P3 */ /* printk("EBUS: child %s irq %d from parent\n", dev->prom_name, dev->irqs[0]); */
-			}
-		} else {
-			dev->num_irqs = 1;  /* dev->num_irqs = len / sizeof(irqs[0]); */
-			if (irqs[0] == 0 || irqs[0] >= 8) {
-				/* See above for the parent. XXX */
-				printk("EBUS: %s got bad irq %d from PROM\n",
-				       dev->prom_node->name, irqs[0]);
-				dev->num_irqs = 0;
-				dev->irqs[0] = 0;
-			} else {
-				dev->irqs[0] =
-					pcic_pin_to_irq(irqs[0],
-							dev->prom_node->name);
-			}
-		}
-	}
-
-	sd = &dev->ofdev.dev.archdata;
-	sd->prom_node = dp;
-	sd->op = &dev->ofdev;
-	sd->iommu = dev->bus->ofdev.dev.parent->archdata.iommu;
-
-	dev->ofdev.node = dp;
-	dev->ofdev.dev.parent = &dev->bus->ofdev.dev;
-	dev->ofdev.dev.bus = &ebus_bus_type;
-	sprintf(dev->ofdev.dev.bus_id, "ebus[%08x]", dp->node);
-
-	/* Register with core */
-	if (of_device_register(&dev->ofdev) != 0)
-		printk(KERN_DEBUG "ebus: device registration error for %s!\n",
-		       dp->path_component_name);
-
-	if ((dp = dp->child) != NULL) {
-		dev->children = (struct linux_ebus_child *)
-			ebus_alloc(sizeof(struct linux_ebus_child));
-
-		child = dev->children;
-		child->next = NULL;
-		child->parent = dev;
-		child->bus = dev->bus;
-		fill_ebus_child(dp, child);
-
-		while ((dp = dp->sibling) != NULL) {
-			child->next = (struct linux_ebus_child *)
-				ebus_alloc(sizeof(struct linux_ebus_child));
-
-			child = child->next;
-			child->next = NULL;
-			child->parent = dev;
-			child->bus = dev->bus;
-			fill_ebus_child(dp, child);
-		}
-	}
-}
-
-void __init ebus_init(void)
-{
-	const struct linux_prom_pci_registers *regs;
-	struct linux_pbm_info *pbm;
-	struct linux_ebus_device *dev;
-	struct linux_ebus *ebus;
-	struct ebus_system_entry *sp;
-	struct pci_dev *pdev;
-	struct pcidev_cookie *cookie;
-	struct device_node *dp;
-	struct resource *p;
-	unsigned short pci_command;
-	int len, reg, nreg;
-	int num_ebus = 0;
-
-	dp = of_find_node_by_path("/");
-	for (sp = ebus_blacklist; sp->esname != NULL; sp++) {
-		if (strcmp(dp->name, sp->esname) == 0) {
-			ebus_blackp = sp->ipt;
-			break;
-		}
-	}
-
-	pdev = pci_get_device(PCI_VENDOR_ID_SUN, PCI_DEVICE_ID_SUN_EBUS, NULL);
-	if (!pdev)
-		return;
-
-	cookie = pdev->sysdata;
-	dp = cookie->prom_node;
-
-	ebus_chain = ebus = (struct linux_ebus *)
-			ebus_alloc(sizeof(struct linux_ebus));
-	ebus->next = NULL;
-
-	while (dp) {
-		struct device_node *nd;
-
-		ebus->prom_node = dp;
-		ebus->self = pdev;
-		ebus->parent = pbm = cookie->pbm;
-
-		/* Enable BUS Master. */
-		pci_read_config_word(pdev, PCI_COMMAND, &pci_command);
-		pci_command |= PCI_COMMAND_MASTER;
-		pci_write_config_word(pdev, PCI_COMMAND, pci_command);
-
-		regs = of_get_property(dp, "reg", &len);
-		if (!regs) {
-			prom_printf("%s: can't find reg property\n",
-				    __func__);
-			prom_halt();
-		}
-		nreg = len / sizeof(struct linux_prom_pci_registers);
-
-		p = &ebus->self->resource[0];
-		for (reg = 0; reg < nreg; reg++) {
-			if (!(regs[reg].which_io & 0x03000000))
-				continue;
-
-			(p++)->start = regs[reg].phys_lo;
-		}
-
-		ebus->ofdev.node = dp;
-		ebus->ofdev.dev.parent = &pdev->dev;
-		ebus->ofdev.dev.bus = &ebus_bus_type;
-		sprintf(ebus->ofdev.dev.bus_id, "ebus%d", num_ebus);
-
-		/* Register with core */
-		if (of_device_register(&ebus->ofdev) != 0)
-			printk(KERN_DEBUG "ebus: device registration error for %s!\n",
-			       dp->path_component_name);
-
-
-		nd = dp->child;
-		if (!nd)
-			goto next_ebus;
-
-		ebus->devices = (struct linux_ebus_device *)
-				ebus_alloc(sizeof(struct linux_ebus_device));
-
-		dev = ebus->devices;
-		dev->next = NULL;
-		dev->children = NULL;
-		dev->bus = ebus;
-		fill_ebus_device(nd, dev);
-
-		while ((nd = nd->sibling) != NULL) {
-			dev->next = (struct linux_ebus_device *)
-				ebus_alloc(sizeof(struct linux_ebus_device));
-
-			dev = dev->next;
-			dev->next = NULL;
-			dev->children = NULL;
-			dev->bus = ebus;
-			fill_ebus_device(nd, dev);
-		}
-
-	next_ebus:
-		pdev = pci_get_device(PCI_VENDOR_ID_SUN,
-				       PCI_DEVICE_ID_SUN_EBUS, pdev);
-		if (!pdev)
-			break;
-
-		cookie = pdev->sysdata;
-		dp = cookie->prom_node;
-
-		ebus->next = (struct linux_ebus *)
-			ebus_alloc(sizeof(struct linux_ebus));
-		ebus = ebus->next;
-		ebus->next = NULL;
-		++num_ebus;
-	}
-	if (pdev)
-		pci_dev_put(pdev);
-}
diff --git a/arch/sparc/kernel/entry.S b/arch/sparc/kernel/entry.S
index e8cdf71..faf9ccd 100644
--- a/arch/sparc/kernel/entry.S
+++ b/arch/sparc/kernel/entry.S
@@ -20,11 +20,7 @@
 #include <asm/memreg.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
-#ifdef CONFIG_SUN4
-#include <asm/pgtsun4.h>
-#else
 #include <asm/pgtsun4c.h>
-#endif
 #include <asm/winmacro.h>
 #include <asm/signal.h>
 #include <asm/obio.h>
@@ -276,17 +272,18 @@
 	 */
 maybe_smp4m_msg:
 	GET_PROCESSOR4M_ID(o3)
-	set	sun4m_interrupts, %l5
-	ld	[%l5], %o5
+	sethi	%hi(sun4m_irq_percpu), %l5
+	sll	%o3, 2, %o3
+	or	%l5, %lo(sun4m_irq_percpu), %o5
 	sethi	%hi(0x40000000), %o2
-	sll	%o3, 12, %o3
 	ld	[%o5 + %o3], %o1
-	andcc	%o1, %o2, %g0
+	ld	[%o1 + 0x00], %o3	! sun4m_irq_percpu[cpu]->pending
+	andcc	%o3, %o2, %g0
 	be,a	smp4m_ticker
 	 cmp	%l7, 14
-	st	%o2, [%o5 + 0x4]
+	st	%o2, [%o1 + 0x04]	! sun4m_irq_percpu[cpu]->clear=0x40000000
 	WRITE_PAUSE
-	ld	[%o5], %g0
+	ld	[%o1 + 0x00], %g0	! sun4m_irq_percpu[cpu]->pending
 	WRITE_PAUSE
 	or	%l0, PSR_PIL, %l4
 	wr	%l4, 0x0, %psr
@@ -304,16 +301,16 @@
 	SAVE_ALL
 	sethi	%hi(0x80000000), %o2
 	GET_PROCESSOR4M_ID(o0)
-	set	sun4m_interrupts, %l5
-	ld	[%l5], %o5
-	sll	%o0, 12, %o0
-	add	%o5, %o0, %o5
-	ld	[%o5], %o3
+	sethi	%hi(sun4m_irq_percpu), %l5
+	or	%l5, %lo(sun4m_irq_percpu), %o5
+	sll	%o0, 2, %o0
+	ld	[%o5 + %o0], %o5
+	ld	[%o5 + 0x00], %o3	! sun4m_irq_percpu[cpu]->pending
 	andcc	%o3, %o2, %g0
 	be	1f			! Must be an NMI async memory error
-	 st	%o2, [%o5 + 4]
+	 st	%o2, [%o5 + 0x04]	! sun4m_irq_percpu[cpu]->clear=0x80000000
 	WRITE_PAUSE
-	ld	[%o5], %g0
+	ld	[%o5 + 0x00], %g0	! sun4m_irq_percpu[cpu]->pending
 	WRITE_PAUSE
 	or	%l0, PSR_PIL, %l4
 	wr	%l4, 0x0, %psr
@@ -327,12 +324,11 @@
 1:
 	/* NMI async memory error handling. */
 	sethi	%hi(0x80000000), %l4
-	sethi	%hi(0x4000), %o3
-	sub	%o5, %o0, %o5
-	add	%o5, %o3, %l5
-	st	%l4, [%l5 + 0xc]
+	sethi	%hi(sun4m_irq_global), %o5
+	ld	[%o5 + %lo(sun4m_irq_global)], %l5
+	st	%l4, [%l5 + 0x0c]	! sun4m_irq_global->mask_set=0x80000000
 	WRITE_PAUSE
-	ld	[%l5], %g0
+	ld	[%l5 + 0x00], %g0	! sun4m_irq_global->pending
 	WRITE_PAUSE
 	or	%l0, PSR_PIL, %l4
 	wr	%l4, 0x0, %psr
@@ -341,9 +337,9 @@
 	WRITE_PAUSE
 	call	sun4m_nmi
 	 nop
-	st	%l4, [%l5 + 0x8]
+	st	%l4, [%l5 + 0x08]	! sun4m_irq_global->mask_clear=0x80000000
 	WRITE_PAUSE
-	ld	[%l5], %g0
+	ld	[%l5 + 0x00], %g0	! sun4m_irq_global->pending
 	WRITE_PAUSE
 	RESTORE_ALL
 
@@ -775,11 +771,7 @@
  * Ugly, but we cant use hardware flushing on the sun4 and we'd require
  * two instructions (Anton)
  */
-#ifdef CONFIG_SUN4
-vac_hwflush_patch1_on:		nop
-#else
 vac_hwflush_patch1_on:		addcc	%l7, -PAGE_SIZE, %l7
-#endif
 
 vac_hwflush_patch2_on:		sta	%g0, [%l3 + %l7] ASI_HWFLUSHSEG
 
@@ -798,42 +790,10 @@
 ! %l7 = 1 for textfault
 ! We want error in %l5, vaddr in %l6
 sun4c_fault:
-#ifdef CONFIG_SUN4
-	sethi	%hi(sun4c_memerr_reg), %l4
-	ld	[%l4+%lo(sun4c_memerr_reg)], %l4  ! memerr ctrl reg addr
-	ld	[%l4], %l6		! memerr ctrl reg
-	ld	[%l4 + 4], %l5		! memerr vaddr reg
-	andcc	%l6, 0x80, %g0		! check for error type
-	st	%g0, [%l4 + 4]		! clear the error
-	be	0f			! normal error
-	 sethi	%hi(AC_BUS_ERROR), %l4	! bus err reg addr
-
-	call	prom_halt	! something weird happened
-					! what exactly did happen?
-					! what should we do here?
-
-0:	or	%l4, %lo(AC_BUS_ERROR), %l4	! bus err reg addr
-	lduba	[%l4] ASI_CONTROL, %l6	! bus err reg
-
-	cmp    %l7, 1			! text fault?
-	be	1f			! yes
-	 nop
-
-	ld     [%l1], %l4		! load instruction that caused fault
-	srl	%l4, 21, %l4
-	andcc	%l4, 1, %g0		! store instruction?
-
-	be	1f			! no
-	 sethi	%hi(SUN4C_SYNC_BADWRITE), %l4 ! yep
-					! %lo(SUN4C_SYNC_BADWRITE) = 0
-	or	%l4, %l6, %l6		! set write bit to emulate sun4c
-1:
-#else
 	sethi	%hi(AC_SYNC_ERR), %l4
 	add	%l4, 0x4, %l6			! AC_SYNC_VA in %l6
 	lda	[%l6] ASI_CONTROL, %l5		! Address
 	lda	[%l4] ASI_CONTROL, %l6		! Error, retained for a bit
-#endif
 
 	andn	%l5, 0xfff, %l5			! Encode all info into l7
 	srl	%l6, 14, %l4
@@ -880,12 +840,7 @@
 	or      %l4, %lo(swapper_pg_dir), %l4
 	sll     %l6, 2, %l6
 	ld      [%l4 + %l6], %l4
-#ifdef CONFIG_SUN4
-	sethi	%hi(PAGE_MASK), %l6
-	andcc	%l4, %l6, %g0
-#else
 	andcc   %l4, PAGE_MASK, %g0
-#endif
 	be      sun4c_fault_fromuser
 	 lduXa  [%l5] ASI_SEGMAP, %l4
 
@@ -937,11 +892,7 @@
 	ld	[%l6 + 0x08], %l3	! tmp = entry->vaddr
 
 	! Flush segment from the cache.
-#ifdef CONFIG_SUN4
-	sethi	%hi((128 * 1024)), %l7
-#else
 	sethi	%hi((64 * 1024)), %l7
-#endif
 9:
 vac_hwflush_patch1:
 vac_linesize_patch:
@@ -1029,12 +980,7 @@
 	or	%l4, %lo(swapper_pg_dir), %l4
 	sll	%l3, 2, %l3
 	ld	[%l4 + %l3], %l4
-#ifndef CONFIG_SUN4
 	and	%l4, PAGE_MASK, %l4
-#else
-	sethi	%hi(PAGE_MASK), %l6
-	and	%l4, %l6, %l4
-#endif
 
 	srl	%l5, (PAGE_SHIFT - 2), %l6
 	and	%l6, ((SUN4C_PTRS_PER_PTE - 1) << 2), %l6
diff --git a/arch/sparc/kernel/head.S b/arch/sparc/kernel/head.S
index 50d9a16..2d325fd 100644
--- a/arch/sparc/kernel/head.S
+++ b/arch/sparc/kernel/head.S
@@ -63,15 +63,9 @@
 
 	.align 4
 
-#ifndef CONFIG_SUN4
 sun4_notsup:
-	.asciz	"Sparc-Linux sun4 needs a specially compiled kernel, turn CONFIG_SUN4 on.\n\n"
+	.asciz	"Sparc-Linux sun4 support does no longer exist.\n\n"
 	.align 4
-#else
-sun4cdm_notsup:
-	.asciz	"Kernel compiled with CONFIG_SUN4 cannot run on SUN4C/SUN4M/SUN4D\nTurn CONFIG_SUN4 off.\n\n"
-	.align 4
-#endif
 
 sun4e_notsup:
         .asciz  "Sparc-Linux sun4e support does not exist\n\n"
@@ -780,15 +774,6 @@
 		 nop
 
 found_version:
-#ifdef CONFIG_SUN4
-/* For people who try sun4 kernels, even if Configure.help advises them. */
-		ld	[%g7 + 0x68], %o1
-		set	sun4cdm_notsup, %o0
-		call	%o1
-		 nop
-		b	halt_me
-		 nop
-#endif
 /* Get the machine type via the mysterious romvec node operations. */
 
 		add	%g7, 0x1c, %l1		
@@ -1150,15 +1135,6 @@
 		 nop
 
 sun4_init:
-#ifdef CONFIG_SUN4
-/* There, happy now Adrian? */
-		set	cputypval, %o2		! Let everyone know we
-		set	' ', %o0			! are a "sun4 " architecture
-		stb	%o0, [%o2 + 0x4]		
-
-		b got_prop 
-		 nop
-#else
 		sethi   %hi(SUN4_PROM_VECTOR+0x84), %o1
 		ld      [%o1 + %lo(SUN4_PROM_VECTOR+0x84)], %o1
 		set     sun4_notsup, %o0
@@ -1170,7 +1146,7 @@
 		 nop
 1:		ba      1b                      ! Cannot exit into KMON
 		 nop
-#endif
+
 no_sun4e_here:
 		ld	[%g7 + 0x68], %o1
 		set	sun4e_notsup, %o0
diff --git a/arch/sparc/kernel/idprom.c b/arch/sparc/kernel/idprom.c
index fc511f3..223a658 100644
--- a/arch/sparc/kernel/idprom.c
+++ b/arch/sparc/kernel/idprom.c
@@ -12,10 +12,6 @@
 #include <asm/oplib.h>
 #include <asm/idprom.h>
 #include <asm/machines.h>  /* Fun with Sun released architectures. */
-#ifdef CONFIG_SUN4
-#include <asm/sun4paddr.h>
-extern void sun4setup(void);
-#endif
 
 struct idprom *idprom;
 static struct idprom idprom_buffer;
@@ -101,7 +97,4 @@
 		    idprom->id_ethaddr[0], idprom->id_ethaddr[1],
 		    idprom->id_ethaddr[2], idprom->id_ethaddr[3],
 		    idprom->id_ethaddr[4], idprom->id_ethaddr[5]);
-#ifdef CONFIG_SUN4
-	sun4setup();
-#endif
 }
diff --git a/arch/sparc/kernel/ioport.c b/arch/sparc/kernel/ioport.c
index 2a8a847..4f025b3 100644
--- a/arch/sparc/kernel/ioport.c
+++ b/arch/sparc/kernel/ioport.c
@@ -42,10 +42,13 @@
 #include <asm/vaddrs.h>
 #include <asm/oplib.h>
 #include <asm/prom.h>
-#include <asm/sbus.h>
 #include <asm/page.h>
 #include <asm/pgalloc.h>
 #include <asm/dma.h>
+#include <asm/iommu.h>
+#include <asm/io-unit.h>
+
+#include "dma.h"
 
 #define mmu_inval_dma_area(p, l)	/* Anton pulled it out for 2.4.0-xx */
 
@@ -139,15 +142,6 @@
 	}
 }
 
-/*
- */
-void __iomem *sbus_ioremap(struct resource *phyres, unsigned long offset,
-    unsigned long size, char *name)
-{
-	return _sparc_alloc_io(phyres->flags & 0xF,
-	    phyres->start + offset, size, name);
-}
-
 void __iomem *of_ioremap(struct resource *res, unsigned long offset,
 			 unsigned long size, char *name)
 {
@@ -164,13 +158,6 @@
 EXPORT_SYMBOL(of_iounmap);
 
 /*
- */
-void sbus_iounmap(volatile void __iomem *addr, unsigned long size)
-{
-	iounmap(addr);
-}
-
-/*
  * Meat of mapping
  */
 static void __iomem *_sparc_alloc_io(unsigned int busno, unsigned long phys,
@@ -246,63 +233,19 @@
 
 #ifdef CONFIG_SBUS
 
-void sbus_set_sbus64(struct sbus_dev *sdev, int x)
+void sbus_set_sbus64(struct device *dev, int x)
 {
 	printk("sbus_set_sbus64: unsupported\n");
 }
 
-extern unsigned int sun4d_build_irq(struct sbus_dev *sdev, int irq);
-void __init sbus_fill_device_irq(struct sbus_dev *sdev)
-{
-	struct linux_prom_irqs irqs[PROMINTR_MAX];
-	int len;
-
-	len = prom_getproperty(sdev->prom_node, "intr",
-			       (char *)irqs, sizeof(irqs));
-	if (len != -1) {
-		sdev->num_irqs = len / 8;
-		if (sdev->num_irqs == 0) {
-			sdev->irqs[0] = 0;
-		} else if (sparc_cpu_model == sun4d) {
-			for (len = 0; len < sdev->num_irqs; len++)
-				sdev->irqs[len] =
-					sun4d_build_irq(sdev, irqs[len].pri);
-		} else {
-			for (len = 0; len < sdev->num_irqs; len++)
-				sdev->irqs[len] = irqs[len].pri;
-		}
-	} else {
-		int interrupts[PROMINTR_MAX];
-
-		/* No "intr" node found-- check for "interrupts" node.
-		 * This node contains SBus interrupt levels, not IPLs
-		 * as in "intr", and no vector values.  We convert
-		 * SBus interrupt levels to PILs (platform specific).
-		 */
-		len = prom_getproperty(sdev->prom_node, "interrupts",
-				       (char *)interrupts, sizeof(interrupts));
-		if (len == -1) {
-			sdev->irqs[0] = 0;
-			sdev->num_irqs = 0;
-		} else {
-			sdev->num_irqs = len / sizeof(int);
-			for (len = 0; len < sdev->num_irqs; len++) {
-				sdev->irqs[len] =
-					sbint_to_irq(sdev, interrupts[len]);
-			}
-		}
-	} 
-}
-
 /*
  * Allocate a chunk of memory suitable for DMA.
  * Typically devices use them for control blocks.
  * CPU may access them without any explicit flushing.
- *
- * XXX Some clever people know that sdev is not used and supply NULL. Watch.
  */
-void *sbus_alloc_consistent(struct sbus_dev *sdev, long len, u32 *dma_addrp)
+void *sbus_alloc_consistent(struct device *dev, long len, u32 *dma_addrp)
 {
+	struct of_device *op = to_of_device(dev);
 	unsigned long len_total = (len + PAGE_SIZE-1) & PAGE_MASK;
 	unsigned long va;
 	struct resource *res;
@@ -336,13 +279,10 @@
 	 * XXX That's where sdev would be used. Currently we load
 	 * all iommu tables with the same translations.
 	 */
-	if (mmu_map_dma_area(dma_addrp, va, res->start, len_total) != 0)
+	if (mmu_map_dma_area(dev, dma_addrp, va, res->start, len_total) != 0)
 		goto err_noiommu;
 
-	/* Set the resource name, if known. */
-	if (sdev) {
-		res->name = sdev->prom_name;
-	}
+	res->name = op->node->name;
 
 	return (void *)(unsigned long)res->start;
 
@@ -356,7 +296,7 @@
 	return NULL;
 }
 
-void sbus_free_consistent(struct sbus_dev *sdev, long n, void *p, u32 ba)
+void sbus_free_consistent(struct device *dev, long n, void *p, u32 ba)
 {
 	struct resource *res;
 	struct page *pgv;
@@ -383,8 +323,8 @@
 	kfree(res);
 
 	/* mmu_inval_dma_area(va, n); */ /* it's consistent, isn't it */
-	pgv = mmu_translate_dvma(ba);
-	mmu_unmap_dma_area(ba, n);
+	pgv = virt_to_page(p);
+	mmu_unmap_dma_area(dev, ba, n);
 
 	__free_pages(pgv, get_order(n));
 }
@@ -394,7 +334,7 @@
  * CPU view of this memory may be inconsistent with
  * a device view and explicit flushing is necessary.
  */
-dma_addr_t sbus_map_single(struct sbus_dev *sdev, void *va, size_t len, int direction)
+dma_addr_t sbus_map_single(struct device *dev, void *va, size_t len, int direction)
 {
 	/* XXX why are some lengths signed, others unsigned? */
 	if (len <= 0) {
@@ -404,17 +344,17 @@
 	if (len > 256*1024) {			/* __get_free_pages() limit */
 		return 0;
 	}
-	return mmu_get_scsi_one(va, len, sdev->bus);
+	return mmu_get_scsi_one(dev, va, len);
 }
 
-void sbus_unmap_single(struct sbus_dev *sdev, dma_addr_t ba, size_t n, int direction)
+void sbus_unmap_single(struct device *dev, dma_addr_t ba, size_t n, int direction)
 {
-	mmu_release_scsi_one(ba, n, sdev->bus);
+	mmu_release_scsi_one(dev, ba, n);
 }
 
-int sbus_map_sg(struct sbus_dev *sdev, struct scatterlist *sg, int n, int direction)
+int sbus_map_sg(struct device *dev, struct scatterlist *sg, int n, int direction)
 {
-	mmu_get_scsi_sgl(sg, n, sdev->bus);
+	mmu_get_scsi_sgl(dev, sg, n);
 
 	/*
 	 * XXX sparc64 can return a partial length here. sun4c should do this
@@ -423,145 +363,28 @@
 	return n;
 }
 
-void sbus_unmap_sg(struct sbus_dev *sdev, struct scatterlist *sg, int n, int direction)
+void sbus_unmap_sg(struct device *dev, struct scatterlist *sg, int n, int direction)
 {
-	mmu_release_scsi_sgl(sg, n, sdev->bus);
+	mmu_release_scsi_sgl(dev, sg, n);
 }
 
-/*
- */
-void sbus_dma_sync_single_for_cpu(struct sbus_dev *sdev, dma_addr_t ba, size_t size, int direction)
+void sbus_dma_sync_single_for_cpu(struct device *dev, dma_addr_t ba, size_t size, int direction)
 {
-#if 0
-	unsigned long va;
-	struct resource *res;
-
-	/* We do not need the resource, just print a message if invalid. */
-	res = _sparc_find_resource(&_sparc_dvma, ba);
-	if (res == NULL)
-		panic("sbus_dma_sync_single: 0x%x\n", ba);
-
-	va = page_address(mmu_translate_dvma(ba)); /* XXX higmem */
-	/*
-	 * XXX This bogosity will be fixed with the iommu rewrite coming soon
-	 * to a kernel near you. - Anton
-	 */
-	/* mmu_inval_dma_area(va, (size + PAGE_SIZE-1) & PAGE_MASK); */
-#endif
 }
 
-void sbus_dma_sync_single_for_device(struct sbus_dev *sdev, dma_addr_t ba, size_t size, int direction)
+void sbus_dma_sync_single_for_device(struct device *dev, dma_addr_t ba, size_t size, int direction)
 {
-#if 0
-	unsigned long va;
-	struct resource *res;
-
-	/* We do not need the resource, just print a message if invalid. */
-	res = _sparc_find_resource(&_sparc_dvma, ba);
-	if (res == NULL)
-		panic("sbus_dma_sync_single: 0x%x\n", ba);
-
-	va = page_address(mmu_translate_dvma(ba)); /* XXX higmem */
-	/*
-	 * XXX This bogosity will be fixed with the iommu rewrite coming soon
-	 * to a kernel near you. - Anton
-	 */
-	/* mmu_inval_dma_area(va, (size + PAGE_SIZE-1) & PAGE_MASK); */
-#endif
 }
 
-void sbus_dma_sync_sg_for_cpu(struct sbus_dev *sdev, struct scatterlist *sg, int n, int direction)
-{
-	printk("sbus_dma_sync_sg_for_cpu: not implemented yet\n");
-}
-
-void sbus_dma_sync_sg_for_device(struct sbus_dev *sdev, struct scatterlist *sg, int n, int direction)
-{
-	printk("sbus_dma_sync_sg_for_device: not implemented yet\n");
-}
-
-/* Support code for sbus_init().  */
-/*
- * XXX This functions appears to be a distorted version of
- * prom_sbus_ranges_init(), with all sun4d stuff cut away.
- * Ask DaveM what is going on here, how is sun4d supposed to work... XXX
- */
-/* added back sun4d patch from Thomas Bogendoerfer - should be OK (crn) */
-void __init sbus_arch_bus_ranges_init(struct device_node *pn, struct sbus_bus *sbus)
-{
-	int parent_node = pn->node;
-
-	if (sparc_cpu_model == sun4d) {
-		struct linux_prom_ranges iounit_ranges[PROMREG_MAX];
-		int num_iounit_ranges, len;
-
-		len = prom_getproperty(parent_node, "ranges",
-				       (char *) iounit_ranges,
-				       sizeof (iounit_ranges));
-		if (len != -1) {
-			num_iounit_ranges =
-				(len / sizeof(struct linux_prom_ranges));
-			prom_adjust_ranges(sbus->sbus_ranges,
-					   sbus->num_sbus_ranges,
-					   iounit_ranges, num_iounit_ranges);
-		}
-	}
-}
-
-void __init sbus_setup_iommu(struct sbus_bus *sbus, struct device_node *dp)
-{
-#ifndef CONFIG_SUN4
-	struct device_node *parent = dp->parent;
-
-	if (sparc_cpu_model != sun4d &&
-	    parent != NULL &&
-	    !strcmp(parent->name, "iommu")) {
-		extern void iommu_init(int iommu_node, struct sbus_bus *sbus);
-
-		iommu_init(parent->node, sbus);
-	}
-
-	if (sparc_cpu_model == sun4d) {
-		extern void iounit_init(int sbi_node, int iounit_node,
-					struct sbus_bus *sbus);
-
-		iounit_init(dp->node, parent->node, sbus);
-	}
-#endif
-}
-
-void __init sbus_setup_arch_props(struct sbus_bus *sbus, struct device_node *dp)
-{
-	if (sparc_cpu_model == sun4d) {
-		struct device_node *parent = dp->parent;
-
-		sbus->devid = of_getintprop_default(parent, "device-id", 0);
-		sbus->board = of_getintprop_default(parent, "board#", 0);
-	}
-}
-
-int __init sbus_arch_preinit(void)
+static int __init sparc_register_ioport(void)
 {
 	register_proc_sparc_ioport();
 
-#ifdef CONFIG_SUN4
-	{
-		extern void sun4_dvma_init(void);
-		sun4_dvma_init();
-	}
-	return 1;
-#else
 	return 0;
-#endif
 }
 
-void __init sbus_arch_postinit(void)
-{
-	if (sparc_cpu_model == sun4d) {
-		extern void sun4d_init_sbi_irq(void);
-		sun4d_init_sbi_irq();
-	}
-}
+arch_initcall(sparc_register_ioport);
+
 #endif /* CONFIG_SBUS */
 
 #ifdef CONFIG_PCI
diff --git a/arch/sparc/kernel/irq.h b/arch/sparc/kernel/irq.h
index 32ef3eb..db75138 100644
--- a/arch/sparc/kernel/irq.h
+++ b/arch/sparc/kernel/irq.h
@@ -13,7 +13,6 @@
 BTFIXUPDEF_CALL(void, disable_pil_irq, unsigned int)
 BTFIXUPDEF_CALL(void, enable_pil_irq, unsigned int)
 BTFIXUPDEF_CALL(void, clear_clock_irq, void)
-BTFIXUPDEF_CALL(void, clear_profile_irq, int)
 BTFIXUPDEF_CALL(void, load_profile_irq, int, unsigned int)
 
 static inline void __disable_irq(unsigned int irq)
@@ -41,11 +40,6 @@
 	BTFIXUP_CALL(clear_clock_irq)();
 }
 
-static inline void clear_profile_irq(int irq)
-{
-	BTFIXUP_CALL(clear_profile_irq)(irq);
-}
-
 static inline void load_profile_irq(int cpu, int limit)
 {
 	BTFIXUP_CALL(load_profile_irq)(cpu, limit);
diff --git a/arch/sparc/kernel/of_device.c b/arch/sparc/kernel/of_device.c
index f58c537..0837bd52e 100644
--- a/arch/sparc/kernel/of_device.c
+++ b/arch/sparc/kernel/of_device.c
@@ -29,15 +29,38 @@
 }
 EXPORT_SYMBOL(of_find_device_by_node);
 
-#ifdef CONFIG_PCI
-struct bus_type ebus_bus_type;
-EXPORT_SYMBOL(ebus_bus_type);
-#endif
+unsigned int irq_of_parse_and_map(struct device_node *node, int index)
+{
+	struct of_device *op = of_find_device_by_node(node);
 
-#ifdef CONFIG_SBUS
-struct bus_type sbus_bus_type;
-EXPORT_SYMBOL(sbus_bus_type);
-#endif
+	if (!op || index >= op->num_irqs)
+		return 0;
+
+	return op->irqs[index];
+}
+EXPORT_SYMBOL(irq_of_parse_and_map);
+
+/* Take the archdata values for IOMMU, STC, and HOSTDATA found in
+ * BUS and propagate to all child of_device objects.
+ */
+void of_propagate_archdata(struct of_device *bus)
+{
+	struct dev_archdata *bus_sd = &bus->dev.archdata;
+	struct device_node *bus_dp = bus->node;
+	struct device_node *dp;
+
+	for (dp = bus_dp->child; dp; dp = dp->sibling) {
+		struct of_device *op = of_find_device_by_node(dp);
+
+		op->dev.archdata.iommu = bus_sd->iommu;
+		op->dev.archdata.stc = bus_sd->stc;
+		op->dev.archdata.host_controller = bus_sd->host_controller;
+		op->dev.archdata.numa_node = bus_sd->numa_node;
+
+		if (dp->child)
+			of_propagate_archdata(op);
+	}
+}
 
 struct bus_type of_platform_bus_type;
 EXPORT_SYMBOL(of_platform_bus_type);
@@ -327,6 +350,27 @@
 	return 1;
 }
 
+static int __init use_1to1_mapping(struct device_node *pp)
+{
+	/* If we have a ranges property in the parent, use it.  */
+	if (of_find_property(pp, "ranges", NULL) != NULL)
+		return 0;
+
+	/* Some SBUS devices use intermediate nodes to express
+	 * hierarchy within the device itself.  These aren't
+	 * real bus nodes, and don't have a 'ranges' property.
+	 * But, we should still pass the translation work up
+	 * to the SBUS itself.
+	 */
+	if (!strcmp(pp->name, "dma") ||
+	    !strcmp(pp->name, "espdma") ||
+	    !strcmp(pp->name, "ledma") ||
+	    !strcmp(pp->name, "lebuffer"))
+		return 0;
+
+	return 1;
+}
+
 static int of_resource_verbose;
 
 static void __init build_device_resources(struct of_device *op,
@@ -373,10 +417,7 @@
 
 		flags = bus->get_flags(reg, 0);
 
-		/* If the immediate parent has no ranges property to apply,
-		 * just use a 1<->1 mapping.
-		 */
-		if (of_find_property(pp, "ranges", NULL) == NULL) {
+		if (use_1to1_mapping(pp)) {
 			result = of_read_addr(addr, na);
 			goto build_res;
 		}
@@ -565,15 +606,6 @@
 	int err;
 
 	err = of_bus_type_init(&of_platform_bus_type, "of");
-#ifdef CONFIG_PCI
-	if (!err)
-		err = of_bus_type_init(&ebus_bus_type, "ebus");
-#endif
-#ifdef CONFIG_SBUS
-	if (!err)
-		err = of_bus_type_init(&sbus_bus_type, "sbus");
-#endif
-
 	if (!err)
 		scan_of_devices();
 
diff --git a/arch/sparc/kernel/pcic.c b/arch/sparc/kernel/pcic.c
index a6a6f98..462584e 100644
--- a/arch/sparc/kernel/pcic.c
+++ b/arch/sparc/kernel/pcic.c
@@ -17,8 +17,6 @@
 #include <linux/slab.h>
 #include <linux/jiffies.h>
 
-#include <asm/ebus.h>
-#include <asm/sbus.h> /* for sanity check... */
 #include <asm/swift.h> /* for cache flushing. */
 #include <asm/io.h>
 
@@ -430,7 +428,6 @@
 
 	pcic_pbm_scan_bus(pcic);
 
-	ebus_init();
 	return 0;
 }
 
@@ -493,10 +490,6 @@
 				 * do ioremap() before accessing PC-style I/O,
 				 * we supply virtual, ready to access address.
 				 *
-				 * Ebus devices do not come here even if
-				 * CheerIO makes a similar conversion.
-				 * See ebus.c for details.
-				 *
 				 * Note that request_region()
 				 * works for these devices.
 				 *
@@ -677,7 +670,7 @@
 }
 
 /*
- * pcic_pin_to_irq() is exported to ebus.c.
+ * pcic_pin_to_irq() is exported to bus probing code
  */
 unsigned int
 pcic_pin_to_irq(unsigned int pin, const char *name)
@@ -904,11 +897,6 @@
 	local_irq_restore(flags);
 }
 
-static void pcic_clear_profile_irq(int cpu)
-{
-	printk("PCIC: unimplemented code: FILE=%s LINE=%d", __FILE__, __LINE__);
-}
-
 static void pcic_load_profile_irq(int cpu, unsigned int limit)
 {
 	printk("PCIC: unimplemented code: FILE=%s LINE=%d", __FILE__, __LINE__);
@@ -934,7 +922,6 @@
 	BTFIXUPSET_CALL(enable_pil_irq, pcic_enable_pil_irq, BTFIXUPCALL_NORM);
 	BTFIXUPSET_CALL(disable_pil_irq, pcic_disable_pil_irq, BTFIXUPCALL_NORM);
 	BTFIXUPSET_CALL(clear_clock_irq, pcic_clear_clock_irq, BTFIXUPCALL_NORM);
-	BTFIXUPSET_CALL(clear_profile_irq, pcic_clear_profile_irq, BTFIXUPCALL_NORM);
 	BTFIXUPSET_CALL(load_profile_irq, pcic_load_profile_irq, BTFIXUPCALL_NORM);
 }
 
diff --git a/arch/sparc/kernel/pmc.c b/arch/sparc/kernel/pmc.c
index 7eca887..2afcfab 100644
--- a/arch/sparc/kernel/pmc.c
+++ b/arch/sparc/kernel/pmc.c
@@ -8,11 +8,11 @@
 #include <linux/fs.h>
 #include <linux/errno.h>
 #include <linux/init.h>
-#include <linux/miscdevice.h>
 #include <linux/pm.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 
 #include <asm/io.h>
-#include <asm/sbus.h>
 #include <asm/oplib.h>
 #include <asm/uaccess.h>
 #include <asm/auxio.h>
@@ -23,17 +23,15 @@
  * #define PMC_NO_IDLE
  */
 
-#define PMC_MINOR	MISC_DYNAMIC_MINOR
 #define PMC_OBPNAME	"SUNW,pmc"
 #define PMC_DEVNAME "pmc"
 
 #define PMC_IDLE_REG	0x00
 #define PMC_IDLE_ON		0x01
 
-volatile static u8 __iomem *regs; 
-static int pmc_regsize;
+static u8 __iomem *regs;
 
-#define pmc_readb(offs)			(sbus_readb(regs+offs))
+#define pmc_readb(offs)		(sbus_readb(regs+offs))
 #define pmc_writeb(val, offs) 	(sbus_writeb(val, regs+offs))
 
 /* 
@@ -53,31 +51,11 @@
 #endif
 } 
 
-static inline void pmc_free(void)
+static int __devinit pmc_probe(struct of_device *op,
+			       const struct of_device_id *match)
 {
-	sbus_iounmap(regs, pmc_regsize);
-}
-
-static int __init pmc_probe(void)
-{
-	struct sbus_bus *sbus = NULL;
-	struct sbus_dev *sdev = NULL;
-	for_each_sbus(sbus) {
-		for_each_sbusdev(sdev, sbus) {
-			if (!strcmp(sdev->prom_name, PMC_OBPNAME)) {
-				goto sbus_done;
-			}
-		}
-	}
-
-sbus_done:
-	if (!sdev) {
-		return -ENODEV;
-	}
-
-	pmc_regsize = sdev->reg_addrs[0].reg_size;
-	regs = sbus_ioremap(&sdev->resource[0], 0, 
-				   pmc_regsize, PMC_OBPNAME);
+	regs = of_ioremap(&op->resource[0], 0,
+			  resource_size(&op->resource[0]), PMC_OBPNAME);
 	if (!regs) {
 		printk(KERN_ERR "%s: unable to map registers\n", PMC_DEVNAME);
 		return -ENODEV;
@@ -92,8 +70,27 @@
 	return 0;
 }
 
+static struct of_device_id __initdata pmc_match[] = {
+	{
+		.name = PMC_OBPNAME,
+	},
+	{},
+};
+MODULE_DEVICE_TABLE(of, pmc_match);
+
+static struct of_platform_driver pmc_driver = {
+	.name		= "pmc",
+	.match_table	= pmc_match,
+	.probe		= pmc_probe,
+};
+
+static int __init pmc_init(void)
+{
+	return of_register_driver(&pmc_driver, &of_bus_type);
+}
+
 /* This driver is not critical to the boot process
  * and is easiest to ioremap when SBus is already
  * initialized, so we install ourselves thusly:
  */
-__initcall(pmc_probe);
+__initcall(pmc_init);
diff --git a/arch/sparc/kernel/process.c b/arch/sparc/kernel/process.c
index 4bb4309..e8c43ff 100644
--- a/arch/sparc/kernel/process.c
+++ b/arch/sparc/kernel/process.c
@@ -75,7 +75,7 @@
 {
 	/* endless idle loop with no priority at all */
 	for (;;) {
-		if (ARCH_SUN4C_SUN4) {
+		if (ARCH_SUN4C) {
 			static int count = HZ;
 			static unsigned long last_jiffies;
 			static unsigned long last_faults;
diff --git a/arch/sparc/kernel/prom.c b/arch/sparc/kernel/prom.c
index cd4fb79..eee5efc 100644
--- a/arch/sparc/kernel/prom.c
+++ b/arch/sparc/kernel/prom.c
@@ -54,6 +54,9 @@
 }
 EXPORT_SYMBOL(of_getintprop_default);
 
+DEFINE_MUTEX(of_set_property_mutex);
+EXPORT_SYMBOL(of_set_property_mutex);
+
 int of_set_property(struct device_node *dp, const char *name, void *val, int len)
 {
 	struct property **prevp;
@@ -77,7 +80,10 @@
 			void *old_val = prop->value;
 			int ret;
 
+			mutex_lock(&of_set_property_mutex);
 			ret = prom_setprop(dp->node, (char *) name, val, len);
+			mutex_unlock(&of_set_property_mutex);
+
 			err = -EINVAL;
 			if (ret >= 0) {
 				prop->value = new_val;
@@ -436,7 +442,6 @@
 
 	switch (prom_vers) {
 	case PROM_V0:
-	case PROM_SUN4:
 		skip = 0;
 		switch (*romvec->pv_stdout) {
 		case PROMDEV_SCREEN:
diff --git a/arch/sparc/kernel/setup.c b/arch/sparc/kernel/setup.c
index 9e451b2..24fe307 100644
--- a/arch/sparc/kernel/setup.c
+++ b/arch/sparc/kernel/setup.c
@@ -213,23 +213,25 @@
 	/* Initialize PROM console and command line. */
 	*cmdline_p = prom_getbootargs();
 	strcpy(boot_command_line, *cmdline_p);
+	parse_early_param();
 
 	/* Set sparc_cpu_model */
 	sparc_cpu_model = sun_unknown;
-	if(!strcmp(&cputypval,"sun4 ")) { sparc_cpu_model=sun4; }
-	if(!strcmp(&cputypval,"sun4c")) { sparc_cpu_model=sun4c; }
-	if(!strcmp(&cputypval,"sun4m")) { sparc_cpu_model=sun4m; }
-	if(!strcmp(&cputypval,"sun4s")) { sparc_cpu_model=sun4m; }  /* CP-1200 with PROM 2.30 -E */
-	if(!strcmp(&cputypval,"sun4d")) { sparc_cpu_model=sun4d; }
-	if(!strcmp(&cputypval,"sun4e")) { sparc_cpu_model=sun4e; }
-	if(!strcmp(&cputypval,"sun4u")) { sparc_cpu_model=sun4u; }
+	if (!strcmp(&cputypval,"sun4 "))
+		sparc_cpu_model = sun4;
+	if (!strcmp(&cputypval,"sun4c"))
+		sparc_cpu_model = sun4c;
+	if (!strcmp(&cputypval,"sun4m"))
+		sparc_cpu_model = sun4m;
+	if (!strcmp(&cputypval,"sun4s"))
+		sparc_cpu_model = sun4m; /* CP-1200 with PROM 2.30 -E */
+	if (!strcmp(&cputypval,"sun4d"))
+		sparc_cpu_model = sun4d;
+	if (!strcmp(&cputypval,"sun4e"))
+		sparc_cpu_model = sun4e;
+	if (!strcmp(&cputypval,"sun4u"))
+		sparc_cpu_model = sun4u;
 
-#ifdef CONFIG_SUN4
-	if (sparc_cpu_model != sun4) {
-		prom_printf("This kernel is for Sun4 architecture only.\n");
-		prom_halt();
-	}
-#endif
 	printk("ARCH: ");
 	switch(sparc_cpu_model) {
 	case sun4:
@@ -263,7 +265,7 @@
 	boot_flags_init(*cmdline_p);
 
 	idprom_init();
-	if (ARCH_SUN4C_SUN4)
+	if (ARCH_SUN4C)
 		sun4c_probe_vac();
 	load_mmu();
 
diff --git a/arch/sparc/kernel/sparc_ksyms.c b/arch/sparc/kernel/sparc_ksyms.c
index b23cea5..b0dfff8 100644
--- a/arch/sparc/kernel/sparc_ksyms.c
+++ b/arch/sparc/kernel/sparc_ksyms.c
@@ -38,17 +38,12 @@
 #include <asm/idprom.h>
 #include <asm/head.h>
 #include <asm/smp.h>
-#include <asm/mostek.h>
 #include <asm/ptrace.h>
 #include <asm/uaccess.h>
 #include <asm/checksum.h>
 #ifdef CONFIG_SBUS
-#include <asm/sbus.h>
 #include <asm/dma.h>
 #endif
-#ifdef CONFIG_PCI
-#include <asm/ebus.h>
-#endif
 #include <asm/io-unit.h>
 #include <asm/bug.h>
 
@@ -127,16 +122,11 @@
 EXPORT_SYMBOL(__udelay);
 EXPORT_SYMBOL(__ndelay);
 EXPORT_SYMBOL(rtc_lock);
-EXPORT_SYMBOL(mostek_lock);
-EXPORT_SYMBOL(mstk48t02_regs);
 #ifdef CONFIG_SUN_AUXIO
 EXPORT_SYMBOL(set_auxio);
 EXPORT_SYMBOL(get_auxio);
 #endif
 EXPORT_SYMBOL(io_remap_pfn_range);
-  /* P3: iounit_xxx may be needed, sun4d users */
-/* EXPORT_SYMBOL(iounit_map_dma_init); */
-/* EXPORT_SYMBOL(iounit_map_dma_page); */
 
 #ifndef CONFIG_SMP
 EXPORT_SYMBOL(BTFIXUP_CALL(___xchg32));
@@ -153,24 +143,9 @@
 EXPORT_SYMBOL(BTFIXUP_CALL(pgprot_noncached));
 
 #ifdef CONFIG_SBUS
-EXPORT_SYMBOL(sbus_root);
-EXPORT_SYMBOL(dma_chain);
 EXPORT_SYMBOL(sbus_set_sbus64);
-EXPORT_SYMBOL(sbus_alloc_consistent);
-EXPORT_SYMBOL(sbus_free_consistent);
-EXPORT_SYMBOL(sbus_map_single);
-EXPORT_SYMBOL(sbus_unmap_single);
-EXPORT_SYMBOL(sbus_map_sg);
-EXPORT_SYMBOL(sbus_unmap_sg);
-EXPORT_SYMBOL(sbus_dma_sync_single_for_cpu);
-EXPORT_SYMBOL(sbus_dma_sync_single_for_device);
-EXPORT_SYMBOL(sbus_dma_sync_sg_for_cpu);
-EXPORT_SYMBOL(sbus_dma_sync_sg_for_device);
-EXPORT_SYMBOL(sbus_iounmap);
-EXPORT_SYMBOL(sbus_ioremap);
 #endif
 #ifdef CONFIG_PCI
-EXPORT_SYMBOL(ebus_chain);
 EXPORT_SYMBOL(insb);
 EXPORT_SYMBOL(outsb);
 EXPORT_SYMBOL(insw);
diff --git a/arch/sparc/kernel/sun4c_irq.c b/arch/sparc/kernel/sun4c_irq.c
index 340fc39..5dc8a57 100644
--- a/arch/sparc/kernel/sun4c_irq.c
+++ b/arch/sparc/kernel/sun4c_irq.c
@@ -18,6 +18,8 @@
 #include <linux/interrupt.h>
 #include <linux/slab.h>
 #include <linux/init.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 #include "irq.h"
 
 #include <asm/ptrace.h>
@@ -31,15 +33,8 @@
 #include <asm/traps.h>
 #include <asm/irq.h>
 #include <asm/io.h>
-#include <asm/sun4paddr.h>
 #include <asm/idprom.h>
 #include <asm/machines.h>
-#include <asm/sbus.h>
-
-#if 0
-static struct resource sun4c_timer_eb = { "sun4c_timer" };
-static struct resource sun4c_intr_eb = { "sun4c_intr" };
-#endif
 
 /*
  * Bit field defines for the interrupt registers on various
@@ -64,19 +59,7 @@
  *
  * so don't go making it static, like I tried. sigh.
  */
-unsigned char *interrupt_enable = NULL;
-
-static int sun4c_pil_map[] = { 0, 1, 2, 3, 5, 7, 8, 9 };
-
-static unsigned int sun4c_sbint_to_irq(struct sbus_dev *sdev,
-				       unsigned int sbint)
-{
-	if (sbint >= sizeof(sun4c_pil_map)) {
-		printk(KERN_ERR "%s: bogus SBINT %d\n", sdev->prom_name, sbint);
-		BUG();
-	}
-	return sun4c_pil_map[sbint];
-}
+unsigned char __iomem *interrupt_enable = NULL;
 
 static void sun4c_disable_irq(unsigned int irq_nr)
 {
@@ -85,7 +68,7 @@
     
 	local_irq_save(flags);
 	irq_nr &= (NR_IRQS - 1);
-	current_mask = *interrupt_enable;
+	current_mask = sbus_readb(interrupt_enable);
 	switch(irq_nr) {
 	case 1:
 		new_mask = ((current_mask) & (~(SUN4C_INT_E1)));
@@ -103,7 +86,7 @@
 		local_irq_restore(flags);
 		return;
 	}
-	*interrupt_enable = new_mask;
+	sbus_writeb(new_mask, interrupt_enable);
 	local_irq_restore(flags);
 }
 
@@ -114,7 +97,7 @@
     
 	local_irq_save(flags);
 	irq_nr &= (NR_IRQS - 1);
-	current_mask = *interrupt_enable;
+	current_mask = sbus_readb(interrupt_enable);
 	switch(irq_nr) {
 	case 1:
 		new_mask = ((current_mask) | SUN4C_INT_E1);
@@ -132,37 +115,22 @@
 		local_irq_restore(flags);
 		return;
 	}
-	*interrupt_enable = new_mask;
+	sbus_writeb(new_mask, interrupt_enable);
 	local_irq_restore(flags);
 }
 
-#define TIMER_IRQ  	10    /* Also at level 14, but we ignore that one. */
-#define PROFILE_IRQ	14    /* Level14 ticker.. used by OBP for polling */
+struct sun4c_timer_info {
+	u32		l10_count;
+	u32		l10_limit;
+	u32		l14_count;
+	u32		l14_limit;
+};
 
-volatile struct sun4c_timer_info *sun4c_timers;
-
-#ifdef CONFIG_SUN4
-/* This is an ugly hack to work around the
-   current timer code, and make it work with 
-   the sun4/260 intersil 
-   */
-volatile struct sun4c_timer_info sun4_timer;
-#endif
+static struct sun4c_timer_info __iomem *sun4c_timers;
 
 static void sun4c_clear_clock_irq(void)
 {
-	volatile unsigned int clear_intr;
-#ifdef CONFIG_SUN4
-	if (idprom->id_machtype == (SM_SUN4 | SM_4_260)) 
-	  clear_intr = sun4_timer.timer_limit10;
-	else
-#endif
-	clear_intr = sun4c_timers->timer_limit10;
-}
-
-static void sun4c_clear_profile_irq(int cpu)
-{
-	/* Errm.. not sure how to do this.. */
+	sbus_readl(&sun4c_timers->l10_limit);
 }
 
 static void sun4c_load_profile_irq(int cpu, unsigned int limit)
@@ -172,41 +140,48 @@
 
 static void __init sun4c_init_timers(irq_handler_t counter_fn)
 {
-	int irq;
+	const struct linux_prom_irqs *irq;
+	struct device_node *dp;
+	const u32 *addr;
+	int err;
 
-	/* Map the Timer chip, this is implemented in hardware inside
-	 * the cache chip on the sun4c.
-	 */
-#ifdef CONFIG_SUN4
-	if (idprom->id_machtype == (SM_SUN4 | SM_4_260))
-		sun4c_timers = &sun4_timer;
-	else
-#endif
-	sun4c_timers = ioremap(SUN_TIMER_PHYSADDR,
-	    sizeof(struct sun4c_timer_info));
+	dp = of_find_node_by_name(NULL, "counter-timer");
+	if (!dp) {
+		prom_printf("sun4c_init_timers: Unable to find counter-timer\n");
+		prom_halt();
+	}
+
+	addr = of_get_property(dp, "address", NULL);
+	if (!addr) {
+		prom_printf("sun4c_init_timers: No address property\n");
+		prom_halt();
+	}
+
+	sun4c_timers = (void __iomem *) (unsigned long) addr[0];
+
+	irq = of_get_property(dp, "intr", NULL);
+	if (!irq) {
+		prom_printf("sun4c_init_timers: No intr property\n");
+		prom_halt();
+	}
 
 	/* Have the level 10 timer tick at 100HZ.  We don't touch the
 	 * level 14 timer limit since we are letting the prom handle
 	 * them until we have a real console driver so L1-A works.
 	 */
-	sun4c_timers->timer_limit10 = (((1000000/HZ) + 1) << 10);
-	master_l10_counter = &sun4c_timers->cur_count10;
-	master_l10_limit = &sun4c_timers->timer_limit10;
+	sbus_writel((((1000000/HZ) + 1) << 10), &sun4c_timers->l10_limit);
 
-	irq = request_irq(TIMER_IRQ,
-			  counter_fn,
+	master_l10_counter = &sun4c_timers->l10_count;
+
+	err = request_irq(irq[0].pri, counter_fn,
 			  (IRQF_DISABLED | SA_STATIC_ALLOC),
 			  "timer", NULL);
-	if (irq) {
-		prom_printf("time_init: unable to attach IRQ%d\n",TIMER_IRQ);
+	if (err) {
+		prom_printf("sun4c_init_timers: request_irq() fails with %d\n", err);
 		prom_halt();
 	}
     
-#if 0
-	/* This does not work on 4/330 */
-	sun4c_enable_irq(10);
-#endif
-	claim_ticker14(NULL, PROFILE_IRQ, 0);
+	sun4c_disable_irq(irq[1].pri);
 }
 
 #ifdef CONFIG_SMP
@@ -215,41 +190,28 @@
 
 void __init sun4c_init_IRQ(void)
 {
-	struct linux_prom_registers int_regs[2];
-	int ie_node;
+	struct device_node *dp;
+	const u32 *addr;
 
-	if (ARCH_SUN4) {
-		interrupt_enable = (char *)
-		    ioremap(sun4_ie_physaddr, PAGE_SIZE);
-	} else {
-		struct resource phyres;
-
-		ie_node = prom_searchsiblings (prom_getchild(prom_root_node),
-				       	"interrupt-enable");
-		if(ie_node == 0)
-			panic("Cannot find /interrupt-enable node");
-
-		/* Depending on the "address" property is bad news... */
-		interrupt_enable = NULL;
-		if (prom_getproperty(ie_node, "reg", (char *) int_regs,
-				     sizeof(int_regs)) != -1) {
-			memset(&phyres, 0, sizeof(struct resource));
-			phyres.flags = int_regs[0].which_io;
-			phyres.start = int_regs[0].phys_addr;
-			interrupt_enable = (char *) sbus_ioremap(&phyres, 0,
-			    int_regs[0].reg_size, "sun4c_intr");
-		}
+	dp = of_find_node_by_name(NULL, "interrupt-enable");
+	if (!dp) {
+		prom_printf("sun4c_init_IRQ: Unable to find interrupt-enable\n");
+		prom_halt();
 	}
-	if (!interrupt_enable)
-		panic("Cannot map interrupt_enable");
 
-	BTFIXUPSET_CALL(sbint_to_irq, sun4c_sbint_to_irq, BTFIXUPCALL_NORM);
+	addr = of_get_property(dp, "address", NULL);
+	if (!addr) {
+		prom_printf("sun4c_init_IRQ: No address property\n");
+		prom_halt();
+	}
+
+	interrupt_enable = (void __iomem *) (unsigned long) addr[0];
+
 	BTFIXUPSET_CALL(enable_irq, sun4c_enable_irq, BTFIXUPCALL_NORM);
 	BTFIXUPSET_CALL(disable_irq, sun4c_disable_irq, BTFIXUPCALL_NORM);
 	BTFIXUPSET_CALL(enable_pil_irq, sun4c_enable_irq, BTFIXUPCALL_NORM);
 	BTFIXUPSET_CALL(disable_pil_irq, sun4c_disable_irq, BTFIXUPCALL_NORM);
 	BTFIXUPSET_CALL(clear_clock_irq, sun4c_clear_clock_irq, BTFIXUPCALL_NORM);
-	BTFIXUPSET_CALL(clear_profile_irq, sun4c_clear_profile_irq, BTFIXUPCALL_NOP);
 	BTFIXUPSET_CALL(load_profile_irq, sun4c_load_profile_irq, BTFIXUPCALL_NOP);
 	sparc_init_timers = sun4c_init_timers;
 #ifdef CONFIG_SMP
@@ -257,6 +219,6 @@
 	BTFIXUPSET_CALL(clear_cpu_int, sun4c_nop, BTFIXUPCALL_NOP);
 	BTFIXUPSET_CALL(set_irq_udt, sun4c_nop, BTFIXUPCALL_NOP);
 #endif
-	*interrupt_enable = (SUN4C_INT_ENABLE);
+	sbus_writeb(SUN4C_INT_ENABLE, interrupt_enable);
 	/* Cannot enable interrupts until OBP ticker is disabled. */
 }
diff --git a/arch/sparc/kernel/sun4d_irq.c b/arch/sparc/kernel/sun4d_irq.c
index 1290b59..d3cb76c 100644
--- a/arch/sparc/kernel/sun4d_irq.c
+++ b/arch/sparc/kernel/sun4d_irq.c
@@ -19,6 +19,8 @@
 #include <linux/smp.h>
 #include <linux/spinlock.h>
 #include <linux/seq_file.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 
 #include <asm/ptrace.h>
 #include <asm/processor.h>
@@ -34,7 +36,6 @@
 #include <asm/io.h>
 #include <asm/pgalloc.h>
 #include <asm/pgtable.h>
-#include <asm/sbus.h>
 #include <asm/sbi.h>
 #include <asm/cacheflush.h>
 #include <asm/irq_regs.h>
@@ -44,16 +45,22 @@
 /* If you trust current SCSI layer to handle different SCSI IRQs, enable this. I don't trust it... -jj */
 /* #define DISTRIBUTE_IRQS */
 
-struct sun4d_timer_regs *sun4d_timers;
+struct sun4d_timer_regs {
+	u32	l10_timer_limit;
+	u32	l10_cur_countx;
+	u32	l10_limit_noclear;
+	u32	ctrl;
+	u32	l10_cur_count;
+};
+
+static struct sun4d_timer_regs __iomem *sun4d_timers;
+
 #define TIMER_IRQ	10
 
 #define MAX_STATIC_ALLOC	4
 extern struct irqaction static_irqaction[MAX_STATIC_ALLOC];
 extern int static_irq_count;
-unsigned char cpu_leds[32];
-#ifdef CONFIG_SMP
 static unsigned char sbus_tid[32];
-#endif
 
 static struct irqaction *irq_action[NR_IRQS];
 extern spinlock_t irq_action_lock;
@@ -72,9 +79,9 @@
 };
 
 static int nsbi;
-#ifdef CONFIG_SMP
+
+/* Exported for sun4d_smp.c */
 DEFINE_SPINLOCK(sun4d_imsk_lock);
-#endif
 
 int show_sun4d_interrupts(struct seq_file *p, void *v)
 {
@@ -257,26 +264,6 @@
 	set_irq_regs(old_regs);
 }
 
-unsigned int sun4d_build_irq(struct sbus_dev *sdev, int irq)
-{
-	int sbusl = pil_to_sbus[irq];
-
-	if (sbusl)
-		return ((sdev->bus->board + 1) << 5) + (sbusl << 2) + sdev->slot;
-	else
-		return irq;
-}
-
-static unsigned int sun4d_sbint_to_irq(struct sbus_dev *sdev,
-				       unsigned int sbint)
-{
-	if (sbint >= sizeof(sbus_to_pil)) {
-		printk(KERN_ERR "%s: bogus SBINT %d\n", sdev->prom_name, sbint);
-		BUG();
-	}
-	return sun4d_build_irq(sdev, sbus_to_pil[sbint]);
-}
-
 int sun4d_request_irq(unsigned int irq,
 		irq_handler_t handler,
 		unsigned long irqflags, const char * devname, void *dev_id)
@@ -360,36 +347,28 @@
 
 static void sun4d_disable_irq(unsigned int irq)
 {
-#ifdef CONFIG_SMP
 	int tid = sbus_tid[(irq >> 5) - 1];
 	unsigned long flags;
-#endif	
 	
-	if (irq < NR_IRQS) return;
-#ifdef CONFIG_SMP
+	if (irq < NR_IRQS)
+		return;
+
 	spin_lock_irqsave(&sun4d_imsk_lock, flags);
 	cc_set_imsk_other(tid, cc_get_imsk_other(tid) | (1 << sbus_to_pil[(irq >> 2) & 7]));
 	spin_unlock_irqrestore(&sun4d_imsk_lock, flags);
-#else		
-	cc_set_imsk(cc_get_imsk() | (1 << sbus_to_pil[(irq >> 2) & 7]));
-#endif
 }
 
 static void sun4d_enable_irq(unsigned int irq)
 {
-#ifdef CONFIG_SMP
 	int tid = sbus_tid[(irq >> 5) - 1];
 	unsigned long flags;
-#endif	
 	
-	if (irq < NR_IRQS) return;
-#ifdef CONFIG_SMP
+	if (irq < NR_IRQS)
+		return;
+
 	spin_lock_irqsave(&sun4d_imsk_lock, flags);
 	cc_set_imsk_other(tid, cc_get_imsk_other(tid) & ~(1 << sbus_to_pil[(irq >> 2) & 7]));
 	spin_unlock_irqrestore(&sun4d_imsk_lock, flags);
-#else		
-	cc_set_imsk(cc_get_imsk() & ~(1 << sbus_to_pil[(irq >> 2) & 7]));
-#endif
 }
 
 #ifdef CONFIG_SMP
@@ -409,47 +388,55 @@
 /* Setup IRQ distribution scheme. */
 void __init sun4d_distribute_irqs(void)
 {
+	struct device_node *dp;
+
 #ifdef DISTRIBUTE_IRQS
-	struct sbus_bus *sbus;
-	unsigned long sbus_serving_map;
+	cpumask_t sbus_serving_map;
 
 	sbus_serving_map = cpu_present_map;
-	for_each_sbus(sbus) {
-		if ((sbus->board * 2) == boot_cpu_id && (cpu_present_map & (1 << (sbus->board * 2 + 1))))
-			sbus_tid[sbus->board] = (sbus->board * 2 + 1);
-		else if (cpu_present_map & (1 << (sbus->board * 2)))
-			sbus_tid[sbus->board] = (sbus->board * 2);
-		else if (cpu_present_map & (1 << (sbus->board * 2 + 1)))
-			sbus_tid[sbus->board] = (sbus->board * 2 + 1);
+	for_each_node_by_name(dp, "sbi") {
+		int board = of_getintprop_default(dp, "board#", 0);
+
+		if ((board * 2) == boot_cpu_id && cpu_isset(board * 2 + 1, cpu_present_map))
+			sbus_tid[board] = (board * 2 + 1);
+		else if (cpu_isset(board * 2, cpu_present_map))
+			sbus_tid[board] = (board * 2);
+		else if (cpu_isset(board * 2 + 1, cpu_present_map))
+			sbus_tid[board] = (board * 2 + 1);
 		else
-			sbus_tid[sbus->board] = 0xff;
-		if (sbus_tid[sbus->board] != 0xff)
-			sbus_serving_map &= ~(1 << sbus_tid[sbus->board]);
+			sbus_tid[board] = 0xff;
+		if (sbus_tid[board] != 0xff)
+			cpu_clear(sbus_tid[board], sbus_serving_map);
 	}
-	for_each_sbus(sbus)
-		if (sbus_tid[sbus->board] == 0xff) {
+	for_each_node_by_name(dp, "sbi") {
+		int board = of_getintprop_default(dp, "board#", 0);
+		if (sbus_tid[board] == 0xff) {
 			int i = 31;
 				
-			if (!sbus_serving_map)
+			if (cpus_empty(sbus_serving_map))
 				sbus_serving_map = cpu_present_map;
-			while (!(sbus_serving_map & (1 << i)))
+			while (cpu_isset(i, sbus_serving_map))
 				i--;
-			sbus_tid[sbus->board] = i;
-			sbus_serving_map &= ~(1 << i);
+			sbus_tid[board] = i;
+			cpu_clear(i, sbus_serving_map);
 		}
-	for_each_sbus(sbus) {
-		printk("sbus%d IRQs directed to CPU%d\n", sbus->board, sbus_tid[sbus->board]);
-		set_sbi_tid(sbus->devid, sbus_tid[sbus->board] << 3);
+	}
+	for_each_node_by_name(dp, "sbi") {
+		int devid = of_getintprop_default(dp, "device-id", 0);
+		int board = of_getintprop_default(dp, "board#", 0);
+		printk("sbus%d IRQs directed to CPU%d\n", board, sbus_tid[board]);
+		set_sbi_tid(devid, sbus_tid[board] << 3);
 	}
 #else
-	struct sbus_bus *sbus;
 	int cpuid = cpu_logical_map(1);
 
 	if (cpuid == -1)
 		cpuid = cpu_logical_map(0);
-	for_each_sbus(sbus) {
-		sbus_tid[sbus->board] = cpuid;
-		set_sbi_tid(sbus->devid, cpuid << 3);
+	for_each_node_by_name(dp, "sbi") {
+		int devid = of_getintprop_default(dp, "device-id", 0);
+		int board = of_getintprop_default(dp, "board#", 0);
+		sbus_tid[board] = cpuid;
+		set_sbi_tid(devid, cpuid << 3);
 	}
 	printk("All sbus IRQs directed to CPU%d\n", cpuid);
 #endif
@@ -458,13 +445,7 @@
  
 static void sun4d_clear_clock_irq(void)
 {
-	volatile unsigned int clear_intr;
-	clear_intr = sun4d_timers->l10_timer_limit;
-}
-
-static void sun4d_clear_profile_irq(int cpu)
-{
-	bw_get_prof_limit(cpu);
+	sbus_readl(&sun4d_timers->l10_timer_limit);
 }
 
 static void sun4d_load_profile_irq(int cpu, unsigned int limit)
@@ -472,98 +453,121 @@
 	bw_set_prof_limit(cpu, limit);
 }
 
-static void __init sun4d_init_timers(irq_handler_t counter_fn)
+static void __init sun4d_load_profile_irqs(void)
 {
-	int irq;
-	int cpu;
-	struct resource r;
-	int mid;
+	int cpu = 0, mid;
 
-	/* Map the User Timer registers. */
-	memset(&r, 0, sizeof(r));
-#ifdef CONFIG_SMP
-	r.start = CSR_BASE(boot_cpu_id)+BW_TIMER_LIMIT;
-#else
-	r.start = CSR_BASE(0)+BW_TIMER_LIMIT;
-#endif
-	r.flags = 0xf;
-	sun4d_timers = (struct sun4d_timer_regs *) sbus_ioremap(&r, 0,
-	    PAGE_SIZE, "user timer");
-
-	sun4d_timers->l10_timer_limit =  (((1000000/HZ) + 1) << 10);
-	master_l10_counter = &sun4d_timers->l10_cur_count;
-	master_l10_limit = &sun4d_timers->l10_timer_limit;
-
-	irq = request_irq(TIMER_IRQ,
-			  counter_fn,
-			  (IRQF_DISABLED | SA_STATIC_ALLOC),
-			  "timer", NULL);
-	if (irq) {
-		prom_printf("time_init: unable to attach IRQ%d\n",TIMER_IRQ);
-		prom_halt();
-	}
-	
-	/* Enable user timer free run for CPU 0 in BW */
-	/* bw_set_ctrl(0, bw_get_ctrl(0) | BW_CTRL_USER_TIMER); */
-
-	cpu = 0;
 	while (!cpu_find_by_instance(cpu, NULL, &mid)) {
 		sun4d_load_profile_irq(mid >> 3, 0);
 		cpu++;
 	}
-		
+}
+
+static void __init sun4d_fixup_trap_table(void)
+{
 #ifdef CONFIG_SMP
-	{
-		unsigned long flags;
-		extern unsigned long lvl14_save[4];
-		struct tt_entry *trap_table = &sparc_ttable[SP_TRAP_IRQ1 + (14 - 1)];
-		extern unsigned int real_irq_entry[], smp4d_ticker[];
-		extern unsigned int patchme_maybe_smp_msg[];
+	unsigned long flags;
+	extern unsigned long lvl14_save[4];
+	struct tt_entry *trap_table = &sparc_ttable[SP_TRAP_IRQ1 + (14 - 1)];
+	extern unsigned int real_irq_entry[], smp4d_ticker[];
+	extern unsigned int patchme_maybe_smp_msg[];
 
-		/* Adjust so that we jump directly to smp4d_ticker */
-		lvl14_save[2] += smp4d_ticker - real_irq_entry;
+	/* Adjust so that we jump directly to smp4d_ticker */
+	lvl14_save[2] += smp4d_ticker - real_irq_entry;
 
-		/* For SMP we use the level 14 ticker, however the bootup code
-		 * has copied the firmware's level 14 vector into the boot cpu's
-		 * trap table, we must fix this now or we get squashed.
-		 */
-		local_irq_save(flags);
-		patchme_maybe_smp_msg[0] = 0x01000000; /* NOP out the branch */
-		trap_table->inst_one = lvl14_save[0];
-		trap_table->inst_two = lvl14_save[1];
-		trap_table->inst_three = lvl14_save[2];
-		trap_table->inst_four = lvl14_save[3];
-		local_flush_cache_all();
-		local_irq_restore(flags);
-	}
+	/* For SMP we use the level 14 ticker, however the bootup code
+	 * has copied the firmware's level 14 vector into the boot cpu's
+	 * trap table, we must fix this now or we get squashed.
+	 */
+	local_irq_save(flags);
+	patchme_maybe_smp_msg[0] = 0x01000000; /* NOP out the branch */
+	trap_table->inst_one = lvl14_save[0];
+	trap_table->inst_two = lvl14_save[1];
+	trap_table->inst_three = lvl14_save[2];
+	trap_table->inst_four = lvl14_save[3];
+	local_flush_cache_all();
+	local_irq_restore(flags);
 #endif
 }
 
+static void __init sun4d_init_timers(irq_handler_t counter_fn)
+{
+	struct device_node *dp;
+	struct resource res;
+	const u32 *reg;
+	int err;
+
+	dp = of_find_node_by_name(NULL, "cpu-unit");
+	if (!dp) {
+		prom_printf("sun4d_init_timers: Unable to find cpu-unit\n");
+		prom_halt();
+	}
+
+	/* Which cpu-unit we use is arbitrary, we can view the bootbus timer
+	 * registers via any cpu's mapping.  The first 'reg' property is the
+	 * bootbus.
+	 */
+	reg = of_get_property(dp, "reg", NULL);
+	if (!reg) {
+		prom_printf("sun4d_init_timers: No reg property\n");
+		prom_halt();
+	}
+
+	res.start = reg[1];
+	res.end = reg[2] - 1;
+	res.flags = reg[0] & 0xff;
+	sun4d_timers = of_ioremap(&res, BW_TIMER_LIMIT,
+				  sizeof(struct sun4d_timer_regs), "user timer");
+	if (!sun4d_timers) {
+		prom_printf("sun4d_init_timers: Can't map timer regs\n");
+		prom_halt();
+	}
+
+	sbus_writel((((1000000/HZ) + 1) << 10), &sun4d_timers->l10_timer_limit);
+
+	master_l10_counter = &sun4d_timers->l10_cur_count;
+
+	err = request_irq(TIMER_IRQ, counter_fn,
+			  (IRQF_DISABLED | SA_STATIC_ALLOC),
+			  "timer", NULL);
+	if (err) {
+		prom_printf("sun4d_init_timers: request_irq() failed with %d\n", err);
+		prom_halt();
+	}
+	sun4d_load_profile_irqs();
+	sun4d_fixup_trap_table();
+}
+
 void __init sun4d_init_sbi_irq(void)
 {
-	struct sbus_bus *sbus;
-	unsigned mask;
+	struct device_node *dp;
+	int target_cpu = 0;
+
+#ifdef CONFIG_SMP
+	target_cpu = boot_cpu_id;
+#endif
 
 	nsbi = 0;
-	for_each_sbus(sbus)
+	for_each_node_by_name(dp, "sbi")
 		nsbi++;
 	sbus_actions = kzalloc (nsbi * 8 * 4 * sizeof(struct sbus_action), GFP_ATOMIC);
 	if (!sbus_actions) {
 		prom_printf("SUN4D: Cannot allocate sbus_actions, halting.\n");
 		prom_halt();
 	}
-	for_each_sbus(sbus) {
-#ifdef CONFIG_SMP	
-		extern unsigned char boot_cpu_id;
-		
-		set_sbi_tid(sbus->devid, boot_cpu_id << 3);
-		sbus_tid[sbus->board] = boot_cpu_id;
-#endif
+	for_each_node_by_name(dp, "sbi") {
+		int devid = of_getintprop_default(dp, "device-id", 0);
+		int board = of_getintprop_default(dp, "board#", 0);
+		unsigned int mask;
+
+		set_sbi_tid(devid, target_cpu << 3);
+		sbus_tid[board] = target_cpu;
+
 		/* Get rid of pending irqs from PROM */
-		mask = acquire_sbi(sbus->devid, 0xffffffff);
+		mask = acquire_sbi(devid, 0xffffffff);
 		if (mask) {
-			printk ("Clearing pending IRQs %08x on SBI %d\n", mask, sbus->board);
-			release_sbi(sbus->devid, mask);
+			printk ("Clearing pending IRQs %08x on SBI %d\n", mask, board);
+			release_sbi(devid, mask);
 		}
 	}
 }
@@ -572,11 +576,9 @@
 {
 	local_irq_disable();
 
-	BTFIXUPSET_CALL(sbint_to_irq, sun4d_sbint_to_irq, BTFIXUPCALL_NORM);
 	BTFIXUPSET_CALL(enable_irq, sun4d_enable_irq, BTFIXUPCALL_NORM);
 	BTFIXUPSET_CALL(disable_irq, sun4d_disable_irq, BTFIXUPCALL_NORM);
 	BTFIXUPSET_CALL(clear_clock_irq, sun4d_clear_clock_irq, BTFIXUPCALL_NORM);
-	BTFIXUPSET_CALL(clear_profile_irq, sun4d_clear_profile_irq, BTFIXUPCALL_NORM);
 	BTFIXUPSET_CALL(load_profile_irq, sun4d_load_profile_irq, BTFIXUPCALL_NORM);
 	sparc_init_timers = sun4d_init_timers;
 #ifdef CONFIG_SMP
diff --git a/arch/sparc/kernel/sun4d_smp.c b/arch/sparc/kernel/sun4d_smp.c
index 6959640..7a6a5e7 100644
--- a/arch/sparc/kernel/sun4d_smp.c
+++ b/arch/sparc/kernel/sun4d_smp.c
@@ -20,6 +20,7 @@
 #include <linux/swap.h>
 #include <linux/profile.h>
 #include <linux/delay.h>
+#include <linux/cpu.h>
 
 #include <asm/ptrace.h>
 #include <asm/atomic.h>
@@ -30,7 +31,6 @@
 #include <asm/pgalloc.h>
 #include <asm/pgtable.h>
 #include <asm/oplib.h>
-#include <asm/sbus.h>
 #include <asm/sbi.h>
 #include <asm/tlbflush.h>
 #include <asm/cacheflush.h>
@@ -72,6 +72,17 @@
 extern void cpu_probe(void);
 extern void sun4d_distribute_irqs(void);
 
+static unsigned char cpu_leds[32];
+
+static inline void show_leds(int cpuid)
+{
+	cpuid &= 0x1e;
+	__asm__ __volatile__ ("stba %0, [%1] %2" : :
+			      "r" ((cpu_leds[cpuid] << 4) | cpu_leds[cpuid+1]),
+			      "r" (ECSR_BASE(cpuid) | BB_LEDS),
+			      "i" (ASI_M_CTL));
+}
+
 void __init smp4d_callin(void)
 {
 	int cpuid = hard_smp4d_processor_id();
@@ -88,6 +99,7 @@
 	local_flush_cache_all();
 	local_flush_tlb_all();
 
+	notify_cpu_starting(cpuid);
 	/*
 	 * Unblock the master CPU _only_ when the scheduler state
 	 * of all secondary CPUs will be up-to-date, so after
diff --git a/arch/sparc/kernel/sun4m_irq.c b/arch/sparc/kernel/sun4m_irq.c
index 94e02de..f103171 100644
--- a/arch/sparc/kernel/sun4m_irq.c
+++ b/arch/sparc/kernel/sun4m_irq.c
@@ -20,6 +20,8 @@
 #include <linux/slab.h>
 #include <linux/init.h>
 #include <linux/ioport.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 
 #include <asm/ptrace.h>
 #include <asm/processor.h>
@@ -35,59 +37,27 @@
 #include <asm/smp.h>
 #include <asm/irq.h>
 #include <asm/io.h>
-#include <asm/sbus.h>
 #include <asm/cacheflush.h>
 
 #include "irq.h"
 
-/* On the sun4m, just like the timers, we have both per-cpu and master
- * interrupt registers.
- */
-
-/* These registers are used for sending/receiving irqs from/to
- * different cpu's.
- */
-struct sun4m_intreg_percpu {
-	unsigned int tbt;        /* Interrupts still pending for this cpu. */
-
-	/* These next two registers are WRITE-ONLY and are only
-	 * "on bit" sensitive, "off bits" written have NO affect.
-	 */
-	unsigned int clear;  /* Clear this cpus irqs here. */
-	unsigned int set;    /* Set this cpus irqs here. */
-	unsigned char space[PAGE_SIZE - 12];
+struct sun4m_irq_percpu {
+	u32		pending;
+	u32		clear;
+	u32		set;
 };
 
-/*
- * djhr
- * Actually the clear and set fields in this struct are misleading..
- * according to the SLAVIO manual (and the same applies for the SEC)
- * the clear field clears bits in the mask which will ENABLE that IRQ
- * the set field sets bits in the mask to DISABLE the IRQ.
- *
- * Also the undirected_xx address in the SLAVIO is defined as
- * RESERVED and write only..
- *
- * DAVEM_NOTE: The SLAVIO only specifies behavior on uniprocessor
- *             sun4m machines, for MP the layout makes more sense.
- */
-struct sun4m_intregs {
-	struct sun4m_intreg_percpu cpu_intregs[SUN4M_NCPUS];
-	unsigned int tbt;                /* IRQ's that are still pending. */
-	unsigned int irqs;               /* Master IRQ bits. */
-
-	/* Again, like the above, two these registers are WRITE-ONLY. */
-	unsigned int clear;              /* Clear master IRQ's by setting bits here. */
-	unsigned int set;                /* Set master IRQ's by setting bits here. */
-
-	/* This register is both READ and WRITE. */
-	unsigned int undirected_target;  /* Which cpu gets undirected irqs. */
+struct sun4m_irq_global {
+	u32		pending;
+	u32		mask;
+	u32		mask_clear;
+	u32		mask_set;
+	u32		interrupt_target;
 };
 
-static unsigned long dummy;
-
-struct sun4m_intregs *sun4m_interrupts;
-unsigned long *irq_rcvreg = &dummy;
+/* Code in entry.S needs to get at these register mappings.  */
+struct sun4m_irq_percpu __iomem *sun4m_irq_percpu[SUN4M_NCPUS];
+struct sun4m_irq_global __iomem *sun4m_irq_global;
 
 /* Dave Redman (djhr@tadpole.co.uk)
  * The sun4m interrupt registers.
@@ -101,8 +71,9 @@
 
 #define	SUN4M_INT_MASKALL	0x80000000	  /* mask all interrupts */
 #define	SUN4M_INT_MODULE_ERR	0x40000000	  /* module error */
-#define	SUN4M_INT_M2S_WRITE	0x20000000	  /* write buffer error */
-#define	SUN4M_INT_ECC		0x10000000	  /* ecc memory error */
+#define	SUN4M_INT_M2S_WRITE_ERR	0x20000000	  /* write buffer error */
+#define	SUN4M_INT_ECC_ERR	0x10000000	  /* ecc memory error */
+#define	SUN4M_INT_VME_ERR	0x08000000	  /* vme async error */
 #define	SUN4M_INT_FLOPPY	0x00400000	  /* floppy disk */
 #define	SUN4M_INT_MODULE	0x00200000	  /* module interrupt */
 #define	SUN4M_INT_VIDEO		0x00100000	  /* onboard video */
@@ -113,75 +84,126 @@
 #define	SUN4M_INT_SERIAL	0x00008000	  /* serial ports */
 #define	SUN4M_INT_KBDMS		0x00004000	  /* keyboard/mouse */
 #define	SUN4M_INT_SBUSBITS	0x00003F80	  /* sbus int bits */
+#define	SUN4M_INT_VMEBITS	0x0000007F	  /* vme int bits */
+
+#define	SUN4M_INT_ERROR		(SUN4M_INT_MODULE_ERR |    \
+				 SUN4M_INT_M2S_WRITE_ERR | \
+				 SUN4M_INT_ECC_ERR |       \
+				 SUN4M_INT_VME_ERR)
 
 #define SUN4M_INT_SBUS(x)	(1 << (x+7))
 #define SUN4M_INT_VME(x)	(1 << (x))
 
-/* These tables only apply for interrupts greater than 15..
- * 
- * any intr value below 0x10 is considered to be a soft-int
- * this may be useful or it may not.. but that's how I've done it.
- * and it won't clash with what OBP is telling us about devices.
+/* Interrupt levels used by OBP */
+#define	OBP_INT_LEVEL_SOFT	0x10
+#define	OBP_INT_LEVEL_ONBOARD	0x20
+#define	OBP_INT_LEVEL_SBUS	0x30
+#define	OBP_INT_LEVEL_VME	0x40
+
+/* Interrupt level assignment on sun4m:
  *
- * take an encoded intr value and lookup if it's valid
- * then get the mask bits that match from irq_mask
+ *	level		source
+ * ------------------------------------------------------------
+ *        1		softint-1
+ *	  2		softint-2, VME/SBUS level 1
+ *	  3		softint-3, VME/SBUS level 2
+ *	  4		softint-4, onboard SCSI
+ *	  5		softint-5, VME/SBUS level 3
+ *	  6		softint-6, onboard ETHERNET
+ *	  7		softint-7, VME/SBUS level 4
+ *	  8		softint-8, onboard VIDEO
+ *	  9		softint-9, VME/SBUS level 5, Module Interrupt
+ *	 10		softint-10, system counter/timer
+ *	 11		softint-11, VME/SBUS level 6, Floppy
+ *	 12		softint-12, Keyboard/Mouse, Serial
+ *	 13		softint-13, VME/SBUS level 7, ISDN Audio
+ *	 14		softint-14, per-processor counter/timer
+ *	 15		softint-15, Asynchronous Errors (broadcast)
  *
- * P3: Translation from irq 0x0d to mask 0x2000 is for MrCoffee.
+ * Each interrupt source is masked distinctly in the sun4m interrupt
+ * registers.  The PIL level alone is therefore ambiguous, since multiple
+ * interrupt sources map to a single PIL.
+ *
+ * This ambiguity is resolved in the 'intr' property for device nodes
+ * in the OF device tree.  Each 'intr' property entry is composed of
+ * two 32-bit words.  The first word is the IRQ priority value, which
+ * is what we're intersted in.  The second word is the IRQ vector, which
+ * is unused.
+ *
+ * The low 4 bits of the IRQ priority indicate the PIL, and the upper
+ * 4 bits indicate onboard vs. SBUS leveled vs. VME leveled.  0x20
+ * means onboard, 0x30 means SBUS leveled, and 0x40 means VME leveled.
+ *
+ * For example, an 'intr' IRQ priority value of 0x24 is onboard SCSI
+ * whereas a value of 0x33 is SBUS level 2.  Here are some sample
+ * 'intr' property IRQ priority values from ss4, ss5, ss10, ss20, and
+ * Tadpole S3 GX systems.
+ *
+ * esp: 	0x24	onboard ESP SCSI
+ * le:  	0x26	onboard Lance ETHERNET
+ * p9100:	0x32	SBUS level 1 P9100 video
+ * bpp:  	0x33	SBUS level 2 BPP parallel port device
+ * DBRI:	0x39	SBUS level 5 DBRI ISDN audio
+ * SUNW,leo:	0x39	SBUS level 5 LEO video
+ * pcmcia:	0x3b	SBUS level 6 PCMCIA controller
+ * uctrl:	0x3b	SBUS level 6 UCTRL device
+ * modem:	0x3d	SBUS level 7 MODEM
+ * zs:		0x2c	onboard keyboard/mouse/serial
+ * floppy:	0x2b	onboard Floppy
+ * power:	0x22	onboard power device (XXX unknown mask bit XXX)
  */
-static unsigned char irq_xlate[32] = {
-    /*  0,  1,  2,  3,  4,  5,  6,  7,  8,  9,  a,  b,  c,  d,  e,  f */
-	0,  0,  0,  0,  1,  0,  2,  0,  3,  0,  4,  5,  6, 14,  0,  7,
-	0,  0,  8,  9,  0, 10,  0, 11,  0, 12,  0, 13,  0, 14,  0,  0
+
+static unsigned long irq_mask[0x50] = {
+	/* SMP */
+	0,  SUN4M_SOFT_INT(1),
+	SUN4M_SOFT_INT(2),  SUN4M_SOFT_INT(3),
+	SUN4M_SOFT_INT(4),  SUN4M_SOFT_INT(5),
+	SUN4M_SOFT_INT(6),  SUN4M_SOFT_INT(7),
+	SUN4M_SOFT_INT(8),  SUN4M_SOFT_INT(9),
+	SUN4M_SOFT_INT(10), SUN4M_SOFT_INT(11),
+	SUN4M_SOFT_INT(12), SUN4M_SOFT_INT(13),
+	SUN4M_SOFT_INT(14), SUN4M_SOFT_INT(15),
+	/* soft */
+	0,  SUN4M_SOFT_INT(1),
+	SUN4M_SOFT_INT(2),  SUN4M_SOFT_INT(3),
+	SUN4M_SOFT_INT(4),  SUN4M_SOFT_INT(5),
+	SUN4M_SOFT_INT(6),  SUN4M_SOFT_INT(7),
+	SUN4M_SOFT_INT(8),  SUN4M_SOFT_INT(9),
+	SUN4M_SOFT_INT(10), SUN4M_SOFT_INT(11),
+	SUN4M_SOFT_INT(12), SUN4M_SOFT_INT(13),
+	SUN4M_SOFT_INT(14), SUN4M_SOFT_INT(15),
+	/* onboard */
+	0, 0, 0, 0,
+	SUN4M_INT_SCSI,  0, SUN4M_INT_ETHERNET, 0,
+	SUN4M_INT_VIDEO, SUN4M_INT_MODULE,
+	SUN4M_INT_REALTIME, SUN4M_INT_FLOPPY,
+	(SUN4M_INT_SERIAL | SUN4M_INT_KBDMS),
+	SUN4M_INT_AUDIO, 0, SUN4M_INT_MODULE_ERR,
+	/* sbus */
+	0, 0, SUN4M_INT_SBUS(0), SUN4M_INT_SBUS(1),
+	0, SUN4M_INT_SBUS(2), 0, SUN4M_INT_SBUS(3),
+	0, SUN4M_INT_SBUS(4), 0, SUN4M_INT_SBUS(5),
+	0, SUN4M_INT_SBUS(6), 0, 0,
+	/* vme */
+	0, 0, SUN4M_INT_VME(0), SUN4M_INT_VME(1),
+	0, SUN4M_INT_VME(2), 0, SUN4M_INT_VME(3),
+	0, SUN4M_INT_VME(4), 0, SUN4M_INT_VME(5),
+	0, SUN4M_INT_VME(6), 0, 0
 };
 
-static unsigned long irq_mask[] = {
-	0,						  /* illegal index */
-	SUN4M_INT_SCSI,				  	  /*  1 irq 4 */
-	SUN4M_INT_ETHERNET,				  /*  2 irq 6 */
-	SUN4M_INT_VIDEO,				  /*  3 irq 8 */
-	SUN4M_INT_REALTIME,				  /*  4 irq 10 */
-	SUN4M_INT_FLOPPY,				  /*  5 irq 11 */
-	(SUN4M_INT_SERIAL | SUN4M_INT_KBDMS),	  	  /*  6 irq 12 */
-	SUN4M_INT_MODULE_ERR,			  	  /*  7 irq 15 */
-	SUN4M_INT_SBUS(0),				  /*  8 irq 2 */
-	SUN4M_INT_SBUS(1),				  /*  9 irq 3 */
-	SUN4M_INT_SBUS(2),				  /* 10 irq 5 */
-	SUN4M_INT_SBUS(3),				  /* 11 irq 7 */
-	SUN4M_INT_SBUS(4),				  /* 12 irq 9 */
-	SUN4M_INT_SBUS(5),				  /* 13 irq 11 */
-	SUN4M_INT_SBUS(6)				  /* 14 irq 13 */
-};
-
-static int sun4m_pil_map[] = { 0, 2, 3, 5, 7, 9, 11, 13 };
-
-static unsigned int sun4m_sbint_to_irq(struct sbus_dev *sdev,
-				       unsigned int sbint)
-{
-	if (sbint >= sizeof(sun4m_pil_map)) {
-		printk(KERN_ERR "%s: bogus SBINT %d\n", sdev->prom_name, sbint);
-		BUG();
-	}
-	return sun4m_pil_map[sbint] | 0x30;
-}
-
 static unsigned long sun4m_get_irqmask(unsigned int irq)
 {
 	unsigned long mask;
     
-	if (irq > 0x20) {
-		/* OBIO/SBUS interrupts */
-		irq &= 0x1f;
-		mask = irq_mask[irq_xlate[irq]];
-		if (!mask)
-			printk("sun4m_get_irqmask: IRQ%d has no valid mask!\n",irq);
-	} else {
-		/* Soft Interrupts will come here.
-		 * Currently there is no way to trigger them but I'm sure
-		 * something could be cooked up.
-		 */
-		irq &= 0xf;
-		mask = SUN4M_SOFT_INT(irq);
-	}
+	if (irq < 0x50)
+		mask = irq_mask[irq];
+	else
+		mask = 0;
+
+	if (!mask)
+		printk(KERN_ERR "sun4m_get_irqmask: IRQ%d has no valid mask!\n",
+		       irq);
+
 	return mask;
 }
 
@@ -193,9 +215,9 @@
 	mask = sun4m_get_irqmask(irq_nr);
 	local_irq_save(flags);
 	if (irq_nr > 15)
-		sun4m_interrupts->set = mask;
+		sbus_writel(mask, &sun4m_irq_global->mask_set);
 	else
-		sun4m_interrupts->cpu_intregs[cpu].set = mask;
+		sbus_writel(mask, &sun4m_irq_percpu[cpu]->set);
 	local_irq_restore(flags);    
 }
 
@@ -212,13 +234,13 @@
 		mask = sun4m_get_irqmask(irq_nr);
 		local_irq_save(flags);
 		if (irq_nr > 15)
-			sun4m_interrupts->clear = mask;
+			sbus_writel(mask, &sun4m_irq_global->mask_clear);
 		else
-			sun4m_interrupts->cpu_intregs[cpu].clear = mask;
+			sbus_writel(mask, &sun4m_irq_percpu[cpu]->clear);
 		local_irq_restore(flags);    
 	} else {
 		local_irq_save(flags);
-		sun4m_interrupts->clear = SUN4M_INT_FLOPPY;
+		sbus_writel(SUN4M_INT_FLOPPY, &sun4m_irq_global->mask_clear);
 		local_irq_restore(flags);
 	}
 }
@@ -236,10 +258,10 @@
 /*9*/	SUN4M_INT_SBUS(4) | SUN4M_INT_VME(4) | SUN4M_INT_MODULE_ERR,
 /*10*/	SUN4M_INT_REALTIME,
 /*11*/	SUN4M_INT_SBUS(5) | SUN4M_INT_VME(5) | SUN4M_INT_FLOPPY,
-/*12*/	SUN4M_INT_SERIAL | SUN4M_INT_KBDMS,
-/*13*/	SUN4M_INT_AUDIO,
+/*12*/	SUN4M_INT_SERIAL  | SUN4M_INT_KBDMS,
+/*13*/	SUN4M_INT_SBUS(6) | SUN4M_INT_VME(6) | SUN4M_INT_AUDIO,
 /*14*/	SUN4M_INT_E14,
-/*15*/	0x00000000
+/*15*/	SUN4M_INT_ERROR
 };
 
 /* We assume the caller has disabled local interrupts when these are called,
@@ -247,126 +269,141 @@
  */
 static void sun4m_disable_pil_irq(unsigned int pil)
 {
-	sun4m_interrupts->set = cpu_pil_to_imask[pil];
+	sbus_writel(cpu_pil_to_imask[pil], &sun4m_irq_global->mask_set);
 }
 
 static void sun4m_enable_pil_irq(unsigned int pil)
 {
-	sun4m_interrupts->clear = cpu_pil_to_imask[pil];
+	sbus_writel(cpu_pil_to_imask[pil], &sun4m_irq_global->mask_clear);
 }
 
 #ifdef CONFIG_SMP
 static void sun4m_send_ipi(int cpu, int level)
 {
-	unsigned long mask;
-
-	mask = sun4m_get_irqmask(level);
-	sun4m_interrupts->cpu_intregs[cpu].set = mask;
+	unsigned long mask = sun4m_get_irqmask(level);
+	sbus_writel(mask, &sun4m_irq_percpu[cpu]->set);
 }
 
 static void sun4m_clear_ipi(int cpu, int level)
 {
-	unsigned long mask;
-
-	mask = sun4m_get_irqmask(level);
-	sun4m_interrupts->cpu_intregs[cpu].clear = mask;
+	unsigned long mask = sun4m_get_irqmask(level);
+	sbus_writel(mask, &sun4m_irq_percpu[cpu]->clear);
 }
 
 static void sun4m_set_udt(int cpu)
 {
-	sun4m_interrupts->undirected_target = cpu;
+	sbus_writel(cpu, &sun4m_irq_global->interrupt_target);
 }
 #endif
 
-#define OBIO_INTR	0x20
-#define TIMER_IRQ  	(OBIO_INTR | 10)
-#define PROFILE_IRQ	(OBIO_INTR | 14)
+struct sun4m_timer_percpu {
+	u32		l14_limit;
+	u32		l14_count;
+	u32		l14_limit_noclear;
+	u32		user_timer_start_stop;
+};
 
-static struct sun4m_timer_regs *sun4m_timers;
+static struct sun4m_timer_percpu __iomem *timers_percpu[SUN4M_NCPUS];
+
+struct sun4m_timer_global {
+	u32		l10_limit;
+	u32		l10_count;
+	u32		l10_limit_noclear;
+	u32		reserved;
+	u32		timer_config;
+};
+
+static struct sun4m_timer_global __iomem *timers_global;
+
+#define TIMER_IRQ  	(OBP_INT_LEVEL_ONBOARD | 10)
+
 unsigned int lvl14_resolution = (((1000000/HZ) + 1) << 10);
 
 static void sun4m_clear_clock_irq(void)
 {
-	volatile unsigned int clear_intr;
-	clear_intr = sun4m_timers->l10_timer_limit;
+	sbus_readl(&timers_global->l10_limit);
 }
 
-static void sun4m_clear_profile_irq(int cpu)
+void sun4m_nmi(struct pt_regs *regs)
 {
-	volatile unsigned int clear;
-    
-	clear = sun4m_timers->cpu_timers[cpu].l14_timer_limit;
+	unsigned long afsr, afar, si;
+
+	printk(KERN_ERR "Aieee: sun4m NMI received!\n");
+	/* XXX HyperSparc hack XXX */
+	__asm__ __volatile__("mov 0x500, %%g1\n\t"
+			     "lda [%%g1] 0x4, %0\n\t"
+			     "mov 0x600, %%g1\n\t"
+			     "lda [%%g1] 0x4, %1\n\t" :
+			     "=r" (afsr), "=r" (afar));
+	printk(KERN_ERR "afsr=%08lx afar=%08lx\n", afsr, afar);
+	si = sbus_readl(&sun4m_irq_global->pending);
+	printk(KERN_ERR "si=%08lx\n", si);
+	if (si & SUN4M_INT_MODULE_ERR)
+		printk(KERN_ERR "Module async error\n");
+	if (si & SUN4M_INT_M2S_WRITE_ERR)
+		printk(KERN_ERR "MBus/SBus async error\n");
+	if (si & SUN4M_INT_ECC_ERR)
+		printk(KERN_ERR "ECC memory error\n");
+	if (si & SUN4M_INT_VME_ERR)
+		printk(KERN_ERR "VME async error\n");
+	printk(KERN_ERR "you lose buddy boy...\n");
+	show_regs(regs);
+	prom_halt();
+}
+
+/* Exported for sun4m_smp.c */
+void sun4m_clear_profile_irq(int cpu)
+{
+	sbus_readl(&timers_percpu[cpu]->l14_limit);
 }
 
 static void sun4m_load_profile_irq(int cpu, unsigned int limit)
 {
-	sun4m_timers->cpu_timers[cpu].l14_timer_limit = limit;
+	sbus_writel(limit, &timers_percpu[cpu]->l14_limit);
 }
 
 static void __init sun4m_init_timers(irq_handler_t counter_fn)
 {
-	int reg_count, irq, cpu;
-	struct linux_prom_registers cnt_regs[PROMREG_MAX];
-	int obio_node, cnt_node;
-	struct resource r;
+	struct device_node *dp = of_find_node_by_name(NULL, "counter");
+	int i, err, len, num_cpu_timers;
+	const u32 *addr;
 
-	cnt_node = 0;
-	if((obio_node =
-	    prom_searchsiblings (prom_getchild(prom_root_node), "obio")) == 0 ||
-	   (obio_node = prom_getchild (obio_node)) == 0 ||
-	   (cnt_node = prom_searchsiblings (obio_node, "counter")) == 0) {
-		prom_printf("Cannot find /obio/counter node\n");
-		prom_halt();
-	}
-	reg_count = prom_getproperty(cnt_node, "reg",
-				     (void *) cnt_regs, sizeof(cnt_regs));
-	reg_count = (reg_count/sizeof(struct linux_prom_registers));
-    
-	/* Apply the obio ranges to the timer registers. */
-	prom_apply_obio_ranges(cnt_regs, reg_count);
-    
-	cnt_regs[4].phys_addr = cnt_regs[reg_count-1].phys_addr;
-	cnt_regs[4].reg_size = cnt_regs[reg_count-1].reg_size;
-	cnt_regs[4].which_io = cnt_regs[reg_count-1].which_io;
-	for(obio_node = 1; obio_node < 4; obio_node++) {
-		cnt_regs[obio_node].phys_addr =
-			cnt_regs[obio_node-1].phys_addr + PAGE_SIZE;
-		cnt_regs[obio_node].reg_size = cnt_regs[obio_node-1].reg_size;
-		cnt_regs[obio_node].which_io = cnt_regs[obio_node-1].which_io;
+	if (!dp) {
+		printk(KERN_ERR "sun4m_init_timers: No 'counter' node.\n");
+		return;
 	}
 
-	memset((char*)&r, 0, sizeof(struct resource));
-	/* Map the per-cpu Counter registers. */
-	r.flags = cnt_regs[0].which_io;
-	r.start = cnt_regs[0].phys_addr;
-	sun4m_timers = (struct sun4m_timer_regs *) sbus_ioremap(&r, 0,
-	    PAGE_SIZE*SUN4M_NCPUS, "sun4m_cpu_cnt");
-	/* Map the system Counter register. */
-	/* XXX Here we expect consequent calls to yeld adjusent maps. */
-	r.flags = cnt_regs[4].which_io;
-	r.start = cnt_regs[4].phys_addr;
-	sbus_ioremap(&r, 0, cnt_regs[4].reg_size, "sun4m_sys_cnt");
-
-	sun4m_timers->l10_timer_limit =  (((1000000/HZ) + 1) << 10);
-	master_l10_counter = &sun4m_timers->l10_cur_count;
-	master_l10_limit = &sun4m_timers->l10_timer_limit;
-
-	irq = request_irq(TIMER_IRQ,
-			  counter_fn,
-			  (IRQF_DISABLED | SA_STATIC_ALLOC),
-			  "timer", NULL);
-	if (irq) {
-		prom_printf("time_init: unable to attach IRQ%d\n",TIMER_IRQ);
-		prom_halt();
+	addr = of_get_property(dp, "address", &len);
+	if (!addr) {
+		printk(KERN_ERR "sun4m_init_timers: No 'address' prop.\n");
+		return;
 	}
-   
-	if (!cpu_find_by_instance(1, NULL, NULL)) {
-		for(cpu = 0; cpu < 4; cpu++)
-			sun4m_timers->cpu_timers[cpu].l14_timer_limit = 0;
-		sun4m_interrupts->set = SUN4M_INT_E14;
-	} else {
-		sun4m_timers->cpu_timers[0].l14_timer_limit = 0;
+
+	num_cpu_timers = (len / sizeof(u32)) - 1;
+	for (i = 0; i < num_cpu_timers; i++) {
+		timers_percpu[i] = (void __iomem *)
+			(unsigned long) addr[i];
 	}
+	timers_global = (void __iomem *)
+		(unsigned long) addr[num_cpu_timers];
+
+	sbus_writel((((1000000/HZ) + 1) << 10), &timers_global->l10_limit);
+
+	master_l10_counter = &timers_global->l10_count;
+
+	err = request_irq(TIMER_IRQ, counter_fn,
+			  (IRQF_DISABLED | SA_STATIC_ALLOC), "timer", NULL);
+	if (err) {
+		printk(KERN_ERR "sun4m_init_timers: Register IRQ error %d.\n",
+			err);
+		return;
+	}
+
+	for (i = 0; i < num_cpu_timers; i++)
+		sbus_writel(0, &timers_percpu[i]->l14_limit);
+	if (num_cpu_timers == 4)
+		sbus_writel(SUN4M_INT_E14, &sun4m_irq_global->mask_set);
+
 #ifdef CONFIG_SMP
 	{
 		unsigned long flags;
@@ -390,70 +427,43 @@
 
 void __init sun4m_init_IRQ(void)
 {
-	int ie_node,i;
-	struct linux_prom_registers int_regs[PROMREG_MAX];
-	int num_regs;
-	struct resource r;
-	int mid;
-    
+	struct device_node *dp = of_find_node_by_name(NULL, "interrupt");
+	int len, i, mid, num_cpu_iregs;
+	const u32 *addr;
+
+	if (!dp) {
+		printk(KERN_ERR "sun4m_init_IRQ: No 'interrupt' node.\n");
+		return;
+	}
+
+	addr = of_get_property(dp, "address", &len);
+	if (!addr) {
+		printk(KERN_ERR "sun4m_init_IRQ: No 'address' prop.\n");
+		return;
+	}
+
+	num_cpu_iregs = (len / sizeof(u32)) - 1;
+	for (i = 0; i < num_cpu_iregs; i++) {
+		sun4m_irq_percpu[i] = (void __iomem *)
+			(unsigned long) addr[i];
+	}
+	sun4m_irq_global = (void __iomem *)
+		(unsigned long) addr[num_cpu_iregs];
+
 	local_irq_disable();
-	if((ie_node = prom_searchsiblings(prom_getchild(prom_root_node), "obio")) == 0 ||
-	   (ie_node = prom_getchild (ie_node)) == 0 ||
-	   (ie_node = prom_searchsiblings (ie_node, "interrupt")) == 0) {
-		prom_printf("Cannot find /obio/interrupt node\n");
-		prom_halt();
-	}
-	num_regs = prom_getproperty(ie_node, "reg", (char *) int_regs,
-				    sizeof(int_regs));
-	num_regs = (num_regs/sizeof(struct linux_prom_registers));
-    
-	/* Apply the obio ranges to these registers. */
-	prom_apply_obio_ranges(int_regs, num_regs);
-    
-	int_regs[4].phys_addr = int_regs[num_regs-1].phys_addr;
-	int_regs[4].reg_size = int_regs[num_regs-1].reg_size;
-	int_regs[4].which_io = int_regs[num_regs-1].which_io;
-	for(ie_node = 1; ie_node < 4; ie_node++) {
-		int_regs[ie_node].phys_addr = int_regs[ie_node-1].phys_addr + PAGE_SIZE;
-		int_regs[ie_node].reg_size = int_regs[ie_node-1].reg_size;
-		int_regs[ie_node].which_io = int_regs[ie_node-1].which_io;
-	}
 
-	memset((char *)&r, 0, sizeof(struct resource));
-	/* Map the interrupt registers for all possible cpus. */
-	r.flags = int_regs[0].which_io;
-	r.start = int_regs[0].phys_addr;
-	sun4m_interrupts = (struct sun4m_intregs *) sbus_ioremap(&r, 0,
-	    PAGE_SIZE*SUN4M_NCPUS, "interrupts_percpu");
-
-	/* Map the system interrupt control registers. */
-	r.flags = int_regs[4].which_io;
-	r.start = int_regs[4].phys_addr;
-	sbus_ioremap(&r, 0, int_regs[4].reg_size, "interrupts_system");
-
-	sun4m_interrupts->set = ~SUN4M_INT_MASKALL;
+	sbus_writel(~SUN4M_INT_MASKALL, &sun4m_irq_global->mask_set);
 	for (i = 0; !cpu_find_by_instance(i, NULL, &mid); i++)
-		sun4m_interrupts->cpu_intregs[mid].clear = ~0x17fff;
+		sbus_writel(~0x17fff, &sun4m_irq_percpu[mid]->clear);
 
-	if (!cpu_find_by_instance(1, NULL, NULL)) {
-		/* system wide interrupts go to cpu 0, this should always
-		 * be safe because it is guaranteed to be fitted or OBP doesn't
-		 * come up
-		 *
-		 * Not sure, but writing here on SLAVIO systems may puke
-		 * so I don't do it unless there is more than 1 cpu.
-		 */
-		irq_rcvreg = (unsigned long *)
-				&sun4m_interrupts->undirected_target;
-		sun4m_interrupts->undirected_target = 0;
-	}
-	BTFIXUPSET_CALL(sbint_to_irq, sun4m_sbint_to_irq, BTFIXUPCALL_NORM);
+	if (num_cpu_iregs == 4)
+		sbus_writel(0, &sun4m_irq_global->interrupt_target);
+
 	BTFIXUPSET_CALL(enable_irq, sun4m_enable_irq, BTFIXUPCALL_NORM);
 	BTFIXUPSET_CALL(disable_irq, sun4m_disable_irq, BTFIXUPCALL_NORM);
 	BTFIXUPSET_CALL(enable_pil_irq, sun4m_enable_pil_irq, BTFIXUPCALL_NORM);
 	BTFIXUPSET_CALL(disable_pil_irq, sun4m_disable_pil_irq, BTFIXUPCALL_NORM);
 	BTFIXUPSET_CALL(clear_clock_irq, sun4m_clear_clock_irq, BTFIXUPCALL_NORM);
-	BTFIXUPSET_CALL(clear_profile_irq, sun4m_clear_profile_irq, BTFIXUPCALL_NORM);
 	BTFIXUPSET_CALL(load_profile_irq, sun4m_load_profile_irq, BTFIXUPCALL_NORM);
 	sparc_init_timers = sun4m_init_timers;
 #ifdef CONFIG_SMP
@@ -461,5 +471,6 @@
 	BTFIXUPSET_CALL(clear_cpu_int, sun4m_clear_ipi, BTFIXUPCALL_NORM);
 	BTFIXUPSET_CALL(set_irq_udt, sun4m_set_udt, BTFIXUPCALL_NORM);
 #endif
+
 	/* Cannot enable interrupts until OBP ticker is disabled. */
 }
diff --git a/arch/sparc/kernel/sun4m_smp.c b/arch/sparc/kernel/sun4m_smp.c
index a14a76a..5fc386d 100644
--- a/arch/sparc/kernel/sun4m_smp.c
+++ b/arch/sparc/kernel/sun4m_smp.c
@@ -17,6 +17,7 @@
 #include <linux/swap.h>
 #include <linux/profile.h>
 #include <linux/delay.h>
+#include <linux/cpu.h>
 
 #include <asm/cacheflush.h>
 #include <asm/tlbflush.h>
@@ -71,6 +72,8 @@
 	local_flush_cache_all();
 	local_flush_tlb_all();
 
+	notify_cpu_starting(cpuid);
+
 	/* Get our local ticker going. */
 	smp_setup_percpu_timer();
 
@@ -313,6 +316,8 @@
 	ccall_info.processors_out[i] = 1;
 }
 
+extern void sun4m_clear_profile_irq(int cpu);
+
 void smp4m_percpu_timer_interrupt(struct pt_regs *regs)
 {
 	struct pt_regs *old_regs;
@@ -320,7 +325,7 @@
 
 	old_regs = set_irq_regs(regs);
 
-	clear_profile_irq(cpu);
+	sun4m_clear_profile_irq(cpu);
 
 	profile_tick(CPU_PROFILING);
 
diff --git a/arch/sparc/kernel/sun4setup.c b/arch/sparc/kernel/sun4setup.c
deleted file mode 100644
index 229a52f..0000000
--- a/arch/sparc/kernel/sun4setup.c
+++ /dev/null
@@ -1,75 +0,0 @@
-/* sun4setup.c: Setup the hardware address of various items in the sun4
- * 		architecture. Called from idprom_init
- *
- * Copyright (C) 1998 Chris G. Davis (cdavis@cois.on.ca)
- */
-
-#include <asm/page.h>
-#include <asm/oplib.h>
-#include <asm/idprom.h>
-#include <asm/sun4paddr.h>
-#include <asm/machines.h>
-
-int sun4_memreg_physaddr;
-int sun4_ie_physaddr;
-int sun4_clock_physaddr;
-int sun4_timer_physaddr;
-int sun4_eth_physaddr;
-int sun4_si_physaddr;
-int sun4_bwtwo_physaddr;
-int sun4_zs0_physaddr;
-int sun4_zs1_physaddr;
-int sun4_dma_physaddr;
-int sun4_esp_physaddr;
-int sun4_ie_physaddr; 
-
-void __init sun4setup(void)
-{
-	printk("Sun4 Hardware Setup v1.0 18/May/98 Chris Davis (cdavis@cois.on.ca). ");
-	/*
-	  setup standard sun4 info
-	  */
-	sun4_ie_physaddr=SUN4_IE_PHYSADDR;
-
-	/*
-	  setup model specific info
-	  */
-	switch(idprom->id_machtype) {
-		case (SM_SUN4 | SM_4_260 ):
-			printk("Setup for a SUN4/260\n");
-			sun4_memreg_physaddr=SUN4_200_MEMREG_PHYSADDR;
-			sun4_clock_physaddr=SUN4_200_CLOCK_PHYSADDR;
-			sun4_timer_physaddr=SUN4_UNUSED_PHYSADDR;
-			sun4_eth_physaddr=SUN4_200_ETH_PHYSADDR;
-			sun4_si_physaddr=SUN4_200_SI_PHYSADDR;
-			sun4_bwtwo_physaddr=SUN4_200_BWTWO_PHYSADDR;
-			sun4_dma_physaddr=SUN4_UNUSED_PHYSADDR;
-			sun4_esp_physaddr=SUN4_UNUSED_PHYSADDR;
-			break;
-		case (SM_SUN4 | SM_4_330 ):
-			printk("Setup for a SUN4/330\n");
-			sun4_memreg_physaddr=SUN4_300_MEMREG_PHYSADDR;
-			sun4_clock_physaddr=SUN4_300_CLOCK_PHYSADDR;
-			sun4_timer_physaddr=SUN4_300_TIMER_PHYSADDR;
-			sun4_eth_physaddr=SUN4_300_ETH_PHYSADDR;
-			sun4_si_physaddr=SUN4_UNUSED_PHYSADDR;
-			sun4_bwtwo_physaddr=SUN4_300_BWTWO_PHYSADDR;
-			sun4_dma_physaddr=SUN4_300_DMA_PHYSADDR;
-			sun4_esp_physaddr=SUN4_300_ESP_PHYSADDR;
-			break;
-		case (SM_SUN4 | SM_4_470 ):
-			printk("Setup for a SUN4/470\n");
-			sun4_memreg_physaddr=SUN4_400_MEMREG_PHYSADDR;
-			sun4_clock_physaddr=SUN4_400_CLOCK_PHYSADDR;
-			sun4_timer_physaddr=SUN4_400_TIMER_PHYSADDR;
-			sun4_eth_physaddr=SUN4_400_ETH_PHYSADDR;
-			sun4_si_physaddr=SUN4_UNUSED_PHYSADDR;
-			sun4_bwtwo_physaddr=SUN4_400_BWTWO_PHYSADDR;
-			sun4_dma_physaddr=SUN4_400_DMA_PHYSADDR;
-			sun4_esp_physaddr=SUN4_400_ESP_PHYSADDR;
-			break;
-		default:
-			;
-	}
-}
-
diff --git a/arch/sparc/kernel/sys_sparc.c b/arch/sparc/kernel/sys_sparc.c
index 4d73421..03035c8 100644
--- a/arch/sparc/kernel/sys_sparc.c
+++ b/arch/sparc/kernel/sys_sparc.c
@@ -53,7 +53,7 @@
 	/* See asm-sparc/uaccess.h */
 	if (len > TASK_SIZE - PAGE_SIZE)
 		return -ENOMEM;
-	if (ARCH_SUN4C_SUN4 && len > 0x20000000)
+	if (ARCH_SUN4C && len > 0x20000000)
 		return -ENOMEM;
 	if (!addr)
 		addr = TASK_UNMAPPED_BASE;
@@ -65,7 +65,7 @@
 
 	for (vmm = find_vma(current->mm, addr); ; vmm = vmm->vm_next) {
 		/* At this point:  (!vmm || addr < vmm->vm_end). */
-		if (ARCH_SUN4C_SUN4 && addr < 0xe0000000 && 0x20000000 - len < addr) {
+		if (ARCH_SUN4C && addr < 0xe0000000 && 0x20000000 - len < addr) {
 			addr = PAGE_OFFSET;
 			vmm = find_vma(current->mm, PAGE_OFFSET);
 		}
@@ -81,7 +81,7 @@
 
 asmlinkage unsigned long sparc_brk(unsigned long brk)
 {
-	if(ARCH_SUN4C_SUN4) {
+	if(ARCH_SUN4C) {
 		if ((brk & 0xe0000000) != (current->mm->brk & 0xe0000000))
 			return current->mm->brk;
 	}
@@ -221,7 +221,7 @@
 
 int sparc_mmap_check(unsigned long addr, unsigned long len)
 {
-	if (ARCH_SUN4C_SUN4 &&
+	if (ARCH_SUN4C &&
 	    (len > 0x20000000 ||
 	     (addr < 0xe0000000 && addr + len > 0x20000000)))
 		return -EINVAL;
diff --git a/arch/sparc/kernel/tick14.c b/arch/sparc/kernel/tick14.c
index 707bfda..138bbf5 100644
--- a/arch/sparc/kernel/tick14.c
+++ b/arch/sparc/kernel/tick14.c
@@ -1,31 +1,12 @@
 /* tick14.c
- * linux/arch/sparc/kernel/tick14.c
  *
  * Copyright (C) 1996 David Redman (djhr@tadpole.co.uk)
  *
  * This file handles the Sparc specific level14 ticker
  * This is really useful for profiling OBP uses it for keyboard
  * aborts and other stuff.
- *
- *
  */
-#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/timex.h>
-#include <linux/interrupt.h>
-
-#include <asm/oplib.h>
-#include <asm/timer.h>
-#include <asm/mostek.h>
-#include <asm/system.h>
-#include <asm/irq.h>
-#include <asm/io.h>
-
-#include "irq.h"
 
 extern unsigned long lvl14_save[5];
 static unsigned long *linux_lvl14 = NULL;
@@ -56,31 +37,3 @@
 	linux_lvl14[2] =  obp_lvl14[2];
 	linux_lvl14[3] =  obp_lvl14[3]; 
 }
-
-void claim_ticker14(irq_handler_t handler,
-		    int irq_nr, unsigned int timeout )
-{
-	int cpu = smp_processor_id();
-
-	/* first we copy the obp handler instructions
-	 */
-	__disable_irq(irq_nr);
-	if (!handler)
-		return;
-    
-	linux_lvl14 = (unsigned long *)lvl14_save[4];
-	obp_lvl14[0] = linux_lvl14[0];
-	obp_lvl14[1] = linux_lvl14[1];
-	obp_lvl14[2] = linux_lvl14[2];
-	obp_lvl14[3] = linux_lvl14[3];
-
-	if (!request_irq(irq_nr,
-			 handler,
-			 (IRQF_DISABLED | SA_STATIC_ALLOC),
-			 "counter14",
-			 NULL)) {
-		install_linux_ticker();
-		load_profile_irq(cpu, timeout);
-		__enable_irq(irq_nr);
-	}
-}
diff --git a/arch/sparc/kernel/time.c b/arch/sparc/kernel/time.c
index 0762f5d..62c1d94 100644
--- a/arch/sparc/kernel/time.c
+++ b/arch/sparc/kernel/time.c
@@ -23,22 +23,24 @@
 #include <linux/mm.h>
 #include <linux/interrupt.h>
 #include <linux/time.h>
+#include <linux/rtc.h>
+#include <linux/rtc/m48t59.h>
 #include <linux/timex.h>
 #include <linux/init.h>
 #include <linux/pci.h>
 #include <linux/ioport.h>
 #include <linux/profile.h>
+#include <linux/of.h>
 #include <linux/of_device.h>
+#include <linux/platform_device.h>
 
 #include <asm/oplib.h>
 #include <asm/timer.h>
-#include <asm/mostek.h>
 #include <asm/system.h>
 #include <asm/irq.h>
 #include <asm/io.h>
 #include <asm/idprom.h>
 #include <asm/machines.h>
-#include <asm/sun4paddr.h>
 #include <asm/page.h>
 #include <asm/pcic.h>
 #include <asm/irq_regs.h>
@@ -46,34 +48,9 @@
 #include "irq.h"
 
 DEFINE_SPINLOCK(rtc_lock);
-static enum sparc_clock_type sp_clock_typ;
-DEFINE_SPINLOCK(mostek_lock);
-void __iomem *mstk48t02_regs = NULL;
-static struct mostek48t08 __iomem *mstk48t08_regs = NULL;
 static int set_rtc_mmss(unsigned long);
 static int sbus_do_settimeofday(struct timespec *tv);
 
-#ifdef CONFIG_SUN4
-struct intersil *intersil_clock;
-#define intersil_cmd(intersil_reg, intsil_cmd) intersil_reg->int_cmd_reg = \
-	(intsil_cmd)
-
-#define intersil_intr(intersil_reg, intsil_cmd) intersil_reg->int_intr_reg = \
-	(intsil_cmd)
-
-#define intersil_start(intersil_reg) intersil_cmd(intersil_reg, \
-	( INTERSIL_START | INTERSIL_32K | INTERSIL_NORMAL | INTERSIL_24H |\
-	  INTERSIL_INTR_ENABLE))
-
-#define intersil_stop(intersil_reg) intersil_cmd(intersil_reg, \
-	( INTERSIL_STOP | INTERSIL_32K | INTERSIL_NORMAL | INTERSIL_24H |\
-	  INTERSIL_INTR_ENABLE))
-
-#define intersil_read_intr(intersil_reg, towhere) towhere = \
-	intersil_reg->int_intr_reg
-
-#endif
-
 unsigned long profile_pc(struct pt_regs *regs)
 {
 	extern char __copy_user_begin[], __copy_user_end[];
@@ -96,7 +73,6 @@
 EXPORT_SYMBOL(profile_pc);
 
 __volatile__ unsigned int *master_l10_counter;
-__volatile__ unsigned int *master_l10_limit;
 
 /*
  * timer_interrupt() needs to keep up the real-time clock,
@@ -116,15 +92,7 @@
 
 	/* Protect counter clear so that do_gettimeoffset works */
 	write_seqlock(&xtime_lock);
-#ifdef CONFIG_SUN4
-	if((idprom->id_machtype == (SM_SUN4 | SM_4_260)) ||
-	   (idprom->id_machtype == (SM_SUN4 | SM_4_110))) {
-		int temp;
-        	intersil_read_intr(intersil_clock, temp);
-		/* re-enable the irq */
-		enable_pil_irq(10);
-	}
-#endif
+
 	clear_clock_irq();
 
 	do_timer(1);
@@ -147,157 +115,56 @@
 	return IRQ_HANDLED;
 }
 
-/* Kick start a stopped clock (procedure from the Sun NVRAM/hostid FAQ). */
-static void __devinit kick_start_clock(void)
+static unsigned char mostek_read_byte(struct device *dev, u32 ofs)
 {
-	struct mostek48t02 *regs = (struct mostek48t02 *)mstk48t02_regs;
-	unsigned char sec;
-	int i, count;
+	struct platform_device *pdev = to_platform_device(dev);
+	struct m48t59_plat_data *pdata = pdev->dev.platform_data;
+	void __iomem *regs = pdata->ioaddr;
+	unsigned char val = readb(regs + ofs);
 
-	prom_printf("CLOCK: Clock was stopped. Kick start ");
-
-	spin_lock_irq(&mostek_lock);
-
-	/* Turn on the kick start bit to start the oscillator. */
-	regs->creg |= MSTK_CREG_WRITE;
-	regs->sec &= ~MSTK_STOP;
-	regs->hour |= MSTK_KICK_START;
-	regs->creg &= ~MSTK_CREG_WRITE;
-
-	spin_unlock_irq(&mostek_lock);
-
-	/* Delay to allow the clock oscillator to start. */
-	sec = MSTK_REG_SEC(regs);
-	for (i = 0; i < 3; i++) {
-		while (sec == MSTK_REG_SEC(regs))
-			for (count = 0; count < 100000; count++)
-				/* nothing */ ;
-		prom_printf(".");
-		sec = regs->sec;
+	/* the year 0 is 1968 */
+	if (ofs == pdata->offset + M48T59_YEAR) {
+		val += 0x68;
+		if ((val & 0xf) > 9)
+			val += 6;
 	}
-	prom_printf("\n");
+	return val;
+}
 
-	spin_lock_irq(&mostek_lock);
+static void mostek_write_byte(struct device *dev, u32 ofs, u8 val)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct m48t59_plat_data *pdata = pdev->dev.platform_data;
+	void __iomem *regs = pdata->ioaddr;
 
-	/* Turn off kick start and set a "valid" time and date. */
-	regs->creg |= MSTK_CREG_WRITE;
-	regs->hour &= ~MSTK_KICK_START;
-	MSTK_SET_REG_SEC(regs,0);
-	MSTK_SET_REG_MIN(regs,0);
-	MSTK_SET_REG_HOUR(regs,0);
-	MSTK_SET_REG_DOW(regs,5);
-	MSTK_SET_REG_DOM(regs,1);
-	MSTK_SET_REG_MONTH(regs,8);
-	MSTK_SET_REG_YEAR(regs,1996 - MSTK_YEAR_ZERO);
-	regs->creg &= ~MSTK_CREG_WRITE;
-
-	spin_unlock_irq(&mostek_lock);
-
-	/* Ensure the kick start bit is off. If it isn't, turn it off. */
-	while (regs->hour & MSTK_KICK_START) {
-		prom_printf("CLOCK: Kick start still on!\n");
-
-		spin_lock_irq(&mostek_lock);
-		regs->creg |= MSTK_CREG_WRITE;
-		regs->hour &= ~MSTK_KICK_START;
-		regs->creg &= ~MSTK_CREG_WRITE;
-		spin_unlock_irq(&mostek_lock);
+	if (ofs == pdata->offset + M48T59_YEAR) {
+		if (val < 0x68)
+			val += 0x32;
+		else
+			val -= 0x68;
+		if ((val & 0xf) > 9)
+			val += 6;
+		if ((val & 0xf0) > 0x9A)
+			val += 0x60;
 	}
-
-	prom_printf("CLOCK: Kick start procedure successful.\n");
+	writeb(val, regs + ofs);
 }
 
-/* Return nonzero if the clock chip battery is low. */
-static inline int has_low_battery(void)
-{
-	struct mostek48t02 *regs = (struct mostek48t02 *)mstk48t02_regs;
-	unsigned char data1, data2;
+static struct m48t59_plat_data m48t59_data = {
+	.read_byte = mostek_read_byte,
+	.write_byte = mostek_write_byte,
+};
 
-	spin_lock_irq(&mostek_lock);
-	data1 = regs->eeprom[0];	/* Read some data. */
-	regs->eeprom[0] = ~data1;	/* Write back the complement. */
-	data2 = regs->eeprom[0];	/* Read back the complement. */
-	regs->eeprom[0] = data1;	/* Restore the original value. */
-	spin_unlock_irq(&mostek_lock);
+/* resource is set at runtime */
+static struct platform_device m48t59_rtc = {
+	.name		= "rtc-m48t59",
+	.id		= 0,
+	.num_resources	= 1,
+	.dev	= {
+		.platform_data = &m48t59_data,
+	},
+};
 
-	return (data1 == data2);	/* Was the write blocked? */
-}
-
-static void __devinit mostek_set_system_time(void)
-{
-	unsigned int year, mon, day, hour, min, sec;
-	struct mostek48t02 *mregs;
-
-	mregs = (struct mostek48t02 *)mstk48t02_regs;
-	if(!mregs) {
-		prom_printf("Something wrong, clock regs not mapped yet.\n");
-		prom_halt();
-	}		
-	spin_lock_irq(&mostek_lock);
-	mregs->creg |= MSTK_CREG_READ;
-	sec = MSTK_REG_SEC(mregs);
-	min = MSTK_REG_MIN(mregs);
-	hour = MSTK_REG_HOUR(mregs);
-	day = MSTK_REG_DOM(mregs);
-	mon = MSTK_REG_MONTH(mregs);
-	year = MSTK_CVT_YEAR( MSTK_REG_YEAR(mregs) );
-	xtime.tv_sec = mktime(year, mon, day, hour, min, sec);
-	xtime.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ);
-        set_normalized_timespec(&wall_to_monotonic,
-                                -xtime.tv_sec, -xtime.tv_nsec);
-	mregs->creg &= ~MSTK_CREG_READ;
-	spin_unlock_irq(&mostek_lock);
-}
-
-/* Probe for the real time clock chip on Sun4 */
-static inline void sun4_clock_probe(void)
-{
-#ifdef CONFIG_SUN4
-	int temp;
-	struct resource r;
-
-	memset(&r, 0, sizeof(r));
-	if( idprom->id_machtype == (SM_SUN4 | SM_4_330) ) {
-		sp_clock_typ = MSTK48T02;
-		r.start = sun4_clock_physaddr;
-		mstk48t02_regs = sbus_ioremap(&r, 0,
-				       sizeof(struct mostek48t02), NULL);
-		mstk48t08_regs = NULL;  /* To catch weirdness */
-		intersil_clock = NULL;  /* just in case */
-
-		/* Kick start the clock if it is completely stopped. */
-		if (mostek_read(mstk48t02_regs + MOSTEK_SEC) & MSTK_STOP)
-			kick_start_clock();
-	} else if( idprom->id_machtype == (SM_SUN4 | SM_4_260)) {
-		/* intersil setup code */
-		printk("Clock: INTERSIL at %8x ",sun4_clock_physaddr);
-		sp_clock_typ = INTERSIL;
-		r.start = sun4_clock_physaddr;
-		intersil_clock = (struct intersil *) 
-		    sbus_ioremap(&r, 0, sizeof(*intersil_clock), "intersil");
-		mstk48t02_regs = 0;  /* just be sure */
-		mstk48t08_regs = NULL;  /* ditto */
-		/* initialise the clock */
-
-		intersil_intr(intersil_clock,INTERSIL_INT_100HZ);
-
-		intersil_start(intersil_clock);
-
-		intersil_read_intr(intersil_clock, temp);
-                while (!(temp & 0x80))
-                        intersil_read_intr(intersil_clock, temp);
-
-                intersil_read_intr(intersil_clock, temp);
-                while (!(temp & 0x80))
-                        intersil_read_intr(intersil_clock, temp);
-
-		intersil_stop(intersil_clock);
-
-	}
-#endif
-}
-
-#ifndef CONFIG_SUN4
 static int __devinit clock_probe(struct of_device *op, const struct of_device_id *match)
 {
 	struct device_node *dp = op->node;
@@ -306,38 +173,26 @@
 	if (!model)
 		return -ENODEV;
 
+	m48t59_rtc.resource = &op->resource[0];
 	if (!strcmp(model, "mk48t02")) {
-		sp_clock_typ = MSTK48T02;
-
 		/* Map the clock register io area read-only */
-		mstk48t02_regs = of_ioremap(&op->resource[0], 0,
-					    sizeof(struct mostek48t02),
-					    "mk48t02");
-		mstk48t08_regs = NULL;  /* To catch weirdness */
+		m48t59_data.ioaddr = of_ioremap(&op->resource[0], 0,
+						2048, "rtc-m48t59");
+		m48t59_data.type = M48T59RTC_TYPE_M48T02;
 	} else if (!strcmp(model, "mk48t08")) {
-		sp_clock_typ = MSTK48T08;
-		mstk48t08_regs = of_ioremap(&op->resource[0], 0,
-					    sizeof(struct mostek48t08),
-					    "mk48t08");
-
-		mstk48t02_regs = &mstk48t08_regs->regs;
+		m48t59_data.ioaddr = of_ioremap(&op->resource[0], 0,
+						8192, "rtc-m48t59");
+		m48t59_data.type = M48T59RTC_TYPE_M48T08;
 	} else
 		return -ENODEV;
 
-	/* Report a low battery voltage condition. */
-	if (has_low_battery())
-		printk(KERN_CRIT "NVRAM: Low battery voltage!\n");
-
-	/* Kick start the clock if it is completely stopped. */
-	if (mostek_read(mstk48t02_regs + MOSTEK_SEC) & MSTK_STOP)
-		kick_start_clock();
-
-	mostek_set_system_time();
+	if (platform_device_register(&m48t59_rtc) < 0)
+		printk(KERN_ERR "Registering RTC device failed\n");
 
 	return 0;
 }
 
-static struct of_device_id clock_match[] = {
+static struct of_device_id __initdata clock_match[] = {
 	{
 		.name = "eeprom",
 	},
@@ -348,7 +203,7 @@
 	.match_table	= clock_match,
 	.probe		= clock_probe,
 	.driver		= {
-		.name	= "clock",
+		.name	= "rtc",
 	},
 };
 
@@ -364,7 +219,6 @@
  * need to see the clock registers.
  */
 fs_initcall(clock_init);
-#endif /* !CONFIG_SUN4 */
 
 static void __init sbus_time_init(void)
 {
@@ -372,51 +226,8 @@
 	BTFIXUPSET_CALL(bus_do_settimeofday, sbus_do_settimeofday, BTFIXUPCALL_NORM);
 	btfixup();
 
-	if (ARCH_SUN4)
-		sun4_clock_probe();
-
 	sparc_init_timers(timer_interrupt);
 	
-#ifdef CONFIG_SUN4
-	if(idprom->id_machtype == (SM_SUN4 | SM_4_330)) {
-		mostek_set_system_time();
-	} else if(idprom->id_machtype == (SM_SUN4 | SM_4_260) ) {
-		/* initialise the intersil on sun4 */
-		unsigned int year, mon, day, hour, min, sec;
-		int temp;
-		struct intersil *iregs;
-
-		iregs=intersil_clock;
-		if(!iregs) {
-			prom_printf("Something wrong, clock regs not mapped yet.\n");
-			prom_halt();
-		}
-
-		intersil_intr(intersil_clock,INTERSIL_INT_100HZ);
-		disable_pil_irq(10);
-		intersil_stop(iregs);
-		intersil_read_intr(intersil_clock, temp);
-
-		temp = iregs->clk.int_csec;
-
-		sec = iregs->clk.int_sec;
-		min = iregs->clk.int_min;
-		hour = iregs->clk.int_hour;
-		day = iregs->clk.int_day;
-		mon = iregs->clk.int_month;
-		year = MSTK_CVT_YEAR(iregs->clk.int_year);
-
-		enable_pil_irq(10);
-		intersil_start(iregs);
-
-		xtime.tv_sec = mktime(year, mon, day, hour, min, sec);
-		xtime.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ);
-	        set_normalized_timespec(&wall_to_monotonic,
- 	                               -xtime.tv_sec, -xtime.tv_nsec);
-		printk("%u/%u/%u %u:%u:%u\n",day,mon,year,hour,min,sec);
-	}
-#endif
-
 	/* Now that OBP ticker has been silenced, it is safe to enable IRQ. */
 	local_irq_enable();
 }
@@ -522,80 +333,15 @@
 	return 0;
 }
 
-/*
- * BUG: This routine does not handle hour overflow properly; it just
- *      sets the minutes. Usually you won't notice until after reboot!
- */
-static int set_rtc_mmss(unsigned long nowtime)
+static int set_rtc_mmss(unsigned long secs)
 {
-	int real_seconds, real_minutes, mostek_minutes;
-	struct mostek48t02 *regs = (struct mostek48t02 *)mstk48t02_regs;
-	unsigned long flags;
-#ifdef CONFIG_SUN4
-	struct intersil *iregs = intersil_clock;
-	int temp;
-#endif
+	struct rtc_device *rtc = rtc_class_open("rtc0");
+	int err = -1;
 
-	/* Not having a register set can lead to trouble. */
-	if (!regs) {
-#ifdef CONFIG_SUN4
-		if(!iregs)
-		return -1;
-	 	else {
-			temp = iregs->clk.int_csec;
-
-			mostek_minutes = iregs->clk.int_min;
-
-			real_seconds = nowtime % 60;
-			real_minutes = nowtime / 60;
-			if (((abs(real_minutes - mostek_minutes) + 15)/30) & 1)
-				real_minutes += 30;	/* correct for half hour time zone */
-			real_minutes %= 60;
-
-			if (abs(real_minutes - mostek_minutes) < 30) {
-				intersil_stop(iregs);
-				iregs->clk.int_sec=real_seconds;
-				iregs->clk.int_min=real_minutes;
-				intersil_start(iregs);
-			} else {
-				printk(KERN_WARNING
-			       "set_rtc_mmss: can't update from %d to %d\n",
-				       mostek_minutes, real_minutes);
-				return -1;
-			}
-			
-			return 0;
-		}
-#endif
+	if (rtc) {
+		err = rtc_set_mmss(rtc, secs);
+		rtc_class_close(rtc);
 	}
 
-	spin_lock_irqsave(&mostek_lock, flags);
-	/* Read the current RTC minutes. */
-	regs->creg |= MSTK_CREG_READ;
-	mostek_minutes = MSTK_REG_MIN(regs);
-	regs->creg &= ~MSTK_CREG_READ;
-
-	/*
-	 * since we're only adjusting minutes and seconds,
-	 * don't interfere with hour overflow. This avoids
-	 * messing with unknown time zones but requires your
-	 * RTC not to be off by more than 15 minutes
-	 */
-	real_seconds = nowtime % 60;
-	real_minutes = nowtime / 60;
-	if (((abs(real_minutes - mostek_minutes) + 15)/30) & 1)
-		real_minutes += 30;	/* correct for half hour time zone */
-	real_minutes %= 60;
-
-	if (abs(real_minutes - mostek_minutes) < 30) {
-		regs->creg |= MSTK_CREG_WRITE;
-		MSTK_SET_REG_SEC(regs,real_seconds);
-		MSTK_SET_REG_MIN(regs,real_minutes);
-		regs->creg &= ~MSTK_CREG_WRITE;
-		spin_unlock_irqrestore(&mostek_lock, flags);
-		return 0;
-	} else {
-		spin_unlock_irqrestore(&mostek_lock, flags);
-		return -1;
-	}
+	return err;
 }
diff --git a/arch/sparc/kernel/traps.c b/arch/sparc/kernel/traps.c
index 5d45d5f..2b7d506 100644
--- a/arch/sparc/kernel/traps.c
+++ b/arch/sparc/kernel/traps.c
@@ -43,23 +43,6 @@
 {
 }
 
-void sun4m_nmi(struct pt_regs *regs)
-{
-	unsigned long afsr, afar;
-
-	printk("Aieee: sun4m NMI received!\n");
-	/* XXX HyperSparc hack XXX */
-	__asm__ __volatile__("mov 0x500, %%g1\n\t"
-			     "lda [%%g1] 0x4, %0\n\t"
-			     "mov 0x600, %%g1\n\t"
-			     "lda [%%g1] 0x4, %1\n\t" :
-			     "=r" (afsr), "=r" (afar));
-	printk("afsr=%08lx afar=%08lx\n", afsr, afar);
-	printk("you lose buddy boy...\n");
-	show_regs(regs);
-	prom_halt();
-}
-
 void sun4d_nmi(struct pt_regs *regs)
 {
 	printk("Aieee: sun4d NMI received!\n");
diff --git a/arch/sparc/mm/Makefile b/arch/sparc/mm/Makefile
index 109c8b2..ea88955 100644
--- a/arch/sparc/mm/Makefile
+++ b/arch/sparc/mm/Makefile
@@ -3,13 +3,8 @@
 
 EXTRA_AFLAGS := -ansi
 
-obj-y    := fault.o init.o loadmmu.o generic.o extable.o btfixup.o
-
-ifeq ($(CONFIG_SUN4),y)
-obj-y	 += nosrmmu.o
-else
-obj-y	 += srmmu.o iommu.o io-unit.o hypersparc.o viking.o tsunami.o swift.o
-endif
+obj-y	:= fault.o init.o loadmmu.o generic.o extable.o btfixup.o \
+	    srmmu.o iommu.o io-unit.o hypersparc.o viking.o tsunami.o swift.o
 
 ifdef CONFIG_HIGHMEM
 obj-y	+= highmem.o
diff --git a/arch/sparc/mm/btfixup.c b/arch/sparc/mm/btfixup.c
index a312d12..5175ac2 100644
--- a/arch/sparc/mm/btfixup.c
+++ b/arch/sparc/mm/btfixup.c
@@ -20,11 +20,7 @@
 
 extern char *srmmu_name;
 static char version[] __initdata = "Boot time fixup v1.6. 4/Mar/98 Jakub Jelinek (jj@ultra.linux.cz). Patching kernel for ";
-#ifdef CONFIG_SUN4
-static char str_sun4c[] __initdata = "sun4\n";
-#else
 static char str_sun4c[] __initdata = "sun4c\n";
-#endif
 static char str_srmmu[] __initdata = "srmmu[%s]/";
 static char str_iommu[] __initdata = "iommu\n";
 static char str_iounit[] __initdata = "io-unit\n";
@@ -86,7 +82,7 @@
 	if (!visited) {
 		visited++;
 		printk(version);
-		if (ARCH_SUN4C_SUN4)
+		if (ARCH_SUN4C)
 			printk(str_sun4c);
 		else {
 			printk(str_srmmu, srmmu_name);
diff --git a/arch/sparc/mm/fault.c b/arch/sparc/mm/fault.c
index 3604c2e..a507e11 100644
--- a/arch/sparc/mm/fault.c
+++ b/arch/sparc/mm/fault.c
@@ -191,7 +191,7 @@
 	 * only copy the information from the master page table,
 	 * nothing more.
 	 */
-	if (!ARCH_SUN4C_SUN4 && address >= TASK_SIZE)
+	if (!ARCH_SUN4C && address >= TASK_SIZE)
 		goto vmalloc_fault;
 
 	info.si_code = SEGV_MAPERR;
diff --git a/arch/sparc/mm/init.c b/arch/sparc/mm/init.c
index e103f1b..677c1e1 100644
--- a/arch/sparc/mm/init.c
+++ b/arch/sparc/mm/init.c
@@ -23,6 +23,7 @@
 #include <linux/highmem.h>
 #include <linux/bootmem.h>
 #include <linux/pagemap.h>
+#include <linux/poison.h>
 
 #include <asm/system.h>
 #include <asm/vac-ops.h>
@@ -480,6 +481,7 @@
 	for (; addr < (unsigned long)(&__init_end); addr += PAGE_SIZE) {
 		struct page *p;
 
+		memset((void *)addr, POISON_FREE_INITMEM, PAGE_SIZE);
 		p = virt_to_page(addr);
 
 		ClearPageReserved(p);
@@ -488,20 +490,26 @@
 		totalram_pages++;
 		num_physpages++;
 	}
-	printk (KERN_INFO "Freeing unused kernel memory: %dk freed\n", (&__init_end - &__init_begin) >> 10);
+	printk(KERN_INFO "Freeing unused kernel memory: %dk freed\n",
+		(&__init_end - &__init_begin) >> 10);
 }
 
 #ifdef CONFIG_BLK_DEV_INITRD
 void free_initrd_mem(unsigned long start, unsigned long end)
 {
 	if (start < end)
-		printk (KERN_INFO "Freeing initrd memory: %ldk freed\n", (end - start) >> 10);
+		printk(KERN_INFO "Freeing initrd memory: %ldk freed\n",
+			(end - start) >> 10);
 	for (; start < end; start += PAGE_SIZE) {
-		struct page *p = virt_to_page(start);
+		struct page *p;
+
+		memset((void *)start, POISON_FREE_INITMEM, PAGE_SIZE);
+		p = virt_to_page(start);
 
 		ClearPageReserved(p);
 		init_page_count(p);
 		__free_page(p);
+		totalram_pages++;
 		num_physpages++;
 	}
 }
diff --git a/arch/sparc/mm/io-unit.c b/arch/sparc/mm/io-unit.c
index f167835..daadf5f 100644
--- a/arch/sparc/mm/io-unit.c
+++ b/arch/sparc/mm/io-unit.c
@@ -12,10 +12,11 @@
 #include <linux/highmem.h>	/* pte_offset_map => kmap_atomic */
 #include <linux/bitops.h>
 #include <linux/scatterlist.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 
 #include <asm/pgalloc.h>
 #include <asm/pgtable.h>
-#include <asm/sbus.h>
 #include <asm/io.h>
 #include <asm/io-unit.h>
 #include <asm/mxcc.h>
@@ -34,13 +35,10 @@
 #define IOPERM        (IOUPTE_CACHE | IOUPTE_WRITE | IOUPTE_VALID)
 #define MKIOPTE(phys) __iopte((((phys)>>4) & IOUPTE_PAGE) | IOPERM)
 
-void __init
-iounit_init(int sbi_node, int io_node, struct sbus_bus *sbus)
+static void __init iounit_iommu_init(struct of_device *op)
 {
-	iopte_t *xpt, *xptend;
 	struct iounit_struct *iounit;
-	struct linux_prom_registers iommu_promregs[PROMREG_MAX];
-	struct resource r;
+	iopte_t *xpt, *xptend;
 
 	iounit = kzalloc(sizeof(struct iounit_struct), GFP_ATOMIC);
 	if (!iounit) {
@@ -55,18 +53,13 @@
 	iounit->rotor[1] = IOUNIT_BMAP2_START;
 	iounit->rotor[2] = IOUNIT_BMAPM_START;
 
-	xpt = NULL;
-	if(prom_getproperty(sbi_node, "reg", (void *) iommu_promregs,
-			    sizeof(iommu_promregs)) != -1) {
-		prom_apply_generic_ranges(io_node, 0, iommu_promregs, 3);
-		memset(&r, 0, sizeof(r));
-		r.flags = iommu_promregs[2].which_io;
-		r.start = iommu_promregs[2].phys_addr;
-		xpt = (iopte_t *) sbus_ioremap(&r, 0, PAGE_SIZE * 16, "XPT");
+	xpt = of_ioremap(&op->resource[2], 0, PAGE_SIZE * 16, "XPT");
+	if (!xpt) {
+		prom_printf("SUN4D: Cannot map External Page Table.");
+		prom_halt();
 	}
-	if(!xpt) panic("Cannot map External Page Table.");
 	
-	sbus->ofdev.dev.archdata.iommu = iounit;
+	op->dev.archdata.iommu = iounit;
 	iounit->page_table = xpt;
 	spin_lock_init(&iounit->lock);
 	
@@ -75,6 +68,25 @@
 	     	iopte_val(*xpt++) = 0;
 }
 
+static int __init iounit_init(void)
+{
+	extern void sun4d_init_sbi_irq(void);
+	struct device_node *dp;
+
+	for_each_node_by_name(dp, "sbi") {
+		struct of_device *op = of_find_device_by_node(dp);
+
+		iounit_iommu_init(op);
+		of_propagate_archdata(op);
+	}
+
+	sun4d_init_sbi_irq();
+
+	return 0;
+}
+
+subsys_initcall(iounit_init);
+
 /* One has to hold iounit->lock to call this */
 static unsigned long iounit_get_area(struct iounit_struct *iounit, unsigned long vaddr, int size)
 {
@@ -124,10 +136,10 @@
 	return vaddr;
 }
 
-static __u32 iounit_get_scsi_one(char *vaddr, unsigned long len, struct sbus_bus *sbus)
+static __u32 iounit_get_scsi_one(struct device *dev, char *vaddr, unsigned long len)
 {
+	struct iounit_struct *iounit = dev->archdata.iommu;
 	unsigned long ret, flags;
-	struct iounit_struct *iounit = sbus->ofdev.dev.archdata.iommu;
 	
 	spin_lock_irqsave(&iounit->lock, flags);
 	ret = iounit_get_area(iounit, (unsigned long)vaddr, len);
@@ -135,10 +147,10 @@
 	return ret;
 }
 
-static void iounit_get_scsi_sgl(struct scatterlist *sg, int sz, struct sbus_bus *sbus)
+static void iounit_get_scsi_sgl(struct device *dev, struct scatterlist *sg, int sz)
 {
+	struct iounit_struct *iounit = dev->archdata.iommu;
 	unsigned long flags;
-	struct iounit_struct *iounit = sbus->ofdev.dev.archdata.iommu;
 
 	/* FIXME: Cache some resolved pages - often several sg entries are to the same page */
 	spin_lock_irqsave(&iounit->lock, flags);
@@ -151,10 +163,10 @@
 	spin_unlock_irqrestore(&iounit->lock, flags);
 }
 
-static void iounit_release_scsi_one(__u32 vaddr, unsigned long len, struct sbus_bus *sbus)
+static void iounit_release_scsi_one(struct device *dev, __u32 vaddr, unsigned long len)
 {
+	struct iounit_struct *iounit = dev->archdata.iommu;
 	unsigned long flags;
-	struct iounit_struct *iounit = sbus->ofdev.dev.archdata.iommu;
 	
 	spin_lock_irqsave(&iounit->lock, flags);
 	len = ((vaddr & ~PAGE_MASK) + len + (PAGE_SIZE-1)) >> PAGE_SHIFT;
@@ -165,11 +177,11 @@
 	spin_unlock_irqrestore(&iounit->lock, flags);
 }
 
-static void iounit_release_scsi_sgl(struct scatterlist *sg, int sz, struct sbus_bus *sbus)
+static void iounit_release_scsi_sgl(struct device *dev, struct scatterlist *sg, int sz)
 {
+	struct iounit_struct *iounit = dev->archdata.iommu;
 	unsigned long flags;
 	unsigned long vaddr, len;
-	struct iounit_struct *iounit = sbus->ofdev.dev.archdata.iommu;
 
 	spin_lock_irqsave(&iounit->lock, flags);
 	while (sz != 0) {
@@ -185,12 +197,12 @@
 }
 
 #ifdef CONFIG_SBUS
-static int iounit_map_dma_area(dma_addr_t *pba, unsigned long va, __u32 addr, int len)
+static int iounit_map_dma_area(struct device *dev, dma_addr_t *pba, unsigned long va, __u32 addr, int len)
 {
+	struct iounit_struct *iounit = dev->archdata.iommu;
 	unsigned long page, end;
 	pgprot_t dvma_prot;
 	iopte_t *iopte;
-	struct sbus_bus *sbus;
 
 	*pba = addr;
 
@@ -212,12 +224,8 @@
 			
 			i = ((addr - IOUNIT_DMA_BASE) >> PAGE_SHIFT);
 
-			for_each_sbus(sbus) {
-				struct iounit_struct *iounit = sbus->ofdev.dev.archdata.iommu;
-
-				iopte = (iopte_t *)(iounit->page_table + i);
-				*iopte = MKIOPTE(__pa(page));
-			}
+			iopte = (iopte_t *)(iounit->page_table + i);
+			*iopte = MKIOPTE(__pa(page));
 		}
 		addr += PAGE_SIZE;
 		va += PAGE_SIZE;
@@ -228,23 +236,10 @@
 	return 0;
 }
 
-static void iounit_unmap_dma_area(unsigned long addr, int len)
+static void iounit_unmap_dma_area(struct device *dev, unsigned long addr, int len)
 {
 	/* XXX Somebody please fill this in */
 }
-
-/* XXX We do not pass sbus device here, bad. */
-static struct page *iounit_translate_dvma(unsigned long addr)
-{
-	struct sbus_bus *sbus = sbus_root;	/* They are all the same */
-	struct iounit_struct *iounit = sbus->ofdev.dev.archdata.iommu;
-	int i;
-	iopte_t *iopte;
-
-	i = ((addr - IOUNIT_DMA_BASE) >> PAGE_SHIFT);
-	iopte = (iopte_t *)(iounit->page_table + i);
-	return pfn_to_page(iopte_val(*iopte) >> (PAGE_SHIFT-4)); /* XXX sun4d guru, help */
-}
 #endif
 
 static char *iounit_lockarea(char *vaddr, unsigned long len)
@@ -271,54 +266,5 @@
 #ifdef CONFIG_SBUS
 	BTFIXUPSET_CALL(mmu_map_dma_area, iounit_map_dma_area, BTFIXUPCALL_NORM);
 	BTFIXUPSET_CALL(mmu_unmap_dma_area, iounit_unmap_dma_area, BTFIXUPCALL_NORM);
-	BTFIXUPSET_CALL(mmu_translate_dvma, iounit_translate_dvma, BTFIXUPCALL_NORM);
 #endif
 }
-
-__u32 iounit_map_dma_init(struct sbus_bus *sbus, int size)
-{
-	int i, j, k, npages;
-	unsigned long rotor, scan, limit;
-	unsigned long flags;
-	__u32 ret;
-	struct iounit_struct *iounit = sbus->ofdev.dev.archdata.iommu;
-
-        npages = (size + (PAGE_SIZE-1)) >> PAGE_SHIFT;
-	i = 0x0213;
-	spin_lock_irqsave(&iounit->lock, flags);
-next:	j = (i & 15);
-	rotor = iounit->rotor[j - 1];
-	limit = iounit->limit[j];
-	scan = rotor;
-nexti:	scan = find_next_zero_bit(iounit->bmap, limit, scan);
-	if (scan + npages > limit) {
-		if (limit != rotor) {
-			limit = rotor;
-			scan = iounit->limit[j - 1];
-			goto nexti;
-		}
-		i >>= 4;
-		if (!(i & 15))
-			panic("iounit_map_dma_init: Couldn't find free iopte slots for %d bytes\n", size);
-		goto next;
-	}
-	for (k = 1, scan++; k < npages; k++)
-		if (test_bit(scan++, iounit->bmap))
-			goto nexti;
-	iounit->rotor[j - 1] = (scan < limit) ? scan : iounit->limit[j - 1];
-	scan -= npages;
-	ret = IOUNIT_DMA_BASE + (scan << PAGE_SHIFT);
-	for (k = 0; k < npages; k++, scan++)
-		set_bit(scan, iounit->bmap);
-	spin_unlock_irqrestore(&iounit->lock, flags);
-	return ret;
-}
-
-__u32 iounit_map_dma_page(__u32 vaddr, void *addr, struct sbus_bus *sbus)
-{
-	int scan = (vaddr - IOUNIT_DMA_BASE) >> PAGE_SHIFT;
-	struct iounit_struct *iounit = sbus->ofdev.dev.archdata.iommu;
-	
-	iounit->page_table[scan] = MKIOPTE(__pa(((unsigned long)addr) & PAGE_MASK));
-	return vaddr + (((unsigned long)addr) & ~PAGE_MASK);
-}
diff --git a/arch/sparc/mm/iommu.c b/arch/sparc/mm/iommu.c
index 4b93427..e7a499e 100644
--- a/arch/sparc/mm/iommu.c
+++ b/arch/sparc/mm/iommu.c
@@ -13,10 +13,11 @@
 #include <linux/slab.h>
 #include <linux/highmem.h>	/* pte_offset_map => kmap_atomic */
 #include <linux/scatterlist.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 
 #include <asm/pgalloc.h>
 #include <asm/pgtable.h>
-#include <asm/sbus.h>
 #include <asm/io.h>
 #include <asm/mxcc.h>
 #include <asm/mbus.h>
@@ -55,30 +56,21 @@
 #define IOPERM        (IOPTE_CACHE | IOPTE_WRITE | IOPTE_VALID)
 #define MKIOPTE(pfn, perm) (((((pfn)<<8) & IOPTE_PAGE) | (perm)) & ~IOPTE_WAZ)
 
-void __init
-iommu_init(int iommund, struct sbus_bus *sbus)
+static void __init sbus_iommu_init(struct of_device *op)
 {
-	unsigned int impl, vers;
-	unsigned long tmp;
 	struct iommu_struct *iommu;
-	struct linux_prom_registers iommu_promregs[PROMREG_MAX];
-	struct resource r;
+	unsigned int impl, vers;
 	unsigned long *bitmap;
+	unsigned long tmp;
 
 	iommu = kmalloc(sizeof(struct iommu_struct), GFP_ATOMIC);
 	if (!iommu) {
 		prom_printf("Unable to allocate iommu structure\n");
 		prom_halt();
 	}
-	iommu->regs = NULL;
-	if (prom_getproperty(iommund, "reg", (void *) iommu_promregs,
-			 sizeof(iommu_promregs)) != -1) {
-		memset(&r, 0, sizeof(r));
-		r.flags = iommu_promregs[0].which_io;
-		r.start = iommu_promregs[0].phys_addr;
-		iommu->regs = (struct iommu_regs *)
-			sbus_ioremap(&r, 0, PAGE_SIZE * 3, "iommu_regs");
-	}
+
+	iommu->regs = of_ioremap(&op->resource[0], 0, PAGE_SIZE * 3,
+				 "iommu_regs");
 	if (!iommu->regs) {
 		prom_printf("Cannot map IOMMU registers\n");
 		prom_halt();
@@ -128,13 +120,29 @@
 	else
 		iommu->usemap.num_colors = 1;
 
-	printk("IOMMU: impl %d vers %d table 0x%p[%d B] map [%d b]\n",
-	    impl, vers, iommu->page_table,
-	    (int)(IOMMU_NPTES*sizeof(iopte_t)), (int)IOMMU_NPTES);
+	printk(KERN_INFO "IOMMU: impl %d vers %d table 0x%p[%d B] map [%d b]\n",
+	       impl, vers, iommu->page_table,
+	       (int)(IOMMU_NPTES*sizeof(iopte_t)), (int)IOMMU_NPTES);
 
-	sbus->ofdev.dev.archdata.iommu = iommu;
+	op->dev.archdata.iommu = iommu;
 }
 
+static int __init iommu_init(void)
+{
+	struct device_node *dp;
+
+	for_each_node_by_name(dp, "iommu") {
+		struct of_device *op = of_find_device_by_node(dp);
+
+		sbus_iommu_init(op);
+		of_propagate_archdata(op);
+	}
+
+	return 0;
+}
+
+subsys_initcall(iommu_init);
+
 /* This begs to be btfixup-ed by srmmu. */
 /* Flush the iotlb entries to ram. */
 /* This could be better if we didn't have to flush whole pages. */
@@ -164,9 +172,9 @@
 	}
 }
 
-static u32 iommu_get_one(struct page *page, int npages, struct sbus_bus *sbus)
+static u32 iommu_get_one(struct device *dev, struct page *page, int npages)
 {
-	struct iommu_struct *iommu = sbus->ofdev.dev.archdata.iommu;
+	struct iommu_struct *iommu = dev->archdata.iommu;
 	int ioptex;
 	iopte_t *iopte, *iopte0;
 	unsigned int busa, busa0;
@@ -194,8 +202,7 @@
 	return busa0;
 }
 
-static u32 iommu_get_scsi_one(char *vaddr, unsigned int len,
-    struct sbus_bus *sbus)
+static u32 iommu_get_scsi_one(struct device *dev, char *vaddr, unsigned int len)
 {
 	unsigned long off;
 	int npages;
@@ -205,22 +212,22 @@
 	off = (unsigned long)vaddr & ~PAGE_MASK;
 	npages = (off + len + PAGE_SIZE-1) >> PAGE_SHIFT;
 	page = virt_to_page((unsigned long)vaddr & PAGE_MASK);
-	busa = iommu_get_one(page, npages, sbus);
+	busa = iommu_get_one(dev, page, npages);
 	return busa + off;
 }
 
-static __u32 iommu_get_scsi_one_noflush(char *vaddr, unsigned long len, struct sbus_bus *sbus)
+static __u32 iommu_get_scsi_one_noflush(struct device *dev, char *vaddr, unsigned long len)
 {
-	return iommu_get_scsi_one(vaddr, len, sbus);
+	return iommu_get_scsi_one(dev, vaddr, len);
 }
 
-static __u32 iommu_get_scsi_one_gflush(char *vaddr, unsigned long len, struct sbus_bus *sbus)
+static __u32 iommu_get_scsi_one_gflush(struct device *dev, char *vaddr, unsigned long len)
 {
 	flush_page_for_dma(0);
-	return iommu_get_scsi_one(vaddr, len, sbus);
+	return iommu_get_scsi_one(dev, vaddr, len);
 }
 
-static __u32 iommu_get_scsi_one_pflush(char *vaddr, unsigned long len, struct sbus_bus *sbus)
+static __u32 iommu_get_scsi_one_pflush(struct device *dev, char *vaddr, unsigned long len)
 {
 	unsigned long page = ((unsigned long) vaddr) & PAGE_MASK;
 
@@ -228,23 +235,23 @@
 		flush_page_for_dma(page);
 		page += PAGE_SIZE;
 	}
-	return iommu_get_scsi_one(vaddr, len, sbus);
+	return iommu_get_scsi_one(dev, vaddr, len);
 }
 
-static void iommu_get_scsi_sgl_noflush(struct scatterlist *sg, int sz, struct sbus_bus *sbus)
+static void iommu_get_scsi_sgl_noflush(struct device *dev, struct scatterlist *sg, int sz)
 {
 	int n;
 
 	while (sz != 0) {
 		--sz;
 		n = (sg->length + sg->offset + PAGE_SIZE-1) >> PAGE_SHIFT;
-		sg->dvma_address = iommu_get_one(sg_page(sg), n, sbus) + sg->offset;
+		sg->dvma_address = iommu_get_one(dev, sg_page(sg), n) + sg->offset;
 		sg->dvma_length = (__u32) sg->length;
 		sg = sg_next(sg);
 	}
 }
 
-static void iommu_get_scsi_sgl_gflush(struct scatterlist *sg, int sz, struct sbus_bus *sbus)
+static void iommu_get_scsi_sgl_gflush(struct device *dev, struct scatterlist *sg, int sz)
 {
 	int n;
 
@@ -252,13 +259,13 @@
 	while (sz != 0) {
 		--sz;
 		n = (sg->length + sg->offset + PAGE_SIZE-1) >> PAGE_SHIFT;
-		sg->dvma_address = iommu_get_one(sg_page(sg), n, sbus) + sg->offset;
+		sg->dvma_address = iommu_get_one(dev, sg_page(sg), n) + sg->offset;
 		sg->dvma_length = (__u32) sg->length;
 		sg = sg_next(sg);
 	}
 }
 
-static void iommu_get_scsi_sgl_pflush(struct scatterlist *sg, int sz, struct sbus_bus *sbus)
+static void iommu_get_scsi_sgl_pflush(struct device *dev, struct scatterlist *sg, int sz)
 {
 	unsigned long page, oldpage = 0;
 	int n, i;
@@ -283,15 +290,15 @@
 			}
 		}
 
-		sg->dvma_address = iommu_get_one(sg_page(sg), n, sbus) + sg->offset;
+		sg->dvma_address = iommu_get_one(dev, sg_page(sg), n) + sg->offset;
 		sg->dvma_length = (__u32) sg->length;
 		sg = sg_next(sg);
 	}
 }
 
-static void iommu_release_one(u32 busa, int npages, struct sbus_bus *sbus)
+static void iommu_release_one(struct device *dev, u32 busa, int npages)
 {
-	struct iommu_struct *iommu = sbus->ofdev.dev.archdata.iommu;
+	struct iommu_struct *iommu = dev->archdata.iommu;
 	int ioptex;
 	int i;
 
@@ -305,17 +312,17 @@
 	bit_map_clear(&iommu->usemap, ioptex, npages);
 }
 
-static void iommu_release_scsi_one(__u32 vaddr, unsigned long len, struct sbus_bus *sbus)
+static void iommu_release_scsi_one(struct device *dev, __u32 vaddr, unsigned long len)
 {
 	unsigned long off;
 	int npages;
 
 	off = vaddr & ~PAGE_MASK;
 	npages = (off + len + PAGE_SIZE-1) >> PAGE_SHIFT;
-	iommu_release_one(vaddr & PAGE_MASK, npages, sbus);
+	iommu_release_one(dev, vaddr & PAGE_MASK, npages);
 }
 
-static void iommu_release_scsi_sgl(struct scatterlist *sg, int sz, struct sbus_bus *sbus)
+static void iommu_release_scsi_sgl(struct device *dev, struct scatterlist *sg, int sz)
 {
 	int n;
 
@@ -323,18 +330,18 @@
 		--sz;
 
 		n = (sg->length + sg->offset + PAGE_SIZE-1) >> PAGE_SHIFT;
-		iommu_release_one(sg->dvma_address & PAGE_MASK, n, sbus);
+		iommu_release_one(dev, sg->dvma_address & PAGE_MASK, n);
 		sg->dvma_address = 0x21212121;
 		sg = sg_next(sg);
 	}
 }
 
 #ifdef CONFIG_SBUS
-static int iommu_map_dma_area(dma_addr_t *pba, unsigned long va,
-    unsigned long addr, int len)
+static int iommu_map_dma_area(struct device *dev, dma_addr_t *pba, unsigned long va,
+			      unsigned long addr, int len)
 {
+	struct iommu_struct *iommu = dev->archdata.iommu;
 	unsigned long page, end;
-	struct iommu_struct *iommu = sbus_root->ofdev.dev.archdata.iommu;
 	iopte_t *iopte = iommu->page_table;
 	iopte_t *first;
 	int ioptex;
@@ -397,9 +404,9 @@
 	return 0;
 }
 
-static void iommu_unmap_dma_area(unsigned long busa, int len)
+static void iommu_unmap_dma_area(struct device *dev, unsigned long busa, int len)
 {
-	struct iommu_struct *iommu = sbus_root->ofdev.dev.archdata.iommu;
+	struct iommu_struct *iommu = dev->archdata.iommu;
 	iopte_t *iopte = iommu->page_table;
 	unsigned long end;
 	int ioptex = (busa - iommu->start) >> PAGE_SHIFT;
@@ -417,15 +424,6 @@
 	iommu_invalidate(iommu->regs);
 	bit_map_clear(&iommu->usemap, ioptex, len >> PAGE_SHIFT);
 }
-
-static struct page *iommu_translate_dvma(unsigned long busa)
-{
-	struct iommu_struct *iommu = sbus_root->ofdev.dev.archdata.iommu;
-	iopte_t *iopte = iommu->page_table;
-
-	iopte += ((busa - iommu->start) >> PAGE_SHIFT);
-	return pfn_to_page((iopte_val(*iopte) & IOPTE_PAGE) >> (PAGE_SHIFT-4));
-}
 #endif
 
 static char *iommu_lockarea(char *vaddr, unsigned long len)
@@ -461,7 +459,6 @@
 #ifdef CONFIG_SBUS
 	BTFIXUPSET_CALL(mmu_map_dma_area, iommu_map_dma_area, BTFIXUPCALL_NORM);
 	BTFIXUPSET_CALL(mmu_unmap_dma_area, iommu_unmap_dma_area, BTFIXUPCALL_NORM);
-	BTFIXUPSET_CALL(mmu_translate_dvma, iommu_translate_dvma, BTFIXUPCALL_NORM);
 #endif
 
 	if (viking_mxcc_present || srmmu_modtype == HyperSparc) {
diff --git a/arch/sparc/mm/nosrmmu.c b/arch/sparc/mm/nosrmmu.c
deleted file mode 100644
index 3701f70..0000000
--- a/arch/sparc/mm/nosrmmu.c
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * nosrmmu.c: This file is a bunch of dummies for sun4 compiles, 
- *         so that it does not need srmmu and avoid ifdefs.
- *
- * Copyright (C) 1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
- */
-
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/init.h>
-#include <asm/mbus.h>
-#include <asm/sbus.h>
-
-static char shouldnothappen[] __initdata = "SUN4 kernel can only run on SUN4\n";
-
-enum mbus_module srmmu_modtype;
-void *srmmu_nocache_pool;
-
-int vac_cache_size = 0;
-
-static void __init should_not_happen(void)
-{
-	prom_printf(shouldnothappen);
-	prom_halt();
-}
-
-void __init srmmu_frob_mem_map(unsigned long start_mem)
-{
-	should_not_happen();
-}
-
-unsigned long __init srmmu_paging_init(unsigned long start_mem, unsigned long end_mem)
-{
-	should_not_happen();
-	return 0;
-}
-
-void __init ld_mmu_srmmu(void)
-{
-	should_not_happen();
-}
-
-void srmmu_mapioaddr(unsigned long physaddr, unsigned long virt_addr, int bus_type, int rdonly)
-{
-}
-
-void srmmu_unmapioaddr(unsigned long virt_addr)
-{
-}
-
-__u32 iounit_map_dma_init(struct sbus_bus *sbus, int size)
-{
-	return 0;
-}
-
-__u32 iounit_map_dma_page(__u32 vaddr, void *addr, struct sbus_bus *sbus)
-{
-	return 0;
-}
diff --git a/arch/sparc/mm/srmmu.c b/arch/sparc/mm/srmmu.c
index ee30462..6a5d7ca 100644
--- a/arch/sparc/mm/srmmu.c
+++ b/arch/sparc/mm/srmmu.c
@@ -31,7 +31,6 @@
 #include <asm/mbus.h>
 #include <asm/cache.h>
 #include <asm/oplib.h>
-#include <asm/sbus.h>
 #include <asm/asi.h>
 #include <asm/msi.h>
 #include <asm/mmu_context.h>
diff --git a/arch/sparc/mm/sun4c.c b/arch/sparc/mm/sun4c.c
index d1782f6..fe65aee 100644
--- a/arch/sparc/mm/sun4c.c
+++ b/arch/sparc/mm/sun4c.c
@@ -31,7 +31,6 @@
 #include <asm/oplib.h>
 #include <asm/openprom.h>
 #include <asm/mmu_context.h>
-#include <asm/sun4paddr.h>
 #include <asm/highmem.h>
 #include <asm/btfixup.h>
 #include <asm/cacheflush.h>
@@ -52,15 +51,11 @@
 
 extern unsigned long page_kernel;
 
-#ifdef CONFIG_SUN4
-#define SUN4C_VAC_SIZE sun4c_vacinfo.num_bytes
-#else
 /* That's it, we prom_halt() on sun4c if the cache size is something other than 65536.
  * So let's save some cycles and just use that everywhere except for that bootup
  * sanity check.
  */
 #define SUN4C_VAC_SIZE 65536
-#endif
 
 #define SUN4C_KERNEL_BUCKETS 32
 
@@ -285,75 +280,32 @@
 {
 	sun4c_disable_vac();
 
-	if (ARCH_SUN4) {
-		switch (idprom->id_machtype) {
-
-		case (SM_SUN4|SM_4_110):
-			sun4c_vacinfo.type = VAC_NONE;
-			sun4c_vacinfo.num_bytes = 0;
-			sun4c_vacinfo.linesize = 0;
-			sun4c_vacinfo.do_hwflushes = 0;
-			prom_printf("No VAC. Get some bucks and buy a real computer.");
-			prom_halt();
-			break;
-
-		case (SM_SUN4|SM_4_260):
-			sun4c_vacinfo.type = VAC_WRITE_BACK;
-			sun4c_vacinfo.num_bytes = 128 * 1024;
-			sun4c_vacinfo.linesize = 16;
-			sun4c_vacinfo.do_hwflushes = 0;
-			break;
-
-		case (SM_SUN4|SM_4_330):
-			sun4c_vacinfo.type = VAC_WRITE_THROUGH;
-			sun4c_vacinfo.num_bytes = 128 * 1024;
-			sun4c_vacinfo.linesize = 16;
-			sun4c_vacinfo.do_hwflushes = 0;
-			break;
-
-		case (SM_SUN4|SM_4_470):
-			sun4c_vacinfo.type = VAC_WRITE_BACK;
-			sun4c_vacinfo.num_bytes = 128 * 1024;
-			sun4c_vacinfo.linesize = 32;
-			sun4c_vacinfo.do_hwflushes = 0;
-			break;
-
-		default:
-			prom_printf("Cannot initialize VAC - weird sun4 model idprom->id_machtype = %d", idprom->id_machtype);
-			prom_halt();
-		};
+	if ((idprom->id_machtype == (SM_SUN4C | SM_4C_SS1)) ||
+	    (idprom->id_machtype == (SM_SUN4C | SM_4C_SS1PLUS))) {
+		/* PROM on SS1 lacks this info, to be super safe we
+		 * hard code it here since this arch is cast in stone.
+		 */
+		sun4c_vacinfo.num_bytes = 65536;
+		sun4c_vacinfo.linesize = 16;
 	} else {
-		sun4c_vacinfo.type = VAC_WRITE_THROUGH;
+		sun4c_vacinfo.num_bytes =
+		 prom_getintdefault(prom_root_node, "vac-size", 65536);
+		sun4c_vacinfo.linesize =
+		 prom_getintdefault(prom_root_node, "vac-linesize", 16);
+	}
+	sun4c_vacinfo.do_hwflushes =
+	 prom_getintdefault(prom_root_node, "vac-hwflush", 0);
 
-		if ((idprom->id_machtype == (SM_SUN4C | SM_4C_SS1)) ||
-		    (idprom->id_machtype == (SM_SUN4C | SM_4C_SS1PLUS))) {
-			/* PROM on SS1 lacks this info, to be super safe we
-			 * hard code it here since this arch is cast in stone.
-			 */
-			sun4c_vacinfo.num_bytes = 65536;
-			sun4c_vacinfo.linesize = 16;
-		} else {
-			sun4c_vacinfo.num_bytes =
-			 prom_getintdefault(prom_root_node, "vac-size", 65536);
-			sun4c_vacinfo.linesize =
-			 prom_getintdefault(prom_root_node, "vac-linesize", 16);
-		}
+	if (sun4c_vacinfo.do_hwflushes == 0)
 		sun4c_vacinfo.do_hwflushes =
-		 prom_getintdefault(prom_root_node, "vac-hwflush", 0);
+		 prom_getintdefault(prom_root_node, "vac_hwflush", 0);
 
-		if (sun4c_vacinfo.do_hwflushes == 0)
-			sun4c_vacinfo.do_hwflushes =
-			 prom_getintdefault(prom_root_node, "vac_hwflush", 0);
-
-		if (sun4c_vacinfo.num_bytes != 65536) {
-			prom_printf("WEIRD Sun4C VAC cache size, "
-				    "tell sparclinux@vger.kernel.org");
-			prom_halt();
-		}
+	if (sun4c_vacinfo.num_bytes != 65536) {
+		prom_printf("WEIRD Sun4C VAC cache size, "
+			    "tell sparclinux@vger.kernel.org");
+		prom_halt();
 	}
 
-	sun4c_vacinfo.num_lines =
-		(sun4c_vacinfo.num_bytes / sun4c_vacinfo.linesize);
 	switch (sun4c_vacinfo.linesize) {
 	case 16:
 		sun4c_vacinfo.log2lsize = 4;
@@ -447,49 +399,18 @@
 
 static void __init sun4c_probe_mmu(void)
 {
-	if (ARCH_SUN4) {
-		switch (idprom->id_machtype) {
-		case (SM_SUN4|SM_4_110):
-			prom_printf("No support for 4100 yet\n");
-			prom_halt();
-			num_segmaps = 256;
-			num_contexts = 8;
-			break;
-
-		case (SM_SUN4|SM_4_260):
-			/* should be 512 segmaps. when it get fixed */
-			num_segmaps = 256;
-			num_contexts = 16;
-			break;
-
-		case (SM_SUN4|SM_4_330):
-			num_segmaps = 256;
-			num_contexts = 16;
-			break;
-
-		case (SM_SUN4|SM_4_470):
-			/* should be 1024 segmaps. when it get fixed */
-			num_segmaps = 256;
-			num_contexts = 64;
-			break;
-		default:
-			prom_printf("Invalid SUN4 model\n");
-			prom_halt();
-		};
+	if ((idprom->id_machtype == (SM_SUN4C | SM_4C_SS1)) ||
+	    (idprom->id_machtype == (SM_SUN4C | SM_4C_SS1PLUS))) {
+		/* Hardcode these just to be safe, PROM on SS1 does
+		* not have this info available in the root node.
+		*/
+		num_segmaps = 128;
+		num_contexts = 8;
 	} else {
-		if ((idprom->id_machtype == (SM_SUN4C | SM_4C_SS1)) ||
-		    (idprom->id_machtype == (SM_SUN4C | SM_4C_SS1PLUS))) {
-			/* Hardcode these just to be safe, PROM on SS1 does
-		 	* not have this info available in the root node.
-		 	*/
-			num_segmaps = 128;
-			num_contexts = 8;
-		} else {
-			num_segmaps =
-			    prom_getintdefault(prom_root_node, "mmu-npmg", 128);
-			num_contexts =
-			    prom_getintdefault(prom_root_node, "mmu-nctx", 0x8);
-		}
+		num_segmaps =
+		    prom_getintdefault(prom_root_node, "mmu-npmg", 128);
+		num_contexts =
+		    prom_getintdefault(prom_root_node, "mmu-nctx", 0x8);
 	}
 	patch_kernel_fault_handler();
 }
@@ -501,18 +422,14 @@
 	int node;
 	struct linux_prom_registers regs[1];
 
-	if (ARCH_SUN4) {
-		sun4c_memerr_reg = ioremap(sun4_memreg_physaddr, PAGE_SIZE);
-	} else {
-		node = prom_getchild(prom_root_node);
-		node = prom_searchsiblings(prom_root_node, "memory-error");
-		if (!node)
-			return;
-		if (prom_getproperty(node, "reg", (char *)regs, sizeof(regs)) <= 0)
-			return;
-		/* hmm I think regs[0].which_io is zero here anyways */
-		sun4c_memerr_reg = ioremap(regs[0].phys_addr, regs[0].reg_size);
-	}
+	node = prom_getchild(prom_root_node);
+	node = prom_searchsiblings(prom_root_node, "memory-error");
+	if (!node)
+		return;
+	if (prom_getproperty(node, "reg", (char *)regs, sizeof(regs)) <= 0)
+		return;
+	/* hmm I think regs[0].which_io is zero here anyways */
+	sun4c_memerr_reg = ioremap(regs[0].phys_addr, regs[0].reg_size);
 }
 
 static inline void sun4c_init_ss2_cache_bug(void)
@@ -521,7 +438,6 @@
 
 	if ((idprom->id_machtype == (SM_SUN4C | SM_4C_SS2)) ||
 	    (idprom->id_machtype == (SM_SUN4C | SM_4C_IPX)) ||
-	    (idprom->id_machtype == (SM_SUN4 | SM_4_330)) ||
 	    (idprom->id_machtype == (SM_SUN4C | SM_4C_ELC))) {
 		/* Whee.. */
 		printk("SS2 cache bug detected, uncaching trap table page\n");
@@ -532,8 +448,8 @@
 }
 
 /* Addr is always aligned on a page boundary for us already. */
-static int sun4c_map_dma_area(dma_addr_t *pba, unsigned long va,
-    unsigned long addr, int len)
+static int sun4c_map_dma_area(struct device *dev, dma_addr_t *pba, unsigned long va,
+			      unsigned long addr, int len)
 {
 	unsigned long page, end;
 
@@ -555,14 +471,7 @@
 	return 0;
 }
 
-static struct page *sun4c_translate_dvma(unsigned long busa)
-{
-	/* Fortunately for us, bus_addr == uncached_virt in sun4c. */
-	unsigned long pte = sun4c_get_pte(busa);
-	return pfn_to_page(pte & SUN4C_PFN_MASK);
-}
-
-static void sun4c_unmap_dma_area(unsigned long busa, int len)
+static void sun4c_unmap_dma_area(struct device *dev, unsigned long busa, int len)
 {
 	/* Fortunately for us, bus_addr == uncached_virt in sun4c. */
 	/* XXX Implement this */
@@ -624,11 +533,7 @@
 {
 	unsigned long vaddr;
 	unsigned char pseg, ctx;
-#ifdef CONFIG_SUN4
-	/* sun4/110 and 260 have no kadb. */
-	if ((idprom->id_machtype != (SM_SUN4 | SM_4_260)) && 
-	    (idprom->id_machtype != (SM_SUN4 | SM_4_110))) {
-#endif
+
 	for (vaddr = KADB_DEBUGGER_BEGVM;
 	     vaddr < LINUX_OPPROM_ENDVM;
 	     vaddr += SUN4C_REAL_PGDIR_SIZE) {
@@ -640,9 +545,7 @@
 			fix_permissions(vaddr, _SUN4C_PAGE_PRIV, 0);
 		}
 	}
-#ifdef CONFIG_SUN4
-	}
-#endif
+
 	for (vaddr = KERNBASE; vaddr < kernel_end; vaddr += SUN4C_REAL_PGDIR_SIZE) {
 		pseg = sun4c_get_segmap(vaddr);
 		mmu_entry_pool[pseg].locked = 1;
@@ -1048,14 +951,10 @@
 	 * so we must flush the cache to guarantee consistency.
 	 */
 	sun4c_flush_page(pages);
-#ifndef CONFIG_SUN4	
 	sun4c_flush_page(pages + PAGE_SIZE);
-#endif
 
 	sun4c_put_pte(addr, BUCKET_PTE(pages));
-#ifndef CONFIG_SUN4	
 	sun4c_put_pte(addr + PAGE_SIZE, BUCKET_PTE(pages + PAGE_SIZE));
-#endif
 
 #ifdef CONFIG_DEBUG_STACK_USAGE
 	memset((void *)addr, 0, PAGE_SIZE << THREAD_INFO_ORDER);
@@ -1072,13 +971,11 @@
 
 	/* We are deleting a mapping, so the flush here is mandatory. */
 	sun4c_flush_page(tiaddr);
-#ifndef CONFIG_SUN4	
 	sun4c_flush_page(tiaddr + PAGE_SIZE);
-#endif
+
 	sun4c_put_pte(tiaddr, 0);
-#ifndef CONFIG_SUN4	
 	sun4c_put_pte(tiaddr + PAGE_SIZE, 0);
-#endif
+
 	sun4c_bucket[entry] = BUCKET_EMPTY;
 	if (entry < sun4c_lowbucket_avail)
 		sun4c_lowbucket_avail = entry;
@@ -1211,7 +1108,7 @@
  * by implication and fool the page locking code above
  * if passed to by mistake.
  */
-static __u32 sun4c_get_scsi_one(char *bufptr, unsigned long len, struct sbus_bus *sbus)
+static __u32 sun4c_get_scsi_one(struct device *dev, char *bufptr, unsigned long len)
 {
 	unsigned long page;
 
@@ -1223,7 +1120,7 @@
 	return (__u32)sun4c_lockarea(bufptr, len);
 }
 
-static void sun4c_get_scsi_sgl(struct scatterlist *sg, int sz, struct sbus_bus *sbus)
+static void sun4c_get_scsi_sgl(struct device *dev, struct scatterlist *sg, int sz)
 {
 	while (sz != 0) {
 		--sz;
@@ -1233,14 +1130,14 @@
 	}
 }
 
-static void sun4c_release_scsi_one(__u32 bufptr, unsigned long len, struct sbus_bus *sbus)
+static void sun4c_release_scsi_one(struct device *dev, __u32 bufptr, unsigned long len)
 {
 	if (bufptr < sun4c_iobuffer_start)
 		return; /* On kernel stack or similar, see above */
 	sun4c_unlockarea((char *)bufptr, len);
 }
 
-static void sun4c_release_scsi_sgl(struct scatterlist *sg, int sz, struct sbus_bus *sbus)
+static void sun4c_release_scsi_sgl(struct device *dev, struct scatterlist *sg, int sz)
 {
 	while (sz != 0) {
 		--sz;
@@ -2263,7 +2160,6 @@
 
 	BTFIXUPSET_CALL(mmu_map_dma_area, sun4c_map_dma_area, BTFIXUPCALL_NORM);
 	BTFIXUPSET_CALL(mmu_unmap_dma_area, sun4c_unmap_dma_area, BTFIXUPCALL_NORM);
-	BTFIXUPSET_CALL(mmu_translate_dvma, sun4c_translate_dvma, BTFIXUPCALL_NORM);
 
 	BTFIXUPSET_CALL(sparc_mapiorange, sun4c_mapiorange, BTFIXUPCALL_NORM);
 	BTFIXUPSET_CALL(sparc_unmapiorange, sun4c_unmapiorange, BTFIXUPCALL_NORM);
diff --git a/arch/sparc/prom/Makefile b/arch/sparc/prom/Makefile
index 7f5eacf..8f7e185 100644
--- a/arch/sparc/prom/Makefile
+++ b/arch/sparc/prom/Makefile
@@ -4,5 +4,3 @@
 
 lib-y := bootstr.o devmap.o devops.o init.o memory.o misc.o mp.o \
 	 palloc.o ranges.o segment.o console.o printf.o tree.o
-
-lib-$(CONFIG_SUN4) += sun4prom.o
diff --git a/arch/sparc/prom/bootstr.c b/arch/sparc/prom/bootstr.c
index 5a35c76..916831d 100644
--- a/arch/sparc/prom/bootstr.c
+++ b/arch/sparc/prom/bootstr.c
@@ -6,15 +6,12 @@
 
 #include <linux/string.h>
 #include <asm/oplib.h>
-#include <asm/sun4prom.h>
 #include <linux/init.h>
 
 #define BARG_LEN  256
 static char barg_buf[BARG_LEN] = { 0 };
 static char fetched __initdata = 0;
 
-extern linux_sun4_romvec *sun4_romvec;
-
 char * __init
 prom_getbootargs(void)
 {
@@ -28,7 +25,6 @@
 
 	switch(prom_vers) {
 	case PROM_V0:
-	case PROM_SUN4:
 		cp = barg_buf;
 		/* Start from 1 and go over fd(0,0,0)kernel */
 		for(iter = 1; iter < 8; iter++) {
diff --git a/arch/sparc/prom/console.c b/arch/sparc/prom/console.c
index 790057a..b3075d7 100644
--- a/arch/sparc/prom/console.c
+++ b/arch/sparc/prom/console.c
@@ -10,7 +10,6 @@
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <asm/openprom.h>
-#include <asm/sun4prom.h>
 #include <asm/oplib.h>
 #include <asm/system.h>
 #include <linux/string.h>
@@ -30,7 +29,6 @@
 	spin_lock_irqsave(&prom_lock, flags);
 	switch(prom_vers) {
 	case PROM_V0:
-	case PROM_SUN4:
 		i = (*(romvec->pv_nbgetchar))();
 		break;
 	case PROM_V2:
@@ -63,7 +61,6 @@
 	spin_lock_irqsave(&prom_lock, flags);
 	switch(prom_vers) {
 	case PROM_V0:
-	case PROM_SUN4:
 		i = (*(romvec->pv_nbputchar))(c);
 		break;
 	case PROM_V2:
diff --git a/arch/sparc/prom/init.c b/arch/sparc/prom/init.c
index 729f870..873217c 100644
--- a/arch/sparc/prom/init.c
+++ b/arch/sparc/prom/init.c
@@ -11,12 +11,10 @@
 
 #include <asm/openprom.h>
 #include <asm/oplib.h>
-#include <asm/sun4prom.h>
 
 struct linux_romvec *romvec;
 enum prom_major_version prom_vers;
 unsigned int prom_rev, prom_prev;
-linux_sun4_romvec *sun4_romvec;
 
 /* The root node of the prom device tree. */
 int prom_root_node;
@@ -34,10 +32,6 @@
 
 void __init prom_init(struct linux_romvec *rp)
 {
-#ifdef CONFIG_SUN4
-	extern struct linux_romvec *sun4_prom_init(void);
-	rp = sun4_prom_init();
-#endif
 	romvec = rp;
 
 	switch(romvec->pv_romvers) {
@@ -50,9 +44,6 @@
 	case 3:
 		prom_vers = PROM_V3;
 		break;
-	case 40:
-		prom_vers = PROM_SUN4;
-		break;
 	default:
 		prom_printf("PROMLIB: Bad PROM version %d\n",
 			    romvec->pv_romvers);
@@ -76,11 +67,8 @@
 
 	prom_ranges_init();
 
-#ifndef CONFIG_SUN4
-	/* SUN4 prints this in sun4_prom_init */
 	printk("PROMLIB: Sun Boot Prom Version %d Revision %d\n",
 	       romvec->pv_romvers, prom_rev);
-#endif
 
 	/* Initialization successful. */
 	return;
diff --git a/arch/sparc/prom/memory.c b/arch/sparc/prom/memory.c
index 947f047..fac7899 100644
--- a/arch/sparc/prom/memory.c
+++ b/arch/sparc/prom/memory.c
@@ -10,7 +10,6 @@
 #include <linux/init.h>
 
 #include <asm/openprom.h>
-#include <asm/sun4prom.h>
 #include <asm/oplib.h>
 #include <asm/page.h>
 
@@ -46,15 +45,6 @@
 	return num_ents;
 }
 
-static int __init prom_meminit_sun4(void)
-{
-#ifdef CONFIG_SUN4
-	sp_banks[0].base_addr = 0;
-	sp_banks[0].num_bytes = *(sun4_romvec->memoryavail);
-#endif
-	return 1;
-}
-
 static int sp_banks_cmp(const void *a, const void *b)
 {
 	const struct sparc_phys_banks *x = a, *y = b;
@@ -81,10 +71,6 @@
 		num_ents = prom_meminit_v2();
 		break;
 
-	case PROM_SUN4:
-		num_ents = prom_meminit_sun4();
-		break;
-
 	default:
 		break;
 	}
diff --git a/arch/sparc/prom/ranges.c b/arch/sparc/prom/ranges.c
index f9b7def..64579a3 100644
--- a/arch/sparc/prom/ranges.c
+++ b/arch/sparc/prom/ranges.c
@@ -9,7 +9,6 @@
 #include <asm/openprom.h>
 #include <asm/oplib.h>
 #include <asm/types.h>
-#include <asm/sbus.h>
 #include <asm/system.h>
 
 struct linux_prom_ranges promlib_obio_ranges[PROMREG_MAX];
diff --git a/arch/sparc/prom/sun4prom.c b/arch/sparc/prom/sun4prom.c
deleted file mode 100644
index 00390a2..0000000
--- a/arch/sparc/prom/sun4prom.c
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- * Copyright (C) 1996 The Australian National University.
- * Copyright (C) 1996 Fujitsu Laboratories Limited
- * Copyright (C) 1997 Michael A. Griffith (grif@acm.org)
- * Copyright (C) 1997 Sun Weenie (ko@ko.reno.nv.us)
- * Copyright (C) 1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
- * 
- * This software may be distributed under the terms of the Gnu
- * Public License version 2 or later
- *
- * fake a really simple Sun prom for the SUN4
- */
-
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <asm/oplib.h>
-#include <asm/idprom.h> 
-#include <asm/machines.h> 
-#include <asm/sun4prom.h>
-#include <asm/asi.h>
-#include <asm/contregs.h>
-#include <linux/init.h>
-
-static struct linux_romvec sun4romvec;
-static struct idprom sun4_idprom;
-
-struct property {
-	char *name;
-	char *value;
-	int length;
-};
-
-struct node {
-	int level;
-	struct property *properties;
-};
-
-struct property null_properties = { NULL, NULL, -1 };
-
-struct property root_properties[] = {
-	{"device_type", "cpu", 4},
-	{"idprom", (char *)&sun4_idprom, sizeof(struct idprom)},
-	{NULL, NULL, -1}
-};
-
-struct node nodes[] = {
-	{ 0, &null_properties }, 
-	{ 0, root_properties },
-	{ -1,&null_properties }
-};
-
-
-static int no_nextnode(int node)
-{
-	if (nodes[node].level == nodes[node+1].level)
-		return node+1;
-	return -1;
-}
-
-static int no_child(int node)
-{
-	if (nodes[node].level == nodes[node+1].level-1)
-		return node+1;
-	return -1;
-}
-
-static struct property *find_property(int node,char *name)
-{
-	struct property *prop = &nodes[node].properties[0];
-	while (prop && prop->name) {
-		if (strcmp(prop->name,name) == 0) return prop;
-		prop++;
-	}
-	return NULL;
-}
-
-static int no_proplen(int node,char *name)
-{
-	struct property *prop = find_property(node,name);
-	if (prop) return prop->length;
-	return -1;
-}
-
-static int no_getprop(int node,char *name,char *value)
-{
-	struct property *prop = find_property(node,name);
-	if (prop) {
-		memcpy(value,prop->value,prop->length);
-		return 1;
-	}
-	return -1;
-}
-
-static int no_setprop(int node,char *name,char *value,int len)
-{
-	return -1;
-}
-
-static char *no_nextprop(int node,char *name)
-{
-	struct property *prop = find_property(node,name);
-	if (prop) return prop[1].name;
-	return NULL;
-}
-
-static struct linux_nodeops sun4_nodeops = {
-	no_nextnode,
-	no_child,
-	no_proplen,
-	no_getprop,
-	no_setprop,
-	no_nextprop
-};
-	
-static int synch_hook;
-
-struct linux_romvec * __init sun4_prom_init(void)
-{
-	int i;
-	unsigned char x;
-	char *p;
-                                
-	p = (char *)&sun4_idprom;
-	for (i = 0; i < sizeof(sun4_idprom); i++) {
-		__asm__ __volatile__ ("lduba [%1] %2, %0" : "=r" (x) :
-				      "r" (AC_IDPROM + i), "i" (ASI_CONTROL));
-		*p++ = x;
-	}
-
-	memset(&sun4romvec,0,sizeof(sun4romvec));
-
-	sun4_romvec = (linux_sun4_romvec *) SUN4_PROM_VECTOR;
-
-	sun4romvec.pv_romvers = 40;
-	sun4romvec.pv_nodeops = &sun4_nodeops;
-	sun4romvec.pv_reboot = sun4_romvec->reboot;
-	sun4romvec.pv_abort = sun4_romvec->abortentry;
-	sun4romvec.pv_halt = sun4_romvec->exittomon;
-	sun4romvec.pv_synchook = (void (**)(void))&synch_hook;
-	sun4romvec.pv_setctxt = sun4_romvec->setcxsegmap;
-	sun4romvec.pv_v0bootargs = sun4_romvec->bootParam;
-	sun4romvec.pv_nbgetchar = sun4_romvec->mayget;
-	sun4romvec.pv_nbputchar = sun4_romvec->mayput;
-	sun4romvec.pv_stdin = sun4_romvec->insource;
-	sun4romvec.pv_stdout = sun4_romvec->outsink;
-	
-	/*
-	 * We turn on the LEDs to let folks without monitors or
-	 * terminals know we booted.   Nothing too fancy now.  They
-	 * are all on, except for LED 5, which blinks.   When we
-	 * have more time, we can teach the penguin to say "By your
-	 * command" or "Activating turbo boost, Michael". :-)
-	 */
-	sun4_romvec->setLEDs(NULL);
-	
-	printk("PROMLIB: Old Sun4 boot PROM monitor %s, romvec version %d\n",
-		sun4_romvec->monid,
-		sun4_romvec->romvecversion);
-
-	return &sun4romvec;
-}
diff --git a/arch/sparc64/Kconfig b/arch/sparc64/Kconfig
index 36b4b7a..5446e2a 100644
--- a/arch/sparc64/Kconfig
+++ b/arch/sparc64/Kconfig
@@ -18,6 +18,13 @@
 	select HAVE_ARCH_KGDB
 	select USE_GENERIC_SMP_HELPERS if SMP
 	select HAVE_ARCH_TRACEHOOK
+	select ARCH_WANT_OPTIONAL_GPIOLIB
+	select RTC_CLASS
+	select RTC_DRV_M48T59
+	select RTC_DRV_CMOS
+	select RTC_DRV_BQ4802
+	select RTC_DRV_SUN4V
+	select RTC_DRV_STARFIRE
 
 config GENERIC_TIME
 	bool
@@ -31,6 +38,11 @@
 	bool
 	default y
 
+config GENERIC_GPIO
+	bool
+	help
+	  Generic GPIO API support
+
 config 64BIT
 	def_bool y
 
@@ -185,6 +197,17 @@
 
 	  If in doubt, say N.
 
+config US3_MC
+	tristate "UltraSPARC-III Memory Controller driver"
+	default y
+	help
+	  This adds a driver for the UltraSPARC-III memory controller.
+	  Loading this driver allows exact mnemonic strings to be
+	  printed in the event of a memory error, so that the faulty DIMM
+	  on the motherboard can be matched to the error.
+
+	  If in doubt, say Y, as this information can be very useful.
+
 # Global things across all Sun machines.
 config GENERIC_LOCKBREAK
 	bool
diff --git a/arch/sparc64/Makefile b/arch/sparc64/Makefile
index b785a39..c7214ab 100644
--- a/arch/sparc64/Makefile
+++ b/arch/sparc64/Makefile
@@ -7,7 +7,7 @@
 # Copyright (C) 1998 Jakub Jelinek (jj@ultra.linux.cz)
 #
 
-CHECKFLAGS	+= -D__sparc__ -D__sparc_v9__ -m64
+CHECKFLAGS	+= -D__sparc__ -D__sparc_v9__ -D__arch64__ -m64
 
 # Undefine sparc when processing vmlinux.lds - it is used
 # And teach CPP we are doing 64 bit builds (for this case)
diff --git a/arch/sparc64/kernel/Makefile b/arch/sparc64/kernel/Makefile
index 418b578..c0b8009 100644
--- a/arch/sparc64/kernel/Makefile
+++ b/arch/sparc64/kernel/Makefile
@@ -7,16 +7,16 @@
 
 extra-y		:= head.o init_task.o vmlinux.lds
 
-obj-y		:= process.o setup.o cpu.o idprom.o \
+obj-y		:= process.o setup.o cpu.o idprom.o reboot.o \
 		   traps.o auxio.o una_asm.o sysfs.o iommu.o \
 		   irq.o ptrace.o time.o sys_sparc.o signal.o \
-		   unaligned.o central.o pci.o starfire.o \
-		   power.o sbus.o sparc64_ksyms.o chmc.o \
+		   unaligned.o central.o starfire.o \
+		   power.o sbus.o sparc64_ksyms.o ebus.o \
 		   visemul.o prom.o of_device.o hvapi.o sstate.o mdesc.o
 
 obj-$(CONFIG_DYNAMIC_FTRACE) += ftrace.o
 obj-$(CONFIG_STACKTRACE) += stacktrace.o
-obj-$(CONFIG_PCI)	 += ebus.o pci_common.o \
+obj-$(CONFIG_PCI)	 += pci.o pci_common.o psycho_common.o \
 			    pci_psycho.o pci_sabre.o pci_schizo.o \
 			    pci_sun4v.o pci_sun4v_asm.o pci_fire.o
 obj-$(CONFIG_PCI_MSI)	+= pci_msi.o
@@ -25,6 +25,7 @@
 obj-$(CONFIG_MODULES) += module.o
 obj-$(CONFIG_US3_FREQ) += us3_cpufreq.o
 obj-$(CONFIG_US2E_FREQ) += us2e_cpufreq.o
+obj-$(CONFIG_US3_MC) += chmc.o
 obj-$(CONFIG_KPROBES) += kprobes.o
 obj-$(CONFIG_SUN_LDOMS) += ldc.o vio.o viohs.o ds.o
 obj-$(CONFIG_AUDIT) += audit.o
diff --git a/arch/sparc64/kernel/auxio.c b/arch/sparc64/kernel/auxio.c
index dd5c7bf..858beda 100644
--- a/arch/sparc64/kernel/auxio.c
+++ b/arch/sparc64/kernel/auxio.c
@@ -109,7 +109,7 @@
 	}
 }
 
-static struct of_device_id auxio_match[] = {
+static struct of_device_id __initdata auxio_match[] = {
 	{
 		.name = "auxio",
 	},
diff --git a/arch/sparc64/kernel/central.c b/arch/sparc64/kernel/central.c
index f2e87d0..05f1c91 100644
--- a/arch/sparc64/kernel/central.c
+++ b/arch/sparc64/kernel/central.c
@@ -1,461 +1,268 @@
 /* central.c: Central FHC driver for Sunfire/Starfire/Wildfire.
  *
- * Copyright (C) 1997, 1999 David S. Miller (davem@davemloft.net)
+ * Copyright (C) 1997, 1999, 2008 David S. Miller (davem@davemloft.net)
  */
 
 #include <linux/kernel.h>
 #include <linux/types.h>
 #include <linux/string.h>
-#include <linux/timer.h>
-#include <linux/sched.h>
-#include <linux/delay.h>
 #include <linux/init.h>
-#include <linux/bootmem.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
 
-#include <asm/page.h>
 #include <asm/fhc.h>
-#include <asm/starfire.h>
+#include <asm/upa.h>
 
-static struct linux_central *central_bus = NULL;
-static struct linux_fhc *fhc_list = NULL;
+struct clock_board {
+	void __iomem		*clock_freq_regs;
+	void __iomem		*clock_regs;
+	void __iomem		*clock_ver_reg;
+	int			num_slots;
+	struct resource		leds_resource;
+	struct platform_device	leds_pdev;
+};
 
-#define IS_CENTRAL_FHC(__fhc)	((__fhc) == central_bus->child)
+struct fhc {
+	void __iomem		*pregs;
+	bool			central;
+	bool			jtag_master;
+	int			board_num;
+	struct resource		leds_resource;
+	struct platform_device	leds_pdev;
+};
 
-static void central_probe_failure(int line)
+static int __devinit clock_board_calc_nslots(struct clock_board *p)
 {
-	prom_printf("CENTRAL: Critical device probe failure at central.c:%d\n",
-		    line);
-	prom_halt();
-}
+	u8 reg = upa_readb(p->clock_regs + CLOCK_STAT1) & 0xc0;
 
-static void central_ranges_init(struct linux_central *central)
-{
-	struct device_node *dp = central->prom_node;
-	const void *pval;
-	int len;
-	
-	central->num_central_ranges = 0;
-	pval = of_get_property(dp, "ranges", &len);
-	if (pval) {
-		memcpy(central->central_ranges, pval, len);
-		central->num_central_ranges =
-			(len / sizeof(struct linux_prom_ranges));
-	}
-}
-
-static void fhc_ranges_init(struct linux_fhc *fhc)
-{
-	struct device_node *dp = fhc->prom_node;
-	const void *pval;
-	int len;
-	
-	fhc->num_fhc_ranges = 0;
-	pval = of_get_property(dp, "ranges", &len);
-	if (pval) {
-		memcpy(fhc->fhc_ranges, pval, len);
-		fhc->num_fhc_ranges =
-			(len / sizeof(struct linux_prom_ranges));
-	}
-}
-
-/* Range application routines are exported to various drivers,
- * so do not __init this.
- */
-static void adjust_regs(struct linux_prom_registers *regp, int nregs,
-			struct linux_prom_ranges *rangep, int nranges)
-{
-	int regc, rngc;
-
-	for (regc = 0; regc < nregs; regc++) {
-		for (rngc = 0; rngc < nranges; rngc++)
-			if (regp[regc].which_io == rangep[rngc].ot_child_space)
-				break; /* Fount it */
-		if (rngc == nranges) /* oops */
-			central_probe_failure(__LINE__);
-		regp[regc].which_io = rangep[rngc].ot_parent_space;
-		regp[regc].phys_addr -= rangep[rngc].ot_child_base;
-		regp[regc].phys_addr += rangep[rngc].ot_parent_base;
-	}
-}
-
-/* Apply probed fhc ranges to registers passed, if no ranges return. */
-static void apply_fhc_ranges(struct linux_fhc *fhc,
-			     struct linux_prom_registers *regs,
-			     int nregs)
-{
-	if (fhc->num_fhc_ranges)
-		adjust_regs(regs, nregs, fhc->fhc_ranges,
-			    fhc->num_fhc_ranges);
-}
-
-/* Apply probed central ranges to registers passed, if no ranges return. */
-static void apply_central_ranges(struct linux_central *central,
-				 struct linux_prom_registers *regs, int nregs)
-{
-	if (central->num_central_ranges)
-		adjust_regs(regs, nregs, central->central_ranges,
-			    central->num_central_ranges);
-}
-
-static void * __init central_alloc_bootmem(unsigned long size)
-{
-	void *ret;
-
-	ret = __alloc_bootmem(size, SMP_CACHE_BYTES, 0UL);
-	if (ret != NULL)
-		memset(ret, 0, size);
-
-	return ret;
-}
-
-static unsigned long prom_reg_to_paddr(struct linux_prom_registers *r)
-{
-	unsigned long ret = ((unsigned long) r->which_io) << 32;
-
-	return ret | (unsigned long) r->phys_addr;
-}
-
-static void __init probe_other_fhcs(void)
-{
-	struct device_node *dp;
-	const struct linux_prom64_registers *fpregs;
-
-	for_each_node_by_name(dp, "fhc") {
-		struct linux_fhc *fhc;
-		int board;
-		u32 tmp;
-
-		if (dp->parent &&
-		    dp->parent->parent != NULL)
-			continue;
-
-		fhc = (struct linux_fhc *)
-			central_alloc_bootmem(sizeof(struct linux_fhc));
-		if (fhc == NULL)
-			central_probe_failure(__LINE__);
-
-		/* Link it into the FHC chain. */
-		fhc->next = fhc_list;
-		fhc_list = fhc;
-
-		/* Toplevel FHCs have no parent. */
-		fhc->parent = NULL;
-		
-		fhc->prom_node = dp;
-		fhc_ranges_init(fhc);
-
-		/* Non-central FHC's have 64-bit OBP format registers. */
-		fpregs = of_get_property(dp, "reg", NULL);
-		if (!fpregs)
-			central_probe_failure(__LINE__);
-
-		/* Only central FHC needs special ranges applied. */
-		fhc->fhc_regs.pregs = fpregs[0].phys_addr;
-		fhc->fhc_regs.ireg = fpregs[1].phys_addr;
-		fhc->fhc_regs.ffregs = fpregs[2].phys_addr;
-		fhc->fhc_regs.sregs = fpregs[3].phys_addr;
-		fhc->fhc_regs.uregs = fpregs[4].phys_addr;
-		fhc->fhc_regs.tregs = fpregs[5].phys_addr;
-
-		board = of_getintprop_default(dp, "board#", -1);
-		fhc->board = board;
-
-		tmp = upa_readl(fhc->fhc_regs.pregs + FHC_PREGS_JCTRL);
-		if ((tmp & FHC_JTAG_CTRL_MENAB) != 0)
-			fhc->jtag_master = 1;
-		else
-			fhc->jtag_master = 0;
-
-		tmp = upa_readl(fhc->fhc_regs.pregs + FHC_PREGS_ID);
-		printk("FHC(board %d): Version[%x] PartID[%x] Manuf[%x] %s\n",
-		       board,
-		       (tmp & FHC_ID_VERS) >> 28,
-		       (tmp & FHC_ID_PARTID) >> 12,
-		       (tmp & FHC_ID_MANUF) >> 1,
-		       (fhc->jtag_master ? "(JTAG Master)" : ""));
-		
-		/* This bit must be set in all non-central FHC's in
-		 * the system.  When it is clear, this identifies
-		 * the central board.
-		 */
-		tmp = upa_readl(fhc->fhc_regs.pregs + FHC_PREGS_CTRL);
-		tmp |= FHC_CONTROL_IXIST;
-		upa_writel(tmp, fhc->fhc_regs.pregs + FHC_PREGS_CTRL);
-	}
-}
-
-static void probe_clock_board(struct linux_central *central,
-			      struct linux_fhc *fhc,
-			      struct device_node *fp)
-{
-	struct device_node *dp;
-	struct linux_prom_registers cregs[3];
-	const struct linux_prom_registers *pr;
-	int nslots, tmp, nregs;
-
-	dp = fp->child;
-	while (dp) {
-		if (!strcmp(dp->name, "clock-board"))
-			break;
-		dp = dp->sibling;
-	}
-	if (!dp)
-		central_probe_failure(__LINE__);
-
-	pr = of_get_property(dp, "reg", &nregs);
-	if (!pr)
-		central_probe_failure(__LINE__);
-
-	memcpy(cregs, pr, nregs);
-	nregs /= sizeof(struct linux_prom_registers);
-
-	apply_fhc_ranges(fhc, &cregs[0], nregs);
-	apply_central_ranges(central, &cregs[0], nregs);
-	central->cfreg = prom_reg_to_paddr(&cregs[0]);
-	central->clkregs = prom_reg_to_paddr(&cregs[1]);
-
-	if (nregs == 2)
-		central->clkver = 0UL;
-	else
-		central->clkver = prom_reg_to_paddr(&cregs[2]);
-
-	tmp = upa_readb(central->clkregs + CLOCK_STAT1);
-	tmp &= 0xc0;
-	switch(tmp) {
+	switch (reg) {
 	case 0x40:
-		nslots = 16;
-		break;
+		return 16;
+
 	case 0xc0:
-		nslots = 8;
-		break;
+		return 8;
+
 	case 0x80:
-		if (central->clkver != 0UL &&
-		   upa_readb(central->clkver) != 0) {
-			if ((upa_readb(central->clkver) & 0x80) != 0)
-				nslots = 4;
+		reg = 0;
+		if (p->clock_ver_reg)
+			reg = upa_readb(p->clock_ver_reg);
+		if (reg) {
+			if (reg & 0x80)
+				return 4;
 			else
-				nslots = 5;
-			break;
+				return 5;
 		}
+		/* Fallthrough */
 	default:
-		nslots = 4;
-		break;
-	};
-	central->slots = nslots;
-	printk("CENTRAL: Detected %d slot Enterprise system. cfreg[%02x] cver[%02x]\n",
-	       central->slots, upa_readb(central->cfreg),
-	       (central->clkver ? upa_readb(central->clkver) : 0x00));
+		return 4;
+	}
 }
 
-static void ZAP(unsigned long iclr, unsigned long imap)
+static int __devinit clock_board_probe(struct of_device *op,
+				       const struct of_device_id *match)
 {
-	u32 imap_tmp;
+	struct clock_board *p = kzalloc(sizeof(*p), GFP_KERNEL);
+	int err = -ENOMEM;
 
-	upa_writel(0, iclr);
-	upa_readl(iclr);
-	imap_tmp = upa_readl(imap);
-	imap_tmp &= ~(0x80000000);
-	upa_writel(imap_tmp, imap);
-	upa_readl(imap);
-}
-
-static void init_all_fhc_hw(void)
-{
-	struct linux_fhc *fhc;
-
-	for (fhc = fhc_list; fhc != NULL; fhc = fhc->next) {
-		u32 tmp;
-
-		/* Clear all of the interrupt mapping registers
-		 * just in case OBP left them in a foul state.
-		 */
-		ZAP(fhc->fhc_regs.ffregs + FHC_FFREGS_ICLR,
-		    fhc->fhc_regs.ffregs + FHC_FFREGS_IMAP);
-		ZAP(fhc->fhc_regs.sregs + FHC_SREGS_ICLR,
-		    fhc->fhc_regs.sregs + FHC_SREGS_IMAP);
-		ZAP(fhc->fhc_regs.uregs + FHC_UREGS_ICLR,
-		    fhc->fhc_regs.uregs + FHC_UREGS_IMAP);
-		ZAP(fhc->fhc_regs.tregs + FHC_TREGS_ICLR,
-		    fhc->fhc_regs.tregs + FHC_TREGS_IMAP);
-
-		/* Setup FHC control register. */
-		tmp = upa_readl(fhc->fhc_regs.pregs + FHC_PREGS_CTRL);
-
-		/* All non-central boards have this bit set. */
-		if (! IS_CENTRAL_FHC(fhc))
-			tmp |= FHC_CONTROL_IXIST;
-
-		/* For all FHCs, clear the firmware synchronization
-		 * line and both low power mode enables.
-		 */
-		tmp &= ~(FHC_CONTROL_AOFF | FHC_CONTROL_BOFF |
-			 FHC_CONTROL_SLINE);
-
-		upa_writel(tmp, fhc->fhc_regs.pregs + FHC_PREGS_CTRL);
-		upa_readl(fhc->fhc_regs.pregs + FHC_PREGS_CTRL);
+	if (!p) {
+		printk(KERN_ERR "clock_board: Cannot allocate struct clock_board\n");
+		goto out;
 	}
 
-}
-
-void __init central_probe(void)
-{
-	struct linux_prom_registers fpregs[6];
-	const struct linux_prom_registers *pr;
-	struct linux_fhc *fhc;
-	struct device_node *dp, *fp;
-	int err;
-
-	dp = of_find_node_by_name(NULL, "central");
-	if (!dp) {
-		if (this_is_starfire)
-			starfire_cpu_setup();
-		return;
+	p->clock_freq_regs = of_ioremap(&op->resource[0], 0,
+					resource_size(&op->resource[0]),
+					"clock_board_freq");
+	if (!p->clock_freq_regs) {
+		printk(KERN_ERR "clock_board: Cannot map clock_freq_regs\n");
+		goto out_free;
 	}
 
-	/* Ok we got one, grab some memory for software state. */
-	central_bus = (struct linux_central *)
-		central_alloc_bootmem(sizeof(struct linux_central));
-	if (central_bus == NULL)
-		central_probe_failure(__LINE__);
-
-	fhc = (struct linux_fhc *)
-		central_alloc_bootmem(sizeof(struct linux_fhc));
-	if (fhc == NULL)
-		central_probe_failure(__LINE__);
-
-	/* First init central. */
-	central_bus->child = fhc;
-	central_bus->prom_node = dp;
-	central_ranges_init(central_bus);
-
-	/* And then central's FHC. */
-	fhc->next = fhc_list;
-	fhc_list = fhc;
-
-	fhc->parent = central_bus;
-	fp = dp->child;
-	while (fp) {
-		if (!strcmp(fp->name, "fhc"))
-			break;
-		fp = fp->sibling;
+	p->clock_regs = of_ioremap(&op->resource[1], 0,
+				   resource_size(&op->resource[1]),
+				   "clock_board_regs");
+	if (!p->clock_regs) {
+		printk(KERN_ERR "clock_board: Cannot map clock_regs\n");
+		goto out_unmap_clock_freq_regs;
 	}
-	if (!fp)
-		central_probe_failure(__LINE__);
 
-	fhc->prom_node = fp;
-	fhc_ranges_init(fhc);
+	if (op->resource[2].flags) {
+		p->clock_ver_reg = of_ioremap(&op->resource[2], 0,
+					      resource_size(&op->resource[2]),
+					      "clock_ver_reg");
+		if (!p->clock_ver_reg) {
+			printk(KERN_ERR "clock_board: Cannot map clock_ver_reg\n");
+			goto out_unmap_clock_regs;
+		}
+	}
 
-	/* Now, map in FHC register set. */
-	pr = of_get_property(fp, "reg", NULL);
-	if (!pr)
-		central_probe_failure(__LINE__);
-	memcpy(fpregs, pr, sizeof(fpregs));
+	p->num_slots = clock_board_calc_nslots(p);
 
-	apply_central_ranges(central_bus, &fpregs[0], 6);
-	
-	fhc->fhc_regs.pregs = prom_reg_to_paddr(&fpregs[0]);
-	fhc->fhc_regs.ireg = prom_reg_to_paddr(&fpregs[1]);
-	fhc->fhc_regs.ffregs = prom_reg_to_paddr(&fpregs[2]);
-	fhc->fhc_regs.sregs = prom_reg_to_paddr(&fpregs[3]);
-	fhc->fhc_regs.uregs = prom_reg_to_paddr(&fpregs[4]);
-	fhc->fhc_regs.tregs = prom_reg_to_paddr(&fpregs[5]);
+	p->leds_resource.start = (unsigned long)
+		(p->clock_regs + CLOCK_CTRL);
+	p->leds_resource.end = p->leds_resource.end;
+	p->leds_resource.name = "leds";
 
-	/* Obtain board number from board status register, Central's
-	 * FHC lacks "board#" property.
-	 */
-	err = upa_readl(fhc->fhc_regs.pregs + FHC_PREGS_BSR);
-	fhc->board = (((err >> 16) & 0x01) |
-		      ((err >> 12) & 0x0e));
+	p->leds_pdev.name = "sunfire-clockboard-leds";
+	p->leds_pdev.resource = &p->leds_resource;
+	p->leds_pdev.num_resources = 1;
+	p->leds_pdev.dev.parent = &op->dev;
 
-	fhc->jtag_master = 0;
+	err = platform_device_register(&p->leds_pdev);
+	if (err) {
+		printk(KERN_ERR "clock_board: Could not register LEDS "
+		       "platform device\n");
+		goto out_unmap_clock_ver_reg;
+	}
 
-	/* Attach the clock board registers for CENTRAL. */
-	probe_clock_board(central_bus, fhc, fp);
+	printk(KERN_INFO "clock_board: Detected %d slot Enterprise system.\n",
+	       p->num_slots);
 
-	err = upa_readl(fhc->fhc_regs.pregs + FHC_PREGS_ID);
-	printk("FHC(board %d): Version[%x] PartID[%x] Manuf[%x] (CENTRAL)\n",
-	       fhc->board,
-	       ((err & FHC_ID_VERS) >> 28),
-	       ((err & FHC_ID_PARTID) >> 12),
-	       ((err & FHC_ID_MANUF) >> 1));
+	err = 0;
+out:
+	return err;
 
-	probe_other_fhcs();
+out_unmap_clock_ver_reg:
+	if (p->clock_ver_reg)
+		of_iounmap(&op->resource[2], p->clock_ver_reg,
+			   resource_size(&op->resource[2]));
 
-	init_all_fhc_hw();
+out_unmap_clock_regs:
+	of_iounmap(&op->resource[1], p->clock_regs,
+		   resource_size(&op->resource[1]));
+
+out_unmap_clock_freq_regs:
+	of_iounmap(&op->resource[0], p->clock_freq_regs,
+		   resource_size(&op->resource[0]));
+
+out_free:
+	kfree(p);
+	goto out;
 }
 
-static inline void fhc_ledblink(struct linux_fhc *fhc, int on)
+static struct of_device_id __initdata clock_board_match[] = {
+	{
+		.name = "clock-board",
+	},
+	{},
+};
+
+static struct of_platform_driver clock_board_driver = {
+	.match_table	= clock_board_match,
+	.probe		= clock_board_probe,
+	.driver		= {
+		.name	= "clock_board",
+	},
+};
+
+static int __devinit fhc_probe(struct of_device *op,
+			       const struct of_device_id *match)
 {
-	u32 tmp;
+	struct fhc *p = kzalloc(sizeof(*p), GFP_KERNEL);
+	int err = -ENOMEM;
+	u32 reg;
 
-	tmp = upa_readl(fhc->fhc_regs.pregs + FHC_PREGS_CTRL);
+	if (!p) {
+		printk(KERN_ERR "fhc: Cannot allocate struct fhc\n");
+		goto out;
+	}
 
-	/* NOTE: reverse logic on this bit */
-	if (on)
-		tmp &= ~(FHC_CONTROL_RLED);
-	else
-		tmp |= FHC_CONTROL_RLED;
-	tmp &= ~(FHC_CONTROL_AOFF | FHC_CONTROL_BOFF | FHC_CONTROL_SLINE);
+	if (!strcmp(op->node->parent->name, "central"))
+		p->central = true;
 
-	upa_writel(tmp, fhc->fhc_regs.pregs + FHC_PREGS_CTRL);
-	upa_readl(fhc->fhc_regs.pregs + FHC_PREGS_CTRL);
+	p->pregs = of_ioremap(&op->resource[0], 0,
+			      resource_size(&op->resource[0]),
+			      "fhc_pregs");
+	if (!p->pregs) {
+		printk(KERN_ERR "fhc: Cannot map pregs\n");
+		goto out_free;
+	}
+
+	if (p->central) {
+		reg = upa_readl(p->pregs + FHC_PREGS_BSR);
+		p->board_num = ((reg >> 16) & 1) | ((reg >> 12) & 0x0e);
+	} else {
+		p->board_num = of_getintprop_default(op->node, "board#", -1);
+		if (p->board_num == -1) {
+			printk(KERN_ERR "fhc: No board# property\n");
+			goto out_unmap_pregs;
+		}
+		if (upa_readl(p->pregs + FHC_PREGS_JCTRL) & FHC_JTAG_CTRL_MENAB)
+			p->jtag_master = true;
+	}
+
+	if (!p->central) {
+		p->leds_resource.start = (unsigned long)
+			(p->pregs + FHC_PREGS_CTRL);
+		p->leds_resource.end = p->leds_resource.end;
+		p->leds_resource.name = "leds";
+
+		p->leds_pdev.name = "sunfire-fhc-leds";
+		p->leds_pdev.resource = &p->leds_resource;
+		p->leds_pdev.num_resources = 1;
+		p->leds_pdev.dev.parent = &op->dev;
+
+		err = platform_device_register(&p->leds_pdev);
+		if (err) {
+			printk(KERN_ERR "fhc: Could not register LEDS "
+			       "platform device\n");
+			goto out_unmap_pregs;
+		}
+	}
+	reg = upa_readl(p->pregs + FHC_PREGS_CTRL);
+
+	if (!p->central)
+		reg |= FHC_CONTROL_IXIST;
+
+	reg &= ~(FHC_CONTROL_AOFF |
+		 FHC_CONTROL_BOFF |
+		 FHC_CONTROL_SLINE);
+
+	upa_writel(reg, p->pregs + FHC_PREGS_CTRL);
+	upa_readl(p->pregs + FHC_PREGS_CTRL);
+
+	reg = upa_readl(p->pregs + FHC_PREGS_ID);
+	printk(KERN_INFO "fhc: Board #%d, Version[%x] PartID[%x] Manuf[%x] %s\n",
+	       p->board_num,
+	       (reg & FHC_ID_VERS) >> 28,
+	       (reg & FHC_ID_PARTID) >> 12,
+	       (reg & FHC_ID_MANUF) >> 1,
+	       (p->jtag_master ?
+		"(JTAG Master)" :
+		(p->central ? "(Central)" : "")));
+
+	err = 0;
+
+out:
+	return err;
+
+out_unmap_pregs:
+	of_iounmap(&op->resource[0], p->pregs, resource_size(&op->resource[0]));
+
+out_free:
+	kfree(p);
+	goto out;
 }
 
-static inline void central_ledblink(struct linux_central *central, int on)
+static struct of_device_id __initdata fhc_match[] = {
+	{
+		.name = "fhc",
+	},
+	{},
+};
+
+static struct of_platform_driver fhc_driver = {
+	.match_table	= fhc_match,
+	.probe		= fhc_probe,
+	.driver		= {
+		.name	= "fhc",
+	},
+};
+
+static int __init sunfire_init(void)
 {
-	u8 tmp;
-
-	tmp = upa_readb(central->clkregs + CLOCK_CTRL);
-
-	/* NOTE: reverse logic on this bit */
-	if (on)
-		tmp &= ~(CLOCK_CTRL_RLED);
-	else
-		tmp |= CLOCK_CTRL_RLED;
-
-	upa_writeb(tmp, central->clkregs + CLOCK_CTRL);
-	upa_readb(central->clkregs + CLOCK_CTRL);
+	(void) of_register_driver(&fhc_driver, &of_platform_bus_type);
+	(void) of_register_driver(&clock_board_driver, &of_platform_bus_type);
+	return 0;
 }
 
-static struct timer_list sftimer;
-static int led_state;
-
-static void sunfire_timer(unsigned long __ignored)
-{
-	struct linux_fhc *fhc;
-
-	central_ledblink(central_bus, led_state);
-	for (fhc = fhc_list; fhc != NULL; fhc = fhc->next)
-		if (! IS_CENTRAL_FHC(fhc))
-			fhc_ledblink(fhc, led_state);
-	led_state = ! led_state;
-	sftimer.expires = jiffies + (HZ >> 1);
-	add_timer(&sftimer);
-}
-
-/* After PCI/SBUS busses have been probed, this is called to perform
- * final initialization of all FireHose Controllers in the system.
- */
-void firetruck_init(void)
-{
-	struct linux_central *central = central_bus;
-	u8 ctrl;
-
-	/* No central bus, nothing to do. */
-	if (central == NULL)
-		return;
-
-	/* OBP leaves it on, turn it off so clock board timer LED
-	 * is in sync with FHC ones.
-	 */
-	ctrl = upa_readb(central->clkregs + CLOCK_CTRL);
-	ctrl &= ~(CLOCK_CTRL_RLED);
-	upa_writeb(ctrl, central->clkregs + CLOCK_CTRL);
-
-	led_state = 0;
-	init_timer(&sftimer);
-	sftimer.data = 0;
-	sftimer.function = &sunfire_timer;
-	sftimer.expires = jiffies + (HZ >> 1);
-	add_timer(&sftimer);
-}
+subsys_initcall(sunfire_init);
diff --git a/arch/sparc64/kernel/chmc.c b/arch/sparc64/kernel/chmc.c
index 6d4f02e..3b9f4d6 100644
--- a/arch/sparc64/kernel/chmc.c
+++ b/arch/sparc64/kernel/chmc.c
@@ -1,6 +1,6 @@
-/* memctrlr.c: Driver for UltraSPARC-III memory controller.
+/* chmc.c: Driver for UltraSPARC-III memory controller.
  *
- * Copyright (C) 2001, 2007 David S. Miller (davem@davemloft.net)
+ * Copyright (C) 2001, 2007, 2008 David S. Miller (davem@davemloft.net)
  */
 
 #include <linux/module.h>
@@ -13,45 +13,64 @@
 #include <linux/smp.h>
 #include <linux/errno.h>
 #include <linux/init.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 #include <asm/spitfire.h>
 #include <asm/chmctrl.h>
 #include <asm/cpudata.h>
 #include <asm/oplib.h>
 #include <asm/prom.h>
+#include <asm/head.h>
 #include <asm/io.h>
+#include <asm/memctrl.h>
+
+#define DRV_MODULE_NAME		"chmc"
+#define PFX DRV_MODULE_NAME	": "
+#define DRV_MODULE_VERSION	"0.2"
+
+MODULE_AUTHOR("David S. Miller (davem@davemloft.net)");
+MODULE_DESCRIPTION("UltraSPARC-III memory controller driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_MODULE_VERSION);
+
+static int mc_type;
+#define MC_TYPE_SAFARI		1
+#define MC_TYPE_JBUS		2
+
+static dimm_printer_t us3mc_dimm_printer;
 
 #define CHMCTRL_NDGRPS	2
 #define CHMCTRL_NDIMMS	4
 
-#define DIMMS_PER_MC	(CHMCTRL_NDGRPS * CHMCTRL_NDIMMS)
+#define CHMC_DIMMS_PER_MC	(CHMCTRL_NDGRPS * CHMCTRL_NDIMMS)
 
 /* OBP memory-layout property format. */
-struct obp_map {
+struct chmc_obp_map {
 	unsigned char	dimm_map[144];
 	unsigned char	pin_map[576];
 };
 
 #define DIMM_LABEL_SZ	8
 
-struct obp_mem_layout {
+struct chmc_obp_mem_layout {
 	/* One max 8-byte string label per DIMM.  Usually
 	 * this matches the label on the motherboard where
 	 * that DIMM resides.
 	 */
-	char		dimm_labels[DIMMS_PER_MC][DIMM_LABEL_SZ];
+	char			dimm_labels[CHMC_DIMMS_PER_MC][DIMM_LABEL_SZ];
 
 	/* If symmetric use map[0], else it is
 	 * asymmetric and map[1] should be used.
 	 */
-	char		symmetric;
+	char			symmetric;
 
-	struct obp_map	map[2];
+	struct chmc_obp_map	map[2];
 };
 
 #define CHMCTRL_NBANKS	4
 
-struct bank_info {
-	struct mctrl_info	*mp;
+struct chmc_bank_info {
+	struct chmc		*p;
 	int			bank_id;
 
 	u64			raw_reg;
@@ -65,28 +84,406 @@
 	unsigned long		size;
 };
 
-struct mctrl_info {
-	struct list_head	list;
-	int			portid;
+struct chmc {
+	struct list_head		list;
+	int				portid;
 
-	struct obp_mem_layout	layout_prop;
-	int			layout_size;
+	struct chmc_obp_mem_layout	layout_prop;
+	int				layout_size;
 
-	void __iomem		*regs;
+	void __iomem			*regs;
 
-	u64			timing_control1;
-	u64			timing_control2;
-	u64			timing_control3;
-	u64			timing_control4;
-	u64			memaddr_control;
+	u64				timing_control1;
+	u64				timing_control2;
+	u64				timing_control3;
+	u64				timing_control4;
+	u64				memaddr_control;
 
-	struct bank_info	logical_banks[CHMCTRL_NBANKS];
+	struct chmc_bank_info		logical_banks[CHMCTRL_NBANKS];
 };
 
+#define JBUSMC_REGS_SIZE		8
+
+#define JB_MC_REG1_DIMM2_BANK3		0x8000000000000000UL
+#define JB_MC_REG1_DIMM1_BANK1		0x4000000000000000UL
+#define JB_MC_REG1_DIMM2_BANK2		0x2000000000000000UL
+#define JB_MC_REG1_DIMM1_BANK0		0x1000000000000000UL
+#define JB_MC_REG1_XOR			0x0000010000000000UL
+#define JB_MC_REG1_ADDR_GEN_2		0x000000e000000000UL
+#define JB_MC_REG1_ADDR_GEN_2_SHIFT	37
+#define JB_MC_REG1_ADDR_GEN_1		0x0000001c00000000UL
+#define JB_MC_REG1_ADDR_GEN_1_SHIFT	34
+#define JB_MC_REG1_INTERLEAVE		0x0000000001800000UL
+#define JB_MC_REG1_INTERLEAVE_SHIFT	23
+#define JB_MC_REG1_DIMM2_PTYPE		0x0000000000200000UL
+#define JB_MC_REG1_DIMM2_PTYPE_SHIFT	21
+#define JB_MC_REG1_DIMM1_PTYPE		0x0000000000100000UL
+#define JB_MC_REG1_DIMM1_PTYPE_SHIFT	20
+
+#define PART_TYPE_X8		0
+#define PART_TYPE_X4		1
+
+#define INTERLEAVE_NONE		0
+#define INTERLEAVE_SAME		1
+#define INTERLEAVE_INTERNAL	2
+#define INTERLEAVE_BOTH		3
+
+#define ADDR_GEN_128MB		0
+#define ADDR_GEN_256MB		1
+#define ADDR_GEN_512MB		2
+#define ADDR_GEN_1GB		3
+
+#define JB_NUM_DIMM_GROUPS	2
+#define JB_NUM_DIMMS_PER_GROUP	2
+#define JB_NUM_DIMMS		(JB_NUM_DIMM_GROUPS * JB_NUM_DIMMS_PER_GROUP)
+
+struct jbusmc_obp_map {
+	unsigned char	dimm_map[18];
+	unsigned char	pin_map[144];
+};
+
+struct jbusmc_obp_mem_layout {
+	/* One max 8-byte string label per DIMM.  Usually
+	 * this matches the label on the motherboard where
+	 * that DIMM resides.
+	 */
+	char		dimm_labels[JB_NUM_DIMMS][DIMM_LABEL_SZ];
+
+	/* If symmetric use map[0], else it is
+	 * asymmetric and map[1] should be used.
+	 */
+	char			symmetric;
+
+	struct jbusmc_obp_map	map;
+
+	char			_pad;
+};
+
+struct jbusmc_dimm_group {
+	struct jbusmc			*controller;
+	int				index;
+	u64				base_addr;
+	u64				size;
+};
+
+struct jbusmc {
+	void __iomem			*regs;
+	u64				mc_reg_1;
+	u32				portid;
+	struct jbusmc_obp_mem_layout	layout;
+	int				layout_len;
+	int				num_dimm_groups;
+	struct jbusmc_dimm_group	dimm_groups[JB_NUM_DIMM_GROUPS];
+	struct list_head		list;
+};
+
+static DEFINE_SPINLOCK(mctrl_list_lock);
 static LIST_HEAD(mctrl_list);
 
+static void mc_list_add(struct list_head *list)
+{
+	spin_lock(&mctrl_list_lock);
+	list_add(list, &mctrl_list);
+	spin_unlock(&mctrl_list_lock);
+}
+
+static void mc_list_del(struct list_head *list)
+{
+	spin_lock(&mctrl_list_lock);
+	list_del_init(list);
+	spin_unlock(&mctrl_list_lock);
+}
+
+#define SYNDROME_MIN	-1
+#define SYNDROME_MAX	144
+
+/* Covert syndrome code into the way the bits are positioned
+ * on the bus.
+ */
+static int syndrome_to_qword_code(int syndrome_code)
+{
+	if (syndrome_code < 128)
+		syndrome_code += 16;
+	else if (syndrome_code < 128 + 9)
+		syndrome_code -= (128 - 7);
+	else if (syndrome_code < (128 + 9 + 3))
+		syndrome_code -= (128 + 9 - 4);
+	else
+		syndrome_code -= (128 + 9 + 3);
+	return syndrome_code;
+}
+
+/* All this magic has to do with how a cache line comes over the wire
+ * on Safari and JBUS.  A 64-bit line comes over in 1 or more quadword
+ * cycles, each of which transmit ECC/MTAG info as well as the actual
+ * data.
+ */
+#define L2_LINE_SIZE		64
+#define L2_LINE_ADDR_MSK	(L2_LINE_SIZE - 1)
+#define QW_PER_LINE		4
+#define QW_BYTES		(L2_LINE_SIZE / QW_PER_LINE)
+#define QW_BITS			144
+#define SAFARI_LAST_BIT		(576 - 1)
+#define JBUS_LAST_BIT		(144 - 1)
+
+static void get_pin_and_dimm_str(int syndrome_code, unsigned long paddr,
+				 int *pin_p, char **dimm_str_p, void *_prop,
+				 int base_dimm_offset)
+{
+	int qword_code = syndrome_to_qword_code(syndrome_code);
+	int cache_line_offset;
+	int offset_inverse;
+	int dimm_map_index;
+	int map_val;
+
+	if (mc_type == MC_TYPE_JBUS) {
+		struct jbusmc_obp_mem_layout *p = _prop;
+
+		/* JBUS */
+		cache_line_offset = qword_code;
+		offset_inverse = (JBUS_LAST_BIT - cache_line_offset);
+		dimm_map_index = offset_inverse / 8;
+		map_val = p->map.dimm_map[dimm_map_index];
+		map_val = ((map_val >> ((7 - (offset_inverse & 7)))) & 1);
+		*dimm_str_p = p->dimm_labels[base_dimm_offset + map_val];
+		*pin_p = p->map.pin_map[cache_line_offset];
+	} else {
+		struct chmc_obp_mem_layout *p = _prop;
+		struct chmc_obp_map *mp;
+		int qword;
+
+		/* Safari */
+		if (p->symmetric)
+			mp = &p->map[0];
+		else
+			mp = &p->map[1];
+
+		qword = (paddr & L2_LINE_ADDR_MSK) / QW_BYTES;
+		cache_line_offset = ((3 - qword) * QW_BITS) + qword_code;
+		offset_inverse = (SAFARI_LAST_BIT - cache_line_offset);
+		dimm_map_index = offset_inverse >> 2;
+		map_val = mp->dimm_map[dimm_map_index];
+		map_val = ((map_val >> ((3 - (offset_inverse & 3)) << 1)) & 0x3);
+		*dimm_str_p = p->dimm_labels[base_dimm_offset + map_val];
+		*pin_p = mp->pin_map[cache_line_offset];
+	}
+}
+
+static struct jbusmc_dimm_group *jbusmc_find_dimm_group(unsigned long phys_addr)
+{
+	struct jbusmc *p;
+
+	list_for_each_entry(p, &mctrl_list, list) {
+		int i;
+
+		for (i = 0; i < p->num_dimm_groups; i++) {
+			struct jbusmc_dimm_group *dp = &p->dimm_groups[i];
+
+			if (phys_addr < dp->base_addr ||
+			    (dp->base_addr + dp->size) <= phys_addr)
+				continue;
+
+			return dp;
+		}
+	}
+	return NULL;
+}
+
+static int jbusmc_print_dimm(int syndrome_code,
+			     unsigned long phys_addr,
+			     char *buf, int buflen)
+{
+	struct jbusmc_obp_mem_layout *prop;
+	struct jbusmc_dimm_group *dp;
+	struct jbusmc *p;
+	int first_dimm;
+
+	dp = jbusmc_find_dimm_group(phys_addr);
+	if (dp == NULL ||
+	    syndrome_code < SYNDROME_MIN ||
+	    syndrome_code > SYNDROME_MAX) {
+		buf[0] = '?';
+		buf[1] = '?';
+		buf[2] = '?';
+		buf[3] = '\0';
+	}
+	p = dp->controller;
+	prop = &p->layout;
+
+	first_dimm = dp->index * JB_NUM_DIMMS_PER_GROUP;
+
+	if (syndrome_code != SYNDROME_MIN) {
+		char *dimm_str;
+		int pin;
+
+		get_pin_and_dimm_str(syndrome_code, phys_addr, &pin,
+				     &dimm_str, prop, first_dimm);
+		sprintf(buf, "%s, pin %3d", dimm_str, pin);
+	} else {
+		int dimm;
+
+		/* Multi-bit error, we just dump out all the
+		 * dimm labels associated with this dimm group.
+		 */
+		for (dimm = 0; dimm < JB_NUM_DIMMS_PER_GROUP; dimm++) {
+			sprintf(buf, "%s ",
+				prop->dimm_labels[first_dimm + dimm]);
+			buf += strlen(buf);
+		}
+	}
+
+	return 0;
+}
+
+static u64 __devinit jbusmc_dimm_group_size(u64 base,
+					    const struct linux_prom64_registers *mem_regs,
+					    int num_mem_regs)
+{
+	u64 max = base + (8UL * 1024 * 1024 * 1024);
+	u64 max_seen = base;
+	int i;
+
+	for (i = 0; i < num_mem_regs; i++) {
+		const struct linux_prom64_registers *ent;
+		u64 this_base;
+		u64 this_end;
+
+		ent = &mem_regs[i];
+		this_base = ent->phys_addr;
+		this_end = this_base + ent->reg_size;
+		if (base < this_base || base >= this_end)
+			continue;
+		if (this_end > max)
+			this_end = max;
+		if (this_end > max_seen)
+			max_seen = this_end;
+	}
+
+	return max_seen - base;
+}
+
+static void __devinit jbusmc_construct_one_dimm_group(struct jbusmc *p,
+						      unsigned long index,
+						      const struct linux_prom64_registers *mem_regs,
+						      int num_mem_regs)
+{
+	struct jbusmc_dimm_group *dp = &p->dimm_groups[index];
+
+	dp->controller = p;
+	dp->index = index;
+
+	dp->base_addr  = (p->portid * (64UL * 1024 * 1024 * 1024));
+	dp->base_addr += (index * (8UL * 1024 * 1024 * 1024));
+	dp->size = jbusmc_dimm_group_size(dp->base_addr, mem_regs, num_mem_regs);
+}
+
+static void __devinit jbusmc_construct_dimm_groups(struct jbusmc *p,
+						   const struct linux_prom64_registers *mem_regs,
+						   int num_mem_regs)
+{
+	if (p->mc_reg_1 & JB_MC_REG1_DIMM1_BANK0) {
+		jbusmc_construct_one_dimm_group(p, 0, mem_regs, num_mem_regs);
+		p->num_dimm_groups++;
+	}
+	if (p->mc_reg_1 & JB_MC_REG1_DIMM2_BANK2) {
+		jbusmc_construct_one_dimm_group(p, 1, mem_regs, num_mem_regs);
+		p->num_dimm_groups++;
+	}
+}
+
+static int __devinit jbusmc_probe(struct of_device *op,
+				  const struct of_device_id *match)
+{
+	const struct linux_prom64_registers *mem_regs;
+	struct device_node *mem_node;
+	int err, len, num_mem_regs;
+	struct jbusmc *p;
+	const u32 *prop;
+	const void *ml;
+
+	err = -ENODEV;
+	mem_node = of_find_node_by_path("/memory");
+	if (!mem_node) {
+		printk(KERN_ERR PFX "Cannot find /memory node.\n");
+		goto out;
+	}
+	mem_regs = of_get_property(mem_node, "reg", &len);
+	if (!mem_regs) {
+		printk(KERN_ERR PFX "Cannot get reg property of /memory node.\n");
+		goto out;
+	}
+	num_mem_regs = len / sizeof(*mem_regs);
+
+	err = -ENOMEM;
+	p = kzalloc(sizeof(*p), GFP_KERNEL);
+	if (!p) {
+		printk(KERN_ERR PFX "Cannot allocate struct jbusmc.\n");
+		goto out;
+	}
+
+	INIT_LIST_HEAD(&p->list);
+
+	err = -ENODEV;
+	prop = of_get_property(op->node, "portid", &len);
+	if (!prop || len != 4) {
+		printk(KERN_ERR PFX "Cannot find portid.\n");
+		goto out_free;
+	}
+
+	p->portid = *prop;
+
+	prop = of_get_property(op->node, "memory-control-register-1", &len);
+	if (!prop || len != 8) {
+		printk(KERN_ERR PFX "Cannot get memory control register 1.\n");
+		goto out_free;
+	}
+
+	p->mc_reg_1 = ((u64)prop[0] << 32) | (u64) prop[1];
+
+	err = -ENOMEM;
+	p->regs = of_ioremap(&op->resource[0], 0, JBUSMC_REGS_SIZE, "jbusmc");
+	if (!p->regs) {
+		printk(KERN_ERR PFX "Cannot map jbusmc regs.\n");
+		goto out_free;
+	}
+
+	err = -ENODEV;
+	ml = of_get_property(op->node, "memory-layout", &p->layout_len);
+	if (!ml) {
+		printk(KERN_ERR PFX "Cannot get memory layout property.\n");
+		goto out_iounmap;
+	}
+	if (p->layout_len > sizeof(p->layout)) {
+		printk(KERN_ERR PFX "Unexpected memory-layout size %d\n",
+		       p->layout_len);
+		goto out_iounmap;
+	}
+	memcpy(&p->layout, ml, p->layout_len);
+
+	jbusmc_construct_dimm_groups(p, mem_regs, num_mem_regs);
+
+	mc_list_add(&p->list);
+
+	printk(KERN_INFO PFX "UltraSPARC-IIIi memory controller at %s\n",
+	       op->node->full_name);
+
+	dev_set_drvdata(&op->dev, p);
+
+	err = 0;
+
+out:
+	return err;
+
+out_iounmap:
+	of_iounmap(&op->resource[0], p->regs, JBUSMC_REGS_SIZE);
+
+out_free:
+	kfree(p);
+	goto out;
+}
+
 /* Does BANK decode PHYS_ADDR? */
-static int bank_match(struct bank_info *bp, unsigned long phys_addr)
+static int chmc_bank_match(struct chmc_bank_info *bp, unsigned long phys_addr)
 {
 	unsigned long upper_bits = (phys_addr & PA_UPPER_BITS) >> PA_UPPER_BITS_SHIFT;
 	unsigned long lower_bits = (phys_addr & PA_LOWER_BITS) >> PA_LOWER_BITS_SHIFT;
@@ -118,25 +515,18 @@
 }
 
 /* Given PHYS_ADDR, search memory controller banks for a match. */
-static struct bank_info *find_bank(unsigned long phys_addr)
+static struct chmc_bank_info *chmc_find_bank(unsigned long phys_addr)
 {
-	struct list_head *mctrl_head = &mctrl_list;
-	struct list_head *mctrl_entry = mctrl_head->next;
+	struct chmc *p;
 
-	for (;;) {
-		struct mctrl_info *mp =
-			list_entry(mctrl_entry, struct mctrl_info, list);
+	list_for_each_entry(p, &mctrl_list, list) {
 		int bank_no;
 
-		if (mctrl_entry == mctrl_head)
-			break;
-		mctrl_entry = mctrl_entry->next;
-
 		for (bank_no = 0; bank_no < CHMCTRL_NBANKS; bank_no++) {
-			struct bank_info *bp;
+			struct chmc_bank_info *bp;
 
-			bp = &mp->logical_banks[bank_no];
-			if (bank_match(bp, phys_addr))
+			bp = &p->logical_banks[bank_no];
+			if (chmc_bank_match(bp, phys_addr))
 				return bp;
 		}
 	}
@@ -145,17 +535,15 @@
 }
 
 /* This is the main purpose of this driver. */
-#define SYNDROME_MIN	-1
-#define SYNDROME_MAX	144
-int chmc_getunumber(int syndrome_code,
-		    unsigned long phys_addr,
-		    char *buf, int buflen)
+static int chmc_print_dimm(int syndrome_code,
+			   unsigned long phys_addr,
+			   char *buf, int buflen)
 {
-	struct bank_info *bp;
-	struct obp_mem_layout *prop;
+	struct chmc_bank_info *bp;
+	struct chmc_obp_mem_layout *prop;
 	int bank_in_controller, first_dimm;
 
-	bp = find_bank(phys_addr);
+	bp = chmc_find_bank(phys_addr);
 	if (bp == NULL ||
 	    syndrome_code < SYNDROME_MIN ||
 	    syndrome_code > SYNDROME_MAX) {
@@ -166,60 +554,18 @@
 		return 0;
 	}
 
-	prop = &bp->mp->layout_prop;
+	prop = &bp->p->layout_prop;
 	bank_in_controller = bp->bank_id & (CHMCTRL_NBANKS - 1);
 	first_dimm  = (bank_in_controller & (CHMCTRL_NDGRPS - 1));
 	first_dimm *= CHMCTRL_NDIMMS;
 
 	if (syndrome_code != SYNDROME_MIN) {
-		struct obp_map *map;
-		int qword, where_in_line, where, map_index, map_offset;
-		unsigned int map_val;
+		char *dimm_str;
+		int pin;
 
-		/* Yaay, single bit error so we can figure out
-		 * the exact dimm.
-		 */
-		if (prop->symmetric)
-			map = &prop->map[0];
-		else
-			map = &prop->map[1];
-
-		/* Covert syndrome code into the way the bits are
-		 * positioned on the bus.
-		 */
-		if (syndrome_code < 144 - 16)
-			syndrome_code += 16;
-		else if (syndrome_code < 144)
-			syndrome_code -= (144 - 7);
-		else if (syndrome_code < (144 + 3))
-			syndrome_code -= (144 + 3 - 4);
-		else
-			syndrome_code -= 144 + 3;
-
-		/* All this magic has to do with how a cache line
-		 * comes over the wire on Safari.  A 64-bit line
-		 * comes over in 4 quadword cycles, each of which
-		 * transmit ECC/MTAG info as well as the actual
-		 * data.  144 bits per quadword, 576 total.
-		 */
-#define LINE_SIZE	64
-#define LINE_ADDR_MSK	(LINE_SIZE - 1)
-#define QW_PER_LINE	4
-#define QW_BYTES	(LINE_SIZE / QW_PER_LINE)
-#define QW_BITS		144
-#define LAST_BIT	(576 - 1)
-
-		qword = (phys_addr & LINE_ADDR_MSK) / QW_BYTES;
-		where_in_line = ((3 - qword) * QW_BITS) + syndrome_code;
-		where = (LAST_BIT - where_in_line);
-		map_index = where >> 2;
-		map_offset = where & 0x3;
-		map_val = map->dimm_map[map_index];
-		map_val = ((map_val >> ((3 - map_offset) << 1)) & (2 - 1));
-
-		sprintf(buf, "%s, pin %3d",
-			prop->dimm_labels[first_dimm + map_val],
-			map->pin_map[where_in_line]);
+		get_pin_and_dimm_str(syndrome_code, phys_addr, &pin,
+				     &dimm_str, prop, first_dimm);
+		sprintf(buf, "%s, pin %3d", dimm_str, pin);
 	} else {
 		int dimm;
 
@@ -240,7 +586,7 @@
  * the code is executing, you must use special ASI load/store else
  * you go through the global mapping.
  */
-static u64 read_mcreg(struct mctrl_info *mp, unsigned long offset)
+static u64 chmc_read_mcreg(struct chmc *p, unsigned long offset)
 {
 	unsigned long ret, this_cpu;
 
@@ -248,14 +594,14 @@
 
 	this_cpu = real_hard_smp_processor_id();
 
-	if (mp->portid == this_cpu) {
+	if (p->portid == this_cpu) {
 		__asm__ __volatile__("ldxa	[%1] %2, %0"
 				     : "=r" (ret)
 				     : "r" (offset), "i" (ASI_MCU_CTRL_REG));
 	} else {
 		__asm__ __volatile__("ldxa	[%1] %2, %0"
 				     : "=r" (ret)
-				     : "r" (mp->regs + offset),
+				     : "r" (p->regs + offset),
 				       "i" (ASI_PHYS_BYPASS_EC_E));
 	}
 
@@ -265,178 +611,253 @@
 }
 
 #if 0 /* currently unused */
-static void write_mcreg(struct mctrl_info *mp, unsigned long offset, u64 val)
+static void chmc_write_mcreg(struct chmc *p, unsigned long offset, u64 val)
 {
-	if (mp->portid == smp_processor_id()) {
+	if (p->portid == smp_processor_id()) {
 		__asm__ __volatile__("stxa	%0, [%1] %2"
 				     : : "r" (val),
 				         "r" (offset), "i" (ASI_MCU_CTRL_REG));
 	} else {
 		__asm__ __volatile__("ldxa	%0, [%1] %2"
 				     : : "r" (val),
-				         "r" (mp->regs + offset),
+				         "r" (p->regs + offset),
 				         "i" (ASI_PHYS_BYPASS_EC_E));
 	}
 }
 #endif
 
-static void interpret_one_decode_reg(struct mctrl_info *mp, int which_bank, u64 val)
+static void chmc_interpret_one_decode_reg(struct chmc *p, int which_bank, u64 val)
 {
-	struct bank_info *p = &mp->logical_banks[which_bank];
+	struct chmc_bank_info *bp = &p->logical_banks[which_bank];
 
-	p->mp = mp;
-	p->bank_id = (CHMCTRL_NBANKS * mp->portid) + which_bank;
-	p->raw_reg = val;
-	p->valid = (val & MEM_DECODE_VALID) >> MEM_DECODE_VALID_SHIFT;
-	p->uk = (val & MEM_DECODE_UK) >> MEM_DECODE_UK_SHIFT;
-	p->um = (val & MEM_DECODE_UM) >> MEM_DECODE_UM_SHIFT;
-	p->lk = (val & MEM_DECODE_LK) >> MEM_DECODE_LK_SHIFT;
-	p->lm = (val & MEM_DECODE_LM) >> MEM_DECODE_LM_SHIFT;
+	bp->p = p;
+	bp->bank_id = (CHMCTRL_NBANKS * p->portid) + which_bank;
+	bp->raw_reg = val;
+	bp->valid = (val & MEM_DECODE_VALID) >> MEM_DECODE_VALID_SHIFT;
+	bp->uk = (val & MEM_DECODE_UK) >> MEM_DECODE_UK_SHIFT;
+	bp->um = (val & MEM_DECODE_UM) >> MEM_DECODE_UM_SHIFT;
+	bp->lk = (val & MEM_DECODE_LK) >> MEM_DECODE_LK_SHIFT;
+	bp->lm = (val & MEM_DECODE_LM) >> MEM_DECODE_LM_SHIFT;
 
-	p->base  =  (p->um);
-	p->base &= ~(p->uk);
-	p->base <<= PA_UPPER_BITS_SHIFT;
+	bp->base  =  (bp->um);
+	bp->base &= ~(bp->uk);
+	bp->base <<= PA_UPPER_BITS_SHIFT;
 
-	switch(p->lk) {
+	switch(bp->lk) {
 	case 0xf:
 	default:
-		p->interleave = 1;
+		bp->interleave = 1;
 		break;
 
 	case 0xe:
-		p->interleave = 2;
+		bp->interleave = 2;
 		break;
 
 	case 0xc:
-		p->interleave = 4;
+		bp->interleave = 4;
 		break;
 
 	case 0x8:
-		p->interleave = 8;
+		bp->interleave = 8;
 		break;
 
 	case 0x0:
-		p->interleave = 16;
+		bp->interleave = 16;
 		break;
 	};
 
 	/* UK[10] is reserved, and UK[11] is not set for the SDRAM
 	 * bank size definition.
 	 */
-	p->size = (((unsigned long)p->uk &
-		    ((1UL << 10UL) - 1UL)) + 1UL) << PA_UPPER_BITS_SHIFT;
-	p->size /= p->interleave;
+	bp->size = (((unsigned long)bp->uk &
+		     ((1UL << 10UL) - 1UL)) + 1UL) << PA_UPPER_BITS_SHIFT;
+	bp->size /= bp->interleave;
 }
 
-static void fetch_decode_regs(struct mctrl_info *mp)
+static void chmc_fetch_decode_regs(struct chmc *p)
 {
-	if (mp->layout_size == 0)
+	if (p->layout_size == 0)
 		return;
 
-	interpret_one_decode_reg(mp, 0,
-				 read_mcreg(mp, CHMCTRL_DECODE1));
-	interpret_one_decode_reg(mp, 1,
-				 read_mcreg(mp, CHMCTRL_DECODE2));
-	interpret_one_decode_reg(mp, 2,
-				 read_mcreg(mp, CHMCTRL_DECODE3));
-	interpret_one_decode_reg(mp, 3,
-				 read_mcreg(mp, CHMCTRL_DECODE4));
+	chmc_interpret_one_decode_reg(p, 0,
+				      chmc_read_mcreg(p, CHMCTRL_DECODE1));
+	chmc_interpret_one_decode_reg(p, 1,
+				      chmc_read_mcreg(p, CHMCTRL_DECODE2));
+	chmc_interpret_one_decode_reg(p, 2,
+				      chmc_read_mcreg(p, CHMCTRL_DECODE3));
+	chmc_interpret_one_decode_reg(p, 3,
+				      chmc_read_mcreg(p, CHMCTRL_DECODE4));
 }
 
-static int init_one_mctrl(struct device_node *dp)
+static int __devinit chmc_probe(struct of_device *op,
+				const struct of_device_id *match)
 {
-	struct mctrl_info *mp = kzalloc(sizeof(*mp), GFP_KERNEL);
-	int portid = of_getintprop_default(dp, "portid", -1);
-	const struct linux_prom64_registers *regs;
+	struct device_node *dp = op->node;
+	unsigned long ver;
 	const void *pval;
-	int len;
+	int len, portid;
+	struct chmc *p;
+	int err;
 
-	if (!mp)
-		return -1;
+	err = -ENODEV;
+	__asm__ ("rdpr %%ver, %0" : "=r" (ver));
+	if ((ver >> 32UL) == __JALAPENO_ID ||
+	    (ver >> 32UL) == __SERRANO_ID)
+		goto out;
+
+	portid = of_getintprop_default(dp, "portid", -1);
 	if (portid == -1)
-		goto fail;
+		goto out;
 
-	mp->portid = portid;
 	pval = of_get_property(dp, "memory-layout", &len);
-	mp->layout_size = len;
+	if (pval && len > sizeof(p->layout_prop)) {
+		printk(KERN_ERR PFX "Unexpected memory-layout property "
+		       "size %d.\n", len);
+		goto out;
+	}
+
+	err = -ENOMEM;
+	p = kzalloc(sizeof(*p), GFP_KERNEL);
+	if (!p) {
+		printk(KERN_ERR PFX "Could not allocate struct chmc.\n");
+		goto out;
+	}
+
+	p->portid = portid;
+	p->layout_size = len;
 	if (!pval)
-		mp->layout_size = 0;
-	else {
-		if (mp->layout_size > sizeof(mp->layout_prop))
-			goto fail;
-		memcpy(&mp->layout_prop, pval, len);
+		p->layout_size = 0;
+	else
+		memcpy(&p->layout_prop, pval, len);
+
+	p->regs = of_ioremap(&op->resource[0], 0, 0x48, "chmc");
+	if (!p->regs) {
+		printk(KERN_ERR PFX "Could not map registers.\n");
+		goto out_free;
 	}
 
-	regs = of_get_property(dp, "reg", NULL);
-	if (!regs || regs->reg_size != 0x48)
-		goto fail;
-
-	mp->regs = ioremap(regs->phys_addr, regs->reg_size);
-	if (mp->regs == NULL)
-		goto fail;
-
-	if (mp->layout_size != 0UL) {
-		mp->timing_control1 = read_mcreg(mp, CHMCTRL_TCTRL1);
-		mp->timing_control2 = read_mcreg(mp, CHMCTRL_TCTRL2);
-		mp->timing_control3 = read_mcreg(mp, CHMCTRL_TCTRL3);
-		mp->timing_control4 = read_mcreg(mp, CHMCTRL_TCTRL4);
-		mp->memaddr_control = read_mcreg(mp, CHMCTRL_MACTRL);
+	if (p->layout_size != 0UL) {
+		p->timing_control1 = chmc_read_mcreg(p, CHMCTRL_TCTRL1);
+		p->timing_control2 = chmc_read_mcreg(p, CHMCTRL_TCTRL2);
+		p->timing_control3 = chmc_read_mcreg(p, CHMCTRL_TCTRL3);
+		p->timing_control4 = chmc_read_mcreg(p, CHMCTRL_TCTRL4);
+		p->memaddr_control = chmc_read_mcreg(p, CHMCTRL_MACTRL);
 	}
 
-	fetch_decode_regs(mp);
+	chmc_fetch_decode_regs(p);
 
-	list_add(&mp->list, &mctrl_list);
+	mc_list_add(&p->list);
 
-	/* Report the device. */
-	printk(KERN_INFO "%s: US3 memory controller at %p [%s]\n",
+	printk(KERN_INFO PFX "UltraSPARC-III memory controller at %s [%s]\n",
 	       dp->full_name,
-	       mp->regs, (mp->layout_size ? "ACTIVE" : "INACTIVE"));
+	       (p->layout_size ? "ACTIVE" : "INACTIVE"));
 
-	return 0;
+	dev_set_drvdata(&op->dev, p);
 
-fail:
-	if (mp) {
-		if (mp->regs != NULL)
-			iounmap(mp->regs);
-		kfree(mp);
-	}
-	return -1;
+	err = 0;
+
+out:
+	return err;
+
+out_free:
+	kfree(p);
+	goto out;
 }
 
-static int __init chmc_init(void)
+static int __devinit us3mc_probe(struct of_device *op,
+				const struct of_device_id *match)
 {
-	struct device_node *dp;
+	if (mc_type == MC_TYPE_SAFARI)
+		return chmc_probe(op, match);
+	else if (mc_type == MC_TYPE_JBUS)
+		return jbusmc_probe(op, match);
+	return -ENODEV;
+}
 
-	/* This driver is only for cheetah platforms. */
-	if (tlb_type != cheetah && tlb_type != cheetah_plus)
+static void __devexit chmc_destroy(struct of_device *op, struct chmc *p)
+{
+	list_del(&p->list);
+	of_iounmap(&op->resource[0], p->regs, 0x48);
+	kfree(p);
+}
+
+static void __devexit jbusmc_destroy(struct of_device *op, struct jbusmc *p)
+{
+	mc_list_del(&p->list);
+	of_iounmap(&op->resource[0], p->regs, JBUSMC_REGS_SIZE);
+	kfree(p);
+}
+
+static int __devexit us3mc_remove(struct of_device *op)
+{
+	void *p = dev_get_drvdata(&op->dev);
+
+	if (p) {
+		if (mc_type == MC_TYPE_SAFARI)
+			chmc_destroy(op, p);
+		else if (mc_type == MC_TYPE_JBUS)
+			jbusmc_destroy(op, p);
+	}
+	return 0;
+}
+
+static const struct of_device_id us3mc_match[] = {
+	{
+		.name = "memory-controller",
+	},
+	{},
+};
+MODULE_DEVICE_TABLE(of, us3mc_match);
+
+static struct of_platform_driver us3mc_driver = {
+	.name		= "us3mc",
+	.match_table	= us3mc_match,
+	.probe		= us3mc_probe,
+	.remove		= __devexit_p(us3mc_remove),
+};
+
+static inline bool us3mc_platform(void)
+{
+	if (tlb_type == cheetah || tlb_type == cheetah_plus)
+		return true;
+	return false;
+}
+
+static int __init us3mc_init(void)
+{
+	unsigned long ver;
+	int ret;
+
+	if (!us3mc_platform())
 		return -ENODEV;
 
-	for_each_node_by_name(dp, "memory-controller")
-		init_one_mctrl(dp);
+	__asm__ __volatile__("rdpr %%ver, %0" : "=r" (ver));
+	if ((ver >> 32UL) == __JALAPENO_ID ||
+	    (ver >> 32UL) == __SERRANO_ID) {
+		mc_type = MC_TYPE_JBUS;
+		us3mc_dimm_printer = jbusmc_print_dimm;
+	} else {
+		mc_type = MC_TYPE_SAFARI;
+		us3mc_dimm_printer = chmc_print_dimm;
+	}
 
-	for_each_node_by_name(dp, "mc-us3")
-		init_one_mctrl(dp);
+	ret = register_dimm_printer(us3mc_dimm_printer);
 
-	return 0;
+	if (!ret) {
+		ret = of_register_driver(&us3mc_driver, &of_bus_type);
+		if (ret)
+			unregister_dimm_printer(us3mc_dimm_printer);
+	}
+	return ret;
 }
 
-static void __exit chmc_cleanup(void)
+static void __exit us3mc_cleanup(void)
 {
-	struct list_head *head = &mctrl_list;
-	struct list_head *tmp = head->next;
-
-	for (;;) {
-		struct mctrl_info *p =
-			list_entry(tmp, struct mctrl_info, list);
-		if (tmp == head)
-			break;
-		tmp = tmp->next;
-
-		list_del(&p->list);
-		iounmap(p->regs);
-		kfree(p);
+	if (us3mc_platform()) {
+		unregister_dimm_printer(us3mc_dimm_printer);
+		of_unregister_driver(&us3mc_driver);
 	}
 }
 
-module_init(chmc_init);
-module_exit(chmc_cleanup);
+module_init(us3mc_init);
+module_exit(us3mc_cleanup);
diff --git a/arch/sparc64/kernel/cpu.c b/arch/sparc64/kernel/cpu.c
index 0097c08..0c9ac83 100644
--- a/arch/sparc64/kernel/cpu.c
+++ b/arch/sparc64/kernel/cpu.c
@@ -1,7 +1,7 @@
 /* cpu.c: Dinky routines to look for the kind of Sparc cpu
  *        we are on.
  *
- * Copyright (C) 1996, 2007 David S. Miller (davem@davemloft.net)
+ * Copyright (C) 1996, 2007, 2008 David S. Miller (davem@davemloft.net)
  */
 
 #include <linux/kernel.h>
@@ -19,53 +19,86 @@
 
 DEFINE_PER_CPU(cpuinfo_sparc, __cpu_data) = { 0 };
 
-struct cpu_iu_info {
-  short manuf;
-  short impl;
-  char* cpu_name;   /* should be enough I hope... */
+struct cpu_chip_info {
+	unsigned short	manuf;
+	unsigned short	impl;
+	const char	*cpu_name;
+	const char	*fp_name;
 };
 
-struct cpu_fp_info {
-  short manuf;
-  short impl;
-  char fpu_vers;
-  char* fp_name;
+static const struct cpu_chip_info cpu_chips[] = {
+	{
+		.manuf		= 0x17,
+		.impl		= 0x10,
+		.cpu_name	= "TI UltraSparc I   (SpitFire)",
+		.fp_name	= "UltraSparc I integrated FPU",
+	},
+	{
+		.manuf		= 0x22,
+		.impl		= 0x10,
+		.cpu_name	= "TI UltraSparc I   (SpitFire)",
+		.fp_name	= "UltraSparc I integrated FPU",
+	},
+	{
+		.manuf		= 0x17,
+		.impl		= 0x11,
+		.cpu_name	= "TI UltraSparc II  (BlackBird)",
+		.fp_name	= "UltraSparc II integrated FPU",
+	},
+	{
+		.manuf		= 0x17,
+		.impl		= 0x12,
+		.cpu_name	= "TI UltraSparc IIi (Sabre)",
+		.fp_name	= "UltraSparc IIi integrated FPU",
+	},
+	{
+		.manuf		= 0x17,
+		.impl		= 0x13,
+		.cpu_name	= "TI UltraSparc IIe (Hummingbird)",
+		.fp_name	= "UltraSparc IIe integrated FPU",
+	},
+	{
+		.manuf		= 0x3e,
+		.impl		= 0x14,
+		.cpu_name	= "TI UltraSparc III (Cheetah)",
+		.fp_name	= "UltraSparc III integrated FPU",
+	},
+	{
+		.manuf		= 0x3e,
+		.impl		= 0x15,
+		.cpu_name	= "TI UltraSparc III+ (Cheetah+)",
+		.fp_name	= "UltraSparc III+ integrated FPU",
+	},
+	{
+		.manuf		= 0x3e,
+		.impl		= 0x16,
+		.cpu_name	= "TI UltraSparc IIIi (Jalapeno)",
+		.fp_name	= "UltraSparc IIIi integrated FPU",
+	},
+	{
+		.manuf		= 0x3e,
+		.impl		= 0x18,
+		.cpu_name	= "TI UltraSparc IV (Jaguar)",
+		.fp_name	= "UltraSparc IV integrated FPU",
+	},
+	{
+		.manuf		= 0x3e,
+		.impl		= 0x19,
+		.cpu_name	= "TI UltraSparc IV+ (Panther)",
+		.fp_name	= "UltraSparc IV+ integrated FPU",
+	},
+	{
+		.manuf		= 0x3e,
+		.impl		= 0x22,
+		.cpu_name	= "TI UltraSparc IIIi+ (Serrano)",
+		.fp_name	= "UltraSparc IIIi+ integrated FPU",
+	},
 };
 
-static struct cpu_fp_info linux_sparc_fpu[] = {
-  { 0x17, 0x10, 0, "UltraSparc I integrated FPU"},
-  { 0x22, 0x10, 0, "UltraSparc I integrated FPU"},
-  { 0x17, 0x11, 0, "UltraSparc II integrated FPU"},
-  { 0x17, 0x12, 0, "UltraSparc IIi integrated FPU"},
-  { 0x17, 0x13, 0, "UltraSparc IIe integrated FPU"},
-  { 0x3e, 0x14, 0, "UltraSparc III integrated FPU"},
-  { 0x3e, 0x15, 0, "UltraSparc III+ integrated FPU"},
-  { 0x3e, 0x16, 0, "UltraSparc IIIi integrated FPU"},
-  { 0x3e, 0x18, 0, "UltraSparc IV integrated FPU"},
-  { 0x3e, 0x19, 0, "UltraSparc IV+ integrated FPU"},
-  { 0x3e, 0x22, 0, "UltraSparc IIIi+ integrated FPU"},
-};
+#define NSPARCCHIPS ARRAY_SIZE(linux_sparc_chips)
 
-#define NSPARCFPU  ARRAY_SIZE(linux_sparc_fpu)
-
-static struct cpu_iu_info linux_sparc_chips[] = {
-  { 0x17, 0x10, "TI UltraSparc I   (SpitFire)"},
-  { 0x22, 0x10, "TI UltraSparc I   (SpitFire)"},
-  { 0x17, 0x11, "TI UltraSparc II  (BlackBird)"},
-  { 0x17, 0x12, "TI UltraSparc IIi (Sabre)"},
-  { 0x17, 0x13, "TI UltraSparc IIe (Hummingbird)"},
-  { 0x3e, 0x14, "TI UltraSparc III (Cheetah)"},
-  { 0x3e, 0x15, "TI UltraSparc III+ (Cheetah+)"},
-  { 0x3e, 0x16, "TI UltraSparc IIIi (Jalapeno)"},
-  { 0x3e, 0x18, "TI UltraSparc IV (Jaguar)"},
-  { 0x3e, 0x19, "TI UltraSparc IV+ (Panther)"},
-  { 0x3e, 0x22, "TI UltraSparc IIIi+ (Serrano)"},
-};
-
-#define NSPARCCHIPS  ARRAY_SIZE(linux_sparc_chips)
-
-char *sparc_cpu_type;
-char *sparc_fpu_type;
+const char *sparc_cpu_type;
+const char *sparc_fpu_type;
 
 static void __init sun4v_cpu_probe(void)
 {
@@ -89,68 +122,45 @@
 	}
 }
 
-void __init cpu_probe(void)
+static const struct cpu_chip_info * __init find_cpu_chip(unsigned short manuf,
+							 unsigned short impl)
 {
-	unsigned long ver, fpu_vers, manuf, impl, fprs;
 	int i;
-	
+
+	for (i = 0; i < ARRAY_SIZE(cpu_chips); i++) {
+		const struct cpu_chip_info *p = &cpu_chips[i];
+
+		if (p->manuf == manuf && p->impl == impl)
+			return p;
+	}
+	return NULL;
+}
+
+static int __init cpu_type_probe(void)
+{
 	if (tlb_type == hypervisor) {
 		sun4v_cpu_probe();
-		return;
-	}
-
-	fprs = fprs_read();
-	fprs_write(FPRS_FEF);
-	__asm__ __volatile__ ("rdpr %%ver, %0; stx %%fsr, [%1]"
-			      : "=&r" (ver)
-			      : "r" (&fpu_vers));
-	fprs_write(fprs);
+	} else {
+		unsigned long ver, manuf, impl;
+		const struct cpu_chip_info *p;
 	
-	manuf = ((ver >> 48) & 0xffff);
-	impl = ((ver >> 32) & 0xffff);
+		__asm__ __volatile__("rdpr %%ver, %0" : "=r" (ver));
+	
+		manuf = ((ver >> 48) & 0xffff);
+		impl = ((ver >> 32) & 0xffff);
 
-	fpu_vers = ((fpu_vers >> 17) & 0x7);
-
-retry:
-	for (i = 0; i < NSPARCCHIPS; i++) {
-		if (linux_sparc_chips[i].manuf == manuf) {
-			if (linux_sparc_chips[i].impl == impl) {
-				sparc_cpu_type =
-					linux_sparc_chips[i].cpu_name;
-				break;
-			}
+		p = find_cpu_chip(manuf, impl);
+		if (p) {
+			sparc_cpu_type = p->cpu_name;
+			sparc_fpu_type = p->fp_name;
+		} else {
+			printk(KERN_ERR "CPU: Unknown chip, manuf[%lx] impl[%lx]\n",
+			       manuf, impl);
+			sparc_cpu_type = "Unknown CPU";
+			sparc_fpu_type = "Unknown FPU";
 		}
 	}
-
-	if (i == NSPARCCHIPS) {
- 		/* Maybe it is a cheetah+ derivative, report it as cheetah+
- 		 * in that case until we learn the real names.
- 		 */
- 		if (manuf == 0x3e &&
- 		    impl > 0x15) {
- 			impl = 0x15;
- 			goto retry;
- 		} else {
- 			printk("DEBUG: manuf[%lx] impl[%lx]\n",
- 			       manuf, impl);
- 		}
-		sparc_cpu_type = "Unknown CPU";
-	}
-
-	for (i = 0; i < NSPARCFPU; i++) {
-		if (linux_sparc_fpu[i].manuf == manuf &&
-		    linux_sparc_fpu[i].impl == impl) {
-			if (linux_sparc_fpu[i].fpu_vers == fpu_vers) {
-				sparc_fpu_type =
-					linux_sparc_fpu[i].fp_name;
-				break;
-			}
-		}
-	}
-
-	if (i == NSPARCFPU) {
- 		printk("DEBUG: manuf[%lx] impl[%lx] fsr.vers[%lx]\n",
- 		       manuf, impl, fpu_vers);
-		sparc_fpu_type = "Unknown FPU";
-	}
+	return 0;
 }
+
+arch_initcall(cpu_type_probe);
diff --git a/arch/sparc64/kernel/ds.c b/arch/sparc64/kernel/ds.c
index d0fa5aa..f52e053 100644
--- a/arch/sparc64/kernel/ds.c
+++ b/arch/sparc64/kernel/ds.c
@@ -1,6 +1,6 @@
 /* ds.c: Domain Services driver for Logical Domains
  *
- * Copyright (C) 2007 David S. Miller <davem@davemloft.net>
+ * Copyright (C) 2007, 2008 David S. Miller <davem@davemloft.net>
  */
 
 #include <linux/kernel.h>
@@ -1217,7 +1217,7 @@
 	return 0;
 }
 
-static struct vio_device_id ds_match[] = {
+static struct vio_device_id __initdata ds_match[] = {
 	{
 		.type = "domain-services-port",
 	},
diff --git a/arch/sparc64/kernel/ebus.c b/arch/sparc64/kernel/ebus.c
index 60d36d1..77dbf6d 100644
--- a/arch/sparc64/kernel/ebus.c
+++ b/arch/sparc64/kernel/ebus.c
@@ -1,5 +1,4 @@
-/*
- * ebus.c: PCI to EBus bridge device.
+/* ebus.c: EBUS DMA library code.
  *
  * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
  * Copyright (C) 1999  David S. Miller (davem@redhat.com)
@@ -9,24 +8,12 @@
 #include <linux/kernel.h>
 #include <linux/types.h>
 #include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/string.h>
 #include <linux/interrupt.h>
 #include <linux/delay.h>
-#include <linux/pci.h>
-#include <linux/of_device.h>
 
-#include <asm/system.h>
-#include <asm/page.h>
-#include <asm/ebus.h>
-#include <asm/oplib.h>
-#include <asm/prom.h>
-#include <asm/bpp.h>
-#include <asm/irq.h>
+#include <asm/ebus_dma.h>
 #include <asm/io.h>
 
-/* EBUS dma library. */
-
 #define EBDMA_CSR	0x00UL	/* Control/Status */
 #define EBDMA_ADDR	0x04UL	/* DMA Address */
 #define EBDMA_COUNT	0x08UL	/* DMA Count */
@@ -268,283 +255,3 @@
 	spin_unlock_irqrestore(&p->lock, flags);
 }
 EXPORT_SYMBOL(ebus_dma_enable);
-
-struct linux_ebus *ebus_chain = NULL;
-
-static inline void *ebus_alloc(size_t size)
-{
-	void *mem;
-
-	mem = kzalloc(size, GFP_ATOMIC);
-	if (!mem)
-		panic("ebus_alloc: out of memory");
-	return mem;
-}
-
-static void __init fill_ebus_child(struct device_node *dp,
-				   struct linux_ebus_child *dev,
-				   int non_standard_regs)
-{
-	struct of_device *op;
-	const int *regs;
-	int i, len;
-
-	dev->prom_node = dp;
-	printk(" (%s)", dp->name);
-
-	regs = of_get_property(dp, "reg", &len);
-	if (!regs)
-		dev->num_addrs = 0;
-	else
-		dev->num_addrs = len / sizeof(regs[0]);
-
-	if (non_standard_regs) {
-		/* This is to handle reg properties which are not
-		 * in the parent relative format.  One example are
-		 * children of the i2c device on CompactPCI systems.
-		 *
-		 * So, for such devices we just record the property
-		 * raw in the child resources.
-		 */
-		for (i = 0; i < dev->num_addrs; i++)
-			dev->resource[i].start = regs[i];
-	} else {
-		for (i = 0; i < dev->num_addrs; i++) {
-			int rnum = regs[i];
-			if (rnum >= dev->parent->num_addrs) {
-				prom_printf("UGH: property for %s was %d, need < %d\n",
-					    dp->name, len, dev->parent->num_addrs);
-				prom_halt();
-			}
-			dev->resource[i].start = dev->parent->resource[i].start;
-			dev->resource[i].end = dev->parent->resource[i].end;
-			dev->resource[i].flags = IORESOURCE_MEM;
-			dev->resource[i].name = dp->name;
-		}
-	}
-
-	op = of_find_device_by_node(dp);
-	if (!op) {
-		dev->num_irqs = 0;
-	} else {
-		dev->num_irqs = op->num_irqs;
-		for (i = 0; i < dev->num_irqs; i++)
-			dev->irqs[i] = op->irqs[i];
-	}
-
-	if (!dev->num_irqs) {
-		/*
-		 * Oh, well, some PROMs don't export interrupts
-		 * property to children of EBus devices...
-		 *
-		 * Be smart about PS/2 keyboard and mouse.
-		 */
-		if (!strcmp(dev->parent->prom_node->name, "8042")) {
-			if (!strcmp(dev->prom_node->name, "kb_ps2")) {
-				dev->num_irqs = 1;
-				dev->irqs[0] = dev->parent->irqs[0];
-			} else {
-				dev->num_irqs = 1;
-				dev->irqs[0] = dev->parent->irqs[1];
-			}
-		}
-	}
-}
-
-static int __init child_regs_nonstandard(struct linux_ebus_device *dev)
-{
-	if (!strcmp(dev->prom_node->name, "i2c") ||
-	    !strcmp(dev->prom_node->name, "SUNW,lombus"))
-		return 1;
-	return 0;
-}
-
-static void __init fill_ebus_device(struct device_node *dp, struct linux_ebus_device *dev)
-{
-	struct linux_ebus_child *child;
-	struct dev_archdata *sd;
-	struct of_device *op;
-	int i, len;
-
-	dev->prom_node = dp;
-
-	printk(" [%s", dp->name);
-
-	op = of_find_device_by_node(dp);
-	if (!op) {
-		dev->num_addrs = 0;
-		dev->num_irqs = 0;
-	} else {
-		const int *regs = of_get_property(dp, "reg", &len);
-
-		if (!regs)
-			len = 0;
-		dev->num_addrs = len / sizeof(struct linux_prom_registers);
-
-		for (i = 0; i < dev->num_addrs; i++)
-			memcpy(&dev->resource[i],
-			       &op->resource[i],
-			       sizeof(struct resource));
-
-		dev->num_irqs = op->num_irqs;
-		for (i = 0; i < dev->num_irqs; i++)
-			dev->irqs[i] = op->irqs[i];
-	}
-
-	sd = &dev->ofdev.dev.archdata;
-	sd->prom_node = dp;
-	sd->op = &dev->ofdev;
-	sd->iommu = dev->bus->ofdev.dev.parent->archdata.iommu;
-	sd->stc = dev->bus->ofdev.dev.parent->archdata.stc;
-	sd->numa_node = dev->bus->ofdev.dev.parent->archdata.numa_node;
-
-	dev->ofdev.node = dp;
-	dev->ofdev.dev.parent = &dev->bus->ofdev.dev;
-	dev->ofdev.dev.bus = &ebus_bus_type;
-	dev_set_name(&dev->ofdev.dev, "ebus[%08x]", dp->node);
-
-	/* Register with core */
-	if (of_device_register(&dev->ofdev) != 0)
-		printk(KERN_DEBUG "ebus: device registration error for %s!\n",
-		       dp->path_component_name);
-
-	dp = dp->child;
-	if (dp) {
-		printk(" ->");
-		dev->children = ebus_alloc(sizeof(struct linux_ebus_child));
-
-		child = dev->children;
-		child->next = NULL;
-		child->parent = dev;
-		child->bus = dev->bus;
-		fill_ebus_child(dp, child,
-				child_regs_nonstandard(dev));
-
-		while ((dp = dp->sibling) != NULL) {
-			child->next = ebus_alloc(sizeof(struct linux_ebus_child));
-
-			child = child->next;
-			child->next = NULL;
-			child->parent = dev;
-			child->bus = dev->bus;
-			fill_ebus_child(dp, child,
-					child_regs_nonstandard(dev));
-		}
-	}
-	printk("]");
-}
-
-static struct pci_dev *find_next_ebus(struct pci_dev *start, int *is_rio_p)
-{
-	struct pci_dev *pdev = start;
-
-	while ((pdev = pci_get_device(PCI_VENDOR_ID_SUN, PCI_ANY_ID, pdev)))
-		if (pdev->device == PCI_DEVICE_ID_SUN_EBUS ||
-			pdev->device == PCI_DEVICE_ID_SUN_RIO_EBUS)
-			break;
-
-	*is_rio_p = !!(pdev && (pdev->device == PCI_DEVICE_ID_SUN_RIO_EBUS));
-
-	return pdev;
-}
-
-void __init ebus_init(void)
-{
-	struct linux_ebus_device *dev;
-	struct linux_ebus *ebus;
-	struct pci_dev *pdev;
-	struct device_node *dp;
-	int is_rio;
-	int num_ebus = 0;
-
-	pdev = find_next_ebus(NULL, &is_rio);
-	if (!pdev) {
-		printk("ebus: No EBus's found.\n");
-		return;
-	}
-
-	dp = pci_device_to_OF_node(pdev);
-
-	ebus_chain = ebus = ebus_alloc(sizeof(struct linux_ebus));
-	ebus->next = NULL;
-	ebus->is_rio = is_rio;
-
-	while (dp) {
-		struct device_node *child;
-
-		/* SUNW,pci-qfe uses four empty ebuses on it.
-		   I think we should not consider them here,
-		   as they have half of the properties this
-		   code expects and once we do PCI hot-plug,
-		   we'd have to tweak with the ebus_chain
-		   in the runtime after initialization. -jj */
-		if (!dp->child) {
-			pdev = find_next_ebus(pdev, &is_rio);
-			if (!pdev) {
-				if (ebus == ebus_chain) {
-					ebus_chain = NULL;
-					printk("ebus: No EBus's found.\n");
-					return;
-				}
-				break;
-			}
-			ebus->is_rio = is_rio;
-			dp = pci_device_to_OF_node(pdev);
-			continue;
-		}
-		printk("ebus%d:", num_ebus);
-
-		ebus->index = num_ebus;
-		ebus->prom_node = dp;
-		ebus->self = pdev;
-
-		ebus->ofdev.node = dp;
-		ebus->ofdev.dev.parent = &pdev->dev;
-		ebus->ofdev.dev.bus = &ebus_bus_type;
-		dev_set_name(&ebus->ofdev.dev, "ebus%d", num_ebus);
-
-		/* Register with core */
-		if (of_device_register(&ebus->ofdev) != 0)
-			printk(KERN_DEBUG "ebus: device registration error for %s!\n",
-			       dp->path_component_name);
-
-
-		child = dp->child;
-		if (!child)
-			goto next_ebus;
-
-		ebus->devices = ebus_alloc(sizeof(struct linux_ebus_device));
-
-		dev = ebus->devices;
-		dev->next = NULL;
-		dev->children = NULL;
-		dev->bus = ebus;
-		fill_ebus_device(child, dev);
-
-		while ((child = child->sibling) != NULL) {
-			dev->next = ebus_alloc(sizeof(struct linux_ebus_device));
-
-			dev = dev->next;
-			dev->next = NULL;
-			dev->children = NULL;
-			dev->bus = ebus;
-			fill_ebus_device(child, dev);
-		}
-
-	next_ebus:
-		printk("\n");
-
-		pdev = find_next_ebus(pdev, &is_rio);
-		if (!pdev)
-			break;
-
-		dp = pci_device_to_OF_node(pdev);
-
-		ebus->next = ebus_alloc(sizeof(struct linux_ebus));
-		ebus = ebus->next;
-		ebus->next = NULL;
-		ebus->is_rio = is_rio;
-		++num_ebus;
-	}
-	pci_dev_put(pdev); /* XXX for the case, when ebusnd is 0, is it OK? */
-}
diff --git a/arch/sparc64/kernel/entry.h b/arch/sparc64/kernel/entry.h
index fc294a2..34d7ab5 100644
--- a/arch/sparc64/kernel/entry.h
+++ b/arch/sparc64/kernel/entry.h
@@ -5,8 +5,8 @@
 #include <linux/types.h>
 #include <linux/init.h>
 
-extern char *sparc_cpu_type;
-extern char *sparc_fpu_type;
+extern const char *sparc_cpu_type;
+extern const char *sparc_fpu_type;
 
 extern void __init per_cpu_patch(void);
 extern void __init sun4v_patch(void);
@@ -22,7 +22,8 @@
 			     unsigned long orig_i0,
 			     unsigned long thread_info_flags);
 
-extern asmlinkage int syscall_trace(struct pt_regs *regs, int syscall_exit_p);
+extern asmlinkage int syscall_trace_enter(struct pt_regs *regs);
+extern asmlinkage void syscall_trace_leave(struct pt_regs *regs);
 
 extern void bad_trap_tl1(struct pt_regs *regs, long lvl);
 
diff --git a/arch/sparc64/kernel/head.S b/arch/sparc64/kernel/head.S
index c9afef0..353226f 100644
--- a/arch/sparc64/kernel/head.S
+++ b/arch/sparc64/kernel/head.S
@@ -10,6 +10,7 @@
 #include <linux/errno.h>
 #include <linux/threads.h>
 #include <linux/init.h>
+#include <linux/linkage.h>
 #include <asm/thread_info.h>
 #include <asm/asi.h>
 #include <asm/pstate.h>
diff --git a/arch/sparc64/kernel/hvapi.c b/arch/sparc64/kernel/hvapi.c
index 691760b..1d272c3 100644
--- a/arch/sparc64/kernel/hvapi.c
+++ b/arch/sparc64/kernel/hvapi.c
@@ -9,7 +9,6 @@
 
 #include <asm/hypervisor.h>
 #include <asm/oplib.h>
-#include <asm/sstate.h>
 
 /* If the hypervisor indicates that the API setting
  * calls are unsupported, by returning HV_EBADTRAP or
@@ -184,8 +183,6 @@
 	if (sun4v_hvapi_register(group, major, &minor))
 		goto bad;
 
-	sun4v_sstate_init();
-
 	return;
 
 bad:
diff --git a/arch/sparc64/kernel/hvcalls.S b/arch/sparc64/kernel/hvcalls.S
index a2810f3..e066269 100644
--- a/arch/sparc64/kernel/hvcalls.S
+++ b/arch/sparc64/kernel/hvcalls.S
@@ -3,89 +3,75 @@
 	 *
 	 * returns %o0: sysino
 	 */
-	.globl	sun4v_devino_to_sysino
-	.type	sun4v_devino_to_sysino,#function
-sun4v_devino_to_sysino:
+ENTRY(sun4v_devino_to_sysino)
 	mov	HV_FAST_INTR_DEVINO2SYSINO, %o5
 	ta	HV_FAST_TRAP
 	retl
 	 mov	%o1, %o0
-	.size	sun4v_devino_to_sysino, .-sun4v_devino_to_sysino
+ENDPROC(sun4v_devino_to_sysino)
 
 	/* %o0: sysino
 	 *
 	 * returns %o0: intr_enabled (HV_INTR_{DISABLED,ENABLED})
 	 */
-	.globl	sun4v_intr_getenabled
-	.type	sun4v_intr_getenabled,#function
-sun4v_intr_getenabled:
+ENTRY(sun4v_intr_getenabled)
 	mov	HV_FAST_INTR_GETENABLED, %o5
 	ta	HV_FAST_TRAP
 	retl
 	 mov	%o1, %o0
-	.size	sun4v_intr_getenabled, .-sun4v_intr_getenabled
+ENDPROC(sun4v_intr_getenabled)
 
 	/* %o0: sysino
 	 * %o1: intr_enabled (HV_INTR_{DISABLED,ENABLED})
 	 */
-	.globl	sun4v_intr_setenabled
-	.type	sun4v_intr_setenabled,#function
-sun4v_intr_setenabled:
+ENTRY(sun4v_intr_setenabled)
 	mov	HV_FAST_INTR_SETENABLED, %o5
 	ta	HV_FAST_TRAP
 	retl
 	 nop
-	.size	sun4v_intr_setenabled, .-sun4v_intr_setenabled
+ENDPROC(sun4v_intr_setenabled)
 
 	/* %o0: sysino
 	 *
 	 * returns %o0: intr_state (HV_INTR_STATE_*)
 	 */
-	.globl	sun4v_intr_getstate
-	.type	sun4v_intr_getstate,#function
-sun4v_intr_getstate:
+ENTRY(sun4v_intr_getstate)
 	mov	HV_FAST_INTR_GETSTATE, %o5
 	ta	HV_FAST_TRAP
 	retl
 	 mov	%o1, %o0
-	.size	sun4v_intr_getstate, .-sun4v_intr_getstate
+ENDPROC(sun4v_intr_getstate)
 
 	/* %o0: sysino
 	 * %o1: intr_state (HV_INTR_STATE_*)
 	 */
-	.globl	sun4v_intr_setstate
-	.type	sun4v_intr_setstate,#function
-sun4v_intr_setstate:
+ENTRY(sun4v_intr_setstate)
 	mov	HV_FAST_INTR_SETSTATE, %o5
 	ta	HV_FAST_TRAP
 	retl
 	 nop
-	.size	sun4v_intr_setstate, .-sun4v_intr_setstate
+ENDPROC(sun4v_intr_setstate)
 
 	/* %o0: sysino
 	 *
 	 * returns %o0: cpuid
 	 */
-	.globl	sun4v_intr_gettarget
-	.type	sun4v_intr_gettarget,#function
-sun4v_intr_gettarget:
+ENTRY(sun4v_intr_gettarget)
 	mov	HV_FAST_INTR_GETTARGET, %o5
 	ta	HV_FAST_TRAP
 	retl
 	 mov	%o1, %o0
-	.size	sun4v_intr_gettarget, .-sun4v_intr_gettarget
+ENDPROC(sun4v_intr_gettarget)
 
 	/* %o0: sysino
 	 * %o1: cpuid
 	 */
-	.globl	sun4v_intr_settarget
-	.type	sun4v_intr_settarget,#function
-sun4v_intr_settarget:
+ENTRY(sun4v_intr_settarget)
 	mov	HV_FAST_INTR_SETTARGET, %o5
 	ta	HV_FAST_TRAP
 	retl
 	 nop
-	.size	sun4v_intr_settarget, .-sun4v_intr_settarget
+ENDPROC(sun4v_intr_settarget)
 
 	/* %o0:	cpuid
 	 * %o1: pc
@@ -94,37 +80,31 @@
 	 *
 	 * returns %o0:	status
 	 */
-	.globl	sun4v_cpu_start
-	.type	sun4v_cpu_start,#function
-sun4v_cpu_start:
+ENTRY(sun4v_cpu_start)
 	mov	HV_FAST_CPU_START, %o5
 	ta	HV_FAST_TRAP
 	retl
 	 nop
-	.size	sun4v_cpu_start, .-sun4v_cpu_start
+ENDPROC(sun4v_cpu_start)
 
 	/* %o0:	cpuid
 	 *
 	 * returns %o0: status
 	 */
-	.globl	sun4v_cpu_stop
-	.type	sun4v_cpu_stop,#function
-sun4v_cpu_stop:
+ENTRY(sun4v_cpu_stop)
 	mov	HV_FAST_CPU_STOP, %o5
 	ta	HV_FAST_TRAP
 	retl
 	 nop
-	.size	sun4v_cpu_stop, .-sun4v_cpu_stop
+ENDPROC(sun4v_cpu_stop)
 
 	/* returns %o0:	status  */
-	.globl	sun4v_cpu_yield
-	.type	sun4v_cpu_yield, #function
-sun4v_cpu_yield:
+ENTRY(sun4v_cpu_yield)
 	mov	HV_FAST_CPU_YIELD, %o5
 	ta	HV_FAST_TRAP
 	retl
 	 nop
-	.size	sun4v_cpu_yield, .-sun4v_cpu_yield
+ENDPROC(sun4v_cpu_yield)
 
 	/* %o0:	type
 	 * %o1:	queue paddr
@@ -132,14 +112,12 @@
 	 *
 	 * returns %o0:	status
 	 */
-	.globl	sun4v_cpu_qconf
-	.type	sun4v_cpu_qconf,#function
-sun4v_cpu_qconf:
+ENTRY(sun4v_cpu_qconf)
 	mov	HV_FAST_CPU_QCONF, %o5
 	ta	HV_FAST_TRAP
 	retl
 	 nop
-	.size	sun4v_cpu_qconf, .-sun4v_cpu_qconf
+ENDPROC(sun4v_cpu_qconf)
 
 	/* %o0:	num cpus in cpu list
 	 * %o1:	cpu list paddr
@@ -147,23 +125,19 @@
 	 *
 	 * returns %o0: status
 	 */
-	.globl	sun4v_cpu_mondo_send
-	.type	sun4v_cpu_mondo_send,#function
-sun4v_cpu_mondo_send:
+ENTRY(sun4v_cpu_mondo_send)
 	mov	HV_FAST_CPU_MONDO_SEND, %o5
 	ta	HV_FAST_TRAP
 	retl
 	 nop
-	.size	sun4v_cpu_mondo_send, .-sun4v_cpu_mondo_send
+ENDPROC(sun4v_cpu_mondo_send)
 
 	/* %o0:	CPU ID
 	 *
 	 * returns %o0:	-status if status non-zero, else
 	 *         %o0:	cpu state as HV_CPU_STATE_*
 	 */
-	.globl	sun4v_cpu_state
-	.type	sun4v_cpu_state,#function
-sun4v_cpu_state:
+ENTRY(sun4v_cpu_state)
 	mov	HV_FAST_CPU_STATE, %o5
 	ta	HV_FAST_TRAP
 	brnz,pn	%o0, 1f
@@ -171,7 +145,7 @@
 	mov	%o1, %o0
 1:	retl
 	 nop
-	.size	sun4v_cpu_state, .-sun4v_cpu_state
+ENDPROC(sun4v_cpu_state)
 
 	/* %o0: virtual address
 	 * %o1: must be zero
@@ -180,28 +154,24 @@
 	 *
 	 * returns %o0: status
 	 */
-	.globl	sun4v_mmu_map_perm_addr
-	.type	sun4v_mmu_map_perm_addr,#function
-sun4v_mmu_map_perm_addr:
+ENTRY(sun4v_mmu_map_perm_addr)
 	mov	HV_FAST_MMU_MAP_PERM_ADDR, %o5
 	ta	HV_FAST_TRAP
 	retl
 	 nop
-	.size	sun4v_mmu_map_perm_addr, .-sun4v_mmu_map_perm_addr
+ENDPROC(sun4v_mmu_map_perm_addr)
 
 	/* %o0: number of TSB descriptions
 	 * %o1: TSB descriptions real address
 	 *
 	 * returns %o0: status
 	 */
-	.globl	sun4v_mmu_tsb_ctx0
-	.type	sun4v_mmu_tsb_ctx0,#function
-sun4v_mmu_tsb_ctx0:
+ENTRY(sun4v_mmu_tsb_ctx0)
 	mov	HV_FAST_MMU_TSB_CTX0, %o5
 	ta	HV_FAST_TRAP
 	retl
 	 nop
-	.size	sun4v_mmu_tsb_ctx0, .-sun4v_mmu_tsb_ctx0
+ENDPROC(sun4v_mmu_tsb_ctx0)
 
 	/* %o0:	API group number
 	 * %o1: pointer to unsigned long major number storage
@@ -209,9 +179,7 @@
 	 *
 	 * returns %o0: status
 	 */
-	.globl	sun4v_get_version
-	.type	sun4v_get_version,#function
-sun4v_get_version:
+ENTRY(sun4v_get_version)
 	mov	HV_CORE_GET_VER, %o5
 	mov	%o1, %o3
 	mov	%o2, %o4
@@ -219,7 +187,7 @@
 	stx	%o1, [%o3]
 	retl
 	 stx	%o2, [%o4]
-	.size	sun4v_get_version, .-sun4v_get_version
+ENDPROC(sun4v_get_version)
 
 	/* %o0: API group number
 	 * %o1: desired major number
@@ -228,51 +196,43 @@
 	 *
 	 * returns %o0: status
 	 */
-	.globl	sun4v_set_version
-	.type	sun4v_set_version,#function
-sun4v_set_version:
+ENTRY(sun4v_set_version)
 	mov	HV_CORE_SET_VER, %o5
 	mov	%o3, %o4
 	ta	HV_CORE_TRAP
 	retl
 	 stx	%o1, [%o4]
-	.size	sun4v_set_version, .-sun4v_set_version
+ENDPROC(sun4v_set_version)
 
 	/* %o0: pointer to unsigned long time
 	 *
 	 * returns %o0: status
 	 */
-	.globl	sun4v_tod_get
-	.type	sun4v_tod_get,#function
-sun4v_tod_get:
+ENTRY(sun4v_tod_get)
 	mov	%o0, %o4
 	mov	HV_FAST_TOD_GET, %o5
 	ta	HV_FAST_TRAP
 	stx	%o1, [%o4]
 	retl
 	 nop
-	.size	sun4v_tod_get, .-sun4v_tod_get
+ENDPROC(sun4v_tod_get)
 
 	/* %o0: time
 	 *
 	 * returns %o0: status
 	 */
-	.globl	sun4v_tod_set
-	.type	sun4v_tod_set,#function
-sun4v_tod_set:
+ENTRY(sun4v_tod_set)
 	mov	HV_FAST_TOD_SET, %o5
 	ta	HV_FAST_TRAP
 	retl
 	 nop
-	.size	sun4v_tod_set, .-sun4v_tod_set
+ENDPROC(sun4v_tod_set)
 
 	/* %o0: pointer to unsigned long status
 	 *
 	 * returns %o0: signed character
 	 */
-	.globl	sun4v_con_getchar
-	.type	sun4v_con_getchar,#function
-sun4v_con_getchar:
+ENTRY(sun4v_con_getchar)
 	mov	%o0, %o4
 	mov	HV_FAST_CONS_GETCHAR, %o5
 	clr	%o0
@@ -281,20 +241,18 @@
 	stx	%o0, [%o4]
 	retl
 	 sra	%o1, 0, %o0
-	.size	sun4v_con_getchar, .-sun4v_con_getchar
+ENDPROC(sun4v_con_getchar)
 
 	/* %o0: signed long character
 	 *
 	 * returns %o0: status
 	 */
-	.globl	sun4v_con_putchar
-	.type	sun4v_con_putchar,#function
-sun4v_con_putchar:
+ENTRY(sun4v_con_putchar)
 	mov	HV_FAST_CONS_PUTCHAR, %o5
 	ta	HV_FAST_TRAP
 	retl
 	 sra	%o0, 0, %o0
-	.size	sun4v_con_putchar, .-sun4v_con_putchar
+ENDPROC(sun4v_con_putchar)
 
 	/* %o0: buffer real address
 	 * %o1: buffer size
@@ -302,9 +260,7 @@
 	 *
 	 * returns %o0: status
 	 */
-	.globl	sun4v_con_read
-	.type	sun4v_con_read,#function
-sun4v_con_read:
+ENTRY(sun4v_con_read)
 	mov	%o2, %o4
 	mov	HV_FAST_CONS_READ, %o5
 	ta	HV_FAST_TRAP
@@ -318,7 +274,7 @@
 	stx	%o1, [%o4]
 1:	retl
 	 nop
-	.size	sun4v_con_read, .-sun4v_con_read
+ENDPROC(sun4v_con_read)
 
 	/* %o0: buffer real address
 	 * %o1: buffer size
@@ -326,43 +282,37 @@
 	 *
 	 * returns %o0: status
 	 */
-	.globl	sun4v_con_write
-	.type	sun4v_con_write,#function
-sun4v_con_write:
+ENTRY(sun4v_con_write)
 	mov	%o2, %o4
 	mov	HV_FAST_CONS_WRITE, %o5
 	ta	HV_FAST_TRAP
 	stx	%o1, [%o4]
 	retl
 	 nop
-	.size	sun4v_con_write, .-sun4v_con_write
+ENDPROC(sun4v_con_write)
 
 	/* %o0:	soft state
 	 * %o1:	address of description string
 	 *
 	 * returns %o0: status
 	 */
-	.globl	sun4v_mach_set_soft_state
-	.type	sun4v_mach_set_soft_state,#function
-sun4v_mach_set_soft_state:
+ENTRY(sun4v_mach_set_soft_state)
 	mov	HV_FAST_MACH_SET_SOFT_STATE, %o5
 	ta	HV_FAST_TRAP
 	retl
 	 nop
-	.size	sun4v_mach_set_soft_state, .-sun4v_mach_set_soft_state
+ENDPROC(sun4v_mach_set_soft_state)
 
 	/* %o0: exit code
 	 *
 	 * Does not return.
 	 */
-	.globl	sun4v_mach_exit
-	.type	sun4v_mach_exit,#function
-sun4v_mach_exit:
+ENTRY(sun4v_mach_exit)
 	mov	HV_FAST_MACH_EXIT, %o5
 	ta	HV_FAST_TRAP
 	retl
 	 nop
-	.size	sun4v_mach_exit, .-sun4v_mach_exit
+ENDPROC(sun4v_mach_exit)
 
 	/* %o0: buffer real address
 	 * %o1: buffer length
@@ -370,44 +320,38 @@
 	 *
 	 * returns %o0: status
 	 */
-	.globl	sun4v_mach_desc
-	.type	sun4v_mach_desc,#function
-sun4v_mach_desc:
+ENTRY(sun4v_mach_desc)
 	mov	%o2, %o4
 	mov	HV_FAST_MACH_DESC, %o5
 	ta	HV_FAST_TRAP
 	stx	%o1, [%o4]
 	retl
 	 nop
-	.size	sun4v_mach_desc, .-sun4v_mach_desc
+ENDPROC(sun4v_mach_desc)
 
 	/* %o0: new timeout in milliseconds
 	 * %o1: pointer to unsigned long orig_timeout
 	 *
 	 * returns %o0: status
 	 */
-	.globl	sun4v_mach_set_watchdog
-	.type	sun4v_mach_set_watchdog,#function
-sun4v_mach_set_watchdog:
+ENTRY(sun4v_mach_set_watchdog)
 	mov	%o1, %o4
 	mov	HV_FAST_MACH_SET_WATCHDOG, %o5
 	ta	HV_FAST_TRAP
 	stx	%o1, [%o4]
 	retl
 	 nop
-	.size	sun4v_mach_set_watchdog, .-sun4v_mach_set_watchdog
+ENDPROC(sun4v_mach_set_watchdog)
 
 	/* No inputs and does not return.  */
-	.globl	sun4v_mach_sir
-	.type	sun4v_mach_sir,#function
-sun4v_mach_sir:
+ENTRY(sun4v_mach_sir)
 	mov	%o1, %o4
 	mov	HV_FAST_MACH_SIR, %o5
 	ta	HV_FAST_TRAP
 	stx	%o1, [%o4]
 	retl
 	 nop
-	.size	sun4v_mach_sir, .-sun4v_mach_sir
+ENDPROC(sun4v_mach_sir)
 
 	/* %o0: channel
 	 * %o1:	ra
@@ -415,14 +359,12 @@
 	 *
 	 * returns %o0:	status
 	 */
-	.globl	sun4v_ldc_tx_qconf
-	.type	sun4v_ldc_tx_qconf,#function
-sun4v_ldc_tx_qconf:
+ENTRY(sun4v_ldc_tx_qconf)
 	mov	HV_FAST_LDC_TX_QCONF, %o5
 	ta	HV_FAST_TRAP
 	retl
 	 nop
-	.size	sun4v_ldc_tx_qconf, .-sun4v_ldc_tx_qconf
+ENDPROC(sun4v_ldc_tx_qconf)
 
 	/* %o0: channel
 	 * %o1:	pointer to unsigned long ra
@@ -430,9 +372,7 @@
 	 *
 	 * returns %o0:	status
 	 */
-	.globl	sun4v_ldc_tx_qinfo
-	.type	sun4v_ldc_tx_qinfo,#function
-sun4v_ldc_tx_qinfo:
+ENTRY(sun4v_ldc_tx_qinfo)
 	mov	%o1, %g1
 	mov	%o2, %g2
 	mov	HV_FAST_LDC_TX_QINFO, %o5
@@ -441,7 +381,7 @@
 	stx	%o2, [%g2]
 	retl
 	 nop
-	.size	sun4v_ldc_tx_qinfo, .-sun4v_ldc_tx_qinfo
+ENDPROC(sun4v_ldc_tx_qinfo)
 
 	/* %o0: channel
 	 * %o1:	pointer to unsigned long head_off
@@ -450,9 +390,7 @@
 	 *
 	 * returns %o0:	status
 	 */
-	.globl	sun4v_ldc_tx_get_state
-	.type	sun4v_ldc_tx_get_state,#function
-sun4v_ldc_tx_get_state:
+ENTRY(sun4v_ldc_tx_get_state)
 	mov	%o1, %g1
 	mov	%o2, %g2
 	mov	%o3, %g3
@@ -463,21 +401,19 @@
 	stx	%o3, [%g3]
 	retl
 	 nop
-	.size	sun4v_ldc_tx_get_state, .-sun4v_ldc_tx_get_state
+ENDPROC(sun4v_ldc_tx_get_state)
 
 	/* %o0: channel
 	 * %o1:	tail_off
 	 *
 	 * returns %o0:	status
 	 */
-	.globl	sun4v_ldc_tx_set_qtail
-	.type	sun4v_ldc_tx_set_qtail,#function
-sun4v_ldc_tx_set_qtail:
+ENTRY(sun4v_ldc_tx_set_qtail)
 	mov	HV_FAST_LDC_TX_SET_QTAIL, %o5
 	ta	HV_FAST_TRAP
 	retl
 	 nop
-	.size	sun4v_ldc_tx_set_qtail, .-sun4v_ldc_tx_set_qtail
+ENDPROC(sun4v_ldc_tx_set_qtail)
 
 	/* %o0: channel
 	 * %o1:	ra
@@ -485,14 +421,12 @@
 	 *
 	 * returns %o0:	status
 	 */
-	.globl	sun4v_ldc_rx_qconf
-	.type	sun4v_ldc_rx_qconf,#function
-sun4v_ldc_rx_qconf:
+ENTRY(sun4v_ldc_rx_qconf)
 	mov	HV_FAST_LDC_RX_QCONF, %o5
 	ta	HV_FAST_TRAP
 	retl
 	 nop
-	.size	sun4v_ldc_rx_qconf, .-sun4v_ldc_rx_qconf
+ENDPROC(sun4v_ldc_rx_qconf)
 
 	/* %o0: channel
 	 * %o1:	pointer to unsigned long ra
@@ -500,9 +434,7 @@
 	 *
 	 * returns %o0:	status
 	 */
-	.globl	sun4v_ldc_rx_qinfo
-	.type	sun4v_ldc_rx_qinfo,#function
-sun4v_ldc_rx_qinfo:
+ENTRY(sun4v_ldc_rx_qinfo)
 	mov	%o1, %g1
 	mov	%o2, %g2
 	mov	HV_FAST_LDC_RX_QINFO, %o5
@@ -511,7 +443,7 @@
 	stx	%o2, [%g2]
 	retl
 	 nop
-	.size	sun4v_ldc_rx_qinfo, .-sun4v_ldc_rx_qinfo
+ENDPROC(sun4v_ldc_rx_qinfo)
 
 	/* %o0: channel
 	 * %o1:	pointer to unsigned long head_off
@@ -520,9 +452,7 @@
 	 *
 	 * returns %o0:	status
 	 */
-	.globl	sun4v_ldc_rx_get_state
-	.type	sun4v_ldc_rx_get_state,#function
-sun4v_ldc_rx_get_state:
+ENTRY(sun4v_ldc_rx_get_state)
 	mov	%o1, %g1
 	mov	%o2, %g2
 	mov	%o3, %g3
@@ -533,21 +463,19 @@
 	stx	%o3, [%g3]
 	retl
 	 nop
-	.size	sun4v_ldc_rx_get_state, .-sun4v_ldc_rx_get_state
+ENDPROC(sun4v_ldc_rx_get_state)
 
 	/* %o0: channel
 	 * %o1:	head_off
 	 *
 	 * returns %o0:	status
 	 */
-	.globl	sun4v_ldc_rx_set_qhead
-	.type	sun4v_ldc_rx_set_qhead,#function
-sun4v_ldc_rx_set_qhead:
+ENTRY(sun4v_ldc_rx_set_qhead)
 	mov	HV_FAST_LDC_RX_SET_QHEAD, %o5
 	ta	HV_FAST_TRAP
 	retl
 	 nop
-	.size	sun4v_ldc_rx_set_qhead, .-sun4v_ldc_rx_set_qhead
+ENDPROC(sun4v_ldc_rx_set_qhead)
 
 	/* %o0: channel
 	 * %o1:	ra
@@ -555,14 +483,12 @@
 	 *
 	 * returns %o0: status
 	 */
-	.globl	sun4v_ldc_set_map_table
-	.type	sun4v_ldc_set_map_table,#function
-sun4v_ldc_set_map_table:
+ENTRY(sun4v_ldc_set_map_table)
 	mov	HV_FAST_LDC_SET_MAP_TABLE, %o5
 	ta	HV_FAST_TRAP
 	retl
 	 nop
-	.size	sun4v_ldc_set_map_table, .-sun4v_ldc_set_map_table
+ENDPROC(sun4v_ldc_set_map_table)
 
 	/* %o0: channel
 	 * %o1:	pointer to unsigned long ra
@@ -570,9 +496,7 @@
 	 *
 	 * returns %o0: status
 	 */
-	.globl	sun4v_ldc_get_map_table
-	.type	sun4v_ldc_get_map_table,#function
-sun4v_ldc_get_map_table:
+ENTRY(sun4v_ldc_get_map_table)
 	mov	%o1, %g1
 	mov	%o2, %g2
 	mov	HV_FAST_LDC_GET_MAP_TABLE, %o5
@@ -581,7 +505,7 @@
 	stx	%o2, [%g2]
 	retl
 	 nop
-	.size	sun4v_ldc_get_map_table, .-sun4v_ldc_get_map_table
+ENDPROC(sun4v_ldc_get_map_table)
 
 	/* %o0:	channel
 	 * %o1:	dir_code
@@ -592,16 +516,14 @@
 	 *
 	 * returns %o0:	status
 	 */
-	.globl	sun4v_ldc_copy
-	.type	sun4v_ldc_copy,#function
-sun4v_ldc_copy:
+ENTRY(sun4v_ldc_copy)
 	mov	%o5, %g1
 	mov	HV_FAST_LDC_COPY, %o5
 	ta	HV_FAST_TRAP
 	stx	%o1, [%g1]
 	retl
 	 nop
-	.size	sun4v_ldc_copy, .-sun4v_ldc_copy
+ENDPROC(sun4v_ldc_copy)
 
 	/* %o0:	channel
 	 * %o1:	cookie
@@ -610,9 +532,7 @@
 	 *
 	 * returns %o0:	status
 	 */
-	.globl	sun4v_ldc_mapin
-	.type	sun4v_ldc_mapin,#function
-sun4v_ldc_mapin:
+ENTRY(sun4v_ldc_mapin)
 	mov	%o2, %g1
 	mov	%o3, %g2
 	mov	HV_FAST_LDC_MAPIN, %o5
@@ -621,20 +541,18 @@
 	stx	%o2, [%g2]
 	retl
 	 nop
-	.size	sun4v_ldc_mapin, .-sun4v_ldc_mapin
+ENDPROC(sun4v_ldc_mapin)
 
 	/* %o0:	ra
 	 *
 	 * returns %o0:	status
 	 */
-	.globl	sun4v_ldc_unmap
-	.type	sun4v_ldc_unmap,#function
-sun4v_ldc_unmap:
+ENTRY(sun4v_ldc_unmap)
 	mov	HV_FAST_LDC_UNMAP, %o5
 	ta	HV_FAST_TRAP
 	retl
 	 nop
-	.size	sun4v_ldc_unmap, .-sun4v_ldc_unmap
+ENDPROC(sun4v_ldc_unmap)
 
 	/* %o0: channel
 	 * %o1:	cookie
@@ -642,14 +560,12 @@
 	 *
 	 * returns %o0:	status
 	 */
-	.globl	sun4v_ldc_revoke
-	.type	sun4v_ldc_revoke,#function
-sun4v_ldc_revoke:
+ENTRY(sun4v_ldc_revoke)
 	mov	HV_FAST_LDC_REVOKE, %o5
 	ta	HV_FAST_TRAP
 	retl
 	 nop
-	.size	sun4v_ldc_revoke, .-sun4v_ldc_revoke
+ENDPROC(sun4v_ldc_revoke)
 
 	/* %o0: device handle
 	 * %o1:	device INO
@@ -657,16 +573,14 @@
 	 *
 	 * returns %o0: status
 	 */
-	.globl	sun4v_vintr_get_cookie
-	.type	sun4v_vintr_get_cookie,#function
-sun4v_vintr_get_cookie:
+ENTRY(sun4v_vintr_get_cookie)
 	mov	%o2, %g1
 	mov	HV_FAST_VINTR_GET_COOKIE, %o5
 	ta	HV_FAST_TRAP
 	stx	%o1, [%g1]
 	retl
 	 nop
-	.size	sun4v_vintr_get_cookie, .-sun4v_vintr_get_cookie
+ENDPROC(sun4v_vintr_get_cookie)
 
 	/* %o0: device handle
 	 * %o1:	device INO
@@ -674,14 +588,12 @@
 	 *
 	 * returns %o0: status
 	 */
-	.globl	sun4v_vintr_set_cookie
-	.type	sun4v_vintr_set_cookie,#function
-sun4v_vintr_set_cookie:
+ENTRY(sun4v_vintr_set_cookie)
 	mov	HV_FAST_VINTR_SET_COOKIE, %o5
 	ta	HV_FAST_TRAP
 	retl
 	 nop
-	.size	sun4v_vintr_set_cookie, .-sun4v_vintr_set_cookie
+ENDPROC(sun4v_vintr_set_cookie)
 
 	/* %o0: device handle
 	 * %o1:	device INO
@@ -689,16 +601,14 @@
 	 *
 	 * returns %o0: status
 	 */
-	.globl	sun4v_vintr_get_valid
-	.type	sun4v_vintr_get_valid,#function
-sun4v_vintr_get_valid:
+ENTRY(sun4v_vintr_get_valid)
 	mov	%o2, %g1
 	mov	HV_FAST_VINTR_GET_VALID, %o5
 	ta	HV_FAST_TRAP
 	stx	%o1, [%g1]
 	retl
 	 nop
-	.size	sun4v_vintr_get_valid, .-sun4v_vintr_get_valid
+ENDPROC(sun4v_vintr_get_valid)
 
 	/* %o0: device handle
 	 * %o1:	device INO
@@ -706,14 +616,12 @@
 	 *
 	 * returns %o0: status
 	 */
-	.globl	sun4v_vintr_set_valid
-	.type	sun4v_vintr_set_valid,#function
-sun4v_vintr_set_valid:
+ENTRY(sun4v_vintr_set_valid)
 	mov	HV_FAST_VINTR_SET_VALID, %o5
 	ta	HV_FAST_TRAP
 	retl
 	 nop
-	.size	sun4v_vintr_set_valid, .-sun4v_vintr_set_valid
+ENDPROC(sun4v_vintr_set_valid)
 
 	/* %o0: device handle
 	 * %o1:	device INO
@@ -721,16 +629,14 @@
 	 *
 	 * returns %o0: status
 	 */
-	.globl	sun4v_vintr_get_state
-	.type	sun4v_vintr_get_state,#function
-sun4v_vintr_get_state:
+ENTRY(sun4v_vintr_get_state)
 	mov	%o2, %g1
 	mov	HV_FAST_VINTR_GET_STATE, %o5
 	ta	HV_FAST_TRAP
 	stx	%o1, [%g1]
 	retl
 	 nop
-	.size	sun4v_vintr_get_state, .-sun4v_vintr_get_state
+ENDPROC(sun4v_vintr_get_state)
 
 	/* %o0: device handle
 	 * %o1:	device INO
@@ -738,14 +644,12 @@
 	 *
 	 * returns %o0: status
 	 */
-	.globl	sun4v_vintr_set_state
-	.type	sun4v_vintr_set_state,#function
-sun4v_vintr_set_state:
+ENTRY(sun4v_vintr_set_state)
 	mov	HV_FAST_VINTR_SET_STATE, %o5
 	ta	HV_FAST_TRAP
 	retl
 	 nop
-	.size	sun4v_vintr_set_state, .-sun4v_vintr_set_state
+ENDPROC(sun4v_vintr_set_state)
 
 	/* %o0: device handle
 	 * %o1:	device INO
@@ -753,16 +657,14 @@
 	 *
 	 * returns %o0: status
 	 */
-	.globl	sun4v_vintr_get_target
-	.type	sun4v_vintr_get_target,#function
-sun4v_vintr_get_target:
+ENTRY(sun4v_vintr_get_target)
 	mov	%o2, %g1
 	mov	HV_FAST_VINTR_GET_TARGET, %o5
 	ta	HV_FAST_TRAP
 	stx	%o1, [%g1]
 	retl
 	 nop
-	.size	sun4v_vintr_get_target, .-sun4v_vintr_get_target
+ENDPROC(sun4v_vintr_get_target)
 
 	/* %o0: device handle
 	 * %o1:	device INO
@@ -770,14 +672,12 @@
 	 *
 	 * returns %o0: status
 	 */
-	.globl	sun4v_vintr_set_target
-	.type	sun4v_vintr_set_target,#function
-sun4v_vintr_set_target:
+ENTRY(sun4v_vintr_set_target)
 	mov	HV_FAST_VINTR_SET_TARGET, %o5
 	ta	HV_FAST_TRAP
 	retl
 	 nop
-	.size	sun4v_vintr_set_target, .-sun4v_vintr_set_target
+ENDPROC(sun4v_vintr_set_target)
 
 	/* %o0: NCS sub-function
 	 * %o1:	sub-function arg real-address
@@ -785,18 +685,14 @@
 	 *
 	 * returns %o0:	status
 	 */
-	.globl	sun4v_ncs_request
-	.type	sun4v_ncs_request,#function
-sun4v_ncs_request:
+ENTRY(sun4v_ncs_request)
 	mov	HV_FAST_NCS_REQUEST, %o5
 	ta	HV_FAST_TRAP
 	retl
 	 nop
-	.size	sun4v_ncs_request, .-sun4v_ncs_request
+ENDPROC(sun4v_ncs_request)
 
-	.globl	sun4v_svc_send
-	.type	sun4v_svc_send,#function
-sun4v_svc_send:
+ENTRY(sun4v_svc_send)
 	save	%sp, -192, %sp
 	mov	%i0, %o0
 	mov	%i1, %o1
@@ -806,11 +702,9 @@
 	stx	%o1, [%i3]
 	ret
 	restore
-	.size	sun4v_svc_send, .-sun4v_svc_send
+ENDPROC(sun4v_svc_send)
 
-	.globl	sun4v_svc_recv
-	.type	sun4v_svc_recv,#function
-sun4v_svc_recv:
+ENTRY(sun4v_svc_recv)
 	save	%sp, -192, %sp
 	mov	%i0, %o0
 	mov	%i1, %o1
@@ -820,62 +714,50 @@
 	stx	%o1, [%i3]
 	ret
 	restore
-	.size	sun4v_svc_recv, .-sun4v_svc_recv
+ENDPROC(sun4v_svc_recv)
 
-	.globl	sun4v_svc_getstatus
-	.type	sun4v_svc_getstatus,#function
-sun4v_svc_getstatus:
+ENTRY(sun4v_svc_getstatus)
 	mov	HV_FAST_SVC_GETSTATUS, %o5
 	mov	%o1, %o4
 	ta	HV_FAST_TRAP
 	stx	%o1, [%o4]
 	retl
 	 nop
-	.size	sun4v_svc_getstatus, .-sun4v_svc_getstatus
+ENDPROC(sun4v_svc_getstatus)
 
-	.globl	sun4v_svc_setstatus
-	.type	sun4v_svc_setstatus,#function
-sun4v_svc_setstatus:
+ENTRY(sun4v_svc_setstatus)
 	mov	HV_FAST_SVC_SETSTATUS, %o5
 	ta	HV_FAST_TRAP
 	retl
 	 nop
-	.size	sun4v_svc_setstatus, .-sun4v_svc_setstatus
+ENDPROC(sun4v_svc_setstatus)
 
-	.globl	sun4v_svc_clrstatus
-	.type	sun4v_svc_clrstatus,#function
-sun4v_svc_clrstatus:
+ENTRY(sun4v_svc_clrstatus)
 	mov	HV_FAST_SVC_CLRSTATUS, %o5
 	ta	HV_FAST_TRAP
 	retl
 	 nop
-	.size	sun4v_svc_clrstatus, .-sun4v_svc_clrstatus
+ENDPROC(sun4v_svc_clrstatus)
 
-	.globl	sun4v_mmustat_conf
-	.type	sun4v_mmustat_conf,#function
-sun4v_mmustat_conf:
+ENTRY(sun4v_mmustat_conf)
 	mov	%o1, %o4
 	mov	HV_FAST_MMUSTAT_CONF, %o5
 	ta	HV_FAST_TRAP
 	stx	%o1, [%o4]
 	retl
 	 nop
-	.size	sun4v_mmustat_conf, .-sun4v_mmustat_conf
+ENDPROC(sun4v_mmustat_conf)
 
-	.globl	sun4v_mmustat_info
-	.type	sun4v_mmustat_info,#function
-sun4v_mmustat_info:
+ENTRY(sun4v_mmustat_info)
 	mov	%o0, %o4
 	mov	HV_FAST_MMUSTAT_INFO, %o5
 	ta	HV_FAST_TRAP
 	stx	%o1, [%o4]
 	retl
 	 nop
-	.size	sun4v_mmustat_info, .-sun4v_mmustat_info
+ENDPROC(sun4v_mmustat_info)
 
-	.globl	sun4v_mmu_demap_all
-	.type	sun4v_mmu_demap_all,#function
-sun4v_mmu_demap_all:
+ENTRY(sun4v_mmu_demap_all)
 	clr	%o0
 	clr	%o1
 	mov	HV_MMU_ALL, %o2
@@ -883,4 +765,4 @@
 	ta	HV_FAST_TRAP
 	retl
 	 nop
-	.size	sun4v_mmu_demap_all, .-sun4v_mmu_demap_all
+ENDPROC(sun4v_mmu_demap_all)
diff --git a/arch/sparc64/kernel/irq.c b/arch/sparc64/kernel/irq.c
index 2396388..52fc836 100644
--- a/arch/sparc64/kernel/irq.c
+++ b/arch/sparc64/kernel/irq.c
@@ -7,6 +7,7 @@
 
 #include <linux/module.h>
 #include <linux/sched.h>
+#include <linux/linkage.h>
 #include <linux/ptrace.h>
 #include <linux/errno.h>
 #include <linux/kernel_stat.h>
@@ -28,7 +29,6 @@
 #include <asm/system.h>
 #include <asm/irq.h>
 #include <asm/io.h>
-#include <asm/sbus.h>
 #include <asm/iommu.h>
 #include <asm/upa.h>
 #include <asm/oplib.h>
@@ -866,7 +866,7 @@
 	: "g1", "g2");
 }
 
-void init_irqwork_curcpu(void)
+void notrace init_irqwork_curcpu(void)
 {
 	int cpu = hard_smp_processor_id();
 
@@ -897,7 +897,7 @@
 	}
 }
 
-void __cpuinit sun4v_register_mondo_queues(int this_cpu)
+void __cpuinit notrace sun4v_register_mondo_queues(int this_cpu)
 {
 	struct trap_per_cpu *tb = &trap_block[this_cpu];
 
diff --git a/arch/sparc64/kernel/of_device.c b/arch/sparc64/kernel/of_device.c
index f845f15..0f616ae 100644
--- a/arch/sparc64/kernel/of_device.c
+++ b/arch/sparc64/kernel/of_device.c
@@ -55,15 +55,38 @@
 }
 EXPORT_SYMBOL(of_find_device_by_node);
 
-#ifdef CONFIG_PCI
-struct bus_type ebus_bus_type;
-EXPORT_SYMBOL(ebus_bus_type);
-#endif
+unsigned int irq_of_parse_and_map(struct device_node *node, int index)
+{
+	struct of_device *op = of_find_device_by_node(node);
 
-#ifdef CONFIG_SBUS
-struct bus_type sbus_bus_type;
-EXPORT_SYMBOL(sbus_bus_type);
-#endif
+	if (!op || index >= op->num_irqs)
+		return 0;
+
+	return op->irqs[index];
+}
+EXPORT_SYMBOL(irq_of_parse_and_map);
+
+/* Take the archdata values for IOMMU, STC, and HOSTDATA found in
+ * BUS and propagate to all child of_device objects.
+ */
+void of_propagate_archdata(struct of_device *bus)
+{
+	struct dev_archdata *bus_sd = &bus->dev.archdata;
+	struct device_node *bus_dp = bus->node;
+	struct device_node *dp;
+
+	for (dp = bus_dp->child; dp; dp = dp->sibling) {
+		struct of_device *op = of_find_device_by_node(dp);
+
+		op->dev.archdata.iommu = bus_sd->iommu;
+		op->dev.archdata.stc = bus_sd->stc;
+		op->dev.archdata.host_controller = bus_sd->host_controller;
+		op->dev.archdata.numa_node = bus_sd->numa_node;
+
+		if (dp->child)
+			of_propagate_archdata(op);
+	}
+}
 
 struct bus_type of_platform_bus_type;
 EXPORT_SYMBOL(of_platform_bus_type);
@@ -169,7 +192,7 @@
 
 static int of_bus_pci_match(struct device_node *np)
 {
-	if (!strcmp(np->type, "pci") || !strcmp(np->type, "pciex")) {
+	if (!strcmp(np->name, "pci")) {
 		const char *model = of_get_property(np, "model", NULL);
 
 		if (model && !strcmp(model, "SUNW,simba"))
@@ -200,7 +223,7 @@
 	/* Treat PCI busses lacking ranges property just like
 	 * simba.
 	 */
-	if (!strcmp(np->type, "pci") || !strcmp(np->type, "pciex")) {
+	if (!strcmp(np->name, "pci")) {
 		if (!of_find_property(np, "ranges", NULL))
 			return 1;
 	}
@@ -378,8 +401,7 @@
 				     int na, int ns, int pna)
 {
 	const u32 *ranges;
-	unsigned int rlen;
-	int rone;
+	int rone, rlen;
 
 	ranges = of_get_property(parent, "ranges", &rlen);
 	if (ranges == NULL || rlen == 0) {
@@ -421,15 +443,24 @@
 
 	/* If the parent is the dma node of an ISA bus, pass
 	 * the translation up to the root.
+	 *
+	 * Some SBUS devices use intermediate nodes to express
+	 * hierarchy within the device itself.  These aren't
+	 * real bus nodes, and don't have a 'ranges' property.
+	 * But, we should still pass the translation work up
+	 * to the SBUS itself.
 	 */
-	if (!strcmp(pp->name, "dma"))
+	if (!strcmp(pp->name, "dma") ||
+	    !strcmp(pp->name, "espdma") ||
+	    !strcmp(pp->name, "ledma") ||
+	    !strcmp(pp->name, "lebuffer"))
 		return 0;
 
 	/* Similarly for all PCI bridges, if we get this far
 	 * it lacks a ranges property, and this will include
 	 * cases like Simba.
 	 */
-	if (!strcmp(pp->type, "pci") || !strcmp(pp->type, "pciex"))
+	if (!strcmp(pp->name, "pci"))
 		return 0;
 
 	return 1;
@@ -714,8 +745,7 @@
 				break;
 			}
 		} else {
-			if (!strcmp(pp->type, "pci") ||
-			    !strcmp(pp->type, "pciex")) {
+			if (!strcmp(pp->name, "pci")) {
 				unsigned int this_orig_irq = irq;
 
 				irq = pci_irq_swizzle(dp, pp, irq);
@@ -845,15 +875,6 @@
 	int err;
 
 	err = of_bus_type_init(&of_platform_bus_type, "of");
-#ifdef CONFIG_PCI
-	if (!err)
-		err = of_bus_type_init(&ebus_bus_type, "ebus");
-#endif
-#ifdef CONFIG_SBUS
-	if (!err)
-		err = of_bus_type_init(&sbus_bus_type, "sbus");
-#endif
-
 	if (!err)
 		scan_of_devices();
 
diff --git a/arch/sparc64/kernel/pci.c b/arch/sparc64/kernel/pci.c
index 5509619..242ac1c 100644
--- a/arch/sparc64/kernel/pci.c
+++ b/arch/sparc64/kernel/pci.c
@@ -18,32 +18,17 @@
 #include <linux/msi.h>
 #include <linux/irq.h>
 #include <linux/init.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
 #include <asm/irq.h>
-#include <asm/ebus.h>
 #include <asm/prom.h>
 #include <asm/apb.h>
 
 #include "pci_impl.h"
 
-#ifndef CONFIG_PCI
-/* A "nop" PCI implementation. */
-asmlinkage int sys_pciconfig_read(unsigned long bus, unsigned long dfn,
-				  unsigned long off, unsigned long len,
-				  unsigned char *buf)
-{
-	return 0;
-}
-asmlinkage int sys_pciconfig_write(unsigned long bus, unsigned long dfn,
-				   unsigned long off, unsigned long len,
-				   unsigned char *buf)
-{
-	return 0;
-}
-#else
-
 /* List of all PCI controllers found in the system. */
 struct pci_pbm_info *pci_pbm_root = NULL;
 
@@ -179,97 +164,6 @@
 	spin_unlock_irqrestore(&pci_poke_lock, flags);
 }
 
-/* Probe for all PCI controllers in the system. */
-extern void sabre_init(struct device_node *, const char *);
-extern void psycho_init(struct device_node *, const char *);
-extern void schizo_init(struct device_node *, const char *);
-extern void schizo_plus_init(struct device_node *, const char *);
-extern void tomatillo_init(struct device_node *, const char *);
-extern void sun4v_pci_init(struct device_node *, const char *);
-extern void fire_pci_init(struct device_node *, const char *);
-
-static struct {
-	char *model_name;
-	void (*init)(struct device_node *, const char *);
-} pci_controller_table[] __initdata = {
-	{ "SUNW,sabre", sabre_init },
-	{ "pci108e,a000", sabre_init },
-	{ "pci108e,a001", sabre_init },
-	{ "SUNW,psycho", psycho_init },
-	{ "pci108e,8000", psycho_init },
-	{ "SUNW,schizo", schizo_init },
-	{ "pci108e,8001", schizo_init },
-	{ "SUNW,schizo+", schizo_plus_init },
-	{ "pci108e,8002", schizo_plus_init },
-	{ "SUNW,tomatillo", tomatillo_init },
-	{ "pci108e,a801", tomatillo_init },
-	{ "SUNW,sun4v-pci", sun4v_pci_init },
-	{ "pciex108e,80f0", fire_pci_init },
-};
-#define PCI_NUM_CONTROLLER_TYPES	ARRAY_SIZE(pci_controller_table)
-
-static int __init pci_controller_init(const char *model_name, int namelen, struct device_node *dp)
-{
-	int i;
-
-	for (i = 0; i < PCI_NUM_CONTROLLER_TYPES; i++) {
-		if (!strncmp(model_name,
-			     pci_controller_table[i].model_name,
-			     namelen)) {
-			pci_controller_table[i].init(dp, model_name);
-			return 1;
-		}
-	}
-
-	return 0;
-}
-
-static int __init pci_controller_scan(int (*handler)(const char *, int, struct device_node *))
-{
-	struct device_node *dp;
-	int count = 0;
-
-	for_each_node_by_name(dp, "pci") {
-		struct property *prop;
-		int len;
-
-		prop = of_find_property(dp, "model", &len);
-		if (!prop)
-			prop = of_find_property(dp, "compatible", &len);
-
-		if (prop) {
-			const char *model = prop->value;
-			int item_len = 0;
-
-			/* Our value may be a multi-valued string in the
-			 * case of some compatible properties. For sanity,
-			 * only try the first one.
-			 */
-			while (model[item_len] && len) {
-				len--;
-				item_len++;
-			}
-
-			if (handler(model, item_len, dp))
-				count++;
-		}
-	}
-
-	return count;
-}
-
-/* Find each controller in the system, attach and initialize
- * software state structure for each and link into the
- * pci_pbm_root.  Setup the controller enough such
- * that bus scanning can be done.
- */
-static void __init pci_controller_probe(void)
-{
-	printk("PCI: Probing for controllers.\n");
-
-	pci_controller_scan(pci_controller_init);
-}
-
 static int ofpci_verbose;
 
 static int __init ofpci_debug(char *str)
@@ -348,11 +242,12 @@
 	}
 }
 
-struct pci_dev *of_create_pci_dev(struct pci_pbm_info *pbm,
-				  struct device_node *node,
-				  struct pci_bus *bus, int devfn)
+static struct pci_dev *of_create_pci_dev(struct pci_pbm_info *pbm,
+					 struct device_node *node,
+					 struct pci_bus *bus, int devfn)
 {
 	struct dev_archdata *sd;
+	struct of_device *op;
 	struct pci_dev *dev;
 	const char *type;
 	u32 class;
@@ -366,14 +261,17 @@
 	sd->stc = &pbm->stc;
 	sd->host_controller = pbm;
 	sd->prom_node = node;
-	sd->op = of_find_device_by_node(node);
+	sd->op = op = of_find_device_by_node(node);
 	sd->numa_node = pbm->numa_node;
 
-	sd = &sd->op->dev.archdata;
+	sd = &op->dev.archdata;
 	sd->iommu = pbm->iommu;
 	sd->stc = &pbm->stc;
 	sd->numa_node = pbm->numa_node;
 
+	if (!strcmp(node->name, "ebus"))
+		of_propagate_archdata(op);
+
 	type = of_get_property(node, "device_type", NULL);
 	if (type == NULL)
 		type = "";
@@ -425,7 +323,7 @@
 	dev->current_state = 4;		/* unknown power state */
 	dev->error_state = pci_channel_io_normal;
 
-	if (!strcmp(type, "pci") || !strcmp(type, "pciex")) {
+	if (!strcmp(node->name, "pci")) {
 		/* a PCI-PCI bridge */
 		dev->hdr_type = PCI_HEADER_TYPE_BRIDGE;
 		dev->rom_base_reg = PCI_ROM_ADDRESS1;
@@ -775,15 +673,15 @@
 		pci_bus_register_of_sysfs(child_bus);
 }
 
-struct pci_bus * __devinit pci_scan_one_pbm(struct pci_pbm_info *pbm)
+struct pci_bus * __devinit pci_scan_one_pbm(struct pci_pbm_info *pbm,
+					    struct device *parent)
 {
-	struct device_node *node = pbm->prom_node;
+	struct device_node *node = pbm->op->node;
 	struct pci_bus *bus;
 
 	printk("PCI: Scanning PBM %s\n", node->full_name);
 
-	/* XXX parent device? XXX */
-	bus = pci_create_bus(NULL, pbm->pci_first_busno, pbm->pci_ops, pbm);
+	bus = pci_create_bus(parent, pbm->pci_first_busno, pbm->pci_ops, pbm);
 	if (!bus) {
 		printk(KERN_ERR "Failed to create bus for %s\n",
 		       node->full_name);
@@ -802,32 +700,6 @@
 	return bus;
 }
 
-static void __init pci_scan_each_controller_bus(void)
-{
-	struct pci_pbm_info *pbm;
-
-	for (pbm = pci_pbm_root; pbm; pbm = pbm->next)
-		pbm->scan_bus(pbm);
-}
-
-extern void power_init(void);
-
-static int __init pcibios_init(void)
-{
-	pci_controller_probe();
-	if (pci_pbm_root == NULL)
-		return 0;
-
-	pci_scan_each_controller_bus();
-
-	ebus_init();
-	power_init();
-
-	return 0;
-}
-
-subsys_initcall(pcibios_init);
-
 void __devinit pcibios_fixup_bus(struct pci_bus *pbus)
 {
 	struct pci_pbm_info *pbm = pbus->sysdata;
@@ -1105,14 +977,14 @@
 EXPORT_SYMBOL(pcibus_to_node);
 #endif
 
-/* Return the domain nuber for this pci bus */
+/* Return the domain number for this pci bus */
 
 int pci_domain_nr(struct pci_bus *pbus)
 {
 	struct pci_pbm_info *pbm = pbus->sysdata;
 	int ret;
 
-	if (pbm == NULL || pbm->parent == NULL) {
+	if (!pbm) {
 		ret = -ENXIO;
 	} else {
 		ret = pbm->index;
@@ -1126,7 +998,7 @@
 int arch_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *desc)
 {
 	struct pci_pbm_info *pbm = pdev->dev.archdata.host_controller;
-	int virt_irq;
+	unsigned int virt_irq;
 
 	if (!pbm->setup_msi_irq)
 		return -EINVAL;
@@ -1140,10 +1012,8 @@
 	struct pci_dev *pdev = entry->dev;
 	struct pci_pbm_info *pbm = pdev->dev.archdata.host_controller;
 
-	if (!pbm->teardown_msi_irq)
-		return;
-
-	return pbm->teardown_msi_irq(virt_irq, pdev);
+	if (pbm->teardown_msi_irq)
+		pbm->teardown_msi_irq(virt_irq, pdev);
 }
 #endif /* !(CONFIG_PCI_MSI) */
 
@@ -1215,5 +1085,3 @@
 	*start = rp->start - offset;
 	*end = rp->end - offset;
 }
-
-#endif /* !(CONFIG_PCI) */
diff --git a/arch/sparc64/kernel/pci_common.c b/arch/sparc64/kernel/pci_common.c
index 09a5ec2..23b8808 100644
--- a/arch/sparc64/kernel/pci_common.c
+++ b/arch/sparc64/kernel/pci_common.c
@@ -314,12 +314,12 @@
 
 void pci_get_pbm_props(struct pci_pbm_info *pbm)
 {
-	const u32 *val = of_get_property(pbm->prom_node, "bus-range", NULL);
+	const u32 *val = of_get_property(pbm->op->node, "bus-range", NULL);
 
 	pbm->pci_first_busno = val[0];
 	pbm->pci_last_busno = val[1];
 
-	val = of_get_property(pbm->prom_node, "ino-bitmap", NULL);
+	val = of_get_property(pbm->op->node, "ino-bitmap", NULL);
 	if (val) {
 		pbm->ino_bitmap = (((u64)val[1] << 32UL) |
 				   ((u64)val[0] <<  0UL));
@@ -365,7 +365,7 @@
 
 static void pci_register_iommu_region(struct pci_pbm_info *pbm)
 {
-	const u32 *vdma = of_get_property(pbm->prom_node, "virtual-dma", NULL);
+	const u32 *vdma = of_get_property(pbm->op->node, "virtual-dma", NULL);
 
 	if (vdma) {
 		struct resource *rp = kmalloc(sizeof(*rp), GFP_KERNEL);
@@ -389,7 +389,7 @@
 	int num_pbm_ranges;
 
 	saw_mem = saw_io = 0;
-	pbm_ranges = of_get_property(pbm->prom_node, "ranges", &i);
+	pbm_ranges = of_get_property(pbm->op->node, "ranges", &i);
 	if (!pbm_ranges) {
 		prom_printf("PCI: Fatal error, missing PBM ranges property "
 			    " for %s\n",
diff --git a/arch/sparc64/kernel/pci_fire.c b/arch/sparc64/kernel/pci_fire.c
index d23bb6f..9462b68 100644
--- a/arch/sparc64/kernel/pci_fire.c
+++ b/arch/sparc64/kernel/pci_fire.c
@@ -8,34 +8,16 @@
 #include <linux/init.h>
 #include <linux/msi.h>
 #include <linux/irq.h>
+#include <linux/of_device.h>
 
-#include <asm/oplib.h>
 #include <asm/prom.h>
 #include <asm/irq.h>
+#include <asm/upa.h>
 
 #include "pci_impl.h"
 
-#define fire_read(__reg) \
-({	u64 __ret; \
-	__asm__ __volatile__("ldxa [%1] %2, %0" \
-			     : "=r" (__ret) \
-			     : "r" (__reg), "i" (ASI_PHYS_BYPASS_EC_E) \
-			     : "memory"); \
-	__ret; \
-})
-#define fire_write(__reg, __val) \
-	__asm__ __volatile__("stxa %0, [%1] %2" \
-			     : /* no outputs */ \
-			     : "r" (__val), "r" (__reg), \
-			       "i" (ASI_PHYS_BYPASS_EC_E) \
-			     : "memory")
-
-static void __init pci_fire_scan_bus(struct pci_pbm_info *pbm)
-{
-	pbm->pci_bus = pci_scan_one_pbm(pbm);
-
-	/* XXX register error interrupt handlers XXX */
-}
+#define DRIVER_NAME	"fire"
+#define PFX		DRIVER_NAME ": "
 
 #define FIRE_IOMMU_CONTROL	0x40000UL
 #define FIRE_IOMMU_TSBBASE	0x40008UL
@@ -69,21 +51,21 @@
 	/*
 	 * Invalidate TLB Entries.
 	 */
-	fire_write(iommu->iommu_flushinv, ~(u64)0);
+	upa_writeq(~(u64)0, iommu->iommu_flushinv);
 
 	err = iommu_table_init(iommu, tsbsize * 8 * 1024, vdma[0], dma_mask,
 			       pbm->numa_node);
 	if (err)
 		return err;
 
-	fire_write(iommu->iommu_tsbbase, __pa(iommu->page_table) | 0x7UL);
+	upa_writeq(__pa(iommu->page_table) | 0x7UL, iommu->iommu_tsbbase);
 
-	control = fire_read(iommu->iommu_control);
+	control = upa_readq(iommu->iommu_control);
 	control |= (0x00000400 /* TSB cache snoop enable */	|
 		    0x00000300 /* Cache mode */			|
 		    0x00000002 /* Bypass enable */		|
 		    0x00000001 /* Translation enable */);
-	fire_write(iommu->iommu_control, control);
+	upa_writeq(control, iommu->iommu_control);
 
 	return 0;
 }
@@ -165,7 +147,7 @@
 static int pci_fire_get_head(struct pci_pbm_info *pbm, unsigned long msiqid,
 			     unsigned long *head)
 {
-	*head = fire_read(pbm->pbm_regs + EVENT_QUEUE_HEAD(msiqid));
+	*head = upa_readq(pbm->pbm_regs + EVENT_QUEUE_HEAD(msiqid));
 	return 0;
 }
 
@@ -191,8 +173,7 @@
 	*msi = msi_num = ((ep->word0 & MSIQ_WORD0_DATA0) >>
 			  MSIQ_WORD0_DATA0_SHIFT);
 
-	fire_write(pbm->pbm_regs + MSI_CLEAR(msi_num),
-		   MSI_CLEAR_EQWR_N);
+	upa_writeq(MSI_CLEAR_EQWR_N, pbm->pbm_regs + MSI_CLEAR(msi_num));
 
 	/* Clear the entry.  */
 	ep->word0 &= ~MSIQ_WORD0_FMT_TYPE;
@@ -208,7 +189,7 @@
 static int pci_fire_set_head(struct pci_pbm_info *pbm, unsigned long msiqid,
 			     unsigned long head)
 {
-	fire_write(pbm->pbm_regs + EVENT_QUEUE_HEAD(msiqid), head);
+	upa_writeq(head, pbm->pbm_regs + EVENT_QUEUE_HEAD(msiqid));
 	return 0;
 }
 
@@ -217,17 +198,16 @@
 {
 	u64 val;
 
-	val = fire_read(pbm->pbm_regs + MSI_MAP(msi));
+	val = upa_readq(pbm->pbm_regs + MSI_MAP(msi));
 	val &= ~(MSI_MAP_EQNUM);
 	val |= msiqid;
-	fire_write(pbm->pbm_regs + MSI_MAP(msi), val);
+	upa_writeq(val, pbm->pbm_regs + MSI_MAP(msi));
 
-	fire_write(pbm->pbm_regs + MSI_CLEAR(msi),
-		   MSI_CLEAR_EQWR_N);
+	upa_writeq(MSI_CLEAR_EQWR_N, pbm->pbm_regs + MSI_CLEAR(msi));
 
-	val = fire_read(pbm->pbm_regs + MSI_MAP(msi));
+	val = upa_readq(pbm->pbm_regs + MSI_MAP(msi));
 	val |= MSI_MAP_VALID;
-	fire_write(pbm->pbm_regs + MSI_MAP(msi), val);
+	upa_writeq(val, pbm->pbm_regs + MSI_MAP(msi));
 
 	return 0;
 }
@@ -237,12 +217,12 @@
 	unsigned long msiqid;
 	u64 val;
 
-	val = fire_read(pbm->pbm_regs + MSI_MAP(msi));
+	val = upa_readq(pbm->pbm_regs + MSI_MAP(msi));
 	msiqid = (val & MSI_MAP_EQNUM);
 
 	val &= ~MSI_MAP_VALID;
 
-	fire_write(pbm->pbm_regs + MSI_MAP(msi), val);
+	upa_writeq(val, pbm->pbm_regs + MSI_MAP(msi));
 
 	return 0;
 }
@@ -261,22 +241,19 @@
 	memset((char *)pages, 0, PAGE_SIZE << order);
 	pbm->msi_queues = (void *) pages;
 
-	fire_write(pbm->pbm_regs + EVENT_QUEUE_BASE_ADDR_REG,
-		   (EVENT_QUEUE_BASE_ADDR_ALL_ONES |
-		    __pa(pbm->msi_queues)));
+	upa_writeq((EVENT_QUEUE_BASE_ADDR_ALL_ONES |
+		    __pa(pbm->msi_queues)),
+		   pbm->pbm_regs + EVENT_QUEUE_BASE_ADDR_REG);
 
-	fire_write(pbm->pbm_regs + IMONDO_DATA0,
-		   pbm->portid << 6);
-	fire_write(pbm->pbm_regs + IMONDO_DATA1, 0);
+	upa_writeq(pbm->portid << 6, pbm->pbm_regs + IMONDO_DATA0);
+	upa_writeq(0, pbm->pbm_regs + IMONDO_DATA1);
 
-	fire_write(pbm->pbm_regs + MSI_32BIT_ADDR,
-		   pbm->msi32_start);
-	fire_write(pbm->pbm_regs + MSI_64BIT_ADDR,
-		   pbm->msi64_start);
+	upa_writeq(pbm->msi32_start, pbm->pbm_regs + MSI_32BIT_ADDR);
+	upa_writeq(pbm->msi64_start, pbm->pbm_regs + MSI_64BIT_ADDR);
 
 	for (i = 0; i < pbm->msiq_num; i++) {
-		fire_write(pbm->pbm_regs + EVENT_QUEUE_HEAD(i), 0);
-		fire_write(pbm->pbm_regs + EVENT_QUEUE_TAIL(i), 0);
+		upa_writeq(0, pbm->pbm_regs + EVENT_QUEUE_HEAD(i));
+		upa_writeq(0, pbm->pbm_regs + EVENT_QUEUE_TAIL(i));
 	}
 
 	return 0;
@@ -310,9 +287,9 @@
 	/* XXX iterate amongst the 4 IRQ controllers XXX */
 	int_ctrlr = (1UL << 6);
 
-	val = fire_read(imap_reg);
+	val = upa_readq(imap_reg);
 	val |= (1UL << 63) | int_ctrlr;
-	fire_write(imap_reg, val);
+	upa_writeq(val, imap_reg);
 
 	fixup = ((pbm->portid << 6) | devino) - int_ctrlr;
 
@@ -320,9 +297,8 @@
 	if (!virt_irq)
 		return -ENOMEM;
 
-	fire_write(pbm->pbm_regs +
-		   EVENT_QUEUE_CONTROL_SET(msiqid),
-		   EVENT_QUEUE_CONTROL_SET_EN);
+	upa_writeq(EVENT_QUEUE_CONTROL_SET_EN,
+		   pbm->pbm_regs + EVENT_QUEUE_CONTROL_SET(msiqid));
 
 	return virt_irq;
 }
@@ -390,77 +366,65 @@
 {
 	u64 val;
 
-	fire_write(pbm->controller_regs + FIRE_PARITY_CONTROL,
-		   FIRE_PARITY_ENAB);
+	upa_writeq(FIRE_PARITY_ENAB,
+		   pbm->controller_regs + FIRE_PARITY_CONTROL);
 
-	fire_write(pbm->controller_regs + FIRE_FATAL_RESET_CTL,
-		   (FIRE_FATAL_RESET_SPARE |
+	upa_writeq((FIRE_FATAL_RESET_SPARE |
 		    FIRE_FATAL_RESET_MB |
 		    FIRE_FATAL_RESET_CPE |
 		    FIRE_FATAL_RESET_APE |
 		    FIRE_FATAL_RESET_PIO |
 		    FIRE_FATAL_RESET_JW |
 		    FIRE_FATAL_RESET_JI |
-		    FIRE_FATAL_RESET_JR));
+		    FIRE_FATAL_RESET_JR),
+		   pbm->controller_regs + FIRE_FATAL_RESET_CTL);
 
-	fire_write(pbm->controller_regs + FIRE_CORE_INTR_ENABLE, ~(u64)0);
+	upa_writeq(~(u64)0, pbm->controller_regs + FIRE_CORE_INTR_ENABLE);
 
-	val = fire_read(pbm->pbm_regs + FIRE_TLU_CTRL);
+	val = upa_readq(pbm->pbm_regs + FIRE_TLU_CTRL);
 	val |= (FIRE_TLU_CTRL_TIM |
 		FIRE_TLU_CTRL_QDET |
 		FIRE_TLU_CTRL_CFG);
-	fire_write(pbm->pbm_regs + FIRE_TLU_CTRL, val);
-	fire_write(pbm->pbm_regs + FIRE_TLU_DEV_CTRL, 0);
-	fire_write(pbm->pbm_regs + FIRE_TLU_LINK_CTRL,
-		   FIRE_TLU_LINK_CTRL_CLK);
+	upa_writeq(val, pbm->pbm_regs + FIRE_TLU_CTRL);
+	upa_writeq(0, pbm->pbm_regs + FIRE_TLU_DEV_CTRL);
+	upa_writeq(FIRE_TLU_LINK_CTRL_CLK,
+		   pbm->pbm_regs + FIRE_TLU_LINK_CTRL);
 
-	fire_write(pbm->pbm_regs + FIRE_LPU_RESET, 0);
-	fire_write(pbm->pbm_regs + FIRE_LPU_LLCFG,
-		   FIRE_LPU_LLCFG_VC0);
-	fire_write(pbm->pbm_regs + FIRE_LPU_FCTRL_UCTRL,
-		   (FIRE_LPU_FCTRL_UCTRL_N |
-		    FIRE_LPU_FCTRL_UCTRL_P));
-	fire_write(pbm->pbm_regs + FIRE_LPU_TXL_FIFOP,
-		   ((0xffff << 16) | (0x0000 << 0)));
-	fire_write(pbm->pbm_regs + FIRE_LPU_LTSSM_CFG2, 3000000);
-	fire_write(pbm->pbm_regs + FIRE_LPU_LTSSM_CFG3, 500000);
-	fire_write(pbm->pbm_regs + FIRE_LPU_LTSSM_CFG4,
-		   (2 << 16) | (140 << 8));
-	fire_write(pbm->pbm_regs + FIRE_LPU_LTSSM_CFG5, 0);
+	upa_writeq(0, pbm->pbm_regs + FIRE_LPU_RESET);
+	upa_writeq(FIRE_LPU_LLCFG_VC0, pbm->pbm_regs + FIRE_LPU_LLCFG);
+	upa_writeq((FIRE_LPU_FCTRL_UCTRL_N | FIRE_LPU_FCTRL_UCTRL_P),
+		   pbm->pbm_regs + FIRE_LPU_FCTRL_UCTRL);
+	upa_writeq(((0xffff << 16) | (0x0000 << 0)),
+		   pbm->pbm_regs + FIRE_LPU_TXL_FIFOP);
+	upa_writeq(3000000, pbm->pbm_regs + FIRE_LPU_LTSSM_CFG2);
+	upa_writeq(500000, pbm->pbm_regs + FIRE_LPU_LTSSM_CFG3);
+	upa_writeq((2 << 16) | (140 << 8),
+		   pbm->pbm_regs + FIRE_LPU_LTSSM_CFG4);
+	upa_writeq(0, pbm->pbm_regs + FIRE_LPU_LTSSM_CFG5);
 
-	fire_write(pbm->pbm_regs + FIRE_DMC_IENAB, ~(u64)0);
-	fire_write(pbm->pbm_regs + FIRE_DMC_DBG_SEL_A, 0);
-	fire_write(pbm->pbm_regs + FIRE_DMC_DBG_SEL_B, 0);
+	upa_writeq(~(u64)0, pbm->pbm_regs + FIRE_DMC_IENAB);
+	upa_writeq(0, pbm->pbm_regs + FIRE_DMC_DBG_SEL_A);
+	upa_writeq(0, pbm->pbm_regs + FIRE_DMC_DBG_SEL_B);
 
-	fire_write(pbm->pbm_regs + FIRE_PEC_IENAB, ~(u64)0);
+	upa_writeq(~(u64)0, pbm->pbm_regs + FIRE_PEC_IENAB);
 }
 
-static int __init pci_fire_pbm_init(struct pci_controller_info *p,
-				    struct device_node *dp, u32 portid)
+static int __init pci_fire_pbm_init(struct pci_pbm_info *pbm,
+				    struct of_device *op, u32 portid)
 {
 	const struct linux_prom64_registers *regs;
-	struct pci_pbm_info *pbm;
+	struct device_node *dp = op->node;
 	int err;
 
-	if ((portid & 1) == 0)
-		pbm = &p->pbm_A;
-	else
-		pbm = &p->pbm_B;
-
-	pbm->next = pci_pbm_root;
-	pci_pbm_root = pbm;
-
 	pbm->numa_node = -1;
 
-	pbm->scan_bus = pci_fire_scan_bus;
 	pbm->pci_ops = &sun4u_pci_ops;
 	pbm->config_space_reg_bits = 12;
 
 	pbm->index = pci_num_pbms++;
 
 	pbm->portid = portid;
-	pbm->parent = p;
-	pbm->prom_node = dp;
+	pbm->op = op;
 	pbm->name = dp->full_name;
 
 	regs = of_get_property(dp, "reg", NULL);
@@ -481,53 +445,77 @@
 
 	pci_fire_msi_init(pbm);
 
+	pbm->pci_bus = pci_scan_one_pbm(pbm, &op->dev);
+
+	/* XXX register error interrupt handlers XXX */
+
+	pbm->next = pci_pbm_root;
+	pci_pbm_root = pbm;
+
 	return 0;
 }
 
-static inline int portid_compare(u32 x, u32 y)
+static int __devinit fire_probe(struct of_device *op,
+				const struct of_device_id *match)
 {
-	if (x == (y ^ 1))
-		return 1;
-	return 0;
-}
-
-void __init fire_pci_init(struct device_node *dp, const char *model_name)
-{
-	struct pci_controller_info *p;
-	u32 portid = of_getintprop_default(dp, "portid", 0xff);
-	struct iommu *iommu;
+	struct device_node *dp = op->node;
 	struct pci_pbm_info *pbm;
+	struct iommu *iommu;
+	u32 portid;
+	int err;
 
-	for (pbm = pci_pbm_root; pbm; pbm = pbm->next) {
-		if (portid_compare(pbm->portid, portid)) {
-			if (pci_fire_pbm_init(pbm->parent, dp, portid))
-				goto fatal_memory_error;
-			return;
-		}
+	portid = of_getintprop_default(dp, "portid", 0xff);
+
+	err = -ENOMEM;
+	pbm = kzalloc(sizeof(*pbm), GFP_KERNEL);
+	if (!pbm) {
+		printk(KERN_ERR PFX "Cannot allocate pci_pbminfo.\n");
+		goto out_err;
 	}
 
-	p = kzalloc(sizeof(struct pci_controller_info), GFP_ATOMIC);
-	if (!p)
-		goto fatal_memory_error;
+	iommu = kzalloc(sizeof(struct iommu), GFP_KERNEL);
+	if (!iommu) {
+		printk(KERN_ERR PFX "Cannot allocate PBM iommu.\n");
+		goto out_free_controller;
+	}
 
-	iommu = kzalloc(sizeof(struct iommu), GFP_ATOMIC);
-	if (!iommu)
-		goto fatal_memory_error;
+	pbm->iommu = iommu;
 
-	p->pbm_A.iommu = iommu;
+	err = pci_fire_pbm_init(pbm, op, portid);
+	if (err)
+		goto out_free_iommu;
 
-	iommu = kzalloc(sizeof(struct iommu), GFP_ATOMIC);
-	if (!iommu)
-		goto fatal_memory_error;
+	dev_set_drvdata(&op->dev, pbm);
 
-	p->pbm_B.iommu = iommu;
+	return 0;
 
-	if (pci_fire_pbm_init(p, dp, portid))
-		goto fatal_memory_error;
+out_free_iommu:
+	kfree(pbm->iommu);
+			
+out_free_controller:
+	kfree(pbm);
 
-	return;
-
-fatal_memory_error:
-	prom_printf("PCI_FIRE: Fatal memory allocation error.\n");
-	prom_halt();
+out_err:
+	return err;
 }
+
+static struct of_device_id __initdata fire_match[] = {
+	{
+		.name = "pci",
+		.compatible = "pciex108e,80f0",
+	},
+	{},
+};
+
+static struct of_platform_driver fire_driver = {
+	.name		= DRIVER_NAME,
+	.match_table	= fire_match,
+	.probe		= fire_probe,
+};
+
+static int __init fire_init(void)
+{
+	return of_register_driver(&fire_driver, &of_bus_type);
+}
+
+subsys_initcall(fire_init);
diff --git a/arch/sparc64/kernel/pci_impl.h b/arch/sparc64/kernel/pci_impl.h
index c385d12..0318682 100644
--- a/arch/sparc64/kernel/pci_impl.h
+++ b/arch/sparc64/kernel/pci_impl.h
@@ -10,6 +10,7 @@
 #include <linux/spinlock.h>
 #include <linux/pci.h>
 #include <linux/msi.h>
+#include <linux/of_device.h>
 #include <asm/io.h>
 #include <asm/prom.h>
 #include <asm/iommu.h>
@@ -56,15 +57,11 @@
 };
 #endif
 
-struct pci_controller_info;
-
 struct pci_pbm_info {
 	struct pci_pbm_info		*next;
+	struct pci_pbm_info		*sibling;
 	int				index;
 
-	/* PCI controller we sit under. */
-	struct pci_controller_info	*parent;
-
 	/* Physical address base of controller registers. */
 	unsigned long			controller_regs;
 
@@ -94,7 +91,7 @@
 	char				*name;
 
 	/* OBP specific information. */
-	struct device_node		*prom_node;
+	struct of_device		*op;
 	u64				ino_bitmap;
 
 	/* PBM I/O and Memory space resources. */
@@ -107,6 +104,10 @@
 	/* This will be 12 on PCI-E controllers, 8 elsewhere.  */
 	unsigned long			config_space_reg_bits;
 
+	unsigned long			pci_afsr;
+	unsigned long			pci_afar;
+	unsigned long			pci_csr;
+
 	/* State of 66MHz capabilities on this PBM. */
 	int				is_66mhz_capable;
 	int				all_devs_66mhz;
@@ -146,25 +147,19 @@
 	unsigned int			pci_first_busno;
 	unsigned int			pci_last_busno;
 	struct pci_bus			*pci_bus;
-	void (*scan_bus)(struct pci_pbm_info *);
 	struct pci_ops			*pci_ops;
 
 	int				numa_node;
 };
 
-struct pci_controller_info {
-	/* The PCI bus modules controlled by us. */
-	struct pci_pbm_info		pbm_A;
-	struct pci_pbm_info		pbm_B;
-};
-
 extern struct pci_pbm_info *pci_pbm_root;
 
 extern int pci_num_pbms;
 
 /* PCI bus scanning and fixup support. */
 extern void pci_get_pbm_props(struct pci_pbm_info *pbm);
-extern struct pci_bus *pci_scan_one_pbm(struct pci_pbm_info *pbm);
+extern struct pci_bus *pci_scan_one_pbm(struct pci_pbm_info *pbm,
+					struct device *parent);
 extern void pci_determine_mem_io_space(struct pci_pbm_info *pbm);
 
 /* Error reporting support. */
@@ -183,4 +178,8 @@
 extern struct pci_ops sun4u_pci_ops;
 extern struct pci_ops sun4v_pci_ops;
 
+extern volatile int pci_poke_in_progress;
+extern volatile int pci_poke_cpu;
+extern volatile int pci_poke_faulted;
+
 #endif /* !(PCI_IMPL_H) */
diff --git a/arch/sparc64/kernel/pci_msi.c b/arch/sparc64/kernel/pci_msi.c
index 60c71e3..2e680f3 100644
--- a/arch/sparc64/kernel/pci_msi.c
+++ b/arch/sparc64/kernel/pci_msi.c
@@ -323,7 +323,7 @@
 	const u32 *val;
 	int len;
 
-	val = of_get_property(pbm->prom_node, "#msi-eqs", &len);
+	val = of_get_property(pbm->op->node, "#msi-eqs", &len);
 	if (!val || len != 4)
 		goto no_msi;
 	pbm->msiq_num = *val;
@@ -346,16 +346,16 @@
 			u32 msi64_len;
 		} *arng;
 
-		val = of_get_property(pbm->prom_node, "msi-eq-size", &len);
+		val = of_get_property(pbm->op->node, "msi-eq-size", &len);
 		if (!val || len != 4)
 			goto no_msi;
 
 		pbm->msiq_ent_count = *val;
 
-		mqp = of_get_property(pbm->prom_node,
+		mqp = of_get_property(pbm->op->node,
 				      "msi-eq-to-devino", &len);
 		if (!mqp)
-			mqp = of_get_property(pbm->prom_node,
+			mqp = of_get_property(pbm->op->node,
 					      "msi-eq-devino", &len);
 		if (!mqp || len != sizeof(struct msiq_prop))
 			goto no_msi;
@@ -363,27 +363,27 @@
 		pbm->msiq_first = mqp->first_msiq;
 		pbm->msiq_first_devino = mqp->first_devino;
 
-		val = of_get_property(pbm->prom_node, "#msi", &len);
+		val = of_get_property(pbm->op->node, "#msi", &len);
 		if (!val || len != 4)
 			goto no_msi;
 		pbm->msi_num = *val;
 
-		mrng = of_get_property(pbm->prom_node, "msi-ranges", &len);
+		mrng = of_get_property(pbm->op->node, "msi-ranges", &len);
 		if (!mrng || len != sizeof(struct msi_range_prop))
 			goto no_msi;
 		pbm->msi_first = mrng->first_msi;
 
-		val = of_get_property(pbm->prom_node, "msi-data-mask", &len);
+		val = of_get_property(pbm->op->node, "msi-data-mask", &len);
 		if (!val || len != 4)
 			goto no_msi;
 		pbm->msi_data_mask = *val;
 
-		val = of_get_property(pbm->prom_node, "msix-data-width", &len);
+		val = of_get_property(pbm->op->node, "msix-data-width", &len);
 		if (!val || len != 4)
 			goto no_msi;
 		pbm->msix_data_width = *val;
 
-		arng = of_get_property(pbm->prom_node, "msi-address-ranges",
+		arng = of_get_property(pbm->op->node, "msi-address-ranges",
 				       &len);
 		if (!arng || len != sizeof(struct addr_range_prop))
 			goto no_msi;
diff --git a/arch/sparc64/kernel/pci_psycho.c b/arch/sparc64/kernel/pci_psycho.c
index e205ade..dfb3ec8 100644
--- a/arch/sparc64/kernel/pci_psycho.c
+++ b/arch/sparc64/kernel/pci_psycho.c
@@ -17,29 +17,14 @@
 #include <asm/irq.h>
 #include <asm/starfire.h>
 #include <asm/prom.h>
-#include <asm/oplib.h>
+#include <asm/upa.h>
 
 #include "pci_impl.h"
 #include "iommu_common.h"
+#include "psycho_common.h"
 
-/* All PSYCHO registers are 64-bits.  The following accessor
- * routines are how they are accessed.  The REG parameter
- * is a physical address.
- */
-#define psycho_read(__reg) \
-({	u64 __ret; \
-	__asm__ __volatile__("ldxa [%1] %2, %0" \
-			     : "=r" (__ret) \
-			     : "r" (__reg), "i" (ASI_PHYS_BYPASS_EC_E) \
-			     : "memory"); \
-	__ret; \
-})
-#define psycho_write(__reg, __val) \
-	__asm__ __volatile__("stxa %0, [%1] %2" \
-			     : /* no outputs */ \
-			     : "r" (__val), "r" (__reg), \
-			       "i" (ASI_PHYS_BYPASS_EC_E) \
-			     : "memory")
+#define DRIVER_NAME	"psycho"
+#define PFX		DRIVER_NAME ": "
 
 /* Misc. PSYCHO PCI controller register offsets and definitions. */
 #define PSYCHO_CONTROL		0x0010UL
@@ -67,37 +52,7 @@
 #define  PSYCHO_PCICTRL_RESV4	 0x00000000000000c0UL /* Reserved                     */
 #define  PSYCHO_PCICTRL_AEN	 0x000000000000003fUL /* PCI DVMA Arbitration Enable  */
 
-/* U2P Programmer's Manual, page 13-55, configuration space
- * address format:
- * 
- *  32             24 23 16 15    11 10       8 7   2  1 0
- * ---------------------------------------------------------
- * |0 0 0 0 0 0 0 0 1| bus | device | function | reg | 0 0 |
- * ---------------------------------------------------------
- */
-#define PSYCHO_CONFIG_BASE(PBM)	\
-	((PBM)->config_space | (1UL << 24))
-#define PSYCHO_CONFIG_ENCODE(BUS, DEVFN, REG)	\
-	(((unsigned long)(BUS)   << 16) |	\
-	 ((unsigned long)(DEVFN) << 8)  |	\
-	 ((unsigned long)(REG)))
-
-static void *psycho_pci_config_mkaddr(struct pci_pbm_info *pbm,
-				      unsigned char bus,
-				      unsigned int devfn,
-				      int where)
-{
-	if (!pbm)
-		return NULL;
-	return (void *)
-		(PSYCHO_CONFIG_BASE(pbm) |
-		 PSYCHO_CONFIG_ENCODE(bus, devfn, where));
-}
-
 /* PSYCHO error handling support. */
-enum psycho_error_type {
-	UE_ERR, CE_ERR, PCI_ERR
-};
 
 /* Helper function of IOMMU error checking, which checks out
  * the state of the streaming buffers.  The IOMMU lock is
@@ -122,129 +77,10 @@
 #define PSYCHO_STC_DATA_B	0xc000UL
 #define PSYCHO_STC_ERR_A	0xb400UL
 #define PSYCHO_STC_ERR_B	0xc400UL
-#define  PSYCHO_STCERR_WRITE	 0x0000000000000002UL	/* Write Error */
-#define  PSYCHO_STCERR_READ	 0x0000000000000001UL	/* Read Error */
 #define PSYCHO_STC_TAG_A	0xb800UL
 #define PSYCHO_STC_TAG_B	0xc800UL
-#define  PSYCHO_STCTAG_PPN	 0x0fffffff00000000UL	/* Physical Page Number */
-#define  PSYCHO_STCTAG_VPN	 0x00000000ffffe000UL	/* Virtual Page Number */
-#define  PSYCHO_STCTAG_VALID	 0x0000000000000002UL	/* Valid */
-#define  PSYCHO_STCTAG_WRITE	 0x0000000000000001UL	/* Writable */
 #define PSYCHO_STC_LINE_A	0xb900UL
 #define PSYCHO_STC_LINE_B	0xc900UL
-#define  PSYCHO_STCLINE_LINDX	 0x0000000001e00000UL	/* LRU Index */
-#define  PSYCHO_STCLINE_SPTR	 0x00000000001f8000UL	/* Dirty Data Start Pointer */
-#define  PSYCHO_STCLINE_LADDR	 0x0000000000007f00UL	/* Line Address */
-#define  PSYCHO_STCLINE_EPTR	 0x00000000000000fcUL	/* Dirty Data End Pointer */
-#define  PSYCHO_STCLINE_VALID	 0x0000000000000002UL	/* Valid */
-#define  PSYCHO_STCLINE_FOFN	 0x0000000000000001UL	/* Fetch Outstanding / Flush Necessary */
-
-static DEFINE_SPINLOCK(stc_buf_lock);
-static unsigned long stc_error_buf[128];
-static unsigned long stc_tag_buf[16];
-static unsigned long stc_line_buf[16];
-
-static void __psycho_check_one_stc(struct pci_pbm_info *pbm,
-				   int is_pbm_a)
-{
-	struct strbuf *strbuf = &pbm->stc;
-	unsigned long regbase = pbm->controller_regs;
-	unsigned long err_base, tag_base, line_base;
-	u64 control;
-	int i;
-
-	if (is_pbm_a) {
-		err_base = regbase + PSYCHO_STC_ERR_A;
-		tag_base = regbase + PSYCHO_STC_TAG_A;
-		line_base = regbase + PSYCHO_STC_LINE_A;
-	} else {
-		err_base = regbase + PSYCHO_STC_ERR_B;
-		tag_base = regbase + PSYCHO_STC_TAG_B;
-		line_base = regbase + PSYCHO_STC_LINE_B;
-	}
-
-	spin_lock(&stc_buf_lock);
-
-	/* This is __REALLY__ dangerous.  When we put the
-	 * streaming buffer into diagnostic mode to probe
-	 * it's tags and error status, we _must_ clear all
-	 * of the line tag valid bits before re-enabling
-	 * the streaming buffer.  If any dirty data lives
-	 * in the STC when we do this, we will end up
-	 * invalidating it before it has a chance to reach
-	 * main memory.
-	 */
-	control = psycho_read(strbuf->strbuf_control);
-	psycho_write(strbuf->strbuf_control,
-		     (control | PSYCHO_STRBUF_CTRL_DENAB));
-	for (i = 0; i < 128; i++) {
-		unsigned long val;
-
-		val = psycho_read(err_base + (i * 8UL));
-		psycho_write(err_base + (i * 8UL), 0UL);
-		stc_error_buf[i] = val;
-	}
-	for (i = 0; i < 16; i++) {
-		stc_tag_buf[i] = psycho_read(tag_base + (i * 8UL));
-		stc_line_buf[i] = psycho_read(line_base + (i * 8UL));
-		psycho_write(tag_base + (i * 8UL), 0UL);
-		psycho_write(line_base + (i * 8UL), 0UL);
-	}
-
-	/* OK, state is logged, exit diagnostic mode. */
-	psycho_write(strbuf->strbuf_control, control);
-
-	for (i = 0; i < 16; i++) {
-		int j, saw_error, first, last;
-
-		saw_error = 0;
-		first = i * 8;
-		last = first + 8;
-		for (j = first; j < last; j++) {
-			unsigned long errval = stc_error_buf[j];
-			if (errval != 0) {
-				saw_error++;
-				printk("%s: STC_ERR(%d)[wr(%d)rd(%d)]\n",
-				       pbm->name,
-				       j,
-				       (errval & PSYCHO_STCERR_WRITE) ? 1 : 0,
-				       (errval & PSYCHO_STCERR_READ) ? 1 : 0);
-			}
-		}
-		if (saw_error != 0) {
-			unsigned long tagval = stc_tag_buf[i];
-			unsigned long lineval = stc_line_buf[i];
-			printk("%s: STC_TAG(%d)[PA(%016lx)VA(%08lx)V(%d)W(%d)]\n",
-			       pbm->name,
-			       i,
-			       ((tagval & PSYCHO_STCTAG_PPN) >> 19UL),
-			       (tagval & PSYCHO_STCTAG_VPN),
-			       ((tagval & PSYCHO_STCTAG_VALID) ? 1 : 0),
-			       ((tagval & PSYCHO_STCTAG_WRITE) ? 1 : 0));
-			printk("%s: STC_LINE(%d)[LIDX(%lx)SP(%lx)LADDR(%lx)EP(%lx)"
-			       "V(%d)FOFN(%d)]\n",
-			       pbm->name,
-			       i,
-			       ((lineval & PSYCHO_STCLINE_LINDX) >> 21UL),
-			       ((lineval & PSYCHO_STCLINE_SPTR) >> 15UL),
-			       ((lineval & PSYCHO_STCLINE_LADDR) >> 8UL),
-			       ((lineval & PSYCHO_STCLINE_EPTR) >> 2UL),
-			       ((lineval & PSYCHO_STCLINE_VALID) ? 1 : 0),
-			       ((lineval & PSYCHO_STCLINE_FOFN) ? 1 : 0));
-		}
-	}
-
-	spin_unlock(&stc_buf_lock);
-}
-
-static void __psycho_check_stc_error(struct pci_pbm_info *pbm,
-				     unsigned long afsr,
-				     unsigned long afar,
-				     enum psycho_error_type type)
-{
-	__psycho_check_one_stc(pbm,
-			       (pbm == &pbm->parent->pbm_A));
-}
 
 /* When an Uncorrectable Error or a PCI Error happens, we
  * interrogate the IOMMU state to see if it is the cause.
@@ -271,122 +107,7 @@
 #define PSYCHO_IOMMU_TSBBASE	0x0208UL
 #define PSYCHO_IOMMU_FLUSH	0x0210UL
 #define PSYCHO_IOMMU_TAG	0xa580UL
-#define  PSYCHO_IOMMU_TAG_ERRSTS (0x3UL << 23UL)
-#define  PSYCHO_IOMMU_TAG_ERR	 (0x1UL << 22UL)
-#define  PSYCHO_IOMMU_TAG_WRITE	 (0x1UL << 21UL)
-#define  PSYCHO_IOMMU_TAG_STREAM (0x1UL << 20UL)
-#define  PSYCHO_IOMMU_TAG_SIZE	 (0x1UL << 19UL)
-#define  PSYCHO_IOMMU_TAG_VPAGE	 0x7ffffUL
 #define PSYCHO_IOMMU_DATA	0xa600UL
-#define  PSYCHO_IOMMU_DATA_VALID (1UL << 30UL)
-#define  PSYCHO_IOMMU_DATA_CACHE (1UL << 28UL)
-#define  PSYCHO_IOMMU_DATA_PPAGE 0xfffffffUL
-static void psycho_check_iommu_error(struct pci_pbm_info *pbm,
-				     unsigned long afsr,
-				     unsigned long afar,
-				     enum psycho_error_type type)
-{
-	struct iommu *iommu = pbm->iommu;
-	unsigned long iommu_tag[16];
-	unsigned long iommu_data[16];
-	unsigned long flags;
-	u64 control;
-	int i;
-
-	spin_lock_irqsave(&iommu->lock, flags);
-	control = psycho_read(iommu->iommu_control);
-	if (control & PSYCHO_IOMMU_CTRL_XLTEERR) {
-		char *type_string;
-
-		/* Clear the error encountered bit. */
-		control &= ~PSYCHO_IOMMU_CTRL_XLTEERR;
-		psycho_write(iommu->iommu_control, control);
-
-		switch((control & PSYCHO_IOMMU_CTRL_XLTESTAT) >> 25UL) {
-		case 0:
-			type_string = "Protection Error";
-			break;
-		case 1:
-			type_string = "Invalid Error";
-			break;
-		case 2:
-			type_string = "TimeOut Error";
-			break;
-		case 3:
-		default:
-			type_string = "ECC Error";
-			break;
-		};
-		printk("%s: IOMMU Error, type[%s]\n",
-		       pbm->name, type_string);
-
-		/* Put the IOMMU into diagnostic mode and probe
-		 * it's TLB for entries with error status.
-		 *
-		 * It is very possible for another DVMA to occur
-		 * while we do this probe, and corrupt the system
-		 * further.  But we are so screwed at this point
-		 * that we are likely to crash hard anyways, so
-		 * get as much diagnostic information to the
-		 * console as we can.
-		 */
-		psycho_write(iommu->iommu_control,
-			     control | PSYCHO_IOMMU_CTRL_DENAB);
-		for (i = 0; i < 16; i++) {
-			unsigned long base = pbm->controller_regs;
-
-			iommu_tag[i] =
-				psycho_read(base + PSYCHO_IOMMU_TAG + (i * 8UL));
-			iommu_data[i] =
-				psycho_read(base + PSYCHO_IOMMU_DATA + (i * 8UL));
-
-			/* Now clear out the entry. */
-			psycho_write(base + PSYCHO_IOMMU_TAG + (i * 8UL), 0);
-			psycho_write(base + PSYCHO_IOMMU_DATA + (i * 8UL), 0);
-		}
-
-		/* Leave diagnostic mode. */
-		psycho_write(iommu->iommu_control, control);
-
-		for (i = 0; i < 16; i++) {
-			unsigned long tag, data;
-
-			tag = iommu_tag[i];
-			if (!(tag & PSYCHO_IOMMU_TAG_ERR))
-				continue;
-
-			data = iommu_data[i];
-			switch((tag & PSYCHO_IOMMU_TAG_ERRSTS) >> 23UL) {
-			case 0:
-				type_string = "Protection Error";
-				break;
-			case 1:
-				type_string = "Invalid Error";
-				break;
-			case 2:
-				type_string = "TimeOut Error";
-				break;
-			case 3:
-			default:
-				type_string = "ECC Error";
-				break;
-			};
-			printk("%s: IOMMU TAG(%d)[error(%s) wr(%d) str(%d) sz(%dK) vpg(%08lx)]\n",
-			       pbm->name, i, type_string,
-			       ((tag & PSYCHO_IOMMU_TAG_WRITE) ? 1 : 0),
-			       ((tag & PSYCHO_IOMMU_TAG_STREAM) ? 1 : 0),
-			       ((tag & PSYCHO_IOMMU_TAG_SIZE) ? 64 : 8),
-			       (tag & PSYCHO_IOMMU_TAG_VPAGE) << IOMMU_PAGE_SHIFT);
-			printk("%s: IOMMU DATA(%d)[valid(%d) cache(%d) ppg(%016lx)]\n",
-			       pbm->name, i,
-			       ((data & PSYCHO_IOMMU_DATA_VALID) ? 1 : 0),
-			       ((data & PSYCHO_IOMMU_DATA_CACHE) ? 1 : 0),
-			       (data & PSYCHO_IOMMU_DATA_PPAGE) << IOMMU_PAGE_SHIFT);
-		}
-	}
-	__psycho_check_stc_error(pbm, afsr, afar, type);
-	spin_unlock_irqrestore(&iommu->lock, flags);
-}
 
 /* Uncorrectable Errors.  Cause of the error and the address are
  * recorded in the UE_AFSR and UE_AFAR of PSYCHO.  They are errors
@@ -410,15 +131,14 @@
 static irqreturn_t psycho_ue_intr(int irq, void *dev_id)
 {
 	struct pci_pbm_info *pbm = dev_id;
-	struct pci_controller_info *p = pbm->parent;
 	unsigned long afsr_reg = pbm->controller_regs + PSYCHO_UE_AFSR;
 	unsigned long afar_reg = pbm->controller_regs + PSYCHO_UE_AFAR;
 	unsigned long afsr, afar, error_bits;
 	int reported;
 
 	/* Latch uncorrectable error status. */
-	afar = psycho_read(afar_reg);
-	afsr = psycho_read(afsr_reg);
+	afar = upa_readq(afar_reg);
+	afsr = upa_readq(afsr_reg);
 
 	/* Clear the primary/secondary error status bits. */
 	error_bits = afsr &
@@ -426,7 +146,7 @@
 		 PSYCHO_UEAFSR_SPIO | PSYCHO_UEAFSR_SDRD | PSYCHO_UEAFSR_SDWR);
 	if (!error_bits)
 		return IRQ_NONE;
-	psycho_write(afsr_reg, error_bits);
+	upa_writeq(error_bits, afsr_reg);
 
 	/* Log the error. */
 	printk("%s: Uncorrectable Error, primary error type[%s]\n",
@@ -463,8 +183,9 @@
 	printk("]\n");
 
 	/* Interrogate both IOMMUs for error status. */
-	psycho_check_iommu_error(&p->pbm_A, afsr, afar, UE_ERR);
-	psycho_check_iommu_error(&p->pbm_B, afsr, afar, UE_ERR);
+	psycho_check_iommu_error(pbm, afsr, afar, UE_ERR);
+	if (pbm->sibling)
+		psycho_check_iommu_error(pbm->sibling, afsr, afar, UE_ERR);
 
 	return IRQ_HANDLED;
 }
@@ -495,8 +216,8 @@
 	int reported;
 
 	/* Latch error status. */
-	afar = psycho_read(afar_reg);
-	afsr = psycho_read(afsr_reg);
+	afar = upa_readq(afar_reg);
+	afsr = upa_readq(afsr_reg);
 
 	/* Clear primary/secondary error status bits. */
 	error_bits = afsr &
@@ -504,7 +225,7 @@
 		 PSYCHO_CEAFSR_SPIO | PSYCHO_CEAFSR_SDRD | PSYCHO_CEAFSR_SDWR);
 	if (!error_bits)
 		return IRQ_NONE;
-	psycho_write(afsr_reg, error_bits);
+	upa_writeq(error_bits, afsr_reg);
 
 	/* Log the error. */
 	printk("%s: Correctable Error, primary error type[%s]\n",
@@ -554,162 +275,9 @@
  */
 #define PSYCHO_PCI_AFSR_A	0x2010UL
 #define PSYCHO_PCI_AFSR_B	0x4010UL
-#define  PSYCHO_PCIAFSR_PMA	0x8000000000000000UL /* Primary Master Abort Error   */
-#define  PSYCHO_PCIAFSR_PTA	0x4000000000000000UL /* Primary Target Abort Error   */
-#define  PSYCHO_PCIAFSR_PRTRY	0x2000000000000000UL /* Primary Excessive Retries    */
-#define  PSYCHO_PCIAFSR_PPERR	0x1000000000000000UL /* Primary Parity Error         */
-#define  PSYCHO_PCIAFSR_SMA	0x0800000000000000UL /* Secondary Master Abort Error */
-#define  PSYCHO_PCIAFSR_STA	0x0400000000000000UL /* Secondary Target Abort Error */
-#define  PSYCHO_PCIAFSR_SRTRY	0x0200000000000000UL /* Secondary Excessive Retries  */
-#define  PSYCHO_PCIAFSR_SPERR	0x0100000000000000UL /* Secondary Parity Error       */
-#define  PSYCHO_PCIAFSR_RESV1	0x00ff000000000000UL /* Reserved                     */
-#define  PSYCHO_PCIAFSR_BMSK	0x0000ffff00000000UL /* Bytemask of failed transfer  */
-#define  PSYCHO_PCIAFSR_BLK	0x0000000080000000UL /* Trans was block operation    */
-#define  PSYCHO_PCIAFSR_RESV2	0x0000000040000000UL /* Reserved                     */
-#define  PSYCHO_PCIAFSR_MID	0x000000003e000000UL /* MID causing the error        */
-#define  PSYCHO_PCIAFSR_RESV3	0x0000000001ffffffUL /* Reserved                     */
 #define PSYCHO_PCI_AFAR_A	0x2018UL
 #define PSYCHO_PCI_AFAR_B	0x4018UL
 
-static irqreturn_t psycho_pcierr_intr_other(struct pci_pbm_info *pbm, int is_pbm_a)
-{
-	unsigned long csr_reg, csr, csr_error_bits;
-	irqreturn_t ret = IRQ_NONE;
-	u16 stat;
-
-	if (is_pbm_a) {
-		csr_reg = pbm->controller_regs + PSYCHO_PCIA_CTRL;
-	} else {
-		csr_reg = pbm->controller_regs + PSYCHO_PCIB_CTRL;
-	}
-	csr = psycho_read(csr_reg);
-	csr_error_bits =
-		csr & (PSYCHO_PCICTRL_SBH_ERR | PSYCHO_PCICTRL_SERR);
-	if (csr_error_bits) {
-		/* Clear the errors.  */
-		psycho_write(csr_reg, csr);
-
-		/* Log 'em.  */
-		if (csr_error_bits & PSYCHO_PCICTRL_SBH_ERR)
-			printk("%s: PCI streaming byte hole error asserted.\n",
-			       pbm->name);
-		if (csr_error_bits & PSYCHO_PCICTRL_SERR)
-			printk("%s: PCI SERR signal asserted.\n", pbm->name);
-		ret = IRQ_HANDLED;
-	}
-	pci_read_config_word(pbm->pci_bus->self, PCI_STATUS, &stat);
-	if (stat & (PCI_STATUS_PARITY |
-		    PCI_STATUS_SIG_TARGET_ABORT |
-		    PCI_STATUS_REC_TARGET_ABORT |
-		    PCI_STATUS_REC_MASTER_ABORT |
-		    PCI_STATUS_SIG_SYSTEM_ERROR)) {
-		printk("%s: PCI bus error, PCI_STATUS[%04x]\n",
-		       pbm->name, stat);
-		pci_write_config_word(pbm->pci_bus->self, PCI_STATUS, 0xffff);
-		ret = IRQ_HANDLED;
-	}
-	return ret;
-}
-
-static irqreturn_t psycho_pcierr_intr(int irq, void *dev_id)
-{
-	struct pci_pbm_info *pbm = dev_id;
-	struct pci_controller_info *p = pbm->parent;
-	unsigned long afsr_reg, afar_reg;
-	unsigned long afsr, afar, error_bits;
-	int is_pbm_a, reported;
-
-	is_pbm_a = (pbm == &pbm->parent->pbm_A);
-	if (is_pbm_a) {
-		afsr_reg = p->pbm_A.controller_regs + PSYCHO_PCI_AFSR_A;
-		afar_reg = p->pbm_A.controller_regs + PSYCHO_PCI_AFAR_A;
-	} else {
-		afsr_reg = p->pbm_A.controller_regs + PSYCHO_PCI_AFSR_B;
-		afar_reg = p->pbm_A.controller_regs + PSYCHO_PCI_AFAR_B;
-	}
-
-	/* Latch error status. */
-	afar = psycho_read(afar_reg);
-	afsr = psycho_read(afsr_reg);
-
-	/* Clear primary/secondary error status bits. */
-	error_bits = afsr &
-		(PSYCHO_PCIAFSR_PMA | PSYCHO_PCIAFSR_PTA |
-		 PSYCHO_PCIAFSR_PRTRY | PSYCHO_PCIAFSR_PPERR |
-		 PSYCHO_PCIAFSR_SMA | PSYCHO_PCIAFSR_STA |
-		 PSYCHO_PCIAFSR_SRTRY | PSYCHO_PCIAFSR_SPERR);
-	if (!error_bits)
-		return psycho_pcierr_intr_other(pbm, is_pbm_a);
-	psycho_write(afsr_reg, error_bits);
-
-	/* Log the error. */
-	printk("%s: PCI Error, primary error type[%s]\n",
-	       pbm->name,
-	       (((error_bits & PSYCHO_PCIAFSR_PMA) ?
-		 "Master Abort" :
-		 ((error_bits & PSYCHO_PCIAFSR_PTA) ?
-		  "Target Abort" :
-		  ((error_bits & PSYCHO_PCIAFSR_PRTRY) ?
-		   "Excessive Retries" :
-		   ((error_bits & PSYCHO_PCIAFSR_PPERR) ?
-		    "Parity Error" : "???"))))));
-	printk("%s: bytemask[%04lx] UPA_MID[%02lx] was_block(%d)\n",
-	       pbm->name,
-	       (afsr & PSYCHO_PCIAFSR_BMSK) >> 32UL,
-	       (afsr & PSYCHO_PCIAFSR_MID) >> 25UL,
-	       (afsr & PSYCHO_PCIAFSR_BLK) ? 1 : 0);
-	printk("%s: PCI AFAR [%016lx]\n", pbm->name, afar);
-	printk("%s: PCI Secondary errors [", pbm->name);
-	reported = 0;
-	if (afsr & PSYCHO_PCIAFSR_SMA) {
-		reported++;
-		printk("(Master Abort)");
-	}
-	if (afsr & PSYCHO_PCIAFSR_STA) {
-		reported++;
-		printk("(Target Abort)");
-	}
-	if (afsr & PSYCHO_PCIAFSR_SRTRY) {
-		reported++;
-		printk("(Excessive Retries)");
-	}
-	if (afsr & PSYCHO_PCIAFSR_SPERR) {
-		reported++;
-		printk("(Parity Error)");
-	}
-	if (!reported)
-		printk("(none)");
-	printk("]\n");
-
-	/* For the error types shown, scan PBM's PCI bus for devices
-	 * which have logged that error type.
-	 */
-
-	/* If we see a Target Abort, this could be the result of an
-	 * IOMMU translation error of some sort.  It is extremely
-	 * useful to log this information as usually it indicates
-	 * a bug in the IOMMU support code or a PCI device driver.
-	 */
-	if (error_bits & (PSYCHO_PCIAFSR_PTA | PSYCHO_PCIAFSR_STA)) {
-		psycho_check_iommu_error(pbm, afsr, afar, PCI_ERR);
-		pci_scan_for_target_abort(pbm, pbm->pci_bus);
-	}
-	if (error_bits & (PSYCHO_PCIAFSR_PMA | PSYCHO_PCIAFSR_SMA))
-		pci_scan_for_master_abort(pbm, pbm->pci_bus);
-
-	/* For excessive retries, PSYCHO/PBM will abort the device
-	 * and there is no way to specifically check for excessive
-	 * retries in the config space status registers.  So what
-	 * we hope is that we'll catch it via the master/target
-	 * abort events.
-	 */
-
-	if (error_bits & (PSYCHO_PCIAFSR_PPERR | PSYCHO_PCIAFSR_SPERR))
-		pci_scan_for_parity_error(pbm, pbm->pci_bus);
-
-	return IRQ_HANDLED;
-}
-
 /* XXX What about PowerFail/PowerManagement??? -DaveM */
 #define PSYCHO_ECC_CTRL		0x0020
 #define  PSYCHO_ECCCTRL_EE	 0x8000000000000000UL /* Enable ECC Checking */
@@ -717,7 +285,7 @@
 #define  PSYCHO_ECCCTRL_CE	 0x2000000000000000UL /* Enable CE INterrupts */
 static void psycho_register_error_handlers(struct pci_pbm_info *pbm)
 {
-	struct of_device *op = of_find_device_by_node(pbm->prom_node);
+	struct of_device *op = of_find_device_by_node(pbm->op->node);
 	unsigned long base = pbm->controller_regs;
 	u64 tmp;
 	int err;
@@ -760,27 +328,26 @@
 		       "err=%d\n", pbm->name, err);
 
 	/* Enable UE and CE interrupts for controller. */
-	psycho_write(base + PSYCHO_ECC_CTRL,
-		     (PSYCHO_ECCCTRL_EE |
-		      PSYCHO_ECCCTRL_UE |
-		      PSYCHO_ECCCTRL_CE));
+	upa_writeq((PSYCHO_ECCCTRL_EE |
+		    PSYCHO_ECCCTRL_UE |
+		    PSYCHO_ECCCTRL_CE), base + PSYCHO_ECC_CTRL);
 
 	/* Enable PCI Error interrupts and clear error
 	 * bits for each PBM.
 	 */
-	tmp = psycho_read(base + PSYCHO_PCIA_CTRL);
+	tmp = upa_readq(base + PSYCHO_PCIA_CTRL);
 	tmp |= (PSYCHO_PCICTRL_SERR |
 		PSYCHO_PCICTRL_SBH_ERR |
 		PSYCHO_PCICTRL_EEN);
 	tmp &= ~(PSYCHO_PCICTRL_SBH_INT);
-	psycho_write(base + PSYCHO_PCIA_CTRL, tmp);
+	upa_writeq(tmp, base + PSYCHO_PCIA_CTRL);
 		     
-	tmp = psycho_read(base + PSYCHO_PCIB_CTRL);
+	tmp = upa_readq(base + PSYCHO_PCIB_CTRL);
 	tmp |= (PSYCHO_PCICTRL_SERR |
 		PSYCHO_PCICTRL_SBH_ERR |
 		PSYCHO_PCICTRL_EEN);
 	tmp &= ~(PSYCHO_PCICTRL_SBH_INT);
-	psycho_write(base + PSYCHO_PCIB_CTRL, tmp);
+	upa_writeq(tmp, base + PSYCHO_PCIB_CTRL);
 }
 
 /* PSYCHO boot time probing and initialization. */
@@ -801,11 +368,12 @@
 	pci_config_write8(addr, 64);
 }
 
-static void __init psycho_scan_bus(struct pci_pbm_info *pbm)
+static void __init psycho_scan_bus(struct pci_pbm_info *pbm,
+				   struct device *parent)
 {
 	pbm_config_busmastering(pbm);
 	pbm->is_66mhz_capable = 0;
-	pbm->pci_bus = pci_scan_one_pbm(pbm);
+	pbm->pci_bus = pci_scan_one_pbm(pbm, parent);
 
 	/* After the PCI bus scan is complete, we can register
 	 * the error interrupt handlers.
@@ -813,61 +381,6 @@
 	psycho_register_error_handlers(pbm);
 }
 
-static int psycho_iommu_init(struct pci_pbm_info *pbm)
-{
-	struct iommu *iommu = pbm->iommu;
-	unsigned long i;
-	u64 control;
-	int err;
-
-	/* Register addresses. */
-	iommu->iommu_control  = pbm->controller_regs + PSYCHO_IOMMU_CONTROL;
-	iommu->iommu_tsbbase  = pbm->controller_regs + PSYCHO_IOMMU_TSBBASE;
-	iommu->iommu_flush    = pbm->controller_regs + PSYCHO_IOMMU_FLUSH;
-	iommu->iommu_tags     = iommu->iommu_flush + (0xa580UL - 0x0210UL);
-
-	/* PSYCHO's IOMMU lacks ctx flushing. */
-	iommu->iommu_ctxflush = 0;
-
-	/* We use the main control register of PSYCHO as the write
-	 * completion register.
-	 */
-	iommu->write_complete_reg = pbm->controller_regs + PSYCHO_CONTROL;
-
-	/*
-	 * Invalidate TLB Entries.
-	 */
-	control = psycho_read(pbm->controller_regs + PSYCHO_IOMMU_CONTROL);
-	control |= PSYCHO_IOMMU_CTRL_DENAB;
-	psycho_write(pbm->controller_regs + PSYCHO_IOMMU_CONTROL, control);
-	for(i = 0; i < 16; i++) {
-		psycho_write(pbm->controller_regs + PSYCHO_IOMMU_TAG + (i * 8UL), 0);
-		psycho_write(pbm->controller_regs + PSYCHO_IOMMU_DATA + (i * 8UL), 0);
-	}
-
-	/* Leave diag mode enabled for full-flushing done
-	 * in pci_iommu.c
-	 */
-	err = iommu_table_init(iommu, IO_TSB_SIZE, 0xc0000000, 0xffffffff,
-			       pbm->numa_node);
-	if (err)
-		return err;
-
-	psycho_write(pbm->controller_regs + PSYCHO_IOMMU_TSBBASE,
-		     __pa(iommu->page_table));
-
-	control = psycho_read(pbm->controller_regs + PSYCHO_IOMMU_CONTROL);
-	control &= ~(PSYCHO_IOMMU_CTRL_TSBSZ | PSYCHO_IOMMU_CTRL_TBWSZ);
-	control |= (PSYCHO_IOMMU_TSBSZ_128K | PSYCHO_IOMMU_CTRL_ENAB);
-	psycho_write(pbm->controller_regs + PSYCHO_IOMMU_CONTROL, control);
-
-	/* If necessary, hook us up for starfire IRQ translations. */
-	if (this_is_starfire)
-		starfire_hookup(pbm->portid);
-
-	return 0;
-}
-
 #define PSYCHO_IRQ_RETRY	0x1a00UL
 #define PSYCHO_PCIA_DIAG	0x2020UL
 #define PSYCHO_PCIB_DIAG	0x4020UL
@@ -884,28 +397,28 @@
 {
 	u64 tmp;
 
-	psycho_write(pbm->controller_regs + PSYCHO_IRQ_RETRY, 5);
+	upa_writeq(5, pbm->controller_regs + PSYCHO_IRQ_RETRY);
 
 	/* Enable arbiter for all PCI slots. */
-	tmp = psycho_read(pbm->controller_regs + PSYCHO_PCIA_CTRL);
+	tmp = upa_readq(pbm->controller_regs + PSYCHO_PCIA_CTRL);
 	tmp |= PSYCHO_PCICTRL_AEN;
-	psycho_write(pbm->controller_regs + PSYCHO_PCIA_CTRL, tmp);
+	upa_writeq(tmp, pbm->controller_regs + PSYCHO_PCIA_CTRL);
 
-	tmp = psycho_read(pbm->controller_regs + PSYCHO_PCIB_CTRL);
+	tmp = upa_readq(pbm->controller_regs + PSYCHO_PCIB_CTRL);
 	tmp |= PSYCHO_PCICTRL_AEN;
-	psycho_write(pbm->controller_regs + PSYCHO_PCIB_CTRL, tmp);
+	upa_writeq(tmp, pbm->controller_regs + PSYCHO_PCIB_CTRL);
 
 	/* Disable DMA write / PIO read synchronization on
 	 * both PCI bus segments.
 	 * [ U2P Erratum 1243770, STP2223BGA data sheet ]
 	 */
-	tmp = psycho_read(pbm->controller_regs + PSYCHO_PCIA_DIAG);
+	tmp = upa_readq(pbm->controller_regs + PSYCHO_PCIA_DIAG);
 	tmp |= PSYCHO_PCIDIAG_DDWSYNC;
-	psycho_write(pbm->controller_regs + PSYCHO_PCIA_DIAG, tmp);
+	upa_writeq(tmp, pbm->controller_regs + PSYCHO_PCIA_DIAG);
 
-	tmp = psycho_read(pbm->controller_regs + PSYCHO_PCIB_DIAG);
+	tmp = upa_readq(pbm->controller_regs + PSYCHO_PCIB_DIAG);
 	tmp |= PSYCHO_PCIDIAG_DDWSYNC;
-	psycho_write(pbm->controller_regs + PSYCHO_PCIB_DIAG, tmp);
+	upa_writeq(tmp, pbm->controller_regs + PSYCHO_PCIB_DIAG);
 }
 
 static void psycho_pbm_strbuf_init(struct pci_pbm_info *pbm,
@@ -918,10 +431,16 @@
 		pbm->stc.strbuf_control  = base + PSYCHO_STRBUF_CONTROL_A;
 		pbm->stc.strbuf_pflush   = base + PSYCHO_STRBUF_FLUSH_A;
 		pbm->stc.strbuf_fsync    = base + PSYCHO_STRBUF_FSYNC_A;
+		pbm->stc.strbuf_err_stat = base + PSYCHO_STC_ERR_A;
+		pbm->stc.strbuf_tag_diag = base + PSYCHO_STC_TAG_A;
+		pbm->stc.strbuf_line_diag= base + PSYCHO_STC_LINE_A;
 	} else {
 		pbm->stc.strbuf_control  = base + PSYCHO_STRBUF_CONTROL_B;
 		pbm->stc.strbuf_pflush   = base + PSYCHO_STRBUF_FLUSH_B;
 		pbm->stc.strbuf_fsync    = base + PSYCHO_STRBUF_FSYNC_B;
+		pbm->stc.strbuf_err_stat = base + PSYCHO_STC_ERR_B;
+		pbm->stc.strbuf_tag_diag = base + PSYCHO_STC_TAG_B;
+		pbm->stc.strbuf_line_diag= base + PSYCHO_STC_LINE_B;
 	}
 	/* PSYCHO's streaming buffer lacks ctx flushing. */
 	pbm->stc.strbuf_ctxflush      = 0;
@@ -944,7 +463,7 @@
 	 */
 #undef PSYCHO_STRBUF_RERUN_ENABLE
 #undef PSYCHO_STRBUF_RERUN_DISABLE
-	control = psycho_read(pbm->stc.strbuf_control);
+	control = upa_readq(pbm->stc.strbuf_control);
 	control |= PSYCHO_STRBUF_CTRL_ENAB;
 	control &= ~(PSYCHO_STRBUF_CTRL_LENAB | PSYCHO_STRBUF_CTRL_LPTR);
 #ifdef PSYCHO_STRBUF_RERUN_ENABLE
@@ -954,7 +473,7 @@
 	control |= PSYCHO_STRBUF_CTRL_RRDIS;
 #endif
 #endif
-	psycho_write(pbm->stc.strbuf_control, control);
+	upa_writeq(control, pbm->stc.strbuf_control);
 
 	pbm->stc.strbuf_enabled = 1;
 }
@@ -966,111 +485,134 @@
 #define PSYCHO_MEMSPACE_B	0x180000000UL
 #define PSYCHO_MEMSPACE_SIZE	0x07fffffffUL
 
-static void __init psycho_pbm_init(struct pci_controller_info *p,
-			    struct device_node *dp, int is_pbm_a)
+static void __init psycho_pbm_init(struct pci_pbm_info *pbm,
+				   struct of_device *op, int is_pbm_a)
 {
-	struct property *prop;
+	psycho_pbm_init_common(pbm, op, "PSYCHO", PBM_CHIP_TYPE_PSYCHO);
+	psycho_pbm_strbuf_init(pbm, is_pbm_a);
+	psycho_scan_bus(pbm, &op->dev);
+}
+
+static struct pci_pbm_info * __devinit psycho_find_sibling(u32 upa_portid)
+{
 	struct pci_pbm_info *pbm;
 
-	if (is_pbm_a)
-		pbm = &p->pbm_A;
-	else
-		pbm = &p->pbm_B;
-
-	pbm->next = pci_pbm_root;
-	pci_pbm_root = pbm;
-
-	pbm->numa_node = -1;
-
-	pbm->scan_bus = psycho_scan_bus;
-	pbm->pci_ops = &sun4u_pci_ops;
-	pbm->config_space_reg_bits = 8;
-
-	pbm->index = pci_num_pbms++;
-
-	pbm->chip_type = PBM_CHIP_TYPE_PSYCHO;
-	pbm->chip_version = 0;
-	prop = of_find_property(dp, "version#", NULL);
-	if (prop)
-		pbm->chip_version = *(int *) prop->value;
-	pbm->chip_revision = 0;
-	prop = of_find_property(dp, "module-revision#", NULL);
-	if (prop)
-		pbm->chip_revision = *(int *) prop->value;
-
-	pbm->parent = p;
-	pbm->prom_node = dp;
-	pbm->name = dp->full_name;
-
-	printk("%s: PSYCHO PCI Bus Module ver[%x:%x]\n",
-	       pbm->name,
-	       pbm->chip_version, pbm->chip_revision);
-
-	pci_determine_mem_io_space(pbm);
-
-	pci_get_pbm_props(pbm);
-
-	psycho_pbm_strbuf_init(pbm, is_pbm_a);
+	for (pbm = pci_pbm_root; pbm; pbm = pbm->next) {
+		if (pbm->portid == upa_portid)
+			return pbm;
+	}
+	return NULL;
 }
 
 #define PSYCHO_CONFIGSPACE	0x001000000UL
 
-void __init psycho_init(struct device_node *dp, char *model_name)
+static int __devinit psycho_probe(struct of_device *op,
+				  const struct of_device_id *match)
 {
-	struct linux_prom64_registers *pr_regs;
-	struct pci_controller_info *p;
+	const struct linux_prom64_registers *pr_regs;
+	struct device_node *dp = op->node;
 	struct pci_pbm_info *pbm;
 	struct iommu *iommu;
-	struct property *prop;
+	int is_pbm_a, err;
 	u32 upa_portid;
-	int is_pbm_a;
 
-	upa_portid = 0xff;
-	prop = of_find_property(dp, "upa-portid", NULL);
-	if (prop)
-		upa_portid = *(u32 *) prop->value;
+	upa_portid = of_getintprop_default(dp, "upa-portid", 0xff);
 
-	for (pbm = pci_pbm_root; pbm; pbm = pbm->next) {
-		struct pci_controller_info *p = pbm->parent;
+	err = -ENOMEM;
+	pbm = kzalloc(sizeof(*pbm), GFP_KERNEL);
+	if (!pbm) {
+		printk(KERN_ERR PFX "Cannot allocate pci_pbm_info.\n");
+		goto out_err;
+	}
 
-		if (p->pbm_A.portid == upa_portid) {
-			is_pbm_a = (p->pbm_A.prom_node == NULL);
-			psycho_pbm_init(p, dp, is_pbm_a);
-			return;
+	pbm->sibling = psycho_find_sibling(upa_portid);
+	if (pbm->sibling) {
+		iommu = pbm->sibling->iommu;
+	} else {
+		iommu = kzalloc(sizeof(struct iommu), GFP_KERNEL);
+		if (!iommu) {
+			printk(KERN_ERR PFX "Cannot allocate PBM iommu.\n");
+			goto out_free_controller;
 		}
 	}
 
-	p = kzalloc(sizeof(struct pci_controller_info), GFP_ATOMIC);
-	if (!p)
-		goto fatal_memory_error;
-	iommu = kzalloc(sizeof(struct iommu), GFP_ATOMIC);
-	if (!iommu)
-		goto fatal_memory_error;
+	pbm->iommu = iommu;
+	pbm->portid = upa_portid;
 
-	p->pbm_A.iommu = p->pbm_B.iommu = iommu;
-
-	p->pbm_A.portid = upa_portid;
-	p->pbm_B.portid = upa_portid;
-
-	prop = of_find_property(dp, "reg", NULL);
-	pr_regs = prop->value;
-
-	p->pbm_A.controller_regs = pr_regs[2].phys_addr;
-	p->pbm_B.controller_regs = pr_regs[2].phys_addr;
-
-	p->pbm_A.config_space = p->pbm_B.config_space =
-		(pr_regs[2].phys_addr + PSYCHO_CONFIGSPACE);
-
-	psycho_controller_hwinit(&p->pbm_A);
-
-	if (psycho_iommu_init(&p->pbm_A))
-		goto fatal_memory_error;
+	pr_regs = of_get_property(dp, "reg", NULL);
+	err = -ENODEV;
+	if (!pr_regs) {
+		printk(KERN_ERR PFX "No reg property.\n");
+		goto out_free_iommu;
+	}
 
 	is_pbm_a = ((pr_regs[0].phys_addr & 0x6000) == 0x2000);
-	psycho_pbm_init(p, dp, is_pbm_a);
-	return;
 
-fatal_memory_error:
-	prom_printf("PSYCHO: Fatal memory allocation error.\n");
-	prom_halt();
+	pbm->controller_regs = pr_regs[2].phys_addr;
+	pbm->config_space = (pr_regs[2].phys_addr + PSYCHO_CONFIGSPACE);
+
+	if (is_pbm_a) {
+		pbm->pci_afsr = pbm->controller_regs + PSYCHO_PCI_AFSR_A;
+		pbm->pci_afar = pbm->controller_regs + PSYCHO_PCI_AFAR_A;
+		pbm->pci_csr  = pbm->controller_regs + PSYCHO_PCIA_CTRL;
+	} else {
+		pbm->pci_afsr = pbm->controller_regs + PSYCHO_PCI_AFSR_B;
+		pbm->pci_afar = pbm->controller_regs + PSYCHO_PCI_AFAR_B;
+		pbm->pci_csr  = pbm->controller_regs + PSYCHO_PCIB_CTRL;
+	}
+
+	psycho_controller_hwinit(pbm);
+	if (!pbm->sibling) {
+		err = psycho_iommu_init(pbm, 128, 0xc0000000,
+					0xffffffff, PSYCHO_CONTROL);
+		if (err)
+			goto out_free_iommu;
+
+		/* If necessary, hook us up for starfire IRQ translations. */
+		if (this_is_starfire)
+			starfire_hookup(pbm->portid);
+	}
+
+	psycho_pbm_init(pbm, op, is_pbm_a);
+
+	pbm->next = pci_pbm_root;
+	pci_pbm_root = pbm;
+
+	if (pbm->sibling)
+		pbm->sibling->sibling = pbm;
+
+	dev_set_drvdata(&op->dev, pbm);
+
+	return 0;
+
+out_free_iommu:
+	if (!pbm->sibling)
+		kfree(pbm->iommu);
+
+out_free_controller:
+	kfree(pbm);
+
+out_err:
+	return err;
 }
+
+static struct of_device_id __initdata psycho_match[] = {
+	{
+		.name = "pci",
+		.compatible = "pci108e,8000",
+	},
+	{},
+};
+
+static struct of_platform_driver psycho_driver = {
+	.name		= DRIVER_NAME,
+	.match_table	= psycho_match,
+	.probe		= psycho_probe,
+};
+
+static int __init psycho_init(void)
+{
+	return of_register_driver(&psycho_driver, &of_bus_type);
+}
+
+subsys_initcall(psycho_init);
diff --git a/arch/sparc64/kernel/pci_sabre.c b/arch/sparc64/kernel/pci_sabre.c
index ade5184..713257b 100644
--- a/arch/sparc64/kernel/pci_sabre.c
+++ b/arch/sparc64/kernel/pci_sabre.c
@@ -16,31 +16,15 @@
 #include <asm/apb.h>
 #include <asm/iommu.h>
 #include <asm/irq.h>
-#include <asm/smp.h>
-#include <asm/oplib.h>
 #include <asm/prom.h>
+#include <asm/upa.h>
 
 #include "pci_impl.h"
 #include "iommu_common.h"
+#include "psycho_common.h"
 
-/* All SABRE registers are 64-bits.  The following accessor
- * routines are how they are accessed.  The REG parameter
- * is a physical address.
- */
-#define sabre_read(__reg) \
-({	u64 __ret; \
-	__asm__ __volatile__("ldxa [%1] %2, %0" \
-			     : "=r" (__ret) \
-			     : "r" (__reg), "i" (ASI_PHYS_BYPASS_EC_E) \
-			     : "memory"); \
-	__ret; \
-})
-#define sabre_write(__reg, __val) \
-	__asm__ __volatile__("stxa %0, [%1] %2" \
-			     : /* no outputs */ \
-			     : "r" (__val), "r" (__reg), \
-			       "i" (ASI_PHYS_BYPASS_EC_E) \
-			     : "memory")
+#define DRIVER_NAME	"sabre"
+#define PFX		DRIVER_NAME ": "
 
 /* SABRE PCI controller register offsets and definitions. */
 #define SABRE_UE_AFSR		0x0030UL
@@ -208,95 +192,6 @@
 static int hummingbird_p;
 static struct pci_bus *sabre_root_bus;
 
-/* SABRE error handling support. */
-static void sabre_check_iommu_error(struct pci_pbm_info *pbm,
-				    unsigned long afsr,
-				    unsigned long afar)
-{
-	struct iommu *iommu = pbm->iommu;
-	unsigned long iommu_tag[16];
-	unsigned long iommu_data[16];
-	unsigned long flags;
-	u64 control;
-	int i;
-
-	spin_lock_irqsave(&iommu->lock, flags);
-	control = sabre_read(iommu->iommu_control);
-	if (control & SABRE_IOMMUCTRL_ERR) {
-		char *type_string;
-
-		/* Clear the error encountered bit.
-		 * NOTE: On Sabre this is write 1 to clear,
-		 *       which is different from Psycho.
-		 */
-		sabre_write(iommu->iommu_control, control);
-		switch((control & SABRE_IOMMUCTRL_ERRSTS) >> 25UL) {
-		case 1:
-			type_string = "Invalid Error";
-			break;
-		case 3:
-			type_string = "ECC Error";
-			break;
-		default:
-			type_string = "Unknown";
-			break;
-		};
-		printk("%s: IOMMU Error, type[%s]\n",
-		       pbm->name, type_string);
-
-		/* Enter diagnostic mode and probe for error'd
-		 * entries in the IOTLB.
-		 */
-		control &= ~(SABRE_IOMMUCTRL_ERRSTS | SABRE_IOMMUCTRL_ERR);
-		sabre_write(iommu->iommu_control,
-			    (control | SABRE_IOMMUCTRL_DENAB));
-		for (i = 0; i < 16; i++) {
-			unsigned long base = pbm->controller_regs;
-
-			iommu_tag[i] =
-				sabre_read(base + SABRE_IOMMU_TAG + (i * 8UL));
-			iommu_data[i] =
-				sabre_read(base + SABRE_IOMMU_DATA + (i * 8UL));
-			sabre_write(base + SABRE_IOMMU_TAG + (i * 8UL), 0);
-			sabre_write(base + SABRE_IOMMU_DATA + (i * 8UL), 0);
-		}
-		sabre_write(iommu->iommu_control, control);
-
-		for (i = 0; i < 16; i++) {
-			unsigned long tag, data;
-
-			tag = iommu_tag[i];
-			if (!(tag & SABRE_IOMMUTAG_ERR))
-				continue;
-
-			data = iommu_data[i];
-			switch((tag & SABRE_IOMMUTAG_ERRSTS) >> 23UL) {
-			case 1:
-				type_string = "Invalid Error";
-				break;
-			case 3:
-				type_string = "ECC Error";
-				break;
-			default:
-				type_string = "Unknown";
-				break;
-			};
-			printk("%s: IOMMU TAG(%d)[RAW(%016lx)error(%s)wr(%d)sz(%dK)vpg(%08lx)]\n",
-			       pbm->name, i, tag, type_string,
-			       ((tag & SABRE_IOMMUTAG_WRITE) ? 1 : 0),
-			       ((tag & SABRE_IOMMUTAG_SIZE) ? 64 : 8),
-			       ((tag & SABRE_IOMMUTAG_VPN) << IOMMU_PAGE_SHIFT));
-			printk("%s: IOMMU DATA(%d)[RAW(%016lx)valid(%d)used(%d)cache(%d)ppg(%016lx)\n",
-			       pbm->name, i, data,
-			       ((data & SABRE_IOMMUDATA_VALID) ? 1 : 0),
-			       ((data & SABRE_IOMMUDATA_USED) ? 1 : 0),
-			       ((data & SABRE_IOMMUDATA_CACHE) ? 1 : 0),
-			       ((data & SABRE_IOMMUDATA_PPN) << IOMMU_PAGE_SHIFT));
-		}
-	}
-	spin_unlock_irqrestore(&iommu->lock, flags);
-}
-
 static irqreturn_t sabre_ue_intr(int irq, void *dev_id)
 {
 	struct pci_pbm_info *pbm = dev_id;
@@ -306,8 +201,8 @@
 	int reported;
 
 	/* Latch uncorrectable error status. */
-	afar = sabre_read(afar_reg);
-	afsr = sabre_read(afsr_reg);
+	afar = upa_readq(afar_reg);
+	afsr = upa_readq(afsr_reg);
 
 	/* Clear the primary/secondary error status bits. */
 	error_bits = afsr &
@@ -316,7 +211,7 @@
 		 SABRE_UEAFSR_SDTE | SABRE_UEAFSR_PDTE);
 	if (!error_bits)
 		return IRQ_NONE;
-	sabre_write(afsr_reg, error_bits);
+	upa_writeq(error_bits, afsr_reg);
 
 	/* Log the error. */
 	printk("%s: Uncorrectable Error, primary error type[%s%s]\n",
@@ -352,7 +247,7 @@
 	printk("]\n");
 
 	/* Interrogate IOMMU for error status. */
-	sabre_check_iommu_error(pbm, afsr, afar);
+	psycho_check_iommu_error(pbm, afsr, afar, UE_ERR);
 
 	return IRQ_HANDLED;
 }
@@ -366,8 +261,8 @@
 	int reported;
 
 	/* Latch error status. */
-	afar = sabre_read(afar_reg);
-	afsr = sabre_read(afsr_reg);
+	afar = upa_readq(afar_reg);
+	afsr = upa_readq(afsr_reg);
 
 	/* Clear primary/secondary error status bits. */
 	error_bits = afsr &
@@ -375,7 +270,7 @@
 		 SABRE_CEAFSR_SDRD | SABRE_CEAFSR_SDWR);
 	if (!error_bits)
 		return IRQ_NONE;
-	sabre_write(afsr_reg, error_bits);
+	upa_writeq(error_bits, afsr_reg);
 
 	/* Log the error. */
 	printk("%s: Correctable Error, primary error type[%s]\n",
@@ -413,136 +308,9 @@
 	return IRQ_HANDLED;
 }
 
-static irqreturn_t sabre_pcierr_intr_other(struct pci_pbm_info *pbm)
-{
-	unsigned long csr_reg, csr, csr_error_bits;
-	irqreturn_t ret = IRQ_NONE;
-	u16 stat;
-
-	csr_reg = pbm->controller_regs + SABRE_PCICTRL;
-	csr = sabre_read(csr_reg);
-	csr_error_bits =
-		csr & SABRE_PCICTRL_SERR;
-	if (csr_error_bits) {
-		/* Clear the errors.  */
-		sabre_write(csr_reg, csr);
-
-		/* Log 'em.  */
-		if (csr_error_bits & SABRE_PCICTRL_SERR)
-			printk("%s: PCI SERR signal asserted.\n",
-			       pbm->name);
-		ret = IRQ_HANDLED;
-	}
-	pci_bus_read_config_word(sabre_root_bus, 0,
-				 PCI_STATUS, &stat);
-	if (stat & (PCI_STATUS_PARITY |
-		    PCI_STATUS_SIG_TARGET_ABORT |
-		    PCI_STATUS_REC_TARGET_ABORT |
-		    PCI_STATUS_REC_MASTER_ABORT |
-		    PCI_STATUS_SIG_SYSTEM_ERROR)) {
-		printk("%s: PCI bus error, PCI_STATUS[%04x]\n",
-		       pbm->name, stat);
-		pci_bus_write_config_word(sabre_root_bus, 0,
-					  PCI_STATUS, 0xffff);
-		ret = IRQ_HANDLED;
-	}
-	return ret;
-}
-
-static irqreturn_t sabre_pcierr_intr(int irq, void *dev_id)
-{
-	struct pci_pbm_info *pbm = dev_id;
-	unsigned long afsr_reg, afar_reg;
-	unsigned long afsr, afar, error_bits;
-	int reported;
-
-	afsr_reg = pbm->controller_regs + SABRE_PIOAFSR;
-	afar_reg = pbm->controller_regs + SABRE_PIOAFAR;
-
-	/* Latch error status. */
-	afar = sabre_read(afar_reg);
-	afsr = sabre_read(afsr_reg);
-
-	/* Clear primary/secondary error status bits. */
-	error_bits = afsr &
-		(SABRE_PIOAFSR_PMA | SABRE_PIOAFSR_PTA |
-		 SABRE_PIOAFSR_PRTRY | SABRE_PIOAFSR_PPERR |
-		 SABRE_PIOAFSR_SMA | SABRE_PIOAFSR_STA |
-		 SABRE_PIOAFSR_SRTRY | SABRE_PIOAFSR_SPERR);
-	if (!error_bits)
-		return sabre_pcierr_intr_other(pbm);
-	sabre_write(afsr_reg, error_bits);
-
-	/* Log the error. */
-	printk("%s: PCI Error, primary error type[%s]\n",
-	       pbm->name,
-	       (((error_bits & SABRE_PIOAFSR_PMA) ?
-		 "Master Abort" :
-		 ((error_bits & SABRE_PIOAFSR_PTA) ?
-		  "Target Abort" :
-		  ((error_bits & SABRE_PIOAFSR_PRTRY) ?
-		   "Excessive Retries" :
-		   ((error_bits & SABRE_PIOAFSR_PPERR) ?
-		    "Parity Error" : "???"))))));
-	printk("%s: bytemask[%04lx] was_block(%d)\n",
-	       pbm->name,
-	       (afsr & SABRE_PIOAFSR_BMSK) >> 32UL,
-	       (afsr & SABRE_PIOAFSR_BLK) ? 1 : 0);
-	printk("%s: PCI AFAR [%016lx]\n", pbm->name, afar);
-	printk("%s: PCI Secondary errors [", pbm->name);
-	reported = 0;
-	if (afsr & SABRE_PIOAFSR_SMA) {
-		reported++;
-		printk("(Master Abort)");
-	}
-	if (afsr & SABRE_PIOAFSR_STA) {
-		reported++;
-		printk("(Target Abort)");
-	}
-	if (afsr & SABRE_PIOAFSR_SRTRY) {
-		reported++;
-		printk("(Excessive Retries)");
-	}
-	if (afsr & SABRE_PIOAFSR_SPERR) {
-		reported++;
-		printk("(Parity Error)");
-	}
-	if (!reported)
-		printk("(none)");
-	printk("]\n");
-
-	/* For the error types shown, scan both PCI buses for devices
-	 * which have logged that error type.
-	 */
-
-	/* If we see a Target Abort, this could be the result of an
-	 * IOMMU translation error of some sort.  It is extremely
-	 * useful to log this information as usually it indicates
-	 * a bug in the IOMMU support code or a PCI device driver.
-	 */
-	if (error_bits & (SABRE_PIOAFSR_PTA | SABRE_PIOAFSR_STA)) {
-		sabre_check_iommu_error(pbm, afsr, afar);
-		pci_scan_for_target_abort(pbm, pbm->pci_bus);
-	}
-	if (error_bits & (SABRE_PIOAFSR_PMA | SABRE_PIOAFSR_SMA))
-		pci_scan_for_master_abort(pbm, pbm->pci_bus);
-
-	/* For excessive retries, SABRE/PBM will abort the device
-	 * and there is no way to specifically check for excessive
-	 * retries in the config space status registers.  So what
-	 * we hope is that we'll catch it via the master/target
-	 * abort events.
-	 */
-
-	if (error_bits & (SABRE_PIOAFSR_PPERR | SABRE_PIOAFSR_SPERR))
-		pci_scan_for_parity_error(pbm, pbm->pci_bus);
-
-	return IRQ_HANDLED;
-}
-
 static void sabre_register_error_handlers(struct pci_pbm_info *pbm)
 {
-	struct device_node *dp = pbm->prom_node;
+	struct device_node *dp = pbm->op->node;
 	struct of_device *op;
 	unsigned long base = pbm->controller_regs;
 	u64 tmp;
@@ -568,33 +336,34 @@
 	 * registering the handler so that we don't get spurious
 	 * interrupts.
 	 */
-	sabre_write(base + SABRE_UE_AFSR,
-		    (SABRE_UEAFSR_PDRD | SABRE_UEAFSR_PDWR |
-		     SABRE_UEAFSR_SDRD | SABRE_UEAFSR_SDWR |
-		     SABRE_UEAFSR_SDTE | SABRE_UEAFSR_PDTE));
+	upa_writeq((SABRE_UEAFSR_PDRD | SABRE_UEAFSR_PDWR |
+		    SABRE_UEAFSR_SDRD | SABRE_UEAFSR_SDWR |
+		    SABRE_UEAFSR_SDTE | SABRE_UEAFSR_PDTE),
+		   base + SABRE_UE_AFSR);
 
 	err = request_irq(op->irqs[1], sabre_ue_intr, 0, "SABRE_UE", pbm);
 	if (err)
 		printk(KERN_WARNING "%s: Couldn't register UE, err=%d.\n",
 		       pbm->name, err);
 
-	sabre_write(base + SABRE_CE_AFSR,
-		    (SABRE_CEAFSR_PDRD | SABRE_CEAFSR_PDWR |
-		     SABRE_CEAFSR_SDRD | SABRE_CEAFSR_SDWR));
+	upa_writeq((SABRE_CEAFSR_PDRD | SABRE_CEAFSR_PDWR |
+		    SABRE_CEAFSR_SDRD | SABRE_CEAFSR_SDWR),
+		   base + SABRE_CE_AFSR);
+
 
 	err = request_irq(op->irqs[2], sabre_ce_intr, 0, "SABRE_CE", pbm);
 	if (err)
 		printk(KERN_WARNING "%s: Couldn't register CE, err=%d.\n",
 		       pbm->name, err);
-	err = request_irq(op->irqs[0], sabre_pcierr_intr, 0,
+	err = request_irq(op->irqs[0], psycho_pcierr_intr, 0,
 			  "SABRE_PCIERR", pbm);
 	if (err)
 		printk(KERN_WARNING "%s: Couldn't register PCIERR, err=%d.\n",
 		       pbm->name, err);
 
-	tmp = sabre_read(base + SABRE_PCICTRL);
+	tmp = upa_readq(base + SABRE_PCICTRL);
 	tmp |= SABRE_PCICTRL_ERREN;
-	sabre_write(base + SABRE_PCICTRL, tmp);
+	upa_writeq(tmp, base + SABRE_PCICTRL);
 }
 
 static void apb_init(struct pci_bus *sabre_bus)
@@ -633,7 +402,8 @@
 	}
 }
 
-static void __init sabre_scan_bus(struct pci_pbm_info *pbm)
+static void __init sabre_scan_bus(struct pci_pbm_info *pbm,
+				  struct device *parent)
 {
 	static int once;
 
@@ -656,12 +426,12 @@
 	 * to live at bus 0.
 	 */
 	if (once != 0) {
-		prom_printf("SABRE: Multiple controllers unsupported.\n");
-		prom_halt();
+		printk(KERN_ERR PFX "Multiple controllers unsupported.\n");
+		return;
 	}
 	once++;
 
-	pbm->pci_bus = pci_scan_one_pbm(pbm);
+	pbm->pci_bus = pci_scan_one_pbm(pbm, parent);
 	if (!pbm->pci_bus)
 		return;
 
@@ -672,133 +442,58 @@
 	sabre_register_error_handlers(pbm);
 }
 
-static int sabre_iommu_init(struct pci_pbm_info *pbm,
-			    int tsbsize, unsigned long dvma_offset,
-			    u32 dma_mask)
+static void __init sabre_pbm_init(struct pci_pbm_info *pbm,
+				  struct of_device *op)
 {
-	struct iommu *iommu = pbm->iommu;
-	unsigned long i;
-	u64 control;
-	int err;
-
-	/* Register addresses. */
-	iommu->iommu_control  = pbm->controller_regs + SABRE_IOMMU_CONTROL;
-	iommu->iommu_tsbbase  = pbm->controller_regs + SABRE_IOMMU_TSBBASE;
-	iommu->iommu_flush    = pbm->controller_regs + SABRE_IOMMU_FLUSH;
-	iommu->iommu_tags     = iommu->iommu_flush + (0xa580UL - 0x0210UL);
-	iommu->write_complete_reg = pbm->controller_regs + SABRE_WRSYNC;
-	/* Sabre's IOMMU lacks ctx flushing. */
-	iommu->iommu_ctxflush = 0;
-                                        
-	/* Invalidate TLB Entries. */
-	control = sabre_read(pbm->controller_regs + SABRE_IOMMU_CONTROL);
-	control |= SABRE_IOMMUCTRL_DENAB;
-	sabre_write(pbm->controller_regs + SABRE_IOMMU_CONTROL, control);
-
-	for(i = 0; i < 16; i++) {
-		sabre_write(pbm->controller_regs + SABRE_IOMMU_TAG + (i * 8UL), 0);
-		sabre_write(pbm->controller_regs + SABRE_IOMMU_DATA + (i * 8UL), 0);
-	}
-
-	/* Leave diag mode enabled for full-flushing done
-	 * in pci_iommu.c
-	 */
-	err = iommu_table_init(iommu, tsbsize * 1024 * 8,
-			       dvma_offset, dma_mask, pbm->numa_node);
-	if (err)
-		return err;
-
-	sabre_write(pbm->controller_regs + SABRE_IOMMU_TSBBASE,
-		    __pa(iommu->page_table));
-
-	control = sabre_read(pbm->controller_regs + SABRE_IOMMU_CONTROL);
-	control &= ~(SABRE_IOMMUCTRL_TSBSZ | SABRE_IOMMUCTRL_TBWSZ);
-	control |= SABRE_IOMMUCTRL_ENAB;
-	switch(tsbsize) {
-	case 64:
-		control |= SABRE_IOMMU_TSBSZ_64K;
-		break;
-	case 128:
-		control |= SABRE_IOMMU_TSBSZ_128K;
-		break;
-	default:
-		prom_printf("iommu_init: Illegal TSB size %d\n", tsbsize);
-		prom_halt();
-		break;
-	}
-	sabre_write(pbm->controller_regs + SABRE_IOMMU_CONTROL, control);
-
-	return 0;
+	psycho_pbm_init_common(pbm, op, "SABRE", PBM_CHIP_TYPE_SABRE);
+	pbm->pci_afsr = pbm->controller_regs + SABRE_PIOAFSR;
+	pbm->pci_afar = pbm->controller_regs + SABRE_PIOAFAR;
+	pbm->pci_csr = pbm->controller_regs + SABRE_PCICTRL;
+	sabre_scan_bus(pbm, &op->dev);
 }
 
-static void __init sabre_pbm_init(struct pci_controller_info *p,
-				  struct pci_pbm_info *pbm, struct device_node *dp)
-{
-	pbm->name = dp->full_name;
-	printk("%s: SABRE PCI Bus Module\n", pbm->name);
-
-	pbm->numa_node = -1;
-
-	pbm->scan_bus = sabre_scan_bus;
-	pbm->pci_ops = &sun4u_pci_ops;
-	pbm->config_space_reg_bits = 8;
-
-	pbm->index = pci_num_pbms++;
-
-	pbm->chip_type = PBM_CHIP_TYPE_SABRE;
-	pbm->parent = p;
-	pbm->prom_node = dp;
-	pci_get_pbm_props(pbm);
-
-	pci_determine_mem_io_space(pbm);
-}
-
-void __init sabre_init(struct device_node *dp, char *model_name)
+static int __devinit sabre_probe(struct of_device *op,
+				 const struct of_device_id *match)
 {
 	const struct linux_prom64_registers *pr_regs;
-	struct pci_controller_info *p;
+	struct device_node *dp = op->node;
 	struct pci_pbm_info *pbm;
-	struct iommu *iommu;
-	int tsbsize;
-	const u32 *vdma;
 	u32 upa_portid, dma_mask;
+	struct iommu *iommu;
+	int tsbsize, err;
+	const u32 *vdma;
 	u64 clear_irq;
 
-	hummingbird_p = 0;
-	if (!strcmp(model_name, "pci108e,a001"))
-		hummingbird_p = 1;
-	else if (!strcmp(model_name, "SUNW,sabre")) {
-		const char *compat = of_get_property(dp, "compatible", NULL);
-		if (compat && !strcmp(compat, "pci108e,a001"))
-			hummingbird_p = 1;
-		if (!hummingbird_p) {
-			struct device_node *dp;
+	hummingbird_p = (match->data != NULL);
+	if (!hummingbird_p) {
+		struct device_node *cpu_dp;
 
-			/* Of course, Sun has to encode things a thousand
-			 * different ways, inconsistently.
-			 */
-			for_each_node_by_type(dp, "cpu") {
-				if (!strcmp(dp->name, "SUNW,UltraSPARC-IIe"))
-					hummingbird_p = 1;
-			}
+		/* Of course, Sun has to encode things a thousand
+		 * different ways, inconsistently.
+		 */
+		for_each_node_by_type(cpu_dp, "cpu") {
+			if (!strcmp(cpu_dp->name, "SUNW,UltraSPARC-IIe"))
+				hummingbird_p = 1;
 		}
 	}
 
-	p = kzalloc(sizeof(*p), GFP_ATOMIC);
-	if (!p)
-		goto fatal_memory_error;
+	err = -ENOMEM;
+	pbm = kzalloc(sizeof(*pbm), GFP_KERNEL);
+	if (!pbm) {
+		printk(KERN_ERR PFX "Cannot allocate pci_pbm_info.\n");
+		goto out_err;
+	}
 
-	iommu = kzalloc(sizeof(*iommu), GFP_ATOMIC);
-	if (!iommu)
-		goto fatal_memory_error;
-	pbm = &p->pbm_A;
+	iommu = kzalloc(sizeof(*iommu), GFP_KERNEL);
+	if (!iommu) {
+		printk(KERN_ERR PFX "Cannot allocate PBM iommu.\n");
+		goto out_free_controller;
+	}
+
 	pbm->iommu = iommu;
 
 	upa_portid = of_getintprop_default(dp, "upa-portid", 0xff);
 
-	pbm->next = pci_pbm_root;
-	pci_pbm_root = pbm;
-
 	pbm->portid = upa_portid;
 
 	/*
@@ -806,6 +501,11 @@
 	 */
 	
 	pr_regs = of_get_property(dp, "reg", NULL);
+	err = -ENODEV;
+	if (!pr_regs) {
+		printk(KERN_ERR PFX "No reg property\n");
+		goto out_free_iommu;
+	}
 
 	/*
 	 * First REG in property is base of entire SABRE register space.
@@ -816,22 +516,25 @@
 
 	/* PCI first */
 	for (clear_irq = SABRE_ICLR_A_SLOT0; clear_irq < SABRE_ICLR_B_SLOT0 + 0x80; clear_irq += 8)
-		sabre_write(pbm->controller_regs + clear_irq, 0x0UL);
+		upa_writeq(0x0UL, pbm->controller_regs + clear_irq);
 
 	/* Then OBIO */
 	for (clear_irq = SABRE_ICLR_SCSI; clear_irq < SABRE_ICLR_SCSI + 0x80; clear_irq += 8)
-		sabre_write(pbm->controller_regs + clear_irq, 0x0UL);
+		upa_writeq(0x0UL, pbm->controller_regs + clear_irq);
 
 	/* Error interrupts are enabled later after the bus scan. */
-	sabre_write(pbm->controller_regs + SABRE_PCICTRL,
-		    (SABRE_PCICTRL_MRLEN   | SABRE_PCICTRL_SERR |
-		     SABRE_PCICTRL_ARBPARK | SABRE_PCICTRL_AEN));
+	upa_writeq((SABRE_PCICTRL_MRLEN   | SABRE_PCICTRL_SERR |
+		    SABRE_PCICTRL_ARBPARK | SABRE_PCICTRL_AEN),
+		   pbm->controller_regs + SABRE_PCICTRL);
 
 	/* Now map in PCI config space for entire SABRE. */
-	pbm->config_space =
-		(pbm->controller_regs + SABRE_CONFIGSPACE);
+	pbm->config_space = pbm->controller_regs + SABRE_CONFIGSPACE;
 
 	vdma = of_get_property(dp, "virtual-dma", NULL);
+	if (!vdma) {
+		printk(KERN_ERR PFX "No virtual-dma property\n");
+		goto out_free_iommu;
+	}
 
 	dma_mask = vdma[0];
 	switch(vdma[1]) {
@@ -849,20 +552,58 @@
 			tsbsize = 128;
 			break;
 		default:
-			prom_printf("SABRE: strange virtual-dma size.\n");
-			prom_halt();
+			printk(KERN_ERR PFX "Strange virtual-dma size.\n");
+			goto out_free_iommu;
 	}
 
-	if (sabre_iommu_init(pbm, tsbsize, vdma[0], dma_mask))
-		goto fatal_memory_error;
+	err = psycho_iommu_init(pbm, tsbsize, vdma[0], dma_mask, SABRE_WRSYNC);
+	if (err)
+		goto out_free_iommu;
 
 	/*
 	 * Look for APB underneath.
 	 */
-	sabre_pbm_init(p, pbm, dp);
-	return;
+	sabre_pbm_init(pbm, op);
 
-fatal_memory_error:
-	prom_printf("SABRE: Fatal memory allocation error.\n");
-	prom_halt();
+	pbm->next = pci_pbm_root;
+	pci_pbm_root = pbm;
+
+	dev_set_drvdata(&op->dev, pbm);
+
+	return 0;
+
+out_free_iommu:
+	kfree(pbm->iommu);
+
+out_free_controller:
+	kfree(pbm);
+
+out_err:
+	return err;
 }
+
+static struct of_device_id __initdata sabre_match[] = {
+	{
+		.name = "pci",
+		.compatible = "pci108e,a001",
+		.data = (void *) 1,
+	},
+	{
+		.name = "pci",
+		.compatible = "pci108e,a000",
+	},
+	{},
+};
+
+static struct of_platform_driver sabre_driver = {
+	.name		= DRIVER_NAME,
+	.match_table	= sabre_match,
+	.probe		= sabre_probe,
+};
+
+static int __init sabre_init(void)
+{
+	return of_register_driver(&sabre_driver, &of_bus_type);
+}
+
+subsys_initcall(sabre_init);
diff --git a/arch/sparc64/kernel/pci_schizo.c b/arch/sparc64/kernel/pci_schizo.c
index 9248c67..45d9dba 100644
--- a/arch/sparc64/kernel/pci_schizo.c
+++ b/arch/sparc64/kernel/pci_schizo.c
@@ -1,6 +1,6 @@
 /* pci_schizo.c: SCHIZO/TOMATILLO specific PCI controller support.
  *
- * Copyright (C) 2001, 2002, 2003, 2007 David S. Miller (davem@davemloft.net)
+ * Copyright (C) 2001, 2002, 2003, 2007, 2008 David S. Miller (davem@davemloft.net)
  */
 
 #include <linux/kernel.h>
@@ -13,32 +13,15 @@
 
 #include <asm/iommu.h>
 #include <asm/irq.h>
-#include <asm/upa.h>
 #include <asm/pstate.h>
 #include <asm/prom.h>
-#include <asm/oplib.h>
+#include <asm/upa.h>
 
 #include "pci_impl.h"
 #include "iommu_common.h"
 
-/* All SCHIZO registers are 64-bits.  The following accessor
- * routines are how they are accessed.  The REG parameter
- * is a physical address.
- */
-#define schizo_read(__reg) \
-({	u64 __ret; \
-	__asm__ __volatile__("ldxa [%1] %2, %0" \
-			     : "=r" (__ret) \
-			     : "r" (__reg), "i" (ASI_PHYS_BYPASS_EC_E) \
-			     : "memory"); \
-	__ret; \
-})
-#define schizo_write(__reg, __val) \
-	__asm__ __volatile__("stxa %0, [%1] %2" \
-			     : /* no outputs */ \
-			     : "r" (__val), "r" (__reg), \
-			       "i" (ASI_PHYS_BYPASS_EC_E) \
-			     : "memory")
+#define DRIVER_NAME	"schizo"
+#define PFX		DRIVER_NAME ": "
 
 /* This is a convention that at least Excalibur and Merlin
  * follow.  I suppose the SCHIZO used in Starcat and friends
@@ -163,25 +146,25 @@
 	 * invalidating it before it has a chance to reach
 	 * main memory.
 	 */
-	control = schizo_read(strbuf->strbuf_control);
-	schizo_write(strbuf->strbuf_control,
-		     (control | SCHIZO_STRBUF_CTRL_DENAB));
+	control = upa_readq(strbuf->strbuf_control);
+	upa_writeq((control | SCHIZO_STRBUF_CTRL_DENAB),
+		   strbuf->strbuf_control);
 	for (i = 0; i < 128; i++) {
 		unsigned long val;
 
-		val = schizo_read(err_base + (i * 8UL));
-		schizo_write(err_base + (i * 8UL), 0UL);
+		val = upa_readq(err_base + (i * 8UL));
+		upa_writeq(0UL, err_base + (i * 8UL));
 		stc_error_buf[i] = val;
 	}
 	for (i = 0; i < 16; i++) {
-		stc_tag_buf[i] = schizo_read(tag_base + (i * 8UL));
-		stc_line_buf[i] = schizo_read(line_base + (i * 8UL));
-		schizo_write(tag_base + (i * 8UL), 0UL);
-		schizo_write(line_base + (i * 8UL), 0UL);
+		stc_tag_buf[i] = upa_readq(tag_base + (i * 8UL));
+		stc_line_buf[i] = upa_readq(line_base + (i * 8UL));
+		upa_writeq(0UL, tag_base + (i * 8UL));
+		upa_writeq(0UL, line_base + (i * 8UL));
 	}
 
 	/* OK, state is logged, exit diagnostic mode. */
-	schizo_write(strbuf->strbuf_control, control);
+	upa_writeq(control, strbuf->strbuf_control);
 
 	for (i = 0; i < 16; i++) {
 		int j, saw_error, first, last;
@@ -258,14 +241,14 @@
 	int i;
 
 	spin_lock_irqsave(&iommu->lock, flags);
-	control = schizo_read(iommu->iommu_control);
+	control = upa_readq(iommu->iommu_control);
 	if (control & SCHIZO_IOMMU_CTRL_XLTEERR) {
 		unsigned long base;
 		char *type_string;
 
 		/* Clear the error encountered bit. */
 		control &= ~SCHIZO_IOMMU_CTRL_XLTEERR;
-		schizo_write(iommu->iommu_control, control);
+		upa_writeq(control, iommu->iommu_control);
 
 		switch((control & SCHIZO_IOMMU_CTRL_XLTESTAT) >> 25UL) {
 		case 0:
@@ -295,24 +278,24 @@
 		 * get as much diagnostic information to the
 		 * console as we can.
 		 */
-		schizo_write(iommu->iommu_control,
-			     control | SCHIZO_IOMMU_CTRL_DENAB);
+		upa_writeq(control | SCHIZO_IOMMU_CTRL_DENAB,
+			   iommu->iommu_control);
 
 		base = pbm->pbm_regs;
 
 		for (i = 0; i < 16; i++) {
 			iommu_tag[i] =
-				schizo_read(base + SCHIZO_IOMMU_TAG + (i * 8UL));
+				upa_readq(base + SCHIZO_IOMMU_TAG + (i * 8UL));
 			iommu_data[i] =
-				schizo_read(base + SCHIZO_IOMMU_DATA + (i * 8UL));
+				upa_readq(base + SCHIZO_IOMMU_DATA + (i * 8UL));
 
 			/* Now clear out the entry. */
-			schizo_write(base + SCHIZO_IOMMU_TAG + (i * 8UL), 0);
-			schizo_write(base + SCHIZO_IOMMU_DATA + (i * 8UL), 0);
+			upa_writeq(0, base + SCHIZO_IOMMU_TAG + (i * 8UL));
+			upa_writeq(0, base + SCHIZO_IOMMU_DATA + (i * 8UL));
 		}
 
 		/* Leave diagnostic mode. */
-		schizo_write(iommu->iommu_control, control);
+		upa_writeq(control, iommu->iommu_control);
 
 		for (i = 0; i < 16; i++) {
 			unsigned long tag, data;
@@ -357,11 +340,12 @@
 	spin_unlock_irqrestore(&iommu->lock, flags);
 }
 
-static void schizo_check_iommu_error(struct pci_controller_info *p,
+static void schizo_check_iommu_error(struct pci_pbm_info *pbm,
 				     enum schizo_error_type type)
 {
-	schizo_check_iommu_error_pbm(&p->pbm_A, type);
-	schizo_check_iommu_error_pbm(&p->pbm_B, type);
+	schizo_check_iommu_error_pbm(pbm, type);
+	if (pbm->sibling)
+		schizo_check_iommu_error_pbm(pbm->sibling, type);
 }
 
 /* Uncorrectable ECC error status gathering. */
@@ -386,14 +370,13 @@
 static irqreturn_t schizo_ue_intr(int irq, void *dev_id)
 {
 	struct pci_pbm_info *pbm = dev_id;
-	struct pci_controller_info *p = pbm->parent;
 	unsigned long afsr_reg = pbm->controller_regs + SCHIZO_UE_AFSR;
 	unsigned long afar_reg = pbm->controller_regs + SCHIZO_UE_AFAR;
 	unsigned long afsr, afar, error_bits;
 	int reported, limit;
 
 	/* Latch uncorrectable error status. */
-	afar = schizo_read(afar_reg);
+	afar = upa_readq(afar_reg);
 
 	/* If either of the error pending bits are set in the
 	 * AFSR, the error status is being actively updated by
@@ -401,7 +384,7 @@
 	 */
 	limit = 1000;
 	do {
-		afsr = schizo_read(afsr_reg);
+		afsr = upa_readq(afsr_reg);
 	} while ((afsr & SCHIZO_UEAFSR_ERRPNDG) != 0 && --limit);
 
 	/* Clear the primary/secondary error status bits. */
@@ -410,7 +393,7 @@
 		 SCHIZO_UEAFSR_SPIO | SCHIZO_UEAFSR_SDMA);
 	if (!error_bits)
 		return IRQ_NONE;
-	schizo_write(afsr_reg, error_bits);
+	upa_writeq(error_bits, afsr_reg);
 
 	/* Log the error. */
 	printk("%s: Uncorrectable Error, primary error type[%s]\n",
@@ -449,7 +432,7 @@
 	printk("]\n");
 
 	/* Interrogate IOMMU for error status. */
-	schizo_check_iommu_error(p, UE_ERR);
+	schizo_check_iommu_error(pbm, UE_ERR);
 
 	return IRQ_HANDLED;
 }
@@ -481,7 +464,7 @@
 	int reported, limit;
 
 	/* Latch error status. */
-	afar = schizo_read(afar_reg);
+	afar = upa_readq(afar_reg);
 
 	/* If either of the error pending bits are set in the
 	 * AFSR, the error status is being actively updated by
@@ -489,7 +472,7 @@
 	 */
 	limit = 1000;
 	do {
-		afsr = schizo_read(afsr_reg);
+		afsr = upa_readq(afsr_reg);
 	} while ((afsr & SCHIZO_UEAFSR_ERRPNDG) != 0 && --limit);
 
 	/* Clear primary/secondary error status bits. */
@@ -498,7 +481,7 @@
 		 SCHIZO_CEAFSR_SPIO | SCHIZO_CEAFSR_SDMA);
 	if (!error_bits)
 		return IRQ_NONE;
-	schizo_write(afsr_reg, error_bits);
+	upa_writeq(error_bits, afsr_reg);
 
 	/* Log the error. */
 	printk("%s: Correctable Error, primary error type[%s]\n",
@@ -600,7 +583,7 @@
 	u16 stat;
 
 	csr_reg = pbm->pbm_regs + SCHIZO_PCI_CTRL;
-	csr = schizo_read(csr_reg);
+	csr = upa_readq(csr_reg);
 	csr_error_bits =
 		csr & (SCHIZO_PCICTRL_BUS_UNUS |
 		       SCHIZO_PCICTRL_TTO_ERR |
@@ -610,7 +593,7 @@
 		       SCHIZO_PCICTRL_SERR);
 	if (csr_error_bits) {
 		/* Clear the errors.  */
-		schizo_write(csr_reg, csr);
+		upa_writeq(csr, csr_reg);
 
 		/* Log 'em.  */
 		if (csr_error_bits & SCHIZO_PCICTRL_BUS_UNUS)
@@ -650,7 +633,6 @@
 static irqreturn_t schizo_pcierr_intr(int irq, void *dev_id)
 {
 	struct pci_pbm_info *pbm = dev_id;
-	struct pci_controller_info *p = pbm->parent;
 	unsigned long afsr_reg, afar_reg, base;
 	unsigned long afsr, afar, error_bits;
 	int reported;
@@ -661,8 +643,8 @@
 	afar_reg = base + SCHIZO_PCI_AFAR;
 
 	/* Latch error status. */
-	afar = schizo_read(afar_reg);
-	afsr = schizo_read(afsr_reg);
+	afar = upa_readq(afar_reg);
+	afsr = upa_readq(afsr_reg);
 
 	/* Clear primary/secondary error status bits. */
 	error_bits = afsr &
@@ -674,7 +656,7 @@
 		 SCHIZO_PCIAFSR_STTO | SCHIZO_PCIAFSR_SUNUS);
 	if (!error_bits)
 		return schizo_pcierr_intr_other(pbm);
-	schizo_write(afsr_reg, error_bits);
+	upa_writeq(error_bits, afsr_reg);
 
 	/* Log the error. */
 	printk("%s: PCI Error, primary error type[%s]\n",
@@ -744,7 +726,7 @@
 	 * a bug in the IOMMU support code or a PCI device driver.
 	 */
 	if (error_bits & (SCHIZO_PCIAFSR_PTA | SCHIZO_PCIAFSR_STA)) {
-		schizo_check_iommu_error(p, PCI_ERR);
+		schizo_check_iommu_error(pbm, PCI_ERR);
 		pci_scan_for_target_abort(pbm, pbm->pci_bus);
 	}
 	if (error_bits & (SCHIZO_PCIAFSR_PMA | SCHIZO_PCIAFSR_SMA))
@@ -805,12 +787,11 @@
 static irqreturn_t schizo_safarierr_intr(int irq, void *dev_id)
 {
 	struct pci_pbm_info *pbm = dev_id;
-	struct pci_controller_info *p = pbm->parent;
 	u64 errlog;
 
-	errlog = schizo_read(pbm->controller_regs + SCHIZO_SAFARI_ERRLOG);
-	schizo_write(pbm->controller_regs + SCHIZO_SAFARI_ERRLOG,
-		     errlog & ~(SAFARI_ERRLOG_ERROUT));
+	errlog = upa_readq(pbm->controller_regs + SCHIZO_SAFARI_ERRLOG);
+	upa_writeq(errlog & ~(SAFARI_ERRLOG_ERROUT),
+		   pbm->controller_regs + SCHIZO_SAFARI_ERRLOG);
 
 	if (!(errlog & BUS_ERROR_UNMAP)) {
 		printk("%s: Unexpected Safari/JBUS error interrupt, errlog[%016lx]\n",
@@ -821,7 +802,7 @@
 
 	printk("%s: Safari/JBUS interrupt, UNMAPPED error, interrogating IOMMUs.\n",
 	       pbm->name);
-	schizo_check_iommu_error(p, SAFARI_ERR);
+	schizo_check_iommu_error(pbm, SAFARI_ERR);
 
 	return IRQ_HANDLED;
 }
@@ -863,7 +844,7 @@
  */
 static void tomatillo_register_error_handlers(struct pci_pbm_info *pbm)
 {
-	struct of_device *op = of_find_device_by_node(pbm->prom_node);
+	struct of_device *op = of_find_device_by_node(pbm->op->node);
 	u64 tmp, err_mask, err_no_mask;
 	int err;
 
@@ -910,10 +891,9 @@
 	}
 
 	/* Enable UE and CE interrupts for controller. */
-	schizo_write(pbm->controller_regs + SCHIZO_ECC_CTRL,
-		     (SCHIZO_ECCCTRL_EE |
-		      SCHIZO_ECCCTRL_UE |
-		      SCHIZO_ECCCTRL_CE));
+	upa_writeq((SCHIZO_ECCCTRL_EE |
+		    SCHIZO_ECCCTRL_UE |
+		    SCHIZO_ECCCTRL_CE), pbm->controller_regs + SCHIZO_ECC_CTRL);
 
 	/* Enable PCI Error interrupts and clear error
 	 * bits.
@@ -926,10 +906,10 @@
 
 	err_no_mask = SCHIZO_PCICTRL_DTO_ERR;
 
-	tmp = schizo_read(pbm->pbm_regs + SCHIZO_PCI_CTRL);
+	tmp = upa_readq(pbm->pbm_regs + SCHIZO_PCI_CTRL);
 	tmp |= err_mask;
 	tmp &= ~err_no_mask;
-	schizo_write(pbm->pbm_regs + SCHIZO_PCI_CTRL, tmp);
+	upa_writeq(tmp, pbm->pbm_regs + SCHIZO_PCI_CTRL);
 
 	err_mask = (SCHIZO_PCIAFSR_PMA | SCHIZO_PCIAFSR_PTA |
 		    SCHIZO_PCIAFSR_PRTRY | SCHIZO_PCIAFSR_PPERR |
@@ -938,7 +918,7 @@
 		    SCHIZO_PCIAFSR_SRTRY | SCHIZO_PCIAFSR_SPERR |
 		    SCHIZO_PCIAFSR_STTO);
 
-	schizo_write(pbm->pbm_regs + SCHIZO_PCI_AFSR, err_mask);
+	upa_writeq(err_mask, pbm->pbm_regs + SCHIZO_PCI_AFSR);
 
 	err_mask = (BUS_ERROR_BADCMD | BUS_ERROR_SNOOP_GR |
 		    BUS_ERROR_SNOOP_PCI | BUS_ERROR_SNOOP_RD |
@@ -950,16 +930,16 @@
 		    BUS_ERROR_APERR | BUS_ERROR_UNMAP |
 		    BUS_ERROR_BUSERR | BUS_ERROR_TIMEOUT);
 
-	schizo_write(pbm->controller_regs + SCHIZO_SAFARI_ERRCTRL,
-		     (SCHIZO_SAFERRCTRL_EN | err_mask));
+	upa_writeq((SCHIZO_SAFERRCTRL_EN | err_mask),
+		   pbm->controller_regs + SCHIZO_SAFARI_ERRCTRL);
 
-	schizo_write(pbm->controller_regs + SCHIZO_SAFARI_IRQCTRL,
-		     (SCHIZO_SAFIRQCTRL_EN | (BUS_ERROR_UNMAP)));
+	upa_writeq((SCHIZO_SAFIRQCTRL_EN | (BUS_ERROR_UNMAP)),
+		   pbm->controller_regs + SCHIZO_SAFARI_IRQCTRL);
 }
 
 static void schizo_register_error_handlers(struct pci_pbm_info *pbm)
 {
-	struct of_device *op = of_find_device_by_node(pbm->prom_node);
+	struct of_device *op = of_find_device_by_node(pbm->op->node);
 	u64 tmp, err_mask, err_no_mask;
 	int err;
 
@@ -1006,10 +986,9 @@
 	}
 
 	/* Enable UE and CE interrupts for controller. */
-	schizo_write(pbm->controller_regs + SCHIZO_ECC_CTRL,
-		     (SCHIZO_ECCCTRL_EE |
-		      SCHIZO_ECCCTRL_UE |
-		      SCHIZO_ECCCTRL_CE));
+	upa_writeq((SCHIZO_ECCCTRL_EE |
+		    SCHIZO_ECCCTRL_UE |
+		    SCHIZO_ECCCTRL_CE), pbm->controller_regs + SCHIZO_ECC_CTRL);
 
 	err_mask = (SCHIZO_PCICTRL_BUS_UNUS |
 		    SCHIZO_PCICTRL_ESLCK |
@@ -1025,18 +1004,18 @@
 	/* Enable PCI Error interrupts and clear error
 	 * bits for each PBM.
 	 */
-	tmp = schizo_read(pbm->pbm_regs + SCHIZO_PCI_CTRL);
+	tmp = upa_readq(pbm->pbm_regs + SCHIZO_PCI_CTRL);
 	tmp |= err_mask;
 	tmp &= ~err_no_mask;
-	schizo_write(pbm->pbm_regs + SCHIZO_PCI_CTRL, tmp);
+	upa_writeq(tmp, pbm->pbm_regs + SCHIZO_PCI_CTRL);
 
-	schizo_write(pbm->pbm_regs + SCHIZO_PCI_AFSR,
-		     (SCHIZO_PCIAFSR_PMA | SCHIZO_PCIAFSR_PTA |
-		      SCHIZO_PCIAFSR_PRTRY | SCHIZO_PCIAFSR_PPERR |
-		      SCHIZO_PCIAFSR_PTTO | SCHIZO_PCIAFSR_PUNUS |
-		      SCHIZO_PCIAFSR_SMA | SCHIZO_PCIAFSR_STA |
-		      SCHIZO_PCIAFSR_SRTRY | SCHIZO_PCIAFSR_SPERR |
-		      SCHIZO_PCIAFSR_STTO | SCHIZO_PCIAFSR_SUNUS));
+	upa_writeq((SCHIZO_PCIAFSR_PMA | SCHIZO_PCIAFSR_PTA |
+		    SCHIZO_PCIAFSR_PRTRY | SCHIZO_PCIAFSR_PPERR |
+		    SCHIZO_PCIAFSR_PTTO | SCHIZO_PCIAFSR_PUNUS |
+		    SCHIZO_PCIAFSR_SMA | SCHIZO_PCIAFSR_STA |
+		    SCHIZO_PCIAFSR_SRTRY | SCHIZO_PCIAFSR_SPERR |
+		    SCHIZO_PCIAFSR_STTO | SCHIZO_PCIAFSR_SUNUS),
+		   pbm->pbm_regs + SCHIZO_PCI_AFSR);
 
 	/* Make all Safari error conditions fatal except unmapped
 	 * errors which we make generate interrupts.
@@ -1063,8 +1042,8 @@
 		      BUS_ERROR_CPU0PS | BUS_ERROR_CPU0PB);
 #endif
 
-	schizo_write(pbm->controller_regs + SCHIZO_SAFARI_ERRCTRL,
-		     (SCHIZO_SAFERRCTRL_EN | err_mask));
+	upa_writeq((SCHIZO_SAFERRCTRL_EN | err_mask),
+		   pbm->controller_regs + SCHIZO_SAFARI_ERRCTRL);
 }
 
 static void pbm_config_busmastering(struct pci_pbm_info *pbm)
@@ -1084,14 +1063,15 @@
 	pci_config_write8(addr, 64);
 }
 
-static void __init schizo_scan_bus(struct pci_pbm_info *pbm)
+static void __devinit schizo_scan_bus(struct pci_pbm_info *pbm,
+				      struct device *parent)
 {
 	pbm_config_busmastering(pbm);
 	pbm->is_66mhz_capable =
-		(of_find_property(pbm->prom_node, "66mhz-capable", NULL)
+		(of_find_property(pbm->op->node, "66mhz-capable", NULL)
 		 != NULL);
 
-	pbm->pci_bus = pci_scan_one_pbm(pbm);
+	pbm->pci_bus = pci_scan_one_pbm(pbm, parent);
 
 	if (pbm->chip_type == PBM_CHIP_TYPE_TOMATILLO)
 		tomatillo_register_error_handlers(pbm);
@@ -1133,12 +1113,12 @@
 	 * streaming buffer and leave the rerun-disable
 	 * setting however OBP set it.
 	 */
-	control = schizo_read(pbm->stc.strbuf_control);
+	control = upa_readq(pbm->stc.strbuf_control);
 	control &= ~(SCHIZO_STRBUF_CTRL_LPTR |
 		     SCHIZO_STRBUF_CTRL_LENAB |
 		     SCHIZO_STRBUF_CTRL_DENAB);
 	control |= SCHIZO_STRBUF_CTRL_ENAB;
-	schizo_write(pbm->stc.strbuf_control, control);
+	upa_writeq(control, pbm->stc.strbuf_control);
 
 	pbm->stc.strbuf_enabled = 1;
 }
@@ -1150,24 +1130,17 @@
 
 static int schizo_pbm_iommu_init(struct pci_pbm_info *pbm)
 {
-	struct iommu *iommu = pbm->iommu;
+	static const u32 vdma_default[] = { 0xc0000000, 0x40000000 };
 	unsigned long i, tagbase, database;
-	struct property *prop;
-	u32 vdma[2], dma_mask;
+	struct iommu *iommu = pbm->iommu;
 	int tsbsize, err;
+	const u32 *vdma;
+	u32 dma_mask;
 	u64 control;
 
-	prop = of_find_property(pbm->prom_node, "virtual-dma", NULL);
-	if (prop) {
-		u32 *val = prop->value;
-
-		vdma[0] = val[0];
-		vdma[1] = val[1];
-	} else {
-		/* No property, use default values. */
-		vdma[0] = 0xc0000000;
-		vdma[1] = 0x40000000;
-	}
+	vdma = of_get_property(pbm->op->node, "virtual-dma", NULL);
+	if (!vdma)
+		vdma = vdma_default;
 
 	dma_mask = vdma[0];
 	switch (vdma[1]) {
@@ -1187,9 +1160,9 @@
 			break;
 
 		default:
-			prom_printf("SCHIZO: strange virtual-dma size.\n");
-			prom_halt();
-	};
+			printk(KERN_ERR PFX "Strange virtual-dma size.\n");
+			return -EINVAL;
+	}
 
 	/* Register addresses, SCHIZO has iommu ctx flushing. */
 	iommu->iommu_control  = pbm->pbm_regs + SCHIZO_IOMMU_CONTROL;
@@ -1206,15 +1179,15 @@
 	/*
 	 * Invalidate TLB Entries.
 	 */
-	control = schizo_read(iommu->iommu_control);
+	control = upa_readq(iommu->iommu_control);
 	control |= SCHIZO_IOMMU_CTRL_DENAB;
-	schizo_write(iommu->iommu_control, control);
+	upa_writeq(control, iommu->iommu_control);
 
 	tagbase = SCHIZO_IOMMU_TAG, database = SCHIZO_IOMMU_DATA;
 
-	for(i = 0; i < 16; i++) {
-		schizo_write(pbm->pbm_regs + tagbase + (i * 8UL), 0);
-		schizo_write(pbm->pbm_regs + database + (i * 8UL), 0);
+	for (i = 0; i < 16; i++) {
+		upa_writeq(0, pbm->pbm_regs + tagbase + (i * 8UL));
+		upa_writeq(0, pbm->pbm_regs + database + (i * 8UL));
 	}
 
 	/* Leave diag mode enabled for full-flushing done
@@ -1222,12 +1195,14 @@
 	 */
 	err = iommu_table_init(iommu, tsbsize * 8 * 1024, vdma[0], dma_mask,
 			       pbm->numa_node);
-	if (err)
+	if (err) {
+		printk(KERN_ERR PFX "iommu_table_init() fails with %d\n", err);
 		return err;
+	}
 
-	schizo_write(iommu->iommu_tsbbase, __pa(iommu->page_table));
+	upa_writeq(__pa(iommu->page_table), iommu->iommu_tsbbase);
 
-	control = schizo_read(iommu->iommu_control);
+	control = upa_readq(iommu->iommu_control);
 	control &= ~(SCHIZO_IOMMU_CTRL_TSBSZ | SCHIZO_IOMMU_CTRL_TBWSZ);
 	switch (tsbsize) {
 	case 64:
@@ -1236,10 +1211,10 @@
 	case 128:
 		control |= SCHIZO_IOMMU_TSBSZ_128K;
 		break;
-	};
+	}
 
 	control |= SCHIZO_IOMMU_CTRL_ENAB;
-	schizo_write(iommu->iommu_control, control);
+	upa_writeq(control, iommu->iommu_control);
 
 	return 0;
 }
@@ -1280,12 +1255,11 @@
 
 static void schizo_pbm_hw_init(struct pci_pbm_info *pbm)
 {
-	struct property *prop;
 	u64 tmp;
 
-	schizo_write(pbm->pbm_regs + SCHIZO_PCI_IRQ_RETRY, 5);
+	upa_writeq(5, pbm->pbm_regs + SCHIZO_PCI_IRQ_RETRY);
 
-	tmp = schizo_read(pbm->pbm_regs + SCHIZO_PCI_CTRL);
+	tmp = upa_readq(pbm->pbm_regs + SCHIZO_PCI_CTRL);
 
 	/* Enable arbiter for all PCI slots.  */
 	tmp |= 0xff;
@@ -1294,8 +1268,7 @@
 	    pbm->chip_version >= 0x2)
 		tmp |= 0x3UL << SCHIZO_PCICTRL_PTO_SHIFT;
 
-	prop = of_find_property(pbm->prom_node, "no-bus-parking", NULL);
-	if (!prop)
+	if (!of_find_property(pbm->op->node, "no-bus-parking", NULL))
 		tmp |= SCHIZO_PCICTRL_PARK;
 	else
 		tmp &= ~SCHIZO_PCICTRL_PARK;
@@ -1311,13 +1284,13 @@
 			SCHIZO_PCICTRL_RDO_PREF |
 			SCHIZO_PCICTRL_RDL_PREF);
 
-	schizo_write(pbm->pbm_regs + SCHIZO_PCI_CTRL, tmp);
+	upa_writeq(tmp, pbm->pbm_regs + SCHIZO_PCI_CTRL);
 
-	tmp = schizo_read(pbm->pbm_regs + SCHIZO_PCI_DIAG);
+	tmp = upa_readq(pbm->pbm_regs + SCHIZO_PCI_DIAG);
 	tmp &= ~(SCHIZO_PCIDIAG_D_RTRYARB |
 		 SCHIZO_PCIDIAG_D_RETRY |
 		 SCHIZO_PCIDIAG_D_INTSYNC);
-	schizo_write(pbm->pbm_regs + SCHIZO_PCI_DIAG, tmp);
+	upa_writeq(tmp, pbm->pbm_regs + SCHIZO_PCI_DIAG);
 
 	if (pbm->chip_type == PBM_CHIP_TYPE_TOMATILLO) {
 		/* Clear prefetch lengths to workaround a bug in
@@ -1329,17 +1302,16 @@
 		       TOMATILLO_IOC_RDONE_CPENAB |
 		       TOMATILLO_IOC_RDLINE_CPENAB);
 
-		schizo_write(pbm->pbm_regs + TOMATILLO_PCI_IOC_CSR,
-			     tmp);
+		upa_writeq(tmp, pbm->pbm_regs + TOMATILLO_PCI_IOC_CSR);
 	}
 }
 
-static int __init schizo_pbm_init(struct pci_controller_info *p,
-				  struct device_node *dp, u32 portid,
-				  int chip_type)
+static int __devinit schizo_pbm_init(struct pci_pbm_info *pbm,
+				     struct of_device *op, u32 portid,
+				     int chip_type)
 {
 	const struct linux_prom64_registers *regs;
-	struct pci_pbm_info *pbm;
+	struct device_node *dp = op->node;
 	const char *chipset_name;
 	int is_pbm_a, err;
 
@@ -1372,25 +1344,19 @@
 	regs = of_get_property(dp, "reg", NULL);
 
 	is_pbm_a = ((regs[0].phys_addr & 0x00700000) == 0x00600000);
-	if (is_pbm_a)
-		pbm = &p->pbm_A;
-	else
-		pbm = &p->pbm_B;
 
 	pbm->next = pci_pbm_root;
 	pci_pbm_root = pbm;
 
 	pbm->numa_node = -1;
 
-	pbm->scan_bus = schizo_scan_bus;
 	pbm->pci_ops = &sun4u_pci_ops;
 	pbm->config_space_reg_bits = 8;
 
 	pbm->index = pci_num_pbms++;
 
 	pbm->portid = portid;
-	pbm->parent = p;
-	pbm->prom_node = dp;
+	pbm->op = op;
 
 	pbm->chip_type = chip_type;
 	pbm->chip_version = of_getintprop_default(dp, "version#", 0);
@@ -1420,6 +1386,8 @@
 
 	schizo_pbm_strbuf_init(pbm);
 
+	schizo_scan_bus(pbm, &op->dev);
+
 	return 0;
 }
 
@@ -1433,62 +1401,104 @@
 	return (x == y);
 }
 
-static void __init __schizo_init(struct device_node *dp, char *model_name,
-				 int chip_type)
+static struct pci_pbm_info * __devinit schizo_find_sibling(u32 portid,
+							   int chip_type)
 {
-	struct pci_controller_info *p;
+	struct pci_pbm_info *pbm;
+
+	for (pbm = pci_pbm_root; pbm; pbm = pbm->next) {
+		if (portid_compare(pbm->portid, portid, chip_type))
+			return pbm;
+	}
+	return NULL;
+}
+
+static int __devinit __schizo_init(struct of_device *op, unsigned long chip_type)
+{
+	struct device_node *dp = op->node;
 	struct pci_pbm_info *pbm;
 	struct iommu *iommu;
 	u32 portid;
+	int err;
 
 	portid = of_getintprop_default(dp, "portid", 0xff);
 
-	for (pbm = pci_pbm_root; pbm; pbm = pbm->next) {
-		if (portid_compare(pbm->portid, portid, chip_type)) {
-			if (schizo_pbm_init(pbm->parent, dp,
-					    portid, chip_type))
-				goto fatal_memory_error;
-			return;
-		}
+	err = -ENOMEM;
+	pbm = kzalloc(sizeof(*pbm), GFP_KERNEL);
+	if (!pbm) {
+		printk(KERN_ERR PFX "Cannot allocate pci_pbm_info.\n");
+		goto out_err;
 	}
 
-	p = kzalloc(sizeof(struct pci_controller_info), GFP_ATOMIC);
-	if (!p)
-		goto fatal_memory_error;
+	pbm->sibling = schizo_find_sibling(portid, chip_type);
 
-	iommu = kzalloc(sizeof(struct iommu), GFP_ATOMIC);
-	if (!iommu)
-		goto fatal_memory_error;
+	iommu = kzalloc(sizeof(struct iommu), GFP_KERNEL);
+	if (!iommu) {
+		printk(KERN_ERR PFX "Cannot allocate PBM A iommu.\n");
+		goto out_free_pbm;
+	}
 
-	p->pbm_A.iommu = iommu;
+	pbm->iommu = iommu;
 
-	iommu = kzalloc(sizeof(struct iommu), GFP_ATOMIC);
-	if (!iommu)
-		goto fatal_memory_error;
+	if (schizo_pbm_init(pbm, op, portid, chip_type))
+		goto out_free_iommu;
 
-	p->pbm_B.iommu = iommu;
+	if (pbm->sibling)
+		pbm->sibling->sibling = pbm;
 
-	if (schizo_pbm_init(p, dp, portid, chip_type))
-		goto fatal_memory_error;
+	dev_set_drvdata(&op->dev, pbm);
 
-	return;
+	return 0;
 
-fatal_memory_error:
-	prom_printf("SCHIZO: Fatal memory allocation error.\n");
-	prom_halt();
+out_free_iommu:
+	kfree(pbm->iommu);
+
+out_free_pbm:
+	kfree(pbm);
+
+out_err:
+	return err;
 }
 
-void __init schizo_init(struct device_node *dp, char *model_name)
+static int __devinit schizo_probe(struct of_device *op,
+				  const struct of_device_id *match)
 {
-	__schizo_init(dp, model_name, PBM_CHIP_TYPE_SCHIZO);
+	return __schizo_init(op, (unsigned long) match->data);
 }
 
-void __init schizo_plus_init(struct device_node *dp, char *model_name)
+/* The ordering of this table is very important.  Some Tomatillo
+ * nodes announce that they are compatible with both pci108e,a801
+ * and pci108e,8001.  So list the chips in reverse chronological
+ * order.
+ */
+static struct of_device_id __initdata schizo_match[] = {
+	{
+		.name = "pci",
+		.compatible = "pci108e,a801",
+		.data = (void *) PBM_CHIP_TYPE_TOMATILLO,
+	},
+	{
+		.name = "pci",
+		.compatible = "pci108e,8002",
+		.data = (void *) PBM_CHIP_TYPE_SCHIZO_PLUS,
+	},
+	{
+		.name = "pci",
+		.compatible = "pci108e,8001",
+		.data = (void *) PBM_CHIP_TYPE_SCHIZO,
+	},
+	{},
+};
+
+static struct of_platform_driver schizo_driver = {
+	.name		= DRIVER_NAME,
+	.match_table	= schizo_match,
+	.probe		= schizo_probe,
+};
+
+static int __init schizo_init(void)
 {
-	__schizo_init(dp, model_name, PBM_CHIP_TYPE_SCHIZO_PLUS);
+	return of_register_driver(&schizo_driver, &of_bus_type);
 }
 
-void __init tomatillo_init(struct device_node *dp, char *model_name)
-{
-	__schizo_init(dp, model_name, PBM_CHIP_TYPE_TOMATILLO);
-}
+subsys_initcall(schizo_init);
diff --git a/arch/sparc64/kernel/pci_sun4v.c b/arch/sparc64/kernel/pci_sun4v.c
index a104c80..e86c73e 100644
--- a/arch/sparc64/kernel/pci_sun4v.c
+++ b/arch/sparc64/kernel/pci_sun4v.c
@@ -13,12 +13,10 @@
 #include <linux/irq.h>
 #include <linux/msi.h>
 #include <linux/log2.h>
+#include <linux/of_device.h>
 
 #include <asm/iommu.h>
 #include <asm/irq.h>
-#include <asm/upa.h>
-#include <asm/pstate.h>
-#include <asm/oplib.h>
 #include <asm/hypervisor.h>
 #include <asm/prom.h>
 
@@ -27,6 +25,9 @@
 
 #include "pci_sun4v.h"
 
+#define DRIVER_NAME	"pci_sun4v"
+#define PFX		DRIVER_NAME ": "
+
 static unsigned long vpci_major = 1;
 static unsigned long vpci_minor = 1;
 
@@ -41,6 +42,7 @@
 };
 
 static DEFINE_PER_CPU(struct iommu_batch, iommu_batch);
+static int iommu_batch_initialized;
 
 /* Interrupts must be disabled.  */
 static inline void iommu_batch_start(struct device *dev, unsigned long prot, unsigned long entry)
@@ -542,15 +544,16 @@
 	.sync_sg_for_cpu		= dma_4v_sync_sg_for_cpu,
 };
 
-static void __init pci_sun4v_scan_bus(struct pci_pbm_info *pbm)
+static void __init pci_sun4v_scan_bus(struct pci_pbm_info *pbm,
+				      struct device *parent)
 {
 	struct property *prop;
 	struct device_node *dp;
 
-	dp = pbm->prom_node;
+	dp = pbm->op->node;
 	prop = of_find_property(dp, "66mhz-capable", NULL);
 	pbm->is_66mhz_capable = (prop != NULL);
-	pbm->pci_bus = pci_scan_one_pbm(pbm);
+	pbm->pci_bus = pci_scan_one_pbm(pbm, parent);
 
 	/* XXX register error interrupt handlers XXX */
 }
@@ -583,29 +586,22 @@
 	return cnt;
 }
 
-static void __init pci_sun4v_iommu_init(struct pci_pbm_info *pbm)
+static int __init pci_sun4v_iommu_init(struct pci_pbm_info *pbm)
 {
+	static const u32 vdma_default[] = { 0x80000000, 0x80000000 };
 	struct iommu *iommu = pbm->iommu;
-	struct property *prop;
 	unsigned long num_tsb_entries, sz, tsbsize;
-	u32 vdma[2], dma_mask, dma_offset;
+	u32 dma_mask, dma_offset;
+	const u32 *vdma;
 
-	prop = of_find_property(pbm->prom_node, "virtual-dma", NULL);
-	if (prop) {
-		u32 *val = prop->value;
-
-		vdma[0] = val[0];
-		vdma[1] = val[1];
-	} else {
-		/* No property, use default values. */
-		vdma[0] = 0x80000000;
-		vdma[1] = 0x80000000;
-	}
+	vdma = of_get_property(pbm->op->node, "virtual-dma", NULL);
+	if (!vdma)
+		vdma = vdma_default;
 
 	if ((vdma[0] | vdma[1]) & ~IO_PAGE_MASK) {
-		prom_printf("PCI-SUN4V: strange virtual-dma[%08x:%08x].\n",
-			    vdma[0], vdma[1]);
-		prom_halt();
+		printk(KERN_ERR PFX "Strange virtual-dma[%08x:%08x].\n",
+		       vdma[0], vdma[1]);
+		return -EINVAL;
 	};
 
 	dma_mask = (roundup_pow_of_two(vdma[1]) - 1UL);
@@ -625,8 +621,8 @@
 	sz = (sz + 7UL) & ~7UL;
 	iommu->arena.map = kzalloc(sz, GFP_KERNEL);
 	if (!iommu->arena.map) {
-		prom_printf("PCI_IOMMU: Error, kmalloc(arena.map) failed.\n");
-		prom_halt();
+		printk(KERN_ERR PFX "Error, kmalloc(arena.map) failed.\n");
+		return -ENOMEM;
 	}
 	iommu->arena.limit = num_tsb_entries;
 
@@ -634,6 +630,8 @@
 	if (sz)
 		printk("%s: Imported %lu TSB entries from OBP\n",
 		       pbm->name, sz);
+
+	return 0;
 }
 
 #ifdef CONFIG_PCI_MSI
@@ -890,29 +888,20 @@
 }
 #endif /* !(CONFIG_PCI_MSI) */
 
-static void __init pci_sun4v_pbm_init(struct pci_controller_info *p,
-				      struct device_node *dp, u32 devhandle)
+static int __init pci_sun4v_pbm_init(struct pci_pbm_info *pbm,
+				     struct of_device *op, u32 devhandle)
 {
-	struct pci_pbm_info *pbm;
-
-	if (devhandle & 0x40)
-		pbm = &p->pbm_B;
-	else
-		pbm = &p->pbm_A;
-
-	pbm->next = pci_pbm_root;
-	pci_pbm_root = pbm;
+	struct device_node *dp = op->node;
+	int err;
 
 	pbm->numa_node = of_node_to_nid(dp);
 
-	pbm->scan_bus = pci_sun4v_scan_bus;
 	pbm->pci_ops = &sun4v_pci_ops;
 	pbm->config_space_reg_bits = 12;
 
 	pbm->index = pci_num_pbms++;
 
-	pbm->parent = p;
-	pbm->prom_node = dp;
+	pbm->op = op;
 
 	pbm->devhandle = devhandle;
 
@@ -924,82 +913,120 @@
 	pci_determine_mem_io_space(pbm);
 
 	pci_get_pbm_props(pbm);
-	pci_sun4v_iommu_init(pbm);
+
+	err = pci_sun4v_iommu_init(pbm);
+	if (err)
+		return err;
+
 	pci_sun4v_msi_init(pbm);
+
+	pci_sun4v_scan_bus(pbm, &op->dev);
+
+	pbm->next = pci_pbm_root;
+	pci_pbm_root = pbm;
+
+	return 0;
 }
 
-void __init sun4v_pci_init(struct device_node *dp, char *model_name)
+static int __devinit pci_sun4v_probe(struct of_device *op,
+				     const struct of_device_id *match)
 {
+	const struct linux_prom64_registers *regs;
 	static int hvapi_negotiated = 0;
-	struct pci_controller_info *p;
 	struct pci_pbm_info *pbm;
+	struct device_node *dp;
 	struct iommu *iommu;
-	struct property *prop;
-	struct linux_prom64_registers *regs;
 	u32 devhandle;
-	int i;
+	int i, err;
+
+	dp = op->node;
 
 	if (!hvapi_negotiated++) {
-		int err = sun4v_hvapi_register(HV_GRP_PCI,
-					       vpci_major,
-					       &vpci_minor);
+		err = sun4v_hvapi_register(HV_GRP_PCI,
+					   vpci_major,
+					   &vpci_minor);
 
 		if (err) {
-			prom_printf("SUN4V_PCI: Could not register hvapi, "
-				    "err=%d\n", err);
-			prom_halt();
+			printk(KERN_ERR PFX "Could not register hvapi, "
+			       "err=%d\n", err);
+			return err;
 		}
-		printk("SUN4V_PCI: Registered hvapi major[%lu] minor[%lu]\n",
+		printk(KERN_INFO PFX "Registered hvapi major[%lu] minor[%lu]\n",
 		       vpci_major, vpci_minor);
 
 		dma_ops = &sun4v_dma_ops;
 	}
 
-	prop = of_find_property(dp, "reg", NULL);
-	if (!prop) {
-		prom_printf("SUN4V_PCI: Could not find config registers\n");
-		prom_halt();
+	regs = of_get_property(dp, "reg", NULL);
+	err = -ENODEV;
+	if (!regs) {
+		printk(KERN_ERR PFX "Could not find config registers\n");
+		goto out_err;
 	}
-	regs = prop->value;
-
 	devhandle = (regs->phys_addr >> 32UL) & 0x0fffffff;
 
-	for (pbm = pci_pbm_root; pbm; pbm = pbm->next) {
-		if (pbm->devhandle == (devhandle ^ 0x40)) {
-			pci_sun4v_pbm_init(pbm->parent, dp, devhandle);
-			return;
+	err = -ENOMEM;
+	if (!iommu_batch_initialized) {
+		for_each_possible_cpu(i) {
+			unsigned long page = get_zeroed_page(GFP_KERNEL);
+
+			if (!page)
+				goto out_err;
+
+			per_cpu(iommu_batch, i).pglist = (u64 *) page;
 		}
+		iommu_batch_initialized = 1;
 	}
 
-	for_each_possible_cpu(i) {
-		unsigned long page = get_zeroed_page(GFP_ATOMIC);
-
-		if (!page)
-			goto fatal_memory_error;
-
-		per_cpu(iommu_batch, i).pglist = (u64 *) page;
+	pbm = kzalloc(sizeof(*pbm), GFP_KERNEL);
+	if (!pbm) {
+		printk(KERN_ERR PFX "Could not allocate pci_pbm_info\n");
+		goto out_err;
 	}
 
-	p = kzalloc(sizeof(struct pci_controller_info), GFP_ATOMIC);
-	if (!p)
-		goto fatal_memory_error;
+	iommu = kzalloc(sizeof(struct iommu), GFP_KERNEL);
+	if (!iommu) {
+		printk(KERN_ERR PFX "Could not allocate pbm iommu\n");
+		goto out_free_controller;
+	}
 
-	iommu = kzalloc(sizeof(struct iommu), GFP_ATOMIC);
-	if (!iommu)
-		goto fatal_memory_error;
+	pbm->iommu = iommu;
 
-	p->pbm_A.iommu = iommu;
+	err = pci_sun4v_pbm_init(pbm, op, devhandle);
+	if (err)
+		goto out_free_iommu;
 
-	iommu = kzalloc(sizeof(struct iommu), GFP_ATOMIC);
-	if (!iommu)
-		goto fatal_memory_error;
+	dev_set_drvdata(&op->dev, pbm);
 
-	p->pbm_B.iommu = iommu;
+	return 0;
 
-	pci_sun4v_pbm_init(p, dp, devhandle);
-	return;
+out_free_iommu:
+	kfree(pbm->iommu);
 
-fatal_memory_error:
-	prom_printf("SUN4V_PCI: Fatal memory allocation error.\n");
-	prom_halt();
+out_free_controller:
+	kfree(pbm);
+
+out_err:
+	return err;
 }
+
+static struct of_device_id __initdata pci_sun4v_match[] = {
+	{
+		.name = "pci",
+		.compatible = "SUNW,sun4v-pci",
+	},
+	{},
+};
+
+static struct of_platform_driver pci_sun4v_driver = {
+	.name		= DRIVER_NAME,
+	.match_table	= pci_sun4v_match,
+	.probe		= pci_sun4v_probe,
+};
+
+static int __init pci_sun4v_init(void)
+{
+	return of_register_driver(&pci_sun4v_driver, &of_bus_type);
+}
+
+subsys_initcall(pci_sun4v_init);
diff --git a/arch/sparc64/kernel/pci_sun4v_asm.S b/arch/sparc64/kernel/pci_sun4v_asm.S
index ecb81f3..e606d46 100644
--- a/arch/sparc64/kernel/pci_sun4v_asm.S
+++ b/arch/sparc64/kernel/pci_sun4v_asm.S
@@ -1,8 +1,9 @@
 /* pci_sun4v_asm: Hypervisor calls for PCI support.
  *
- * Copyright (C) 2006 David S. Miller <davem@davemloft.net>
+ * Copyright (C) 2006, 2008 David S. Miller <davem@davemloft.net>
  */
 
+#include <linux/linkage.h>
 #include <asm/hypervisor.h>
 
 	/* %o0: devhandle
@@ -14,8 +15,7 @@
 	 * returns %o0:	-status if status was non-zero, else
 	 *         %o0:	num pages mapped
 	 */
-	.globl	pci_sun4v_iommu_map
-pci_sun4v_iommu_map:
+ENTRY(pci_sun4v_iommu_map)
 	mov	%o5, %g1
 	mov	HV_FAST_PCI_IOMMU_MAP, %o5
 	ta	HV_FAST_TRAP
@@ -24,6 +24,7 @@
 	mov	%o1, %o0
 1:	retl
 	 nop
+ENDPROC(pci_sun4v_iommu_map)
 
 	/* %o0: devhandle
 	 * %o1:	tsbid
@@ -31,12 +32,12 @@
 	 *
 	 * returns %o0:	num ttes demapped
 	 */
-	.globl	pci_sun4v_iommu_demap
-pci_sun4v_iommu_demap:
+ENTRY(pci_sun4v_iommu_demap)
 	mov	HV_FAST_PCI_IOMMU_DEMAP, %o5
 	ta	HV_FAST_TRAP
 	retl
 	 mov	%o1, %o0
+ENDPROC(pci_sun4v_iommu_demap)
 
 	/* %o0: devhandle
 	 * %o1:	tsbid
@@ -45,8 +46,7 @@
 	 *
 	 * returns %o0:	status
 	 */
-	.globl	pci_sun4v_iommu_getmap
-pci_sun4v_iommu_getmap:
+ENTRY(pci_sun4v_iommu_getmap)
 	mov	%o2, %o4
 	mov	HV_FAST_PCI_IOMMU_GETMAP, %o5
 	ta	HV_FAST_TRAP
@@ -54,6 +54,7 @@
 	stx	%o2, [%o3]
 	retl
 	 mov	%o0, %o0
+ENDPROC(pci_sun4v_iommu_getmap)
 
 	/* %o0: devhandle
 	 * %o1:	pci_device
@@ -65,14 +66,14 @@
 	 * If there is an error, the data will be returned
 	 * as all 1's.
 	 */
-	.globl	pci_sun4v_config_get
-pci_sun4v_config_get:
+ENTRY(pci_sun4v_config_get)
 	mov	HV_FAST_PCI_CONFIG_GET, %o5
 	ta	HV_FAST_TRAP
 	brnz,a,pn %o1, 1f
 	 mov	-1, %o2
 1:	retl
 	 mov	%o2, %o0
+ENDPROC(pci_sun4v_config_get)
 
 	/* %o0: devhandle
 	 * %o1:	pci_device
@@ -85,14 +86,14 @@
 	 * status will be zero if the operation completed
 	 * successfully, else -1 if not
 	 */
-	.globl	pci_sun4v_config_put
-pci_sun4v_config_put:
+ENTRY(pci_sun4v_config_put)
 	mov	HV_FAST_PCI_CONFIG_PUT, %o5
 	ta	HV_FAST_TRAP
 	brnz,a,pn %o1, 1f
 	 mov	-1, %o1
 1:	retl
 	 mov	%o1, %o0
+ENDPROC(pci_sun4v_config_put)
 
 	/* %o0: devhandle
 	 * %o1: msiqid
@@ -104,12 +105,12 @@
 	 * status will be zero if the operation completed
 	 * successfully, else -1 if not
 	 */
-	.globl	pci_sun4v_msiq_conf
-pci_sun4v_msiq_conf:
+ENTRY(pci_sun4v_msiq_conf)
 	mov	HV_FAST_PCI_MSIQ_CONF, %o5
 	ta	HV_FAST_TRAP
 	retl
 	 mov	%o0, %o0
+ENDPROC(pci_sun4v_msiq_conf)
 
 	/* %o0: devhandle
 	 * %o1: msiqid
@@ -118,8 +119,7 @@
 	 *
 	 * returns %o0: status
 	 */
-	.globl	pci_sun4v_msiq_info
-pci_sun4v_msiq_info:
+ENTRY(pci_sun4v_msiq_info)
 	mov	%o2, %o4
 	mov	HV_FAST_PCI_MSIQ_INFO, %o5
 	ta	HV_FAST_TRAP
@@ -127,6 +127,7 @@
 	stx	%o2, [%o3]
 	retl
 	 mov	%o0, %o0
+ENDPROC(pci_sun4v_msiq_info)
 
 	/* %o0: devhandle
 	 * %o1: msiqid
@@ -134,13 +135,13 @@
 	 *
 	 * returns %o0: status
 	 */
-	.globl	pci_sun4v_msiq_getvalid
-pci_sun4v_msiq_getvalid:
+ENTRY(pci_sun4v_msiq_getvalid)
 	mov	HV_FAST_PCI_MSIQ_GETVALID, %o5
 	ta	HV_FAST_TRAP
 	stx	%o1, [%o2]
 	retl
 	 mov	%o0, %o0
+ENDPROC(pci_sun4v_msiq_getvalid)
 
 	/* %o0: devhandle
 	 * %o1: msiqid
@@ -148,12 +149,12 @@
 	 *
 	 * returns %o0: status
 	 */
-	.globl	pci_sun4v_msiq_setvalid
-pci_sun4v_msiq_setvalid:
+ENTRY(pci_sun4v_msiq_setvalid)
 	mov	HV_FAST_PCI_MSIQ_SETVALID, %o5
 	ta	HV_FAST_TRAP
 	retl
 	 mov	%o0, %o0
+ENDPROC(pci_sun4v_msiq_setvalid)
 
 	/* %o0: devhandle
 	 * %o1: msiqid
@@ -161,13 +162,13 @@
 	 *
 	 * returns %o0: status
 	 */
-	.globl	pci_sun4v_msiq_getstate
-pci_sun4v_msiq_getstate:
+ENTRY(pci_sun4v_msiq_getstate)
 	mov	HV_FAST_PCI_MSIQ_GETSTATE, %o5
 	ta	HV_FAST_TRAP
 	stx	%o1, [%o2]
 	retl
 	 mov	%o0, %o0
+ENDPROC(pci_sun4v_msiq_getstate)
 
 	/* %o0: devhandle
 	 * %o1: msiqid
@@ -175,12 +176,12 @@
 	 *
 	 * returns %o0: status
 	 */
-	.globl	pci_sun4v_msiq_setstate
-pci_sun4v_msiq_setstate:
+ENTRY(pci_sun4v_msiq_setstate)
 	mov	HV_FAST_PCI_MSIQ_SETSTATE, %o5
 	ta	HV_FAST_TRAP
 	retl
 	 mov	%o0, %o0
+ENDPROC(pci_sun4v_msiq_setstate)
 
 	/* %o0: devhandle
 	 * %o1: msiqid
@@ -188,13 +189,13 @@
 	 *
 	 * returns %o0: status
 	 */
-	.globl	pci_sun4v_msiq_gethead
-pci_sun4v_msiq_gethead:
+ENTRY(pci_sun4v_msiq_gethead)
 	mov	HV_FAST_PCI_MSIQ_GETHEAD, %o5
 	ta	HV_FAST_TRAP
 	stx	%o1, [%o2]
 	retl
 	 mov	%o0, %o0
+ENDPROC(pci_sun4v_msiq_gethead)
 
 	/* %o0: devhandle
 	 * %o1: msiqid
@@ -202,12 +203,12 @@
 	 *
 	 * returns %o0: status
 	 */
-	.globl	pci_sun4v_msiq_sethead
-pci_sun4v_msiq_sethead:
+ENTRY(pci_sun4v_msiq_sethead)
 	mov	HV_FAST_PCI_MSIQ_SETHEAD, %o5
 	ta	HV_FAST_TRAP
 	retl
 	 mov	%o0, %o0
+ENDPROC(pci_sun4v_msiq_sethead)
 
 	/* %o0: devhandle
 	 * %o1: msiqid
@@ -215,13 +216,13 @@
 	 *
 	 * returns %o0: status
 	 */
-	.globl	pci_sun4v_msiq_gettail
-pci_sun4v_msiq_gettail:
+ENTRY(pci_sun4v_msiq_gettail)
 	mov	HV_FAST_PCI_MSIQ_GETTAIL, %o5
 	ta	HV_FAST_TRAP
 	stx	%o1, [%o2]
 	retl
 	 mov	%o0, %o0
+ENDPROC(pci_sun4v_msiq_gettail)
 
 	/* %o0: devhandle
 	 * %o1: msinum
@@ -229,13 +230,13 @@
 	 *
 	 * returns %o0: status
 	 */
-	.globl	pci_sun4v_msi_getvalid
-pci_sun4v_msi_getvalid:
+ENTRY(pci_sun4v_msi_getvalid)
 	mov	HV_FAST_PCI_MSI_GETVALID, %o5
 	ta	HV_FAST_TRAP
 	stx	%o1, [%o2]
 	retl
 	 mov	%o0, %o0
+ENDPROC(pci_sun4v_msi_getvalid)
 
 	/* %o0: devhandle
 	 * %o1: msinum
@@ -243,12 +244,12 @@
 	 *
 	 * returns %o0: status
 	 */
-	.globl	pci_sun4v_msi_setvalid
-pci_sun4v_msi_setvalid:
+ENTRY(pci_sun4v_msi_setvalid)
 	mov	HV_FAST_PCI_MSI_SETVALID, %o5
 	ta	HV_FAST_TRAP
 	retl
 	 mov	%o0, %o0
+ENDPROC(pci_sun4v_msi_setvalid)
 
 	/* %o0: devhandle
 	 * %o1: msinum
@@ -256,13 +257,13 @@
 	 *
 	 * returns %o0: status
 	 */
-	.globl	pci_sun4v_msi_getmsiq
-pci_sun4v_msi_getmsiq:
+ENTRY(pci_sun4v_msi_getmsiq)
 	mov	HV_FAST_PCI_MSI_GETMSIQ, %o5
 	ta	HV_FAST_TRAP
 	stx	%o1, [%o2]
 	retl
 	 mov	%o0, %o0
+ENDPROC(pci_sun4v_msi_getmsiq)
 
 	/* %o0: devhandle
 	 * %o1: msinum
@@ -271,12 +272,12 @@
 	 *
 	 * returns %o0: status
 	 */
-	.globl	pci_sun4v_msi_setmsiq
-pci_sun4v_msi_setmsiq:
+ENTRY(pci_sun4v_msi_setmsiq)
 	mov	HV_FAST_PCI_MSI_SETMSIQ, %o5
 	ta	HV_FAST_TRAP
 	retl
 	 mov	%o0, %o0
+ENDPROC(pci_sun4v_msi_setmsiq)
 
 	/* %o0: devhandle
 	 * %o1: msinum
@@ -284,13 +285,13 @@
 	 *
 	 * returns %o0: status
 	 */
-	.globl	pci_sun4v_msi_getstate
-pci_sun4v_msi_getstate:
+ENTRY(pci_sun4v_msi_getstate)
 	mov	HV_FAST_PCI_MSI_GETSTATE, %o5
 	ta	HV_FAST_TRAP
 	stx	%o1, [%o2]
 	retl
 	 mov	%o0, %o0
+ENDPROC(pci_sun4v_msi_getstate)
 
 	/* %o0: devhandle
 	 * %o1: msinum
@@ -298,12 +299,12 @@
 	 *
 	 * returns %o0: status
 	 */
-	.globl	pci_sun4v_msi_setstate
-pci_sun4v_msi_setstate:
+ENTRY(pci_sun4v_msi_setstate)
 	mov	HV_FAST_PCI_MSI_SETSTATE, %o5
 	ta	HV_FAST_TRAP
 	retl
 	 mov	%o0, %o0
+ENDPROC(pci_sun4v_msi_setstate)
 
 	/* %o0: devhandle
 	 * %o1: msinum
@@ -311,13 +312,13 @@
 	 *
 	 * returns %o0: status
 	 */
-	.globl	pci_sun4v_msg_getmsiq
-pci_sun4v_msg_getmsiq:
+ENTRY(pci_sun4v_msg_getmsiq)
 	mov	HV_FAST_PCI_MSG_GETMSIQ, %o5
 	ta	HV_FAST_TRAP
 	stx	%o1, [%o2]
 	retl
 	 mov	%o0, %o0
+ENDPROC(pci_sun4v_msg_getmsiq)
 
 	/* %o0: devhandle
 	 * %o1: msinum
@@ -325,12 +326,12 @@
 	 *
 	 * returns %o0: status
 	 */
-	.globl	pci_sun4v_msg_setmsiq
-pci_sun4v_msg_setmsiq:
+ENTRY(pci_sun4v_msg_setmsiq)
 	mov	HV_FAST_PCI_MSG_SETMSIQ, %o5
 	ta	HV_FAST_TRAP
 	retl
 	 mov	%o0, %o0
+ENDPROC(pci_sun4v_msg_setmsiq)
 
 	/* %o0: devhandle
 	 * %o1: msinum
@@ -338,13 +339,13 @@
 	 *
 	 * returns %o0: status
 	 */
-	.globl	pci_sun4v_msg_getvalid
-pci_sun4v_msg_getvalid:
+ENTRY(pci_sun4v_msg_getvalid)
 	mov	HV_FAST_PCI_MSG_GETVALID, %o5
 	ta	HV_FAST_TRAP
 	stx	%o1, [%o2]
 	retl
 	 mov	%o0, %o0
+ENDPROC(pci_sun4v_msg_getvalid)
 
 	/* %o0: devhandle
 	 * %o1: msinum
@@ -352,10 +353,10 @@
 	 *
 	 * returns %o0: status
 	 */
-	.globl	pci_sun4v_msg_setvalid
-pci_sun4v_msg_setvalid:
+ENTRY(pci_sun4v_msg_setvalid)
 	mov	HV_FAST_PCI_MSG_SETVALID, %o5
 	ta	HV_FAST_TRAP
 	retl
 	 mov	%o0, %o0
+ENDPROC(pci_sun4v_msg_setvalid)
 
diff --git a/arch/sparc64/kernel/power.c b/arch/sparc64/kernel/power.c
index 3bb987a..076cad7 100644
--- a/arch/sparc64/kernel/power.c
+++ b/arch/sparc64/kernel/power.c
@@ -1,34 +1,17 @@
 /* power.c: Power management driver.
  *
- * Copyright (C) 1999, 2007 David S. Miller (davem@davemloft.net)
+ * Copyright (C) 1999, 2007, 2008 David S. Miller (davem@davemloft.net)
  */
 
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/init.h>
-#include <linux/sched.h>
-#include <linux/signal.h>
-#include <linux/delay.h>
 #include <linux/interrupt.h>
-#include <linux/pm.h>
-#include <linux/syscalls.h>
 #include <linux/reboot.h>
 #include <linux/of_device.h>
 
-#include <asm/system.h>
-#include <asm/auxio.h>
 #include <asm/prom.h>
 #include <asm/io.h>
-#include <asm/sstate.h>
-#include <asm/reboot.h>
-
-#include <linux/unistd.h>
-
-/*
- * sysctl - toggle power-off restriction for serial console 
- * systems in machine_power_off()
- */
-int scons_pwroff = 1; 
 
 static void __iomem *power_reg;
 
@@ -40,31 +23,6 @@
 	return IRQ_HANDLED;
 }
 
-static void (*poweroff_method)(void) = machine_alt_power_off;
-
-void machine_power_off(void)
-{
-	sstate_poweroff();
-	if (strcmp(of_console_device->type, "serial") || scons_pwroff) {
-		if (power_reg) {
-			/* Both register bits seem to have the
-			 * same effect, so until I figure out
-			 * what the difference is...
-			 */
-			writel(AUXIO_PCIO_CPWR_OFF | AUXIO_PCIO_SPWR_OFF, power_reg);
-		} else {
-			if (poweroff_method != NULL) {
-				poweroff_method();
-				/* not reached */
-			}
-		}
-	}
-	machine_halt();
-}
-
-void (*pm_power_off)(void) = machine_power_off;
-EXPORT_SYMBOL(pm_power_off);
-
 static int __init has_button_interrupt(unsigned int irq, struct device_node *dp)
 {
 	if (irq == 0xffffffff)
@@ -85,8 +43,6 @@
 	printk(KERN_INFO "%s: Control reg at %lx\n",
 	       op->node->name, res->start);
 
-	poweroff_method = machine_halt;  /* able to use the standard halt */
-
 	if (has_button_interrupt(irq, op->node)) {
 		if (request_irq(irq,
 				power_handler, 0, "power", NULL) < 0)
@@ -96,7 +52,7 @@
 	return 0;
 }
 
-static struct of_device_id power_match[] = {
+static struct of_device_id __initdata power_match[] = {
 	{
 		.name = "power",
 	},
@@ -111,8 +67,9 @@
 	},
 };
 
-void __init power_init(void)
+static int __init power_init(void)
 {
-	of_register_driver(&power_driver, &of_platform_bus_type);
-	return;
+	return of_register_driver(&power_driver, &of_platform_bus_type);
 }
+
+device_initcall(power_init);
diff --git a/arch/sparc64/kernel/process.c b/arch/sparc64/kernel/process.c
index 15f4178..d5e2ace 100644
--- a/arch/sparc64/kernel/process.c
+++ b/arch/sparc64/kernel/process.c
@@ -22,7 +22,6 @@
 #include <linux/ptrace.h>
 #include <linux/slab.h>
 #include <linux/user.h>
-#include <linux/reboot.h>
 #include <linux/delay.h>
 #include <linux/compat.h>
 #include <linux/tick.h>
@@ -31,7 +30,6 @@
 #include <linux/elfcore.h>
 #include <linux/sysrq.h>
 
-#include <asm/oplib.h>
 #include <asm/uaccess.h>
 #include <asm/system.h>
 #include <asm/page.h>
@@ -46,8 +44,6 @@
 #include <asm/mmu_context.h>
 #include <asm/unistd.h>
 #include <asm/hypervisor.h>
-#include <asm/sstate.h>
-#include <asm/reboot.h>
 #include <asm/syscalls.h>
 #include <asm/irq_regs.h>
 #include <asm/smp.h>
@@ -115,35 +111,6 @@
 	}
 }
 
-void machine_halt(void)
-{
-	sstate_halt();
-	prom_halt();
-	panic("Halt failed!");
-}
-
-void machine_alt_power_off(void)
-{
-	sstate_poweroff();
-	prom_halt_power_off();
-	panic("Power-off failed!");
-}
-
-void machine_restart(char * cmd)
-{
-	char *p;
-	
-	sstate_reboot();
-	p = strchr (reboot_command, '\n');
-	if (p) *p = 0;
-	if (cmd)
-		prom_reboot(cmd);
-	if (*reboot_command)
-		prom_reboot(reboot_command);
-	prom_reboot("");
-	panic("Reboot failed!");
-}
-
 #ifdef CONFIG_COMPAT
 static void show_regwindow32(struct pt_regs *regs)
 {
@@ -248,7 +215,6 @@
 	global_reg_snapshot[this_cpu].o7 = regs->u_regs[UREG_I7];
 
 	if (regs->tstate & TSTATE_PRIV) {
-		struct thread_info *tp = current_thread_info();
 		struct reg_window *rw;
 
 		rw = (struct reg_window *)
@@ -304,7 +270,6 @@
 
 	for_each_online_cpu(cpu) {
 		struct global_reg_snapshot *gp = &global_reg_snapshot[cpu];
-		struct thread_info *tp;
 
 		__global_reg_poll(gp);
 
diff --git a/arch/sparc64/kernel/prom.c b/arch/sparc64/kernel/prom.c
index 7151513..dbba82f 100644
--- a/arch/sparc64/kernel/prom.c
+++ b/arch/sparc64/kernel/prom.c
@@ -38,7 +38,7 @@
 {
 	struct device_node *np;
 
-	for (np = allnodes; np != 0; np = np->allnext)
+	for (np = allnodes; np; np = np->allnext)
 		if (np->node == handle)
 			break;
 
@@ -59,6 +59,9 @@
 }
 EXPORT_SYMBOL(of_getintprop_default);
 
+DEFINE_MUTEX(of_set_property_mutex);
+EXPORT_SYMBOL(of_set_property_mutex);
+
 int of_set_property(struct device_node *dp, const char *name, void *val, int len)
 {
 	struct property **prevp;
@@ -82,7 +85,10 @@
 			void *old_val = prop->value;
 			int ret;
 
+			mutex_lock(&of_set_property_mutex);
 			ret = prom_setprop(dp->node, name, val, len);
+			mutex_unlock(&of_set_property_mutex);
+
 			err = -EINVAL;
 			if (ret >= 0) {
 				prop->value = new_val;
@@ -945,22 +951,30 @@
 		for (i = 0; i < ARRAY_SIZE(pci_irq_trans_table); i++) {
 			struct irq_trans *t = &pci_irq_trans_table[i];
 
-			if (!strcmp(model, t->name))
-				return t->init(dp);
+			if (!strcmp(model, t->name)) {
+				t->init(dp);
+				return;
+			}
 		}
 	}
 #endif
 #ifdef CONFIG_SBUS
 	if (!strcmp(dp->name, "sbus") ||
-	    !strcmp(dp->name, "sbi"))
-		return sbus_irq_trans_init(dp);
+	    !strcmp(dp->name, "sbi")) {
+		sbus_irq_trans_init(dp);
+		return;
+	}
 #endif
 	if (!strcmp(dp->name, "fhc") &&
-	    !strcmp(dp->parent->name, "central"))
-		return central_irq_trans_init(dp);
+	    !strcmp(dp->parent->name, "central")) {
+		central_irq_trans_init(dp);
+		return;
+	}
 	if (!strcmp(dp->name, "virtual-devices") ||
-	    !strcmp(dp->name, "niu"))
-		return sun4v_vdev_irq_trans_init(dp);
+	    !strcmp(dp->name, "niu")) {
+		sun4v_vdev_irq_trans_init(dp);
+		return;
+	}
 }
 
 static int is_root_node(const struct device_node *dp)
@@ -1231,32 +1245,49 @@
 
 	if (parent != NULL) {
 		if (!strcmp(parent->type, "pci") ||
-		    !strcmp(parent->type, "pciex"))
-			return pci_path_component(dp, tmp_buf);
-		if (!strcmp(parent->type, "sbus"))
-			return sbus_path_component(dp, tmp_buf);
-		if (!strcmp(parent->type, "upa"))
-			return upa_path_component(dp, tmp_buf);
-		if (!strcmp(parent->type, "ebus"))
-			return ebus_path_component(dp, tmp_buf);
+		    !strcmp(parent->type, "pciex")) {
+			pci_path_component(dp, tmp_buf);
+			return;
+		}
+		if (!strcmp(parent->type, "sbus")) {
+			sbus_path_component(dp, tmp_buf);
+			return;
+		}
+		if (!strcmp(parent->type, "upa")) {
+			upa_path_component(dp, tmp_buf);
+			return;
+		}
+		if (!strcmp(parent->type, "ebus")) {
+			ebus_path_component(dp, tmp_buf);
+			return;
+		}
 		if (!strcmp(parent->name, "usb") ||
-		    !strcmp(parent->name, "hub"))
-			return usb_path_component(dp, tmp_buf);
-		if (!strcmp(parent->type, "i2c"))
-			return i2c_path_component(dp, tmp_buf);
-		if (!strcmp(parent->type, "firewire"))
-			return ieee1394_path_component(dp, tmp_buf);
-		if (!strcmp(parent->type, "virtual-devices"))
-			return vdev_path_component(dp, tmp_buf);
-
+		    !strcmp(parent->name, "hub")) {
+			usb_path_component(dp, tmp_buf);
+			return;
+		}
+		if (!strcmp(parent->type, "i2c")) {
+			i2c_path_component(dp, tmp_buf);
+			return;
+		}
+		if (!strcmp(parent->type, "firewire")) {
+			ieee1394_path_component(dp, tmp_buf);
+			return;
+		}
+		if (!strcmp(parent->type, "virtual-devices")) {
+			vdev_path_component(dp, tmp_buf);
+			return;
+		}
 		/* "isa" is handled with platform naming */
 	}
 
 	/* Use platform naming convention.  */
-	if (tlb_type == hypervisor)
-		return sun4v_path_component(dp, tmp_buf);
-	else
-		return sun4u_path_component(dp, tmp_buf);
+	if (tlb_type == hypervisor) {
+		sun4v_path_component(dp, tmp_buf);
+		return;
+	} else {
+		sun4u_path_component(dp, tmp_buf);
+	}
 }
 
 static char * __init build_path_component(struct device_node *dp)
diff --git a/arch/sparc64/kernel/psycho_common.c b/arch/sparc64/kernel/psycho_common.c
new file mode 100644
index 0000000..7909964
--- /dev/null
+++ b/arch/sparc64/kernel/psycho_common.c
@@ -0,0 +1,470 @@
+/* psycho_common.c: Code common to PSYCHO and derivative PCI controllers.
+ *
+ * Copyright (C) 2008 David S. Miller <davem@davemloft.net>
+ */
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+
+#include <asm/upa.h>
+
+#include "pci_impl.h"
+#include "iommu_common.h"
+#include "psycho_common.h"
+
+#define  PSYCHO_STRBUF_CTRL_DENAB	0x0000000000000002UL
+#define  PSYCHO_STCERR_WRITE		0x0000000000000002UL
+#define  PSYCHO_STCERR_READ		0x0000000000000001UL
+#define  PSYCHO_STCTAG_PPN		0x0fffffff00000000UL
+#define  PSYCHO_STCTAG_VPN		0x00000000ffffe000UL
+#define  PSYCHO_STCTAG_VALID		0x0000000000000002UL
+#define  PSYCHO_STCTAG_WRITE		0x0000000000000001UL
+#define  PSYCHO_STCLINE_LINDX		0x0000000001e00000UL
+#define  PSYCHO_STCLINE_SPTR		0x00000000001f8000UL
+#define  PSYCHO_STCLINE_LADDR		0x0000000000007f00UL
+#define  PSYCHO_STCLINE_EPTR		0x00000000000000fcUL
+#define  PSYCHO_STCLINE_VALID		0x0000000000000002UL
+#define  PSYCHO_STCLINE_FOFN		0x0000000000000001UL
+
+static DEFINE_SPINLOCK(stc_buf_lock);
+static unsigned long stc_error_buf[128];
+static unsigned long stc_tag_buf[16];
+static unsigned long stc_line_buf[16];
+
+static void psycho_check_stc_error(struct pci_pbm_info *pbm)
+{
+	unsigned long err_base, tag_base, line_base;
+	struct strbuf *strbuf = &pbm->stc;
+	u64 control;
+	int i;
+
+	if (!strbuf->strbuf_control)
+		return;
+
+	err_base = strbuf->strbuf_err_stat;
+	tag_base = strbuf->strbuf_tag_diag;
+	line_base = strbuf->strbuf_line_diag;
+
+	spin_lock(&stc_buf_lock);
+
+	/* This is __REALLY__ dangerous.  When we put the streaming
+	 * buffer into diagnostic mode to probe it's tags and error
+	 * status, we _must_ clear all of the line tag valid bits
+	 * before re-enabling the streaming buffer.  If any dirty data
+	 * lives in the STC when we do this, we will end up
+	 * invalidating it before it has a chance to reach main
+	 * memory.
+	 */
+	control = upa_readq(strbuf->strbuf_control);
+	upa_writeq(control | PSYCHO_STRBUF_CTRL_DENAB, strbuf->strbuf_control);
+	for (i = 0; i < 128; i++) {
+		u64 val;
+
+		val = upa_readq(err_base + (i * 8UL));
+		upa_writeq(0UL, err_base + (i * 8UL));
+		stc_error_buf[i] = val;
+	}
+	for (i = 0; i < 16; i++) {
+		stc_tag_buf[i] = upa_readq(tag_base + (i * 8UL));
+		stc_line_buf[i] = upa_readq(line_base + (i * 8UL));
+		upa_writeq(0UL, tag_base + (i * 8UL));
+		upa_writeq(0UL, line_base + (i * 8UL));
+	}
+
+	/* OK, state is logged, exit diagnostic mode. */
+	upa_writeq(control, strbuf->strbuf_control);
+
+	for (i = 0; i < 16; i++) {
+		int j, saw_error, first, last;
+
+		saw_error = 0;
+		first = i * 8;
+		last = first + 8;
+		for (j = first; j < last; j++) {
+			u64 errval = stc_error_buf[j];
+			if (errval != 0) {
+				saw_error++;
+				printk(KERN_ERR "%s: STC_ERR(%d)[wr(%d)"
+				       "rd(%d)]\n",
+				       pbm->name,
+				       j,
+				       (errval & PSYCHO_STCERR_WRITE) ? 1 : 0,
+				       (errval & PSYCHO_STCERR_READ) ? 1 : 0);
+			}
+		}
+		if (saw_error != 0) {
+			u64 tagval = stc_tag_buf[i];
+			u64 lineval = stc_line_buf[i];
+			printk(KERN_ERR "%s: STC_TAG(%d)[PA(%016lx)VA(%08lx)"
+			       "V(%d)W(%d)]\n",
+			       pbm->name,
+			       i,
+			       ((tagval & PSYCHO_STCTAG_PPN) >> 19UL),
+			       (tagval & PSYCHO_STCTAG_VPN),
+			       ((tagval & PSYCHO_STCTAG_VALID) ? 1 : 0),
+			       ((tagval & PSYCHO_STCTAG_WRITE) ? 1 : 0));
+			printk(KERN_ERR "%s: STC_LINE(%d)[LIDX(%lx)SP(%lx)"
+			       "LADDR(%lx)EP(%lx)V(%d)FOFN(%d)]\n",
+			       pbm->name,
+			       i,
+			       ((lineval & PSYCHO_STCLINE_LINDX) >> 21UL),
+			       ((lineval & PSYCHO_STCLINE_SPTR) >> 15UL),
+			       ((lineval & PSYCHO_STCLINE_LADDR) >> 8UL),
+			       ((lineval & PSYCHO_STCLINE_EPTR) >> 2UL),
+			       ((lineval & PSYCHO_STCLINE_VALID) ? 1 : 0),
+			       ((lineval & PSYCHO_STCLINE_FOFN) ? 1 : 0));
+		}
+	}
+
+	spin_unlock(&stc_buf_lock);
+}
+
+#define PSYCHO_IOMMU_TAG		0xa580UL
+#define PSYCHO_IOMMU_DATA		0xa600UL
+
+static void psycho_record_iommu_tags_and_data(struct pci_pbm_info *pbm,
+					      u64 *tag, u64 *data)
+{
+	int i;
+
+	for (i = 0; i < 16; i++) {
+		unsigned long base = pbm->controller_regs;
+		unsigned long off = i * 8UL;
+
+		tag[i] = upa_readq(base + PSYCHO_IOMMU_TAG+off);
+		data[i] = upa_readq(base + PSYCHO_IOMMU_DATA+off);
+
+		/* Now clear out the entry. */
+		upa_writeq(0, base + PSYCHO_IOMMU_TAG + off);
+		upa_writeq(0, base + PSYCHO_IOMMU_DATA + off);
+	}
+}
+
+#define  PSYCHO_IOMMU_TAG_ERRSTS (0x3UL << 23UL)
+#define  PSYCHO_IOMMU_TAG_ERR	 (0x1UL << 22UL)
+#define  PSYCHO_IOMMU_TAG_WRITE	 (0x1UL << 21UL)
+#define  PSYCHO_IOMMU_TAG_STREAM (0x1UL << 20UL)
+#define  PSYCHO_IOMMU_TAG_SIZE	 (0x1UL << 19UL)
+#define  PSYCHO_IOMMU_TAG_VPAGE	 0x7ffffUL
+#define  PSYCHO_IOMMU_DATA_VALID (1UL << 30UL)
+#define  PSYCHO_IOMMU_DATA_CACHE (1UL << 28UL)
+#define  PSYCHO_IOMMU_DATA_PPAGE 0xfffffffUL
+
+static void psycho_dump_iommu_tags_and_data(struct pci_pbm_info *pbm,
+					    u64 *tag, u64 *data)
+{
+	int i;
+
+	for (i = 0; i < 16; i++) {
+		u64 tag_val, data_val;
+		const char *type_str;
+		tag_val = tag[i];
+		if (!(tag_val & PSYCHO_IOMMU_TAG_ERR))
+			continue;
+
+		data_val = data[i];
+		switch((tag_val & PSYCHO_IOMMU_TAG_ERRSTS) >> 23UL) {
+		case 0:
+			type_str = "Protection Error";
+			break;
+		case 1:
+			type_str = "Invalid Error";
+			break;
+		case 2:
+			type_str = "TimeOut Error";
+			break;
+		case 3:
+		default:
+			type_str = "ECC Error";
+			break;
+		}
+
+		printk(KERN_ERR "%s: IOMMU TAG(%d)[error(%s) wr(%d) "
+		       "str(%d) sz(%dK) vpg(%08lx)]\n",
+		       pbm->name, i, type_str,
+		       ((tag_val & PSYCHO_IOMMU_TAG_WRITE) ? 1 : 0),
+		       ((tag_val & PSYCHO_IOMMU_TAG_STREAM) ? 1 : 0),
+		       ((tag_val & PSYCHO_IOMMU_TAG_SIZE) ? 64 : 8),
+		       (tag_val & PSYCHO_IOMMU_TAG_VPAGE) << IOMMU_PAGE_SHIFT);
+		printk(KERN_ERR "%s: IOMMU DATA(%d)[valid(%d) cache(%d) "
+		       "ppg(%016lx)]\n",
+		       pbm->name, i,
+		       ((data_val & PSYCHO_IOMMU_DATA_VALID) ? 1 : 0),
+		       ((data_val & PSYCHO_IOMMU_DATA_CACHE) ? 1 : 0),
+		       (data_val & PSYCHO_IOMMU_DATA_PPAGE)<<IOMMU_PAGE_SHIFT);
+	}
+}
+
+#define  PSYCHO_IOMMU_CTRL_XLTESTAT	0x0000000006000000UL
+#define  PSYCHO_IOMMU_CTRL_XLTEERR	0x0000000001000000UL
+
+void psycho_check_iommu_error(struct pci_pbm_info *pbm,
+			      unsigned long afsr,
+			      unsigned long afar,
+			      enum psycho_error_type type)
+{
+	u64 control, iommu_tag[16], iommu_data[16];
+	struct iommu *iommu = pbm->iommu;
+	unsigned long flags;
+
+	spin_lock_irqsave(&iommu->lock, flags);
+	control = upa_readq(iommu->iommu_control);
+	if (control & PSYCHO_IOMMU_CTRL_XLTEERR) {
+		const char *type_str;
+
+		control &= ~PSYCHO_IOMMU_CTRL_XLTEERR;
+		upa_writeq(control, iommu->iommu_control);
+
+		switch ((control & PSYCHO_IOMMU_CTRL_XLTESTAT) >> 25UL) {
+		case 0:
+			type_str = "Protection Error";
+			break;
+		case 1:
+			type_str = "Invalid Error";
+			break;
+		case 2:
+			type_str = "TimeOut Error";
+			break;
+		case 3:
+		default:
+			type_str = "ECC Error";
+			break;
+		};
+		printk(KERN_ERR "%s: IOMMU Error, type[%s]\n",
+		       pbm->name, type_str);
+
+		/* It is very possible for another DVMA to occur while
+		 * we do this probe, and corrupt the system further.
+		 * But we are so screwed at this point that we are
+		 * likely to crash hard anyways, so get as much
+		 * diagnostic information to the console as we can.
+		 */
+		psycho_record_iommu_tags_and_data(pbm, iommu_tag, iommu_data);
+		psycho_dump_iommu_tags_and_data(pbm, iommu_tag, iommu_data);
+	}
+	psycho_check_stc_error(pbm);
+	spin_unlock_irqrestore(&iommu->lock, flags);
+}
+
+#define  PSYCHO_PCICTRL_SBH_ERR	 0x0000000800000000UL
+#define  PSYCHO_PCICTRL_SERR	 0x0000000400000000UL
+
+static irqreturn_t psycho_pcierr_intr_other(struct pci_pbm_info *pbm)
+{
+	irqreturn_t ret = IRQ_NONE;
+	u64 csr, csr_error_bits;
+	u16 stat, *addr;
+
+	csr = upa_readq(pbm->pci_csr);
+	csr_error_bits = csr & (PSYCHO_PCICTRL_SBH_ERR | PSYCHO_PCICTRL_SERR);
+	if (csr_error_bits) {
+		/* Clear the errors.  */
+		upa_writeq(csr, pbm->pci_csr);
+
+		/* Log 'em.  */
+		if (csr_error_bits & PSYCHO_PCICTRL_SBH_ERR)
+			printk(KERN_ERR "%s: PCI streaming byte hole "
+			       "error asserted.\n", pbm->name);
+		if (csr_error_bits & PSYCHO_PCICTRL_SERR)
+			printk(KERN_ERR "%s: PCI SERR signal asserted.\n",
+			       pbm->name);
+		ret = IRQ_HANDLED;
+	}
+	addr = psycho_pci_config_mkaddr(pbm, pbm->pci_first_busno,
+					0, PCI_STATUS);
+	pci_config_read16(addr, &stat);
+	if (stat & (PCI_STATUS_PARITY |
+		    PCI_STATUS_SIG_TARGET_ABORT |
+		    PCI_STATUS_REC_TARGET_ABORT |
+		    PCI_STATUS_REC_MASTER_ABORT |
+		    PCI_STATUS_SIG_SYSTEM_ERROR)) {
+		printk(KERN_ERR "%s: PCI bus error, PCI_STATUS[%04x]\n",
+		       pbm->name, stat);
+		pci_config_write16(addr, 0xffff);
+		ret = IRQ_HANDLED;
+	}
+	return ret;
+}
+
+#define  PSYCHO_PCIAFSR_PMA	0x8000000000000000UL
+#define  PSYCHO_PCIAFSR_PTA	0x4000000000000000UL
+#define  PSYCHO_PCIAFSR_PRTRY	0x2000000000000000UL
+#define  PSYCHO_PCIAFSR_PPERR	0x1000000000000000UL
+#define  PSYCHO_PCIAFSR_SMA	0x0800000000000000UL
+#define  PSYCHO_PCIAFSR_STA	0x0400000000000000UL
+#define  PSYCHO_PCIAFSR_SRTRY	0x0200000000000000UL
+#define  PSYCHO_PCIAFSR_SPERR	0x0100000000000000UL
+#define  PSYCHO_PCIAFSR_RESV1	0x00ff000000000000UL
+#define  PSYCHO_PCIAFSR_BMSK	0x0000ffff00000000UL
+#define  PSYCHO_PCIAFSR_BLK	0x0000000080000000UL
+#define  PSYCHO_PCIAFSR_RESV2	0x0000000040000000UL
+#define  PSYCHO_PCIAFSR_MID	0x000000003e000000UL
+#define  PSYCHO_PCIAFSR_RESV3	0x0000000001ffffffUL
+
+irqreturn_t psycho_pcierr_intr(int irq, void *dev_id)
+{
+	struct pci_pbm_info *pbm = dev_id;
+	u64 afsr, afar, error_bits;
+	int reported;
+
+	afsr = upa_readq(pbm->pci_afsr);
+	afar = upa_readq(pbm->pci_afar);
+	error_bits = afsr &
+		(PSYCHO_PCIAFSR_PMA | PSYCHO_PCIAFSR_PTA |
+		 PSYCHO_PCIAFSR_PRTRY | PSYCHO_PCIAFSR_PPERR |
+		 PSYCHO_PCIAFSR_SMA | PSYCHO_PCIAFSR_STA |
+		 PSYCHO_PCIAFSR_SRTRY | PSYCHO_PCIAFSR_SPERR);
+	if (!error_bits)
+		return psycho_pcierr_intr_other(pbm);
+	upa_writeq(error_bits, pbm->pci_afsr);
+	printk(KERN_ERR "%s: PCI Error, primary error type[%s]\n",
+	       pbm->name,
+	       (((error_bits & PSYCHO_PCIAFSR_PMA) ?
+		 "Master Abort" :
+		 ((error_bits & PSYCHO_PCIAFSR_PTA) ?
+		  "Target Abort" :
+		  ((error_bits & PSYCHO_PCIAFSR_PRTRY) ?
+		   "Excessive Retries" :
+		   ((error_bits & PSYCHO_PCIAFSR_PPERR) ?
+		    "Parity Error" : "???"))))));
+	printk(KERN_ERR "%s: bytemask[%04lx] UPA_MID[%02lx] was_block(%d)\n",
+	       pbm->name,
+	       (afsr & PSYCHO_PCIAFSR_BMSK) >> 32UL,
+	       (afsr & PSYCHO_PCIAFSR_MID) >> 25UL,
+	       (afsr & PSYCHO_PCIAFSR_BLK) ? 1 : 0);
+	printk(KERN_ERR "%s: PCI AFAR [%016lx]\n", pbm->name, afar);
+	printk(KERN_ERR "%s: PCI Secondary errors [", pbm->name);
+	reported = 0;
+	if (afsr & PSYCHO_PCIAFSR_SMA) {
+		reported++;
+		printk("(Master Abort)");
+	}
+	if (afsr & PSYCHO_PCIAFSR_STA) {
+		reported++;
+		printk("(Target Abort)");
+	}
+	if (afsr & PSYCHO_PCIAFSR_SRTRY) {
+		reported++;
+		printk("(Excessive Retries)");
+	}
+	if (afsr & PSYCHO_PCIAFSR_SPERR) {
+		reported++;
+		printk("(Parity Error)");
+	}
+	if (!reported)
+		printk("(none)");
+	printk("]\n");
+
+	if (error_bits & (PSYCHO_PCIAFSR_PTA | PSYCHO_PCIAFSR_STA)) {
+		psycho_check_iommu_error(pbm, afsr, afar, PCI_ERR);
+		pci_scan_for_target_abort(pbm, pbm->pci_bus);
+	}
+	if (error_bits & (PSYCHO_PCIAFSR_PMA | PSYCHO_PCIAFSR_SMA))
+		pci_scan_for_master_abort(pbm, pbm->pci_bus);
+
+	if (error_bits & (PSYCHO_PCIAFSR_PPERR | PSYCHO_PCIAFSR_SPERR))
+		pci_scan_for_parity_error(pbm, pbm->pci_bus);
+
+	return IRQ_HANDLED;
+}
+
+static void psycho_iommu_flush(struct pci_pbm_info *pbm)
+{
+	int i;
+
+	for (i = 0; i < 16; i++) {
+		unsigned long off = i * 8;
+
+		upa_writeq(0, pbm->controller_regs + PSYCHO_IOMMU_TAG + off);
+		upa_writeq(0, pbm->controller_regs + PSYCHO_IOMMU_DATA + off);
+	}
+}
+
+#define PSYCHO_IOMMU_CONTROL		0x0200UL
+#define  PSYCHO_IOMMU_CTRL_TSBSZ	0x0000000000070000UL
+#define  PSYCHO_IOMMU_TSBSZ_1K      	0x0000000000000000UL
+#define  PSYCHO_IOMMU_TSBSZ_2K      	0x0000000000010000UL
+#define  PSYCHO_IOMMU_TSBSZ_4K      	0x0000000000020000UL
+#define  PSYCHO_IOMMU_TSBSZ_8K      	0x0000000000030000UL
+#define  PSYCHO_IOMMU_TSBSZ_16K     	0x0000000000040000UL
+#define  PSYCHO_IOMMU_TSBSZ_32K     	0x0000000000050000UL
+#define  PSYCHO_IOMMU_TSBSZ_64K     	0x0000000000060000UL
+#define  PSYCHO_IOMMU_TSBSZ_128K    	0x0000000000070000UL
+#define  PSYCHO_IOMMU_CTRL_TBWSZ    	0x0000000000000004UL
+#define  PSYCHO_IOMMU_CTRL_DENAB    	0x0000000000000002UL
+#define  PSYCHO_IOMMU_CTRL_ENAB     	0x0000000000000001UL
+#define PSYCHO_IOMMU_FLUSH		0x0210UL
+#define PSYCHO_IOMMU_TSBBASE		0x0208UL
+
+int psycho_iommu_init(struct pci_pbm_info *pbm, int tsbsize,
+		      u32 dvma_offset, u32 dma_mask,
+		      unsigned long write_complete_offset)
+{
+	struct iommu *iommu = pbm->iommu;
+	u64 control;
+	int err;
+
+	iommu->iommu_control  = pbm->controller_regs + PSYCHO_IOMMU_CONTROL;
+	iommu->iommu_tsbbase  = pbm->controller_regs + PSYCHO_IOMMU_TSBBASE;
+	iommu->iommu_flush    = pbm->controller_regs + PSYCHO_IOMMU_FLUSH;
+	iommu->iommu_tags     = pbm->controller_regs + PSYCHO_IOMMU_TAG;
+	iommu->write_complete_reg = (pbm->controller_regs +
+				     write_complete_offset);
+
+	iommu->iommu_ctxflush = 0;
+
+	control = upa_readq(iommu->iommu_control);
+	control |= PSYCHO_IOMMU_CTRL_DENAB;
+	upa_writeq(control, iommu->iommu_control);
+
+	psycho_iommu_flush(pbm);
+
+	/* Leave diag mode enabled for full-flushing done in pci_iommu.c */
+	err = iommu_table_init(iommu, tsbsize * 1024 * 8,
+			       dvma_offset, dma_mask, pbm->numa_node);
+	if (err)
+		return err;
+
+	upa_writeq(__pa(iommu->page_table), iommu->iommu_tsbbase);
+
+	control = upa_readq(iommu->iommu_control);
+	control &= ~(PSYCHO_IOMMU_CTRL_TSBSZ | PSYCHO_IOMMU_CTRL_TBWSZ);
+	control |= PSYCHO_IOMMU_CTRL_ENAB;
+
+	switch (tsbsize) {
+	case 64:
+		control |= PSYCHO_IOMMU_TSBSZ_64K;
+		break;
+	case 128:
+		control |= PSYCHO_IOMMU_TSBSZ_128K;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	upa_writeq(control, iommu->iommu_control);
+
+	return 0;
+
+}
+
+void psycho_pbm_init_common(struct pci_pbm_info *pbm, struct of_device *op,
+			    const char *chip_name, int chip_type)
+{
+	struct device_node *dp = op->node;
+
+	pbm->name = dp->full_name;
+	pbm->numa_node = -1;
+	pbm->chip_type = chip_type;
+	pbm->chip_version = of_getintprop_default(dp, "version#", 0);
+	pbm->chip_revision = of_getintprop_default(dp, "module-revision#", 0);
+	pbm->op = op;
+	pbm->pci_ops = &sun4u_pci_ops;
+	pbm->config_space_reg_bits = 8;
+	pbm->index = pci_num_pbms++;
+	pci_get_pbm_props(pbm);
+	pci_determine_mem_io_space(pbm);
+
+	printk(KERN_INFO "%s: %s PCI Bus Module ver[%x:%x]\n",
+	       pbm->name, chip_name,
+	       pbm->chip_version, pbm->chip_revision);
+}
diff --git a/arch/sparc64/kernel/psycho_common.h b/arch/sparc64/kernel/psycho_common.h
new file mode 100644
index 0000000..092c278
--- /dev/null
+++ b/arch/sparc64/kernel/psycho_common.h
@@ -0,0 +1,48 @@
+#ifndef _PSYCHO_COMMON_H
+#define _PSYCHO_COMMON_H
+
+/* U2P Programmer's Manual, page 13-55, configuration space
+ * address format:
+ * 
+ *  32             24 23 16 15    11 10       8 7   2  1 0
+ * ---------------------------------------------------------
+ * |0 0 0 0 0 0 0 0 1| bus | device | function | reg | 0 0 |
+ * ---------------------------------------------------------
+ */
+#define PSYCHO_CONFIG_BASE(PBM)	\
+	((PBM)->config_space | (1UL << 24))
+#define PSYCHO_CONFIG_ENCODE(BUS, DEVFN, REG)	\
+	(((unsigned long)(BUS)   << 16) |	\
+	 ((unsigned long)(DEVFN) << 8)  |	\
+	 ((unsigned long)(REG)))
+
+static inline void *psycho_pci_config_mkaddr(struct pci_pbm_info *pbm,
+					     unsigned char bus,
+					     unsigned int devfn,
+					     int where)
+{
+	return (void *)
+		(PSYCHO_CONFIG_BASE(pbm) |
+		 PSYCHO_CONFIG_ENCODE(bus, devfn, where));
+}
+
+enum psycho_error_type {
+	UE_ERR, CE_ERR, PCI_ERR
+};
+
+extern void psycho_check_iommu_error(struct pci_pbm_info *pbm,
+				     unsigned long afsr,
+				     unsigned long afar,
+				     enum psycho_error_type type);
+
+extern irqreturn_t psycho_pcierr_intr(int irq, void *dev_id);
+
+extern int psycho_iommu_init(struct pci_pbm_info *pbm, int tsbsize,
+			     u32 dvma_offset, u32 dma_mask,
+			     unsigned long write_complete_offset);
+
+extern void psycho_pbm_init_common(struct pci_pbm_info *pbm,
+				   struct of_device *op,
+				   const char *chip_name, int chip_type);
+
+#endif /* _PSYCHO_COMMON_H */
diff --git a/arch/sparc64/kernel/ptrace.c b/arch/sparc64/kernel/ptrace.c
index 10306e4..f43adbc 100644
--- a/arch/sparc64/kernel/ptrace.c
+++ b/arch/sparc64/kernel/ptrace.c
@@ -1050,31 +1050,17 @@
 	return ret;
 }
 
-asmlinkage int syscall_trace(struct pt_regs *regs, int syscall_exit_p)
+asmlinkage int syscall_trace_enter(struct pt_regs *regs)
 {
 	int ret = 0;
 
 	/* do the secure computing check first */
 	secure_computing(regs->u_regs[UREG_G1]);
 
-	if (unlikely(current->audit_context) && syscall_exit_p) {
-		unsigned long tstate = regs->tstate;
-		int result = AUDITSC_SUCCESS;
+	if (test_thread_flag(TIF_SYSCALL_TRACE))
+		ret = tracehook_report_syscall_entry(regs);
 
-		if (unlikely(tstate & (TSTATE_XCARRY | TSTATE_ICARRY)))
-			result = AUDITSC_FAILURE;
-
-		audit_syscall_exit(result, regs->u_regs[UREG_I0]);
-	}
-
-	if (test_thread_flag(TIF_SYSCALL_TRACE)) {
-		if (syscall_exit_p)
-			tracehook_report_syscall_exit(regs, 0);
-		else
-			ret = tracehook_report_syscall_entry(regs);
-	}
-
-	if (unlikely(current->audit_context) && !syscall_exit_p && !ret)
+	if (unlikely(current->audit_context) && !ret)
 		audit_syscall_entry((test_thread_flag(TIF_32BIT) ?
 				     AUDIT_ARCH_SPARC :
 				     AUDIT_ARCH_SPARC64),
@@ -1086,3 +1072,19 @@
 
 	return ret;
 }
+
+asmlinkage void syscall_trace_leave(struct pt_regs *regs)
+{
+	if (unlikely(current->audit_context)) {
+		unsigned long tstate = regs->tstate;
+		int result = AUDITSC_SUCCESS;
+
+		if (unlikely(tstate & (TSTATE_XCARRY | TSTATE_ICARRY)))
+			result = AUDITSC_FAILURE;
+
+		audit_syscall_exit(result, regs->u_regs[UREG_I0]);
+	}
+
+	if (test_thread_flag(TIF_SYSCALL_TRACE))
+		tracehook_report_syscall_exit(regs, 0);
+}
diff --git a/arch/sparc64/kernel/reboot.c b/arch/sparc64/kernel/reboot.c
new file mode 100644
index 0000000..ef89d3d
--- /dev/null
+++ b/arch/sparc64/kernel/reboot.c
@@ -0,0 +1,53 @@
+/* reboot.c: reboot/shutdown/halt/poweroff handling
+ *
+ * Copyright (C) 2008 David S. Miller <davem@davemloft.net>
+ */
+#include <linux/kernel.h>
+#include <linux/reboot.h>
+#include <linux/module.h>
+#include <linux/pm.h>
+
+#include <asm/system.h>
+#include <asm/oplib.h>
+#include <asm/prom.h>
+
+/* sysctl - toggle power-off restriction for serial console
+ * systems in machine_power_off()
+ */
+int scons_pwroff = 1;
+
+/* This isn't actually used, it exists merely to satisfy the
+ * reference in kernel/sys.c
+ */
+void (*pm_power_off)(void) = machine_power_off;
+EXPORT_SYMBOL(pm_power_off);
+
+void machine_power_off(void)
+{
+	if (strcmp(of_console_device->type, "serial") || scons_pwroff)
+		prom_halt_power_off();
+
+	prom_halt();
+}
+
+void machine_halt(void)
+{
+	prom_halt();
+	panic("Halt failed!");
+}
+
+void machine_restart(char *cmd)
+{
+	char *p;
+
+	p = strchr(reboot_command, '\n');
+	if (p)
+		*p = 0;
+	if (cmd)
+		prom_reboot(cmd);
+	if (*reboot_command)
+		prom_reboot(reboot_command);
+	prom_reboot("");
+	panic("Reboot failed!");
+}
+
diff --git a/arch/sparc64/kernel/sbus.c b/arch/sparc64/kernel/sbus.c
index e33a8a6..2ead310 100644
--- a/arch/sparc64/kernel/sbus.c
+++ b/arch/sparc64/kernel/sbus.c
@@ -11,15 +11,17 @@
 #include <linux/slab.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 
 #include <asm/page.h>
-#include <asm/sbus.h>
 #include <asm/io.h>
 #include <asm/upa.h>
 #include <asm/cache.h>
 #include <asm/dma.h>
 #include <asm/irq.h>
 #include <asm/prom.h>
+#include <asm/oplib.h>
 #include <asm/starfire.h>
 
 #include "iommu_common.h"
@@ -52,13 +54,23 @@
 #define STRBUF_TAG_VALID	0x02UL
 
 /* Enable 64-bit DVMA mode for the given device. */
-void sbus_set_sbus64(struct sbus_dev *sdev, int bursts)
+void sbus_set_sbus64(struct device *dev, int bursts)
 {
-	struct iommu *iommu = sdev->ofdev.dev.archdata.iommu;
-	int slot = sdev->slot;
+	struct iommu *iommu = dev->archdata.iommu;
+	struct of_device *op = to_of_device(dev);
+	const struct linux_prom_registers *regs;
 	unsigned long cfg_reg;
+	int slot;
 	u64 val;
 
+	regs = of_get_property(op->node, "reg", NULL);
+	if (!regs) {
+		printk(KERN_ERR "sbus_set_sbus64: Cannot find regs for %s\n",
+		       op->node->full_name);
+		return;
+	}
+	slot = regs->which_io;
+
 	cfg_reg = iommu->write_complete_reg;
 	switch (slot) {
 	case 0:
@@ -191,10 +203,9 @@
 	return imap + diff;
 }
 
-unsigned int sbus_build_irq(void *buscookie, unsigned int ino)
+static unsigned int sbus_build_irq(struct of_device *op, unsigned int ino)
 {
-	struct sbus_bus *sbus = (struct sbus_bus *)buscookie;
-	struct iommu *iommu = sbus->ofdev.dev.archdata.iommu;
+	struct iommu *iommu = op->dev.archdata.iommu;
 	unsigned long reg_base = iommu->write_complete_reg - 0x2000UL;
 	unsigned long imap, iclr;
 	int sbus_level = 0;
@@ -255,12 +266,12 @@
 #define  SYSIO_UEAFSR_RESV2 0x0000001fffffffffUL /* Reserved                  */
 static irqreturn_t sysio_ue_handler(int irq, void *dev_id)
 {
-	struct sbus_bus *sbus = dev_id;
-	struct iommu *iommu = sbus->ofdev.dev.archdata.iommu;
+	struct of_device *op = dev_id;
+	struct iommu *iommu = op->dev.archdata.iommu;
 	unsigned long reg_base = iommu->write_complete_reg - 0x2000UL;
 	unsigned long afsr_reg, afar_reg;
 	unsigned long afsr, afar, error_bits;
-	int reported;
+	int reported, portid;
 
 	afsr_reg = reg_base + SYSIO_UE_AFSR;
 	afar_reg = reg_base + SYSIO_UE_AFAR;
@@ -275,9 +286,11 @@
 		 SYSIO_UEAFSR_SPIO | SYSIO_UEAFSR_SDRD | SYSIO_UEAFSR_SDWR);
 	upa_writeq(error_bits, afsr_reg);
 
+	portid = of_getintprop_default(op->node, "portid", -1);
+
 	/* Log the error. */
 	printk("SYSIO[%x]: Uncorrectable ECC Error, primary error type[%s]\n",
-	       sbus->portid,
+	       portid,
 	       (((error_bits & SYSIO_UEAFSR_PPIO) ?
 		 "PIO" :
 		 ((error_bits & SYSIO_UEAFSR_PDRD) ?
@@ -285,12 +298,12 @@
 		  ((error_bits & SYSIO_UEAFSR_PDWR) ?
 		   "DVMA Write" : "???")))));
 	printk("SYSIO[%x]: DOFF[%lx] SIZE[%lx] MID[%lx]\n",
-	       sbus->portid,
+	       portid,
 	       (afsr & SYSIO_UEAFSR_DOFF) >> 45UL,
 	       (afsr & SYSIO_UEAFSR_SIZE) >> 42UL,
 	       (afsr & SYSIO_UEAFSR_MID) >> 37UL);
-	printk("SYSIO[%x]: AFAR[%016lx]\n", sbus->portid, afar);
-	printk("SYSIO[%x]: Secondary UE errors [", sbus->portid);
+	printk("SYSIO[%x]: AFAR[%016lx]\n", portid, afar);
+	printk("SYSIO[%x]: Secondary UE errors [", portid);
 	reported = 0;
 	if (afsr & SYSIO_UEAFSR_SPIO) {
 		reported++;
@@ -327,12 +340,12 @@
 #define  SYSIO_CEAFSR_RESV2 0x0000001fffffffffUL /* Reserved                  */
 static irqreturn_t sysio_ce_handler(int irq, void *dev_id)
 {
-	struct sbus_bus *sbus = dev_id;
-	struct iommu *iommu = sbus->ofdev.dev.archdata.iommu;
+	struct of_device *op = dev_id;
+	struct iommu *iommu = op->dev.archdata.iommu;
 	unsigned long reg_base = iommu->write_complete_reg - 0x2000UL;
 	unsigned long afsr_reg, afar_reg;
 	unsigned long afsr, afar, error_bits;
-	int reported;
+	int reported, portid;
 
 	afsr_reg = reg_base + SYSIO_CE_AFSR;
 	afar_reg = reg_base + SYSIO_CE_AFAR;
@@ -347,8 +360,10 @@
 		 SYSIO_CEAFSR_SPIO | SYSIO_CEAFSR_SDRD | SYSIO_CEAFSR_SDWR);
 	upa_writeq(error_bits, afsr_reg);
 
+	portid = of_getintprop_default(op->node, "portid", -1);
+
 	printk("SYSIO[%x]: Correctable ECC Error, primary error type[%s]\n",
-	       sbus->portid,
+	       portid,
 	       (((error_bits & SYSIO_CEAFSR_PPIO) ?
 		 "PIO" :
 		 ((error_bits & SYSIO_CEAFSR_PDRD) ?
@@ -360,14 +375,14 @@
 	 * XXX UDB CE trap handler does... -DaveM
 	 */
 	printk("SYSIO[%x]: DOFF[%lx] ECC Syndrome[%lx] Size[%lx] MID[%lx]\n",
-	       sbus->portid,
+	       portid,
 	       (afsr & SYSIO_CEAFSR_DOFF) >> 45UL,
 	       (afsr & SYSIO_CEAFSR_ESYND) >> 48UL,
 	       (afsr & SYSIO_CEAFSR_SIZE) >> 42UL,
 	       (afsr & SYSIO_CEAFSR_MID) >> 37UL);
-	printk("SYSIO[%x]: AFAR[%016lx]\n", sbus->portid, afar);
+	printk("SYSIO[%x]: AFAR[%016lx]\n", portid, afar);
 
-	printk("SYSIO[%x]: Secondary CE errors [", sbus->portid);
+	printk("SYSIO[%x]: Secondary CE errors [", portid);
 	reported = 0;
 	if (afsr & SYSIO_CEAFSR_SPIO) {
 		reported++;
@@ -404,11 +419,11 @@
 #define  SYSIO_SBAFSR_RESV3 0x0000001fffffffffUL /* Reserved                  */
 static irqreturn_t sysio_sbus_error_handler(int irq, void *dev_id)
 {
-	struct sbus_bus *sbus = dev_id;
-	struct iommu *iommu = sbus->ofdev.dev.archdata.iommu;
+	struct of_device *op = dev_id;
+	struct iommu *iommu = op->dev.archdata.iommu;
 	unsigned long afsr_reg, afar_reg, reg_base;
 	unsigned long afsr, afar, error_bits;
-	int reported;
+	int reported, portid;
 
 	reg_base = iommu->write_complete_reg - 0x2000UL;
 	afsr_reg = reg_base + SYSIO_SBUS_AFSR;
@@ -423,9 +438,11 @@
 		 SYSIO_SBAFSR_SLE | SYSIO_SBAFSR_STO | SYSIO_SBAFSR_SBERR);
 	upa_writeq(error_bits, afsr_reg);
 
+	portid = of_getintprop_default(op->node, "portid", -1);
+
 	/* Log the error. */
 	printk("SYSIO[%x]: SBUS Error, primary error type[%s] read(%d)\n",
-	       sbus->portid,
+	       portid,
 	       (((error_bits & SYSIO_SBAFSR_PLE) ?
 		 "Late PIO Error" :
 		 ((error_bits & SYSIO_SBAFSR_PTO) ?
@@ -434,11 +451,11 @@
 		   "Error Ack" : "???")))),
 	       (afsr & SYSIO_SBAFSR_RD) ? 1 : 0);
 	printk("SYSIO[%x]: size[%lx] MID[%lx]\n",
-	       sbus->portid,
+	       portid,
 	       (afsr & SYSIO_SBAFSR_SIZE) >> 42UL,
 	       (afsr & SYSIO_SBAFSR_MID) >> 37UL);
-	printk("SYSIO[%x]: AFAR[%016lx]\n", sbus->portid, afar);
-	printk("SYSIO[%x]: Secondary SBUS errors [", sbus->portid);
+	printk("SYSIO[%x]: AFAR[%016lx]\n", portid, afar);
+	printk("SYSIO[%x]: Secondary SBUS errors [", portid);
 	reported = 0;
 	if (afsr & SYSIO_SBAFSR_SLE) {
 		reported++;
@@ -470,34 +487,37 @@
 #define SYSIO_CE_INO		0x35
 #define SYSIO_SBUSERR_INO	0x36
 
-static void __init sysio_register_error_handlers(struct sbus_bus *sbus)
+static void __init sysio_register_error_handlers(struct of_device *op)
 {
-	struct iommu *iommu = sbus->ofdev.dev.archdata.iommu;
+	struct iommu *iommu = op->dev.archdata.iommu;
 	unsigned long reg_base = iommu->write_complete_reg - 0x2000UL;
 	unsigned int irq;
 	u64 control;
+	int portid;
 
-	irq = sbus_build_irq(sbus, SYSIO_UE_INO);
+	portid = of_getintprop_default(op->node, "portid", -1);
+
+	irq = sbus_build_irq(op, SYSIO_UE_INO);
 	if (request_irq(irq, sysio_ue_handler, 0,
-			"SYSIO_UE", sbus) < 0) {
+			"SYSIO_UE", op) < 0) {
 		prom_printf("SYSIO[%x]: Cannot register UE interrupt.\n",
-			    sbus->portid);
+			    portid);
 		prom_halt();
 	}
 
-	irq = sbus_build_irq(sbus, SYSIO_CE_INO);
+	irq = sbus_build_irq(op, SYSIO_CE_INO);
 	if (request_irq(irq, sysio_ce_handler, 0,
-			"SYSIO_CE", sbus) < 0) {
+			"SYSIO_CE", op) < 0) {
 		prom_printf("SYSIO[%x]: Cannot register CE interrupt.\n",
-			    sbus->portid);
+			    portid);
 		prom_halt();
 	}
 
-	irq = sbus_build_irq(sbus, SYSIO_SBUSERR_INO);
+	irq = sbus_build_irq(op, SYSIO_SBUSERR_INO);
 	if (request_irq(irq, sysio_sbus_error_handler, 0,
-			"SYSIO_SBERR", sbus) < 0) {
+			"SYSIO_SBERR", op) < 0) {
 		prom_printf("SYSIO[%x]: Cannot register SBUS Error interrupt.\n",
-			    sbus->portid);
+			    portid);
 		prom_halt();
 	}
 
@@ -513,19 +533,15 @@
 }
 
 /* Boot time initialization. */
-static void __init sbus_iommu_init(int __node, struct sbus_bus *sbus)
+static void __init sbus_iommu_init(struct of_device *op)
 {
 	const struct linux_prom64_registers *pr;
-	struct device_node *dp;
+	struct device_node *dp = op->node;
 	struct iommu *iommu;
 	struct strbuf *strbuf;
 	unsigned long regs, reg_base;
+	int i, portid;
 	u64 control;
-	int i;
-
-	dp = of_find_node_by_phandle(__node);
-
-	sbus->portid = of_getintprop_default(dp, "upa-portid", -1);
 
 	pr = of_get_property(dp, "reg", NULL);
 	if (!pr) {
@@ -542,9 +558,9 @@
 	if (!strbuf)
 		goto fatal_memory_error;
 
-	sbus->ofdev.dev.archdata.iommu = iommu;
-	sbus->ofdev.dev.archdata.stc = strbuf;
-	sbus->ofdev.dev.archdata.numa_node = -1;
+	op->dev.archdata.iommu = iommu;
+	op->dev.archdata.stc = strbuf;
+	op->dev.archdata.numa_node = -1;
 
 	reg_base = regs + SYSIO_IOMMUREG_BASE;
 	iommu->iommu_control = reg_base + IOMMU_CONTROL;
@@ -572,8 +588,9 @@
 	 */
 	iommu->write_complete_reg = regs + 0x2000UL;
 
-	printk("SYSIO: UPA portID %x, at %016lx\n",
-	       sbus->portid, regs);
+	portid = of_getintprop_default(op->node, "portid", -1);
+	printk(KERN_INFO "SYSIO: UPA portID %x, at %016lx\n",
+	       portid, regs);
 
 	/* Setup for TSB_SIZE=7, TBW_SIZE=0, MMU_DE=1, MMU_EN=1 */
 	if (iommu_table_init(iommu, IO_TSB_SIZE, MAP_BASE, 0xffffffff, -1))
@@ -631,56 +648,27 @@
 
 	/* Now some Xfire specific grot... */
 	if (this_is_starfire)
-		starfire_hookup(sbus->portid);
+		starfire_hookup(portid);
 
-	sysio_register_error_handlers(sbus);
+	sysio_register_error_handlers(op);
 	return;
 
 fatal_memory_error:
 	prom_printf("sbus_iommu_init: Fatal memory allocation error.\n");
 }
 
-void sbus_fill_device_irq(struct sbus_dev *sdev)
+static int __init sbus_init(void)
 {
-	struct device_node *dp = of_find_node_by_phandle(sdev->prom_node);
-	const struct linux_prom_irqs *irqs;
+	struct device_node *dp;
 
-	irqs = of_get_property(dp, "interrupts", NULL);
-	if (!irqs) {
-		sdev->irqs[0] = 0;
-		sdev->num_irqs = 0;
-	} else {
-		unsigned int pri = irqs[0].pri;
+	for_each_node_by_name(dp, "sbus") {
+		struct of_device *op = of_find_device_by_node(dp);
 
-		sdev->num_irqs = 1;
-		if (pri < 0x20)
-			pri += sdev->slot * 8;
-
-		sdev->irqs[0] =	sbus_build_irq(sdev->bus, pri);
+		sbus_iommu_init(op);
+		of_propagate_archdata(op);
 	}
-}
 
-void __init sbus_arch_bus_ranges_init(struct device_node *pn, struct sbus_bus *sbus)
-{
-}
-
-void __init sbus_setup_iommu(struct sbus_bus *sbus, struct device_node *dp)
-{
-	sbus_iommu_init(dp->node, sbus);
-}
-
-void __init sbus_setup_arch_props(struct sbus_bus *sbus, struct device_node *dp)
-{
-}
-
-int __init sbus_arch_preinit(void)
-{
 	return 0;
 }
 
-void __init sbus_arch_postinit(void)
-{
-	extern void firetruck_init(void);
-
-	firetruck_init();
-}
+subsys_initcall(sbus_init);
diff --git a/arch/sparc64/kernel/smp.c b/arch/sparc64/kernel/smp.c
index 2be166c..e562711 100644
--- a/arch/sparc64/kernel/smp.c
+++ b/arch/sparc64/kernel/smp.c
@@ -21,6 +21,7 @@
 #include <linux/jiffies.h>
 #include <linux/profile.h>
 #include <linux/lmb.h>
+#include <linux/cpu.h>
 
 #include <asm/head.h>
 #include <asm/ptrace.h>
@@ -115,6 +116,9 @@
 	atomic_inc(&init_mm.mm_count);
 	current->active_mm = &init_mm;
 
+	/* inform the notifiers about the new cpu */
+	notify_cpu_starting(cpuid);
+
 	while (!cpu_isset(cpuid, smp_commenced_mask))
 		rmb();
 
diff --git a/arch/sparc64/kernel/sparc64_ksyms.c b/arch/sparc64/kernel/sparc64_ksyms.c
index 0804f71..30bba8b 100644
--- a/arch/sparc64/kernel/sparc64_ksyms.c
+++ b/arch/sparc64/kernel/sparc64_ksyms.c
@@ -36,7 +36,6 @@
 #include <asm/elf.h>
 #include <asm/head.h>
 #include <asm/smp.h>
-#include <asm/mostek.h>
 #include <asm/ptrace.h>
 #include <asm/uaccess.h>
 #include <asm/checksum.h>
@@ -44,12 +43,8 @@
 #include <asm/pgalloc.h>
 #include <asm/cacheflush.h>
 #ifdef CONFIG_SBUS
-#include <asm/sbus.h>
 #include <asm/dma.h>
 #endif
-#ifdef CONFIG_PCI
-#include <asm/ebus.h>
-#endif
 #include <asm/ns87303.h>
 #include <asm/timer.h>
 #include <asm/cpudata.h>
@@ -68,7 +63,6 @@
 extern void *__memscan_generic(void *, int, size_t);
 extern int __memcmp(const void *, const void *, __kernel_size_t);
 extern __kernel_size_t strlen(const char *);
-extern void syscall_trace(struct pt_regs *, int);
 extern void sys_sigsuspend(void);
 extern int compat_sys_ioctl(unsigned int fd, unsigned int cmd, u32 arg);
 extern int (*handle_mathemu)(struct pt_regs *, struct fpustate *);
@@ -154,26 +148,12 @@
 EXPORT_SYMBOL(__flush_dcache_range);
 #endif
 
-EXPORT_SYMBOL(mostek_lock);
-EXPORT_SYMBOL(mstk48t02_regs);
 #ifdef CONFIG_SUN_AUXIO
 EXPORT_SYMBOL(auxio_set_led);
 EXPORT_SYMBOL(auxio_set_lte);
 #endif
 #ifdef CONFIG_SBUS
-EXPORT_SYMBOL(sbus_root);
-EXPORT_SYMBOL(dma_chain);
 EXPORT_SYMBOL(sbus_set_sbus64);
-EXPORT_SYMBOL(sbus_alloc_consistent);
-EXPORT_SYMBOL(sbus_free_consistent);
-EXPORT_SYMBOL(sbus_map_single);
-EXPORT_SYMBOL(sbus_unmap_single);
-EXPORT_SYMBOL(sbus_map_sg);
-EXPORT_SYMBOL(sbus_unmap_sg);
-EXPORT_SYMBOL(sbus_dma_sync_single_for_cpu);
-EXPORT_SYMBOL(sbus_dma_sync_single_for_device);
-EXPORT_SYMBOL(sbus_dma_sync_sg_for_cpu);
-EXPORT_SYMBOL(sbus_dma_sync_sg_for_device);
 #endif
 EXPORT_SYMBOL(outsb);
 EXPORT_SYMBOL(outsw);
@@ -182,7 +162,6 @@
 EXPORT_SYMBOL(insw);
 EXPORT_SYMBOL(insl);
 #ifdef CONFIG_PCI
-EXPORT_SYMBOL(ebus_chain);
 EXPORT_SYMBOL(pci_alloc_consistent);
 EXPORT_SYMBOL(pci_free_consistent);
 EXPORT_SYMBOL(pci_map_single);
@@ -300,3 +279,5 @@
 EXPORT_SYMBOL(xor_niagara_3);
 EXPORT_SYMBOL(xor_niagara_4);
 EXPORT_SYMBOL(xor_niagara_5);
+
+EXPORT_SYMBOL_GPL(real_hard_smp_processor_id);
diff --git a/arch/sparc64/kernel/sstate.c b/arch/sparc64/kernel/sstate.c
index 5b6e75b..8cdbe59 100644
--- a/arch/sparc64/kernel/sstate.c
+++ b/arch/sparc64/kernel/sstate.c
@@ -1,14 +1,15 @@
 /* sstate.c: System soft state support.
  *
- * Copyright (C) 2007 David S. Miller <davem@davemloft.net>
+ * Copyright (C) 2007, 2008 David S. Miller <davem@davemloft.net>
  */
 
 #include <linux/kernel.h>
 #include <linux/notifier.h>
+#include <linux/reboot.h>
 #include <linux/init.h>
 
 #include <asm/hypervisor.h>
-#include <asm/sstate.h>
+#include <asm/spitfire.h>
 #include <asm/oplib.h>
 #include <asm/head.h>
 #include <asm/io.h>
@@ -50,30 +51,33 @@
 static const char panicing_msg[32] __attribute__((aligned(32))) =
 	"Linux panicing";
 
-void sstate_booting(void)
+static int sstate_reboot_call(struct notifier_block *np, unsigned long type, void *_unused)
 {
-	do_set_sstate(HV_SOFT_STATE_TRANSITION, booting_msg);
+	const char *msg;
+
+	switch (type) {
+	case SYS_DOWN:
+	default:
+		msg = rebooting_msg;
+		break;
+
+	case SYS_HALT:
+		msg = halting_msg;
+		break;
+
+	case SYS_POWER_OFF:
+		msg = poweroff_msg;
+		break;
+	}
+
+	do_set_sstate(HV_SOFT_STATE_TRANSITION, msg);
+
+	return NOTIFY_OK;
 }
 
-void sstate_running(void)
-{
-	do_set_sstate(HV_SOFT_STATE_NORMAL, running_msg);
-}
-
-void sstate_halt(void)
-{
-	do_set_sstate(HV_SOFT_STATE_TRANSITION, halting_msg);
-}
-
-void sstate_poweroff(void)
-{
-	do_set_sstate(HV_SOFT_STATE_TRANSITION, poweroff_msg);
-}
-
-void sstate_reboot(void)
-{
-	do_set_sstate(HV_SOFT_STATE_TRANSITION, rebooting_msg);
-}
+static struct notifier_block sstate_reboot_notifier = {
+	.notifier_call = sstate_reboot_call,
+};
 
 static int sstate_panic_event(struct notifier_block *n, unsigned long event, void *ptr)
 {
@@ -87,18 +91,37 @@
 	.priority	=	INT_MAX,
 };
 
-void __init sun4v_sstate_init(void)
+static int __init sstate_init(void)
 {
 	unsigned long major, minor;
 
+	if (tlb_type != hypervisor)
+		return 0;
+
 	major = 1;
 	minor = 0;
 	if (sun4v_hvapi_register(HV_GRP_SOFT_STATE, major, &minor))
-		return;
+		return 0;
 
 	hv_supports_soft_state = 1;
 
 	prom_sun4v_guest_soft_state();
+
+	do_set_sstate(HV_SOFT_STATE_TRANSITION, booting_msg);
+
 	atomic_notifier_chain_register(&panic_notifier_list,
 				       &sstate_panic_block);
+	register_reboot_notifier(&sstate_reboot_notifier);
+
+	return 0;
 }
+
+core_initcall(sstate_init);
+
+static int __init sstate_running(void)
+{
+	do_set_sstate(HV_SOFT_STATE_NORMAL, running_msg);
+	return 0;
+}
+
+late_initcall(sstate_running);
diff --git a/arch/sparc64/kernel/starfire.c b/arch/sparc64/kernel/starfire.c
index 7461581..060d0f3 100644
--- a/arch/sparc64/kernel/starfire.c
+++ b/arch/sparc64/kernel/starfire.c
@@ -28,11 +28,6 @@
 		this_is_starfire = 1;
 }
 
-void starfire_cpu_setup(void)
-{
-	/* Currently, nothing to do.  */
-}
-
 int starfire_hard_smp_processor_id(void)
 {
 	return upa_readl(0x1fff40000d0UL);
diff --git a/arch/sparc64/kernel/sys_sparc32.c b/arch/sparc64/kernel/sys_sparc32.c
index 3d11853..3320c9d 100644
--- a/arch/sparc64/kernel/sys_sparc32.c
+++ b/arch/sparc64/kernel/sys_sparc32.c
@@ -575,14 +575,6 @@
 	return do_sys_settimeofday(tv ? &kts : NULL, tz ? &ktz : NULL);
 }
 
-/* These are here just in case some old sparc32 binary calls it. */
-asmlinkage long sys32_pause(void)
-{
-	current->state = TASK_INTERRUPTIBLE;
-	schedule();
-	return -ERESTARTNOHAND;
-}
-
 asmlinkage compat_ssize_t sys32_pread64(unsigned int fd,
 					char __user *ubuf,
 					compat_size_t count,
diff --git a/arch/sparc64/kernel/syscalls.S b/arch/sparc64/kernel/syscalls.S
index a2f2427..7a6786a 100644
--- a/arch/sparc64/kernel/syscalls.S
+++ b/arch/sparc64/kernel/syscalls.S
@@ -65,9 +65,8 @@
 	andcc	%l5, (_TIF_SYSCALL_TRACE|_TIF_SECCOMP|_TIF_SYSCALL_AUDIT), %g0
 	be,pt	%icc, rtrap
 	 nop
-	add	%sp, PTREGS_OFF, %o0
-	call	syscall_trace
-	 mov	1, %o1
+	call	syscall_trace_leave
+	 add	%sp, PTREGS_OFF, %o0
 	ba,pt	%xcc, rtrap
 	 nop
 
@@ -159,9 +158,8 @@
 	 or	%l7, %lo(sys_ni_syscall), %l7
 
 linux_syscall_trace32:
-	add	%sp, PTREGS_OFF, %o0
-	call	syscall_trace
-	 clr	%o1
+	call	syscall_trace_enter
+	 add	%sp, PTREGS_OFF, %o0
 	brnz,pn	%o0, 3f
 	 mov	-ENOSYS, %o0
 	srl	%i0, 0, %o0
@@ -172,9 +170,8 @@
 	 srl	%i3, 0, %o3
 
 linux_syscall_trace:
-	add	%sp, PTREGS_OFF, %o0
-	call	syscall_trace
-	 clr	%o1
+	call	syscall_trace_enter
+	 add	%sp, PTREGS_OFF, %o0
 	brnz,pn	%o0, 3f
 	 mov	-ENOSYS, %o0
 	mov	%i0, %o0
@@ -275,9 +272,8 @@
 	b,pt	%xcc, rtrap
 	 stx	%l2, [%sp + PTREGS_OFF + PT_V9_TNPC]
 linux_syscall_trace2:
-	add	%sp, PTREGS_OFF, %o0
-	call	syscall_trace
-	 mov	1, %o1
+	call	syscall_trace_leave
+	 add	%sp, PTREGS_OFF, %o0
 	stx	%l1, [%sp + PTREGS_OFF + PT_V9_TPC]
 	ba,pt	%xcc, rtrap
 	 stx	%l2, [%sp + PTREGS_OFF + PT_V9_TNPC]
diff --git a/arch/sparc64/kernel/systbls.S b/arch/sparc64/kernel/systbls.S
index 0fdbf3b..5daee4b 100644
--- a/arch/sparc64/kernel/systbls.S
+++ b/arch/sparc64/kernel/systbls.S
@@ -23,7 +23,7 @@
 /*10*/  .word sys_unlink, sunos_execv, sys_chdir, sys_chown16, sys32_mknod
 /*15*/	.word sys_chmod, sys_lchown16, sparc_brk, sys32_perfctr, sys32_lseek
 /*20*/	.word sys_getpid, sys_capget, sys_capset, sys_setuid16, sys_getuid16
-/*25*/	.word sys32_vmsplice, compat_sys_ptrace, sys_alarm, sys32_sigaltstack, sys32_pause
+/*25*/	.word sys32_vmsplice, compat_sys_ptrace, sys_alarm, sys32_sigaltstack, sys_pause
 /*30*/	.word compat_sys_utime, sys_lchown, sys_fchown, sys32_access, sys32_nice
 	.word sys_chown, sys_sync, sys32_kill, compat_sys_newstat, sys32_sendfile
 /*40*/	.word compat_sys_newlstat, sys_dup, sys_pipe, compat_sys_times, sys_getuid
diff --git a/arch/sparc64/kernel/time.c b/arch/sparc64/kernel/time.c
index cc16fdc..80d71a5 100644
--- a/arch/sparc64/kernel/time.c
+++ b/arch/sparc64/kernel/time.c
@@ -30,13 +30,14 @@
 #include <linux/percpu.h>
 #include <linux/miscdevice.h>
 #include <linux/rtc.h>
+#include <linux/rtc/m48t59.h>
 #include <linux/kernel_stat.h>
 #include <linux/clockchips.h>
 #include <linux/clocksource.h>
 #include <linux/of_device.h>
+#include <linux/platform_device.h>
 
 #include <asm/oplib.h>
-#include <asm/mostek.h>
 #include <asm/timer.h>
 #include <asm/irq.h>
 #include <asm/io.h>
@@ -50,18 +51,7 @@
 
 #include "entry.h"
 
-DEFINE_SPINLOCK(mostek_lock);
 DEFINE_SPINLOCK(rtc_lock);
-void __iomem *mstk48t02_regs = NULL;
-#ifdef CONFIG_PCI
-unsigned long ds1287_regs = 0UL;
-static void __iomem *bq4802_regs;
-#endif
-
-static void __iomem *mstk48t08_regs;
-static void __iomem *mstk48t59_regs;
-
-static int set_rtc_mmss(unsigned long);
 
 #define TICK_PRIV_BIT	(1UL << 63)
 #define TICKCMP_IRQ_BIT	(1UL << 63)
@@ -405,313 +395,167 @@
 
 int update_persistent_clock(struct timespec now)
 {
-	return set_rtc_mmss(now.tv_sec);
-}
+	struct rtc_device *rtc = rtc_class_open("rtc0");
+	int err = -1;
 
-/* Kick start a stopped clock (procedure from the Sun NVRAM/hostid FAQ). */
-static void __init kick_start_clock(void)
-{
-	void __iomem *regs = mstk48t02_regs;
-	u8 sec, tmp;
-	int i, count;
-
-	prom_printf("CLOCK: Clock was stopped. Kick start ");
-
-	spin_lock_irq(&mostek_lock);
-
-	/* Turn on the kick start bit to start the oscillator. */
-	tmp = mostek_read(regs + MOSTEK_CREG);
-	tmp |= MSTK_CREG_WRITE;
-	mostek_write(regs + MOSTEK_CREG, tmp);
-	tmp = mostek_read(regs + MOSTEK_SEC);
-	tmp &= ~MSTK_STOP;
-	mostek_write(regs + MOSTEK_SEC, tmp);
-	tmp = mostek_read(regs + MOSTEK_HOUR);
-	tmp |= MSTK_KICK_START;
-	mostek_write(regs + MOSTEK_HOUR, tmp);
-	tmp = mostek_read(regs + MOSTEK_CREG);
-	tmp &= ~MSTK_CREG_WRITE;
-	mostek_write(regs + MOSTEK_CREG, tmp);
-
-	spin_unlock_irq(&mostek_lock);
-
-	/* Delay to allow the clock oscillator to start. */
-	sec = MSTK_REG_SEC(regs);
-	for (i = 0; i < 3; i++) {
-		while (sec == MSTK_REG_SEC(regs))
-			for (count = 0; count < 100000; count++)
-				/* nothing */ ;
-		prom_printf(".");
-		sec = MSTK_REG_SEC(regs);
-	}
-	prom_printf("\n");
-
-	spin_lock_irq(&mostek_lock);
-
-	/* Turn off kick start and set a "valid" time and date. */
-	tmp = mostek_read(regs + MOSTEK_CREG);
-	tmp |= MSTK_CREG_WRITE;
-	mostek_write(regs + MOSTEK_CREG, tmp);
-	tmp = mostek_read(regs + MOSTEK_HOUR);
-	tmp &= ~MSTK_KICK_START;
-	mostek_write(regs + MOSTEK_HOUR, tmp);
-	MSTK_SET_REG_SEC(regs,0);
-	MSTK_SET_REG_MIN(regs,0);
-	MSTK_SET_REG_HOUR(regs,0);
-	MSTK_SET_REG_DOW(regs,5);
-	MSTK_SET_REG_DOM(regs,1);
-	MSTK_SET_REG_MONTH(regs,8);
-	MSTK_SET_REG_YEAR(regs,1996 - MSTK_YEAR_ZERO);
-	tmp = mostek_read(regs + MOSTEK_CREG);
-	tmp &= ~MSTK_CREG_WRITE;
-	mostek_write(regs + MOSTEK_CREG, tmp);
-
-	spin_unlock_irq(&mostek_lock);
-
-	/* Ensure the kick start bit is off. If it isn't, turn it off. */
-	while (mostek_read(regs + MOSTEK_HOUR) & MSTK_KICK_START) {
-		prom_printf("CLOCK: Kick start still on!\n");
-
-		spin_lock_irq(&mostek_lock);
-
-		tmp = mostek_read(regs + MOSTEK_CREG);
-		tmp |= MSTK_CREG_WRITE;
-		mostek_write(regs + MOSTEK_CREG, tmp);
-
-		tmp = mostek_read(regs + MOSTEK_HOUR);
-		tmp &= ~MSTK_KICK_START;
-		mostek_write(regs + MOSTEK_HOUR, tmp);
-
-		tmp = mostek_read(regs + MOSTEK_CREG);
-		tmp &= ~MSTK_CREG_WRITE;
-		mostek_write(regs + MOSTEK_CREG, tmp);
-
-		spin_unlock_irq(&mostek_lock);
+	if (rtc) {
+		err = rtc_set_mmss(rtc, now.tv_sec);
+		rtc_class_close(rtc);
 	}
 
-	prom_printf("CLOCK: Kick start procedure successful.\n");
+	return err;
 }
 
-/* Return nonzero if the clock chip battery is low. */
-static int __init has_low_battery(void)
+unsigned long cmos_regs;
+EXPORT_SYMBOL(cmos_regs);
+
+static struct resource rtc_cmos_resource;
+
+static struct platform_device rtc_cmos_device = {
+	.name		= "rtc_cmos",
+	.id		= -1,
+	.resource	= &rtc_cmos_resource,
+	.num_resources	= 1,
+};
+
+static int __devinit rtc_probe(struct of_device *op, const struct of_device_id *match)
 {
-	void __iomem *regs = mstk48t02_regs;
-	u8 data1, data2;
+	struct resource *r;
 
-	spin_lock_irq(&mostek_lock);
+	printk(KERN_INFO "%s: RTC regs at 0x%lx\n",
+	       op->node->full_name, op->resource[0].start);
 
-	data1 = mostek_read(regs + MOSTEK_EEPROM);	/* Read some data. */
-	mostek_write(regs + MOSTEK_EEPROM, ~data1);	/* Write back the complement. */
-	data2 = mostek_read(regs + MOSTEK_EEPROM);	/* Read back the complement. */
-	mostek_write(regs + MOSTEK_EEPROM, data1);	/* Restore original value. */
-
-	spin_unlock_irq(&mostek_lock);
-
-	return (data1 == data2);	/* Was the write blocked? */
-}
-
-static void __init mostek_set_system_time(void __iomem *mregs)
-{
-	unsigned int year, mon, day, hour, min, sec;
-	u8 tmp;
-
-	spin_lock_irq(&mostek_lock);
-
-	/* Traditional Mostek chip. */
-	tmp = mostek_read(mregs + MOSTEK_CREG);
-	tmp |= MSTK_CREG_READ;
-	mostek_write(mregs + MOSTEK_CREG, tmp);
-
-	sec = MSTK_REG_SEC(mregs);
-	min = MSTK_REG_MIN(mregs);
-	hour = MSTK_REG_HOUR(mregs);
-	day = MSTK_REG_DOM(mregs);
-	mon = MSTK_REG_MONTH(mregs);
-	year = MSTK_CVT_YEAR( MSTK_REG_YEAR(mregs) );
-
-	xtime.tv_sec = mktime(year, mon, day, hour, min, sec);
-	xtime.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ);
-	set_normalized_timespec(&wall_to_monotonic,
- 	                        -xtime.tv_sec, -xtime.tv_nsec);
-
-	tmp = mostek_read(mregs + MOSTEK_CREG);
-	tmp &= ~MSTK_CREG_READ;
-	mostek_write(mregs + MOSTEK_CREG, tmp);
-
-	spin_unlock_irq(&mostek_lock);
-}
-
-/* Probe for the real time clock chip. */
-static void __init set_system_time(void)
-{
-	unsigned int year, mon, day, hour, min, sec;
-	void __iomem *mregs = mstk48t02_regs;
-#ifdef CONFIG_PCI
-	unsigned long dregs = ds1287_regs;
-	void __iomem *bregs = bq4802_regs;
-#else
-	unsigned long dregs = 0UL;
-	void __iomem *bregs = 0UL;
-#endif
-
-	if (!mregs && !dregs && !bregs) {
-		prom_printf("Something wrong, clock regs not mapped yet.\n");
-		prom_halt();
-	}		
-
-	if (mregs) {
-		mostek_set_system_time(mregs);
-		return;
-	}
-
-	if (bregs) {
-		unsigned char val = readb(bregs + 0x0e);
-		unsigned int century;
-
-		/* BQ4802 RTC chip. */
-
-		writeb(val | 0x08, bregs + 0x0e);
-
-		sec  = readb(bregs + 0x00);
-		min  = readb(bregs + 0x02);
-		hour = readb(bregs + 0x04);
-		day  = readb(bregs + 0x06);
-		mon  = readb(bregs + 0x09);
-		year = readb(bregs + 0x0a);
-		century = readb(bregs + 0x0f);
-
-		writeb(val, bregs + 0x0e);
-
-		BCD_TO_BIN(sec);
-		BCD_TO_BIN(min);
-		BCD_TO_BIN(hour);
-		BCD_TO_BIN(day);
-		BCD_TO_BIN(mon);
-		BCD_TO_BIN(year);
-		BCD_TO_BIN(century);
-
-		year += (century * 100);
-	} else {
-		/* Dallas 12887 RTC chip. */
-
-		do {
-			sec  = CMOS_READ(RTC_SECONDS);
-			min  = CMOS_READ(RTC_MINUTES);
-			hour = CMOS_READ(RTC_HOURS);
-			day  = CMOS_READ(RTC_DAY_OF_MONTH);
-			mon  = CMOS_READ(RTC_MONTH);
-			year = CMOS_READ(RTC_YEAR);
-		} while (sec != CMOS_READ(RTC_SECONDS));
-
-		if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
-			BCD_TO_BIN(sec);
-			BCD_TO_BIN(min);
-			BCD_TO_BIN(hour);
-			BCD_TO_BIN(day);
-			BCD_TO_BIN(mon);
-			BCD_TO_BIN(year);
-		}
-		if ((year += 1900) < 1970)
-			year += 100;
-	}
-
-	xtime.tv_sec = mktime(year, mon, day, hour, min, sec);
-	xtime.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ);
-	set_normalized_timespec(&wall_to_monotonic,
- 	                        -xtime.tv_sec, -xtime.tv_nsec);
-}
-
-/* davem suggests we keep this within the 4M locked kernel image */
-static u32 starfire_get_time(void)
-{
-	static char obp_gettod[32];
-	static u32 unix_tod;
-
-	sprintf(obp_gettod, "h# %08x unix-gettod",
-		(unsigned int) (long) &unix_tod);
-	prom_feval(obp_gettod);
-
-	return unix_tod;
-}
-
-static int starfire_set_time(u32 val)
-{
-	/* Do nothing, time is set using the service processor
-	 * console on this platform.
+	/* The CMOS RTC driver only accepts IORESOURCE_IO, so cons
+	 * up a fake resource so that the probe works for all cases.
+	 * When the RTC is behind an ISA bus it will have IORESOURCE_IO
+	 * already, whereas when it's behind EBUS is will be IORESOURCE_MEM.
 	 */
-	return 0;
+
+	r = &rtc_cmos_resource;
+	r->flags = IORESOURCE_IO;
+	r->name = op->resource[0].name;
+	r->start = op->resource[0].start;
+	r->end = op->resource[0].end;
+
+	cmos_regs = op->resource[0].start;
+	return platform_device_register(&rtc_cmos_device);
 }
 
-static u32 hypervisor_get_time(void)
-{
-	unsigned long ret, time;
-	int retries = 10000;
+static struct of_device_id __initdata rtc_match[] = {
+	{
+		.name = "rtc",
+		.compatible = "m5819",
+	},
+	{
+		.name = "rtc",
+		.compatible = "isa-m5819p",
+	},
+	{
+		.name = "rtc",
+		.compatible = "isa-m5823p",
+	},
+	{
+		.name = "rtc",
+		.compatible = "ds1287",
+	},
+	{},
+};
 
-retry:
-	ret = sun4v_tod_get(&time);
-	if (ret == HV_EOK)
-		return time;
-	if (ret == HV_EWOULDBLOCK) {
-		if (--retries > 0) {
-			udelay(100);
-			goto retry;
-		}
-		printk(KERN_WARNING "SUN4V: tod_get() timed out.\n");
-		return 0;
+static struct of_platform_driver rtc_driver = {
+	.match_table	= rtc_match,
+	.probe		= rtc_probe,
+	.driver		= {
+		.name	= "rtc",
+	},
+};
+
+static struct platform_device rtc_bq4802_device = {
+	.name		= "rtc-bq4802",
+	.id		= -1,
+	.num_resources	= 1,
+};
+
+static int __devinit bq4802_probe(struct of_device *op, const struct of_device_id *match)
+{
+
+	printk(KERN_INFO "%s: BQ4802 regs at 0x%lx\n",
+	       op->node->full_name, op->resource[0].start);
+
+	rtc_bq4802_device.resource = &op->resource[0];
+	return platform_device_register(&rtc_bq4802_device);
+}
+
+static struct of_device_id __initdata bq4802_match[] = {
+	{
+		.name = "rtc",
+		.compatible = "bq4802",
+	},
+};
+
+static struct of_platform_driver bq4802_driver = {
+	.match_table	= bq4802_match,
+	.probe		= bq4802_probe,
+	.driver		= {
+		.name	= "bq4802",
+	},
+};
+
+static unsigned char mostek_read_byte(struct device *dev, u32 ofs)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct m48t59_plat_data *pdata = pdev->dev.platform_data;
+	void __iomem *regs;
+	unsigned char val;
+
+	regs = (void __iomem *) pdev->resource[0].start;
+	val = readb(regs + ofs);
+
+	/* the year 0 is 1968 */
+	if (ofs == pdata->offset + M48T59_YEAR) {
+		val += 0x68;
+		if ((val & 0xf) > 9)
+			val += 6;
 	}
-	printk(KERN_WARNING "SUN4V: tod_get() not supported.\n");
-	return 0;
+	return val;
 }
 
-static int hypervisor_set_time(u32 secs)
+static void mostek_write_byte(struct device *dev, u32 ofs, u8 val)
 {
-	unsigned long ret;
-	int retries = 10000;
-
-retry:
-	ret = sun4v_tod_set(secs);
-	if (ret == HV_EOK)
-		return 0;
-	if (ret == HV_EWOULDBLOCK) {
-		if (--retries > 0) {
-			udelay(100);
-			goto retry;
-		}
-		printk(KERN_WARNING "SUN4V: tod_set() timed out.\n");
-		return -EAGAIN;
-	}
-	printk(KERN_WARNING "SUN4V: tod_set() not supported.\n");
-	return -EOPNOTSUPP;
-}
-
-static int __init clock_model_matches(const char *model)
-{
-	if (strcmp(model, "mk48t02") &&
-	    strcmp(model, "mk48t08") &&
-	    strcmp(model, "mk48t59") &&
-	    strcmp(model, "m5819") &&
-	    strcmp(model, "m5819p") &&
-	    strcmp(model, "m5823") &&
-	    strcmp(model, "ds1287") &&
-	    strcmp(model, "bq4802"))
-		return 0;
-
-	return 1;
-}
-
-static int __devinit clock_probe(struct of_device *op, const struct of_device_id *match)
-{
-	struct device_node *dp = op->node;
-	const char *model = of_get_property(dp, "model", NULL);
-	const char *compat = of_get_property(dp, "compatible", NULL);
-	unsigned long size, flags;
+	struct platform_device *pdev = to_platform_device(dev);
+	struct m48t59_plat_data *pdata = pdev->dev.platform_data;
 	void __iomem *regs;
 
-	if (!model)
-		model = compat;
+	regs = (void __iomem *) pdev->resource[0].start;
+	if (ofs == pdata->offset + M48T59_YEAR) {
+		if (val < 0x68)
+			val += 0x32;
+		else
+			val -= 0x68;
+		if ((val & 0xf) > 9)
+			val += 6;
+		if ((val & 0xf0) > 0x9A)
+			val += 0x60;
+	}
+	writeb(val, regs + ofs);
+}
 
-	if (!model || !clock_model_matches(model))
-		return -ENODEV;
+static struct m48t59_plat_data m48t59_data = {
+	.read_byte	= mostek_read_byte,
+	.write_byte	= mostek_write_byte,
+};
+
+static struct platform_device m48t59_rtc = {
+	.name		= "rtc-m48t59",
+	.id		= 0,
+	.num_resources	= 1,
+	.dev	= {
+		.platform_data = &m48t59_data,
+	},
+};
+
+static int __devinit mostek_probe(struct of_device *op, const struct of_device_id *match)
+{
+	struct device_node *dp = op->node;
 
 	/* On an Enterprise system there can be multiple mostek clocks.
 	 * We should only match the one that is on the central FHC bus.
@@ -720,88 +564,51 @@
 	    strcmp(dp->parent->parent->name, "central") != 0)
 		return -ENODEV;
 
-	size = (op->resource[0].end - op->resource[0].start) + 1;
-	regs = of_ioremap(&op->resource[0], 0, size, "clock");
-	if (!regs)
-		return -ENOMEM;
+	printk(KERN_INFO "%s: Mostek regs at 0x%lx\n",
+	       dp->full_name, op->resource[0].start);
 
-#ifdef CONFIG_PCI
-	if (!strcmp(model, "ds1287") ||
-	    !strcmp(model, "m5819") ||
-	    !strcmp(model, "m5819p") ||
-	    !strcmp(model, "m5823")) {
-		ds1287_regs = (unsigned long) regs;
-	} else if (!strcmp(model, "bq4802")) {
-		bq4802_regs = regs;
-	} else
-#endif
-	if (model[5] == '0' && model[6] == '2') {
-		mstk48t02_regs = regs;
-	} else if(model[5] == '0' && model[6] == '8') {
-		mstk48t08_regs = regs;
-		mstk48t02_regs = mstk48t08_regs + MOSTEK_48T08_48T02;
-	} else {
-		mstk48t59_regs = regs;
-		mstk48t02_regs = mstk48t59_regs + MOSTEK_48T59_48T02;
-	}
-
-	printk(KERN_INFO "%s: Clock regs at %p\n", dp->full_name, regs);
-
-	local_irq_save(flags);
-
-	if (mstk48t02_regs != NULL) {
-		/* Report a low battery voltage condition. */
-		if (has_low_battery())
-			prom_printf("NVRAM: Low battery voltage!\n");
-
-		/* Kick start the clock if it is completely stopped. */
-		if (mostek_read(mstk48t02_regs + MOSTEK_SEC) & MSTK_STOP)
-			kick_start_clock();
-	}
-
-	set_system_time();
-	
-	local_irq_restore(flags);
-
-	return 0;
+	m48t59_rtc.resource = &op->resource[0];
+	return platform_device_register(&m48t59_rtc);
 }
 
-static struct of_device_id clock_match[] = {
+static struct of_device_id __initdata mostek_match[] = {
 	{
 		.name = "eeprom",
 	},
-	{
-		.name = "rtc",
-	},
 	{},
 };
 
-static struct of_platform_driver clock_driver = {
-	.match_table	= clock_match,
-	.probe		= clock_probe,
+static struct of_platform_driver mostek_driver = {
+	.match_table	= mostek_match,
+	.probe		= mostek_probe,
 	.driver		= {
-		.name	= "clock",
+		.name	= "mostek",
 	},
 };
 
+static struct platform_device rtc_sun4v_device = {
+	.name		= "rtc-sun4v",
+	.id		= -1,
+};
+
+static struct platform_device rtc_starfire_device = {
+	.name		= "rtc-starfire",
+	.id		= -1,
+};
+
 static int __init clock_init(void)
 {
-	if (this_is_starfire) {
-		xtime.tv_sec = starfire_get_time();
-		xtime.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ);
-		set_normalized_timespec(&wall_to_monotonic,
-		                        -xtime.tv_sec, -xtime.tv_nsec);
-		return 0;
-	}
-	if (tlb_type == hypervisor) {
-		xtime.tv_sec = hypervisor_get_time();
-		xtime.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ);
-		set_normalized_timespec(&wall_to_monotonic,
-		                        -xtime.tv_sec, -xtime.tv_nsec);
-		return 0;
-	}
+	if (this_is_starfire)
+		return platform_device_register(&rtc_starfire_device);
 
-	return of_register_driver(&clock_driver, &of_platform_bus_type);
+	if (tlb_type == hypervisor)
+		return platform_device_register(&rtc_sun4v_device);
+
+	(void) of_register_driver(&rtc_driver, &of_platform_bus_type);
+	(void) of_register_driver(&mostek_driver, &of_platform_bus_type);
+	(void) of_register_driver(&bq4802_driver, &of_platform_bus_type);
+
+	return 0;
 }
 
 /* Must be after subsys_initcall() so that busses are probed.  Must
@@ -814,7 +621,7 @@
 static unsigned long sparc64_init_timers(void)
 {
 	struct device_node *dp;
-	unsigned long clock;
+	unsigned long freq;
 
 	dp = of_find_node_by_path("/");
 	if (tlb_type == spitfire) {
@@ -827,17 +634,17 @@
 		if (manuf == 0x17 && impl == 0x13) {
 			/* Hummingbird, aka Ultra-IIe */
 			tick_ops = &hbtick_operations;
-			clock = of_getintprop_default(dp, "stick-frequency", 0);
+			freq = of_getintprop_default(dp, "stick-frequency", 0);
 		} else {
 			tick_ops = &tick_operations;
-			clock = local_cpu_data().clock_tick;
+			freq = local_cpu_data().clock_tick;
 		}
 	} else {
 		tick_ops = &stick_operations;
-		clock = of_getintprop_default(dp, "stick-frequency", 0);
+		freq = of_getintprop_default(dp, "stick-frequency", 0);
 	}
 
-	return clock;
+	return freq;
 }
 
 struct freq_table {
@@ -1029,16 +836,16 @@
 
 void __init time_init(void)
 {
-	unsigned long clock = sparc64_init_timers();
+	unsigned long freq = sparc64_init_timers();
 
-	tb_ticks_per_usec = clock / USEC_PER_SEC;
+	tb_ticks_per_usec = freq / USEC_PER_SEC;
 
 	timer_ticks_per_nsec_quotient =
-		clocksource_hz2mult(clock, SPARC64_NSEC_PER_CYC_SHIFT);
+		clocksource_hz2mult(freq, SPARC64_NSEC_PER_CYC_SHIFT);
 
 	clocksource_tick.name = tick_ops->name;
 	clocksource_tick.mult =
-		clocksource_hz2mult(clock,
+		clocksource_hz2mult(freq,
 				    clocksource_tick.shift);
 	clocksource_tick.read = tick_ops->get_tick;
 
@@ -1049,7 +856,7 @@
 
 	sparc64_clockevent.name = tick_ops->name;
 
-	setup_clockevent_multiplier(clock);
+	setup_clockevent_multiplier(freq);
 
 	sparc64_clockevent.max_delta_ns =
 		clockevent_delta2ns(0x7fffffffffffffffUL, &sparc64_clockevent);
@@ -1070,672 +877,8 @@
 		>> SPARC64_NSEC_PER_CYC_SHIFT;
 }
 
-static int set_rtc_mmss(unsigned long nowtime)
-{
-	int real_seconds, real_minutes, chip_minutes;
-	void __iomem *mregs = mstk48t02_regs;
-#ifdef CONFIG_PCI
-	unsigned long dregs = ds1287_regs;
-	void __iomem *bregs = bq4802_regs;
-#else
-	unsigned long dregs = 0UL;
-	void __iomem *bregs = 0UL;
-#endif
-	unsigned long flags;
-	u8 tmp;
-
-	/* 
-	 * Not having a register set can lead to trouble.
-	 * Also starfire doesn't have a tod clock.
-	 */
-	if (!mregs && !dregs && !bregs)
-		return -1;
-
-	if (mregs) {
-		spin_lock_irqsave(&mostek_lock, flags);
-
-		/* Read the current RTC minutes. */
-		tmp = mostek_read(mregs + MOSTEK_CREG);
-		tmp |= MSTK_CREG_READ;
-		mostek_write(mregs + MOSTEK_CREG, tmp);
-
-		chip_minutes = MSTK_REG_MIN(mregs);
-
-		tmp = mostek_read(mregs + MOSTEK_CREG);
-		tmp &= ~MSTK_CREG_READ;
-		mostek_write(mregs + MOSTEK_CREG, tmp);
-
-		/*
-		 * since we're only adjusting minutes and seconds,
-		 * don't interfere with hour overflow. This avoids
-		 * messing with unknown time zones but requires your
-		 * RTC not to be off by more than 15 minutes
-		 */
-		real_seconds = nowtime % 60;
-		real_minutes = nowtime / 60;
-		if (((abs(real_minutes - chip_minutes) + 15)/30) & 1)
-			real_minutes += 30;	/* correct for half hour time zone */
-		real_minutes %= 60;
-
-		if (abs(real_minutes - chip_minutes) < 30) {
-			tmp = mostek_read(mregs + MOSTEK_CREG);
-			tmp |= MSTK_CREG_WRITE;
-			mostek_write(mregs + MOSTEK_CREG, tmp);
-
-			MSTK_SET_REG_SEC(mregs,real_seconds);
-			MSTK_SET_REG_MIN(mregs,real_minutes);
-
-			tmp = mostek_read(mregs + MOSTEK_CREG);
-			tmp &= ~MSTK_CREG_WRITE;
-			mostek_write(mregs + MOSTEK_CREG, tmp);
-
-			spin_unlock_irqrestore(&mostek_lock, flags);
-
-			return 0;
-		} else {
-			spin_unlock_irqrestore(&mostek_lock, flags);
-
-			return -1;
-		}
-	} else if (bregs) {
-		int retval = 0;
-		unsigned char val = readb(bregs + 0x0e);
-
-		/* BQ4802 RTC chip. */
-
-		writeb(val | 0x08, bregs + 0x0e);
-
-		chip_minutes = readb(bregs + 0x02);
-		BCD_TO_BIN(chip_minutes);
-		real_seconds = nowtime % 60;
-		real_minutes = nowtime / 60;
-		if (((abs(real_minutes - chip_minutes) + 15)/30) & 1)
-			real_minutes += 30;
-		real_minutes %= 60;
-
-		if (abs(real_minutes - chip_minutes) < 30) {
-			BIN_TO_BCD(real_seconds);
-			BIN_TO_BCD(real_minutes);
-			writeb(real_seconds, bregs + 0x00);
-			writeb(real_minutes, bregs + 0x02);
-		} else {
-			printk(KERN_WARNING
-			       "set_rtc_mmss: can't update from %d to %d\n",
-			       chip_minutes, real_minutes);
-			retval = -1;
-		}
-
-		writeb(val, bregs + 0x0e);
-
-		return retval;
-	} else {
-		int retval = 0;
-		unsigned char save_control, save_freq_select;
-
-		/* Stolen from arch/i386/kernel/time.c, see there for
-		 * credits and descriptive comments.
-		 */
-		spin_lock_irqsave(&rtc_lock, flags);
-		save_control = CMOS_READ(RTC_CONTROL); /* tell the clock it's being set */
-		CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL);
-
-		save_freq_select = CMOS_READ(RTC_FREQ_SELECT); /* stop and reset prescaler */
-		CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT);
-
-		chip_minutes = CMOS_READ(RTC_MINUTES);
-		if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
-			BCD_TO_BIN(chip_minutes);
-		real_seconds = nowtime % 60;
-		real_minutes = nowtime / 60;
-		if (((abs(real_minutes - chip_minutes) + 15)/30) & 1)
-			real_minutes += 30;
-		real_minutes %= 60;
-
-		if (abs(real_minutes - chip_minutes) < 30) {
-			if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
-				BIN_TO_BCD(real_seconds);
-				BIN_TO_BCD(real_minutes);
-			}
-			CMOS_WRITE(real_seconds,RTC_SECONDS);
-			CMOS_WRITE(real_minutes,RTC_MINUTES);
-		} else {
-			printk(KERN_WARNING
-			       "set_rtc_mmss: can't update from %d to %d\n",
-			       chip_minutes, real_minutes);
-			retval = -1;
-		}
-
-		CMOS_WRITE(save_control, RTC_CONTROL);
-		CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT);
-		spin_unlock_irqrestore(&rtc_lock, flags);
-
-		return retval;
-	}
-}
-
-#define RTC_IS_OPEN		0x01	/* means /dev/rtc is in use	*/
-static unsigned char mini_rtc_status;	/* bitmapped status byte.	*/
-
-#define FEBRUARY	2
-#define	STARTOFTIME	1970
-#define SECDAY		86400L
-#define SECYR		(SECDAY * 365)
-#define	leapyear(year)		((year) % 4 == 0 && \
-				 ((year) % 100 != 0 || (year) % 400 == 0))
-#define	days_in_year(a) 	(leapyear(a) ? 366 : 365)
-#define	days_in_month(a) 	(month_days[(a) - 1])
-
-static int month_days[12] = {
-	31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
-};
-
-/*
- * This only works for the Gregorian calendar - i.e. after 1752 (in the UK)
- */
-static void GregorianDay(struct rtc_time * tm)
-{
-	int leapsToDate;
-	int lastYear;
-	int day;
-	int MonthOffset[] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
-
-	lastYear = tm->tm_year - 1;
-
-	/*
-	 * Number of leap corrections to apply up to end of last year
-	 */
-	leapsToDate = lastYear / 4 - lastYear / 100 + lastYear / 400;
-
-	/*
-	 * This year is a leap year if it is divisible by 4 except when it is
-	 * divisible by 100 unless it is divisible by 400
-	 *
-	 * e.g. 1904 was a leap year, 1900 was not, 1996 is, and 2000 was
-	 */
-	day = tm->tm_mon > 2 && leapyear(tm->tm_year);
-
-	day += lastYear*365 + leapsToDate + MonthOffset[tm->tm_mon-1] +
-		   tm->tm_mday;
-
-	tm->tm_wday = day % 7;
-}
-
-static void to_tm(int tim, struct rtc_time *tm)
-{
-	register int    i;
-	register long   hms, day;
-
-	day = tim / SECDAY;
-	hms = tim % SECDAY;
-
-	/* Hours, minutes, seconds are easy */
-	tm->tm_hour = hms / 3600;
-	tm->tm_min = (hms % 3600) / 60;
-	tm->tm_sec = (hms % 3600) % 60;
-
-	/* Number of years in days */
-	for (i = STARTOFTIME; day >= days_in_year(i); i++)
-		day -= days_in_year(i);
-	tm->tm_year = i;
-
-	/* Number of months in days left */
-	if (leapyear(tm->tm_year))
-		days_in_month(FEBRUARY) = 29;
-	for (i = 1; day >= days_in_month(i); i++)
-		day -= days_in_month(i);
-	days_in_month(FEBRUARY) = 28;
-	tm->tm_mon = i;
-
-	/* Days are what is left over (+1) from all that. */
-	tm->tm_mday = day + 1;
-
-	/*
-	 * Determine the day of week
-	 */
-	GregorianDay(tm);
-}
-
-/* Both Starfire and SUN4V give us seconds since Jan 1st, 1970,
- * aka Unix time.  So we have to convert to/from rtc_time.
- */
-static void starfire_get_rtc_time(struct rtc_time *time)
-{
-	u32 seconds = starfire_get_time();
-
-	to_tm(seconds, time);
-	time->tm_year -= 1900;
-	time->tm_mon -= 1;
-}
-
-static int starfire_set_rtc_time(struct rtc_time *time)
-{
-	u32 seconds = mktime(time->tm_year + 1900, time->tm_mon + 1,
-			     time->tm_mday, time->tm_hour,
-			     time->tm_min, time->tm_sec);
-
-	return starfire_set_time(seconds);
-}
-
-static void hypervisor_get_rtc_time(struct rtc_time *time)
-{
-	u32 seconds = hypervisor_get_time();
-
-	to_tm(seconds, time);
-	time->tm_year -= 1900;
-	time->tm_mon -= 1;
-}
-
-static int hypervisor_set_rtc_time(struct rtc_time *time)
-{
-	u32 seconds = mktime(time->tm_year + 1900, time->tm_mon + 1,
-			     time->tm_mday, time->tm_hour,
-			     time->tm_min, time->tm_sec);
-
-	return hypervisor_set_time(seconds);
-}
-
-#ifdef CONFIG_PCI
-static void bq4802_get_rtc_time(struct rtc_time *time)
-{
-	unsigned char val = readb(bq4802_regs + 0x0e);
-	unsigned int century;
-
-	writeb(val | 0x08, bq4802_regs + 0x0e);
-
-	time->tm_sec = readb(bq4802_regs + 0x00);
-	time->tm_min = readb(bq4802_regs + 0x02);
-	time->tm_hour = readb(bq4802_regs + 0x04);
-	time->tm_mday = readb(bq4802_regs + 0x06);
-	time->tm_mon = readb(bq4802_regs + 0x09);
-	time->tm_year = readb(bq4802_regs + 0x0a);
-	time->tm_wday = readb(bq4802_regs + 0x08);
-	century = readb(bq4802_regs + 0x0f);
-
-	writeb(val, bq4802_regs + 0x0e);
-
-	BCD_TO_BIN(time->tm_sec);
-	BCD_TO_BIN(time->tm_min);
-	BCD_TO_BIN(time->tm_hour);
-	BCD_TO_BIN(time->tm_mday);
-	BCD_TO_BIN(time->tm_mon);
-	BCD_TO_BIN(time->tm_year);
-	BCD_TO_BIN(time->tm_wday);
-	BCD_TO_BIN(century);
-
-	time->tm_year += (century * 100);
-	time->tm_year -= 1900;
-
-	time->tm_mon--;
-}
-
-static int bq4802_set_rtc_time(struct rtc_time *time)
-{
-	unsigned char val = readb(bq4802_regs + 0x0e);
-	unsigned char sec, min, hrs, day, mon, yrs, century;
-	unsigned int year;
-
-	year = time->tm_year + 1900;
-	century = year / 100;
-	yrs = year % 100;
-
-	mon = time->tm_mon + 1;   /* tm_mon starts at zero */
-	day = time->tm_mday;
-	hrs = time->tm_hour;
-	min = time->tm_min;
-	sec = time->tm_sec;
-
-	BIN_TO_BCD(sec);
-	BIN_TO_BCD(min);
-	BIN_TO_BCD(hrs);
-	BIN_TO_BCD(day);
-	BIN_TO_BCD(mon);
-	BIN_TO_BCD(yrs);
-	BIN_TO_BCD(century);
-
-	writeb(val | 0x08, bq4802_regs + 0x0e);
-
-	writeb(sec, bq4802_regs + 0x00);
-	writeb(min, bq4802_regs + 0x02);
-	writeb(hrs, bq4802_regs + 0x04);
-	writeb(day, bq4802_regs + 0x06);
-	writeb(mon, bq4802_regs + 0x09);
-	writeb(yrs, bq4802_regs + 0x0a);
-	writeb(century, bq4802_regs + 0x0f);
-
-	writeb(val, bq4802_regs + 0x0e);
-
-	return 0;
-}
-
-static void cmos_get_rtc_time(struct rtc_time *rtc_tm)
-{
-	unsigned char ctrl;
-
-	rtc_tm->tm_sec = CMOS_READ(RTC_SECONDS);
-	rtc_tm->tm_min = CMOS_READ(RTC_MINUTES);
-	rtc_tm->tm_hour = CMOS_READ(RTC_HOURS);
-	rtc_tm->tm_mday = CMOS_READ(RTC_DAY_OF_MONTH);
-	rtc_tm->tm_mon = CMOS_READ(RTC_MONTH);
-	rtc_tm->tm_year = CMOS_READ(RTC_YEAR);
-	rtc_tm->tm_wday = CMOS_READ(RTC_DAY_OF_WEEK);
-
-	ctrl = CMOS_READ(RTC_CONTROL);
-	if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
-		BCD_TO_BIN(rtc_tm->tm_sec);
-		BCD_TO_BIN(rtc_tm->tm_min);
-		BCD_TO_BIN(rtc_tm->tm_hour);
-		BCD_TO_BIN(rtc_tm->tm_mday);
-		BCD_TO_BIN(rtc_tm->tm_mon);
-		BCD_TO_BIN(rtc_tm->tm_year);
-		BCD_TO_BIN(rtc_tm->tm_wday);
-	}
-
-	if (rtc_tm->tm_year <= 69)
-		rtc_tm->tm_year += 100;
-
-	rtc_tm->tm_mon--;
-}
-
-static int cmos_set_rtc_time(struct rtc_time *rtc_tm)
-{
-	unsigned char mon, day, hrs, min, sec;
-	unsigned char save_control, save_freq_select;
-	unsigned int yrs;
-
-	yrs = rtc_tm->tm_year;
-	mon = rtc_tm->tm_mon + 1;
-	day = rtc_tm->tm_mday;
-	hrs = rtc_tm->tm_hour;
-	min = rtc_tm->tm_min;
-	sec = rtc_tm->tm_sec;
-
-	if (yrs >= 100)
-		yrs -= 100;
-
-	if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
-		BIN_TO_BCD(sec);
-		BIN_TO_BCD(min);
-		BIN_TO_BCD(hrs);
-		BIN_TO_BCD(day);
-		BIN_TO_BCD(mon);
-		BIN_TO_BCD(yrs);
-	}
-
-	save_control = CMOS_READ(RTC_CONTROL);
-	CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL);
-	save_freq_select = CMOS_READ(RTC_FREQ_SELECT);
-	CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT);
-
-	CMOS_WRITE(yrs, RTC_YEAR);
-	CMOS_WRITE(mon, RTC_MONTH);
-	CMOS_WRITE(day, RTC_DAY_OF_MONTH);
-	CMOS_WRITE(hrs, RTC_HOURS);
-	CMOS_WRITE(min, RTC_MINUTES);
-	CMOS_WRITE(sec, RTC_SECONDS);
-
-	CMOS_WRITE(save_control, RTC_CONTROL);
-	CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT);
-
-	return 0;
-}
-#endif /* CONFIG_PCI */
-
-static void mostek_get_rtc_time(struct rtc_time *rtc_tm)
-{
-	void __iomem *regs = mstk48t02_regs;
-	u8 tmp;
-
-	spin_lock_irq(&mostek_lock);
-
-	tmp = mostek_read(regs + MOSTEK_CREG);
-	tmp |= MSTK_CREG_READ;
-	mostek_write(regs + MOSTEK_CREG, tmp);
-
-	rtc_tm->tm_sec = MSTK_REG_SEC(regs);
-	rtc_tm->tm_min = MSTK_REG_MIN(regs);
-	rtc_tm->tm_hour = MSTK_REG_HOUR(regs);
-	rtc_tm->tm_mday = MSTK_REG_DOM(regs);
-	rtc_tm->tm_mon = MSTK_REG_MONTH(regs);
-	rtc_tm->tm_year = MSTK_CVT_YEAR( MSTK_REG_YEAR(regs) );
-	rtc_tm->tm_wday = MSTK_REG_DOW(regs);
-
-	tmp = mostek_read(regs + MOSTEK_CREG);
-	tmp &= ~MSTK_CREG_READ;
-	mostek_write(regs + MOSTEK_CREG, tmp);
-
-	spin_unlock_irq(&mostek_lock);
-
-	rtc_tm->tm_mon--;
-	rtc_tm->tm_wday--;
-	rtc_tm->tm_year -= 1900;
-}
-
-static int mostek_set_rtc_time(struct rtc_time *rtc_tm)
-{
-	unsigned char mon, day, hrs, min, sec, wday;
-	void __iomem *regs = mstk48t02_regs;
-	unsigned int yrs;
-	u8 tmp;
-
-	yrs = rtc_tm->tm_year + 1900;
-	mon = rtc_tm->tm_mon + 1;
-	day = rtc_tm->tm_mday;
-	wday = rtc_tm->tm_wday + 1;
-	hrs = rtc_tm->tm_hour;
-	min = rtc_tm->tm_min;
-	sec = rtc_tm->tm_sec;
-
-	spin_lock_irq(&mostek_lock);
-
-	tmp = mostek_read(regs + MOSTEK_CREG);
-	tmp |= MSTK_CREG_WRITE;
-	mostek_write(regs + MOSTEK_CREG, tmp);
-
-	MSTK_SET_REG_SEC(regs, sec);
-	MSTK_SET_REG_MIN(regs, min);
-	MSTK_SET_REG_HOUR(regs, hrs);
-	MSTK_SET_REG_DOW(regs, wday);
-	MSTK_SET_REG_DOM(regs, day);
-	MSTK_SET_REG_MONTH(regs, mon);
-	MSTK_SET_REG_YEAR(regs, yrs - MSTK_YEAR_ZERO);
-
-	tmp = mostek_read(regs + MOSTEK_CREG);
-	tmp &= ~MSTK_CREG_WRITE;
-	mostek_write(regs + MOSTEK_CREG, tmp);
-
-	spin_unlock_irq(&mostek_lock);
-
-	return 0;
-}
-
-struct mini_rtc_ops {
-	void (*get_rtc_time)(struct rtc_time *);
-	int (*set_rtc_time)(struct rtc_time *);
-};
-
-static struct mini_rtc_ops starfire_rtc_ops = {
-	.get_rtc_time = starfire_get_rtc_time,
-	.set_rtc_time = starfire_set_rtc_time,
-};
-
-static struct mini_rtc_ops hypervisor_rtc_ops = {
-	.get_rtc_time = hypervisor_get_rtc_time,
-	.set_rtc_time = hypervisor_set_rtc_time,
-};
-
-#ifdef CONFIG_PCI
-static struct mini_rtc_ops bq4802_rtc_ops = {
-	.get_rtc_time = bq4802_get_rtc_time,
-	.set_rtc_time = bq4802_set_rtc_time,
-};
-
-static struct mini_rtc_ops cmos_rtc_ops = {
-	.get_rtc_time = cmos_get_rtc_time,
-	.set_rtc_time = cmos_set_rtc_time,
-};
-#endif /* CONFIG_PCI */
-
-static struct mini_rtc_ops mostek_rtc_ops = {
-	.get_rtc_time = mostek_get_rtc_time,
-	.set_rtc_time = mostek_set_rtc_time,
-};
-
-static struct mini_rtc_ops *mini_rtc_ops;
-
-static inline void mini_get_rtc_time(struct rtc_time *time)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&rtc_lock, flags);
-	mini_rtc_ops->get_rtc_time(time);
-	spin_unlock_irqrestore(&rtc_lock, flags);
-}
-
-static inline int mini_set_rtc_time(struct rtc_time *time)
-{
-	unsigned long flags;
-	int err;
-
-	spin_lock_irqsave(&rtc_lock, flags);
-	err = mini_rtc_ops->set_rtc_time(time);
-	spin_unlock_irqrestore(&rtc_lock, flags);
-
-	return err;
-}
-
-static int mini_rtc_ioctl(struct inode *inode, struct file *file,
-			  unsigned int cmd, unsigned long arg)
-{
-	struct rtc_time wtime;
-	void __user *argp = (void __user *)arg;
-
-	switch (cmd) {
-
-	case RTC_PLL_GET:
-		return -EINVAL;
-
-	case RTC_PLL_SET:
-		return -EINVAL;
-
-	case RTC_UIE_OFF:	/* disable ints from RTC updates.	*/
-		return 0;
-
-	case RTC_UIE_ON:	/* enable ints for RTC updates.	*/
-	        return -EINVAL;
-
-	case RTC_RD_TIME:	/* Read the time/date from RTC	*/
-		/* this doesn't get week-day, who cares */
-		memset(&wtime, 0, sizeof(wtime));
-		mini_get_rtc_time(&wtime);
-
-		return copy_to_user(argp, &wtime, sizeof(wtime)) ? -EFAULT : 0;
-
-	case RTC_SET_TIME:	/* Set the RTC */
-	    {
-		int year, days;
-
-		if (!capable(CAP_SYS_TIME))
-			return -EACCES;
-
-		if (copy_from_user(&wtime, argp, sizeof(wtime)))
-			return -EFAULT;
-
-		year = wtime.tm_year + 1900;
-		days = month_days[wtime.tm_mon] +
-		       ((wtime.tm_mon == 1) && leapyear(year));
-
-		if ((wtime.tm_mon < 0 || wtime.tm_mon > 11) ||
-		    (wtime.tm_mday < 1))
-			return -EINVAL;
-
-		if (wtime.tm_mday < 0 || wtime.tm_mday > days)
-			return -EINVAL;
-
-		if (wtime.tm_hour < 0 || wtime.tm_hour >= 24 ||
-		    wtime.tm_min < 0 || wtime.tm_min >= 60 ||
-		    wtime.tm_sec < 0 || wtime.tm_sec >= 60)
-			return -EINVAL;
-
-		return mini_set_rtc_time(&wtime);
-	    }
-	}
-
-	return -EINVAL;
-}
-
-static int mini_rtc_open(struct inode *inode, struct file *file)
-{
-	lock_kernel();
-	if (mini_rtc_status & RTC_IS_OPEN) {
-		unlock_kernel();
-		return -EBUSY;
-	}
-
-	mini_rtc_status |= RTC_IS_OPEN;
-	unlock_kernel();
-
-	return 0;
-}
-
-static int mini_rtc_release(struct inode *inode, struct file *file)
-{
-	mini_rtc_status &= ~RTC_IS_OPEN;
-	return 0;
-}
-
-
-static const struct file_operations mini_rtc_fops = {
-	.owner		= THIS_MODULE,
-	.ioctl		= mini_rtc_ioctl,
-	.open		= mini_rtc_open,
-	.release	= mini_rtc_release,
-};
-
-static struct miscdevice rtc_mini_dev =
-{
-	.minor		= RTC_MINOR,
-	.name		= "rtc",
-	.fops		= &mini_rtc_fops,
-};
-
-static int __init rtc_mini_init(void)
-{
-	int retval;
-
-	if (tlb_type == hypervisor)
-		mini_rtc_ops = &hypervisor_rtc_ops;
-	else if (this_is_starfire)
-		mini_rtc_ops = &starfire_rtc_ops;
-#ifdef CONFIG_PCI
-	else if (bq4802_regs)
-		mini_rtc_ops = &bq4802_rtc_ops;
-	else if (ds1287_regs)
-		mini_rtc_ops = &cmos_rtc_ops;
-#endif /* CONFIG_PCI */
-	else if (mstk48t02_regs)
-		mini_rtc_ops = &mostek_rtc_ops;
-	else
-		return -ENODEV;
-
-	printk(KERN_INFO "Mini RTC Driver\n");
-
-	retval = misc_register(&rtc_mini_dev);
-	if (retval < 0)
-		return retval;
-
-	return 0;
-}
-
-static void __exit rtc_mini_exit(void)
-{
-	misc_deregister(&rtc_mini_dev);
-}
-
 int __devinit read_current_timer(unsigned long *timer_val)
 {
 	*timer_val = tick_ops->get_tick();
 	return 0;
 }
-
-module_init(rtc_mini_init);
-module_exit(rtc_mini_exit);
diff --git a/arch/sparc64/kernel/traps.c b/arch/sparc64/kernel/traps.c
index 3d92412..81ccd22 100644
--- a/arch/sparc64/kernel/traps.c
+++ b/arch/sparc64/kernel/traps.c
@@ -10,6 +10,7 @@
 
 #include <linux/module.h>
 #include <linux/sched.h>
+#include <linux/linkage.h>
 #include <linux/kernel.h>
 #include <linux/signal.h>
 #include <linux/smp.h>
@@ -37,6 +38,7 @@
 #include <asm/timer.h>
 #include <asm/head.h>
 #include <asm/prom.h>
+#include <asm/memctrl.h>
 
 #include "entry.h"
 #include "kstack.h"
@@ -128,6 +130,56 @@
 }
 #endif
 
+static DEFINE_SPINLOCK(dimm_handler_lock);
+static dimm_printer_t dimm_handler;
+
+static int sprintf_dimm(int synd_code, unsigned long paddr, char *buf, int buflen)
+{
+	unsigned long flags;
+	int ret = -ENODEV;
+
+	spin_lock_irqsave(&dimm_handler_lock, flags);
+	if (dimm_handler) {
+		ret = dimm_handler(synd_code, paddr, buf, buflen);
+	} else if (tlb_type == spitfire) {
+		if (prom_getunumber(synd_code, paddr, buf, buflen) == -1)
+			ret = -EINVAL;
+		else
+			ret = 0;
+	} else
+		ret = -ENODEV;
+	spin_unlock_irqrestore(&dimm_handler_lock, flags);
+
+	return ret;
+}
+
+int register_dimm_printer(dimm_printer_t func)
+{
+	unsigned long flags;
+	int ret = 0;
+
+	spin_lock_irqsave(&dimm_handler_lock, flags);
+	if (!dimm_handler)
+		dimm_handler = func;
+	else
+		ret = -EEXIST;
+	spin_unlock_irqrestore(&dimm_handler_lock, flags);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(register_dimm_printer);
+
+void unregister_dimm_printer(dimm_printer_t func)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&dimm_handler_lock, flags);
+	if (dimm_handler == func)
+		dimm_handler = NULL;
+	spin_unlock_irqrestore(&dimm_handler_lock, flags);
+}
+EXPORT_SYMBOL_GPL(unregister_dimm_printer);
+
 void spitfire_insn_access_exception(struct pt_regs *regs, unsigned long sfsr, unsigned long sfar)
 {
 	siginfo_t info;
@@ -290,10 +342,7 @@
 }
 
 #ifdef CONFIG_PCI
-/* This is really pathetic... */
-extern volatile int pci_poke_in_progress;
-extern volatile int pci_poke_cpu;
-extern volatile int pci_poke_faulted;
+#include "pci_impl.h"
 #endif
 
 /* When access exceptions happen, we must do this. */
@@ -375,8 +424,7 @@
 
 	if (udbl & bit) {
 		scode = ecc_syndrome_table[udbl & 0xff];
-		if (prom_getunumber(scode, afar,
-				    memmod_str, sizeof(memmod_str)) == -1)
+		if (sprintf_dimm(scode, afar, memmod_str, sizeof(memmod_str)) < 0)
 			p = syndrome_unknown;
 		else
 			p = memmod_str;
@@ -387,8 +435,7 @@
 
 	if (udbh & bit) {
 		scode = ecc_syndrome_table[udbh & 0xff];
-		if (prom_getunumber(scode, afar,
-				    memmod_str, sizeof(memmod_str)) == -1)
+		if (sprintf_dimm(scode, afar, memmod_str, sizeof(memmod_str)) < 0)
 			p = syndrome_unknown;
 		else
 			p = memmod_str;
@@ -1061,8 +1108,6 @@
 	return "???";
 }
 
-extern int chmc_getunumber(int, unsigned long, char *, int);
-
 static void cheetah_log_errors(struct pt_regs *regs, struct cheetah_err_info *info,
 			       unsigned long afsr, unsigned long afar, int recoverable)
 {
@@ -1104,7 +1149,7 @@
 
 		syndrome = (afsr & CHAFSR_E_SYNDROME) >> CHAFSR_E_SYNDROME_SHIFT;
 		syndrome = cheetah_ecc_syntab[syndrome];
-		ret = chmc_getunumber(syndrome, afar, unum, sizeof(unum));
+		ret = sprintf_dimm(syndrome, afar, unum, sizeof(unum));
 		if (ret != -1)
 			printk("%s" "ERROR(%d): AFAR E-syndrome [%s]\n",
 			       (recoverable ? KERN_WARNING : KERN_CRIT),
@@ -1115,7 +1160,7 @@
 
 		syndrome = (afsr & CHAFSR_M_SYNDROME) >> CHAFSR_M_SYNDROME_SHIFT;
 		syndrome = cheetah_mtag_syntab[syndrome];
-		ret = chmc_getunumber(syndrome, afar, unum, sizeof(unum));
+		ret = sprintf_dimm(syndrome, afar, unum, sizeof(unum));
 		if (ret != -1)
 			printk("%s" "ERROR(%d): AFAR M-syndrome [%s]\n",
 			       (recoverable ? KERN_WARNING : KERN_CRIT),
@@ -2223,7 +2268,6 @@
 
 extern int handle_popc(u32 insn, struct pt_regs *regs);
 extern int handle_ldf_stq(u32 insn, struct pt_regs *regs);
-extern int vis_emul(struct pt_regs *, unsigned int);
 
 void do_illegal_instruction(struct pt_regs *regs)
 {
@@ -2453,7 +2497,7 @@
 /* This can get invoked before sched_init() so play it super safe
  * and use hard_smp_processor_id().
  */
-void init_cur_cpu_trap(struct thread_info *t)
+void notrace init_cur_cpu_trap(struct thread_info *t)
 {
 	int cpu = hard_smp_processor_id();
 	struct trap_per_cpu *p = &trap_block[cpu];
diff --git a/arch/sparc64/kernel/vio.c b/arch/sparc64/kernel/vio.c
index a490077..92b1f8e 100644
--- a/arch/sparc64/kernel/vio.c
+++ b/arch/sparc64/kernel/vio.c
@@ -152,7 +152,7 @@
 static DEVICE_ATTR(obppath, S_IRUSR | S_IRGRP | S_IROTH,
 		   show_pciobppath_attr, NULL);
 
-struct device_node *cdev_node;
+static struct device_node *cdev_node;
 
 static struct vio_dev *root_vdev;
 static u64 cdev_cfg_handle;
@@ -371,9 +371,9 @@
 	.node_name	= "domain-services-port",
 };
 
-const char *channel_devices_node = "channel-devices";
-const char *channel_devices_compat = "SUNW,sun4v-channel-devices";
-const char *cfg_handle_prop = "cfg-handle";
+static const char *channel_devices_node = "channel-devices";
+static const char *channel_devices_compat = "SUNW,sun4v-channel-devices";
+static const char *cfg_handle_prop = "cfg-handle";
 
 static int __init vio_init(void)
 {
diff --git a/arch/sparc64/kernel/visemul.c b/arch/sparc64/kernel/visemul.c
index c3fd647..9e05cb5 100644
--- a/arch/sparc64/kernel/visemul.c
+++ b/arch/sparc64/kernel/visemul.c
@@ -243,7 +243,7 @@
 struct edge_tab {
 	u16 left, right;
 };
-struct edge_tab edge8_tab[8] = {
+static struct edge_tab edge8_tab[8] = {
 	{ 0xff, 0x80 },
 	{ 0x7f, 0xc0 },
 	{ 0x3f, 0xe0 },
@@ -253,7 +253,7 @@
 	{ 0x03, 0xfe },
 	{ 0x01, 0xff },
 };
-struct edge_tab edge8_tab_l[8] = {
+static struct edge_tab edge8_tab_l[8] = {
 	{ 0xff, 0x01 },
 	{ 0xfe, 0x03 },
 	{ 0xfc, 0x07 },
@@ -263,23 +263,23 @@
 	{ 0xc0, 0x7f },
 	{ 0x80, 0xff },
 };
-struct edge_tab edge16_tab[4] = {
+static struct edge_tab edge16_tab[4] = {
 	{ 0xf, 0x8 },
 	{ 0x7, 0xc },
 	{ 0x3, 0xe },
 	{ 0x1, 0xf },
 };
-struct edge_tab edge16_tab_l[4] = {
+static struct edge_tab edge16_tab_l[4] = {
 	{ 0xf, 0x1 },
 	{ 0xe, 0x3 },
 	{ 0xc, 0x7 },
 	{ 0x8, 0xf },
 };
-struct edge_tab edge32_tab[2] = {
+static struct edge_tab edge32_tab[2] = {
 	{ 0x3, 0x2 },
 	{ 0x1, 0x3 },
 };
-struct edge_tab edge32_tab_l[2] = {
+static struct edge_tab edge32_tab_l[2] = {
 	{ 0x3, 0x1 },
 	{ 0x2, 0x3 },
 };
diff --git a/arch/sparc64/mm/fault.c b/arch/sparc64/mm/fault.c
index ea7d7ae..a9e474b 100644
--- a/arch/sparc64/mm/fault.c
+++ b/arch/sparc64/mm/fault.c
@@ -51,43 +51,6 @@
 }
 #endif
 
-/*
- * To debug kernel to catch accesses to certain virtual/physical addresses.
- * Mode = 0 selects physical watchpoints, mode = 1 selects virtual watchpoints.
- * flags = VM_READ watches memread accesses, flags = VM_WRITE watches memwrite accesses.
- * Caller passes in a 64bit aligned addr, with mask set to the bytes that need to be
- * watched. This is only useful on a single cpu machine for now. After the watchpoint
- * is detected, the process causing it will be killed, thus preventing an infinite loop.
- */
-void set_brkpt(unsigned long addr, unsigned char mask, int flags, int mode)
-{
-	unsigned long lsubits;
-
-	__asm__ __volatile__("ldxa [%%g0] %1, %0"
-			     : "=r" (lsubits)
-			     : "i" (ASI_LSU_CONTROL));
-	lsubits &= ~(LSU_CONTROL_PM | LSU_CONTROL_VM |
-		     LSU_CONTROL_PR | LSU_CONTROL_VR |
-		     LSU_CONTROL_PW | LSU_CONTROL_VW);
-
-	__asm__ __volatile__("stxa	%0, [%1] %2\n\t"
-			     "membar	#Sync"
-			     : /* no outputs */
-			     : "r" (addr), "r" (mode ? VIRT_WATCHPOINT : PHYS_WATCHPOINT),
-			       "i" (ASI_DMMU));
-
-	lsubits |= ((unsigned long)mask << (mode ? 25 : 33));
-	if (flags & VM_READ)
-		lsubits |= (mode ? LSU_CONTROL_VR : LSU_CONTROL_PR);
-	if (flags & VM_WRITE)
-		lsubits |= (mode ? LSU_CONTROL_VW : LSU_CONTROL_PW);
-	__asm__ __volatile__("stxa %0, [%%g0] %1\n\t"
-			     "membar #Sync"
-			     : /* no outputs */
-			     : "r" (lsubits), "i" (ASI_LSU_CONTROL)
-			     : "memory");
-}
-
 static void __kprobes unhandled_fault(unsigned long address,
 				      struct task_struct *tsk,
 				      struct pt_regs *regs)
diff --git a/arch/sparc64/mm/init.c b/arch/sparc64/mm/init.c
index a41df7b..3c10daf 100644
--- a/arch/sparc64/mm/init.c
+++ b/arch/sparc64/mm/init.c
@@ -46,15 +46,11 @@
 #include <asm/tsb.h>
 #include <asm/hypervisor.h>
 #include <asm/prom.h>
-#include <asm/sstate.h>
 #include <asm/mdesc.h>
 #include <asm/cpudata.h>
 #include <asm/irq.h>
 
-#define MAX_PHYS_ADDRESS	(1UL << 42UL)
-#define KPTE_BITMAP_CHUNK_SZ	(256UL * 1024UL * 1024UL)
-#define KPTE_BITMAP_BYTES	\
-	((MAX_PHYS_ADDRESS / KPTE_BITMAP_CHUNK_SZ) / 8)
+#include "init.h"
 
 unsigned long kern_linear_pte_xor[2] __read_mostly;
 
@@ -416,17 +412,9 @@
 #endif /* CONFIG_DEBUG_DCFLUSH */
 }
 
-struct linux_prom_translation {
-	unsigned long virt;
-	unsigned long size;
-	unsigned long data;
-};
-
-/* Exported for kernel TLB miss handling in ktlb.S */
 struct linux_prom_translation prom_trans[512] __read_mostly;
 unsigned int prom_trans_ents __read_mostly;
 
-/* Exported for SMP bootup purposes. */
 unsigned long kern_locked_tte_data;
 
 /* The obp translations are saved based on 8k pagesize, since obp can
@@ -938,6 +926,10 @@
 	int count, nid;
 	u64 grp;
 
+	/* This is the right thing to do on currently supported
+	 * SUN4U NUMA platforms as well, as the PCI controller does
+	 * not sit behind any particular memory controller.
+	 */
 	if (!mlgroups)
 		return -1;
 
@@ -1206,8 +1198,44 @@
 	return err;
 }
 
+static int __init numa_parse_jbus(void)
+{
+	unsigned long cpu, index;
+
+	/* NUMA node id is encoded in bits 36 and higher, and there is
+	 * a 1-to-1 mapping from CPU ID to NUMA node ID.
+	 */
+	index = 0;
+	for_each_present_cpu(cpu) {
+		numa_cpu_lookup_table[cpu] = index;
+		numa_cpumask_lookup_table[index] = cpumask_of_cpu(cpu);
+		node_masks[index].mask = ~((1UL << 36UL) - 1UL);
+		node_masks[index].val = cpu << 36UL;
+
+		index++;
+	}
+	num_node_masks = index;
+
+	add_node_ranges();
+
+	for (index = 0; index < num_node_masks; index++) {
+		allocate_node_data(index);
+		node_set_online(index);
+	}
+
+	return 0;
+}
+
 static int __init numa_parse_sun4u(void)
 {
+	if (tlb_type == cheetah || tlb_type == cheetah_plus) {
+		unsigned long ver;
+
+		__asm__ ("rdpr %%ver, %0" : "=r" (ver));
+		if ((ver >> 32UL) == __JALAPENO_ID ||
+		    (ver >> 32UL) == __SERRANO_ID)
+			return numa_parse_jbus();
+	}
 	return -1;
 }
 
@@ -1633,8 +1661,6 @@
 
 /* paging_init() sets up the page tables */
 
-extern void central_probe(void);
-
 static unsigned long last_valid_pfn;
 pgd_t swapper_pg_dir[2048];
 
@@ -1679,8 +1705,6 @@
 	kern_base = (prom_boot_mapping_phys_low >> 22UL) << 22UL;
 	kern_size = (unsigned long)&_end - (unsigned long)KERNBASE;
 
-	sstate_booting();
-
 	/* Invalidate both kernel TSBs.  */
 	memset(swapper_tsb, 0x40, sizeof(swapper_tsb));
 #ifndef CONFIG_DEBUG_PAGEALLOC
@@ -1803,9 +1827,6 @@
 	}
 
 	printk("Booting Linux...\n");
-
-	central_probe();
-	cpu_probe();
 }
 
 int __init page_in_phys_avail(unsigned long paddr)
@@ -2032,7 +2053,6 @@
 pgprot_t PAGE_SHARED __read_mostly;
 EXPORT_SYMBOL(PAGE_SHARED);
 
-pgprot_t PAGE_EXEC __read_mostly;
 unsigned long pg_iobits __read_mostly;
 
 unsigned long _PAGE_IE __read_mostly;
@@ -2045,14 +2065,6 @@
 EXPORT_SYMBOL(_PAGE_CACHE);
 
 #ifdef CONFIG_SPARSEMEM_VMEMMAP
-
-#define VMEMMAP_CHUNK_SHIFT	22
-#define VMEMMAP_CHUNK		(1UL << VMEMMAP_CHUNK_SHIFT)
-#define VMEMMAP_CHUNK_MASK	~(VMEMMAP_CHUNK - 1UL)
-#define VMEMMAP_ALIGN(x)	(((x)+VMEMMAP_CHUNK-1UL)&VMEMMAP_CHUNK_MASK)
-
-#define VMEMMAP_SIZE	((((1UL << MAX_PHYSADDR_BITS) >> PAGE_SHIFT) * \
-			  sizeof(struct page *)) >> VMEMMAP_CHUNK_SHIFT)
 unsigned long vmemmap_table[VMEMMAP_SIZE];
 
 int __meminit vmemmap_populate(struct page *start, unsigned long nr, int node)
@@ -2136,7 +2148,6 @@
 				       _PAGE_CACHE_4U | _PAGE_P_4U |
 				       __ACCESS_BITS_4U | __DIRTY_BITS_4U |
 				       _PAGE_EXEC_4U | _PAGE_L_4U);
-	PAGE_EXEC = __pgprot(_PAGE_EXEC_4U);
 
 	_PAGE_IE = _PAGE_IE_4U;
 	_PAGE_E = _PAGE_E_4U;
@@ -2147,10 +2158,10 @@
 
 #ifdef CONFIG_DEBUG_PAGEALLOC
 	kern_linear_pte_xor[0] = (_PAGE_VALID | _PAGE_SZBITS_4U) ^
-		0xfffff80000000000;
+		0xfffff80000000000UL;
 #else
 	kern_linear_pte_xor[0] = (_PAGE_VALID | _PAGE_SZ4MB_4U) ^
-		0xfffff80000000000;
+		0xfffff80000000000UL;
 #endif
 	kern_linear_pte_xor[0] |= (_PAGE_CP_4U | _PAGE_CV_4U |
 				   _PAGE_P_4U | _PAGE_W_4U);
@@ -2188,7 +2199,6 @@
 				__ACCESS_BITS_4V | __DIRTY_BITS_4V |
 				_PAGE_EXEC_4V);
 	PAGE_KERNEL_LOCKED = PAGE_KERNEL;
-	PAGE_EXEC = __pgprot(_PAGE_EXEC_4V);
 
 	_PAGE_IE = _PAGE_IE_4V;
 	_PAGE_E = _PAGE_E_4V;
@@ -2196,20 +2206,20 @@
 
 #ifdef CONFIG_DEBUG_PAGEALLOC
 	kern_linear_pte_xor[0] = (_PAGE_VALID | _PAGE_SZBITS_4V) ^
-		0xfffff80000000000;
+		0xfffff80000000000UL;
 #else
 	kern_linear_pte_xor[0] = (_PAGE_VALID | _PAGE_SZ4MB_4V) ^
-		0xfffff80000000000;
+		0xfffff80000000000UL;
 #endif
 	kern_linear_pte_xor[0] |= (_PAGE_CP_4V | _PAGE_CV_4V |
 				   _PAGE_P_4V | _PAGE_W_4V);
 
 #ifdef CONFIG_DEBUG_PAGEALLOC
 	kern_linear_pte_xor[1] = (_PAGE_VALID | _PAGE_SZBITS_4V) ^
-		0xfffff80000000000;
+		0xfffff80000000000UL;
 #else
 	kern_linear_pte_xor[1] = (_PAGE_VALID | _PAGE_SZ256MB_4V) ^
-		0xfffff80000000000;
+		0xfffff80000000000UL;
 #endif
 	kern_linear_pte_xor[1] |= (_PAGE_CP_4V | _PAGE_CV_4V |
 				   _PAGE_P_4V | _PAGE_W_4V);
diff --git a/arch/sparc64/mm/init.h b/arch/sparc64/mm/init.h
new file mode 100644
index 0000000..1606387
--- /dev/null
+++ b/arch/sparc64/mm/init.h
@@ -0,0 +1,49 @@
+#ifndef _SPARC64_MM_INIT_H
+#define _SPARC64_MM_INIT_H
+
+/* Most of the symbols in this file are defined in init.c and
+ * marked non-static so that assembler code can get at them.
+ */
+
+#define MAX_PHYS_ADDRESS	(1UL << 42UL)
+#define KPTE_BITMAP_CHUNK_SZ	(256UL * 1024UL * 1024UL)
+#define KPTE_BITMAP_BYTES	\
+	((MAX_PHYS_ADDRESS / KPTE_BITMAP_CHUNK_SZ) / 8)
+
+extern unsigned long kern_linear_pte_xor[2];
+extern unsigned long kpte_linear_bitmap[KPTE_BITMAP_BYTES / sizeof(unsigned long)];
+extern unsigned int sparc64_highest_unlocked_tlb_ent;
+extern unsigned long sparc64_kern_pri_context;
+extern unsigned long sparc64_kern_pri_nuc_bits;
+extern unsigned long sparc64_kern_sec_context;
+extern void mmu_info(struct seq_file *m);
+
+struct linux_prom_translation {
+	unsigned long virt;
+	unsigned long size;
+	unsigned long data;
+};
+
+/* Exported for kernel TLB miss handling in ktlb.S */
+extern struct linux_prom_translation prom_trans[512];
+extern unsigned int prom_trans_ents;
+
+/* Exported for SMP bootup purposes. */
+extern unsigned long kern_locked_tte_data;
+
+extern void prom_world(int enter);
+
+extern void free_initmem(void);
+
+#ifdef CONFIG_SPARSEMEM_VMEMMAP
+#define VMEMMAP_CHUNK_SHIFT	22
+#define VMEMMAP_CHUNK		(1UL << VMEMMAP_CHUNK_SHIFT)
+#define VMEMMAP_CHUNK_MASK	~(VMEMMAP_CHUNK - 1UL)
+#define VMEMMAP_ALIGN(x)	(((x)+VMEMMAP_CHUNK-1UL)&VMEMMAP_CHUNK_MASK)
+
+#define VMEMMAP_SIZE	((((1UL << MAX_PHYSADDR_BITS) >> PAGE_SHIFT) * \
+			  sizeof(struct page *)) >> VMEMMAP_CHUNK_SHIFT)
+extern unsigned long vmemmap_table[VMEMMAP_SIZE];
+#endif
+
+#endif /* _SPARC64_MM_INIT_H */
diff --git a/arch/sparc64/mm/tlb.c b/arch/sparc64/mm/tlb.c
index ae24919..d8f21e2 100644
--- a/arch/sparc64/mm/tlb.c
+++ b/arch/sparc64/mm/tlb.c
@@ -19,7 +19,7 @@
 
 /* Heavily inspired by the ppc64 code.  */
 
-DEFINE_PER_CPU(struct mmu_gather, mmu_gathers) = { 0, };
+DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
 
 void flush_tlb_pending(void)
 {
diff --git a/arch/um/Kconfig.char b/arch/um/Kconfig.char
index 1b238eb..70dabd1 100644
--- a/arch/um/Kconfig.char
+++ b/arch/um/Kconfig.char
@@ -203,6 +203,10 @@
 	tristate
 	default UML_SOUND
 
+config SOUND_OSS_CORE
+	bool
+	default UML_SOUND
+
 config HOSTAUDIO
 	tristate
 	default UML_SOUND
diff --git a/arch/um/Kconfig.i386 b/arch/um/Kconfig.i386
index e09edfa..1f57c11 100644
--- a/arch/um/Kconfig.i386
+++ b/arch/um/Kconfig.i386
@@ -9,8 +9,9 @@
 	default y
 
 config X86_32
-       bool
-       default y
+	bool
+	default y
+  	select HAVE_AOUT
 
 config RWSEM_XCHGADD_ALGORITHM
 	def_bool y
@@ -42,6 +43,3 @@
 config GENERIC_HWEIGHT
 	bool
 	default y
-
-config ARCH_SUPPORTS_AOUT
-	def_bool y
diff --git a/arch/um/Kconfig.x86_64 b/arch/um/Kconfig.x86_64
index 5696e7b..40b3407 100644
--- a/arch/um/Kconfig.x86_64
+++ b/arch/um/Kconfig.x86_64
@@ -37,6 +37,3 @@
 config GENERIC_HWEIGHT
 	bool
 	default y
-
-config ARCH_SUPPORTS_AOUT
-	def_bool y
diff --git a/arch/um/drivers/line.c b/arch/um/drivers/line.c
index d741f35..14a102e 100644
--- a/arch/um/drivers/line.c
+++ b/arch/um/drivers/line.c
@@ -275,6 +275,8 @@
 	case TIOCGLTC:
 	case TIOCSLTC:
 #endif
+	/* Note: these are out of date as we now have TCGETS2 etc but this
+	   whole lot should probably go away */
 	case TCGETS:
 	case TCSETSF:
 	case TCSETSW:
diff --git a/arch/um/kernel/smp.c b/arch/um/kernel/smp.c
index be2d50c..0457721 100644
--- a/arch/um/kernel/smp.c
+++ b/arch/um/kernel/smp.c
@@ -85,6 +85,7 @@
 	while (!cpu_isset(cpu, smp_commenced_mask))
 		cpu_relax();
 
+	notify_cpu_starting(cpu);
 	cpu_set(cpu, cpu_online_map);
 	default_idle();
 	return 0;
diff --git a/arch/um/sys-x86_64/syscall_table.c b/arch/um/sys-x86_64/syscall_table.c
index c128eb8..32f5fbe 100644
--- a/arch/um/sys-x86_64/syscall_table.c
+++ b/arch/um/sys-x86_64/syscall_table.c
@@ -41,12 +41,12 @@
 #define stub_rt_sigreturn sys_rt_sigreturn
 
 #define __SYSCALL(nr, sym) extern asmlinkage void sym(void) ;
-#undef _ASM_X86_64_UNISTD_H_
+#undef ASM_X86__UNISTD_64_H
 #include <asm-x86/unistd_64.h>
 
 #undef __SYSCALL
 #define __SYSCALL(nr, sym) [ nr ] = sym,
-#undef _ASM_X86_64_UNISTD_H_
+#undef ASM_X86__UNISTD_64_H
 
 typedef void (*sys_call_ptr_t)(void);
 
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index ed92864..837a9aa 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -18,6 +18,7 @@
 ### Arch settings
 config X86
 	def_bool y
+	select HAVE_AOUT if X86_32
 	select HAVE_UNSTABLE_SCHED_CLOCK
 	select HAVE_IDE
 	select HAVE_OPROFILE
@@ -29,6 +30,7 @@
 	select HAVE_FTRACE
 	select HAVE_KVM if ((X86_32 && !X86_VOYAGER && !X86_VISWS && !X86_NUMAQ) || X86_64)
 	select HAVE_ARCH_KGDB if !X86_VOYAGER
+	select HAVE_ARCH_TRACEHOOK
 	select HAVE_GENERIC_DMA_COHERENT if X86_32
 	select HAVE_EFFICIENT_UNALIGNED_ACCESS
 
@@ -151,9 +153,6 @@
 	bool
 	default X86_64
 
-config ARCH_SUPPORTS_AOUT
-	def_bool y
-
 config ARCH_SUPPORTS_OPTIMIZED_INLINING
 	def_bool y
 
@@ -553,6 +552,7 @@
 config AMD_IOMMU
 	bool "AMD IOMMU support"
 	select SWIOTLB
+	select PCI_MSI
 	depends on X86_64 && PCI && ACPI
 	help
 	  With this option you can enable support for AMD IOMMU hardware in
@@ -776,23 +776,45 @@
 	  Say N otherwise.
 
 config MICROCODE
-	tristate "/dev/cpu/microcode - Intel IA32 CPU microcode support"
+	tristate "/dev/cpu/microcode - microcode support"
 	select FW_LOADER
 	---help---
 	  If you say Y here, you will be able to update the microcode on
-	  Intel processors in the IA32 family, e.g. Pentium Pro, Pentium II,
-	  Pentium III, Pentium 4, Xeon etc.  You will obviously need the
-	  actual microcode binary data itself which is not shipped with the
-	  Linux kernel.
+	  certain Intel and AMD processors. The Intel support is for the
+	  IA32 family, e.g. Pentium Pro, Pentium II, Pentium III,
+	  Pentium 4, Xeon etc. The AMD support is for family 0x10 and
+	  0x11 processors, e.g. Opteron, Phenom and Turion 64 Ultra.
+	  You will obviously need the actual microcode binary data itself
+	  which is not shipped with the Linux kernel.
 
-	  For latest news and information on obtaining all the required
-	  ingredients for this driver, check:
-	  <http://www.urbanmyth.org/microcode/>.
+	  This option selects the general module only, you need to select
+	  at least one vendor specific module as well.
 
 	  To compile this driver as a module, choose M here: the
 	  module will be called microcode.
 
-config MICROCODE_OLD_INTERFACE
+config MICROCODE_INTEL
+       bool "Intel microcode patch loading support"
+       depends on MICROCODE
+       default MICROCODE
+       select FW_LOADER
+       --help---
+         This options enables microcode patch loading support for Intel
+         processors.
+
+         For latest news and information on obtaining all the required
+         Intel ingredients for this driver, check:
+         <http://www.urbanmyth.org/microcode/>.
+
+config MICROCODE_AMD
+       bool "AMD microcode patch loading support"
+       depends on MICROCODE
+       select FW_LOADER
+       --help---
+         If you select this option, microcode patch loading support for AMD
+	 processors will be enabled.
+
+   config MICROCODE_OLD_INTERFACE
 	def_bool y
 	depends on MICROCODE
 
@@ -925,13 +947,15 @@
 	def_bool n
 	prompt "PAE (Physical Address Extension) Support"
 	depends on X86_32 && !HIGHMEM4G
-	select RESOURCES_64BIT
 	help
 	  PAE is required for NX support, and furthermore enables
 	  larger swapspace support for non-overcommit purposes. It
 	  has the cost of more pagetable lookup overhead, and also
 	  consumes more pagetable space per process.
 
+config ARCH_PHYS_ADDR_T_64BIT
+       def_bool X86_64 || X86_PAE
+
 # Common NUMA Features
 config NUMA
 	bool "Numa Memory Allocation and Scheduler Support (EXPERIMENTAL)"
@@ -1020,7 +1044,7 @@
 
 config ARCH_FLATMEM_ENABLE
 	def_bool y
-	depends on X86_32 && ARCH_SELECT_MEMORY_MODEL && X86_PC && !NUMA
+	depends on X86_32 && ARCH_SELECT_MEMORY_MODEL && !NUMA
 
 config ARCH_DISCONTIGMEM_ENABLE
 	def_bool y
@@ -1036,7 +1060,7 @@
 
 config ARCH_SPARSEMEM_ENABLE
 	def_bool y
-	depends on X86_64 || NUMA || (EXPERIMENTAL && X86_PC)
+	depends on X86_64 || NUMA || (EXPERIMENTAL && X86_PC) || X86_GENERICARCH
 	select SPARSEMEM_STATIC if X86_32
 	select SPARSEMEM_VMEMMAP_ENABLE if X86_64
 
@@ -1059,6 +1083,56 @@
 	  low memory.  Setting this option will put user-space page table
 	  entries in high memory.
 
+config X86_CHECK_BIOS_CORRUPTION
+        bool "Check for low memory corruption"
+	help
+	 Periodically check for memory corruption in low memory, which
+	 is suspected to be caused by BIOS.  Even when enabled in the
+	 configuration, it is disabled at runtime.  Enable it by
+	 setting "memory_corruption_check=1" on the kernel command
+	 line.  By default it scans the low 64k of memory every 60
+	 seconds; see the memory_corruption_check_size and
+	 memory_corruption_check_period parameters in
+	 Documentation/kernel-parameters.txt to adjust this.
+
+	 When enabled with the default parameters, this option has
+	 almost no overhead, as it reserves a relatively small amount
+	 of memory and scans it infrequently.  It both detects corruption
+	 and prevents it from affecting the running system.
+
+	 It is, however, intended as a diagnostic tool; if repeatable
+	 BIOS-originated corruption always affects the same memory,
+	 you can use memmap= to prevent the kernel from using that
+	 memory.
+
+config X86_BOOTPARAM_MEMORY_CORRUPTION_CHECK
+        bool "Set the default setting of memory_corruption_check"
+	depends on X86_CHECK_BIOS_CORRUPTION
+	default y
+	help
+	 Set whether the default state of memory_corruption_check is
+	 on or off.
+
+config X86_RESERVE_LOW_64K
+        bool "Reserve low 64K of RAM on AMI/Phoenix BIOSen"
+	default y
+	help
+	 Reserve the first 64K of physical RAM on BIOSes that are known
+	 to potentially corrupt that memory range. A numbers of BIOSes are
+	 known to utilize this area during suspend/resume, so it must not
+	 be used by the kernel.
+
+	 Set this to N if you are absolutely sure that you trust the BIOS
+	 to get all its memory reservations and usages right.
+
+	 If you have doubts about the BIOS (e.g. suspend/resume does not
+	 work or there's kernel crashes after certain hardware hotplug
+	 events) and it's not AMI or Phoenix, then you might want to enable
+	 X86_CHECK_BIOS_CORRUPTION=y to allow the kernel to check typical
+	 corruption patterns.
+
+	 Say Y if unsure.
+
 config MATH_EMULATION
 	bool
 	prompt "Math emulation" if X86_32
@@ -1117,10 +1191,10 @@
 	  You can safely say Y even if your machine doesn't have MTRRs, you'll
 	  just add about 9 KB to your kernel.
 
-	  See <file:Documentation/mtrr.txt> for more information.
+	  See <file:Documentation/x86/mtrr.txt> for more information.
 
 config MTRR_SANITIZER
-	bool
+	def_bool y
 	prompt "MTRR cleanup support"
 	depends on MTRR
 	help
@@ -1131,7 +1205,7 @@
 	  The largest mtrr entry size for a continous block can be set with
 	  mtrr_chunk_size.
 
-	  If unsure, say N.
+	  If unsure, say Y.
 
 config MTRR_SANITIZER_ENABLE_DEFAULT
 	int "MTRR cleanup enable value (0-1)"
@@ -1191,7 +1265,6 @@
 config SECCOMP
 	def_bool y
 	prompt "Enable seccomp to safely compute untrusted bytecode"
-	depends on PROC_FS
 	help
 	  This kernel feature is useful for number crunching applications
 	  that may need to compute untrusted bytecode during their
@@ -1199,7 +1272,7 @@
 	  the process as file descriptors supporting the read/write
 	  syscalls, it's possible to isolate those applications in
 	  their own address space using seccomp. Once seccomp is
-	  enabled via /proc/<pid>/seccomp, it cannot be disabled
+	  enabled via prctl(PR_SET_SECCOMP), it cannot be disabled
 	  and the task is only allowed to execute a few safe syscalls
 	  defined by each seccomp mode.
 
@@ -1356,14 +1429,14 @@
 	  Don't change this unless you know what you are doing.
 
 config HOTPLUG_CPU
-	bool "Support for suspend on SMP and hot-pluggable CPUs (EXPERIMENTAL)"
-	depends on SMP && HOTPLUG && EXPERIMENTAL && !X86_VOYAGER
+	bool "Support for hot-pluggable CPUs"
+	depends on SMP && HOTPLUG && !X86_VOYAGER
 	---help---
-	  Say Y here to experiment with turning CPUs off and on, and to
-	  enable suspend on SMP systems. CPUs can be controlled through
-	  /sys/devices/system/cpu.
-	  Say N if you want to disable CPU hotplug and don't need to
-	  suspend.
+	  Say Y here to allow turning CPUs off and on. CPUs can be
+	  controlled through /sys/devices/system/cpu.
+	  ( Note: power management support will enable this option
+	    automatically on SMP systems. )
+	  Say N if you want to disable CPU hotplug.
 
 config COMPAT_VDSO
 	def_bool y
@@ -1378,6 +1451,51 @@
 
 	  If unsure, say Y.
 
+config CMDLINE_BOOL
+	bool "Built-in kernel command line"
+	default n
+	help
+	  Allow for specifying boot arguments to the kernel at
+	  build time.  On some systems (e.g. embedded ones), it is
+	  necessary or convenient to provide some or all of the
+	  kernel boot arguments with the kernel itself (that is,
+	  to not rely on the boot loader to provide them.)
+
+	  To compile command line arguments into the kernel,
+	  set this option to 'Y', then fill in the
+	  the boot arguments in CONFIG_CMDLINE.
+
+	  Systems with fully functional boot loaders (i.e. non-embedded)
+	  should leave this option set to 'N'.
+
+config CMDLINE
+	string "Built-in kernel command string"
+	depends on CMDLINE_BOOL
+	default ""
+	help
+	  Enter arguments here that should be compiled into the kernel
+	  image and used at boot time.  If the boot loader provides a
+	  command line at boot time, it is appended to this string to
+	  form the full kernel command line, when the system boots.
+
+	  However, you can use the CONFIG_CMDLINE_OVERRIDE option to
+	  change this behavior.
+
+	  In most cases, the command line (whether built-in or provided
+	  by the boot loader) should specify the device for the root
+	  file system.
+
+config CMDLINE_OVERRIDE
+	bool "Built-in command line overrides boot loader arguments"
+	default n
+	depends on CMDLINE_BOOL
+	help
+	  Set this option to 'Y' to have the kernel ignore the boot loader
+	  command line, and use ONLY the built-in command line.
+
+	  This is used to work around broken boot loaders.  This should
+	  be set to 'N' under normal conditions.
+
 endmenu
 
 config ARCH_ENABLE_MEMORY_HOTPLUG
@@ -1643,6 +1761,14 @@
 	 workaround will setup a 1:1 mapping for the first
 	 16M to make floppy (an ISA device) work.
 
+config INTR_REMAP
+	bool "Support for Interrupt Remapping (EXPERIMENTAL)"
+	depends on X86_64 && X86_IO_APIC && PCI_MSI && ACPI && EXPERIMENTAL
+	help
+	 Supports Interrupt remapping for IO-APIC and MSI devices.
+	 To use x2apic mode in the CPU's which support x2APIC enhancements or
+	 to support platforms with CPU's having > 8 bit APIC ID, say Y.
+
 source "drivers/pci/pcie/Kconfig"
 
 source "drivers/pci/Kconfig"
@@ -1759,7 +1885,7 @@
 
 config IA32_AOUT
        tristate "IA32 a.out support"
-       depends on IA32_EMULATION && ARCH_SUPPORTS_AOUT
+       depends on IA32_EMULATION
        help
          Support old a.out binaries in the 32bit emulation.
 
@@ -1773,7 +1899,7 @@
 
 config SYSVIPC_COMPAT
 	def_bool y
-	depends on X86_64 && COMPAT && SYSVIPC
+	depends on COMPAT && SYSVIPC
 
 endmenu
 
diff --git a/arch/x86/Kconfig.cpu b/arch/x86/Kconfig.cpu
index b225219..0b7c4a3 100644
--- a/arch/x86/Kconfig.cpu
+++ b/arch/x86/Kconfig.cpu
@@ -38,8 +38,7 @@
 	  - "Crusoe" for the Transmeta Crusoe series.
 	  - "Efficeon" for the Transmeta Efficeon series.
 	  - "Winchip-C6" for original IDT Winchip.
-	  - "Winchip-2" for IDT Winchip 2.
-	  - "Winchip-2A" for IDT Winchips with 3dNow! capabilities.
+	  - "Winchip-2" for IDT Winchips with 3dNow! capabilities.
 	  - "GeodeGX1" for Geode GX1 (Cyrix MediaGX).
 	  - "Geode GX/LX" For AMD Geode GX and LX processors.
 	  - "CyrixIII/VIA C3" for VIA Cyrix III or VIA C3.
@@ -194,19 +193,11 @@
 	  treat this chip as a 586TSC with some extended instructions
 	  and alignment requirements.
 
-config MWINCHIP2
-	bool "Winchip-2"
-	depends on X86_32
-	help
-	  Select this for an IDT Winchip-2.  Linux and GCC
-	  treat this chip as a 586TSC with some extended instructions
-	  and alignment requirements.
-
 config MWINCHIP3D
-	bool "Winchip-2A/Winchip-3"
+	bool "Winchip-2/Winchip-2A/Winchip-3"
 	depends on X86_32
 	help
-	  Select this for an IDT Winchip-2A or 3.  Linux and GCC
+	  Select this for an IDT Winchip-2, 2A or 3.  Linux and GCC
 	  treat this chip as a 586TSC with some extended instructions
 	  and alignment requirements.  Also enable out of order memory
 	  stores for this CPU, which can increase performance of some
@@ -318,7 +309,7 @@
 	int
 	default "7" if MPENTIUM4 || X86_GENERIC || GENERIC_CPU || MPSC
 	default "4" if X86_ELAN || M486 || M386 || MGEODEGX1
-	default "5" if MWINCHIP3D || MWINCHIP2 || MWINCHIPC6 || MCRUSOE || MEFFICEON || MCYRIXIII || MK6 || MPENTIUMIII || MPENTIUMII || M686 || M586MMX || M586TSC || M586 || MVIAC3_2 || MGEODE_LX
+	default "5" if MWINCHIP3D || MWINCHIPC6 || MCRUSOE || MEFFICEON || MCYRIXIII || MK6 || MPENTIUMIII || MPENTIUMII || M686 || M586MMX || M586TSC || M586 || MVIAC3_2 || MGEODE_LX
 	default "6" if MK7 || MK8 || MPENTIUMM || MCORE2 || MVIAC7
 
 config X86_XADD
@@ -360,7 +351,7 @@
 
 config X86_ALIGNMENT_16
 	def_bool y
-	depends on MWINCHIP3D || MWINCHIP2 || MWINCHIPC6 || MCYRIXIII || X86_ELAN || MK6 || M586MMX || M586TSC || M586 || M486 || MVIAC3_2 || MGEODEGX1
+	depends on MWINCHIP3D || MWINCHIPC6 || MCYRIXIII || X86_ELAN || MK6 || M586MMX || M586TSC || M586 || M486 || MVIAC3_2 || MGEODEGX1
 
 config X86_INTEL_USERCOPY
 	def_bool y
@@ -368,7 +359,7 @@
 
 config X86_USE_PPRO_CHECKSUM
 	def_bool y
-	depends on MWINCHIP3D || MWINCHIP2 || MWINCHIPC6 || MCYRIXIII || MK7 || MK6 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || MK8 || MVIAC3_2 || MEFFICEON || MGEODE_LX || MCORE2
+	depends on MWINCHIP3D || MWINCHIPC6 || MCYRIXIII || MK7 || MK6 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || MK8 || MVIAC3_2 || MEFFICEON || MGEODE_LX || MCORE2
 
 config X86_USE_3DNOW
 	def_bool y
@@ -376,7 +367,7 @@
 
 config X86_OOSTORE
 	def_bool y
-	depends on (MWINCHIP3D || MWINCHIP2 || MWINCHIPC6) && MTRR
+	depends on (MWINCHIP3D || MWINCHIPC6) && MTRR
 
 #
 # P6_NOPs are a relatively minor optimization that require a family >=
@@ -396,7 +387,7 @@
 
 config X86_TSC
 	def_bool y
-	depends on ((MWINCHIP3D || MWINCHIP2 || MCRUSOE || MEFFICEON || MCYRIXIII || MK7 || MK6 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || M586MMX || M586TSC || MK8 || MVIAC3_2 || MVIAC7 || MGEODEGX1 || MGEODE_LX || MCORE2) && !X86_NUMAQ) || X86_64
+	depends on ((MWINCHIP3D || MCRUSOE || MEFFICEON || MCYRIXIII || MK7 || MK6 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || M586MMX || M586TSC || MK8 || MVIAC3_2 || MVIAC7 || MGEODEGX1 || MGEODE_LX || MCORE2) && !X86_NUMAQ) || X86_64
 
 config X86_CMPXCHG64
 	def_bool y
@@ -406,7 +397,7 @@
 # generates cmov.
 config X86_CMOV
 	def_bool y
-	depends on (MK7 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || MVIAC3_2 || MVIAC7 || X86_64)
+	depends on (MK8 || MK7 || MCORE2 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || MVIAC3_2 || MVIAC7 || MCRUSOE || MEFFICEON || X86_64)
 
 config X86_MINIMUM_CPU_FAMILY
 	int
@@ -417,4 +408,124 @@
 
 config X86_DEBUGCTLMSR
 	def_bool y
-	depends on !(MK6 || MWINCHIPC6 || MWINCHIP2 || MWINCHIP3D || MCYRIXIII || M586MMX || M586TSC || M586 || M486 || M386)
+	depends on !(MK6 || MWINCHIPC6 || MWINCHIP3D || MCYRIXIII || M586MMX || M586TSC || M586 || M486 || M386)
+
+menuconfig PROCESSOR_SELECT
+	bool "Supported processor vendors" if EMBEDDED
+	help
+	  This lets you choose what x86 vendor support code your kernel
+	  will include.
+
+config CPU_SUP_INTEL
+	default y
+	bool "Support Intel processors" if PROCESSOR_SELECT
+	help
+	  This enables detection, tunings and quirks for Intel processors
+
+	  You need this enabled if you want your kernel to run on an
+	  Intel CPU. Disabling this option on other types of CPUs
+	  makes the kernel a tiny bit smaller. Disabling it on an Intel
+	  CPU might render the kernel unbootable.
+
+	  If unsure, say N.
+
+config CPU_SUP_CYRIX_32
+	default y
+	bool "Support Cyrix processors" if PROCESSOR_SELECT
+	depends on !64BIT
+	help
+	  This enables detection, tunings and quirks for Cyrix processors
+
+	  You need this enabled if you want your kernel to run on a
+	  Cyrix CPU. Disabling this option on other types of CPUs
+	  makes the kernel a tiny bit smaller. Disabling it on a Cyrix
+	  CPU might render the kernel unbootable.
+
+	  If unsure, say N.
+
+config CPU_SUP_AMD
+	default y
+	bool "Support AMD processors" if PROCESSOR_SELECT
+	help
+	  This enables detection, tunings and quirks for AMD processors
+
+	  You need this enabled if you want your kernel to run on an
+	  AMD CPU. Disabling this option on other types of CPUs
+	  makes the kernel a tiny bit smaller. Disabling it on an AMD
+	  CPU might render the kernel unbootable.
+
+	  If unsure, say N.
+
+config CPU_SUP_CENTAUR_32
+	default y
+	bool "Support Centaur processors" if PROCESSOR_SELECT
+	depends on !64BIT
+	help
+	  This enables detection, tunings and quirks for Centaur processors
+
+	  You need this enabled if you want your kernel to run on a
+	  Centaur CPU. Disabling this option on other types of CPUs
+	  makes the kernel a tiny bit smaller. Disabling it on a Centaur
+	  CPU might render the kernel unbootable.
+
+	  If unsure, say N.
+
+config CPU_SUP_CENTAUR_64
+	default y
+	bool "Support Centaur processors" if PROCESSOR_SELECT
+	depends on 64BIT
+	help
+	  This enables detection, tunings and quirks for Centaur processors
+
+	  You need this enabled if you want your kernel to run on a
+	  Centaur CPU. Disabling this option on other types of CPUs
+	  makes the kernel a tiny bit smaller. Disabling it on a Centaur
+	  CPU might render the kernel unbootable.
+
+	  If unsure, say N.
+
+config CPU_SUP_TRANSMETA_32
+	default y
+	bool "Support Transmeta processors" if PROCESSOR_SELECT
+	depends on !64BIT
+	help
+	  This enables detection, tunings and quirks for Transmeta processors
+
+	  You need this enabled if you want your kernel to run on a
+	  Transmeta CPU. Disabling this option on other types of CPUs
+	  makes the kernel a tiny bit smaller. Disabling it on a Transmeta
+	  CPU might render the kernel unbootable.
+
+	  If unsure, say N.
+
+config CPU_SUP_UMC_32
+	default y
+	bool "Support UMC processors" if PROCESSOR_SELECT
+	depends on !64BIT
+	help
+	  This enables detection, tunings and quirks for UMC processors
+
+	  You need this enabled if you want your kernel to run on a
+	  UMC CPU. Disabling this option on other types of CPUs
+	  makes the kernel a tiny bit smaller. Disabling it on a UMC
+	  CPU might render the kernel unbootable.
+
+	  If unsure, say N.
+
+config X86_DS
+	bool "Debug Store support"
+	default y
+	help
+	  Add support for Debug Store.
+	  This allows the kernel to provide a memory buffer to the hardware
+	  to store various profiling and tracing events.
+
+config X86_PTRACE_BTS
+	bool "ptrace interface to Branch Trace Store"
+	default y
+	depends on (X86_DS && X86_DEBUGCTLMSR)
+	help
+	  Add a ptrace interface to allow collecting an execution trace
+	  of the traced task.
+	  This collects control flow changes in a (cyclic) buffer and allows
+	  debuggers to fill in the gaps and show an execution trace of the debuggee.
diff --git a/arch/x86/Kconfig.debug b/arch/x86/Kconfig.debug
index 092f019..2a3dfbd 100644
--- a/arch/x86/Kconfig.debug
+++ b/arch/x86/Kconfig.debug
@@ -43,6 +43,19 @@
 	  with klogd/syslogd or the X server. You should normally N here,
 	  unless you want to debug such a crash.
 
+config EARLY_PRINTK_DBGP
+	bool "Early printk via EHCI debug port"
+	default n
+	depends on EARLY_PRINTK && PCI
+	help
+	  Write kernel log output directly into the EHCI debug port.
+
+	  This is useful for kernel debugging when your machine crashes very
+	  early before the console code is initialized. For normal operation
+	  it is not recommended because it looks ugly and doesn't cooperate
+	  with klogd/syslogd or the X server. You should normally N here,
+	  unless you want to debug such a crash. You need usb debug device.
+
 config DEBUG_STACKOVERFLOW
 	bool "Check for stack overflows"
 	depends on DEBUG_KERNEL
diff --git a/arch/x86/Makefile_32.cpu b/arch/x86/Makefile_32.cpu
index e372b58..80177ec 100644
--- a/arch/x86/Makefile_32.cpu
+++ b/arch/x86/Makefile_32.cpu
@@ -28,7 +28,6 @@
 cflags-$(CONFIG_MCRUSOE)	+= -march=i686 $(align)-functions=0 $(align)-jumps=0 $(align)-loops=0
 cflags-$(CONFIG_MEFFICEON)	+= -march=i686 $(call tune,pentium3) $(align)-functions=0 $(align)-jumps=0 $(align)-loops=0
 cflags-$(CONFIG_MWINCHIPC6)	+= $(call cc-option,-march=winchip-c6,-march=i586)
-cflags-$(CONFIG_MWINCHIP2)	+= $(call cc-option,-march=winchip2,-march=i586)
 cflags-$(CONFIG_MWINCHIP3D)	+= $(call cc-option,-march=winchip2,-march=i586)
 cflags-$(CONFIG_MCYRIXIII)	+= $(call cc-option,-march=c3,-march=i486) $(align)-functions=0 $(align)-jumps=0 $(align)-loops=0
 cflags-$(CONFIG_MVIAC3_2)	+= $(call cc-option,-march=c3-2,-march=i686)
@@ -45,3 +44,8 @@
 # cpu entries
 cflags-$(CONFIG_X86_GENERIC) 	+= $(call tune,generic,$(call tune,i686))
 
+# Bug fix for binutils: this option is required in order to keep
+# binutils from generating NOPL instructions against our will.
+ifneq ($(CONFIG_X86_P6_NOP),y)
+cflags-y			+= $(call cc-option,-Wa$(comma)-mtune=generic32,)
+endif
diff --git a/arch/x86/boot/Makefile b/arch/x86/boot/Makefile
index 7ee102f..cd48c72 100644
--- a/arch/x86/boot/Makefile
+++ b/arch/x86/boot/Makefile
@@ -72,9 +72,7 @@
 KBUILD_CFLAGS +=   $(call cc-option,-m32)
 KBUILD_AFLAGS	:= $(KBUILD_CFLAGS) -D__ASSEMBLY__
 
-$(obj)/zImage:  IMAGE_OFFSET := 0x1000
 $(obj)/zImage:  asflags-y := $(SVGA_MODE) $(RAMDISK)
-$(obj)/bzImage: IMAGE_OFFSET := 0x100000
 $(obj)/bzImage: ccflags-y := -D__BIG_KERNEL__
 $(obj)/bzImage: asflags-y := $(SVGA_MODE) $(RAMDISK) -D__BIG_KERNEL__
 $(obj)/bzImage: BUILDFLAGS   := -b
@@ -117,7 +115,7 @@
 	$(call if_changed,objcopy)
 
 $(obj)/compressed/vmlinux: FORCE
-	$(Q)$(MAKE) $(build)=$(obj)/compressed IMAGE_OFFSET=$(IMAGE_OFFSET) $@
+	$(Q)$(MAKE) $(build)=$(obj)/compressed $@
 
 # Set this if you want to pass append arguments to the zdisk/fdimage/isoimage kernel
 FDARGS =
@@ -181,6 +179,7 @@
 	mkisofs -J -r -o $(obj)/image.iso -b isolinux.bin -c boot.cat \
 		-no-emul-boot -boot-load-size 4 -boot-info-table \
 		$(obj)/isoimage
+	isohybrid $(obj)/image.iso 2>/dev/null || true
 	rm -rf $(obj)/isoimage
 
 zlilo: $(BOOTIMAGE)
diff --git a/arch/x86/boot/compressed/Makefile b/arch/x86/boot/compressed/Makefile
index 92fdd35..1771c80 100644
--- a/arch/x86/boot/compressed/Makefile
+++ b/arch/x86/boot/compressed/Makefile
@@ -27,9 +27,8 @@
 	$(call if_changed,objcopy)
 
 
-ifeq ($(CONFIG_X86_32),y)
-targets += vmlinux.bin.all vmlinux.relocs
-hostprogs-y := relocs
+targets += vmlinux.bin.all vmlinux.relocs relocs
+hostprogs-$(CONFIG_X86_32) += relocs
 
 quiet_cmd_relocs = RELOCS  $@
       cmd_relocs = $(obj)/relocs $< > $@;$(obj)/relocs --abs-relocs $<
@@ -43,6 +42,8 @@
 $(obj)/vmlinux.bin.all: $(vmlinux.bin.all-y) FORCE
 	$(call if_changed,relocbin)
 
+ifeq ($(CONFIG_X86_32),y)
+
 ifdef CONFIG_RELOCATABLE
 $(obj)/vmlinux.bin.gz: $(obj)/vmlinux.bin.all FORCE
 	$(call if_changed,gzip)
@@ -59,6 +60,5 @@
 LDFLAGS_piggy.o := -r --format binary --oformat elf64-x86-64 -T
 endif
 
-
 $(obj)/piggy.o: $(obj)/vmlinux.scr $(obj)/vmlinux.bin.gz FORCE
 	$(call if_changed,ld)
diff --git a/arch/x86/boot/compressed/head_32.S b/arch/x86/boot/compressed/head_32.S
index ba7736c..29c5fbf 100644
--- a/arch/x86/boot/compressed/head_32.S
+++ b/arch/x86/boot/compressed/head_32.S
@@ -137,14 +137,15 @@
  */
 	movl output_len(%ebx), %eax
 	pushl %eax
+			# push arguments for decompress_kernel:
 	pushl %ebp	# output address
 	movl input_len(%ebx), %eax
 	pushl %eax	# input_len
 	leal input_data(%ebx), %eax
 	pushl %eax	# input_data
 	leal boot_heap(%ebx), %eax
-	pushl %eax	# heap area as third argument
-	pushl %esi	# real mode pointer as second arg
+	pushl %eax	# heap area
+	pushl %esi	# real mode pointer
 	call decompress_kernel
 	addl $20, %esp
 	popl %ecx
diff --git a/arch/x86/boot/compressed/misc.c b/arch/x86/boot/compressed/misc.c
index 9fea737..5780d36 100644
--- a/arch/x86/boot/compressed/misc.c
+++ b/arch/x86/boot/compressed/misc.c
@@ -16,7 +16,7 @@
  */
 #undef CONFIG_PARAVIRT
 #ifdef CONFIG_X86_32
-#define _ASM_DESC_H_ 1
+#define ASM_X86__DESC_H 1
 #endif
 
 #ifdef CONFIG_X86_64
@@ -27,7 +27,7 @@
 #include <linux/linkage.h>
 #include <linux/screen_info.h>
 #include <linux/elf.h>
-#include <asm/io.h>
+#include <linux/io.h>
 #include <asm/page.h>
 #include <asm/boot.h>
 #include <asm/bootparam.h>
@@ -251,7 +251,7 @@
 				y--;
 			}
 		} else {
-			vidmem [(x + cols * y) * 2] = c;
+			vidmem[(x + cols * y) * 2] = c;
 			if (++x >= cols) {
 				x = 0;
 				if (++y >= lines) {
@@ -277,7 +277,8 @@
 	int i;
 	char *ss = s;
 
-	for (i = 0; i < n; i++) ss[i] = c;
+	for (i = 0; i < n; i++)
+		ss[i] = c;
 	return s;
 }
 
@@ -287,7 +288,8 @@
 	const char *s = src;
 	char *d = dest;
 
-	for (i = 0; i < n; i++) d[i] = s[i];
+	for (i = 0; i < n; i++)
+		d[i] = s[i];
 	return dest;
 }
 
diff --git a/arch/x86/boot/compressed/relocs.c b/arch/x86/boot/compressed/relocs.c
index a1310c5..857e492 100644
--- a/arch/x86/boot/compressed/relocs.c
+++ b/arch/x86/boot/compressed/relocs.c
@@ -492,7 +492,7 @@
 			continue;
 		}
 		sh_symtab = sec_symtab->symtab;
-		sym_strtab = sec->link->strtab;
+		sym_strtab = sec_symtab->link->strtab;
 		for (j = 0; j < sec->shdr.sh_size/sizeof(Elf32_Rel); j++) {
 			Elf32_Rel *rel;
 			Elf32_Sym *sym;
diff --git a/arch/x86/boot/cpu.c b/arch/x86/boot/cpu.c
index 75298fe..6ec6bb6 100644
--- a/arch/x86/boot/cpu.c
+++ b/arch/x86/boot/cpu.c
@@ -59,17 +59,18 @@
 			u32 e = err_flags[i];
 
 			for (j = 0; j < 32; j++) {
-				int n = (i << 5)+j;
-				if (*msg_strs < n) {
+				if (msg_strs[0] < i ||
+				    (msg_strs[0] == i && msg_strs[1] < j)) {
 					/* Skip to the next string */
-					do {
-						msg_strs++;
-					} while (*msg_strs);
-					msg_strs++;
+					msg_strs += 2;
+					while (*msg_strs++)
+						;
 				}
 				if (e & 1) {
-					if (*msg_strs == n && msg_strs[1])
-						printf("%s ", msg_strs+1);
+					if (msg_strs[0] == i &&
+					    msg_strs[1] == j &&
+					    msg_strs[2])
+						printf("%s ", msg_strs+2);
 					else
 						printf("%d:%d ", i, j);
 				}
diff --git a/arch/x86/boot/edd.c b/arch/x86/boot/edd.c
index d93cbc6..1aae8f3 100644
--- a/arch/x86/boot/edd.c
+++ b/arch/x86/boot/edd.c
@@ -41,6 +41,7 @@
 	char *mbrbuf_ptr, *mbrbuf_end;
 	u32 buf_base, mbr_base;
 	extern char _end[];
+	u16 mbr_magic;
 
 	sector_size = ei->params.bytes_per_sector;
 	if (!sector_size)
@@ -58,11 +59,15 @@
 	if (mbrbuf_end > (char *)(size_t)boot_params.hdr.heap_end_ptr)
 		return -1;
 
+	memset(mbrbuf_ptr, 0, sector_size);
 	if (read_mbr(devno, mbrbuf_ptr))
 		return -1;
 
 	*mbrsig = *(u32 *)&mbrbuf_ptr[EDD_MBR_SIG_OFFSET];
-	return 0;
+	mbr_magic = *(u16 *)&mbrbuf_ptr[510];
+
+	/* check for valid MBR magic */
+	return mbr_magic == 0xAA55 ? 0 : -1;
 }
 
 static int get_edd_info(u8 devno, struct edd_info *ei)
diff --git a/arch/x86/boot/header.S b/arch/x86/boot/header.S
index af86e43..b993062 100644
--- a/arch/x86/boot/header.S
+++ b/arch/x86/boot/header.S
@@ -30,7 +30,6 @@
 SYSSIZE		= DEF_SYSSIZE		/* system size: # of 16-byte clicks */
 					/* to be loaded */
 ROOT_DEV	= 0			/* ROOT_DEV is now written by "build" */
-SWAP_DEV	= 0			/* SWAP_DEV is now written by "build" */
 
 #ifndef SVGA_MODE
 #define SVGA_MODE ASK_VGA
diff --git a/arch/x86/boot/mkcpustr.c b/arch/x86/boot/mkcpustr.c
index bbe7695..8ef60f2 100644
--- a/arch/x86/boot/mkcpustr.c
+++ b/arch/x86/boot/mkcpustr.c
@@ -15,33 +15,33 @@
 
 #include <stdio.h>
 
-#include "../kernel/cpu/feature_names.c"
-
-#if NCAPFLAGS > 8
-# error "Need to adjust the boot code handling of CPUID strings"
-#endif
+#include "../kernel/cpu/capflags.c"
 
 int main(void)
 {
-	int i;
+	int i, j;
 	const char *str;
 
 	printf("static const char x86_cap_strs[] = \n");
 
-	for (i = 0; i < NCAPINTS*32; i++) {
-		str = x86_cap_flags[i];
+	for (i = 0; i < NCAPINTS; i++) {
+		for (j = 0; j < 32; j++) {
+			str = x86_cap_flags[i*32+j];
 
-		if (i == NCAPINTS*32-1) {
-			/* The last entry must be unconditional; this
-			   also consumes the compiler-added null character */
-			if (!str)
-				str = "";
-			printf("\t\"\\x%02x\"\"%s\"\n", i, str);
-		} else if (str) {
-			printf("#if REQUIRED_MASK%d & (1 << %d)\n"
-			       "\t\"\\x%02x\"\"%s\\0\"\n"
-			       "#endif\n",
-			       i >> 5, i & 31, i, str);
+			if (i == NCAPINTS-1 && j == 31) {
+				/* The last entry must be unconditional; this
+				   also consumes the compiler-added null
+				   character */
+				if (!str)
+					str = "";
+				printf("\t\"\\x%02x\\x%02x\"\"%s\"\n",
+				       i, j, str);
+			} else if (str) {
+				printf("#if REQUIRED_MASK%d & (1 << %d)\n"
+				       "\t\"\\x%02x\\x%02x\"\"%s\\0\"\n"
+				       "#endif\n",
+				       i, j, i, j, str);
+			}
 		}
 	}
 	printf("\t;\n");
diff --git a/arch/x86/boot/video-vesa.c b/arch/x86/boot/video-vesa.c
index 401ad99..1e6fe02 100644
--- a/arch/x86/boot/video-vesa.c
+++ b/arch/x86/boot/video-vesa.c
@@ -224,7 +224,7 @@
 static void vesa_store_mode_params_graphics(void)
 {
 	/* Tell the kernel we're in VESA graphics mode */
-	boot_params.screen_info.orig_video_isVGA = 0x23;
+	boot_params.screen_info.orig_video_isVGA = VIDEO_TYPE_VLFB;
 
 	/* Mode parameters */
 	boot_params.screen_info.vesa_attributes = vminfo.mode_attr;
diff --git a/arch/x86/configs/i386_defconfig b/arch/x86/configs/i386_defconfig
index 104275e..52d0359 100644
--- a/arch/x86/configs/i386_defconfig
+++ b/arch/x86/configs/i386_defconfig
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.27-rc4
-# Mon Aug 25 15:04:00 2008
+# Linux kernel version: 2.6.27-rc5
+# Wed Sep  3 17:23:09 2008
 #
 # CONFIG_64BIT is not set
 CONFIG_X86_32=y
@@ -202,7 +202,7 @@
 # CONFIG_M586 is not set
 # CONFIG_M586TSC is not set
 # CONFIG_M586MMX is not set
-# CONFIG_M686 is not set
+CONFIG_M686=y
 # CONFIG_MPENTIUMII is not set
 # CONFIG_MPENTIUMIII is not set
 # CONFIG_MPENTIUMM is not set
@@ -213,7 +213,6 @@
 # CONFIG_MCRUSOE is not set
 # CONFIG_MEFFICEON is not set
 # CONFIG_MWINCHIPC6 is not set
-# CONFIG_MWINCHIP2 is not set
 # CONFIG_MWINCHIP3D is not set
 # CONFIG_MGEODEGX1 is not set
 # CONFIG_MGEODE_LX is not set
@@ -221,13 +220,14 @@
 # CONFIG_MVIAC3_2 is not set
 # CONFIG_MVIAC7 is not set
 # CONFIG_MPSC is not set
-CONFIG_MCORE2=y
+# CONFIG_MCORE2 is not set
 # CONFIG_GENERIC_CPU is not set
 CONFIG_X86_GENERIC=y
 CONFIG_X86_CPU=y
 CONFIG_X86_CMPXCHG=y
 CONFIG_X86_L1_CACHE_SHIFT=7
 CONFIG_X86_XADD=y
+# CONFIG_X86_PPRO_FENCE is not set
 CONFIG_X86_WP_WORKS_OK=y
 CONFIG_X86_INVLPG=y
 CONFIG_X86_BSWAP=y
@@ -235,14 +235,15 @@
 CONFIG_X86_INTEL_USERCOPY=y
 CONFIG_X86_USE_PPRO_CHECKSUM=y
 CONFIG_X86_TSC=y
+CONFIG_X86_CMOV=y
 CONFIG_X86_MINIMUM_CPU_FAMILY=4
 CONFIG_X86_DEBUGCTLMSR=y
 CONFIG_HPET_TIMER=y
 CONFIG_HPET_EMULATE_RTC=y
 CONFIG_DMI=y
 # CONFIG_IOMMU_HELPER is not set
-CONFIG_NR_CPUS=4
-# CONFIG_SCHED_SMT is not set
+CONFIG_NR_CPUS=64
+CONFIG_SCHED_SMT=y
 CONFIG_SCHED_MC=y
 # CONFIG_PREEMPT_NONE is not set
 CONFIG_PREEMPT_VOLUNTARY=y
@@ -254,7 +255,8 @@
 # CONFIG_TOSHIBA is not set
 # CONFIG_I8K is not set
 CONFIG_X86_REBOOTFIXUPS=y
-# CONFIG_MICROCODE is not set
+CONFIG_MICROCODE=y
+CONFIG_MICROCODE_OLD_INTERFACE=y
 CONFIG_X86_MSR=y
 CONFIG_X86_CPUID=y
 # CONFIG_NOHIGHMEM is not set
@@ -1532,7 +1534,6 @@
 CONFIG_VGA_CONSOLE=y
 CONFIG_VGACON_SOFT_SCROLLBACK=y
 CONFIG_VGACON_SOFT_SCROLLBACK_SIZE=64
-CONFIG_VIDEO_SELECT=y
 CONFIG_DUMMY_CONSOLE=y
 # CONFIG_FRAMEBUFFER_CONSOLE is not set
 CONFIG_LOGO=y
@@ -2115,7 +2116,7 @@
 CONFIG_DEFAULT_IO_DELAY_TYPE=0
 CONFIG_DEBUG_BOOT_PARAMS=y
 # CONFIG_CPA_DEBUG is not set
-# CONFIG_OPTIMIZE_INLINING is not set
+CONFIG_OPTIMIZE_INLINING=y
 
 #
 # Security options
diff --git a/arch/x86/configs/x86_64_defconfig b/arch/x86/configs/x86_64_defconfig
index 678c8ac..f0a03d7 100644
--- a/arch/x86/configs/x86_64_defconfig
+++ b/arch/x86/configs/x86_64_defconfig
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.27-rc4
-# Mon Aug 25 14:40:46 2008
+# Linux kernel version: 2.6.27-rc5
+# Wed Sep  3 17:13:39 2008
 #
 CONFIG_64BIT=y
 # CONFIG_X86_32 is not set
@@ -210,7 +210,6 @@
 # CONFIG_MCRUSOE is not set
 # CONFIG_MEFFICEON is not set
 # CONFIG_MWINCHIPC6 is not set
-# CONFIG_MWINCHIP2 is not set
 # CONFIG_MWINCHIP3D is not set
 # CONFIG_MGEODEGX1 is not set
 # CONFIG_MGEODE_LX is not set
@@ -218,17 +217,14 @@
 # CONFIG_MVIAC3_2 is not set
 # CONFIG_MVIAC7 is not set
 # CONFIG_MPSC is not set
-CONFIG_MCORE2=y
-# CONFIG_GENERIC_CPU is not set
+# CONFIG_MCORE2 is not set
+CONFIG_GENERIC_CPU=y
 CONFIG_X86_CPU=y
-CONFIG_X86_L1_CACHE_BYTES=64
-CONFIG_X86_INTERNODE_CACHE_BYTES=64
+CONFIG_X86_L1_CACHE_BYTES=128
+CONFIG_X86_INTERNODE_CACHE_BYTES=128
 CONFIG_X86_CMPXCHG=y
-CONFIG_X86_L1_CACHE_SHIFT=6
+CONFIG_X86_L1_CACHE_SHIFT=7
 CONFIG_X86_WP_WORKS_OK=y
-CONFIG_X86_INTEL_USERCOPY=y
-CONFIG_X86_USE_PPRO_CHECKSUM=y
-CONFIG_X86_P6_NOP=y
 CONFIG_X86_TSC=y
 CONFIG_X86_CMPXCHG64=y
 CONFIG_X86_CMOV=y
@@ -243,9 +239,8 @@
 CONFIG_AMD_IOMMU=y
 CONFIG_SWIOTLB=y
 CONFIG_IOMMU_HELPER=y
-# CONFIG_MAXSMP is not set
-CONFIG_NR_CPUS=4
-# CONFIG_SCHED_SMT is not set
+CONFIG_NR_CPUS=64
+CONFIG_SCHED_SMT=y
 CONFIG_SCHED_MC=y
 # CONFIG_PREEMPT_NONE is not set
 CONFIG_PREEMPT_VOLUNTARY=y
@@ -254,7 +249,8 @@
 CONFIG_X86_IO_APIC=y
 # CONFIG_X86_MCE is not set
 # CONFIG_I8K is not set
-# CONFIG_MICROCODE is not set
+CONFIG_MICROCODE=y
+CONFIG_MICROCODE_OLD_INTERFACE=y
 CONFIG_X86_MSR=y
 CONFIG_X86_CPUID=y
 CONFIG_NUMA=y
@@ -290,7 +286,7 @@
 CONFIG_VIRT_TO_BUS=y
 CONFIG_MTRR=y
 # CONFIG_MTRR_SANITIZER is not set
-# CONFIG_X86_PAT is not set
+CONFIG_X86_PAT=y
 CONFIG_EFI=y
 CONFIG_SECCOMP=y
 # CONFIG_HZ_100 is not set
@@ -1508,7 +1504,6 @@
 CONFIG_VGA_CONSOLE=y
 CONFIG_VGACON_SOFT_SCROLLBACK=y
 CONFIG_VGACON_SOFT_SCROLLBACK_SIZE=64
-CONFIG_VIDEO_SELECT=y
 CONFIG_DUMMY_CONSOLE=y
 # CONFIG_FRAMEBUFFER_CONSOLE is not set
 CONFIG_LOGO=y
@@ -2089,7 +2084,7 @@
 CONFIG_DEFAULT_IO_DELAY_TYPE=0
 CONFIG_DEBUG_BOOT_PARAMS=y
 # CONFIG_CPA_DEBUG is not set
-# CONFIG_OPTIMIZE_INLINING is not set
+CONFIG_OPTIMIZE_INLINING=y
 
 #
 # Security options
diff --git a/arch/x86/crypto/Makefile b/arch/x86/crypto/Makefile
index 3874c2d..903de4a 100644
--- a/arch/x86/crypto/Makefile
+++ b/arch/x86/crypto/Makefile
@@ -10,6 +10,8 @@
 obj-$(CONFIG_CRYPTO_TWOFISH_X86_64) += twofish-x86_64.o
 obj-$(CONFIG_CRYPTO_SALSA20_X86_64) += salsa20-x86_64.o
 
+obj-$(CONFIG_CRYPTO_CRC32C_INTEL) += crc32c-intel.o
+
 aes-i586-y := aes-i586-asm_32.o aes_glue.o
 twofish-i586-y := twofish-i586-asm_32.o twofish_glue.o
 salsa20-i586-y := salsa20-i586-asm_32.o salsa20_glue.o
diff --git a/arch/x86/crypto/crc32c-intel.c b/arch/x86/crypto/crc32c-intel.c
new file mode 100644
index 0000000..070afc5
--- /dev/null
+++ b/arch/x86/crypto/crc32c-intel.c
@@ -0,0 +1,197 @@
+/*
+ * Using hardware provided CRC32 instruction to accelerate the CRC32 disposal.
+ * CRC32C polynomial:0x1EDC6F41(BE)/0x82F63B78(LE)
+ * CRC32 is a new instruction in Intel SSE4.2, the reference can be found at:
+ * http://www.intel.com/products/processor/manuals/
+ * Intel(R) 64 and IA-32 Architectures Software Developer's Manual
+ * Volume 2A: Instruction Set Reference, A-M
+ *
+ * Copyright (c) 2008 Austin Zhang <austin_zhang@linux.intel.com>
+ * Copyright (c) 2008 Kent Liu <kent.liu@intel.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/init.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <crypto/internal/hash.h>
+
+#include <asm/cpufeature.h>
+
+#define CHKSUM_BLOCK_SIZE	1
+#define CHKSUM_DIGEST_SIZE	4
+
+#define SCALE_F	sizeof(unsigned long)
+
+#ifdef CONFIG_X86_64
+#define REX_PRE "0x48, "
+#else
+#define REX_PRE
+#endif
+
+static u32 crc32c_intel_le_hw_byte(u32 crc, unsigned char const *data, size_t length)
+{
+	while (length--) {
+		__asm__ __volatile__(
+			".byte 0xf2, 0xf, 0x38, 0xf0, 0xf1"
+			:"=S"(crc)
+			:"0"(crc), "c"(*data)
+		);
+		data++;
+	}
+
+	return crc;
+}
+
+static u32 __pure crc32c_intel_le_hw(u32 crc, unsigned char const *p, size_t len)
+{
+	unsigned int iquotient = len / SCALE_F;
+	unsigned int iremainder = len % SCALE_F;
+	unsigned long *ptmp = (unsigned long *)p;
+
+	while (iquotient--) {
+		__asm__ __volatile__(
+			".byte 0xf2, " REX_PRE "0xf, 0x38, 0xf1, 0xf1;"
+			:"=S"(crc)
+			:"0"(crc), "c"(*ptmp)
+		);
+		ptmp++;
+	}
+
+	if (iremainder)
+		crc = crc32c_intel_le_hw_byte(crc, (unsigned char *)ptmp,
+				 iremainder);
+
+	return crc;
+}
+
+/*
+ * Setting the seed allows arbitrary accumulators and flexible XOR policy
+ * If your algorithm starts with ~0, then XOR with ~0 before you set
+ * the seed.
+ */
+static int crc32c_intel_setkey(struct crypto_ahash *hash, const u8 *key,
+			unsigned int keylen)
+{
+	u32 *mctx = crypto_ahash_ctx(hash);
+
+	if (keylen != sizeof(u32)) {
+		crypto_ahash_set_flags(hash, CRYPTO_TFM_RES_BAD_KEY_LEN);
+		return -EINVAL;
+	}
+	*mctx = le32_to_cpup((__le32 *)key);
+	return 0;
+}
+
+static int crc32c_intel_init(struct ahash_request *req)
+{
+	u32 *mctx = crypto_ahash_ctx(crypto_ahash_reqtfm(req));
+	u32 *crcp = ahash_request_ctx(req);
+
+	*crcp = *mctx;
+
+	return 0;
+}
+
+static int crc32c_intel_update(struct ahash_request *req)
+{
+	struct crypto_hash_walk walk;
+	u32 *crcp = ahash_request_ctx(req);
+	u32 crc = *crcp;
+	int nbytes;
+
+	for (nbytes = crypto_hash_walk_first(req, &walk); nbytes;
+	   nbytes = crypto_hash_walk_done(&walk, 0))
+	crc = crc32c_intel_le_hw(crc, walk.data, nbytes);
+
+	*crcp = crc;
+	return 0;
+}
+
+static int crc32c_intel_final(struct ahash_request *req)
+{
+	u32 *crcp = ahash_request_ctx(req);
+
+	*(__le32 *)req->result = ~cpu_to_le32p(crcp);
+	return 0;
+}
+
+static int crc32c_intel_digest(struct ahash_request *req)
+{
+	struct crypto_hash_walk walk;
+	u32 *mctx = crypto_ahash_ctx(crypto_ahash_reqtfm(req));
+	u32 crc = *mctx;
+	int nbytes;
+
+	for (nbytes = crypto_hash_walk_first(req, &walk); nbytes;
+	   nbytes = crypto_hash_walk_done(&walk, 0))
+		crc = crc32c_intel_le_hw(crc, walk.data, nbytes);
+
+	*(__le32 *)req->result = ~cpu_to_le32(crc);
+	return 0;
+}
+
+static int crc32c_intel_cra_init(struct crypto_tfm *tfm)
+{
+	u32 *key = crypto_tfm_ctx(tfm);
+
+	*key = ~0;
+
+	tfm->crt_ahash.reqsize = sizeof(u32);
+
+	return 0;
+}
+
+static struct crypto_alg alg = {
+	.cra_name               =       "crc32c",
+	.cra_driver_name        =       "crc32c-intel",
+	.cra_priority           =       200,
+	.cra_flags              =       CRYPTO_ALG_TYPE_AHASH,
+	.cra_blocksize          =       CHKSUM_BLOCK_SIZE,
+	.cra_alignmask          =       3,
+	.cra_ctxsize            =       sizeof(u32),
+	.cra_module             =       THIS_MODULE,
+	.cra_list               =       LIST_HEAD_INIT(alg.cra_list),
+	.cra_init               =       crc32c_intel_cra_init,
+	.cra_type               =       &crypto_ahash_type,
+	.cra_u                  =       {
+		.ahash = {
+			.digestsize    =       CHKSUM_DIGEST_SIZE,
+			.setkey        =       crc32c_intel_setkey,
+			.init          =       crc32c_intel_init,
+			.update        =       crc32c_intel_update,
+			.final         =       crc32c_intel_final,
+			.digest        =       crc32c_intel_digest,
+		}
+	}
+};
+
+
+static int __init crc32c_intel_mod_init(void)
+{
+	if (cpu_has_xmm4_2)
+		return crypto_register_alg(&alg);
+	else
+		return -ENODEV;
+}
+
+static void __exit crc32c_intel_mod_fini(void)
+{
+	crypto_unregister_alg(&alg);
+}
+
+module_init(crc32c_intel_mod_init);
+module_exit(crc32c_intel_mod_fini);
+
+MODULE_AUTHOR("Austin Zhang <austin.zhang@intel.com>, Kent Liu <kent.liu@intel.com>");
+MODULE_DESCRIPTION("CRC32c (Castagnoli) optimization using Intel Hardware.");
+MODULE_LICENSE("GPL");
+
+MODULE_ALIAS("crc32c");
+MODULE_ALIAS("crc32c-intel");
+
diff --git a/arch/x86/ia32/ia32_aout.c b/arch/x86/ia32/ia32_aout.c
index a0e1dbe..127ec3f 100644
--- a/arch/x86/ia32/ia32_aout.c
+++ b/arch/x86/ia32/ia32_aout.c
@@ -85,8 +85,10 @@
 	dump->regs.ax = regs->ax;
 	dump->regs.ds = current->thread.ds;
 	dump->regs.es = current->thread.es;
-	asm("movl %%fs,%0" : "=r" (fs)); dump->regs.fs = fs;
-	asm("movl %%gs,%0" : "=r" (gs)); dump->regs.gs = gs;
+	savesegment(fs, fs);
+	dump->regs.fs = fs;
+	savesegment(gs, gs);
+	dump->regs.gs = gs;
 	dump->regs.orig_ax = regs->orig_ax;
 	dump->regs.ip = regs->ip;
 	dump->regs.cs = regs->cs;
@@ -430,8 +432,9 @@
 	current->mm->start_stack =
 		(unsigned long)create_aout_tables((char __user *)bprm->p, bprm);
 	/* start thread */
-	asm volatile("movl %0,%%fs" :: "r" (0)); \
-	asm volatile("movl %0,%%es; movl %0,%%ds": :"r" (__USER32_DS));
+	loadsegment(fs, 0);
+	loadsegment(ds, __USER32_DS);
+	loadsegment(es, __USER32_DS);
 	load_gs_index(0);
 	(regs)->ip = ex.a_entry;
 	(regs)->sp = current->mm->start_stack;
diff --git a/arch/x86/ia32/ia32_signal.c b/arch/x86/ia32/ia32_signal.c
index 20af4c7..4bc02b2 100644
--- a/arch/x86/ia32/ia32_signal.c
+++ b/arch/x86/ia32/ia32_signal.c
@@ -179,9 +179,10 @@
 	u32 pretcode;
 	int sig;
 	struct sigcontext_ia32 sc;
-	struct _fpstate_ia32 fpstate;
+	struct _fpstate_ia32 fpstate_unused; /* look at kernel/sigframe.h */
 	unsigned int extramask[_COMPAT_NSIG_WORDS-1];
 	char retcode[8];
+	/* fp state follows here */
 };
 
 struct rt_sigframe
@@ -192,8 +193,8 @@
 	u32 puc;
 	compat_siginfo_t info;
 	struct ucontext_ia32 uc;
-	struct _fpstate_ia32 fpstate;
 	char retcode[8];
+	/* fp state follows here */
 };
 
 #define COPY(x)		{ 		\
@@ -206,7 +207,7 @@
 	{ unsigned int cur;						\
 	  unsigned short pre;						\
 	  err |= __get_user(pre, &sc->seg);				\
-	  asm volatile("movl %%" #seg ",%0" : "=r" (cur));		\
+	  savesegment(seg, cur);					\
 	  pre |= mask;							\
 	  if (pre != cur) loadsegment(seg, pre); }
 
@@ -215,7 +216,7 @@
 				   unsigned int *peax)
 {
 	unsigned int tmpflags, gs, oldgs, err = 0;
-	struct _fpstate_ia32 __user *buf;
+	void __user *buf;
 	u32 tmp;
 
 	/* Always make any pending restarted system calls return -EINTR */
@@ -235,7 +236,7 @@
 	 */
 	err |= __get_user(gs, &sc->gs);
 	gs |= 3;
-	asm("movl %%gs,%0" : "=r" (oldgs));
+	savesegment(gs, oldgs);
 	if (gs != oldgs)
 		load_gs_index(gs);
 
@@ -259,26 +260,12 @@
 
 	err |= __get_user(tmp, &sc->fpstate);
 	buf = compat_ptr(tmp);
-	if (buf) {
-		if (!access_ok(VERIFY_READ, buf, sizeof(*buf)))
-			goto badframe;
-		err |= restore_i387_ia32(buf);
-	} else {
-		struct task_struct *me = current;
-
-		if (used_math()) {
-			clear_fpu(me);
-			clear_used_math();
-		}
-	}
+	err |= restore_i387_xstate_ia32(buf);
 
 	err |= __get_user(tmp, &sc->ax);
 	*peax = tmp;
 
 	return err;
-
-badframe:
-	return 1;
 }
 
 asmlinkage long sys32_sigreturn(struct pt_regs *regs)
@@ -350,46 +337,42 @@
  */
 
 static int ia32_setup_sigcontext(struct sigcontext_ia32 __user *sc,
-				 struct _fpstate_ia32 __user *fpstate,
+				 void __user *fpstate,
 				 struct pt_regs *regs, unsigned int mask)
 {
 	int tmp, err = 0;
 
-	tmp = 0;
-	__asm__("movl %%gs,%0" : "=r"(tmp): "0"(tmp));
+	savesegment(gs, tmp);
 	err |= __put_user(tmp, (unsigned int __user *)&sc->gs);
-	__asm__("movl %%fs,%0" : "=r"(tmp): "0"(tmp));
+	savesegment(fs, tmp);
 	err |= __put_user(tmp, (unsigned int __user *)&sc->fs);
-	__asm__("movl %%ds,%0" : "=r"(tmp): "0"(tmp));
+	savesegment(ds, tmp);
 	err |= __put_user(tmp, (unsigned int __user *)&sc->ds);
-	__asm__("movl %%es,%0" : "=r"(tmp): "0"(tmp));
+	savesegment(es, tmp);
 	err |= __put_user(tmp, (unsigned int __user *)&sc->es);
 
-	err |= __put_user((u32)regs->di, &sc->di);
-	err |= __put_user((u32)regs->si, &sc->si);
-	err |= __put_user((u32)regs->bp, &sc->bp);
-	err |= __put_user((u32)regs->sp, &sc->sp);
-	err |= __put_user((u32)regs->bx, &sc->bx);
-	err |= __put_user((u32)regs->dx, &sc->dx);
-	err |= __put_user((u32)regs->cx, &sc->cx);
-	err |= __put_user((u32)regs->ax, &sc->ax);
-	err |= __put_user((u32)regs->cs, &sc->cs);
-	err |= __put_user((u32)regs->ss, &sc->ss);
+	err |= __put_user(regs->di, &sc->di);
+	err |= __put_user(regs->si, &sc->si);
+	err |= __put_user(regs->bp, &sc->bp);
+	err |= __put_user(regs->sp, &sc->sp);
+	err |= __put_user(regs->bx, &sc->bx);
+	err |= __put_user(regs->dx, &sc->dx);
+	err |= __put_user(regs->cx, &sc->cx);
+	err |= __put_user(regs->ax, &sc->ax);
+	err |= __put_user(regs->cs, &sc->cs);
+	err |= __put_user(regs->ss, &sc->ss);
 	err |= __put_user(current->thread.trap_no, &sc->trapno);
 	err |= __put_user(current->thread.error_code, &sc->err);
-	err |= __put_user((u32)regs->ip, &sc->ip);
-	err |= __put_user((u32)regs->flags, &sc->flags);
-	err |= __put_user((u32)regs->sp, &sc->sp_at_signal);
+	err |= __put_user(regs->ip, &sc->ip);
+	err |= __put_user(regs->flags, &sc->flags);
+	err |= __put_user(regs->sp, &sc->sp_at_signal);
 
-	tmp = save_i387_ia32(fpstate);
+	tmp = save_i387_xstate_ia32(fpstate);
 	if (tmp < 0)
 		err = -EFAULT;
-	else {
-		clear_used_math();
-		stts();
+	else
 		err |= __put_user(ptr_to_compat(tmp ? fpstate : NULL),
 					&sc->fpstate);
-	}
 
 	/* non-iBCS2 extensions.. */
 	err |= __put_user(mask, &sc->oldmask);
@@ -402,7 +385,8 @@
  * Determine which stack to use..
  */
 static void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs,
-				 size_t frame_size)
+				 size_t frame_size,
+				 void **fpstate)
 {
 	unsigned long sp;
 
@@ -421,6 +405,11 @@
 		 ka->sa.sa_restorer)
 		sp = (unsigned long) ka->sa.sa_restorer;
 
+	if (used_math()) {
+		sp = sp - sig_xstate_ia32_size;
+		*fpstate = (struct _fpstate_ia32 *) sp;
+	}
+
 	sp -= frame_size;
 	/* Align the stack pointer according to the i386 ABI,
 	 * i.e. so that on function entry ((sp + 4) & 15) == 0. */
@@ -434,6 +423,7 @@
 	struct sigframe __user *frame;
 	void __user *restorer;
 	int err = 0;
+	void __user *fpstate = NULL;
 
 	/* copy_to_user optimizes that into a single 8 byte store */
 	static const struct {
@@ -448,25 +438,21 @@
 		0,
 	};
 
-	frame = get_sigframe(ka, regs, sizeof(*frame));
+	frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate);
 
 	if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
-		goto give_sigsegv;
+		return -EFAULT;
 
-	err |= __put_user(sig, &frame->sig);
-	if (err)
-		goto give_sigsegv;
+	if (__put_user(sig, &frame->sig))
+		return -EFAULT;
 
-	err |= ia32_setup_sigcontext(&frame->sc, &frame->fpstate, regs,
-					set->sig[0]);
-	if (err)
-		goto give_sigsegv;
+	if (ia32_setup_sigcontext(&frame->sc, fpstate, regs, set->sig[0]))
+		return -EFAULT;
 
 	if (_COMPAT_NSIG_WORDS > 1) {
-		err |= __copy_to_user(frame->extramask, &set->sig[1],
-				      sizeof(frame->extramask));
-		if (err)
-			goto give_sigsegv;
+		if (__copy_to_user(frame->extramask, &set->sig[1],
+				   sizeof(frame->extramask)))
+			return -EFAULT;
 	}
 
 	if (ka->sa.sa_flags & SA_RESTORER) {
@@ -487,7 +473,7 @@
 	 */
 	err |= __copy_to_user(frame->retcode, &code, 8);
 	if (err)
-		goto give_sigsegv;
+		return -EFAULT;
 
 	/* Set up registers for signal handler */
 	regs->sp = (unsigned long) frame;
@@ -498,8 +484,8 @@
 	regs->dx = 0;
 	regs->cx = 0;
 
-	asm volatile("movl %0,%%ds" :: "r" (__USER32_DS));
-	asm volatile("movl %0,%%es" :: "r" (__USER32_DS));
+	loadsegment(ds, __USER32_DS);
+	loadsegment(es, __USER32_DS);
 
 	regs->cs = __USER32_CS;
 	regs->ss = __USER32_DS;
@@ -510,10 +496,6 @@
 #endif
 
 	return 0;
-
-give_sigsegv:
-	force_sigsegv(sig, current);
-	return -EFAULT;
 }
 
 int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
@@ -522,6 +504,7 @@
 	struct rt_sigframe __user *frame;
 	void __user *restorer;
 	int err = 0;
+	void __user *fpstate = NULL;
 
 	/* __copy_to_user optimizes that into a single 8 byte store */
 	static const struct {
@@ -537,30 +520,33 @@
 		0,
 	};
 
-	frame = get_sigframe(ka, regs, sizeof(*frame));
+	frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate);
 
 	if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
-		goto give_sigsegv;
+		return -EFAULT;
 
 	err |= __put_user(sig, &frame->sig);
 	err |= __put_user(ptr_to_compat(&frame->info), &frame->pinfo);
 	err |= __put_user(ptr_to_compat(&frame->uc), &frame->puc);
 	err |= copy_siginfo_to_user32(&frame->info, info);
 	if (err)
-		goto give_sigsegv;
+		return -EFAULT;
 
 	/* Create the ucontext.  */
-	err |= __put_user(0, &frame->uc.uc_flags);
+	if (cpu_has_xsave)
+		err |= __put_user(UC_FP_XSTATE, &frame->uc.uc_flags);
+	else
+		err |= __put_user(0, &frame->uc.uc_flags);
 	err |= __put_user(0, &frame->uc.uc_link);
 	err |= __put_user(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp);
 	err |= __put_user(sas_ss_flags(regs->sp),
 			  &frame->uc.uc_stack.ss_flags);
 	err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
-	err |= ia32_setup_sigcontext(&frame->uc.uc_mcontext, &frame->fpstate,
+	err |= ia32_setup_sigcontext(&frame->uc.uc_mcontext, fpstate,
 				     regs, set->sig[0]);
 	err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
 	if (err)
-		goto give_sigsegv;
+		return -EFAULT;
 
 	if (ka->sa.sa_flags & SA_RESTORER)
 		restorer = ka->sa.sa_restorer;
@@ -575,7 +561,7 @@
 	 */
 	err |= __copy_to_user(frame->retcode, &code, 8);
 	if (err)
-		goto give_sigsegv;
+		return -EFAULT;
 
 	/* Set up registers for signal handler */
 	regs->sp = (unsigned long) frame;
@@ -591,8 +577,8 @@
 	regs->dx = (unsigned long) &frame->info;
 	regs->cx = (unsigned long) &frame->uc;
 
-	asm volatile("movl %0,%%ds" :: "r" (__USER32_DS));
-	asm volatile("movl %0,%%es" :: "r" (__USER32_DS));
+	loadsegment(ds, __USER32_DS);
+	loadsegment(es, __USER32_DS);
 
 	regs->cs = __USER32_CS;
 	regs->ss = __USER32_DS;
@@ -603,8 +589,4 @@
 #endif
 
 	return 0;
-
-give_sigsegv:
-	force_sigsegv(sig, current);
-	return -EFAULT;
 }
diff --git a/arch/x86/ia32/ia32entry.S b/arch/x86/ia32/ia32entry.S
index ffc1bb4..eb43147 100644
--- a/arch/x86/ia32/ia32entry.S
+++ b/arch/x86/ia32/ia32entry.S
@@ -39,11 +39,11 @@
 	.endm 
 
 	/* clobbers %eax */	
-	.macro  CLEAR_RREGS
+	.macro  CLEAR_RREGS _r9=rax
 	xorl 	%eax,%eax
 	movq	%rax,R11(%rsp)
 	movq	%rax,R10(%rsp)
-	movq	%rax,R9(%rsp)
+	movq	%\_r9,R9(%rsp)
 	movq	%rax,R8(%rsp)
 	.endm
 
@@ -52,11 +52,10 @@
 	 * We don't reload %eax because syscall_trace_enter() returned
 	 * the value it wants us to use in the table lookup.
 	 */
-	.macro LOAD_ARGS32 offset
-	movl \offset(%rsp),%r11d
-	movl \offset+8(%rsp),%r10d
+	.macro LOAD_ARGS32 offset, _r9=0
+	.if \_r9
 	movl \offset+16(%rsp),%r9d
-	movl \offset+24(%rsp),%r8d
+	.endif
 	movl \offset+40(%rsp),%ecx
 	movl \offset+48(%rsp),%edx
 	movl \offset+56(%rsp),%esi
@@ -145,7 +144,7 @@
 	SAVE_ARGS 0,0,1
  	/* no need to do an access_ok check here because rbp has been
  	   32bit zero extended */ 
-1:	movl	(%rbp),%r9d
+1:	movl	(%rbp),%ebp
  	.section __ex_table,"a"
  	.quad 1b,ia32_badarg
  	.previous	
@@ -157,7 +156,7 @@
 	cmpl	$(IA32_NR_syscalls-1),%eax
 	ja	ia32_badsys
 sysenter_do_call:
-	IA32_ARG_FIXUP 1
+	IA32_ARG_FIXUP
 sysenter_dispatch:
 	call	*ia32_sys_call_table(,%rax,8)
 	movq	%rax,RAX-ARGOFFSET(%rsp)
@@ -234,20 +233,17 @@
 #endif
 
 sysenter_tracesys:
-	xchgl	%r9d,%ebp
 #ifdef CONFIG_AUDITSYSCALL
 	testl	$(_TIF_WORK_SYSCALL_ENTRY & ~_TIF_SYSCALL_AUDIT),TI_flags(%r10)
 	jz	sysenter_auditsys
 #endif
 	SAVE_REST
 	CLEAR_RREGS
-	movq	%r9,R9(%rsp)
 	movq	$-ENOSYS,RAX(%rsp)/* ptrace can change this for a bad syscall */
 	movq	%rsp,%rdi        /* &pt_regs -> arg1 */
 	call	syscall_trace_enter
 	LOAD_ARGS32 ARGOFFSET  /* reload args from stack in case ptrace changed it */
 	RESTORE_REST
-	xchgl	%ebp,%r9d
 	cmpl	$(IA32_NR_syscalls-1),%eax
 	ja	int_ret_from_sys_call /* sysenter_tracesys has set RAX(%rsp) */
 	jmp	sysenter_do_call
@@ -314,9 +310,9 @@
 	testl $_TIF_WORK_SYSCALL_ENTRY,TI_flags(%r10)
 	CFI_REMEMBER_STATE
 	jnz   cstar_tracesys
-cstar_do_call:	
 	cmpl $IA32_NR_syscalls-1,%eax
 	ja  ia32_badsys
+cstar_do_call:
 	IA32_ARG_FIXUP 1
 cstar_dispatch:
 	call *ia32_sys_call_table(,%rax,8)
@@ -357,15 +353,13 @@
 #endif
 	xchgl %r9d,%ebp
 	SAVE_REST
-	CLEAR_RREGS
-	movq %r9,R9(%rsp)
+	CLEAR_RREGS r9
 	movq $-ENOSYS,RAX(%rsp)	/* ptrace can change this for a bad syscall */
 	movq %rsp,%rdi        /* &pt_regs -> arg1 */
 	call syscall_trace_enter
-	LOAD_ARGS32 ARGOFFSET  /* reload args from stack in case ptrace changed it */
+	LOAD_ARGS32 ARGOFFSET, 1  /* reload args from stack in case ptrace changed it */
 	RESTORE_REST
 	xchgl %ebp,%r9d
-	movl RSP-ARGOFFSET(%rsp), %r8d
 	cmpl $(IA32_NR_syscalls-1),%eax
 	ja int_ret_from_sys_call /* cstar_tracesys has set RAX(%rsp) */
 	jmp cstar_do_call
diff --git a/arch/x86/ia32/sys_ia32.c b/arch/x86/ia32/sys_ia32.c
index d3c6408..beda423 100644
--- a/arch/x86/ia32/sys_ia32.c
+++ b/arch/x86/ia32/sys_ia32.c
@@ -556,15 +556,6 @@
 	return ret;
 }
 
-/* These are here just in case some old ia32 binary calls it. */
-asmlinkage long sys32_pause(void)
-{
-	current->state = TASK_INTERRUPTIBLE;
-	schedule();
-	return -ERESTARTNOHAND;
-}
-
-
 #ifdef CONFIG_SYSCTL_SYSCALL
 struct sysctl_ia32 {
 	unsigned int	name;
diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile
index 3db651f..0d41f03 100644
--- a/arch/x86/kernel/Makefile
+++ b/arch/x86/kernel/Makefile
@@ -10,7 +10,7 @@
 # Do not profile debug and lowlevel utilities
 CFLAGS_REMOVE_tsc.o = -pg
 CFLAGS_REMOVE_rtc.o = -pg
-CFLAGS_REMOVE_paravirt.o = -pg
+CFLAGS_REMOVE_paravirt-spinlocks.o = -pg
 endif
 
 #
@@ -23,7 +23,7 @@
 CFLAGS_tsc.o		:= $(nostackp)
 
 obj-y			:= process_$(BITS).o signal_$(BITS).o entry_$(BITS).o
-obj-y			+= traps_$(BITS).o irq_$(BITS).o
+obj-y			+= traps.o irq_$(BITS).o dumpstack_$(BITS).o
 obj-y			+= time_$(BITS).o ioport.o ldt.o
 obj-y			+= setup.o i8259.o irqinit_$(BITS).o setup_percpu.o
 obj-$(CONFIG_X86_VISWS)	+= visws_quirks.o
@@ -38,7 +38,7 @@
 
 obj-$(CONFIG_X86_TRAMPOLINE)	+= trampoline.o
 obj-y				+= process.o
-obj-y				+= i387.o
+obj-y				+= i387.o xsave.o
 obj-y				+= ptrace.o
 obj-y				+= ds.o
 obj-$(CONFIG_X86_32)		+= tls.o
@@ -51,7 +51,6 @@
 obj-$(CONFIG_MCA)		+= mca_32.o
 obj-$(CONFIG_X86_MSR)		+= msr.o
 obj-$(CONFIG_X86_CPUID)		+= cpuid.o
-obj-$(CONFIG_MICROCODE)		+= microcode.o
 obj-$(CONFIG_PCI)		+= early-quirks.o
 apm-y				:= apm_32.o
 obj-$(CONFIG_APM)		+= apm.o
@@ -69,6 +68,7 @@
 obj-$(CONFIG_KEXEC)		+= relocate_kernel_$(BITS).o crash.o
 obj-$(CONFIG_CRASH_DUMP)	+= crash_dump_$(BITS).o
 obj-$(CONFIG_X86_NUMAQ)		+= numaq_32.o
+obj-$(CONFIG_X86_ES7000)	+= es7000_32.o
 obj-$(CONFIG_X86_SUMMIT_NUMA)	+= summit_32.o
 obj-y				+= vsmp_64.o
 obj-$(CONFIG_KPROBES)		+= kprobes.o
@@ -89,7 +89,7 @@
 obj-$(CONFIG_VMI)		+= vmi_32.o vmiclock_32.o
 obj-$(CONFIG_KVM_GUEST)		+= kvm.o
 obj-$(CONFIG_KVM_CLOCK)		+= kvmclock.o
-obj-$(CONFIG_PARAVIRT)		+= paravirt.o paravirt_patch_$(BITS).o
+obj-$(CONFIG_PARAVIRT)		+= paravirt.o paravirt_patch_$(BITS).o paravirt-spinlocks.o
 obj-$(CONFIG_PARAVIRT_CLOCK)	+= pvclock.o
 
 obj-$(CONFIG_PCSPKR_PLATFORM)	+= pcspeaker.o
@@ -99,11 +99,18 @@
 
 obj-$(CONFIG_OLPC)		+= olpc.o
 
+microcode-y				:= microcode_core.o
+microcode-$(CONFIG_MICROCODE_INTEL)	+= microcode_intel.o
+microcode-$(CONFIG_MICROCODE_AMD)	+= microcode_amd.o
+obj-$(CONFIG_MICROCODE)			+= microcode.o
+
 ###
 # 64 bit specific files
 ifeq ($(CONFIG_X86_64),y)
         obj-y				+= genapic_64.o genapic_flat_64.o genx2apic_uv_x.o tlb_uv.o
 	obj-y				+= bios_uv.o
+        obj-y				+= genx2apic_cluster.o
+        obj-y				+= genx2apic_phys.o
         obj-$(CONFIG_X86_PM_TIMER)	+= pmtimer_64.o
         obj-$(CONFIG_AUDIT)		+= audit_64.o
 
diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c
index bfd10fd..eb875cd 100644
--- a/arch/x86/kernel/acpi/boot.c
+++ b/arch/x86/kernel/acpi/boot.c
@@ -58,7 +58,6 @@
 #ifdef	CONFIG_X86_64
 
 #include <asm/proto.h>
-#include <asm/genapic.h>
 
 #else				/* X86 */
 
@@ -97,8 +96,6 @@
 #warning ACPI uses CMPXCHG, i486 and later hardware
 #endif
 
-static int acpi_mcfg_64bit_base_addr __initdata = FALSE;
-
 /* --------------------------------------------------------------------------
                               Boot-time Configuration
    -------------------------------------------------------------------------- */
@@ -160,6 +157,8 @@
 struct acpi_mcfg_allocation *pci_mmcfg_config;
 int pci_mmcfg_config_num;
 
+static int acpi_mcfg_64bit_base_addr __initdata = FALSE;
+
 static int __init acpi_mcfg_oem_check(struct acpi_table_mcfg *mcfg)
 {
 	if (!strcmp(mcfg->header.oem_id, "SGI"))
@@ -253,10 +252,8 @@
 		return;
 	}
 
-#ifdef CONFIG_X86_32
 	if (boot_cpu_physical_apicid != -1U)
 		ver = apic_version[boot_cpu_physical_apicid];
-#endif
 
 	generic_processor_info(id, ver);
 }
@@ -775,11 +772,9 @@
 
 	set_fixmap_nocache(FIX_APIC_BASE, address);
 	if (boot_cpu_physical_apicid == -1U) {
-		boot_cpu_physical_apicid  = GET_APIC_ID(read_apic_id());
-#ifdef CONFIG_X86_32
+		boot_cpu_physical_apicid  = read_apic_id();
 		apic_version[boot_cpu_physical_apicid] =
 			 GET_APIC_VERSION(apic_read(APIC_LVR));
-#endif
 	}
 }
 
@@ -1351,7 +1346,9 @@
 				acpi_ioapic = 1;
 
 				smp_found_config = 1;
+#ifdef CONFIG_X86_32
 				setup_apic_routing();
+#endif
 			}
 		}
 		if (error == -EINVAL) {
@@ -1421,8 +1418,16 @@
  */
 static int __init dmi_ignore_irq0_timer_override(const struct dmi_system_id *d)
 {
-	pr_notice("%s detected: Ignoring BIOS IRQ0 pin2 override\n", d->ident);
-	acpi_skip_timer_override = 1;
+	/*
+	 * The ati_ixp4x0_rev() early PCI quirk should have set
+	 * the acpi_skip_timer_override flag already:
+	 */
+	if (!acpi_skip_timer_override) {
+		WARN(1, KERN_ERR "ati_ixp4x0 quirk not complete.\n");
+		pr_notice("%s detected: Ignoring BIOS IRQ0 pin2 override\n",
+			d->ident);
+		acpi_skip_timer_override = 1;
+	}
 	return 0;
 }
 
@@ -1605,6 +1610,14 @@
 	 */
 	{
 	 .callback = dmi_ignore_irq0_timer_override,
+	 .ident = "HP nx6115 laptop",
+	 .matches = {
+		     DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
+		     DMI_MATCH(DMI_PRODUCT_NAME, "HP Compaq nx6115"),
+		     },
+	 },
+	{
+	 .callback = dmi_ignore_irq0_timer_override,
 	 .ident = "HP NX6125 laptop",
 	 .matches = {
 		     DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
@@ -1619,6 +1632,14 @@
 		     DMI_MATCH(DMI_PRODUCT_NAME, "HP Compaq nx6325"),
 		     },
 	 },
+	{
+	 .callback = dmi_ignore_irq0_timer_override,
+	 .ident = "HP 6715b laptop",
+	 .matches = {
+		     DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
+		     DMI_MATCH(DMI_PRODUCT_NAME, "HP Compaq 6715b"),
+		     },
+	 },
 	{}
 };
 
diff --git a/arch/x86/kernel/alternative.c b/arch/x86/kernel/alternative.c
index 65a0c1b..a84ac7b 100644
--- a/arch/x86/kernel/alternative.c
+++ b/arch/x86/kernel/alternative.c
@@ -231,25 +231,25 @@
 			continue;
 		if (*ptr > text_end)
 			continue;
-		text_poke(*ptr, ((unsigned char []){0xf0}), 1); /* add lock prefix */
+		/* turn DS segment override prefix into lock prefix */
+		text_poke(*ptr, ((unsigned char []){0xf0}), 1);
 	};
 }
 
 static void alternatives_smp_unlock(u8 **start, u8 **end, u8 *text, u8 *text_end)
 {
 	u8 **ptr;
-	char insn[1];
 
 	if (noreplace_smp)
 		return;
 
-	add_nops(insn, 1);
 	for (ptr = start; ptr < end; ptr++) {
 		if (*ptr < text)
 			continue;
 		if (*ptr > text_end)
 			continue;
-		text_poke(*ptr, insn, 1);
+		/* turn lock prefix into DS segment override prefix */
+		text_poke(*ptr, ((unsigned char []){0x3E}), 1);
 	};
 }
 
@@ -444,7 +444,7 @@
 					    _text, _etext);
 
 		/* Only switch to UP mode if we don't immediately boot others */
-		if (num_possible_cpus() == 1 || setup_max_cpus <= 1)
+		if (num_present_cpus() == 1 || setup_max_cpus <= 1)
 			alternatives_smp_switch(0);
 	}
 #endif
diff --git a/arch/x86/kernel/amd_iommu.c b/arch/x86/kernel/amd_iommu.c
index 69b4d06..34e4d11 100644
--- a/arch/x86/kernel/amd_iommu.c
+++ b/arch/x86/kernel/amd_iommu.c
@@ -33,6 +33,10 @@
 
 static DEFINE_RWLOCK(amd_iommu_devtable_lock);
 
+/* A list of preallocated protection domains */
+static LIST_HEAD(iommu_pd_list);
+static DEFINE_SPINLOCK(iommu_pd_list_lock);
+
 /*
  * general struct to manage commands send to an IOMMU
  */
@@ -51,6 +55,102 @@
 
 /****************************************************************************
  *
+ * Interrupt handling functions
+ *
+ ****************************************************************************/
+
+static void iommu_print_event(void *__evt)
+{
+	u32 *event = __evt;
+	int type  = (event[1] >> EVENT_TYPE_SHIFT)  & EVENT_TYPE_MASK;
+	int devid = (event[0] >> EVENT_DEVID_SHIFT) & EVENT_DEVID_MASK;
+	int domid = (event[1] >> EVENT_DOMID_SHIFT) & EVENT_DOMID_MASK;
+	int flags = (event[1] >> EVENT_FLAGS_SHIFT) & EVENT_FLAGS_MASK;
+	u64 address = (u64)(((u64)event[3]) << 32) | event[2];
+
+	printk(KERN_ERR "AMD IOMMU: Event logged [");
+
+	switch (type) {
+	case EVENT_TYPE_ILL_DEV:
+		printk("ILLEGAL_DEV_TABLE_ENTRY device=%02x:%02x.%x "
+		       "address=0x%016llx flags=0x%04x]\n",
+		       PCI_BUS(devid), PCI_SLOT(devid), PCI_FUNC(devid),
+		       address, flags);
+		break;
+	case EVENT_TYPE_IO_FAULT:
+		printk("IO_PAGE_FAULT device=%02x:%02x.%x "
+		       "domain=0x%04x address=0x%016llx flags=0x%04x]\n",
+		       PCI_BUS(devid), PCI_SLOT(devid), PCI_FUNC(devid),
+		       domid, address, flags);
+		break;
+	case EVENT_TYPE_DEV_TAB_ERR:
+		printk("DEV_TAB_HARDWARE_ERROR device=%02x:%02x.%x "
+		       "address=0x%016llx flags=0x%04x]\n",
+		       PCI_BUS(devid), PCI_SLOT(devid), PCI_FUNC(devid),
+		       address, flags);
+		break;
+	case EVENT_TYPE_PAGE_TAB_ERR:
+		printk("PAGE_TAB_HARDWARE_ERROR device=%02x:%02x.%x "
+		       "domain=0x%04x address=0x%016llx flags=0x%04x]\n",
+		       PCI_BUS(devid), PCI_SLOT(devid), PCI_FUNC(devid),
+		       domid, address, flags);
+		break;
+	case EVENT_TYPE_ILL_CMD:
+		printk("ILLEGAL_COMMAND_ERROR address=0x%016llx]\n", address);
+		break;
+	case EVENT_TYPE_CMD_HARD_ERR:
+		printk("COMMAND_HARDWARE_ERROR address=0x%016llx "
+		       "flags=0x%04x]\n", address, flags);
+		break;
+	case EVENT_TYPE_IOTLB_INV_TO:
+		printk("IOTLB_INV_TIMEOUT device=%02x:%02x.%x "
+		       "address=0x%016llx]\n",
+		       PCI_BUS(devid), PCI_SLOT(devid), PCI_FUNC(devid),
+		       address);
+		break;
+	case EVENT_TYPE_INV_DEV_REQ:
+		printk("INVALID_DEVICE_REQUEST device=%02x:%02x.%x "
+		       "address=0x%016llx flags=0x%04x]\n",
+		       PCI_BUS(devid), PCI_SLOT(devid), PCI_FUNC(devid),
+		       address, flags);
+		break;
+	default:
+		printk(KERN_ERR "UNKNOWN type=0x%02x]\n", type);
+	}
+}
+
+static void iommu_poll_events(struct amd_iommu *iommu)
+{
+	u32 head, tail;
+	unsigned long flags;
+
+	spin_lock_irqsave(&iommu->lock, flags);
+
+	head = readl(iommu->mmio_base + MMIO_EVT_HEAD_OFFSET);
+	tail = readl(iommu->mmio_base + MMIO_EVT_TAIL_OFFSET);
+
+	while (head != tail) {
+		iommu_print_event(iommu->evt_buf + head);
+		head = (head + EVENT_ENTRY_SIZE) % iommu->evt_buf_size;
+	}
+
+	writel(head, iommu->mmio_base + MMIO_EVT_HEAD_OFFSET);
+
+	spin_unlock_irqrestore(&iommu->lock, flags);
+}
+
+irqreturn_t amd_iommu_int_handler(int irq, void *data)
+{
+	struct amd_iommu *iommu;
+
+	list_for_each_entry(iommu, &amd_iommu_list, list)
+		iommu_poll_events(iommu);
+
+	return IRQ_HANDLED;
+}
+
+/****************************************************************************
+ *
  * IOMMU command queuing functions
  *
  ****************************************************************************/
@@ -101,10 +201,10 @@
  */
 static int iommu_completion_wait(struct amd_iommu *iommu)
 {
-	int ret, ready = 0;
+	int ret = 0, ready = 0;
 	unsigned status = 0;
 	struct iommu_cmd cmd;
-	unsigned long i = 0;
+	unsigned long flags, i = 0;
 
 	memset(&cmd, 0, sizeof(cmd));
 	cmd.data[0] = CMD_COMPL_WAIT_INT_MASK;
@@ -112,10 +212,12 @@
 
 	iommu->need_sync = 0;
 
-	ret = iommu_queue_command(iommu, &cmd);
+	spin_lock_irqsave(&iommu->lock, flags);
+
+	ret = __iommu_queue_command(iommu, &cmd);
 
 	if (ret)
-		return ret;
+		goto out;
 
 	while (!ready && (i < EXIT_LOOP_COUNT)) {
 		++i;
@@ -130,6 +232,8 @@
 
 	if (unlikely((i == EXIT_LOOP_COUNT) && printk_ratelimit()))
 		printk(KERN_WARNING "AMD IOMMU: Completion wait loop failed\n");
+out:
+	spin_unlock_irqrestore(&iommu->lock, flags);
 
 	return 0;
 }
@@ -140,6 +244,7 @@
 static int iommu_queue_inv_dev_entry(struct amd_iommu *iommu, u16 devid)
 {
 	struct iommu_cmd cmd;
+	int ret;
 
 	BUG_ON(iommu == NULL);
 
@@ -147,9 +252,11 @@
 	CMD_SET_TYPE(&cmd, CMD_INV_DEV_ENTRY);
 	cmd.data[0] = devid;
 
+	ret = iommu_queue_command(iommu, &cmd);
+
 	iommu->need_sync = 1;
 
-	return iommu_queue_command(iommu, &cmd);
+	return ret;
 }
 
 /*
@@ -159,6 +266,7 @@
 		u64 address, u16 domid, int pde, int s)
 {
 	struct iommu_cmd cmd;
+	int ret;
 
 	memset(&cmd, 0, sizeof(cmd));
 	address &= PAGE_MASK;
@@ -171,9 +279,11 @@
 	if (pde) /* PDE bit - we wan't flush everything not only the PTEs */
 		cmd.data[2] |= CMD_INV_IOMMU_PAGES_PDE_MASK;
 
+	ret = iommu_queue_command(iommu, &cmd);
+
 	iommu->need_sync = 1;
 
-	return iommu_queue_command(iommu, &cmd);
+	return ret;
 }
 
 /*
@@ -203,6 +313,14 @@
 	return 0;
 }
 
+/* Flush the whole IO/TLB for a given protection domain */
+static void iommu_flush_tlb(struct amd_iommu *iommu, u16 domid)
+{
+	u64 address = CMD_INV_IOMMU_ALL_PAGES_ADDRESS;
+
+	iommu_queue_inv_iommu_pages(iommu, address, domid, 0, 1);
+}
+
 /****************************************************************************
  *
  * The functions below are used the create the page table mappings for
@@ -362,11 +480,6 @@
  * efficient allocator.
  *
  ****************************************************************************/
-static unsigned long dma_mask_to_pages(unsigned long mask)
-{
-	return (mask >> PAGE_SHIFT) +
-		(PAGE_ALIGN(mask & ~PAGE_MASK) >> PAGE_SHIFT);
-}
 
 /*
  * The address allocator core function.
@@ -375,25 +488,31 @@
  */
 static unsigned long dma_ops_alloc_addresses(struct device *dev,
 					     struct dma_ops_domain *dom,
-					     unsigned int pages)
+					     unsigned int pages,
+					     unsigned long align_mask,
+					     u64 dma_mask)
 {
-	unsigned long limit = dma_mask_to_pages(*dev->dma_mask);
+	unsigned long limit;
 	unsigned long address;
-	unsigned long size = dom->aperture_size >> PAGE_SHIFT;
 	unsigned long boundary_size;
 
 	boundary_size = ALIGN(dma_get_seg_boundary(dev) + 1,
 			PAGE_SIZE) >> PAGE_SHIFT;
-	limit = limit < size ? limit : size;
+	limit = iommu_device_max_index(dom->aperture_size >> PAGE_SHIFT, 0,
+				       dma_mask >> PAGE_SHIFT);
 
-	if (dom->next_bit >= limit)
+	if (dom->next_bit >= limit) {
 		dom->next_bit = 0;
+		dom->need_flush = true;
+	}
 
 	address = iommu_area_alloc(dom->bitmap, limit, dom->next_bit, pages,
-			0 , boundary_size, 0);
-	if (address == -1)
+				   0 , boundary_size, align_mask);
+	if (address == -1) {
 		address = iommu_area_alloc(dom->bitmap, limit, 0, pages,
-				0, boundary_size, 0);
+				0, boundary_size, align_mask);
+		dom->need_flush = true;
+	}
 
 	if (likely(address != -1)) {
 		dom->next_bit = address + pages;
@@ -459,7 +578,7 @@
 	if (start_page + pages > last_page)
 		pages = last_page - start_page;
 
-	set_bit_string(dom->bitmap, start_page, pages);
+	iommu_area_reserve(dom->bitmap, start_page, pages);
 }
 
 static void dma_ops_free_pagetable(struct dma_ops_domain *dma_dom)
@@ -553,6 +672,9 @@
 	dma_dom->bitmap[0] = 1;
 	dma_dom->next_bit = 0;
 
+	dma_dom->need_flush = false;
+	dma_dom->target_dev = 0xffff;
+
 	/* Intialize the exclusion range if necessary */
 	if (iommu->exclusion_start &&
 	    iommu->exclusion_start < dma_dom->aperture_size) {
@@ -623,12 +745,13 @@
 
 	u64 pte_root = virt_to_phys(domain->pt_root);
 
-	pte_root |= (domain->mode & 0x07) << 9;
-	pte_root |= IOMMU_PTE_IR | IOMMU_PTE_IW | IOMMU_PTE_P | 2;
+	pte_root |= (domain->mode & DEV_ENTRY_MODE_MASK)
+		    << DEV_ENTRY_MODE_SHIFT;
+	pte_root |= IOMMU_PTE_IR | IOMMU_PTE_IW | IOMMU_PTE_P | IOMMU_PTE_TV;
 
 	write_lock_irqsave(&amd_iommu_devtable_lock, flags);
-	amd_iommu_dev_table[devid].data[0] = pte_root;
-	amd_iommu_dev_table[devid].data[1] = pte_root >> 32;
+	amd_iommu_dev_table[devid].data[0] = lower_32_bits(pte_root);
+	amd_iommu_dev_table[devid].data[1] = upper_32_bits(pte_root);
 	amd_iommu_dev_table[devid].data[2] = domain->id;
 
 	amd_iommu_pd_table[devid] = domain;
@@ -646,6 +769,45 @@
  *****************************************************************************/
 
 /*
+ * This function checks if the driver got a valid device from the caller to
+ * avoid dereferencing invalid pointers.
+ */
+static bool check_device(struct device *dev)
+{
+	if (!dev || !dev->dma_mask)
+		return false;
+
+	return true;
+}
+
+/*
+ * In this function the list of preallocated protection domains is traversed to
+ * find the domain for a specific device
+ */
+static struct dma_ops_domain *find_protection_domain(u16 devid)
+{
+	struct dma_ops_domain *entry, *ret = NULL;
+	unsigned long flags;
+
+	if (list_empty(&iommu_pd_list))
+		return NULL;
+
+	spin_lock_irqsave(&iommu_pd_list_lock, flags);
+
+	list_for_each_entry(entry, &iommu_pd_list, list) {
+		if (entry->target_dev == devid) {
+			ret = entry;
+			list_del(&ret->list);
+			break;
+		}
+	}
+
+	spin_unlock_irqrestore(&iommu_pd_list_lock, flags);
+
+	return ret;
+}
+
+/*
  * In the dma_ops path we only have the struct device. This function
  * finds the corresponding IOMMU, the protection domain and the
  * requestor id for a given device.
@@ -661,27 +823,30 @@
 	struct pci_dev *pcidev;
 	u16 _bdf;
 
-	BUG_ON(!dev || dev->bus != &pci_bus_type || !dev->dma_mask);
+	*iommu = NULL;
+	*domain = NULL;
+	*bdf = 0xffff;
+
+	if (dev->bus != &pci_bus_type)
+		return 0;
 
 	pcidev = to_pci_dev(dev);
 	_bdf = calc_devid(pcidev->bus->number, pcidev->devfn);
 
 	/* device not translated by any IOMMU in the system? */
-	if (_bdf > amd_iommu_last_bdf) {
-		*iommu = NULL;
-		*domain = NULL;
-		*bdf = 0xffff;
+	if (_bdf > amd_iommu_last_bdf)
 		return 0;
-	}
 
 	*bdf = amd_iommu_alias_table[_bdf];
 
 	*iommu = amd_iommu_rlookup_table[*bdf];
 	if (*iommu == NULL)
 		return 0;
-	dma_dom = (*iommu)->default_dom;
 	*domain = domain_for_device(*bdf);
 	if (*domain == NULL) {
+		dma_dom = find_protection_domain(*bdf);
+		if (!dma_dom)
+			dma_dom = (*iommu)->default_dom;
 		*domain = &dma_dom->domain;
 		set_device_domain(*iommu, *domain, *bdf);
 		printk(KERN_INFO "AMD IOMMU: Using protection domain %d for "
@@ -760,17 +925,24 @@
 			       struct dma_ops_domain *dma_dom,
 			       phys_addr_t paddr,
 			       size_t size,
-			       int dir)
+			       int dir,
+			       bool align,
+			       u64 dma_mask)
 {
 	dma_addr_t offset = paddr & ~PAGE_MASK;
 	dma_addr_t address, start;
 	unsigned int pages;
+	unsigned long align_mask = 0;
 	int i;
 
 	pages = iommu_num_pages(paddr, size);
 	paddr &= PAGE_MASK;
 
-	address = dma_ops_alloc_addresses(dev, dma_dom, pages);
+	if (align)
+		align_mask = (1UL << get_order(size)) - 1;
+
+	address = dma_ops_alloc_addresses(dev, dma_dom, pages, align_mask,
+					  dma_mask);
 	if (unlikely(address == bad_dma_address))
 		goto out;
 
@@ -782,6 +954,12 @@
 	}
 	address += offset;
 
+	if (unlikely(dma_dom->need_flush && !amd_iommu_unmap_flush)) {
+		iommu_flush_tlb(iommu, dma_dom->domain.id);
+		dma_dom->need_flush = false;
+	} else if (unlikely(iommu_has_npcache(iommu)))
+		iommu_flush_pages(iommu, dma_dom->domain.id, address, size);
+
 out:
 	return address;
 }
@@ -812,6 +990,9 @@
 	}
 
 	dma_ops_free_addresses(dma_dom, dma_addr, pages);
+
+	if (amd_iommu_unmap_flush)
+		iommu_flush_pages(iommu, dma_dom->domain.id, dma_addr, size);
 }
 
 /*
@@ -825,6 +1006,12 @@
 	struct protection_domain *domain;
 	u16 devid;
 	dma_addr_t addr;
+	u64 dma_mask;
+
+	if (!check_device(dev))
+		return bad_dma_address;
+
+	dma_mask = *dev->dma_mask;
 
 	get_device_resources(dev, &iommu, &domain, &devid);
 
@@ -833,14 +1020,12 @@
 		return (dma_addr_t)paddr;
 
 	spin_lock_irqsave(&domain->lock, flags);
-	addr = __map_single(dev, iommu, domain->priv, paddr, size, dir);
+	addr = __map_single(dev, iommu, domain->priv, paddr, size, dir, false,
+			    dma_mask);
 	if (addr == bad_dma_address)
 		goto out;
 
-	if (iommu_has_npcache(iommu))
-		iommu_flush_pages(iommu, domain->id, addr, size);
-
-	if (iommu->need_sync)
+	if (unlikely(iommu->need_sync))
 		iommu_completion_wait(iommu);
 
 out:
@@ -860,7 +1045,8 @@
 	struct protection_domain *domain;
 	u16 devid;
 
-	if (!get_device_resources(dev, &iommu, &domain, &devid))
+	if (!check_device(dev) ||
+	    !get_device_resources(dev, &iommu, &domain, &devid))
 		/* device not handled by any AMD IOMMU */
 		return;
 
@@ -868,9 +1054,7 @@
 
 	__unmap_single(iommu, domain->priv, dma_addr, size, dir);
 
-	iommu_flush_pages(iommu, domain->id, dma_addr, size);
-
-	if (iommu->need_sync)
+	if (unlikely(iommu->need_sync))
 		iommu_completion_wait(iommu);
 
 	spin_unlock_irqrestore(&domain->lock, flags);
@@ -909,6 +1093,12 @@
 	struct scatterlist *s;
 	phys_addr_t paddr;
 	int mapped_elems = 0;
+	u64 dma_mask;
+
+	if (!check_device(dev))
+		return 0;
+
+	dma_mask = *dev->dma_mask;
 
 	get_device_resources(dev, &iommu, &domain, &devid);
 
@@ -921,19 +1111,17 @@
 		paddr = sg_phys(s);
 
 		s->dma_address = __map_single(dev, iommu, domain->priv,
-					      paddr, s->length, dir);
+					      paddr, s->length, dir, false,
+					      dma_mask);
 
 		if (s->dma_address) {
 			s->dma_length = s->length;
 			mapped_elems++;
 		} else
 			goto unmap;
-		if (iommu_has_npcache(iommu))
-			iommu_flush_pages(iommu, domain->id, s->dma_address,
-					  s->dma_length);
 	}
 
-	if (iommu->need_sync)
+	if (unlikely(iommu->need_sync))
 		iommu_completion_wait(iommu);
 
 out:
@@ -967,7 +1155,8 @@
 	u16 devid;
 	int i;
 
-	if (!get_device_resources(dev, &iommu, &domain, &devid))
+	if (!check_device(dev) ||
+	    !get_device_resources(dev, &iommu, &domain, &devid))
 		return;
 
 	spin_lock_irqsave(&domain->lock, flags);
@@ -975,12 +1164,10 @@
 	for_each_sg(sglist, s, nelems, i) {
 		__unmap_single(iommu, domain->priv, s->dma_address,
 			       s->dma_length, dir);
-		iommu_flush_pages(iommu, domain->id, s->dma_address,
-				  s->dma_length);
 		s->dma_address = s->dma_length = 0;
 	}
 
-	if (iommu->need_sync)
+	if (unlikely(iommu->need_sync))
 		iommu_completion_wait(iommu);
 
 	spin_unlock_irqrestore(&domain->lock, flags);
@@ -998,25 +1185,33 @@
 	struct protection_domain *domain;
 	u16 devid;
 	phys_addr_t paddr;
+	u64 dma_mask = dev->coherent_dma_mask;
 
+	if (!check_device(dev))
+		return NULL;
+
+	if (!get_device_resources(dev, &iommu, &domain, &devid))
+		flag &= ~(__GFP_DMA | __GFP_HIGHMEM | __GFP_DMA32);
+
+	flag |= __GFP_ZERO;
 	virt_addr = (void *)__get_free_pages(flag, get_order(size));
 	if (!virt_addr)
 		return 0;
 
-	memset(virt_addr, 0, size);
 	paddr = virt_to_phys(virt_addr);
 
-	get_device_resources(dev, &iommu, &domain, &devid);
-
 	if (!iommu || !domain) {
 		*dma_addr = (dma_addr_t)paddr;
 		return virt_addr;
 	}
 
+	if (!dma_mask)
+		dma_mask = *dev->dma_mask;
+
 	spin_lock_irqsave(&domain->lock, flags);
 
 	*dma_addr = __map_single(dev, iommu, domain->priv, paddr,
-				 size, DMA_BIDIRECTIONAL);
+				 size, DMA_BIDIRECTIONAL, true, dma_mask);
 
 	if (*dma_addr == bad_dma_address) {
 		free_pages((unsigned long)virt_addr, get_order(size));
@@ -1024,10 +1219,7 @@
 		goto out;
 	}
 
-	if (iommu_has_npcache(iommu))
-		iommu_flush_pages(iommu, domain->id, *dma_addr, size);
-
-	if (iommu->need_sync)
+	if (unlikely(iommu->need_sync))
 		iommu_completion_wait(iommu);
 
 out:
@@ -1038,8 +1230,6 @@
 
 /*
  * The exported free_coherent function for dma_ops.
- * FIXME: fix the generic x86 DMA layer so that it actually calls that
- *        function.
  */
 static void free_coherent(struct device *dev, size_t size,
 			  void *virt_addr, dma_addr_t dma_addr)
@@ -1049,6 +1239,9 @@
 	struct protection_domain *domain;
 	u16 devid;
 
+	if (!check_device(dev))
+		return;
+
 	get_device_resources(dev, &iommu, &domain, &devid);
 
 	if (!iommu || !domain)
@@ -1057,9 +1250,8 @@
 	spin_lock_irqsave(&domain->lock, flags);
 
 	__unmap_single(iommu, domain->priv, dma_addr, size, DMA_BIDIRECTIONAL);
-	iommu_flush_pages(iommu, domain->id, dma_addr, size);
 
-	if (iommu->need_sync)
+	if (unlikely(iommu->need_sync))
 		iommu_completion_wait(iommu);
 
 	spin_unlock_irqrestore(&domain->lock, flags);
@@ -1069,6 +1261,30 @@
 }
 
 /*
+ * This function is called by the DMA layer to find out if we can handle a
+ * particular device. It is part of the dma_ops.
+ */
+static int amd_iommu_dma_supported(struct device *dev, u64 mask)
+{
+	u16 bdf;
+	struct pci_dev *pcidev;
+
+	/* No device or no PCI device */
+	if (!dev || dev->bus != &pci_bus_type)
+		return 0;
+
+	pcidev = to_pci_dev(dev);
+
+	bdf = calc_devid(pcidev->bus->number, pcidev->devfn);
+
+	/* Out of our scope? */
+	if (bdf > amd_iommu_last_bdf)
+		return 0;
+
+	return 1;
+}
+
+/*
  * The function for pre-allocating protection domains.
  *
  * If the driver core informs the DMA layer if a driver grabs a device
@@ -1097,10 +1313,9 @@
 		if (!dma_dom)
 			continue;
 		init_unity_mappings_for_device(dma_dom, devid);
-		set_device_domain(iommu, &dma_dom->domain, devid);
-		printk(KERN_INFO "AMD IOMMU: Allocated domain %d for device ",
-		       dma_dom->domain.id);
-		print_devid(devid, 1);
+		dma_dom->target_dev = devid;
+
+		list_add_tail(&dma_dom->list, &iommu_pd_list);
 	}
 }
 
@@ -1111,6 +1326,7 @@
 	.unmap_single = unmap_single,
 	.map_sg = map_sg,
 	.unmap_sg = unmap_sg,
+	.dma_supported = amd_iommu_dma_supported,
 };
 
 /*
diff --git a/arch/x86/kernel/amd_iommu_init.c b/arch/x86/kernel/amd_iommu_init.c
index a69cc0f..4cd8083 100644
--- a/arch/x86/kernel/amd_iommu_init.c
+++ b/arch/x86/kernel/amd_iommu_init.c
@@ -22,6 +22,8 @@
 #include <linux/gfp.h>
 #include <linux/list.h>
 #include <linux/sysdev.h>
+#include <linux/interrupt.h>
+#include <linux/msi.h>
 #include <asm/pci-direct.h>
 #include <asm/amd_iommu_types.h>
 #include <asm/amd_iommu.h>
@@ -30,7 +32,6 @@
 /*
  * definitions for the ACPI scanning code
  */
-#define PCI_BUS(x) (((x) >> 8) & 0xff)
 #define IVRS_HEADER_LENGTH 48
 
 #define ACPI_IVHD_TYPE                  0x10
@@ -121,6 +122,7 @@
 					   we find in ACPI */
 unsigned amd_iommu_aperture_order = 26; /* size of aperture in power of 2 */
 int amd_iommu_isolate;			/* if 1, device isolation is enabled */
+bool amd_iommu_unmap_flush;		/* if true, flush on every unmap */
 
 LIST_HEAD(amd_iommu_list);		/* list of all AMD IOMMUs in the
 					   system */
@@ -234,7 +236,7 @@
 {
 	u32 ctrl;
 
-	ctrl = (u64)readl(iommu->mmio_base + MMIO_CONTROL_OFFSET);
+	ctrl = readl(iommu->mmio_base + MMIO_CONTROL_OFFSET);
 	ctrl &= ~(1 << bit);
 	writel(ctrl, iommu->mmio_base + MMIO_CONTROL_OFFSET);
 }
@@ -242,13 +244,23 @@
 /* Function to enable the hardware */
 void __init iommu_enable(struct amd_iommu *iommu)
 {
-	printk(KERN_INFO "AMD IOMMU: Enabling IOMMU at ");
-	print_devid(iommu->devid, 0);
-	printk(" cap 0x%hx\n", iommu->cap_ptr);
+	printk(KERN_INFO "AMD IOMMU: Enabling IOMMU "
+	       "at %02x:%02x.%x cap 0x%hx\n",
+	       iommu->dev->bus->number,
+	       PCI_SLOT(iommu->dev->devfn),
+	       PCI_FUNC(iommu->dev->devfn),
+	       iommu->cap_ptr);
 
 	iommu_feature_enable(iommu, CONTROL_IOMMU_EN);
 }
 
+/* Function to enable IOMMU event logging and event interrupts */
+void __init iommu_enable_event_logging(struct amd_iommu *iommu)
+{
+	iommu_feature_enable(iommu, CONTROL_EVT_LOG_EN);
+	iommu_feature_enable(iommu, CONTROL_EVT_INT_EN);
+}
+
 /*
  * mapping and unmapping functions for the IOMMU MMIO space. Each AMD IOMMU in
  * the system has one.
@@ -286,6 +298,14 @@
  ****************************************************************************/
 
 /*
+ * This function calculates the length of a given IVHD entry
+ */
+static inline int ivhd_entry_length(u8 *ivhd)
+{
+	return 0x04 << (*ivhd >> 6);
+}
+
+/*
  * This function reads the last device id the IOMMU has to handle from the PCI
  * capability header for this IOMMU
  */
@@ -329,7 +349,7 @@
 		default:
 			break;
 		}
-		p += 0x04 << (*p >> 6);
+		p += ivhd_entry_length(p);
 	}
 
 	WARN_ON(p != end);
@@ -414,7 +434,32 @@
 
 static void __init free_command_buffer(struct amd_iommu *iommu)
 {
-	free_pages((unsigned long)iommu->cmd_buf, get_order(CMD_BUFFER_SIZE));
+	free_pages((unsigned long)iommu->cmd_buf,
+		   get_order(iommu->cmd_buf_size));
+}
+
+/* allocates the memory where the IOMMU will log its events to */
+static u8 * __init alloc_event_buffer(struct amd_iommu *iommu)
+{
+	u64 entry;
+	iommu->evt_buf = (u8 *)__get_free_pages(GFP_KERNEL | __GFP_ZERO,
+						get_order(EVT_BUFFER_SIZE));
+
+	if (iommu->evt_buf == NULL)
+		return NULL;
+
+	entry = (u64)virt_to_phys(iommu->evt_buf) | EVT_LEN_MASK;
+	memcpy_toio(iommu->mmio_base + MMIO_EVT_BUF_OFFSET,
+		    &entry, sizeof(entry));
+
+	iommu->evt_buf_size = EVT_BUFFER_SIZE;
+
+	return iommu->evt_buf;
+}
+
+static void __init free_event_buffer(struct amd_iommu *iommu)
+{
+	free_pages((unsigned long)iommu->evt_buf, get_order(EVT_BUFFER_SIZE));
 }
 
 /* sets a specific bit in the device table entry. */
@@ -487,19 +532,21 @@
  */
 static void __init init_iommu_from_pci(struct amd_iommu *iommu)
 {
-	int bus = PCI_BUS(iommu->devid);
-	int dev = PCI_SLOT(iommu->devid);
-	int fn  = PCI_FUNC(iommu->devid);
 	int cap_ptr = iommu->cap_ptr;
-	u32 range;
+	u32 range, misc;
 
-	iommu->cap = read_pci_config(bus, dev, fn, cap_ptr+MMIO_CAP_HDR_OFFSET);
+	pci_read_config_dword(iommu->dev, cap_ptr + MMIO_CAP_HDR_OFFSET,
+			      &iommu->cap);
+	pci_read_config_dword(iommu->dev, cap_ptr + MMIO_RANGE_OFFSET,
+			      &range);
+	pci_read_config_dword(iommu->dev, cap_ptr + MMIO_MISC_OFFSET,
+			      &misc);
 
-	range = read_pci_config(bus, dev, fn, cap_ptr+MMIO_RANGE_OFFSET);
 	iommu->first_device = calc_devid(MMIO_GET_BUS(range),
 					 MMIO_GET_FD(range));
 	iommu->last_device = calc_devid(MMIO_GET_BUS(range),
 					MMIO_GET_LD(range));
+	iommu->evt_msi_num = MMIO_MSI_NUM(misc);
 }
 
 /*
@@ -604,7 +651,7 @@
 			break;
 		}
 
-		p += 0x04 << (e->type >> 6);
+		p += ivhd_entry_length(p);
 	}
 }
 
@@ -622,6 +669,7 @@
 static void __init free_iommu_one(struct amd_iommu *iommu)
 {
 	free_command_buffer(iommu);
+	free_event_buffer(iommu);
 	iommu_unmap_mmio_space(iommu);
 }
 
@@ -649,8 +697,12 @@
 	/*
 	 * Copy data from ACPI table entry to the iommu struct
 	 */
-	iommu->devid = h->devid;
+	iommu->dev = pci_get_bus_and_slot(PCI_BUS(h->devid), h->devid & 0xff);
+	if (!iommu->dev)
+		return 1;
+
 	iommu->cap_ptr = h->cap_ptr;
+	iommu->pci_seg = h->pci_seg;
 	iommu->mmio_phys = h->mmio_phys;
 	iommu->mmio_base = iommu_map_mmio_space(h->mmio_phys);
 	if (!iommu->mmio_base)
@@ -661,11 +713,17 @@
 	if (!iommu->cmd_buf)
 		return -ENOMEM;
 
+	iommu->evt_buf = alloc_event_buffer(iommu);
+	if (!iommu->evt_buf)
+		return -ENOMEM;
+
+	iommu->int_enabled = false;
+
 	init_iommu_from_pci(iommu);
 	init_iommu_from_acpi(iommu, h);
 	init_iommu_devices(iommu);
 
-	return 0;
+	return pci_enable_device(iommu->dev);
 }
 
 /*
@@ -706,6 +764,95 @@
 
 /****************************************************************************
  *
+ * The following functions initialize the MSI interrupts for all IOMMUs
+ * in the system. Its a bit challenging because there could be multiple
+ * IOMMUs per PCI BDF but we can call pci_enable_msi(x) only once per
+ * pci_dev.
+ *
+ ****************************************************************************/
+
+static int __init iommu_setup_msix(struct amd_iommu *iommu)
+{
+	struct amd_iommu *curr;
+	struct msix_entry entries[32]; /* only 32 supported by AMD IOMMU */
+	int nvec = 0, i;
+
+	list_for_each_entry(curr, &amd_iommu_list, list) {
+		if (curr->dev == iommu->dev) {
+			entries[nvec].entry = curr->evt_msi_num;
+			entries[nvec].vector = 0;
+			curr->int_enabled = true;
+			nvec++;
+		}
+	}
+
+	if (pci_enable_msix(iommu->dev, entries, nvec)) {
+		pci_disable_msix(iommu->dev);
+		return 1;
+	}
+
+	for (i = 0; i < nvec; ++i) {
+		int r = request_irq(entries->vector, amd_iommu_int_handler,
+				    IRQF_SAMPLE_RANDOM,
+				    "AMD IOMMU",
+				    NULL);
+		if (r)
+			goto out_free;
+	}
+
+	return 0;
+
+out_free:
+	for (i -= 1; i >= 0; --i)
+		free_irq(entries->vector, NULL);
+
+	pci_disable_msix(iommu->dev);
+
+	return 1;
+}
+
+static int __init iommu_setup_msi(struct amd_iommu *iommu)
+{
+	int r;
+	struct amd_iommu *curr;
+
+	list_for_each_entry(curr, &amd_iommu_list, list) {
+		if (curr->dev == iommu->dev)
+			curr->int_enabled = true;
+	}
+
+
+	if (pci_enable_msi(iommu->dev))
+		return 1;
+
+	r = request_irq(iommu->dev->irq, amd_iommu_int_handler,
+			IRQF_SAMPLE_RANDOM,
+			"AMD IOMMU",
+			NULL);
+
+	if (r) {
+		pci_disable_msi(iommu->dev);
+		return 1;
+	}
+
+	return 0;
+}
+
+static int __init iommu_init_msi(struct amd_iommu *iommu)
+{
+	if (iommu->int_enabled)
+		return 0;
+
+	if (pci_find_capability(iommu->dev, PCI_CAP_ID_MSIX))
+		return iommu_setup_msix(iommu);
+	else if (pci_find_capability(iommu->dev, PCI_CAP_ID_MSI))
+		return iommu_setup_msi(iommu);
+
+	return 1;
+}
+
+/****************************************************************************
+ *
  * The next functions belong to the third pass of parsing the ACPI
  * table. In this last pass the memory mapping requirements are
  * gathered (like exclusion and unity mapping reanges).
@@ -811,7 +958,6 @@
 	for (devid = 0; devid <= amd_iommu_last_bdf; ++devid) {
 		set_dev_entry_bit(devid, DEV_ENTRY_VALID);
 		set_dev_entry_bit(devid, DEV_ENTRY_TRANSLATION);
-		set_dev_entry_bit(devid, DEV_ENTRY_NO_PAGE_FAULT);
 	}
 }
 
@@ -825,6 +971,8 @@
 
 	list_for_each_entry(iommu, &amd_iommu_list, list) {
 		iommu_set_exclusion_range(iommu);
+		iommu_init_msi(iommu);
+		iommu_enable_event_logging(iommu);
 		iommu_enable(iommu);
 	}
 }
@@ -995,11 +1143,17 @@
 	else
 		printk("disabled\n");
 
+	if (amd_iommu_unmap_flush)
+		printk(KERN_INFO "AMD IOMMU: IO/TLB flush on unmap enabled\n");
+	else
+		printk(KERN_INFO "AMD IOMMU: Lazy IO/TLB flushing enabled\n");
+
 out:
 	return ret;
 
 free:
-	free_pages((unsigned long)amd_iommu_pd_alloc_bitmap, 1);
+	free_pages((unsigned long)amd_iommu_pd_alloc_bitmap,
+		   get_order(MAX_DOMAIN_ID/8));
 
 	free_pages((unsigned long)amd_iommu_pd_table,
 		   get_order(rlookup_table_size));
@@ -1057,8 +1211,10 @@
 static int __init parse_amd_iommu_options(char *str)
 {
 	for (; *str; ++str) {
-		if (strcmp(str, "isolate") == 0)
+		if (strncmp(str, "isolate", 7) == 0)
 			amd_iommu_isolate = 1;
+		if (strncmp(str, "fullflush", 11) == 0)
+			amd_iommu_unmap_flush = true;
 	}
 
 	return 1;
diff --git a/arch/x86/kernel/aperture_64.c b/arch/x86/kernel/aperture_64.c
index 44e2182..9a32b37 100644
--- a/arch/x86/kernel/aperture_64.c
+++ b/arch/x86/kernel/aperture_64.c
@@ -455,11 +455,11 @@
 		   force_iommu ||
 		   valid_agp ||
 		   fallback_aper_force) {
-		printk(KERN_ERR
+		printk(KERN_INFO
 			"Your BIOS doesn't leave a aperture memory hole\n");
-		printk(KERN_ERR
+		printk(KERN_INFO
 			"Please enable the IOMMU option in the BIOS setup\n");
-		printk(KERN_ERR
+		printk(KERN_INFO
 			"This costs you %d MB of RAM\n",
 				32 << fallback_aper_order);
 
diff --git a/arch/x86/kernel/apic_32.c b/arch/x86/kernel/apic_32.c
index f88bd0d..21c831d 100644
--- a/arch/x86/kernel/apic_32.c
+++ b/arch/x86/kernel/apic_32.c
@@ -60,10 +60,8 @@
 static int force_enable_local_apic;
 int disable_apic;
 
-/* Local APIC timer verification ok */
-static int local_apic_timer_verify_ok;
 /* Disable local APIC timer from the kernel commandline or via dmi quirk */
-static int local_apic_timer_disabled;
+static int disable_apic_timer __cpuinitdata;
 /* Local APIC timer works in C2 */
 int local_apic_timer_c2_ok;
 EXPORT_SYMBOL_GPL(local_apic_timer_c2_ok);
@@ -130,7 +128,11 @@
  */
 static inline int lapic_is_integrated(void)
 {
+#ifdef CONFIG_X86_64
+	return 1;
+#else
 	return APIC_INTEGRATED(lapic_get_version());
+#endif
 }
 
 /*
@@ -145,13 +147,18 @@
 	return lapic_get_version() >= 0x14;
 }
 
-void apic_wait_icr_idle(void)
+/*
+ * Paravirt kernels also might be using these below ops. So we still
+ * use generic apic_read()/apic_write(), which might be pointing to different
+ * ops in PARAVIRT case.
+ */
+void xapic_wait_icr_idle(void)
 {
 	while (apic_read(APIC_ICR) & APIC_ICR_BUSY)
 		cpu_relax();
 }
 
-u32 safe_apic_wait_icr_idle(void)
+u32 safe_xapic_wait_icr_idle(void)
 {
 	u32 send_status;
 	int timeout;
@@ -167,16 +174,48 @@
 	return send_status;
 }
 
+void xapic_icr_write(u32 low, u32 id)
+{
+	apic_write(APIC_ICR2, SET_APIC_DEST_FIELD(id));
+	apic_write(APIC_ICR, low);
+}
+
+u64 xapic_icr_read(void)
+{
+	u32 icr1, icr2;
+
+	icr2 = apic_read(APIC_ICR2);
+	icr1 = apic_read(APIC_ICR);
+
+	return icr1 | ((u64)icr2 << 32);
+}
+
+static struct apic_ops xapic_ops = {
+	.read = native_apic_mem_read,
+	.write = native_apic_mem_write,
+	.icr_read = xapic_icr_read,
+	.icr_write = xapic_icr_write,
+	.wait_icr_idle = xapic_wait_icr_idle,
+	.safe_wait_icr_idle = safe_xapic_wait_icr_idle,
+};
+
+struct apic_ops __read_mostly *apic_ops = &xapic_ops;
+EXPORT_SYMBOL_GPL(apic_ops);
+
 /**
  * enable_NMI_through_LVT0 - enable NMI through local vector table 0
  */
 void __cpuinit enable_NMI_through_LVT0(void)
 {
-	unsigned int v = APIC_DM_NMI;
+	unsigned int v;
 
-	/* Level triggered for 82489DX */
+	/* unmask and set to NMI */
+	v = APIC_DM_NMI;
+
+	/* Level triggered for 82489DX (32bit mode) */
 	if (!lapic_is_integrated())
 		v |= APIC_LVT_LEVEL_TRIGGER;
+
 	apic_write(APIC_LVT0, v);
 }
 
@@ -193,9 +232,13 @@
  */
 int lapic_get_maxlvt(void)
 {
-	unsigned int v = apic_read(APIC_LVR);
+	unsigned int v;
 
-	/* 82489DXs do not report # of LVT entries. */
+	v = apic_read(APIC_LVR);
+	/*
+	 * - we always have APIC integrated on 64bit mode
+	 * - 82489DXs do not report # of LVT entries
+	 */
 	return APIC_INTEGRATED(GET_APIC_VERSION(v)) ? GET_APIC_MAXLVT(v) : 2;
 }
 
@@ -203,8 +246,12 @@
  * Local APIC timer
  */
 
-/* Clock divisor is set to 16 */
+/* Clock divisor */
+#ifdef CONFG_X86_64
+#define APIC_DIVISOR 1
+#else
 #define APIC_DIVISOR 16
+#endif
 
 /*
  * This function sets up the local APIC timer, with a timeout of
@@ -212,6 +259,9 @@
  * this function twice on the boot CPU, once with a bogus timeout
  * value, second time for real. The other (noncalibrating) CPUs
  * call this function only once, with the real, calibrated value.
+ *
+ * We do reads before writes even if unnecessary, to get around the
+ * P5 APIC double write bug.
  */
 static void __setup_APIC_LVTT(unsigned int clocks, int oneshot, int irqen)
 {
@@ -233,14 +283,48 @@
 	 */
 	tmp_value = apic_read(APIC_TDCR);
 	apic_write(APIC_TDCR,
-		   (tmp_value & ~(APIC_TDR_DIV_1 | APIC_TDR_DIV_TMBASE)) |
-		   APIC_TDR_DIV_16);
+		(tmp_value & ~(APIC_TDR_DIV_1 | APIC_TDR_DIV_TMBASE)) |
+		APIC_TDR_DIV_16);
 
 	if (!oneshot)
 		apic_write(APIC_TMICT, clocks / APIC_DIVISOR);
 }
 
 /*
+ * Setup extended LVT, AMD specific (K8, family 10h)
+ *
+ * Vector mappings are hard coded. On K8 only offset 0 (APIC500) and
+ * MCE interrupts are supported. Thus MCE offset must be set to 0.
+ *
+ * If mask=1, the LVT entry does not generate interrupts while mask=0
+ * enables the vector. See also the BKDGs.
+ */
+
+#define APIC_EILVT_LVTOFF_MCE 0
+#define APIC_EILVT_LVTOFF_IBS 1
+
+static void setup_APIC_eilvt(u8 lvt_off, u8 vector, u8 msg_type, u8 mask)
+{
+	unsigned long reg = (lvt_off << 4) + APIC_EILVT0;
+	unsigned int  v   = (mask << 16) | (msg_type << 8) | vector;
+
+	apic_write(reg, v);
+}
+
+u8 setup_APIC_eilvt_mce(u8 vector, u8 msg_type, u8 mask)
+{
+	setup_APIC_eilvt(APIC_EILVT_LVTOFF_MCE, vector, msg_type, mask);
+	return APIC_EILVT_LVTOFF_MCE;
+}
+
+u8 setup_APIC_eilvt_ibs(u8 vector, u8 msg_type, u8 mask)
+{
+	setup_APIC_eilvt(APIC_EILVT_LVTOFF_IBS, vector, msg_type, mask);
+	return APIC_EILVT_LVTOFF_IBS;
+}
+EXPORT_SYMBOL_GPL(setup_APIC_eilvt_ibs);
+
+/*
  * Program the next event, relative to now
  */
 static int lapic_next_event(unsigned long delta,
@@ -259,8 +343,8 @@
 	unsigned long flags;
 	unsigned int v;
 
-	/* Lapic used for broadcast ? */
-	if (!local_apic_timer_verify_ok)
+	/* Lapic used as dummy for broadcast ? */
+	if (evt->features & CLOCK_EVT_FEAT_DUMMY)
 		return;
 
 	local_irq_save(flags);
@@ -473,7 +557,7 @@
 		return -1;
 	}
 
-	local_apic_timer_verify_ok = 1;
+	levt->features &= ~CLOCK_EVT_FEAT_DUMMY;
 
 	/* We trust the pm timer based calibration */
 	if (!pm_referenced) {
@@ -507,11 +591,11 @@
 		if (deltaj >= LAPIC_CAL_LOOPS-2 && deltaj <= LAPIC_CAL_LOOPS+2)
 			apic_printk(APIC_VERBOSE, "... jiffies result ok\n");
 		else
-			local_apic_timer_verify_ok = 0;
+			levt->features |= CLOCK_EVT_FEAT_DUMMY;
 	} else
 		local_irq_enable();
 
-	if (!local_apic_timer_verify_ok) {
+	if (levt->features & CLOCK_EVT_FEAT_DUMMY) {
 		printk(KERN_WARNING
 		       "APIC timer disabled due to verification failure.\n");
 			return -1;
@@ -533,7 +617,8 @@
 	 * timer as a dummy clock event source on SMP systems, so the
 	 * broadcast mechanism is used. On UP systems simply ignore it.
 	 */
-	if (local_apic_timer_disabled) {
+	if (disable_apic_timer) {
+		printk(KERN_INFO "Disabling APIC timer\n");
 		/* No broadcast on UP ! */
 		if (num_possible_cpus() > 1) {
 			lapic_clockevent.mult = 1;
@@ -602,7 +687,11 @@
 	/*
 	 * the NMI deadlock-detector uses this.
 	 */
+#ifdef CONFIG_X86_64
+	add_pda(apic_timer_irqs, 1);
+#else
 	per_cpu(irq_stat, cpu).apic_timer_irqs++;
+#endif
 
 	evt->event_handler(evt);
 }
@@ -642,35 +731,6 @@
 }
 
 /*
- * Setup extended LVT, AMD specific (K8, family 10h)
- *
- * Vector mappings are hard coded. On K8 only offset 0 (APIC500) and
- * MCE interrupts are supported. Thus MCE offset must be set to 0.
- */
-
-#define APIC_EILVT_LVTOFF_MCE 0
-#define APIC_EILVT_LVTOFF_IBS 1
-
-static void setup_APIC_eilvt(u8 lvt_off, u8 vector, u8 msg_type, u8 mask)
-{
-	unsigned long reg = (lvt_off << 4) + APIC_EILVT0;
-	unsigned int  v   = (mask << 16) | (msg_type << 8) | vector;
-	apic_write(reg, v);
-}
-
-u8 setup_APIC_eilvt_mce(u8 vector, u8 msg_type, u8 mask)
-{
-	setup_APIC_eilvt(APIC_EILVT_LVTOFF_MCE, vector, msg_type, mask);
-	return APIC_EILVT_LVTOFF_MCE;
-}
-
-u8 setup_APIC_eilvt_ibs(u8 vector, u8 msg_type, u8 mask)
-{
-	setup_APIC_eilvt(APIC_EILVT_LVTOFF_IBS, vector, msg_type, mask);
-	return APIC_EILVT_LVTOFF_IBS;
-}
-
-/*
  * Local APIC start and shutdown
  */
 
@@ -715,7 +775,7 @@
 	}
 
 	/* lets not touch this if we didn't frob it */
-#ifdef CONFIG_X86_MCE_P4THERMAL
+#if defined(CONFIG_X86_MCE_P4THERMAL) || defined(X86_MCE_INTEL)
 	if (maxlvt >= 5) {
 		v = apic_read(APIC_LVTTHMR);
 		apic_write(APIC_LVTTHMR, v | APIC_LVT_MASKED);
@@ -732,10 +792,6 @@
 	if (maxlvt >= 4)
 		apic_write(APIC_LVTPC, APIC_LVT_MASKED);
 
-#ifdef CONFIG_X86_MCE_P4THERMAL
-	if (maxlvt >= 5)
-		apic_write(APIC_LVTTHMR, APIC_LVT_MASKED);
-#endif
 	/* Integrated APIC (!82489DX) ? */
 	if (lapic_is_integrated()) {
 		if (maxlvt > 3)
@@ -750,7 +806,7 @@
  */
 void disable_local_APIC(void)
 {
-	unsigned long value;
+	unsigned int value;
 
 	clear_local_APIC();
 
@@ -762,6 +818,7 @@
 	value &= ~APIC_SPIV_APIC_ENABLED;
 	apic_write(APIC_SPIV, value);
 
+#ifdef CONFIG_X86_32
 	/*
 	 * When LAPIC was disabled by the BIOS and enabled by the kernel,
 	 * restore the disabled state.
@@ -773,6 +830,7 @@
 		l &= ~MSR_IA32_APICBASE_ENABLE;
 		wrmsr(MSR_IA32_APICBASE, l, h);
 	}
+#endif
 }
 
 /*
@@ -789,11 +847,15 @@
 		return;
 
 	local_irq_save(flags);
-	clear_local_APIC();
 
-	if (enabled_via_apicbase)
+#ifdef CONFIG_X86_32
+	if (!enabled_via_apicbase)
+		clear_local_APIC();
+	else
+#endif
 		disable_local_APIC();
 
+
 	local_irq_restore(flags);
 }
 
@@ -838,6 +900,12 @@
 	 */
 	reg0 = apic_read(APIC_ID);
 	apic_printk(APIC_DEBUG, "Getting ID: %x\n", reg0);
+	apic_write(APIC_ID, reg0 ^ APIC_ID_MASK);
+	reg1 = apic_read(APIC_ID);
+	apic_printk(APIC_DEBUG, "Getting ID: %x\n", reg1);
+	apic_write(APIC_ID, reg0);
+	if (reg1 != (reg0 ^ APIC_ID_MASK))
+		return 0;
 
 	/*
 	 * The next two are just to see if we have sane values.
@@ -863,14 +931,15 @@
 	 */
 	if (modern_apic() || boot_cpu_data.x86_vendor == X86_VENDOR_AMD)
 		return;
+
 	/*
 	 * Wait for idle.
 	 */
 	apic_wait_icr_idle();
 
 	apic_printk(APIC_DEBUG, "Synchronizing Arb IDs.\n");
-	apic_write(APIC_ICR,
-		   APIC_DEST_ALLINC | APIC_INT_LEVELTRIG | APIC_DM_INIT);
+	apic_write(APIC_ICR, APIC_DEST_ALLINC |
+			APIC_INT_LEVELTRIG | APIC_DM_INIT);
 }
 
 /*
@@ -878,7 +947,7 @@
  */
 void __init init_bsp_APIC(void)
 {
-	unsigned long value;
+	unsigned int value;
 
 	/*
 	 * Don't do the setup now if we have a SMP BIOS as the
@@ -899,11 +968,13 @@
 	value &= ~APIC_VECTOR_MASK;
 	value |= APIC_SPIV_APIC_ENABLED;
 
+#ifdef CONFIG_X86_32
 	/* This bit is reserved on P4/Xeon and should be cleared */
 	if ((boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) &&
 	    (boot_cpu_data.x86 == 15))
 		value &= ~APIC_SPIV_FOCUS_DISABLED;
 	else
+#endif
 		value |= APIC_SPIV_FOCUS_DISABLED;
 	value |= SPURIOUS_APIC_VECTOR;
 	apic_write(APIC_SPIV, value);
@@ -922,6 +993,16 @@
 {
 	unsigned long oldvalue, value, maxlvt;
 	if (lapic_is_integrated() && !esr_disable) {
+		if (esr_disable) {
+			/*
+			 * Something untraceable is creating bad interrupts on
+			 * secondary quads ... for the moment, just leave the
+			 * ESR disabled - we can't do anything useful with the
+			 * errors anyway - mbligh
+			 */
+			printk(KERN_INFO "Leaving ESR disabled.\n");
+			return;
+		}
 		/* !82489DX */
 		maxlvt = lapic_get_maxlvt();
 		if (maxlvt > 3)		/* Due to the Pentium erratum 3AP. */
@@ -942,16 +1023,7 @@
 				"vector: 0x%08lx  after: 0x%08lx\n",
 				oldvalue, value);
 	} else {
-		if (esr_disable)
-			/*
-			 * Something untraceable is creating bad interrupts on
-			 * secondary quads ... for the moment, just leave the
-			 * ESR disabled - we can't do anything useful with the
-			 * errors anyway - mbligh
-			 */
-			printk(KERN_INFO "Leaving ESR disabled.\n");
-		else
-			printk(KERN_INFO "No ESR for 82489DX.\n");
+		printk(KERN_INFO "No ESR for 82489DX.\n");
 	}
 }
 
@@ -1089,13 +1161,17 @@
 
 void __cpuinit end_local_APIC_setup(void)
 {
-	unsigned long value;
-
 	lapic_setup_esr();
-	/* Disable the local apic timer */
-	value = apic_read(APIC_LVTT);
-	value |= (APIC_LVT_MASKED | LOCAL_TIMER_VECTOR);
-	apic_write(APIC_LVTT, value);
+
+#ifdef CONFIG_X86_32
+	{
+		unsigned int value;
+		/* Disable the local apic timer */
+		value = apic_read(APIC_LVTT);
+		value |= (APIC_LVT_MASKED | LOCAL_TIMER_VECTOR);
+		apic_write(APIC_LVTT, value);
+	}
+#endif
 
 	setup_apic_nmi_watchdog(NULL);
 	apic_pm_activate();
@@ -1205,7 +1281,7 @@
 	 * default configuration (or the MP table is broken).
 	 */
 	if (boot_cpu_physical_apicid == -1U)
-		boot_cpu_physical_apicid = GET_APIC_ID(read_apic_id());
+		boot_cpu_physical_apicid = read_apic_id();
 
 }
 
@@ -1242,7 +1318,7 @@
 	 * might be zero if read from MP tables. Get it from LAPIC.
 	 */
 #ifdef CONFIG_CRASH_DUMP
-	boot_cpu_physical_apicid = GET_APIC_ID(read_apic_id());
+	boot_cpu_physical_apicid = read_apic_id();
 #endif
 	physid_set_mask_of_physid(boot_cpu_physical_apicid, &phys_cpu_present_map);
 
@@ -1321,59 +1397,12 @@
 	irq_exit();
 }
 
-#ifdef CONFIG_SMP
-void __init smp_intr_init(void)
-{
-	/*
-	 * 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]);
-
-	/*
-	 * The reschedule interrupt is a CPU-to-CPU reschedule-helper
-	 * IPI, driven by wakeup.
-	 */
-	alloc_intr_gate(RESCHEDULE_VECTOR, reschedule_interrupt);
-
-	/* IPI for invalidation */
-	alloc_intr_gate(INVALIDATE_TLB_VECTOR, invalidate_interrupt);
-
-	/* IPI for generic function call */
-	alloc_intr_gate(CALL_FUNCTION_VECTOR, call_function_interrupt);
-
-	/* IPI for single call function */
-	set_intr_gate(CALL_FUNCTION_SINGLE_VECTOR,
-				call_function_single_interrupt);
-}
-#endif
-
-/*
- * Initialize APIC interrupts
- */
-void __init apic_intr_init(void)
-{
-#ifdef CONFIG_SMP
-	smp_intr_init();
-#endif
-	/* self generated IPI for local APIC timer */
-	alloc_intr_gate(LOCAL_TIMER_VECTOR, apic_timer_interrupt);
-
-	/* IPI vectors for APIC spurious and error interrupts */
-	alloc_intr_gate(SPURIOUS_APIC_VECTOR, spurious_interrupt);
-	alloc_intr_gate(ERROR_APIC_VECTOR, error_interrupt);
-
-	/* thermal monitor LVT interrupt */
-#ifdef CONFIG_X86_MCE_P4THERMAL
-	alloc_intr_gate(THERMAL_APIC_VECTOR, thermal_interrupt);
-#endif
-}
-
 /**
  * connect_bsp_APIC - attach the APIC to the interrupt system
  */
 void __init connect_bsp_APIC(void)
 {
+#ifdef CONFIG_X86_32
 	if (pic_mode) {
 		/*
 		 * Do not trust the local APIC being empty at bootup.
@@ -1388,6 +1417,7 @@
 		outb(0x70, 0x22);
 		outb(0x01, 0x23);
 	}
+#endif
 	enable_apic_mode();
 }
 
@@ -1400,6 +1430,9 @@
  */
 void disconnect_bsp_APIC(int virt_wire_setup)
 {
+	unsigned int value;
+
+#ifdef CONFIG_X86_32
 	if (pic_mode) {
 		/*
 		 * Put the board back into PIC mode (has an effect only on
@@ -1411,54 +1444,53 @@
 				"entering PIC mode.\n");
 		outb(0x70, 0x22);
 		outb(0x00, 0x23);
-	} else {
-		/* Go back to Virtual Wire compatibility mode */
-		unsigned long value;
+		return;
+	}
+#endif
 
-		/* For the spurious interrupt use vector F, and enable it */
-		value = apic_read(APIC_SPIV);
-		value &= ~APIC_VECTOR_MASK;
-		value |= APIC_SPIV_APIC_ENABLED;
-		value |= 0xf;
-		apic_write(APIC_SPIV, value);
+	/* Go back to Virtual Wire compatibility mode */
 
-		if (!virt_wire_setup) {
-			/*
-			 * For LVT0 make it edge triggered, active high,
-			 * external and enabled
-			 */
-			value = apic_read(APIC_LVT0);
-			value &= ~(APIC_MODE_MASK | APIC_SEND_PENDING |
-				APIC_INPUT_POLARITY | APIC_LVT_REMOTE_IRR |
-				APIC_LVT_LEVEL_TRIGGER | APIC_LVT_MASKED);
-			value |= APIC_LVT_REMOTE_IRR | APIC_SEND_PENDING;
-			value = SET_APIC_DELIVERY_MODE(value, APIC_MODE_EXTINT);
-			apic_write(APIC_LVT0, value);
-		} else {
-			/* Disable LVT0 */
-			apic_write(APIC_LVT0, APIC_LVT_MASKED);
-		}
+	/* For the spurious interrupt use vector F, and enable it */
+	value = apic_read(APIC_SPIV);
+	value &= ~APIC_VECTOR_MASK;
+	value |= APIC_SPIV_APIC_ENABLED;
+	value |= 0xf;
+	apic_write(APIC_SPIV, value);
 
+	if (!virt_wire_setup) {
 		/*
-		 * For LVT1 make it edge triggered, active high, nmi and
-		 * enabled
+		 * For LVT0 make it edge triggered, active high,
+		 * external and enabled
 		 */
-		value = apic_read(APIC_LVT1);
-		value &= ~(
-			APIC_MODE_MASK | APIC_SEND_PENDING |
+		value = apic_read(APIC_LVT0);
+		value &= ~(APIC_MODE_MASK | APIC_SEND_PENDING |
 			APIC_INPUT_POLARITY | APIC_LVT_REMOTE_IRR |
 			APIC_LVT_LEVEL_TRIGGER | APIC_LVT_MASKED);
 		value |= APIC_LVT_REMOTE_IRR | APIC_SEND_PENDING;
-		value = SET_APIC_DELIVERY_MODE(value, APIC_MODE_NMI);
-		apic_write(APIC_LVT1, value);
+		value = SET_APIC_DELIVERY_MODE(value, APIC_MODE_EXTINT);
+		apic_write(APIC_LVT0, value);
+	} else {
+		/* Disable LVT0 */
+		apic_write(APIC_LVT0, APIC_LVT_MASKED);
 	}
+
+	/*
+	 * For LVT1 make it edge triggered, active high,
+	 * nmi and enabled
+	 */
+	value = apic_read(APIC_LVT1);
+	value &= ~(APIC_MODE_MASK | APIC_SEND_PENDING |
+			APIC_INPUT_POLARITY | APIC_LVT_REMOTE_IRR |
+			APIC_LVT_LEVEL_TRIGGER | APIC_LVT_MASKED);
+	value |= APIC_LVT_REMOTE_IRR | APIC_SEND_PENDING;
+	value = SET_APIC_DELIVERY_MODE(value, APIC_MODE_NMI);
+	apic_write(APIC_LVT1, value);
 }
 
 void __cpuinit generic_processor_info(int apicid, int version)
 {
 	int cpu;
 	cpumask_t tmp_map;
-	physid_mask_t phys_cpu;
 
 	/*
 	 * Validate version
@@ -1471,9 +1503,6 @@
 	}
 	apic_version[apicid] = version;
 
-	phys_cpu = apicid_to_cpu_present(apicid);
-	physids_or(phys_cpu_present_map, phys_cpu_present_map, phys_cpu);
-
 	if (num_processors >= NR_CPUS) {
 		printk(KERN_WARNING "WARNING: NR_CPUS limit of %i reached."
 			"  Processor ignored.\n", NR_CPUS);
@@ -1484,17 +1513,19 @@
 	cpus_complement(tmp_map, cpu_present_map);
 	cpu = first_cpu(tmp_map);
 
-	if (apicid == boot_cpu_physical_apicid)
+	physid_set(apicid, phys_cpu_present_map);
+	if (apicid == boot_cpu_physical_apicid) {
 		/*
 		 * x86_bios_cpu_apicid is required to have processors listed
 		 * in same order as logical cpu numbers. Hence the first
 		 * entry is BSP, and so on.
 		 */
 		cpu = 0;
-
+	}
 	if (apicid > max_physical_apicid)
 		max_physical_apicid = apicid;
 
+#ifdef CONFIG_X86_32
 	/*
 	 * Would be preferable to switch to bigsmp when CONFIG_HOTPLUG_CPU=y
 	 * but we need to work other dependencies like SMP_SUSPEND etc
@@ -1514,7 +1545,9 @@
 			def_to_bigsmp = 1;
 		}
 	}
-#ifdef CONFIG_SMP
+#endif
+
+#if defined(CONFIG_X86_SMP) || defined(CONFIG_X86_64)
 	/* are we being called early in kernel startup? */
 	if (early_per_cpu_ptr(x86_cpu_to_apicid)) {
 		u16 *cpu_to_apicid = early_per_cpu_ptr(x86_cpu_to_apicid);
@@ -1527,6 +1560,7 @@
 		per_cpu(x86_bios_cpu_apicid, cpu) = apicid;
 	}
 #endif
+
 	cpu_set(cpu, cpu_possible_map);
 	cpu_set(cpu, cpu_present_map);
 }
@@ -1537,6 +1571,11 @@
 #ifdef CONFIG_PM
 
 static struct {
+	/*
+	 * 'active' is true if the local APIC was enabled by us and
+	 * not the BIOS; this signifies that we are also responsible
+	 * for disabling it before entering apm/acpi suspend
+	 */
 	int active;
 	/* r/w apic fields */
 	unsigned int apic_id;
@@ -1577,7 +1616,7 @@
 	apic_pm_state.apic_lvterr = apic_read(APIC_LVTERR);
 	apic_pm_state.apic_tmict = apic_read(APIC_TMICT);
 	apic_pm_state.apic_tdcr = apic_read(APIC_TDCR);
-#ifdef CONFIG_X86_MCE_P4THERMAL
+#if defined(CONFIG_X86_MCE_P4THERMAL) || defined(CONFIG_X86_MCE_INTEL)
 	if (maxlvt >= 5)
 		apic_pm_state.apic_thmr = apic_read(APIC_LVTTHMR);
 #endif
@@ -1601,16 +1640,23 @@
 
 	local_irq_save(flags);
 
-	/*
-	 * Make sure the APICBASE points to the right address
-	 *
-	 * FIXME! This will be wrong if we ever support suspend on
-	 * SMP! We'll need to do this as part of the CPU restore!
-	 */
-	rdmsr(MSR_IA32_APICBASE, l, h);
-	l &= ~MSR_IA32_APICBASE_BASE;
-	l |= MSR_IA32_APICBASE_ENABLE | mp_lapic_addr;
-	wrmsr(MSR_IA32_APICBASE, l, h);
+#ifdef CONFIG_X86_64
+	if (x2apic)
+		enable_x2apic();
+	else
+#endif
+	{
+		/*
+		 * Make sure the APICBASE points to the right address
+		 *
+		 * FIXME! This will be wrong if we ever support suspend on
+		 * SMP! We'll need to do this as part of the CPU restore!
+		 */
+		rdmsr(MSR_IA32_APICBASE, l, h);
+		l &= ~MSR_IA32_APICBASE_BASE;
+		l |= MSR_IA32_APICBASE_ENABLE | mp_lapic_addr;
+		wrmsr(MSR_IA32_APICBASE, l, h);
+	}
 
 	apic_write(APIC_LVTERR, ERROR_APIC_VECTOR | APIC_LVT_MASKED);
 	apic_write(APIC_ID, apic_pm_state.apic_id);
@@ -1620,7 +1666,7 @@
 	apic_write(APIC_SPIV, apic_pm_state.apic_spiv);
 	apic_write(APIC_LVT0, apic_pm_state.apic_lvt0);
 	apic_write(APIC_LVT1, apic_pm_state.apic_lvt1);
-#ifdef CONFIG_X86_MCE_P4THERMAL
+#if defined(CONFIG_X86_MCE_P4THERMAL) || defined(CONFIG_X86_MCE_INTEL)
 	if (maxlvt >= 5)
 		apic_write(APIC_LVTTHMR, apic_pm_state.apic_thmr);
 #endif
@@ -1634,7 +1680,9 @@
 	apic_write(APIC_LVTERR, apic_pm_state.apic_lvterr);
 	apic_write(APIC_ESR, 0);
 	apic_read(APIC_ESR);
+
 	local_irq_restore(flags);
+
 	return 0;
 }
 
@@ -1690,20 +1738,20 @@
 }
 early_param("lapic", parse_lapic);
 
-static int __init parse_nolapic(char *arg)
+static int __init setup_disableapic(char *arg)
 {
 	disable_apic = 1;
 	setup_clear_cpu_cap(X86_FEATURE_APIC);
 	return 0;
 }
-early_param("nolapic", parse_nolapic);
+early_param("disableapic", setup_disableapic);
 
-static int __init parse_disable_lapic_timer(char *arg)
+/* same as disableapic, for compatibility */
+static int __init setup_nolapic(char *arg)
 {
-	local_apic_timer_disabled = 1;
-	return 0;
+	return setup_disableapic(arg);
 }
-early_param("nolapic_timer", parse_disable_lapic_timer);
+early_param("nolapic", setup_nolapic);
 
 static int __init parse_lapic_timer_c2_ok(char *arg)
 {
@@ -1712,15 +1760,40 @@
 }
 early_param("lapic_timer_c2_ok", parse_lapic_timer_c2_ok);
 
+static int __init parse_disable_apic_timer(char *arg)
+{
+	disable_apic_timer = 1;
+	return 0;
+}
+early_param("noapictimer", parse_disable_apic_timer);
+
+static int __init parse_nolapic_timer(char *arg)
+{
+	disable_apic_timer = 1;
+	return 0;
+}
+early_param("nolapic_timer", parse_nolapic_timer);
+
 static int __init apic_set_verbosity(char *arg)
 {
-	if (!arg)
+	if (!arg)  {
+#ifdef CONFIG_X86_64
+		skip_ioapic_setup = 0;
+		ioapic_force = 1;
+		return 0;
+#endif
 		return -EINVAL;
+	}
 
-	if (strcmp(arg, "debug") == 0)
+	if (strcmp("debug", arg) == 0)
 		apic_verbosity = APIC_DEBUG;
-	else if (strcmp(arg, "verbose") == 0)
+	else if (strcmp("verbose", arg) == 0)
 		apic_verbosity = APIC_VERBOSE;
+	else {
+		printk(KERN_WARNING "APIC Verbosity level %s not recognised"
+			" use apic=verbose or apic=debug\n", arg);
+		return -EINVAL;
+	}
 
 	return 0;
 }
diff --git a/arch/x86/kernel/apic_64.c b/arch/x86/kernel/apic_64.c
index 446c062..94ddb69a 100644
--- a/arch/x86/kernel/apic_64.c
+++ b/arch/x86/kernel/apic_64.c
@@ -27,6 +27,7 @@
 #include <linux/clockchips.h>
 #include <linux/acpi_pmtmr.h>
 #include <linux/module.h>
+#include <linux/dmar.h>
 
 #include <asm/atomic.h>
 #include <asm/smp.h>
@@ -39,13 +40,20 @@
 #include <asm/proto.h>
 #include <asm/timex.h>
 #include <asm/apic.h>
+#include <asm/i8259.h>
 
 #include <mach_ipi.h>
 #include <mach_apic.h>
 
+/* Disable local APIC timer from the kernel commandline or via dmi quirk */
 static int disable_apic_timer __cpuinitdata;
 static int apic_calibrate_pmtmr __initdata;
 int disable_apic;
+int disable_x2apic;
+int x2apic;
+
+/* x2apic enabled before OS handover */
+int x2apic_preenabled;
 
 /* Local APIC timer works in C2 */
 int local_apic_timer_c2_ok;
@@ -73,6 +81,9 @@
 static void lapic_timer_broadcast(cpumask_t mask);
 static void apic_pm_activate(void);
 
+/*
+ * The local apic timer can be used for any function which is CPU local.
+ */
 static struct clock_event_device lapic_clockevent = {
 	.name		= "lapic",
 	.features	= CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT
@@ -99,11 +110,15 @@
 }
 
 /*
- * Check, if the APIC is integrated or a seperate chip
+ * Check, if the APIC is integrated or a separate chip
  */
 static inline int lapic_is_integrated(void)
 {
+#ifdef CONFIG_X86_64
 	return 1;
+#else
+	return APIC_INTEGRATED(lapic_get_version());
+#endif
 }
 
 /*
@@ -118,13 +133,18 @@
 	return lapic_get_version() >= 0x14;
 }
 
-void apic_wait_icr_idle(void)
+/*
+ * Paravirt kernels also might be using these below ops. So we still
+ * use generic apic_read()/apic_write(), which might be pointing to different
+ * ops in PARAVIRT case.
+ */
+void xapic_wait_icr_idle(void)
 {
 	while (apic_read(APIC_ICR) & APIC_ICR_BUSY)
 		cpu_relax();
 }
 
-u32 safe_apic_wait_icr_idle(void)
+u32 safe_xapic_wait_icr_idle(void)
 {
 	u32 send_status;
 	int timeout;
@@ -140,6 +160,68 @@
 	return send_status;
 }
 
+void xapic_icr_write(u32 low, u32 id)
+{
+	apic_write(APIC_ICR2, SET_APIC_DEST_FIELD(id));
+	apic_write(APIC_ICR, low);
+}
+
+u64 xapic_icr_read(void)
+{
+	u32 icr1, icr2;
+
+	icr2 = apic_read(APIC_ICR2);
+	icr1 = apic_read(APIC_ICR);
+
+	return icr1 | ((u64)icr2 << 32);
+}
+
+static struct apic_ops xapic_ops = {
+	.read = native_apic_mem_read,
+	.write = native_apic_mem_write,
+	.icr_read = xapic_icr_read,
+	.icr_write = xapic_icr_write,
+	.wait_icr_idle = xapic_wait_icr_idle,
+	.safe_wait_icr_idle = safe_xapic_wait_icr_idle,
+};
+
+struct apic_ops __read_mostly *apic_ops = &xapic_ops;
+EXPORT_SYMBOL_GPL(apic_ops);
+
+static void x2apic_wait_icr_idle(void)
+{
+	/* no need to wait for icr idle in x2apic */
+	return;
+}
+
+static u32 safe_x2apic_wait_icr_idle(void)
+{
+	/* no need to wait for icr idle in x2apic */
+	return 0;
+}
+
+void x2apic_icr_write(u32 low, u32 id)
+{
+	wrmsrl(APIC_BASE_MSR + (APIC_ICR >> 4), ((__u64) id) << 32 | low);
+}
+
+u64 x2apic_icr_read(void)
+{
+	unsigned long val;
+
+	rdmsrl(APIC_BASE_MSR + (APIC_ICR >> 4), val);
+	return val;
+}
+
+static struct apic_ops x2apic_ops = {
+	.read = native_apic_msr_read,
+	.write = native_apic_msr_write,
+	.icr_read = x2apic_icr_read,
+	.icr_write = x2apic_icr_write,
+	.wait_icr_idle = x2apic_wait_icr_idle,
+	.safe_wait_icr_idle = safe_x2apic_wait_icr_idle,
+};
+
 /**
  * enable_NMI_through_LVT0 - enable NMI through local vector table 0
  */
@@ -149,6 +231,11 @@
 
 	/* unmask and set to NMI */
 	v = APIC_DM_NMI;
+
+	/* Level triggered for 82489DX (32bit mode) */
+	if (!lapic_is_integrated())
+		v |= APIC_LVT_LEVEL_TRIGGER;
+
 	apic_write(APIC_LVT0, v);
 }
 
@@ -157,14 +244,28 @@
  */
 int lapic_get_maxlvt(void)
 {
-	unsigned int v, maxlvt;
+	unsigned int v;
 
 	v = apic_read(APIC_LVR);
-	maxlvt = GET_APIC_MAXLVT(v);
-	return maxlvt;
+	/*
+	 * - we always have APIC integrated on 64bit mode
+	 * - 82489DXs do not report # of LVT entries
+	 */
+	return APIC_INTEGRATED(GET_APIC_VERSION(v)) ? GET_APIC_MAXLVT(v) : 2;
 }
 
 /*
+ * Local APIC timer
+ */
+
+/* Clock divisor */
+#ifdef CONFG_X86_64
+#define APIC_DIVISOR 1
+#else
+#define APIC_DIVISOR 16
+#endif
+
+/*
  * This function sets up the local APIC timer, with a timeout of
  * 'clocks' APIC bus clock. During calibration we actually call
  * this function twice on the boot CPU, once with a bogus timeout
@@ -174,7 +275,6 @@
  * We do reads before writes even if unnecessary, to get around the
  * P5 APIC double write bug.
  */
-
 static void __setup_APIC_LVTT(unsigned int clocks, int oneshot, int irqen)
 {
 	unsigned int lvtt_value, tmp_value;
@@ -182,6 +282,9 @@
 	lvtt_value = LOCAL_TIMER_VECTOR;
 	if (!oneshot)
 		lvtt_value |= APIC_LVT_TIMER_PERIODIC;
+	if (!lapic_is_integrated())
+		lvtt_value |= SET_APIC_TIMER_BASE(APIC_TIMER_BASE_DIV);
+
 	if (!irqen)
 		lvtt_value |= APIC_LVT_MASKED;
 
@@ -191,12 +294,12 @@
 	 * Divide PICLK by 16
 	 */
 	tmp_value = apic_read(APIC_TDCR);
-	apic_write(APIC_TDCR, (tmp_value
-				& ~(APIC_TDR_DIV_1 | APIC_TDR_DIV_TMBASE))
-				| APIC_TDR_DIV_16);
+	apic_write(APIC_TDCR,
+		(tmp_value & ~(APIC_TDR_DIV_1 | APIC_TDR_DIV_TMBASE)) |
+		APIC_TDR_DIV_16);
 
 	if (!oneshot)
-		apic_write(APIC_TMICT, clocks);
+		apic_write(APIC_TMICT, clocks / APIC_DIVISOR);
 }
 
 /*
@@ -204,6 +307,9 @@
  *
  * Vector mappings are hard coded. On K8 only offset 0 (APIC500) and
  * MCE interrupts are supported. Thus MCE offset must be set to 0.
+ *
+ * If mask=1, the LVT entry does not generate interrupts while mask=0
+ * enables the vector. See also the BKDGs.
  */
 
 #define APIC_EILVT_LVTOFF_MCE 0
@@ -228,6 +334,7 @@
 	setup_APIC_eilvt(APIC_EILVT_LVTOFF_IBS, vector, msg_type, mask);
 	return APIC_EILVT_LVTOFF_IBS;
 }
+EXPORT_SYMBOL_GPL(setup_APIC_eilvt_ibs);
 
 /*
  * Program the next event, relative to now
@@ -366,7 +473,7 @@
 	lapic_clockevent.min_delta_ns =
 		clockevent_delta2ns(0xF, &lapic_clockevent);
 
-	calibration_result = result / HZ;
+	calibration_result = (result * APIC_DIVISOR) / HZ;
 
 	/*
 	 * Do a sanity check on the APIC calibration result
@@ -388,10 +495,10 @@
 void __init setup_boot_APIC_clock(void)
 {
 	/*
-	 * The local apic timer can be disabled via the kernel commandline.
-	 * Register the lapic timer as a dummy clock event source on SMP
-	 * systems, so the broadcast mechanism is used. On UP systems simply
-	 * ignore it.
+	 * The local apic timer can be disabled via the kernel
+	 * commandline or from the CPU detection code. Register the lapic
+	 * timer as a dummy clock event source on SMP systems, so the
+	 * broadcast mechanism is used. On UP systems simply ignore it.
 	 */
 	if (disable_apic_timer) {
 		printk(KERN_INFO "Disabling APIC timer\n");
@@ -403,7 +510,9 @@
 		return;
 	}
 
-	printk(KERN_INFO "Using local APIC timer interrupts.\n");
+	apic_printk(APIC_VERBOSE, "Using local APIC timer interrupts.\n"
+		    "calibrating APIC timer ...\n");
+
 	if (calibrate_APIC_clock()) {
 		/* No broadcast on UP ! */
 		if (num_possible_cpus() > 1)
@@ -422,6 +531,7 @@
 		printk(KERN_WARNING "APIC timer registered as dummy,"
 			" due to nmi_watchdog=%d!\n", nmi_watchdog);
 
+	/* Setup the lapic or request the broadcast */
 	setup_APIC_timer();
 }
 
@@ -460,7 +570,11 @@
 	/*
 	 * the NMI deadlock-detector uses this.
 	 */
+#ifdef CONFIG_X86_64
 	add_pda(apic_timer_irqs, 1);
+#else
+	per_cpu(irq_stat, cpu).apic_timer_irqs++;
+#endif
 
 	evt->event_handler(evt);
 }
@@ -491,6 +605,7 @@
 	irq_enter();
 	local_apic_timer_interrupt();
 	irq_exit();
+
 	set_irq_regs(old_regs);
 }
 
@@ -544,6 +659,13 @@
 		apic_write(APIC_LVTPC, v | APIC_LVT_MASKED);
 	}
 
+	/* lets not touch this if we didn't frob it */
+#if defined(CONFIG_X86_MCE_P4THERMAL) || defined(X86_MCE_INTEL)
+	if (maxlvt >= 5) {
+		v = apic_read(APIC_LVTTHMR);
+		apic_write(APIC_LVTTHMR, v | APIC_LVT_MASKED);
+	}
+#endif
 	/*
 	 * Clean APIC state for other OSs:
 	 */
@@ -554,8 +676,14 @@
 		apic_write(APIC_LVTERR, APIC_LVT_MASKED);
 	if (maxlvt >= 4)
 		apic_write(APIC_LVTPC, APIC_LVT_MASKED);
-	apic_write(APIC_ESR, 0);
-	apic_read(APIC_ESR);
+
+	/* Integrated APIC (!82489DX) ? */
+	if (lapic_is_integrated()) {
+		if (maxlvt > 3)
+			/* Clear ESR due to Pentium errata 3AP and 11AP */
+			apic_write(APIC_ESR, 0);
+		apic_read(APIC_ESR);
+	}
 }
 
 /**
@@ -574,8 +702,28 @@
 	value = apic_read(APIC_SPIV);
 	value &= ~APIC_SPIV_APIC_ENABLED;
 	apic_write(APIC_SPIV, value);
+
+#ifdef CONFIG_X86_32
+	/*
+	 * When LAPIC was disabled by the BIOS and enabled by the kernel,
+	 * restore the disabled state.
+	 */
+	if (enabled_via_apicbase) {
+		unsigned int l, h;
+
+		rdmsr(MSR_IA32_APICBASE, l, h);
+		l &= ~MSR_IA32_APICBASE_ENABLE;
+		wrmsr(MSR_IA32_APICBASE, l, h);
+	}
+#endif
 }
 
+/*
+ * If Linux enabled the LAPIC against the BIOS default disable it down before
+ * re-entering the BIOS on shutdown.  Otherwise the BIOS may get confused and
+ * not power-off.  Additionally clear all LVT entries before disable_local_APIC
+ * for the case where Linux didn't enable the LAPIC.
+ */
 void lapic_shutdown(void)
 {
 	unsigned long flags;
@@ -585,7 +733,13 @@
 
 	local_irq_save(flags);
 
-	disable_local_APIC();
+#ifdef CONFIG_X86_32
+	if (!enabled_via_apicbase)
+		clear_local_APIC();
+	else
+#endif
+		disable_local_APIC();
+
 
 	local_irq_restore(flags);
 }
@@ -629,10 +783,10 @@
 	/*
 	 * The ID register is read/write in a real APIC.
 	 */
-	reg0 = read_apic_id();
+	reg0 = apic_read(APIC_ID);
 	apic_printk(APIC_DEBUG, "Getting ID: %x\n", reg0);
 	apic_write(APIC_ID, reg0 ^ APIC_ID_MASK);
-	reg1 = read_apic_id();
+	reg1 = apic_read(APIC_ID);
 	apic_printk(APIC_DEBUG, "Getting ID: %x\n", reg1);
 	apic_write(APIC_ID, reg0);
 	if (reg1 != (reg0 ^ APIC_ID_MASK))
@@ -656,8 +810,11 @@
  */
 void __init sync_Arb_IDs(void)
 {
-	/* Unsupported on P4 - see Intel Dev. Manual Vol. 3, Ch. 8.6.1 */
-	if (modern_apic())
+	/*
+	 * Unsupported on P4 - see Intel Dev. Manual Vol. 3, Ch. 8.6.1 And not
+	 * needed on AMD.
+	 */
+	if (modern_apic() || boot_cpu_data.x86_vendor == X86_VENDOR_AMD)
 		return;
 
 	/*
@@ -666,8 +823,8 @@
 	apic_wait_icr_idle();
 
 	apic_printk(APIC_DEBUG, "Synchronizing Arb IDs.\n");
-	apic_write(APIC_ICR, APIC_DEST_ALLINC | APIC_INT_LEVELTRIG
-				| APIC_DM_INIT);
+	apic_write(APIC_ICR, APIC_DEST_ALLINC |
+			APIC_INT_LEVELTRIG | APIC_DM_INIT);
 }
 
 /*
@@ -684,8 +841,6 @@
 	if (smp_found_config || !cpu_has_apic)
 		return;
 
-	value = apic_read(APIC_LVR);
-
 	/*
 	 * Do not trust the local APIC being empty at bootup.
 	 */
@@ -697,7 +852,15 @@
 	value = apic_read(APIC_SPIV);
 	value &= ~APIC_VECTOR_MASK;
 	value |= APIC_SPIV_APIC_ENABLED;
-	value |= APIC_SPIV_FOCUS_DISABLED;
+
+#ifdef CONFIG_X86_32
+	/* This bit is reserved on P4/Xeon and should be cleared */
+	if ((boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) &&
+	    (boot_cpu_data.x86 == 15))
+		value &= ~APIC_SPIV_FOCUS_DISABLED;
+	else
+#endif
+		value |= APIC_SPIV_FOCUS_DISABLED;
 	value |= SPURIOUS_APIC_VECTOR;
 	apic_write(APIC_SPIV, value);
 
@@ -706,9 +869,50 @@
 	 */
 	apic_write(APIC_LVT0, APIC_DM_EXTINT);
 	value = APIC_DM_NMI;
+	if (!lapic_is_integrated())		/* 82489DX */
+		value |= APIC_LVT_LEVEL_TRIGGER;
 	apic_write(APIC_LVT1, value);
 }
 
+static void __cpuinit lapic_setup_esr(void)
+{
+	unsigned long oldvalue, value, maxlvt;
+	if (lapic_is_integrated() && !esr_disable) {
+		if (esr_disable) {
+			/*
+			 * Something untraceable is creating bad interrupts on
+			 * secondary quads ... for the moment, just leave the
+			 * ESR disabled - we can't do anything useful with the
+			 * errors anyway - mbligh
+			 */
+			printk(KERN_INFO "Leaving ESR disabled.\n");
+			return;
+		}
+		/* !82489DX */
+		maxlvt = lapic_get_maxlvt();
+		if (maxlvt > 3)		/* Due to the Pentium erratum 3AP. */
+			apic_write(APIC_ESR, 0);
+		oldvalue = apic_read(APIC_ESR);
+
+		/* enables sending errors */
+		value = ERROR_APIC_VECTOR;
+		apic_write(APIC_LVTERR, value);
+		/*
+		 * spec says clear errors after enabling vector.
+		 */
+		if (maxlvt > 3)
+			apic_write(APIC_ESR, 0);
+		value = apic_read(APIC_ESR);
+		if (value != oldvalue)
+			apic_printk(APIC_VERBOSE, "ESR value before enabling "
+				"vector: 0x%08lx  after: 0x%08lx\n",
+				oldvalue, value);
+	} else {
+		printk(KERN_INFO "No ESR for 82489DX.\n");
+	}
+}
+
+
 /**
  * setup_local_APIC - setup the local APIC
  */
@@ -814,25 +1018,143 @@
 	preempt_enable();
 }
 
-static void __cpuinit lapic_setup_esr(void)
-{
-	unsigned maxlvt = lapic_get_maxlvt();
-
-	apic_write(APIC_LVTERR, ERROR_APIC_VECTOR);
-	/*
-	 * spec says clear errors after enabling vector.
-	 */
-	if (maxlvt > 3)
-		apic_write(APIC_ESR, 0);
-}
-
 void __cpuinit end_local_APIC_setup(void)
 {
 	lapic_setup_esr();
+
+#ifdef CONFIG_X86_32
+	{
+		unsigned int value;
+		/* Disable the local apic timer */
+		value = apic_read(APIC_LVTT);
+		value |= (APIC_LVT_MASKED | LOCAL_TIMER_VECTOR);
+		apic_write(APIC_LVTT, value);
+	}
+#endif
+
 	setup_apic_nmi_watchdog(NULL);
 	apic_pm_activate();
 }
 
+void check_x2apic(void)
+{
+	int msr, msr2;
+
+	rdmsr(MSR_IA32_APICBASE, msr, msr2);
+
+	if (msr & X2APIC_ENABLE) {
+		printk("x2apic enabled by BIOS, switching to x2apic ops\n");
+		x2apic_preenabled = x2apic = 1;
+		apic_ops = &x2apic_ops;
+	}
+}
+
+void enable_x2apic(void)
+{
+	int msr, msr2;
+
+	rdmsr(MSR_IA32_APICBASE, msr, msr2);
+	if (!(msr & X2APIC_ENABLE)) {
+		printk("Enabling x2apic\n");
+		wrmsr(MSR_IA32_APICBASE, msr | X2APIC_ENABLE, 0);
+	}
+}
+
+void enable_IR_x2apic(void)
+{
+#ifdef CONFIG_INTR_REMAP
+	int ret;
+	unsigned long flags;
+
+	if (!cpu_has_x2apic)
+		return;
+
+	if (!x2apic_preenabled && disable_x2apic) {
+		printk(KERN_INFO
+		       "Skipped enabling x2apic and Interrupt-remapping "
+		       "because of nox2apic\n");
+		return;
+	}
+
+	if (x2apic_preenabled && disable_x2apic)
+		panic("Bios already enabled x2apic, can't enforce nox2apic");
+
+	if (!x2apic_preenabled && skip_ioapic_setup) {
+		printk(KERN_INFO
+		       "Skipped enabling x2apic and Interrupt-remapping "
+		       "because of skipping io-apic setup\n");
+		return;
+	}
+
+	ret = dmar_table_init();
+	if (ret) {
+		printk(KERN_INFO
+		       "dmar_table_init() failed with %d:\n", ret);
+
+		if (x2apic_preenabled)
+			panic("x2apic enabled by bios. But IR enabling failed");
+		else
+			printk(KERN_INFO
+			       "Not enabling x2apic,Intr-remapping\n");
+		return;
+	}
+
+	local_irq_save(flags);
+	mask_8259A();
+	save_mask_IO_APIC_setup();
+
+	ret = enable_intr_remapping(1);
+
+	if (ret && x2apic_preenabled) {
+		local_irq_restore(flags);
+		panic("x2apic enabled by bios. But IR enabling failed");
+	}
+
+	if (ret)
+		goto end;
+
+	if (!x2apic) {
+		x2apic = 1;
+		apic_ops = &x2apic_ops;
+		enable_x2apic();
+	}
+end:
+	if (ret)
+		/*
+		 * IR enabling failed
+		 */
+		restore_IO_APIC_setup();
+	else
+		reinit_intr_remapped_IO_APIC(x2apic_preenabled);
+
+	unmask_8259A();
+	local_irq_restore(flags);
+
+	if (!ret) {
+		if (!x2apic_preenabled)
+			printk(KERN_INFO
+			       "Enabled x2apic and interrupt-remapping\n");
+		else
+			printk(KERN_INFO
+			       "Enabled Interrupt-remapping\n");
+	} else
+		printk(KERN_ERR
+		       "Failed to enable Interrupt-remapping and x2apic\n");
+#else
+	if (!cpu_has_x2apic)
+		return;
+
+	if (x2apic_preenabled)
+		panic("x2apic enabled prior OS handover,"
+		      " enable CONFIG_INTR_REMAP");
+
+	printk(KERN_INFO "Enable CONFIG_INTR_REMAP for enabling intr-remapping "
+	       " and x2apic\n");
+#endif
+
+	return;
+}
+
 /*
  * Detect and enable local APICs on non-SMP boards.
  * Original code written by Keir Fraser.
@@ -872,7 +1194,7 @@
 	 * Fetch the APIC ID of the BSP in case we have a
 	 * default configuration (or the MP table is broken).
 	 */
-	boot_cpu_physical_apicid = GET_APIC_ID(read_apic_id());
+	boot_cpu_physical_apicid = read_apic_id();
 }
 
 /**
@@ -880,6 +1202,11 @@
  */
 void __init init_apic_mappings(void)
 {
+	if (x2apic) {
+		boot_cpu_physical_apicid = read_apic_id();
+		return;
+	}
+
 	/*
 	 * If no local APIC can be found then set up a fake all
 	 * zeroes page to simulate the local APIC and another
@@ -899,13 +1226,15 @@
 	 * Fetch the APIC ID of the BSP in case we have a
 	 * default configuration (or the MP table is broken).
 	 */
-	boot_cpu_physical_apicid = GET_APIC_ID(read_apic_id());
+	boot_cpu_physical_apicid = read_apic_id();
 }
 
 /*
  * This initializes the IO-APIC and APIC hardware if this is
  * a UP kernel.
  */
+int apic_version[MAX_APICS];
+
 int __init APIC_init_uniprocessor(void)
 {
 	if (disable_apic) {
@@ -918,6 +1247,9 @@
 		return -1;
 	}
 
+	enable_IR_x2apic();
+	setup_apic_routing();
+
 	verify_local_APIC();
 
 	connect_bsp_APIC();
@@ -1004,17 +1336,57 @@
 }
 
 /**
- *  * connect_bsp_APIC - attach the APIC to the interrupt system
- *   */
+ * connect_bsp_APIC - attach the APIC to the interrupt system
+ */
 void __init connect_bsp_APIC(void)
 {
+#ifdef CONFIG_X86_32
+	if (pic_mode) {
+		/*
+		 * Do not trust the local APIC being empty at bootup.
+		 */
+		clear_local_APIC();
+		/*
+		 * PIC mode, enable APIC mode in the IMCR, i.e.  connect BSP's
+		 * local APIC to INT and NMI lines.
+		 */
+		apic_printk(APIC_VERBOSE, "leaving PIC mode, "
+				"enabling APIC mode.\n");
+		outb(0x70, 0x22);
+		outb(0x01, 0x23);
+	}
+#endif
 	enable_apic_mode();
 }
 
+/**
+ * disconnect_bsp_APIC - detach the APIC from the interrupt system
+ * @virt_wire_setup:	indicates, whether virtual wire mode is selected
+ *
+ * Virtual wire mode is necessary to deliver legacy interrupts even when the
+ * APIC is disabled.
+ */
 void disconnect_bsp_APIC(int virt_wire_setup)
 {
+	unsigned int value;
+
+#ifdef CONFIG_X86_32
+	if (pic_mode) {
+		/*
+		 * Put the board back into PIC mode (has an effect only on
+		 * certain older boards).  Note that APIC interrupts, including
+		 * IPIs, won't work beyond this point!  The only exception are
+		 * INIT IPIs.
+		 */
+		apic_printk(APIC_VERBOSE, "disabling APIC mode, "
+				"entering PIC mode.\n");
+		outb(0x70, 0x22);
+		outb(0x00, 0x23);
+		return;
+	}
+#endif
+
 	/* Go back to Virtual Wire compatibility mode */
-	unsigned long value;
 
 	/* For the spurious interrupt use vector F, and enable it */
 	value = apic_read(APIC_SPIV);
@@ -1040,7 +1412,10 @@
 		apic_write(APIC_LVT0, APIC_LVT_MASKED);
 	}
 
-	/* For LVT1 make it edge triggered, active high, nmi and enabled */
+	/*
+	 * For LVT1 make it edge triggered, active high,
+	 * nmi and enabled
+	 */
 	value = apic_read(APIC_LVT1);
 	value &= ~(APIC_MODE_MASK | APIC_SEND_PENDING |
 			APIC_INPUT_POLARITY | APIC_LVT_REMOTE_IRR |
@@ -1055,9 +1430,20 @@
 	int cpu;
 	cpumask_t tmp_map;
 
+	/*
+	 * Validate version
+	 */
+	if (version == 0x0) {
+		printk(KERN_WARNING "BIOS bug, APIC version is 0 for CPU#%d! "
+				"fixing up to 0x10. (tell your hw vendor)\n",
+				version);
+		version = 0x10;
+	}
+	apic_version[apicid] = version;
+
 	if (num_processors >= NR_CPUS) {
 		printk(KERN_WARNING "WARNING: NR_CPUS limit of %i reached."
-		       " Processor ignored.\n", NR_CPUS);
+			"  Processor ignored.\n", NR_CPUS);
 		return;
 	}
 
@@ -1077,6 +1463,29 @@
 	if (apicid > max_physical_apicid)
 		max_physical_apicid = apicid;
 
+#ifdef CONFIG_X86_32
+	/*
+	 * Would be preferable to switch to bigsmp when CONFIG_HOTPLUG_CPU=y
+	 * but we need to work other dependencies like SMP_SUSPEND etc
+	 * before this can be done without some confusion.
+	 * if (CPU_HOTPLUG_ENABLED || num_processors > 8)
+	 *       - Ashok Raj <ashok.raj@intel.com>
+	 */
+	if (max_physical_apicid >= 8) {
+		switch (boot_cpu_data.x86_vendor) {
+		case X86_VENDOR_INTEL:
+			if (!APIC_XAPIC(version)) {
+				def_to_bigsmp = 0;
+				break;
+			}
+			/* If P4 and above fall through */
+		case X86_VENDOR_AMD:
+			def_to_bigsmp = 1;
+		}
+	}
+#endif
+
+#if defined(CONFIG_X86_SMP) || defined(CONFIG_X86_64)
 	/* are we being called early in kernel startup? */
 	if (early_per_cpu_ptr(x86_cpu_to_apicid)) {
 		u16 *cpu_to_apicid = early_per_cpu_ptr(x86_cpu_to_apicid);
@@ -1088,20 +1497,28 @@
 		per_cpu(x86_cpu_to_apicid, cpu) = apicid;
 		per_cpu(x86_bios_cpu_apicid, cpu) = apicid;
 	}
+#endif
 
 	cpu_set(cpu, cpu_possible_map);
 	cpu_set(cpu, cpu_present_map);
 }
 
+int hard_smp_processor_id(void)
+{
+	return read_apic_id();
+}
+
 /*
  * Power management
  */
 #ifdef CONFIG_PM
 
 static struct {
-	/* 'active' is true if the local APIC was enabled by us and
-	   not the BIOS; this signifies that we are also responsible
-	   for disabling it before entering apm/acpi suspend */
+	/*
+	 * 'active' is true if the local APIC was enabled by us and
+	 * not the BIOS; this signifies that we are also responsible
+	 * for disabling it before entering apm/acpi suspend
+	 */
 	int active;
 	/* r/w apic fields */
 	unsigned int apic_id;
@@ -1129,7 +1546,7 @@
 
 	maxlvt = lapic_get_maxlvt();
 
-	apic_pm_state.apic_id = read_apic_id();
+	apic_pm_state.apic_id = apic_read(APIC_ID);
 	apic_pm_state.apic_taskpri = apic_read(APIC_TASKPRI);
 	apic_pm_state.apic_ldr = apic_read(APIC_LDR);
 	apic_pm_state.apic_dfr = apic_read(APIC_DFR);
@@ -1142,10 +1559,11 @@
 	apic_pm_state.apic_lvterr = apic_read(APIC_LVTERR);
 	apic_pm_state.apic_tmict = apic_read(APIC_TMICT);
 	apic_pm_state.apic_tdcr = apic_read(APIC_TDCR);
-#ifdef CONFIG_X86_MCE_INTEL
+#if defined(CONFIG_X86_MCE_P4THERMAL) || defined(CONFIG_X86_MCE_INTEL)
 	if (maxlvt >= 5)
 		apic_pm_state.apic_thmr = apic_read(APIC_LVTTHMR);
 #endif
+
 	local_irq_save(flags);
 	disable_local_APIC();
 	local_irq_restore(flags);
@@ -1164,10 +1582,25 @@
 	maxlvt = lapic_get_maxlvt();
 
 	local_irq_save(flags);
-	rdmsr(MSR_IA32_APICBASE, l, h);
-	l &= ~MSR_IA32_APICBASE_BASE;
-	l |= MSR_IA32_APICBASE_ENABLE | mp_lapic_addr;
-	wrmsr(MSR_IA32_APICBASE, l, h);
+
+#ifdef CONFIG_X86_64
+	if (x2apic)
+		enable_x2apic();
+	else
+#endif
+	{
+		/*
+		 * Make sure the APICBASE points to the right address
+		 *
+		 * FIXME! This will be wrong if we ever support suspend on
+		 * SMP! We'll need to do this as part of the CPU restore!
+		 */
+		rdmsr(MSR_IA32_APICBASE, l, h);
+		l &= ~MSR_IA32_APICBASE_BASE;
+		l |= MSR_IA32_APICBASE_ENABLE | mp_lapic_addr;
+		wrmsr(MSR_IA32_APICBASE, l, h);
+	}
+
 	apic_write(APIC_LVTERR, ERROR_APIC_VECTOR | APIC_LVT_MASKED);
 	apic_write(APIC_ID, apic_pm_state.apic_id);
 	apic_write(APIC_DFR, apic_pm_state.apic_dfr);
@@ -1176,7 +1609,7 @@
 	apic_write(APIC_SPIV, apic_pm_state.apic_spiv);
 	apic_write(APIC_LVT0, apic_pm_state.apic_lvt0);
 	apic_write(APIC_LVT1, apic_pm_state.apic_lvt1);
-#ifdef CONFIG_X86_MCE_INTEL
+#if defined(CONFIG_X86_MCE_P4THERMAL) || defined(CONFIG_X86_MCE_INTEL)
 	if (maxlvt >= 5)
 		apic_write(APIC_LVTTHMR, apic_pm_state.apic_thmr);
 #endif
@@ -1190,10 +1623,17 @@
 	apic_write(APIC_LVTERR, apic_pm_state.apic_lvterr);
 	apic_write(APIC_ESR, 0);
 	apic_read(APIC_ESR);
+
 	local_irq_restore(flags);
+
 	return 0;
 }
 
+/*
+ * This device has no shutdown method - fully functioning local APICs
+ * are needed on every CPU up until machine_halt/restart/poweroff.
+ */
+
 static struct sysdev_class lapic_sysclass = {
 	.name		= "lapic",
 	.resume		= lapic_resume,
@@ -1307,31 +1747,19 @@
 	return (clusters > 2);
 }
 
+static __init int setup_nox2apic(char *str)
+{
+	disable_x2apic = 1;
+	clear_cpu_cap(&boot_cpu_data, X86_FEATURE_X2APIC);
+	return 0;
+}
+early_param("nox2apic", setup_nox2apic);
+
+
 /*
  * APIC command line parameters
  */
-static int __init apic_set_verbosity(char *str)
-{
-	if (str == NULL)  {
-		skip_ioapic_setup = 0;
-		ioapic_force = 1;
-		return 0;
-	}
-	if (strcmp("debug", str) == 0)
-		apic_verbosity = APIC_DEBUG;
-	else if (strcmp("verbose", str) == 0)
-		apic_verbosity = APIC_VERBOSE;
-	else {
-		printk(KERN_WARNING "APIC Verbosity level %s not recognised"
-				" use apic=verbose or apic=debug\n", str);
-		return -EINVAL;
-	}
-
-	return 0;
-}
-early_param("apic", apic_set_verbosity);
-
-static __init int setup_disableapic(char *str)
+static int __init setup_disableapic(char *arg)
 {
 	disable_apic = 1;
 	setup_clear_cpu_cap(X86_FEATURE_APIC);
@@ -1340,9 +1768,9 @@
 early_param("disableapic", setup_disableapic);
 
 /* same as disableapic, for compatibility */
-static __init int setup_nolapic(char *str)
+static int __init setup_nolapic(char *arg)
 {
-	return setup_disableapic(str);
+	return setup_disableapic(arg);
 }
 early_param("nolapic", setup_nolapic);
 
@@ -1353,14 +1781,19 @@
 }
 early_param("lapic_timer_c2_ok", parse_lapic_timer_c2_ok);
 
-static __init int setup_noapictimer(char *str)
+static int __init parse_disable_apic_timer(char *arg)
 {
-	if (str[0] != ' ' && str[0] != 0)
-		return 0;
 	disable_apic_timer = 1;
-	return 1;
+	return 0;
 }
-__setup("noapictimer", setup_noapictimer);
+early_param("noapictimer", parse_disable_apic_timer);
+
+static int __init parse_nolapic_timer(char *arg)
+{
+	disable_apic_timer = 1;
+	return 0;
+}
+early_param("nolapic_timer", parse_nolapic_timer);
 
 static __init int setup_apicpmtimer(char *s)
 {
@@ -1370,6 +1803,31 @@
 }
 __setup("apicpmtimer", setup_apicpmtimer);
 
+static int __init apic_set_verbosity(char *arg)
+{
+	if (!arg)  {
+#ifdef CONFIG_X86_64
+		skip_ioapic_setup = 0;
+		ioapic_force = 1;
+		return 0;
+#endif
+		return -EINVAL;
+	}
+
+	if (strcmp("debug", arg) == 0)
+		apic_verbosity = APIC_DEBUG;
+	else if (strcmp("verbose", arg) == 0)
+		apic_verbosity = APIC_VERBOSE;
+	else {
+		printk(KERN_WARNING "APIC Verbosity level %s not recognised"
+			" use apic=verbose or apic=debug\n", arg);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+early_param("apic", apic_set_verbosity);
+
 static int __init lapic_insert_resource(void)
 {
 	if (!apic_phys)
diff --git a/arch/x86/kernel/apm_32.c b/arch/x86/kernel/apm_32.c
index 9ee24e6..5145a6e 100644
--- a/arch/x86/kernel/apm_32.c
+++ b/arch/x86/kernel/apm_32.c
@@ -228,12 +228,12 @@
 #include <linux/suspend.h>
 #include <linux/kthread.h>
 #include <linux/jiffies.h>
-#include <linux/smp_lock.h>
 
 #include <asm/system.h>
 #include <asm/uaccess.h>
 #include <asm/desc.h>
 #include <asm/i8253.h>
+#include <asm/olpc.h>
 #include <asm/paravirt.h>
 #include <asm/reboot.h>
 
@@ -2217,7 +2217,7 @@
 
 	dmi_check_system(apm_dmi_table);
 
-	if (apm_info.bios.version == 0 || paravirt_enabled()) {
+	if (apm_info.bios.version == 0 || paravirt_enabled() || machine_is_olpc()) {
 		printk(KERN_INFO "apm: BIOS not found.\n");
 		return -ENODEV;
 	}
diff --git a/arch/x86/kernel/asm-offsets_64.c b/arch/x86/kernel/asm-offsets_64.c
index aa89387..505543a 100644
--- a/arch/x86/kernel/asm-offsets_64.c
+++ b/arch/x86/kernel/asm-offsets_64.c
@@ -22,7 +22,7 @@
 
 #define __NO_STUBS 1
 #undef __SYSCALL
-#undef _ASM_X86_64_UNISTD_H_
+#undef ASM_X86__UNISTD_64_H
 #define __SYSCALL(nr, sym) [nr] = 1,
 static char syscalls[] = {
 #include <asm/unistd.h>
diff --git a/arch/x86/kernel/bios_uv.c b/arch/x86/kernel/bios_uv.c
index c639bd5..fdd585f 100644
--- a/arch/x86/kernel/bios_uv.c
+++ b/arch/x86/kernel/bios_uv.c
@@ -25,11 +25,11 @@
 {
 	const char *str;
 	switch (status) {
-	case  0: str = "Call completed without error"; break;
-	case -1: str = "Not implemented"; break;
-	case -2: str = "Invalid argument"; break;
-	case -3: str = "Call completed with error"; break;
-	default: str = "Unknown BIOS status code"; break;
+	case  0: str = "Call completed without error";	break;
+	case -1: str = "Not implemented";		break;
+	case -2: str = "Invalid argument";		break;
+	case -3: str = "Call completed with error";	break;
+	default: str = "Unknown BIOS status code";	break;
 	}
 	return str;
 }
diff --git a/arch/x86/kernel/cpu/Makefile b/arch/x86/kernel/cpu/Makefile
index ee76eaa..7f0b45a 100644
--- a/arch/x86/kernel/cpu/Makefile
+++ b/arch/x86/kernel/cpu/Makefile
@@ -3,22 +3,30 @@
 #
 
 obj-y			:= intel_cacheinfo.o addon_cpuid_features.o
-obj-y			+= proc.o feature_names.o
+obj-y			+= proc.o capflags.o powerflags.o common.o
 
-obj-$(CONFIG_X86_32)	+= common.o bugs.o
-obj-$(CONFIG_X86_64)	+= common_64.o bugs_64.o
-obj-$(CONFIG_X86_32)	+= amd.o
-obj-$(CONFIG_X86_64)	+= amd_64.o
-obj-$(CONFIG_X86_32)	+= cyrix.o
-obj-$(CONFIG_X86_32)	+= centaur.o
-obj-$(CONFIG_X86_64)	+= centaur_64.o
-obj-$(CONFIG_X86_32)	+= transmeta.o
-obj-$(CONFIG_X86_32)	+= intel.o
-obj-$(CONFIG_X86_64)	+= intel_64.o
-obj-$(CONFIG_X86_32)	+= umc.o
+obj-$(CONFIG_X86_32)	+= bugs.o cmpxchg.o
+obj-$(CONFIG_X86_64)	+= bugs_64.o
+
+obj-$(CONFIG_CPU_SUP_INTEL)		+= intel.o
+obj-$(CONFIG_CPU_SUP_AMD)		+= amd.o
+obj-$(CONFIG_CPU_SUP_CYRIX_32)		+= cyrix.o
+obj-$(CONFIG_CPU_SUP_CENTAUR_32)	+= centaur.o
+obj-$(CONFIG_CPU_SUP_CENTAUR_64)	+= centaur_64.o
+obj-$(CONFIG_CPU_SUP_TRANSMETA_32)	+= transmeta.o
+obj-$(CONFIG_CPU_SUP_UMC_32)		+= umc.o
 
 obj-$(CONFIG_X86_MCE)	+= mcheck/
 obj-$(CONFIG_MTRR)	+= mtrr/
 obj-$(CONFIG_CPU_FREQ)	+= cpufreq/
 
 obj-$(CONFIG_X86_LOCAL_APIC) += perfctr-watchdog.o
+
+quiet_cmd_mkcapflags = MKCAP   $@
+      cmd_mkcapflags = $(PERL) $(srctree)/$(src)/mkcapflags.pl $< $@
+
+cpufeature = $(src)/../../../../include/asm-x86/cpufeature.h
+
+targets += capflags.c
+$(obj)/capflags.c: $(cpufeature) $(src)/mkcapflags.pl FORCE
+	$(call if_changed,mkcapflags)
diff --git a/arch/x86/kernel/cpu/addon_cpuid_features.c b/arch/x86/kernel/cpu/addon_cpuid_features.c
index a6ef672..0d9c993 100644
--- a/arch/x86/kernel/cpu/addon_cpuid_features.c
+++ b/arch/x86/kernel/cpu/addon_cpuid_features.c
@@ -7,6 +7,8 @@
 #include <asm/pat.h>
 #include <asm/processor.h>
 
+#include <mach_apic.h>
+
 struct cpuid_bit {
 	u16 feature;
 	u8 reg;
@@ -48,6 +50,92 @@
 	}
 }
 
+/* leaf 0xb SMT level */
+#define SMT_LEVEL	0
+
+/* leaf 0xb sub-leaf types */
+#define INVALID_TYPE	0
+#define SMT_TYPE	1
+#define CORE_TYPE	2
+
+#define LEAFB_SUBTYPE(ecx)		(((ecx) >> 8) & 0xff)
+#define BITS_SHIFT_NEXT_LEVEL(eax)	((eax) & 0x1f)
+#define LEVEL_MAX_SIBLINGS(ebx)		((ebx) & 0xffff)
+
+/*
+ * Check for extended topology enumeration cpuid leaf 0xb and if it
+ * exists, use it for populating initial_apicid and cpu topology
+ * detection.
+ */
+void __cpuinit detect_extended_topology(struct cpuinfo_x86 *c)
+{
+#ifdef CONFIG_SMP
+	unsigned int eax, ebx, ecx, edx, sub_index;
+	unsigned int ht_mask_width, core_plus_mask_width;
+	unsigned int core_select_mask, core_level_siblings;
+
+	if (c->cpuid_level < 0xb)
+		return;
+
+	cpuid_count(0xb, SMT_LEVEL, &eax, &ebx, &ecx, &edx);
+
+	/*
+	 * check if the cpuid leaf 0xb is actually implemented.
+	 */
+	if (ebx == 0 || (LEAFB_SUBTYPE(ecx) != SMT_TYPE))
+		return;
+
+	set_cpu_cap(c, X86_FEATURE_XTOPOLOGY);
+
+	/*
+	 * initial apic id, which also represents 32-bit extended x2apic id.
+	 */
+	c->initial_apicid = edx;
+
+	/*
+	 * Populate HT related information from sub-leaf level 0.
+	 */
+	core_level_siblings = smp_num_siblings = LEVEL_MAX_SIBLINGS(ebx);
+	core_plus_mask_width = ht_mask_width = BITS_SHIFT_NEXT_LEVEL(eax);
+
+	sub_index = 1;
+	do {
+		cpuid_count(0xb, sub_index, &eax, &ebx, &ecx, &edx);
+
+		/*
+		 * Check for the Core type in the implemented sub leaves.
+		 */
+		if (LEAFB_SUBTYPE(ecx) == CORE_TYPE) {
+			core_level_siblings = LEVEL_MAX_SIBLINGS(ebx);
+			core_plus_mask_width = BITS_SHIFT_NEXT_LEVEL(eax);
+			break;
+		}
+
+		sub_index++;
+	} while (LEAFB_SUBTYPE(ecx) != INVALID_TYPE);
+
+	core_select_mask = (~(-1 << core_plus_mask_width)) >> ht_mask_width;
+
+#ifdef CONFIG_X86_32
+	c->cpu_core_id = phys_pkg_id(c->initial_apicid, ht_mask_width)
+						 & core_select_mask;
+	c->phys_proc_id = phys_pkg_id(c->initial_apicid, core_plus_mask_width);
+#else
+	c->cpu_core_id = phys_pkg_id(ht_mask_width) & core_select_mask;
+	c->phys_proc_id = phys_pkg_id(core_plus_mask_width);
+#endif
+	c->x86_max_cores = (core_level_siblings / smp_num_siblings);
+
+
+	printk(KERN_INFO  "CPU: Physical Processor ID: %d\n",
+	       c->phys_proc_id);
+	if (c->x86_max_cores > 1)
+		printk(KERN_INFO  "CPU: Processor Core ID: %d\n",
+		       c->cpu_core_id);
+	return;
+#endif
+}
+
 #ifdef CONFIG_X86_PAT
 void __cpuinit validate_pat_support(struct cpuinfo_x86 *c)
 {
diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c
index 18514ed..32e7352 100644
--- a/arch/x86/kernel/cpu/amd.c
+++ b/arch/x86/kernel/cpu/amd.c
@@ -1,13 +1,22 @@
 #include <linux/init.h>
 #include <linux/bitops.h>
 #include <linux/mm.h>
+
 #include <asm/io.h>
 #include <asm/processor.h>
 #include <asm/apic.h>
 
+#ifdef CONFIG_X86_64
+# include <asm/numa_64.h>
+# include <asm/mmconfig.h>
+# include <asm/cacheflush.h>
+#endif
+
 #include <mach_apic.h>
+
 #include "cpu.h"
 
+#ifdef CONFIG_X86_32
 /*
  *	B step AMD K6 before B 9730xxxx have hardware bugs that can cause
  *	misexecution of code under Linux. Owners of such processors should
@@ -24,26 +33,273 @@
 extern void vide(void);
 __asm__(".align 4\nvide: ret");
 
-static void __cpuinit early_init_amd(struct cpuinfo_x86 *c)
+static void __cpuinit init_amd_k5(struct cpuinfo_x86 *c)
 {
-	if (cpuid_eax(0x80000000) >= 0x80000007) {
-		c->x86_power = cpuid_edx(0x80000007);
-		if (c->x86_power & (1<<8))
-			set_cpu_cap(c, X86_FEATURE_CONSTANT_TSC);
+/*
+ * General Systems BIOSen alias the cpu frequency registers
+ * of the Elan at 0x000df000. Unfortuantly, one of the Linux
+ * drivers subsequently pokes it, and changes the CPU speed.
+ * Workaround : Remove the unneeded alias.
+ */
+#define CBAR		(0xfffc) /* Configuration Base Address  (32-bit) */
+#define CBAR_ENB	(0x80000000)
+#define CBAR_KEY	(0X000000CB)
+	if (c->x86_model == 9 || c->x86_model == 10) {
+		if (inl (CBAR) & CBAR_ENB)
+			outl (0 | CBAR_KEY, CBAR);
+	}
+}
+
+
+static void __cpuinit init_amd_k6(struct cpuinfo_x86 *c)
+{
+	u32 l, h;
+	int mbytes = num_physpages >> (20-PAGE_SHIFT);
+
+	if (c->x86_model < 6) {
+		/* Based on AMD doc 20734R - June 2000 */
+		if (c->x86_model == 0) {
+			clear_cpu_cap(c, X86_FEATURE_APIC);
+			set_cpu_cap(c, X86_FEATURE_PGE);
+		}
+		return;
 	}
 
+	if (c->x86_model == 6 && c->x86_mask == 1) {
+		const int K6_BUG_LOOP = 1000000;
+		int n;
+		void (*f_vide)(void);
+		unsigned long d, d2;
+
+		printk(KERN_INFO "AMD K6 stepping B detected - ");
+
+		/*
+		 * It looks like AMD fixed the 2.6.2 bug and improved indirect
+		 * calls at the same time.
+		 */
+
+		n = K6_BUG_LOOP;
+		f_vide = vide;
+		rdtscl(d);
+		while (n--)
+			f_vide();
+		rdtscl(d2);
+		d = d2-d;
+
+		if (d > 20*K6_BUG_LOOP)
+			printk("system stability may be impaired when more than 32 MB are used.\n");
+		else
+			printk("probably OK (after B9730xxxx).\n");
+		printk(KERN_INFO "Please see http://membres.lycos.fr/poulot/k6bug.html\n");
+	}
+
+	/* K6 with old style WHCR */
+	if (c->x86_model < 8 ||
+	   (c->x86_model == 8 && c->x86_mask < 8)) {
+		/* We can only write allocate on the low 508Mb */
+		if (mbytes > 508)
+			mbytes = 508;
+
+		rdmsr(MSR_K6_WHCR, l, h);
+		if ((l&0x0000FFFF) == 0) {
+			unsigned long flags;
+			l = (1<<0)|((mbytes/4)<<1);
+			local_irq_save(flags);
+			wbinvd();
+			wrmsr(MSR_K6_WHCR, l, h);
+			local_irq_restore(flags);
+			printk(KERN_INFO "Enabling old style K6 write allocation for %d Mb\n",
+				mbytes);
+		}
+		return;
+	}
+
+	if ((c->x86_model == 8 && c->x86_mask > 7) ||
+	     c->x86_model == 9 || c->x86_model == 13) {
+		/* The more serious chips .. */
+
+		if (mbytes > 4092)
+			mbytes = 4092;
+
+		rdmsr(MSR_K6_WHCR, l, h);
+		if ((l&0xFFFF0000) == 0) {
+			unsigned long flags;
+			l = ((mbytes>>2)<<22)|(1<<16);
+			local_irq_save(flags);
+			wbinvd();
+			wrmsr(MSR_K6_WHCR, l, h);
+			local_irq_restore(flags);
+			printk(KERN_INFO "Enabling new style K6 write allocation for %d Mb\n",
+				mbytes);
+		}
+
+		return;
+	}
+
+	if (c->x86_model == 10) {
+		/* AMD Geode LX is model 10 */
+		/* placeholder for any needed mods */
+		return;
+	}
+}
+
+static void __cpuinit init_amd_k7(struct cpuinfo_x86 *c)
+{
+	u32 l, h;
+
+	/*
+	 * Bit 15 of Athlon specific MSR 15, needs to be 0
+	 * to enable SSE on Palomino/Morgan/Barton CPU's.
+	 * If the BIOS didn't enable it already, enable it here.
+	 */
+	if (c->x86_model >= 6 && c->x86_model <= 10) {
+		if (!cpu_has(c, X86_FEATURE_XMM)) {
+			printk(KERN_INFO "Enabling disabled K7/SSE Support.\n");
+			rdmsr(MSR_K7_HWCR, l, h);
+			l &= ~0x00008000;
+			wrmsr(MSR_K7_HWCR, l, h);
+			set_cpu_cap(c, X86_FEATURE_XMM);
+		}
+	}
+
+	/*
+	 * It's been determined by AMD that Athlons since model 8 stepping 1
+	 * are more robust with CLK_CTL set to 200xxxxx instead of 600xxxxx
+	 * As per AMD technical note 27212 0.2
+	 */
+	if ((c->x86_model == 8 && c->x86_mask >= 1) || (c->x86_model > 8)) {
+		rdmsr(MSR_K7_CLK_CTL, l, h);
+		if ((l & 0xfff00000) != 0x20000000) {
+			printk ("CPU: CLK_CTL MSR was %x. Reprogramming to %x\n", l,
+				((l & 0x000fffff)|0x20000000));
+			wrmsr(MSR_K7_CLK_CTL, (l & 0x000fffff)|0x20000000, h);
+		}
+	}
+
+	set_cpu_cap(c, X86_FEATURE_K7);
+}
+#endif
+
+#if defined(CONFIG_NUMA) && defined(CONFIG_X86_64)
+static int __cpuinit nearby_node(int apicid)
+{
+	int i, node;
+
+	for (i = apicid - 1; i >= 0; i--) {
+		node = apicid_to_node[i];
+		if (node != NUMA_NO_NODE && node_online(node))
+			return node;
+	}
+	for (i = apicid + 1; i < MAX_LOCAL_APIC; i++) {
+		node = apicid_to_node[i];
+		if (node != NUMA_NO_NODE && node_online(node))
+			return node;
+	}
+	return first_node(node_online_map); /* Shouldn't happen */
+}
+#endif
+
+/*
+ * On a AMD dual core setup the lower bits of the APIC id distingush the cores.
+ * Assumes number of cores is a power of two.
+ */
+static void __cpuinit amd_detect_cmp(struct cpuinfo_x86 *c)
+{
+#ifdef CONFIG_X86_HT
+	unsigned bits;
+
+	bits = c->x86_coreid_bits;
+
+	/* Low order bits define the core id (index of core in socket) */
+	c->cpu_core_id = c->initial_apicid & ((1 << bits)-1);
+	/* Convert the initial APIC ID into the socket ID */
+	c->phys_proc_id = c->initial_apicid >> bits;
+#endif
+}
+
+static void __cpuinit srat_detect_node(struct cpuinfo_x86 *c)
+{
+#if defined(CONFIG_NUMA) && defined(CONFIG_X86_64)
+	int cpu = smp_processor_id();
+	int node;
+	unsigned apicid = hard_smp_processor_id();
+
+	node = c->phys_proc_id;
+	if (apicid_to_node[apicid] != NUMA_NO_NODE)
+		node = apicid_to_node[apicid];
+	if (!node_online(node)) {
+		/* Two possibilities here:
+		   - The CPU is missing memory and no node was created.
+		   In that case try picking one from a nearby CPU
+		   - The APIC IDs differ from the HyperTransport node IDs
+		   which the K8 northbridge parsing fills in.
+		   Assume they are all increased by a constant offset,
+		   but in the same order as the HT nodeids.
+		   If that doesn't result in a usable node fall back to the
+		   path for the previous case.  */
+
+		int ht_nodeid = c->initial_apicid;
+
+		if (ht_nodeid >= 0 &&
+		    apicid_to_node[ht_nodeid] != NUMA_NO_NODE)
+			node = apicid_to_node[ht_nodeid];
+		/* Pick a nearby node */
+		if (!node_online(node))
+			node = nearby_node(apicid);
+	}
+	numa_set_node(cpu, node);
+
+	printk(KERN_INFO "CPU %d/%x -> Node %d\n", cpu, apicid, node);
+#endif
+}
+
+static void __cpuinit early_init_amd_mc(struct cpuinfo_x86 *c)
+{
+#ifdef CONFIG_X86_HT
+	unsigned bits, ecx;
+
+	/* Multi core CPU? */
+	if (c->extended_cpuid_level < 0x80000008)
+		return;
+
+	ecx = cpuid_ecx(0x80000008);
+
+	c->x86_max_cores = (ecx & 0xff) + 1;
+
+	/* CPU telling us the core id bits shift? */
+	bits = (ecx >> 12) & 0xF;
+
+	/* Otherwise recompute */
+	if (bits == 0) {
+		while ((1 << bits) < c->x86_max_cores)
+			bits++;
+	}
+
+	c->x86_coreid_bits = bits;
+#endif
+}
+
+static void __cpuinit early_init_amd(struct cpuinfo_x86 *c)
+{
+	early_init_amd_mc(c);
+
+	/* c->x86_power is 8000_0007 edx. Bit 8 is constant TSC */
+	if (c->x86_power & (1<<8))
+		set_cpu_cap(c, X86_FEATURE_CONSTANT_TSC);
+
+#ifdef CONFIG_X86_64
+	set_cpu_cap(c, X86_FEATURE_SYSCALL32);
+#else
 	/*  Set MTRR capability flag if appropriate */
-	if (c->x86_model == 13 || c->x86_model == 9 ||
-	   (c->x86_model == 8 && c->x86_mask >= 8))
-		set_cpu_cap(c, X86_FEATURE_K6_MTRR);
+	if (c->x86 == 5)
+		if (c->x86_model == 13 || c->x86_model == 9 ||
+		    (c->x86_model == 8 && c->x86_mask >= 8))
+			set_cpu_cap(c, X86_FEATURE_K6_MTRR);
+#endif
 }
 
 static void __cpuinit init_amd(struct cpuinfo_x86 *c)
 {
-	u32 l, h;
-	int mbytes = num_physpages >> (20-PAGE_SHIFT);
-	int r;
-
 #ifdef CONFIG_SMP
 	unsigned long long value;
 
@@ -54,7 +310,7 @@
 	 * Errata 63 for SH-B3 steppings
 	 * Errata 122 for all steppings (F+ have it disabled by default)
 	 */
-	if (c->x86 == 15) {
+	if (c->x86 == 0xf) {
 		rdmsrl(MSR_K7_HWCR, value);
 		value |= 1 << 6;
 		wrmsrl(MSR_K7_HWCR, value);
@@ -64,209 +320,119 @@
 	early_init_amd(c);
 
 	/*
-	 *	FIXME: We should handle the K5 here. Set up the write
-	 *	range and also turn on MSR 83 bits 4 and 31 (write alloc,
-	 *	no bus pipeline)
-	 */
-
-	/*
 	 * Bit 31 in normal CPUID used for nonstandard 3DNow ID;
 	 * 3DNow is IDd by bit 31 in extended CPUID (1*32+31) anyway
 	 */
 	clear_cpu_cap(c, 0*32+31);
 
-	r = get_model_name(c);
+#ifdef CONFIG_X86_64
+	/* On C+ stepping K8 rep microcode works well for copy/memset */
+	if (c->x86 == 0xf) {
+		u32 level;
+
+		level = cpuid_eax(1);
+		if((level >= 0x0f48 && level < 0x0f50) || level >= 0x0f58)
+			set_cpu_cap(c, X86_FEATURE_REP_GOOD);
+	}
+	if (c->x86 == 0x10 || c->x86 == 0x11)
+		set_cpu_cap(c, X86_FEATURE_REP_GOOD);
+#else
+
+	/*
+	 *	FIXME: We should handle the K5 here. Set up the write
+	 *	range and also turn on MSR 83 bits 4 and 31 (write alloc,
+	 *	no bus pipeline)
+	 */
 
 	switch (c->x86) {
 	case 4:
-		/*
-		 * General Systems BIOSen alias the cpu frequency registers
-		 * of the Elan at 0x000df000. Unfortuantly, one of the Linux
-		 * drivers subsequently pokes it, and changes the CPU speed.
-		 * Workaround : Remove the unneeded alias.
-		 */
-#define CBAR		(0xfffc) /* Configuration Base Address  (32-bit) */
-#define CBAR_ENB	(0x80000000)
-#define CBAR_KEY	(0X000000CB)
-			if (c->x86_model == 9 || c->x86_model == 10) {
-				if (inl (CBAR) & CBAR_ENB)
-					outl (0 | CBAR_KEY, CBAR);
-			}
-			break;
+		init_amd_k5(c);
+		break;
 	case 5:
-			if (c->x86_model < 6) {
-				/* Based on AMD doc 20734R - June 2000 */
-				if (c->x86_model == 0) {
-					clear_cpu_cap(c, X86_FEATURE_APIC);
-					set_cpu_cap(c, X86_FEATURE_PGE);
-				}
-				break;
-			}
-
-			if (c->x86_model == 6 && c->x86_mask == 1) {
-				const int K6_BUG_LOOP = 1000000;
-				int n;
-				void (*f_vide)(void);
-				unsigned long d, d2;
-
-				printk(KERN_INFO "AMD K6 stepping B detected - ");
-
-				/*
-				 * It looks like AMD fixed the 2.6.2 bug and improved indirect
-				 * calls at the same time.
-				 */
-
-				n = K6_BUG_LOOP;
-				f_vide = vide;
-				rdtscl(d);
-				while (n--)
-					f_vide();
-				rdtscl(d2);
-				d = d2-d;
-
-				if (d > 20*K6_BUG_LOOP)
-					printk("system stability may be impaired when more than 32 MB are used.\n");
-				else
-					printk("probably OK (after B9730xxxx).\n");
-				printk(KERN_INFO "Please see http://membres.lycos.fr/poulot/k6bug.html\n");
-			}
-
-			/* K6 with old style WHCR */
-			if (c->x86_model < 8 ||
-			   (c->x86_model == 8 && c->x86_mask < 8)) {
-				/* We can only write allocate on the low 508Mb */
-				if (mbytes > 508)
-					mbytes = 508;
-
-				rdmsr(MSR_K6_WHCR, l, h);
-				if ((l&0x0000FFFF) == 0) {
-					unsigned long flags;
-					l = (1<<0)|((mbytes/4)<<1);
-					local_irq_save(flags);
-					wbinvd();
-					wrmsr(MSR_K6_WHCR, l, h);
-					local_irq_restore(flags);
-					printk(KERN_INFO "Enabling old style K6 write allocation for %d Mb\n",
-						mbytes);
-				}
-				break;
-			}
-
-			if ((c->x86_model == 8 && c->x86_mask > 7) ||
-			     c->x86_model == 9 || c->x86_model == 13) {
-				/* The more serious chips .. */
-
-				if (mbytes > 4092)
-					mbytes = 4092;
-
-				rdmsr(MSR_K6_WHCR, l, h);
-				if ((l&0xFFFF0000) == 0) {
-					unsigned long flags;
-					l = ((mbytes>>2)<<22)|(1<<16);
-					local_irq_save(flags);
-					wbinvd();
-					wrmsr(MSR_K6_WHCR, l, h);
-					local_irq_restore(flags);
-					printk(KERN_INFO "Enabling new style K6 write allocation for %d Mb\n",
-						mbytes);
-				}
-
-				break;
-			}
-
-			if (c->x86_model == 10) {
-				/* AMD Geode LX is model 10 */
-				/* placeholder for any needed mods */
-				break;
-			}
-			break;
+		init_amd_k6(c);
+		break;
 	case 6: /* An Athlon/Duron */
-
-			/*
-			 * Bit 15 of Athlon specific MSR 15, needs to be 0
-			 * to enable SSE on Palomino/Morgan/Barton CPU's.
-			 * If the BIOS didn't enable it already, enable it here.
-			 */
-			if (c->x86_model >= 6 && c->x86_model <= 10) {
-				if (!cpu_has(c, X86_FEATURE_XMM)) {
-					printk(KERN_INFO "Enabling disabled K7/SSE Support.\n");
-					rdmsr(MSR_K7_HWCR, l, h);
-					l &= ~0x00008000;
-					wrmsr(MSR_K7_HWCR, l, h);
-					set_cpu_cap(c, X86_FEATURE_XMM);
-				}
-			}
-
-			/*
-			 * It's been determined by AMD that Athlons since model 8 stepping 1
-			 * are more robust with CLK_CTL set to 200xxxxx instead of 600xxxxx
-			 * As per AMD technical note 27212 0.2
-			 */
-			if ((c->x86_model == 8 && c->x86_mask >= 1) || (c->x86_model > 8)) {
-				rdmsr(MSR_K7_CLK_CTL, l, h);
-				if ((l & 0xfff00000) != 0x20000000) {
-					printk ("CPU: CLK_CTL MSR was %x. Reprogramming to %x\n", l,
-						((l & 0x000fffff)|0x20000000));
-					wrmsr(MSR_K7_CLK_CTL, (l & 0x000fffff)|0x20000000, h);
-				}
-			}
-			break;
-	}
-
-	switch (c->x86) {
-	case 15:
-	/* Use K8 tuning for Fam10h and Fam11h */
-	case 0x10:
-	case 0x11:
-		set_cpu_cap(c, X86_FEATURE_K8);
+		init_amd_k7(c);
 		break;
-	case 6:
-		set_cpu_cap(c, X86_FEATURE_K7);
-		break;
-	}
-	if (c->x86 >= 6)
-		set_cpu_cap(c, X86_FEATURE_FXSAVE_LEAK);
-
-	display_cacheinfo(c);
-
-	if (cpuid_eax(0x80000000) >= 0x80000008)
-		c->x86_max_cores = (cpuid_ecx(0x80000008) & 0xff) + 1;
-
-#ifdef CONFIG_X86_HT
-	/*
-	 * On a AMD multi core setup the lower bits of the APIC id
-	 * distinguish the cores.
-	 */
-	if (c->x86_max_cores > 1) {
-		int cpu = smp_processor_id();
-		unsigned bits = (cpuid_ecx(0x80000008) >> 12) & 0xf;
-
-		if (bits == 0) {
-			while ((1 << bits) < c->x86_max_cores)
-				bits++;
-		}
-		c->cpu_core_id = c->phys_proc_id & ((1<<bits)-1);
-		c->phys_proc_id >>= bits;
-		printk(KERN_INFO "CPU %d(%d) -> Core %d\n",
-		       cpu, c->x86_max_cores, c->cpu_core_id);
-	}
-#endif
-
-	if (cpuid_eax(0x80000000) >= 0x80000006) {
-		if ((c->x86 == 0x10) && (cpuid_edx(0x80000006) & 0xf000))
-			num_cache_leaves = 4;
-		else
-			num_cache_leaves = 3;
 	}
 
 	/* K6s reports MCEs but don't actually have all the MSRs */
 	if (c->x86 < 6)
 		clear_cpu_cap(c, X86_FEATURE_MCE);
+#endif
 
-	if (cpu_has_xmm2)
+	/* Enable workaround for FXSAVE leak */
+	if (c->x86 >= 6)
+		set_cpu_cap(c, X86_FEATURE_FXSAVE_LEAK);
+
+	if (!c->x86_model_id[0]) {
+		switch (c->x86) {
+		case 0xf:
+			/* Should distinguish Models here, but this is only
+			   a fallback anyways. */
+			strcpy(c->x86_model_id, "Hammer");
+			break;
+		}
+	}
+
+	display_cacheinfo(c);
+
+	/* Multi core CPU? */
+	if (c->extended_cpuid_level >= 0x80000008) {
+		amd_detect_cmp(c);
+		srat_detect_node(c);
+	}
+
+#ifdef CONFIG_X86_32
+	detect_ht(c);
+#endif
+
+	if (c->extended_cpuid_level >= 0x80000006) {
+		if ((c->x86 >= 0x0f) && (cpuid_edx(0x80000006) & 0xf000))
+			num_cache_leaves = 4;
+		else
+			num_cache_leaves = 3;
+	}
+
+	if (c->x86 >= 0xf && c->x86 <= 0x11)
+		set_cpu_cap(c, X86_FEATURE_K8);
+
+	if (cpu_has_xmm2) {
+		/* MFENCE stops RDTSC speculation */
 		set_cpu_cap(c, X86_FEATURE_MFENCE_RDTSC);
+	}
+
+#ifdef CONFIG_X86_64
+	if (c->x86 == 0x10) {
+		/* do this for boot cpu */
+		if (c == &boot_cpu_data)
+			check_enable_amd_mmconf_dmi();
+
+		fam10h_check_enable_mmcfg();
+	}
+
+	if (c == &boot_cpu_data && c->x86 >= 0xf && c->x86 <= 0x11) {
+		unsigned long long tseg;
+
+		/*
+		 * Split up direct mapping around the TSEG SMM area.
+		 * Don't do it for gbpages because there seems very little
+		 * benefit in doing so.
+		 */
+		if (!rdmsrl_safe(MSR_K8_TSEG_ADDR, &tseg)) {
+		    printk(KERN_DEBUG "tseg: %010llx\n", tseg);
+		    if ((tseg>>PMD_SHIFT) <
+				(max_low_pfn_mapped>>(PMD_SHIFT-PAGE_SHIFT)) ||
+			((tseg>>PMD_SHIFT) <
+				(max_pfn_mapped>>(PMD_SHIFT-PAGE_SHIFT)) &&
+			 (tseg>>PMD_SHIFT) >= (1ULL<<(32 - PMD_SHIFT))))
+			set_memory_4k((unsigned long)__va(tseg), 1);
+		}
+	}
+#endif
 }
 
+#ifdef CONFIG_X86_32
 static unsigned int __cpuinit amd_size_cache(struct cpuinfo_x86 *c, unsigned int size)
 {
 	/* AMD errata T13 (order #21922) */
@@ -279,10 +445,12 @@
 	}
 	return size;
 }
+#endif
 
 static struct cpu_dev amd_cpu_dev __cpuinitdata = {
 	.c_vendor	= "AMD",
 	.c_ident	= { "AuthenticAMD" },
+#ifdef CONFIG_X86_32
 	.c_models = {
 		{ .vendor = X86_VENDOR_AMD, .family = 4, .model_names =
 		  {
@@ -295,9 +463,11 @@
 		  }
 		},
 	},
+	.c_size_cache	= amd_size_cache,
+#endif
 	.c_early_init   = early_init_amd,
 	.c_init		= init_amd,
-	.c_size_cache	= amd_size_cache,
+	.c_x86_vendor	= X86_VENDOR_AMD,
 };
 
-cpu_vendor_dev_register(X86_VENDOR_AMD, &amd_cpu_dev);
+cpu_dev_register(amd_cpu_dev);
diff --git a/arch/x86/kernel/cpu/amd_64.c b/arch/x86/kernel/cpu/amd_64.c
deleted file mode 100644
index d1692b2..0000000
--- a/arch/x86/kernel/cpu/amd_64.c
+++ /dev/null
@@ -1,224 +0,0 @@
-#include <linux/init.h>
-#include <linux/mm.h>
-
-#include <asm/numa_64.h>
-#include <asm/mmconfig.h>
-#include <asm/cacheflush.h>
-
-#include <mach_apic.h>
-
-#include "cpu.h"
-
-int force_mwait __cpuinitdata;
-
-#ifdef CONFIG_NUMA
-static int __cpuinit nearby_node(int apicid)
-{
-	int i, node;
-
-	for (i = apicid - 1; i >= 0; i--) {
-		node = apicid_to_node[i];
-		if (node != NUMA_NO_NODE && node_online(node))
-			return node;
-	}
-	for (i = apicid + 1; i < MAX_LOCAL_APIC; i++) {
-		node = apicid_to_node[i];
-		if (node != NUMA_NO_NODE && node_online(node))
-			return node;
-	}
-	return first_node(node_online_map); /* Shouldn't happen */
-}
-#endif
-
-/*
- * On a AMD dual core setup the lower bits of the APIC id distingush the cores.
- * Assumes number of cores is a power of two.
- */
-static void __cpuinit amd_detect_cmp(struct cpuinfo_x86 *c)
-{
-#ifdef CONFIG_SMP
-	unsigned bits;
-#ifdef CONFIG_NUMA
-	int cpu = smp_processor_id();
-	int node = 0;
-	unsigned apicid = hard_smp_processor_id();
-#endif
-	bits = c->x86_coreid_bits;
-
-	/* Low order bits define the core id (index of core in socket) */
-	c->cpu_core_id = c->initial_apicid & ((1 << bits)-1);
-	/* Convert the initial APIC ID into the socket ID */
-	c->phys_proc_id = c->initial_apicid >> bits;
-
-#ifdef CONFIG_NUMA
-	node = c->phys_proc_id;
-	if (apicid_to_node[apicid] != NUMA_NO_NODE)
-		node = apicid_to_node[apicid];
-	if (!node_online(node)) {
-		/* Two possibilities here:
-		   - The CPU is missing memory and no node was created.
-		   In that case try picking one from a nearby CPU
-		   - The APIC IDs differ from the HyperTransport node IDs
-		   which the K8 northbridge parsing fills in.
-		   Assume they are all increased by a constant offset,
-		   but in the same order as the HT nodeids.
-		   If that doesn't result in a usable node fall back to the
-		   path for the previous case.  */
-
-		int ht_nodeid = c->initial_apicid;
-
-		if (ht_nodeid >= 0 &&
-		    apicid_to_node[ht_nodeid] != NUMA_NO_NODE)
-			node = apicid_to_node[ht_nodeid];
-		/* Pick a nearby node */
-		if (!node_online(node))
-			node = nearby_node(apicid);
-	}
-	numa_set_node(cpu, node);
-
-	printk(KERN_INFO "CPU %d/%x -> Node %d\n", cpu, apicid, node);
-#endif
-#endif
-}
-
-static void __cpuinit early_init_amd_mc(struct cpuinfo_x86 *c)
-{
-#ifdef CONFIG_SMP
-	unsigned bits, ecx;
-
-	/* Multi core CPU? */
-	if (c->extended_cpuid_level < 0x80000008)
-		return;
-
-	ecx = cpuid_ecx(0x80000008);
-
-	c->x86_max_cores = (ecx & 0xff) + 1;
-
-	/* CPU telling us the core id bits shift? */
-	bits = (ecx >> 12) & 0xF;
-
-	/* Otherwise recompute */
-	if (bits == 0) {
-		while ((1 << bits) < c->x86_max_cores)
-			bits++;
-	}
-
-	c->x86_coreid_bits = bits;
-
-#endif
-}
-
-static void __cpuinit early_init_amd(struct cpuinfo_x86 *c)
-{
-	early_init_amd_mc(c);
-
-	/* c->x86_power is 8000_0007 edx. Bit 8 is constant TSC */
-	if (c->x86_power & (1<<8))
-		set_cpu_cap(c, X86_FEATURE_CONSTANT_TSC);
-
-	set_cpu_cap(c, X86_FEATURE_SYSCALL32);
-}
-
-static void __cpuinit init_amd(struct cpuinfo_x86 *c)
-{
-	unsigned level;
-
-#ifdef CONFIG_SMP
-	unsigned long value;
-
-	/*
-	 * Disable TLB flush filter by setting HWCR.FFDIS on K8
-	 * bit 6 of msr C001_0015
-	 *
-	 * Errata 63 for SH-B3 steppings
-	 * Errata 122 for all steppings (F+ have it disabled by default)
-	 */
-	if (c->x86 == 0xf) {
-		rdmsrl(MSR_K8_HWCR, value);
-		value |= 1 << 6;
-		wrmsrl(MSR_K8_HWCR, value);
-	}
-#endif
-
-	/* Bit 31 in normal CPUID used for nonstandard 3DNow ID;
-	   3DNow is IDd by bit 31 in extended CPUID (1*32+31) anyway */
-	clear_cpu_cap(c, 0*32+31);
-
-	/* On C+ stepping K8 rep microcode works well for copy/memset */
-	if (c->x86 == 0xf) {
-		level = cpuid_eax(1);
-		if((level >= 0x0f48 && level < 0x0f50) || level >= 0x0f58)
-			set_cpu_cap(c, X86_FEATURE_REP_GOOD);
-	}
-	if (c->x86 == 0x10 || c->x86 == 0x11)
-		set_cpu_cap(c, X86_FEATURE_REP_GOOD);
-
-	/* Enable workaround for FXSAVE leak */
-	if (c->x86 >= 6)
-		set_cpu_cap(c, X86_FEATURE_FXSAVE_LEAK);
-
-	level = get_model_name(c);
-	if (!level) {
-		switch (c->x86) {
-		case 0xf:
-			/* Should distinguish Models here, but this is only
-			   a fallback anyways. */
-			strcpy(c->x86_model_id, "Hammer");
-			break;
-		}
-	}
-	display_cacheinfo(c);
-
-	/* Multi core CPU? */
-	if (c->extended_cpuid_level >= 0x80000008)
-		amd_detect_cmp(c);
-
-	if (c->extended_cpuid_level >= 0x80000006 &&
-		(cpuid_edx(0x80000006) & 0xf000))
-		num_cache_leaves = 4;
-	else
-		num_cache_leaves = 3;
-
-	if (c->x86 >= 0xf && c->x86 <= 0x11)
-		set_cpu_cap(c, X86_FEATURE_K8);
-
-	/* MFENCE stops RDTSC speculation */
-	set_cpu_cap(c, X86_FEATURE_MFENCE_RDTSC);
-
-	if (c->x86 == 0x10) {
-		/* do this for boot cpu */
-		if (c == &boot_cpu_data)
-			check_enable_amd_mmconf_dmi();
-
-		fam10h_check_enable_mmcfg();
-	}
-
-	if (c == &boot_cpu_data && c->x86 >= 0xf && c->x86 <= 0x11) {
-		unsigned long long tseg;
-
-		/*
-		 * Split up direct mapping around the TSEG SMM area.
-		 * Don't do it for gbpages because there seems very little
-		 * benefit in doing so.
-		 */
-		if (!rdmsrl_safe(MSR_K8_TSEG_ADDR, &tseg)) {
-		    printk(KERN_DEBUG "tseg: %010llx\n", tseg);
-		    if ((tseg>>PMD_SHIFT) <
-				(max_low_pfn_mapped>>(PMD_SHIFT-PAGE_SHIFT)) ||
-			((tseg>>PMD_SHIFT) <
-				(max_pfn_mapped>>(PMD_SHIFT-PAGE_SHIFT)) &&
-			 (tseg>>PMD_SHIFT) >= (1ULL<<(32 - PMD_SHIFT))))
-			set_memory_4k((unsigned long)__va(tseg), 1);
-		}
-	}
-}
-
-static struct cpu_dev amd_cpu_dev __cpuinitdata = {
-	.c_vendor	= "AMD",
-	.c_ident	= { "AuthenticAMD" },
-	.c_early_init   = early_init_amd,
-	.c_init		= init_amd,
-};
-
-cpu_vendor_dev_register(X86_VENDOR_AMD, &amd_cpu_dev);
-
diff --git a/arch/x86/kernel/cpu/centaur.c b/arch/x86/kernel/cpu/centaur.c
index a0534c0..89bfdd9 100644
--- a/arch/x86/kernel/cpu/centaur.c
+++ b/arch/x86/kernel/cpu/centaur.c
@@ -289,7 +289,6 @@
 	if (c->x86_model >= 6 && c->x86_model < 9)
 		set_cpu_cap(c, X86_FEATURE_3DNOW);
 
-	get_model_name(c);
 	display_cacheinfo(c);
 }
 
@@ -475,6 +474,7 @@
 	.c_early_init	= early_init_centaur,
 	.c_init		= init_centaur,
 	.c_size_cache	= centaur_size_cache,
+	.c_x86_vendor	= X86_VENDOR_CENTAUR,
 };
 
-cpu_vendor_dev_register(X86_VENDOR_CENTAUR, &centaur_cpu_dev);
+cpu_dev_register(centaur_cpu_dev);
diff --git a/arch/x86/kernel/cpu/centaur_64.c b/arch/x86/kernel/cpu/centaur_64.c
index 1d181c4..a1625f5 100644
--- a/arch/x86/kernel/cpu/centaur_64.c
+++ b/arch/x86/kernel/cpu/centaur_64.c
@@ -16,9 +16,10 @@
 
 static void __cpuinit init_centaur(struct cpuinfo_x86 *c)
 {
+	early_init_centaur(c);
+
 	if (c->x86 == 0x6 && c->x86_model >= 0xf) {
 		c->x86_cache_alignment = c->x86_clflush_size * 2;
-		set_cpu_cap(c, X86_FEATURE_CONSTANT_TSC);
 		set_cpu_cap(c, X86_FEATURE_REP_GOOD);
 	}
 	set_cpu_cap(c, X86_FEATURE_LFENCE_RDTSC);
@@ -29,7 +30,8 @@
 	.c_ident	= { "CentaurHauls" },
 	.c_early_init	= early_init_centaur,
 	.c_init		= init_centaur,
+	.c_x86_vendor	= X86_VENDOR_CENTAUR,
 };
 
-cpu_vendor_dev_register(X86_VENDOR_CENTAUR, &centaur_cpu_dev);
+cpu_dev_register(centaur_cpu_dev);
 
diff --git a/arch/x86/kernel/cpu/cmpxchg.c b/arch/x86/kernel/cpu/cmpxchg.c
new file mode 100644
index 0000000..2056ccf
--- /dev/null
+++ b/arch/x86/kernel/cpu/cmpxchg.c
@@ -0,0 +1,72 @@
+/*
+ * cmpxchg*() fallbacks for CPU not supporting these instructions
+ */
+
+#include <linux/kernel.h>
+#include <linux/smp.h>
+#include <linux/module.h>
+
+#ifndef CONFIG_X86_CMPXCHG
+unsigned long cmpxchg_386_u8(volatile void *ptr, u8 old, u8 new)
+{
+	u8 prev;
+	unsigned long flags;
+
+	/* Poor man's cmpxchg for 386. Unsuitable for SMP */
+	local_irq_save(flags);
+	prev = *(u8 *)ptr;
+	if (prev == old)
+		*(u8 *)ptr = new;
+	local_irq_restore(flags);
+	return prev;
+}
+EXPORT_SYMBOL(cmpxchg_386_u8);
+
+unsigned long cmpxchg_386_u16(volatile void *ptr, u16 old, u16 new)
+{
+	u16 prev;
+	unsigned long flags;
+
+	/* Poor man's cmpxchg for 386. Unsuitable for SMP */
+	local_irq_save(flags);
+	prev = *(u16 *)ptr;
+	if (prev == old)
+		*(u16 *)ptr = new;
+	local_irq_restore(flags);
+	return prev;
+}
+EXPORT_SYMBOL(cmpxchg_386_u16);
+
+unsigned long cmpxchg_386_u32(volatile void *ptr, u32 old, u32 new)
+{
+	u32 prev;
+	unsigned long flags;
+
+	/* Poor man's cmpxchg for 386. Unsuitable for SMP */
+	local_irq_save(flags);
+	prev = *(u32 *)ptr;
+	if (prev == old)
+		*(u32 *)ptr = new;
+	local_irq_restore(flags);
+	return prev;
+}
+EXPORT_SYMBOL(cmpxchg_386_u32);
+#endif
+
+#ifndef CONFIG_X86_CMPXCHG64
+unsigned long long cmpxchg_486_u64(volatile void *ptr, u64 old, u64 new)
+{
+	u64 prev;
+	unsigned long flags;
+
+	/* Poor man's cmpxchg8b for 386 and 486. Unsuitable for SMP */
+	local_irq_save(flags);
+	prev = *(u64 *)ptr;
+	if (prev == old)
+		*(u64 *)ptr = new;
+	local_irq_restore(flags);
+	return prev;
+}
+EXPORT_SYMBOL(cmpxchg_486_u64);
+#endif
+
diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c
index 8aab851..25581dc 100644
--- a/arch/x86/kernel/cpu/common.c
+++ b/arch/x86/kernel/cpu/common.c
@@ -1,28 +1,62 @@
 #include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
 #include <linux/string.h>
+#include <linux/bootmem.h>
+#include <linux/bitops.h>
+#include <linux/module.h>
+#include <linux/kgdb.h>
+#include <linux/topology.h>
 #include <linux/delay.h>
 #include <linux/smp.h>
-#include <linux/module.h>
 #include <linux/percpu.h>
-#include <linux/bootmem.h>
-#include <asm/processor.h>
 #include <asm/i387.h>
 #include <asm/msr.h>
 #include <asm/io.h>
+#include <asm/linkage.h>
 #include <asm/mmu_context.h>
 #include <asm/mtrr.h>
 #include <asm/mce.h>
 #include <asm/pat.h>
 #include <asm/asm.h>
+#include <asm/numa.h>
 #ifdef CONFIG_X86_LOCAL_APIC
 #include <asm/mpspec.h>
 #include <asm/apic.h>
 #include <mach_apic.h>
+#include <asm/genapic.h>
 #endif
 
+#include <asm/pda.h>
+#include <asm/pgtable.h>
+#include <asm/processor.h>
+#include <asm/desc.h>
+#include <asm/atomic.h>
+#include <asm/proto.h>
+#include <asm/sections.h>
+#include <asm/setup.h>
+
 #include "cpu.h"
 
+static struct cpu_dev *this_cpu __cpuinitdata;
+
+#ifdef CONFIG_X86_64
+/* We need valid kernel segments for data and code in long mode too
+ * IRET will check the segment types  kkeil 2000/10/28
+ * Also sysret mandates a special GDT layout
+ */
+/* The TLS descriptors are currently at a different place compared to i386.
+   Hopefully nobody expects them at a fixed place (Wine?) */
 DEFINE_PER_CPU(struct gdt_page, gdt_page) = { .gdt = {
+	[GDT_ENTRY_KERNEL32_CS] = { { { 0x0000ffff, 0x00cf9b00 } } },
+	[GDT_ENTRY_KERNEL_CS] = { { { 0x0000ffff, 0x00af9b00 } } },
+	[GDT_ENTRY_KERNEL_DS] = { { { 0x0000ffff, 0x00cf9300 } } },
+	[GDT_ENTRY_DEFAULT_USER32_CS] = { { { 0x0000ffff, 0x00cffb00 } } },
+	[GDT_ENTRY_DEFAULT_USER_DS] = { { { 0x0000ffff, 0x00cff300 } } },
+	[GDT_ENTRY_DEFAULT_USER_CS] = { { { 0x0000ffff, 0x00affb00 } } },
+} };
+#else
+DEFINE_PER_CPU_PAGE_ALIGNED(struct gdt_page, gdt_page) = { .gdt = {
 	[GDT_ENTRY_KERNEL_CS] = { { { 0x0000ffff, 0x00cf9a00 } } },
 	[GDT_ENTRY_KERNEL_DS] = { { { 0x0000ffff, 0x00cf9200 } } },
 	[GDT_ENTRY_DEFAULT_USER_CS] = { { { 0x0000ffff, 0x00cffa00 } } },
@@ -56,34 +90,13 @@
 	[GDT_ENTRY_ESPFIX_SS] = { { { 0x00000000, 0x00c09200 } } },
 	[GDT_ENTRY_PERCPU] = { { { 0x00000000, 0x00000000 } } },
 } };
+#endif
 EXPORT_PER_CPU_SYMBOL_GPL(gdt_page);
 
-__u32 cleared_cpu_caps[NCAPINTS] __cpuinitdata;
-
+#ifdef CONFIG_X86_32
 static int cachesize_override __cpuinitdata = -1;
 static int disable_x86_serial_nr __cpuinitdata = 1;
 
-struct cpu_dev *cpu_devs[X86_VENDOR_NUM] = {};
-
-static void __cpuinit default_init(struct cpuinfo_x86 *c)
-{
-	/* Not much we can do here... */
-	/* Check if at least it has cpuid */
-	if (c->cpuid_level == -1) {
-		/* No cpuid. It must be an ancient CPU */
-		if (c->x86 == 4)
-			strcpy(c->x86_model_id, "486");
-		else if (c->x86 == 3)
-			strcpy(c->x86_model_id, "386");
-	}
-}
-
-static struct cpu_dev __cpuinitdata default_cpu = {
-	.c_init	= default_init,
-	.c_vendor = "Unknown",
-};
-static struct cpu_dev *this_cpu __cpuinitdata = &default_cpu;
-
 static int __init cachesize_setup(char *str)
 {
 	get_option(&str, &cachesize_override);
@@ -91,71 +104,91 @@
 }
 __setup("cachesize=", cachesize_setup);
 
-int __cpuinit get_model_name(struct cpuinfo_x86 *c)
+static int __init x86_fxsr_setup(char *s)
 {
-	unsigned int *v;
-	char *p, *q;
-
-	if (cpuid_eax(0x80000000) < 0x80000004)
-		return 0;
-
-	v = (unsigned int *) c->x86_model_id;
-	cpuid(0x80000002, &v[0], &v[1], &v[2], &v[3]);
-	cpuid(0x80000003, &v[4], &v[5], &v[6], &v[7]);
-	cpuid(0x80000004, &v[8], &v[9], &v[10], &v[11]);
-	c->x86_model_id[48] = 0;
-
-	/* Intel chips right-justify this string for some dumb reason;
-	   undo that brain damage */
-	p = q = &c->x86_model_id[0];
-	while (*p == ' ')
-	     p++;
-	if (p != q) {
-	     while (*p)
-		  *q++ = *p++;
-	     while (q <= &c->x86_model_id[48])
-		  *q++ = '\0';	/* Zero-pad the rest */
-	}
-
+	setup_clear_cpu_cap(X86_FEATURE_FXSR);
+	setup_clear_cpu_cap(X86_FEATURE_XMM);
 	return 1;
 }
+__setup("nofxsr", x86_fxsr_setup);
 
-
-void __cpuinit display_cacheinfo(struct cpuinfo_x86 *c)
+static int __init x86_sep_setup(char *s)
 {
-	unsigned int n, dummy, ecx, edx, l2size;
-
-	n = cpuid_eax(0x80000000);
-
-	if (n >= 0x80000005) {
-		cpuid(0x80000005, &dummy, &dummy, &ecx, &edx);
-		printk(KERN_INFO "CPU: L1 I Cache: %dK (%d bytes/line), D cache %dK (%d bytes/line)\n",
-			edx>>24, edx&0xFF, ecx>>24, ecx&0xFF);
-		c->x86_cache_size = (ecx>>24)+(edx>>24);
-	}
-
-	if (n < 0x80000006)	/* Some chips just has a large L1. */
-		return;
-
-	ecx = cpuid_ecx(0x80000006);
-	l2size = ecx >> 16;
-
-	/* do processor-specific cache resizing */
-	if (this_cpu->c_size_cache)
-		l2size = this_cpu->c_size_cache(c, l2size);
-
-	/* Allow user to override all this if necessary. */
-	if (cachesize_override != -1)
-		l2size = cachesize_override;
-
-	if (l2size == 0)
-		return;		/* Again, no L2 cache is possible */
-
-	c->x86_cache_size = l2size;
-
-	printk(KERN_INFO "CPU: L2 Cache: %dK (%d bytes/line)\n",
-	       l2size, ecx & 0xFF);
+	setup_clear_cpu_cap(X86_FEATURE_SEP);
+	return 1;
 }
+__setup("nosep", x86_sep_setup);
+
+/* Standard macro to see if a specific flag is changeable */
+static inline int flag_is_changeable_p(u32 flag)
+{
+	u32 f1, f2;
+
+	/*
+	 * Cyrix and IDT cpus allow disabling of CPUID
+	 * so the code below may return different results
+	 * when it is executed before and after enabling
+	 * the CPUID. Add "volatile" to not allow gcc to
+	 * optimize the subsequent calls to this function.
+	 */
+	asm volatile ("pushfl\n\t"
+		      "pushfl\n\t"
+		      "popl %0\n\t"
+		      "movl %0,%1\n\t"
+		      "xorl %2,%0\n\t"
+		      "pushl %0\n\t"
+		      "popfl\n\t"
+		      "pushfl\n\t"
+		      "popl %0\n\t"
+		      "popfl\n\t"
+		      : "=&r" (f1), "=&r" (f2)
+		      : "ir" (flag));
+
+	return ((f1^f2) & flag) != 0;
+}
+
+/* Probe for the CPUID instruction */
+static int __cpuinit have_cpuid_p(void)
+{
+	return flag_is_changeable_p(X86_EFLAGS_ID);
+}
+
+static void __cpuinit squash_the_stupid_serial_number(struct cpuinfo_x86 *c)
+{
+	if (cpu_has(c, X86_FEATURE_PN) && disable_x86_serial_nr) {
+		/* Disable processor serial number */
+		unsigned long lo, hi;
+		rdmsr(MSR_IA32_BBL_CR_CTL, lo, hi);
+		lo |= 0x200000;
+		wrmsr(MSR_IA32_BBL_CR_CTL, lo, hi);
+		printk(KERN_NOTICE "CPU serial number disabled.\n");
+		clear_cpu_cap(c, X86_FEATURE_PN);
+
+		/* Disabling the serial number may affect the cpuid level */
+		c->cpuid_level = cpuid_eax(0);
+	}
+}
+
+static int __init x86_serial_nr_setup(char *s)
+{
+	disable_x86_serial_nr = 0;
+	return 1;
+}
+__setup("serialnumber", x86_serial_nr_setup);
+#else
+static inline int flag_is_changeable_p(u32 flag)
+{
+	return 1;
+}
+/* Probe for the CPUID instruction */
+static inline int have_cpuid_p(void)
+{
+	return 1;
+}
+static inline void squash_the_stupid_serial_number(struct cpuinfo_x86 *c)
+{
+}
+#endif
 
 /*
  * Naming convention should be: <Name> [(<Codename>)]
@@ -185,81 +218,210 @@
 	return NULL;		/* Not found */
 }
 
+__u32 cleared_cpu_caps[NCAPINTS] __cpuinitdata;
 
-static void __cpuinit get_cpu_vendor(struct cpuinfo_x86 *c, int early)
+/* Current gdt points %fs at the "master" per-cpu area: after this,
+ * it's on the real one. */
+void switch_to_new_gdt(void)
+{
+	struct desc_ptr gdt_descr;
+
+	gdt_descr.address = (long)get_cpu_gdt_table(smp_processor_id());
+	gdt_descr.size = GDT_SIZE - 1;
+	load_gdt(&gdt_descr);
+#ifdef CONFIG_X86_32
+	asm("mov %0, %%fs" : : "r" (__KERNEL_PERCPU) : "memory");
+#endif
+}
+
+static struct cpu_dev *cpu_devs[X86_VENDOR_NUM] = {};
+
+static void __cpuinit default_init(struct cpuinfo_x86 *c)
+{
+#ifdef CONFIG_X86_64
+	display_cacheinfo(c);
+#else
+	/* Not much we can do here... */
+	/* Check if at least it has cpuid */
+	if (c->cpuid_level == -1) {
+		/* No cpuid. It must be an ancient CPU */
+		if (c->x86 == 4)
+			strcpy(c->x86_model_id, "486");
+		else if (c->x86 == 3)
+			strcpy(c->x86_model_id, "386");
+	}
+#endif
+}
+
+static struct cpu_dev __cpuinitdata default_cpu = {
+	.c_init	= default_init,
+	.c_vendor = "Unknown",
+	.c_x86_vendor = X86_VENDOR_UNKNOWN,
+};
+
+static void __cpuinit get_model_name(struct cpuinfo_x86 *c)
+{
+	unsigned int *v;
+	char *p, *q;
+
+	if (c->extended_cpuid_level < 0x80000004)
+		return;
+
+	v = (unsigned int *) c->x86_model_id;
+	cpuid(0x80000002, &v[0], &v[1], &v[2], &v[3]);
+	cpuid(0x80000003, &v[4], &v[5], &v[6], &v[7]);
+	cpuid(0x80000004, &v[8], &v[9], &v[10], &v[11]);
+	c->x86_model_id[48] = 0;
+
+	/* Intel chips right-justify this string for some dumb reason;
+	   undo that brain damage */
+	p = q = &c->x86_model_id[0];
+	while (*p == ' ')
+	     p++;
+	if (p != q) {
+	     while (*p)
+		  *q++ = *p++;
+	     while (q <= &c->x86_model_id[48])
+		  *q++ = '\0';	/* Zero-pad the rest */
+	}
+}
+
+void __cpuinit display_cacheinfo(struct cpuinfo_x86 *c)
+{
+	unsigned int n, dummy, ebx, ecx, edx, l2size;
+
+	n = c->extended_cpuid_level;
+
+	if (n >= 0x80000005) {
+		cpuid(0x80000005, &dummy, &ebx, &ecx, &edx);
+		printk(KERN_INFO "CPU: L1 I Cache: %dK (%d bytes/line), D cache %dK (%d bytes/line)\n",
+				edx>>24, edx&0xFF, ecx>>24, ecx&0xFF);
+		c->x86_cache_size = (ecx>>24) + (edx>>24);
+#ifdef CONFIG_X86_64
+		/* On K8 L1 TLB is inclusive, so don't count it */
+		c->x86_tlbsize = 0;
+#endif
+	}
+
+	if (n < 0x80000006)	/* Some chips just has a large L1. */
+		return;
+
+	cpuid(0x80000006, &dummy, &ebx, &ecx, &edx);
+	l2size = ecx >> 16;
+
+#ifdef CONFIG_X86_64
+	c->x86_tlbsize += ((ebx >> 16) & 0xfff) + (ebx & 0xfff);
+#else
+	/* do processor-specific cache resizing */
+	if (this_cpu->c_size_cache)
+		l2size = this_cpu->c_size_cache(c, l2size);
+
+	/* Allow user to override all this if necessary. */
+	if (cachesize_override != -1)
+		l2size = cachesize_override;
+
+	if (l2size == 0)
+		return;		/* Again, no L2 cache is possible */
+#endif
+
+	c->x86_cache_size = l2size;
+
+	printk(KERN_INFO "CPU: L2 Cache: %dK (%d bytes/line)\n",
+			l2size, ecx & 0xFF);
+}
+
+void __cpuinit detect_ht(struct cpuinfo_x86 *c)
+{
+#ifdef CONFIG_X86_HT
+	u32 eax, ebx, ecx, edx;
+	int index_msb, core_bits;
+
+	if (!cpu_has(c, X86_FEATURE_HT))
+		return;
+
+	if (cpu_has(c, X86_FEATURE_CMP_LEGACY))
+		goto out;
+
+	if (cpu_has(c, X86_FEATURE_XTOPOLOGY))
+		return;
+
+	cpuid(1, &eax, &ebx, &ecx, &edx);
+
+	smp_num_siblings = (ebx & 0xff0000) >> 16;
+
+	if (smp_num_siblings == 1) {
+		printk(KERN_INFO  "CPU: Hyper-Threading is disabled\n");
+	} else if (smp_num_siblings > 1) {
+
+		if (smp_num_siblings > NR_CPUS) {
+			printk(KERN_WARNING "CPU: Unsupported number of siblings %d",
+					smp_num_siblings);
+			smp_num_siblings = 1;
+			return;
+		}
+
+		index_msb = get_count_order(smp_num_siblings);
+#ifdef CONFIG_X86_64
+		c->phys_proc_id = phys_pkg_id(index_msb);
+#else
+		c->phys_proc_id = phys_pkg_id(c->initial_apicid, index_msb);
+#endif
+
+		smp_num_siblings = smp_num_siblings / c->x86_max_cores;
+
+		index_msb = get_count_order(smp_num_siblings);
+
+		core_bits = get_count_order(c->x86_max_cores);
+
+#ifdef CONFIG_X86_64
+		c->cpu_core_id = phys_pkg_id(index_msb) &
+					       ((1 << core_bits) - 1);
+#else
+		c->cpu_core_id = phys_pkg_id(c->initial_apicid, index_msb) &
+					       ((1 << core_bits) - 1);
+#endif
+	}
+
+out:
+	if ((c->x86_max_cores * smp_num_siblings) > 1) {
+		printk(KERN_INFO  "CPU: Physical Processor ID: %d\n",
+		       c->phys_proc_id);
+		printk(KERN_INFO  "CPU: Processor Core ID: %d\n",
+		       c->cpu_core_id);
+	}
+#endif
+}
+
+static void __cpuinit get_cpu_vendor(struct cpuinfo_x86 *c)
 {
 	char *v = c->x86_vendor_id;
 	int i;
 	static int printed;
 
 	for (i = 0; i < X86_VENDOR_NUM; i++) {
-		if (cpu_devs[i]) {
-			if (!strcmp(v, cpu_devs[i]->c_ident[0]) ||
-			    (cpu_devs[i]->c_ident[1] &&
-			     !strcmp(v, cpu_devs[i]->c_ident[1]))) {
-				c->x86_vendor = i;
-				if (!early)
-					this_cpu = cpu_devs[i];
-				return;
-			}
+		if (!cpu_devs[i])
+			break;
+
+		if (!strcmp(v, cpu_devs[i]->c_ident[0]) ||
+		    (cpu_devs[i]->c_ident[1] &&
+		     !strcmp(v, cpu_devs[i]->c_ident[1]))) {
+			this_cpu = cpu_devs[i];
+			c->x86_vendor = this_cpu->c_x86_vendor;
+			return;
 		}
 	}
+
 	if (!printed) {
 		printed++;
-		printk(KERN_ERR "CPU: Vendor unknown, using generic init.\n");
+		printk(KERN_ERR "CPU: vendor_id '%s' unknown, using generic init.\n", v);
 		printk(KERN_ERR "CPU: Your system may be unstable.\n");
 	}
+
 	c->x86_vendor = X86_VENDOR_UNKNOWN;
 	this_cpu = &default_cpu;
 }
 
-
-static int __init x86_fxsr_setup(char *s)
-{
-	setup_clear_cpu_cap(X86_FEATURE_FXSR);
-	setup_clear_cpu_cap(X86_FEATURE_XMM);
-	return 1;
-}
-__setup("nofxsr", x86_fxsr_setup);
-
-
-static int __init x86_sep_setup(char *s)
-{
-	setup_clear_cpu_cap(X86_FEATURE_SEP);
-	return 1;
-}
-__setup("nosep", x86_sep_setup);
-
-
-/* Standard macro to see if a specific flag is changeable */
-static inline int flag_is_changeable_p(u32 flag)
-{
-	u32 f1, f2;
-
-	asm("pushfl\n\t"
-	    "pushfl\n\t"
-	    "popl %0\n\t"
-	    "movl %0,%1\n\t"
-	    "xorl %2,%0\n\t"
-	    "pushl %0\n\t"
-	    "popfl\n\t"
-	    "pushfl\n\t"
-	    "popl %0\n\t"
-	    "popfl\n\t"
-	    : "=&r" (f1), "=&r" (f2)
-	    : "ir" (flag));
-
-	return ((f1^f2) & flag) != 0;
-}
-
-
-/* Probe for the CPUID instruction */
-static int __cpuinit have_cpuid_p(void)
-{
-	return flag_is_changeable_p(X86_EFLAGS_ID);
-}
-
-void __init cpu_detect(struct cpuinfo_x86 *c)
+void __cpuinit cpu_detect(struct cpuinfo_x86 *c)
 {
 	/* Get vendor name */
 	cpuid(0x00000000, (unsigned int *)&c->cpuid_level,
@@ -268,48 +430,85 @@
 	      (unsigned int *)&c->x86_vendor_id[4]);
 
 	c->x86 = 4;
+	/* Intel-defined flags: level 0x00000001 */
 	if (c->cpuid_level >= 0x00000001) {
 		u32 junk, tfms, cap0, misc;
 		cpuid(0x00000001, &tfms, &misc, &junk, &cap0);
-		c->x86 = (tfms >> 8) & 15;
-		c->x86_model = (tfms >> 4) & 15;
+		c->x86 = (tfms >> 8) & 0xf;
+		c->x86_model = (tfms >> 4) & 0xf;
+		c->x86_mask = tfms & 0xf;
 		if (c->x86 == 0xf)
 			c->x86 += (tfms >> 20) & 0xff;
 		if (c->x86 >= 0x6)
-			c->x86_model += ((tfms >> 16) & 0xF) << 4;
-		c->x86_mask = tfms & 15;
+			c->x86_model += ((tfms >> 16) & 0xf) << 4;
 		if (cap0 & (1<<19)) {
-			c->x86_cache_alignment = ((misc >> 8) & 0xff) * 8;
 			c->x86_clflush_size = ((misc >> 8) & 0xff) * 8;
+			c->x86_cache_alignment = c->x86_clflush_size;
 		}
 	}
 }
-static void __cpuinit early_get_cap(struct cpuinfo_x86 *c)
+
+static void __cpuinit get_cpu_cap(struct cpuinfo_x86 *c)
 {
 	u32 tfms, xlvl;
-	unsigned int ebx;
+	u32 ebx;
 
-	memset(&c->x86_capability, 0, sizeof c->x86_capability);
-	if (have_cpuid_p()) {
-		/* Intel-defined flags: level 0x00000001 */
-		if (c->cpuid_level >= 0x00000001) {
-			u32 capability, excap;
-			cpuid(0x00000001, &tfms, &ebx, &excap, &capability);
-			c->x86_capability[0] = capability;
-			c->x86_capability[4] = excap;
-		}
-
-		/* AMD-defined flags: level 0x80000001 */
-		xlvl = cpuid_eax(0x80000000);
-		if ((xlvl & 0xffff0000) == 0x80000000) {
-			if (xlvl >= 0x80000001) {
-				c->x86_capability[1] = cpuid_edx(0x80000001);
-				c->x86_capability[6] = cpuid_ecx(0x80000001);
-			}
-		}
-
+	/* Intel-defined flags: level 0x00000001 */
+	if (c->cpuid_level >= 0x00000001) {
+		u32 capability, excap;
+		cpuid(0x00000001, &tfms, &ebx, &excap, &capability);
+		c->x86_capability[0] = capability;
+		c->x86_capability[4] = excap;
 	}
 
+	/* AMD-defined flags: level 0x80000001 */
+	xlvl = cpuid_eax(0x80000000);
+	c->extended_cpuid_level = xlvl;
+	if ((xlvl & 0xffff0000) == 0x80000000) {
+		if (xlvl >= 0x80000001) {
+			c->x86_capability[1] = cpuid_edx(0x80000001);
+			c->x86_capability[6] = cpuid_ecx(0x80000001);
+		}
+	}
+
+#ifdef CONFIG_X86_64
+	if (c->extended_cpuid_level >= 0x80000008) {
+		u32 eax = cpuid_eax(0x80000008);
+
+		c->x86_virt_bits = (eax >> 8) & 0xff;
+		c->x86_phys_bits = eax & 0xff;
+	}
+#endif
+
+	if (c->extended_cpuid_level >= 0x80000007)
+		c->x86_power = cpuid_edx(0x80000007);
+
+}
+
+static void __cpuinit identify_cpu_without_cpuid(struct cpuinfo_x86 *c)
+{
+#ifdef CONFIG_X86_32
+	int i;
+
+	/*
+	 * First of all, decide if this is a 486 or higher
+	 * It's a 486 if we can modify the AC flag
+	 */
+	if (flag_is_changeable_p(X86_EFLAGS_AC))
+		c->x86 = 4;
+	else
+		c->x86 = 3;
+
+	for (i = 0; i < X86_VENDOR_NUM; i++)
+		if (cpu_devs[i] && cpu_devs[i]->c_identify) {
+			c->x86_vendor_id[0] = 0;
+			cpu_devs[i]->c_identify(c);
+			if (c->x86_vendor_id[0]) {
+				get_cpu_vendor(c);
+				break;
+			}
+		}
+#endif
 }
 
 /*
@@ -321,139 +520,114 @@
  * WARNING: this function is only called on the BP.  Don't add code here
  * that is supposed to run on all CPUs.
  */
-static void __init early_cpu_detect(void)
+static void __init early_identify_cpu(struct cpuinfo_x86 *c)
 {
-	struct cpuinfo_x86 *c = &boot_cpu_data;
-
-	c->x86_cache_alignment = 32;
+#ifdef CONFIG_X86_64
+	c->x86_clflush_size = 64;
+#else
 	c->x86_clflush_size = 32;
+#endif
+	c->x86_cache_alignment = c->x86_clflush_size;
 
+	memset(&c->x86_capability, 0, sizeof c->x86_capability);
+	c->extended_cpuid_level = 0;
+
+	if (!have_cpuid_p())
+		identify_cpu_without_cpuid(c);
+
+	/* cyrix could have cpuid enabled via c_identify()*/
 	if (!have_cpuid_p())
 		return;
 
 	cpu_detect(c);
 
-	get_cpu_vendor(c, 1);
+	get_cpu_vendor(c);
 
-	early_get_cap(c);
+	get_cpu_cap(c);
 
-	if (c->x86_vendor != X86_VENDOR_UNKNOWN &&
-	    cpu_devs[c->x86_vendor]->c_early_init)
-		cpu_devs[c->x86_vendor]->c_early_init(c);
+	if (this_cpu->c_early_init)
+		this_cpu->c_early_init(c);
+
+	validate_pat_support(c);
+}
+
+void __init early_cpu_init(void)
+{
+	struct cpu_dev **cdev;
+	int count = 0;
+
+	printk("KERNEL supported cpus:\n");
+	for (cdev = __x86_cpu_dev_start; cdev < __x86_cpu_dev_end; cdev++) {
+		struct cpu_dev *cpudev = *cdev;
+		unsigned int j;
+
+		if (count >= X86_VENDOR_NUM)
+			break;
+		cpu_devs[count] = cpudev;
+		count++;
+
+		for (j = 0; j < 2; j++) {
+			if (!cpudev->c_ident[j])
+				continue;
+			printk("  %s %s\n", cpudev->c_vendor,
+				cpudev->c_ident[j]);
+		}
+	}
+
+	early_identify_cpu(&boot_cpu_data);
 }
 
 /*
  * The NOPL instruction is supposed to exist on all CPUs with
- * family >= 6, unfortunately, that's not true in practice because
+ * family >= 6; unfortunately, that's not true in practice because
  * of early VIA chips and (more importantly) broken virtualizers that
- * are not easy to detect.  Hence, probe for it based on first
- * principles.
+ * are not easy to detect.  In the latter case it doesn't even *fail*
+ * reliably, so probing for it doesn't even work.  Disable it completely
+ * unless we can find a reliable way to detect all the broken cases.
  */
 static void __cpuinit detect_nopl(struct cpuinfo_x86 *c)
 {
-	const u32 nopl_signature = 0x888c53b1; /* Random number */
-	u32 has_nopl = nopl_signature;
-
 	clear_cpu_cap(c, X86_FEATURE_NOPL);
-	if (c->x86 >= 6) {
-		asm volatile("\n"
-			     "1:      .byte 0x0f,0x1f,0xc0\n" /* nopl %eax */
-			     "2:\n"
-			     "        .section .fixup,\"ax\"\n"
-			     "3:      xor %0,%0\n"
-			     "        jmp 2b\n"
-			     "        .previous\n"
-			     _ASM_EXTABLE(1b,3b)
-			     : "+a" (has_nopl));
-
-		if (has_nopl == nopl_signature)
-			set_cpu_cap(c, X86_FEATURE_NOPL);
-	}
 }
 
 static void __cpuinit generic_identify(struct cpuinfo_x86 *c)
 {
-	u32 tfms, xlvl;
-	unsigned int ebx;
+	c->extended_cpuid_level = 0;
 
-	if (have_cpuid_p()) {
-		/* Get vendor name */
-		cpuid(0x00000000, (unsigned int *)&c->cpuid_level,
-		      (unsigned int *)&c->x86_vendor_id[0],
-		      (unsigned int *)&c->x86_vendor_id[8],
-		      (unsigned int *)&c->x86_vendor_id[4]);
+	if (!have_cpuid_p())
+		identify_cpu_without_cpuid(c);
 
-		get_cpu_vendor(c, 0);
-		/* Initialize the standard set of capabilities */
-		/* Note that the vendor-specific code below might override */
-		/* Intel-defined flags: level 0x00000001 */
-		if (c->cpuid_level >= 0x00000001) {
-			u32 capability, excap;
-			cpuid(0x00000001, &tfms, &ebx, &excap, &capability);
-			c->x86_capability[0] = capability;
-			c->x86_capability[4] = excap;
-			c->x86 = (tfms >> 8) & 15;
-			c->x86_model = (tfms >> 4) & 15;
-			if (c->x86 == 0xf)
-				c->x86 += (tfms >> 20) & 0xff;
-			if (c->x86 >= 0x6)
-				c->x86_model += ((tfms >> 16) & 0xF) << 4;
-			c->x86_mask = tfms & 15;
-			c->initial_apicid = (ebx >> 24) & 0xFF;
-#ifdef CONFIG_X86_HT
-			c->apicid = phys_pkg_id(c->initial_apicid, 0);
-			c->phys_proc_id = c->initial_apicid;
-#else
-			c->apicid = c->initial_apicid;
+	/* cyrix could have cpuid enabled via c_identify()*/
+	if (!have_cpuid_p())
+		return;
+
+	cpu_detect(c);
+
+	get_cpu_vendor(c);
+
+	get_cpu_cap(c);
+
+	if (c->cpuid_level >= 0x00000001) {
+		c->initial_apicid = (cpuid_ebx(1) >> 24) & 0xFF;
+#ifdef CONFIG_X86_32
+# ifdef CONFIG_X86_HT
+		c->apicid = phys_pkg_id(c->initial_apicid, 0);
+# else
+		c->apicid = c->initial_apicid;
+# endif
 #endif
-			if (test_cpu_cap(c, X86_FEATURE_CLFLSH))
-				c->x86_clflush_size = ((ebx >> 8) & 0xff) * 8;
-		} else {
-			/* Have CPUID level 0 only - unheard of */
-			c->x86 = 4;
-		}
 
-		/* AMD-defined flags: level 0x80000001 */
-		xlvl = cpuid_eax(0x80000000);
-		if ((xlvl & 0xffff0000) == 0x80000000) {
-			if (xlvl >= 0x80000001) {
-				c->x86_capability[1] = cpuid_edx(0x80000001);
-				c->x86_capability[6] = cpuid_ecx(0x80000001);
-			}
-			if (xlvl >= 0x80000004)
-				get_model_name(c); /* Default name */
-		}
-
-		init_scattered_cpuid_features(c);
-		detect_nopl(c);
+#ifdef CONFIG_X86_HT
+		c->phys_proc_id = c->initial_apicid;
+#endif
 	}
+
+	get_model_name(c); /* Default name */
+
+	init_scattered_cpuid_features(c);
+	detect_nopl(c);
 }
 
-static void __cpuinit squash_the_stupid_serial_number(struct cpuinfo_x86 *c)
-{
-	if (cpu_has(c, X86_FEATURE_PN) && disable_x86_serial_nr) {
-		/* Disable processor serial number */
-		unsigned long lo, hi;
-		rdmsr(MSR_IA32_BBL_CR_CTL, lo, hi);
-		lo |= 0x200000;
-		wrmsr(MSR_IA32_BBL_CR_CTL, lo, hi);
-		printk(KERN_NOTICE "CPU serial number disabled.\n");
-		clear_cpu_cap(c, X86_FEATURE_PN);
-
-		/* Disabling the serial number may affect the cpuid level */
-		c->cpuid_level = cpuid_eax(0);
-	}
-}
-
-static int __init x86_serial_nr_setup(char *s)
-{
-	disable_x86_serial_nr = 0;
-	return 1;
-}
-__setup("serialnumber", x86_serial_nr_setup);
-
-
-
 /*
  * This does the hard work of actually picking apart the CPU stuff...
  */
@@ -464,30 +638,29 @@
 	c->loops_per_jiffy = loops_per_jiffy;
 	c->x86_cache_size = -1;
 	c->x86_vendor = X86_VENDOR_UNKNOWN;
-	c->cpuid_level = -1;	/* CPUID not detected */
 	c->x86_model = c->x86_mask = 0;	/* So far unknown... */
 	c->x86_vendor_id[0] = '\0'; /* Unset */
 	c->x86_model_id[0] = '\0';  /* Unset */
 	c->x86_max_cores = 1;
+	c->x86_coreid_bits = 0;
+#ifdef CONFIG_X86_64
+	c->x86_clflush_size = 64;
+#else
+	c->cpuid_level = -1;	/* CPUID not detected */
 	c->x86_clflush_size = 32;
+#endif
+	c->x86_cache_alignment = c->x86_clflush_size;
 	memset(&c->x86_capability, 0, sizeof c->x86_capability);
 
-	if (!have_cpuid_p()) {
-		/*
-		 * First of all, decide if this is a 486 or higher
-		 * It's a 486 if we can modify the AC flag
-		 */
-		if (flag_is_changeable_p(X86_EFLAGS_AC))
-			c->x86 = 4;
-		else
-			c->x86 = 3;
-	}
-
 	generic_identify(c);
 
 	if (this_cpu->c_identify)
 		this_cpu->c_identify(c);
 
+#ifdef CONFIG_X86_64
+	c->apicid = phys_pkg_id(0);
+#endif
+
 	/*
 	 * Vendor-specific initialization.  In this section we
 	 * canonicalize the feature flags, meaning if there are
@@ -521,6 +694,10 @@
 				c->x86, c->x86_model);
 	}
 
+#ifdef CONFIG_X86_64
+	detect_ht(c);
+#endif
+
 	/*
 	 * On SMP, boot_cpu_data holds the common feature set between
 	 * all CPUs; so make sure that we indicate which features are
@@ -529,7 +706,7 @@
 	 */
 	if (c != &boot_cpu_data) {
 		/* AND the already accumulated flags with these */
-		for (i = 0 ; i < NCAPINTS ; i++)
+		for (i = 0; i < NCAPINTS; i++)
 			boot_cpu_data.x86_capability[i] &= c->x86_capability[i];
 	}
 
@@ -537,72 +714,91 @@
 	for (i = 0; i < NCAPINTS; i++)
 		c->x86_capability[i] &= ~cleared_cpu_caps[i];
 
+#ifdef CONFIG_X86_MCE
 	/* Init Machine Check Exception if available. */
 	mcheck_init(c);
+#endif
 
 	select_idle_routine(c);
+
+#if defined(CONFIG_NUMA) && defined(CONFIG_X86_64)
+	numa_add_cpu(smp_processor_id());
+#endif
 }
 
+#ifdef CONFIG_X86_64
+static void vgetcpu_set_mode(void)
+{
+	if (cpu_has(&boot_cpu_data, X86_FEATURE_RDTSCP))
+		vgetcpu_mode = VGETCPU_RDTSCP;
+	else
+		vgetcpu_mode = VGETCPU_LSL;
+}
+#endif
+
 void __init identify_boot_cpu(void)
 {
 	identify_cpu(&boot_cpu_data);
+#ifdef CONFIG_X86_32
 	sysenter_setup();
 	enable_sep_cpu();
+#else
+	vgetcpu_set_mode();
+#endif
 }
 
 void __cpuinit identify_secondary_cpu(struct cpuinfo_x86 *c)
 {
 	BUG_ON(c == &boot_cpu_data);
 	identify_cpu(c);
+#ifdef CONFIG_X86_32
 	enable_sep_cpu();
+#endif
 	mtrr_ap_init();
 }
 
-#ifdef CONFIG_X86_HT
-void __cpuinit detect_ht(struct cpuinfo_x86 *c)
+struct msr_range {
+	unsigned min;
+	unsigned max;
+};
+
+static struct msr_range msr_range_array[] __cpuinitdata = {
+	{ 0x00000000, 0x00000418},
+	{ 0xc0000000, 0xc000040b},
+	{ 0xc0010000, 0xc0010142},
+	{ 0xc0011000, 0xc001103b},
+};
+
+static void __cpuinit print_cpu_msr(void)
 {
-	u32 	eax, ebx, ecx, edx;
-	int 	index_msb, core_bits;
+	unsigned index;
+	u64 val;
+	int i;
+	unsigned index_min, index_max;
 
-	cpuid(1, &eax, &ebx, &ecx, &edx);
-
-	if (!cpu_has(c, X86_FEATURE_HT) || cpu_has(c, X86_FEATURE_CMP_LEGACY))
-		return;
-
-	smp_num_siblings = (ebx & 0xff0000) >> 16;
-
-	if (smp_num_siblings == 1) {
-		printk(KERN_INFO  "CPU: Hyper-Threading is disabled\n");
-	} else if (smp_num_siblings > 1) {
-
-		if (smp_num_siblings > NR_CPUS) {
-			printk(KERN_WARNING "CPU: Unsupported number of the "
-					"siblings %d", smp_num_siblings);
-			smp_num_siblings = 1;
-			return;
+	for (i = 0; i < ARRAY_SIZE(msr_range_array); i++) {
+		index_min = msr_range_array[i].min;
+		index_max = msr_range_array[i].max;
+		for (index = index_min; index < index_max; index++) {
+			if (rdmsrl_amd_safe(index, &val))
+				continue;
+			printk(KERN_INFO " MSR%08x: %016llx\n", index, val);
 		}
-
-		index_msb = get_count_order(smp_num_siblings);
-		c->phys_proc_id = phys_pkg_id(c->initial_apicid, index_msb);
-
-		printk(KERN_INFO  "CPU: Physical Processor ID: %d\n",
-		       c->phys_proc_id);
-
-		smp_num_siblings = smp_num_siblings / c->x86_max_cores;
-
-		index_msb = get_count_order(smp_num_siblings) ;
-
-		core_bits = get_count_order(c->x86_max_cores);
-
-		c->cpu_core_id = phys_pkg_id(c->initial_apicid, index_msb) &
-					       ((1 << core_bits) - 1);
-
-		if (c->x86_max_cores > 1)
-			printk(KERN_INFO  "CPU: Processor Core ID: %d\n",
-			       c->cpu_core_id);
 	}
 }
-#endif
+
+static int show_msr __cpuinitdata;
+static __init int setup_show_msr(char *arg)
+{
+	int num;
+
+	get_option(&arg, &num);
+
+	if (num > 0)
+		show_msr = num;
+	return 1;
+}
+__setup("show_msr=", setup_show_msr);
 
 static __init int setup_noclflush(char *arg)
 {
@@ -620,18 +816,26 @@
 	else if (c->cpuid_level >= 0)
 		vendor = c->x86_vendor_id;
 
-	if (vendor && strncmp(c->x86_model_id, vendor, strlen(vendor)))
-		printk("%s ", vendor);
+	if (vendor && !strstr(c->x86_model_id, vendor))
+		printk(KERN_CONT "%s ", vendor);
 
-	if (!c->x86_model_id[0])
-		printk("%d86", c->x86);
+	if (c->x86_model_id[0])
+		printk(KERN_CONT "%s", c->x86_model_id);
 	else
-		printk("%s", c->x86_model_id);
+		printk(KERN_CONT "%d86", c->x86);
 
 	if (c->x86_mask || c->cpuid_level >= 0)
-		printk(" stepping %02x\n", c->x86_mask);
+		printk(KERN_CONT " stepping %02x\n", c->x86_mask);
 	else
-		printk("\n");
+		printk(KERN_CONT "\n");
+
+#ifdef CONFIG_SMP
+	if (c->cpu_index < show_msr)
+		print_cpu_msr();
+#else
+	if (show_msr)
+		print_cpu_msr();
+#endif
 }
 
 static __init int setup_disablecpuid(char *arg)
@@ -647,19 +851,89 @@
 
 cpumask_t cpu_initialized __cpuinitdata = CPU_MASK_NONE;
 
-void __init early_cpu_init(void)
+#ifdef CONFIG_X86_64
+struct x8664_pda **_cpu_pda __read_mostly;
+EXPORT_SYMBOL(_cpu_pda);
+
+struct desc_ptr idt_descr = { 256 * 16 - 1, (unsigned long) idt_table };
+
+char boot_cpu_stack[IRQSTACKSIZE] __page_aligned_bss;
+
+void __cpuinit pda_init(int cpu)
 {
-	struct cpu_vendor_dev *cvdev;
+	struct x8664_pda *pda = cpu_pda(cpu);
 
-	for (cvdev = __x86cpuvendor_start ;
-	     cvdev < __x86cpuvendor_end   ;
-	     cvdev++)
-		cpu_devs[cvdev->vendor] = cvdev->cpu_dev;
+	/* Setup up data that may be needed in __get_free_pages early */
+	loadsegment(fs, 0);
+	loadsegment(gs, 0);
+	/* Memory clobbers used to order PDA accessed */
+	mb();
+	wrmsrl(MSR_GS_BASE, pda);
+	mb();
 
-	early_cpu_detect();
-	validate_pat_support(&boot_cpu_data);
+	pda->cpunumber = cpu;
+	pda->irqcount = -1;
+	pda->kernelstack = (unsigned long)stack_thread_info() -
+				 PDA_STACKOFFSET + THREAD_SIZE;
+	pda->active_mm = &init_mm;
+	pda->mmu_state = 0;
+
+	if (cpu == 0) {
+		/* others are initialized in smpboot.c */
+		pda->pcurrent = &init_task;
+		pda->irqstackptr = boot_cpu_stack;
+		pda->irqstackptr += IRQSTACKSIZE - 64;
+	} else {
+		if (!pda->irqstackptr) {
+			pda->irqstackptr = (char *)
+				__get_free_pages(GFP_ATOMIC, IRQSTACK_ORDER);
+			if (!pda->irqstackptr)
+				panic("cannot allocate irqstack for cpu %d",
+				      cpu);
+			pda->irqstackptr += IRQSTACKSIZE - 64;
+		}
+
+		if (pda->nodenumber == 0 && cpu_to_node(cpu) != NUMA_NO_NODE)
+			pda->nodenumber = cpu_to_node(cpu);
+	}
 }
 
+char boot_exception_stacks[(N_EXCEPTION_STACKS - 1) * EXCEPTION_STKSZ +
+			   DEBUG_STKSZ] __page_aligned_bss;
+
+extern asmlinkage void ignore_sysret(void);
+
+/* May not be marked __init: used by software suspend */
+void syscall_init(void)
+{
+	/*
+	 * LSTAR and STAR live in a bit strange symbiosis.
+	 * They both write to the same internal register. STAR allows to
+	 * set CS/DS but only a 32bit target. LSTAR sets the 64bit rip.
+	 */
+	wrmsrl(MSR_STAR,  ((u64)__USER32_CS)<<48  | ((u64)__KERNEL_CS)<<32);
+	wrmsrl(MSR_LSTAR, system_call);
+	wrmsrl(MSR_CSTAR, ignore_sysret);
+
+#ifdef CONFIG_IA32_EMULATION
+	syscall32_cpu_init();
+#endif
+
+	/* Flags to clear on syscall */
+	wrmsrl(MSR_SYSCALL_MASK,
+	       X86_EFLAGS_TF|X86_EFLAGS_DF|X86_EFLAGS_IF|X86_EFLAGS_IOPL);
+}
+
+unsigned long kernel_eflags;
+
+/*
+ * Copies of the original ist values from the tss are only accessed during
+ * debugging, no special alignment required.
+ */
+DEFINE_PER_CPU(struct orig_ist, orig_ist);
+
+#else
+
 /* Make sure %fs is initialized properly in idle threads */
 struct pt_regs * __cpuinit idle_regs(struct pt_regs *regs)
 {
@@ -667,25 +941,136 @@
 	regs->fs = __KERNEL_PERCPU;
 	return regs;
 }
-
-/* Current gdt points %fs at the "master" per-cpu area: after this,
- * it's on the real one. */
-void switch_to_new_gdt(void)
-{
-	struct desc_ptr gdt_descr;
-
-	gdt_descr.address = (long)get_cpu_gdt_table(smp_processor_id());
-	gdt_descr.size = GDT_SIZE - 1;
-	load_gdt(&gdt_descr);
-	asm("mov %0, %%fs" : : "r" (__KERNEL_PERCPU) : "memory");
-}
+#endif
 
 /*
  * cpu_init() initializes state that is per-CPU. Some data is already
  * initialized (naturally) in the bootstrap process, such as the GDT
  * and IDT. We reload them nevertheless, this function acts as a
  * 'CPU state barrier', nothing should get across.
+ * A lot of state is already set up in PDA init for 64 bit
  */
+#ifdef CONFIG_X86_64
+void __cpuinit cpu_init(void)
+{
+	int cpu = stack_smp_processor_id();
+	struct tss_struct *t = &per_cpu(init_tss, cpu);
+	struct orig_ist *orig_ist = &per_cpu(orig_ist, cpu);
+	unsigned long v;
+	char *estacks = NULL;
+	struct task_struct *me;
+	int i;
+
+	/* CPU 0 is initialised in head64.c */
+	if (cpu != 0)
+		pda_init(cpu);
+	else
+		estacks = boot_exception_stacks;
+
+	me = current;
+
+	if (cpu_test_and_set(cpu, cpu_initialized))
+		panic("CPU#%d already initialized!\n", cpu);
+
+	printk(KERN_INFO "Initializing CPU#%d\n", cpu);
+
+	clear_in_cr4(X86_CR4_VME|X86_CR4_PVI|X86_CR4_TSD|X86_CR4_DE);
+
+	/*
+	 * Initialize the per-CPU GDT with the boot GDT,
+	 * and set up the GDT descriptor:
+	 */
+
+	switch_to_new_gdt();
+	load_idt((const struct desc_ptr *)&idt_descr);
+
+	memset(me->thread.tls_array, 0, GDT_ENTRY_TLS_ENTRIES * 8);
+	syscall_init();
+
+	wrmsrl(MSR_FS_BASE, 0);
+	wrmsrl(MSR_KERNEL_GS_BASE, 0);
+	barrier();
+
+	check_efer();
+	if (cpu != 0 && x2apic)
+		enable_x2apic();
+
+	/*
+	 * set up and load the per-CPU TSS
+	 */
+	if (!orig_ist->ist[0]) {
+		static const unsigned int order[N_EXCEPTION_STACKS] = {
+		  [0 ... N_EXCEPTION_STACKS - 1] = EXCEPTION_STACK_ORDER,
+		  [DEBUG_STACK - 1] = DEBUG_STACK_ORDER
+		};
+		for (v = 0; v < N_EXCEPTION_STACKS; v++) {
+			if (cpu) {
+				estacks = (char *)__get_free_pages(GFP_ATOMIC, order[v]);
+				if (!estacks)
+					panic("Cannot allocate exception "
+					      "stack %ld %d\n", v, cpu);
+			}
+			estacks += PAGE_SIZE << order[v];
+			orig_ist->ist[v] = t->x86_tss.ist[v] =
+					(unsigned long)estacks;
+		}
+	}
+
+	t->x86_tss.io_bitmap_base = offsetof(struct tss_struct, io_bitmap);
+	/*
+	 * <= is required because the CPU will access up to
+	 * 8 bits beyond the end of the IO permission bitmap.
+	 */
+	for (i = 0; i <= IO_BITMAP_LONGS; i++)
+		t->io_bitmap[i] = ~0UL;
+
+	atomic_inc(&init_mm.mm_count);
+	me->active_mm = &init_mm;
+	if (me->mm)
+		BUG();
+	enter_lazy_tlb(&init_mm, me);
+
+	load_sp0(t, &current->thread);
+	set_tss_desc(cpu, t);
+	load_TR_desc();
+	load_LDT(&init_mm.context);
+
+#ifdef CONFIG_KGDB
+	/*
+	 * If the kgdb is connected no debug regs should be altered.  This
+	 * is only applicable when KGDB and a KGDB I/O module are built
+	 * into the kernel and you are using early debugging with
+	 * kgdbwait. KGDB will control the kernel HW breakpoint registers.
+	 */
+	if (kgdb_connected && arch_kgdb_ops.correct_hw_break)
+		arch_kgdb_ops.correct_hw_break();
+	else {
+#endif
+	/*
+	 * Clear all 6 debug registers:
+	 */
+
+	set_debugreg(0UL, 0);
+	set_debugreg(0UL, 1);
+	set_debugreg(0UL, 2);
+	set_debugreg(0UL, 3);
+	set_debugreg(0UL, 6);
+	set_debugreg(0UL, 7);
+#ifdef CONFIG_KGDB
+	/* If the kgdb is connected no debug regs should be altered. */
+	}
+#endif
+
+	fpu_init();
+
+	raw_local_save_flags(kernel_eflags);
+
+	if (is_uv_system())
+		uv_cpu_init();
+}
+
+#else
+
 void __cpuinit cpu_init(void)
 {
 	int cpu = smp_processor_id();
@@ -739,19 +1124,21 @@
 	/*
 	 * Force FPU initialization:
 	 */
-	current_thread_info()->status = 0;
+	if (cpu_has_xsave)
+		current_thread_info()->status = TS_XSAVE;
+	else
+		current_thread_info()->status = 0;
 	clear_used_math();
 	mxcsr_feature_mask_init();
+
+	/*
+	 * Boot processor to setup the FP and extended state context info.
+	 */
+	if (!smp_processor_id())
+		init_thread_xstate();
+
+	xsave_init();
 }
 
-#ifdef CONFIG_HOTPLUG_CPU
-void __cpuinit cpu_uninit(void)
-{
-	int cpu = raw_smp_processor_id();
-	cpu_clear(cpu, cpu_initialized);
 
-	/* lazy TLB state */
-	per_cpu(cpu_tlbstate, cpu).state = 0;
-	per_cpu(cpu_tlbstate, cpu).active_mm = &init_mm;
-}
 #endif
diff --git a/arch/x86/kernel/cpu/common_64.c b/arch/x86/kernel/cpu/common_64.c
deleted file mode 100644
index a11f5d4..0000000
--- a/arch/x86/kernel/cpu/common_64.c
+++ /dev/null
@@ -1,712 +0,0 @@
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/string.h>
-#include <linux/bootmem.h>
-#include <linux/bitops.h>
-#include <linux/module.h>
-#include <linux/kgdb.h>
-#include <linux/topology.h>
-#include <linux/delay.h>
-#include <linux/smp.h>
-#include <linux/percpu.h>
-#include <asm/i387.h>
-#include <asm/msr.h>
-#include <asm/io.h>
-#include <asm/linkage.h>
-#include <asm/mmu_context.h>
-#include <asm/mtrr.h>
-#include <asm/mce.h>
-#include <asm/pat.h>
-#include <asm/asm.h>
-#include <asm/numa.h>
-#ifdef CONFIG_X86_LOCAL_APIC
-#include <asm/mpspec.h>
-#include <asm/apic.h>
-#include <mach_apic.h>
-#endif
-#include <asm/pda.h>
-#include <asm/pgtable.h>
-#include <asm/processor.h>
-#include <asm/desc.h>
-#include <asm/atomic.h>
-#include <asm/proto.h>
-#include <asm/sections.h>
-#include <asm/setup.h>
-#include <asm/genapic.h>
-
-#include "cpu.h"
-
-/* We need valid kernel segments for data and code in long mode too
- * IRET will check the segment types  kkeil 2000/10/28
- * Also sysret mandates a special GDT layout
- */
-/* The TLS descriptors are currently at a different place compared to i386.
-   Hopefully nobody expects them at a fixed place (Wine?) */
-DEFINE_PER_CPU(struct gdt_page, gdt_page) = { .gdt = {
-	[GDT_ENTRY_KERNEL32_CS] = { { { 0x0000ffff, 0x00cf9b00 } } },
-	[GDT_ENTRY_KERNEL_CS] = { { { 0x0000ffff, 0x00af9b00 } } },
-	[GDT_ENTRY_KERNEL_DS] = { { { 0x0000ffff, 0x00cf9300 } } },
-	[GDT_ENTRY_DEFAULT_USER32_CS] = { { { 0x0000ffff, 0x00cffb00 } } },
-	[GDT_ENTRY_DEFAULT_USER_DS] = { { { 0x0000ffff, 0x00cff300 } } },
-	[GDT_ENTRY_DEFAULT_USER_CS] = { { { 0x0000ffff, 0x00affb00 } } },
-} };
-EXPORT_PER_CPU_SYMBOL_GPL(gdt_page);
-
-__u32 cleared_cpu_caps[NCAPINTS] __cpuinitdata;
-
-/* Current gdt points %fs at the "master" per-cpu area: after this,
- * it's on the real one. */
-void switch_to_new_gdt(void)
-{
-	struct desc_ptr gdt_descr;
-
-	gdt_descr.address = (long)get_cpu_gdt_table(smp_processor_id());
-	gdt_descr.size = GDT_SIZE - 1;
-	load_gdt(&gdt_descr);
-}
-
-struct cpu_dev *cpu_devs[X86_VENDOR_NUM] = {};
-
-static void __cpuinit default_init(struct cpuinfo_x86 *c)
-{
-	display_cacheinfo(c);
-}
-
-static struct cpu_dev __cpuinitdata default_cpu = {
-	.c_init	= default_init,
-	.c_vendor = "Unknown",
-};
-static struct cpu_dev *this_cpu __cpuinitdata = &default_cpu;
-
-int __cpuinit get_model_name(struct cpuinfo_x86 *c)
-{
-	unsigned int *v;
-
-	if (c->extended_cpuid_level < 0x80000004)
-		return 0;
-
-	v = (unsigned int *) c->x86_model_id;
-	cpuid(0x80000002, &v[0], &v[1], &v[2], &v[3]);
-	cpuid(0x80000003, &v[4], &v[5], &v[6], &v[7]);
-	cpuid(0x80000004, &v[8], &v[9], &v[10], &v[11]);
-	c->x86_model_id[48] = 0;
-	return 1;
-}
-
-
-void __cpuinit display_cacheinfo(struct cpuinfo_x86 *c)
-{
-	unsigned int n, dummy, ebx, ecx, edx;
-
-	n = c->extended_cpuid_level;
-
-	if (n >= 0x80000005) {
-		cpuid(0x80000005, &dummy, &ebx, &ecx, &edx);
-		printk(KERN_INFO "CPU: L1 I Cache: %dK (%d bytes/line), "
-		       "D cache %dK (%d bytes/line)\n",
-		       edx>>24, edx&0xFF, ecx>>24, ecx&0xFF);
-		c->x86_cache_size = (ecx>>24) + (edx>>24);
-		/* On K8 L1 TLB is inclusive, so don't count it */
-		c->x86_tlbsize = 0;
-	}
-
-	if (n >= 0x80000006) {
-		cpuid(0x80000006, &dummy, &ebx, &ecx, &edx);
-		ecx = cpuid_ecx(0x80000006);
-		c->x86_cache_size = ecx >> 16;
-		c->x86_tlbsize += ((ebx >> 16) & 0xfff) + (ebx & 0xfff);
-
-		printk(KERN_INFO "CPU: L2 Cache: %dK (%d bytes/line)\n",
-		c->x86_cache_size, ecx & 0xFF);
-	}
-}
-
-void __cpuinit detect_ht(struct cpuinfo_x86 *c)
-{
-#ifdef CONFIG_SMP
-	u32 eax, ebx, ecx, edx;
-	int index_msb, core_bits;
-
-	cpuid(1, &eax, &ebx, &ecx, &edx);
-
-
-	if (!cpu_has(c, X86_FEATURE_HT))
-		return;
-	if (cpu_has(c, X86_FEATURE_CMP_LEGACY))
-		goto out;
-
-	smp_num_siblings = (ebx & 0xff0000) >> 16;
-
-	if (smp_num_siblings == 1) {
-		printk(KERN_INFO  "CPU: Hyper-Threading is disabled\n");
-	} else if (smp_num_siblings > 1) {
-
-		if (smp_num_siblings > NR_CPUS) {
-			printk(KERN_WARNING "CPU: Unsupported number of "
-			       "siblings %d", smp_num_siblings);
-			smp_num_siblings = 1;
-			return;
-		}
-
-		index_msb = get_count_order(smp_num_siblings);
-		c->phys_proc_id = phys_pkg_id(index_msb);
-
-		smp_num_siblings = smp_num_siblings / c->x86_max_cores;
-
-		index_msb = get_count_order(smp_num_siblings);
-
-		core_bits = get_count_order(c->x86_max_cores);
-
-		c->cpu_core_id = phys_pkg_id(index_msb) &
-					       ((1 << core_bits) - 1);
-	}
-out:
-	if ((c->x86_max_cores * smp_num_siblings) > 1) {
-		printk(KERN_INFO  "CPU: Physical Processor ID: %d\n",
-		       c->phys_proc_id);
-		printk(KERN_INFO  "CPU: Processor Core ID: %d\n",
-		       c->cpu_core_id);
-	}
-
-#endif
-}
-
-static void __cpuinit get_cpu_vendor(struct cpuinfo_x86 *c)
-{
-	char *v = c->x86_vendor_id;
-	int i;
-	static int printed;
-
-	for (i = 0; i < X86_VENDOR_NUM; i++) {
-		if (cpu_devs[i]) {
-			if (!strcmp(v, cpu_devs[i]->c_ident[0]) ||
-			    (cpu_devs[i]->c_ident[1] &&
-			    !strcmp(v, cpu_devs[i]->c_ident[1]))) {
-				c->x86_vendor = i;
-				this_cpu = cpu_devs[i];
-				return;
-			}
-		}
-	}
-	if (!printed) {
-		printed++;
-		printk(KERN_ERR "CPU: Vendor unknown, using generic init.\n");
-		printk(KERN_ERR "CPU: Your system may be unstable.\n");
-	}
-	c->x86_vendor = X86_VENDOR_UNKNOWN;
-}
-
-static void __init early_cpu_support_print(void)
-{
-	int i,j;
-	struct cpu_dev *cpu_devx;
-
-	printk("KERNEL supported cpus:\n");
-	for (i = 0; i < X86_VENDOR_NUM; i++) {
-		cpu_devx = cpu_devs[i];
-		if (!cpu_devx)
-			continue;
-		for (j = 0; j < 2; j++) {
-			if (!cpu_devx->c_ident[j])
-				continue;
-			printk("  %s %s\n", cpu_devx->c_vendor,
-				cpu_devx->c_ident[j]);
-		}
-	}
-}
-
-/*
- * The NOPL instruction is supposed to exist on all CPUs with
- * family >= 6, unfortunately, that's not true in practice because
- * of early VIA chips and (more importantly) broken virtualizers that
- * are not easy to detect.  Hence, probe for it based on first
- * principles.
- *
- * Note: no 64-bit chip is known to lack these, but put the code here
- * for consistency with 32 bits, and to make it utterly trivial to
- * diagnose the problem should it ever surface.
- */
-static void __cpuinit detect_nopl(struct cpuinfo_x86 *c)
-{
-	const u32 nopl_signature = 0x888c53b1; /* Random number */
-	u32 has_nopl = nopl_signature;
-
-	clear_cpu_cap(c, X86_FEATURE_NOPL);
-	if (c->x86 >= 6) {
-		asm volatile("\n"
-			     "1:      .byte 0x0f,0x1f,0xc0\n" /* nopl %eax */
-			     "2:\n"
-			     "        .section .fixup,\"ax\"\n"
-			     "3:      xor %0,%0\n"
-			     "        jmp 2b\n"
-			     "        .previous\n"
-			     _ASM_EXTABLE(1b,3b)
-			     : "+a" (has_nopl));
-
-		if (has_nopl == nopl_signature)
-			set_cpu_cap(c, X86_FEATURE_NOPL);
-	}
-}
-
-static void __cpuinit early_identify_cpu(struct cpuinfo_x86 *c);
-
-void __init early_cpu_init(void)
-{
-        struct cpu_vendor_dev *cvdev;
-
-        for (cvdev = __x86cpuvendor_start ;
-             cvdev < __x86cpuvendor_end   ;
-             cvdev++)
-                cpu_devs[cvdev->vendor] = cvdev->cpu_dev;
-	early_cpu_support_print();
-	early_identify_cpu(&boot_cpu_data);
-}
-
-/* Do some early cpuid on the boot CPU to get some parameter that are
-   needed before check_bugs. Everything advanced is in identify_cpu
-   below. */
-static void __cpuinit early_identify_cpu(struct cpuinfo_x86 *c)
-{
-	u32 tfms, xlvl;
-
-	c->loops_per_jiffy = loops_per_jiffy;
-	c->x86_cache_size = -1;
-	c->x86_vendor = X86_VENDOR_UNKNOWN;
-	c->x86_model = c->x86_mask = 0;	/* So far unknown... */
-	c->x86_vendor_id[0] = '\0'; /* Unset */
-	c->x86_model_id[0] = '\0';  /* Unset */
-	c->x86_clflush_size = 64;
-	c->x86_cache_alignment = c->x86_clflush_size;
-	c->x86_max_cores = 1;
-	c->x86_coreid_bits = 0;
-	c->extended_cpuid_level = 0;
-	memset(&c->x86_capability, 0, sizeof c->x86_capability);
-
-	/* Get vendor name */
-	cpuid(0x00000000, (unsigned int *)&c->cpuid_level,
-	      (unsigned int *)&c->x86_vendor_id[0],
-	      (unsigned int *)&c->x86_vendor_id[8],
-	      (unsigned int *)&c->x86_vendor_id[4]);
-
-	get_cpu_vendor(c);
-
-	/* Initialize the standard set of capabilities */
-	/* Note that the vendor-specific code below might override */
-
-	/* Intel-defined flags: level 0x00000001 */
-	if (c->cpuid_level >= 0x00000001) {
-		__u32 misc;
-		cpuid(0x00000001, &tfms, &misc, &c->x86_capability[4],
-		      &c->x86_capability[0]);
-		c->x86 = (tfms >> 8) & 0xf;
-		c->x86_model = (tfms >> 4) & 0xf;
-		c->x86_mask = tfms & 0xf;
-		if (c->x86 == 0xf)
-			c->x86 += (tfms >> 20) & 0xff;
-		if (c->x86 >= 0x6)
-			c->x86_model += ((tfms >> 16) & 0xF) << 4;
-		if (test_cpu_cap(c, X86_FEATURE_CLFLSH))
-			c->x86_clflush_size = ((misc >> 8) & 0xff) * 8;
-	} else {
-		/* Have CPUID level 0 only - unheard of */
-		c->x86 = 4;
-	}
-
-	c->initial_apicid = (cpuid_ebx(1) >> 24) & 0xff;
-#ifdef CONFIG_SMP
-	c->phys_proc_id = c->initial_apicid;
-#endif
-	/* AMD-defined flags: level 0x80000001 */
-	xlvl = cpuid_eax(0x80000000);
-	c->extended_cpuid_level = xlvl;
-	if ((xlvl & 0xffff0000) == 0x80000000) {
-		if (xlvl >= 0x80000001) {
-			c->x86_capability[1] = cpuid_edx(0x80000001);
-			c->x86_capability[6] = cpuid_ecx(0x80000001);
-		}
-		if (xlvl >= 0x80000004)
-			get_model_name(c); /* Default name */
-	}
-
-	/* Transmeta-defined flags: level 0x80860001 */
-	xlvl = cpuid_eax(0x80860000);
-	if ((xlvl & 0xffff0000) == 0x80860000) {
-		/* Don't set x86_cpuid_level here for now to not confuse. */
-		if (xlvl >= 0x80860001)
-			c->x86_capability[2] = cpuid_edx(0x80860001);
-	}
-
-	if (c->extended_cpuid_level >= 0x80000007)
-		c->x86_power = cpuid_edx(0x80000007);
-
-	if (c->extended_cpuid_level >= 0x80000008) {
-		u32 eax = cpuid_eax(0x80000008);
-
-		c->x86_virt_bits = (eax >> 8) & 0xff;
-		c->x86_phys_bits = eax & 0xff;
-	}
-
-	detect_nopl(c);
-
-	if (c->x86_vendor != X86_VENDOR_UNKNOWN &&
-	    cpu_devs[c->x86_vendor]->c_early_init)
-		cpu_devs[c->x86_vendor]->c_early_init(c);
-
-	validate_pat_support(c);
-}
-
-/*
- * This does the hard work of actually picking apart the CPU stuff...
- */
-static void __cpuinit identify_cpu(struct cpuinfo_x86 *c)
-{
-	int i;
-
-	early_identify_cpu(c);
-
-	init_scattered_cpuid_features(c);
-
-	c->apicid = phys_pkg_id(0);
-
-	/*
-	 * Vendor-specific initialization.  In this section we
-	 * canonicalize the feature flags, meaning if there are
-	 * features a certain CPU supports which CPUID doesn't
-	 * tell us, CPUID claiming incorrect flags, or other bugs,
-	 * we handle them here.
-	 *
-	 * At the end of this section, c->x86_capability better
-	 * indicate the features this CPU genuinely supports!
-	 */
-	if (this_cpu->c_init)
-		this_cpu->c_init(c);
-
-	detect_ht(c);
-
-	/*
-	 * On SMP, boot_cpu_data holds the common feature set between
-	 * all CPUs; so make sure that we indicate which features are
-	 * common between the CPUs.  The first time this routine gets
-	 * executed, c == &boot_cpu_data.
-	 */
-	if (c != &boot_cpu_data) {
-		/* AND the already accumulated flags with these */
-		for (i = 0; i < NCAPINTS; i++)
-			boot_cpu_data.x86_capability[i] &= c->x86_capability[i];
-	}
-
-	/* Clear all flags overriden by options */
-	for (i = 0; i < NCAPINTS; i++)
-		c->x86_capability[i] &= ~cleared_cpu_caps[i];
-
-#ifdef CONFIG_X86_MCE
-	mcheck_init(c);
-#endif
-	select_idle_routine(c);
-
-#ifdef CONFIG_NUMA
-	numa_add_cpu(smp_processor_id());
-#endif
-
-}
-
-void __cpuinit identify_boot_cpu(void)
-{
-	identify_cpu(&boot_cpu_data);
-}
-
-void __cpuinit identify_secondary_cpu(struct cpuinfo_x86 *c)
-{
-	BUG_ON(c == &boot_cpu_data);
-	identify_cpu(c);
-	mtrr_ap_init();
-}
-
-static __init int setup_noclflush(char *arg)
-{
-	setup_clear_cpu_cap(X86_FEATURE_CLFLSH);
-	return 1;
-}
-__setup("noclflush", setup_noclflush);
-
-void __cpuinit print_cpu_info(struct cpuinfo_x86 *c)
-{
-	if (c->x86_model_id[0])
-		printk(KERN_CONT "%s", c->x86_model_id);
-
-	if (c->x86_mask || c->cpuid_level >= 0)
-		printk(KERN_CONT " stepping %02x\n", c->x86_mask);
-	else
-		printk(KERN_CONT "\n");
-}
-
-static __init int setup_disablecpuid(char *arg)
-{
-	int bit;
-	if (get_option(&arg, &bit) && bit < NCAPINTS*32)
-		setup_clear_cpu_cap(bit);
-	else
-		return 0;
-	return 1;
-}
-__setup("clearcpuid=", setup_disablecpuid);
-
-cpumask_t cpu_initialized __cpuinitdata = CPU_MASK_NONE;
-
-struct x8664_pda **_cpu_pda __read_mostly;
-EXPORT_SYMBOL(_cpu_pda);
-
-struct desc_ptr idt_descr = { 256 * 16 - 1, (unsigned long) idt_table };
-
-char boot_cpu_stack[IRQSTACKSIZE] __page_aligned_bss;
-
-unsigned long __supported_pte_mask __read_mostly = ~0UL;
-EXPORT_SYMBOL_GPL(__supported_pte_mask);
-
-static int do_not_nx __cpuinitdata;
-
-/* noexec=on|off
-Control non executable mappings for 64bit processes.
-
-on	Enable(default)
-off	Disable
-*/
-static int __init nonx_setup(char *str)
-{
-	if (!str)
-		return -EINVAL;
-	if (!strncmp(str, "on", 2)) {
-		__supported_pte_mask |= _PAGE_NX;
-		do_not_nx = 0;
-	} else if (!strncmp(str, "off", 3)) {
-		do_not_nx = 1;
-		__supported_pte_mask &= ~_PAGE_NX;
-	}
-	return 0;
-}
-early_param("noexec", nonx_setup);
-
-int force_personality32;
-
-/* noexec32=on|off
-Control non executable heap for 32bit processes.
-To control the stack too use noexec=off
-
-on	PROT_READ does not imply PROT_EXEC for 32bit processes (default)
-off	PROT_READ implies PROT_EXEC
-*/
-static int __init nonx32_setup(char *str)
-{
-	if (!strcmp(str, "on"))
-		force_personality32 &= ~READ_IMPLIES_EXEC;
-	else if (!strcmp(str, "off"))
-		force_personality32 |= READ_IMPLIES_EXEC;
-	return 1;
-}
-__setup("noexec32=", nonx32_setup);
-
-void pda_init(int cpu)
-{
-	struct x8664_pda *pda = cpu_pda(cpu);
-
-	/* Setup up data that may be needed in __get_free_pages early */
-	loadsegment(fs, 0);
-	loadsegment(gs, 0);
-	/* Memory clobbers used to order PDA accessed */
-	mb();
-	wrmsrl(MSR_GS_BASE, pda);
-	mb();
-
-	pda->cpunumber = cpu;
-	pda->irqcount = -1;
-	pda->kernelstack = (unsigned long)stack_thread_info() -
-				 PDA_STACKOFFSET + THREAD_SIZE;
-	pda->active_mm = &init_mm;
-	pda->mmu_state = 0;
-
-	if (cpu == 0) {
-		/* others are initialized in smpboot.c */
-		pda->pcurrent = &init_task;
-		pda->irqstackptr = boot_cpu_stack;
-		pda->irqstackptr += IRQSTACKSIZE - 64;
-	} else {
-		if (!pda->irqstackptr) {
-			pda->irqstackptr = (char *)
-				__get_free_pages(GFP_ATOMIC, IRQSTACK_ORDER);
-			if (!pda->irqstackptr)
-				panic("cannot allocate irqstack for cpu %d",
-				      cpu);
-			pda->irqstackptr += IRQSTACKSIZE - 64;
-		}
-
-		if (pda->nodenumber == 0 && cpu_to_node(cpu) != NUMA_NO_NODE)
-			pda->nodenumber = cpu_to_node(cpu);
-	}
-}
-
-char boot_exception_stacks[(N_EXCEPTION_STACKS - 1) * EXCEPTION_STKSZ +
-			   DEBUG_STKSZ] __page_aligned_bss;
-
-extern asmlinkage void ignore_sysret(void);
-
-/* May not be marked __init: used by software suspend */
-void syscall_init(void)
-{
-	/*
-	 * LSTAR and STAR live in a bit strange symbiosis.
-	 * They both write to the same internal register. STAR allows to
-	 * set CS/DS but only a 32bit target. LSTAR sets the 64bit rip.
-	 */
-	wrmsrl(MSR_STAR,  ((u64)__USER32_CS)<<48  | ((u64)__KERNEL_CS)<<32);
-	wrmsrl(MSR_LSTAR, system_call);
-	wrmsrl(MSR_CSTAR, ignore_sysret);
-
-#ifdef CONFIG_IA32_EMULATION
-	syscall32_cpu_init();
-#endif
-
-	/* Flags to clear on syscall */
-	wrmsrl(MSR_SYSCALL_MASK,
-	       X86_EFLAGS_TF|X86_EFLAGS_DF|X86_EFLAGS_IF|X86_EFLAGS_IOPL);
-}
-
-void __cpuinit check_efer(void)
-{
-	unsigned long efer;
-
-	rdmsrl(MSR_EFER, efer);
-	if (!(efer & EFER_NX) || do_not_nx)
-		__supported_pte_mask &= ~_PAGE_NX;
-}
-
-unsigned long kernel_eflags;
-
-/*
- * Copies of the original ist values from the tss are only accessed during
- * debugging, no special alignment required.
- */
-DEFINE_PER_CPU(struct orig_ist, orig_ist);
-
-/*
- * cpu_init() initializes state that is per-CPU. Some data is already
- * initialized (naturally) in the bootstrap process, such as the GDT
- * and IDT. We reload them nevertheless, this function acts as a
- * 'CPU state barrier', nothing should get across.
- * A lot of state is already set up in PDA init.
- */
-void __cpuinit cpu_init(void)
-{
-	int cpu = stack_smp_processor_id();
-	struct tss_struct *t = &per_cpu(init_tss, cpu);
-	struct orig_ist *orig_ist = &per_cpu(orig_ist, cpu);
-	unsigned long v;
-	char *estacks = NULL;
-	struct task_struct *me;
-	int i;
-
-	/* CPU 0 is initialised in head64.c */
-	if (cpu != 0)
-		pda_init(cpu);
-	else
-		estacks = boot_exception_stacks;
-
-	me = current;
-
-	if (cpu_test_and_set(cpu, cpu_initialized))
-		panic("CPU#%d already initialized!\n", cpu);
-
-	printk(KERN_INFO "Initializing CPU#%d\n", cpu);
-
-	clear_in_cr4(X86_CR4_VME|X86_CR4_PVI|X86_CR4_TSD|X86_CR4_DE);
-
-	/*
-	 * Initialize the per-CPU GDT with the boot GDT,
-	 * and set up the GDT descriptor:
-	 */
-
-	switch_to_new_gdt();
-	load_idt((const struct desc_ptr *)&idt_descr);
-
-	memset(me->thread.tls_array, 0, GDT_ENTRY_TLS_ENTRIES * 8);
-	syscall_init();
-
-	wrmsrl(MSR_FS_BASE, 0);
-	wrmsrl(MSR_KERNEL_GS_BASE, 0);
-	barrier();
-
-	check_efer();
-
-	/*
-	 * set up and load the per-CPU TSS
-	 */
-	if (!orig_ist->ist[0]) {
-		static const unsigned int order[N_EXCEPTION_STACKS] = {
-		  [0 ... N_EXCEPTION_STACKS - 1] = EXCEPTION_STACK_ORDER,
-		  [DEBUG_STACK - 1] = DEBUG_STACK_ORDER
-		};
-		for (v = 0; v < N_EXCEPTION_STACKS; v++) {
-			if (cpu) {
-				estacks = (char *)__get_free_pages(GFP_ATOMIC, order[v]);
-				if (!estacks)
-					panic("Cannot allocate exception "
-					      "stack %ld %d\n", v, cpu);
-			}
-			estacks += PAGE_SIZE << order[v];
-			orig_ist->ist[v] = t->x86_tss.ist[v] =
-					(unsigned long)estacks;
-		}
-	}
-
-	t->x86_tss.io_bitmap_base = offsetof(struct tss_struct, io_bitmap);
-	/*
-	 * <= is required because the CPU will access up to
-	 * 8 bits beyond the end of the IO permission bitmap.
-	 */
-	for (i = 0; i <= IO_BITMAP_LONGS; i++)
-		t->io_bitmap[i] = ~0UL;
-
-	atomic_inc(&init_mm.mm_count);
-	me->active_mm = &init_mm;
-	if (me->mm)
-		BUG();
-	enter_lazy_tlb(&init_mm, me);
-
-	load_sp0(t, &current->thread);
-	set_tss_desc(cpu, t);
-	load_TR_desc();
-	load_LDT(&init_mm.context);
-
-#ifdef CONFIG_KGDB
-	/*
-	 * If the kgdb is connected no debug regs should be altered.  This
-	 * is only applicable when KGDB and a KGDB I/O module are built
-	 * into the kernel and you are using early debugging with
-	 * kgdbwait. KGDB will control the kernel HW breakpoint registers.
-	 */
-	if (kgdb_connected && arch_kgdb_ops.correct_hw_break)
-		arch_kgdb_ops.correct_hw_break();
-	else {
-#endif
-	/*
-	 * Clear all 6 debug registers:
-	 */
-
-	set_debugreg(0UL, 0);
-	set_debugreg(0UL, 1);
-	set_debugreg(0UL, 2);
-	set_debugreg(0UL, 3);
-	set_debugreg(0UL, 6);
-	set_debugreg(0UL, 7);
-#ifdef CONFIG_KGDB
-	/* If the kgdb is connected no debug regs should be altered. */
-	}
-#endif
-
-	fpu_init();
-
-	raw_local_save_flags(kernel_eflags);
-
-	if (is_uv_system())
-		uv_cpu_init();
-}
diff --git a/arch/x86/kernel/cpu/cpu.h b/arch/x86/kernel/cpu/cpu.h
index 4d894e8..de4094a 100644
--- a/arch/x86/kernel/cpu/cpu.h
+++ b/arch/x86/kernel/cpu/cpu.h
@@ -21,23 +21,16 @@
 	void		(*c_init)(struct cpuinfo_x86 * c);
 	void		(*c_identify)(struct cpuinfo_x86 * c);
 	unsigned int	(*c_size_cache)(struct cpuinfo_x86 * c, unsigned int size);
+	int	c_x86_vendor;
 };
 
-extern struct cpu_dev * cpu_devs [X86_VENDOR_NUM];
+#define cpu_dev_register(cpu_devX) \
+	static struct cpu_dev *__cpu_dev_##cpu_devX __used \
+	__attribute__((__section__(".x86_cpu_dev.init"))) = \
+	&cpu_devX;
 
-struct cpu_vendor_dev {
-	int vendor;
-	struct cpu_dev *cpu_dev;
-};
+extern struct cpu_dev *__x86_cpu_dev_start[], *__x86_cpu_dev_end[];
 
-#define cpu_vendor_dev_register(cpu_vendor_id, cpu_dev) \
-	static struct cpu_vendor_dev __cpu_vendor_dev_##cpu_vendor_id __used \
-	__attribute__((__section__(".x86cpuvendor.init"))) = \
-	{ cpu_vendor_id, cpu_dev }
-
-extern struct cpu_vendor_dev __x86cpuvendor_start[], __x86cpuvendor_end[];
-
-extern int get_model_name(struct cpuinfo_x86 *c);
 extern void display_cacheinfo(struct cpuinfo_x86 *c);
 
 #endif
diff --git a/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c b/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c
index dd097b8..c24c4a4 100644
--- a/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c
+++ b/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c
@@ -256,7 +256,8 @@
  * Only IA32_APERF/IA32_MPERF ratio is architecturally defined and
  * no meaning should be associated with absolute values of these MSRs.
  */
-static unsigned int get_measured_perf(unsigned int cpu)
+static unsigned int get_measured_perf(struct cpufreq_policy *policy,
+				      unsigned int cpu)
 {
 	union {
 		struct {
@@ -326,7 +327,7 @@
 
 #endif
 
-	retval = per_cpu(drv_data, cpu)->max_freq * perf_percent / 100;
+	retval = per_cpu(drv_data, policy->cpu)->max_freq * perf_percent / 100;
 
 	put_cpu();
 	set_cpus_allowed_ptr(current, &saved_mask);
@@ -785,7 +786,11 @@
 	if (ret)
 		return ret;
 
-	return cpufreq_register_driver(&acpi_cpufreq_driver);
+	ret = cpufreq_register_driver(&acpi_cpufreq_driver);
+	if (ret)
+		free_percpu(acpi_perf_data);
+
+	return ret;
 }
 
 static void __exit acpi_cpufreq_exit(void)
@@ -795,8 +800,6 @@
 	cpufreq_unregister_driver(&acpi_cpufreq_driver);
 
 	free_percpu(acpi_perf_data);
-
-	return;
 }
 
 module_param(acpi_pstate_strict, uint, 0644);
diff --git a/arch/x86/kernel/cpu/cpufreq/elanfreq.c b/arch/x86/kernel/cpu/cpufreq/elanfreq.c
index e4a4bf8..fe613c9 100644
--- a/arch/x86/kernel/cpu/cpufreq/elanfreq.c
+++ b/arch/x86/kernel/cpu/cpufreq/elanfreq.c
@@ -25,8 +25,8 @@
 #include <linux/cpufreq.h>
 
 #include <asm/msr.h>
-#include <asm/timex.h>
-#include <asm/io.h>
+#include <linux/timex.h>
+#include <linux/io.h>
 
 #define REG_CSCIR 0x22		/* Chip Setup and Control Index Register    */
 #define REG_CSCDR 0x23		/* Chip Setup and Control Data  Register    */
@@ -82,7 +82,7 @@
 	u8 clockspeed_reg;    /* Clock Speed Register */
 
 	local_irq_disable();
-	outb_p(0x80,REG_CSCIR);
+	outb_p(0x80, REG_CSCIR);
 	clockspeed_reg = inb_p(REG_CSCDR);
 	local_irq_enable();
 
@@ -98,10 +98,10 @@
 	}
 
 	/* 33 MHz is not 32 MHz... */
-	if ((clockspeed_reg & 0xE0)==0xA0)
+	if ((clockspeed_reg & 0xE0) == 0xA0)
 		return 33000;
 
-	return ((1<<((clockspeed_reg & 0xE0) >> 5)) * 1000);
+	return (1<<((clockspeed_reg & 0xE0) >> 5)) * 1000;
 }
 
 
@@ -117,7 +117,7 @@
  *	There is no return value.
  */
 
-static void elanfreq_set_cpu_state (unsigned int state)
+static void elanfreq_set_cpu_state(unsigned int state)
 {
 	struct cpufreq_freqs    freqs;
 
@@ -144,20 +144,20 @@
 	 */
 
 	local_irq_disable();
-	outb_p(0x40,REG_CSCIR);		/* Disable hyperspeed mode */
-	outb_p(0x00,REG_CSCDR);
+	outb_p(0x40, REG_CSCIR);		/* Disable hyperspeed mode */
+	outb_p(0x00, REG_CSCDR);
 	local_irq_enable();		/* wait till internal pipelines and */
 	udelay(1000);			/* buffers have cleaned up          */
 
 	local_irq_disable();
 
 	/* now, set the CPU clock speed register (0x80) */
-	outb_p(0x80,REG_CSCIR);
-	outb_p(elan_multiplier[state].val80h,REG_CSCDR);
+	outb_p(0x80, REG_CSCIR);
+	outb_p(elan_multiplier[state].val80h, REG_CSCDR);
 
 	/* now, the hyperspeed bit in PMU Force Mode Register (0x40) */
-	outb_p(0x40,REG_CSCIR);
-	outb_p(elan_multiplier[state].val40h,REG_CSCDR);
+	outb_p(0x40, REG_CSCIR);
+	outb_p(elan_multiplier[state].val40h, REG_CSCDR);
 	udelay(10000);
 	local_irq_enable();
 
@@ -173,12 +173,12 @@
  *	for the hardware supported by the driver.
  */
 
-static int elanfreq_verify (struct cpufreq_policy *policy)
+static int elanfreq_verify(struct cpufreq_policy *policy)
 {
 	return cpufreq_frequency_table_verify(policy, &elanfreq_table[0]);
 }
 
-static int elanfreq_target (struct cpufreq_policy *policy,
+static int elanfreq_target(struct cpufreq_policy *policy,
 			    unsigned int target_freq,
 			    unsigned int relation)
 {
@@ -205,7 +205,7 @@
 
 	/* capability check */
 	if ((c->x86_vendor != X86_VENDOR_AMD) ||
-	    (c->x86 != 4) || (c->x86_model!=10))
+	    (c->x86 != 4) || (c->x86_model != 10))
 		return -ENODEV;
 
 	/* max freq */
@@ -213,7 +213,7 @@
 		max_freq = elanfreq_get_cpu_frequency(0);
 
 	/* table init */
-	for (i=0; (elanfreq_table[i].frequency != CPUFREQ_TABLE_END); i++) {
+	for (i = 0; (elanfreq_table[i].frequency != CPUFREQ_TABLE_END); i++) {
 		if (elanfreq_table[i].frequency > max_freq)
 			elanfreq_table[i].frequency = CPUFREQ_ENTRY_INVALID;
 	}
@@ -224,7 +224,7 @@
 
 	result = cpufreq_frequency_table_cpuinfo(policy, elanfreq_table);
 	if (result)
-		return (result);
+		return result;
 
 	cpufreq_frequency_table_get_attr(elanfreq_table, policy->cpu);
 	return 0;
@@ -260,7 +260,7 @@
 #endif
 
 
-static struct freq_attr* elanfreq_attr[] = {
+static struct freq_attr *elanfreq_attr[] = {
 	&cpufreq_freq_attr_scaling_available_freqs,
 	NULL,
 };
@@ -284,9 +284,9 @@
 
 	/* Test if we have the right hardware */
 	if ((c->x86_vendor != X86_VENDOR_AMD) ||
-		(c->x86 != 4) || (c->x86_model!=10)) {
+		(c->x86 != 4) || (c->x86_model != 10)) {
 		printk(KERN_INFO "elanfreq: error: no Elan processor found!\n");
-                return -ENODEV;
+		return -ENODEV;
 	}
 	return cpufreq_register_driver(&elanfreq_driver);
 }
@@ -298,7 +298,7 @@
 }
 
 
-module_param (max_freq, int, 0444);
+module_param(max_freq, int, 0444);
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Robert Schwebel <r.schwebel@pengutronix.de>, Sven Geggus <sven@geggus.net>");
diff --git a/arch/x86/kernel/cpu/cpufreq/p4-clockmod.c b/arch/x86/kernel/cpu/cpufreq/p4-clockmod.c
index f1685fb..b8e05ee 100644
--- a/arch/x86/kernel/cpu/cpufreq/p4-clockmod.c
+++ b/arch/x86/kernel/cpu/cpufreq/p4-clockmod.c
@@ -171,7 +171,7 @@
 	}
 
 	if (c->x86 != 0xF) {
-		printk(KERN_WARNING PFX "Unknown p4-clockmod-capable CPU. Please send an e-mail to <cpufreq@lists.linux.org.uk>\n");
+		printk(KERN_WARNING PFX "Unknown p4-clockmod-capable CPU. Please send an e-mail to <cpufreq@vger.kernel.org>\n");
 		return 0;
 	}
 
diff --git a/arch/x86/kernel/cpu/cpufreq/powernow-k6.c b/arch/x86/kernel/cpu/cpufreq/powernow-k6.c
index eb9b62b..b5ced80 100644
--- a/arch/x86/kernel/cpu/cpufreq/powernow-k6.c
+++ b/arch/x86/kernel/cpu/cpufreq/powernow-k6.c
@@ -15,12 +15,11 @@
 #include <linux/slab.h>
 
 #include <asm/msr.h>
-#include <asm/timex.h>
-#include <asm/io.h>
+#include <linux/timex.h>
+#include <linux/io.h>
 
-
-#define POWERNOW_IOPORT 0xfff0         /* it doesn't matter where, as long
-					  as it is unused */
+#define POWERNOW_IOPORT 0xfff0          /* it doesn't matter where, as long
+					   as it is unused */
 
 static unsigned int                     busfreq;   /* FSB, in 10 kHz */
 static unsigned int                     max_multiplier;
@@ -53,7 +52,7 @@
 
 	msrval = POWERNOW_IOPORT + 0x1;
 	wrmsr(MSR_K6_EPMR, msrval, 0); /* enable the PowerNow port */
-	invalue=inl(POWERNOW_IOPORT + 0x8);
+	invalue = inl(POWERNOW_IOPORT + 0x8);
 	msrval = POWERNOW_IOPORT + 0x0;
 	wrmsr(MSR_K6_EPMR, msrval, 0); /* disable it again */
 
@@ -67,9 +66,9 @@
  *
  *   Tries to change the PowerNow! multiplier
  */
-static void powernow_k6_set_state (unsigned int best_i)
+static void powernow_k6_set_state(unsigned int best_i)
 {
-	unsigned long           outvalue=0, invalue=0;
+	unsigned long           outvalue = 0, invalue = 0;
 	unsigned long           msrval;
 	struct cpufreq_freqs    freqs;
 
@@ -90,10 +89,10 @@
 
 	msrval = POWERNOW_IOPORT + 0x1;
 	wrmsr(MSR_K6_EPMR, msrval, 0); /* enable the PowerNow port */
-	invalue=inl(POWERNOW_IOPORT + 0x8);
+	invalue = inl(POWERNOW_IOPORT + 0x8);
 	invalue = invalue & 0xf;
 	outvalue = outvalue | invalue;
-	outl(outvalue ,(POWERNOW_IOPORT + 0x8));
+	outl(outvalue , (POWERNOW_IOPORT + 0x8));
 	msrval = POWERNOW_IOPORT + 0x0;
 	wrmsr(MSR_K6_EPMR, msrval, 0); /* disable it again */
 
@@ -124,7 +123,7 @@
  *
  * sets a new CPUFreq policy
  */
-static int powernow_k6_target (struct cpufreq_policy *policy,
+static int powernow_k6_target(struct cpufreq_policy *policy,
 			       unsigned int target_freq,
 			       unsigned int relation)
 {
@@ -152,7 +151,7 @@
 	busfreq = cpu_khz / max_multiplier;
 
 	/* table init */
-	for (i=0; (clock_ratio[i].frequency != CPUFREQ_TABLE_END); i++) {
+	for (i = 0; (clock_ratio[i].frequency != CPUFREQ_TABLE_END); i++) {
 		if (clock_ratio[i].index > max_multiplier)
 			clock_ratio[i].frequency = CPUFREQ_ENTRY_INVALID;
 		else
@@ -165,7 +164,7 @@
 
 	result = cpufreq_frequency_table_cpuinfo(policy, clock_ratio);
 	if (result)
-		return (result);
+		return result;
 
 	cpufreq_frequency_table_get_attr(clock_ratio, policy->cpu);
 
@@ -176,8 +175,8 @@
 static int powernow_k6_cpu_exit(struct cpufreq_policy *policy)
 {
 	unsigned int i;
-	for (i=0; i<8; i++) {
-		if (i==max_multiplier)
+	for (i = 0; i < 8; i++) {
+		if (i == max_multiplier)
 			powernow_k6_set_state(i);
 	}
 	cpufreq_frequency_table_put_attr(policy->cpu);
@@ -189,7 +188,7 @@
 	return busfreq * powernow_k6_get_cpu_multiplier();
 }
 
-static struct freq_attr* powernow_k6_attr[] = {
+static struct freq_attr *powernow_k6_attr[] = {
 	&cpufreq_freq_attr_scaling_available_freqs,
 	NULL,
 };
@@ -227,7 +226,7 @@
 	}
 
 	if (cpufreq_register_driver(&powernow_k6_driver)) {
-		release_region (POWERNOW_IOPORT, 16);
+		release_region(POWERNOW_IOPORT, 16);
 		return -EINVAL;
 	}
 
@@ -243,13 +242,13 @@
 static void __exit powernow_k6_exit(void)
 {
 	cpufreq_unregister_driver(&powernow_k6_driver);
-	release_region (POWERNOW_IOPORT, 16);
+	release_region(POWERNOW_IOPORT, 16);
 }
 
 
-MODULE_AUTHOR ("Arjan van de Ven <arjanv@redhat.com>, Dave Jones <davej@codemonkey.org.uk>, Dominik Brodowski <linux@brodo.de>");
-MODULE_DESCRIPTION ("PowerNow! driver for AMD K6-2+ / K6-3+ processors.");
-MODULE_LICENSE ("GPL");
+MODULE_AUTHOR("Arjan van de Ven <arjanv@redhat.com>, Dave Jones <davej@codemonkey.org.uk>, Dominik Brodowski <linux@brodo.de>");
+MODULE_DESCRIPTION("PowerNow! driver for AMD K6-2+ / K6-3+ processors.");
+MODULE_LICENSE("GPL");
 
 module_init(powernow_k6_init);
 module_exit(powernow_k6_exit);
diff --git a/arch/x86/kernel/cpu/cpufreq/speedstep-centrino.c b/arch/x86/kernel/cpu/cpufreq/speedstep-centrino.c
index 15e13c0..3b5f064 100644
--- a/arch/x86/kernel/cpu/cpufreq/speedstep-centrino.c
+++ b/arch/x86/kernel/cpu/cpufreq/speedstep-centrino.c
@@ -26,7 +26,7 @@
 #include <asm/cpufeature.h>
 
 #define PFX		"speedstep-centrino: "
-#define MAINTAINER	"cpufreq@lists.linux.org.uk"
+#define MAINTAINER	"cpufreq@vger.kernel.org"
 
 #define dprintk(msg...) \
 	cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, "speedstep-centrino", msg)
diff --git a/arch/x86/kernel/cpu/cyrix.c b/arch/x86/kernel/cpu/cyrix.c
index 898a5a2..ffd0f5e 100644
--- a/arch/x86/kernel/cpu/cyrix.c
+++ b/arch/x86/kernel/cpu/cyrix.c
@@ -121,7 +121,7 @@
 	setCx86(CX86_CCR3, (ccr3 & 0x0f) | 0x10); /* enable MAPEN */
 
 	/* Load/Store Serialize to mem access disable (=reorder it) */
-	setCx86(CX86_PCR0, getCx86(CX86_PCR0) & ~0x80);
+	setCx86_old(CX86_PCR0, getCx86_old(CX86_PCR0) & ~0x80);
 	/* set load/store serialize from 1GB to 4GB */
 	ccr3 |= 0xe0;
 	setCx86(CX86_CCR3, ccr3);
@@ -132,11 +132,11 @@
 	printk(KERN_INFO "Enable Memory-Write-back mode on Cyrix/NSC processor.\n");
 
 	/* CCR2 bit 2: unlock NW bit */
-	setCx86(CX86_CCR2, getCx86(CX86_CCR2) & ~0x04);
+	setCx86_old(CX86_CCR2, getCx86_old(CX86_CCR2) & ~0x04);
 	/* set 'Not Write-through' */
 	write_cr0(read_cr0() | X86_CR0_NW);
 	/* CCR2 bit 2: lock NW bit and set WT1 */
-	setCx86(CX86_CCR2, getCx86(CX86_CCR2) | 0x14);
+	setCx86_old(CX86_CCR2, getCx86_old(CX86_CCR2) | 0x14);
 }
 
 /*
@@ -150,14 +150,14 @@
 	local_irq_save(flags);
 
 	/* Suspend on halt power saving and enable #SUSP pin */
-	setCx86(CX86_CCR2, getCx86(CX86_CCR2) | 0x88);
+	setCx86_old(CX86_CCR2, getCx86_old(CX86_CCR2) | 0x88);
 
 	ccr3 = getCx86(CX86_CCR3);
 	setCx86(CX86_CCR3, (ccr3 & 0x0f) | 0x10);	/* enable MAPEN */
 
 
 	/* FPU fast, DTE cache, Mem bypass */
-	setCx86(CX86_CCR4, getCx86(CX86_CCR4) | 0x38);
+	setCx86_old(CX86_CCR4, getCx86_old(CX86_CCR4) | 0x38);
 	setCx86(CX86_CCR3, ccr3);			/* disable MAPEN */
 
 	set_cx86_memwb();
@@ -291,7 +291,7 @@
 		/* GXm supports extended cpuid levels 'ala' AMD */
 		if (c->cpuid_level == 2) {
 			/* Enable cxMMX extensions (GX1 Datasheet 54) */
-			setCx86(CX86_CCR7, getCx86(CX86_CCR7) | 1);
+			setCx86_old(CX86_CCR7, getCx86_old(CX86_CCR7) | 1);
 
 			/*
 			 * GXm : 0x30 ... 0x5f GXm  datasheet 51
@@ -301,7 +301,6 @@
 			 */
 			if ((0x30 <= dir1 && dir1 <= 0x6f) || (0x80 <= dir1 && dir1 <= 0x8f))
 				geode_configure();
-			get_model_name(c);  /* get CPU marketing name */
 			return;
 		} else { /* MediaGX */
 			Cx86_cb[2] = (dir0_lsn & 1) ? '3' : '4';
@@ -314,7 +313,7 @@
 		if (dir1 > 7) {
 			dir0_msn++;  /* M II */
 			/* Enable MMX extensions (App note 108) */
-			setCx86(CX86_CCR7, getCx86(CX86_CCR7)|1);
+			setCx86_old(CX86_CCR7, getCx86_old(CX86_CCR7)|1);
 		} else {
 			c->coma_bug = 1;      /* 6x86MX, it has the bug. */
 		}
@@ -429,7 +428,7 @@
 			local_irq_save(flags);
 			ccr3 = getCx86(CX86_CCR3);
 			setCx86(CX86_CCR3, (ccr3 & 0x0f) | 0x10);       /* enable MAPEN  */
-			setCx86(CX86_CCR4, getCx86(CX86_CCR4) | 0x80);  /* enable cpuid  */
+			setCx86_old(CX86_CCR4, getCx86_old(CX86_CCR4) | 0x80);  /* enable cpuid  */
 			setCx86(CX86_CCR3, ccr3);                       /* disable MAPEN */
 			local_irq_restore(flags);
 		}
@@ -442,14 +441,16 @@
 	.c_early_init	= early_init_cyrix,
 	.c_init		= init_cyrix,
 	.c_identify	= cyrix_identify,
+	.c_x86_vendor	= X86_VENDOR_CYRIX,
 };
 
-cpu_vendor_dev_register(X86_VENDOR_CYRIX, &cyrix_cpu_dev);
+cpu_dev_register(cyrix_cpu_dev);
 
 static struct cpu_dev nsc_cpu_dev __cpuinitdata = {
 	.c_vendor	= "NSC",
 	.c_ident	= { "Geode by NSC" },
 	.c_init		= init_nsc,
+	.c_x86_vendor	= X86_VENDOR_NSC,
 };
 
-cpu_vendor_dev_register(X86_VENDOR_NSC, &nsc_cpu_dev);
+cpu_dev_register(nsc_cpu_dev);
diff --git a/arch/x86/kernel/cpu/feature_names.c b/arch/x86/kernel/cpu/feature_names.c
deleted file mode 100644
index c901779..0000000
--- a/arch/x86/kernel/cpu/feature_names.c
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Strings for the various x86 capability flags.
- *
- * This file must not contain any executable code.
- */
-
-#include <asm/cpufeature.h>
-
-/*
- * These flag bits must match the definitions in <asm/cpufeature.h>.
- * NULL means this bit is undefined or reserved; either way it doesn't
- * have meaning as far as Linux is concerned.  Note that it's important
- * to realize there is a difference between this table and CPUID -- if
- * applications want to get the raw CPUID data, they should access
- * /dev/cpu/<cpu_nr>/cpuid instead.
- */
-const char * const x86_cap_flags[NCAPINTS*32] = {
-	/* Intel-defined */
-	"fpu", "vme", "de", "pse", "tsc", "msr", "pae", "mce",
-	"cx8", "apic", NULL, "sep", "mtrr", "pge", "mca", "cmov",
-	"pat", "pse36", "pn", "clflush", NULL, "dts", "acpi", "mmx",
-	"fxsr", "sse", "sse2", "ss", "ht", "tm", "ia64", "pbe",
-
-	/* AMD-defined */
-	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-	NULL, NULL, NULL, "syscall", NULL, NULL, NULL, NULL,
-	NULL, NULL, NULL, "mp", "nx", NULL, "mmxext", NULL,
-	NULL, "fxsr_opt", "pdpe1gb", "rdtscp", NULL, "lm",
-	"3dnowext", "3dnow",
-
-	/* Transmeta-defined */
-	"recovery", "longrun", NULL, "lrti", NULL, NULL, NULL, NULL,
-	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-
-	/* Other (Linux-defined) */
-	"cxmmx", "k6_mtrr", "cyrix_arr", "centaur_mcr",
-	NULL, NULL, NULL, NULL,
-	"constant_tsc", "up", NULL, "arch_perfmon",
-	"pebs", "bts", NULL, NULL,
-	"rep_good", NULL, NULL, NULL,
-	"nopl", NULL, NULL, NULL,
-	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-
-	/* Intel-defined (#2) */
-	"pni", NULL, NULL, "monitor", "ds_cpl", "vmx", "smx", "est",
-	"tm2", "ssse3", "cid", NULL, NULL, "cx16", "xtpr", NULL,
-	NULL, NULL, "dca", "sse4_1", "sse4_2", NULL, NULL, "popcnt",
-	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-
-	/* VIA/Cyrix/Centaur-defined */
-	NULL, NULL, "rng", "rng_en", NULL, NULL, "ace", "ace_en",
-	"ace2", "ace2_en", "phe", "phe_en", "pmm", "pmm_en", NULL, NULL,
-	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-
-	/* AMD-defined (#2) */
-	"lahf_lm", "cmp_legacy", "svm", "extapic",
-	"cr8_legacy", "abm", "sse4a", "misalignsse",
-	"3dnowprefetch", "osvw", "ibs", "sse5",
-	"skinit", "wdt", NULL, NULL,
-	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-
-	/* Auxiliary (Linux-defined) */
-	"ida", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-};
-
-const char *const x86_power_flags[32] = {
-	"ts",	/* temperature sensor */
-	"fid",  /* frequency id control */
-	"vid",  /* voltage id control */
-	"ttp",  /* thermal trip */
-	"tm",
-	"stc",
-	"100mhzsteps",
-	"hwpstate",
-	"",	/* tsc invariant mapped to constant_tsc */
-		/* nothing */
-};
diff --git a/arch/x86/kernel/cpu/intel.c b/arch/x86/kernel/cpu/intel.c
index b75f256..99468db 100644
--- a/arch/x86/kernel/cpu/intel.c
+++ b/arch/x86/kernel/cpu/intel.c
@@ -15,6 +15,11 @@
 #include <asm/ds.h>
 #include <asm/bugs.h>
 
+#ifdef CONFIG_X86_64
+#include <asm/topology.h>
+#include <asm/numa_64.h>
+#endif
+
 #include "cpu.h"
 
 #ifdef CONFIG_X86_LOCAL_APIC
@@ -23,23 +28,22 @@
 #include <mach_apic.h>
 #endif
 
-#ifdef CONFIG_X86_INTEL_USERCOPY
-/*
- * Alignment at which movsl is preferred for bulk memory copies.
- */
-struct movsl_mask movsl_mask __read_mostly;
-#endif
-
 static void __cpuinit early_init_intel(struct cpuinfo_x86 *c)
 {
-	/* Netburst reports 64 bytes clflush size, but does IO in 128 bytes */
-	if (c->x86 == 15 && c->x86_cache_alignment == 64)
-		c->x86_cache_alignment = 128;
 	if ((c->x86 == 0xf && c->x86_model >= 0x03) ||
 		(c->x86 == 0x6 && c->x86_model >= 0x0e))
 		set_cpu_cap(c, X86_FEATURE_CONSTANT_TSC);
+
+#ifdef CONFIG_X86_64
+	set_cpu_cap(c, X86_FEATURE_SYSENTER32);
+#else
+	/* Netburst reports 64 bytes clflush size, but does IO in 128 bytes */
+	if (c->x86 == 15 && c->x86_cache_alignment == 64)
+		c->x86_cache_alignment = 128;
+#endif
 }
 
+#ifdef CONFIG_X86_32
 /*
  *	Early probe support logic for ppro memory erratum #50
  *
@@ -59,45 +63,6 @@
 	return 0;
 }
 
-
-/*
- * P4 Xeon errata 037 workaround.
- * Hardware prefetcher may cause stale data to be loaded into the cache.
- */
-static void __cpuinit Intel_errata_workarounds(struct cpuinfo_x86 *c)
-{
-	unsigned long lo, hi;
-
-	if ((c->x86 == 15) && (c->x86_model == 1) && (c->x86_mask == 1)) {
-		rdmsr(MSR_IA32_MISC_ENABLE, lo, hi);
-		if ((lo & (1<<9)) == 0) {
-			printk (KERN_INFO "CPU: C0 stepping P4 Xeon detected.\n");
-			printk (KERN_INFO "CPU: Disabling hardware prefetching (Errata 037)\n");
-			lo |= (1<<9);	/* Disable hw prefetching */
-			wrmsr (MSR_IA32_MISC_ENABLE, lo, hi);
-		}
-	}
-}
-
-
-/*
- * find out the number of processor cores on the die
- */
-static int __cpuinit num_cpu_cores(struct cpuinfo_x86 *c)
-{
-	unsigned int eax, ebx, ecx, edx;
-
-	if (c->cpuid_level < 4)
-		return 1;
-
-	/* Intel has a non-standard dependency on %ecx for this CPUID level. */
-	cpuid_count(4, 0, &eax, &ebx, &ecx, &edx);
-	if (eax & 0x1f)
-		return ((eax >> 26) + 1);
-	else
-		return 1;
-}
-
 #ifdef CONFIG_X86_F00F_BUG
 static void __cpuinit trap_init_f00f_bug(void)
 {
@@ -112,12 +77,9 @@
 }
 #endif
 
-static void __cpuinit init_intel(struct cpuinfo_x86 *c)
+static void __cpuinit intel_workarounds(struct cpuinfo_x86 *c)
 {
-	unsigned int l2 = 0;
-	char *p = NULL;
-
-	early_init_intel(c);
+	unsigned long lo, hi;
 
 #ifdef CONFIG_X86_F00F_BUG
 	/*
@@ -138,6 +100,148 @@
 	}
 #endif
 
+	/*
+	 * SEP CPUID bug: Pentium Pro reports SEP but doesn't have it until
+	 * model 3 mask 3
+	 */
+	if ((c->x86<<8 | c->x86_model<<4 | c->x86_mask) < 0x633)
+		clear_cpu_cap(c, X86_FEATURE_SEP);
+
+	/*
+	 * P4 Xeon errata 037 workaround.
+	 * Hardware prefetcher may cause stale data to be loaded into the cache.
+	 */
+	if ((c->x86 == 15) && (c->x86_model == 1) && (c->x86_mask == 1)) {
+		rdmsr(MSR_IA32_MISC_ENABLE, lo, hi);
+		if ((lo & (1<<9)) == 0) {
+			printk (KERN_INFO "CPU: C0 stepping P4 Xeon detected.\n");
+			printk (KERN_INFO "CPU: Disabling hardware prefetching (Errata 037)\n");
+			lo |= (1<<9);	/* Disable hw prefetching */
+			wrmsr (MSR_IA32_MISC_ENABLE, lo, hi);
+		}
+	}
+
+	/*
+	 * See if we have a good local APIC by checking for buggy Pentia,
+	 * i.e. all B steppings and the C2 stepping of P54C when using their
+	 * integrated APIC (see 11AP erratum in "Pentium Processor
+	 * Specification Update").
+	 */
+	if (cpu_has_apic && (c->x86<<8 | c->x86_model<<4) == 0x520 &&
+	    (c->x86_mask < 0x6 || c->x86_mask == 0xb))
+		set_cpu_cap(c, X86_FEATURE_11AP);
+
+
+#ifdef CONFIG_X86_INTEL_USERCOPY
+	/*
+	 * Set up the preferred alignment for movsl bulk memory moves
+	 */
+	switch (c->x86) {
+	case 4:		/* 486: untested */
+		break;
+	case 5:		/* Old Pentia: untested */
+		break;
+	case 6:		/* PII/PIII only like movsl with 8-byte alignment */
+		movsl_mask.mask = 7;
+		break;
+	case 15:	/* P4 is OK down to 8-byte alignment */
+		movsl_mask.mask = 7;
+		break;
+	}
+#endif
+
+#ifdef CONFIG_X86_NUMAQ
+	numaq_tsc_disable();
+#endif
+}
+#else
+static void __cpuinit intel_workarounds(struct cpuinfo_x86 *c)
+{
+}
+#endif
+
+static void __cpuinit srat_detect_node(void)
+{
+#if defined(CONFIG_NUMA) && defined(CONFIG_X86_64)
+	unsigned node;
+	int cpu = smp_processor_id();
+	int apicid = hard_smp_processor_id();
+
+	/* Don't do the funky fallback heuristics the AMD version employs
+	   for now. */
+	node = apicid_to_node[apicid];
+	if (node == NUMA_NO_NODE || !node_online(node))
+		node = first_node(node_online_map);
+	numa_set_node(cpu, node);
+
+	printk(KERN_INFO "CPU %d/%x -> Node %d\n", cpu, apicid, node);
+#endif
+}
+
+/*
+ * find out the number of processor cores on the die
+ */
+static int __cpuinit intel_num_cpu_cores(struct cpuinfo_x86 *c)
+{
+	unsigned int eax, ebx, ecx, edx;
+
+	if (c->cpuid_level < 4)
+		return 1;
+
+	/* Intel has a non-standard dependency on %ecx for this CPUID level. */
+	cpuid_count(4, 0, &eax, &ebx, &ecx, &edx);
+	if (eax & 0x1f)
+		return ((eax >> 26) + 1);
+	else
+		return 1;
+}
+
+static void __cpuinit detect_vmx_virtcap(struct cpuinfo_x86 *c)
+{
+	/* Intel VMX MSR indicated features */
+#define X86_VMX_FEATURE_PROC_CTLS_TPR_SHADOW	0x00200000
+#define X86_VMX_FEATURE_PROC_CTLS_VNMI		0x00400000
+#define X86_VMX_FEATURE_PROC_CTLS_2ND_CTLS	0x80000000
+#define X86_VMX_FEATURE_PROC_CTLS2_VIRT_APIC	0x00000001
+#define X86_VMX_FEATURE_PROC_CTLS2_EPT		0x00000002
+#define X86_VMX_FEATURE_PROC_CTLS2_VPID		0x00000020
+
+	u32 vmx_msr_low, vmx_msr_high, msr_ctl, msr_ctl2;
+
+	clear_cpu_cap(c, X86_FEATURE_TPR_SHADOW);
+	clear_cpu_cap(c, X86_FEATURE_VNMI);
+	clear_cpu_cap(c, X86_FEATURE_FLEXPRIORITY);
+	clear_cpu_cap(c, X86_FEATURE_EPT);
+	clear_cpu_cap(c, X86_FEATURE_VPID);
+
+	rdmsr(MSR_IA32_VMX_PROCBASED_CTLS, vmx_msr_low, vmx_msr_high);
+	msr_ctl = vmx_msr_high | vmx_msr_low;
+	if (msr_ctl & X86_VMX_FEATURE_PROC_CTLS_TPR_SHADOW)
+		set_cpu_cap(c, X86_FEATURE_TPR_SHADOW);
+	if (msr_ctl & X86_VMX_FEATURE_PROC_CTLS_VNMI)
+		set_cpu_cap(c, X86_FEATURE_VNMI);
+	if (msr_ctl & X86_VMX_FEATURE_PROC_CTLS_2ND_CTLS) {
+		rdmsr(MSR_IA32_VMX_PROCBASED_CTLS2,
+		      vmx_msr_low, vmx_msr_high);
+		msr_ctl2 = vmx_msr_high | vmx_msr_low;
+		if ((msr_ctl2 & X86_VMX_FEATURE_PROC_CTLS2_VIRT_APIC) &&
+		    (msr_ctl & X86_VMX_FEATURE_PROC_CTLS_TPR_SHADOW))
+			set_cpu_cap(c, X86_FEATURE_FLEXPRIORITY);
+		if (msr_ctl2 & X86_VMX_FEATURE_PROC_CTLS2_EPT)
+			set_cpu_cap(c, X86_FEATURE_EPT);
+		if (msr_ctl2 & X86_VMX_FEATURE_PROC_CTLS2_VPID)
+			set_cpu_cap(c, X86_FEATURE_VPID);
+	}
+}
+
+static void __cpuinit init_intel(struct cpuinfo_x86 *c)
+{
+	unsigned int l2 = 0;
+
+	early_init_intel(c);
+
+	intel_workarounds(c);
+
 	l2 = init_intel_cacheinfo(c);
 	if (c->cpuid_level > 9) {
 		unsigned eax = cpuid_eax(10);
@@ -146,16 +250,32 @@
 			set_cpu_cap(c, X86_FEATURE_ARCH_PERFMON);
 	}
 
-	/* SEP CPUID bug: Pentium Pro reports SEP but doesn't have it until model 3 mask 3 */
-	if ((c->x86<<8 | c->x86_model<<4 | c->x86_mask) < 0x633)
-		clear_cpu_cap(c, X86_FEATURE_SEP);
+	if (cpu_has_xmm2)
+		set_cpu_cap(c, X86_FEATURE_LFENCE_RDTSC);
+	if (cpu_has_ds) {
+		unsigned int l1;
+		rdmsr(MSR_IA32_MISC_ENABLE, l1, l2);
+		if (!(l1 & (1<<11)))
+			set_cpu_cap(c, X86_FEATURE_BTS);
+		if (!(l1 & (1<<12)))
+			set_cpu_cap(c, X86_FEATURE_PEBS);
+		ds_init_intel(c);
+	}
 
+#ifdef CONFIG_X86_64
+	if (c->x86 == 15)
+		c->x86_cache_alignment = c->x86_clflush_size * 2;
+	if (c->x86 == 6)
+		set_cpu_cap(c, X86_FEATURE_REP_GOOD);
+#else
 	/*
 	 * Names for the Pentium II/Celeron processors
 	 * detectable only by also checking the cache size.
 	 * Dixon is NOT a Celeron.
 	 */
 	if (c->x86 == 6) {
+		char *p = NULL;
+
 		switch (c->x86_model) {
 		case 5:
 			if (c->x86_mask == 0) {
@@ -178,70 +298,41 @@
 				p = "Celeron (Coppermine)";
 			break;
 		}
+
+		if (p)
+			strcpy(c->x86_model_id, p);
 	}
 
-	if (p)
-		strcpy(c->x86_model_id, p);
-
-	c->x86_max_cores = num_cpu_cores(c);
-
-	detect_ht(c);
-
-	/* Work around errata */
-	Intel_errata_workarounds(c);
-
-#ifdef CONFIG_X86_INTEL_USERCOPY
-	/*
-	 * Set up the preferred alignment for movsl bulk memory moves
-	 */
-	switch (c->x86) {
-	case 4:		/* 486: untested */
-		break;
-	case 5:		/* Old Pentia: untested */
-		break;
-	case 6:		/* PII/PIII only like movsl with 8-byte alignment */
-		movsl_mask.mask = 7;
-		break;
-	case 15:	/* P4 is OK down to 8-byte alignment */
-		movsl_mask.mask = 7;
-		break;
-	}
-#endif
-
-	if (cpu_has_xmm2)
-		set_cpu_cap(c, X86_FEATURE_LFENCE_RDTSC);
-	if (c->x86 == 15) {
+	if (c->x86 == 15)
 		set_cpu_cap(c, X86_FEATURE_P4);
-	}
 	if (c->x86 == 6)
 		set_cpu_cap(c, X86_FEATURE_P3);
-	if (cpu_has_ds) {
-		unsigned int l1;
-		rdmsr(MSR_IA32_MISC_ENABLE, l1, l2);
-		if (!(l1 & (1<<11)))
-			set_cpu_cap(c, X86_FEATURE_BTS);
-		if (!(l1 & (1<<12)))
-			set_cpu_cap(c, X86_FEATURE_PEBS);
-	}
 
 	if (cpu_has_bts)
-		ds_init_intel(c);
+		ptrace_bts_init_intel(c);
 
-	/*
-	 * See if we have a good local APIC by checking for buggy Pentia,
-	 * i.e. all B steppings and the C2 stepping of P54C when using their
-	 * integrated APIC (see 11AP erratum in "Pentium Processor
-	 * Specification Update").
-	 */
-	if (cpu_has_apic && (c->x86<<8 | c->x86_model<<4) == 0x520 &&
-	    (c->x86_mask < 0x6 || c->x86_mask == 0xb))
-		set_cpu_cap(c, X86_FEATURE_11AP);
-
-#ifdef CONFIG_X86_NUMAQ
-	numaq_tsc_disable();
 #endif
+
+	detect_extended_topology(c);
+	if (!cpu_has(c, X86_FEATURE_XTOPOLOGY)) {
+		/*
+		 * let's use the legacy cpuid vector 0x1 and 0x4 for topology
+		 * detection.
+		 */
+		c->x86_max_cores = intel_num_cpu_cores(c);
+#ifdef CONFIG_X86_32
+		detect_ht(c);
+#endif
+	}
+
+	/* Work around errata */
+	srat_detect_node();
+
+	if (cpu_has(c, X86_FEATURE_VMX))
+		detect_vmx_virtcap(c);
 }
 
+#ifdef CONFIG_X86_32
 static unsigned int __cpuinit intel_size_cache(struct cpuinfo_x86 *c, unsigned int size)
 {
 	/*
@@ -254,10 +345,12 @@
 		size = 256;
 	return size;
 }
+#endif
 
 static struct cpu_dev intel_cpu_dev __cpuinitdata = {
 	.c_vendor	= "Intel",
 	.c_ident	= { "GenuineIntel" },
+#ifdef CONFIG_X86_32
 	.c_models = {
 		{ .vendor = X86_VENDOR_INTEL, .family = 4, .model_names =
 		  {
@@ -307,76 +400,12 @@
 		  }
 		},
 	},
+	.c_size_cache	= intel_size_cache,
+#endif
 	.c_early_init   = early_init_intel,
 	.c_init		= init_intel,
-	.c_size_cache	= intel_size_cache,
+	.c_x86_vendor	= X86_VENDOR_INTEL,
 };
 
-cpu_vendor_dev_register(X86_VENDOR_INTEL, &intel_cpu_dev);
-
-#ifndef CONFIG_X86_CMPXCHG
-unsigned long cmpxchg_386_u8(volatile void *ptr, u8 old, u8 new)
-{
-	u8 prev;
-	unsigned long flags;
-
-	/* Poor man's cmpxchg for 386. Unsuitable for SMP */
-	local_irq_save(flags);
-	prev = *(u8 *)ptr;
-	if (prev == old)
-		*(u8 *)ptr = new;
-	local_irq_restore(flags);
-	return prev;
-}
-EXPORT_SYMBOL(cmpxchg_386_u8);
-
-unsigned long cmpxchg_386_u16(volatile void *ptr, u16 old, u16 new)
-{
-	u16 prev;
-	unsigned long flags;
-
-	/* Poor man's cmpxchg for 386. Unsuitable for SMP */
-	local_irq_save(flags);
-	prev = *(u16 *)ptr;
-	if (prev == old)
-		*(u16 *)ptr = new;
-	local_irq_restore(flags);
-	return prev;
-}
-EXPORT_SYMBOL(cmpxchg_386_u16);
-
-unsigned long cmpxchg_386_u32(volatile void *ptr, u32 old, u32 new)
-{
-	u32 prev;
-	unsigned long flags;
-
-	/* Poor man's cmpxchg for 386. Unsuitable for SMP */
-	local_irq_save(flags);
-	prev = *(u32 *)ptr;
-	if (prev == old)
-		*(u32 *)ptr = new;
-	local_irq_restore(flags);
-	return prev;
-}
-EXPORT_SYMBOL(cmpxchg_386_u32);
-#endif
-
-#ifndef CONFIG_X86_CMPXCHG64
-unsigned long long cmpxchg_486_u64(volatile void *ptr, u64 old, u64 new)
-{
-	u64 prev;
-	unsigned long flags;
-
-	/* Poor man's cmpxchg8b for 386 and 486. Unsuitable for SMP */
-	local_irq_save(flags);
-	prev = *(u64 *)ptr;
-	if (prev == old)
-		*(u64 *)ptr = new;
-	local_irq_restore(flags);
-	return prev;
-}
-EXPORT_SYMBOL(cmpxchg_486_u64);
-#endif
-
-/* arch_initcall(intel_cpu_init); */
+cpu_dev_register(intel_cpu_dev);
 
diff --git a/arch/x86/kernel/cpu/intel_64.c b/arch/x86/kernel/cpu/intel_64.c
deleted file mode 100644
index 1019c58..0000000
--- a/arch/x86/kernel/cpu/intel_64.c
+++ /dev/null
@@ -1,95 +0,0 @@
-#include <linux/init.h>
-#include <linux/smp.h>
-#include <asm/processor.h>
-#include <asm/ptrace.h>
-#include <asm/topology.h>
-#include <asm/numa_64.h>
-
-#include "cpu.h"
-
-static void __cpuinit early_init_intel(struct cpuinfo_x86 *c)
-{
-	if ((c->x86 == 0xf && c->x86_model >= 0x03) ||
-	    (c->x86 == 0x6 && c->x86_model >= 0x0e))
-		set_cpu_cap(c, X86_FEATURE_CONSTANT_TSC);
-
-	set_cpu_cap(c, X86_FEATURE_SYSENTER32);
-}
-
-/*
- * find out the number of processor cores on the die
- */
-static int __cpuinit intel_num_cpu_cores(struct cpuinfo_x86 *c)
-{
-	unsigned int eax, t;
-
-	if (c->cpuid_level < 4)
-		return 1;
-
-	cpuid_count(4, 0, &eax, &t, &t, &t);
-
-	if (eax & 0x1f)
-		return ((eax >> 26) + 1);
-	else
-		return 1;
-}
-
-static void __cpuinit srat_detect_node(void)
-{
-#ifdef CONFIG_NUMA
-	unsigned node;
-	int cpu = smp_processor_id();
-	int apicid = hard_smp_processor_id();
-
-	/* Don't do the funky fallback heuristics the AMD version employs
-	   for now. */
-	node = apicid_to_node[apicid];
-	if (node == NUMA_NO_NODE || !node_online(node))
-		node = first_node(node_online_map);
-	numa_set_node(cpu, node);
-
-	printk(KERN_INFO "CPU %d/%x -> Node %d\n", cpu, apicid, node);
-#endif
-}
-
-static void __cpuinit init_intel(struct cpuinfo_x86 *c)
-{
-	init_intel_cacheinfo(c);
-	if (c->cpuid_level > 9) {
-		unsigned eax = cpuid_eax(10);
-		/* Check for version and the number of counters */
-		if ((eax & 0xff) && (((eax>>8) & 0xff) > 1))
-			set_cpu_cap(c, X86_FEATURE_ARCH_PERFMON);
-	}
-
-	if (cpu_has_ds) {
-		unsigned int l1, l2;
-		rdmsr(MSR_IA32_MISC_ENABLE, l1, l2);
-		if (!(l1 & (1<<11)))
-			set_cpu_cap(c, X86_FEATURE_BTS);
-		if (!(l1 & (1<<12)))
-			set_cpu_cap(c, X86_FEATURE_PEBS);
-	}
-
-
-	if (cpu_has_bts)
-		ds_init_intel(c);
-
-	if (c->x86 == 15)
-		c->x86_cache_alignment = c->x86_clflush_size * 2;
-	if (c->x86 == 6)
-		set_cpu_cap(c, X86_FEATURE_REP_GOOD);
-	set_cpu_cap(c, X86_FEATURE_LFENCE_RDTSC);
-	c->x86_max_cores = intel_num_cpu_cores(c);
-
-	srat_detect_node();
-}
-
-static struct cpu_dev intel_cpu_dev __cpuinitdata = {
-	.c_vendor	= "Intel",
-	.c_ident	= { "GenuineIntel" },
-	.c_early_init   = early_init_intel,
-	.c_init		= init_intel,
-};
-cpu_vendor_dev_register(X86_VENDOR_INTEL, &intel_cpu_dev);
-
diff --git a/arch/x86/kernel/cpu/intel_cacheinfo.c b/arch/x86/kernel/cpu/intel_cacheinfo.c
index 6b0a10b..3f46afb 100644
--- a/arch/x86/kernel/cpu/intel_cacheinfo.c
+++ b/arch/x86/kernel/cpu/intel_cacheinfo.c
@@ -1,8 +1,8 @@
 /*
- *      Routines to indentify caches on Intel CPU.
+ *	Routines to indentify caches on Intel CPU.
  *
- *      Changes:
- *      Venkatesh Pallipadi	: Adding cache identification through cpuid(4)
+ *	Changes:
+ *	Venkatesh Pallipadi	: Adding cache identification through cpuid(4)
  *		Ashok Raj <ashok.raj@intel.com>: Work with CPU hotplug infrastructure.
  *	Andi Kleen / Andreas Herrmann	: CPUID4 emulation on AMD.
  */
@@ -13,6 +13,7 @@
 #include <linux/compiler.h>
 #include <linux/cpu.h>
 #include <linux/sched.h>
+#include <linux/pci.h>
 
 #include <asm/processor.h>
 #include <asm/smp.h>
@@ -130,9 +131,18 @@
 	union _cpuid4_leaf_ebx ebx;
 	union _cpuid4_leaf_ecx ecx;
 	unsigned long size;
+	unsigned long can_disable;
 	cpumask_t shared_cpu_map;	/* future?: only cpus/node is needed */
 };
 
+#ifdef CONFIG_PCI
+static struct pci_device_id k8_nb_id[] = {
+	{ PCI_DEVICE(PCI_VENDOR_ID_AMD, 0x1103) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_AMD, 0x1203) },
+	{}
+};
+#endif
+
 unsigned short			num_cache_leaves;
 
 /* AMD doesn't have CPUID4. Emulate it here to report the same
@@ -182,9 +192,10 @@
 static unsigned char levels[] __cpuinitdata = { 1, 1, 2, 3 };
 static unsigned char types[] __cpuinitdata = { 1, 2, 3, 3 };
 
-static void __cpuinit amd_cpuid4(int leaf, union _cpuid4_leaf_eax *eax,
-		       union _cpuid4_leaf_ebx *ebx,
-		       union _cpuid4_leaf_ecx *ecx)
+static void __cpuinit
+amd_cpuid4(int leaf, union _cpuid4_leaf_eax *eax,
+		     union _cpuid4_leaf_ebx *ebx,
+		     union _cpuid4_leaf_ecx *ecx)
 {
 	unsigned dummy;
 	unsigned line_size, lines_per_tag, assoc, size_in_kb;
@@ -251,27 +262,40 @@
 		(ebx->split.ways_of_associativity + 1) - 1;
 }
 
-static int __cpuinit cpuid4_cache_lookup(int index, struct _cpuid4_info *this_leaf)
+static void __cpuinit
+amd_check_l3_disable(int index, struct _cpuid4_info *this_leaf)
+{
+	if (index < 3)
+		return;
+	this_leaf->can_disable = 1;
+}
+
+static int
+__cpuinit cpuid4_cache_lookup(int index, struct _cpuid4_info *this_leaf)
 {
 	union _cpuid4_leaf_eax 	eax;
 	union _cpuid4_leaf_ebx 	ebx;
 	union _cpuid4_leaf_ecx 	ecx;
 	unsigned		edx;
 
-	if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD)
+	if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD) {
 		amd_cpuid4(index, &eax, &ebx, &ecx);
-	else
-		cpuid_count(4, index, &eax.full, &ebx.full, &ecx.full,  &edx);
+		if (boot_cpu_data.x86 >= 0x10)
+			amd_check_l3_disable(index, this_leaf);
+	} else {
+		cpuid_count(4, index, &eax.full, &ebx.full, &ecx.full, &edx);
+	}
+
 	if (eax.split.type == CACHE_TYPE_NULL)
 		return -EIO; /* better error ? */
 
 	this_leaf->eax = eax;
 	this_leaf->ebx = ebx;
 	this_leaf->ecx = ecx;
-	this_leaf->size = (ecx.split.number_of_sets + 1) *
-		(ebx.split.coherency_line_size + 1) *
-		(ebx.split.physical_line_partition + 1) *
-		(ebx.split.ways_of_associativity + 1);
+	this_leaf->size = (ecx.split.number_of_sets          + 1) *
+			  (ebx.split.coherency_line_size     + 1) *
+			  (ebx.split.physical_line_partition + 1) *
+			  (ebx.split.ways_of_associativity   + 1);
 	return 0;
 }
 
@@ -453,7 +477,7 @@
 
 /* pointer to _cpuid4_info array (for each cache leaf) */
 static DEFINE_PER_CPU(struct _cpuid4_info *, cpuid4_info);
-#define CPUID4_INFO_IDX(x, y)    (&((per_cpu(cpuid4_info, x))[y]))
+#define CPUID4_INFO_IDX(x, y)	(&((per_cpu(cpuid4_info, x))[y]))
 
 #ifdef CONFIG_SMP
 static void __cpuinit cache_shared_cpu_map_setup(unsigned int cpu, int index)
@@ -490,7 +514,7 @@
 
 	this_leaf = CPUID4_INFO_IDX(cpu, index);
 	for_each_cpu_mask_nr(sibling, this_leaf->shared_cpu_map) {
-		sibling_leaf = CPUID4_INFO_IDX(sibling, index);	
+		sibling_leaf = CPUID4_INFO_IDX(sibling, index);
 		cpu_clear(cpu, sibling_leaf->shared_cpu_map);
 	}
 }
@@ -572,7 +596,7 @@
 
 /* pointer to array of kobjects for cpuX/cache/indexY */
 static DEFINE_PER_CPU(struct _index_kobject *, index_kobject);
-#define INDEX_KOBJECT_PTR(x, y)    (&((per_cpu(index_kobject, x))[y]))
+#define INDEX_KOBJECT_PTR(x, y)		(&((per_cpu(index_kobject, x))[y]))
 
 #define show_one_plus(file_name, object, val)				\
 static ssize_t show_##file_name						\
@@ -637,6 +661,99 @@
 	}
 }
 
+#define to_object(k)	container_of(k, struct _index_kobject, kobj)
+#define to_attr(a)	container_of(a, struct _cache_attr, attr)
+
+#ifdef CONFIG_PCI
+static struct pci_dev *get_k8_northbridge(int node)
+{
+	struct pci_dev *dev = NULL;
+	int i;
+
+	for (i = 0; i <= node; i++) {
+		do {
+			dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev);
+			if (!dev)
+				break;
+		} while (!pci_match_id(&k8_nb_id[0], dev));
+		if (!dev)
+			break;
+	}
+	return dev;
+}
+#else
+static struct pci_dev *get_k8_northbridge(int node)
+{
+	return NULL;
+}
+#endif
+
+static ssize_t show_cache_disable(struct _cpuid4_info *this_leaf, char *buf)
+{
+	int node = cpu_to_node(first_cpu(this_leaf->shared_cpu_map));
+	struct pci_dev *dev = NULL;
+	ssize_t ret = 0;
+	int i;
+
+	if (!this_leaf->can_disable)
+		return sprintf(buf, "Feature not enabled\n");
+
+	dev = get_k8_northbridge(node);
+	if (!dev) {
+		printk(KERN_ERR "Attempting AMD northbridge operation on a system with no northbridge\n");
+		return -EINVAL;
+	}
+
+	for (i = 0; i < 2; i++) {
+		unsigned int reg;
+
+		pci_read_config_dword(dev, 0x1BC + i * 4, &reg);
+
+		ret += sprintf(buf, "%sEntry: %d\n", buf, i);
+		ret += sprintf(buf, "%sReads:  %s\tNew Entries: %s\n",  
+			buf,
+			reg & 0x80000000 ? "Disabled" : "Allowed",
+			reg & 0x40000000 ? "Disabled" : "Allowed");
+		ret += sprintf(buf, "%sSubCache: %x\tIndex: %x\n",
+			buf, (reg & 0x30000) >> 16, reg & 0xfff);
+	}
+	return ret;
+}
+
+static ssize_t
+store_cache_disable(struct _cpuid4_info *this_leaf, const char *buf,
+		    size_t count)
+{
+	int node = cpu_to_node(first_cpu(this_leaf->shared_cpu_map));
+	struct pci_dev *dev = NULL;
+	unsigned int ret, index, val;
+
+	if (!this_leaf->can_disable)
+		return 0;
+
+	if (strlen(buf) > 15)
+		return -EINVAL;
+
+	ret = sscanf(buf, "%x %x", &index, &val);
+	if (ret != 2)
+		return -EINVAL;
+	if (index > 1)
+		return -EINVAL;
+
+	val |= 0xc0000000;
+	dev = get_k8_northbridge(node);
+	if (!dev) {
+		printk(KERN_ERR "Attempting AMD northbridge operation on a system with no northbridge\n");
+		return -EINVAL;
+	}
+
+	pci_write_config_dword(dev, 0x1BC + index * 4, val & ~0x40000000);
+	wbinvd();
+	pci_write_config_dword(dev, 0x1BC + index * 4, val);
+
+	return 1;
+}
+
 struct _cache_attr {
 	struct attribute attr;
 	ssize_t (*show)(struct _cpuid4_info *, char *);
@@ -657,6 +774,8 @@
 define_one_ro(shared_cpu_map);
 define_one_ro(shared_cpu_list);
 
+static struct _cache_attr cache_disable = __ATTR(cache_disable, 0644, show_cache_disable, store_cache_disable);
+
 static struct attribute * default_attrs[] = {
 	&type.attr,
 	&level.attr,
@@ -667,12 +786,10 @@
 	&size.attr,
 	&shared_cpu_map.attr,
 	&shared_cpu_list.attr,
+	&cache_disable.attr,
 	NULL
 };
 
-#define to_object(k) container_of(k, struct _index_kobject, kobj)
-#define to_attr(a) container_of(a, struct _cache_attr, attr)
-
 static ssize_t show(struct kobject * kobj, struct attribute * attr, char * buf)
 {
 	struct _cache_attr *fattr = to_attr(attr);
@@ -682,14 +799,22 @@
 	ret = fattr->show ?
 		fattr->show(CPUID4_INFO_IDX(this_leaf->cpu, this_leaf->index),
 			buf) :
-	       	0;
+		0;
 	return ret;
 }
 
 static ssize_t store(struct kobject * kobj, struct attribute * attr,
 		     const char * buf, size_t count)
 {
-	return 0;
+	struct _cache_attr *fattr = to_attr(attr);
+	struct _index_kobject *this_leaf = to_object(kobj);
+	ssize_t ret;
+
+	ret = fattr->store ?
+		fattr->store(CPUID4_INFO_IDX(this_leaf->cpu, this_leaf->index),
+			buf, count) :
+		0;
+	return ret;
 }
 
 static struct sysfs_ops sysfs_ops = {
diff --git a/arch/x86/kernel/cpu/mcheck/mce_64.c b/arch/x86/kernel/cpu/mcheck/mce_64.c
index 726a5fc..4b031a4 100644
--- a/arch/x86/kernel/cpu/mcheck/mce_64.c
+++ b/arch/x86/kernel/cpu/mcheck/mce_64.c
@@ -860,7 +860,7 @@
 	return err;
 }
 
-static void mce_remove_device(unsigned int cpu)
+static __cpuinit void mce_remove_device(unsigned int cpu)
 {
 	int i;
 
diff --git a/arch/x86/kernel/cpu/mkcapflags.pl b/arch/x86/kernel/cpu/mkcapflags.pl
new file mode 100644
index 0000000..dfea390
--- /dev/null
+++ b/arch/x86/kernel/cpu/mkcapflags.pl
@@ -0,0 +1,32 @@
+#!/usr/bin/perl
+#
+# Generate the x86_cap_flags[] array from include/asm-x86/cpufeature.h
+#
+
+($in, $out) = @ARGV;
+
+open(IN, "< $in\0")   or die "$0: cannot open: $in: $!\n";
+open(OUT, "> $out\0") or die "$0: cannot create: $out: $!\n";
+
+print OUT "#include <asm/cpufeature.h>\n\n";
+print OUT "const char * const x86_cap_flags[NCAPINTS*32] = {\n";
+
+while (defined($line = <IN>)) {
+	if ($line =~ /^\s*\#\s*define\s+(X86_FEATURE_(\S+))\s+(.*)$/) {
+		$macro = $1;
+		$feature = $2;
+		$tail = $3;
+		if ($tail =~ /\/\*\s*\"([^"]*)\".*\*\//) {
+			$feature = $1;
+		}
+
+		if ($feature ne '') {
+			printf OUT "\t%-32s = \"%s\",\n",
+				"[$macro]", "\L$feature";
+		}
+	}
+}
+print OUT "};\n";
+
+close(IN);
+close(OUT);
diff --git a/arch/x86/kernel/cpu/mtrr/generic.c b/arch/x86/kernel/cpu/mtrr/generic.c
index cb7d3b6..4e8d77f 100644
--- a/arch/x86/kernel/cpu/mtrr/generic.c
+++ b/arch/x86/kernel/cpu/mtrr/generic.c
@@ -401,12 +401,7 @@
 		tmp |= ~((1<<(hi - 1)) - 1);
 
 		if (tmp != mask_lo) {
-			static int once = 1;
-
-			if (once) {
-				printk(KERN_INFO "mtrr: your BIOS has set up an incorrect mask, fixing it up.\n");
-				once = 0;
-			}
+			WARN_ONCE(1, KERN_INFO "mtrr: your BIOS has set up an incorrect mask, fixing it up.\n");
 			mask_lo = tmp;
 		}
 	}
diff --git a/arch/x86/kernel/cpu/mtrr/if.c b/arch/x86/kernel/cpu/mtrr/if.c
index 84c480b..4c42146 100644
--- a/arch/x86/kernel/cpu/mtrr/if.c
+++ b/arch/x86/kernel/cpu/mtrr/if.c
@@ -405,9 +405,9 @@
 			}
 			/* RED-PEN: base can be > 32bit */ 
 			len += seq_printf(seq, 
-				   "reg%02i: base=0x%05lx000 (%4luMB), size=%4lu%cB: %s, count=%d\n",
+				   "reg%02i: base=0x%06lx000 (%5luMB), size=%5lu%cB, count=%d: %s\n",
 			     i, base, base >> (20 - PAGE_SHIFT), size, factor,
-			     mtrr_attrib_to_str(type), mtrr_usage_table[i]);
+			     mtrr_usage_table[i], mtrr_attrib_to_str(type));
 		}
 	}
 	return 0;
diff --git a/arch/x86/kernel/cpu/mtrr/main.c b/arch/x86/kernel/cpu/mtrr/main.c
index b117d7f..c78c048 100644
--- a/arch/x86/kernel/cpu/mtrr/main.c
+++ b/arch/x86/kernel/cpu/mtrr/main.c
@@ -729,7 +729,7 @@
 	mtrr_type type;
 };
 
-struct var_mtrr_range_state __initdata range_state[RANGE_NUM];
+static struct var_mtrr_range_state __initdata range_state[RANGE_NUM];
 static int __initdata debug_print;
 
 static int __init
@@ -759,7 +759,8 @@
 	/* take out UC ranges */
 	for (i = 0; i < num_var_ranges; i++) {
 		type = range_state[i].type;
-		if (type != MTRR_TYPE_UNCACHABLE)
+		if (type != MTRR_TYPE_UNCACHABLE &&
+		    type != MTRR_TYPE_WRPROT)
 			continue;
 		size = range_state[i].size_pfn;
 		if (!size)
@@ -834,7 +835,14 @@
 		enable_mtrr_cleanup = 1;
 	return 0;
 }
-early_param("enble_mtrr_cleanup", enable_mtrr_cleanup_setup);
+early_param("enable_mtrr_cleanup", enable_mtrr_cleanup_setup);
+
+static int __init mtrr_cleanup_debug_setup(char *str)
+{
+	debug_print = 1;
+	return 0;
+}
+early_param("mtrr_cleanup_debug", mtrr_cleanup_debug_setup);
 
 struct var_mtrr_state {
 	unsigned long	range_startk;
@@ -898,6 +906,27 @@
 	}
 }
 
+static unsigned long to_size_factor(unsigned long sizek, char *factorp)
+{
+	char factor;
+	unsigned long base = sizek;
+
+	if (base & ((1<<10) - 1)) {
+		/* not MB alignment */
+		factor = 'K';
+	} else if (base & ((1<<20) - 1)){
+		factor = 'M';
+		base >>= 10;
+	} else {
+		factor = 'G';
+		base >>= 20;
+	}
+
+	*factorp = factor;
+
+	return base;
+}
+
 static unsigned int __init
 range_to_mtrr(unsigned int reg, unsigned long range_startk,
 	      unsigned long range_sizek, unsigned char type)
@@ -919,13 +948,21 @@
 			align = max_align;
 
 		sizek = 1 << align;
-		if (debug_print)
+		if (debug_print) {
+			char start_factor = 'K', size_factor = 'K';
+			unsigned long start_base, size_base;
+
+			start_base = to_size_factor(range_startk, &start_factor),
+			size_base = to_size_factor(sizek, &size_factor),
+
 			printk(KERN_DEBUG "Setting variable MTRR %d, "
-				"base: %ldMB, range: %ldMB, type %s\n",
-				reg, range_startk >> 10, sizek >> 10,
+				"base: %ld%cB, range: %ld%cB, type %s\n",
+				reg, start_base, start_factor,
+				size_base, size_factor,
 				(type == MTRR_TYPE_UNCACHABLE)?"UC":
 				    ((type == MTRR_TYPE_WRBACK)?"WB":"Other")
 				);
+		}
 		save_var_mtrr(reg++, range_startk, sizek, type);
 		range_startk += sizek;
 		range_sizek -= sizek;
@@ -970,6 +1007,8 @@
 	/* try to append some small hole */
 	range0_basek = state->range_startk;
 	range0_sizek = ALIGN(state->range_sizek, chunk_sizek);
+
+	/* no increase */
 	if (range0_sizek == state->range_sizek) {
 		if (debug_print)
 			printk(KERN_DEBUG "rangeX: %016lx - %016lx\n",
@@ -980,13 +1019,40 @@
 		return 0;
 	}
 
-	range0_sizek -= chunk_sizek;
-	if (range0_sizek && sizek) {
-	    while (range0_basek + range0_sizek > (basek + sizek)) {
-		range0_sizek -= chunk_sizek;
-		if (!range0_sizek)
-			break;
-	    }
+	/* only cut back, when it is not the last */
+	if (sizek) {
+		while (range0_basek + range0_sizek > (basek + sizek)) {
+			if (range0_sizek >= chunk_sizek)
+				range0_sizek -= chunk_sizek;
+			else
+				range0_sizek = 0;
+
+			if (!range0_sizek)
+				break;
+		}
+	}
+
+second_try:
+	range_basek = range0_basek + range0_sizek;
+
+	/* one hole in the middle */
+	if (range_basek > basek && range_basek <= (basek + sizek))
+		second_sizek = range_basek - basek;
+
+	if (range0_sizek > state->range_sizek) {
+
+		/* one hole in middle or at end */
+		hole_sizek = range0_sizek - state->range_sizek - second_sizek;
+
+		/* hole size should be less than half of range0 size */
+		if (hole_sizek >= (range0_sizek >> 1) &&
+		    range0_sizek >= chunk_sizek) {
+			range0_sizek -= chunk_sizek;
+			second_sizek = 0;
+			hole_sizek = 0;
+
+			goto second_try;
+		}
 	}
 
 	if (range0_sizek) {
@@ -996,50 +1062,28 @@
 				(range0_basek + range0_sizek)<<10);
 		state->reg = range_to_mtrr(state->reg, range0_basek,
 				range0_sizek, MTRR_TYPE_WRBACK);
-
 	}
 
-	range_basek = range0_basek + range0_sizek;
-	range_sizek = chunk_sizek;
-
-	if (range_basek + range_sizek > basek &&
-	    range_basek + range_sizek <= (basek + sizek)) {
-		/* one hole */
-		second_basek = basek;
-		second_sizek = range_basek + range_sizek - basek;
-	}
-
-	/* if last piece, only could one hole near end */
-	if ((second_basek || !basek) &&
-	    range_sizek - (state->range_sizek - range0_sizek) - second_sizek <
-	    (chunk_sizek >> 1)) {
-		/*
-		 * one hole in middle (second_sizek is 0) or at end
-		 * (second_sizek is 0 )
-		 */
-		hole_sizek = range_sizek - (state->range_sizek - range0_sizek)
-				 - second_sizek;
-		hole_basek = range_basek + range_sizek - hole_sizek
-				 - second_sizek;
-	} else {
-		/* fallback for big hole, or several holes */
+	if (range0_sizek < state->range_sizek) {
+		/* need to handle left over */
 		range_sizek = state->range_sizek - range0_sizek;
-		second_basek = 0;
-		second_sizek = 0;
+
+		if (debug_print)
+			printk(KERN_DEBUG "range: %016lx - %016lx\n",
+				 range_basek<<10,
+				 (range_basek + range_sizek)<<10);
+		state->reg = range_to_mtrr(state->reg, range_basek,
+				 range_sizek, MTRR_TYPE_WRBACK);
 	}
 
-	if (debug_print)
-		printk(KERN_DEBUG "range: %016lx - %016lx\n", range_basek<<10,
-			 (range_basek + range_sizek)<<10);
-	state->reg = range_to_mtrr(state->reg, range_basek, range_sizek,
-					 MTRR_TYPE_WRBACK);
 	if (hole_sizek) {
+		hole_basek = range_basek - hole_sizek - second_sizek;
 		if (debug_print)
 			printk(KERN_DEBUG "hole: %016lx - %016lx\n",
-				 hole_basek<<10, (hole_basek + hole_sizek)<<10);
-		state->reg = range_to_mtrr(state->reg, hole_basek, hole_sizek,
-						 MTRR_TYPE_UNCACHABLE);
-
+				 hole_basek<<10,
+				 (hole_basek + hole_sizek)<<10);
+		state->reg = range_to_mtrr(state->reg, hole_basek,
+				 hole_sizek, MTRR_TYPE_UNCACHABLE);
 	}
 
 	return second_sizek;
@@ -1154,11 +1198,11 @@
 };
 
 /*
- * gran_size: 1M, 2M, ..., 2G
- * chunk size: gran_size, ..., 4G
- * so we need (2+13)*6
+ * gran_size: 64K, 128K, 256K, 512K, 1M, 2M, ..., 2G
+ * chunk size: gran_size, ..., 2G
+ * so we need (1+16)*8
  */
-#define NUM_RESULT	90
+#define NUM_RESULT	136
 #define PSHIFT		(PAGE_SHIFT - 10)
 
 static struct mtrr_cleanup_result __initdata result[NUM_RESULT];
@@ -1168,13 +1212,14 @@
 static int __init mtrr_cleanup(unsigned address_bits)
 {
 	unsigned long extra_remove_base, extra_remove_size;
-	unsigned long i, base, size, def, dummy;
+	unsigned long base, size, def, dummy;
 	mtrr_type type;
 	int nr_range, nr_range_new;
 	u64 chunk_size, gran_size;
 	unsigned long range_sums, range_sums_new;
 	int index_good;
 	int num_reg_good;
+	int i;
 
 	/* extra one for all 0 */
 	int num[MTRR_NUM_TYPES + 1];
@@ -1204,6 +1249,8 @@
 			continue;
 		if (!size)
 			type = MTRR_NUM_TYPES;
+		if (type == MTRR_TYPE_WRPROT)
+			type = MTRR_TYPE_UNCACHABLE;
 		num[type]++;
 	}
 
@@ -1216,23 +1263,57 @@
 		num_var_ranges - num[MTRR_NUM_TYPES])
 		return 0;
 
+	/* print original var MTRRs at first, for debugging: */
+	printk(KERN_DEBUG "original variable MTRRs\n");
+	for (i = 0; i < num_var_ranges; i++) {
+		char start_factor = 'K', size_factor = 'K';
+		unsigned long start_base, size_base;
+
+		size_base = range_state[i].size_pfn << (PAGE_SHIFT - 10);
+		if (!size_base)
+			continue;
+
+		size_base = to_size_factor(size_base, &size_factor),
+		start_base = range_state[i].base_pfn << (PAGE_SHIFT - 10);
+		start_base = to_size_factor(start_base, &start_factor),
+		type = range_state[i].type;
+
+		printk(KERN_DEBUG "reg %d, base: %ld%cB, range: %ld%cB, type %s\n",
+			i, start_base, start_factor,
+			size_base, size_factor,
+			(type == MTRR_TYPE_UNCACHABLE) ? "UC" :
+			    ((type == MTRR_TYPE_WRPROT) ? "WP" :
+			     ((type == MTRR_TYPE_WRBACK) ? "WB" : "Other"))
+			);
+	}
+
 	memset(range, 0, sizeof(range));
 	extra_remove_size = 0;
-	if (mtrr_tom2) {
-		extra_remove_base = 1 << (32 - PAGE_SHIFT);
+	extra_remove_base = 1 << (32 - PAGE_SHIFT);
+	if (mtrr_tom2)
 		extra_remove_size =
 			(mtrr_tom2 >> PAGE_SHIFT) - extra_remove_base;
-	}
 	nr_range = x86_get_mtrr_mem_range(range, 0, extra_remove_base,
 					  extra_remove_size);
+	/*
+	 * [0, 1M) should always be coverred by var mtrr with WB
+	 * and fixed mtrrs should take effective before var mtrr for it
+	 */
+	nr_range = add_range_with_merge(range, nr_range, 0,
+					(1ULL<<(20 - PAGE_SHIFT)) - 1);
+	/* sort the ranges */
+	sort(range, nr_range, sizeof(struct res_range), cmp_range, NULL);
+
 	range_sums = sum_ranges(range, nr_range);
 	printk(KERN_INFO "total RAM coverred: %ldM\n",
 	       range_sums >> (20 - PAGE_SHIFT));
 
 	if (mtrr_chunk_size && mtrr_gran_size) {
 		int num_reg;
+		char gran_factor, chunk_factor, lose_factor;
+		unsigned long gran_base, chunk_base, lose_base;
 
-		debug_print = 1;
+		debug_print++;
 		/* convert ranges to var ranges state */
 		num_reg = x86_setup_var_mtrrs(range, nr_range, mtrr_chunk_size,
 					      mtrr_gran_size);
@@ -1256,34 +1337,48 @@
 			result[i].lose_cover_sizek =
 				(range_sums - range_sums_new) << PSHIFT;
 
-		printk(KERN_INFO "%sgran_size: %ldM \tchunk_size: %ldM \t",
-			 result[i].bad?"*BAD*":" ", result[i].gran_sizek >> 10,
-			 result[i].chunk_sizek >> 10);
-		printk(KERN_CONT "num_reg: %d  \tlose cover RAM: %s%ldM \n",
+		gran_base = to_size_factor(result[i].gran_sizek, &gran_factor),
+		chunk_base = to_size_factor(result[i].chunk_sizek, &chunk_factor),
+		lose_base = to_size_factor(result[i].lose_cover_sizek, &lose_factor),
+		printk(KERN_INFO "%sgran_size: %ld%c \tchunk_size: %ld%c \t",
+			 result[i].bad?"*BAD*":" ",
+			 gran_base, gran_factor, chunk_base, chunk_factor);
+		printk(KERN_CONT "num_reg: %d  \tlose cover RAM: %s%ld%c\n",
 			 result[i].num_reg, result[i].bad?"-":"",
-			 result[i].lose_cover_sizek >> 10);
+			 lose_base, lose_factor);
 		if (!result[i].bad) {
 			set_var_mtrr_all(address_bits);
 			return 1;
 		}
 		printk(KERN_INFO "invalid mtrr_gran_size or mtrr_chunk_size, "
 		       "will find optimal one\n");
-		debug_print = 0;
+		debug_print--;
 		memset(result, 0, sizeof(result[0]));
 	}
 
 	i = 0;
 	memset(min_loss_pfn, 0xff, sizeof(min_loss_pfn));
 	memset(result, 0, sizeof(result));
-	for (gran_size = (1ULL<<20); gran_size < (1ULL<<32); gran_size <<= 1) {
-		for (chunk_size = gran_size; chunk_size < (1ULL<<33);
+	for (gran_size = (1ULL<<16); gran_size < (1ULL<<32); gran_size <<= 1) {
+		char gran_factor;
+		unsigned long gran_base;
+
+		if (debug_print)
+			gran_base = to_size_factor(gran_size >> 10, &gran_factor);
+
+		for (chunk_size = gran_size; chunk_size < (1ULL<<32);
 		     chunk_size <<= 1) {
 			int num_reg;
 
-			if (debug_print)
-				printk(KERN_INFO
-			       "\ngran_size: %lldM   chunk_size_size: %lldM\n",
-				       gran_size >> 20, chunk_size >> 20);
+			if (debug_print) {
+				char chunk_factor;
+				unsigned long chunk_base;
+
+				chunk_base = to_size_factor(chunk_size>>10, &chunk_factor),
+				printk(KERN_INFO "\n");
+				printk(KERN_INFO "gran_size: %ld%c   chunk_size: %ld%c \n",
+				       gran_base, gran_factor, chunk_base, chunk_factor);
+			}
 			if (i >= NUM_RESULT)
 				continue;
 
@@ -1326,12 +1421,18 @@
 
 	/* print out all */
 	for (i = 0; i < NUM_RESULT; i++) {
-		printk(KERN_INFO "%sgran_size: %ldM \tchunk_size: %ldM \t",
-		       result[i].bad?"*BAD* ":" ", result[i].gran_sizek >> 10,
-		       result[i].chunk_sizek >> 10);
-		printk(KERN_CONT "num_reg: %d \tlose RAM: %s%ldM\n",
-		       result[i].num_reg, result[i].bad?"-":"",
-		       result[i].lose_cover_sizek >> 10);
+		char gran_factor, chunk_factor, lose_factor;
+		unsigned long gran_base, chunk_base, lose_base;
+
+		gran_base = to_size_factor(result[i].gran_sizek, &gran_factor),
+		chunk_base = to_size_factor(result[i].chunk_sizek, &chunk_factor),
+		lose_base = to_size_factor(result[i].lose_cover_sizek, &lose_factor),
+		printk(KERN_INFO "%sgran_size: %ld%c \tchunk_size: %ld%c \t",
+			 result[i].bad?"*BAD*":" ",
+			 gran_base, gran_factor, chunk_base, chunk_factor);
+		printk(KERN_CONT "num_reg: %d  \tlose cover RAM: %s%ld%c\n",
+			 result[i].num_reg, result[i].bad?"-":"",
+			 lose_base, lose_factor);
 	}
 
 	/* try to find the optimal index */
@@ -1339,10 +1440,8 @@
 		nr_mtrr_spare_reg = num_var_ranges - 1;
 	num_reg_good = -1;
 	for (i = num_var_ranges - nr_mtrr_spare_reg; i > 0; i--) {
-		if (!min_loss_pfn[i]) {
+		if (!min_loss_pfn[i])
 			num_reg_good = i;
-			break;
-		}
 	}
 
 	index_good = -1;
@@ -1358,21 +1457,26 @@
 	}
 
 	if (index_good != -1) {
+		char gran_factor, chunk_factor, lose_factor;
+		unsigned long gran_base, chunk_base, lose_base;
+
 		printk(KERN_INFO "Found optimal setting for mtrr clean up\n");
 		i = index_good;
-		printk(KERN_INFO "gran_size: %ldM \tchunk_size: %ldM \t",
-				result[i].gran_sizek >> 10,
-				result[i].chunk_sizek >> 10);
-		printk(KERN_CONT "num_reg: %d \tlose RAM: %ldM\n",
-				result[i].num_reg,
-				result[i].lose_cover_sizek >> 10);
+		gran_base = to_size_factor(result[i].gran_sizek, &gran_factor),
+		chunk_base = to_size_factor(result[i].chunk_sizek, &chunk_factor),
+		lose_base = to_size_factor(result[i].lose_cover_sizek, &lose_factor),
+		printk(KERN_INFO "gran_size: %ld%c \tchunk_size: %ld%c \t",
+			 gran_base, gran_factor, chunk_base, chunk_factor);
+		printk(KERN_CONT "num_reg: %d  \tlose RAM: %ld%c\n",
+			 result[i].num_reg, lose_base, lose_factor);
 		/* convert ranges to var ranges state */
 		chunk_size = result[i].chunk_sizek;
 		chunk_size <<= 10;
 		gran_size = result[i].gran_sizek;
 		gran_size <<= 10;
-		debug_print = 1;
+		debug_print++;
 		x86_setup_var_mtrrs(range, nr_range, chunk_size, gran_size);
+		debug_print--;
 		set_var_mtrr_all(address_bits);
 		return 1;
 	}
diff --git a/arch/x86/kernel/cpu/perfctr-watchdog.c b/arch/x86/kernel/cpu/perfctr-watchdog.c
index 05cc22d..6bff382 100644
--- a/arch/x86/kernel/cpu/perfctr-watchdog.c
+++ b/arch/x86/kernel/cpu/perfctr-watchdog.c
@@ -295,13 +295,19 @@
 	/* setup the timer */
 	wrmsr(evntsel_msr, evntsel, 0);
 	write_watchdog_counter(perfctr_msr, "K7_PERFCTR0",nmi_hz);
+
+	/* initialize the wd struct before enabling */
+	wd->perfctr_msr = perfctr_msr;
+	wd->evntsel_msr = evntsel_msr;
+	wd->cccr_msr = 0;  /* unused */
+
+	/* ok, everything is initialized, announce that we're set */
+	cpu_nmi_set_wd_enabled();
+
 	apic_write(APIC_LVTPC, APIC_DM_NMI);
 	evntsel |= K7_EVNTSEL_ENABLE;
 	wrmsr(evntsel_msr, evntsel, 0);
 
-	wd->perfctr_msr = perfctr_msr;
-	wd->evntsel_msr = evntsel_msr;
-	wd->cccr_msr = 0;  /* unused */
 	return 1;
 }
 
@@ -379,13 +385,19 @@
 	wrmsr(evntsel_msr, evntsel, 0);
 	nmi_hz = adjust_for_32bit_ctr(nmi_hz);
 	write_watchdog_counter32(perfctr_msr, "P6_PERFCTR0",nmi_hz);
+
+	/* initialize the wd struct before enabling */
+	wd->perfctr_msr = perfctr_msr;
+	wd->evntsel_msr = evntsel_msr;
+	wd->cccr_msr = 0;  /* unused */
+
+	/* ok, everything is initialized, announce that we're set */
+	cpu_nmi_set_wd_enabled();
+
 	apic_write(APIC_LVTPC, APIC_DM_NMI);
 	evntsel |= P6_EVNTSEL0_ENABLE;
 	wrmsr(evntsel_msr, evntsel, 0);
 
-	wd->perfctr_msr = perfctr_msr;
-	wd->evntsel_msr = evntsel_msr;
-	wd->cccr_msr = 0;  /* unused */
 	return 1;
 }
 
@@ -432,6 +444,27 @@
 #define P4_CCCR_ENABLE		(1 << 12)
 #define P4_CCCR_OVF 		(1 << 31)
 
+#define P4_CONTROLS 18
+static unsigned int p4_controls[18] = {
+	MSR_P4_BPU_CCCR0,
+	MSR_P4_BPU_CCCR1,
+	MSR_P4_BPU_CCCR2,
+	MSR_P4_BPU_CCCR3,
+	MSR_P4_MS_CCCR0,
+	MSR_P4_MS_CCCR1,
+	MSR_P4_MS_CCCR2,
+	MSR_P4_MS_CCCR3,
+	MSR_P4_FLAME_CCCR0,
+	MSR_P4_FLAME_CCCR1,
+	MSR_P4_FLAME_CCCR2,
+	MSR_P4_FLAME_CCCR3,
+	MSR_P4_IQ_CCCR0,
+	MSR_P4_IQ_CCCR1,
+	MSR_P4_IQ_CCCR2,
+	MSR_P4_IQ_CCCR3,
+	MSR_P4_IQ_CCCR4,
+	MSR_P4_IQ_CCCR5,
+};
 /*
  * Set up IQ_COUNTER0 to behave like a clock, by having IQ_CCCR0 filter
  * CRU_ESCR0 (with any non-null event selector) through a complemented
@@ -473,6 +506,26 @@
 		evntsel_msr = MSR_P4_CRU_ESCR0;
 		cccr_msr = MSR_P4_IQ_CCCR0;
 		cccr_val = P4_CCCR_OVF_PMI0 | P4_CCCR_ESCR_SELECT(4);
+
+		/*
+		 * If we're on the kdump kernel or other situation, we may
+		 * still have other performance counter registers set to
+		 * interrupt and they'll keep interrupting forever because
+		 * of the P4_CCCR_OVF quirk. So we need to ACK all the
+		 * pending interrupts and disable all the registers here,
+		 * before reenabling the NMI delivery. Refer to p4_rearm()
+		 * about the P4_CCCR_OVF quirk.
+		 */
+		if (reset_devices) {
+			unsigned int low, high;
+			int i;
+
+			for (i = 0; i < P4_CONTROLS; i++) {
+				rdmsr(p4_controls[i], low, high);
+				low &= ~(P4_CCCR_ENABLE | P4_CCCR_OVF);
+				wrmsr(p4_controls[i], low, high);
+			}
+		}
 	} else {
 		/* logical cpu 1 */
 		perfctr_msr = MSR_P4_IQ_PERFCTR1;
@@ -499,12 +552,17 @@
 	wrmsr(evntsel_msr, evntsel, 0);
 	wrmsr(cccr_msr, cccr_val, 0);
 	write_watchdog_counter(perfctr_msr, "P4_IQ_COUNTER0", nmi_hz);
-	apic_write(APIC_LVTPC, APIC_DM_NMI);
-	cccr_val |= P4_CCCR_ENABLE;
-	wrmsr(cccr_msr, cccr_val, 0);
+
 	wd->perfctr_msr = perfctr_msr;
 	wd->evntsel_msr = evntsel_msr;
 	wd->cccr_msr = cccr_msr;
+
+	/* ok, everything is initialized, announce that we're set */
+	cpu_nmi_set_wd_enabled();
+
+	apic_write(APIC_LVTPC, APIC_DM_NMI);
+	cccr_val |= P4_CCCR_ENABLE;
+	wrmsr(cccr_msr, cccr_val, 0);
 	return 1;
 }
 
@@ -620,13 +678,17 @@
 	wrmsr(evntsel_msr, evntsel, 0);
 	nmi_hz = adjust_for_32bit_ctr(nmi_hz);
 	write_watchdog_counter32(perfctr_msr, "INTEL_ARCH_PERFCTR0", nmi_hz);
-	apic_write(APIC_LVTPC, APIC_DM_NMI);
-	evntsel |= ARCH_PERFMON_EVENTSEL0_ENABLE;
-	wrmsr(evntsel_msr, evntsel, 0);
 
 	wd->perfctr_msr = perfctr_msr;
 	wd->evntsel_msr = evntsel_msr;
 	wd->cccr_msr = 0;  /* unused */
+
+	/* ok, everything is initialized, announce that we're set */
+	cpu_nmi_set_wd_enabled();
+
+	apic_write(APIC_LVTPC, APIC_DM_NMI);
+	evntsel |= ARCH_PERFMON_EVENTSEL0_ENABLE;
+	wrmsr(evntsel_msr, evntsel, 0);
 	intel_arch_wd_ops.checkbit = 1ULL << (eax.split.bit_width - 1);
 	return 1;
 }
diff --git a/arch/x86/kernel/cpu/powerflags.c b/arch/x86/kernel/cpu/powerflags.c
new file mode 100644
index 0000000..5abbea2
--- /dev/null
+++ b/arch/x86/kernel/cpu/powerflags.c
@@ -0,0 +1,20 @@
+/*
+ * Strings for the various x86 power flags
+ *
+ * This file must not contain any executable code.
+ */
+
+#include <asm/cpufeature.h>
+
+const char *const x86_power_flags[32] = {
+	"ts",	/* temperature sensor */
+	"fid",  /* frequency id control */
+	"vid",  /* voltage id control */
+	"ttp",  /* thermal trip */
+	"tm",
+	"stc",
+	"100mhzsteps",
+	"hwpstate",
+	"",	/* tsc invariant mapped to constant_tsc */
+		/* nothing */
+};
diff --git a/arch/x86/kernel/cpu/transmeta.c b/arch/x86/kernel/cpu/transmeta.c
index b911a2c..52b3fef 100644
--- a/arch/x86/kernel/cpu/transmeta.c
+++ b/arch/x86/kernel/cpu/transmeta.c
@@ -5,6 +5,18 @@
 #include <asm/msr.h>
 #include "cpu.h"
 
+static void __cpuinit early_init_transmeta(struct cpuinfo_x86 *c)
+{
+	u32 xlvl;
+
+	/* Transmeta-defined flags: level 0x80860001 */
+	xlvl = cpuid_eax(0x80860000);
+	if ((xlvl & 0xffff0000) == 0x80860000) {
+		if (xlvl >= 0x80860001)
+			c->x86_capability[2] = cpuid_edx(0x80860001);
+	}
+}
+
 static void __cpuinit init_transmeta(struct cpuinfo_x86 *c)
 {
 	unsigned int cap_mask, uk, max, dummy;
@@ -12,7 +24,8 @@
 	unsigned int cpu_rev, cpu_freq = 0, cpu_flags, new_cpu_rev;
 	char cpu_info[65];
 
-	get_model_name(c);	/* Same as AMD/Cyrix */
+	early_init_transmeta(c);
+
 	display_cacheinfo(c);
 
 	/* Print CMS and CPU revision */
@@ -85,23 +98,12 @@
 #endif
 }
 
-static void __cpuinit transmeta_identify(struct cpuinfo_x86 *c)
-{
-	u32 xlvl;
-
-	/* Transmeta-defined flags: level 0x80860001 */
-	xlvl = cpuid_eax(0x80860000);
-	if ((xlvl & 0xffff0000) == 0x80860000) {
-		if (xlvl >= 0x80860001)
-			c->x86_capability[2] = cpuid_edx(0x80860001);
-	}
-}
-
 static struct cpu_dev transmeta_cpu_dev __cpuinitdata = {
 	.c_vendor	= "Transmeta",
 	.c_ident	= { "GenuineTMx86", "TransmetaCPU" },
+	.c_early_init	= early_init_transmeta,
 	.c_init		= init_transmeta,
-	.c_identify	= transmeta_identify,
+	.c_x86_vendor	= X86_VENDOR_TRANSMETA,
 };
 
-cpu_vendor_dev_register(X86_VENDOR_TRANSMETA, &transmeta_cpu_dev);
+cpu_dev_register(transmeta_cpu_dev);
diff --git a/arch/x86/kernel/cpu/umc.c b/arch/x86/kernel/cpu/umc.c
index b1fc909..e777f79 100644
--- a/arch/x86/kernel/cpu/umc.c
+++ b/arch/x86/kernel/cpu/umc.c
@@ -19,7 +19,8 @@
 		  }
 		},
 	},
+	.c_x86_vendor	= X86_VENDOR_UMC,
 };
 
-cpu_vendor_dev_register(X86_VENDOR_UMC, &umc_cpu_dev);
+cpu_dev_register(umc_cpu_dev);
 
diff --git a/arch/x86/kernel/cpuid.c b/arch/x86/kernel/cpuid.c
index 8e9cd6a..6a44d64 100644
--- a/arch/x86/kernel/cpuid.c
+++ b/arch/x86/kernel/cpuid.c
@@ -36,7 +36,6 @@
 #include <linux/smp_lock.h>
 #include <linux/major.h>
 #include <linux/fs.h>
-#include <linux/smp_lock.h>
 #include <linux/device.h>
 #include <linux/cpu.h>
 #include <linux/notifier.h>
diff --git a/arch/x86/kernel/crash_dump_64.c b/arch/x86/kernel/crash_dump_64.c
index 15e6c6b..e90a60e 100644
--- a/arch/x86/kernel/crash_dump_64.c
+++ b/arch/x86/kernel/crash_dump_64.c
@@ -7,9 +7,8 @@
 
 #include <linux/errno.h>
 #include <linux/crash_dump.h>
-
-#include <asm/uaccess.h>
-#include <asm/io.h>
+#include <linux/uaccess.h>
+#include <linux/io.h>
 
 /**
  * copy_oldmem_page - copy one page from "oldmem"
@@ -25,7 +24,7 @@
  * in the current kernel. We stitch up a pte, similar to kmap_atomic.
  */
 ssize_t copy_oldmem_page(unsigned long pfn, char *buf,
-                               size_t csize, unsigned long offset, int userbuf)
+		size_t csize, unsigned long offset, int userbuf)
 {
 	void  *vaddr;
 
@@ -33,14 +32,16 @@
 		return 0;
 
 	vaddr = ioremap(pfn << PAGE_SHIFT, PAGE_SIZE);
+	if (!vaddr)
+		return -ENOMEM;
 
 	if (userbuf) {
-		if (copy_to_user(buf, (vaddr + offset), csize)) {
+		if (copy_to_user(buf, vaddr + offset, csize)) {
 			iounmap(vaddr);
 			return -EFAULT;
 		}
 	} else
-	memcpy(buf, (vaddr + offset), csize);
+		memcpy(buf, vaddr + offset, csize);
 
 	iounmap(vaddr);
 	return csize;
diff --git a/arch/x86/kernel/doublefault_32.c b/arch/x86/kernel/doublefault_32.c
index a47798b..b4f14c6 100644
--- a/arch/x86/kernel/doublefault_32.c
+++ b/arch/x86/kernel/doublefault_32.c
@@ -66,6 +66,6 @@
 		.ds		= __USER_DS,
 		.fs		= __KERNEL_PERCPU,
 
-		.__cr3		= __pa(swapper_pg_dir)
+		.__cr3		= __pa_nodebug(swapper_pg_dir),
 	}
 };
diff --git a/arch/x86/kernel/ds.c b/arch/x86/kernel/ds.c
index 11c11b8..2b69994 100644
--- a/arch/x86/kernel/ds.c
+++ b/arch/x86/kernel/ds.c
@@ -2,26 +2,49 @@
  * Debug Store support
  *
  * This provides a low-level interface to the hardware's Debug Store
- * feature that is used for last branch recording (LBR) and
+ * feature that is used for branch trace store (BTS) and
  * precise-event based sampling (PEBS).
  *
- * Different architectures use a different DS layout/pointer size.
- * The below functions therefore work on a void*.
+ * It manages:
+ * - per-thread and per-cpu allocation of BTS and PEBS
+ * - buffer memory allocation (optional)
+ * - buffer overflow handling
+ * - buffer access
+ *
+ * It assumes:
+ * - get_task_struct on all parameter tasks
+ * - current is allowed to trace parameter tasks
  *
  *
- * Since there is no user for PEBS, yet, only LBR (or branch
- * trace store, BTS) is supported.
- *
- *
- * Copyright (C) 2007 Intel Corporation.
- * Markus Metzger <markus.t.metzger@intel.com>, Dec 2007
+ * Copyright (C) 2007-2008 Intel Corporation.
+ * Markus Metzger <markus.t.metzger@intel.com>, 2007-2008
  */
 
+
+#ifdef CONFIG_X86_DS
+
 #include <asm/ds.h>
 
 #include <linux/errno.h>
 #include <linux/string.h>
 #include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+
+
+/*
+ * The configuration for a particular DS hardware implementation.
+ */
+struct ds_configuration {
+	/* the size of the DS structure in bytes */
+	unsigned char  sizeof_ds;
+	/* the size of one pointer-typed field in the DS structure in bytes;
+	   this covers the first 8 fields related to buffer management. */
+	unsigned char  sizeof_field;
+	/* the size of a BTS/PEBS record in bytes */
+	unsigned char  sizeof_rec[2];
+};
+static struct ds_configuration ds_cfg;
 
 
 /*
@@ -44,378 +67,747 @@
  *   (interrupt occurs when write pointer passes interrupt pointer)
  * - value to which counter is reset following counter overflow
  *
- * On later architectures, the last branch recording hardware uses
- * 64bit pointers even in 32bit mode.
+ * Later architectures use 64bit pointers throughout, whereas earlier
+ * architectures use 32bit pointers in 32bit mode.
  *
  *
- * Branch Trace Store (BTS) records store information about control
- * flow changes. They at least provide the following information:
- * - source linear address
- * - destination linear address
+ * We compute the base address for the first 8 fields based on:
+ * - the field size stored in the DS configuration
+ * - the relative field position
+ * - an offset giving the start of the respective region
  *
- * Netburst supported a predicated bit that had been dropped in later
- * architectures. We do not suppor it.
+ * This offset is further used to index various arrays holding
+ * information for BTS and PEBS at the respective index.
  *
- *
- * In order to abstract from the actual DS and BTS layout, we describe
- * the access to the relevant fields.
- * Thanks to Andi Kleen for proposing this design.
- *
- * The implementation, however, is not as general as it might seem. In
- * order to stay somewhat simple and efficient, we assume an
- * underlying unsigned type (mostly a pointer type) and we expect the
- * field to be at least as big as that type.
+ * On later 32bit processors, we only access the lower 32bit of the
+ * 64bit pointer fields. The upper halves will be zeroed out.
  */
 
-/*
- * A special from_ip address to indicate that the BTS record is an
- * info record that needs to be interpreted or skipped.
- */
-#define BTS_ESCAPE_ADDRESS (-1)
-
-/*
- * A field access descriptor
- */
-struct access_desc {
-	unsigned char offset;
-	unsigned char size;
+enum ds_field {
+	ds_buffer_base = 0,
+	ds_index,
+	ds_absolute_maximum,
+	ds_interrupt_threshold,
 };
 
-/*
- * The configuration for a particular DS/BTS hardware implementation.
- */
-struct ds_configuration {
-	/* the DS configuration */
-	unsigned char  sizeof_ds;
-	struct access_desc bts_buffer_base;
-	struct access_desc bts_index;
-	struct access_desc bts_absolute_maximum;
-	struct access_desc bts_interrupt_threshold;
-	/* the BTS configuration */
-	unsigned char  sizeof_bts;
-	struct access_desc from_ip;
-	struct access_desc to_ip;
-	/* BTS variants used to store additional information like
-	   timestamps */
-	struct access_desc info_type;
-	struct access_desc info_data;
-	unsigned long debugctl_mask;
+enum ds_qualifier {
+	ds_bts  = 0,
+	ds_pebs
 };
 
-/*
- * The global configuration used by the below accessor functions
- */
-static struct ds_configuration ds_cfg;
+static inline unsigned long ds_get(const unsigned char *base,
+				   enum ds_qualifier qual, enum ds_field field)
+{
+	base += (ds_cfg.sizeof_field * (field + (4 * qual)));
+	return *(unsigned long *)base;
+}
+
+static inline void ds_set(unsigned char *base, enum ds_qualifier qual,
+			  enum ds_field field, unsigned long value)
+{
+	base += (ds_cfg.sizeof_field * (field + (4 * qual)));
+	(*(unsigned long *)base) = value;
+}
+
 
 /*
- * Accessor functions for some DS and BTS fields using the above
- * global ptrace_bts_cfg.
+ * Locking is done only for allocating BTS or PEBS resources and for
+ * guarding context and buffer memory allocation.
+ *
+ * Most functions require the current task to own the ds context part
+ * they are going to access. All the locking is done when validating
+ * access to the context.
  */
-static inline unsigned long get_bts_buffer_base(char *base)
-{
-	return *(unsigned long *)(base + ds_cfg.bts_buffer_base.offset);
-}
-static inline void set_bts_buffer_base(char *base, unsigned long value)
-{
-	(*(unsigned long *)(base + ds_cfg.bts_buffer_base.offset)) = value;
-}
-static inline unsigned long get_bts_index(char *base)
-{
-	return *(unsigned long *)(base + ds_cfg.bts_index.offset);
-}
-static inline void set_bts_index(char *base, unsigned long value)
-{
-	(*(unsigned long *)(base + ds_cfg.bts_index.offset)) = value;
-}
-static inline unsigned long get_bts_absolute_maximum(char *base)
-{
-	return *(unsigned long *)(base + ds_cfg.bts_absolute_maximum.offset);
-}
-static inline void set_bts_absolute_maximum(char *base, unsigned long value)
-{
-	(*(unsigned long *)(base + ds_cfg.bts_absolute_maximum.offset)) = value;
-}
-static inline unsigned long get_bts_interrupt_threshold(char *base)
-{
-	return *(unsigned long *)(base + ds_cfg.bts_interrupt_threshold.offset);
-}
-static inline void set_bts_interrupt_threshold(char *base, unsigned long value)
-{
-	(*(unsigned long *)(base + ds_cfg.bts_interrupt_threshold.offset)) = value;
-}
-static inline unsigned long get_from_ip(char *base)
-{
-	return *(unsigned long *)(base + ds_cfg.from_ip.offset);
-}
-static inline void set_from_ip(char *base, unsigned long value)
-{
-	(*(unsigned long *)(base + ds_cfg.from_ip.offset)) = value;
-}
-static inline unsigned long get_to_ip(char *base)
-{
-	return *(unsigned long *)(base + ds_cfg.to_ip.offset);
-}
-static inline void set_to_ip(char *base, unsigned long value)
-{
-	(*(unsigned long *)(base + ds_cfg.to_ip.offset)) = value;
-}
-static inline unsigned char get_info_type(char *base)
-{
-	return *(unsigned char *)(base + ds_cfg.info_type.offset);
-}
-static inline void set_info_type(char *base, unsigned char value)
-{
-	(*(unsigned char *)(base + ds_cfg.info_type.offset)) = value;
-}
-static inline unsigned long get_info_data(char *base)
-{
-	return *(unsigned long *)(base + ds_cfg.info_data.offset);
-}
-static inline void set_info_data(char *base, unsigned long value)
-{
-	(*(unsigned long *)(base + ds_cfg.info_data.offset)) = value;
-}
+static spinlock_t ds_lock = __SPIN_LOCK_UNLOCKED(ds_lock);
 
-
-int ds_allocate(void **dsp, size_t bts_size_in_bytes)
+/*
+ * Validate that the current task is allowed to access the BTS/PEBS
+ * buffer of the parameter task.
+ *
+ * Returns 0, if access is granted; -Eerrno, otherwise.
+ */
+static inline int ds_validate_access(struct ds_context *context,
+				     enum ds_qualifier qual)
 {
-	size_t bts_size_in_records;
-	unsigned long bts;
-	void *ds;
+	if (!context)
+		return -EPERM;
 
-	if (!ds_cfg.sizeof_ds || !ds_cfg.sizeof_bts)
-		return -EOPNOTSUPP;
-
-	if (bts_size_in_bytes < 0)
-		return -EINVAL;
-
-	bts_size_in_records =
-		bts_size_in_bytes / ds_cfg.sizeof_bts;
-	bts_size_in_bytes =
-		bts_size_in_records * ds_cfg.sizeof_bts;
-
-	if (bts_size_in_bytes <= 0)
-		return -EINVAL;
-
-	bts = (unsigned long)kzalloc(bts_size_in_bytes, GFP_KERNEL);
-
-	if (!bts)
-		return -ENOMEM;
-
-	ds = kzalloc(ds_cfg.sizeof_ds, GFP_KERNEL);
-
-	if (!ds) {
-		kfree((void *)bts);
-		return -ENOMEM;
-	}
-
-	set_bts_buffer_base(ds, bts);
-	set_bts_index(ds, bts);
-	set_bts_absolute_maximum(ds, bts + bts_size_in_bytes);
-	set_bts_interrupt_threshold(ds, bts + bts_size_in_bytes + 1);
-
-	*dsp = ds;
-	return 0;
-}
-
-int ds_free(void **dsp)
-{
-	if (*dsp) {
-		kfree((void *)get_bts_buffer_base(*dsp));
-		kfree(*dsp);
-		*dsp = NULL;
-	}
-	return 0;
-}
-
-int ds_get_bts_size(void *ds)
-{
-	int size_in_bytes;
-
-	if (!ds_cfg.sizeof_ds || !ds_cfg.sizeof_bts)
-		return -EOPNOTSUPP;
-
-	if (!ds)
+	if (context->owner[qual] == current)
 		return 0;
 
-	size_in_bytes =
-		get_bts_absolute_maximum(ds) -
-		get_bts_buffer_base(ds);
-	return size_in_bytes;
+	return -EPERM;
 }
 
-int ds_get_bts_end(void *ds)
+
+/*
+ * We either support (system-wide) per-cpu or per-thread allocation.
+ * We distinguish the two based on the task_struct pointer, where a
+ * NULL pointer indicates per-cpu allocation for the current cpu.
+ *
+ * Allocations are use-counted. As soon as resources are allocated,
+ * further allocations must be of the same type (per-cpu or
+ * per-thread). We model this by counting allocations (i.e. the number
+ * of tracers of a certain type) for one type negatively:
+ *   =0  no tracers
+ *   >0  number of per-thread tracers
+ *   <0  number of per-cpu tracers
+ *
+ * The below functions to get and put tracers and to check the
+ * allocation type require the ds_lock to be held by the caller.
+ *
+ * Tracers essentially gives the number of ds contexts for a certain
+ * type of allocation.
+ */
+static long tracers;
+
+static inline void get_tracer(struct task_struct *task)
 {
-	int size_in_bytes = ds_get_bts_size(ds);
-
-	if (size_in_bytes <= 0)
-		return size_in_bytes;
-
-	return size_in_bytes / ds_cfg.sizeof_bts;
+	tracers += (task ? 1 : -1);
 }
 
-int ds_get_bts_index(void *ds)
+static inline void put_tracer(struct task_struct *task)
 {
-	int index_offset_in_bytes;
-
-	if (!ds_cfg.sizeof_ds || !ds_cfg.sizeof_bts)
-		return -EOPNOTSUPP;
-
-	index_offset_in_bytes =
-		get_bts_index(ds) -
-		get_bts_buffer_base(ds);
-
-	return index_offset_in_bytes / ds_cfg.sizeof_bts;
+	tracers -= (task ? 1 : -1);
 }
 
-int ds_set_overflow(void *ds, int method)
+static inline int check_tracer(struct task_struct *task)
 {
-	switch (method) {
-	case DS_O_SIGNAL:
-		return -EOPNOTSUPP;
-	case DS_O_WRAP:
-		return 0;
-	default:
-		return -EINVAL;
-	}
+	return (task ? (tracers >= 0) : (tracers <= 0));
 }
 
-int ds_get_overflow(void *ds)
+
+/*
+ * The DS context is either attached to a thread or to a cpu:
+ * - in the former case, the thread_struct contains a pointer to the
+ *   attached context.
+ * - in the latter case, we use a static array of per-cpu context
+ *   pointers.
+ *
+ * Contexts are use-counted. They are allocated on first access and
+ * deallocated when the last user puts the context.
+ *
+ * We distinguish between an allocating and a non-allocating get of a
+ * context:
+ * - the allocating get is used for requesting BTS/PEBS resources. It
+ *   requires the caller to hold the global ds_lock.
+ * - the non-allocating get is used for all other cases. A
+ *   non-existing context indicates an error. It acquires and releases
+ *   the ds_lock itself for obtaining the context.
+ *
+ * A context and its DS configuration are allocated and deallocated
+ * together. A context always has a DS configuration of the
+ * appropriate size.
+ */
+static DEFINE_PER_CPU(struct ds_context *, system_context);
+
+#define this_system_context per_cpu(system_context, smp_processor_id())
+
+/*
+ * Returns the pointer to the parameter task's context or to the
+ * system-wide context, if task is NULL.
+ *
+ * Increases the use count of the returned context, if not NULL.
+ */
+static inline struct ds_context *ds_get_context(struct task_struct *task)
 {
-	return DS_O_WRAP;
+	struct ds_context *context;
+
+	spin_lock(&ds_lock);
+
+	context = (task ? task->thread.ds_ctx : this_system_context);
+	if (context)
+		context->count++;
+
+	spin_unlock(&ds_lock);
+
+	return context;
 }
 
-int ds_clear(void *ds)
+/*
+ * Same as ds_get_context, but allocates the context and it's DS
+ * structure, if necessary; returns NULL; if out of memory.
+ *
+ * pre: requires ds_lock to be held
+ */
+static inline struct ds_context *ds_alloc_context(struct task_struct *task)
 {
-	int bts_size = ds_get_bts_size(ds);
-	unsigned long bts_base;
+	struct ds_context **p_context =
+		(task ? &task->thread.ds_ctx : &this_system_context);
+	struct ds_context *context = *p_context;
 
-	if (bts_size <= 0)
-		return bts_size;
+	if (!context) {
+		context = kzalloc(sizeof(*context), GFP_KERNEL);
 
-	bts_base = get_bts_buffer_base(ds);
-	memset((void *)bts_base, 0, bts_size);
+		if (!context)
+			return NULL;
 
-	set_bts_index(ds, bts_base);
-	return 0;
-}
+		context->ds = kzalloc(ds_cfg.sizeof_ds, GFP_KERNEL);
+		if (!context->ds) {
+			kfree(context);
+			return NULL;
+		}
 
-int ds_read_bts(void *ds, int index, struct bts_struct *out)
-{
-	void *bts;
+		*p_context = context;
 
-	if (!ds_cfg.sizeof_ds || !ds_cfg.sizeof_bts)
-		return -EOPNOTSUPP;
+		context->this = p_context;
+		context->task = task;
 
-	if (index < 0)
-		return -EINVAL;
+		if (task)
+			set_tsk_thread_flag(task, TIF_DS_AREA_MSR);
 
-	if (index >= ds_get_bts_size(ds))
-		return -EINVAL;
+		if (!task || (task == current))
+			wrmsr(MSR_IA32_DS_AREA, (unsigned long)context->ds, 0);
 
-	bts = (void *)(get_bts_buffer_base(ds) + (index * ds_cfg.sizeof_bts));
-
-	memset(out, 0, sizeof(*out));
-	if (get_from_ip(bts) == BTS_ESCAPE_ADDRESS) {
-		out->qualifier       = get_info_type(bts);
-		out->variant.jiffies = get_info_data(bts);
-	} else {
-		out->qualifier = BTS_BRANCH;
-		out->variant.lbr.from_ip = get_from_ip(bts);
-		out->variant.lbr.to_ip   = get_to_ip(bts);
+		get_tracer(task);
 	}
 
-	return sizeof(*out);;
+	context->count++;
+
+	return context;
 }
 
-int ds_write_bts(void *ds, const struct bts_struct *in)
+/*
+ * Decreases the use count of the parameter context, if not NULL.
+ * Deallocates the context, if the use count reaches zero.
+ */
+static inline void ds_put_context(struct ds_context *context)
 {
-	unsigned long bts;
+	if (!context)
+		return;
 
-	if (!ds_cfg.sizeof_ds || !ds_cfg.sizeof_bts)
+	spin_lock(&ds_lock);
+
+	if (--context->count)
+		goto out;
+
+	*(context->this) = NULL;
+
+	if (context->task)
+		clear_tsk_thread_flag(context->task, TIF_DS_AREA_MSR);
+
+	if (!context->task || (context->task == current))
+		wrmsrl(MSR_IA32_DS_AREA, 0);
+
+	put_tracer(context->task);
+
+	/* free any leftover buffers from tracers that did not
+	 * deallocate them properly. */
+	kfree(context->buffer[ds_bts]);
+	kfree(context->buffer[ds_pebs]);
+	kfree(context->ds);
+	kfree(context);
+ out:
+	spin_unlock(&ds_lock);
+}
+
+
+/*
+ * Handle a buffer overflow
+ *
+ * task: the task whose buffers are overflowing;
+ *       NULL for a buffer overflow on the current cpu
+ * context: the ds context
+ * qual: the buffer type
+ */
+static void ds_overflow(struct task_struct *task, struct ds_context *context,
+			enum ds_qualifier qual)
+{
+	if (!context)
+		return;
+
+	if (context->callback[qual])
+		(*context->callback[qual])(task);
+
+	/* todo: do some more overflow handling */
+}
+
+
+/*
+ * Allocate a non-pageable buffer of the parameter size.
+ * Checks the memory and the locked memory rlimit.
+ *
+ * Returns the buffer, if successful;
+ *         NULL, if out of memory or rlimit exceeded.
+ *
+ * size: the requested buffer size in bytes
+ * pages (out): if not NULL, contains the number of pages reserved
+ */
+static inline void *ds_allocate_buffer(size_t size, unsigned int *pages)
+{
+	unsigned long rlim, vm, pgsz;
+	void *buffer;
+
+	pgsz = PAGE_ALIGN(size) >> PAGE_SHIFT;
+
+	rlim = current->signal->rlim[RLIMIT_AS].rlim_cur >> PAGE_SHIFT;
+	vm   = current->mm->total_vm  + pgsz;
+	if (rlim < vm)
+		return NULL;
+
+	rlim = current->signal->rlim[RLIMIT_MEMLOCK].rlim_cur >> PAGE_SHIFT;
+	vm   = current->mm->locked_vm  + pgsz;
+	if (rlim < vm)
+		return NULL;
+
+	buffer = kzalloc(size, GFP_KERNEL);
+	if (!buffer)
+		return NULL;
+
+	current->mm->total_vm  += pgsz;
+	current->mm->locked_vm += pgsz;
+
+	if (pages)
+		*pages = pgsz;
+
+	return buffer;
+}
+
+static int ds_request(struct task_struct *task, void *base, size_t size,
+		      ds_ovfl_callback_t ovfl, enum ds_qualifier qual)
+{
+	struct ds_context *context;
+	unsigned long buffer, adj;
+	const unsigned long alignment = (1 << 3);
+	int error = 0;
+
+	if (!ds_cfg.sizeof_ds)
 		return -EOPNOTSUPP;
 
-	if (ds_get_bts_size(ds) <= 0)
-		return -ENXIO;
-
-	bts = get_bts_index(ds);
-
-	memset((void *)bts, 0, ds_cfg.sizeof_bts);
-	switch (in->qualifier) {
-	case BTS_INVALID:
-		break;
-
-	case BTS_BRANCH:
-		set_from_ip((void *)bts, in->variant.lbr.from_ip);
-		set_to_ip((void *)bts, in->variant.lbr.to_ip);
-		break;
-
-	case BTS_TASK_ARRIVES:
-	case BTS_TASK_DEPARTS:
-		set_from_ip((void *)bts, BTS_ESCAPE_ADDRESS);
-		set_info_type((void *)bts, in->qualifier);
-		set_info_data((void *)bts, in->variant.jiffies);
-		break;
-
-	default:
+	/* we require some space to do alignment adjustments below */
+	if (size < (alignment + ds_cfg.sizeof_rec[qual]))
 		return -EINVAL;
+
+	/* buffer overflow notification is not yet implemented */
+	if (ovfl)
+		return -EOPNOTSUPP;
+
+
+	spin_lock(&ds_lock);
+
+	if (!check_tracer(task))
+		return -EPERM;
+
+	error = -ENOMEM;
+	context = ds_alloc_context(task);
+	if (!context)
+		goto out_unlock;
+
+	error = -EALREADY;
+	if (context->owner[qual] == current)
+		goto out_unlock;
+	error = -EPERM;
+	if (context->owner[qual] != NULL)
+		goto out_unlock;
+	context->owner[qual] = current;
+
+	spin_unlock(&ds_lock);
+
+
+	error = -ENOMEM;
+	if (!base) {
+		base = ds_allocate_buffer(size, &context->pages[qual]);
+		if (!base)
+			goto out_release;
+
+		context->buffer[qual]   = base;
+	}
+	error = 0;
+
+	context->callback[qual] = ovfl;
+
+	/* adjust the buffer address and size to meet alignment
+	 * constraints:
+	 * - buffer is double-word aligned
+	 * - size is multiple of record size
+	 *
+	 * We checked the size at the very beginning; we have enough
+	 * space to do the adjustment.
+	 */
+	buffer = (unsigned long)base;
+
+	adj = ALIGN(buffer, alignment) - buffer;
+	buffer += adj;
+	size   -= adj;
+
+	size /= ds_cfg.sizeof_rec[qual];
+	size *= ds_cfg.sizeof_rec[qual];
+
+	ds_set(context->ds, qual, ds_buffer_base, buffer);
+	ds_set(context->ds, qual, ds_index, buffer);
+	ds_set(context->ds, qual, ds_absolute_maximum, buffer + size);
+
+	if (ovfl) {
+		/* todo: select a suitable interrupt threshold */
+	} else
+		ds_set(context->ds, qual,
+		       ds_interrupt_threshold, buffer + size + 1);
+
+	/* we keep the context until ds_release */
+	return error;
+
+ out_release:
+	context->owner[qual] = NULL;
+	ds_put_context(context);
+	return error;
+
+ out_unlock:
+	spin_unlock(&ds_lock);
+	ds_put_context(context);
+	return error;
+}
+
+int ds_request_bts(struct task_struct *task, void *base, size_t size,
+		   ds_ovfl_callback_t ovfl)
+{
+	return ds_request(task, base, size, ovfl, ds_bts);
+}
+
+int ds_request_pebs(struct task_struct *task, void *base, size_t size,
+		    ds_ovfl_callback_t ovfl)
+{
+	return ds_request(task, base, size, ovfl, ds_pebs);
+}
+
+static int ds_release(struct task_struct *task, enum ds_qualifier qual)
+{
+	struct ds_context *context;
+	int error;
+
+	context = ds_get_context(task);
+	error = ds_validate_access(context, qual);
+	if (error < 0)
+		goto out;
+
+	kfree(context->buffer[qual]);
+	context->buffer[qual] = NULL;
+
+	current->mm->total_vm  -= context->pages[qual];
+	current->mm->locked_vm -= context->pages[qual];
+	context->pages[qual] = 0;
+	context->owner[qual] = NULL;
+
+	/*
+	 * we put the context twice:
+	 *   once for the ds_get_context
+	 *   once for the corresponding ds_request
+	 */
+	ds_put_context(context);
+ out:
+	ds_put_context(context);
+	return error;
+}
+
+int ds_release_bts(struct task_struct *task)
+{
+	return ds_release(task, ds_bts);
+}
+
+int ds_release_pebs(struct task_struct *task)
+{
+	return ds_release(task, ds_pebs);
+}
+
+static int ds_get_index(struct task_struct *task, size_t *pos,
+			enum ds_qualifier qual)
+{
+	struct ds_context *context;
+	unsigned long base, index;
+	int error;
+
+	context = ds_get_context(task);
+	error = ds_validate_access(context, qual);
+	if (error < 0)
+		goto out;
+
+	base  = ds_get(context->ds, qual, ds_buffer_base);
+	index = ds_get(context->ds, qual, ds_index);
+
+	error = ((index - base) / ds_cfg.sizeof_rec[qual]);
+	if (pos)
+		*pos = error;
+ out:
+	ds_put_context(context);
+	return error;
+}
+
+int ds_get_bts_index(struct task_struct *task, size_t *pos)
+{
+	return ds_get_index(task, pos, ds_bts);
+}
+
+int ds_get_pebs_index(struct task_struct *task, size_t *pos)
+{
+	return ds_get_index(task, pos, ds_pebs);
+}
+
+static int ds_get_end(struct task_struct *task, size_t *pos,
+		      enum ds_qualifier qual)
+{
+	struct ds_context *context;
+	unsigned long base, end;
+	int error;
+
+	context = ds_get_context(task);
+	error = ds_validate_access(context, qual);
+	if (error < 0)
+		goto out;
+
+	base = ds_get(context->ds, qual, ds_buffer_base);
+	end  = ds_get(context->ds, qual, ds_absolute_maximum);
+
+	error = ((end - base) / ds_cfg.sizeof_rec[qual]);
+	if (pos)
+		*pos = error;
+ out:
+	ds_put_context(context);
+	return error;
+}
+
+int ds_get_bts_end(struct task_struct *task, size_t *pos)
+{
+	return ds_get_end(task, pos, ds_bts);
+}
+
+int ds_get_pebs_end(struct task_struct *task, size_t *pos)
+{
+	return ds_get_end(task, pos, ds_pebs);
+}
+
+static int ds_access(struct task_struct *task, size_t index,
+		     const void **record, enum ds_qualifier qual)
+{
+	struct ds_context *context;
+	unsigned long base, idx;
+	int error;
+
+	if (!record)
+		return -EINVAL;
+
+	context = ds_get_context(task);
+	error = ds_validate_access(context, qual);
+	if (error < 0)
+		goto out;
+
+	base = ds_get(context->ds, qual, ds_buffer_base);
+	idx = base + (index * ds_cfg.sizeof_rec[qual]);
+
+	error = -EINVAL;
+	if (idx > ds_get(context->ds, qual, ds_absolute_maximum))
+		goto out;
+
+	*record = (const void *)idx;
+	error = ds_cfg.sizeof_rec[qual];
+ out:
+	ds_put_context(context);
+	return error;
+}
+
+int ds_access_bts(struct task_struct *task, size_t index, const void **record)
+{
+	return ds_access(task, index, record, ds_bts);
+}
+
+int ds_access_pebs(struct task_struct *task, size_t index, const void **record)
+{
+	return ds_access(task, index, record, ds_pebs);
+}
+
+static int ds_write(struct task_struct *task, const void *record, size_t size,
+		    enum ds_qualifier qual, int force)
+{
+	struct ds_context *context;
+	int error;
+
+	if (!record)
+		return -EINVAL;
+
+	error = -EPERM;
+	context = ds_get_context(task);
+	if (!context)
+		goto out;
+
+	if (!force) {
+		error = ds_validate_access(context, qual);
+		if (error < 0)
+			goto out;
 	}
 
-	bts = bts + ds_cfg.sizeof_bts;
-	if (bts >= get_bts_absolute_maximum(ds))
-		bts = get_bts_buffer_base(ds);
-	set_bts_index(ds, bts);
+	error = 0;
+	while (size) {
+		unsigned long base, index, end, write_end, int_th;
+		unsigned long write_size, adj_write_size;
 
-	return ds_cfg.sizeof_bts;
+		/*
+		 * write as much as possible without producing an
+		 * overflow interrupt.
+		 *
+		 * interrupt_threshold must either be
+		 * - bigger than absolute_maximum or
+		 * - point to a record between buffer_base and absolute_maximum
+		 *
+		 * index points to a valid record.
+		 */
+		base   = ds_get(context->ds, qual, ds_buffer_base);
+		index  = ds_get(context->ds, qual, ds_index);
+		end    = ds_get(context->ds, qual, ds_absolute_maximum);
+		int_th = ds_get(context->ds, qual, ds_interrupt_threshold);
+
+		write_end = min(end, int_th);
+
+		/* if we are already beyond the interrupt threshold,
+		 * we fill the entire buffer */
+		if (write_end <= index)
+			write_end = end;
+
+		if (write_end <= index)
+			goto out;
+
+		write_size = min((unsigned long) size, write_end - index);
+		memcpy((void *)index, record, write_size);
+
+		record = (const char *)record + write_size;
+		size  -= write_size;
+		error += write_size;
+
+		adj_write_size = write_size / ds_cfg.sizeof_rec[qual];
+		adj_write_size *= ds_cfg.sizeof_rec[qual];
+
+		/* zero out trailing bytes */
+		memset((char *)index + write_size, 0,
+		       adj_write_size - write_size);
+		index += adj_write_size;
+
+		if (index >= end)
+			index = base;
+		ds_set(context->ds, qual, ds_index, index);
+
+		if (index >= int_th)
+			ds_overflow(task, context, qual);
+	}
+
+ out:
+	ds_put_context(context);
+	return error;
 }
 
-unsigned long ds_debugctl_mask(void)
+int ds_write_bts(struct task_struct *task, const void *record, size_t size)
 {
-	return ds_cfg.debugctl_mask;
+	return ds_write(task, record, size, ds_bts, /* force = */ 0);
 }
 
-#ifdef __i386__
-static const struct ds_configuration ds_cfg_netburst = {
-	.sizeof_ds = 9 * 4,
-	.bts_buffer_base = { 0, 4 },
-	.bts_index = { 4, 4 },
-	.bts_absolute_maximum = { 8, 4 },
-	.bts_interrupt_threshold = { 12, 4 },
-	.sizeof_bts = 3 * 4,
-	.from_ip = { 0, 4 },
-	.to_ip = { 4, 4 },
-	.info_type = { 4, 1 },
-	.info_data = { 8, 4 },
-	.debugctl_mask = (1<<2)|(1<<3)
+int ds_write_pebs(struct task_struct *task, const void *record, size_t size)
+{
+	return ds_write(task, record, size, ds_pebs, /* force = */ 0);
+}
+
+int ds_unchecked_write_bts(struct task_struct *task,
+			   const void *record, size_t size)
+{
+	return ds_write(task, record, size, ds_bts, /* force = */ 1);
+}
+
+int ds_unchecked_write_pebs(struct task_struct *task,
+			    const void *record, size_t size)
+{
+	return ds_write(task, record, size, ds_pebs, /* force = */ 1);
+}
+
+static int ds_reset_or_clear(struct task_struct *task,
+			     enum ds_qualifier qual, int clear)
+{
+	struct ds_context *context;
+	unsigned long base, end;
+	int error;
+
+	context = ds_get_context(task);
+	error = ds_validate_access(context, qual);
+	if (error < 0)
+		goto out;
+
+	base = ds_get(context->ds, qual, ds_buffer_base);
+	end  = ds_get(context->ds, qual, ds_absolute_maximum);
+
+	if (clear)
+		memset((void *)base, 0, end - base);
+
+	ds_set(context->ds, qual, ds_index, base);
+
+	error = 0;
+ out:
+	ds_put_context(context);
+	return error;
+}
+
+int ds_reset_bts(struct task_struct *task)
+{
+	return ds_reset_or_clear(task, ds_bts, /* clear = */ 0);
+}
+
+int ds_reset_pebs(struct task_struct *task)
+{
+	return ds_reset_or_clear(task, ds_pebs, /* clear = */ 0);
+}
+
+int ds_clear_bts(struct task_struct *task)
+{
+	return ds_reset_or_clear(task, ds_bts, /* clear = */ 1);
+}
+
+int ds_clear_pebs(struct task_struct *task)
+{
+	return ds_reset_or_clear(task, ds_pebs, /* clear = */ 1);
+}
+
+int ds_get_pebs_reset(struct task_struct *task, u64 *value)
+{
+	struct ds_context *context;
+	int error;
+
+	if (!value)
+		return -EINVAL;
+
+	context = ds_get_context(task);
+	error = ds_validate_access(context, ds_pebs);
+	if (error < 0)
+		goto out;
+
+	*value = *(u64 *)(context->ds + (ds_cfg.sizeof_field * 8));
+
+	error = 0;
+ out:
+	ds_put_context(context);
+	return error;
+}
+
+int ds_set_pebs_reset(struct task_struct *task, u64 value)
+{
+	struct ds_context *context;
+	int error;
+
+	context = ds_get_context(task);
+	error = ds_validate_access(context, ds_pebs);
+	if (error < 0)
+		goto out;
+
+	*(u64 *)(context->ds + (ds_cfg.sizeof_field * 8)) = value;
+
+	error = 0;
+ out:
+	ds_put_context(context);
+	return error;
+}
+
+static const struct ds_configuration ds_cfg_var = {
+	.sizeof_ds    = sizeof(long) * 12,
+	.sizeof_field = sizeof(long),
+	.sizeof_rec[ds_bts]   = sizeof(long) * 3,
+	.sizeof_rec[ds_pebs]  = sizeof(long) * 10
 };
-
-static const struct ds_configuration ds_cfg_pentium_m = {
-	.sizeof_ds = 9 * 4,
-	.bts_buffer_base = { 0, 4 },
-	.bts_index = { 4, 4 },
-	.bts_absolute_maximum = { 8, 4 },
-	.bts_interrupt_threshold = { 12, 4 },
-	.sizeof_bts = 3 * 4,
-	.from_ip = { 0, 4 },
-	.to_ip = { 4, 4 },
-	.info_type = { 4, 1 },
-	.info_data = { 8, 4 },
-	.debugctl_mask = (1<<6)|(1<<7)
-};
-#endif /* _i386_ */
-
-static const struct ds_configuration ds_cfg_core2 = {
-	.sizeof_ds = 9 * 8,
-	.bts_buffer_base = { 0, 8 },
-	.bts_index = { 8, 8 },
-	.bts_absolute_maximum = { 16, 8 },
-	.bts_interrupt_threshold = { 24, 8 },
-	.sizeof_bts = 3 * 8,
-	.from_ip = { 0, 8 },
-	.to_ip = { 8, 8 },
-	.info_type = { 8, 1 },
-	.info_data = { 16, 8 },
-	.debugctl_mask = (1<<6)|(1<<7)|(1<<9)
+static const struct ds_configuration ds_cfg_64 = {
+	.sizeof_ds    = 8 * 12,
+	.sizeof_field = 8,
+	.sizeof_rec[ds_bts]   = 8 * 3,
+	.sizeof_rec[ds_pebs]  = 8 * 10
 };
 
 static inline void
@@ -429,14 +821,13 @@
 	switch (c->x86) {
 	case 0x6:
 		switch (c->x86_model) {
-#ifdef __i386__
 		case 0xD:
 		case 0xE: /* Pentium M */
-			ds_configure(&ds_cfg_pentium_m);
+			ds_configure(&ds_cfg_var);
 			break;
-#endif /* _i386_ */
 		case 0xF: /* Core2 */
-			ds_configure(&ds_cfg_core2);
+		case 0x1C: /* Atom */
+			ds_configure(&ds_cfg_64);
 			break;
 		default:
 			/* sorry, don't know about them */
@@ -445,13 +836,11 @@
 		break;
 	case 0xF:
 		switch (c->x86_model) {
-#ifdef __i386__
 		case 0x0:
 		case 0x1:
 		case 0x2: /* Netburst */
-			ds_configure(&ds_cfg_netburst);
+			ds_configure(&ds_cfg_var);
 			break;
-#endif /* _i386_ */
 		default:
 			/* sorry, don't know about them */
 			break;
@@ -462,3 +851,14 @@
 		break;
 	}
 }
+
+void ds_free(struct ds_context *context)
+{
+	/* This is called when the task owning the parameter context
+	 * is dying. There should not be any user of that context left
+	 * to disturb us, anymore. */
+	unsigned long leftovers = context->count;
+	while (leftovers--)
+		ds_put_context(context);
+}
+#endif /* CONFIG_X86_DS */
diff --git a/arch/x86/kernel/dumpstack_32.c b/arch/x86/kernel/dumpstack_32.c
new file mode 100644
index 0000000..201ee35
--- /dev/null
+++ b/arch/x86/kernel/dumpstack_32.c
@@ -0,0 +1,447 @@
+/*
+ *  Copyright (C) 1991, 1992  Linus Torvalds
+ *  Copyright (C) 2000, 2001, 2002 Andi Kleen, SuSE Labs
+ */
+#include <linux/kallsyms.h>
+#include <linux/kprobes.h>
+#include <linux/uaccess.h>
+#include <linux/utsname.h>
+#include <linux/hardirq.h>
+#include <linux/kdebug.h>
+#include <linux/module.h>
+#include <linux/ptrace.h>
+#include <linux/kexec.h>
+#include <linux/bug.h>
+#include <linux/nmi.h>
+
+#include <asm/stacktrace.h>
+
+#define STACKSLOTS_PER_LINE 8
+#define get_bp(bp) asm("movl %%ebp, %0" : "=r" (bp) :)
+
+int panic_on_unrecovered_nmi;
+int kstack_depth_to_print = 3 * STACKSLOTS_PER_LINE;
+static unsigned int code_bytes = 64;
+static int die_counter;
+
+void printk_address(unsigned long address, int reliable)
+{
+	printk(" [<%p>] %s%pS\n", (void *) address,
+			reliable ? "" : "? ", (void *) address);
+}
+
+static inline int valid_stack_ptr(struct thread_info *tinfo,
+			void *p, unsigned int size, void *end)
+{
+	void *t = tinfo;
+	if (end) {
+		if (p < end && p >= (end-THREAD_SIZE))
+			return 1;
+		else
+			return 0;
+	}
+	return p > t && p < t + THREAD_SIZE - size;
+}
+
+/* The form of the top of the frame on the stack */
+struct stack_frame {
+	struct stack_frame *next_frame;
+	unsigned long return_address;
+};
+
+static inline unsigned long
+print_context_stack(struct thread_info *tinfo,
+		unsigned long *stack, unsigned long bp,
+		const struct stacktrace_ops *ops, void *data,
+		unsigned long *end)
+{
+	struct stack_frame *frame = (struct stack_frame *)bp;
+
+	while (valid_stack_ptr(tinfo, stack, sizeof(*stack), end)) {
+		unsigned long addr;
+
+		addr = *stack;
+		if (__kernel_text_address(addr)) {
+			if ((unsigned long) stack == bp + sizeof(long)) {
+				ops->address(data, addr, 1);
+				frame = frame->next_frame;
+				bp = (unsigned long) frame;
+			} else {
+				ops->address(data, addr, bp == 0);
+			}
+		}
+		stack++;
+	}
+	return bp;
+}
+
+void dump_trace(struct task_struct *task, struct pt_regs *regs,
+		unsigned long *stack, unsigned long bp,
+		const struct stacktrace_ops *ops, void *data)
+{
+	if (!task)
+		task = current;
+
+	if (!stack) {
+		unsigned long dummy;
+		stack = &dummy;
+		if (task && task != current)
+			stack = (unsigned long *)task->thread.sp;
+	}
+
+#ifdef CONFIG_FRAME_POINTER
+	if (!bp) {
+		if (task == current) {
+			/* Grab bp right from our regs */
+			get_bp(bp);
+		} else {
+			/* bp is the last reg pushed by switch_to */
+			bp = *(unsigned long *) task->thread.sp;
+		}
+	}
+#endif
+
+	for (;;) {
+		struct thread_info *context;
+
+		context = (struct thread_info *)
+			((unsigned long)stack & (~(THREAD_SIZE - 1)));
+		bp = print_context_stack(context, stack, bp, ops, data, NULL);
+
+		stack = (unsigned long *)context->previous_esp;
+		if (!stack)
+			break;
+		if (ops->stack(data, "IRQ") < 0)
+			break;
+		touch_nmi_watchdog();
+	}
+}
+EXPORT_SYMBOL(dump_trace);
+
+static void
+print_trace_warning_symbol(void *data, char *msg, unsigned long symbol)
+{
+	printk(data);
+	print_symbol(msg, symbol);
+	printk("\n");
+}
+
+static void print_trace_warning(void *data, char *msg)
+{
+	printk("%s%s\n", (char *)data, msg);
+}
+
+static int print_trace_stack(void *data, char *name)
+{
+	printk("%s <%s> ", (char *)data, name);
+	return 0;
+}
+
+/*
+ * Print one address/symbol entries per line.
+ */
+static void print_trace_address(void *data, unsigned long addr, int reliable)
+{
+	touch_nmi_watchdog();
+	printk(data);
+	printk_address(addr, reliable);
+}
+
+static const struct stacktrace_ops print_trace_ops = {
+	.warning = print_trace_warning,
+	.warning_symbol = print_trace_warning_symbol,
+	.stack = print_trace_stack,
+	.address = print_trace_address,
+};
+
+static void
+show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs,
+		unsigned long *stack, unsigned long bp, char *log_lvl)
+{
+	printk("%sCall Trace:\n", log_lvl);
+	dump_trace(task, regs, stack, bp, &print_trace_ops, log_lvl);
+}
+
+void show_trace(struct task_struct *task, struct pt_regs *regs,
+		unsigned long *stack, unsigned long bp)
+{
+	show_trace_log_lvl(task, regs, stack, bp, "");
+}
+
+static void
+show_stack_log_lvl(struct task_struct *task, struct pt_regs *regs,
+		unsigned long *sp, unsigned long bp, char *log_lvl)
+{
+	unsigned long *stack;
+	int i;
+
+	if (sp == NULL) {
+		if (task)
+			sp = (unsigned long *)task->thread.sp;
+		else
+			sp = (unsigned long *)&sp;
+	}
+
+	stack = sp;
+	for (i = 0; i < kstack_depth_to_print; i++) {
+		if (kstack_end(stack))
+			break;
+		if (i && ((i % STACKSLOTS_PER_LINE) == 0))
+			printk("\n%s", log_lvl);
+		printk(" %08lx", *stack++);
+		touch_nmi_watchdog();
+	}
+	printk("\n");
+	show_trace_log_lvl(task, regs, sp, bp, log_lvl);
+}
+
+void show_stack(struct task_struct *task, unsigned long *sp)
+{
+	show_stack_log_lvl(task, NULL, sp, 0, "");
+}
+
+/*
+ * The architecture-independent dump_stack generator
+ */
+void dump_stack(void)
+{
+	unsigned long bp = 0;
+	unsigned long stack;
+
+#ifdef CONFIG_FRAME_POINTER
+	if (!bp)
+		get_bp(bp);
+#endif
+
+	printk("Pid: %d, comm: %.20s %s %s %.*s\n",
+		current->pid, current->comm, print_tainted(),
+		init_utsname()->release,
+		(int)strcspn(init_utsname()->version, " "),
+		init_utsname()->version);
+	show_trace(NULL, NULL, &stack, bp);
+}
+
+EXPORT_SYMBOL(dump_stack);
+
+void show_registers(struct pt_regs *regs)
+{
+	int i;
+
+	print_modules();
+	__show_regs(regs, 0);
+
+	printk(KERN_EMERG "Process %.*s (pid: %d, ti=%p task=%p task.ti=%p)\n",
+		TASK_COMM_LEN, current->comm, task_pid_nr(current),
+		current_thread_info(), current, task_thread_info(current));
+	/*
+	 * When in-kernel, we also print out the stack and code at the
+	 * time of the fault..
+	 */
+	if (!user_mode_vm(regs)) {
+		unsigned int code_prologue = code_bytes * 43 / 64;
+		unsigned int code_len = code_bytes;
+		unsigned char c;
+		u8 *ip;
+
+		printk(KERN_EMERG "Stack:\n");
+		show_stack_log_lvl(NULL, regs, &regs->sp,
+				0, KERN_EMERG);
+
+		printk(KERN_EMERG "Code: ");
+
+		ip = (u8 *)regs->ip - code_prologue;
+		if (ip < (u8 *)PAGE_OFFSET || probe_kernel_address(ip, c)) {
+			/* try starting at IP */
+			ip = (u8 *)regs->ip;
+			code_len = code_len - code_prologue + 1;
+		}
+		for (i = 0; i < code_len; i++, ip++) {
+			if (ip < (u8 *)PAGE_OFFSET ||
+					probe_kernel_address(ip, c)) {
+				printk(" Bad EIP value.");
+				break;
+			}
+			if (ip == (u8 *)regs->ip)
+				printk("<%02x> ", c);
+			else
+				printk("%02x ", c);
+		}
+	}
+	printk("\n");
+}
+
+int is_valid_bugaddr(unsigned long ip)
+{
+	unsigned short ud2;
+
+	if (ip < PAGE_OFFSET)
+		return 0;
+	if (probe_kernel_address((unsigned short *)ip, ud2))
+		return 0;
+
+	return ud2 == 0x0b0f;
+}
+
+static raw_spinlock_t die_lock = __RAW_SPIN_LOCK_UNLOCKED;
+static int die_owner = -1;
+static unsigned int die_nest_count;
+
+unsigned __kprobes long oops_begin(void)
+{
+	unsigned long flags;
+
+	oops_enter();
+
+	if (die_owner != raw_smp_processor_id()) {
+		console_verbose();
+		raw_local_irq_save(flags);
+		__raw_spin_lock(&die_lock);
+		die_owner = smp_processor_id();
+		die_nest_count = 0;
+		bust_spinlocks(1);
+	} else {
+		raw_local_irq_save(flags);
+	}
+	die_nest_count++;
+	return flags;
+}
+
+void __kprobes oops_end(unsigned long flags, struct pt_regs *regs, int signr)
+{
+	bust_spinlocks(0);
+	die_owner = -1;
+	add_taint(TAINT_DIE);
+	__raw_spin_unlock(&die_lock);
+	raw_local_irq_restore(flags);
+
+	if (!regs)
+		return;
+
+	if (kexec_should_crash(current))
+		crash_kexec(regs);
+	if (in_interrupt())
+		panic("Fatal exception in interrupt");
+	if (panic_on_oops)
+		panic("Fatal exception");
+	oops_exit();
+	do_exit(signr);
+}
+
+int __kprobes __die(const char *str, struct pt_regs *regs, long err)
+{
+	unsigned short ss;
+	unsigned long sp;
+
+	printk(KERN_EMERG "%s: %04lx [#%d] ", str, err & 0xffff, ++die_counter);
+#ifdef CONFIG_PREEMPT
+	printk("PREEMPT ");
+#endif
+#ifdef CONFIG_SMP
+	printk("SMP ");
+#endif
+#ifdef CONFIG_DEBUG_PAGEALLOC
+	printk("DEBUG_PAGEALLOC");
+#endif
+	printk("\n");
+	if (notify_die(DIE_OOPS, str, regs, err,
+			current->thread.trap_no, SIGSEGV) == NOTIFY_STOP)
+		return 1;
+
+	show_registers(regs);
+	/* Executive summary in case the oops scrolled away */
+	sp = (unsigned long) (&regs->sp);
+	savesegment(ss, ss);
+	if (user_mode(regs)) {
+		sp = regs->sp;
+		ss = regs->ss & 0xffff;
+	}
+	printk(KERN_EMERG "EIP: [<%08lx>] ", regs->ip);
+	print_symbol("%s", regs->ip);
+	printk(" SS:ESP %04x:%08lx\n", ss, sp);
+	return 0;
+}
+
+/*
+ * This is gone through when something in the kernel has done something bad
+ * and is about to be terminated:
+ */
+void die(const char *str, struct pt_regs *regs, long err)
+{
+	unsigned long flags = oops_begin();
+
+	if (die_nest_count < 3) {
+		report_bug(regs->ip, regs);
+
+		if (__die(str, regs, err))
+			regs = NULL;
+	} else {
+		printk(KERN_EMERG "Recursive die() failure, output suppressed\n");
+	}
+
+	oops_end(flags, regs, SIGSEGV);
+}
+
+static DEFINE_SPINLOCK(nmi_print_lock);
+
+void notrace __kprobes
+die_nmi(char *str, struct pt_regs *regs, int do_panic)
+{
+	if (notify_die(DIE_NMIWATCHDOG, str, regs, 0, 2, SIGINT) == NOTIFY_STOP)
+		return;
+
+	spin_lock(&nmi_print_lock);
+	/*
+	* We are in trouble anyway, lets at least try
+	* to get a message out:
+	*/
+	bust_spinlocks(1);
+	printk(KERN_EMERG "%s", str);
+	printk(" on CPU%d, ip %08lx, registers:\n",
+		smp_processor_id(), regs->ip);
+	show_registers(regs);
+	if (do_panic)
+		panic("Non maskable interrupt");
+	console_silent();
+	spin_unlock(&nmi_print_lock);
+	bust_spinlocks(0);
+
+	/*
+	 * If we are in kernel we are probably nested up pretty bad
+	 * and might aswell get out now while we still can:
+	 */
+	if (!user_mode_vm(regs)) {
+		current->thread.trap_no = 2;
+		crash_kexec(regs);
+	}
+
+	do_exit(SIGSEGV);
+}
+
+static int __init oops_setup(char *s)
+{
+	if (!s)
+		return -EINVAL;
+	if (!strcmp(s, "panic"))
+		panic_on_oops = 1;
+	return 0;
+}
+early_param("oops", oops_setup);
+
+static int __init kstack_setup(char *s)
+{
+	if (!s)
+		return -EINVAL;
+	kstack_depth_to_print = simple_strtoul(s, NULL, 0);
+	return 0;
+}
+early_param("kstack", kstack_setup);
+
+static int __init code_bytes_setup(char *s)
+{
+	code_bytes = simple_strtoul(s, NULL, 0);
+	if (code_bytes > 8192)
+		code_bytes = 8192;
+
+	return 1;
+}
+__setup("code_bytes=", code_bytes_setup);
diff --git a/arch/x86/kernel/dumpstack_64.c b/arch/x86/kernel/dumpstack_64.c
new file mode 100644
index 0000000..086cc81
--- /dev/null
+++ b/arch/x86/kernel/dumpstack_64.c
@@ -0,0 +1,573 @@
+/*
+ *  Copyright (C) 1991, 1992  Linus Torvalds
+ *  Copyright (C) 2000, 2001, 2002 Andi Kleen, SuSE Labs
+ */
+#include <linux/kallsyms.h>
+#include <linux/kprobes.h>
+#include <linux/uaccess.h>
+#include <linux/utsname.h>
+#include <linux/hardirq.h>
+#include <linux/kdebug.h>
+#include <linux/module.h>
+#include <linux/ptrace.h>
+#include <linux/kexec.h>
+#include <linux/bug.h>
+#include <linux/nmi.h>
+
+#include <asm/stacktrace.h>
+
+#define STACKSLOTS_PER_LINE 4
+#define get_bp(bp) asm("movq %%rbp, %0" : "=r" (bp) :)
+
+int panic_on_unrecovered_nmi;
+int kstack_depth_to_print = 3 * STACKSLOTS_PER_LINE;
+static unsigned int code_bytes = 64;
+static int die_counter;
+
+void printk_address(unsigned long address, int reliable)
+{
+	printk(" [<%p>] %s%pS\n", (void *) address,
+			reliable ? "" : "? ", (void *) address);
+}
+
+static unsigned long *in_exception_stack(unsigned cpu, unsigned long stack,
+					unsigned *usedp, char **idp)
+{
+	static char ids[][8] = {
+		[DEBUG_STACK - 1] = "#DB",
+		[NMI_STACK - 1] = "NMI",
+		[DOUBLEFAULT_STACK - 1] = "#DF",
+		[STACKFAULT_STACK - 1] = "#SS",
+		[MCE_STACK - 1] = "#MC",
+#if DEBUG_STKSZ > EXCEPTION_STKSZ
+		[N_EXCEPTION_STACKS ...
+			N_EXCEPTION_STACKS + DEBUG_STKSZ / EXCEPTION_STKSZ - 2] = "#DB[?]"
+#endif
+	};
+	unsigned k;
+
+	/*
+	 * Iterate over all exception stacks, and figure out whether
+	 * 'stack' is in one of them:
+	 */
+	for (k = 0; k < N_EXCEPTION_STACKS; k++) {
+		unsigned long end = per_cpu(orig_ist, cpu).ist[k];
+		/*
+		 * Is 'stack' above this exception frame's end?
+		 * If yes then skip to the next frame.
+		 */
+		if (stack >= end)
+			continue;
+		/*
+		 * Is 'stack' above this exception frame's start address?
+		 * If yes then we found the right frame.
+		 */
+		if (stack >= end - EXCEPTION_STKSZ) {
+			/*
+			 * Make sure we only iterate through an exception
+			 * stack once. If it comes up for the second time
+			 * then there's something wrong going on - just
+			 * break out and return NULL:
+			 */
+			if (*usedp & (1U << k))
+				break;
+			*usedp |= 1U << k;
+			*idp = ids[k];
+			return (unsigned long *)end;
+		}
+		/*
+		 * If this is a debug stack, and if it has a larger size than
+		 * the usual exception stacks, then 'stack' might still
+		 * be within the lower portion of the debug stack:
+		 */
+#if DEBUG_STKSZ > EXCEPTION_STKSZ
+		if (k == DEBUG_STACK - 1 && stack >= end - DEBUG_STKSZ) {
+			unsigned j = N_EXCEPTION_STACKS - 1;
+
+			/*
+			 * Black magic. A large debug stack is composed of
+			 * multiple exception stack entries, which we
+			 * iterate through now. Dont look:
+			 */
+			do {
+				++j;
+				end -= EXCEPTION_STKSZ;
+				ids[j][4] = '1' + (j - N_EXCEPTION_STACKS);
+			} while (stack < end - EXCEPTION_STKSZ);
+			if (*usedp & (1U << j))
+				break;
+			*usedp |= 1U << j;
+			*idp = ids[j];
+			return (unsigned long *)end;
+		}
+#endif
+	}
+	return NULL;
+}
+
+/*
+ * x86-64 can have up to three kernel stacks:
+ * process stack
+ * interrupt stack
+ * severe exception (double fault, nmi, stack fault, debug, mce) hardware stack
+ */
+
+static inline int valid_stack_ptr(struct thread_info *tinfo,
+			void *p, unsigned int size, void *end)
+{
+	void *t = tinfo;
+	if (end) {
+		if (p < end && p >= (end-THREAD_SIZE))
+			return 1;
+		else
+			return 0;
+	}
+	return p > t && p < t + THREAD_SIZE - size;
+}
+
+/* The form of the top of the frame on the stack */
+struct stack_frame {
+	struct stack_frame *next_frame;
+	unsigned long return_address;
+};
+
+static inline unsigned long
+print_context_stack(struct thread_info *tinfo,
+		unsigned long *stack, unsigned long bp,
+		const struct stacktrace_ops *ops, void *data,
+		unsigned long *end)
+{
+	struct stack_frame *frame = (struct stack_frame *)bp;
+
+	while (valid_stack_ptr(tinfo, stack, sizeof(*stack), end)) {
+		unsigned long addr;
+
+		addr = *stack;
+		if (__kernel_text_address(addr)) {
+			if ((unsigned long) stack == bp + sizeof(long)) {
+				ops->address(data, addr, 1);
+				frame = frame->next_frame;
+				bp = (unsigned long) frame;
+			} else {
+				ops->address(data, addr, bp == 0);
+			}
+		}
+		stack++;
+	}
+	return bp;
+}
+
+void dump_trace(struct task_struct *task, struct pt_regs *regs,
+		unsigned long *stack, unsigned long bp,
+		const struct stacktrace_ops *ops, void *data)
+{
+	const unsigned cpu = get_cpu();
+	unsigned long *irqstack_end = (unsigned long *)cpu_pda(cpu)->irqstackptr;
+	unsigned used = 0;
+	struct thread_info *tinfo;
+
+	if (!task)
+		task = current;
+
+	if (!stack) {
+		unsigned long dummy;
+		stack = &dummy;
+		if (task && task != current)
+			stack = (unsigned long *)task->thread.sp;
+	}
+
+#ifdef CONFIG_FRAME_POINTER
+	if (!bp) {
+		if (task == current) {
+			/* Grab bp right from our regs */
+			get_bp(bp);
+		} else {
+			/* bp is the last reg pushed by switch_to */
+			bp = *(unsigned long *) task->thread.sp;
+		}
+	}
+#endif
+
+	/*
+	 * Print function call entries in all stacks, starting at the
+	 * current stack address. If the stacks consist of nested
+	 * exceptions
+	 */
+	tinfo = task_thread_info(task);
+	for (;;) {
+		char *id;
+		unsigned long *estack_end;
+		estack_end = in_exception_stack(cpu, (unsigned long)stack,
+						&used, &id);
+
+		if (estack_end) {
+			if (ops->stack(data, id) < 0)
+				break;
+
+			bp = print_context_stack(tinfo, stack, bp, ops,
+							data, estack_end);
+			ops->stack(data, "<EOE>");
+			/*
+			 * We link to the next stack via the
+			 * second-to-last pointer (index -2 to end) in the
+			 * exception stack:
+			 */
+			stack = (unsigned long *) estack_end[-2];
+			continue;
+		}
+		if (irqstack_end) {
+			unsigned long *irqstack;
+			irqstack = irqstack_end -
+				(IRQSTACKSIZE - 64) / sizeof(*irqstack);
+
+			if (stack >= irqstack && stack < irqstack_end) {
+				if (ops->stack(data, "IRQ") < 0)
+					break;
+				bp = print_context_stack(tinfo, stack, bp,
+						ops, data, irqstack_end);
+				/*
+				 * We link to the next stack (which would be
+				 * the process stack normally) the last
+				 * pointer (index -1 to end) in the IRQ stack:
+				 */
+				stack = (unsigned long *) (irqstack_end[-1]);
+				irqstack_end = NULL;
+				ops->stack(data, "EOI");
+				continue;
+			}
+		}
+		break;
+	}
+
+	/*
+	 * This handles the process stack:
+	 */
+	bp = print_context_stack(tinfo, stack, bp, ops, data, NULL);
+	put_cpu();
+}
+EXPORT_SYMBOL(dump_trace);
+
+static void
+print_trace_warning_symbol(void *data, char *msg, unsigned long symbol)
+{
+	printk(data);
+	print_symbol(msg, symbol);
+	printk("\n");
+}
+
+static void print_trace_warning(void *data, char *msg)
+{
+	printk("%s%s\n", (char *)data, msg);
+}
+
+static int print_trace_stack(void *data, char *name)
+{
+	printk("%s <%s> ", (char *)data, name);
+	return 0;
+}
+
+/*
+ * Print one address/symbol entries per line.
+ */
+static void print_trace_address(void *data, unsigned long addr, int reliable)
+{
+	touch_nmi_watchdog();
+	printk(data);
+	printk_address(addr, reliable);
+}
+
+static const struct stacktrace_ops print_trace_ops = {
+	.warning = print_trace_warning,
+	.warning_symbol = print_trace_warning_symbol,
+	.stack = print_trace_stack,
+	.address = print_trace_address,
+};
+
+static void
+show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs,
+		unsigned long *stack, unsigned long bp, char *log_lvl)
+{
+	printk("%sCall Trace:\n", log_lvl);
+	dump_trace(task, regs, stack, bp, &print_trace_ops, log_lvl);
+}
+
+void show_trace(struct task_struct *task, struct pt_regs *regs,
+		unsigned long *stack, unsigned long bp)
+{
+	show_trace_log_lvl(task, regs, stack, bp, "");
+}
+
+static void
+show_stack_log_lvl(struct task_struct *task, struct pt_regs *regs,
+		unsigned long *sp, unsigned long bp, char *log_lvl)
+{
+	unsigned long *stack;
+	int i;
+	const int cpu = smp_processor_id();
+	unsigned long *irqstack_end =
+		(unsigned long *) (cpu_pda(cpu)->irqstackptr);
+	unsigned long *irqstack =
+		(unsigned long *) (cpu_pda(cpu)->irqstackptr - IRQSTACKSIZE);
+
+	/*
+	 * debugging aid: "show_stack(NULL, NULL);" prints the
+	 * back trace for this cpu.
+	 */
+
+	if (sp == NULL) {
+		if (task)
+			sp = (unsigned long *)task->thread.sp;
+		else
+			sp = (unsigned long *)&sp;
+	}
+
+	stack = sp;
+	for (i = 0; i < kstack_depth_to_print; i++) {
+		if (stack >= irqstack && stack <= irqstack_end) {
+			if (stack == irqstack_end) {
+				stack = (unsigned long *) (irqstack_end[-1]);
+				printk(" <EOI> ");
+			}
+		} else {
+		if (((long) stack & (THREAD_SIZE-1)) == 0)
+			break;
+		}
+		if (i && ((i % STACKSLOTS_PER_LINE) == 0))
+			printk("\n%s", log_lvl);
+		printk(" %016lx", *stack++);
+		touch_nmi_watchdog();
+	}
+	printk("\n");
+	show_trace_log_lvl(task, regs, sp, bp, log_lvl);
+}
+
+void show_stack(struct task_struct *task, unsigned long *sp)
+{
+	show_stack_log_lvl(task, NULL, sp, 0, "");
+}
+
+/*
+ * The architecture-independent dump_stack generator
+ */
+void dump_stack(void)
+{
+	unsigned long bp = 0;
+	unsigned long stack;
+
+#ifdef CONFIG_FRAME_POINTER
+	if (!bp)
+		get_bp(bp);
+#endif
+
+	printk("Pid: %d, comm: %.20s %s %s %.*s\n",
+		current->pid, current->comm, print_tainted(),
+		init_utsname()->release,
+		(int)strcspn(init_utsname()->version, " "),
+		init_utsname()->version);
+	show_trace(NULL, NULL, &stack, bp);
+}
+EXPORT_SYMBOL(dump_stack);
+
+void show_registers(struct pt_regs *regs)
+{
+	int i;
+	unsigned long sp;
+	const int cpu = smp_processor_id();
+	struct task_struct *cur = cpu_pda(cpu)->pcurrent;
+
+	sp = regs->sp;
+	printk("CPU %d ", cpu);
+	__show_regs(regs, 1);
+	printk("Process %s (pid: %d, threadinfo %p, task %p)\n",
+		cur->comm, cur->pid, task_thread_info(cur), cur);
+
+	/*
+	 * When in-kernel, we also print out the stack and code at the
+	 * time of the fault..
+	 */
+	if (!user_mode(regs)) {
+		unsigned int code_prologue = code_bytes * 43 / 64;
+		unsigned int code_len = code_bytes;
+		unsigned char c;
+		u8 *ip;
+
+		printk(KERN_EMERG "Stack:\n");
+		show_stack_log_lvl(NULL, regs, (unsigned long *)sp,
+				regs->bp, KERN_EMERG);
+
+		printk(KERN_EMERG "Code: ");
+
+		ip = (u8 *)regs->ip - code_prologue;
+		if (ip < (u8 *)PAGE_OFFSET || probe_kernel_address(ip, c)) {
+			/* try starting at IP */
+			ip = (u8 *)regs->ip;
+			code_len = code_len - code_prologue + 1;
+		}
+		for (i = 0; i < code_len; i++, ip++) {
+			if (ip < (u8 *)PAGE_OFFSET ||
+					probe_kernel_address(ip, c)) {
+				printk(" Bad RIP value.");
+				break;
+			}
+			if (ip == (u8 *)regs->ip)
+				printk("<%02x> ", c);
+			else
+				printk("%02x ", c);
+		}
+	}
+	printk("\n");
+}
+
+int is_valid_bugaddr(unsigned long ip)
+{
+	unsigned short ud2;
+
+	if (__copy_from_user(&ud2, (const void __user *) ip, sizeof(ud2)))
+		return 0;
+
+	return ud2 == 0x0b0f;
+}
+
+static raw_spinlock_t die_lock = __RAW_SPIN_LOCK_UNLOCKED;
+static int die_owner = -1;
+static unsigned int die_nest_count;
+
+unsigned __kprobes long oops_begin(void)
+{
+	int cpu;
+	unsigned long flags;
+
+	oops_enter();
+
+	/* racy, but better than risking deadlock. */
+	raw_local_irq_save(flags);
+	cpu = smp_processor_id();
+	if (!__raw_spin_trylock(&die_lock)) {
+		if (cpu == die_owner)
+			/* nested oops. should stop eventually */;
+		else
+			__raw_spin_lock(&die_lock);
+	}
+	die_nest_count++;
+	die_owner = cpu;
+	console_verbose();
+	bust_spinlocks(1);
+	return flags;
+}
+
+void __kprobes oops_end(unsigned long flags, struct pt_regs *regs, int signr)
+{
+	die_owner = -1;
+	bust_spinlocks(0);
+	die_nest_count--;
+	if (!die_nest_count)
+		/* Nest count reaches zero, release the lock. */
+		__raw_spin_unlock(&die_lock);
+	raw_local_irq_restore(flags);
+	if (!regs) {
+		oops_exit();
+		return;
+	}
+	if (in_interrupt())
+		panic("Fatal exception in interrupt");
+	if (panic_on_oops)
+		panic("Fatal exception");
+	oops_exit();
+	do_exit(signr);
+}
+
+int __kprobes __die(const char *str, struct pt_regs *regs, long err)
+{
+	printk(KERN_EMERG "%s: %04lx [#%d] ", str, err & 0xffff, ++die_counter);
+#ifdef CONFIG_PREEMPT
+	printk("PREEMPT ");
+#endif
+#ifdef CONFIG_SMP
+	printk("SMP ");
+#endif
+#ifdef CONFIG_DEBUG_PAGEALLOC
+	printk("DEBUG_PAGEALLOC");
+#endif
+	printk("\n");
+	if (notify_die(DIE_OOPS, str, regs, err,
+			current->thread.trap_no, SIGSEGV) == NOTIFY_STOP)
+		return 1;
+
+	show_registers(regs);
+	add_taint(TAINT_DIE);
+	/* Executive summary in case the oops scrolled away */
+	printk(KERN_ALERT "RIP ");
+	printk_address(regs->ip, 1);
+	printk(" RSP <%016lx>\n", regs->sp);
+	if (kexec_should_crash(current))
+		crash_kexec(regs);
+	return 0;
+}
+
+void die(const char *str, struct pt_regs *regs, long err)
+{
+	unsigned long flags = oops_begin();
+
+	if (!user_mode(regs))
+		report_bug(regs->ip, regs);
+
+	if (__die(str, regs, err))
+		regs = NULL;
+	oops_end(flags, regs, SIGSEGV);
+}
+
+notrace __kprobes void
+die_nmi(char *str, struct pt_regs *regs, int do_panic)
+{
+	unsigned long flags;
+
+	if (notify_die(DIE_NMIWATCHDOG, str, regs, 0, 2, SIGINT) == NOTIFY_STOP)
+		return;
+
+	flags = oops_begin();
+	/*
+	 * We are in trouble anyway, lets at least try
+	 * to get a message out.
+	 */
+	printk(KERN_EMERG "%s", str);
+	printk(" on CPU%d, ip %08lx, registers:\n",
+		smp_processor_id(), regs->ip);
+	show_registers(regs);
+	if (kexec_should_crash(current))
+		crash_kexec(regs);
+	if (do_panic || panic_on_oops)
+		panic("Non maskable interrupt");
+	oops_end(flags, NULL, SIGBUS);
+	nmi_exit();
+	local_irq_enable();
+	do_exit(SIGBUS);
+}
+
+static int __init oops_setup(char *s)
+{
+	if (!s)
+		return -EINVAL;
+	if (!strcmp(s, "panic"))
+		panic_on_oops = 1;
+	return 0;
+}
+early_param("oops", oops_setup);
+
+static int __init kstack_setup(char *s)
+{
+	if (!s)
+		return -EINVAL;
+	kstack_depth_to_print = simple_strtoul(s, NULL, 0);
+	return 0;
+}
+early_param("kstack", kstack_setup);
+
+static int __init code_bytes_setup(char *s)
+{
+	code_bytes = simple_strtoul(s, NULL, 0);
+	if (code_bytes > 8192)
+		code_bytes = 8192;
+
+	return 1;
+}
+__setup("code_bytes=", code_bytes_setup);
diff --git a/arch/x86/kernel/e820.c b/arch/x86/kernel/e820.c
index 66e48aa..ce97bf3 100644
--- a/arch/x86/kernel/e820.c
+++ b/arch/x86/kernel/e820.c
@@ -148,6 +148,9 @@
 		case E820_NVS:
 			printk(KERN_CONT "(ACPI NVS)\n");
 			break;
+		case E820_UNUSABLE:
+			printk("(unusable)\n");
+			break;
 		default:
 			printk(KERN_CONT "type %u\n", e820.map[i].type);
 			break;
@@ -1260,6 +1263,7 @@
 	case E820_RAM:	return "System RAM";
 	case E820_ACPI:	return "ACPI Tables";
 	case E820_NVS:	return "ACPI Non-volatile Storage";
+	case E820_UNUSABLE:	return "Unusable memory";
 	default:	return "reserved";
 	}
 }
@@ -1267,6 +1271,7 @@
 /*
  * Mark e820 reserved areas as busy for the resource manager.
  */
+static struct resource __initdata *e820_res;
 void __init e820_reserve_resources(void)
 {
 	int i;
@@ -1274,20 +1279,26 @@
 	u64 end;
 
 	res = alloc_bootmem_low(sizeof(struct resource) * e820.nr_map);
+	e820_res = res;
 	for (i = 0; i < e820.nr_map; i++) {
 		end = e820.map[i].addr + e820.map[i].size - 1;
-#ifndef CONFIG_RESOURCES_64BIT
-		if (end > 0x100000000ULL) {
+		if (end != (resource_size_t)end) {
 			res++;
 			continue;
 		}
-#endif
 		res->name = e820_type_to_string(e820.map[i].type);
 		res->start = e820.map[i].addr;
 		res->end = end;
 
 		res->flags = IORESOURCE_MEM | IORESOURCE_BUSY;
-		insert_resource(&iomem_resource, res);
+
+		/*
+		 * don't register the region that could be conflicted with
+		 * pci device BAR resource and insert them later in
+		 * pcibios_resource_survey()
+		 */
+		if (e820.map[i].type != E820_RESERVED || res->start < (1ULL<<20))
+			insert_resource(&iomem_resource, res);
 		res++;
 	}
 
@@ -1299,6 +1310,19 @@
 	}
 }
 
+void __init e820_reserve_resources_late(void)
+{
+	int i;
+	struct resource *res;
+
+	res = e820_res;
+	for (i = 0; i < e820.nr_map; i++) {
+		if (!res->parent && res->end)
+			reserve_region_with_split(&iomem_resource, res->start, res->end, res->name);
+		res++;
+	}
+}
+
 char *__init default_machine_specific_memory_setup(void)
 {
 	char *who = "BIOS-e820";
diff --git a/arch/x86/kernel/early-quirks.c b/arch/x86/kernel/early-quirks.c
index 4353cf5..733c4f8 100644
--- a/arch/x86/kernel/early-quirks.c
+++ b/arch/x86/kernel/early-quirks.c
@@ -95,6 +95,66 @@
 
 }
 
+static u32 ati_ixp4x0_rev(int num, int slot, int func)
+{
+	u32 d;
+	u8  b;
+
+	b = read_pci_config_byte(num, slot, func, 0xac);
+	b &= ~(1<<5);
+	write_pci_config_byte(num, slot, func, 0xac, b);
+
+	d = read_pci_config(num, slot, func, 0x70);
+	d |= 1<<8;
+	write_pci_config(num, slot, func, 0x70, d);
+
+	d = read_pci_config(num, slot, func, 0x8);
+	d &= 0xff;
+	return d;
+}
+
+static void __init ati_bugs(int num, int slot, int func)
+{
+#if defined(CONFIG_ACPI) && defined (CONFIG_X86_IO_APIC)
+	u32 d;
+	u8  b;
+
+	if (acpi_use_timer_override)
+		return;
+
+	d = ati_ixp4x0_rev(num, slot, func);
+	if (d  < 0x82)
+		acpi_skip_timer_override = 1;
+	else {
+		/* check for IRQ0 interrupt swap */
+		outb(0x72, 0xcd6); b = inb(0xcd7);
+		if (!(b & 0x2))
+			acpi_skip_timer_override = 1;
+	}
+
+	if (acpi_skip_timer_override) {
+		printk(KERN_INFO "SB4X0 revision 0x%x\n", d);
+		printk(KERN_INFO "Ignoring ACPI timer override.\n");
+		printk(KERN_INFO "If you got timer trouble "
+		       "try acpi_use_timer_override\n");
+	}
+#endif
+}
+
+#ifdef CONFIG_DMAR
+static void __init intel_g33_dmar(int num, int slot, int func)
+{
+	struct acpi_table_header *dmar_tbl;
+	acpi_status status;
+
+	status = acpi_get_table(ACPI_SIG_DMAR, 0, &dmar_tbl);
+	if (ACPI_SUCCESS(status)) {
+		printk(KERN_INFO "BIOS BUG: DMAR advertised on Intel G31/G33 chipset -- ignoring\n");
+		dmar_disabled = 1;
+	}
+}
+#endif
+
 #define QFLAG_APPLY_ONCE 	0x1
 #define QFLAG_APPLIED		0x2
 #define QFLAG_DONE		(QFLAG_APPLY_ONCE|QFLAG_APPLIED)
@@ -114,6 +174,12 @@
 	  PCI_CLASS_BRIDGE_PCI, PCI_ANY_ID, QFLAG_APPLY_ONCE, via_bugs },
 	{ PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_K8_NB,
 	  PCI_CLASS_BRIDGE_HOST, PCI_ANY_ID, 0, fix_hypertransport_config },
+	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP400_SMBUS,
+	  PCI_CLASS_SERIAL_SMBUS, PCI_ANY_ID, 0, ati_bugs },
+#ifdef CONFIG_DMAR
+	{ PCI_VENDOR_ID_INTEL, 0x29c0,
+	  PCI_CLASS_BRIDGE_HOST, PCI_ANY_ID, 0, intel_g33_dmar },
+#endif
 	{}
 };
 
diff --git a/arch/x86/kernel/early_printk.c b/arch/x86/kernel/early_printk.c
index ff9e735..34ad997 100644
--- a/arch/x86/kernel/early_printk.c
+++ b/arch/x86/kernel/early_printk.c
@@ -3,11 +3,19 @@
 #include <linux/init.h>
 #include <linux/string.h>
 #include <linux/screen_info.h>
+#include <linux/usb/ch9.h>
+#include <linux/pci_regs.h>
+#include <linux/pci_ids.h>
+#include <linux/errno.h>
 #include <asm/io.h>
 #include <asm/processor.h>
 #include <asm/fcntl.h>
 #include <asm/setup.h>
 #include <xen/hvc-console.h>
+#include <asm/pci-direct.h>
+#include <asm/pgtable.h>
+#include <asm/fixmap.h>
+#include <linux/usb/ehci_def.h>
 
 /* Simple VGA output */
 #define VGABASE		(__ISA_IO_base + 0xb8000)
@@ -78,6 +86,7 @@
 static int early_serial_putc(unsigned char ch)
 {
 	unsigned timeout = 0xffff;
+
 	while ((inb(early_serial_base + LSR) & XMTRDY) == 0 && --timeout)
 		cpu_relax();
 	outb(ch, early_serial_base + TXR);
@@ -111,7 +120,7 @@
 		if (!strncmp(s, "0x", 2)) {
 			early_serial_base = simple_strtoul(s, &e, 16);
 		} else {
-			static int bases[] = { 0x3f8, 0x2f8 };
+			static const int __initconst bases[] = { 0x3f8, 0x2f8 };
 
 			if (!strncmp(s, "ttyS", 4))
 				s += 4;
@@ -151,6 +160,721 @@
 	.index =	-1,
 };
 
+#ifdef CONFIG_EARLY_PRINTK_DBGP
+
+static struct ehci_caps __iomem *ehci_caps;
+static struct ehci_regs __iomem *ehci_regs;
+static struct ehci_dbg_port __iomem *ehci_debug;
+static unsigned int dbgp_endpoint_out;
+
+struct ehci_dev {
+	u32 bus;
+	u32 slot;
+	u32 func;
+};
+
+static struct ehci_dev ehci_dev;
+
+#define USB_DEBUG_DEVNUM 127
+
+#define DBGP_DATA_TOGGLE	0x8800
+
+static inline u32 dbgp_pid_update(u32 x, u32 tok)
+{
+	return ((x ^ DBGP_DATA_TOGGLE) & 0xffff00) | (tok & 0xff);
+}
+
+static inline u32 dbgp_len_update(u32 x, u32 len)
+{
+	return (x & ~0x0f) | (len & 0x0f);
+}
+
+/*
+ * USB Packet IDs (PIDs)
+ */
+
+/* token */
+#define USB_PID_OUT		0xe1
+#define USB_PID_IN		0x69
+#define USB_PID_SOF		0xa5
+#define USB_PID_SETUP		0x2d
+/* handshake */
+#define USB_PID_ACK		0xd2
+#define USB_PID_NAK		0x5a
+#define USB_PID_STALL		0x1e
+#define USB_PID_NYET		0x96
+/* data */
+#define USB_PID_DATA0		0xc3
+#define USB_PID_DATA1		0x4b
+#define USB_PID_DATA2		0x87
+#define USB_PID_MDATA		0x0f
+/* Special */
+#define USB_PID_PREAMBLE	0x3c
+#define USB_PID_ERR		0x3c
+#define USB_PID_SPLIT		0x78
+#define USB_PID_PING		0xb4
+#define USB_PID_UNDEF_0		0xf0
+
+#define USB_PID_DATA_TOGGLE	0x88
+#define DBGP_CLAIM (DBGP_OWNER | DBGP_ENABLED | DBGP_INUSE)
+
+#define PCI_CAP_ID_EHCI_DEBUG	0xa
+
+#define HUB_ROOT_RESET_TIME	50	/* times are in msec */
+#define HUB_SHORT_RESET_TIME	10
+#define HUB_LONG_RESET_TIME	200
+#define HUB_RESET_TIMEOUT	500
+
+#define DBGP_MAX_PACKET		8
+
+static int dbgp_wait_until_complete(void)
+{
+	u32 ctrl;
+	int loop = 0x100000;
+
+	do {
+		ctrl = readl(&ehci_debug->control);
+		/* Stop when the transaction is finished */
+		if (ctrl & DBGP_DONE)
+			break;
+	} while (--loop > 0);
+
+	if (!loop)
+		return -1;
+
+	/*
+	 * Now that we have observed the completed transaction,
+	 * clear the done bit.
+	 */
+	writel(ctrl | DBGP_DONE, &ehci_debug->control);
+	return (ctrl & DBGP_ERROR) ? -DBGP_ERRCODE(ctrl) : DBGP_LEN(ctrl);
+}
+
+static void dbgp_mdelay(int ms)
+{
+	int i;
+
+	while (ms--) {
+		for (i = 0; i < 1000; i++)
+			outb(0x1, 0x80);
+	}
+}
+
+static void dbgp_breath(void)
+{
+	/* Sleep to give the debug port a chance to breathe */
+}
+
+static int dbgp_wait_until_done(unsigned ctrl)
+{
+	u32 pids, lpid;
+	int ret;
+	int loop = 3;
+
+retry:
+	writel(ctrl | DBGP_GO, &ehci_debug->control);
+	ret = dbgp_wait_until_complete();
+	pids = readl(&ehci_debug->pids);
+	lpid = DBGP_PID_GET(pids);
+
+	if (ret < 0)
+		return ret;
+
+	/*
+	 * If the port is getting full or it has dropped data
+	 * start pacing ourselves, not necessary but it's friendly.
+	 */
+	if ((lpid == USB_PID_NAK) || (lpid == USB_PID_NYET))
+		dbgp_breath();
+
+	/* If I get a NACK reissue the transmission */
+	if (lpid == USB_PID_NAK) {
+		if (--loop > 0)
+			goto retry;
+	}
+
+	return ret;
+}
+
+static void dbgp_set_data(const void *buf, int size)
+{
+	const unsigned char *bytes = buf;
+	u32 lo, hi;
+	int i;
+
+	lo = hi = 0;
+	for (i = 0; i < 4 && i < size; i++)
+		lo |= bytes[i] << (8*i);
+	for (; i < 8 && i < size; i++)
+		hi |= bytes[i] << (8*(i - 4));
+	writel(lo, &ehci_debug->data03);
+	writel(hi, &ehci_debug->data47);
+}
+
+static void dbgp_get_data(void *buf, int size)
+{
+	unsigned char *bytes = buf;
+	u32 lo, hi;
+	int i;
+
+	lo = readl(&ehci_debug->data03);
+	hi = readl(&ehci_debug->data47);
+	for (i = 0; i < 4 && i < size; i++)
+		bytes[i] = (lo >> (8*i)) & 0xff;
+	for (; i < 8 && i < size; i++)
+		bytes[i] = (hi >> (8*(i - 4))) & 0xff;
+}
+
+static int dbgp_bulk_write(unsigned devnum, unsigned endpoint,
+			 const char *bytes, int size)
+{
+	u32 pids, addr, ctrl;
+	int ret;
+
+	if (size > DBGP_MAX_PACKET)
+		return -1;
+
+	addr = DBGP_EPADDR(devnum, endpoint);
+
+	pids = readl(&ehci_debug->pids);
+	pids = dbgp_pid_update(pids, USB_PID_OUT);
+
+	ctrl = readl(&ehci_debug->control);
+	ctrl = dbgp_len_update(ctrl, size);
+	ctrl |= DBGP_OUT;
+	ctrl |= DBGP_GO;
+
+	dbgp_set_data(bytes, size);
+	writel(addr, &ehci_debug->address);
+	writel(pids, &ehci_debug->pids);
+
+	ret = dbgp_wait_until_done(ctrl);
+	if (ret < 0)
+		return ret;
+
+	return ret;
+}
+
+static int dbgp_bulk_read(unsigned devnum, unsigned endpoint, void *data,
+				 int size)
+{
+	u32 pids, addr, ctrl;
+	int ret;
+
+	if (size > DBGP_MAX_PACKET)
+		return -1;
+
+	addr = DBGP_EPADDR(devnum, endpoint);
+
+	pids = readl(&ehci_debug->pids);
+	pids = dbgp_pid_update(pids, USB_PID_IN);
+
+	ctrl = readl(&ehci_debug->control);
+	ctrl = dbgp_len_update(ctrl, size);
+	ctrl &= ~DBGP_OUT;
+	ctrl |= DBGP_GO;
+
+	writel(addr, &ehci_debug->address);
+	writel(pids, &ehci_debug->pids);
+	ret = dbgp_wait_until_done(ctrl);
+	if (ret < 0)
+		return ret;
+
+	if (size > ret)
+		size = ret;
+	dbgp_get_data(data, size);
+	return ret;
+}
+
+static int dbgp_control_msg(unsigned devnum, int requesttype, int request,
+	int value, int index, void *data, int size)
+{
+	u32 pids, addr, ctrl;
+	struct usb_ctrlrequest req;
+	int read;
+	int ret;
+
+	read = (requesttype & USB_DIR_IN) != 0;
+	if (size > (read ? DBGP_MAX_PACKET:0))
+		return -1;
+
+	/* Compute the control message */
+	req.bRequestType = requesttype;
+	req.bRequest = request;
+	req.wValue = cpu_to_le16(value);
+	req.wIndex = cpu_to_le16(index);
+	req.wLength = cpu_to_le16(size);
+
+	pids = DBGP_PID_SET(USB_PID_DATA0, USB_PID_SETUP);
+	addr = DBGP_EPADDR(devnum, 0);
+
+	ctrl = readl(&ehci_debug->control);
+	ctrl = dbgp_len_update(ctrl, sizeof(req));
+	ctrl |= DBGP_OUT;
+	ctrl |= DBGP_GO;
+
+	/* Send the setup message */
+	dbgp_set_data(&req, sizeof(req));
+	writel(addr, &ehci_debug->address);
+	writel(pids, &ehci_debug->pids);
+	ret = dbgp_wait_until_done(ctrl);
+	if (ret < 0)
+		return ret;
+
+	/* Read the result */
+	return dbgp_bulk_read(devnum, 0, data, size);
+}
+
+
+/* Find a PCI capability */
+static u32 __init find_cap(u32 num, u32 slot, u32 func, int cap)
+{
+	u8 pos;
+	int bytes;
+
+	if (!(read_pci_config_16(num, slot, func, PCI_STATUS) &
+		PCI_STATUS_CAP_LIST))
+		return 0;
+
+	pos = read_pci_config_byte(num, slot, func, PCI_CAPABILITY_LIST);
+	for (bytes = 0; bytes < 48 && pos >= 0x40; bytes++) {
+		u8 id;
+
+		pos &= ~3;
+		id = read_pci_config_byte(num, slot, func, pos+PCI_CAP_LIST_ID);
+		if (id == 0xff)
+			break;
+		if (id == cap)
+			return pos;
+
+		pos = read_pci_config_byte(num, slot, func,
+						 pos+PCI_CAP_LIST_NEXT);
+	}
+	return 0;
+}
+
+static u32 __init __find_dbgp(u32 bus, u32 slot, u32 func)
+{
+	u32 class;
+
+	class = read_pci_config(bus, slot, func, PCI_CLASS_REVISION);
+	if ((class >> 8) != PCI_CLASS_SERIAL_USB_EHCI)
+		return 0;
+
+	return find_cap(bus, slot, func, PCI_CAP_ID_EHCI_DEBUG);
+}
+
+static u32 __init find_dbgp(int ehci_num, u32 *rbus, u32 *rslot, u32 *rfunc)
+{
+	u32 bus, slot, func;
+
+	for (bus = 0; bus < 256; bus++) {
+		for (slot = 0; slot < 32; slot++) {
+			for (func = 0; func < 8; func++) {
+				unsigned cap;
+
+				cap = __find_dbgp(bus, slot, func);
+
+				if (!cap)
+					continue;
+				if (ehci_num-- != 0)
+					continue;
+				*rbus = bus;
+				*rslot = slot;
+				*rfunc = func;
+				return cap;
+			}
+		}
+	}
+	return 0;
+}
+
+static int ehci_reset_port(int port)
+{
+	u32 portsc;
+	u32 delay_time, delay;
+	int loop;
+
+	/* Reset the usb debug port */
+	portsc = readl(&ehci_regs->port_status[port - 1]);
+	portsc &= ~PORT_PE;
+	portsc |= PORT_RESET;
+	writel(portsc, &ehci_regs->port_status[port - 1]);
+
+	delay = HUB_ROOT_RESET_TIME;
+	for (delay_time = 0; delay_time < HUB_RESET_TIMEOUT;
+	     delay_time += delay) {
+		dbgp_mdelay(delay);
+
+		portsc = readl(&ehci_regs->port_status[port - 1]);
+		if (portsc & PORT_RESET) {
+			/* force reset to complete */
+			loop = 2;
+			writel(portsc & ~(PORT_RWC_BITS | PORT_RESET),
+				&ehci_regs->port_status[port - 1]);
+			do {
+				portsc = readl(&ehci_regs->port_status[port-1]);
+			} while ((portsc & PORT_RESET) && (--loop > 0));
+		}
+
+		/* Device went away? */
+		if (!(portsc & PORT_CONNECT))
+			return -ENOTCONN;
+
+		/* bomb out completely if something weird happend */
+		if ((portsc & PORT_CSC))
+			return -EINVAL;
+
+		/* If we've finished resetting, then break out of the loop */
+		if (!(portsc & PORT_RESET) && (portsc & PORT_PE))
+			return 0;
+	}
+	return -EBUSY;
+}
+
+static int ehci_wait_for_port(int port)
+{
+	u32 status;
+	int ret, reps;
+
+	for (reps = 0; reps < 3; reps++) {
+		dbgp_mdelay(100);
+		status = readl(&ehci_regs->status);
+		if (status & STS_PCD) {
+			ret = ehci_reset_port(port);
+			if (ret == 0)
+				return 0;
+		}
+	}
+	return -ENOTCONN;
+}
+
+#ifdef DBGP_DEBUG
+# define dbgp_printk early_printk
+#else
+static inline void dbgp_printk(const char *fmt, ...) { }
+#endif
+
+typedef void (*set_debug_port_t)(int port);
+
+static void default_set_debug_port(int port)
+{
+}
+
+static set_debug_port_t set_debug_port = default_set_debug_port;
+
+static void nvidia_set_debug_port(int port)
+{
+	u32 dword;
+	dword = read_pci_config(ehci_dev.bus, ehci_dev.slot, ehci_dev.func,
+				 0x74);
+	dword &= ~(0x0f<<12);
+	dword |= ((port & 0x0f)<<12);
+	write_pci_config(ehci_dev.bus, ehci_dev.slot, ehci_dev.func, 0x74,
+				 dword);
+	dbgp_printk("set debug port to %d\n", port);
+}
+
+static void __init detect_set_debug_port(void)
+{
+	u32 vendorid;
+
+	vendorid = read_pci_config(ehci_dev.bus, ehci_dev.slot, ehci_dev.func,
+		 0x00);
+
+	if ((vendorid & 0xffff) == 0x10de) {
+		dbgp_printk("using nvidia set_debug_port\n");
+		set_debug_port = nvidia_set_debug_port;
+	}
+}
+
+static int __init ehci_setup(void)
+{
+	struct usb_debug_descriptor dbgp_desc;
+	u32 cmd, ctrl, status, portsc, hcs_params;
+	u32 debug_port, new_debug_port = 0, n_ports;
+	u32  devnum;
+	int ret, i;
+	int loop;
+	int port_map_tried;
+	int playtimes = 3;
+
+try_next_time:
+	port_map_tried = 0;
+
+try_next_port:
+
+	hcs_params = readl(&ehci_caps->hcs_params);
+	debug_port = HCS_DEBUG_PORT(hcs_params);
+	n_ports    = HCS_N_PORTS(hcs_params);
+
+	dbgp_printk("debug_port: %d\n", debug_port);
+	dbgp_printk("n_ports:    %d\n", n_ports);
+
+	for (i = 1; i <= n_ports; i++) {
+		portsc = readl(&ehci_regs->port_status[i-1]);
+		dbgp_printk("portstatus%d: %08x\n", i, portsc);
+	}
+
+	if (port_map_tried && (new_debug_port != debug_port)) {
+		if (--playtimes) {
+			set_debug_port(new_debug_port);
+			goto try_next_time;
+		}
+		return -1;
+	}
+
+	loop = 10;
+	/* Reset the EHCI controller */
+	cmd = readl(&ehci_regs->command);
+	cmd |= CMD_RESET;
+	writel(cmd, &ehci_regs->command);
+	do {
+		cmd = readl(&ehci_regs->command);
+	} while ((cmd & CMD_RESET) && (--loop > 0));
+
+	if (!loop) {
+		dbgp_printk("can not reset ehci\n");
+		return -1;
+	}
+	dbgp_printk("ehci reset done\n");
+
+	/* Claim ownership, but do not enable yet */
+	ctrl = readl(&ehci_debug->control);
+	ctrl |= DBGP_OWNER;
+	ctrl &= ~(DBGP_ENABLED | DBGP_INUSE);
+	writel(ctrl, &ehci_debug->control);
+
+	/* Start the ehci running */
+	cmd = readl(&ehci_regs->command);
+	cmd &= ~(CMD_LRESET | CMD_IAAD | CMD_PSE | CMD_ASE | CMD_RESET);
+	cmd |= CMD_RUN;
+	writel(cmd, &ehci_regs->command);
+
+	/* Ensure everything is routed to the EHCI */
+	writel(FLAG_CF, &ehci_regs->configured_flag);
+
+	/* Wait until the controller is no longer halted */
+	loop = 10;
+	do {
+		status = readl(&ehci_regs->status);
+	} while ((status & STS_HALT) && (--loop > 0));
+
+	if (!loop) {
+		dbgp_printk("ehci can be started\n");
+		return -1;
+	}
+	dbgp_printk("ehci started\n");
+
+	/* Wait for a device to show up in the debug port */
+	ret = ehci_wait_for_port(debug_port);
+	if (ret < 0) {
+		dbgp_printk("No device found in debug port\n");
+		goto next_debug_port;
+	}
+	dbgp_printk("ehci wait for port done\n");
+
+	/* Enable the debug port */
+	ctrl = readl(&ehci_debug->control);
+	ctrl |= DBGP_CLAIM;
+	writel(ctrl, &ehci_debug->control);
+	ctrl = readl(&ehci_debug->control);
+	if ((ctrl & DBGP_CLAIM) != DBGP_CLAIM) {
+		dbgp_printk("No device in debug port\n");
+		writel(ctrl & ~DBGP_CLAIM, &ehci_debug->control);
+		goto err;
+	}
+	dbgp_printk("debug ported enabled\n");
+
+	/* Completely transfer the debug device to the debug controller */
+	portsc = readl(&ehci_regs->port_status[debug_port - 1]);
+	portsc &= ~PORT_PE;
+	writel(portsc, &ehci_regs->port_status[debug_port - 1]);
+
+	dbgp_mdelay(100);
+
+	/* Find the debug device and make it device number 127 */
+	for (devnum = 0; devnum <= 127; devnum++) {
+		ret = dbgp_control_msg(devnum,
+			USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE,
+			USB_REQ_GET_DESCRIPTOR, (USB_DT_DEBUG << 8), 0,
+			&dbgp_desc, sizeof(dbgp_desc));
+		if (ret > 0)
+			break;
+	}
+	if (devnum > 127) {
+		dbgp_printk("Could not find attached debug device\n");
+		goto err;
+	}
+	if (ret < 0) {
+		dbgp_printk("Attached device is not a debug device\n");
+		goto err;
+	}
+	dbgp_endpoint_out = dbgp_desc.bDebugOutEndpoint;
+
+	/* Move the device to 127 if it isn't already there */
+	if (devnum != USB_DEBUG_DEVNUM) {
+		ret = dbgp_control_msg(devnum,
+			USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE,
+			USB_REQ_SET_ADDRESS, USB_DEBUG_DEVNUM, 0, NULL, 0);
+		if (ret < 0) {
+			dbgp_printk("Could not move attached device to %d\n",
+				USB_DEBUG_DEVNUM);
+			goto err;
+		}
+		devnum = USB_DEBUG_DEVNUM;
+		dbgp_printk("debug device renamed to 127\n");
+	}
+
+	/* Enable the debug interface */
+	ret = dbgp_control_msg(USB_DEBUG_DEVNUM,
+		USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE,
+		USB_REQ_SET_FEATURE, USB_DEVICE_DEBUG_MODE, 0, NULL, 0);
+	if (ret < 0) {
+		dbgp_printk(" Could not enable the debug device\n");
+		goto err;
+	}
+	dbgp_printk("debug interface enabled\n");
+
+	/* Perform a small write to get the even/odd data state in sync
+	 */
+	ret = dbgp_bulk_write(USB_DEBUG_DEVNUM, dbgp_endpoint_out, " ", 1);
+	if (ret < 0) {
+		dbgp_printk("dbgp_bulk_write failed: %d\n", ret);
+		goto err;
+	}
+	dbgp_printk("small write doned\n");
+
+	return 0;
+err:
+	/* Things didn't work so remove my claim */
+	ctrl = readl(&ehci_debug->control);
+	ctrl &= ~(DBGP_CLAIM | DBGP_OUT);
+	writel(ctrl, &ehci_debug->control);
+	return -1;
+
+next_debug_port:
+	port_map_tried |= (1<<(debug_port - 1));
+	new_debug_port = ((debug_port-1+1)%n_ports) + 1;
+	if (port_map_tried != ((1<<n_ports) - 1)) {
+		set_debug_port(new_debug_port);
+		goto try_next_port;
+	}
+	if (--playtimes) {
+		set_debug_port(new_debug_port);
+		goto try_next_time;
+	}
+
+	return -1;
+}
+
+static int __init early_dbgp_init(char *s)
+{
+	u32 debug_port, bar, offset;
+	u32 bus, slot, func, cap;
+	void __iomem *ehci_bar;
+	u32 dbgp_num;
+	u32 bar_val;
+	char *e;
+	int ret;
+	u8 byte;
+
+	if (!early_pci_allowed())
+		return -1;
+
+	dbgp_num = 0;
+	if (*s)
+		dbgp_num = simple_strtoul(s, &e, 10);
+	dbgp_printk("dbgp_num: %d\n", dbgp_num);
+
+	cap = find_dbgp(dbgp_num, &bus, &slot, &func);
+	if (!cap)
+		return -1;
+
+	dbgp_printk("Found EHCI debug port on %02x:%02x.%1x\n", bus, slot,
+			 func);
+
+	debug_port = read_pci_config(bus, slot, func, cap);
+	bar = (debug_port >> 29) & 0x7;
+	bar = (bar * 4) + 0xc;
+	offset = (debug_port >> 16) & 0xfff;
+	dbgp_printk("bar: %02x offset: %03x\n", bar, offset);
+	if (bar != PCI_BASE_ADDRESS_0) {
+		dbgp_printk("only debug ports on bar 1 handled.\n");
+
+		return -1;
+	}
+
+	bar_val = read_pci_config(bus, slot, func, PCI_BASE_ADDRESS_0);
+	dbgp_printk("bar_val: %02x offset: %03x\n", bar_val, offset);
+	if (bar_val & ~PCI_BASE_ADDRESS_MEM_MASK) {
+		dbgp_printk("only simple 32bit mmio bars supported\n");
+
+		return -1;
+	}
+
+	/* double check if the mem space is enabled */
+	byte = read_pci_config_byte(bus, slot, func, 0x04);
+	if (!(byte & 0x2)) {
+		byte  |= 0x02;
+		write_pci_config_byte(bus, slot, func, 0x04, byte);
+		dbgp_printk("mmio for ehci enabled\n");
+	}
+
+	/*
+	 * FIXME I don't have the bar size so just guess PAGE_SIZE is more
+	 * than enough.  1K is the biggest I have seen.
+	 */
+	set_fixmap_nocache(FIX_DBGP_BASE, bar_val & PAGE_MASK);
+	ehci_bar = (void __iomem *)__fix_to_virt(FIX_DBGP_BASE);
+	ehci_bar += bar_val & ~PAGE_MASK;
+	dbgp_printk("ehci_bar: %p\n", ehci_bar);
+
+	ehci_caps  = ehci_bar;
+	ehci_regs  = ehci_bar + HC_LENGTH(readl(&ehci_caps->hc_capbase));
+	ehci_debug = ehci_bar + offset;
+	ehci_dev.bus = bus;
+	ehci_dev.slot = slot;
+	ehci_dev.func = func;
+
+	detect_set_debug_port();
+
+	ret = ehci_setup();
+	if (ret < 0) {
+		dbgp_printk("ehci_setup failed\n");
+		ehci_debug = NULL;
+
+		return -1;
+	}
+
+	return 0;
+}
+
+static void early_dbgp_write(struct console *con, const char *str, u32 n)
+{
+	int chunk, ret;
+
+	if (!ehci_debug)
+		return;
+	while (n > 0) {
+		chunk = n;
+		if (chunk > DBGP_MAX_PACKET)
+			chunk = DBGP_MAX_PACKET;
+		ret = dbgp_bulk_write(USB_DEBUG_DEVNUM,
+			dbgp_endpoint_out, str, chunk);
+		str += chunk;
+		n -= chunk;
+	}
+}
+
+static struct console early_dbgp_console = {
+	.name =		"earlydbg",
+	.write =	early_dbgp_write,
+	.flags =	CON_PRINTBUFFER,
+	.index =	-1,
+};
+#endif
+
 /* Console interface to a host file on AMD's SimNow! */
 
 static int simnow_fd;
@@ -165,6 +889,7 @@
 static noinline long simnow(long cmd, long a, long b, long c)
 {
 	long ret;
+
 	asm volatile("cpuid" :
 		     "=a" (ret) :
 		     "b" (a), "c" (b), "d" (c), "0" (MAGIC1), "D" (cmd + MAGIC2));
@@ -174,6 +899,7 @@
 static void __init simnow_init(char *str)
 {
 	char *fn = "klog";
+
 	if (*str == '=')
 		fn = ++str;
 	/* error ignored */
@@ -194,7 +920,7 @@
 
 /* Direct interface for emergencies */
 static struct console *early_console = &early_vga_console;
-static int early_console_initialized;
+static int __initdata early_console_initialized;
 
 asmlinkage void early_printk(const char *fmt, ...)
 {
@@ -208,10 +934,11 @@
 	va_end(ap);
 }
 
-static int __initdata keep_early;
 
 static int __init setup_early_printk(char *buf)
 {
+	int keep_early;
+
 	if (!buf)
 		return 0;
 
@@ -219,8 +946,7 @@
 		return 0;
 	early_console_initialized = 1;
 
-	if (strstr(buf, "keep"))
-		keep_early = 1;
+	keep_early = (strstr(buf, "keep") != NULL);
 
 	if (!strncmp(buf, "serial", 6)) {
 		early_serial_init(buf + 6);
@@ -238,6 +964,17 @@
 		simnow_init(buf + 6);
 		early_console = &simnow_console;
 		keep_early = 1;
+#ifdef CONFIG_EARLY_PRINTK_DBGP
+	} else if (!strncmp(buf, "dbgp", 4)) {
+		if (early_dbgp_init(buf+4) < 0)
+			return 0;
+		early_console = &early_dbgp_console;
+		/*
+		 * usb subsys will reset ehci controller, so don't keep
+		 * that early console
+		 */
+		keep_early = 0;
+#endif
 #ifdef CONFIG_HVC_XEN
 	} else if (!strncmp(buf, "xen", 3)) {
 		early_console = &xenboot_console;
@@ -251,4 +988,5 @@
 	register_console(early_console);
 	return 0;
 }
+
 early_param("earlyprintk", setup_early_printk);
diff --git a/arch/x86/kernel/efi.c b/arch/x86/kernel/efi.c
index 06cc8d4..945a31c 100644
--- a/arch/x86/kernel/efi.c
+++ b/arch/x86/kernel/efi.c
@@ -414,9 +414,11 @@
 	if (memmap.map == NULL)
 		printk(KERN_ERR "Could not map the EFI memory map!\n");
 	memmap.map_end = memmap.map + (memmap.nr_map * memmap.desc_size);
+
 	if (memmap.desc_size != sizeof(efi_memory_desc_t))
-		printk(KERN_WARNING "Kernel-defined memdesc"
-		       "doesn't match the one from EFI!\n");
+		printk(KERN_WARNING
+		  "Kernel-defined memdesc doesn't match the one from EFI!\n");
+
 	if (add_efi_memmap)
 		do_add_efi_memmap();
 
diff --git a/arch/x86/kernel/entry_32.S b/arch/x86/kernel/entry_32.S
index 109792b..b21fbfa 100644
--- a/arch/x86/kernel/entry_32.S
+++ b/arch/x86/kernel/entry_32.S
@@ -730,6 +730,7 @@
 	movl $(__USER_DS), %ecx
 	movl %ecx, %ds
 	movl %ecx, %es
+	TRACE_IRQS_OFF
 	movl %esp,%eax			# pt_regs pointer
 	call *%edi
 	jmp ret_from_exception
@@ -760,20 +761,9 @@
 	RING0_INT_FRAME
 	pushl $-1			# mark this as an int
 	CFI_ADJUST_CFA_OFFSET 4
-	SAVE_ALL
-	GET_CR0_INTO_EAX
-	testl $0x4, %eax		# EM (math emulation bit)
-	jne device_not_available_emulate
-	preempt_stop(CLBR_ANY)
-	call math_state_restore
-	jmp ret_from_exception
-device_not_available_emulate:
-	pushl $0			# temporary storage for ORIG_EIP
+	pushl $do_device_not_available
 	CFI_ADJUST_CFA_OFFSET 4
-	call math_emulate
-	addl $4, %esp
-	CFI_ADJUST_CFA_OFFSET -4
-	jmp ret_from_exception
+	jmp error_code
 	CFI_ENDPROC
 END(device_not_available)
 
@@ -814,6 +804,7 @@
 	pushl $-1			# mark this as an int
 	CFI_ADJUST_CFA_OFFSET 4
 	SAVE_ALL
+	TRACE_IRQS_OFF
 	xorl %edx,%edx			# error code 0
 	movl %esp,%eax			# pt_regs pointer
 	call do_debug
@@ -858,6 +849,7 @@
 	pushl %eax
 	CFI_ADJUST_CFA_OFFSET 4
 	SAVE_ALL
+	TRACE_IRQS_OFF
 	xorl %edx,%edx		# zero error code
 	movl %esp,%eax		# pt_regs pointer
 	call do_nmi
@@ -898,6 +890,7 @@
 	pushl %eax
 	CFI_ADJUST_CFA_OFFSET 4
 	SAVE_ALL
+	TRACE_IRQS_OFF
 	FIXUP_ESPFIX_STACK		# %eax == %esp
 	xorl %edx,%edx			# zero error code
 	call do_nmi
@@ -928,6 +921,7 @@
 	pushl $-1			# mark this as an int
 	CFI_ADJUST_CFA_OFFSET 4
 	SAVE_ALL
+	TRACE_IRQS_OFF
 	xorl %edx,%edx		# zero error code
 	movl %esp,%eax		# pt_regs pointer
 	call do_int3
@@ -1030,7 +1024,7 @@
 	RING0_INT_FRAME
 	pushl $0
 	CFI_ADJUST_CFA_OFFSET 4
-	pushl machine_check_vector
+	pushl $do_machine_check
 	CFI_ADJUST_CFA_OFFSET 4
 	jmp error_code
 	CFI_ENDPROC
diff --git a/arch/x86/kernel/entry_64.S b/arch/x86/kernel/entry_64.S
index 89434d4..1db6ce4 100644
--- a/arch/x86/kernel/entry_64.S
+++ b/arch/x86/kernel/entry_64.S
@@ -275,9 +275,9 @@
 ENTRY(ret_from_fork)
 	CFI_DEFAULT_STACK
 	push kernel_eflags(%rip)
-	CFI_ADJUST_CFA_OFFSET 4
+	CFI_ADJUST_CFA_OFFSET 8
 	popf				# reset kernel eflags
-	CFI_ADJUST_CFA_OFFSET -4
+	CFI_ADJUST_CFA_OFFSET -8
 	call schedule_tail
 	GET_THREAD_INFO(%rcx)
 	testl $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT),TI_flags(%rcx)
@@ -667,6 +667,13 @@
 	SAVE_ARGS
 	leaq -ARGOFFSET(%rsp),%rdi	# arg1 for handler
 	pushq %rbp
+	/*
+	 * Save rbp twice: One is for marking the stack frame, as usual, and the
+	 * other, to fill pt_regs properly. This is because bx comes right
+	 * before the last saved register in that structure, and not bp. If the
+	 * base pointer were in the place bx is today, this would not be needed.
+	 */
+	movq %rbp, -8(%rsp)
 	CFI_ADJUST_CFA_OFFSET	8
 	CFI_REL_OFFSET		rbp, 0
 	movq %rsp,%rbp
@@ -932,6 +939,9 @@
 	.if \ist
 	movq	%gs:pda_data_offset, %rbp
 	.endif
+	.if \irqtrace
+	TRACE_IRQS_OFF
+	.endif
 	movq %rsp,%rdi
 	movq ORIG_RAX(%rsp),%rsi
 	movq $-1,ORIG_RAX(%rsp)
@@ -1058,7 +1068,8 @@
 	je  error_kernelspace
 error_swapgs:	
 	SWAPGS
-error_sti:	
+error_sti:
+	TRACE_IRQS_OFF
 	movq %rdi,RDI(%rsp) 	
 	CFI_REL_OFFSET	rdi,RDI
 	movq %rsp,%rdi
@@ -1232,7 +1243,7 @@
 END(simd_coprocessor_error)
 
 ENTRY(device_not_available)
-	zeroentry math_state_restore
+	zeroentry do_device_not_available
 END(device_not_available)
 
 	/* runs on exception stack */
diff --git a/arch/x86/kernel/es7000_32.c b/arch/x86/kernel/es7000_32.c
new file mode 100644
index 0000000..f454c78f
--- /dev/null
+++ b/arch/x86/kernel/es7000_32.c
@@ -0,0 +1,363 @@
+/*
+ * Written by: Garry Forsgren, Unisys Corporation
+ *             Natalie Protasevich, Unisys Corporation
+ * This file contains the code to configure and interface
+ * with Unisys ES7000 series hardware system manager.
+ *
+ * Copyright (c) 2003 Unisys Corporation.  All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * Contact information: Unisys Corporation, Township Line & Union Meeting
+ * Roads-A, Unisys Way, Blue Bell, Pennsylvania, 19424, or:
+ *
+ * http://www.unisys.com
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/smp.h>
+#include <linux/string.h>
+#include <linux/spinlock.h>
+#include <linux/errno.h>
+#include <linux/notifier.h>
+#include <linux/reboot.h>
+#include <linux/init.h>
+#include <linux/acpi.h>
+#include <asm/io.h>
+#include <asm/nmi.h>
+#include <asm/smp.h>
+#include <asm/apicdef.h>
+#include <mach_mpparse.h>
+
+/*
+ * ES7000 chipsets
+ */
+
+#define NON_UNISYS		0
+#define ES7000_CLASSIC		1
+#define ES7000_ZORRO		2
+
+
+#define	MIP_REG			1
+#define	MIP_PSAI_REG		4
+
+#define	MIP_BUSY		1
+#define	MIP_SPIN		0xf0000
+#define	MIP_VALID		0x0100000000000000ULL
+#define	MIP_PORT(VALUE)	((VALUE >> 32) & 0xffff)
+
+#define	MIP_RD_LO(VALUE)	(VALUE & 0xffffffff)
+
+struct mip_reg_info {
+	unsigned long long mip_info;
+	unsigned long long delivery_info;
+	unsigned long long host_reg;
+	unsigned long long mip_reg;
+};
+
+struct part_info {
+	unsigned char type;
+	unsigned char length;
+	unsigned char part_id;
+	unsigned char apic_mode;
+	unsigned long snum;
+	char ptype[16];
+	char sname[64];
+	char pname[64];
+};
+
+struct psai {
+	unsigned long long entry_type;
+	unsigned long long addr;
+	unsigned long long bep_addr;
+};
+
+struct es7000_mem_info {
+	unsigned char type;
+	unsigned char length;
+	unsigned char resv[6];
+	unsigned long long  start;
+	unsigned long long  size;
+};
+
+struct es7000_oem_table {
+	unsigned long long hdr;
+	struct mip_reg_info mip;
+	struct part_info pif;
+	struct es7000_mem_info shm;
+	struct psai psai;
+};
+
+#ifdef CONFIG_ACPI
+
+struct oem_table {
+	struct acpi_table_header Header;
+	u32 OEMTableAddr;
+	u32 OEMTableSize;
+};
+
+extern int find_unisys_acpi_oem_table(unsigned long *oem_addr);
+extern void unmap_unisys_acpi_oem_table(unsigned long oem_addr);
+#endif
+
+struct mip_reg {
+	unsigned long long off_0;
+	unsigned long long off_8;
+	unsigned long long off_10;
+	unsigned long long off_18;
+	unsigned long long off_20;
+	unsigned long long off_28;
+	unsigned long long off_30;
+	unsigned long long off_38;
+};
+
+#define	MIP_SW_APIC		0x1020b
+#define	MIP_FUNC(VALUE)		(VALUE & 0xff)
+
+/*
+ * ES7000 Globals
+ */
+
+static volatile unsigned long	*psai = NULL;
+static struct mip_reg		*mip_reg;
+static struct mip_reg		*host_reg;
+static int 			mip_port;
+static unsigned long		mip_addr, host_addr;
+
+int es7000_plat;
+
+/*
+ * GSI override for ES7000 platforms.
+ */
+
+static unsigned int base;
+
+static int
+es7000_rename_gsi(int ioapic, int gsi)
+{
+	if (es7000_plat == ES7000_ZORRO)
+		return gsi;
+
+	if (!base) {
+		int i;
+		for (i = 0; i < nr_ioapics; i++)
+			base += nr_ioapic_registers[i];
+	}
+
+	if (!ioapic && (gsi < 16))
+		gsi += base;
+	return gsi;
+}
+
+void __init
+setup_unisys(void)
+{
+	/*
+	 * Determine the generation of the ES7000 currently running.
+	 *
+	 * es7000_plat = 1 if the machine is a 5xx ES7000 box
+	 * es7000_plat = 2 if the machine is a x86_64 ES7000 box
+	 *
+	 */
+	if (!(boot_cpu_data.x86 <= 15 && boot_cpu_data.x86_model <= 2))
+		es7000_plat = ES7000_ZORRO;
+	else
+		es7000_plat = ES7000_CLASSIC;
+	ioapic_renumber_irq = es7000_rename_gsi;
+}
+
+/*
+ * Parse the OEM Table
+ */
+
+int __init
+parse_unisys_oem (char *oemptr)
+{
+	int                     i;
+	int 			success = 0;
+	unsigned char           type, size;
+	unsigned long           val;
+	char                    *tp = NULL;
+	struct psai             *psaip = NULL;
+	struct mip_reg_info 	*mi;
+	struct mip_reg		*host, *mip;
+
+	tp = oemptr;
+
+	tp += 8;
+
+	for (i=0; i <= 6; i++) {
+		type = *tp++;
+		size = *tp++;
+		tp -= 2;
+		switch (type) {
+		case MIP_REG:
+			mi = (struct mip_reg_info *)tp;
+			val = MIP_RD_LO(mi->host_reg);
+			host_addr = val;
+			host = (struct mip_reg *)val;
+			host_reg = __va(host);
+			val = MIP_RD_LO(mi->mip_reg);
+			mip_port = MIP_PORT(mi->mip_info);
+			mip_addr = val;
+			mip = (struct mip_reg *)val;
+			mip_reg = __va(mip);
+			pr_debug("es7000_mipcfg: host_reg = 0x%lx \n",
+				 (unsigned long)host_reg);
+			pr_debug("es7000_mipcfg: mip_reg = 0x%lx \n",
+				 (unsigned long)mip_reg);
+			success++;
+			break;
+		case MIP_PSAI_REG:
+			psaip = (struct psai *)tp;
+			if (tp != NULL) {
+				if (psaip->addr)
+					psai = __va(psaip->addr);
+				else
+					psai = NULL;
+				success++;
+			}
+			break;
+		default:
+			break;
+		}
+		tp += size;
+	}
+
+	if (success < 2) {
+		es7000_plat = NON_UNISYS;
+	} else
+		setup_unisys();
+	return es7000_plat;
+}
+
+#ifdef CONFIG_ACPI
+static unsigned long oem_addrX;
+static unsigned long oem_size;
+int __init find_unisys_acpi_oem_table(unsigned long *oem_addr)
+{
+	struct acpi_table_header *header = NULL;
+	int i = 0;
+	acpi_size tbl_size;
+
+	while (ACPI_SUCCESS(acpi_get_table_with_size("OEM1", i++, &header, &tbl_size))) {
+		if (!memcmp((char *) &header->oem_id, "UNISYS", 6)) {
+			struct oem_table *t = (struct oem_table *)header;
+
+			oem_addrX = t->OEMTableAddr;
+			oem_size = t->OEMTableSize;
+			early_acpi_os_unmap_memory(header, tbl_size);
+
+			*oem_addr = (unsigned long)__acpi_map_table(oem_addrX,
+								    oem_size);
+			return 0;
+		}
+		early_acpi_os_unmap_memory(header, tbl_size);
+	}
+	return -1;
+}
+
+void __init unmap_unisys_acpi_oem_table(unsigned long oem_addr)
+{
+	if (!oem_addr)
+		return;
+
+	__acpi_unmap_table((char *)oem_addr, oem_size);
+}
+#endif
+
+static void
+es7000_spin(int n)
+{
+	int i = 0;
+
+	while (i++ < n)
+		rep_nop();
+}
+
+static int __init
+es7000_mip_write(struct mip_reg *mip_reg)
+{
+	int			status = 0;
+	int			spin;
+
+	spin = MIP_SPIN;
+	while (((unsigned long long)host_reg->off_38 &
+		(unsigned long long)MIP_VALID) != 0) {
+			if (--spin <= 0) {
+				printk("es7000_mip_write: Timeout waiting for Host Valid Flag");
+				return -1;
+			}
+		es7000_spin(MIP_SPIN);
+	}
+
+	memcpy(host_reg, mip_reg, sizeof(struct mip_reg));
+	outb(1, mip_port);
+
+	spin = MIP_SPIN;
+
+	while (((unsigned long long)mip_reg->off_38 &
+		(unsigned long long)MIP_VALID) == 0) {
+		if (--spin <= 0) {
+			printk("es7000_mip_write: Timeout waiting for MIP Valid Flag");
+			return -1;
+		}
+		es7000_spin(MIP_SPIN);
+	}
+
+	status = ((unsigned long long)mip_reg->off_0 &
+		(unsigned long long)0xffff0000000000ULL) >> 48;
+	mip_reg->off_38 = ((unsigned long long)mip_reg->off_38 &
+		(unsigned long long)~MIP_VALID);
+	return status;
+}
+
+int
+es7000_start_cpu(int cpu, unsigned long eip)
+{
+	unsigned long vect = 0, psaival = 0;
+
+	if (psai == NULL)
+		return -1;
+
+	vect = ((unsigned long)__pa(eip)/0x1000) << 16;
+	psaival = (0x1000000 | vect | cpu);
+
+	while (*psai & 0x1000000)
+                ;
+
+	*psai = psaival;
+
+	return 0;
+
+}
+
+void __init
+es7000_sw_apic(void)
+{
+	if (es7000_plat) {
+		int mip_status;
+		struct mip_reg es7000_mip_reg;
+
+		printk("ES7000: Enabling APIC mode.\n");
+        	memset(&es7000_mip_reg, 0, sizeof(struct mip_reg));
+        	es7000_mip_reg.off_0 = MIP_SW_APIC;
+        	es7000_mip_reg.off_38 = (MIP_VALID);
+        	while ((mip_status = es7000_mip_write(&es7000_mip_reg)) != 0)
+              		printk("es7000_sw_apic: command failed, status = %x\n",
+				mip_status);
+		return;
+	}
+}
diff --git a/arch/x86/kernel/genapic_64.c b/arch/x86/kernel/genapic_64.c
index eaff0bb..6c9bfc9 100644
--- a/arch/x86/kernel/genapic_64.c
+++ b/arch/x86/kernel/genapic_64.c
@@ -16,87 +16,63 @@
 #include <linux/ctype.h>
 #include <linux/init.h>
 #include <linux/hardirq.h>
+#include <linux/dmar.h>
 
 #include <asm/smp.h>
 #include <asm/ipi.h>
 #include <asm/genapic.h>
 
-#ifdef CONFIG_ACPI
-#include <acpi/acpi_bus.h>
-#endif
-
-DEFINE_PER_CPU(int, x2apic_extra_bits);
+extern struct genapic apic_flat;
+extern struct genapic apic_physflat;
+extern struct genapic apic_x2xpic_uv_x;
+extern struct genapic apic_x2apic_phys;
+extern struct genapic apic_x2apic_cluster;
 
 struct genapic __read_mostly *genapic = &apic_flat;
 
-static enum uv_system_type uv_system_type;
+static struct genapic *apic_probe[] __initdata = {
+	&apic_x2apic_uv_x,
+	&apic_x2apic_phys,
+	&apic_x2apic_cluster,
+	&apic_physflat,
+	NULL,
+};
 
 /*
  * Check the APIC IDs in bios_cpu_apicid and choose the APIC mode.
  */
 void __init setup_apic_routing(void)
 {
-	if (uv_system_type == UV_NON_UNIQUE_APIC)
-		genapic = &apic_x2apic_uv_x;
-	else
-#ifdef CONFIG_ACPI
-	/*
-	 * Quirk: some x86_64 machines can only use physical APIC mode
-	 * regardless of how many processors are present (x86_64 ES7000
-	 * is an example).
-	 */
-	if (acpi_gbl_FADT.header.revision > FADT2_REVISION_ID &&
-			(acpi_gbl_FADT.flags & ACPI_FADT_APIC_PHYSICAL))
-		genapic = &apic_physflat;
-	else
-#endif
+	if (genapic == &apic_x2apic_phys || genapic == &apic_x2apic_cluster) {
+		if (!intr_remapping_enabled)
+			genapic = &apic_flat;
+	}
 
-	if (max_physical_apicid < 8)
-		genapic = &apic_flat;
-	else
-		genapic = &apic_physflat;
-
-	printk(KERN_INFO "Setting APIC routing to %s\n", genapic->name);
+	if (genapic == &apic_flat) {
+		if (max_physical_apicid >= 8)
+			genapic = &apic_physflat;
+		printk(KERN_INFO "Setting APIC routing to %s\n", genapic->name);
+	}
 }
 
 /* Same for both flat and physical. */
 
-void send_IPI_self(int vector)
+void apic_send_IPI_self(int vector)
 {
 	__send_IPI_shortcut(APIC_DEST_SELF, vector, APIC_DEST_PHYSICAL);
 }
 
 int __init acpi_madt_oem_check(char *oem_id, char *oem_table_id)
 {
-	if (!strcmp(oem_id, "SGI")) {
-		if (!strcmp(oem_table_id, "UVL"))
-			uv_system_type = UV_LEGACY_APIC;
-		else if (!strcmp(oem_table_id, "UVX"))
-			uv_system_type = UV_X2APIC;
-		else if (!strcmp(oem_table_id, "UVH"))
-			uv_system_type = UV_NON_UNIQUE_APIC;
+	int i;
+
+	for (i = 0; apic_probe[i]; ++i) {
+		if (apic_probe[i]->acpi_madt_oem_check(oem_id, oem_table_id)) {
+			genapic = apic_probe[i];
+			printk(KERN_INFO "Setting APIC routing to %s.\n",
+				genapic->name);
+			return 1;
+		}
 	}
 	return 0;
 }
-
-unsigned int read_apic_id(void)
-{
-	unsigned int id;
-
-	WARN_ON(preemptible() && num_online_cpus() > 1);
-	id = apic_read(APIC_ID);
-	if (uv_system_type >= UV_X2APIC)
-		id  |= __get_cpu_var(x2apic_extra_bits);
-	return id;
-}
-
-enum uv_system_type get_uv_system_type(void)
-{
-	return uv_system_type;
-}
-
-int is_uv_system(void)
-{
-	return uv_system_type != UV_NONE;
-}
-EXPORT_SYMBOL_GPL(is_uv_system);
diff --git a/arch/x86/kernel/genapic_flat_64.c b/arch/x86/kernel/genapic_flat_64.c
index 786548a..9eca5ba 100644
--- a/arch/x86/kernel/genapic_flat_64.c
+++ b/arch/x86/kernel/genapic_flat_64.c
@@ -15,9 +15,20 @@
 #include <linux/kernel.h>
 #include <linux/ctype.h>
 #include <linux/init.h>
+#include <linux/hardirq.h>
 #include <asm/smp.h>
 #include <asm/ipi.h>
 #include <asm/genapic.h>
+#include <mach_apicdef.h>
+
+#ifdef CONFIG_ACPI
+#include <acpi/acpi_bus.h>
+#endif
+
+static int __init flat_acpi_madt_oem_check(char *oem_id, char *oem_table_id)
+{
+	return 1;
+}
 
 static cpumask_t flat_target_cpus(void)
 {
@@ -95,9 +106,33 @@
 		__send_IPI_shortcut(APIC_DEST_ALLINC, vector, APIC_DEST_LOGICAL);
 }
 
+static unsigned int get_apic_id(unsigned long x)
+{
+	unsigned int id;
+
+	id = (((x)>>24) & 0xFFu);
+	return id;
+}
+
+static unsigned long set_apic_id(unsigned int id)
+{
+	unsigned long x;
+
+	x = ((id & 0xFFu)<<24);
+	return x;
+}
+
+static unsigned int read_xapic_id(void)
+{
+	unsigned int id;
+
+	id = get_apic_id(apic_read(APIC_ID));
+	return id;
+}
+
 static int flat_apic_id_registered(void)
 {
-	return physid_isset(GET_APIC_ID(read_apic_id()), phys_cpu_present_map);
+	return physid_isset(read_xapic_id(), phys_cpu_present_map);
 }
 
 static unsigned int flat_cpu_mask_to_apicid(cpumask_t cpumask)
@@ -112,6 +147,7 @@
 
 struct genapic apic_flat =  {
 	.name = "flat",
+	.acpi_madt_oem_check = flat_acpi_madt_oem_check,
 	.int_delivery_mode = dest_LowestPrio,
 	.int_dest_mode = (APIC_DEST_LOGICAL != 0),
 	.target_cpus = flat_target_cpus,
@@ -121,8 +157,12 @@
 	.send_IPI_all = flat_send_IPI_all,
 	.send_IPI_allbutself = flat_send_IPI_allbutself,
 	.send_IPI_mask = flat_send_IPI_mask,
+	.send_IPI_self = apic_send_IPI_self,
 	.cpu_mask_to_apicid = flat_cpu_mask_to_apicid,
 	.phys_pkg_id = phys_pkg_id,
+	.get_apic_id = get_apic_id,
+	.set_apic_id = set_apic_id,
+	.apic_id_mask = (0xFFu<<24),
 };
 
 /*
@@ -130,6 +170,21 @@
  * We cannot use logical delivery in this case because the mask
  * overflows, so use physical mode.
  */
+static int __init physflat_acpi_madt_oem_check(char *oem_id, char *oem_table_id)
+{
+#ifdef CONFIG_ACPI
+	/*
+	 * Quirk: some x86_64 machines can only use physical APIC mode
+	 * regardless of how many processors are present (x86_64 ES7000
+	 * is an example).
+	 */
+	if (acpi_gbl_FADT.header.revision > FADT2_REVISION_ID &&
+		(acpi_gbl_FADT.flags & ACPI_FADT_APIC_PHYSICAL))
+		return 1;
+#endif
+
+	return 0;
+}
 
 static cpumask_t physflat_target_cpus(void)
 {
@@ -176,6 +231,7 @@
 
 struct genapic apic_physflat =  {
 	.name = "physical flat",
+	.acpi_madt_oem_check = physflat_acpi_madt_oem_check,
 	.int_delivery_mode = dest_Fixed,
 	.int_dest_mode = (APIC_DEST_PHYSICAL != 0),
 	.target_cpus = physflat_target_cpus,
@@ -185,6 +241,10 @@
 	.send_IPI_all = physflat_send_IPI_all,
 	.send_IPI_allbutself = physflat_send_IPI_allbutself,
 	.send_IPI_mask = physflat_send_IPI_mask,
+	.send_IPI_self = apic_send_IPI_self,
 	.cpu_mask_to_apicid = physflat_cpu_mask_to_apicid,
 	.phys_pkg_id = phys_pkg_id,
+	.get_apic_id = get_apic_id,
+	.set_apic_id = set_apic_id,
+	.apic_id_mask = (0xFFu<<24),
 };
diff --git a/arch/x86/kernel/genx2apic_cluster.c b/arch/x86/kernel/genx2apic_cluster.c
new file mode 100644
index 0000000..e4bf2cc
--- /dev/null
+++ b/arch/x86/kernel/genx2apic_cluster.c
@@ -0,0 +1,159 @@
+#include <linux/threads.h>
+#include <linux/cpumask.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/ctype.h>
+#include <linux/init.h>
+#include <linux/dmar.h>
+
+#include <asm/smp.h>
+#include <asm/ipi.h>
+#include <asm/genapic.h>
+
+DEFINE_PER_CPU(u32, x86_cpu_to_logical_apicid);
+
+static int __init x2apic_acpi_madt_oem_check(char *oem_id, char *oem_table_id)
+{
+	if (cpu_has_x2apic)
+		return 1;
+
+	return 0;
+}
+
+/* Start with all IRQs pointing to boot CPU.  IRQ balancing will shift them. */
+
+static cpumask_t x2apic_target_cpus(void)
+{
+	return cpumask_of_cpu(0);
+}
+
+/*
+ * for now each logical cpu is in its own vector allocation domain.
+ */
+static cpumask_t x2apic_vector_allocation_domain(int cpu)
+{
+	cpumask_t domain = CPU_MASK_NONE;
+	cpu_set(cpu, domain);
+	return domain;
+}
+
+static void __x2apic_send_IPI_dest(unsigned int apicid, int vector,
+				   unsigned int dest)
+{
+	unsigned long cfg;
+
+	cfg = __prepare_ICR(0, vector, dest);
+
+	/*
+	 * send the IPI.
+	 */
+	x2apic_icr_write(cfg, apicid);
+}
+
+/*
+ * for now, we send the IPI's one by one in the cpumask.
+ * TBD: Based on the cpu mask, we can send the IPI's to the cluster group
+ * at once. We have 16 cpu's in a cluster. This will minimize IPI register
+ * writes.
+ */
+static void x2apic_send_IPI_mask(cpumask_t mask, int vector)
+{
+	unsigned long flags;
+	unsigned long query_cpu;
+
+	local_irq_save(flags);
+	for_each_cpu_mask(query_cpu, mask) {
+		__x2apic_send_IPI_dest(per_cpu(x86_cpu_to_logical_apicid, query_cpu),
+				       vector, APIC_DEST_LOGICAL);
+	}
+	local_irq_restore(flags);
+}
+
+static void x2apic_send_IPI_allbutself(int vector)
+{
+	cpumask_t mask = cpu_online_map;
+
+	cpu_clear(smp_processor_id(), mask);
+
+	if (!cpus_empty(mask))
+		x2apic_send_IPI_mask(mask, vector);
+}
+
+static void x2apic_send_IPI_all(int vector)
+{
+	x2apic_send_IPI_mask(cpu_online_map, vector);
+}
+
+static int x2apic_apic_id_registered(void)
+{
+	return 1;
+}
+
+static unsigned int x2apic_cpu_mask_to_apicid(cpumask_t cpumask)
+{
+	int cpu;
+
+	/*
+	 * We're using fixed IRQ delivery, can only return one phys APIC ID.
+	 * May as well be the first.
+	 */
+	cpu = first_cpu(cpumask);
+	if ((unsigned)cpu < NR_CPUS)
+		return per_cpu(x86_cpu_to_logical_apicid, cpu);
+	else
+		return BAD_APICID;
+}
+
+static unsigned int get_apic_id(unsigned long x)
+{
+	unsigned int id;
+
+	id = x;
+	return id;
+}
+
+static unsigned long set_apic_id(unsigned int id)
+{
+	unsigned long x;
+
+	x = id;
+	return x;
+}
+
+static unsigned int phys_pkg_id(int index_msb)
+{
+	return current_cpu_data.initial_apicid >> index_msb;
+}
+
+static void x2apic_send_IPI_self(int vector)
+{
+	apic_write(APIC_SELF_IPI, vector);
+}
+
+static void init_x2apic_ldr(void)
+{
+	int cpu = smp_processor_id();
+
+	per_cpu(x86_cpu_to_logical_apicid, cpu) = apic_read(APIC_LDR);
+	return;
+}
+
+struct genapic apic_x2apic_cluster = {
+	.name = "cluster x2apic",
+	.acpi_madt_oem_check = x2apic_acpi_madt_oem_check,
+	.int_delivery_mode = dest_LowestPrio,
+	.int_dest_mode = (APIC_DEST_LOGICAL != 0),
+	.target_cpus = x2apic_target_cpus,
+	.vector_allocation_domain = x2apic_vector_allocation_domain,
+	.apic_id_registered = x2apic_apic_id_registered,
+	.init_apic_ldr = init_x2apic_ldr,
+	.send_IPI_all = x2apic_send_IPI_all,
+	.send_IPI_allbutself = x2apic_send_IPI_allbutself,
+	.send_IPI_mask = x2apic_send_IPI_mask,
+	.send_IPI_self = x2apic_send_IPI_self,
+	.cpu_mask_to_apicid = x2apic_cpu_mask_to_apicid,
+	.phys_pkg_id = phys_pkg_id,
+	.get_apic_id = get_apic_id,
+	.set_apic_id = set_apic_id,
+	.apic_id_mask = (0xFFFFFFFFu),
+};
diff --git a/arch/x86/kernel/genx2apic_phys.c b/arch/x86/kernel/genx2apic_phys.c
new file mode 100644
index 0000000..8f1343d
--- /dev/null
+++ b/arch/x86/kernel/genx2apic_phys.c
@@ -0,0 +1,154 @@
+#include <linux/threads.h>
+#include <linux/cpumask.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/ctype.h>
+#include <linux/init.h>
+#include <linux/dmar.h>
+
+#include <asm/smp.h>
+#include <asm/ipi.h>
+#include <asm/genapic.h>
+
+static int x2apic_phys;
+
+static int set_x2apic_phys_mode(char *arg)
+{
+	x2apic_phys = 1;
+	return 0;
+}
+early_param("x2apic_phys", set_x2apic_phys_mode);
+
+static int __init x2apic_acpi_madt_oem_check(char *oem_id, char *oem_table_id)
+{
+	if (cpu_has_x2apic && x2apic_phys)
+		return 1;
+
+	return 0;
+}
+
+/* Start with all IRQs pointing to boot CPU.  IRQ balancing will shift them. */
+
+static cpumask_t x2apic_target_cpus(void)
+{
+	return cpumask_of_cpu(0);
+}
+
+static cpumask_t x2apic_vector_allocation_domain(int cpu)
+{
+	cpumask_t domain = CPU_MASK_NONE;
+	cpu_set(cpu, domain);
+	return domain;
+}
+
+static void __x2apic_send_IPI_dest(unsigned int apicid, int vector,
+				   unsigned int dest)
+{
+	unsigned long cfg;
+
+	cfg = __prepare_ICR(0, vector, dest);
+
+	/*
+	 * send the IPI.
+	 */
+	x2apic_icr_write(cfg, apicid);
+}
+
+static void x2apic_send_IPI_mask(cpumask_t mask, int vector)
+{
+	unsigned long flags;
+	unsigned long query_cpu;
+
+	local_irq_save(flags);
+	for_each_cpu_mask(query_cpu, mask) {
+		__x2apic_send_IPI_dest(per_cpu(x86_cpu_to_apicid, query_cpu),
+				       vector, APIC_DEST_PHYSICAL);
+	}
+	local_irq_restore(flags);
+}
+
+static void x2apic_send_IPI_allbutself(int vector)
+{
+	cpumask_t mask = cpu_online_map;
+
+	cpu_clear(smp_processor_id(), mask);
+
+	if (!cpus_empty(mask))
+		x2apic_send_IPI_mask(mask, vector);
+}
+
+static void x2apic_send_IPI_all(int vector)
+{
+	x2apic_send_IPI_mask(cpu_online_map, vector);
+}
+
+static int x2apic_apic_id_registered(void)
+{
+	return 1;
+}
+
+static unsigned int x2apic_cpu_mask_to_apicid(cpumask_t cpumask)
+{
+	int cpu;
+
+	/*
+	 * We're using fixed IRQ delivery, can only return one phys APIC ID.
+	 * May as well be the first.
+	 */
+	cpu = first_cpu(cpumask);
+	if ((unsigned)cpu < NR_CPUS)
+		return per_cpu(x86_cpu_to_apicid, cpu);
+	else
+		return BAD_APICID;
+}
+
+static unsigned int get_apic_id(unsigned long x)
+{
+	unsigned int id;
+
+	id = x;
+	return id;
+}
+
+static unsigned long set_apic_id(unsigned int id)
+{
+	unsigned long x;
+
+	x = id;
+	return x;
+}
+
+static unsigned int phys_pkg_id(int index_msb)
+{
+	return current_cpu_data.initial_apicid >> index_msb;
+}
+
+void x2apic_send_IPI_self(int vector)
+{
+	apic_write(APIC_SELF_IPI, vector);
+}
+
+void init_x2apic_ldr(void)
+{
+	return;
+}
+
+struct genapic apic_x2apic_phys = {
+	.name = "physical x2apic",
+	.acpi_madt_oem_check = x2apic_acpi_madt_oem_check,
+	.int_delivery_mode = dest_Fixed,
+	.int_dest_mode = (APIC_DEST_PHYSICAL != 0),
+	.target_cpus = x2apic_target_cpus,
+	.vector_allocation_domain = x2apic_vector_allocation_domain,
+	.apic_id_registered = x2apic_apic_id_registered,
+	.init_apic_ldr = init_x2apic_ldr,
+	.send_IPI_all = x2apic_send_IPI_all,
+	.send_IPI_allbutself = x2apic_send_IPI_allbutself,
+	.send_IPI_mask = x2apic_send_IPI_mask,
+	.send_IPI_self = x2apic_send_IPI_self,
+	.cpu_mask_to_apicid = x2apic_cpu_mask_to_apicid,
+	.phys_pkg_id = phys_pkg_id,
+	.get_apic_id = get_apic_id,
+	.set_apic_id = set_apic_id,
+	.apic_id_mask = (0xFFFFFFFFu),
+};
diff --git a/arch/x86/kernel/genx2apic_uv_x.c b/arch/x86/kernel/genx2apic_uv_x.c
index bfa837c..33581d9 100644
--- a/arch/x86/kernel/genx2apic_uv_x.c
+++ b/arch/x86/kernel/genx2apic_uv_x.c
@@ -12,12 +12,12 @@
 #include <linux/threads.h>
 #include <linux/cpumask.h>
 #include <linux/string.h>
-#include <linux/kernel.h>
 #include <linux/ctype.h>
 #include <linux/init.h>
 #include <linux/sched.h>
 #include <linux/bootmem.h>
 #include <linux/module.h>
+#include <linux/hardirq.h>
 #include <asm/smp.h>
 #include <asm/ipi.h>
 #include <asm/genapic.h>
@@ -26,6 +26,36 @@
 #include <asm/uv/uv_hub.h>
 #include <asm/uv/bios.h>
 
+DEFINE_PER_CPU(int, x2apic_extra_bits);
+
+static enum uv_system_type uv_system_type;
+
+static int __init uv_acpi_madt_oem_check(char *oem_id, char *oem_table_id)
+{
+	if (!strcmp(oem_id, "SGI")) {
+		if (!strcmp(oem_table_id, "UVL"))
+			uv_system_type = UV_LEGACY_APIC;
+		else if (!strcmp(oem_table_id, "UVX"))
+			uv_system_type = UV_X2APIC;
+		else if (!strcmp(oem_table_id, "UVH")) {
+			uv_system_type = UV_NON_UNIQUE_APIC;
+			return 1;
+		}
+	}
+	return 0;
+}
+
+enum uv_system_type get_uv_system_type(void)
+{
+	return uv_system_type;
+}
+
+int is_uv_system(void)
+{
+	return uv_system_type != UV_NONE;
+}
+EXPORT_SYMBOL_GPL(is_uv_system);
+
 DEFINE_PER_CPU(struct uv_hub_info_s, __uv_hub_info);
 EXPORT_PER_CPU_SYMBOL_GPL(__uv_hub_info);
 
@@ -84,7 +114,7 @@
 	unsigned long val, apicid, lapicid;
 	int pnode;
 
-	apicid = per_cpu(x86_cpu_to_apicid, cpu); /* ZZZ - cache node-local ? */
+	apicid = per_cpu(x86_cpu_to_apicid, cpu);
 	lapicid = apicid & 0x3f;		/* ZZZ macro needed */
 	pnode = uv_apicid_to_pnode(apicid);
 	val =
@@ -123,6 +153,10 @@
 	return 1;
 }
 
+static void uv_init_apic_ldr(void)
+{
+}
+
 static unsigned int uv_cpu_mask_to_apicid(cpumask_t cpumask)
 {
 	int cpu;
@@ -138,31 +172,59 @@
 		return BAD_APICID;
 }
 
-static unsigned int phys_pkg_id(int index_msb)
+static unsigned int get_apic_id(unsigned long x)
 {
-	return GET_APIC_ID(read_apic_id()) >> index_msb;
+	unsigned int id;
+
+	WARN_ON(preemptible() && num_online_cpus() > 1);
+	id = x | __get_cpu_var(x2apic_extra_bits);
+
+	return id;
 }
 
-#ifdef ZZZ		/* Needs x2apic patch */
+static unsigned long set_apic_id(unsigned int id)
+{
+	unsigned long x;
+
+	/* maskout x2apic_extra_bits ? */
+	x = id;
+	return x;
+}
+
+static unsigned int uv_read_apic_id(void)
+{
+
+	return get_apic_id(apic_read(APIC_ID));
+}
+
+static unsigned int phys_pkg_id(int index_msb)
+{
+	return uv_read_apic_id() >> index_msb;
+}
+
 static void uv_send_IPI_self(int vector)
 {
 	apic_write(APIC_SELF_IPI, vector);
 }
-#endif
 
 struct genapic apic_x2apic_uv_x = {
 	.name = "UV large system",
+	.acpi_madt_oem_check = uv_acpi_madt_oem_check,
 	.int_delivery_mode = dest_Fixed,
 	.int_dest_mode = (APIC_DEST_PHYSICAL != 0),
 	.target_cpus = uv_target_cpus,
-	.vector_allocation_domain = uv_vector_allocation_domain,/* Fixme ZZZ */
+	.vector_allocation_domain = uv_vector_allocation_domain,
 	.apic_id_registered = uv_apic_id_registered,
+	.init_apic_ldr = uv_init_apic_ldr,
 	.send_IPI_all = uv_send_IPI_all,
 	.send_IPI_allbutself = uv_send_IPI_allbutself,
 	.send_IPI_mask = uv_send_IPI_mask,
-	/* ZZZ.send_IPI_self = uv_send_IPI_self, */
+	.send_IPI_self = uv_send_IPI_self,
 	.cpu_mask_to_apicid = uv_cpu_mask_to_apicid,
-	.phys_pkg_id = phys_pkg_id,	/* Fixme ZZZ */
+	.phys_pkg_id = phys_pkg_id,
+	.get_apic_id = get_apic_id,
+	.set_apic_id = set_apic_id,
+	.apic_id_mask = (0xFFFFFFFFu),
 };
 
 static __cpuinit void set_x2apic_extra_bits(int pnode)
@@ -222,12 +284,13 @@
 
 enum map_type {map_wb, map_uc};
 
-static __init void map_high(char *id, unsigned long base, int shift, enum map_type map_type)
+static __init void map_high(char *id, unsigned long base, int shift,
+			    int max_pnode, enum map_type map_type)
 {
 	unsigned long bytes, paddr;
 
 	paddr = base << shift;
-	bytes = (1UL << shift);
+	bytes = (1UL << shift) * (max_pnode + 1);
 	printk(KERN_INFO "UV: Map %s_HI 0x%lx - 0x%lx\n", id, paddr,
 	       					paddr + bytes);
 	if (map_type == map_uc)
@@ -243,7 +306,7 @@
 
 	gru.v = uv_read_local_mmr(UVH_RH_GAM_GRU_OVERLAY_CONFIG_MMR);
 	if (gru.s.enable)
-		map_high("GRU", gru.s.base, shift, map_wb);
+		map_high("GRU", gru.s.base, shift, max_pnode, map_wb);
 }
 
 static __init void map_config_high(int max_pnode)
@@ -253,7 +316,7 @@
 
 	cfg.v = uv_read_local_mmr(UVH_RH_GAM_CFG_OVERLAY_CONFIG_MMR);
 	if (cfg.s.enable)
-		map_high("CONFIG", cfg.s.base, shift, map_uc);
+		map_high("CONFIG", cfg.s.base, shift, max_pnode, map_uc);
 }
 
 static __init void map_mmr_high(int max_pnode)
@@ -263,7 +326,7 @@
 
 	mmr.v = uv_read_local_mmr(UVH_RH_GAM_MMR_OVERLAY_CONFIG_MMR);
 	if (mmr.s.enable)
-		map_high("MMR", mmr.s.base, shift, map_uc);
+		map_high("MMR", mmr.s.base, shift, max_pnode, map_uc);
 }
 
 static __init void map_mmioh_high(int max_pnode)
@@ -273,7 +336,7 @@
 
 	mmioh.v = uv_read_local_mmr(UVH_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR);
 	if (mmioh.s.enable)
-		map_high("MMIOH", mmioh.s.base, shift, map_uc);
+		map_high("MMIOH", mmioh.s.base, shift, max_pnode, map_uc);
 }
 
 static __init void uv_rtc_init(void)
@@ -401,3 +464,5 @@
 	if (get_uv_system_type() == UV_NON_UNIQUE_APIC)
 		set_x2apic_extra_bits(uv_hub_info->pnode);
 }
+
+
diff --git a/arch/x86/kernel/head.c b/arch/x86/kernel/head.c
index 3e66bd3..1dcb0f1 100644
--- a/arch/x86/kernel/head.c
+++ b/arch/x86/kernel/head.c
@@ -35,6 +35,7 @@
 
 	/* start of EBDA area */
 	ebda_addr = get_bios_ebda();
+	printk(KERN_INFO "BIOS EBDA/lowmem at: %08x/%08x\n", ebda_addr, lowmem);
 
 	/* Fixup: bios puts an EBDA in the top 64K segment */
 	/* of conventional memory, but does not adjust lowmem. */
diff --git a/arch/x86/kernel/head64.c b/arch/x86/kernel/head64.c
index 9bfc4d7..d16084f 100644
--- a/arch/x86/kernel/head64.c
+++ b/arch/x86/kernel/head64.c
@@ -108,12 +108,11 @@
 	}
 	load_idt((const struct desc_ptr *)&idt_descr);
 
-	early_printk("Kernel alive\n");
+	if (console_loglevel == 10)
+		early_printk("Kernel alive\n");
 
 	x86_64_init_pda();
 
-	early_printk("Kernel really alive\n");
-
 	x86_64_start_reservations(real_mode_data);
 }
 
diff --git a/arch/x86/kernel/head_32.S b/arch/x86/kernel/head_32.S
index a7010c3..e835b4e 100644
--- a/arch/x86/kernel/head_32.S
+++ b/arch/x86/kernel/head_32.S
@@ -172,10 +172,6 @@
  *
  * Note that the stack is not yet set up!
  */
-#define PTE_ATTR	0x007		/* PRESENT+RW+USER */
-#define PDE_ATTR	0x067		/* PRESENT+RW+USER+DIRTY+ACCESSED */
-#define PGD_ATTR	0x001		/* PRESENT (no other attributes) */
-
 default_entry:
 #ifdef CONFIG_X86_PAE
 
@@ -196,9 +192,9 @@
 	movl $pa(pg0), %edi
 	movl %edi, pa(init_pg_tables_start)
 	movl $pa(swapper_pg_pmd), %edx
-	movl $PTE_ATTR, %eax
+	movl $PTE_IDENT_ATTR, %eax
 10:
-	leal PDE_ATTR(%edi),%ecx		/* Create PMD entry */
+	leal PDE_IDENT_ATTR(%edi),%ecx		/* Create PMD entry */
 	movl %ecx,(%edx)			/* Store PMD entry */
 						/* Upper half already zero */
 	addl $8,%edx
@@ -215,7 +211,7 @@
 	 * End condition: we must map up to and including INIT_MAP_BEYOND_END
 	 * bytes beyond the end of our own page tables.
 	 */
-	leal (INIT_MAP_BEYOND_END+PTE_ATTR)(%edi),%ebp
+	leal (INIT_MAP_BEYOND_END+PTE_IDENT_ATTR)(%edi),%ebp
 	cmpl %ebp,%eax
 	jb 10b
 1:
@@ -224,7 +220,7 @@
 	movl %eax, pa(max_pfn_mapped)
 
 	/* Do early initialization of the fixmap area */
-	movl $pa(swapper_pg_fixmap)+PDE_ATTR,%eax
+	movl $pa(swapper_pg_fixmap)+PDE_IDENT_ATTR,%eax
 	movl %eax,pa(swapper_pg_pmd+0x1000*KPMDS-8)
 #else	/* Not PAE */
 
@@ -233,9 +229,9 @@
 	movl $pa(pg0), %edi
 	movl %edi, pa(init_pg_tables_start)
 	movl $pa(swapper_pg_dir), %edx
-	movl $PTE_ATTR, %eax
+	movl $PTE_IDENT_ATTR, %eax
 10:
-	leal PDE_ATTR(%edi),%ecx		/* Create PDE entry */
+	leal PDE_IDENT_ATTR(%edi),%ecx		/* Create PDE entry */
 	movl %ecx,(%edx)			/* Store identity PDE entry */
 	movl %ecx,page_pde_offset(%edx)		/* Store kernel PDE entry */
 	addl $4,%edx
@@ -249,7 +245,7 @@
 	 * bytes beyond the end of our own page tables; the +0x007 is
 	 * the attribute bits
 	 */
-	leal (INIT_MAP_BEYOND_END+PTE_ATTR)(%edi),%ebp
+	leal (INIT_MAP_BEYOND_END+PTE_IDENT_ATTR)(%edi),%ebp
 	cmpl %ebp,%eax
 	jb 10b
 	movl %edi,pa(init_pg_tables_end)
@@ -257,7 +253,7 @@
 	movl %eax, pa(max_pfn_mapped)
 
 	/* Do early initialization of the fixmap area */
-	movl $pa(swapper_pg_fixmap)+PDE_ATTR,%eax
+	movl $pa(swapper_pg_fixmap)+PDE_IDENT_ATTR,%eax
 	movl %eax,pa(swapper_pg_dir+0xffc)
 #endif
 	jmp 3f
@@ -634,19 +630,19 @@
 	/* Page-aligned for the benefit of paravirt? */
 	.align PAGE_SIZE_asm
 ENTRY(swapper_pg_dir)
-	.long	pa(swapper_pg_pmd+PGD_ATTR),0		/* low identity map */
+	.long	pa(swapper_pg_pmd+PGD_IDENT_ATTR),0	/* low identity map */
 # if KPMDS == 3
-	.long	pa(swapper_pg_pmd+PGD_ATTR),0
-	.long	pa(swapper_pg_pmd+PGD_ATTR+0x1000),0
-	.long	pa(swapper_pg_pmd+PGD_ATTR+0x2000),0
+	.long	pa(swapper_pg_pmd+PGD_IDENT_ATTR),0
+	.long	pa(swapper_pg_pmd+PGD_IDENT_ATTR+0x1000),0
+	.long	pa(swapper_pg_pmd+PGD_IDENT_ATTR+0x2000),0
 # elif KPMDS == 2
 	.long	0,0
-	.long	pa(swapper_pg_pmd+PGD_ATTR),0
-	.long	pa(swapper_pg_pmd+PGD_ATTR+0x1000),0
+	.long	pa(swapper_pg_pmd+PGD_IDENT_ATTR),0
+	.long	pa(swapper_pg_pmd+PGD_IDENT_ATTR+0x1000),0
 # elif KPMDS == 1
 	.long	0,0
 	.long	0,0
-	.long	pa(swapper_pg_pmd+PGD_ATTR),0
+	.long	pa(swapper_pg_pmd+PGD_IDENT_ATTR),0
 # else
 #  error "Kernel PMDs should be 1, 2 or 3"
 # endif
diff --git a/arch/x86/kernel/head_64.S b/arch/x86/kernel/head_64.S
index db3280a..26cfdc1 100644
--- a/arch/x86/kernel/head_64.S
+++ b/arch/x86/kernel/head_64.S
@@ -110,7 +110,7 @@
 	movq	%rdi, %rax
 	shrq	$PMD_SHIFT, %rax
 	andq	$(PTRS_PER_PMD - 1), %rax
-	leaq	__PAGE_KERNEL_LARGE_EXEC(%rdi), %rdx
+	leaq	__PAGE_KERNEL_IDENT_LARGE_EXEC(%rdi), %rdx
 	leaq	level2_spare_pgt(%rip), %rbx
 	movq	%rdx, 0(%rbx, %rax, 8)
 ident_complete:
@@ -374,7 +374,7 @@
 	/* Since I easily can, map the first 1G.
 	 * Don't set NX because code runs from these pages.
 	 */
-	PMDS(0, __PAGE_KERNEL_LARGE_EXEC, PTRS_PER_PMD)
+	PMDS(0, __PAGE_KERNEL_IDENT_LARGE_EXEC, PTRS_PER_PMD)
 
 NEXT_PAGE(level2_kernel_pgt)
 	/*
diff --git a/arch/x86/kernel/hpet.c b/arch/x86/kernel/hpet.c
index 73deaff..acf62fc 100644
--- a/arch/x86/kernel/hpet.c
+++ b/arch/x86/kernel/hpet.c
@@ -115,13 +115,17 @@
 	hd.hd_phys_address = hpet_address;
 	hd.hd_address = hpet;
 	hd.hd_nirqs = nrtimers;
-	hd.hd_flags = HPET_DATA_PLATFORM;
 	hpet_reserve_timer(&hd, 0);
 
 #ifdef CONFIG_HPET_EMULATE_RTC
 	hpet_reserve_timer(&hd, 1);
 #endif
 
+	/*
+	 * NOTE that hd_irq[] reflects IOAPIC input pins (LEGACY_8254
+	 * is wrong for i8259!) not the output IRQ.  Many BIOS writers
+	 * don't bother configuring *any* comparator interrupts.
+	 */
 	hd.hd_irq[0] = HPET_LEGACY_8254;
 	hd.hd_irq[1] = HPET_LEGACY_RTC;
 
diff --git a/arch/x86/kernel/i387.c b/arch/x86/kernel/i387.c
index eb9ddd8..1f20608 100644
--- a/arch/x86/kernel/i387.c
+++ b/arch/x86/kernel/i387.c
@@ -21,9 +21,12 @@
 # include <asm/sigcontext32.h>
 # include <asm/user32.h>
 #else
-# define save_i387_ia32		save_i387
-# define restore_i387_ia32	restore_i387
+# define save_i387_xstate_ia32		save_i387_xstate
+# define restore_i387_xstate_ia32	restore_i387_xstate
 # define _fpstate_ia32		_fpstate
+# define _xstate_ia32		_xstate
+# define sig_xstate_ia32_size   sig_xstate_size
+# define fx_sw_reserved_ia32	fx_sw_reserved
 # define user_i387_ia32_struct	user_i387_struct
 # define user32_fxsr_struct	user_fxsr_struct
 #endif
@@ -36,6 +39,7 @@
 
 static unsigned int		mxcsr_feature_mask __read_mostly = 0xffffffffu;
 unsigned int xstate_size;
+unsigned int sig_xstate_ia32_size = sizeof(struct _fpstate_ia32);
 static struct i387_fxsave_struct fx_scratch __cpuinitdata;
 
 void __cpuinit mxcsr_feature_mask_init(void)
@@ -61,6 +65,11 @@
 		return;
 	}
 
+	if (cpu_has_xsave) {
+		xsave_cntxt_init();
+		return;
+	}
+
 	if (cpu_has_fxsr)
 		xstate_size = sizeof(struct i387_fxsave_struct);
 #ifdef CONFIG_X86_32
@@ -83,9 +92,19 @@
 
 	write_cr0(oldcr0 & ~(X86_CR0_TS|X86_CR0_EM)); /* clear TS and EM */
 
+	/*
+	 * Boot processor to setup the FP and extended state context info.
+	 */
+	if (!smp_processor_id())
+		init_thread_xstate();
+	xsave_init();
+
 	mxcsr_feature_mask_init();
 	/* clean state in init */
-	current_thread_info()->status = 0;
+	if (cpu_has_xsave)
+		current_thread_info()->status = TS_XSAVE;
+	else
+		current_thread_info()->status = 0;
 	clear_used_math();
 }
 #endif	/* CONFIG_X86_64 */
@@ -195,6 +214,13 @@
 	 */
 	target->thread.xstate->fxsave.mxcsr &= mxcsr_feature_mask;
 
+	/*
+	 * update the header bits in the xsave header, indicating the
+	 * presence of FP and SSE state.
+	 */
+	if (cpu_has_xsave)
+		target->thread.xstate->xsave.xsave_hdr.xstate_bv |= XSTATE_FPSSE;
+
 	return ret;
 }
 
@@ -395,6 +421,12 @@
 	if (!ret)
 		convert_to_fxsr(target, &env);
 
+	/*
+	 * update the header bit in the xsave header, indicating the
+	 * presence of FP.
+	 */
+	if (cpu_has_xsave)
+		target->thread.xstate->xsave.xsave_hdr.xstate_bv |= XSTATE_FP;
 	return ret;
 }
 
@@ -407,7 +439,6 @@
 	struct task_struct *tsk = current;
 	struct i387_fsave_struct *fp = &tsk->thread.xstate->fsave;
 
-	unlazy_fpu(tsk);
 	fp->status = fp->swd;
 	if (__copy_to_user(buf, fp, sizeof(struct i387_fsave_struct)))
 		return -1;
@@ -421,8 +452,6 @@
 	struct user_i387_ia32_struct env;
 	int err = 0;
 
-	unlazy_fpu(tsk);
-
 	convert_from_fxsr(&env, tsk);
 	if (__copy_to_user(buf, &env, sizeof(env)))
 		return -1;
@@ -432,16 +461,54 @@
 	if (err)
 		return -1;
 
-	if (__copy_to_user(&buf->_fxsr_env[0], fx,
-			   sizeof(struct i387_fxsave_struct)))
+	if (__copy_to_user(&buf->_fxsr_env[0], fx, xstate_size))
 		return -1;
 	return 1;
 }
 
-int save_i387_ia32(struct _fpstate_ia32 __user *buf)
+static int save_i387_xsave(void __user *buf)
 {
+	struct task_struct *tsk = current;
+	struct _fpstate_ia32 __user *fx = buf;
+	int err = 0;
+
+	/*
+	 * For legacy compatible, we always set FP/SSE bits in the bit
+	 * vector while saving the state to the user context.
+	 * This will enable us capturing any changes(during sigreturn) to
+	 * the FP/SSE bits by the legacy applications which don't touch
+	 * xstate_bv in the xsave header.
+	 *
+	 * xsave aware applications can change the xstate_bv in the xsave
+	 * header as well as change any contents in the memory layout.
+	 * xrestore as part of sigreturn will capture all the changes.
+	 */
+	tsk->thread.xstate->xsave.xsave_hdr.xstate_bv |= XSTATE_FPSSE;
+
+	if (save_i387_fxsave(fx) < 0)
+		return -1;
+
+	err = __copy_to_user(&fx->sw_reserved, &fx_sw_reserved_ia32,
+			     sizeof(struct _fpx_sw_bytes));
+	err |= __put_user(FP_XSTATE_MAGIC2,
+			  (__u32 __user *) (buf + sig_xstate_ia32_size
+					    - FP_XSTATE_MAGIC2_SIZE));
+	if (err)
+		return -1;
+
+	return 1;
+}
+
+int save_i387_xstate_ia32(void __user *buf)
+{
+	struct _fpstate_ia32 __user *fp = (struct _fpstate_ia32 __user *) buf;
+	struct task_struct *tsk = current;
+
 	if (!used_math())
 		return 0;
+
+	if (!access_ok(VERIFY_WRITE, buf, sig_xstate_ia32_size))
+		return -EACCES;
 	/*
 	 * This will cause a "finit" to be triggered by the next
 	 * attempted FPU operation by the 'current' process.
@@ -451,13 +518,17 @@
 	if (!HAVE_HWFP) {
 		return fpregs_soft_get(current, NULL,
 				       0, sizeof(struct user_i387_ia32_struct),
-				       NULL, buf) ? -1 : 1;
+				       NULL, fp) ? -1 : 1;
 	}
 
+	unlazy_fpu(tsk);
+
+	if (cpu_has_xsave)
+		return save_i387_xsave(fp);
 	if (cpu_has_fxsr)
-		return save_i387_fxsave(buf);
+		return save_i387_fxsave(fp);
 	else
-		return save_i387_fsave(buf);
+		return save_i387_fsave(fp);
 }
 
 static inline int restore_i387_fsave(struct _fpstate_ia32 __user *buf)
@@ -468,14 +539,15 @@
 				sizeof(struct i387_fsave_struct));
 }
 
-static int restore_i387_fxsave(struct _fpstate_ia32 __user *buf)
+static int restore_i387_fxsave(struct _fpstate_ia32 __user *buf,
+			       unsigned int size)
 {
 	struct task_struct *tsk = current;
 	struct user_i387_ia32_struct env;
 	int err;
 
 	err = __copy_from_user(&tsk->thread.xstate->fxsave, &buf->_fxsr_env[0],
-			       sizeof(struct i387_fxsave_struct));
+			       size);
 	/* mxcsr reserved bits must be masked to zero for security reasons */
 	tsk->thread.xstate->fxsave.mxcsr &= mxcsr_feature_mask;
 	if (err || __copy_from_user(&env, buf, sizeof(env)))
@@ -485,14 +557,69 @@
 	return 0;
 }
 
-int restore_i387_ia32(struct _fpstate_ia32 __user *buf)
+static int restore_i387_xsave(void __user *buf)
+{
+	struct _fpx_sw_bytes fx_sw_user;
+	struct _fpstate_ia32 __user *fx_user =
+			((struct _fpstate_ia32 __user *) buf);
+	struct i387_fxsave_struct __user *fx =
+		(struct i387_fxsave_struct __user *) &fx_user->_fxsr_env[0];
+	struct xsave_hdr_struct *xsave_hdr =
+				&current->thread.xstate->xsave.xsave_hdr;
+	u64 mask;
+	int err;
+
+	if (check_for_xstate(fx, buf, &fx_sw_user))
+		goto fx_only;
+
+	mask = fx_sw_user.xstate_bv;
+
+	err = restore_i387_fxsave(buf, fx_sw_user.xstate_size);
+
+	xsave_hdr->xstate_bv &= pcntxt_mask;
+	/*
+	 * These bits must be zero.
+	 */
+	xsave_hdr->reserved1[0] = xsave_hdr->reserved1[1] = 0;
+
+	/*
+	 * Init the state that is not present in the memory layout
+	 * and enabled by the OS.
+	 */
+	mask = ~(pcntxt_mask & ~mask);
+	xsave_hdr->xstate_bv &= mask;
+
+	return err;
+fx_only:
+	/*
+	 * Couldn't find the extended state information in the memory
+	 * layout. Restore the FP/SSE and init the other extended state
+	 * enabled by the OS.
+	 */
+	xsave_hdr->xstate_bv = XSTATE_FPSSE;
+	return restore_i387_fxsave(buf, sizeof(struct i387_fxsave_struct));
+}
+
+int restore_i387_xstate_ia32(void __user *buf)
 {
 	int err;
 	struct task_struct *tsk = current;
+	struct _fpstate_ia32 __user *fp = (struct _fpstate_ia32 __user *) buf;
 
 	if (HAVE_HWFP)
 		clear_fpu(tsk);
 
+	if (!buf) {
+		if (used_math()) {
+			clear_fpu(tsk);
+			clear_used_math();
+		}
+
+		return 0;
+	} else
+		if (!access_ok(VERIFY_READ, buf, sig_xstate_ia32_size))
+			return -EACCES;
+
 	if (!used_math()) {
 		err = init_fpu(tsk);
 		if (err)
@@ -500,14 +627,17 @@
 	}
 
 	if (HAVE_HWFP) {
-		if (cpu_has_fxsr)
-			err = restore_i387_fxsave(buf);
+		if (cpu_has_xsave)
+			err = restore_i387_xsave(buf);
+		else if (cpu_has_fxsr)
+			err = restore_i387_fxsave(fp, sizeof(struct
+							   i387_fxsave_struct));
 		else
-			err = restore_i387_fsave(buf);
+			err = restore_i387_fsave(fp);
 	} else {
 		err = fpregs_soft_set(current, NULL,
 				      0, sizeof(struct user_i387_ia32_struct),
-				      NULL, buf) != 0;
+				      NULL, fp) != 0;
 	}
 	set_used_math();
 
diff --git a/arch/x86/kernel/i8259.c b/arch/x86/kernel/i8259.c
index dc92b49..4b8a53d 100644
--- a/arch/x86/kernel/i8259.c
+++ b/arch/x86/kernel/i8259.c
@@ -282,6 +282,30 @@
 
 device_initcall(i8259A_init_sysfs);
 
+void mask_8259A(void)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&i8259A_lock, flags);
+
+	outb(0xff, PIC_MASTER_IMR);	/* mask all of 8259A-1 */
+	outb(0xff, PIC_SLAVE_IMR);	/* mask all of 8259A-2 */
+
+	spin_unlock_irqrestore(&i8259A_lock, flags);
+}
+
+void unmask_8259A(void)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&i8259A_lock, flags);
+
+	outb(cached_master_mask, PIC_MASTER_IMR); /* restore master IRQ mask */
+	outb(cached_slave_mask, PIC_SLAVE_IMR);	  /* restore slave IRQ mask */
+
+	spin_unlock_irqrestore(&i8259A_lock, flags);
+}
+
 void init_8259A(int auto_eoi)
 {
 	unsigned long flags;
diff --git a/arch/x86/kernel/io_apic_32.c b/arch/x86/kernel/io_apic_32.c
index 09cddb5..e710289 100644
--- a/arch/x86/kernel/io_apic_32.c
+++ b/arch/x86/kernel/io_apic_32.c
@@ -46,10 +46,13 @@
 #include <asm/nmi.h>
 #include <asm/msidef.h>
 #include <asm/hypertransport.h>
+#include <asm/setup.h>
 
 #include <mach_apic.h>
 #include <mach_apicdef.h>
 
+#define __apicdebuginit(type) static type __init
+
 int (*ioapic_renumber_irq)(int ioapic, int irq);
 atomic_t irq_mis_count;
 
@@ -1341,7 +1344,8 @@
 	ioapic_write_entry(apic, pin, entry);
 }
 
-void __init print_IO_APIC(void)
+
+__apicdebuginit(void) print_IO_APIC(void)
 {
 	int apic, i;
 	union IO_APIC_reg_00 reg_00;
@@ -1456,9 +1460,7 @@
 	return;
 }
 
-#if 0
-
-static void print_APIC_bitfield(int base)
+__apicdebuginit(void) print_APIC_bitfield(int base)
 {
 	unsigned int v;
 	int i, j;
@@ -1479,9 +1481,10 @@
 	}
 }
 
-void /*__init*/ print_local_APIC(void *dummy)
+__apicdebuginit(void) print_local_APIC(void *dummy)
 {
 	unsigned int v, ver, maxlvt;
+	u64 icr;
 
 	if (apic_verbosity == APIC_QUIET)
 		return;
@@ -1490,7 +1493,7 @@
 		smp_processor_id(), hard_smp_processor_id());
 	v = apic_read(APIC_ID);
 	printk(KERN_INFO "... APIC ID:      %08x (%01x)\n", v,
-			GET_APIC_ID(read_apic_id()));
+			GET_APIC_ID(v));
 	v = apic_read(APIC_LVR);
 	printk(KERN_INFO "... APIC VERSION: %08x\n", v);
 	ver = GET_APIC_VERSION(v);
@@ -1532,10 +1535,9 @@
 		printk(KERN_DEBUG "... APIC ESR: %08x\n", v);
 	}
 
-	v = apic_read(APIC_ICR);
-	printk(KERN_DEBUG "... APIC ICR: %08x\n", v);
-	v = apic_read(APIC_ICR2);
-	printk(KERN_DEBUG "... APIC ICR2: %08x\n", v);
+	icr = apic_icr_read();
+	printk(KERN_DEBUG "... APIC ICR: %08x\n", icr);
+	printk(KERN_DEBUG "... APIC ICR2: %08x\n", icr >> 32);
 
 	v = apic_read(APIC_LVTT);
 	printk(KERN_DEBUG "... APIC LVTT: %08x\n", v);
@@ -1563,12 +1565,12 @@
 	printk("\n");
 }
 
-void print_all_local_APICs(void)
+__apicdebuginit(void) print_all_local_APICs(void)
 {
 	on_each_cpu(print_local_APIC, NULL, 1);
 }
 
-void /*__init*/ print_PIC(void)
+__apicdebuginit(void) print_PIC(void)
 {
 	unsigned int v;
 	unsigned long flags;
@@ -1600,7 +1602,17 @@
 	printk(KERN_DEBUG "... PIC ELCR: %04x\n", v);
 }
 
-#endif  /*  0  */
+__apicdebuginit(int) print_all_ICs(void)
+{
+	print_PIC();
+	print_all_local_APICs();
+	print_IO_APIC();
+
+	return 0;
+}
+
+fs_initcall(print_all_ICs);
+
 
 static void __init enable_IO_APIC(void)
 {
@@ -1698,8 +1710,7 @@
 		entry.dest_mode       = 0; /* Physical */
 		entry.delivery_mode   = dest_ExtINT; /* ExtInt */
 		entry.vector          = 0;
-		entry.dest.physical.physical_dest =
-					GET_APIC_ID(read_apic_id());
+		entry.dest.physical.physical_dest = read_apic_id();
 
 		/*
 		 * Add it to the IO-APIC irq-routing table:
@@ -1725,10 +1736,8 @@
 	unsigned char old_id;
 	unsigned long flags;
 
-#ifdef CONFIG_X86_NUMAQ
-	if (found_numaq)
+	if (x86_quirks->setup_ioapic_ids && x86_quirks->setup_ioapic_ids())
 		return;
-#endif
 
 	/*
 	 * Don't check I/O APIC IDs for xAPIC systems.  They have
@@ -2329,8 +2338,6 @@
 	setup_IO_APIC_irqs();
 	init_IO_APIC_traps();
 	check_timer();
-	if (!acpi_ioapic)
-		print_IO_APIC();
 }
 
 /*
diff --git a/arch/x86/kernel/io_apic_64.c b/arch/x86/kernel/io_apic_64.c
index 61a83b7..02063ae 100644
--- a/arch/x86/kernel/io_apic_64.c
+++ b/arch/x86/kernel/io_apic_64.c
@@ -37,6 +37,7 @@
 #include <acpi/acpi_bus.h>
 #endif
 #include <linux/bootmem.h>
+#include <linux/dmar.h>
 
 #include <asm/idle.h>
 #include <asm/io.h>
@@ -49,10 +50,13 @@
 #include <asm/nmi.h>
 #include <asm/msidef.h>
 #include <asm/hypertransport.h>
+#include <asm/irq_remapping.h>
 
 #include <mach_ipi.h>
 #include <mach_apic.h>
 
+#define __apicdebuginit(type) static type __init
+
 struct irq_cfg {
 	cpumask_t domain;
 	cpumask_t old_domain;
@@ -87,8 +91,6 @@
 
 char system_vectors[NR_VECTORS] = { [0 ... NR_VECTORS-1] = SYS_VECTOR_FREE};
 
-#define __apicdebuginit  __init
-
 int sis_apic_bug; /* not actually supported, dummy for compile */
 
 static int no_timer_check;
@@ -108,6 +110,9 @@
  */
 int nr_ioapic_registers[MAX_IO_APICS];
 
+/* I/O APIC RTE contents at the OS boot up */
+struct IO_APIC_route_entry *early_ioapic_entries[MAX_IO_APICS];
+
 /* I/O APIC entries */
 struct mp_config_ioapic mp_ioapics[MAX_IO_APICS];
 int nr_ioapics;
@@ -303,7 +308,12 @@
 		pin = entry->pin;
 		if (pin == -1)
 			break;
-		io_apic_write(apic, 0x11 + pin*2, dest);
+		/*
+		 * With interrupt-remapping, destination information comes
+		 * from interrupt-remapping table entry.
+		 */
+		if (!irq_remapped(irq))
+			io_apic_write(apic, 0x11 + pin*2, dest);
 		reg = io_apic_read(apic, 0x10 + pin*2);
 		reg &= ~IO_APIC_REDIR_VECTOR_MASK;
 		reg |= vector;
@@ -440,6 +450,69 @@
 			clear_IO_APIC_pin(apic, pin);
 }
 
+/*
+ * Saves and masks all the unmasked IO-APIC RTE's
+ */
+int save_mask_IO_APIC_setup(void)
+{
+	union IO_APIC_reg_01 reg_01;
+	unsigned long flags;
+	int apic, pin;
+
+	/*
+	 * The number of IO-APIC IRQ registers (== #pins):
+	 */
+	for (apic = 0; apic < nr_ioapics; apic++) {
+		spin_lock_irqsave(&ioapic_lock, flags);
+		reg_01.raw = io_apic_read(apic, 1);
+		spin_unlock_irqrestore(&ioapic_lock, flags);
+		nr_ioapic_registers[apic] = reg_01.bits.entries+1;
+	}
+
+	for (apic = 0; apic < nr_ioapics; apic++) {
+		early_ioapic_entries[apic] =
+			kzalloc(sizeof(struct IO_APIC_route_entry) *
+				nr_ioapic_registers[apic], GFP_KERNEL);
+		if (!early_ioapic_entries[apic])
+			return -ENOMEM;
+	}
+
+	for (apic = 0; apic < nr_ioapics; apic++)
+		for (pin = 0; pin < nr_ioapic_registers[apic]; pin++) {
+			struct IO_APIC_route_entry entry;
+
+			entry = early_ioapic_entries[apic][pin] =
+				ioapic_read_entry(apic, pin);
+			if (!entry.mask) {
+				entry.mask = 1;
+				ioapic_write_entry(apic, pin, entry);
+			}
+		}
+	return 0;
+}
+
+void restore_IO_APIC_setup(void)
+{
+	int apic, pin;
+
+	for (apic = 0; apic < nr_ioapics; apic++)
+		for (pin = 0; pin < nr_ioapic_registers[apic]; pin++)
+			ioapic_write_entry(apic, pin,
+					   early_ioapic_entries[apic][pin]);
+}
+
+void reinit_intr_remapped_IO_APIC(int intr_remapping)
+{
+	/*
+	 * for now plain restore of previous settings.
+	 * TBD: In the case of OS enabling interrupt-remapping,
+	 * IO-APIC RTE's need to be setup to point to interrupt-remapping
+	 * table entries. for now, do a plain restore, and wait for
+	 * the setup_IO_APIC_irqs() to do proper initialization.
+	 */
+	restore_IO_APIC_setup();
+}
+
 int skip_ioapic_setup;
 int ioapic_force;
 
@@ -839,18 +912,98 @@
 }
 
 static struct irq_chip ioapic_chip;
+#ifdef CONFIG_INTR_REMAP
+static struct irq_chip ir_ioapic_chip;
+#endif
 
 static void ioapic_register_intr(int irq, unsigned long trigger)
 {
-	if (trigger) {
+	if (trigger)
 		irq_desc[irq].status |= IRQ_LEVEL;
-		set_irq_chip_and_handler_name(irq, &ioapic_chip,
-					      handle_fasteoi_irq, "fasteoi");
-	} else {
+	else
 		irq_desc[irq].status &= ~IRQ_LEVEL;
+
+#ifdef CONFIG_INTR_REMAP
+	if (irq_remapped(irq)) {
+		irq_desc[irq].status |= IRQ_MOVE_PCNTXT;
+		if (trigger)
+			set_irq_chip_and_handler_name(irq, &ir_ioapic_chip,
+						      handle_fasteoi_irq,
+						     "fasteoi");
+		else
+			set_irq_chip_and_handler_name(irq, &ir_ioapic_chip,
+						      handle_edge_irq, "edge");
+		return;
+	}
+#endif
+	if (trigger)
+		set_irq_chip_and_handler_name(irq, &ioapic_chip,
+					      handle_fasteoi_irq,
+					      "fasteoi");
+	else
 		set_irq_chip_and_handler_name(irq, &ioapic_chip,
 					      handle_edge_irq, "edge");
+}
+
+static int setup_ioapic_entry(int apic, int irq,
+			      struct IO_APIC_route_entry *entry,
+			      unsigned int destination, int trigger,
+			      int polarity, int vector)
+{
+	/*
+	 * add it to the IO-APIC irq-routing table:
+	 */
+	memset(entry,0,sizeof(*entry));
+
+#ifdef CONFIG_INTR_REMAP
+	if (intr_remapping_enabled) {
+		struct intel_iommu *iommu = map_ioapic_to_ir(apic);
+		struct irte irte;
+		struct IR_IO_APIC_route_entry *ir_entry =
+			(struct IR_IO_APIC_route_entry *) entry;
+		int index;
+
+		if (!iommu)
+			panic("No mapping iommu for ioapic %d\n", apic);
+
+		index = alloc_irte(iommu, irq, 1);
+		if (index < 0)
+			panic("Failed to allocate IRTE for ioapic %d\n", apic);
+
+		memset(&irte, 0, sizeof(irte));
+
+		irte.present = 1;
+		irte.dst_mode = INT_DEST_MODE;
+		irte.trigger_mode = trigger;
+		irte.dlvry_mode = INT_DELIVERY_MODE;
+		irte.vector = vector;
+		irte.dest_id = IRTE_DEST(destination);
+
+		modify_irte(irq, &irte);
+
+		ir_entry->index2 = (index >> 15) & 0x1;
+		ir_entry->zero = 0;
+		ir_entry->format = 1;
+		ir_entry->index = (index & 0x7fff);
+	} else
+#endif
+	{
+		entry->delivery_mode = INT_DELIVERY_MODE;
+		entry->dest_mode = INT_DEST_MODE;
+		entry->dest = destination;
 	}
+
+	entry->mask = 0;				/* enable IRQ */
+	entry->trigger = trigger;
+	entry->polarity = polarity;
+	entry->vector = vector;
+
+	/* Mask level triggered irqs.
+	 * Use IRQ_DELAYED_DISABLE for edge triggered irqs.
+	 */
+	if (trigger)
+		entry->mask = 1;
+	return 0;
 }
 
 static void setup_IO_APIC_irq(int apic, int pin, unsigned int irq,
@@ -875,24 +1028,15 @@
 		    apic, mp_ioapics[apic].mp_apicid, pin, cfg->vector,
 		    irq, trigger, polarity);
 
-	/*
-	 * add it to the IO-APIC irq-routing table:
-	 */
-	memset(&entry,0,sizeof(entry));
 
-	entry.delivery_mode = INT_DELIVERY_MODE;
-	entry.dest_mode = INT_DEST_MODE;
-	entry.dest = cpu_mask_to_apicid(mask);
-	entry.mask = 0;				/* enable IRQ */
-	entry.trigger = trigger;
-	entry.polarity = polarity;
-	entry.vector = cfg->vector;
-
-	/* Mask level triggered irqs.
-	 * Use IRQ_DELAYED_DISABLE for edge triggered irqs.
-	 */
-	if (trigger)
-		entry.mask = 1;
+	if (setup_ioapic_entry(mp_ioapics[apic].mp_apicid, irq, &entry,
+			       cpu_mask_to_apicid(mask), trigger, polarity,
+			       cfg->vector)) {
+		printk("Failed to setup ioapic entry for ioapic  %d, pin %d\n",
+		       mp_ioapics[apic].mp_apicid, pin);
+		__clear_irq_vector(irq);
+		return;
+	}
 
 	ioapic_register_intr(irq, trigger);
 	if (irq < 16)
@@ -944,6 +1088,9 @@
 {
 	struct IO_APIC_route_entry entry;
 
+	if (intr_remapping_enabled)
+		return;
+
 	memset(&entry, 0, sizeof(entry));
 
 	/*
@@ -970,7 +1117,8 @@
 	ioapic_write_entry(apic, pin, entry);
 }
 
-void __apicdebuginit print_IO_APIC(void)
+
+__apicdebuginit(void) print_IO_APIC(void)
 {
 	int apic, i;
 	union IO_APIC_reg_00 reg_00;
@@ -1064,9 +1212,7 @@
 	return;
 }
 
-#if 0
-
-static __apicdebuginit void print_APIC_bitfield (int base)
+__apicdebuginit(void) print_APIC_bitfield(int base)
 {
 	unsigned int v;
 	int i, j;
@@ -1087,9 +1233,10 @@
 	}
 }
 
-void __apicdebuginit print_local_APIC(void * dummy)
+__apicdebuginit(void) print_local_APIC(void *dummy)
 {
 	unsigned int v, ver, maxlvt;
+	unsigned long icr;
 
 	if (apic_verbosity == APIC_QUIET)
 		return;
@@ -1097,7 +1244,7 @@
 	printk("\n" KERN_DEBUG "printing local APIC contents on CPU#%d/%d:\n",
 		smp_processor_id(), hard_smp_processor_id());
 	v = apic_read(APIC_ID);
-	printk(KERN_INFO "... APIC ID:      %08x (%01x)\n", v, GET_APIC_ID(read_apic_id()));
+	printk(KERN_INFO "... APIC ID:      %08x (%01x)\n", v, read_apic_id());
 	v = apic_read(APIC_LVR);
 	printk(KERN_INFO "... APIC VERSION: %08x\n", v);
 	ver = GET_APIC_VERSION(v);
@@ -1133,10 +1280,9 @@
 	v = apic_read(APIC_ESR);
 	printk(KERN_DEBUG "... APIC ESR: %08x\n", v);
 
-	v = apic_read(APIC_ICR);
-	printk(KERN_DEBUG "... APIC ICR: %08x\n", v);
-	v = apic_read(APIC_ICR2);
-	printk(KERN_DEBUG "... APIC ICR2: %08x\n", v);
+	icr = apic_icr_read();
+	printk(KERN_DEBUG "... APIC ICR: %08x\n", (u32)icr);
+	printk(KERN_DEBUG "... APIC ICR2: %08x\n", (u32)(icr >> 32));
 
 	v = apic_read(APIC_LVTT);
 	printk(KERN_DEBUG "... APIC LVTT: %08x\n", v);
@@ -1164,12 +1310,12 @@
 	printk("\n");
 }
 
-void print_all_local_APICs (void)
+__apicdebuginit(void) print_all_local_APICs(void)
 {
 	on_each_cpu(print_local_APIC, NULL, 1);
 }
 
-void __apicdebuginit print_PIC(void)
+__apicdebuginit(void) print_PIC(void)
 {
 	unsigned int v;
 	unsigned long flags;
@@ -1201,7 +1347,17 @@
 	printk(KERN_DEBUG "... PIC ELCR: %04x\n", v);
 }
 
-#endif  /*  0  */
+__apicdebuginit(int) print_all_ICs(void)
+{
+	print_PIC();
+	print_all_local_APICs();
+	print_IO_APIC();
+
+	return 0;
+}
+
+fs_initcall(print_all_ICs);
+
 
 void __init enable_IO_APIC(void)
 {
@@ -1291,7 +1447,7 @@
 		entry.dest_mode       = 0; /* Physical */
 		entry.delivery_mode   = dest_ExtINT; /* ExtInt */
 		entry.vector          = 0;
-		entry.dest          = GET_APIC_ID(read_apic_id());
+		entry.dest            = read_apic_id();
 
 		/*
 		 * Add it to the IO-APIC irq-routing table:
@@ -1397,6 +1553,147 @@
  */
 
 #ifdef CONFIG_SMP
+
+#ifdef CONFIG_INTR_REMAP
+static void ir_irq_migration(struct work_struct *work);
+
+static DECLARE_DELAYED_WORK(ir_migration_work, ir_irq_migration);
+
+/*
+ * Migrate the IO-APIC irq in the presence of intr-remapping.
+ *
+ * For edge triggered, irq migration is a simple atomic update(of vector
+ * and cpu destination) of IRTE and flush the hardware cache.
+ *
+ * For level triggered, we need to modify the io-apic RTE aswell with the update
+ * vector information, along with modifying IRTE with vector and destination.
+ * So irq migration for level triggered is little  bit more complex compared to
+ * edge triggered migration. But the good news is, we use the same algorithm
+ * for level triggered migration as we have today, only difference being,
+ * we now initiate the irq migration from process context instead of the
+ * interrupt context.
+ *
+ * In future, when we do a directed EOI (combined with cpu EOI broadcast
+ * suppression) to the IO-APIC, level triggered irq migration will also be
+ * as simple as edge triggered migration and we can do the irq migration
+ * with a simple atomic update to IO-APIC RTE.
+ */
+static void migrate_ioapic_irq(int irq, cpumask_t mask)
+{
+	struct irq_cfg *cfg = irq_cfg + irq;
+	struct irq_desc *desc = irq_desc + irq;
+	cpumask_t tmp, cleanup_mask;
+	struct irte irte;
+	int modify_ioapic_rte = desc->status & IRQ_LEVEL;
+	unsigned int dest;
+	unsigned long flags;
+
+	cpus_and(tmp, mask, cpu_online_map);
+	if (cpus_empty(tmp))
+		return;
+
+	if (get_irte(irq, &irte))
+		return;
+
+	if (assign_irq_vector(irq, mask))
+		return;
+
+	cpus_and(tmp, cfg->domain, mask);
+	dest = cpu_mask_to_apicid(tmp);
+
+	if (modify_ioapic_rte) {
+		spin_lock_irqsave(&ioapic_lock, flags);
+		__target_IO_APIC_irq(irq, dest, cfg->vector);
+		spin_unlock_irqrestore(&ioapic_lock, flags);
+	}
+
+	irte.vector = cfg->vector;
+	irte.dest_id = IRTE_DEST(dest);
+
+	/*
+	 * Modified the IRTE and flushes the Interrupt entry cache.
+	 */
+	modify_irte(irq, &irte);
+
+	if (cfg->move_in_progress) {
+		cpus_and(cleanup_mask, cfg->old_domain, cpu_online_map);
+		cfg->move_cleanup_count = cpus_weight(cleanup_mask);
+		send_IPI_mask(cleanup_mask, IRQ_MOVE_CLEANUP_VECTOR);
+		cfg->move_in_progress = 0;
+	}
+
+	irq_desc[irq].affinity = mask;
+}
+
+static int migrate_irq_remapped_level(int irq)
+{
+	int ret = -1;
+
+	mask_IO_APIC_irq(irq);
+
+	if (io_apic_level_ack_pending(irq)) {
+		/*
+	 	 * Interrupt in progress. Migrating irq now will change the
+		 * vector information in the IO-APIC RTE and that will confuse
+		 * the EOI broadcast performed by cpu.
+		 * So, delay the irq migration to the next instance.
+		 */
+		schedule_delayed_work(&ir_migration_work, 1);
+		goto unmask;
+	}
+
+	/* everthing is clear. we have right of way */
+	migrate_ioapic_irq(irq, irq_desc[irq].pending_mask);
+
+	ret = 0;
+	irq_desc[irq].status &= ~IRQ_MOVE_PENDING;
+	cpus_clear(irq_desc[irq].pending_mask);
+
+unmask:
+	unmask_IO_APIC_irq(irq);
+	return ret;
+}
+
+static void ir_irq_migration(struct work_struct *work)
+{
+	int irq;
+
+	for (irq = 0; irq < NR_IRQS; irq++) {
+		struct irq_desc *desc = irq_desc + irq;
+		if (desc->status & IRQ_MOVE_PENDING) {
+			unsigned long flags;
+
+			spin_lock_irqsave(&desc->lock, flags);
+			if (!desc->chip->set_affinity ||
+			    !(desc->status & IRQ_MOVE_PENDING)) {
+				desc->status &= ~IRQ_MOVE_PENDING;
+				spin_unlock_irqrestore(&desc->lock, flags);
+				continue;
+			}
+
+			desc->chip->set_affinity(irq,
+					         irq_desc[irq].pending_mask);
+			spin_unlock_irqrestore(&desc->lock, flags);
+		}
+	}
+}
+
+/*
+ * Migrates the IRQ destination in the process context.
+ */
+static void set_ir_ioapic_affinity_irq(unsigned int irq, cpumask_t mask)
+{
+	if (irq_desc[irq].status & IRQ_LEVEL) {
+		irq_desc[irq].status |= IRQ_MOVE_PENDING;
+		irq_desc[irq].pending_mask = mask;
+		migrate_irq_remapped_level(irq);
+		return;
+	}
+
+	migrate_ioapic_irq(irq, mask);
+}
+#endif
+
 asmlinkage void smp_irq_move_cleanup_interrupt(void)
 {
 	unsigned vector, me;
@@ -1453,6 +1750,17 @@
 #else
 static inline void irq_complete_move(unsigned int irq) {}
 #endif
+#ifdef CONFIG_INTR_REMAP
+static void ack_x2apic_level(unsigned int irq)
+{
+	ack_x2APIC_irq();
+}
+
+static void ack_x2apic_edge(unsigned int irq)
+{
+	ack_x2APIC_irq();
+}
+#endif
 
 static void ack_apic_edge(unsigned int irq)
 {
@@ -1527,6 +1835,21 @@
 	.retrigger	= ioapic_retrigger_irq,
 };
 
+#ifdef CONFIG_INTR_REMAP
+static struct irq_chip ir_ioapic_chip __read_mostly = {
+	.name 		= "IR-IO-APIC",
+	.startup 	= startup_ioapic_irq,
+	.mask	 	= mask_IO_APIC_irq,
+	.unmask	 	= unmask_IO_APIC_irq,
+	.ack 		= ack_x2apic_edge,
+	.eoi 		= ack_x2apic_level,
+#ifdef CONFIG_SMP
+	.set_affinity 	= set_ir_ioapic_affinity_irq,
+#endif
+	.retrigger	= ioapic_retrigger_irq,
+};
+#endif
+
 static inline void init_IO_APIC_traps(void)
 {
 	int irq;
@@ -1712,6 +2035,8 @@
 	 * 8259A.
 	 */
 	if (pin1 == -1) {
+		if (intr_remapping_enabled)
+			panic("BIOS bug: timer not connected to IO-APIC");
 		pin1 = pin2;
 		apic1 = apic2;
 		no_pin1 = 1;
@@ -1738,6 +2063,8 @@
 				clear_IO_APIC_pin(0, pin1);
 			goto out;
 		}
+		if (intr_remapping_enabled)
+			panic("timer doesn't work through Interrupt-remapped IO-APIC");
 		clear_IO_APIC_pin(apic1, pin1);
 		if (!no_pin1)
 			apic_printk(APIC_QUIET, KERN_ERR "..MP-BIOS bug: "
@@ -1854,8 +2181,6 @@
 	setup_IO_APIC_irqs();
 	init_IO_APIC_traps();
 	check_timer();
-	if (!acpi_ioapic)
-		print_IO_APIC();
 }
 
 struct sysfs_ioapic_data {
@@ -1977,6 +2302,9 @@
 
 	dynamic_irq_cleanup(irq);
 
+#ifdef CONFIG_INTR_REMAP
+	free_irte(irq);
+#endif
 	spin_lock_irqsave(&vector_lock, flags);
 	__clear_irq_vector(irq);
 	spin_unlock_irqrestore(&vector_lock, flags);
@@ -1995,10 +2323,41 @@
 
 	tmp = TARGET_CPUS;
 	err = assign_irq_vector(irq, tmp);
-	if (!err) {
-		cpus_and(tmp, cfg->domain, tmp);
-		dest = cpu_mask_to_apicid(tmp);
+	if (err)
+		return err;
 
+	cpus_and(tmp, cfg->domain, tmp);
+	dest = cpu_mask_to_apicid(tmp);
+
+#ifdef CONFIG_INTR_REMAP
+	if (irq_remapped(irq)) {
+		struct irte irte;
+		int ir_index;
+		u16 sub_handle;
+
+		ir_index = map_irq_to_irte_handle(irq, &sub_handle);
+		BUG_ON(ir_index == -1);
+
+		memset (&irte, 0, sizeof(irte));
+
+		irte.present = 1;
+		irte.dst_mode = INT_DEST_MODE;
+		irte.trigger_mode = 0; /* edge */
+		irte.dlvry_mode = INT_DELIVERY_MODE;
+		irte.vector = cfg->vector;
+		irte.dest_id = IRTE_DEST(dest);
+
+		modify_irte(irq, &irte);
+
+		msg->address_hi = MSI_ADDR_BASE_HI;
+		msg->data = sub_handle;
+		msg->address_lo = MSI_ADDR_BASE_LO | MSI_ADDR_IR_EXT_INT |
+				  MSI_ADDR_IR_SHV |
+				  MSI_ADDR_IR_INDEX1(ir_index) |
+				  MSI_ADDR_IR_INDEX2(ir_index);
+	} else
+#endif
+	{
 		msg->address_hi = MSI_ADDR_BASE_HI;
 		msg->address_lo =
 			MSI_ADDR_BASE_LO |
@@ -2049,6 +2408,55 @@
 	write_msi_msg(irq, &msg);
 	irq_desc[irq].affinity = mask;
 }
+
+#ifdef CONFIG_INTR_REMAP
+/*
+ * Migrate the MSI irq to another cpumask. This migration is
+ * done in the process context using interrupt-remapping hardware.
+ */
+static void ir_set_msi_irq_affinity(unsigned int irq, cpumask_t mask)
+{
+	struct irq_cfg *cfg = irq_cfg + irq;
+	unsigned int dest;
+	cpumask_t tmp, cleanup_mask;
+	struct irte irte;
+
+	cpus_and(tmp, mask, cpu_online_map);
+	if (cpus_empty(tmp))
+		return;
+
+	if (get_irte(irq, &irte))
+		return;
+
+	if (assign_irq_vector(irq, mask))
+		return;
+
+	cpus_and(tmp, cfg->domain, mask);
+	dest = cpu_mask_to_apicid(tmp);
+
+	irte.vector = cfg->vector;
+	irte.dest_id = IRTE_DEST(dest);
+
+	/*
+	 * atomically update the IRTE with the new destination and vector.
+	 */
+	modify_irte(irq, &irte);
+
+	/*
+	 * After this point, all the interrupts will start arriving
+	 * at the new destination. So, time to cleanup the previous
+	 * vector allocation.
+	 */
+	if (cfg->move_in_progress) {
+		cpus_and(cleanup_mask, cfg->old_domain, cpu_online_map);
+		cfg->move_cleanup_count = cpus_weight(cleanup_mask);
+		send_IPI_mask(cleanup_mask, IRQ_MOVE_CLEANUP_VECTOR);
+		cfg->move_in_progress = 0;
+	}
+
+	irq_desc[irq].affinity = mask;
+}
+#endif
 #endif /* CONFIG_SMP */
 
 /*
@@ -2066,28 +2474,159 @@
 	.retrigger	= ioapic_retrigger_irq,
 };
 
-int arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc)
+#ifdef CONFIG_INTR_REMAP
+static struct irq_chip msi_ir_chip = {
+	.name		= "IR-PCI-MSI",
+	.unmask		= unmask_msi_irq,
+	.mask		= mask_msi_irq,
+	.ack		= ack_x2apic_edge,
+#ifdef CONFIG_SMP
+	.set_affinity	= ir_set_msi_irq_affinity,
+#endif
+	.retrigger	= ioapic_retrigger_irq,
+};
+
+/*
+ * Map the PCI dev to the corresponding remapping hardware unit
+ * and allocate 'nvec' consecutive interrupt-remapping table entries
+ * in it.
+ */
+static int msi_alloc_irte(struct pci_dev *dev, int irq, int nvec)
 {
+	struct intel_iommu *iommu;
+	int index;
+
+	iommu = map_dev_to_ir(dev);
+	if (!iommu) {
+		printk(KERN_ERR
+		       "Unable to map PCI %s to iommu\n", pci_name(dev));
+		return -ENOENT;
+	}
+
+	index = alloc_irte(iommu, irq, nvec);
+	if (index < 0) {
+		printk(KERN_ERR
+		       "Unable to allocate %d IRTE for PCI %s\n", nvec,
+		        pci_name(dev));
+		return -ENOSPC;
+	}
+	return index;
+}
+#endif
+
+static int setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc, int irq)
+{
+	int ret;
 	struct msi_msg msg;
-	int irq, ret;
-	irq = create_irq();
-	if (irq < 0)
-		return irq;
 
 	ret = msi_compose_msg(dev, irq, &msg);
-	if (ret < 0) {
-		destroy_irq(irq);
+	if (ret < 0)
 		return ret;
-	}
 
 	set_irq_msi(irq, desc);
 	write_msi_msg(irq, &msg);
 
-	set_irq_chip_and_handler_name(irq, &msi_chip, handle_edge_irq, "edge");
+#ifdef CONFIG_INTR_REMAP
+	if (irq_remapped(irq)) {
+		struct irq_desc *desc = irq_desc + irq;
+		/*
+		 * irq migration in process context
+		 */
+		desc->status |= IRQ_MOVE_PCNTXT;
+		set_irq_chip_and_handler_name(irq, &msi_ir_chip, handle_edge_irq, "edge");
+	} else
+#endif
+		set_irq_chip_and_handler_name(irq, &msi_chip, handle_edge_irq, "edge");
 
 	return 0;
 }
 
+int arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc)
+{
+	int irq, ret;
+
+	irq = create_irq();
+	if (irq < 0)
+		return irq;
+
+#ifdef CONFIG_INTR_REMAP
+	if (!intr_remapping_enabled)
+		goto no_ir;
+
+	ret = msi_alloc_irte(dev, irq, 1);
+	if (ret < 0)
+		goto error;
+no_ir:
+#endif
+	ret = setup_msi_irq(dev, desc, irq);
+	if (ret < 0) {
+		destroy_irq(irq);
+		return ret;
+	}
+	return 0;
+
+#ifdef CONFIG_INTR_REMAP
+error:
+	destroy_irq(irq);
+	return ret;
+#endif
+}
+
+int arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
+{
+	int irq, ret, sub_handle;
+	struct msi_desc *desc;
+#ifdef CONFIG_INTR_REMAP
+	struct intel_iommu *iommu = 0;
+	int index = 0;
+#endif
+
+	sub_handle = 0;
+	list_for_each_entry(desc, &dev->msi_list, list) {
+		irq = create_irq();
+		if (irq < 0)
+			return irq;
+#ifdef CONFIG_INTR_REMAP
+		if (!intr_remapping_enabled)
+			goto no_ir;
+
+		if (!sub_handle) {
+			/*
+			 * allocate the consecutive block of IRTE's
+			 * for 'nvec'
+			 */
+			index = msi_alloc_irte(dev, irq, nvec);
+			if (index < 0) {
+				ret = index;
+				goto error;
+			}
+		} else {
+			iommu = map_dev_to_ir(dev);
+			if (!iommu) {
+				ret = -ENOENT;
+				goto error;
+			}
+			/*
+			 * setup the mapping between the irq and the IRTE
+			 * base index, the sub_handle pointing to the
+			 * appropriate interrupt remap table entry.
+			 */
+			set_irte_irq(irq, iommu, index, sub_handle);
+		}
+no_ir:
+#endif
+		ret = setup_msi_irq(dev, desc, irq);
+		if (ret < 0)
+			goto error;
+		sub_handle++;
+	}
+	return 0;
+
+error:
+	destroy_irq(irq);
+	return ret;
+}
+
 void arch_teardown_msi_irq(unsigned int irq)
 {
 	destroy_irq(irq);
@@ -2333,6 +2872,10 @@
 				setup_IO_APIC_irq(ioapic, pin, irq,
 						  irq_trigger(irq_entry),
 						  irq_polarity(irq_entry));
+#ifdef CONFIG_INTR_REMAP
+			else if (intr_remapping_enabled)
+				set_ir_ioapic_affinity_irq(irq, TARGET_CPUS);
+#endif
 			else
 				set_ioapic_affinity_irq(irq, TARGET_CPUS);
 		}
diff --git a/arch/x86/kernel/ioport.c b/arch/x86/kernel/ioport.c
index 50e5e4a..1919143 100644
--- a/arch/x86/kernel/ioport.c
+++ b/arch/x86/kernel/ioport.c
@@ -14,6 +14,7 @@
 #include <linux/slab.h>
 #include <linux/thread_info.h>
 #include <linux/syscalls.h>
+#include <asm/syscalls.h>
 
 /* Set EXTENT bits starting at BASE in BITMAP to value TURN_ON. */
 static void set_bitmap(unsigned long *bitmap, unsigned int base,
diff --git a/arch/x86/kernel/ipi.c b/arch/x86/kernel/ipi.c
index 3f7537b..f1c688e 100644
--- a/arch/x86/kernel/ipi.c
+++ b/arch/x86/kernel/ipi.c
@@ -20,6 +20,8 @@
 
 #ifdef CONFIG_X86_32
 #include <mach_apic.h>
+#include <mach_ipi.h>
+
 /*
  * the following functions deal with sending IPIs between CPUs.
  *
@@ -147,7 +149,6 @@
 }
 
 /* must come after the send_IPI functions above for inlining */
-#include <mach_ipi.h>
 static int convert_apicid_to_cpu(int apic_id)
 {
 	int i;
diff --git a/arch/x86/kernel/irq_32.c b/arch/x86/kernel/irq_32.c
index 1cf8c1f..b71e02d 100644
--- a/arch/x86/kernel/irq_32.c
+++ b/arch/x86/kernel/irq_32.c
@@ -325,7 +325,7 @@
 		for_each_online_cpu(j)
 			seq_printf(p, "%10u ",
 				per_cpu(irq_stat,j).irq_call_count);
-		seq_printf(p, "  function call interrupts\n");
+		seq_printf(p, "  Function call interrupts\n");
 		seq_printf(p, "TLB: ");
 		for_each_online_cpu(j)
 			seq_printf(p, "%10u ",
diff --git a/arch/x86/kernel/irq_64.c b/arch/x86/kernel/irq_64.c
index 1f78b23..f065fe9 100644
--- a/arch/x86/kernel/irq_64.c
+++ b/arch/x86/kernel/irq_64.c
@@ -129,7 +129,7 @@
 		seq_printf(p, "CAL: ");
 		for_each_online_cpu(j)
 			seq_printf(p, "%10u ", cpu_pda(j)->irq_call_count);
-		seq_printf(p, "  function call interrupts\n");
+		seq_printf(p, "  Function call interrupts\n");
 		seq_printf(p, "TLB: ");
 		for_each_online_cpu(j)
 			seq_printf(p, "%10u ", cpu_pda(j)->irq_tlb_count);
diff --git a/arch/x86/kernel/irqinit_32.c b/arch/x86/kernel/irqinit_32.c
index d669142..9200a1e 100644
--- a/arch/x86/kernel/irqinit_32.c
+++ b/arch/x86/kernel/irqinit_32.c
@@ -74,6 +74,15 @@
 	}
 }
 
+/*
+ * IRQ2 is cascade interrupt to second interrupt controller
+ */
+static struct irqaction irq2 = {
+	.handler = no_action,
+	.mask = CPU_MASK_NONE,
+	.name = "cascade",
+};
+
 /* Overridden in paravirt.c */
 void init_IRQ(void) __attribute__((weak, alias("native_init_IRQ")));
 
@@ -98,6 +107,46 @@
 			set_intr_gate(vector, interrupt[i]);
 	}
 
+#if defined(CONFIG_X86_LOCAL_APIC) && defined(CONFIG_SMP)
+	/*
+	 * 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]);
+
+	/*
+	 * The reschedule interrupt is a CPU-to-CPU reschedule-helper
+	 * IPI, driven by wakeup.
+	 */
+	alloc_intr_gate(RESCHEDULE_VECTOR, reschedule_interrupt);
+
+	/* IPI for invalidation */
+	alloc_intr_gate(INVALIDATE_TLB_VECTOR, invalidate_interrupt);
+
+	/* IPI for generic function call */
+	alloc_intr_gate(CALL_FUNCTION_VECTOR, call_function_interrupt);
+
+	/* IPI for single call function */
+	set_intr_gate(CALL_FUNCTION_SINGLE_VECTOR, call_function_single_interrupt);
+#endif
+
+#ifdef CONFIG_X86_LOCAL_APIC
+	/* self generated IPI for local APIC timer */
+	alloc_intr_gate(LOCAL_TIMER_VECTOR, apic_timer_interrupt);
+
+	/* IPI vectors for APIC spurious and error interrupts */
+	alloc_intr_gate(SPURIOUS_APIC_VECTOR, spurious_interrupt);
+	alloc_intr_gate(ERROR_APIC_VECTOR, error_interrupt);
+#endif
+
+#if defined(CONFIG_X86_LOCAL_APIC) && defined(CONFIG_X86_MCE_P4THERMAL)
+	/* thermal monitor LVT interrupt */
+	alloc_intr_gate(THERMAL_APIC_VECTOR, thermal_interrupt);
+#endif
+
+	if (!acpi_ioapic)
+		setup_irq(2, &irq2);
+
 	/* setup after call gates are initialised (usually add in
 	 * the architecture specific gates)
 	 */
diff --git a/arch/x86/kernel/irqinit_64.c b/arch/x86/kernel/irqinit_64.c
index 1f26fd9..5b5be9d 100644
--- a/arch/x86/kernel/irqinit_64.c
+++ b/arch/x86/kernel/irqinit_64.c
@@ -135,7 +135,7 @@
 	[IRQ15_VECTOR + 1 ... NR_VECTORS - 1] = -1
 };
 
-static void __init init_ISA_irqs (void)
+void __init init_ISA_irqs(void)
 {
 	int i;
 
@@ -164,22 +164,8 @@
 
 void init_IRQ(void) __attribute__((weak, alias("native_init_IRQ")));
 
-void __init native_init_IRQ(void)
+static void __init smp_intr_init(void)
 {
-	int i;
-
-	init_ISA_irqs();
-	/*
-	 * Cover the whole vector space, no vector can escape
-	 * us. (some of these will be overridden and become
-	 * 'special' SMP interrupts)
-	 */
-	for (i = 0; i < (NR_VECTORS - FIRST_EXTERNAL_VECTOR); i++) {
-		int vector = FIRST_EXTERNAL_VECTOR + i;
-		if (vector != IA32_SYSCALL_VECTOR)
-			set_intr_gate(vector, interrupt[i]);
-	}
-
 #ifdef CONFIG_SMP
 	/*
 	 * The reschedule interrupt is a CPU-to-CPU reschedule-helper
@@ -207,6 +193,12 @@
 	/* Low priority IPI to cleanup after moving an irq */
 	set_intr_gate(IRQ_MOVE_CLEANUP_VECTOR, irq_move_cleanup_interrupt);
 #endif
+}
+
+static void __init apic_intr_init(void)
+{
+	smp_intr_init();
+
 	alloc_intr_gate(THERMAL_APIC_VECTOR, thermal_interrupt);
 	alloc_intr_gate(THRESHOLD_APIC_VECTOR, threshold_interrupt);
 
@@ -216,6 +208,25 @@
 	/* IPI vectors for APIC spurious and error interrupts */
 	alloc_intr_gate(SPURIOUS_APIC_VECTOR, spurious_interrupt);
 	alloc_intr_gate(ERROR_APIC_VECTOR, error_interrupt);
+}
+
+void __init native_init_IRQ(void)
+{
+	int i;
+
+	init_ISA_irqs();
+	/*
+	 * Cover the whole vector space, no vector can escape
+	 * us. (some of these will be overridden and become
+	 * 'special' SMP interrupts)
+	 */
+	for (i = 0; i < (NR_VECTORS - FIRST_EXTERNAL_VECTOR); i++) {
+		int vector = FIRST_EXTERNAL_VECTOR + i;
+		if (vector != IA32_SYSCALL_VECTOR)
+			set_intr_gate(vector, interrupt[i]);
+	}
+
+	apic_intr_init();
 
 	if (!acpi_ioapic)
 		setup_irq(2, &irq2);
diff --git a/arch/x86/kernel/k8.c b/arch/x86/kernel/k8.c
index 7377ccb..304d8bad 100644
--- a/arch/x86/kernel/k8.c
+++ b/arch/x86/kernel/k8.c
@@ -16,8 +16,9 @@
 static u32 *flush_words;
 
 struct pci_device_id k8_nb_ids[] = {
-	{ PCI_DEVICE(PCI_VENDOR_ID_AMD, 0x1103) },
-	{ PCI_DEVICE(PCI_VENDOR_ID_AMD, 0x1203) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_K8_NB_MISC) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_10H_NB_MISC) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_11H_NB_MISC) },
 	{}
 };
 EXPORT_SYMBOL(k8_nb_ids);
diff --git a/arch/x86/kernel/kdebugfs.c b/arch/x86/kernel/kdebugfs.c
index f2d43bc..ff7d3b0 100644
--- a/arch/x86/kernel/kdebugfs.c
+++ b/arch/x86/kernel/kdebugfs.c
@@ -139,6 +139,7 @@
 		if (PageHighMem(pg)) {
 			data = ioremap_cache(pa_data, sizeof(*data));
 			if (!data) {
+				kfree(node);
 				error = -ENXIO;
 				goto err_dir;
 			}
diff --git a/arch/x86/kernel/kgdb.c b/arch/x86/kernel/kgdb.c
index f47f0eb..10435a1 100644
--- a/arch/x86/kernel/kgdb.c
+++ b/arch/x86/kernel/kgdb.c
@@ -69,6 +69,9 @@
  */
 void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs)
 {
+#ifndef CONFIG_X86_32
+	u32 *gdb_regs32 = (u32 *)gdb_regs;
+#endif
 	gdb_regs[GDB_AX]	= regs->ax;
 	gdb_regs[GDB_BX]	= regs->bx;
 	gdb_regs[GDB_CX]	= regs->cx;
@@ -76,9 +79,9 @@
 	gdb_regs[GDB_SI]	= regs->si;
 	gdb_regs[GDB_DI]	= regs->di;
 	gdb_regs[GDB_BP]	= regs->bp;
-	gdb_regs[GDB_PS]	= regs->flags;
 	gdb_regs[GDB_PC]	= regs->ip;
 #ifdef CONFIG_X86_32
+	gdb_regs[GDB_PS]	= regs->flags;
 	gdb_regs[GDB_DS]	= regs->ds;
 	gdb_regs[GDB_ES]	= regs->es;
 	gdb_regs[GDB_CS]	= regs->cs;
@@ -94,6 +97,9 @@
 	gdb_regs[GDB_R13]	= regs->r13;
 	gdb_regs[GDB_R14]	= regs->r14;
 	gdb_regs[GDB_R15]	= regs->r15;
+	gdb_regs32[GDB_PS]	= regs->flags;
+	gdb_regs32[GDB_CS]	= regs->cs;
+	gdb_regs32[GDB_SS]	= regs->ss;
 #endif
 	gdb_regs[GDB_SP]	= regs->sp;
 }
@@ -112,6 +118,9 @@
  */
 void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p)
 {
+#ifndef CONFIG_X86_32
+	u32 *gdb_regs32 = (u32 *)gdb_regs;
+#endif
 	gdb_regs[GDB_AX]	= 0;
 	gdb_regs[GDB_BX]	= 0;
 	gdb_regs[GDB_CX]	= 0;
@@ -129,8 +138,10 @@
 	gdb_regs[GDB_FS]	= 0xFFFF;
 	gdb_regs[GDB_GS]	= 0xFFFF;
 #else
-	gdb_regs[GDB_PS]	= *(unsigned long *)(p->thread.sp + 8);
-	gdb_regs[GDB_PC]	= 0;
+	gdb_regs32[GDB_PS]	= *(unsigned long *)(p->thread.sp + 8);
+	gdb_regs32[GDB_CS]	= __KERNEL_CS;
+	gdb_regs32[GDB_SS]	= __KERNEL_DS;
+	gdb_regs[GDB_PC]	= p->thread.ip;
 	gdb_regs[GDB_R8]	= 0;
 	gdb_regs[GDB_R9]	= 0;
 	gdb_regs[GDB_R10]	= 0;
@@ -153,6 +164,9 @@
  */
 void gdb_regs_to_pt_regs(unsigned long *gdb_regs, struct pt_regs *regs)
 {
+#ifndef CONFIG_X86_32
+	u32 *gdb_regs32 = (u32 *)gdb_regs;
+#endif
 	regs->ax		= gdb_regs[GDB_AX];
 	regs->bx		= gdb_regs[GDB_BX];
 	regs->cx		= gdb_regs[GDB_CX];
@@ -160,9 +174,9 @@
 	regs->si		= gdb_regs[GDB_SI];
 	regs->di		= gdb_regs[GDB_DI];
 	regs->bp		= gdb_regs[GDB_BP];
-	regs->flags		= gdb_regs[GDB_PS];
 	regs->ip		= gdb_regs[GDB_PC];
 #ifdef CONFIG_X86_32
+	regs->flags		= gdb_regs[GDB_PS];
 	regs->ds		= gdb_regs[GDB_DS];
 	regs->es		= gdb_regs[GDB_ES];
 	regs->cs		= gdb_regs[GDB_CS];
@@ -175,6 +189,9 @@
 	regs->r13		= gdb_regs[GDB_R13];
 	regs->r14		= gdb_regs[GDB_R14];
 	regs->r15		= gdb_regs[GDB_R15];
+	regs->flags		= gdb_regs32[GDB_PS];
+	regs->cs		= gdb_regs32[GDB_CS];
+	regs->ss		= gdb_regs32[GDB_SS];
 #endif
 }
 
@@ -378,10 +395,8 @@
 		if (remcomInBuffer[0] == 's') {
 			linux_regs->flags |= X86_EFLAGS_TF;
 			kgdb_single_step = 1;
-			if (kgdb_contthread) {
-				atomic_set(&kgdb_cpu_doing_single_step,
-					   raw_smp_processor_id());
-			}
+			atomic_set(&kgdb_cpu_doing_single_step,
+				   raw_smp_processor_id());
 		}
 
 		get_debugreg(dr6, 6);
@@ -440,12 +455,7 @@
 		return NOTIFY_DONE;
 
 	case DIE_NMI_IPI:
-		if (atomic_read(&kgdb_active) != -1) {
-			/* KGDB CPU roundup */
-			kgdb_nmicallback(raw_smp_processor_id(), regs);
-			was_in_debug_nmi[raw_smp_processor_id()] = 1;
-			touch_nmi_watchdog();
-		}
+		/* Just ignore, we will handle the roundup on DIE_NMI. */
 		return NOTIFY_DONE;
 
 	case DIE_NMIUNKNOWN:
@@ -466,9 +476,15 @@
 
 	case DIE_DEBUG:
 		if (atomic_read(&kgdb_cpu_doing_single_step) ==
-			raw_smp_processor_id() &&
-			user_mode(regs))
-			return single_step_cont(regs, args);
+		    raw_smp_processor_id()) {
+			if (user_mode(regs))
+				return single_step_cont(regs, args);
+			break;
+		} else if (test_thread_flag(TIF_SINGLESTEP))
+			/* This means a user thread is single stepping
+			 * a system call which should be ignored
+			 */
+			return NOTIFY_DONE;
 		/* fall through */
 	default:
 		if (user_mode(regs))
diff --git a/arch/x86/kernel/kvm.c b/arch/x86/kernel/kvm.c
index 8b7a3cf..478bca9 100644
--- a/arch/x86/kernel/kvm.c
+++ b/arch/x86/kernel/kvm.c
@@ -178,7 +178,7 @@
 	kvm_deferred_mmu_op(&ftlb, sizeof ftlb);
 }
 
-static void kvm_release_pt(u32 pfn)
+static void kvm_release_pt(unsigned long pfn)
 {
 	struct kvm_mmu_op_release_pt rpt = {
 		.header.op = KVM_MMU_OP_RELEASE_PT,
diff --git a/arch/x86/kernel/ldt.c b/arch/x86/kernel/ldt.c
index b68e21f..eee32b4 100644
--- a/arch/x86/kernel/ldt.c
+++ b/arch/x86/kernel/ldt.c
@@ -18,6 +18,7 @@
 #include <asm/ldt.h>
 #include <asm/desc.h>
 #include <asm/mmu_context.h>
+#include <asm/syscalls.h>
 
 #ifdef CONFIG_SMP
 static void flush_ldt(void *current_mm)
@@ -51,6 +52,8 @@
 	memset(newldt + oldsize * LDT_ENTRY_SIZE, 0,
 	       (mincount - oldsize) * LDT_ENTRY_SIZE);
 
+	paravirt_alloc_ldt(newldt, mincount);
+
 #ifdef CONFIG_X86_64
 	/* CHECKME: Do we really need this ? */
 	wmb();
@@ -73,6 +76,7 @@
 #endif
 	}
 	if (oldsize) {
+		paravirt_free_ldt(oldldt, oldsize);
 		if (oldsize * LDT_ENTRY_SIZE > PAGE_SIZE)
 			vfree(oldldt);
 		else
@@ -84,10 +88,13 @@
 static inline int copy_ldt(mm_context_t *new, mm_context_t *old)
 {
 	int err = alloc_ldt(new, old->size, 0);
+	int i;
 
 	if (err < 0)
 		return err;
-	memcpy(new->ldt, old->ldt, old->size * LDT_ENTRY_SIZE);
+
+	for(i = 0; i < old->size; i++)
+		write_ldt_entry(new->ldt, i, old->ldt + i * LDT_ENTRY_SIZE);
 	return 0;
 }
 
@@ -124,6 +131,7 @@
 		if (mm == current->active_mm)
 			clear_LDT();
 #endif
+		paravirt_free_ldt(mm->context.ldt, mm->context.size);
 		if (mm->context.size * LDT_ENTRY_SIZE > PAGE_SIZE)
 			vfree(mm->context.ldt);
 		else
diff --git a/arch/x86/kernel/microcode.c b/arch/x86/kernel/microcode.c
deleted file mode 100644
index 652fa5c..0000000
--- a/arch/x86/kernel/microcode.c
+++ /dev/null
@@ -1,853 +0,0 @@
-/*
- *	Intel CPU Microcode Update Driver for Linux
- *
- *	Copyright (C) 2000-2006 Tigran Aivazian <tigran@aivazian.fsnet.co.uk>
- *		      2006	Shaohua Li <shaohua.li@intel.com>
- *
- *	This driver allows to upgrade microcode on Intel processors
- *	belonging to IA-32 family - PentiumPro, Pentium II,
- *	Pentium III, Xeon, Pentium 4, etc.
- *
- *	Reference: Section 8.11 of Volume 3a, IA-32 Intel? Architecture
- *	Software Developer's Manual
- *	Order Number 253668 or free download from:
- *
- *	http://developer.intel.com/design/pentium4/manuals/253668.htm
- *
- *	For more information, go to http://www.urbanmyth.org/microcode
- *
- *	This program is free software; you can redistribute it and/or
- *	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.
- *
- *	1.0	16 Feb 2000, Tigran Aivazian <tigran@sco.com>
- *		Initial release.
- *	1.01	18 Feb 2000, Tigran Aivazian <tigran@sco.com>
- *		Added read() support + cleanups.
- *	1.02	21 Feb 2000, Tigran Aivazian <tigran@sco.com>
- *		Added 'device trimming' support. open(O_WRONLY) zeroes
- *		and frees the saved copy of applied microcode.
- *	1.03	29 Feb 2000, Tigran Aivazian <tigran@sco.com>
- *		Made to use devfs (/dev/cpu/microcode) + cleanups.
- *	1.04	06 Jun 2000, Simon Trimmer <simon@veritas.com>
- *		Added misc device support (now uses both devfs and misc).
- *		Added MICROCODE_IOCFREE ioctl to clear memory.
- *	1.05	09 Jun 2000, Simon Trimmer <simon@veritas.com>
- *		Messages for error cases (non Intel & no suitable microcode).
- *	1.06	03 Aug 2000, Tigran Aivazian <tigran@veritas.com>
- *		Removed ->release(). Removed exclusive open and status bitmap.
- *		Added microcode_rwsem to serialize read()/write()/ioctl().
- *		Removed global kernel lock usage.
- *	1.07	07 Sep 2000, Tigran Aivazian <tigran@veritas.com>
- *		Write 0 to 0x8B msr and then cpuid before reading revision,
- *		so that it works even if there were no update done by the
- *		BIOS. Otherwise, reading from 0x8B gives junk (which happened
- *		to be 0 on my machine which is why it worked even when I
- *		disabled update by the BIOS)
- *		Thanks to Eric W. Biederman <ebiederman@lnxi.com> for the fix.
- *	1.08	11 Dec 2000, Richard Schaal <richard.schaal@intel.com> and
- *			     Tigran Aivazian <tigran@veritas.com>
- *		Intel Pentium 4 processor support and bugfixes.
- *	1.09	30 Oct 2001, Tigran Aivazian <tigran@veritas.com>
- *		Bugfix for HT (Hyper-Threading) enabled processors
- *		whereby processor resources are shared by all logical processors
- *		in a single CPU package.
- *	1.10	28 Feb 2002 Asit K Mallick <asit.k.mallick@intel.com> and
- *		Tigran Aivazian <tigran@veritas.com>,
- *		Serialize updates as required on HT processors due to speculative
- *		nature of implementation.
- *	1.11	22 Mar 2002 Tigran Aivazian <tigran@veritas.com>
- *		Fix the panic when writing zero-length microcode chunk.
- *	1.12	29 Sep 2003 Nitin Kamble <nitin.a.kamble@intel.com>,
- *		Jun Nakajima <jun.nakajima@intel.com>
- *		Support for the microcode updates in the new format.
- *	1.13	10 Oct 2003 Tigran Aivazian <tigran@veritas.com>
- *		Removed ->read() method and obsoleted MICROCODE_IOCFREE ioctl
- *		because we no longer hold a copy of applied microcode
- *		in kernel memory.
- *	1.14	25 Jun 2004 Tigran Aivazian <tigran@veritas.com>
- *		Fix sigmatch() macro to handle old CPUs with pf == 0.
- *		Thanks to Stuart Swales for pointing out this bug.
- */
-
-//#define DEBUG /* pr_debug */
-#include <linux/capability.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/sched.h>
-#include <linux/smp_lock.h>
-#include <linux/cpumask.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/vmalloc.h>
-#include <linux/miscdevice.h>
-#include <linux/spinlock.h>
-#include <linux/mm.h>
-#include <linux/fs.h>
-#include <linux/mutex.h>
-#include <linux/cpu.h>
-#include <linux/firmware.h>
-#include <linux/platform_device.h>
-
-#include <asm/msr.h>
-#include <asm/uaccess.h>
-#include <asm/processor.h>
-
-MODULE_DESCRIPTION("Intel CPU (IA-32) Microcode Update Driver");
-MODULE_AUTHOR("Tigran Aivazian <tigran@aivazian.fsnet.co.uk>");
-MODULE_LICENSE("GPL");
-
-#define MICROCODE_VERSION 	"1.14a"
-
-#define DEFAULT_UCODE_DATASIZE 	(2000) 	  /* 2000 bytes */
-#define MC_HEADER_SIZE		(sizeof (microcode_header_t))  	  /* 48 bytes */
-#define DEFAULT_UCODE_TOTALSIZE (DEFAULT_UCODE_DATASIZE + MC_HEADER_SIZE) /* 2048 bytes */
-#define EXT_HEADER_SIZE		(sizeof (struct extended_sigtable)) /* 20 bytes */
-#define EXT_SIGNATURE_SIZE	(sizeof (struct extended_signature)) /* 12 bytes */
-#define DWSIZE			(sizeof (u32))
-#define get_totalsize(mc) \
-	(((microcode_t *)mc)->hdr.totalsize ? \
-	 ((microcode_t *)mc)->hdr.totalsize : DEFAULT_UCODE_TOTALSIZE)
-#define get_datasize(mc) \
-	(((microcode_t *)mc)->hdr.datasize ? \
-	 ((microcode_t *)mc)->hdr.datasize : DEFAULT_UCODE_DATASIZE)
-
-#define sigmatch(s1, s2, p1, p2) \
-	(((s1) == (s2)) && (((p1) & (p2)) || (((p1) == 0) && ((p2) == 0))))
-
-#define exttable_size(et) ((et)->count * EXT_SIGNATURE_SIZE + EXT_HEADER_SIZE)
-
-/* serialize access to the physical write to MSR 0x79 */
-static DEFINE_SPINLOCK(microcode_update_lock);
-
-/* no concurrent ->write()s are allowed on /dev/cpu/microcode */
-static DEFINE_MUTEX(microcode_mutex);
-
-static struct ucode_cpu_info {
-	int valid;
-	unsigned int sig;
-	unsigned int pf;
-	unsigned int rev;
-	microcode_t *mc;
-} ucode_cpu_info[NR_CPUS];
-
-static void collect_cpu_info(int cpu_num)
-{
-	struct cpuinfo_x86 *c = &cpu_data(cpu_num);
-	struct ucode_cpu_info *uci = ucode_cpu_info + cpu_num;
-	unsigned int val[2];
-
-	/* We should bind the task to the CPU */
-	BUG_ON(raw_smp_processor_id() != cpu_num);
-	uci->pf = uci->rev = 0;
-	uci->mc = NULL;
-	uci->valid = 1;
-
-	if (c->x86_vendor != X86_VENDOR_INTEL || c->x86 < 6 ||
-	    	cpu_has(c, X86_FEATURE_IA64)) {
-		printk(KERN_ERR "microcode: CPU%d not a capable Intel "
-			"processor\n", cpu_num);
-		uci->valid = 0;
-		return;
-	}
-
-	uci->sig = cpuid_eax(0x00000001);
-
-	if ((c->x86_model >= 5) || (c->x86 > 6)) {
-		/* get processor flags from MSR 0x17 */
-		rdmsr(MSR_IA32_PLATFORM_ID, val[0], val[1]);
-		uci->pf = 1 << ((val[1] >> 18) & 7);
-	}
-
-	wrmsr(MSR_IA32_UCODE_REV, 0, 0);
-	/* see notes above for revision 1.07.  Apparent chip bug */
-	sync_core();
-	/* get the current revision from MSR 0x8B */
-	rdmsr(MSR_IA32_UCODE_REV, val[0], uci->rev);
-	pr_debug("microcode: collect_cpu_info : sig=0x%x, pf=0x%x, rev=0x%x\n",
-			uci->sig, uci->pf, uci->rev);
-}
-
-static inline int microcode_update_match(int cpu_num,
-	microcode_header_t *mc_header, int sig, int pf)
-{
-	struct ucode_cpu_info *uci = ucode_cpu_info + cpu_num;
-
-	if (!sigmatch(sig, uci->sig, pf, uci->pf)
-		|| mc_header->rev <= uci->rev)
-		return 0;
-	return 1;
-}
-
-static int microcode_sanity_check(void *mc)
-{
-	microcode_header_t *mc_header = mc;
-	struct extended_sigtable *ext_header = NULL;
-	struct extended_signature *ext_sig;
-	unsigned long total_size, data_size, ext_table_size;
-	int sum, orig_sum, ext_sigcount = 0, i;
-
-	total_size = get_totalsize(mc_header);
-	data_size = get_datasize(mc_header);
-	if (data_size + MC_HEADER_SIZE > total_size) {
-		printk(KERN_ERR "microcode: error! "
-			"Bad data size in microcode data file\n");
-		return -EINVAL;
-	}
-
-	if (mc_header->ldrver != 1 || mc_header->hdrver != 1) {
-		printk(KERN_ERR "microcode: error! "
-			"Unknown microcode update format\n");
-		return -EINVAL;
-	}
-	ext_table_size = total_size - (MC_HEADER_SIZE + data_size);
-	if (ext_table_size) {
-		if ((ext_table_size < EXT_HEADER_SIZE)
-		 || ((ext_table_size - EXT_HEADER_SIZE) % EXT_SIGNATURE_SIZE)) {
-			printk(KERN_ERR "microcode: error! "
-				"Small exttable size in microcode data file\n");
-			return -EINVAL;
-		}
-		ext_header = mc + MC_HEADER_SIZE + data_size;
-		if (ext_table_size != exttable_size(ext_header)) {
-			printk(KERN_ERR "microcode: error! "
-				"Bad exttable size in microcode data file\n");
-			return -EFAULT;
-		}
-		ext_sigcount = ext_header->count;
-	}
-
-	/* check extended table checksum */
-	if (ext_table_size) {
-		int ext_table_sum = 0;
-		int *ext_tablep = (int *)ext_header;
-
-		i = ext_table_size / DWSIZE;
-		while (i--)
-			ext_table_sum += ext_tablep[i];
-		if (ext_table_sum) {
-			printk(KERN_WARNING "microcode: aborting, "
-				"bad extended signature table checksum\n");
-			return -EINVAL;
-		}
-	}
-
-	/* calculate the checksum */
-	orig_sum = 0;
-	i = (MC_HEADER_SIZE + data_size) / DWSIZE;
-	while (i--)
-		orig_sum += ((int *)mc)[i];
-	if (orig_sum) {
-		printk(KERN_ERR "microcode: aborting, bad checksum\n");
-		return -EINVAL;
-	}
-	if (!ext_table_size)
-		return 0;
-	/* check extended signature checksum */
-	for (i = 0; i < ext_sigcount; i++) {
-		ext_sig = (void *)ext_header + EXT_HEADER_SIZE +
-			  EXT_SIGNATURE_SIZE * i;
-		sum = orig_sum
-			- (mc_header->sig + mc_header->pf + mc_header->cksum)
-			+ (ext_sig->sig + ext_sig->pf + ext_sig->cksum);
-		if (sum) {
-			printk(KERN_ERR "microcode: aborting, bad checksum\n");
-			return -EINVAL;
-		}
-	}
-	return 0;
-}
-
-/*
- * return 0 - no update found
- * return 1 - found update
- * return < 0 - error
- */
-static int get_maching_microcode(void *mc, int cpu)
-{
-	struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
-	microcode_header_t *mc_header = mc;
-	struct extended_sigtable *ext_header;
-	unsigned long total_size = get_totalsize(mc_header);
-	int ext_sigcount, i;
-	struct extended_signature *ext_sig;
-	void *new_mc;
-
-	if (microcode_update_match(cpu, mc_header,
-			mc_header->sig, mc_header->pf))
-		goto find;
-
-	if (total_size <= get_datasize(mc_header) + MC_HEADER_SIZE)
-		return 0;
-
-	ext_header = mc + get_datasize(mc_header) + MC_HEADER_SIZE;
-	ext_sigcount = ext_header->count;
-	ext_sig = (void *)ext_header + EXT_HEADER_SIZE;
-	for (i = 0; i < ext_sigcount; i++) {
-		if (microcode_update_match(cpu, mc_header,
-				ext_sig->sig, ext_sig->pf))
-			goto find;
-		ext_sig++;
-	}
-	return 0;
-find:
-	pr_debug("microcode: CPU%d found a matching microcode update with"
-		" version 0x%x (current=0x%x)\n", cpu, mc_header->rev,uci->rev);
-	new_mc = vmalloc(total_size);
-	if (!new_mc) {
-		printk(KERN_ERR "microcode: error! Can not allocate memory\n");
-		return -ENOMEM;
-	}
-
-	/* free previous update file */
-	vfree(uci->mc);
-
-	memcpy(new_mc, mc, total_size);
-	uci->mc = new_mc;
-	return 1;
-}
-
-static void apply_microcode(int cpu)
-{
-	unsigned long flags;
-	unsigned int val[2];
-	int cpu_num = raw_smp_processor_id();
-	struct ucode_cpu_info *uci = ucode_cpu_info + cpu_num;
-
-	/* We should bind the task to the CPU */
-	BUG_ON(cpu_num != cpu);
-
-	if (uci->mc == NULL)
-		return;
-
-	/* serialize access to the physical write to MSR 0x79 */
-	spin_lock_irqsave(&microcode_update_lock, flags);
-
-	/* write microcode via MSR 0x79 */
-	wrmsr(MSR_IA32_UCODE_WRITE,
-		(unsigned long) uci->mc->bits,
-		(unsigned long) uci->mc->bits >> 16 >> 16);
-	wrmsr(MSR_IA32_UCODE_REV, 0, 0);
-
-	/* see notes above for revision 1.07.  Apparent chip bug */
-	sync_core();
-
-	/* get the current revision from MSR 0x8B */
-	rdmsr(MSR_IA32_UCODE_REV, val[0], val[1]);
-
-	spin_unlock_irqrestore(&microcode_update_lock, flags);
-	if (val[1] != uci->mc->hdr.rev) {
-		printk(KERN_ERR "microcode: CPU%d update from revision "
-			"0x%x to 0x%x failed\n", cpu_num, uci->rev, val[1]);
-		return;
-	}
-	printk(KERN_INFO "microcode: CPU%d updated from revision "
-	       "0x%x to 0x%x, date = %08x \n",
-	       cpu_num, uci->rev, val[1], uci->mc->hdr.date);
-	uci->rev = val[1];
-}
-
-#ifdef CONFIG_MICROCODE_OLD_INTERFACE
-static void __user *user_buffer;	/* user area microcode data buffer */
-static unsigned int user_buffer_size;	/* it's size */
-
-static long get_next_ucode(void **mc, long offset)
-{
-	microcode_header_t mc_header;
-	unsigned long total_size;
-
-	/* No more data */
-	if (offset >= user_buffer_size)
-		return 0;
-	if (copy_from_user(&mc_header, user_buffer + offset, MC_HEADER_SIZE)) {
-		printk(KERN_ERR "microcode: error! Can not read user data\n");
-		return -EFAULT;
-	}
-	total_size = get_totalsize(&mc_header);
-	if (offset + total_size > user_buffer_size) {
-		printk(KERN_ERR "microcode: error! Bad total size in microcode "
-				"data file\n");
-		return -EINVAL;
-	}
-	*mc = vmalloc(total_size);
-	if (!*mc)
-		return -ENOMEM;
-	if (copy_from_user(*mc, user_buffer + offset, total_size)) {
-		printk(KERN_ERR "microcode: error! Can not read user data\n");
-		vfree(*mc);
-		return -EFAULT;
-	}
-	return offset + total_size;
-}
-
-static int do_microcode_update (void)
-{
-	long cursor = 0;
-	int error = 0;
-	void *new_mc = NULL;
-	int cpu;
-	cpumask_t old;
-
-	old = current->cpus_allowed;
-
-	while ((cursor = get_next_ucode(&new_mc, cursor)) > 0) {
-		error = microcode_sanity_check(new_mc);
-		if (error)
-			goto out;
-		/*
-		 * It's possible the data file has multiple matching ucode,
-		 * lets keep searching till the latest version
-		 */
-		for_each_online_cpu(cpu) {
-			struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
-
-			if (!uci->valid)
-				continue;
-			set_cpus_allowed_ptr(current, &cpumask_of_cpu(cpu));
-			error = get_maching_microcode(new_mc, cpu);
-			if (error < 0)
-				goto out;
-			if (error == 1)
-				apply_microcode(cpu);
-		}
-		vfree(new_mc);
-	}
-out:
-	if (cursor > 0)
-		vfree(new_mc);
-	if (cursor < 0)
-		error = cursor;
-	set_cpus_allowed_ptr(current, &old);
-	return error;
-}
-
-static int microcode_open (struct inode *unused1, struct file *unused2)
-{
-	cycle_kernel_lock();
-	return capable(CAP_SYS_RAWIO) ? 0 : -EPERM;
-}
-
-static ssize_t microcode_write (struct file *file, const char __user *buf, size_t len, loff_t *ppos)
-{
-	ssize_t ret;
-
-	if ((len >> PAGE_SHIFT) > num_physpages) {
-		printk(KERN_ERR "microcode: too much data (max %ld pages)\n", num_physpages);
-		return -EINVAL;
-	}
-
-	get_online_cpus();
-	mutex_lock(&microcode_mutex);
-
-	user_buffer = (void __user *) buf;
-	user_buffer_size = (int) len;
-
-	ret = do_microcode_update();
-	if (!ret)
-		ret = (ssize_t)len;
-
-	mutex_unlock(&microcode_mutex);
-	put_online_cpus();
-
-	return ret;
-}
-
-static const struct file_operations microcode_fops = {
-	.owner		= THIS_MODULE,
-	.write		= microcode_write,
-	.open		= microcode_open,
-};
-
-static struct miscdevice microcode_dev = {
-	.minor		= MICROCODE_MINOR,
-	.name		= "microcode",
-	.fops		= &microcode_fops,
-};
-
-static int __init microcode_dev_init (void)
-{
-	int error;
-
-	error = misc_register(&microcode_dev);
-	if (error) {
-		printk(KERN_ERR
-			"microcode: can't misc_register on minor=%d\n",
-			MICROCODE_MINOR);
-		return error;
-	}
-
-	return 0;
-}
-
-static void microcode_dev_exit (void)
-{
-	misc_deregister(&microcode_dev);
-}
-
-MODULE_ALIAS_MISCDEV(MICROCODE_MINOR);
-#else
-#define microcode_dev_init() 0
-#define microcode_dev_exit() do { } while(0)
-#endif
-
-static long get_next_ucode_from_buffer(void **mc, const u8 *buf,
-	unsigned long size, long offset)
-{
-	microcode_header_t *mc_header;
-	unsigned long total_size;
-
-	/* No more data */
-	if (offset >= size)
-		return 0;
-	mc_header = (microcode_header_t *)(buf + offset);
-	total_size = get_totalsize(mc_header);
-
-	if (offset + total_size > size) {
-		printk(KERN_ERR "microcode: error! Bad data in microcode data file\n");
-		return -EINVAL;
-	}
-
-	*mc = vmalloc(total_size);
-	if (!*mc) {
-		printk(KERN_ERR "microcode: error! Can not allocate memory\n");
-		return -ENOMEM;
-	}
-	memcpy(*mc, buf + offset, total_size);
-	return offset + total_size;
-}
-
-/* fake device for request_firmware */
-static struct platform_device *microcode_pdev;
-
-static int cpu_request_microcode(int cpu)
-{
-	char name[30];
-	struct cpuinfo_x86 *c = &cpu_data(cpu);
-	const struct firmware *firmware;
-	const u8 *buf;
-	unsigned long size;
-	long offset = 0;
-	int error;
-	void *mc;
-
-	/* We should bind the task to the CPU */
-	BUG_ON(cpu != raw_smp_processor_id());
-	sprintf(name,"intel-ucode/%02x-%02x-%02x",
-		c->x86, c->x86_model, c->x86_mask);
-	error = request_firmware(&firmware, name, &microcode_pdev->dev);
-	if (error) {
-		pr_debug("microcode: data file %s load failed\n", name);
-		return error;
-	}
-	buf = firmware->data;
-	size = firmware->size;
-	while ((offset = get_next_ucode_from_buffer(&mc, buf, size, offset))
-			> 0) {
-		error = microcode_sanity_check(mc);
-		if (error)
-			break;
-		error = get_maching_microcode(mc, cpu);
-		if (error < 0)
-			break;
-		/*
-		 * It's possible the data file has multiple matching ucode,
-		 * lets keep searching till the latest version
-		 */
-		if (error == 1) {
-			apply_microcode(cpu);
-			error = 0;
-		}
-		vfree(mc);
-	}
-	if (offset > 0)
-		vfree(mc);
-	if (offset < 0)
-		error = offset;
-	release_firmware(firmware);
-
-	return error;
-}
-
-static int apply_microcode_check_cpu(int cpu)
-{
-	struct cpuinfo_x86 *c = &cpu_data(cpu);
-	struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
-	cpumask_t old;
-	unsigned int val[2];
-	int err = 0;
-
-	/* Check if the microcode is available */
-	if (!uci->mc)
-		return 0;
-
-	old = current->cpus_allowed;
-	set_cpus_allowed_ptr(current, &cpumask_of_cpu(cpu));
-
-	/* Check if the microcode we have in memory matches the CPU */
-	if (c->x86_vendor != X86_VENDOR_INTEL || c->x86 < 6 ||
-	    cpu_has(c, X86_FEATURE_IA64) || uci->sig != cpuid_eax(0x00000001))
-		err = -EINVAL;
-
-	if (!err && ((c->x86_model >= 5) || (c->x86 > 6))) {
-		/* get processor flags from MSR 0x17 */
-		rdmsr(MSR_IA32_PLATFORM_ID, val[0], val[1]);
-		if (uci->pf != (1 << ((val[1] >> 18) & 7)))
-			err = -EINVAL;
-	}
-
-	if (!err) {
-		wrmsr(MSR_IA32_UCODE_REV, 0, 0);
-		/* see notes above for revision 1.07.  Apparent chip bug */
-		sync_core();
-		/* get the current revision from MSR 0x8B */
-		rdmsr(MSR_IA32_UCODE_REV, val[0], val[1]);
-		if (uci->rev != val[1])
-			err = -EINVAL;
-	}
-
-	if (!err)
-		apply_microcode(cpu);
-	else
-		printk(KERN_ERR "microcode: Could not apply microcode to CPU%d:"
-			" sig=0x%x, pf=0x%x, rev=0x%x\n",
-			cpu, uci->sig, uci->pf, uci->rev);
-
-	set_cpus_allowed_ptr(current, &old);
-	return err;
-}
-
-static void microcode_init_cpu(int cpu, int resume)
-{
-	cpumask_t old;
-	struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
-
-	old = current->cpus_allowed;
-
-	set_cpus_allowed_ptr(current, &cpumask_of_cpu(cpu));
-	mutex_lock(&microcode_mutex);
-	collect_cpu_info(cpu);
-	if (uci->valid && system_state == SYSTEM_RUNNING && !resume)
-		cpu_request_microcode(cpu);
-	mutex_unlock(&microcode_mutex);
-	set_cpus_allowed_ptr(current, &old);
-}
-
-static void microcode_fini_cpu(int cpu)
-{
-	struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
-
-	mutex_lock(&microcode_mutex);
-	uci->valid = 0;
-	vfree(uci->mc);
-	uci->mc = NULL;
-	mutex_unlock(&microcode_mutex);
-}
-
-static ssize_t reload_store(struct sys_device *dev,
-			    struct sysdev_attribute *attr,
-			    const char *buf, size_t sz)
-{
-	struct ucode_cpu_info *uci = ucode_cpu_info + dev->id;
-	char *end;
-	unsigned long val = simple_strtoul(buf, &end, 0);
-	int err = 0;
-	int cpu = dev->id;
-
-	if (end == buf)
-		return -EINVAL;
-	if (val == 1) {
-		cpumask_t old = current->cpus_allowed;
-
-		get_online_cpus();
-		set_cpus_allowed_ptr(current, &cpumask_of_cpu(cpu));
-
-		mutex_lock(&microcode_mutex);
-		if (uci->valid)
-			err = cpu_request_microcode(cpu);
-		mutex_unlock(&microcode_mutex);
-		put_online_cpus();
-		set_cpus_allowed_ptr(current, &old);
-	}
-	if (err)
-		return err;
-	return sz;
-}
-
-static ssize_t version_show(struct sys_device *dev,
-			struct sysdev_attribute *attr, char *buf)
-{
-	struct ucode_cpu_info *uci = ucode_cpu_info + dev->id;
-
-	return sprintf(buf, "0x%x\n", uci->rev);
-}
-
-static ssize_t pf_show(struct sys_device *dev,
-			struct sysdev_attribute *attr, char *buf)
-{
-	struct ucode_cpu_info *uci = ucode_cpu_info + dev->id;
-
-	return sprintf(buf, "0x%x\n", uci->pf);
-}
-
-static SYSDEV_ATTR(reload, 0200, NULL, reload_store);
-static SYSDEV_ATTR(version, 0400, version_show, NULL);
-static SYSDEV_ATTR(processor_flags, 0400, pf_show, NULL);
-
-static struct attribute *mc_default_attrs[] = {
-	&attr_reload.attr,
-	&attr_version.attr,
-	&attr_processor_flags.attr,
-	NULL
-};
-
-static struct attribute_group mc_attr_group = {
-	.attrs = mc_default_attrs,
-	.name = "microcode",
-};
-
-static int __mc_sysdev_add(struct sys_device *sys_dev, int resume)
-{
-	int err, cpu = sys_dev->id;
-	struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
-
-	if (!cpu_online(cpu))
-		return 0;
-
-	pr_debug("microcode: CPU%d added\n", cpu);
-	memset(uci, 0, sizeof(*uci));
-
-	err = sysfs_create_group(&sys_dev->kobj, &mc_attr_group);
-	if (err)
-		return err;
-
-	microcode_init_cpu(cpu, resume);
-
-	return 0;
-}
-
-static int mc_sysdev_add(struct sys_device *sys_dev)
-{
-	return __mc_sysdev_add(sys_dev, 0);
-}
-
-static int mc_sysdev_remove(struct sys_device *sys_dev)
-{
-	int cpu = sys_dev->id;
-
-	if (!cpu_online(cpu))
-		return 0;
-
-	pr_debug("microcode: CPU%d removed\n", cpu);
-	microcode_fini_cpu(cpu);
-	sysfs_remove_group(&sys_dev->kobj, &mc_attr_group);
-	return 0;
-}
-
-static int mc_sysdev_resume(struct sys_device *dev)
-{
-	int cpu = dev->id;
-
-	if (!cpu_online(cpu))
-		return 0;
-	pr_debug("microcode: CPU%d resumed\n", cpu);
-	/* only CPU 0 will apply ucode here */
-	apply_microcode(0);
-	return 0;
-}
-
-static struct sysdev_driver mc_sysdev_driver = {
-	.add = mc_sysdev_add,
-	.remove = mc_sysdev_remove,
-	.resume = mc_sysdev_resume,
-};
-
-static __cpuinit int
-mc_cpu_callback(struct notifier_block *nb, unsigned long action, void *hcpu)
-{
-	unsigned int cpu = (unsigned long)hcpu;
-	struct sys_device *sys_dev;
-
-	sys_dev = get_cpu_sysdev(cpu);
-	switch (action) {
-	case CPU_UP_CANCELED_FROZEN:
-		/* The CPU refused to come up during a system resume */
-		microcode_fini_cpu(cpu);
-		break;
-	case CPU_ONLINE:
-	case CPU_DOWN_FAILED:
-		mc_sysdev_add(sys_dev);
-		break;
-	case CPU_ONLINE_FROZEN:
-		/* System-wide resume is in progress, try to apply microcode */
-		if (apply_microcode_check_cpu(cpu)) {
-			/* The application of microcode failed */
-			microcode_fini_cpu(cpu);
-			__mc_sysdev_add(sys_dev, 1);
-			break;
-		}
-	case CPU_DOWN_FAILED_FROZEN:
-		if (sysfs_create_group(&sys_dev->kobj, &mc_attr_group))
-			printk(KERN_ERR "microcode: Failed to create the sysfs "
-				"group for CPU%d\n", cpu);
-		break;
-	case CPU_DOWN_PREPARE:
-		mc_sysdev_remove(sys_dev);
-		break;
-	case CPU_DOWN_PREPARE_FROZEN:
-		/* Suspend is in progress, only remove the interface */
-		sysfs_remove_group(&sys_dev->kobj, &mc_attr_group);
-		break;
-	}
-	return NOTIFY_OK;
-}
-
-static struct notifier_block __refdata mc_cpu_notifier = {
-	.notifier_call = mc_cpu_callback,
-};
-
-static int __init microcode_init (void)
-{
-	int error;
-
-	printk(KERN_INFO
-		"IA-32 Microcode Update Driver: v" MICROCODE_VERSION " <tigran@aivazian.fsnet.co.uk>\n");
-
-	error = microcode_dev_init();
-	if (error)
-		return error;
-	microcode_pdev = platform_device_register_simple("microcode", -1,
-							 NULL, 0);
-	if (IS_ERR(microcode_pdev)) {
-		microcode_dev_exit();
-		return PTR_ERR(microcode_pdev);
-	}
-
-	get_online_cpus();
-	error = sysdev_driver_register(&cpu_sysdev_class, &mc_sysdev_driver);
-	put_online_cpus();
-	if (error) {
-		microcode_dev_exit();
-		platform_device_unregister(microcode_pdev);
-		return error;
-	}
-
-	register_hotcpu_notifier(&mc_cpu_notifier);
-	return 0;
-}
-
-static void __exit microcode_exit (void)
-{
-	microcode_dev_exit();
-
-	unregister_hotcpu_notifier(&mc_cpu_notifier);
-
-	get_online_cpus();
-	sysdev_driver_unregister(&cpu_sysdev_class, &mc_sysdev_driver);
-	put_online_cpus();
-
-	platform_device_unregister(microcode_pdev);
-}
-
-module_init(microcode_init)
-module_exit(microcode_exit)
diff --git a/arch/x86/kernel/microcode_amd.c b/arch/x86/kernel/microcode_amd.c
new file mode 100644
index 0000000..7a1f8ee
--- /dev/null
+++ b/arch/x86/kernel/microcode_amd.c
@@ -0,0 +1,435 @@
+/*
+ *  AMD CPU Microcode Update Driver for Linux
+ *  Copyright (C) 2008 Advanced Micro Devices Inc.
+ *
+ *  Author: Peter Oruba <peter.oruba@amd.com>
+ *
+ *  Based on work by:
+ *  Tigran Aivazian <tigran@aivazian.fsnet.co.uk>
+ *
+ *  This driver allows to upgrade microcode on AMD
+ *  family 0x10 and 0x11 processors.
+ *
+ *  Licensed unter the terms of the GNU General Public
+ *  License version 2. See file COPYING for details.
+*/
+
+#include <linux/capability.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/cpumask.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/miscdevice.h>
+#include <linux/spinlock.h>
+#include <linux/mm.h>
+#include <linux/fs.h>
+#include <linux/mutex.h>
+#include <linux/cpu.h>
+#include <linux/firmware.h>
+#include <linux/platform_device.h>
+#include <linux/pci.h>
+#include <linux/pci_ids.h>
+
+#include <asm/msr.h>
+#include <asm/uaccess.h>
+#include <asm/processor.h>
+#include <asm/microcode.h>
+
+MODULE_DESCRIPTION("AMD Microcode Update Driver");
+MODULE_AUTHOR("Peter Oruba <peter.oruba@amd.com>");
+MODULE_LICENSE("GPL v2");
+
+#define UCODE_MAGIC                0x00414d44
+#define UCODE_EQUIV_CPU_TABLE_TYPE 0x00000000
+#define UCODE_UCODE_TYPE           0x00000001
+
+struct equiv_cpu_entry {
+	unsigned int installed_cpu;
+	unsigned int fixed_errata_mask;
+	unsigned int fixed_errata_compare;
+	unsigned int equiv_cpu;
+};
+
+struct microcode_header_amd {
+	unsigned int  data_code;
+	unsigned int  patch_id;
+	unsigned char mc_patch_data_id[2];
+	unsigned char mc_patch_data_len;
+	unsigned char init_flag;
+	unsigned int  mc_patch_data_checksum;
+	unsigned int  nb_dev_id;
+	unsigned int  sb_dev_id;
+	unsigned char processor_rev_id[2];
+	unsigned char nb_rev_id;
+	unsigned char sb_rev_id;
+	unsigned char bios_api_rev;
+	unsigned char reserved1[3];
+	unsigned int  match_reg[8];
+};
+
+struct microcode_amd {
+	struct microcode_header_amd hdr;
+	unsigned int mpb[0];
+};
+
+#define UCODE_MAX_SIZE          (2048)
+#define DEFAULT_UCODE_DATASIZE	(896)
+#define MC_HEADER_SIZE		(sizeof(struct microcode_header_amd))
+#define DEFAULT_UCODE_TOTALSIZE (DEFAULT_UCODE_DATASIZE + MC_HEADER_SIZE)
+#define DWSIZE			(sizeof(u32))
+/* For now we support a fixed ucode total size only */
+#define get_totalsize(mc) \
+	((((struct microcode_amd *)mc)->hdr.mc_patch_data_len * 28) \
+	 + MC_HEADER_SIZE)
+
+/* serialize access to the physical write */
+static DEFINE_SPINLOCK(microcode_update_lock);
+
+static struct equiv_cpu_entry *equiv_cpu_table;
+
+static int collect_cpu_info_amd(int cpu, struct cpu_signature *csig)
+{
+	struct cpuinfo_x86 *c = &cpu_data(cpu);
+
+	memset(csig, 0, sizeof(*csig));
+
+	if (c->x86_vendor != X86_VENDOR_AMD || c->x86 < 0x10) {
+		printk(KERN_ERR "microcode: CPU%d not a capable AMD processor\n",
+		       cpu);
+		return -1;
+	}
+
+	asm volatile("movl %1, %%ecx; rdmsr"
+		     : "=a" (csig->rev)
+		     : "i" (0x0000008B) : "ecx");
+
+	printk(KERN_INFO "microcode: collect_cpu_info_amd : patch_id=0x%x\n",
+		csig->rev);
+
+	return 0;
+}
+
+static int get_matching_microcode(int cpu, void *mc, int rev)
+{
+	struct microcode_header_amd *mc_header = mc;
+	struct pci_dev *nb_pci_dev, *sb_pci_dev;
+	unsigned int current_cpu_id;
+	unsigned int equiv_cpu_id = 0x00;
+	unsigned int i = 0;
+
+	BUG_ON(equiv_cpu_table == NULL);
+	current_cpu_id = cpuid_eax(0x00000001);
+
+	while (equiv_cpu_table[i].installed_cpu != 0) {
+		if (current_cpu_id == equiv_cpu_table[i].installed_cpu) {
+			equiv_cpu_id = equiv_cpu_table[i].equiv_cpu;
+			break;
+		}
+		i++;
+	}
+
+	if (!equiv_cpu_id) {
+		printk(KERN_ERR "microcode: CPU%d cpu_id "
+		       "not found in equivalent cpu table \n", cpu);
+		return 0;
+	}
+
+	if ((mc_header->processor_rev_id[0]) != (equiv_cpu_id & 0xff)) {
+		printk(KERN_ERR
+			"microcode: CPU%d patch does not match "
+			"(patch is %x, cpu extended is %x) \n",
+			cpu, mc_header->processor_rev_id[0],
+			(equiv_cpu_id & 0xff));
+		return 0;
+	}
+
+	if ((mc_header->processor_rev_id[1]) != ((equiv_cpu_id >> 16) & 0xff)) {
+		printk(KERN_ERR "microcode: CPU%d patch does not match "
+			"(patch is %x, cpu base id is %x) \n",
+			cpu, mc_header->processor_rev_id[1],
+			((equiv_cpu_id >> 16) & 0xff));
+
+		return 0;
+	}
+
+	/* ucode may be northbridge specific */
+	if (mc_header->nb_dev_id) {
+		nb_pci_dev = pci_get_device(PCI_VENDOR_ID_AMD,
+					    (mc_header->nb_dev_id & 0xff),
+					    NULL);
+		if ((!nb_pci_dev) ||
+		    (mc_header->nb_rev_id != nb_pci_dev->revision)) {
+			printk(KERN_ERR "microcode: CPU%d NB mismatch \n", cpu);
+			pci_dev_put(nb_pci_dev);
+			return 0;
+		}
+		pci_dev_put(nb_pci_dev);
+	}
+
+	/* ucode may be southbridge specific */
+	if (mc_header->sb_dev_id) {
+		sb_pci_dev = pci_get_device(PCI_VENDOR_ID_AMD,
+					    (mc_header->sb_dev_id & 0xff),
+					    NULL);
+		if ((!sb_pci_dev) ||
+		    (mc_header->sb_rev_id != sb_pci_dev->revision)) {
+			printk(KERN_ERR "microcode: CPU%d SB mismatch \n", cpu);
+			pci_dev_put(sb_pci_dev);
+			return 0;
+		}
+		pci_dev_put(sb_pci_dev);
+	}
+
+	if (mc_header->patch_id <= rev)
+		return 0;
+
+	return 1;
+}
+
+static void apply_microcode_amd(int cpu)
+{
+	unsigned long flags;
+	unsigned int eax, edx;
+	unsigned int rev;
+	int cpu_num = raw_smp_processor_id();
+	struct ucode_cpu_info *uci = ucode_cpu_info + cpu_num;
+	struct microcode_amd *mc_amd = uci->mc;
+	unsigned long addr;
+
+	/* We should bind the task to the CPU */
+	BUG_ON(cpu_num != cpu);
+
+	if (mc_amd == NULL)
+		return;
+
+	spin_lock_irqsave(&microcode_update_lock, flags);
+
+	addr = (unsigned long)&mc_amd->hdr.data_code;
+	edx = (unsigned int)(((unsigned long)upper_32_bits(addr)));
+	eax = (unsigned int)(((unsigned long)lower_32_bits(addr)));
+
+	asm volatile("movl %0, %%ecx; wrmsr" :
+		     : "i" (0xc0010020), "a" (eax), "d" (edx) : "ecx");
+
+	/* get patch id after patching */
+	asm volatile("movl %1, %%ecx; rdmsr"
+		     : "=a" (rev)
+		     : "i" (0x0000008B) : "ecx");
+
+	spin_unlock_irqrestore(&microcode_update_lock, flags);
+
+	/* check current patch id and patch's id for match */
+	if (rev != mc_amd->hdr.patch_id) {
+		printk(KERN_ERR "microcode: CPU%d update from revision "
+		       "0x%x to 0x%x failed\n", cpu_num,
+		       mc_amd->hdr.patch_id, rev);
+		return;
+	}
+
+	printk(KERN_INFO "microcode: CPU%d updated from revision "
+	       "0x%x to 0x%x \n",
+	       cpu_num, uci->cpu_sig.rev, mc_amd->hdr.patch_id);
+
+	uci->cpu_sig.rev = rev;
+}
+
+static void * get_next_ucode(u8 *buf, unsigned int size,
+			int (*get_ucode_data)(void *, const void *, size_t),
+			unsigned int *mc_size)
+{
+	unsigned int total_size;
+#define UCODE_CONTAINER_SECTION_HDR	8
+	u8 section_hdr[UCODE_CONTAINER_SECTION_HDR];
+	void *mc;
+
+	if (get_ucode_data(section_hdr, buf, UCODE_CONTAINER_SECTION_HDR))
+		return NULL;
+
+	if (section_hdr[0] != UCODE_UCODE_TYPE) {
+		printk(KERN_ERR "microcode: error! "
+		       "Wrong microcode payload type field\n");
+		return NULL;
+	}
+
+	total_size = (unsigned long) (section_hdr[4] + (section_hdr[5] << 8));
+
+	printk(KERN_INFO "microcode: size %u, total_size %u\n",
+		size, total_size);
+
+	if (total_size > size || total_size > UCODE_MAX_SIZE) {
+		printk(KERN_ERR "microcode: error! Bad data in microcode data file\n");
+		return NULL;
+	}
+
+	mc = vmalloc(UCODE_MAX_SIZE);
+	if (mc) {
+		memset(mc, 0, UCODE_MAX_SIZE);
+		if (get_ucode_data(mc, buf + UCODE_CONTAINER_SECTION_HDR, total_size)) {
+			vfree(mc);
+			mc = NULL;
+		} else
+			*mc_size = total_size + UCODE_CONTAINER_SECTION_HDR;
+	}
+#undef UCODE_CONTAINER_SECTION_HDR
+	return mc;
+}
+
+
+static int install_equiv_cpu_table(u8 *buf,
+		int (*get_ucode_data)(void *, const void *, size_t))
+{
+#define UCODE_CONTAINER_HEADER_SIZE	12
+	u8 *container_hdr[UCODE_CONTAINER_HEADER_SIZE];
+	unsigned int *buf_pos = (unsigned int *)container_hdr;
+	unsigned long size;
+
+	if (get_ucode_data(&container_hdr, buf, UCODE_CONTAINER_HEADER_SIZE))
+		return 0;
+
+	size = buf_pos[2];
+
+	if (buf_pos[1] != UCODE_EQUIV_CPU_TABLE_TYPE || !size) {
+		printk(KERN_ERR "microcode: error! "
+		       "Wrong microcode equivalnet cpu table\n");
+		return 0;
+	}
+
+	equiv_cpu_table = (struct equiv_cpu_entry *) vmalloc(size);
+	if (!equiv_cpu_table) {
+		printk(KERN_ERR "microcode: error, can't allocate memory for equiv CPU table\n");
+		return 0;
+	}
+
+	buf += UCODE_CONTAINER_HEADER_SIZE;
+	if (get_ucode_data(equiv_cpu_table, buf, size)) {
+		vfree(equiv_cpu_table);
+		return 0;
+	}
+
+	return size + UCODE_CONTAINER_HEADER_SIZE; /* add header length */
+#undef UCODE_CONTAINER_HEADER_SIZE
+}
+
+static void free_equiv_cpu_table(void)
+{
+	if (equiv_cpu_table) {
+		vfree(equiv_cpu_table);
+		equiv_cpu_table = NULL;
+	}
+}
+
+static int generic_load_microcode(int cpu, void *data, size_t size,
+		int (*get_ucode_data)(void *, const void *, size_t))
+{
+	struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
+	u8 *ucode_ptr = data, *new_mc = NULL, *mc;
+	int new_rev = uci->cpu_sig.rev;
+	unsigned int leftover;
+	unsigned long offset;
+
+	offset = install_equiv_cpu_table(ucode_ptr, get_ucode_data);
+	if (!offset) {
+		printk(KERN_ERR "microcode: installing equivalent cpu table failed\n");
+		return -EINVAL;
+	}
+
+	ucode_ptr += offset;
+	leftover = size - offset;
+
+	while (leftover) {
+		unsigned int uninitialized_var(mc_size);
+		struct microcode_header_amd *mc_header;
+
+		mc = get_next_ucode(ucode_ptr, leftover, get_ucode_data, &mc_size);
+		if (!mc)
+			break;
+
+		mc_header = (struct microcode_header_amd *)mc;
+		if (get_matching_microcode(cpu, mc, new_rev)) {
+			if (new_mc)
+				vfree(new_mc);
+			new_rev = mc_header->patch_id;
+			new_mc  = mc;
+		} else 
+			vfree(mc);
+
+		ucode_ptr += mc_size;
+		leftover  -= mc_size;
+	}
+
+	if (new_mc) {
+		if (!leftover) {
+			if (uci->mc)
+				vfree(uci->mc);
+			uci->mc = new_mc;
+			pr_debug("microcode: CPU%d found a matching microcode update with"
+				" version 0x%x (current=0x%x)\n",
+				cpu, new_rev, uci->cpu_sig.rev);
+		} else
+			vfree(new_mc);
+	}
+
+	free_equiv_cpu_table();
+
+	return (int)leftover;
+}
+
+static int get_ucode_fw(void *to, const void *from, size_t n)
+{
+	memcpy(to, from, n);
+	return 0;
+}
+
+static int request_microcode_fw(int cpu, struct device *device)
+{
+	const char *fw_name = "amd-ucode/microcode_amd.bin";
+	const struct firmware *firmware;
+	int ret;
+
+	/* We should bind the task to the CPU */
+	BUG_ON(cpu != raw_smp_processor_id());
+
+	ret = request_firmware(&firmware, fw_name, device);
+	if (ret) {
+		printk(KERN_ERR "microcode: ucode data file %s load failed\n", fw_name);
+		return ret;
+	}
+
+	ret = generic_load_microcode(cpu, (void*)firmware->data, firmware->size,
+			&get_ucode_fw);
+
+	release_firmware(firmware);
+
+	return ret;
+}
+
+static int request_microcode_user(int cpu, const void __user *buf, size_t size)
+{
+	printk(KERN_WARNING "microcode: AMD microcode update via /dev/cpu/microcode"
+			"is not supported\n");
+	return -1;
+}
+
+static void microcode_fini_cpu_amd(int cpu)
+{
+	struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
+
+	vfree(uci->mc);
+	uci->mc = NULL;
+}
+
+static struct microcode_ops microcode_amd_ops = {
+	.request_microcode_user           = request_microcode_user,
+	.request_microcode_fw             = request_microcode_fw,
+	.collect_cpu_info                 = collect_cpu_info_amd,
+	.apply_microcode                  = apply_microcode_amd,
+	.microcode_fini_cpu               = microcode_fini_cpu_amd,
+};
+
+struct microcode_ops * __init init_amd_microcode(void)
+{
+	return &microcode_amd_ops;
+}
diff --git a/arch/x86/kernel/microcode_core.c b/arch/x86/kernel/microcode_core.c
new file mode 100644
index 0000000..936d8d5
--- /dev/null
+++ b/arch/x86/kernel/microcode_core.c
@@ -0,0 +1,508 @@
+/*
+ *	Intel CPU Microcode Update Driver for Linux
+ *
+ *	Copyright (C) 2000-2006 Tigran Aivazian <tigran@aivazian.fsnet.co.uk>
+ *		      2006	Shaohua Li <shaohua.li@intel.com>
+ *
+ *	This driver allows to upgrade microcode on Intel processors
+ *	belonging to IA-32 family - PentiumPro, Pentium II,
+ *	Pentium III, Xeon, Pentium 4, etc.
+ *
+ *	Reference: Section 8.11 of Volume 3a, IA-32 Intel? Architecture
+ *	Software Developer's Manual
+ *	Order Number 253668 or free download from:
+ *
+ *	http://developer.intel.com/design/pentium4/manuals/253668.htm
+ *
+ *	For more information, go to http://www.urbanmyth.org/microcode
+ *
+ *	This program is free software; you can redistribute it and/or
+ *	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.
+ *
+ *	1.0	16 Feb 2000, Tigran Aivazian <tigran@sco.com>
+ *		Initial release.
+ *	1.01	18 Feb 2000, Tigran Aivazian <tigran@sco.com>
+ *		Added read() support + cleanups.
+ *	1.02	21 Feb 2000, Tigran Aivazian <tigran@sco.com>
+ *		Added 'device trimming' support. open(O_WRONLY) zeroes
+ *		and frees the saved copy of applied microcode.
+ *	1.03	29 Feb 2000, Tigran Aivazian <tigran@sco.com>
+ *		Made to use devfs (/dev/cpu/microcode) + cleanups.
+ *	1.04	06 Jun 2000, Simon Trimmer <simon@veritas.com>
+ *		Added misc device support (now uses both devfs and misc).
+ *		Added MICROCODE_IOCFREE ioctl to clear memory.
+ *	1.05	09 Jun 2000, Simon Trimmer <simon@veritas.com>
+ *		Messages for error cases (non Intel & no suitable microcode).
+ *	1.06	03 Aug 2000, Tigran Aivazian <tigran@veritas.com>
+ *		Removed ->release(). Removed exclusive open and status bitmap.
+ *		Added microcode_rwsem to serialize read()/write()/ioctl().
+ *		Removed global kernel lock usage.
+ *	1.07	07 Sep 2000, Tigran Aivazian <tigran@veritas.com>
+ *		Write 0 to 0x8B msr and then cpuid before reading revision,
+ *		so that it works even if there were no update done by the
+ *		BIOS. Otherwise, reading from 0x8B gives junk (which happened
+ *		to be 0 on my machine which is why it worked even when I
+ *		disabled update by the BIOS)
+ *		Thanks to Eric W. Biederman <ebiederman@lnxi.com> for the fix.
+ *	1.08	11 Dec 2000, Richard Schaal <richard.schaal@intel.com> and
+ *			     Tigran Aivazian <tigran@veritas.com>
+ *		Intel Pentium 4 processor support and bugfixes.
+ *	1.09	30 Oct 2001, Tigran Aivazian <tigran@veritas.com>
+ *		Bugfix for HT (Hyper-Threading) enabled processors
+ *		whereby processor resources are shared by all logical processors
+ *		in a single CPU package.
+ *	1.10	28 Feb 2002 Asit K Mallick <asit.k.mallick@intel.com> and
+ *		Tigran Aivazian <tigran@veritas.com>,
+ *		Serialize updates as required on HT processors due to
+ *		speculative nature of implementation.
+ *	1.11	22 Mar 2002 Tigran Aivazian <tigran@veritas.com>
+ *		Fix the panic when writing zero-length microcode chunk.
+ *	1.12	29 Sep 2003 Nitin Kamble <nitin.a.kamble@intel.com>,
+ *		Jun Nakajima <jun.nakajima@intel.com>
+ *		Support for the microcode updates in the new format.
+ *	1.13	10 Oct 2003 Tigran Aivazian <tigran@veritas.com>
+ *		Removed ->read() method and obsoleted MICROCODE_IOCFREE ioctl
+ *		because we no longer hold a copy of applied microcode
+ *		in kernel memory.
+ *	1.14	25 Jun 2004 Tigran Aivazian <tigran@veritas.com>
+ *		Fix sigmatch() macro to handle old CPUs with pf == 0.
+ *		Thanks to Stuart Swales for pointing out this bug.
+ */
+#include <linux/capability.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/smp_lock.h>
+#include <linux/cpumask.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/miscdevice.h>
+#include <linux/spinlock.h>
+#include <linux/mm.h>
+#include <linux/fs.h>
+#include <linux/mutex.h>
+#include <linux/cpu.h>
+#include <linux/firmware.h>
+#include <linux/platform_device.h>
+
+#include <asm/msr.h>
+#include <asm/uaccess.h>
+#include <asm/processor.h>
+#include <asm/microcode.h>
+
+MODULE_DESCRIPTION("Microcode Update Driver");
+MODULE_AUTHOR("Tigran Aivazian <tigran@aivazian.fsnet.co.uk>");
+MODULE_LICENSE("GPL");
+
+#define MICROCODE_VERSION 	"2.00"
+
+struct microcode_ops *microcode_ops;
+
+/* no concurrent ->write()s are allowed on /dev/cpu/microcode */
+static DEFINE_MUTEX(microcode_mutex);
+
+struct ucode_cpu_info ucode_cpu_info[NR_CPUS];
+EXPORT_SYMBOL_GPL(ucode_cpu_info);
+
+#ifdef CONFIG_MICROCODE_OLD_INTERFACE
+static int do_microcode_update(const void __user *buf, size_t size)
+{
+	cpumask_t old;
+	int error = 0;
+	int cpu;
+
+	old = current->cpus_allowed;
+
+	for_each_online_cpu(cpu) {
+		struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
+
+		if (!uci->valid)
+			continue;
+
+		set_cpus_allowed_ptr(current, &cpumask_of_cpu(cpu));
+		error = microcode_ops->request_microcode_user(cpu, buf, size);
+		if (error < 0)
+			goto out;
+		if (!error)
+			microcode_ops->apply_microcode(cpu);
+	}
+out:
+	set_cpus_allowed_ptr(current, &old);
+	return error;
+}
+
+static int microcode_open(struct inode *unused1, struct file *unused2)
+{
+	cycle_kernel_lock();
+	return capable(CAP_SYS_RAWIO) ? 0 : -EPERM;
+}
+
+static ssize_t microcode_write(struct file *file, const char __user *buf,
+			       size_t len, loff_t *ppos)
+{
+	ssize_t ret;
+
+	if ((len >> PAGE_SHIFT) > num_physpages) {
+		printk(KERN_ERR "microcode: too much data (max %ld pages)\n",
+		       num_physpages);
+		return -EINVAL;
+	}
+
+	get_online_cpus();
+	mutex_lock(&microcode_mutex);
+
+	ret = do_microcode_update(buf, len);
+	if (!ret)
+		ret = (ssize_t)len;
+
+	mutex_unlock(&microcode_mutex);
+	put_online_cpus();
+
+	return ret;
+}
+
+static const struct file_operations microcode_fops = {
+	.owner		= THIS_MODULE,
+	.write		= microcode_write,
+	.open		= microcode_open,
+};
+
+static struct miscdevice microcode_dev = {
+	.minor		= MICROCODE_MINOR,
+	.name		= "microcode",
+	.fops		= &microcode_fops,
+};
+
+static int __init microcode_dev_init(void)
+{
+	int error;
+
+	error = misc_register(&microcode_dev);
+	if (error) {
+		printk(KERN_ERR
+			"microcode: can't misc_register on minor=%d\n",
+			MICROCODE_MINOR);
+		return error;
+	}
+
+	return 0;
+}
+
+static void microcode_dev_exit(void)
+{
+	misc_deregister(&microcode_dev);
+}
+
+MODULE_ALIAS_MISCDEV(MICROCODE_MINOR);
+#else
+#define microcode_dev_init() 0
+#define microcode_dev_exit() do { } while (0)
+#endif
+
+/* fake device for request_firmware */
+struct platform_device *microcode_pdev;
+
+static ssize_t reload_store(struct sys_device *dev,
+			    struct sysdev_attribute *attr,
+			    const char *buf, size_t sz)
+{
+	struct ucode_cpu_info *uci = ucode_cpu_info + dev->id;
+	char *end;
+	unsigned long val = simple_strtoul(buf, &end, 0);
+	int err = 0;
+	int cpu = dev->id;
+
+	if (end == buf)
+		return -EINVAL;
+	if (val == 1) {
+		cpumask_t old = current->cpus_allowed;
+
+		get_online_cpus();
+		if (cpu_online(cpu)) {
+			set_cpus_allowed_ptr(current, &cpumask_of_cpu(cpu));
+			mutex_lock(&microcode_mutex);
+			if (uci->valid) {
+				err = microcode_ops->request_microcode_fw(cpu,
+						&microcode_pdev->dev);
+				if (!err)
+					microcode_ops->apply_microcode(cpu);
+			}
+			mutex_unlock(&microcode_mutex);
+			set_cpus_allowed_ptr(current, &old);
+		}
+		put_online_cpus();
+	}
+	if (err)
+		return err;
+	return sz;
+}
+
+static ssize_t version_show(struct sys_device *dev,
+			struct sysdev_attribute *attr, char *buf)
+{
+	struct ucode_cpu_info *uci = ucode_cpu_info + dev->id;
+
+	return sprintf(buf, "0x%x\n", uci->cpu_sig.rev);
+}
+
+static ssize_t pf_show(struct sys_device *dev,
+			struct sysdev_attribute *attr, char *buf)
+{
+	struct ucode_cpu_info *uci = ucode_cpu_info + dev->id;
+
+	return sprintf(buf, "0x%x\n", uci->cpu_sig.pf);
+}
+
+static SYSDEV_ATTR(reload, 0200, NULL, reload_store);
+static SYSDEV_ATTR(version, 0400, version_show, NULL);
+static SYSDEV_ATTR(processor_flags, 0400, pf_show, NULL);
+
+static struct attribute *mc_default_attrs[] = {
+	&attr_reload.attr,
+	&attr_version.attr,
+	&attr_processor_flags.attr,
+	NULL
+};
+
+static struct attribute_group mc_attr_group = {
+	.attrs = mc_default_attrs,
+	.name = "microcode",
+};
+
+static void microcode_fini_cpu(int cpu)
+{
+	struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
+
+	mutex_lock(&microcode_mutex);
+	microcode_ops->microcode_fini_cpu(cpu);
+	uci->valid = 0;
+	mutex_unlock(&microcode_mutex);
+}
+
+static void collect_cpu_info(int cpu)
+{
+	struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
+
+	memset(uci, 0, sizeof(*uci));
+	if (!microcode_ops->collect_cpu_info(cpu, &uci->cpu_sig))
+		uci->valid = 1;
+}
+
+static int microcode_resume_cpu(int cpu)
+{
+	struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
+	struct cpu_signature nsig;
+
+	pr_debug("microcode: CPU%d resumed\n", cpu);
+
+	if (!uci->mc)
+		return 1;
+
+	/*
+	 * Let's verify that the 'cached' ucode does belong
+	 * to this cpu (a bit of paranoia):
+	 */
+	if (microcode_ops->collect_cpu_info(cpu, &nsig)) {
+		microcode_fini_cpu(cpu);
+		return -1;
+	}
+
+	if (memcmp(&nsig, &uci->cpu_sig, sizeof(nsig))) {
+		microcode_fini_cpu(cpu);
+		/* Should we look for a new ucode here? */
+		return 1;
+	}
+
+	return 0;
+}
+
+void microcode_update_cpu(int cpu)
+{
+	struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
+	int err = 0;
+
+	/*
+	 * Check if the system resume is in progress (uci->valid != NULL),
+	 * otherwise just request a firmware:
+	 */
+	if (uci->valid) {
+		err = microcode_resume_cpu(cpu);
+	} else {	
+		collect_cpu_info(cpu);
+		if (uci->valid && system_state == SYSTEM_RUNNING)
+			err = microcode_ops->request_microcode_fw(cpu,
+					&microcode_pdev->dev);
+	}
+	if (!err)
+		microcode_ops->apply_microcode(cpu);
+}
+
+static void microcode_init_cpu(int cpu)
+{
+	cpumask_t old = current->cpus_allowed;
+
+	set_cpus_allowed_ptr(current, &cpumask_of_cpu(cpu));
+	/* We should bind the task to the CPU */
+	BUG_ON(raw_smp_processor_id() != cpu);
+
+	mutex_lock(&microcode_mutex);
+	microcode_update_cpu(cpu);
+	mutex_unlock(&microcode_mutex);
+
+	set_cpus_allowed_ptr(current, &old);
+}
+
+static int mc_sysdev_add(struct sys_device *sys_dev)
+{
+	int err, cpu = sys_dev->id;
+	struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
+
+	if (!cpu_online(cpu))
+		return 0;
+
+	pr_debug("microcode: CPU%d added\n", cpu);
+	memset(uci, 0, sizeof(*uci));
+
+	err = sysfs_create_group(&sys_dev->kobj, &mc_attr_group);
+	if (err)
+		return err;
+
+	microcode_init_cpu(cpu);
+	return 0;
+}
+
+static int mc_sysdev_remove(struct sys_device *sys_dev)
+{
+	int cpu = sys_dev->id;
+
+	if (!cpu_online(cpu))
+		return 0;
+
+	pr_debug("microcode: CPU%d removed\n", cpu);
+	microcode_fini_cpu(cpu);
+	sysfs_remove_group(&sys_dev->kobj, &mc_attr_group);
+	return 0;
+}
+
+static int mc_sysdev_resume(struct sys_device *dev)
+{
+	int cpu = dev->id;
+
+	if (!cpu_online(cpu))
+		return 0;
+
+	/* only CPU 0 will apply ucode here */
+	microcode_update_cpu(0);
+	return 0;
+}
+
+static struct sysdev_driver mc_sysdev_driver = {
+	.add = mc_sysdev_add,
+	.remove = mc_sysdev_remove,
+	.resume = mc_sysdev_resume,
+};
+
+static __cpuinit int
+mc_cpu_callback(struct notifier_block *nb, unsigned long action, void *hcpu)
+{
+	unsigned int cpu = (unsigned long)hcpu;
+	struct sys_device *sys_dev;
+
+	sys_dev = get_cpu_sysdev(cpu);
+	switch (action) {
+	case CPU_ONLINE:
+	case CPU_ONLINE_FROZEN:
+		microcode_init_cpu(cpu);
+	case CPU_DOWN_FAILED:
+	case CPU_DOWN_FAILED_FROZEN:
+		pr_debug("microcode: CPU%d added\n", cpu);
+		if (sysfs_create_group(&sys_dev->kobj, &mc_attr_group))
+			printk(KERN_ERR "microcode: Failed to create the sysfs "
+				"group for CPU%d\n", cpu);
+		break;
+	case CPU_DOWN_PREPARE:
+	case CPU_DOWN_PREPARE_FROZEN:
+		/* Suspend is in progress, only remove the interface */
+		sysfs_remove_group(&sys_dev->kobj, &mc_attr_group);
+		pr_debug("microcode: CPU%d removed\n", cpu);
+		break;
+	case CPU_DEAD:
+	case CPU_UP_CANCELED_FROZEN:
+		/* The CPU refused to come up during a system resume */
+		microcode_fini_cpu(cpu);
+		break;
+	}
+	return NOTIFY_OK;
+}
+
+static struct notifier_block __refdata mc_cpu_notifier = {
+	.notifier_call = mc_cpu_callback,
+};
+
+static int __init microcode_init(void)
+{
+	struct cpuinfo_x86 *c = &cpu_data(0);
+	int error;
+
+	if (c->x86_vendor == X86_VENDOR_INTEL)
+		microcode_ops = init_intel_microcode();
+	else if (c->x86_vendor == X86_VENDOR_AMD)
+		microcode_ops = init_amd_microcode();
+
+	if (!microcode_ops) {
+		printk(KERN_ERR "microcode: no support for this CPU vendor\n");
+		return -ENODEV;
+	}
+
+	error = microcode_dev_init();
+	if (error)
+		return error;
+	microcode_pdev = platform_device_register_simple("microcode", -1,
+							 NULL, 0);
+	if (IS_ERR(microcode_pdev)) {
+		microcode_dev_exit();
+		return PTR_ERR(microcode_pdev);
+	}
+
+	get_online_cpus();
+	error = sysdev_driver_register(&cpu_sysdev_class, &mc_sysdev_driver);
+	put_online_cpus();
+	if (error) {
+		microcode_dev_exit();
+		platform_device_unregister(microcode_pdev);
+		return error;
+	}
+
+	register_hotcpu_notifier(&mc_cpu_notifier);
+
+	printk(KERN_INFO
+	       "Microcode Update Driver: v" MICROCODE_VERSION
+	       " <tigran@aivazian.fsnet.co.uk>"
+	       " <peter.oruba@amd.com>\n");
+
+	return 0;
+}
+
+static void __exit microcode_exit(void)
+{
+	microcode_dev_exit();
+
+	unregister_hotcpu_notifier(&mc_cpu_notifier);
+
+	get_online_cpus();
+	sysdev_driver_unregister(&cpu_sysdev_class, &mc_sysdev_driver);
+	put_online_cpus();
+
+	platform_device_unregister(microcode_pdev);
+
+	microcode_ops = NULL;
+
+	printk(KERN_INFO
+	       "Microcode Update Driver: v" MICROCODE_VERSION " removed.\n");
+}
+
+module_init(microcode_init);
+module_exit(microcode_exit);
diff --git a/arch/x86/kernel/microcode_intel.c b/arch/x86/kernel/microcode_intel.c
new file mode 100644
index 0000000..622dc4a
--- /dev/null
+++ b/arch/x86/kernel/microcode_intel.c
@@ -0,0 +1,480 @@
+/*
+ *	Intel CPU Microcode Update Driver for Linux
+ *
+ *	Copyright (C) 2000-2006 Tigran Aivazian <tigran@aivazian.fsnet.co.uk>
+ *		      2006	Shaohua Li <shaohua.li@intel.com>
+ *
+ *	This driver allows to upgrade microcode on Intel processors
+ *	belonging to IA-32 family - PentiumPro, Pentium II,
+ *	Pentium III, Xeon, Pentium 4, etc.
+ *
+ *	Reference: Section 8.11 of Volume 3a, IA-32 Intel? Architecture
+ *	Software Developer's Manual
+ *	Order Number 253668 or free download from:
+ *
+ *	http://developer.intel.com/design/pentium4/manuals/253668.htm
+ *
+ *	For more information, go to http://www.urbanmyth.org/microcode
+ *
+ *	This program is free software; you can redistribute it and/or
+ *	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.
+ *
+ *	1.0	16 Feb 2000, Tigran Aivazian <tigran@sco.com>
+ *		Initial release.
+ *	1.01	18 Feb 2000, Tigran Aivazian <tigran@sco.com>
+ *		Added read() support + cleanups.
+ *	1.02	21 Feb 2000, Tigran Aivazian <tigran@sco.com>
+ *		Added 'device trimming' support. open(O_WRONLY) zeroes
+ *		and frees the saved copy of applied microcode.
+ *	1.03	29 Feb 2000, Tigran Aivazian <tigran@sco.com>
+ *		Made to use devfs (/dev/cpu/microcode) + cleanups.
+ *	1.04	06 Jun 2000, Simon Trimmer <simon@veritas.com>
+ *		Added misc device support (now uses both devfs and misc).
+ *		Added MICROCODE_IOCFREE ioctl to clear memory.
+ *	1.05	09 Jun 2000, Simon Trimmer <simon@veritas.com>
+ *		Messages for error cases (non Intel & no suitable microcode).
+ *	1.06	03 Aug 2000, Tigran Aivazian <tigran@veritas.com>
+ *		Removed ->release(). Removed exclusive open and status bitmap.
+ *		Added microcode_rwsem to serialize read()/write()/ioctl().
+ *		Removed global kernel lock usage.
+ *	1.07	07 Sep 2000, Tigran Aivazian <tigran@veritas.com>
+ *		Write 0 to 0x8B msr and then cpuid before reading revision,
+ *		so that it works even if there were no update done by the
+ *		BIOS. Otherwise, reading from 0x8B gives junk (which happened
+ *		to be 0 on my machine which is why it worked even when I
+ *		disabled update by the BIOS)
+ *		Thanks to Eric W. Biederman <ebiederman@lnxi.com> for the fix.
+ *	1.08	11 Dec 2000, Richard Schaal <richard.schaal@intel.com> and
+ *			     Tigran Aivazian <tigran@veritas.com>
+ *		Intel Pentium 4 processor support and bugfixes.
+ *	1.09	30 Oct 2001, Tigran Aivazian <tigran@veritas.com>
+ *		Bugfix for HT (Hyper-Threading) enabled processors
+ *		whereby processor resources are shared by all logical processors
+ *		in a single CPU package.
+ *	1.10	28 Feb 2002 Asit K Mallick <asit.k.mallick@intel.com> and
+ *		Tigran Aivazian <tigran@veritas.com>,
+ *		Serialize updates as required on HT processors due to
+ *		speculative nature of implementation.
+ *	1.11	22 Mar 2002 Tigran Aivazian <tigran@veritas.com>
+ *		Fix the panic when writing zero-length microcode chunk.
+ *	1.12	29 Sep 2003 Nitin Kamble <nitin.a.kamble@intel.com>,
+ *		Jun Nakajima <jun.nakajima@intel.com>
+ *		Support for the microcode updates in the new format.
+ *	1.13	10 Oct 2003 Tigran Aivazian <tigran@veritas.com>
+ *		Removed ->read() method and obsoleted MICROCODE_IOCFREE ioctl
+ *		because we no longer hold a copy of applied microcode
+ *		in kernel memory.
+ *	1.14	25 Jun 2004 Tigran Aivazian <tigran@veritas.com>
+ *		Fix sigmatch() macro to handle old CPUs with pf == 0.
+ *		Thanks to Stuart Swales for pointing out this bug.
+ */
+#include <linux/capability.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/smp_lock.h>
+#include <linux/cpumask.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/miscdevice.h>
+#include <linux/spinlock.h>
+#include <linux/mm.h>
+#include <linux/fs.h>
+#include <linux/mutex.h>
+#include <linux/cpu.h>
+#include <linux/firmware.h>
+#include <linux/platform_device.h>
+
+#include <asm/msr.h>
+#include <asm/uaccess.h>
+#include <asm/processor.h>
+#include <asm/microcode.h>
+
+MODULE_DESCRIPTION("Microcode Update Driver");
+MODULE_AUTHOR("Tigran Aivazian <tigran@aivazian.fsnet.co.uk>");
+MODULE_LICENSE("GPL");
+
+struct microcode_header_intel {
+	unsigned int            hdrver;
+	unsigned int            rev;
+	unsigned int            date;
+	unsigned int            sig;
+	unsigned int            cksum;
+	unsigned int            ldrver;
+	unsigned int            pf;
+	unsigned int            datasize;
+	unsigned int            totalsize;
+	unsigned int            reserved[3];
+};
+
+struct microcode_intel {
+	struct microcode_header_intel hdr;
+	unsigned int            bits[0];
+};
+
+/* microcode format is extended from prescott processors */
+struct extended_signature {
+	unsigned int            sig;
+	unsigned int            pf;
+	unsigned int            cksum;
+};
+
+struct extended_sigtable {
+	unsigned int            count;
+	unsigned int            cksum;
+	unsigned int            reserved[3];
+	struct extended_signature sigs[0];
+};
+
+#define DEFAULT_UCODE_DATASIZE 	(2000)
+#define MC_HEADER_SIZE		(sizeof(struct microcode_header_intel))
+#define DEFAULT_UCODE_TOTALSIZE (DEFAULT_UCODE_DATASIZE + MC_HEADER_SIZE)
+#define EXT_HEADER_SIZE		(sizeof(struct extended_sigtable))
+#define EXT_SIGNATURE_SIZE	(sizeof(struct extended_signature))
+#define DWSIZE			(sizeof(u32))
+#define get_totalsize(mc) \
+	(((struct microcode_intel *)mc)->hdr.totalsize ? \
+	 ((struct microcode_intel *)mc)->hdr.totalsize : \
+	 DEFAULT_UCODE_TOTALSIZE)
+
+#define get_datasize(mc) \
+	(((struct microcode_intel *)mc)->hdr.datasize ? \
+	 ((struct microcode_intel *)mc)->hdr.datasize : DEFAULT_UCODE_DATASIZE)
+
+#define sigmatch(s1, s2, p1, p2) \
+	(((s1) == (s2)) && (((p1) & (p2)) || (((p1) == 0) && ((p2) == 0))))
+
+#define exttable_size(et) ((et)->count * EXT_SIGNATURE_SIZE + EXT_HEADER_SIZE)
+
+/* serialize access to the physical write to MSR 0x79 */
+static DEFINE_SPINLOCK(microcode_update_lock);
+
+static int collect_cpu_info(int cpu_num, struct cpu_signature *csig)
+{
+	struct cpuinfo_x86 *c = &cpu_data(cpu_num);
+	unsigned int val[2];
+
+	memset(csig, 0, sizeof(*csig));
+
+	if (c->x86_vendor != X86_VENDOR_INTEL || c->x86 < 6 ||
+	    cpu_has(c, X86_FEATURE_IA64)) {
+		printk(KERN_ERR "microcode: CPU%d not a capable Intel "
+			"processor\n", cpu_num);
+		return -1;
+	}
+
+	csig->sig = cpuid_eax(0x00000001);
+
+	if ((c->x86_model >= 5) || (c->x86 > 6)) {
+		/* get processor flags from MSR 0x17 */
+		rdmsr(MSR_IA32_PLATFORM_ID, val[0], val[1]);
+		csig->pf = 1 << ((val[1] >> 18) & 7);
+	}
+
+	wrmsr(MSR_IA32_UCODE_REV, 0, 0);
+	/* see notes above for revision 1.07.  Apparent chip bug */
+	sync_core();
+	/* get the current revision from MSR 0x8B */
+	rdmsr(MSR_IA32_UCODE_REV, val[0], csig->rev);
+	pr_debug("microcode: collect_cpu_info : sig=0x%x, pf=0x%x, rev=0x%x\n",
+			csig->sig, csig->pf, csig->rev);
+
+	return 0;
+}
+
+static inline int update_match_cpu(struct cpu_signature *csig, int sig, int pf)
+{
+	return (!sigmatch(sig, csig->sig, pf, csig->pf)) ? 0 : 1;
+}
+
+static inline int 
+update_match_revision(struct microcode_header_intel *mc_header,	int rev)
+{
+	return (mc_header->rev <= rev) ? 0 : 1;
+}
+
+static int microcode_sanity_check(void *mc)
+{
+	struct microcode_header_intel *mc_header = mc;
+	struct extended_sigtable *ext_header = NULL;
+	struct extended_signature *ext_sig;
+	unsigned long total_size, data_size, ext_table_size;
+	int sum, orig_sum, ext_sigcount = 0, i;
+
+	total_size = get_totalsize(mc_header);
+	data_size = get_datasize(mc_header);
+	if (data_size + MC_HEADER_SIZE > total_size) {
+		printk(KERN_ERR "microcode: error! "
+			"Bad data size in microcode data file\n");
+		return -EINVAL;
+	}
+
+	if (mc_header->ldrver != 1 || mc_header->hdrver != 1) {
+		printk(KERN_ERR "microcode: error! "
+			"Unknown microcode update format\n");
+		return -EINVAL;
+	}
+	ext_table_size = total_size - (MC_HEADER_SIZE + data_size);
+	if (ext_table_size) {
+		if ((ext_table_size < EXT_HEADER_SIZE)
+		 || ((ext_table_size - EXT_HEADER_SIZE) % EXT_SIGNATURE_SIZE)) {
+			printk(KERN_ERR "microcode: error! "
+				"Small exttable size in microcode data file\n");
+			return -EINVAL;
+		}
+		ext_header = mc + MC_HEADER_SIZE + data_size;
+		if (ext_table_size != exttable_size(ext_header)) {
+			printk(KERN_ERR "microcode: error! "
+				"Bad exttable size in microcode data file\n");
+			return -EFAULT;
+		}
+		ext_sigcount = ext_header->count;
+	}
+
+	/* check extended table checksum */
+	if (ext_table_size) {
+		int ext_table_sum = 0;
+		int *ext_tablep = (int *)ext_header;
+
+		i = ext_table_size / DWSIZE;
+		while (i--)
+			ext_table_sum += ext_tablep[i];
+		if (ext_table_sum) {
+			printk(KERN_WARNING "microcode: aborting, "
+				"bad extended signature table checksum\n");
+			return -EINVAL;
+		}
+	}
+
+	/* calculate the checksum */
+	orig_sum = 0;
+	i = (MC_HEADER_SIZE + data_size) / DWSIZE;
+	while (i--)
+		orig_sum += ((int *)mc)[i];
+	if (orig_sum) {
+		printk(KERN_ERR "microcode: aborting, bad checksum\n");
+		return -EINVAL;
+	}
+	if (!ext_table_size)
+		return 0;
+	/* check extended signature checksum */
+	for (i = 0; i < ext_sigcount; i++) {
+		ext_sig = (void *)ext_header + EXT_HEADER_SIZE +
+			  EXT_SIGNATURE_SIZE * i;
+		sum = orig_sum
+			- (mc_header->sig + mc_header->pf + mc_header->cksum)
+			+ (ext_sig->sig + ext_sig->pf + ext_sig->cksum);
+		if (sum) {
+			printk(KERN_ERR "microcode: aborting, bad checksum\n");
+			return -EINVAL;
+		}
+	}
+	return 0;
+}
+
+/*
+ * return 0 - no update found
+ * return 1 - found update
+ */
+static int
+get_matching_microcode(struct cpu_signature *cpu_sig, void *mc, int rev)
+{
+	struct microcode_header_intel *mc_header = mc;
+	struct extended_sigtable *ext_header;
+	unsigned long total_size = get_totalsize(mc_header);
+	int ext_sigcount, i;
+	struct extended_signature *ext_sig;
+
+	if (!update_match_revision(mc_header, rev))
+		return 0;
+
+	if (update_match_cpu(cpu_sig, mc_header->sig, mc_header->pf))
+		return 1;
+
+	/* Look for ext. headers: */
+	if (total_size <= get_datasize(mc_header) + MC_HEADER_SIZE)
+		return 0;
+
+	ext_header = mc + get_datasize(mc_header) + MC_HEADER_SIZE;
+	ext_sigcount = ext_header->count;
+	ext_sig = (void *)ext_header + EXT_HEADER_SIZE;
+
+	for (i = 0; i < ext_sigcount; i++) {
+		if (update_match_cpu(cpu_sig, ext_sig->sig, ext_sig->pf))
+			return 1;
+		ext_sig++;
+	}
+	return 0;
+}
+
+static void apply_microcode(int cpu)
+{
+	unsigned long flags;
+	unsigned int val[2];
+	int cpu_num = raw_smp_processor_id();
+	struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
+	struct microcode_intel *mc_intel = uci->mc;
+
+	/* We should bind the task to the CPU */
+	BUG_ON(cpu_num != cpu);
+
+	if (mc_intel == NULL)
+		return;
+
+	/* serialize access to the physical write to MSR 0x79 */
+	spin_lock_irqsave(&microcode_update_lock, flags);
+
+	/* write microcode via MSR 0x79 */
+	wrmsr(MSR_IA32_UCODE_WRITE,
+	      (unsigned long) mc_intel->bits,
+	      (unsigned long) mc_intel->bits >> 16 >> 16);
+	wrmsr(MSR_IA32_UCODE_REV, 0, 0);
+
+	/* see notes above for revision 1.07.  Apparent chip bug */
+	sync_core();
+
+	/* get the current revision from MSR 0x8B */
+	rdmsr(MSR_IA32_UCODE_REV, val[0], val[1]);
+
+	spin_unlock_irqrestore(&microcode_update_lock, flags);
+	if (val[1] != mc_intel->hdr.rev) {
+		printk(KERN_ERR "microcode: CPU%d update from revision "
+			"0x%x to 0x%x failed\n", cpu_num, uci->cpu_sig.rev, val[1]);
+		return;
+	}
+	printk(KERN_INFO "microcode: CPU%d updated from revision "
+	       "0x%x to 0x%x, date = %04x-%02x-%02x \n",
+		cpu_num, uci->cpu_sig.rev, val[1],
+		mc_intel->hdr.date & 0xffff,
+		mc_intel->hdr.date >> 24,
+		(mc_intel->hdr.date >> 16) & 0xff);
+	uci->cpu_sig.rev = val[1];
+}
+
+static int generic_load_microcode(int cpu, void *data, size_t size,
+		int (*get_ucode_data)(void *, const void *, size_t))
+{
+	struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
+	u8 *ucode_ptr = data, *new_mc = NULL, *mc;
+	int new_rev = uci->cpu_sig.rev;
+	unsigned int leftover = size;
+
+	while (leftover) {
+		struct microcode_header_intel mc_header;
+		unsigned int mc_size;
+
+		if (get_ucode_data(&mc_header, ucode_ptr, sizeof(mc_header)))
+			break;
+
+		mc_size = get_totalsize(&mc_header);
+		if (!mc_size || mc_size > leftover) {
+			printk(KERN_ERR "microcode: error!"
+					"Bad data in microcode data file\n");
+			break;
+		}
+
+		mc = vmalloc(mc_size);
+		if (!mc)
+			break;
+
+		if (get_ucode_data(mc, ucode_ptr, mc_size) ||
+		    microcode_sanity_check(mc) < 0) {
+			vfree(mc);
+			break;
+		}
+
+		if (get_matching_microcode(&uci->cpu_sig, mc, new_rev)) {
+			if (new_mc)
+				vfree(new_mc);
+			new_rev = mc_header.rev;
+			new_mc  = mc;
+		} else
+			vfree(mc);
+
+		ucode_ptr += mc_size;
+		leftover  -= mc_size;
+	}
+
+	if (new_mc) {
+		if (!leftover) {
+			if (uci->mc)
+				vfree(uci->mc);
+			uci->mc = (struct microcode_intel *)new_mc;
+			pr_debug("microcode: CPU%d found a matching microcode update with"
+				 " version 0x%x (current=0x%x)\n",
+				cpu, new_rev, uci->cpu_sig.rev);
+		} else
+			vfree(new_mc);
+	}
+
+	return (int)leftover;
+}
+
+static int get_ucode_fw(void *to, const void *from, size_t n)
+{
+	memcpy(to, from, n);
+	return 0;
+}
+
+static int request_microcode_fw(int cpu, struct device *device)
+{
+	char name[30];
+	struct cpuinfo_x86 *c = &cpu_data(cpu);
+	const struct firmware *firmware;
+	int ret;
+
+	/* We should bind the task to the CPU */
+	BUG_ON(cpu != raw_smp_processor_id());
+	sprintf(name, "intel-ucode/%02x-%02x-%02x",
+		c->x86, c->x86_model, c->x86_mask);
+	ret = request_firmware(&firmware, name, device);
+	if (ret) {
+		pr_debug("microcode: data file %s load failed\n", name);
+		return ret;
+	}
+
+	ret = generic_load_microcode(cpu, (void*)firmware->data, firmware->size,
+			&get_ucode_fw);
+
+	release_firmware(firmware);
+
+	return ret;
+}
+
+static int get_ucode_user(void *to, const void *from, size_t n)
+{
+	return copy_from_user(to, from, n);
+}
+
+static int request_microcode_user(int cpu, const void __user *buf, size_t size)
+{
+	/* We should bind the task to the CPU */
+	BUG_ON(cpu != raw_smp_processor_id());
+
+	return generic_load_microcode(cpu, (void*)buf, size, &get_ucode_user);
+}
+
+static void microcode_fini_cpu(int cpu)
+{
+	struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
+
+	vfree(uci->mc);
+	uci->mc = NULL;
+}
+
+struct microcode_ops microcode_intel_ops = {
+	.request_microcode_user		  = request_microcode_user,
+	.request_microcode_fw             = request_microcode_fw,
+	.collect_cpu_info                 = collect_cpu_info,
+	.apply_microcode                  = apply_microcode,
+	.microcode_fini_cpu               = microcode_fini_cpu,
+};
+
+struct microcode_ops * __init init_intel_microcode(void)
+{
+	return &microcode_intel_ops;
+}
+
diff --git a/arch/x86/kernel/mpparse.c b/arch/x86/kernel/mpparse.c
index b3fb430..f98f4e1 100644
--- a/arch/x86/kernel/mpparse.c
+++ b/arch/x86/kernel/mpparse.c
@@ -397,7 +397,9 @@
        generic_bigsmp_probe();
 #endif
 
+#ifdef CONFIG_X86_32
 	setup_apic_routing();
+#endif
 	if (!num_processors)
 		printk(KERN_ERR "MPTABLE: no processors registered!\n");
 	return num_processors;
diff --git a/arch/x86/kernel/nmi.c b/arch/x86/kernel/nmi.c
index abb78a2..2c97f07 100644
--- a/arch/x86/kernel/nmi.c
+++ b/arch/x86/kernel/nmi.c
@@ -299,6 +299,15 @@
 		on_each_cpu(__acpi_nmi_disable, NULL, 1);
 }
 
+/*
+ * This function is called as soon the LAPIC NMI watchdog driver has everything
+ * in place and it's ready to check if the NMIs belong to the NMI watchdog
+ */
+void cpu_nmi_set_wd_enabled(void)
+{
+	__get_cpu_var(wd_enabled) = 1;
+}
+
 void setup_apic_nmi_watchdog(void *unused)
 {
 	if (__get_cpu_var(wd_enabled))
@@ -311,8 +320,6 @@
 
 	switch (nmi_watchdog) {
 	case NMI_LOCAL_APIC:
-		 /* enable it before to avoid race with handler */
-		__get_cpu_var(wd_enabled) = 1;
 		if (lapic_watchdog_init(nmi_hz) < 0) {
 			__get_cpu_var(wd_enabled) = 0;
 			return;
diff --git a/arch/x86/kernel/numaq_32.c b/arch/x86/kernel/numaq_32.c
index eecc8c1..4caff39 100644
--- a/arch/x86/kernel/numaq_32.c
+++ b/arch/x86/kernel/numaq_32.c
@@ -229,6 +229,12 @@
 	}
 }
 
+static int __init numaq_setup_ioapic_ids(void)
+{
+	/* so can skip it */
+	return 1;
+}
+
 static struct x86_quirks numaq_x86_quirks __initdata = {
 	.arch_pre_time_init	= numaq_pre_time_init,
 	.arch_time_init		= NULL,
@@ -243,6 +249,7 @@
 	.mpc_oem_bus_info	= mpc_oem_bus_info,
 	.mpc_oem_pci_bus	= mpc_oem_pci_bus,
 	.smp_read_mpc_oem	= smp_read_mpc_oem,
+	.setup_ioapic_ids	= numaq_setup_ioapic_ids,
 };
 
 void numaq_mps_oem_check(struct mp_config_table *mpc, char *oem,
diff --git a/arch/x86/kernel/olpc.c b/arch/x86/kernel/olpc.c
index 3e66722..7a13fac 100644
--- a/arch/x86/kernel/olpc.c
+++ b/arch/x86/kernel/olpc.c
@@ -190,12 +190,12 @@
 static void __init platform_detect(void)
 {
 	size_t propsize;
-	u32 rev;
+	__be32 rev;
 
 	if (ofw("getprop", 4, 1, NULL, "board-revision-int", &rev, 4,
 			&propsize) || propsize != 4) {
 		printk(KERN_ERR "ofw: getprop call failed!\n");
-		rev = 0;
+		rev = cpu_to_be32(0);
 	}
 	olpc_platform_info.boardrev = be32_to_cpu(rev);
 }
@@ -203,7 +203,7 @@
 static void __init platform_detect(void)
 {
 	/* stopgap until OFW support is added to the kernel */
-	olpc_platform_info.boardrev = be32_to_cpu(0xc2);
+	olpc_platform_info.boardrev = 0xc2;
 }
 #endif
 
diff --git a/arch/x86/kernel/paravirt-spinlocks.c b/arch/x86/kernel/paravirt-spinlocks.c
new file mode 100644
index 0000000..0e9f198
--- /dev/null
+++ b/arch/x86/kernel/paravirt-spinlocks.c
@@ -0,0 +1,37 @@
+/*
+ * Split spinlock implementation out into its own file, so it can be
+ * compiled in a FTRACE-compatible way.
+ */
+#include <linux/spinlock.h>
+#include <linux/module.h>
+
+#include <asm/paravirt.h>
+
+static void default_spin_lock_flags(struct raw_spinlock *lock, unsigned long flags)
+{
+	__raw_spin_lock(lock);
+}
+
+struct pv_lock_ops pv_lock_ops = {
+#ifdef CONFIG_SMP
+	.spin_is_locked = __ticket_spin_is_locked,
+	.spin_is_contended = __ticket_spin_is_contended,
+
+	.spin_lock = __ticket_spin_lock,
+	.spin_lock_flags = default_spin_lock_flags,
+	.spin_trylock = __ticket_spin_trylock,
+	.spin_unlock = __ticket_spin_unlock,
+#endif
+};
+EXPORT_SYMBOL(pv_lock_ops);
+
+void __init paravirt_use_bytelocks(void)
+{
+#ifdef CONFIG_SMP
+	pv_lock_ops.spin_is_locked = __byte_spin_is_locked;
+	pv_lock_ops.spin_is_contended = __byte_spin_is_contended;
+	pv_lock_ops.spin_lock = __byte_spin_lock;
+	pv_lock_ops.spin_trylock = __byte_spin_trylock;
+	pv_lock_ops.spin_unlock = __byte_spin_unlock;
+#endif
+}
diff --git a/arch/x86/kernel/paravirt.c b/arch/x86/kernel/paravirt.c
index 300da17..e4c8fb6 100644
--- a/arch/x86/kernel/paravirt.c
+++ b/arch/x86/kernel/paravirt.c
@@ -268,17 +268,6 @@
 	return __get_cpu_var(paravirt_lazy_mode);
 }
 
-void __init paravirt_use_bytelocks(void)
-{
-#ifdef CONFIG_SMP
-	pv_lock_ops.spin_is_locked = __byte_spin_is_locked;
-	pv_lock_ops.spin_is_contended = __byte_spin_is_contended;
-	pv_lock_ops.spin_lock = __byte_spin_lock;
-	pv_lock_ops.spin_trylock = __byte_spin_trylock;
-	pv_lock_ops.spin_unlock = __byte_spin_unlock;
-#endif
-}
-
 struct pv_info pv_info = {
 	.name = "bare hardware",
 	.paravirt_enabled = 0,
@@ -330,6 +319,7 @@
 #endif
 	.wbinvd = native_wbinvd,
 	.read_msr = native_read_msr_safe,
+	.read_msr_amd = native_read_msr_amd_safe,
 	.write_msr = native_write_msr_safe,
 	.read_tsc = native_read_tsc,
 	.read_pmc = native_read_pmc,
@@ -348,6 +338,10 @@
 	.write_ldt_entry = native_write_ldt_entry,
 	.write_gdt_entry = native_write_gdt_entry,
 	.write_idt_entry = native_write_idt_entry,
+
+	.alloc_ldt = paravirt_nop,
+	.free_ldt = paravirt_nop,
+
 	.load_sp0 = native_load_sp0,
 
 #if defined(CONFIG_X86_32) || defined(CONFIG_IA32_EMULATION)
@@ -373,8 +367,6 @@
 
 struct pv_apic_ops pv_apic_ops = {
 #ifdef CONFIG_X86_LOCAL_APIC
-	.apic_write = native_apic_write,
-	.apic_read = native_apic_read,
 	.setup_boot_clock = setup_boot_APIC_clock,
 	.setup_secondary_clock = setup_secondary_APIC_clock,
 	.startup_ipi_hook = paravirt_nop,
@@ -461,18 +453,6 @@
 	.set_fixmap = native_set_fixmap,
 };
 
-struct pv_lock_ops pv_lock_ops = {
-#ifdef CONFIG_SMP
-	.spin_is_locked = __ticket_spin_is_locked,
-	.spin_is_contended = __ticket_spin_is_contended,
-
-	.spin_lock = __ticket_spin_lock,
-	.spin_trylock = __ticket_spin_trylock,
-	.spin_unlock = __ticket_spin_unlock,
-#endif
-};
-EXPORT_SYMBOL(pv_lock_ops);
-
 EXPORT_SYMBOL_GPL(pv_time_ops);
 EXPORT_SYMBOL    (pv_cpu_ops);
 EXPORT_SYMBOL    (pv_mmu_ops);
diff --git a/arch/x86/kernel/paravirt_patch_32.c b/arch/x86/kernel/paravirt_patch_32.c
index 5826221..9fe644f 100644
--- a/arch/x86/kernel/paravirt_patch_32.c
+++ b/arch/x86/kernel/paravirt_patch_32.c
@@ -23,7 +23,7 @@
 			start = start_##ops##_##x;		\
 			end = end_##ops##_##x;			\
 			goto patch_site
-	switch(type) {
+	switch (type) {
 		PATCH_SITE(pv_irq_ops, irq_disable);
 		PATCH_SITE(pv_irq_ops, irq_enable);
 		PATCH_SITE(pv_irq_ops, restore_fl);
diff --git a/arch/x86/kernel/pci-calgary_64.c b/arch/x86/kernel/pci-calgary_64.c
index dcdac6c..080d1d2 100644
--- a/arch/x86/kernel/pci-calgary_64.c
+++ b/arch/x86/kernel/pci-calgary_64.c
@@ -261,7 +261,7 @@
 			       badbit, tbl, start_addr, npages);
 	}
 
-	set_bit_string(tbl->it_map, index, npages);
+	iommu_area_reserve(tbl->it_map, index, npages);
 
 	spin_unlock_irqrestore(&tbl->it_lock, flags);
 }
@@ -491,6 +491,8 @@
 	npages = size >> PAGE_SHIFT;
 	order = get_order(size);
 
+	flag &= ~(__GFP_DMA | __GFP_HIGHMEM | __GFP_DMA32);
+
 	/* alloc enough pages (and possibly more) */
 	ret = (void *)__get_free_pages(flag, order);
 	if (!ret)
@@ -510,8 +512,22 @@
 	return ret;
 }
 
+static void calgary_free_coherent(struct device *dev, size_t size,
+				  void *vaddr, dma_addr_t dma_handle)
+{
+	unsigned int npages;
+	struct iommu_table *tbl = find_iommu_table(dev);
+
+	size = PAGE_ALIGN(size);
+	npages = size >> PAGE_SHIFT;
+
+	iommu_free(tbl, dma_handle, npages);
+	free_pages((unsigned long)vaddr, get_order(size));
+}
+
 static struct dma_mapping_ops calgary_dma_ops = {
 	.alloc_coherent = calgary_alloc_coherent,
+	.free_coherent = calgary_free_coherent,
 	.map_single = calgary_map_single,
 	.unmap_single = calgary_unmap_single,
 	.map_sg = calgary_map_sg,
diff --git a/arch/x86/kernel/pci-dma.c b/arch/x86/kernel/pci-dma.c
index 87d4d69..0a3824e 100644
--- a/arch/x86/kernel/pci-dma.c
+++ b/arch/x86/kernel/pci-dma.c
@@ -41,11 +41,12 @@
 /* Dummy device used for NULL arguments (normally ISA). Better would
    be probably a smaller DMA mask, but this is bug-to-bug compatible
    to older i386. */
-struct device fallback_dev = {
+struct device x86_dma_fallback_dev = {
 	.bus_id = "fallback device",
 	.coherent_dma_mask = DMA_32BIT_MASK,
-	.dma_mask = &fallback_dev.coherent_dma_mask,
+	.dma_mask = &x86_dma_fallback_dev.coherent_dma_mask,
 };
+EXPORT_SYMBOL(x86_dma_fallback_dev);
 
 int dma_set_mask(struct device *dev, u64 mask)
 {
@@ -82,7 +83,7 @@
 	 * using 512M as goal
 	 */
 	align = 64ULL<<20;
-	size = round_up(dma32_bootmem_size, align);
+	size = roundup(dma32_bootmem_size, align);
 	dma32_bootmem_ptr = __alloc_bootmem_nopanic(size, align,
 				 512ULL<<20);
 	if (dma32_bootmem_ptr)
@@ -133,6 +134,37 @@
 EXPORT_SYMBOL(iommu_num_pages);
 #endif
 
+void *dma_generic_alloc_coherent(struct device *dev, size_t size,
+				 dma_addr_t *dma_addr, gfp_t flag)
+{
+	unsigned long dma_mask;
+	struct page *page;
+	dma_addr_t addr;
+
+	dma_mask = dma_alloc_coherent_mask(dev, flag);
+
+	flag |= __GFP_ZERO;
+again:
+	page = alloc_pages_node(dev_to_node(dev), flag, get_order(size));
+	if (!page)
+		return NULL;
+
+	addr = page_to_phys(page);
+	if (!is_buffer_dma_capable(dma_mask, addr, size)) {
+		__free_pages(page, get_order(size));
+
+		if (dma_mask < DMA_32BIT_MASK && !(flag & GFP_DMA)) {
+			flag = (flag & ~GFP_DMA32) | GFP_DMA;
+			goto again;
+		}
+
+		return NULL;
+	}
+
+	*dma_addr = addr;
+	return page_address(page);
+}
+
 /*
  * See <Documentation/x86_64/boot-options.txt> for the iommu kernel parameter
  * documentation.
@@ -241,147 +273,6 @@
 }
 EXPORT_SYMBOL(dma_supported);
 
-/* Allocate DMA memory on node near device */
-static noinline struct page *
-dma_alloc_pages(struct device *dev, gfp_t gfp, unsigned order)
-{
-	int node;
-
-	node = dev_to_node(dev);
-
-	return alloc_pages_node(node, gfp, order);
-}
-
-/*
- * Allocate memory for a coherent mapping.
- */
-void *
-dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle,
-		   gfp_t gfp)
-{
-	struct dma_mapping_ops *ops = get_dma_ops(dev);
-	void *memory = NULL;
-	struct page *page;
-	unsigned long dma_mask = 0;
-	dma_addr_t bus;
-	int noretry = 0;
-
-	/* ignore region specifiers */
-	gfp &= ~(__GFP_DMA | __GFP_HIGHMEM | __GFP_DMA32);
-
-	if (dma_alloc_from_coherent(dev, size, dma_handle, &memory))
-		return memory;
-
-	if (!dev) {
-		dev = &fallback_dev;
-		gfp |= GFP_DMA;
-	}
-	dma_mask = dev->coherent_dma_mask;
-	if (dma_mask == 0)
-		dma_mask = (gfp & GFP_DMA) ? DMA_24BIT_MASK : DMA_32BIT_MASK;
-
-	/* Device not DMA able */
-	if (dev->dma_mask == NULL)
-		return NULL;
-
-	/* Don't invoke OOM killer or retry in lower 16MB DMA zone */
-	if (gfp & __GFP_DMA)
-		noretry = 1;
-
-#ifdef CONFIG_X86_64
-	/* Why <=? Even when the mask is smaller than 4GB it is often
-	   larger than 16MB and in this case we have a chance of
-	   finding fitting memory in the next higher zone first. If
-	   not retry with true GFP_DMA. -AK */
-	if (dma_mask <= DMA_32BIT_MASK && !(gfp & GFP_DMA)) {
-		gfp |= GFP_DMA32;
-		if (dma_mask < DMA_32BIT_MASK)
-			noretry = 1;
-	}
-#endif
-
- again:
-	page = dma_alloc_pages(dev,
-		noretry ? gfp | __GFP_NORETRY : gfp, get_order(size));
-	if (page == NULL)
-		return NULL;
-
-	{
-		int high, mmu;
-		bus = page_to_phys(page);
-		memory = page_address(page);
-		high = (bus + size) >= dma_mask;
-		mmu = high;
-		if (force_iommu && !(gfp & GFP_DMA))
-			mmu = 1;
-		else if (high) {
-			free_pages((unsigned long)memory,
-				   get_order(size));
-
-			/* Don't use the 16MB ZONE_DMA unless absolutely
-			   needed. It's better to use remapping first. */
-			if (dma_mask < DMA_32BIT_MASK && !(gfp & GFP_DMA)) {
-				gfp = (gfp & ~GFP_DMA32) | GFP_DMA;
-				goto again;
-			}
-
-			/* Let low level make its own zone decisions */
-			gfp &= ~(GFP_DMA32|GFP_DMA);
-
-			if (ops->alloc_coherent)
-				return ops->alloc_coherent(dev, size,
-							   dma_handle, gfp);
-			return NULL;
-		}
-
-		memset(memory, 0, size);
-		if (!mmu) {
-			*dma_handle = bus;
-			return memory;
-		}
-	}
-
-	if (ops->alloc_coherent) {
-		free_pages((unsigned long)memory, get_order(size));
-		gfp &= ~(GFP_DMA|GFP_DMA32);
-		return ops->alloc_coherent(dev, size, dma_handle, gfp);
-	}
-
-	if (ops->map_simple) {
-		*dma_handle = ops->map_simple(dev, virt_to_phys(memory),
-					      size,
-					      PCI_DMA_BIDIRECTIONAL);
-		if (*dma_handle != bad_dma_address)
-			return memory;
-	}
-
-	if (panic_on_overflow)
-		panic("dma_alloc_coherent: IOMMU overflow by %lu bytes\n",
-		      (unsigned long)size);
-	free_pages((unsigned long)memory, get_order(size));
-	return NULL;
-}
-EXPORT_SYMBOL(dma_alloc_coherent);
-
-/*
- * Unmap coherent memory.
- * The caller must ensure that the device has finished accessing the mapping.
- */
-void dma_free_coherent(struct device *dev, size_t size,
-			 void *vaddr, dma_addr_t bus)
-{
-	struct dma_mapping_ops *ops = get_dma_ops(dev);
-
-	int order = get_order(size);
-	WARN_ON(irqs_disabled());	/* for portability */
-	if (dma_release_from_coherent(dev, order, vaddr))
-		return;
-	if (ops->unmap_single)
-		ops->unmap_single(dev, bus, size, 0);
-	free_pages((unsigned long)vaddr, order);
-}
-EXPORT_SYMBOL(dma_free_coherent);
-
 static int __init pci_iommu_init(void)
 {
 	calgary_iommu_init();
diff --git a/arch/x86/kernel/pci-gart_64.c b/arch/x86/kernel/pci-gart_64.c
index 49285f8..145f1c8 100644
--- a/arch/x86/kernel/pci-gart_64.c
+++ b/arch/x86/kernel/pci-gart_64.c
@@ -27,8 +27,8 @@
 #include <linux/scatterlist.h>
 #include <linux/iommu-helper.h>
 #include <linux/sysdev.h>
+#include <linux/io.h>
 #include <asm/atomic.h>
-#include <asm/io.h>
 #include <asm/mtrr.h>
 #include <asm/pgtable.h>
 #include <asm/proto.h>
@@ -80,9 +80,10 @@
 AGPEXTERN __u32 *agp_gatt_table;
 
 static unsigned long next_bit;  /* protected by iommu_bitmap_lock */
-static int need_flush;		/* global flush state. set for each gart wrap */
+static bool need_flush;		/* global flush state. set for each gart wrap */
 
-static unsigned long alloc_iommu(struct device *dev, int size)
+static unsigned long alloc_iommu(struct device *dev, int size,
+				 unsigned long align_mask)
 {
 	unsigned long offset, flags;
 	unsigned long boundary_size;
@@ -90,26 +91,27 @@
 
 	base_index = ALIGN(iommu_bus_base & dma_get_seg_boundary(dev),
 			   PAGE_SIZE) >> PAGE_SHIFT;
-	boundary_size = ALIGN(dma_get_seg_boundary(dev) + 1,
+	boundary_size = ALIGN((unsigned long long)dma_get_seg_boundary(dev) + 1,
 			      PAGE_SIZE) >> PAGE_SHIFT;
 
 	spin_lock_irqsave(&iommu_bitmap_lock, flags);
 	offset = iommu_area_alloc(iommu_gart_bitmap, iommu_pages, next_bit,
-				  size, base_index, boundary_size, 0);
+				  size, base_index, boundary_size, align_mask);
 	if (offset == -1) {
-		need_flush = 1;
+		need_flush = true;
 		offset = iommu_area_alloc(iommu_gart_bitmap, iommu_pages, 0,
-					  size, base_index, boundary_size, 0);
+					  size, base_index, boundary_size,
+					  align_mask);
 	}
 	if (offset != -1) {
 		next_bit = offset+size;
 		if (next_bit >= iommu_pages) {
 			next_bit = 0;
-			need_flush = 1;
+			need_flush = true;
 		}
 	}
 	if (iommu_fullflush)
-		need_flush = 1;
+		need_flush = true;
 	spin_unlock_irqrestore(&iommu_bitmap_lock, flags);
 
 	return offset;
@@ -134,7 +136,7 @@
 	spin_lock_irqsave(&iommu_bitmap_lock, flags);
 	if (need_flush) {
 		k8_flush_garts();
-		need_flush = 0;
+		need_flush = false;
 	}
 	spin_unlock_irqrestore(&iommu_bitmap_lock, flags);
 }
@@ -173,7 +175,8 @@
 	       iommu_leak_pages);
 	for (i = 0; i < iommu_leak_pages; i += 2) {
 		printk(KERN_DEBUG "%lu: ", iommu_pages-i);
-		printk_address((unsigned long) iommu_leak_tab[iommu_pages-i], 0);
+		printk_address((unsigned long) iommu_leak_tab[iommu_pages-i],
+				0);
 		printk(KERN_CONT "%c", (i+1)%2 == 0 ? '\n' : ' ');
 	}
 	printk(KERN_DEBUG "\n");
@@ -212,34 +215,24 @@
 static inline int
 need_iommu(struct device *dev, unsigned long addr, size_t size)
 {
-	u64 mask = *dev->dma_mask;
-	int high = addr + size > mask;
-	int mmu = high;
-
-	if (force_iommu)
-		mmu = 1;
-
-	return mmu;
+	return force_iommu ||
+		!is_buffer_dma_capable(*dev->dma_mask, addr, size);
 }
 
 static inline int
 nonforced_iommu(struct device *dev, unsigned long addr, size_t size)
 {
-	u64 mask = *dev->dma_mask;
-	int high = addr + size > mask;
-	int mmu = high;
-
-	return mmu;
+	return !is_buffer_dma_capable(*dev->dma_mask, addr, size);
 }
 
 /* Map a single continuous physical area into the IOMMU.
  * Caller needs to check if the iommu is needed and flush.
  */
 static dma_addr_t dma_map_area(struct device *dev, dma_addr_t phys_mem,
-				size_t size, int dir)
+				size_t size, int dir, unsigned long align_mask)
 {
 	unsigned long npages = iommu_num_pages(phys_mem, size);
-	unsigned long iommu_page = alloc_iommu(dev, npages);
+	unsigned long iommu_page = alloc_iommu(dev, npages, align_mask);
 	int i;
 
 	if (iommu_page == -1) {
@@ -259,16 +252,6 @@
 	return iommu_bus_base + iommu_page*PAGE_SIZE + (phys_mem & ~PAGE_MASK);
 }
 
-static dma_addr_t
-gart_map_simple(struct device *dev, phys_addr_t paddr, size_t size, int dir)
-{
-	dma_addr_t map = dma_map_area(dev, paddr, size, dir);
-
-	flush_gart();
-
-	return map;
-}
-
 /* Map a single area into the IOMMU */
 static dma_addr_t
 gart_map_single(struct device *dev, phys_addr_t paddr, size_t size, int dir)
@@ -276,12 +259,13 @@
 	unsigned long bus;
 
 	if (!dev)
-		dev = &fallback_dev;
+		dev = &x86_dma_fallback_dev;
 
 	if (!need_iommu(dev, paddr, size))
 		return paddr;
 
-	bus = gart_map_simple(dev, paddr, size, dir);
+	bus = dma_map_area(dev, paddr, size, dir, 0);
+	flush_gart();
 
 	return bus;
 }
@@ -340,7 +324,7 @@
 		unsigned long addr = sg_phys(s);
 
 		if (nonforced_iommu(dev, addr, s->length)) {
-			addr = dma_map_area(dev, addr, s->length, dir);
+			addr = dma_map_area(dev, addr, s->length, dir, 0);
 			if (addr == bad_dma_address) {
 				if (i > 0)
 					gart_unmap_sg(dev, sg, i, dir);
@@ -362,7 +346,7 @@
 			  int nelems, struct scatterlist *sout,
 			  unsigned long pages)
 {
-	unsigned long iommu_start = alloc_iommu(dev, pages);
+	unsigned long iommu_start = alloc_iommu(dev, pages, 0);
 	unsigned long iommu_page = iommu_start;
 	struct scatterlist *s;
 	int i;
@@ -427,7 +411,7 @@
 		return 0;
 
 	if (!dev)
-		dev = &fallback_dev;
+		dev = &x86_dma_fallback_dev;
 
 	out = 0;
 	start = 0;
@@ -499,6 +483,46 @@
 	return 0;
 }
 
+/* allocate and map a coherent mapping */
+static void *
+gart_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_addr,
+		    gfp_t flag)
+{
+	dma_addr_t paddr;
+	unsigned long align_mask;
+	struct page *page;
+
+	if (force_iommu && !(flag & GFP_DMA)) {
+		flag &= ~(__GFP_DMA | __GFP_HIGHMEM | __GFP_DMA32);
+		page = alloc_pages(flag | __GFP_ZERO, get_order(size));
+		if (!page)
+			return NULL;
+
+		align_mask = (1UL << get_order(size)) - 1;
+		paddr = dma_map_area(dev, page_to_phys(page), size,
+				     DMA_BIDIRECTIONAL, align_mask);
+
+		flush_gart();
+		if (paddr != bad_dma_address) {
+			*dma_addr = paddr;
+			return page_address(page);
+		}
+		__free_pages(page, get_order(size));
+	} else
+		return dma_generic_alloc_coherent(dev, size, dma_addr, flag);
+
+	return NULL;
+}
+
+/* free a coherent mapping */
+static void
+gart_free_coherent(struct device *dev, size_t size, void *vaddr,
+		   dma_addr_t dma_addr)
+{
+	gart_unmap_single(dev, dma_addr, size, DMA_BIDIRECTIONAL);
+	free_pages((unsigned long)vaddr, get_order(size));
+}
+
 static int no_agp;
 
 static __init unsigned long check_iommu_size(unsigned long aper, u64 aper_size)
@@ -626,7 +650,6 @@
 	struct pci_dev *dev;
 	void *gatt;
 	int i, error;
-	unsigned long start_pfn, end_pfn;
 
 	printk(KERN_INFO "PCI-DMA: Disabling AGP.\n");
 	aper_size = aper_base = info->aper_size = 0;
@@ -650,13 +673,13 @@
 	info->aper_size = aper_size >> 20;
 
 	gatt_size = (aper_size >> PAGE_SHIFT) * sizeof(u32);
-	gatt = (void *)__get_free_pages(GFP_KERNEL, get_order(gatt_size));
+	gatt = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO,
+					get_order(gatt_size));
 	if (!gatt)
 		panic("Cannot allocate GATT table");
 	if (set_memory_uc((unsigned long)gatt, gatt_size >> PAGE_SHIFT))
 		panic("Could not set GART PTEs to uncacheable pages");
 
-	memset(gatt, 0, gatt_size);
 	agp_gatt_table = gatt;
 
 	enable_gart_translations();
@@ -665,19 +688,14 @@
 	if (!error)
 		error = sysdev_register(&device_gart);
 	if (error)
-		panic("Could not register gart_sysdev -- would corrupt data on next suspend");
+		panic("Could not register gart_sysdev -- "
+		      "would corrupt data on next suspend");
 
 	flush_gart();
 
 	printk(KERN_INFO "PCI-DMA: aperture base @ %x size %u KB\n",
 	       aper_base, aper_size>>10);
 
-	/* need to map that range */
-	end_pfn = (aper_base>>PAGE_SHIFT) + (aper_size>>PAGE_SHIFT);
-	if (end_pfn > max_low_pfn_mapped) {
-		start_pfn = (aper_base>>PAGE_SHIFT);
-		init_memory_mapping(start_pfn<<PAGE_SHIFT, end_pfn<<PAGE_SHIFT);
-	}
 	return 0;
 
  nommu:
@@ -687,20 +705,13 @@
 	return -1;
 }
 
-extern int agp_amd64_init(void);
-
 static struct dma_mapping_ops gart_dma_ops = {
 	.map_single			= gart_map_single,
-	.map_simple			= gart_map_simple,
 	.unmap_single			= gart_unmap_single,
-	.sync_single_for_cpu		= NULL,
-	.sync_single_for_device		= NULL,
-	.sync_single_range_for_cpu	= NULL,
-	.sync_single_range_for_device	= NULL,
-	.sync_sg_for_cpu		= NULL,
-	.sync_sg_for_device		= NULL,
 	.map_sg				= gart_map_sg,
 	.unmap_sg			= gart_unmap_sg,
+	.alloc_coherent			= gart_alloc_coherent,
+	.free_coherent			= gart_free_coherent,
 };
 
 void gart_iommu_shutdown(void)
@@ -727,7 +738,8 @@
 {
 	struct agp_kern_info info;
 	unsigned long iommu_start;
-	unsigned long aper_size;
+	unsigned long aper_base, aper_size;
+	unsigned long start_pfn, end_pfn;
 	unsigned long scratch;
 	long i;
 
@@ -759,30 +771,35 @@
 	    (no_agp && init_k8_gatt(&info) < 0)) {
 		if (max_pfn > MAX_DMA32_PFN) {
 			printk(KERN_WARNING "More than 4GB of memory "
-			       	          "but GART IOMMU not available.\n"
-			       KERN_WARNING "falling back to iommu=soft.\n");
+			       "but GART IOMMU not available.\n");
+			printk(KERN_WARNING "falling back to iommu=soft.\n");
 		}
 		return;
 	}
 
+	/* need to map that range */
+	aper_size = info.aper_size << 20;
+	aper_base = info.aper_base;
+	end_pfn = (aper_base>>PAGE_SHIFT) + (aper_size>>PAGE_SHIFT);
+	if (end_pfn > max_low_pfn_mapped) {
+		start_pfn = (aper_base>>PAGE_SHIFT);
+		init_memory_mapping(start_pfn<<PAGE_SHIFT, end_pfn<<PAGE_SHIFT);
+	}
+
 	printk(KERN_INFO "PCI-DMA: using GART IOMMU.\n");
-	aper_size = info.aper_size * 1024 * 1024;
 	iommu_size = check_iommu_size(info.aper_base, aper_size);
 	iommu_pages = iommu_size >> PAGE_SHIFT;
 
-	iommu_gart_bitmap = (void *) __get_free_pages(GFP_KERNEL,
+	iommu_gart_bitmap = (void *) __get_free_pages(GFP_KERNEL | __GFP_ZERO,
 						      get_order(iommu_pages/8));
 	if (!iommu_gart_bitmap)
 		panic("Cannot allocate iommu bitmap\n");
-	memset(iommu_gart_bitmap, 0, iommu_pages/8);
 
 #ifdef CONFIG_IOMMU_LEAK
 	if (leak_trace) {
-		iommu_leak_tab = (void *)__get_free_pages(GFP_KERNEL,
+		iommu_leak_tab = (void *)__get_free_pages(GFP_KERNEL|__GFP_ZERO,
 				  get_order(iommu_pages*sizeof(void *)));
-		if (iommu_leak_tab)
-			memset(iommu_leak_tab, 0, iommu_pages * 8);
-		else
+		if (!iommu_leak_tab)
 			printk(KERN_DEBUG
 			       "PCI-DMA: Cannot allocate leak trace area\n");
 	}
@@ -792,7 +809,7 @@
 	 * Out of IOMMU space handling.
 	 * Reserve some invalid pages at the beginning of the GART.
 	 */
-	set_bit_string(iommu_gart_bitmap, 0, EMERGENCY_PAGES);
+	iommu_area_reserve(iommu_gart_bitmap, 0, EMERGENCY_PAGES);
 
 	agp_memory_reserved = iommu_size;
 	printk(KERN_INFO
@@ -850,7 +867,8 @@
 	if (!strncmp(p, "leak", 4)) {
 		leak_trace = 1;
 		p += 4;
-		if (*p == '=') ++p;
+		if (*p == '=')
+			++p;
 		if (isdigit(*p) && get_option(&p, &arg))
 			iommu_leak_pages = arg;
 	}
diff --git a/arch/x86/kernel/pci-nommu.c b/arch/x86/kernel/pci-nommu.c
index 3f91f71..c70ab5a 100644
--- a/arch/x86/kernel/pci-nommu.c
+++ b/arch/x86/kernel/pci-nommu.c
@@ -14,7 +14,7 @@
 static int
 check_addr(char *name, struct device *hwdev, dma_addr_t bus, size_t size)
 {
-	if (hwdev && bus + size > *hwdev->dma_mask) {
+	if (hwdev && !is_buffer_dma_capable(*hwdev->dma_mask, bus, size)) {
 		if (*hwdev->dma_mask >= DMA_32BIT_MASK)
 			printk(KERN_ERR
 			    "nommu_%s: overflow %Lx+%zu of device mask %Lx\n",
@@ -72,7 +72,15 @@
 	return nents;
 }
 
+static void nommu_free_coherent(struct device *dev, size_t size, void *vaddr,
+				dma_addr_t dma_addr)
+{
+	free_pages((unsigned long)vaddr, get_order(size));
+}
+
 struct dma_mapping_ops nommu_dma_ops = {
+	.alloc_coherent = dma_generic_alloc_coherent,
+	.free_coherent = nommu_free_coherent,
 	.map_single = nommu_map_single,
 	.map_sg = nommu_map_sg,
 	.is_phys = 1,
diff --git a/arch/x86/kernel/pcspeaker.c b/arch/x86/kernel/pcspeaker.c
index bc1f2d3..a311ffc 100644
--- a/arch/x86/kernel/pcspeaker.c
+++ b/arch/x86/kernel/pcspeaker.c
@@ -1,20 +1,13 @@
 #include <linux/platform_device.h>
-#include <linux/errno.h>
+#include <linux/err.h>
 #include <linux/init.h>
 
 static __init int add_pcspkr(void)
 {
 	struct platform_device *pd;
-	int ret;
 
-	pd = platform_device_alloc("pcspkr", -1);
-	if (!pd)
-		return -ENOMEM;
+	pd = platform_device_register_simple("pcspkr", -1, NULL, 0);
 
-	ret = platform_device_add(pd);
-	if (ret)
-		platform_device_put(pd);
-
-	return ret;
+	return IS_ERR(pd) ? PTR_ERR(pd) : 0;
 }
 device_initcall(add_pcspkr);
diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c
index 7fc4d5b..c622772 100644
--- a/arch/x86/kernel/process.c
+++ b/arch/x86/kernel/process.c
@@ -15,7 +15,6 @@
 EXPORT_SYMBOL(idle_nomwait);
 
 struct kmem_cache *task_xstate_cachep;
-static int force_mwait __cpuinitdata;
 
 int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src)
 {
@@ -185,7 +184,8 @@
 static void poll_idle(void)
 {
 	local_irq_enable();
-	cpu_relax();
+	while (!need_resched())
+		cpu_relax();
 }
 
 /*
@@ -246,6 +246,14 @@
 	return 1;
 }
 
+static cpumask_t c1e_mask = CPU_MASK_NONE;
+static int c1e_detected;
+
+void c1e_remove_cpu(int cpu)
+{
+	cpu_clear(cpu, c1e_mask);
+}
+
 /*
  * C1E aware idle routine. We check for C1E active in the interrupt
  * pending message MSR. If we detect C1E, then we handle it the same
@@ -253,9 +261,6 @@
  */
 static void c1e_idle(void)
 {
-	static cpumask_t c1e_mask = CPU_MASK_NONE;
-	static int c1e_detected;
-
 	if (need_resched())
 		return;
 
@@ -265,8 +270,10 @@
 		rdmsr(MSR_K8_INT_PENDING_MSG, lo, hi);
 		if (lo & K8_INTP_C1E_ACTIVE_MASK) {
 			c1e_detected = 1;
-			mark_tsc_unstable("TSC halt in C1E");
-			printk(KERN_INFO "System has C1E enabled\n");
+			if (!boot_cpu_has(X86_FEATURE_CONSTANT_TSC))
+				mark_tsc_unstable("TSC halt in AMD C1E");
+			printk(KERN_INFO "System has AMD C1E enabled\n");
+			set_cpu_cap(&boot_cpu_data, X86_FEATURE_AMDC1E);
 		}
 	}
 
diff --git a/arch/x86/kernel/process_32.c b/arch/x86/kernel/process_32.c
index 3b7a1dd..0a1302f 100644
--- a/arch/x86/kernel/process_32.c
+++ b/arch/x86/kernel/process_32.c
@@ -37,6 +37,7 @@
 #include <linux/tick.h>
 #include <linux/percpu.h>
 #include <linux/prctl.h>
+#include <linux/dmi.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
@@ -55,6 +56,9 @@
 #include <asm/tlbflush.h>
 #include <asm/cpu.h>
 #include <asm/kdebug.h>
+#include <asm/idle.h>
+#include <asm/syscalls.h>
+#include <asm/smp.h>
 
 asmlinkage void ret_from_fork(void) __asm__("ret_from_fork");
 
@@ -72,46 +76,12 @@
 	return ((unsigned long *)tsk->thread.sp)[3];
 }
 
-#ifdef CONFIG_HOTPLUG_CPU
-#include <asm/nmi.h>
-
-static void cpu_exit_clear(void)
-{
-	int cpu = raw_smp_processor_id();
-
-	idle_task_exit();
-
-	cpu_uninit();
-	irq_ctx_exit(cpu);
-
-	cpu_clear(cpu, cpu_callout_map);
-	cpu_clear(cpu, cpu_callin_map);
-
-	numa_remove_cpu(cpu);
-}
-
-/* We don't actually take CPU down, just spin without interrupts. */
-static inline void play_dead(void)
-{
-	/* This must be done before dead CPU ack */
-	cpu_exit_clear();
-	mb();
-	/* Ack it */
-	__get_cpu_var(cpu_state) = CPU_DEAD;
-
-	/*
-	 * With physical CPU hotplug, we should halt the cpu
-	 */
-	local_irq_disable();
-	/* mask all interrupts, flush any and all caches, and halt */
-	wbinvd_halt();
-}
-#else
+#ifndef CONFIG_SMP
 static inline void play_dead(void)
 {
 	BUG();
 }
-#endif /* CONFIG_HOTPLUG_CPU */
+#endif
 
 /*
  * The idle thread. There's no useful work to be
@@ -153,12 +123,13 @@
 	}
 }
 
-void __show_registers(struct pt_regs *regs, int all)
+void __show_regs(struct pt_regs *regs, int all)
 {
 	unsigned long cr0 = 0L, cr2 = 0L, cr3 = 0L, cr4 = 0L;
 	unsigned long d0, d1, d2, d3, d6, d7;
 	unsigned long sp;
 	unsigned short ss, gs;
+	const char *board;
 
 	if (user_mode_vm(regs)) {
 		sp = regs->sp;
@@ -171,11 +142,15 @@
 	}
 
 	printk("\n");
-	printk("Pid: %d, comm: %s %s (%s %.*s)\n",
+
+	board = dmi_get_system_info(DMI_PRODUCT_NAME);
+	if (!board)
+		board = "";
+	printk("Pid: %d, comm: %s %s (%s %.*s) %s\n",
 			task_pid_nr(current), current->comm,
 			print_tainted(), init_utsname()->release,
 			(int)strcspn(init_utsname()->version, " "),
-			init_utsname()->version);
+			init_utsname()->version, board);
 
 	printk("EIP: %04x:[<%08lx>] EFLAGS: %08lx CPU: %d\n",
 			(u16)regs->cs, regs->ip, regs->flags,
@@ -214,7 +189,7 @@
 
 void show_regs(struct pt_regs *regs)
 {
-	__show_registers(regs, 1);
+	__show_regs(regs, 1);
 	show_trace(NULL, regs, &regs->sp, regs->bp);
 }
 
@@ -275,6 +250,14 @@
 		tss->x86_tss.io_bitmap_base = INVALID_IO_BITMAP_OFFSET;
 		put_cpu();
 	}
+#ifdef CONFIG_X86_DS
+	/* Free any DS contexts that have not been properly released. */
+	if (unlikely(current->thread.ds_ctx)) {
+		/* we clear debugctl to make sure DS is not used. */
+		update_debugctlmsr(0);
+		ds_free(current->thread.ds_ctx);
+	}
+#endif /* CONFIG_X86_DS */
 }
 
 void flush_thread(void)
@@ -436,6 +419,35 @@
 	return 0;
 }
 
+#ifdef CONFIG_X86_DS
+static int update_debugctl(struct thread_struct *prev,
+			struct thread_struct *next, unsigned long debugctl)
+{
+	unsigned long ds_prev = 0;
+	unsigned long ds_next = 0;
+
+	if (prev->ds_ctx)
+		ds_prev = (unsigned long)prev->ds_ctx->ds;
+	if (next->ds_ctx)
+		ds_next = (unsigned long)next->ds_ctx->ds;
+
+	if (ds_next != ds_prev) {
+		/* we clear debugctl to make sure DS
+		 * is not in use when we change it */
+		debugctl = 0;
+		update_debugctlmsr(0);
+		wrmsr(MSR_IA32_DS_AREA, ds_next, 0);
+	}
+	return debugctl;
+}
+#else
+static int update_debugctl(struct thread_struct *prev,
+			struct thread_struct *next, unsigned long debugctl)
+{
+	return debugctl;
+}
+#endif /* CONFIG_X86_DS */
+
 static noinline void
 __switch_to_xtra(struct task_struct *prev_p, struct task_struct *next_p,
 		 struct tss_struct *tss)
@@ -446,14 +458,7 @@
 	prev = &prev_p->thread;
 	next = &next_p->thread;
 
-	debugctl = prev->debugctlmsr;
-	if (next->ds_area_msr != prev->ds_area_msr) {
-		/* we clear debugctl to make sure DS
-		 * is not in use when we change it */
-		debugctl = 0;
-		update_debugctlmsr(0);
-		wrmsr(MSR_IA32_DS_AREA, next->ds_area_msr, 0);
-	}
+	debugctl = update_debugctl(prev, next, prev->debugctlmsr);
 
 	if (next->debugctlmsr != debugctl)
 		update_debugctlmsr(next->debugctlmsr);
@@ -477,13 +482,13 @@
 			hard_enable_TSC();
 	}
 
-#ifdef X86_BTS
+#ifdef CONFIG_X86_PTRACE_BTS
 	if (test_tsk_thread_flag(prev_p, TIF_BTS_TRACE_TS))
 		ptrace_bts_take_timestamp(prev_p, BTS_TASK_DEPARTS);
 
 	if (test_tsk_thread_flag(next_p, TIF_BTS_TRACE_TS))
 		ptrace_bts_take_timestamp(next_p, BTS_TASK_ARRIVES);
-#endif
+#endif /* CONFIG_X86_PTRACE_BTS */
 
 
 	if (!test_tsk_thread_flag(next_p, TIF_IO_BITMAP)) {
diff --git a/arch/x86/kernel/process_64.c b/arch/x86/kernel/process_64.c
index 71553b6..cd8c0ed 100644
--- a/arch/x86/kernel/process_64.c
+++ b/arch/x86/kernel/process_64.c
@@ -37,11 +37,11 @@
 #include <linux/kdebug.h>
 #include <linux/tick.h>
 #include <linux/prctl.h>
+#include <linux/uaccess.h>
+#include <linux/io.h>
 
-#include <asm/uaccess.h>
 #include <asm/pgtable.h>
 #include <asm/system.h>
-#include <asm/io.h>
 #include <asm/processor.h>
 #include <asm/i387.h>
 #include <asm/mmu_context.h>
@@ -51,6 +51,7 @@
 #include <asm/proto.h>
 #include <asm/ia32.h>
 #include <asm/idle.h>
+#include <asm/syscalls.h>
 
 asmlinkage extern void ret_from_fork(void);
 
@@ -85,28 +86,12 @@
 	__exit_idle();
 }
 
-#ifdef CONFIG_HOTPLUG_CPU
-DECLARE_PER_CPU(int, cpu_state);
-
-#include <asm/nmi.h>
-/* We halt the CPU with physical CPU hotplug */
-static inline void play_dead(void)
-{
-	idle_task_exit();
-	mb();
-	/* Ack it */
-	__get_cpu_var(cpu_state) = CPU_DEAD;
-
-	local_irq_disable();
-	/* mask all interrupts, flush any and all caches, and halt */
-	wbinvd_halt();
-}
-#else
+#ifndef CONFIG_SMP
 static inline void play_dead(void)
 {
 	BUG();
 }
-#endif /* CONFIG_HOTPLUG_CPU */
+#endif
 
 /*
  * The idle thread. There's no useful work to be
@@ -151,7 +136,7 @@
 }
 
 /* Prints also some state that isn't saved in the pt_regs */
-void __show_regs(struct pt_regs * regs)
+void __show_regs(struct pt_regs *regs, int all)
 {
 	unsigned long cr0 = 0L, cr2 = 0L, cr3 = 0L, cr4 = 0L, fs, gs, shadowgs;
 	unsigned long d0, d1, d2, d3, d6, d7;
@@ -160,60 +145,65 @@
 
 	printk("\n");
 	print_modules();
-	printk("Pid: %d, comm: %.20s %s %s %.*s\n",
+	printk(KERN_INFO "Pid: %d, comm: %.20s %s %s %.*s\n",
 		current->pid, current->comm, print_tainted(),
 		init_utsname()->release,
 		(int)strcspn(init_utsname()->version, " "),
 		init_utsname()->version);
-	printk("RIP: %04lx:[<%016lx>] ", regs->cs & 0xffff, regs->ip);
+	printk(KERN_INFO "RIP: %04lx:[<%016lx>] ", regs->cs & 0xffff, regs->ip);
 	printk_address(regs->ip, 1);
-	printk("RSP: %04lx:%016lx  EFLAGS: %08lx\n", regs->ss, regs->sp,
-		regs->flags);
-	printk("RAX: %016lx RBX: %016lx RCX: %016lx\n",
+	printk(KERN_INFO "RSP: %04lx:%016lx  EFLAGS: %08lx\n", regs->ss,
+			regs->sp, regs->flags);
+	printk(KERN_INFO "RAX: %016lx RBX: %016lx RCX: %016lx\n",
 	       regs->ax, regs->bx, regs->cx);
-	printk("RDX: %016lx RSI: %016lx RDI: %016lx\n",
+	printk(KERN_INFO "RDX: %016lx RSI: %016lx RDI: %016lx\n",
 	       regs->dx, regs->si, regs->di);
-	printk("RBP: %016lx R08: %016lx R09: %016lx\n",
+	printk(KERN_INFO "RBP: %016lx R08: %016lx R09: %016lx\n",
 	       regs->bp, regs->r8, regs->r9);
-	printk("R10: %016lx R11: %016lx R12: %016lx\n",
-	       regs->r10, regs->r11, regs->r12); 
-	printk("R13: %016lx R14: %016lx R15: %016lx\n",
-	       regs->r13, regs->r14, regs->r15); 
+	printk(KERN_INFO "R10: %016lx R11: %016lx R12: %016lx\n",
+	       regs->r10, regs->r11, regs->r12);
+	printk(KERN_INFO "R13: %016lx R14: %016lx R15: %016lx\n",
+	       regs->r13, regs->r14, regs->r15);
 
-	asm("movl %%ds,%0" : "=r" (ds)); 
-	asm("movl %%cs,%0" : "=r" (cs)); 
-	asm("movl %%es,%0" : "=r" (es)); 
+	asm("movl %%ds,%0" : "=r" (ds));
+	asm("movl %%cs,%0" : "=r" (cs));
+	asm("movl %%es,%0" : "=r" (es));
 	asm("movl %%fs,%0" : "=r" (fsindex));
 	asm("movl %%gs,%0" : "=r" (gsindex));
 
 	rdmsrl(MSR_FS_BASE, fs);
-	rdmsrl(MSR_GS_BASE, gs); 
-	rdmsrl(MSR_KERNEL_GS_BASE, shadowgs); 
+	rdmsrl(MSR_GS_BASE, gs);
+	rdmsrl(MSR_KERNEL_GS_BASE, shadowgs);
+
+	if (!all)
+		return;
 
 	cr0 = read_cr0();
 	cr2 = read_cr2();
 	cr3 = read_cr3();
 	cr4 = read_cr4();
 
-	printk("FS:  %016lx(%04x) GS:%016lx(%04x) knlGS:%016lx\n", 
-	       fs,fsindex,gs,gsindex,shadowgs); 
-	printk("CS:  %04x DS: %04x ES: %04x CR0: %016lx\n", cs, ds, es, cr0); 
-	printk("CR2: %016lx CR3: %016lx CR4: %016lx\n", cr2, cr3, cr4);
+	printk(KERN_INFO "FS:  %016lx(%04x) GS:%016lx(%04x) knlGS:%016lx\n",
+	       fs, fsindex, gs, gsindex, shadowgs);
+	printk(KERN_INFO "CS:  %04x DS: %04x ES: %04x CR0: %016lx\n", cs, ds,
+			es, cr0);
+	printk(KERN_INFO "CR2: %016lx CR3: %016lx CR4: %016lx\n", cr2, cr3,
+			cr4);
 
 	get_debugreg(d0, 0);
 	get_debugreg(d1, 1);
 	get_debugreg(d2, 2);
-	printk("DR0: %016lx DR1: %016lx DR2: %016lx\n", d0, d1, d2);
+	printk(KERN_INFO "DR0: %016lx DR1: %016lx DR2: %016lx\n", d0, d1, d2);
 	get_debugreg(d3, 3);
 	get_debugreg(d6, 6);
 	get_debugreg(d7, 7);
-	printk("DR3: %016lx DR6: %016lx DR7: %016lx\n", d3, d6, d7);
+	printk(KERN_INFO "DR3: %016lx DR6: %016lx DR7: %016lx\n", d3, d6, d7);
 }
 
 void show_regs(struct pt_regs *regs)
 {
-	printk("CPU %d:", smp_processor_id());
-	__show_regs(regs);
+	printk(KERN_INFO "CPU %d:", smp_processor_id());
+	__show_regs(regs, 1);
 	show_trace(NULL, regs, (void *)(regs + 1), regs->bp);
 }
 
@@ -238,6 +228,14 @@
 		t->io_bitmap_max = 0;
 		put_cpu();
 	}
+#ifdef CONFIG_X86_DS
+	/* Free any DS contexts that have not been properly released. */
+	if (unlikely(t->ds_ctx)) {
+		/* we clear debugctl to make sure DS is not used. */
+		update_debugctlmsr(0);
+		ds_free(t->ds_ctx);
+	}
+#endif /* CONFIG_X86_DS */
 }
 
 void flush_thread(void)
@@ -313,10 +311,10 @@
 
 int copy_thread(int nr, unsigned long clone_flags, unsigned long sp,
 		unsigned long unused,
-	struct task_struct * p, struct pt_regs * regs)
+	struct task_struct *p, struct pt_regs *regs)
 {
 	int err;
-	struct pt_regs * childregs;
+	struct pt_regs *childregs;
 	struct task_struct *me = current;
 
 	childregs = ((struct pt_regs *)
@@ -361,10 +359,10 @@
 		if (test_thread_flag(TIF_IA32))
 			err = do_set_thread_area(p, -1,
 				(struct user_desc __user *)childregs->si, 0);
-		else 			
-#endif	 
-			err = do_arch_prctl(p, ARCH_SET_FS, childregs->r8); 
-		if (err) 
+		else
+#endif
+			err = do_arch_prctl(p, ARCH_SET_FS, childregs->r8);
+		if (err)
 			goto out;
 	}
 	err = 0;
@@ -471,13 +469,27 @@
 	next = &next_p->thread;
 
 	debugctl = prev->debugctlmsr;
-	if (next->ds_area_msr != prev->ds_area_msr) {
-		/* we clear debugctl to make sure DS
-		 * is not in use when we change it */
-		debugctl = 0;
-		update_debugctlmsr(0);
-		wrmsrl(MSR_IA32_DS_AREA, next->ds_area_msr);
+
+#ifdef CONFIG_X86_DS
+	{
+		unsigned long ds_prev = 0, ds_next = 0;
+
+		if (prev->ds_ctx)
+			ds_prev = (unsigned long)prev->ds_ctx->ds;
+		if (next->ds_ctx)
+			ds_next = (unsigned long)next->ds_ctx->ds;
+
+		if (ds_next != ds_prev) {
+			/*
+			 * We clear debugctl to make sure DS
+			 * is not in use when we change it:
+			 */
+			debugctl = 0;
+			update_debugctlmsr(0);
+			wrmsrl(MSR_IA32_DS_AREA, ds_next);
+		}
 	}
+#endif /* CONFIG_X86_DS */
 
 	if (next->debugctlmsr != debugctl)
 		update_debugctlmsr(next->debugctlmsr);
@@ -515,13 +527,13 @@
 		memset(tss->io_bitmap, 0xff, prev->io_bitmap_max);
 	}
 
-#ifdef X86_BTS
+#ifdef CONFIG_X86_PTRACE_BTS
 	if (test_tsk_thread_flag(prev_p, TIF_BTS_TRACE_TS))
 		ptrace_bts_take_timestamp(prev_p, BTS_TASK_DEPARTS);
 
 	if (test_tsk_thread_flag(next_p, TIF_BTS_TRACE_TS))
 		ptrace_bts_take_timestamp(next_p, BTS_TASK_ARRIVES);
-#endif
+#endif /* CONFIG_X86_PTRACE_BTS */
 }
 
 /*
@@ -543,7 +555,7 @@
 	unsigned fsindex, gsindex;
 
 	/* we're going to use this soon, after a few expensive things */
-	if (next_p->fpu_counter>5)
+	if (next_p->fpu_counter > 5)
 		prefetch(next->xstate);
 
 	/*
@@ -551,13 +563,13 @@
 	 */
 	load_sp0(tss, next);
 
-	/* 
+	/*
 	 * Switch DS and ES.
 	 * This won't pick up thread selector changes, but I guess that is ok.
 	 */
 	savesegment(es, prev->es);
 	if (unlikely(next->es | prev->es))
-		loadsegment(es, next->es); 
+		loadsegment(es, next->es);
 
 	savesegment(ds, prev->ds);
 	if (unlikely(next->ds | prev->ds))
@@ -583,7 +595,7 @@
 	 */
 	arch_leave_lazy_cpu_mode();
 
-	/* 
+	/*
 	 * Switch FS and GS.
 	 *
 	 * Segment register != 0 always requires a reload.  Also
@@ -592,13 +604,13 @@
 	 */
 	if (unlikely(fsindex | next->fsindex | prev->fs)) {
 		loadsegment(fs, next->fsindex);
-		/* 
+		/*
 		 * Check if the user used a selector != 0; if yes
 		 *  clear 64bit base, since overloaded base is always
 		 *  mapped to the Null selector
 		 */
 		if (fsindex)
-			prev->fs = 0;				
+			prev->fs = 0;
 	}
 	/* when next process has a 64bit base use it */
 	if (next->fs)
@@ -608,7 +620,7 @@
 	if (unlikely(gsindex | next->gsindex | prev->gs)) {
 		load_gs_index(next->gsindex);
 		if (gsindex)
-			prev->gs = 0;				
+			prev->gs = 0;
 	}
 	if (next->gs)
 		wrmsrl(MSR_KERNEL_GS_BASE, next->gs);
@@ -617,12 +629,12 @@
 	/* Must be after DS reload */
 	unlazy_fpu(prev_p);
 
-	/* 
+	/*
 	 * Switch the PDA and FPU contexts.
 	 */
 	prev->usersp = read_pda(oldrsp);
 	write_pda(oldrsp, next->usersp);
-	write_pda(pcurrent, next_p); 
+	write_pda(pcurrent, next_p);
 
 	write_pda(kernelstack,
 		  (unsigned long)task_stack_page(next_p) +
@@ -663,7 +675,7 @@
 		char __user * __user *envp, struct pt_regs *regs)
 {
 	long error;
-	char * filename;
+	char *filename;
 
 	filename = getname(name);
 	error = PTR_ERR(filename);
@@ -721,55 +733,55 @@
 unsigned long get_wchan(struct task_struct *p)
 {
 	unsigned long stack;
-	u64 fp,ip;
+	u64 fp, ip;
 	int count = 0;
 
-	if (!p || p == current || p->state==TASK_RUNNING)
-		return 0; 
+	if (!p || p == current || p->state == TASK_RUNNING)
+		return 0;
 	stack = (unsigned long)task_stack_page(p);
-	if (p->thread.sp < stack || p->thread.sp > stack+THREAD_SIZE)
+	if (p->thread.sp < stack || p->thread.sp >= stack+THREAD_SIZE)
 		return 0;
 	fp = *(u64 *)(p->thread.sp);
-	do { 
+	do {
 		if (fp < (unsigned long)stack ||
-		    fp > (unsigned long)stack+THREAD_SIZE)
-			return 0; 
+		    fp >= (unsigned long)stack+THREAD_SIZE)
+			return 0;
 		ip = *(u64 *)(fp+8);
 		if (!in_sched_functions(ip))
 			return ip;
-		fp = *(u64 *)fp; 
-	} while (count++ < 16); 
+		fp = *(u64 *)fp;
+	} while (count++ < 16);
 	return 0;
 }
 
 long do_arch_prctl(struct task_struct *task, int code, unsigned long addr)
-{ 
-	int ret = 0; 
+{
+	int ret = 0;
 	int doit = task == current;
 	int cpu;
 
-	switch (code) { 
+	switch (code) {
 	case ARCH_SET_GS:
 		if (addr >= TASK_SIZE_OF(task))
-			return -EPERM; 
+			return -EPERM;
 		cpu = get_cpu();
-		/* handle small bases via the GDT because that's faster to 
+		/* handle small bases via the GDT because that's faster to
 		   switch. */
-		if (addr <= 0xffffffff) {  
-			set_32bit_tls(task, GS_TLS, addr); 
-			if (doit) { 
+		if (addr <= 0xffffffff) {
+			set_32bit_tls(task, GS_TLS, addr);
+			if (doit) {
 				load_TLS(&task->thread, cpu);
-				load_gs_index(GS_TLS_SEL); 
+				load_gs_index(GS_TLS_SEL);
 			}
-			task->thread.gsindex = GS_TLS_SEL; 
+			task->thread.gsindex = GS_TLS_SEL;
 			task->thread.gs = 0;
-		} else { 
+		} else {
 			task->thread.gsindex = 0;
 			task->thread.gs = addr;
 			if (doit) {
 				load_gs_index(0);
 				ret = checking_wrmsrl(MSR_KERNEL_GS_BASE, addr);
-			} 
+			}
 		}
 		put_cpu();
 		break;
@@ -823,8 +835,7 @@
 				rdmsrl(MSR_KERNEL_GS_BASE, base);
 			else
 				base = task->thread.gs;
-		}
-		else
+		} else
 			base = task->thread.gs;
 		ret = put_user(base, (unsigned long __user *)addr);
 		break;
diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c
index e37dccc..0a6d8c1 100644
--- a/arch/x86/kernel/ptrace.c
+++ b/arch/x86/kernel/ptrace.c
@@ -14,6 +14,7 @@
 #include <linux/errno.h>
 #include <linux/ptrace.h>
 #include <linux/regset.h>
+#include <linux/tracehook.h>
 #include <linux/user.h>
 #include <linux/elf.h>
 #include <linux/security.h>
@@ -39,7 +40,9 @@
 	REGSET_GENERAL,
 	REGSET_FP,
 	REGSET_XFP,
+	REGSET_IOPERM64 = REGSET_XFP,
 	REGSET_TLS,
+	REGSET_IOPERM32,
 };
 
 /*
@@ -69,7 +72,7 @@
 
 #define FLAG_MASK		FLAG_MASK_32
 
-static long *pt_regs_access(struct pt_regs *regs, unsigned long regno)
+static unsigned long *pt_regs_access(struct pt_regs *regs, unsigned long regno)
 {
 	BUILD_BUG_ON(offsetof(struct pt_regs, bx) != 0);
 	regno >>= 2;
@@ -554,45 +557,138 @@
 	return 0;
 }
 
-#ifdef X86_BTS
-
-static int ptrace_bts_get_size(struct task_struct *child)
+/*
+ * These access the current or another (stopped) task's io permission
+ * bitmap for debugging or core dump.
+ */
+static int ioperm_active(struct task_struct *target,
+			 const struct user_regset *regset)
 {
-	if (!child->thread.ds_area_msr)
-		return -ENXIO;
-
-	return ds_get_bts_index((void *)child->thread.ds_area_msr);
+	return target->thread.io_bitmap_max / regset->size;
 }
 
-static int ptrace_bts_read_record(struct task_struct *child,
-				  long index,
+static int ioperm_get(struct task_struct *target,
+		      const struct user_regset *regset,
+		      unsigned int pos, unsigned int count,
+		      void *kbuf, void __user *ubuf)
+{
+	if (!target->thread.io_bitmap_ptr)
+		return -ENXIO;
+
+	return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+				   target->thread.io_bitmap_ptr,
+				   0, IO_BITMAP_BYTES);
+}
+
+#ifdef CONFIG_X86_PTRACE_BTS
+/*
+ * The configuration for a particular BTS hardware implementation.
+ */
+struct bts_configuration {
+	/* the size of a BTS record in bytes; at most BTS_MAX_RECORD_SIZE */
+	unsigned char  sizeof_bts;
+	/* the size of a field in the BTS record in bytes */
+	unsigned char  sizeof_field;
+	/* a bitmask to enable/disable BTS in DEBUGCTL MSR */
+	unsigned long debugctl_mask;
+};
+static struct bts_configuration bts_cfg;
+
+#define BTS_MAX_RECORD_SIZE (8 * 3)
+
+
+/*
+ * Branch Trace Store (BTS) uses the following format. Different
+ * architectures vary in the size of those fields.
+ * - source linear address
+ * - destination linear address
+ * - flags
+ *
+ * Later architectures use 64bit pointers throughout, whereas earlier
+ * architectures use 32bit pointers in 32bit mode.
+ *
+ * We compute the base address for the first 8 fields based on:
+ * - the field size stored in the DS configuration
+ * - the relative field position
+ *
+ * In order to store additional information in the BTS buffer, we use
+ * a special source address to indicate that the record requires
+ * special interpretation.
+ *
+ * Netburst indicated via a bit in the flags field whether the branch
+ * was predicted; this is ignored.
+ */
+
+enum bts_field {
+	bts_from = 0,
+	bts_to,
+	bts_flags,
+
+	bts_escape = (unsigned long)-1,
+	bts_qual = bts_to,
+	bts_jiffies = bts_flags
+};
+
+static inline unsigned long bts_get(const char *base, enum bts_field field)
+{
+	base += (bts_cfg.sizeof_field * field);
+	return *(unsigned long *)base;
+}
+
+static inline void bts_set(char *base, enum bts_field field, unsigned long val)
+{
+	base += (bts_cfg.sizeof_field * field);;
+	(*(unsigned long *)base) = val;
+}
+
+/*
+ * Translate a BTS record from the raw format into the bts_struct format
+ *
+ * out (out): bts_struct interpretation
+ * raw: raw BTS record
+ */
+static void ptrace_bts_translate_record(struct bts_struct *out, const void *raw)
+{
+	memset(out, 0, sizeof(*out));
+	if (bts_get(raw, bts_from) == bts_escape) {
+		out->qualifier       = bts_get(raw, bts_qual);
+		out->variant.jiffies = bts_get(raw, bts_jiffies);
+	} else {
+		out->qualifier = BTS_BRANCH;
+		out->variant.lbr.from_ip = bts_get(raw, bts_from);
+		out->variant.lbr.to_ip   = bts_get(raw, bts_to);
+	}
+}
+
+static int ptrace_bts_read_record(struct task_struct *child, size_t index,
 				  struct bts_struct __user *out)
 {
 	struct bts_struct ret;
-	int retval;
-	int bts_end;
-	int bts_index;
+	const void *bts_record;
+	size_t bts_index, bts_end;
+	int error;
 
-	if (!child->thread.ds_area_msr)
-		return -ENXIO;
+	error = ds_get_bts_end(child, &bts_end);
+	if (error < 0)
+		return error;
 
-	if (index < 0)
-		return -EINVAL;
-
-	bts_end = ds_get_bts_end((void *)child->thread.ds_area_msr);
 	if (bts_end <= index)
 		return -EINVAL;
 
-	/* translate the ptrace bts index into the ds bts index */
-	bts_index = ds_get_bts_index((void *)child->thread.ds_area_msr);
-	bts_index -= (index + 1);
-	if (bts_index < 0)
-		bts_index += bts_end;
+	error = ds_get_bts_index(child, &bts_index);
+	if (error < 0)
+		return error;
 
-	retval = ds_read_bts((void *)child->thread.ds_area_msr,
-			     bts_index, &ret);
-	if (retval < 0)
-		return retval;
+	/* translate the ptrace bts index into the ds bts index */
+	bts_index += bts_end - (index + 1);
+	if (bts_end <= bts_index)
+		bts_index -= bts_end;
+
+	error = ds_access_bts(child, bts_index, &bts_record);
+	if (error < 0)
+		return error;
+
+	ptrace_bts_translate_record(&ret, bts_record);
 
 	if (copy_to_user(out, &ret, sizeof(ret)))
 		return -EFAULT;
@@ -600,101 +696,106 @@
 	return sizeof(ret);
 }
 
-static int ptrace_bts_clear(struct task_struct *child)
-{
-	if (!child->thread.ds_area_msr)
-		return -ENXIO;
-
-	return ds_clear((void *)child->thread.ds_area_msr);
-}
-
 static int ptrace_bts_drain(struct task_struct *child,
 			    long size,
 			    struct bts_struct __user *out)
 {
-	int end, i;
-	void *ds = (void *)child->thread.ds_area_msr;
+	struct bts_struct ret;
+	const unsigned char *raw;
+	size_t end, i;
+	int error;
 
-	if (!ds)
-		return -ENXIO;
-
-	end = ds_get_bts_index(ds);
-	if (end <= 0)
-		return end;
+	error = ds_get_bts_index(child, &end);
+	if (error < 0)
+		return error;
 
 	if (size < (end * sizeof(struct bts_struct)))
 		return -EIO;
 
-	for (i = 0; i < end; i++, out++) {
-		struct bts_struct ret;
-		int retval;
+	error = ds_access_bts(child, 0, (const void **)&raw);
+	if (error < 0)
+		return error;
 
-		retval = ds_read_bts(ds, i, &ret);
-		if (retval < 0)
-			return retval;
+	for (i = 0; i < end; i++, out++, raw += bts_cfg.sizeof_bts) {
+		ptrace_bts_translate_record(&ret, raw);
 
 		if (copy_to_user(out, &ret, sizeof(ret)))
 			return -EFAULT;
 	}
 
-	ds_clear(ds);
+	error = ds_clear_bts(child);
+	if (error < 0)
+		return error;
 
 	return end;
 }
 
+static void ptrace_bts_ovfl(struct task_struct *child)
+{
+	send_sig(child->thread.bts_ovfl_signal, child, 0);
+}
+
 static int ptrace_bts_config(struct task_struct *child,
 			     long cfg_size,
 			     const struct ptrace_bts_config __user *ucfg)
 {
 	struct ptrace_bts_config cfg;
-	int bts_size, ret = 0;
-	void *ds;
+	int error = 0;
 
+	error = -EOPNOTSUPP;
+	if (!bts_cfg.sizeof_bts)
+		goto errout;
+
+	error = -EIO;
 	if (cfg_size < sizeof(cfg))
-		return -EIO;
+		goto errout;
 
+	error = -EFAULT;
 	if (copy_from_user(&cfg, ucfg, sizeof(cfg)))
-		return -EFAULT;
+		goto errout;
 
-	if ((int)cfg.size < 0)
-		return -EINVAL;
+	error = -EINVAL;
+	if ((cfg.flags & PTRACE_BTS_O_SIGNAL) &&
+	    !(cfg.flags & PTRACE_BTS_O_ALLOC))
+		goto errout;
 
-	bts_size = 0;
-	ds = (void *)child->thread.ds_area_msr;
-	if (ds) {
-		bts_size = ds_get_bts_size(ds);
-		if (bts_size < 0)
-			return bts_size;
-	}
-	cfg.size = PAGE_ALIGN(cfg.size);
+	if (cfg.flags & PTRACE_BTS_O_ALLOC) {
+		ds_ovfl_callback_t ovfl = NULL;
+		unsigned int sig = 0;
 
-	if (bts_size != cfg.size) {
-		ret = ptrace_bts_realloc(child, cfg.size,
-					 cfg.flags & PTRACE_BTS_O_CUT_SIZE);
-		if (ret < 0)
+		/* we ignore the error in case we were not tracing child */
+		(void)ds_release_bts(child);
+
+		if (cfg.flags & PTRACE_BTS_O_SIGNAL) {
+			if (!cfg.signal)
+				goto errout;
+
+			sig  = cfg.signal;
+			ovfl = ptrace_bts_ovfl;
+		}
+
+		error = ds_request_bts(child, /* base = */ NULL, cfg.size, ovfl);
+		if (error < 0)
 			goto errout;
 
-		ds = (void *)child->thread.ds_area_msr;
+		child->thread.bts_ovfl_signal = sig;
 	}
 
-	if (cfg.flags & PTRACE_BTS_O_SIGNAL)
-		ret = ds_set_overflow(ds, DS_O_SIGNAL);
-	else
-		ret = ds_set_overflow(ds, DS_O_WRAP);
-	if (ret < 0)
+	error = -EINVAL;
+	if (!child->thread.ds_ctx && cfg.flags)
 		goto errout;
 
 	if (cfg.flags & PTRACE_BTS_O_TRACE)
-		child->thread.debugctlmsr |= ds_debugctl_mask();
+		child->thread.debugctlmsr |= bts_cfg.debugctl_mask;
 	else
-		child->thread.debugctlmsr &= ~ds_debugctl_mask();
+		child->thread.debugctlmsr &= ~bts_cfg.debugctl_mask;
 
 	if (cfg.flags & PTRACE_BTS_O_SCHED)
 		set_tsk_thread_flag(child, TIF_BTS_TRACE_TS);
 	else
 		clear_tsk_thread_flag(child, TIF_BTS_TRACE_TS);
 
-	ret = sizeof(cfg);
+	error = sizeof(cfg);
 
 out:
 	if (child->thread.debugctlmsr)
@@ -702,10 +803,10 @@
 	else
 		clear_tsk_thread_flag(child, TIF_DEBUGCTLMSR);
 
-	return ret;
+	return error;
 
 errout:
-	child->thread.debugctlmsr &= ~ds_debugctl_mask();
+	child->thread.debugctlmsr &= ~bts_cfg.debugctl_mask;
 	clear_tsk_thread_flag(child, TIF_BTS_TRACE_TS);
 	goto out;
 }
@@ -714,119 +815,79 @@
 			     long cfg_size,
 			     struct ptrace_bts_config __user *ucfg)
 {
-	void *ds = (void *)child->thread.ds_area_msr;
 	struct ptrace_bts_config cfg;
+	size_t end;
+	const void *base, *max;
+	int error;
 
 	if (cfg_size < sizeof(cfg))
 		return -EIO;
 
+	error = ds_get_bts_end(child, &end);
+	if (error < 0)
+		return error;
+
+	error = ds_access_bts(child, /* index = */ 0, &base);
+	if (error < 0)
+		return error;
+
+	error = ds_access_bts(child, /* index = */ end, &max);
+	if (error < 0)
+		return error;
+
 	memset(&cfg, 0, sizeof(cfg));
-
-	if (ds) {
-		cfg.size = ds_get_bts_size(ds);
-
-		if (ds_get_overflow(ds) == DS_O_SIGNAL)
-			cfg.flags |= PTRACE_BTS_O_SIGNAL;
-
-		if (test_tsk_thread_flag(child, TIF_DEBUGCTLMSR) &&
-		    child->thread.debugctlmsr & ds_debugctl_mask())
-			cfg.flags |= PTRACE_BTS_O_TRACE;
-
-		if (test_tsk_thread_flag(child, TIF_BTS_TRACE_TS))
-			cfg.flags |= PTRACE_BTS_O_SCHED;
-	}
-
+	cfg.size = (max - base);
+	cfg.signal = child->thread.bts_ovfl_signal;
 	cfg.bts_size = sizeof(struct bts_struct);
 
+	if (cfg.signal)
+		cfg.flags |= PTRACE_BTS_O_SIGNAL;
+
+	if (test_tsk_thread_flag(child, TIF_DEBUGCTLMSR) &&
+	    child->thread.debugctlmsr & bts_cfg.debugctl_mask)
+		cfg.flags |= PTRACE_BTS_O_TRACE;
+
+	if (test_tsk_thread_flag(child, TIF_BTS_TRACE_TS))
+		cfg.flags |= PTRACE_BTS_O_SCHED;
+
 	if (copy_to_user(ucfg, &cfg, sizeof(cfg)))
 		return -EFAULT;
 
 	return sizeof(cfg);
 }
 
-
 static int ptrace_bts_write_record(struct task_struct *child,
 				   const struct bts_struct *in)
 {
-	int retval;
+	unsigned char bts_record[BTS_MAX_RECORD_SIZE];
 
-	if (!child->thread.ds_area_msr)
-		return -ENXIO;
+	BUG_ON(BTS_MAX_RECORD_SIZE < bts_cfg.sizeof_bts);
 
-	retval = ds_write_bts((void *)child->thread.ds_area_msr, in);
-	if (retval)
-		return retval;
+	memset(bts_record, 0, bts_cfg.sizeof_bts);
+	switch (in->qualifier) {
+	case BTS_INVALID:
+		break;
 
-	return sizeof(*in);
-}
+	case BTS_BRANCH:
+		bts_set(bts_record, bts_from, in->variant.lbr.from_ip);
+		bts_set(bts_record, bts_to,   in->variant.lbr.to_ip);
+		break;
 
-static int ptrace_bts_realloc(struct task_struct *child,
-			      int size, int reduce_size)
-{
-	unsigned long rlim, vm;
-	int ret, old_size;
+	case BTS_TASK_ARRIVES:
+	case BTS_TASK_DEPARTS:
+		bts_set(bts_record, bts_from,    bts_escape);
+		bts_set(bts_record, bts_qual,    in->qualifier);
+		bts_set(bts_record, bts_jiffies, in->variant.jiffies);
+		break;
 
-	if (size < 0)
+	default:
 		return -EINVAL;
-
-	old_size = ds_get_bts_size((void *)child->thread.ds_area_msr);
-	if (old_size < 0)
-		return old_size;
-
-	ret = ds_free((void **)&child->thread.ds_area_msr);
-	if (ret < 0)
-		goto out;
-
-	size >>= PAGE_SHIFT;
-	old_size >>= PAGE_SHIFT;
-
-	current->mm->total_vm  -= old_size;
-	current->mm->locked_vm -= old_size;
-
-	if (size == 0)
-		goto out;
-
-	rlim = current->signal->rlim[RLIMIT_AS].rlim_cur >> PAGE_SHIFT;
-	vm = current->mm->total_vm  + size;
-	if (rlim < vm) {
-		ret = -ENOMEM;
-
-		if (!reduce_size)
-			goto out;
-
-		size = rlim - current->mm->total_vm;
-		if (size <= 0)
-			goto out;
 	}
 
-	rlim = current->signal->rlim[RLIMIT_MEMLOCK].rlim_cur >> PAGE_SHIFT;
-	vm = current->mm->locked_vm  + size;
-	if (rlim < vm) {
-		ret = -ENOMEM;
-
-		if (!reduce_size)
-			goto out;
-
-		size = rlim - current->mm->locked_vm;
-		if (size <= 0)
-			goto out;
-	}
-
-	ret = ds_allocate((void **)&child->thread.ds_area_msr,
-			  size << PAGE_SHIFT);
-	if (ret < 0)
-		goto out;
-
-	current->mm->total_vm  += size;
-	current->mm->locked_vm += size;
-
-out:
-	if (child->thread.ds_area_msr)
-		set_tsk_thread_flag(child, TIF_DS_AREA_MSR);
-	else
-		clear_tsk_thread_flag(child, TIF_DS_AREA_MSR);
-
-	return ret;
+	/* The writing task will be the switched-to task on a context
+	 * switch. It needs to write into the switched-from task's BTS
+	 * buffer. */
+	return ds_unchecked_write_bts(child, bts_record, bts_cfg.sizeof_bts);
 }
 
 void ptrace_bts_take_timestamp(struct task_struct *tsk,
@@ -839,7 +900,66 @@
 
 	ptrace_bts_write_record(tsk, &rec);
 }
-#endif /* X86_BTS */
+
+static const struct bts_configuration bts_cfg_netburst = {
+	.sizeof_bts    = sizeof(long) * 3,
+	.sizeof_field  = sizeof(long),
+	.debugctl_mask = (1<<2)|(1<<3)|(1<<5)
+};
+
+static const struct bts_configuration bts_cfg_pentium_m = {
+	.sizeof_bts    = sizeof(long) * 3,
+	.sizeof_field  = sizeof(long),
+	.debugctl_mask = (1<<6)|(1<<7)
+};
+
+static const struct bts_configuration bts_cfg_core2 = {
+	.sizeof_bts    = 8 * 3,
+	.sizeof_field  = 8,
+	.debugctl_mask = (1<<6)|(1<<7)|(1<<9)
+};
+
+static inline void bts_configure(const struct bts_configuration *cfg)
+{
+	bts_cfg = *cfg;
+}
+
+void __cpuinit ptrace_bts_init_intel(struct cpuinfo_x86 *c)
+{
+	switch (c->x86) {
+	case 0x6:
+		switch (c->x86_model) {
+		case 0xD:
+		case 0xE: /* Pentium M */
+			bts_configure(&bts_cfg_pentium_m);
+			break;
+		case 0xF: /* Core2 */
+        case 0x1C: /* Atom */
+			bts_configure(&bts_cfg_core2);
+			break;
+		default:
+			/* sorry, don't know about them */
+			break;
+		}
+		break;
+	case 0xF:
+		switch (c->x86_model) {
+		case 0x0:
+		case 0x1:
+		case 0x2: /* Netburst */
+			bts_configure(&bts_cfg_netburst);
+			break;
+		default:
+			/* sorry, don't know about them */
+			break;
+		}
+		break;
+	default:
+		/* sorry, don't know about them */
+		break;
+	}
+}
+#endif /* CONFIG_X86_PTRACE_BTS */
 
 /*
  * Called by kernel/ptrace.c when detaching..
@@ -852,15 +972,15 @@
 #ifdef TIF_SYSCALL_EMU
 	clear_tsk_thread_flag(child, TIF_SYSCALL_EMU);
 #endif
-	if (child->thread.ds_area_msr) {
-#ifdef X86_BTS
-		ptrace_bts_realloc(child, 0, 0);
-#endif
-		child->thread.debugctlmsr &= ~ds_debugctl_mask();
-		if (!child->thread.debugctlmsr)
-			clear_tsk_thread_flag(child, TIF_DEBUGCTLMSR);
-		clear_tsk_thread_flag(child, TIF_BTS_TRACE_TS);
-	}
+#ifdef CONFIG_X86_PTRACE_BTS
+	(void)ds_release_bts(child);
+
+	child->thread.debugctlmsr &= ~bts_cfg.debugctl_mask;
+	if (!child->thread.debugctlmsr)
+		clear_tsk_thread_flag(child, TIF_DEBUGCTLMSR);
+
+	clear_tsk_thread_flag(child, TIF_BTS_TRACE_TS);
+#endif /* CONFIG_X86_PTRACE_BTS */
 }
 
 #if defined CONFIG_X86_32 || defined CONFIG_IA32_EMULATION
@@ -980,7 +1100,7 @@
 	/*
 	 * These bits need more cooking - not enabled yet:
 	 */
-#ifdef X86_BTS
+#ifdef CONFIG_X86_PTRACE_BTS
 	case PTRACE_BTS_CONFIG:
 		ret = ptrace_bts_config
 			(child, data, (struct ptrace_bts_config __user *)addr);
@@ -992,7 +1112,7 @@
 		break;
 
 	case PTRACE_BTS_SIZE:
-		ret = ptrace_bts_get_size(child);
+		ret = ds_get_bts_index(child, /* pos = */ NULL);
 		break;
 
 	case PTRACE_BTS_GET:
@@ -1001,14 +1121,14 @@
 		break;
 
 	case PTRACE_BTS_CLEAR:
-		ret = ptrace_bts_clear(child);
+		ret = ds_clear_bts(child);
 		break;
 
 	case PTRACE_BTS_DRAIN:
 		ret = ptrace_bts_drain
 			(child, data, (struct bts_struct __user *) addr);
 		break;
-#endif
+#endif /* CONFIG_X86_PTRACE_BTS */
 
 	default:
 		ret = ptrace_request(child, request, addr, data);
@@ -1290,6 +1410,12 @@
 		.size = sizeof(long), .align = sizeof(long),
 		.active = xfpregs_active, .get = xfpregs_get, .set = xfpregs_set
 	},
+	[REGSET_IOPERM64] = {
+		.core_note_type = NT_386_IOPERM,
+		.n = IO_BITMAP_LONGS,
+		.size = sizeof(long), .align = sizeof(long),
+		.active = ioperm_active, .get = ioperm_get
+	},
 };
 
 static const struct user_regset_view user_x86_64_view = {
@@ -1336,6 +1462,12 @@
 		.active = regset_tls_active,
 		.get = regset_tls_get, .set = regset_tls_set
 	},
+	[REGSET_IOPERM32] = {
+		.core_note_type = NT_386_IOPERM,
+		.n = IO_BITMAP_BYTES / sizeof(u32),
+		.size = sizeof(u32), .align = sizeof(u32),
+		.active = ioperm_active, .get = ioperm_get
+	},
 };
 
 static const struct user_regset_view user_x86_32_view = {
@@ -1357,7 +1489,8 @@
 #endif
 }
 
-void send_sigtrap(struct task_struct *tsk, struct pt_regs *regs, int error_code)
+void send_sigtrap(struct task_struct *tsk, struct pt_regs *regs,
+					 int error_code, int si_code)
 {
 	struct siginfo info;
 
@@ -1366,7 +1499,7 @@
 
 	memset(&info, 0, sizeof(info));
 	info.si_signo = SIGTRAP;
-	info.si_code = TRAP_BRKPT;
+	info.si_code = si_code;
 
 	/* User-mode ip? */
 	info.si_addr = user_mode_vm(regs) ? (void __user *) regs->ip : NULL;
@@ -1375,30 +1508,6 @@
 	force_sig_info(SIGTRAP, &info, tsk);
 }
 
-static void syscall_trace(struct pt_regs *regs)
-{
-	if (!(current->ptrace & PT_PTRACED))
-		return;
-
-#if 0
-	printk("trace %s ip %lx sp %lx ax %d origrax %d caller %lx tiflags %x ptrace %x\n",
-	       current->comm,
-	       regs->ip, regs->sp, regs->ax, regs->orig_ax, __builtin_return_address(0),
-	       current_thread_info()->flags, current->ptrace);
-#endif
-
-	ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
-				? 0x80 : 0));
-	/*
-	 * this isn't the same as continuing with a signal, but it will do
-	 * for normal use.  strace only continues with a signal if the
-	 * stopping signal is not SIGTRAP.  -brl
-	 */
-	if (current->exit_code) {
-		send_sig(current->exit_code, current, 1);
-		current->exit_code = 0;
-	}
-}
 
 #ifdef CONFIG_X86_32
 # define IS_IA32	1
@@ -1432,8 +1541,9 @@
 	if (unlikely(test_thread_flag(TIF_SYSCALL_EMU)))
 		ret = -1L;
 
-	if (ret || test_thread_flag(TIF_SYSCALL_TRACE))
-		syscall_trace(regs);
+	if ((ret || test_thread_flag(TIF_SYSCALL_TRACE)) &&
+	    tracehook_report_syscall_entry(regs))
+		ret = -1L;
 
 	if (unlikely(current->audit_context)) {
 		if (IS_IA32)
@@ -1459,7 +1569,7 @@
 		audit_syscall_exit(AUDITSC_RESULT(regs->ax), regs->ax);
 
 	if (test_thread_flag(TIF_SYSCALL_TRACE))
-		syscall_trace(regs);
+		tracehook_report_syscall_exit(regs, 0);
 
 	/*
 	 * If TIF_SYSCALL_EMU is set, we only get here because of
@@ -1475,6 +1585,6 @@
 	 * system call instruction.
 	 */
 	if (test_thread_flag(TIF_SINGLESTEP) &&
-	    (current->ptrace & PT_PTRACED))
-		send_sigtrap(current, regs, 0);
+	    tracehook_consider_fatal_signal(current, SIGTRAP, SIG_DFL))
+		send_sigtrap(current, regs, 0, TRAP_BRKPT);
 }
diff --git a/arch/x86/kernel/quirks.c b/arch/x86/kernel/quirks.c
index d138588..f6a11b9 100644
--- a/arch/x86/kernel/quirks.c
+++ b/arch/x86/kernel/quirks.c
@@ -354,9 +354,27 @@
 	printk(KERN_DEBUG "Force enabled HPET at resume\n");
 }
 
+static u32 ati_ixp4x0_rev(struct pci_dev *dev)
+{
+	u32 d;
+	u8  b;
+
+	pci_read_config_byte(dev, 0xac, &b);
+	b &= ~(1<<5);
+	pci_write_config_byte(dev, 0xac, b);
+	pci_read_config_dword(dev, 0x70, &d);
+	d |= 1<<8;
+	pci_write_config_dword(dev, 0x70, d);
+	pci_read_config_dword(dev, 0x8, &d);
+	d &= 0xff;
+	dev_printk(KERN_DEBUG, &dev->dev, "SB4X0 revision 0x%x\n", d);
+	return d;
+}
+
 static void ati_force_enable_hpet(struct pci_dev *dev)
 {
-	u32 uninitialized_var(val);
+	u32 d, val;
+	u8  b;
 
 	if (hpet_address || force_hpet_address)
 		return;
@@ -366,14 +384,33 @@
 		return;
 	}
 
+	d = ati_ixp4x0_rev(dev);
+	if (d  < 0x82)
+		return;
+
+	/* base address */
 	pci_write_config_dword(dev, 0x14, 0xfed00000);
 	pci_read_config_dword(dev, 0x14, &val);
+
+	/* enable interrupt */
+	outb(0x72, 0xcd6); b = inb(0xcd7);
+	b |= 0x1;
+	outb(0x72, 0xcd6); outb(b, 0xcd7);
+	outb(0x72, 0xcd6); b = inb(0xcd7);
+	if (!(b & 0x1))
+		return;
+	pci_read_config_dword(dev, 0x64, &d);
+	d |= (1<<10);
+	pci_write_config_dword(dev, 0x64, d);
+	pci_read_config_dword(dev, 0x64, &d);
+	if (!(d & (1<<10)))
+		return;
+
 	force_hpet_address = val;
 	force_hpet_resume_type = ATI_FORCE_HPET_RESUME;
 	dev_printk(KERN_DEBUG, &dev->dev, "Force enabled HPET at 0x%lx\n",
 		   force_hpet_address);
 	cached_dev = dev;
-	return;
 }
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP400_SMBUS,
 			 ati_force_enable_hpet);
diff --git a/arch/x86/kernel/reboot.c b/arch/x86/kernel/reboot.c
index 724adfc..f4c93f1 100644
--- a/arch/x86/kernel/reboot.c
+++ b/arch/x86/kernel/reboot.c
@@ -29,7 +29,11 @@
 
 static const struct desc_ptr no_idt = {};
 static int reboot_mode;
-enum reboot_type reboot_type = BOOT_KBD;
+/*
+ * Keyboard reset and triple fault may result in INIT, not RESET, which
+ * doesn't work when we're in vmx root mode.  Try ACPI first.
+ */
+enum reboot_type reboot_type = BOOT_ACPI;
 int reboot_force;
 
 #if defined(CONFIG_X86_32) && defined(CONFIG_SMP)
diff --git a/arch/x86/kernel/rtc.c b/arch/x86/kernel/rtc.c
index 05191bb..0a23b57 100644
--- a/arch/x86/kernel/rtc.c
+++ b/arch/x86/kernel/rtc.c
@@ -223,11 +223,25 @@
 static __init int add_rtc_cmos(void)
 {
 #ifdef CONFIG_PNP
-	if (!pnp_platform_devices)
-		platform_device_register(&rtc_device);
-#else
+	static const char *ids[] __initconst =
+	    { "PNP0b00", "PNP0b01", "PNP0b02", };
+	struct pnp_dev *dev;
+	struct pnp_id *id;
+	int i;
+
+	pnp_for_each_dev(dev) {
+		for (id = dev->id; id; id = id->next) {
+			for (i = 0; i < ARRAY_SIZE(ids); i++) {
+				if (compare_pnp_id(id, ids[i]) != 0)
+					return 0;
+			}
+		}
+	}
+#endif
+
 	platform_device_register(&rtc_device);
-#endif /* CONFIG_PNP */
+	dev_info(&rtc_device.dev,
+		 "registered platform RTC device (no PNP device found)\n");
 	return 0;
 }
 device_initcall(add_rtc_cmos);
diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c
index 362d4e7..2255782 100644
--- a/arch/x86/kernel/setup.c
+++ b/arch/x86/kernel/setup.c
@@ -223,6 +223,9 @@
 #define RAMDISK_LOAD_FLAG		0x4000
 
 static char __initdata command_line[COMMAND_LINE_SIZE];
+#ifdef CONFIG_CMDLINE_BOOL
+static char __initdata builtin_cmdline[COMMAND_LINE_SIZE] = CONFIG_CMDLINE;
+#endif
 
 #if defined(CONFIG_EDD) || defined(CONFIG_EDD_MODULE)
 struct edd edd;
@@ -299,7 +302,7 @@
 		if (clen > MAX_MAP_CHUNK-slop)
 			clen = MAX_MAP_CHUNK-slop;
 		mapaddr = ramdisk_image & PAGE_MASK;
-		p = early_ioremap(mapaddr, clen+slop);
+		p = early_memremap(mapaddr, clen+slop);
 		memcpy(q, p+slop, clen);
 		early_iounmap(p, clen+slop);
 		q += clen;
@@ -376,7 +379,7 @@
 		return;
 	pa_data = boot_params.hdr.setup_data;
 	while (pa_data) {
-		data = early_ioremap(pa_data, PAGE_SIZE);
+		data = early_memremap(pa_data, PAGE_SIZE);
 		switch (data->type) {
 		case SETUP_E820_EXT:
 			parse_e820_ext(data, pa_data);
@@ -399,7 +402,7 @@
 		return;
 	pa_data = boot_params.hdr.setup_data;
 	while (pa_data) {
-		data = early_ioremap(pa_data, sizeof(*data));
+		data = early_memremap(pa_data, sizeof(*data));
 		e820_update_range(pa_data, sizeof(*data)+data->len,
 			 E820_RAM, E820_RESERVED_KERN);
 		found = 1;
@@ -425,7 +428,7 @@
 		return;
 	pa_data = boot_params.hdr.setup_data;
 	while (pa_data) {
-		data = early_ioremap(pa_data, sizeof(*data));
+		data = early_memremap(pa_data, sizeof(*data));
 		sprintf(buf, "setup data %x", data->type);
 		reserve_early(pa_data, pa_data+sizeof(*data)+data->len, buf);
 		pa_data = data->next;
@@ -579,6 +582,190 @@
 struct x86_quirks *x86_quirks __initdata = &default_x86_quirks;
 
 /*
+ * Some BIOSes seem to corrupt the low 64k of memory during events
+ * like suspend/resume and unplugging an HDMI cable.  Reserve all
+ * remaining free memory in that area and fill it with a distinct
+ * pattern.
+ */
+#ifdef CONFIG_X86_CHECK_BIOS_CORRUPTION
+#define MAX_SCAN_AREAS	8
+
+static int __read_mostly memory_corruption_check = -1;
+
+static unsigned __read_mostly corruption_check_size = 64*1024;
+static unsigned __read_mostly corruption_check_period = 60; /* seconds */
+
+static struct e820entry scan_areas[MAX_SCAN_AREAS];
+static int num_scan_areas;
+
+
+static int set_corruption_check(char *arg)
+{
+	char *end;
+
+	memory_corruption_check = simple_strtol(arg, &end, 10);
+
+	return (*end == 0) ? 0 : -EINVAL;
+}
+early_param("memory_corruption_check", set_corruption_check);
+
+static int set_corruption_check_period(char *arg)
+{
+	char *end;
+
+	corruption_check_period = simple_strtoul(arg, &end, 10);
+
+	return (*end == 0) ? 0 : -EINVAL;
+}
+early_param("memory_corruption_check_period", set_corruption_check_period);
+
+static int set_corruption_check_size(char *arg)
+{
+	char *end;
+	unsigned size;
+
+	size = memparse(arg, &end);
+
+	if (*end == '\0')
+		corruption_check_size = size;
+
+	return (size == corruption_check_size) ? 0 : -EINVAL;
+}
+early_param("memory_corruption_check_size", set_corruption_check_size);
+
+
+static void __init setup_bios_corruption_check(void)
+{
+	u64 addr = PAGE_SIZE;	/* assume first page is reserved anyway */
+
+	if (memory_corruption_check == -1) {
+		memory_corruption_check =
+#ifdef CONFIG_X86_BOOTPARAM_MEMORY_CORRUPTION_CHECK
+			1
+#else
+			0
+#endif
+			;
+	}
+
+	if (corruption_check_size == 0)
+		memory_corruption_check = 0;
+
+	if (!memory_corruption_check)
+		return;
+
+	corruption_check_size = round_up(corruption_check_size, PAGE_SIZE);
+
+	while(addr < corruption_check_size && num_scan_areas < MAX_SCAN_AREAS) {
+		u64 size;
+		addr = find_e820_area_size(addr, &size, PAGE_SIZE);
+
+		if (addr == 0)
+			break;
+
+		if ((addr + size) > corruption_check_size)
+			size = corruption_check_size - addr;
+
+		if (size == 0)
+			break;
+
+		e820_update_range(addr, size, E820_RAM, E820_RESERVED);
+		scan_areas[num_scan_areas].addr = addr;
+		scan_areas[num_scan_areas].size = size;
+		num_scan_areas++;
+
+		/* Assume we've already mapped this early memory */
+		memset(__va(addr), 0, size);
+
+		addr += size;
+	}
+
+	printk(KERN_INFO "Scanning %d areas for low memory corruption\n",
+	       num_scan_areas);
+	update_e820();
+}
+
+static struct timer_list periodic_check_timer;
+
+void check_for_bios_corruption(void)
+{
+	int i;
+	int corruption = 0;
+
+	if (!memory_corruption_check)
+		return;
+
+	for(i = 0; i < num_scan_areas; i++) {
+		unsigned long *addr = __va(scan_areas[i].addr);
+		unsigned long size = scan_areas[i].size;
+
+		for(; size; addr++, size -= sizeof(unsigned long)) {
+			if (!*addr)
+				continue;
+			printk(KERN_ERR "Corrupted low memory at %p (%lx phys) = %08lx\n",
+			       addr, __pa(addr), *addr);
+			corruption = 1;
+			*addr = 0;
+		}
+	}
+
+	WARN(corruption, KERN_ERR "Memory corruption detected in low memory\n");
+}
+
+static void periodic_check_for_corruption(unsigned long data)
+{
+	check_for_bios_corruption();
+	mod_timer(&periodic_check_timer, round_jiffies(jiffies + corruption_check_period*HZ));
+}
+
+void start_periodic_check_for_corruption(void)
+{
+	if (!memory_corruption_check || corruption_check_period == 0)
+		return;
+
+	printk(KERN_INFO "Scanning for low memory corruption every %d seconds\n",
+	       corruption_check_period);
+
+	init_timer(&periodic_check_timer);
+	periodic_check_timer.function = &periodic_check_for_corruption;
+	periodic_check_for_corruption(0);
+}
+#endif
+
+static int __init dmi_low_memory_corruption(const struct dmi_system_id *d)
+{
+	printk(KERN_NOTICE
+		"%s detected: BIOS may corrupt low RAM, working it around.\n",
+		d->ident);
+
+	e820_update_range(0, 0x10000, E820_RAM, E820_RESERVED);
+	sanitize_e820_map(e820.map, ARRAY_SIZE(e820.map), &e820.nr_map);
+
+	return 0;
+}
+
+/* List of systems that have known low memory corruption BIOS problems */
+static struct dmi_system_id __initdata bad_bios_dmi_table[] = {
+#ifdef CONFIG_X86_RESERVE_LOW_64K
+	{
+		.callback = dmi_low_memory_corruption,
+		.ident = "AMI BIOS",
+		.matches = {
+			DMI_MATCH(DMI_BIOS_VENDOR, "American Megatrends Inc."),
+		},
+	},
+	{
+		.callback = dmi_low_memory_corruption,
+		.ident = "Phoenix BIOS",
+		.matches = {
+			DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies, LTD"),
+		},
+	},
+#endif
+	{}
+};
+
+/*
  * Determine if we were loaded by an EFI loader.  If so, then we have also been
  * passed the efi memmap, systab, etc., so we should use these data structures
  * for initialization.  Note, the efi init code path is determined by the
@@ -665,11 +852,28 @@
 	bss_resource.start = virt_to_phys(&__bss_start);
 	bss_resource.end = virt_to_phys(&__bss_stop)-1;
 
+#ifdef CONFIG_CMDLINE_BOOL
+#ifdef CONFIG_CMDLINE_OVERRIDE
+	strlcpy(boot_command_line, builtin_cmdline, COMMAND_LINE_SIZE);
+#else
+	if (builtin_cmdline[0]) {
+		/* append boot loader cmdline to builtin */
+		strlcat(builtin_cmdline, " ", COMMAND_LINE_SIZE);
+		strlcat(builtin_cmdline, boot_command_line, COMMAND_LINE_SIZE);
+		strlcpy(boot_command_line, builtin_cmdline, COMMAND_LINE_SIZE);
+	}
+#endif
+#endif
+
 	strlcpy(command_line, boot_command_line, COMMAND_LINE_SIZE);
 	*cmdline_p = command_line;
 
 	parse_early_param();
 
+#ifdef CONFIG_X86_64
+	check_efer();
+#endif
+
 #if defined(CONFIG_VMI) && defined(CONFIG_X86_32)
 	/*
 	 * Must be before kernel pagetables are setup
@@ -695,6 +899,10 @@
 
 	finish_e820_parsing();
 
+	dmi_scan_machine();
+
+	dmi_check_system(bad_bios_dmi_table);
+
 #ifdef CONFIG_X86_32
 	probe_roms();
 #endif
@@ -738,7 +946,8 @@
 #else
 	num_physpages = max_pfn;
 
-	check_efer();
+ 	if (cpu_has_x2apic)
+ 		check_x2apic();
 
 	/* How many end-of-memory variables you have, grandma! */
 	/* need this before calling reserve_initrd */
@@ -750,6 +959,10 @@
 	high_memory = (void *)__va(max_pfn * PAGE_SIZE - 1) + 1;
 #endif
 
+#ifdef CONFIG_X86_CHECK_BIOS_CORRUPTION
+	setup_bios_corruption_check();
+#endif
+
 	/* max_pfn_mapped is updated here */
 	max_low_pfn_mapped = init_memory_mapping(0, max_low_pfn<<PAGE_SHIFT);
 	max_pfn_mapped = max_low_pfn_mapped;
@@ -778,8 +991,6 @@
 	vsmp_init();
 #endif
 
-	dmi_scan_machine();
-
 	io_delay_init();
 
 	/*
@@ -787,6 +998,8 @@
 	 */
 	acpi_boot_table_init();
 
+	early_acpi_boot_init();
+
 #ifdef CONFIG_ACPI_NUMA
 	/*
 	 * Parse SRAT to discover nodes.
@@ -882,3 +1095,5 @@
 #endif
 #endif
 }
+
+
diff --git a/arch/x86/kernel/setup_percpu.c b/arch/x86/kernel/setup_percpu.c
index 76e305e..0e67f72 100644
--- a/arch/x86/kernel/setup_percpu.c
+++ b/arch/x86/kernel/setup_percpu.c
@@ -162,9 +162,16 @@
 			printk(KERN_INFO
 			       "cpu %d has no node %d or node-local memory\n",
 				cpu, node);
+			if (ptr)
+				printk(KERN_DEBUG "per cpu data for cpu%d at %016lx\n",
+					 cpu, __pa(ptr));
 		}
-		else
+		else {
 			ptr = alloc_bootmem_pages_node(NODE_DATA(node), size);
+			if (ptr)
+				printk(KERN_DEBUG "per cpu data for cpu%d on node%d at %016lx\n",
+					 cpu, node, __pa(ptr));
+		}
 #endif
 		per_cpu_offset(cpu) = ptr - __per_cpu_start;
 		memcpy(ptr, __per_cpu_start, __per_cpu_end - __per_cpu_start);
diff --git a/arch/x86/kernel/sigframe.h b/arch/x86/kernel/sigframe.h
index 72bbb51..cc673aa 100644
--- a/arch/x86/kernel/sigframe.h
+++ b/arch/x86/kernel/sigframe.h
@@ -3,9 +3,18 @@
 	char __user *pretcode;
 	int sig;
 	struct sigcontext sc;
-	struct _fpstate fpstate;
+	/*
+	 * fpstate is unused. fpstate is moved/allocated after
+	 * retcode[] below. This movement allows to have the FP state and the
+	 * future state extensions (xsave) stay together.
+	 * And at the same time retaining the unused fpstate, prevents changing
+	 * the offset of extramask[] in the sigframe and thus prevent any
+	 * legacy application accessing/modifying it.
+	 */
+	struct _fpstate fpstate_unused;
 	unsigned long extramask[_NSIG_WORDS-1];
 	char retcode[8];
+	/* fp state follows here */
 };
 
 struct rt_sigframe {
@@ -15,13 +24,19 @@
 	void __user *puc;
 	struct siginfo info;
 	struct ucontext uc;
-	struct _fpstate fpstate;
 	char retcode[8];
+	/* fp state follows here */
 };
 #else
 struct rt_sigframe {
 	char __user *pretcode;
 	struct ucontext uc;
 	struct siginfo info;
+	/* fp state follows here */
 };
+
+int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
+		sigset_t *set, struct pt_regs *regs);
+int ia32_setup_frame(int sig, struct k_sigaction *ka,
+		sigset_t *set, struct pt_regs *regs);
 #endif
diff --git a/arch/x86/kernel/signal_32.c b/arch/x86/kernel/signal_32.c
index 6fb5bcd..d6dd057 100644
--- a/arch/x86/kernel/signal_32.c
+++ b/arch/x86/kernel/signal_32.c
@@ -17,6 +17,7 @@
 #include <linux/errno.h>
 #include <linux/sched.h>
 #include <linux/wait.h>
+#include <linux/tracehook.h>
 #include <linux/elf.h>
 #include <linux/smp.h>
 #include <linux/mm.h>
@@ -26,6 +27,8 @@
 #include <asm/uaccess.h>
 #include <asm/i387.h>
 #include <asm/vdso.h>
+#include <asm/syscall.h>
+#include <asm/syscalls.h>
 
 #include "sigframe.h"
 
@@ -110,6 +113,27 @@
 	return do_sigaltstack(uss, uoss, regs->sp);
 }
 
+#define COPY(x)			{		\
+	err |= __get_user(regs->x, &sc->x);	\
+}
+
+#define COPY_SEG(seg)		{			\
+		unsigned short tmp;			\
+		err |= __get_user(tmp, &sc->seg);	\
+		regs->seg = tmp;			\
+}
+
+#define COPY_SEG_STRICT(seg)	{			\
+		unsigned short tmp;			\
+		err |= __get_user(tmp, &sc->seg);	\
+		regs->seg = tmp | 3;			\
+}
+
+#define GET_SEG(seg)		{			\
+		unsigned short tmp;			\
+		err |= __get_user(tmp, &sc->seg);	\
+		loadsegment(seg, tmp);			\
+}
 
 /*
  * Do a signal return; undo the signal stack.
@@ -118,28 +142,13 @@
 restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc,
 		   unsigned long *pax)
 {
+	void __user *buf;
+	unsigned int tmpflags;
 	unsigned int err = 0;
 
 	/* Always make any pending restarted system calls return -EINTR */
 	current_thread_info()->restart_block.fn = do_no_restart_syscall;
 
-#define COPY(x)		err |= __get_user(regs->x, &sc->x)
-
-#define COPY_SEG(seg)							\
-	{ unsigned short tmp;						\
-	  err |= __get_user(tmp, &sc->seg);				\
-	  regs->seg = tmp; }
-
-#define COPY_SEG_STRICT(seg)						\
-	{ unsigned short tmp;						\
-	  err |= __get_user(tmp, &sc->seg);				\
-	  regs->seg = tmp|3; }
-
-#define GET_SEG(seg)							\
-	{ unsigned short tmp;						\
-	  err |= __get_user(tmp, &sc->seg);				\
-	  loadsegment(seg, tmp); }
-
 	GET_SEG(gs);
 	COPY_SEG(fs);
 	COPY_SEG(es);
@@ -149,38 +158,15 @@
 	COPY_SEG_STRICT(cs);
 	COPY_SEG_STRICT(ss);
 
-	{
-		unsigned int tmpflags;
+	err |= __get_user(tmpflags, &sc->flags);
+	regs->flags = (regs->flags & ~FIX_EFLAGS) | (tmpflags & FIX_EFLAGS);
+	regs->orig_ax = -1;		/* disable syscall checks */
 
-		err |= __get_user(tmpflags, &sc->flags);
-		regs->flags = (regs->flags & ~FIX_EFLAGS) |
-						(tmpflags & FIX_EFLAGS);
-		regs->orig_ax = -1;		/* disable syscall checks */
-	}
-
-	{
-		struct _fpstate __user *buf;
-
-		err |= __get_user(buf, &sc->fpstate);
-		if (buf) {
-			if (!access_ok(VERIFY_READ, buf, sizeof(*buf)))
-				goto badframe;
-			err |= restore_i387(buf);
-		} else {
-			struct task_struct *me = current;
-
-			if (used_math()) {
-				clear_fpu(me);
-				clear_used_math();
-			}
-		}
-	}
+	err |= __get_user(buf, &sc->fpstate);
+	err |= restore_i387_xstate(buf);
 
 	err |= __get_user(*pax, &sc->ax);
 	return err;
-
-badframe:
-	return 1;
 }
 
 asmlinkage unsigned long sys_sigreturn(unsigned long __unused)
@@ -226,9 +212,8 @@
 	return 0;
 }
 
-asmlinkage int sys_rt_sigreturn(unsigned long __unused)
+static long do_rt_sigreturn(struct pt_regs *regs)
 {
-	struct pt_regs *regs = (struct pt_regs *)&__unused;
 	struct rt_sigframe __user *frame;
 	unsigned long ax;
 	sigset_t set;
@@ -254,15 +239,22 @@
 	return ax;
 
 badframe:
-	force_sig(SIGSEGV, current);
+	signal_fault(regs, frame, "rt_sigreturn");
 	return 0;
 }
 
+asmlinkage int sys_rt_sigreturn(unsigned long __unused)
+{
+	struct pt_regs *regs = (struct pt_regs *)&__unused;
+
+	return do_rt_sigreturn(regs);
+}
+
 /*
  * Set up a signal frame.
  */
 static int
-setup_sigcontext(struct sigcontext __user *sc, struct _fpstate __user *fpstate,
+setup_sigcontext(struct sigcontext __user *sc, void __user *fpstate,
 		 struct pt_regs *regs, unsigned long mask)
 {
 	int tmp, err = 0;
@@ -289,7 +281,7 @@
 	err |= __put_user(regs->sp, &sc->sp_at_signal);
 	err |= __put_user(regs->ss, (unsigned int __user *)&sc->ss);
 
-	tmp = save_i387(fpstate);
+	tmp = save_i387_xstate(fpstate);
 	if (tmp < 0)
 		err = 1;
 	else
@@ -306,7 +298,8 @@
  * Determine which stack to use..
  */
 static inline void __user *
-get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size)
+get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size,
+	     void **fpstate)
 {
 	unsigned long sp;
 
@@ -332,6 +325,11 @@
 			sp = (unsigned long) ka->sa.sa_restorer;
 	}
 
+	if (used_math()) {
+		sp = sp - sig_xstate_size;
+		*fpstate = (struct _fpstate *) sp;
+	}
+
 	sp -= frame_size;
 	/*
 	 * Align the stack pointer according to the i386 ABI,
@@ -343,38 +341,29 @@
 }
 
 static int
-setup_frame(int sig, struct k_sigaction *ka, sigset_t *set,
-	    struct pt_regs *regs)
+__setup_frame(int sig, struct k_sigaction *ka, sigset_t *set,
+	      struct pt_regs *regs)
 {
 	struct sigframe __user *frame;
 	void __user *restorer;
 	int err = 0;
-	int usig;
+	void __user *fpstate = NULL;
 
-	frame = get_sigframe(ka, regs, sizeof(*frame));
+	frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate);
 
 	if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
-		goto give_sigsegv;
+		return -EFAULT;
 
-	usig = current_thread_info()->exec_domain
-		&& current_thread_info()->exec_domain->signal_invmap
-		&& sig < 32
-		? current_thread_info()->exec_domain->signal_invmap[sig]
-		: sig;
+	if (__put_user(sig, &frame->sig))
+		return -EFAULT;
 
-	err = __put_user(usig, &frame->sig);
-	if (err)
-		goto give_sigsegv;
-
-	err = setup_sigcontext(&frame->sc, &frame->fpstate, regs, set->sig[0]);
-	if (err)
-		goto give_sigsegv;
+	if (setup_sigcontext(&frame->sc, fpstate, regs, set->sig[0]))
+		return -EFAULT;
 
 	if (_NSIG_WORDS > 1) {
-		err = __copy_to_user(&frame->extramask, &set->sig[1],
-				      sizeof(frame->extramask));
-		if (err)
-			goto give_sigsegv;
+		if (__copy_to_user(&frame->extramask, &set->sig[1],
+				   sizeof(frame->extramask)))
+			return -EFAULT;
 	}
 
 	if (current->mm->context.vdso)
@@ -399,7 +388,7 @@
 	err |= __put_user(0x80cd, (short __user *)(frame->retcode+6));
 
 	if (err)
-		goto give_sigsegv;
+		return -EFAULT;
 
 	/* Set up registers for signal handler */
 	regs->sp = (unsigned long)frame;
@@ -414,50 +403,43 @@
 	regs->cs = __USER_CS;
 
 	return 0;
-
-give_sigsegv:
-	force_sigsegv(sig, current);
-	return -EFAULT;
 }
 
-static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
-			  sigset_t *set, struct pt_regs *regs)
+static int __setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
+			    sigset_t *set, struct pt_regs *regs)
 {
 	struct rt_sigframe __user *frame;
 	void __user *restorer;
 	int err = 0;
-	int usig;
+	void __user *fpstate = NULL;
 
-	frame = get_sigframe(ka, regs, sizeof(*frame));
+	frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate);
 
 	if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
-		goto give_sigsegv;
+		return -EFAULT;
 
-	usig = current_thread_info()->exec_domain
-		&& current_thread_info()->exec_domain->signal_invmap
-		&& sig < 32
-		? current_thread_info()->exec_domain->signal_invmap[sig]
-		: sig;
-
-	err |= __put_user(usig, &frame->sig);
+	err |= __put_user(sig, &frame->sig);
 	err |= __put_user(&frame->info, &frame->pinfo);
 	err |= __put_user(&frame->uc, &frame->puc);
 	err |= copy_siginfo_to_user(&frame->info, info);
 	if (err)
-		goto give_sigsegv;
+		return -EFAULT;
 
 	/* Create the ucontext.  */
-	err |= __put_user(0, &frame->uc.uc_flags);
+	if (cpu_has_xsave)
+		err |= __put_user(UC_FP_XSTATE, &frame->uc.uc_flags);
+	else
+		err |= __put_user(0, &frame->uc.uc_flags);
 	err |= __put_user(0, &frame->uc.uc_link);
 	err |= __put_user(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp);
 	err |= __put_user(sas_ss_flags(regs->sp),
 			  &frame->uc.uc_stack.ss_flags);
 	err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
-	err |= setup_sigcontext(&frame->uc.uc_mcontext, &frame->fpstate,
+	err |= setup_sigcontext(&frame->uc.uc_mcontext, fpstate,
 				regs, set->sig[0]);
 	err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
 	if (err)
-		goto give_sigsegv;
+		return -EFAULT;
 
 	/* Set up to return from userspace.  */
 	restorer = VDSO32_SYMBOL(current->mm->context.vdso, rt_sigreturn);
@@ -477,12 +459,12 @@
 	err |= __put_user(0x80cd, (short __user *)(frame->retcode+5));
 
 	if (err)
-		goto give_sigsegv;
+		return -EFAULT;
 
 	/* Set up registers for signal handler */
 	regs->sp = (unsigned long)frame;
 	regs->ip = (unsigned long)ka->sa.sa_handler;
-	regs->ax = (unsigned long)usig;
+	regs->ax = (unsigned long)sig;
 	regs->dx = (unsigned long)&frame->info;
 	regs->cx = (unsigned long)&frame->uc;
 
@@ -492,15 +474,48 @@
 	regs->cs = __USER_CS;
 
 	return 0;
-
-give_sigsegv:
-	force_sigsegv(sig, current);
-	return -EFAULT;
 }
 
 /*
  * OK, we're invoking a handler:
  */
+static int signr_convert(int sig)
+{
+	struct thread_info *info = current_thread_info();
+
+	if (info->exec_domain && info->exec_domain->signal_invmap && sig < 32)
+		return info->exec_domain->signal_invmap[sig];
+	return sig;
+}
+
+#define is_ia32	1
+#define ia32_setup_frame	__setup_frame
+#define ia32_setup_rt_frame	__setup_rt_frame
+
+static int
+setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
+	       sigset_t *set, struct pt_regs *regs)
+{
+	int usig = signr_convert(sig);
+	int ret;
+
+	/* Set up the stack frame */
+	if (is_ia32) {
+		if (ka->sa.sa_flags & SA_SIGINFO)
+			ret = ia32_setup_rt_frame(usig, ka, info, set, regs);
+		else
+			ret = ia32_setup_frame(usig, ka, set, regs);
+	} else
+		ret = __setup_rt_frame(sig, ka, info, set, regs);
+
+	if (ret) {
+		force_sigsegv(sig, current);
+		return -EFAULT;
+	}
+
+	return ret;
+}
+
 static int
 handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
 	      sigset_t *oldset, struct pt_regs *regs)
@@ -508,9 +523,9 @@
 	int ret;
 
 	/* Are we from a system call? */
-	if ((long)regs->orig_ax >= 0) {
+	if (syscall_get_nr(current, regs) >= 0) {
 		/* If so, check system call restarting.. */
-		switch (regs->ax) {
+		switch (syscall_get_error(current, regs)) {
 		case -ERESTART_RESTARTBLOCK:
 		case -ERESTARTNOHAND:
 			regs->ax = -EINTR;
@@ -537,15 +552,20 @@
 	    likely(test_and_clear_thread_flag(TIF_FORCED_TF)))
 		regs->flags &= ~X86_EFLAGS_TF;
 
-	/* Set up the stack frame */
-	if (ka->sa.sa_flags & SA_SIGINFO)
-		ret = setup_rt_frame(sig, ka, info, oldset, regs);
-	else
-		ret = setup_frame(sig, ka, oldset, regs);
+	ret = setup_rt_frame(sig, ka, info, oldset, regs);
 
 	if (ret)
 		return ret;
 
+#ifdef CONFIG_X86_64
+	/*
+	 * This has nothing to do with segment registers,
+	 * despite the name.  This magic affects uaccess.h
+	 * macros' behavior.  Reset it to the normal setting.
+	 */
+	set_fs(USER_DS);
+#endif
+
 	/*
 	 * Clear the direction flag as per the ABI for function entry.
 	 */
@@ -558,8 +578,6 @@
 	 * handler too.
 	 */
 	regs->flags &= ~X86_EFLAGS_TF;
-	if (test_thread_flag(TIF_SINGLESTEP))
-		ptrace_notify(SIGTRAP);
 
 	spin_lock_irq(&current->sighand->siglock);
 	sigorsets(&current->blocked, &current->blocked, &ka->sa.sa_mask);
@@ -568,9 +586,13 @@
 	recalc_sigpending();
 	spin_unlock_irq(&current->sighand->siglock);
 
+	tracehook_signal_handler(sig, info, ka, regs,
+				 test_thread_flag(TIF_SINGLESTEP));
+
 	return 0;
 }
 
+#define NR_restart_syscall	__NR_restart_syscall
 /*
  * Note that 'init' is a special process: it doesn't get signals it doesn't
  * want to handle. Thus you cannot kill init even with a SIGKILL even by
@@ -623,9 +645,9 @@
 	}
 
 	/* Did we come from a system call? */
-	if ((long)regs->orig_ax >= 0) {
+	if (syscall_get_nr(current, regs) >= 0) {
 		/* Restart the system call - no handlers present */
-		switch (regs->ax) {
+		switch (syscall_get_error(current, regs)) {
 		case -ERESTARTNOHAND:
 		case -ERESTARTSYS:
 		case -ERESTARTNOINTR:
@@ -634,7 +656,7 @@
 			break;
 
 		case -ERESTART_RESTARTBLOCK:
-			regs->ax = __NR_restart_syscall;
+			regs->ax = NR_restart_syscall;
 			regs->ip -= 2;
 			break;
 		}
@@ -657,9 +679,38 @@
 void
 do_notify_resume(struct pt_regs *regs, void *unused, __u32 thread_info_flags)
 {
+#if defined(CONFIG_X86_64) && defined(CONFIG_X86_MCE)
+	/* notify userspace of pending MCEs */
+	if (thread_info_flags & _TIF_MCE_NOTIFY)
+		mce_notify_user();
+#endif /* CONFIG_X86_64 && CONFIG_X86_MCE */
+
 	/* deal with pending signal delivery */
 	if (thread_info_flags & _TIF_SIGPENDING)
 		do_signal(regs);
 
+	if (thread_info_flags & _TIF_NOTIFY_RESUME) {
+		clear_thread_flag(TIF_NOTIFY_RESUME);
+		tracehook_notify_resume(regs);
+	}
+
+#ifdef CONFIG_X86_32
 	clear_thread_flag(TIF_IRET);
+#endif /* CONFIG_X86_32 */
+}
+
+void signal_fault(struct pt_regs *regs, void __user *frame, char *where)
+{
+	struct task_struct *me = current;
+
+	if (show_unhandled_signals && printk_ratelimit()) {
+		printk(KERN_INFO
+		       "%s[%d] bad frame in %s frame:%p ip:%lx sp:%lx orax:%lx",
+		       me->comm, me->pid, where, frame,
+		       regs->ip, regs->sp, regs->orig_ax);
+		print_vma_addr(" in ", regs->ip);
+		printk(KERN_CONT "\n");
+	}
+
+	force_sig(SIGSEGV, me);
 }
diff --git a/arch/x86/kernel/signal_64.c b/arch/x86/kernel/signal_64.c
index ca316b5..a5c9627 100644
--- a/arch/x86/kernel/signal_64.c
+++ b/arch/x86/kernel/signal_64.c
@@ -15,17 +15,21 @@
 #include <linux/errno.h>
 #include <linux/wait.h>
 #include <linux/ptrace.h>
+#include <linux/tracehook.h>
 #include <linux/unistd.h>
 #include <linux/stddef.h>
 #include <linux/personality.h>
 #include <linux/compiler.h>
+#include <linux/uaccess.h>
+
 #include <asm/processor.h>
 #include <asm/ucontext.h>
-#include <asm/uaccess.h>
 #include <asm/i387.h>
 #include <asm/proto.h>
 #include <asm/ia32_unistd.h>
 #include <asm/mce.h>
+#include <asm/syscall.h>
+#include <asm/syscalls.h>
 #include "sigframe.h"
 
 #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
@@ -41,11 +45,6 @@
 # define FIX_EFLAGS	__FIX_EFLAGS
 #endif
 
-int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
-               sigset_t *set, struct pt_regs * regs); 
-int ia32_setup_frame(int sig, struct k_sigaction *ka,
-            sigset_t *set, struct pt_regs * regs); 
-
 asmlinkage long
 sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss,
 		struct pt_regs *regs)
@@ -53,67 +52,14 @@
 	return do_sigaltstack(uss, uoss, regs->sp);
 }
 
-/*
- * Signal frame handlers.
- */
-
-static inline int save_i387(struct _fpstate __user *buf)
-{
-	struct task_struct *tsk = current;
-	int err = 0;
-
-	BUILD_BUG_ON(sizeof(struct user_i387_struct) !=
-			sizeof(tsk->thread.xstate->fxsave));
-
-	if ((unsigned long)buf % 16)
-		printk("save_i387: bad fpstate %p\n", buf);
-
-	if (!used_math())
-		return 0;
-	clear_used_math(); /* trigger finit */
-	if (task_thread_info(tsk)->status & TS_USEDFPU) {
-		err = save_i387_checking((struct i387_fxsave_struct __user *)
-					 buf);
-		if (err)
-			return err;
-		task_thread_info(tsk)->status &= ~TS_USEDFPU;
-		stts();
-	} else {
-		if (__copy_to_user(buf, &tsk->thread.xstate->fxsave,
-				   sizeof(struct i387_fxsave_struct)))
-			return -1;
-	}
-	return 1;
+#define COPY(x)			{		\
+	err |= __get_user(regs->x, &sc->x);	\
 }
 
-/*
- * This restores directly out of user space. Exceptions are handled.
- */
-static inline int restore_i387(struct _fpstate __user *buf)
-{
-	struct task_struct *tsk = current;
-	int err;
-
-	if (!used_math()) {
-		err = init_fpu(tsk);
-		if (err)
-			return err;
-	}
-
-	if (!(task_thread_info(current)->status & TS_USEDFPU)) {
-		clts();
-		task_thread_info(current)->status |= TS_USEDFPU;
-	}
-	err = restore_fpu_checking((__force struct i387_fxsave_struct *)buf);
-	if (unlikely(err)) {
-		/*
-		 * Encountered an error while doing the restore from the
-		 * user buffer, clear the fpu state.
-		 */
-		clear_fpu(tsk);
-		clear_used_math();
-	}
-	return err;
+#define COPY_SEG_STRICT(seg)	{			\
+		unsigned short tmp;			\
+		err |= __get_user(tmp, &sc->seg);	\
+		regs->seg = tmp | 3;			\
 }
 
 /*
@@ -123,13 +69,13 @@
 restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc,
 		   unsigned long *pax)
 {
+	void __user *buf;
+	unsigned int tmpflags;
 	unsigned int err = 0;
 
 	/* Always make any pending restarted system calls return -EINTR */
 	current_thread_info()->restart_block.fn = do_no_restart_syscall;
 
-#define COPY(x)		err |= __get_user(regs->x, &sc->x)
-
 	COPY(di); COPY(si); COPY(bp); COPY(sp); COPY(bx);
 	COPY(dx); COPY(cx); COPY(ip);
 	COPY(r8);
@@ -144,48 +90,24 @@
 	/* Kernel saves and restores only the CS segment register on signals,
 	 * which is the bare minimum needed to allow mixed 32/64-bit code.
 	 * App's signal handler can save/restore other segments if needed. */
-	{
-		unsigned cs;
-		err |= __get_user(cs, &sc->cs);
-		regs->cs = cs | 3;	/* Force into user mode */
-	}
+	COPY_SEG_STRICT(cs);
 
-	{
-		unsigned int tmpflags;
-		err |= __get_user(tmpflags, &sc->flags);
-		regs->flags = (regs->flags & ~FIX_EFLAGS) | (tmpflags & FIX_EFLAGS);
-		regs->orig_ax = -1;		/* disable syscall checks */
-	}
+	err |= __get_user(tmpflags, &sc->flags);
+	regs->flags = (regs->flags & ~FIX_EFLAGS) | (tmpflags & FIX_EFLAGS);
+	regs->orig_ax = -1;		/* disable syscall checks */
 
-	{
-		struct _fpstate __user * buf;
-		err |= __get_user(buf, &sc->fpstate);
-
-		if (buf) {
-			if (!access_ok(VERIFY_READ, buf, sizeof(*buf)))
-				goto badframe;
-			err |= restore_i387(buf);
-		} else {
-			struct task_struct *me = current;
-			if (used_math()) {
-				clear_fpu(me);
-				clear_used_math();
-			}
-		}
-	}
+	err |= __get_user(buf, &sc->fpstate);
+	err |= restore_i387_xstate(buf);
 
 	err |= __get_user(*pax, &sc->ax);
 	return err;
-
-badframe:
-	return 1;
 }
 
-asmlinkage long sys_rt_sigreturn(struct pt_regs *regs)
+static long do_rt_sigreturn(struct pt_regs *regs)
 {
 	struct rt_sigframe __user *frame;
-	sigset_t set;
 	unsigned long ax;
+	sigset_t set;
 
 	frame = (struct rt_sigframe __user *)(regs->sp - sizeof(long));
 	if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
@@ -198,7 +120,7 @@
 	current->blocked = set;
 	recalc_sigpending();
 	spin_unlock_irq(&current->sighand->siglock);
-	
+
 	if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &ax))
 		goto badframe;
 
@@ -208,16 +130,22 @@
 	return ax;
 
 badframe:
-	signal_fault(regs,frame,"sigreturn");
+	signal_fault(regs, frame, "rt_sigreturn");
 	return 0;
-}	
+}
+
+asmlinkage long sys_rt_sigreturn(struct pt_regs *regs)
+{
+	return do_rt_sigreturn(regs);
+}
 
 /*
  * Set up a signal frame.
  */
 
 static inline int
-setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs, unsigned long mask, struct task_struct *me)
+setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs,
+		unsigned long mask, struct task_struct *me)
 {
 	int err = 0;
 
@@ -269,41 +197,40 @@
 			sp = current->sas_ss_sp + current->sas_ss_size;
 	}
 
-	return (void __user *)round_down(sp - size, 16);
+	return (void __user *)round_down(sp - size, 64);
 }
 
-static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
-			   sigset_t *set, struct pt_regs * regs)
+static int __setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
+			    sigset_t *set, struct pt_regs *regs)
 {
 	struct rt_sigframe __user *frame;
-	struct _fpstate __user *fp = NULL; 
+	void __user *fp = NULL;
 	int err = 0;
 	struct task_struct *me = current;
 
 	if (used_math()) {
-		fp = get_stack(ka, regs, sizeof(struct _fpstate)); 
+		fp = get_stack(ka, regs, sig_xstate_size);
 		frame = (void __user *)round_down(
 			(unsigned long)fp - sizeof(struct rt_sigframe), 16) - 8;
 
-		if (!access_ok(VERIFY_WRITE, fp, sizeof(struct _fpstate)))
-			goto give_sigsegv;
-
-		if (save_i387(fp) < 0) 
-			err |= -1; 
+		if (save_i387_xstate(fp) < 0)
+			return -EFAULT;
 	} else
 		frame = get_stack(ka, regs, sizeof(struct rt_sigframe)) - 8;
 
 	if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
-		goto give_sigsegv;
+		return -EFAULT;
 
-	if (ka->sa.sa_flags & SA_SIGINFO) { 
-		err |= copy_siginfo_to_user(&frame->info, info);
-		if (err)
-			goto give_sigsegv;
+	if (ka->sa.sa_flags & SA_SIGINFO) {
+		if (copy_siginfo_to_user(&frame->info, info))
+			return -EFAULT;
 	}
-		
+
 	/* Create the ucontext.  */
-	err |= __put_user(0, &frame->uc.uc_flags);
+	if (cpu_has_xsave)
+		err |= __put_user(UC_FP_XSTATE, &frame->uc.uc_flags);
+	else
+		err |= __put_user(0, &frame->uc.uc_flags);
 	err |= __put_user(0, &frame->uc.uc_link);
 	err |= __put_user(me->sas_ss_sp, &frame->uc.uc_stack.ss_sp);
 	err |= __put_user(sas_ss_flags(regs->sp),
@@ -311,9 +238,9 @@
 	err |= __put_user(me->sas_ss_size, &frame->uc.uc_stack.ss_size);
 	err |= setup_sigcontext(&frame->uc.uc_mcontext, regs, set->sig[0], me);
 	err |= __put_user(fp, &frame->uc.uc_mcontext.fpstate);
-	if (sizeof(*set) == 16) { 
+	if (sizeof(*set) == 16) {
 		__put_user(set->sig[0], &frame->uc.uc_sigmask.sig[0]);
-		__put_user(set->sig[1], &frame->uc.uc_sigmask.sig[1]); 
+		__put_user(set->sig[1], &frame->uc.uc_sigmask.sig[1]);
 	} else
 		err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
 
@@ -324,15 +251,15 @@
 		err |= __put_user(ka->sa.sa_restorer, &frame->pretcode);
 	} else {
 		/* could use a vstub here */
-		goto give_sigsegv; 
+		return -EFAULT;
 	}
 
 	if (err)
-		goto give_sigsegv;
+		return -EFAULT;
 
 	/* Set up registers for signal handler */
 	regs->di = sig;
-	/* In case the signal handler was declared without prototypes */ 
+	/* In case the signal handler was declared without prototypes */
 	regs->ax = 0;
 
 	/* This also works for non SA_SIGINFO handlers because they expect the
@@ -348,44 +275,45 @@
 	regs->cs = __USER_CS;
 
 	return 0;
-
-give_sigsegv:
-	force_sigsegv(sig, current);
-	return -EFAULT;
-}
-
-/*
- * Return -1L or the syscall number that @regs is executing.
- */
-static long current_syscall(struct pt_regs *regs)
-{
-	/*
-	 * We always sign-extend a -1 value being set here,
-	 * so this is always either -1L or a syscall number.
-	 */
-	return regs->orig_ax;
-}
-
-/*
- * Return a value that is -EFOO if the system call in @regs->orig_ax
- * returned an error.  This only works for @regs from @current.
- */
-static long current_syscall_ret(struct pt_regs *regs)
-{
-#ifdef CONFIG_IA32_EMULATION
-	if (test_thread_flag(TIF_IA32))
-		/*
-		 * Sign-extend the value so (int)-EFOO becomes (long)-EFOO
-		 * and will match correctly in comparisons.
-		 */
-		return (int) regs->ax;
-#endif
-	return regs->ax;
 }
 
 /*
  * OK, we're invoking a handler
- */	
+ */
+static int signr_convert(int sig)
+{
+	return sig;
+}
+
+#ifdef CONFIG_IA32_EMULATION
+#define is_ia32	test_thread_flag(TIF_IA32)
+#else
+#define is_ia32	0
+#endif
+
+static int
+setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
+	       sigset_t *set, struct pt_regs *regs)
+{
+	int usig = signr_convert(sig);
+	int ret;
+
+	/* Set up the stack frame */
+	if (is_ia32) {
+		if (ka->sa.sa_flags & SA_SIGINFO)
+			ret = ia32_setup_rt_frame(usig, ka, info, set, regs);
+		else
+			ret = ia32_setup_frame(usig, ka, set, regs);
+	} else
+		ret = __setup_rt_frame(sig, ka, info, set, regs);
+
+	if (ret) {
+		force_sigsegv(sig, current);
+		return -EFAULT;
+	}
+
+	return ret;
+}
 
 static int
 handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
@@ -394,9 +322,9 @@
 	int ret;
 
 	/* Are we from a system call? */
-	if (current_syscall(regs) >= 0) {
+	if (syscall_get_nr(current, regs) >= 0) {
 		/* If so, check system call restarting.. */
-		switch (current_syscall_ret(regs)) {
+		switch (syscall_get_error(current, regs)) {
 		case -ERESTART_RESTARTBLOCK:
 		case -ERESTARTNOHAND:
 			regs->ax = -EINTR;
@@ -423,50 +351,48 @@
 	    likely(test_and_clear_thread_flag(TIF_FORCED_TF)))
 		regs->flags &= ~X86_EFLAGS_TF;
 
-#ifdef CONFIG_IA32_EMULATION
-	if (test_thread_flag(TIF_IA32)) {
-		if (ka->sa.sa_flags & SA_SIGINFO)
-			ret = ia32_setup_rt_frame(sig, ka, info, oldset, regs);
-		else
-			ret = ia32_setup_frame(sig, ka, oldset, regs);
-	} else 
-#endif
 	ret = setup_rt_frame(sig, ka, info, oldset, regs);
 
-	if (ret == 0) {
-		/*
-		 * This has nothing to do with segment registers,
-		 * despite the name.  This magic affects uaccess.h
-		 * macros' behavior.  Reset it to the normal setting.
-		 */
-		set_fs(USER_DS);
+	if (ret)
+		return ret;
 
-		/*
-		 * Clear the direction flag as per the ABI for function entry.
-		 */
-		regs->flags &= ~X86_EFLAGS_DF;
+#ifdef CONFIG_X86_64
+	/*
+	 * This has nothing to do with segment registers,
+	 * despite the name.  This magic affects uaccess.h
+	 * macros' behavior.  Reset it to the normal setting.
+	 */
+	set_fs(USER_DS);
+#endif
 
-		/*
-		 * Clear TF when entering the signal handler, but
-		 * notify any tracer that was single-stepping it.
-		 * The tracer may want to single-step inside the
-		 * handler too.
-		 */
-		regs->flags &= ~X86_EFLAGS_TF;
-		if (test_thread_flag(TIF_SINGLESTEP))
-			ptrace_notify(SIGTRAP);
+	/*
+	 * Clear the direction flag as per the ABI for function entry.
+	 */
+	regs->flags &= ~X86_EFLAGS_DF;
 
-		spin_lock_irq(&current->sighand->siglock);
-		sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
-		if (!(ka->sa.sa_flags & SA_NODEFER))
-			sigaddset(&current->blocked,sig);
-		recalc_sigpending();
-		spin_unlock_irq(&current->sighand->siglock);
-	}
+	/*
+	 * Clear TF when entering the signal handler, but
+	 * notify any tracer that was single-stepping it.
+	 * The tracer may want to single-step inside the
+	 * handler too.
+	 */
+	regs->flags &= ~X86_EFLAGS_TF;
 
-	return ret;
+	spin_lock_irq(&current->sighand->siglock);
+	sigorsets(&current->blocked, &current->blocked, &ka->sa.sa_mask);
+	if (!(ka->sa.sa_flags & SA_NODEFER))
+		sigaddset(&current->blocked, sig);
+	recalc_sigpending();
+	spin_unlock_irq(&current->sighand->siglock);
+
+	tracehook_signal_handler(sig, info, ka, regs,
+				 test_thread_flag(TIF_SINGLESTEP));
+
+	return 0;
 }
 
+#define NR_restart_syscall	\
+	test_thread_flag(TIF_IA32) ? __NR_ia32_restart_syscall : __NR_restart_syscall
 /*
  * Note that 'init' is a special process: it doesn't get signals it doesn't
  * want to handle. Thus you cannot kill init even with a SIGKILL even by
@@ -496,7 +422,8 @@
 
 	signr = get_signal_to_deliver(&info, &ka, regs, NULL);
 	if (signr > 0) {
-		/* Re-enable any watchpoints before delivering the
+		/*
+		 * Re-enable any watchpoints before delivering the
 		 * signal to user space. The processor register will
 		 * have been cleared if the watchpoint triggered
 		 * inside the kernel.
@@ -504,7 +431,7 @@
 		if (current->thread.debugreg7)
 			set_debugreg(current->thread.debugreg7, 7);
 
-		/* Whee!  Actually deliver the signal.  */
+		/* Whee! Actually deliver the signal.  */
 		if (handle_signal(signr, &info, &ka, oldset, regs) == 0) {
 			/*
 			 * A signal was successfully delivered; the saved
@@ -518,19 +445,18 @@
 	}
 
 	/* Did we come from a system call? */
-	if (current_syscall(regs) >= 0) {
+	if (syscall_get_nr(current, regs) >= 0) {
 		/* Restart the system call - no handlers present */
-		switch (current_syscall_ret(regs)) {
+		switch (syscall_get_error(current, regs)) {
 		case -ERESTARTNOHAND:
 		case -ERESTARTSYS:
 		case -ERESTARTNOINTR:
 			regs->ax = regs->orig_ax;
 			regs->ip -= 2;
 			break;
+
 		case -ERESTART_RESTARTBLOCK:
-			regs->ax = test_thread_flag(TIF_IA32) ?
-					__NR_ia32_restart_syscall :
-					__NR_restart_syscall;
+			regs->ax = NR_restart_syscall;
 			regs->ip -= 2;
 			break;
 		}
@@ -546,29 +472,45 @@
 	}
 }
 
-void do_notify_resume(struct pt_regs *regs, void *unused,
-		      __u32 thread_info_flags)
+/*
+ * notification of userspace execution resumption
+ * - triggered by the TIF_WORK_MASK flags
+ */
+void
+do_notify_resume(struct pt_regs *regs, void *unused, __u32 thread_info_flags)
 {
-#ifdef CONFIG_X86_MCE
+#if defined(CONFIG_X86_64) && defined(CONFIG_X86_MCE)
 	/* notify userspace of pending MCEs */
 	if (thread_info_flags & _TIF_MCE_NOTIFY)
 		mce_notify_user();
-#endif /* CONFIG_X86_MCE */
+#endif /* CONFIG_X86_64 && CONFIG_X86_MCE */
 
 	/* deal with pending signal delivery */
 	if (thread_info_flags & _TIF_SIGPENDING)
 		do_signal(regs);
+
+	if (thread_info_flags & _TIF_NOTIFY_RESUME) {
+		clear_thread_flag(TIF_NOTIFY_RESUME);
+		tracehook_notify_resume(regs);
+	}
+
+#ifdef CONFIG_X86_32
+	clear_thread_flag(TIF_IRET);
+#endif /* CONFIG_X86_32 */
 }
 
 void signal_fault(struct pt_regs *regs, void __user *frame, char *where)
-{ 
-	struct task_struct *me = current; 
+{
+	struct task_struct *me = current;
+
 	if (show_unhandled_signals && printk_ratelimit()) {
-		printk("%s[%d] bad frame in %s frame:%p ip:%lx sp:%lx orax:%lx",
-	       me->comm,me->pid,where,frame,regs->ip,regs->sp,regs->orig_ax);
+		printk(KERN_INFO
+		       "%s[%d] bad frame in %s frame:%p ip:%lx sp:%lx orax:%lx",
+		       me->comm, me->pid, where, frame,
+		       regs->ip, regs->sp, regs->orig_ax);
 		print_vma_addr(" in ", regs->ip);
-		printk("\n");
+		printk(KERN_CONT "\n");
 	}
 
-	force_sig(SIGSEGV, me); 
-} 
+	force_sig(SIGSEGV, me);
+}
diff --git a/arch/x86/kernel/smp.c b/arch/x86/kernel/smp.c
index 361b7a4..18f9b19 100644
--- a/arch/x86/kernel/smp.c
+++ b/arch/x86/kernel/smp.c
@@ -214,12 +214,16 @@
 struct smp_ops smp_ops = {
 	.smp_prepare_boot_cpu = native_smp_prepare_boot_cpu,
 	.smp_prepare_cpus = native_smp_prepare_cpus,
-	.cpu_up = native_cpu_up,
 	.smp_cpus_done = native_smp_cpus_done,
 
 	.smp_send_stop = native_smp_send_stop,
 	.smp_send_reschedule = native_smp_send_reschedule,
 
+	.cpu_up = native_cpu_up,
+	.cpu_die = native_cpu_die,
+	.cpu_disable = native_cpu_disable,
+	.play_dead = native_play_dead,
+
 	.send_call_func_ipi = native_send_call_func_ipi,
 	.send_call_func_single_ipi = native_send_call_func_single_ipi,
 };
diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c
index 7985c5b..8c3aca7 100644
--- a/arch/x86/kernel/smpboot.c
+++ b/arch/x86/kernel/smpboot.c
@@ -52,6 +52,7 @@
 #include <asm/desc.h>
 #include <asm/nmi.h>
 #include <asm/irq.h>
+#include <asm/idle.h>
 #include <asm/smp.h>
 #include <asm/trampoline.h>
 #include <asm/cpu.h>
@@ -88,7 +89,7 @@
 #define get_idle_for_cpu(x)      (per_cpu(idle_thread_array, x))
 #define set_idle_for_cpu(x, p)   (per_cpu(idle_thread_array, x) = (p))
 #else
-struct task_struct *idle_thread_array[NR_CPUS] __cpuinitdata ;
+static struct task_struct *idle_thread_array[NR_CPUS] __cpuinitdata ;
 #define get_idle_for_cpu(x)      (idle_thread_array[(x)])
 #define set_idle_for_cpu(x, p)   (idle_thread_array[(x)] = (p))
 #endif
@@ -123,13 +124,12 @@
 
 static atomic_t init_deasserted;
 
-static int boot_cpu_logical_apicid;
 
 /* representing cpus for which sibling maps can be computed */
 static cpumask_t cpu_sibling_setup_map;
 
 /* Set if we find a B stepping CPU */
-int __cpuinitdata smp_b_stepping;
+static int __cpuinitdata smp_b_stepping;
 
 #if defined(CONFIG_NUMA) && defined(CONFIG_X86_32)
 
@@ -165,6 +165,8 @@
 #endif
 
 #ifdef CONFIG_X86_32
+static int boot_cpu_logical_apicid;
+
 u8 cpu_2_logical_apicid[NR_CPUS] __read_mostly =
 					{ [0 ... NR_CPUS-1] = BAD_APICID };
 
@@ -210,7 +212,7 @@
 	/*
 	 * (This works even if the APIC is not enabled.)
 	 */
-	phys_id = GET_APIC_ID(read_apic_id());
+	phys_id = read_apic_id();
 	cpuid = smp_processor_id();
 	if (cpu_isset(cpuid, cpu_callin_map)) {
 		panic("%s: phys CPU#%d, CPU#%d already present??\n", __func__,
@@ -257,6 +259,7 @@
 	end_local_APIC_setup();
 	map_cpu_to_logical_apicid();
 
+	notify_cpu_starting(cpuid);
 	/*
 	 * Get our bogomips.
 	 *
@@ -331,14 +334,17 @@
 	 * does not change while we are assigning vectors to cpus.  Holding
 	 * this lock ensures we don't half assign or remove an irq from a cpu.
 	 */
-	ipi_call_lock_irq();
+	ipi_call_lock();
 	lock_vector_lock();
 	__setup_vector_irq(smp_processor_id());
 	cpu_set(smp_processor_id(), cpu_online_map);
 	unlock_vector_lock();
-	ipi_call_unlock_irq();
+	ipi_call_unlock();
 	per_cpu(cpu_state, smp_processor_id()) = CPU_ONLINE;
 
+	/* enable local interrupts */
+	local_irq_enable();
+
 	setup_secondary_clock();
 
 	wmb();
@@ -550,8 +556,7 @@
 			printk(KERN_CONT
 			       "a previous APIC delivery may have failed\n");
 
-		apic_write(APIC_ICR2, SET_APIC_DEST_FIELD(apicid));
-		apic_write(APIC_ICR, APIC_DM_REMRD | regs[i]);
+		apic_icr_write(APIC_DM_REMRD | regs[i], apicid);
 
 		timeout = 0;
 		do {
@@ -583,11 +588,9 @@
 	int maxlvt;
 
 	/* Target chip */
-	apic_write(APIC_ICR2, SET_APIC_DEST_FIELD(logical_apicid));
-
 	/* Boot on the stack */
 	/* Kick the second */
-	apic_write(APIC_ICR, APIC_DM_NMI | APIC_DEST_LOGICAL);
+	apic_icr_write(APIC_DM_NMI | APIC_DEST_LOGICAL, logical_apicid);
 
 	pr_debug("Waiting for send to finish...\n");
 	send_status = safe_apic_wait_icr_idle();
@@ -596,10 +599,12 @@
 	 * Give the other CPU some time to accept the IPI.
 	 */
 	udelay(200);
-	maxlvt = lapic_get_maxlvt();
-	if (maxlvt > 3)			/* Due to the Pentium erratum 3AP.  */
-		apic_write(APIC_ESR, 0);
-	accept_status = (apic_read(APIC_ESR) & 0xEF);
+	if (APIC_INTEGRATED(apic_version[phys_apicid])) {
+		maxlvt = lapic_get_maxlvt();
+		if (maxlvt > 3)			/* Due to the Pentium erratum 3AP.  */
+			apic_write(APIC_ESR, 0);
+		accept_status = (apic_read(APIC_ESR) & 0xEF);
+	}
 	pr_debug("NMI sent.\n");
 
 	if (send_status)
@@ -640,13 +645,11 @@
 	/*
 	 * Turn INIT on target chip
 	 */
-	apic_write(APIC_ICR2, SET_APIC_DEST_FIELD(phys_apicid));
-
 	/*
 	 * Send IPI
 	 */
-	apic_write(APIC_ICR,
-		   APIC_INT_LEVELTRIG | APIC_INT_ASSERT | APIC_DM_INIT);
+	apic_icr_write(APIC_INT_LEVELTRIG | APIC_INT_ASSERT | APIC_DM_INIT,
+		       phys_apicid);
 
 	pr_debug("Waiting for send to finish...\n");
 	send_status = safe_apic_wait_icr_idle();
@@ -656,10 +659,8 @@
 	pr_debug("Deasserting INIT.\n");
 
 	/* Target chip */
-	apic_write(APIC_ICR2, SET_APIC_DEST_FIELD(phys_apicid));
-
 	/* Send IPI */
-	apic_write(APIC_ICR, APIC_INT_LEVELTRIG | APIC_DM_INIT);
+	apic_icr_write(APIC_INT_LEVELTRIG | APIC_DM_INIT, phys_apicid);
 
 	pr_debug("Waiting for send to finish...\n");
 	send_status = safe_apic_wait_icr_idle();
@@ -702,11 +703,10 @@
 		 */
 
 		/* Target chip */
-		apic_write(APIC_ICR2, SET_APIC_DEST_FIELD(phys_apicid));
-
 		/* Boot on the stack */
 		/* Kick the second */
-		apic_write(APIC_ICR, APIC_DM_STARTUP | (start_eip >> 12));
+		apic_icr_write(APIC_DM_STARTUP | (start_eip >> 12),
+			       phys_apicid);
 
 		/*
 		 * Give the other CPU some time to accept the IPI.
@@ -1175,10 +1175,17 @@
 	 * Setup boot CPU information
 	 */
 	smp_store_cpu_info(0); /* Final full version of the data */
+#ifdef CONFIG_X86_32
 	boot_cpu_logical_apicid = logical_smp_processor_id();
+#endif
 	current_thread_info()->cpu = 0;  /* needed? */
 	set_cpu_sibling_map(0);
 
+#ifdef CONFIG_X86_64
+	enable_IR_x2apic();
+	setup_apic_routing();
+#endif
+
 	if (smp_sanity_check(max_cpus) < 0) {
 		printk(KERN_INFO "SMP disabled\n");
 		disable_smp();
@@ -1186,9 +1193,9 @@
 	}
 
 	preempt_disable();
-	if (GET_APIC_ID(read_apic_id()) != boot_cpu_physical_apicid) {
+	if (read_apic_id() != boot_cpu_physical_apicid) {
 		panic("Boot APIC ID in local APIC unexpected (%d vs %d)",
-		     GET_APIC_ID(read_apic_id()), boot_cpu_physical_apicid);
+		     read_apic_id(), boot_cpu_physical_apicid);
 		/* Or can we switch back to PIC here? */
 	}
 	preempt_enable();
@@ -1254,6 +1261,44 @@
 	check_nmi_watchdog();
 }
 
+/*
+ * cpu_possible_map should be static, it cannot change as cpu's
+ * are onlined, or offlined. The reason is per-cpu data-structures
+ * are allocated by some modules at init time, and dont expect to
+ * do this dynamically on cpu arrival/departure.
+ * cpu_present_map on the other hand can change dynamically.
+ * In case when cpu_hotplug is not compiled, then we resort to current
+ * behaviour, which is cpu_possible == cpu_present.
+ * - Ashok Raj
+ *
+ * Three ways to find out the number of additional hotplug CPUs:
+ * - If the BIOS specified disabled CPUs in ACPI/mptables use that.
+ * - The user can overwrite it with additional_cpus=NUM
+ * - Otherwise don't reserve additional CPUs.
+ * We do this because additional CPUs waste a lot of memory.
+ * -AK
+ */
+__init void prefill_possible_map(void)
+{
+	int i, possible;
+
+	/* no processor from mptable or madt */
+	if (!num_processors)
+		num_processors = 1;
+
+	possible = num_processors + disabled_cpus;
+	if (possible > NR_CPUS)
+		possible = NR_CPUS;
+
+	printk(KERN_INFO "SMP: Allowing %d CPUs, %d hotplug CPUs\n",
+		possible, max_t(int, possible - num_processors, 0));
+
+	for (i = 0; i < possible; i++)
+		cpu_set(i, cpu_possible_map);
+
+	nr_cpu_ids = possible;
+}
+
 #ifdef CONFIG_HOTPLUG_CPU
 
 static void remove_siblinginfo(int cpu)
@@ -1279,63 +1324,6 @@
 	cpu_clear(cpu, cpu_sibling_setup_map);
 }
 
-static int additional_cpus __initdata = -1;
-
-static __init int setup_additional_cpus(char *s)
-{
-	return s && get_option(&s, &additional_cpus) ? 0 : -EINVAL;
-}
-early_param("additional_cpus", setup_additional_cpus);
-
-/*
- * cpu_possible_map should be static, it cannot change as cpu's
- * are onlined, or offlined. The reason is per-cpu data-structures
- * are allocated by some modules at init time, and dont expect to
- * do this dynamically on cpu arrival/departure.
- * cpu_present_map on the other hand can change dynamically.
- * In case when cpu_hotplug is not compiled, then we resort to current
- * behaviour, which is cpu_possible == cpu_present.
- * - Ashok Raj
- *
- * Three ways to find out the number of additional hotplug CPUs:
- * - If the BIOS specified disabled CPUs in ACPI/mptables use that.
- * - The user can overwrite it with additional_cpus=NUM
- * - Otherwise don't reserve additional CPUs.
- * We do this because additional CPUs waste a lot of memory.
- * -AK
- */
-__init void prefill_possible_map(void)
-{
-	int i;
-	int possible;
-
-	/* no processor from mptable or madt */
-	if (!num_processors)
-		num_processors = 1;
-
-#ifdef CONFIG_HOTPLUG_CPU
-	if (additional_cpus == -1) {
-		if (disabled_cpus > 0)
-			additional_cpus = disabled_cpus;
-		else
-			additional_cpus = 0;
-	}
-#else
-	additional_cpus = 0;
-#endif
-	possible = num_processors + additional_cpus;
-	if (possible > NR_CPUS)
-		possible = NR_CPUS;
-
-	printk(KERN_INFO "SMP: Allowing %d CPUs, %d hotplug CPUs\n",
-		possible, max_t(int, possible - num_processors, 0));
-
-	for (i = 0; i < possible; i++)
-		cpu_set(i, cpu_possible_map);
-
-	nr_cpu_ids = possible;
-}
-
 static void __ref remove_cpu_from_maps(int cpu)
 {
 	cpu_clear(cpu, cpu_online_map);
@@ -1346,7 +1334,29 @@
 	numa_remove_cpu(cpu);
 }
 
-int __cpu_disable(void)
+void cpu_disable_common(void)
+{
+	int cpu = smp_processor_id();
+	/*
+	 * HACK:
+	 * Allow any queued timer interrupts to get serviced
+	 * This is only a temporary solution until we cleanup
+	 * fixup_irqs as we do for IA64.
+	 */
+	local_irq_enable();
+	mdelay(1);
+
+	local_irq_disable();
+	remove_siblinginfo(cpu);
+
+	/* It's now safe to remove this processor from the online map */
+	lock_vector_lock();
+	remove_cpu_from_maps(cpu);
+	unlock_vector_lock();
+	fixup_irqs(cpu_online_map);
+}
+
+int native_cpu_disable(void)
 {
 	int cpu = smp_processor_id();
 
@@ -1365,27 +1375,11 @@
 		stop_apic_nmi_watchdog(NULL);
 	clear_local_APIC();
 
-	/*
-	 * HACK:
-	 * Allow any queued timer interrupts to get serviced
-	 * This is only a temporary solution until we cleanup
-	 * fixup_irqs as we do for IA64.
-	 */
-	local_irq_enable();
-	mdelay(1);
-
-	local_irq_disable();
-	remove_siblinginfo(cpu);
-
-	/* It's now safe to remove this processor from the online map */
-	lock_vector_lock();
-	remove_cpu_from_maps(cpu);
-	unlock_vector_lock();
-	fixup_irqs(cpu_online_map);
+	cpu_disable_common();
 	return 0;
 }
 
-void __cpu_die(unsigned int cpu)
+void native_cpu_die(unsigned int cpu)
 {
 	/* We don't do anything here: idle task is faking death itself. */
 	unsigned int i;
@@ -1402,15 +1396,45 @@
 	}
 	printk(KERN_ERR "CPU %u didn't die...\n", cpu);
 }
+
+void play_dead_common(void)
+{
+	idle_task_exit();
+	reset_lazy_tlbstate();
+	irq_ctx_exit(raw_smp_processor_id());
+	c1e_remove_cpu(raw_smp_processor_id());
+
+	mb();
+	/* Ack it */
+	__get_cpu_var(cpu_state) = CPU_DEAD;
+
+	/*
+	 * With physical CPU hotplug, we should halt the cpu
+	 */
+	local_irq_disable();
+}
+
+void native_play_dead(void)
+{
+	play_dead_common();
+	wbinvd_halt();
+}
+
 #else /* ... !CONFIG_HOTPLUG_CPU */
-int __cpu_disable(void)
+int native_cpu_disable(void)
 {
 	return -ENOSYS;
 }
 
-void __cpu_die(unsigned int cpu)
+void native_cpu_die(unsigned int cpu)
 {
 	/* We said "no" in __cpu_disable */
 	BUG();
 }
+
+void native_play_dead(void)
+{
+	BUG();
+}
+
 #endif
diff --git a/arch/x86/kernel/summit_32.c b/arch/x86/kernel/summit_32.c
index d67ce5f..7b98785 100644
--- a/arch/x86/kernel/summit_32.c
+++ b/arch/x86/kernel/summit_32.c
@@ -30,7 +30,7 @@
 #include <linux/init.h>
 #include <asm/io.h>
 #include <asm/bios_ebda.h>
-#include <asm/mach-summit/mach_mpparse.h>
+#include <asm/summit/mpparse.h>
 
 static struct rio_table_hdr *rio_table_hdr __initdata;
 static struct scal_detail   *scal_devs[MAX_NUMNODES] __initdata;
diff --git a/arch/x86/kernel/sys_i386_32.c b/arch/x86/kernel/sys_i386_32.c
index 7066cb8..1884a8d 100644
--- a/arch/x86/kernel/sys_i386_32.c
+++ b/arch/x86/kernel/sys_i386_32.c
@@ -22,6 +22,8 @@
 #include <linux/uaccess.h>
 #include <linux/unistd.h>
 
+#include <asm/syscalls.h>
+
 asmlinkage long sys_mmap2(unsigned long addr, unsigned long len,
 			  unsigned long prot, unsigned long flags,
 			  unsigned long fd, unsigned long pgoff)
diff --git a/arch/x86/kernel/sys_x86_64.c b/arch/x86/kernel/sys_x86_64.c
index 3b360ef..6bc211a 100644
--- a/arch/x86/kernel/sys_x86_64.c
+++ b/arch/x86/kernel/sys_x86_64.c
@@ -13,15 +13,17 @@
 #include <linux/utsname.h>
 #include <linux/personality.h>
 #include <linux/random.h>
+#include <linux/uaccess.h>
 
-#include <asm/uaccess.h>
 #include <asm/ia32.h>
+#include <asm/syscalls.h>
 
-asmlinkage long sys_mmap(unsigned long addr, unsigned long len, unsigned long prot, unsigned long flags,
-	unsigned long fd, unsigned long off)
+asmlinkage long sys_mmap(unsigned long addr, unsigned long len,
+		unsigned long prot, unsigned long flags,
+		unsigned long fd, unsigned long off)
 {
 	long error;
-	struct file * file;
+	struct file *file;
 
 	error = -EINVAL;
 	if (off & ~PAGE_MASK)
@@ -56,9 +58,9 @@
 		   unmapped base down for this case. This can give
 		   conflicts with the heap, but we assume that glibc
 		   malloc knows how to fall back to mmap. Give it 1GB
-		   of playground for now. -AK */ 
-		*begin = 0x40000000; 
-		*end = 0x80000000;		
+		   of playground for now. -AK */
+		*begin = 0x40000000;
+		*end = 0x80000000;
 		if (current->flags & PF_RANDOMIZE) {
 			new_begin = randomize_range(*begin, *begin + 0x02000000, 0);
 			if (new_begin)
@@ -66,9 +68,9 @@
 		}
 	} else {
 		*begin = TASK_UNMAPPED_BASE;
-		*end = TASK_SIZE; 
+		*end = TASK_SIZE;
 	}
-} 
+}
 
 unsigned long
 arch_get_unmapped_area(struct file *filp, unsigned long addr,
@@ -78,11 +80,11 @@
 	struct vm_area_struct *vma;
 	unsigned long start_addr;
 	unsigned long begin, end;
-	
+
 	if (flags & MAP_FIXED)
 		return addr;
 
-	find_start_end(flags, &begin, &end); 
+	find_start_end(flags, &begin, &end);
 
 	if (len > end)
 		return -ENOMEM;
@@ -96,12 +98,12 @@
 	}
 	if (((flags & MAP_32BIT) || test_thread_flag(TIF_IA32))
 	    && len <= mm->cached_hole_size) {
-	        mm->cached_hole_size = 0;
+		mm->cached_hole_size = 0;
 		mm->free_area_cache = begin;
 	}
 	addr = mm->free_area_cache;
-	if (addr < begin) 
-		addr = begin; 
+	if (addr < begin)
+		addr = begin;
 	start_addr = addr;
 
 full_search:
@@ -127,7 +129,7 @@
 			return addr;
 		}
 		if (addr + mm->cached_hole_size < vma->vm_start)
-		        mm->cached_hole_size = vma->vm_start - addr;
+			mm->cached_hole_size = vma->vm_start - addr;
 
 		addr = vma->vm_end;
 	}
@@ -177,7 +179,7 @@
 		vma = find_vma(mm, addr-len);
 		if (!vma || addr <= vma->vm_start)
 			/* remember the address as a hint for next time */
-			return (mm->free_area_cache = addr-len);
+			return mm->free_area_cache = addr-len;
 	}
 
 	if (mm->mmap_base < len)
@@ -194,7 +196,7 @@
 		vma = find_vma(mm, addr);
 		if (!vma || addr+len <= vma->vm_start)
 			/* remember the address as a hint for next time */
-			return (mm->free_area_cache = addr);
+			return mm->free_area_cache = addr;
 
 		/* remember the largest hole we saw so far */
 		if (addr + mm->cached_hole_size < vma->vm_start)
@@ -224,13 +226,13 @@
 }
 
 
-asmlinkage long sys_uname(struct new_utsname __user * name)
+asmlinkage long sys_uname(struct new_utsname __user *name)
 {
 	int err;
 	down_read(&uts_sem);
-	err = copy_to_user(name, utsname(), sizeof (*name));
+	err = copy_to_user(name, utsname(), sizeof(*name));
 	up_read(&uts_sem);
-	if (personality(current->personality) == PER_LINUX32) 
-		err |= copy_to_user(&name->machine, "i686", 5); 		
+	if (personality(current->personality) == PER_LINUX32)
+		err |= copy_to_user(&name->machine, "i686", 5);
 	return err ? -EFAULT : 0;
 }
diff --git a/arch/x86/kernel/syscall_64.c b/arch/x86/kernel/syscall_64.c
index 170d43c..3d1be4f 100644
--- a/arch/x86/kernel/syscall_64.c
+++ b/arch/x86/kernel/syscall_64.c
@@ -8,12 +8,12 @@
 #define __NO_STUBS
 
 #define __SYSCALL(nr, sym) extern asmlinkage void sym(void) ;
-#undef _ASM_X86_64_UNISTD_H_
+#undef ASM_X86__UNISTD_64_H
 #include <asm/unistd_64.h>
 
 #undef __SYSCALL
 #define __SYSCALL(nr, sym) [nr] = sym,
-#undef _ASM_X86_64_UNISTD_H_
+#undef ASM_X86__UNISTD_64_H
 
 typedef void (*sys_call_ptr_t)(void);
 
diff --git a/arch/x86/kernel/time_32.c b/arch/x86/kernel/time_32.c
index ffe3c66..77b400f 100644
--- a/arch/x86/kernel/time_32.c
+++ b/arch/x86/kernel/time_32.c
@@ -36,6 +36,7 @@
 #include <asm/arch_hooks.h>
 #include <asm/hpet.h>
 #include <asm/time.h>
+#include <asm/timer.h>
 
 #include "do_timer.h"
 
@@ -46,10 +47,9 @@
 	unsigned long pc = instruction_pointer(regs);
 
 #ifdef CONFIG_SMP
-	if (!v8086_mode(regs) && SEGMENT_IS_KERNEL_CODE(regs->cs) &&
-	    in_lock_functions(pc)) {
+	if (!user_mode_vm(regs) && in_lock_functions(pc)) {
 #ifdef CONFIG_FRAME_POINTER
-		return *(unsigned long *)(regs->bp + 4);
+		return *(unsigned long *)(regs->bp + sizeof(long));
 #else
 		unsigned long *sp = (unsigned long *)&regs->sp;
 
@@ -94,6 +94,7 @@
 
 	do_timer_interrupt_hook();
 
+#ifdef CONFIG_MCA
 	if (MCA_bus) {
 		/* The PS/2 uses level-triggered interrupts.  You can't
 		turn them off, nor would you want to (any attempt to
@@ -107,6 +108,7 @@
 		u8 irq_v = inb_p( 0x61 );	/* read the current state */
 		outb_p( irq_v|0x80, 0x61 );	/* reset the IRQ */
 	}
+#endif
 
 	return IRQ_HANDLED;
 }
diff --git a/arch/x86/kernel/time_64.c b/arch/x86/kernel/time_64.c
index e3d49c5..cb19d65 100644
--- a/arch/x86/kernel/time_64.c
+++ b/arch/x86/kernel/time_64.c
@@ -16,6 +16,7 @@
 #include <linux/interrupt.h>
 #include <linux/module.h>
 #include <linux/time.h>
+#include <linux/mca.h>
 
 #include <asm/i8253.h>
 #include <asm/hpet.h>
@@ -33,23 +34,34 @@
 	/* Assume the lock function has either no stack frame or a copy
 	   of flags from PUSHF
 	   Eflags always has bits 22 and up cleared unlike kernel addresses. */
-	if (!user_mode(regs) && in_lock_functions(pc)) {
+	if (!user_mode_vm(regs) && in_lock_functions(pc)) {
+#ifdef CONFIG_FRAME_POINTER
+		return *(unsigned long *)(regs->bp + sizeof(long));
+#else
 		unsigned long *sp = (unsigned long *)regs->sp;
 		if (sp[0] >> 22)
 			return sp[0];
 		if (sp[1] >> 22)
 			return sp[1];
+#endif
 	}
 	return pc;
 }
 EXPORT_SYMBOL(profile_pc);
 
-static irqreturn_t timer_event_interrupt(int irq, void *dev_id)
+irqreturn_t timer_interrupt(int irq, void *dev_id)
 {
 	add_pda(irq0_irqs, 1);
 
 	global_clock_event->event_handler(global_clock_event);
 
+#ifdef CONFIG_MCA
+	if (MCA_bus) {
+		u8 irq_v = inb_p(0x61);       /* read the current state */
+		outb_p(irq_v|0x80, 0x61);     /* reset the IRQ */
+	}
+#endif
+
 	return IRQ_HANDLED;
 }
 
@@ -100,7 +112,7 @@
 }
 
 static struct irqaction irq0 = {
-	.handler	= timer_event_interrupt,
+	.handler	= timer_interrupt,
 	.flags		= IRQF_DISABLED | IRQF_IRQPOLL | IRQF_NOBALANCING,
 	.mask		= CPU_MASK_NONE,
 	.name		= "timer"
@@ -111,16 +123,13 @@
 	if (!hpet_enable())
 		setup_pit_timer();
 
+	irq0.mask = cpumask_of_cpu(0);
 	setup_irq(0, &irq0);
 }
 
 void __init time_init(void)
 {
 	tsc_init();
-	if (cpu_has(&boot_cpu_data, X86_FEATURE_RDTSCP))
-		vgetcpu_mode = VGETCPU_RDTSCP;
-	else
-		vgetcpu_mode = VGETCPU_LSL;
 
 	late_time_init = choose_time_init();
 }
diff --git a/arch/x86/kernel/tlb_32.c b/arch/x86/kernel/tlb_32.c
index fec1ece..e00534b 100644
--- a/arch/x86/kernel/tlb_32.c
+++ b/arch/x86/kernel/tlb_32.c
@@ -241,3 +241,11 @@
 	on_each_cpu(do_flush_tlb_all, NULL, 1);
 }
 
+void reset_lazy_tlbstate(void)
+{
+	int cpu = raw_smp_processor_id();
+
+	per_cpu(cpu_tlbstate, cpu).state = 0;
+	per_cpu(cpu_tlbstate, cpu).active_mm = &init_mm;
+}
+
diff --git a/arch/x86/kernel/tls.c b/arch/x86/kernel/tls.c
index ab6bf37..6bb7b85 100644
--- a/arch/x86/kernel/tls.c
+++ b/arch/x86/kernel/tls.c
@@ -10,6 +10,7 @@
 #include <asm/ldt.h>
 #include <asm/processor.h>
 #include <asm/proto.h>
+#include <asm/syscalls.h>
 
 #include "tls.h"
 
diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c
new file mode 100644
index 0000000..e062974
--- /dev/null
+++ b/arch/x86/kernel/traps.c
@@ -0,0 +1,1034 @@
+/*
+ *  Copyright (C) 1991, 1992  Linus Torvalds
+ *  Copyright (C) 2000, 2001, 2002 Andi Kleen, SuSE Labs
+ *
+ *  Pentium III FXSR, SSE support
+ *	Gareth Hughes <gareth@valinux.com>, May 2000
+ */
+
+/*
+ * Handle hardware traps and faults.
+ */
+#include <linux/interrupt.h>
+#include <linux/kallsyms.h>
+#include <linux/spinlock.h>
+#include <linux/kprobes.h>
+#include <linux/uaccess.h>
+#include <linux/utsname.h>
+#include <linux/kdebug.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/ptrace.h>
+#include <linux/string.h>
+#include <linux/unwind.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/kexec.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/init.h>
+#include <linux/bug.h>
+#include <linux/nmi.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/io.h>
+
+#ifdef CONFIG_EISA
+#include <linux/ioport.h>
+#include <linux/eisa.h>
+#endif
+
+#ifdef CONFIG_MCA
+#include <linux/mca.h>
+#endif
+
+#if defined(CONFIG_EDAC)
+#include <linux/edac.h>
+#endif
+
+#include <asm/stacktrace.h>
+#include <asm/processor.h>
+#include <asm/debugreg.h>
+#include <asm/atomic.h>
+#include <asm/system.h>
+#include <asm/unwind.h>
+#include <asm/traps.h>
+#include <asm/desc.h>
+#include <asm/i387.h>
+
+#include <mach_traps.h>
+
+#ifdef CONFIG_X86_64
+#include <asm/pgalloc.h>
+#include <asm/proto.h>
+#include <asm/pda.h>
+#else
+#include <asm/processor-flags.h>
+#include <asm/arch_hooks.h>
+#include <asm/nmi.h>
+#include <asm/smp.h>
+#include <asm/io.h>
+#include <asm/traps.h>
+
+#include "cpu/mcheck/mce.h"
+
+DECLARE_BITMAP(used_vectors, NR_VECTORS);
+EXPORT_SYMBOL_GPL(used_vectors);
+
+asmlinkage int system_call(void);
+
+/* Do we ignore FPU interrupts ? */
+char ignore_fpu_irq;
+
+/*
+ * The IDT has to be page-aligned to simplify the Pentium
+ * F0 0F bug workaround.. We have a special link segment
+ * for this.
+ */
+gate_desc idt_table[256]
+	__attribute__((__section__(".data.idt"))) = { { { { 0, 0 } } }, };
+#endif
+
+static int ignore_nmis;
+
+static inline void conditional_sti(struct pt_regs *regs)
+{
+	if (regs->flags & X86_EFLAGS_IF)
+		local_irq_enable();
+}
+
+static inline void preempt_conditional_sti(struct pt_regs *regs)
+{
+	inc_preempt_count();
+	if (regs->flags & X86_EFLAGS_IF)
+		local_irq_enable();
+}
+
+static inline void preempt_conditional_cli(struct pt_regs *regs)
+{
+	if (regs->flags & X86_EFLAGS_IF)
+		local_irq_disable();
+	dec_preempt_count();
+}
+
+#ifdef CONFIG_X86_32
+static inline void
+die_if_kernel(const char *str, struct pt_regs *regs, long err)
+{
+	if (!user_mode_vm(regs))
+		die(str, regs, err);
+}
+
+/*
+ * Perform the lazy TSS's I/O bitmap copy. If the TSS has an
+ * invalid offset set (the LAZY one) and the faulting thread has
+ * a valid I/O bitmap pointer, we copy the I/O bitmap in the TSS,
+ * we set the offset field correctly and return 1.
+ */
+static int lazy_iobitmap_copy(void)
+{
+	struct thread_struct *thread;
+	struct tss_struct *tss;
+	int cpu;
+
+	cpu = get_cpu();
+	tss = &per_cpu(init_tss, cpu);
+	thread = &current->thread;
+
+	if (tss->x86_tss.io_bitmap_base == INVALID_IO_BITMAP_OFFSET_LAZY &&
+	    thread->io_bitmap_ptr) {
+		memcpy(tss->io_bitmap, thread->io_bitmap_ptr,
+		       thread->io_bitmap_max);
+		/*
+		 * If the previously set map was extending to higher ports
+		 * than the current one, pad extra space with 0xff (no access).
+		 */
+		if (thread->io_bitmap_max < tss->io_bitmap_max) {
+			memset((char *) tss->io_bitmap +
+				thread->io_bitmap_max, 0xff,
+				tss->io_bitmap_max - thread->io_bitmap_max);
+		}
+		tss->io_bitmap_max = thread->io_bitmap_max;
+		tss->x86_tss.io_bitmap_base = IO_BITMAP_OFFSET;
+		tss->io_bitmap_owner = thread;
+		put_cpu();
+
+		return 1;
+	}
+	put_cpu();
+
+	return 0;
+}
+#endif
+
+static void __kprobes
+do_trap(int trapnr, int signr, char *str, struct pt_regs *regs,
+	long error_code, siginfo_t *info)
+{
+	struct task_struct *tsk = current;
+
+#ifdef CONFIG_X86_32
+	if (regs->flags & X86_VM_MASK) {
+		/*
+		 * traps 0, 1, 3, 4, and 5 should be forwarded to vm86.
+		 * On nmi (interrupt 2), do_trap should not be called.
+		 */
+		if (trapnr < 6)
+			goto vm86_trap;
+		goto trap_signal;
+	}
+#endif
+
+	if (!user_mode(regs))
+		goto kernel_trap;
+
+#ifdef CONFIG_X86_32
+trap_signal:
+#endif
+	/*
+	 * We want error_code and trap_no set for userspace faults and
+	 * kernelspace faults which result in die(), but not
+	 * kernelspace faults which are fixed up.  die() gives the
+	 * process no chance to handle the signal and notice the
+	 * kernel fault information, so that won't result in polluting
+	 * the information about previously queued, but not yet
+	 * delivered, faults.  See also do_general_protection below.
+	 */
+	tsk->thread.error_code = error_code;
+	tsk->thread.trap_no = trapnr;
+
+#ifdef CONFIG_X86_64
+	if (show_unhandled_signals && unhandled_signal(tsk, signr) &&
+	    printk_ratelimit()) {
+		printk(KERN_INFO
+		       "%s[%d] trap %s ip:%lx sp:%lx error:%lx",
+		       tsk->comm, tsk->pid, str,
+		       regs->ip, regs->sp, error_code);
+		print_vma_addr(" in ", regs->ip);
+		printk("\n");
+	}
+#endif
+
+	if (info)
+		force_sig_info(signr, info, tsk);
+	else
+		force_sig(signr, tsk);
+	return;
+
+kernel_trap:
+	if (!fixup_exception(regs)) {
+		tsk->thread.error_code = error_code;
+		tsk->thread.trap_no = trapnr;
+		die(str, regs, error_code);
+	}
+	return;
+
+#ifdef CONFIG_X86_32
+vm86_trap:
+	if (handle_vm86_trap((struct kernel_vm86_regs *) regs,
+						error_code, trapnr))
+		goto trap_signal;
+	return;
+#endif
+}
+
+#define DO_ERROR(trapnr, signr, str, name)				\
+dotraplinkage void do_##name(struct pt_regs *regs, long error_code)	\
+{									\
+	if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr)	\
+							== NOTIFY_STOP)	\
+		return;							\
+	conditional_sti(regs);						\
+	do_trap(trapnr, signr, str, regs, error_code, NULL);		\
+}
+
+#define DO_ERROR_INFO(trapnr, signr, str, name, sicode, siaddr)		\
+dotraplinkage void do_##name(struct pt_regs *regs, long error_code)	\
+{									\
+	siginfo_t info;							\
+	info.si_signo = signr;						\
+	info.si_errno = 0;						\
+	info.si_code = sicode;						\
+	info.si_addr = (void __user *)siaddr;				\
+	if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr)	\
+							== NOTIFY_STOP)	\
+		return;							\
+	conditional_sti(regs);						\
+	do_trap(trapnr, signr, str, regs, error_code, &info);		\
+}
+
+DO_ERROR_INFO(0, SIGFPE, "divide error", divide_error, FPE_INTDIV, regs->ip)
+DO_ERROR(4, SIGSEGV, "overflow", overflow)
+DO_ERROR(5, SIGSEGV, "bounds", bounds)
+DO_ERROR_INFO(6, SIGILL, "invalid opcode", invalid_op, ILL_ILLOPN, regs->ip)
+DO_ERROR(9, SIGFPE, "coprocessor segment overrun", coprocessor_segment_overrun)
+DO_ERROR(10, SIGSEGV, "invalid TSS", invalid_TSS)
+DO_ERROR(11, SIGBUS, "segment not present", segment_not_present)
+#ifdef CONFIG_X86_32
+DO_ERROR(12, SIGBUS, "stack segment", stack_segment)
+#endif
+DO_ERROR_INFO(17, SIGBUS, "alignment check", alignment_check, BUS_ADRALN, 0)
+
+#ifdef CONFIG_X86_64
+/* Runs on IST stack */
+dotraplinkage void do_stack_segment(struct pt_regs *regs, long error_code)
+{
+	if (notify_die(DIE_TRAP, "stack segment", regs, error_code,
+			12, SIGBUS) == NOTIFY_STOP)
+		return;
+	preempt_conditional_sti(regs);
+	do_trap(12, SIGBUS, "stack segment", regs, error_code, NULL);
+	preempt_conditional_cli(regs);
+}
+
+dotraplinkage void do_double_fault(struct pt_regs *regs, long error_code)
+{
+	static const char str[] = "double fault";
+	struct task_struct *tsk = current;
+
+	/* Return not checked because double check cannot be ignored */
+	notify_die(DIE_TRAP, str, regs, error_code, 8, SIGSEGV);
+
+	tsk->thread.error_code = error_code;
+	tsk->thread.trap_no = 8;
+
+	/* This is always a kernel trap and never fixable (and thus must
+	   never return). */
+	for (;;)
+		die(str, regs, error_code);
+}
+#endif
+
+dotraplinkage void __kprobes
+do_general_protection(struct pt_regs *regs, long error_code)
+{
+	struct task_struct *tsk;
+
+	conditional_sti(regs);
+
+#ifdef CONFIG_X86_32
+	if (lazy_iobitmap_copy()) {
+		/* restart the faulting instruction */
+		return;
+	}
+
+	if (regs->flags & X86_VM_MASK)
+		goto gp_in_vm86;
+#endif
+
+	tsk = current;
+	if (!user_mode(regs))
+		goto gp_in_kernel;
+
+	tsk->thread.error_code = error_code;
+	tsk->thread.trap_no = 13;
+
+	if (show_unhandled_signals && unhandled_signal(tsk, SIGSEGV) &&
+			printk_ratelimit()) {
+		printk(KERN_INFO
+			"%s[%d] general protection ip:%lx sp:%lx error:%lx",
+			tsk->comm, task_pid_nr(tsk),
+			regs->ip, regs->sp, error_code);
+		print_vma_addr(" in ", regs->ip);
+		printk("\n");
+	}
+
+	force_sig(SIGSEGV, tsk);
+	return;
+
+#ifdef CONFIG_X86_32
+gp_in_vm86:
+	local_irq_enable();
+	handle_vm86_fault((struct kernel_vm86_regs *) regs, error_code);
+	return;
+#endif
+
+gp_in_kernel:
+	if (fixup_exception(regs))
+		return;
+
+	tsk->thread.error_code = error_code;
+	tsk->thread.trap_no = 13;
+	if (notify_die(DIE_GPF, "general protection fault", regs,
+				error_code, 13, SIGSEGV) == NOTIFY_STOP)
+		return;
+	die("general protection fault", regs, error_code);
+}
+
+static notrace __kprobes void
+mem_parity_error(unsigned char reason, struct pt_regs *regs)
+{
+	printk(KERN_EMERG
+		"Uhhuh. NMI received for unknown reason %02x on CPU %d.\n",
+			reason, smp_processor_id());
+
+	printk(KERN_EMERG
+		"You have some hardware problem, likely on the PCI bus.\n");
+
+#if defined(CONFIG_EDAC)
+	if (edac_handler_set()) {
+		edac_atomic_assert_error();
+		return;
+	}
+#endif
+
+	if (panic_on_unrecovered_nmi)
+		panic("NMI: Not continuing");
+
+	printk(KERN_EMERG "Dazed and confused, but trying to continue\n");
+
+	/* Clear and disable the memory parity error line. */
+	reason = (reason & 0xf) | 4;
+	outb(reason, 0x61);
+}
+
+static notrace __kprobes void
+io_check_error(unsigned char reason, struct pt_regs *regs)
+{
+	unsigned long i;
+
+	printk(KERN_EMERG "NMI: IOCK error (debug interrupt?)\n");
+	show_registers(regs);
+
+	/* Re-enable the IOCK line, wait for a few seconds */
+	reason = (reason & 0xf) | 8;
+	outb(reason, 0x61);
+
+	i = 2000;
+	while (--i)
+		udelay(1000);
+
+	reason &= ~8;
+	outb(reason, 0x61);
+}
+
+static notrace __kprobes void
+unknown_nmi_error(unsigned char reason, struct pt_regs *regs)
+{
+	if (notify_die(DIE_NMIUNKNOWN, "nmi", regs, reason, 2, SIGINT) ==
+			NOTIFY_STOP)
+		return;
+#ifdef CONFIG_MCA
+	/*
+	 * Might actually be able to figure out what the guilty party
+	 * is:
+	 */
+	if (MCA_bus) {
+		mca_handle_nmi();
+		return;
+	}
+#endif
+	printk(KERN_EMERG
+		"Uhhuh. NMI received for unknown reason %02x on CPU %d.\n",
+			reason, smp_processor_id());
+
+	printk(KERN_EMERG "Do you have a strange power saving mode enabled?\n");
+	if (panic_on_unrecovered_nmi)
+		panic("NMI: Not continuing");
+
+	printk(KERN_EMERG "Dazed and confused, but trying to continue\n");
+}
+
+static notrace __kprobes void default_do_nmi(struct pt_regs *regs)
+{
+	unsigned char reason = 0;
+	int cpu;
+
+	cpu = smp_processor_id();
+
+	/* Only the BSP gets external NMIs from the system. */
+	if (!cpu)
+		reason = get_nmi_reason();
+
+	if (!(reason & 0xc0)) {
+		if (notify_die(DIE_NMI_IPI, "nmi_ipi", regs, reason, 2, SIGINT)
+								== NOTIFY_STOP)
+			return;
+#ifdef CONFIG_X86_LOCAL_APIC
+		/*
+		 * Ok, so this is none of the documented NMI sources,
+		 * so it must be the NMI watchdog.
+		 */
+		if (nmi_watchdog_tick(regs, reason))
+			return;
+		if (!do_nmi_callback(regs, cpu))
+			unknown_nmi_error(reason, regs);
+#else
+		unknown_nmi_error(reason, regs);
+#endif
+
+		return;
+	}
+	if (notify_die(DIE_NMI, "nmi", regs, reason, 2, SIGINT) == NOTIFY_STOP)
+		return;
+
+	/* AK: following checks seem to be broken on modern chipsets. FIXME */
+	if (reason & 0x80)
+		mem_parity_error(reason, regs);
+	if (reason & 0x40)
+		io_check_error(reason, regs);
+#ifdef CONFIG_X86_32
+	/*
+	 * Reassert NMI in case it became active meanwhile
+	 * as it's edge-triggered:
+	 */
+	reassert_nmi();
+#endif
+}
+
+dotraplinkage notrace __kprobes void
+do_nmi(struct pt_regs *regs, long error_code)
+{
+	nmi_enter();
+
+#ifdef CONFIG_X86_32
+	{ int cpu; cpu = smp_processor_id(); ++nmi_count(cpu); }
+#else
+	add_pda(__nmi_count, 1);
+#endif
+
+	if (!ignore_nmis)
+		default_do_nmi(regs);
+
+	nmi_exit();
+}
+
+void stop_nmi(void)
+{
+	acpi_nmi_disable();
+	ignore_nmis++;
+}
+
+void restart_nmi(void)
+{
+	ignore_nmis--;
+	acpi_nmi_enable();
+}
+
+/* May run on IST stack. */
+dotraplinkage void __kprobes do_int3(struct pt_regs *regs, long error_code)
+{
+#ifdef CONFIG_KPROBES
+	if (notify_die(DIE_INT3, "int3", regs, error_code, 3, SIGTRAP)
+			== NOTIFY_STOP)
+		return;
+#else
+	if (notify_die(DIE_TRAP, "int3", regs, error_code, 3, SIGTRAP)
+			== NOTIFY_STOP)
+		return;
+#endif
+
+	preempt_conditional_sti(regs);
+	do_trap(3, SIGTRAP, "int3", regs, error_code, NULL);
+	preempt_conditional_cli(regs);
+}
+
+#ifdef CONFIG_X86_64
+/* Help handler running on IST stack to switch back to user stack
+   for scheduling or signal handling. The actual stack switch is done in
+   entry.S */
+asmlinkage __kprobes struct pt_regs *sync_regs(struct pt_regs *eregs)
+{
+	struct pt_regs *regs = eregs;
+	/* Did already sync */
+	if (eregs == (struct pt_regs *)eregs->sp)
+		;
+	/* Exception from user space */
+	else if (user_mode(eregs))
+		regs = task_pt_regs(current);
+	/* Exception from kernel and interrupts are enabled. Move to
+	   kernel process stack. */
+	else if (eregs->flags & X86_EFLAGS_IF)
+		regs = (struct pt_regs *)(eregs->sp -= sizeof(struct pt_regs));
+	if (eregs != regs)
+		*regs = *eregs;
+	return regs;
+}
+#endif
+
+/*
+ * Our handling of the processor debug registers is non-trivial.
+ * We do not clear them on entry and exit from the kernel. Therefore
+ * it is possible to get a watchpoint trap here from inside the kernel.
+ * However, the code in ./ptrace.c has ensured that the user can
+ * only set watchpoints on userspace addresses. Therefore the in-kernel
+ * watchpoint trap can only occur in code which is reading/writing
+ * from user space. Such code must not hold kernel locks (since it
+ * can equally take a page fault), therefore it is safe to call
+ * force_sig_info even though that claims and releases locks.
+ *
+ * Code in ./signal.c ensures that the debug control register
+ * is restored before we deliver any signal, and therefore that
+ * user code runs with the correct debug control register even though
+ * we clear it here.
+ *
+ * Being careful here means that we don't have to be as careful in a
+ * lot of more complicated places (task switching can be a bit lazy
+ * about restoring all the debug state, and ptrace doesn't have to
+ * find every occurrence of the TF bit that could be saved away even
+ * by user code)
+ *
+ * May run on IST stack.
+ */
+dotraplinkage void __kprobes do_debug(struct pt_regs *regs, long error_code)
+{
+	struct task_struct *tsk = current;
+	unsigned long condition;
+	int si_code;
+
+	get_debugreg(condition, 6);
+
+	/*
+	 * The processor cleared BTF, so don't mark that we need it set.
+	 */
+	clear_tsk_thread_flag(tsk, TIF_DEBUGCTLMSR);
+	tsk->thread.debugctlmsr = 0;
+
+	if (notify_die(DIE_DEBUG, "debug", regs, condition, error_code,
+						SIGTRAP) == NOTIFY_STOP)
+		return;
+
+	/* It's safe to allow irq's after DR6 has been saved */
+	preempt_conditional_sti(regs);
+
+	/* Mask out spurious debug traps due to lazy DR7 setting */
+	if (condition & (DR_TRAP0|DR_TRAP1|DR_TRAP2|DR_TRAP3)) {
+		if (!tsk->thread.debugreg7)
+			goto clear_dr7;
+	}
+
+#ifdef CONFIG_X86_32
+	if (regs->flags & X86_VM_MASK)
+		goto debug_vm86;
+#endif
+
+	/* Save debug status register where ptrace can see it */
+	tsk->thread.debugreg6 = condition;
+
+	/*
+	 * Single-stepping through TF: make sure we ignore any events in
+	 * kernel space (but re-enable TF when returning to user mode).
+	 */
+	if (condition & DR_STEP) {
+		if (!user_mode(regs))
+			goto clear_TF_reenable;
+	}
+
+	si_code = get_si_code(condition);
+	/* Ok, finally something we can handle */
+	send_sigtrap(tsk, regs, error_code, si_code);
+
+	/*
+	 * Disable additional traps. They'll be re-enabled when
+	 * the signal is delivered.
+	 */
+clear_dr7:
+	set_debugreg(0, 7);
+	preempt_conditional_cli(regs);
+	return;
+
+#ifdef CONFIG_X86_32
+debug_vm86:
+	handle_vm86_trap((struct kernel_vm86_regs *) regs, error_code, 1);
+	preempt_conditional_cli(regs);
+	return;
+#endif
+
+clear_TF_reenable:
+	set_tsk_thread_flag(tsk, TIF_SINGLESTEP);
+	regs->flags &= ~X86_EFLAGS_TF;
+	preempt_conditional_cli(regs);
+	return;
+}
+
+#ifdef CONFIG_X86_64
+static int kernel_math_error(struct pt_regs *regs, const char *str, int trapnr)
+{
+	if (fixup_exception(regs))
+		return 1;
+
+	notify_die(DIE_GPF, str, regs, 0, trapnr, SIGFPE);
+	/* Illegal floating point operation in the kernel */
+	current->thread.trap_no = trapnr;
+	die(str, regs, 0);
+	return 0;
+}
+#endif
+
+/*
+ * Note that we play around with the 'TS' bit in an attempt to get
+ * the correct behaviour even in the presence of the asynchronous
+ * IRQ13 behaviour
+ */
+void math_error(void __user *ip)
+{
+	struct task_struct *task;
+	siginfo_t info;
+	unsigned short cwd, swd;
+
+	/*
+	 * Save the info for the exception handler and clear the error.
+	 */
+	task = current;
+	save_init_fpu(task);
+	task->thread.trap_no = 16;
+	task->thread.error_code = 0;
+	info.si_signo = SIGFPE;
+	info.si_errno = 0;
+	info.si_code = __SI_FAULT;
+	info.si_addr = ip;
+	/*
+	 * (~cwd & swd) will mask out exceptions that are not set to unmasked
+	 * status.  0x3f is the exception bits in these regs, 0x200 is the
+	 * C1 reg you need in case of a stack fault, 0x040 is the stack
+	 * fault bit.  We should only be taking one exception at a time,
+	 * so if this combination doesn't produce any single exception,
+	 * then we have a bad program that isn't synchronizing its FPU usage
+	 * and it will suffer the consequences since we won't be able to
+	 * fully reproduce the context of the exception
+	 */
+	cwd = get_fpu_cwd(task);
+	swd = get_fpu_swd(task);
+	switch (swd & ~cwd & 0x3f) {
+	case 0x000: /* No unmasked exception */
+#ifdef CONFIG_X86_32
+		return;
+#endif
+	default: /* Multiple exceptions */
+		break;
+	case 0x001: /* Invalid Op */
+		/*
+		 * swd & 0x240 == 0x040: Stack Underflow
+		 * swd & 0x240 == 0x240: Stack Overflow
+		 * User must clear the SF bit (0x40) if set
+		 */
+		info.si_code = FPE_FLTINV;
+		break;
+	case 0x002: /* Denormalize */
+	case 0x010: /* Underflow */
+		info.si_code = FPE_FLTUND;
+		break;
+	case 0x004: /* Zero Divide */
+		info.si_code = FPE_FLTDIV;
+		break;
+	case 0x008: /* Overflow */
+		info.si_code = FPE_FLTOVF;
+		break;
+	case 0x020: /* Precision */
+		info.si_code = FPE_FLTRES;
+		break;
+	}
+	force_sig_info(SIGFPE, &info, task);
+}
+
+dotraplinkage void do_coprocessor_error(struct pt_regs *regs, long error_code)
+{
+	conditional_sti(regs);
+
+#ifdef CONFIG_X86_32
+	ignore_fpu_irq = 1;
+#else
+	if (!user_mode(regs) &&
+	    kernel_math_error(regs, "kernel x87 math error", 16))
+		return;
+#endif
+
+	math_error((void __user *)regs->ip);
+}
+
+static void simd_math_error(void __user *ip)
+{
+	struct task_struct *task;
+	siginfo_t info;
+	unsigned short mxcsr;
+
+	/*
+	 * Save the info for the exception handler and clear the error.
+	 */
+	task = current;
+	save_init_fpu(task);
+	task->thread.trap_no = 19;
+	task->thread.error_code = 0;
+	info.si_signo = SIGFPE;
+	info.si_errno = 0;
+	info.si_code = __SI_FAULT;
+	info.si_addr = ip;
+	/*
+	 * The SIMD FPU exceptions are handled a little differently, as there
+	 * is only a single status/control register.  Thus, to determine which
+	 * unmasked exception was caught we must mask the exception mask bits
+	 * at 0x1f80, and then use these to mask the exception bits at 0x3f.
+	 */
+	mxcsr = get_fpu_mxcsr(task);
+	switch (~((mxcsr & 0x1f80) >> 7) & (mxcsr & 0x3f)) {
+	case 0x000:
+	default:
+		break;
+	case 0x001: /* Invalid Op */
+		info.si_code = FPE_FLTINV;
+		break;
+	case 0x002: /* Denormalize */
+	case 0x010: /* Underflow */
+		info.si_code = FPE_FLTUND;
+		break;
+	case 0x004: /* Zero Divide */
+		info.si_code = FPE_FLTDIV;
+		break;
+	case 0x008: /* Overflow */
+		info.si_code = FPE_FLTOVF;
+		break;
+	case 0x020: /* Precision */
+		info.si_code = FPE_FLTRES;
+		break;
+	}
+	force_sig_info(SIGFPE, &info, task);
+}
+
+dotraplinkage void
+do_simd_coprocessor_error(struct pt_regs *regs, long error_code)
+{
+	conditional_sti(regs);
+
+#ifdef CONFIG_X86_32
+	if (cpu_has_xmm) {
+		/* Handle SIMD FPU exceptions on PIII+ processors. */
+		ignore_fpu_irq = 1;
+		simd_math_error((void __user *)regs->ip);
+		return;
+	}
+	/*
+	 * Handle strange cache flush from user space exception
+	 * in all other cases.  This is undocumented behaviour.
+	 */
+	if (regs->flags & X86_VM_MASK) {
+		handle_vm86_fault((struct kernel_vm86_regs *)regs, error_code);
+		return;
+	}
+	current->thread.trap_no = 19;
+	current->thread.error_code = error_code;
+	die_if_kernel("cache flush denied", regs, error_code);
+	force_sig(SIGSEGV, current);
+#else
+	if (!user_mode(regs) &&
+			kernel_math_error(regs, "kernel simd math error", 19))
+		return;
+	simd_math_error((void __user *)regs->ip);
+#endif
+}
+
+dotraplinkage void
+do_spurious_interrupt_bug(struct pt_regs *regs, long error_code)
+{
+	conditional_sti(regs);
+#if 0
+	/* No need to warn about this any longer. */
+	printk(KERN_INFO "Ignoring P6 Local APIC Spurious Interrupt Bug...\n");
+#endif
+}
+
+#ifdef CONFIG_X86_32
+unsigned long patch_espfix_desc(unsigned long uesp, unsigned long kesp)
+{
+	struct desc_struct *gdt = get_cpu_gdt_table(smp_processor_id());
+	unsigned long base = (kesp - uesp) & -THREAD_SIZE;
+	unsigned long new_kesp = kesp - base;
+	unsigned long lim_pages = (new_kesp | (THREAD_SIZE - 1)) >> PAGE_SHIFT;
+	__u64 desc = *(__u64 *)&gdt[GDT_ENTRY_ESPFIX_SS];
+
+	/* Set up base for espfix segment */
+	desc &= 0x00f0ff0000000000ULL;
+	desc |=	((((__u64)base) << 16) & 0x000000ffffff0000ULL) |
+		((((__u64)base) << 32) & 0xff00000000000000ULL) |
+		((((__u64)lim_pages) << 32) & 0x000f000000000000ULL) |
+		(lim_pages & 0xffff);
+	*(__u64 *)&gdt[GDT_ENTRY_ESPFIX_SS] = desc;
+
+	return new_kesp;
+}
+#else
+asmlinkage void __attribute__((weak)) smp_thermal_interrupt(void)
+{
+}
+
+asmlinkage void __attribute__((weak)) mce_threshold_interrupt(void)
+{
+}
+#endif
+
+/*
+ * 'math_state_restore()' saves the current math information in the
+ * old math state array, and gets the new ones from the current task
+ *
+ * Careful.. There are problems with IBM-designed IRQ13 behaviour.
+ * Don't touch unless you *really* know how it works.
+ *
+ * Must be called with kernel preemption disabled (in this case,
+ * local interrupts are disabled at the call-site in entry.S).
+ */
+asmlinkage void math_state_restore(void)
+{
+	struct thread_info *thread = current_thread_info();
+	struct task_struct *tsk = thread->task;
+
+	if (!tsk_used_math(tsk)) {
+		local_irq_enable();
+		/*
+		 * does a slab alloc which can sleep
+		 */
+		if (init_fpu(tsk)) {
+			/*
+			 * ran out of memory!
+			 */
+			do_group_exit(SIGKILL);
+			return;
+		}
+		local_irq_disable();
+	}
+
+	clts();				/* Allow maths ops (or we recurse) */
+#ifdef CONFIG_X86_32
+	restore_fpu(tsk);
+#else
+	/*
+	 * Paranoid restore. send a SIGSEGV if we fail to restore the state.
+	 */
+	if (unlikely(restore_fpu_checking(tsk))) {
+		stts();
+		force_sig(SIGSEGV, tsk);
+		return;
+	}
+#endif
+	thread->status |= TS_USEDFPU;	/* So we fnsave on switch_to() */
+	tsk->fpu_counter++;
+}
+EXPORT_SYMBOL_GPL(math_state_restore);
+
+#ifndef CONFIG_MATH_EMULATION
+asmlinkage void math_emulate(long arg)
+{
+	printk(KERN_EMERG
+		"math-emulation not enabled and no coprocessor found.\n");
+	printk(KERN_EMERG "killing %s.\n", current->comm);
+	force_sig(SIGFPE, current);
+	schedule();
+}
+#endif /* CONFIG_MATH_EMULATION */
+
+dotraplinkage void __kprobes
+do_device_not_available(struct pt_regs *regs, long error)
+{
+#ifdef CONFIG_X86_32
+	if (read_cr0() & X86_CR0_EM) {
+		conditional_sti(regs);
+		math_emulate(0);
+	} else {
+		math_state_restore(); /* interrupts still off */
+		conditional_sti(regs);
+	}
+#else
+	math_state_restore();
+#endif
+}
+
+#ifdef CONFIG_X86_32
+#ifdef CONFIG_X86_MCE
+dotraplinkage void __kprobes do_machine_check(struct pt_regs *regs, long error)
+{
+	conditional_sti(regs);
+	machine_check_vector(regs, error);
+}
+#endif
+
+dotraplinkage void do_iret_error(struct pt_regs *regs, long error_code)
+{
+	siginfo_t info;
+	local_irq_enable();
+
+	info.si_signo = SIGILL;
+	info.si_errno = 0;
+	info.si_code = ILL_BADSTK;
+	info.si_addr = 0;
+	if (notify_die(DIE_TRAP, "iret exception",
+			regs, error_code, 32, SIGILL) == NOTIFY_STOP)
+		return;
+	do_trap(32, SIGILL, "iret exception", regs, error_code, &info);
+}
+#endif
+
+void __init trap_init(void)
+{
+#ifdef CONFIG_X86_32
+	int i;
+#endif
+
+#ifdef CONFIG_EISA
+	void __iomem *p = early_ioremap(0x0FFFD9, 4);
+
+	if (readl(p) == 'E' + ('I'<<8) + ('S'<<16) + ('A'<<24))
+		EISA_bus = 1;
+	early_iounmap(p, 4);
+#endif
+
+	set_intr_gate(0, &divide_error);
+	set_intr_gate_ist(1, &debug, DEBUG_STACK);
+	set_intr_gate_ist(2, &nmi, NMI_STACK);
+	/* int3 can be called from all */
+	set_system_intr_gate_ist(3, &int3, DEBUG_STACK);
+	/* int4 can be called from all */
+	set_system_intr_gate(4, &overflow);
+	set_intr_gate(5, &bounds);
+	set_intr_gate(6, &invalid_op);
+	set_intr_gate(7, &device_not_available);
+#ifdef CONFIG_X86_32
+	set_task_gate(8, GDT_ENTRY_DOUBLEFAULT_TSS);
+#else
+	set_intr_gate_ist(8, &double_fault, DOUBLEFAULT_STACK);
+#endif
+	set_intr_gate(9, &coprocessor_segment_overrun);
+	set_intr_gate(10, &invalid_TSS);
+	set_intr_gate(11, &segment_not_present);
+	set_intr_gate_ist(12, &stack_segment, STACKFAULT_STACK);
+	set_intr_gate(13, &general_protection);
+	set_intr_gate(14, &page_fault);
+	set_intr_gate(15, &spurious_interrupt_bug);
+	set_intr_gate(16, &coprocessor_error);
+	set_intr_gate(17, &alignment_check);
+#ifdef CONFIG_X86_MCE
+	set_intr_gate_ist(18, &machine_check, MCE_STACK);
+#endif
+	set_intr_gate(19, &simd_coprocessor_error);
+
+#ifdef CONFIG_IA32_EMULATION
+	set_system_intr_gate(IA32_SYSCALL_VECTOR, ia32_syscall);
+#endif
+
+#ifdef CONFIG_X86_32
+	if (cpu_has_fxsr) {
+		printk(KERN_INFO "Enabling fast FPU save and restore... ");
+		set_in_cr4(X86_CR4_OSFXSR);
+		printk("done.\n");
+	}
+	if (cpu_has_xmm) {
+		printk(KERN_INFO
+			"Enabling unmasked SIMD FPU exception support... ");
+		set_in_cr4(X86_CR4_OSXMMEXCPT);
+		printk("done.\n");
+	}
+
+	set_system_trap_gate(SYSCALL_VECTOR, &system_call);
+
+	/* Reserve all the builtin and the syscall vector: */
+	for (i = 0; i < FIRST_EXTERNAL_VECTOR; i++)
+		set_bit(i, used_vectors);
+
+	set_bit(SYSCALL_VECTOR, used_vectors);
+#endif
+	/*
+	 * Should be a barrier for any external CPU state:
+	 */
+	cpu_init();
+
+#ifdef CONFIG_X86_32
+	trap_init_hook();
+#endif
+}
diff --git a/arch/x86/kernel/traps_32.c b/arch/x86/kernel/traps_32.c
deleted file mode 100644
index 03df8e4..0000000
--- a/arch/x86/kernel/traps_32.c
+++ /dev/null
@@ -1,1256 +0,0 @@
-/*
- *  Copyright (C) 1991, 1992  Linus Torvalds
- *  Copyright (C) 2000, 2001, 2002 Andi Kleen, SuSE Labs
- *
- *  Pentium III FXSR, SSE support
- *	Gareth Hughes <gareth@valinux.com>, May 2000
- */
-
-/*
- * 'Traps.c' handles hardware traps and faults after we have saved some
- * state in 'asm.s'.
- */
-#include <linux/interrupt.h>
-#include <linux/kallsyms.h>
-#include <linux/spinlock.h>
-#include <linux/highmem.h>
-#include <linux/kprobes.h>
-#include <linux/uaccess.h>
-#include <linux/utsname.h>
-#include <linux/kdebug.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/ptrace.h>
-#include <linux/string.h>
-#include <linux/unwind.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/kexec.h>
-#include <linux/sched.h>
-#include <linux/timer.h>
-#include <linux/init.h>
-#include <linux/bug.h>
-#include <linux/nmi.h>
-#include <linux/mm.h>
-
-#ifdef CONFIG_EISA
-#include <linux/ioport.h>
-#include <linux/eisa.h>
-#endif
-
-#ifdef CONFIG_MCA
-#include <linux/mca.h>
-#endif
-
-#if defined(CONFIG_EDAC)
-#include <linux/edac.h>
-#endif
-
-#include <asm/arch_hooks.h>
-#include <asm/stacktrace.h>
-#include <asm/processor.h>
-#include <asm/debugreg.h>
-#include <asm/atomic.h>
-#include <asm/system.h>
-#include <asm/unwind.h>
-#include <asm/desc.h>
-#include <asm/i387.h>
-#include <asm/nmi.h>
-#include <asm/smp.h>
-#include <asm/io.h>
-#include <asm/traps.h>
-
-#include "mach_traps.h"
-
-DECLARE_BITMAP(used_vectors, NR_VECTORS);
-EXPORT_SYMBOL_GPL(used_vectors);
-
-asmlinkage int system_call(void);
-
-/* Do we ignore FPU interrupts ? */
-char ignore_fpu_irq;
-
-/*
- * The IDT has to be page-aligned to simplify the Pentium
- * F0 0F bug workaround.. We have a special link segment
- * for this.
- */
-gate_desc idt_table[256]
-	__attribute__((__section__(".data.idt"))) = { { { { 0, 0 } } }, };
-
-int panic_on_unrecovered_nmi;
-int kstack_depth_to_print = 24;
-static unsigned int code_bytes = 64;
-static int ignore_nmis;
-static int die_counter;
-
-void printk_address(unsigned long address, int reliable)
-{
-#ifdef CONFIG_KALLSYMS
-	unsigned long offset = 0;
-	unsigned long symsize;
-	const char *symname;
-	char *modname;
-	char *delim = ":";
-	char namebuf[KSYM_NAME_LEN];
-	char reliab[4] = "";
-
-	symname = kallsyms_lookup(address, &symsize, &offset,
-					&modname, namebuf);
-	if (!symname) {
-		printk(" [<%08lx>]\n", address);
-		return;
-	}
-	if (!reliable)
-		strcpy(reliab, "? ");
-
-	if (!modname)
-		modname = delim = "";
-	printk(" [<%08lx>] %s%s%s%s%s+0x%lx/0x%lx\n",
-		address, reliab, delim, modname, delim, symname, offset, symsize);
-#else
-	printk(" [<%08lx>]\n", address);
-#endif
-}
-
-static inline int valid_stack_ptr(struct thread_info *tinfo,
-			void *p, unsigned int size)
-{
-	void *t = tinfo;
-	return	p > t && p <= t + THREAD_SIZE - size;
-}
-
-/* The form of the top of the frame on the stack */
-struct stack_frame {
-	struct stack_frame *next_frame;
-	unsigned long return_address;
-};
-
-static inline unsigned long
-print_context_stack(struct thread_info *tinfo,
-		unsigned long *stack, unsigned long bp,
-		const struct stacktrace_ops *ops, void *data)
-{
-	struct stack_frame *frame = (struct stack_frame *)bp;
-
-	while (valid_stack_ptr(tinfo, stack, sizeof(*stack))) {
-		unsigned long addr;
-
-		addr = *stack;
-		if (__kernel_text_address(addr)) {
-			if ((unsigned long) stack == bp + 4) {
-				ops->address(data, addr, 1);
-				frame = frame->next_frame;
-				bp = (unsigned long) frame;
-			} else {
-				ops->address(data, addr, bp == 0);
-			}
-		}
-		stack++;
-	}
-	return bp;
-}
-
-void dump_trace(struct task_struct *task, struct pt_regs *regs,
-		unsigned long *stack, unsigned long bp,
-		const struct stacktrace_ops *ops, void *data)
-{
-	if (!task)
-		task = current;
-
-	if (!stack) {
-		unsigned long dummy;
-		stack = &dummy;
-		if (task != current)
-			stack = (unsigned long *)task->thread.sp;
-	}
-
-#ifdef CONFIG_FRAME_POINTER
-	if (!bp) {
-		if (task == current) {
-			/* Grab bp right from our regs */
-			asm("movl %%ebp, %0" : "=r" (bp) :);
-		} else {
-			/* bp is the last reg pushed by switch_to */
-			bp = *(unsigned long *) task->thread.sp;
-		}
-	}
-#endif
-
-	for (;;) {
-		struct thread_info *context;
-
-		context = (struct thread_info *)
-			((unsigned long)stack & (~(THREAD_SIZE - 1)));
-		bp = print_context_stack(context, stack, bp, ops, data);
-		/*
-		 * Should be after the line below, but somewhere
-		 * in early boot context comes out corrupted and we
-		 * can't reference it:
-		 */
-		if (ops->stack(data, "IRQ") < 0)
-			break;
-		stack = (unsigned long *)context->previous_esp;
-		if (!stack)
-			break;
-		touch_nmi_watchdog();
-	}
-}
-EXPORT_SYMBOL(dump_trace);
-
-static void
-print_trace_warning_symbol(void *data, char *msg, unsigned long symbol)
-{
-	printk(data);
-	print_symbol(msg, symbol);
-	printk("\n");
-}
-
-static void print_trace_warning(void *data, char *msg)
-{
-	printk("%s%s\n", (char *)data, msg);
-}
-
-static int print_trace_stack(void *data, char *name)
-{
-	return 0;
-}
-
-/*
- * Print one address/symbol entries per line.
- */
-static void print_trace_address(void *data, unsigned long addr, int reliable)
-{
-	printk("%s [<%08lx>] ", (char *)data, addr);
-	if (!reliable)
-		printk("? ");
-	print_symbol("%s\n", addr);
-	touch_nmi_watchdog();
-}
-
-static const struct stacktrace_ops print_trace_ops = {
-	.warning = print_trace_warning,
-	.warning_symbol = print_trace_warning_symbol,
-	.stack = print_trace_stack,
-	.address = print_trace_address,
-};
-
-static void
-show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs,
-		unsigned long *stack, unsigned long bp, char *log_lvl)
-{
-	dump_trace(task, regs, stack, bp, &print_trace_ops, log_lvl);
-	printk("%s =======================\n", log_lvl);
-}
-
-void show_trace(struct task_struct *task, struct pt_regs *regs,
-		unsigned long *stack, unsigned long bp)
-{
-	show_trace_log_lvl(task, regs, stack, bp, "");
-}
-
-static void
-show_stack_log_lvl(struct task_struct *task, struct pt_regs *regs,
-		   unsigned long *sp, unsigned long bp, char *log_lvl)
-{
-	unsigned long *stack;
-	int i;
-
-	if (sp == NULL) {
-		if (task)
-			sp = (unsigned long *)task->thread.sp;
-		else
-			sp = (unsigned long *)&sp;
-	}
-
-	stack = sp;
-	for (i = 0; i < kstack_depth_to_print; i++) {
-		if (kstack_end(stack))
-			break;
-		if (i && ((i % 8) == 0))
-			printk("\n%s       ", log_lvl);
-		printk("%08lx ", *stack++);
-	}
-	printk("\n%sCall Trace:\n", log_lvl);
-
-	show_trace_log_lvl(task, regs, sp, bp, log_lvl);
-}
-
-void show_stack(struct task_struct *task, unsigned long *sp)
-{
-	printk("       ");
-	show_stack_log_lvl(task, NULL, sp, 0, "");
-}
-
-/*
- * The architecture-independent dump_stack generator
- */
-void dump_stack(void)
-{
-	unsigned long bp = 0;
-	unsigned long stack;
-
-#ifdef CONFIG_FRAME_POINTER
-	if (!bp)
-		asm("movl %%ebp, %0" : "=r" (bp):);
-#endif
-
-	printk("Pid: %d, comm: %.20s %s %s %.*s\n",
-		current->pid, current->comm, print_tainted(),
-		init_utsname()->release,
-		(int)strcspn(init_utsname()->version, " "),
-		init_utsname()->version);
-
-	show_trace(current, NULL, &stack, bp);
-}
-
-EXPORT_SYMBOL(dump_stack);
-
-void show_registers(struct pt_regs *regs)
-{
-	int i;
-
-	print_modules();
-	__show_registers(regs, 0);
-
-	printk(KERN_EMERG "Process %.*s (pid: %d, ti=%p task=%p task.ti=%p)",
-		TASK_COMM_LEN, current->comm, task_pid_nr(current),
-		current_thread_info(), current, task_thread_info(current));
-	/*
-	 * When in-kernel, we also print out the stack and code at the
-	 * time of the fault..
-	 */
-	if (!user_mode_vm(regs)) {
-		unsigned int code_prologue = code_bytes * 43 / 64;
-		unsigned int code_len = code_bytes;
-		unsigned char c;
-		u8 *ip;
-
-		printk("\n" KERN_EMERG "Stack: ");
-		show_stack_log_lvl(NULL, regs, &regs->sp, 0, KERN_EMERG);
-
-		printk(KERN_EMERG "Code: ");
-
-		ip = (u8 *)regs->ip - code_prologue;
-		if (ip < (u8 *)PAGE_OFFSET || probe_kernel_address(ip, c)) {
-			/* try starting at EIP */
-			ip = (u8 *)regs->ip;
-			code_len = code_len - code_prologue + 1;
-		}
-		for (i = 0; i < code_len; i++, ip++) {
-			if (ip < (u8 *)PAGE_OFFSET ||
-					probe_kernel_address(ip, c)) {
-				printk(" Bad EIP value.");
-				break;
-			}
-			if (ip == (u8 *)regs->ip)
-				printk("<%02x> ", c);
-			else
-				printk("%02x ", c);
-		}
-	}
-	printk("\n");
-}
-
-int is_valid_bugaddr(unsigned long ip)
-{
-	unsigned short ud2;
-
-	if (ip < PAGE_OFFSET)
-		return 0;
-	if (probe_kernel_address((unsigned short *)ip, ud2))
-		return 0;
-
-	return ud2 == 0x0b0f;
-}
-
-static raw_spinlock_t die_lock = __RAW_SPIN_LOCK_UNLOCKED;
-static int die_owner = -1;
-static unsigned int die_nest_count;
-
-unsigned __kprobes long oops_begin(void)
-{
-	unsigned long flags;
-
-	oops_enter();
-
-	if (die_owner != raw_smp_processor_id()) {
-		console_verbose();
-		raw_local_irq_save(flags);
-		__raw_spin_lock(&die_lock);
-		die_owner = smp_processor_id();
-		die_nest_count = 0;
-		bust_spinlocks(1);
-	} else {
-		raw_local_irq_save(flags);
-	}
-	die_nest_count++;
-	return flags;
-}
-
-void __kprobes oops_end(unsigned long flags, struct pt_regs *regs, int signr)
-{
-	bust_spinlocks(0);
-	die_owner = -1;
-	add_taint(TAINT_DIE);
-	__raw_spin_unlock(&die_lock);
-	raw_local_irq_restore(flags);
-
-	if (!regs)
-		return;
-
-	if (kexec_should_crash(current))
-		crash_kexec(regs);
-
-	if (in_interrupt())
-		panic("Fatal exception in interrupt");
-
-	if (panic_on_oops)
-		panic("Fatal exception");
-
-	oops_exit();
-	do_exit(signr);
-}
-
-int __kprobes __die(const char *str, struct pt_regs *regs, long err)
-{
-	unsigned short ss;
-	unsigned long sp;
-
-	printk(KERN_EMERG "%s: %04lx [#%d] ", str, err & 0xffff, ++die_counter);
-#ifdef CONFIG_PREEMPT
-	printk("PREEMPT ");
-#endif
-#ifdef CONFIG_SMP
-	printk("SMP ");
-#endif
-#ifdef CONFIG_DEBUG_PAGEALLOC
-	printk("DEBUG_PAGEALLOC");
-#endif
-	printk("\n");
-	if (notify_die(DIE_OOPS, str, regs, err,
-			current->thread.trap_no, SIGSEGV) == NOTIFY_STOP)
-		return 1;
-
-	show_registers(regs);
-	/* Executive summary in case the oops scrolled away */
-	sp = (unsigned long) (&regs->sp);
-	savesegment(ss, ss);
-	if (user_mode(regs)) {
-		sp = regs->sp;
-		ss = regs->ss & 0xffff;
-	}
-	printk(KERN_EMERG "EIP: [<%08lx>] ", regs->ip);
-	print_symbol("%s", regs->ip);
-	printk(" SS:ESP %04x:%08lx\n", ss, sp);
-	return 0;
-}
-
-/*
- * This is gone through when something in the kernel has done something bad
- * and is about to be terminated:
- */
-void die(const char *str, struct pt_regs *regs, long err)
-{
-	unsigned long flags = oops_begin();
-
-	if (die_nest_count < 3) {
-		report_bug(regs->ip, regs);
-
-		if (__die(str, regs, err))
-			regs = NULL;
-	} else {
-		printk(KERN_EMERG "Recursive die() failure, output suppressed\n");
-	}
-
-	oops_end(flags, regs, SIGSEGV);
-}
-
-static inline void
-die_if_kernel(const char *str, struct pt_regs *regs, long err)
-{
-	if (!user_mode_vm(regs))
-		die(str, regs, err);
-}
-
-static void __kprobes
-do_trap(int trapnr, int signr, char *str, int vm86, struct pt_regs *regs,
-	long error_code, siginfo_t *info)
-{
-	struct task_struct *tsk = current;
-
-	if (regs->flags & X86_VM_MASK) {
-		if (vm86)
-			goto vm86_trap;
-		goto trap_signal;
-	}
-
-	if (!user_mode(regs))
-		goto kernel_trap;
-
-trap_signal:
-	/*
-	 * We want error_code and trap_no set for userspace faults and
-	 * kernelspace faults which result in die(), but not
-	 * kernelspace faults which are fixed up.  die() gives the
-	 * process no chance to handle the signal and notice the
-	 * kernel fault information, so that won't result in polluting
-	 * the information about previously queued, but not yet
-	 * delivered, faults.  See also do_general_protection below.
-	 */
-	tsk->thread.error_code = error_code;
-	tsk->thread.trap_no = trapnr;
-
-	if (info)
-		force_sig_info(signr, info, tsk);
-	else
-		force_sig(signr, tsk);
-	return;
-
-kernel_trap:
-	if (!fixup_exception(regs)) {
-		tsk->thread.error_code = error_code;
-		tsk->thread.trap_no = trapnr;
-		die(str, regs, error_code);
-	}
-	return;
-
-vm86_trap:
-	if (handle_vm86_trap((struct kernel_vm86_regs *) regs,
-						error_code, trapnr))
-		goto trap_signal;
-	return;
-}
-
-#define DO_ERROR(trapnr, signr, str, name)				\
-void do_##name(struct pt_regs *regs, long error_code)			\
-{									\
-	trace_hardirqs_fixup();						\
-	if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr)	\
-							== NOTIFY_STOP)	\
-		return;							\
-	do_trap(trapnr, signr, str, 0, regs, error_code, NULL);		\
-}
-
-#define DO_ERROR_INFO(trapnr, signr, str, name, sicode, siaddr, irq)	\
-void do_##name(struct pt_regs *regs, long error_code)			\
-{									\
-	siginfo_t info;							\
-	if (irq)							\
-		local_irq_enable();					\
-	info.si_signo = signr;						\
-	info.si_errno = 0;						\
-	info.si_code = sicode;						\
-	info.si_addr = (void __user *)siaddr;				\
-	if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr)	\
-							== NOTIFY_STOP)	\
-		return;							\
-	do_trap(trapnr, signr, str, 0, regs, error_code, &info);	\
-}
-
-#define DO_VM86_ERROR(trapnr, signr, str, name)				\
-void do_##name(struct pt_regs *regs, long error_code)			\
-{									\
-	if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr)	\
-							== NOTIFY_STOP)	\
-		return;							\
-	do_trap(trapnr, signr, str, 1, regs, error_code, NULL);		\
-}
-
-#define DO_VM86_ERROR_INFO(trapnr, signr, str, name, sicode, siaddr)	\
-void do_##name(struct pt_regs *regs, long error_code)			\
-{									\
-	siginfo_t info;							\
-	info.si_signo = signr;						\
-	info.si_errno = 0;						\
-	info.si_code = sicode;						\
-	info.si_addr = (void __user *)siaddr;				\
-	trace_hardirqs_fixup();						\
-	if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr)	\
-							== NOTIFY_STOP)	\
-		return;							\
-	do_trap(trapnr, signr, str, 1, regs, error_code, &info);	\
-}
-
-DO_VM86_ERROR_INFO(0, SIGFPE, "divide error", divide_error, FPE_INTDIV, regs->ip)
-#ifndef CONFIG_KPROBES
-DO_VM86_ERROR(3, SIGTRAP, "int3", int3)
-#endif
-DO_VM86_ERROR(4, SIGSEGV, "overflow", overflow)
-DO_VM86_ERROR(5, SIGSEGV, "bounds", bounds)
-DO_ERROR_INFO(6, SIGILL, "invalid opcode", invalid_op, ILL_ILLOPN, regs->ip, 0)
-DO_ERROR(9, SIGFPE, "coprocessor segment overrun", coprocessor_segment_overrun)
-DO_ERROR(10, SIGSEGV, "invalid TSS", invalid_TSS)
-DO_ERROR(11, SIGBUS, "segment not present", segment_not_present)
-DO_ERROR(12, SIGBUS, "stack segment", stack_segment)
-DO_ERROR_INFO(17, SIGBUS, "alignment check", alignment_check, BUS_ADRALN, 0, 0)
-DO_ERROR_INFO(32, SIGILL, "iret exception", iret_error, ILL_BADSTK, 0, 1)
-
-void __kprobes
-do_general_protection(struct pt_regs *regs, long error_code)
-{
-	struct task_struct *tsk;
-	struct thread_struct *thread;
-	struct tss_struct *tss;
-	int cpu;
-
-	cpu = get_cpu();
-	tss = &per_cpu(init_tss, cpu);
-	thread = &current->thread;
-
-	/*
-	 * Perform the lazy TSS's I/O bitmap copy. If the TSS has an
-	 * invalid offset set (the LAZY one) and the faulting thread has
-	 * a valid I/O bitmap pointer, we copy the I/O bitmap in the TSS
-	 * and we set the offset field correctly. Then we let the CPU to
-	 * restart the faulting instruction.
-	 */
-	if (tss->x86_tss.io_bitmap_base == INVALID_IO_BITMAP_OFFSET_LAZY &&
-	    thread->io_bitmap_ptr) {
-		memcpy(tss->io_bitmap, thread->io_bitmap_ptr,
-		       thread->io_bitmap_max);
-		/*
-		 * If the previously set map was extending to higher ports
-		 * than the current one, pad extra space with 0xff (no access).
-		 */
-		if (thread->io_bitmap_max < tss->io_bitmap_max) {
-			memset((char *) tss->io_bitmap +
-				thread->io_bitmap_max, 0xff,
-				tss->io_bitmap_max - thread->io_bitmap_max);
-		}
-		tss->io_bitmap_max = thread->io_bitmap_max;
-		tss->x86_tss.io_bitmap_base = IO_BITMAP_OFFSET;
-		tss->io_bitmap_owner = thread;
-		put_cpu();
-
-		return;
-	}
-	put_cpu();
-
-	if (regs->flags & X86_VM_MASK)
-		goto gp_in_vm86;
-
-	tsk = current;
-	if (!user_mode(regs))
-		goto gp_in_kernel;
-
-	tsk->thread.error_code = error_code;
-	tsk->thread.trap_no = 13;
-
-	if (show_unhandled_signals && unhandled_signal(tsk, SIGSEGV) &&
-			printk_ratelimit()) {
-		printk(KERN_INFO
-			"%s[%d] general protection ip:%lx sp:%lx error:%lx",
-			tsk->comm, task_pid_nr(tsk),
-			regs->ip, regs->sp, error_code);
-		print_vma_addr(" in ", regs->ip);
-		printk("\n");
-	}
-
-	force_sig(SIGSEGV, tsk);
-	return;
-
-gp_in_vm86:
-	local_irq_enable();
-	handle_vm86_fault((struct kernel_vm86_regs *) regs, error_code);
-	return;
-
-gp_in_kernel:
-	if (fixup_exception(regs))
-		return;
-
-	tsk->thread.error_code = error_code;
-	tsk->thread.trap_no = 13;
-	if (notify_die(DIE_GPF, "general protection fault", regs,
-				error_code, 13, SIGSEGV) == NOTIFY_STOP)
-		return;
-	die("general protection fault", regs, error_code);
-}
-
-static notrace __kprobes void
-mem_parity_error(unsigned char reason, struct pt_regs *regs)
-{
-	printk(KERN_EMERG
-		"Uhhuh. NMI received for unknown reason %02x on CPU %d.\n",
-			reason, smp_processor_id());
-
-	printk(KERN_EMERG
-		"You have some hardware problem, likely on the PCI bus.\n");
-
-#if defined(CONFIG_EDAC)
-	if (edac_handler_set()) {
-		edac_atomic_assert_error();
-		return;
-	}
-#endif
-
-	if (panic_on_unrecovered_nmi)
-		panic("NMI: Not continuing");
-
-	printk(KERN_EMERG "Dazed and confused, but trying to continue\n");
-
-	/* Clear and disable the memory parity error line. */
-	clear_mem_error(reason);
-}
-
-static notrace __kprobes void
-io_check_error(unsigned char reason, struct pt_regs *regs)
-{
-	unsigned long i;
-
-	printk(KERN_EMERG "NMI: IOCK error (debug interrupt?)\n");
-	show_registers(regs);
-
-	/* Re-enable the IOCK line, wait for a few seconds */
-	reason = (reason & 0xf) | 8;
-	outb(reason, 0x61);
-
-	i = 2000;
-	while (--i)
-		udelay(1000);
-
-	reason &= ~8;
-	outb(reason, 0x61);
-}
-
-static notrace __kprobes void
-unknown_nmi_error(unsigned char reason, struct pt_regs *regs)
-{
-	if (notify_die(DIE_NMIUNKNOWN, "nmi", regs, reason, 2, SIGINT) == NOTIFY_STOP)
-		return;
-#ifdef CONFIG_MCA
-	/*
-	 * Might actually be able to figure out what the guilty party
-	 * is:
-	 */
-	if (MCA_bus) {
-		mca_handle_nmi();
-		return;
-	}
-#endif
-	printk(KERN_EMERG
-		"Uhhuh. NMI received for unknown reason %02x on CPU %d.\n",
-			reason, smp_processor_id());
-
-	printk(KERN_EMERG "Do you have a strange power saving mode enabled?\n");
-	if (panic_on_unrecovered_nmi)
-		panic("NMI: Not continuing");
-
-	printk(KERN_EMERG "Dazed and confused, but trying to continue\n");
-}
-
-static DEFINE_SPINLOCK(nmi_print_lock);
-
-void notrace __kprobes die_nmi(char *str, struct pt_regs *regs, int do_panic)
-{
-	if (notify_die(DIE_NMIWATCHDOG, str, regs, 0, 2, SIGINT) == NOTIFY_STOP)
-		return;
-
-	spin_lock(&nmi_print_lock);
-	/*
-	* We are in trouble anyway, lets at least try
-	* to get a message out:
-	*/
-	bust_spinlocks(1);
-	printk(KERN_EMERG "%s", str);
-	printk(" on CPU%d, ip %08lx, registers:\n",
-		smp_processor_id(), regs->ip);
-	show_registers(regs);
-	if (do_panic)
-		panic("Non maskable interrupt");
-	console_silent();
-	spin_unlock(&nmi_print_lock);
-	bust_spinlocks(0);
-
-	/*
-	 * If we are in kernel we are probably nested up pretty bad
-	 * and might aswell get out now while we still can:
-	 */
-	if (!user_mode_vm(regs)) {
-		current->thread.trap_no = 2;
-		crash_kexec(regs);
-	}
-
-	do_exit(SIGSEGV);
-}
-
-static notrace __kprobes void default_do_nmi(struct pt_regs *regs)
-{
-	unsigned char reason = 0;
-	int cpu;
-
-	cpu = smp_processor_id();
-
-	/* Only the BSP gets external NMIs from the system. */
-	if (!cpu)
-		reason = get_nmi_reason();
-
-	if (!(reason & 0xc0)) {
-		if (notify_die(DIE_NMI_IPI, "nmi_ipi", regs, reason, 2, SIGINT)
-								== NOTIFY_STOP)
-			return;
-#ifdef CONFIG_X86_LOCAL_APIC
-		/*
-		 * Ok, so this is none of the documented NMI sources,
-		 * so it must be the NMI watchdog.
-		 */
-		if (nmi_watchdog_tick(regs, reason))
-			return;
-		if (!do_nmi_callback(regs, cpu))
-			unknown_nmi_error(reason, regs);
-#else
-		unknown_nmi_error(reason, regs);
-#endif
-
-		return;
-	}
-	if (notify_die(DIE_NMI, "nmi", regs, reason, 2, SIGINT) == NOTIFY_STOP)
-		return;
-
-	/* AK: following checks seem to be broken on modern chipsets. FIXME */
-	if (reason & 0x80)
-		mem_parity_error(reason, regs);
-	if (reason & 0x40)
-		io_check_error(reason, regs);
-	/*
-	 * Reassert NMI in case it became active meanwhile
-	 * as it's edge-triggered:
-	 */
-	reassert_nmi();
-}
-
-notrace __kprobes void do_nmi(struct pt_regs *regs, long error_code)
-{
-	int cpu;
-
-	nmi_enter();
-
-	cpu = smp_processor_id();
-
-	++nmi_count(cpu);
-
-	if (!ignore_nmis)
-		default_do_nmi(regs);
-
-	nmi_exit();
-}
-
-void stop_nmi(void)
-{
-	acpi_nmi_disable();
-	ignore_nmis++;
-}
-
-void restart_nmi(void)
-{
-	ignore_nmis--;
-	acpi_nmi_enable();
-}
-
-#ifdef CONFIG_KPROBES
-void __kprobes do_int3(struct pt_regs *regs, long error_code)
-{
-	trace_hardirqs_fixup();
-
-	if (notify_die(DIE_INT3, "int3", regs, error_code, 3, SIGTRAP)
-			== NOTIFY_STOP)
-		return;
-	/*
-	 * This is an interrupt gate, because kprobes wants interrupts
-	 * disabled. Normal trap handlers don't.
-	 */
-	restore_interrupts(regs);
-
-	do_trap(3, SIGTRAP, "int3", 1, regs, error_code, NULL);
-}
-#endif
-
-/*
- * Our handling of the processor debug registers is non-trivial.
- * We do not clear them on entry and exit from the kernel. Therefore
- * it is possible to get a watchpoint trap here from inside the kernel.
- * However, the code in ./ptrace.c has ensured that the user can
- * only set watchpoints on userspace addresses. Therefore the in-kernel
- * watchpoint trap can only occur in code which is reading/writing
- * from user space. Such code must not hold kernel locks (since it
- * can equally take a page fault), therefore it is safe to call
- * force_sig_info even though that claims and releases locks.
- *
- * Code in ./signal.c ensures that the debug control register
- * is restored before we deliver any signal, and therefore that
- * user code runs with the correct debug control register even though
- * we clear it here.
- *
- * Being careful here means that we don't have to be as careful in a
- * lot of more complicated places (task switching can be a bit lazy
- * about restoring all the debug state, and ptrace doesn't have to
- * find every occurrence of the TF bit that could be saved away even
- * by user code)
- */
-void __kprobes do_debug(struct pt_regs *regs, long error_code)
-{
-	struct task_struct *tsk = current;
-	unsigned int condition;
-
-	trace_hardirqs_fixup();
-
-	get_debugreg(condition, 6);
-
-	/*
-	 * The processor cleared BTF, so don't mark that we need it set.
-	 */
-	clear_tsk_thread_flag(tsk, TIF_DEBUGCTLMSR);
-	tsk->thread.debugctlmsr = 0;
-
-	if (notify_die(DIE_DEBUG, "debug", regs, condition, error_code,
-						SIGTRAP) == NOTIFY_STOP)
-		return;
-	/* It's safe to allow irq's after DR6 has been saved */
-	if (regs->flags & X86_EFLAGS_IF)
-		local_irq_enable();
-
-	/* Mask out spurious debug traps due to lazy DR7 setting */
-	if (condition & (DR_TRAP0|DR_TRAP1|DR_TRAP2|DR_TRAP3)) {
-		if (!tsk->thread.debugreg7)
-			goto clear_dr7;
-	}
-
-	if (regs->flags & X86_VM_MASK)
-		goto debug_vm86;
-
-	/* Save debug status register where ptrace can see it */
-	tsk->thread.debugreg6 = condition;
-
-	/*
-	 * Single-stepping through TF: make sure we ignore any events in
-	 * kernel space (but re-enable TF when returning to user mode).
-	 */
-	if (condition & DR_STEP) {
-		/*
-		 * We already checked v86 mode above, so we can
-		 * check for kernel mode by just checking the CPL
-		 * of CS.
-		 */
-		if (!user_mode(regs))
-			goto clear_TF_reenable;
-	}
-
-	/* Ok, finally something we can handle */
-	send_sigtrap(tsk, regs, error_code);
-
-	/*
-	 * Disable additional traps. They'll be re-enabled when
-	 * the signal is delivered.
-	 */
-clear_dr7:
-	set_debugreg(0, 7);
-	return;
-
-debug_vm86:
-	handle_vm86_trap((struct kernel_vm86_regs *) regs, error_code, 1);
-	return;
-
-clear_TF_reenable:
-	set_tsk_thread_flag(tsk, TIF_SINGLESTEP);
-	regs->flags &= ~X86_EFLAGS_TF;
-	return;
-}
-
-/*
- * Note that we play around with the 'TS' bit in an attempt to get
- * the correct behaviour even in the presence of the asynchronous
- * IRQ13 behaviour
- */
-void math_error(void __user *ip)
-{
-	struct task_struct *task;
-	siginfo_t info;
-	unsigned short cwd, swd;
-
-	/*
-	 * Save the info for the exception handler and clear the error.
-	 */
-	task = current;
-	save_init_fpu(task);
-	task->thread.trap_no = 16;
-	task->thread.error_code = 0;
-	info.si_signo = SIGFPE;
-	info.si_errno = 0;
-	info.si_code = __SI_FAULT;
-	info.si_addr = ip;
-	/*
-	 * (~cwd & swd) will mask out exceptions that are not set to unmasked
-	 * status.  0x3f is the exception bits in these regs, 0x200 is the
-	 * C1 reg you need in case of a stack fault, 0x040 is the stack
-	 * fault bit.  We should only be taking one exception at a time,
-	 * so if this combination doesn't produce any single exception,
-	 * then we have a bad program that isn't synchronizing its FPU usage
-	 * and it will suffer the consequences since we won't be able to
-	 * fully reproduce the context of the exception
-	 */
-	cwd = get_fpu_cwd(task);
-	swd = get_fpu_swd(task);
-	switch (swd & ~cwd & 0x3f) {
-	case 0x000: /* No unmasked exception */
-		return;
-	default: /* Multiple exceptions */
-		break;
-	case 0x001: /* Invalid Op */
-		/*
-		 * swd & 0x240 == 0x040: Stack Underflow
-		 * swd & 0x240 == 0x240: Stack Overflow
-		 * User must clear the SF bit (0x40) if set
-		 */
-		info.si_code = FPE_FLTINV;
-		break;
-	case 0x002: /* Denormalize */
-	case 0x010: /* Underflow */
-		info.si_code = FPE_FLTUND;
-		break;
-	case 0x004: /* Zero Divide */
-		info.si_code = FPE_FLTDIV;
-		break;
-	case 0x008: /* Overflow */
-		info.si_code = FPE_FLTOVF;
-		break;
-	case 0x020: /* Precision */
-		info.si_code = FPE_FLTRES;
-		break;
-	}
-	force_sig_info(SIGFPE, &info, task);
-}
-
-void do_coprocessor_error(struct pt_regs *regs, long error_code)
-{
-	ignore_fpu_irq = 1;
-	math_error((void __user *)regs->ip);
-}
-
-static void simd_math_error(void __user *ip)
-{
-	struct task_struct *task;
-	siginfo_t info;
-	unsigned short mxcsr;
-
-	/*
-	 * Save the info for the exception handler and clear the error.
-	 */
-	task = current;
-	save_init_fpu(task);
-	task->thread.trap_no = 19;
-	task->thread.error_code = 0;
-	info.si_signo = SIGFPE;
-	info.si_errno = 0;
-	info.si_code = __SI_FAULT;
-	info.si_addr = ip;
-	/*
-	 * The SIMD FPU exceptions are handled a little differently, as there
-	 * is only a single status/control register.  Thus, to determine which
-	 * unmasked exception was caught we must mask the exception mask bits
-	 * at 0x1f80, and then use these to mask the exception bits at 0x3f.
-	 */
-	mxcsr = get_fpu_mxcsr(task);
-	switch (~((mxcsr & 0x1f80) >> 7) & (mxcsr & 0x3f)) {
-	case 0x000:
-	default:
-		break;
-	case 0x001: /* Invalid Op */
-		info.si_code = FPE_FLTINV;
-		break;
-	case 0x002: /* Denormalize */
-	case 0x010: /* Underflow */
-		info.si_code = FPE_FLTUND;
-		break;
-	case 0x004: /* Zero Divide */
-		info.si_code = FPE_FLTDIV;
-		break;
-	case 0x008: /* Overflow */
-		info.si_code = FPE_FLTOVF;
-		break;
-	case 0x020: /* Precision */
-		info.si_code = FPE_FLTRES;
-		break;
-	}
-	force_sig_info(SIGFPE, &info, task);
-}
-
-void do_simd_coprocessor_error(struct pt_regs *regs, long error_code)
-{
-	if (cpu_has_xmm) {
-		/* Handle SIMD FPU exceptions on PIII+ processors. */
-		ignore_fpu_irq = 1;
-		simd_math_error((void __user *)regs->ip);
-		return;
-	}
-	/*
-	 * Handle strange cache flush from user space exception
-	 * in all other cases.  This is undocumented behaviour.
-	 */
-	if (regs->flags & X86_VM_MASK) {
-		handle_vm86_fault((struct kernel_vm86_regs *)regs, error_code);
-		return;
-	}
-	current->thread.trap_no = 19;
-	current->thread.error_code = error_code;
-	die_if_kernel("cache flush denied", regs, error_code);
-	force_sig(SIGSEGV, current);
-}
-
-void do_spurious_interrupt_bug(struct pt_regs *regs, long error_code)
-{
-#if 0
-	/* No need to warn about this any longer. */
-	printk(KERN_INFO "Ignoring P6 Local APIC Spurious Interrupt Bug...\n");
-#endif
-}
-
-unsigned long patch_espfix_desc(unsigned long uesp, unsigned long kesp)
-{
-	struct desc_struct *gdt = get_cpu_gdt_table(smp_processor_id());
-	unsigned long base = (kesp - uesp) & -THREAD_SIZE;
-	unsigned long new_kesp = kesp - base;
-	unsigned long lim_pages = (new_kesp | (THREAD_SIZE - 1)) >> PAGE_SHIFT;
-	__u64 desc = *(__u64 *)&gdt[GDT_ENTRY_ESPFIX_SS];
-
-	/* Set up base for espfix segment */
-	desc &= 0x00f0ff0000000000ULL;
-	desc |=	((((__u64)base) << 16) & 0x000000ffffff0000ULL) |
-		((((__u64)base) << 32) & 0xff00000000000000ULL) |
-		((((__u64)lim_pages) << 32) & 0x000f000000000000ULL) |
-		(lim_pages & 0xffff);
-	*(__u64 *)&gdt[GDT_ENTRY_ESPFIX_SS] = desc;
-
-	return new_kesp;
-}
-
-/*
- * 'math_state_restore()' saves the current math information in the
- * old math state array, and gets the new ones from the current task
- *
- * Careful.. There are problems with IBM-designed IRQ13 behaviour.
- * Don't touch unless you *really* know how it works.
- *
- * Must be called with kernel preemption disabled (in this case,
- * local interrupts are disabled at the call-site in entry.S).
- */
-asmlinkage void math_state_restore(void)
-{
-	struct thread_info *thread = current_thread_info();
-	struct task_struct *tsk = thread->task;
-
-	if (!tsk_used_math(tsk)) {
-		local_irq_enable();
-		/*
-		 * does a slab alloc which can sleep
-		 */
-		if (init_fpu(tsk)) {
-			/*
-			 * ran out of memory!
-			 */
-			do_group_exit(SIGKILL);
-			return;
-		}
-		local_irq_disable();
-	}
-
-	clts();				/* Allow maths ops (or we recurse) */
-	restore_fpu(tsk);
-	thread->status |= TS_USEDFPU;	/* So we fnsave on switch_to() */
-	tsk->fpu_counter++;
-}
-EXPORT_SYMBOL_GPL(math_state_restore);
-
-#ifndef CONFIG_MATH_EMULATION
-
-asmlinkage void math_emulate(long arg)
-{
-	printk(KERN_EMERG
-		"math-emulation not enabled and no coprocessor found.\n");
-	printk(KERN_EMERG "killing %s.\n", current->comm);
-	force_sig(SIGFPE, current);
-	schedule();
-}
-
-#endif /* CONFIG_MATH_EMULATION */
-
-void __init trap_init(void)
-{
-	int i;
-
-#ifdef CONFIG_EISA
-	void __iomem *p = early_ioremap(0x0FFFD9, 4);
-
-	if (readl(p) == 'E' + ('I'<<8) + ('S'<<16) + ('A'<<24))
-		EISA_bus = 1;
-	early_iounmap(p, 4);
-#endif
-
-	set_trap_gate(0, &divide_error);
-	set_intr_gate(1, &debug);
-	set_intr_gate(2, &nmi);
-	set_system_intr_gate(3, &int3); /* int3 can be called from all */
-	set_system_gate(4, &overflow); /* int4 can be called from all */
-	set_trap_gate(5, &bounds);
-	set_trap_gate(6, &invalid_op);
-	set_trap_gate(7, &device_not_available);
-	set_task_gate(8, GDT_ENTRY_DOUBLEFAULT_TSS);
-	set_trap_gate(9, &coprocessor_segment_overrun);
-	set_trap_gate(10, &invalid_TSS);
-	set_trap_gate(11, &segment_not_present);
-	set_trap_gate(12, &stack_segment);
-	set_trap_gate(13, &general_protection);
-	set_intr_gate(14, &page_fault);
-	set_trap_gate(15, &spurious_interrupt_bug);
-	set_trap_gate(16, &coprocessor_error);
-	set_trap_gate(17, &alignment_check);
-#ifdef CONFIG_X86_MCE
-	set_trap_gate(18, &machine_check);
-#endif
-	set_trap_gate(19, &simd_coprocessor_error);
-
-	if (cpu_has_fxsr) {
-		printk(KERN_INFO "Enabling fast FPU save and restore... ");
-		set_in_cr4(X86_CR4_OSFXSR);
-		printk("done.\n");
-	}
-	if (cpu_has_xmm) {
-		printk(KERN_INFO
-			"Enabling unmasked SIMD FPU exception support... ");
-		set_in_cr4(X86_CR4_OSXMMEXCPT);
-		printk("done.\n");
-	}
-
-	set_system_gate(SYSCALL_VECTOR, &system_call);
-
-	/* Reserve all the builtin and the syscall vector: */
-	for (i = 0; i < FIRST_EXTERNAL_VECTOR; i++)
-		set_bit(i, used_vectors);
-
-	set_bit(SYSCALL_VECTOR, used_vectors);
-
-	init_thread_xstate();
-	/*
-	 * Should be a barrier for any external CPU state:
-	 */
-	cpu_init();
-
-	trap_init_hook();
-}
-
-static int __init kstack_setup(char *s)
-{
-	kstack_depth_to_print = simple_strtoul(s, NULL, 0);
-
-	return 1;
-}
-__setup("kstack=", kstack_setup);
-
-static int __init code_bytes_setup(char *s)
-{
-	code_bytes = simple_strtoul(s, NULL, 0);
-	if (code_bytes > 8192)
-		code_bytes = 8192;
-
-	return 1;
-}
-__setup("code_bytes=", code_bytes_setup);
diff --git a/arch/x86/kernel/traps_64.c b/arch/x86/kernel/traps_64.c
deleted file mode 100644
index 513caac..0000000
--- a/arch/x86/kernel/traps_64.c
+++ /dev/null
@@ -1,1212 +0,0 @@
-/*
- *  Copyright (C) 1991, 1992  Linus Torvalds
- *  Copyright (C) 2000, 2001, 2002 Andi Kleen, SuSE Labs
- *
- *  Pentium III FXSR, SSE support
- *	Gareth Hughes <gareth@valinux.com>, May 2000
- */
-
-/*
- * 'Traps.c' handles hardware traps and faults after we have saved some
- * state in 'entry.S'.
- */
-#include <linux/moduleparam.h>
-#include <linux/interrupt.h>
-#include <linux/kallsyms.h>
-#include <linux/spinlock.h>
-#include <linux/kprobes.h>
-#include <linux/uaccess.h>
-#include <linux/utsname.h>
-#include <linux/kdebug.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/ptrace.h>
-#include <linux/string.h>
-#include <linux/unwind.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/kexec.h>
-#include <linux/sched.h>
-#include <linux/timer.h>
-#include <linux/init.h>
-#include <linux/bug.h>
-#include <linux/nmi.h>
-#include <linux/mm.h>
-
-#if defined(CONFIG_EDAC)
-#include <linux/edac.h>
-#endif
-
-#include <asm/stacktrace.h>
-#include <asm/processor.h>
-#include <asm/debugreg.h>
-#include <asm/atomic.h>
-#include <asm/system.h>
-#include <asm/unwind.h>
-#include <asm/desc.h>
-#include <asm/i387.h>
-#include <asm/nmi.h>
-#include <asm/smp.h>
-#include <asm/io.h>
-#include <asm/pgalloc.h>
-#include <asm/proto.h>
-#include <asm/pda.h>
-#include <asm/traps.h>
-
-#include <mach_traps.h>
-
-int panic_on_unrecovered_nmi;
-int kstack_depth_to_print = 12;
-static unsigned int code_bytes = 64;
-static int ignore_nmis;
-static int die_counter;
-
-static inline void conditional_sti(struct pt_regs *regs)
-{
-	if (regs->flags & X86_EFLAGS_IF)
-		local_irq_enable();
-}
-
-static inline void preempt_conditional_sti(struct pt_regs *regs)
-{
-	inc_preempt_count();
-	if (regs->flags & X86_EFLAGS_IF)
-		local_irq_enable();
-}
-
-static inline void preempt_conditional_cli(struct pt_regs *regs)
-{
-	if (regs->flags & X86_EFLAGS_IF)
-		local_irq_disable();
-	/* Make sure to not schedule here because we could be running
-	   on an exception stack. */
-	dec_preempt_count();
-}
-
-void printk_address(unsigned long address, int reliable)
-{
-	printk(" [<%016lx>] %s%pS\n", address, reliable ? "": "? ", (void *) address);
-}
-
-static unsigned long *in_exception_stack(unsigned cpu, unsigned long stack,
-					unsigned *usedp, char **idp)
-{
-	static char ids[][8] = {
-		[DEBUG_STACK - 1] = "#DB",
-		[NMI_STACK - 1] = "NMI",
-		[DOUBLEFAULT_STACK - 1] = "#DF",
-		[STACKFAULT_STACK - 1] = "#SS",
-		[MCE_STACK - 1] = "#MC",
-#if DEBUG_STKSZ > EXCEPTION_STKSZ
-		[N_EXCEPTION_STACKS ... N_EXCEPTION_STACKS + DEBUG_STKSZ / EXCEPTION_STKSZ - 2] = "#DB[?]"
-#endif
-	};
-	unsigned k;
-
-	/*
-	 * Iterate over all exception stacks, and figure out whether
-	 * 'stack' is in one of them:
-	 */
-	for (k = 0; k < N_EXCEPTION_STACKS; k++) {
-		unsigned long end = per_cpu(orig_ist, cpu).ist[k];
-		/*
-		 * Is 'stack' above this exception frame's end?
-		 * If yes then skip to the next frame.
-		 */
-		if (stack >= end)
-			continue;
-		/*
-		 * Is 'stack' above this exception frame's start address?
-		 * If yes then we found the right frame.
-		 */
-		if (stack >= end - EXCEPTION_STKSZ) {
-			/*
-			 * Make sure we only iterate through an exception
-			 * stack once. If it comes up for the second time
-			 * then there's something wrong going on - just
-			 * break out and return NULL:
-			 */
-			if (*usedp & (1U << k))
-				break;
-			*usedp |= 1U << k;
-			*idp = ids[k];
-			return (unsigned long *)end;
-		}
-		/*
-		 * If this is a debug stack, and if it has a larger size than
-		 * the usual exception stacks, then 'stack' might still
-		 * be within the lower portion of the debug stack:
-		 */
-#if DEBUG_STKSZ > EXCEPTION_STKSZ
-		if (k == DEBUG_STACK - 1 && stack >= end - DEBUG_STKSZ) {
-			unsigned j = N_EXCEPTION_STACKS - 1;
-
-			/*
-			 * Black magic. A large debug stack is composed of
-			 * multiple exception stack entries, which we
-			 * iterate through now. Dont look:
-			 */
-			do {
-				++j;
-				end -= EXCEPTION_STKSZ;
-				ids[j][4] = '1' + (j - N_EXCEPTION_STACKS);
-			} while (stack < end - EXCEPTION_STKSZ);
-			if (*usedp & (1U << j))
-				break;
-			*usedp |= 1U << j;
-			*idp = ids[j];
-			return (unsigned long *)end;
-		}
-#endif
-	}
-	return NULL;
-}
-
-/*
- * x86-64 can have up to three kernel stacks: 
- * process stack
- * interrupt stack
- * severe exception (double fault, nmi, stack fault, debug, mce) hardware stack
- */
-
-static inline int valid_stack_ptr(struct thread_info *tinfo,
-			void *p, unsigned int size, void *end)
-{
-	void *t = tinfo;
-	if (end) {
-		if (p < end && p >= (end-THREAD_SIZE))
-			return 1;
-		else
-			return 0;
-	}
-	return p > t && p < t + THREAD_SIZE - size;
-}
-
-/* The form of the top of the frame on the stack */
-struct stack_frame {
-	struct stack_frame *next_frame;
-	unsigned long return_address;
-};
-
-static inline unsigned long
-print_context_stack(struct thread_info *tinfo,
-		unsigned long *stack, unsigned long bp,
-		const struct stacktrace_ops *ops, void *data,
-		unsigned long *end)
-{
-	struct stack_frame *frame = (struct stack_frame *)bp;
-
-	while (valid_stack_ptr(tinfo, stack, sizeof(*stack), end)) {
-		unsigned long addr;
-
-		addr = *stack;
-		if (__kernel_text_address(addr)) {
-			if ((unsigned long) stack == bp + 8) {
-				ops->address(data, addr, 1);
-				frame = frame->next_frame;
-				bp = (unsigned long) frame;
-			} else {
-				ops->address(data, addr, bp == 0);
-			}
-		}
-		stack++;
-	}
-	return bp;
-}
-
-void dump_trace(struct task_struct *task, struct pt_regs *regs,
-		unsigned long *stack, unsigned long bp,
-		const struct stacktrace_ops *ops, void *data)
-{
-	const unsigned cpu = get_cpu();
-	unsigned long *irqstack_end = (unsigned long*)cpu_pda(cpu)->irqstackptr;
-	unsigned used = 0;
-	struct thread_info *tinfo;
-
-	if (!task)
-		task = current;
-
-	if (!stack) {
-		unsigned long dummy;
-		stack = &dummy;
-		if (task && task != current)
-			stack = (unsigned long *)task->thread.sp;
-	}
-
-#ifdef CONFIG_FRAME_POINTER
-	if (!bp) {
-		if (task == current) {
-			/* Grab bp right from our regs */
-			asm("movq %%rbp, %0" : "=r" (bp) :);
-		} else {
-			/* bp is the last reg pushed by switch_to */
-			bp = *(unsigned long *) task->thread.sp;
-		}
-	}
-#endif
-
-	/*
-	 * Print function call entries in all stacks, starting at the
-	 * current stack address. If the stacks consist of nested
-	 * exceptions
-	 */
-	tinfo = task_thread_info(task);
-	for (;;) {
-		char *id;
-		unsigned long *estack_end;
-		estack_end = in_exception_stack(cpu, (unsigned long)stack,
-						&used, &id);
-
-		if (estack_end) {
-			if (ops->stack(data, id) < 0)
-				break;
-
-			bp = print_context_stack(tinfo, stack, bp, ops,
-							data, estack_end);
-			ops->stack(data, "<EOE>");
-			/*
-			 * We link to the next stack via the
-			 * second-to-last pointer (index -2 to end) in the
-			 * exception stack:
-			 */
-			stack = (unsigned long *) estack_end[-2];
-			continue;
-		}
-		if (irqstack_end) {
-			unsigned long *irqstack;
-			irqstack = irqstack_end -
-				(IRQSTACKSIZE - 64) / sizeof(*irqstack);
-
-			if (stack >= irqstack && stack < irqstack_end) {
-				if (ops->stack(data, "IRQ") < 0)
-					break;
-				bp = print_context_stack(tinfo, stack, bp,
-						ops, data, irqstack_end);
-				/*
-				 * We link to the next stack (which would be
-				 * the process stack normally) the last
-				 * pointer (index -1 to end) in the IRQ stack:
-				 */
-				stack = (unsigned long *) (irqstack_end[-1]);
-				irqstack_end = NULL;
-				ops->stack(data, "EOI");
-				continue;
-			}
-		}
-		break;
-	}
-
-	/*
-	 * This handles the process stack:
-	 */
-	bp = print_context_stack(tinfo, stack, bp, ops, data, NULL);
-	put_cpu();
-}
-EXPORT_SYMBOL(dump_trace);
-
-static void
-print_trace_warning_symbol(void *data, char *msg, unsigned long symbol)
-{
-	print_symbol(msg, symbol);
-	printk("\n");
-}
-
-static void print_trace_warning(void *data, char *msg)
-{
-	printk("%s\n", msg);
-}
-
-static int print_trace_stack(void *data, char *name)
-{
-	printk(" <%s> ", name);
-	return 0;
-}
-
-static void print_trace_address(void *data, unsigned long addr, int reliable)
-{
-	touch_nmi_watchdog();
-	printk_address(addr, reliable);
-}
-
-static const struct stacktrace_ops print_trace_ops = {
-	.warning = print_trace_warning,
-	.warning_symbol = print_trace_warning_symbol,
-	.stack = print_trace_stack,
-	.address = print_trace_address,
-};
-
-static void
-show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs,
-		unsigned long *stack, unsigned long bp, char *log_lvl)
-{
-	printk("\nCall Trace:\n");
-	dump_trace(task, regs, stack, bp, &print_trace_ops, log_lvl);
-	printk("\n");
-}
-
-void show_trace(struct task_struct *task, struct pt_regs *regs,
-		unsigned long *stack, unsigned long bp)
-{
-	show_trace_log_lvl(task, regs, stack, bp, "");
-}
-
-static void
-show_stack_log_lvl(struct task_struct *task, struct pt_regs *regs,
-		unsigned long *sp, unsigned long bp, char *log_lvl)
-{
-	unsigned long *stack;
-	int i;
-	const int cpu = smp_processor_id();
-	unsigned long *irqstack_end = (unsigned long *) (cpu_pda(cpu)->irqstackptr);
-	unsigned long *irqstack = (unsigned long *) (cpu_pda(cpu)->irqstackptr - IRQSTACKSIZE);
-
-	// debugging aid: "show_stack(NULL, NULL);" prints the
-	// back trace for this cpu.
-
-	if (sp == NULL) {
-		if (task)
-			sp = (unsigned long *)task->thread.sp;
-		else
-			sp = (unsigned long *)&sp;
-	}
-
-	stack = sp;
-	for (i = 0; i < kstack_depth_to_print; i++) {
-		if (stack >= irqstack && stack <= irqstack_end) {
-			if (stack == irqstack_end) {
-				stack = (unsigned long *) (irqstack_end[-1]);
-				printk(" <EOI> ");
-			}
-		} else {
-		if (((long) stack & (THREAD_SIZE-1)) == 0)
-			break;
-		}
-		if (i && ((i % 4) == 0))
-			printk("\n");
-		printk(" %016lx", *stack++);
-		touch_nmi_watchdog();
-	}
-	show_trace_log_lvl(task, regs, sp, bp, log_lvl);
-}
-
-void show_stack(struct task_struct *task, unsigned long *sp)
-{
-	show_stack_log_lvl(task, NULL, sp, 0, "");
-}
-
-/*
- * The architecture-independent dump_stack generator
- */
-void dump_stack(void)
-{
-	unsigned long bp = 0;
-	unsigned long stack;
-
-#ifdef CONFIG_FRAME_POINTER
-	if (!bp)
-		asm("movq %%rbp, %0" : "=r" (bp):);
-#endif
-
-	printk("Pid: %d, comm: %.20s %s %s %.*s\n",
-		current->pid, current->comm, print_tainted(),
-		init_utsname()->release,
-		(int)strcspn(init_utsname()->version, " "),
-		init_utsname()->version);
-	show_trace(NULL, NULL, &stack, bp);
-}
-
-EXPORT_SYMBOL(dump_stack);
-
-void show_registers(struct pt_regs *regs)
-{
-	int i;
-	unsigned long sp;
-	const int cpu = smp_processor_id();
-	struct task_struct *cur = cpu_pda(cpu)->pcurrent;
-
-	sp = regs->sp;
-	printk("CPU %d ", cpu);
-	__show_regs(regs);
-	printk("Process %s (pid: %d, threadinfo %p, task %p)\n",
-		cur->comm, cur->pid, task_thread_info(cur), cur);
-
-	/*
-	 * When in-kernel, we also print out the stack and code at the
-	 * time of the fault..
-	 */
-	if (!user_mode(regs)) {
-		unsigned int code_prologue = code_bytes * 43 / 64;
-		unsigned int code_len = code_bytes;
-		unsigned char c;
-		u8 *ip;
-
-		printk("Stack: ");
-		show_stack_log_lvl(NULL, regs, (unsigned long *)sp,
-				regs->bp, "");
-		printk("\n");
-
-		printk(KERN_EMERG "Code: ");
-
-		ip = (u8 *)regs->ip - code_prologue;
-		if (ip < (u8 *)PAGE_OFFSET || probe_kernel_address(ip, c)) {
-			/* try starting at RIP */
-			ip = (u8 *)regs->ip;
-			code_len = code_len - code_prologue + 1;
-		}
-		for (i = 0; i < code_len; i++, ip++) {
-			if (ip < (u8 *)PAGE_OFFSET ||
-					probe_kernel_address(ip, c)) {
-				printk(" Bad RIP value.");
-				break;
-			}
-			if (ip == (u8 *)regs->ip)
-				printk("<%02x> ", c);
-			else
-				printk("%02x ", c);
-		}
-	}
-	printk("\n");
-}
-
-int is_valid_bugaddr(unsigned long ip)
-{
-	unsigned short ud2;
-
-	if (__copy_from_user(&ud2, (const void __user *) ip, sizeof(ud2)))
-		return 0;
-
-	return ud2 == 0x0b0f;
-}
-
-static raw_spinlock_t die_lock = __RAW_SPIN_LOCK_UNLOCKED;
-static int die_owner = -1;
-static unsigned int die_nest_count;
-
-unsigned __kprobes long oops_begin(void)
-{
-	int cpu;
-	unsigned long flags;
-
-	oops_enter();
-
-	/* racy, but better than risking deadlock. */
-	raw_local_irq_save(flags);
-	cpu = smp_processor_id();
-	if (!__raw_spin_trylock(&die_lock)) {
-		if (cpu == die_owner) 
-			/* nested oops. should stop eventually */;
-		else
-			__raw_spin_lock(&die_lock);
-	}
-	die_nest_count++;
-	die_owner = cpu;
-	console_verbose();
-	bust_spinlocks(1);
-	return flags;
-}
-
-void __kprobes oops_end(unsigned long flags, struct pt_regs *regs, int signr)
-{
-	die_owner = -1;
-	bust_spinlocks(0);
-	die_nest_count--;
-	if (!die_nest_count)
-		/* Nest count reaches zero, release the lock. */
-		__raw_spin_unlock(&die_lock);
-	raw_local_irq_restore(flags);
-	if (!regs) {
-		oops_exit();
-		return;
-	}
-	if (panic_on_oops)
-		panic("Fatal exception");
-	oops_exit();
-	do_exit(signr);
-}
-
-int __kprobes __die(const char *str, struct pt_regs *regs, long err)
-{
-	printk(KERN_EMERG "%s: %04lx [%u] ", str, err & 0xffff, ++die_counter);
-#ifdef CONFIG_PREEMPT
-	printk("PREEMPT ");
-#endif
-#ifdef CONFIG_SMP
-	printk("SMP ");
-#endif
-#ifdef CONFIG_DEBUG_PAGEALLOC
-	printk("DEBUG_PAGEALLOC");
-#endif
-	printk("\n");
-	if (notify_die(DIE_OOPS, str, regs, err,
-			current->thread.trap_no, SIGSEGV) == NOTIFY_STOP)
-		return 1;
-
-	show_registers(regs);
-	add_taint(TAINT_DIE);
-	/* Executive summary in case the oops scrolled away */
-	printk(KERN_ALERT "RIP ");
-	printk_address(regs->ip, 1);
-	printk(" RSP <%016lx>\n", regs->sp);
-	if (kexec_should_crash(current))
-		crash_kexec(regs);
-	return 0;
-}
-
-void die(const char *str, struct pt_regs *regs, long err)
-{
-	unsigned long flags = oops_begin();
-
-	if (!user_mode(regs))
-		report_bug(regs->ip, regs);
-
-	if (__die(str, regs, err))
-		regs = NULL;
-	oops_end(flags, regs, SIGSEGV);
-}
-
-notrace __kprobes void
-die_nmi(char *str, struct pt_regs *regs, int do_panic)
-{
-	unsigned long flags;
-
-	if (notify_die(DIE_NMIWATCHDOG, str, regs, 0, 2, SIGINT) == NOTIFY_STOP)
-		return;
-
-	flags = oops_begin();
-	/*
-	 * We are in trouble anyway, lets at least try
-	 * to get a message out.
-	 */
-	printk(KERN_EMERG "%s", str);
-	printk(" on CPU%d, ip %08lx, registers:\n",
-		smp_processor_id(), regs->ip);
-	show_registers(regs);
-	if (kexec_should_crash(current))
-		crash_kexec(regs);
-	if (do_panic || panic_on_oops)
-		panic("Non maskable interrupt");
-	oops_end(flags, NULL, SIGBUS);
-	nmi_exit();
-	local_irq_enable();
-	do_exit(SIGBUS);
-}
-
-static void __kprobes
-do_trap(int trapnr, int signr, char *str, struct pt_regs *regs,
-	long error_code, siginfo_t *info)
-{
-	struct task_struct *tsk = current;
-
-	if (!user_mode(regs))
-		goto kernel_trap;
-
-	/*
-	 * We want error_code and trap_no set for userspace faults and
-	 * kernelspace faults which result in die(), but not
-	 * kernelspace faults which are fixed up.  die() gives the
-	 * process no chance to handle the signal and notice the
-	 * kernel fault information, so that won't result in polluting
-	 * the information about previously queued, but not yet
-	 * delivered, faults.  See also do_general_protection below.
-	 */
-	tsk->thread.error_code = error_code;
-	tsk->thread.trap_no = trapnr;
-
-	if (show_unhandled_signals && unhandled_signal(tsk, signr) &&
-	    printk_ratelimit()) {
-		printk(KERN_INFO
-		       "%s[%d] trap %s ip:%lx sp:%lx error:%lx",
-		       tsk->comm, tsk->pid, str,
-		       regs->ip, regs->sp, error_code);
-		print_vma_addr(" in ", regs->ip);
-		printk("\n");
-	}
-
-	if (info)
-		force_sig_info(signr, info, tsk);
-	else
-		force_sig(signr, tsk);
-	return;
-
-kernel_trap:
-	if (!fixup_exception(regs)) {
-		tsk->thread.error_code = error_code;
-		tsk->thread.trap_no = trapnr;
-		die(str, regs, error_code);
-	}
-	return;
-}
-
-#define DO_ERROR(trapnr, signr, str, name) \
-asmlinkage void do_##name(struct pt_regs * regs, long error_code)	\
-{									\
-	if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr)	\
-							== NOTIFY_STOP)	\
-		return;							\
-	conditional_sti(regs);						\
-	do_trap(trapnr, signr, str, regs, error_code, NULL);		\
-}
-
-#define DO_ERROR_INFO(trapnr, signr, str, name, sicode, siaddr)		\
-asmlinkage void do_##name(struct pt_regs * regs, long error_code)	\
-{									\
-	siginfo_t info;							\
-	info.si_signo = signr;						\
-	info.si_errno = 0;						\
-	info.si_code = sicode;						\
-	info.si_addr = (void __user *)siaddr;				\
-	trace_hardirqs_fixup();						\
-	if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr)	\
-							== NOTIFY_STOP)	\
-		return;							\
-	conditional_sti(regs);						\
-	do_trap(trapnr, signr, str, regs, error_code, &info);		\
-}
-
-DO_ERROR_INFO(0, SIGFPE, "divide error", divide_error, FPE_INTDIV, regs->ip)
-DO_ERROR(4, SIGSEGV, "overflow", overflow)
-DO_ERROR(5, SIGSEGV, "bounds", bounds)
-DO_ERROR_INFO(6, SIGILL, "invalid opcode", invalid_op, ILL_ILLOPN, regs->ip)
-DO_ERROR(9, SIGFPE, "coprocessor segment overrun", coprocessor_segment_overrun)
-DO_ERROR(10, SIGSEGV, "invalid TSS", invalid_TSS)
-DO_ERROR(11, SIGBUS, "segment not present", segment_not_present)
-DO_ERROR_INFO(17, SIGBUS, "alignment check", alignment_check, BUS_ADRALN, 0)
-
-/* Runs on IST stack */
-asmlinkage void do_stack_segment(struct pt_regs *regs, long error_code)
-{
-	if (notify_die(DIE_TRAP, "stack segment", regs, error_code,
-			12, SIGBUS) == NOTIFY_STOP)
-		return;
-	preempt_conditional_sti(regs);
-	do_trap(12, SIGBUS, "stack segment", regs, error_code, NULL);
-	preempt_conditional_cli(regs);
-}
-
-asmlinkage void do_double_fault(struct pt_regs * regs, long error_code)
-{
-	static const char str[] = "double fault";
-	struct task_struct *tsk = current;
-
-	/* Return not checked because double check cannot be ignored */
-	notify_die(DIE_TRAP, str, regs, error_code, 8, SIGSEGV);
-
-	tsk->thread.error_code = error_code;
-	tsk->thread.trap_no = 8;
-
-	/* This is always a kernel trap and never fixable (and thus must
-	   never return). */
-	for (;;)
-		die(str, regs, error_code);
-}
-
-asmlinkage void __kprobes
-do_general_protection(struct pt_regs *regs, long error_code)
-{
-	struct task_struct *tsk;
-
-	conditional_sti(regs);
-
-	tsk = current;
-	if (!user_mode(regs))
-		goto gp_in_kernel;
-
-	tsk->thread.error_code = error_code;
-	tsk->thread.trap_no = 13;
-
-	if (show_unhandled_signals && unhandled_signal(tsk, SIGSEGV) &&
-			printk_ratelimit()) {
-		printk(KERN_INFO
-			"%s[%d] general protection ip:%lx sp:%lx error:%lx",
-			tsk->comm, tsk->pid,
-			regs->ip, regs->sp, error_code);
-		print_vma_addr(" in ", regs->ip);
-		printk("\n");
-	}
-
-	force_sig(SIGSEGV, tsk);
-	return;
-
-gp_in_kernel:
-	if (fixup_exception(regs))
-		return;
-
-	tsk->thread.error_code = error_code;
-	tsk->thread.trap_no = 13;
-	if (notify_die(DIE_GPF, "general protection fault", regs,
-				error_code, 13, SIGSEGV) == NOTIFY_STOP)
-		return;
-	die("general protection fault", regs, error_code);
-}
-
-static notrace __kprobes void
-mem_parity_error(unsigned char reason, struct pt_regs *regs)
-{
-	printk(KERN_EMERG "Uhhuh. NMI received for unknown reason %02x.\n",
-		reason);
-	printk(KERN_EMERG "You have some hardware problem, likely on the PCI bus.\n");
-
-#if defined(CONFIG_EDAC)
-	if (edac_handler_set()) {
-		edac_atomic_assert_error();
-		return;
-	}
-#endif
-
-	if (panic_on_unrecovered_nmi)
-		panic("NMI: Not continuing");
-
-	printk(KERN_EMERG "Dazed and confused, but trying to continue\n");
-
-	/* Clear and disable the memory parity error line. */
-	reason = (reason & 0xf) | 4;
-	outb(reason, 0x61);
-}
-
-static notrace __kprobes void
-io_check_error(unsigned char reason, struct pt_regs *regs)
-{
-	printk("NMI: IOCK error (debug interrupt?)\n");
-	show_registers(regs);
-
-	/* Re-enable the IOCK line, wait for a few seconds */
-	reason = (reason & 0xf) | 8;
-	outb(reason, 0x61);
-	mdelay(2000);
-	reason &= ~8;
-	outb(reason, 0x61);
-}
-
-static notrace __kprobes void
-unknown_nmi_error(unsigned char reason, struct pt_regs * regs)
-{
-	if (notify_die(DIE_NMIUNKNOWN, "nmi", regs, reason, 2, SIGINT) == NOTIFY_STOP)
-		return;
-	printk(KERN_EMERG "Uhhuh. NMI received for unknown reason %02x.\n",
-		reason);
-	printk(KERN_EMERG "Do you have a strange power saving mode enabled?\n");
-
-	if (panic_on_unrecovered_nmi)
-		panic("NMI: Not continuing");
-
-	printk(KERN_EMERG "Dazed and confused, but trying to continue\n");
-}
-
-/* Runs on IST stack. This code must keep interrupts off all the time.
-   Nested NMIs are prevented by the CPU. */
-asmlinkage notrace __kprobes void default_do_nmi(struct pt_regs *regs)
-{
-	unsigned char reason = 0;
-	int cpu;
-
-	cpu = smp_processor_id();
-
-	/* Only the BSP gets external NMIs from the system. */
-	if (!cpu)
-		reason = get_nmi_reason();
-
-	if (!(reason & 0xc0)) {
-		if (notify_die(DIE_NMI_IPI, "nmi_ipi", regs, reason, 2, SIGINT)
-								== NOTIFY_STOP)
-			return;
-		/*
-		 * Ok, so this is none of the documented NMI sources,
-		 * so it must be the NMI watchdog.
-		 */
-		if (nmi_watchdog_tick(regs, reason))
-			return;
-		if (!do_nmi_callback(regs, cpu))
-			unknown_nmi_error(reason, regs);
-
-		return;
-	}
-	if (notify_die(DIE_NMI, "nmi", regs, reason, 2, SIGINT) == NOTIFY_STOP)
-		return;
-
-	/* AK: following checks seem to be broken on modern chipsets. FIXME */
-	if (reason & 0x80)
-		mem_parity_error(reason, regs);
-	if (reason & 0x40)
-		io_check_error(reason, regs);
-}
-
-asmlinkage notrace __kprobes void
-do_nmi(struct pt_regs *regs, long error_code)
-{
-	nmi_enter();
-
-	add_pda(__nmi_count, 1);
-
-	if (!ignore_nmis)
-		default_do_nmi(regs);
-
-	nmi_exit();
-}
-
-void stop_nmi(void)
-{
-	acpi_nmi_disable();
-	ignore_nmis++;
-}
-
-void restart_nmi(void)
-{
-	ignore_nmis--;
-	acpi_nmi_enable();
-}
-
-/* runs on IST stack. */
-asmlinkage void __kprobes do_int3(struct pt_regs *regs, long error_code)
-{
-	trace_hardirqs_fixup();
-
-	if (notify_die(DIE_INT3, "int3", regs, error_code, 3, SIGTRAP)
-			== NOTIFY_STOP)
-		return;
-
-	preempt_conditional_sti(regs);
-	do_trap(3, SIGTRAP, "int3", regs, error_code, NULL);
-	preempt_conditional_cli(regs);
-}
-
-/* Help handler running on IST stack to switch back to user stack
-   for scheduling or signal handling. The actual stack switch is done in
-   entry.S */
-asmlinkage __kprobes struct pt_regs *sync_regs(struct pt_regs *eregs)
-{
-	struct pt_regs *regs = eregs;
-	/* Did already sync */
-	if (eregs == (struct pt_regs *)eregs->sp)
-		;
-	/* Exception from user space */
-	else if (user_mode(eregs))
-		regs = task_pt_regs(current);
-	/* Exception from kernel and interrupts are enabled. Move to
- 	   kernel process stack. */
-	else if (eregs->flags & X86_EFLAGS_IF)
-		regs = (struct pt_regs *)(eregs->sp -= sizeof(struct pt_regs));
-	if (eregs != regs)
-		*regs = *eregs;
-	return regs;
-}
-
-/* runs on IST stack. */
-asmlinkage void __kprobes do_debug(struct pt_regs * regs,
-				   unsigned long error_code)
-{
-	struct task_struct *tsk = current;
-	unsigned long condition;
-	siginfo_t info;
-
-	trace_hardirqs_fixup();
-
-	get_debugreg(condition, 6);
-
-	/*
-	 * The processor cleared BTF, so don't mark that we need it set.
-	 */
-	clear_tsk_thread_flag(tsk, TIF_DEBUGCTLMSR);
-	tsk->thread.debugctlmsr = 0;
-
-	if (notify_die(DIE_DEBUG, "debug", regs, condition, error_code,
-						SIGTRAP) == NOTIFY_STOP)
-		return;
-
-	preempt_conditional_sti(regs);
-
-	/* Mask out spurious debug traps due to lazy DR7 setting */
-	if (condition & (DR_TRAP0|DR_TRAP1|DR_TRAP2|DR_TRAP3)) {
-		if (!tsk->thread.debugreg7)
-			goto clear_dr7;
-	}
-
-	tsk->thread.debugreg6 = condition;
-
-	/*
-	 * Single-stepping through TF: make sure we ignore any events in
-	 * kernel space (but re-enable TF when returning to user mode).
-	 */
-	if (condition & DR_STEP) {
-		if (!user_mode(regs))
-			goto clear_TF_reenable;
-	}
-
-	/* Ok, finally something we can handle */
-	tsk->thread.trap_no = 1;
-	tsk->thread.error_code = error_code;
-	info.si_signo = SIGTRAP;
-	info.si_errno = 0;
-	info.si_code = TRAP_BRKPT;
-	info.si_addr = user_mode(regs) ? (void __user *)regs->ip : NULL;
-	force_sig_info(SIGTRAP, &info, tsk);
-
-clear_dr7:
-	set_debugreg(0, 7);
-	preempt_conditional_cli(regs);
-	return;
-
-clear_TF_reenable:
-	set_tsk_thread_flag(tsk, TIF_SINGLESTEP);
-	regs->flags &= ~X86_EFLAGS_TF;
-	preempt_conditional_cli(regs);
-	return;
-}
-
-static int kernel_math_error(struct pt_regs *regs, const char *str, int trapnr)
-{
-	if (fixup_exception(regs))
-		return 1;
-
-	notify_die(DIE_GPF, str, regs, 0, trapnr, SIGFPE);
-	/* Illegal floating point operation in the kernel */
-	current->thread.trap_no = trapnr;
-	die(str, regs, 0);
-	return 0;
-}
-
-/*
- * Note that we play around with the 'TS' bit in an attempt to get
- * the correct behaviour even in the presence of the asynchronous
- * IRQ13 behaviour
- */
-asmlinkage void do_coprocessor_error(struct pt_regs *regs)
-{
-	void __user *ip = (void __user *)(regs->ip);
-	struct task_struct *task;
-	siginfo_t info;
-	unsigned short cwd, swd;
-
-	conditional_sti(regs);
-	if (!user_mode(regs) &&
-	    kernel_math_error(regs, "kernel x87 math error", 16))
-		return;
-
-	/*
-	 * Save the info for the exception handler and clear the error.
-	 */
-	task = current;
-	save_init_fpu(task);
-	task->thread.trap_no = 16;
-	task->thread.error_code = 0;
-	info.si_signo = SIGFPE;
-	info.si_errno = 0;
-	info.si_code = __SI_FAULT;
-	info.si_addr = ip;
-	/*
-	 * (~cwd & swd) will mask out exceptions that are not set to unmasked
-	 * status.  0x3f is the exception bits in these regs, 0x200 is the
-	 * C1 reg you need in case of a stack fault, 0x040 is the stack
-	 * fault bit.  We should only be taking one exception at a time,
-	 * so if this combination doesn't produce any single exception,
-	 * then we have a bad program that isn't synchronizing its FPU usage
-	 * and it will suffer the consequences since we won't be able to
-	 * fully reproduce the context of the exception
-	 */
-	cwd = get_fpu_cwd(task);
-	swd = get_fpu_swd(task);
-	switch (swd & ~cwd & 0x3f) {
-	case 0x000: /* No unmasked exception */
-	default: /* Multiple exceptions */
-		break;
-	case 0x001: /* Invalid Op */
-		/*
-		 * swd & 0x240 == 0x040: Stack Underflow
-		 * swd & 0x240 == 0x240: Stack Overflow
-		 * User must clear the SF bit (0x40) if set
-		 */
-		info.si_code = FPE_FLTINV;
-		break;
-	case 0x002: /* Denormalize */
-	case 0x010: /* Underflow */
-		info.si_code = FPE_FLTUND;
-		break;
-	case 0x004: /* Zero Divide */
-		info.si_code = FPE_FLTDIV;
-		break;
-	case 0x008: /* Overflow */
-		info.si_code = FPE_FLTOVF;
-		break;
-	case 0x020: /* Precision */
-		info.si_code = FPE_FLTRES;
-		break;
-	}
-	force_sig_info(SIGFPE, &info, task);
-}
-
-asmlinkage void bad_intr(void)
-{
-	printk("bad interrupt"); 
-}
-
-asmlinkage void do_simd_coprocessor_error(struct pt_regs *regs)
-{
-	void __user *ip = (void __user *)(regs->ip);
-	struct task_struct *task;
-	siginfo_t info;
-	unsigned short mxcsr;
-
-	conditional_sti(regs);
-	if (!user_mode(regs) &&
-        	kernel_math_error(regs, "kernel simd math error", 19))
-		return;
-
-	/*
-	 * Save the info for the exception handler and clear the error.
-	 */
-	task = current;
-	save_init_fpu(task);
-	task->thread.trap_no = 19;
-	task->thread.error_code = 0;
-	info.si_signo = SIGFPE;
-	info.si_errno = 0;
-	info.si_code = __SI_FAULT;
-	info.si_addr = ip;
-	/*
-	 * The SIMD FPU exceptions are handled a little differently, as there
-	 * is only a single status/control register.  Thus, to determine which
-	 * unmasked exception was caught we must mask the exception mask bits
-	 * at 0x1f80, and then use these to mask the exception bits at 0x3f.
-	 */
-	mxcsr = get_fpu_mxcsr(task);
-	switch (~((mxcsr & 0x1f80) >> 7) & (mxcsr & 0x3f)) {
-	case 0x000:
-	default:
-		break;
-	case 0x001: /* Invalid Op */
-		info.si_code = FPE_FLTINV;
-		break;
-	case 0x002: /* Denormalize */
-	case 0x010: /* Underflow */
-		info.si_code = FPE_FLTUND;
-		break;
-	case 0x004: /* Zero Divide */
-		info.si_code = FPE_FLTDIV;
-		break;
-	case 0x008: /* Overflow */
-		info.si_code = FPE_FLTOVF;
-		break;
-	case 0x020: /* Precision */
-		info.si_code = FPE_FLTRES;
-		break;
-	}
-	force_sig_info(SIGFPE, &info, task);
-}
-
-asmlinkage void do_spurious_interrupt_bug(struct pt_regs * regs)
-{
-}
-
-asmlinkage void __attribute__((weak)) smp_thermal_interrupt(void)
-{
-}
-
-asmlinkage void __attribute__((weak)) mce_threshold_interrupt(void)
-{
-}
-
-/*
- * 'math_state_restore()' saves the current math information in the
- * old math state array, and gets the new ones from the current task
- *
- * Careful.. There are problems with IBM-designed IRQ13 behaviour.
- * Don't touch unless you *really* know how it works.
- */
-asmlinkage void math_state_restore(void)
-{
-	struct task_struct *me = current;
-
-	if (!used_math()) {
-		local_irq_enable();
-		/*
-		 * does a slab alloc which can sleep
-		 */
-		if (init_fpu(me)) {
-			/*
-			 * ran out of memory!
-			 */
-			do_group_exit(SIGKILL);
-			return;
-		}
-		local_irq_disable();
-	}
-
-	clts();				/* Allow maths ops (or we recurse) */
-	/*
-	 * Paranoid restore. send a SIGSEGV if we fail to restore the state.
-	 */
-	if (unlikely(restore_fpu_checking(&me->thread.xstate->fxsave))) {
-		stts();
-		force_sig(SIGSEGV, me);
-		return;
-	}
-	task_thread_info(me)->status |= TS_USEDFPU;
-	me->fpu_counter++;
-}
-EXPORT_SYMBOL_GPL(math_state_restore);
-
-void __init trap_init(void)
-{
-	set_intr_gate(0, &divide_error);
-	set_intr_gate_ist(1, &debug, DEBUG_STACK);
-	set_intr_gate_ist(2, &nmi, NMI_STACK);
- 	set_system_gate_ist(3, &int3, DEBUG_STACK); /* int3 can be called from all */
-	set_system_gate(4, &overflow); /* int4 can be called from all */
-	set_intr_gate(5, &bounds);
-	set_intr_gate(6, &invalid_op);
-	set_intr_gate(7, &device_not_available);
-	set_intr_gate_ist(8, &double_fault, DOUBLEFAULT_STACK);
-	set_intr_gate(9, &coprocessor_segment_overrun);
-	set_intr_gate(10, &invalid_TSS);
-	set_intr_gate(11, &segment_not_present);
-	set_intr_gate_ist(12, &stack_segment, STACKFAULT_STACK);
-	set_intr_gate(13, &general_protection);
-	set_intr_gate(14, &page_fault);
-	set_intr_gate(15, &spurious_interrupt_bug);
-	set_intr_gate(16, &coprocessor_error);
-	set_intr_gate(17, &alignment_check);
-#ifdef CONFIG_X86_MCE
-	set_intr_gate_ist(18, &machine_check, MCE_STACK);
-#endif
-	set_intr_gate(19, &simd_coprocessor_error);
-
-#ifdef CONFIG_IA32_EMULATION
-	set_system_gate(IA32_SYSCALL_VECTOR, ia32_syscall);
-#endif
-	/*
-	 * initialize the per thread extended state:
-	 */
-	init_thread_xstate();
-	/*
-	 * Should be a barrier for any external CPU state:
-	 */
-	cpu_init();
-}
-
-static int __init oops_setup(char *s)
-{
-	if (!s)
-		return -EINVAL;
-	if (!strcmp(s, "panic"))
-		panic_on_oops = 1;
-	return 0;
-}
-early_param("oops", oops_setup);
-
-static int __init kstack_setup(char *s)
-{
-	if (!s)
-		return -EINVAL;
-	kstack_depth_to_print = simple_strtoul(s, NULL, 0);
-	return 0;
-}
-early_param("kstack", kstack_setup);
-
-static int __init code_bytes_setup(char *s)
-{
-	code_bytes = simple_strtoul(s, NULL, 0);
-	if (code_bytes > 8192)
-		code_bytes = 8192;
-
-	return 1;
-}
-__setup("code_bytes=", code_bytes_setup);
diff --git a/arch/x86/kernel/tsc.c b/arch/x86/kernel/tsc.c
index 8f98e9d..161bb85 100644
--- a/arch/x86/kernel/tsc.c
+++ b/arch/x86/kernel/tsc.c
@@ -104,7 +104,7 @@
 /*
  * Read TSC and the reference counters. Take care of SMI disturbance
  */
-static u64 tsc_read_refs(u64 *pm, u64 *hpet)
+static u64 tsc_read_refs(u64 *p, int hpet)
 {
 	u64 t1, t2;
 	int i;
@@ -112,9 +112,9 @@
 	for (i = 0; i < MAX_RETRIES; i++) {
 		t1 = get_cycles();
 		if (hpet)
-			*hpet = hpet_readl(HPET_COUNTER) & 0xFFFFFFFF;
+			*p = hpet_readl(HPET_COUNTER) & 0xFFFFFFFF;
 		else
-			*pm = acpi_pm_read_early();
+			*p = acpi_pm_read_early();
 		t2 = get_cycles();
 		if ((t2 - t1) < SMI_TRESHOLD)
 			return t2;
@@ -123,13 +123,59 @@
 }
 
 /*
+ * Calculate the TSC frequency from HPET reference
+ */
+static unsigned long calc_hpet_ref(u64 deltatsc, u64 hpet1, u64 hpet2)
+{
+	u64 tmp;
+
+	if (hpet2 < hpet1)
+		hpet2 += 0x100000000ULL;
+	hpet2 -= hpet1;
+	tmp = ((u64)hpet2 * hpet_readl(HPET_PERIOD));
+	do_div(tmp, 1000000);
+	do_div(deltatsc, tmp);
+
+	return (unsigned long) deltatsc;
+}
+
+/*
+ * Calculate the TSC frequency from PMTimer reference
+ */
+static unsigned long calc_pmtimer_ref(u64 deltatsc, u64 pm1, u64 pm2)
+{
+	u64 tmp;
+
+	if (!pm1 && !pm2)
+		return ULONG_MAX;
+
+	if (pm2 < pm1)
+		pm2 += (u64)ACPI_PM_OVRRUN;
+	pm2 -= pm1;
+	tmp = pm2 * 1000000000LL;
+	do_div(tmp, PMTMR_TICKS_PER_SEC);
+	do_div(deltatsc, tmp);
+
+	return (unsigned long) deltatsc;
+}
+
+#define CAL_MS		10
+#define CAL_LATCH	(CLOCK_TICK_RATE / (1000 / CAL_MS))
+#define CAL_PIT_LOOPS	1000
+
+#define CAL2_MS		50
+#define CAL2_LATCH	(CLOCK_TICK_RATE / (1000 / CAL2_MS))
+#define CAL2_PIT_LOOPS	5000
+
+
+/*
  * Try to calibrate the TSC against the Programmable
  * Interrupt Timer and return the frequency of the TSC
  * in kHz.
  *
  * Return ULONG_MAX on failure to calibrate.
  */
-static unsigned long pit_calibrate_tsc(void)
+static unsigned long pit_calibrate_tsc(u32 latch, unsigned long ms, int loopmin)
 {
 	u64 tsc, t1, t2, delta;
 	unsigned long tscmin, tscmax;
@@ -144,8 +190,8 @@
 	 * (LSB then MSB) to begin countdown.
 	 */
 	outb(0xb0, 0x43);
-	outb((CLOCK_TICK_RATE / (1000 / 50)) & 0xff, 0x42);
-	outb((CLOCK_TICK_RATE / (1000 / 50)) >> 8, 0x42);
+	outb(latch & 0xff, 0x42);
+	outb(latch >> 8, 0x42);
 
 	tsc = t1 = t2 = get_cycles();
 
@@ -166,31 +212,154 @@
 	/*
 	 * Sanity checks:
 	 *
-	 * If we were not able to read the PIT more than 5000
+	 * If we were not able to read the PIT more than loopmin
 	 * times, then we have been hit by a massive SMI
 	 *
 	 * If the maximum is 10 times larger than the minimum,
 	 * then we got hit by an SMI as well.
 	 */
-	if (pitcnt < 5000 || tscmax > 10 * tscmin)
+	if (pitcnt < loopmin || tscmax > 10 * tscmin)
 		return ULONG_MAX;
 
 	/* Calculate the PIT value */
 	delta = t2 - t1;
-	do_div(delta, 50);
+	do_div(delta, ms);
 	return delta;
 }
 
+/*
+ * This reads the current MSB of the PIT counter, and
+ * checks if we are running on sufficiently fast and
+ * non-virtualized hardware.
+ *
+ * Our expectations are:
+ *
+ *  - the PIT is running at roughly 1.19MHz
+ *
+ *  - each IO is going to take about 1us on real hardware,
+ *    but we allow it to be much faster (by a factor of 10) or
+ *    _slightly_ slower (ie we allow up to a 2us read+counter
+ *    update - anything else implies a unacceptably slow CPU
+ *    or PIT for the fast calibration to work.
+ *
+ *  - with 256 PIT ticks to read the value, we have 214us to
+ *    see the same MSB (and overhead like doing a single TSC
+ *    read per MSB value etc).
+ *
+ *  - We're doing 2 reads per loop (LSB, MSB), and we expect
+ *    them each to take about a microsecond on real hardware.
+ *    So we expect a count value of around 100. But we'll be
+ *    generous, and accept anything over 50.
+ *
+ *  - if the PIT is stuck, and we see *many* more reads, we
+ *    return early (and the next caller of pit_expect_msb()
+ *    then consider it a failure when they don't see the
+ *    next expected value).
+ *
+ * These expectations mean that we know that we have seen the
+ * transition from one expected value to another with a fairly
+ * high accuracy, and we didn't miss any events. We can thus
+ * use the TSC value at the transitions to calculate a pretty
+ * good value for the TSC frequencty.
+ */
+static inline int pit_expect_msb(unsigned char val)
+{
+	int count = 0;
+
+	for (count = 0; count < 50000; count++) {
+		/* Ignore LSB */
+		inb(0x42);
+		if (inb(0x42) != val)
+			break;
+	}
+	return count > 50;
+}
+
+/*
+ * How many MSB values do we want to see? We aim for a
+ * 15ms calibration, which assuming a 2us counter read
+ * error should give us roughly 150 ppm precision for
+ * the calibration.
+ */
+#define QUICK_PIT_MS 15
+#define QUICK_PIT_ITERATIONS (QUICK_PIT_MS * PIT_TICK_RATE / 1000 / 256)
+
+static unsigned long quick_pit_calibrate(void)
+{
+	/* Set the Gate high, disable speaker */
+	outb((inb(0x61) & ~0x02) | 0x01, 0x61);
+
+	/*
+	 * Counter 2, mode 0 (one-shot), binary count
+	 *
+	 * NOTE! Mode 2 decrements by two (and then the
+	 * output is flipped each time, giving the same
+	 * final output frequency as a decrement-by-one),
+	 * so mode 0 is much better when looking at the
+	 * individual counts.
+	 */
+	outb(0xb0, 0x43);
+
+	/* Start at 0xffff */
+	outb(0xff, 0x42);
+	outb(0xff, 0x42);
+
+	if (pit_expect_msb(0xff)) {
+		int i;
+		u64 t1, t2, delta;
+		unsigned char expect = 0xfe;
+
+		t1 = get_cycles();
+		for (i = 0; i < QUICK_PIT_ITERATIONS; i++, expect--) {
+			if (!pit_expect_msb(expect))
+				goto failed;
+		}
+		t2 = get_cycles();
+
+		/*
+		 * Make sure we can rely on the second TSC timestamp:
+		 */
+		if (!pit_expect_msb(expect))
+			goto failed;
+
+		/*
+		 * Ok, if we get here, then we've seen the
+		 * MSB of the PIT decrement QUICK_PIT_ITERATIONS
+		 * times, and each MSB had many hits, so we never
+		 * had any sudden jumps.
+		 *
+		 * As a result, we can depend on there not being
+		 * any odd delays anywhere, and the TSC reads are
+		 * reliable.
+		 *
+		 * kHz = ticks / time-in-seconds / 1000;
+		 * kHz = (t2 - t1) / (QPI * 256 / PIT_TICK_RATE) / 1000
+		 * kHz = ((t2 - t1) * PIT_TICK_RATE) / (QPI * 256 * 1000)
+		 */
+		delta = (t2 - t1)*PIT_TICK_RATE;
+		do_div(delta, QUICK_PIT_ITERATIONS*256*1000);
+		printk("Fast TSC calibration using PIT\n");
+		return delta;
+	}
+failed:
+	return 0;
+}
 
 /**
  * native_calibrate_tsc - calibrate the tsc on boot
  */
 unsigned long native_calibrate_tsc(void)
 {
-	u64 tsc1, tsc2, delta, pm1, pm2, hpet1, hpet2;
+	u64 tsc1, tsc2, delta, ref1, ref2;
 	unsigned long tsc_pit_min = ULONG_MAX, tsc_ref_min = ULONG_MAX;
-	unsigned long flags;
-	int hpet = is_hpet_enabled(), i;
+	unsigned long flags, latch, ms, fast_calibrate;
+	int hpet = is_hpet_enabled(), i, loopmin;
+
+	local_irq_save(flags);
+	fast_calibrate = quick_pit_calibrate();
+	local_irq_restore(flags);
+	if (fast_calibrate)
+		return fast_calibrate;
 
 	/*
 	 * Run 5 calibration loops to get the lowest frequency value
@@ -216,7 +385,13 @@
 	 * calibration delay loop as we have to wait for a certain
 	 * amount of time anyway.
 	 */
-	for (i = 0; i < 5; i++) {
+
+	/* Preset PIT loop values */
+	latch = CAL_LATCH;
+	ms = CAL_MS;
+	loopmin = CAL_PIT_LOOPS;
+
+	for (i = 0; i < 3; i++) {
 		unsigned long tsc_pit_khz;
 
 		/*
@@ -226,16 +401,16 @@
 		 * read the end value.
 		 */
 		local_irq_save(flags);
-		tsc1 = tsc_read_refs(&pm1, hpet ? &hpet1 : NULL);
-		tsc_pit_khz = pit_calibrate_tsc();
-		tsc2 = tsc_read_refs(&pm2, hpet ? &hpet2 : NULL);
+		tsc1 = tsc_read_refs(&ref1, hpet);
+		tsc_pit_khz = pit_calibrate_tsc(latch, ms, loopmin);
+		tsc2 = tsc_read_refs(&ref2, hpet);
 		local_irq_restore(flags);
 
 		/* Pick the lowest PIT TSC calibration so far */
 		tsc_pit_min = min(tsc_pit_min, tsc_pit_khz);
 
 		/* hpet or pmtimer available ? */
-		if (!hpet && !pm1 && !pm2)
+		if (!hpet && !ref1 && !ref2)
 			continue;
 
 		/* Check, whether the sampling was disturbed by an SMI */
@@ -243,23 +418,41 @@
 			continue;
 
 		tsc2 = (tsc2 - tsc1) * 1000000LL;
+		if (hpet)
+			tsc2 = calc_hpet_ref(tsc2, ref1, ref2);
+		else
+			tsc2 = calc_pmtimer_ref(tsc2, ref1, ref2);
 
-		if (hpet) {
-			if (hpet2 < hpet1)
-				hpet2 += 0x100000000ULL;
-			hpet2 -= hpet1;
-			tsc1 = ((u64)hpet2 * hpet_readl(HPET_PERIOD));
-			do_div(tsc1, 1000000);
-		} else {
-			if (pm2 < pm1)
-				pm2 += (u64)ACPI_PM_OVRRUN;
-			pm2 -= pm1;
-			tsc1 = pm2 * 1000000000LL;
-			do_div(tsc1, PMTMR_TICKS_PER_SEC);
+		tsc_ref_min = min(tsc_ref_min, (unsigned long) tsc2);
+
+		/* Check the reference deviation */
+		delta = ((u64) tsc_pit_min) * 100;
+		do_div(delta, tsc_ref_min);
+
+		/*
+		 * If both calibration results are inside a 10% window
+		 * then we can be sure, that the calibration
+		 * succeeded. We break out of the loop right away. We
+		 * use the reference value, as it is more precise.
+		 */
+		if (delta >= 90 && delta <= 110) {
+			printk(KERN_INFO
+			       "TSC: PIT calibration matches %s. %d loops\n",
+			       hpet ? "HPET" : "PMTIMER", i + 1);
+			return tsc_ref_min;
 		}
 
-		do_div(tsc2, tsc1);
-		tsc_ref_min = min(tsc_ref_min, (unsigned long) tsc2);
+		/*
+		 * Check whether PIT failed more than once. This
+		 * happens in virtualized environments. We need to
+		 * give the virtual PC a slightly longer timeframe for
+		 * the HPET/PMTIMER to make the result precise.
+		 */
+		if (i == 1 && tsc_pit_min == ULONG_MAX) {
+			latch = CAL2_LATCH;
+			ms = CAL2_MS;
+			loopmin = CAL2_PIT_LOOPS;
+		}
 	}
 
 	/*
@@ -270,7 +463,7 @@
 		printk(KERN_WARNING "TSC: Unable to calibrate against PIT\n");
 
 		/* We don't have an alternative source, disable TSC */
-		if (!hpet && !pm1 && !pm2) {
+		if (!hpet && !ref1 && !ref2) {
 			printk("TSC: No reference (HPET/PMTIMER) available\n");
 			return 0;
 		}
@@ -278,7 +471,7 @@
 		/* The alternative source failed as well, disable TSC */
 		if (tsc_ref_min == ULONG_MAX) {
 			printk(KERN_WARNING "TSC: HPET/PMTIMER calibration "
-			       "failed due to SMI disturbance.\n");
+			       "failed.\n");
 			return 0;
 		}
 
@@ -290,44 +483,25 @@
 	}
 
 	/* We don't have an alternative source, use the PIT calibration value */
-	if (!hpet && !pm1 && !pm2) {
+	if (!hpet && !ref1 && !ref2) {
 		printk(KERN_INFO "TSC: Using PIT calibration value\n");
 		return tsc_pit_min;
 	}
 
 	/* The alternative source failed, use the PIT calibration value */
 	if (tsc_ref_min == ULONG_MAX) {
-		printk(KERN_WARNING "TSC: HPET/PMTIMER calibration failed due "
-		       "to SMI disturbance. Using PIT calibration\n");
+		printk(KERN_WARNING "TSC: HPET/PMTIMER calibration failed. "
+		       "Using PIT calibration\n");
 		return tsc_pit_min;
 	}
 
-	/* Check the reference deviation */
-	delta = ((u64) tsc_pit_min) * 100;
-	do_div(delta, tsc_ref_min);
-
-	/*
-	 * If both calibration results are inside a 5% window, the we
-	 * use the lower frequency of those as it is probably the
-	 * closest estimate.
-	 */
-	if (delta >= 95 && delta <= 105) {
-		printk(KERN_INFO "TSC: PIT calibration confirmed by %s.\n",
-		       hpet ? "HPET" : "PMTIMER");
-		printk(KERN_INFO "TSC: using %s calibration value\n",
-		       tsc_pit_min <= tsc_ref_min ? "PIT" :
-		       hpet ? "HPET" : "PMTIMER");
-		return tsc_pit_min <= tsc_ref_min ? tsc_pit_min : tsc_ref_min;
-	}
-
-	printk(KERN_WARNING "TSC: PIT calibration deviates from %s: %lu %lu.\n",
-	       hpet ? "HPET" : "PMTIMER", tsc_pit_min, tsc_ref_min);
-
 	/*
 	 * The calibration values differ too much. In doubt, we use
 	 * the PIT value as we know that there are PMTIMERs around
-	 * running at double speed.
+	 * running at double speed. At least we let the user know:
 	 */
+	printk(KERN_WARNING "TSC: PIT calibration deviates from %s: %lu %lu.\n",
+	       hpet ? "HPET" : "PMTIMER", tsc_pit_min, tsc_ref_min);
 	printk(KERN_INFO "TSC: Using PIT calibration value\n");
 	return tsc_pit_min;
 }
diff --git a/arch/x86/kernel/visws_quirks.c b/arch/x86/kernel/visws_quirks.c
index 594ef47..61a97e6 100644
--- a/arch/x86/kernel/visws_quirks.c
+++ b/arch/x86/kernel/visws_quirks.c
@@ -25,45 +25,31 @@
 #include <asm/visws/cobalt.h>
 #include <asm/visws/piix4.h>
 #include <asm/arch_hooks.h>
+#include <asm/io_apic.h>
 #include <asm/fixmap.h>
 #include <asm/reboot.h>
 #include <asm/setup.h>
 #include <asm/e820.h>
-#include <asm/smp.h>
 #include <asm/io.h>
 
 #include <mach_ipi.h>
 
 #include "mach_apic.h"
 
-#include <linux/init.h>
-#include <linux/smp.h>
-
 #include <linux/kernel_stat.h>
-#include <linux/interrupt.h>
-#include <linux/init.h>
 
-#include <asm/io.h>
-#include <asm/apic.h>
 #include <asm/i8259.h>
 #include <asm/irq_vectors.h>
-#include <asm/visws/cobalt.h>
 #include <asm/visws/lithium.h>
-#include <asm/visws/piix4.h>
 
 #include <linux/sched.h>
 #include <linux/kernel.h>
-#include <linux/init.h>
 #include <linux/pci.h>
 #include <linux/pci_ids.h>
 
 extern int no_broadcast;
 
-#include <asm/io.h>
 #include <asm/apic.h>
-#include <asm/arch_hooks.h>
-#include <asm/visws/cobalt.h>
-#include <asm/visws/lithium.h>
 
 char visws_board_type	= -1;
 char visws_board_rev	= -1;
diff --git a/arch/x86/kernel/vm86_32.c b/arch/x86/kernel/vm86_32.c
index 38f566f..4eeb5cf 100644
--- a/arch/x86/kernel/vm86_32.c
+++ b/arch/x86/kernel/vm86_32.c
@@ -46,6 +46,7 @@
 #include <asm/io.h>
 #include <asm/tlbflush.h>
 #include <asm/irq.h>
+#include <asm/syscalls.h>
 
 /*
  * Known problems:
diff --git a/arch/x86/kernel/vmi_32.c b/arch/x86/kernel/vmi_32.c
index 6ca515d..8b6c393 100644
--- a/arch/x86/kernel/vmi_32.c
+++ b/arch/x86/kernel/vmi_32.c
@@ -235,7 +235,7 @@
 				const void *desc)
 {
 	u32 *ldt_entry = (u32 *)desc;
-	vmi_ops.write_idt_entry(dt, entry, ldt_entry[0], ldt_entry[1]);
+	vmi_ops.write_ldt_entry(dt, entry, ldt_entry[0], ldt_entry[1]);
 }
 
 static void vmi_load_sp0(struct tss_struct *tss,
@@ -393,13 +393,13 @@
 }
 #endif
 
-static void vmi_allocate_pte(struct mm_struct *mm, u32 pfn)
+static void vmi_allocate_pte(struct mm_struct *mm, unsigned long pfn)
 {
 	vmi_set_page_type(pfn, VMI_PAGE_L1);
 	vmi_ops.allocate_page(pfn, VMI_PAGE_L1, 0, 0, 0);
 }
 
-static void vmi_allocate_pmd(struct mm_struct *mm, u32 pfn)
+static void vmi_allocate_pmd(struct mm_struct *mm, unsigned long pfn)
 {
  	/*
 	 * This call comes in very early, before mem_map is setup.
@@ -410,20 +410,20 @@
 	vmi_ops.allocate_page(pfn, VMI_PAGE_L2, 0, 0, 0);
 }
 
-static void vmi_allocate_pmd_clone(u32 pfn, u32 clonepfn, u32 start, u32 count)
+static void vmi_allocate_pmd_clone(unsigned long pfn, unsigned long clonepfn, unsigned long start, unsigned long count)
 {
  	vmi_set_page_type(pfn, VMI_PAGE_L2 | VMI_PAGE_CLONE);
 	vmi_check_page_type(clonepfn, VMI_PAGE_L2);
 	vmi_ops.allocate_page(pfn, VMI_PAGE_L2 | VMI_PAGE_CLONE, clonepfn, start, count);
 }
 
-static void vmi_release_pte(u32 pfn)
+static void vmi_release_pte(unsigned long pfn)
 {
 	vmi_ops.release_page(pfn, VMI_PAGE_L1);
 	vmi_set_page_type(pfn, VMI_PAGE_NORMAL);
 }
 
-static void vmi_release_pmd(u32 pfn)
+static void vmi_release_pmd(unsigned long pfn)
 {
 	vmi_ops.release_page(pfn, VMI_PAGE_L2);
 	vmi_set_page_type(pfn, VMI_PAGE_NORMAL);
@@ -905,8 +905,8 @@
 #endif
 
 #ifdef CONFIG_X86_LOCAL_APIC
-	para_fill(pv_apic_ops.apic_read, APICRead);
-	para_fill(pv_apic_ops.apic_write, APICWrite);
+       para_fill(apic_ops->read, APICRead);
+       para_fill(apic_ops->write, APICWrite);
 #endif
 
 	/*
diff --git a/arch/x86/kernel/vmlinux_32.lds.S b/arch/x86/kernel/vmlinux_32.lds.S
index af5bdad..a9b8560 100644
--- a/arch/x86/kernel/vmlinux_32.lds.S
+++ b/arch/x86/kernel/vmlinux_32.lds.S
@@ -140,10 +140,10 @@
 	*(.con_initcall.init)
   	__con_initcall_end = .;
   }
-  .x86cpuvendor.init : AT(ADDR(.x86cpuvendor.init) - LOAD_OFFSET) {
-	__x86cpuvendor_start = .;
-	*(.x86cpuvendor.init)
-	__x86cpuvendor_end = .;
+  .x86_cpu_dev.init : AT(ADDR(.x86_cpu_dev.init) - LOAD_OFFSET) {
+	__x86_cpu_dev_start = .;
+	*(.x86_cpu_dev.init)
+	__x86_cpu_dev_end = .;
   }
   SECURITY_INIT
   . = ALIGN(4);
@@ -180,6 +180,7 @@
   . = ALIGN(PAGE_SIZE);
   .data.percpu  : AT(ADDR(.data.percpu) - LOAD_OFFSET) {
 	__per_cpu_start = .;
+	*(.data.percpu.page_aligned)
 	*(.data.percpu)
 	*(.data.percpu.shared_aligned)
 	__per_cpu_end = .;
diff --git a/arch/x86/kernel/vmlinux_64.lds.S b/arch/x86/kernel/vmlinux_64.lds.S
index 63e5c1a..46e0544 100644
--- a/arch/x86/kernel/vmlinux_64.lds.S
+++ b/arch/x86/kernel/vmlinux_64.lds.S
@@ -168,12 +168,11 @@
 	*(.con_initcall.init)
   }
   __con_initcall_end = .;
-  . = ALIGN(16);
-  __x86cpuvendor_start = .;
-  .x86cpuvendor.init : AT(ADDR(.x86cpuvendor.init) - LOAD_OFFSET) {
-	*(.x86cpuvendor.init)
+  __x86_cpu_dev_start = .;
+  .x86_cpu_dev.init : AT(ADDR(.x86_cpu_dev.init) - LOAD_OFFSET) {
+	*(.x86_cpu_dev.init)
   }
-  __x86cpuvendor_end = .;
+  __x86_cpu_dev_end = .;
   SECURITY_INIT
 
   . = ALIGN(8);
diff --git a/arch/x86/kernel/vsmp_64.c b/arch/x86/kernel/vsmp_64.c
index 0c029e8..7766d36 100644
--- a/arch/x86/kernel/vsmp_64.c
+++ b/arch/x86/kernel/vsmp_64.c
@@ -61,7 +61,7 @@
 	native_restore_fl((flags | X86_EFLAGS_IF) & (~X86_EFLAGS_AC));
 }
 
-static unsigned __init vsmp_patch(u8 type, u16 clobbers, void *ibuf,
+static unsigned __init_or_module vsmp_patch(u8 type, u16 clobbers, void *ibuf,
 				  unsigned long addr, unsigned len)
 {
 	switch (type) {
diff --git a/arch/x86/kernel/xsave.c b/arch/x86/kernel/xsave.c
new file mode 100644
index 0000000..9abac8a
--- /dev/null
+++ b/arch/x86/kernel/xsave.c
@@ -0,0 +1,345 @@
+/*
+ * xsave/xrstor support.
+ *
+ * Author: Suresh Siddha <suresh.b.siddha@intel.com>
+ */
+#include <linux/bootmem.h>
+#include <linux/compat.h>
+#include <asm/i387.h>
+#ifdef CONFIG_IA32_EMULATION
+#include <asm/sigcontext32.h>
+#endif
+#include <asm/xcr.h>
+
+/*
+ * Supported feature mask by the CPU and the kernel.
+ */
+u64 pcntxt_mask;
+
+struct _fpx_sw_bytes fx_sw_reserved;
+#ifdef CONFIG_IA32_EMULATION
+struct _fpx_sw_bytes fx_sw_reserved_ia32;
+#endif
+
+/*
+ * Check for the presence of extended state information in the
+ * user fpstate pointer in the sigcontext.
+ */
+int check_for_xstate(struct i387_fxsave_struct __user *buf,
+		     void __user *fpstate,
+		     struct _fpx_sw_bytes *fx_sw_user)
+{
+	int min_xstate_size = sizeof(struct i387_fxsave_struct) +
+			      sizeof(struct xsave_hdr_struct);
+	unsigned int magic2;
+	int err;
+
+	err = __copy_from_user(fx_sw_user, &buf->sw_reserved[0],
+			       sizeof(struct _fpx_sw_bytes));
+
+	if (err)
+		return err;
+
+	/*
+	 * First Magic check failed.
+	 */
+	if (fx_sw_user->magic1 != FP_XSTATE_MAGIC1)
+		return -1;
+
+	/*
+	 * Check for error scenarios.
+	 */
+	if (fx_sw_user->xstate_size < min_xstate_size ||
+	    fx_sw_user->xstate_size > xstate_size ||
+	    fx_sw_user->xstate_size > fx_sw_user->extended_size)
+		return -1;
+
+	err = __get_user(magic2, (__u32 *) (((void *)fpstate) +
+					    fx_sw_user->extended_size -
+					    FP_XSTATE_MAGIC2_SIZE));
+	/*
+	 * Check for the presence of second magic word at the end of memory
+	 * layout. This detects the case where the user just copied the legacy
+	 * fpstate layout with out copying the extended state information
+	 * in the memory layout.
+	 */
+	if (err || magic2 != FP_XSTATE_MAGIC2)
+		return -1;
+
+	return 0;
+}
+
+#ifdef CONFIG_X86_64
+/*
+ * Signal frame handlers.
+ */
+
+int save_i387_xstate(void __user *buf)
+{
+	struct task_struct *tsk = current;
+	int err = 0;
+
+	if (!access_ok(VERIFY_WRITE, buf, sig_xstate_size))
+		return -EACCES;
+
+	BUG_ON(sig_xstate_size < xstate_size);
+
+	if ((unsigned long)buf % 64)
+		printk("save_i387_xstate: bad fpstate %p\n", buf);
+
+	if (!used_math())
+		return 0;
+	clear_used_math(); /* trigger finit */
+	if (task_thread_info(tsk)->status & TS_USEDFPU) {
+		/*
+	 	 * Start with clearing the user buffer. This will present a
+	 	 * clean context for the bytes not touched by the fxsave/xsave.
+		 */
+		err = __clear_user(buf, sig_xstate_size);
+		if (err)
+			return err;
+
+		if (task_thread_info(tsk)->status & TS_XSAVE)
+			err = xsave_user(buf);
+		else
+			err = fxsave_user(buf);
+
+		if (err)
+			return err;
+		task_thread_info(tsk)->status &= ~TS_USEDFPU;
+		stts();
+	} else {
+		if (__copy_to_user(buf, &tsk->thread.xstate->fxsave,
+				   xstate_size))
+			return -1;
+	}
+
+	if (task_thread_info(tsk)->status & TS_XSAVE) {
+		struct _fpstate __user *fx = buf;
+		struct _xstate __user *x = buf;
+		u64 xstate_bv;
+
+		err = __copy_to_user(&fx->sw_reserved, &fx_sw_reserved,
+				     sizeof(struct _fpx_sw_bytes));
+
+		err |= __put_user(FP_XSTATE_MAGIC2,
+				  (__u32 __user *) (buf + sig_xstate_size
+						    - FP_XSTATE_MAGIC2_SIZE));
+
+		/*
+		 * Read the xstate_bv which we copied (directly from the cpu or
+		 * from the state in task struct) to the user buffers and
+		 * set the FP/SSE bits.
+		 */
+		err |= __get_user(xstate_bv, &x->xstate_hdr.xstate_bv);
+
+		/*
+		 * For legacy compatible, we always set FP/SSE bits in the bit
+		 * vector while saving the state to the user context. This will
+		 * enable us capturing any changes(during sigreturn) to
+		 * the FP/SSE bits by the legacy applications which don't touch
+		 * xstate_bv in the xsave header.
+		 *
+		 * xsave aware apps can change the xstate_bv in the xsave
+		 * header as well as change any contents in the memory layout.
+		 * xrestore as part of sigreturn will capture all the changes.
+		 */
+		xstate_bv |= XSTATE_FPSSE;
+
+		err |= __put_user(xstate_bv, &x->xstate_hdr.xstate_bv);
+
+		if (err)
+			return err;
+	}
+
+	return 1;
+}
+
+/*
+ * Restore the extended state if present. Otherwise, restore the FP/SSE
+ * state.
+ */
+int restore_user_xstate(void __user *buf)
+{
+	struct _fpx_sw_bytes fx_sw_user;
+	u64 mask;
+	int err;
+
+	if (((unsigned long)buf % 64) ||
+	     check_for_xstate(buf, buf, &fx_sw_user))
+		goto fx_only;
+
+	mask = fx_sw_user.xstate_bv;
+
+	/*
+	 * restore the state passed by the user.
+	 */
+	err = xrestore_user(buf, mask);
+	if (err)
+		return err;
+
+	/*
+	 * init the state skipped by the user.
+	 */
+	mask = pcntxt_mask & ~mask;
+
+	xrstor_state(init_xstate_buf, mask);
+
+	return 0;
+
+fx_only:
+	/*
+	 * couldn't find the extended state information in the
+	 * memory layout. Restore just the FP/SSE and init all
+	 * the other extended state.
+	 */
+	xrstor_state(init_xstate_buf, pcntxt_mask & ~XSTATE_FPSSE);
+	return fxrstor_checking((__force struct i387_fxsave_struct *)buf);
+}
+
+/*
+ * This restores directly out of user space. Exceptions are handled.
+ */
+int restore_i387_xstate(void __user *buf)
+{
+	struct task_struct *tsk = current;
+	int err = 0;
+
+	if (!buf) {
+		if (used_math())
+			goto clear;
+		return 0;
+	} else
+		if (!access_ok(VERIFY_READ, buf, sig_xstate_size))
+			return -EACCES;
+
+	if (!used_math()) {
+		err = init_fpu(tsk);
+		if (err)
+			return err;
+	}
+
+	if (!(task_thread_info(current)->status & TS_USEDFPU)) {
+		clts();
+		task_thread_info(current)->status |= TS_USEDFPU;
+	}
+	if (task_thread_info(tsk)->status & TS_XSAVE)
+		err = restore_user_xstate(buf);
+	else
+		err = fxrstor_checking((__force struct i387_fxsave_struct *)
+				       buf);
+	if (unlikely(err)) {
+		/*
+		 * Encountered an error while doing the restore from the
+		 * user buffer, clear the fpu state.
+		 */
+clear:
+		clear_fpu(tsk);
+		clear_used_math();
+	}
+	return err;
+}
+#endif
+
+/*
+ * Prepare the SW reserved portion of the fxsave memory layout, indicating
+ * the presence of the extended state information in the memory layout
+ * pointed by the fpstate pointer in the sigcontext.
+ * This will be saved when ever the FP and extended state context is
+ * saved on the user stack during the signal handler delivery to the user.
+ */
+void prepare_fx_sw_frame(void)
+{
+	int size_extended = (xstate_size - sizeof(struct i387_fxsave_struct)) +
+			     FP_XSTATE_MAGIC2_SIZE;
+
+	sig_xstate_size = sizeof(struct _fpstate) + size_extended;
+
+#ifdef CONFIG_IA32_EMULATION
+	sig_xstate_ia32_size = sizeof(struct _fpstate_ia32) + size_extended;
+#endif
+
+	memset(&fx_sw_reserved, 0, sizeof(fx_sw_reserved));
+
+	fx_sw_reserved.magic1 = FP_XSTATE_MAGIC1;
+	fx_sw_reserved.extended_size = sig_xstate_size;
+	fx_sw_reserved.xstate_bv = pcntxt_mask;
+	fx_sw_reserved.xstate_size = xstate_size;
+#ifdef CONFIG_IA32_EMULATION
+	memcpy(&fx_sw_reserved_ia32, &fx_sw_reserved,
+	       sizeof(struct _fpx_sw_bytes));
+	fx_sw_reserved_ia32.extended_size = sig_xstate_ia32_size;
+#endif
+}
+
+/*
+ * Represents init state for the supported extended state.
+ */
+struct xsave_struct *init_xstate_buf;
+
+#ifdef CONFIG_X86_64
+unsigned int sig_xstate_size = sizeof(struct _fpstate);
+#endif
+
+/*
+ * Enable the extended processor state save/restore feature
+ */
+void __cpuinit xsave_init(void)
+{
+	if (!cpu_has_xsave)
+		return;
+
+	set_in_cr4(X86_CR4_OSXSAVE);
+
+	/*
+	 * Enable all the features that the HW is capable of
+	 * and the Linux kernel is aware of.
+	 */
+	xsetbv(XCR_XFEATURE_ENABLED_MASK, pcntxt_mask);
+}
+
+/*
+ * setup the xstate image representing the init state
+ */
+static void __init setup_xstate_init(void)
+{
+	init_xstate_buf = alloc_bootmem(xstate_size);
+	init_xstate_buf->i387.mxcsr = MXCSR_DEFAULT;
+}
+
+/*
+ * Enable and initialize the xsave feature.
+ */
+void __init xsave_cntxt_init(void)
+{
+	unsigned int eax, ebx, ecx, edx;
+
+	cpuid_count(0xd, 0, &eax, &ebx, &ecx, &edx);
+	pcntxt_mask = eax + ((u64)edx << 32);
+
+	if ((pcntxt_mask & XSTATE_FPSSE) != XSTATE_FPSSE) {
+		printk(KERN_ERR "FP/SSE not shown under xsave features 0x%llx\n",
+		       pcntxt_mask);
+		BUG();
+	}
+
+	/*
+	 * for now OS knows only about FP/SSE
+	 */
+	pcntxt_mask = pcntxt_mask & XCNTXT_MASK;
+	xsave_init();
+
+	/*
+	 * Recompute the context size for enabled features
+	 */
+	cpuid_count(0xd, 0, &eax, &ebx, &ecx, &edx);
+	xstate_size = ebx;
+
+	prepare_fx_sw_frame();
+
+	setup_xstate_init();
+
+	printk(KERN_INFO "xsave/xrstor: enabled xstate_bv 0x%llx, "
+	       "cntxt size 0x%x\n",
+	       pcntxt_mask, xstate_size);
+}
diff --git a/arch/x86/kvm/vmx.h b/arch/x86/kvm/vmx.h
index 23e8373..17e2599 100644
--- a/arch/x86/kvm/vmx.h
+++ b/arch/x86/kvm/vmx.h
@@ -331,21 +331,6 @@
 
 #define AR_RESERVD_MASK 0xfffe0f00
 
-#define MSR_IA32_VMX_BASIC                      0x480
-#define MSR_IA32_VMX_PINBASED_CTLS              0x481
-#define MSR_IA32_VMX_PROCBASED_CTLS             0x482
-#define MSR_IA32_VMX_EXIT_CTLS                  0x483
-#define MSR_IA32_VMX_ENTRY_CTLS                 0x484
-#define MSR_IA32_VMX_MISC                       0x485
-#define MSR_IA32_VMX_CR0_FIXED0                 0x486
-#define MSR_IA32_VMX_CR0_FIXED1                 0x487
-#define MSR_IA32_VMX_CR4_FIXED0                 0x488
-#define MSR_IA32_VMX_CR4_FIXED1                 0x489
-#define MSR_IA32_VMX_VMCS_ENUM                  0x48a
-#define MSR_IA32_VMX_PROCBASED_CTLS2            0x48b
-#define MSR_IA32_VMX_EPT_VPID_CAP               0x48c
-
-#define MSR_IA32_FEATURE_CONTROL                0x3a
 #define MSR_IA32_FEATURE_CONTROL_LOCKED         0x1
 #define MSR_IA32_FEATURE_CONTROL_VMXON_ENABLED  0x4
 
diff --git a/arch/x86/lguest/boot.c b/arch/x86/lguest/boot.c
index d9249a8..65f0b8a 100644
--- a/arch/x86/lguest/boot.c
+++ b/arch/x86/lguest/boot.c
@@ -55,6 +55,7 @@
 #include <linux/lguest_launcher.h>
 #include <linux/virtio_console.h>
 #include <linux/pm.h>
+#include <asm/apic.h>
 #include <asm/lguest.h>
 #include <asm/paravirt.h>
 #include <asm/param.h>
@@ -783,14 +784,44 @@
  * code qualifies for Advanced.  It will also never interrupt anything.  It
  * does, however, allow us to get through the Linux boot code. */
 #ifdef CONFIG_X86_LOCAL_APIC
-static void lguest_apic_write(unsigned long reg, u32 v)
+static void lguest_apic_write(u32 reg, u32 v)
 {
 }
 
-static u32 lguest_apic_read(unsigned long reg)
+static u32 lguest_apic_read(u32 reg)
 {
 	return 0;
 }
+
+static u64 lguest_apic_icr_read(void)
+{
+	return 0;
+}
+
+static void lguest_apic_icr_write(u32 low, u32 id)
+{
+	/* Warn to see if there's any stray references */
+	WARN_ON(1);
+}
+
+static void lguest_apic_wait_icr_idle(void)
+{
+	return;
+}
+
+static u32 lguest_apic_safe_wait_icr_idle(void)
+{
+	return 0;
+}
+
+static struct apic_ops lguest_basic_apic_ops = {
+	.read = lguest_apic_read,
+	.write = lguest_apic_write,
+	.icr_read = lguest_apic_icr_read,
+	.icr_write = lguest_apic_icr_write,
+	.wait_icr_idle = lguest_apic_wait_icr_idle,
+	.safe_wait_icr_idle = lguest_apic_safe_wait_icr_idle,
+};
 #endif
 
 /* STOP!  Until an interrupt comes in. */
@@ -990,8 +1021,7 @@
 
 #ifdef CONFIG_X86_LOCAL_APIC
 	/* apic read/write intercepts */
-	pv_apic_ops.apic_write = lguest_apic_write;
-	pv_apic_ops.apic_read = lguest_apic_read;
+	apic_ops = &lguest_basic_apic_ops;
 #endif
 
 	/* time operations */
diff --git a/arch/x86/lib/Makefile b/arch/x86/lib/Makefile
index aa3fa41..55e11aa 100644
--- a/arch/x86/lib/Makefile
+++ b/arch/x86/lib/Makefile
@@ -17,9 +17,6 @@
         lib-$(CONFIG_X86_USE_3DNOW) += mmx_32.o
 else
         obj-y += io_64.o iomap_copy_64.o
-
-        CFLAGS_csum-partial_64.o := -funroll-loops
-
         lib-y += csum-partial_64.o csum-copy_64.o csum-wrappers_64.o
         lib-y += thunk_64.o clear_page_64.o copy_page_64.o
         lib-y += memmove_64.o memset_64.o
diff --git a/arch/x86/lib/msr-on-cpu.c b/arch/x86/lib/msr-on-cpu.c
index 01b868b..321cf72 100644
--- a/arch/x86/lib/msr-on-cpu.c
+++ b/arch/x86/lib/msr-on-cpu.c
@@ -16,37 +16,46 @@
 	rdmsr(rv->msr_no, rv->l, rv->h);
 }
 
-static void __rdmsr_safe_on_cpu(void *info)
+static void __wrmsr_on_cpu(void *info)
 {
 	struct msr_info *rv = info;
 
-	rv->err = rdmsr_safe(rv->msr_no, &rv->l, &rv->h);
+	wrmsr(rv->msr_no, rv->l, rv->h);
 }
 
-static int _rdmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 *l, u32 *h, int safe)
+int rdmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 *l, u32 *h)
 {
-	int err = 0;
+	int err;
 	struct msr_info rv;
 
 	rv.msr_no = msr_no;
-	if (safe) {
-		err = smp_call_function_single(cpu, __rdmsr_safe_on_cpu,
-					       &rv, 1);
-		err = err ? err : rv.err;
-	} else {
-		err = smp_call_function_single(cpu, __rdmsr_on_cpu, &rv, 1);
-	}
+	err = smp_call_function_single(cpu, __rdmsr_on_cpu, &rv, 1);
 	*l = rv.l;
 	*h = rv.h;
 
 	return err;
 }
 
-static void __wrmsr_on_cpu(void *info)
+int wrmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 l, u32 h)
+{
+	int err;
+	struct msr_info rv;
+
+	rv.msr_no = msr_no;
+	rv.l = l;
+	rv.h = h;
+	err = smp_call_function_single(cpu, __wrmsr_on_cpu, &rv, 1);
+
+	return err;
+}
+
+/* These "safe" variants are slower and should be used when the target MSR
+   may not actually exist. */
+static void __rdmsr_safe_on_cpu(void *info)
 {
 	struct msr_info *rv = info;
 
-	wrmsr(rv->msr_no, rv->l, rv->h);
+	rv->err = rdmsr_safe(rv->msr_no, &rv->l, &rv->h);
 }
 
 static void __wrmsr_safe_on_cpu(void *info)
@@ -56,45 +65,30 @@
 	rv->err = wrmsr_safe(rv->msr_no, rv->l, rv->h);
 }
 
-static int _wrmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 l, u32 h, int safe)
+int rdmsr_safe_on_cpu(unsigned int cpu, u32 msr_no, u32 *l, u32 *h)
 {
-	int err = 0;
+	int err;
+	struct msr_info rv;
+
+	rv.msr_no = msr_no;
+	err = smp_call_function_single(cpu, __rdmsr_safe_on_cpu, &rv, 1);
+	*l = rv.l;
+	*h = rv.h;
+
+	return err ? err : rv.err;
+}
+
+int wrmsr_safe_on_cpu(unsigned int cpu, u32 msr_no, u32 l, u32 h)
+{
+	int err;
 	struct msr_info rv;
 
 	rv.msr_no = msr_no;
 	rv.l = l;
 	rv.h = h;
-	if (safe) {
-		err = smp_call_function_single(cpu, __wrmsr_safe_on_cpu,
-					       &rv, 1);
-		err = err ? err : rv.err;
-	} else {
-		err = smp_call_function_single(cpu, __wrmsr_on_cpu, &rv, 1);
-	}
+	err = smp_call_function_single(cpu, __wrmsr_safe_on_cpu, &rv, 1);
 
-	return err;
-}
-
-int wrmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 l, u32 h)
-{
-	return _wrmsr_on_cpu(cpu, msr_no, l, h, 0);
-}
-
-int rdmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 *l, u32 *h)
-{
-	return _rdmsr_on_cpu(cpu, msr_no, l, h, 0);
-}
-
-/* These "safe" variants are slower and should be used when the target MSR
-   may not actually exist. */
-int wrmsr_safe_on_cpu(unsigned int cpu, u32 msr_no, u32 l, u32 h)
-{
-	return _wrmsr_on_cpu(cpu, msr_no, l, h, 1);
-}
-
-int rdmsr_safe_on_cpu(unsigned int cpu, u32 msr_no, u32 *l, u32 *h)
-{
-	return _rdmsr_on_cpu(cpu, msr_no, l, h, 1);
+	return err ? err : rv.err;
 }
 
 EXPORT_SYMBOL(rdmsr_on_cpu);
diff --git a/arch/x86/lib/string_32.c b/arch/x86/lib/string_32.c
index 94972e7..82004d2 100644
--- a/arch/x86/lib/string_32.c
+++ b/arch/x86/lib/string_32.c
@@ -22,7 +22,7 @@
 		"testb %%al,%%al\n\t"
 		"jne 1b"
 		: "=&S" (d0), "=&D" (d1), "=&a" (d2)
-		:"0" (src), "1" (dest) : "memory");
+		: "0" (src), "1" (dest) : "memory");
 	return dest;
 }
 EXPORT_SYMBOL(strcpy);
@@ -42,7 +42,7 @@
 		"stosb\n"
 		"2:"
 		: "=&S" (d0), "=&D" (d1), "=&c" (d2), "=&a" (d3)
-		:"0" (src), "1" (dest), "2" (count) : "memory");
+		: "0" (src), "1" (dest), "2" (count) : "memory");
 	return dest;
 }
 EXPORT_SYMBOL(strncpy);
@@ -60,7 +60,7 @@
 		"testb %%al,%%al\n\t"
 		"jne 1b"
 		: "=&S" (d0), "=&D" (d1), "=&a" (d2), "=&c" (d3)
-		: "0" (src), "1" (dest), "2" (0), "3" (0xffffffffu): "memory");
+		: "0" (src), "1" (dest), "2" (0), "3" (0xffffffffu) : "memory");
 	return dest;
 }
 EXPORT_SYMBOL(strcat);
@@ -105,9 +105,9 @@
 		"2:\tsbbl %%eax,%%eax\n\t"
 		"orb $1,%%al\n"
 		"3:"
-		:"=a" (res), "=&S" (d0), "=&D" (d1)
-		:"1" (cs), "2" (ct)
-		:"memory");
+		: "=a" (res), "=&S" (d0), "=&D" (d1)
+		: "1" (cs), "2" (ct)
+		: "memory");
 	return res;
 }
 EXPORT_SYMBOL(strcmp);
@@ -130,9 +130,9 @@
 		"3:\tsbbl %%eax,%%eax\n\t"
 		"orb $1,%%al\n"
 		"4:"
-		:"=a" (res), "=&S" (d0), "=&D" (d1), "=&c" (d2)
-		:"1" (cs), "2" (ct), "3" (count)
-		:"memory");
+		: "=a" (res), "=&S" (d0), "=&D" (d1), "=&c" (d2)
+		: "1" (cs), "2" (ct), "3" (count)
+		: "memory");
 	return res;
 }
 EXPORT_SYMBOL(strncmp);
@@ -152,9 +152,9 @@
 		"movl $1,%1\n"
 		"2:\tmovl %1,%0\n\t"
 		"decl %0"
-		:"=a" (res), "=&S" (d0)
-		:"1" (s), "0" (c)
-		:"memory");
+		: "=a" (res), "=&S" (d0)
+		: "1" (s), "0" (c)
+		: "memory");
 	return res;
 }
 EXPORT_SYMBOL(strchr);
@@ -169,9 +169,9 @@
 		"scasb\n\t"
 		"notl %0\n\t"
 		"decl %0"
-		:"=c" (res), "=&D" (d0)
-		:"1" (s), "a" (0), "0" (0xffffffffu)
-		:"memory");
+		: "=c" (res), "=&D" (d0)
+		: "1" (s), "a" (0), "0" (0xffffffffu)
+		: "memory");
 	return res;
 }
 EXPORT_SYMBOL(strlen);
@@ -189,9 +189,9 @@
 		"je 1f\n\t"
 		"movl $1,%0\n"
 		"1:\tdecl %0"
-		:"=D" (res), "=&c" (d0)
-		:"a" (c), "0" (cs), "1" (count)
-		:"memory");
+		: "=D" (res), "=&c" (d0)
+		: "a" (c), "0" (cs), "1" (count)
+		: "memory");
 	return res;
 }
 EXPORT_SYMBOL(memchr);
@@ -228,9 +228,9 @@
 		"cmpl $-1,%1\n\t"
 		"jne 1b\n"
 		"3:\tsubl %2,%0"
-		:"=a" (res), "=&d" (d0)
-		:"c" (s), "1" (count)
-		:"memory");
+		: "=a" (res), "=&d" (d0)
+		: "c" (s), "1" (count)
+		: "memory");
 	return res;
 }
 EXPORT_SYMBOL(strnlen);
diff --git a/arch/x86/lib/strstr_32.c b/arch/x86/lib/strstr_32.c
index 42e8a50..8e2d55f 100644
--- a/arch/x86/lib/strstr_32.c
+++ b/arch/x86/lib/strstr_32.c
@@ -23,9 +23,9 @@
 	"jne 1b\n\t"
 	"xorl %%eax,%%eax\n\t"
 	"2:"
-	:"=a" (__res), "=&c" (d0), "=&S" (d1)
-	:"0" (0), "1" (0xffffffff), "2" (cs), "g" (ct)
-	:"dx", "di");
+	: "=a" (__res), "=&c" (d0), "=&S" (d1)
+	: "0" (0), "1" (0xffffffff), "2" (cs), "g" (ct)
+	: "dx", "di");
 return __res;
 }
 
diff --git a/arch/x86/lib/usercopy_32.c b/arch/x86/lib/usercopy_32.c
index 24e6094..9e68075 100644
--- a/arch/x86/lib/usercopy_32.c
+++ b/arch/x86/lib/usercopy_32.c
@@ -14,6 +14,13 @@
 #include <asm/uaccess.h>
 #include <asm/mmx.h>
 
+#ifdef CONFIG_X86_INTEL_USERCOPY
+/*
+ * Alignment at which movsl is preferred for bulk memory copies.
+ */
+struct movsl_mask movsl_mask __read_mostly;
+#endif
+
 static inline int __movsl_is_ok(unsigned long a1, unsigned long a2, unsigned long n)
 {
 #ifdef CONFIG_X86_INTEL_USERCOPY
diff --git a/arch/x86/mach-default/setup.c b/arch/x86/mach-default/setup.c
index 3d31783..37b9ae4 100644
--- a/arch/x86/mach-default/setup.c
+++ b/arch/x86/mach-default/setup.c
@@ -10,13 +10,15 @@
 #include <asm/e820.h>
 #include <asm/setup.h>
 
+#include <mach_ipi.h>
+
 #ifdef CONFIG_HOTPLUG_CPU
 #define DEFAULT_SEND_IPI	(1)
 #else
 #define DEFAULT_SEND_IPI	(0)
 #endif
 
-int no_broadcast=DEFAULT_SEND_IPI;
+int no_broadcast = DEFAULT_SEND_IPI;
 
 /**
  * pre_intr_init_hook - initialisation prior to setting up interrupt vectors
@@ -36,15 +38,6 @@
 	init_ISA_irqs();
 }
 
-/*
- * IRQ2 is cascade interrupt to second interrupt controller
- */
-static struct irqaction irq2 = {
-	.handler = no_action,
-	.mask = CPU_MASK_NONE,
-	.name = "cascade",
-};
-
 /**
  * intr_init_hook - post gate setup interrupt initialisation
  *
@@ -60,12 +53,6 @@
 		if (x86_quirks->arch_intr_init())
 			return;
 	}
-#ifdef CONFIG_X86_LOCAL_APIC
-	apic_intr_init();
-#endif
-
-	if (!acpi_ioapic)
-		setup_irq(2, &irq2);
 }
 
 /**
diff --git a/arch/x86/mach-es7000/Makefile b/arch/x86/mach-es7000/Makefile
deleted file mode 100644
index 3ef8b43..0000000
--- a/arch/x86/mach-es7000/Makefile
+++ /dev/null
@@ -1,5 +0,0 @@
-#
-# Makefile for the linux kernel.
-#
-
-obj-$(CONFIG_X86_ES7000)	:= es7000plat.o
diff --git a/arch/x86/mach-es7000/es7000.h b/arch/x86/mach-es7000/es7000.h
deleted file mode 100644
index c8d5aa1..0000000
--- a/arch/x86/mach-es7000/es7000.h
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * Written by: Garry Forsgren, Unisys Corporation
- *             Natalie Protasevich, Unisys Corporation
- * This file contains the code to configure and interface 
- * with Unisys ES7000 series hardware system manager.
- *
- * Copyright (c) 2003 Unisys Corporation.  All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it would be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write the Free Software Foundation, Inc., 59
- * Temple Place - Suite 330, Boston MA 02111-1307, USA.
- *
- * Contact information: Unisys Corporation, Township Line & Union Meeting 
- * Roads-A, Unisys Way, Blue Bell, Pennsylvania, 19424, or:
- *
- * http://www.unisys.com
- */
-
-/*
- * ES7000 chipsets
- */
-
-#define NON_UNISYS		0
-#define ES7000_CLASSIC		1
-#define ES7000_ZORRO		2
-
-
-#define	MIP_REG			1
-#define	MIP_PSAI_REG		4
-
-#define	MIP_BUSY		1
-#define	MIP_SPIN		0xf0000
-#define	MIP_VALID		0x0100000000000000ULL
-#define	MIP_PORT(VALUE)	((VALUE >> 32) & 0xffff)
-
-#define	MIP_RD_LO(VALUE)	(VALUE & 0xffffffff)   
-
-struct mip_reg_info {
-	unsigned long long mip_info;
-	unsigned long long delivery_info;
-	unsigned long long host_reg;
-	unsigned long long mip_reg;
-};
-
-struct part_info {
-	unsigned char type;   
-	unsigned char length;
-	unsigned char part_id;
-	unsigned char apic_mode;
-	unsigned long snum;    
-	char ptype[16];
-	char sname[64];
-	char pname[64];
-};
-
-struct psai {
-	unsigned long long entry_type;
-	unsigned long long addr;
-	unsigned long long bep_addr;
-};
-
-struct es7000_mem_info {
-	unsigned char type;   
-	unsigned char length;
-	unsigned char resv[6];
-	unsigned long long  start; 
-	unsigned long long  size; 
-};
-
-struct es7000_oem_table {
-	unsigned long long hdr;
-	struct mip_reg_info mip;
-	struct part_info pif;
-	struct es7000_mem_info shm;
-	struct psai psai;
-};
-
-#ifdef CONFIG_ACPI
-
-struct oem_table {
-	struct acpi_table_header Header;
-	u32 OEMTableAddr;
-	u32 OEMTableSize;
-};
-
-extern int find_unisys_acpi_oem_table(unsigned long *oem_addr);
-#endif
-
-struct mip_reg {
-	unsigned long long off_0;
-	unsigned long long off_8;
-	unsigned long long off_10;
-	unsigned long long off_18;
-	unsigned long long off_20;
-	unsigned long long off_28;
-	unsigned long long off_30;
-	unsigned long long off_38;
-};
-
-#define	MIP_SW_APIC		0x1020b
-#define	MIP_FUNC(VALUE) 	(VALUE & 0xff)
-
-extern int parse_unisys_oem (char *oemptr);
-extern void setup_unisys(void);
-extern int es7000_start_cpu(int cpu, unsigned long eip);
-extern void es7000_sw_apic(void);
diff --git a/arch/x86/mach-es7000/es7000plat.c b/arch/x86/mach-es7000/es7000plat.c
deleted file mode 100644
index 50189af..0000000
--- a/arch/x86/mach-es7000/es7000plat.c
+++ /dev/null
@@ -1,262 +0,0 @@
-/*
- * Written by: Garry Forsgren, Unisys Corporation
- *             Natalie Protasevich, Unisys Corporation
- * This file contains the code to configure and interface
- * with Unisys ES7000 series hardware system manager.
- *
- * Copyright (c) 2003 Unisys Corporation.  All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it would be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write the Free Software Foundation, Inc., 59
- * Temple Place - Suite 330, Boston MA 02111-1307, USA.
- *
- * Contact information: Unisys Corporation, Township Line & Union Meeting
- * Roads-A, Unisys Way, Blue Bell, Pennsylvania, 19424, or:
- *
- * http://www.unisys.com
- */
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/smp.h>
-#include <linux/string.h>
-#include <linux/spinlock.h>
-#include <linux/errno.h>
-#include <linux/notifier.h>
-#include <linux/reboot.h>
-#include <linux/init.h>
-#include <linux/acpi.h>
-#include <asm/io.h>
-#include <asm/nmi.h>
-#include <asm/smp.h>
-#include <asm/apicdef.h>
-#include "es7000.h"
-#include <mach_mpparse.h>
-
-/*
- * ES7000 Globals
- */
-
-static volatile unsigned long	*psai = NULL;
-static struct mip_reg		*mip_reg;
-static struct mip_reg		*host_reg;
-static int 			mip_port;
-static unsigned long		mip_addr, host_addr;
-
-int es7000_plat;
-
-/*
- * GSI override for ES7000 platforms.
- */
-
-static unsigned int base;
-
-static int
-es7000_rename_gsi(int ioapic, int gsi)
-{
-	if (es7000_plat == ES7000_ZORRO)
-		return gsi;
-
-	if (!base) {
-		int i;
-		for (i = 0; i < nr_ioapics; i++)
-			base += nr_ioapic_registers[i];
-	}
-
-	if (!ioapic && (gsi < 16)) 
-		gsi += base;
-	return gsi;
-}
-
-void __init
-setup_unisys(void)
-{
-	/*
-	 * Determine the generation of the ES7000 currently running.
-	 *
-	 * es7000_plat = 1 if the machine is a 5xx ES7000 box
-	 * es7000_plat = 2 if the machine is a x86_64 ES7000 box
-	 *
-	 */
-	if (!(boot_cpu_data.x86 <= 15 && boot_cpu_data.x86_model <= 2))
-		es7000_plat = ES7000_ZORRO;
-	else
-		es7000_plat = ES7000_CLASSIC;
-	ioapic_renumber_irq = es7000_rename_gsi;
-}
-
-/*
- * Parse the OEM Table
- */
-
-int __init
-parse_unisys_oem (char *oemptr)
-{
-	int                     i;
-	int 			success = 0;
-	unsigned char           type, size;
-	unsigned long           val;
-	char                    *tp = NULL;
-	struct psai             *psaip = NULL;
-	struct mip_reg_info 	*mi;
-	struct mip_reg		*host, *mip;
-
-	tp = oemptr;
-
-	tp += 8;
-
-	for (i=0; i <= 6; i++) {
-		type = *tp++;
-		size = *tp++;
-		tp -= 2;
-		switch (type) {
-		case MIP_REG:
-			mi = (struct mip_reg_info *)tp;
-			val = MIP_RD_LO(mi->host_reg);
-			host_addr = val;
-			host = (struct mip_reg *)val;
-			host_reg = __va(host);
-			val = MIP_RD_LO(mi->mip_reg);
-			mip_port = MIP_PORT(mi->mip_info);
-			mip_addr = val;
-			mip = (struct mip_reg *)val;
-			mip_reg = __va(mip);
-			pr_debug("es7000_mipcfg: host_reg = 0x%lx \n",
-				 (unsigned long)host_reg);
-			pr_debug("es7000_mipcfg: mip_reg = 0x%lx \n",
-				 (unsigned long)mip_reg);
-			success++;
-			break;
-		case MIP_PSAI_REG:
-			psaip = (struct psai *)tp;
-			if (tp != NULL) {
-				if (psaip->addr)
-					psai = __va(psaip->addr);
-				else
-					psai = NULL;
-				success++;
-			}
-			break;
-		default:
-			break;
-		}
-		tp += size;
-	}
-
-	if (success < 2) {
-		es7000_plat = NON_UNISYS;
-	} else
-		setup_unisys();
-	return es7000_plat;
-}
-
-#ifdef CONFIG_ACPI
-int __init
-find_unisys_acpi_oem_table(unsigned long *oem_addr)
-{
-	struct acpi_table_header *header = NULL;
-	int i = 0;
-	while (ACPI_SUCCESS(acpi_get_table("OEM1", i++, &header))) {
-		if (!memcmp((char *) &header->oem_id, "UNISYS", 6)) {
-			struct oem_table *t = (struct oem_table *)header;
-			*oem_addr = (unsigned long)__acpi_map_table(t->OEMTableAddr,
-								    t->OEMTableSize);
-			return 0;
-		}
-	}
-	return -1;
-}
-#endif
-
-static void
-es7000_spin(int n)
-{
-	int i = 0;
-
-	while (i++ < n)
-		rep_nop();
-}
-
-static int __init
-es7000_mip_write(struct mip_reg *mip_reg)
-{
-	int			status = 0;
-	int			spin;
-
-	spin = MIP_SPIN;
-	while (((unsigned long long)host_reg->off_38 &
-		(unsigned long long)MIP_VALID) != 0) {
-			if (--spin <= 0) {
-				printk("es7000_mip_write: Timeout waiting for Host Valid Flag");
-				return -1;
-			}
-		es7000_spin(MIP_SPIN);
-	}
-
-	memcpy(host_reg, mip_reg, sizeof(struct mip_reg));
-	outb(1, mip_port);
-
-	spin = MIP_SPIN;
-
-	while (((unsigned long long)mip_reg->off_38 &
-		(unsigned long long)MIP_VALID) == 0) {
-		if (--spin <= 0) {
-			printk("es7000_mip_write: Timeout waiting for MIP Valid Flag");
-			return -1;
-		}
-		es7000_spin(MIP_SPIN);
-	}
-
-	status = ((unsigned long long)mip_reg->off_0 &
-		(unsigned long long)0xffff0000000000ULL) >> 48;
-	mip_reg->off_38 = ((unsigned long long)mip_reg->off_38 &
-		(unsigned long long)~MIP_VALID);
-	return status;
-}
-
-int
-es7000_start_cpu(int cpu, unsigned long eip)
-{
-	unsigned long vect = 0, psaival = 0;
-
-	if (psai == NULL)
-		return -1;
-
-	vect = ((unsigned long)__pa(eip)/0x1000) << 16;
-	psaival = (0x1000000 | vect | cpu);
-
-	while (*psai & 0x1000000)
-                ;
-
-	*psai = psaival;
-
-	return 0;
-
-}
-
-void __init
-es7000_sw_apic(void)
-{
-	if (es7000_plat) {
-		int mip_status;
-		struct mip_reg es7000_mip_reg;
-
-		printk("ES7000: Enabling APIC mode.\n");
-        	memset(&es7000_mip_reg, 0, sizeof(struct mip_reg));
-        	es7000_mip_reg.off_0 = MIP_SW_APIC;
-        	es7000_mip_reg.off_38 = (MIP_VALID);
-        	while ((mip_status = es7000_mip_write(&es7000_mip_reg)) != 0)
-              		printk("es7000_sw_apic: command failed, status = %x\n",
-				mip_status);
-		return;
-	}
-}
diff --git a/arch/x86/mach-generic/Makefile b/arch/x86/mach-generic/Makefile
index 0dbd780..6730f4e 100644
--- a/arch/x86/mach-generic/Makefile
+++ b/arch/x86/mach-generic/Makefile
@@ -9,4 +9,3 @@
 obj-$(CONFIG_X86_SUMMIT)	+= summit.o
 obj-$(CONFIG_X86_BIGSMP)	+= bigsmp.o
 obj-$(CONFIG_X86_ES7000)	+= es7000.o
-obj-$(CONFIG_X86_ES7000)	+= ../../x86/mach-es7000/
diff --git a/arch/x86/mach-generic/bigsmp.c b/arch/x86/mach-generic/bigsmp.c
index 59d7717..df37fc9 100644
--- a/arch/x86/mach-generic/bigsmp.c
+++ b/arch/x86/mach-generic/bigsmp.c
@@ -5,18 +5,17 @@
 #define APIC_DEFINITION 1
 #include <linux/threads.h>
 #include <linux/cpumask.h>
-#include <asm/smp.h>
 #include <asm/mpspec.h>
 #include <asm/genapic.h>
 #include <asm/fixmap.h>
 #include <asm/apicdef.h>
 #include <linux/kernel.h>
-#include <linux/smp.h>
 #include <linux/init.h>
 #include <linux/dmi.h>
-#include <asm/mach-bigsmp/mach_apic.h>
-#include <asm/mach-bigsmp/mach_apicdef.h>
-#include <asm/mach-bigsmp/mach_ipi.h>
+#include <asm/bigsmp/apicdef.h>
+#include <linux/smp.h>
+#include <asm/bigsmp/apic.h>
+#include <asm/bigsmp/ipi.h>
 #include <asm/mach-default/mach_mpparse.h>
 
 static int dmi_bigsmp; /* can be set by dmi scanners */
diff --git a/arch/x86/mach-generic/es7000.c b/arch/x86/mach-generic/es7000.c
index 4742626..6513d41 100644
--- a/arch/x86/mach-generic/es7000.c
+++ b/arch/x86/mach-generic/es7000.c
@@ -4,20 +4,19 @@
 #define APIC_DEFINITION 1
 #include <linux/threads.h>
 #include <linux/cpumask.h>
-#include <asm/smp.h>
 #include <asm/mpspec.h>
 #include <asm/genapic.h>
 #include <asm/fixmap.h>
 #include <asm/apicdef.h>
 #include <linux/kernel.h>
 #include <linux/string.h>
-#include <linux/smp.h>
 #include <linux/init.h>
-#include <asm/mach-es7000/mach_apicdef.h>
-#include <asm/mach-es7000/mach_apic.h>
-#include <asm/mach-es7000/mach_ipi.h>
-#include <asm/mach-es7000/mach_mpparse.h>
-#include <asm/mach-es7000/mach_wakecpu.h>
+#include <asm/es7000/apicdef.h>
+#include <linux/smp.h>
+#include <asm/es7000/apic.h>
+#include <asm/es7000/ipi.h>
+#include <asm/es7000/mpparse.h>
+#include <asm/es7000/wakecpu.h>
 
 static int probe_es7000(void)
 {
@@ -48,16 +47,26 @@
 /* Hook from generic ACPI tables.c */
 static int __init acpi_madt_oem_check(char *oem_id, char *oem_table_id)
 {
-	unsigned long oem_addr;
+	unsigned long oem_addr = 0;
+	int check_dsdt;
+	int ret = 0;
+
+	/* check dsdt at first to avoid clear fix_map for oem_addr */
+	check_dsdt = es7000_check_dsdt();
+
 	if (!find_unisys_acpi_oem_table(&oem_addr)) {
-		if (es7000_check_dsdt())
-			return parse_unisys_oem((char *)oem_addr);
+		if (check_dsdt)
+			ret = parse_unisys_oem((char *)oem_addr);
 		else {
 			setup_unisys();
-			return 1;
+			ret = 1;
 		}
+		/*
+		 * we need to unmap it
+		 */
+		unmap_unisys_acpi_oem_table(oem_addr);
 	}
-	return 0;
+	return ret;
 }
 #else
 static int __init acpi_madt_oem_check(char *oem_id, char *oem_table_id)
diff --git a/arch/x86/mach-generic/numaq.c b/arch/x86/mach-generic/numaq.c
index 8091e68..8cf5839 100644
--- a/arch/x86/mach-generic/numaq.c
+++ b/arch/x86/mach-generic/numaq.c
@@ -4,7 +4,6 @@
 #define APIC_DEFINITION 1
 #include <linux/threads.h>
 #include <linux/cpumask.h>
-#include <linux/smp.h>
 #include <asm/mpspec.h>
 #include <asm/genapic.h>
 #include <asm/fixmap.h>
@@ -12,11 +11,12 @@
 #include <linux/kernel.h>
 #include <linux/string.h>
 #include <linux/init.h>
-#include <asm/mach-numaq/mach_apic.h>
-#include <asm/mach-numaq/mach_apicdef.h>
-#include <asm/mach-numaq/mach_ipi.h>
-#include <asm/mach-numaq/mach_mpparse.h>
-#include <asm/mach-numaq/mach_wakecpu.h>
+#include <asm/numaq/apicdef.h>
+#include <linux/smp.h>
+#include <asm/numaq/apic.h>
+#include <asm/numaq/ipi.h>
+#include <asm/numaq/mpparse.h>
+#include <asm/numaq/wakecpu.h>
 #include <asm/numaq.h>
 
 static int mps_oem_check(struct mp_config_table *mpc, char *oem,
diff --git a/arch/x86/mach-generic/summit.c b/arch/x86/mach-generic/summit.c
index a97ea0f..6ad6b67 100644
--- a/arch/x86/mach-generic/summit.c
+++ b/arch/x86/mach-generic/summit.c
@@ -4,19 +4,18 @@
 #define APIC_DEFINITION 1
 #include <linux/threads.h>
 #include <linux/cpumask.h>
-#include <asm/smp.h>
 #include <asm/mpspec.h>
 #include <asm/genapic.h>
 #include <asm/fixmap.h>
 #include <asm/apicdef.h>
 #include <linux/kernel.h>
 #include <linux/string.h>
-#include <linux/smp.h>
 #include <linux/init.h>
-#include <asm/mach-summit/mach_apic.h>
-#include <asm/mach-summit/mach_apicdef.h>
-#include <asm/mach-summit/mach_ipi.h>
-#include <asm/mach-summit/mach_mpparse.h>
+#include <asm/summit/apicdef.h>
+#include <linux/smp.h>
+#include <asm/summit/apic.h>
+#include <asm/summit/ipi.h>
+#include <asm/summit/mpparse.h>
 
 static int probe_summit(void)
 {
diff --git a/arch/x86/mach-voyager/voyager_smp.c b/arch/x86/mach-voyager/voyager_smp.c
index ee0fba0..199a5f4 100644
--- a/arch/x86/mach-voyager/voyager_smp.c
+++ b/arch/x86/mach-voyager/voyager_smp.c
@@ -448,6 +448,8 @@
 
 	VDEBUG(("VOYAGER SMP: CPU%d, stack at about %p\n", cpuid, &cpuid));
 
+	notify_cpu_starting(cpuid);
+
 	/* enable interrupts */
 	local_irq_enable();
 
diff --git a/arch/x86/mm/Makefile b/arch/x86/mm/Makefile
index dfb932d..59f89b4 100644
--- a/arch/x86/mm/Makefile
+++ b/arch/x86/mm/Makefile
@@ -13,12 +13,8 @@
 mmiotrace-y			:= pf_in.o mmio-mod.o
 obj-$(CONFIG_MMIOTRACE_TEST)	+= testmmiotrace.o
 
-ifeq ($(CONFIG_X86_32),y)
-obj-$(CONFIG_NUMA)		+= discontig_32.o
-else
-obj-$(CONFIG_NUMA)		+= numa_64.o
+obj-$(CONFIG_NUMA)		+= numa_$(BITS).o
 obj-$(CONFIG_K8_NUMA)		+= k8topology_64.o
-endif
 obj-$(CONFIG_ACPI_NUMA)		+= srat_$(BITS).o
 
 obj-$(CONFIG_MEMTEST)		+= memtest.o
diff --git a/arch/x86/mm/discontig_32.c b/arch/x86/mm/discontig_32.c
deleted file mode 100644
index 62fa440..0000000
--- a/arch/x86/mm/discontig_32.c
+++ /dev/null
@@ -1,444 +0,0 @@
-/*
- * Written by: Patricia Gaughen <gone@us.ibm.com>, IBM Corporation
- * August 2002: added remote node KVA remap - Martin J. Bligh 
- *
- * Copyright (C) 2002, IBM Corp.
- *
- * All rights reserved.          
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
- * NON INFRINGEMENT.  See the GNU General Public License for more
- * details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include <linux/mm.h>
-#include <linux/bootmem.h>
-#include <linux/mmzone.h>
-#include <linux/highmem.h>
-#include <linux/initrd.h>
-#include <linux/nodemask.h>
-#include <linux/module.h>
-#include <linux/kexec.h>
-#include <linux/pfn.h>
-#include <linux/swap.h>
-#include <linux/acpi.h>
-
-#include <asm/e820.h>
-#include <asm/setup.h>
-#include <asm/mmzone.h>
-#include <asm/bios_ebda.h>
-#include <asm/proto.h>
-
-struct pglist_data *node_data[MAX_NUMNODES] __read_mostly;
-EXPORT_SYMBOL(node_data);
-
-/*
- * numa interface - we expect the numa architecture specific code to have
- *                  populated the following initialisation.
- *
- * 1) node_online_map  - the map of all nodes configured (online) in the system
- * 2) node_start_pfn   - the starting page frame number for a node
- * 3) node_end_pfn     - the ending page fram number for a node
- */
-unsigned long node_start_pfn[MAX_NUMNODES] __read_mostly;
-unsigned long node_end_pfn[MAX_NUMNODES] __read_mostly;
-
-
-#ifdef CONFIG_DISCONTIGMEM
-/*
- * 4) physnode_map     - the mapping between a pfn and owning node
- * physnode_map keeps track of the physical memory layout of a generic
- * numa node on a 64Mb break (each element of the array will
- * represent 64Mb of memory and will be marked by the node id.  so,
- * if the first gig is on node 0, and the second gig is on node 1
- * physnode_map will contain:
- *
- *     physnode_map[0-15] = 0;
- *     physnode_map[16-31] = 1;
- *     physnode_map[32- ] = -1;
- */
-s8 physnode_map[MAX_ELEMENTS] __read_mostly = { [0 ... (MAX_ELEMENTS - 1)] = -1};
-EXPORT_SYMBOL(physnode_map);
-
-void memory_present(int nid, unsigned long start, unsigned long end)
-{
-	unsigned long pfn;
-
-	printk(KERN_INFO "Node: %d, start_pfn: %lx, end_pfn: %lx\n",
-			nid, start, end);
-	printk(KERN_DEBUG "  Setting physnode_map array to node %d for pfns:\n", nid);
-	printk(KERN_DEBUG "  ");
-	for (pfn = start; pfn < end; pfn += PAGES_PER_ELEMENT) {
-		physnode_map[pfn / PAGES_PER_ELEMENT] = nid;
-		printk(KERN_CONT "%lx ", pfn);
-	}
-	printk(KERN_CONT "\n");
-}
-
-unsigned long node_memmap_size_bytes(int nid, unsigned long start_pfn,
-					      unsigned long end_pfn)
-{
-	unsigned long nr_pages = end_pfn - start_pfn;
-
-	if (!nr_pages)
-		return 0;
-
-	return (nr_pages + 1) * sizeof(struct page);
-}
-#endif
-
-extern unsigned long find_max_low_pfn(void);
-extern unsigned long highend_pfn, highstart_pfn;
-
-#define LARGE_PAGE_BYTES (PTRS_PER_PTE * PAGE_SIZE)
-
-unsigned long node_remap_size[MAX_NUMNODES];
-static void *node_remap_start_vaddr[MAX_NUMNODES];
-void set_pmd_pfn(unsigned long vaddr, unsigned long pfn, pgprot_t flags);
-
-static unsigned long kva_start_pfn;
-static unsigned long kva_pages;
-/*
- * FLAT - support for basic PC memory model with discontig enabled, essentially
- *        a single node with all available processors in it with a flat
- *        memory map.
- */
-int __init get_memcfg_numa_flat(void)
-{
-	printk(KERN_DEBUG "NUMA - single node, flat memory mode\n");
-
-	node_start_pfn[0] = 0;
-	node_end_pfn[0] = max_pfn;
-	e820_register_active_regions(0, 0, max_pfn);
-	memory_present(0, 0, max_pfn);
-	node_remap_size[0] = node_memmap_size_bytes(0, 0, max_pfn);
-
-        /* Indicate there is one node available. */
-	nodes_clear(node_online_map);
-	node_set_online(0);
-	return 1;
-}
-
-/*
- * Find the highest page frame number we have available for the node
- */
-static void __init propagate_e820_map_node(int nid)
-{
-	if (node_end_pfn[nid] > max_pfn)
-		node_end_pfn[nid] = max_pfn;
-	/*
-	 * if a user has given mem=XXXX, then we need to make sure 
-	 * that the node _starts_ before that, too, not just ends
-	 */
-	if (node_start_pfn[nid] > max_pfn)
-		node_start_pfn[nid] = max_pfn;
-	BUG_ON(node_start_pfn[nid] > node_end_pfn[nid]);
-}
-
-/* 
- * Allocate memory for the pg_data_t for this node via a crude pre-bootmem
- * method.  For node zero take this from the bottom of memory, for
- * subsequent nodes place them at node_remap_start_vaddr which contains
- * node local data in physically node local memory.  See setup_memory()
- * for details.
- */
-static void __init allocate_pgdat(int nid)
-{
-	char buf[16];
-
-	if (node_has_online_mem(nid) && node_remap_start_vaddr[nid])
-		NODE_DATA(nid) = (pg_data_t *)node_remap_start_vaddr[nid];
-	else {
-		unsigned long pgdat_phys;
-		pgdat_phys = find_e820_area(min_low_pfn<<PAGE_SHIFT,
-				 max_pfn_mapped<<PAGE_SHIFT,
-				 sizeof(pg_data_t),
-				 PAGE_SIZE);
-		NODE_DATA(nid) = (pg_data_t *)(pfn_to_kaddr(pgdat_phys>>PAGE_SHIFT));
-		memset(buf, 0, sizeof(buf));
-		sprintf(buf, "NODE_DATA %d",  nid);
-		reserve_early(pgdat_phys, pgdat_phys + sizeof(pg_data_t), buf);
-	}
-	printk(KERN_DEBUG "allocate_pgdat: node %d NODE_DATA %08lx\n",
-		nid, (unsigned long)NODE_DATA(nid));
-}
-
-/*
- * In the DISCONTIGMEM and SPARSEMEM memory model, a portion of the kernel
- * virtual address space (KVA) is reserved and portions of nodes are mapped
- * using it. This is to allow node-local memory to be allocated for
- * structures that would normally require ZONE_NORMAL. The memory is
- * allocated with alloc_remap() and callers should be prepared to allocate
- * from the bootmem allocator instead.
- */
-static unsigned long node_remap_start_pfn[MAX_NUMNODES];
-static void *node_remap_end_vaddr[MAX_NUMNODES];
-static void *node_remap_alloc_vaddr[MAX_NUMNODES];
-static unsigned long node_remap_offset[MAX_NUMNODES];
-
-void *alloc_remap(int nid, unsigned long size)
-{
-	void *allocation = node_remap_alloc_vaddr[nid];
-
-	size = ALIGN(size, L1_CACHE_BYTES);
-
-	if (!allocation || (allocation + size) >= node_remap_end_vaddr[nid])
-		return 0;
-
-	node_remap_alloc_vaddr[nid] += size;
-	memset(allocation, 0, size);
-
-	return allocation;
-}
-
-static void __init remap_numa_kva(void)
-{
-	void *vaddr;
-	unsigned long pfn;
-	int node;
-
-	for_each_online_node(node) {
-		printk(KERN_DEBUG "remap_numa_kva: node %d\n", node);
-		for (pfn=0; pfn < node_remap_size[node]; pfn += PTRS_PER_PTE) {
-			vaddr = node_remap_start_vaddr[node]+(pfn<<PAGE_SHIFT);
-			printk(KERN_DEBUG "remap_numa_kva: %08lx to pfn %08lx\n",
-				(unsigned long)vaddr,
-				node_remap_start_pfn[node] + pfn);
-			set_pmd_pfn((ulong) vaddr, 
-				node_remap_start_pfn[node] + pfn, 
-				PAGE_KERNEL_LARGE);
-		}
-	}
-}
-
-static unsigned long calculate_numa_remap_pages(void)
-{
-	int nid;
-	unsigned long size, reserve_pages = 0;
-
-	for_each_online_node(nid) {
-		u64 node_kva_target;
-		u64 node_kva_final;
-
-		/*
-		 * The acpi/srat node info can show hot-add memroy zones
-		 * where memory could be added but not currently present.
-		 */
-		printk(KERN_DEBUG "node %d pfn: [%lx - %lx]\n",
-			nid, node_start_pfn[nid], node_end_pfn[nid]);
-		if (node_start_pfn[nid] > max_pfn)
-			continue;
-		if (!node_end_pfn[nid])
-			continue;
-		if (node_end_pfn[nid] > max_pfn)
-			node_end_pfn[nid] = max_pfn;
-
-		/* ensure the remap includes space for the pgdat. */
-		size = node_remap_size[nid] + sizeof(pg_data_t);
-
-		/* convert size to large (pmd size) pages, rounding up */
-		size = (size + LARGE_PAGE_BYTES - 1) / LARGE_PAGE_BYTES;
-		/* now the roundup is correct, convert to PAGE_SIZE pages */
-		size = size * PTRS_PER_PTE;
-
-		node_kva_target = round_down(node_end_pfn[nid] - size,
-						 PTRS_PER_PTE);
-		node_kva_target <<= PAGE_SHIFT;
-		do {
-			node_kva_final = find_e820_area(node_kva_target,
-					((u64)node_end_pfn[nid])<<PAGE_SHIFT,
-						((u64)size)<<PAGE_SHIFT,
-						LARGE_PAGE_BYTES);
-			node_kva_target -= LARGE_PAGE_BYTES;
-		} while (node_kva_final == -1ULL &&
-			 (node_kva_target>>PAGE_SHIFT) > (node_start_pfn[nid]));
-
-		if (node_kva_final == -1ULL)
-			panic("Can not get kva ram\n");
-
-		node_remap_size[nid] = size;
-		node_remap_offset[nid] = reserve_pages;
-		reserve_pages += size;
-		printk(KERN_DEBUG "Reserving %ld pages of KVA for lmem_map of"
-				  " node %d at %llx\n",
-				size, nid, node_kva_final>>PAGE_SHIFT);
-
-		/*
-		 *  prevent kva address below max_low_pfn want it on system
-		 *  with less memory later.
-		 *  layout will be: KVA address , KVA RAM
-		 *
-		 *  we are supposed to only record the one less then max_low_pfn
-		 *  but we could have some hole in high memory, and it will only
-		 *  check page_is_ram(pfn) && !page_is_reserved_early(pfn) to decide
-		 *  to use it as free.
-		 *  So reserve_early here, hope we don't run out of that array
-		 */
-		reserve_early(node_kva_final,
-			      node_kva_final+(((u64)size)<<PAGE_SHIFT),
-			      "KVA RAM");
-
-		node_remap_start_pfn[nid] = node_kva_final>>PAGE_SHIFT;
-		remove_active_range(nid, node_remap_start_pfn[nid],
-					 node_remap_start_pfn[nid] + size);
-	}
-	printk(KERN_INFO "Reserving total of %lx pages for numa KVA remap\n",
-			reserve_pages);
-	return reserve_pages;
-}
-
-static void init_remap_allocator(int nid)
-{
-	node_remap_start_vaddr[nid] = pfn_to_kaddr(
-			kva_start_pfn + node_remap_offset[nid]);
-	node_remap_end_vaddr[nid] = node_remap_start_vaddr[nid] +
-		(node_remap_size[nid] * PAGE_SIZE);
-	node_remap_alloc_vaddr[nid] = node_remap_start_vaddr[nid] +
-		ALIGN(sizeof(pg_data_t), PAGE_SIZE);
-
-	printk(KERN_DEBUG "node %d will remap to vaddr %08lx - %08lx\n", nid,
-		(ulong) node_remap_start_vaddr[nid],
-		(ulong) node_remap_end_vaddr[nid]);
-}
-
-void __init initmem_init(unsigned long start_pfn,
-				  unsigned long end_pfn)
-{
-	int nid;
-	long kva_target_pfn;
-
-	/*
-	 * When mapping a NUMA machine we allocate the node_mem_map arrays
-	 * from node local memory.  They are then mapped directly into KVA
-	 * between zone normal and vmalloc space.  Calculate the size of
-	 * this space and use it to adjust the boundary between ZONE_NORMAL
-	 * and ZONE_HIGHMEM.
-	 */
-
-	get_memcfg_numa();
-
-	kva_pages = round_up(calculate_numa_remap_pages(), PTRS_PER_PTE);
-
-	kva_target_pfn = round_down(max_low_pfn - kva_pages, PTRS_PER_PTE);
-	do {
-		kva_start_pfn = find_e820_area(kva_target_pfn<<PAGE_SHIFT,
-					max_low_pfn<<PAGE_SHIFT,
-					kva_pages<<PAGE_SHIFT,
-					PTRS_PER_PTE<<PAGE_SHIFT) >> PAGE_SHIFT;
-		kva_target_pfn -= PTRS_PER_PTE;
-	} while (kva_start_pfn == -1UL && kva_target_pfn > min_low_pfn);
-
-	if (kva_start_pfn == -1UL)
-		panic("Can not get kva space\n");
-
-	printk(KERN_INFO "kva_start_pfn ~ %lx max_low_pfn ~ %lx\n",
-		kva_start_pfn, max_low_pfn);
-	printk(KERN_INFO "max_pfn = %lx\n", max_pfn);
-
-	/* avoid clash with initrd */
-	reserve_early(kva_start_pfn<<PAGE_SHIFT,
-		      (kva_start_pfn + kva_pages)<<PAGE_SHIFT,
-		     "KVA PG");
-#ifdef CONFIG_HIGHMEM
-	highstart_pfn = highend_pfn = max_pfn;
-	if (max_pfn > max_low_pfn)
-		highstart_pfn = max_low_pfn;
-	printk(KERN_NOTICE "%ldMB HIGHMEM available.\n",
-	       pages_to_mb(highend_pfn - highstart_pfn));
-	num_physpages = highend_pfn;
-	high_memory = (void *) __va(highstart_pfn * PAGE_SIZE - 1) + 1;
-#else
-	num_physpages = max_low_pfn;
-	high_memory = (void *) __va(max_low_pfn * PAGE_SIZE - 1) + 1;
-#endif
-	printk(KERN_NOTICE "%ldMB LOWMEM available.\n",
-			pages_to_mb(max_low_pfn));
-	printk(KERN_DEBUG "max_low_pfn = %lx, highstart_pfn = %lx\n",
-			max_low_pfn, highstart_pfn);
-
-	printk(KERN_DEBUG "Low memory ends at vaddr %08lx\n",
-			(ulong) pfn_to_kaddr(max_low_pfn));
-	for_each_online_node(nid) {
-		init_remap_allocator(nid);
-
-		allocate_pgdat(nid);
-	}
-	remap_numa_kva();
-
-	printk(KERN_DEBUG "High memory starts at vaddr %08lx\n",
-			(ulong) pfn_to_kaddr(highstart_pfn));
-	for_each_online_node(nid)
-		propagate_e820_map_node(nid);
-
-	for_each_online_node(nid)
-		memset(NODE_DATA(nid), 0, sizeof(struct pglist_data));
-
-	NODE_DATA(0)->bdata = &bootmem_node_data[0];
-	setup_bootmem_allocator();
-}
-
-void __init set_highmem_pages_init(void)
-{
-#ifdef CONFIG_HIGHMEM
-	struct zone *zone;
-	int nid;
-
-	for_each_zone(zone) {
-		unsigned long zone_start_pfn, zone_end_pfn;
-
-		if (!is_highmem(zone))
-			continue;
-
-		zone_start_pfn = zone->zone_start_pfn;
-		zone_end_pfn = zone_start_pfn + zone->spanned_pages;
-
-		nid = zone_to_nid(zone);
-		printk(KERN_INFO "Initializing %s for node %d (%08lx:%08lx)\n",
-				zone->name, nid, zone_start_pfn, zone_end_pfn);
-
-		add_highpages_with_active_regions(nid, zone_start_pfn,
-				 zone_end_pfn);
-	}
-	totalram_pages += totalhigh_pages;
-#endif
-}
-
-#ifdef CONFIG_MEMORY_HOTPLUG
-static int paddr_to_nid(u64 addr)
-{
-	int nid;
-	unsigned long pfn = PFN_DOWN(addr);
-
-	for_each_node(nid)
-		if (node_start_pfn[nid] <= pfn &&
-		    pfn < node_end_pfn[nid])
-			return nid;
-
-	return -1;
-}
-
-/*
- * This function is used to ask node id BEFORE memmap and mem_section's
- * initialization (pfn_to_nid() can't be used yet).
- * If _PXM is not defined on ACPI's DSDT, node id must be found by this.
- */
-int memory_add_physaddr_to_nid(u64 addr)
-{
-	int nid = paddr_to_nid(addr);
-	return (nid >= 0) ? nid : 0;
-}
-
-EXPORT_SYMBOL_GPL(memory_add_physaddr_to_nid);
-#endif
-
diff --git a/arch/x86/mm/dump_pagetables.c b/arch/x86/mm/dump_pagetables.c
index a20d1fa..e7277cb 100644
--- a/arch/x86/mm/dump_pagetables.c
+++ b/arch/x86/mm/dump_pagetables.c
@@ -148,8 +148,8 @@
 	 * we have now. "break" is either changing perms, levels or
 	 * address space marker.
 	 */
-	prot = pgprot_val(new_prot) & ~(PTE_PFN_MASK);
-	cur = pgprot_val(st->current_prot) & ~(PTE_PFN_MASK);
+	prot = pgprot_val(new_prot) & PTE_FLAGS_MASK;
+	cur = pgprot_val(st->current_prot) & PTE_FLAGS_MASK;
 
 	if (!st->level) {
 		/* First entry */
diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c
index 455f3fe..3f2b896 100644
--- a/arch/x86/mm/fault.c
+++ b/arch/x86/mm/fault.c
@@ -35,6 +35,7 @@
 #include <asm/tlbflush.h>
 #include <asm/proto.h>
 #include <asm-generic/sections.h>
+#include <asm/traps.h>
 
 /*
  * Page fault error code bits
@@ -357,8 +358,6 @@
 	return 0;
 }
 
-void do_invalid_op(struct pt_regs *, unsigned long);
-
 static int is_f00f_bug(struct pt_regs *regs, unsigned long address)
 {
 #ifdef CONFIG_X86_F00F_BUG
@@ -593,11 +592,6 @@
 	unsigned long flags;
 #endif
 
-	/*
-	 * We can fault from pretty much anywhere, with unknown IRQ state.
-	 */
-	trace_hardirqs_fixup();
-
 	tsk = current;
 	mm = tsk->mm;
 	prefetchw(&mm->mmap_sem);
@@ -915,15 +909,15 @@
 
 void vmalloc_sync_all(void)
 {
-#ifdef CONFIG_X86_32
-	unsigned long start = VMALLOC_START & PGDIR_MASK;
 	unsigned long address;
 
+#ifdef CONFIG_X86_32
 	if (SHARED_KERNEL_PMD)
 		return;
 
-	BUILD_BUG_ON(TASK_SIZE & ~PGDIR_MASK);
-	for (address = start; address >= TASK_SIZE; address += PGDIR_SIZE) {
+	for (address = VMALLOC_START & PMD_MASK;
+	     address >= TASK_SIZE && address < FIXADDR_TOP;
+	     address += PMD_SIZE) {
 		unsigned long flags;
 		struct page *page;
 
@@ -936,10 +930,8 @@
 		spin_unlock_irqrestore(&pgd_lock, flags);
 	}
 #else /* CONFIG_X86_64 */
-	unsigned long start = VMALLOC_START & PGDIR_MASK;
-	unsigned long address;
-
-	for (address = start; address <= VMALLOC_END; address += PGDIR_SIZE) {
+	for (address = VMALLOC_START & PGDIR_MASK; address <= VMALLOC_END;
+	     address += PGDIR_SIZE) {
 		const pgd_t *pgd_ref = pgd_offset_k(address);
 		unsigned long flags;
 		struct page *page;
diff --git a/arch/x86/mm/gup.c b/arch/x86/mm/gup.c
index 007bb06..4ba373c 100644
--- a/arch/x86/mm/gup.c
+++ b/arch/x86/mm/gup.c
@@ -82,7 +82,7 @@
 		pte_t pte = gup_get_pte(ptep);
 		struct page *page;
 
-		if ((pte_val(pte) & (mask | _PAGE_SPECIAL)) != mask) {
+		if ((pte_flags(pte) & (mask | _PAGE_SPECIAL)) != mask) {
 			pte_unmap(ptep);
 			return 0;
 		}
@@ -116,10 +116,10 @@
 	mask = _PAGE_PRESENT|_PAGE_USER;
 	if (write)
 		mask |= _PAGE_RW;
-	if ((pte_val(pte) & mask) != mask)
+	if ((pte_flags(pte) & mask) != mask)
 		return 0;
 	/* hugepages are never "special" */
-	VM_BUG_ON(pte_val(pte) & _PAGE_SPECIAL);
+	VM_BUG_ON(pte_flags(pte) & _PAGE_SPECIAL);
 	VM_BUG_ON(!pfn_valid(pte_pfn(pte)));
 
 	refs = 0;
@@ -173,10 +173,10 @@
 	mask = _PAGE_PRESENT|_PAGE_USER;
 	if (write)
 		mask |= _PAGE_RW;
-	if ((pte_val(pte) & mask) != mask)
+	if ((pte_flags(pte) & mask) != mask)
 		return 0;
 	/* hugepages are never "special" */
-	VM_BUG_ON(pte_val(pte) & _PAGE_SPECIAL);
+	VM_BUG_ON(pte_flags(pte) & _PAGE_SPECIAL);
 	VM_BUG_ON(!pfn_valid(pte_pfn(pte)));
 
 	refs = 0;
diff --git a/arch/x86/mm/init_32.c b/arch/x86/mm/init_32.c
index d37f293..8396868 100644
--- a/arch/x86/mm/init_32.c
+++ b/arch/x86/mm/init_32.c
@@ -31,6 +31,7 @@
 #include <linux/cpumask.h>
 
 #include <asm/asm.h>
+#include <asm/bios_ebda.h>
 #include <asm/processor.h>
 #include <asm/system.h>
 #include <asm/uaccess.h>
@@ -47,6 +48,7 @@
 #include <asm/paravirt.h>
 #include <asm/setup.h>
 #include <asm/cacheflush.h>
+#include <asm/smp.h>
 
 unsigned int __VMALLOC_RESERVE = 128 << 20;
 
@@ -194,11 +196,30 @@
 	pgd_t *pgd;
 	pmd_t *pmd;
 	pte_t *pte;
-	unsigned pages_2m = 0, pages_4k = 0;
+	unsigned pages_2m, pages_4k;
+	int mapping_iter;
+
+	/*
+	 * First iteration will setup identity mapping using large/small pages
+	 * based on use_pse, with other attributes same as set by
+	 * the early code in head_32.S
+	 *
+	 * Second iteration will setup the appropriate attributes (NX, GLOBAL..)
+	 * as desired for the kernel identity mapping.
+	 *
+	 * This two pass mechanism conforms to the TLB app note which says:
+	 *
+	 *     "Software should not write to a paging-structure entry in a way
+	 *      that would change, for any linear address, both the page size
+	 *      and either the page frame or attributes."
+	 */
+	mapping_iter = 1;
 
 	if (!cpu_has_pse)
 		use_pse = 0;
 
+repeat:
+	pages_2m = pages_4k = 0;
 	pfn = start_pfn;
 	pgd_idx = pgd_index((pfn<<PAGE_SHIFT) + PAGE_OFFSET);
 	pgd = pgd_base + pgd_idx;
@@ -224,6 +245,13 @@
 			if (use_pse) {
 				unsigned int addr2;
 				pgprot_t prot = PAGE_KERNEL_LARGE;
+				/*
+				 * first pass will use the same initial
+				 * identity mapping attribute + _PAGE_PSE.
+				 */
+				pgprot_t init_prot =
+					__pgprot(PTE_IDENT_ATTR |
+						 _PAGE_PSE);
 
 				addr2 = (pfn + PTRS_PER_PTE-1) * PAGE_SIZE +
 					PAGE_OFFSET + PAGE_SIZE-1;
@@ -233,7 +261,10 @@
 					prot = PAGE_KERNEL_LARGE_EXEC;
 
 				pages_2m++;
-				set_pmd(pmd, pfn_pmd(pfn, prot));
+				if (mapping_iter == 1)
+					set_pmd(pmd, pfn_pmd(pfn, init_prot));
+				else
+					set_pmd(pmd, pfn_pmd(pfn, prot));
 
 				pfn += PTRS_PER_PTE;
 				continue;
@@ -245,17 +276,43 @@
 			for (; pte_ofs < PTRS_PER_PTE && pfn < end_pfn;
 			     pte++, pfn++, pte_ofs++, addr += PAGE_SIZE) {
 				pgprot_t prot = PAGE_KERNEL;
+				/*
+				 * first pass will use the same initial
+				 * identity mapping attribute.
+				 */
+				pgprot_t init_prot = __pgprot(PTE_IDENT_ATTR);
 
 				if (is_kernel_text(addr))
 					prot = PAGE_KERNEL_EXEC;
 
 				pages_4k++;
-				set_pte(pte, pfn_pte(pfn, prot));
+				if (mapping_iter == 1)
+					set_pte(pte, pfn_pte(pfn, init_prot));
+				else
+					set_pte(pte, pfn_pte(pfn, prot));
 			}
 		}
 	}
-	update_page_count(PG_LEVEL_2M, pages_2m);
-	update_page_count(PG_LEVEL_4K, pages_4k);
+	if (mapping_iter == 1) {
+		/*
+		 * update direct mapping page count only in the first
+		 * iteration.
+		 */
+		update_page_count(PG_LEVEL_2M, pages_2m);
+		update_page_count(PG_LEVEL_4K, pages_4k);
+
+		/*
+		 * local global flush tlb, which will flush the previous
+		 * mappings present in both small and large page TLB's.
+		 */
+		__flush_tlb_all();
+
+		/*
+		 * Second iteration will set the actual desired PTE attributes.
+		 */
+		mapping_iter = 2;
+		goto repeat;
+	}
 }
 
 /*
@@ -458,11 +515,7 @@
 {
 	pgd_t *pgd_base = swapper_pg_dir;
 
-	paravirt_pagetable_setup_start(pgd_base);
-
 	permanent_kmaps_init(pgd_base);
-
-	paravirt_pagetable_setup_done(pgd_base);
 }
 
 #ifdef CONFIG_ACPI_SLEEP
@@ -505,7 +558,7 @@
 
 int nx_enabled;
 
-pteval_t __supported_pte_mask __read_mostly = ~(_PAGE_NX | _PAGE_GLOBAL);
+pteval_t __supported_pte_mask __read_mostly = ~(_PAGE_NX | _PAGE_GLOBAL | _PAGE_IOMAP);
 EXPORT_SYMBOL_GPL(__supported_pte_mask);
 
 #ifdef CONFIG_X86_PAE
@@ -722,7 +775,7 @@
 	after_init_bootmem = 1;
 }
 
-static void __init find_early_table_space(unsigned long end)
+static void __init find_early_table_space(unsigned long end, int use_pse)
 {
 	unsigned long puds, pmds, ptes, tables, start;
 
@@ -732,7 +785,7 @@
 	pmds = (end + PMD_SIZE - 1) >> PMD_SHIFT;
 	tables += PAGE_ALIGN(pmds * sizeof(pmd_t));
 
-	if (cpu_has_pse) {
+	if (use_pse) {
 		unsigned long extra;
 
 		extra = end - ((end>>PMD_SHIFT) << PMD_SHIFT);
@@ -772,12 +825,22 @@
 	pgd_t *pgd_base = swapper_pg_dir;
 	unsigned long start_pfn, end_pfn;
 	unsigned long big_page_start;
+#ifdef CONFIG_DEBUG_PAGEALLOC
+	/*
+	 * For CONFIG_DEBUG_PAGEALLOC, identity mapping will use small pages.
+	 * This will simplify cpa(), which otherwise needs to support splitting
+	 * large pages into small in interrupt context, etc.
+	 */
+	int use_pse = 0;
+#else
+	int use_pse = cpu_has_pse;
+#endif
 
 	/*
 	 * Find space for the kernel direct mapping tables.
 	 */
 	if (!after_init_bootmem)
-		find_early_table_space(end);
+		find_early_table_space(end, use_pse);
 
 #ifdef CONFIG_X86_PAE
 	set_nx();
@@ -823,7 +886,7 @@
 	end_pfn = (end>>PMD_SHIFT) << (PMD_SHIFT - PAGE_SHIFT);
 	if (start_pfn < end_pfn)
 		kernel_physical_mapping_init(pgd_base, start_pfn, end_pfn,
-						cpu_has_pse);
+					     use_pse);
 
 	/* tail is not big page alignment ? */
 	start_pfn = end_pfn;
@@ -907,6 +970,8 @@
 	int codesize, reservedpages, datasize, initsize;
 	int tmp;
 
+	start_periodic_check_for_corruption();
+
 #ifdef CONFIG_FLATMEM
 	BUG_ON(!mem_map);
 #endif
@@ -986,7 +1051,6 @@
 	if (boot_cpu_data.wp_works_ok < 0)
 		test_wp_bit();
 
-	cpa_init();
 	save_pg_dir();
 	zap_low_mappings();
 }
diff --git a/arch/x86/mm/init_64.c b/arch/x86/mm/init_64.c
index d3746ef..b8e461d 100644
--- a/arch/x86/mm/init_64.c
+++ b/arch/x86/mm/init_64.c
@@ -31,6 +31,7 @@
 #include <linux/nmi.h>
 
 #include <asm/processor.h>
+#include <asm/bios_ebda.h>
 #include <asm/system.h>
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
@@ -88,6 +89,62 @@
 
 int after_bootmem;
 
+pteval_t __supported_pte_mask __read_mostly = ~_PAGE_IOMAP;
+EXPORT_SYMBOL_GPL(__supported_pte_mask);
+
+static int do_not_nx __cpuinitdata;
+
+/*
+ * noexec=on|off
+ * Control non-executable mappings for 64-bit processes.
+ *
+ * on	Enable (default)
+ * off	Disable
+ */
+static int __init nonx_setup(char *str)
+{
+	if (!str)
+		return -EINVAL;
+	if (!strncmp(str, "on", 2)) {
+		__supported_pte_mask |= _PAGE_NX;
+		do_not_nx = 0;
+	} else if (!strncmp(str, "off", 3)) {
+		do_not_nx = 1;
+		__supported_pte_mask &= ~_PAGE_NX;
+	}
+	return 0;
+}
+early_param("noexec", nonx_setup);
+
+void __cpuinit check_efer(void)
+{
+	unsigned long efer;
+
+	rdmsrl(MSR_EFER, efer);
+	if (!(efer & EFER_NX) || do_not_nx)
+		__supported_pte_mask &= ~_PAGE_NX;
+}
+
+int force_personality32;
+
+/*
+ * noexec32=on|off
+ * Control non executable heap for 32bit processes.
+ * To control the stack too use noexec=off
+ *
+ * on	PROT_READ does not imply PROT_EXEC for 32-bit processes (default)
+ * off	PROT_READ implies PROT_EXEC
+ */
+static int __init nonx32_setup(char *str)
+{
+	if (!strcmp(str, "on"))
+		force_personality32 &= ~READ_IMPLIES_EXEC;
+	else if (!strcmp(str, "off"))
+		force_personality32 |= READ_IMPLIES_EXEC;
+	return 1;
+}
+__setup("noexec32=", nonx32_setup);
+
 /*
  * NOTE: This function is marked __ref because it calls __init function
  * (alloc_bootmem_pages). It's safe to do it ONLY when after_bootmem == 0.
@@ -139,9 +196,6 @@
 	}
 
 	pte = pte_offset_kernel(pmd, vaddr);
-	if (!pte_none(*pte) && pte_val(new_pte) &&
-	    pte_val(*pte) != (pte_val(new_pte) & __supported_pte_mask))
-		pte_ERROR(*pte);
 	set_pte(pte, new_pte);
 
 	/*
@@ -225,7 +279,7 @@
 void __init cleanup_highmap(void)
 {
 	unsigned long vaddr = __START_KERNEL_map;
-	unsigned long end = round_up((unsigned long)_end, PMD_SIZE) - 1;
+	unsigned long end = roundup((unsigned long)_end, PMD_SIZE) - 1;
 	pmd_t *pmd = level2_kernel_pgt;
 	pmd_t *last_pmd = pmd + PTRS_PER_PMD;
 
@@ -256,7 +310,7 @@
 	if (pfn >= table_top)
 		panic("alloc_low_page: ran out of memory");
 
-	adr = early_ioremap(pfn * PAGE_SIZE, PAGE_SIZE);
+	adr = early_memremap(pfn * PAGE_SIZE, PAGE_SIZE);
 	memset(adr, 0, PAGE_SIZE);
 	*phys  = pfn * PAGE_SIZE;
 	return adr;
@@ -271,7 +325,8 @@
 }
 
 static unsigned long __meminit
-phys_pte_init(pte_t *pte_page, unsigned long addr, unsigned long end)
+phys_pte_init(pte_t *pte_page, unsigned long addr, unsigned long end,
+	      pgprot_t prot)
 {
 	unsigned pages = 0;
 	unsigned long last_map_addr = end;
@@ -289,36 +344,43 @@
 			break;
 		}
 
+		/*
+		 * We will re-use the existing mapping.
+		 * Xen for example has some special requirements, like mapping
+		 * pagetable pages as RO. So assume someone who pre-setup
+		 * these mappings are more intelligent.
+		 */
 		if (pte_val(*pte))
 			continue;
 
 		if (0)
 			printk("   pte=%p addr=%lx pte=%016lx\n",
 			       pte, addr, pfn_pte(addr >> PAGE_SHIFT, PAGE_KERNEL).pte);
-		set_pte(pte, pfn_pte(addr >> PAGE_SHIFT, PAGE_KERNEL));
-		last_map_addr = (addr & PAGE_MASK) + PAGE_SIZE;
 		pages++;
+		set_pte(pte, pfn_pte(addr >> PAGE_SHIFT, prot));
+		last_map_addr = (addr & PAGE_MASK) + PAGE_SIZE;
 	}
+
 	update_page_count(PG_LEVEL_4K, pages);
 
 	return last_map_addr;
 }
 
 static unsigned long __meminit
-phys_pte_update(pmd_t *pmd, unsigned long address, unsigned long end)
+phys_pte_update(pmd_t *pmd, unsigned long address, unsigned long end,
+		pgprot_t prot)
 {
 	pte_t *pte = (pte_t *)pmd_page_vaddr(*pmd);
 
-	return phys_pte_init(pte, address, end);
+	return phys_pte_init(pte, address, end, prot);
 }
 
 static unsigned long __meminit
 phys_pmd_init(pmd_t *pmd_page, unsigned long address, unsigned long end,
-			 unsigned long page_size_mask)
+	      unsigned long page_size_mask, pgprot_t prot)
 {
 	unsigned long pages = 0;
 	unsigned long last_map_addr = end;
-	unsigned long start = address;
 
 	int i = pmd_index(address);
 
@@ -326,6 +388,7 @@
 		unsigned long pte_phys;
 		pmd_t *pmd = pmd_page + pmd_index(address);
 		pte_t *pte;
+		pgprot_t new_prot = prot;
 
 		if (address >= end) {
 			if (!after_bootmem) {
@@ -339,27 +402,40 @@
 			if (!pmd_large(*pmd)) {
 				spin_lock(&init_mm.page_table_lock);
 				last_map_addr = phys_pte_update(pmd, address,
-								end);
+								end, prot);
 				spin_unlock(&init_mm.page_table_lock);
+				continue;
 			}
-			/* Count entries we're using from level2_ident_pgt */
-			if (start == 0)
-				pages++;
-			continue;
+			/*
+			 * If we are ok with PG_LEVEL_2M mapping, then we will
+			 * use the existing mapping,
+			 *
+			 * Otherwise, we will split the large page mapping but
+			 * use the same existing protection bits except for
+			 * large page, so that we don't violate Intel's TLB
+			 * Application note (317080) which says, while changing
+			 * the page sizes, new and old translations should
+			 * not differ with respect to page frame and
+			 * attributes.
+			 */
+			if (page_size_mask & (1 << PG_LEVEL_2M))
+				continue;
+			new_prot = pte_pgprot(pte_clrhuge(*(pte_t *)pmd));
 		}
 
 		if (page_size_mask & (1<<PG_LEVEL_2M)) {
 			pages++;
 			spin_lock(&init_mm.page_table_lock);
 			set_pte((pte_t *)pmd,
-				pfn_pte(address >> PAGE_SHIFT, PAGE_KERNEL_LARGE));
+				pfn_pte(address >> PAGE_SHIFT,
+					__pgprot(pgprot_val(prot) | _PAGE_PSE)));
 			spin_unlock(&init_mm.page_table_lock);
 			last_map_addr = (address & PMD_MASK) + PMD_SIZE;
 			continue;
 		}
 
 		pte = alloc_low_page(&pte_phys);
-		last_map_addr = phys_pte_init(pte, address, end);
+		last_map_addr = phys_pte_init(pte, address, end, new_prot);
 		unmap_low_page(pte);
 
 		spin_lock(&init_mm.page_table_lock);
@@ -372,12 +448,12 @@
 
 static unsigned long __meminit
 phys_pmd_update(pud_t *pud, unsigned long address, unsigned long end,
-			 unsigned long page_size_mask)
+		unsigned long page_size_mask, pgprot_t prot)
 {
 	pmd_t *pmd = pmd_offset(pud, 0);
 	unsigned long last_map_addr;
 
-	last_map_addr = phys_pmd_init(pmd, address, end, page_size_mask);
+	last_map_addr = phys_pmd_init(pmd, address, end, page_size_mask, prot);
 	__flush_tlb_all();
 	return last_map_addr;
 }
@@ -394,6 +470,7 @@
 		unsigned long pmd_phys;
 		pud_t *pud = pud_page + pud_index(addr);
 		pmd_t *pmd;
+		pgprot_t prot = PAGE_KERNEL;
 
 		if (addr >= end)
 			break;
@@ -405,10 +482,26 @@
 		}
 
 		if (pud_val(*pud)) {
-			if (!pud_large(*pud))
+			if (!pud_large(*pud)) {
 				last_map_addr = phys_pmd_update(pud, addr, end,
-							 page_size_mask);
-			continue;
+							 page_size_mask, prot);
+				continue;
+			}
+			/*
+			 * If we are ok with PG_LEVEL_1G mapping, then we will
+			 * use the existing mapping.
+			 *
+			 * Otherwise, we will split the gbpage mapping but use
+			 * the same existing protection  bits except for large
+			 * page, so that we don't violate Intel's TLB
+			 * Application note (317080) which says, while changing
+			 * the page sizes, new and old translations should
+			 * not differ with respect to page frame and
+			 * attributes.
+			 */
+			if (page_size_mask & (1 << PG_LEVEL_1G))
+				continue;
+			prot = pte_pgprot(pte_clrhuge(*(pte_t *)pud));
 		}
 
 		if (page_size_mask & (1<<PG_LEVEL_1G)) {
@@ -422,7 +515,8 @@
 		}
 
 		pmd = alloc_low_page(&pmd_phys);
-		last_map_addr = phys_pmd_init(pmd, addr, end, page_size_mask);
+		last_map_addr = phys_pmd_init(pmd, addr, end, page_size_mask,
+					      prot);
 		unmap_low_page(pmd);
 
 		spin_lock(&init_mm.page_table_lock);
@@ -430,6 +524,7 @@
 		spin_unlock(&init_mm.page_table_lock);
 	}
 	__flush_tlb_all();
+
 	update_page_count(PG_LEVEL_1G, pages);
 
 	return last_map_addr;
@@ -446,27 +541,28 @@
 	return phys_pud_init(pud, addr, end, page_size_mask);
 }
 
-static void __init find_early_table_space(unsigned long end)
+static void __init find_early_table_space(unsigned long end, int use_pse,
+					  int use_gbpages)
 {
 	unsigned long puds, pmds, ptes, tables, start;
 
 	puds = (end + PUD_SIZE - 1) >> PUD_SHIFT;
-	tables = round_up(puds * sizeof(pud_t), PAGE_SIZE);
-	if (direct_gbpages) {
+	tables = roundup(puds * sizeof(pud_t), PAGE_SIZE);
+	if (use_gbpages) {
 		unsigned long extra;
 		extra = end - ((end>>PUD_SHIFT) << PUD_SHIFT);
 		pmds = (extra + PMD_SIZE - 1) >> PMD_SHIFT;
 	} else
 		pmds = (end + PMD_SIZE - 1) >> PMD_SHIFT;
-	tables += round_up(pmds * sizeof(pmd_t), PAGE_SIZE);
+	tables += roundup(pmds * sizeof(pmd_t), PAGE_SIZE);
 
-	if (cpu_has_pse) {
+	if (use_pse) {
 		unsigned long extra;
 		extra = end - ((end>>PMD_SHIFT) << PMD_SHIFT);
 		ptes = (extra + PAGE_SIZE - 1) >> PAGE_SHIFT;
 	} else
 		ptes = (end + PAGE_SIZE - 1) >> PAGE_SHIFT;
-	tables += round_up(ptes * sizeof(pte_t), PAGE_SIZE);
+	tables += roundup(ptes * sizeof(pte_t), PAGE_SIZE);
 
 	/*
 	 * RED-PEN putting page tables only on node 0 could
@@ -528,6 +624,7 @@
 		pgd_populate(&init_mm, pgd, __va(pud_phys));
 		spin_unlock(&init_mm.page_table_lock);
 	}
+	__flush_tlb_all();
 
 	return last_map_addr;
 }
@@ -571,6 +668,7 @@
 
 	struct map_range mr[NR_RANGE_MR];
 	int nr_range, i;
+	int use_pse, use_gbpages;
 
 	printk(KERN_INFO "init_memory_mapping\n");
 
@@ -584,9 +682,21 @@
 	if (!after_bootmem)
 		init_gbpages();
 
-	if (direct_gbpages)
+#ifdef CONFIG_DEBUG_PAGEALLOC
+	/*
+	 * For CONFIG_DEBUG_PAGEALLOC, identity mapping will use small pages.
+	 * This will simplify cpa(), which otherwise needs to support splitting
+	 * large pages into small in interrupt context, etc.
+	 */
+	use_pse = use_gbpages = 0;
+#else
+	use_pse = cpu_has_pse;
+	use_gbpages = direct_gbpages;
+#endif
+
+	if (use_gbpages)
 		page_size_mask |= 1 << PG_LEVEL_1G;
-	if (cpu_has_pse)
+	if (use_pse)
 		page_size_mask |= 1 << PG_LEVEL_2M;
 
 	memset(mr, 0, sizeof(mr));
@@ -636,7 +746,7 @@
 		old_start = mr[i].start;
 		memmove(&mr[i], &mr[i+1],
 			 (nr_range - 1 - i) * sizeof (struct map_range));
-		mr[i].start = old_start;
+		mr[i--].start = old_start;
 		nr_range--;
 	}
 
@@ -647,7 +757,7 @@
 			 (mr[i].page_size_mask & (1<<PG_LEVEL_2M))?"2M":"4k"));
 
 	if (!after_bootmem)
-		find_early_table_space(end);
+		find_early_table_space(end, use_pse, use_gbpages);
 
 	for (i = 0; i < nr_range; i++)
 		last_map_addr = kernel_physical_mapping_init(
@@ -769,6 +879,8 @@
 {
 	long codesize, reservedpages, datasize, initsize;
 
+	start_periodic_check_for_corruption();
+
 	pci_iommu_alloc();
 
 	/* clear_bss() already clear the empty_zero_page */
@@ -806,8 +918,6 @@
 		reservedpages << (PAGE_SHIFT-10),
 		datasize >> 10,
 		initsize >> 10);
-
-	cpa_init();
 }
 
 void free_init_pages(char *what, unsigned long begin, unsigned long end)
diff --git a/arch/x86/mm/ioremap.c b/arch/x86/mm/ioremap.c
index d4b6e6a..ae71e11 100644
--- a/arch/x86/mm/ioremap.c
+++ b/arch/x86/mm/ioremap.c
@@ -24,19 +24,48 @@
 
 #ifdef CONFIG_X86_64
 
-unsigned long __phys_addr(unsigned long x)
-{
-	if (x >= __START_KERNEL_map)
-		return x - __START_KERNEL_map + phys_base;
-	return x - PAGE_OFFSET;
-}
-EXPORT_SYMBOL(__phys_addr);
-
 static inline int phys_addr_valid(unsigned long addr)
 {
 	return addr < (1UL << boot_cpu_data.x86_phys_bits);
 }
 
+unsigned long __phys_addr(unsigned long x)
+{
+	if (x >= __START_KERNEL_map) {
+		x -= __START_KERNEL_map;
+		VIRTUAL_BUG_ON(x >= KERNEL_IMAGE_SIZE);
+		x += phys_base;
+	} else {
+		VIRTUAL_BUG_ON(x < PAGE_OFFSET);
+		x -= PAGE_OFFSET;
+		VIRTUAL_BUG_ON(system_state == SYSTEM_BOOTING ? x > MAXMEM :
+					!phys_addr_valid(x));
+	}
+	return x;
+}
+EXPORT_SYMBOL(__phys_addr);
+
+bool __virt_addr_valid(unsigned long x)
+{
+	if (x >= __START_KERNEL_map) {
+		x -= __START_KERNEL_map;
+		if (x >= KERNEL_IMAGE_SIZE)
+			return false;
+		x += phys_base;
+	} else {
+		if (x < PAGE_OFFSET)
+			return false;
+		x -= PAGE_OFFSET;
+		if (system_state == SYSTEM_BOOTING ?
+				x > MAXMEM : !phys_addr_valid(x)) {
+			return false;
+		}
+	}
+
+	return pfn_valid(x >> PAGE_SHIFT);
+}
+EXPORT_SYMBOL(__virt_addr_valid);
+
 #else
 
 static inline int phys_addr_valid(unsigned long addr)
@@ -44,6 +73,28 @@
 	return 1;
 }
 
+#ifdef CONFIG_DEBUG_VIRTUAL
+unsigned long __phys_addr(unsigned long x)
+{
+	/* VMALLOC_* aren't constants; not available at the boot time */
+	VIRTUAL_BUG_ON(x < PAGE_OFFSET);
+	VIRTUAL_BUG_ON(system_state != SYSTEM_BOOTING &&
+		is_vmalloc_addr((void *) x));
+	return x - PAGE_OFFSET;
+}
+EXPORT_SYMBOL(__phys_addr);
+#endif
+
+bool __virt_addr_valid(unsigned long x)
+{
+	if (x < PAGE_OFFSET)
+		return false;
+	if (system_state != SYSTEM_BOOTING && is_vmalloc_addr((void *) x))
+		return false;
+	return pfn_valid((x - PAGE_OFFSET) >> PAGE_SHIFT);
+}
+EXPORT_SYMBOL(__virt_addr_valid);
+
 #endif
 
 int page_is_ram(unsigned long pagenr)
@@ -83,6 +134,25 @@
 	return 0;
 }
 
+int pagerange_is_ram(unsigned long start, unsigned long end)
+{
+	int ram_page = 0, not_rampage = 0;
+	unsigned long page_nr;
+
+	for (page_nr = (start >> PAGE_SHIFT); page_nr < (end >> PAGE_SHIFT);
+	     ++page_nr) {
+		if (page_is_ram(page_nr))
+			ram_page = 1;
+		else
+			not_rampage = 1;
+
+		if (ram_page == not_rampage)
+			return -1;
+	}
+
+	return ram_page;
+}
+
 /*
  * Fix up the linear direct mapping of the kernel to avoid cache attribute
  * conflicts.
@@ -150,6 +220,12 @@
 		return (__force void __iomem *)phys_to_virt(phys_addr);
 
 	/*
+	 * Check if the request spans more than any BAR in the iomem resource
+	 * tree.
+	 */
+	WARN_ON(iomem_map_sanity_check(phys_addr, size));
+
+	/*
 	 * Don't allow anybody to remap normal RAM that we're using..
 	 */
 	for (pfn = phys_addr >> PAGE_SHIFT;
@@ -204,16 +280,16 @@
 	switch (prot_val) {
 	case _PAGE_CACHE_UC:
 	default:
-		prot = PAGE_KERNEL_NOCACHE;
+		prot = PAGE_KERNEL_IO_NOCACHE;
 		break;
 	case _PAGE_CACHE_UC_MINUS:
-		prot = PAGE_KERNEL_UC_MINUS;
+		prot = PAGE_KERNEL_IO_UC_MINUS;
 		break;
 	case _PAGE_CACHE_WC:
-		prot = PAGE_KERNEL_WC;
+		prot = PAGE_KERNEL_IO_WC;
 		break;
 	case _PAGE_CACHE_WB:
-		prot = PAGE_KERNEL;
+		prot = PAGE_KERNEL_IO;
 		break;
 	}
 
@@ -421,7 +497,7 @@
 	return;
 }
 
-int __initdata early_ioremap_debug;
+static int __initdata early_ioremap_debug;
 
 static int __init early_ioremap_debug_setup(char *str)
 {
@@ -530,12 +606,12 @@
 }
 
 static inline void __init early_set_fixmap(enum fixed_addresses idx,
-					unsigned long phys)
+					   unsigned long phys, pgprot_t prot)
 {
 	if (after_paging_init)
-		set_fixmap(idx, phys);
+		__set_fixmap(idx, phys, prot);
 	else
-		__early_set_fixmap(idx, phys, PAGE_KERNEL);
+		__early_set_fixmap(idx, phys, prot);
 }
 
 static inline void __init early_clear_fixmap(enum fixed_addresses idx)
@@ -546,16 +622,22 @@
 		__early_set_fixmap(idx, 0, __pgprot(0));
 }
 
-
-int __initdata early_ioremap_nested;
-
+static void *prev_map[FIX_BTMAPS_SLOTS] __initdata;
+static unsigned long prev_size[FIX_BTMAPS_SLOTS] __initdata;
 static int __init check_early_ioremap_leak(void)
 {
-	if (!early_ioremap_nested)
+	int count = 0;
+	int i;
+
+	for (i = 0; i < FIX_BTMAPS_SLOTS; i++)
+		if (prev_map[i])
+			count++;
+
+	if (!count)
 		return 0;
 	WARN(1, KERN_WARNING
 	       "Debug warning: early ioremap leak of %d areas detected.\n",
-		early_ioremap_nested);
+		count);
 	printk(KERN_WARNING
 		"please boot with early_ioremap_debug and report the dmesg.\n");
 
@@ -563,18 +645,33 @@
 }
 late_initcall(check_early_ioremap_leak);
 
-void __init *early_ioremap(unsigned long phys_addr, unsigned long size)
+static void __init *__early_ioremap(unsigned long phys_addr, unsigned long size, pgprot_t prot)
 {
 	unsigned long offset, last_addr;
-	unsigned int nrpages, nesting;
+	unsigned int nrpages;
 	enum fixed_addresses idx0, idx;
+	int i, slot;
 
 	WARN_ON(system_state != SYSTEM_BOOTING);
 
-	nesting = early_ioremap_nested;
+	slot = -1;
+	for (i = 0; i < FIX_BTMAPS_SLOTS; i++) {
+		if (!prev_map[i]) {
+			slot = i;
+			break;
+		}
+	}
+
+	if (slot < 0) {
+		printk(KERN_INFO "early_iomap(%08lx, %08lx) not found slot\n",
+			 phys_addr, size);
+		WARN_ON(1);
+		return NULL;
+	}
+
 	if (early_ioremap_debug) {
 		printk(KERN_INFO "early_ioremap(%08lx, %08lx) [%d] => ",
-		       phys_addr, size, nesting);
+		       phys_addr, size, slot);
 		dump_stack();
 	}
 
@@ -585,17 +682,13 @@
 		return NULL;
 	}
 
-	if (nesting >= FIX_BTMAPS_NESTING) {
-		WARN_ON(1);
-		return NULL;
-	}
-	early_ioremap_nested++;
+	prev_size[slot] = size;
 	/*
 	 * Mappings have to be page-aligned
 	 */
 	offset = phys_addr & ~PAGE_MASK;
 	phys_addr &= PAGE_MASK;
-	size = PAGE_ALIGN(last_addr) - phys_addr;
+	size = PAGE_ALIGN(last_addr + 1) - phys_addr;
 
 	/*
 	 * Mappings have to fit in the FIX_BTMAP area.
@@ -609,10 +702,10 @@
 	/*
 	 * Ok, go for it..
 	 */
-	idx0 = FIX_BTMAP_BEGIN - NR_FIX_BTMAPS*nesting;
+	idx0 = FIX_BTMAP_BEGIN - NR_FIX_BTMAPS*slot;
 	idx = idx0;
 	while (nrpages > 0) {
-		early_set_fixmap(idx, phys_addr);
+		early_set_fixmap(idx, phys_addr, prot);
 		phys_addr += PAGE_SIZE;
 		--idx;
 		--nrpages;
@@ -620,7 +713,20 @@
 	if (early_ioremap_debug)
 		printk(KERN_CONT "%08lx + %08lx\n", offset, fix_to_virt(idx0));
 
-	return (void *) (offset + fix_to_virt(idx0));
+	prev_map[slot] = (void *) (offset + fix_to_virt(idx0));
+	return prev_map[slot];
+}
+
+/* Remap an IO device */
+void __init *early_ioremap(unsigned long phys_addr, unsigned long size)
+{
+	return __early_ioremap(phys_addr, size, PAGE_KERNEL_IO);
+}
+
+/* Remap memory */
+void __init *early_memremap(unsigned long phys_addr, unsigned long size)
+{
+	return __early_ioremap(phys_addr, size, PAGE_KERNEL);
 }
 
 void __init early_iounmap(void *addr, unsigned long size)
@@ -629,15 +735,33 @@
 	unsigned long offset;
 	unsigned int nrpages;
 	enum fixed_addresses idx;
-	int nesting;
+	int i, slot;
 
-	nesting = --early_ioremap_nested;
-	if (WARN_ON(nesting < 0))
+	slot = -1;
+	for (i = 0; i < FIX_BTMAPS_SLOTS; i++) {
+		if (prev_map[i] == addr) {
+			slot = i;
+			break;
+		}
+	}
+
+	if (slot < 0) {
+		printk(KERN_INFO "early_iounmap(%p, %08lx) not found slot\n",
+			 addr, size);
+		WARN_ON(1);
 		return;
+	}
+
+	if (prev_size[slot] != size) {
+		printk(KERN_INFO "early_iounmap(%p, %08lx) [%d] size not consistent %08lx\n",
+			 addr, size, slot, prev_size[slot]);
+		WARN_ON(1);
+		return;
+	}
 
 	if (early_ioremap_debug) {
 		printk(KERN_INFO "early_iounmap(%p, %08lx) [%d]\n", addr,
-		       size, nesting);
+		       size, slot);
 		dump_stack();
 	}
 
@@ -649,12 +773,13 @@
 	offset = virt_addr & ~PAGE_MASK;
 	nrpages = PAGE_ALIGN(offset + size - 1) >> PAGE_SHIFT;
 
-	idx = FIX_BTMAP_BEGIN - NR_FIX_BTMAPS*nesting;
+	idx = FIX_BTMAP_BEGIN - NR_FIX_BTMAPS*slot;
 	while (nrpages > 0) {
 		early_clear_fixmap(idx);
 		--idx;
 		--nrpages;
 	}
+	prev_map[slot] = 0;
 }
 
 void __this_fixmap_does_not_exist(void)
diff --git a/arch/x86/mm/numa_32.c b/arch/x86/mm/numa_32.c
new file mode 100644
index 0000000..847c164
--- /dev/null
+++ b/arch/x86/mm/numa_32.c
@@ -0,0 +1,444 @@
+/*
+ * Written by: Patricia Gaughen <gone@us.ibm.com>, IBM Corporation
+ * August 2002: added remote node KVA remap - Martin J. Bligh 
+ *
+ * Copyright (C) 2002, IBM Corp.
+ *
+ * All rights reserved.          
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/mm.h>
+#include <linux/bootmem.h>
+#include <linux/mmzone.h>
+#include <linux/highmem.h>
+#include <linux/initrd.h>
+#include <linux/nodemask.h>
+#include <linux/module.h>
+#include <linux/kexec.h>
+#include <linux/pfn.h>
+#include <linux/swap.h>
+#include <linux/acpi.h>
+
+#include <asm/e820.h>
+#include <asm/setup.h>
+#include <asm/mmzone.h>
+#include <asm/bios_ebda.h>
+#include <asm/proto.h>
+
+struct pglist_data *node_data[MAX_NUMNODES] __read_mostly;
+EXPORT_SYMBOL(node_data);
+
+/*
+ * numa interface - we expect the numa architecture specific code to have
+ *                  populated the following initialisation.
+ *
+ * 1) node_online_map  - the map of all nodes configured (online) in the system
+ * 2) node_start_pfn   - the starting page frame number for a node
+ * 3) node_end_pfn     - the ending page fram number for a node
+ */
+unsigned long node_start_pfn[MAX_NUMNODES] __read_mostly;
+unsigned long node_end_pfn[MAX_NUMNODES] __read_mostly;
+
+
+#ifdef CONFIG_DISCONTIGMEM
+/*
+ * 4) physnode_map     - the mapping between a pfn and owning node
+ * physnode_map keeps track of the physical memory layout of a generic
+ * numa node on a 64Mb break (each element of the array will
+ * represent 64Mb of memory and will be marked by the node id.  so,
+ * if the first gig is on node 0, and the second gig is on node 1
+ * physnode_map will contain:
+ *
+ *     physnode_map[0-15] = 0;
+ *     physnode_map[16-31] = 1;
+ *     physnode_map[32- ] = -1;
+ */
+s8 physnode_map[MAX_ELEMENTS] __read_mostly = { [0 ... (MAX_ELEMENTS - 1)] = -1};
+EXPORT_SYMBOL(physnode_map);
+
+void memory_present(int nid, unsigned long start, unsigned long end)
+{
+	unsigned long pfn;
+
+	printk(KERN_INFO "Node: %d, start_pfn: %lx, end_pfn: %lx\n",
+			nid, start, end);
+	printk(KERN_DEBUG "  Setting physnode_map array to node %d for pfns:\n", nid);
+	printk(KERN_DEBUG "  ");
+	for (pfn = start; pfn < end; pfn += PAGES_PER_ELEMENT) {
+		physnode_map[pfn / PAGES_PER_ELEMENT] = nid;
+		printk(KERN_CONT "%lx ", pfn);
+	}
+	printk(KERN_CONT "\n");
+}
+
+unsigned long node_memmap_size_bytes(int nid, unsigned long start_pfn,
+					      unsigned long end_pfn)
+{
+	unsigned long nr_pages = end_pfn - start_pfn;
+
+	if (!nr_pages)
+		return 0;
+
+	return (nr_pages + 1) * sizeof(struct page);
+}
+#endif
+
+extern unsigned long find_max_low_pfn(void);
+extern unsigned long highend_pfn, highstart_pfn;
+
+#define LARGE_PAGE_BYTES (PTRS_PER_PTE * PAGE_SIZE)
+
+unsigned long node_remap_size[MAX_NUMNODES];
+static void *node_remap_start_vaddr[MAX_NUMNODES];
+void set_pmd_pfn(unsigned long vaddr, unsigned long pfn, pgprot_t flags);
+
+static unsigned long kva_start_pfn;
+static unsigned long kva_pages;
+/*
+ * FLAT - support for basic PC memory model with discontig enabled, essentially
+ *        a single node with all available processors in it with a flat
+ *        memory map.
+ */
+int __init get_memcfg_numa_flat(void)
+{
+	printk(KERN_DEBUG "NUMA - single node, flat memory mode\n");
+
+	node_start_pfn[0] = 0;
+	node_end_pfn[0] = max_pfn;
+	e820_register_active_regions(0, 0, max_pfn);
+	memory_present(0, 0, max_pfn);
+	node_remap_size[0] = node_memmap_size_bytes(0, 0, max_pfn);
+
+        /* Indicate there is one node available. */
+	nodes_clear(node_online_map);
+	node_set_online(0);
+	return 1;
+}
+
+/*
+ * Find the highest page frame number we have available for the node
+ */
+static void __init propagate_e820_map_node(int nid)
+{
+	if (node_end_pfn[nid] > max_pfn)
+		node_end_pfn[nid] = max_pfn;
+	/*
+	 * if a user has given mem=XXXX, then we need to make sure 
+	 * that the node _starts_ before that, too, not just ends
+	 */
+	if (node_start_pfn[nid] > max_pfn)
+		node_start_pfn[nid] = max_pfn;
+	BUG_ON(node_start_pfn[nid] > node_end_pfn[nid]);
+}
+
+/* 
+ * Allocate memory for the pg_data_t for this node via a crude pre-bootmem
+ * method.  For node zero take this from the bottom of memory, for
+ * subsequent nodes place them at node_remap_start_vaddr which contains
+ * node local data in physically node local memory.  See setup_memory()
+ * for details.
+ */
+static void __init allocate_pgdat(int nid)
+{
+	char buf[16];
+
+	if (node_has_online_mem(nid) && node_remap_start_vaddr[nid])
+		NODE_DATA(nid) = (pg_data_t *)node_remap_start_vaddr[nid];
+	else {
+		unsigned long pgdat_phys;
+		pgdat_phys = find_e820_area(min_low_pfn<<PAGE_SHIFT,
+				 max_pfn_mapped<<PAGE_SHIFT,
+				 sizeof(pg_data_t),
+				 PAGE_SIZE);
+		NODE_DATA(nid) = (pg_data_t *)(pfn_to_kaddr(pgdat_phys>>PAGE_SHIFT));
+		memset(buf, 0, sizeof(buf));
+		sprintf(buf, "NODE_DATA %d",  nid);
+		reserve_early(pgdat_phys, pgdat_phys + sizeof(pg_data_t), buf);
+	}
+	printk(KERN_DEBUG "allocate_pgdat: node %d NODE_DATA %08lx\n",
+		nid, (unsigned long)NODE_DATA(nid));
+}
+
+/*
+ * In the DISCONTIGMEM and SPARSEMEM memory model, a portion of the kernel
+ * virtual address space (KVA) is reserved and portions of nodes are mapped
+ * using it. This is to allow node-local memory to be allocated for
+ * structures that would normally require ZONE_NORMAL. The memory is
+ * allocated with alloc_remap() and callers should be prepared to allocate
+ * from the bootmem allocator instead.
+ */
+static unsigned long node_remap_start_pfn[MAX_NUMNODES];
+static void *node_remap_end_vaddr[MAX_NUMNODES];
+static void *node_remap_alloc_vaddr[MAX_NUMNODES];
+static unsigned long node_remap_offset[MAX_NUMNODES];
+
+void *alloc_remap(int nid, unsigned long size)
+{
+	void *allocation = node_remap_alloc_vaddr[nid];
+
+	size = ALIGN(size, L1_CACHE_BYTES);
+
+	if (!allocation || (allocation + size) >= node_remap_end_vaddr[nid])
+		return 0;
+
+	node_remap_alloc_vaddr[nid] += size;
+	memset(allocation, 0, size);
+
+	return allocation;
+}
+
+static void __init remap_numa_kva(void)
+{
+	void *vaddr;
+	unsigned long pfn;
+	int node;
+
+	for_each_online_node(node) {
+		printk(KERN_DEBUG "remap_numa_kva: node %d\n", node);
+		for (pfn=0; pfn < node_remap_size[node]; pfn += PTRS_PER_PTE) {
+			vaddr = node_remap_start_vaddr[node]+(pfn<<PAGE_SHIFT);
+			printk(KERN_DEBUG "remap_numa_kva: %08lx to pfn %08lx\n",
+				(unsigned long)vaddr,
+				node_remap_start_pfn[node] + pfn);
+			set_pmd_pfn((ulong) vaddr, 
+				node_remap_start_pfn[node] + pfn, 
+				PAGE_KERNEL_LARGE);
+		}
+	}
+}
+
+static unsigned long calculate_numa_remap_pages(void)
+{
+	int nid;
+	unsigned long size, reserve_pages = 0;
+
+	for_each_online_node(nid) {
+		u64 node_kva_target;
+		u64 node_kva_final;
+
+		/*
+		 * The acpi/srat node info can show hot-add memroy zones
+		 * where memory could be added but not currently present.
+		 */
+		printk(KERN_DEBUG "node %d pfn: [%lx - %lx]\n",
+			nid, node_start_pfn[nid], node_end_pfn[nid]);
+		if (node_start_pfn[nid] > max_pfn)
+			continue;
+		if (!node_end_pfn[nid])
+			continue;
+		if (node_end_pfn[nid] > max_pfn)
+			node_end_pfn[nid] = max_pfn;
+
+		/* ensure the remap includes space for the pgdat. */
+		size = node_remap_size[nid] + sizeof(pg_data_t);
+
+		/* convert size to large (pmd size) pages, rounding up */
+		size = (size + LARGE_PAGE_BYTES - 1) / LARGE_PAGE_BYTES;
+		/* now the roundup is correct, convert to PAGE_SIZE pages */
+		size = size * PTRS_PER_PTE;
+
+		node_kva_target = round_down(node_end_pfn[nid] - size,
+						 PTRS_PER_PTE);
+		node_kva_target <<= PAGE_SHIFT;
+		do {
+			node_kva_final = find_e820_area(node_kva_target,
+					((u64)node_end_pfn[nid])<<PAGE_SHIFT,
+						((u64)size)<<PAGE_SHIFT,
+						LARGE_PAGE_BYTES);
+			node_kva_target -= LARGE_PAGE_BYTES;
+		} while (node_kva_final == -1ULL &&
+			 (node_kva_target>>PAGE_SHIFT) > (node_start_pfn[nid]));
+
+		if (node_kva_final == -1ULL)
+			panic("Can not get kva ram\n");
+
+		node_remap_size[nid] = size;
+		node_remap_offset[nid] = reserve_pages;
+		reserve_pages += size;
+		printk(KERN_DEBUG "Reserving %ld pages of KVA for lmem_map of"
+				  " node %d at %llx\n",
+				size, nid, node_kva_final>>PAGE_SHIFT);
+
+		/*
+		 *  prevent kva address below max_low_pfn want it on system
+		 *  with less memory later.
+		 *  layout will be: KVA address , KVA RAM
+		 *
+		 *  we are supposed to only record the one less then max_low_pfn
+		 *  but we could have some hole in high memory, and it will only
+		 *  check page_is_ram(pfn) && !page_is_reserved_early(pfn) to decide
+		 *  to use it as free.
+		 *  So reserve_early here, hope we don't run out of that array
+		 */
+		reserve_early(node_kva_final,
+			      node_kva_final+(((u64)size)<<PAGE_SHIFT),
+			      "KVA RAM");
+
+		node_remap_start_pfn[nid] = node_kva_final>>PAGE_SHIFT;
+		remove_active_range(nid, node_remap_start_pfn[nid],
+					 node_remap_start_pfn[nid] + size);
+	}
+	printk(KERN_INFO "Reserving total of %lx pages for numa KVA remap\n",
+			reserve_pages);
+	return reserve_pages;
+}
+
+static void init_remap_allocator(int nid)
+{
+	node_remap_start_vaddr[nid] = pfn_to_kaddr(
+			kva_start_pfn + node_remap_offset[nid]);
+	node_remap_end_vaddr[nid] = node_remap_start_vaddr[nid] +
+		(node_remap_size[nid] * PAGE_SIZE);
+	node_remap_alloc_vaddr[nid] = node_remap_start_vaddr[nid] +
+		ALIGN(sizeof(pg_data_t), PAGE_SIZE);
+
+	printk(KERN_DEBUG "node %d will remap to vaddr %08lx - %08lx\n", nid,
+		(ulong) node_remap_start_vaddr[nid],
+		(ulong) node_remap_end_vaddr[nid]);
+}
+
+void __init initmem_init(unsigned long start_pfn,
+				  unsigned long end_pfn)
+{
+	int nid;
+	long kva_target_pfn;
+
+	/*
+	 * When mapping a NUMA machine we allocate the node_mem_map arrays
+	 * from node local memory.  They are then mapped directly into KVA
+	 * between zone normal and vmalloc space.  Calculate the size of
+	 * this space and use it to adjust the boundary between ZONE_NORMAL
+	 * and ZONE_HIGHMEM.
+	 */
+
+	get_memcfg_numa();
+
+	kva_pages = roundup(calculate_numa_remap_pages(), PTRS_PER_PTE);
+
+	kva_target_pfn = round_down(max_low_pfn - kva_pages, PTRS_PER_PTE);
+	do {
+		kva_start_pfn = find_e820_area(kva_target_pfn<<PAGE_SHIFT,
+					max_low_pfn<<PAGE_SHIFT,
+					kva_pages<<PAGE_SHIFT,
+					PTRS_PER_PTE<<PAGE_SHIFT) >> PAGE_SHIFT;
+		kva_target_pfn -= PTRS_PER_PTE;
+	} while (kva_start_pfn == -1UL && kva_target_pfn > min_low_pfn);
+
+	if (kva_start_pfn == -1UL)
+		panic("Can not get kva space\n");
+
+	printk(KERN_INFO "kva_start_pfn ~ %lx max_low_pfn ~ %lx\n",
+		kva_start_pfn, max_low_pfn);
+	printk(KERN_INFO "max_pfn = %lx\n", max_pfn);
+
+	/* avoid clash with initrd */
+	reserve_early(kva_start_pfn<<PAGE_SHIFT,
+		      (kva_start_pfn + kva_pages)<<PAGE_SHIFT,
+		     "KVA PG");
+#ifdef CONFIG_HIGHMEM
+	highstart_pfn = highend_pfn = max_pfn;
+	if (max_pfn > max_low_pfn)
+		highstart_pfn = max_low_pfn;
+	printk(KERN_NOTICE "%ldMB HIGHMEM available.\n",
+	       pages_to_mb(highend_pfn - highstart_pfn));
+	num_physpages = highend_pfn;
+	high_memory = (void *) __va(highstart_pfn * PAGE_SIZE - 1) + 1;
+#else
+	num_physpages = max_low_pfn;
+	high_memory = (void *) __va(max_low_pfn * PAGE_SIZE - 1) + 1;
+#endif
+	printk(KERN_NOTICE "%ldMB LOWMEM available.\n",
+			pages_to_mb(max_low_pfn));
+	printk(KERN_DEBUG "max_low_pfn = %lx, highstart_pfn = %lx\n",
+			max_low_pfn, highstart_pfn);
+
+	printk(KERN_DEBUG "Low memory ends at vaddr %08lx\n",
+			(ulong) pfn_to_kaddr(max_low_pfn));
+	for_each_online_node(nid) {
+		init_remap_allocator(nid);
+
+		allocate_pgdat(nid);
+	}
+	remap_numa_kva();
+
+	printk(KERN_DEBUG "High memory starts at vaddr %08lx\n",
+			(ulong) pfn_to_kaddr(highstart_pfn));
+	for_each_online_node(nid)
+		propagate_e820_map_node(nid);
+
+	for_each_online_node(nid)
+		memset(NODE_DATA(nid), 0, sizeof(struct pglist_data));
+
+	NODE_DATA(0)->bdata = &bootmem_node_data[0];
+	setup_bootmem_allocator();
+}
+
+void __init set_highmem_pages_init(void)
+{
+#ifdef CONFIG_HIGHMEM
+	struct zone *zone;
+	int nid;
+
+	for_each_zone(zone) {
+		unsigned long zone_start_pfn, zone_end_pfn;
+
+		if (!is_highmem(zone))
+			continue;
+
+		zone_start_pfn = zone->zone_start_pfn;
+		zone_end_pfn = zone_start_pfn + zone->spanned_pages;
+
+		nid = zone_to_nid(zone);
+		printk(KERN_INFO "Initializing %s for node %d (%08lx:%08lx)\n",
+				zone->name, nid, zone_start_pfn, zone_end_pfn);
+
+		add_highpages_with_active_regions(nid, zone_start_pfn,
+				 zone_end_pfn);
+	}
+	totalram_pages += totalhigh_pages;
+#endif
+}
+
+#ifdef CONFIG_MEMORY_HOTPLUG
+static int paddr_to_nid(u64 addr)
+{
+	int nid;
+	unsigned long pfn = PFN_DOWN(addr);
+
+	for_each_node(nid)
+		if (node_start_pfn[nid] <= pfn &&
+		    pfn < node_end_pfn[nid])
+			return nid;
+
+	return -1;
+}
+
+/*
+ * This function is used to ask node id BEFORE memmap and mem_section's
+ * initialization (pfn_to_nid() can't be used yet).
+ * If _PXM is not defined on ACPI's DSDT, node id must be found by this.
+ */
+int memory_add_physaddr_to_nid(u64 addr)
+{
+	int nid = paddr_to_nid(addr);
+	return (nid >= 0) ? nid : 0;
+}
+
+EXPORT_SYMBOL_GPL(memory_add_physaddr_to_nid);
+#endif
+
diff --git a/arch/x86/mm/numa_64.c b/arch/x86/mm/numa_64.c
index a4dd793..cebcbf1 100644
--- a/arch/x86/mm/numa_64.c
+++ b/arch/x86/mm/numa_64.c
@@ -79,7 +79,7 @@
 		return 0;
 
 	addr = 0x8000;
-	nodemap_size = round_up(sizeof(s16) * memnodemapsize, L1_CACHE_BYTES);
+	nodemap_size = roundup(sizeof(s16) * memnodemapsize, L1_CACHE_BYTES);
 	nodemap_addr = find_e820_area(addr, max_pfn<<PAGE_SHIFT,
 				      nodemap_size, L1_CACHE_BYTES);
 	if (nodemap_addr == -1UL) {
@@ -176,10 +176,10 @@
 	unsigned long start_pfn, last_pfn, bootmap_pages, bootmap_size;
 	unsigned long bootmap_start, nodedata_phys;
 	void *bootmap;
-	const int pgdat_size = round_up(sizeof(pg_data_t), PAGE_SIZE);
+	const int pgdat_size = roundup(sizeof(pg_data_t), PAGE_SIZE);
 	int nid;
 
-	start = round_up(start, ZONE_ALIGN);
+	start = roundup(start, ZONE_ALIGN);
 
 	printk(KERN_INFO "Bootmem setup node %d %016lx-%016lx\n", nodeid,
 	       start, end);
@@ -210,9 +210,9 @@
 	bootmap_pages = bootmem_bootmap_pages(last_pfn - start_pfn);
 	nid = phys_to_nid(nodedata_phys);
 	if (nid == nodeid)
-		bootmap_start = round_up(nodedata_phys + pgdat_size, PAGE_SIZE);
+		bootmap_start = roundup(nodedata_phys + pgdat_size, PAGE_SIZE);
 	else
-		bootmap_start = round_up(start, PAGE_SIZE);
+		bootmap_start = roundup(start, PAGE_SIZE);
 	/*
 	 * SMP_CACHE_BYTES could be enough, but init_bootmem_node like
 	 * to use that to align to PAGE_SIZE
diff --git a/arch/x86/mm/pageattr-test.c b/arch/x86/mm/pageattr-test.c
index d4aa503..e1d1069 100644
--- a/arch/x86/mm/pageattr-test.c
+++ b/arch/x86/mm/pageattr-test.c
@@ -32,7 +32,7 @@
 	GPS			= (1<<30)
 };
 
-#define PAGE_TESTBIT	__pgprot(_PAGE_UNUSED1)
+#define PAGE_CPA_TEST	__pgprot(_PAGE_CPA_TEST)
 
 static int pte_testbit(pte_t pte)
 {
@@ -118,6 +118,7 @@
 	unsigned int level;
 	int i, k;
 	int err;
+	unsigned long test_addr;
 
 	if (print)
 		printk(KERN_INFO "CPA self-test:\n");
@@ -172,7 +173,8 @@
 			continue;
 		}
 
-		err = change_page_attr_set(addr[i], len[i], PAGE_TESTBIT);
+		test_addr = addr[i];
+		err = change_page_attr_set(&test_addr, len[i], PAGE_CPA_TEST, 0);
 		if (err < 0) {
 			printk(KERN_ERR "CPA %d failed %d\n", i, err);
 			failed++;
@@ -204,7 +206,8 @@
 			failed++;
 			continue;
 		}
-		err = change_page_attr_clear(addr[i], len[i], PAGE_TESTBIT);
+		test_addr = addr[i];
+		err = change_page_attr_clear(&test_addr, len[i], PAGE_CPA_TEST, 0);
 		if (err < 0) {
 			printk(KERN_ERR "CPA reverting failed: %d\n", err);
 			failed++;
diff --git a/arch/x86/mm/pageattr.c b/arch/x86/mm/pageattr.c
index 43e2f84..a9ec89c 100644
--- a/arch/x86/mm/pageattr.c
+++ b/arch/x86/mm/pageattr.c
@@ -25,15 +25,27 @@
  * The current flushing context - we pass it instead of 5 arguments:
  */
 struct cpa_data {
-	unsigned long	vaddr;
+	unsigned long	*vaddr;
 	pgprot_t	mask_set;
 	pgprot_t	mask_clr;
 	int		numpages;
-	int		flushtlb;
+	int		flags;
 	unsigned long	pfn;
 	unsigned	force_split : 1;
+	int		curpage;
 };
 
+/*
+ * Serialize cpa() (for !DEBUG_PAGEALLOC which uses large identity mappings)
+ * using cpa_lock. So that we don't allow any other cpu, with stale large tlb
+ * entries change the page attribute in parallel to some other cpu
+ * splitting a large page entry along with changing the attribute.
+ */
+static DEFINE_SPINLOCK(cpa_lock);
+
+#define CPA_FLUSHTLB 1
+#define CPA_ARRAY 2
+
 #ifdef CONFIG_PROC_FS
 static unsigned long direct_pages_count[PG_LEVEL_NUM];
 
@@ -84,7 +96,7 @@
 
 static inline unsigned long highmap_end_pfn(void)
 {
-	return __pa(round_up((unsigned long)_end, PMD_SIZE)) >> PAGE_SHIFT;
+	return __pa(roundup((unsigned long)_end, PMD_SIZE)) >> PAGE_SHIFT;
 }
 
 #endif
@@ -190,6 +202,41 @@
 	}
 }
 
+static void cpa_flush_array(unsigned long *start, int numpages, int cache)
+{
+	unsigned int i, level;
+	unsigned long *addr;
+
+	BUG_ON(irqs_disabled());
+
+	on_each_cpu(__cpa_flush_range, NULL, 1);
+
+	if (!cache)
+		return;
+
+	/* 4M threshold */
+	if (numpages >= 1024) {
+		if (boot_cpu_data.x86_model >= 4)
+			wbinvd();
+		return;
+	}
+	/*
+	 * We only need to flush on one CPU,
+	 * clflush is a MESI-coherent instruction that
+	 * will cause all other CPUs to flush the same
+	 * cachelines:
+	 */
+	for (i = 0, addr = start; i < numpages; i++, addr++) {
+		pte_t *pte = lookup_address(*addr, &level);
+
+		/*
+		 * Only flush present addresses:
+		 */
+		if (pte && (pte_val(*pte) & _PAGE_PRESENT))
+			clflush_cache_range((void *) *addr, PAGE_SIZE);
+	}
+}
+
 /*
  * Certain areas of memory on x86 require very specific protection flags,
  * for example the BIOS area or kernel text. Callers don't always get this
@@ -398,7 +445,7 @@
 		 */
 		new_pte = pfn_pte(pte_pfn(old_pte), canon_pgprot(new_prot));
 		__set_pmd_pte(kpte, address, new_pte);
-		cpa->flushtlb = 1;
+		cpa->flags |= CPA_FLUSHTLB;
 		do_split = 0;
 	}
 
@@ -408,84 +455,6 @@
 	return do_split;
 }
 
-static LIST_HEAD(page_pool);
-static unsigned long pool_size, pool_pages, pool_low;
-static unsigned long pool_used, pool_failed;
-
-static void cpa_fill_pool(struct page **ret)
-{
-	gfp_t gfp = GFP_KERNEL;
-	unsigned long flags;
-	struct page *p;
-
-	/*
-	 * Avoid recursion (on debug-pagealloc) and also signal
-	 * our priority to get to these pagetables:
-	 */
-	if (current->flags & PF_MEMALLOC)
-		return;
-	current->flags |= PF_MEMALLOC;
-
-	/*
-	 * Allocate atomically from atomic contexts:
-	 */
-	if (in_atomic() || irqs_disabled() || debug_pagealloc)
-		gfp =  GFP_ATOMIC | __GFP_NORETRY | __GFP_NOWARN;
-
-	while (pool_pages < pool_size || (ret && !*ret)) {
-		p = alloc_pages(gfp, 0);
-		if (!p) {
-			pool_failed++;
-			break;
-		}
-		/*
-		 * If the call site needs a page right now, provide it:
-		 */
-		if (ret && !*ret) {
-			*ret = p;
-			continue;
-		}
-		spin_lock_irqsave(&pgd_lock, flags);
-		list_add(&p->lru, &page_pool);
-		pool_pages++;
-		spin_unlock_irqrestore(&pgd_lock, flags);
-	}
-
-	current->flags &= ~PF_MEMALLOC;
-}
-
-#define SHIFT_MB		(20 - PAGE_SHIFT)
-#define ROUND_MB_GB		((1 << 10) - 1)
-#define SHIFT_MB_GB		10
-#define POOL_PAGES_PER_GB	16
-
-void __init cpa_init(void)
-{
-	struct sysinfo si;
-	unsigned long gb;
-
-	si_meminfo(&si);
-	/*
-	 * Calculate the number of pool pages:
-	 *
-	 * Convert totalram (nr of pages) to MiB and round to the next
-	 * GiB. Shift MiB to Gib and multiply the result by
-	 * POOL_PAGES_PER_GB:
-	 */
-	if (debug_pagealloc) {
-		gb = ((si.totalram >> SHIFT_MB) + ROUND_MB_GB) >> SHIFT_MB_GB;
-		pool_size = POOL_PAGES_PER_GB * gb;
-	} else {
-		pool_size = 1;
-	}
-	pool_low = pool_size;
-
-	cpa_fill_pool(NULL);
-	printk(KERN_DEBUG
-	       "CPA: page pool initialized %lu of %lu pages preallocated\n",
-	       pool_pages, pool_size);
-}
-
 static int split_large_page(pte_t *kpte, unsigned long address)
 {
 	unsigned long flags, pfn, pfninc = 1;
@@ -494,28 +463,15 @@
 	pgprot_t ref_prot;
 	struct page *base;
 
-	/*
-	 * Get a page from the pool. The pool list is protected by the
-	 * pgd_lock, which we have to take anyway for the split
-	 * operation:
-	 */
+	if (!debug_pagealloc)
+		spin_unlock(&cpa_lock);
+	base = alloc_pages(GFP_KERNEL, 0);
+	if (!debug_pagealloc)
+		spin_lock(&cpa_lock);
+	if (!base)
+		return -ENOMEM;
+
 	spin_lock_irqsave(&pgd_lock, flags);
-	if (list_empty(&page_pool)) {
-		spin_unlock_irqrestore(&pgd_lock, flags);
-		base = NULL;
-		cpa_fill_pool(&base);
-		if (!base)
-			return -ENOMEM;
-		spin_lock_irqsave(&pgd_lock, flags);
-	} else {
-		base = list_first_entry(&page_pool, struct page, lru);
-		list_del(&base->lru);
-		pool_pages--;
-
-		if (pool_pages < pool_low)
-			pool_low = pool_pages;
-	}
-
 	/*
 	 * Check for races, another CPU might have split this page
 	 * up for us already:
@@ -572,11 +528,8 @@
 	 * If we dropped out via the lookup_address check under
 	 * pgd_lock then stick the page back into the pool:
 	 */
-	if (base) {
-		list_add(&base->lru, &page_pool);
-		pool_pages++;
-	} else
-		pool_used++;
+	if (base)
+		__free_page(base);
 	spin_unlock_irqrestore(&pgd_lock, flags);
 
 	return 0;
@@ -584,11 +537,16 @@
 
 static int __change_page_attr(struct cpa_data *cpa, int primary)
 {
-	unsigned long address = cpa->vaddr;
+	unsigned long address;
 	int do_split, err;
 	unsigned int level;
 	pte_t *kpte, old_pte;
 
+	if (cpa->flags & CPA_ARRAY)
+		address = cpa->vaddr[cpa->curpage];
+	else
+		address = *cpa->vaddr;
+
 repeat:
 	kpte = lookup_address(address, &level);
 	if (!kpte)
@@ -600,7 +558,7 @@
 			return 0;
 		WARN(1, KERN_WARNING "CPA: called for zero pte. "
 		       "vaddr = %lx cpa->vaddr = %lx\n", address,
-		       cpa->vaddr);
+		       *cpa->vaddr);
 		return -EINVAL;
 	}
 
@@ -626,7 +584,7 @@
 		 */
 		if (pte_val(old_pte) != pte_val(new_pte)) {
 			set_pte_atomic(kpte, new_pte);
-			cpa->flushtlb = 1;
+			cpa->flags |= CPA_FLUSHTLB;
 		}
 		cpa->numpages = 1;
 		return 0;
@@ -650,7 +608,25 @@
 	 */
 	err = split_large_page(kpte, address);
 	if (!err) {
-		cpa->flushtlb = 1;
+		/*
+	 	 * Do a global flush tlb after splitting the large page
+	 	 * and before we do the actual change page attribute in the PTE.
+	 	 *
+	 	 * With out this, we violate the TLB application note, that says
+	 	 * "The TLBs may contain both ordinary and large-page
+		 *  translations for a 4-KByte range of linear addresses. This
+		 *  may occur if software modifies the paging structures so that
+		 *  the page size used for the address range changes. If the two
+		 *  translations differ with respect to page frame or attributes
+		 *  (e.g., permissions), processor behavior is undefined and may
+		 *  be implementation-specific."
+	 	 *
+	 	 * We do this global tlb flush inside the cpa_lock, so that we
+		 * don't allow any other cpu, with stale tlb entries change the
+		 * page attribute in parallel, that also falls into the
+		 * just split large page entry.
+	 	 */
+		flush_tlb_all();
 		goto repeat;
 	}
 
@@ -663,6 +639,7 @@
 {
 	struct cpa_data alias_cpa;
 	int ret = 0;
+	unsigned long temp_cpa_vaddr, vaddr;
 
 	if (cpa->pfn >= max_pfn_mapped)
 		return 0;
@@ -675,16 +652,24 @@
 	 * No need to redo, when the primary call touched the direct
 	 * mapping already:
 	 */
-	if (!(within(cpa->vaddr, PAGE_OFFSET,
+	if (cpa->flags & CPA_ARRAY)
+		vaddr = cpa->vaddr[cpa->curpage];
+	else
+		vaddr = *cpa->vaddr;
+
+	if (!(within(vaddr, PAGE_OFFSET,
 		    PAGE_OFFSET + (max_low_pfn_mapped << PAGE_SHIFT))
 #ifdef CONFIG_X86_64
-		|| within(cpa->vaddr, PAGE_OFFSET + (1UL<<32),
+		|| within(vaddr, PAGE_OFFSET + (1UL<<32),
 		    PAGE_OFFSET + (max_pfn_mapped << PAGE_SHIFT))
 #endif
 	)) {
 
 		alias_cpa = *cpa;
-		alias_cpa.vaddr = (unsigned long) __va(cpa->pfn << PAGE_SHIFT);
+		temp_cpa_vaddr = (unsigned long) __va(cpa->pfn << PAGE_SHIFT);
+		alias_cpa.vaddr = &temp_cpa_vaddr;
+		alias_cpa.flags &= ~CPA_ARRAY;
+
 
 		ret = __change_page_attr_set_clr(&alias_cpa, 0);
 	}
@@ -696,7 +681,7 @@
 	 * No need to redo, when the primary call touched the high
 	 * mapping already:
 	 */
-	if (within(cpa->vaddr, (unsigned long) _text, (unsigned long) _end))
+	if (within(vaddr, (unsigned long) _text, (unsigned long) _end))
 		return 0;
 
 	/*
@@ -707,8 +692,9 @@
 		return 0;
 
 	alias_cpa = *cpa;
-	alias_cpa.vaddr =
-		(cpa->pfn << PAGE_SHIFT) + __START_KERNEL_map - phys_base;
+	temp_cpa_vaddr = (cpa->pfn << PAGE_SHIFT) + __START_KERNEL_map - phys_base;
+	alias_cpa.vaddr = &temp_cpa_vaddr;
+	alias_cpa.flags &= ~CPA_ARRAY;
 
 	/*
 	 * The high mapping range is imprecise, so ignore the return value.
@@ -728,8 +714,15 @@
 		 * preservation check.
 		 */
 		cpa->numpages = numpages;
+		/* for array changes, we can't use large page */
+		if (cpa->flags & CPA_ARRAY)
+			cpa->numpages = 1;
 
+		if (!debug_pagealloc)
+			spin_lock(&cpa_lock);
 		ret = __change_page_attr(cpa, checkalias);
+		if (!debug_pagealloc)
+			spin_unlock(&cpa_lock);
 		if (ret)
 			return ret;
 
@@ -746,7 +739,11 @@
 		 */
 		BUG_ON(cpa->numpages > numpages);
 		numpages -= cpa->numpages;
-		cpa->vaddr += cpa->numpages * PAGE_SIZE;
+		if (cpa->flags & CPA_ARRAY)
+			cpa->curpage++;
+		else
+			*cpa->vaddr += cpa->numpages * PAGE_SIZE;
+
 	}
 	return 0;
 }
@@ -757,9 +754,9 @@
 		(_PAGE_PAT | _PAGE_PAT_LARGE | _PAGE_PWT | _PAGE_PCD);
 }
 
-static int change_page_attr_set_clr(unsigned long addr, int numpages,
+static int change_page_attr_set_clr(unsigned long *addr, int numpages,
 				    pgprot_t mask_set, pgprot_t mask_clr,
-				    int force_split)
+				    int force_split, int array)
 {
 	struct cpa_data cpa;
 	int ret, cache, checkalias;
@@ -774,21 +771,38 @@
 		return 0;
 
 	/* Ensure we are PAGE_SIZE aligned */
-	if (addr & ~PAGE_MASK) {
-		addr &= PAGE_MASK;
-		/*
-		 * People should not be passing in unaligned addresses:
-		 */
-		WARN_ON_ONCE(1);
+	if (!array) {
+		if (*addr & ~PAGE_MASK) {
+			*addr &= PAGE_MASK;
+			/*
+			 * People should not be passing in unaligned addresses:
+			 */
+			WARN_ON_ONCE(1);
+		}
+	} else {
+		int i;
+		for (i = 0; i < numpages; i++) {
+			if (addr[i] & ~PAGE_MASK) {
+				addr[i] &= PAGE_MASK;
+				WARN_ON_ONCE(1);
+			}
+		}
 	}
 
+	/* Must avoid aliasing mappings in the highmem code */
+	kmap_flush_unused();
+
 	cpa.vaddr = addr;
 	cpa.numpages = numpages;
 	cpa.mask_set = mask_set;
 	cpa.mask_clr = mask_clr;
-	cpa.flushtlb = 0;
+	cpa.flags = 0;
+	cpa.curpage = 0;
 	cpa.force_split = force_split;
 
+	if (array)
+		cpa.flags |= CPA_ARRAY;
+
 	/* No alias checking for _NX bit modifications */
 	checkalias = (pgprot_val(mask_set) | pgprot_val(mask_clr)) != _PAGE_NX;
 
@@ -797,7 +811,7 @@
 	/*
 	 * Check whether we really changed something:
 	 */
-	if (!cpa.flushtlb)
+	if (!(cpa.flags & CPA_FLUSHTLB))
 		goto out;
 
 	/*
@@ -812,27 +826,30 @@
 	 * error case we fall back to cpa_flush_all (which uses
 	 * wbindv):
 	 */
-	if (!ret && cpu_has_clflush)
-		cpa_flush_range(addr, numpages, cache);
-	else
+	if (!ret && cpu_has_clflush) {
+		if (cpa.flags & CPA_ARRAY)
+			cpa_flush_array(addr, numpages, cache);
+		else
+			cpa_flush_range(*addr, numpages, cache);
+	} else
 		cpa_flush_all(cache);
 
 out:
-	cpa_fill_pool(NULL);
-
 	return ret;
 }
 
-static inline int change_page_attr_set(unsigned long addr, int numpages,
-				       pgprot_t mask)
+static inline int change_page_attr_set(unsigned long *addr, int numpages,
+				       pgprot_t mask, int array)
 {
-	return change_page_attr_set_clr(addr, numpages, mask, __pgprot(0), 0);
+	return change_page_attr_set_clr(addr, numpages, mask, __pgprot(0), 0,
+		array);
 }
 
-static inline int change_page_attr_clear(unsigned long addr, int numpages,
-					 pgprot_t mask)
+static inline int change_page_attr_clear(unsigned long *addr, int numpages,
+					 pgprot_t mask, int array)
 {
-	return change_page_attr_set_clr(addr, numpages, __pgprot(0), mask, 0);
+	return change_page_attr_set_clr(addr, numpages, __pgprot(0), mask, 0,
+		array);
 }
 
 int _set_memory_uc(unsigned long addr, int numpages)
@@ -840,8 +857,8 @@
 	/*
 	 * for now UC MINUS. see comments in ioremap_nocache()
 	 */
-	return change_page_attr_set(addr, numpages,
-				    __pgprot(_PAGE_CACHE_UC_MINUS));
+	return change_page_attr_set(&addr, numpages,
+				    __pgprot(_PAGE_CACHE_UC_MINUS), 0);
 }
 
 int set_memory_uc(unsigned long addr, int numpages)
@@ -857,10 +874,48 @@
 }
 EXPORT_SYMBOL(set_memory_uc);
 
+int set_memory_array_uc(unsigned long *addr, int addrinarray)
+{
+	unsigned long start;
+	unsigned long end;
+	int i;
+	/*
+	 * for now UC MINUS. see comments in ioremap_nocache()
+	 */
+	for (i = 0; i < addrinarray; i++) {
+		start = __pa(addr[i]);
+		for (end = start + PAGE_SIZE; i < addrinarray - 1; end += PAGE_SIZE) {
+			if (end != __pa(addr[i + 1]))
+				break;
+			i++;
+		}
+		if (reserve_memtype(start, end, _PAGE_CACHE_UC_MINUS, NULL))
+			goto out;
+	}
+
+	return change_page_attr_set(addr, addrinarray,
+				    __pgprot(_PAGE_CACHE_UC_MINUS), 1);
+out:
+	for (i = 0; i < addrinarray; i++) {
+		unsigned long tmp = __pa(addr[i]);
+
+		if (tmp == start)
+			break;
+		for (end = tmp + PAGE_SIZE; i < addrinarray - 1; end += PAGE_SIZE) {
+			if (end != __pa(addr[i + 1]))
+				break;
+			i++;
+		}
+		free_memtype(tmp, end);
+	}
+	return -EINVAL;
+}
+EXPORT_SYMBOL(set_memory_array_uc);
+
 int _set_memory_wc(unsigned long addr, int numpages)
 {
-	return change_page_attr_set(addr, numpages,
-				    __pgprot(_PAGE_CACHE_WC));
+	return change_page_attr_set(&addr, numpages,
+				    __pgprot(_PAGE_CACHE_WC), 0);
 }
 
 int set_memory_wc(unsigned long addr, int numpages)
@@ -878,8 +933,8 @@
 
 int _set_memory_wb(unsigned long addr, int numpages)
 {
-	return change_page_attr_clear(addr, numpages,
-				      __pgprot(_PAGE_CACHE_MASK));
+	return change_page_attr_clear(&addr, numpages,
+				      __pgprot(_PAGE_CACHE_MASK), 0);
 }
 
 int set_memory_wb(unsigned long addr, int numpages)
@@ -890,37 +945,59 @@
 }
 EXPORT_SYMBOL(set_memory_wb);
 
+int set_memory_array_wb(unsigned long *addr, int addrinarray)
+{
+	int i;
+
+	for (i = 0; i < addrinarray; i++) {
+		unsigned long start = __pa(addr[i]);
+		unsigned long end;
+
+		for (end = start + PAGE_SIZE; i < addrinarray - 1; end += PAGE_SIZE) {
+			if (end != __pa(addr[i + 1]))
+				break;
+			i++;
+		}
+		free_memtype(start, end);
+	}
+	return change_page_attr_clear(addr, addrinarray,
+				      __pgprot(_PAGE_CACHE_MASK), 1);
+}
+EXPORT_SYMBOL(set_memory_array_wb);
+
 int set_memory_x(unsigned long addr, int numpages)
 {
-	return change_page_attr_clear(addr, numpages, __pgprot(_PAGE_NX));
+	return change_page_attr_clear(&addr, numpages, __pgprot(_PAGE_NX), 0);
 }
 EXPORT_SYMBOL(set_memory_x);
 
 int set_memory_nx(unsigned long addr, int numpages)
 {
-	return change_page_attr_set(addr, numpages, __pgprot(_PAGE_NX));
+	return change_page_attr_set(&addr, numpages, __pgprot(_PAGE_NX), 0);
 }
 EXPORT_SYMBOL(set_memory_nx);
 
 int set_memory_ro(unsigned long addr, int numpages)
 {
-	return change_page_attr_clear(addr, numpages, __pgprot(_PAGE_RW));
+	return change_page_attr_clear(&addr, numpages, __pgprot(_PAGE_RW), 0);
 }
+EXPORT_SYMBOL_GPL(set_memory_ro);
 
 int set_memory_rw(unsigned long addr, int numpages)
 {
-	return change_page_attr_set(addr, numpages, __pgprot(_PAGE_RW));
+	return change_page_attr_set(&addr, numpages, __pgprot(_PAGE_RW), 0);
 }
+EXPORT_SYMBOL_GPL(set_memory_rw);
 
 int set_memory_np(unsigned long addr, int numpages)
 {
-	return change_page_attr_clear(addr, numpages, __pgprot(_PAGE_PRESENT));
+	return change_page_attr_clear(&addr, numpages, __pgprot(_PAGE_PRESENT), 0);
 }
 
 int set_memory_4k(unsigned long addr, int numpages)
 {
-	return change_page_attr_set_clr(addr, numpages, __pgprot(0),
-					__pgprot(0), 1);
+	return change_page_attr_set_clr(&addr, numpages, __pgprot(0),
+					__pgprot(0), 1, 0);
 }
 
 int set_pages_uc(struct page *page, int numpages)
@@ -973,22 +1050,38 @@
 
 static int __set_pages_p(struct page *page, int numpages)
 {
-	struct cpa_data cpa = { .vaddr = (unsigned long) page_address(page),
+	unsigned long tempaddr = (unsigned long) page_address(page);
+	struct cpa_data cpa = { .vaddr = &tempaddr,
 				.numpages = numpages,
 				.mask_set = __pgprot(_PAGE_PRESENT | _PAGE_RW),
-				.mask_clr = __pgprot(0)};
+				.mask_clr = __pgprot(0),
+				.flags = 0};
 
-	return __change_page_attr_set_clr(&cpa, 1);
+	/*
+	 * No alias checking needed for setting present flag. otherwise,
+	 * we may need to break large pages for 64-bit kernel text
+	 * mappings (this adds to complexity if we want to do this from
+	 * atomic context especially). Let's keep it simple!
+	 */
+	return __change_page_attr_set_clr(&cpa, 0);
 }
 
 static int __set_pages_np(struct page *page, int numpages)
 {
-	struct cpa_data cpa = { .vaddr = (unsigned long) page_address(page),
+	unsigned long tempaddr = (unsigned long) page_address(page);
+	struct cpa_data cpa = { .vaddr = &tempaddr,
 				.numpages = numpages,
 				.mask_set = __pgprot(0),
-				.mask_clr = __pgprot(_PAGE_PRESENT | _PAGE_RW)};
+				.mask_clr = __pgprot(_PAGE_PRESENT | _PAGE_RW),
+				.flags = 0};
 
-	return __change_page_attr_set_clr(&cpa, 1);
+	/*
+	 * No alias checking needed for setting not present flag. otherwise,
+	 * we may need to break large pages for 64-bit kernel text
+	 * mappings (this adds to complexity if we want to do this from
+	 * atomic context especially). Let's keep it simple!
+	 */
+	return __change_page_attr_set_clr(&cpa, 0);
 }
 
 void kernel_map_pages(struct page *page, int numpages, int enable)
@@ -1008,11 +1101,8 @@
 
 	/*
 	 * The return value is ignored as the calls cannot fail.
-	 * Large pages are kept enabled at boot time, and are
-	 * split up quickly with DEBUG_PAGEALLOC. If a splitup
-	 * fails here (due to temporary memory shortage) no damage
-	 * is done because we just keep the largepage intact up
-	 * to the next attempt when it will likely be split up:
+	 * Large pages for identity mappings are not used at boot time
+	 * and hence no memory allocations during large page split.
 	 */
 	if (enable)
 		__set_pages_p(page, numpages);
@@ -1024,53 +1114,8 @@
 	 * but that can deadlock->flush only current cpu:
 	 */
 	__flush_tlb_all();
-
-	/*
-	 * Try to refill the page pool here. We can do this only after
-	 * the tlb flush.
-	 */
-	cpa_fill_pool(NULL);
 }
 
-#ifdef CONFIG_DEBUG_FS
-static int dpa_show(struct seq_file *m, void *v)
-{
-	seq_puts(m, "DEBUG_PAGEALLOC\n");
-	seq_printf(m, "pool_size     : %lu\n", pool_size);
-	seq_printf(m, "pool_pages    : %lu\n", pool_pages);
-	seq_printf(m, "pool_low      : %lu\n", pool_low);
-	seq_printf(m, "pool_used     : %lu\n", pool_used);
-	seq_printf(m, "pool_failed   : %lu\n", pool_failed);
-
-	return 0;
-}
-
-static int dpa_open(struct inode *inode, struct file *filp)
-{
-	return single_open(filp, dpa_show, NULL);
-}
-
-static const struct file_operations dpa_fops = {
-	.open		= dpa_open,
-	.read		= seq_read,
-	.llseek		= seq_lseek,
-	.release	= single_release,
-};
-
-static int __init debug_pagealloc_proc_init(void)
-{
-	struct dentry *de;
-
-	de = debugfs_create_file("debug_pagealloc", 0600, NULL, NULL,
-				 &dpa_fops);
-	if (!de)
-		return -ENOMEM;
-
-	return 0;
-}
-__initcall(debug_pagealloc_proc_init);
-#endif
-
 #ifdef CONFIG_HIBERNATION
 
 bool kernel_page_present(struct page *page)
diff --git a/arch/x86/mm/pat.c b/arch/x86/mm/pat.c
index 2a50e0f..738fd0f2 100644
--- a/arch/x86/mm/pat.c
+++ b/arch/x86/mm/pat.c
@@ -7,24 +7,24 @@
  * Loosely based on earlier PAT patchset from Eric Biederman and Andi Kleen.
  */
 
-#include <linux/mm.h>
-#include <linux/kernel.h>
-#include <linux/gfp.h>
-#include <linux/fs.h>
+#include <linux/seq_file.h>
 #include <linux/bootmem.h>
 #include <linux/debugfs.h>
-#include <linux/seq_file.h>
+#include <linux/kernel.h>
+#include <linux/gfp.h>
+#include <linux/mm.h>
+#include <linux/fs.h>
 
-#include <asm/msr.h>
-#include <asm/tlbflush.h>
-#include <asm/processor.h>
-#include <asm/page.h>
-#include <asm/pgtable.h>
-#include <asm/pat.h>
-#include <asm/e820.h>
 #include <asm/cacheflush.h>
+#include <asm/processor.h>
+#include <asm/tlbflush.h>
+#include <asm/pgtable.h>
 #include <asm/fcntl.h>
+#include <asm/e820.h>
 #include <asm/mtrr.h>
+#include <asm/page.h>
+#include <asm/msr.h>
+#include <asm/pat.h>
 #include <asm/io.h>
 
 #ifdef CONFIG_X86_PAT
@@ -46,6 +46,7 @@
 
 
 static int debug_enable;
+
 static int __init pat_debug_setup(char *str)
 {
 	debug_enable = 1;
@@ -145,14 +146,14 @@
  */
 
 struct memtype {
-	u64 start;
-	u64 end;
-	unsigned long type;
-	struct list_head nd;
+	u64			start;
+	u64			end;
+	unsigned long		type;
+	struct list_head	nd;
 };
 
 static LIST_HEAD(memtype_list);
-static DEFINE_SPINLOCK(memtype_lock); 	/* protects memtype list */
+static DEFINE_SPINLOCK(memtype_lock);	/* protects memtype list */
 
 /*
  * Does intersection of PAT memory type and MTRR memory type and returns
@@ -180,8 +181,8 @@
 	return req_type;
 }
 
-static int chk_conflict(struct memtype *new, struct memtype *entry,
-			unsigned long *type)
+static int
+chk_conflict(struct memtype *new, struct memtype *entry, unsigned long *type)
 {
 	if (new->type != entry->type) {
 		if (type) {
@@ -211,6 +212,66 @@
 static u64 cached_start;
 
 /*
+ * For RAM pages, mark the pages as non WB memory type using
+ * PageNonWB (PG_arch_1). We allow only one set_memory_uc() or
+ * set_memory_wc() on a RAM page at a time before marking it as WB again.
+ * This is ok, because only one driver will be owning the page and
+ * doing set_memory_*() calls.
+ *
+ * For now, we use PageNonWB to track that the RAM page is being mapped
+ * as non WB. In future, we will have to use one more flag
+ * (or some other mechanism in page_struct) to distinguish between
+ * UC and WC mapping.
+ */
+static int reserve_ram_pages_type(u64 start, u64 end, unsigned long req_type,
+				  unsigned long *new_type)
+{
+	struct page *page;
+	u64 pfn, end_pfn;
+
+	for (pfn = (start >> PAGE_SHIFT); pfn < (end >> PAGE_SHIFT); ++pfn) {
+		page = pfn_to_page(pfn);
+		if (page_mapped(page) || PageNonWB(page))
+			goto out;
+
+		SetPageNonWB(page);
+	}
+	return 0;
+
+out:
+	end_pfn = pfn;
+	for (pfn = (start >> PAGE_SHIFT); pfn < end_pfn; ++pfn) {
+		page = pfn_to_page(pfn);
+		ClearPageNonWB(page);
+	}
+
+	return -EINVAL;
+}
+
+static int free_ram_pages_type(u64 start, u64 end)
+{
+	struct page *page;
+	u64 pfn, end_pfn;
+
+	for (pfn = (start >> PAGE_SHIFT); pfn < (end >> PAGE_SHIFT); ++pfn) {
+		page = pfn_to_page(pfn);
+		if (page_mapped(page) || !PageNonWB(page))
+			goto out;
+
+		ClearPageNonWB(page);
+	}
+	return 0;
+
+out:
+	end_pfn = pfn;
+	for (pfn = (start >> PAGE_SHIFT); pfn < end_pfn; ++pfn) {
+		page = pfn_to_page(pfn);
+		SetPageNonWB(page);
+	}
+	return -EINVAL;
+}
+
+/*
  * req_type typically has one of the:
  * - _PAGE_CACHE_WB
  * - _PAGE_CACHE_WC
@@ -226,14 +287,15 @@
  * it will return a negative return value.
  */
 int reserve_memtype(u64 start, u64 end, unsigned long req_type,
-			unsigned long *new_type)
+		    unsigned long *new_type)
 {
 	struct memtype *new, *entry;
 	unsigned long actual_type;
 	struct list_head *where;
+	int is_range_ram;
 	int err = 0;
 
- 	BUG_ON(start >= end); /* end is exclusive */
+	BUG_ON(start >= end); /* end is exclusive */
 
 	if (!pat_enabled) {
 		/* This is identical to page table setting without PAT */
@@ -266,17 +328,24 @@
 			actual_type = _PAGE_CACHE_WB;
 		else
 			actual_type = _PAGE_CACHE_UC_MINUS;
-	} else
+	} else {
 		actual_type = pat_x_mtrr_type(start, end,
 					      req_type & _PAGE_CACHE_MASK);
+	}
+
+	is_range_ram = pagerange_is_ram(start, end);
+	if (is_range_ram == 1)
+		return reserve_ram_pages_type(start, end, req_type, new_type);
+	else if (is_range_ram < 0)
+		return -EINVAL;
 
 	new  = kmalloc(sizeof(struct memtype), GFP_KERNEL);
 	if (!new)
 		return -ENOMEM;
 
-	new->start = start;
-	new->end = end;
-	new->type = actual_type;
+	new->start	= start;
+	new->end	= end;
+	new->type	= actual_type;
 
 	if (new_type)
 		*new_type = actual_type;
@@ -335,6 +404,7 @@
 		       start, end, cattr_name(new->type), cattr_name(req_type));
 		kfree(new);
 		spin_unlock(&memtype_lock);
+
 		return err;
 	}
 
@@ -358,6 +428,7 @@
 {
 	struct memtype *entry;
 	int err = -EINVAL;
+	int is_range_ram;
 
 	if (!pat_enabled)
 		return 0;
@@ -366,6 +437,12 @@
 	if (is_ISA_range(start, end - 1))
 		return 0;
 
+	is_range_ram = pagerange_is_ram(start, end);
+	if (is_range_ram == 1)
+		return free_ram_pages_type(start, end);
+	else if (is_range_ram < 0)
+		return -EINVAL;
+
 	spin_lock(&memtype_lock);
 	list_for_each_entry(entry, &memtype_list, nd) {
 		if (entry->start == start && entry->end == end) {
@@ -386,6 +463,7 @@
 	}
 
 	dprintk("free_memtype request 0x%Lx-0x%Lx\n", start, end);
+
 	return err;
 }
 
@@ -492,9 +570,9 @@
 
 void map_devmem(unsigned long pfn, unsigned long size, pgprot_t vma_prot)
 {
+	unsigned long want_flags = (pgprot_val(vma_prot) & _PAGE_CACHE_MASK);
 	u64 addr = (u64)pfn << PAGE_SHIFT;
 	unsigned long flags;
-	unsigned long want_flags = (pgprot_val(vma_prot) & _PAGE_CACHE_MASK);
 
 	reserve_memtype(addr, addr + size, want_flags, &flags);
 	if (flags != want_flags) {
@@ -514,7 +592,7 @@
 	free_memtype(addr, addr + size);
 }
 
-#if defined(CONFIG_DEBUG_FS)
+#if defined(CONFIG_DEBUG_FS) && defined(CONFIG_X86_PAT)
 
 /* get Nth element of the linked list */
 static struct memtype *memtype_get_idx(loff_t pos)
@@ -537,6 +615,7 @@
 	}
 	spin_unlock(&memtype_lock);
 	kfree(print_entry);
+
 	return NULL;
 }
 
@@ -567,6 +646,7 @@
 	seq_printf(seq, "%s @ 0x%Lx-0x%Lx\n", cattr_name(print_entry->type),
 			print_entry->start, print_entry->end);
 	kfree(print_entry);
+
 	return 0;
 }
 
@@ -598,4 +678,4 @@
 
 late_initcall(pat_memtype_list_init);
 
-#endif /* CONFIG_DEBUG_FS */
+#endif /* CONFIG_DEBUG_FS && CONFIG_X86_PAT */
diff --git a/arch/x86/mm/pgtable.c b/arch/x86/mm/pgtable.c
index d503027..86f2ffc 100644
--- a/arch/x86/mm/pgtable.c
+++ b/arch/x86/mm/pgtable.c
@@ -63,10 +63,8 @@
 #define UNSHARED_PTRS_PER_PGD				\
 	(SHARED_KERNEL_PMD ? KERNEL_PGD_BOUNDARY : PTRS_PER_PGD)
 
-static void pgd_ctor(void *p)
+static void pgd_ctor(pgd_t *pgd)
 {
-	pgd_t *pgd = p;
-
 	/* If the pgd points to a shared pagetable level (either the
 	   ptes in non-PAE, or shared PMD in PAE), then just copy the
 	   references from swapper_pg_dir. */
@@ -87,7 +85,7 @@
 		pgd_list_add(pgd);
 }
 
-static void pgd_dtor(void *pgd)
+static void pgd_dtor(pgd_t *pgd)
 {
 	unsigned long flags; /* can be called from interrupt context */
 
diff --git a/arch/x86/mm/pgtable_32.c b/arch/x86/mm/pgtable_32.c
index cab0abb..0951db9 100644
--- a/arch/x86/mm/pgtable_32.c
+++ b/arch/x86/mm/pgtable_32.c
@@ -123,7 +123,8 @@
 	if (!arg)
 		return -EINVAL;
 
-	__VMALLOC_RESERVE = memparse(arg, &arg);
+	/* Add VMALLOC_OFFSET to the parsed value due to vm area guard hole*/
+	__VMALLOC_RESERVE = memparse(arg, &arg) + VMALLOC_OFFSET;
 	return 0;
 }
 early_param("vmalloc", parse_vmalloc);
diff --git a/arch/x86/mm/srat_64.c b/arch/x86/mm/srat_64.c
index 1b4763e..51c0a2f 100644
--- a/arch/x86/mm/srat_64.c
+++ b/arch/x86/mm/srat_64.c
@@ -138,7 +138,7 @@
 		return;
 	}
 
-	if (is_uv_system())
+	if (get_uv_system_type() >= UV_X2APIC)
 		apic_id = (pa->apic_id << 8) | pa->local_sapic_eid;
 	else
 		apic_id = pa->apic_id;
diff --git a/arch/x86/oprofile/Makefile b/arch/x86/oprofile/Makefile
index 30f3eb3..446902b 100644
--- a/arch/x86/oprofile/Makefile
+++ b/arch/x86/oprofile/Makefile
@@ -7,6 +7,6 @@
 		timer_int.o )
 
 oprofile-y				:= $(DRIVER_OBJS) init.o backtrace.o
-oprofile-$(CONFIG_X86_LOCAL_APIC) 	+= nmi_int.o op_model_athlon.o \
+oprofile-$(CONFIG_X86_LOCAL_APIC) 	+= nmi_int.o op_model_amd.o \
 					   op_model_ppro.o op_model_p4.o
 oprofile-$(CONFIG_X86_IO_APIC)		+= nmi_timer_int.o
diff --git a/arch/x86/oprofile/nmi_int.c b/arch/x86/oprofile/nmi_int.c
index 0227694..57f6c90 100644
--- a/arch/x86/oprofile/nmi_int.c
+++ b/arch/x86/oprofile/nmi_int.c
@@ -1,10 +1,11 @@
 /**
  * @file nmi_int.c
  *
- * @remark Copyright 2002 OProfile authors
+ * @remark Copyright 2002-2008 OProfile authors
  * @remark Read the file COPYING
  *
  * @author John Levon <levon@movementarian.org>
+ * @author Robert Richter <robert.richter@amd.com>
  */
 
 #include <linux/init.h>
@@ -295,10 +296,12 @@
 
 static void nmi_shutdown(void)
 {
-	struct op_msrs *msrs = &get_cpu_var(cpu_msrs);
+	struct op_msrs *msrs;
+
 	nmi_enabled = 0;
 	on_each_cpu(nmi_cpu_shutdown, NULL, 1);
 	unregister_die_notifier(&profile_exceptions_nb);
+	msrs = &get_cpu_var(cpu_msrs);
 	model->shutdown(msrs);
 	free_msrs();
 	put_cpu_var(cpu_msrs);
@@ -437,6 +440,7 @@
 	__u8 vendor = boot_cpu_data.x86_vendor;
 	__u8 family = boot_cpu_data.x86;
 	char *cpu_type;
+	int ret = 0;
 
 	if (!cpu_has_apic)
 		return -ENODEV;
@@ -449,19 +453,23 @@
 		default:
 			return -ENODEV;
 		case 6:
-			model = &op_athlon_spec;
+			model = &op_amd_spec;
 			cpu_type = "i386/athlon";
 			break;
 		case 0xf:
-			model = &op_athlon_spec;
+			model = &op_amd_spec;
 			/* Actually it could be i386/hammer too, but give
 			 user space an consistent name. */
 			cpu_type = "x86-64/hammer";
 			break;
 		case 0x10:
-			model = &op_athlon_spec;
+			model = &op_amd_spec;
 			cpu_type = "x86-64/family10";
 			break;
+		case 0x11:
+			model = &op_amd_spec;
+			cpu_type = "x86-64/family11h";
+			break;
 		}
 		break;
 
@@ -488,17 +496,24 @@
 		return -ENODEV;
 	}
 
-	init_sysfs();
 #ifdef CONFIG_SMP
 	register_cpu_notifier(&oprofile_cpu_nb);
 #endif
-	using_nmi = 1;
+	/* default values, can be overwritten by model */
 	ops->create_files = nmi_create_files;
 	ops->setup = nmi_setup;
 	ops->shutdown = nmi_shutdown;
 	ops->start = nmi_start;
 	ops->stop = nmi_stop;
 	ops->cpu_type = cpu_type;
+
+	if (model->init)
+		ret = model->init(ops);
+	if (ret)
+		return ret;
+
+	init_sysfs();
+	using_nmi = 1;
 	printk(KERN_INFO "oprofile: using NMI interrupt.\n");
 	return 0;
 }
@@ -511,4 +526,6 @@
 		unregister_cpu_notifier(&oprofile_cpu_nb);
 #endif
 	}
+	if (model->exit)
+		model->exit();
 }
diff --git a/arch/x86/oprofile/op_model_amd.c b/arch/x86/oprofile/op_model_amd.c
new file mode 100644
index 0000000..d9faf60
--- /dev/null
+++ b/arch/x86/oprofile/op_model_amd.c
@@ -0,0 +1,543 @@
+/*
+ * @file op_model_amd.c
+ * athlon / K7 / K8 / Family 10h model-specific MSR operations
+ *
+ * @remark Copyright 2002-2008 OProfile authors
+ * @remark Read the file COPYING
+ *
+ * @author John Levon
+ * @author Philippe Elie
+ * @author Graydon Hoare
+ * @author Robert Richter <robert.richter@amd.com>
+ * @author Barry Kasindorf
+*/
+
+#include <linux/oprofile.h>
+#include <linux/device.h>
+#include <linux/pci.h>
+
+#include <asm/ptrace.h>
+#include <asm/msr.h>
+#include <asm/nmi.h>
+
+#include "op_x86_model.h"
+#include "op_counter.h"
+
+#define NUM_COUNTERS 4
+#define NUM_CONTROLS 4
+
+#define CTR_IS_RESERVED(msrs, c) (msrs->counters[(c)].addr ? 1 : 0)
+#define CTR_READ(l, h, msrs, c) do {rdmsr(msrs->counters[(c)].addr, (l), (h)); } while (0)
+#define CTR_WRITE(l, msrs, c) do {wrmsr(msrs->counters[(c)].addr, -(unsigned int)(l), -1); } while (0)
+#define CTR_OVERFLOWED(n) (!((n) & (1U<<31)))
+
+#define CTRL_IS_RESERVED(msrs, c) (msrs->controls[(c)].addr ? 1 : 0)
+#define CTRL_READ(l, h, msrs, c) do {rdmsr(msrs->controls[(c)].addr, (l), (h)); } while (0)
+#define CTRL_WRITE(l, h, msrs, c) do {wrmsr(msrs->controls[(c)].addr, (l), (h)); } while (0)
+#define CTRL_SET_ACTIVE(n) (n |= (1<<22))
+#define CTRL_SET_INACTIVE(n) (n &= ~(1<<22))
+#define CTRL_CLEAR_LO(x) (x &= (1<<21))
+#define CTRL_CLEAR_HI(x) (x &= 0xfffffcf0)
+#define CTRL_SET_ENABLE(val) (val |= 1<<20)
+#define CTRL_SET_USR(val, u) (val |= ((u & 1) << 16))
+#define CTRL_SET_KERN(val, k) (val |= ((k & 1) << 17))
+#define CTRL_SET_UM(val, m) (val |= (m << 8))
+#define CTRL_SET_EVENT_LOW(val, e) (val |= (e & 0xff))
+#define CTRL_SET_EVENT_HIGH(val, e) (val |= ((e >> 8) & 0xf))
+#define CTRL_SET_HOST_ONLY(val, h) (val |= ((h & 1) << 9))
+#define CTRL_SET_GUEST_ONLY(val, h) (val |= ((h & 1) << 8))
+
+static unsigned long reset_value[NUM_COUNTERS];
+
+#ifdef CONFIG_OPROFILE_IBS
+
+/* IbsFetchCtl bits/masks */
+#define IBS_FETCH_HIGH_VALID_BIT	(1UL << 17)	/* bit 49 */
+#define IBS_FETCH_HIGH_ENABLE		(1UL << 16)	/* bit 48 */
+#define IBS_FETCH_LOW_MAX_CNT_MASK	0x0000FFFFUL	/* MaxCnt mask */
+
+/*IbsOpCtl bits */
+#define IBS_OP_LOW_VALID_BIT		(1ULL<<18)	/* bit 18 */
+#define IBS_OP_LOW_ENABLE		(1ULL<<17)	/* bit 17 */
+
+/* Codes used in cpu_buffer.c */
+/* This produces duplicate code, need to be fixed */
+#define IBS_FETCH_BEGIN 3
+#define IBS_OP_BEGIN    4
+
+/* The function interface needs to be fixed, something like add
+   data. Should then be added to linux/oprofile.h. */
+extern void oprofile_add_ibs_sample(struct pt_regs *const regs,
+				    unsigned int * const ibs_sample, u8 code);
+
+struct ibs_fetch_sample {
+	/* MSRC001_1031 IBS Fetch Linear Address Register */
+	unsigned int ibs_fetch_lin_addr_low;
+	unsigned int ibs_fetch_lin_addr_high;
+	/* MSRC001_1030 IBS Fetch Control Register */
+	unsigned int ibs_fetch_ctl_low;
+	unsigned int ibs_fetch_ctl_high;
+	/* MSRC001_1032 IBS Fetch Physical Address Register */
+	unsigned int ibs_fetch_phys_addr_low;
+	unsigned int ibs_fetch_phys_addr_high;
+};
+
+struct ibs_op_sample {
+	/* MSRC001_1034 IBS Op Logical Address Register (IbsRIP) */
+	unsigned int ibs_op_rip_low;
+	unsigned int ibs_op_rip_high;
+	/* MSRC001_1035 IBS Op Data Register */
+	unsigned int ibs_op_data1_low;
+	unsigned int ibs_op_data1_high;
+	/* MSRC001_1036 IBS Op Data 2 Register */
+	unsigned int ibs_op_data2_low;
+	unsigned int ibs_op_data2_high;
+	/* MSRC001_1037 IBS Op Data 3 Register */
+	unsigned int ibs_op_data3_low;
+	unsigned int ibs_op_data3_high;
+	/* MSRC001_1038 IBS DC Linear Address Register (IbsDcLinAd) */
+	unsigned int ibs_dc_linear_low;
+	unsigned int ibs_dc_linear_high;
+	/* MSRC001_1039 IBS DC Physical Address Register (IbsDcPhysAd) */
+	unsigned int ibs_dc_phys_low;
+	unsigned int ibs_dc_phys_high;
+};
+
+/*
+ * unitialize the APIC for the IBS interrupts if needed on AMD Family10h+
+*/
+static void clear_ibs_nmi(void);
+
+static int ibs_allowed;	/* AMD Family10h and later */
+
+struct op_ibs_config {
+	unsigned long op_enabled;
+	unsigned long fetch_enabled;
+	unsigned long max_cnt_fetch;
+	unsigned long max_cnt_op;
+	unsigned long rand_en;
+	unsigned long dispatched_ops;
+};
+
+static struct op_ibs_config ibs_config;
+
+#endif
+
+/* functions for op_amd_spec */
+
+static void op_amd_fill_in_addresses(struct op_msrs * const msrs)
+{
+	int i;
+
+	for (i = 0; i < NUM_COUNTERS; i++) {
+		if (reserve_perfctr_nmi(MSR_K7_PERFCTR0 + i))
+			msrs->counters[i].addr = MSR_K7_PERFCTR0 + i;
+		else
+			msrs->counters[i].addr = 0;
+	}
+
+	for (i = 0; i < NUM_CONTROLS; i++) {
+		if (reserve_evntsel_nmi(MSR_K7_EVNTSEL0 + i))
+			msrs->controls[i].addr = MSR_K7_EVNTSEL0 + i;
+		else
+			msrs->controls[i].addr = 0;
+	}
+}
+
+
+static void op_amd_setup_ctrs(struct op_msrs const * const msrs)
+{
+	unsigned int low, high;
+	int i;
+
+	/* clear all counters */
+	for (i = 0 ; i < NUM_CONTROLS; ++i) {
+		if (unlikely(!CTRL_IS_RESERVED(msrs, i)))
+			continue;
+		CTRL_READ(low, high, msrs, i);
+		CTRL_CLEAR_LO(low);
+		CTRL_CLEAR_HI(high);
+		CTRL_WRITE(low, high, msrs, i);
+	}
+
+	/* avoid a false detection of ctr overflows in NMI handler */
+	for (i = 0; i < NUM_COUNTERS; ++i) {
+		if (unlikely(!CTR_IS_RESERVED(msrs, i)))
+			continue;
+		CTR_WRITE(1, msrs, i);
+	}
+
+	/* enable active counters */
+	for (i = 0; i < NUM_COUNTERS; ++i) {
+		if ((counter_config[i].enabled) && (CTR_IS_RESERVED(msrs, i))) {
+			reset_value[i] = counter_config[i].count;
+
+			CTR_WRITE(counter_config[i].count, msrs, i);
+
+			CTRL_READ(low, high, msrs, i);
+			CTRL_CLEAR_LO(low);
+			CTRL_CLEAR_HI(high);
+			CTRL_SET_ENABLE(low);
+			CTRL_SET_USR(low, counter_config[i].user);
+			CTRL_SET_KERN(low, counter_config[i].kernel);
+			CTRL_SET_UM(low, counter_config[i].unit_mask);
+			CTRL_SET_EVENT_LOW(low, counter_config[i].event);
+			CTRL_SET_EVENT_HIGH(high, counter_config[i].event);
+			CTRL_SET_HOST_ONLY(high, 0);
+			CTRL_SET_GUEST_ONLY(high, 0);
+
+			CTRL_WRITE(low, high, msrs, i);
+		} else {
+			reset_value[i] = 0;
+		}
+	}
+}
+
+#ifdef CONFIG_OPROFILE_IBS
+
+static inline int
+op_amd_handle_ibs(struct pt_regs * const regs,
+		  struct op_msrs const * const msrs)
+{
+	unsigned int low, high;
+	struct ibs_fetch_sample ibs_fetch;
+	struct ibs_op_sample ibs_op;
+
+	if (!ibs_allowed)
+		return 1;
+
+	if (ibs_config.fetch_enabled) {
+		rdmsr(MSR_AMD64_IBSFETCHCTL, low, high);
+		if (high & IBS_FETCH_HIGH_VALID_BIT) {
+			ibs_fetch.ibs_fetch_ctl_high = high;
+			ibs_fetch.ibs_fetch_ctl_low = low;
+			rdmsr(MSR_AMD64_IBSFETCHLINAD, low, high);
+			ibs_fetch.ibs_fetch_lin_addr_high = high;
+			ibs_fetch.ibs_fetch_lin_addr_low = low;
+			rdmsr(MSR_AMD64_IBSFETCHPHYSAD, low, high);
+			ibs_fetch.ibs_fetch_phys_addr_high = high;
+			ibs_fetch.ibs_fetch_phys_addr_low = low;
+
+			oprofile_add_ibs_sample(regs,
+						(unsigned int *)&ibs_fetch,
+						IBS_FETCH_BEGIN);
+
+			/*reenable the IRQ */
+			rdmsr(MSR_AMD64_IBSFETCHCTL, low, high);
+			high &= ~IBS_FETCH_HIGH_VALID_BIT;
+			high |= IBS_FETCH_HIGH_ENABLE;
+			low &= IBS_FETCH_LOW_MAX_CNT_MASK;
+			wrmsr(MSR_AMD64_IBSFETCHCTL, low, high);
+		}
+	}
+
+	if (ibs_config.op_enabled) {
+		rdmsr(MSR_AMD64_IBSOPCTL, low, high);
+		if (low & IBS_OP_LOW_VALID_BIT) {
+			rdmsr(MSR_AMD64_IBSOPRIP, low, high);
+			ibs_op.ibs_op_rip_low = low;
+			ibs_op.ibs_op_rip_high = high;
+			rdmsr(MSR_AMD64_IBSOPDATA, low, high);
+			ibs_op.ibs_op_data1_low = low;
+			ibs_op.ibs_op_data1_high = high;
+			rdmsr(MSR_AMD64_IBSOPDATA2, low, high);
+			ibs_op.ibs_op_data2_low = low;
+			ibs_op.ibs_op_data2_high = high;
+			rdmsr(MSR_AMD64_IBSOPDATA3, low, high);
+			ibs_op.ibs_op_data3_low = low;
+			ibs_op.ibs_op_data3_high = high;
+			rdmsr(MSR_AMD64_IBSDCLINAD, low, high);
+			ibs_op.ibs_dc_linear_low = low;
+			ibs_op.ibs_dc_linear_high = high;
+			rdmsr(MSR_AMD64_IBSDCPHYSAD, low, high);
+			ibs_op.ibs_dc_phys_low = low;
+			ibs_op.ibs_dc_phys_high = high;
+
+			/* reenable the IRQ */
+			oprofile_add_ibs_sample(regs,
+						(unsigned int *)&ibs_op,
+						IBS_OP_BEGIN);
+			rdmsr(MSR_AMD64_IBSOPCTL, low, high);
+			high = 0;
+			low &= ~IBS_OP_LOW_VALID_BIT;
+			low |= IBS_OP_LOW_ENABLE;
+			wrmsr(MSR_AMD64_IBSOPCTL, low, high);
+		}
+	}
+
+	return 1;
+}
+
+#endif
+
+static int op_amd_check_ctrs(struct pt_regs * const regs,
+			     struct op_msrs const * const msrs)
+{
+	unsigned int low, high;
+	int i;
+
+	for (i = 0 ; i < NUM_COUNTERS; ++i) {
+		if (!reset_value[i])
+			continue;
+		CTR_READ(low, high, msrs, i);
+		if (CTR_OVERFLOWED(low)) {
+			oprofile_add_sample(regs, i);
+			CTR_WRITE(reset_value[i], msrs, i);
+		}
+	}
+
+#ifdef CONFIG_OPROFILE_IBS
+	op_amd_handle_ibs(regs, msrs);
+#endif
+
+	/* See op_model_ppro.c */
+	return 1;
+}
+
+static void op_amd_start(struct op_msrs const * const msrs)
+{
+	unsigned int low, high;
+	int i;
+	for (i = 0 ; i < NUM_COUNTERS ; ++i) {
+		if (reset_value[i]) {
+			CTRL_READ(low, high, msrs, i);
+			CTRL_SET_ACTIVE(low);
+			CTRL_WRITE(low, high, msrs, i);
+		}
+	}
+
+#ifdef CONFIG_OPROFILE_IBS
+	if (ibs_allowed && ibs_config.fetch_enabled) {
+		low = (ibs_config.max_cnt_fetch >> 4) & 0xFFFF;
+		high = IBS_FETCH_HIGH_ENABLE;
+		wrmsr(MSR_AMD64_IBSFETCHCTL, low, high);
+	}
+
+	if (ibs_allowed && ibs_config.op_enabled) {
+		low = ((ibs_config.max_cnt_op >> 4) & 0xFFFF) + IBS_OP_LOW_ENABLE;
+		high = 0;
+		wrmsr(MSR_AMD64_IBSOPCTL, low, high);
+	}
+#endif
+}
+
+
+static void op_amd_stop(struct op_msrs const * const msrs)
+{
+	unsigned int low, high;
+	int i;
+
+	/* Subtle: stop on all counters to avoid race with
+	 * setting our pm callback */
+	for (i = 0 ; i < NUM_COUNTERS ; ++i) {
+		if (!reset_value[i])
+			continue;
+		CTRL_READ(low, high, msrs, i);
+		CTRL_SET_INACTIVE(low);
+		CTRL_WRITE(low, high, msrs, i);
+	}
+
+#ifdef CONFIG_OPROFILE_IBS
+	if (ibs_allowed && ibs_config.fetch_enabled) {
+		low = 0;		/* clear max count and enable */
+		high = 0;
+		wrmsr(MSR_AMD64_IBSFETCHCTL, low, high);
+	}
+
+	if (ibs_allowed && ibs_config.op_enabled) {
+		low = 0;		/* clear max count and enable */
+		high = 0;
+		wrmsr(MSR_AMD64_IBSOPCTL, low, high);
+	}
+#endif
+}
+
+static void op_amd_shutdown(struct op_msrs const * const msrs)
+{
+	int i;
+
+	for (i = 0 ; i < NUM_COUNTERS ; ++i) {
+		if (CTR_IS_RESERVED(msrs, i))
+			release_perfctr_nmi(MSR_K7_PERFCTR0 + i);
+	}
+	for (i = 0 ; i < NUM_CONTROLS ; ++i) {
+		if (CTRL_IS_RESERVED(msrs, i))
+			release_evntsel_nmi(MSR_K7_EVNTSEL0 + i);
+	}
+}
+
+#ifndef CONFIG_OPROFILE_IBS
+
+/* no IBS support */
+
+static int op_amd_init(struct oprofile_operations *ops)
+{
+	return 0;
+}
+
+static void op_amd_exit(void) {}
+
+#else
+
+static u8 ibs_eilvt_off;
+
+static inline void apic_init_ibs_nmi_per_cpu(void *arg)
+{
+	ibs_eilvt_off = setup_APIC_eilvt_ibs(0, APIC_EILVT_MSG_NMI, 0);
+}
+
+static inline void apic_clear_ibs_nmi_per_cpu(void *arg)
+{
+	setup_APIC_eilvt_ibs(0, APIC_EILVT_MSG_FIX, 1);
+}
+
+static int pfm_amd64_setup_eilvt(void)
+{
+#define IBSCTL_LVTOFFSETVAL		(1 << 8)
+#define IBSCTL				0x1cc
+	struct pci_dev *cpu_cfg;
+	int nodes;
+	u32 value = 0;
+
+	/* per CPU setup */
+	on_each_cpu(apic_init_ibs_nmi_per_cpu, NULL, 1);
+
+	nodes = 0;
+	cpu_cfg = NULL;
+	do {
+		cpu_cfg = pci_get_device(PCI_VENDOR_ID_AMD,
+					 PCI_DEVICE_ID_AMD_10H_NB_MISC,
+					 cpu_cfg);
+		if (!cpu_cfg)
+			break;
+		++nodes;
+		pci_write_config_dword(cpu_cfg, IBSCTL, ibs_eilvt_off
+				       | IBSCTL_LVTOFFSETVAL);
+		pci_read_config_dword(cpu_cfg, IBSCTL, &value);
+		if (value != (ibs_eilvt_off | IBSCTL_LVTOFFSETVAL)) {
+			printk(KERN_DEBUG "Failed to setup IBS LVT offset, "
+				"IBSCTL = 0x%08x", value);
+			return 1;
+		}
+	} while (1);
+
+	if (!nodes) {
+		printk(KERN_DEBUG "No CPU node configured for IBS");
+		return 1;
+	}
+
+#ifdef CONFIG_NUMA
+	/* Sanity check */
+	/* Works only for 64bit with proper numa implementation. */
+	if (nodes != num_possible_nodes()) {
+		printk(KERN_DEBUG "Failed to setup CPU node(s) for IBS, "
+			"found: %d, expected %d",
+			nodes, num_possible_nodes());
+		return 1;
+	}
+#endif
+	return 0;
+}
+
+/*
+ * initialize the APIC for the IBS interrupts
+ * if available (AMD Family10h rev B0 and later)
+ */
+static void setup_ibs(void)
+{
+	ibs_allowed = boot_cpu_has(X86_FEATURE_IBS);
+
+	if (!ibs_allowed)
+		return;
+
+	if (pfm_amd64_setup_eilvt()) {
+		ibs_allowed = 0;
+		return;
+	}
+
+	printk(KERN_INFO "oprofile: AMD IBS detected\n");
+}
+
+
+/*
+ * unitialize the APIC for the IBS interrupts if needed on AMD Family10h
+ * rev B0 and later */
+static void clear_ibs_nmi(void)
+{
+	if (ibs_allowed)
+		on_each_cpu(apic_clear_ibs_nmi_per_cpu, NULL, 1);
+}
+
+static int (*create_arch_files)(struct super_block * sb, struct dentry * root);
+
+static int setup_ibs_files(struct super_block * sb, struct dentry * root)
+{
+	char buf[12];
+	struct dentry *dir;
+	int ret = 0;
+
+	/* architecture specific files */
+	if (create_arch_files)
+		ret = create_arch_files(sb, root);
+
+	if (ret)
+		return ret;
+
+	if (!ibs_allowed)
+		return ret;
+
+	/* model specific files */
+
+	/* setup some reasonable defaults */
+	ibs_config.max_cnt_fetch = 250000;
+	ibs_config.fetch_enabled = 0;
+	ibs_config.max_cnt_op = 250000;
+	ibs_config.op_enabled = 0;
+	ibs_config.dispatched_ops = 1;
+	snprintf(buf,  sizeof(buf), "ibs_fetch");
+	dir = oprofilefs_mkdir(sb, root, buf);
+	oprofilefs_create_ulong(sb, dir, "rand_enable",
+				&ibs_config.rand_en);
+	oprofilefs_create_ulong(sb, dir, "enable",
+		&ibs_config.fetch_enabled);
+	oprofilefs_create_ulong(sb, dir, "max_count",
+		&ibs_config.max_cnt_fetch);
+	snprintf(buf,  sizeof(buf), "ibs_uops");
+	dir = oprofilefs_mkdir(sb, root, buf);
+	oprofilefs_create_ulong(sb, dir, "enable",
+		&ibs_config.op_enabled);
+	oprofilefs_create_ulong(sb, dir, "max_count",
+		&ibs_config.max_cnt_op);
+	oprofilefs_create_ulong(sb, dir, "dispatched_ops",
+		&ibs_config.dispatched_ops);
+
+	return 0;
+}
+
+static int op_amd_init(struct oprofile_operations *ops)
+{
+	setup_ibs();
+	create_arch_files = ops->create_files;
+	ops->create_files = setup_ibs_files;
+	return 0;
+}
+
+static void op_amd_exit(void)
+{
+	clear_ibs_nmi();
+}
+
+#endif
+
+struct op_x86_model_spec const op_amd_spec = {
+	.init = op_amd_init,
+	.exit = op_amd_exit,
+	.num_counters = NUM_COUNTERS,
+	.num_controls = NUM_CONTROLS,
+	.fill_in_addresses = &op_amd_fill_in_addresses,
+	.setup_ctrs = &op_amd_setup_ctrs,
+	.check_ctrs = &op_amd_check_ctrs,
+	.start = &op_amd_start,
+	.stop = &op_amd_stop,
+	.shutdown = &op_amd_shutdown
+};
diff --git a/arch/x86/oprofile/op_model_athlon.c b/arch/x86/oprofile/op_model_athlon.c
deleted file mode 100644
index 3d53487..0000000
--- a/arch/x86/oprofile/op_model_athlon.c
+++ /dev/null
@@ -1,190 +0,0 @@
-/*
- * @file op_model_athlon.h
- * athlon / K7 / K8 / Family 10h model-specific MSR operations
- *
- * @remark Copyright 2002 OProfile authors
- * @remark Read the file COPYING
- *
- * @author John Levon
- * @author Philippe Elie
- * @author Graydon Hoare
- */
-
-#include <linux/oprofile.h>
-#include <asm/ptrace.h>
-#include <asm/msr.h>
-#include <asm/nmi.h>
-
-#include "op_x86_model.h"
-#include "op_counter.h"
-
-#define NUM_COUNTERS 4
-#define NUM_CONTROLS 4
-
-#define CTR_IS_RESERVED(msrs, c) (msrs->counters[(c)].addr ? 1 : 0)
-#define CTR_READ(l, h, msrs, c) do {rdmsr(msrs->counters[(c)].addr, (l), (h)); } while (0)
-#define CTR_WRITE(l, msrs, c) do {wrmsr(msrs->counters[(c)].addr, -(unsigned int)(l), -1); } while (0)
-#define CTR_OVERFLOWED(n) (!((n) & (1U<<31)))
-
-#define CTRL_IS_RESERVED(msrs, c) (msrs->controls[(c)].addr ? 1 : 0)
-#define CTRL_READ(l, h, msrs, c) do {rdmsr(msrs->controls[(c)].addr, (l), (h)); } while (0)
-#define CTRL_WRITE(l, h, msrs, c) do {wrmsr(msrs->controls[(c)].addr, (l), (h)); } while (0)
-#define CTRL_SET_ACTIVE(n) (n |= (1<<22))
-#define CTRL_SET_INACTIVE(n) (n &= ~(1<<22))
-#define CTRL_CLEAR_LO(x) (x &= (1<<21))
-#define CTRL_CLEAR_HI(x) (x &= 0xfffffcf0)
-#define CTRL_SET_ENABLE(val) (val |= 1<<20)
-#define CTRL_SET_USR(val, u) (val |= ((u & 1) << 16))
-#define CTRL_SET_KERN(val, k) (val |= ((k & 1) << 17))
-#define CTRL_SET_UM(val, m) (val |= (m << 8))
-#define CTRL_SET_EVENT_LOW(val, e) (val |= (e & 0xff))
-#define CTRL_SET_EVENT_HIGH(val, e) (val |= ((e >> 8) & 0xf))
-#define CTRL_SET_HOST_ONLY(val, h) (val |= ((h & 1) << 9))
-#define CTRL_SET_GUEST_ONLY(val, h) (val |= ((h & 1) << 8))
-
-static unsigned long reset_value[NUM_COUNTERS];
-
-static void athlon_fill_in_addresses(struct op_msrs * const msrs)
-{
-	int i;
-
-	for (i = 0; i < NUM_COUNTERS; i++) {
-		if (reserve_perfctr_nmi(MSR_K7_PERFCTR0 + i))
-			msrs->counters[i].addr = MSR_K7_PERFCTR0 + i;
-		else
-			msrs->counters[i].addr = 0;
-	}
-
-	for (i = 0; i < NUM_CONTROLS; i++) {
-		if (reserve_evntsel_nmi(MSR_K7_EVNTSEL0 + i))
-			msrs->controls[i].addr = MSR_K7_EVNTSEL0 + i;
-		else
-			msrs->controls[i].addr = 0;
-	}
-}
-
-
-static void athlon_setup_ctrs(struct op_msrs const * const msrs)
-{
-	unsigned int low, high;
-	int i;
-
-	/* clear all counters */
-	for (i = 0 ; i < NUM_CONTROLS; ++i) {
-		if (unlikely(!CTRL_IS_RESERVED(msrs, i)))
-			continue;
-		CTRL_READ(low, high, msrs, i);
-		CTRL_CLEAR_LO(low);
-		CTRL_CLEAR_HI(high);
-		CTRL_WRITE(low, high, msrs, i);
-	}
-
-	/* avoid a false detection of ctr overflows in NMI handler */
-	for (i = 0; i < NUM_COUNTERS; ++i) {
-		if (unlikely(!CTR_IS_RESERVED(msrs, i)))
-			continue;
-		CTR_WRITE(1, msrs, i);
-	}
-
-	/* enable active counters */
-	for (i = 0; i < NUM_COUNTERS; ++i) {
-		if ((counter_config[i].enabled) && (CTR_IS_RESERVED(msrs, i))) {
-			reset_value[i] = counter_config[i].count;
-
-			CTR_WRITE(counter_config[i].count, msrs, i);
-
-			CTRL_READ(low, high, msrs, i);
-			CTRL_CLEAR_LO(low);
-			CTRL_CLEAR_HI(high);
-			CTRL_SET_ENABLE(low);
-			CTRL_SET_USR(low, counter_config[i].user);
-			CTRL_SET_KERN(low, counter_config[i].kernel);
-			CTRL_SET_UM(low, counter_config[i].unit_mask);
-			CTRL_SET_EVENT_LOW(low, counter_config[i].event);
-			CTRL_SET_EVENT_HIGH(high, counter_config[i].event);
-			CTRL_SET_HOST_ONLY(high, 0);
-			CTRL_SET_GUEST_ONLY(high, 0);
-
-			CTRL_WRITE(low, high, msrs, i);
-		} else {
-			reset_value[i] = 0;
-		}
-	}
-}
-
-
-static int athlon_check_ctrs(struct pt_regs * const regs,
-			     struct op_msrs const * const msrs)
-{
-	unsigned int low, high;
-	int i;
-
-	for (i = 0 ; i < NUM_COUNTERS; ++i) {
-		if (!reset_value[i])
-			continue;
-		CTR_READ(low, high, msrs, i);
-		if (CTR_OVERFLOWED(low)) {
-			oprofile_add_sample(regs, i);
-			CTR_WRITE(reset_value[i], msrs, i);
-		}
-	}
-
-	/* See op_model_ppro.c */
-	return 1;
-}
-
-
-static void athlon_start(struct op_msrs const * const msrs)
-{
-	unsigned int low, high;
-	int i;
-	for (i = 0 ; i < NUM_COUNTERS ; ++i) {
-		if (reset_value[i]) {
-			CTRL_READ(low, high, msrs, i);
-			CTRL_SET_ACTIVE(low);
-			CTRL_WRITE(low, high, msrs, i);
-		}
-	}
-}
-
-
-static void athlon_stop(struct op_msrs const * const msrs)
-{
-	unsigned int low, high;
-	int i;
-
-	/* Subtle: stop on all counters to avoid race with
-	 * setting our pm callback */
-	for (i = 0 ; i < NUM_COUNTERS ; ++i) {
-		if (!reset_value[i])
-			continue;
-		CTRL_READ(low, high, msrs, i);
-		CTRL_SET_INACTIVE(low);
-		CTRL_WRITE(low, high, msrs, i);
-	}
-}
-
-static void athlon_shutdown(struct op_msrs const * const msrs)
-{
-	int i;
-
-	for (i = 0 ; i < NUM_COUNTERS ; ++i) {
-		if (CTR_IS_RESERVED(msrs, i))
-			release_perfctr_nmi(MSR_K7_PERFCTR0 + i);
-	}
-	for (i = 0 ; i < NUM_CONTROLS ; ++i) {
-		if (CTRL_IS_RESERVED(msrs, i))
-			release_evntsel_nmi(MSR_K7_EVNTSEL0 + i);
-	}
-}
-
-struct op_x86_model_spec const op_athlon_spec = {
-	.num_counters = NUM_COUNTERS,
-	.num_controls = NUM_CONTROLS,
-	.fill_in_addresses = &athlon_fill_in_addresses,
-	.setup_ctrs = &athlon_setup_ctrs,
-	.check_ctrs = &athlon_check_ctrs,
-	.start = &athlon_start,
-	.stop = &athlon_stop,
-	.shutdown = &athlon_shutdown
-};
diff --git a/arch/x86/oprofile/op_model_p4.c b/arch/x86/oprofile/op_model_p4.c
index 56b4757..43ac5af 100644
--- a/arch/x86/oprofile/op_model_p4.c
+++ b/arch/x86/oprofile/op_model_p4.c
@@ -10,11 +10,12 @@
 
 #include <linux/oprofile.h>
 #include <linux/smp.h>
+#include <linux/ptrace.h>
+#include <linux/nmi.h>
 #include <asm/msr.h>
-#include <asm/ptrace.h>
 #include <asm/fixmap.h>
 #include <asm/apic.h>
-#include <asm/nmi.h>
+
 
 #include "op_x86_model.h"
 #include "op_counter.h"
@@ -40,7 +41,7 @@
 static inline void setup_num_counters(void)
 {
 #ifdef CONFIG_SMP
-	if (smp_num_siblings == 2){
+	if (smp_num_siblings == 2) {
 		num_counters = NUM_COUNTERS_HT2;
 		num_controls = NUM_CONTROLS_HT2;
 	}
@@ -86,7 +87,7 @@
 #define CTR_FLAME_2    (1 << 6)
 #define CTR_IQ_5       (1 << 7)
 
-static struct p4_counter_binding p4_counters [NUM_COUNTERS_NON_HT] = {
+static struct p4_counter_binding p4_counters[NUM_COUNTERS_NON_HT] = {
 	{ CTR_BPU_0,   MSR_P4_BPU_PERFCTR0,   MSR_P4_BPU_CCCR0 },
 	{ CTR_MS_0,    MSR_P4_MS_PERFCTR0,    MSR_P4_MS_CCCR0 },
 	{ CTR_FLAME_0, MSR_P4_FLAME_PERFCTR0, MSR_P4_FLAME_CCCR0 },
@@ -97,32 +98,32 @@
 	{ CTR_IQ_5,    MSR_P4_IQ_PERFCTR5,    MSR_P4_IQ_CCCR5 }
 };
 
-#define NUM_UNUSED_CCCRS	NUM_CCCRS_NON_HT - NUM_COUNTERS_NON_HT
+#define NUM_UNUSED_CCCRS (NUM_CCCRS_NON_HT - NUM_COUNTERS_NON_HT)
 
 /* p4 event codes in libop/op_event.h are indices into this table. */
 
 static struct p4_event_binding p4_events[NUM_EVENTS] = {
-	
+
 	{ /* BRANCH_RETIRED */
-		0x05, 0x06, 
+		0x05, 0x06,
 		{ {CTR_IQ_4, MSR_P4_CRU_ESCR2},
 		  {CTR_IQ_5, MSR_P4_CRU_ESCR3} }
 	},
-	
+
 	{ /* MISPRED_BRANCH_RETIRED */
-		0x04, 0x03, 
+		0x04, 0x03,
 		{ { CTR_IQ_4, MSR_P4_CRU_ESCR0},
 		  { CTR_IQ_5, MSR_P4_CRU_ESCR1} }
 	},
-	
+
 	{ /* TC_DELIVER_MODE */
 		0x01, 0x01,
-		{ { CTR_MS_0, MSR_P4_TC_ESCR0},  
+		{ { CTR_MS_0, MSR_P4_TC_ESCR0},
 		  { CTR_MS_2, MSR_P4_TC_ESCR1} }
 	},
-	
+
 	{ /* BPU_FETCH_REQUEST */
-		0x00, 0x03, 
+		0x00, 0x03,
 		{ { CTR_BPU_0, MSR_P4_BPU_ESCR0},
 		  { CTR_BPU_2, MSR_P4_BPU_ESCR1} }
 	},
@@ -146,7 +147,7 @@
 	},
 
 	{ /* LOAD_PORT_REPLAY */
-		0x02, 0x04, 
+		0x02, 0x04,
 		{ { CTR_FLAME_0, MSR_P4_SAAT_ESCR0},
 		  { CTR_FLAME_2, MSR_P4_SAAT_ESCR1} }
 	},
@@ -170,43 +171,43 @@
 	},
 
 	{ /* BSQ_CACHE_REFERENCE */
-		0x07, 0x0c, 
+		0x07, 0x0c,
 		{ { CTR_BPU_0, MSR_P4_BSU_ESCR0},
 		  { CTR_BPU_2, MSR_P4_BSU_ESCR1} }
 	},
 
 	{ /* IOQ_ALLOCATION */
-		0x06, 0x03, 
+		0x06, 0x03,
 		{ { CTR_BPU_0, MSR_P4_FSB_ESCR0},
 		  { 0, 0 } }
 	},
 
 	{ /* IOQ_ACTIVE_ENTRIES */
-		0x06, 0x1a, 
+		0x06, 0x1a,
 		{ { CTR_BPU_2, MSR_P4_FSB_ESCR1},
 		  { 0, 0 } }
 	},
 
 	{ /* FSB_DATA_ACTIVITY */
-		0x06, 0x17, 
+		0x06, 0x17,
 		{ { CTR_BPU_0, MSR_P4_FSB_ESCR0},
 		  { CTR_BPU_2, MSR_P4_FSB_ESCR1} }
 	},
 
 	{ /* BSQ_ALLOCATION */
-		0x07, 0x05, 
+		0x07, 0x05,
 		{ { CTR_BPU_0, MSR_P4_BSU_ESCR0},
 		  { 0, 0 } }
 	},
 
 	{ /* BSQ_ACTIVE_ENTRIES */
 		0x07, 0x06,
-		{ { CTR_BPU_2, MSR_P4_BSU_ESCR1 /* guess */},  
+		{ { CTR_BPU_2, MSR_P4_BSU_ESCR1 /* guess */},
 		  { 0, 0 } }
 	},
 
 	{ /* X87_ASSIST */
-		0x05, 0x03, 
+		0x05, 0x03,
 		{ { CTR_IQ_4, MSR_P4_CRU_ESCR2},
 		  { CTR_IQ_5, MSR_P4_CRU_ESCR3} }
 	},
@@ -216,21 +217,21 @@
 		{ { CTR_FLAME_0, MSR_P4_FIRM_ESCR0},
 		  { CTR_FLAME_2, MSR_P4_FIRM_ESCR1} }
 	},
-  
+
 	{ /* PACKED_SP_UOP */
-		0x01, 0x08, 
+		0x01, 0x08,
 		{ { CTR_FLAME_0, MSR_P4_FIRM_ESCR0},
 		  { CTR_FLAME_2, MSR_P4_FIRM_ESCR1} }
 	},
-  
+
 	{ /* PACKED_DP_UOP */
-		0x01, 0x0c, 
+		0x01, 0x0c,
 		{ { CTR_FLAME_0, MSR_P4_FIRM_ESCR0},
 		  { CTR_FLAME_2, MSR_P4_FIRM_ESCR1} }
 	},
 
 	{ /* SCALAR_SP_UOP */
-		0x01, 0x0a, 
+		0x01, 0x0a,
 		{ { CTR_FLAME_0, MSR_P4_FIRM_ESCR0},
 		  { CTR_FLAME_2, MSR_P4_FIRM_ESCR1} }
 	},
@@ -242,31 +243,31 @@
 	},
 
 	{ /* 64BIT_MMX_UOP */
-		0x01, 0x02, 
+		0x01, 0x02,
 		{ { CTR_FLAME_0, MSR_P4_FIRM_ESCR0},
 		  { CTR_FLAME_2, MSR_P4_FIRM_ESCR1} }
 	},
-  
+
 	{ /* 128BIT_MMX_UOP */
-		0x01, 0x1a, 
+		0x01, 0x1a,
 		{ { CTR_FLAME_0, MSR_P4_FIRM_ESCR0},
 		  { CTR_FLAME_2, MSR_P4_FIRM_ESCR1} }
 	},
 
 	{ /* X87_FP_UOP */
-		0x01, 0x04, 
+		0x01, 0x04,
 		{ { CTR_FLAME_0, MSR_P4_FIRM_ESCR0},
 		  { CTR_FLAME_2, MSR_P4_FIRM_ESCR1} }
 	},
-  
+
 	{ /* X87_SIMD_MOVES_UOP */
-		0x01, 0x2e, 
+		0x01, 0x2e,
 		{ { CTR_FLAME_0, MSR_P4_FIRM_ESCR0},
 		  { CTR_FLAME_2, MSR_P4_FIRM_ESCR1} }
 	},
-  
+
 	{ /* MACHINE_CLEAR */
-		0x05, 0x02, 
+		0x05, 0x02,
 		{ { CTR_IQ_4, MSR_P4_CRU_ESCR2},
 		  { CTR_IQ_5, MSR_P4_CRU_ESCR3} }
 	},
@@ -276,9 +277,9 @@
 		{ { CTR_BPU_0, MSR_P4_FSB_ESCR0},
 		  { CTR_BPU_2, MSR_P4_FSB_ESCR1} }
 	},
-  
+
 	{ /* TC_MS_XFER */
-		0x00, 0x05, 
+		0x00, 0x05,
 		{ { CTR_MS_0, MSR_P4_MS_ESCR0},
 		  { CTR_MS_2, MSR_P4_MS_ESCR1} }
 	},
@@ -308,7 +309,7 @@
 	},
 
 	{ /* INSTR_RETIRED */
-		0x04, 0x02, 
+		0x04, 0x02,
 		{ { CTR_IQ_4, MSR_P4_CRU_ESCR0},
 		  { CTR_IQ_5, MSR_P4_CRU_ESCR1} }
 	},
@@ -319,14 +320,14 @@
 		  { CTR_IQ_5, MSR_P4_CRU_ESCR1} }
 	},
 
-	{ /* UOP_TYPE */    
-		0x02, 0x02, 
+	{ /* UOP_TYPE */
+		0x02, 0x02,
 		{ { CTR_IQ_4, MSR_P4_RAT_ESCR0},
 		  { CTR_IQ_5, MSR_P4_RAT_ESCR1} }
 	},
 
 	{ /* RETIRED_MISPRED_BRANCH_TYPE */
-		0x02, 0x05, 
+		0x02, 0x05,
 		{ { CTR_MS_0, MSR_P4_TBPU_ESCR0},
 		  { CTR_MS_2, MSR_P4_TBPU_ESCR1} }
 	},
@@ -349,8 +350,8 @@
 #define ESCR_SET_OS_1(escr, os) ((escr) |= (((os) & 1) << 1))
 #define ESCR_SET_EVENT_SELECT(escr, sel) ((escr) |= (((sel) & 0x3f) << 25))
 #define ESCR_SET_EVENT_MASK(escr, mask) ((escr) |= (((mask) & 0xffff) << 9))
-#define ESCR_READ(escr,high,ev,i) do {rdmsr(ev->bindings[(i)].escr_address, (escr), (high));} while (0)
-#define ESCR_WRITE(escr,high,ev,i) do {wrmsr(ev->bindings[(i)].escr_address, (escr), (high));} while (0)
+#define ESCR_READ(escr, high, ev, i) do {rdmsr(ev->bindings[(i)].escr_address, (escr), (high)); } while (0)
+#define ESCR_WRITE(escr, high, ev, i) do {wrmsr(ev->bindings[(i)].escr_address, (escr), (high)); } while (0)
 
 #define CCCR_RESERVED_BITS 0x38030FFF
 #define CCCR_CLEAR(cccr) ((cccr) &= CCCR_RESERVED_BITS)
@@ -360,15 +361,15 @@
 #define CCCR_SET_PMI_OVF_1(cccr) ((cccr) |= (1<<27))
 #define CCCR_SET_ENABLE(cccr) ((cccr) |= (1<<12))
 #define CCCR_SET_DISABLE(cccr) ((cccr) &= ~(1<<12))
-#define CCCR_READ(low, high, i) do {rdmsr(p4_counters[(i)].cccr_address, (low), (high));} while (0)
-#define CCCR_WRITE(low, high, i) do {wrmsr(p4_counters[(i)].cccr_address, (low), (high));} while (0)
+#define CCCR_READ(low, high, i) do {rdmsr(p4_counters[(i)].cccr_address, (low), (high)); } while (0)
+#define CCCR_WRITE(low, high, i) do {wrmsr(p4_counters[(i)].cccr_address, (low), (high)); } while (0)
 #define CCCR_OVF_P(cccr) ((cccr) & (1U<<31))
 #define CCCR_CLEAR_OVF(cccr) ((cccr) &= (~(1U<<31)))
 
-#define CTRL_IS_RESERVED(msrs,c) (msrs->controls[(c)].addr ? 1 : 0)
-#define CTR_IS_RESERVED(msrs,c) (msrs->counters[(c)].addr ? 1 : 0)
-#define CTR_READ(l,h,i) do {rdmsr(p4_counters[(i)].counter_address, (l), (h));} while (0)
-#define CTR_WRITE(l,i) do {wrmsr(p4_counters[(i)].counter_address, -(u32)(l), -1);} while (0)
+#define CTRL_IS_RESERVED(msrs, c) (msrs->controls[(c)].addr ? 1 : 0)
+#define CTR_IS_RESERVED(msrs, c) (msrs->counters[(c)].addr ? 1 : 0)
+#define CTR_READ(l, h, i) do {rdmsr(p4_counters[(i)].counter_address, (l), (h)); } while (0)
+#define CTR_WRITE(l, i) do {wrmsr(p4_counters[(i)].counter_address, -(u32)(l), -1); } while (0)
 #define CTR_OVERFLOW_P(ctr) (!((ctr) & 0x80000000))
 
 
@@ -380,7 +381,7 @@
 #ifdef CONFIG_SMP
 	int cpu = smp_processor_id();
 	return (cpu != first_cpu(per_cpu(cpu_sibling_map, cpu)));
-#endif	
+#endif
 	return 0;
 }
 
@@ -395,25 +396,23 @@
 
 static void p4_fill_in_addresses(struct op_msrs * const msrs)
 {
-	unsigned int i; 
+	unsigned int i;
 	unsigned int addr, cccraddr, stag;
 
 	setup_num_counters();
 	stag = get_stagger();
 
 	/* initialize some registers */
-	for (i = 0; i < num_counters; ++i) {
+	for (i = 0; i < num_counters; ++i)
 		msrs->counters[i].addr = 0;
-	}
-	for (i = 0; i < num_controls; ++i) {
+	for (i = 0; i < num_controls; ++i)
 		msrs->controls[i].addr = 0;
-	}
-	
+
 	/* the counter & cccr registers we pay attention to */
 	for (i = 0; i < num_counters; ++i) {
 		addr = p4_counters[VIRT_CTR(stag, i)].counter_address;
 		cccraddr = p4_counters[VIRT_CTR(stag, i)].cccr_address;
-		if (reserve_perfctr_nmi(addr)){
+		if (reserve_perfctr_nmi(addr)) {
 			msrs->counters[i].addr = addr;
 			msrs->controls[i].addr = cccraddr;
 		}
@@ -447,22 +446,22 @@
 		if (reserve_evntsel_nmi(addr))
 			msrs->controls[i].addr = addr;
 	}
-	
+
 	for (addr = MSR_P4_MS_ESCR0 + stag;
-	     addr <= MSR_P4_TC_ESCR1; ++i, addr += addr_increment()) { 
+	     addr <= MSR_P4_TC_ESCR1; ++i, addr += addr_increment()) {
 		if (reserve_evntsel_nmi(addr))
 			msrs->controls[i].addr = addr;
 	}
-	
+
 	for (addr = MSR_P4_IX_ESCR0 + stag;
-	     addr <= MSR_P4_CRU_ESCR3; ++i, addr += addr_increment()) { 
+	     addr <= MSR_P4_CRU_ESCR3; ++i, addr += addr_increment()) {
 		if (reserve_evntsel_nmi(addr))
 			msrs->controls[i].addr = addr;
 	}
 
 	/* there are 2 remaining non-contiguously located ESCRs */
 
-	if (num_counters == NUM_COUNTERS_NON_HT) {		
+	if (num_counters == NUM_COUNTERS_NON_HT) {
 		/* standard non-HT CPUs handle both remaining ESCRs*/
 		if (reserve_evntsel_nmi(MSR_P4_CRU_ESCR5))
 			msrs->controls[i++].addr = MSR_P4_CRU_ESCR5;
@@ -498,20 +497,20 @@
 	unsigned int stag;
 
 	stag = get_stagger();
-	
+
 	/* convert from counter *number* to counter *bit* */
 	counter_bit = 1 << VIRT_CTR(stag, ctr);
-	
+
 	/* find our event binding structure. */
 	if (counter_config[ctr].event <= 0 || counter_config[ctr].event > NUM_EVENTS) {
-		printk(KERN_ERR 
-		       "oprofile: P4 event code 0x%lx out of range\n", 
+		printk(KERN_ERR
+		       "oprofile: P4 event code 0x%lx out of range\n",
 		       counter_config[ctr].event);
 		return;
 	}
-	
+
 	ev = &(p4_events[counter_config[ctr].event - 1]);
-	
+
 	for (i = 0; i < maxbind; i++) {
 		if (ev->bindings[i].virt_counter & counter_bit) {
 
@@ -526,25 +525,24 @@
 				ESCR_SET_OS_1(escr, counter_config[ctr].kernel);
 			}
 			ESCR_SET_EVENT_SELECT(escr, ev->event_select);
-			ESCR_SET_EVENT_MASK(escr, counter_config[ctr].unit_mask);			
+			ESCR_SET_EVENT_MASK(escr, counter_config[ctr].unit_mask);
 			ESCR_WRITE(escr, high, ev, i);
-		       
+
 			/* modify CCCR */
 			CCCR_READ(cccr, high, VIRT_CTR(stag, ctr));
 			CCCR_CLEAR(cccr);
 			CCCR_SET_REQUIRED_BITS(cccr);
 			CCCR_SET_ESCR_SELECT(cccr, ev->escr_select);
-			if (stag == 0) {
+			if (stag == 0)
 				CCCR_SET_PMI_OVF_0(cccr);
-			} else {
+			else
 				CCCR_SET_PMI_OVF_1(cccr);
-			}
 			CCCR_WRITE(cccr, high, VIRT_CTR(stag, ctr));
 			return;
 		}
 	}
 
-	printk(KERN_ERR 
+	printk(KERN_ERR
 	       "oprofile: P4 event code 0x%lx no binding, stag %d ctr %d\n",
 	       counter_config[ctr].event, stag, ctr);
 }
@@ -559,14 +557,14 @@
 	stag = get_stagger();
 
 	rdmsr(MSR_IA32_MISC_ENABLE, low, high);
-	if (! MISC_PMC_ENABLED_P(low)) {
+	if (!MISC_PMC_ENABLED_P(low)) {
 		printk(KERN_ERR "oprofile: P4 PMC not available\n");
 		return;
 	}
 
 	/* clear the cccrs we will use */
 	for (i = 0 ; i < num_counters ; i++) {
-		if (unlikely(!CTRL_IS_RESERVED(msrs,i)))
+		if (unlikely(!CTRL_IS_RESERVED(msrs, i)))
 			continue;
 		rdmsr(p4_counters[VIRT_CTR(stag, i)].cccr_address, low, high);
 		CCCR_CLEAR(low);
@@ -576,14 +574,14 @@
 
 	/* clear all escrs (including those outside our concern) */
 	for (i = num_counters; i < num_controls; i++) {
-		if (unlikely(!CTRL_IS_RESERVED(msrs,i)))
+		if (unlikely(!CTRL_IS_RESERVED(msrs, i)))
 			continue;
 		wrmsr(msrs->controls[i].addr, 0, 0);
 	}
 
 	/* setup all counters */
 	for (i = 0 ; i < num_counters ; ++i) {
-		if ((counter_config[i].enabled) && (CTRL_IS_RESERVED(msrs,i))) {
+		if ((counter_config[i].enabled) && (CTRL_IS_RESERVED(msrs, i))) {
 			reset_value[i] = counter_config[i].count;
 			pmc_setup_one_p4_counter(i);
 			CTR_WRITE(counter_config[i].count, VIRT_CTR(stag, i));
@@ -603,11 +601,11 @@
 	stag = get_stagger();
 
 	for (i = 0; i < num_counters; ++i) {
-		
-		if (!reset_value[i]) 
+
+		if (!reset_value[i])
 			continue;
 
-		/* 
+		/*
 		 * there is some eccentricity in the hardware which
 		 * requires that we perform 2 extra corrections:
 		 *
@@ -616,24 +614,24 @@
 		 *
 		 * - write the counter back twice to ensure it gets
 		 *   updated properly.
-		 * 
+		 *
 		 * the former seems to be related to extra NMIs happening
 		 * during the current NMI; the latter is reported as errata
 		 * N15 in intel doc 249199-029, pentium 4 specification
 		 * update, though their suggested work-around does not
 		 * appear to solve the problem.
 		 */
-		
+
 		real = VIRT_CTR(stag, i);
 
 		CCCR_READ(low, high, real);
- 		CTR_READ(ctr, high, real);
+		CTR_READ(ctr, high, real);
 		if (CCCR_OVF_P(low) || CTR_OVERFLOW_P(ctr)) {
 			oprofile_add_sample(regs, i);
- 			CTR_WRITE(reset_value[i], real);
+			CTR_WRITE(reset_value[i], real);
 			CCCR_CLEAR_OVF(low);
 			CCCR_WRITE(low, high, real);
- 			CTR_WRITE(reset_value[i], real);
+			CTR_WRITE(reset_value[i], real);
 		}
 	}
 
@@ -683,15 +681,16 @@
 	int i;
 
 	for (i = 0 ; i < num_counters ; ++i) {
-		if (CTR_IS_RESERVED(msrs,i))
+		if (CTR_IS_RESERVED(msrs, i))
 			release_perfctr_nmi(msrs->counters[i].addr);
 	}
-	/* some of the control registers are specially reserved in
+	/*
+	 * some of the control registers are specially reserved in
 	 * conjunction with the counter registers (hence the starting offset).
 	 * This saves a few bits.
 	 */
 	for (i = num_counters ; i < num_controls ; ++i) {
-		if (CTRL_IS_RESERVED(msrs,i))
+		if (CTRL_IS_RESERVED(msrs, i))
 			release_evntsel_nmi(msrs->controls[i].addr);
 	}
 }
diff --git a/arch/x86/oprofile/op_x86_model.h b/arch/x86/oprofile/op_x86_model.h
index 45b605f..05a0261 100644
--- a/arch/x86/oprofile/op_x86_model.h
+++ b/arch/x86/oprofile/op_x86_model.h
@@ -32,6 +32,8 @@
  * various x86 CPU models' perfctr support.
  */
 struct op_x86_model_spec {
+	int (*init)(struct oprofile_operations *ops);
+	void (*exit)(void);
 	unsigned int const num_counters;
 	unsigned int const num_controls;
 	void (*fill_in_addresses)(struct op_msrs * const msrs);
@@ -46,6 +48,6 @@
 extern struct op_x86_model_spec const op_ppro_spec;
 extern struct op_x86_model_spec const op_p4_spec;
 extern struct op_x86_model_spec const op_p4_ht2_spec;
-extern struct op_x86_model_spec const op_athlon_spec;
+extern struct op_x86_model_spec const op_amd_spec;
 
 #endif /* OP_X86_MODEL_H */
diff --git a/arch/x86/pci/acpi.c b/arch/x86/pci/acpi.c
index 19af069..1d88d2b 100644
--- a/arch/x86/pci/acpi.c
+++ b/arch/x86/pci/acpi.c
@@ -250,10 +250,5 @@
 			acpi_pci_irq_enable(dev);
 	}
 
-#ifdef CONFIG_X86_IO_APIC
-	if (acpi_ioapic)
-		print_IO_APIC();
-#endif
-
 	return 0;
 }
diff --git a/arch/x86/pci/amd_bus.c b/arch/x86/pci/amd_bus.c
index 6a0fca7..22e0576 100644
--- a/arch/x86/pci/amd_bus.c
+++ b/arch/x86/pci/amd_bus.c
@@ -580,7 +580,7 @@
 				    unsigned long action, void *hcpu)
 {
 	int cpu = (long)hcpu;
-	switch(action) {
+	switch (action) {
 	case CPU_ONLINE:
 	case CPU_ONLINE_FROZEN:
 		smp_call_function_single(cpu, enable_pci_io_ecs, NULL, 0);
diff --git a/arch/x86/pci/fixup.c b/arch/x86/pci/fixup.c
index 4bdaa59..3c27a80 100644
--- a/arch/x86/pci/fixup.c
+++ b/arch/x86/pci/fixup.c
@@ -511,3 +511,31 @@
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, 0x1202, fam10h_pci_cfg_space_size);
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, 0x1203, fam10h_pci_cfg_space_size);
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, 0x1204, fam10h_pci_cfg_space_size);
+
+/*
+ * SB600: Disable BAR1 on device 14.0 to avoid HPET resources from
+ * confusing the PCI engine:
+ */
+static void sb600_disable_hpet_bar(struct pci_dev *dev)
+{
+	u8 val;
+
+	/*
+	 * The SB600 and SB700 both share the same device
+	 * ID, but the PM register 0x55 does something different
+	 * for the SB700, so make sure we are dealing with the
+	 * SB600 before touching the bit:
+	 */
+
+	pci_read_config_byte(dev, 0x08, &val);
+
+	if (val < 0x2F) {
+		outb(0x55, 0xCD6);
+		val = inb(0xCD7);
+
+		/* Set bit 7 in PM register 0x55 */
+		outb(0x55, 0xCD6);
+		outb(val | 0x80, 0xCD7);
+	}
+}
+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_ATI, 0x4385, sb600_disable_hpet_bar);
diff --git a/arch/x86/pci/i386.c b/arch/x86/pci/i386.c
index 8791fc5..844df0c 100644
--- a/arch/x86/pci/i386.c
+++ b/arch/x86/pci/i386.c
@@ -33,6 +33,7 @@
 #include <linux/bootmem.h>
 
 #include <asm/pat.h>
+#include <asm/e820.h>
 
 #include "pci.h"
 
@@ -227,6 +228,8 @@
 	pcibios_allocate_bus_resources(&pci_root_buses);
 	pcibios_allocate_resources(0);
 	pcibios_allocate_resources(1);
+
+	e820_reserve_resources_late();
 }
 
 /**
diff --git a/arch/x86/pci/irq.c b/arch/x86/pci/irq.c
index 8e07718..006599d 100644
--- a/arch/x86/pci/irq.c
+++ b/arch/x86/pci/irq.c
@@ -1043,35 +1043,44 @@
 		if (io_apic_assign_pci_irqs) {
 			int irq;
 
-			if (pin) {
-				/*
-				 * interrupt pins are numbered starting
-				 * from 1
-				 */
-				pin--;
-				irq = IO_APIC_get_PCI_irq_vector(dev->bus->number,
-					PCI_SLOT(dev->devfn), pin);
-	/*
-	 * Busses behind bridges are typically not listed in the MP-table.
-	 * In this case we have to look up the IRQ based on the parent bus,
-	 * parent slot, and pin number. The SMP code detects such bridged
-	 * busses itself so we should get into this branch reliably.
-	 */
-				if (irq < 0 && dev->bus->parent) { /* go back to the bridge */
-					struct pci_dev *bridge = dev->bus->self;
+			if (!pin)
+				continue;
 
-					pin = (pin + PCI_SLOT(dev->devfn)) % 4;
-					irq = IO_APIC_get_PCI_irq_vector(bridge->bus->number,
-							PCI_SLOT(bridge->devfn), pin);
-					if (irq >= 0)
-						dev_warn(&dev->dev, "using bridge %s INT %c to get IRQ %d\n",
-							 pci_name(bridge),
-							 'A' + pin, irq);
-				}
-				if (irq >= 0) {
-					dev_info(&dev->dev, "PCI->APIC IRQ transform: INT %c -> IRQ %d\n", 'A' + pin, irq);
-					dev->irq = irq;
-				}
+			/*
+			 * interrupt pins are numbered starting from 1
+			 */
+			pin--;
+			irq = IO_APIC_get_PCI_irq_vector(dev->bus->number,
+				PCI_SLOT(dev->devfn), pin);
+			/*
+			 * Busses behind bridges are typically not listed in the
+			 * MP-table.  In this case we have to look up the IRQ
+			 * based on the parent bus, parent slot, and pin number.
+			 * The SMP code detects such bridged busses itself so we
+			 * should get into this branch reliably.
+			 */
+			if (irq < 0 && dev->bus->parent) {
+				/* go back to the bridge */
+				struct pci_dev *bridge = dev->bus->self;
+				int bus;
+
+				pin = (pin + PCI_SLOT(dev->devfn)) % 4;
+				bus = bridge->bus->number;
+				irq = IO_APIC_get_PCI_irq_vector(bus,
+						PCI_SLOT(bridge->devfn), pin);
+				if (irq >= 0)
+					dev_warn(&dev->dev,
+						"using bridge %s INT %c to "
+							"get IRQ %d\n",
+						 pci_name(bridge),
+						 'A' + pin, irq);
+			}
+			if (irq >= 0) {
+				dev_info(&dev->dev,
+					"PCI->APIC IRQ transform: INT %c "
+						"-> IRQ %d\n",
+					'A' + pin, irq);
+				dev->irq = irq;
 			}
 		}
 #endif
diff --git a/arch/x86/pci/mmconfig-shared.c b/arch/x86/pci/mmconfig-shared.c
index d963576..654a223 100644
--- a/arch/x86/pci/mmconfig-shared.c
+++ b/arch/x86/pci/mmconfig-shared.c
@@ -209,7 +209,7 @@
 	return name != NULL;
 }
 
-static void __init pci_mmcfg_insert_resources(unsigned long resource_flags)
+static void __init pci_mmcfg_insert_resources(void)
 {
 #define PCI_MMCFG_RESOURCE_NAME_LEN 19
 	int i;
@@ -233,7 +233,7 @@
 			 cfg->pci_segment);
 		res->start = cfg->address;
 		res->end = res->start + (num_buses << 20) - 1;
-		res->flags = IORESOURCE_MEM | resource_flags;
+		res->flags = IORESOURCE_MEM | IORESOURCE_BUSY;
 		insert_resource(&iomem_resource, res);
 		names += PCI_MMCFG_RESOURCE_NAME_LEN;
 	}
@@ -434,11 +434,9 @@
 	    (pci_mmcfg_config[0].address == 0))
 		return;
 
-	if (pci_mmcfg_arch_init()) {
-		if (known_bridge)
-			pci_mmcfg_insert_resources(IORESOURCE_BUSY);
+	if (pci_mmcfg_arch_init())
 		pci_probe = (pci_probe & ~PCI_PROBE_MASK) | PCI_PROBE_MMCONF;
-	} else {
+	else {
 		/*
 		 * Signal not to attempt to insert mmcfg resources because
 		 * the architecture mmcfg setup could not initialize.
@@ -475,7 +473,7 @@
 	 * marked so it won't cause request errors when __request_region is
 	 * called.
 	 */
-	pci_mmcfg_insert_resources(0);
+	pci_mmcfg_insert_resources();
 
 	return 0;
 }
diff --git a/arch/x86/power/cpu_32.c b/arch/x86/power/cpu_32.c
index d3e083d..274d060 100644
--- a/arch/x86/power/cpu_32.c
+++ b/arch/x86/power/cpu_32.c
@@ -11,6 +11,7 @@
 #include <linux/suspend.h>
 #include <asm/mtrr.h>
 #include <asm/mce.h>
+#include <asm/xcr.h>
 
 static struct saved_context saved_context;
 
@@ -126,6 +127,12 @@
 	if (boot_cpu_has(X86_FEATURE_SEP))
 		enable_sep_cpu();
 
+	/*
+	 * restore XCR0 for xsave capable cpu's.
+	 */
+	if (cpu_has_xsave)
+		xsetbv(XCR_XFEATURE_ENABLED_MASK, pcntxt_mask);
+
 	fix_processor_context();
 	do_fpu_end();
 	mtrr_ap_init();
diff --git a/arch/x86/power/cpu_64.c b/arch/x86/power/cpu_64.c
index 66bdfb5..e3b6cf7 100644
--- a/arch/x86/power/cpu_64.c
+++ b/arch/x86/power/cpu_64.c
@@ -14,6 +14,7 @@
 #include <asm/page.h>
 #include <asm/pgtable.h>
 #include <asm/mtrr.h>
+#include <asm/xcr.h>
 
 static void fix_processor_context(void);
 
@@ -122,6 +123,12 @@
 	wrmsrl(MSR_GS_BASE, ctxt->gs_base);
 	wrmsrl(MSR_KERNEL_GS_BASE, ctxt->gs_kernel_base);
 
+	/*
+	 * restore XCR0 for xsave capable cpu's.
+	 */
+	if (cpu_has_xsave)
+		xsetbv(XCR_XFEATURE_ENABLED_MASK, pcntxt_mask);
+
 	fix_processor_context();
 
 	do_fpu_end();
diff --git a/arch/x86/power/hibernate_asm_32.S b/arch/x86/power/hibernate_asm_32.S
index 4fc7e87..d1e9b53 100644
--- a/arch/x86/power/hibernate_asm_32.S
+++ b/arch/x86/power/hibernate_asm_32.S
@@ -1,5 +1,3 @@
-.text
-
 /*
  * This may not use any stack, nor any variable that is not "NoSave":
  *
@@ -12,17 +10,18 @@
 #include <asm/segment.h>
 #include <asm/page.h>
 #include <asm/asm-offsets.h>
+#include <asm/processor-flags.h>
 
-	.text
+.text
 
 ENTRY(swsusp_arch_suspend)
-
 	movl %esp, saved_context_esp
 	movl %ebx, saved_context_ebx
 	movl %ebp, saved_context_ebp
 	movl %esi, saved_context_esi
 	movl %edi, saved_context_edi
-	pushfl ; popl saved_context_eflags
+	pushfl
+	popl saved_context_eflags
 
 	call swsusp_save
 	ret
@@ -59,7 +58,7 @@
 	movl	mmu_cr4_features, %ecx
 	jecxz	1f	# cr4 Pentium and higher, skip if zero
 	movl	%ecx, %edx
-	andl	$~(1<<7), %edx;  # PGE
+	andl	$~(X86_CR4_PGE), %edx
 	movl	%edx, %cr4;  # turn off PGE
 1:
 	movl	%cr3, %eax;  # flush TLB
@@ -74,7 +73,8 @@
 	movl saved_context_esi, %esi
 	movl saved_context_edi, %edi
 
-	pushl saved_context_eflags ; popfl
+	pushl saved_context_eflags
+	popfl
 
 	xorl	%eax, %eax
 
diff --git a/arch/x86/xen/Kconfig b/arch/x86/xen/Kconfig
index 3815e42..87b9ab1 100644
--- a/arch/x86/xen/Kconfig
+++ b/arch/x86/xen/Kconfig
@@ -26,5 +26,13 @@
 
 config XEN_SAVE_RESTORE
        bool
-       depends on PM
-       default y
\ No newline at end of file
+       depends on XEN && PM
+       default y
+
+config XEN_DEBUG_FS
+	bool "Enable Xen debug and tuning parameters in debugfs"
+	depends on XEN && DEBUG_FS
+	default n
+	help
+	  Enable statistics output and various tuning options in debugfs.
+	  Enabling this option may incur a significant performance overhead.
diff --git a/arch/x86/xen/Makefile b/arch/x86/xen/Makefile
index 59c1e53..3139479 100644
--- a/arch/x86/xen/Makefile
+++ b/arch/x86/xen/Makefile
@@ -1,4 +1,12 @@
-obj-y		:= enlighten.o setup.o multicalls.o mmu.o \
+ifdef CONFIG_FTRACE
+# Do not profile debug and lowlevel utilities
+CFLAGS_REMOVE_spinlock.o = -pg
+CFLAGS_REMOVE_time.o = -pg
+CFLAGS_REMOVE_irq.o = -pg
+endif
+
+obj-y		:= enlighten.o setup.o multicalls.o mmu.o irq.o \
 			time.o xen-asm_$(BITS).o grant-table.o suspend.o
 
-obj-$(CONFIG_SMP)	+= smp.o
+obj-$(CONFIG_SMP)		+= smp.o spinlock.o
+obj-$(CONFIG_XEN_DEBUG_FS)	+= debugfs.o
\ No newline at end of file
diff --git a/arch/x86/xen/debugfs.c b/arch/x86/xen/debugfs.c
new file mode 100644
index 0000000..b53225d
--- /dev/null
+++ b/arch/x86/xen/debugfs.c
@@ -0,0 +1,123 @@
+#include <linux/init.h>
+#include <linux/debugfs.h>
+#include <linux/module.h>
+
+#include "debugfs.h"
+
+static struct dentry *d_xen_debug;
+
+struct dentry * __init xen_init_debugfs(void)
+{
+	if (!d_xen_debug) {
+		d_xen_debug = debugfs_create_dir("xen", NULL);
+
+		if (!d_xen_debug)
+			pr_warning("Could not create 'xen' debugfs directory\n");
+	}
+
+	return d_xen_debug;
+}
+
+struct array_data
+{
+	void *array;
+	unsigned elements;
+};
+
+static int u32_array_open(struct inode *inode, struct file *file)
+{
+	file->private_data = NULL;
+	return nonseekable_open(inode, file);
+}
+
+static size_t format_array(char *buf, size_t bufsize, const char *fmt,
+			   u32 *array, unsigned array_size)
+{
+	size_t ret = 0;
+	unsigned i;
+
+	for(i = 0; i < array_size; i++) {
+		size_t len;
+
+		len = snprintf(buf, bufsize, fmt, array[i]);
+		len++;	/* ' ' or '\n' */
+		ret += len;
+
+		if (buf) {
+			buf += len;
+			bufsize -= len;
+			buf[-1] = (i == array_size-1) ? '\n' : ' ';
+		}
+	}
+
+	ret++;		/* \0 */
+	if (buf)
+		*buf = '\0';
+
+	return ret;
+}
+
+static char *format_array_alloc(const char *fmt, u32 *array, unsigned array_size)
+{
+	size_t len = format_array(NULL, 0, fmt, array, array_size);
+	char *ret;
+
+	ret = kmalloc(len, GFP_KERNEL);
+	if (ret == NULL)
+		return NULL;
+
+	format_array(ret, len, fmt, array, array_size);
+	return ret;
+}
+
+static ssize_t u32_array_read(struct file *file, char __user *buf, size_t len,
+			      loff_t *ppos)
+{
+	struct inode *inode = file->f_path.dentry->d_inode;
+	struct array_data *data = inode->i_private;
+	size_t size;
+
+	if (*ppos == 0) {
+		if (file->private_data) {
+			kfree(file->private_data);
+			file->private_data = NULL;
+		}
+
+		file->private_data = format_array_alloc("%u", data->array, data->elements);
+	}
+
+	size = 0;
+	if (file->private_data)
+		size = strlen(file->private_data);
+
+	return simple_read_from_buffer(buf, len, ppos, file->private_data, size);
+}
+
+static int xen_array_release(struct inode *inode, struct file *file)
+{
+	kfree(file->private_data);
+
+	return 0;
+}
+
+static struct file_operations u32_array_fops = {
+	.owner	= THIS_MODULE,
+	.open	= u32_array_open,
+	.release= xen_array_release,
+	.read	= u32_array_read,
+};
+
+struct dentry *xen_debugfs_create_u32_array(const char *name, mode_t mode,
+					    struct dentry *parent,
+					    u32 *array, unsigned elements)
+{
+	struct array_data *data = kmalloc(sizeof(*data), GFP_KERNEL);
+
+	if (data == NULL)
+		return NULL;
+
+	data->array = array;
+	data->elements = elements;
+
+	return debugfs_create_file(name, mode, parent, data, &u32_array_fops);
+}
diff --git a/arch/x86/xen/debugfs.h b/arch/x86/xen/debugfs.h
new file mode 100644
index 0000000..e281320
--- /dev/null
+++ b/arch/x86/xen/debugfs.h
@@ -0,0 +1,10 @@
+#ifndef _XEN_DEBUGFS_H
+#define _XEN_DEBUGFS_H
+
+struct dentry * __init xen_init_debugfs(void);
+
+struct dentry *xen_debugfs_create_u32_array(const char *name, mode_t mode,
+					    struct dentry *parent,
+					    u32 *array, unsigned elements);
+
+#endif /* _XEN_DEBUGFS_H */
diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c
index a4e201b..0013a72 100644
--- a/arch/x86/xen/enlighten.c
+++ b/arch/x86/xen/enlighten.c
@@ -30,12 +30,12 @@
 #include <xen/interface/xen.h>
 #include <xen/interface/physdev.h>
 #include <xen/interface/vcpu.h>
-#include <xen/interface/sched.h>
 #include <xen/features.h>
 #include <xen/page.h>
 #include <xen/hvc-console.h>
 
 #include <asm/paravirt.h>
+#include <asm/apic.h>
 #include <asm/page.h>
 #include <asm/xen/hypercall.h>
 #include <asm/xen/hypervisor.h>
@@ -57,6 +57,9 @@
 DEFINE_PER_CPU(struct vcpu_info *, xen_vcpu);
 DEFINE_PER_CPU(struct vcpu_info, xen_vcpu_info);
 
+enum xen_domain_type xen_domain_type = XEN_NATIVE;
+EXPORT_SYMBOL_GPL(xen_domain_type);
+
 /*
  * Identity map, in addition to plain kernel map.  This needs to be
  * large enough to allocate page table pages to allocate the rest.
@@ -110,7 +113,14 @@
  *
  * 0: not available, 1: available
  */
-static int have_vcpu_info_placement = 1;
+static int have_vcpu_info_placement =
+#ifdef CONFIG_X86_32
+	1
+#else
+	0
+#endif
+	;
+
 
 static void xen_vcpu_setup(int cpu)
 {
@@ -226,94 +236,6 @@
 	return HYPERVISOR_get_debugreg(reg);
 }
 
-static unsigned long xen_save_fl(void)
-{
-	struct vcpu_info *vcpu;
-	unsigned long flags;
-
-	vcpu = x86_read_percpu(xen_vcpu);
-
-	/* flag has opposite sense of mask */
-	flags = !vcpu->evtchn_upcall_mask;
-
-	/* convert to IF type flag
-	   -0 -> 0x00000000
-	   -1 -> 0xffffffff
-	*/
-	return (-flags) & X86_EFLAGS_IF;
-}
-
-static void xen_restore_fl(unsigned long flags)
-{
-	struct vcpu_info *vcpu;
-
-	/* convert from IF type flag */
-	flags = !(flags & X86_EFLAGS_IF);
-
-	/* There's a one instruction preempt window here.  We need to
-	   make sure we're don't switch CPUs between getting the vcpu
-	   pointer and updating the mask. */
-	preempt_disable();
-	vcpu = x86_read_percpu(xen_vcpu);
-	vcpu->evtchn_upcall_mask = flags;
-	preempt_enable_no_resched();
-
-	/* Doesn't matter if we get preempted here, because any
-	   pending event will get dealt with anyway. */
-
-	if (flags == 0) {
-		preempt_check_resched();
-		barrier(); /* unmask then check (avoid races) */
-		if (unlikely(vcpu->evtchn_upcall_pending))
-			force_evtchn_callback();
-	}
-}
-
-static void xen_irq_disable(void)
-{
-	/* There's a one instruction preempt window here.  We need to
-	   make sure we're don't switch CPUs between getting the vcpu
-	   pointer and updating the mask. */
-	preempt_disable();
-	x86_read_percpu(xen_vcpu)->evtchn_upcall_mask = 1;
-	preempt_enable_no_resched();
-}
-
-static void xen_irq_enable(void)
-{
-	struct vcpu_info *vcpu;
-
-	/* We don't need to worry about being preempted here, since
-	   either a) interrupts are disabled, so no preemption, or b)
-	   the caller is confused and is trying to re-enable interrupts
-	   on an indeterminate processor. */
-
-	vcpu = x86_read_percpu(xen_vcpu);
-	vcpu->evtchn_upcall_mask = 0;
-
-	/* Doesn't matter if we get preempted here, because any
-	   pending event will get dealt with anyway. */
-
-	barrier(); /* unmask then check (avoid races) */
-	if (unlikely(vcpu->evtchn_upcall_pending))
-		force_evtchn_callback();
-}
-
-static void xen_safe_halt(void)
-{
-	/* Blocking includes an implicit local_irq_enable(). */
-	if (HYPERVISOR_sched_op(SCHEDOP_block, NULL) != 0)
-		BUG();
-}
-
-static void xen_halt(void)
-{
-	if (irqs_disabled())
-		HYPERVISOR_vcpu_op(VCPUOP_down, smp_processor_id(), NULL);
-	else
-		xen_safe_halt();
-}
-
 static void xen_leave_lazy(void)
 {
 	paravirt_leave_lazy(paravirt_get_lazy_mode());
@@ -325,6 +247,59 @@
 	return 0;
 }
 
+/*
+ * Set the page permissions for a particular virtual address.  If the
+ * address is a vmalloc mapping (or other non-linear mapping), then
+ * find the linear mapping of the page and also set its protections to
+ * match.
+ */
+static void set_aliased_prot(void *v, pgprot_t prot)
+{
+	int level;
+	pte_t *ptep;
+	pte_t pte;
+	unsigned long pfn;
+	struct page *page;
+
+	ptep = lookup_address((unsigned long)v, &level);
+	BUG_ON(ptep == NULL);
+
+	pfn = pte_pfn(*ptep);
+	page = pfn_to_page(pfn);
+
+	pte = pfn_pte(pfn, prot);
+
+	if (HYPERVISOR_update_va_mapping((unsigned long)v, pte, 0))
+		BUG();
+
+	if (!PageHighMem(page)) {
+		void *av = __va(PFN_PHYS(pfn));
+
+		if (av != v)
+			if (HYPERVISOR_update_va_mapping((unsigned long)av, pte, 0))
+				BUG();
+	} else
+		kmap_flush_unused();
+}
+
+static void xen_alloc_ldt(struct desc_struct *ldt, unsigned entries)
+{
+	const unsigned entries_per_page = PAGE_SIZE / LDT_ENTRY_SIZE;
+	int i;
+
+	for(i = 0; i < entries; i += entries_per_page)
+		set_aliased_prot(ldt + i, PAGE_KERNEL_RO);
+}
+
+static void xen_free_ldt(struct desc_struct *ldt, unsigned entries)
+{
+	const unsigned entries_per_page = PAGE_SIZE / LDT_ENTRY_SIZE;
+	int i;
+
+	for(i = 0; i < entries; i += entries_per_page)
+		set_aliased_prot(ldt + i, PAGE_KERNEL);
+}
+
 static void xen_set_ldt(const void *addr, unsigned entries)
 {
 	struct mmuext_op *op;
@@ -425,8 +400,7 @@
 static void xen_write_ldt_entry(struct desc_struct *dt, int entrynum,
 				const void *ptr)
 {
-	unsigned long lp = (unsigned long)&dt[entrynum];
-	xmaddr_t mach_lp = virt_to_machine(lp);
+	xmaddr_t mach_lp = arbitrary_virt_to_machine(&dt[entrynum]);
 	u64 entry = *(u64 *)ptr;
 
 	preempt_disable();
@@ -559,7 +533,7 @@
 }
 
 static void xen_load_sp0(struct tss_struct *tss,
-			  struct thread_struct *thread)
+			 struct thread_struct *thread)
 {
 	struct multicall_space mcs = xen_mc_entry(0);
 	MULTI_stack_switch(mcs.mc, __KERNEL_DS, thread->sp0);
@@ -580,16 +554,47 @@
 }
 
 #ifdef CONFIG_X86_LOCAL_APIC
-static u32 xen_apic_read(unsigned long reg)
+static u32 xen_apic_read(u32 reg)
 {
 	return 0;
 }
 
-static void xen_apic_write(unsigned long reg, u32 val)
+static void xen_apic_write(u32 reg, u32 val)
 {
 	/* Warn to see if there's any stray references */
 	WARN_ON(1);
 }
+
+static u64 xen_apic_icr_read(void)
+{
+	return 0;
+}
+
+static void xen_apic_icr_write(u32 low, u32 id)
+{
+	/* Warn to see if there's any stray references */
+	WARN_ON(1);
+}
+
+static void xen_apic_wait_icr_idle(void)
+{
+        return;
+}
+
+static u32 xen_safe_apic_wait_icr_idle(void)
+{
+        return 0;
+}
+
+static struct apic_ops xen_basic_apic_ops = {
+	.read = xen_apic_read,
+	.write = xen_apic_write,
+	.icr_read = xen_apic_icr_read,
+	.icr_write = xen_apic_icr_write,
+	.wait_icr_idle = xen_apic_wait_icr_idle,
+	.safe_wait_icr_idle = xen_safe_apic_wait_icr_idle,
+};
+
 #endif
 
 static void xen_flush_tlb(void)
@@ -803,6 +808,19 @@
 			ret = -EFAULT;
 		break;
 #endif
+
+	case MSR_STAR:
+	case MSR_CSTAR:
+	case MSR_LSTAR:
+	case MSR_SYSCALL_MASK:
+	case MSR_IA32_SYSENTER_CS:
+	case MSR_IA32_SYSENTER_ESP:
+	case MSR_IA32_SYSENTER_EIP:
+		/* Fast syscall setup is all done in hypercalls, so
+		   these are all ignored.  Stub them out here to stop
+		   Xen console noise. */
+		break;
+
 	default:
 		ret = native_write_msr_safe(msr, low, high);
 	}
@@ -812,7 +830,7 @@
 
 /* Early in boot, while setting up the initial pagetable, assume
    everything is pinned. */
-static __init void xen_alloc_pte_init(struct mm_struct *mm, u32 pfn)
+static __init void xen_alloc_pte_init(struct mm_struct *mm, unsigned long pfn)
 {
 #ifdef CONFIG_FLATMEM
 	BUG_ON(mem_map);	/* should only be used early */
@@ -822,7 +840,7 @@
 
 /* Early release_pte assumes that all pts are pinned, since there's
    only init_mm and anything attached to that is pinned. */
-static void xen_release_pte_init(u32 pfn)
+static void xen_release_pte_init(unsigned long pfn)
 {
 	make_lowmem_page_readwrite(__va(PFN_PHYS(pfn)));
 }
@@ -838,7 +856,7 @@
 
 /* This needs to make sure the new pte page is pinned iff its being
    attached to a pinned pagetable. */
-static void xen_alloc_ptpage(struct mm_struct *mm, u32 pfn, unsigned level)
+static void xen_alloc_ptpage(struct mm_struct *mm, unsigned long pfn, unsigned level)
 {
 	struct page *page = pfn_to_page(pfn);
 
@@ -846,8 +864,8 @@
 		SetPagePinned(page);
 
 		if (!PageHighMem(page)) {
-			make_lowmem_page_readonly(__va(PFN_PHYS(pfn)));
-			if (level == PT_PTE)
+			make_lowmem_page_readonly(__va(PFN_PHYS((unsigned long)pfn)));
+			if (level == PT_PTE && USE_SPLIT_PTLOCKS)
 				pin_pagetable_pfn(MMUEXT_PIN_L1_TABLE, pfn);
 		} else
 			/* make sure there are no stray mappings of
@@ -856,12 +874,12 @@
 	}
 }
 
-static void xen_alloc_pte(struct mm_struct *mm, u32 pfn)
+static void xen_alloc_pte(struct mm_struct *mm, unsigned long pfn)
 {
 	xen_alloc_ptpage(mm, pfn, PT_PTE);
 }
 
-static void xen_alloc_pmd(struct mm_struct *mm, u32 pfn)
+static void xen_alloc_pmd(struct mm_struct *mm, unsigned long pfn)
 {
 	xen_alloc_ptpage(mm, pfn, PT_PMD);
 }
@@ -909,13 +927,13 @@
 }
 
 /* This should never happen until we're OK to use struct page */
-static void xen_release_ptpage(u32 pfn, unsigned level)
+static void xen_release_ptpage(unsigned long pfn, unsigned level)
 {
 	struct page *page = pfn_to_page(pfn);
 
 	if (PagePinned(page)) {
 		if (!PageHighMem(page)) {
-			if (level == PT_PTE)
+			if (level == PT_PTE && USE_SPLIT_PTLOCKS)
 				pin_pagetable_pfn(MMUEXT_UNPIN_TABLE, pfn);
 			make_lowmem_page_readwrite(__va(PFN_PHYS(pfn)));
 		}
@@ -923,23 +941,23 @@
 	}
 }
 
-static void xen_release_pte(u32 pfn)
+static void xen_release_pte(unsigned long pfn)
 {
 	xen_release_ptpage(pfn, PT_PTE);
 }
 
-static void xen_release_pmd(u32 pfn)
+static void xen_release_pmd(unsigned long pfn)
 {
 	xen_release_ptpage(pfn, PT_PMD);
 }
 
 #if PAGETABLE_LEVELS == 4
-static void xen_alloc_pud(struct mm_struct *mm, u32 pfn)
+static void xen_alloc_pud(struct mm_struct *mm, unsigned long pfn)
 {
 	xen_alloc_ptpage(mm, pfn, PT_PUD);
 }
 
-static void xen_release_pud(u32 pfn)
+static void xen_release_pud(unsigned long pfn)
 {
 	xen_release_ptpage(pfn, PT_PUD);
 }
@@ -962,6 +980,7 @@
 }
 #endif
 
+#ifdef CONFIG_X86_32
 static __init pte_t mask_rw_pte(pte_t *ptep, pte_t pte)
 {
 	/* If there's an existing pte, then don't allow _PAGE_RW to be set */
@@ -980,6 +999,7 @@
 
 	xen_set_pte(ptep, pte);
 }
+#endif
 
 static __init void xen_pagetable_setup_start(pgd_t *base)
 {
@@ -1046,7 +1066,6 @@
 
 	/* xen_vcpu_setup managed to place the vcpu_info within the
 	   percpu area for all cpus, so make use of it */
-#ifdef CONFIG_X86_32
 	if (have_vcpu_info_placement) {
 		printk(KERN_INFO "Xen: using vcpu_info placement\n");
 
@@ -1056,7 +1075,6 @@
 		pv_irq_ops.irq_enable = xen_irq_enable_direct;
 		pv_mmu_ops.read_cr2 = xen_read_cr2_direct;
 	}
-#endif
 }
 
 static unsigned xen_patch(u8 type, u16 clobbers, void *insnbuf,
@@ -1077,12 +1095,10 @@
 	goto patch_site
 
 	switch (type) {
-#ifdef CONFIG_X86_32
 		SITE(pv_irq_ops, irq_enable);
 		SITE(pv_irq_ops, irq_disable);
 		SITE(pv_irq_ops, save_fl);
 		SITE(pv_irq_ops, restore_fl);
-#endif /* CONFIG_X86_32 */
 #undef SITE
 
 	patch_site:
@@ -1220,6 +1236,9 @@
 	.load_gs_index = xen_load_gs_index,
 #endif
 
+	.alloc_ldt = xen_alloc_ldt,
+	.free_ldt = xen_free_ldt,
+
 	.store_gdt = native_store_gdt,
 	.store_idt = native_store_idt,
 	.store_tr = xen_store_tr,
@@ -1241,40 +1260,8 @@
 	},
 };
 
-static void __init __xen_init_IRQ(void)
-{
-#ifdef CONFIG_X86_64
-	int i;
-
-	/* Create identity vector->irq map */
-	for(i = 0; i < NR_VECTORS; i++) {
-		int cpu;
-
-		for_each_possible_cpu(cpu)
-			per_cpu(vector_irq, cpu)[i] = i;
-	}
-#endif	/* CONFIG_X86_64 */
-
-	xen_init_IRQ();
-}
-
-static const struct pv_irq_ops xen_irq_ops __initdata = {
-	.init_IRQ = __xen_init_IRQ,
-	.save_fl = xen_save_fl,
-	.restore_fl = xen_restore_fl,
-	.irq_disable = xen_irq_disable,
-	.irq_enable = xen_irq_enable,
-	.safe_halt = xen_safe_halt,
-	.halt = xen_halt,
-#ifdef CONFIG_X86_64
-	.adjust_exception_frame = xen_adjust_exception_frame,
-#endif
-};
-
 static const struct pv_apic_ops xen_apic_ops __initdata = {
 #ifdef CONFIG_X86_LOCAL_APIC
-	.apic_write = xen_apic_write,
-	.apic_read = xen_apic_read,
 	.setup_boot_clock = paravirt_nop,
 	.setup_secondary_clock = paravirt_nop,
 	.startup_ipi_hook = paravirt_nop,
@@ -1413,7 +1400,7 @@
 	if (HYPERVISOR_xen_version(XENVER_platform_parameters, &pp) == 0)
 		top = pp.virt_start;
 
-	reserve_top_address(-top + 2 * PAGE_SIZE);
+	reserve_top_address(-top);
 #endif	/* CONFIG_X86_32 */
 }
 
@@ -1447,48 +1434,11 @@
 	return __ka(m2p(maddr));
 }
 
-#ifdef CONFIG_X86_64
-static void walk(pgd_t *pgd, unsigned long addr)
-{
-	unsigned l4idx = pgd_index(addr);
-	unsigned l3idx = pud_index(addr);
-	unsigned l2idx = pmd_index(addr);
-	unsigned l1idx = pte_index(addr);
-	pgd_t l4;
-	pud_t l3;
-	pmd_t l2;
-	pte_t l1;
-
-	xen_raw_printk("walk %p, %lx -> %d %d %d %d\n",
-		       pgd, addr, l4idx, l3idx, l2idx, l1idx);
-
-	l4 = pgd[l4idx];
-	xen_raw_printk("  l4: %016lx\n", l4.pgd);
-	xen_raw_printk("      %016lx\n", pgd_val(l4));
-
-	l3 = ((pud_t *)(m2v(l4.pgd)))[l3idx];
-	xen_raw_printk("  l3: %016lx\n", l3.pud);
-	xen_raw_printk("      %016lx\n", pud_val(l3));
-
-	l2 = ((pmd_t *)(m2v(l3.pud)))[l2idx];
-	xen_raw_printk("  l2: %016lx\n", l2.pmd);
-	xen_raw_printk("      %016lx\n", pmd_val(l2));
-
-	l1 = ((pte_t *)(m2v(l2.pmd)))[l1idx];
-	xen_raw_printk("  l1: %016lx\n", l1.pte);
-	xen_raw_printk("      %016lx\n", pte_val(l1));
-}
-#endif
-
 static void set_page_prot(void *addr, pgprot_t prot)
 {
 	unsigned long pfn = __pa(addr) >> PAGE_SHIFT;
 	pte_t pte = pfn_pte(pfn, prot);
 
-	xen_raw_printk("addr=%p pfn=%lx mfn=%lx prot=%016llx pte=%016llx\n",
-		       addr, pfn, get_phys_to_machine(pfn),
-		       pgprot_val(prot), pte.pte);
-
 	if (HYPERVISOR_update_va_mapping((unsigned long)addr, pte, 0))
 		BUG();
 }
@@ -1664,6 +1614,8 @@
 	if (!xen_start_info)
 		return;
 
+	xen_domain_type = XEN_PV_DOMAIN;
+
 	BUG_ON(memcmp(xen_start_info->magic, "xen-3", 5) != 0);
 
 	xen_setup_features();
@@ -1673,10 +1625,18 @@
 	pv_init_ops = xen_init_ops;
 	pv_time_ops = xen_time_ops;
 	pv_cpu_ops = xen_cpu_ops;
-	pv_irq_ops = xen_irq_ops;
 	pv_apic_ops = xen_apic_ops;
 	pv_mmu_ops = xen_mmu_ops;
 
+	xen_init_irq_ops();
+
+#ifdef CONFIG_X86_LOCAL_APIC
+	/*
+	 * set up the basic apic ops.
+	 */
+	apic_ops = &xen_basic_apic_ops;
+#endif
+
 	if (xen_feature(XENFEAT_mmu_pt_update_preserve_ad)) {
 		pv_mmu_ops.ptep_modify_prot_start = xen_ptep_modify_prot_start;
 		pv_mmu_ops.ptep_modify_prot_commit = xen_ptep_modify_prot_commit;
@@ -1700,7 +1660,7 @@
 
 	/* Prevent unwanted bits from being set in PTEs. */
 	__supported_pte_mask &= ~_PAGE_GLOBAL;
-	if (!is_initial_xendomain())
+	if (!xen_initial_domain())
 		__supported_pte_mask &= ~(_PAGE_PWT | _PAGE_PCD);
 
 	/* Don't do the full vcpu_info placement stuff until we have a
@@ -1735,7 +1695,7 @@
 	boot_params.hdr.ramdisk_size = xen_start_info->mod_len;
 	boot_params.hdr.cmd_line_ptr = __pa(xen_start_info->cmd_line);
 
-	if (!is_initial_xendomain()) {
+	if (!xen_initial_domain()) {
 		add_preferred_console("xenboot", 0, NULL);
 		add_preferred_console("tty", 0, NULL);
 		add_preferred_console("hvc", 0, NULL);
@@ -1743,15 +1703,6 @@
 
 	xen_raw_console_write("about to get started...\n");
 
-#if 0
-	xen_raw_printk("&boot_params=%p __pa(&boot_params)=%lx __va(__pa(&boot_params))=%lx\n",
-		       &boot_params, __pa_symbol(&boot_params),
-		       __va(__pa_symbol(&boot_params)));
-
-	walk(pgd, &boot_params);
-	walk(pgd, __va(__pa(&boot_params)));
-#endif
-
 	/* Start the world */
 #ifdef CONFIG_X86_32
 	i386_start_kernel();
diff --git a/arch/x86/xen/irq.c b/arch/x86/xen/irq.c
new file mode 100644
index 0000000..28b85ab
--- /dev/null
+++ b/arch/x86/xen/irq.c
@@ -0,0 +1,143 @@
+#include <linux/hardirq.h>
+
+#include <xen/interface/xen.h>
+#include <xen/interface/sched.h>
+#include <xen/interface/vcpu.h>
+
+#include <asm/xen/hypercall.h>
+#include <asm/xen/hypervisor.h>
+
+#include "xen-ops.h"
+
+/*
+ * Force a proper event-channel callback from Xen after clearing the
+ * callback mask. We do this in a very simple manner, by making a call
+ * down into Xen. The pending flag will be checked by Xen on return.
+ */
+void xen_force_evtchn_callback(void)
+{
+	(void)HYPERVISOR_xen_version(0, NULL);
+}
+
+static void __init __xen_init_IRQ(void)
+{
+#ifdef CONFIG_X86_64
+	int i;
+
+	/* Create identity vector->irq map */
+	for(i = 0; i < NR_VECTORS; i++) {
+		int cpu;
+
+		for_each_possible_cpu(cpu)
+			per_cpu(vector_irq, cpu)[i] = i;
+	}
+#endif	/* CONFIG_X86_64 */
+
+	xen_init_IRQ();
+}
+
+static unsigned long xen_save_fl(void)
+{
+	struct vcpu_info *vcpu;
+	unsigned long flags;
+
+	vcpu = x86_read_percpu(xen_vcpu);
+
+	/* flag has opposite sense of mask */
+	flags = !vcpu->evtchn_upcall_mask;
+
+	/* convert to IF type flag
+	   -0 -> 0x00000000
+	   -1 -> 0xffffffff
+	*/
+	return (-flags) & X86_EFLAGS_IF;
+}
+
+static void xen_restore_fl(unsigned long flags)
+{
+	struct vcpu_info *vcpu;
+
+	/* convert from IF type flag */
+	flags = !(flags & X86_EFLAGS_IF);
+
+	/* There's a one instruction preempt window here.  We need to
+	   make sure we're don't switch CPUs between getting the vcpu
+	   pointer and updating the mask. */
+	preempt_disable();
+	vcpu = x86_read_percpu(xen_vcpu);
+	vcpu->evtchn_upcall_mask = flags;
+	preempt_enable_no_resched();
+
+	/* Doesn't matter if we get preempted here, because any
+	   pending event will get dealt with anyway. */
+
+	if (flags == 0) {
+		preempt_check_resched();
+		barrier(); /* unmask then check (avoid races) */
+		if (unlikely(vcpu->evtchn_upcall_pending))
+			xen_force_evtchn_callback();
+	}
+}
+
+static void xen_irq_disable(void)
+{
+	/* There's a one instruction preempt window here.  We need to
+	   make sure we're don't switch CPUs between getting the vcpu
+	   pointer and updating the mask. */
+	preempt_disable();
+	x86_read_percpu(xen_vcpu)->evtchn_upcall_mask = 1;
+	preempt_enable_no_resched();
+}
+
+static void xen_irq_enable(void)
+{
+	struct vcpu_info *vcpu;
+
+	/* We don't need to worry about being preempted here, since
+	   either a) interrupts are disabled, so no preemption, or b)
+	   the caller is confused and is trying to re-enable interrupts
+	   on an indeterminate processor. */
+
+	vcpu = x86_read_percpu(xen_vcpu);
+	vcpu->evtchn_upcall_mask = 0;
+
+	/* Doesn't matter if we get preempted here, because any
+	   pending event will get dealt with anyway. */
+
+	barrier(); /* unmask then check (avoid races) */
+	if (unlikely(vcpu->evtchn_upcall_pending))
+		xen_force_evtchn_callback();
+}
+
+static void xen_safe_halt(void)
+{
+	/* Blocking includes an implicit local_irq_enable(). */
+	if (HYPERVISOR_sched_op(SCHEDOP_block, NULL) != 0)
+		BUG();
+}
+
+static void xen_halt(void)
+{
+	if (irqs_disabled())
+		HYPERVISOR_vcpu_op(VCPUOP_down, smp_processor_id(), NULL);
+	else
+		xen_safe_halt();
+}
+
+static const struct pv_irq_ops xen_irq_ops __initdata = {
+	.init_IRQ = __xen_init_IRQ,
+	.save_fl = xen_save_fl,
+	.restore_fl = xen_restore_fl,
+	.irq_disable = xen_irq_disable,
+	.irq_enable = xen_irq_enable,
+	.safe_halt = xen_safe_halt,
+	.halt = xen_halt,
+#ifdef CONFIG_X86_64
+	.adjust_exception_frame = xen_adjust_exception_frame,
+#endif
+};
+
+void __init xen_init_irq_ops()
+{
+	pv_irq_ops = xen_irq_ops;
+}
diff --git a/arch/x86/xen/mmu.c b/arch/x86/xen/mmu.c
index aa37469..ae173f6 100644
--- a/arch/x86/xen/mmu.c
+++ b/arch/x86/xen/mmu.c
@@ -40,6 +40,7 @@
  */
 #include <linux/sched.h>
 #include <linux/highmem.h>
+#include <linux/debugfs.h>
 #include <linux/bug.h>
 
 #include <asm/pgtable.h>
@@ -57,6 +58,61 @@
 
 #include "multicalls.h"
 #include "mmu.h"
+#include "debugfs.h"
+
+#define MMU_UPDATE_HISTO	30
+
+#ifdef CONFIG_XEN_DEBUG_FS
+
+static struct {
+	u32 pgd_update;
+	u32 pgd_update_pinned;
+	u32 pgd_update_batched;
+
+	u32 pud_update;
+	u32 pud_update_pinned;
+	u32 pud_update_batched;
+
+	u32 pmd_update;
+	u32 pmd_update_pinned;
+	u32 pmd_update_batched;
+
+	u32 pte_update;
+	u32 pte_update_pinned;
+	u32 pte_update_batched;
+
+	u32 mmu_update;
+	u32 mmu_update_extended;
+	u32 mmu_update_histo[MMU_UPDATE_HISTO];
+
+	u32 prot_commit;
+	u32 prot_commit_batched;
+
+	u32 set_pte_at;
+	u32 set_pte_at_batched;
+	u32 set_pte_at_pinned;
+	u32 set_pte_at_current;
+	u32 set_pte_at_kernel;
+} mmu_stats;
+
+static u8 zero_stats;
+
+static inline void check_zero(void)
+{
+	if (unlikely(zero_stats)) {
+		memset(&mmu_stats, 0, sizeof(mmu_stats));
+		zero_stats = 0;
+	}
+}
+
+#define ADD_STATS(elem, val)			\
+	do { check_zero(); mmu_stats.elem += (val); } while(0)
+
+#else  /* !CONFIG_XEN_DEBUG_FS */
+
+#define ADD_STATS(elem, val)	do { (void)(val); } while(0)
+
+#endif /* CONFIG_XEN_DEBUG_FS */
 
 /*
  * Just beyond the highest usermode address.  STACK_TOP_MAX has a
@@ -229,25 +285,35 @@
 }
 
 
-static bool page_pinned(void *ptr)
+static bool xen_page_pinned(void *ptr)
 {
 	struct page *page = virt_to_page(ptr);
 
 	return PagePinned(page);
 }
 
-static void extend_mmu_update(const struct mmu_update *update)
+static void xen_extend_mmu_update(const struct mmu_update *update)
 {
 	struct multicall_space mcs;
 	struct mmu_update *u;
 
 	mcs = xen_mc_extend_args(__HYPERVISOR_mmu_update, sizeof(*u));
 
-	if (mcs.mc != NULL)
+	if (mcs.mc != NULL) {
+		ADD_STATS(mmu_update_extended, 1);
+		ADD_STATS(mmu_update_histo[mcs.mc->args[1]], -1);
+
 		mcs.mc->args[1]++;
-	else {
+
+		if (mcs.mc->args[1] < MMU_UPDATE_HISTO)
+			ADD_STATS(mmu_update_histo[mcs.mc->args[1]], 1);
+		else
+			ADD_STATS(mmu_update_histo[0], 1);
+	} else {
+		ADD_STATS(mmu_update, 1);
 		mcs = __xen_mc_entry(sizeof(*u));
 		MULTI_mmu_update(mcs.mc, mcs.args, 1, NULL, DOMID_SELF);
+		ADD_STATS(mmu_update_histo[1], 1);
 	}
 
 	u = mcs.args;
@@ -265,7 +331,9 @@
 	/* ptr may be ioremapped for 64-bit pagetable setup */
 	u.ptr = arbitrary_virt_to_machine(ptr).maddr;
 	u.val = pmd_val_ma(val);
-	extend_mmu_update(&u);
+	xen_extend_mmu_update(&u);
+
+	ADD_STATS(pmd_update_batched, paravirt_get_lazy_mode() == PARAVIRT_LAZY_MMU);
 
 	xen_mc_issue(PARAVIRT_LAZY_MMU);
 
@@ -274,13 +342,17 @@
 
 void xen_set_pmd(pmd_t *ptr, pmd_t val)
 {
+	ADD_STATS(pmd_update, 1);
+
 	/* If page is not pinned, we can just update the entry
 	   directly */
-	if (!page_pinned(ptr)) {
+	if (!xen_page_pinned(ptr)) {
 		*ptr = val;
 		return;
 	}
 
+	ADD_STATS(pmd_update_pinned, 1);
+
 	xen_set_pmd_hyper(ptr, val);
 }
 
@@ -300,12 +372,18 @@
 	if (mm == &init_mm)
 		preempt_disable();
 
+	ADD_STATS(set_pte_at, 1);
+//	ADD_STATS(set_pte_at_pinned, xen_page_pinned(ptep));
+	ADD_STATS(set_pte_at_current, mm == current->mm);
+	ADD_STATS(set_pte_at_kernel, mm == &init_mm);
+
 	if (mm == current->mm || mm == &init_mm) {
 		if (paravirt_get_lazy_mode() == PARAVIRT_LAZY_MMU) {
 			struct multicall_space mcs;
 			mcs = xen_mc_entry(0);
 
 			MULTI_update_va_mapping(mcs.mc, addr, pteval, 0);
+			ADD_STATS(set_pte_at_batched, 1);
 			xen_mc_issue(PARAVIRT_LAZY_MMU);
 			goto out;
 		} else
@@ -334,7 +412,10 @@
 
 	u.ptr = virt_to_machine(ptep).maddr | MMU_PT_UPDATE_PRESERVE_AD;
 	u.val = pte_val_ma(pte);
-	extend_mmu_update(&u);
+	xen_extend_mmu_update(&u);
+
+	ADD_STATS(prot_commit, 1);
+	ADD_STATS(prot_commit_batched, paravirt_get_lazy_mode() == PARAVIRT_LAZY_MMU);
 
 	xen_mc_issue(PARAVIRT_LAZY_MMU);
 }
@@ -400,7 +481,9 @@
 	/* ptr may be ioremapped for 64-bit pagetable setup */
 	u.ptr = arbitrary_virt_to_machine(ptr).maddr;
 	u.val = pud_val_ma(val);
-	extend_mmu_update(&u);
+	xen_extend_mmu_update(&u);
+
+	ADD_STATS(pud_update_batched, paravirt_get_lazy_mode() == PARAVIRT_LAZY_MMU);
 
 	xen_mc_issue(PARAVIRT_LAZY_MMU);
 
@@ -409,18 +492,26 @@
 
 void xen_set_pud(pud_t *ptr, pud_t val)
 {
+	ADD_STATS(pud_update, 1);
+
 	/* If page is not pinned, we can just update the entry
 	   directly */
-	if (!page_pinned(ptr)) {
+	if (!xen_page_pinned(ptr)) {
 		*ptr = val;
 		return;
 	}
 
+	ADD_STATS(pud_update_pinned, 1);
+
 	xen_set_pud_hyper(ptr, val);
 }
 
 void xen_set_pte(pte_t *ptep, pte_t pte)
 {
+	ADD_STATS(pte_update, 1);
+//	ADD_STATS(pte_update_pinned, xen_page_pinned(ptep));
+	ADD_STATS(pte_update_batched, paravirt_get_lazy_mode() == PARAVIRT_LAZY_MMU);
+
 #ifdef CONFIG_X86_PAE
 	ptep->pte_high = pte.pte_high;
 	smp_wmb();
@@ -490,7 +581,7 @@
 
 	u.ptr = virt_to_machine(ptr).maddr;
 	u.val = pgd_val_ma(val);
-	extend_mmu_update(&u);
+	xen_extend_mmu_update(&u);
 }
 
 /*
@@ -517,17 +608,22 @@
 {
 	pgd_t *user_ptr = xen_get_user_pgd(ptr);
 
+	ADD_STATS(pgd_update, 1);
+
 	/* If page is not pinned, we can just update the entry
 	   directly */
-	if (!page_pinned(ptr)) {
+	if (!xen_page_pinned(ptr)) {
 		*ptr = val;
 		if (user_ptr) {
-			WARN_ON(page_pinned(user_ptr));
+			WARN_ON(xen_page_pinned(user_ptr));
 			*user_ptr = val;
 		}
 		return;
 	}
 
+	ADD_STATS(pgd_update_pinned, 1);
+	ADD_STATS(pgd_update_batched, paravirt_get_lazy_mode() == PARAVIRT_LAZY_MMU);
+
 	/* If it's pinned, then we can at least batch the kernel and
 	   user updates together. */
 	xen_mc_batch();
@@ -555,9 +651,12 @@
  * For 64-bit, we must skip the Xen hole in the middle of the address
  * space, just after the big x86-64 virtual hole.
  */
-static int pgd_walk(pgd_t *pgd, int (*func)(struct page *, enum pt_level),
-		    unsigned long limit)
+static int xen_pgd_walk(struct mm_struct *mm,
+			int (*func)(struct mm_struct *mm, struct page *,
+				    enum pt_level),
+			unsigned long limit)
 {
+	pgd_t *pgd = mm->pgd;
 	int flush = 0;
 	unsigned hole_low, hole_high;
 	unsigned pgdidx_limit, pudidx_limit, pmdidx_limit;
@@ -590,8 +689,6 @@
 	pmdidx_limit = 0;
 #endif
 
-	flush |= (*func)(virt_to_page(pgd), PT_PGD);
-
 	for (pgdidx = 0; pgdidx <= pgdidx_limit; pgdidx++) {
 		pud_t *pud;
 
@@ -604,7 +701,7 @@
 		pud = pud_offset(&pgd[pgdidx], 0);
 
 		if (PTRS_PER_PUD > 1) /* not folded */
-			flush |= (*func)(virt_to_page(pud), PT_PUD);
+			flush |= (*func)(mm, virt_to_page(pud), PT_PUD);
 
 		for (pudidx = 0; pudidx < PTRS_PER_PUD; pudidx++) {
 			pmd_t *pmd;
@@ -619,7 +716,7 @@
 			pmd = pmd_offset(&pud[pudidx], 0);
 
 			if (PTRS_PER_PMD > 1) /* not folded */
-				flush |= (*func)(virt_to_page(pmd), PT_PMD);
+				flush |= (*func)(mm, virt_to_page(pmd), PT_PMD);
 
 			for (pmdidx = 0; pmdidx < PTRS_PER_PMD; pmdidx++) {
 				struct page *pte;
@@ -633,28 +730,34 @@
 					continue;
 
 				pte = pmd_page(pmd[pmdidx]);
-				flush |= (*func)(pte, PT_PTE);
+				flush |= (*func)(mm, pte, PT_PTE);
 			}
 		}
 	}
+
 out:
+	/* Do the top level last, so that the callbacks can use it as
+	   a cue to do final things like tlb flushes. */
+	flush |= (*func)(mm, virt_to_page(pgd), PT_PGD);
 
 	return flush;
 }
 
-static spinlock_t *lock_pte(struct page *page)
+/* If we're using split pte locks, then take the page's lock and
+   return a pointer to it.  Otherwise return NULL. */
+static spinlock_t *xen_pte_lock(struct page *page, struct mm_struct *mm)
 {
 	spinlock_t *ptl = NULL;
 
-#if NR_CPUS >= CONFIG_SPLIT_PTLOCK_CPUS
+#if USE_SPLIT_PTLOCKS
 	ptl = __pte_lockptr(page);
-	spin_lock(ptl);
+	spin_lock_nest_lock(ptl, &mm->page_table_lock);
 #endif
 
 	return ptl;
 }
 
-static void do_unlock(void *v)
+static void xen_pte_unlock(void *v)
 {
 	spinlock_t *ptl = v;
 	spin_unlock(ptl);
@@ -672,7 +775,8 @@
 	MULTI_mmuext_op(mcs.mc, op, 1, NULL, DOMID_SELF);
 }
 
-static int pin_page(struct page *page, enum pt_level level)
+static int xen_pin_page(struct mm_struct *mm, struct page *page,
+			enum pt_level level)
 {
 	unsigned pgfl = TestSetPagePinned(page);
 	int flush;
@@ -691,21 +795,40 @@
 
 		flush = 0;
 
+		/*
+		 * We need to hold the pagetable lock between the time
+		 * we make the pagetable RO and when we actually pin
+		 * it.  If we don't, then other users may come in and
+		 * attempt to update the pagetable by writing it,
+		 * which will fail because the memory is RO but not
+		 * pinned, so Xen won't do the trap'n'emulate.
+		 *
+		 * If we're using split pte locks, we can't hold the
+		 * entire pagetable's worth of locks during the
+		 * traverse, because we may wrap the preempt count (8
+		 * bits).  The solution is to mark RO and pin each PTE
+		 * page while holding the lock.  This means the number
+		 * of locks we end up holding is never more than a
+		 * batch size (~32 entries, at present).
+		 *
+		 * If we're not using split pte locks, we needn't pin
+		 * the PTE pages independently, because we're
+		 * protected by the overall pagetable lock.
+		 */
 		ptl = NULL;
 		if (level == PT_PTE)
-			ptl = lock_pte(page);
+			ptl = xen_pte_lock(page, mm);
 
 		MULTI_update_va_mapping(mcs.mc, (unsigned long)pt,
 					pfn_pte(pfn, PAGE_KERNEL_RO),
 					level == PT_PGD ? UVMF_TLB_FLUSH : 0);
 
-		if (level == PT_PTE)
+		if (ptl) {
 			xen_do_pin(MMUEXT_PIN_L1_TABLE, pfn);
 
-		if (ptl) {
 			/* Queue a deferred unlock for when this batch
 			   is completed. */
-			xen_mc_callback(do_unlock, ptl);
+			xen_mc_callback(xen_pte_unlock, ptl);
 		}
 	}
 
@@ -715,11 +838,11 @@
 /* This is called just after a mm has been created, but it has not
    been used yet.  We need to make sure that its pagetable is all
    read-only, and can be pinned. */
-void xen_pgd_pin(pgd_t *pgd)
+static void __xen_pgd_pin(struct mm_struct *mm, pgd_t *pgd)
 {
 	xen_mc_batch();
 
-	if (pgd_walk(pgd, pin_page, USER_LIMIT)) {
+	if (xen_pgd_walk(mm, xen_pin_page, USER_LIMIT)) {
 		/* re-enable interrupts for kmap_flush_unused */
 		xen_mc_issue(0);
 		kmap_flush_unused();
@@ -733,25 +856,35 @@
 		xen_do_pin(MMUEXT_PIN_L4_TABLE, PFN_DOWN(__pa(pgd)));
 
 		if (user_pgd) {
-			pin_page(virt_to_page(user_pgd), PT_PGD);
+			xen_pin_page(mm, virt_to_page(user_pgd), PT_PGD);
 			xen_do_pin(MMUEXT_PIN_L4_TABLE, PFN_DOWN(__pa(user_pgd)));
 		}
 	}
 #else /* CONFIG_X86_32 */
 #ifdef CONFIG_X86_PAE
 	/* Need to make sure unshared kernel PMD is pinnable */
-	pin_page(virt_to_page(pgd_page(pgd[pgd_index(TASK_SIZE)])), PT_PMD);
+	xen_pin_page(mm, virt_to_page(pgd_page(pgd[pgd_index(TASK_SIZE)])),
+		     PT_PMD);
 #endif
 	xen_do_pin(MMUEXT_PIN_L3_TABLE, PFN_DOWN(__pa(pgd)));
 #endif /* CONFIG_X86_64 */
 	xen_mc_issue(0);
 }
 
+static void xen_pgd_pin(struct mm_struct *mm)
+{
+	__xen_pgd_pin(mm, mm->pgd);
+}
+
 /*
  * On save, we need to pin all pagetables to make sure they get their
  * mfns turned into pfns.  Search the list for any unpinned pgds and pin
  * them (unpinned pgds are not currently in use, probably because the
  * process is under construction or destruction).
+ *
+ * Expected to be called in stop_machine() ("equivalent to taking
+ * every spinlock in the system"), so the locking doesn't really
+ * matter all that much.
  */
 void xen_mm_pin_all(void)
 {
@@ -762,7 +895,7 @@
 
 	list_for_each_entry(page, &pgd_list, lru) {
 		if (!PagePinned(page)) {
-			xen_pgd_pin((pgd_t *)page_address(page));
+			__xen_pgd_pin(&init_mm, (pgd_t *)page_address(page));
 			SetPageSavePinned(page);
 		}
 	}
@@ -775,7 +908,8 @@
  * that's before we have page structures to store the bits.  So do all
  * the book-keeping now.
  */
-static __init int mark_pinned(struct page *page, enum pt_level level)
+static __init int xen_mark_pinned(struct mm_struct *mm, struct page *page,
+				  enum pt_level level)
 {
 	SetPagePinned(page);
 	return 0;
@@ -783,10 +917,11 @@
 
 void __init xen_mark_init_mm_pinned(void)
 {
-	pgd_walk(init_mm.pgd, mark_pinned, FIXADDR_TOP);
+	xen_pgd_walk(&init_mm, xen_mark_pinned, FIXADDR_TOP);
 }
 
-static int unpin_page(struct page *page, enum pt_level level)
+static int xen_unpin_page(struct mm_struct *mm, struct page *page,
+			  enum pt_level level)
 {
 	unsigned pgfl = TestClearPagePinned(page);
 
@@ -796,10 +931,18 @@
 		spinlock_t *ptl = NULL;
 		struct multicall_space mcs;
 
+		/*
+		 * Do the converse to pin_page.  If we're using split
+		 * pte locks, we must be holding the lock for while
+		 * the pte page is unpinned but still RO to prevent
+		 * concurrent updates from seeing it in this
+		 * partially-pinned state.
+		 */
 		if (level == PT_PTE) {
-			ptl = lock_pte(page);
+			ptl = xen_pte_lock(page, mm);
 
-			xen_do_pin(MMUEXT_UNPIN_TABLE, pfn);
+			if (ptl)
+				xen_do_pin(MMUEXT_UNPIN_TABLE, pfn);
 		}
 
 		mcs = __xen_mc_entry(0);
@@ -810,7 +953,7 @@
 
 		if (ptl) {
 			/* unlock when batch completed */
-			xen_mc_callback(do_unlock, ptl);
+			xen_mc_callback(xen_pte_unlock, ptl);
 		}
 	}
 
@@ -818,7 +961,7 @@
 }
 
 /* Release a pagetables pages back as normal RW */
-static void xen_pgd_unpin(pgd_t *pgd)
+static void __xen_pgd_unpin(struct mm_struct *mm, pgd_t *pgd)
 {
 	xen_mc_batch();
 
@@ -830,21 +973,27 @@
 
 		if (user_pgd) {
 			xen_do_pin(MMUEXT_UNPIN_TABLE, PFN_DOWN(__pa(user_pgd)));
-			unpin_page(virt_to_page(user_pgd), PT_PGD);
+			xen_unpin_page(mm, virt_to_page(user_pgd), PT_PGD);
 		}
 	}
 #endif
 
 #ifdef CONFIG_X86_PAE
 	/* Need to make sure unshared kernel PMD is unpinned */
-	pin_page(virt_to_page(pgd_page(pgd[pgd_index(TASK_SIZE)])), PT_PMD);
+	xen_unpin_page(mm, virt_to_page(pgd_page(pgd[pgd_index(TASK_SIZE)])),
+		       PT_PMD);
 #endif
 
-	pgd_walk(pgd, unpin_page, USER_LIMIT);
+	xen_pgd_walk(mm, xen_unpin_page, USER_LIMIT);
 
 	xen_mc_issue(0);
 }
 
+static void xen_pgd_unpin(struct mm_struct *mm)
+{
+	__xen_pgd_unpin(mm, mm->pgd);
+}
+
 /*
  * On resume, undo any pinning done at save, so that the rest of the
  * kernel doesn't see any unexpected pinned pagetables.
@@ -859,7 +1008,7 @@
 	list_for_each_entry(page, &pgd_list, lru) {
 		if (PageSavePinned(page)) {
 			BUG_ON(!PagePinned(page));
-			xen_pgd_unpin((pgd_t *)page_address(page));
+			__xen_pgd_unpin(&init_mm, (pgd_t *)page_address(page));
 			ClearPageSavePinned(page);
 		}
 	}
@@ -870,14 +1019,14 @@
 void xen_activate_mm(struct mm_struct *prev, struct mm_struct *next)
 {
 	spin_lock(&next->page_table_lock);
-	xen_pgd_pin(next->pgd);
+	xen_pgd_pin(next);
 	spin_unlock(&next->page_table_lock);
 }
 
 void xen_dup_mmap(struct mm_struct *oldmm, struct mm_struct *mm)
 {
 	spin_lock(&mm->page_table_lock);
-	xen_pgd_pin(mm->pgd);
+	xen_pgd_pin(mm);
 	spin_unlock(&mm->page_table_lock);
 }
 
@@ -907,7 +1056,7 @@
 	}
 }
 
-static void drop_mm_ref(struct mm_struct *mm)
+static void xen_drop_mm_ref(struct mm_struct *mm)
 {
 	cpumask_t mask;
 	unsigned cpu;
@@ -937,7 +1086,7 @@
 		smp_call_function_mask(mask, drop_other_mm_ref, mm, 1);
 }
 #else
-static void drop_mm_ref(struct mm_struct *mm)
+static void xen_drop_mm_ref(struct mm_struct *mm)
 {
 	if (current->active_mm == mm)
 		load_cr3(swapper_pg_dir);
@@ -961,14 +1110,77 @@
 void xen_exit_mmap(struct mm_struct *mm)
 {
 	get_cpu();		/* make sure we don't move around */
-	drop_mm_ref(mm);
+	xen_drop_mm_ref(mm);
 	put_cpu();
 
 	spin_lock(&mm->page_table_lock);
 
 	/* pgd may not be pinned in the error exit path of execve */
-	if (page_pinned(mm->pgd))
-		xen_pgd_unpin(mm->pgd);
+	if (xen_page_pinned(mm->pgd))
+		xen_pgd_unpin(mm);
 
 	spin_unlock(&mm->page_table_lock);
 }
+
+#ifdef CONFIG_XEN_DEBUG_FS
+
+static struct dentry *d_mmu_debug;
+
+static int __init xen_mmu_debugfs(void)
+{
+	struct dentry *d_xen = xen_init_debugfs();
+
+	if (d_xen == NULL)
+		return -ENOMEM;
+
+	d_mmu_debug = debugfs_create_dir("mmu", d_xen);
+
+	debugfs_create_u8("zero_stats", 0644, d_mmu_debug, &zero_stats);
+
+	debugfs_create_u32("pgd_update", 0444, d_mmu_debug, &mmu_stats.pgd_update);
+	debugfs_create_u32("pgd_update_pinned", 0444, d_mmu_debug,
+			   &mmu_stats.pgd_update_pinned);
+	debugfs_create_u32("pgd_update_batched", 0444, d_mmu_debug,
+			   &mmu_stats.pgd_update_pinned);
+
+	debugfs_create_u32("pud_update", 0444, d_mmu_debug, &mmu_stats.pud_update);
+	debugfs_create_u32("pud_update_pinned", 0444, d_mmu_debug,
+			   &mmu_stats.pud_update_pinned);
+	debugfs_create_u32("pud_update_batched", 0444, d_mmu_debug,
+			   &mmu_stats.pud_update_pinned);
+
+	debugfs_create_u32("pmd_update", 0444, d_mmu_debug, &mmu_stats.pmd_update);
+	debugfs_create_u32("pmd_update_pinned", 0444, d_mmu_debug,
+			   &mmu_stats.pmd_update_pinned);
+	debugfs_create_u32("pmd_update_batched", 0444, d_mmu_debug,
+			   &mmu_stats.pmd_update_pinned);
+
+	debugfs_create_u32("pte_update", 0444, d_mmu_debug, &mmu_stats.pte_update);
+//	debugfs_create_u32("pte_update_pinned", 0444, d_mmu_debug,
+//			   &mmu_stats.pte_update_pinned);
+	debugfs_create_u32("pte_update_batched", 0444, d_mmu_debug,
+			   &mmu_stats.pte_update_pinned);
+
+	debugfs_create_u32("mmu_update", 0444, d_mmu_debug, &mmu_stats.mmu_update);
+	debugfs_create_u32("mmu_update_extended", 0444, d_mmu_debug,
+			   &mmu_stats.mmu_update_extended);
+	xen_debugfs_create_u32_array("mmu_update_histo", 0444, d_mmu_debug,
+				     mmu_stats.mmu_update_histo, 20);
+
+	debugfs_create_u32("set_pte_at", 0444, d_mmu_debug, &mmu_stats.set_pte_at);
+	debugfs_create_u32("set_pte_at_batched", 0444, d_mmu_debug,
+			   &mmu_stats.set_pte_at_batched);
+	debugfs_create_u32("set_pte_at_current", 0444, d_mmu_debug,
+			   &mmu_stats.set_pte_at_current);
+	debugfs_create_u32("set_pte_at_kernel", 0444, d_mmu_debug,
+			   &mmu_stats.set_pte_at_kernel);
+
+	debugfs_create_u32("prot_commit", 0444, d_mmu_debug, &mmu_stats.prot_commit);
+	debugfs_create_u32("prot_commit_batched", 0444, d_mmu_debug,
+			   &mmu_stats.prot_commit_batched);
+
+	return 0;
+}
+fs_initcall(xen_mmu_debugfs);
+
+#endif	/* CONFIG_XEN_DEBUG_FS */
diff --git a/arch/x86/xen/mmu.h b/arch/x86/xen/mmu.h
index 0f59bd0..98d7165 100644
--- a/arch/x86/xen/mmu.h
+++ b/arch/x86/xen/mmu.h
@@ -18,9 +18,6 @@
 void xen_dup_mmap(struct mm_struct *oldmm, struct mm_struct *mm);
 void xen_exit_mmap(struct mm_struct *mm);
 
-void xen_pgd_pin(pgd_t *pgd);
-//void xen_pgd_unpin(pgd_t *pgd);
-
 pteval_t xen_pte_val(pte_t);
 pmdval_t xen_pmd_val(pmd_t);
 pgdval_t xen_pgd_val(pgd_t);
diff --git a/arch/x86/xen/multicalls.c b/arch/x86/xen/multicalls.c
index 9efd1c6..8ea8a0d 100644
--- a/arch/x86/xen/multicalls.c
+++ b/arch/x86/xen/multicalls.c
@@ -21,16 +21,20 @@
  */
 #include <linux/percpu.h>
 #include <linux/hardirq.h>
+#include <linux/debugfs.h>
 
 #include <asm/xen/hypercall.h>
 
 #include "multicalls.h"
+#include "debugfs.h"
+
+#define MC_BATCH	32
 
 #define MC_DEBUG	1
 
-#define MC_BATCH	32
 #define MC_ARGS		(MC_BATCH * 16)
 
+
 struct mc_buffer {
 	struct multicall_entry entries[MC_BATCH];
 #if MC_DEBUG
@@ -47,6 +51,76 @@
 static DEFINE_PER_CPU(struct mc_buffer, mc_buffer);
 DEFINE_PER_CPU(unsigned long, xen_mc_irq_flags);
 
+/* flush reasons 0- slots, 1- args, 2- callbacks */
+enum flush_reasons
+{
+	FL_SLOTS,
+	FL_ARGS,
+	FL_CALLBACKS,
+
+	FL_N_REASONS
+};
+
+#ifdef CONFIG_XEN_DEBUG_FS
+#define NHYPERCALLS	40		/* not really */
+
+static struct {
+	unsigned histo[MC_BATCH+1];
+
+	unsigned issued;
+	unsigned arg_total;
+	unsigned hypercalls;
+	unsigned histo_hypercalls[NHYPERCALLS];
+
+	unsigned flush[FL_N_REASONS];
+} mc_stats;
+
+static u8 zero_stats;
+
+static inline void check_zero(void)
+{
+	if (unlikely(zero_stats)) {
+		memset(&mc_stats, 0, sizeof(mc_stats));
+		zero_stats = 0;
+	}
+}
+
+static void mc_add_stats(const struct mc_buffer *mc)
+{
+	int i;
+
+	check_zero();
+
+	mc_stats.issued++;
+	mc_stats.hypercalls += mc->mcidx;
+	mc_stats.arg_total += mc->argidx;
+
+	mc_stats.histo[mc->mcidx]++;
+	for(i = 0; i < mc->mcidx; i++) {
+		unsigned op = mc->entries[i].op;
+		if (op < NHYPERCALLS)
+			mc_stats.histo_hypercalls[op]++;
+	}
+}
+
+static void mc_stats_flush(enum flush_reasons idx)
+{
+	check_zero();
+
+	mc_stats.flush[idx]++;
+}
+
+#else  /* !CONFIG_XEN_DEBUG_FS */
+
+static inline void mc_add_stats(const struct mc_buffer *mc)
+{
+}
+
+static inline void mc_stats_flush(enum flush_reasons idx)
+{
+}
+#endif	/* CONFIG_XEN_DEBUG_FS */
+
 void xen_mc_flush(void)
 {
 	struct mc_buffer *b = &__get_cpu_var(mc_buffer);
@@ -60,6 +134,8 @@
 	   something in the middle */
 	local_irq_save(flags);
 
+	mc_add_stats(b);
+
 	if (b->mcidx) {
 #if MC_DEBUG
 		memcpy(b->debug, b->entries,
@@ -115,6 +191,7 @@
 
 	if (b->mcidx == MC_BATCH ||
 	    (argidx + args) > MC_ARGS) {
+		mc_stats_flush(b->mcidx == MC_BATCH ? FL_SLOTS : FL_ARGS);
 		xen_mc_flush();
 		argidx = roundup(b->argidx, sizeof(u64));
 	}
@@ -158,10 +235,44 @@
 	struct mc_buffer *b = &__get_cpu_var(mc_buffer);
 	struct callback *cb;
 
-	if (b->cbidx == MC_BATCH)
+	if (b->cbidx == MC_BATCH) {
+		mc_stats_flush(FL_CALLBACKS);
 		xen_mc_flush();
+	}
 
 	cb = &b->callbacks[b->cbidx++];
 	cb->fn = fn;
 	cb->data = data;
 }
+
+#ifdef CONFIG_XEN_DEBUG_FS
+
+static struct dentry *d_mc_debug;
+
+static int __init xen_mc_debugfs(void)
+{
+	struct dentry *d_xen = xen_init_debugfs();
+
+	if (d_xen == NULL)
+		return -ENOMEM;
+
+	d_mc_debug = debugfs_create_dir("multicalls", d_xen);
+
+	debugfs_create_u8("zero_stats", 0644, d_mc_debug, &zero_stats);
+
+	debugfs_create_u32("batches", 0444, d_mc_debug, &mc_stats.issued);
+	debugfs_create_u32("hypercalls", 0444, d_mc_debug, &mc_stats.hypercalls);
+	debugfs_create_u32("arg_total", 0444, d_mc_debug, &mc_stats.arg_total);
+
+	xen_debugfs_create_u32_array("batch_histo", 0444, d_mc_debug,
+				     mc_stats.histo, MC_BATCH);
+	xen_debugfs_create_u32_array("hypercall_histo", 0444, d_mc_debug,
+				     mc_stats.histo_hypercalls, NHYPERCALLS);
+	xen_debugfs_create_u32_array("flush_reasons", 0444, d_mc_debug,
+				     mc_stats.flush, FL_N_REASONS);
+
+	return 0;
+}
+fs_initcall(xen_mc_debugfs);
+
+#endif	/* CONFIG_XEN_DEBUG_FS */
diff --git a/arch/x86/xen/setup.c b/arch/x86/xen/setup.c
index b6acc3a..d679010 100644
--- a/arch/x86/xen/setup.c
+++ b/arch/x86/xen/setup.c
@@ -42,7 +42,7 @@
 
 	e820.nr_map = 0;
 
-	e820_add_region(0, PFN_PHYS(max_pfn), E820_RAM);
+	e820_add_region(0, PFN_PHYS((u64)max_pfn), E820_RAM);
 
 	/*
 	 * Even though this is normal, usable memory under Xen, reserve
diff --git a/arch/x86/xen/smp.c b/arch/x86/xen/smp.c
index d8faf79..d77da61 100644
--- a/arch/x86/xen/smp.c
+++ b/arch/x86/xen/smp.c
@@ -11,11 +11,8 @@
  * useful topology information for the kernel to make use of.  As a
  * result, all CPUs are treated as if they're single-core and
  * single-threaded.
- *
- * This does not handle HOTPLUG_CPU yet.
  */
 #include <linux/sched.h>
-#include <linux/kernel_stat.h>
 #include <linux/err.h>
 #include <linux/smp.h>
 
@@ -36,8 +33,6 @@
 #include "xen-ops.h"
 #include "mmu.h"
 
-static void __cpuinit xen_init_lock_cpu(int cpu);
-
 cpumask_t xen_cpu_initialized_map;
 
 static DEFINE_PER_CPU(int, resched_irq);
@@ -64,11 +59,12 @@
 	return IRQ_HANDLED;
 }
 
-static __cpuinit void cpu_bringup_and_idle(void)
+static __cpuinit void cpu_bringup(void)
 {
 	int cpu = smp_processor_id();
 
 	cpu_init();
+	touch_softlockup_watchdog();
 	preempt_disable();
 
 	xen_enable_sysenter();
@@ -89,6 +85,11 @@
 	local_irq_enable();
 
 	wmb();			/* make sure everything is out */
+}
+
+static __cpuinit void cpu_bringup_and_idle(void)
+{
+	cpu_bringup();
 	cpu_idle();
 }
 
@@ -212,8 +213,6 @@
 
 		cpu_set(cpu, cpu_present_map);
 	}
-
-	//init_xenbus_allowed_cpumask();
 }
 
 static __cpuinit int
@@ -281,12 +280,6 @@
 	struct task_struct *idle = idle_task(cpu);
 	int rc;
 
-#if 0
-	rc = cpu_up_check(cpu);
-	if (rc)
-		return rc;
-#endif
-
 #ifdef CONFIG_X86_64
 	/* Allocate node local memory for AP pdas */
 	WARN_ON(cpu == 0);
@@ -339,6 +332,60 @@
 {
 }
 
+#ifdef CONFIG_HOTPLUG_CPU
+static int xen_cpu_disable(void)
+{
+	unsigned int cpu = smp_processor_id();
+	if (cpu == 0)
+		return -EBUSY;
+
+	cpu_disable_common();
+
+	load_cr3(swapper_pg_dir);
+	return 0;
+}
+
+static void xen_cpu_die(unsigned int cpu)
+{
+	while (HYPERVISOR_vcpu_op(VCPUOP_is_up, cpu, NULL)) {
+		current->state = TASK_UNINTERRUPTIBLE;
+		schedule_timeout(HZ/10);
+	}
+	unbind_from_irqhandler(per_cpu(resched_irq, cpu), NULL);
+	unbind_from_irqhandler(per_cpu(callfunc_irq, cpu), NULL);
+	unbind_from_irqhandler(per_cpu(debug_irq, cpu), NULL);
+	unbind_from_irqhandler(per_cpu(callfuncsingle_irq, cpu), NULL);
+	xen_uninit_lock_cpu(cpu);
+	xen_teardown_timer(cpu);
+
+	if (num_online_cpus() == 1)
+		alternatives_smp_switch(0);
+}
+
+static void xen_play_dead(void)
+{
+	play_dead_common();
+	HYPERVISOR_vcpu_op(VCPUOP_down, smp_processor_id(), NULL);
+	cpu_bringup();
+}
+
+#else /* !CONFIG_HOTPLUG_CPU */
+static int xen_cpu_disable(void)
+{
+	return -ENOSYS;
+}
+
+static void xen_cpu_die(unsigned int cpu)
+{
+	BUG();
+}
+
+static void xen_play_dead(void)
+{
+	BUG();
+}
+
+#endif
 static void stop_self(void *v)
 {
 	int cpu = smp_processor_id();
@@ -419,176 +466,16 @@
 	return IRQ_HANDLED;
 }
 
-struct xen_spinlock {
-	unsigned char lock;		/* 0 -> free; 1 -> locked */
-	unsigned short spinners;	/* count of waiting cpus */
-};
-
-static int xen_spin_is_locked(struct raw_spinlock *lock)
-{
-	struct xen_spinlock *xl = (struct xen_spinlock *)lock;
-
-	return xl->lock != 0;
-}
-
-static int xen_spin_is_contended(struct raw_spinlock *lock)
-{
-	struct xen_spinlock *xl = (struct xen_spinlock *)lock;
-
-	/* Not strictly true; this is only the count of contended
-	   lock-takers entering the slow path. */
-	return xl->spinners != 0;
-}
-
-static int xen_spin_trylock(struct raw_spinlock *lock)
-{
-	struct xen_spinlock *xl = (struct xen_spinlock *)lock;
-	u8 old = 1;
-
-	asm("xchgb %b0,%1"
-	    : "+q" (old), "+m" (xl->lock) : : "memory");
-
-	return old == 0;
-}
-
-static DEFINE_PER_CPU(int, lock_kicker_irq) = -1;
-static DEFINE_PER_CPU(struct xen_spinlock *, lock_spinners);
-
-static inline void spinning_lock(struct xen_spinlock *xl)
-{
-	__get_cpu_var(lock_spinners) = xl;
-	wmb();			/* set lock of interest before count */
-	asm(LOCK_PREFIX " incw %0"
-	    : "+m" (xl->spinners) : : "memory");
-}
-
-static inline void unspinning_lock(struct xen_spinlock *xl)
-{
-	asm(LOCK_PREFIX " decw %0"
-	    : "+m" (xl->spinners) : : "memory");
-	wmb();			/* decrement count before clearing lock */
-	__get_cpu_var(lock_spinners) = NULL;
-}
-
-static noinline int xen_spin_lock_slow(struct raw_spinlock *lock)
-{
-	struct xen_spinlock *xl = (struct xen_spinlock *)lock;
-	int irq = __get_cpu_var(lock_kicker_irq);
-	int ret;
-
-	/* If kicker interrupts not initialized yet, just spin */
-	if (irq == -1)
-		return 0;
-
-	/* announce we're spinning */
-	spinning_lock(xl);
-
-	/* clear pending */
-	xen_clear_irq_pending(irq);
-
-	/* check again make sure it didn't become free while
-	   we weren't looking  */
-	ret = xen_spin_trylock(lock);
-	if (ret)
-		goto out;
-
-	/* block until irq becomes pending */
-	xen_poll_irq(irq);
-	kstat_this_cpu.irqs[irq]++;
-
-out:
-	unspinning_lock(xl);
-	return ret;
-}
-
-static void xen_spin_lock(struct raw_spinlock *lock)
-{
-	struct xen_spinlock *xl = (struct xen_spinlock *)lock;
-	int timeout;
-	u8 oldval;
-
-	do {
-		timeout = 1 << 10;
-
-		asm("1: xchgb %1,%0\n"
-		    "   testb %1,%1\n"
-		    "   jz 3f\n"
-		    "2: rep;nop\n"
-		    "   cmpb $0,%0\n"
-		    "   je 1b\n"
-		    "   dec %2\n"
-		    "   jnz 2b\n"
-		    "3:\n"
-		    : "+m" (xl->lock), "=q" (oldval), "+r" (timeout)
-		    : "1" (1)
-		    : "memory");
-
-	} while (unlikely(oldval != 0 && !xen_spin_lock_slow(lock)));
-}
-
-static noinline void xen_spin_unlock_slow(struct xen_spinlock *xl)
-{
-	int cpu;
-
-	for_each_online_cpu(cpu) {
-		/* XXX should mix up next cpu selection */
-		if (per_cpu(lock_spinners, cpu) == xl) {
-			xen_send_IPI_one(cpu, XEN_SPIN_UNLOCK_VECTOR);
-			break;
-		}
-	}
-}
-
-static void xen_spin_unlock(struct raw_spinlock *lock)
-{
-	struct xen_spinlock *xl = (struct xen_spinlock *)lock;
-
-	smp_wmb();		/* make sure no writes get moved after unlock */
-	xl->lock = 0;		/* release lock */
-
-	/* make sure unlock happens before kick */
-	barrier();
-
-	if (unlikely(xl->spinners))
-		xen_spin_unlock_slow(xl);
-}
-
-static __cpuinit void xen_init_lock_cpu(int cpu)
-{
-	int irq;
-	const char *name;
-
-	name = kasprintf(GFP_KERNEL, "spinlock%d", cpu);
-	irq = bind_ipi_to_irqhandler(XEN_SPIN_UNLOCK_VECTOR,
-				     cpu,
-				     xen_reschedule_interrupt,
-				     IRQF_DISABLED|IRQF_PERCPU|IRQF_NOBALANCING,
-				     name,
-				     NULL);
-
-	if (irq >= 0) {
-		disable_irq(irq); /* make sure it's never delivered */
-		per_cpu(lock_kicker_irq, cpu) = irq;
-	}
-
-	printk("cpu %d spinlock event irq %d\n", cpu, irq);
-}
-
-static void __init xen_init_spinlocks(void)
-{
-	pv_lock_ops.spin_is_locked = xen_spin_is_locked;
-	pv_lock_ops.spin_is_contended = xen_spin_is_contended;
-	pv_lock_ops.spin_lock = xen_spin_lock;
-	pv_lock_ops.spin_trylock = xen_spin_trylock;
-	pv_lock_ops.spin_unlock = xen_spin_unlock;
-}
-
 static const struct smp_ops xen_smp_ops __initdata = {
 	.smp_prepare_boot_cpu = xen_smp_prepare_boot_cpu,
 	.smp_prepare_cpus = xen_smp_prepare_cpus,
-	.cpu_up = xen_cpu_up,
 	.smp_cpus_done = xen_smp_cpus_done,
 
+	.cpu_up = xen_cpu_up,
+	.cpu_die = xen_cpu_die,
+	.cpu_disable = xen_cpu_disable,
+	.play_dead = xen_play_dead,
+
 	.smp_send_stop = xen_smp_send_stop,
 	.smp_send_reschedule = xen_smp_send_reschedule,
 
diff --git a/arch/x86/xen/spinlock.c b/arch/x86/xen/spinlock.c
new file mode 100644
index 0000000..dd71e3a
--- /dev/null
+++ b/arch/x86/xen/spinlock.c
@@ -0,0 +1,428 @@
+/*
+ * Split spinlock implementation out into its own file, so it can be
+ * compiled in a FTRACE-compatible way.
+ */
+#include <linux/kernel_stat.h>
+#include <linux/spinlock.h>
+#include <linux/debugfs.h>
+#include <linux/log2.h>
+
+#include <asm/paravirt.h>
+
+#include <xen/interface/xen.h>
+#include <xen/events.h>
+
+#include "xen-ops.h"
+#include "debugfs.h"
+
+#ifdef CONFIG_XEN_DEBUG_FS
+static struct xen_spinlock_stats
+{
+	u64 taken;
+	u32 taken_slow;
+	u32 taken_slow_nested;
+	u32 taken_slow_pickup;
+	u32 taken_slow_spurious;
+	u32 taken_slow_irqenable;
+
+	u64 released;
+	u32 released_slow;
+	u32 released_slow_kicked;
+
+#define HISTO_BUCKETS	30
+	u32 histo_spin_total[HISTO_BUCKETS+1];
+	u32 histo_spin_spinning[HISTO_BUCKETS+1];
+	u32 histo_spin_blocked[HISTO_BUCKETS+1];
+
+	u64 time_total;
+	u64 time_spinning;
+	u64 time_blocked;
+} spinlock_stats;
+
+static u8 zero_stats;
+
+static unsigned lock_timeout = 1 << 10;
+#define TIMEOUT lock_timeout
+
+static inline void check_zero(void)
+{
+	if (unlikely(zero_stats)) {
+		memset(&spinlock_stats, 0, sizeof(spinlock_stats));
+		zero_stats = 0;
+	}
+}
+
+#define ADD_STATS(elem, val)			\
+	do { check_zero(); spinlock_stats.elem += (val); } while(0)
+
+static inline u64 spin_time_start(void)
+{
+	return xen_clocksource_read();
+}
+
+static void __spin_time_accum(u64 delta, u32 *array)
+{
+	unsigned index = ilog2(delta);
+
+	check_zero();
+
+	if (index < HISTO_BUCKETS)
+		array[index]++;
+	else
+		array[HISTO_BUCKETS]++;
+}
+
+static inline void spin_time_accum_spinning(u64 start)
+{
+	u32 delta = xen_clocksource_read() - start;
+
+	__spin_time_accum(delta, spinlock_stats.histo_spin_spinning);
+	spinlock_stats.time_spinning += delta;
+}
+
+static inline void spin_time_accum_total(u64 start)
+{
+	u32 delta = xen_clocksource_read() - start;
+
+	__spin_time_accum(delta, spinlock_stats.histo_spin_total);
+	spinlock_stats.time_total += delta;
+}
+
+static inline void spin_time_accum_blocked(u64 start)
+{
+	u32 delta = xen_clocksource_read() - start;
+
+	__spin_time_accum(delta, spinlock_stats.histo_spin_blocked);
+	spinlock_stats.time_blocked += delta;
+}
+#else  /* !CONFIG_XEN_DEBUG_FS */
+#define TIMEOUT			(1 << 10)
+#define ADD_STATS(elem, val)	do { (void)(val); } while(0)
+
+static inline u64 spin_time_start(void)
+{
+	return 0;
+}
+
+static inline void spin_time_accum_total(u64 start)
+{
+}
+static inline void spin_time_accum_spinning(u64 start)
+{
+}
+static inline void spin_time_accum_blocked(u64 start)
+{
+}
+#endif  /* CONFIG_XEN_DEBUG_FS */
+
+struct xen_spinlock {
+	unsigned char lock;		/* 0 -> free; 1 -> locked */
+	unsigned short spinners;	/* count of waiting cpus */
+};
+
+static int xen_spin_is_locked(struct raw_spinlock *lock)
+{
+	struct xen_spinlock *xl = (struct xen_spinlock *)lock;
+
+	return xl->lock != 0;
+}
+
+static int xen_spin_is_contended(struct raw_spinlock *lock)
+{
+	struct xen_spinlock *xl = (struct xen_spinlock *)lock;
+
+	/* Not strictly true; this is only the count of contended
+	   lock-takers entering the slow path. */
+	return xl->spinners != 0;
+}
+
+static int xen_spin_trylock(struct raw_spinlock *lock)
+{
+	struct xen_spinlock *xl = (struct xen_spinlock *)lock;
+	u8 old = 1;
+
+	asm("xchgb %b0,%1"
+	    : "+q" (old), "+m" (xl->lock) : : "memory");
+
+	return old == 0;
+}
+
+static DEFINE_PER_CPU(int, lock_kicker_irq) = -1;
+static DEFINE_PER_CPU(struct xen_spinlock *, lock_spinners);
+
+/*
+ * Mark a cpu as interested in a lock.  Returns the CPU's previous
+ * lock of interest, in case we got preempted by an interrupt.
+ */
+static inline struct xen_spinlock *spinning_lock(struct xen_spinlock *xl)
+{
+	struct xen_spinlock *prev;
+
+	prev = __get_cpu_var(lock_spinners);
+	__get_cpu_var(lock_spinners) = xl;
+
+	wmb();			/* set lock of interest before count */
+
+	asm(LOCK_PREFIX " incw %0"
+	    : "+m" (xl->spinners) : : "memory");
+
+	return prev;
+}
+
+/*
+ * Mark a cpu as no longer interested in a lock.  Restores previous
+ * lock of interest (NULL for none).
+ */
+static inline void unspinning_lock(struct xen_spinlock *xl, struct xen_spinlock *prev)
+{
+	asm(LOCK_PREFIX " decw %0"
+	    : "+m" (xl->spinners) : : "memory");
+	wmb();			/* decrement count before restoring lock */
+	__get_cpu_var(lock_spinners) = prev;
+}
+
+static noinline int xen_spin_lock_slow(struct raw_spinlock *lock, bool irq_enable)
+{
+	struct xen_spinlock *xl = (struct xen_spinlock *)lock;
+	struct xen_spinlock *prev;
+	int irq = __get_cpu_var(lock_kicker_irq);
+	int ret;
+	unsigned long flags;
+	u64 start;
+
+	/* If kicker interrupts not initialized yet, just spin */
+	if (irq == -1)
+		return 0;
+
+	start = spin_time_start();
+
+	/* announce we're spinning */
+	prev = spinning_lock(xl);
+
+	flags = __raw_local_save_flags();
+	if (irq_enable) {
+		ADD_STATS(taken_slow_irqenable, 1);
+		raw_local_irq_enable();
+	}
+
+	ADD_STATS(taken_slow, 1);
+	ADD_STATS(taken_slow_nested, prev != NULL);
+
+	do {
+		/* clear pending */
+		xen_clear_irq_pending(irq);
+
+		/* check again make sure it didn't become free while
+		   we weren't looking  */
+		ret = xen_spin_trylock(lock);
+		if (ret) {
+			ADD_STATS(taken_slow_pickup, 1);
+
+			/*
+			 * If we interrupted another spinlock while it
+			 * was blocking, make sure it doesn't block
+			 * without rechecking the lock.
+			 */
+			if (prev != NULL)
+				xen_set_irq_pending(irq);
+			goto out;
+		}
+
+		/*
+		 * Block until irq becomes pending.  If we're
+		 * interrupted at this point (after the trylock but
+		 * before entering the block), then the nested lock
+		 * handler guarantees that the irq will be left
+		 * pending if there's any chance the lock became free;
+		 * xen_poll_irq() returns immediately if the irq is
+		 * pending.
+		 */
+		xen_poll_irq(irq);
+		ADD_STATS(taken_slow_spurious, !xen_test_irq_pending(irq));
+	} while (!xen_test_irq_pending(irq)); /* check for spurious wakeups */
+
+	kstat_this_cpu.irqs[irq]++;
+
+out:
+	raw_local_irq_restore(flags);
+	unspinning_lock(xl, prev);
+	spin_time_accum_blocked(start);
+
+	return ret;
+}
+
+static inline void __xen_spin_lock(struct raw_spinlock *lock, bool irq_enable)
+{
+	struct xen_spinlock *xl = (struct xen_spinlock *)lock;
+	unsigned timeout;
+	u8 oldval;
+	u64 start_spin;
+
+	ADD_STATS(taken, 1);
+
+	start_spin = spin_time_start();
+
+	do {
+		u64 start_spin_fast = spin_time_start();
+
+		timeout = TIMEOUT;
+
+		asm("1: xchgb %1,%0\n"
+		    "   testb %1,%1\n"
+		    "   jz 3f\n"
+		    "2: rep;nop\n"
+		    "   cmpb $0,%0\n"
+		    "   je 1b\n"
+		    "   dec %2\n"
+		    "   jnz 2b\n"
+		    "3:\n"
+		    : "+m" (xl->lock), "=q" (oldval), "+r" (timeout)
+		    : "1" (1)
+		    : "memory");
+
+		spin_time_accum_spinning(start_spin_fast);
+
+	} while (unlikely(oldval != 0 &&
+			  (TIMEOUT == ~0 || !xen_spin_lock_slow(lock, irq_enable))));
+
+	spin_time_accum_total(start_spin);
+}
+
+static void xen_spin_lock(struct raw_spinlock *lock)
+{
+	__xen_spin_lock(lock, false);
+}
+
+static void xen_spin_lock_flags(struct raw_spinlock *lock, unsigned long flags)
+{
+	__xen_spin_lock(lock, !raw_irqs_disabled_flags(flags));
+}
+
+static noinline void xen_spin_unlock_slow(struct xen_spinlock *xl)
+{
+	int cpu;
+
+	ADD_STATS(released_slow, 1);
+
+	for_each_online_cpu(cpu) {
+		/* XXX should mix up next cpu selection */
+		if (per_cpu(lock_spinners, cpu) == xl) {
+			ADD_STATS(released_slow_kicked, 1);
+			xen_send_IPI_one(cpu, XEN_SPIN_UNLOCK_VECTOR);
+			break;
+		}
+	}
+}
+
+static void xen_spin_unlock(struct raw_spinlock *lock)
+{
+	struct xen_spinlock *xl = (struct xen_spinlock *)lock;
+
+	ADD_STATS(released, 1);
+
+	smp_wmb();		/* make sure no writes get moved after unlock */
+	xl->lock = 0;		/* release lock */
+
+	/* make sure unlock happens before kick */
+	barrier();
+
+	if (unlikely(xl->spinners))
+		xen_spin_unlock_slow(xl);
+}
+
+static irqreturn_t dummy_handler(int irq, void *dev_id)
+{
+	BUG();
+	return IRQ_HANDLED;
+}
+
+void __cpuinit xen_init_lock_cpu(int cpu)
+{
+	int irq;
+	const char *name;
+
+	name = kasprintf(GFP_KERNEL, "spinlock%d", cpu);
+	irq = bind_ipi_to_irqhandler(XEN_SPIN_UNLOCK_VECTOR,
+				     cpu,
+				     dummy_handler,
+				     IRQF_DISABLED|IRQF_PERCPU|IRQF_NOBALANCING,
+				     name,
+				     NULL);
+
+	if (irq >= 0) {
+		disable_irq(irq); /* make sure it's never delivered */
+		per_cpu(lock_kicker_irq, cpu) = irq;
+	}
+
+	printk("cpu %d spinlock event irq %d\n", cpu, irq);
+}
+
+void xen_uninit_lock_cpu(int cpu)
+{
+	unbind_from_irqhandler(per_cpu(lock_kicker_irq, cpu), NULL);
+}
+
+void __init xen_init_spinlocks(void)
+{
+	pv_lock_ops.spin_is_locked = xen_spin_is_locked;
+	pv_lock_ops.spin_is_contended = xen_spin_is_contended;
+	pv_lock_ops.spin_lock = xen_spin_lock;
+	pv_lock_ops.spin_lock_flags = xen_spin_lock_flags;
+	pv_lock_ops.spin_trylock = xen_spin_trylock;
+	pv_lock_ops.spin_unlock = xen_spin_unlock;
+}
+
+#ifdef CONFIG_XEN_DEBUG_FS
+
+static struct dentry *d_spin_debug;
+
+static int __init xen_spinlock_debugfs(void)
+{
+	struct dentry *d_xen = xen_init_debugfs();
+
+	if (d_xen == NULL)
+		return -ENOMEM;
+
+	d_spin_debug = debugfs_create_dir("spinlocks", d_xen);
+
+	debugfs_create_u8("zero_stats", 0644, d_spin_debug, &zero_stats);
+
+	debugfs_create_u32("timeout", 0644, d_spin_debug, &lock_timeout);
+
+	debugfs_create_u64("taken", 0444, d_spin_debug, &spinlock_stats.taken);
+	debugfs_create_u32("taken_slow", 0444, d_spin_debug,
+			   &spinlock_stats.taken_slow);
+	debugfs_create_u32("taken_slow_nested", 0444, d_spin_debug,
+			   &spinlock_stats.taken_slow_nested);
+	debugfs_create_u32("taken_slow_pickup", 0444, d_spin_debug,
+			   &spinlock_stats.taken_slow_pickup);
+	debugfs_create_u32("taken_slow_spurious", 0444, d_spin_debug,
+			   &spinlock_stats.taken_slow_spurious);
+	debugfs_create_u32("taken_slow_irqenable", 0444, d_spin_debug,
+			   &spinlock_stats.taken_slow_irqenable);
+
+	debugfs_create_u64("released", 0444, d_spin_debug, &spinlock_stats.released);
+	debugfs_create_u32("released_slow", 0444, d_spin_debug,
+			   &spinlock_stats.released_slow);
+	debugfs_create_u32("released_slow_kicked", 0444, d_spin_debug,
+			   &spinlock_stats.released_slow_kicked);
+
+	debugfs_create_u64("time_spinning", 0444, d_spin_debug,
+			   &spinlock_stats.time_spinning);
+	debugfs_create_u64("time_blocked", 0444, d_spin_debug,
+			   &spinlock_stats.time_blocked);
+	debugfs_create_u64("time_total", 0444, d_spin_debug,
+			   &spinlock_stats.time_total);
+
+	xen_debugfs_create_u32_array("histo_total", 0444, d_spin_debug,
+				     spinlock_stats.histo_spin_total, HISTO_BUCKETS + 1);
+	xen_debugfs_create_u32_array("histo_spinning", 0444, d_spin_debug,
+				     spinlock_stats.histo_spin_spinning, HISTO_BUCKETS + 1);
+	xen_debugfs_create_u32_array("histo_blocked", 0444, d_spin_debug,
+				     spinlock_stats.histo_spin_blocked, HISTO_BUCKETS + 1);
+
+	return 0;
+}
+fs_initcall(xen_spinlock_debugfs);
+
+#endif	/* CONFIG_XEN_DEBUG_FS */
diff --git a/arch/x86/xen/time.c b/arch/x86/xen/time.c
index 685b774..004ba86 100644
--- a/arch/x86/xen/time.c
+++ b/arch/x86/xen/time.c
@@ -30,8 +30,6 @@
 #define TIMER_SLOP	100000
 #define NS_PER_TICK	(1000000000LL / HZ)
 
-static cycle_t xen_clocksource_read(void);
-
 /* runstate info updated by Xen */
 static DEFINE_PER_CPU(struct vcpu_runstate_info, runstate);
 
@@ -213,7 +211,7 @@
 	return xen_khz;
 }
 
-static cycle_t xen_clocksource_read(void)
+cycle_t xen_clocksource_read(void)
 {
         struct pvclock_vcpu_time_info *src;
 	cycle_t ret;
@@ -452,6 +450,14 @@
 	setup_runstate_info(cpu);
 }
 
+void xen_teardown_timer(int cpu)
+{
+	struct clock_event_device *evt;
+	BUG_ON(cpu == 0);
+	evt = &per_cpu(xen_clock_events, cpu);
+	unbind_from_irqhandler(evt->irq, NULL);
+}
+
 void xen_setup_cpu_clockevents(void)
 {
 	BUG_ON(preemptible());
diff --git a/arch/x86/xen/xen-asm_32.S b/arch/x86/xen/xen-asm_32.S
index 2497a30..42786f5 100644
--- a/arch/x86/xen/xen-asm_32.S
+++ b/arch/x86/xen/xen-asm_32.S
@@ -298,7 +298,7 @@
 	push %eax
 	push %ecx
 	push %edx
-	call force_evtchn_callback
+	call xen_force_evtchn_callback
 	pop %edx
 	pop %ecx
 	pop %eax
diff --git a/arch/x86/xen/xen-asm_64.S b/arch/x86/xen/xen-asm_64.S
index 7f58304..05794c5 100644
--- a/arch/x86/xen/xen-asm_64.S
+++ b/arch/x86/xen/xen-asm_64.S
@@ -26,8 +26,15 @@
 /* Pseudo-flag used for virtual NMI, which we don't implement yet */
 #define XEN_EFLAGS_NMI	0x80000000
 
-#if 0
-#include <asm/percpu.h>
+#if 1
+/*
+	x86-64 does not yet support direct access to percpu variables
+	via a segment override, so we just need to make sure this code
+	never gets used
+ */
+#define BUG			ud2a
+#define PER_CPU_VAR(var, off)	0xdeadbeef
+#endif
 
 /*
 	Enable events.  This clears the event mask and tests the pending
@@ -35,6 +42,8 @@
 	events, then enter the hypervisor to get them handled.
  */
 ENTRY(xen_irq_enable_direct)
+	BUG
+
 	/* Unmask events */
 	movb $0, PER_CPU_VAR(xen_vcpu_info, XEN_vcpu_info_mask)
 
@@ -58,6 +67,8 @@
 	non-zero.
  */
 ENTRY(xen_irq_disable_direct)
+	BUG
+
 	movb $1, PER_CPU_VAR(xen_vcpu_info, XEN_vcpu_info_mask)
 ENDPATCH(xen_irq_disable_direct)
 	ret
@@ -74,6 +85,8 @@
 	Xen and x86 use opposite senses (mask vs enable).
  */
 ENTRY(xen_save_fl_direct)
+	BUG
+
 	testb $0xff, PER_CPU_VAR(xen_vcpu_info, XEN_vcpu_info_mask)
 	setz %ah
 	addb %ah,%ah
@@ -91,6 +104,8 @@
 	if so.
  */
 ENTRY(xen_restore_fl_direct)
+	BUG
+
 	testb $X86_EFLAGS_IF>>8, %ah
 	setz PER_CPU_VAR(xen_vcpu_info, XEN_vcpu_info_mask)
 	/* Preempt here doesn't matter because that will deal with
@@ -122,7 +137,7 @@
 	push %r9
 	push %r10
 	push %r11
-	call force_evtchn_callback
+	call xen_force_evtchn_callback
 	pop %r11
 	pop %r10
 	pop %r9
@@ -133,7 +148,6 @@
 	pop %rcx
 	pop %rax
 	ret
-#endif
 
 ENTRY(xen_adjust_exception_frame)
 	mov 8+0(%rsp),%rcx
diff --git a/arch/x86/xen/xen-ops.h b/arch/x86/xen/xen-ops.h
index dd3c231..d7422dc 100644
--- a/arch/x86/xen/xen-ops.h
+++ b/arch/x86/xen/xen-ops.h
@@ -2,6 +2,7 @@
 #define XEN_OPS_H
 
 #include <linux/init.h>
+#include <linux/clocksource.h>
 #include <linux/irqreturn.h>
 #include <xen/xen-ops.h>
 
@@ -31,7 +32,10 @@
 
 void __init xen_build_dynamic_phys_to_machine(void);
 
+void xen_init_irq_ops(void);
 void xen_setup_timer(int cpu);
+void xen_teardown_timer(int cpu);
+cycle_t xen_clocksource_read(void);
 void xen_setup_cpu_clockevents(void);
 unsigned long xen_tsc_khz(void);
 void __init xen_time_init(void);
@@ -50,6 +54,10 @@
 #ifdef CONFIG_SMP
 void xen_smp_init(void);
 
+void __init xen_init_spinlocks(void);
+__cpuinit void xen_init_lock_cpu(int cpu);
+void xen_uninit_lock_cpu(int cpu);
+
 extern cpumask_t xen_cpu_initialized_map;
 #else
 static inline void xen_smp_init(void) {}
diff --git a/arch/xtensa/kernel/setup.c b/arch/xtensa/kernel/setup.c
index a00359e..9606d2b 100644
--- a/arch/xtensa/kernel/setup.c
+++ b/arch/xtensa/kernel/setup.c
@@ -53,11 +53,6 @@
 struct fd_ops *fd_ops;
 #endif
 
-#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
-extern struct ide_ops no_ide_ops;
-struct ide_ops *ide_ops;
-#endif
-
 extern struct rtc_ops no_rtc_ops;
 struct rtc_ops *rtc_ops;
 
diff --git a/block/Makefile b/block/Makefile
index 208000b..bfe7304 100644
--- a/block/Makefile
+++ b/block/Makefile
@@ -4,8 +4,8 @@
 
 obj-$(CONFIG_BLOCK) := elevator.o blk-core.o blk-tag.o blk-sysfs.o \
 			blk-barrier.o blk-settings.o blk-ioc.o blk-map.o \
-			blk-exec.o blk-merge.o ioctl.o genhd.o scsi_ioctl.o \
-			cmd-filter.o
+			blk-exec.o blk-merge.o blk-softirq.o blk-timeout.o \
+			ioctl.o genhd.o scsi_ioctl.o cmd-filter.o
 
 obj-$(CONFIG_BLK_DEV_BSG)	+= bsg.o
 obj-$(CONFIG_IOSCHED_NOOP)	+= noop-iosched.o
diff --git a/block/as-iosched.c b/block/as-iosched.c
index cf4eb0e..71f0abb 100644
--- a/block/as-iosched.c
+++ b/block/as-iosched.c
@@ -462,7 +462,7 @@
 			del_timer(&ad->antic_timer);
 		ad->antic_status = ANTIC_FINISHED;
 		/* see as_work_handler */
-		kblockd_schedule_work(&ad->antic_work);
+		kblockd_schedule_work(ad->q, &ad->antic_work);
 	}
 }
 
@@ -483,7 +483,7 @@
 		aic = ad->io_context->aic;
 
 		ad->antic_status = ANTIC_FINISHED;
-		kblockd_schedule_work(&ad->antic_work);
+		kblockd_schedule_work(q, &ad->antic_work);
 
 		if (aic->ttime_samples == 0) {
 			/* process anticipated on has exited or timed out*/
@@ -745,6 +745,14 @@
  */
 static int as_can_anticipate(struct as_data *ad, struct request *rq)
 {
+#if 0 /* disable for now, we need to check tag level as well */
+	/*
+	 * SSD device without seek penalty, disable idling
+	 */
+	if (blk_queue_nonrot(ad->q)) axman
+		return 0;
+#endif
+
 	if (!ad->io_context)
 		/*
 		 * Last request submitted was a write
@@ -844,7 +852,7 @@
 	if (ad->changed_batch && ad->nr_dispatched == 1) {
 		ad->current_batch_expires = jiffies +
 					ad->batch_expire[ad->batch_data_dir];
-		kblockd_schedule_work(&ad->antic_work);
+		kblockd_schedule_work(q, &ad->antic_work);
 		ad->changed_batch = 0;
 
 		if (ad->batch_data_dir == REQ_SYNC)
diff --git a/block/blk-barrier.c b/block/blk-barrier.c
index a09ead1..5c99ff8 100644
--- a/block/blk-barrier.c
+++ b/block/blk-barrier.c
@@ -293,7 +293,7 @@
 	bio->bi_end_io = bio_end_empty_barrier;
 	bio->bi_private = &wait;
 	bio->bi_bdev = bdev;
-	submit_bio(1 << BIO_RW_BARRIER, bio);
+	submit_bio(WRITE_BARRIER, bio);
 
 	wait_for_completion(&wait);
 
@@ -315,3 +315,73 @@
 	return ret;
 }
 EXPORT_SYMBOL(blkdev_issue_flush);
+
+static void blkdev_discard_end_io(struct bio *bio, int err)
+{
+	if (err) {
+		if (err == -EOPNOTSUPP)
+			set_bit(BIO_EOPNOTSUPP, &bio->bi_flags);
+		clear_bit(BIO_UPTODATE, &bio->bi_flags);
+	}
+
+	bio_put(bio);
+}
+
+/**
+ * blkdev_issue_discard - queue a discard
+ * @bdev:	blockdev to issue discard for
+ * @sector:	start sector
+ * @nr_sects:	number of sectors to discard
+ * @gfp_mask:	memory allocation flags (for bio_alloc)
+ *
+ * Description:
+ *    Issue a discard request for the sectors in question. Does not wait.
+ */
+int blkdev_issue_discard(struct block_device *bdev,
+			 sector_t sector, sector_t nr_sects, gfp_t gfp_mask)
+{
+	struct request_queue *q;
+	struct bio *bio;
+	int ret = 0;
+
+	if (bdev->bd_disk == NULL)
+		return -ENXIO;
+
+	q = bdev_get_queue(bdev);
+	if (!q)
+		return -ENXIO;
+
+	if (!q->prepare_discard_fn)
+		return -EOPNOTSUPP;
+
+	while (nr_sects && !ret) {
+		bio = bio_alloc(gfp_mask, 0);
+		if (!bio)
+			return -ENOMEM;
+
+		bio->bi_end_io = blkdev_discard_end_io;
+		bio->bi_bdev = bdev;
+
+		bio->bi_sector = sector;
+
+		if (nr_sects > q->max_hw_sectors) {
+			bio->bi_size = q->max_hw_sectors << 9;
+			nr_sects -= q->max_hw_sectors;
+			sector += q->max_hw_sectors;
+		} else {
+			bio->bi_size = nr_sects << 9;
+			nr_sects = 0;
+		}
+		bio_get(bio);
+		submit_bio(DISCARD_BARRIER, bio);
+
+		/* Check if it failed immediately */
+		if (bio_flagged(bio, BIO_EOPNOTSUPP))
+			ret = -EOPNOTSUPP;
+		else if (!bio_flagged(bio, BIO_UPTODATE))
+			ret = -EIO;
+		bio_put(bio);
+	}
+	return ret;
+}
+EXPORT_SYMBOL(blkdev_issue_discard);
diff --git a/block/blk-core.c b/block/blk-core.c
index 2cba5ef..2d053b5 100644
--- a/block/blk-core.c
+++ b/block/blk-core.c
@@ -26,8 +26,6 @@
 #include <linux/swap.h>
 #include <linux/writeback.h>
 #include <linux/task_io_accounting_ops.h>
-#include <linux/interrupt.h>
-#include <linux/cpu.h>
 #include <linux/blktrace_api.h>
 #include <linux/fault-inject.h>
 
@@ -50,27 +48,26 @@
  */
 static struct workqueue_struct *kblockd_workqueue;
 
-static DEFINE_PER_CPU(struct list_head, blk_cpu_done);
-
 static void drive_stat_acct(struct request *rq, int new_io)
 {
 	struct hd_struct *part;
 	int rw = rq_data_dir(rq);
+	int cpu;
 
 	if (!blk_fs_request(rq) || !rq->rq_disk)
 		return;
 
-	part = get_part(rq->rq_disk, rq->sector);
+	cpu = part_stat_lock();
+	part = disk_map_sector_rcu(rq->rq_disk, rq->sector);
+
 	if (!new_io)
-		__all_stat_inc(rq->rq_disk, part, merges[rw], rq->sector);
+		part_stat_inc(cpu, part, merges[rw]);
 	else {
-		disk_round_stats(rq->rq_disk);
-		rq->rq_disk->in_flight++;
-		if (part) {
-			part_round_stats(part);
-			part->in_flight++;
-		}
+		part_round_stats(cpu, part);
+		part_inc_in_flight(part);
 	}
+
+	part_stat_unlock();
 }
 
 void blk_queue_congestion_threshold(struct request_queue *q)
@@ -113,7 +110,8 @@
 	memset(rq, 0, sizeof(*rq));
 
 	INIT_LIST_HEAD(&rq->queuelist);
-	INIT_LIST_HEAD(&rq->donelist);
+	INIT_LIST_HEAD(&rq->timeout_list);
+	rq->cpu = -1;
 	rq->q = q;
 	rq->sector = rq->hard_sector = (sector_t) -1;
 	INIT_HLIST_NODE(&rq->hash);
@@ -308,7 +306,7 @@
 	blk_add_trace_pdu_int(q, BLK_TA_UNPLUG_TIMER, NULL,
 				q->rq.count[READ] + q->rq.count[WRITE]);
 
-	kblockd_schedule_work(&q->unplug_work);
+	kblockd_schedule_work(q, &q->unplug_work);
 }
 
 void blk_unplug(struct request_queue *q)
@@ -325,6 +323,21 @@
 }
 EXPORT_SYMBOL(blk_unplug);
 
+static void blk_invoke_request_fn(struct request_queue *q)
+{
+	/*
+	 * one level of recursion is ok and is much faster than kicking
+	 * the unplug handling
+	 */
+	if (!queue_flag_test_and_set(QUEUE_FLAG_REENTER, q)) {
+		q->request_fn(q);
+		queue_flag_clear(QUEUE_FLAG_REENTER, q);
+	} else {
+		queue_flag_set(QUEUE_FLAG_PLUGGED, q);
+		kblockd_schedule_work(q, &q->unplug_work);
+	}
+}
+
 /**
  * blk_start_queue - restart a previously stopped queue
  * @q:    The &struct request_queue in question
@@ -339,18 +352,7 @@
 	WARN_ON(!irqs_disabled());
 
 	queue_flag_clear(QUEUE_FLAG_STOPPED, q);
-
-	/*
-	 * one level of recursion is ok and is much faster than kicking
-	 * the unplug handling
-	 */
-	if (!queue_flag_test_and_set(QUEUE_FLAG_REENTER, q)) {
-		q->request_fn(q);
-		queue_flag_clear(QUEUE_FLAG_REENTER, q);
-	} else {
-		blk_plug_device(q);
-		kblockd_schedule_work(&q->unplug_work);
-	}
+	blk_invoke_request_fn(q);
 }
 EXPORT_SYMBOL(blk_start_queue);
 
@@ -408,15 +410,8 @@
 	 * Only recurse once to avoid overrunning the stack, let the unplug
 	 * handling reinvoke the handler shortly if we already got there.
 	 */
-	if (!elv_queue_empty(q)) {
-		if (!queue_flag_test_and_set(QUEUE_FLAG_REENTER, q)) {
-			q->request_fn(q);
-			queue_flag_clear(QUEUE_FLAG_REENTER, q);
-		} else {
-			blk_plug_device(q);
-			kblockd_schedule_work(&q->unplug_work);
-		}
-	}
+	if (!elv_queue_empty(q))
+		blk_invoke_request_fn(q);
 }
 EXPORT_SYMBOL(__blk_run_queue);
 
@@ -441,6 +436,14 @@
 
 void blk_cleanup_queue(struct request_queue *q)
 {
+	/*
+	 * We know we have process context here, so we can be a little
+	 * cautious and ensure that pending block actions on this device
+	 * are done before moving on. Going into this function, we should
+	 * not have processes doing IO to this device.
+	 */
+	blk_sync_queue(q);
+
 	mutex_lock(&q->sysfs_lock);
 	queue_flag_set_unlocked(QUEUE_FLAG_DEAD, q);
 	mutex_unlock(&q->sysfs_lock);
@@ -496,6 +499,8 @@
 	}
 
 	init_timer(&q->unplug_timer);
+	setup_timer(&q->timeout, blk_rq_timed_out_timer, (unsigned long) q);
+	INIT_LIST_HEAD(&q->timeout_list);
 
 	kobject_init(&q->kobj, &blk_queue_ktype);
 
@@ -531,7 +536,7 @@
  *    request queue; this lock will be taken also from interrupt context, so irq
  *    disabling is needed for it.
  *
- *    Function returns a pointer to the initialized request queue, or NULL if
+ *    Function returns a pointer to the initialized request queue, or %NULL if
  *    it didn't succeed.
  *
  * Note:
@@ -569,7 +574,8 @@
 	q->request_fn		= rfn;
 	q->prep_rq_fn		= NULL;
 	q->unplug_fn		= generic_unplug_device;
-	q->queue_flags		= (1 << QUEUE_FLAG_CLUSTER);
+	q->queue_flags		= (1 << QUEUE_FLAG_CLUSTER |
+				   1 << QUEUE_FLAG_STACKABLE);
 	q->queue_lock		= lock;
 
 	blk_queue_segment_boundary(q, 0xffffffff);
@@ -624,10 +630,6 @@
 
 	blk_rq_init(q, rq);
 
-	/*
-	 * first three bits are identical in rq->cmd_flags and bio->bi_rw,
-	 * see bio.h and blkdev.h
-	 */
 	rq->cmd_flags = rw | REQ_ALLOCED;
 
 	if (priv) {
@@ -888,9 +890,11 @@
  */
 void blk_start_queueing(struct request_queue *q)
 {
-	if (!blk_queue_plugged(q))
+	if (!blk_queue_plugged(q)) {
+		if (unlikely(blk_queue_stopped(q)))
+			return;
 		q->request_fn(q);
-	else
+	} else
 		__generic_unplug_device(q);
 }
 EXPORT_SYMBOL(blk_start_queueing);
@@ -907,6 +911,8 @@
  */
 void blk_requeue_request(struct request_queue *q, struct request *rq)
 {
+	blk_delete_timer(rq);
+	blk_clear_rq_complete(rq);
 	blk_add_trace_rq(q, rq, BLK_TA_REQUEUE);
 
 	if (blk_rq_tagged(rq))
@@ -917,7 +923,7 @@
 EXPORT_SYMBOL(blk_requeue_request);
 
 /**
- * blk_insert_request - insert a special request in to a request queue
+ * blk_insert_request - insert a special request into a request queue
  * @q:		request queue where request should be inserted
  * @rq:		request to be inserted
  * @at_head:	insert request at head or tail of queue
@@ -927,8 +933,8 @@
  *    Many block devices need to execute commands asynchronously, so they don't
  *    block the whole kernel from preemption during request execution.  This is
  *    accomplished normally by inserting aritficial requests tagged as
- *    REQ_SPECIAL in to the corresponding request queue, and letting them be
- *    scheduled for actual execution by the request queue.
+ *    REQ_TYPE_SPECIAL in to the corresponding request queue, and letting them
+ *    be scheduled for actual execution by the request queue.
  *
  *    We have the option of inserting the head or the tail of the queue.
  *    Typically we use the tail for new ioctls and so forth.  We use the head
@@ -982,8 +988,22 @@
 	__elv_add_request(q, req, ELEVATOR_INSERT_SORT, 0);
 }
 
-/*
- * disk_round_stats()	- Round off the performance stats on a struct
+static void part_round_stats_single(int cpu, struct hd_struct *part,
+				    unsigned long now)
+{
+	if (now == part->stamp)
+		return;
+
+	if (part->in_flight) {
+		__part_stat_add(cpu, part, time_in_queue,
+				part->in_flight * (now - part->stamp));
+		__part_stat_add(cpu, part, io_ticks, (now - part->stamp));
+	}
+	part->stamp = now;
+}
+
+/**
+ * part_round_stats()	- Round off the performance stats on a struct
  * disk_stats.
  *
  * The average IO queue length and utilisation statistics are maintained
@@ -997,36 +1017,15 @@
  * /proc/diskstats.  This accounts immediately for all queue usage up to
  * the current jiffies and restarts the counters again.
  */
-void disk_round_stats(struct gendisk *disk)
+void part_round_stats(int cpu, struct hd_struct *part)
 {
 	unsigned long now = jiffies;
 
-	if (now == disk->stamp)
-		return;
-
-	if (disk->in_flight) {
-		__disk_stat_add(disk, time_in_queue,
-				disk->in_flight * (now - disk->stamp));
-		__disk_stat_add(disk, io_ticks, (now - disk->stamp));
-	}
-	disk->stamp = now;
+	if (part->partno)
+		part_round_stats_single(cpu, &part_to_disk(part)->part0, now);
+	part_round_stats_single(cpu, part, now);
 }
-EXPORT_SYMBOL_GPL(disk_round_stats);
-
-void part_round_stats(struct hd_struct *part)
-{
-	unsigned long now = jiffies;
-
-	if (now == part->stamp)
-		return;
-
-	if (part->in_flight) {
-		__part_stat_add(part, time_in_queue,
-				part->in_flight * (now - part->stamp));
-		__part_stat_add(part, io_ticks, (now - part->stamp));
-	}
-	part->stamp = now;
-}
+EXPORT_SYMBOL_GPL(part_round_stats);
 
 /*
  * queue lock must be held
@@ -1070,6 +1069,7 @@
 
 void init_request_from_bio(struct request *req, struct bio *bio)
 {
+	req->cpu = bio->bi_comp_cpu;
 	req->cmd_type = REQ_TYPE_FS;
 
 	/*
@@ -1081,7 +1081,12 @@
 	/*
 	 * REQ_BARRIER implies no merging, but lets make it explicit
 	 */
-	if (unlikely(bio_barrier(bio)))
+	if (unlikely(bio_discard(bio))) {
+		req->cmd_flags |= REQ_DISCARD;
+		if (bio_barrier(bio))
+			req->cmd_flags |= REQ_SOFTBARRIER;
+		req->q->prepare_discard_fn(req->q, req);
+	} else if (unlikely(bio_barrier(bio)))
 		req->cmd_flags |= (REQ_HARDBARRIER | REQ_NOMERGE);
 
 	if (bio_sync(bio))
@@ -1099,7 +1104,7 @@
 static int __make_request(struct request_queue *q, struct bio *bio)
 {
 	struct request *req;
-	int el_ret, nr_sectors, barrier, err;
+	int el_ret, nr_sectors, barrier, discard, err;
 	const unsigned short prio = bio_prio(bio);
 	const int sync = bio_sync(bio);
 	int rw_flags;
@@ -1114,7 +1119,14 @@
 	blk_queue_bounce(q, &bio);
 
 	barrier = bio_barrier(bio);
-	if (unlikely(barrier) && (q->next_ordered == QUEUE_ORDERED_NONE)) {
+	if (unlikely(barrier) && bio_has_data(bio) &&
+	    (q->next_ordered == QUEUE_ORDERED_NONE)) {
+		err = -EOPNOTSUPP;
+		goto end_io;
+	}
+
+	discard = bio_discard(bio);
+	if (unlikely(discard) && !q->prepare_discard_fn) {
 		err = -EOPNOTSUPP;
 		goto end_io;
 	}
@@ -1138,6 +1150,8 @@
 		req->biotail = bio;
 		req->nr_sectors = req->hard_nr_sectors += nr_sectors;
 		req->ioprio = ioprio_best(req->ioprio, prio);
+		if (!blk_rq_cpu_valid(req))
+			req->cpu = bio->bi_comp_cpu;
 		drive_stat_acct(req, 0);
 		if (!attempt_back_merge(q, req))
 			elv_merged_request(q, req, el_ret);
@@ -1165,6 +1179,8 @@
 		req->sector = req->hard_sector = bio->bi_sector;
 		req->nr_sectors = req->hard_nr_sectors += nr_sectors;
 		req->ioprio = ioprio_best(req->ioprio, prio);
+		if (!blk_rq_cpu_valid(req))
+			req->cpu = bio->bi_comp_cpu;
 		drive_stat_acct(req, 0);
 		if (!attempt_front_merge(q, req))
 			elv_merged_request(q, req, el_ret);
@@ -1200,13 +1216,15 @@
 	init_request_from_bio(req, bio);
 
 	spin_lock_irq(q->queue_lock);
+	if (test_bit(QUEUE_FLAG_SAME_COMP, &q->queue_flags) ||
+	    bio_flagged(bio, BIO_CPU_AFFINE))
+		req->cpu = blk_cpu_to_group(smp_processor_id());
 	if (elv_queue_empty(q))
 		blk_plug_device(q);
 	add_request(q, req);
 out:
 	if (sync)
 		__generic_unplug_device(q);
-
 	spin_unlock_irq(q->queue_lock);
 	return 0;
 
@@ -1260,8 +1278,9 @@
 
 static int should_fail_request(struct bio *bio)
 {
-	if ((bio->bi_bdev->bd_disk->flags & GENHD_FL_FAIL) ||
-	    (bio->bi_bdev->bd_part && bio->bi_bdev->bd_part->make_it_fail))
+	struct hd_struct *part = bio->bi_bdev->bd_part;
+
+	if (part_to_disk(part)->part0.make_it_fail || part->make_it_fail)
 		return should_fail(&fail_make_request, bio->bi_size);
 
 	return 0;
@@ -1314,7 +1333,7 @@
 }
 
 /**
- * generic_make_request: hand a buffer to its device driver for I/O
+ * generic_make_request - hand a buffer to its device driver for I/O
  * @bio:  The bio describing the location in memory and on the device.
  *
  * generic_make_request() is used to make I/O requests of block
@@ -1409,7 +1428,8 @@
 
 		if (bio_check_eod(bio, nr_sectors))
 			goto end_io;
-		if (bio_empty_barrier(bio) && !q->prepare_flush_fn) {
+		if ((bio_empty_barrier(bio) && !q->prepare_flush_fn) ||
+		    (bio_discard(bio) && !q->prepare_discard_fn)) {
 			err = -EOPNOTSUPP;
 			goto end_io;
 		}
@@ -1471,13 +1491,13 @@
 EXPORT_SYMBOL(generic_make_request);
 
 /**
- * submit_bio: submit a bio to the block device layer for I/O
+ * submit_bio - submit a bio to the block device layer for I/O
  * @rw: whether to %READ or %WRITE, or maybe to %READA (read ahead)
  * @bio: The &struct bio which describes the I/O
  *
  * submit_bio() is very similar in purpose to generic_make_request(), and
  * uses that function to do most of the work. Both are fairly rough
- * interfaces, @bio must be presetup and ready for I/O.
+ * interfaces; @bio must be presetup and ready for I/O.
  *
  */
 void submit_bio(int rw, struct bio *bio)
@@ -1490,11 +1510,7 @@
 	 * If it's a regular read/write or a barrier with data attached,
 	 * go through the normal accounting stuff before submission.
 	 */
-	if (!bio_empty_barrier(bio)) {
-
-		BIO_BUG_ON(!bio->bi_size);
-		BIO_BUG_ON(!bio->bi_io_vec);
-
+	if (bio_has_data(bio)) {
 		if (rw & WRITE) {
 			count_vm_events(PGPGOUT, count);
 		} else {
@@ -1517,9 +1533,90 @@
 EXPORT_SYMBOL(submit_bio);
 
 /**
+ * blk_rq_check_limits - Helper function to check a request for the queue limit
+ * @q:  the queue
+ * @rq: the request being checked
+ *
+ * Description:
+ *    @rq may have been made based on weaker limitations of upper-level queues
+ *    in request stacking drivers, and it may violate the limitation of @q.
+ *    Since the block layer and the underlying device driver trust @rq
+ *    after it is inserted to @q, it should be checked against @q before
+ *    the insertion using this generic function.
+ *
+ *    This function should also be useful for request stacking drivers
+ *    in some cases below, so export this fuction.
+ *    Request stacking drivers like request-based dm may change the queue
+ *    limits while requests are in the queue (e.g. dm's table swapping).
+ *    Such request stacking drivers should check those requests agaist
+ *    the new queue limits again when they dispatch those requests,
+ *    although such checkings are also done against the old queue limits
+ *    when submitting requests.
+ */
+int blk_rq_check_limits(struct request_queue *q, struct request *rq)
+{
+	if (rq->nr_sectors > q->max_sectors ||
+	    rq->data_len > q->max_hw_sectors << 9) {
+		printk(KERN_ERR "%s: over max size limit.\n", __func__);
+		return -EIO;
+	}
+
+	/*
+	 * queue's settings related to segment counting like q->bounce_pfn
+	 * may differ from that of other stacking queues.
+	 * Recalculate it to check the request correctly on this queue's
+	 * limitation.
+	 */
+	blk_recalc_rq_segments(rq);
+	if (rq->nr_phys_segments > q->max_phys_segments ||
+	    rq->nr_phys_segments > q->max_hw_segments) {
+		printk(KERN_ERR "%s: over max segments limit.\n", __func__);
+		return -EIO;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(blk_rq_check_limits);
+
+/**
+ * blk_insert_cloned_request - Helper for stacking drivers to submit a request
+ * @q:  the queue to submit the request
+ * @rq: the request being queued
+ */
+int blk_insert_cloned_request(struct request_queue *q, struct request *rq)
+{
+	unsigned long flags;
+
+	if (blk_rq_check_limits(q, rq))
+		return -EIO;
+
+#ifdef CONFIG_FAIL_MAKE_REQUEST
+	if (rq->rq_disk && rq->rq_disk->part0.make_it_fail &&
+	    should_fail(&fail_make_request, blk_rq_bytes(rq)))
+		return -EIO;
+#endif
+
+	spin_lock_irqsave(q->queue_lock, flags);
+
+	/*
+	 * Submitting request must be dequeued before calling this function
+	 * because it will be linked to another request_queue
+	 */
+	BUG_ON(blk_queued_rq(rq));
+
+	drive_stat_acct(rq, 1);
+	__elv_add_request(q, rq, ELEVATOR_INSERT_BACK, 0);
+
+	spin_unlock_irqrestore(q->queue_lock, flags);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(blk_insert_cloned_request);
+
+/**
  * __end_that_request_first - end I/O on a request
  * @req:      the request being processed
- * @error:    0 for success, < 0 for error
+ * @error:    %0 for success, < %0 for error
  * @nr_bytes: number of bytes to complete
  *
  * Description:
@@ -1527,8 +1624,8 @@
  *     for the next range of segments (if any) in the cluster.
  *
  * Return:
- *     0 - we are done with this request, call end_that_request_last()
- *     1 - still buffers pending for this request
+ *     %0 - we are done with this request, call end_that_request_last()
+ *     %1 - still buffers pending for this request
  **/
 static int __end_that_request_first(struct request *req, int error,
 				    int nr_bytes)
@@ -1539,7 +1636,7 @@
 	blk_add_trace_rq(req->q, req, BLK_TA_COMPLETE);
 
 	/*
-	 * for a REQ_BLOCK_PC request, we want to carry any eventual
+	 * for a REQ_TYPE_BLOCK_PC request, we want to carry any eventual
 	 * sense key with us all the way through
 	 */
 	if (!blk_pc_request(req))
@@ -1552,11 +1649,14 @@
 	}
 
 	if (blk_fs_request(req) && req->rq_disk) {
-		struct hd_struct *part = get_part(req->rq_disk, req->sector);
 		const int rw = rq_data_dir(req);
+		struct hd_struct *part;
+		int cpu;
 
-		all_stat_add(req->rq_disk, part, sectors[rw],
-				nr_bytes >> 9, req->sector);
+		cpu = part_stat_lock();
+		part = disk_map_sector_rcu(req->rq_disk, req->sector);
+		part_stat_add(cpu, part, sectors[rw], nr_bytes >> 9);
+		part_stat_unlock();
 	}
 
 	total_bytes = bio_nbytes = 0;
@@ -1641,88 +1741,14 @@
 }
 
 /*
- * splice the completion data to a local structure and hand off to
- * process_completion_queue() to complete the requests
- */
-static void blk_done_softirq(struct softirq_action *h)
-{
-	struct list_head *cpu_list, local_list;
-
-	local_irq_disable();
-	cpu_list = &__get_cpu_var(blk_cpu_done);
-	list_replace_init(cpu_list, &local_list);
-	local_irq_enable();
-
-	while (!list_empty(&local_list)) {
-		struct request *rq;
-
-		rq = list_entry(local_list.next, struct request, donelist);
-		list_del_init(&rq->donelist);
-		rq->q->softirq_done_fn(rq);
-	}
-}
-
-static int __cpuinit blk_cpu_notify(struct notifier_block *self,
-				    unsigned long action, void *hcpu)
-{
-	/*
-	 * If a CPU goes away, splice its entries to the current CPU
-	 * and trigger a run of the softirq
-	 */
-	if (action == CPU_DEAD || action == CPU_DEAD_FROZEN) {
-		int cpu = (unsigned long) hcpu;
-
-		local_irq_disable();
-		list_splice_init(&per_cpu(blk_cpu_done, cpu),
-				 &__get_cpu_var(blk_cpu_done));
-		raise_softirq_irqoff(BLOCK_SOFTIRQ);
-		local_irq_enable();
-	}
-
-	return NOTIFY_OK;
-}
-
-
-static struct notifier_block blk_cpu_notifier __cpuinitdata = {
-	.notifier_call	= blk_cpu_notify,
-};
-
-/**
- * blk_complete_request - end I/O on a request
- * @req:      the request being processed
- *
- * Description:
- *     Ends all I/O on a request. It does not handle partial completions,
- *     unless the driver actually implements this in its completion callback
- *     through requeueing. The actual completion happens out-of-order,
- *     through a softirq handler. The user must have registered a completion
- *     callback through blk_queue_softirq_done().
- **/
-
-void blk_complete_request(struct request *req)
-{
-	struct list_head *cpu_list;
-	unsigned long flags;
-
-	BUG_ON(!req->q->softirq_done_fn);
-
-	local_irq_save(flags);
-
-	cpu_list = &__get_cpu_var(blk_cpu_done);
-	list_add_tail(&req->donelist, cpu_list);
-	raise_softirq_irqoff(BLOCK_SOFTIRQ);
-
-	local_irq_restore(flags);
-}
-EXPORT_SYMBOL(blk_complete_request);
-
-/*
  * queue lock must be held
  */
 static void end_that_request_last(struct request *req, int error)
 {
 	struct gendisk *disk = req->rq_disk;
 
+	blk_delete_timer(req);
+
 	if (blk_rq_tagged(req))
 		blk_queue_end_tag(req->q, req);
 
@@ -1740,16 +1766,18 @@
 	if (disk && blk_fs_request(req) && req != &req->q->bar_rq) {
 		unsigned long duration = jiffies - req->start_time;
 		const int rw = rq_data_dir(req);
-		struct hd_struct *part = get_part(disk, req->sector);
+		struct hd_struct *part;
+		int cpu;
 
-		__all_stat_inc(disk, part, ios[rw], req->sector);
-		__all_stat_add(disk, part, ticks[rw], duration, req->sector);
-		disk_round_stats(disk);
-		disk->in_flight--;
-		if (part) {
-			part_round_stats(part);
-			part->in_flight--;
-		}
+		cpu = part_stat_lock();
+		part = disk_map_sector_rcu(disk, req->sector);
+
+		part_stat_inc(cpu, part, ios[rw]);
+		part_stat_add(cpu, part, ticks[rw], duration);
+		part_round_stats(cpu, part);
+		part_dec_in_flight(part);
+
+		part_stat_unlock();
 	}
 
 	if (req->end_io)
@@ -1762,17 +1790,6 @@
 	}
 }
 
-static inline void __end_request(struct request *rq, int uptodate,
-				 unsigned int nr_bytes)
-{
-	int error = 0;
-
-	if (uptodate <= 0)
-		error = uptodate ? uptodate : -EIO;
-
-	__blk_end_request(rq, error, nr_bytes);
-}
-
 /**
  * blk_rq_bytes - Returns bytes left to complete in the entire request
  * @rq: the request being processed
@@ -1803,92 +1820,36 @@
 EXPORT_SYMBOL_GPL(blk_rq_cur_bytes);
 
 /**
- * end_queued_request - end all I/O on a queued request
- * @rq:		the request being processed
- * @uptodate:	error value or 0/1 uptodate flag
- *
- * Description:
- *     Ends all I/O on a request, and removes it from the block layer queues.
- *     Not suitable for normal IO completion, unless the driver still has
- *     the request attached to the block layer.
- *
- **/
-void end_queued_request(struct request *rq, int uptodate)
-{
-	__end_request(rq, uptodate, blk_rq_bytes(rq));
-}
-EXPORT_SYMBOL(end_queued_request);
-
-/**
- * end_dequeued_request - end all I/O on a dequeued request
- * @rq:		the request being processed
- * @uptodate:	error value or 0/1 uptodate flag
- *
- * Description:
- *     Ends all I/O on a request. The request must already have been
- *     dequeued using blkdev_dequeue_request(), as is normally the case
- *     for most drivers.
- *
- **/
-void end_dequeued_request(struct request *rq, int uptodate)
-{
-	__end_request(rq, uptodate, blk_rq_bytes(rq));
-}
-EXPORT_SYMBOL(end_dequeued_request);
-
-
-/**
  * end_request - end I/O on the current segment of the request
  * @req:	the request being processed
- * @uptodate:	error value or 0/1 uptodate flag
+ * @uptodate:	error value or %0/%1 uptodate flag
  *
  * Description:
  *     Ends I/O on the current segment of a request. If that is the only
  *     remaining segment, the request is also completed and freed.
  *
- *     This is a remnant of how older block drivers handled IO completions.
- *     Modern drivers typically end IO on the full request in one go, unless
+ *     This is a remnant of how older block drivers handled I/O completions.
+ *     Modern drivers typically end I/O on the full request in one go, unless
  *     they have a residual value to account for. For that case this function
  *     isn't really useful, unless the residual just happens to be the
  *     full current segment. In other words, don't use this function in new
- *     code. Either use end_request_completely(), or the
- *     end_that_request_chunk() (along with end_that_request_last()) for
- *     partial completions.
- *
+ *     code. Use blk_end_request() or __blk_end_request() to end a request.
  **/
 void end_request(struct request *req, int uptodate)
 {
-	__end_request(req, uptodate, req->hard_cur_sectors << 9);
+	int error = 0;
+
+	if (uptodate <= 0)
+		error = uptodate ? uptodate : -EIO;
+
+	__blk_end_request(req, error, req->hard_cur_sectors << 9);
 }
 EXPORT_SYMBOL(end_request);
 
-/**
- * blk_end_io - Generic end_io function to complete a request.
- * @rq:           the request being processed
- * @error:        0 for success, < 0 for error
- * @nr_bytes:     number of bytes to complete @rq
- * @bidi_bytes:   number of bytes to complete @rq->next_rq
- * @drv_callback: function called between completion of bios in the request
- *                and completion of the request.
- *                If the callback returns non 0, this helper returns without
- *                completion of the request.
- *
- * Description:
- *     Ends I/O on a number of bytes attached to @rq and @rq->next_rq.
- *     If @rq has leftover, sets it up for the next range of segments.
- *
- * Return:
- *     0 - we are done with this request
- *     1 - this request is not freed yet, it still has pending buffers.
- **/
-static int blk_end_io(struct request *rq, int error, unsigned int nr_bytes,
-		      unsigned int bidi_bytes,
-		      int (drv_callback)(struct request *))
+static int end_that_request_data(struct request *rq, int error,
+				 unsigned int nr_bytes, unsigned int bidi_bytes)
 {
-	struct request_queue *q = rq->q;
-	unsigned long flags = 0UL;
-
-	if (blk_fs_request(rq) || blk_pc_request(rq)) {
+	if (rq->bio) {
 		if (__end_that_request_first(rq, error, nr_bytes))
 			return 1;
 
@@ -1898,6 +1859,38 @@
 			return 1;
 	}
 
+	return 0;
+}
+
+/**
+ * blk_end_io - Generic end_io function to complete a request.
+ * @rq:           the request being processed
+ * @error:        %0 for success, < %0 for error
+ * @nr_bytes:     number of bytes to complete @rq
+ * @bidi_bytes:   number of bytes to complete @rq->next_rq
+ * @drv_callback: function called between completion of bios in the request
+ *                and completion of the request.
+ *                If the callback returns non %0, this helper returns without
+ *                completion of the request.
+ *
+ * Description:
+ *     Ends I/O on a number of bytes attached to @rq and @rq->next_rq.
+ *     If @rq has leftover, sets it up for the next range of segments.
+ *
+ * Return:
+ *     %0 - we are done with this request
+ *     %1 - this request is not freed yet, it still has pending buffers.
+ **/
+static int blk_end_io(struct request *rq, int error, unsigned int nr_bytes,
+		      unsigned int bidi_bytes,
+		      int (drv_callback)(struct request *))
+{
+	struct request_queue *q = rq->q;
+	unsigned long flags = 0UL;
+
+	if (end_that_request_data(rq, error, nr_bytes, bidi_bytes))
+		return 1;
+
 	/* Special feature for tricky drivers */
 	if (drv_callback && drv_callback(rq))
 		return 1;
@@ -1914,7 +1907,7 @@
 /**
  * blk_end_request - Helper function for drivers to complete the request.
  * @rq:       the request being processed
- * @error:    0 for success, < 0 for error
+ * @error:    %0 for success, < %0 for error
  * @nr_bytes: number of bytes to complete
  *
  * Description:
@@ -1922,8 +1915,8 @@
  *     If @rq has leftover, sets it up for the next range of segments.
  *
  * Return:
- *     0 - we are done with this request
- *     1 - still buffers pending for this request
+ *     %0 - we are done with this request
+ *     %1 - still buffers pending for this request
  **/
 int blk_end_request(struct request *rq, int error, unsigned int nr_bytes)
 {
@@ -1934,22 +1927,20 @@
 /**
  * __blk_end_request - Helper function for drivers to complete the request.
  * @rq:       the request being processed
- * @error:    0 for success, < 0 for error
+ * @error:    %0 for success, < %0 for error
  * @nr_bytes: number of bytes to complete
  *
  * Description:
  *     Must be called with queue lock held unlike blk_end_request().
  *
  * Return:
- *     0 - we are done with this request
- *     1 - still buffers pending for this request
+ *     %0 - we are done with this request
+ *     %1 - still buffers pending for this request
  **/
 int __blk_end_request(struct request *rq, int error, unsigned int nr_bytes)
 {
-	if (blk_fs_request(rq) || blk_pc_request(rq)) {
-		if (__end_that_request_first(rq, error, nr_bytes))
-			return 1;
-	}
+	if (rq->bio && __end_that_request_first(rq, error, nr_bytes))
+		return 1;
 
 	add_disk_randomness(rq->rq_disk);
 
@@ -1962,7 +1953,7 @@
 /**
  * blk_end_bidi_request - Helper function for drivers to complete bidi request.
  * @rq:         the bidi request being processed
- * @error:      0 for success, < 0 for error
+ * @error:      %0 for success, < %0 for error
  * @nr_bytes:   number of bytes to complete @rq
  * @bidi_bytes: number of bytes to complete @rq->next_rq
  *
@@ -1970,8 +1961,8 @@
  *     Ends I/O on a number of bytes attached to @rq and @rq->next_rq.
  *
  * Return:
- *     0 - we are done with this request
- *     1 - still buffers pending for this request
+ *     %0 - we are done with this request
+ *     %1 - still buffers pending for this request
  **/
 int blk_end_bidi_request(struct request *rq, int error, unsigned int nr_bytes,
 			 unsigned int bidi_bytes)
@@ -1981,13 +1972,43 @@
 EXPORT_SYMBOL_GPL(blk_end_bidi_request);
 
 /**
+ * blk_update_request - Special helper function for request stacking drivers
+ * @rq:           the request being processed
+ * @error:        %0 for success, < %0 for error
+ * @nr_bytes:     number of bytes to complete @rq
+ *
+ * Description:
+ *     Ends I/O on a number of bytes attached to @rq, but doesn't complete
+ *     the request structure even if @rq doesn't have leftover.
+ *     If @rq has leftover, sets it up for the next range of segments.
+ *
+ *     This special helper function is only for request stacking drivers
+ *     (e.g. request-based dm) so that they can handle partial completion.
+ *     Actual device drivers should use blk_end_request instead.
+ */
+void blk_update_request(struct request *rq, int error, unsigned int nr_bytes)
+{
+	if (!end_that_request_data(rq, error, nr_bytes, 0)) {
+		/*
+		 * These members are not updated in end_that_request_data()
+		 * when all bios are completed.
+		 * Update them so that the request stacking driver can find
+		 * how many bytes remain in the request later.
+		 */
+		rq->nr_sectors = rq->hard_nr_sectors = 0;
+		rq->current_nr_sectors = rq->hard_cur_sectors = 0;
+	}
+}
+EXPORT_SYMBOL_GPL(blk_update_request);
+
+/**
  * blk_end_request_callback - Special helper function for tricky drivers
  * @rq:           the request being processed
- * @error:        0 for success, < 0 for error
+ * @error:        %0 for success, < %0 for error
  * @nr_bytes:     number of bytes to complete
  * @drv_callback: function called between completion of bios in the request
  *                and completion of the request.
- *                If the callback returns non 0, this helper returns without
+ *                If the callback returns non %0, this helper returns without
  *                completion of the request.
  *
  * Description:
@@ -2000,10 +2021,10 @@
  *     Don't use this interface in other places anymore.
  *
  * Return:
- *     0 - we are done with this request
- *     1 - this request is not freed yet.
- *         this request still has pending buffers or
- *         the driver doesn't want to finish this request yet.
+ *     %0 - we are done with this request
+ *     %1 - this request is not freed yet.
+ *          this request still has pending buffers or
+ *          the driver doesn't want to finish this request yet.
  **/
 int blk_end_request_callback(struct request *rq, int error,
 			     unsigned int nr_bytes,
@@ -2016,15 +2037,17 @@
 void blk_rq_bio_prep(struct request_queue *q, struct request *rq,
 		     struct bio *bio)
 {
-	/* first two bits are identical in rq->cmd_flags and bio->bi_rw */
+	/* Bit 0 (R/W) is identical in rq->cmd_flags and bio->bi_rw, and
+	   we want BIO_RW_AHEAD (bit 1) to imply REQ_FAILFAST (bit 1). */
 	rq->cmd_flags |= (bio->bi_rw & 3);
 
-	rq->nr_phys_segments = bio_phys_segments(q, bio);
-	rq->nr_hw_segments = bio_hw_segments(q, bio);
+	if (bio_has_data(bio)) {
+		rq->nr_phys_segments = bio_phys_segments(q, bio);
+		rq->buffer = bio_data(bio);
+	}
 	rq->current_nr_sectors = bio_cur_sectors(bio);
 	rq->hard_cur_sectors = rq->current_nr_sectors;
 	rq->hard_nr_sectors = rq->nr_sectors = bio_sectors(bio);
-	rq->buffer = bio_data(bio);
 	rq->data_len = bio->bi_size;
 
 	rq->bio = rq->biotail = bio;
@@ -2033,7 +2056,35 @@
 		rq->rq_disk = bio->bi_bdev->bd_disk;
 }
 
-int kblockd_schedule_work(struct work_struct *work)
+/**
+ * blk_lld_busy - Check if underlying low-level drivers of a device are busy
+ * @q : the queue of the device being checked
+ *
+ * Description:
+ *    Check if underlying low-level drivers of a device are busy.
+ *    If the drivers want to export their busy state, they must set own
+ *    exporting function using blk_queue_lld_busy() first.
+ *
+ *    Basically, this function is used only by request stacking drivers
+ *    to stop dispatching requests to underlying devices when underlying
+ *    devices are busy.  This behavior helps more I/O merging on the queue
+ *    of the request stacking driver and prevents I/O throughput regression
+ *    on burst I/O load.
+ *
+ * Return:
+ *    0 - Not busy (The request stacking driver should dispatch request)
+ *    1 - Busy (The request stacking driver should stop dispatching request)
+ */
+int blk_lld_busy(struct request_queue *q)
+{
+	if (q->lld_busy_fn)
+		return q->lld_busy_fn(q);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(blk_lld_busy);
+
+int kblockd_schedule_work(struct request_queue *q, struct work_struct *work)
 {
 	return queue_work(kblockd_workqueue, work);
 }
@@ -2047,8 +2098,6 @@
 
 int __init blk_dev_init(void)
 {
-	int i;
-
 	kblockd_workqueue = create_workqueue("kblockd");
 	if (!kblockd_workqueue)
 		panic("Failed to create kblockd\n");
@@ -2059,12 +2108,6 @@
 	blk_requestq_cachep = kmem_cache_create("blkdev_queue",
 			sizeof(struct request_queue), 0, SLAB_PANIC, NULL);
 
-	for_each_possible_cpu(i)
-		INIT_LIST_HEAD(&per_cpu(blk_cpu_done, i));
-
-	open_softirq(BLOCK_SOFTIRQ, blk_done_softirq);
-	register_hotcpu_notifier(&blk_cpu_notifier);
-
 	return 0;
 }
 
diff --git a/block/blk-exec.c b/block/blk-exec.c
index 9bceff7..6af716d 100644
--- a/block/blk-exec.c
+++ b/block/blk-exec.c
@@ -16,7 +16,7 @@
 /**
  * blk_end_sync_rq - executes a completion event on a request
  * @rq: request to complete
- * @error: end io status of the request
+ * @error: end I/O status of the request
  */
 static void blk_end_sync_rq(struct request *rq, int error)
 {
@@ -41,7 +41,7 @@
  * @done:	I/O completion handler
  *
  * Description:
- *    Insert a fully prepared request at the back of the io scheduler queue
+ *    Insert a fully prepared request at the back of the I/O scheduler queue
  *    for execution.  Don't wait for completion.
  */
 void blk_execute_rq_nowait(struct request_queue *q, struct gendisk *bd_disk,
@@ -72,7 +72,7 @@
  * @at_head:    insert request at head or tail of queue
  *
  * Description:
- *    Insert a fully prepared request at the back of the io scheduler queue
+ *    Insert a fully prepared request at the back of the I/O scheduler queue
  *    for execution and wait for completion.
  */
 int blk_execute_rq(struct request_queue *q, struct gendisk *bd_disk,
diff --git a/block/blk-integrity.c b/block/blk-integrity.c
index 3f1a847..61a8e2f 100644
--- a/block/blk-integrity.c
+++ b/block/blk-integrity.c
@@ -108,51 +108,51 @@
 EXPORT_SYMBOL(blk_rq_map_integrity_sg);
 
 /**
- * blk_integrity_compare - Compare integrity profile of two block devices
- * @b1:		Device to compare
- * @b2:		Device to compare
+ * blk_integrity_compare - Compare integrity profile of two disks
+ * @gd1:	Disk to compare
+ * @gd2:	Disk to compare
  *
  * Description: Meta-devices like DM and MD need to verify that all
  * sub-devices use the same integrity format before advertising to
  * upper layers that they can send/receive integrity metadata.  This
- * function can be used to check whether two block devices have
+ * function can be used to check whether two gendisk devices have
  * compatible integrity formats.
  */
-int blk_integrity_compare(struct block_device *bd1, struct block_device *bd2)
+int blk_integrity_compare(struct gendisk *gd1, struct gendisk *gd2)
 {
-	struct blk_integrity *b1 = bd1->bd_disk->integrity;
-	struct blk_integrity *b2 = bd2->bd_disk->integrity;
+	struct blk_integrity *b1 = gd1->integrity;
+	struct blk_integrity *b2 = gd2->integrity;
 
-	BUG_ON(bd1->bd_disk == NULL);
-	BUG_ON(bd2->bd_disk == NULL);
+	if (!b1 && !b2)
+		return 0;
 
 	if (!b1 || !b2)
-		return 0;
+		return -1;
 
 	if (b1->sector_size != b2->sector_size) {
 		printk(KERN_ERR "%s: %s/%s sector sz %u != %u\n", __func__,
-		       bd1->bd_disk->disk_name, bd2->bd_disk->disk_name,
+		       gd1->disk_name, gd2->disk_name,
 		       b1->sector_size, b2->sector_size);
 		return -1;
 	}
 
 	if (b1->tuple_size != b2->tuple_size) {
 		printk(KERN_ERR "%s: %s/%s tuple sz %u != %u\n", __func__,
-		       bd1->bd_disk->disk_name, bd2->bd_disk->disk_name,
+		       gd1->disk_name, gd2->disk_name,
 		       b1->tuple_size, b2->tuple_size);
 		return -1;
 	}
 
 	if (b1->tag_size && b2->tag_size && (b1->tag_size != b2->tag_size)) {
 		printk(KERN_ERR "%s: %s/%s tag sz %u != %u\n", __func__,
-		       bd1->bd_disk->disk_name, bd2->bd_disk->disk_name,
+		       gd1->disk_name, gd2->disk_name,
 		       b1->tag_size, b2->tag_size);
 		return -1;
 	}
 
 	if (strcmp(b1->name, b2->name)) {
 		printk(KERN_ERR "%s: %s/%s type %s != %s\n", __func__,
-		       bd1->bd_disk->disk_name, bd2->bd_disk->disk_name,
+		       gd1->disk_name, gd2->disk_name,
 		       b1->name, b2->name);
 		return -1;
 	}
@@ -331,7 +331,8 @@
 			return -1;
 
 		if (kobject_init_and_add(&bi->kobj, &integrity_ktype,
-					 &disk->dev.kobj, "%s", "integrity")) {
+					 &disk_to_dev(disk)->kobj,
+					 "%s", "integrity")) {
 			kmem_cache_free(integrity_cachep, bi);
 			return -1;
 		}
@@ -375,7 +376,7 @@
 
 	kobject_uevent(&bi->kobj, KOBJ_REMOVE);
 	kobject_del(&bi->kobj);
-	kobject_put(&disk->dev.kobj);
 	kmem_cache_free(integrity_cachep, bi);
+	disk->integrity = NULL;
 }
 EXPORT_SYMBOL(blk_integrity_unregister);
diff --git a/block/blk-map.c b/block/blk-map.c
index af37e4a..4849fa3 100644
--- a/block/blk-map.c
+++ b/block/blk-map.c
@@ -41,10 +41,10 @@
 }
 
 static int __blk_rq_map_user(struct request_queue *q, struct request *rq,
-			     void __user *ubuf, unsigned int len)
+			     struct rq_map_data *map_data, void __user *ubuf,
+			     unsigned int len, int null_mapped, gfp_t gfp_mask)
 {
 	unsigned long uaddr;
-	unsigned int alignment;
 	struct bio *bio, *orig_bio;
 	int reading, ret;
 
@@ -55,15 +55,17 @@
 	 * direct dma. else, set up kernel bounce buffers
 	 */
 	uaddr = (unsigned long) ubuf;
-	alignment = queue_dma_alignment(q) | q->dma_pad_mask;
-	if (!(uaddr & alignment) && !(len & alignment))
-		bio = bio_map_user(q, NULL, uaddr, len, reading);
+	if (blk_rq_aligned(q, ubuf, len) && !map_data)
+		bio = bio_map_user(q, NULL, uaddr, len, reading, gfp_mask);
 	else
-		bio = bio_copy_user(q, uaddr, len, reading);
+		bio = bio_copy_user(q, map_data, uaddr, len, reading, gfp_mask);
 
 	if (IS_ERR(bio))
 		return PTR_ERR(bio);
 
+	if (null_mapped)
+		bio->bi_flags |= (1 << BIO_NULL_MAPPED);
+
 	orig_bio = bio;
 	blk_queue_bounce(q, &bio);
 
@@ -85,17 +87,19 @@
 }
 
 /**
- * blk_rq_map_user - map user data to a request, for REQ_BLOCK_PC usage
+ * blk_rq_map_user - map user data to a request, for REQ_TYPE_BLOCK_PC usage
  * @q:		request queue where request should be inserted
  * @rq:		request structure to fill
+ * @map_data:   pointer to the rq_map_data holding pages (if necessary)
  * @ubuf:	the user buffer
  * @len:	length of user data
+ * @gfp_mask:	memory allocation flags
  *
  * Description:
- *    Data will be mapped directly for zero copy io, if possible. Otherwise
+ *    Data will be mapped directly for zero copy I/O, if possible. Otherwise
  *    a kernel bounce buffer is used.
  *
- *    A matching blk_rq_unmap_user() must be issued at the end of io, while
+ *    A matching blk_rq_unmap_user() must be issued at the end of I/O, while
  *    still in process context.
  *
  *    Note: The mapped bio may need to be bounced through blk_queue_bounce()
@@ -105,16 +109,22 @@
  *    unmapping.
  */
 int blk_rq_map_user(struct request_queue *q, struct request *rq,
-		    void __user *ubuf, unsigned long len)
+		    struct rq_map_data *map_data, void __user *ubuf,
+		    unsigned long len, gfp_t gfp_mask)
 {
 	unsigned long bytes_read = 0;
 	struct bio *bio = NULL;
-	int ret;
+	int ret, null_mapped = 0;
 
 	if (len > (q->max_hw_sectors << 9))
 		return -EINVAL;
-	if (!len || !ubuf)
+	if (!len)
 		return -EINVAL;
+	if (!ubuf) {
+		if (!map_data || rq_data_dir(rq) != READ)
+			return -EINVAL;
+		null_mapped = 1;
+	}
 
 	while (bytes_read != len) {
 		unsigned long map_len, end, start;
@@ -132,7 +142,8 @@
 		if (end - start > BIO_MAX_PAGES)
 			map_len -= PAGE_SIZE;
 
-		ret = __blk_rq_map_user(q, rq, ubuf, map_len);
+		ret = __blk_rq_map_user(q, rq, map_data, ubuf, map_len,
+					null_mapped, gfp_mask);
 		if (ret < 0)
 			goto unmap_rq;
 		if (!bio)
@@ -154,18 +165,20 @@
 EXPORT_SYMBOL(blk_rq_map_user);
 
 /**
- * blk_rq_map_user_iov - map user data to a request, for REQ_BLOCK_PC usage
+ * blk_rq_map_user_iov - map user data to a request, for REQ_TYPE_BLOCK_PC usage
  * @q:		request queue where request should be inserted
  * @rq:		request to map data to
+ * @map_data:   pointer to the rq_map_data holding pages (if necessary)
  * @iov:	pointer to the iovec
  * @iov_count:	number of elements in the iovec
  * @len:	I/O byte count
+ * @gfp_mask:	memory allocation flags
  *
  * Description:
- *    Data will be mapped directly for zero copy io, if possible. Otherwise
+ *    Data will be mapped directly for zero copy I/O, if possible. Otherwise
  *    a kernel bounce buffer is used.
  *
- *    A matching blk_rq_unmap_user() must be issued at the end of io, while
+ *    A matching blk_rq_unmap_user() must be issued at the end of I/O, while
  *    still in process context.
  *
  *    Note: The mapped bio may need to be bounced through blk_queue_bounce()
@@ -175,7 +188,8 @@
  *    unmapping.
  */
 int blk_rq_map_user_iov(struct request_queue *q, struct request *rq,
-			struct sg_iovec *iov, int iov_count, unsigned int len)
+			struct rq_map_data *map_data, struct sg_iovec *iov,
+			int iov_count, unsigned int len, gfp_t gfp_mask)
 {
 	struct bio *bio;
 	int i, read = rq_data_dir(rq) == READ;
@@ -193,10 +207,11 @@
 		}
 	}
 
-	if (unaligned || (q->dma_pad_mask & len))
-		bio = bio_copy_user_iov(q, iov, iov_count, read);
+	if (unaligned || (q->dma_pad_mask & len) || map_data)
+		bio = bio_copy_user_iov(q, map_data, iov, iov_count, read,
+					gfp_mask);
 	else
-		bio = bio_map_user_iov(q, NULL, iov, iov_count, read);
+		bio = bio_map_user_iov(q, NULL, iov, iov_count, read, gfp_mask);
 
 	if (IS_ERR(bio))
 		return PTR_ERR(bio);
@@ -216,6 +231,7 @@
 	rq->buffer = rq->data = NULL;
 	return 0;
 }
+EXPORT_SYMBOL(blk_rq_map_user_iov);
 
 /**
  * blk_rq_unmap_user - unmap a request with user data
@@ -224,7 +240,7 @@
  * Description:
  *    Unmap a rq previously mapped by blk_rq_map_user(). The caller must
  *    supply the original rq->bio from the blk_rq_map_user() return, since
- *    the io completion may have changed rq->bio.
+ *    the I/O completion may have changed rq->bio.
  */
 int blk_rq_unmap_user(struct bio *bio)
 {
@@ -250,7 +266,7 @@
 EXPORT_SYMBOL(blk_rq_unmap_user);
 
 /**
- * blk_rq_map_kern - map kernel data to a request, for REQ_BLOCK_PC usage
+ * blk_rq_map_kern - map kernel data to a request, for REQ_TYPE_BLOCK_PC usage
  * @q:		request queue where request should be inserted
  * @rq:		request to fill
  * @kbuf:	the kernel buffer
@@ -264,8 +280,6 @@
 int blk_rq_map_kern(struct request_queue *q, struct request *rq, void *kbuf,
 		    unsigned int len, gfp_t gfp_mask)
 {
-	unsigned long kaddr;
-	unsigned int alignment;
 	int reading = rq_data_dir(rq) == READ;
 	int do_copy = 0;
 	struct bio *bio;
@@ -275,11 +289,7 @@
 	if (!len || !kbuf)
 		return -EINVAL;
 
-	kaddr = (unsigned long)kbuf;
-	alignment = queue_dma_alignment(q) | q->dma_pad_mask;
-	do_copy = ((kaddr & alignment) || (len & alignment) ||
-		   object_is_on_stack(kbuf));
-
+	do_copy = !blk_rq_aligned(q, kbuf, len) || object_is_on_stack(kbuf);
 	if (do_copy)
 		bio = bio_copy_kern(q, kbuf, len, gfp_mask, reading);
 	else
diff --git a/block/blk-merge.c b/block/blk-merge.c
index 5efc9e7..908d3e1 100644
--- a/block/blk-merge.c
+++ b/block/blk-merge.c
@@ -11,7 +11,7 @@
 
 void blk_recalc_rq_sectors(struct request *rq, int nsect)
 {
-	if (blk_fs_request(rq)) {
+	if (blk_fs_request(rq) || blk_discard_rq(rq)) {
 		rq->hard_sector += nsect;
 		rq->hard_nr_sectors -= nsect;
 
@@ -41,12 +41,9 @@
 void blk_recalc_rq_segments(struct request *rq)
 {
 	int nr_phys_segs;
-	int nr_hw_segs;
 	unsigned int phys_size;
-	unsigned int hw_size;
 	struct bio_vec *bv, *bvprv = NULL;
 	int seg_size;
-	int hw_seg_size;
 	int cluster;
 	struct req_iterator iter;
 	int high, highprv = 1;
@@ -56,8 +53,8 @@
 		return;
 
 	cluster = test_bit(QUEUE_FLAG_CLUSTER, &q->queue_flags);
-	hw_seg_size = seg_size = 0;
-	phys_size = hw_size = nr_phys_segs = nr_hw_segs = 0;
+	seg_size = 0;
+	phys_size = nr_phys_segs = 0;
 	rq_for_each_segment(bv, rq, iter) {
 		/*
 		 * the trick here is making sure that a high page is never
@@ -66,7 +63,7 @@
 		 */
 		high = page_to_pfn(bv->bv_page) > q->bounce_pfn;
 		if (high || highprv)
-			goto new_hw_segment;
+			goto new_segment;
 		if (cluster) {
 			if (seg_size + bv->bv_len > q->max_segment_size)
 				goto new_segment;
@@ -74,40 +71,19 @@
 				goto new_segment;
 			if (!BIOVEC_SEG_BOUNDARY(q, bvprv, bv))
 				goto new_segment;
-			if (BIOVEC_VIRT_OVERSIZE(hw_seg_size + bv->bv_len))
-				goto new_hw_segment;
 
 			seg_size += bv->bv_len;
-			hw_seg_size += bv->bv_len;
 			bvprv = bv;
 			continue;
 		}
 new_segment:
-		if (BIOVEC_VIRT_MERGEABLE(bvprv, bv) &&
-		    !BIOVEC_VIRT_OVERSIZE(hw_seg_size + bv->bv_len))
-			hw_seg_size += bv->bv_len;
-		else {
-new_hw_segment:
-			if (nr_hw_segs == 1 &&
-			    hw_seg_size > rq->bio->bi_hw_front_size)
-				rq->bio->bi_hw_front_size = hw_seg_size;
-			hw_seg_size = BIOVEC_VIRT_START_SIZE(bv) + bv->bv_len;
-			nr_hw_segs++;
-		}
-
 		nr_phys_segs++;
 		bvprv = bv;
 		seg_size = bv->bv_len;
 		highprv = high;
 	}
 
-	if (nr_hw_segs == 1 &&
-	    hw_seg_size > rq->bio->bi_hw_front_size)
-		rq->bio->bi_hw_front_size = hw_seg_size;
-	if (hw_seg_size > rq->biotail->bi_hw_back_size)
-		rq->biotail->bi_hw_back_size = hw_seg_size;
 	rq->nr_phys_segments = nr_phys_segs;
-	rq->nr_hw_segments = nr_hw_segs;
 }
 
 void blk_recount_segments(struct request_queue *q, struct bio *bio)
@@ -120,7 +96,6 @@
 	blk_recalc_rq_segments(&rq);
 	bio->bi_next = nxt;
 	bio->bi_phys_segments = rq.nr_phys_segments;
-	bio->bi_hw_segments = rq.nr_hw_segments;
 	bio->bi_flags |= (1 << BIO_SEG_VALID);
 }
 EXPORT_SYMBOL(blk_recount_segments);
@@ -131,13 +106,17 @@
 	if (!test_bit(QUEUE_FLAG_CLUSTER, &q->queue_flags))
 		return 0;
 
-	if (!BIOVEC_PHYS_MERGEABLE(__BVEC_END(bio), __BVEC_START(nxt)))
-		return 0;
 	if (bio->bi_size + nxt->bi_size > q->max_segment_size)
 		return 0;
 
+	if (!bio_has_data(bio))
+		return 1;
+
+	if (!BIOVEC_PHYS_MERGEABLE(__BVEC_END(bio), __BVEC_START(nxt)))
+		return 0;
+
 	/*
-	 * bio and nxt are contigous in memory, check if the queue allows
+	 * bio and nxt are contiguous in memory; check if the queue allows
 	 * these two to be merged into one
 	 */
 	if (BIO_SEG_BOUNDARY(q, bio, nxt))
@@ -146,22 +125,6 @@
 	return 0;
 }
 
-static int blk_hw_contig_segment(struct request_queue *q, struct bio *bio,
-				 struct bio *nxt)
-{
-	if (!bio_flagged(bio, BIO_SEG_VALID))
-		blk_recount_segments(q, bio);
-	if (!bio_flagged(nxt, BIO_SEG_VALID))
-		blk_recount_segments(q, nxt);
-	if (!BIOVEC_VIRT_MERGEABLE(__BVEC_END(bio), __BVEC_START(nxt)) ||
-	    BIOVEC_VIRT_OVERSIZE(bio->bi_hw_back_size + nxt->bi_hw_front_size))
-		return 0;
-	if (bio->bi_hw_back_size + nxt->bi_hw_front_size > q->max_segment_size)
-		return 0;
-
-	return 1;
-}
-
 /*
  * map a request to scatterlist, return number of sg entries setup. Caller
  * must make sure sg can hold rq->nr_phys_segments entries
@@ -275,10 +238,9 @@
 				    struct request *req,
 				    struct bio *bio)
 {
-	int nr_hw_segs = bio_hw_segments(q, bio);
 	int nr_phys_segs = bio_phys_segments(q, bio);
 
-	if (req->nr_hw_segments + nr_hw_segs > q->max_hw_segments
+	if (req->nr_phys_segments + nr_phys_segs > q->max_hw_segments
 	    || req->nr_phys_segments + nr_phys_segs > q->max_phys_segments) {
 		req->cmd_flags |= REQ_NOMERGE;
 		if (req == q->last_merge)
@@ -290,7 +252,6 @@
 	 * This will form the start of a new hw segment.  Bump both
 	 * counters.
 	 */
-	req->nr_hw_segments += nr_hw_segs;
 	req->nr_phys_segments += nr_phys_segs;
 	return 1;
 }
@@ -299,7 +260,6 @@
 		     struct bio *bio)
 {
 	unsigned short max_sectors;
-	int len;
 
 	if (unlikely(blk_pc_request(req)))
 		max_sectors = q->max_hw_sectors;
@@ -316,19 +276,6 @@
 		blk_recount_segments(q, req->biotail);
 	if (!bio_flagged(bio, BIO_SEG_VALID))
 		blk_recount_segments(q, bio);
-	len = req->biotail->bi_hw_back_size + bio->bi_hw_front_size;
-	if (BIOVEC_VIRT_MERGEABLE(__BVEC_END(req->biotail), __BVEC_START(bio))
-	    && !BIOVEC_VIRT_OVERSIZE(len)) {
-		int mergeable =  ll_new_mergeable(q, req, bio);
-
-		if (mergeable) {
-			if (req->nr_hw_segments == 1)
-				req->bio->bi_hw_front_size = len;
-			if (bio->bi_hw_segments == 1)
-				bio->bi_hw_back_size = len;
-		}
-		return mergeable;
-	}
 
 	return ll_new_hw_segment(q, req, bio);
 }
@@ -337,7 +284,6 @@
 		      struct bio *bio)
 {
 	unsigned short max_sectors;
-	int len;
 
 	if (unlikely(blk_pc_request(req)))
 		max_sectors = q->max_hw_sectors;
@@ -351,23 +297,10 @@
 			q->last_merge = NULL;
 		return 0;
 	}
-	len = bio->bi_hw_back_size + req->bio->bi_hw_front_size;
 	if (!bio_flagged(bio, BIO_SEG_VALID))
 		blk_recount_segments(q, bio);
 	if (!bio_flagged(req->bio, BIO_SEG_VALID))
 		blk_recount_segments(q, req->bio);
-	if (BIOVEC_VIRT_MERGEABLE(__BVEC_END(bio), __BVEC_START(req->bio)) &&
-	    !BIOVEC_VIRT_OVERSIZE(len)) {
-		int mergeable =  ll_new_mergeable(q, req, bio);
-
-		if (mergeable) {
-			if (bio->bi_hw_segments == 1)
-				bio->bi_hw_front_size = len;
-			if (req->nr_hw_segments == 1)
-				req->biotail->bi_hw_back_size = len;
-		}
-		return mergeable;
-	}
 
 	return ll_new_hw_segment(q, req, bio);
 }
@@ -376,7 +309,6 @@
 				struct request *next)
 {
 	int total_phys_segments;
-	int total_hw_segments;
 
 	/*
 	 * First check if the either of the requests are re-queued
@@ -398,26 +330,11 @@
 	if (total_phys_segments > q->max_phys_segments)
 		return 0;
 
-	total_hw_segments = req->nr_hw_segments + next->nr_hw_segments;
-	if (blk_hw_contig_segment(q, req->biotail, next->bio)) {
-		int len = req->biotail->bi_hw_back_size +
-				next->bio->bi_hw_front_size;
-		/*
-		 * propagate the combined length to the end of the requests
-		 */
-		if (req->nr_hw_segments == 1)
-			req->bio->bi_hw_front_size = len;
-		if (next->nr_hw_segments == 1)
-			next->biotail->bi_hw_back_size = len;
-		total_hw_segments--;
-	}
-
-	if (total_hw_segments > q->max_hw_segments)
+	if (total_phys_segments > q->max_hw_segments)
 		return 0;
 
 	/* Merge is OK... */
 	req->nr_phys_segments = total_phys_segments;
-	req->nr_hw_segments = total_hw_segments;
 	return 1;
 }
 
@@ -470,17 +387,21 @@
 	elv_merge_requests(q, req, next);
 
 	if (req->rq_disk) {
-		struct hd_struct *part
-			= get_part(req->rq_disk, req->sector);
-		disk_round_stats(req->rq_disk);
-		req->rq_disk->in_flight--;
-		if (part) {
-			part_round_stats(part);
-			part->in_flight--;
-		}
+		struct hd_struct *part;
+		int cpu;
+
+		cpu = part_stat_lock();
+		part = disk_map_sector_rcu(req->rq_disk, req->sector);
+
+		part_round_stats(cpu, part);
+		part_dec_in_flight(part);
+
+		part_stat_unlock();
 	}
 
 	req->ioprio = ioprio_best(req->ioprio, next->ioprio);
+	if (blk_rq_cpu_valid(next))
+		req->cpu = next->cpu;
 
 	__blk_put_request(q, next);
 	return 1;
diff --git a/block/blk-settings.c b/block/blk-settings.c
index dfc7701..b21dcdb 100644
--- a/block/blk-settings.c
+++ b/block/blk-settings.c
@@ -33,6 +33,23 @@
 EXPORT_SYMBOL(blk_queue_prep_rq);
 
 /**
+ * blk_queue_set_discard - set a discard_sectors function for queue
+ * @q:		queue
+ * @dfn:	prepare_discard function
+ *
+ * It's possible for a queue to register a discard callback which is used
+ * to transform a discard request into the appropriate type for the
+ * hardware. If none is registered, then discard requests are failed
+ * with %EOPNOTSUPP.
+ *
+ */
+void blk_queue_set_discard(struct request_queue *q, prepare_discard_fn *dfn)
+{
+	q->prepare_discard_fn = dfn;
+}
+EXPORT_SYMBOL(blk_queue_set_discard);
+
+/**
  * blk_queue_merge_bvec - set a merge_bvec function for queue
  * @q:		queue
  * @mbfn:	merge_bvec_fn
@@ -60,6 +77,24 @@
 }
 EXPORT_SYMBOL(blk_queue_softirq_done);
 
+void blk_queue_rq_timeout(struct request_queue *q, unsigned int timeout)
+{
+	q->rq_timeout = timeout;
+}
+EXPORT_SYMBOL_GPL(blk_queue_rq_timeout);
+
+void blk_queue_rq_timed_out(struct request_queue *q, rq_timed_out_fn *fn)
+{
+	q->rq_timed_out_fn = fn;
+}
+EXPORT_SYMBOL_GPL(blk_queue_rq_timed_out);
+
+void blk_queue_lld_busy(struct request_queue *q, lld_busy_fn *fn)
+{
+	q->lld_busy_fn = fn;
+}
+EXPORT_SYMBOL_GPL(blk_queue_lld_busy);
+
 /**
  * blk_queue_make_request - define an alternate make_request function for a device
  * @q:  the request queue for the device to be affected
@@ -127,7 +162,7 @@
  *    Different hardware can have different requirements as to what pages
  *    it can do I/O directly to. A low level driver can call
  *    blk_queue_bounce_limit to have lower memory pages allocated as bounce
- *    buffers for doing I/O to pages residing above @page.
+ *    buffers for doing I/O to pages residing above @dma_addr.
  **/
 void blk_queue_bounce_limit(struct request_queue *q, u64 dma_addr)
 {
@@ -212,7 +247,7 @@
  * Description:
  *    Enables a low level driver to set an upper limit on the number of
  *    hw data segments in a request.  This would be the largest number of
- *    address/length pairs the host adapter can actually give as once
+ *    address/length pairs the host adapter can actually give at once
  *    to the device.
  **/
 void blk_queue_max_hw_segments(struct request_queue *q,
@@ -393,7 +428,7 @@
  * @mask:  alignment mask
  *
  * description:
- *    set required memory and length aligment for direct dma transactions.
+ *    set required memory and length alignment for direct dma transactions.
  *    this is used when buiding direct io requests for the queue.
  *
  **/
@@ -409,7 +444,7 @@
  * @mask:  alignment mask
  *
  * description:
- *    update required memory and length aligment for direct dma transactions.
+ *    update required memory and length alignment for direct dma transactions.
  *    If the requested alignment is larger than the current alignment, then
  *    the current queue alignment is updated to the new value, otherwise it
  *    is left alone.  The design of this is to allow multiple objects
diff --git a/block/blk-softirq.c b/block/blk-softirq.c
new file mode 100644
index 0000000..e660d26
--- /dev/null
+++ b/block/blk-softirq.c
@@ -0,0 +1,175 @@
+/*
+ * Functions related to softirq rq completions
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/bio.h>
+#include <linux/blkdev.h>
+#include <linux/interrupt.h>
+#include <linux/cpu.h>
+
+#include "blk.h"
+
+static DEFINE_PER_CPU(struct list_head, blk_cpu_done);
+
+/*
+ * Softirq action handler - move entries to local list and loop over them
+ * while passing them to the queue registered handler.
+ */
+static void blk_done_softirq(struct softirq_action *h)
+{
+	struct list_head *cpu_list, local_list;
+
+	local_irq_disable();
+	cpu_list = &__get_cpu_var(blk_cpu_done);
+	list_replace_init(cpu_list, &local_list);
+	local_irq_enable();
+
+	while (!list_empty(&local_list)) {
+		struct request *rq;
+
+		rq = list_entry(local_list.next, struct request, csd.list);
+		list_del_init(&rq->csd.list);
+		rq->q->softirq_done_fn(rq);
+	}
+}
+
+#if defined(CONFIG_SMP) && defined(CONFIG_USE_GENERIC_SMP_HELPERS)
+static void trigger_softirq(void *data)
+{
+	struct request *rq = data;
+	unsigned long flags;
+	struct list_head *list;
+
+	local_irq_save(flags);
+	list = &__get_cpu_var(blk_cpu_done);
+	list_add_tail(&rq->csd.list, list);
+
+	if (list->next == &rq->csd.list)
+		raise_softirq_irqoff(BLOCK_SOFTIRQ);
+
+	local_irq_restore(flags);
+}
+
+/*
+ * Setup and invoke a run of 'trigger_softirq' on the given cpu.
+ */
+static int raise_blk_irq(int cpu, struct request *rq)
+{
+	if (cpu_online(cpu)) {
+		struct call_single_data *data = &rq->csd;
+
+		data->func = trigger_softirq;
+		data->info = rq;
+		data->flags = 0;
+
+		__smp_call_function_single(cpu, data);
+		return 0;
+	}
+
+	return 1;
+}
+#else /* CONFIG_SMP && CONFIG_USE_GENERIC_SMP_HELPERS */
+static int raise_blk_irq(int cpu, struct request *rq)
+{
+	return 1;
+}
+#endif
+
+static int __cpuinit blk_cpu_notify(struct notifier_block *self,
+				    unsigned long action, void *hcpu)
+{
+	/*
+	 * If a CPU goes away, splice its entries to the current CPU
+	 * and trigger a run of the softirq
+	 */
+	if (action == CPU_DEAD || action == CPU_DEAD_FROZEN) {
+		int cpu = (unsigned long) hcpu;
+
+		local_irq_disable();
+		list_splice_init(&per_cpu(blk_cpu_done, cpu),
+				 &__get_cpu_var(blk_cpu_done));
+		raise_softirq_irqoff(BLOCK_SOFTIRQ);
+		local_irq_enable();
+	}
+
+	return NOTIFY_OK;
+}
+
+static struct notifier_block __cpuinitdata blk_cpu_notifier = {
+	.notifier_call	= blk_cpu_notify,
+};
+
+void __blk_complete_request(struct request *req)
+{
+	struct request_queue *q = req->q;
+	unsigned long flags;
+	int ccpu, cpu, group_cpu;
+
+	BUG_ON(!q->softirq_done_fn);
+
+	local_irq_save(flags);
+	cpu = smp_processor_id();
+	group_cpu = blk_cpu_to_group(cpu);
+
+	/*
+	 * Select completion CPU
+	 */
+	if (test_bit(QUEUE_FLAG_SAME_COMP, &q->queue_flags) && req->cpu != -1)
+		ccpu = req->cpu;
+	else
+		ccpu = cpu;
+
+	if (ccpu == cpu || ccpu == group_cpu) {
+		struct list_head *list;
+do_local:
+		list = &__get_cpu_var(blk_cpu_done);
+		list_add_tail(&req->csd.list, list);
+
+		/*
+		 * if the list only contains our just added request,
+		 * signal a raise of the softirq. If there are already
+		 * entries there, someone already raised the irq but it
+		 * hasn't run yet.
+		 */
+		if (list->next == &req->csd.list)
+			raise_softirq_irqoff(BLOCK_SOFTIRQ);
+	} else if (raise_blk_irq(ccpu, req))
+		goto do_local;
+
+	local_irq_restore(flags);
+}
+
+/**
+ * blk_complete_request - end I/O on a request
+ * @req:      the request being processed
+ *
+ * Description:
+ *     Ends all I/O on a request. It does not handle partial completions,
+ *     unless the driver actually implements this in its completion callback
+ *     through requeueing. The actual completion happens out-of-order,
+ *     through a softirq handler. The user must have registered a completion
+ *     callback through blk_queue_softirq_done().
+ **/
+void blk_complete_request(struct request *req)
+{
+	if (unlikely(blk_should_fake_timeout(req->q)))
+		return;
+	if (!blk_mark_rq_complete(req))
+		__blk_complete_request(req);
+}
+EXPORT_SYMBOL(blk_complete_request);
+
+__init int blk_softirq_init(void)
+{
+	int i;
+
+	for_each_possible_cpu(i)
+		INIT_LIST_HEAD(&per_cpu(blk_cpu_done, i));
+
+	open_softirq(BLOCK_SOFTIRQ, blk_done_softirq);
+	register_hotcpu_notifier(&blk_cpu_notifier);
+	return 0;
+}
+subsys_initcall(blk_softirq_init);
diff --git a/block/blk-sysfs.c b/block/blk-sysfs.c
index 304ec73..21e275d 100644
--- a/block/blk-sysfs.c
+++ b/block/blk-sysfs.c
@@ -156,6 +156,30 @@
 	return ret;
 }
 
+static ssize_t queue_rq_affinity_show(struct request_queue *q, char *page)
+{
+	unsigned int set = test_bit(QUEUE_FLAG_SAME_COMP, &q->queue_flags);
+
+	return queue_var_show(set != 0, page);
+}
+
+static ssize_t
+queue_rq_affinity_store(struct request_queue *q, const char *page, size_t count)
+{
+	ssize_t ret = -EINVAL;
+#if defined(CONFIG_USE_GENERIC_SMP_HELPERS)
+	unsigned long val;
+
+	ret = queue_var_store(&val, page, count);
+	spin_lock_irq(q->queue_lock);
+	if (val)
+		queue_flag_set(QUEUE_FLAG_SAME_COMP, q);
+	else
+		queue_flag_clear(QUEUE_FLAG_SAME_COMP,  q);
+	spin_unlock_irq(q->queue_lock);
+#endif
+	return ret;
+}
 
 static struct queue_sysfs_entry queue_requests_entry = {
 	.attr = {.name = "nr_requests", .mode = S_IRUGO | S_IWUSR },
@@ -197,6 +221,12 @@
 	.store = queue_nomerges_store,
 };
 
+static struct queue_sysfs_entry queue_rq_affinity_entry = {
+	.attr = {.name = "rq_affinity", .mode = S_IRUGO | S_IWUSR },
+	.show = queue_rq_affinity_show,
+	.store = queue_rq_affinity_store,
+};
+
 static struct attribute *default_attrs[] = {
 	&queue_requests_entry.attr,
 	&queue_ra_entry.attr,
@@ -205,6 +235,7 @@
 	&queue_iosched_entry.attr,
 	&queue_hw_sector_size_entry.attr,
 	&queue_nomerges_entry.attr,
+	&queue_rq_affinity_entry.attr,
 	NULL,
 };
 
@@ -310,7 +341,7 @@
 	if (!q->request_fn)
 		return 0;
 
-	ret = kobject_add(&q->kobj, kobject_get(&disk->dev.kobj),
+	ret = kobject_add(&q->kobj, kobject_get(&disk_to_dev(disk)->kobj),
 			  "%s", "queue");
 	if (ret < 0)
 		return ret;
@@ -339,6 +370,6 @@
 
 		kobject_uevent(&q->kobj, KOBJ_REMOVE);
 		kobject_del(&q->kobj);
-		kobject_put(&disk->dev.kobj);
+		kobject_put(&disk_to_dev(disk)->kobj);
 	}
 }
diff --git a/block/blk-tag.c b/block/blk-tag.c
index ed5166f..c0d419e 100644
--- a/block/blk-tag.c
+++ b/block/blk-tag.c
@@ -29,7 +29,7 @@
  * __blk_free_tags - release a given set of tag maintenance info
  * @bqt:	the tag map to free
  *
- * Tries to free the specified @bqt@.  Returns true if it was
+ * Tries to free the specified @bqt.  Returns true if it was
  * actually freed and false if there are still references using it
  */
 static int __blk_free_tags(struct blk_queue_tag *bqt)
@@ -78,7 +78,7 @@
  * blk_free_tags - release a given set of tag maintenance info
  * @bqt:	the tag map to free
  *
- * For externally managed @bqt@ frees the map.  Callers of this
+ * For externally managed @bqt frees the map.  Callers of this
  * function must guarantee to have released all the queues that
  * might have been using this tag map.
  */
@@ -94,7 +94,7 @@
  * @q:  the request queue for the device
  *
  *  Notes:
- *	This is used to disabled tagged queuing to a device, yet leave
+ *	This is used to disable tagged queuing to a device, yet leave
  *	queue in function.
  **/
 void blk_queue_free_tags(struct request_queue *q)
@@ -271,7 +271,7 @@
  * @rq: the request that has completed
  *
  *  Description:
- *    Typically called when end_that_request_first() returns 0, meaning
+ *    Typically called when end_that_request_first() returns %0, meaning
  *    all transfers have been done for a request. It's important to call
  *    this function before end_that_request_last(), as that will put the
  *    request back on the free list thus corrupting the internal tag list.
@@ -337,6 +337,7 @@
 int blk_queue_start_tag(struct request_queue *q, struct request *rq)
 {
 	struct blk_queue_tag *bqt = q->queue_tags;
+	unsigned max_depth, offset;
 	int tag;
 
 	if (unlikely((rq->cmd_flags & REQ_QUEUED))) {
@@ -350,10 +351,19 @@
 	/*
 	 * Protect against shared tag maps, as we may not have exclusive
 	 * access to the tag map.
+	 *
+	 * We reserve a few tags just for sync IO, since we don't want
+	 * to starve sync IO on behalf of flooding async IO.
 	 */
+	max_depth = bqt->max_depth;
+	if (rq_is_sync(rq))
+		offset = 0;
+	else
+		offset = max_depth >> 2;
+
 	do {
-		tag = find_first_zero_bit(bqt->tag_map, bqt->max_depth);
-		if (tag >= bqt->max_depth)
+		tag = find_next_zero_bit(bqt->tag_map, max_depth, offset);
+		if (tag >= max_depth)
 			return 1;
 
 	} while (test_and_set_bit_lock(tag, bqt->tag_map));
diff --git a/block/blk-timeout.c b/block/blk-timeout.c
new file mode 100644
index 0000000..972a63f
--- /dev/null
+++ b/block/blk-timeout.c
@@ -0,0 +1,238 @@
+/*
+ * Functions related to generic timeout handling of requests.
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/blkdev.h>
+#include <linux/fault-inject.h>
+
+#include "blk.h"
+
+#ifdef CONFIG_FAIL_IO_TIMEOUT
+
+static DECLARE_FAULT_ATTR(fail_io_timeout);
+
+static int __init setup_fail_io_timeout(char *str)
+{
+	return setup_fault_attr(&fail_io_timeout, str);
+}
+__setup("fail_io_timeout=", setup_fail_io_timeout);
+
+int blk_should_fake_timeout(struct request_queue *q)
+{
+	if (!test_bit(QUEUE_FLAG_FAIL_IO, &q->queue_flags))
+		return 0;
+
+	return should_fail(&fail_io_timeout, 1);
+}
+
+static int __init fail_io_timeout_debugfs(void)
+{
+	return init_fault_attr_dentries(&fail_io_timeout, "fail_io_timeout");
+}
+
+late_initcall(fail_io_timeout_debugfs);
+
+ssize_t part_timeout_show(struct device *dev, struct device_attribute *attr,
+			  char *buf)
+{
+	struct gendisk *disk = dev_to_disk(dev);
+	int set = test_bit(QUEUE_FLAG_FAIL_IO, &disk->queue->queue_flags);
+
+	return sprintf(buf, "%d\n", set != 0);
+}
+
+ssize_t part_timeout_store(struct device *dev, struct device_attribute *attr,
+			   const char *buf, size_t count)
+{
+	struct gendisk *disk = dev_to_disk(dev);
+	int val;
+
+	if (count) {
+		struct request_queue *q = disk->queue;
+		char *p = (char *) buf;
+
+		val = simple_strtoul(p, &p, 10);
+		spin_lock_irq(q->queue_lock);
+		if (val)
+			queue_flag_set(QUEUE_FLAG_FAIL_IO, q);
+		else
+			queue_flag_clear(QUEUE_FLAG_FAIL_IO, q);
+		spin_unlock_irq(q->queue_lock);
+	}
+
+	return count;
+}
+
+#endif /* CONFIG_FAIL_IO_TIMEOUT */
+
+/*
+ * blk_delete_timer - Delete/cancel timer for a given function.
+ * @req:	request that we are canceling timer for
+ *
+ */
+void blk_delete_timer(struct request *req)
+{
+	struct request_queue *q = req->q;
+
+	/*
+	 * Nothing to detach
+	 */
+	if (!q->rq_timed_out_fn || !req->deadline)
+		return;
+
+	list_del_init(&req->timeout_list);
+
+	if (list_empty(&q->timeout_list))
+		del_timer(&q->timeout);
+}
+
+static void blk_rq_timed_out(struct request *req)
+{
+	struct request_queue *q = req->q;
+	enum blk_eh_timer_return ret;
+
+	ret = q->rq_timed_out_fn(req);
+	switch (ret) {
+	case BLK_EH_HANDLED:
+		__blk_complete_request(req);
+		break;
+	case BLK_EH_RESET_TIMER:
+		blk_clear_rq_complete(req);
+		blk_add_timer(req);
+		break;
+	case BLK_EH_NOT_HANDLED:
+		/*
+		 * LLD handles this for now but in the future
+		 * we can send a request msg to abort the command
+		 * and we can move more of the generic scsi eh code to
+		 * the blk layer.
+		 */
+		break;
+	default:
+		printk(KERN_ERR "block: bad eh return: %d\n", ret);
+		break;
+	}
+}
+
+void blk_rq_timed_out_timer(unsigned long data)
+{
+	struct request_queue *q = (struct request_queue *) data;
+	unsigned long flags, uninitialized_var(next), next_set = 0;
+	struct request *rq, *tmp;
+
+	spin_lock_irqsave(q->queue_lock, flags);
+
+	list_for_each_entry_safe(rq, tmp, &q->timeout_list, timeout_list) {
+		if (time_after_eq(jiffies, rq->deadline)) {
+			list_del_init(&rq->timeout_list);
+
+			/*
+			 * Check if we raced with end io completion
+			 */
+			if (blk_mark_rq_complete(rq))
+				continue;
+			blk_rq_timed_out(rq);
+		}
+		if (!next_set) {
+			next = rq->deadline;
+			next_set = 1;
+		} else if (time_after(next, rq->deadline))
+			next = rq->deadline;
+	}
+
+	if (next_set && !list_empty(&q->timeout_list))
+		mod_timer(&q->timeout, round_jiffies(next));
+
+	spin_unlock_irqrestore(q->queue_lock, flags);
+}
+
+/**
+ * blk_abort_request -- Request request recovery for the specified command
+ * @req:	pointer to the request of interest
+ *
+ * This function requests that the block layer start recovery for the
+ * request by deleting the timer and calling the q's timeout function.
+ * LLDDs who implement their own error recovery MAY ignore the timeout
+ * event if they generated blk_abort_req. Must hold queue lock.
+ */
+void blk_abort_request(struct request *req)
+{
+	if (blk_mark_rq_complete(req))
+		return;
+	blk_delete_timer(req);
+	blk_rq_timed_out(req);
+}
+EXPORT_SYMBOL_GPL(blk_abort_request);
+
+/**
+ * blk_add_timer - Start timeout timer for a single request
+ * @req:	request that is about to start running.
+ *
+ * Notes:
+ *    Each request has its own timer, and as it is added to the queue, we
+ *    set up the timer. When the request completes, we cancel the timer.
+ */
+void blk_add_timer(struct request *req)
+{
+	struct request_queue *q = req->q;
+	unsigned long expiry;
+
+	if (!q->rq_timed_out_fn)
+		return;
+
+	BUG_ON(!list_empty(&req->timeout_list));
+	BUG_ON(test_bit(REQ_ATOM_COMPLETE, &req->atomic_flags));
+
+	if (req->timeout)
+		req->deadline = jiffies + req->timeout;
+	else {
+		req->deadline = jiffies + q->rq_timeout;
+		/*
+		 * Some LLDs, like scsi, peek at the timeout to prevent
+		 * a command from being retried forever.
+		 */
+		req->timeout = q->rq_timeout;
+	}
+	list_add_tail(&req->timeout_list, &q->timeout_list);
+
+	/*
+	 * If the timer isn't already pending or this timeout is earlier
+	 * than an existing one, modify the timer. Round to next nearest
+	 * second.
+	 */
+	expiry = round_jiffies(req->deadline);
+
+	/*
+	 * We use ->deadline == 0 to detect whether a timer was added or
+	 * not, so just increase to next jiffy for that specific case
+	 */
+	if (unlikely(!req->deadline))
+		req->deadline = 1;
+
+	if (!timer_pending(&q->timeout) ||
+	    time_before(expiry, q->timeout.expires))
+		mod_timer(&q->timeout, expiry);
+}
+
+/**
+ * blk_abort_queue -- Abort all request on given queue
+ * @queue:	pointer to queue
+ *
+ */
+void blk_abort_queue(struct request_queue *q)
+{
+	unsigned long flags;
+	struct request *rq, *tmp;
+
+	spin_lock_irqsave(q->queue_lock, flags);
+
+	elv_abort_queue(q);
+
+	list_for_each_entry_safe(rq, tmp, &q->timeout_list, timeout_list)
+		blk_abort_request(rq);
+
+	spin_unlock_irqrestore(q->queue_lock, flags);
+
+}
+EXPORT_SYMBOL_GPL(blk_abort_queue);
diff --git a/block/blk.h b/block/blk.h
index c79f30e..e5c5797 100644
--- a/block/blk.h
+++ b/block/blk.h
@@ -17,6 +17,42 @@
 
 void blk_unplug_work(struct work_struct *work);
 void blk_unplug_timeout(unsigned long data);
+void blk_rq_timed_out_timer(unsigned long data);
+void blk_delete_timer(struct request *);
+void blk_add_timer(struct request *);
+
+/*
+ * Internal atomic flags for request handling
+ */
+enum rq_atomic_flags {
+	REQ_ATOM_COMPLETE = 0,
+};
+
+/*
+ * EH timer and IO completion will both attempt to 'grab' the request, make
+ * sure that only one of them suceeds
+ */
+static inline int blk_mark_rq_complete(struct request *rq)
+{
+	return test_and_set_bit(REQ_ATOM_COMPLETE, &rq->atomic_flags);
+}
+
+static inline void blk_clear_rq_complete(struct request *rq)
+{
+	clear_bit(REQ_ATOM_COMPLETE, &rq->atomic_flags);
+}
+
+#ifdef CONFIG_FAIL_IO_TIMEOUT
+int blk_should_fake_timeout(struct request_queue *);
+ssize_t part_timeout_show(struct device *, struct device_attribute *, char *);
+ssize_t part_timeout_store(struct device *, struct device_attribute *,
+				const char *, size_t);
+#else
+static inline int blk_should_fake_timeout(struct request_queue *q)
+{
+	return 0;
+}
+#endif
 
 struct io_context *current_io_context(gfp_t gfp_flags, int node);
 
@@ -59,4 +95,16 @@
 
 #endif /* BLK_DEV_INTEGRITY */
 
+static inline int blk_cpu_to_group(int cpu)
+{
+#ifdef CONFIG_SCHED_MC
+	cpumask_t mask = cpu_coregroup_map(cpu);
+	return first_cpu(mask);
+#elif defined(CONFIG_SCHED_SMT)
+	return first_cpu(per_cpu(cpu_sibling_map, cpu));
+#else
+	return cpu;
+#endif
+}
+
 #endif
diff --git a/block/blktrace.c b/block/blktrace.c
index eb9651c..85049a7 100644
--- a/block/blktrace.c
+++ b/block/blktrace.c
@@ -111,23 +111,9 @@
  */
 static u32 ddir_act[2] __read_mostly = { BLK_TC_ACT(BLK_TC_READ), BLK_TC_ACT(BLK_TC_WRITE) };
 
-/*
- * Bio action bits of interest
- */
-static u32 bio_act[9] __read_mostly = { 0, BLK_TC_ACT(BLK_TC_BARRIER), BLK_TC_ACT(BLK_TC_SYNC), 0, BLK_TC_ACT(BLK_TC_AHEAD), 0, 0, 0, BLK_TC_ACT(BLK_TC_META) };
-
-/*
- * More could be added as needed, taking care to increment the decrementer
- * to get correct indexing
- */
-#define trace_barrier_bit(rw)	\
-	(((rw) & (1 << BIO_RW_BARRIER)) >> (BIO_RW_BARRIER - 0))
-#define trace_sync_bit(rw)	\
-	(((rw) & (1 << BIO_RW_SYNC)) >> (BIO_RW_SYNC - 1))
-#define trace_ahead_bit(rw)	\
-	(((rw) & (1 << BIO_RW_AHEAD)) << (2 - BIO_RW_AHEAD))
-#define trace_meta_bit(rw)	\
-	(((rw) & (1 << BIO_RW_META)) >> (BIO_RW_META - 3))
+/* The ilog2() calls fall out because they're constant */
+#define MASK_TC_BIT(rw, __name) ( (rw & (1 << BIO_RW_ ## __name)) << \
+	  (ilog2(BLK_TC_ ## __name) + BLK_TC_SHIFT - BIO_RW_ ## __name) )
 
 /*
  * The worker for the various blk_add_trace*() types. Fills out a
@@ -147,10 +133,11 @@
 		return;
 
 	what |= ddir_act[rw & WRITE];
-	what |= bio_act[trace_barrier_bit(rw)];
-	what |= bio_act[trace_sync_bit(rw)];
-	what |= bio_act[trace_ahead_bit(rw)];
-	what |= bio_act[trace_meta_bit(rw)];
+	what |= MASK_TC_BIT(rw, BARRIER);
+	what |= MASK_TC_BIT(rw, SYNC);
+	what |= MASK_TC_BIT(rw, AHEAD);
+	what |= MASK_TC_BIT(rw, META);
+	what |= MASK_TC_BIT(rw, DISCARD);
 
 	pid = tsk->pid;
 	if (unlikely(act_log_check(bt, what, sector, pid)))
@@ -382,7 +369,8 @@
 	if (!buts->buf_size || !buts->buf_nr)
 		return -EINVAL;
 
-	strcpy(buts->name, name);
+	strncpy(buts->name, name, BLKTRACE_BDEV_SIZE);
+	buts->name[BLKTRACE_BDEV_SIZE - 1] = '\0';
 
 	/*
 	 * some device names have larger paths - convert the slashes
diff --git a/block/bsg.c b/block/bsg.c
index 0aae8d7..56cb343 100644
--- a/block/bsg.c
+++ b/block/bsg.c
@@ -283,7 +283,8 @@
 		next_rq->cmd_type = rq->cmd_type;
 
 		dxferp = (void*)(unsigned long)hdr->din_xferp;
-		ret =  blk_rq_map_user(q, next_rq, dxferp, hdr->din_xfer_len);
+		ret =  blk_rq_map_user(q, next_rq, NULL, dxferp,
+				       hdr->din_xfer_len, GFP_KERNEL);
 		if (ret)
 			goto out;
 	}
@@ -298,7 +299,8 @@
 		dxfer_len = 0;
 
 	if (dxfer_len) {
-		ret = blk_rq_map_user(q, rq, dxferp, dxfer_len);
+		ret = blk_rq_map_user(q, rq, NULL, dxferp, dxfer_len,
+				      GFP_KERNEL);
 		if (ret)
 			goto out;
 	}
diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c
index 1e2aff8..6a062ee 100644
--- a/block/cfq-iosched.c
+++ b/block/cfq-iosched.c
@@ -39,6 +39,7 @@
 #define CFQ_MIN_TT		(2)
 
 #define CFQ_SLICE_SCALE		(5)
+#define CFQ_HW_QUEUE_MIN	(5)
 
 #define RQ_CIC(rq)		\
 	((struct cfq_io_context *) (rq)->elevator_private)
@@ -86,7 +87,14 @@
 
 	int rq_in_driver;
 	int sync_flight;
+
+	/*
+	 * queue-depth detection
+	 */
+	int rq_queued;
 	int hw_tag;
+	int hw_tag_samples;
+	int rq_in_driver_peak;
 
 	/*
 	 * idle window management
@@ -244,7 +252,7 @@
 {
 	if (cfqd->busy_queues) {
 		cfq_log(cfqd, "schedule dispatch");
-		kblockd_schedule_work(&cfqd->unplug_work);
+		kblockd_schedule_work(cfqd->queue, &cfqd->unplug_work);
 	}
 }
 
@@ -654,15 +662,6 @@
 	cfq_log_cfqq(cfqd, RQ_CFQQ(rq), "activate rq, drv=%d",
 						cfqd->rq_in_driver);
 
-	/*
-	 * If the depth is larger 1, it really could be queueing. But lets
-	 * make the mark a little higher - idling could still be good for
-	 * low queueing, and a low queueing number could also just indicate
-	 * a SCSI mid layer like behaviour where limit+1 is often seen.
-	 */
-	if (!cfqd->hw_tag && cfqd->rq_in_driver > 4)
-		cfqd->hw_tag = 1;
-
 	cfqd->last_position = rq->hard_sector + rq->hard_nr_sectors;
 }
 
@@ -686,6 +685,7 @@
 	list_del_init(&rq->queuelist);
 	cfq_del_rq_rb(rq);
 
+	cfqq->cfqd->rq_queued--;
 	if (rq_is_meta(rq)) {
 		WARN_ON(!cfqq->meta_pending);
 		cfqq->meta_pending--;
@@ -878,6 +878,14 @@
 	struct cfq_io_context *cic;
 	unsigned long sl;
 
+	/*
+	 * SSD device without seek penalty, disable idling. But only do so
+	 * for devices that support queuing, otherwise we still have a problem
+	 * with sync vs async workloads.
+	 */
+	if (blk_queue_nonrot(cfqd->queue) && cfqd->hw_tag)
+		return;
+
 	WARN_ON(!RB_EMPTY_ROOT(&cfqq->sort_list));
 	WARN_ON(cfq_cfqq_slice_new(cfqq));
 
@@ -1833,6 +1841,7 @@
 {
 	struct cfq_io_context *cic = RQ_CIC(rq);
 
+	cfqd->rq_queued++;
 	if (rq_is_meta(rq))
 		cfqq->meta_pending++;
 
@@ -1880,6 +1889,31 @@
 	cfq_rq_enqueued(cfqd, cfqq, rq);
 }
 
+/*
+ * Update hw_tag based on peak queue depth over 50 samples under
+ * sufficient load.
+ */
+static void cfq_update_hw_tag(struct cfq_data *cfqd)
+{
+	if (cfqd->rq_in_driver > cfqd->rq_in_driver_peak)
+		cfqd->rq_in_driver_peak = cfqd->rq_in_driver;
+
+	if (cfqd->rq_queued <= CFQ_HW_QUEUE_MIN &&
+	    cfqd->rq_in_driver <= CFQ_HW_QUEUE_MIN)
+		return;
+
+	if (cfqd->hw_tag_samples++ < 50)
+		return;
+
+	if (cfqd->rq_in_driver_peak >= CFQ_HW_QUEUE_MIN)
+		cfqd->hw_tag = 1;
+	else
+		cfqd->hw_tag = 0;
+
+	cfqd->hw_tag_samples = 0;
+	cfqd->rq_in_driver_peak = 0;
+}
+
 static void cfq_completed_request(struct request_queue *q, struct request *rq)
 {
 	struct cfq_queue *cfqq = RQ_CFQQ(rq);
@@ -1890,6 +1924,8 @@
 	now = jiffies;
 	cfq_log_cfqq(cfqd, cfqq, "complete");
 
+	cfq_update_hw_tag(cfqd);
+
 	WARN_ON(!cfqd->rq_in_driver);
 	WARN_ON(!cfqq->dispatched);
 	cfqd->rq_in_driver--;
@@ -2200,6 +2236,7 @@
 	cfqd->cfq_slice[1] = cfq_slice_sync;
 	cfqd->cfq_slice_async_rq = cfq_slice_async_rq;
 	cfqd->cfq_slice_idle = cfq_slice_idle;
+	cfqd->hw_tag = 1;
 
 	return cfqd;
 }
diff --git a/block/cmd-filter.c b/block/cmd-filter.c
index 79c1499..e669aed 100644
--- a/block/cmd-filter.c
+++ b/block/cmd-filter.c
@@ -211,14 +211,10 @@
 {
 	int ret;
 	struct blk_cmd_filter *filter = &disk->queue->cmd_filter;
-	struct kobject *parent = kobject_get(disk->holder_dir->parent);
 
-	if (!parent)
-		return -ENODEV;
-
-	ret = kobject_init_and_add(&filter->kobj, &rcf_ktype, parent,
+	ret = kobject_init_and_add(&filter->kobj, &rcf_ktype,
+				   &disk_to_dev(disk)->kobj,
 				   "%s", "cmd_filter");
-
 	if (ret < 0)
 		return ret;
 
@@ -231,7 +227,6 @@
 	struct blk_cmd_filter *filter = &disk->queue->cmd_filter;
 
 	kobject_put(&filter->kobj);
-	kobject_put(disk->holder_dir->parent);
 }
 EXPORT_SYMBOL(blk_unregister_filter);
 #endif
diff --git a/block/compat_ioctl.c b/block/compat_ioctl.c
index c23177e..1e559fb 100644
--- a/block/compat_ioctl.c
+++ b/block/compat_ioctl.c
@@ -788,6 +788,7 @@
 		return compat_hdio_getgeo(disk, bdev, compat_ptr(arg));
 	case BLKFLSBUF:
 	case BLKROSET:
+	case BLKDISCARD:
 	/*
 	 * the ones below are implemented in blkdev_locked_ioctl,
 	 * but we call blkdev_ioctl, which gets the lock for us
diff --git a/block/deadline-iosched.c b/block/deadline-iosched.c
index 342448c..fd31117 100644
--- a/block/deadline-iosched.c
+++ b/block/deadline-iosched.c
@@ -33,7 +33,7 @@
 	 */
 	struct rb_root sort_list[2];	
 	struct list_head fifo_list[2];
-	
+
 	/*
 	 * next in sort order. read, write or both are NULL
 	 */
@@ -53,7 +53,11 @@
 
 static void deadline_move_request(struct deadline_data *, struct request *);
 
-#define RQ_RB_ROOT(dd, rq)	(&(dd)->sort_list[rq_data_dir((rq))])
+static inline struct rb_root *
+deadline_rb_root(struct deadline_data *dd, struct request *rq)
+{
+	return &dd->sort_list[rq_data_dir(rq)];
+}
 
 /*
  * get the request after `rq' in sector-sorted order
@@ -72,15 +76,11 @@
 static void
 deadline_add_rq_rb(struct deadline_data *dd, struct request *rq)
 {
-	struct rb_root *root = RQ_RB_ROOT(dd, rq);
+	struct rb_root *root = deadline_rb_root(dd, rq);
 	struct request *__alias;
 
-retry:
-	__alias = elv_rb_add(root, rq);
-	if (unlikely(__alias)) {
+	while (unlikely(__alias = elv_rb_add(root, rq)))
 		deadline_move_request(dd, __alias);
-		goto retry;
-	}
 }
 
 static inline void
@@ -91,7 +91,7 @@
 	if (dd->next_rq[data_dir] == rq)
 		dd->next_rq[data_dir] = deadline_latter_request(rq);
 
-	elv_rb_del(RQ_RB_ROOT(dd, rq), rq);
+	elv_rb_del(deadline_rb_root(dd, rq), rq);
 }
 
 /*
@@ -106,7 +106,7 @@
 	deadline_add_rq_rb(dd, rq);
 
 	/*
-	 * set expire time (only used for reads) and add to fifo list
+	 * set expire time and add to fifo list
 	 */
 	rq_set_fifo_time(rq, jiffies + dd->fifo_expire[data_dir]);
 	list_add_tail(&rq->queuelist, &dd->fifo_list[data_dir]);
@@ -162,7 +162,7 @@
 	 * if the merge was a front merge, we need to reposition request
 	 */
 	if (type == ELEVATOR_FRONT_MERGE) {
-		elv_rb_del(RQ_RB_ROOT(dd, req), req);
+		elv_rb_del(deadline_rb_root(dd, req), req);
 		deadline_add_rq_rb(dd, req);
 	}
 }
@@ -212,7 +212,7 @@
 	dd->next_rq[WRITE] = NULL;
 	dd->next_rq[data_dir] = deadline_latter_request(rq);
 
-	dd->last_sector = rq->sector + rq->nr_sectors;
+	dd->last_sector = rq_end_sector(rq);
 
 	/*
 	 * take it off the sort and fifo list, move
@@ -222,7 +222,7 @@
 }
 
 /*
- * deadline_check_fifo returns 0 if there are no expired reads on the fifo,
+ * deadline_check_fifo returns 0 if there are no expired requests on the fifo,
  * 1 otherwise. Requires !list_empty(&dd->fifo_list[data_dir])
  */
 static inline int deadline_check_fifo(struct deadline_data *dd, int ddir)
@@ -258,17 +258,9 @@
 	else
 		rq = dd->next_rq[READ];
 
-	if (rq) {
-		/* we have a "next request" */
-		
-		if (dd->last_sector != rq->sector)
-			/* end the batch on a non sequential request */
-			dd->batching += dd->fifo_batch;
-		
-		if (dd->batching < dd->fifo_batch)
-			/* we are still entitled to batch */
-			goto dispatch_request;
-	}
+	if (rq && dd->batching < dd->fifo_batch)
+		/* we have a next request are still entitled to batch */
+		goto dispatch_request;
 
 	/*
 	 * at this point we are not running a batch. select the appropriate
diff --git a/block/elevator.c b/block/elevator.c
index ed6f8f3..0451892 100644
--- a/block/elevator.c
+++ b/block/elevator.c
@@ -34,8 +34,9 @@
 #include <linux/delay.h>
 #include <linux/blktrace_api.h>
 #include <linux/hash.h>
+#include <linux/uaccess.h>
 
-#include <asm/uaccess.h>
+#include "blk.h"
 
 static DEFINE_SPINLOCK(elv_list_lock);
 static LIST_HEAD(elv_list);
@@ -75,6 +76,12 @@
 		return 0;
 
 	/*
+	 * Don't merge file system requests and discard requests
+	 */
+	if (bio_discard(bio) != bio_discard(rq->bio))
+		return 0;
+
+	/*
 	 * different data direction or already started, don't merge
 	 */
 	if (bio_data_dir(bio) != rq_data_dir(rq))
@@ -438,6 +445,8 @@
 	list_for_each_prev(entry, &q->queue_head) {
 		struct request *pos = list_entry_rq(entry);
 
+		if (blk_discard_rq(rq) != blk_discard_rq(pos))
+			break;
 		if (rq_data_dir(rq) != rq_data_dir(pos))
 			break;
 		if (pos->cmd_flags & stop_flags)
@@ -607,7 +616,7 @@
 		break;
 
 	case ELEVATOR_INSERT_SORT:
-		BUG_ON(!blk_fs_request(rq));
+		BUG_ON(!blk_fs_request(rq) && !blk_discard_rq(rq));
 		rq->cmd_flags |= REQ_SORTED;
 		q->nr_sorted++;
 		if (rq_mergeable(rq)) {
@@ -692,7 +701,7 @@
 		 * this request is scheduling boundary, update
 		 * end_sector
 		 */
-		if (blk_fs_request(rq)) {
+		if (blk_fs_request(rq) || blk_discard_rq(rq)) {
 			q->end_sector = rq_end_sector(rq);
 			q->boundary_rq = rq;
 		}
@@ -745,7 +754,7 @@
 		 * not ever see it.
 		 */
 		if (blk_empty_barrier(rq)) {
-			end_queued_request(rq, 1);
+			__blk_end_request(rq, 0, blk_rq_bytes(rq));
 			continue;
 		}
 		if (!(rq->cmd_flags & REQ_STARTED)) {
@@ -764,6 +773,12 @@
 			 */
 			rq->cmd_flags |= REQ_STARTED;
 			blk_add_trace_rq(q, rq, BLK_TA_ISSUE);
+
+			/*
+			 * We are now handing the request to the hardware,
+			 * add the timeout handler
+			 */
+			blk_add_timer(rq);
 		}
 
 		if (!q->boundary_rq || q->boundary_rq == rq) {
@@ -782,7 +797,6 @@
 			 * device can handle
 			 */
 			rq->nr_phys_segments++;
-			rq->nr_hw_segments++;
 		}
 
 		if (!q->prep_rq_fn)
@@ -805,14 +819,13 @@
 				 * so that we don't add it again
 				 */
 				--rq->nr_phys_segments;
-				--rq->nr_hw_segments;
 			}
 
 			rq = NULL;
 			break;
 		} else if (ret == BLKPREP_KILL) {
 			rq->cmd_flags |= REQ_QUIET;
-			end_queued_request(rq, 0);
+			__blk_end_request(rq, -EIO, blk_rq_bytes(rq));
 		} else {
 			printk(KERN_ERR "%s: bad return=%d\n", __func__, ret);
 			break;
@@ -901,6 +914,19 @@
 	return ELV_MQUEUE_MAY;
 }
 
+void elv_abort_queue(struct request_queue *q)
+{
+	struct request *rq;
+
+	while (!list_empty(&q->queue_head)) {
+		rq = list_entry_rq(q->queue_head.next);
+		rq->cmd_flags |= REQ_QUIET;
+		blk_add_trace_rq(q, rq, BLK_TA_ABORT);
+		__blk_end_request(rq, -EIO, blk_rq_bytes(rq));
+	}
+}
+EXPORT_SYMBOL(elv_abort_queue);
+
 void elv_completed_request(struct request_queue *q, struct request *rq)
 {
 	elevator_t *e = q->elevator;
diff --git a/block/genhd.c b/block/genhd.c
index e0ce23ac..4cd3433 100644
--- a/block/genhd.c
+++ b/block/genhd.c
@@ -16,6 +16,7 @@
 #include <linux/kobj_map.h>
 #include <linux/buffer_head.h>
 #include <linux/mutex.h>
+#include <linux/idr.h>
 
 #include "blk.h"
 
@@ -24,8 +25,194 @@
 struct kobject *block_depr;
 #endif
 
+/* for extended dynamic devt allocation, currently only one major is used */
+#define MAX_EXT_DEVT		(1 << MINORBITS)
+
+/* For extended devt allocation.  ext_devt_mutex prevents look up
+ * results from going away underneath its user.
+ */
+static DEFINE_MUTEX(ext_devt_mutex);
+static DEFINE_IDR(ext_devt_idr);
+
 static struct device_type disk_type;
 
+/**
+ * disk_get_part - get partition
+ * @disk: disk to look partition from
+ * @partno: partition number
+ *
+ * Look for partition @partno from @disk.  If found, increment
+ * reference count and return it.
+ *
+ * CONTEXT:
+ * Don't care.
+ *
+ * RETURNS:
+ * Pointer to the found partition on success, NULL if not found.
+ */
+struct hd_struct *disk_get_part(struct gendisk *disk, int partno)
+{
+	struct hd_struct *part = NULL;
+	struct disk_part_tbl *ptbl;
+
+	if (unlikely(partno < 0))
+		return NULL;
+
+	rcu_read_lock();
+
+	ptbl = rcu_dereference(disk->part_tbl);
+	if (likely(partno < ptbl->len)) {
+		part = rcu_dereference(ptbl->part[partno]);
+		if (part)
+			get_device(part_to_dev(part));
+	}
+
+	rcu_read_unlock();
+
+	return part;
+}
+EXPORT_SYMBOL_GPL(disk_get_part);
+
+/**
+ * disk_part_iter_init - initialize partition iterator
+ * @piter: iterator to initialize
+ * @disk: disk to iterate over
+ * @flags: DISK_PITER_* flags
+ *
+ * Initialize @piter so that it iterates over partitions of @disk.
+ *
+ * CONTEXT:
+ * Don't care.
+ */
+void disk_part_iter_init(struct disk_part_iter *piter, struct gendisk *disk,
+			  unsigned int flags)
+{
+	struct disk_part_tbl *ptbl;
+
+	rcu_read_lock();
+	ptbl = rcu_dereference(disk->part_tbl);
+
+	piter->disk = disk;
+	piter->part = NULL;
+
+	if (flags & DISK_PITER_REVERSE)
+		piter->idx = ptbl->len - 1;
+	else if (flags & DISK_PITER_INCL_PART0)
+		piter->idx = 0;
+	else
+		piter->idx = 1;
+
+	piter->flags = flags;
+
+	rcu_read_unlock();
+}
+EXPORT_SYMBOL_GPL(disk_part_iter_init);
+
+/**
+ * disk_part_iter_next - proceed iterator to the next partition and return it
+ * @piter: iterator of interest
+ *
+ * Proceed @piter to the next partition and return it.
+ *
+ * CONTEXT:
+ * Don't care.
+ */
+struct hd_struct *disk_part_iter_next(struct disk_part_iter *piter)
+{
+	struct disk_part_tbl *ptbl;
+	int inc, end;
+
+	/* put the last partition */
+	disk_put_part(piter->part);
+	piter->part = NULL;
+
+	/* get part_tbl */
+	rcu_read_lock();
+	ptbl = rcu_dereference(piter->disk->part_tbl);
+
+	/* determine iteration parameters */
+	if (piter->flags & DISK_PITER_REVERSE) {
+		inc = -1;
+		if (piter->flags & DISK_PITER_INCL_PART0)
+			end = -1;
+		else
+			end = 0;
+	} else {
+		inc = 1;
+		end = ptbl->len;
+	}
+
+	/* iterate to the next partition */
+	for (; piter->idx != end; piter->idx += inc) {
+		struct hd_struct *part;
+
+		part = rcu_dereference(ptbl->part[piter->idx]);
+		if (!part)
+			continue;
+		if (!(piter->flags & DISK_PITER_INCL_EMPTY) && !part->nr_sects)
+			continue;
+
+		get_device(part_to_dev(part));
+		piter->part = part;
+		piter->idx += inc;
+		break;
+	}
+
+	rcu_read_unlock();
+
+	return piter->part;
+}
+EXPORT_SYMBOL_GPL(disk_part_iter_next);
+
+/**
+ * disk_part_iter_exit - finish up partition iteration
+ * @piter: iter of interest
+ *
+ * Called when iteration is over.  Cleans up @piter.
+ *
+ * CONTEXT:
+ * Don't care.
+ */
+void disk_part_iter_exit(struct disk_part_iter *piter)
+{
+	disk_put_part(piter->part);
+	piter->part = NULL;
+}
+EXPORT_SYMBOL_GPL(disk_part_iter_exit);
+
+/**
+ * disk_map_sector_rcu - map sector to partition
+ * @disk: gendisk of interest
+ * @sector: sector to map
+ *
+ * Find out which partition @sector maps to on @disk.  This is
+ * primarily used for stats accounting.
+ *
+ * CONTEXT:
+ * RCU read locked.  The returned partition pointer is valid only
+ * while preemption is disabled.
+ *
+ * RETURNS:
+ * Found partition on success, part0 is returned if no partition matches
+ */
+struct hd_struct *disk_map_sector_rcu(struct gendisk *disk, sector_t sector)
+{
+	struct disk_part_tbl *ptbl;
+	int i;
+
+	ptbl = rcu_dereference(disk->part_tbl);
+
+	for (i = 1; i < ptbl->len; i++) {
+		struct hd_struct *part = rcu_dereference(ptbl->part[i]);
+
+		if (part && part->start_sect <= sector &&
+		    sector < part->start_sect + part->nr_sects)
+			return part;
+	}
+	return &disk->part0;
+}
+EXPORT_SYMBOL_GPL(disk_map_sector_rcu);
+
 /*
  * Can be deleted altogether. Later.
  *
@@ -43,14 +230,14 @@
 }
 
 #ifdef CONFIG_PROC_FS
-void blkdev_show(struct seq_file *f, off_t offset)
+void blkdev_show(struct seq_file *seqf, off_t offset)
 {
 	struct blk_major_name *dp;
 
 	if (offset < BLKDEV_MAJOR_HASH_SIZE) {
 		mutex_lock(&block_class_lock);
 		for (dp = major_names[offset]; dp; dp = dp->next)
-			seq_printf(f, "%3d %s\n", dp->major, dp->name);
+			seq_printf(seqf, "%3d %s\n", dp->major, dp->name);
 		mutex_unlock(&block_class_lock);
 	}
 }
@@ -136,6 +323,118 @@
 
 static struct kobj_map *bdev_map;
 
+/**
+ * blk_mangle_minor - scatter minor numbers apart
+ * @minor: minor number to mangle
+ *
+ * Scatter consecutively allocated @minor number apart if MANGLE_DEVT
+ * is enabled.  Mangling twice gives the original value.
+ *
+ * RETURNS:
+ * Mangled value.
+ *
+ * CONTEXT:
+ * Don't care.
+ */
+static int blk_mangle_minor(int minor)
+{
+#ifdef CONFIG_DEBUG_BLOCK_EXT_DEVT
+	int i;
+
+	for (i = 0; i < MINORBITS / 2; i++) {
+		int low = minor & (1 << i);
+		int high = minor & (1 << (MINORBITS - 1 - i));
+		int distance = MINORBITS - 1 - 2 * i;
+
+		minor ^= low | high;	/* clear both bits */
+		low <<= distance;	/* swap the positions */
+		high >>= distance;
+		minor |= low | high;	/* and set */
+	}
+#endif
+	return minor;
+}
+
+/**
+ * blk_alloc_devt - allocate a dev_t for a partition
+ * @part: partition to allocate dev_t for
+ * @gfp_mask: memory allocation flag
+ * @devt: out parameter for resulting dev_t
+ *
+ * Allocate a dev_t for block device.
+ *
+ * RETURNS:
+ * 0 on success, allocated dev_t is returned in *@devt.  -errno on
+ * failure.
+ *
+ * CONTEXT:
+ * Might sleep.
+ */
+int blk_alloc_devt(struct hd_struct *part, dev_t *devt)
+{
+	struct gendisk *disk = part_to_disk(part);
+	int idx, rc;
+
+	/* in consecutive minor range? */
+	if (part->partno < disk->minors) {
+		*devt = MKDEV(disk->major, disk->first_minor + part->partno);
+		return 0;
+	}
+
+	/* allocate ext devt */
+	do {
+		if (!idr_pre_get(&ext_devt_idr, GFP_KERNEL))
+			return -ENOMEM;
+		rc = idr_get_new(&ext_devt_idr, part, &idx);
+	} while (rc == -EAGAIN);
+
+	if (rc)
+		return rc;
+
+	if (idx > MAX_EXT_DEVT) {
+		idr_remove(&ext_devt_idr, idx);
+		return -EBUSY;
+	}
+
+	*devt = MKDEV(BLOCK_EXT_MAJOR, blk_mangle_minor(idx));
+	return 0;
+}
+
+/**
+ * blk_free_devt - free a dev_t
+ * @devt: dev_t to free
+ *
+ * Free @devt which was allocated using blk_alloc_devt().
+ *
+ * CONTEXT:
+ * Might sleep.
+ */
+void blk_free_devt(dev_t devt)
+{
+	might_sleep();
+
+	if (devt == MKDEV(0, 0))
+		return;
+
+	if (MAJOR(devt) == BLOCK_EXT_MAJOR) {
+		mutex_lock(&ext_devt_mutex);
+		idr_remove(&ext_devt_idr, blk_mangle_minor(MINOR(devt)));
+		mutex_unlock(&ext_devt_mutex);
+	}
+}
+
+static char *bdevt_str(dev_t devt, char *buf)
+{
+	if (MAJOR(devt) <= 0xff && MINOR(devt) <= 0xff) {
+		char tbuf[BDEVT_SIZE];
+		snprintf(tbuf, BDEVT_SIZE, "%02x%02x", MAJOR(devt), MINOR(devt));
+		snprintf(buf, BDEVT_SIZE, "%-9s", tbuf);
+	} else
+		snprintf(buf, BDEVT_SIZE, "%03x:%05x", MAJOR(devt), MINOR(devt));
+
+	return buf;
+}
+
 /*
  * Register device numbers dev..(dev+range-1)
  * range must be nonzero
@@ -157,11 +456,11 @@
 
 EXPORT_SYMBOL(blk_unregister_region);
 
-static struct kobject *exact_match(dev_t devt, int *part, void *data)
+static struct kobject *exact_match(dev_t devt, int *partno, void *data)
 {
 	struct gendisk *p = data;
 
-	return &p->dev.kobj;
+	return &disk_to_dev(p)->kobj;
 }
 
 static int exact_lock(dev_t devt, void *data)
@@ -179,21 +478,46 @@
  *
  * This function registers the partitioning information in @disk
  * with the kernel.
+ *
+ * FIXME: error handling
  */
 void add_disk(struct gendisk *disk)
 {
 	struct backing_dev_info *bdi;
+	dev_t devt;
 	int retval;
 
+	/* minors == 0 indicates to use ext devt from part0 and should
+	 * be accompanied with EXT_DEVT flag.  Make sure all
+	 * parameters make sense.
+	 */
+	WARN_ON(disk->minors && !(disk->major || disk->first_minor));
+	WARN_ON(!disk->minors && !(disk->flags & GENHD_FL_EXT_DEVT));
+
 	disk->flags |= GENHD_FL_UP;
-	blk_register_region(MKDEV(disk->major, disk->first_minor),
-			    disk->minors, NULL, exact_match, exact_lock, disk);
+
+	retval = blk_alloc_devt(&disk->part0, &devt);
+	if (retval) {
+		WARN_ON(1);
+		return;
+	}
+	disk_to_dev(disk)->devt = devt;
+
+	/* ->major and ->first_minor aren't supposed to be
+	 * dereferenced from here on, but set them just in case.
+	 */
+	disk->major = MAJOR(devt);
+	disk->first_minor = MINOR(devt);
+
+	blk_register_region(disk_devt(disk), disk->minors, NULL,
+			    exact_match, exact_lock, disk);
 	register_disk(disk);
 	blk_register_queue(disk);
 
 	bdi = &disk->queue->backing_dev_info;
-	bdi_register_dev(bdi, MKDEV(disk->major, disk->first_minor));
-	retval = sysfs_create_link(&disk->dev.kobj, &bdi->dev->kobj, "bdi");
+	bdi_register_dev(bdi, disk_devt(disk));
+	retval = sysfs_create_link(&disk_to_dev(disk)->kobj, &bdi->dev->kobj,
+				   "bdi");
 	WARN_ON(retval);
 }
 
@@ -202,79 +526,72 @@
 
 void unlink_gendisk(struct gendisk *disk)
 {
-	sysfs_remove_link(&disk->dev.kobj, "bdi");
+	sysfs_remove_link(&disk_to_dev(disk)->kobj, "bdi");
 	bdi_unregister(&disk->queue->backing_dev_info);
 	blk_unregister_queue(disk);
-	blk_unregister_region(MKDEV(disk->major, disk->first_minor),
-			      disk->minors);
+	blk_unregister_region(disk_devt(disk), disk->minors);
 }
 
 /**
  * get_gendisk - get partitioning information for a given device
- * @dev: device to get partitioning information for
+ * @devt: device to get partitioning information for
+ * @part: returned partition index
  *
  * This function gets the structure containing partitioning
- * information for the given device @dev.
+ * information for the given device @devt.
  */
-struct gendisk *get_gendisk(dev_t devt, int *part)
+struct gendisk *get_gendisk(dev_t devt, int *partno)
 {
-	struct kobject *kobj = kobj_lookup(bdev_map, devt, part);
-	struct device *dev = kobj_to_dev(kobj);
+	struct gendisk *disk = NULL;
 
-	return  kobj ? dev_to_disk(dev) : NULL;
-}
+	if (MAJOR(devt) != BLOCK_EXT_MAJOR) {
+		struct kobject *kobj;
 
-/*
- * print a partitions - intended for places where the root filesystem can't be
- * mounted and thus to give the victim some idea of what went wrong
- */
-static int printk_partition(struct device *dev, void *data)
-{
-	struct gendisk *sgp;
-	char buf[BDEVNAME_SIZE];
-	int n;
+		kobj = kobj_lookup(bdev_map, devt, partno);
+		if (kobj)
+			disk = dev_to_disk(kobj_to_dev(kobj));
+	} else {
+		struct hd_struct *part;
 
-	if (dev->type != &disk_type)
-		goto exit;
-
-	sgp = dev_to_disk(dev);
-	/*
-	 * Don't show empty devices or things that have been surpressed
-	 */
-	if (get_capacity(sgp) == 0 ||
-	    (sgp->flags & GENHD_FL_SUPPRESS_PARTITION_INFO))
-		goto exit;
-
-	/*
-	 * Note, unlike /proc/partitions, I am showing the numbers in
-	 * hex - the same format as the root= option takes.
-	 */
-	printk("%02x%02x %10llu %s",
-		sgp->major, sgp->first_minor,
-		(unsigned long long)get_capacity(sgp) >> 1,
-		disk_name(sgp, 0, buf));
-	if (sgp->driverfs_dev != NULL &&
-	    sgp->driverfs_dev->driver != NULL)
-		printk(" driver: %s\n",
-			sgp->driverfs_dev->driver->name);
-	else
-		printk(" (driver?)\n");
-
-	/* now show the partitions */
-	for (n = 0; n < sgp->minors - 1; ++n) {
-		if (sgp->part[n] == NULL)
-			goto exit;
-		if (sgp->part[n]->nr_sects == 0)
-			goto exit;
-		printk("  %02x%02x %10llu %s\n",
-			sgp->major, n + 1 + sgp->first_minor,
-			(unsigned long long)sgp->part[n]->nr_sects >> 1,
-			disk_name(sgp, n + 1, buf));
+		mutex_lock(&ext_devt_mutex);
+		part = idr_find(&ext_devt_idr, blk_mangle_minor(MINOR(devt)));
+		if (part && get_disk(part_to_disk(part))) {
+			*partno = part->partno;
+			disk = part_to_disk(part);
+		}
+		mutex_unlock(&ext_devt_mutex);
 	}
-exit:
-	return 0;
+
+	return disk;
 }
 
+/**
+ * bdget_disk - do bdget() by gendisk and partition number
+ * @disk: gendisk of interest
+ * @partno: partition number
+ *
+ * Find partition @partno from @disk, do bdget() on it.
+ *
+ * CONTEXT:
+ * Don't care.
+ *
+ * RETURNS:
+ * Resulting block_device on success, NULL on failure.
+ */
+struct block_device *bdget_disk(struct gendisk *disk, int partno)
+{
+	struct hd_struct *part;
+	struct block_device *bdev = NULL;
+
+	part = disk_get_part(disk, partno);
+	if (part)
+		bdev = bdget(part_devt(part));
+	disk_put_part(part);
+
+	return bdev;
+}
+EXPORT_SYMBOL(bdget_disk);
+
 /*
  * print a full list of all partitions - intended for places where the root
  * filesystem can't be mounted and thus to give the victim some idea of what
@@ -282,120 +599,145 @@
  */
 void __init printk_all_partitions(void)
 {
-	mutex_lock(&block_class_lock);
-	class_for_each_device(&block_class, NULL, NULL, printk_partition);
-	mutex_unlock(&block_class_lock);
+	struct class_dev_iter iter;
+	struct device *dev;
+
+	class_dev_iter_init(&iter, &block_class, NULL, &disk_type);
+	while ((dev = class_dev_iter_next(&iter))) {
+		struct gendisk *disk = dev_to_disk(dev);
+		struct disk_part_iter piter;
+		struct hd_struct *part;
+		char name_buf[BDEVNAME_SIZE];
+		char devt_buf[BDEVT_SIZE];
+
+		/*
+		 * Don't show empty devices or things that have been
+		 * surpressed
+		 */
+		if (get_capacity(disk) == 0 ||
+		    (disk->flags & GENHD_FL_SUPPRESS_PARTITION_INFO))
+			continue;
+
+		/*
+		 * Note, unlike /proc/partitions, I am showing the
+		 * numbers in hex - the same format as the root=
+		 * option takes.
+		 */
+		disk_part_iter_init(&piter, disk, DISK_PITER_INCL_PART0);
+		while ((part = disk_part_iter_next(&piter))) {
+			bool is_part0 = part == &disk->part0;
+
+			printk("%s%s %10llu %s", is_part0 ? "" : "  ",
+			       bdevt_str(part_devt(part), devt_buf),
+			       (unsigned long long)part->nr_sects >> 1,
+			       disk_name(disk, part->partno, name_buf));
+			if (is_part0) {
+				if (disk->driverfs_dev != NULL &&
+				    disk->driverfs_dev->driver != NULL)
+					printk(" driver: %s\n",
+					      disk->driverfs_dev->driver->name);
+				else
+					printk(" (driver?)\n");
+			} else
+				printk("\n");
+		}
+		disk_part_iter_exit(&piter);
+	}
+	class_dev_iter_exit(&iter);
 }
 
 #ifdef CONFIG_PROC_FS
 /* iterator */
-static int find_start(struct device *dev, void *data)
+static void *disk_seqf_start(struct seq_file *seqf, loff_t *pos)
 {
-	loff_t *k = data;
+	loff_t skip = *pos;
+	struct class_dev_iter *iter;
+	struct device *dev;
 
-	if (dev->type != &disk_type)
-		return 0;
-	if (!*k)
-		return 1;
-	(*k)--;
-	return 0;
+	iter = kmalloc(sizeof(*iter), GFP_KERNEL);
+	if (!iter)
+		return ERR_PTR(-ENOMEM);
+
+	seqf->private = iter;
+	class_dev_iter_init(iter, &block_class, NULL, &disk_type);
+	do {
+		dev = class_dev_iter_next(iter);
+		if (!dev)
+			return NULL;
+	} while (skip--);
+
+	return dev_to_disk(dev);
 }
 
-static void *part_start(struct seq_file *part, loff_t *pos)
+static void *disk_seqf_next(struct seq_file *seqf, void *v, loff_t *pos)
 {
 	struct device *dev;
-	loff_t k = *pos;
 
-	if (!k)
-		part->private = (void *)1LU;	/* tell show to print header */
-
-	mutex_lock(&block_class_lock);
-	dev = class_find_device(&block_class, NULL, &k, find_start);
-	if (dev) {
-		put_device(dev);
+	(*pos)++;
+	dev = class_dev_iter_next(seqf->private);
+	if (dev)
 		return dev_to_disk(dev);
-	}
+
 	return NULL;
 }
 
-static int find_next(struct device *dev, void *data)
+static void disk_seqf_stop(struct seq_file *seqf, void *v)
 {
-	if (dev->type == &disk_type)
-		return 1;
-	return 0;
-}
+	struct class_dev_iter *iter = seqf->private;
 
-static void *part_next(struct seq_file *part, void *v, loff_t *pos)
-{
-	struct gendisk *gp = v;
-	struct device *dev;
-	++*pos;
-	dev = class_find_device(&block_class, &gp->dev, NULL, find_next);
-	if (dev) {
-		put_device(dev);
-		return dev_to_disk(dev);
+	/* stop is called even after start failed :-( */
+	if (iter) {
+		class_dev_iter_exit(iter);
+		kfree(iter);
 	}
-	return NULL;
 }
 
-static void part_stop(struct seq_file *part, void *v)
+static void *show_partition_start(struct seq_file *seqf, loff_t *pos)
 {
-	mutex_unlock(&block_class_lock);
+	static void *p;
+
+	p = disk_seqf_start(seqf, pos);
+	if (!IS_ERR(p) && p && !*pos)
+		seq_puts(seqf, "major minor  #blocks  name\n\n");
+	return p;
 }
 
-static int show_partition(struct seq_file *part, void *v)
+static int show_partition(struct seq_file *seqf, void *v)
 {
 	struct gendisk *sgp = v;
-	int n;
+	struct disk_part_iter piter;
+	struct hd_struct *part;
 	char buf[BDEVNAME_SIZE];
 
-	/*
-	 * Print header if start told us to do.  This is to preserve
-	 * the original behavior of not printing header if no
-	 * partition exists.  This hackery will be removed later with
-	 * class iteration clean up.
-	 */
-	if (part->private) {
-		seq_puts(part, "major minor  #blocks  name\n\n");
-		part->private = NULL;
-	}
-
 	/* Don't show non-partitionable removeable devices or empty devices */
-	if (!get_capacity(sgp) ||
-			(sgp->minors == 1 && (sgp->flags & GENHD_FL_REMOVABLE)))
+	if (!get_capacity(sgp) || (!disk_partitionable(sgp) &&
+				   (sgp->flags & GENHD_FL_REMOVABLE)))
 		return 0;
 	if (sgp->flags & GENHD_FL_SUPPRESS_PARTITION_INFO)
 		return 0;
 
 	/* show the full disk and all non-0 size partitions of it */
-	seq_printf(part, "%4d  %4d %10llu %s\n",
-		sgp->major, sgp->first_minor,
-		(unsigned long long)get_capacity(sgp) >> 1,
-		disk_name(sgp, 0, buf));
-	for (n = 0; n < sgp->minors - 1; n++) {
-		if (!sgp->part[n])
-			continue;
-		if (sgp->part[n]->nr_sects == 0)
-			continue;
-		seq_printf(part, "%4d  %4d %10llu %s\n",
-			sgp->major, n + 1 + sgp->first_minor,
-			(unsigned long long)sgp->part[n]->nr_sects >> 1 ,
-			disk_name(sgp, n + 1, buf));
-	}
+	disk_part_iter_init(&piter, sgp, DISK_PITER_INCL_PART0);
+	while ((part = disk_part_iter_next(&piter)))
+		seq_printf(seqf, "%4d  %7d %10llu %s\n",
+			   MAJOR(part_devt(part)), MINOR(part_devt(part)),
+			   (unsigned long long)part->nr_sects >> 1,
+			   disk_name(sgp, part->partno, buf));
+	disk_part_iter_exit(&piter);
 
 	return 0;
 }
 
 const struct seq_operations partitions_op = {
-	.start	= part_start,
-	.next	= part_next,
-	.stop	= part_stop,
+	.start	= show_partition_start,
+	.next	= disk_seqf_next,
+	.stop	= disk_seqf_stop,
 	.show	= show_partition
 };
 #endif
 
 
-static struct kobject *base_probe(dev_t devt, int *part, void *data)
+static struct kobject *base_probe(dev_t devt, int *partno, void *data)
 {
 	if (request_module("block-major-%d-%d", MAJOR(devt), MINOR(devt)) > 0)
 		/* Make old-style 2.4 aliases work */
@@ -431,6 +773,14 @@
 	return sprintf(buf, "%d\n", disk->minors);
 }
 
+static ssize_t disk_ext_range_show(struct device *dev,
+				   struct device_attribute *attr, char *buf)
+{
+	struct gendisk *disk = dev_to_disk(dev);
+
+	return sprintf(buf, "%d\n", disk_max_parts(disk));
+}
+
 static ssize_t disk_removable_show(struct device *dev,
 				   struct device_attribute *attr, char *buf)
 {
@@ -445,15 +795,7 @@
 {
 	struct gendisk *disk = dev_to_disk(dev);
 
-	return sprintf(buf, "%d\n", disk->policy ? 1 : 0);
-}
-
-static ssize_t disk_size_show(struct device *dev,
-			      struct device_attribute *attr, char *buf)
-{
-	struct gendisk *disk = dev_to_disk(dev);
-
-	return sprintf(buf, "%llu\n", (unsigned long long)get_capacity(disk));
+	return sprintf(buf, "%d\n", get_disk_ro(disk) ? 1 : 0);
 }
 
 static ssize_t disk_capability_show(struct device *dev,
@@ -464,73 +806,26 @@
 	return sprintf(buf, "%x\n", disk->flags);
 }
 
-static ssize_t disk_stat_show(struct device *dev,
-			      struct device_attribute *attr, char *buf)
-{
-	struct gendisk *disk = dev_to_disk(dev);
-
-	preempt_disable();
-	disk_round_stats(disk);
-	preempt_enable();
-	return sprintf(buf,
-		"%8lu %8lu %8llu %8u "
-		"%8lu %8lu %8llu %8u "
-		"%8u %8u %8u"
-		"\n",
-		disk_stat_read(disk, ios[READ]),
-		disk_stat_read(disk, merges[READ]),
-		(unsigned long long)disk_stat_read(disk, sectors[READ]),
-		jiffies_to_msecs(disk_stat_read(disk, ticks[READ])),
-		disk_stat_read(disk, ios[WRITE]),
-		disk_stat_read(disk, merges[WRITE]),
-		(unsigned long long)disk_stat_read(disk, sectors[WRITE]),
-		jiffies_to_msecs(disk_stat_read(disk, ticks[WRITE])),
-		disk->in_flight,
-		jiffies_to_msecs(disk_stat_read(disk, io_ticks)),
-		jiffies_to_msecs(disk_stat_read(disk, time_in_queue)));
-}
-
-#ifdef CONFIG_FAIL_MAKE_REQUEST
-static ssize_t disk_fail_show(struct device *dev,
-			      struct device_attribute *attr, char *buf)
-{
-	struct gendisk *disk = dev_to_disk(dev);
-
-	return sprintf(buf, "%d\n", disk->flags & GENHD_FL_FAIL ? 1 : 0);
-}
-
-static ssize_t disk_fail_store(struct device *dev,
-			       struct device_attribute *attr,
-			       const char *buf, size_t count)
-{
-	struct gendisk *disk = dev_to_disk(dev);
-	int i;
-
-	if (count > 0 && sscanf(buf, "%d", &i) > 0) {
-		if (i == 0)
-			disk->flags &= ~GENHD_FL_FAIL;
-		else
-			disk->flags |= GENHD_FL_FAIL;
-	}
-
-	return count;
-}
-
-#endif
-
 static DEVICE_ATTR(range, S_IRUGO, disk_range_show, NULL);
+static DEVICE_ATTR(ext_range, S_IRUGO, disk_ext_range_show, NULL);
 static DEVICE_ATTR(removable, S_IRUGO, disk_removable_show, NULL);
 static DEVICE_ATTR(ro, S_IRUGO, disk_ro_show, NULL);
-static DEVICE_ATTR(size, S_IRUGO, disk_size_show, NULL);
+static DEVICE_ATTR(size, S_IRUGO, part_size_show, NULL);
 static DEVICE_ATTR(capability, S_IRUGO, disk_capability_show, NULL);
-static DEVICE_ATTR(stat, S_IRUGO, disk_stat_show, NULL);
+static DEVICE_ATTR(stat, S_IRUGO, part_stat_show, NULL);
 #ifdef CONFIG_FAIL_MAKE_REQUEST
 static struct device_attribute dev_attr_fail =
-	__ATTR(make-it-fail, S_IRUGO|S_IWUSR, disk_fail_show, disk_fail_store);
+	__ATTR(make-it-fail, S_IRUGO|S_IWUSR, part_fail_show, part_fail_store);
+#endif
+#ifdef CONFIG_FAIL_IO_TIMEOUT
+static struct device_attribute dev_attr_fail_timeout =
+	__ATTR(io-timeout-fail,  S_IRUGO|S_IWUSR, part_timeout_show,
+		part_timeout_store);
 #endif
 
 static struct attribute *disk_attrs[] = {
 	&dev_attr_range.attr,
+	&dev_attr_ext_range.attr,
 	&dev_attr_removable.attr,
 	&dev_attr_ro.attr,
 	&dev_attr_size.attr,
@@ -539,6 +834,9 @@
 #ifdef CONFIG_FAIL_MAKE_REQUEST
 	&dev_attr_fail.attr,
 #endif
+#ifdef CONFIG_FAIL_IO_TIMEOUT
+	&dev_attr_fail_timeout.attr,
+#endif
 	NULL
 };
 
@@ -551,13 +849,87 @@
 	NULL
 };
 
+static void disk_free_ptbl_rcu_cb(struct rcu_head *head)
+{
+	struct disk_part_tbl *ptbl =
+		container_of(head, struct disk_part_tbl, rcu_head);
+
+	kfree(ptbl);
+}
+
+/**
+ * disk_replace_part_tbl - replace disk->part_tbl in RCU-safe way
+ * @disk: disk to replace part_tbl for
+ * @new_ptbl: new part_tbl to install
+ *
+ * Replace disk->part_tbl with @new_ptbl in RCU-safe way.  The
+ * original ptbl is freed using RCU callback.
+ *
+ * LOCKING:
+ * Matching bd_mutx locked.
+ */
+static void disk_replace_part_tbl(struct gendisk *disk,
+				  struct disk_part_tbl *new_ptbl)
+{
+	struct disk_part_tbl *old_ptbl = disk->part_tbl;
+
+	rcu_assign_pointer(disk->part_tbl, new_ptbl);
+	if (old_ptbl)
+		call_rcu(&old_ptbl->rcu_head, disk_free_ptbl_rcu_cb);
+}
+
+/**
+ * disk_expand_part_tbl - expand disk->part_tbl
+ * @disk: disk to expand part_tbl for
+ * @partno: expand such that this partno can fit in
+ *
+ * Expand disk->part_tbl such that @partno can fit in.  disk->part_tbl
+ * uses RCU to allow unlocked dereferencing for stats and other stuff.
+ *
+ * LOCKING:
+ * Matching bd_mutex locked, might sleep.
+ *
+ * RETURNS:
+ * 0 on success, -errno on failure.
+ */
+int disk_expand_part_tbl(struct gendisk *disk, int partno)
+{
+	struct disk_part_tbl *old_ptbl = disk->part_tbl;
+	struct disk_part_tbl *new_ptbl;
+	int len = old_ptbl ? old_ptbl->len : 0;
+	int target = partno + 1;
+	size_t size;
+	int i;
+
+	/* disk_max_parts() is zero during initialization, ignore if so */
+	if (disk_max_parts(disk) && target > disk_max_parts(disk))
+		return -EINVAL;
+
+	if (target <= len)
+		return 0;
+
+	size = sizeof(*new_ptbl) + target * sizeof(new_ptbl->part[0]);
+	new_ptbl = kzalloc_node(size, GFP_KERNEL, disk->node_id);
+	if (!new_ptbl)
+		return -ENOMEM;
+
+	INIT_RCU_HEAD(&new_ptbl->rcu_head);
+	new_ptbl->len = target;
+
+	for (i = 0; i < len; i++)
+		rcu_assign_pointer(new_ptbl->part[i], old_ptbl->part[i]);
+
+	disk_replace_part_tbl(disk, new_ptbl);
+	return 0;
+}
+
 static void disk_release(struct device *dev)
 {
 	struct gendisk *disk = dev_to_disk(dev);
 
 	kfree(disk->random);
-	kfree(disk->part);
-	free_disk_stats(disk);
+	disk_replace_part_tbl(disk, NULL);
+	free_part_stats(&disk->part0);
 	kfree(disk);
 }
 struct class block_class = {
@@ -578,83 +950,31 @@
  * The output looks suspiciously like /proc/partitions with a bunch of
  * extra fields.
  */
-
-static void *diskstats_start(struct seq_file *part, loff_t *pos)
-{
-	struct device *dev;
-	loff_t k = *pos;
-
-	mutex_lock(&block_class_lock);
-	dev = class_find_device(&block_class, NULL, &k, find_start);
-	if (dev) {
-		put_device(dev);
-		return dev_to_disk(dev);
-	}
-	return NULL;
-}
-
-static void *diskstats_next(struct seq_file *part, void *v, loff_t *pos)
+static int diskstats_show(struct seq_file *seqf, void *v)
 {
 	struct gendisk *gp = v;
-	struct device *dev;
-
-	++*pos;
-	dev = class_find_device(&block_class, &gp->dev, NULL, find_next);
-	if (dev) {
-		put_device(dev);
-		return dev_to_disk(dev);
-	}
-	return NULL;
-}
-
-static void diskstats_stop(struct seq_file *part, void *v)
-{
-	mutex_unlock(&block_class_lock);
-}
-
-static int diskstats_show(struct seq_file *s, void *v)
-{
-	struct gendisk *gp = v;
+	struct disk_part_iter piter;
+	struct hd_struct *hd;
 	char buf[BDEVNAME_SIZE];
-	int n = 0;
+	int cpu;
 
 	/*
-	if (&gp->dev.kobj.entry == block_class.devices.next)
-		seq_puts(s,	"major minor name"
+	if (&disk_to_dev(gp)->kobj.entry == block_class.devices.next)
+		seq_puts(seqf,	"major minor name"
 				"     rio rmerge rsect ruse wio wmerge "
 				"wsect wuse running use aveq"
 				"\n\n");
 	*/
  
-	preempt_disable();
-	disk_round_stats(gp);
-	preempt_enable();
-	seq_printf(s, "%4d %4d %s %lu %lu %llu %u %lu %lu %llu %u %u %u %u\n",
-		gp->major, n + gp->first_minor, disk_name(gp, n, buf),
-		disk_stat_read(gp, ios[0]), disk_stat_read(gp, merges[0]),
-		(unsigned long long)disk_stat_read(gp, sectors[0]),
-		jiffies_to_msecs(disk_stat_read(gp, ticks[0])),
-		disk_stat_read(gp, ios[1]), disk_stat_read(gp, merges[1]),
-		(unsigned long long)disk_stat_read(gp, sectors[1]),
-		jiffies_to_msecs(disk_stat_read(gp, ticks[1])),
-		gp->in_flight,
-		jiffies_to_msecs(disk_stat_read(gp, io_ticks)),
-		jiffies_to_msecs(disk_stat_read(gp, time_in_queue)));
-
-	/* now show all non-0 size partitions of it */
-	for (n = 0; n < gp->minors - 1; n++) {
-		struct hd_struct *hd = gp->part[n];
-
-		if (!hd || !hd->nr_sects)
-			continue;
-
-		preempt_disable();
-		part_round_stats(hd);
-		preempt_enable();
-		seq_printf(s, "%4d %4d %s %lu %lu %llu "
+	disk_part_iter_init(&piter, gp, DISK_PITER_INCL_PART0);
+	while ((hd = disk_part_iter_next(&piter))) {
+		cpu = part_stat_lock();
+		part_round_stats(cpu, hd);
+		part_stat_unlock();
+		seq_printf(seqf, "%4d %7d %s %lu %lu %llu "
 			   "%u %lu %lu %llu %u %u %u %u\n",
-			   gp->major, n + gp->first_minor + 1,
-			   disk_name(gp, n + 1, buf),
+			   MAJOR(part_devt(hd)), MINOR(part_devt(hd)),
+			   disk_name(gp, hd->partno, buf),
 			   part_stat_read(hd, ios[0]),
 			   part_stat_read(hd, merges[0]),
 			   (unsigned long long)part_stat_read(hd, sectors[0]),
@@ -668,14 +988,15 @@
 			   jiffies_to_msecs(part_stat_read(hd, time_in_queue))
 			);
 	}
+	disk_part_iter_exit(&piter);
  
 	return 0;
 }
 
 const struct seq_operations diskstats_op = {
-	.start	= diskstats_start,
-	.next	= diskstats_next,
-	.stop	= diskstats_stop,
+	.start	= disk_seqf_start,
+	.next	= disk_seqf_next,
+	.stop	= disk_seqf_stop,
 	.show	= diskstats_show
 };
 #endif /* CONFIG_PROC_FS */
@@ -690,7 +1011,7 @@
 	 * set enviroment vars to indicate which event this is for
 	 * so that user space will know to go check the media status.
 	 */
-	kobject_uevent_env(&gd->dev.kobj, KOBJ_CHANGE, envp);
+	kobject_uevent_env(&disk_to_dev(gd)->kobj, KOBJ_CHANGE, envp);
 	put_device(gd->driverfs_dev);
 }
 
@@ -703,42 +1024,29 @@
 EXPORT_SYMBOL_GPL(genhd_media_change_notify);
 #endif  /*  0  */
 
-struct find_block {
-	const char *name;
-	int part;
-};
-
-static int match_id(struct device *dev, void *data)
+dev_t blk_lookup_devt(const char *name, int partno)
 {
-	struct find_block *find = data;
-
-	if (dev->type != &disk_type)
-		return 0;
-	if (strcmp(dev->bus_id, find->name) == 0) {
-		struct gendisk *disk = dev_to_disk(dev);
-		if (find->part < disk->minors)
-			return 1;
-	}
-	return 0;
-}
-
-dev_t blk_lookup_devt(const char *name, int part)
-{
-	struct device *dev;
 	dev_t devt = MKDEV(0, 0);
-	struct find_block find;
+	struct class_dev_iter iter;
+	struct device *dev;
 
-	mutex_lock(&block_class_lock);
-	find.name = name;
-	find.part = part;
-	dev = class_find_device(&block_class, NULL, &find, match_id);
-	if (dev) {
-		put_device(dev);
-		devt = MKDEV(MAJOR(dev->devt),
-			     MINOR(dev->devt) + part);
+	class_dev_iter_init(&iter, &block_class, NULL, &disk_type);
+	while ((dev = class_dev_iter_next(&iter))) {
+		struct gendisk *disk = dev_to_disk(dev);
+		struct hd_struct *part;
+
+		if (strcmp(dev->bus_id, name))
+			continue;
+
+		part = disk_get_part(disk, partno);
+		if (part) {
+			devt = part_devt(part);
+			disk_put_part(part);
+			break;
+		}
+		disk_put_part(part);
 	}
-	mutex_unlock(&block_class_lock);
-
+	class_dev_iter_exit(&iter);
 	return devt;
 }
 EXPORT_SYMBOL(blk_lookup_devt);
@@ -747,6 +1055,7 @@
 {
 	return alloc_disk_node(minors, -1);
 }
+EXPORT_SYMBOL(alloc_disk);
 
 struct gendisk *alloc_disk_node(int minors, int node_id)
 {
@@ -755,32 +1064,28 @@
 	disk = kmalloc_node(sizeof(struct gendisk),
 				GFP_KERNEL | __GFP_ZERO, node_id);
 	if (disk) {
-		if (!init_disk_stats(disk)) {
+		if (!init_part_stats(&disk->part0)) {
 			kfree(disk);
 			return NULL;
 		}
-		if (minors > 1) {
-			int size = (minors - 1) * sizeof(struct hd_struct *);
-			disk->part = kmalloc_node(size,
-				GFP_KERNEL | __GFP_ZERO, node_id);
-			if (!disk->part) {
-				free_disk_stats(disk);
-				kfree(disk);
-				return NULL;
-			}
+		if (disk_expand_part_tbl(disk, 0)) {
+			free_part_stats(&disk->part0);
+			kfree(disk);
+			return NULL;
 		}
+		disk->part_tbl->part[0] = &disk->part0;
+
 		disk->minors = minors;
 		rand_initialize_disk(disk);
-		disk->dev.class = &block_class;
-		disk->dev.type = &disk_type;
-		device_initialize(&disk->dev);
+		disk_to_dev(disk)->class = &block_class;
+		disk_to_dev(disk)->type = &disk_type;
+		device_initialize(disk_to_dev(disk));
 		INIT_WORK(&disk->async_notify,
 			media_change_notify_thread);
+		disk->node_id = node_id;
 	}
 	return disk;
 }
-
-EXPORT_SYMBOL(alloc_disk);
 EXPORT_SYMBOL(alloc_disk_node);
 
 struct kobject *get_disk(struct gendisk *disk)
@@ -793,7 +1098,7 @@
 	owner = disk->fops->owner;
 	if (owner && !try_module_get(owner))
 		return NULL;
-	kobj = kobject_get(&disk->dev.kobj);
+	kobj = kobject_get(&disk_to_dev(disk)->kobj);
 	if (kobj == NULL) {
 		module_put(owner);
 		return NULL;
@@ -807,27 +1112,28 @@
 void put_disk(struct gendisk *disk)
 {
 	if (disk)
-		kobject_put(&disk->dev.kobj);
+		kobject_put(&disk_to_dev(disk)->kobj);
 }
 
 EXPORT_SYMBOL(put_disk);
 
 void set_device_ro(struct block_device *bdev, int flag)
 {
-	if (bdev->bd_contains != bdev)
-		bdev->bd_part->policy = flag;
-	else
-		bdev->bd_disk->policy = flag;
+	bdev->bd_part->policy = flag;
 }
 
 EXPORT_SYMBOL(set_device_ro);
 
 void set_disk_ro(struct gendisk *disk, int flag)
 {
-	int i;
-	disk->policy = flag;
-	for (i = 0; i < disk->minors - 1; i++)
-		if (disk->part[i]) disk->part[i]->policy = flag;
+	struct disk_part_iter piter;
+	struct hd_struct *part;
+
+	disk_part_iter_init(&piter, disk,
+			    DISK_PITER_INCL_EMPTY | DISK_PITER_INCL_PART0);
+	while ((part = disk_part_iter_next(&piter)))
+		part->policy = flag;
+	disk_part_iter_exit(&piter);
 }
 
 EXPORT_SYMBOL(set_disk_ro);
@@ -836,18 +1142,15 @@
 {
 	if (!bdev)
 		return 0;
-	else if (bdev->bd_contains != bdev)
-		return bdev->bd_part->policy;
-	else
-		return bdev->bd_disk->policy;
+	return bdev->bd_part->policy;
 }
 
 EXPORT_SYMBOL(bdev_read_only);
 
-int invalidate_partition(struct gendisk *disk, int index)
+int invalidate_partition(struct gendisk *disk, int partno)
 {
 	int res = 0;
-	struct block_device *bdev = bdget_disk(disk, index);
+	struct block_device *bdev = bdget_disk(disk, partno);
 	if (bdev) {
 		fsync_bdev(bdev);
 		res = __invalidate_device(bdev);
diff --git a/block/ioctl.c b/block/ioctl.c
index 77185e5..38bee321 100644
--- a/block/ioctl.c
+++ b/block/ioctl.c
@@ -12,11 +12,12 @@
 {
 	struct block_device *bdevp;
 	struct gendisk *disk;
+	struct hd_struct *part;
 	struct blkpg_ioctl_arg a;
 	struct blkpg_partition p;
+	struct disk_part_iter piter;
 	long long start, length;
-	int part;
-	int i;
+	int partno;
 	int err;
 
 	if (!capable(CAP_SYS_ADMIN))
@@ -28,8 +29,8 @@
 	disk = bdev->bd_disk;
 	if (bdev != bdev->bd_contains)
 		return -EINVAL;
-	part = p.pno;
-	if (part <= 0 || part >= disk->minors)
+	partno = p.pno;
+	if (partno <= 0)
 		return -EINVAL;
 	switch (a.op) {
 		case BLKPG_ADD_PARTITION:
@@ -43,36 +44,37 @@
 				    || pstart < 0 || plength < 0)
 					return -EINVAL;
 			}
-			/* partition number in use? */
-			mutex_lock(&bdev->bd_mutex);
-			if (disk->part[part - 1]) {
-				mutex_unlock(&bdev->bd_mutex);
-				return -EBUSY;
-			}
-			/* overlap? */
-			for (i = 0; i < disk->minors - 1; i++) {
-				struct hd_struct *s = disk->part[i];
 
-				if (!s)
-					continue;
-				if (!(start+length <= s->start_sect ||
-				      start >= s->start_sect + s->nr_sects)) {
+			mutex_lock(&bdev->bd_mutex);
+
+			/* overlap? */
+			disk_part_iter_init(&piter, disk,
+					    DISK_PITER_INCL_EMPTY);
+			while ((part = disk_part_iter_next(&piter))) {
+				if (!(start + length <= part->start_sect ||
+				      start >= part->start_sect + part->nr_sects)) {
+					disk_part_iter_exit(&piter);
 					mutex_unlock(&bdev->bd_mutex);
 					return -EBUSY;
 				}
 			}
+			disk_part_iter_exit(&piter);
+
 			/* all seems OK */
-			err = add_partition(disk, part, start, length, ADDPART_FLAG_NONE);
+			err = add_partition(disk, partno, start, length,
+					    ADDPART_FLAG_NONE);
 			mutex_unlock(&bdev->bd_mutex);
 			return err;
 		case BLKPG_DEL_PARTITION:
-			if (!disk->part[part-1])
+			part = disk_get_part(disk, partno);
+			if (!part)
 				return -ENXIO;
-			if (disk->part[part - 1]->nr_sects == 0)
-				return -ENXIO;
-			bdevp = bdget_disk(disk, part);
+
+			bdevp = bdget(part_devt(part));
+			disk_put_part(part);
 			if (!bdevp)
 				return -ENOMEM;
+
 			mutex_lock(&bdevp->bd_mutex);
 			if (bdevp->bd_openers) {
 				mutex_unlock(&bdevp->bd_mutex);
@@ -84,7 +86,7 @@
 			invalidate_bdev(bdevp);
 
 			mutex_lock_nested(&bdev->bd_mutex, 1);
-			delete_partition(disk, part);
+			delete_partition(disk, partno);
 			mutex_unlock(&bdev->bd_mutex);
 			mutex_unlock(&bdevp->bd_mutex);
 			bdput(bdevp);
@@ -100,7 +102,7 @@
 	struct gendisk *disk = bdev->bd_disk;
 	int res;
 
-	if (disk->minors == 1 || bdev != bdev->bd_contains)
+	if (!disk_partitionable(disk) || bdev != bdev->bd_contains)
 		return -EINVAL;
 	if (!capable(CAP_SYS_ADMIN))
 		return -EACCES;
@@ -111,6 +113,69 @@
 	return res;
 }
 
+static void blk_ioc_discard_endio(struct bio *bio, int err)
+{
+	if (err) {
+		if (err == -EOPNOTSUPP)
+			set_bit(BIO_EOPNOTSUPP, &bio->bi_flags);
+		clear_bit(BIO_UPTODATE, &bio->bi_flags);
+	}
+	complete(bio->bi_private);
+}
+
+static int blk_ioctl_discard(struct block_device *bdev, uint64_t start,
+			     uint64_t len)
+{
+	struct request_queue *q = bdev_get_queue(bdev);
+	int ret = 0;
+
+	if (start & 511)
+		return -EINVAL;
+	if (len & 511)
+		return -EINVAL;
+	start >>= 9;
+	len >>= 9;
+
+	if (start + len > (bdev->bd_inode->i_size >> 9))
+		return -EINVAL;
+
+	if (!q->prepare_discard_fn)
+		return -EOPNOTSUPP;
+
+	while (len && !ret) {
+		DECLARE_COMPLETION_ONSTACK(wait);
+		struct bio *bio;
+
+		bio = bio_alloc(GFP_KERNEL, 0);
+		if (!bio)
+			return -ENOMEM;
+
+		bio->bi_end_io = blk_ioc_discard_endio;
+		bio->bi_bdev = bdev;
+		bio->bi_private = &wait;
+		bio->bi_sector = start;
+
+		if (len > q->max_hw_sectors) {
+			bio->bi_size = q->max_hw_sectors << 9;
+			len -= q->max_hw_sectors;
+			start += q->max_hw_sectors;
+		} else {
+			bio->bi_size = len << 9;
+			len = 0;
+		}
+		submit_bio(DISCARD_NOBARRIER, bio);
+
+		wait_for_completion(&wait);
+
+		if (bio_flagged(bio, BIO_EOPNOTSUPP))
+			ret = -EOPNOTSUPP;
+		else if (!bio_flagged(bio, BIO_UPTODATE))
+			ret = -EIO;
+		bio_put(bio);
+	}
+	return ret;
+}
+
 static int put_ushort(unsigned long arg, unsigned short val)
 {
 	return put_user(val, (unsigned short __user *)arg);
@@ -258,6 +323,19 @@
 		set_device_ro(bdev, n);
 		unlock_kernel();
 		return 0;
+
+	case BLKDISCARD: {
+		uint64_t range[2];
+
+		if (!(file->f_mode & FMODE_WRITE))
+			return -EBADF;
+
+		if (copy_from_user(range, (void __user *)arg, sizeof(range)))
+			return -EFAULT;
+
+		return blk_ioctl_discard(bdev, range[0], range[1]);
+	}
+
 	case HDIO_GETGEO: {
 		struct hd_geometry geo;
 
diff --git a/block/scsi_ioctl.c b/block/scsi_ioctl.c
index ec4b7f2..c34272a 100644
--- a/block/scsi_ioctl.c
+++ b/block/scsi_ioctl.c
@@ -185,6 +185,7 @@
 	__set_bit(GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL, filter->write_ok);
 	__set_bit(GPCMD_LOAD_UNLOAD, filter->write_ok);
 	__set_bit(GPCMD_SET_STREAMING, filter->write_ok);
+	__set_bit(GPCMD_SET_READ_AHEAD, filter->write_ok);
 }
 EXPORT_SYMBOL_GPL(blk_set_cmd_filter_defaults);
 
@@ -313,11 +314,12 @@
 			goto out;
 		}
 
-		ret = blk_rq_map_user_iov(q, rq, iov, hdr->iovec_count,
-					  hdr->dxfer_len);
+		ret = blk_rq_map_user_iov(q, rq, NULL, iov, hdr->iovec_count,
+					  hdr->dxfer_len, GFP_KERNEL);
 		kfree(iov);
 	} else if (hdr->dxfer_len)
-		ret = blk_rq_map_user(q, rq, hdr->dxferp, hdr->dxfer_len);
+		ret = blk_rq_map_user(q, rq, NULL, hdr->dxferp, hdr->dxfer_len,
+				      GFP_KERNEL);
 
 	if (ret)
 		goto out;
diff --git a/crypto/Kconfig b/crypto/Kconfig
index d831859..39dbd8e 100644
--- a/crypto/Kconfig
+++ b/crypto/Kconfig
@@ -21,6 +21,14 @@
 
 comment "Crypto core or helper"
 
+config CRYPTO_FIPS
+	bool "FIPS 200 compliance"
+	help
+	  This options enables the fips boot option which is
+	  required if you want to system to operate in a FIPS 200
+	  certification.  You should say no unless you know what
+	  this is.
+
 config CRYPTO_ALGAPI
 	tristate
 	help
@@ -33,14 +41,21 @@
 config CRYPTO_BLKCIPHER
 	tristate
 	select CRYPTO_ALGAPI
+	select CRYPTO_RNG
 
 config CRYPTO_HASH
 	tristate
 	select CRYPTO_ALGAPI
 
+config CRYPTO_RNG
+	tristate
+	select CRYPTO_ALGAPI
+
 config CRYPTO_MANAGER
 	tristate "Cryptographic algorithm manager"
-	select CRYPTO_ALGAPI
+	select CRYPTO_AEAD
+	select CRYPTO_HASH
+	select CRYPTO_BLKCIPHER
 	help
 	  Create default cryptographic template instantiations such as
 	  cbc(aes).
@@ -85,9 +100,7 @@
 config CRYPTO_TEST
 	tristate "Testing module"
 	depends on m
-	select CRYPTO_ALGAPI
-	select CRYPTO_AEAD
-	select CRYPTO_BLKCIPHER
+	select CRYPTO_MANAGER
 	help
 	  Quick & dirty crypto test module.
 
@@ -113,6 +126,7 @@
 	tristate "Sequence Number IV Generator"
 	select CRYPTO_AEAD
 	select CRYPTO_BLKCIPHER
+	select CRYPTO_RNG
 	help
 	  This IV generator generates an IV based on a sequence number by
 	  xoring it with a salt.  This algorithm is mainly useful for CTR
@@ -219,7 +233,19 @@
 	  Castagnoli, et al Cyclic Redundancy-Check Algorithm.  Used
 	  by iSCSI for header and data digests and by others.
 	  See Castagnoli93.  This implementation uses lib/libcrc32c.
-          Module will be crc32c.
+	  Module will be crc32c.
+
+config CRYPTO_CRC32C_INTEL
+	tristate "CRC32c INTEL hardware acceleration"
+	depends on X86
+	select CRYPTO_HASH
+	help
+	  In Intel processor with SSE4.2 supported, the processor will
+	  support CRC32C implementation using hardware accelerated CRC32
+	  instruction. This option will create 'crc32c-intel' module,
+	  which will enable any routine to use the CRC32 instruction to
+	  gain performance compared with software implementation.
+	  Module will be crc32c-intel.
 
 config CRYPTO_MD4
 	tristate "MD4 digest algorithm"
@@ -243,55 +269,58 @@
 	  of the algorithm.
 
 config CRYPTO_RMD128
-  tristate "RIPEMD-128 digest algorithm"
-  select CRYPTO_ALGAPI
-  help
-    RIPEMD-128 (ISO/IEC 10118-3:2004).
+	tristate "RIPEMD-128 digest algorithm"
+	select CRYPTO_ALGAPI
+	help
+	  RIPEMD-128 (ISO/IEC 10118-3:2004).
 
-    RIPEMD-128 is a 128-bit cryptographic hash function. It should only
-    to be used as a secure replacement for RIPEMD. For other use cases
-    RIPEMD-160 should be used.
+	  RIPEMD-128 is a 128-bit cryptographic hash function. It should only
+	  to be used as a secure replacement for RIPEMD. For other use cases
+	  RIPEMD-160 should be used.
 
-    Developed by Hans Dobbertin, Antoon Bosselaers and Bart Preneel.
-    See <http://home.esat.kuleuven.be/~bosselae/ripemd160.html>
+	  Developed by Hans Dobbertin, Antoon Bosselaers and Bart Preneel.
+	  See <http://home.esat.kuleuven.be/~bosselae/ripemd160.html>
 
 config CRYPTO_RMD160
-  tristate "RIPEMD-160 digest algorithm"
-  select CRYPTO_ALGAPI
-  help
-    RIPEMD-160 (ISO/IEC 10118-3:2004).
+	tristate "RIPEMD-160 digest algorithm"
+	select CRYPTO_ALGAPI
+	help
+	  RIPEMD-160 (ISO/IEC 10118-3:2004).
 
-    RIPEMD-160 is a 160-bit cryptographic hash function. It is intended
-    to be used as a secure replacement for the 128-bit hash functions
-    MD4, MD5 and it's predecessor RIPEMD (not to be confused with RIPEMD-128).
+	  RIPEMD-160 is a 160-bit cryptographic hash function. It is intended
+	  to be used as a secure replacement for the 128-bit hash functions
+	  MD4, MD5 and it's predecessor RIPEMD
+	  (not to be confused with RIPEMD-128).
 
-    It's speed is comparable to SHA1 and there are no known attacks against
-    RIPEMD-160.
+	  It's speed is comparable to SHA1 and there are no known attacks
+	  against RIPEMD-160.
 
-    Developed by Hans Dobbertin, Antoon Bosselaers and Bart Preneel.
-    See <http://home.esat.kuleuven.be/~bosselae/ripemd160.html>
+	  Developed by Hans Dobbertin, Antoon Bosselaers and Bart Preneel.
+	  See <http://home.esat.kuleuven.be/~bosselae/ripemd160.html>
 
 config CRYPTO_RMD256
-  tristate "RIPEMD-256 digest algorithm"
-  select CRYPTO_ALGAPI
-  help
-    RIPEMD-256 is an optional extension of RIPEMD-128 with a 256 bit hash.
-    It is intended for applications that require longer hash-results, without
-    needing a larger security level (than RIPEMD-128).
+	tristate "RIPEMD-256 digest algorithm"
+	select CRYPTO_ALGAPI
+	help
+	  RIPEMD-256 is an optional extension of RIPEMD-128 with a
+	  256 bit hash. It is intended for applications that require
+	  longer hash-results, without needing a larger security level
+	  (than RIPEMD-128).
 
-    Developed by Hans Dobbertin, Antoon Bosselaers and Bart Preneel.
-    See <http://home.esat.kuleuven.be/~bosselae/ripemd160.html>
+	  Developed by Hans Dobbertin, Antoon Bosselaers and Bart Preneel.
+	  See <http://home.esat.kuleuven.be/~bosselae/ripemd160.html>
 
 config CRYPTO_RMD320
-  tristate "RIPEMD-320 digest algorithm"
-  select CRYPTO_ALGAPI
-  help
-    RIPEMD-320 is an optional extension of RIPEMD-160 with a 320 bit hash.
-    It is intended for applications that require longer hash-results, without
-    needing a larger security level (than RIPEMD-160).
+	tristate "RIPEMD-320 digest algorithm"
+	select CRYPTO_ALGAPI
+	help
+	  RIPEMD-320 is an optional extension of RIPEMD-160 with a
+	  320 bit hash. It is intended for applications that require
+	  longer hash-results, without needing a larger security level
+	  (than RIPEMD-160).
 
-    Developed by Hans Dobbertin, Antoon Bosselaers and Bart Preneel.
-    See <http://home.esat.kuleuven.be/~bosselae/ripemd160.html>
+	  Developed by Hans Dobbertin, Antoon Bosselaers and Bart Preneel.
+	  See <http://home.esat.kuleuven.be/~bosselae/ripemd160.html>
 
 config CRYPTO_SHA1
 	tristate "SHA1 digest algorithm"
@@ -308,8 +337,8 @@
 	  This version of SHA implements a 256 bit hash with 128 bits of
 	  security against collision attacks.
 
-          This code also includes SHA-224, a 224 bit hash with 112 bits
-          of security against collision attacks.
+	  This code also includes SHA-224, a 224 bit hash with 112 bits
+	  of security against collision attacks.
 
 config CRYPTO_SHA512
 	tristate "SHA384 and SHA512 digest algorithms"
@@ -666,6 +695,18 @@
 	help
 	  This is the LZO algorithm.
 
+comment "Random Number Generation"
+
+config CRYPTO_ANSI_CPRNG
+	tristate "Pseudo Random Number Generation for Cryptographic modules"
+	select CRYPTO_AES
+	select CRYPTO_RNG
+	select CRYPTO_FIPS
+	help
+	  This option enables the generic pseudo random number generator
+	  for cryptographic modules.  Uses the Algorithm specified in
+	  ANSI X9.31 A.2.4
+
 source "drivers/crypto/Kconfig"
 
 endif	# if CRYPTO
diff --git a/crypto/Makefile b/crypto/Makefile
index d4f3ed8..5862b80 100644
--- a/crypto/Makefile
+++ b/crypto/Makefile
@@ -5,6 +5,8 @@
 obj-$(CONFIG_CRYPTO) += crypto.o
 crypto-objs := api.o cipher.o digest.o compress.o
 
+obj-$(CONFIG_CRYPTO_FIPS) += fips.o
+
 crypto_algapi-$(CONFIG_PROC_FS) += proc.o
 crypto_algapi-objs := algapi.o scatterwalk.o $(crypto_algapi-y)
 obj-$(CONFIG_CRYPTO_ALGAPI) += crypto_algapi.o
@@ -13,15 +15,17 @@
 
 crypto_blkcipher-objs := ablkcipher.o
 crypto_blkcipher-objs += blkcipher.o
-crypto_blkcipher-objs += chainiv.o
-crypto_blkcipher-objs += eseqiv.o
 obj-$(CONFIG_CRYPTO_BLKCIPHER) += crypto_blkcipher.o
+obj-$(CONFIG_CRYPTO_BLKCIPHER) += chainiv.o
+obj-$(CONFIG_CRYPTO_BLKCIPHER) += eseqiv.o
 obj-$(CONFIG_CRYPTO_SEQIV) += seqiv.o
 
 crypto_hash-objs := hash.o
 crypto_hash-objs += ahash.o
 obj-$(CONFIG_CRYPTO_HASH) += crypto_hash.o
 
+cryptomgr-objs := algboss.o testmgr.o
+
 obj-$(CONFIG_CRYPTO_MANAGER) += cryptomgr.o
 obj-$(CONFIG_CRYPTO_HMAC) += hmac.o
 obj-$(CONFIG_CRYPTO_XCBC) += xcbc.o
@@ -69,7 +73,9 @@
 obj-$(CONFIG_CRYPTO_CRC32C) += crc32c.o
 obj-$(CONFIG_CRYPTO_AUTHENC) += authenc.o
 obj-$(CONFIG_CRYPTO_LZO) += lzo.o
-
+obj-$(CONFIG_CRYPTO_RNG) += rng.o
+obj-$(CONFIG_CRYPTO_RNG) += krng.o
+obj-$(CONFIG_CRYPTO_ANSI_CPRNG) += ansi_cprng.o
 obj-$(CONFIG_CRYPTO_TEST) += tcrypt.o
 
 #
diff --git a/crypto/algapi.c b/crypto/algapi.c
index e65cb50..7c41e740 100644
--- a/crypto/algapi.c
+++ b/crypto/algapi.c
@@ -21,15 +21,15 @@
 
 #include "internal.h"
 
+static void crypto_remove_final(struct list_head *list);
+
 static LIST_HEAD(crypto_template_list);
 
 void crypto_larval_error(const char *name, u32 type, u32 mask)
 {
 	struct crypto_alg *alg;
 
-	down_read(&crypto_alg_sem);
-	alg = __crypto_alg_lookup(name, type, mask);
-	up_read(&crypto_alg_sem);
+	alg = crypto_alg_lookup(name, type, mask);
 
 	if (alg) {
 		if (crypto_is_larval(alg)) {
@@ -128,23 +128,97 @@
 	}
 }
 
-static int __crypto_register_alg(struct crypto_alg *alg,
-				 struct list_head *list)
+static struct crypto_larval *__crypto_register_alg(struct crypto_alg *alg)
 {
 	struct crypto_alg *q;
+	struct crypto_larval *larval;
 	int ret = -EAGAIN;
 
 	if (crypto_is_dead(alg))
-		goto out;
+		goto err;
 
 	INIT_LIST_HEAD(&alg->cra_users);
 
+	/* No cheating! */
+	alg->cra_flags &= ~CRYPTO_ALG_TESTED;
+
 	ret = -EEXIST;
 
 	atomic_set(&alg->cra_refcnt, 1);
 	list_for_each_entry(q, &crypto_alg_list, cra_list) {
 		if (q == alg)
-			goto out;
+			goto err;
+
+		if (crypto_is_larval(q)) {
+			if (!strcmp(alg->cra_driver_name, q->cra_driver_name))
+				goto err;
+			continue;
+		}
+
+		if (!strcmp(q->cra_driver_name, alg->cra_name) ||
+		    !strcmp(q->cra_name, alg->cra_driver_name))
+			goto err;
+	}
+
+	larval = crypto_larval_alloc(alg->cra_name,
+				     alg->cra_flags | CRYPTO_ALG_TESTED, 0);
+	if (IS_ERR(larval))
+		goto out;
+
+	ret = -ENOENT;
+	larval->adult = crypto_mod_get(alg);
+	if (!larval->adult)
+		goto free_larval;
+
+	atomic_set(&larval->alg.cra_refcnt, 1);
+	memcpy(larval->alg.cra_driver_name, alg->cra_driver_name,
+	       CRYPTO_MAX_ALG_NAME);
+	larval->alg.cra_priority = alg->cra_priority;
+
+	list_add(&alg->cra_list, &crypto_alg_list);
+	list_add(&larval->alg.cra_list, &crypto_alg_list);
+
+out:	
+	return larval;
+
+free_larval:
+	kfree(larval);
+err:
+	larval = ERR_PTR(ret);
+	goto out;
+}
+
+void crypto_alg_tested(const char *name, int err)
+{
+	struct crypto_larval *test;
+	struct crypto_alg *alg;
+	struct crypto_alg *q;
+	LIST_HEAD(list);
+
+	down_write(&crypto_alg_sem);
+	list_for_each_entry(q, &crypto_alg_list, cra_list) {
+		if (!crypto_is_larval(q))
+			continue;
+
+		test = (struct crypto_larval *)q;
+
+		if (!strcmp(q->cra_driver_name, name))
+			goto found;
+	}
+
+	printk(KERN_ERR "alg: Unexpected test result for %s: %d\n", name, err);
+	goto unlock;
+
+found:
+	alg = test->adult;
+	if (err || list_empty(&alg->cra_list))
+		goto complete;
+
+	alg->cra_flags |= CRYPTO_ALG_TESTED;
+
+	list_for_each_entry(q, &crypto_alg_list, cra_list) {
+		if (q == alg)
+			continue;
 
 		if (crypto_is_moribund(q))
 			continue;
@@ -180,17 +254,18 @@
 		    q->cra_priority > alg->cra_priority)
 			continue;
 
-		crypto_remove_spawns(&q->cra_users, list, alg->cra_flags);
+		crypto_remove_spawns(&q->cra_users, &list, alg->cra_flags);
 	}
-	
-	list_add(&alg->cra_list, &crypto_alg_list);
 
-	crypto_notify(CRYPTO_MSG_ALG_REGISTER, alg);
-	ret = 0;
+complete:
+	complete_all(&test->completion);
 
-out:	
-	return ret;
+unlock:
+	up_write(&crypto_alg_sem);
+
+	crypto_remove_final(&list);
 }
+EXPORT_SYMBOL_GPL(crypto_alg_tested);
 
 static void crypto_remove_final(struct list_head *list)
 {
@@ -203,9 +278,27 @@
 	}
 }
 
+static void crypto_wait_for_test(struct crypto_larval *larval)
+{
+	int err;
+
+	err = crypto_probing_notify(CRYPTO_MSG_ALG_REGISTER, larval->adult);
+	if (err != NOTIFY_STOP) {
+		if (WARN_ON(err != NOTIFY_DONE))
+			goto out;
+		crypto_alg_tested(larval->alg.cra_driver_name, 0);
+	}
+
+	err = wait_for_completion_interruptible(&larval->completion);
+	WARN_ON(err);
+
+out:
+	crypto_larval_kill(&larval->alg);
+}
+
 int crypto_register_alg(struct crypto_alg *alg)
 {
-	LIST_HEAD(list);
+	struct crypto_larval *larval;
 	int err;
 
 	err = crypto_check_alg(alg);
@@ -213,11 +306,14 @@
 		return err;
 
 	down_write(&crypto_alg_sem);
-	err = __crypto_register_alg(alg, &list);
+	larval = __crypto_register_alg(alg);
 	up_write(&crypto_alg_sem);
 
-	crypto_remove_final(&list);
-	return err;
+	if (IS_ERR(larval))
+		return PTR_ERR(larval);
+
+	crypto_wait_for_test(larval);
+	return 0;
 }
 EXPORT_SYMBOL_GPL(crypto_register_alg);
 
@@ -335,8 +431,8 @@
 int crypto_register_instance(struct crypto_template *tmpl,
 			     struct crypto_instance *inst)
 {
-	LIST_HEAD(list);
-	int err = -EINVAL;
+	struct crypto_larval *larval;
+	int err;
 
 	err = crypto_check_alg(&inst->alg);
 	if (err)
@@ -346,8 +442,8 @@
 
 	down_write(&crypto_alg_sem);
 
-	err = __crypto_register_alg(&inst->alg, &list);
-	if (err)
+	larval = __crypto_register_alg(&inst->alg);
+	if (IS_ERR(larval))
 		goto unlock;
 
 	hlist_add_head(&inst->list, &tmpl->instances);
@@ -356,7 +452,12 @@
 unlock:
 	up_write(&crypto_alg_sem);
 
-	crypto_remove_final(&list);
+	err = PTR_ERR(larval);
+	if (IS_ERR(larval))
+		goto err;
+
+	crypto_wait_for_test(larval);
+	err = 0;
 
 err:
 	return err;
diff --git a/crypto/algboss.c b/crypto/algboss.c
new file mode 100644
index 0000000..4601e426
--- /dev/null
+++ b/crypto/algboss.c
@@ -0,0 +1,300 @@
+/*
+ * Create default crypto algorithm instances.
+ *
+ * Copyright (c) 2006 Herbert Xu <herbert@gondor.apana.org.au>
+ *
+ * This program is free software; you can redistribute it and/or 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/crypto.h>
+#include <linux/ctype.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/kthread.h>
+#include <linux/module.h>
+#include <linux/notifier.h>
+#include <linux/rtnetlink.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+
+#include "internal.h"
+
+struct cryptomgr_param {
+	struct rtattr *tb[CRYPTO_MAX_ATTRS + 2];
+
+	struct {
+		struct rtattr attr;
+		struct crypto_attr_type data;
+	} type;
+
+	union {
+		struct rtattr attr;
+		struct {
+			struct rtattr attr;
+			struct crypto_attr_alg data;
+		} alg;
+		struct {
+			struct rtattr attr;
+			struct crypto_attr_u32 data;
+		} nu32;
+	} attrs[CRYPTO_MAX_ATTRS];
+
+	char larval[CRYPTO_MAX_ALG_NAME];
+	char template[CRYPTO_MAX_ALG_NAME];
+
+	u32 otype;
+	u32 omask;
+};
+
+struct crypto_test_param {
+	char driver[CRYPTO_MAX_ALG_NAME];
+	char alg[CRYPTO_MAX_ALG_NAME];
+	u32 type;
+};
+
+static int cryptomgr_probe(void *data)
+{
+	struct cryptomgr_param *param = data;
+	struct crypto_template *tmpl;
+	struct crypto_instance *inst;
+	int err;
+
+	tmpl = crypto_lookup_template(param->template);
+	if (!tmpl)
+		goto err;
+
+	do {
+		inst = tmpl->alloc(param->tb);
+		if (IS_ERR(inst))
+			err = PTR_ERR(inst);
+		else if ((err = crypto_register_instance(tmpl, inst)))
+			tmpl->free(inst);
+	} while (err == -EAGAIN && !signal_pending(current));
+
+	crypto_tmpl_put(tmpl);
+
+	if (err)
+		goto err;
+
+out:
+	kfree(param);
+	module_put_and_exit(0);
+
+err:
+	crypto_larval_error(param->larval, param->otype, param->omask);
+	goto out;
+}
+
+static int cryptomgr_schedule_probe(struct crypto_larval *larval)
+{
+	struct task_struct *thread;
+	struct cryptomgr_param *param;
+	const char *name = larval->alg.cra_name;
+	const char *p;
+	unsigned int len;
+	int i;
+
+	if (!try_module_get(THIS_MODULE))
+		goto err;
+
+	param = kzalloc(sizeof(*param), GFP_KERNEL);
+	if (!param)
+		goto err_put_module;
+
+	for (p = name; isalnum(*p) || *p == '-' || *p == '_'; p++)
+		;
+
+	len = p - name;
+	if (!len || *p != '(')
+		goto err_free_param;
+
+	memcpy(param->template, name, len);
+
+	i = 0;
+	for (;;) {
+		int notnum = 0;
+
+		name = ++p;
+		len = 0;
+
+		for (; isalnum(*p) || *p == '-' || *p == '_'; p++)
+			notnum |= !isdigit(*p);
+
+		if (*p == '(') {
+			int recursion = 0;
+
+			for (;;) {
+				if (!*++p)
+					goto err_free_param;
+				if (*p == '(')
+					recursion++;
+				else if (*p == ')' && !recursion--)
+					break;
+			}
+
+			notnum = 1;
+			p++;
+		}
+
+		len = p - name;
+		if (!len)
+			goto err_free_param;
+
+		if (notnum) {
+			param->attrs[i].alg.attr.rta_len =
+				sizeof(param->attrs[i].alg);
+			param->attrs[i].alg.attr.rta_type = CRYPTOA_ALG;
+			memcpy(param->attrs[i].alg.data.name, name, len);
+		} else {
+			param->attrs[i].nu32.attr.rta_len =
+				sizeof(param->attrs[i].nu32);
+			param->attrs[i].nu32.attr.rta_type = CRYPTOA_U32;
+			param->attrs[i].nu32.data.num =
+				simple_strtol(name, NULL, 0);
+		}
+
+		param->tb[i + 1] = &param->attrs[i].attr;
+		i++;
+
+		if (i >= CRYPTO_MAX_ATTRS)
+			goto err_free_param;
+
+		if (*p == ')')
+			break;
+
+		if (*p != ',')
+			goto err_free_param;
+	}
+
+	if (!i)
+		goto err_free_param;
+
+	param->tb[i + 1] = NULL;
+
+	param->type.attr.rta_len = sizeof(param->type);
+	param->type.attr.rta_type = CRYPTOA_TYPE;
+	param->type.data.type = larval->alg.cra_flags & ~CRYPTO_ALG_TESTED;
+	param->type.data.mask = larval->mask & ~CRYPTO_ALG_TESTED;
+	param->tb[0] = &param->type.attr;
+
+	param->otype = larval->alg.cra_flags;
+	param->omask = larval->mask;
+
+	memcpy(param->larval, larval->alg.cra_name, CRYPTO_MAX_ALG_NAME);
+
+	thread = kthread_run(cryptomgr_probe, param, "cryptomgr_probe");
+	if (IS_ERR(thread))
+		goto err_free_param;
+
+	return NOTIFY_STOP;
+
+err_free_param:
+	kfree(param);
+err_put_module:
+	module_put(THIS_MODULE);
+err:
+	return NOTIFY_OK;
+}
+
+static int cryptomgr_test(void *data)
+{
+	struct crypto_test_param *param = data;
+	u32 type = param->type;
+	int err = 0;
+
+	if (!((type ^ CRYPTO_ALG_TYPE_BLKCIPHER) &
+	      CRYPTO_ALG_TYPE_BLKCIPHER_MASK) && !(type & CRYPTO_ALG_GENIV))
+		goto skiptest;
+
+	err = alg_test(param->driver, param->alg, type, CRYPTO_ALG_TESTED);
+
+skiptest:
+	crypto_alg_tested(param->driver, err);
+
+	kfree(param);
+	module_put_and_exit(0);
+}
+
+static int cryptomgr_schedule_test(struct crypto_alg *alg)
+{
+	struct task_struct *thread;
+	struct crypto_test_param *param;
+
+	if (!try_module_get(THIS_MODULE))
+		goto err;
+
+	param = kzalloc(sizeof(*param), GFP_KERNEL);
+	if (!param)
+		goto err_put_module;
+
+	memcpy(param->driver, alg->cra_driver_name, sizeof(param->driver));
+	memcpy(param->alg, alg->cra_name, sizeof(param->alg));
+	param->type = alg->cra_flags;
+
+	thread = kthread_run(cryptomgr_test, param, "cryptomgr_test");
+	if (IS_ERR(thread))
+		goto err_free_param;
+
+	return NOTIFY_STOP;
+
+err_free_param:
+	kfree(param);
+err_put_module:
+	module_put(THIS_MODULE);
+err:
+	return NOTIFY_OK;
+}
+
+static int cryptomgr_notify(struct notifier_block *this, unsigned long msg,
+			    void *data)
+{
+	switch (msg) {
+	case CRYPTO_MSG_ALG_REQUEST:
+		return cryptomgr_schedule_probe(data);
+	case CRYPTO_MSG_ALG_REGISTER:
+		return cryptomgr_schedule_test(data);
+	}
+
+	return NOTIFY_DONE;
+}
+
+static struct notifier_block cryptomgr_notifier = {
+	.notifier_call = cryptomgr_notify,
+};
+
+static int __init cryptomgr_init(void)
+{
+	int err;
+
+	err = testmgr_init();
+	if (err)
+		return err;
+
+	err = crypto_register_notifier(&cryptomgr_notifier);
+	if (err)
+		goto free_testmgr;
+
+	return 0;
+
+free_testmgr:
+	testmgr_exit();
+	return err;
+}
+
+static void __exit cryptomgr_exit(void)
+{
+	int err = crypto_unregister_notifier(&cryptomgr_notifier);
+	BUG_ON(err);
+
+	testmgr_exit();
+}
+
+subsys_initcall(cryptomgr_init);
+module_exit(cryptomgr_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Crypto Algorithm Manager");
diff --git a/crypto/ansi_cprng.c b/crypto/ansi_cprng.c
new file mode 100644
index 0000000..72db0fd
--- /dev/null
+++ b/crypto/ansi_cprng.c
@@ -0,0 +1,417 @@
+/*
+ * PRNG: Pseudo Random Number Generator
+ *       Based on NIST Recommended PRNG From ANSI X9.31 Appendix A.2.4 using
+ *       AES 128 cipher
+ *
+ *  (C) Neil Horman <nhorman@tuxdriver.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
+ *  any later version.
+ *
+ *
+ */
+
+#include <crypto/internal/rng.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/string.h>
+
+#include "internal.h"
+
+#define DEFAULT_PRNG_KEY "0123456789abcdef"
+#define DEFAULT_PRNG_KSZ 16
+#define DEFAULT_BLK_SZ 16
+#define DEFAULT_V_SEED "zaybxcwdveuftgsh"
+
+/*
+ * Flags for the prng_context flags field
+ */
+
+#define PRNG_FIXED_SIZE 0x1
+#define PRNG_NEED_RESET 0x2
+
+/*
+ * Note: DT is our counter value
+ *	 I is our intermediate value
+ *	 V is our seed vector
+ * See http://csrc.nist.gov/groups/STM/cavp/documents/rng/931rngext.pdf
+ * for implementation details
+ */
+
+
+struct prng_context {
+	spinlock_t prng_lock;
+	unsigned char rand_data[DEFAULT_BLK_SZ];
+	unsigned char last_rand_data[DEFAULT_BLK_SZ];
+	unsigned char DT[DEFAULT_BLK_SZ];
+	unsigned char I[DEFAULT_BLK_SZ];
+	unsigned char V[DEFAULT_BLK_SZ];
+	u32 rand_data_valid;
+	struct crypto_cipher *tfm;
+	u32 flags;
+};
+
+static int dbg;
+
+static void hexdump(char *note, unsigned char *buf, unsigned int len)
+{
+	if (dbg) {
+		printk(KERN_CRIT "%s", note);
+		print_hex_dump(KERN_CONT, "", DUMP_PREFIX_OFFSET,
+				16, 1,
+				buf, len, false);
+	}
+}
+
+#define dbgprint(format, args...) do {\
+if (dbg)\
+	printk(format, ##args);\
+} while (0)
+
+static void xor_vectors(unsigned char *in1, unsigned char *in2,
+			unsigned char *out, unsigned int size)
+{
+	int i;
+
+	for (i = 0; i < size; i++)
+		out[i] = in1[i] ^ in2[i];
+
+}
+/*
+ * Returns DEFAULT_BLK_SZ bytes of random data per call
+ * returns 0 if generation succeded, <0 if something went wrong
+ */
+static int _get_more_prng_bytes(struct prng_context *ctx)
+{
+	int i;
+	unsigned char tmp[DEFAULT_BLK_SZ];
+	unsigned char *output = NULL;
+
+
+	dbgprint(KERN_CRIT "Calling _get_more_prng_bytes for context %p\n",
+		ctx);
+
+	hexdump("Input DT: ", ctx->DT, DEFAULT_BLK_SZ);
+	hexdump("Input I: ", ctx->I, DEFAULT_BLK_SZ);
+	hexdump("Input V: ", ctx->V, DEFAULT_BLK_SZ);
+
+	/*
+	 * This algorithm is a 3 stage state machine
+	 */
+	for (i = 0; i < 3; i++) {
+
+		switch (i) {
+		case 0:
+			/*
+			 * Start by encrypting the counter value
+			 * This gives us an intermediate value I
+			 */
+			memcpy(tmp, ctx->DT, DEFAULT_BLK_SZ);
+			output = ctx->I;
+			hexdump("tmp stage 0: ", tmp, DEFAULT_BLK_SZ);
+			break;
+		case 1:
+
+			/*
+			 * Next xor I with our secret vector V
+			 * encrypt that result to obtain our
+			 * pseudo random data which we output
+			 */
+			xor_vectors(ctx->I, ctx->V, tmp, DEFAULT_BLK_SZ);
+			hexdump("tmp stage 1: ", tmp, DEFAULT_BLK_SZ);
+			output = ctx->rand_data;
+			break;
+		case 2:
+			/*
+			 * First check that we didn't produce the same
+			 * random data that we did last time around through this
+			 */
+			if (!memcmp(ctx->rand_data, ctx->last_rand_data,
+					DEFAULT_BLK_SZ)) {
+				printk(KERN_ERR
+					"ctx %p Failed repetition check!\n",
+					ctx);
+				ctx->flags |= PRNG_NEED_RESET;
+				return -EINVAL;
+			}
+			memcpy(ctx->last_rand_data, ctx->rand_data,
+				DEFAULT_BLK_SZ);
+
+			/*
+			 * Lastly xor the random data with I
+			 * and encrypt that to obtain a new secret vector V
+			 */
+			xor_vectors(ctx->rand_data, ctx->I, tmp,
+				DEFAULT_BLK_SZ);
+			output = ctx->V;
+			hexdump("tmp stage 2: ", tmp, DEFAULT_BLK_SZ);
+			break;
+		}
+
+
+		/* do the encryption */
+		crypto_cipher_encrypt_one(ctx->tfm, output, tmp);
+
+	}
+
+	/*
+	 * Now update our DT value
+	 */
+	for (i = 0; i < DEFAULT_BLK_SZ; i++) {
+		ctx->DT[i] += 1;
+		if (ctx->DT[i] != 0)
+			break;
+	}
+
+	dbgprint("Returning new block for context %p\n", ctx);
+	ctx->rand_data_valid = 0;
+
+	hexdump("Output DT: ", ctx->DT, DEFAULT_BLK_SZ);
+	hexdump("Output I: ", ctx->I, DEFAULT_BLK_SZ);
+	hexdump("Output V: ", ctx->V, DEFAULT_BLK_SZ);
+	hexdump("New Random Data: ", ctx->rand_data, DEFAULT_BLK_SZ);
+
+	return 0;
+}
+
+/* Our exported functions */
+static int get_prng_bytes(char *buf, size_t nbytes, struct prng_context *ctx)
+{
+	unsigned long flags;
+	unsigned char *ptr = buf;
+	unsigned int byte_count = (unsigned int)nbytes;
+	int err;
+
+
+	if (nbytes < 0)
+		return -EINVAL;
+
+	spin_lock_irqsave(&ctx->prng_lock, flags);
+
+	err = -EINVAL;
+	if (ctx->flags & PRNG_NEED_RESET)
+		goto done;
+
+	/*
+	 * If the FIXED_SIZE flag is on, only return whole blocks of
+	 * pseudo random data
+	 */
+	err = -EINVAL;
+	if (ctx->flags & PRNG_FIXED_SIZE) {
+		if (nbytes < DEFAULT_BLK_SZ)
+			goto done;
+		byte_count = DEFAULT_BLK_SZ;
+	}
+
+	err = byte_count;
+
+	dbgprint(KERN_CRIT "getting %d random bytes for context %p\n",
+		byte_count, ctx);
+
+
+remainder:
+	if (ctx->rand_data_valid == DEFAULT_BLK_SZ) {
+		if (_get_more_prng_bytes(ctx) < 0) {
+			memset(buf, 0, nbytes);
+			err = -EINVAL;
+			goto done;
+		}
+	}
+
+	/*
+	 * Copy up to the next whole block size
+	 */
+	if (byte_count < DEFAULT_BLK_SZ) {
+		for (; ctx->rand_data_valid < DEFAULT_BLK_SZ;
+			ctx->rand_data_valid++) {
+			*ptr = ctx->rand_data[ctx->rand_data_valid];
+			ptr++;
+			byte_count--;
+			if (byte_count == 0)
+				goto done;
+		}
+	}
+
+	/*
+	 * Now copy whole blocks
+	 */
+	for (; byte_count >= DEFAULT_BLK_SZ; byte_count -= DEFAULT_BLK_SZ) {
+		if (_get_more_prng_bytes(ctx) < 0) {
+			memset(buf, 0, nbytes);
+			err = -EINVAL;
+			goto done;
+		}
+		memcpy(ptr, ctx->rand_data, DEFAULT_BLK_SZ);
+		ctx->rand_data_valid += DEFAULT_BLK_SZ;
+		ptr += DEFAULT_BLK_SZ;
+	}
+
+	/*
+	 * Now copy any extra partial data
+	 */
+	if (byte_count)
+		goto remainder;
+
+done:
+	spin_unlock_irqrestore(&ctx->prng_lock, flags);
+	dbgprint(KERN_CRIT "returning %d from get_prng_bytes in context %p\n",
+		err, ctx);
+	return err;
+}
+
+static void free_prng_context(struct prng_context *ctx)
+{
+	crypto_free_cipher(ctx->tfm);
+}
+
+static int reset_prng_context(struct prng_context *ctx,
+			      unsigned char *key, size_t klen,
+			      unsigned char *V, unsigned char *DT)
+{
+	int ret;
+	int rc = -EINVAL;
+	unsigned char *prng_key;
+
+	spin_lock(&ctx->prng_lock);
+	ctx->flags |= PRNG_NEED_RESET;
+
+	prng_key = (key != NULL) ? key : (unsigned char *)DEFAULT_PRNG_KEY;
+
+	if (!key)
+		klen = DEFAULT_PRNG_KSZ;
+
+	if (V)
+		memcpy(ctx->V, V, DEFAULT_BLK_SZ);
+	else
+		memcpy(ctx->V, DEFAULT_V_SEED, DEFAULT_BLK_SZ);
+
+	if (DT)
+		memcpy(ctx->DT, DT, DEFAULT_BLK_SZ);
+	else
+		memset(ctx->DT, 0, DEFAULT_BLK_SZ);
+
+	memset(ctx->rand_data, 0, DEFAULT_BLK_SZ);
+	memset(ctx->last_rand_data, 0, DEFAULT_BLK_SZ);
+
+	if (ctx->tfm)
+		crypto_free_cipher(ctx->tfm);
+
+	ctx->tfm = crypto_alloc_cipher("aes", 0, 0);
+	if (IS_ERR(ctx->tfm)) {
+		dbgprint(KERN_CRIT "Failed to alloc tfm for context %p\n",
+			ctx);
+		ctx->tfm = NULL;
+		goto out;
+	}
+
+	ctx->rand_data_valid = DEFAULT_BLK_SZ;
+
+	ret = crypto_cipher_setkey(ctx->tfm, prng_key, klen);
+	if (ret) {
+		dbgprint(KERN_CRIT "PRNG: setkey() failed flags=%x\n",
+			crypto_cipher_get_flags(ctx->tfm));
+		crypto_free_cipher(ctx->tfm);
+		goto out;
+	}
+
+	rc = 0;
+	ctx->flags &= ~PRNG_NEED_RESET;
+out:
+	spin_unlock(&ctx->prng_lock);
+
+	return rc;
+
+}
+
+static int cprng_init(struct crypto_tfm *tfm)
+{
+	struct prng_context *ctx = crypto_tfm_ctx(tfm);
+
+	spin_lock_init(&ctx->prng_lock);
+
+	return reset_prng_context(ctx, NULL, DEFAULT_PRNG_KSZ, NULL, NULL);
+}
+
+static void cprng_exit(struct crypto_tfm *tfm)
+{
+	free_prng_context(crypto_tfm_ctx(tfm));
+}
+
+static int cprng_get_random(struct crypto_rng *tfm, u8 *rdata,
+			    unsigned int dlen)
+{
+	struct prng_context *prng = crypto_rng_ctx(tfm);
+
+	return get_prng_bytes(rdata, dlen, prng);
+}
+
+static int cprng_reset(struct crypto_rng *tfm, u8 *seed, unsigned int slen)
+{
+	struct prng_context *prng = crypto_rng_ctx(tfm);
+	u8 *key = seed + DEFAULT_PRNG_KSZ;
+
+	if (slen < DEFAULT_PRNG_KSZ + DEFAULT_BLK_SZ)
+		return -EINVAL;
+
+	reset_prng_context(prng, key, DEFAULT_PRNG_KSZ, seed, NULL);
+
+	if (prng->flags & PRNG_NEED_RESET)
+		return -EINVAL;
+	return 0;
+}
+
+static struct crypto_alg rng_alg = {
+	.cra_name		= "stdrng",
+	.cra_driver_name	= "ansi_cprng",
+	.cra_priority		= 100,
+	.cra_flags		= CRYPTO_ALG_TYPE_RNG,
+	.cra_ctxsize		= sizeof(struct prng_context),
+	.cra_type		= &crypto_rng_type,
+	.cra_module		= THIS_MODULE,
+	.cra_list		= LIST_HEAD_INIT(rng_alg.cra_list),
+	.cra_init		= cprng_init,
+	.cra_exit		= cprng_exit,
+	.cra_u			= {
+		.rng = {
+			.rng_make_random	= cprng_get_random,
+			.rng_reset		= cprng_reset,
+			.seedsize = DEFAULT_PRNG_KSZ + DEFAULT_BLK_SZ,
+		}
+	}
+};
+
+
+/* Module initalization */
+static int __init prng_mod_init(void)
+{
+	int ret = 0;
+
+	if (fips_enabled)
+		rng_alg.cra_priority += 200;
+
+	ret = crypto_register_alg(&rng_alg);
+
+	if (ret)
+		goto out;
+out:
+	return 0;
+}
+
+static void __exit prng_mod_fini(void)
+{
+	crypto_unregister_alg(&rng_alg);
+	return;
+}
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Software Pseudo Random Number Generator");
+MODULE_AUTHOR("Neil Horman <nhorman@tuxdriver.com>");
+module_param(dbg, int, 0);
+MODULE_PARM_DESC(dbg, "Boolean to enable debugging (0/1 == off/on)");
+module_init(prng_mod_init);
+module_exit(prng_mod_fini);
+MODULE_ALIAS("stdrng");
diff --git a/crypto/api.c b/crypto/api.c
index d06e332..0444d24 100644
--- a/crypto/api.c
+++ b/crypto/api.c
@@ -55,7 +55,13 @@
 }
 EXPORT_SYMBOL_GPL(crypto_mod_put);
 
-struct crypto_alg *__crypto_alg_lookup(const char *name, u32 type, u32 mask)
+static inline int crypto_is_test_larval(struct crypto_larval *larval)
+{
+	return larval->alg.cra_driver_name[0];
+}
+
+static struct crypto_alg *__crypto_alg_lookup(const char *name, u32 type,
+					      u32 mask)
 {
 	struct crypto_alg *q, *alg = NULL;
 	int best = -2;
@@ -70,6 +76,7 @@
 			continue;
 
 		if (crypto_is_larval(q) &&
+		    !crypto_is_test_larval((struct crypto_larval *)q) &&
 		    ((struct crypto_larval *)q)->mask != mask)
 			continue;
 
@@ -92,7 +99,6 @@
 
 	return alg;
 }
-EXPORT_SYMBOL_GPL(__crypto_alg_lookup);
 
 static void crypto_larval_destroy(struct crypto_alg *alg)
 {
@@ -104,10 +110,8 @@
 	kfree(larval);
 }
 
-static struct crypto_alg *crypto_larval_alloc(const char *name, u32 type,
-					      u32 mask)
+struct crypto_larval *crypto_larval_alloc(const char *name, u32 type, u32 mask)
 {
-	struct crypto_alg *alg;
 	struct crypto_larval *larval;
 
 	larval = kzalloc(sizeof(*larval), GFP_KERNEL);
@@ -119,10 +123,25 @@
 	larval->alg.cra_priority = -1;
 	larval->alg.cra_destroy = crypto_larval_destroy;
 
-	atomic_set(&larval->alg.cra_refcnt, 2);
 	strlcpy(larval->alg.cra_name, name, CRYPTO_MAX_ALG_NAME);
 	init_completion(&larval->completion);
 
+	return larval;
+}
+EXPORT_SYMBOL_GPL(crypto_larval_alloc);
+
+static struct crypto_alg *crypto_larval_add(const char *name, u32 type,
+					    u32 mask)
+{
+	struct crypto_alg *alg;
+	struct crypto_larval *larval;
+
+	larval = crypto_larval_alloc(name, type, mask);
+	if (IS_ERR(larval))
+		return ERR_CAST(larval);
+
+	atomic_set(&larval->alg.cra_refcnt, 2);
+
 	down_write(&crypto_alg_sem);
 	alg = __crypto_alg_lookup(name, type, mask);
 	if (!alg) {
@@ -152,21 +171,29 @@
 static struct crypto_alg *crypto_larval_wait(struct crypto_alg *alg)
 {
 	struct crypto_larval *larval = (void *)alg;
+	long timeout;
 
-	wait_for_completion_interruptible_timeout(&larval->completion, 60 * HZ);
+	timeout = wait_for_completion_interruptible_timeout(
+		&larval->completion, 60 * HZ);
+
 	alg = larval->adult;
-	if (alg) {
-		if (!crypto_mod_get(alg))
-			alg = ERR_PTR(-EAGAIN);
-	} else
+	if (timeout < 0)
+		alg = ERR_PTR(-EINTR);
+	else if (!timeout)
+		alg = ERR_PTR(-ETIMEDOUT);
+	else if (!alg)
 		alg = ERR_PTR(-ENOENT);
+	else if (crypto_is_test_larval(larval) &&
+		 !(alg->cra_flags & CRYPTO_ALG_TESTED))
+		alg = ERR_PTR(-EAGAIN);
+	else if (!crypto_mod_get(alg))
+		alg = ERR_PTR(-EAGAIN);
 	crypto_mod_put(&larval->alg);
 
 	return alg;
 }
 
-static struct crypto_alg *crypto_alg_lookup(const char *name, u32 type,
-					    u32 mask)
+struct crypto_alg *crypto_alg_lookup(const char *name, u32 type, u32 mask)
 {
 	struct crypto_alg *alg;
 
@@ -176,6 +203,7 @@
 
 	return alg;
 }
+EXPORT_SYMBOL_GPL(crypto_alg_lookup);
 
 struct crypto_alg *crypto_larval_lookup(const char *name, u32 type, u32 mask)
 {
@@ -192,25 +220,40 @@
 	if (alg)
 		return crypto_is_larval(alg) ? crypto_larval_wait(alg) : alg;
 
-	return crypto_larval_alloc(name, type, mask);
+	return crypto_larval_add(name, type, mask);
 }
 EXPORT_SYMBOL_GPL(crypto_larval_lookup);
 
+int crypto_probing_notify(unsigned long val, void *v)
+{
+	int ok;
+
+	ok = blocking_notifier_call_chain(&crypto_chain, val, v);
+	if (ok == NOTIFY_DONE) {
+		request_module("cryptomgr");
+		ok = blocking_notifier_call_chain(&crypto_chain, val, v);
+	}
+
+	return ok;
+}
+EXPORT_SYMBOL_GPL(crypto_probing_notify);
+
 struct crypto_alg *crypto_alg_mod_lookup(const char *name, u32 type, u32 mask)
 {
 	struct crypto_alg *alg;
 	struct crypto_alg *larval;
 	int ok;
 
+	if (!(mask & CRYPTO_ALG_TESTED)) {
+		type |= CRYPTO_ALG_TESTED;
+		mask |= CRYPTO_ALG_TESTED;
+	}
+
 	larval = crypto_larval_lookup(name, type, mask);
 	if (IS_ERR(larval) || !crypto_is_larval(larval))
 		return larval;
 
-	ok = crypto_notify(CRYPTO_MSG_ALG_REQUEST, larval);
-	if (ok == NOTIFY_DONE) {
-		request_module("cryptomgr");
-		ok = crypto_notify(CRYPTO_MSG_ALG_REQUEST, larval);
-	}
+	ok = crypto_probing_notify(CRYPTO_MSG_ALG_REQUEST, larval);
 
 	if (ok == NOTIFY_STOP)
 		alg = crypto_larval_wait(larval);
diff --git a/crypto/blkcipher.c b/crypto/blkcipher.c
index 185f955..4a7e65c 100644
--- a/crypto/blkcipher.c
+++ b/crypto/blkcipher.c
@@ -696,34 +696,5 @@
 }
 EXPORT_SYMBOL_GPL(skcipher_geniv_exit);
 
-static int __init blkcipher_module_init(void)
-{
-	int err;
-
-	err = chainiv_module_init();
-	if (err)
-		goto out;
-
-	err = eseqiv_module_init();
-	if (err)
-		goto eseqiv_err;
-
-out:
-	return err;
-
-eseqiv_err:
-	chainiv_module_exit();
-	goto out;
-}
-
-static void __exit blkcipher_module_exit(void)
-{
-	eseqiv_module_exit();
-	chainiv_module_exit();
-}
-
-module_init(blkcipher_module_init);
-module_exit(blkcipher_module_exit);
-
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("Generic block chaining cipher type");
diff --git a/crypto/chainiv.c b/crypto/chainiv.c
index 9affade..7c37a49 100644
--- a/crypto/chainiv.c
+++ b/crypto/chainiv.c
@@ -14,11 +14,11 @@
  */
 
 #include <crypto/internal/skcipher.h>
+#include <crypto/rng.h>
 #include <linux/err.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/random.h>
 #include <linux/spinlock.h>
 #include <linux/string.h>
 #include <linux/workqueue.h>
@@ -83,6 +83,7 @@
 {
 	struct crypto_ablkcipher *geniv = skcipher_givcrypt_reqtfm(req);
 	struct chainiv_ctx *ctx = crypto_ablkcipher_ctx(geniv);
+	int err = 0;
 
 	spin_lock_bh(&ctx->lock);
 	if (crypto_ablkcipher_crt(geniv)->givencrypt !=
@@ -90,11 +91,15 @@
 		goto unlock;
 
 	crypto_ablkcipher_crt(geniv)->givencrypt = chainiv_givencrypt;
-	get_random_bytes(ctx->iv, crypto_ablkcipher_ivsize(geniv));
+	err = crypto_rng_get_bytes(crypto_default_rng, ctx->iv,
+				   crypto_ablkcipher_ivsize(geniv));
 
 unlock:
 	spin_unlock_bh(&ctx->lock);
 
+	if (err)
+		return err;
+
 	return chainiv_givencrypt(req);
 }
 
@@ -203,6 +208,7 @@
 {
 	struct crypto_ablkcipher *geniv = skcipher_givcrypt_reqtfm(req);
 	struct async_chainiv_ctx *ctx = crypto_ablkcipher_ctx(geniv);
+	int err = 0;
 
 	if (test_and_set_bit(CHAINIV_STATE_INUSE, &ctx->state))
 		goto out;
@@ -212,11 +218,15 @@
 		goto unlock;
 
 	crypto_ablkcipher_crt(geniv)->givencrypt = async_chainiv_givencrypt;
-	get_random_bytes(ctx->iv, crypto_ablkcipher_ivsize(geniv));
+	err = crypto_rng_get_bytes(crypto_default_rng, ctx->iv,
+				   crypto_ablkcipher_ivsize(geniv));
 
 unlock:
 	clear_bit(CHAINIV_STATE_INUSE, &ctx->state);
 
+	if (err)
+		return err;
+
 out:
 	return async_chainiv_givencrypt(req);
 }
@@ -284,9 +294,13 @@
 	if (IS_ERR(algt))
 		return ERR_PTR(err);
 
+	err = crypto_get_default_rng();
+	if (err)
+		return ERR_PTR(err);
+
 	inst = skcipher_geniv_alloc(&chainiv_tmpl, tb, 0, 0);
 	if (IS_ERR(inst))
-		goto out;
+		goto put_rng;
 
 	inst->alg.cra_ablkcipher.givencrypt = chainiv_givencrypt_first;
 
@@ -311,21 +325,37 @@
 
 out:
 	return inst;
+
+put_rng:
+	crypto_put_default_rng();
+	goto out;
+}
+
+static void chainiv_free(struct crypto_instance *inst)
+{
+	skcipher_geniv_free(inst);
+	crypto_put_default_rng();
 }
 
 static struct crypto_template chainiv_tmpl = {
 	.name = "chainiv",
 	.alloc = chainiv_alloc,
-	.free = skcipher_geniv_free,
+	.free = chainiv_free,
 	.module = THIS_MODULE,
 };
 
-int __init chainiv_module_init(void)
+static int __init chainiv_module_init(void)
 {
 	return crypto_register_template(&chainiv_tmpl);
 }
 
-void chainiv_module_exit(void)
+static void chainiv_module_exit(void)
 {
 	crypto_unregister_template(&chainiv_tmpl);
 }
+
+module_init(chainiv_module_init);
+module_exit(chainiv_module_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Chain IV Generator");
diff --git a/crypto/cryptomgr.c b/crypto/cryptomgr.c
deleted file mode 100644
index e5e3cf8..0000000
--- a/crypto/cryptomgr.c
+++ /dev/null
@@ -1,222 +0,0 @@
-/*
- * Create default crypto algorithm instances.
- *
- * Copyright (c) 2006 Herbert Xu <herbert@gondor.apana.org.au>
- *
- * This program is free software; you can redistribute it and/or 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/crypto.h>
-#include <linux/ctype.h>
-#include <linux/err.h>
-#include <linux/init.h>
-#include <linux/kthread.h>
-#include <linux/module.h>
-#include <linux/notifier.h>
-#include <linux/rtnetlink.h>
-#include <linux/sched.h>
-#include <linux/string.h>
-
-#include "internal.h"
-
-struct cryptomgr_param {
-	struct rtattr *tb[CRYPTO_MAX_ATTRS + 2];
-
-	struct {
-		struct rtattr attr;
-		struct crypto_attr_type data;
-	} type;
-
-	union {
-		struct rtattr attr;
-		struct {
-			struct rtattr attr;
-			struct crypto_attr_alg data;
-		} alg;
-		struct {
-			struct rtattr attr;
-			struct crypto_attr_u32 data;
-		} nu32;
-	} attrs[CRYPTO_MAX_ATTRS];
-
-	char larval[CRYPTO_MAX_ALG_NAME];
-	char template[CRYPTO_MAX_ALG_NAME];
-};
-
-static int cryptomgr_probe(void *data)
-{
-	struct cryptomgr_param *param = data;
-	struct crypto_template *tmpl;
-	struct crypto_instance *inst;
-	int err;
-
-	tmpl = crypto_lookup_template(param->template);
-	if (!tmpl)
-		goto err;
-
-	do {
-		inst = tmpl->alloc(param->tb);
-		if (IS_ERR(inst))
-			err = PTR_ERR(inst);
-		else if ((err = crypto_register_instance(tmpl, inst)))
-			tmpl->free(inst);
-	} while (err == -EAGAIN && !signal_pending(current));
-
-	crypto_tmpl_put(tmpl);
-
-	if (err)
-		goto err;
-
-out:
-	kfree(param);
-	module_put_and_exit(0);
-
-err:
-	crypto_larval_error(param->larval, param->type.data.type,
-			    param->type.data.mask);
-	goto out;
-}
-
-static int cryptomgr_schedule_probe(struct crypto_larval *larval)
-{
-	struct task_struct *thread;
-	struct cryptomgr_param *param;
-	const char *name = larval->alg.cra_name;
-	const char *p;
-	unsigned int len;
-	int i;
-
-	if (!try_module_get(THIS_MODULE))
-		goto err;
-
-	param = kzalloc(sizeof(*param), GFP_KERNEL);
-	if (!param)
-		goto err_put_module;
-
-	for (p = name; isalnum(*p) || *p == '-' || *p == '_'; p++)
-		;
-
-	len = p - name;
-	if (!len || *p != '(')
-		goto err_free_param;
-
-	memcpy(param->template, name, len);
-
-	i = 0;
-	for (;;) {
-		int notnum = 0;
-
-		name = ++p;
-		len = 0;
-
-		for (; isalnum(*p) || *p == '-' || *p == '_'; p++)
-			notnum |= !isdigit(*p);
-
-		if (*p == '(') {
-			int recursion = 0;
-
-			for (;;) {
-				if (!*++p)
-					goto err_free_param;
-				if (*p == '(')
-					recursion++;
-				else if (*p == ')' && !recursion--)
-					break;
-			}
-
-			notnum = 1;
-			p++;
-		}
-
-		len = p - name;
-		if (!len)
-			goto err_free_param;
-
-		if (notnum) {
-			param->attrs[i].alg.attr.rta_len =
-				sizeof(param->attrs[i].alg);
-			param->attrs[i].alg.attr.rta_type = CRYPTOA_ALG;
-			memcpy(param->attrs[i].alg.data.name, name, len);
-		} else {
-			param->attrs[i].nu32.attr.rta_len =
-				sizeof(param->attrs[i].nu32);
-			param->attrs[i].nu32.attr.rta_type = CRYPTOA_U32;
-			param->attrs[i].nu32.data.num =
-				simple_strtol(name, NULL, 0);
-		}
-
-		param->tb[i + 1] = &param->attrs[i].attr;
-		i++;
-
-		if (i >= CRYPTO_MAX_ATTRS)
-			goto err_free_param;
-
-		if (*p == ')')
-			break;
-
-		if (*p != ',')
-			goto err_free_param;
-	}
-
-	if (!i)
-		goto err_free_param;
-
-	param->tb[i + 1] = NULL;
-
-	param->type.attr.rta_len = sizeof(param->type);
-	param->type.attr.rta_type = CRYPTOA_TYPE;
-	param->type.data.type = larval->alg.cra_flags;
-	param->type.data.mask = larval->mask;
-	param->tb[0] = &param->type.attr;
-
-	memcpy(param->larval, larval->alg.cra_name, CRYPTO_MAX_ALG_NAME);
-
-	thread = kthread_run(cryptomgr_probe, param, "cryptomgr");
-	if (IS_ERR(thread))
-		goto err_free_param;
-
-	return NOTIFY_STOP;
-
-err_free_param:
-	kfree(param);
-err_put_module:
-	module_put(THIS_MODULE);
-err:
-	return NOTIFY_OK;
-}
-
-static int cryptomgr_notify(struct notifier_block *this, unsigned long msg,
-			    void *data)
-{
-	switch (msg) {
-	case CRYPTO_MSG_ALG_REQUEST:
-		return cryptomgr_schedule_probe(data);
-	}
-
-	return NOTIFY_DONE;
-}
-
-static struct notifier_block cryptomgr_notifier = {
-	.notifier_call = cryptomgr_notify,
-};
-
-static int __init cryptomgr_init(void)
-{
-	return crypto_register_notifier(&cryptomgr_notifier);
-}
-
-static void __exit cryptomgr_exit(void)
-{
-	int err = crypto_unregister_notifier(&cryptomgr_notifier);
-	BUG_ON(err);
-}
-
-module_init(cryptomgr_init);
-module_exit(cryptomgr_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("Crypto Algorithm Manager");
diff --git a/crypto/eseqiv.c b/crypto/eseqiv.c
index 881d309..2a342c8 100644
--- a/crypto/eseqiv.c
+++ b/crypto/eseqiv.c
@@ -16,13 +16,13 @@
  */
 
 #include <crypto/internal/skcipher.h>
+#include <crypto/rng.h>
 #include <crypto/scatterwalk.h>
 #include <linux/err.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/mm.h>
 #include <linux/module.h>
-#include <linux/random.h>
 #include <linux/scatterlist.h>
 #include <linux/spinlock.h>
 #include <linux/string.h>
@@ -163,17 +163,22 @@
 {
 	struct crypto_ablkcipher *geniv = skcipher_givcrypt_reqtfm(req);
 	struct eseqiv_ctx *ctx = crypto_ablkcipher_ctx(geniv);
+	int err = 0;
 
 	spin_lock_bh(&ctx->lock);
 	if (crypto_ablkcipher_crt(geniv)->givencrypt != eseqiv_givencrypt_first)
 		goto unlock;
 
 	crypto_ablkcipher_crt(geniv)->givencrypt = eseqiv_givencrypt;
-	get_random_bytes(ctx->salt, crypto_ablkcipher_ivsize(geniv));
+	err = crypto_rng_get_bytes(crypto_default_rng, ctx->salt,
+				   crypto_ablkcipher_ivsize(geniv));
 
 unlock:
 	spin_unlock_bh(&ctx->lock);
 
+	if (err)
+		return err;
+
 	return eseqiv_givencrypt(req);
 }
 
@@ -216,9 +221,13 @@
 	struct crypto_instance *inst;
 	int err;
 
+	err = crypto_get_default_rng();
+	if (err)
+		return ERR_PTR(err);
+
 	inst = skcipher_geniv_alloc(&eseqiv_tmpl, tb, 0, 0);
 	if (IS_ERR(inst))
-		goto out;
+		goto put_rng;
 
 	err = -EINVAL;
 	if (inst->alg.cra_ablkcipher.ivsize != inst->alg.cra_blocksize)
@@ -238,22 +247,36 @@
 free_inst:
 	skcipher_geniv_free(inst);
 	inst = ERR_PTR(err);
+put_rng:
+	crypto_put_default_rng();
 	goto out;
 }
 
+static void eseqiv_free(struct crypto_instance *inst)
+{
+	skcipher_geniv_free(inst);
+	crypto_put_default_rng();
+}
+
 static struct crypto_template eseqiv_tmpl = {
 	.name = "eseqiv",
 	.alloc = eseqiv_alloc,
-	.free = skcipher_geniv_free,
+	.free = eseqiv_free,
 	.module = THIS_MODULE,
 };
 
-int __init eseqiv_module_init(void)
+static int __init eseqiv_module_init(void)
 {
 	return crypto_register_template(&eseqiv_tmpl);
 }
 
-void __exit eseqiv_module_exit(void)
+static void __exit eseqiv_module_exit(void)
 {
 	crypto_unregister_template(&eseqiv_tmpl);
 }
+
+module_init(eseqiv_module_init);
+module_exit(eseqiv_module_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Encrypted Sequence Number IV Generator");
diff --git a/crypto/fips.c b/crypto/fips.c
new file mode 100644
index 0000000..5539700
--- /dev/null
+++ b/crypto/fips.c
@@ -0,0 +1,27 @@
+/*
+ * FIPS 200 support.
+ *
+ * Copyright (c) 2008 Neil Horman <nhorman@tuxdriver.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 "internal.h"
+
+int fips_enabled;
+EXPORT_SYMBOL_GPL(fips_enabled);
+
+/* Process kernel command-line parameter at boot time. fips=0 or fips=1 */
+static int fips_enable(char *str)
+{
+	fips_enabled = !!simple_strtol(str, NULL, 0);
+	printk(KERN_INFO "fips mode: %s\n",
+		fips_enabled ? "enabled" : "disabled");
+	return 1;
+}
+
+__setup("fips=", fips_enable);
diff --git a/crypto/internal.h b/crypto/internal.h
index 683fcb2..8ef72d7 100644
--- a/crypto/internal.h
+++ b/crypto/internal.h
@@ -26,6 +26,12 @@
 #include <linux/rwsem.h>
 #include <linux/slab.h>
 
+#ifdef CONFIG_CRYPTO_FIPS
+extern int fips_enabled;
+#else
+#define fips_enabled 0
+#endif
+
 /* Crypto notification events. */
 enum {
 	CRYPTO_MSG_ALG_REQUEST,
@@ -82,7 +88,7 @@
 }
 
 struct crypto_alg *crypto_mod_get(struct crypto_alg *alg);
-struct crypto_alg *__crypto_alg_lookup(const char *name, u32 type, u32 mask);
+struct crypto_alg *crypto_alg_lookup(const char *name, u32 type, u32 mask);
 struct crypto_alg *crypto_alg_mod_lookup(const char *name, u32 type, u32 mask);
 
 int crypto_init_digest_ops(struct crypto_tfm *tfm);
@@ -94,9 +100,11 @@
 void crypto_exit_cipher_ops(struct crypto_tfm *tfm);
 void crypto_exit_compress_ops(struct crypto_tfm *tfm);
 
+struct crypto_larval *crypto_larval_alloc(const char *name, u32 type, u32 mask);
 void crypto_larval_kill(struct crypto_alg *alg);
 struct crypto_alg *crypto_larval_lookup(const char *name, u32 type, u32 mask);
 void crypto_larval_error(const char *name, u32 type, u32 mask);
+void crypto_alg_tested(const char *name, int err);
 
 void crypto_shoot_alg(struct crypto_alg *alg);
 struct crypto_tfm *__crypto_alloc_tfm(struct crypto_alg *alg, u32 type,
@@ -107,6 +115,10 @@
 
 int crypto_register_notifier(struct notifier_block *nb);
 int crypto_unregister_notifier(struct notifier_block *nb);
+int crypto_probing_notify(unsigned long val, void *v);
+
+int __init testmgr_init(void);
+void testmgr_exit(void);
 
 static inline void crypto_alg_put(struct crypto_alg *alg)
 {
@@ -139,9 +151,9 @@
 	return alg->cra_flags & (CRYPTO_ALG_DEAD | CRYPTO_ALG_DYING);
 }
 
-static inline int crypto_notify(unsigned long val, void *v)
+static inline void crypto_notify(unsigned long val, void *v)
 {
-	return blocking_notifier_call_chain(&crypto_chain, val, v);
+	blocking_notifier_call_chain(&crypto_chain, val, v);
 }
 
 #endif	/* _CRYPTO_INTERNAL_H */
diff --git a/crypto/krng.c b/crypto/krng.c
new file mode 100644
index 0000000..4328bb3
--- /dev/null
+++ b/crypto/krng.c
@@ -0,0 +1,66 @@
+/*
+ * RNG implementation using standard kernel RNG.
+ *
+ * Copyright (c) 2008 Herbert Xu <herbert@gondor.apana.org.au>
+ *
+ * This program is free software; you can redistribute it and/or 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
+ * any later version.
+ *
+ */
+
+#include <crypto/internal/rng.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/random.h>
+
+static int krng_get_random(struct crypto_rng *tfm, u8 *rdata, unsigned int dlen)
+{
+	get_random_bytes(rdata, dlen);
+	return 0;
+}
+
+static int krng_reset(struct crypto_rng *tfm, u8 *seed, unsigned int slen)
+{
+	return 0;
+}
+
+static struct crypto_alg krng_alg = {
+	.cra_name		= "stdrng",
+	.cra_driver_name	= "krng",
+	.cra_priority		= 200,
+	.cra_flags		= CRYPTO_ALG_TYPE_RNG,
+	.cra_ctxsize		= 0,
+	.cra_type		= &crypto_rng_type,
+	.cra_module		= THIS_MODULE,
+	.cra_list		= LIST_HEAD_INIT(krng_alg.cra_list),
+	.cra_u			= {
+		.rng = {
+			.rng_make_random	= krng_get_random,
+			.rng_reset		= krng_reset,
+			.seedsize		= 0,
+		}
+	}
+};
+
+
+/* Module initalization */
+static int __init krng_mod_init(void)
+{
+	return crypto_register_alg(&krng_alg);
+}
+
+static void __exit krng_mod_fini(void)
+{
+	crypto_unregister_alg(&krng_alg);
+	return;
+}
+
+module_init(krng_mod_init);
+module_exit(krng_mod_fini);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Kernel Random Number Generator");
+MODULE_ALIAS("stdrng");
diff --git a/crypto/proc.c b/crypto/proc.c
index 02ff567..37a13d0 100644
--- a/crypto/proc.c
+++ b/crypto/proc.c
@@ -19,8 +19,53 @@
 #include <linux/rwsem.h>
 #include <linux/proc_fs.h>
 #include <linux/seq_file.h>
+#include <linux/sysctl.h>
 #include "internal.h"
 
+#ifdef CONFIG_CRYPTO_FIPS
+static struct ctl_table crypto_sysctl_table[] = {
+	{
+		.ctl_name       = CTL_UNNUMBERED,
+		.procname       = "fips_enabled",
+		.data           = &fips_enabled,
+		.maxlen         = sizeof(int),
+		.mode           = 0444,
+		.proc_handler   = &proc_dointvec
+	},
+	{
+		.ctl_name = 0,
+	},
+};
+
+static struct ctl_table crypto_dir_table[] = {
+	{
+		.ctl_name       = CTL_UNNUMBERED,
+		.procname       = "crypto",
+		.mode           = 0555,
+		.child          = crypto_sysctl_table
+	},
+	{
+		.ctl_name = 0,
+	},
+};
+
+static struct ctl_table_header *crypto_sysctls;
+
+static void crypto_proc_fips_init(void)
+{
+	crypto_sysctls = register_sysctl_table(crypto_dir_table);
+}
+
+static void crypto_proc_fips_exit(void)
+{
+	if (crypto_sysctls)
+		unregister_sysctl_table(crypto_sysctls);
+}
+#else
+#define crypto_proc_fips_init()
+#define crypto_proc_fips_exit()
+#endif
+
 static void *c_start(struct seq_file *m, loff_t *pos)
 {
 	down_read(&crypto_alg_sem);
@@ -46,8 +91,11 @@
 	seq_printf(m, "module       : %s\n", module_name(alg->cra_module));
 	seq_printf(m, "priority     : %d\n", alg->cra_priority);
 	seq_printf(m, "refcnt       : %d\n", atomic_read(&alg->cra_refcnt));
+	seq_printf(m, "selftest     : %s\n",
+		   (alg->cra_flags & CRYPTO_ALG_TESTED) ?
+		   "passed" : "unknown");
 	
-	switch (alg->cra_flags & CRYPTO_ALG_TYPE_MASK) {
+	switch (alg->cra_flags & (CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_LARVAL)) {
 	case CRYPTO_ALG_TYPE_CIPHER:
 		seq_printf(m, "type         : cipher\n");
 		seq_printf(m, "blocksize    : %u\n", alg->cra_blocksize);
@@ -67,7 +115,10 @@
 		seq_printf(m, "type         : compression\n");
 		break;
 	default:
-		if (alg->cra_type && alg->cra_type->show)
+		if (alg->cra_flags & CRYPTO_ALG_LARVAL) {
+			seq_printf(m, "type         : larval\n");
+			seq_printf(m, "flags        : 0x%x\n", alg->cra_flags);
+		} else if (alg->cra_type && alg->cra_type->show)
 			alg->cra_type->show(m, alg);
 		else
 			seq_printf(m, "type         : unknown\n");
@@ -100,9 +151,11 @@
 void __init crypto_init_proc(void)
 {
 	proc_create("crypto", 0, NULL, &proc_crypto_ops);
+	crypto_proc_fips_init();
 }
 
 void __exit crypto_exit_proc(void)
 {
+	crypto_proc_fips_exit();
 	remove_proc_entry("crypto", NULL);
 }
diff --git a/crypto/rng.c b/crypto/rng.c
new file mode 100644
index 0000000..6e94bc7
--- /dev/null
+++ b/crypto/rng.c
@@ -0,0 +1,126 @@
+/*
+ * Cryptographic API.
+ *
+ * RNG operations.
+ *
+ * Copyright (c) 2008 Neil Horman <nhorman@tuxdriver.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 <asm/atomic.h>
+#include <crypto/internal/rng.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/random.h>
+#include <linux/seq_file.h>
+#include <linux/string.h>
+
+static DEFINE_MUTEX(crypto_default_rng_lock);
+struct crypto_rng *crypto_default_rng;
+EXPORT_SYMBOL_GPL(crypto_default_rng);
+static int crypto_default_rng_refcnt;
+
+static int rngapi_reset(struct crypto_rng *tfm, u8 *seed, unsigned int slen)
+{
+	u8 *buf = NULL;
+	int err;
+
+	if (!seed && slen) {
+		buf = kmalloc(slen, GFP_KERNEL);
+		if (!buf)
+			return -ENOMEM;
+
+		get_random_bytes(buf, slen);
+		seed = buf;
+	}
+
+	err = crypto_rng_alg(tfm)->rng_reset(tfm, seed, slen);
+
+	kfree(buf);
+	return err;
+}
+
+static int crypto_init_rng_ops(struct crypto_tfm *tfm, u32 type, u32 mask)
+{
+	struct rng_alg *alg = &tfm->__crt_alg->cra_rng;
+	struct rng_tfm *ops = &tfm->crt_rng;
+
+	ops->rng_gen_random = alg->rng_make_random;
+	ops->rng_reset = rngapi_reset;
+
+	return 0;
+}
+
+static void crypto_rng_show(struct seq_file *m, struct crypto_alg *alg)
+	__attribute__ ((unused));
+static void crypto_rng_show(struct seq_file *m, struct crypto_alg *alg)
+{
+	seq_printf(m, "type         : rng\n");
+	seq_printf(m, "seedsize     : %u\n", alg->cra_rng.seedsize);
+}
+
+static unsigned int crypto_rng_ctxsize(struct crypto_alg *alg, u32 type,
+				       u32 mask)
+{
+	return alg->cra_ctxsize;
+}
+
+const struct crypto_type crypto_rng_type = {
+	.ctxsize = crypto_rng_ctxsize,
+	.init = crypto_init_rng_ops,
+#ifdef CONFIG_PROC_FS
+	.show = crypto_rng_show,
+#endif
+};
+EXPORT_SYMBOL_GPL(crypto_rng_type);
+
+int crypto_get_default_rng(void)
+{
+	struct crypto_rng *rng;
+	int err;
+
+	mutex_lock(&crypto_default_rng_lock);
+	if (!crypto_default_rng) {
+		rng = crypto_alloc_rng("stdrng", 0, 0);
+		err = PTR_ERR(rng);
+		if (IS_ERR(rng))
+			goto unlock;
+
+		err = crypto_rng_reset(rng, NULL, crypto_rng_seedsize(rng));
+		if (err) {
+			crypto_free_rng(rng);
+			goto unlock;
+		}
+
+		crypto_default_rng = rng;
+	}
+
+	crypto_default_rng_refcnt++;
+	err = 0;
+
+unlock:
+	mutex_unlock(&crypto_default_rng_lock);
+
+	return err;
+}
+EXPORT_SYMBOL_GPL(crypto_get_default_rng);
+
+void crypto_put_default_rng(void)
+{
+	mutex_lock(&crypto_default_rng_lock);
+	if (!--crypto_default_rng_refcnt) {
+		crypto_free_rng(crypto_default_rng);
+		crypto_default_rng = NULL;
+	}
+	mutex_unlock(&crypto_default_rng_lock);
+}
+EXPORT_SYMBOL_GPL(crypto_put_default_rng);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Random Number Genertor");
diff --git a/crypto/seqiv.c b/crypto/seqiv.c
index b903aab..5a013a8 100644
--- a/crypto/seqiv.c
+++ b/crypto/seqiv.c
@@ -15,11 +15,11 @@
 
 #include <crypto/internal/aead.h>
 #include <crypto/internal/skcipher.h>
+#include <crypto/rng.h>
 #include <linux/err.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/random.h>
 #include <linux/spinlock.h>
 #include <linux/string.h>
 
@@ -189,17 +189,22 @@
 {
 	struct crypto_ablkcipher *geniv = skcipher_givcrypt_reqtfm(req);
 	struct seqiv_ctx *ctx = crypto_ablkcipher_ctx(geniv);
+	int err = 0;
 
 	spin_lock_bh(&ctx->lock);
 	if (crypto_ablkcipher_crt(geniv)->givencrypt != seqiv_givencrypt_first)
 		goto unlock;
 
 	crypto_ablkcipher_crt(geniv)->givencrypt = seqiv_givencrypt;
-	get_random_bytes(ctx->salt, crypto_ablkcipher_ivsize(geniv));
+	err = crypto_rng_get_bytes(crypto_default_rng, ctx->salt,
+				   crypto_ablkcipher_ivsize(geniv));
 
 unlock:
 	spin_unlock_bh(&ctx->lock);
 
+	if (err)
+		return err;
+
 	return seqiv_givencrypt(req);
 }
 
@@ -207,17 +212,22 @@
 {
 	struct crypto_aead *geniv = aead_givcrypt_reqtfm(req);
 	struct seqiv_ctx *ctx = crypto_aead_ctx(geniv);
+	int err = 0;
 
 	spin_lock_bh(&ctx->lock);
 	if (crypto_aead_crt(geniv)->givencrypt != seqiv_aead_givencrypt_first)
 		goto unlock;
 
 	crypto_aead_crt(geniv)->givencrypt = seqiv_aead_givencrypt;
-	get_random_bytes(ctx->salt, crypto_aead_ivsize(geniv));
+	err = crypto_rng_get_bytes(crypto_default_rng, ctx->salt,
+				   crypto_aead_ivsize(geniv));
 
 unlock:
 	spin_unlock_bh(&ctx->lock);
 
+	if (err)
+		return err;
+
 	return seqiv_aead_givencrypt(req);
 }
 
@@ -298,19 +308,27 @@
 	if (IS_ERR(algt))
 		return ERR_PTR(err);
 
+	err = crypto_get_default_rng();
+	if (err)
+		return ERR_PTR(err);
+
 	if ((algt->type ^ CRYPTO_ALG_TYPE_AEAD) & CRYPTO_ALG_TYPE_MASK)
 		inst = seqiv_ablkcipher_alloc(tb);
 	else
 		inst = seqiv_aead_alloc(tb);
 
 	if (IS_ERR(inst))
-		goto out;
+		goto put_rng;
 
 	inst->alg.cra_alignmask |= __alignof__(u32) - 1;
 	inst->alg.cra_ctxsize += sizeof(struct seqiv_ctx);
 
 out:
 	return inst;
+
+put_rng:
+	crypto_put_default_rng();
+	goto out;
 }
 
 static void seqiv_free(struct crypto_instance *inst)
@@ -319,6 +337,7 @@
 		skcipher_geniv_free(inst);
 	else
 		aead_geniv_free(inst);
+	crypto_put_default_rng();
 }
 
 static struct crypto_template seqiv_tmpl = {
diff --git a/crypto/tcrypt.c b/crypto/tcrypt.c
index 6636802..28a45a1 100644
--- a/crypto/tcrypt.c
+++ b/crypto/tcrypt.c
@@ -19,11 +19,9 @@
 #include <linux/err.h>
 #include <linux/init.h>
 #include <linux/module.h>
-#include <linux/mm.h>
 #include <linux/slab.h>
 #include <linux/scatterlist.h>
 #include <linux/string.h>
-#include <linux/crypto.h>
 #include <linux/moduleparam.h>
 #include <linux/jiffies.h>
 #include <linux/timex.h>
@@ -31,45 +29,23 @@
 #include "tcrypt.h"
 
 /*
- * Need to kmalloc() memory for testing.
+ * Need slab memory for testing (size in number of pages).
  */
-#define TVMEMSIZE	16384
-#define XBUFSIZE	32768
+#define TVMEMSIZE	4
 
 /*
- * Indexes into the xbuf to simulate cross-page access.
- */
-#define IDX1		32
-#define IDX2		32400
-#define IDX3		1
-#define IDX4		8193
-#define IDX5		22222
-#define IDX6		17101
-#define IDX7		27333
-#define IDX8		3000
-
-/*
-* Used by test_cipher()
+* Used by test_cipher_speed()
 */
 #define ENCRYPT 1
 #define DECRYPT 0
 
-struct tcrypt_result {
-	struct completion completion;
-	int err;
-};
-
-static unsigned int IDX[8] = { IDX1, IDX2, IDX3, IDX4, IDX5, IDX6, IDX7, IDX8 };
-
 /*
  * Used by test_cipher_speed()
  */
 static unsigned int sec;
 
 static int mode;
-static char *xbuf;
-static char *axbuf;
-static char *tvmem;
+static char *tvmem[TVMEMSIZE];
 
 static char *check[] = {
 	"des", "md5", "des3_ede", "rot13", "sha1", "sha224", "sha256",
@@ -80,655 +56,13 @@
 	"lzo", "cts", NULL
 };
 
-static void hexdump(unsigned char *buf, unsigned int len)
+static int test_cipher_jiffies(struct blkcipher_desc *desc, int enc,
+			       struct scatterlist *sg, int blen, int sec)
 {
-	print_hex_dump(KERN_CONT, "", DUMP_PREFIX_OFFSET,
-			16, 1,
-			buf, len, false);
-}
-
-static void tcrypt_complete(struct crypto_async_request *req, int err)
-{
-	struct tcrypt_result *res = req->data;
-
-	if (err == -EINPROGRESS)
-		return;
-
-	res->err = err;
-	complete(&res->completion);
-}
-
-static void test_hash(char *algo, struct hash_testvec *template,
-		      unsigned int tcount)
-{
-	unsigned int i, j, k, temp;
-	struct scatterlist sg[8];
-	char result[64];
-	struct crypto_ahash *tfm;
-	struct ahash_request *req;
-	struct tcrypt_result tresult;
-	int ret;
-	void *hash_buff;
-
-	printk("\ntesting %s\n", algo);
-
-	init_completion(&tresult.completion);
-
-	tfm = crypto_alloc_ahash(algo, 0, 0);
-	if (IS_ERR(tfm)) {
-		printk("failed to load transform for %s: %ld\n", algo,
-		       PTR_ERR(tfm));
-		return;
-	}
-
-	req = ahash_request_alloc(tfm, GFP_KERNEL);
-	if (!req) {
-		printk(KERN_ERR "failed to allocate request for %s\n", algo);
-		goto out_noreq;
-	}
-	ahash_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
-				   tcrypt_complete, &tresult);
-
-	for (i = 0; i < tcount; i++) {
-		printk("test %u:\n", i + 1);
-		memset(result, 0, 64);
-
-		hash_buff = kzalloc(template[i].psize, GFP_KERNEL);
-		if (!hash_buff)
-			continue;
-
-		memcpy(hash_buff, template[i].plaintext, template[i].psize);
-		sg_init_one(&sg[0], hash_buff, template[i].psize);
-
-		if (template[i].ksize) {
-			crypto_ahash_clear_flags(tfm, ~0);
-			ret = crypto_ahash_setkey(tfm, template[i].key,
-						  template[i].ksize);
-			if (ret) {
-				printk("setkey() failed ret=%d\n", ret);
-				kfree(hash_buff);
-				goto out;
-			}
-		}
-
-		ahash_request_set_crypt(req, sg, result, template[i].psize);
-		ret = crypto_ahash_digest(req);
-		switch (ret) {
-		case 0:
-			break;
-		case -EINPROGRESS:
-		case -EBUSY:
-			ret = wait_for_completion_interruptible(
-				&tresult.completion);
-			if (!ret && !(ret = tresult.err)) {
-				INIT_COMPLETION(tresult.completion);
-				break;
-			}
-			/* fall through */
-		default:
-			printk("digest () failed ret=%d\n", ret);
-			kfree(hash_buff);
-			goto out;
-		}
-
-		hexdump(result, crypto_ahash_digestsize(tfm));
-		printk("%s\n",
-		       memcmp(result, template[i].digest,
-			      crypto_ahash_digestsize(tfm)) ?
-		       "fail" : "pass");
-		kfree(hash_buff);
-	}
-
-	printk("testing %s across pages\n", algo);
-
-	/* setup the dummy buffer first */
-	memset(xbuf, 0, XBUFSIZE);
-
-	j = 0;
-	for (i = 0; i < tcount; i++) {
-		if (template[i].np) {
-			j++;
-			printk("test %u:\n", j);
-			memset(result, 0, 64);
-
-			temp = 0;
-			sg_init_table(sg, template[i].np);
-			for (k = 0; k < template[i].np; k++) {
-				memcpy(&xbuf[IDX[k]],
-				       template[i].plaintext + temp,
-				       template[i].tap[k]);
-				temp += template[i].tap[k];
-				sg_set_buf(&sg[k], &xbuf[IDX[k]],
-					    template[i].tap[k]);
-			}
-
-			if (template[i].ksize) {
-				crypto_ahash_clear_flags(tfm, ~0);
-				ret = crypto_ahash_setkey(tfm, template[i].key,
-							  template[i].ksize);
-
-				if (ret) {
-					printk("setkey() failed ret=%d\n", ret);
-					goto out;
-				}
-			}
-
-			ahash_request_set_crypt(req, sg, result,
-						template[i].psize);
-			ret = crypto_ahash_digest(req);
-			switch (ret) {
-			case 0:
-				break;
-			case -EINPROGRESS:
-			case -EBUSY:
-				ret = wait_for_completion_interruptible(
-					&tresult.completion);
-				if (!ret && !(ret = tresult.err)) {
-					INIT_COMPLETION(tresult.completion);
-					break;
-				}
-				/* fall through */
-			default:
-				printk("digest () failed ret=%d\n", ret);
-				goto out;
-			}
-
-			hexdump(result, crypto_ahash_digestsize(tfm));
-			printk("%s\n",
-			       memcmp(result, template[i].digest,
-				      crypto_ahash_digestsize(tfm)) ?
-			       "fail" : "pass");
-		}
-	}
-
-out:
-	ahash_request_free(req);
-out_noreq:
-	crypto_free_ahash(tfm);
-}
-
-static void test_aead(char *algo, int enc, struct aead_testvec *template,
-		      unsigned int tcount)
-{
-	unsigned int ret, i, j, k, n, temp;
-	char *q;
-	struct crypto_aead *tfm;
-	char *key;
-	struct aead_request *req;
-	struct scatterlist sg[8];
-	struct scatterlist asg[8];
-	const char *e;
-	struct tcrypt_result result;
-	unsigned int authsize;
-	void *input;
-	void *assoc;
-	char iv[MAX_IVLEN];
-
-	if (enc == ENCRYPT)
-		e = "encryption";
-	else
-		e = "decryption";
-
-	printk(KERN_INFO "\ntesting %s %s\n", algo, e);
-
-	init_completion(&result.completion);
-
-	tfm = crypto_alloc_aead(algo, 0, 0);
-
-	if (IS_ERR(tfm)) {
-		printk(KERN_INFO "failed to load transform for %s: %ld\n",
-		       algo, PTR_ERR(tfm));
-		return;
-	}
-
-	req = aead_request_alloc(tfm, GFP_KERNEL);
-	if (!req) {
-		printk(KERN_INFO "failed to allocate request for %s\n", algo);
-		goto out;
-	}
-
-	aead_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
-				  tcrypt_complete, &result);
-
-	for (i = 0, j = 0; i < tcount; i++) {
-		if (!template[i].np) {
-			printk(KERN_INFO "test %u (%d bit key):\n",
-			       ++j, template[i].klen * 8);
-
-			/* some tepmplates have no input data but they will
-			 * touch input
-			 */
-			input = kzalloc(template[i].ilen + template[i].rlen, GFP_KERNEL);
-			if (!input)
-				continue;
-
-			assoc = kzalloc(template[i].alen, GFP_KERNEL);
-			if (!assoc) {
-				kfree(input);
-				continue;
-			}
-
-			memcpy(input, template[i].input, template[i].ilen);
-			memcpy(assoc, template[i].assoc, template[i].alen);
-			if (template[i].iv)
-				memcpy(iv, template[i].iv, MAX_IVLEN);
-			else
-				memset(iv, 0, MAX_IVLEN);
-
-			crypto_aead_clear_flags(tfm, ~0);
-			if (template[i].wk)
-				crypto_aead_set_flags(
-					tfm, CRYPTO_TFM_REQ_WEAK_KEY);
-
-			if (template[i].key)
-				key = template[i].key;
-			else
-				key = kzalloc(template[i].klen, GFP_KERNEL);
-
-			ret = crypto_aead_setkey(tfm, key,
-						 template[i].klen);
-			if (ret) {
-				printk(KERN_INFO "setkey() failed flags=%x\n",
-				       crypto_aead_get_flags(tfm));
-
-				if (!template[i].fail)
-					goto next_one;
-			}
-
-			authsize = abs(template[i].rlen - template[i].ilen);
-			ret = crypto_aead_setauthsize(tfm, authsize);
-			if (ret) {
-				printk(KERN_INFO
-				       "failed to set authsize = %u\n",
-				       authsize);
-				goto next_one;
-			}
-
-			sg_init_one(&sg[0], input,
-				    template[i].ilen + (enc ? authsize : 0));
-
-			sg_init_one(&asg[0], assoc, template[i].alen);
-
-			aead_request_set_crypt(req, sg, sg,
-					       template[i].ilen, iv);
-
-			aead_request_set_assoc(req, asg, template[i].alen);
-
-			ret = enc ?
-				crypto_aead_encrypt(req) :
-				crypto_aead_decrypt(req);
-
-			switch (ret) {
-			case 0:
-				break;
-			case -EINPROGRESS:
-			case -EBUSY:
-				ret = wait_for_completion_interruptible(
-					&result.completion);
-				if (!ret && !(ret = result.err)) {
-					INIT_COMPLETION(result.completion);
-					break;
-				}
-				/* fall through */
-			default:
-				printk(KERN_INFO "%s () failed err=%d\n",
-				       e, -ret);
-				goto next_one;
-			}
-
-			q = input;
-			hexdump(q, template[i].rlen);
-
-			printk(KERN_INFO "enc/dec: %s\n",
-			       memcmp(q, template[i].result,
-				      template[i].rlen) ? "fail" : "pass");
-next_one:
-			if (!template[i].key)
-				kfree(key);
-			kfree(assoc);
-			kfree(input);
-		}
-	}
-
-	printk(KERN_INFO "\ntesting %s %s across pages (chunking)\n", algo, e);
-	memset(axbuf, 0, XBUFSIZE);
-
-	for (i = 0, j = 0; i < tcount; i++) {
-		if (template[i].np) {
-			printk(KERN_INFO "test %u (%d bit key):\n",
-			       ++j, template[i].klen * 8);
-
-			if (template[i].iv)
-				memcpy(iv, template[i].iv, MAX_IVLEN);
-			else
-				memset(iv, 0, MAX_IVLEN);
-
-			crypto_aead_clear_flags(tfm, ~0);
-			if (template[i].wk)
-				crypto_aead_set_flags(
-					tfm, CRYPTO_TFM_REQ_WEAK_KEY);
-			key = template[i].key;
-
-			ret = crypto_aead_setkey(tfm, key, template[i].klen);
-			if (ret) {
-				printk(KERN_INFO "setkey() failed flags=%x\n",
-				       crypto_aead_get_flags(tfm));
-
-				if (!template[i].fail)
-					goto out;
-			}
-
-			memset(xbuf, 0, XBUFSIZE);
-			sg_init_table(sg, template[i].np);
-			for (k = 0, temp = 0; k < template[i].np; k++) {
-				memcpy(&xbuf[IDX[k]],
-				       template[i].input + temp,
-				       template[i].tap[k]);
-				temp += template[i].tap[k];
-				sg_set_buf(&sg[k], &xbuf[IDX[k]],
-					   template[i].tap[k]);
-			}
-
-			authsize = abs(template[i].rlen - template[i].ilen);
-			ret = crypto_aead_setauthsize(tfm, authsize);
-			if (ret) {
-				printk(KERN_INFO
-				       "failed to set authsize = %u\n",
-				       authsize);
-				goto out;
-			}
-
-			if (enc)
-				sg[k - 1].length += authsize;
-
-			sg_init_table(asg, template[i].anp);
-			for (k = 0, temp = 0; k < template[i].anp; k++) {
-				memcpy(&axbuf[IDX[k]],
-				       template[i].assoc + temp,
-				       template[i].atap[k]);
-				temp += template[i].atap[k];
-				sg_set_buf(&asg[k], &axbuf[IDX[k]],
-					   template[i].atap[k]);
-			}
-
-			aead_request_set_crypt(req, sg, sg,
-					       template[i].ilen,
-					       iv);
-
-			aead_request_set_assoc(req, asg, template[i].alen);
-
-			ret = enc ?
-				crypto_aead_encrypt(req) :
-				crypto_aead_decrypt(req);
-
-			switch (ret) {
-			case 0:
-				break;
-			case -EINPROGRESS:
-			case -EBUSY:
-				ret = wait_for_completion_interruptible(
-					&result.completion);
-				if (!ret && !(ret = result.err)) {
-					INIT_COMPLETION(result.completion);
-					break;
-				}
-				/* fall through */
-			default:
-				printk(KERN_INFO "%s () failed err=%d\n",
-				       e, -ret);
-				goto out;
-			}
-
-			for (k = 0, temp = 0; k < template[i].np; k++) {
-				printk(KERN_INFO "page %u\n", k);
-				q = &xbuf[IDX[k]];
-
-				n = template[i].tap[k];
-				if (k == template[i].np - 1)
-					n += enc ? authsize : -authsize;
-				hexdump(q, n);
-				printk(KERN_INFO "%s\n",
-				       memcmp(q, template[i].result + temp, n) ?
-				       "fail" : "pass");
-
-				q += n;
-				if (k == template[i].np - 1 && !enc) {
-					if (memcmp(q, template[i].input +
-						      temp + n, authsize))
-						n = authsize;
-					else
-						n = 0;
-				} else {
-					for (n = 0; q[n]; n++)
-						;
-				}
-				if (n) {
-					printk("Result buffer corruption %u "
-					       "bytes:\n", n);
-					hexdump(q, n);
-				}
-
-				temp += template[i].tap[k];
-			}
-		}
-	}
-
-out:
-	crypto_free_aead(tfm);
-	aead_request_free(req);
-}
-
-static void test_cipher(char *algo, int enc,
-			struct cipher_testvec *template, unsigned int tcount)
-{
-	unsigned int ret, i, j, k, n, temp;
-	char *q;
-	struct crypto_ablkcipher *tfm;
-	struct ablkcipher_request *req;
-	struct scatterlist sg[8];
-	const char *e;
-	struct tcrypt_result result;
-	void *data;
-	char iv[MAX_IVLEN];
-
-	if (enc == ENCRYPT)
-	        e = "encryption";
-	else
-		e = "decryption";
-
-	printk("\ntesting %s %s\n", algo, e);
-
-	init_completion(&result.completion);
-	tfm = crypto_alloc_ablkcipher(algo, 0, 0);
-
-	if (IS_ERR(tfm)) {
-		printk("failed to load transform for %s: %ld\n", algo,
-		       PTR_ERR(tfm));
-		return;
-	}
-
-	req = ablkcipher_request_alloc(tfm, GFP_KERNEL);
-	if (!req) {
-		printk("failed to allocate request for %s\n", algo);
-		goto out;
-	}
-
-	ablkcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
-					tcrypt_complete, &result);
-
-	j = 0;
-	for (i = 0; i < tcount; i++) {
-
-		data = kzalloc(template[i].ilen, GFP_KERNEL);
-		if (!data)
-			continue;
-
-		memcpy(data, template[i].input, template[i].ilen);
-		if (template[i].iv)
-			memcpy(iv, template[i].iv, MAX_IVLEN);
-		else
-			memset(iv, 0, MAX_IVLEN);
-
-		if (!(template[i].np)) {
-			j++;
-			printk("test %u (%d bit key):\n",
-			j, template[i].klen * 8);
-
-			crypto_ablkcipher_clear_flags(tfm, ~0);
-			if (template[i].wk)
-				crypto_ablkcipher_set_flags(
-					tfm, CRYPTO_TFM_REQ_WEAK_KEY);
-
-			ret = crypto_ablkcipher_setkey(tfm, template[i].key,
-						       template[i].klen);
-			if (ret) {
-				printk("setkey() failed flags=%x\n",
-				       crypto_ablkcipher_get_flags(tfm));
-
-				if (!template[i].fail) {
-					kfree(data);
-					goto out;
-				}
-			}
-
-			sg_init_one(&sg[0], data, template[i].ilen);
-
-			ablkcipher_request_set_crypt(req, sg, sg,
-						     template[i].ilen, iv);
-			ret = enc ?
-				crypto_ablkcipher_encrypt(req) :
-				crypto_ablkcipher_decrypt(req);
-
-			switch (ret) {
-			case 0:
-				break;
-			case -EINPROGRESS:
-			case -EBUSY:
-				ret = wait_for_completion_interruptible(
-					&result.completion);
-				if (!ret && !((ret = result.err))) {
-					INIT_COMPLETION(result.completion);
-					break;
-				}
-				/* fall through */
-			default:
-				printk("%s () failed err=%d\n", e, -ret);
-				kfree(data);
-				goto out;
-			}
-
-			q = data;
-			hexdump(q, template[i].rlen);
-
-			printk("%s\n",
-			       memcmp(q, template[i].result,
-				      template[i].rlen) ? "fail" : "pass");
-		}
-		kfree(data);
-	}
-
-	printk("\ntesting %s %s across pages (chunking)\n", algo, e);
-
-	j = 0;
-	for (i = 0; i < tcount; i++) {
-
-		if (template[i].iv)
-			memcpy(iv, template[i].iv, MAX_IVLEN);
-		else
-			memset(iv, 0, MAX_IVLEN);
-
-		if (template[i].np) {
-			j++;
-			printk("test %u (%d bit key):\n",
-			j, template[i].klen * 8);
-
-			memset(xbuf, 0, XBUFSIZE);
-			crypto_ablkcipher_clear_flags(tfm, ~0);
-			if (template[i].wk)
-				crypto_ablkcipher_set_flags(
-					tfm, CRYPTO_TFM_REQ_WEAK_KEY);
-
-			ret = crypto_ablkcipher_setkey(tfm, template[i].key,
-						       template[i].klen);
-			if (ret) {
-				printk("setkey() failed flags=%x\n",
-						crypto_ablkcipher_get_flags(tfm));
-
-				if (!template[i].fail)
-					goto out;
-			}
-
-			temp = 0;
-			sg_init_table(sg, template[i].np);
-			for (k = 0; k < template[i].np; k++) {
-				memcpy(&xbuf[IDX[k]],
-						template[i].input + temp,
-						template[i].tap[k]);
-				temp += template[i].tap[k];
-				sg_set_buf(&sg[k], &xbuf[IDX[k]],
-						template[i].tap[k]);
-			}
-
-			ablkcipher_request_set_crypt(req, sg, sg,
-					template[i].ilen, iv);
-
-			ret = enc ?
-				crypto_ablkcipher_encrypt(req) :
-				crypto_ablkcipher_decrypt(req);
-
-			switch (ret) {
-			case 0:
-				break;
-			case -EINPROGRESS:
-			case -EBUSY:
-				ret = wait_for_completion_interruptible(
-					&result.completion);
-				if (!ret && !((ret = result.err))) {
-					INIT_COMPLETION(result.completion);
-					break;
-				}
-				/* fall through */
-			default:
-				printk("%s () failed err=%d\n", e, -ret);
-				goto out;
-			}
-
-			temp = 0;
-			for (k = 0; k < template[i].np; k++) {
-				printk("page %u\n", k);
-				q = &xbuf[IDX[k]];
-				hexdump(q, template[i].tap[k]);
-				printk("%s\n",
-					memcmp(q, template[i].result + temp,
-						template[i].tap[k]) ? "fail" :
-					"pass");
-
-				for (n = 0; q[template[i].tap[k] + n]; n++)
-					;
-				if (n) {
-					printk("Result buffer corruption %u "
-					       "bytes:\n", n);
-					hexdump(&q[template[i].tap[k]], n);
-				}
-				temp += template[i].tap[k];
-			}
-		}
-	}
-out:
-	crypto_free_ablkcipher(tfm);
-	ablkcipher_request_free(req);
-}
-
-static int test_cipher_jiffies(struct blkcipher_desc *desc, int enc, char *p,
-			       int blen, int sec)
-{
-	struct scatterlist sg[1];
 	unsigned long start, end;
 	int bcount;
 	int ret;
 
-	sg_init_one(sg, p, blen);
-
 	for (start = jiffies, end = start + sec * HZ, bcount = 0;
 	     time_before(jiffies, end); bcount++) {
 		if (enc)
@@ -745,16 +79,13 @@
 	return 0;
 }
 
-static int test_cipher_cycles(struct blkcipher_desc *desc, int enc, char *p,
-			      int blen)
+static int test_cipher_cycles(struct blkcipher_desc *desc, int enc,
+			      struct scatterlist *sg, int blen)
 {
-	struct scatterlist sg[1];
 	unsigned long cycles = 0;
 	int ret = 0;
 	int i;
 
-	sg_init_one(sg, p, blen);
-
 	local_bh_disable();
 	local_irq_disable();
 
@@ -799,12 +130,12 @@
 
 static u32 block_sizes[] = { 16, 64, 256, 1024, 8192, 0 };
 
-static void test_cipher_speed(char *algo, int enc, unsigned int sec,
-			      struct cipher_testvec *template,
+static void test_cipher_speed(const char *algo, int enc, unsigned int sec,
+			      struct cipher_speed_template *template,
 			      unsigned int tcount, u8 *keysize)
 {
 	unsigned int ret, i, j, iv_len;
-	unsigned char *key, *p, iv[128];
+	const char *key, iv[128];
 	struct crypto_blkcipher *tfm;
 	struct blkcipher_desc desc;
 	const char *e;
@@ -832,27 +163,28 @@
 
 		b_size = block_sizes;
 		do {
+			struct scatterlist sg[TVMEMSIZE];
 
-			if ((*keysize + *b_size) > TVMEMSIZE) {
-				printk("template (%u) too big for tvmem (%u)\n",
-						*keysize + *b_size, TVMEMSIZE);
+			if ((*keysize + *b_size) > TVMEMSIZE * PAGE_SIZE) {
+				printk("template (%u) too big for "
+				       "tvmem (%lu)\n", *keysize + *b_size,
+				       TVMEMSIZE * PAGE_SIZE);
 				goto out;
 			}
 
 			printk("test %u (%d bit key, %d byte blocks): ", i,
 					*keysize * 8, *b_size);
 
-			memset(tvmem, 0xff, *keysize + *b_size);
+			memset(tvmem[0], 0xff, PAGE_SIZE);
 
 			/* set key, plain text and IV */
-			key = (unsigned char *)tvmem;
+			key = tvmem[0];
 			for (j = 0; j < tcount; j++) {
 				if (template[j].klen == *keysize) {
 					key = template[j].key;
 					break;
 				}
 			}
-			p = (unsigned char *)tvmem + *keysize;
 
 			ret = crypto_blkcipher_setkey(tfm, key, *keysize);
 			if (ret) {
@@ -861,6 +193,14 @@
 				goto out;
 			}
 
+			sg_init_table(sg, TVMEMSIZE);
+			sg_set_buf(sg, tvmem[0] + *keysize,
+				   PAGE_SIZE - *keysize);
+			for (j = 1; j < TVMEMSIZE; j++) {
+				sg_set_buf(sg + j, tvmem[j], PAGE_SIZE);
+				memset (tvmem[j], 0xff, PAGE_SIZE);
+			}
+
 			iv_len = crypto_blkcipher_ivsize(tfm);
 			if (iv_len) {
 				memset(&iv, 0xff, iv_len);
@@ -868,9 +208,11 @@
 			}
 
 			if (sec)
-				ret = test_cipher_jiffies(&desc, enc, p, *b_size, sec);
+				ret = test_cipher_jiffies(&desc, enc, sg,
+							  *b_size, sec);
 			else
-				ret = test_cipher_cycles(&desc, enc, p, *b_size);
+				ret = test_cipher_cycles(&desc, enc, sg,
+							 *b_size);
 
 			if (ret) {
 				printk("%s() failed flags=%x\n", e, desc.flags);
@@ -886,19 +228,16 @@
 	crypto_free_blkcipher(tfm);
 }
 
-static int test_hash_jiffies_digest(struct hash_desc *desc, char *p, int blen,
+static int test_hash_jiffies_digest(struct hash_desc *desc,
+				    struct scatterlist *sg, int blen,
 				    char *out, int sec)
 {
-	struct scatterlist sg[1];
 	unsigned long start, end;
 	int bcount;
 	int ret;
 
-	sg_init_table(sg, 1);
-
 	for (start = jiffies, end = start + sec * HZ, bcount = 0;
 	     time_before(jiffies, end); bcount++) {
-		sg_set_buf(sg, p, blen);
 		ret = crypto_hash_digest(desc, sg, blen, out);
 		if (ret)
 			return ret;
@@ -910,18 +249,15 @@
 	return 0;
 }
 
-static int test_hash_jiffies(struct hash_desc *desc, char *p, int blen,
-			     int plen, char *out, int sec)
+static int test_hash_jiffies(struct hash_desc *desc, struct scatterlist *sg,
+			     int blen, int plen, char *out, int sec)
 {
-	struct scatterlist sg[1];
 	unsigned long start, end;
 	int bcount, pcount;
 	int ret;
 
 	if (plen == blen)
-		return test_hash_jiffies_digest(desc, p, blen, out, sec);
-
-	sg_init_table(sg, 1);
+		return test_hash_jiffies_digest(desc, sg, blen, out, sec);
 
 	for (start = jiffies, end = start + sec * HZ, bcount = 0;
 	     time_before(jiffies, end); bcount++) {
@@ -929,7 +265,6 @@
 		if (ret)
 			return ret;
 		for (pcount = 0; pcount < blen; pcount += plen) {
-			sg_set_buf(sg, p + pcount, plen);
 			ret = crypto_hash_update(desc, sg, plen);
 			if (ret)
 				return ret;
@@ -946,22 +281,18 @@
 	return 0;
 }
 
-static int test_hash_cycles_digest(struct hash_desc *desc, char *p, int blen,
-				   char *out)
+static int test_hash_cycles_digest(struct hash_desc *desc,
+				   struct scatterlist *sg, int blen, char *out)
 {
-	struct scatterlist sg[1];
 	unsigned long cycles = 0;
 	int i;
 	int ret;
 
-	sg_init_table(sg, 1);
-
 	local_bh_disable();
 	local_irq_disable();
 
 	/* Warm-up run. */
 	for (i = 0; i < 4; i++) {
-		sg_set_buf(sg, p, blen);
 		ret = crypto_hash_digest(desc, sg, blen, out);
 		if (ret)
 			goto out;
@@ -973,7 +304,6 @@
 
 		start = get_cycles();
 
-		sg_set_buf(sg, p, blen);
 		ret = crypto_hash_digest(desc, sg, blen, out);
 		if (ret)
 			goto out;
@@ -996,18 +326,15 @@
 	return 0;
 }
 
-static int test_hash_cycles(struct hash_desc *desc, char *p, int blen,
-			    int plen, char *out)
+static int test_hash_cycles(struct hash_desc *desc, struct scatterlist *sg,
+			    int blen, int plen, char *out)
 {
-	struct scatterlist sg[1];
 	unsigned long cycles = 0;
 	int i, pcount;
 	int ret;
 
 	if (plen == blen)
-		return test_hash_cycles_digest(desc, p, blen, out);
-
-	sg_init_table(sg, 1);
+		return test_hash_cycles_digest(desc, sg, blen, out);
 
 	local_bh_disable();
 	local_irq_disable();
@@ -1018,7 +345,6 @@
 		if (ret)
 			goto out;
 		for (pcount = 0; pcount < blen; pcount += plen) {
-			sg_set_buf(sg, p + pcount, plen);
 			ret = crypto_hash_update(desc, sg, plen);
 			if (ret)
 				goto out;
@@ -1038,7 +364,6 @@
 		if (ret)
 			goto out;
 		for (pcount = 0; pcount < blen; pcount += plen) {
-			sg_set_buf(sg, p + pcount, plen);
 			ret = crypto_hash_update(desc, sg, plen);
 			if (ret)
 				goto out;
@@ -1065,9 +390,10 @@
 	return 0;
 }
 
-static void test_hash_speed(char *algo, unsigned int sec,
-			      struct hash_speed *speed)
+static void test_hash_speed(const char *algo, unsigned int sec,
+			    struct hash_speed *speed)
 {
+	struct scatterlist sg[TVMEMSIZE];
 	struct crypto_hash *tfm;
 	struct hash_desc desc;
 	char output[1024];
@@ -1093,23 +419,27 @@
 		goto out;
 	}
 
+	sg_init_table(sg, TVMEMSIZE);
+	for (i = 0; i < TVMEMSIZE; i++) {
+		sg_set_buf(sg + i, tvmem[i], PAGE_SIZE);
+		memset(tvmem[i], 0xff, PAGE_SIZE);
+	}
+
 	for (i = 0; speed[i].blen != 0; i++) {
-		if (speed[i].blen > TVMEMSIZE) {
-			printk("template (%u) too big for tvmem (%u)\n",
-			       speed[i].blen, TVMEMSIZE);
+		if (speed[i].blen > TVMEMSIZE * PAGE_SIZE) {
+			printk("template (%u) too big for tvmem (%lu)\n",
+			       speed[i].blen, TVMEMSIZE * PAGE_SIZE);
 			goto out;
 		}
 
 		printk("test%3u (%5u byte blocks,%5u bytes per update,%4u updates): ",
 		       i, speed[i].blen, speed[i].plen, speed[i].blen / speed[i].plen);
 
-		memset(tvmem, 0xff, speed[i].blen);
-
 		if (sec)
-			ret = test_hash_jiffies(&desc, tvmem, speed[i].blen,
+			ret = test_hash_jiffies(&desc, sg, speed[i].blen,
 						speed[i].plen, output, sec);
 		else
-			ret = test_hash_cycles(&desc, tvmem, speed[i].blen,
+			ret = test_hash_cycles(&desc, sg, speed[i].blen,
 					       speed[i].plen, output);
 
 		if (ret) {
@@ -1122,73 +452,6 @@
 	crypto_free_hash(tfm);
 }
 
-static void test_comp(char *algo, struct comp_testvec *ctemplate,
-		       struct comp_testvec *dtemplate, int ctcount, int dtcount)
-{
-	unsigned int i;
-	char result[COMP_BUF_SIZE];
-	struct crypto_comp *tfm;
-	unsigned int tsize;
-
-	printk("\ntesting %s compression\n", algo);
-
-	tfm = crypto_alloc_comp(algo, 0, CRYPTO_ALG_ASYNC);
-	if (IS_ERR(tfm)) {
-		printk("failed to load transform for %s\n", algo);
-		return;
-	}
-
-	for (i = 0; i < ctcount; i++) {
-		int ilen, ret, dlen = COMP_BUF_SIZE;
-
-		printk("test %u:\n", i + 1);
-		memset(result, 0, sizeof (result));
-
-		ilen = ctemplate[i].inlen;
-		ret = crypto_comp_compress(tfm, ctemplate[i].input,
-		                           ilen, result, &dlen);
-		if (ret) {
-			printk("fail: ret=%d\n", ret);
-			continue;
-		}
-		hexdump(result, dlen);
-		printk("%s (ratio %d:%d)\n",
-		       memcmp(result, ctemplate[i].output, dlen) ? "fail" : "pass",
-		       ilen, dlen);
-	}
-
-	printk("\ntesting %s decompression\n", algo);
-
-	tsize = sizeof(struct comp_testvec);
-	tsize *= dtcount;
-	if (tsize > TVMEMSIZE) {
-		printk("template (%u) too big for tvmem (%u)\n", tsize,
-		       TVMEMSIZE);
-		goto out;
-	}
-
-	for (i = 0; i < dtcount; i++) {
-		int ilen, ret, dlen = COMP_BUF_SIZE;
-
-		printk("test %u:\n", i + 1);
-		memset(result, 0, sizeof (result));
-
-		ilen = dtemplate[i].inlen;
-		ret = crypto_comp_decompress(tfm, dtemplate[i].input,
-		                             ilen, result, &dlen);
-		if (ret) {
-			printk("fail: ret=%d\n", ret);
-			continue;
-		}
-		hexdump(result, dlen);
-		printk("%s (ratio %d:%d)\n",
-		       memcmp(result, dtemplate[i].output, dlen) ? "fail" : "pass",
-		       ilen, dlen);
-	}
-out:
-	crypto_free_comp(tfm);
-}
-
 static void test_available(void)
 {
 	char **name = check;
@@ -1201,549 +464,237 @@
 	}
 }
 
-static void do_test(void)
+static inline int tcrypt_test(const char *alg)
 {
-	switch (mode) {
+	return alg_test(alg, alg, 0, 0);
+}
 
+static void do_test(int m)
+{
+	int i;
+
+	switch (m) {
 	case 0:
-		test_hash("md5", md5_tv_template, MD5_TEST_VECTORS);
-
-		test_hash("sha1", sha1_tv_template, SHA1_TEST_VECTORS);
-
-		//DES
-		test_cipher("ecb(des)", ENCRYPT, des_enc_tv_template,
-			    DES_ENC_TEST_VECTORS);
-		test_cipher("ecb(des)", DECRYPT, des_dec_tv_template,
-			    DES_DEC_TEST_VECTORS);
-		test_cipher("cbc(des)", ENCRYPT, des_cbc_enc_tv_template,
-			    DES_CBC_ENC_TEST_VECTORS);
-		test_cipher("cbc(des)", DECRYPT, des_cbc_dec_tv_template,
-			    DES_CBC_DEC_TEST_VECTORS);
-
-		//DES3_EDE
-		test_cipher("ecb(des3_ede)", ENCRYPT, des3_ede_enc_tv_template,
-			    DES3_EDE_ENC_TEST_VECTORS);
-		test_cipher("ecb(des3_ede)", DECRYPT, des3_ede_dec_tv_template,
-			    DES3_EDE_DEC_TEST_VECTORS);
-
-		test_cipher("cbc(des3_ede)", ENCRYPT,
-			    des3_ede_cbc_enc_tv_template,
-			    DES3_EDE_CBC_ENC_TEST_VECTORS);
-
-		test_cipher("cbc(des3_ede)", DECRYPT,
-			    des3_ede_cbc_dec_tv_template,
-			    DES3_EDE_CBC_DEC_TEST_VECTORS);
-
-		test_hash("md4", md4_tv_template, MD4_TEST_VECTORS);
-
-		test_hash("sha224", sha224_tv_template, SHA224_TEST_VECTORS);
-
-		test_hash("sha256", sha256_tv_template, SHA256_TEST_VECTORS);
-
-		//BLOWFISH
-		test_cipher("ecb(blowfish)", ENCRYPT, bf_enc_tv_template,
-			    BF_ENC_TEST_VECTORS);
-		test_cipher("ecb(blowfish)", DECRYPT, bf_dec_tv_template,
-			    BF_DEC_TEST_VECTORS);
-		test_cipher("cbc(blowfish)", ENCRYPT, bf_cbc_enc_tv_template,
-			    BF_CBC_ENC_TEST_VECTORS);
-		test_cipher("cbc(blowfish)", DECRYPT, bf_cbc_dec_tv_template,
-			    BF_CBC_DEC_TEST_VECTORS);
-
-		//TWOFISH
-		test_cipher("ecb(twofish)", ENCRYPT, tf_enc_tv_template,
-			    TF_ENC_TEST_VECTORS);
-		test_cipher("ecb(twofish)", DECRYPT, tf_dec_tv_template,
-			    TF_DEC_TEST_VECTORS);
-		test_cipher("cbc(twofish)", ENCRYPT, tf_cbc_enc_tv_template,
-			    TF_CBC_ENC_TEST_VECTORS);
-		test_cipher("cbc(twofish)", DECRYPT, tf_cbc_dec_tv_template,
-			    TF_CBC_DEC_TEST_VECTORS);
-
-		//SERPENT
-		test_cipher("ecb(serpent)", ENCRYPT, serpent_enc_tv_template,
-			    SERPENT_ENC_TEST_VECTORS);
-		test_cipher("ecb(serpent)", DECRYPT, serpent_dec_tv_template,
-			    SERPENT_DEC_TEST_VECTORS);
-
-		//TNEPRES
-		test_cipher("ecb(tnepres)", ENCRYPT, tnepres_enc_tv_template,
-			    TNEPRES_ENC_TEST_VECTORS);
-		test_cipher("ecb(tnepres)", DECRYPT, tnepres_dec_tv_template,
-			    TNEPRES_DEC_TEST_VECTORS);
-
-		//AES
-		test_cipher("ecb(aes)", ENCRYPT, aes_enc_tv_template,
-			    AES_ENC_TEST_VECTORS);
-		test_cipher("ecb(aes)", DECRYPT, aes_dec_tv_template,
-			    AES_DEC_TEST_VECTORS);
-		test_cipher("cbc(aes)", ENCRYPT, aes_cbc_enc_tv_template,
-			    AES_CBC_ENC_TEST_VECTORS);
-		test_cipher("cbc(aes)", DECRYPT, aes_cbc_dec_tv_template,
-			    AES_CBC_DEC_TEST_VECTORS);
-		test_cipher("lrw(aes)", ENCRYPT, aes_lrw_enc_tv_template,
-			    AES_LRW_ENC_TEST_VECTORS);
-		test_cipher("lrw(aes)", DECRYPT, aes_lrw_dec_tv_template,
-			    AES_LRW_DEC_TEST_VECTORS);
-		test_cipher("xts(aes)", ENCRYPT, aes_xts_enc_tv_template,
-			    AES_XTS_ENC_TEST_VECTORS);
-		test_cipher("xts(aes)", DECRYPT, aes_xts_dec_tv_template,
-			    AES_XTS_DEC_TEST_VECTORS);
-		test_cipher("rfc3686(ctr(aes))", ENCRYPT, aes_ctr_enc_tv_template,
-			    AES_CTR_ENC_TEST_VECTORS);
-		test_cipher("rfc3686(ctr(aes))", DECRYPT, aes_ctr_dec_tv_template,
-			    AES_CTR_DEC_TEST_VECTORS);
-		test_aead("gcm(aes)", ENCRYPT, aes_gcm_enc_tv_template,
-			  AES_GCM_ENC_TEST_VECTORS);
-		test_aead("gcm(aes)", DECRYPT, aes_gcm_dec_tv_template,
-			  AES_GCM_DEC_TEST_VECTORS);
-		test_aead("ccm(aes)", ENCRYPT, aes_ccm_enc_tv_template,
-			  AES_CCM_ENC_TEST_VECTORS);
-		test_aead("ccm(aes)", DECRYPT, aes_ccm_dec_tv_template,
-			  AES_CCM_DEC_TEST_VECTORS);
-
-		//CAST5
-		test_cipher("ecb(cast5)", ENCRYPT, cast5_enc_tv_template,
-			    CAST5_ENC_TEST_VECTORS);
-		test_cipher("ecb(cast5)", DECRYPT, cast5_dec_tv_template,
-			    CAST5_DEC_TEST_VECTORS);
-
-		//CAST6
-		test_cipher("ecb(cast6)", ENCRYPT, cast6_enc_tv_template,
-			    CAST6_ENC_TEST_VECTORS);
-		test_cipher("ecb(cast6)", DECRYPT, cast6_dec_tv_template,
-			    CAST6_DEC_TEST_VECTORS);
-
-		//ARC4
-		test_cipher("ecb(arc4)", ENCRYPT, arc4_enc_tv_template,
-			    ARC4_ENC_TEST_VECTORS);
-		test_cipher("ecb(arc4)", DECRYPT, arc4_dec_tv_template,
-			    ARC4_DEC_TEST_VECTORS);
-
-		//TEA
-		test_cipher("ecb(tea)", ENCRYPT, tea_enc_tv_template,
-			    TEA_ENC_TEST_VECTORS);
-		test_cipher("ecb(tea)", DECRYPT, tea_dec_tv_template,
-			    TEA_DEC_TEST_VECTORS);
-
-
-		//XTEA
-		test_cipher("ecb(xtea)", ENCRYPT, xtea_enc_tv_template,
-			    XTEA_ENC_TEST_VECTORS);
-		test_cipher("ecb(xtea)", DECRYPT, xtea_dec_tv_template,
-			    XTEA_DEC_TEST_VECTORS);
-
-		//KHAZAD
-		test_cipher("ecb(khazad)", ENCRYPT, khazad_enc_tv_template,
-			    KHAZAD_ENC_TEST_VECTORS);
-		test_cipher("ecb(khazad)", DECRYPT, khazad_dec_tv_template,
-			    KHAZAD_DEC_TEST_VECTORS);
-
-		//ANUBIS
-		test_cipher("ecb(anubis)", ENCRYPT, anubis_enc_tv_template,
-			    ANUBIS_ENC_TEST_VECTORS);
-		test_cipher("ecb(anubis)", DECRYPT, anubis_dec_tv_template,
-			    ANUBIS_DEC_TEST_VECTORS);
-		test_cipher("cbc(anubis)", ENCRYPT, anubis_cbc_enc_tv_template,
-			    ANUBIS_CBC_ENC_TEST_VECTORS);
-		test_cipher("cbc(anubis)", DECRYPT, anubis_cbc_dec_tv_template,
-			    ANUBIS_CBC_ENC_TEST_VECTORS);
-
-		//XETA
-		test_cipher("ecb(xeta)", ENCRYPT, xeta_enc_tv_template,
-			    XETA_ENC_TEST_VECTORS);
-		test_cipher("ecb(xeta)", DECRYPT, xeta_dec_tv_template,
-			    XETA_DEC_TEST_VECTORS);
-
-		//FCrypt
-		test_cipher("pcbc(fcrypt)", ENCRYPT, fcrypt_pcbc_enc_tv_template,
-			    FCRYPT_ENC_TEST_VECTORS);
-		test_cipher("pcbc(fcrypt)", DECRYPT, fcrypt_pcbc_dec_tv_template,
-			    FCRYPT_DEC_TEST_VECTORS);
-
-		//CAMELLIA
-		test_cipher("ecb(camellia)", ENCRYPT,
-			    camellia_enc_tv_template,
-			    CAMELLIA_ENC_TEST_VECTORS);
-		test_cipher("ecb(camellia)", DECRYPT,
-			    camellia_dec_tv_template,
-			    CAMELLIA_DEC_TEST_VECTORS);
-		test_cipher("cbc(camellia)", ENCRYPT,
-			    camellia_cbc_enc_tv_template,
-			    CAMELLIA_CBC_ENC_TEST_VECTORS);
-		test_cipher("cbc(camellia)", DECRYPT,
-			    camellia_cbc_dec_tv_template,
-			    CAMELLIA_CBC_DEC_TEST_VECTORS);
-
-		//SEED
-		test_cipher("ecb(seed)", ENCRYPT, seed_enc_tv_template,
-			    SEED_ENC_TEST_VECTORS);
-		test_cipher("ecb(seed)", DECRYPT, seed_dec_tv_template,
-			    SEED_DEC_TEST_VECTORS);
-
-		//CTS
-		test_cipher("cts(cbc(aes))", ENCRYPT, cts_mode_enc_tv_template,
-			    CTS_MODE_ENC_TEST_VECTORS);
-		test_cipher("cts(cbc(aes))", DECRYPT, cts_mode_dec_tv_template,
-			    CTS_MODE_DEC_TEST_VECTORS);
-
-		test_hash("sha384", sha384_tv_template, SHA384_TEST_VECTORS);
-		test_hash("sha512", sha512_tv_template, SHA512_TEST_VECTORS);
-		test_hash("wp512", wp512_tv_template, WP512_TEST_VECTORS);
-		test_hash("wp384", wp384_tv_template, WP384_TEST_VECTORS);
-		test_hash("wp256", wp256_tv_template, WP256_TEST_VECTORS);
-		test_hash("tgr192", tgr192_tv_template, TGR192_TEST_VECTORS);
-		test_hash("tgr160", tgr160_tv_template, TGR160_TEST_VECTORS);
-		test_hash("tgr128", tgr128_tv_template, TGR128_TEST_VECTORS);
-		test_comp("deflate", deflate_comp_tv_template,
-			  deflate_decomp_tv_template, DEFLATE_COMP_TEST_VECTORS,
-			  DEFLATE_DECOMP_TEST_VECTORS);
-		test_comp("lzo", lzo_comp_tv_template, lzo_decomp_tv_template,
-			  LZO_COMP_TEST_VECTORS, LZO_DECOMP_TEST_VECTORS);
-		test_hash("crc32c", crc32c_tv_template, CRC32C_TEST_VECTORS);
-		test_hash("hmac(md5)", hmac_md5_tv_template,
-			  HMAC_MD5_TEST_VECTORS);
-		test_hash("hmac(sha1)", hmac_sha1_tv_template,
-			  HMAC_SHA1_TEST_VECTORS);
-		test_hash("hmac(sha224)", hmac_sha224_tv_template,
-			  HMAC_SHA224_TEST_VECTORS);
-		test_hash("hmac(sha256)", hmac_sha256_tv_template,
-			  HMAC_SHA256_TEST_VECTORS);
-		test_hash("hmac(sha384)", hmac_sha384_tv_template,
-			  HMAC_SHA384_TEST_VECTORS);
-		test_hash("hmac(sha512)", hmac_sha512_tv_template,
-			  HMAC_SHA512_TEST_VECTORS);
-
-		test_hash("xcbc(aes)", aes_xcbc128_tv_template,
-			  XCBC_AES_TEST_VECTORS);
-
-		test_hash("michael_mic", michael_mic_tv_template, MICHAEL_MIC_TEST_VECTORS);
+		for (i = 1; i < 200; i++)
+			do_test(i);
 		break;
 
 	case 1:
-		test_hash("md5", md5_tv_template, MD5_TEST_VECTORS);
+		tcrypt_test("md5");
 		break;
 
 	case 2:
-		test_hash("sha1", sha1_tv_template, SHA1_TEST_VECTORS);
+		tcrypt_test("sha1");
 		break;
 
 	case 3:
-		test_cipher("ecb(des)", ENCRYPT, des_enc_tv_template,
-			    DES_ENC_TEST_VECTORS);
-		test_cipher("ecb(des)", DECRYPT, des_dec_tv_template,
-			    DES_DEC_TEST_VECTORS);
-		test_cipher("cbc(des)", ENCRYPT, des_cbc_enc_tv_template,
-			    DES_CBC_ENC_TEST_VECTORS);
-		test_cipher("cbc(des)", DECRYPT, des_cbc_dec_tv_template,
-			    DES_CBC_DEC_TEST_VECTORS);
+		tcrypt_test("ecb(des)");
+		tcrypt_test("cbc(des)");
 		break;
 
 	case 4:
-		test_cipher("ecb(des3_ede)", ENCRYPT, des3_ede_enc_tv_template,
-			    DES3_EDE_ENC_TEST_VECTORS);
-		test_cipher("ecb(des3_ede)", DECRYPT, des3_ede_dec_tv_template,
-			    DES3_EDE_DEC_TEST_VECTORS);
-
-		test_cipher("cbc(des3_ede)", ENCRYPT,
-			    des3_ede_cbc_enc_tv_template,
-			    DES3_EDE_CBC_ENC_TEST_VECTORS);
-
-		test_cipher("cbc(des3_ede)", DECRYPT,
-			    des3_ede_cbc_dec_tv_template,
-			    DES3_EDE_CBC_DEC_TEST_VECTORS);
+		tcrypt_test("ecb(des3_ede)");
+		tcrypt_test("cbc(des3_ede)");
 		break;
 
 	case 5:
-		test_hash("md4", md4_tv_template, MD4_TEST_VECTORS);
+		tcrypt_test("md4");
 		break;
 
 	case 6:
-		test_hash("sha256", sha256_tv_template, SHA256_TEST_VECTORS);
+		tcrypt_test("sha256");
 		break;
 
 	case 7:
-		test_cipher("ecb(blowfish)", ENCRYPT, bf_enc_tv_template,
-			    BF_ENC_TEST_VECTORS);
-		test_cipher("ecb(blowfish)", DECRYPT, bf_dec_tv_template,
-			    BF_DEC_TEST_VECTORS);
-		test_cipher("cbc(blowfish)", ENCRYPT, bf_cbc_enc_tv_template,
-			    BF_CBC_ENC_TEST_VECTORS);
-		test_cipher("cbc(blowfish)", DECRYPT, bf_cbc_dec_tv_template,
-			    BF_CBC_DEC_TEST_VECTORS);
+		tcrypt_test("ecb(blowfish)");
+		tcrypt_test("cbc(blowfish)");
 		break;
 
 	case 8:
-		test_cipher("ecb(twofish)", ENCRYPT, tf_enc_tv_template,
-			    TF_ENC_TEST_VECTORS);
-		test_cipher("ecb(twofish)", DECRYPT, tf_dec_tv_template,
-			    TF_DEC_TEST_VECTORS);
-		test_cipher("cbc(twofish)", ENCRYPT, tf_cbc_enc_tv_template,
-			    TF_CBC_ENC_TEST_VECTORS);
-		test_cipher("cbc(twofish)", DECRYPT, tf_cbc_dec_tv_template,
-			    TF_CBC_DEC_TEST_VECTORS);
+		tcrypt_test("ecb(twofish)");
+		tcrypt_test("cbc(twofish)");
 		break;
 
 	case 9:
-		test_cipher("ecb(serpent)", ENCRYPT, serpent_enc_tv_template,
-			    SERPENT_ENC_TEST_VECTORS);
-		test_cipher("ecb(serpent)", DECRYPT, serpent_dec_tv_template,
-			    SERPENT_DEC_TEST_VECTORS);
+		tcrypt_test("ecb(serpent)");
 		break;
 
 	case 10:
-		test_cipher("ecb(aes)", ENCRYPT, aes_enc_tv_template,
-			    AES_ENC_TEST_VECTORS);
-		test_cipher("ecb(aes)", DECRYPT, aes_dec_tv_template,
-			    AES_DEC_TEST_VECTORS);
-		test_cipher("cbc(aes)", ENCRYPT, aes_cbc_enc_tv_template,
-			    AES_CBC_ENC_TEST_VECTORS);
-		test_cipher("cbc(aes)", DECRYPT, aes_cbc_dec_tv_template,
-			    AES_CBC_DEC_TEST_VECTORS);
-		test_cipher("lrw(aes)", ENCRYPT, aes_lrw_enc_tv_template,
-			    AES_LRW_ENC_TEST_VECTORS);
-		test_cipher("lrw(aes)", DECRYPT, aes_lrw_dec_tv_template,
-			    AES_LRW_DEC_TEST_VECTORS);
-		test_cipher("xts(aes)", ENCRYPT, aes_xts_enc_tv_template,
-			    AES_XTS_ENC_TEST_VECTORS);
-		test_cipher("xts(aes)", DECRYPT, aes_xts_dec_tv_template,
-			    AES_XTS_DEC_TEST_VECTORS);
-		test_cipher("rfc3686(ctr(aes))", ENCRYPT, aes_ctr_enc_tv_template,
-			    AES_CTR_ENC_TEST_VECTORS);
-		test_cipher("rfc3686(ctr(aes))", DECRYPT, aes_ctr_dec_tv_template,
-			    AES_CTR_DEC_TEST_VECTORS);
+		tcrypt_test("ecb(aes)");
+		tcrypt_test("cbc(aes)");
+		tcrypt_test("lrw(aes)");
+		tcrypt_test("xts(aes)");
+		tcrypt_test("rfc3686(ctr(aes))");
 		break;
 
 	case 11:
-		test_hash("sha384", sha384_tv_template, SHA384_TEST_VECTORS);
+		tcrypt_test("sha384");
 		break;
 
 	case 12:
-		test_hash("sha512", sha512_tv_template, SHA512_TEST_VECTORS);
+		tcrypt_test("sha512");
 		break;
 
 	case 13:
-		test_comp("deflate", deflate_comp_tv_template,
-			  deflate_decomp_tv_template, DEFLATE_COMP_TEST_VECTORS,
-			  DEFLATE_DECOMP_TEST_VECTORS);
+		tcrypt_test("deflate");
 		break;
 
 	case 14:
-		test_cipher("ecb(cast5)", ENCRYPT, cast5_enc_tv_template,
-			    CAST5_ENC_TEST_VECTORS);
-		test_cipher("ecb(cast5)", DECRYPT, cast5_dec_tv_template,
-			    CAST5_DEC_TEST_VECTORS);
+		tcrypt_test("ecb(cast5)");
 		break;
 
 	case 15:
-		test_cipher("ecb(cast6)", ENCRYPT, cast6_enc_tv_template,
-			    CAST6_ENC_TEST_VECTORS);
-		test_cipher("ecb(cast6)", DECRYPT, cast6_dec_tv_template,
-			    CAST6_DEC_TEST_VECTORS);
+		tcrypt_test("ecb(cast6)");
 		break;
 
 	case 16:
-		test_cipher("ecb(arc4)", ENCRYPT, arc4_enc_tv_template,
-			    ARC4_ENC_TEST_VECTORS);
-		test_cipher("ecb(arc4)", DECRYPT, arc4_dec_tv_template,
-			    ARC4_DEC_TEST_VECTORS);
+		tcrypt_test("ecb(arc4)");
 		break;
 
 	case 17:
-		test_hash("michael_mic", michael_mic_tv_template, MICHAEL_MIC_TEST_VECTORS);
+		tcrypt_test("michael_mic");
 		break;
 
 	case 18:
-		test_hash("crc32c", crc32c_tv_template, CRC32C_TEST_VECTORS);
+		tcrypt_test("crc32c");
 		break;
 
 	case 19:
-		test_cipher("ecb(tea)", ENCRYPT, tea_enc_tv_template,
-			    TEA_ENC_TEST_VECTORS);
-		test_cipher("ecb(tea)", DECRYPT, tea_dec_tv_template,
-			    TEA_DEC_TEST_VECTORS);
+		tcrypt_test("ecb(tea)");
 		break;
 
 	case 20:
-		test_cipher("ecb(xtea)", ENCRYPT, xtea_enc_tv_template,
-			    XTEA_ENC_TEST_VECTORS);
-		test_cipher("ecb(xtea)", DECRYPT, xtea_dec_tv_template,
-			    XTEA_DEC_TEST_VECTORS);
+		tcrypt_test("ecb(xtea)");
 		break;
 
 	case 21:
-		test_cipher("ecb(khazad)", ENCRYPT, khazad_enc_tv_template,
-			    KHAZAD_ENC_TEST_VECTORS);
-		test_cipher("ecb(khazad)", DECRYPT, khazad_dec_tv_template,
-			    KHAZAD_DEC_TEST_VECTORS);
+		tcrypt_test("ecb(khazad)");
 		break;
 
 	case 22:
-		test_hash("wp512", wp512_tv_template, WP512_TEST_VECTORS);
+		tcrypt_test("wp512");
 		break;
 
 	case 23:
-		test_hash("wp384", wp384_tv_template, WP384_TEST_VECTORS);
+		tcrypt_test("wp384");
 		break;
 
 	case 24:
-		test_hash("wp256", wp256_tv_template, WP256_TEST_VECTORS);
+		tcrypt_test("wp256");
 		break;
 
 	case 25:
-		test_cipher("ecb(tnepres)", ENCRYPT, tnepres_enc_tv_template,
-			    TNEPRES_ENC_TEST_VECTORS);
-		test_cipher("ecb(tnepres)", DECRYPT, tnepres_dec_tv_template,
-			    TNEPRES_DEC_TEST_VECTORS);
+		tcrypt_test("ecb(tnepres)");
 		break;
 
 	case 26:
-		test_cipher("ecb(anubis)", ENCRYPT, anubis_enc_tv_template,
-			    ANUBIS_ENC_TEST_VECTORS);
-		test_cipher("ecb(anubis)", DECRYPT, anubis_dec_tv_template,
-			    ANUBIS_DEC_TEST_VECTORS);
-		test_cipher("cbc(anubis)", ENCRYPT, anubis_cbc_enc_tv_template,
-			    ANUBIS_CBC_ENC_TEST_VECTORS);
-		test_cipher("cbc(anubis)", DECRYPT, anubis_cbc_dec_tv_template,
-			    ANUBIS_CBC_ENC_TEST_VECTORS);
+		tcrypt_test("ecb(anubis)");
+		tcrypt_test("cbc(anubis)");
 		break;
 
 	case 27:
-		test_hash("tgr192", tgr192_tv_template, TGR192_TEST_VECTORS);
+		tcrypt_test("tgr192");
 		break;
 
 	case 28:
 
-		test_hash("tgr160", tgr160_tv_template, TGR160_TEST_VECTORS);
+		tcrypt_test("tgr160");
 		break;
 
 	case 29:
-		test_hash("tgr128", tgr128_tv_template, TGR128_TEST_VECTORS);
+		tcrypt_test("tgr128");
 		break;
 
 	case 30:
-		test_cipher("ecb(xeta)", ENCRYPT, xeta_enc_tv_template,
-			    XETA_ENC_TEST_VECTORS);
-		test_cipher("ecb(xeta)", DECRYPT, xeta_dec_tv_template,
-			    XETA_DEC_TEST_VECTORS);
+		tcrypt_test("ecb(xeta)");
 		break;
 
 	case 31:
-		test_cipher("pcbc(fcrypt)", ENCRYPT, fcrypt_pcbc_enc_tv_template,
-			    FCRYPT_ENC_TEST_VECTORS);
-		test_cipher("pcbc(fcrypt)", DECRYPT, fcrypt_pcbc_dec_tv_template,
-			    FCRYPT_DEC_TEST_VECTORS);
+		tcrypt_test("pcbc(fcrypt)");
 		break;
 
 	case 32:
-		test_cipher("ecb(camellia)", ENCRYPT,
-			    camellia_enc_tv_template,
-			    CAMELLIA_ENC_TEST_VECTORS);
-		test_cipher("ecb(camellia)", DECRYPT,
-			    camellia_dec_tv_template,
-			    CAMELLIA_DEC_TEST_VECTORS);
-		test_cipher("cbc(camellia)", ENCRYPT,
-			    camellia_cbc_enc_tv_template,
-			    CAMELLIA_CBC_ENC_TEST_VECTORS);
-		test_cipher("cbc(camellia)", DECRYPT,
-			    camellia_cbc_dec_tv_template,
-			    CAMELLIA_CBC_DEC_TEST_VECTORS);
+		tcrypt_test("ecb(camellia)");
+		tcrypt_test("cbc(camellia)");
 		break;
 	case 33:
-		test_hash("sha224", sha224_tv_template, SHA224_TEST_VECTORS);
+		tcrypt_test("sha224");
 		break;
 
 	case 34:
-		test_cipher("salsa20", ENCRYPT,
-			    salsa20_stream_enc_tv_template,
-			    SALSA20_STREAM_ENC_TEST_VECTORS);
+		tcrypt_test("salsa20");
 		break;
 
 	case 35:
-		test_aead("gcm(aes)", ENCRYPT, aes_gcm_enc_tv_template,
-			  AES_GCM_ENC_TEST_VECTORS);
-		test_aead("gcm(aes)", DECRYPT, aes_gcm_dec_tv_template,
-			  AES_GCM_DEC_TEST_VECTORS);
+		tcrypt_test("gcm(aes)");
 		break;
 
 	case 36:
-		test_comp("lzo", lzo_comp_tv_template, lzo_decomp_tv_template,
-			  LZO_COMP_TEST_VECTORS, LZO_DECOMP_TEST_VECTORS);
+		tcrypt_test("lzo");
 		break;
 
 	case 37:
-		test_aead("ccm(aes)", ENCRYPT, aes_ccm_enc_tv_template,
-			  AES_CCM_ENC_TEST_VECTORS);
-		test_aead("ccm(aes)", DECRYPT, aes_ccm_dec_tv_template,
-			  AES_CCM_DEC_TEST_VECTORS);
+		tcrypt_test("ccm(aes)");
 		break;
 
 	case 38:
-		test_cipher("cts(cbc(aes))", ENCRYPT, cts_mode_enc_tv_template,
-			    CTS_MODE_ENC_TEST_VECTORS);
-		test_cipher("cts(cbc(aes))", DECRYPT, cts_mode_dec_tv_template,
-			    CTS_MODE_DEC_TEST_VECTORS);
+		tcrypt_test("cts(cbc(aes))");
 		break;
 
         case 39:
-		test_hash("rmd128", rmd128_tv_template, RMD128_TEST_VECTORS);
+		tcrypt_test("rmd128");
 		break;
 
         case 40:
-		test_hash("rmd160", rmd160_tv_template, RMD160_TEST_VECTORS);
+		tcrypt_test("rmd160");
 		break;
 
 	case 41:
-		test_hash("rmd256", rmd256_tv_template, RMD256_TEST_VECTORS);
+		tcrypt_test("rmd256");
 		break;
 
 	case 42:
-		test_hash("rmd320", rmd320_tv_template, RMD320_TEST_VECTORS);
+		tcrypt_test("rmd320");
+		break;
+
+	case 43:
+		tcrypt_test("ecb(seed)");
 		break;
 
 	case 100:
-		test_hash("hmac(md5)", hmac_md5_tv_template,
-			  HMAC_MD5_TEST_VECTORS);
+		tcrypt_test("hmac(md5)");
 		break;
 
 	case 101:
-		test_hash("hmac(sha1)", hmac_sha1_tv_template,
-			  HMAC_SHA1_TEST_VECTORS);
+		tcrypt_test("hmac(sha1)");
 		break;
 
 	case 102:
-		test_hash("hmac(sha256)", hmac_sha256_tv_template,
-			  HMAC_SHA256_TEST_VECTORS);
+		tcrypt_test("hmac(sha256)");
 		break;
 
 	case 103:
-		test_hash("hmac(sha384)", hmac_sha384_tv_template,
-			  HMAC_SHA384_TEST_VECTORS);
+		tcrypt_test("hmac(sha384)");
 		break;
 
 	case 104:
-		test_hash("hmac(sha512)", hmac_sha512_tv_template,
-			  HMAC_SHA512_TEST_VECTORS);
+		tcrypt_test("hmac(sha512)");
 		break;
 
 	case 105:
-		test_hash("hmac(sha224)", hmac_sha224_tv_template,
-			  HMAC_SHA224_TEST_VECTORS);
+		tcrypt_test("hmac(sha224)");
 		break;
 
 	case 106:
-		test_hash("xcbc(aes)", aes_xcbc128_tv_template,
-			  XCBC_AES_TEST_VECTORS);
+		tcrypt_test("xcbc(aes)");
 		break;
 
 	case 107:
-		test_hash("hmac(rmd128)", hmac_rmd128_tv_template,
-			  HMAC_RMD128_TEST_VECTORS);
+		tcrypt_test("hmac(rmd128)");
 		break;
 
 	case 108:
-		test_hash("hmac(rmd160)", hmac_rmd160_tv_template,
-			  HMAC_RMD160_TEST_VECTORS);
+		tcrypt_test("hmac(rmd160)");
 		break;
 
 	case 200:
@@ -1767,16 +718,16 @@
 
 	case 201:
 		test_cipher_speed("ecb(des3_ede)", ENCRYPT, sec,
-				des3_ede_enc_tv_template, DES3_EDE_ENC_TEST_VECTORS,
+				des3_speed_template, DES3_SPEED_VECTORS,
 				speed_template_24);
 		test_cipher_speed("ecb(des3_ede)", DECRYPT, sec,
-				des3_ede_enc_tv_template, DES3_EDE_ENC_TEST_VECTORS,
+				des3_speed_template, DES3_SPEED_VECTORS,
 				speed_template_24);
 		test_cipher_speed("cbc(des3_ede)", ENCRYPT, sec,
-				des3_ede_enc_tv_template, DES3_EDE_ENC_TEST_VECTORS,
+				des3_speed_template, DES3_SPEED_VECTORS,
 				speed_template_24);
 		test_cipher_speed("cbc(des3_ede)", DECRYPT, sec,
-				des3_ede_enc_tv_template, DES3_EDE_ENC_TEST_VECTORS,
+				des3_speed_template, DES3_SPEED_VECTORS,
 				speed_template_24);
 		break;
 
@@ -1906,31 +857,21 @@
 	case 1000:
 		test_available();
 		break;
-
-	default:
-		/* useful for debugging */
-		printk("not testing anything\n");
-		break;
 	}
 }
 
 static int __init tcrypt_mod_init(void)
 {
 	int err = -ENOMEM;
+	int i;
 
-	tvmem = kmalloc(TVMEMSIZE, GFP_KERNEL);
-	if (tvmem == NULL)
-		return err;
+	for (i = 0; i < TVMEMSIZE; i++) {
+		tvmem[i] = (void *)__get_free_page(GFP_KERNEL);
+		if (!tvmem[i])
+			goto err_free_tv;
+	}
 
-	xbuf = kmalloc(XBUFSIZE, GFP_KERNEL);
-	if (xbuf == NULL)
-		goto err_free_tv;
-
-	axbuf = kmalloc(XBUFSIZE, GFP_KERNEL);
-	if (axbuf == NULL)
-		goto err_free_xbuf;
-
-	do_test();
+	do_test(mode);
 
 	/* We intentionaly return -EAGAIN to prevent keeping
 	 * the module. It does all its work from init()
@@ -1940,11 +881,9 @@
 	 */
 	err = -EAGAIN;
 
-	kfree(axbuf);
- err_free_xbuf:
-	kfree(xbuf);
- err_free_tv:
-	kfree(tvmem);
+err_free_tv:
+	for (i = 0; i < TVMEMSIZE && tvmem[i]; i++)
+		free_page((unsigned long)tvmem[i]);
 
 	return err;
 }
diff --git a/crypto/tcrypt.h b/crypto/tcrypt.h
index 801e0c2..966bbfa 100644
--- a/crypto/tcrypt.h
+++ b/crypto/tcrypt.h
@@ -17,53 +17,9 @@
 #ifndef _CRYPTO_TCRYPT_H
 #define _CRYPTO_TCRYPT_H
 
-#define MAX_DIGEST_SIZE		64
-#define MAX_TAP			8
-
-#define MAX_KEYLEN		56
-#define MAX_IVLEN		32
-
-struct hash_testvec {
-	/* only used with keyed hash algorithms */
-	char *key;
-	char *plaintext;
-	char *digest;
-	unsigned char tap[MAX_TAP];
-	unsigned char psize;
-	unsigned char np;
-	unsigned char ksize;
-};
-
-struct cipher_testvec {
-	char *key;
-	char *iv;
-	char *input;
-	char *result;
-	unsigned char tap[MAX_TAP];
-	int np;
-	unsigned char fail;
-	unsigned char wk; /* weak key flag */
-	unsigned char klen;
-	unsigned short ilen;
-	unsigned short rlen;
-};
-
-struct aead_testvec {
-	char *key;
-	char *iv;
-	char *input;
-	char *assoc;
-	char *result;
-	unsigned char tap[MAX_TAP];
-	unsigned char atap[MAX_TAP];
-	int np;
-	int anp;
-	unsigned char fail;
-	unsigned char wk; /* weak key flag */
-	unsigned char klen;
-	unsigned short ilen;
-	unsigned short alen;
-	unsigned short rlen;
+struct cipher_speed_template {
+	const char *key;
+	unsigned int klen;
 };
 
 struct hash_speed {
@@ -71,8673 +27,20 @@
 	unsigned int plen;	/* per-update length */
 };
 
-static char zeroed_string[48];
-
-/*
- * MD4 test vectors from RFC1320
- */
-#define MD4_TEST_VECTORS	7
-
-static struct hash_testvec md4_tv_template [] = {
-	{
-		.plaintext = "",
-		.digest	= "\x31\xd6\xcf\xe0\xd1\x6a\xe9\x31"
-			  "\xb7\x3c\x59\xd7\xe0\xc0\x89\xc0",
-	}, {
-		.plaintext = "a",
-		.psize	= 1,
-		.digest	= "\xbd\xe5\x2c\xb3\x1d\xe3\x3e\x46"
-			  "\x24\x5e\x05\xfb\xdb\xd6\xfb\x24",
-	}, {
-		.plaintext = "abc",
-		.psize	= 3,
-		.digest	= "\xa4\x48\x01\x7a\xaf\x21\xd8\x52"
-			  "\x5f\xc1\x0a\xe8\x7a\xa6\x72\x9d",
-	}, {
-		.plaintext = "message digest",
-		.psize	= 14,
-		.digest	= "\xd9\x13\x0a\x81\x64\x54\x9f\xe8"
-			"\x18\x87\x48\x06\xe1\xc7\x01\x4b",
-	}, {
-		.plaintext = "abcdefghijklmnopqrstuvwxyz",
-		.psize	= 26,
-		.digest	= "\xd7\x9e\x1c\x30\x8a\xa5\xbb\xcd"
-			  "\xee\xa8\xed\x63\xdf\x41\x2d\xa9",
-		.np	= 2,
-		.tap	= { 13, 13 },
-	}, {
-		.plaintext = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
-		.psize	= 62,
-		.digest	= "\x04\x3f\x85\x82\xf2\x41\xdb\x35"
-			  "\x1c\xe6\x27\xe1\x53\xe7\xf0\xe4",
-	}, {
-		.plaintext = "123456789012345678901234567890123456789012345678901234567890123"
-			   "45678901234567890",
-		.psize	= 80,
-		.digest	= "\xe3\x3b\x4d\xdc\x9c\x38\xf2\x19"
-			  "\x9c\x3e\x7b\x16\x4f\xcc\x05\x36",
-	},
-};
-
-/*
- * MD5 test vectors from RFC1321
- */
-#define MD5_TEST_VECTORS	7
-
-static struct hash_testvec md5_tv_template[] = {
-	{
-		.digest	= "\xd4\x1d\x8c\xd9\x8f\x00\xb2\x04"
-			  "\xe9\x80\x09\x98\xec\xf8\x42\x7e",
-	}, {
-		.plaintext = "a",
-		.psize	= 1,
-		.digest	= "\x0c\xc1\x75\xb9\xc0\xf1\xb6\xa8"
-			  "\x31\xc3\x99\xe2\x69\x77\x26\x61",
-	}, {
-		.plaintext = "abc",
-		.psize	= 3,
-		.digest	= "\x90\x01\x50\x98\x3c\xd2\x4f\xb0"
-			  "\xd6\x96\x3f\x7d\x28\xe1\x7f\x72",
-	}, {
-		.plaintext = "message digest",
-		.psize	= 14,
-		.digest	= "\xf9\x6b\x69\x7d\x7c\xb7\x93\x8d"
-			  "\x52\x5a\x2f\x31\xaa\xf1\x61\xd0",
-	}, {
-		.plaintext = "abcdefghijklmnopqrstuvwxyz",
-		.psize	= 26,
-		.digest	= "\xc3\xfc\xd3\xd7\x61\x92\xe4\x00"
-			  "\x7d\xfb\x49\x6c\xca\x67\xe1\x3b",
-		.np	= 2,
-		.tap	= {13, 13}
-	}, {
-		.plaintext = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
-		.psize	= 62,
-		.digest	= "\xd1\x74\xab\x98\xd2\x77\xd9\xf5"
-			  "\xa5\x61\x1c\x2c\x9f\x41\x9d\x9f",
-	}, {
-		.plaintext = "12345678901234567890123456789012345678901234567890123456789012"
-			   "345678901234567890",
-		.psize	= 80,
-		.digest	= "\x57\xed\xf4\xa2\x2b\xe3\xc9\x55"
-			  "\xac\x49\xda\x2e\x21\x07\xb6\x7a",
-	}
-
-};
-
-/*
- * RIPEMD-128 test vectors from ISO/IEC 10118-3:2004(E)
- */
-#define RMD128_TEST_VECTORS     10
-
-static struct hash_testvec rmd128_tv_template[] = {
-	{
-		.digest	= "\xcd\xf2\x62\x13\xa1\x50\xdc\x3e"
-			  "\xcb\x61\x0f\x18\xf6\xb3\x8b\x46",
-	}, {
-		.plaintext = "a",
-		.psize	= 1,
-		.digest	= "\x86\xbe\x7a\xfa\x33\x9d\x0f\xc7"
-			  "\xcf\xc7\x85\xe7\x2f\x57\x8d\x33",
-	}, {
-		.plaintext = "abc",
-		.psize	= 3,
-		.digest	= "\xc1\x4a\x12\x19\x9c\x66\xe4\xba"
-			  "\x84\x63\x6b\x0f\x69\x14\x4c\x77",
-	}, {
-		.plaintext = "message digest",
-		.psize	= 14,
-		.digest	= "\x9e\x32\x7b\x3d\x6e\x52\x30\x62"
-			  "\xaf\xc1\x13\x2d\x7d\xf9\xd1\xb8",
-	}, {
-		.plaintext = "abcdefghijklmnopqrstuvwxyz",
-		.psize	= 26,
-		.digest	= "\xfd\x2a\xa6\x07\xf7\x1d\xc8\xf5"
-			  "\x10\x71\x49\x22\xb3\x71\x83\x4e",
-	}, {
-		.plaintext = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcde"
-			     "fghijklmnopqrstuvwxyz0123456789",
-		.psize	= 62,
-		.digest	= "\xd1\xe9\x59\xeb\x17\x9c\x91\x1f"
-			  "\xae\xa4\x62\x4c\x60\xc5\xc7\x02",
-	}, {
-		.plaintext = "1234567890123456789012345678901234567890"
-			     "1234567890123456789012345678901234567890",
-		.psize	= 80,
-		.digest	= "\x3f\x45\xef\x19\x47\x32\xc2\xdb"
-			  "\xb2\xc4\xa2\xc7\x69\x79\x5f\xa3",
-        }, {
-		.plaintext = "abcdbcdecdefdefgefghfghighij"
-			     "hijkijkljklmklmnlmnomnopnopq",
-		.psize	= 56,
-		.digest	= "\xa1\xaa\x06\x89\xd0\xfa\xfa\x2d"
-			  "\xdc\x22\xe8\x8b\x49\x13\x3a\x06",
-		.np	= 2,
-		.tap	= { 28, 28 },
-	}, {
-		.plaintext = "abcdefghbcdefghicdefghijdefghijkefghijklfghi"
-			     "jklmghijklmnhijklmnoijklmnopjklmnopqklmnopqr"
-			     "lmnopqrsmnopqrstnopqrstu",
-		.psize	= 112,
-		.digest	= "\xd4\xec\xc9\x13\xe1\xdf\x77\x6b"
-			  "\xf4\x8d\xe9\xd5\x5b\x1f\x25\x46",
-	}, {
-		.plaintext = "abcdbcdecdefdefgefghfghighijhijk",
-		.psize	= 32,
-		.digest	= "\x13\xfc\x13\xe8\xef\xff\x34\x7d"
-			  "\xe1\x93\xff\x46\xdb\xac\xcf\xd4",
-	}
-};
-
-/*
- * RIPEMD-160 test vectors from ISO/IEC 10118-3:2004(E)
- */
-#define RMD160_TEST_VECTORS     10
-
-static struct hash_testvec rmd160_tv_template[] = {
-	{
-		.digest	= "\x9c\x11\x85\xa5\xc5\xe9\xfc\x54\x61\x28"
-			  "\x08\x97\x7e\xe8\xf5\x48\xb2\x25\x8d\x31",
-	}, {
-		.plaintext = "a",
-		.psize	= 1,
-		.digest	= "\x0b\xdc\x9d\x2d\x25\x6b\x3e\xe9\xda\xae"
-			  "\x34\x7b\xe6\xf4\xdc\x83\x5a\x46\x7f\xfe",
-	}, {
-		.plaintext = "abc",
-		.psize	= 3,
-		.digest	= "\x8e\xb2\x08\xf7\xe0\x5d\x98\x7a\x9b\x04"
-			  "\x4a\x8e\x98\xc6\xb0\x87\xf1\x5a\x0b\xfc",
-	}, {
-		.plaintext = "message digest",
-		.psize	= 14,
-		.digest	= "\x5d\x06\x89\xef\x49\xd2\xfa\xe5\x72\xb8"
-			  "\x81\xb1\x23\xa8\x5f\xfa\x21\x59\x5f\x36",
-	}, {
-		.plaintext = "abcdefghijklmnopqrstuvwxyz",
-		.psize	= 26,
-		.digest	= "\xf7\x1c\x27\x10\x9c\x69\x2c\x1b\x56\xbb"
-			  "\xdc\xeb\x5b\x9d\x28\x65\xb3\x70\x8d\xbc",
-	}, {
-		.plaintext = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcde"
-			     "fghijklmnopqrstuvwxyz0123456789",
-		.psize	= 62,
-		.digest	= "\xb0\xe2\x0b\x6e\x31\x16\x64\x02\x86\xed"
-			  "\x3a\x87\xa5\x71\x30\x79\xb2\x1f\x51\x89",
-	}, {
-		.plaintext = "1234567890123456789012345678901234567890"
-			     "1234567890123456789012345678901234567890",
-		.psize	= 80,
-		.digest	= "\x9b\x75\x2e\x45\x57\x3d\x4b\x39\xf4\xdb"
-			  "\xd3\x32\x3c\xab\x82\xbf\x63\x32\x6b\xfb",
-        }, {
-		.plaintext = "abcdbcdecdefdefgefghfghighij"
-			     "hijkijkljklmklmnlmnomnopnopq",
-		.psize	= 56,
-		.digest	= "\x12\xa0\x53\x38\x4a\x9c\x0c\x88\xe4\x05"
-			  "\xa0\x6c\x27\xdc\xf4\x9a\xda\x62\xeb\x2b",
-		.np	= 2,
-		.tap	= { 28, 28 },
-	}, {
-		.plaintext = "abcdefghbcdefghicdefghijdefghijkefghijklfghi"
-			     "jklmghijklmnhijklmnoijklmnopjklmnopqklmnopqr"
-			     "lmnopqrsmnopqrstnopqrstu",
-		.psize	= 112,
-		.digest	= "\x6f\x3f\xa3\x9b\x6b\x50\x3c\x38\x4f\x91"
-			  "\x9a\x49\xa7\xaa\x5c\x2c\x08\xbd\xfb\x45",
-	}, {
-		.plaintext = "abcdbcdecdefdefgefghfghighijhijk",
-		.psize	= 32,
-		.digest	= "\x94\xc2\x64\x11\x54\x04\xe6\x33\x79\x0d"
-			  "\xfc\xc8\x7b\x58\x7d\x36\x77\x06\x7d\x9f",
-	}
-};
-
-/*
- * RIPEMD-256 test vectors
- */
-#define RMD256_TEST_VECTORS     8
-
-static struct hash_testvec rmd256_tv_template[] = {
-	{
-		.digest	= "\x02\xba\x4c\x4e\x5f\x8e\xcd\x18"
-			  "\x77\xfc\x52\xd6\x4d\x30\xe3\x7a"
-			  "\x2d\x97\x74\xfb\x1e\x5d\x02\x63"
-			  "\x80\xae\x01\x68\xe3\xc5\x52\x2d",
-	}, {
-		.plaintext = "a",
-		.psize	= 1,
-		.digest	= "\xf9\x33\x3e\x45\xd8\x57\xf5\xd9"
-			  "\x0a\x91\xba\xb7\x0a\x1e\xba\x0c"
-			  "\xfb\x1b\xe4\xb0\x78\x3c\x9a\xcf"
-			  "\xcd\x88\x3a\x91\x34\x69\x29\x25",
-	}, {
-		.plaintext = "abc",
-		.psize	= 3,
-		.digest	= "\xaf\xbd\x6e\x22\x8b\x9d\x8c\xbb"
-			  "\xce\xf5\xca\x2d\x03\xe6\xdb\xa1"
-			  "\x0a\xc0\xbc\x7d\xcb\xe4\x68\x0e"
-			  "\x1e\x42\xd2\xe9\x75\x45\x9b\x65",
-	}, {
-		.plaintext = "message digest",
-		.psize	= 14,
-		.digest	= "\x87\xe9\x71\x75\x9a\x1c\xe4\x7a"
-			  "\x51\x4d\x5c\x91\x4c\x39\x2c\x90"
-			  "\x18\xc7\xc4\x6b\xc1\x44\x65\x55"
-			  "\x4a\xfc\xdf\x54\xa5\x07\x0c\x0e",
-	}, {
-		.plaintext = "abcdefghijklmnopqrstuvwxyz",
-		.psize	= 26,
-		.digest	= "\x64\x9d\x30\x34\x75\x1e\xa2\x16"
-			  "\x77\x6b\xf9\xa1\x8a\xcc\x81\xbc"
-			  "\x78\x96\x11\x8a\x51\x97\x96\x87"
-			  "\x82\xdd\x1f\xd9\x7d\x8d\x51\x33",
-	}, {
-		.plaintext = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcde"
-			     "fghijklmnopqrstuvwxyz0123456789",
-		.psize	= 62,
-		.digest	= "\x57\x40\xa4\x08\xac\x16\xb7\x20"
-			  "\xb8\x44\x24\xae\x93\x1c\xbb\x1f"
-			  "\xe3\x63\xd1\xd0\xbf\x40\x17\xf1"
-			  "\xa8\x9f\x7e\xa6\xde\x77\xa0\xb8",
-	}, {
-		.plaintext = "1234567890123456789012345678901234567890"
-			     "1234567890123456789012345678901234567890",
-		.psize	= 80,
-		.digest	= "\x06\xfd\xcc\x7a\x40\x95\x48\xaa"
-			  "\xf9\x13\x68\xc0\x6a\x62\x75\xb5"
-			  "\x53\xe3\xf0\x99\xbf\x0e\xa4\xed"
-			  "\xfd\x67\x78\xdf\x89\xa8\x90\xdd",
-        }, {
-		.plaintext = "abcdbcdecdefdefgefghfghighij"
-			     "hijkijkljklmklmnlmnomnopnopq",
-		.psize	= 56,
-		.digest	= "\x38\x43\x04\x55\x83\xaa\xc6\xc8"
-			  "\xc8\xd9\x12\x85\x73\xe7\xa9\x80"
-			  "\x9a\xfb\x2a\x0f\x34\xcc\xc3\x6e"
-			  "\xa9\xe7\x2f\x16\xf6\x36\x8e\x3f",
-		.np	= 2,
-		.tap	= { 28, 28 },
-	}
-};
-
-/*
- * RIPEMD-320 test vectors
- */
-#define RMD320_TEST_VECTORS     8
-
-static struct hash_testvec rmd320_tv_template[] = {
-	{
-		.digest	= "\x22\xd6\x5d\x56\x61\x53\x6c\xdc\x75\xc1"
-			  "\xfd\xf5\xc6\xde\x7b\x41\xb9\xf2\x73\x25"
-			  "\xeb\xc6\x1e\x85\x57\x17\x7d\x70\x5a\x0e"
-			  "\xc8\x80\x15\x1c\x3a\x32\xa0\x08\x99\xb8",
-	}, {
-		.plaintext = "a",
-		.psize	= 1,
-		.digest	= "\xce\x78\x85\x06\x38\xf9\x26\x58\xa5\xa5"
-			  "\x85\x09\x75\x79\x92\x6d\xda\x66\x7a\x57"
-			  "\x16\x56\x2c\xfc\xf6\xfb\xe7\x7f\x63\x54"
-			  "\x2f\x99\xb0\x47\x05\xd6\x97\x0d\xff\x5d",
-	}, {
-		.plaintext = "abc",
-		.psize	= 3,
-		.digest	= "\xde\x4c\x01\xb3\x05\x4f\x89\x30\xa7\x9d"
-			  "\x09\xae\x73\x8e\x92\x30\x1e\x5a\x17\x08"
-			  "\x5b\xef\xfd\xc1\xb8\xd1\x16\x71\x3e\x74"
-			  "\xf8\x2f\xa9\x42\xd6\x4c\xdb\xc4\x68\x2d",
-	}, {
-		.plaintext = "message digest",
-		.psize	= 14,
-		.digest	= "\x3a\x8e\x28\x50\x2e\xd4\x5d\x42\x2f\x68"
-			  "\x84\x4f\x9d\xd3\x16\xe7\xb9\x85\x33\xfa"
-			  "\x3f\x2a\x91\xd2\x9f\x84\xd4\x25\xc8\x8d"
-			  "\x6b\x4e\xff\x72\x7d\xf6\x6a\x7c\x01\x97",
-	}, {
-		.plaintext = "abcdefghijklmnopqrstuvwxyz",
-		.psize	= 26,
-		.digest	= "\xca\xbd\xb1\x81\x0b\x92\x47\x0a\x20\x93"
-			  "\xaa\x6b\xce\x05\x95\x2c\x28\x34\x8c\xf4"
-			  "\x3f\xf6\x08\x41\x97\x51\x66\xbb\x40\xed"
-			  "\x23\x40\x04\xb8\x82\x44\x63\xe6\xb0\x09",
-	}, {
-		.plaintext = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcde"
-			     "fghijklmnopqrstuvwxyz0123456789",
-		.psize	= 62,
-		.digest	= "\xed\x54\x49\x40\xc8\x6d\x67\xf2\x50\xd2"
-			  "\x32\xc3\x0b\x7b\x3e\x57\x70\xe0\xc6\x0c"
-			  "\x8c\xb9\xa4\xca\xfe\x3b\x11\x38\x8a\xf9"
-			  "\x92\x0e\x1b\x99\x23\x0b\x84\x3c\x86\xa4",
-	}, {
-		.plaintext = "1234567890123456789012345678901234567890"
-			     "1234567890123456789012345678901234567890",
-		.psize	= 80,
-		.digest	= "\x55\x78\x88\xaf\x5f\x6d\x8e\xd6\x2a\xb6"
-			  "\x69\x45\xc6\xd2\xa0\xa4\x7e\xcd\x53\x41"
-			  "\xe9\x15\xeb\x8f\xea\x1d\x05\x24\x95\x5f"
-			  "\x82\x5d\xc7\x17\xe4\xa0\x08\xab\x2d\x42",
-        }, {
-		.plaintext = "abcdbcdecdefdefgefghfghighij"
-			     "hijkijkljklmklmnlmnomnopnopq",
-		.psize	= 56,
-		.digest	= "\xd0\x34\xa7\x95\x0c\xf7\x22\x02\x1b\xa4"
-			  "\xb8\x4d\xf7\x69\xa5\xde\x20\x60\xe2\x59"
-			  "\xdf\x4c\x9b\xb4\xa4\x26\x8c\x0e\x93\x5b"
-			  "\xbc\x74\x70\xa9\x69\xc9\xd0\x72\xa1\xac",
-		.np	= 2,
-		.tap	= { 28, 28 },
-	}
-};
-
-/*
- * SHA1 test vectors  from from FIPS PUB 180-1
- */
-#define SHA1_TEST_VECTORS	2
-
-static struct hash_testvec sha1_tv_template[] = {
-	{
-		.plaintext = "abc",
-		.psize	= 3,
-		.digest	= "\xa9\x99\x3e\x36\x47\x06\x81\x6a\xba\x3e"
-			  "\x25\x71\x78\x50\xc2\x6c\x9c\xd0\xd8\x9d",
-	}, {
-		.plaintext = "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
-		.psize	= 56,
-		.digest	= "\x84\x98\x3e\x44\x1c\x3b\xd2\x6e\xba\xae"
-			  "\x4a\xa1\xf9\x51\x29\xe5\xe5\x46\x70\xf1",
-		.np	= 2,
-		.tap	= { 28, 28 }
-	}
-};
-
-
-/*
- * SHA224 test vectors from from FIPS PUB 180-2
- */
-#define SHA224_TEST_VECTORS     2
-
-static struct hash_testvec sha224_tv_template[] = {
-	{
-		.plaintext = "abc",
-		.psize  = 3,
-		.digest = "\x23\x09\x7D\x22\x34\x05\xD8\x22"
-			  "\x86\x42\xA4\x77\xBD\xA2\x55\xB3"
-			  "\x2A\xAD\xBC\xE4\xBD\xA0\xB3\xF7"
-			  "\xE3\x6C\x9D\xA7",
-	}, {
-		.plaintext =
-		"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
-		.psize  = 56,
-		.digest = "\x75\x38\x8B\x16\x51\x27\x76\xCC"
-			  "\x5D\xBA\x5D\xA1\xFD\x89\x01\x50"
-			  "\xB0\xC6\x45\x5C\xB4\xF5\x8B\x19"
-			  "\x52\x52\x25\x25",
-		.np     = 2,
-		.tap    = { 28, 28 }
-	}
-};
-
-/*
- * SHA256 test vectors from from NIST
- */
-#define SHA256_TEST_VECTORS	2
-
-static struct hash_testvec sha256_tv_template[] = {
-	{
-		.plaintext = "abc",
-		.psize	= 3,
-		.digest	= "\xba\x78\x16\xbf\x8f\x01\xcf\xea"
-			  "\x41\x41\x40\xde\x5d\xae\x22\x23"
-			  "\xb0\x03\x61\xa3\x96\x17\x7a\x9c"
-			  "\xb4\x10\xff\x61\xf2\x00\x15\xad",
-	}, {
-		.plaintext = "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
-		.psize	= 56,
-		.digest	= "\x24\x8d\x6a\x61\xd2\x06\x38\xb8"
-			  "\xe5\xc0\x26\x93\x0c\x3e\x60\x39"
-			  "\xa3\x3c\xe4\x59\x64\xff\x21\x67"
-			  "\xf6\xec\xed\xd4\x19\xdb\x06\xc1",
-		.np	= 2,
-		.tap	= { 28, 28 }
-	},
-};
-
-/*
- * SHA384 test vectors from from NIST and kerneli
- */
-#define SHA384_TEST_VECTORS	4
-
-static struct hash_testvec sha384_tv_template[] = {
-	{
-		.plaintext= "abc",
-		.psize	= 3,
-		.digest	= "\xcb\x00\x75\x3f\x45\xa3\x5e\x8b"
-			  "\xb5\xa0\x3d\x69\x9a\xc6\x50\x07"
-			  "\x27\x2c\x32\xab\x0e\xde\xd1\x63"
-			  "\x1a\x8b\x60\x5a\x43\xff\x5b\xed"
-			  "\x80\x86\x07\x2b\xa1\xe7\xcc\x23"
-			  "\x58\xba\xec\xa1\x34\xc8\x25\xa7",
-	}, {
-		.plaintext = "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
-		.psize	= 56,
-		.digest	= "\x33\x91\xfd\xdd\xfc\x8d\xc7\x39"
-			  "\x37\x07\xa6\x5b\x1b\x47\x09\x39"
-			  "\x7c\xf8\xb1\xd1\x62\xaf\x05\xab"
-			  "\xfe\x8f\x45\x0d\xe5\xf3\x6b\xc6"
-			  "\xb0\x45\x5a\x85\x20\xbc\x4e\x6f"
-			  "\x5f\xe9\x5b\x1f\xe3\xc8\x45\x2b",
-	}, {
-		.plaintext = "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn"
-			   "hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu",
-		.psize	= 112,
-		.digest	= "\x09\x33\x0c\x33\xf7\x11\x47\xe8"
-			  "\x3d\x19\x2f\xc7\x82\xcd\x1b\x47"
-			  "\x53\x11\x1b\x17\x3b\x3b\x05\xd2"
-			  "\x2f\xa0\x80\x86\xe3\xb0\xf7\x12"
-			  "\xfc\xc7\xc7\x1a\x55\x7e\x2d\xb9"
-			  "\x66\xc3\xe9\xfa\x91\x74\x60\x39",
-	}, {
-		.plaintext = "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcd"
-			   "efghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz",
-		.psize	= 104,
-		.digest	= "\x3d\x20\x89\x73\xab\x35\x08\xdb"
-			  "\xbd\x7e\x2c\x28\x62\xba\x29\x0a"
-			  "\xd3\x01\x0e\x49\x78\xc1\x98\xdc"
-			  "\x4d\x8f\xd0\x14\xe5\x82\x82\x3a"
-			  "\x89\xe1\x6f\x9b\x2a\x7b\xbc\x1a"
-			  "\xc9\x38\xe2\xd1\x99\xe8\xbe\xa4",
-		.np	= 4,
-		.tap	= { 26, 26, 26, 26 }
-	},
-};
-
-/*
- * SHA512 test vectors from from NIST and kerneli
- */
-#define SHA512_TEST_VECTORS	4
-
-static struct hash_testvec sha512_tv_template[] = {
-	{
-		.plaintext = "abc",
-		.psize	= 3,
-		.digest	= "\xdd\xaf\x35\xa1\x93\x61\x7a\xba"
-			  "\xcc\x41\x73\x49\xae\x20\x41\x31"
-			  "\x12\xe6\xfa\x4e\x89\xa9\x7e\xa2"
-			  "\x0a\x9e\xee\xe6\x4b\x55\xd3\x9a"
-			  "\x21\x92\x99\x2a\x27\x4f\xc1\xa8"
-			  "\x36\xba\x3c\x23\xa3\xfe\xeb\xbd"
-			  "\x45\x4d\x44\x23\x64\x3c\xe8\x0e"
-			  "\x2a\x9a\xc9\x4f\xa5\x4c\xa4\x9f",
-	}, {
-		.plaintext = "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
-		.psize	= 56,
-		.digest	= "\x20\x4a\x8f\xc6\xdd\xa8\x2f\x0a"
-			  "\x0c\xed\x7b\xeb\x8e\x08\xa4\x16"
-			  "\x57\xc1\x6e\xf4\x68\xb2\x28\xa8"
-			  "\x27\x9b\xe3\x31\xa7\x03\xc3\x35"
-			  "\x96\xfd\x15\xc1\x3b\x1b\x07\xf9"
-			  "\xaa\x1d\x3b\xea\x57\x78\x9c\xa0"
-			  "\x31\xad\x85\xc7\xa7\x1d\xd7\x03"
-			  "\x54\xec\x63\x12\x38\xca\x34\x45",
-	}, {
-		.plaintext = "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn"
-			   "hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu",
-		.psize	= 112,
-		.digest	= "\x8e\x95\x9b\x75\xda\xe3\x13\xda"
-			  "\x8c\xf4\xf7\x28\x14\xfc\x14\x3f"
-			  "\x8f\x77\x79\xc6\xeb\x9f\x7f\xa1"
-			  "\x72\x99\xae\xad\xb6\x88\x90\x18"
-			  "\x50\x1d\x28\x9e\x49\x00\xf7\xe4"
-			  "\x33\x1b\x99\xde\xc4\xb5\x43\x3a"
-			  "\xc7\xd3\x29\xee\xb6\xdd\x26\x54"
-			  "\x5e\x96\xe5\x5b\x87\x4b\xe9\x09",
-	}, {
-		.plaintext = "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcd"
-			   "efghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz",
-		.psize	= 104,
-		.digest	= "\x93\x0d\x0c\xef\xcb\x30\xff\x11"
-			  "\x33\xb6\x89\x81\x21\xf1\xcf\x3d"
-			  "\x27\x57\x8a\xfc\xaf\xe8\x67\x7c"
-			  "\x52\x57\xcf\x06\x99\x11\xf7\x5d"
-			  "\x8f\x58\x31\xb5\x6e\xbf\xda\x67"
-			  "\xb2\x78\xe6\x6d\xff\x8b\x84\xfe"
-			  "\x2b\x28\x70\xf7\x42\xa5\x80\xd8"
-			  "\xed\xb4\x19\x87\x23\x28\x50\xc9",
-		.np	= 4,
-		.tap	= { 26, 26, 26, 26 }
-	},
-};
-
-
-/*
- * WHIRLPOOL test vectors from Whirlpool package
- * by Vincent Rijmen and Paulo S. L. M. Barreto as part of the NESSIE
- * submission
- */
-#define WP512_TEST_VECTORS	8
-
-static struct hash_testvec wp512_tv_template[] = {
-	{
-		.plaintext = "",
-		.psize	= 0,
-		.digest	= "\x19\xFA\x61\xD7\x55\x22\xA4\x66"
-			  "\x9B\x44\xE3\x9C\x1D\x2E\x17\x26"
-			  "\xC5\x30\x23\x21\x30\xD4\x07\xF8"
-			  "\x9A\xFE\xE0\x96\x49\x97\xF7\xA7"
-			  "\x3E\x83\xBE\x69\x8B\x28\x8F\xEB"
-			  "\xCF\x88\xE3\xE0\x3C\x4F\x07\x57"
-			  "\xEA\x89\x64\xE5\x9B\x63\xD9\x37"
-			  "\x08\xB1\x38\xCC\x42\xA6\x6E\xB3",
-
-
-	}, {
-		.plaintext = "a",
-		.psize	= 1,
-		.digest	= "\x8A\xCA\x26\x02\x79\x2A\xEC\x6F"
-			  "\x11\xA6\x72\x06\x53\x1F\xB7\xD7"
-			  "\xF0\xDF\xF5\x94\x13\x14\x5E\x69"
-			  "\x73\xC4\x50\x01\xD0\x08\x7B\x42"
-			  "\xD1\x1B\xC6\x45\x41\x3A\xEF\xF6"
-			  "\x3A\x42\x39\x1A\x39\x14\x5A\x59"
-			  "\x1A\x92\x20\x0D\x56\x01\x95\xE5"
-			  "\x3B\x47\x85\x84\xFD\xAE\x23\x1A",
-	}, {
-		.plaintext = "abc",
-		.psize	= 3,
-		.digest	= "\x4E\x24\x48\xA4\xC6\xF4\x86\xBB"
-			  "\x16\xB6\x56\x2C\x73\xB4\x02\x0B"
-			  "\xF3\x04\x3E\x3A\x73\x1B\xCE\x72"
-			  "\x1A\xE1\xB3\x03\xD9\x7E\x6D\x4C"
-			  "\x71\x81\xEE\xBD\xB6\xC5\x7E\x27"
-			  "\x7D\x0E\x34\x95\x71\x14\xCB\xD6"
-			  "\xC7\x97\xFC\x9D\x95\xD8\xB5\x82"
-			  "\xD2\x25\x29\x20\x76\xD4\xEE\xF5",
-	}, {
-		.plaintext = "message digest",
-		.psize	= 14,
-		.digest	= "\x37\x8C\x84\xA4\x12\x6E\x2D\xC6"
-			  "\xE5\x6D\xCC\x74\x58\x37\x7A\xAC"
-			  "\x83\x8D\x00\x03\x22\x30\xF5\x3C"
-			  "\xE1\xF5\x70\x0C\x0F\xFB\x4D\x3B"
-			  "\x84\x21\x55\x76\x59\xEF\x55\xC1"
-			  "\x06\xB4\xB5\x2A\xC5\xA4\xAA\xA6"
-			  "\x92\xED\x92\x00\x52\x83\x8F\x33"
-			  "\x62\xE8\x6D\xBD\x37\xA8\x90\x3E",
-	}, {
-		.plaintext = "abcdefghijklmnopqrstuvwxyz",
-		.psize	= 26,
-		.digest	= "\xF1\xD7\x54\x66\x26\x36\xFF\xE9"
-			  "\x2C\x82\xEB\xB9\x21\x2A\x48\x4A"
-			  "\x8D\x38\x63\x1E\xAD\x42\x38\xF5"
-			  "\x44\x2E\xE1\x3B\x80\x54\xE4\x1B"
-			  "\x08\xBF\x2A\x92\x51\xC3\x0B\x6A"
-			  "\x0B\x8A\xAE\x86\x17\x7A\xB4\xA6"
-			  "\xF6\x8F\x67\x3E\x72\x07\x86\x5D"
-			  "\x5D\x98\x19\xA3\xDB\xA4\xEB\x3B",
-	}, {
-		.plaintext = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
-			   "abcdefghijklmnopqrstuvwxyz0123456789",
-		.psize	= 62,
-		.digest	= "\xDC\x37\xE0\x08\xCF\x9E\xE6\x9B"
-			  "\xF1\x1F\x00\xED\x9A\xBA\x26\x90"
-			  "\x1D\xD7\xC2\x8C\xDE\xC0\x66\xCC"
-			  "\x6A\xF4\x2E\x40\xF8\x2F\x3A\x1E"
-			  "\x08\xEB\xA2\x66\x29\x12\x9D\x8F"
-			  "\xB7\xCB\x57\x21\x1B\x92\x81\xA6"
-			  "\x55\x17\xCC\x87\x9D\x7B\x96\x21"
-			  "\x42\xC6\x5F\x5A\x7A\xF0\x14\x67",
-	}, {
-		.plaintext = "1234567890123456789012345678901234567890"
-			   "1234567890123456789012345678901234567890",
-		.psize	= 80,
-		.digest	= "\x46\x6E\xF1\x8B\xAB\xB0\x15\x4D"
-			  "\x25\xB9\xD3\x8A\x64\x14\xF5\xC0"
-			  "\x87\x84\x37\x2B\xCC\xB2\x04\xD6"
-			  "\x54\x9C\x4A\xFA\xDB\x60\x14\x29"
-			  "\x4D\x5B\xD8\xDF\x2A\x6C\x44\xE5"
-			  "\x38\xCD\x04\x7B\x26\x81\xA5\x1A"
-			  "\x2C\x60\x48\x1E\x88\xC5\xA2\x0B"
-			  "\x2C\x2A\x80\xCF\x3A\x9A\x08\x3B",
-	}, {
-		.plaintext = "abcdbcdecdefdefgefghfghighijhijk",
-		.psize	= 32,
-		.digest	= "\x2A\x98\x7E\xA4\x0F\x91\x70\x61"
-			  "\xF5\xD6\xF0\xA0\xE4\x64\x4F\x48"
-			  "\x8A\x7A\x5A\x52\xDE\xEE\x65\x62"
-			  "\x07\xC5\x62\xF9\x88\xE9\x5C\x69"
-			  "\x16\xBD\xC8\x03\x1B\xC5\xBE\x1B"
-			  "\x7B\x94\x76\x39\xFE\x05\x0B\x56"
-			  "\x93\x9B\xAA\xA0\xAD\xFF\x9A\xE6"
-			  "\x74\x5B\x7B\x18\x1C\x3B\xE3\xFD",
-	},
-};
-
-#define WP384_TEST_VECTORS	8
-
-static struct hash_testvec wp384_tv_template[] = {
-	{
-		.plaintext = "",
-		.psize	= 0,
-		.digest	= "\x19\xFA\x61\xD7\x55\x22\xA4\x66"
-			  "\x9B\x44\xE3\x9C\x1D\x2E\x17\x26"
-			  "\xC5\x30\x23\x21\x30\xD4\x07\xF8"
-			  "\x9A\xFE\xE0\x96\x49\x97\xF7\xA7"
-			  "\x3E\x83\xBE\x69\x8B\x28\x8F\xEB"
-			  "\xCF\x88\xE3\xE0\x3C\x4F\x07\x57",
-
-
-	}, {
-		.plaintext = "a",
-		.psize	= 1,
-		.digest	= "\x8A\xCA\x26\x02\x79\x2A\xEC\x6F"
-			  "\x11\xA6\x72\x06\x53\x1F\xB7\xD7"
-			  "\xF0\xDF\xF5\x94\x13\x14\x5E\x69"
-			  "\x73\xC4\x50\x01\xD0\x08\x7B\x42"
-			  "\xD1\x1B\xC6\x45\x41\x3A\xEF\xF6"
-			  "\x3A\x42\x39\x1A\x39\x14\x5A\x59",
-	}, {
-		.plaintext = "abc",
-		.psize	= 3,
-		.digest	= "\x4E\x24\x48\xA4\xC6\xF4\x86\xBB"
-			  "\x16\xB6\x56\x2C\x73\xB4\x02\x0B"
-			  "\xF3\x04\x3E\x3A\x73\x1B\xCE\x72"
-			  "\x1A\xE1\xB3\x03\xD9\x7E\x6D\x4C"
-			  "\x71\x81\xEE\xBD\xB6\xC5\x7E\x27"
-			  "\x7D\x0E\x34\x95\x71\x14\xCB\xD6",
-	}, {
-		.plaintext = "message digest",
-		.psize	= 14,
-		.digest	= "\x37\x8C\x84\xA4\x12\x6E\x2D\xC6"
-			  "\xE5\x6D\xCC\x74\x58\x37\x7A\xAC"
-			  "\x83\x8D\x00\x03\x22\x30\xF5\x3C"
-			  "\xE1\xF5\x70\x0C\x0F\xFB\x4D\x3B"
-			  "\x84\x21\x55\x76\x59\xEF\x55\xC1"
-			  "\x06\xB4\xB5\x2A\xC5\xA4\xAA\xA6",
-	}, {
-		.plaintext = "abcdefghijklmnopqrstuvwxyz",
-		.psize	= 26,
-		.digest	= "\xF1\xD7\x54\x66\x26\x36\xFF\xE9"
-			  "\x2C\x82\xEB\xB9\x21\x2A\x48\x4A"
-			  "\x8D\x38\x63\x1E\xAD\x42\x38\xF5"
-			  "\x44\x2E\xE1\x3B\x80\x54\xE4\x1B"
-			  "\x08\xBF\x2A\x92\x51\xC3\x0B\x6A"
-			  "\x0B\x8A\xAE\x86\x17\x7A\xB4\xA6",
-	}, {
-		.plaintext = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
-			   "abcdefghijklmnopqrstuvwxyz0123456789",
-		.psize	= 62,
-		.digest	= "\xDC\x37\xE0\x08\xCF\x9E\xE6\x9B"
-			  "\xF1\x1F\x00\xED\x9A\xBA\x26\x90"
-			  "\x1D\xD7\xC2\x8C\xDE\xC0\x66\xCC"
-			  "\x6A\xF4\x2E\x40\xF8\x2F\x3A\x1E"
-			  "\x08\xEB\xA2\x66\x29\x12\x9D\x8F"
-			  "\xB7\xCB\x57\x21\x1B\x92\x81\xA6",
-	}, {
-		.plaintext = "1234567890123456789012345678901234567890"
-			   "1234567890123456789012345678901234567890",
-		.psize	= 80,
-		.digest	= "\x46\x6E\xF1\x8B\xAB\xB0\x15\x4D"
-			  "\x25\xB9\xD3\x8A\x64\x14\xF5\xC0"
-			  "\x87\x84\x37\x2B\xCC\xB2\x04\xD6"
-			  "\x54\x9C\x4A\xFA\xDB\x60\x14\x29"
-			  "\x4D\x5B\xD8\xDF\x2A\x6C\x44\xE5"
-			  "\x38\xCD\x04\x7B\x26\x81\xA5\x1A",
-	}, {
-		.plaintext = "abcdbcdecdefdefgefghfghighijhijk",
-		.psize	= 32,
-		.digest	= "\x2A\x98\x7E\xA4\x0F\x91\x70\x61"
-			  "\xF5\xD6\xF0\xA0\xE4\x64\x4F\x48"
-			  "\x8A\x7A\x5A\x52\xDE\xEE\x65\x62"
-			  "\x07\xC5\x62\xF9\x88\xE9\x5C\x69"
-			  "\x16\xBD\xC8\x03\x1B\xC5\xBE\x1B"
-			  "\x7B\x94\x76\x39\xFE\x05\x0B\x56",
-	},
-};
-
-#define WP256_TEST_VECTORS	8
-
-static struct hash_testvec wp256_tv_template[] = {
-	{
-		.plaintext = "",
-		.psize	= 0,
-		.digest	= "\x19\xFA\x61\xD7\x55\x22\xA4\x66"
-			  "\x9B\x44\xE3\x9C\x1D\x2E\x17\x26"
-			  "\xC5\x30\x23\x21\x30\xD4\x07\xF8"
-			  "\x9A\xFE\xE0\x96\x49\x97\xF7\xA7",
-
-
-	}, {
-		.plaintext = "a",
-		.psize	= 1,
-		.digest	= "\x8A\xCA\x26\x02\x79\x2A\xEC\x6F"
-			  "\x11\xA6\x72\x06\x53\x1F\xB7\xD7"
-			  "\xF0\xDF\xF5\x94\x13\x14\x5E\x69"
-			  "\x73\xC4\x50\x01\xD0\x08\x7B\x42",
-	}, {
-		.plaintext = "abc",
-		.psize	= 3,
-		.digest	= "\x4E\x24\x48\xA4\xC6\xF4\x86\xBB"
-			  "\x16\xB6\x56\x2C\x73\xB4\x02\x0B"
-			  "\xF3\x04\x3E\x3A\x73\x1B\xCE\x72"
-			  "\x1A\xE1\xB3\x03\xD9\x7E\x6D\x4C",
-	}, {
-		.plaintext = "message digest",
-		.psize	= 14,
-		.digest	= "\x37\x8C\x84\xA4\x12\x6E\x2D\xC6"
-			  "\xE5\x6D\xCC\x74\x58\x37\x7A\xAC"
-			  "\x83\x8D\x00\x03\x22\x30\xF5\x3C"
-			  "\xE1\xF5\x70\x0C\x0F\xFB\x4D\x3B",
-	}, {
-		.plaintext = "abcdefghijklmnopqrstuvwxyz",
-		.psize	= 26,
-		.digest	= "\xF1\xD7\x54\x66\x26\x36\xFF\xE9"
-			  "\x2C\x82\xEB\xB9\x21\x2A\x48\x4A"
-			  "\x8D\x38\x63\x1E\xAD\x42\x38\xF5"
-			  "\x44\x2E\xE1\x3B\x80\x54\xE4\x1B",
-	}, {
-		.plaintext = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
-			   "abcdefghijklmnopqrstuvwxyz0123456789",
-		.psize	= 62,
-		.digest	= "\xDC\x37\xE0\x08\xCF\x9E\xE6\x9B"
-			  "\xF1\x1F\x00\xED\x9A\xBA\x26\x90"
-			  "\x1D\xD7\xC2\x8C\xDE\xC0\x66\xCC"
-			  "\x6A\xF4\x2E\x40\xF8\x2F\x3A\x1E",
-	}, {
-		.plaintext = "1234567890123456789012345678901234567890"
-			   "1234567890123456789012345678901234567890",
-		.psize	= 80,
-		.digest	= "\x46\x6E\xF1\x8B\xAB\xB0\x15\x4D"
-			  "\x25\xB9\xD3\x8A\x64\x14\xF5\xC0"
-			  "\x87\x84\x37\x2B\xCC\xB2\x04\xD6"
-			  "\x54\x9C\x4A\xFA\xDB\x60\x14\x29",
-	}, {
-		.plaintext = "abcdbcdecdefdefgefghfghighijhijk",
-		.psize	= 32,
-		.digest	= "\x2A\x98\x7E\xA4\x0F\x91\x70\x61"
-			  "\xF5\xD6\xF0\xA0\xE4\x64\x4F\x48"
-			  "\x8A\x7A\x5A\x52\xDE\xEE\x65\x62"
-			  "\x07\xC5\x62\xF9\x88\xE9\x5C\x69",
-	},
-};
-
-/*
- * TIGER test vectors from Tiger website
- */
-#define TGR192_TEST_VECTORS	6
-
-static struct hash_testvec tgr192_tv_template[] = {
-	{
-		.plaintext = "",
-		.psize	= 0,
-		.digest = "\x24\xf0\x13\x0c\x63\xac\x93\x32"
-			  "\x16\x16\x6e\x76\xb1\xbb\x92\x5f"
-			  "\xf3\x73\xde\x2d\x49\x58\x4e\x7a",
-	}, {
-		.plaintext = "abc",
-		.psize	= 3,
-		.digest = "\xf2\x58\xc1\xe8\x84\x14\xab\x2a"
-			  "\x52\x7a\xb5\x41\xff\xc5\xb8\xbf"
-			  "\x93\x5f\x7b\x95\x1c\x13\x29\x51",
-	}, {
-		.plaintext = "Tiger",
-		.psize	= 5,
-		.digest = "\x9f\x00\xf5\x99\x07\x23\x00\xdd"
-			  "\x27\x6a\xbb\x38\xc8\xeb\x6d\xec"
-			  "\x37\x79\x0c\x11\x6f\x9d\x2b\xdf",
-	}, {
-		.plaintext = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-",
-		.psize	= 64,
-		.digest = "\x87\xfb\x2a\x90\x83\x85\x1c\xf7"
-			  "\x47\x0d\x2c\xf8\x10\xe6\xdf\x9e"
-			  "\xb5\x86\x44\x50\x34\xa5\xa3\x86",
-	}, {
-		.plaintext = "ABCDEFGHIJKLMNOPQRSTUVWXYZ=abcdefghijklmnopqrstuvwxyz+0123456789",
-		.psize	= 64,
-		.digest = "\x46\x7d\xb8\x08\x63\xeb\xce\x48"
-			  "\x8d\xf1\xcd\x12\x61\x65\x5d\xe9"
-			  "\x57\x89\x65\x65\x97\x5f\x91\x97",
-	}, {
-		.plaintext = "Tiger - A Fast New Hash Function, "
-			   "by Ross Anderson and Eli Biham, "
-			   "proceedings of Fast Software Encryption 3, "
-			   "Cambridge, 1996.",
-		.psize  = 125,
-		.digest = "\x3d\x9a\xeb\x03\xd1\xbd\x1a\x63"
-			  "\x57\xb2\x77\x4d\xfd\x6d\x5b\x24"
-			  "\xdd\x68\x15\x1d\x50\x39\x74\xfc",
-	},
-};
-
-#define TGR160_TEST_VECTORS	6
-
-static struct hash_testvec tgr160_tv_template[] = {
-	{
-		.plaintext = "",
-		.psize	= 0,
-		.digest = "\x24\xf0\x13\x0c\x63\xac\x93\x32"
-			  "\x16\x16\x6e\x76\xb1\xbb\x92\x5f"
-			  "\xf3\x73\xde\x2d",
-	}, {
-		.plaintext = "abc",
-		.psize	= 3,
-		.digest = "\xf2\x58\xc1\xe8\x84\x14\xab\x2a"
-			  "\x52\x7a\xb5\x41\xff\xc5\xb8\xbf"
-			  "\x93\x5f\x7b\x95",
-	}, {
-		.plaintext = "Tiger",
-		.psize	= 5,
-		.digest = "\x9f\x00\xf5\x99\x07\x23\x00\xdd"
-			  "\x27\x6a\xbb\x38\xc8\xeb\x6d\xec"
-			  "\x37\x79\x0c\x11",
-	}, {
-		.plaintext = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-",
-		.psize	= 64,
-		.digest = "\x87\xfb\x2a\x90\x83\x85\x1c\xf7"
-			  "\x47\x0d\x2c\xf8\x10\xe6\xdf\x9e"
-			  "\xb5\x86\x44\x50",
-	}, {
-		.plaintext = "ABCDEFGHIJKLMNOPQRSTUVWXYZ=abcdefghijklmnopqrstuvwxyz+0123456789",
-		.psize	= 64,
-		.digest = "\x46\x7d\xb8\x08\x63\xeb\xce\x48"
-			  "\x8d\xf1\xcd\x12\x61\x65\x5d\xe9"
-			  "\x57\x89\x65\x65",
-	}, {
-		.plaintext = "Tiger - A Fast New Hash Function, "
-			   "by Ross Anderson and Eli Biham, "
-			   "proceedings of Fast Software Encryption 3, "
-			   "Cambridge, 1996.",
-		.psize  = 125,
-		.digest = "\x3d\x9a\xeb\x03\xd1\xbd\x1a\x63"
-			  "\x57\xb2\x77\x4d\xfd\x6d\x5b\x24"
-			  "\xdd\x68\x15\x1d",
-	},
-};
-
-#define TGR128_TEST_VECTORS	6
-
-static struct hash_testvec tgr128_tv_template[] = {
-	{
-		.plaintext = "",
-		.psize	= 0,
-		.digest = "\x24\xf0\x13\x0c\x63\xac\x93\x32"
-			  "\x16\x16\x6e\x76\xb1\xbb\x92\x5f",
-	}, {
-		.plaintext = "abc",
-		.psize	= 3,
-		.digest = "\xf2\x58\xc1\xe8\x84\x14\xab\x2a"
-			  "\x52\x7a\xb5\x41\xff\xc5\xb8\xbf",
-	}, {
-		.plaintext = "Tiger",
-		.psize	= 5,
-		.digest = "\x9f\x00\xf5\x99\x07\x23\x00\xdd"
-			  "\x27\x6a\xbb\x38\xc8\xeb\x6d\xec",
-	}, {
-		.plaintext = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-",
-		.psize	= 64,
-		.digest = "\x87\xfb\x2a\x90\x83\x85\x1c\xf7"
-			  "\x47\x0d\x2c\xf8\x10\xe6\xdf\x9e",
-	}, {
-		.plaintext = "ABCDEFGHIJKLMNOPQRSTUVWXYZ=abcdefghijklmnopqrstuvwxyz+0123456789",
-		.psize	= 64,
-		.digest = "\x46\x7d\xb8\x08\x63\xeb\xce\x48"
-			  "\x8d\xf1\xcd\x12\x61\x65\x5d\xe9",
-	}, {
-		.plaintext = "Tiger - A Fast New Hash Function, "
-			   "by Ross Anderson and Eli Biham, "
-			   "proceedings of Fast Software Encryption 3, "
-			   "Cambridge, 1996.",
-		.psize  = 125,
-		.digest = "\x3d\x9a\xeb\x03\xd1\xbd\x1a\x63"
-			  "\x57\xb2\x77\x4d\xfd\x6d\x5b\x24",
-	},
-};
-
-/*
- * HMAC-MD5 test vectors from RFC2202
- * (These need to be fixed to not use strlen).
- */
-#define HMAC_MD5_TEST_VECTORS	7
-
-static struct hash_testvec hmac_md5_tv_template[] =
-{
-	{
-		.key	= "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b",
-		.ksize	= 16,
-		.plaintext = "Hi There",
-		.psize	= 8,
-		.digest	= "\x92\x94\x72\x7a\x36\x38\xbb\x1c"
-			  "\x13\xf4\x8e\xf8\x15\x8b\xfc\x9d",
-	}, {
-		.key	= "Jefe",
-		.ksize	= 4,
-		.plaintext = "what do ya want for nothing?",
-		.psize	= 28,
-		.digest	= "\x75\x0c\x78\x3e\x6a\xb0\xb5\x03"
-			  "\xea\xa8\x6e\x31\x0a\x5d\xb7\x38",
-		.np	= 2,
-		.tap	= {14, 14}
-	}, {
-		.key	= "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa",
-		.ksize	= 16,
-		.plaintext = "\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd"
-			"\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd"
-			"\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd"
-			"\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd",
-		.psize	= 50,
-		.digest	= "\x56\xbe\x34\x52\x1d\x14\x4c\x88"
-			  "\xdb\xb8\xc7\x33\xf0\xe8\xb3\xf6",
-	}, {
-		.key	= "\x01\x02\x03\x04\x05\x06\x07\x08"
-			  "\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10"
-			  "\x11\x12\x13\x14\x15\x16\x17\x18\x19",
-		.ksize	= 25,
-		.plaintext = "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"
-			"\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"
-			"\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"
-			"\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd",
-		.psize	= 50,
-		.digest	= "\x69\x7e\xaf\x0a\xca\x3a\x3a\xea"
-			  "\x3a\x75\x16\x47\x46\xff\xaa\x79",
-	}, {
-		.key	= "\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c",
-		.ksize	= 16,
-		.plaintext = "Test With Truncation",
-		.psize	= 20,
-		.digest	= "\x56\x46\x1e\xf2\x34\x2e\xdc\x00"
-			  "\xf9\xba\xb9\x95\x69\x0e\xfd\x4c",
-	}, {
-		.key	= "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			"\xaa\xaa",
-		.ksize	= 80,
-		.plaintext = "Test Using Larger Than Block-Size Key - Hash Key First",
-		.psize	= 54,
-		.digest	= "\x6b\x1a\xb7\xfe\x4b\xd7\xbf\x8f"
-			  "\x0b\x62\xe6\xce\x61\xb9\xd0\xcd",
-	}, {
-		.key	= "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			"\xaa\xaa",
-		.ksize	= 80,
-		.plaintext = "Test Using Larger Than Block-Size Key and Larger Than One "
-			   "Block-Size Data",
-		.psize	= 73,
-		.digest	= "\x6f\x63\x0f\xad\x67\xcd\xa0\xee"
-			  "\x1f\xb1\xf5\x62\xdb\x3a\xa5\x3e",
-	},
-};
-
-/*
- * HMAC-RIPEMD128 test vectors from RFC2286
- */
-#define HMAC_RMD128_TEST_VECTORS	7
-
-static struct hash_testvec hmac_rmd128_tv_template[] = {
-	{
-		.key	= "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b",
-		.ksize	= 16,
-		.plaintext = "Hi There",
-		.psize	= 8,
-		.digest	= "\xfb\xf6\x1f\x94\x92\xaa\x4b\xbf"
-			  "\x81\xc1\x72\xe8\x4e\x07\x34\xdb",
-	}, {
-		.key	= "Jefe",
-		.ksize	= 4,
-		.plaintext = "what do ya want for nothing?",
-		.psize	= 28,
-		.digest	= "\x87\x5f\x82\x88\x62\xb6\xb3\x34"
-			  "\xb4\x27\xc5\x5f\x9f\x7f\xf0\x9b",
-		.np	= 2,
-		.tap	= { 14, 14 },
-	}, {
-		.key	= "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa",
-		.ksize	= 16,
-		.plaintext = "\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd"
-			"\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd"
-			"\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd"
-			"\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd",
-		.psize	= 50,
-		.digest	= "\x09\xf0\xb2\x84\x6d\x2f\x54\x3d"
-			  "\xa3\x63\xcb\xec\x8d\x62\xa3\x8d",
-	}, {
-		.key	= "\x01\x02\x03\x04\x05\x06\x07\x08"
-			  "\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10"
-			  "\x11\x12\x13\x14\x15\x16\x17\x18\x19",
-		.ksize	= 25,
-		.plaintext = "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"
-			"\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"
-			"\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"
-			"\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd",
-		.psize	= 50,
-		.digest	= "\xbd\xbb\xd7\xcf\x03\xe4\x4b\x5a"
-			  "\xa6\x0a\xf8\x15\xbe\x4d\x22\x94",
-	}, {
-		.key	= "\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c",
-		.ksize	= 16,
-		.plaintext = "Test With Truncation",
-		.psize	= 20,
-		.digest	= "\xe7\x98\x08\xf2\x4b\x25\xfd\x03"
-			  "\x1c\x15\x5f\x0d\x55\x1d\x9a\x3a",
-	}, {
-		.key	= "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			"\xaa\xaa",
-		.ksize	= 80,
-		.plaintext = "Test Using Larger Than Block-Size Key - Hash Key First",
-		.psize	= 54,
-		.digest	= "\xdc\x73\x29\x28\xde\x98\x10\x4a"
-			  "\x1f\x59\xd3\x73\xc1\x50\xac\xbb",
-	}, {
-		.key	= "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			"\xaa\xaa",
-		.ksize	= 80,
-		.plaintext = "Test Using Larger Than Block-Size Key and Larger Than One "
-			   "Block-Size Data",
-		.psize	= 73,
-		.digest	= "\x5c\x6b\xec\x96\x79\x3e\x16\xd4"
-			  "\x06\x90\xc2\x37\x63\x5f\x30\xc5",
-	},
-};
-
-/*
- * HMAC-RIPEMD160 test vectors from RFC2286
- */
-#define HMAC_RMD160_TEST_VECTORS	7
-
-static struct hash_testvec hmac_rmd160_tv_template[] = {
-	{
-		.key	= "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b",
-		.ksize	= 20,
-		.plaintext = "Hi There",
-		.psize	= 8,
-		.digest	= "\x24\xcb\x4b\xd6\x7d\x20\xfc\x1a\x5d\x2e"
-			  "\xd7\x73\x2d\xcc\x39\x37\x7f\x0a\x56\x68",
-	}, {
-		.key	= "Jefe",
-		.ksize	= 4,
-		.plaintext = "what do ya want for nothing?",
-		.psize	= 28,
-		.digest	= "\xdd\xa6\xc0\x21\x3a\x48\x5a\x9e\x24\xf4"
-			  "\x74\x20\x64\xa7\xf0\x33\xb4\x3c\x40\x69",
-		.np	= 2,
-		.tap	= { 14, 14 },
-	}, {
-		.key	= "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa",
-		.ksize	= 20,
-		.plaintext = "\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd"
-			"\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd"
-			"\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd"
-			"\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd",
-		.psize	= 50,
-		.digest	= "\xb0\xb1\x05\x36\x0d\xe7\x59\x96\x0a\xb4"
-			  "\xf3\x52\x98\xe1\x16\xe2\x95\xd8\xe7\xc1",
-	}, {
-		.key	= "\x01\x02\x03\x04\x05\x06\x07\x08"
-			  "\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10"
-			  "\x11\x12\x13\x14\x15\x16\x17\x18\x19",
-		.ksize	= 25,
-		.plaintext = "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"
-			"\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"
-			"\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"
-			"\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd",
-		.psize	= 50,
-		.digest	= "\xd5\xca\x86\x2f\x4d\x21\xd5\xe6\x10\xe1"
-			  "\x8b\x4c\xf1\xbe\xb9\x7a\x43\x65\xec\xf4",
-	}, {
-		.key	= "\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c",
-		.ksize	= 20,
-		.plaintext = "Test With Truncation",
-		.psize	= 20,
-		.digest	= "\x76\x19\x69\x39\x78\xf9\x1d\x90\x53\x9a"
-			  "\xe7\x86\x50\x0f\xf3\xd8\xe0\x51\x8e\x39",
-	}, {
-		.key	= "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			"\xaa\xaa",
-		.ksize	= 80,
-		.plaintext = "Test Using Larger Than Block-Size Key - Hash Key First",
-		.psize	= 54,
-		.digest	= "\x64\x66\xca\x07\xac\x5e\xac\x29\xe1\xbd"
-			  "\x52\x3e\x5a\xda\x76\x05\xb7\x91\xfd\x8b",
-	}, {
-		.key	= "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			"\xaa\xaa",
-		.ksize	= 80,
-		.plaintext = "Test Using Larger Than Block-Size Key and Larger Than One "
-			   "Block-Size Data",
-		.psize	= 73,
-		.digest	= "\x69\xea\x60\x79\x8d\x71\x61\x6c\xce\x5f"
-			  "\xd0\x87\x1e\x23\x75\x4c\xd7\x5d\x5a\x0a",
-	},
-};
-
-/*
- * HMAC-SHA1 test vectors from RFC2202
- */
-#define HMAC_SHA1_TEST_VECTORS	7
-
-static struct hash_testvec hmac_sha1_tv_template[] = {
-	{
-		.key	= "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b",
-		.ksize	= 20,
-		.plaintext = "Hi There",
-		.psize	= 8,
-		.digest	= "\xb6\x17\x31\x86\x55\x05\x72\x64"
-			  "\xe2\x8b\xc0\xb6\xfb\x37\x8c\x8e\xf1"
-			  "\x46\xbe",
-	}, {
-		.key	= "Jefe",
-		.ksize	= 4,
-		.plaintext = "what do ya want for nothing?",
-		.psize	= 28,
-		.digest	= "\xef\xfc\xdf\x6a\xe5\xeb\x2f\xa2\xd2\x74"
-			  "\x16\xd5\xf1\x84\xdf\x9c\x25\x9a\x7c\x79",
-		.np	= 2,
-		.tap	= { 14, 14 }
-	}, {
-		.key	= "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa",
-		.ksize	= 20,
-		.plaintext = "\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd"
-			"\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd"
-			"\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd"
-			"\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd",
-		.psize	= 50,
-		.digest	= "\x12\x5d\x73\x42\xb9\xac\x11\xcd\x91\xa3"
-			  "\x9a\xf4\x8a\xa1\x7b\x4f\x63\xf1\x75\xd3",
-	}, {
-		.key	= "\x01\x02\x03\x04\x05\x06\x07\x08"
-			  "\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10"
-			  "\x11\x12\x13\x14\x15\x16\x17\x18\x19",
-		.ksize	= 25,
-		.plaintext = "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"
-			"\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"
-			"\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"
-			"\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd",
-		.psize	= 50,
-		.digest	= "\x4c\x90\x07\xf4\x02\x62\x50\xc6\xbc\x84"
-			  "\x14\xf9\xbf\x50\xc8\x6c\x2d\x72\x35\xda",
-	}, {
-		.key	= "\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c",
-		.ksize	= 20,
-		.plaintext = "Test With Truncation",
-		.psize	= 20,
-		.digest	= "\x4c\x1a\x03\x42\x4b\x55\xe0\x7f\xe7\xf2"
-			  "\x7b\xe1\xd5\x8b\xb9\x32\x4a\x9a\x5a\x04",
-	}, {
-		.key	= "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			"\xaa\xaa",
-		.ksize	= 80,
-		.plaintext = "Test Using Larger Than Block-Size Key - Hash Key First",
-		.psize	= 54,
-		.digest	= "\xaa\x4a\xe5\xe1\x52\x72\xd0\x0e\x95\x70"
-			  "\x56\x37\xce\x8a\x3b\x55\xed\x40\x21\x12",
-	}, {
-		.key	= "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			"\xaa\xaa",
-		.ksize	= 80,
-		.plaintext = "Test Using Larger Than Block-Size Key and Larger Than One "
-			   "Block-Size Data",
-		.psize	= 73,
-		.digest	= "\xe8\xe9\x9d\x0f\x45\x23\x7d\x78\x6d\x6b"
-			  "\xba\xa7\x96\x5c\x78\x08\xbb\xff\x1a\x91",
-	},
-};
-
-
-/*
- * SHA224 HMAC test vectors from RFC4231
- */
-#define HMAC_SHA224_TEST_VECTORS    4
-
-static struct hash_testvec hmac_sha224_tv_template[] = {
-	{
-		.key    = "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b"
-			"\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b"
-			"\x0b\x0b\x0b\x0b",
-		.ksize  = 20,
-		/*  ("Hi There") */
-		.plaintext = "\x48\x69\x20\x54\x68\x65\x72\x65",
-		.psize  = 8,
-		.digest = "\x89\x6f\xb1\x12\x8a\xbb\xdf\x19"
-			"\x68\x32\x10\x7c\xd4\x9d\xf3\x3f"
-			"\x47\xb4\xb1\x16\x99\x12\xba\x4f"
-			"\x53\x68\x4b\x22",
-	}, {
-		.key    = "Jefe",
-		.ksize  = 4,
-		/* ("what do ya want for nothing?") */
-		.plaintext = "\x77\x68\x61\x74\x20\x64\x6f\x20"
-			"\x79\x61\x20\x77\x61\x6e\x74\x20"
-			"\x66\x6f\x72\x20\x6e\x6f\x74\x68"
-			"\x69\x6e\x67\x3f",
-		.psize  = 28,
-		.digest = "\xa3\x0e\x01\x09\x8b\xc6\xdb\xbf"
-			"\x45\x69\x0f\x3a\x7e\x9e\x6d\x0f"
-			"\x8b\xbe\xa2\xa3\x9e\x61\x48\x00"
-			"\x8f\xd0\x5e\x44",
-		.np = 4,
-		.tap    = { 7, 7, 7, 7 }
-	}, {
-		.key    = "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			"\xaa\xaa\xaa",
-		.ksize  = 131,
-		/* ("Test Using Larger Than Block-Size Key - Hash Key First") */
-		.plaintext = "\x54\x65\x73\x74\x20\x55\x73\x69"
-			"\x6e\x67\x20\x4c\x61\x72\x67\x65"
-			"\x72\x20\x54\x68\x61\x6e\x20\x42"
-			"\x6c\x6f\x63\x6b\x2d\x53\x69\x7a"
-			"\x65\x20\x4b\x65\x79\x20\x2d\x20"
-			"\x48\x61\x73\x68\x20\x4b\x65\x79"
-			"\x20\x46\x69\x72\x73\x74",
-		.psize  = 54,
-		.digest = "\x95\xe9\xa0\xdb\x96\x20\x95\xad"
-			"\xae\xbe\x9b\x2d\x6f\x0d\xbc\xe2"
-			"\xd4\x99\xf1\x12\xf2\xd2\xb7\x27"
-			"\x3f\xa6\x87\x0e",
-	}, {
-		.key    = "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			"\xaa\xaa\xaa",
-		.ksize  = 131,
-		/* ("This is a test using a larger than block-size key and a")
-		(" larger than block-size data. The key needs to be")
-			(" hashed before being used by the HMAC algorithm.") */
-		.plaintext = "\x54\x68\x69\x73\x20\x69\x73\x20"
-			"\x61\x20\x74\x65\x73\x74\x20\x75"
-			"\x73\x69\x6e\x67\x20\x61\x20\x6c"
-			"\x61\x72\x67\x65\x72\x20\x74\x68"
-			"\x61\x6e\x20\x62\x6c\x6f\x63\x6b"
-			"\x2d\x73\x69\x7a\x65\x20\x6b\x65"
-			"\x79\x20\x61\x6e\x64\x20\x61\x20"
-			"\x6c\x61\x72\x67\x65\x72\x20\x74"
-			"\x68\x61\x6e\x20\x62\x6c\x6f\x63"
-			"\x6b\x2d\x73\x69\x7a\x65\x20\x64"
-			"\x61\x74\x61\x2e\x20\x54\x68\x65"
-			"\x20\x6b\x65\x79\x20\x6e\x65\x65"
-			"\x64\x73\x20\x74\x6f\x20\x62\x65"
-			"\x20\x68\x61\x73\x68\x65\x64\x20"
-			"\x62\x65\x66\x6f\x72\x65\x20\x62"
-			"\x65\x69\x6e\x67\x20\x75\x73\x65"
-			"\x64\x20\x62\x79\x20\x74\x68\x65"
-			"\x20\x48\x4d\x41\x43\x20\x61\x6c"
-			"\x67\x6f\x72\x69\x74\x68\x6d\x2e",
-		.psize  = 152,
-		.digest = "\x3a\x85\x41\x66\xac\x5d\x9f\x02"
-			"\x3f\x54\xd5\x17\xd0\xb3\x9d\xbd"
-			"\x94\x67\x70\xdb\x9c\x2b\x95\xc9"
-			"\xf6\xf5\x65\xd1",
-	},
-};
-
-/*
- * HMAC-SHA256 test vectors from
- * draft-ietf-ipsec-ciph-sha-256-01.txt
- */
-#define HMAC_SHA256_TEST_VECTORS	10
-
-static struct hash_testvec hmac_sha256_tv_template[] = {
-	{
-		.key	= "\x01\x02\x03\x04\x05\x06\x07\x08"
-			  "\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10"
-			  "\x11\x12\x13\x14\x15\x16\x17\x18"
-			  "\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20",
-		.ksize	= 32,
-		.plaintext = "abc",
-		.psize	= 3,
-		.digest	= "\xa2\x1b\x1f\x5d\x4c\xf4\xf7\x3a"
-			  "\x4d\xd9\x39\x75\x0f\x7a\x06\x6a"
-			  "\x7f\x98\xcc\x13\x1c\xb1\x6a\x66"
-			  "\x92\x75\x90\x21\xcf\xab\x81\x81",
-	}, {
-		.key	= "\x01\x02\x03\x04\x05\x06\x07\x08"
-			  "\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10"
-			  "\x11\x12\x13\x14\x15\x16\x17\x18"
-			  "\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20",
-		.ksize	= 32,
-		.plaintext = "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
-		.psize	= 56,
-		.digest	= "\x10\x4f\xdc\x12\x57\x32\x8f\x08"
-			  "\x18\x4b\xa7\x31\x31\xc5\x3c\xae"
-			  "\xe6\x98\xe3\x61\x19\x42\x11\x49"
-			  "\xea\x8c\x71\x24\x56\x69\x7d\x30",
-	}, {
-		.key	= "\x01\x02\x03\x04\x05\x06\x07\x08"
-			  "\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10"
-			  "\x11\x12\x13\x14\x15\x16\x17\x18"
-			  "\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20",
-		.ksize	= 32,
-		.plaintext = "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
-			   "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
-		.psize	= 112,
-		.digest	= "\x47\x03\x05\xfc\x7e\x40\xfe\x34"
-			  "\xd3\xee\xb3\xe7\x73\xd9\x5a\xab"
-			  "\x73\xac\xf0\xfd\x06\x04\x47\xa5"
-			  "\xeb\x45\x95\xbf\x33\xa9\xd1\xa3",
-	}, {
-		.key	= "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b"
-			"\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b"
-			"\x0b\x0b\x0b\x0b\x0b\x0b",
-		.ksize	= 32,
-		.plaintext = "Hi There",
-		.psize	= 8,
-		.digest	= "\x19\x8a\x60\x7e\xb4\x4b\xfb\xc6"
-			  "\x99\x03\xa0\xf1\xcf\x2b\xbd\xc5"
-			  "\xba\x0a\xa3\xf3\xd9\xae\x3c\x1c"
-			  "\x7a\x3b\x16\x96\xa0\xb6\x8c\xf7",
-	}, {
-		.key	= "Jefe",
-		.ksize	= 4,
-		.plaintext = "what do ya want for nothing?",
-		.psize	= 28,
-		.digest	= "\x5b\xdc\xc1\x46\xbf\x60\x75\x4e"
-			  "\x6a\x04\x24\x26\x08\x95\x75\xc7"
-			  "\x5a\x00\x3f\x08\x9d\x27\x39\x83"
-			  "\x9d\xec\x58\xb9\x64\xec\x38\x43",
-		.np	= 2,
-		.tap	= { 14, 14 }
-	}, {
-		.key	= "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa",
-		.ksize	= 32,
-		.plaintext = "\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd"
-			"\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd"
-			"\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd"
-			"\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd",
-		.psize	= 50,
-		.digest	= "\xcd\xcb\x12\x20\xd1\xec\xcc\xea"
-			  "\x91\xe5\x3a\xba\x30\x92\xf9\x62"
-			  "\xe5\x49\xfe\x6c\xe9\xed\x7f\xdc"
-			  "\x43\x19\x1f\xbd\xe4\x5c\x30\xb0",
-	}, {
-		.key	= "\x01\x02\x03\x04\x05\x06\x07\x08"
-			  "\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10"
-			  "\x11\x12\x13\x14\x15\x16\x17\x18"
-			  "\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20"
-			  "\x21\x22\x23\x24\x25",
-		.ksize	= 37,
-		.plaintext = "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"
-			"\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"
-			"\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"
-			"\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd",
-		.psize	= 50,
-		.digest	= "\xd4\x63\x3c\x17\xf6\xfb\x8d\x74"
-			  "\x4c\x66\xde\xe0\xf8\xf0\x74\x55"
-			  "\x6e\xc4\xaf\x55\xef\x07\x99\x85"
-			  "\x41\x46\x8e\xb4\x9b\xd2\xe9\x17",
-	}, {
-		.key	= "\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c"
-			"\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c"
-			"\x0c\x0c\x0c\x0c\x0c\x0c",
-		.ksize	= 32,
-		.plaintext = "Test With Truncation",
-		.psize	= 20,
-		.digest	= "\x75\x46\xaf\x01\x84\x1f\xc0\x9b"
-			  "\x1a\xb9\xc3\x74\x9a\x5f\x1c\x17"
-			  "\xd4\xf5\x89\x66\x8a\x58\x7b\x27"
-			  "\x00\xa9\xc9\x7c\x11\x93\xcf\x42",
-	}, {
-		.key	= "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			"\xaa\xaa",
-		.ksize	= 80,
-		.plaintext = "Test Using Larger Than Block-Size Key - Hash Key First",
-		.psize	= 54,
-		.digest	= "\x69\x53\x02\x5e\xd9\x6f\x0c\x09"
-			  "\xf8\x0a\x96\xf7\x8e\x65\x38\xdb"
-			  "\xe2\xe7\xb8\x20\xe3\xdd\x97\x0e"
-			  "\x7d\xdd\x39\x09\x1b\x32\x35\x2f",
-	}, {
-		.key	= "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			"\xaa\xaa",
-		.ksize	= 80,
-		.plaintext = "Test Using Larger Than Block-Size Key and Larger Than "
-			   "One Block-Size Data",
-		.psize	= 73,
-		.digest	= "\x63\x55\xac\x22\xe8\x90\xd0\xa3"
-			  "\xc8\x48\x1a\x5c\xa4\x82\x5b\xc8"
-			  "\x84\xd3\xe7\xa1\xff\x98\xa2\xfc"
-			  "\x2a\xc7\xd8\xe0\x64\xc3\xb2\xe6",
-	},
-};
-
-#define XCBC_AES_TEST_VECTORS 6
-
-static struct hash_testvec aes_xcbc128_tv_template[] = {
-	{
-		.key	= "\x00\x01\x02\x03\x04\x05\x06\x07"
-			  "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
-		.plaintext = zeroed_string,
-		.digest = "\x75\xf0\x25\x1d\x52\x8a\xc0\x1c"
-			  "\x45\x73\xdf\xd5\x84\xd7\x9f\x29",
-		.psize	= 0,
-		.ksize	= 16,
-	}, {
-		.key	= "\x00\x01\x02\x03\x04\x05\x06\x07"
-			  "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
-		.plaintext = "\x00\x01\x02",
-		.digest	= "\x5b\x37\x65\x80\xae\x2f\x19\xaf"
-			  "\xe7\x21\x9c\xee\xf1\x72\x75\x6f",
-		.psize	= 3,
-		.ksize	= 16,
-	} , {
-		.key	= "\x00\x01\x02\x03\x04\x05\x06\x07"
-			  "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
-		.plaintext = "\x00\x01\x02\x03\x04\x05\x06\x07"
-			     "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
-		.digest = "\xd2\xa2\x46\xfa\x34\x9b\x68\xa7"
-			  "\x99\x98\xa4\x39\x4f\xf7\xa2\x63",
-		.psize	= 16,
-		.ksize	= 16,
-	}, {
-		.key	= "\x00\x01\x02\x03\x04\x05\x06\x07"
-			  "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
-		.plaintext = "\x00\x01\x02\x03\x04\x05\x06\x07"
-			     "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
-			     "\x10\x11\x12\x13",
-		.digest = "\x47\xf5\x1b\x45\x64\x96\x62\x15"
-			  "\xb8\x98\x5c\x63\x05\x5e\xd3\x08",
-		.tap	= { 10, 10 },
-		.psize	= 20,
-		.np	= 2,
-		.ksize	= 16,
-	}, {
-		.key	= "\x00\x01\x02\x03\x04\x05\x06\x07"
-			  "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
-		.plaintext = "\x00\x01\x02\x03\x04\x05\x06\x07"
-			     "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
-			     "\x10\x11\x12\x13\x14\x15\x16\x17"
-			     "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f",
-		.digest = "\xf5\x4f\x0e\xc8\xd2\xb9\xf3\xd3"
-			  "\x68\x07\x73\x4b\xd5\x28\x3f\xd4",
-		.psize	= 32,
-		.ksize	= 16,
-	}, {
-		.key	= "\x00\x01\x02\x03\x04\x05\x06\x07"
-			  "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
-		.plaintext = "\x00\x01\x02\x03\x04\x05\x06\x07"
-			     "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
-			     "\x10\x11\x12\x13\x14\x15\x16\x17"
-			     "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
-			     "\x20\x21",
-		.digest = "\xbe\xcb\xb3\xbc\xcd\xb5\x18\xa3"
-			  "\x06\x77\xd5\x48\x1f\xb6\xb4\xd8",
-		.tap	= { 17, 17 },
-		.psize	= 34,
-		.np	= 2,
-		.ksize	= 16,
-	}
-};
-
-/*
- * SHA384 HMAC test vectors from RFC4231
- */
-
-#define HMAC_SHA384_TEST_VECTORS	4
-
-static struct hash_testvec hmac_sha384_tv_template[] = {
-	{
-		.key	= "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b"
-			  "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b"
-			  "\x0b\x0b\x0b\x0b",
-		.ksize	= 20,
-		.plaintext = "Hi There",
-		.psize	= 8,
-		.digest	= "\xaf\xd0\x39\x44\xd8\x48\x95\x62"
-			  "\x6b\x08\x25\xf4\xab\x46\x90\x7f"
-			  "\x15\xf9\xda\xdb\xe4\x10\x1e\xc6"
-			  "\x82\xaa\x03\x4c\x7c\xeb\xc5\x9c"
-			  "\xfa\xea\x9e\xa9\x07\x6e\xde\x7f"
-			  "\x4a\xf1\x52\xe8\xb2\xfa\x9c\xb6",
-	}, {
-		.key	= "Jefe",
-		.ksize	= 4,
-		.plaintext = "what do ya want for nothing?",
-		.psize	= 28,
-		.digest	= "\xaf\x45\xd2\xe3\x76\x48\x40\x31"
-			  "\x61\x7f\x78\xd2\xb5\x8a\x6b\x1b"
-			  "\x9c\x7e\xf4\x64\xf5\xa0\x1b\x47"
-			  "\xe4\x2e\xc3\x73\x63\x22\x44\x5e"
-			  "\x8e\x22\x40\xca\x5e\x69\xe2\xc7"
-			  "\x8b\x32\x39\xec\xfa\xb2\x16\x49",
-		.np	= 4,
-		.tap	= { 7, 7, 7, 7 }
-	}, {
-		.key	= "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			  "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			  "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			  "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			  "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			  "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			  "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			  "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			  "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			  "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			  "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			  "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			  "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			  "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			  "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			  "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			  "\xaa\xaa\xaa",
-		.ksize	= 131,
-		.plaintext = "Test Using Larger Than Block-Siz"
-			   "e Key - Hash Key First",
-		.psize	= 54,
-		.digest	= "\x4e\xce\x08\x44\x85\x81\x3e\x90"
-			  "\x88\xd2\xc6\x3a\x04\x1b\xc5\xb4"
-			  "\x4f\x9e\xf1\x01\x2a\x2b\x58\x8f"
-			  "\x3c\xd1\x1f\x05\x03\x3a\xc4\xc6"
-			  "\x0c\x2e\xf6\xab\x40\x30\xfe\x82"
-			  "\x96\x24\x8d\xf1\x63\xf4\x49\x52",
-	}, {
-		.key	= "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			  "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			  "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			  "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			  "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			  "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			  "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			  "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			  "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			  "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			  "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			  "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			  "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			  "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			  "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			  "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			  "\xaa\xaa\xaa",
-		.ksize	= 131,
-		.plaintext = "This is a test u"
-			   "sing a larger th"
-			   "an block-size ke"
-			   "y and a larger t"
-			   "han block-size d"
-			   "ata. The key nee"
-			   "ds to be hashed "
-			   "before being use"
-			   "d by the HMAC al"
-			   "gorithm.",
-		.psize	= 152,
-		.digest	= "\x66\x17\x17\x8e\x94\x1f\x02\x0d"
-			  "\x35\x1e\x2f\x25\x4e\x8f\xd3\x2c"
-			  "\x60\x24\x20\xfe\xb0\xb8\xfb\x9a"
-			  "\xdc\xce\xbb\x82\x46\x1e\x99\xc5"
-			  "\xa6\x78\xcc\x31\xe7\x99\x17\x6d"
-			  "\x38\x60\xe6\x11\x0c\x46\x52\x3e",
-	},
-};
-
-/*
- * SHA512 HMAC test vectors from RFC4231
- */
-
-#define HMAC_SHA512_TEST_VECTORS	4
-
-static struct hash_testvec hmac_sha512_tv_template[] = {
-	{
-		.key	= "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b"
-			  "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b"
-			  "\x0b\x0b\x0b\x0b",
-		.ksize	= 20,
-		.plaintext = "Hi There",
-		.psize	= 8,
-		.digest	= "\x87\xaa\x7c\xde\xa5\xef\x61\x9d"
-			  "\x4f\xf0\xb4\x24\x1a\x1d\x6c\xb0"
-			  "\x23\x79\xf4\xe2\xce\x4e\xc2\x78"
-			  "\x7a\xd0\xb3\x05\x45\xe1\x7c\xde"
-			  "\xda\xa8\x33\xb7\xd6\xb8\xa7\x02"
-			  "\x03\x8b\x27\x4e\xae\xa3\xf4\xe4"
-			  "\xbe\x9d\x91\x4e\xeb\x61\xf1\x70"
-			  "\x2e\x69\x6c\x20\x3a\x12\x68\x54",
-	}, {
-		.key	= "Jefe",
-		.ksize	= 4,
-		.plaintext = "what do ya want for nothing?",
-		.psize	= 28,
-		.digest	= "\x16\x4b\x7a\x7b\xfc\xf8\x19\xe2"
-			  "\xe3\x95\xfb\xe7\x3b\x56\xe0\xa3"
-			  "\x87\xbd\x64\x22\x2e\x83\x1f\xd6"
-			  "\x10\x27\x0c\xd7\xea\x25\x05\x54"
-			  "\x97\x58\xbf\x75\xc0\x5a\x99\x4a"
-			  "\x6d\x03\x4f\x65\xf8\xf0\xe6\xfd"
-			  "\xca\xea\xb1\xa3\x4d\x4a\x6b\x4b"
-			  "\x63\x6e\x07\x0a\x38\xbc\xe7\x37",
-		.np	= 4,
-		.tap	= { 7, 7, 7, 7 }
-	}, {
-		.key	= "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			  "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			  "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			  "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			  "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			  "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			  "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			  "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			  "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			  "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			  "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			  "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			  "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			  "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			  "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			  "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			  "\xaa\xaa\xaa",
-		.ksize	= 131,
-		.plaintext = "Test Using Large"
-			   "r Than Block-Siz"
-			   "e Key - Hash Key"
-			   " First",
-		.psize	= 54,
-		.digest	= "\x80\xb2\x42\x63\xc7\xc1\xa3\xeb"
-			"\xb7\x14\x93\xc1\xdd\x7b\xe8\xb4"
-			"\x9b\x46\xd1\xf4\x1b\x4a\xee\xc1"
-			"\x12\x1b\x01\x37\x83\xf8\xf3\x52"
-			"\x6b\x56\xd0\x37\xe0\x5f\x25\x98"
-			"\xbd\x0f\xd2\x21\x5d\x6a\x1e\x52"
-			"\x95\xe6\x4f\x73\xf6\x3f\x0a\xec"
-			"\x8b\x91\x5a\x98\x5d\x78\x65\x98",
-	}, {
-		.key	= "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-			"\xaa\xaa\xaa",
-		.ksize	= 131,
-		.plaintext =
-			  "This is a test u"
-			  "sing a larger th"
-			  "an block-size ke"
-			  "y and a larger t"
-			  "han block-size d"
-			  "ata. The key nee"
-			  "ds to be hashed "
-			  "before being use"
-			  "d by the HMAC al"
-			  "gorithm.",
-		.psize	= 152,
-		.digest	= "\xe3\x7b\x6a\x77\x5d\xc8\x7d\xba"
-			"\xa4\xdf\xa9\xf9\x6e\x5e\x3f\xfd"
-			"\xde\xbd\x71\xf8\x86\x72\x89\x86"
-			"\x5d\xf5\xa3\x2d\x20\xcd\xc9\x44"
-			"\xb6\x02\x2c\xac\x3c\x49\x82\xb1"
-			"\x0d\x5e\xeb\x55\xc3\xe4\xde\x15"
-			"\x13\x46\x76\xfb\x6d\xe0\x44\x60"
-			"\x65\xc9\x74\x40\xfa\x8c\x6a\x58",
-	},
-};
-
 /*
  * DES test vectors.
  */
-#define DES_ENC_TEST_VECTORS		10
-#define DES_DEC_TEST_VECTORS		4
-#define DES_CBC_ENC_TEST_VECTORS	5
-#define DES_CBC_DEC_TEST_VECTORS	4
-#define DES3_EDE_ENC_TEST_VECTORS	3
-#define DES3_EDE_DEC_TEST_VECTORS	3
-#define DES3_EDE_CBC_ENC_TEST_VECTORS	1
-#define DES3_EDE_CBC_DEC_TEST_VECTORS	1
+#define DES3_SPEED_VECTORS	1
 
-static struct cipher_testvec des_enc_tv_template[] = {
-	{ /* From Applied Cryptography */
-		.key	= "\x01\x23\x45\x67\x89\xab\xcd\xef",
-		.klen	= 8,
-		.input	= "\x01\x23\x45\x67\x89\xab\xcd\xe7",
-		.ilen	= 8,
-		.result	= "\xc9\x57\x44\x25\x6a\x5e\xd3\x1d",
-		.rlen	= 8,
-	}, { /* Same key, different plaintext block */
-		.key	= "\x01\x23\x45\x67\x89\xab\xcd\xef",
-		.klen	= 8,
-		.input	= "\x22\x33\x44\x55\x66\x77\x88\x99",
-		.ilen	= 8,
-		.result	= "\xf7\x9c\x89\x2a\x33\x8f\x4a\x8b",
-		.rlen	= 8,
-	}, { /* Sbox test from NBS */
-		.key	= "\x7c\xa1\x10\x45\x4a\x1a\x6e\x57",
-		.klen	= 8,
-		.input	= "\x01\xa1\xd6\xd0\x39\x77\x67\x42",
-		.ilen	= 8,
-		.result	= "\x69\x0f\x5b\x0d\x9a\x26\x93\x9b",
-		.rlen	= 8,
-	}, { /* Three blocks */
-		.key	= "\x01\x23\x45\x67\x89\xab\xcd\xef",
-		.klen	= 8,
-		.input	= "\x01\x23\x45\x67\x89\xab\xcd\xe7"
-			  "\x22\x33\x44\x55\x66\x77\x88\x99"
-			  "\xca\xfe\xba\xbe\xfe\xed\xbe\xef",
-		.ilen	= 24,
-		.result	= "\xc9\x57\x44\x25\x6a\x5e\xd3\x1d"
-			  "\xf7\x9c\x89\x2a\x33\x8f\x4a\x8b"
-			  "\xb4\x99\x26\xf7\x1f\xe1\xd4\x90",
-		.rlen	= 24,
-	}, { /* Weak key */
-		.fail	= 1,
-		.wk	= 1,
-		.key	= "\x01\x01\x01\x01\x01\x01\x01\x01",
-		.klen	= 8,
-		.input	= "\x01\x23\x45\x67\x89\xab\xcd\xe7",
-		.ilen	= 8,
-		.result	= "\xc9\x57\x44\x25\x6a\x5e\xd3\x1d",
-		.rlen	= 8,
-	}, { /* Two blocks -- for testing encryption across pages */
-		.key	= "\x01\x23\x45\x67\x89\xab\xcd\xef",
-		.klen	= 8,
-		.input	= "\x01\x23\x45\x67\x89\xab\xcd\xe7"
-			  "\x22\x33\x44\x55\x66\x77\x88\x99",
-		.ilen	= 16,
-		.result	= "\xc9\x57\x44\x25\x6a\x5e\xd3\x1d"
-			  "\xf7\x9c\x89\x2a\x33\x8f\x4a\x8b",
-		.rlen	= 16,
-		.np	= 2,
-		.tap	= { 8, 8 }
-	}, { /* Four blocks -- for testing encryption with chunking */
-		.key	= "\x01\x23\x45\x67\x89\xab\xcd\xef",
-		.klen	= 8,
-		.input	= "\x01\x23\x45\x67\x89\xab\xcd\xe7"
-			  "\x22\x33\x44\x55\x66\x77\x88\x99"
-			  "\xca\xfe\xba\xbe\xfe\xed\xbe\xef"
-			  "\x22\x33\x44\x55\x66\x77\x88\x99",
-		.ilen	= 32,
-		.result	= "\xc9\x57\x44\x25\x6a\x5e\xd3\x1d"
-			  "\xf7\x9c\x89\x2a\x33\x8f\x4a\x8b"
-			  "\xb4\x99\x26\xf7\x1f\xe1\xd4\x90"
-			  "\xf7\x9c\x89\x2a\x33\x8f\x4a\x8b",
-		.rlen	= 32,
-		.np	= 3,
-		.tap	= { 14, 10, 8 }
-	}, {
-		.key	= "\x01\x23\x45\x67\x89\xab\xcd\xef",
-		.klen	= 8,
-		.input	= "\x01\x23\x45\x67\x89\xab\xcd\xe7"
-			  "\x22\x33\x44\x55\x66\x77\x88\x99"
-			  "\xca\xfe\xba\xbe\xfe\xed\xbe\xef",
-		.ilen	= 24,
-		.result	= "\xc9\x57\x44\x25\x6a\x5e\xd3\x1d"
-			  "\xf7\x9c\x89\x2a\x33\x8f\x4a\x8b"
-			  "\xb4\x99\x26\xf7\x1f\xe1\xd4\x90",
-		.rlen	= 24,
-		.np	= 4,
-		.tap	= { 2, 1, 3, 18 }
-	}, {
-		.key	= "\x01\x23\x45\x67\x89\xab\xcd\xef",
-		.klen	= 8,
-		.input	= "\x01\x23\x45\x67\x89\xab\xcd\xe7"
-			  "\x22\x33\x44\x55\x66\x77\x88\x99",
-		.ilen	= 16,
-		.result	= "\xc9\x57\x44\x25\x6a\x5e\xd3\x1d"
-			  "\xf7\x9c\x89\x2a\x33\x8f\x4a\x8b",
-		.rlen	= 16,
-		.np	= 5,
-		.tap	= { 2, 2, 2, 2, 8 }
-	}, {
-		.key	= "\x01\x23\x45\x67\x89\xab\xcd\xef",
-		.klen	= 8,
-		.input	= "\x01\x23\x45\x67\x89\xab\xcd\xe7",
-		.ilen	= 8,
-		.result	= "\xc9\x57\x44\x25\x6a\x5e\xd3\x1d",
-		.rlen	= 8,
-		.np	= 8,
-		.tap	= { 1, 1, 1, 1, 1, 1, 1, 1 }
-	},
-};
-
-static struct cipher_testvec des_dec_tv_template[] = {
-	{ /* From Applied Cryptography */
-		.key	= "\x01\x23\x45\x67\x89\xab\xcd\xef",
-		.klen	= 8,
-		.input	= "\xc9\x57\x44\x25\x6a\x5e\xd3\x1d",
-		.ilen	= 8,
-		.result	= "\x01\x23\x45\x67\x89\xab\xcd\xe7",
-		.rlen	= 8,
-	}, { /* Sbox test from NBS */
-		.key	= "\x7c\xa1\x10\x45\x4a\x1a\x6e\x57",
-		.klen	= 8,
-		.input	= "\x69\x0f\x5b\x0d\x9a\x26\x93\x9b",
-		.ilen	= 8,
-		.result	= "\x01\xa1\xd6\xd0\x39\x77\x67\x42",
-		.rlen	= 8,
-	}, { /* Two blocks, for chunking test */
-		.key	= "\x01\x23\x45\x67\x89\xab\xcd\xef",
-		.klen	= 8,
-		.input	= "\xc9\x57\x44\x25\x6a\x5e\xd3\x1d"
-			  "\x69\x0f\x5b\x0d\x9a\x26\x93\x9b",
-		.ilen	= 16,
-		.result	= "\x01\x23\x45\x67\x89\xab\xcd\xe7"
-			  "\xa3\x99\x7b\xca\xaf\x69\xa0\xf5",
-		.rlen	= 16,
-		.np	= 2,
-		.tap	= { 8, 8 }
-	}, {
-		.key	= "\x01\x23\x45\x67\x89\xab\xcd\xef",
-		.klen	= 8,
-		.input	= "\xc9\x57\x44\x25\x6a\x5e\xd3\x1d"
-			  "\x69\x0f\x5b\x0d\x9a\x26\x93\x9b",
-		.ilen	= 16,
-		.result	= "\x01\x23\x45\x67\x89\xab\xcd\xe7"
-			  "\xa3\x99\x7b\xca\xaf\x69\xa0\xf5",
-		.rlen	= 16,
-		.np	= 3,
-		.tap	= { 3, 12, 1 }
-	},
-};
-
-static struct cipher_testvec des_cbc_enc_tv_template[] = {
-	{ /* From OpenSSL */
-		.key	= "\x01\x23\x45\x67\x89\xab\xcd\xef",
-		.klen	= 8,
-		.iv	= "\xfe\xdc\xba\x98\x76\x54\x32\x10",
-		.input	= "\x37\x36\x35\x34\x33\x32\x31\x20"
-			  "\x4e\x6f\x77\x20\x69\x73\x20\x74"
-			  "\x68\x65\x20\x74\x69\x6d\x65\x20",
-		.ilen	= 24,
-		.result	= "\xcc\xd1\x73\xff\xab\x20\x39\xf4"
-			  "\xac\xd8\xae\xfd\xdf\xd8\xa1\xeb"
-			  "\x46\x8e\x91\x15\x78\x88\xba\x68",
-		.rlen	= 24,
-	}, { /* FIPS Pub 81 */
-		.key	= "\x01\x23\x45\x67\x89\xab\xcd\xef",
-		.klen	= 8,
-		.iv	= "\x12\x34\x56\x78\x90\xab\xcd\xef",
-		.input	= "\x4e\x6f\x77\x20\x69\x73\x20\x74",
-		.ilen	= 8,
-		.result	= "\xe5\xc7\xcd\xde\x87\x2b\xf2\x7c",
-		.rlen	= 8,
-	}, {
-		.key	= "\x01\x23\x45\x67\x89\xab\xcd\xef",
-		.klen	= 8,
-		.iv	= "\xe5\xc7\xcd\xde\x87\x2b\xf2\x7c",
-		.input	= "\x68\x65\x20\x74\x69\x6d\x65\x20",
-		.ilen	= 8,
-		.result	= "\x43\xe9\x34\x00\x8c\x38\x9c\x0f",
-		.rlen	= 8,
-	}, {
-		.key	= "\x01\x23\x45\x67\x89\xab\xcd\xef",
-		.klen	= 8,
-		.iv	= "\x43\xe9\x34\x00\x8c\x38\x9c\x0f",
-		.input	= "\x66\x6f\x72\x20\x61\x6c\x6c\x20",
-		.ilen	= 8,
-		.result	= "\x68\x37\x88\x49\x9a\x7c\x05\xf6",
-		.rlen	= 8,
-	}, { /* Copy of openssl vector for chunk testing */
-	     /* From OpenSSL */
-		.key	= "\x01\x23\x45\x67\x89\xab\xcd\xef",
-		.klen	= 8,
-		.iv	= "\xfe\xdc\xba\x98\x76\x54\x32\x10",
-		.input	= "\x37\x36\x35\x34\x33\x32\x31\x20"
-			  "\x4e\x6f\x77\x20\x69\x73\x20\x74"
-			  "\x68\x65\x20\x74\x69\x6d\x65\x20",
-		.ilen	= 24,
-		.result	= "\xcc\xd1\x73\xff\xab\x20\x39\xf4"
-			  "\xac\xd8\xae\xfd\xdf\xd8\xa1\xeb"
-			  "\x46\x8e\x91\x15\x78\x88\xba\x68",
-		.rlen	= 24,
-		.np	= 2,
-		.tap	= { 13, 11 }
-	},
-};
-
-static struct cipher_testvec des_cbc_dec_tv_template[] = {
-	{ /* FIPS Pub 81 */
-		.key	= "\x01\x23\x45\x67\x89\xab\xcd\xef",
-		.klen	= 8,
-		.iv	= "\x12\x34\x56\x78\x90\xab\xcd\xef",
-		.input	= "\xe5\xc7\xcd\xde\x87\x2b\xf2\x7c",
-		.ilen	= 8,
-		.result	= "\x4e\x6f\x77\x20\x69\x73\x20\x74",
-		.rlen	= 8,
-	}, {
-		.key	= "\x01\x23\x45\x67\x89\xab\xcd\xef",
-		.klen	= 8,
-		.iv	= "\xe5\xc7\xcd\xde\x87\x2b\xf2\x7c",
-		.input	= "\x43\xe9\x34\x00\x8c\x38\x9c\x0f",
-		.ilen	= 8,
-		.result	= "\x68\x65\x20\x74\x69\x6d\x65\x20",
-		.rlen	= 8,
-	}, {
-		.key	= "\x01\x23\x45\x67\x89\xab\xcd\xef",
-		.klen	= 8,
-		.iv	= "\x43\xe9\x34\x00\x8c\x38\x9c\x0f",
-		.input	= "\x68\x37\x88\x49\x9a\x7c\x05\xf6",
-		.ilen	= 8,
-		.result	= "\x66\x6f\x72\x20\x61\x6c\x6c\x20",
-		.rlen	= 8,
-	}, { /* Copy of above, for chunk testing */
-		.key	= "\x01\x23\x45\x67\x89\xab\xcd\xef",
-		.klen	= 8,
-		.iv	= "\x43\xe9\x34\x00\x8c\x38\x9c\x0f",
-		.input	= "\x68\x37\x88\x49\x9a\x7c\x05\xf6",
-		.ilen	= 8,
-		.result	= "\x66\x6f\x72\x20\x61\x6c\x6c\x20",
-		.rlen	= 8,
-		.np	= 2,
-		.tap	= { 4, 4 }
-	},
-};
-
-static struct cipher_testvec des3_ede_enc_tv_template[] = {
-	{ /* These are from openssl */
+static struct cipher_speed_template des3_speed_template[] = {
+	{
 		.key	= "\x01\x23\x45\x67\x89\xab\xcd\xef"
 			  "\x55\x55\x55\x55\x55\x55\x55\x55"
 			  "\xfe\xdc\xba\x98\x76\x54\x32\x10",
 		.klen	= 24,
-		.input	= "\x73\x6f\x6d\x65\x64\x61\x74\x61",
-		.ilen	= 8,
-		.result	= "\x18\xd7\x48\xe5\x63\x62\x05\x72",
-		.rlen	= 8,
-	}, {
-		.key	= "\x03\x52\x02\x07\x67\x20\x82\x17"
-			  "\x86\x02\x87\x66\x59\x08\x21\x98"
-			  "\x64\x05\x6a\xbd\xfe\xa9\x34\x57",
-		.klen	= 24,
-		.input	= "\x73\x71\x75\x69\x67\x67\x6c\x65",
-		.ilen	= 8,
-		.result	= "\xc0\x7d\x2a\x0f\xa5\x66\xfa\x30",
-		.rlen	= 8,
-	}, {
-		.key	= "\x10\x46\x10\x34\x89\x98\x80\x20"
-			  "\x91\x07\xd0\x15\x89\x19\x01\x01"
-			  "\x19\x07\x92\x10\x98\x1a\x01\x01",
-		.klen	= 24,
-		.input	= "\x00\x00\x00\x00\x00\x00\x00\x00",
-		.ilen	= 8,
-		.result	= "\xe1\xef\x62\xc3\x32\xfe\x82\x5b",
-		.rlen	= 8,
-	},
-};
-
-static struct cipher_testvec des3_ede_dec_tv_template[] = {
-	{ /* These are from openssl */
-		.key	= "\x01\x23\x45\x67\x89\xab\xcd\xef"
-			  "\x55\x55\x55\x55\x55\x55\x55\x55"
-			  "\xfe\xdc\xba\x98\x76\x54\x32\x10",
-		.klen	= 24,
-		.input	= "\x18\xd7\x48\xe5\x63\x62\x05\x72",
-		.ilen	= 8,
-		.result	= "\x73\x6f\x6d\x65\x64\x61\x74\x61",
-		.rlen	= 8,
-	}, {
-		.key	= "\x03\x52\x02\x07\x67\x20\x82\x17"
-			  "\x86\x02\x87\x66\x59\x08\x21\x98"
-			  "\x64\x05\x6a\xbd\xfe\xa9\x34\x57",
-		.klen	= 24,
-		.input	= "\xc0\x7d\x2a\x0f\xa5\x66\xfa\x30",
-		.ilen	= 8,
-		.result	= "\x73\x71\x75\x69\x67\x67\x6c\x65",
-		.rlen	= 8,
-	}, {
-		.key	= "\x10\x46\x10\x34\x89\x98\x80\x20"
-			  "\x91\x07\xd0\x15\x89\x19\x01\x01"
-			  "\x19\x07\x92\x10\x98\x1a\x01\x01",
-		.klen	= 24,
-		.input	= "\xe1\xef\x62\xc3\x32\xfe\x82\x5b",
-		.ilen	= 8,
-		.result	= "\x00\x00\x00\x00\x00\x00\x00\x00",
-		.rlen	= 8,
-	},
-};
-
-static struct cipher_testvec des3_ede_cbc_enc_tv_template[] = {
-	{ /* Generated from openssl */
-		.key	= "\xE9\xC0\xFF\x2E\x76\x0B\x64\x24"
-			  "\x44\x4D\x99\x5A\x12\xD6\x40\xC0"
-			  "\xEA\xC2\x84\xE8\x14\x95\xDB\xE8",
-		.klen	= 24,
-		.iv	= "\x7D\x33\x88\x93\x0F\x93\xB2\x42",
-		.input	= "\x6f\x54\x20\x6f\x61\x4d\x79\x6e"
-			  "\x53\x20\x63\x65\x65\x72\x73\x74"
-			  "\x54\x20\x6f\x6f\x4d\x20\x6e\x61"
-			  "\x20\x79\x65\x53\x72\x63\x74\x65"
-			  "\x20\x73\x6f\x54\x20\x6f\x61\x4d"
-			  "\x79\x6e\x53\x20\x63\x65\x65\x72"
-			  "\x73\x74\x54\x20\x6f\x6f\x4d\x20"
-			  "\x6e\x61\x20\x79\x65\x53\x72\x63"
-			  "\x74\x65\x20\x73\x6f\x54\x20\x6f"
-			  "\x61\x4d\x79\x6e\x53\x20\x63\x65"
-			  "\x65\x72\x73\x74\x54\x20\x6f\x6f"
-			  "\x4d\x20\x6e\x61\x20\x79\x65\x53"
-			  "\x72\x63\x74\x65\x20\x73\x6f\x54"
-			  "\x20\x6f\x61\x4d\x79\x6e\x53\x20"
-			  "\x63\x65\x65\x72\x73\x74\x54\x20"
-			  "\x6f\x6f\x4d\x20\x6e\x61\x0a\x79",
-		.ilen	= 128,
-		.result	= "\x0e\x2d\xb6\x97\x3c\x56\x33\xf4"
-			  "\x67\x17\x21\xc7\x6e\x8a\xd5\x49"
-			  "\x74\xb3\x49\x05\xc5\x1c\xd0\xed"
-			  "\x12\x56\x5c\x53\x96\xb6\x00\x7d"
-			  "\x90\x48\xfc\xf5\x8d\x29\x39\xcc"
-			  "\x8a\xd5\x35\x18\x36\x23\x4e\xd7"
-			  "\x76\xd1\xda\x0c\x94\x67\xbb\x04"
-			  "\x8b\xf2\x03\x6c\xa8\xcf\xb6\xea"
-			  "\x22\x64\x47\xaa\x8f\x75\x13\xbf"
-			  "\x9f\xc2\xc3\xf0\xc9\x56\xc5\x7a"
-			  "\x71\x63\x2e\x89\x7b\x1e\x12\xca"
-			  "\xe2\x5f\xaf\xd8\xa4\xf8\xc9\x7a"
-			  "\xd6\xf9\x21\x31\x62\x44\x45\xa6"
-			  "\xd6\xbc\x5a\xd3\x2d\x54\x43\xcc"
-			  "\x9d\xde\xa5\x70\xe9\x42\x45\x8a"
-			  "\x6b\xfa\xb1\x91\x13\xb0\xd9\x19",
-		.rlen	= 128,
-	},
-};
-
-static struct cipher_testvec des3_ede_cbc_dec_tv_template[] = {
-	{ /* Generated from openssl */
-		.key	= "\xE9\xC0\xFF\x2E\x76\x0B\x64\x24"
-			  "\x44\x4D\x99\x5A\x12\xD6\x40\xC0"
-			  "\xEA\xC2\x84\xE8\x14\x95\xDB\xE8",
-		.klen	= 24,
-		.iv	= "\x7D\x33\x88\x93\x0F\x93\xB2\x42",
-		.input	= "\x0e\x2d\xb6\x97\x3c\x56\x33\xf4"
-			  "\x67\x17\x21\xc7\x6e\x8a\xd5\x49"
-			  "\x74\xb3\x49\x05\xc5\x1c\xd0\xed"
-			  "\x12\x56\x5c\x53\x96\xb6\x00\x7d"
-			  "\x90\x48\xfc\xf5\x8d\x29\x39\xcc"
-			  "\x8a\xd5\x35\x18\x36\x23\x4e\xd7"
-			  "\x76\xd1\xda\x0c\x94\x67\xbb\x04"
-			  "\x8b\xf2\x03\x6c\xa8\xcf\xb6\xea"
-			  "\x22\x64\x47\xaa\x8f\x75\x13\xbf"
-			  "\x9f\xc2\xc3\xf0\xc9\x56\xc5\x7a"
-			  "\x71\x63\x2e\x89\x7b\x1e\x12\xca"
-			  "\xe2\x5f\xaf\xd8\xa4\xf8\xc9\x7a"
-			  "\xd6\xf9\x21\x31\x62\x44\x45\xa6"
-			  "\xd6\xbc\x5a\xd3\x2d\x54\x43\xcc"
-			  "\x9d\xde\xa5\x70\xe9\x42\x45\x8a"
-			  "\x6b\xfa\xb1\x91\x13\xb0\xd9\x19",
-		.ilen	= 128,
-		.result	= "\x6f\x54\x20\x6f\x61\x4d\x79\x6e"
-			  "\x53\x20\x63\x65\x65\x72\x73\x74"
-			  "\x54\x20\x6f\x6f\x4d\x20\x6e\x61"
-			  "\x20\x79\x65\x53\x72\x63\x74\x65"
-			  "\x20\x73\x6f\x54\x20\x6f\x61\x4d"
-			  "\x79\x6e\x53\x20\x63\x65\x65\x72"
-			  "\x73\x74\x54\x20\x6f\x6f\x4d\x20"
-			  "\x6e\x61\x20\x79\x65\x53\x72\x63"
-			  "\x74\x65\x20\x73\x6f\x54\x20\x6f"
-			  "\x61\x4d\x79\x6e\x53\x20\x63\x65"
-			  "\x65\x72\x73\x74\x54\x20\x6f\x6f"
-			  "\x4d\x20\x6e\x61\x20\x79\x65\x53"
-			  "\x72\x63\x74\x65\x20\x73\x6f\x54"
-			  "\x20\x6f\x61\x4d\x79\x6e\x53\x20"
-			  "\x63\x65\x65\x72\x73\x74\x54\x20"
-			  "\x6f\x6f\x4d\x20\x6e\x61\x0a\x79",
-		.rlen	= 128,
-	},
-};
-
-/*
- * Blowfish test vectors.
- */
-#define BF_ENC_TEST_VECTORS	6
-#define BF_DEC_TEST_VECTORS	6
-#define BF_CBC_ENC_TEST_VECTORS	1
-#define BF_CBC_DEC_TEST_VECTORS	1
-
-static struct cipher_testvec bf_enc_tv_template[] = {
-	{ /* DES test vectors from OpenSSL */
-		.key	= "\x00\x00\x00\x00\x00\x00\x00\x00",
-		.klen	= 8,
-		.input	= "\x00\x00\x00\x00\x00\x00\x00\x00",
-		.ilen	= 8,
-		.result	= "\x4e\xf9\x97\x45\x61\x98\xdd\x78",
-		.rlen	= 8,
-	}, {
-		.key	= "\x1f\x1f\x1f\x1f\x0e\x0e\x0e\x0e",
-		.klen	= 8,
-		.input	= "\x01\x23\x45\x67\x89\xab\xcd\xef",
-		.ilen	= 8,
-		.result	= "\xa7\x90\x79\x51\x08\xea\x3c\xae",
-		.rlen	= 8,
-	}, {
-		.key	= "\xf0\xe1\xd2\xc3\xb4\xa5\x96\x87",
-		.klen	= 8,
-		.input	= "\xfe\xdc\xba\x98\x76\x54\x32\x10",
-		.ilen	= 8,
-		.result	= "\xe8\x7a\x24\x4e\x2c\xc8\x5e\x82",
-		.rlen	= 8,
-	}, { /* Vary the keylength... */
-		.key	= "\xf0\xe1\xd2\xc3\xb4\xa5\x96\x87"
-			  "\x78\x69\x5a\x4b\x3c\x2d\x1e\x0f",
-		.klen	= 16,
-		.input	= "\xfe\xdc\xba\x98\x76\x54\x32\x10",
-		.ilen	= 8,
-		.result	= "\x93\x14\x28\x87\xee\x3b\xe1\x5c",
-		.rlen	= 8,
-	}, {
-		.key	= "\xf0\xe1\xd2\xc3\xb4\xa5\x96\x87"
-			  "\x78\x69\x5a\x4b\x3c\x2d\x1e\x0f"
-			  "\x00\x11\x22\x33\x44",
-		.klen	= 21,
-		.input	= "\xfe\xdc\xba\x98\x76\x54\x32\x10",
-		.ilen	= 8,
-		.result	= "\xe6\xf5\x1e\xd7\x9b\x9d\xb2\x1f",
-		.rlen	= 8,
-	}, { /* Generated with bf488 */
-		.key	= "\xf0\xe1\xd2\xc3\xb4\xa5\x96\x87"
-			  "\x78\x69\x5a\x4b\x3c\x2d\x1e\x0f"
-			  "\x00\x11\x22\x33\x44\x55\x66\x77"
-			  "\x04\x68\x91\x04\xc2\xfd\x3b\x2f"
-			  "\x58\x40\x23\x64\x1a\xba\x61\x76"
-			  "\x1f\x1f\x1f\x1f\x0e\x0e\x0e\x0e"
-			  "\xff\xff\xff\xff\xff\xff\xff\xff",
-		.klen	= 56,
-		.input	= "\xfe\xdc\xba\x98\x76\x54\x32\x10",
-		.ilen	= 8,
-		.result	= "\xc0\x45\x04\x01\x2e\x4e\x1f\x53",
-		.rlen	= 8,
-	},
-};
-
-static struct cipher_testvec bf_dec_tv_template[] = {
-	{ /* DES test vectors from OpenSSL */
-		.key	= "\x00\x00\x00\x00\x00\x00\x00\x00",
-		.klen	= 8,
-		.input	= "\x4e\xf9\x97\x45\x61\x98\xdd\x78",
-		.ilen	= 8,
-		.result	= "\x00\x00\x00\x00\x00\x00\x00\x00",
-		.rlen	= 8,
-	}, {
-		.key	= "\x1f\x1f\x1f\x1f\x0e\x0e\x0e\x0e",
-		.klen	= 8,
-		.input	= "\xa7\x90\x79\x51\x08\xea\x3c\xae",
-		.ilen	= 8,
-		.result	= "\x01\x23\x45\x67\x89\xab\xcd\xef",
-		.rlen	= 8,
-	}, {
-		.key	= "\xf0\xe1\xd2\xc3\xb4\xa5\x96\x87",
-		.klen	= 8,
-		.input	= "\xe8\x7a\x24\x4e\x2c\xc8\x5e\x82",
-		.ilen	= 8,
-		.result	= "\xfe\xdc\xba\x98\x76\x54\x32\x10",
-		.rlen	= 8,
-	}, { /* Vary the keylength... */
-		.key	= "\xf0\xe1\xd2\xc3\xb4\xa5\x96\x87"
-			  "\x78\x69\x5a\x4b\x3c\x2d\x1e\x0f",
-		.klen	= 16,
-		.input	= "\x93\x14\x28\x87\xee\x3b\xe1\x5c",
-		.ilen	= 8,
-		.result	= "\xfe\xdc\xba\x98\x76\x54\x32\x10",
-		.rlen	= 8,
-	}, {
-		.key	= "\xf0\xe1\xd2\xc3\xb4\xa5\x96\x87"
-			  "\x78\x69\x5a\x4b\x3c\x2d\x1e\x0f"
-			  "\x00\x11\x22\x33\x44",
-		.klen	= 21,
-		.input	= "\xe6\xf5\x1e\xd7\x9b\x9d\xb2\x1f",
-		.ilen	= 8,
-		.result	= "\xfe\xdc\xba\x98\x76\x54\x32\x10",
-		.rlen	= 8,
-	}, { /* Generated with bf488, using OpenSSL, Libgcrypt and Nettle */
-		.key	= "\xf0\xe1\xd2\xc3\xb4\xa5\x96\x87"
-			  "\x78\x69\x5a\x4b\x3c\x2d\x1e\x0f"
-			  "\x00\x11\x22\x33\x44\x55\x66\x77"
-			  "\x04\x68\x91\x04\xc2\xfd\x3b\x2f"
-			  "\x58\x40\x23\x64\x1a\xba\x61\x76"
-			  "\x1f\x1f\x1f\x1f\x0e\x0e\x0e\x0e"
-			  "\xff\xff\xff\xff\xff\xff\xff\xff",
-		.klen	= 56,
-		.input	= "\xc0\x45\x04\x01\x2e\x4e\x1f\x53",
-		.ilen	= 8,
-		.result	= "\xfe\xdc\xba\x98\x76\x54\x32\x10",
-		.rlen	= 8,
-	},
-};
-
-static struct cipher_testvec bf_cbc_enc_tv_template[] = {
-	{ /* From OpenSSL */
-		.key	= "\x01\x23\x45\x67\x89\xab\xcd\xef"
-			  "\xf0\xe1\xd2\xc3\xb4\xa5\x96\x87",
-		.klen	= 16,
-		.iv	= "\xfe\xdc\xba\x98\x76\x54\x32\x10",
-		.input	= "\x37\x36\x35\x34\x33\x32\x31\x20"
-			  "\x4e\x6f\x77\x20\x69\x73\x20\x74"
-			  "\x68\x65\x20\x74\x69\x6d\x65\x20"
-			  "\x66\x6f\x72\x20\x00\x00\x00\x00",
-		.ilen	= 32,
-		.result	= "\x6b\x77\xb4\xd6\x30\x06\xde\xe6"
-			  "\x05\xb1\x56\xe2\x74\x03\x97\x93"
-			  "\x58\xde\xb9\xe7\x15\x46\x16\xd9"
-			  "\x59\xf1\x65\x2b\xd5\xff\x92\xcc",
-		.rlen	= 32,
-	},
-};
-
-static struct cipher_testvec bf_cbc_dec_tv_template[] = {
-	{ /* From OpenSSL */
-		.key	= "\x01\x23\x45\x67\x89\xab\xcd\xef"
-			  "\xf0\xe1\xd2\xc3\xb4\xa5\x96\x87",
-		.klen	= 16,
-		.iv	= "\xfe\xdc\xba\x98\x76\x54\x32\x10",
-		.input	= "\x6b\x77\xb4\xd6\x30\x06\xde\xe6"
-			  "\x05\xb1\x56\xe2\x74\x03\x97\x93"
-			  "\x58\xde\xb9\xe7\x15\x46\x16\xd9"
-			  "\x59\xf1\x65\x2b\xd5\xff\x92\xcc",
-		.ilen	= 32,
-		.result	= "\x37\x36\x35\x34\x33\x32\x31\x20"
-			  "\x4e\x6f\x77\x20\x69\x73\x20\x74"
-			  "\x68\x65\x20\x74\x69\x6d\x65\x20"
-			  "\x66\x6f\x72\x20\x00\x00\x00\x00",
-		.rlen	= 32,
-	},
-};
-
-/*
- * Twofish test vectors.
- */
-#define TF_ENC_TEST_VECTORS		3
-#define TF_DEC_TEST_VECTORS		3
-#define TF_CBC_ENC_TEST_VECTORS		4
-#define TF_CBC_DEC_TEST_VECTORS		4
-
-static struct cipher_testvec tf_enc_tv_template[] = {
-	{
-		.key	= zeroed_string,
-		.klen	= 16,
-		.input	= zeroed_string,
-		.ilen	= 16,
-		.result	= "\x9f\x58\x9f\x5c\xf6\x12\x2c\x32"
-			  "\xb6\xbf\xec\x2f\x2a\xe8\xc3\x5a",
-		.rlen	= 16,
-	}, {
-		.key	= "\x01\x23\x45\x67\x89\xab\xcd\xef"
-			  "\xfe\xdc\xba\x98\x76\x54\x32\x10"
-			  "\x00\x11\x22\x33\x44\x55\x66\x77",
-		.klen	= 24,
-		.input	= zeroed_string,
-		.ilen	= 16,
-		.result	= "\xcf\xd1\xd2\xe5\xa9\xbe\x9c\xdf"
-			  "\x50\x1f\x13\xb8\x92\xbd\x22\x48",
-		.rlen	= 16,
-	}, {
-		.key	= "\x01\x23\x45\x67\x89\xab\xcd\xef"
-			  "\xfe\xdc\xba\x98\x76\x54\x32\x10"
-			  "\x00\x11\x22\x33\x44\x55\x66\x77"
-			  "\x88\x99\xaa\xbb\xcc\xdd\xee\xff",
-		.klen	= 32,
-		.input	= zeroed_string,
-		.ilen	= 16,
-		.result	= "\x37\x52\x7b\xe0\x05\x23\x34\xb8"
-			  "\x9f\x0c\xfc\xca\xe8\x7c\xfa\x20",
-		.rlen	= 16,
-	},
-};
-
-static struct cipher_testvec tf_dec_tv_template[] = {
-	{
-		.key	= zeroed_string,
-		.klen	= 16,
-		.input	= "\x9f\x58\x9f\x5c\xf6\x12\x2c\x32"
-			  "\xb6\xbf\xec\x2f\x2a\xe8\xc3\x5a",
-		.ilen	= 16,
-		.result	= zeroed_string,
-		.rlen	= 16,
-	}, {
-		.key	= "\x01\x23\x45\x67\x89\xab\xcd\xef"
-			  "\xfe\xdc\xba\x98\x76\x54\x32\x10"
-			  "\x00\x11\x22\x33\x44\x55\x66\x77",
-		.klen	= 24,
-		.input	= "\xcf\xd1\xd2\xe5\xa9\xbe\x9c\xdf"
-			  "\x50\x1f\x13\xb8\x92\xbd\x22\x48",
-		.ilen	= 16,
-		.result	= zeroed_string,
-		.rlen	= 16,
-	}, {
-		.key	= "\x01\x23\x45\x67\x89\xab\xcd\xef"
-			  "\xfe\xdc\xba\x98\x76\x54\x32\x10"
-			  "\x00\x11\x22\x33\x44\x55\x66\x77"
-			  "\x88\x99\xaa\xbb\xcc\xdd\xee\xff",
-		.klen	= 32,
-		.input	= "\x37\x52\x7b\xe0\x05\x23\x34\xb8"
-			  "\x9f\x0c\xfc\xca\xe8\x7c\xfa\x20",
-		.ilen	= 16,
-		.result	= zeroed_string,
-		.rlen	= 16,
-	},
-};
-
-static struct cipher_testvec tf_cbc_enc_tv_template[] = {
-	{ /* Generated with Nettle */
-		.key	= zeroed_string,
-		.klen	= 16,
-		.iv	= zeroed_string,
-		.input	= zeroed_string,
-		.ilen	= 16,
-		.result	= "\x9f\x58\x9f\x5c\xf6\x12\x2c\x32"
-			  "\xb6\xbf\xec\x2f\x2a\xe8\xc3\x5a",
-		.rlen	= 16,
-	}, {
-		.key	= zeroed_string,
-		.klen	= 16,
-		.iv	= "\x9f\x58\x9f\x5c\xf6\x12\x2c\x32"
-			  "\xb6\xbf\xec\x2f\x2a\xe8\xc3\x5a",
-		.input	= zeroed_string,
-		.ilen	= 16,
-		.result	= "\xd4\x91\xdb\x16\xe7\xb1\xc3\x9e"
-			  "\x86\xcb\x08\x6b\x78\x9f\x54\x19",
-		.rlen	= 16,
-	}, {
-		.key	= zeroed_string,
-		.klen	= 16,
-		.iv	= "\xd4\x91\xdb\x16\xe7\xb1\xc3\x9e"
-			  "\x86\xcb\x08\x6b\x78\x9f\x54\x19",
-		.input	= zeroed_string,
-		.ilen	= 16,
-		.result	= "\x05\xef\x8c\x61\xa8\x11\x58\x26"
-			  "\x34\xba\x5c\xb7\x10\x6a\xa6\x41",
-		.rlen	= 16,
-	}, {
-		.key	= zeroed_string,
-		.klen	= 16,
-		.iv	= zeroed_string,
-		.input	= zeroed_string,
-		.ilen	= 48,
-		.result	= "\x9f\x58\x9f\x5c\xf6\x12\x2c\x32"
-			  "\xb6\xbf\xec\x2f\x2a\xe8\xc3\x5a"
-			  "\xd4\x91\xdb\x16\xe7\xb1\xc3\x9e"
-			  "\x86\xcb\x08\x6b\x78\x9f\x54\x19"
-			  "\x05\xef\x8c\x61\xa8\x11\x58\x26"
-			  "\x34\xba\x5c\xb7\x10\x6a\xa6\x41",
-		.rlen	= 48,
-	},
-};
-
-static struct cipher_testvec tf_cbc_dec_tv_template[] = {
-	{ /* Reverse of the first four above */
-		.key	= zeroed_string,
-		.klen	= 16,
-		.iv	= zeroed_string,
-		.input	= "\x9f\x58\x9f\x5c\xf6\x12\x2c\x32"
-			  "\xb6\xbf\xec\x2f\x2a\xe8\xc3\x5a",
-		.ilen	= 16,
-		.result	= zeroed_string,
-		.rlen	= 16,
-	}, {
-		.key	= zeroed_string,
-		.klen	= 16,
-		.iv	= "\x9f\x58\x9f\x5c\xf6\x12\x2c\x32"
-			  "\xb6\xbf\xec\x2f\x2a\xe8\xc3\x5a",
-		.input	= "\xd4\x91\xdb\x16\xe7\xb1\xc3\x9e"
-			  "\x86\xcb\x08\x6b\x78\x9f\x54\x19",
-		.ilen	= 16,
-		.result	= zeroed_string,
-		.rlen	= 16,
-	}, {
-		.key	= zeroed_string,
-		.klen	= 16,
-		.iv	= "\xd4\x91\xdb\x16\xe7\xb1\xc3\x9e"
-			  "\x86\xcb\x08\x6b\x78\x9f\x54\x19",
-		.input	= "\x05\xef\x8c\x61\xa8\x11\x58\x26"
-			  "\x34\xba\x5c\xb7\x10\x6a\xa6\x41",
-		.ilen	= 16,
-		.result	= zeroed_string,
-		.rlen	= 16,
-	}, {
-		.key	= zeroed_string,
-		.klen	= 16,
-		.iv	= zeroed_string,
-		.input	= "\x9f\x58\x9f\x5c\xf6\x12\x2c\x32"
-			  "\xb6\xbf\xec\x2f\x2a\xe8\xc3\x5a"
-			  "\xd4\x91\xdb\x16\xe7\xb1\xc3\x9e"
-			  "\x86\xcb\x08\x6b\x78\x9f\x54\x19"
-			  "\x05\xef\x8c\x61\xa8\x11\x58\x26"
-			  "\x34\xba\x5c\xb7\x10\x6a\xa6\x41",
-		.ilen	= 48,
-		.result	= zeroed_string,
-		.rlen	= 48,
-	},
-};
-
-/*
- * Serpent test vectors.  These are backwards because Serpent writes
- * octet sequences in right-to-left mode.
- */
-#define SERPENT_ENC_TEST_VECTORS	4
-#define SERPENT_DEC_TEST_VECTORS	4
-
-#define TNEPRES_ENC_TEST_VECTORS	4
-#define TNEPRES_DEC_TEST_VECTORS	4
-
-static struct cipher_testvec serpent_enc_tv_template[] = {
-	{
-		.input	= "\x00\x01\x02\x03\x04\x05\x06\x07"
-			  "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
-		.ilen	= 16,
-		.result	= "\x12\x07\xfc\xce\x9b\xd0\xd6\x47"
-			  "\x6a\xe9\x8f\xbe\xd1\x43\xa0\xe2",
-		.rlen	= 16,
-	}, {
-		.key	= "\x00\x01\x02\x03\x04\x05\x06\x07"
-			  "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
-		.klen	= 16,
-		.input	= "\x00\x01\x02\x03\x04\x05\x06\x07"
-			  "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
-		.ilen	= 16,
-		.result	= "\x4c\x7d\x8a\x32\x80\x72\xa2\x2c"
-			  "\x82\x3e\x4a\x1f\x3a\xcd\xa1\x6d",
-		.rlen	= 16,
-	}, {
-		.key	= "\x00\x01\x02\x03\x04\x05\x06\x07"
-			  "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
-			  "\x10\x11\x12\x13\x14\x15\x16\x17"
-			  "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f",
-		.klen	= 32,
-		.input	= "\x00\x01\x02\x03\x04\x05\x06\x07"
-			  "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
-		.ilen	= 16,
-		.result	= "\xde\x26\x9f\xf8\x33\xe4\x32\xb8"
-			  "\x5b\x2e\x88\xd2\x70\x1c\xe7\x5c",
-		.rlen	= 16,
-	}, {
-		.key	= "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80",
-		.klen	= 16,
-		.input	= zeroed_string,
-		.ilen	= 16,
-		.result	= "\xdd\xd2\x6b\x98\xa5\xff\xd8\x2c"
-			  "\x05\x34\x5a\x9d\xad\xbf\xaf\x49",
-		.rlen	= 16,
-	},
-};
-
-static struct cipher_testvec tnepres_enc_tv_template[] = {
-	{ /* KeySize=128, PT=0, I=1 */
-		.input	= "\x00\x00\x00\x00\x00\x00\x00\x00"
-			  "\x00\x00\x00\x00\x00\x00\x00\x00",
-		.key    = "\x80\x00\x00\x00\x00\x00\x00\x00"
-			  "\x00\x00\x00\x00\x00\x00\x00\x00",
-		.klen   = 16,
-		.ilen	= 16,
-		.result	= "\x49\xaf\xbf\xad\x9d\x5a\x34\x05"
-			  "\x2c\xd8\xff\xa5\x98\x6b\xd2\xdd",
-		.rlen	= 16,
-	}, { /* KeySize=192, PT=0, I=1 */
-		.key	= "\x80\x00\x00\x00\x00\x00\x00\x00"
-			  "\x00\x00\x00\x00\x00\x00\x00\x00"
-			  "\x00\x00\x00\x00\x00\x00\x00\x00",
-		.klen	= 24,
-		.input	= "\x00\x00\x00\x00\x00\x00\x00\x00"
-			  "\x00\x00\x00\x00\x00\x00\x00\x00",
-		.ilen	= 16,
-		.result	= "\xe7\x8e\x54\x02\xc7\x19\x55\x68"
-			  "\xac\x36\x78\xf7\xa3\xf6\x0c\x66",
-		.rlen	= 16,
-	}, { /* KeySize=256, PT=0, I=1 */
-		.key	= "\x80\x00\x00\x00\x00\x00\x00\x00"
-			  "\x00\x00\x00\x00\x00\x00\x00\x00"
-			  "\x00\x00\x00\x00\x00\x00\x00\x00"
-			  "\x00\x00\x00\x00\x00\x00\x00\x00",
-		.klen	= 32,
-		.input	= "\x00\x00\x00\x00\x00\x00\x00\x00"
-			  "\x00\x00\x00\x00\x00\x00\x00\x00",
-		.ilen	= 16,
-		.result	= "\xab\xed\x96\xe7\x66\xbf\x28\xcb"
-			  "\xc0\xeb\xd2\x1a\x82\xef\x08\x19",
-		.rlen	= 16,
-	}, { /* KeySize=256, I=257 */
-		.key	= "\x1f\x1e\x1d\x1c\x1b\x1a\x19\x18"
-			  "\x17\x16\x15\x14\x13\x12\x11\x10"
-			  "\x0f\x0e\x0d\x0c\x0b\x0a\x09\x08"
-			  "\x07\x06\x05\x04\x03\x02\x01\x00",
-		.klen	= 32,
-		.input	= "\x0f\x0e\x0d\x0c\x0b\x0a\x09\x08"
-			  "\x07\x06\x05\x04\x03\x02\x01\x00",
-		.ilen	= 16,
-		.result	= "\x5c\xe7\x1c\x70\xd2\x88\x2e\x5b"
-			  "\xb8\x32\xe4\x33\xf8\x9f\x26\xde",
-		.rlen	= 16,
-	},
-};
-
-
-static struct cipher_testvec serpent_dec_tv_template[] = {
-	{
-		.input	= "\x12\x07\xfc\xce\x9b\xd0\xd6\x47"
-			  "\x6a\xe9\x8f\xbe\xd1\x43\xa0\xe2",
-		.ilen	= 16,
-		.result	= "\x00\x01\x02\x03\x04\x05\x06\x07"
-			  "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
-		.rlen	= 16,
-	}, {
-		.key	= "\x00\x01\x02\x03\x04\x05\x06\x07"
-			  "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
-		.klen	= 16,
-		.input	= "\x4c\x7d\x8a\x32\x80\x72\xa2\x2c"
-			  "\x82\x3e\x4a\x1f\x3a\xcd\xa1\x6d",
-		.ilen	= 16,
-		.result	= "\x00\x01\x02\x03\x04\x05\x06\x07"
-			  "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
-		.rlen	= 16,
-	}, {
-		.key	= "\x00\x01\x02\x03\x04\x05\x06\x07"
-			  "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
-			  "\x10\x11\x12\x13\x14\x15\x16\x17"
-			  "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f",
-		.klen	= 32,
-		.input	= "\xde\x26\x9f\xf8\x33\xe4\x32\xb8"
-			  "\x5b\x2e\x88\xd2\x70\x1c\xe7\x5c",
-		.ilen	= 16,
-		.result	= "\x00\x01\x02\x03\x04\x05\x06\x07"
-			  "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
-		.rlen	= 16,
-	}, {
-		.key	= "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80",
-		.klen	= 16,
-		.input	= "\xdd\xd2\x6b\x98\xa5\xff\xd8\x2c"
-			  "\x05\x34\x5a\x9d\xad\xbf\xaf\x49",
-		.ilen	= 16,
-		.result	= zeroed_string,
-		.rlen	= 16,
-	},
-};
-
-static struct cipher_testvec tnepres_dec_tv_template[] = {
-	{
-		.input	= "\x41\xcc\x6b\x31\x59\x31\x45\x97"
-			  "\x6d\x6f\xbb\x38\x4b\x37\x21\x28",
-		.ilen	= 16,
-		.result	= "\x00\x01\x02\x03\x04\x05\x06\x07"
-			  "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
-		.rlen	= 16,
-	}, {
-		.key	= "\x00\x01\x02\x03\x04\x05\x06\x07"
-			  "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
-		.klen	= 16,
-		.input	= "\xea\xf4\xd7\xfc\xd8\x01\x34\x47"
-			  "\x81\x45\x0b\xfa\x0c\xd6\xad\x6e",
-		.ilen	= 16,
-		.result	= "\x00\x01\x02\x03\x04\x05\x06\x07"
-			  "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
-		.rlen	= 16,
-	}, {
-		.key	= "\x00\x01\x02\x03\x04\x05\x06\x07"
-			  "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
-			  "\x10\x11\x12\x13\x14\x15\x16\x17"
-			  "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f",
-		.klen	= 32,
-		.input	= "\x64\xa9\x1a\x37\xed\x9f\xe7\x49"
-			  "\xa8\x4e\x76\xd6\xf5\x0d\x78\xee",
-		.ilen	= 16,
-		.result	= "\x00\x01\x02\x03\x04\x05\x06\x07"
-			  "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
-		.rlen	= 16,
-	}, { /* KeySize=128, I=121 */
-		.key	= "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80",
-		.klen	= 16,
-		.input	= "\x3d\xda\xbf\xc0\x06\xda\xab\x06"
-			  "\x46\x2a\xf4\xef\x81\x54\x4e\x26",
-		.ilen	= 16,
-		.result	= zeroed_string,
-		.rlen	= 16,
-	},
-};
-
-
-/* Cast6 test vectors from RFC 2612 */
-#define CAST6_ENC_TEST_VECTORS	3
-#define CAST6_DEC_TEST_VECTORS  3
-
-static struct cipher_testvec cast6_enc_tv_template[] = {
-	{
-		.key	= "\x23\x42\xbb\x9e\xfa\x38\x54\x2c"
-			  "\x0a\xf7\x56\x47\xf2\x9f\x61\x5d",
-		.klen	= 16,
-		.input	= zeroed_string,
-		.ilen	= 16,
-		.result	= "\xc8\x42\xa0\x89\x72\xb4\x3d\x20"
-			  "\x83\x6c\x91\xd1\xb7\x53\x0f\x6b",
-		.rlen	= 16,
-	}, {
-		.key	= "\x23\x42\xbb\x9e\xfa\x38\x54\x2c"
-			  "\xbe\xd0\xac\x83\x94\x0a\xc2\x98"
-			  "\xba\xc7\x7a\x77\x17\x94\x28\x63",
-		.klen	= 24,
-		.input	= zeroed_string,
-		.ilen	= 16,
-		.result	= "\x1b\x38\x6c\x02\x10\xdc\xad\xcb"
-			  "\xdd\x0e\x41\xaa\x08\xa7\xa7\xe8",
-		.rlen	= 16,
-	}, {
-		.key	= "\x23\x42\xbb\x9e\xfa\x38\x54\x2c"
-			  "\xbe\xd0\xac\x83\x94\x0a\xc2\x98"
-			  "\x8d\x7c\x47\xce\x26\x49\x08\x46"
-			  "\x1c\xc1\xb5\x13\x7a\xe6\xb6\x04",
-		.klen	= 32,
-		.input	= zeroed_string,
-		.ilen	= 16,
-		.result	= "\x4f\x6a\x20\x38\x28\x68\x97\xb9"
-			  "\xc9\x87\x01\x36\x55\x33\x17\xfa",
-		.rlen	= 16,
-	},
-};
-
-static struct cipher_testvec cast6_dec_tv_template[] = {
-	{
-		.key	= "\x23\x42\xbb\x9e\xfa\x38\x54\x2c"
-			  "\x0a\xf7\x56\x47\xf2\x9f\x61\x5d",
-		.klen	= 16,
-		.input	= "\xc8\x42\xa0\x89\x72\xb4\x3d\x20"
-			  "\x83\x6c\x91\xd1\xb7\x53\x0f\x6b",
-		.ilen	= 16,
-		.result	= zeroed_string,
-		.rlen	= 16,
-	}, {
-		.key	= "\x23\x42\xbb\x9e\xfa\x38\x54\x2c"
-			  "\xbe\xd0\xac\x83\x94\x0a\xc2\x98"
-			  "\xba\xc7\x7a\x77\x17\x94\x28\x63",
-		.klen	= 24,
-		.input	= "\x1b\x38\x6c\x02\x10\xdc\xad\xcb"
-			  "\xdd\x0e\x41\xaa\x08\xa7\xa7\xe8",
-		.ilen	= 16,
-		.result	= zeroed_string,
-		.rlen	= 16,
-	}, {
-		.key	= "\x23\x42\xbb\x9e\xfa\x38\x54\x2c"
-			  "\xbe\xd0\xac\x83\x94\x0a\xc2\x98"
-			  "\x8d\x7c\x47\xce\x26\x49\x08\x46"
-			  "\x1c\xc1\xb5\x13\x7a\xe6\xb6\x04",
-		.klen	= 32,
-		.input	= "\x4f\x6a\x20\x38\x28\x68\x97\xb9"
-			  "\xc9\x87\x01\x36\x55\x33\x17\xfa",
-		.ilen	= 16,
-		.result	= zeroed_string,
-		.rlen	= 16,
-	},
-};
-
-
-/*
- * AES test vectors.
- */
-#define AES_ENC_TEST_VECTORS 3
-#define AES_DEC_TEST_VECTORS 3
-#define AES_CBC_ENC_TEST_VECTORS 4
-#define AES_CBC_DEC_TEST_VECTORS 4
-#define AES_LRW_ENC_TEST_VECTORS 8
-#define AES_LRW_DEC_TEST_VECTORS 8
-#define AES_XTS_ENC_TEST_VECTORS 4
-#define AES_XTS_DEC_TEST_VECTORS 4
-#define AES_CTR_ENC_TEST_VECTORS 7
-#define AES_CTR_DEC_TEST_VECTORS 6
-#define AES_GCM_ENC_TEST_VECTORS 9
-#define AES_GCM_DEC_TEST_VECTORS 8
-#define AES_CCM_ENC_TEST_VECTORS 7
-#define AES_CCM_DEC_TEST_VECTORS 7
-
-static struct cipher_testvec aes_enc_tv_template[] = {
-	{ /* From FIPS-197 */
-		.key	= "\x00\x01\x02\x03\x04\x05\x06\x07"
-			  "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
-		.klen	= 16,
-		.input	= "\x00\x11\x22\x33\x44\x55\x66\x77"
-			  "\x88\x99\xaa\xbb\xcc\xdd\xee\xff",
-		.ilen	= 16,
-		.result	= "\x69\xc4\xe0\xd8\x6a\x7b\x04\x30"
-			  "\xd8\xcd\xb7\x80\x70\xb4\xc5\x5a",
-		.rlen	= 16,
-	}, {
-		.key	= "\x00\x01\x02\x03\x04\x05\x06\x07"
-			  "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
-			  "\x10\x11\x12\x13\x14\x15\x16\x17",
-		.klen	= 24,
-		.input	= "\x00\x11\x22\x33\x44\x55\x66\x77"
-			  "\x88\x99\xaa\xbb\xcc\xdd\xee\xff",
-		.ilen	= 16,
-		.result	= "\xdd\xa9\x7c\xa4\x86\x4c\xdf\xe0"
-			  "\x6e\xaf\x70\xa0\xec\x0d\x71\x91",
-		.rlen	= 16,
-	}, {
-		.key	= "\x00\x01\x02\x03\x04\x05\x06\x07"
-			  "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
-			  "\x10\x11\x12\x13\x14\x15\x16\x17"
-			  "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f",
-		.klen	= 32,
-		.input	= "\x00\x11\x22\x33\x44\x55\x66\x77"
-			  "\x88\x99\xaa\xbb\xcc\xdd\xee\xff",
-		.ilen	= 16,
-		.result	= "\x8e\xa2\xb7\xca\x51\x67\x45\xbf"
-			  "\xea\xfc\x49\x90\x4b\x49\x60\x89",
-		.rlen	= 16,
-	},
-};
-
-static struct cipher_testvec aes_dec_tv_template[] = {
-	{ /* From FIPS-197 */
-		.key	= "\x00\x01\x02\x03\x04\x05\x06\x07"
-			  "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
-		.klen	= 16,
-		.input	= "\x69\xc4\xe0\xd8\x6a\x7b\x04\x30"
-			  "\xd8\xcd\xb7\x80\x70\xb4\xc5\x5a",
-		.ilen	= 16,
-		.result	= "\x00\x11\x22\x33\x44\x55\x66\x77"
-			  "\x88\x99\xaa\xbb\xcc\xdd\xee\xff",
-		.rlen	= 16,
-	}, {
-		.key	= "\x00\x01\x02\x03\x04\x05\x06\x07"
-			  "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
-			  "\x10\x11\x12\x13\x14\x15\x16\x17",
-		.klen	= 24,
-		.input	= "\xdd\xa9\x7c\xa4\x86\x4c\xdf\xe0"
-			  "\x6e\xaf\x70\xa0\xec\x0d\x71\x91",
-		.ilen	= 16,
-		.result	= "\x00\x11\x22\x33\x44\x55\x66\x77"
-			  "\x88\x99\xaa\xbb\xcc\xdd\xee\xff",
-		.rlen	= 16,
-	}, {
-		.key	= "\x00\x01\x02\x03\x04\x05\x06\x07"
-			  "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
-			  "\x10\x11\x12\x13\x14\x15\x16\x17"
-			  "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f",
-		.klen	= 32,
-		.input	= "\x8e\xa2\xb7\xca\x51\x67\x45\xbf"
-			  "\xea\xfc\x49\x90\x4b\x49\x60\x89",
-		.ilen	= 16,
-		.result	= "\x00\x11\x22\x33\x44\x55\x66\x77"
-			  "\x88\x99\xaa\xbb\xcc\xdd\xee\xff",
-		.rlen	= 16,
-	},
-};
-
-static struct cipher_testvec aes_cbc_enc_tv_template[] = {
-	{ /* From RFC 3602 */
-		.key    = "\x06\xa9\x21\x40\x36\xb8\xa1\x5b"
-			  "\x51\x2e\x03\xd5\x34\x12\x00\x06",
-		.klen   = 16,
-		.iv	= "\x3d\xaf\xba\x42\x9d\x9e\xb4\x30"
-			  "\xb4\x22\xda\x80\x2c\x9f\xac\x41",
-		.input	= "Single block msg",
-		.ilen   = 16,
-		.result = "\xe3\x53\x77\x9c\x10\x79\xae\xb8"
-			  "\x27\x08\x94\x2d\xbe\x77\x18\x1a",
-		.rlen   = 16,
-	}, {
-		.key    = "\xc2\x86\x69\x6d\x88\x7c\x9a\xa0"
-			  "\x61\x1b\xbb\x3e\x20\x25\xa4\x5a",
-		.klen   = 16,
-		.iv     = "\x56\x2e\x17\x99\x6d\x09\x3d\x28"
-			  "\xdd\xb3\xba\x69\x5a\x2e\x6f\x58",
-		.input  = "\x00\x01\x02\x03\x04\x05\x06\x07"
-			  "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
-			  "\x10\x11\x12\x13\x14\x15\x16\x17"
-			  "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f",
-		.ilen   = 32,
-		.result = "\xd2\x96\xcd\x94\xc2\xcc\xcf\x8a"
-			  "\x3a\x86\x30\x28\xb5\xe1\xdc\x0a"
-			  "\x75\x86\x60\x2d\x25\x3c\xff\xf9"
-			  "\x1b\x82\x66\xbe\xa6\xd6\x1a\xb1",
-		.rlen   = 32,
-	}, { /* From NIST SP800-38A */
-		.key	= "\x8e\x73\xb0\xf7\xda\x0e\x64\x52"
-			  "\xc8\x10\xf3\x2b\x80\x90\x79\xe5"
-			  "\x62\xf8\xea\xd2\x52\x2c\x6b\x7b",
-		.klen	= 24,
-		.iv	= "\x00\x01\x02\x03\x04\x05\x06\x07"
-			  "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
-		.input	= "\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96"
-			  "\xe9\x3d\x7e\x11\x73\x93\x17\x2a"
-			  "\xae\x2d\x8a\x57\x1e\x03\xac\x9c"
-			  "\x9e\xb7\x6f\xac\x45\xaf\x8e\x51"
-			  "\x30\xc8\x1c\x46\xa3\x5c\xe4\x11"
-			  "\xe5\xfb\xc1\x19\x1a\x0a\x52\xef"
-			  "\xf6\x9f\x24\x45\xdf\x4f\x9b\x17"
-			  "\xad\x2b\x41\x7b\xe6\x6c\x37\x10",
-		.ilen	= 64,
-		.result	= "\x4f\x02\x1d\xb2\x43\xbc\x63\x3d"
-			  "\x71\x78\x18\x3a\x9f\xa0\x71\xe8"
-			  "\xb4\xd9\xad\xa9\xad\x7d\xed\xf4"
-			  "\xe5\xe7\x38\x76\x3f\x69\x14\x5a"
-			  "\x57\x1b\x24\x20\x12\xfb\x7a\xe0"
-			  "\x7f\xa9\xba\xac\x3d\xf1\x02\xe0"
-			  "\x08\xb0\xe2\x79\x88\x59\x88\x81"
-			  "\xd9\x20\xa9\xe6\x4f\x56\x15\xcd",
-		.rlen	= 64,
-	}, {
-		.key	= "\x60\x3d\xeb\x10\x15\xca\x71\xbe"
-			  "\x2b\x73\xae\xf0\x85\x7d\x77\x81"
-			  "\x1f\x35\x2c\x07\x3b\x61\x08\xd7"
-			  "\x2d\x98\x10\xa3\x09\x14\xdf\xf4",
-		.klen	= 32,
-		.iv	= "\x00\x01\x02\x03\x04\x05\x06\x07"
-			  "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
-		.input	= "\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96"
-			  "\xe9\x3d\x7e\x11\x73\x93\x17\x2a"
-			  "\xae\x2d\x8a\x57\x1e\x03\xac\x9c"
-			  "\x9e\xb7\x6f\xac\x45\xaf\x8e\x51"
-			  "\x30\xc8\x1c\x46\xa3\x5c\xe4\x11"
-			  "\xe5\xfb\xc1\x19\x1a\x0a\x52\xef"
-			  "\xf6\x9f\x24\x45\xdf\x4f\x9b\x17"
-			  "\xad\x2b\x41\x7b\xe6\x6c\x37\x10",
-		.ilen	= 64,
-		.result	= "\xf5\x8c\x4c\x04\xd6\xe5\xf1\xba"
-			  "\x77\x9e\xab\xfb\x5f\x7b\xfb\xd6"
-			  "\x9c\xfc\x4e\x96\x7e\xdb\x80\x8d"
-			  "\x67\x9f\x77\x7b\xc6\x70\x2c\x7d"
-			  "\x39\xf2\x33\x69\xa9\xd9\xba\xcf"
-			  "\xa5\x30\xe2\x63\x04\x23\x14\x61"
-			  "\xb2\xeb\x05\xe2\xc3\x9b\xe9\xfc"
-			  "\xda\x6c\x19\x07\x8c\x6a\x9d\x1b",
-		.rlen	= 64,
-	},
-};
-
-static struct cipher_testvec aes_cbc_dec_tv_template[] = {
-	{ /* From RFC 3602 */
-		.key    = "\x06\xa9\x21\x40\x36\xb8\xa1\x5b"
-			  "\x51\x2e\x03\xd5\x34\x12\x00\x06",
-		.klen   = 16,
-		.iv     = "\x3d\xaf\xba\x42\x9d\x9e\xb4\x30"
-			  "\xb4\x22\xda\x80\x2c\x9f\xac\x41",
-		.input  = "\xe3\x53\x77\x9c\x10\x79\xae\xb8"
-			  "\x27\x08\x94\x2d\xbe\x77\x18\x1a",
-		.ilen   = 16,
-		.result = "Single block msg",
-		.rlen   = 16,
-	}, {
-		.key    = "\xc2\x86\x69\x6d\x88\x7c\x9a\xa0"
-			  "\x61\x1b\xbb\x3e\x20\x25\xa4\x5a",
-		.klen   = 16,
-		.iv     = "\x56\x2e\x17\x99\x6d\x09\x3d\x28"
-			  "\xdd\xb3\xba\x69\x5a\x2e\x6f\x58",
-		.input  = "\xd2\x96\xcd\x94\xc2\xcc\xcf\x8a"
-			  "\x3a\x86\x30\x28\xb5\xe1\xdc\x0a"
-			  "\x75\x86\x60\x2d\x25\x3c\xff\xf9"
-			  "\x1b\x82\x66\xbe\xa6\xd6\x1a\xb1",
-		.ilen   = 32,
-		.result = "\x00\x01\x02\x03\x04\x05\x06\x07"
-			  "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
-			  "\x10\x11\x12\x13\x14\x15\x16\x17"
-			  "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f",
-		.rlen   = 32,
-	}, { /* From NIST SP800-38A */
-		.key	= "\x8e\x73\xb0\xf7\xda\x0e\x64\x52"
-			  "\xc8\x10\xf3\x2b\x80\x90\x79\xe5"
-			  "\x62\xf8\xea\xd2\x52\x2c\x6b\x7b",
-		.klen	= 24,
-		.iv	= "\x00\x01\x02\x03\x04\x05\x06\x07"
-			  "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
-		.input	= "\x4f\x02\x1d\xb2\x43\xbc\x63\x3d"
-			  "\x71\x78\x18\x3a\x9f\xa0\x71\xe8"
-			  "\xb4\xd9\xad\xa9\xad\x7d\xed\xf4"
-			  "\xe5\xe7\x38\x76\x3f\x69\x14\x5a"
-			  "\x57\x1b\x24\x20\x12\xfb\x7a\xe0"
-			  "\x7f\xa9\xba\xac\x3d\xf1\x02\xe0"
-			  "\x08\xb0\xe2\x79\x88\x59\x88\x81"
-			  "\xd9\x20\xa9\xe6\x4f\x56\x15\xcd",
-		.ilen	= 64,
-		.result	= "\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96"
-			  "\xe9\x3d\x7e\x11\x73\x93\x17\x2a"
-			  "\xae\x2d\x8a\x57\x1e\x03\xac\x9c"
-			  "\x9e\xb7\x6f\xac\x45\xaf\x8e\x51"
-			  "\x30\xc8\x1c\x46\xa3\x5c\xe4\x11"
-			  "\xe5\xfb\xc1\x19\x1a\x0a\x52\xef"
-			  "\xf6\x9f\x24\x45\xdf\x4f\x9b\x17"
-			  "\xad\x2b\x41\x7b\xe6\x6c\x37\x10",
-		.rlen	= 64,
-	}, {
-		.key	= "\x60\x3d\xeb\x10\x15\xca\x71\xbe"
-			  "\x2b\x73\xae\xf0\x85\x7d\x77\x81"
-			  "\x1f\x35\x2c\x07\x3b\x61\x08\xd7"
-			  "\x2d\x98\x10\xa3\x09\x14\xdf\xf4",
-		.klen	= 32,
-		.iv	= "\x00\x01\x02\x03\x04\x05\x06\x07"
-			  "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
-		.input	= "\xf5\x8c\x4c\x04\xd6\xe5\xf1\xba"
-			  "\x77\x9e\xab\xfb\x5f\x7b\xfb\xd6"
-			  "\x9c\xfc\x4e\x96\x7e\xdb\x80\x8d"
-			  "\x67\x9f\x77\x7b\xc6\x70\x2c\x7d"
-			  "\x39\xf2\x33\x69\xa9\xd9\xba\xcf"
-			  "\xa5\x30\xe2\x63\x04\x23\x14\x61"
-			  "\xb2\xeb\x05\xe2\xc3\x9b\xe9\xfc"
-			  "\xda\x6c\x19\x07\x8c\x6a\x9d\x1b",
-		.ilen	= 64,
-		.result	= "\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96"
-			  "\xe9\x3d\x7e\x11\x73\x93\x17\x2a"
-			  "\xae\x2d\x8a\x57\x1e\x03\xac\x9c"
-			  "\x9e\xb7\x6f\xac\x45\xaf\x8e\x51"
-			  "\x30\xc8\x1c\x46\xa3\x5c\xe4\x11"
-			  "\xe5\xfb\xc1\x19\x1a\x0a\x52\xef"
-			  "\xf6\x9f\x24\x45\xdf\x4f\x9b\x17"
-			  "\xad\x2b\x41\x7b\xe6\x6c\x37\x10",
-		.rlen	= 64,
-	},
-};
-
-static struct cipher_testvec aes_lrw_enc_tv_template[] = {
-	/* from http://grouper.ieee.org/groups/1619/email/pdf00017.pdf */
-	{ /* LRW-32-AES 1 */
-		.key    = "\x45\x62\xac\x25\xf8\x28\x17\x6d"
-			  "\x4c\x26\x84\x14\xb5\x68\x01\x85"
-			  "\x25\x8e\x2a\x05\xe7\x3e\x9d\x03"
-			  "\xee\x5a\x83\x0c\xcc\x09\x4c\x87",
-		.klen   = 32,
-		.iv     = "\x00\x00\x00\x00\x00\x00\x00\x00"
-			  "\x00\x00\x00\x00\x00\x00\x00\x01",
-		.input  = "\x30\x31\x32\x33\x34\x35\x36\x37"
-			  "\x38\x39\x41\x42\x43\x44\x45\x46",
-		.ilen   = 16,
-		.result = "\xf1\xb2\x73\xcd\x65\xa3\xdf\x5f"
-			  "\xe9\x5d\x48\x92\x54\x63\x4e\xb8",
-		.rlen   = 16,
-	}, { /* LRW-32-AES 2 */
-		.key    = "\x59\x70\x47\x14\xf5\x57\x47\x8c"
-			  "\xd7\x79\xe8\x0f\x54\x88\x79\x44"
-			  "\x0d\x48\xf0\xb7\xb1\x5a\x53\xea"
-			  "\x1c\xaa\x6b\x29\xc2\xca\xfb\xaf",
-		.klen   = 32,
-		.iv     = "\x00\x00\x00\x00\x00\x00\x00\x00"
-			  "\x00\x00\x00\x00\x00\x00\x00\x02",
-		.input  = "\x30\x31\x32\x33\x34\x35\x36\x37"
-			  "\x38\x39\x41\x42\x43\x44\x45\x46",
-		.ilen   = 16,
-		.result = "\x00\xc8\x2b\xae\x95\xbb\xcd\xe5"
-			  "\x27\x4f\x07\x69\xb2\x60\xe1\x36",
-		.rlen   = 16,
-	}, { /* LRW-32-AES 3 */
-		.key    = "\xd8\x2a\x91\x34\xb2\x6a\x56\x50"
-			  "\x30\xfe\x69\xe2\x37\x7f\x98\x47"
-			  "\xcd\xf9\x0b\x16\x0c\x64\x8f\xb6"
-			  "\xb0\x0d\x0d\x1b\xae\x85\x87\x1f",
-		.klen   = 32,
-		.iv     = "\x00\x00\x00\x00\x00\x00\x00\x00"
-			  "\x00\x00\x00\x02\x00\x00\x00\x00",
-		.input  = "\x30\x31\x32\x33\x34\x35\x36\x37"
-			  "\x38\x39\x41\x42\x43\x44\x45\x46",
-		.ilen   = 16,
-		.result = "\x76\x32\x21\x83\xed\x8f\xf1\x82"
-			  "\xf9\x59\x62\x03\x69\x0e\x5e\x01",
-		.rlen   = 16,
-	}, { /* LRW-32-AES 4 */
-		.key    = "\x0f\x6a\xef\xf8\xd3\xd2\xbb\x15"
-			  "\x25\x83\xf7\x3c\x1f\x01\x28\x74"
-			  "\xca\xc6\xbc\x35\x4d\x4a\x65\x54"
-			  "\x90\xae\x61\xcf\x7b\xae\xbd\xcc"
-			  "\xad\xe4\x94\xc5\x4a\x29\xae\x70",
-		.klen   = 40,
-		.iv     = "\x00\x00\x00\x00\x00\x00\x00\x00"
-			  "\x00\x00\x00\x00\x00\x00\x00\x01",
-		.input  = "\x30\x31\x32\x33\x34\x35\x36\x37"
-			  "\x38\x39\x41\x42\x43\x44\x45\x46",
-		.ilen   = 16,
-		.result = "\x9c\x0f\x15\x2f\x55\xa2\xd8\xf0"
-			  "\xd6\x7b\x8f\x9e\x28\x22\xbc\x41",
-		.rlen   = 16,
-	}, { /* LRW-32-AES 5 */
-		.key    = "\x8a\xd4\xee\x10\x2f\xbd\x81\xff"
-			  "\xf8\x86\xce\xac\x93\xc5\xad\xc6"
-			  "\xa0\x19\x07\xc0\x9d\xf7\xbb\xdd"
-			  "\x52\x13\xb2\xb7\xf0\xff\x11\xd8"
-			  "\xd6\x08\xd0\xcd\x2e\xb1\x17\x6f",
-		.klen   = 40,
-		.iv     = "\x00\x00\x00\x00\x00\x00\x00\x00"
-			  "\x00\x00\x00\x02\x00\x00\x00\x00",
-		.input  = "\x30\x31\x32\x33\x34\x35\x36\x37"
-			  "\x38\x39\x41\x42\x43\x44\x45\x46",
-		.ilen   = 16,
-		.result = "\xd4\x27\x6a\x7f\x14\x91\x3d\x65"
-			  "\xc8\x60\x48\x02\x87\xe3\x34\x06",
-		.rlen   = 16,
-	}, { /* LRW-32-AES 6 */
-		.key    = "\xf8\xd4\x76\xff\xd6\x46\xee\x6c"
-			  "\x23\x84\xcb\x1c\x77\xd6\x19\x5d"
-			  "\xfe\xf1\xa9\xf3\x7b\xbc\x8d\x21"
-			  "\xa7\x9c\x21\xf8\xcb\x90\x02\x89"
-			  "\xa8\x45\x34\x8e\xc8\xc5\xb5\xf1"
-			  "\x26\xf5\x0e\x76\xfe\xfd\x1b\x1e",
-		.klen   = 48,
-		.iv     = "\x00\x00\x00\x00\x00\x00\x00\x00"
-			  "\x00\x00\x00\x00\x00\x00\x00\x01",
-		.input  = "\x30\x31\x32\x33\x34\x35\x36\x37"
-			  "\x38\x39\x41\x42\x43\x44\x45\x46",
-		.ilen   = 16,
-		.result = "\xbd\x06\xb8\xe1\xdb\x98\x89\x9e"
-			  "\xc4\x98\xe4\x91\xcf\x1c\x70\x2b",
-		.rlen   = 16,
-	}, { /* LRW-32-AES 7 */
-		.key    = "\xfb\x76\x15\xb2\x3d\x80\x89\x1d"
-			  "\xd4\x70\x98\x0b\xc7\x95\x84\xc8"
-			  "\xb2\xfb\x64\xce\x60\x97\x87\x8d"
-			  "\x17\xfc\xe4\x5a\x49\xe8\x30\xb7"
-			  "\x6e\x78\x17\xe7\x2d\x5e\x12\xd4"
-			  "\x60\x64\x04\x7a\xf1\x2f\x9e\x0c",
-		.klen   = 48,
-		.iv     = "\x00\x00\x00\x00\x00\x00\x00\x00"
-			  "\x00\x00\x00\x02\x00\x00\x00\x00",
-		.input  = "\x30\x31\x32\x33\x34\x35\x36\x37"
-			  "\x38\x39\x41\x42\x43\x44\x45\x46",
-		.ilen   = 16,
-		.result = "\x5b\x90\x8e\xc1\xab\xdd\x67\x5f"
-			  "\x3d\x69\x8a\x95\x53\xc8\x9c\xe5",
-		.rlen   = 16,
-	}, {
-/* http://www.mail-archive.com/stds-p1619@listserv.ieee.org/msg00173.html */
-		.key    = "\xf8\xd4\x76\xff\xd6\x46\xee\x6c"
-			  "\x23\x84\xcb\x1c\x77\xd6\x19\x5d"
-			  "\xfe\xf1\xa9\xf3\x7b\xbc\x8d\x21"
-			  "\xa7\x9c\x21\xf8\xcb\x90\x02\x89"
-			  "\xa8\x45\x34\x8e\xc8\xc5\xb5\xf1"
-			  "\x26\xf5\x0e\x76\xfe\xfd\x1b\x1e",
-		.klen   = 48,
-		.iv     = "\x00\x00\x00\x00\x00\x00\x00\x00"
-			  "\x00\x00\x00\x00\x00\x00\x00\x01",
-		.input  = "\x05\x11\xb7\x18\xab\xc6\x2d\xac"
-			  "\x70\x5d\xf6\x22\x94\xcd\xe5\x6c"
-			  "\x17\x6b\xf6\x1c\xf0\xf3\x6e\xf8"
-			  "\x50\x38\x1f\x71\x49\xb6\x57\xd6"
-			  "\x8f\xcb\x8d\x6b\xe3\xa6\x29\x90"
-			  "\xfe\x2a\x62\x82\xae\x6d\x8b\xf6"
-			  "\xad\x1e\x9e\x20\x5f\x38\xbe\x04"
-			  "\xda\x10\x8e\xed\xa2\xa4\x87\xab"
-			  "\xda\x6b\xb4\x0c\x75\xba\xd3\x7c"
-			  "\xc9\xac\x42\x31\x95\x7c\xc9\x04"
-			  "\xeb\xd5\x6e\x32\x69\x8a\xdb\xa6"
-			  "\x15\xd7\x3f\x4f\x2f\x66\x69\x03"
-			  "\x9c\x1f\x54\x0f\xde\x1f\xf3\x65"
-			  "\x4c\x96\x12\xed\x7c\x92\x03\x01"
-			  "\x6f\xbc\x35\x93\xac\xf1\x27\xf1"
-			  "\xb4\x96\x82\x5a\x5f\xb0\xa0\x50"
-			  "\x89\xa4\x8e\x66\x44\x85\xcc\xfd"
-			  "\x33\x14\x70\xe3\x96\xb2\xc3\xd3"
-			  "\xbb\x54\x5a\x1a\xf9\x74\xa2\xc5"
-			  "\x2d\x64\x75\xdd\xb4\x54\xe6\x74"
-			  "\x8c\xd3\x9d\x9e\x86\xab\x51\x53"
-			  "\xb7\x93\x3e\x6f\xd0\x4e\x2c\x40"
-			  "\xf6\xa8\x2e\x3e\x9d\xf4\x66\xa5"
-			  "\x76\x12\x73\x44\x1a\x56\xd7\x72"
-			  "\x88\xcd\x21\x8c\x4c\x0f\xfe\xda"
-			  "\x95\xe0\x3a\xa6\xa5\x84\x46\xcd"
-			  "\xd5\x3e\x9d\x3a\xe2\x67\xe6\x60"
-			  "\x1a\xe2\x70\x85\x58\xc2\x1b\x09"
-			  "\xe1\xd7\x2c\xca\xad\xa8\x8f\xf9"
-			  "\xac\xb3\x0e\xdb\xca\x2e\xe2\xb8"
-			  "\x51\x71\xd9\x3c\x6c\xf1\x56\xf8"
-			  "\xea\x9c\xf1\xfb\x0c\xe6\xb7\x10"
-			  "\x1c\xf8\xa9\x7c\xe8\x53\x35\xc1"
-			  "\x90\x3e\x76\x4a\x74\xa4\x21\x2c"
-			  "\xf6\x2c\x4e\x0f\x94\x3a\x88\x2e"
-			  "\x41\x09\x6a\x33\x7d\xf6\xdd\x3f"
-			  "\x8d\x23\x31\x74\x84\xeb\x88\x6e"
-			  "\xcc\xb9\xbc\x22\x83\x19\x07\x22"
-			  "\xa5\x2d\xdf\xa5\xf3\x80\x85\x78"
-			  "\x84\x39\x6a\x6d\x6a\x99\x4f\xa5"
-			  "\x15\xfe\x46\xb0\xe4\x6c\xa5\x41"
-			  "\x3c\xce\x8f\x42\x60\x71\xa7\x75"
-			  "\x08\x40\x65\x8a\x82\xbf\xf5\x43"
-			  "\x71\x96\xa9\x4d\x44\x8a\x20\xbe"
-			  "\xfa\x4d\xbb\xc0\x7d\x31\x96\x65"
-			  "\xe7\x75\xe5\x3e\xfd\x92\x3b\xc9"
-			  "\x55\xbb\x16\x7e\xf7\xc2\x8c\xa4"
-			  "\x40\x1d\xe5\xef\x0e\xdf\xe4\x9a"
-			  "\x62\x73\x65\xfd\x46\x63\x25\x3d"
-			  "\x2b\xaf\xe5\x64\xfe\xa5\x5c\xcf"
-			  "\x24\xf3\xb4\xac\x64\xba\xdf\x4b"
-			  "\xc6\x96\x7d\x81\x2d\x8d\x97\xf7"
-			  "\xc5\x68\x77\x84\x32\x2b\xcc\x85"
-			  "\x74\x96\xf0\x12\x77\x61\xb9\xeb"
-			  "\x71\xaa\x82\xcb\x1c\xdb\x89\xc8"
-			  "\xc6\xb5\xe3\x5c\x7d\x39\x07\x24"
-			  "\xda\x39\x87\x45\xc0\x2b\xbb\x01"
-			  "\xac\xbc\x2a\x5c\x7f\xfc\xe8\xce"
-			  "\x6d\x9c\x6f\xed\xd3\xc1\xa1\xd6"
-			  "\xc5\x55\xa9\x66\x2f\xe1\xc8\x32"
-			  "\xa6\x5d\xa4\x3a\x98\x73\xe8\x45"
-			  "\xa4\xc7\xa8\xb4\xf6\x13\x03\xf6"
-			  "\xe9\x2e\xc4\x29\x0f\x84\xdb\xc4"
-			  "\x21\xc4\xc2\x75\x67\x89\x37\x0a",
-		.ilen   = 512,
-		.result = "\x1a\x1d\xa9\x30\xad\xf9\x2f\x9b"
-			  "\xb6\x1d\xae\xef\xf0\x2f\xf8\x5a"
-			  "\x39\x3c\xbf\x2a\xb2\x45\xb2\x23"
-			  "\x1b\x63\x3c\xcf\xaa\xbe\xcf\x4e"
-			  "\xfa\xe8\x29\xc2\x20\x68\x2b\x3c"
-			  "\x2e\x8b\xf7\x6e\x25\xbd\xe3\x3d"
-			  "\x66\x27\xd6\xaf\xd6\x64\x3e\xe3"
-			  "\xe8\x58\x46\x97\x39\x51\x07\xde"
-			  "\xcb\x37\xbc\xa9\xc0\x5f\x75\xc3"
-			  "\x0e\x84\x23\x1d\x16\xd4\x1c\x59"
-			  "\x9c\x1a\x02\x55\xab\x3a\x97\x1d"
-			  "\xdf\xdd\xc7\x06\x51\xd7\x70\xae"
-			  "\x23\xc6\x8c\xf5\x1e\xa0\xe5\x82"
-			  "\xb8\xb2\xbf\x04\xa0\x32\x8e\x68"
-			  "\xeb\xaf\x6e\x2d\x94\x22\x2f\xce"
-			  "\x4c\xb5\x59\xe2\xa2\x2f\xa0\x98"
-			  "\x1a\x97\xc6\xd4\xb5\x00\x59\xf2"
-			  "\x84\x14\x72\xb1\x9a\x6e\xa3\x7f"
-			  "\xea\x20\xe7\xcb\x65\x77\x3a\xdf"
-			  "\xc8\x97\x67\x15\xc2\x2a\x27\xcc"
-			  "\x18\x55\xa1\x24\x0b\x24\x24\xaf"
-			  "\x5b\xec\x68\xb8\xc8\xf5\xba\x63"
-			  "\xff\xed\x89\xce\xd5\x3d\x88\xf3"
-			  "\x25\xef\x05\x7c\x3a\xef\xeb\xd8"
-			  "\x7a\x32\x0d\xd1\x1e\x58\x59\x99"
-			  "\x90\x25\xb5\x26\xb0\xe3\x2b\x6c"
-			  "\x4c\xa9\x8b\x84\x4f\x5e\x01\x50"
-			  "\x41\x30\x58\xc5\x62\x74\x52\x1d"
-			  "\x45\x24\x6a\x42\x64\x4f\x97\x1c"
-			  "\xa8\x66\xb5\x6d\x79\xd4\x0d\x48"
-			  "\xc5\x5f\xf3\x90\x32\xdd\xdd\xe1"
-			  "\xe4\xa9\x9f\xfc\xc3\x52\x5a\x46"
-			  "\xe4\x81\x84\x95\x36\x59\x7a\x6b"
-			  "\xaa\xb3\x60\xad\xce\x9f\x9f\x28"
-			  "\xe0\x01\x75\x22\xc4\x4e\xa9\x62"
-			  "\x5c\x62\x0d\x00\xcb\x13\xe8\x43"
-			  "\x72\xd4\x2d\x53\x46\xb5\xd1\x16"
-			  "\x22\x18\xdf\x34\x33\xf5\xd6\x1c"
-			  "\xb8\x79\x78\x97\x94\xff\x72\x13"
-			  "\x4c\x27\xfc\xcb\xbf\x01\x53\xa6"
-			  "\xb4\x50\x6e\xde\xdf\xb5\x43\xa4"
-			  "\x59\xdf\x52\xf9\x7c\xe0\x11\x6f"
-			  "\x2d\x14\x8e\x24\x61\x2c\xe1\x17"
-			  "\xcc\xce\x51\x0c\x19\x8a\x82\x30"
-			  "\x94\xd5\x3d\x6a\x53\x06\x5e\xbd"
-			  "\xb7\xeb\xfa\xfd\x27\x51\xde\x85"
-			  "\x1e\x86\x53\x11\x53\x94\x00\xee"
-			  "\x2b\x8c\x08\x2a\xbf\xdd\xae\x11"
-			  "\xcb\x1e\xa2\x07\x9a\x80\xcf\x62"
-			  "\x9b\x09\xdc\x95\x3c\x96\x8e\xb1"
-			  "\x09\xbd\xe4\xeb\xdb\xca\x70\x7a"
-			  "\x9e\xfa\x31\x18\x45\x3c\x21\x33"
-			  "\xb0\xb3\x2b\xea\xf3\x71\x2d\xe1"
-			  "\x03\xad\x1b\x48\xd4\x67\x27\xf0"
-			  "\x62\xe4\x3d\xfb\x9b\x08\x76\xe7"
-			  "\xdd\x2b\x01\x39\x04\x5a\x58\x7a"
-			  "\xf7\x11\x90\xec\xbd\x51\x5c\x32"
-			  "\x6b\xd7\x35\x39\x02\x6b\xf2\xa6"
-			  "\xd0\x0d\x07\xe1\x06\xc4\x5b\x7d"
-			  "\xe4\x6a\xd7\xee\x15\x1f\x83\xb4"
-			  "\xa3\xa7\x5e\xc3\x90\xb7\xef\xd3"
-			  "\xb7\x4f\xf8\x92\x4c\xb7\x3c\x29"
-			  "\xcd\x7e\x2b\x5d\x43\xea\x42\xe7"
-			  "\x74\x3f\x7d\x58\x88\x75\xde\x3e",
-		.rlen   = 512,
 	}
 };
 
-static struct cipher_testvec aes_lrw_dec_tv_template[] = {
-	/* from http://grouper.ieee.org/groups/1619/email/pdf00017.pdf */
-	/* same as enc vectors with input and result reversed */
-	{ /* LRW-32-AES 1 */
-		.key    = "\x45\x62\xac\x25\xf8\x28\x17\x6d"
-			  "\x4c\x26\x84\x14\xb5\x68\x01\x85"
-			  "\x25\x8e\x2a\x05\xe7\x3e\x9d\x03"
-			  "\xee\x5a\x83\x0c\xcc\x09\x4c\x87",
-		.klen   = 32,
-		.iv     = "\x00\x00\x00\x00\x00\x00\x00\x00"
-			  "\x00\x00\x00\x00\x00\x00\x00\x01",
-		.input  = "\xf1\xb2\x73\xcd\x65\xa3\xdf\x5f"
-			  "\xe9\x5d\x48\x92\x54\x63\x4e\xb8",
-		.ilen   = 16,
-		.result = "\x30\x31\x32\x33\x34\x35\x36\x37"
-			  "\x38\x39\x41\x42\x43\x44\x45\x46",
-		.rlen   = 16,
-	}, { /* LRW-32-AES 2 */
-		.key    = "\x59\x70\x47\x14\xf5\x57\x47\x8c"
-			  "\xd7\x79\xe8\x0f\x54\x88\x79\x44"
-			  "\x0d\x48\xf0\xb7\xb1\x5a\x53\xea"
-			  "\x1c\xaa\x6b\x29\xc2\xca\xfb\xaf",
-		.klen   = 32,
-		.iv     = "\x00\x00\x00\x00\x00\x00\x00\x00"
-			  "\x00\x00\x00\x00\x00\x00\x00\x02",
-		.input  = "\x00\xc8\x2b\xae\x95\xbb\xcd\xe5"
-			  "\x27\x4f\x07\x69\xb2\x60\xe1\x36",
-		.ilen   = 16,
-		.result  = "\x30\x31\x32\x33\x34\x35\x36\x37"
-			   "\x38\x39\x41\x42\x43\x44\x45\x46",
-		.rlen   = 16,
-	}, { /* LRW-32-AES 3 */
-		.key    = "\xd8\x2a\x91\x34\xb2\x6a\x56\x50"
-			  "\x30\xfe\x69\xe2\x37\x7f\x98\x47"
-			  "\xcd\xf9\x0b\x16\x0c\x64\x8f\xb6"
-			  "\xb0\x0d\x0d\x1b\xae\x85\x87\x1f",
-		.klen   = 32,
-		.iv     = "\x00\x00\x00\x00\x00\x00\x00\x00"
-			  "\x00\x00\x00\x02\x00\x00\x00\x00",
-		.input  = "\x76\x32\x21\x83\xed\x8f\xf1\x82"
-			  "\xf9\x59\x62\x03\x69\x0e\x5e\x01",
-		.ilen   = 16,
-		.result = "\x30\x31\x32\x33\x34\x35\x36\x37"
-			  "\x38\x39\x41\x42\x43\x44\x45\x46",
-		.rlen   = 16,
-	}, { /* LRW-32-AES 4 */
-		.key    = "\x0f\x6a\xef\xf8\xd3\xd2\xbb\x15"
-			  "\x25\x83\xf7\x3c\x1f\x01\x28\x74"
-			  "\xca\xc6\xbc\x35\x4d\x4a\x65\x54"
-			  "\x90\xae\x61\xcf\x7b\xae\xbd\xcc"
-			  "\xad\xe4\x94\xc5\x4a\x29\xae\x70",
-		.klen   = 40,
-		.iv     = "\x00\x00\x00\x00\x00\x00\x00\x00"
-			  "\x00\x00\x00\x00\x00\x00\x00\x01",
-		.input  = "\x9c\x0f\x15\x2f\x55\xa2\xd8\xf0"
-			  "\xd6\x7b\x8f\x9e\x28\x22\xbc\x41",
-		.ilen   = 16,
-		.result = "\x30\x31\x32\x33\x34\x35\x36\x37"
-			  "\x38\x39\x41\x42\x43\x44\x45\x46",
-		.rlen   = 16,
-	}, { /* LRW-32-AES 5 */
-		.key    = "\x8a\xd4\xee\x10\x2f\xbd\x81\xff"
-			  "\xf8\x86\xce\xac\x93\xc5\xad\xc6"
-			  "\xa0\x19\x07\xc0\x9d\xf7\xbb\xdd"
-			  "\x52\x13\xb2\xb7\xf0\xff\x11\xd8"
-			  "\xd6\x08\xd0\xcd\x2e\xb1\x17\x6f",
-		.klen   = 40,
-		.iv     = "\x00\x00\x00\x00\x00\x00\x00\x00"
-			  "\x00\x00\x00\x02\x00\x00\x00\x00",
-		.input  = "\xd4\x27\x6a\x7f\x14\x91\x3d\x65"
-			  "\xc8\x60\x48\x02\x87\xe3\x34\x06",
-		.ilen   = 16,
-		.result = "\x30\x31\x32\x33\x34\x35\x36\x37"
-			  "\x38\x39\x41\x42\x43\x44\x45\x46",
-		.rlen   = 16,
-	}, { /* LRW-32-AES 6 */
-		.key    = "\xf8\xd4\x76\xff\xd6\x46\xee\x6c"
-			  "\x23\x84\xcb\x1c\x77\xd6\x19\x5d"
-			  "\xfe\xf1\xa9\xf3\x7b\xbc\x8d\x21"
-			  "\xa7\x9c\x21\xf8\xcb\x90\x02\x89"
-			  "\xa8\x45\x34\x8e\xc8\xc5\xb5\xf1"
-			  "\x26\xf5\x0e\x76\xfe\xfd\x1b\x1e",
-		.klen   = 48,
-		.iv     = "\x00\x00\x00\x00\x00\x00\x00\x00"
-			  "\x00\x00\x00\x00\x00\x00\x00\x01",
-		.input  = "\xbd\x06\xb8\xe1\xdb\x98\x89\x9e"
-			  "\xc4\x98\xe4\x91\xcf\x1c\x70\x2b",
-		.ilen   = 16,
-		.result = "\x30\x31\x32\x33\x34\x35\x36\x37"
-			  "\x38\x39\x41\x42\x43\x44\x45\x46",
-		.rlen   = 16,
-	}, { /* LRW-32-AES 7 */
-		.key    = "\xfb\x76\x15\xb2\x3d\x80\x89\x1d"
-			  "\xd4\x70\x98\x0b\xc7\x95\x84\xc8"
-			  "\xb2\xfb\x64\xce\x60\x97\x87\x8d"
-			  "\x17\xfc\xe4\x5a\x49\xe8\x30\xb7"
-			  "\x6e\x78\x17\xe7\x2d\x5e\x12\xd4"
-			  "\x60\x64\x04\x7a\xf1\x2f\x9e\x0c",
-		.klen   = 48,
-		.iv     = "\x00\x00\x00\x00\x00\x00\x00\x00"
-			  "\x00\x00\x00\x02\x00\x00\x00\x00",
-		.input  = "\x5b\x90\x8e\xc1\xab\xdd\x67\x5f"
-			  "\x3d\x69\x8a\x95\x53\xc8\x9c\xe5",
-		.ilen   = 16,
-		.result = "\x30\x31\x32\x33\x34\x35\x36\x37"
-			  "\x38\x39\x41\x42\x43\x44\x45\x46",
-		.rlen   = 16,
-	}, {
-/* http://www.mail-archive.com/stds-p1619@listserv.ieee.org/msg00173.html */
-		.key    = "\xf8\xd4\x76\xff\xd6\x46\xee\x6c"
-			  "\x23\x84\xcb\x1c\x77\xd6\x19\x5d"
-			  "\xfe\xf1\xa9\xf3\x7b\xbc\x8d\x21"
-			  "\xa7\x9c\x21\xf8\xcb\x90\x02\x89"
-			  "\xa8\x45\x34\x8e\xc8\xc5\xb5\xf1"
-			  "\x26\xf5\x0e\x76\xfe\xfd\x1b\x1e",
-		.klen   = 48,
-		.iv     = "\x00\x00\x00\x00\x00\x00\x00\x00"
-			  "\x00\x00\x00\x00\x00\x00\x00\x01",
-		.input	= "\x1a\x1d\xa9\x30\xad\xf9\x2f\x9b"
-			  "\xb6\x1d\xae\xef\xf0\x2f\xf8\x5a"
-			  "\x39\x3c\xbf\x2a\xb2\x45\xb2\x23"
-			  "\x1b\x63\x3c\xcf\xaa\xbe\xcf\x4e"
-			  "\xfa\xe8\x29\xc2\x20\x68\x2b\x3c"
-			  "\x2e\x8b\xf7\x6e\x25\xbd\xe3\x3d"
-			  "\x66\x27\xd6\xaf\xd6\x64\x3e\xe3"
-			  "\xe8\x58\x46\x97\x39\x51\x07\xde"
-			  "\xcb\x37\xbc\xa9\xc0\x5f\x75\xc3"
-			  "\x0e\x84\x23\x1d\x16\xd4\x1c\x59"
-			  "\x9c\x1a\x02\x55\xab\x3a\x97\x1d"
-			  "\xdf\xdd\xc7\x06\x51\xd7\x70\xae"
-			  "\x23\xc6\x8c\xf5\x1e\xa0\xe5\x82"
-			  "\xb8\xb2\xbf\x04\xa0\x32\x8e\x68"
-			  "\xeb\xaf\x6e\x2d\x94\x22\x2f\xce"
-			  "\x4c\xb5\x59\xe2\xa2\x2f\xa0\x98"
-			  "\x1a\x97\xc6\xd4\xb5\x00\x59\xf2"
-			  "\x84\x14\x72\xb1\x9a\x6e\xa3\x7f"
-			  "\xea\x20\xe7\xcb\x65\x77\x3a\xdf"
-			  "\xc8\x97\x67\x15\xc2\x2a\x27\xcc"
-			  "\x18\x55\xa1\x24\x0b\x24\x24\xaf"
-			  "\x5b\xec\x68\xb8\xc8\xf5\xba\x63"
-			  "\xff\xed\x89\xce\xd5\x3d\x88\xf3"
-			  "\x25\xef\x05\x7c\x3a\xef\xeb\xd8"
-			  "\x7a\x32\x0d\xd1\x1e\x58\x59\x99"
-			  "\x90\x25\xb5\x26\xb0\xe3\x2b\x6c"
-			  "\x4c\xa9\x8b\x84\x4f\x5e\x01\x50"
-			  "\x41\x30\x58\xc5\x62\x74\x52\x1d"
-			  "\x45\x24\x6a\x42\x64\x4f\x97\x1c"
-			  "\xa8\x66\xb5\x6d\x79\xd4\x0d\x48"
-			  "\xc5\x5f\xf3\x90\x32\xdd\xdd\xe1"
-			  "\xe4\xa9\x9f\xfc\xc3\x52\x5a\x46"
-			  "\xe4\x81\x84\x95\x36\x59\x7a\x6b"
-			  "\xaa\xb3\x60\xad\xce\x9f\x9f\x28"
-			  "\xe0\x01\x75\x22\xc4\x4e\xa9\x62"
-			  "\x5c\x62\x0d\x00\xcb\x13\xe8\x43"
-			  "\x72\xd4\x2d\x53\x46\xb5\xd1\x16"
-			  "\x22\x18\xdf\x34\x33\xf5\xd6\x1c"
-			  "\xb8\x79\x78\x97\x94\xff\x72\x13"
-			  "\x4c\x27\xfc\xcb\xbf\x01\x53\xa6"
-			  "\xb4\x50\x6e\xde\xdf\xb5\x43\xa4"
-			  "\x59\xdf\x52\xf9\x7c\xe0\x11\x6f"
-			  "\x2d\x14\x8e\x24\x61\x2c\xe1\x17"
-			  "\xcc\xce\x51\x0c\x19\x8a\x82\x30"
-			  "\x94\xd5\x3d\x6a\x53\x06\x5e\xbd"
-			  "\xb7\xeb\xfa\xfd\x27\x51\xde\x85"
-			  "\x1e\x86\x53\x11\x53\x94\x00\xee"
-			  "\x2b\x8c\x08\x2a\xbf\xdd\xae\x11"
-			  "\xcb\x1e\xa2\x07\x9a\x80\xcf\x62"
-			  "\x9b\x09\xdc\x95\x3c\x96\x8e\xb1"
-			  "\x09\xbd\xe4\xeb\xdb\xca\x70\x7a"
-			  "\x9e\xfa\x31\x18\x45\x3c\x21\x33"
-			  "\xb0\xb3\x2b\xea\xf3\x71\x2d\xe1"
-			  "\x03\xad\x1b\x48\xd4\x67\x27\xf0"
-			  "\x62\xe4\x3d\xfb\x9b\x08\x76\xe7"
-			  "\xdd\x2b\x01\x39\x04\x5a\x58\x7a"
-			  "\xf7\x11\x90\xec\xbd\x51\x5c\x32"
-			  "\x6b\xd7\x35\x39\x02\x6b\xf2\xa6"
-			  "\xd0\x0d\x07\xe1\x06\xc4\x5b\x7d"
-			  "\xe4\x6a\xd7\xee\x15\x1f\x83\xb4"
-			  "\xa3\xa7\x5e\xc3\x90\xb7\xef\xd3"
-			  "\xb7\x4f\xf8\x92\x4c\xb7\x3c\x29"
-			  "\xcd\x7e\x2b\x5d\x43\xea\x42\xe7"
-			  "\x74\x3f\x7d\x58\x88\x75\xde\x3e",
-		.ilen   = 512,
-		.result	= "\x05\x11\xb7\x18\xab\xc6\x2d\xac"
-			  "\x70\x5d\xf6\x22\x94\xcd\xe5\x6c"
-			  "\x17\x6b\xf6\x1c\xf0\xf3\x6e\xf8"
-			  "\x50\x38\x1f\x71\x49\xb6\x57\xd6"
-			  "\x8f\xcb\x8d\x6b\xe3\xa6\x29\x90"
-			  "\xfe\x2a\x62\x82\xae\x6d\x8b\xf6"
-			  "\xad\x1e\x9e\x20\x5f\x38\xbe\x04"
-			  "\xda\x10\x8e\xed\xa2\xa4\x87\xab"
-			  "\xda\x6b\xb4\x0c\x75\xba\xd3\x7c"
-			  "\xc9\xac\x42\x31\x95\x7c\xc9\x04"
-			  "\xeb\xd5\x6e\x32\x69\x8a\xdb\xa6"
-			  "\x15\xd7\x3f\x4f\x2f\x66\x69\x03"
-			  "\x9c\x1f\x54\x0f\xde\x1f\xf3\x65"
-			  "\x4c\x96\x12\xed\x7c\x92\x03\x01"
-			  "\x6f\xbc\x35\x93\xac\xf1\x27\xf1"
-			  "\xb4\x96\x82\x5a\x5f\xb0\xa0\x50"
-			  "\x89\xa4\x8e\x66\x44\x85\xcc\xfd"
-			  "\x33\x14\x70\xe3\x96\xb2\xc3\xd3"
-			  "\xbb\x54\x5a\x1a\xf9\x74\xa2\xc5"
-			  "\x2d\x64\x75\xdd\xb4\x54\xe6\x74"
-			  "\x8c\xd3\x9d\x9e\x86\xab\x51\x53"
-			  "\xb7\x93\x3e\x6f\xd0\x4e\x2c\x40"
-			  "\xf6\xa8\x2e\x3e\x9d\xf4\x66\xa5"
-			  "\x76\x12\x73\x44\x1a\x56\xd7\x72"
-			  "\x88\xcd\x21\x8c\x4c\x0f\xfe\xda"
-			  "\x95\xe0\x3a\xa6\xa5\x84\x46\xcd"
-			  "\xd5\x3e\x9d\x3a\xe2\x67\xe6\x60"
-			  "\x1a\xe2\x70\x85\x58\xc2\x1b\x09"
-			  "\xe1\xd7\x2c\xca\xad\xa8\x8f\xf9"
-			  "\xac\xb3\x0e\xdb\xca\x2e\xe2\xb8"
-			  "\x51\x71\xd9\x3c\x6c\xf1\x56\xf8"
-			  "\xea\x9c\xf1\xfb\x0c\xe6\xb7\x10"
-			  "\x1c\xf8\xa9\x7c\xe8\x53\x35\xc1"
-			  "\x90\x3e\x76\x4a\x74\xa4\x21\x2c"
-			  "\xf6\x2c\x4e\x0f\x94\x3a\x88\x2e"
-			  "\x41\x09\x6a\x33\x7d\xf6\xdd\x3f"
-			  "\x8d\x23\x31\x74\x84\xeb\x88\x6e"
-			  "\xcc\xb9\xbc\x22\x83\x19\x07\x22"
-			  "\xa5\x2d\xdf\xa5\xf3\x80\x85\x78"
-			  "\x84\x39\x6a\x6d\x6a\x99\x4f\xa5"
-			  "\x15\xfe\x46\xb0\xe4\x6c\xa5\x41"
-			  "\x3c\xce\x8f\x42\x60\x71\xa7\x75"
-			  "\x08\x40\x65\x8a\x82\xbf\xf5\x43"
-			  "\x71\x96\xa9\x4d\x44\x8a\x20\xbe"
-			  "\xfa\x4d\xbb\xc0\x7d\x31\x96\x65"
-			  "\xe7\x75\xe5\x3e\xfd\x92\x3b\xc9"
-			  "\x55\xbb\x16\x7e\xf7\xc2\x8c\xa4"
-			  "\x40\x1d\xe5\xef\x0e\xdf\xe4\x9a"
-			  "\x62\x73\x65\xfd\x46\x63\x25\x3d"
-			  "\x2b\xaf\xe5\x64\xfe\xa5\x5c\xcf"
-			  "\x24\xf3\xb4\xac\x64\xba\xdf\x4b"
-			  "\xc6\x96\x7d\x81\x2d\x8d\x97\xf7"
-			  "\xc5\x68\x77\x84\x32\x2b\xcc\x85"
-			  "\x74\x96\xf0\x12\x77\x61\xb9\xeb"
-			  "\x71\xaa\x82\xcb\x1c\xdb\x89\xc8"
-			  "\xc6\xb5\xe3\x5c\x7d\x39\x07\x24"
-			  "\xda\x39\x87\x45\xc0\x2b\xbb\x01"
-			  "\xac\xbc\x2a\x5c\x7f\xfc\xe8\xce"
-			  "\x6d\x9c\x6f\xed\xd3\xc1\xa1\xd6"
-			  "\xc5\x55\xa9\x66\x2f\xe1\xc8\x32"
-			  "\xa6\x5d\xa4\x3a\x98\x73\xe8\x45"
-			  "\xa4\xc7\xa8\xb4\xf6\x13\x03\xf6"
-			  "\xe9\x2e\xc4\x29\x0f\x84\xdb\xc4"
-			  "\x21\xc4\xc2\x75\x67\x89\x37\x0a",
-		.rlen   = 512,
-	}
-};
-
-static struct cipher_testvec aes_xts_enc_tv_template[] = {
-	/* http://grouper.ieee.org/groups/1619/email/pdf00086.pdf */
-	{ /* XTS-AES 1 */
-		.key    = "\x00\x00\x00\x00\x00\x00\x00\x00"
-			  "\x00\x00\x00\x00\x00\x00\x00\x00"
-			  "\x00\x00\x00\x00\x00\x00\x00\x00"
-			  "\x00\x00\x00\x00\x00\x00\x00\x00",
-		.klen   = 32,
-		.iv     = "\x00\x00\x00\x00\x00\x00\x00\x00"
-			  "\x00\x00\x00\x00\x00\x00\x00\x00",
-		.input  = "\x00\x00\x00\x00\x00\x00\x00\x00"
-			  "\x00\x00\x00\x00\x00\x00\x00\x00"
-			  "\x00\x00\x00\x00\x00\x00\x00\x00"
-			  "\x00\x00\x00\x00\x00\x00\x00\x00",
-		.ilen   = 32,
-		.result = "\x91\x7c\xf6\x9e\xbd\x68\xb2\xec"
-			  "\x9b\x9f\xe9\xa3\xea\xdd\xa6\x92"
-			  "\xcd\x43\xd2\xf5\x95\x98\xed\x85"
-			  "\x8c\x02\xc2\x65\x2f\xbf\x92\x2e",
-		.rlen   = 32,
-	}, { /* XTS-AES 2 */
-		.key    = "\x11\x11\x11\x11\x11\x11\x11\x11"
-			  "\x11\x11\x11\x11\x11\x11\x11\x11"
-			  "\x22\x22\x22\x22\x22\x22\x22\x22"
-			  "\x22\x22\x22\x22\x22\x22\x22\x22",
-		.klen   = 32,
-		.iv     = "\x33\x33\x33\x33\x33\x00\x00\x00"
-			  "\x00\x00\x00\x00\x00\x00\x00\x00",
-		.input  = "\x44\x44\x44\x44\x44\x44\x44\x44"
-			  "\x44\x44\x44\x44\x44\x44\x44\x44"
-			  "\x44\x44\x44\x44\x44\x44\x44\x44"
-			  "\x44\x44\x44\x44\x44\x44\x44\x44",
-		.ilen   = 32,
-		.result = "\xc4\x54\x18\x5e\x6a\x16\x93\x6e"
-			  "\x39\x33\x40\x38\xac\xef\x83\x8b"
-			  "\xfb\x18\x6f\xff\x74\x80\xad\xc4"
-			  "\x28\x93\x82\xec\xd6\xd3\x94\xf0",
-		.rlen   = 32,
-	}, { /* XTS-AES 3 */
-		.key    = "\xff\xfe\xfd\xfc\xfb\xfa\xf9\xf8"
-			  "\xf7\xf6\xf5\xf4\xf3\xf2\xf1\xf0"
-			  "\x22\x22\x22\x22\x22\x22\x22\x22"
-			  "\x22\x22\x22\x22\x22\x22\x22\x22",
-		.klen   = 32,
-		.iv     = "\x33\x33\x33\x33\x33\x00\x00\x00"
-			  "\x00\x00\x00\x00\x00\x00\x00\x00",
-		.input  = "\x44\x44\x44\x44\x44\x44\x44\x44"
-			  "\x44\x44\x44\x44\x44\x44\x44\x44"
-			  "\x44\x44\x44\x44\x44\x44\x44\x44"
-			  "\x44\x44\x44\x44\x44\x44\x44\x44",
-		.ilen   = 32,
-		.result = "\xaf\x85\x33\x6b\x59\x7a\xfc\x1a"
-			  "\x90\x0b\x2e\xb2\x1e\xc9\x49\xd2"
-			  "\x92\xdf\x4c\x04\x7e\x0b\x21\x53"
-			  "\x21\x86\xa5\x97\x1a\x22\x7a\x89",
-		.rlen   = 32,
-	}, { /* XTS-AES 4 */
-		.key    = "\x27\x18\x28\x18\x28\x45\x90\x45"
-			  "\x23\x53\x60\x28\x74\x71\x35\x26"
-			  "\x31\x41\x59\x26\x53\x58\x97\x93"
-			  "\x23\x84\x62\x64\x33\x83\x27\x95",
-		.klen   = 32,
-		.iv     = "\x00\x00\x00\x00\x00\x00\x00\x00"
-			  "\x00\x00\x00\x00\x00\x00\x00\x00",
-		.input  = "\x00\x01\x02\x03\x04\x05\x06\x07"
-			  "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
-			  "\x10\x11\x12\x13\x14\x15\x16\x17"
-			  "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
-			  "\x20\x21\x22\x23\x24\x25\x26\x27"
-			  "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f"
-			  "\x30\x31\x32\x33\x34\x35\x36\x37"
-			  "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f"
-			  "\x40\x41\x42\x43\x44\x45\x46\x47"
-			  "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f"
-			  "\x50\x51\x52\x53\x54\x55\x56\x57"
-			  "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f"
-			  "\x60\x61\x62\x63\x64\x65\x66\x67"
-			  "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f"
-			  "\x70\x71\x72\x73\x74\x75\x76\x77"
-			  "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f"
-			  "\x80\x81\x82\x83\x84\x85\x86\x87"
-			  "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"
-			  "\x90\x91\x92\x93\x94\x95\x96\x97"
-			  "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f"
-			  "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7"
-			  "\xa8\xa9\xaa\xab\xac\xad\xae\xaf"
-			  "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7"
-			  "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf"
-			  "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7"
-			  "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf"
-			  "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7"
-			  "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf"
-			  "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7"
-			  "\xe8\xe9\xea\xeb\xec\xed\xee\xef"
-			  "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7"
-			  "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff"
-			  "\x00\x01\x02\x03\x04\x05\x06\x07"
-			  "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
-			  "\x10\x11\x12\x13\x14\x15\x16\x17"
-			  "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
-			  "\x20\x21\x22\x23\x24\x25\x26\x27"
-			  "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f"
-			  "\x30\x31\x32\x33\x34\x35\x36\x37"
-			  "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f"
-			  "\x40\x41\x42\x43\x44\x45\x46\x47"
-			  "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f"
-			  "\x50\x51\x52\x53\x54\x55\x56\x57"
-			  "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f"
-			  "\x60\x61\x62\x63\x64\x65\x66\x67"
-			  "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f"
-			  "\x70\x71\x72\x73\x74\x75\x76\x77"
-			  "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f"
-			  "\x80\x81\x82\x83\x84\x85\x86\x87"
-			  "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"
-			  "\x90\x91\x92\x93\x94\x95\x96\x97"
-			  "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f"
-			  "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7"
-			  "\xa8\xa9\xaa\xab\xac\xad\xae\xaf"
-			  "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7"
-			  "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf"
-			  "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7"
-			  "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf"
-			  "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7"
-			  "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf"
-			  "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7"
-			  "\xe8\xe9\xea\xeb\xec\xed\xee\xef"
-			  "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7"
-			  "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff",
-		.ilen   = 512,
-		.result = "\x27\xa7\x47\x9b\xef\xa1\xd4\x76"
-			  "\x48\x9f\x30\x8c\xd4\xcf\xa6\xe2"
-			  "\xa9\x6e\x4b\xbe\x32\x08\xff\x25"
-			  "\x28\x7d\xd3\x81\x96\x16\xe8\x9c"
-			  "\xc7\x8c\xf7\xf5\xe5\x43\x44\x5f"
-			  "\x83\x33\xd8\xfa\x7f\x56\x00\x00"
-			  "\x05\x27\x9f\xa5\xd8\xb5\xe4\xad"
-			  "\x40\xe7\x36\xdd\xb4\xd3\x54\x12"
-			  "\x32\x80\x63\xfd\x2a\xab\x53\xe5"
-			  "\xea\x1e\x0a\x9f\x33\x25\x00\xa5"
-			  "\xdf\x94\x87\xd0\x7a\x5c\x92\xcc"
-			  "\x51\x2c\x88\x66\xc7\xe8\x60\xce"
-			  "\x93\xfd\xf1\x66\xa2\x49\x12\xb4"
-			  "\x22\x97\x61\x46\xae\x20\xce\x84"
-			  "\x6b\xb7\xdc\x9b\xa9\x4a\x76\x7a"
-			  "\xae\xf2\x0c\x0d\x61\xad\x02\x65"
-			  "\x5e\xa9\x2d\xc4\xc4\xe4\x1a\x89"
-			  "\x52\xc6\x51\xd3\x31\x74\xbe\x51"
-			  "\xa1\x0c\x42\x11\x10\xe6\xd8\x15"
-			  "\x88\xed\xe8\x21\x03\xa2\x52\xd8"
-			  "\xa7\x50\xe8\x76\x8d\xef\xff\xed"
-			  "\x91\x22\x81\x0a\xae\xb9\x9f\x91"
-			  "\x72\xaf\x82\xb6\x04\xdc\x4b\x8e"
-			  "\x51\xbc\xb0\x82\x35\xa6\xf4\x34"
-			  "\x13\x32\xe4\xca\x60\x48\x2a\x4b"
-			  "\xa1\xa0\x3b\x3e\x65\x00\x8f\xc5"
-			  "\xda\x76\xb7\x0b\xf1\x69\x0d\xb4"
-			  "\xea\xe2\x9c\x5f\x1b\xad\xd0\x3c"
-			  "\x5c\xcf\x2a\x55\xd7\x05\xdd\xcd"
-			  "\x86\xd4\x49\x51\x1c\xeb\x7e\xc3"
-			  "\x0b\xf1\x2b\x1f\xa3\x5b\x91\x3f"
-			  "\x9f\x74\x7a\x8a\xfd\x1b\x13\x0e"
-			  "\x94\xbf\xf9\x4e\xff\xd0\x1a\x91"
-			  "\x73\x5c\xa1\x72\x6a\xcd\x0b\x19"
-			  "\x7c\x4e\x5b\x03\x39\x36\x97\xe1"
-			  "\x26\x82\x6f\xb6\xbb\xde\x8e\xcc"
-			  "\x1e\x08\x29\x85\x16\xe2\xc9\xed"
-			  "\x03\xff\x3c\x1b\x78\x60\xf6\xde"
-			  "\x76\xd4\xce\xcd\x94\xc8\x11\x98"
-			  "\x55\xef\x52\x97\xca\x67\xe9\xf3"
-			  "\xe7\xff\x72\xb1\xe9\x97\x85\xca"
-			  "\x0a\x7e\x77\x20\xc5\xb3\x6d\xc6"
-			  "\xd7\x2c\xac\x95\x74\xc8\xcb\xbc"
-			  "\x2f\x80\x1e\x23\xe5\x6f\xd3\x44"
-			  "\xb0\x7f\x22\x15\x4b\xeb\xa0\xf0"
-			  "\x8c\xe8\x89\x1e\x64\x3e\xd9\x95"
-			  "\xc9\x4d\x9a\x69\xc9\xf1\xb5\xf4"
-			  "\x99\x02\x7a\x78\x57\x2a\xee\xbd"
-			  "\x74\xd2\x0c\xc3\x98\x81\xc2\x13"
-			  "\xee\x77\x0b\x10\x10\xe4\xbe\xa7"
-			  "\x18\x84\x69\x77\xae\x11\x9f\x7a"
-			  "\x02\x3a\xb5\x8c\xca\x0a\xd7\x52"
-			  "\xaf\xe6\x56\xbb\x3c\x17\x25\x6a"
-			  "\x9f\x6e\x9b\xf1\x9f\xdd\x5a\x38"
-			  "\xfc\x82\xbb\xe8\x72\xc5\x53\x9e"
-			  "\xdb\x60\x9e\xf4\xf7\x9c\x20\x3e"
-			  "\xbb\x14\x0f\x2e\x58\x3c\xb2\xad"
-			  "\x15\xb4\xaa\x5b\x65\x50\x16\xa8"
-			  "\x44\x92\x77\xdb\xd4\x77\xef\x2c"
-			  "\x8d\x6c\x01\x7d\xb7\x38\xb1\x8d"
-			  "\xeb\x4a\x42\x7d\x19\x23\xce\x3f"
-			  "\xf2\x62\x73\x57\x79\xa4\x18\xf2"
-			  "\x0a\x28\x2d\xf9\x20\x14\x7b\xea"
-			  "\xbe\x42\x1e\xe5\x31\x9d\x05\x68",
-		.rlen   = 512,
-	}
-};
-
-static struct cipher_testvec aes_xts_dec_tv_template[] = {
-	/* http://grouper.ieee.org/groups/1619/email/pdf00086.pdf */
-	{ /* XTS-AES 1 */
-		.key    = "\x00\x00\x00\x00\x00\x00\x00\x00"
-			  "\x00\x00\x00\x00\x00\x00\x00\x00"
-			  "\x00\x00\x00\x00\x00\x00\x00\x00"
-			  "\x00\x00\x00\x00\x00\x00\x00\x00",
-		.klen   = 32,
-		.iv     = "\x00\x00\x00\x00\x00\x00\x00\x00"
-			  "\x00\x00\x00\x00\x00\x00\x00\x00",
-		.input = "\x91\x7c\xf6\x9e\xbd\x68\xb2\xec"
-			 "\x9b\x9f\xe9\xa3\xea\xdd\xa6\x92"
-			 "\xcd\x43\xd2\xf5\x95\x98\xed\x85"
-			 "\x8c\x02\xc2\x65\x2f\xbf\x92\x2e",
-		.ilen   = 32,
-		.result  = "\x00\x00\x00\x00\x00\x00\x00\x00"
-			   "\x00\x00\x00\x00\x00\x00\x00\x00"
-			   "\x00\x00\x00\x00\x00\x00\x00\x00"
-			   "\x00\x00\x00\x00\x00\x00\x00\x00",
-		.rlen   = 32,
-	}, { /* XTS-AES 2 */
-		.key    = "\x11\x11\x11\x11\x11\x11\x11\x11"
-			  "\x11\x11\x11\x11\x11\x11\x11\x11"
-			  "\x22\x22\x22\x22\x22\x22\x22\x22"
-			  "\x22\x22\x22\x22\x22\x22\x22\x22",
-		.klen   = 32,
-		.iv     = "\x33\x33\x33\x33\x33\x00\x00\x00"
-			  "\x00\x00\x00\x00\x00\x00\x00\x00",
-		.input  = "\xc4\x54\x18\x5e\x6a\x16\x93\x6e"
-			  "\x39\x33\x40\x38\xac\xef\x83\x8b"
-			  "\xfb\x18\x6f\xff\x74\x80\xad\xc4"
-			  "\x28\x93\x82\xec\xd6\xd3\x94\xf0",
-		.ilen   = 32,
-		.result = "\x44\x44\x44\x44\x44\x44\x44\x44"
-			  "\x44\x44\x44\x44\x44\x44\x44\x44"
-			  "\x44\x44\x44\x44\x44\x44\x44\x44"
-			  "\x44\x44\x44\x44\x44\x44\x44\x44",
-		.rlen   = 32,
-	}, { /* XTS-AES 3 */
-		.key    = "\xff\xfe\xfd\xfc\xfb\xfa\xf9\xf8"
-			  "\xf7\xf6\xf5\xf4\xf3\xf2\xf1\xf0"
-			  "\x22\x22\x22\x22\x22\x22\x22\x22"
-			  "\x22\x22\x22\x22\x22\x22\x22\x22",
-		.klen   = 32,
-		.iv     = "\x33\x33\x33\x33\x33\x00\x00\x00"
-			  "\x00\x00\x00\x00\x00\x00\x00\x00",
-		.input = "\xaf\x85\x33\x6b\x59\x7a\xfc\x1a"
-			  "\x90\x0b\x2e\xb2\x1e\xc9\x49\xd2"
-			  "\x92\xdf\x4c\x04\x7e\x0b\x21\x53"
-			  "\x21\x86\xa5\x97\x1a\x22\x7a\x89",
-		.ilen   = 32,
-		.result  = "\x44\x44\x44\x44\x44\x44\x44\x44"
-			  "\x44\x44\x44\x44\x44\x44\x44\x44"
-			  "\x44\x44\x44\x44\x44\x44\x44\x44"
-			  "\x44\x44\x44\x44\x44\x44\x44\x44",
-		.rlen   = 32,
-	}, { /* XTS-AES 4 */
-		.key    = "\x27\x18\x28\x18\x28\x45\x90\x45"
-			  "\x23\x53\x60\x28\x74\x71\x35\x26"
-			  "\x31\x41\x59\x26\x53\x58\x97\x93"
-			  "\x23\x84\x62\x64\x33\x83\x27\x95",
-		.klen   = 32,
-		.iv     = "\x00\x00\x00\x00\x00\x00\x00\x00"
-			  "\x00\x00\x00\x00\x00\x00\x00\x00",
-		.input  = "\x27\xa7\x47\x9b\xef\xa1\xd4\x76"
-			  "\x48\x9f\x30\x8c\xd4\xcf\xa6\xe2"
-			  "\xa9\x6e\x4b\xbe\x32\x08\xff\x25"
-			  "\x28\x7d\xd3\x81\x96\x16\xe8\x9c"
-			  "\xc7\x8c\xf7\xf5\xe5\x43\x44\x5f"
-			  "\x83\x33\xd8\xfa\x7f\x56\x00\x00"
-			  "\x05\x27\x9f\xa5\xd8\xb5\xe4\xad"
-			  "\x40\xe7\x36\xdd\xb4\xd3\x54\x12"
-			  "\x32\x80\x63\xfd\x2a\xab\x53\xe5"
-			  "\xea\x1e\x0a\x9f\x33\x25\x00\xa5"
-			  "\xdf\x94\x87\xd0\x7a\x5c\x92\xcc"
-			  "\x51\x2c\x88\x66\xc7\xe8\x60\xce"
-			  "\x93\xfd\xf1\x66\xa2\x49\x12\xb4"
-			  "\x22\x97\x61\x46\xae\x20\xce\x84"
-			  "\x6b\xb7\xdc\x9b\xa9\x4a\x76\x7a"
-			  "\xae\xf2\x0c\x0d\x61\xad\x02\x65"
-			  "\x5e\xa9\x2d\xc4\xc4\xe4\x1a\x89"
-			  "\x52\xc6\x51\xd3\x31\x74\xbe\x51"
-			  "\xa1\x0c\x42\x11\x10\xe6\xd8\x15"
-			  "\x88\xed\xe8\x21\x03\xa2\x52\xd8"
-			  "\xa7\x50\xe8\x76\x8d\xef\xff\xed"
-			  "\x91\x22\x81\x0a\xae\xb9\x9f\x91"
-			  "\x72\xaf\x82\xb6\x04\xdc\x4b\x8e"
-			  "\x51\xbc\xb0\x82\x35\xa6\xf4\x34"
-			  "\x13\x32\xe4\xca\x60\x48\x2a\x4b"
-			  "\xa1\xa0\x3b\x3e\x65\x00\x8f\xc5"
-			  "\xda\x76\xb7\x0b\xf1\x69\x0d\xb4"
-			  "\xea\xe2\x9c\x5f\x1b\xad\xd0\x3c"
-			  "\x5c\xcf\x2a\x55\xd7\x05\xdd\xcd"
-			  "\x86\xd4\x49\x51\x1c\xeb\x7e\xc3"
-			  "\x0b\xf1\x2b\x1f\xa3\x5b\x91\x3f"
-			  "\x9f\x74\x7a\x8a\xfd\x1b\x13\x0e"
-			  "\x94\xbf\xf9\x4e\xff\xd0\x1a\x91"
-			  "\x73\x5c\xa1\x72\x6a\xcd\x0b\x19"
-			  "\x7c\x4e\x5b\x03\x39\x36\x97\xe1"
-			  "\x26\x82\x6f\xb6\xbb\xde\x8e\xcc"
-			  "\x1e\x08\x29\x85\x16\xe2\xc9\xed"
-			  "\x03\xff\x3c\x1b\x78\x60\xf6\xde"
-			  "\x76\xd4\xce\xcd\x94\xc8\x11\x98"
-			  "\x55\xef\x52\x97\xca\x67\xe9\xf3"
-			  "\xe7\xff\x72\xb1\xe9\x97\x85\xca"
-			  "\x0a\x7e\x77\x20\xc5\xb3\x6d\xc6"
-			  "\xd7\x2c\xac\x95\x74\xc8\xcb\xbc"
-			  "\x2f\x80\x1e\x23\xe5\x6f\xd3\x44"
-			  "\xb0\x7f\x22\x15\x4b\xeb\xa0\xf0"
-			  "\x8c\xe8\x89\x1e\x64\x3e\xd9\x95"
-			  "\xc9\x4d\x9a\x69\xc9\xf1\xb5\xf4"
-			  "\x99\x02\x7a\x78\x57\x2a\xee\xbd"
-			  "\x74\xd2\x0c\xc3\x98\x81\xc2\x13"
-			  "\xee\x77\x0b\x10\x10\xe4\xbe\xa7"
-			  "\x18\x84\x69\x77\xae\x11\x9f\x7a"
-			  "\x02\x3a\xb5\x8c\xca\x0a\xd7\x52"
-			  "\xaf\xe6\x56\xbb\x3c\x17\x25\x6a"
-			  "\x9f\x6e\x9b\xf1\x9f\xdd\x5a\x38"
-			  "\xfc\x82\xbb\xe8\x72\xc5\x53\x9e"
-			  "\xdb\x60\x9e\xf4\xf7\x9c\x20\x3e"
-			  "\xbb\x14\x0f\x2e\x58\x3c\xb2\xad"
-			  "\x15\xb4\xaa\x5b\x65\x50\x16\xa8"
-			  "\x44\x92\x77\xdb\xd4\x77\xef\x2c"
-			  "\x8d\x6c\x01\x7d\xb7\x38\xb1\x8d"
-			  "\xeb\x4a\x42\x7d\x19\x23\xce\x3f"
-			  "\xf2\x62\x73\x57\x79\xa4\x18\xf2"
-			  "\x0a\x28\x2d\xf9\x20\x14\x7b\xea"
-			  "\xbe\x42\x1e\xe5\x31\x9d\x05\x68",
-		.ilen   = 512,
-		.result = "\x00\x01\x02\x03\x04\x05\x06\x07"
-			  "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
-			  "\x10\x11\x12\x13\x14\x15\x16\x17"
-			  "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
-			  "\x20\x21\x22\x23\x24\x25\x26\x27"
-			  "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f"
-			  "\x30\x31\x32\x33\x34\x35\x36\x37"
-			  "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f"
-			  "\x40\x41\x42\x43\x44\x45\x46\x47"
-			  "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f"
-			  "\x50\x51\x52\x53\x54\x55\x56\x57"
-			  "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f"
-			  "\x60\x61\x62\x63\x64\x65\x66\x67"
-			  "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f"
-			  "\x70\x71\x72\x73\x74\x75\x76\x77"
-			  "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f"
-			  "\x80\x81\x82\x83\x84\x85\x86\x87"
-			  "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"
-			  "\x90\x91\x92\x93\x94\x95\x96\x97"
-			  "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f"
-			  "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7"
-			  "\xa8\xa9\xaa\xab\xac\xad\xae\xaf"
-			  "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7"
-			  "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf"
-			  "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7"
-			  "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf"
-			  "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7"
-			  "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf"
-			  "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7"
-			  "\xe8\xe9\xea\xeb\xec\xed\xee\xef"
-			  "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7"
-			  "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff"
-			  "\x00\x01\x02\x03\x04\x05\x06\x07"
-			  "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
-			  "\x10\x11\x12\x13\x14\x15\x16\x17"
-			  "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
-			  "\x20\x21\x22\x23\x24\x25\x26\x27"
-			  "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f"
-			  "\x30\x31\x32\x33\x34\x35\x36\x37"
-			  "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f"
-			  "\x40\x41\x42\x43\x44\x45\x46\x47"
-			  "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f"
-			  "\x50\x51\x52\x53\x54\x55\x56\x57"
-			  "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f"
-			  "\x60\x61\x62\x63\x64\x65\x66\x67"
-			  "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f"
-			  "\x70\x71\x72\x73\x74\x75\x76\x77"
-			  "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f"
-			  "\x80\x81\x82\x83\x84\x85\x86\x87"
-			  "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"
-			  "\x90\x91\x92\x93\x94\x95\x96\x97"
-			  "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f"
-			  "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7"
-			  "\xa8\xa9\xaa\xab\xac\xad\xae\xaf"
-			  "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7"
-			  "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf"
-			  "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7"
-			  "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf"
-			  "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7"
-			  "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf"
-			  "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7"
-			  "\xe8\xe9\xea\xeb\xec\xed\xee\xef"
-			  "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7"
-			  "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff",
-		.rlen   = 512,
-	}
-};
-
-
-static struct cipher_testvec aes_ctr_enc_tv_template[] = {
-	{ /* From RFC 3686 */
-		.key	= "\xae\x68\x52\xf8\x12\x10\x67\xcc"
-			  "\x4b\xf7\xa5\x76\x55\x77\xf3\x9e"
-			  "\x00\x00\x00\x30",
-		.klen	= 20,
-		.iv	= "\x00\x00\x00\x00\x00\x00\x00\x00",
-		.input	= "Single block msg",
-		.ilen	= 16,
-		.result = "\xe4\x09\x5d\x4f\xb7\xa7\xb3\x79"
-			  "\x2d\x61\x75\xa3\x26\x13\x11\xb8",
-		.rlen	= 16,
-	}, {
-		.key	= "\x7e\x24\x06\x78\x17\xfa\xe0\xd7"
-			  "\x43\xd6\xce\x1f\x32\x53\x91\x63"
-			  "\x00\x6c\xb6\xdb",
-		.klen	= 20,
-		.iv	= "\xc0\x54\x3b\x59\xda\x48\xd9\x0b",
-		.input	= "\x00\x01\x02\x03\x04\x05\x06\x07"
-			  "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
-			  "\x10\x11\x12\x13\x14\x15\x16\x17"
-			  "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f",
-		.ilen	= 32,
-		.result = "\x51\x04\xa1\x06\x16\x8a\x72\xd9"
-			  "\x79\x0d\x41\xee\x8e\xda\xd3\x88"
-			  "\xeb\x2e\x1e\xfc\x46\xda\x57\xc8"
-			  "\xfc\xe6\x30\xdf\x91\x41\xbe\x28",
-		.rlen	= 32,
-	}, {
-		.key	= "\x16\xaf\x5b\x14\x5f\xc9\xf5\x79"
-			  "\xc1\x75\xf9\x3e\x3b\xfb\x0e\xed"
-			  "\x86\x3d\x06\xcc\xfd\xb7\x85\x15"
-			  "\x00\x00\x00\x48",
-		.klen	= 28,
-		.iv	= "\x36\x73\x3c\x14\x7d\x6d\x93\xcb",
-		.input	= "Single block msg",
-		.ilen	= 16,
-		.result	= "\x4b\x55\x38\x4f\xe2\x59\xc9\xc8"
-			  "\x4e\x79\x35\xa0\x03\xcb\xe9\x28",
-		.rlen	= 16,
-	}, {
-		.key	= "\x7c\x5c\xb2\x40\x1b\x3d\xc3\x3c"
-			  "\x19\xe7\x34\x08\x19\xe0\xf6\x9c"
-			  "\x67\x8c\x3d\xb8\xe6\xf6\xa9\x1a"
-			  "\x00\x96\xb0\x3b",
-		.klen	= 28,
-		.iv	= "\x02\x0c\x6e\xad\xc2\xcb\x50\x0d",
-		.input	= "\x00\x01\x02\x03\x04\x05\x06\x07"
-			  "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
-			  "\x10\x11\x12\x13\x14\x15\x16\x17"
-			  "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f",
-		.ilen	= 32,
-		.result	= "\x45\x32\x43\xfc\x60\x9b\x23\x32"
-			  "\x7e\xdf\xaa\xfa\x71\x31\xcd\x9f"
-			  "\x84\x90\x70\x1c\x5a\xd4\xa7\x9c"
-			  "\xfc\x1f\xe0\xff\x42\xf4\xfb\x00",
-		.rlen	= 32,
-	}, {
-		.key	= "\x77\x6b\xef\xf2\x85\x1d\xb0\x6f"
-			  "\x4c\x8a\x05\x42\xc8\x69\x6f\x6c"
-			  "\x6a\x81\xaf\x1e\xec\x96\xb4\xd3"
-			  "\x7f\xc1\xd6\x89\xe6\xc1\xc1\x04"
-			  "\x00\x00\x00\x60",
-		.klen	= 36,
-		.iv	= "\xdb\x56\x72\xc9\x7a\xa8\xf0\xb2",
-		.input	= "Single block msg",
-		.ilen	= 16,
-		.result = "\x14\x5a\xd0\x1d\xbf\x82\x4e\xc7"
-			  "\x56\x08\x63\xdc\x71\xe3\xe0\xc0",
-		.rlen	= 16,
-	}, {
-		.key	= "\xf6\xd6\x6d\x6b\xd5\x2d\x59\xbb"
-			  "\x07\x96\x36\x58\x79\xef\xf8\x86"
-			  "\xc6\x6d\xd5\x1a\x5b\x6a\x99\x74"
-			  "\x4b\x50\x59\x0c\x87\xa2\x38\x84"
-			  "\x00\xfa\xac\x24",
-		.klen	= 36,
-		.iv	= "\xc1\x58\x5e\xf1\x5a\x43\xd8\x75",
-		.input	= "\x00\x01\x02\x03\x04\x05\x06\x07"
-			  "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
-			  "\x10\x11\x12\x13\x14\x15\x16\x17"
-			  "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f",
-		.ilen	= 32,
-		.result = "\xf0\x5e\x23\x1b\x38\x94\x61\x2c"
-			  "\x49\xee\x00\x0b\x80\x4e\xb2\xa9"
-			  "\xb8\x30\x6b\x50\x8f\x83\x9d\x6a"
-			  "\x55\x30\x83\x1d\x93\x44\xaf\x1c",
-		.rlen	= 32,
-	}, {
-	// generated using Crypto++
-		.key = "\x00\x01\x02\x03\x04\x05\x06\x07"
-			"\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
-			"\x10\x11\x12\x13\x14\x15\x16\x17"
-			"\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
-			"\x00\x00\x00\x00",
-		.klen = 32 + 4,
-		.iv = "\x00\x00\x00\x00\x00\x00\x00\x00",
-		.input =
-			"\x00\x01\x02\x03\x04\x05\x06\x07"
-			"\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
-			"\x10\x11\x12\x13\x14\x15\x16\x17"
-			"\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
-			"\x20\x21\x22\x23\x24\x25\x26\x27"
-			"\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f"
-			"\x30\x31\x32\x33\x34\x35\x36\x37"
-			"\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f"
-			"\x40\x41\x42\x43\x44\x45\x46\x47"
-			"\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f"
-			"\x50\x51\x52\x53\x54\x55\x56\x57"
-			"\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f"
-			"\x60\x61\x62\x63\x64\x65\x66\x67"
-			"\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f"
-			"\x70\x71\x72\x73\x74\x75\x76\x77"
-			"\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f"
-			"\x80\x81\x82\x83\x84\x85\x86\x87"
-			"\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"
-			"\x90\x91\x92\x93\x94\x95\x96\x97"
-			"\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f"
-			"\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7"
-			"\xa8\xa9\xaa\xab\xac\xad\xae\xaf"
-			"\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7"
-			"\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf"
-			"\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7"
-			"\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf"
-			"\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7"
-			"\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf"
-			"\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7"
-			"\xe8\xe9\xea\xeb\xec\xed\xee\xef"
-			"\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7"
-			"\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff"
-			"\x00\x03\x06\x09\x0c\x0f\x12\x15"
-			"\x18\x1b\x1e\x21\x24\x27\x2a\x2d"
-			"\x30\x33\x36\x39\x3c\x3f\x42\x45"
-			"\x48\x4b\x4e\x51\x54\x57\x5a\x5d"
-			"\x60\x63\x66\x69\x6c\x6f\x72\x75"
-			"\x78\x7b\x7e\x81\x84\x87\x8a\x8d"
-			"\x90\x93\x96\x99\x9c\x9f\xa2\xa5"
-			"\xa8\xab\xae\xb1\xb4\xb7\xba\xbd"
-			"\xc0\xc3\xc6\xc9\xcc\xcf\xd2\xd5"
-			"\xd8\xdb\xde\xe1\xe4\xe7\xea\xed"
-			"\xf0\xf3\xf6\xf9\xfc\xff\x02\x05"
-			"\x08\x0b\x0e\x11\x14\x17\x1a\x1d"
-			"\x20\x23\x26\x29\x2c\x2f\x32\x35"
-			"\x38\x3b\x3e\x41\x44\x47\x4a\x4d"
-			"\x50\x53\x56\x59\x5c\x5f\x62\x65"
-			"\x68\x6b\x6e\x71\x74\x77\x7a\x7d"
-			"\x80\x83\x86\x89\x8c\x8f\x92\x95"
-			"\x98\x9b\x9e\xa1\xa4\xa7\xaa\xad"
-			"\xb0\xb3\xb6\xb9\xbc\xbf\xc2\xc5"
-			"\xc8\xcb\xce\xd1\xd4\xd7\xda\xdd"
-			"\xe0\xe3\xe6\xe9\xec\xef\xf2\xf5"
-			"\xf8\xfb\xfe\x01\x04\x07\x0a\x0d"
-			"\x10\x13\x16\x19\x1c\x1f\x22\x25"
-			"\x28\x2b\x2e\x31\x34\x37\x3a\x3d"
-			"\x40\x43\x46\x49\x4c\x4f\x52\x55"
-			"\x58\x5b\x5e\x61\x64\x67\x6a\x6d"
-			"\x70\x73\x76\x79\x7c\x7f\x82\x85"
-			"\x88\x8b\x8e\x91\x94\x97\x9a\x9d"
-			"\xa0\xa3\xa6\xa9\xac\xaf\xb2\xb5"
-			"\xb8\xbb\xbe\xc1\xc4\xc7\xca\xcd"
-			"\xd0\xd3\xd6\xd9\xdc\xdf\xe2\xe5"
-			"\xe8\xeb\xee\xf1\xf4\xf7\xfa\xfd"
-			"\x00\x05\x0a\x0f\x14\x19\x1e\x23"
-			"\x28\x2d\x32\x37\x3c\x41\x46\x4b"
-			"\x50\x55\x5a\x5f\x64\x69\x6e\x73"
-			"\x78\x7d\x82\x87\x8c\x91\x96\x9b"
-			"\xa0\xa5\xaa\xaf\xb4\xb9\xbe\xc3"
-			"\xc8\xcd\xd2\xd7\xdc\xe1\xe6\xeb"
-			"\xf0\xf5\xfa\xff\x04\x09\x0e\x13"
-			"\x18\x1d\x22\x27\x2c\x31\x36\x3b"
-			"\x40\x45\x4a\x4f\x54\x59\x5e\x63"
-			"\x68\x6d\x72\x77\x7c\x81\x86\x8b"
-			"\x90\x95\x9a\x9f\xa4\xa9\xae\xb3"
-			"\xb8\xbd\xc2\xc7\xcc\xd1\xd6\xdb"
-			"\xe0\xe5\xea\xef\xf4\xf9\xfe\x03"
-			"\x08\x0d\x12\x17\x1c\x21\x26\x2b"
-			"\x30\x35\x3a\x3f\x44\x49\x4e\x53"
-			"\x58\x5d\x62\x67\x6c\x71\x76\x7b"
-			"\x80\x85\x8a\x8f\x94\x99\x9e\xa3"
-			"\xa8\xad\xb2\xb7\xbc\xc1\xc6\xcb"
-			"\xd0\xd5\xda\xdf\xe4\xe9\xee\xf3"
-			"\xf8\xfd\x02\x07\x0c\x11\x16\x1b"
-			"\x20\x25\x2a\x2f\x34\x39\x3e\x43"
-			"\x48\x4d\x52\x57\x5c\x61\x66\x6b"
-			"\x70\x75\x7a\x7f\x84\x89\x8e\x93"
-			"\x98\x9d\xa2\xa7\xac\xb1\xb6\xbb"
-			"\xc0\xc5\xca\xcf\xd4\xd9\xde\xe3"
-			"\xe8\xed\xf2\xf7\xfc\x01\x06\x0b"
-			"\x10\x15\x1a\x1f\x24\x29\x2e\x33"
-			"\x38\x3d\x42\x47\x4c\x51\x56\x5b"
-			"\x60\x65\x6a\x6f\x74\x79\x7e\x83"
-			"\x88\x8d\x92\x97\x9c\xa1\xa6\xab"
-			"\xb0\xb5\xba\xbf\xc4\xc9\xce\xd3"
-			"\xd8\xdd\xe2\xe7\xec\xf1\xf6\xfb"
-			"\x00\x07\x0e\x15\x1c\x23\x2a\x31"
-			"\x38\x3f\x46\x4d\x54\x5b\x62\x69"
-			"\x70\x77\x7e\x85\x8c\x93\x9a\xa1"
-			"\xa8\xaf\xb6\xbd\xc4\xcb\xd2\xd9"
-			"\xe0\xe7\xee\xf5\xfc\x03\x0a\x11"
-			"\x18\x1f\x26\x2d\x34\x3b\x42\x49"
-			"\x50\x57\x5e\x65\x6c\x73\x7a\x81"
-			"\x88\x8f\x96\x9d\xa4\xab\xb2\xb9"
-			"\xc0\xc7\xce\xd5\xdc\xe3\xea\xf1"
-			"\xf8\xff\x06\x0d\x14\x1b\x22\x29"
-			"\x30\x37\x3e\x45\x4c\x53\x5a\x61"
-			"\x68\x6f\x76\x7d\x84\x8b\x92\x99"
-			"\xa0\xa7\xae\xb5\xbc\xc3\xca\xd1"
-			"\xd8\xdf\xe6\xed\xf4\xfb\x02\x09"
-			"\x10\x17\x1e\x25\x2c\x33\x3a\x41"
-			"\x48\x4f\x56\x5d\x64\x6b\x72\x79"
-			"\x80\x87\x8e\x95\x9c\xa3\xaa\xb1"
-			"\xb8\xbf\xc6\xcd\xd4\xdb\xe2\xe9"
-			"\xf0\xf7\xfe\x05\x0c\x13\x1a\x21"
-			"\x28\x2f\x36\x3d\x44\x4b\x52\x59"
-			"\x60\x67\x6e\x75\x7c\x83\x8a\x91"
-			"\x98\x9f\xa6\xad\xb4\xbb\xc2\xc9"
-			"\xd0\xd7\xde\xe5\xec\xf3\xfa\x01"
-			"\x08\x0f\x16\x1d\x24\x2b\x32\x39"
-			"\x40\x47\x4e\x55\x5c\x63\x6a\x71"
-			"\x78\x7f\x86\x8d\x94\x9b\xa2\xa9"
-			"\xb0\xb7\xbe\xc5\xcc\xd3\xda\xe1"
-			"\xe8\xef\xf6\xfd\x04\x0b\x12\x19"
-			"\x20\x27\x2e\x35\x3c\x43\x4a\x51"
-			"\x58\x5f\x66\x6d\x74\x7b\x82\x89"
-			"\x90\x97\x9e\xa5\xac\xb3\xba\xc1"
-			"\xc8\xcf\xd6\xdd\xe4\xeb\xf2\xf9"
-			"\x00\x09\x12\x1b\x24\x2d\x36\x3f"
-			"\x48\x51\x5a\x63\x6c\x75\x7e\x87"
-			"\x90\x99\xa2\xab\xb4\xbd\xc6\xcf"
-			"\xd8\xe1\xea\xf3\xfc\x05\x0e\x17"
-			"\x20\x29\x32\x3b\x44\x4d\x56\x5f"
-			"\x68\x71\x7a\x83\x8c\x95\x9e\xa7"
-			"\xb0\xb9\xc2\xcb\xd4\xdd\xe6\xef"
-			"\xf8\x01\x0a\x13\x1c\x25\x2e\x37"
-			"\x40\x49\x52\x5b\x64\x6d\x76\x7f"
-			"\x88\x91\x9a\xa3\xac\xb5\xbe\xc7"
-			"\xd0\xd9\xe2\xeb\xf4\xfd\x06\x0f"
-			"\x18\x21\x2a\x33\x3c\x45\x4e\x57"
-			"\x60\x69\x72\x7b\x84\x8d\x96\x9f"
-			"\xa8\xb1\xba\xc3\xcc\xd5\xde\xe7"
-			"\xf0\xf9\x02\x0b\x14\x1d\x26\x2f"
-			"\x38\x41\x4a\x53\x5c\x65\x6e\x77"
-			"\x80\x89\x92\x9b\xa4\xad\xb6\xbf"
-			"\xc8\xd1\xda\xe3\xec\xf5\xfe\x07"
-			"\x10\x19\x22\x2b\x34\x3d\x46\x4f"
-			"\x58\x61\x6a\x73\x7c\x85\x8e\x97"
-			"\xa0\xa9\xb2\xbb\xc4\xcd\xd6\xdf"
-			"\xe8\xf1\xfa\x03\x0c\x15\x1e\x27"
-			"\x30\x39\x42\x4b\x54\x5d\x66\x6f"
-			"\x78\x81\x8a\x93\x9c\xa5\xae\xb7"
-			"\xc0\xc9\xd2\xdb\xe4\xed\xf6\xff"
-			"\x08\x11\x1a\x23\x2c\x35\x3e\x47"
-			"\x50\x59\x62\x6b\x74\x7d\x86\x8f"
-			"\x98\xa1\xaa\xb3\xbc\xc5\xce\xd7"
-			"\xe0\xe9\xf2\xfb\x04\x0d\x16\x1f"
-			"\x28\x31\x3a\x43\x4c\x55\x5e\x67"
-			"\x70\x79\x82\x8b\x94\x9d\xa6\xaf"
-			"\xb8\xc1\xca\xd3\xdc\xe5\xee\xf7"
-			"\x00\x0b\x16\x21\x2c\x37\x42\x4d"
-			"\x58\x63\x6e\x79\x84\x8f\x9a\xa5"
-			"\xb0\xbb\xc6\xd1\xdc\xe7\xf2\xfd"
-			"\x08\x13\x1e\x29\x34\x3f\x4a\x55"
-			"\x60\x6b\x76\x81\x8c\x97\xa2\xad"
-			"\xb8\xc3\xce\xd9\xe4\xef\xfa\x05"
-			"\x10\x1b\x26\x31\x3c\x47\x52\x5d"
-			"\x68\x73\x7e\x89\x94\x9f\xaa\xb5"
-			"\xc0\xcb\xd6\xe1\xec\xf7\x02\x0d"
-			"\x18\x23\x2e\x39\x44\x4f\x5a\x65"
-			"\x70\x7b\x86\x91\x9c\xa7\xb2\xbd"
-			"\xc8\xd3\xde\xe9\xf4\xff\x0a\x15"
-			"\x20\x2b\x36\x41\x4c\x57\x62\x6d"
-			"\x78\x83\x8e\x99\xa4\xaf\xba\xc5"
-			"\xd0\xdb\xe6\xf1\xfc\x07\x12\x1d"
-			"\x28\x33\x3e\x49\x54\x5f\x6a\x75"
-			"\x80\x8b\x96\xa1\xac\xb7\xc2\xcd"
-			"\xd8\xe3\xee\xf9\x04\x0f\x1a\x25"
-			"\x30\x3b\x46\x51\x5c\x67\x72\x7d"
-			"\x88\x93\x9e\xa9\xb4\xbf\xca\xd5"
-			"\xe0\xeb\xf6\x01\x0c\x17\x22\x2d"
-			"\x38\x43\x4e\x59\x64\x6f\x7a\x85"
-			"\x90\x9b\xa6\xb1\xbc\xc7\xd2\xdd"
-			"\xe8\xf3\xfe\x09\x14\x1f\x2a\x35"
-			"\x40\x4b\x56\x61\x6c\x77\x82\x8d"
-			"\x98\xa3\xae\xb9\xc4\xcf\xda\xe5"
-			"\xf0\xfb\x06\x11\x1c\x27\x32\x3d"
-			"\x48\x53\x5e\x69\x74\x7f\x8a\x95"
-			"\xa0\xab\xb6\xc1\xcc\xd7\xe2\xed"
-			"\xf8\x03\x0e\x19\x24\x2f\x3a\x45"
-			"\x50\x5b\x66\x71\x7c\x87\x92\x9d"
-			"\xa8\xb3\xbe\xc9\xd4\xdf\xea\xf5"
-			"\x00\x0d\x1a\x27\x34\x41\x4e\x5b"
-			"\x68\x75\x82\x8f\x9c\xa9\xb6\xc3"
-			"\xd0\xdd\xea\xf7\x04\x11\x1e\x2b"
-			"\x38\x45\x52\x5f\x6c\x79\x86\x93"
-			"\xa0\xad\xba\xc7\xd4\xe1\xee\xfb"
-			"\x08\x15\x22\x2f\x3c\x49\x56\x63"
-			"\x70\x7d\x8a\x97\xa4\xb1\xbe\xcb"
-			"\xd8\xe5\xf2\xff\x0c\x19\x26\x33"
-			"\x40\x4d\x5a\x67\x74\x81\x8e\x9b"
-			"\xa8\xb5\xc2\xcf\xdc\xe9\xf6\x03"
-			"\x10\x1d\x2a\x37\x44\x51\x5e\x6b"
-			"\x78\x85\x92\x9f\xac\xb9\xc6\xd3"
-			"\xe0\xed\xfa\x07\x14\x21\x2e\x3b"
-			"\x48\x55\x62\x6f\x7c\x89\x96\xa3"
-			"\xb0\xbd\xca\xd7\xe4\xf1\xfe\x0b"
-			"\x18\x25\x32\x3f\x4c\x59\x66\x73"
-			"\x80\x8d\x9a\xa7\xb4\xc1\xce\xdb"
-			"\xe8\xf5\x02\x0f\x1c\x29\x36\x43"
-			"\x50\x5d\x6a\x77\x84\x91\x9e\xab"
-			"\xb8\xc5\xd2\xdf\xec\xf9\x06\x13"
-			"\x20\x2d\x3a\x47\x54\x61\x6e\x7b"
-			"\x88\x95\xa2\xaf\xbc\xc9\xd6\xe3"
-			"\xf0\xfd\x0a\x17\x24\x31\x3e\x4b"
-			"\x58\x65\x72\x7f\x8c\x99\xa6\xb3"
-			"\xc0\xcd\xda\xe7\xf4\x01\x0e\x1b"
-			"\x28\x35\x42\x4f\x5c\x69\x76\x83"
-			"\x90\x9d\xaa\xb7\xc4\xd1\xde\xeb"
-			"\xf8\x05\x12\x1f\x2c\x39\x46\x53"
-			"\x60\x6d\x7a\x87\x94\xa1\xae\xbb"
-			"\xc8\xd5\xe2\xef\xfc\x09\x16\x23"
-			"\x30\x3d\x4a\x57\x64\x71\x7e\x8b"
-			"\x98\xa5\xb2\xbf\xcc\xd9\xe6\xf3"
-			"\x00\x0f\x1e\x2d\x3c\x4b\x5a\x69"
-			"\x78\x87\x96\xa5\xb4\xc3\xd2\xe1"
-			"\xf0\xff\x0e\x1d\x2c\x3b\x4a\x59"
-			"\x68\x77\x86\x95\xa4\xb3\xc2\xd1"
-			"\xe0\xef\xfe\x0d\x1c\x2b\x3a\x49"
-			"\x58\x67\x76\x85\x94\xa3\xb2\xc1"
-			"\xd0\xdf\xee\xfd\x0c\x1b\x2a\x39"
-			"\x48\x57\x66\x75\x84\x93\xa2\xb1"
-			"\xc0\xcf\xde\xed\xfc\x0b\x1a\x29"
-			"\x38\x47\x56\x65\x74\x83\x92\xa1"
-			"\xb0\xbf\xce\xdd\xec\xfb\x0a\x19"
-			"\x28\x37\x46\x55\x64\x73\x82\x91"
-			"\xa0\xaf\xbe\xcd\xdc\xeb\xfa\x09"
-			"\x18\x27\x36\x45\x54\x63\x72\x81"
-			"\x90\x9f\xae\xbd\xcc\xdb\xea\xf9"
-			"\x08\x17\x26\x35\x44\x53\x62\x71"
-			"\x80\x8f\x9e\xad\xbc\xcb\xda\xe9"
-			"\xf8\x07\x16\x25\x34\x43\x52\x61"
-			"\x70\x7f\x8e\x9d\xac\xbb\xca\xd9"
-			"\xe8\xf7\x06\x15\x24\x33\x42\x51"
-			"\x60\x6f\x7e\x8d\x9c\xab\xba\xc9"
-			"\xd8\xe7\xf6\x05\x14\x23\x32\x41"
-			"\x50\x5f\x6e\x7d\x8c\x9b\xaa\xb9"
-			"\xc8\xd7\xe6\xf5\x04\x13\x22\x31"
-			"\x40\x4f\x5e\x6d\x7c\x8b\x9a\xa9"
-			"\xb8\xc7\xd6\xe5\xf4\x03\x12\x21"
-			"\x30\x3f\x4e\x5d\x6c\x7b\x8a\x99"
-			"\xa8\xb7\xc6\xd5\xe4\xf3\x02\x11"
-			"\x20\x2f\x3e\x4d\x5c\x6b\x7a\x89"
-			"\x98\xa7\xb6\xc5\xd4\xe3\xf2\x01"
-			"\x10\x1f\x2e\x3d\x4c\x5b\x6a\x79"
-			"\x88\x97\xa6\xb5\xc4\xd3\xe2\xf1"
-			"\x00\x11\x22\x33\x44\x55\x66\x77"
-			"\x88\x99\xaa\xbb\xcc\xdd\xee\xff"
-			"\x10\x21\x32\x43\x54\x65\x76\x87"
-			"\x98\xa9\xba\xcb\xdc\xed\xfe\x0f"
-			"\x20\x31\x42\x53\x64\x75\x86\x97"
-			"\xa8\xb9\xca\xdb\xec\xfd\x0e\x1f"
-			"\x30\x41\x52\x63\x74\x85\x96\xa7"
-			"\xb8\xc9\xda\xeb\xfc\x0d\x1e\x2f"
-			"\x40\x51\x62\x73\x84\x95\xa6\xb7"
-			"\xc8\xd9\xea\xfb\x0c\x1d\x2e\x3f"
-			"\x50\x61\x72\x83\x94\xa5\xb6\xc7"
-			"\xd8\xe9\xfa\x0b\x1c\x2d\x3e\x4f"
-			"\x60\x71\x82\x93\xa4\xb5\xc6\xd7"
-			"\xe8\xf9\x0a\x1b\x2c\x3d\x4e\x5f"
-			"\x70\x81\x92\xa3\xb4\xc5\xd6\xe7"
-			"\xf8\x09\x1a\x2b\x3c\x4d\x5e\x6f"
-			"\x80\x91\xa2\xb3\xc4\xd5\xe6\xf7"
-			"\x08\x19\x2a\x3b\x4c\x5d\x6e\x7f"
-			"\x90\xa1\xb2\xc3\xd4\xe5\xf6\x07"
-			"\x18\x29\x3a\x4b\x5c\x6d\x7e\x8f"
-			"\xa0\xb1\xc2\xd3\xe4\xf5\x06\x17"
-			"\x28\x39\x4a\x5b\x6c\x7d\x8e\x9f"
-			"\xb0\xc1\xd2\xe3\xf4\x05\x16\x27"
-			"\x38\x49\x5a\x6b\x7c\x8d\x9e\xaf"
-			"\xc0\xd1\xe2\xf3\x04\x15\x26\x37"
-			"\x48\x59\x6a\x7b\x8c\x9d\xae\xbf"
-			"\xd0\xe1\xf2\x03\x14\x25\x36\x47"
-			"\x58\x69\x7a\x8b\x9c\xad\xbe\xcf"
-			"\xe0\xf1\x02\x13\x24\x35\x46\x57"
-			"\x68\x79\x8a\x9b\xac\xbd\xce\xdf"
-			"\xf0\x01\x12\x23\x34\x45\x56\x67"
-			"\x78\x89\x9a\xab\xbc\xcd\xde\xef"
-			"\x00\x13\x26\x39\x4c\x5f\x72\x85"
-			"\x98\xab\xbe\xd1\xe4\xf7\x0a\x1d"
-			"\x30\x43\x56\x69\x7c\x8f\xa2\xb5"
-			"\xc8\xdb\xee\x01\x14\x27\x3a\x4d"
-			"\x60\x73\x86\x99\xac\xbf\xd2\xe5"
-			"\xf8\x0b\x1e\x31\x44\x57\x6a\x7d"
-			"\x90\xa3\xb6\xc9\xdc\xef\x02\x15"
-			"\x28\x3b\x4e\x61\x74\x87\x9a\xad"
-			"\xc0\xd3\xe6\xf9\x0c\x1f\x32\x45"
-			"\x58\x6b\x7e\x91\xa4\xb7\xca\xdd"
-			"\xf0\x03\x16\x29\x3c\x4f\x62\x75"
-			"\x88\x9b\xae\xc1\xd4\xe7\xfa\x0d"
-			"\x20\x33\x46\x59\x6c\x7f\x92\xa5"
-			"\xb8\xcb\xde\xf1\x04\x17\x2a\x3d"
-			"\x50\x63\x76\x89\x9c\xaf\xc2\xd5"
-			"\xe8\xfb\x0e\x21\x34\x47\x5a\x6d"
-			"\x80\x93\xa6\xb9\xcc\xdf\xf2\x05"
-			"\x18\x2b\x3e\x51\x64\x77\x8a\x9d"
-			"\xb0\xc3\xd6\xe9\xfc\x0f\x22\x35"
-			"\x48\x5b\x6e\x81\x94\xa7\xba\xcd"
-			"\xe0\xf3\x06\x19\x2c\x3f\x52\x65"
-			"\x78\x8b\x9e\xb1\xc4\xd7\xea\xfd"
-			"\x10\x23\x36\x49\x5c\x6f\x82\x95"
-			"\xa8\xbb\xce\xe1\xf4\x07\x1a\x2d"
-			"\x40\x53\x66\x79\x8c\x9f\xb2\xc5"
-			"\xd8\xeb\xfe\x11\x24\x37\x4a\x5d"
-			"\x70\x83\x96\xa9\xbc\xcf\xe2\xf5"
-			"\x08\x1b\x2e\x41\x54\x67\x7a\x8d"
-			"\xa0\xb3\xc6\xd9\xec\xff\x12\x25"
-			"\x38\x4b\x5e\x71\x84\x97\xaa\xbd"
-			"\xd0\xe3\xf6\x09\x1c\x2f\x42\x55"
-			"\x68\x7b\x8e\xa1\xb4\xc7\xda\xed"
-			"\x00\x15\x2a\x3f\x54\x69\x7e\x93"
-			"\xa8\xbd\xd2\xe7\xfc\x11\x26\x3b"
-			"\x50\x65\x7a\x8f\xa4\xb9\xce\xe3"
-			"\xf8\x0d\x22\x37\x4c\x61\x76\x8b"
-			"\xa0\xb5\xca\xdf\xf4\x09\x1e\x33"
-			"\x48\x5d\x72\x87\x9c\xb1\xc6\xdb"
-			"\xf0\x05\x1a\x2f\x44\x59\x6e\x83"
-			"\x98\xad\xc2\xd7\xec\x01\x16\x2b"
-			"\x40\x55\x6a\x7f\x94\xa9\xbe\xd3"
-			"\xe8\xfd\x12\x27\x3c\x51\x66\x7b"
-			"\x90\xa5\xba\xcf\xe4\xf9\x0e\x23"
-			"\x38\x4d\x62\x77\x8c\xa1\xb6\xcb"
-			"\xe0\xf5\x0a\x1f\x34\x49\x5e\x73"
-			"\x88\x9d\xb2\xc7\xdc\xf1\x06\x1b"
-			"\x30\x45\x5a\x6f\x84\x99\xae\xc3"
-			"\xd8\xed\x02\x17\x2c\x41\x56\x6b"
-			"\x80\x95\xaa\xbf\xd4\xe9\xfe\x13"
-			"\x28\x3d\x52\x67\x7c\x91\xa6\xbb"
-			"\xd0\xe5\xfa\x0f\x24\x39\x4e\x63"
-			"\x78\x8d\xa2\xb7\xcc\xe1\xf6\x0b"
-			"\x20\x35\x4a\x5f\x74\x89\x9e\xb3"
-			"\xc8\xdd\xf2\x07\x1c\x31\x46\x5b"
-			"\x70\x85\x9a\xaf\xc4\xd9\xee\x03"
-			"\x18\x2d\x42\x57\x6c\x81\x96\xab"
-			"\xc0\xd5\xea\xff\x14\x29\x3e\x53"
-			"\x68\x7d\x92\xa7\xbc\xd1\xe6\xfb"
-			"\x10\x25\x3a\x4f\x64\x79\x8e\xa3"
-			"\xb8\xcd\xe2\xf7\x0c\x21\x36\x4b"
-			"\x60\x75\x8a\x9f\xb4\xc9\xde\xf3"
-			"\x08\x1d\x32\x47\x5c\x71\x86\x9b"
-			"\xb0\xc5\xda\xef\x04\x19\x2e\x43"
-			"\x58\x6d\x82\x97\xac\xc1\xd6\xeb"
-			"\x00\x17\x2e\x45\x5c\x73\x8a\xa1"
-			"\xb8\xcf\xe6\xfd\x14\x2b\x42\x59"
-			"\x70\x87\x9e\xb5\xcc\xe3\xfa\x11"
-			"\x28\x3f\x56\x6d\x84\x9b\xb2\xc9"
-			"\xe0\xf7\x0e\x25\x3c\x53\x6a\x81"
-			"\x98\xaf\xc6\xdd\xf4\x0b\x22\x39"
-			"\x50\x67\x7e\x95\xac\xc3\xda\xf1"
-			"\x08\x1f\x36\x4d\x64\x7b\x92\xa9"
-			"\xc0\xd7\xee\x05\x1c\x33\x4a\x61"
-			"\x78\x8f\xa6\xbd\xd4\xeb\x02\x19"
-			"\x30\x47\x5e\x75\x8c\xa3\xba\xd1"
-			"\xe8\xff\x16\x2d\x44\x5b\x72\x89"
-			"\xa0\xb7\xce\xe5\xfc\x13\x2a\x41"
-			"\x58\x6f\x86\x9d\xb4\xcb\xe2\xf9"
-			"\x10\x27\x3e\x55\x6c\x83\x9a\xb1"
-			"\xc8\xdf\xf6\x0d\x24\x3b\x52\x69"
-			"\x80\x97\xae\xc5\xdc\xf3\x0a\x21"
-			"\x38\x4f\x66\x7d\x94\xab\xc2\xd9"
-			"\xf0\x07\x1e\x35\x4c\x63\x7a\x91"
-			"\xa8\xbf\xd6\xed\x04\x1b\x32\x49"
-			"\x60\x77\x8e\xa5\xbc\xd3\xea\x01"
-			"\x18\x2f\x46\x5d\x74\x8b\xa2\xb9"
-			"\xd0\xe7\xfe\x15\x2c\x43\x5a\x71"
-			"\x88\x9f\xb6\xcd\xe4\xfb\x12\x29"
-			"\x40\x57\x6e\x85\x9c\xb3\xca\xe1"
-			"\xf8\x0f\x26\x3d\x54\x6b\x82\x99"
-			"\xb0\xc7\xde\xf5\x0c\x23\x3a\x51"
-			"\x68\x7f\x96\xad\xc4\xdb\xf2\x09"
-			"\x20\x37\x4e\x65\x7c\x93\xaa\xc1"
-			"\xd8\xef\x06\x1d\x34\x4b\x62\x79"
-			"\x90\xa7\xbe\xd5\xec\x03\x1a\x31"
-			"\x48\x5f\x76\x8d\xa4\xbb\xd2\xe9"
-			"\x00\x19\x32\x4b\x64\x7d\x96\xaf"
-			"\xc8\xe1\xfa\x13\x2c\x45\x5e\x77"
-			"\x90\xa9\xc2\xdb\xf4\x0d\x26\x3f"
-			"\x58\x71\x8a\xa3\xbc\xd5\xee\x07"
-			"\x20\x39\x52\x6b\x84\x9d\xb6\xcf"
-			"\xe8\x01\x1a\x33\x4c\x65\x7e\x97"
-			"\xb0\xc9\xe2\xfb\x14\x2d\x46\x5f"
-			"\x78\x91\xaa\xc3\xdc\xf5\x0e\x27"
-			"\x40\x59\x72\x8b\xa4\xbd\xd6\xef"
-			"\x08\x21\x3a\x53\x6c\x85\x9e\xb7"
-			"\xd0\xe9\x02\x1b\x34\x4d\x66\x7f"
-			"\x98\xb1\xca\xe3\xfc\x15\x2e\x47"
-			"\x60\x79\x92\xab\xc4\xdd\xf6\x0f"
-			"\x28\x41\x5a\x73\x8c\xa5\xbe\xd7"
-			"\xf0\x09\x22\x3b\x54\x6d\x86\x9f"
-			"\xb8\xd1\xea\x03\x1c\x35\x4e\x67"
-			"\x80\x99\xb2\xcb\xe4\xfd\x16\x2f"
-			"\x48\x61\x7a\x93\xac\xc5\xde\xf7"
-			"\x10\x29\x42\x5b\x74\x8d\xa6\xbf"
-			"\xd8\xf1\x0a\x23\x3c\x55\x6e\x87"
-			"\xa0\xb9\xd2\xeb\x04\x1d\x36\x4f"
-			"\x68\x81\x9a\xb3\xcc\xe5\xfe\x17"
-			"\x30\x49\x62\x7b\x94\xad\xc6\xdf"
-			"\xf8\x11\x2a\x43\x5c\x75\x8e\xa7"
-			"\xc0\xd9\xf2\x0b\x24\x3d\x56\x6f"
-			"\x88\xa1\xba\xd3\xec\x05\x1e\x37"
-			"\x50\x69\x82\x9b\xb4\xcd\xe6\xff"
-			"\x18\x31\x4a\x63\x7c\x95\xae\xc7"
-			"\xe0\xf9\x12\x2b\x44\x5d\x76\x8f"
-			"\xa8\xc1\xda\xf3\x0c\x25\x3e\x57"
-			"\x70\x89\xa2\xbb\xd4\xed\x06\x1f"
-			"\x38\x51\x6a\x83\x9c\xb5\xce\xe7"
-			"\x00\x1b\x36\x51\x6c\x87\xa2\xbd"
-			"\xd8\xf3\x0e\x29\x44\x5f\x7a\x95"
-			"\xb0\xcb\xe6\x01\x1c\x37\x52\x6d"
-			"\x88\xa3\xbe\xd9\xf4\x0f\x2a\x45"
-			"\x60\x7b\x96\xb1\xcc\xe7\x02\x1d"
-			"\x38\x53\x6e\x89\xa4\xbf\xda\xf5"
-			"\x10\x2b\x46\x61\x7c\x97\xb2\xcd"
-			"\xe8\x03\x1e\x39\x54\x6f\x8a\xa5"
-			"\xc0\xdb\xf6\x11\x2c\x47\x62\x7d"
-			"\x98\xb3\xce\xe9\x04\x1f\x3a\x55"
-			"\x70\x8b\xa6\xc1\xdc\xf7\x12\x2d"
-			"\x48\x63\x7e\x99\xb4\xcf\xea\x05"
-			"\x20\x3b\x56\x71\x8c\xa7\xc2\xdd"
-			"\xf8\x13\x2e\x49\x64\x7f\x9a\xb5"
-			"\xd0\xeb\x06\x21\x3c\x57\x72\x8d"
-			"\xa8\xc3\xde\xf9\x14\x2f\x4a\x65"
-			"\x80\x9b\xb6\xd1\xec\x07\x22\x3d"
-			"\x58\x73\x8e\xa9\xc4\xdf\xfa\x15"
-			"\x30\x4b\x66\x81\x9c\xb7\xd2\xed"
-			"\x08\x23\x3e\x59\x74\x8f\xaa\xc5"
-			"\xe0\xfb\x16\x31\x4c\x67\x82\x9d"
-			"\xb8\xd3\xee\x09\x24\x3f\x5a\x75"
-			"\x90\xab\xc6\xe1\xfc\x17\x32\x4d"
-			"\x68\x83\x9e\xb9\xd4\xef\x0a\x25"
-			"\x40\x5b\x76\x91\xac\xc7\xe2\xfd"
-			"\x18\x33\x4e\x69\x84\x9f\xba\xd5"
-			"\xf0\x0b\x26\x41\x5c\x77\x92\xad"
-			"\xc8\xe3\xfe\x19\x34\x4f\x6a\x85"
-			"\xa0\xbb\xd6\xf1\x0c\x27\x42\x5d"
-			"\x78\x93\xae\xc9\xe4\xff\x1a\x35"
-			"\x50\x6b\x86\xa1\xbc\xd7\xf2\x0d"
-			"\x28\x43\x5e\x79\x94\xaf\xca\xe5"
-			"\x00\x1d\x3a\x57\x74\x91\xae\xcb"
-			"\xe8\x05\x22\x3f\x5c\x79\x96\xb3"
-			"\xd0\xed\x0a\x27\x44\x61\x7e\x9b"
-			"\xb8\xd5\xf2\x0f\x2c\x49\x66\x83"
-			"\xa0\xbd\xda\xf7\x14\x31\x4e\x6b"
-			"\x88\xa5\xc2\xdf\xfc\x19\x36\x53"
-			"\x70\x8d\xaa\xc7\xe4\x01\x1e\x3b"
-			"\x58\x75\x92\xaf\xcc\xe9\x06\x23"
-			"\x40\x5d\x7a\x97\xb4\xd1\xee\x0b"
-			"\x28\x45\x62\x7f\x9c\xb9\xd6\xf3"
-			"\x10\x2d\x4a\x67\x84\xa1\xbe\xdb"
-			"\xf8\x15\x32\x4f\x6c\x89\xa6\xc3"
-			"\xe0\xfd\x1a\x37\x54\x71\x8e\xab"
-			"\xc8\xe5\x02\x1f\x3c\x59\x76\x93"
-			"\xb0\xcd\xea\x07\x24\x41\x5e\x7b"
-			"\x98\xb5\xd2\xef\x0c\x29\x46\x63"
-			"\x80\x9d\xba\xd7\xf4\x11\x2e\x4b"
-			"\x68\x85\xa2\xbf\xdc\xf9\x16\x33"
-			"\x50\x6d\x8a\xa7\xc4\xe1\xfe\x1b"
-			"\x38\x55\x72\x8f\xac\xc9\xe6\x03"
-			"\x20\x3d\x5a\x77\x94\xb1\xce\xeb"
-			"\x08\x25\x42\x5f\x7c\x99\xb6\xd3"
-			"\xf0\x0d\x2a\x47\x64\x81\x9e\xbb"
-			"\xd8\xf5\x12\x2f\x4c\x69\x86\xa3"
-			"\xc0\xdd\xfa\x17\x34\x51\x6e\x8b"
-			"\xa8\xc5\xe2\xff\x1c\x39\x56\x73"
-			"\x90\xad\xca\xe7\x04\x21\x3e\x5b"
-			"\x78\x95\xb2\xcf\xec\x09\x26\x43"
-			"\x60\x7d\x9a\xb7\xd4\xf1\x0e\x2b"
-			"\x48\x65\x82\x9f\xbc\xd9\xf6\x13"
-			"\x30\x4d\x6a\x87\xa4\xc1\xde\xfb"
-			"\x18\x35\x52\x6f\x8c\xa9\xc6\xe3"
-			"\x00\x1f\x3e\x5d\x7c\x9b\xba\xd9"
-			"\xf8\x17\x36\x55\x74\x93\xb2\xd1"
-			"\xf0\x0f\x2e\x4d\x6c\x8b\xaa\xc9"
-			"\xe8\x07\x26\x45\x64\x83\xa2\xc1"
-			"\xe0\xff\x1e\x3d\x5c\x7b\x9a\xb9"
-			"\xd8\xf7\x16\x35\x54\x73\x92\xb1"
-			"\xd0\xef\x0e\x2d\x4c\x6b\x8a\xa9"
-			"\xc8\xe7\x06\x25\x44\x63\x82\xa1"
-			"\xc0\xdf\xfe\x1d\x3c\x5b\x7a\x99"
-			"\xb8\xd7\xf6\x15\x34\x53\x72\x91"
-			"\xb0\xcf\xee\x0d\x2c\x4b\x6a\x89"
-			"\xa8\xc7\xe6\x05\x24\x43\x62\x81"
-			"\xa0\xbf\xde\xfd\x1c\x3b\x5a\x79"
-			"\x98\xb7\xd6\xf5\x14\x33\x52\x71"
-			"\x90\xaf\xce\xed\x0c\x2b\x4a\x69"
-			"\x88\xa7\xc6\xe5\x04\x23\x42\x61"
-			"\x80\x9f\xbe\xdd\xfc\x1b\x3a\x59"
-			"\x78\x97\xb6\xd5\xf4\x13\x32\x51"
-			"\x70\x8f\xae\xcd\xec\x0b\x2a\x49"
-			"\x68\x87\xa6\xc5\xe4\x03\x22\x41"
-			"\x60\x7f\x9e\xbd\xdc\xfb\x1a\x39"
-			"\x58\x77\x96\xb5\xd4\xf3\x12\x31"
-			"\x50\x6f\x8e\xad\xcc\xeb\x0a\x29"
-			"\x48\x67\x86\xa5\xc4\xe3\x02\x21"
-			"\x40\x5f\x7e\x9d\xbc\xdb\xfa\x19"
-			"\x38\x57\x76\x95\xb4\xd3\xf2\x11"
-			"\x30\x4f\x6e\x8d\xac\xcb\xea\x09"
-			"\x28\x47\x66\x85\xa4\xc3\xe2\x01"
-			"\x20\x3f\x5e\x7d\x9c\xbb\xda\xf9"
-			"\x18\x37\x56\x75\x94\xb3\xd2\xf1"
-			"\x10\x2f\x4e\x6d\x8c\xab\xca\xe9"
-			"\x08\x27\x46\x65\x84\xa3\xc2\xe1"
-			"\x00\x21\x42\x63",
-		.ilen = 4100,
-		.result =
-			"\xf0\x5c\x74\xad\x4e\xbc\x99\xe2"
-			"\xae\xff\x91\x3a\x44\xcf\x38\x32"
-			"\x1e\xad\xa7\xcd\xa1\x39\x95\xaa"
-			"\x10\xb1\xb3\x2e\x04\x31\x8f\x86"
-			"\xf2\x62\x74\x70\x0c\xa4\x46\x08"
-			"\xa8\xb7\x99\xa8\xe9\xd2\x73\x79"
-			"\x7e\x6e\xd4\x8f\x1e\xc7\x8e\x31"
-			"\x0b\xfa\x4b\xce\xfd\xf3\x57\x71"
-			"\xe9\x46\x03\xa5\x3d\x34\x00\xe2"
-			"\x18\xff\x75\x6d\x06\x2d\x00\xab"
-			"\xb9\x3e\x6c\x59\xc5\x84\x06\xb5"
-			"\x8b\xd0\x89\x9c\x4a\x79\x16\xc6"
-			"\x3d\x74\x54\xfa\x44\xcd\x23\x26"
-			"\x5c\xcf\x7e\x28\x92\x32\xbf\xdf"
-			"\xa7\x20\x3c\x74\x58\x2a\x9a\xde"
-			"\x61\x00\x1c\x4f\xff\x59\xc4\x22"
-			"\xac\x3c\xd0\xe8\x6c\xf9\x97\x1b"
-			"\x58\x9b\xad\x71\xe8\xa9\xb5\x0d"
-			"\xee\x2f\x04\x1f\x7f\xbc\x99\xee"
-			"\x84\xff\x42\x60\xdc\x3a\x18\xa5"
-			"\x81\xf9\xef\xdc\x7a\x0f\x65\x41"
-			"\x2f\xa3\xd3\xf9\xc2\xcb\xc0\x4d"
-			"\x8f\xd3\x76\x96\xad\x49\x6d\x38"
-			"\x3d\x39\x0b\x6c\x80\xb7\x54\x69"
-			"\xf0\x2c\x90\x02\x29\x0d\x1c\x12"
-			"\xad\x55\xc3\x8b\x68\xd9\xcc\xb3"
-			"\xb2\x64\x33\x90\x5e\xca\x4b\xe2"
-			"\xfb\x75\xdc\x63\xf7\x9f\x82\x74"
-			"\xf0\xc9\xaa\x7f\xe9\x2a\x9b\x33"
-			"\xbc\x88\x00\x7f\xca\xb2\x1f\x14"
-			"\xdb\xc5\x8e\x7b\x11\x3c\x3e\x08"
-			"\xf3\x83\xe8\xe0\x94\x86\x2e\x92"
-			"\x78\x6b\x01\xc9\xc7\x83\xba\x21"
-			"\x6a\x25\x15\x33\x4e\x45\x08\xec"
-			"\x35\xdb\xe0\x6e\x31\x51\x79\xa9"
-			"\x42\x44\x65\xc1\xa0\xf1\xf9\x2a"
-			"\x70\xd5\xb6\xc6\xc1\x8c\x39\xfc"
-			"\x25\xa6\x55\xd9\xdd\x2d\x4c\xec"
-			"\x49\xc6\xeb\x0e\xa8\x25\x2a\x16"
-			"\x1b\x66\x84\xda\xe2\x92\xe5\xc0"
-			"\xc8\x53\x07\xaf\x80\x84\xec\xfd"
-			"\xcd\xd1\x6e\xcd\x6f\x6a\xf5\x36"
-			"\xc5\x15\xe5\x25\x7d\x77\xd1\x1a"
-			"\x93\x36\xa9\xcf\x7c\xa4\x54\x4a"
-			"\x06\x51\x48\x4e\xf6\x59\x87\xd2"
-			"\x04\x02\xef\xd3\x44\xde\x76\x31"
-			"\xb3\x34\x17\x1b\x9d\x66\x11\x9f"
-			"\x1e\xcc\x17\xe9\xc7\x3c\x1b\xe7"
-			"\xcb\x50\x08\xfc\xdc\x2b\x24\xdb"
-			"\x65\x83\xd0\x3b\xe3\x30\xea\x94"
-			"\x6c\xe7\xe8\x35\x32\xc7\xdb\x64"
-			"\xb4\x01\xab\x36\x2c\x77\x13\xaf"
-			"\xf8\x2b\x88\x3f\x54\x39\xc4\x44"
-			"\xfe\xef\x6f\x68\x34\xbe\x0f\x05"
-			"\x16\x6d\xf6\x0a\x30\xe7\xe3\xed"
-			"\xc4\xde\x3c\x1b\x13\xd8\xdb\xfe"
-			"\x41\x62\xe5\x28\xd4\x8d\xa3\xc7"
-			"\x93\x97\xc6\x48\x45\x1d\x9f\x83"
-			"\xdf\x4b\x40\x3e\x42\x25\x87\x80"
-			"\x4c\x7d\xa8\xd4\x98\x23\x95\x75"
-			"\x41\x8c\xda\x41\x9b\xd4\xa7\x06"
-			"\xb5\xf1\x71\x09\x53\xbe\xca\xbf"
-			"\x32\x03\xed\xf0\x50\x1c\x56\x39"
-			"\x5b\xa4\x75\x18\xf7\x9b\x58\xef"
-			"\x53\xfc\x2a\x38\x23\x15\x75\xcd"
-			"\x45\xe5\x5a\x82\x55\xba\x21\xfa"
-			"\xd4\xbd\xc6\x94\x7c\xc5\x80\x12"
-			"\xf7\x4b\x32\xc4\x9a\x82\xd8\x28"
-			"\x8f\xd9\xc2\x0f\x60\x03\xbe\x5e"
-			"\x21\xd6\x5f\x58\xbf\x5c\xb1\x32"
-			"\x82\x8d\xa9\xe5\xf2\x66\x1a\xc0"
-			"\xa0\xbc\x58\x2f\x71\xf5\x2f\xed"
-			"\xd1\x26\xb9\xd8\x49\x5a\x07\x19"
-			"\x01\x7c\x59\xb0\xf8\xa4\xb7\xd3"
-			"\x7b\x1a\x8c\x38\xf4\x50\xa4\x59"
-			"\xb0\xcc\x41\x0b\x88\x7f\xe5\x31"
-			"\xb3\x42\xba\xa2\x7e\xd4\x32\x71"
-			"\x45\x87\x48\xa9\xc2\xf2\x89\xb3"
-			"\xe4\xa7\x7e\x52\x15\x61\xfa\xfe"
-			"\xc9\xdd\x81\xeb\x13\xab\xab\xc3"
-			"\x98\x59\xd8\x16\x3d\x14\x7a\x1c"
-			"\x3c\x41\x9a\x16\x16\x9b\xd2\xd2"
-			"\x69\x3a\x29\x23\xac\x86\x32\xa5"
-			"\x48\x9c\x9e\xf3\x47\x77\x81\x70"
-			"\x24\xe8\x85\xd2\xf5\xb5\xfa\xff"
-			"\x59\x6a\xd3\x50\x59\x43\x59\xde"
-			"\xd9\xf1\x55\xa5\x0c\xc3\x1a\x1a"
-			"\x18\x34\x0d\x1a\x63\x33\xed\x10"
-			"\xe0\x1d\x2a\x18\xd2\xc0\x54\xa8"
-			"\xca\xb5\x9a\xd3\xdd\xca\x45\x84"
-			"\x50\xe7\x0f\xfe\xa4\x99\x5a\xbe"
-			"\x43\x2d\x9a\xcb\x92\x3f\x5a\x1d"
-			"\x85\xd8\xc9\xdf\x68\xc9\x12\x80"
-			"\x56\x0c\xdc\x00\xdc\x3a\x7d\x9d"
-			"\xa3\xa2\xe8\x4d\xbf\xf9\x70\xa0"
-			"\xa4\x13\x4f\x6b\xaf\x0a\x89\x7f"
-			"\xda\xf0\xbf\x9b\xc8\x1d\xe5\xf8"
-			"\x2e\x8b\x07\xb5\x73\x1b\xcc\xa2"
-			"\xa6\xad\x30\xbc\x78\x3c\x5b\x10"
-			"\xfa\x5e\x62\x2d\x9e\x64\xb3\x33"
-			"\xce\xf9\x1f\x86\xe7\x8b\xa2\xb8"
-			"\xe8\x99\x57\x8c\x11\xed\x66\xd9"
-			"\x3c\x72\xb9\xc3\xe6\x4e\x17\x3a"
-			"\x6a\xcb\x42\x24\x06\xed\x3e\x4e"
-			"\xa3\xe8\x6a\x94\xda\x0d\x4e\xd5"
-			"\x14\x19\xcf\xb6\x26\xd8\x2e\xcc"
-			"\x64\x76\x38\x49\x4d\xfe\x30\x6d"
-			"\xe4\xc8\x8c\x7b\xc4\xe0\x35\xba"
-			"\x22\x6e\x76\xe1\x1a\xf2\x53\xc3"
-			"\x28\xa2\x82\x1f\x61\x69\xad\xc1"
-			"\x7b\x28\x4b\x1e\x6c\x85\x95\x9b"
-			"\x51\xb5\x17\x7f\x12\x69\x8c\x24"
-			"\xd5\xc7\x5a\x5a\x11\x54\xff\x5a"
-			"\xf7\x16\xc3\x91\xa6\xf0\xdc\x0a"
-			"\xb6\xa7\x4a\x0d\x7a\x58\xfe\xa5"
-			"\xf5\xcb\x8f\x7b\x0e\xea\x57\xe7"
-			"\xbd\x79\xd6\x1c\x88\x23\x6c\xf2"
-			"\x4d\x29\x77\x53\x35\x6a\x00\x8d"
-			"\xcd\xa3\x58\xbe\x77\x99\x18\xf8"
-			"\xe6\xe1\x8f\xe9\x37\x8f\xe3\xe2"
-			"\x5a\x8a\x93\x25\xaf\xf3\x78\x80"
-			"\xbe\xa6\x1b\xc6\xac\x8b\x1c\x91"
-			"\x58\xe1\x9f\x89\x35\x9d\x1d\x21"
-			"\x29\x9f\xf4\x99\x02\x27\x0f\xa8"
-			"\x4f\x79\x94\x2b\x33\x2c\xda\xa2"
-			"\x26\x39\x83\x94\xef\x27\xd8\x53"
-			"\x8f\x66\x0d\xe4\x41\x7d\x34\xcd"
-			"\x43\x7c\x95\x0a\x53\xef\x66\xda"
-			"\x7e\x9b\xf3\x93\xaf\xd0\x73\x71"
-			"\xba\x40\x9b\x74\xf8\xd7\xd7\x41"
-			"\x6d\xaf\x72\x9c\x8d\x21\x87\x3c"
-			"\xfd\x0a\x90\xa9\x47\x96\x9e\xd3"
-			"\x88\xee\x73\xcf\x66\x2f\x52\x56"
-			"\x6d\xa9\x80\x4c\xe2\x6f\x62\x88"
-			"\x3f\x0e\x54\x17\x48\x80\x5d\xd3"
-			"\xc3\xda\x25\x3d\xa1\xc8\xcb\x9f"
-			"\x9b\x70\xb3\xa1\xeb\x04\x52\xa1"
-			"\xf2\x22\x0f\xfc\xc8\x18\xfa\xf9"
-			"\x85\x9c\xf1\xac\xeb\x0c\x02\x46"
-			"\x75\xd2\xf5\x2c\xe3\xd2\x59\x94"
-			"\x12\xf3\x3c\xfc\xd7\x92\xfa\x36"
-			"\xba\x61\x34\x38\x7c\xda\x48\x3e"
-			"\x08\xc9\x39\x23\x5e\x02\x2c\x1a"
-			"\x18\x7e\xb4\xd9\xfd\x9e\x40\x02"
-			"\xb1\x33\x37\x32\xe7\xde\xd6\xd0"
-			"\x7c\x58\x65\x4b\xf8\x34\x27\x9c"
-			"\x44\xb4\xbd\xe9\xe9\x4c\x78\x7d"
-			"\x4b\x9f\xce\xb1\xcd\x47\xa5\x37"
-			"\xe5\x6d\xbd\xb9\x43\x94\x0a\xd4"
-			"\xd6\xf9\x04\x5f\xb5\x66\x6c\x1a"
-			"\x35\x12\xe3\x36\x28\x27\x36\x58"
-			"\x01\x2b\x79\xe4\xba\x6d\x10\x7d"
-			"\x65\xdf\x84\x95\xf4\xd5\xb6\x8f"
-			"\x2b\x9f\x96\x00\x86\x60\xf0\x21"
-			"\x76\xa8\x6a\x8c\x28\x1c\xb3\x6b"
-			"\x97\xd7\xb6\x53\x2a\xcc\xab\x40"
-			"\x9d\x62\x79\x58\x52\xe6\x65\xb7"
-			"\xab\x55\x67\x9c\x89\x7c\x03\xb0"
-			"\x73\x59\xc5\x81\xf5\x18\x17\x5c"
-			"\x89\xf3\x78\x35\x44\x62\x78\x72"
-			"\xd0\x96\xeb\x31\xe7\x87\x77\x14"
-			"\x99\x51\xf2\x59\x26\x9e\xb5\xa6"
-			"\x45\xfe\x6e\xbd\x07\x4c\x94\x5a"
-			"\xa5\x7d\xfc\xf1\x2b\x77\xe2\xfe"
-			"\x17\xd4\x84\xa0\xac\xb5\xc7\xda"
-			"\xa9\x1a\xb6\xf3\x74\x11\xb4\x9d"
-			"\xfb\x79\x2e\x04\x2d\x50\x28\x83"
-			"\xbf\xc6\x52\xd3\x34\xd6\xe8\x7a"
-			"\xb6\xea\xe7\xa8\x6c\x15\x1e\x2c"
-			"\x57\xbc\x48\x4e\x5f\x5c\xb6\x92"
-			"\xd2\x49\x77\x81\x6d\x90\x70\xae"
-			"\x98\xa1\x03\x0d\x6b\xb9\x77\x14"
-			"\xf1\x4e\x23\xd3\xf8\x68\xbd\xc2"
-			"\xfe\x04\xb7\x5c\xc5\x17\x60\x8f"
-			"\x65\x54\xa4\x7a\x42\xdc\x18\x0d"
-			"\xb5\xcf\x0f\xd3\xc7\x91\x66\x1b"
-			"\x45\x42\x27\x75\x50\xe5\xee\xb8"
-			"\x7f\x33\x2c\xba\x4a\x92\x4d\x2c"
-			"\x3c\xe3\x0d\x80\x01\xba\x0d\x29"
-			"\xd8\x3c\xe9\x13\x16\x57\xe6\xea"
-			"\x94\x52\xe7\x00\x4d\x30\xb0\x0f"
-			"\x35\xb8\xb8\xa7\xb1\xb5\x3b\x44"
-			"\xe1\x2f\xfd\x88\xed\x43\xe7\x52"
-			"\x10\x93\xb3\x8a\x30\x6b\x0a\xf7"
-			"\x23\xc6\x50\x9d\x4a\xb0\xde\xc3"
-			"\xdc\x9b\x2f\x01\x56\x36\x09\xc5"
-			"\x2f\x6b\xfe\xf1\xd8\x27\x45\x03"
-			"\x30\x5e\x5c\x5b\xb4\x62\x0e\x1a"
-			"\xa9\x21\x2b\x92\x94\x87\x62\x57"
-			"\x4c\x10\x74\x1a\xf1\x0a\xc5\x84"
-			"\x3b\x9e\x72\x02\xd7\xcc\x09\x56"
-			"\xbd\x54\xc1\xf0\xc3\xe3\xb3\xf8"
-			"\xd2\x0d\x61\xcb\xef\xce\x0d\x05"
-			"\xb0\x98\xd9\x8e\x4f\xf9\xbc\x93"
-			"\xa6\xea\xc8\xcf\x10\x53\x4b\xf1"
-			"\xec\xfc\x89\xf9\x64\xb0\x22\xbf"
-			"\x9e\x55\x46\x9f\x7c\x50\x8e\x84"
-			"\x54\x20\x98\xd7\x6c\x40\x1e\xdb"
-			"\x69\x34\x78\x61\x24\x21\x9c\x8a"
-			"\xb3\x62\x31\x8b\x6e\xf5\x2a\x35"
-			"\x86\x13\xb1\x6c\x64\x2e\x41\xa5"
-			"\x05\xf2\x42\xba\xd2\x3a\x0d\x8e"
-			"\x8a\x59\x94\x3c\xcf\x36\x27\x82"
-			"\xc2\x45\xee\x58\xcd\x88\xb4\xec"
-			"\xde\xb2\x96\x0a\xaf\x38\x6f\x88"
-			"\xd7\xd8\xe1\xdf\xb9\x96\xa9\x0a"
-			"\xb1\x95\x28\x86\x20\xe9\x17\x49"
-			"\xa2\x29\x38\xaa\xa5\xe9\x6e\xf1"
-			"\x19\x27\xc0\xd5\x2a\x22\xc3\x0b"
-			"\xdb\x7c\x73\x10\xb9\xba\x89\x76"
-			"\x54\xae\x7d\x71\xb3\x93\xf6\x32"
-			"\xe6\x47\x43\x55\xac\xa0\x0d\xc2"
-			"\x93\x27\x4a\x8e\x0e\x74\x15\xc7"
-			"\x0b\x85\xd9\x0c\xa9\x30\x7a\x3e"
-			"\xea\x8f\x85\x6d\x3a\x12\x4f\x72"
-			"\x69\x58\x7a\x80\xbb\xb5\x97\xf3"
-			"\xcf\x70\xd2\x5d\xdd\x4d\x21\x79"
-			"\x54\x4d\xe4\x05\xe8\xbd\xc2\x62"
-			"\xb1\x3b\x77\x1c\xd6\x5c\xf3\xa0"
-			"\x79\x00\xa8\x6c\x29\xd9\x18\x24"
-			"\x36\xa2\x46\xc0\x96\x65\x7f\xbd"
-			"\x2a\xed\x36\x16\x0c\xaa\x9f\xf4"
-			"\xc5\xb4\xe2\x12\xed\x69\xed\x4f"
-			"\x26\x2c\x39\x52\x89\x98\xe7\x2c"
-			"\x99\xa4\x9e\xa3\x9b\x99\x46\x7a"
-			"\x3a\xdc\xa8\x59\xa3\xdb\xc3\x3b"
-			"\x95\x0d\x3b\x09\x6e\xee\x83\x5d"
-			"\x32\x4d\xed\xab\xfa\x98\x14\x4e"
-			"\xc3\x15\x45\x53\x61\xc4\x93\xbd"
-			"\x90\xf4\x99\x95\x4c\xe6\x76\x92"
-			"\x29\x90\x46\x30\x92\x69\x7d\x13"
-			"\xf2\xa5\xcd\x69\x49\x44\xb2\x0f"
-			"\x63\x40\x36\x5f\x09\xe2\x78\xf8"
-			"\x91\xe3\xe2\xfa\x10\xf7\xc8\x24"
-			"\xa8\x89\x32\x5c\x37\x25\x1d\xb2"
-			"\xea\x17\x8a\x0a\xa9\x64\xc3\x7c"
-			"\x3c\x7c\xbd\xc6\x79\x34\xe7\xe2"
-			"\x85\x8e\xbf\xf8\xde\x92\xa0\xae"
-			"\x20\xc4\xf6\xbb\x1f\x38\x19\x0e"
-			"\xe8\x79\x9c\xa1\x23\xe9\x54\x7e"
-			"\x37\x2f\xe2\x94\x32\xaf\xa0\x23"
-			"\x49\xe4\xc0\xb3\xac\x00\x8f\x36"
-			"\x05\xc4\xa6\x96\xec\x05\x98\x4f"
-			"\x96\x67\x57\x1f\x20\x86\x1b\x2d"
-			"\x69\xe4\x29\x93\x66\x5f\xaf\x6b"
-			"\x88\x26\x2c\x67\x02\x4b\x52\xd0"
-			"\x83\x7a\x43\x1f\xc0\x71\x15\x25"
-			"\x77\x65\x08\x60\x11\x76\x4c\x8d"
-			"\xed\xa9\x27\xc6\xb1\x2a\x2c\x6a"
-			"\x4a\x97\xf5\xc6\xb7\x70\x42\xd3"
-			"\x03\xd1\x24\x95\xec\x6d\xab\x38"
-			"\x72\xce\xe2\x8b\x33\xd7\x51\x09"
-			"\xdc\x45\xe0\x09\x96\x32\xf3\xc4"
-			"\x84\xdc\x73\x73\x2d\x1b\x11\x98"
-			"\xc5\x0e\x69\x28\x94\xc7\xb5\x4d"
-			"\xc8\x8a\xd0\xaa\x13\x2e\x18\x74"
-			"\xdd\xd1\x1e\xf3\x90\xe8\xfc\x9a"
-			"\x72\x4a\x0e\xd1\xe4\xfb\x0d\x96"
-			"\xd1\x0c\x79\x85\x1b\x1c\xfe\xe1"
-			"\x62\x8f\x7a\x73\x32\xab\xc8\x18"
-			"\x69\xe3\x34\x30\xdf\x13\xa6\xe5"
-			"\xe8\x0e\x67\x7f\x81\x11\xb4\x60"
-			"\xc7\xbd\x79\x65\x50\xdc\xc4\x5b"
-			"\xde\x39\xa4\x01\x72\x63\xf3\xd1"
-			"\x64\x4e\xdf\xfc\x27\x92\x37\x0d"
-			"\x57\xcd\x11\x4f\x11\x04\x8e\x1d"
-			"\x16\xf7\xcd\x92\x9a\x99\x30\x14"
-			"\xf1\x7c\x67\x1b\x1f\x41\x0b\xe8"
-			"\x32\xe8\xb8\xc1\x4f\x54\x86\x4f"
-			"\xe5\x79\x81\x73\xcd\x43\x59\x68"
-			"\x73\x02\x3b\x78\x21\x72\x43\x00"
-			"\x49\x17\xf7\x00\xaf\x68\x24\x53"
-			"\x05\x0a\xc3\x33\xe0\x33\x3f\x69"
-			"\xd2\x84\x2f\x0b\xed\xde\x04\xf4"
-			"\x11\x94\x13\x69\x51\x09\x28\xde"
-			"\x57\x5c\xef\xdc\x9a\x49\x1c\x17"
-			"\x97\xf3\x96\xc1\x7f\x5d\x2e\x7d"
-			"\x55\xb8\xb3\x02\x09\xb3\x1f\xe7"
-			"\xc9\x8d\xa3\x36\x34\x8a\x77\x13"
-			"\x30\x63\x4c\xa5\xcd\xc3\xe0\x7e"
-			"\x05\xa1\x7b\x0c\xcb\x74\x47\x31"
-			"\x62\x03\x43\xf1\x87\xb4\xb0\x85"
-			"\x87\x8e\x4b\x25\xc7\xcf\xae\x4b"
-			"\x36\x46\x3e\x62\xbc\x6f\xeb\x5f"
-			"\x73\xac\xe6\x07\xee\xc1\xa1\xd6"
-			"\xc4\xab\xc9\xd6\x89\x45\xe1\xf1"
-			"\x04\x4e\x1a\x6f\xbb\x4f\x3a\xa3"
-			"\xa0\xcb\xa3\x0a\xd8\x71\x35\x55"
-			"\xe4\xbc\x2e\x04\x06\xe6\xff\x5b"
-			"\x1c\xc0\x11\x7c\xc5\x17\xf3\x38"
-			"\xcf\xe9\xba\x0f\x0e\xef\x02\xc2"
-			"\x8d\xc6\xbc\x4b\x67\x20\x95\xd7"
-			"\x2c\x45\x5b\x86\x44\x8c\x6f\x2e"
-			"\x7e\x9f\x1c\x77\xba\x6b\x0e\xa3"
-			"\x69\xdc\xab\x24\x57\x60\x47\xc1"
-			"\xd1\xa5\x9d\x23\xe6\xb1\x37\xfe"
-			"\x93\xd2\x4c\x46\xf9\x0c\xc6\xfb"
-			"\xd6\x9d\x99\x69\xab\x7a\x07\x0c"
-			"\x65\xe7\xc4\x08\x96\xe2\xa5\x01"
-			"\x3f\x46\x07\x05\x7e\xe8\x9a\x90"
-			"\x50\xdc\xe9\x7a\xea\xa1\x39\x6e"
-			"\x66\xe4\x6f\xa5\x5f\xb2\xd9\x5b"
-			"\xf5\xdb\x2a\x32\xf0\x11\x6f\x7c"
-			"\x26\x10\x8f\x3d\x80\xe9\x58\xf7"
-			"\xe0\xa8\x57\xf8\xdb\x0e\xce\x99"
-			"\x63\x19\x3d\xd5\xec\x1b\x77\x69"
-			"\x98\xf6\xe4\x5f\x67\x17\x4b\x09"
-			"\x85\x62\x82\x70\x18\xe2\x9a\x78"
-			"\xe2\x62\xbd\xb4\xf1\x42\xc6\xfb"
-			"\x08\xd0\xbd\xeb\x4e\x09\xf2\xc8"
-			"\x1e\xdc\x3d\x32\x21\x56\x9c\x4f"
-			"\x35\xf3\x61\x06\x72\x84\xc4\x32"
-			"\xf2\xf1\xfa\x0b\x2f\xc3\xdb\x02"
-			"\x04\xc2\xde\x57\x64\x60\x8d\xcf"
-			"\xcb\x86\x5d\x97\x3e\xb1\x9c\x01"
-			"\xd6\x28\x8f\x99\xbc\x46\xeb\x05"
-			"\xaf\x7e\xb8\x21\x2a\x56\x85\x1c"
-			"\xb3\x71\xa0\xde\xca\x96\xf1\x78"
-			"\x49\xa2\x99\x81\x80\x5c\x01\xf5"
-			"\xa0\xa2\x56\x63\xe2\x70\x07\xa5"
-			"\x95\xd6\x85\xeb\x36\x9e\xa9\x51"
-			"\x66\x56\x5f\x1d\x02\x19\xe2\xf6"
-			"\x4f\x73\x38\x09\x75\x64\x48\xe0"
-			"\xf1\x7e\x0e\xe8\x9d\xf9\xed\x94"
-			"\xfe\x16\x26\x62\x49\x74\xf4\xb0"
-			"\xd4\xa9\x6c\xb0\xfd\x53\xe9\x81"
-			"\xe0\x7a\xbf\xcf\xb5\xc4\x01\x81"
-			"\x79\x99\x77\x01\x3b\xe9\xa2\xb6"
-			"\xe6\x6a\x8a\x9e\x56\x1c\x8d\x1e"
-			"\x8f\x06\x55\x2c\x6c\xdc\x92\x87"
-			"\x64\x3b\x4b\x19\xa1\x13\x64\x1d"
-			"\x4a\xe9\xc0\x00\xb8\x95\xef\x6b"
-			"\x1a\x86\x6d\x37\x52\x02\xc2\xe0"
-			"\xc8\xbb\x42\x0c\x02\x21\x4a\xc9"
-			"\xef\xa0\x54\xe4\x5e\x16\x53\x81"
-			"\x70\x62\x10\xaf\xde\xb8\xb5\xd3"
-			"\xe8\x5e\x6c\xc3\x8a\x3e\x18\x07"
-			"\xf2\x2f\x7d\xa7\xe1\x3d\x4e\xb4"
-			"\x26\xa7\xa3\x93\x86\xb2\x04\x1e"
-			"\x53\x5d\x86\xd6\xde\x65\xca\xe3"
-			"\x4e\xc1\xcf\xef\xc8\x70\x1b\x83"
-			"\x13\xdd\x18\x8b\x0d\x76\xd2\xf6"
-			"\x37\x7a\x93\x7a\x50\x11\x9f\x96"
-			"\x86\x25\xfd\xac\xdc\xbe\x18\x93"
-			"\x19\x6b\xec\x58\x4f\xb9\x75\xa7"
-			"\xdd\x3f\x2f\xec\xc8\x5a\x84\xab"
-			"\xd5\xe4\x8a\x07\xf6\x4d\x23\xd6"
-			"\x03\xfb\x03\x6a\xea\x66\xbf\xd4"
-			"\xb1\x34\xfb\x78\xe9\x55\xdc\x7c"
-			"\x3d\x9c\xe5\x9a\xac\xc3\x7a\x80"
-			"\x24\x6d\xa0\xef\x25\x7c\xb7\xea"
-			"\xce\x4d\x5f\x18\x60\xce\x87\x22"
-			"\x66\x2f\xd5\xdd\xdd\x02\x21\x75"
-			"\x82\xa0\x1f\x58\xc6\xd3\x62\xf7"
-			"\x32\xd8\xaf\x1e\x07\x77\x51\x96"
-			"\xd5\x6b\x1e\x7e\x80\x02\xe8\x67"
-			"\xea\x17\x0b\x10\xd2\x3f\x28\x25"
-			"\x4f\x05\x77\x02\x14\x69\xf0\x2c"
-			"\xbe\x0c\xf1\x74\x30\xd1\xb9\x9b"
-			"\xfc\x8c\xbb\x04\x16\xd9\xba\xc3"
-			"\xbc\x91\x8a\xc4\x30\xa4\xb0\x12"
-			"\x4c\x21\x87\xcb\xc9\x1d\x16\x96"
-			"\x07\x6f\x23\x54\xb9\x6f\x79\xe5"
-			"\x64\xc0\x64\xda\xb1\xae\xdd\x60"
-			"\x6c\x1a\x9d\xd3\x04\x8e\x45\xb0"
-			"\x92\x61\xd0\x48\x81\xed\x5e\x1d"
-			"\xa0\xc9\xa4\x33\xc7\x13\x51\x5d"
-			"\x7f\x83\x73\xb6\x70\x18\x65\x3e"
-			"\x2f\x0e\x7a\x12\x39\x98\xab\xd8"
-			"\x7e\x6f\xa3\xd1\xba\x56\xad\xbd"
-			"\xf0\x03\x01\x1c\x85\x35\x9f\xeb"
-			"\x19\x63\xa1\xaf\xfe\x2d\x35\x50"
-			"\x39\xa0\x65\x7c\x95\x7e\x6b\xfe"
-			"\xc1\xac\x07\x7c\x98\x4f\xbe\x57"
-			"\xa7\x22\xec\xe2\x7e\x29\x09\x53"
-			"\xe8\xbf\xb4\x7e\x3f\x8f\xfc\x14"
-			"\xce\x54\xf9\x18\x58\xb5\xff\x44"
-			"\x05\x9d\xce\x1b\xb6\x82\x23\xc8"
-			"\x2e\xbc\x69\xbb\x4a\x29\x0f\x65"
-			"\x94\xf0\x63\x06\x0e\xef\x8c\xbd"
-			"\xff\xfd\xb0\x21\x6e\x57\x05\x75"
-			"\xda\xd5\xc4\xeb\x8d\x32\xf7\x50"
-			"\xd3\x6f\x22\xed\x5f\x8e\xa2\x5b"
-			"\x80\x8c\xc8\x78\x40\x24\x4b\x89"
-			"\x30\xce\x7a\x97\x0e\xc4\xaf\xef"
-			"\x9b\xb4\xcd\x66\x74\x14\x04\x2b"
-			"\xf7\xce\x0b\x1c\x6e\xc2\x78\x8c"
-			"\xca\xc5\xd0\x1c\x95\x4a\x91\x2d"
-			"\xa7\x20\xeb\x86\x52\xb7\x67\xd8"
-			"\x0c\xd6\x04\x14\xde\x51\x74\x75"
-			"\xe7\x11\xb4\x87\xa3\x3d\x2d\xad"
-			"\x4f\xef\xa0\x0f\x70\x00\x6d\x13"
-			"\x19\x1d\x41\x50\xe9\xd8\xf0\x32"
-			"\x71\xbc\xd3\x11\xf2\xac\xbe\xaf"
-			"\x75\x46\x65\x4e\x07\x34\x37\xa3"
-			"\x89\xfe\x75\xd4\x70\x4c\xc6\x3f"
-			"\x69\x24\x0e\x38\x67\x43\x8c\xde"
-			"\x06\xb5\xb8\xe7\xc4\xf0\x41\x8f"
-			"\xf0\xbd\x2f\x0b\xb9\x18\xf8\xde"
-			"\x64\xb1\xdb\xee\x00\x50\x77\xe1"
-			"\xc7\xff\xa6\xfa\xdd\x70\xf4\xe3"
-			"\x93\xe9\x77\x35\x3d\x4b\x2f\x2b"
-			"\x6d\x55\xf0\xfc\x88\x54\x4e\x89"
-			"\xc1\x8a\x23\x31\x2d\x14\x2a\xb8"
-			"\x1b\x15\xdd\x9e\x6e\x7b\xda\x05"
-			"\x91\x7d\x62\x64\x96\x72\xde\xfc"
-			"\xc1\xec\xf0\x23\x51\x6f\xdb\x5b"
-			"\x1d\x08\x57\xce\x09\xb8\xf6\xcd"
-			"\x8d\x95\xf2\x20\xbf\x0f\x20\x57"
-			"\x98\x81\x84\x4f\x15\x5c\x76\xe7"
-			"\x3e\x0a\x3a\x6c\xc4\x8a\xbe\x78"
-			"\x74\x77\xc3\x09\x4b\x5d\x48\xe4"
-			"\xc8\xcb\x0b\xea\x17\x28\xcf\xcf"
-			"\x31\x32\x44\xa4\xe5\x0e\x1a\x98"
-			"\x94\xc4\xf0\xff\xae\x3e\x44\xe8"
-			"\xa5\xb3\xb5\x37\x2f\xe8\xaf\x6f"
-			"\x28\xc1\x37\x5f\x31\xd2\xb9\x33"
-			"\xb1\xb2\x52\x94\x75\x2c\x29\x59"
-			"\x06\xc2\x25\xe8\x71\x65\x4e\xed"
-			"\xc0\x9c\xb1\xbb\x25\xdc\x6c\xe7"
-			"\x4b\xa5\x7a\x54\x7a\x60\xff\x7a"
-			"\xe0\x50\x40\x96\x35\x63\xe4\x0b"
-			"\x76\xbd\xa4\x65\x00\x1b\x57\x88"
-			"\xae\xed\x39\x88\x42\x11\x3c\xed"
-			"\x85\x67\x7d\xb9\x68\x82\xe9\x43"
-			"\x3c\x47\x53\xfa\xe8\xf8\x9f\x1f"
-			"\x9f\xef\x0f\xf7\x30\xd9\x30\x0e"
-			"\xb9\x9f\x69\x18\x2f\x7e\xf8\xf8"
-			"\xf8\x8c\x0f\xd4\x02\x4d\xea\xcd"
-			"\x0a\x9c\x6f\x71\x6d\x5a\x4c\x60"
-			"\xce\x20\x56\x32\xc6\xc5\x99\x1f"
-			"\x09\xe6\x4e\x18\x1a\x15\x13\xa8"
-			"\x7d\xb1\x6b\xc0\xb2\x6d\xf8\x26"
-			"\x66\xf8\x3d\x18\x74\x70\x66\x7a"
-			"\x34\x17\xde\xba\x47\xf1\x06\x18"
-			"\xcb\xaf\xeb\x4a\x1e\x8f\xa7\x77"
-			"\xe0\x3b\x78\x62\x66\xc9\x10\xea"
-			"\x1f\xb7\x29\x0a\x45\xa1\x1d\x1e"
-			"\x1d\xe2\x65\x61\x50\x9c\xd7\x05"
-			"\xf2\x0b\x5b\x12\x61\x02\xc8\xe5"
-			"\x63\x4f\x20\x0c\x07\x17\x33\x5e"
-			"\x03\x9a\x53\x0f\x2e\x55\xfe\x50"
-			"\x43\x7d\xd0\xb6\x7e\x5a\xda\xae"
-			"\x58\xef\x15\xa9\x83\xd9\x46\xb1"
-			"\x42\xaa\xf5\x02\x6c\xce\x92\x06"
-			"\x1b\xdb\x66\x45\x91\x79\xc2\x2d"
-			"\xe6\x53\xd3\x14\xfd\xbb\x44\x63"
-			"\xc6\xd7\x3d\x7a\x0c\x75\x78\x9d"
-			"\x5c\xa6\x39\xb3\xe5\x63\xca\x8b"
-			"\xfe\xd3\xef\x60\x83\xf6\x8e\x70"
-			"\xb6\x67\xc7\x77\xed\x23\xef\x4c"
-			"\xf0\xed\x2d\x07\x59\x6f\xc1\x01"
-			"\x34\x37\x08\xab\xd9\x1f\x09\xb1"
-			"\xce\x5b\x17\xff\x74\xf8\x9c\xd5"
-			"\x2c\x56\x39\x79\x0f\x69\x44\x75"
-			"\x58\x27\x01\xc4\xbf\xa7\xa1\x1d"
-			"\x90\x17\x77\x86\x5a\x3f\xd9\xd1"
-			"\x0e\xa0\x10\xf8\xec\x1e\xa5\x7f"
-			"\x5e\x36\xd1\xe3\x04\x2c\x70\xf7"
-			"\x8e\xc0\x98\x2f\x6c\x94\x2b\x41"
-			"\xb7\x60\x00\xb7\x2e\xb8\x02\x8d"
-			"\xb8\xb0\xd3\x86\xba\x1d\xd7\x90"
-			"\xd6\xb6\xe1\xfc\xd7\xd8\x28\x06"
-			"\x63\x9b\xce\x61\x24\x79\xc0\x70"
-			"\x52\xd0\xb6\xd4\x28\x95\x24\x87"
-			"\x03\x1f\xb7\x9a\xda\xa3\xfb\x52"
-			"\x5b\x68\xe7\x4c\x8c\x24\xe1\x42"
-			"\xf7\xd5\xfd\xad\x06\x32\x9f\xba"
-			"\xc1\xfc\xdd\xc6\xfc\xfc\xb3\x38"
-			"\x74\x56\x58\x40\x02\x37\x52\x2c"
-			"\x55\xcc\xb3\x9e\x7a\xe9\xd4\x38"
-			"\x41\x5e\x0c\x35\xe2\x11\xd1\x13"
-			"\xf8\xb7\x8d\x72\x6b\x22\x2a\xb0"
-			"\xdb\x08\xba\x35\xb9\x3f\xc8\xd3"
-			"\x24\x90\xec\x58\xd2\x09\xc7\x2d"
-			"\xed\x38\x80\x36\x72\x43\x27\x49"
-			"\x4a\x80\x8a\xa2\xe8\xd3\xda\x30"
-			"\x7d\xb6\x82\x37\x86\x92\x86\x3e"
-			"\x08\xb2\x28\x5a\x55\x44\x24\x7d"
-			"\x40\x48\x8a\xb6\x89\x58\x08\xa0"
-			"\xd6\x6d\x3a\x17\xbf\xf6\x54\xa2"
-			"\xf5\xd3\x8c\x0f\x78\x12\x57\x8b"
-			"\xd5\xc2\xfd\x58\x5b\x7f\x38\xe3"
-			"\xcc\xb7\x7c\x48\xb3\x20\xe8\x81"
-			"\x14\x32\x45\x05\xe0\xdb\x9f\x75"
-			"\x85\xb4\x6a\xfc\x95\xe3\x54\x22"
-			"\x12\xee\x30\xfe\xd8\x30\xef\x34"
-			"\x50\xab\x46\x30\x98\x2f\xb7\xc0"
-			"\x15\xa2\x83\xb6\xf2\x06\x21\xa2"
-			"\xc3\x26\x37\x14\xd1\x4d\xb5\x10"
-			"\x52\x76\x4d\x6a\xee\xb5\x2b\x15"
-			"\xb7\xf9\x51\xe8\x2a\xaf\xc7\xfa"
-			"\x77\xaf\xb0\x05\x4d\xd1\x68\x8e"
-			"\x74\x05\x9f\x9d\x93\xa5\x3e\x7f"
-			"\x4e\x5f\x9d\xcb\x09\xc7\x83\xe3"
-			"\x02\x9d\x27\x1f\xef\x85\x05\x8d"
-			"\xec\x55\x88\x0f\x0d\x7c\x4c\xe8"
-			"\xa1\x75\xa0\xd8\x06\x47\x14\xef"
-			"\xaa\x61\xcf\x26\x15\xad\xd8\xa3"
-			"\xaa\x75\xf2\x78\x4a\x5a\x61\xdf"
-			"\x8b\xc7\x04\xbc\xb2\x32\xd2\x7e"
-			"\x42\xee\xb4\x2f\x51\xff\x7b\x2e"
-			"\xd3\x02\xe8\xdc\x5d\x0d\x50\xdc"
-			"\xae\xb7\x46\xf9\xa8\xe6\xd0\x16"
-			"\xcc\xe6\x2c\x81\xc7\xad\xe9\xf0"
-			"\x05\x72\x6d\x3d\x0a\x7a\xa9\x02"
-			"\xac\x82\x93\x6e\xb6\x1c\x28\xfc"
-			"\x44\x12\xfb\x73\x77\xd4\x13\x39"
-			"\x29\x88\x8a\xf3\x5c\xa6\x36\xa0"
-			"\x2a\xed\x7e\xb1\x1d\xd6\x4c\x6b"
-			"\x41\x01\x18\x5d\x5d\x07\x97\xa6"
-			"\x4b\xef\x31\x18\xea\xac\xb1\x84"
-			"\x21\xed\xda\x86",
-		.rlen = 4100,
-	},
-};
-
-static struct cipher_testvec aes_ctr_dec_tv_template[] = {
-	{ /* From RFC 3686 */
-		.key	= "\xae\x68\x52\xf8\x12\x10\x67\xcc"
-			  "\x4b\xf7\xa5\x76\x55\x77\xf3\x9e"
-			  "\x00\x00\x00\x30",
-		.klen	= 20,
-		.iv	= "\x00\x00\x00\x00\x00\x00\x00\x00",
-		.input	= "\xe4\x09\x5d\x4f\xb7\xa7\xb3\x79"
-			  "\x2d\x61\x75\xa3\x26\x13\x11\xb8",
-		.ilen	= 16,
-		.result	= "Single block msg",
-		.rlen	= 16,
-	}, {
-		.key	= "\x7e\x24\x06\x78\x17\xfa\xe0\xd7"
-			  "\x43\xd6\xce\x1f\x32\x53\x91\x63"
-			  "\x00\x6c\xb6\xdb",
-		.klen	= 20,
-		.iv	= "\xc0\x54\x3b\x59\xda\x48\xd9\x0b",
-		.input	= "\x51\x04\xa1\x06\x16\x8a\x72\xd9"
-			  "\x79\x0d\x41\xee\x8e\xda\xd3\x88"
-			  "\xeb\x2e\x1e\xfc\x46\xda\x57\xc8"
-			  "\xfc\xe6\x30\xdf\x91\x41\xbe\x28",
-		.ilen	= 32,
-		.result	= "\x00\x01\x02\x03\x04\x05\x06\x07"
-			  "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
-			  "\x10\x11\x12\x13\x14\x15\x16\x17"
-			  "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f",
-		.rlen	= 32,
-	}, {
-		.key	= "\x16\xaf\x5b\x14\x5f\xc9\xf5\x79"
-			  "\xc1\x75\xf9\x3e\x3b\xfb\x0e\xed"
-			  "\x86\x3d\x06\xcc\xfd\xb7\x85\x15"
-			  "\x00\x00\x00\x48",
-		.klen	= 28,
-		.iv	= "\x36\x73\x3c\x14\x7d\x6d\x93\xcb",
-		.input	= "\x4b\x55\x38\x4f\xe2\x59\xc9\xc8"
-			  "\x4e\x79\x35\xa0\x03\xcb\xe9\x28",
-		.ilen	= 16,
-		.result	= "Single block msg",
-		.rlen	= 16,
-	}, {
-		.key	= "\x7c\x5c\xb2\x40\x1b\x3d\xc3\x3c"
-			  "\x19\xe7\x34\x08\x19\xe0\xf6\x9c"
-			  "\x67\x8c\x3d\xb8\xe6\xf6\xa9\x1a"
-			  "\x00\x96\xb0\x3b",
-		.klen	= 28,
-		.iv	= "\x02\x0c\x6e\xad\xc2\xcb\x50\x0d",
-		.input	= "\x45\x32\x43\xfc\x60\x9b\x23\x32"
-			  "\x7e\xdf\xaa\xfa\x71\x31\xcd\x9f"
-			  "\x84\x90\x70\x1c\x5a\xd4\xa7\x9c"
-			  "\xfc\x1f\xe0\xff\x42\xf4\xfb\x00",
-		.ilen	= 32,
-		.result	= "\x00\x01\x02\x03\x04\x05\x06\x07"
-			  "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
-			  "\x10\x11\x12\x13\x14\x15\x16\x17"
-			  "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f",
-		.rlen	= 32,
-	}, { 
-		.key	= "\x77\x6b\xef\xf2\x85\x1d\xb0\x6f"
-			  "\x4c\x8a\x05\x42\xc8\x69\x6f\x6c"
-			  "\x6a\x81\xaf\x1e\xec\x96\xb4\xd3"
-			  "\x7f\xc1\xd6\x89\xe6\xc1\xc1\x04"
-			  "\x00\x00\x00\x60",
-		.klen	= 36,
-		.iv	= "\xdb\x56\x72\xc9\x7a\xa8\xf0\xb2",
-		.input	= "\x14\x5a\xd0\x1d\xbf\x82\x4e\xc7"
-			  "\x56\x08\x63\xdc\x71\xe3\xe0\xc0",
-		.ilen	= 16,
-		.result	= "Single block msg",
-		.rlen	= 16,
-	}, {
-		.key	= "\xf6\xd6\x6d\x6b\xd5\x2d\x59\xbb"
-			  "\x07\x96\x36\x58\x79\xef\xf8\x86"
-			  "\xc6\x6d\xd5\x1a\x5b\x6a\x99\x74"
-			  "\x4b\x50\x59\x0c\x87\xa2\x38\x84"
-			  "\x00\xfa\xac\x24",
-		.klen	= 36,
-		.iv	= "\xc1\x58\x5e\xf1\x5a\x43\xd8\x75",
-		.input	= "\xf0\x5e\x23\x1b\x38\x94\x61\x2c"
-			  "\x49\xee\x00\x0b\x80\x4e\xb2\xa9"
-			  "\xb8\x30\x6b\x50\x8f\x83\x9d\x6a"
-			  "\x55\x30\x83\x1d\x93\x44\xaf\x1c",
-		.ilen	= 32,
-		.result	= "\x00\x01\x02\x03\x04\x05\x06\x07"
-			  "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
-			  "\x10\x11\x12\x13\x14\x15\x16\x17"
-			  "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f",
-		.rlen	= 32,
-	},
-};
-
-static struct aead_testvec aes_gcm_enc_tv_template[] = {
-	{ /* From McGrew & Viega - http://citeseer.ist.psu.edu/656989.html */
-		.key    = zeroed_string,
-		.klen	= 16,
-		.result	= "\x58\xe2\xfc\xce\xfa\x7e\x30\x61"
-			  "\x36\x7f\x1d\x57\xa4\xe7\x45\x5a",
-		.rlen	= 16,
-	}, {
-		.key    = zeroed_string,
-		.klen	= 16,
-		.input  = zeroed_string,
-		.ilen	= 16,
-		.result = "\x03\x88\xda\xce\x60\xb6\xa3\x92"
-			  "\xf3\x28\xc2\xb9\x71\xb2\xfe\x78"
-			  "\xab\x6e\x47\xd4\x2c\xec\x13\xbd"
-			  "\xf5\x3a\x67\xb2\x12\x57\xbd\xdf",
-		.rlen	= 32,
-	}, {
-		.key	= "\xfe\xff\xe9\x92\x86\x65\x73\x1c"
-			  "\x6d\x6a\x8f\x94\x67\x30\x83\x08",
-		.klen	= 16,
-		.iv	= "\xca\xfe\xba\xbe\xfa\xce\xdb\xad"
-			  "\xde\xca\xf8\x88",
-		.input	= "\xd9\x31\x32\x25\xf8\x84\x06\xe5"
-			  "\xa5\x59\x09\xc5\xaf\xf5\x26\x9a"
-			  "\x86\xa7\xa9\x53\x15\x34\xf7\xda"
-			  "\x2e\x4c\x30\x3d\x8a\x31\x8a\x72"
-			  "\x1c\x3c\x0c\x95\x95\x68\x09\x53"
-			  "\x2f\xcf\x0e\x24\x49\xa6\xb5\x25"
-			  "\xb1\x6a\xed\xf5\xaa\x0d\xe6\x57"
-			  "\xba\x63\x7b\x39\x1a\xaf\xd2\x55",
-		.ilen	= 64,
-		.result = "\x42\x83\x1e\xc2\x21\x77\x74\x24"
-			  "\x4b\x72\x21\xb7\x84\xd0\xd4\x9c"
-			  "\xe3\xaa\x21\x2f\x2c\x02\xa4\xe0"
-			  "\x35\xc1\x7e\x23\x29\xac\xa1\x2e"
-			  "\x21\xd5\x14\xb2\x54\x66\x93\x1c"
-			  "\x7d\x8f\x6a\x5a\xac\x84\xaa\x05"
-			  "\x1b\xa3\x0b\x39\x6a\x0a\xac\x97"
-			  "\x3d\x58\xe0\x91\x47\x3f\x59\x85"
-			  "\x4d\x5c\x2a\xf3\x27\xcd\x64\xa6"
-			  "\x2c\xf3\x5a\xbd\x2b\xa6\xfa\xb4",
-		.rlen	= 80,
-	}, {
-		.key	= "\xfe\xff\xe9\x92\x86\x65\x73\x1c"
-			  "\x6d\x6a\x8f\x94\x67\x30\x83\x08",
-		.klen	= 16,
-		.iv	= "\xca\xfe\xba\xbe\xfa\xce\xdb\xad"
-			  "\xde\xca\xf8\x88",
-		.input	= "\xd9\x31\x32\x25\xf8\x84\x06\xe5"
-			  "\xa5\x59\x09\xc5\xaf\xf5\x26\x9a"
-			  "\x86\xa7\xa9\x53\x15\x34\xf7\xda"
-			  "\x2e\x4c\x30\x3d\x8a\x31\x8a\x72"
-			  "\x1c\x3c\x0c\x95\x95\x68\x09\x53"
-			  "\x2f\xcf\x0e\x24\x49\xa6\xb5\x25"
-			  "\xb1\x6a\xed\xf5\xaa\x0d\xe6\x57"
-			  "\xba\x63\x7b\x39",
-		.ilen	= 60,
-		.assoc	= "\xfe\xed\xfa\xce\xde\xad\xbe\xef"
-			  "\xfe\xed\xfa\xce\xde\xad\xbe\xef"
-			  "\xab\xad\xda\xd2",
-		.alen	= 20,
-		.result = "\x42\x83\x1e\xc2\x21\x77\x74\x24"
-			  "\x4b\x72\x21\xb7\x84\xd0\xd4\x9c"
-			  "\xe3\xaa\x21\x2f\x2c\x02\xa4\xe0"
-			  "\x35\xc1\x7e\x23\x29\xac\xa1\x2e"
-			  "\x21\xd5\x14\xb2\x54\x66\x93\x1c"
-			  "\x7d\x8f\x6a\x5a\xac\x84\xaa\x05"
-			  "\x1b\xa3\x0b\x39\x6a\x0a\xac\x97"
-			  "\x3d\x58\xe0\x91"
-			  "\x5b\xc9\x4f\xbc\x32\x21\xa5\xdb"
-			  "\x94\xfa\xe9\x5a\xe7\x12\x1a\x47",
-		.rlen	= 76,
-	}, {
-		.key    = zeroed_string,
-		.klen	= 24,
-		.result	= "\xcd\x33\xb2\x8a\xc7\x73\xf7\x4b"
-			  "\xa0\x0e\xd1\xf3\x12\x57\x24\x35",
-		.rlen	= 16,
-	}, {
-		.key    = zeroed_string,
-		.klen	= 24,
-		.input  = zeroed_string,
-		.ilen	= 16,
-		.result = "\x98\xe7\x24\x7c\x07\xf0\xfe\x41"
-			  "\x1c\x26\x7e\x43\x84\xb0\xf6\x00"
-			  "\x2f\xf5\x8d\x80\x03\x39\x27\xab"
-			  "\x8e\xf4\xd4\x58\x75\x14\xf0\xfb",
-		.rlen	= 32,
-	}, {
-		.key	= "\xfe\xff\xe9\x92\x86\x65\x73\x1c"
-			  "\x6d\x6a\x8f\x94\x67\x30\x83\x08"
-			  "\xfe\xff\xe9\x92\x86\x65\x73\x1c",
-		.klen	= 24,
-		.iv	= "\xca\xfe\xba\xbe\xfa\xce\xdb\xad"
-			  "\xde\xca\xf8\x88",
-		.input	= "\xd9\x31\x32\x25\xf8\x84\x06\xe5"
-			  "\xa5\x59\x09\xc5\xaf\xf5\x26\x9a"
-			  "\x86\xa7\xa9\x53\x15\x34\xf7\xda"
-			  "\x2e\x4c\x30\x3d\x8a\x31\x8a\x72"
-			  "\x1c\x3c\x0c\x95\x95\x68\x09\x53"
-			  "\x2f\xcf\x0e\x24\x49\xa6\xb5\x25"
-			  "\xb1\x6a\xed\xf5\xaa\x0d\xe6\x57"
-			  "\xba\x63\x7b\x39\x1a\xaf\xd2\x55",
-		.ilen	= 64,
-		.result = "\x39\x80\xca\x0b\x3c\x00\xe8\x41"
-			  "\xeb\x06\xfa\xc4\x87\x2a\x27\x57"
-			  "\x85\x9e\x1c\xea\xa6\xef\xd9\x84"
-			  "\x62\x85\x93\xb4\x0c\xa1\xe1\x9c"
-			  "\x7d\x77\x3d\x00\xc1\x44\xc5\x25"
-			  "\xac\x61\x9d\x18\xc8\x4a\x3f\x47"
-			  "\x18\xe2\x44\x8b\x2f\xe3\x24\xd9"
-			  "\xcc\xda\x27\x10\xac\xad\xe2\x56"
-			  "\x99\x24\xa7\xc8\x58\x73\x36\xbf"
-			  "\xb1\x18\x02\x4d\xb8\x67\x4a\x14",
-		.rlen	= 80,
-	}, {
-		.key	= "\xfe\xff\xe9\x92\x86\x65\x73\x1c"
-			  "\x6d\x6a\x8f\x94\x67\x30\x83\x08"
-			  "\xfe\xff\xe9\x92\x86\x65\x73\x1c",
-		.klen	= 24,
-		.iv	= "\xca\xfe\xba\xbe\xfa\xce\xdb\xad"
-			  "\xde\xca\xf8\x88",
-		.input	= "\xd9\x31\x32\x25\xf8\x84\x06\xe5"
-			  "\xa5\x59\x09\xc5\xaf\xf5\x26\x9a"
-			  "\x86\xa7\xa9\x53\x15\x34\xf7\xda"
-			  "\x2e\x4c\x30\x3d\x8a\x31\x8a\x72"
-			  "\x1c\x3c\x0c\x95\x95\x68\x09\x53"
-			  "\x2f\xcf\x0e\x24\x49\xa6\xb5\x25"
-			  "\xb1\x6a\xed\xf5\xaa\x0d\xe6\x57"
-			  "\xba\x63\x7b\x39",
-		.ilen	= 60,
-		.assoc	= "\xfe\xed\xfa\xce\xde\xad\xbe\xef"
-			  "\xfe\xed\xfa\xce\xde\xad\xbe\xef"
-			  "\xab\xad\xda\xd2",
-		.alen	= 20,
-		.result = "\x39\x80\xca\x0b\x3c\x00\xe8\x41"
-			  "\xeb\x06\xfa\xc4\x87\x2a\x27\x57"
-			  "\x85\x9e\x1c\xea\xa6\xef\xd9\x84"
-			  "\x62\x85\x93\xb4\x0c\xa1\xe1\x9c"
-			  "\x7d\x77\x3d\x00\xc1\x44\xc5\x25"
-			  "\xac\x61\x9d\x18\xc8\x4a\x3f\x47"
-			  "\x18\xe2\x44\x8b\x2f\xe3\x24\xd9"
-			  "\xcc\xda\x27\x10"
-			  "\x25\x19\x49\x8e\x80\xf1\x47\x8f"
-			  "\x37\xba\x55\xbd\x6d\x27\x61\x8c",
-		.rlen	= 76,
-		.np	= 2,
-		.tap	= { 32, 28 },
-		.anp	= 2,
-		.atap	= { 8, 12 }
-	}, {
-		.key    = zeroed_string,
-		.klen	= 32,
-		.result	= "\x53\x0f\x8a\xfb\xc7\x45\x36\xb9"
-			  "\xa9\x63\xb4\xf1\xc4\xcb\x73\x8b",
-		.rlen	= 16,
-	}
-};
-
-static struct aead_testvec aes_gcm_dec_tv_template[] = {
-	{ /* From McGrew & Viega - http://citeseer.ist.psu.edu/656989.html */
-		.key    = zeroed_string,
-		.klen	= 32,
-		.input	= "\xce\xa7\x40\x3d\x4d\x60\x6b\x6e"
-			  "\x07\x4e\xc5\xd3\xba\xf3\x9d\x18"
-			  "\xd0\xd1\xc8\xa7\x99\x99\x6b\xf0"
-			  "\x26\x5b\x98\xb5\xd4\x8a\xb9\x19",
-		.ilen	= 32,
-		.result  = zeroed_string,
-		.rlen	= 16,
-	}, {
-		.key	= "\xfe\xff\xe9\x92\x86\x65\x73\x1c"
-			  "\x6d\x6a\x8f\x94\x67\x30\x83\x08"
-			  "\xfe\xff\xe9\x92\x86\x65\x73\x1c"
-			  "\x6d\x6a\x8f\x94\x67\x30\x83\x08",
-		.klen	= 32,
-		.iv	= "\xca\xfe\xba\xbe\xfa\xce\xdb\xad"
-			  "\xde\xca\xf8\x88",
-		.input	= "\x52\x2d\xc1\xf0\x99\x56\x7d\x07"
-			  "\xf4\x7f\x37\xa3\x2a\x84\x42\x7d"
-			  "\x64\x3a\x8c\xdc\xbf\xe5\xc0\xc9"
-			  "\x75\x98\xa2\xbd\x25\x55\xd1\xaa"
-			  "\x8c\xb0\x8e\x48\x59\x0d\xbb\x3d"
-			  "\xa7\xb0\x8b\x10\x56\x82\x88\x38"
-			  "\xc5\xf6\x1e\x63\x93\xba\x7a\x0a"
-			  "\xbc\xc9\xf6\x62\x89\x80\x15\xad"
-			  "\xb0\x94\xda\xc5\xd9\x34\x71\xbd"
-			  "\xec\x1a\x50\x22\x70\xe3\xcc\x6c",
-		.ilen	= 80,
-		.result = "\xd9\x31\x32\x25\xf8\x84\x06\xe5"
-			  "\xa5\x59\x09\xc5\xaf\xf5\x26\x9a"
-			  "\x86\xa7\xa9\x53\x15\x34\xf7\xda"
-			  "\x2e\x4c\x30\x3d\x8a\x31\x8a\x72"
-			  "\x1c\x3c\x0c\x95\x95\x68\x09\x53"
-			  "\x2f\xcf\x0e\x24\x49\xa6\xb5\x25"
-			  "\xb1\x6a\xed\xf5\xaa\x0d\xe6\x57"
-			  "\xba\x63\x7b\x39\x1a\xaf\xd2\x55",
-		.rlen	= 64,
-	}, {
-		.key	= "\xfe\xff\xe9\x92\x86\x65\x73\x1c"
-			  "\x6d\x6a\x8f\x94\x67\x30\x83\x08"
-			  "\xfe\xff\xe9\x92\x86\x65\x73\x1c"
-			  "\x6d\x6a\x8f\x94\x67\x30\x83\x08",
-		.klen	= 32,
-		.iv	= "\xca\xfe\xba\xbe\xfa\xce\xdb\xad"
-			  "\xde\xca\xf8\x88",
-		.input	= "\x52\x2d\xc1\xf0\x99\x56\x7d\x07"
-			  "\xf4\x7f\x37\xa3\x2a\x84\x42\x7d"
-			  "\x64\x3a\x8c\xdc\xbf\xe5\xc0\xc9"
-			  "\x75\x98\xa2\xbd\x25\x55\xd1\xaa"
-			  "\x8c\xb0\x8e\x48\x59\x0d\xbb\x3d"
-			  "\xa7\xb0\x8b\x10\x56\x82\x88\x38"
-			  "\xc5\xf6\x1e\x63\x93\xba\x7a\x0a"
-			  "\xbc\xc9\xf6\x62"
-			  "\x76\xfc\x6e\xce\x0f\x4e\x17\x68"
-			  "\xcd\xdf\x88\x53\xbb\x2d\x55\x1b",
-		.ilen	= 76,
-		.assoc	= "\xfe\xed\xfa\xce\xde\xad\xbe\xef"
-			  "\xfe\xed\xfa\xce\xde\xad\xbe\xef"
-			  "\xab\xad\xda\xd2",
-		.alen	= 20,
-		.result = "\xd9\x31\x32\x25\xf8\x84\x06\xe5"
-			  "\xa5\x59\x09\xc5\xaf\xf5\x26\x9a"
-			  "\x86\xa7\xa9\x53\x15\x34\xf7\xda"
-			  "\x2e\x4c\x30\x3d\x8a\x31\x8a\x72"
-			  "\x1c\x3c\x0c\x95\x95\x68\x09\x53"
-			  "\x2f\xcf\x0e\x24\x49\xa6\xb5\x25"
-			  "\xb1\x6a\xed\xf5\xaa\x0d\xe6\x57"
-			  "\xba\x63\x7b\x39",
-		.rlen	= 60,
-		.np     = 2,
-		.tap    = { 48, 28 },
-		.anp	= 3,
-		.atap	= { 8, 8, 4 }
-	}, {
-		.key	= "\xfe\xff\xe9\x92\x86\x65\x73\x1c"
-			  "\x6d\x6a\x8f\x94\x67\x30\x83\x08",
-		.klen	= 16,
-		.iv	= "\xca\xfe\xba\xbe\xfa\xce\xdb\xad"
-			  "\xde\xca\xf8\x88",
-		.input	= "\x42\x83\x1e\xc2\x21\x77\x74\x24"
-			  "\x4b\x72\x21\xb7\x84\xd0\xd4\x9c"
-			  "\xe3\xaa\x21\x2f\x2c\x02\xa4\xe0"
-			  "\x35\xc1\x7e\x23\x29\xac\xa1\x2e"
-			  "\x21\xd5\x14\xb2\x54\x66\x93\x1c"
-			  "\x7d\x8f\x6a\x5a\xac\x84\xaa\x05"
-			  "\x1b\xa3\x0b\x39\x6a\x0a\xac\x97"
-			  "\x3d\x58\xe0\x91\x47\x3f\x59\x85"
-			  "\x4d\x5c\x2a\xf3\x27\xcd\x64\xa6"
-			  "\x2c\xf3\x5a\xbd\x2b\xa6\xfa\xb4",
-		.ilen	= 80,
-		.result = "\xd9\x31\x32\x25\xf8\x84\x06\xe5"
-			  "\xa5\x59\x09\xc5\xaf\xf5\x26\x9a"
-			  "\x86\xa7\xa9\x53\x15\x34\xf7\xda"
-			  "\x2e\x4c\x30\x3d\x8a\x31\x8a\x72"
-			  "\x1c\x3c\x0c\x95\x95\x68\x09\x53"
-			  "\x2f\xcf\x0e\x24\x49\xa6\xb5\x25"
-			  "\xb1\x6a\xed\xf5\xaa\x0d\xe6\x57"
-			  "\xba\x63\x7b\x39\x1a\xaf\xd2\x55",
-		.rlen	= 64,
-	}, {
-		.key	= "\xfe\xff\xe9\x92\x86\x65\x73\x1c"
-			  "\x6d\x6a\x8f\x94\x67\x30\x83\x08",
-		.klen	= 16,
-		.iv	= "\xca\xfe\xba\xbe\xfa\xce\xdb\xad"
-			  "\xde\xca\xf8\x88",
-		.input	= "\x42\x83\x1e\xc2\x21\x77\x74\x24"
-			  "\x4b\x72\x21\xb7\x84\xd0\xd4\x9c"
-			  "\xe3\xaa\x21\x2f\x2c\x02\xa4\xe0"
-			  "\x35\xc1\x7e\x23\x29\xac\xa1\x2e"
-			  "\x21\xd5\x14\xb2\x54\x66\x93\x1c"
-			  "\x7d\x8f\x6a\x5a\xac\x84\xaa\x05"
-			  "\x1b\xa3\x0b\x39\x6a\x0a\xac\x97"
-			  "\x3d\x58\xe0\x91"
-			  "\x5b\xc9\x4f\xbc\x32\x21\xa5\xdb"
-			  "\x94\xfa\xe9\x5a\xe7\x12\x1a\x47",
-		.ilen	= 76,
-		.assoc	= "\xfe\xed\xfa\xce\xde\xad\xbe\xef"
-			  "\xfe\xed\xfa\xce\xde\xad\xbe\xef"
-			  "\xab\xad\xda\xd2",
-		.alen	= 20,
-		.result = "\xd9\x31\x32\x25\xf8\x84\x06\xe5"
-			  "\xa5\x59\x09\xc5\xaf\xf5\x26\x9a"
-			  "\x86\xa7\xa9\x53\x15\x34\xf7\xda"
-			  "\x2e\x4c\x30\x3d\x8a\x31\x8a\x72"
-			  "\x1c\x3c\x0c\x95\x95\x68\x09\x53"
-			  "\x2f\xcf\x0e\x24\x49\xa6\xb5\x25"
-			  "\xb1\x6a\xed\xf5\xaa\x0d\xe6\x57"
-			  "\xba\x63\x7b\x39",
-		.rlen	= 60,
-	}, {
-		.key    = zeroed_string,
-		.klen	= 24,
-		.input	= "\x98\xe7\x24\x7c\x07\xf0\xfe\x41"
-			  "\x1c\x26\x7e\x43\x84\xb0\xf6\x00"
-			  "\x2f\xf5\x8d\x80\x03\x39\x27\xab"
-			  "\x8e\xf4\xd4\x58\x75\x14\xf0\xfb",
-		.ilen	= 32,
-		.result  = zeroed_string,
-		.rlen	= 16,
-	}, {
-		.key	= "\xfe\xff\xe9\x92\x86\x65\x73\x1c"
-			  "\x6d\x6a\x8f\x94\x67\x30\x83\x08"
-			  "\xfe\xff\xe9\x92\x86\x65\x73\x1c",
-		.klen	= 24,
-		.iv	= "\xca\xfe\xba\xbe\xfa\xce\xdb\xad"
-			  "\xde\xca\xf8\x88",
-		.input	= "\x39\x80\xca\x0b\x3c\x00\xe8\x41"
-			  "\xeb\x06\xfa\xc4\x87\x2a\x27\x57"
-			  "\x85\x9e\x1c\xea\xa6\xef\xd9\x84"
-			  "\x62\x85\x93\xb4\x0c\xa1\xe1\x9c"
-			  "\x7d\x77\x3d\x00\xc1\x44\xc5\x25"
-			  "\xac\x61\x9d\x18\xc8\x4a\x3f\x47"
-			  "\x18\xe2\x44\x8b\x2f\xe3\x24\xd9"
-			  "\xcc\xda\x27\x10\xac\xad\xe2\x56"
-			  "\x99\x24\xa7\xc8\x58\x73\x36\xbf"
-			  "\xb1\x18\x02\x4d\xb8\x67\x4a\x14",
-		.ilen	= 80,
-		.result = "\xd9\x31\x32\x25\xf8\x84\x06\xe5"
-			  "\xa5\x59\x09\xc5\xaf\xf5\x26\x9a"
-			  "\x86\xa7\xa9\x53\x15\x34\xf7\xda"
-			  "\x2e\x4c\x30\x3d\x8a\x31\x8a\x72"
-			  "\x1c\x3c\x0c\x95\x95\x68\x09\x53"
-			  "\x2f\xcf\x0e\x24\x49\xa6\xb5\x25"
-			  "\xb1\x6a\xed\xf5\xaa\x0d\xe6\x57"
-			  "\xba\x63\x7b\x39\x1a\xaf\xd2\x55",
-		.rlen	= 64,
-	}, {
-		.key	= "\xfe\xff\xe9\x92\x86\x65\x73\x1c"
-			  "\x6d\x6a\x8f\x94\x67\x30\x83\x08"
-			  "\xfe\xff\xe9\x92\x86\x65\x73\x1c",
-		.klen	= 24,
-		.iv	= "\xca\xfe\xba\xbe\xfa\xce\xdb\xad"
-			  "\xde\xca\xf8\x88",
-		.input	= "\x39\x80\xca\x0b\x3c\x00\xe8\x41"
-			  "\xeb\x06\xfa\xc4\x87\x2a\x27\x57"
-			  "\x85\x9e\x1c\xea\xa6\xef\xd9\x84"
-			  "\x62\x85\x93\xb4\x0c\xa1\xe1\x9c"
-			  "\x7d\x77\x3d\x00\xc1\x44\xc5\x25"
-			  "\xac\x61\x9d\x18\xc8\x4a\x3f\x47"
-			  "\x18\xe2\x44\x8b\x2f\xe3\x24\xd9"
-			  "\xcc\xda\x27\x10"
-			  "\x25\x19\x49\x8e\x80\xf1\x47\x8f"
-			  "\x37\xba\x55\xbd\x6d\x27\x61\x8c",
-		.ilen	= 76,
-		.assoc	= "\xfe\xed\xfa\xce\xde\xad\xbe\xef"
-			  "\xfe\xed\xfa\xce\xde\xad\xbe\xef"
-			  "\xab\xad\xda\xd2",
-		.alen	= 20,
-		.result = "\xd9\x31\x32\x25\xf8\x84\x06\xe5"
-			  "\xa5\x59\x09\xc5\xaf\xf5\x26\x9a"
-			  "\x86\xa7\xa9\x53\x15\x34\xf7\xda"
-			  "\x2e\x4c\x30\x3d\x8a\x31\x8a\x72"
-			  "\x1c\x3c\x0c\x95\x95\x68\x09\x53"
-			  "\x2f\xcf\x0e\x24\x49\xa6\xb5\x25"
-			  "\xb1\x6a\xed\xf5\xaa\x0d\xe6\x57"
-			  "\xba\x63\x7b\x39",
-		.rlen	= 60,
-	}
-};
-
-static struct aead_testvec aes_ccm_enc_tv_template[] = {
-	{ /* From RFC 3610 */
-		.key	= "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7"
-			  "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf",
-		.klen	= 16,
-		.iv	= "\x01\x00\x00\x00\x03\x02\x01\x00"
-			  "\xa0\xa1\xa2\xa3\xa4\xa5\x00\x00",
-		.assoc	= "\x00\x01\x02\x03\x04\x05\x06\x07",
-		.alen	= 8,
-		.input	= "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
-			  "\x10\x11\x12\x13\x14\x15\x16\x17"
-			  "\x18\x19\x1a\x1b\x1c\x1d\x1e",
-		.ilen	= 23,
-		.result	= "\x58\x8c\x97\x9a\x61\xc6\x63\xd2"
-			  "\xf0\x66\xd0\xc2\xc0\xf9\x89\x80"
-			  "\x6d\x5f\x6b\x61\xda\xc3\x84\x17"
-			  "\xe8\xd1\x2c\xfd\xf9\x26\xe0",
-		.rlen	= 31,
-	}, {
-		.key	= "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7"
-			  "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf",
-		.klen	= 16,
-		.iv	= "\x01\x00\x00\x00\x07\x06\x05\x04"
-			  "\xa0\xa1\xa2\xa3\xa4\xa5\x00\x00",
-		.assoc	= "\x00\x01\x02\x03\x04\x05\x06\x07"
-			  "\x08\x09\x0a\x0b",
-		.alen	= 12,
-		.input	= "\x0c\x0d\x0e\x0f\x10\x11\x12\x13"
-			  "\x14\x15\x16\x17\x18\x19\x1a\x1b"
-			  "\x1c\x1d\x1e\x1f",
-		.ilen	= 20,
-		.result	= "\xdc\xf1\xfb\x7b\x5d\x9e\x23\xfb"
-			  "\x9d\x4e\x13\x12\x53\x65\x8a\xd8"
-			  "\x6e\xbd\xca\x3e\x51\xe8\x3f\x07"
-			  "\x7d\x9c\x2d\x93",
-		.rlen	= 28,
-	}, {
-		.key	= "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7"
-			  "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf",
-		.klen	= 16,
-		.iv	= "\x01\x00\x00\x00\x0b\x0a\x09\x08"
-			  "\xa0\xa1\xa2\xa3\xa4\xa5\x00\x00",
-		.assoc	= "\x00\x01\x02\x03\x04\x05\x06\x07",
-		.alen	= 8,
-		.input	= "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
-			  "\x10\x11\x12\x13\x14\x15\x16\x17"
-			  "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
-			  "\x20",
-		.ilen	= 25,
-		.result	= "\x82\x53\x1a\x60\xcc\x24\x94\x5a"
-			  "\x4b\x82\x79\x18\x1a\xb5\xc8\x4d"
-			  "\xf2\x1c\xe7\xf9\xb7\x3f\x42\xe1"
-			  "\x97\xea\x9c\x07\xe5\x6b\x5e\xb1"
-			  "\x7e\x5f\x4e",
-		.rlen	= 35,
-	}, {
-		.key	= "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7"
-			  "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf",
-		.klen	= 16,
-		.iv	= "\x01\x00\x00\x00\x0c\x0b\x0a\x09"
-			  "\xa0\xa1\xa2\xa3\xa4\xa5\x00\x00",
-		.assoc	= "\x00\x01\x02\x03\x04\x05\x06\x07"
-			  "\x08\x09\x0a\x0b",
-		.alen	= 12,
-		.input	= "\x0c\x0d\x0e\x0f\x10\x11\x12\x13"
-			  "\x14\x15\x16\x17\x18\x19\x1a\x1b"
-			  "\x1c\x1d\x1e",
-		.ilen	= 19,
-		.result	= "\x07\x34\x25\x94\x15\x77\x85\x15"
-			  "\x2b\x07\x40\x98\x33\x0a\xbb\x14"
-			  "\x1b\x94\x7b\x56\x6a\xa9\x40\x6b"
-			  "\x4d\x99\x99\x88\xdd",
-		.rlen	= 29,
-	}, {
-		.key	= "\xd7\x82\x8d\x13\xb2\xb0\xbd\xc3"
-			  "\x25\xa7\x62\x36\xdf\x93\xcc\x6b",
-		.klen	= 16,
-		.iv	= "\x01\x00\x33\x56\x8e\xf7\xb2\x63"
-			  "\x3c\x96\x96\x76\x6c\xfa\x00\x00",
-		.assoc	= "\x63\x01\x8f\x76\xdc\x8a\x1b\xcb",
-		.alen	= 8,
-		.input	= "\x90\x20\xea\x6f\x91\xbd\xd8\x5a"
-			  "\xfa\x00\x39\xba\x4b\xaf\xf9\xbf"
-			  "\xb7\x9c\x70\x28\x94\x9c\xd0\xec",
-		.ilen	= 24,
-		.result	= "\x4c\xcb\x1e\x7c\xa9\x81\xbe\xfa"
-			  "\xa0\x72\x6c\x55\xd3\x78\x06\x12"
-			  "\x98\xc8\x5c\x92\x81\x4a\xbc\x33"
-			  "\xc5\x2e\xe8\x1d\x7d\x77\xc0\x8a",
-		.rlen	= 32,
-	}, {
-		.key	= "\xd7\x82\x8d\x13\xb2\xb0\xbd\xc3"
-			  "\x25\xa7\x62\x36\xdf\x93\xcc\x6b",
-		.klen	= 16,
-		.iv	= "\x01\x00\xd5\x60\x91\x2d\x3f\x70"
-			  "\x3c\x96\x96\x76\x6c\xfa\x00\x00",
-		.assoc	= "\xcd\x90\x44\xd2\xb7\x1f\xdb\x81"
-			  "\x20\xea\x60\xc0",
-		.alen	= 12,
-		.input	= "\x64\x35\xac\xba\xfb\x11\xa8\x2e"
-			  "\x2f\x07\x1d\x7c\xa4\xa5\xeb\xd9"
-			  "\x3a\x80\x3b\xa8\x7f",
-		.ilen	= 21,
-		.result	= "\x00\x97\x69\xec\xab\xdf\x48\x62"
-			  "\x55\x94\xc5\x92\x51\xe6\x03\x57"
-			  "\x22\x67\x5e\x04\xc8\x47\x09\x9e"
-			  "\x5a\xe0\x70\x45\x51",
-		.rlen	= 29,
-	}, {
-		.key	= "\xd7\x82\x8d\x13\xb2\xb0\xbd\xc3"
-			  "\x25\xa7\x62\x36\xdf\x93\xcc\x6b",
-		.klen	= 16,
-		.iv	= "\x01\x00\x42\xff\xf8\xf1\x95\x1c"
-			  "\x3c\x96\x96\x76\x6c\xfa\x00\x00",
-		.assoc	= "\xd8\x5b\xc7\xe6\x9f\x94\x4f\xb8",
-		.alen	= 8,
-		.input	= "\x8a\x19\xb9\x50\xbc\xf7\x1a\x01"
-			  "\x8e\x5e\x67\x01\xc9\x17\x87\x65"
-			  "\x98\x09\xd6\x7d\xbe\xdd\x18",
-		.ilen	= 23,
-		.result	= "\xbc\x21\x8d\xaa\x94\x74\x27\xb6"
-			  "\xdb\x38\x6a\x99\xac\x1a\xef\x23"
-			  "\xad\xe0\xb5\x29\x39\xcb\x6a\x63"
-			  "\x7c\xf9\xbe\xc2\x40\x88\x97\xc6"
-			  "\xba",
-		.rlen	= 33,
-	},
-};
-
-static struct aead_testvec aes_ccm_dec_tv_template[] = {
-	{ /* From RFC 3610 */
-		.key	= "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7"
-			  "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf",
-		.klen	= 16,
-		.iv	= "\x01\x00\x00\x00\x03\x02\x01\x00"
-			  "\xa0\xa1\xa2\xa3\xa4\xa5\x00\x00",
-		.assoc	= "\x00\x01\x02\x03\x04\x05\x06\x07",
-		.alen	= 8,
-		.input	= "\x58\x8c\x97\x9a\x61\xc6\x63\xd2"
-			  "\xf0\x66\xd0\xc2\xc0\xf9\x89\x80"
-			  "\x6d\x5f\x6b\x61\xda\xc3\x84\x17"
-			  "\xe8\xd1\x2c\xfd\xf9\x26\xe0",
-		.ilen	= 31,
-		.result	= "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
-			  "\x10\x11\x12\x13\x14\x15\x16\x17"
-			  "\x18\x19\x1a\x1b\x1c\x1d\x1e",
-		.rlen	= 23,
-	}, {
-		.key	= "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7"
-			  "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf",
-		.klen	= 16,
-		.iv	= "\x01\x00\x00\x00\x07\x06\x05\x04"
-			  "\xa0\xa1\xa2\xa3\xa4\xa5\x00\x00",
-		.assoc	= "\x00\x01\x02\x03\x04\x05\x06\x07"
-			  "\x08\x09\x0a\x0b",
-		.alen	= 12,
-		.input	= "\xdc\xf1\xfb\x7b\x5d\x9e\x23\xfb"
-			  "\x9d\x4e\x13\x12\x53\x65\x8a\xd8"
-			  "\x6e\xbd\xca\x3e\x51\xe8\x3f\x07"
-			  "\x7d\x9c\x2d\x93",
-		.ilen	= 28,
-		.result	= "\x0c\x0d\x0e\x0f\x10\x11\x12\x13"
-			  "\x14\x15\x16\x17\x18\x19\x1a\x1b"
-			  "\x1c\x1d\x1e\x1f",
-		.rlen	= 20,
-	}, {
-		.key	= "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7"
-			  "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf",
-		.klen	= 16,
-		.iv	= "\x01\x00\x00\x00\x0b\x0a\x09\x08"
-			  "\xa0\xa1\xa2\xa3\xa4\xa5\x00\x00",
-		.assoc	= "\x00\x01\x02\x03\x04\x05\x06\x07",
-		.alen	= 8,
-		.input	= "\x82\x53\x1a\x60\xcc\x24\x94\x5a"
-			  "\x4b\x82\x79\x18\x1a\xb5\xc8\x4d"
-			  "\xf2\x1c\xe7\xf9\xb7\x3f\x42\xe1"
-			  "\x97\xea\x9c\x07\xe5\x6b\x5e\xb1"
-			  "\x7e\x5f\x4e",
-		.ilen	= 35,
-		.result	= "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
-			  "\x10\x11\x12\x13\x14\x15\x16\x17"
-			  "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
-			  "\x20",
-		.rlen	= 25,
-	}, {
-		.key	= "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7"
-			  "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf",
-		.klen	= 16,
-		.iv	= "\x01\x00\x00\x00\x0c\x0b\x0a\x09"
-			  "\xa0\xa1\xa2\xa3\xa4\xa5\x00\x00",
-		.assoc	= "\x00\x01\x02\x03\x04\x05\x06\x07"
-			  "\x08\x09\x0a\x0b",
-		.alen	= 12,
-		.input	= "\x07\x34\x25\x94\x15\x77\x85\x15"
-			  "\x2b\x07\x40\x98\x33\x0a\xbb\x14"
-			  "\x1b\x94\x7b\x56\x6a\xa9\x40\x6b"
-			  "\x4d\x99\x99\x88\xdd",
-		.ilen	= 29,
-		.result	= "\x0c\x0d\x0e\x0f\x10\x11\x12\x13"
-			  "\x14\x15\x16\x17\x18\x19\x1a\x1b"
-			  "\x1c\x1d\x1e",
-		.rlen	= 19,
-	}, {
-		.key	= "\xd7\x82\x8d\x13\xb2\xb0\xbd\xc3"
-			  "\x25\xa7\x62\x36\xdf\x93\xcc\x6b",
-		.klen	= 16,
-		.iv	= "\x01\x00\x33\x56\x8e\xf7\xb2\x63"
-			  "\x3c\x96\x96\x76\x6c\xfa\x00\x00",
-		.assoc	= "\x63\x01\x8f\x76\xdc\x8a\x1b\xcb",
-		.alen	= 8,
-		.input	= "\x4c\xcb\x1e\x7c\xa9\x81\xbe\xfa"
-			  "\xa0\x72\x6c\x55\xd3\x78\x06\x12"
-			  "\x98\xc8\x5c\x92\x81\x4a\xbc\x33"
-			  "\xc5\x2e\xe8\x1d\x7d\x77\xc0\x8a",
-		.ilen	= 32,
-		.result	= "\x90\x20\xea\x6f\x91\xbd\xd8\x5a"
-			  "\xfa\x00\x39\xba\x4b\xaf\xf9\xbf"
-			  "\xb7\x9c\x70\x28\x94\x9c\xd0\xec",
-		.rlen	= 24,
-	}, {
-		.key	= "\xd7\x82\x8d\x13\xb2\xb0\xbd\xc3"
-			  "\x25\xa7\x62\x36\xdf\x93\xcc\x6b",
-		.klen	= 16,
-		.iv	= "\x01\x00\xd5\x60\x91\x2d\x3f\x70"
-			  "\x3c\x96\x96\x76\x6c\xfa\x00\x00",
-		.assoc	= "\xcd\x90\x44\xd2\xb7\x1f\xdb\x81"
-			  "\x20\xea\x60\xc0",
-		.alen	= 12,
-		.input	= "\x00\x97\x69\xec\xab\xdf\x48\x62"
-			  "\x55\x94\xc5\x92\x51\xe6\x03\x57"
-			  "\x22\x67\x5e\x04\xc8\x47\x09\x9e"
-			  "\x5a\xe0\x70\x45\x51",
-		.ilen	= 29,
-		.result	= "\x64\x35\xac\xba\xfb\x11\xa8\x2e"
-			  "\x2f\x07\x1d\x7c\xa4\xa5\xeb\xd9"
-			  "\x3a\x80\x3b\xa8\x7f",
-		.rlen	= 21,
-	}, {
-		.key	= "\xd7\x82\x8d\x13\xb2\xb0\xbd\xc3"
-			  "\x25\xa7\x62\x36\xdf\x93\xcc\x6b",
-		.klen	= 16,
-		.iv	= "\x01\x00\x42\xff\xf8\xf1\x95\x1c"
-			  "\x3c\x96\x96\x76\x6c\xfa\x00\x00",
-		.assoc	= "\xd8\x5b\xc7\xe6\x9f\x94\x4f\xb8",
-		.alen	= 8,
-		.input	= "\xbc\x21\x8d\xaa\x94\x74\x27\xb6"
-			  "\xdb\x38\x6a\x99\xac\x1a\xef\x23"
-			  "\xad\xe0\xb5\x29\x39\xcb\x6a\x63"
-			  "\x7c\xf9\xbe\xc2\x40\x88\x97\xc6"
-			  "\xba",
-		.ilen	= 33,
-		.result	= "\x8a\x19\xb9\x50\xbc\xf7\x1a\x01"
-			  "\x8e\x5e\x67\x01\xc9\x17\x87\x65"
-			  "\x98\x09\xd6\x7d\xbe\xdd\x18",
-		.rlen	= 23,
-	},
-};
-
-/* Cast5 test vectors from RFC 2144 */
-#define CAST5_ENC_TEST_VECTORS	3
-#define CAST5_DEC_TEST_VECTORS	3
-
-static struct cipher_testvec cast5_enc_tv_template[] = {
-	{
-		.key	= "\x01\x23\x45\x67\x12\x34\x56\x78"
-			  "\x23\x45\x67\x89\x34\x56\x78\x9a",
-		.klen	= 16,
-		.input	= "\x01\x23\x45\x67\x89\xab\xcd\xef",
-		.ilen	= 8,
-		.result	= "\x23\x8b\x4f\xe5\x84\x7e\x44\xb2",
-		.rlen	= 8,
-	}, {
-		.key	= "\x01\x23\x45\x67\x12\x34\x56\x78"
-			  "\x23\x45",
-		.klen	= 10,
-		.input	= "\x01\x23\x45\x67\x89\xab\xcd\xef",
-		.ilen	= 8,
-		.result	= "\xeb\x6a\x71\x1a\x2c\x02\x27\x1b",
-		.rlen	= 8,
-	}, {
-		.key	= "\x01\x23\x45\x67\x12",
-		.klen	= 5,
-		.input	= "\x01\x23\x45\x67\x89\xab\xcd\xef",
-		.ilen	= 8,
-		.result	= "\x7a\xc8\x16\xd1\x6e\x9b\x30\x2e",
-		.rlen	= 8,
-	},
-};
-
-static struct cipher_testvec cast5_dec_tv_template[] = {
-	{
-		.key	= "\x01\x23\x45\x67\x12\x34\x56\x78"
-			  "\x23\x45\x67\x89\x34\x56\x78\x9a",
-		.klen	= 16,
-		.input	= "\x23\x8b\x4f\xe5\x84\x7e\x44\xb2",
-		.ilen	= 8,
-		.result	= "\x01\x23\x45\x67\x89\xab\xcd\xef",
-		.rlen	= 8,
-	}, {
-		.key	= "\x01\x23\x45\x67\x12\x34\x56\x78"
-			  "\x23\x45",
-		.klen	= 10,
-		.input	= "\xeb\x6a\x71\x1a\x2c\x02\x27\x1b",
-		.ilen	= 8,
-		.result	= "\x01\x23\x45\x67\x89\xab\xcd\xef",
-		.rlen	= 8,
-	}, {
-		.key	= "\x01\x23\x45\x67\x12",
-		.klen	= 5,
-		.input	= "\x7a\xc8\x16\xd1\x6e\x9b\x30\x2e",
-		.ilen	= 8,
-		.result	= "\x01\x23\x45\x67\x89\xab\xcd\xef",
-		.rlen	= 8,
-	},
-};
-
-/*
- * ARC4 test vectors from OpenSSL
- */
-#define ARC4_ENC_TEST_VECTORS	7
-#define ARC4_DEC_TEST_VECTORS	7
-
-static struct cipher_testvec arc4_enc_tv_template[] = {
-	{
-		.key	= "\x01\x23\x45\x67\x89\xab\xcd\xef",
-		.klen	= 8,
-		.input	= "\x01\x23\x45\x67\x89\xab\xcd\xef",
-		.ilen	= 8,
-		.result	= "\x75\xb7\x87\x80\x99\xe0\xc5\x96",
-		.rlen	= 8,
-	}, {
-		.key	= "\x01\x23\x45\x67\x89\xab\xcd\xef",
-		.klen	= 8,
-		.input	= "\x00\x00\x00\x00\x00\x00\x00\x00",
-		.ilen	= 8,
-		.result	= "\x74\x94\xc2\xe7\x10\x4b\x08\x79",
-		.rlen	= 8,
-	}, {
-		.key	= "\x00\x00\x00\x00\x00\x00\x00\x00",
-		.klen	= 8,
-		.input	= "\x00\x00\x00\x00\x00\x00\x00\x00",
-		.ilen	= 8,
-		.result	= "\xde\x18\x89\x41\xa3\x37\x5d\x3a",
-		.rlen	= 8,
-	}, {
-		.key	= "\xef\x01\x23\x45",
-		.klen	= 4,
-		.input	= "\x00\x00\x00\x00\x00\x00\x00\x00"
-			  "\x00\x00\x00\x00\x00\x00\x00\x00"
-			  "\x00\x00\x00\x00",
-		.ilen	= 20,
-		.result	= "\xd6\xa1\x41\xa7\xec\x3c\x38\xdf"
-			  "\xbd\x61\x5a\x11\x62\xe1\xc7\xba"
-			  "\x36\xb6\x78\x58",
-		.rlen	= 20,
-	}, {
-		.key	= "\x01\x23\x45\x67\x89\xab\xcd\xef",
-		.klen	= 8,
-		.input	= "\x12\x34\x56\x78\x9A\xBC\xDE\xF0"
-			  "\x12\x34\x56\x78\x9A\xBC\xDE\xF0"
-			  "\x12\x34\x56\x78\x9A\xBC\xDE\xF0"
-			  "\x12\x34\x56\x78",
-		.ilen	= 28,
-		.result	= "\x66\xa0\x94\x9f\x8a\xf7\xd6\x89"
-			  "\x1f\x7f\x83\x2b\xa8\x33\xc0\x0c"
-			  "\x89\x2e\xbe\x30\x14\x3c\xe2\x87"
-			  "\x40\x01\x1e\xcf",
-		.rlen	= 28,
-	}, {
-		.key	= "\xef\x01\x23\x45",
-		.klen	= 4,
-		.input	= "\x00\x00\x00\x00\x00\x00\x00\x00"
-			  "\x00\x00",
-		.ilen	= 10,
-		.result	= "\xd6\xa1\x41\xa7\xec\x3c\x38\xdf"
-			  "\xbd\x61",
-		.rlen	= 10,
-	}, {
-		.key	= "\x01\x23\x45\x67\x89\xAB\xCD\xEF"
-			"\x00\x00\x00\x00\x00\x00\x00\x00",
-		.klen	= 16,
-		.input	= "\x01\x23\x45\x67\x89\xAB\xCD\xEF",
-		.ilen	= 8,
-		.result	= "\x69\x72\x36\x59\x1B\x52\x42\xB1",
-		.rlen	= 8,
-	},
-};
-
-static struct cipher_testvec arc4_dec_tv_template[] = {
-	{
-		.key	= "\x01\x23\x45\x67\x89\xab\xcd\xef",
-		.klen	= 8,
-		.input	= "\x75\xb7\x87\x80\x99\xe0\xc5\x96",
-		.ilen	= 8,
-		.result	= "\x01\x23\x45\x67\x89\xab\xcd\xef",
-		.rlen	= 8,
-	}, {
-		.key	= "\x01\x23\x45\x67\x89\xab\xcd\xef",
-		.klen	= 8,
-		.input	= "\x74\x94\xc2\xe7\x10\x4b\x08\x79",
-		.ilen	= 8,
-		.result	= "\x00\x00\x00\x00\x00\x00\x00\x00",
-		.rlen	= 8,
-	}, {
-		.key	= "\x00\x00\x00\x00\x00\x00\x00\x00",
-		.klen	= 8,
-		.input	= "\xde\x18\x89\x41\xa3\x37\x5d\x3a",
-		.ilen	= 8,
-		.result	= "\x00\x00\x00\x00\x00\x00\x00\x00",
-		.rlen	= 8,
-	}, {
-		.key	= "\xef\x01\x23\x45",
-		.klen	= 4,
-		.input	= "\xd6\xa1\x41\xa7\xec\x3c\x38\xdf"
-			  "\xbd\x61\x5a\x11\x62\xe1\xc7\xba"
-			  "\x36\xb6\x78\x58",
-		.ilen	= 20,
-		.result	= "\x00\x00\x00\x00\x00\x00\x00\x00"
-			  "\x00\x00\x00\x00\x00\x00\x00\x00"
-			  "\x00\x00\x00\x00",
-		.rlen	= 20,
-	}, {
-		.key	= "\x01\x23\x45\x67\x89\xab\xcd\xef",
-		.klen	= 8,
-		.input	= "\x66\xa0\x94\x9f\x8a\xf7\xd6\x89"
-			  "\x1f\x7f\x83\x2b\xa8\x33\xc0\x0c"
-			  "\x89\x2e\xbe\x30\x14\x3c\xe2\x87"
-			  "\x40\x01\x1e\xcf",
-		.ilen	= 28,
-		.result	= "\x12\x34\x56\x78\x9A\xBC\xDE\xF0"
-			  "\x12\x34\x56\x78\x9A\xBC\xDE\xF0"
-			  "\x12\x34\x56\x78\x9A\xBC\xDE\xF0"
-			  "\x12\x34\x56\x78",
-		.rlen	= 28,
-	}, {
-		.key	= "\xef\x01\x23\x45",
-		.klen	= 4,
-		.input	= "\xd6\xa1\x41\xa7\xec\x3c\x38\xdf"
-			  "\xbd\x61",
-		.ilen	= 10,
-		.result	= "\x00\x00\x00\x00\x00\x00\x00\x00"
-			  "\x00\x00",
-		.rlen	= 10,
-	}, {
-		.key	= "\x01\x23\x45\x67\x89\xAB\xCD\xEF"
-			"\x00\x00\x00\x00\x00\x00\x00\x00",
-		.klen	= 16,
-		.input	= "\x69\x72\x36\x59\x1B\x52\x42\xB1",
-		.ilen	= 8,
-		.result	= "\x01\x23\x45\x67\x89\xAB\xCD\xEF",
-		.rlen	= 8,
-	},
-};
-
-/*
- * TEA test vectors
- */
-#define TEA_ENC_TEST_VECTORS	4
-#define TEA_DEC_TEST_VECTORS	4
-
-static struct cipher_testvec tea_enc_tv_template[] = {
-	{
-		.key    = zeroed_string,
-		.klen	= 16,
-		.input  = zeroed_string,
-		.ilen	= 8,
-		.result	= "\x0a\x3a\xea\x41\x40\xa9\xba\x94",
-		.rlen	= 8,
-	}, {
-		.key	= "\x2b\x02\x05\x68\x06\x14\x49\x76"
-			  "\x77\x5d\x0e\x26\x6c\x28\x78\x43",
-		.klen	= 16,
-		.input	= "\x74\x65\x73\x74\x20\x6d\x65\x2e",
-		.ilen	= 8,
-		.result	= "\x77\x5d\x2a\x6a\xf6\xce\x92\x09",
-		.rlen	= 8,
-	}, {
-		.key	= "\x09\x65\x43\x11\x66\x44\x39\x25"
-			  "\x51\x3a\x16\x10\x0a\x08\x12\x6e",
-		.klen	= 16,
-		.input	= "\x6c\x6f\x6e\x67\x65\x72\x5f\x74"
-			  "\x65\x73\x74\x5f\x76\x65\x63\x74",
-		.ilen	= 16,
-		.result	= "\xbe\x7a\xbb\x81\x95\x2d\x1f\x1e"
-			  "\xdd\x89\xa1\x25\x04\x21\xdf\x95",
-		.rlen	= 16,
-	}, {
-		.key	= "\x4d\x76\x32\x17\x05\x3f\x75\x2c"
-			  "\x5d\x04\x16\x36\x15\x72\x63\x2f",
-		.klen	= 16,
-		.input	= "\x54\x65\x61\x20\x69\x73\x20\x67"
-			  "\x6f\x6f\x64\x20\x66\x6f\x72\x20"
-			  "\x79\x6f\x75\x21\x21\x21\x20\x72"
-			  "\x65\x61\x6c\x6c\x79\x21\x21\x21",
-		.ilen	= 32,
-		.result	= "\xe0\x4d\x5d\x3c\xb7\x8c\x36\x47"
-			  "\x94\x18\x95\x91\xa9\xfc\x49\xf8"
-			  "\x44\xd1\x2d\xc2\x99\xb8\x08\x2a"
-			  "\x07\x89\x73\xc2\x45\x92\xc6\x90",
-		.rlen	= 32,
-	}
-};
-
-static struct cipher_testvec tea_dec_tv_template[] = {
-	{
-		.key    = zeroed_string,
-		.klen	= 16,
-		.input	= "\x0a\x3a\xea\x41\x40\xa9\xba\x94",
-		.ilen	= 8,
-		.result = zeroed_string,
-		.rlen	= 8,
-	}, {
-		.key	= "\x2b\x02\x05\x68\x06\x14\x49\x76"
-			  "\x77\x5d\x0e\x26\x6c\x28\x78\x43",
-		.klen	= 16,
-		.input	= "\x77\x5d\x2a\x6a\xf6\xce\x92\x09",
-		.ilen	= 8,
-		.result	= "\x74\x65\x73\x74\x20\x6d\x65\x2e",
-		.rlen	= 8,
-	}, {
-		.key	= "\x09\x65\x43\x11\x66\x44\x39\x25"
-			  "\x51\x3a\x16\x10\x0a\x08\x12\x6e",
-		.klen	= 16,
-		.input	= "\xbe\x7a\xbb\x81\x95\x2d\x1f\x1e"
-			  "\xdd\x89\xa1\x25\x04\x21\xdf\x95",
-		.ilen   = 16,
-		.result	= "\x6c\x6f\x6e\x67\x65\x72\x5f\x74"
-			  "\x65\x73\x74\x5f\x76\x65\x63\x74",
-		.rlen	= 16,
-	}, {
-		.key	= "\x4d\x76\x32\x17\x05\x3f\x75\x2c"
-			  "\x5d\x04\x16\x36\x15\x72\x63\x2f",
-		.klen	= 16,
-		.input	= "\xe0\x4d\x5d\x3c\xb7\x8c\x36\x47"
-			  "\x94\x18\x95\x91\xa9\xfc\x49\xf8"
-			  "\x44\xd1\x2d\xc2\x99\xb8\x08\x2a"
-			  "\x07\x89\x73\xc2\x45\x92\xc6\x90",
-		.ilen	= 32,
-		.result	= "\x54\x65\x61\x20\x69\x73\x20\x67"
-			  "\x6f\x6f\x64\x20\x66\x6f\x72\x20"
-			  "\x79\x6f\x75\x21\x21\x21\x20\x72"
-			  "\x65\x61\x6c\x6c\x79\x21\x21\x21",
-		.rlen	= 32,
-	}
-};
-
-/*
- * XTEA test vectors
- */
-#define XTEA_ENC_TEST_VECTORS	4
-#define XTEA_DEC_TEST_VECTORS	4
-
-static struct cipher_testvec xtea_enc_tv_template[] = {
-	{
-		.key    = zeroed_string,
-		.klen	= 16,
-		.input  = zeroed_string,
-		.ilen	= 8,
-		.result	= "\xd8\xd4\xe9\xde\xd9\x1e\x13\xf7",
-		.rlen	= 8,
-	}, {
-		.key	= "\x2b\x02\x05\x68\x06\x14\x49\x76"
-			  "\x77\x5d\x0e\x26\x6c\x28\x78\x43",
-		.klen	= 16,
-		.input	= "\x74\x65\x73\x74\x20\x6d\x65\x2e",
-		.ilen	= 8,
-		.result	= "\x94\xeb\xc8\x96\x84\x6a\x49\xa8",
-		.rlen	= 8,
-	}, {
-		.key	= "\x09\x65\x43\x11\x66\x44\x39\x25"
-			  "\x51\x3a\x16\x10\x0a\x08\x12\x6e",
-		.klen	= 16,
-		.input	= "\x6c\x6f\x6e\x67\x65\x72\x5f\x74"
-			  "\x65\x73\x74\x5f\x76\x65\x63\x74",
-		.ilen	= 16,
-		.result	= "\x3e\xce\xae\x22\x60\x56\xa8\x9d"
-			  "\x77\x4d\xd4\xb4\x87\x24\xe3\x9a",
-		.rlen	= 16,
-	}, {
-		.key	= "\x4d\x76\x32\x17\x05\x3f\x75\x2c"
-			  "\x5d\x04\x16\x36\x15\x72\x63\x2f",
-		.klen	= 16,
-		.input	= "\x54\x65\x61\x20\x69\x73\x20\x67"
-			  "\x6f\x6f\x64\x20\x66\x6f\x72\x20"
-			  "\x79\x6f\x75\x21\x21\x21\x20\x72"
-			  "\x65\x61\x6c\x6c\x79\x21\x21\x21",
-		.ilen	= 32,
-		.result	= "\x99\x81\x9f\x5d\x6f\x4b\x31\x3a"
-			  "\x86\xff\x6f\xd0\xe3\x87\x70\x07"
-			  "\x4d\xb8\xcf\xf3\x99\x50\xb3\xd4"
-			  "\x73\xa2\xfa\xc9\x16\x59\x5d\x81",
-		.rlen	= 32,
-	}
-};
-
-static struct cipher_testvec xtea_dec_tv_template[] = {
-	{
-		.key    = zeroed_string,
-		.klen	= 16,
-		.input	= "\xd8\xd4\xe9\xde\xd9\x1e\x13\xf7",
-		.ilen	= 8,
-		.result = zeroed_string,
-		.rlen	= 8,
-	}, {
-		.key	= "\x2b\x02\x05\x68\x06\x14\x49\x76"
-			  "\x77\x5d\x0e\x26\x6c\x28\x78\x43",
-		.klen	= 16,
-		.input	= "\x94\xeb\xc8\x96\x84\x6a\x49\xa8",
-		.ilen	= 8,
-		.result	= "\x74\x65\x73\x74\x20\x6d\x65\x2e",
-		.rlen	= 8,
-	}, {
-		.key	= "\x09\x65\x43\x11\x66\x44\x39\x25"
-			  "\x51\x3a\x16\x10\x0a\x08\x12\x6e",
-		.klen	= 16,
-		.input	= "\x3e\xce\xae\x22\x60\x56\xa8\x9d"
-			  "\x77\x4d\xd4\xb4\x87\x24\xe3\x9a",
-		.ilen	= 16,
-		.result	= "\x6c\x6f\x6e\x67\x65\x72\x5f\x74"
-			  "\x65\x73\x74\x5f\x76\x65\x63\x74",
-		.rlen	= 16,
-	}, {
-		.key	= "\x4d\x76\x32\x17\x05\x3f\x75\x2c"
-			  "\x5d\x04\x16\x36\x15\x72\x63\x2f",
-		.klen	= 16,
-		.input	= "\x99\x81\x9f\x5d\x6f\x4b\x31\x3a"
-			  "\x86\xff\x6f\xd0\xe3\x87\x70\x07"
-			  "\x4d\xb8\xcf\xf3\x99\x50\xb3\xd4"
-			  "\x73\xa2\xfa\xc9\x16\x59\x5d\x81",
-		.ilen	= 32,
-		.result	= "\x54\x65\x61\x20\x69\x73\x20\x67"
-			  "\x6f\x6f\x64\x20\x66\x6f\x72\x20"
-			  "\x79\x6f\x75\x21\x21\x21\x20\x72"
-			  "\x65\x61\x6c\x6c\x79\x21\x21\x21",
-		.rlen	= 32,
-	}
-};
-
-/*
- * KHAZAD test vectors.
- */
-#define KHAZAD_ENC_TEST_VECTORS 5
-#define KHAZAD_DEC_TEST_VECTORS 5
-
-static struct cipher_testvec khazad_enc_tv_template[] = {
-	{
-		.key	= "\x80\x00\x00\x00\x00\x00\x00\x00"
-			  "\x00\x00\x00\x00\x00\x00\x00\x00",
-		.klen	= 16,
-		.input	= "\x00\x00\x00\x00\x00\x00\x00\x00",
-		.ilen	= 8,
-		.result	= "\x49\xa4\xce\x32\xac\x19\x0e\x3f",
-		.rlen	= 8,
-	}, {
-		.key	= "\x38\x38\x38\x38\x38\x38\x38\x38"
-			  "\x38\x38\x38\x38\x38\x38\x38\x38",
-		.klen	= 16,
-		.input	= "\x38\x38\x38\x38\x38\x38\x38\x38",
-		.ilen	= 8,
-		.result	= "\x7e\x82\x12\xa1\xd9\x5b\xe4\xf9",
-		.rlen	= 8,
-	}, {
-		.key	= "\xa2\xa2\xa2\xa2\xa2\xa2\xa2\xa2"
-			"\xa2\xa2\xa2\xa2\xa2\xa2\xa2\xa2",
-		.klen	= 16,
-		.input	= "\xa2\xa2\xa2\xa2\xa2\xa2\xa2\xa2",
-		.ilen	= 8,
-		.result	= "\xaa\xbe\xc1\x95\xc5\x94\x1a\x9c",
-		.rlen	= 8,
-	}, {
-		.key	= "\x2f\x2f\x2f\x2f\x2f\x2f\x2f\x2f"
-			"\x2f\x2f\x2f\x2f\x2f\x2f\x2f\x2f",
-		.klen	= 16,
-		.input	= "\x2f\x2f\x2f\x2f\x2f\x2f\x2f\x2f",
-		.ilen	= 8,
-		.result = "\x04\x74\xf5\x70\x50\x16\xd3\xb8",
-		.rlen	= 8,
-	}, {
-		.key	= "\x2f\x2f\x2f\x2f\x2f\x2f\x2f\x2f"
-			"\x2f\x2f\x2f\x2f\x2f\x2f\x2f\x2f",
-		.klen	= 16,
-		.input	= "\x2f\x2f\x2f\x2f\x2f\x2f\x2f\x2f"
-			"\x2f\x2f\x2f\x2f\x2f\x2f\x2f\x2f",
-		.ilen	= 16,
-		.result = "\x04\x74\xf5\x70\x50\x16\xd3\xb8"
-			"\x04\x74\xf5\x70\x50\x16\xd3\xb8",
-		.rlen	= 16,
-	},
-};
-
-static struct cipher_testvec khazad_dec_tv_template[] = {
-	{
-		.key	= "\x80\x00\x00\x00\x00\x00\x00\x00"
-			  "\x00\x00\x00\x00\x00\x00\x00\x00",
-		.klen	= 16,
-		.input	= "\x49\xa4\xce\x32\xac\x19\x0e\x3f",
-		.ilen	= 8,
-		.result	= "\x00\x00\x00\x00\x00\x00\x00\x00",
-		.rlen	= 8,
-	}, {
-		.key	= "\x38\x38\x38\x38\x38\x38\x38\x38"
-			  "\x38\x38\x38\x38\x38\x38\x38\x38",
-		.klen	= 16,
-		.input	= "\x7e\x82\x12\xa1\xd9\x5b\xe4\xf9",
-		.ilen	= 8,
-		.result	= "\x38\x38\x38\x38\x38\x38\x38\x38",
-		.rlen	= 8,
-	}, {
-		.key	= "\xa2\xa2\xa2\xa2\xa2\xa2\xa2\xa2"
-			"\xa2\xa2\xa2\xa2\xa2\xa2\xa2\xa2",
-		.klen	= 16,
-		.input	= "\xaa\xbe\xc1\x95\xc5\x94\x1a\x9c",
-		.ilen	= 8,
-		.result	= "\xa2\xa2\xa2\xa2\xa2\xa2\xa2\xa2",
-		.rlen	= 8,
-	}, {
-		.key	= "\x2f\x2f\x2f\x2f\x2f\x2f\x2f\x2f"
-			"\x2f\x2f\x2f\x2f\x2f\x2f\x2f\x2f",
-		.klen	= 16,
-		.input  = "\x04\x74\xf5\x70\x50\x16\xd3\xb8",
-		.ilen	= 8,
-		.result	= "\x2f\x2f\x2f\x2f\x2f\x2f\x2f\x2f",
-		.rlen	= 8,
-	}, {
-		.key	= "\x2f\x2f\x2f\x2f\x2f\x2f\x2f\x2f"
-			"\x2f\x2f\x2f\x2f\x2f\x2f\x2f\x2f",
-		.klen	= 16,
-		.input  = "\x04\x74\xf5\x70\x50\x16\xd3\xb8"
-			"\x04\x74\xf5\x70\x50\x16\xd3\xb8",
-		.ilen	= 16,
-		.result	= "\x2f\x2f\x2f\x2f\x2f\x2f\x2f\x2f"
-			"\x2f\x2f\x2f\x2f\x2f\x2f\x2f\x2f",
-		.rlen	= 16,
-	},
-};
-
-/*
- * Anubis test vectors.
- */
-
-#define ANUBIS_ENC_TEST_VECTORS			5
-#define ANUBIS_DEC_TEST_VECTORS			5
-#define ANUBIS_CBC_ENC_TEST_VECTORS		2
-#define ANUBIS_CBC_DEC_TEST_VECTORS		2
-
-static struct cipher_testvec anubis_enc_tv_template[] = {
-	{
-		.key	= "\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe"
-			  "\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe",
-		.klen	= 16,
-		.input	= "\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe"
-			  "\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe",
-		.ilen	= 16,
-		.result	= "\x6d\xc5\xda\xa2\x26\x7d\x62\x6f"
-			  "\x08\xb7\x52\x8e\x6e\x6e\x86\x90",
-		.rlen	= 16,
-	}, {
-
-		.key	= "\x03\x03\x03\x03\x03\x03\x03\x03"
-			  "\x03\x03\x03\x03\x03\x03\x03\x03"
-			  "\x03\x03\x03\x03",
-		.klen	= 20,
-		.input	= "\x03\x03\x03\x03\x03\x03\x03\x03"
-			  "\x03\x03\x03\x03\x03\x03\x03\x03",
-		.ilen	= 16,
-		.result	= "\xdb\xf1\x42\xf4\xd1\x8a\xc7\x49"
-			  "\x87\x41\x6f\x82\x0a\x98\x64\xae",
-		.rlen	= 16,
-	}, {
-		.key	= "\x24\x24\x24\x24\x24\x24\x24\x24"
-			  "\x24\x24\x24\x24\x24\x24\x24\x24"
-			  "\x24\x24\x24\x24\x24\x24\x24\x24"
-			  "\x24\x24\x24\x24",
-		.klen	= 28,
-		.input	= "\x24\x24\x24\x24\x24\x24\x24\x24"
-			  "\x24\x24\x24\x24\x24\x24\x24\x24",
-		.ilen	= 16,
-		.result	= "\xfd\x1b\x4a\xe3\xbf\xf0\xad\x3d"
-			  "\x06\xd3\x61\x27\xfd\x13\x9e\xde",
-		.rlen	= 16,
-	}, {
-		.key	= "\x25\x25\x25\x25\x25\x25\x25\x25"
-			  "\x25\x25\x25\x25\x25\x25\x25\x25"
-			  "\x25\x25\x25\x25\x25\x25\x25\x25"
-			  "\x25\x25\x25\x25\x25\x25\x25\x25",
-		.klen	= 32,
-		.input	= "\x25\x25\x25\x25\x25\x25\x25\x25"
-			  "\x25\x25\x25\x25\x25\x25\x25\x25",
-		.ilen	= 16,
-		.result	= "\x1a\x91\xfb\x2b\xb7\x78\x6b\xc4"
-			"\x17\xd9\xff\x40\x3b\x0e\xe5\xfe",
-		.rlen	= 16,
-	}, {
-		.key	= "\x35\x35\x35\x35\x35\x35\x35\x35"
-			  "\x35\x35\x35\x35\x35\x35\x35\x35"
-			  "\x35\x35\x35\x35\x35\x35\x35\x35"
-			  "\x35\x35\x35\x35\x35\x35\x35\x35"
-			  "\x35\x35\x35\x35\x35\x35\x35\x35",
-		.klen	= 40,
-		.input	= "\x35\x35\x35\x35\x35\x35\x35\x35"
-			  "\x35\x35\x35\x35\x35\x35\x35\x35",
-		.ilen	= 16,
-		.result = "\xa5\x2c\x85\x6f\x9c\xba\xa0\x97"
-			  "\x9e\xc6\x84\x0f\x17\x21\x07\xee",
-		.rlen	= 16,
-	},
-};
-
-static struct cipher_testvec anubis_dec_tv_template[] = {
-	{
-		.key	= "\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe"
-			  "\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe",
-		.klen	= 16,
-		.input	= "\x6d\xc5\xda\xa2\x26\x7d\x62\x6f"
-			  "\x08\xb7\x52\x8e\x6e\x6e\x86\x90",
-		.ilen	= 16,
-		.result	= "\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe"
-			  "\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe",
-		.rlen	= 16,
-	}, {
-
-		.key	= "\x03\x03\x03\x03\x03\x03\x03\x03"
-			  "\x03\x03\x03\x03\x03\x03\x03\x03"
-			  "\x03\x03\x03\x03",
-		.klen	= 20,
-		.input	= "\xdb\xf1\x42\xf4\xd1\x8a\xc7\x49"
-			  "\x87\x41\x6f\x82\x0a\x98\x64\xae",
-		.ilen	= 16,
-		.result	= "\x03\x03\x03\x03\x03\x03\x03\x03"
-			  "\x03\x03\x03\x03\x03\x03\x03\x03",
-		.rlen	= 16,
-	}, {
-		.key	= "\x24\x24\x24\x24\x24\x24\x24\x24"
-			  "\x24\x24\x24\x24\x24\x24\x24\x24"
-			  "\x24\x24\x24\x24\x24\x24\x24\x24"
-			  "\x24\x24\x24\x24",
-		.klen	= 28,
-		.input	= "\xfd\x1b\x4a\xe3\xbf\xf0\xad\x3d"
-			  "\x06\xd3\x61\x27\xfd\x13\x9e\xde",
-		.ilen	= 16,
-		.result	= "\x24\x24\x24\x24\x24\x24\x24\x24"
-			  "\x24\x24\x24\x24\x24\x24\x24\x24",
-		.rlen	= 16,
-	}, {
-		.key	= "\x25\x25\x25\x25\x25\x25\x25\x25"
-			  "\x25\x25\x25\x25\x25\x25\x25\x25"
-			  "\x25\x25\x25\x25\x25\x25\x25\x25"
-			  "\x25\x25\x25\x25\x25\x25\x25\x25",
-		.klen	= 32,
-		.input	= "\x1a\x91\xfb\x2b\xb7\x78\x6b\xc4"
-			"\x17\xd9\xff\x40\x3b\x0e\xe5\xfe",
-		.ilen	= 16,
-		.result	= "\x25\x25\x25\x25\x25\x25\x25\x25"
-			  "\x25\x25\x25\x25\x25\x25\x25\x25",
-		.rlen	= 16,
-	}, {
-		.key	= "\x35\x35\x35\x35\x35\x35\x35\x35"
-			  "\x35\x35\x35\x35\x35\x35\x35\x35"
-			  "\x35\x35\x35\x35\x35\x35\x35\x35"
-			  "\x35\x35\x35\x35\x35\x35\x35\x35"
-			  "\x35\x35\x35\x35\x35\x35\x35\x35",
-		.input = "\xa5\x2c\x85\x6f\x9c\xba\xa0\x97"
-			 "\x9e\xc6\x84\x0f\x17\x21\x07\xee",
-		.klen	= 40,
-		.ilen	= 16,
-		.result	= "\x35\x35\x35\x35\x35\x35\x35\x35"
-			  "\x35\x35\x35\x35\x35\x35\x35\x35",
-		.rlen	= 16,
-	},
-};
-
-static struct cipher_testvec anubis_cbc_enc_tv_template[] = {
-	{
-		.key	= "\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe"
-			  "\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe",
-		.klen	= 16,
-		.input	= "\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe"
-			  "\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe"
-			  "\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe"
-			  "\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe",
-		.ilen	= 32,
-		.result	= "\x6d\xc5\xda\xa2\x26\x7d\x62\x6f"
-			  "\x08\xb7\x52\x8e\x6e\x6e\x86\x90"
-			  "\x86\xd8\xb5\x6f\x98\x5e\x8a\x66"
-			  "\x4f\x1f\x78\xa1\xbb\x37\xf1\xbe",
-		.rlen	= 32,
-	}, {
-		.key	= "\x35\x35\x35\x35\x35\x35\x35\x35"
-			  "\x35\x35\x35\x35\x35\x35\x35\x35"
-			  "\x35\x35\x35\x35\x35\x35\x35\x35"
-			  "\x35\x35\x35\x35\x35\x35\x35\x35"
-			  "\x35\x35\x35\x35\x35\x35\x35\x35",
-		.klen	= 40,
-		.input	= "\x35\x35\x35\x35\x35\x35\x35\x35"
-			  "\x35\x35\x35\x35\x35\x35\x35\x35"
-			  "\x35\x35\x35\x35\x35\x35\x35\x35"
-			  "\x35\x35\x35\x35\x35\x35\x35\x35",
-		.ilen	= 32,
-		.result = "\xa5\x2c\x85\x6f\x9c\xba\xa0\x97"
-			  "\x9e\xc6\x84\x0f\x17\x21\x07\xee"
-			  "\xa2\xbc\x06\x98\xc6\x4b\xda\x75"
-			  "\x2e\xaa\xbe\x58\xce\x01\x5b\xc7",
-		.rlen	= 32,
-	},
-};
-
-static struct cipher_testvec anubis_cbc_dec_tv_template[] = {
-	{
-		.key	= "\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe"
-			  "\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe",
-		.klen	= 16,
-		.input	= "\x6d\xc5\xda\xa2\x26\x7d\x62\x6f"
-			  "\x08\xb7\x52\x8e\x6e\x6e\x86\x90"
-			  "\x86\xd8\xb5\x6f\x98\x5e\x8a\x66"
-			  "\x4f\x1f\x78\xa1\xbb\x37\xf1\xbe",
-		.ilen	= 32,
-		.result	= "\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe"
-			  "\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe"
-			  "\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe"
-			  "\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe",
-		.rlen	= 32,
-	}, {
-		.key	= "\x35\x35\x35\x35\x35\x35\x35\x35"
-			  "\x35\x35\x35\x35\x35\x35\x35\x35"
-			  "\x35\x35\x35\x35\x35\x35\x35\x35"
-			  "\x35\x35\x35\x35\x35\x35\x35\x35"
-			  "\x35\x35\x35\x35\x35\x35\x35\x35",
-		.klen	= 40,
-		.input = "\xa5\x2c\x85\x6f\x9c\xba\xa0\x97"
-			  "\x9e\xc6\x84\x0f\x17\x21\x07\xee"
-			  "\xa2\xbc\x06\x98\xc6\x4b\xda\x75"
-			  "\x2e\xaa\xbe\x58\xce\x01\x5b\xc7",
-		.ilen	= 32,
-		.result	= "\x35\x35\x35\x35\x35\x35\x35\x35"
-			  "\x35\x35\x35\x35\x35\x35\x35\x35"
-			  "\x35\x35\x35\x35\x35\x35\x35\x35"
-			  "\x35\x35\x35\x35\x35\x35\x35\x35",
-		.rlen	= 32,
-	},
-};
-
-/* 
- * XETA test vectors 
- */
-#define XETA_ENC_TEST_VECTORS	4
-#define XETA_DEC_TEST_VECTORS	4
-
-static struct cipher_testvec xeta_enc_tv_template[] = {
-	{
-		.key    = zeroed_string,
-		.klen	= 16,
-		.input  = zeroed_string,
-		.ilen	= 8,
-		.result	= "\xaa\x22\x96\xe5\x6c\x61\xf3\x45",
-		.rlen	= 8,
-	}, {
-		.key	= "\x2b\x02\x05\x68\x06\x14\x49\x76"
-			  "\x77\x5d\x0e\x26\x6c\x28\x78\x43",
-		.klen	= 16,
-		.input	= "\x74\x65\x73\x74\x20\x6d\x65\x2e",
-		.ilen	= 8,
-		.result	= "\x82\x3e\xeb\x35\xdc\xdd\xd9\xc3",
-		.rlen	= 8,
-	}, {
-		.key	= "\x09\x65\x43\x11\x66\x44\x39\x25"
-			  "\x51\x3a\x16\x10\x0a\x08\x12\x6e",
-		.klen	= 16,
-		.input	= "\x6c\x6f\x6e\x67\x65\x72\x5f\x74"
-			  "\x65\x73\x74\x5f\x76\x65\x63\x74",
-		.ilen	= 16,
-		.result	= "\xe2\x04\xdb\xf2\x89\x85\x9e\xea"
-			  "\x61\x35\xaa\xed\xb5\xcb\x71\x2c",
-		.rlen	= 16,
-	}, {
-		.key	= "\x4d\x76\x32\x17\x05\x3f\x75\x2c"
-			  "\x5d\x04\x16\x36\x15\x72\x63\x2f",
-		.klen	= 16,
-		.input	= "\x54\x65\x61\x20\x69\x73\x20\x67"
-			  "\x6f\x6f\x64\x20\x66\x6f\x72\x20"
-			  "\x79\x6f\x75\x21\x21\x21\x20\x72"
-			  "\x65\x61\x6c\x6c\x79\x21\x21\x21",
-		.ilen	= 32,
-		.result	= "\x0b\x03\xcd\x8a\xbe\x95\xfd\xb1"
-			  "\xc1\x44\x91\x0b\xa5\xc9\x1b\xb4"
-			  "\xa9\xda\x1e\x9e\xb1\x3e\x2a\x8f"
-			  "\xea\xa5\x6a\x85\xd1\xf4\xa8\xa5",
-		.rlen	= 32,
-	}
-};
-
-static struct cipher_testvec xeta_dec_tv_template[] = {
-	{
-		.key    = zeroed_string,
-		.klen	= 16,
-		.input	= "\xaa\x22\x96\xe5\x6c\x61\xf3\x45",
-		.ilen	= 8,
-		.result = zeroed_string,
-		.rlen	= 8,
-	}, {
-		.key	= "\x2b\x02\x05\x68\x06\x14\x49\x76"
-			  "\x77\x5d\x0e\x26\x6c\x28\x78\x43",
-		.klen	= 16,
-		.input	= "\x82\x3e\xeb\x35\xdc\xdd\xd9\xc3",
-		.ilen	= 8,
-		.result	= "\x74\x65\x73\x74\x20\x6d\x65\x2e",
-		.rlen	= 8,
-	}, {
-		.key	= "\x09\x65\x43\x11\x66\x44\x39\x25"
-			  "\x51\x3a\x16\x10\x0a\x08\x12\x6e",
-		.klen	= 16,
-		.input	= "\xe2\x04\xdb\xf2\x89\x85\x9e\xea"
-			  "\x61\x35\xaa\xed\xb5\xcb\x71\x2c",
-		.ilen	= 16,
-		.result	= "\x6c\x6f\x6e\x67\x65\x72\x5f\x74"
-			  "\x65\x73\x74\x5f\x76\x65\x63\x74",
-		.rlen	= 16,
-	}, {
-		.key	= "\x4d\x76\x32\x17\x05\x3f\x75\x2c"
-			  "\x5d\x04\x16\x36\x15\x72\x63\x2f",
-		.klen	= 16,
-		.input	= "\x0b\x03\xcd\x8a\xbe\x95\xfd\xb1"
-			  "\xc1\x44\x91\x0b\xa5\xc9\x1b\xb4"
-			  "\xa9\xda\x1e\x9e\xb1\x3e\x2a\x8f"
-			  "\xea\xa5\x6a\x85\xd1\xf4\xa8\xa5",
-		.ilen	= 32,
-		.result	= "\x54\x65\x61\x20\x69\x73\x20\x67"
-			  "\x6f\x6f\x64\x20\x66\x6f\x72\x20"
-			  "\x79\x6f\x75\x21\x21\x21\x20\x72"
-			  "\x65\x61\x6c\x6c\x79\x21\x21\x21",
-		.rlen	= 32,
-	}
-};
-
-/* 
- * FCrypt test vectors 
- */
-#define FCRYPT_ENC_TEST_VECTORS	ARRAY_SIZE(fcrypt_pcbc_enc_tv_template)
-#define FCRYPT_DEC_TEST_VECTORS	ARRAY_SIZE(fcrypt_pcbc_dec_tv_template)
-
-static struct cipher_testvec fcrypt_pcbc_enc_tv_template[] = {
-	{ /* http://www.openafs.org/pipermail/openafs-devel/2000-December/005320.html */
-		.key	= "\x00\x00\x00\x00\x00\x00\x00\x00",
-		.klen	= 8,
-		.iv	= "\x00\x00\x00\x00\x00\x00\x00\x00",
-		.input	= "\x00\x00\x00\x00\x00\x00\x00\x00",
-		.ilen	= 8,
-		.result	= "\x0E\x09\x00\xC7\x3E\xF7\xED\x41",
-		.rlen	= 8,
-	}, {
-		.key	= "\x11\x44\x77\xAA\xDD\x00\x33\x66",
-		.klen	= 8,
-		.iv	= "\x00\x00\x00\x00\x00\x00\x00\x00",
-		.input	= "\x12\x34\x56\x78\x9A\xBC\xDE\xF0",
-		.ilen	= 8,
-		.result	= "\xD8\xED\x78\x74\x77\xEC\x06\x80",
-		.rlen	= 8,
-	}, { /* From Arla */
-		.key	= "\xf0\xe1\xd2\xc3\xb4\xa5\x96\x87",
-		.klen	= 8,
-		.iv	= "\xfe\xdc\xba\x98\x76\x54\x32\x10",
-		.input	= "The quick brown fox jumps over the lazy dogs.\0\0",
-		.ilen	= 48,
-		.result	= "\x00\xf0\x0e\x11\x75\xe6\x23\x82"
-			  "\xee\xac\x98\x62\x44\x51\xe4\x84"
-			  "\xc3\x59\xd8\xaa\x64\x60\xae\xf7"
-			  "\xd2\xd9\x13\x79\x72\xa3\x45\x03"
-			  "\x23\xb5\x62\xd7\x0c\xf5\x27\xd1"
-			  "\xf8\x91\x3c\xac\x44\x22\x92\xef",
-		.rlen	= 48,
-	}, {
-		.key	= "\xfe\xdc\xba\x98\x76\x54\x32\x10",
-		.klen	= 8,
-		.iv	= "\xf0\xe1\xd2\xc3\xb4\xa5\x96\x87",
-		.input	= "The quick brown fox jumps over the lazy dogs.\0\0",
-		.ilen	= 48,
-		.result	= "\xca\x90\xf5\x9d\xcb\xd4\xd2\x3c"
-			  "\x01\x88\x7f\x3e\x31\x6e\x62\x9d"
-			  "\xd8\xe0\x57\xa3\x06\x3a\x42\x58"
-			  "\x2a\x28\xfe\x72\x52\x2f\xdd\xe0"
-			  "\x19\x89\x09\x1c\x2a\x8e\x8c\x94"
-			  "\xfc\xc7\x68\xe4\x88\xaa\xde\x0f",
-		.rlen	= 48,
-	}, { /* split-page version */
-		.key	= "\xfe\xdc\xba\x98\x76\x54\x32\x10",
-		.klen	= 8,
-		.iv	= "\xf0\xe1\xd2\xc3\xb4\xa5\x96\x87",
-		.input	= "The quick brown fox jumps over the lazy dogs.\0\0",
-		.ilen	= 48,
-		.result	= "\xca\x90\xf5\x9d\xcb\xd4\xd2\x3c"
-			  "\x01\x88\x7f\x3e\x31\x6e\x62\x9d"
-			  "\xd8\xe0\x57\xa3\x06\x3a\x42\x58"
-			  "\x2a\x28\xfe\x72\x52\x2f\xdd\xe0"
-			  "\x19\x89\x09\x1c\x2a\x8e\x8c\x94"
-			  "\xfc\xc7\x68\xe4\x88\xaa\xde\x0f",
-		.rlen	= 48,
-		.np	= 2,
-		.tap	= { 20, 28 },
-	}
-};
-
-static struct cipher_testvec fcrypt_pcbc_dec_tv_template[] = {
-	{ /* http://www.openafs.org/pipermail/openafs-devel/2000-December/005320.html */
-		.key	= "\x00\x00\x00\x00\x00\x00\x00\x00",
-		.klen	= 8,
-		.iv	= "\x00\x00\x00\x00\x00\x00\x00\x00",
-		.input	= "\x0E\x09\x00\xC7\x3E\xF7\xED\x41",
-		.ilen	= 8,
-		.result	= "\x00\x00\x00\x00\x00\x00\x00\x00",
-		.rlen	= 8,
-	}, {
-		.key	= "\x11\x44\x77\xAA\xDD\x00\x33\x66",
-		.klen	= 8,
-		.iv	= "\x00\x00\x00\x00\x00\x00\x00\x00",
-		.input	= "\xD8\xED\x78\x74\x77\xEC\x06\x80",
-		.ilen	= 8,
-		.result	= "\x12\x34\x56\x78\x9A\xBC\xDE\xF0",
-		.rlen	= 8,
-	}, { /* From Arla */
-		.key	= "\xf0\xe1\xd2\xc3\xb4\xa5\x96\x87",
-		.klen	= 8,
-		.iv	= "\xfe\xdc\xba\x98\x76\x54\x32\x10",
-		.input	= "\x00\xf0\x0e\x11\x75\xe6\x23\x82"
-			  "\xee\xac\x98\x62\x44\x51\xe4\x84"
-			  "\xc3\x59\xd8\xaa\x64\x60\xae\xf7"
-			  "\xd2\xd9\x13\x79\x72\xa3\x45\x03"
-			  "\x23\xb5\x62\xd7\x0c\xf5\x27\xd1"
-			  "\xf8\x91\x3c\xac\x44\x22\x92\xef",
-		.ilen	= 48,
-		.result	= "The quick brown fox jumps over the lazy dogs.\0\0",
-		.rlen	= 48,
-	}, {
-		.key	= "\xfe\xdc\xba\x98\x76\x54\x32\x10",
-		.klen	= 8,
-		.iv	= "\xf0\xe1\xd2\xc3\xb4\xa5\x96\x87",
-		.input	= "\xca\x90\xf5\x9d\xcb\xd4\xd2\x3c"
-			  "\x01\x88\x7f\x3e\x31\x6e\x62\x9d"
-			  "\xd8\xe0\x57\xa3\x06\x3a\x42\x58"
-			  "\x2a\x28\xfe\x72\x52\x2f\xdd\xe0"
-			  "\x19\x89\x09\x1c\x2a\x8e\x8c\x94"
-			  "\xfc\xc7\x68\xe4\x88\xaa\xde\x0f",
-		.ilen	= 48,
-		.result	= "The quick brown fox jumps over the lazy dogs.\0\0",
-		.rlen	= 48,
-	}, { /* split-page version */
-		.key	= "\xfe\xdc\xba\x98\x76\x54\x32\x10",
-		.klen	= 8,
-		.iv	= "\xf0\xe1\xd2\xc3\xb4\xa5\x96\x87",
-		.input	= "\xca\x90\xf5\x9d\xcb\xd4\xd2\x3c"
-			  "\x01\x88\x7f\x3e\x31\x6e\x62\x9d"
-			  "\xd8\xe0\x57\xa3\x06\x3a\x42\x58"
-			  "\x2a\x28\xfe\x72\x52\x2f\xdd\xe0"
-			  "\x19\x89\x09\x1c\x2a\x8e\x8c\x94"
-			  "\xfc\xc7\x68\xe4\x88\xaa\xde\x0f",
-		.ilen	= 48,
-		.result	= "The quick brown fox jumps over the lazy dogs.\0\0",
-		.rlen	= 48,
-		.np	= 2,
-		.tap	= { 20, 28 },
-	}
-};
-
-/*
- * CAMELLIA test vectors.
- */
-#define CAMELLIA_ENC_TEST_VECTORS 3
-#define CAMELLIA_DEC_TEST_VECTORS 3
-#define CAMELLIA_CBC_ENC_TEST_VECTORS 2
-#define CAMELLIA_CBC_DEC_TEST_VECTORS 2
-
-static struct cipher_testvec camellia_enc_tv_template[] = {
-	{
-		.key	= "\x01\x23\x45\x67\x89\xab\xcd\xef"
-			  "\xfe\xdc\xba\x98\x76\x54\x32\x10",
-		.klen	= 16,
-		.input	= "\x01\x23\x45\x67\x89\xab\xcd\xef"
-			  "\xfe\xdc\xba\x98\x76\x54\x32\x10",
-		.ilen	= 16,
-		.result	= "\x67\x67\x31\x38\x54\x96\x69\x73"
-			  "\x08\x57\x06\x56\x48\xea\xbe\x43",
-		.rlen	= 16,
-	}, {
-		.key	= "\x01\x23\x45\x67\x89\xab\xcd\xef"
-			  "\xfe\xdc\xba\x98\x76\x54\x32\x10"
-			  "\x00\x11\x22\x33\x44\x55\x66\x77",
-		.klen	= 24,
-		.input	= "\x01\x23\x45\x67\x89\xab\xcd\xef"
-			  "\xfe\xdc\xba\x98\x76\x54\x32\x10",
-		.ilen	= 16,
-		.result	= "\xb4\x99\x34\x01\xb3\xe9\x96\xf8"
-			  "\x4e\xe5\xce\xe7\xd7\x9b\x09\xb9",
-		.rlen	= 16,
-	}, {
-		.key	= "\x01\x23\x45\x67\x89\xab\xcd\xef"
-			  "\xfe\xdc\xba\x98\x76\x54\x32\x10"
-			  "\x00\x11\x22\x33\x44\x55\x66\x77"
-			  "\x88\x99\xaa\xbb\xcc\xdd\xee\xff",
-		.klen	= 32,
-		.input	= "\x01\x23\x45\x67\x89\xab\xcd\xef"
-			  "\xfe\xdc\xba\x98\x76\x54\x32\x10",
-		.ilen	= 16,
-		.result	= "\x9a\xcc\x23\x7d\xff\x16\xd7\x6c"
-			  "\x20\xef\x7c\x91\x9e\x3a\x75\x09",
-		.rlen	= 16,
-	},
-};
-
-static struct cipher_testvec camellia_dec_tv_template[] = {
-	{
-		.key	= "\x01\x23\x45\x67\x89\xab\xcd\xef"
-			  "\xfe\xdc\xba\x98\x76\x54\x32\x10",
-		.klen	= 16,
-		.input	= "\x67\x67\x31\x38\x54\x96\x69\x73"
-			  "\x08\x57\x06\x56\x48\xea\xbe\x43",
-		.ilen	= 16,
-		.result	= "\x01\x23\x45\x67\x89\xab\xcd\xef"
-			  "\xfe\xdc\xba\x98\x76\x54\x32\x10",
-		.rlen	= 16,
-	}, {
-		.key	= "\x01\x23\x45\x67\x89\xab\xcd\xef"
-			  "\xfe\xdc\xba\x98\x76\x54\x32\x10"
-			  "\x00\x11\x22\x33\x44\x55\x66\x77",
-		.klen	= 24,
-		.input	= "\xb4\x99\x34\x01\xb3\xe9\x96\xf8"
-			  "\x4e\xe5\xce\xe7\xd7\x9b\x09\xb9",
-		.ilen	= 16,
-		.result	= "\x01\x23\x45\x67\x89\xab\xcd\xef"
-			  "\xfe\xdc\xba\x98\x76\x54\x32\x10",
-		.rlen	= 16,
-	}, {
-		.key	= "\x01\x23\x45\x67\x89\xab\xcd\xef"
-			  "\xfe\xdc\xba\x98\x76\x54\x32\x10"
-			  "\x00\x11\x22\x33\x44\x55\x66\x77"
-			  "\x88\x99\xaa\xbb\xcc\xdd\xee\xff",
-		.klen	= 32,
-		.input	= "\x9a\xcc\x23\x7d\xff\x16\xd7\x6c"
-			  "\x20\xef\x7c\x91\x9e\x3a\x75\x09",
-		.ilen	= 16,
-		.result	= "\x01\x23\x45\x67\x89\xab\xcd\xef"
-			  "\xfe\xdc\xba\x98\x76\x54\x32\x10",
-		.rlen	= 16,
-	},
-};
-
-static struct cipher_testvec camellia_cbc_enc_tv_template[] = {
-	{
-		.key    = "\x06\xa9\x21\x40\x36\xb8\xa1\x5b"
-			  "\x51\x2e\x03\xd5\x34\x12\x00\x06",
-		.klen   = 16,
-		.iv	= "\x3d\xaf\xba\x42\x9d\x9e\xb4\x30"
-			  "\xb4\x22\xda\x80\x2c\x9f\xac\x41",
-		.input	= "Single block msg",
-		.ilen   = 16,
-		.result = "\xea\x32\x12\x76\x3b\x50\x10\xe7"
-			  "\x18\xf6\xfd\x5d\xf6\x8f\x13\x51",
-		.rlen   = 16,
-	}, {
-		.key    = "\xc2\x86\x69\x6d\x88\x7c\x9a\xa0"
-			  "\x61\x1b\xbb\x3e\x20\x25\xa4\x5a",
-		.klen   = 16,
-		.iv     = "\x56\x2e\x17\x99\x6d\x09\x3d\x28"
-			  "\xdd\xb3\xba\x69\x5a\x2e\x6f\x58",
-		.input  = "\x00\x01\x02\x03\x04\x05\x06\x07"
-			  "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
-			  "\x10\x11\x12\x13\x14\x15\x16\x17"
-			  "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f",
-		.ilen   = 32,
-		.result = "\xa5\xdf\x6e\x50\xda\x70\x6c\x01"
-			  "\x4a\xab\xf3\xf2\xd6\xfc\x6c\xfd"
-			  "\x19\xb4\x3e\x57\x1c\x02\x5e\xa0"
-			  "\x15\x78\xe0\x5e\xf2\xcb\x87\x16",
-		.rlen   = 32,
-	},
-};
-
-static struct cipher_testvec camellia_cbc_dec_tv_template[] = {
-	{
-		.key    = "\x06\xa9\x21\x40\x36\xb8\xa1\x5b"
-			  "\x51\x2e\x03\xd5\x34\x12\x00\x06",
-		.klen   = 16,
-		.iv	= "\x3d\xaf\xba\x42\x9d\x9e\xb4\x30"
-			  "\xb4\x22\xda\x80\x2c\x9f\xac\x41",
-		.input	= "\xea\x32\x12\x76\x3b\x50\x10\xe7"
-			  "\x18\xf6\xfd\x5d\xf6\x8f\x13\x51",
-		.ilen   = 16,
-		.result = "Single block msg",
-		.rlen   = 16,
-	}, {
-		.key    = "\xc2\x86\x69\x6d\x88\x7c\x9a\xa0"
-			  "\x61\x1b\xbb\x3e\x20\x25\xa4\x5a",
-		.klen   = 16,
-		.iv     = "\x56\x2e\x17\x99\x6d\x09\x3d\x28"
-			  "\xdd\xb3\xba\x69\x5a\x2e\x6f\x58",
-		.input = "\xa5\xdf\x6e\x50\xda\x70\x6c\x01"
-			  "\x4a\xab\xf3\xf2\xd6\xfc\x6c\xfd"
-			  "\x19\xb4\x3e\x57\x1c\x02\x5e\xa0"
-			  "\x15\x78\xe0\x5e\xf2\xcb\x87\x16",
-		.ilen   = 32,
-		.result = "\x00\x01\x02\x03\x04\x05\x06\x07"
-			  "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
-			  "\x10\x11\x12\x13\x14\x15\x16\x17"
-			  "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f",
-		.rlen   = 32,
-	},
-};
-
-/*
- * SEED test vectors
- */
-#define SEED_ENC_TEST_VECTORS	4
-#define SEED_DEC_TEST_VECTORS	4
-
-static struct cipher_testvec seed_enc_tv_template[] = {
-	{
-		.key    = zeroed_string,
-		.klen	= 16,
-		.input  = "\x00\x01\x02\x03\x04\x05\x06\x07"
-			  "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
-		.ilen	= 16,
-		.result	= "\x5e\xba\xc6\xe0\x05\x4e\x16\x68"
-			  "\x19\xaf\xf1\xcc\x6d\x34\x6c\xdb",
-		.rlen	= 16,
-	}, {
-		.key	= "\x00\x01\x02\x03\x04\x05\x06\x07"
-			  "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
-		.klen	= 16,
-		.input	= zeroed_string,
-		.ilen	= 16,
-		.result	= "\xc1\x1f\x22\xf2\x01\x40\x50\x50"
-			  "\x84\x48\x35\x97\xe4\x37\x0f\x43",
-		.rlen	= 16,
-	}, {
-		.key	= "\x47\x06\x48\x08\x51\xe6\x1b\xe8"
-			  "\x5d\x74\xbf\xb3\xfd\x95\x61\x85",
-		.klen	= 16,
-		.input	= "\x83\xa2\xf8\xa2\x88\x64\x1f\xb9"
-			  "\xa4\xe9\xa5\xcc\x2f\x13\x1c\x7d",
-		.ilen	= 16,
-		.result	= "\xee\x54\xd1\x3e\xbc\xae\x70\x6d"
-			  "\x22\x6b\xc3\x14\x2c\xd4\x0d\x4a",
-		.rlen	= 16,
-	}, {
-		.key	= "\x28\xdb\xc3\xbc\x49\xff\xd8\x7d"
-			  "\xcf\xa5\x09\xb1\x1d\x42\x2b\xe7",
-		.klen	= 16,
-		.input	= "\xb4\x1e\x6b\xe2\xeb\xa8\x4a\x14"
-			  "\x8e\x2e\xed\x84\x59\x3c\x5e\xc7",
-		.ilen	= 16,
-		.result	= "\x9b\x9b\x7b\xfc\xd1\x81\x3c\xb9"
-			  "\x5d\x0b\x36\x18\xf4\x0f\x51\x22",
-		.rlen	= 16,
-	}
-};
-
-static struct cipher_testvec seed_dec_tv_template[] = {
-	{
-		.key    = zeroed_string,
-		.klen	= 16,
-		.input	= "\x5e\xba\xc6\xe0\x05\x4e\x16\x68"
-			  "\x19\xaf\xf1\xcc\x6d\x34\x6c\xdb",
-		.ilen	= 16,
-		.result	= "\x00\x01\x02\x03\x04\x05\x06\x07"
-			  "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
-		.rlen	= 16,
-	}, {
-		.key	= "\x00\x01\x02\x03\x04\x05\x06\x07"
-			  "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
-		.klen	= 16,
-		.input	= "\xc1\x1f\x22\xf2\x01\x40\x50\x50"
-			  "\x84\x48\x35\x97\xe4\x37\x0f\x43",
-		.ilen	= 16,
-		.result	= zeroed_string,
-		.rlen	= 16,
-	}, {
-		.key	= "\x47\x06\x48\x08\x51\xe6\x1b\xe8"
-			  "\x5d\x74\xbf\xb3\xfd\x95\x61\x85",
-		.klen	= 16,
-		.input	= "\xee\x54\xd1\x3e\xbc\xae\x70\x6d"
-			  "\x22\x6b\xc3\x14\x2c\xd4\x0d\x4a",
-		.ilen	= 16,
-		.result	= "\x83\xa2\xf8\xa2\x88\x64\x1f\xb9"
-			  "\xa4\xe9\xa5\xcc\x2f\x13\x1c\x7d",
-		.rlen	= 16,
-	}, {
-		.key	= "\x28\xdb\xc3\xbc\x49\xff\xd8\x7d"
-			  "\xcf\xa5\x09\xb1\x1d\x42\x2b\xe7",
-		.klen	= 16,
-		.input	= "\x9b\x9b\x7b\xfc\xd1\x81\x3c\xb9"
-			  "\x5d\x0b\x36\x18\xf4\x0f\x51\x22",
-		.ilen	= 16,
-		.result	= "\xb4\x1e\x6b\xe2\xeb\xa8\x4a\x14"
-			  "\x8e\x2e\xed\x84\x59\x3c\x5e\xc7",
-		.rlen	= 16,
-	}
-};
-
-#define SALSA20_STREAM_ENC_TEST_VECTORS 5
-static struct cipher_testvec salsa20_stream_enc_tv_template[] = {
-	/*
-	* Testvectors from verified.test-vectors submitted to ECRYPT.
-	* They are truncated to size 39, 64, 111, 129 to test a variety
-	* of input length.
-	*/
-	{ /* Set 3, vector 0 */
-		.key	= "\x00\x01\x02\x03\x04\x05\x06\x07"
-			"\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F",
-		.klen	= 16,
-		.iv     = "\x00\x00\x00\x00\x00\x00\x00\x00",
-		.input	= "\x00\x00\x00\x00\x00\x00\x00\x00"
-			"\x00\x00\x00\x00\x00\x00\x00\x00"
-			"\x00\x00\x00\x00\x00\x00\x00\x00"
-			"\x00\x00\x00\x00\x00\x00\x00\x00"
-			"\x00\x00\x00\x00\x00\x00\x00",
-		.ilen	= 39,
-		.result	= "\x2D\xD5\xC3\xF7\xBA\x2B\x20\xF7"
-			 "\x68\x02\x41\x0C\x68\x86\x88\x89"
-			 "\x5A\xD8\xC1\xBD\x4E\xA6\xC9\xB1"
-			 "\x40\xFB\x9B\x90\xE2\x10\x49\xBF"
-			 "\x58\x3F\x52\x79\x70\xEB\xC1",
-		.rlen	= 39,
-	}, { /* Set 5, vector 0 */
-		.key	= "\x00\x00\x00\x00\x00\x00\x00\x00"
-			"\x00\x00\x00\x00\x00\x00\x00\x00",
-		.klen	= 16,
-		.iv     = "\x80\x00\x00\x00\x00\x00\x00\x00",
-		.input	= "\x00\x00\x00\x00\x00\x00\x00\x00"
-			"\x00\x00\x00\x00\x00\x00\x00\x00"
-			"\x00\x00\x00\x00\x00\x00\x00\x00"
-			"\x00\x00\x00\x00\x00\x00\x00\x00"
-			"\x00\x00\x00\x00\x00\x00\x00\x00"
-			"\x00\x00\x00\x00\x00\x00\x00\x00"
-			"\x00\x00\x00\x00\x00\x00\x00\x00"
-			"\x00\x00\x00\x00\x00\x00\x00\x00",
-		.ilen	= 64,
-		.result	= "\xB6\x6C\x1E\x44\x46\xDD\x95\x57"
-			 "\xE5\x78\xE2\x23\xB0\xB7\x68\x01"
-			 "\x7B\x23\xB2\x67\xBB\x02\x34\xAE"
-			 "\x46\x26\xBF\x44\x3F\x21\x97\x76"
-			 "\x43\x6F\xB1\x9F\xD0\xE8\x86\x6F"
-			 "\xCD\x0D\xE9\xA9\x53\x8F\x4A\x09"
-			 "\xCA\x9A\xC0\x73\x2E\x30\xBC\xF9"
-			 "\x8E\x4F\x13\xE4\xB9\xE2\x01\xD9",
-		.rlen	= 64,
-	}, { /* Set 3, vector 27 */
-		.key	= "\x1B\x1C\x1D\x1E\x1F\x20\x21\x22"
-			"\x23\x24\x25\x26\x27\x28\x29\x2A"
-			"\x2B\x2C\x2D\x2E\x2F\x30\x31\x32"
-			"\x33\x34\x35\x36\x37\x38\x39\x3A",
-		.klen	= 32,
-		.iv     = "\x00\x00\x00\x00\x00\x00\x00\x00",
-		.input	= "\x00\x00\x00\x00\x00\x00\x00\x00"
-			"\x00\x00\x00\x00\x00\x00\x00\x00"
-			"\x00\x00\x00\x00\x00\x00\x00\x00"
-			"\x00\x00\x00\x00\x00\x00\x00\x00"
-			"\x00\x00\x00\x00\x00\x00\x00\x00"
-			"\x00\x00\x00\x00\x00\x00\x00\x00"
-			"\x00\x00\x00\x00\x00\x00\x00\x00"
-			"\x00\x00\x00\x00\x00\x00\x00\x00"
-			"\x00\x00\x00\x00\x00\x00\x00\x00"
-			"\x00\x00\x00\x00\x00\x00\x00\x00"
-			"\x00\x00\x00\x00\x00\x00\x00\x00"
-			"\x00\x00\x00\x00\x00\x00\x00\x00"
-			"\x00\x00\x00\x00\x00\x00\x00\x00"
-			"\x00\x00\x00\x00\x00\x00\x00",
-		.ilen	= 111,
-		.result	= "\xAE\x39\x50\x8E\xAC\x9A\xEC\xE7"
-			 "\xBF\x97\xBB\x20\xB9\xDE\xE4\x1F"
-			 "\x87\xD9\x47\xF8\x28\x91\x35\x98"
-			 "\xDB\x72\xCC\x23\x29\x48\x56\x5E"
-			 "\x83\x7E\x0B\xF3\x7D\x5D\x38\x7B"
-			 "\x2D\x71\x02\xB4\x3B\xB5\xD8\x23"
-			 "\xB0\x4A\xDF\x3C\xEC\xB6\xD9\x3B"
-			 "\x9B\xA7\x52\xBE\xC5\xD4\x50\x59"
-			 "\x15\x14\xB4\x0E\x40\xE6\x53\xD1"
-			 "\x83\x9C\x5B\xA0\x92\x29\x6B\x5E"
-			 "\x96\x5B\x1E\x2F\xD3\xAC\xC1\x92"
-			 "\xB1\x41\x3F\x19\x2F\xC4\x3B\xC6"
-			 "\x95\x46\x45\x54\xE9\x75\x03\x08"
-			 "\x44\xAF\xE5\x8A\x81\x12\x09",
-		.rlen	= 111,
-	}, { /* Set 5, vector 27 */
-		.key	= "\x00\x00\x00\x00\x00\x00\x00\x00"
-			"\x00\x00\x00\x00\x00\x00\x00\x00"
-			"\x00\x00\x00\x00\x00\x00\x00\x00"
-			"\x00\x00\x00\x00\x00\x00\x00\x00",
-		.klen	= 32,
-		.iv     = "\x00\x00\x00\x10\x00\x00\x00\x00",
-		.input	= "\x00\x00\x00\x00\x00\x00\x00\x00"
-			"\x00\x00\x00\x00\x00\x00\x00\x00"
-			"\x00\x00\x00\x00\x00\x00\x00\x00"
-			"\x00\x00\x00\x00\x00\x00\x00\x00"
-			"\x00\x00\x00\x00\x00\x00\x00\x00"
-			"\x00\x00\x00\x00\x00\x00\x00\x00"
-			"\x00\x00\x00\x00\x00\x00\x00\x00"
-			"\x00\x00\x00\x00\x00\x00\x00\x00"
-			"\x00\x00\x00\x00\x00\x00\x00\x00"
-			"\x00\x00\x00\x00\x00\x00\x00\x00"
-			"\x00\x00\x00\x00\x00\x00\x00\x00"
-			"\x00\x00\x00\x00\x00\x00\x00\x00"
-			"\x00\x00\x00\x00\x00\x00\x00\x00"
-			"\x00\x00\x00\x00\x00\x00\x00\x00"
-			"\x00\x00\x00\x00\x00\x00\x00\x00"
-			"\x00\x00\x00\x00\x00\x00\x00\x00"
-			"\x00",
-		.ilen	= 129,
-		.result	= "\xD2\xDB\x1A\x5C\xF1\xC1\xAC\xDB"
-			 "\xE8\x1A\x7A\x43\x40\xEF\x53\x43"
-			 "\x5E\x7F\x4B\x1A\x50\x52\x3F\x8D"
-			 "\x28\x3D\xCF\x85\x1D\x69\x6E\x60"
-			 "\xF2\xDE\x74\x56\x18\x1B\x84\x10"
-			 "\xD4\x62\xBA\x60\x50\xF0\x61\xF2"
-			 "\x1C\x78\x7F\xC1\x24\x34\xAF\x58"
-			 "\xBF\x2C\x59\xCA\x90\x77\xF3\xB0"
-			 "\x5B\x4A\xDF\x89\xCE\x2C\x2F\xFC"
-			 "\x67\xF0\xE3\x45\xE8\xB3\xB3\x75"
-			 "\xA0\x95\x71\xA1\x29\x39\x94\xCA"
-			 "\x45\x2F\xBD\xCB\x10\xB6\xBE\x9F"
-			 "\x8E\xF9\xB2\x01\x0A\x5A\x0A\xB7"
-			 "\x6B\x9D\x70\x8E\x4B\xD6\x2F\xCD"
-			 "\x2E\x40\x48\x75\xE9\xE2\x21\x45"
-			 "\x0B\xC9\xB6\xB5\x66\xBC\x9A\x59"
-			 "\x5A",
-		.rlen	= 129,
-	}, { /* large test vector generated using Crypto++ */
-		.key =  "\x00\x01\x02\x03\x04\x05\x06\x07"
-			"\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
-			"\x10\x11\x12\x13\x14\x15\x16\x17"
-			"\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f",
-		.klen = 32,
-		.iv =	"\x00\x00\x00\x00\x00\x00\x00\x00"
-			"\x00\x00\x00\x00\x00\x00\x00\x00",
-		.input =
-			"\x00\x01\x02\x03\x04\x05\x06\x07"
-			"\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
-			"\x10\x11\x12\x13\x14\x15\x16\x17"
-			"\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
-			"\x20\x21\x22\x23\x24\x25\x26\x27"
-			"\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f"
-			"\x30\x31\x32\x33\x34\x35\x36\x37"
-			"\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f"
-			"\x40\x41\x42\x43\x44\x45\x46\x47"
-			"\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f"
-			"\x50\x51\x52\x53\x54\x55\x56\x57"
-			"\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f"
-			"\x60\x61\x62\x63\x64\x65\x66\x67"
-			"\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f"
-			"\x70\x71\x72\x73\x74\x75\x76\x77"
-			"\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f"
-			"\x80\x81\x82\x83\x84\x85\x86\x87"
-			"\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"
-			"\x90\x91\x92\x93\x94\x95\x96\x97"
-			"\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f"
-			"\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7"
-			"\xa8\xa9\xaa\xab\xac\xad\xae\xaf"
-			"\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7"
-			"\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf"
-			"\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7"
-			"\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf"
-			"\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7"
-			"\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf"
-			"\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7"
-			"\xe8\xe9\xea\xeb\xec\xed\xee\xef"
-			"\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7"
-			"\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff"
-			"\x00\x03\x06\x09\x0c\x0f\x12\x15"
-			"\x18\x1b\x1e\x21\x24\x27\x2a\x2d"
-			"\x30\x33\x36\x39\x3c\x3f\x42\x45"
-			"\x48\x4b\x4e\x51\x54\x57\x5a\x5d"
-			"\x60\x63\x66\x69\x6c\x6f\x72\x75"
-			"\x78\x7b\x7e\x81\x84\x87\x8a\x8d"
-			"\x90\x93\x96\x99\x9c\x9f\xa2\xa5"
-			"\xa8\xab\xae\xb1\xb4\xb7\xba\xbd"
-			"\xc0\xc3\xc6\xc9\xcc\xcf\xd2\xd5"
-			"\xd8\xdb\xde\xe1\xe4\xe7\xea\xed"
-			"\xf0\xf3\xf6\xf9\xfc\xff\x02\x05"
-			"\x08\x0b\x0e\x11\x14\x17\x1a\x1d"
-			"\x20\x23\x26\x29\x2c\x2f\x32\x35"
-			"\x38\x3b\x3e\x41\x44\x47\x4a\x4d"
-			"\x50\x53\x56\x59\x5c\x5f\x62\x65"
-			"\x68\x6b\x6e\x71\x74\x77\x7a\x7d"
-			"\x80\x83\x86\x89\x8c\x8f\x92\x95"
-			"\x98\x9b\x9e\xa1\xa4\xa7\xaa\xad"
-			"\xb0\xb3\xb6\xb9\xbc\xbf\xc2\xc5"
-			"\xc8\xcb\xce\xd1\xd4\xd7\xda\xdd"
-			"\xe0\xe3\xe6\xe9\xec\xef\xf2\xf5"
-			"\xf8\xfb\xfe\x01\x04\x07\x0a\x0d"
-			"\x10\x13\x16\x19\x1c\x1f\x22\x25"
-			"\x28\x2b\x2e\x31\x34\x37\x3a\x3d"
-			"\x40\x43\x46\x49\x4c\x4f\x52\x55"
-			"\x58\x5b\x5e\x61\x64\x67\x6a\x6d"
-			"\x70\x73\x76\x79\x7c\x7f\x82\x85"
-			"\x88\x8b\x8e\x91\x94\x97\x9a\x9d"
-			"\xa0\xa3\xa6\xa9\xac\xaf\xb2\xb5"
-			"\xb8\xbb\xbe\xc1\xc4\xc7\xca\xcd"
-			"\xd0\xd3\xd6\xd9\xdc\xdf\xe2\xe5"
-			"\xe8\xeb\xee\xf1\xf4\xf7\xfa\xfd"
-			"\x00\x05\x0a\x0f\x14\x19\x1e\x23"
-			"\x28\x2d\x32\x37\x3c\x41\x46\x4b"
-			"\x50\x55\x5a\x5f\x64\x69\x6e\x73"
-			"\x78\x7d\x82\x87\x8c\x91\x96\x9b"
-			"\xa0\xa5\xaa\xaf\xb4\xb9\xbe\xc3"
-			"\xc8\xcd\xd2\xd7\xdc\xe1\xe6\xeb"
-			"\xf0\xf5\xfa\xff\x04\x09\x0e\x13"
-			"\x18\x1d\x22\x27\x2c\x31\x36\x3b"
-			"\x40\x45\x4a\x4f\x54\x59\x5e\x63"
-			"\x68\x6d\x72\x77\x7c\x81\x86\x8b"
-			"\x90\x95\x9a\x9f\xa4\xa9\xae\xb3"
-			"\xb8\xbd\xc2\xc7\xcc\xd1\xd6\xdb"
-			"\xe0\xe5\xea\xef\xf4\xf9\xfe\x03"
-			"\x08\x0d\x12\x17\x1c\x21\x26\x2b"
-			"\x30\x35\x3a\x3f\x44\x49\x4e\x53"
-			"\x58\x5d\x62\x67\x6c\x71\x76\x7b"
-			"\x80\x85\x8a\x8f\x94\x99\x9e\xa3"
-			"\xa8\xad\xb2\xb7\xbc\xc1\xc6\xcb"
-			"\xd0\xd5\xda\xdf\xe4\xe9\xee\xf3"
-			"\xf8\xfd\x02\x07\x0c\x11\x16\x1b"
-			"\x20\x25\x2a\x2f\x34\x39\x3e\x43"
-			"\x48\x4d\x52\x57\x5c\x61\x66\x6b"
-			"\x70\x75\x7a\x7f\x84\x89\x8e\x93"
-			"\x98\x9d\xa2\xa7\xac\xb1\xb6\xbb"
-			"\xc0\xc5\xca\xcf\xd4\xd9\xde\xe3"
-			"\xe8\xed\xf2\xf7\xfc\x01\x06\x0b"
-			"\x10\x15\x1a\x1f\x24\x29\x2e\x33"
-			"\x38\x3d\x42\x47\x4c\x51\x56\x5b"
-			"\x60\x65\x6a\x6f\x74\x79\x7e\x83"
-			"\x88\x8d\x92\x97\x9c\xa1\xa6\xab"
-			"\xb0\xb5\xba\xbf\xc4\xc9\xce\xd3"
-			"\xd8\xdd\xe2\xe7\xec\xf1\xf6\xfb"
-			"\x00\x07\x0e\x15\x1c\x23\x2a\x31"
-			"\x38\x3f\x46\x4d\x54\x5b\x62\x69"
-			"\x70\x77\x7e\x85\x8c\x93\x9a\xa1"
-			"\xa8\xaf\xb6\xbd\xc4\xcb\xd2\xd9"
-			"\xe0\xe7\xee\xf5\xfc\x03\x0a\x11"
-			"\x18\x1f\x26\x2d\x34\x3b\x42\x49"
-			"\x50\x57\x5e\x65\x6c\x73\x7a\x81"
-			"\x88\x8f\x96\x9d\xa4\xab\xb2\xb9"
-			"\xc0\xc7\xce\xd5\xdc\xe3\xea\xf1"
-			"\xf8\xff\x06\x0d\x14\x1b\x22\x29"
-			"\x30\x37\x3e\x45\x4c\x53\x5a\x61"
-			"\x68\x6f\x76\x7d\x84\x8b\x92\x99"
-			"\xa0\xa7\xae\xb5\xbc\xc3\xca\xd1"
-			"\xd8\xdf\xe6\xed\xf4\xfb\x02\x09"
-			"\x10\x17\x1e\x25\x2c\x33\x3a\x41"
-			"\x48\x4f\x56\x5d\x64\x6b\x72\x79"
-			"\x80\x87\x8e\x95\x9c\xa3\xaa\xb1"
-			"\xb8\xbf\xc6\xcd\xd4\xdb\xe2\xe9"
-			"\xf0\xf7\xfe\x05\x0c\x13\x1a\x21"
-			"\x28\x2f\x36\x3d\x44\x4b\x52\x59"
-			"\x60\x67\x6e\x75\x7c\x83\x8a\x91"
-			"\x98\x9f\xa6\xad\xb4\xbb\xc2\xc9"
-			"\xd0\xd7\xde\xe5\xec\xf3\xfa\x01"
-			"\x08\x0f\x16\x1d\x24\x2b\x32\x39"
-			"\x40\x47\x4e\x55\x5c\x63\x6a\x71"
-			"\x78\x7f\x86\x8d\x94\x9b\xa2\xa9"
-			"\xb0\xb7\xbe\xc5\xcc\xd3\xda\xe1"
-			"\xe8\xef\xf6\xfd\x04\x0b\x12\x19"
-			"\x20\x27\x2e\x35\x3c\x43\x4a\x51"
-			"\x58\x5f\x66\x6d\x74\x7b\x82\x89"
-			"\x90\x97\x9e\xa5\xac\xb3\xba\xc1"
-			"\xc8\xcf\xd6\xdd\xe4\xeb\xf2\xf9"
-			"\x00\x09\x12\x1b\x24\x2d\x36\x3f"
-			"\x48\x51\x5a\x63\x6c\x75\x7e\x87"
-			"\x90\x99\xa2\xab\xb4\xbd\xc6\xcf"
-			"\xd8\xe1\xea\xf3\xfc\x05\x0e\x17"
-			"\x20\x29\x32\x3b\x44\x4d\x56\x5f"
-			"\x68\x71\x7a\x83\x8c\x95\x9e\xa7"
-			"\xb0\xb9\xc2\xcb\xd4\xdd\xe6\xef"
-			"\xf8\x01\x0a\x13\x1c\x25\x2e\x37"
-			"\x40\x49\x52\x5b\x64\x6d\x76\x7f"
-			"\x88\x91\x9a\xa3\xac\xb5\xbe\xc7"
-			"\xd0\xd9\xe2\xeb\xf4\xfd\x06\x0f"
-			"\x18\x21\x2a\x33\x3c\x45\x4e\x57"
-			"\x60\x69\x72\x7b\x84\x8d\x96\x9f"
-			"\xa8\xb1\xba\xc3\xcc\xd5\xde\xe7"
-			"\xf0\xf9\x02\x0b\x14\x1d\x26\x2f"
-			"\x38\x41\x4a\x53\x5c\x65\x6e\x77"
-			"\x80\x89\x92\x9b\xa4\xad\xb6\xbf"
-			"\xc8\xd1\xda\xe3\xec\xf5\xfe\x07"
-			"\x10\x19\x22\x2b\x34\x3d\x46\x4f"
-			"\x58\x61\x6a\x73\x7c\x85\x8e\x97"
-			"\xa0\xa9\xb2\xbb\xc4\xcd\xd6\xdf"
-			"\xe8\xf1\xfa\x03\x0c\x15\x1e\x27"
-			"\x30\x39\x42\x4b\x54\x5d\x66\x6f"
-			"\x78\x81\x8a\x93\x9c\xa5\xae\xb7"
-			"\xc0\xc9\xd2\xdb\xe4\xed\xf6\xff"
-			"\x08\x11\x1a\x23\x2c\x35\x3e\x47"
-			"\x50\x59\x62\x6b\x74\x7d\x86\x8f"
-			"\x98\xa1\xaa\xb3\xbc\xc5\xce\xd7"
-			"\xe0\xe9\xf2\xfb\x04\x0d\x16\x1f"
-			"\x28\x31\x3a\x43\x4c\x55\x5e\x67"
-			"\x70\x79\x82\x8b\x94\x9d\xa6\xaf"
-			"\xb8\xc1\xca\xd3\xdc\xe5\xee\xf7"
-			"\x00\x0b\x16\x21\x2c\x37\x42\x4d"
-			"\x58\x63\x6e\x79\x84\x8f\x9a\xa5"
-			"\xb0\xbb\xc6\xd1\xdc\xe7\xf2\xfd"
-			"\x08\x13\x1e\x29\x34\x3f\x4a\x55"
-			"\x60\x6b\x76\x81\x8c\x97\xa2\xad"
-			"\xb8\xc3\xce\xd9\xe4\xef\xfa\x05"
-			"\x10\x1b\x26\x31\x3c\x47\x52\x5d"
-			"\x68\x73\x7e\x89\x94\x9f\xaa\xb5"
-			"\xc0\xcb\xd6\xe1\xec\xf7\x02\x0d"
-			"\x18\x23\x2e\x39\x44\x4f\x5a\x65"
-			"\x70\x7b\x86\x91\x9c\xa7\xb2\xbd"
-			"\xc8\xd3\xde\xe9\xf4\xff\x0a\x15"
-			"\x20\x2b\x36\x41\x4c\x57\x62\x6d"
-			"\x78\x83\x8e\x99\xa4\xaf\xba\xc5"
-			"\xd0\xdb\xe6\xf1\xfc\x07\x12\x1d"
-			"\x28\x33\x3e\x49\x54\x5f\x6a\x75"
-			"\x80\x8b\x96\xa1\xac\xb7\xc2\xcd"
-			"\xd8\xe3\xee\xf9\x04\x0f\x1a\x25"
-			"\x30\x3b\x46\x51\x5c\x67\x72\x7d"
-			"\x88\x93\x9e\xa9\xb4\xbf\xca\xd5"
-			"\xe0\xeb\xf6\x01\x0c\x17\x22\x2d"
-			"\x38\x43\x4e\x59\x64\x6f\x7a\x85"
-			"\x90\x9b\xa6\xb1\xbc\xc7\xd2\xdd"
-			"\xe8\xf3\xfe\x09\x14\x1f\x2a\x35"
-			"\x40\x4b\x56\x61\x6c\x77\x82\x8d"
-			"\x98\xa3\xae\xb9\xc4\xcf\xda\xe5"
-			"\xf0\xfb\x06\x11\x1c\x27\x32\x3d"
-			"\x48\x53\x5e\x69\x74\x7f\x8a\x95"
-			"\xa0\xab\xb6\xc1\xcc\xd7\xe2\xed"
-			"\xf8\x03\x0e\x19\x24\x2f\x3a\x45"
-			"\x50\x5b\x66\x71\x7c\x87\x92\x9d"
-			"\xa8\xb3\xbe\xc9\xd4\xdf\xea\xf5"
-			"\x00\x0d\x1a\x27\x34\x41\x4e\x5b"
-			"\x68\x75\x82\x8f\x9c\xa9\xb6\xc3"
-			"\xd0\xdd\xea\xf7\x04\x11\x1e\x2b"
-			"\x38\x45\x52\x5f\x6c\x79\x86\x93"
-			"\xa0\xad\xba\xc7\xd4\xe1\xee\xfb"
-			"\x08\x15\x22\x2f\x3c\x49\x56\x63"
-			"\x70\x7d\x8a\x97\xa4\xb1\xbe\xcb"
-			"\xd8\xe5\xf2\xff\x0c\x19\x26\x33"
-			"\x40\x4d\x5a\x67\x74\x81\x8e\x9b"
-			"\xa8\xb5\xc2\xcf\xdc\xe9\xf6\x03"
-			"\x10\x1d\x2a\x37\x44\x51\x5e\x6b"
-			"\x78\x85\x92\x9f\xac\xb9\xc6\xd3"
-			"\xe0\xed\xfa\x07\x14\x21\x2e\x3b"
-			"\x48\x55\x62\x6f\x7c\x89\x96\xa3"
-			"\xb0\xbd\xca\xd7\xe4\xf1\xfe\x0b"
-			"\x18\x25\x32\x3f\x4c\x59\x66\x73"
-			"\x80\x8d\x9a\xa7\xb4\xc1\xce\xdb"
-			"\xe8\xf5\x02\x0f\x1c\x29\x36\x43"
-			"\x50\x5d\x6a\x77\x84\x91\x9e\xab"
-			"\xb8\xc5\xd2\xdf\xec\xf9\x06\x13"
-			"\x20\x2d\x3a\x47\x54\x61\x6e\x7b"
-			"\x88\x95\xa2\xaf\xbc\xc9\xd6\xe3"
-			"\xf0\xfd\x0a\x17\x24\x31\x3e\x4b"
-			"\x58\x65\x72\x7f\x8c\x99\xa6\xb3"
-			"\xc0\xcd\xda\xe7\xf4\x01\x0e\x1b"
-			"\x28\x35\x42\x4f\x5c\x69\x76\x83"
-			"\x90\x9d\xaa\xb7\xc4\xd1\xde\xeb"
-			"\xf8\x05\x12\x1f\x2c\x39\x46\x53"
-			"\x60\x6d\x7a\x87\x94\xa1\xae\xbb"
-			"\xc8\xd5\xe2\xef\xfc\x09\x16\x23"
-			"\x30\x3d\x4a\x57\x64\x71\x7e\x8b"
-			"\x98\xa5\xb2\xbf\xcc\xd9\xe6\xf3"
-			"\x00\x0f\x1e\x2d\x3c\x4b\x5a\x69"
-			"\x78\x87\x96\xa5\xb4\xc3\xd2\xe1"
-			"\xf0\xff\x0e\x1d\x2c\x3b\x4a\x59"
-			"\x68\x77\x86\x95\xa4\xb3\xc2\xd1"
-			"\xe0\xef\xfe\x0d\x1c\x2b\x3a\x49"
-			"\x58\x67\x76\x85\x94\xa3\xb2\xc1"
-			"\xd0\xdf\xee\xfd\x0c\x1b\x2a\x39"
-			"\x48\x57\x66\x75\x84\x93\xa2\xb1"
-			"\xc0\xcf\xde\xed\xfc\x0b\x1a\x29"
-			"\x38\x47\x56\x65\x74\x83\x92\xa1"
-			"\xb0\xbf\xce\xdd\xec\xfb\x0a\x19"
-			"\x28\x37\x46\x55\x64\x73\x82\x91"
-			"\xa0\xaf\xbe\xcd\xdc\xeb\xfa\x09"
-			"\x18\x27\x36\x45\x54\x63\x72\x81"
-			"\x90\x9f\xae\xbd\xcc\xdb\xea\xf9"
-			"\x08\x17\x26\x35\x44\x53\x62\x71"
-			"\x80\x8f\x9e\xad\xbc\xcb\xda\xe9"
-			"\xf8\x07\x16\x25\x34\x43\x52\x61"
-			"\x70\x7f\x8e\x9d\xac\xbb\xca\xd9"
-			"\xe8\xf7\x06\x15\x24\x33\x42\x51"
-			"\x60\x6f\x7e\x8d\x9c\xab\xba\xc9"
-			"\xd8\xe7\xf6\x05\x14\x23\x32\x41"
-			"\x50\x5f\x6e\x7d\x8c\x9b\xaa\xb9"
-			"\xc8\xd7\xe6\xf5\x04\x13\x22\x31"
-			"\x40\x4f\x5e\x6d\x7c\x8b\x9a\xa9"
-			"\xb8\xc7\xd6\xe5\xf4\x03\x12\x21"
-			"\x30\x3f\x4e\x5d\x6c\x7b\x8a\x99"
-			"\xa8\xb7\xc6\xd5\xe4\xf3\x02\x11"
-			"\x20\x2f\x3e\x4d\x5c\x6b\x7a\x89"
-			"\x98\xa7\xb6\xc5\xd4\xe3\xf2\x01"
-			"\x10\x1f\x2e\x3d\x4c\x5b\x6a\x79"
-			"\x88\x97\xa6\xb5\xc4\xd3\xe2\xf1"
-			"\x00\x11\x22\x33\x44\x55\x66\x77"
-			"\x88\x99\xaa\xbb\xcc\xdd\xee\xff"
-			"\x10\x21\x32\x43\x54\x65\x76\x87"
-			"\x98\xa9\xba\xcb\xdc\xed\xfe\x0f"
-			"\x20\x31\x42\x53\x64\x75\x86\x97"
-			"\xa8\xb9\xca\xdb\xec\xfd\x0e\x1f"
-			"\x30\x41\x52\x63\x74\x85\x96\xa7"
-			"\xb8\xc9\xda\xeb\xfc\x0d\x1e\x2f"
-			"\x40\x51\x62\x73\x84\x95\xa6\xb7"
-			"\xc8\xd9\xea\xfb\x0c\x1d\x2e\x3f"
-			"\x50\x61\x72\x83\x94\xa5\xb6\xc7"
-			"\xd8\xe9\xfa\x0b\x1c\x2d\x3e\x4f"
-			"\x60\x71\x82\x93\xa4\xb5\xc6\xd7"
-			"\xe8\xf9\x0a\x1b\x2c\x3d\x4e\x5f"
-			"\x70\x81\x92\xa3\xb4\xc5\xd6\xe7"
-			"\xf8\x09\x1a\x2b\x3c\x4d\x5e\x6f"
-			"\x80\x91\xa2\xb3\xc4\xd5\xe6\xf7"
-			"\x08\x19\x2a\x3b\x4c\x5d\x6e\x7f"
-			"\x90\xa1\xb2\xc3\xd4\xe5\xf6\x07"
-			"\x18\x29\x3a\x4b\x5c\x6d\x7e\x8f"
-			"\xa0\xb1\xc2\xd3\xe4\xf5\x06\x17"
-			"\x28\x39\x4a\x5b\x6c\x7d\x8e\x9f"
-			"\xb0\xc1\xd2\xe3\xf4\x05\x16\x27"
-			"\x38\x49\x5a\x6b\x7c\x8d\x9e\xaf"
-			"\xc0\xd1\xe2\xf3\x04\x15\x26\x37"
-			"\x48\x59\x6a\x7b\x8c\x9d\xae\xbf"
-			"\xd0\xe1\xf2\x03\x14\x25\x36\x47"
-			"\x58\x69\x7a\x8b\x9c\xad\xbe\xcf"
-			"\xe0\xf1\x02\x13\x24\x35\x46\x57"
-			"\x68\x79\x8a\x9b\xac\xbd\xce\xdf"
-			"\xf0\x01\x12\x23\x34\x45\x56\x67"
-			"\x78\x89\x9a\xab\xbc\xcd\xde\xef"
-			"\x00\x13\x26\x39\x4c\x5f\x72\x85"
-			"\x98\xab\xbe\xd1\xe4\xf7\x0a\x1d"
-			"\x30\x43\x56\x69\x7c\x8f\xa2\xb5"
-			"\xc8\xdb\xee\x01\x14\x27\x3a\x4d"
-			"\x60\x73\x86\x99\xac\xbf\xd2\xe5"
-			"\xf8\x0b\x1e\x31\x44\x57\x6a\x7d"
-			"\x90\xa3\xb6\xc9\xdc\xef\x02\x15"
-			"\x28\x3b\x4e\x61\x74\x87\x9a\xad"
-			"\xc0\xd3\xe6\xf9\x0c\x1f\x32\x45"
-			"\x58\x6b\x7e\x91\xa4\xb7\xca\xdd"
-			"\xf0\x03\x16\x29\x3c\x4f\x62\x75"
-			"\x88\x9b\xae\xc1\xd4\xe7\xfa\x0d"
-			"\x20\x33\x46\x59\x6c\x7f\x92\xa5"
-			"\xb8\xcb\xde\xf1\x04\x17\x2a\x3d"
-			"\x50\x63\x76\x89\x9c\xaf\xc2\xd5"
-			"\xe8\xfb\x0e\x21\x34\x47\x5a\x6d"
-			"\x80\x93\xa6\xb9\xcc\xdf\xf2\x05"
-			"\x18\x2b\x3e\x51\x64\x77\x8a\x9d"
-			"\xb0\xc3\xd6\xe9\xfc\x0f\x22\x35"
-			"\x48\x5b\x6e\x81\x94\xa7\xba\xcd"
-			"\xe0\xf3\x06\x19\x2c\x3f\x52\x65"
-			"\x78\x8b\x9e\xb1\xc4\xd7\xea\xfd"
-			"\x10\x23\x36\x49\x5c\x6f\x82\x95"
-			"\xa8\xbb\xce\xe1\xf4\x07\x1a\x2d"
-			"\x40\x53\x66\x79\x8c\x9f\xb2\xc5"
-			"\xd8\xeb\xfe\x11\x24\x37\x4a\x5d"
-			"\x70\x83\x96\xa9\xbc\xcf\xe2\xf5"
-			"\x08\x1b\x2e\x41\x54\x67\x7a\x8d"
-			"\xa0\xb3\xc6\xd9\xec\xff\x12\x25"
-			"\x38\x4b\x5e\x71\x84\x97\xaa\xbd"
-			"\xd0\xe3\xf6\x09\x1c\x2f\x42\x55"
-			"\x68\x7b\x8e\xa1\xb4\xc7\xda\xed"
-			"\x00\x15\x2a\x3f\x54\x69\x7e\x93"
-			"\xa8\xbd\xd2\xe7\xfc\x11\x26\x3b"
-			"\x50\x65\x7a\x8f\xa4\xb9\xce\xe3"
-			"\xf8\x0d\x22\x37\x4c\x61\x76\x8b"
-			"\xa0\xb5\xca\xdf\xf4\x09\x1e\x33"
-			"\x48\x5d\x72\x87\x9c\xb1\xc6\xdb"
-			"\xf0\x05\x1a\x2f\x44\x59\x6e\x83"
-			"\x98\xad\xc2\xd7\xec\x01\x16\x2b"
-			"\x40\x55\x6a\x7f\x94\xa9\xbe\xd3"
-			"\xe8\xfd\x12\x27\x3c\x51\x66\x7b"
-			"\x90\xa5\xba\xcf\xe4\xf9\x0e\x23"
-			"\x38\x4d\x62\x77\x8c\xa1\xb6\xcb"
-			"\xe0\xf5\x0a\x1f\x34\x49\x5e\x73"
-			"\x88\x9d\xb2\xc7\xdc\xf1\x06\x1b"
-			"\x30\x45\x5a\x6f\x84\x99\xae\xc3"
-			"\xd8\xed\x02\x17\x2c\x41\x56\x6b"
-			"\x80\x95\xaa\xbf\xd4\xe9\xfe\x13"
-			"\x28\x3d\x52\x67\x7c\x91\xa6\xbb"
-			"\xd0\xe5\xfa\x0f\x24\x39\x4e\x63"
-			"\x78\x8d\xa2\xb7\xcc\xe1\xf6\x0b"
-			"\x20\x35\x4a\x5f\x74\x89\x9e\xb3"
-			"\xc8\xdd\xf2\x07\x1c\x31\x46\x5b"
-			"\x70\x85\x9a\xaf\xc4\xd9\xee\x03"
-			"\x18\x2d\x42\x57\x6c\x81\x96\xab"
-			"\xc0\xd5\xea\xff\x14\x29\x3e\x53"
-			"\x68\x7d\x92\xa7\xbc\xd1\xe6\xfb"
-			"\x10\x25\x3a\x4f\x64\x79\x8e\xa3"
-			"\xb8\xcd\xe2\xf7\x0c\x21\x36\x4b"
-			"\x60\x75\x8a\x9f\xb4\xc9\xde\xf3"
-			"\x08\x1d\x32\x47\x5c\x71\x86\x9b"
-			"\xb0\xc5\xda\xef\x04\x19\x2e\x43"
-			"\x58\x6d\x82\x97\xac\xc1\xd6\xeb"
-			"\x00\x17\x2e\x45\x5c\x73\x8a\xa1"
-			"\xb8\xcf\xe6\xfd\x14\x2b\x42\x59"
-			"\x70\x87\x9e\xb5\xcc\xe3\xfa\x11"
-			"\x28\x3f\x56\x6d\x84\x9b\xb2\xc9"
-			"\xe0\xf7\x0e\x25\x3c\x53\x6a\x81"
-			"\x98\xaf\xc6\xdd\xf4\x0b\x22\x39"
-			"\x50\x67\x7e\x95\xac\xc3\xda\xf1"
-			"\x08\x1f\x36\x4d\x64\x7b\x92\xa9"
-			"\xc0\xd7\xee\x05\x1c\x33\x4a\x61"
-			"\x78\x8f\xa6\xbd\xd4\xeb\x02\x19"
-			"\x30\x47\x5e\x75\x8c\xa3\xba\xd1"
-			"\xe8\xff\x16\x2d\x44\x5b\x72\x89"
-			"\xa0\xb7\xce\xe5\xfc\x13\x2a\x41"
-			"\x58\x6f\x86\x9d\xb4\xcb\xe2\xf9"
-			"\x10\x27\x3e\x55\x6c\x83\x9a\xb1"
-			"\xc8\xdf\xf6\x0d\x24\x3b\x52\x69"
-			"\x80\x97\xae\xc5\xdc\xf3\x0a\x21"
-			"\x38\x4f\x66\x7d\x94\xab\xc2\xd9"
-			"\xf0\x07\x1e\x35\x4c\x63\x7a\x91"
-			"\xa8\xbf\xd6\xed\x04\x1b\x32\x49"
-			"\x60\x77\x8e\xa5\xbc\xd3\xea\x01"
-			"\x18\x2f\x46\x5d\x74\x8b\xa2\xb9"
-			"\xd0\xe7\xfe\x15\x2c\x43\x5a\x71"
-			"\x88\x9f\xb6\xcd\xe4\xfb\x12\x29"
-			"\x40\x57\x6e\x85\x9c\xb3\xca\xe1"
-			"\xf8\x0f\x26\x3d\x54\x6b\x82\x99"
-			"\xb0\xc7\xde\xf5\x0c\x23\x3a\x51"
-			"\x68\x7f\x96\xad\xc4\xdb\xf2\x09"
-			"\x20\x37\x4e\x65\x7c\x93\xaa\xc1"
-			"\xd8\xef\x06\x1d\x34\x4b\x62\x79"
-			"\x90\xa7\xbe\xd5\xec\x03\x1a\x31"
-			"\x48\x5f\x76\x8d\xa4\xbb\xd2\xe9"
-			"\x00\x19\x32\x4b\x64\x7d\x96\xaf"
-			"\xc8\xe1\xfa\x13\x2c\x45\x5e\x77"
-			"\x90\xa9\xc2\xdb\xf4\x0d\x26\x3f"
-			"\x58\x71\x8a\xa3\xbc\xd5\xee\x07"
-			"\x20\x39\x52\x6b\x84\x9d\xb6\xcf"
-			"\xe8\x01\x1a\x33\x4c\x65\x7e\x97"
-			"\xb0\xc9\xe2\xfb\x14\x2d\x46\x5f"
-			"\x78\x91\xaa\xc3\xdc\xf5\x0e\x27"
-			"\x40\x59\x72\x8b\xa4\xbd\xd6\xef"
-			"\x08\x21\x3a\x53\x6c\x85\x9e\xb7"
-			"\xd0\xe9\x02\x1b\x34\x4d\x66\x7f"
-			"\x98\xb1\xca\xe3\xfc\x15\x2e\x47"
-			"\x60\x79\x92\xab\xc4\xdd\xf6\x0f"
-			"\x28\x41\x5a\x73\x8c\xa5\xbe\xd7"
-			"\xf0\x09\x22\x3b\x54\x6d\x86\x9f"
-			"\xb8\xd1\xea\x03\x1c\x35\x4e\x67"
-			"\x80\x99\xb2\xcb\xe4\xfd\x16\x2f"
-			"\x48\x61\x7a\x93\xac\xc5\xde\xf7"
-			"\x10\x29\x42\x5b\x74\x8d\xa6\xbf"
-			"\xd8\xf1\x0a\x23\x3c\x55\x6e\x87"
-			"\xa0\xb9\xd2\xeb\x04\x1d\x36\x4f"
-			"\x68\x81\x9a\xb3\xcc\xe5\xfe\x17"
-			"\x30\x49\x62\x7b\x94\xad\xc6\xdf"
-			"\xf8\x11\x2a\x43\x5c\x75\x8e\xa7"
-			"\xc0\xd9\xf2\x0b\x24\x3d\x56\x6f"
-			"\x88\xa1\xba\xd3\xec\x05\x1e\x37"
-			"\x50\x69\x82\x9b\xb4\xcd\xe6\xff"
-			"\x18\x31\x4a\x63\x7c\x95\xae\xc7"
-			"\xe0\xf9\x12\x2b\x44\x5d\x76\x8f"
-			"\xa8\xc1\xda\xf3\x0c\x25\x3e\x57"
-			"\x70\x89\xa2\xbb\xd4\xed\x06\x1f"
-			"\x38\x51\x6a\x83\x9c\xb5\xce\xe7"
-			"\x00\x1b\x36\x51\x6c\x87\xa2\xbd"
-			"\xd8\xf3\x0e\x29\x44\x5f\x7a\x95"
-			"\xb0\xcb\xe6\x01\x1c\x37\x52\x6d"
-			"\x88\xa3\xbe\xd9\xf4\x0f\x2a\x45"
-			"\x60\x7b\x96\xb1\xcc\xe7\x02\x1d"
-			"\x38\x53\x6e\x89\xa4\xbf\xda\xf5"
-			"\x10\x2b\x46\x61\x7c\x97\xb2\xcd"
-			"\xe8\x03\x1e\x39\x54\x6f\x8a\xa5"
-			"\xc0\xdb\xf6\x11\x2c\x47\x62\x7d"
-			"\x98\xb3\xce\xe9\x04\x1f\x3a\x55"
-			"\x70\x8b\xa6\xc1\xdc\xf7\x12\x2d"
-			"\x48\x63\x7e\x99\xb4\xcf\xea\x05"
-			"\x20\x3b\x56\x71\x8c\xa7\xc2\xdd"
-			"\xf8\x13\x2e\x49\x64\x7f\x9a\xb5"
-			"\xd0\xeb\x06\x21\x3c\x57\x72\x8d"
-			"\xa8\xc3\xde\xf9\x14\x2f\x4a\x65"
-			"\x80\x9b\xb6\xd1\xec\x07\x22\x3d"
-			"\x58\x73\x8e\xa9\xc4\xdf\xfa\x15"
-			"\x30\x4b\x66\x81\x9c\xb7\xd2\xed"
-			"\x08\x23\x3e\x59\x74\x8f\xaa\xc5"
-			"\xe0\xfb\x16\x31\x4c\x67\x82\x9d"
-			"\xb8\xd3\xee\x09\x24\x3f\x5a\x75"
-			"\x90\xab\xc6\xe1\xfc\x17\x32\x4d"
-			"\x68\x83\x9e\xb9\xd4\xef\x0a\x25"
-			"\x40\x5b\x76\x91\xac\xc7\xe2\xfd"
-			"\x18\x33\x4e\x69\x84\x9f\xba\xd5"
-			"\xf0\x0b\x26\x41\x5c\x77\x92\xad"
-			"\xc8\xe3\xfe\x19\x34\x4f\x6a\x85"
-			"\xa0\xbb\xd6\xf1\x0c\x27\x42\x5d"
-			"\x78\x93\xae\xc9\xe4\xff\x1a\x35"
-			"\x50\x6b\x86\xa1\xbc\xd7\xf2\x0d"
-			"\x28\x43\x5e\x79\x94\xaf\xca\xe5"
-			"\x00\x1d\x3a\x57\x74\x91\xae\xcb"
-			"\xe8\x05\x22\x3f\x5c\x79\x96\xb3"
-			"\xd0\xed\x0a\x27\x44\x61\x7e\x9b"
-			"\xb8\xd5\xf2\x0f\x2c\x49\x66\x83"
-			"\xa0\xbd\xda\xf7\x14\x31\x4e\x6b"
-			"\x88\xa5\xc2\xdf\xfc\x19\x36\x53"
-			"\x70\x8d\xaa\xc7\xe4\x01\x1e\x3b"
-			"\x58\x75\x92\xaf\xcc\xe9\x06\x23"
-			"\x40\x5d\x7a\x97\xb4\xd1\xee\x0b"
-			"\x28\x45\x62\x7f\x9c\xb9\xd6\xf3"
-			"\x10\x2d\x4a\x67\x84\xa1\xbe\xdb"
-			"\xf8\x15\x32\x4f\x6c\x89\xa6\xc3"
-			"\xe0\xfd\x1a\x37\x54\x71\x8e\xab"
-			"\xc8\xe5\x02\x1f\x3c\x59\x76\x93"
-			"\xb0\xcd\xea\x07\x24\x41\x5e\x7b"
-			"\x98\xb5\xd2\xef\x0c\x29\x46\x63"
-			"\x80\x9d\xba\xd7\xf4\x11\x2e\x4b"
-			"\x68\x85\xa2\xbf\xdc\xf9\x16\x33"
-			"\x50\x6d\x8a\xa7\xc4\xe1\xfe\x1b"
-			"\x38\x55\x72\x8f\xac\xc9\xe6\x03"
-			"\x20\x3d\x5a\x77\x94\xb1\xce\xeb"
-			"\x08\x25\x42\x5f\x7c\x99\xb6\xd3"
-			"\xf0\x0d\x2a\x47\x64\x81\x9e\xbb"
-			"\xd8\xf5\x12\x2f\x4c\x69\x86\xa3"
-			"\xc0\xdd\xfa\x17\x34\x51\x6e\x8b"
-			"\xa8\xc5\xe2\xff\x1c\x39\x56\x73"
-			"\x90\xad\xca\xe7\x04\x21\x3e\x5b"
-			"\x78\x95\xb2\xcf\xec\x09\x26\x43"
-			"\x60\x7d\x9a\xb7\xd4\xf1\x0e\x2b"
-			"\x48\x65\x82\x9f\xbc\xd9\xf6\x13"
-			"\x30\x4d\x6a\x87\xa4\xc1\xde\xfb"
-			"\x18\x35\x52\x6f\x8c\xa9\xc6\xe3"
-			"\x00\x1f\x3e\x5d\x7c\x9b\xba\xd9"
-			"\xf8\x17\x36\x55\x74\x93\xb2\xd1"
-			"\xf0\x0f\x2e\x4d\x6c\x8b\xaa\xc9"
-			"\xe8\x07\x26\x45\x64\x83\xa2\xc1"
-			"\xe0\xff\x1e\x3d\x5c\x7b\x9a\xb9"
-			"\xd8\xf7\x16\x35\x54\x73\x92\xb1"
-			"\xd0\xef\x0e\x2d\x4c\x6b\x8a\xa9"
-			"\xc8\xe7\x06\x25\x44\x63\x82\xa1"
-			"\xc0\xdf\xfe\x1d\x3c\x5b\x7a\x99"
-			"\xb8\xd7\xf6\x15\x34\x53\x72\x91"
-			"\xb0\xcf\xee\x0d\x2c\x4b\x6a\x89"
-			"\xa8\xc7\xe6\x05\x24\x43\x62\x81"
-			"\xa0\xbf\xde\xfd\x1c\x3b\x5a\x79"
-			"\x98\xb7\xd6\xf5\x14\x33\x52\x71"
-			"\x90\xaf\xce\xed\x0c\x2b\x4a\x69"
-			"\x88\xa7\xc6\xe5\x04\x23\x42\x61"
-			"\x80\x9f\xbe\xdd\xfc\x1b\x3a\x59"
-			"\x78\x97\xb6\xd5\xf4\x13\x32\x51"
-			"\x70\x8f\xae\xcd\xec\x0b\x2a\x49"
-			"\x68\x87\xa6\xc5\xe4\x03\x22\x41"
-			"\x60\x7f\x9e\xbd\xdc\xfb\x1a\x39"
-			"\x58\x77\x96\xb5\xd4\xf3\x12\x31"
-			"\x50\x6f\x8e\xad\xcc\xeb\x0a\x29"
-			"\x48\x67\x86\xa5\xc4\xe3\x02\x21"
-			"\x40\x5f\x7e\x9d\xbc\xdb\xfa\x19"
-			"\x38\x57\x76\x95\xb4\xd3\xf2\x11"
-			"\x30\x4f\x6e\x8d\xac\xcb\xea\x09"
-			"\x28\x47\x66\x85\xa4\xc3\xe2\x01"
-			"\x20\x3f\x5e\x7d\x9c\xbb\xda\xf9"
-			"\x18\x37\x56\x75\x94\xb3\xd2\xf1"
-			"\x10\x2f\x4e\x6d\x8c\xab\xca\xe9"
-			"\x08\x27\x46\x65\x84\xa3\xc2\xe1"
-			"\x00\x21\x42\x63",
-		.ilen = 4100,
-		.result =
-			"\xb5\x81\xf5\x64\x18\x73\xe3\xf0"
-			"\x4c\x13\xf2\x77\x18\x60\x65\x5e"
-			"\x29\x01\xce\x98\x55\x53\xf9\x0c"
-			"\x2a\x08\xd5\x09\xb3\x57\x55\x56"
-			"\xc5\xe9\x56\x90\xcb\x6a\xa3\xc0"
-			"\xff\xc4\x79\xb4\xd2\x97\x5d\xc4"
-			"\x43\xd1\xfe\x94\x7b\x88\x06\x5a"
-			"\xb2\x9e\x2c\xfc\x44\x03\xb7\x90"
-			"\xa0\xc1\xba\x6a\x33\xb8\xc7\xb2"
-			"\x9d\xe1\x12\x4f\xc0\x64\xd4\x01"
-			"\xfe\x8c\x7a\x66\xf7\xe6\x5a\x91"
-			"\xbb\xde\x56\x86\xab\x65\x21\x30"
-			"\x00\x84\x65\x24\xa5\x7d\x85\xb4"
-			"\xe3\x17\xed\x3a\xb7\x6f\xb4\x0b"
-			"\x0b\xaf\x15\xae\x5a\x8f\xf2\x0c"
-			"\x2f\x27\xf4\x09\xd8\xd2\x96\xb7"
-			"\x71\xf2\xc5\x99\x4d\x7e\x7f\x75"
-			"\x77\x89\x30\x8b\x59\xdb\xa2\xb2"
-			"\xa0\xf3\x19\x39\x2b\xc5\x7e\x3f"
-			"\x4f\xd9\xd3\x56\x28\x97\x44\xdc"
-			"\xc0\x8b\x77\x24\xd9\x52\xe7\xc5"
-			"\xaf\xf6\x7d\x59\xb2\x44\x05\x1d"
-			"\xb1\xb0\x11\xa5\x0f\xec\x33\xe1"
-			"\x6d\x1b\x4e\x1f\xff\x57\x91\xb4"
-			"\x5b\x9a\x96\xc5\x53\xbc\xae\x20"
-			"\x3c\xbb\x14\xe2\xe8\x22\x33\xc1"
-			"\x5e\x76\x9e\x46\x99\xf6\x2a\x15"
-			"\xc6\x97\x02\xa0\x66\x43\xd1\xa6"
-			"\x31\xa6\x9f\xfb\xf4\xd3\x69\xe5"
-			"\xcd\x76\x95\xb8\x7a\x82\x7f\x21"
-			"\x45\xff\x3f\xce\x55\xf6\x95\x10"
-			"\x08\x77\x10\x43\xc6\xf3\x09\xe5"
-			"\x68\xe7\x3c\xad\x00\x52\x45\x0d"
-			"\xfe\x2d\xc6\xc2\x94\x8c\x12\x1d"
-			"\xe6\x25\xae\x98\x12\x8e\x19\x9c"
-			"\x81\x68\xb1\x11\xf6\x69\xda\xe3"
-			"\x62\x08\x18\x7a\x25\x49\x28\xac"
-			"\xba\x71\x12\x0b\xe4\xa2\xe5\xc7"
-			"\x5d\x8e\xec\x49\x40\x21\xbf\x5a"
-			"\x98\xf3\x02\x68\x55\x03\x7f\x8a"
-			"\xe5\x94\x0c\x32\x5c\x07\x82\x63"
-			"\xaf\x6f\x91\x40\x84\x8e\x52\x25"
-			"\xd0\xb0\x29\x53\x05\xe2\x50\x7a"
-			"\x34\xeb\xc9\x46\x20\xa8\x3d\xde"
-			"\x7f\x16\x5f\x36\xc5\x2e\xdc\xd1"
-			"\x15\x47\xc7\x50\x40\x6d\x91\xc5"
-			"\xe7\x93\x95\x1a\xd3\x57\xbc\x52"
-			"\x33\xee\x14\x19\x22\x52\x89\xa7"
-			"\x4a\x25\x56\x77\x4b\xca\xcf\x0a"
-			"\xe1\xf5\x35\x85\x30\x7e\x59\x4a"
-			"\xbd\x14\x5b\xdf\xe3\x46\xcb\xac"
-			"\x1f\x6c\x96\x0e\xf4\x81\xd1\x99"
-			"\xca\x88\x63\x3d\x02\x58\x6b\xa9"
-			"\xe5\x9f\xb3\x00\xb2\x54\xc6\x74"
-			"\x1c\xbf\x46\xab\x97\xcc\xf8\x54"
-			"\x04\x07\x08\x52\xe6\xc0\xda\x93"
-			"\x74\x7d\x93\x99\x5d\x78\x68\xa6"
-			"\x2e\x6b\xd3\x6a\x69\xcc\x12\x6b"
-			"\xd4\xc7\xa5\xc6\xe7\xf6\x03\x04"
-			"\x5d\xcd\x61\x5e\x17\x40\xdc\xd1"
-			"\x5c\xf5\x08\xdf\x5c\x90\x85\xa4"
-			"\xaf\xf6\x78\xbb\x0d\xf1\xf4\xa4"
-			"\x54\x26\x72\x9e\x61\xfa\x86\xcf"
-			"\xe8\x9e\xa1\xe0\xc7\x48\x23\xae"
-			"\x5a\x90\xae\x75\x0a\x74\x18\x89"
-			"\x05\xb1\x92\xb2\x7f\xd0\x1b\xa6"
-			"\x62\x07\x25\x01\xc7\xc2\x4f\xf9"
-			"\xe8\xfe\x63\x95\x80\x07\xb4\x26"
-			"\xcc\xd1\x26\xb6\xc4\x3f\x9e\xcb"
-			"\x8e\x3b\x2e\x44\x16\xd3\x10\x9a"
-			"\x95\x08\xeb\xc8\xcb\xeb\xbf\x6f"
-			"\x0b\xcd\x1f\xc8\xca\x86\xaa\xec"
-			"\x33\xe6\x69\xf4\x45\x25\x86\x3a"
-			"\x22\x94\x4f\x00\x23\x6a\x44\xc2"
-			"\x49\x97\x33\xab\x36\x14\x0a\x70"
-			"\x24\xc3\xbe\x04\x3b\x79\xa0\xf9"
-			"\xb8\xe7\x76\x29\x22\x83\xd7\xf2"
-			"\x94\xf4\x41\x49\xba\x5f\x7b\x07"
-			"\xb5\xfb\xdb\x03\x1a\x9f\xb6\x4c"
-			"\xc2\x2e\x37\x40\x49\xc3\x38\x16"
-			"\xe2\x4f\x77\x82\xb0\x68\x4c\x71"
-			"\x1d\x57\x61\x9c\xd9\x4e\x54\x99"
-			"\x47\x13\x28\x73\x3c\xbb\x00\x90"
-			"\xf3\x4d\xc9\x0e\xfd\xe7\xb1\x71"
-			"\xd3\x15\x79\xbf\xcc\x26\x2f\xbd"
-			"\xad\x6c\x50\x69\x6c\x3e\x6d\x80"
-			"\x9a\xea\x78\xaf\x19\xb2\x0d\x4d"
-			"\xad\x04\x07\xae\x22\x90\x4a\x93"
-			"\x32\x0e\x36\x9b\x1b\x46\xba\x3b"
-			"\xb4\xac\xc6\xd1\xa2\x31\x53\x3b"
-			"\x2a\x3d\x45\xfe\x03\x61\x10\x85"
-			"\x17\x69\xa6\x78\xcc\x6c\x87\x49"
-			"\x53\xf9\x80\x10\xde\x80\xa2\x41"
-			"\x6a\xc3\x32\x02\xad\x6d\x3c\x56"
-			"\x00\x71\x51\x06\xa7\xbd\xfb\xef"
-			"\x3c\xb5\x9f\xfc\x48\x7d\x53\x7c"
-			"\x66\xb0\x49\x23\xc4\x47\x10\x0e"
-			"\xe5\x6c\x74\x13\xe6\xc5\x3f\xaa"
-			"\xde\xff\x07\x44\xdd\x56\x1b\xad"
-			"\x09\x77\xfb\x5b\x12\xb8\x0d\x38"
-			"\x17\x37\x35\x7b\x9b\xbc\xfe\xd4"
-			"\x7e\x8b\xda\x7e\x5b\x04\xa7\x22"
-			"\xa7\x31\xa1\x20\x86\xc7\x1b\x99"
-			"\xdb\xd1\x89\xf4\x94\xa3\x53\x69"
-			"\x8d\xe7\xe8\x74\x11\x8d\x74\xd6"
-			"\x07\x37\x91\x9f\xfd\x67\x50\x3a"
-			"\xc9\xe1\xf4\x36\xd5\xa0\x47\xd1"
-			"\xf9\xe5\x39\xa3\x31\xac\x07\x36"
-			"\x23\xf8\x66\x18\x14\x28\x34\x0f"
-			"\xb8\xd0\xe7\x29\xb3\x04\x4b\x55"
-			"\x01\x41\xb2\x75\x8d\xcb\x96\x85"
-			"\x3a\xfb\xab\x2b\x9e\xfa\x58\x20"
-			"\x44\x1f\xc0\x14\x22\x75\x61\xe8"
-			"\xaa\x19\xcf\xf1\x82\x56\xf4\xd7"
-			"\x78\x7b\x3d\x5f\xb3\x9e\x0b\x8a"
-			"\x57\x50\xdb\x17\x41\x65\x4d\xa3"
-			"\x02\xc9\x9c\x9c\x53\xfb\x39\x39"
-			"\x9b\x1d\x72\x24\xda\xb7\x39\xbe"
-			"\x13\x3b\xfa\x29\xda\x9e\x54\x64"
-			"\x6e\xba\xd8\xa1\xcb\xb3\x36\xfa"
-			"\xcb\x47\x85\xe9\x61\x38\xbc\xbe"
-			"\xc5\x00\x38\x2a\x54\xf7\xc4\xb9"
-			"\xb3\xd3\x7b\xa0\xa0\xf8\x72\x7f"
-			"\x8c\x8e\x82\x0e\xc6\x1c\x75\x9d"
-			"\xca\x8e\x61\x87\xde\xad\x80\xd2"
-			"\xf5\xf9\x80\xef\x15\x75\xaf\xf5"
-			"\x80\xfb\xff\x6d\x1e\x25\xb7\x40"
-			"\x61\x6a\x39\x5a\x6a\xb5\x31\xab"
-			"\x97\x8a\x19\x89\x44\x40\xc0\xa6"
-			"\xb4\x4e\x30\x32\x7b\x13\xe7\x67"
-			"\xa9\x8b\x57\x04\xc2\x01\xa6\xf4"
-			"\x28\x99\xad\x2c\x76\xa3\x78\xc2"
-			"\x4a\xe6\xca\x5c\x50\x6a\xc1\xb0"
-			"\x62\x4b\x10\x8e\x7c\x17\x43\xb3"
-			"\x17\x66\x1c\x3e\x8d\x69\xf0\x5a"
-			"\x71\xf5\x97\xdc\xd1\x45\xdd\x28"
-			"\xf3\x5d\xdf\x53\x7b\x11\xe5\xbc"
-			"\x4c\xdb\x1b\x51\x6b\xe9\xfb\x3d"
-			"\xc1\xc3\x2c\xb9\x71\xf5\xb6\xb2"
-			"\x13\x36\x79\x80\x53\xe8\xd3\xa6"
-			"\x0a\xaf\xfd\x56\x97\xf7\x40\x8e"
-			"\x45\xce\xf8\xb0\x9e\x5c\x33\x82"
-			"\xb0\x44\x56\xfc\x05\x09\xe9\x2a"
-			"\xac\x26\x80\x14\x1d\xc8\x3a\x35"
-			"\x4c\x82\x97\xfd\x76\xb7\xa9\x0a"
-			"\x35\x58\x79\x8e\x0f\x66\xea\xaf"
-			"\x51\x6c\x09\xa9\x6e\x9b\xcb\x9a"
-			"\x31\x47\xa0\x2f\x7c\x71\xb4\x4a"
-			"\x11\xaa\x8c\x66\xc5\x64\xe6\x3a"
-			"\x54\xda\x24\x6a\xc4\x41\x65\x46"
-			"\x82\xa0\x0a\x0f\x5f\xfb\x25\xd0"
-			"\x2c\x91\xa7\xee\xc4\x81\x07\x86"
-			"\x75\x5e\x33\x69\x97\xe4\x2c\xa8"
-			"\x9d\x9f\x0b\x6a\xbe\xad\x98\xda"
-			"\x6d\x94\x41\xda\x2c\x1e\x89\xc4"
-			"\xc2\xaf\x1e\x00\x05\x0b\x83\x60"
-			"\xbd\x43\xea\x15\x23\x7f\xb9\xac"
-			"\xee\x4f\x2c\xaf\x2a\xf3\xdf\xd0"
-			"\xf3\x19\x31\xbb\x4a\x74\x84\x17"
-			"\x52\x32\x2c\x7d\x61\xe4\xcb\xeb"
-			"\x80\x38\x15\x52\xcb\x6f\xea\xe5"
-			"\x73\x9c\xd9\x24\x69\xc6\x95\x32"
-			"\x21\xc8\x11\xe4\xdc\x36\xd7\x93"
-			"\x38\x66\xfb\xb2\x7f\x3a\xb9\xaf"
-			"\x31\xdd\x93\x75\x78\x8a\x2c\x94"
-			"\x87\x1a\x58\xec\x9e\x7d\x4d\xba"
-			"\xe1\xe5\x4d\xfc\xbc\xa4\x2a\x14"
-			"\xef\xcc\xa7\xec\xab\x43\x09\x18"
-			"\xd3\xab\x68\xd1\x07\x99\x44\x47"
-			"\xd6\x83\x85\x3b\x30\xea\xa9\x6b"
-			"\x63\xea\xc4\x07\xfb\x43\x2f\xa4"
-			"\xaa\xb0\xab\x03\x89\xce\x3f\x8c"
-			"\x02\x7c\x86\x54\xbc\x88\xaf\x75"
-			"\xd2\xdc\x63\x17\xd3\x26\xf6\x96"
-			"\xa9\x3c\xf1\x61\x8c\x11\x18\xcc"
-			"\xd6\xea\x5b\xe2\xcd\xf0\xf1\xb2"
-			"\xe5\x35\x90\x1f\x85\x4c\x76\x5b"
-			"\x66\xce\x44\xa4\x32\x9f\xe6\x7b"
-			"\x71\x6e\x9f\x58\x15\x67\x72\x87"
-			"\x64\x8e\x3a\x44\x45\xd4\x76\xfa"
-			"\xc2\xf6\xef\x85\x05\x18\x7a\x9b"
-			"\xba\x41\x54\xac\xf0\xfc\x59\x12"
-			"\x3f\xdf\xa0\xe5\x8a\x65\xfd\x3a"
-			"\x62\x8d\x83\x2c\x03\xbe\x05\x76"
-			"\x2e\x53\x49\x97\x94\x33\xae\x40"
-			"\x81\x15\xdb\x6e\xad\xaa\xf5\x4b"
-			"\xe3\x98\x70\xdf\xe0\x7c\xcd\xdb"
-			"\x02\xd4\x7d\x2f\xc1\xe6\xb4\xf3"
-			"\xd7\x0d\x7a\xd9\x23\x9e\x87\x2d"
-			"\xce\x87\xad\xcc\x72\x05\x00\x29"
-			"\xdc\x73\x7f\x64\xc1\x15\x0e\xc2"
-			"\xdf\xa7\x5f\xeb\x41\xa1\xcd\xef"
-			"\x5c\x50\x79\x2a\x56\x56\x71\x8c"
-			"\xac\xc0\x79\x50\x69\xca\x59\x32"
-			"\x65\xf2\x54\xe4\x52\x38\x76\xd1"
-			"\x5e\xde\x26\x9e\xfb\x75\x2e\x11"
-			"\xb5\x10\xf4\x17\x73\xf5\x89\xc7"
-			"\x4f\x43\x5c\x8e\x7c\xb9\x05\x52"
-			"\x24\x40\x99\xfe\x9b\x85\x0b\x6c"
-			"\x22\x3e\x8b\xae\x86\xa1\xd2\x79"
-			"\x05\x68\x6b\xab\xe3\x41\x49\xed"
-			"\x15\xa1\x8d\x40\x2d\x61\xdf\x1a"
-			"\x59\xc9\x26\x8b\xef\x30\x4c\x88"
-			"\x4b\x10\xf8\x8d\xa6\x92\x9f\x4b"
-			"\xf3\xc4\x53\x0b\x89\x5d\x28\x92"
-			"\xcf\x78\xb2\xc0\x5d\xed\x7e\xfc"
-			"\xc0\x12\x23\x5f\x5a\x78\x86\x43"
-			"\x6e\x27\xf7\x5a\xa7\x6a\xed\x19"
-			"\x04\xf0\xb3\x12\xd1\xbd\x0e\x89"
-			"\x6e\xbc\x96\xa8\xd8\x49\x39\x9f"
-			"\x7e\x67\xf0\x2e\x3e\x01\xa9\xba"
-			"\xec\x8b\x62\x8e\xcb\x4a\x70\x43"
-			"\xc7\xc2\xc4\xca\x82\x03\x73\xe9"
-			"\x11\xdf\xcf\x54\xea\xc9\xb0\x95"
-			"\x51\xc0\x13\x3d\x92\x05\xfa\xf4"
-			"\xa9\x34\xc8\xce\x6c\x3d\x54\xcc"
-			"\xc4\xaf\xf1\xdc\x11\x44\x26\xa2"
-			"\xaf\xf1\x85\x75\x7d\x03\x61\x68"
-			"\x4e\x78\xc6\x92\x7d\x86\x7d\x77"
-			"\xdc\x71\x72\xdb\xc6\xae\xa1\xcb"
-			"\x70\x9a\x0b\x19\xbe\x4a\x6c\x2a"
-			"\xe2\xba\x6c\x64\x9a\x13\x28\xdf"
-			"\x85\x75\xe6\x43\xf6\x87\x08\x68"
-			"\x6e\xba\x6e\x79\x9f\x04\xbc\x23"
-			"\x50\xf6\x33\x5c\x1f\x24\x25\xbe"
-			"\x33\x47\x80\x45\x56\xa3\xa7\xd7"
-			"\x7a\xb1\x34\x0b\x90\x3c\x9c\xad"
-			"\x44\x5f\x9e\x0e\x9d\xd4\xbd\x93"
-			"\x5e\xfa\x3c\xe0\xb0\xd9\xed\xf3"
-			"\xd6\x2e\xff\x24\xd8\x71\x6c\xed"
-			"\xaf\x55\xeb\x22\xac\x93\x68\x32"
-			"\x05\x5b\x47\xdd\xc6\x4a\xcb\xc7"
-			"\x10\xe1\x3c\x92\x1a\xf3\x23\x78"
-			"\x2b\xa1\xd2\x80\xf4\x12\xb1\x20"
-			"\x8f\xff\x26\x35\xdd\xfb\xc7\x4e"
-			"\x78\xf1\x2d\x50\x12\x77\xa8\x60"
-			"\x7c\x0f\xf5\x16\x2f\x63\x70\x2a"
-			"\xc0\x96\x80\x4e\x0a\xb4\x93\x35"
-			"\x5d\x1d\x3f\x56\xf7\x2f\xbb\x90"
-			"\x11\x16\x8f\xa2\xec\x47\xbe\xac"
-			"\x56\x01\x26\x56\xb1\x8c\xb2\x10"
-			"\xf9\x1a\xca\xf5\xd1\xb7\x39\x20"
-			"\x63\xf1\x69\x20\x4f\x13\x12\x1f"
-			"\x5b\x65\xfc\x98\xf7\xc4\x7a\xbe"
-			"\xf7\x26\x4d\x2b\x84\x7b\x42\xad"
-			"\xd8\x7a\x0a\xb4\xd8\x74\xbf\xc1"
-			"\xf0\x6e\xb4\x29\xa3\xbb\xca\x46"
-			"\x67\x70\x6a\x2d\xce\x0e\xa2\x8a"
-			"\xa9\x87\xbf\x05\xc4\xc1\x04\xa3"
-			"\xab\xd4\x45\x43\x8c\xb6\x02\xb0"
-			"\x41\xc8\xfc\x44\x3d\x59\xaa\x2e"
-			"\x44\x21\x2a\x8d\x88\x9d\x57\xf4"
-			"\xa0\x02\x77\xb8\xa6\xa0\xe6\x75"
-			"\x5c\x82\x65\x3e\x03\x5c\x29\x8f"
-			"\x38\x55\xab\x33\x26\xef\x9f\x43"
-			"\x52\xfd\x68\xaf\x36\xb4\xbb\x9a"
-			"\x58\x09\x09\x1b\xc3\x65\x46\x46"
-			"\x1d\xa7\x94\x18\x23\x50\x2c\xca"
-			"\x2c\x55\x19\x97\x01\x9d\x93\x3b"
-			"\x63\x86\xf2\x03\x67\x45\xd2\x72"
-			"\x28\x52\x6c\xf4\xe3\x1c\xb5\x11"
-			"\x13\xf1\xeb\x21\xc7\xd9\x56\x82"
-			"\x2b\x82\x39\xbd\x69\x54\xed\x62"
-			"\xc3\xe2\xde\x73\xd4\x6a\x12\xae"
-			"\x13\x21\x7f\x4b\x5b\xfc\xbf\xe8"
-			"\x2b\xbe\x56\xba\x68\x8b\x9a\xb1"
-			"\x6e\xfa\xbf\x7e\x5a\x4b\xf1\xac"
-			"\x98\x65\x85\xd1\x93\x53\xd3\x7b"
-			"\x09\xdd\x4b\x10\x6d\x84\xb0\x13"
-			"\x65\xbd\xcf\x52\x09\xc4\x85\xe2"
-			"\x84\x74\x15\x65\xb7\xf7\x51\xaf"
-			"\x55\xad\xa4\xd1\x22\x54\x70\x94"
-			"\xa0\x1c\x90\x41\xfd\x99\xd7\x5a"
-			"\x31\xef\xaa\x25\xd0\x7f\x4f\xea"
-			"\x1d\x55\x42\xe5\x49\xb0\xd0\x46"
-			"\x62\x36\x43\xb2\x82\x15\x75\x50"
-			"\xa4\x72\xeb\x54\x27\x1f\x8a\xe4"
-			"\x7d\xe9\x66\xc5\xf1\x53\xa4\xd1"
-			"\x0c\xeb\xb8\xf8\xbc\xd4\xe2\xe7"
-			"\xe1\xf8\x4b\xcb\xa9\xa1\xaf\x15"
-			"\x83\xcb\x72\xd0\x33\x79\x00\x2d"
-			"\x9f\xd7\xf1\x2e\x1e\x10\xe4\x45"
-			"\xc0\x75\x3a\x39\xea\x68\xf7\x5d"
-			"\x1b\x73\x8f\xe9\x8e\x0f\x72\x47"
-			"\xae\x35\x0a\x31\x7a\x14\x4d\x4a"
-			"\x6f\x47\xf7\x7e\x91\x6e\x74\x8b"
-			"\x26\x47\xf9\xc3\xf9\xde\x70\xf5"
-			"\x61\xab\xa9\x27\x9f\x82\xe4\x9c"
-			"\x89\x91\x3f\x2e\x6a\xfd\xb5\x49"
-			"\xe9\xfd\x59\x14\x36\x49\x40\x6d"
-			"\x32\xd8\x85\x42\xf3\xa5\xdf\x0c"
-			"\xa8\x27\xd7\x54\xe2\x63\x2f\xf2"
-			"\x7e\x8b\x8b\xe7\xf1\x9a\x95\x35"
-			"\x43\xdc\x3a\xe4\xb6\xf4\xd0\xdf"
-			"\x9c\xcb\x94\xf3\x21\xa0\x77\x50"
-			"\xe2\xc6\xc4\xc6\x5f\x09\x64\x5b"
-			"\x92\x90\xd8\xe1\xd1\xed\x4b\x42"
-			"\xd7\x37\xaf\x65\x3d\x11\x39\xb6"
-			"\x24\x8a\x60\xae\xd6\x1e\xbf\x0e"
-			"\x0d\xd7\xdc\x96\x0e\x65\x75\x4e"
-			"\x29\x06\x9d\xa4\x51\x3a\x10\x63"
-			"\x8f\x17\x07\xd5\x8e\x3c\xf4\x28"
-			"\x00\x5a\x5b\x05\x19\xd8\xc0\x6c"
-			"\xe5\x15\xe4\x9c\x9d\x71\x9d\x5e"
-			"\x94\x29\x1a\xa7\x80\xfa\x0e\x33"
-			"\x03\xdd\xb7\x3e\x9a\xa9\x26\x18"
-			"\x37\xa9\x64\x08\x4d\x94\x5a\x88"
-			"\xca\x35\xce\x81\x02\xe3\x1f\x1b"
-			"\x89\x1a\x77\x85\xe3\x41\x6d\x32"
-			"\x42\x19\x23\x7d\xc8\x73\xee\x25"
-			"\x85\x0d\xf8\x31\x25\x79\x1b\x6f"
-			"\x79\x25\xd2\xd8\xd4\x23\xfd\xf7"
-			"\x82\x36\x6a\x0c\x46\x22\x15\xe9"
-			"\xff\x72\x41\x91\x91\x7d\x3a\xb7"
-			"\xdd\x65\x99\x70\xf6\x8d\x84\xf8"
-			"\x67\x15\x20\x11\xd6\xb2\x55\x7b"
-			"\xdb\x87\xee\xef\x55\x89\x2a\x59"
-			"\x2b\x07\x8f\x43\x8a\x59\x3c\x01"
-			"\x8b\x65\x54\xa1\x66\xd5\x38\xbd"
-			"\xc6\x30\xa9\xcc\x49\xb6\xa8\x1b"
-			"\xb8\xc0\x0e\xe3\x45\x28\xe2\xff"
-			"\x41\x9f\x7e\x7c\xd1\xae\x9e\x25"
-			"\x3f\x4c\x7c\x7c\xf4\xa8\x26\x4d"
-			"\x5c\xfd\x4b\x27\x18\xf9\x61\x76"
-			"\x48\xba\x0c\x6b\xa9\x4d\xfc\xf5"
-			"\x3b\x35\x7e\x2f\x4a\xa9\xc2\x9a"
-			"\xae\xab\x86\x09\x89\xc9\xc2\x40"
-			"\x39\x2c\x81\xb3\xb8\x17\x67\xc2"
-			"\x0d\x32\x4a\x3a\x67\x81\xd7\x1a"
-			"\x34\x52\xc5\xdb\x0a\xf5\x63\x39"
-			"\xea\x1f\xe1\x7c\xa1\x9e\xc1\x35"
-			"\xe3\xb1\x18\x45\x67\xf9\x22\x38"
-			"\x95\xd9\x34\x34\x86\xc6\x41\x94"
-			"\x15\xf9\x5b\x41\xa6\x87\x8b\xf8"
-			"\xd5\xe1\x1b\xe2\x5b\xf3\x86\x10"
-			"\xff\xe6\xae\x69\x76\xbc\x0d\xb4"
-			"\x09\x90\x0c\xa2\x65\x0c\xad\x74"
-			"\xf5\xd7\xff\xda\xc1\xce\x85\xbe"
-			"\x00\xa7\xff\x4d\x2f\x65\xd3\x8c"
-			"\x86\x2d\x05\xe8\xed\x3e\x6b\x8b"
-			"\x0f\x3d\x83\x8c\xf1\x1d\x5b\x96"
-			"\x2e\xb1\x9c\xc2\x98\xe1\x70\xb9"
-			"\xba\x5c\x8a\x43\xd6\x34\xa7\x2d"
-			"\xc9\x92\xae\xf2\xa5\x7b\x05\x49"
-			"\xa7\x33\x34\x86\xca\xe4\x96\x23"
-			"\x76\x5b\xf2\xc6\xf1\x51\x28\x42"
-			"\x7b\xcc\x76\x8f\xfa\xa2\xad\x31"
-			"\xd4\xd6\x7a\x6d\x25\x25\x54\xe4"
-			"\x3f\x50\x59\xe1\x5c\x05\xb7\x27"
-			"\x48\xbf\x07\xec\x1b\x13\xbe\x2b"
-			"\xa1\x57\x2b\xd5\xab\xd7\xd0\x4c"
-			"\x1e\xcb\x71\x9b\xc5\x90\x85\xd3"
-			"\xde\x59\xec\x71\xeb\x89\xbb\xd0"
-			"\x09\x50\xe1\x16\x3f\xfd\x1c\x34"
-			"\xc3\x1c\xa1\x10\x77\x53\x98\xef"
-			"\xf2\xfd\xa5\x01\x59\xc2\x9b\x26"
-			"\xc7\x42\xd9\x49\xda\x58\x2b\x6e"
-			"\x9f\x53\x19\x76\x7e\xd9\xc9\x0e"
-			"\x68\xc8\x7f\x51\x22\x42\xef\x49"
-			"\xa4\x55\xb6\x36\xac\x09\xc7\x31"
-			"\x88\x15\x4b\x2e\x8f\x3a\x08\xf7"
-			"\xd8\xf7\xa8\xc5\xa9\x33\xa6\x45"
-			"\xe4\xc4\x94\x76\xf3\x0d\x8f\x7e"
-			"\xc8\xf6\xbc\x23\x0a\xb6\x4c\xd3"
-			"\x6a\xcd\x36\xc2\x90\x5c\x5c\x3c"
-			"\x65\x7b\xc2\xd6\xcc\xe6\x0d\x87"
-			"\x73\x2e\x71\x79\x16\x06\x63\x28"
-			"\x09\x15\xd8\x89\x38\x38\x3d\xb5"
-			"\x42\x1c\x08\x24\xf7\x2a\xd2\x9d"
-			"\xc8\xca\xef\xf9\x27\xd8\x07\x86"
-			"\xf7\x43\x0b\x55\x15\x3f\x9f\x83"
-			"\xef\xdc\x49\x9d\x2a\xc1\x54\x62"
-			"\xbd\x9b\x66\x55\x9f\xb7\x12\xf3"
-			"\x1b\x4d\x9d\x2a\x5c\xed\x87\x75"
-			"\x87\x26\xec\x61\x2c\xb4\x0f\x89"
-			"\xb0\xfb\x2e\x68\x5d\x15\xc7\x8d"
-			"\x2e\xc0\xd9\xec\xaf\x4f\xd2\x25"
-			"\x29\xe8\xd2\x26\x2b\x67\xe9\xfc"
-			"\x2b\xa8\x67\x96\x12\x1f\x5b\x96"
-			"\xc6\x14\x53\xaf\x44\xea\xd6\xe2"
-			"\x94\x98\xe4\x12\x93\x4c\x92\xe0"
-			"\x18\xa5\x8d\x2d\xe4\x71\x3c\x47"
-			"\x4c\xf7\xe6\x47\x9e\xc0\x68\xdf"
-			"\xd4\xf5\x5a\x74\xb1\x2b\x29\x03"
-			"\x19\x07\xaf\x90\x62\x5c\x68\x98"
-			"\x48\x16\x11\x02\x9d\xee\xb4\x9b"
-			"\xe5\x42\x7f\x08\xfd\x16\x32\x0b"
-			"\xd0\xb3\xfa\x2b\xb7\x99\xf9\x29"
-			"\xcd\x20\x45\x9f\xb3\x1a\x5d\xa2"
-			"\xaf\x4d\xe0\xbd\x42\x0d\xbc\x74"
-			"\x99\x9c\x8e\x53\x1a\xb4\x3e\xbd"
-			"\xa2\x9a\x2d\xf7\xf8\x39\x0f\x67"
-			"\x63\xfc\x6b\xc0\xaf\xb3\x4b\x4f"
-			"\x55\xc4\xcf\xa7\xc8\x04\x11\x3e"
-			"\x14\x32\xbb\x1b\x38\x77\xd6\x7f"
-			"\x54\x4c\xdf\x75\xf3\x07\x2d\x33"
-			"\x9b\xa8\x20\xe1\x7b\x12\xb5\xf3"
-			"\xef\x2f\xce\x72\xe5\x24\x60\xc1"
-			"\x30\xe2\xab\xa1\x8e\x11\x09\xa8"
-			"\x21\x33\x44\xfe\x7f\x35\x32\x93"
-			"\x39\xa7\xad\x8b\x79\x06\xb2\xcb"
-			"\x4e\xa9\x5f\xc7\xba\x74\x29\xec"
-			"\x93\xa0\x4e\x54\x93\xc0\xbc\x55"
-			"\x64\xf0\x48\xe5\x57\x99\xee\x75"
-			"\xd6\x79\x0f\x66\xb7\xc6\x57\x76"
-			"\xf7\xb7\xf3\x9c\xc5\x60\xe8\x7f"
-			"\x83\x76\xd6\x0e\xaa\xe6\x90\x39"
-			"\x1d\xa6\x32\x6a\x34\xe3\x55\xf8"
-			"\x58\xa0\x58\x7d\x33\xe0\x22\x39"
-			"\x44\x64\x87\x86\x5a\x2f\xa7\x7e"
-			"\x0f\x38\xea\xb0\x30\xcc\x61\xa5"
-			"\x6a\x32\xae\x1e\xf7\xe9\xd0\xa9"
-			"\x0c\x32\x4b\xb5\x49\x28\xab\x85"
-			"\x2f\x8e\x01\x36\x38\x52\xd0\xba"
-			"\xd6\x02\x78\xf8\x0e\x3e\x9c\x8b"
-			"\x6b\x45\x99\x3f\x5c\xfe\x58\xf1"
-			"\x5c\x94\x04\xe1\xf5\x18\x6d\x51"
-			"\xb2\x5d\x18\x20\xb6\xc2\x9a\x42"
-			"\x1d\xb3\xab\x3c\xb6\x3a\x13\x03"
-			"\xb2\x46\x82\x4f\xfc\x64\xbc\x4f"
-			"\xca\xfa\x9c\xc0\xd5\xa7\xbd\x11"
-			"\xb7\xe4\x5a\xf6\x6f\x4d\x4d\x54"
-			"\xea\xa4\x98\x66\xd4\x22\x3b\xd3"
-			"\x8f\x34\x47\xd9\x7c\xf4\x72\x3b"
-			"\x4d\x02\x77\xf6\xd6\xdd\x08\x0a"
-			"\x81\xe1\x86\x89\x3e\x56\x10\x3c"
-			"\xba\xd7\x81\x8c\x08\xbc\x8b\xe2"
-			"\x53\xec\xa7\x89\xee\xc8\x56\xb5"
-			"\x36\x2c\xb2\x03\xba\x99\xdd\x7c"
-			"\x48\xa0\xb0\xbc\x91\x33\xe9\xa8"
-			"\xcb\xcd\xcf\x59\x5f\x1f\x15\xe2"
-			"\x56\xf5\x4e\x01\x35\x27\x45\x77"
-			"\x47\xc8\xbc\xcb\x7e\x39\xc1\x97"
-			"\x28\xd3\x84\xfc\x2c\x3e\xc8\xad"
-			"\x9c\xf8\x8a\x61\x9c\x28\xaa\xc5"
-			"\x99\x20\x43\x85\x9d\xa5\xe2\x8b"
-			"\xb8\xae\xeb\xd0\x32\x0d\x52\x78"
-			"\x09\x56\x3f\xc7\xd8\x7e\x26\xfc"
-			"\x37\xfb\x6f\x04\xfc\xfa\x92\x10"
-			"\xac\xf8\x3e\x21\xdc\x8c\x21\x16"
-			"\x7d\x67\x6e\xf6\xcd\xda\xb6\x98"
-			"\x23\xab\x23\x3c\xb2\x10\xa0\x53"
-			"\x5a\x56\x9f\xc5\xd0\xff\xbb\xe4"
-			"\x98\x3c\x69\x1e\xdb\x38\x8f\x7e"
-			"\x0f\xd2\x98\x88\x81\x8b\x45\x67"
-			"\xea\x33\xf1\xeb\xe9\x97\x55\x2e"
-			"\xd9\xaa\xeb\x5a\xec\xda\xe1\x68"
-			"\xa8\x9d\x3c\x84\x7c\x05\x3d\x62"
-			"\x87\x8f\x03\x21\x28\x95\x0c\x89"
-			"\x25\x22\x4a\xb0\x93\xa9\x50\xa2"
-			"\x2f\x57\x6e\x18\x42\x19\x54\x0c"
-			"\x55\x67\xc6\x11\x49\xf4\x5c\xd2"
-			"\xe9\x3d\xdd\x8b\x48\x71\x21\x00"
-			"\xc3\x9a\x6c\x85\x74\x28\x83\x4a"
-			"\x1b\x31\x05\xe1\x06\x92\xe7\xda"
-			"\x85\x73\x78\x45\x20\x7f\xae\x13"
-			"\x7c\x33\x06\x22\xf4\x83\xf9\x35"
-			"\x3f\x6c\x71\xa8\x4e\x48\xbe\x9b"
-			"\xce\x8a\xba\xda\xbe\x28\x08\xf7"
-			"\xe2\x14\x8c\x71\xea\x72\xf9\x33"
-			"\xf2\x88\x3f\xd7\xbb\x69\x6c\x29"
-			"\x19\xdc\x84\xce\x1f\x12\x4f\xc8"
-			"\xaf\xa5\x04\xba\x5a\xab\xb0\xd9"
-			"\x14\x1f\x6c\x68\x98\x39\x89\x7a"
-			"\xd9\xd8\x2f\xdf\xa8\x47\x4a\x25"
-			"\xe2\xfb\x33\xf4\x59\x78\xe1\x68"
-			"\x85\xcf\xfe\x59\x20\xd4\x05\x1d"
-			"\x80\x99\xae\xbc\xca\xae\x0f\x2f"
-			"\x65\x43\x34\x8e\x7e\xac\xd3\x93"
-			"\x2f\xac\x6d\x14\x3d\x02\x07\x70"
-			"\x9d\xa4\xf3\x1b\x5c\x36\xfc\x01"
-			"\x73\x34\x85\x0c\x6c\xd6\xf1\xbd"
-			"\x3f\xdf\xee\xf5\xd9\xba\x56\xef"
-			"\xf4\x9b\x6b\xee\x9f\x5a\x78\x6d"
-			"\x32\x19\xf4\xf7\xf8\x4c\x69\x0b"
-			"\x4b\xbc\xbb\xb7\xf2\x85\xaf\x70"
-			"\x75\x24\x6c\x54\xa7\x0e\x4d\x1d"
-			"\x01\xbf\x08\xac\xcf\x7f\x2c\xe3"
-			"\x14\x89\x5e\x70\x5a\x99\x92\xcd"
-			"\x01\x84\xc8\xd2\xab\xe5\x4f\x58"
-			"\xe7\x0f\x2f\x0e\xff\x68\xea\xfd"
-			"\x15\xb3\x17\xe6\xb0\xe7\x85\xd8"
-			"\x23\x2e\x05\xc7\xc9\xc4\x46\x1f"
-			"\xe1\x9e\x49\x20\x23\x24\x4d\x7e"
-			"\x29\x65\xff\xf4\xb6\xfd\x1a\x85"
-			"\xc4\x16\xec\xfc\xea\x7b\xd6\x2c"
-			"\x43\xf8\xb7\xbf\x79\xc0\x85\xcd"
-			"\xef\xe1\x98\xd3\xa5\xf7\x90\x8c"
-			"\xe9\x7f\x80\x6b\xd2\xac\x4c\x30"
-			"\xa7\xc6\x61\x6c\xd2\xf9\x2c\xff"
-			"\x30\xbc\x22\x81\x7d\x93\x12\xe4"
-			"\x0a\xcd\xaf\xdd\xe8\xab\x0a\x1e"
-			"\x13\xa4\x27\xc3\x5f\xf7\x4b\xbb"
-			"\x37\x09\x4b\x91\x6f\x92\x4f\xaf"
-			"\x52\xee\xdf\xef\x09\x6f\xf7\x5c"
-			"\x6e\x12\x17\x72\x63\x57\xc7\xba"
-			"\x3b\x6b\x38\x32\x73\x1b\x9c\x80"
-			"\xc1\x7a\xc6\xcf\xcd\x35\xc0\x6b"
-			"\x31\x1a\x6b\xe9\xd8\x2c\x29\x3f"
-			"\x96\xfb\xb6\xcd\x13\x91\x3b\xc2"
-			"\xd2\xa3\x31\x8d\xa4\xcd\x57\xcd"
-			"\x13\x3d\x64\xfd\x06\xce\xe6\xdc"
-			"\x0c\x24\x43\x31\x40\x57\xf1\x72"
-			"\x17\xe3\x3a\x63\x6d\x35\xcf\x5d"
-			"\x97\x40\x59\xdd\xf7\x3c\x02\xf7"
-			"\x1c\x7e\x05\xbb\xa9\x0d\x01\xb1"
-			"\x8e\xc0\x30\xa9\x53\x24\xc9\x89"
-			"\x84\x6d\xaa\xd0\xcd\x91\xc2\x4d"
-			"\x91\xb0\x89\xe2\xbf\x83\x44\xaa"
-			"\x28\x72\x23\xa0\xc2\xad\xad\x1c"
-			"\xfc\x3f\x09\x7a\x0b\xdc\xc5\x1b"
-			"\x87\x13\xc6\x5b\x59\x8d\xf2\xc8"
-			"\xaf\xdf\x11\x95",
-		.rlen = 4100,
-	},
-};
-
-/*
- * CTS (Cipher Text Stealing) mode tests
- */
-#define CTS_MODE_ENC_TEST_VECTORS 6
-#define CTS_MODE_DEC_TEST_VECTORS 6
-static struct cipher_testvec cts_mode_enc_tv_template[] = {
-	{ /* from rfc3962 */
-		.klen	= 16,
-		.key    = "\x63\x68\x69\x63\x6b\x65\x6e\x20"
-			  "\x74\x65\x72\x69\x79\x61\x6b\x69",
-		.ilen	= 17,
-		.input  = "\x49\x20\x77\x6f\x75\x6c\x64\x20"
-			  "\x6c\x69\x6b\x65\x20\x74\x68\x65"
-			  "\x20",
-		.rlen	= 17,
-		.result	= "\xc6\x35\x35\x68\xf2\xbf\x8c\xb4"
-			  "\xd8\xa5\x80\x36\x2d\xa7\xff\x7f"
-			  "\x97",
-	}, {
-		.klen	= 16,
-		.key    = "\x63\x68\x69\x63\x6b\x65\x6e\x20"
-			  "\x74\x65\x72\x69\x79\x61\x6b\x69",
-		.ilen   = 31,
-		.input  = "\x49\x20\x77\x6f\x75\x6c\x64\x20"
-			  "\x6c\x69\x6b\x65\x20\x74\x68\x65"
-			  "\x20\x47\x65\x6e\x65\x72\x61\x6c"
-			  "\x20\x47\x61\x75\x27\x73\x20",
-		.rlen   = 31,
-		.result = "\xfc\x00\x78\x3e\x0e\xfd\xb2\xc1"
-			  "\xd4\x45\xd4\xc8\xef\xf7\xed\x22"
-			  "\x97\x68\x72\x68\xd6\xec\xcc\xc0"
-			  "\xc0\x7b\x25\xe2\x5e\xcf\xe5",
-	}, {
-		.klen	= 16,
-		.key    = "\x63\x68\x69\x63\x6b\x65\x6e\x20"
-			  "\x74\x65\x72\x69\x79\x61\x6b\x69",
-		.ilen   = 32,
-		.input  = "\x49\x20\x77\x6f\x75\x6c\x64\x20"
-			  "\x6c\x69\x6b\x65\x20\x74\x68\x65"
-			  "\x20\x47\x65\x6e\x65\x72\x61\x6c"
-			  "\x20\x47\x61\x75\x27\x73\x20\x43",
-		.rlen   = 32,
-		.result = "\x39\x31\x25\x23\xa7\x86\x62\xd5"
-			  "\xbe\x7f\xcb\xcc\x98\xeb\xf5\xa8"
-			  "\x97\x68\x72\x68\xd6\xec\xcc\xc0"
-			  "\xc0\x7b\x25\xe2\x5e\xcf\xe5\x84",
-	}, {
-		.klen	= 16,
-		.key    = "\x63\x68\x69\x63\x6b\x65\x6e\x20"
-			  "\x74\x65\x72\x69\x79\x61\x6b\x69",
-		.ilen   = 47,
-		.input  = "\x49\x20\x77\x6f\x75\x6c\x64\x20"
-			  "\x6c\x69\x6b\x65\x20\x74\x68\x65"
-			  "\x20\x47\x65\x6e\x65\x72\x61\x6c"
-			  "\x20\x47\x61\x75\x27\x73\x20\x43"
-			  "\x68\x69\x63\x6b\x65\x6e\x2c\x20"
-			  "\x70\x6c\x65\x61\x73\x65\x2c",
-		.rlen   = 47,
-		.result = "\x97\x68\x72\x68\xd6\xec\xcc\xc0"
-			  "\xc0\x7b\x25\xe2\x5e\xcf\xe5\x84"
-			  "\xb3\xff\xfd\x94\x0c\x16\xa1\x8c"
-			  "\x1b\x55\x49\xd2\xf8\x38\x02\x9e"
-			  "\x39\x31\x25\x23\xa7\x86\x62\xd5"
-			  "\xbe\x7f\xcb\xcc\x98\xeb\xf5",
-	}, {
-		.klen	= 16,
-		.key    = "\x63\x68\x69\x63\x6b\x65\x6e\x20"
-			  "\x74\x65\x72\x69\x79\x61\x6b\x69",
-		.ilen   = 48,
-		.input  = "\x49\x20\x77\x6f\x75\x6c\x64\x20"
-			  "\x6c\x69\x6b\x65\x20\x74\x68\x65"
-			  "\x20\x47\x65\x6e\x65\x72\x61\x6c"
-			  "\x20\x47\x61\x75\x27\x73\x20\x43"
-			  "\x68\x69\x63\x6b\x65\x6e\x2c\x20"
-			  "\x70\x6c\x65\x61\x73\x65\x2c\x20",
-		.rlen   = 48,
-		.result = "\x97\x68\x72\x68\xd6\xec\xcc\xc0"
-			  "\xc0\x7b\x25\xe2\x5e\xcf\xe5\x84"
-			  "\x9d\xad\x8b\xbb\x96\xc4\xcd\xc0"
-			  "\x3b\xc1\x03\xe1\xa1\x94\xbb\xd8"
-			  "\x39\x31\x25\x23\xa7\x86\x62\xd5"
-			  "\xbe\x7f\xcb\xcc\x98\xeb\xf5\xa8",
-	}, {
-		.klen	= 16,
-		.key    = "\x63\x68\x69\x63\x6b\x65\x6e\x20"
-			  "\x74\x65\x72\x69\x79\x61\x6b\x69",
-		.ilen   = 64,
-		.input  = "\x49\x20\x77\x6f\x75\x6c\x64\x20"
-			  "\x6c\x69\x6b\x65\x20\x74\x68\x65"
-			  "\x20\x47\x65\x6e\x65\x72\x61\x6c"
-			  "\x20\x47\x61\x75\x27\x73\x20\x43"
-			  "\x68\x69\x63\x6b\x65\x6e\x2c\x20"
-			  "\x70\x6c\x65\x61\x73\x65\x2c\x20"
-			  "\x61\x6e\x64\x20\x77\x6f\x6e\x74"
-			  "\x6f\x6e\x20\x73\x6f\x75\x70\x2e",
-		.rlen   = 64,
-		.result = "\x97\x68\x72\x68\xd6\xec\xcc\xc0"
-			  "\xc0\x7b\x25\xe2\x5e\xcf\xe5\x84"
-			  "\x39\x31\x25\x23\xa7\x86\x62\xd5"
-			  "\xbe\x7f\xcb\xcc\x98\xeb\xf5\xa8"
-			  "\x48\x07\xef\xe8\x36\xee\x89\xa5"
-			  "\x26\x73\x0d\xbc\x2f\x7b\xc8\x40"
-			  "\x9d\xad\x8b\xbb\x96\xc4\xcd\xc0"
-			  "\x3b\xc1\x03\xe1\xa1\x94\xbb\xd8",
-	}
-};
-
-static struct cipher_testvec cts_mode_dec_tv_template[] = {
-	{ /* from rfc3962 */
-		.klen	= 16,
-		.key    = "\x63\x68\x69\x63\x6b\x65\x6e\x20"
-			  "\x74\x65\x72\x69\x79\x61\x6b\x69",
-		.rlen	= 17,
-		.result = "\x49\x20\x77\x6f\x75\x6c\x64\x20"
-			  "\x6c\x69\x6b\x65\x20\x74\x68\x65"
-			  "\x20",
-		.ilen	= 17,
-		.input	= "\xc6\x35\x35\x68\xf2\xbf\x8c\xb4"
-			  "\xd8\xa5\x80\x36\x2d\xa7\xff\x7f"
-			  "\x97",
-	}, {
-		.klen	= 16,
-		.key    = "\x63\x68\x69\x63\x6b\x65\x6e\x20"
-			  "\x74\x65\x72\x69\x79\x61\x6b\x69",
-		.rlen   = 31,
-		.result = "\x49\x20\x77\x6f\x75\x6c\x64\x20"
-			  "\x6c\x69\x6b\x65\x20\x74\x68\x65"
-			  "\x20\x47\x65\x6e\x65\x72\x61\x6c"
-			  "\x20\x47\x61\x75\x27\x73\x20",
-		.ilen   = 31,
-		.input  = "\xfc\x00\x78\x3e\x0e\xfd\xb2\xc1"
-			  "\xd4\x45\xd4\xc8\xef\xf7\xed\x22"
-			  "\x97\x68\x72\x68\xd6\xec\xcc\xc0"
-			  "\xc0\x7b\x25\xe2\x5e\xcf\xe5",
-	}, {
-		.klen	= 16,
-		.key    = "\x63\x68\x69\x63\x6b\x65\x6e\x20"
-			  "\x74\x65\x72\x69\x79\x61\x6b\x69",
-		.rlen   = 32,
-		.result = "\x49\x20\x77\x6f\x75\x6c\x64\x20"
-			  "\x6c\x69\x6b\x65\x20\x74\x68\x65"
-			  "\x20\x47\x65\x6e\x65\x72\x61\x6c"
-			  "\x20\x47\x61\x75\x27\x73\x20\x43",
-		.ilen   = 32,
-		.input  = "\x39\x31\x25\x23\xa7\x86\x62\xd5"
-			  "\xbe\x7f\xcb\xcc\x98\xeb\xf5\xa8"
-			  "\x97\x68\x72\x68\xd6\xec\xcc\xc0"
-			  "\xc0\x7b\x25\xe2\x5e\xcf\xe5\x84",
-	}, {
-		.klen	= 16,
-		.key    = "\x63\x68\x69\x63\x6b\x65\x6e\x20"
-			  "\x74\x65\x72\x69\x79\x61\x6b\x69",
-		.rlen   = 47,
-		.result = "\x49\x20\x77\x6f\x75\x6c\x64\x20"
-			  "\x6c\x69\x6b\x65\x20\x74\x68\x65"
-			  "\x20\x47\x65\x6e\x65\x72\x61\x6c"
-			  "\x20\x47\x61\x75\x27\x73\x20\x43"
-			  "\x68\x69\x63\x6b\x65\x6e\x2c\x20"
-			  "\x70\x6c\x65\x61\x73\x65\x2c",
-		.ilen   = 47,
-		.input  = "\x97\x68\x72\x68\xd6\xec\xcc\xc0"
-			  "\xc0\x7b\x25\xe2\x5e\xcf\xe5\x84"
-			  "\xb3\xff\xfd\x94\x0c\x16\xa1\x8c"
-			  "\x1b\x55\x49\xd2\xf8\x38\x02\x9e"
-			  "\x39\x31\x25\x23\xa7\x86\x62\xd5"
-			  "\xbe\x7f\xcb\xcc\x98\xeb\xf5",
-	}, {
-		.klen	= 16,
-		.key    = "\x63\x68\x69\x63\x6b\x65\x6e\x20"
-			  "\x74\x65\x72\x69\x79\x61\x6b\x69",
-		.rlen   = 48,
-		.result = "\x49\x20\x77\x6f\x75\x6c\x64\x20"
-			  "\x6c\x69\x6b\x65\x20\x74\x68\x65"
-			  "\x20\x47\x65\x6e\x65\x72\x61\x6c"
-			  "\x20\x47\x61\x75\x27\x73\x20\x43"
-			  "\x68\x69\x63\x6b\x65\x6e\x2c\x20"
-			  "\x70\x6c\x65\x61\x73\x65\x2c\x20",
-		.ilen   = 48,
-		.input  = "\x97\x68\x72\x68\xd6\xec\xcc\xc0"
-			  "\xc0\x7b\x25\xe2\x5e\xcf\xe5\x84"
-			  "\x9d\xad\x8b\xbb\x96\xc4\xcd\xc0"
-			  "\x3b\xc1\x03\xe1\xa1\x94\xbb\xd8"
-			  "\x39\x31\x25\x23\xa7\x86\x62\xd5"
-			  "\xbe\x7f\xcb\xcc\x98\xeb\xf5\xa8",
-	}, {
-		.klen	= 16,
-		.key    = "\x63\x68\x69\x63\x6b\x65\x6e\x20"
-			  "\x74\x65\x72\x69\x79\x61\x6b\x69",
-		.rlen   = 64,
-		.result = "\x49\x20\x77\x6f\x75\x6c\x64\x20"
-			  "\x6c\x69\x6b\x65\x20\x74\x68\x65"
-			  "\x20\x47\x65\x6e\x65\x72\x61\x6c"
-			  "\x20\x47\x61\x75\x27\x73\x20\x43"
-			  "\x68\x69\x63\x6b\x65\x6e\x2c\x20"
-			  "\x70\x6c\x65\x61\x73\x65\x2c\x20"
-			  "\x61\x6e\x64\x20\x77\x6f\x6e\x74"
-			  "\x6f\x6e\x20\x73\x6f\x75\x70\x2e",
-		.ilen   = 64,
-		.input  = "\x97\x68\x72\x68\xd6\xec\xcc\xc0"
-			  "\xc0\x7b\x25\xe2\x5e\xcf\xe5\x84"
-			  "\x39\x31\x25\x23\xa7\x86\x62\xd5"
-			  "\xbe\x7f\xcb\xcc\x98\xeb\xf5\xa8"
-			  "\x48\x07\xef\xe8\x36\xee\x89\xa5"
-			  "\x26\x73\x0d\xbc\x2f\x7b\xc8\x40"
-			  "\x9d\xad\x8b\xbb\x96\xc4\xcd\xc0"
-			  "\x3b\xc1\x03\xe1\xa1\x94\xbb\xd8",
-	}
-};
-
-/*
- * Compression stuff.
- */
-#define COMP_BUF_SIZE           512
-
-struct comp_testvec {
-	int inlen, outlen;
-	char input[COMP_BUF_SIZE];
-	char output[COMP_BUF_SIZE];
-};
-
-/*
- * Deflate test vectors (null-terminated strings).
- * Params: winbits=11, Z_DEFAULT_COMPRESSION, MAX_MEM_LEVEL.
- */
-#define DEFLATE_COMP_TEST_VECTORS 2
-#define DEFLATE_DECOMP_TEST_VECTORS 2
-
-static struct comp_testvec deflate_comp_tv_template[] = {
-	{
-		.inlen	= 70,
-		.outlen	= 38,
-		.input	= "Join us now and share the software "
-			"Join us now and share the software ",
-		.output	= "\xf3\xca\xcf\xcc\x53\x28\x2d\x56"
-			  "\xc8\xcb\x2f\x57\x48\xcc\x4b\x51"
-			  "\x28\xce\x48\x2c\x4a\x55\x28\xc9"
-			  "\x48\x55\x28\xce\x4f\x2b\x29\x07"
-			  "\x71\xbc\x08\x2b\x01\x00",
-	}, {
-		.inlen	= 191,
-		.outlen	= 122,
-		.input	= "This document describes a compression method based on the DEFLATE"
-			"compression algorithm.  This document defines the application of "
-			"the DEFLATE algorithm to the IP Payload Compression Protocol.",
-		.output	= "\x5d\x8d\x31\x0e\xc2\x30\x10\x04"
-			  "\xbf\xb2\x2f\xc8\x1f\x10\x04\x09"
-			  "\x89\xc2\x85\x3f\x70\xb1\x2f\xf8"
-			  "\x24\xdb\x67\xd9\x47\xc1\xef\x49"
-			  "\x68\x12\x51\xae\x76\x67\xd6\x27"
-			  "\x19\x88\x1a\xde\x85\xab\x21\xf2"
-			  "\x08\x5d\x16\x1e\x20\x04\x2d\xad"
-			  "\xf3\x18\xa2\x15\x85\x2d\x69\xc4"
-			  "\x42\x83\x23\xb6\x6c\x89\x71\x9b"
-			  "\xef\xcf\x8b\x9f\xcf\x33\xca\x2f"
-			  "\xed\x62\xa9\x4c\x80\xff\x13\xaf"
-			  "\x52\x37\xed\x0e\x52\x6b\x59\x02"
-			  "\xd9\x4e\xe8\x7a\x76\x1d\x02\x98"
-			  "\xfe\x8a\x87\x83\xa3\x4f\x56\x8a"
-			  "\xb8\x9e\x8e\x5c\x57\xd3\xa0\x79"
-			  "\xfa\x02",
-	},
-};
-
-static struct comp_testvec deflate_decomp_tv_template[] = {
-	{
-		.inlen	= 122,
-		.outlen	= 191,
-		.input	= "\x5d\x8d\x31\x0e\xc2\x30\x10\x04"
-			  "\xbf\xb2\x2f\xc8\x1f\x10\x04\x09"
-			  "\x89\xc2\x85\x3f\x70\xb1\x2f\xf8"
-			  "\x24\xdb\x67\xd9\x47\xc1\xef\x49"
-			  "\x68\x12\x51\xae\x76\x67\xd6\x27"
-			  "\x19\x88\x1a\xde\x85\xab\x21\xf2"
-			  "\x08\x5d\x16\x1e\x20\x04\x2d\xad"
-			  "\xf3\x18\xa2\x15\x85\x2d\x69\xc4"
-			  "\x42\x83\x23\xb6\x6c\x89\x71\x9b"
-			  "\xef\xcf\x8b\x9f\xcf\x33\xca\x2f"
-			  "\xed\x62\xa9\x4c\x80\xff\x13\xaf"
-			  "\x52\x37\xed\x0e\x52\x6b\x59\x02"
-			  "\xd9\x4e\xe8\x7a\x76\x1d\x02\x98"
-			  "\xfe\x8a\x87\x83\xa3\x4f\x56\x8a"
-			  "\xb8\x9e\x8e\x5c\x57\xd3\xa0\x79"
-			  "\xfa\x02",
-		.output	= "This document describes a compression method based on the DEFLATE"
-			"compression algorithm.  This document defines the application of "
-			"the DEFLATE algorithm to the IP Payload Compression Protocol.",
-	}, {
-		.inlen	= 38,
-		.outlen	= 70,
-		.input	= "\xf3\xca\xcf\xcc\x53\x28\x2d\x56"
-			  "\xc8\xcb\x2f\x57\x48\xcc\x4b\x51"
-			  "\x28\xce\x48\x2c\x4a\x55\x28\xc9"
-			  "\x48\x55\x28\xce\x4f\x2b\x29\x07"
-			  "\x71\xbc\x08\x2b\x01\x00",
-		.output	= "Join us now and share the software "
-			"Join us now and share the software ",
-	},
-};
-
-/*
- * LZO test vectors (null-terminated strings).
- */
-#define LZO_COMP_TEST_VECTORS 2
-#define LZO_DECOMP_TEST_VECTORS 2
-
-static struct comp_testvec lzo_comp_tv_template[] = {
-	{
-		.inlen	= 70,
-		.outlen	= 46,
-		.input	= "Join us now and share the software "
-			"Join us now and share the software ",
-		.output	= "\x00\x0d\x4a\x6f\x69\x6e\x20\x75"
-			"\x73\x20\x6e\x6f\x77\x20\x61\x6e"
-			"\x64\x20\x73\x68\x61\x72\x65\x20"
-			"\x74\x68\x65\x20\x73\x6f\x66\x74"
-			"\x77\x70\x01\x01\x4a\x6f\x69\x6e"
-			"\x3d\x88\x00\x11\x00\x00",
-	}, {
-		.inlen	= 159,
-		.outlen	= 133,
-		.input	= "This document describes a compression method based on the LZO "
-			"compression algorithm.  This document defines the application of "
-			"the LZO algorithm used in UBIFS.",
-		.output	= "\x00\x2b\x54\x68\x69\x73\x20\x64"
-			  "\x6f\x63\x75\x6d\x65\x6e\x74\x20"
-			  "\x64\x65\x73\x63\x72\x69\x62\x65"
-			  "\x73\x20\x61\x20\x63\x6f\x6d\x70"
-			  "\x72\x65\x73\x73\x69\x6f\x6e\x20"
-			  "\x6d\x65\x74\x68\x6f\x64\x20\x62"
-			  "\x61\x73\x65\x64\x20\x6f\x6e\x20"
-			  "\x74\x68\x65\x20\x4c\x5a\x4f\x2b"
-			  "\x8c\x00\x0d\x61\x6c\x67\x6f\x72"
-			  "\x69\x74\x68\x6d\x2e\x20\x20\x54"
-			  "\x68\x69\x73\x2a\x54\x01\x02\x66"
-			  "\x69\x6e\x65\x73\x94\x06\x05\x61"
-			  "\x70\x70\x6c\x69\x63\x61\x74\x76"
-			  "\x0a\x6f\x66\x88\x02\x60\x09\x27"
-			  "\xf0\x00\x0c\x20\x75\x73\x65\x64"
-			  "\x20\x69\x6e\x20\x55\x42\x49\x46"
-			  "\x53\x2e\x11\x00\x00",
-	},
-};
-
-static struct comp_testvec lzo_decomp_tv_template[] = {
-	{
-		.inlen	= 133,
-		.outlen	= 159,
-		.input	= "\x00\x2b\x54\x68\x69\x73\x20\x64"
-			  "\x6f\x63\x75\x6d\x65\x6e\x74\x20"
-			  "\x64\x65\x73\x63\x72\x69\x62\x65"
-			  "\x73\x20\x61\x20\x63\x6f\x6d\x70"
-			  "\x72\x65\x73\x73\x69\x6f\x6e\x20"
-			  "\x6d\x65\x74\x68\x6f\x64\x20\x62"
-			  "\x61\x73\x65\x64\x20\x6f\x6e\x20"
-			  "\x74\x68\x65\x20\x4c\x5a\x4f\x2b"
-			  "\x8c\x00\x0d\x61\x6c\x67\x6f\x72"
-			  "\x69\x74\x68\x6d\x2e\x20\x20\x54"
-			  "\x68\x69\x73\x2a\x54\x01\x02\x66"
-			  "\x69\x6e\x65\x73\x94\x06\x05\x61"
-			  "\x70\x70\x6c\x69\x63\x61\x74\x76"
-			  "\x0a\x6f\x66\x88\x02\x60\x09\x27"
-			  "\xf0\x00\x0c\x20\x75\x73\x65\x64"
-			  "\x20\x69\x6e\x20\x55\x42\x49\x46"
-			  "\x53\x2e\x11\x00\x00",
-		.output	= "This document describes a compression method based on the LZO "
-			"compression algorithm.  This document defines the application of "
-			"the LZO algorithm used in UBIFS.",
-	}, {
-		.inlen	= 46,
-		.outlen	= 70,
-		.input	= "\x00\x0d\x4a\x6f\x69\x6e\x20\x75"
-			  "\x73\x20\x6e\x6f\x77\x20\x61\x6e"
-			  "\x64\x20\x73\x68\x61\x72\x65\x20"
-			  "\x74\x68\x65\x20\x73\x6f\x66\x74"
-			  "\x77\x70\x01\x01\x4a\x6f\x69\x6e"
-			  "\x3d\x88\x00\x11\x00\x00",
-		.output	= "Join us now and share the software "
-			"Join us now and share the software ",
-	},
-};
-
-/*
- * Michael MIC test vectors from IEEE 802.11i
- */
-#define MICHAEL_MIC_TEST_VECTORS 6
-
-static struct hash_testvec michael_mic_tv_template[] = {
-	{
-		.key = "\x00\x00\x00\x00\x00\x00\x00\x00",
-		.ksize = 8,
-		.plaintext = zeroed_string,
-		.psize = 0,
-		.digest = "\x82\x92\x5c\x1c\xa1\xd1\x30\xb8",
-	},
-	{
-		.key = "\x82\x92\x5c\x1c\xa1\xd1\x30\xb8",
-		.ksize = 8,
-		.plaintext = "M",
-		.psize = 1,
-		.digest = "\x43\x47\x21\xca\x40\x63\x9b\x3f",
-	},
-	{
-		.key = "\x43\x47\x21\xca\x40\x63\x9b\x3f",
-		.ksize = 8,
-		.plaintext = "Mi",
-		.psize = 2,
-		.digest = "\xe8\xf9\xbe\xca\xe9\x7e\x5d\x29",
-	},
-	{
-		.key = "\xe8\xf9\xbe\xca\xe9\x7e\x5d\x29",
-		.ksize = 8,
-		.plaintext = "Mic",
-		.psize = 3,
-		.digest = "\x90\x03\x8f\xc6\xcf\x13\xc1\xdb",
-	},
-	{
-		.key = "\x90\x03\x8f\xc6\xcf\x13\xc1\xdb",
-		.ksize = 8,
-		.plaintext = "Mich",
-		.psize = 4,
-		.digest = "\xd5\x5e\x10\x05\x10\x12\x89\x86",
-	},
-	{
-		.key = "\xd5\x5e\x10\x05\x10\x12\x89\x86",
-		.ksize = 8,
-		.plaintext = "Michael",
-		.psize = 7,
-		.digest = "\x0a\x94\x2b\x12\x4e\xca\xa5\x46",
-	}
-};
-
-/*
- * CRC32C test vectors
- */
-#define CRC32C_TEST_VECTORS 14
-
-static struct hash_testvec crc32c_tv_template[] = {
-	{
-		.psize = 0,
-		.digest = "\x00\x00\x00\x00",
-	},
-	{
-		.key = "\x87\xa9\xcb\xed",
-		.ksize = 4,
-		.psize = 0,
-		.digest = "\x78\x56\x34\x12",
-	},
-	{
-		.key = "\xff\xff\xff\xff",
-		.ksize = 4,
-		.plaintext = "\x01\x02\x03\x04\x05\x06\x07\x08"
-			     "\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10"
-			     "\x11\x12\x13\x14\x15\x16\x17\x18"
-			     "\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20"
-			     "\x21\x22\x23\x24\x25\x26\x27\x28",
-		.psize = 40,
-		.digest = "\x7f\x15\x2c\x0e",
-	},
-	{
-		.key = "\xff\xff\xff\xff",
-		.ksize = 4,
-		.plaintext = "\x29\x2a\x2b\x2c\x2d\x2e\x2f\x30"
-			     "\x31\x32\x33\x34\x35\x36\x37\x38"
-			     "\x39\x3a\x3b\x3c\x3d\x3e\x3f\x40"
-			     "\x41\x42\x43\x44\x45\x46\x47\x48"
-			     "\x49\x4a\x4b\x4c\x4d\x4e\x4f\x50",
-		.psize = 40,
-		.digest = "\xf6\xeb\x80\xe9",
-	},
-	{
-		.key = "\xff\xff\xff\xff",
-		.ksize = 4,
-		.plaintext = "\x51\x52\x53\x54\x55\x56\x57\x58"
-			     "\x59\x5a\x5b\x5c\x5d\x5e\x5f\x60"
-			     "\x61\x62\x63\x64\x65\x66\x67\x68"
-			     "\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70"
-			     "\x71\x72\x73\x74\x75\x76\x77\x78",
-		.psize = 40,
-		.digest = "\xed\xbd\x74\xde",
-	},
-	{
-		.key = "\xff\xff\xff\xff",
-		.ksize = 4,
-		.plaintext = "\x79\x7a\x7b\x7c\x7d\x7e\x7f\x80"
-			     "\x81\x82\x83\x84\x85\x86\x87\x88"
-			     "\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90"
-			     "\x91\x92\x93\x94\x95\x96\x97\x98"
-			     "\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0",
-		.psize = 40,
-		.digest = "\x62\xc8\x79\xd5",
-	},
-	{
-		.key = "\xff\xff\xff\xff",
-		.ksize = 4,
-		.plaintext = "\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8"
-			     "\xa9\xaa\xab\xac\xad\xae\xaf\xb0"
-			     "\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8"
-			     "\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0"
-			     "\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8",
-		.psize = 40,
-		.digest = "\xd0\x9a\x97\xba",
-	},
-	{
-		.key = "\xff\xff\xff\xff",
-		.ksize = 4,
-		.plaintext = "\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0"
-			     "\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8"
-			     "\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0"
-			     "\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8"
-			     "\xe9\xea\xeb\xec\xed\xee\xef\xf0",
-		.psize = 40,
-		.digest = "\x13\xd9\x29\x2b",
-	},
-	{
-		.key = "\x80\xea\xd3\xf1",
-		.ksize = 4,
-		.plaintext = "\x29\x2a\x2b\x2c\x2d\x2e\x2f\x30"
-			     "\x31\x32\x33\x34\x35\x36\x37\x38"
-			     "\x39\x3a\x3b\x3c\x3d\x3e\x3f\x40"
-			     "\x41\x42\x43\x44\x45\x46\x47\x48"
-			     "\x49\x4a\x4b\x4c\x4d\x4e\x4f\x50",
-		.psize = 40,
-		.digest = "\x0c\xb5\xe2\xa2",
-	},
-	{
-		.key = "\xf3\x4a\x1d\x5d",
-		.ksize = 4,
-		.plaintext = "\x51\x52\x53\x54\x55\x56\x57\x58"
-			     "\x59\x5a\x5b\x5c\x5d\x5e\x5f\x60"
-			     "\x61\x62\x63\x64\x65\x66\x67\x68"
-			     "\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70"
-			     "\x71\x72\x73\x74\x75\x76\x77\x78",
-		.psize = 40,
-		.digest = "\xd1\x7f\xfb\xa6",
-	},
-	{
-		.key = "\x2e\x80\x04\x59",
-		.ksize = 4,
-		.plaintext = "\x79\x7a\x7b\x7c\x7d\x7e\x7f\x80"
-			     "\x81\x82\x83\x84\x85\x86\x87\x88"
-			     "\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90"
-			     "\x91\x92\x93\x94\x95\x96\x97\x98"
-			     "\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0",
-		.psize = 40,
-		.digest = "\x59\x33\xe6\x7a",
-	},
-	{
-		.key = "\xa6\xcc\x19\x85",
-		.ksize = 4,
-		.plaintext = "\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8"
-			     "\xa9\xaa\xab\xac\xad\xae\xaf\xb0"
-			     "\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8"
-			     "\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0"
-			     "\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8",
-		.psize = 40,
-		.digest = "\xbe\x03\x01\xd2",
-	},
-	{
-		.key = "\x41\xfc\xfe\x2d",
-		.ksize = 4,
-		.plaintext = "\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0"
-			     "\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8"
-			     "\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0"
-			     "\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8"
-			     "\xe9\xea\xeb\xec\xed\xee\xef\xf0",
-		.psize = 40,
-		.digest = "\x75\xd3\xc5\x24",
-	},
-	{
-		.key = "\xff\xff\xff\xff",
-		.ksize = 4,
-		.plaintext = "\x01\x02\x03\x04\x05\x06\x07\x08"
-			     "\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10"
-			     "\x11\x12\x13\x14\x15\x16\x17\x18"
-			     "\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20"
-			     "\x21\x22\x23\x24\x25\x26\x27\x28"
-			     "\x29\x2a\x2b\x2c\x2d\x2e\x2f\x30"
-			     "\x31\x32\x33\x34\x35\x36\x37\x38"
-			     "\x39\x3a\x3b\x3c\x3d\x3e\x3f\x40"
-			     "\x41\x42\x43\x44\x45\x46\x47\x48"
-			     "\x49\x4a\x4b\x4c\x4d\x4e\x4f\x50"
-			     "\x51\x52\x53\x54\x55\x56\x57\x58"
-			     "\x59\x5a\x5b\x5c\x5d\x5e\x5f\x60"
-			     "\x61\x62\x63\x64\x65\x66\x67\x68"
-			     "\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70"
-			     "\x71\x72\x73\x74\x75\x76\x77\x78"
-			     "\x79\x7a\x7b\x7c\x7d\x7e\x7f\x80"
-			     "\x81\x82\x83\x84\x85\x86\x87\x88"
-			     "\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90"
-			     "\x91\x92\x93\x94\x95\x96\x97\x98"
-			     "\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0"
-			     "\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8"
-			     "\xa9\xaa\xab\xac\xad\xae\xaf\xb0"
-			     "\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8"
-			     "\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0"
-			     "\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8"
-			     "\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0"
-			     "\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8"
-			     "\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0"
-			     "\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8"
-			     "\xe9\xea\xeb\xec\xed\xee\xef\xf0",
-		.psize = 240,
-		.digest = "\x75\xd3\xc5\x24",
-		.np = 2,
-		.tap = { 31, 209 }
-	},
-};
-
 /*
  * Cipher speed tests
  */
diff --git a/crypto/testmgr.c b/crypto/testmgr.c
new file mode 100644
index 0000000..b828c6c
--- /dev/null
+++ b/crypto/testmgr.c
@@ -0,0 +1,1868 @@
+/*
+ * Algorithm testing framework and tests.
+ *
+ * Copyright (c) 2002 James Morris <jmorris@intercode.com.au>
+ * Copyright (c) 2002 Jean-Francois Dive <jef@linuxbe.org>
+ * Copyright (c) 2007 Nokia Siemens Networks
+ * Copyright (c) 2008 Herbert Xu <herbert@gondor.apana.org.au>
+ *
+ * This program is free software; you can redistribute it and/or 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 <crypto/hash.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/scatterlist.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+
+#include "internal.h"
+#include "testmgr.h"
+
+/*
+ * Need slab memory for testing (size in number of pages).
+ */
+#define XBUFSIZE	8
+
+/*
+ * Indexes into the xbuf to simulate cross-page access.
+ */
+#define IDX1		32
+#define IDX2		32400
+#define IDX3		1
+#define IDX4		8193
+#define IDX5		22222
+#define IDX6		17101
+#define IDX7		27333
+#define IDX8		3000
+
+/*
+* Used by test_cipher()
+*/
+#define ENCRYPT 1
+#define DECRYPT 0
+
+struct tcrypt_result {
+	struct completion completion;
+	int err;
+};
+
+struct aead_test_suite {
+	struct {
+		struct aead_testvec *vecs;
+		unsigned int count;
+	} enc, dec;
+};
+
+struct cipher_test_suite {
+	struct {
+		struct cipher_testvec *vecs;
+		unsigned int count;
+	} enc, dec;
+};
+
+struct comp_test_suite {
+	struct {
+		struct comp_testvec *vecs;
+		unsigned int count;
+	} comp, decomp;
+};
+
+struct hash_test_suite {
+	struct hash_testvec *vecs;
+	unsigned int count;
+};
+
+struct alg_test_desc {
+	const char *alg;
+	int (*test)(const struct alg_test_desc *desc, const char *driver,
+		    u32 type, u32 mask);
+
+	union {
+		struct aead_test_suite aead;
+		struct cipher_test_suite cipher;
+		struct comp_test_suite comp;
+		struct hash_test_suite hash;
+	} suite;
+};
+
+static unsigned int IDX[8] = { IDX1, IDX2, IDX3, IDX4, IDX5, IDX6, IDX7, IDX8 };
+
+static char *xbuf[XBUFSIZE];
+static char *axbuf[XBUFSIZE];
+
+static void hexdump(unsigned char *buf, unsigned int len)
+{
+	print_hex_dump(KERN_CONT, "", DUMP_PREFIX_OFFSET,
+			16, 1,
+			buf, len, false);
+}
+
+static void tcrypt_complete(struct crypto_async_request *req, int err)
+{
+	struct tcrypt_result *res = req->data;
+
+	if (err == -EINPROGRESS)
+		return;
+
+	res->err = err;
+	complete(&res->completion);
+}
+
+static int test_hash(struct crypto_ahash *tfm, struct hash_testvec *template,
+		     unsigned int tcount)
+{
+	const char *algo = crypto_tfm_alg_driver_name(crypto_ahash_tfm(tfm));
+	unsigned int i, j, k, temp;
+	struct scatterlist sg[8];
+	char result[64];
+	struct ahash_request *req;
+	struct tcrypt_result tresult;
+	int ret;
+	void *hash_buff;
+
+	init_completion(&tresult.completion);
+
+	req = ahash_request_alloc(tfm, GFP_KERNEL);
+	if (!req) {
+		printk(KERN_ERR "alg: hash: Failed to allocate request for "
+		       "%s\n", algo);
+		ret = -ENOMEM;
+		goto out_noreq;
+	}
+	ahash_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
+				   tcrypt_complete, &tresult);
+
+	for (i = 0; i < tcount; i++) {
+		memset(result, 0, 64);
+
+		hash_buff = xbuf[0];
+
+		memcpy(hash_buff, template[i].plaintext, template[i].psize);
+		sg_init_one(&sg[0], hash_buff, template[i].psize);
+
+		if (template[i].ksize) {
+			crypto_ahash_clear_flags(tfm, ~0);
+			ret = crypto_ahash_setkey(tfm, template[i].key,
+						  template[i].ksize);
+			if (ret) {
+				printk(KERN_ERR "alg: hash: setkey failed on "
+				       "test %d for %s: ret=%d\n", i + 1, algo,
+				       -ret);
+				goto out;
+			}
+		}
+
+		ahash_request_set_crypt(req, sg, result, template[i].psize);
+		ret = crypto_ahash_digest(req);
+		switch (ret) {
+		case 0:
+			break;
+		case -EINPROGRESS:
+		case -EBUSY:
+			ret = wait_for_completion_interruptible(
+				&tresult.completion);
+			if (!ret && !(ret = tresult.err)) {
+				INIT_COMPLETION(tresult.completion);
+				break;
+			}
+			/* fall through */
+		default:
+			printk(KERN_ERR "alg: hash: digest failed on test %d "
+			       "for %s: ret=%d\n", i + 1, algo, -ret);
+			goto out;
+		}
+
+		if (memcmp(result, template[i].digest,
+			   crypto_ahash_digestsize(tfm))) {
+			printk(KERN_ERR "alg: hash: Test %d failed for %s\n",
+			       i + 1, algo);
+			hexdump(result, crypto_ahash_digestsize(tfm));
+			ret = -EINVAL;
+			goto out;
+		}
+	}
+
+	j = 0;
+	for (i = 0; i < tcount; i++) {
+		if (template[i].np) {
+			j++;
+			memset(result, 0, 64);
+
+			temp = 0;
+			sg_init_table(sg, template[i].np);
+			for (k = 0; k < template[i].np; k++) {
+				sg_set_buf(&sg[k],
+					   memcpy(xbuf[IDX[k] >> PAGE_SHIFT] +
+						  offset_in_page(IDX[k]),
+						  template[i].plaintext + temp,
+						  template[i].tap[k]),
+					   template[i].tap[k]);
+				temp += template[i].tap[k];
+			}
+
+			if (template[i].ksize) {
+				crypto_ahash_clear_flags(tfm, ~0);
+				ret = crypto_ahash_setkey(tfm, template[i].key,
+							  template[i].ksize);
+
+				if (ret) {
+					printk(KERN_ERR "alg: hash: setkey "
+					       "failed on chunking test %d "
+					       "for %s: ret=%d\n", j, algo,
+					       -ret);
+					goto out;
+				}
+			}
+
+			ahash_request_set_crypt(req, sg, result,
+						template[i].psize);
+			ret = crypto_ahash_digest(req);
+			switch (ret) {
+			case 0:
+				break;
+			case -EINPROGRESS:
+			case -EBUSY:
+				ret = wait_for_completion_interruptible(
+					&tresult.completion);
+				if (!ret && !(ret = tresult.err)) {
+					INIT_COMPLETION(tresult.completion);
+					break;
+				}
+				/* fall through */
+			default:
+				printk(KERN_ERR "alg: hash: digest failed "
+				       "on chunking test %d for %s: "
+				       "ret=%d\n", j, algo, -ret);
+				goto out;
+			}
+
+			if (memcmp(result, template[i].digest,
+				   crypto_ahash_digestsize(tfm))) {
+				printk(KERN_ERR "alg: hash: Chunking test %d "
+				       "failed for %s\n", j, algo);
+				hexdump(result, crypto_ahash_digestsize(tfm));
+				ret = -EINVAL;
+				goto out;
+			}
+		}
+	}
+
+	ret = 0;
+
+out:
+	ahash_request_free(req);
+out_noreq:
+	return ret;
+}
+
+static int test_aead(struct crypto_aead *tfm, int enc,
+		     struct aead_testvec *template, unsigned int tcount)
+{
+	const char *algo = crypto_tfm_alg_driver_name(crypto_aead_tfm(tfm));
+	unsigned int i, j, k, n, temp;
+	int ret = 0;
+	char *q;
+	char *key;
+	struct aead_request *req;
+	struct scatterlist sg[8];
+	struct scatterlist asg[8];
+	const char *e;
+	struct tcrypt_result result;
+	unsigned int authsize;
+	void *input;
+	void *assoc;
+	char iv[MAX_IVLEN];
+
+	if (enc == ENCRYPT)
+		e = "encryption";
+	else
+		e = "decryption";
+
+	init_completion(&result.completion);
+
+	req = aead_request_alloc(tfm, GFP_KERNEL);
+	if (!req) {
+		printk(KERN_ERR "alg: aead: Failed to allocate request for "
+		       "%s\n", algo);
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	aead_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
+				  tcrypt_complete, &result);
+
+	for (i = 0, j = 0; i < tcount; i++) {
+		if (!template[i].np) {
+			j++;
+
+			/* some tepmplates have no input data but they will
+			 * touch input
+			 */
+			input = xbuf[0];
+			assoc = axbuf[0];
+
+			memcpy(input, template[i].input, template[i].ilen);
+			memcpy(assoc, template[i].assoc, template[i].alen);
+			if (template[i].iv)
+				memcpy(iv, template[i].iv, MAX_IVLEN);
+			else
+				memset(iv, 0, MAX_IVLEN);
+
+			crypto_aead_clear_flags(tfm, ~0);
+			if (template[i].wk)
+				crypto_aead_set_flags(
+					tfm, CRYPTO_TFM_REQ_WEAK_KEY);
+
+			key = template[i].key;
+
+			ret = crypto_aead_setkey(tfm, key,
+						 template[i].klen);
+			if (!ret == template[i].fail) {
+				printk(KERN_ERR "alg: aead: setkey failed on "
+				       "test %d for %s: flags=%x\n", j, algo,
+				       crypto_aead_get_flags(tfm));
+				goto out;
+			} else if (ret)
+				continue;
+
+			authsize = abs(template[i].rlen - template[i].ilen);
+			ret = crypto_aead_setauthsize(tfm, authsize);
+			if (ret) {
+				printk(KERN_ERR "alg: aead: Failed to set "
+				       "authsize to %u on test %d for %s\n",
+				       authsize, j, algo);
+				goto out;
+			}
+
+			sg_init_one(&sg[0], input,
+				    template[i].ilen + (enc ? authsize : 0));
+
+			sg_init_one(&asg[0], assoc, template[i].alen);
+
+			aead_request_set_crypt(req, sg, sg,
+					       template[i].ilen, iv);
+
+			aead_request_set_assoc(req, asg, template[i].alen);
+
+			ret = enc ?
+				crypto_aead_encrypt(req) :
+				crypto_aead_decrypt(req);
+
+			switch (ret) {
+			case 0:
+				break;
+			case -EINPROGRESS:
+			case -EBUSY:
+				ret = wait_for_completion_interruptible(
+					&result.completion);
+				if (!ret && !(ret = result.err)) {
+					INIT_COMPLETION(result.completion);
+					break;
+				}
+				/* fall through */
+			default:
+				printk(KERN_ERR "alg: aead: %s failed on test "
+				       "%d for %s: ret=%d\n", e, j, algo, -ret);
+				goto out;
+			}
+
+			q = input;
+			if (memcmp(q, template[i].result, template[i].rlen)) {
+				printk(KERN_ERR "alg: aead: Test %d failed on "
+				       "%s for %s\n", j, e, algo);
+				hexdump(q, template[i].rlen);
+				ret = -EINVAL;
+				goto out;
+			}
+		}
+	}
+
+	for (i = 0, j = 0; i < tcount; i++) {
+		if (template[i].np) {
+			j++;
+
+			if (template[i].iv)
+				memcpy(iv, template[i].iv, MAX_IVLEN);
+			else
+				memset(iv, 0, MAX_IVLEN);
+
+			crypto_aead_clear_flags(tfm, ~0);
+			if (template[i].wk)
+				crypto_aead_set_flags(
+					tfm, CRYPTO_TFM_REQ_WEAK_KEY);
+			key = template[i].key;
+
+			ret = crypto_aead_setkey(tfm, key, template[i].klen);
+			if (!ret == template[i].fail) {
+				printk(KERN_ERR "alg: aead: setkey failed on "
+				       "chunk test %d for %s: flags=%x\n", j,
+				       algo, crypto_aead_get_flags(tfm));
+				goto out;
+			} else if (ret)
+				continue;
+
+			authsize = abs(template[i].rlen - template[i].ilen);
+
+			ret = -EINVAL;
+			sg_init_table(sg, template[i].np);
+			for (k = 0, temp = 0; k < template[i].np; k++) {
+				if (WARN_ON(offset_in_page(IDX[k]) +
+					    template[i].tap[k] > PAGE_SIZE))
+					goto out;
+
+				q = xbuf[IDX[k] >> PAGE_SHIFT] +
+				    offset_in_page(IDX[k]);
+
+				memcpy(q, template[i].input + temp,
+				       template[i].tap[k]);
+
+				n = template[i].tap[k];
+				if (k == template[i].np - 1 && enc)
+					n += authsize;
+				if (offset_in_page(q) + n < PAGE_SIZE)
+					q[n] = 0;
+
+				sg_set_buf(&sg[k], q, template[i].tap[k]);
+				temp += template[i].tap[k];
+			}
+
+			ret = crypto_aead_setauthsize(tfm, authsize);
+			if (ret) {
+				printk(KERN_ERR "alg: aead: Failed to set "
+				       "authsize to %u on chunk test %d for "
+				       "%s\n", authsize, j, algo);
+				goto out;
+			}
+
+			if (enc) {
+				if (WARN_ON(sg[k - 1].offset +
+					    sg[k - 1].length + authsize >
+					    PAGE_SIZE)) {
+					ret = -EINVAL;
+					goto out;
+				}
+
+				sg[k - 1].length += authsize;
+			}
+
+			sg_init_table(asg, template[i].anp);
+			for (k = 0, temp = 0; k < template[i].anp; k++) {
+				sg_set_buf(&asg[k],
+					   memcpy(axbuf[IDX[k] >> PAGE_SHIFT] +
+						  offset_in_page(IDX[k]),
+						  template[i].assoc + temp,
+						  template[i].atap[k]),
+					   template[i].atap[k]);
+				temp += template[i].atap[k];
+			}
+
+			aead_request_set_crypt(req, sg, sg,
+					       template[i].ilen,
+					       iv);
+
+			aead_request_set_assoc(req, asg, template[i].alen);
+
+			ret = enc ?
+				crypto_aead_encrypt(req) :
+				crypto_aead_decrypt(req);
+
+			switch (ret) {
+			case 0:
+				break;
+			case -EINPROGRESS:
+			case -EBUSY:
+				ret = wait_for_completion_interruptible(
+					&result.completion);
+				if (!ret && !(ret = result.err)) {
+					INIT_COMPLETION(result.completion);
+					break;
+				}
+				/* fall through */
+			default:
+				printk(KERN_ERR "alg: aead: %s failed on "
+				       "chunk test %d for %s: ret=%d\n", e, j,
+				       algo, -ret);
+				goto out;
+			}
+
+			ret = -EINVAL;
+			for (k = 0, temp = 0; k < template[i].np; k++) {
+				q = xbuf[IDX[k] >> PAGE_SHIFT] +
+				    offset_in_page(IDX[k]);
+
+				n = template[i].tap[k];
+				if (k == template[i].np - 1)
+					n += enc ? authsize : -authsize;
+
+				if (memcmp(q, template[i].result + temp, n)) {
+					printk(KERN_ERR "alg: aead: Chunk "
+					       "test %d failed on %s at page "
+					       "%u for %s\n", j, e, k, algo);
+					hexdump(q, n);
+					goto out;
+				}
+
+				q += n;
+				if (k == template[i].np - 1 && !enc) {
+					if (memcmp(q, template[i].input +
+						      temp + n, authsize))
+						n = authsize;
+					else
+						n = 0;
+				} else {
+					for (n = 0; offset_in_page(q + n) &&
+						    q[n]; n++)
+						;
+				}
+				if (n) {
+					printk(KERN_ERR "alg: aead: Result "
+					       "buffer corruption in chunk "
+					       "test %d on %s at page %u for "
+					       "%s: %u bytes:\n", j, e, k,
+					       algo, n);
+					hexdump(q, n);
+					goto out;
+				}
+
+				temp += template[i].tap[k];
+			}
+		}
+	}
+
+	ret = 0;
+
+out:
+	aead_request_free(req);
+	return ret;
+}
+
+static int test_cipher(struct crypto_cipher *tfm, int enc,
+		       struct cipher_testvec *template, unsigned int tcount)
+{
+	const char *algo = crypto_tfm_alg_driver_name(crypto_cipher_tfm(tfm));
+	unsigned int i, j, k;
+	int ret;
+	char *q;
+	const char *e;
+	void *data;
+
+	if (enc == ENCRYPT)
+	        e = "encryption";
+	else
+		e = "decryption";
+
+	j = 0;
+	for (i = 0; i < tcount; i++) {
+		if (template[i].np)
+			continue;
+
+		j++;
+
+		data = xbuf[0];
+		memcpy(data, template[i].input, template[i].ilen);
+
+		crypto_cipher_clear_flags(tfm, ~0);
+		if (template[i].wk)
+			crypto_cipher_set_flags(tfm, CRYPTO_TFM_REQ_WEAK_KEY);
+
+		ret = crypto_cipher_setkey(tfm, template[i].key,
+					   template[i].klen);
+		if (!ret == template[i].fail) {
+			printk(KERN_ERR "alg: cipher: setkey failed "
+			       "on test %d for %s: flags=%x\n", j,
+			       algo, crypto_cipher_get_flags(tfm));
+			goto out;
+		} else if (ret)
+			continue;
+
+		for (k = 0; k < template[i].ilen;
+		     k += crypto_cipher_blocksize(tfm)) {
+			if (enc)
+				crypto_cipher_encrypt_one(tfm, data + k,
+							  data + k);
+			else
+				crypto_cipher_decrypt_one(tfm, data + k,
+							  data + k);
+		}
+
+		q = data;
+		if (memcmp(q, template[i].result, template[i].rlen)) {
+			printk(KERN_ERR "alg: cipher: Test %d failed "
+			       "on %s for %s\n", j, e, algo);
+			hexdump(q, template[i].rlen);
+			ret = -EINVAL;
+			goto out;
+		}
+	}
+
+	ret = 0;
+
+out:
+	return ret;
+}
+
+static int test_skcipher(struct crypto_ablkcipher *tfm, int enc,
+			 struct cipher_testvec *template, unsigned int tcount)
+{
+	const char *algo =
+		crypto_tfm_alg_driver_name(crypto_ablkcipher_tfm(tfm));
+	unsigned int i, j, k, n, temp;
+	int ret;
+	char *q;
+	struct ablkcipher_request *req;
+	struct scatterlist sg[8];
+	const char *e;
+	struct tcrypt_result result;
+	void *data;
+	char iv[MAX_IVLEN];
+
+	if (enc == ENCRYPT)
+	        e = "encryption";
+	else
+		e = "decryption";
+
+	init_completion(&result.completion);
+
+	req = ablkcipher_request_alloc(tfm, GFP_KERNEL);
+	if (!req) {
+		printk(KERN_ERR "alg: skcipher: Failed to allocate request "
+		       "for %s\n", algo);
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	ablkcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
+					tcrypt_complete, &result);
+
+	j = 0;
+	for (i = 0; i < tcount; i++) {
+		if (template[i].iv)
+			memcpy(iv, template[i].iv, MAX_IVLEN);
+		else
+			memset(iv, 0, MAX_IVLEN);
+
+		if (!(template[i].np)) {
+			j++;
+
+			data = xbuf[0];
+			memcpy(data, template[i].input, template[i].ilen);
+
+			crypto_ablkcipher_clear_flags(tfm, ~0);
+			if (template[i].wk)
+				crypto_ablkcipher_set_flags(
+					tfm, CRYPTO_TFM_REQ_WEAK_KEY);
+
+			ret = crypto_ablkcipher_setkey(tfm, template[i].key,
+						       template[i].klen);
+			if (!ret == template[i].fail) {
+				printk(KERN_ERR "alg: skcipher: setkey failed "
+				       "on test %d for %s: flags=%x\n", j,
+				       algo, crypto_ablkcipher_get_flags(tfm));
+				goto out;
+			} else if (ret)
+				continue;
+
+			sg_init_one(&sg[0], data, template[i].ilen);
+
+			ablkcipher_request_set_crypt(req, sg, sg,
+						     template[i].ilen, iv);
+			ret = enc ?
+				crypto_ablkcipher_encrypt(req) :
+				crypto_ablkcipher_decrypt(req);
+
+			switch (ret) {
+			case 0:
+				break;
+			case -EINPROGRESS:
+			case -EBUSY:
+				ret = wait_for_completion_interruptible(
+					&result.completion);
+				if (!ret && !((ret = result.err))) {
+					INIT_COMPLETION(result.completion);
+					break;
+				}
+				/* fall through */
+			default:
+				printk(KERN_ERR "alg: skcipher: %s failed on "
+				       "test %d for %s: ret=%d\n", e, j, algo,
+				       -ret);
+				goto out;
+			}
+
+			q = data;
+			if (memcmp(q, template[i].result, template[i].rlen)) {
+				printk(KERN_ERR "alg: skcipher: Test %d "
+				       "failed on %s for %s\n", j, e, algo);
+				hexdump(q, template[i].rlen);
+				ret = -EINVAL;
+				goto out;
+			}
+		}
+	}
+
+	j = 0;
+	for (i = 0; i < tcount; i++) {
+
+		if (template[i].iv)
+			memcpy(iv, template[i].iv, MAX_IVLEN);
+		else
+			memset(iv, 0, MAX_IVLEN);
+
+		if (template[i].np) {
+			j++;
+
+			crypto_ablkcipher_clear_flags(tfm, ~0);
+			if (template[i].wk)
+				crypto_ablkcipher_set_flags(
+					tfm, CRYPTO_TFM_REQ_WEAK_KEY);
+
+			ret = crypto_ablkcipher_setkey(tfm, template[i].key,
+						       template[i].klen);
+			if (!ret == template[i].fail) {
+				printk(KERN_ERR "alg: skcipher: setkey failed "
+				       "on chunk test %d for %s: flags=%x\n",
+				       j, algo,
+				       crypto_ablkcipher_get_flags(tfm));
+				goto out;
+			} else if (ret)
+				continue;
+
+			temp = 0;
+			ret = -EINVAL;
+			sg_init_table(sg, template[i].np);
+			for (k = 0; k < template[i].np; k++) {
+				if (WARN_ON(offset_in_page(IDX[k]) +
+					    template[i].tap[k] > PAGE_SIZE))
+					goto out;
+
+				q = xbuf[IDX[k] >> PAGE_SHIFT] +
+				    offset_in_page(IDX[k]);
+
+				memcpy(q, template[i].input + temp,
+				       template[i].tap[k]);
+
+				if (offset_in_page(q) + template[i].tap[k] <
+				    PAGE_SIZE)
+					q[template[i].tap[k]] = 0;
+
+				sg_set_buf(&sg[k], q, template[i].tap[k]);
+
+				temp += template[i].tap[k];
+			}
+
+			ablkcipher_request_set_crypt(req, sg, sg,
+					template[i].ilen, iv);
+
+			ret = enc ?
+				crypto_ablkcipher_encrypt(req) :
+				crypto_ablkcipher_decrypt(req);
+
+			switch (ret) {
+			case 0:
+				break;
+			case -EINPROGRESS:
+			case -EBUSY:
+				ret = wait_for_completion_interruptible(
+					&result.completion);
+				if (!ret && !((ret = result.err))) {
+					INIT_COMPLETION(result.completion);
+					break;
+				}
+				/* fall through */
+			default:
+				printk(KERN_ERR "alg: skcipher: %s failed on "
+				       "chunk test %d for %s: ret=%d\n", e, j,
+				       algo, -ret);
+				goto out;
+			}
+
+			temp = 0;
+			ret = -EINVAL;
+			for (k = 0; k < template[i].np; k++) {
+				q = xbuf[IDX[k] >> PAGE_SHIFT] +
+				    offset_in_page(IDX[k]);
+
+				if (memcmp(q, template[i].result + temp,
+					   template[i].tap[k])) {
+					printk(KERN_ERR "alg: skcipher: Chunk "
+					       "test %d failed on %s at page "
+					       "%u for %s\n", j, e, k, algo);
+					hexdump(q, template[i].tap[k]);
+					goto out;
+				}
+
+				q += template[i].tap[k];
+				for (n = 0; offset_in_page(q + n) && q[n]; n++)
+					;
+				if (n) {
+					printk(KERN_ERR "alg: skcipher: "
+					       "Result buffer corruption in "
+					       "chunk test %d on %s at page "
+					       "%u for %s: %u bytes:\n", j, e,
+					       k, algo, n);
+					hexdump(q, n);
+					goto out;
+				}
+				temp += template[i].tap[k];
+			}
+		}
+	}
+
+	ret = 0;
+
+out:
+	ablkcipher_request_free(req);
+	return ret;
+}
+
+static int test_comp(struct crypto_comp *tfm, struct comp_testvec *ctemplate,
+		     struct comp_testvec *dtemplate, int ctcount, int dtcount)
+{
+	const char *algo = crypto_tfm_alg_driver_name(crypto_comp_tfm(tfm));
+	unsigned int i;
+	char result[COMP_BUF_SIZE];
+	int ret;
+
+	for (i = 0; i < ctcount; i++) {
+		int ilen, dlen = COMP_BUF_SIZE;
+
+		memset(result, 0, sizeof (result));
+
+		ilen = ctemplate[i].inlen;
+		ret = crypto_comp_compress(tfm, ctemplate[i].input,
+		                           ilen, result, &dlen);
+		if (ret) {
+			printk(KERN_ERR "alg: comp: compression failed "
+			       "on test %d for %s: ret=%d\n", i + 1, algo,
+			       -ret);
+			goto out;
+		}
+
+		if (memcmp(result, ctemplate[i].output, dlen)) {
+			printk(KERN_ERR "alg: comp: Compression test %d "
+			       "failed for %s\n", i + 1, algo);
+			hexdump(result, dlen);
+			ret = -EINVAL;
+			goto out;
+		}
+	}
+
+	for (i = 0; i < dtcount; i++) {
+		int ilen, ret, dlen = COMP_BUF_SIZE;
+
+		memset(result, 0, sizeof (result));
+
+		ilen = dtemplate[i].inlen;
+		ret = crypto_comp_decompress(tfm, dtemplate[i].input,
+		                             ilen, result, &dlen);
+		if (ret) {
+			printk(KERN_ERR "alg: comp: decompression failed "
+			       "on test %d for %s: ret=%d\n", i + 1, algo,
+			       -ret);
+			goto out;
+		}
+
+		if (memcmp(result, dtemplate[i].output, dlen)) {
+			printk(KERN_ERR "alg: comp: Decompression test %d "
+			       "failed for %s\n", i + 1, algo);
+			hexdump(result, dlen);
+			ret = -EINVAL;
+			goto out;
+		}
+	}
+
+	ret = 0;
+
+out:
+	return ret;
+}
+
+static int alg_test_aead(const struct alg_test_desc *desc, const char *driver,
+			 u32 type, u32 mask)
+{
+	struct crypto_aead *tfm;
+	int err = 0;
+
+	tfm = crypto_alloc_aead(driver, type, mask);
+	if (IS_ERR(tfm)) {
+		printk(KERN_ERR "alg: aead: Failed to load transform for %s: "
+		       "%ld\n", driver, PTR_ERR(tfm));
+		return PTR_ERR(tfm);
+	}
+
+	if (desc->suite.aead.enc.vecs) {
+		err = test_aead(tfm, ENCRYPT, desc->suite.aead.enc.vecs,
+				desc->suite.aead.enc.count);
+		if (err)
+			goto out;
+	}
+
+	if (!err && desc->suite.aead.dec.vecs)
+		err = test_aead(tfm, DECRYPT, desc->suite.aead.dec.vecs,
+				desc->suite.aead.dec.count);
+
+out:
+	crypto_free_aead(tfm);
+	return err;
+}
+
+static int alg_test_cipher(const struct alg_test_desc *desc,
+			   const char *driver, u32 type, u32 mask)
+{
+	struct crypto_cipher *tfm;
+	int err = 0;
+
+	tfm = crypto_alloc_cipher(driver, type, mask);
+	if (IS_ERR(tfm)) {
+		printk(KERN_ERR "alg: cipher: Failed to load transform for "
+		       "%s: %ld\n", driver, PTR_ERR(tfm));
+		return PTR_ERR(tfm);
+	}
+
+	if (desc->suite.cipher.enc.vecs) {
+		err = test_cipher(tfm, ENCRYPT, desc->suite.cipher.enc.vecs,
+				  desc->suite.cipher.enc.count);
+		if (err)
+			goto out;
+	}
+
+	if (desc->suite.cipher.dec.vecs)
+		err = test_cipher(tfm, DECRYPT, desc->suite.cipher.dec.vecs,
+				  desc->suite.cipher.dec.count);
+
+out:
+	crypto_free_cipher(tfm);
+	return err;
+}
+
+static int alg_test_skcipher(const struct alg_test_desc *desc,
+			     const char *driver, u32 type, u32 mask)
+{
+	struct crypto_ablkcipher *tfm;
+	int err = 0;
+
+	tfm = crypto_alloc_ablkcipher(driver, type, mask);
+	if (IS_ERR(tfm)) {
+		printk(KERN_ERR "alg: skcipher: Failed to load transform for "
+		       "%s: %ld\n", driver, PTR_ERR(tfm));
+		return PTR_ERR(tfm);
+	}
+
+	if (desc->suite.cipher.enc.vecs) {
+		err = test_skcipher(tfm, ENCRYPT, desc->suite.cipher.enc.vecs,
+				    desc->suite.cipher.enc.count);
+		if (err)
+			goto out;
+	}
+
+	if (desc->suite.cipher.dec.vecs)
+		err = test_skcipher(tfm, DECRYPT, desc->suite.cipher.dec.vecs,
+				    desc->suite.cipher.dec.count);
+
+out:
+	crypto_free_ablkcipher(tfm);
+	return err;
+}
+
+static int alg_test_comp(const struct alg_test_desc *desc, const char *driver,
+			 u32 type, u32 mask)
+{
+	struct crypto_comp *tfm;
+	int err;
+
+	tfm = crypto_alloc_comp(driver, type, mask);
+	if (IS_ERR(tfm)) {
+		printk(KERN_ERR "alg: comp: Failed to load transform for %s: "
+		       "%ld\n", driver, PTR_ERR(tfm));
+		return PTR_ERR(tfm);
+	}
+
+	err = test_comp(tfm, desc->suite.comp.comp.vecs,
+			desc->suite.comp.decomp.vecs,
+			desc->suite.comp.comp.count,
+			desc->suite.comp.decomp.count);
+
+	crypto_free_comp(tfm);
+	return err;
+}
+
+static int alg_test_hash(const struct alg_test_desc *desc, const char *driver,
+			 u32 type, u32 mask)
+{
+	struct crypto_ahash *tfm;
+	int err;
+
+	tfm = crypto_alloc_ahash(driver, type, mask);
+	if (IS_ERR(tfm)) {
+		printk(KERN_ERR "alg: hash: Failed to load transform for %s: "
+		       "%ld\n", driver, PTR_ERR(tfm));
+		return PTR_ERR(tfm);
+	}
+
+	err = test_hash(tfm, desc->suite.hash.vecs, desc->suite.hash.count);
+
+	crypto_free_ahash(tfm);
+	return err;
+}
+
+/* Please keep this list sorted by algorithm name. */
+static const struct alg_test_desc alg_test_descs[] = {
+	{
+		.alg = "cbc(aes)",
+		.test = alg_test_skcipher,
+		.suite = {
+			.cipher = {
+				.enc = {
+					.vecs = aes_cbc_enc_tv_template,
+					.count = AES_CBC_ENC_TEST_VECTORS
+				},
+				.dec = {
+					.vecs = aes_cbc_dec_tv_template,
+					.count = AES_CBC_DEC_TEST_VECTORS
+				}
+			}
+		}
+	}, {
+		.alg = "cbc(anubis)",
+		.test = alg_test_skcipher,
+		.suite = {
+			.cipher = {
+				.enc = {
+					.vecs = anubis_cbc_enc_tv_template,
+					.count = ANUBIS_CBC_ENC_TEST_VECTORS
+				},
+				.dec = {
+					.vecs = anubis_cbc_dec_tv_template,
+					.count = ANUBIS_CBC_DEC_TEST_VECTORS
+				}
+			}
+		}
+	}, {
+		.alg = "cbc(blowfish)",
+		.test = alg_test_skcipher,
+		.suite = {
+			.cipher = {
+				.enc = {
+					.vecs = bf_cbc_enc_tv_template,
+					.count = BF_CBC_ENC_TEST_VECTORS
+				},
+				.dec = {
+					.vecs = bf_cbc_dec_tv_template,
+					.count = BF_CBC_DEC_TEST_VECTORS
+				}
+			}
+		}
+	}, {
+		.alg = "cbc(camellia)",
+		.test = alg_test_skcipher,
+		.suite = {
+			.cipher = {
+				.enc = {
+					.vecs = camellia_cbc_enc_tv_template,
+					.count = CAMELLIA_CBC_ENC_TEST_VECTORS
+				},
+				.dec = {
+					.vecs = camellia_cbc_dec_tv_template,
+					.count = CAMELLIA_CBC_DEC_TEST_VECTORS
+				}
+			}
+		}
+	}, {
+		.alg = "cbc(des)",
+		.test = alg_test_skcipher,
+		.suite = {
+			.cipher = {
+				.enc = {
+					.vecs = des_cbc_enc_tv_template,
+					.count = DES_CBC_ENC_TEST_VECTORS
+				},
+				.dec = {
+					.vecs = des_cbc_dec_tv_template,
+					.count = DES_CBC_DEC_TEST_VECTORS
+				}
+			}
+		}
+	}, {
+		.alg = "cbc(des3_ede)",
+		.test = alg_test_skcipher,
+		.suite = {
+			.cipher = {
+				.enc = {
+					.vecs = des3_ede_cbc_enc_tv_template,
+					.count = DES3_EDE_CBC_ENC_TEST_VECTORS
+				},
+				.dec = {
+					.vecs = des3_ede_cbc_dec_tv_template,
+					.count = DES3_EDE_CBC_DEC_TEST_VECTORS
+				}
+			}
+		}
+	}, {
+		.alg = "cbc(twofish)",
+		.test = alg_test_skcipher,
+		.suite = {
+			.cipher = {
+				.enc = {
+					.vecs = tf_cbc_enc_tv_template,
+					.count = TF_CBC_ENC_TEST_VECTORS
+				},
+				.dec = {
+					.vecs = tf_cbc_dec_tv_template,
+					.count = TF_CBC_DEC_TEST_VECTORS
+				}
+			}
+		}
+	}, {
+		.alg = "ccm(aes)",
+		.test = alg_test_aead,
+		.suite = {
+			.aead = {
+				.enc = {
+					.vecs = aes_ccm_enc_tv_template,
+					.count = AES_CCM_ENC_TEST_VECTORS
+				},
+				.dec = {
+					.vecs = aes_ccm_dec_tv_template,
+					.count = AES_CCM_DEC_TEST_VECTORS
+				}
+			}
+		}
+	}, {
+		.alg = "crc32c",
+		.test = alg_test_hash,
+		.suite = {
+			.hash = {
+				.vecs = crc32c_tv_template,
+				.count = CRC32C_TEST_VECTORS
+			}
+		}
+	}, {
+		.alg = "cts(cbc(aes))",
+		.test = alg_test_skcipher,
+		.suite = {
+			.cipher = {
+				.enc = {
+					.vecs = cts_mode_enc_tv_template,
+					.count = CTS_MODE_ENC_TEST_VECTORS
+				},
+				.dec = {
+					.vecs = cts_mode_dec_tv_template,
+					.count = CTS_MODE_DEC_TEST_VECTORS
+				}
+			}
+		}
+	}, {
+		.alg = "deflate",
+		.test = alg_test_comp,
+		.suite = {
+			.comp = {
+				.comp = {
+					.vecs = deflate_comp_tv_template,
+					.count = DEFLATE_COMP_TEST_VECTORS
+				},
+				.decomp = {
+					.vecs = deflate_decomp_tv_template,
+					.count = DEFLATE_DECOMP_TEST_VECTORS
+				}
+			}
+		}
+	}, {
+		.alg = "ecb(aes)",
+		.test = alg_test_skcipher,
+		.suite = {
+			.cipher = {
+				.enc = {
+					.vecs = aes_enc_tv_template,
+					.count = AES_ENC_TEST_VECTORS
+				},
+				.dec = {
+					.vecs = aes_dec_tv_template,
+					.count = AES_DEC_TEST_VECTORS
+				}
+			}
+		}
+	}, {
+		.alg = "ecb(anubis)",
+		.test = alg_test_skcipher,
+		.suite = {
+			.cipher = {
+				.enc = {
+					.vecs = anubis_enc_tv_template,
+					.count = ANUBIS_ENC_TEST_VECTORS
+				},
+				.dec = {
+					.vecs = anubis_dec_tv_template,
+					.count = ANUBIS_DEC_TEST_VECTORS
+				}
+			}
+		}
+	}, {
+		.alg = "ecb(arc4)",
+		.test = alg_test_skcipher,
+		.suite = {
+			.cipher = {
+				.enc = {
+					.vecs = arc4_enc_tv_template,
+					.count = ARC4_ENC_TEST_VECTORS
+				},
+				.dec = {
+					.vecs = arc4_dec_tv_template,
+					.count = ARC4_DEC_TEST_VECTORS
+				}
+			}
+		}
+	}, {
+		.alg = "ecb(blowfish)",
+		.test = alg_test_skcipher,
+		.suite = {
+			.cipher = {
+				.enc = {
+					.vecs = bf_enc_tv_template,
+					.count = BF_ENC_TEST_VECTORS
+				},
+				.dec = {
+					.vecs = bf_dec_tv_template,
+					.count = BF_DEC_TEST_VECTORS
+				}
+			}
+		}
+	}, {
+		.alg = "ecb(camellia)",
+		.test = alg_test_skcipher,
+		.suite = {
+			.cipher = {
+				.enc = {
+					.vecs = camellia_enc_tv_template,
+					.count = CAMELLIA_ENC_TEST_VECTORS
+				},
+				.dec = {
+					.vecs = camellia_dec_tv_template,
+					.count = CAMELLIA_DEC_TEST_VECTORS
+				}
+			}
+		}
+	}, {
+		.alg = "ecb(cast5)",
+		.test = alg_test_skcipher,
+		.suite = {
+			.cipher = {
+				.enc = {
+					.vecs = cast5_enc_tv_template,
+					.count = CAST5_ENC_TEST_VECTORS
+				},
+				.dec = {
+					.vecs = cast5_dec_tv_template,
+					.count = CAST5_DEC_TEST_VECTORS
+				}
+			}
+		}
+	}, {
+		.alg = "ecb(cast6)",
+		.test = alg_test_skcipher,
+		.suite = {
+			.cipher = {
+				.enc = {
+					.vecs = cast6_enc_tv_template,
+					.count = CAST6_ENC_TEST_VECTORS
+				},
+				.dec = {
+					.vecs = cast6_dec_tv_template,
+					.count = CAST6_DEC_TEST_VECTORS
+				}
+			}
+		}
+	}, {
+		.alg = "ecb(des)",
+		.test = alg_test_skcipher,
+		.suite = {
+			.cipher = {
+				.enc = {
+					.vecs = des_enc_tv_template,
+					.count = DES_ENC_TEST_VECTORS
+				},
+				.dec = {
+					.vecs = des_dec_tv_template,
+					.count = DES_DEC_TEST_VECTORS
+				}
+			}
+		}
+	}, {
+		.alg = "ecb(des3_ede)",
+		.test = alg_test_skcipher,
+		.suite = {
+			.cipher = {
+				.enc = {
+					.vecs = des3_ede_enc_tv_template,
+					.count = DES3_EDE_ENC_TEST_VECTORS
+				},
+				.dec = {
+					.vecs = des3_ede_dec_tv_template,
+					.count = DES3_EDE_DEC_TEST_VECTORS
+				}
+			}
+		}
+	}, {
+		.alg = "ecb(khazad)",
+		.test = alg_test_skcipher,
+		.suite = {
+			.cipher = {
+				.enc = {
+					.vecs = khazad_enc_tv_template,
+					.count = KHAZAD_ENC_TEST_VECTORS
+				},
+				.dec = {
+					.vecs = khazad_dec_tv_template,
+					.count = KHAZAD_DEC_TEST_VECTORS
+				}
+			}
+		}
+	}, {
+		.alg = "ecb(seed)",
+		.test = alg_test_skcipher,
+		.suite = {
+			.cipher = {
+				.enc = {
+					.vecs = seed_enc_tv_template,
+					.count = SEED_ENC_TEST_VECTORS
+				},
+				.dec = {
+					.vecs = seed_dec_tv_template,
+					.count = SEED_DEC_TEST_VECTORS
+				}
+			}
+		}
+	}, {
+		.alg = "ecb(serpent)",
+		.test = alg_test_skcipher,
+		.suite = {
+			.cipher = {
+				.enc = {
+					.vecs = serpent_enc_tv_template,
+					.count = SERPENT_ENC_TEST_VECTORS
+				},
+				.dec = {
+					.vecs = serpent_dec_tv_template,
+					.count = SERPENT_DEC_TEST_VECTORS
+				}
+			}
+		}
+	}, {
+		.alg = "ecb(tea)",
+		.test = alg_test_skcipher,
+		.suite = {
+			.cipher = {
+				.enc = {
+					.vecs = tea_enc_tv_template,
+					.count = TEA_ENC_TEST_VECTORS
+				},
+				.dec = {
+					.vecs = tea_dec_tv_template,
+					.count = TEA_DEC_TEST_VECTORS
+				}
+			}
+		}
+	}, {
+		.alg = "ecb(tnepres)",
+		.test = alg_test_skcipher,
+		.suite = {
+			.cipher = {
+				.enc = {
+					.vecs = tnepres_enc_tv_template,
+					.count = TNEPRES_ENC_TEST_VECTORS
+				},
+				.dec = {
+					.vecs = tnepres_dec_tv_template,
+					.count = TNEPRES_DEC_TEST_VECTORS
+				}
+			}
+		}
+	}, {
+		.alg = "ecb(twofish)",
+		.test = alg_test_skcipher,
+		.suite = {
+			.cipher = {
+				.enc = {
+					.vecs = tf_enc_tv_template,
+					.count = TF_ENC_TEST_VECTORS
+				},
+				.dec = {
+					.vecs = tf_dec_tv_template,
+					.count = TF_DEC_TEST_VECTORS
+				}
+			}
+		}
+	}, {
+		.alg = "ecb(xeta)",
+		.test = alg_test_skcipher,
+		.suite = {
+			.cipher = {
+				.enc = {
+					.vecs = xeta_enc_tv_template,
+					.count = XETA_ENC_TEST_VECTORS
+				},
+				.dec = {
+					.vecs = xeta_dec_tv_template,
+					.count = XETA_DEC_TEST_VECTORS
+				}
+			}
+		}
+	}, {
+		.alg = "ecb(xtea)",
+		.test = alg_test_skcipher,
+		.suite = {
+			.cipher = {
+				.enc = {
+					.vecs = xtea_enc_tv_template,
+					.count = XTEA_ENC_TEST_VECTORS
+				},
+				.dec = {
+					.vecs = xtea_dec_tv_template,
+					.count = XTEA_DEC_TEST_VECTORS
+				}
+			}
+		}
+	}, {
+		.alg = "gcm(aes)",
+		.test = alg_test_aead,
+		.suite = {
+			.aead = {
+				.enc = {
+					.vecs = aes_gcm_enc_tv_template,
+					.count = AES_GCM_ENC_TEST_VECTORS
+				},
+				.dec = {
+					.vecs = aes_gcm_dec_tv_template,
+					.count = AES_GCM_DEC_TEST_VECTORS
+				}
+			}
+		}
+	}, {
+		.alg = "hmac(md5)",
+		.test = alg_test_hash,
+		.suite = {
+			.hash = {
+				.vecs = hmac_md5_tv_template,
+				.count = HMAC_MD5_TEST_VECTORS
+			}
+		}
+	}, {
+		.alg = "hmac(rmd128)",
+		.test = alg_test_hash,
+		.suite = {
+			.hash = {
+				.vecs = hmac_rmd128_tv_template,
+				.count = HMAC_RMD128_TEST_VECTORS
+			}
+		}
+	}, {
+		.alg = "hmac(rmd160)",
+		.test = alg_test_hash,
+		.suite = {
+			.hash = {
+				.vecs = hmac_rmd160_tv_template,
+				.count = HMAC_RMD160_TEST_VECTORS
+			}
+		}
+	}, {
+		.alg = "hmac(sha1)",
+		.test = alg_test_hash,
+		.suite = {
+			.hash = {
+				.vecs = hmac_sha1_tv_template,
+				.count = HMAC_SHA1_TEST_VECTORS
+			}
+		}
+	}, {
+		.alg = "hmac(sha224)",
+		.test = alg_test_hash,
+		.suite = {
+			.hash = {
+				.vecs = hmac_sha224_tv_template,
+				.count = HMAC_SHA224_TEST_VECTORS
+			}
+		}
+	}, {
+		.alg = "hmac(sha256)",
+		.test = alg_test_hash,
+		.suite = {
+			.hash = {
+				.vecs = hmac_sha256_tv_template,
+				.count = HMAC_SHA256_TEST_VECTORS
+			}
+		}
+	}, {
+		.alg = "hmac(sha384)",
+		.test = alg_test_hash,
+		.suite = {
+			.hash = {
+				.vecs = hmac_sha384_tv_template,
+				.count = HMAC_SHA384_TEST_VECTORS
+			}
+		}
+	}, {
+		.alg = "hmac(sha512)",
+		.test = alg_test_hash,
+		.suite = {
+			.hash = {
+				.vecs = hmac_sha512_tv_template,
+				.count = HMAC_SHA512_TEST_VECTORS
+			}
+		}
+	}, {
+		.alg = "lrw(aes)",
+		.test = alg_test_skcipher,
+		.suite = {
+			.cipher = {
+				.enc = {
+					.vecs = aes_lrw_enc_tv_template,
+					.count = AES_LRW_ENC_TEST_VECTORS
+				},
+				.dec = {
+					.vecs = aes_lrw_dec_tv_template,
+					.count = AES_LRW_DEC_TEST_VECTORS
+				}
+			}
+		}
+	}, {
+		.alg = "lzo",
+		.test = alg_test_comp,
+		.suite = {
+			.comp = {
+				.comp = {
+					.vecs = lzo_comp_tv_template,
+					.count = LZO_COMP_TEST_VECTORS
+				},
+				.decomp = {
+					.vecs = lzo_decomp_tv_template,
+					.count = LZO_DECOMP_TEST_VECTORS
+				}
+			}
+		}
+	}, {
+		.alg = "md4",
+		.test = alg_test_hash,
+		.suite = {
+			.hash = {
+				.vecs = md4_tv_template,
+				.count = MD4_TEST_VECTORS
+			}
+		}
+	}, {
+		.alg = "md5",
+		.test = alg_test_hash,
+		.suite = {
+			.hash = {
+				.vecs = md5_tv_template,
+				.count = MD5_TEST_VECTORS
+			}
+		}
+	}, {
+		.alg = "michael_mic",
+		.test = alg_test_hash,
+		.suite = {
+			.hash = {
+				.vecs = michael_mic_tv_template,
+				.count = MICHAEL_MIC_TEST_VECTORS
+			}
+		}
+	}, {
+		.alg = "pcbc(fcrypt)",
+		.test = alg_test_skcipher,
+		.suite = {
+			.cipher = {
+				.enc = {
+					.vecs = fcrypt_pcbc_enc_tv_template,
+					.count = FCRYPT_ENC_TEST_VECTORS
+				},
+				.dec = {
+					.vecs = fcrypt_pcbc_dec_tv_template,
+					.count = FCRYPT_DEC_TEST_VECTORS
+				}
+			}
+		}
+	}, {
+		.alg = "rfc3686(ctr(aes))",
+		.test = alg_test_skcipher,
+		.suite = {
+			.cipher = {
+				.enc = {
+					.vecs = aes_ctr_enc_tv_template,
+					.count = AES_CTR_ENC_TEST_VECTORS
+				},
+				.dec = {
+					.vecs = aes_ctr_dec_tv_template,
+					.count = AES_CTR_DEC_TEST_VECTORS
+				}
+			}
+		}
+	}, {
+		.alg = "rmd128",
+		.test = alg_test_hash,
+		.suite = {
+			.hash = {
+				.vecs = rmd128_tv_template,
+				.count = RMD128_TEST_VECTORS
+			}
+		}
+	}, {
+		.alg = "rmd160",
+		.test = alg_test_hash,
+		.suite = {
+			.hash = {
+				.vecs = rmd160_tv_template,
+				.count = RMD160_TEST_VECTORS
+			}
+		}
+	}, {
+		.alg = "rmd256",
+		.test = alg_test_hash,
+		.suite = {
+			.hash = {
+				.vecs = rmd256_tv_template,
+				.count = RMD256_TEST_VECTORS
+			}
+		}
+	}, {
+		.alg = "rmd320",
+		.test = alg_test_hash,
+		.suite = {
+			.hash = {
+				.vecs = rmd320_tv_template,
+				.count = RMD320_TEST_VECTORS
+			}
+		}
+	}, {
+		.alg = "salsa20",
+		.test = alg_test_skcipher,
+		.suite = {
+			.cipher = {
+				.enc = {
+					.vecs = salsa20_stream_enc_tv_template,
+					.count = SALSA20_STREAM_ENC_TEST_VECTORS
+				}
+			}
+		}
+	}, {
+		.alg = "sha1",
+		.test = alg_test_hash,
+		.suite = {
+			.hash = {
+				.vecs = sha1_tv_template,
+				.count = SHA1_TEST_VECTORS
+			}
+		}
+	}, {
+		.alg = "sha224",
+		.test = alg_test_hash,
+		.suite = {
+			.hash = {
+				.vecs = sha224_tv_template,
+				.count = SHA224_TEST_VECTORS
+			}
+		}
+	}, {
+		.alg = "sha256",
+		.test = alg_test_hash,
+		.suite = {
+			.hash = {
+				.vecs = sha256_tv_template,
+				.count = SHA256_TEST_VECTORS
+			}
+		}
+	}, {
+		.alg = "sha384",
+		.test = alg_test_hash,
+		.suite = {
+			.hash = {
+				.vecs = sha384_tv_template,
+				.count = SHA384_TEST_VECTORS
+			}
+		}
+	}, {
+		.alg = "sha512",
+		.test = alg_test_hash,
+		.suite = {
+			.hash = {
+				.vecs = sha512_tv_template,
+				.count = SHA512_TEST_VECTORS
+			}
+		}
+	}, {
+		.alg = "tgr128",
+		.test = alg_test_hash,
+		.suite = {
+			.hash = {
+				.vecs = tgr128_tv_template,
+				.count = TGR128_TEST_VECTORS
+			}
+		}
+	}, {
+		.alg = "tgr160",
+		.test = alg_test_hash,
+		.suite = {
+			.hash = {
+				.vecs = tgr160_tv_template,
+				.count = TGR160_TEST_VECTORS
+			}
+		}
+	}, {
+		.alg = "tgr192",
+		.test = alg_test_hash,
+		.suite = {
+			.hash = {
+				.vecs = tgr192_tv_template,
+				.count = TGR192_TEST_VECTORS
+			}
+		}
+	}, {
+		.alg = "wp256",
+		.test = alg_test_hash,
+		.suite = {
+			.hash = {
+				.vecs = wp256_tv_template,
+				.count = WP256_TEST_VECTORS
+			}
+		}
+	}, {
+		.alg = "wp384",
+		.test = alg_test_hash,
+		.suite = {
+			.hash = {
+				.vecs = wp384_tv_template,
+				.count = WP384_TEST_VECTORS
+			}
+		}
+	}, {
+		.alg = "wp512",
+		.test = alg_test_hash,
+		.suite = {
+			.hash = {
+				.vecs = wp512_tv_template,
+				.count = WP512_TEST_VECTORS
+			}
+		}
+	}, {
+		.alg = "xcbc(aes)",
+		.test = alg_test_hash,
+		.suite = {
+			.hash = {
+				.vecs = aes_xcbc128_tv_template,
+				.count = XCBC_AES_TEST_VECTORS
+			}
+		}
+	}, {
+		.alg = "xts(aes)",
+		.test = alg_test_skcipher,
+		.suite = {
+			.cipher = {
+				.enc = {
+					.vecs = aes_xts_enc_tv_template,
+					.count = AES_XTS_ENC_TEST_VECTORS
+				},
+				.dec = {
+					.vecs = aes_xts_dec_tv_template,
+					.count = AES_XTS_DEC_TEST_VECTORS
+				}
+			}
+		}
+	}
+};
+
+static int alg_find_test(const char *alg)
+{
+	int start = 0;
+	int end = ARRAY_SIZE(alg_test_descs);
+
+	while (start < end) {
+		int i = (start + end) / 2;
+		int diff = strcmp(alg_test_descs[i].alg, alg);
+
+		if (diff > 0) {
+			end = i;
+			continue;
+		}
+
+		if (diff < 0) {
+			start = i + 1;
+			continue;
+		}
+
+		return i;
+	}
+
+	return -1;
+}
+
+int alg_test(const char *driver, const char *alg, u32 type, u32 mask)
+{
+	int i;
+
+	if ((type & CRYPTO_ALG_TYPE_MASK) == CRYPTO_ALG_TYPE_CIPHER) {
+		char nalg[CRYPTO_MAX_ALG_NAME];
+
+		if (snprintf(nalg, sizeof(nalg), "ecb(%s)", alg) >=
+		    sizeof(nalg))
+			return -ENAMETOOLONG;
+
+		i = alg_find_test(nalg);
+		if (i < 0)
+			goto notest;
+
+		return alg_test_cipher(alg_test_descs + i, driver, type, mask);
+	}
+
+	i = alg_find_test(alg);
+	if (i < 0)
+		goto notest;
+
+	return alg_test_descs[i].test(alg_test_descs + i, driver,
+				      type, mask);
+
+notest:
+	printk(KERN_INFO "alg: No test for %s (%s)\n", alg, driver);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(alg_test);
+
+int __init testmgr_init(void)
+{
+	int i;
+
+	for (i = 0; i < XBUFSIZE; i++) {
+		xbuf[i] = (void *)__get_free_page(GFP_KERNEL);
+		if (!xbuf[i])
+			goto err_free_xbuf;
+	}
+
+	for (i = 0; i < XBUFSIZE; i++) {
+		axbuf[i] = (void *)__get_free_page(GFP_KERNEL);
+		if (!axbuf[i])
+			goto err_free_axbuf;
+	}
+
+	return 0;
+
+err_free_axbuf:
+	for (i = 0; i < XBUFSIZE && axbuf[i]; i++)
+		free_page((unsigned long)axbuf[i]);
+err_free_xbuf:
+	for (i = 0; i < XBUFSIZE && xbuf[i]; i++)
+		free_page((unsigned long)xbuf[i]);
+
+	return -ENOMEM;
+}
+
+void testmgr_exit(void)
+{
+	int i;
+
+	for (i = 0; i < XBUFSIZE; i++)
+		free_page((unsigned long)axbuf[i]);
+	for (i = 0; i < XBUFSIZE; i++)
+		free_page((unsigned long)xbuf[i]);
+}
diff --git a/crypto/testmgr.h b/crypto/testmgr.h
new file mode 100644
index 0000000..dee94d9
--- /dev/null
+++ b/crypto/testmgr.h
@@ -0,0 +1,8738 @@
+/*
+ * Algorithm testing framework and tests.
+ *
+ * Copyright (c) 2002 James Morris <jmorris@intercode.com.au>
+ * Copyright (c) 2002 Jean-Francois Dive <jef@linuxbe.org>
+ * Copyright (c) 2007 Nokia Siemens Networks
+ * Copyright (c) 2008 Herbert Xu <herbert@gondor.apana.org.au>
+ *
+ * This program is free software; you can redistribute it and/or 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 _CRYPTO_TESTMGR_H
+#define _CRYPTO_TESTMGR_H
+
+#define MAX_DIGEST_SIZE		64
+#define MAX_TAP			8
+
+#define MAX_KEYLEN		56
+#define MAX_IVLEN		32
+
+struct hash_testvec {
+	/* only used with keyed hash algorithms */
+	char *key;
+	char *plaintext;
+	char *digest;
+	unsigned char tap[MAX_TAP];
+	unsigned char psize;
+	unsigned char np;
+	unsigned char ksize;
+};
+
+struct cipher_testvec {
+	char *key;
+	char *iv;
+	char *input;
+	char *result;
+	unsigned short tap[MAX_TAP];
+	int np;
+	unsigned char fail;
+	unsigned char wk; /* weak key flag */
+	unsigned char klen;
+	unsigned short ilen;
+	unsigned short rlen;
+};
+
+struct aead_testvec {
+	char *key;
+	char *iv;
+	char *input;
+	char *assoc;
+	char *result;
+	unsigned char tap[MAX_TAP];
+	unsigned char atap[MAX_TAP];
+	int np;
+	int anp;
+	unsigned char fail;
+	unsigned char wk; /* weak key flag */
+	unsigned char klen;
+	unsigned short ilen;
+	unsigned short alen;
+	unsigned short rlen;
+};
+
+static char zeroed_string[48];
+
+/*
+ * MD4 test vectors from RFC1320
+ */
+#define MD4_TEST_VECTORS	7
+
+static struct hash_testvec md4_tv_template [] = {
+	{
+		.plaintext = "",
+		.digest	= "\x31\xd6\xcf\xe0\xd1\x6a\xe9\x31"
+			  "\xb7\x3c\x59\xd7\xe0\xc0\x89\xc0",
+	}, {
+		.plaintext = "a",
+		.psize	= 1,
+		.digest	= "\xbd\xe5\x2c\xb3\x1d\xe3\x3e\x46"
+			  "\x24\x5e\x05\xfb\xdb\xd6\xfb\x24",
+	}, {
+		.plaintext = "abc",
+		.psize	= 3,
+		.digest	= "\xa4\x48\x01\x7a\xaf\x21\xd8\x52"
+			  "\x5f\xc1\x0a\xe8\x7a\xa6\x72\x9d",
+	}, {
+		.plaintext = "message digest",
+		.psize	= 14,
+		.digest	= "\xd9\x13\x0a\x81\x64\x54\x9f\xe8"
+			"\x18\x87\x48\x06\xe1\xc7\x01\x4b",
+	}, {
+		.plaintext = "abcdefghijklmnopqrstuvwxyz",
+		.psize	= 26,
+		.digest	= "\xd7\x9e\x1c\x30\x8a\xa5\xbb\xcd"
+			  "\xee\xa8\xed\x63\xdf\x41\x2d\xa9",
+		.np	= 2,
+		.tap	= { 13, 13 },
+	}, {
+		.plaintext = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
+		.psize	= 62,
+		.digest	= "\x04\x3f\x85\x82\xf2\x41\xdb\x35"
+			  "\x1c\xe6\x27\xe1\x53\xe7\xf0\xe4",
+	}, {
+		.plaintext = "123456789012345678901234567890123456789012345678901234567890123"
+			   "45678901234567890",
+		.psize	= 80,
+		.digest	= "\xe3\x3b\x4d\xdc\x9c\x38\xf2\x19"
+			  "\x9c\x3e\x7b\x16\x4f\xcc\x05\x36",
+	},
+};
+
+/*
+ * MD5 test vectors from RFC1321
+ */
+#define MD5_TEST_VECTORS	7
+
+static struct hash_testvec md5_tv_template[] = {
+	{
+		.digest	= "\xd4\x1d\x8c\xd9\x8f\x00\xb2\x04"
+			  "\xe9\x80\x09\x98\xec\xf8\x42\x7e",
+	}, {
+		.plaintext = "a",
+		.psize	= 1,
+		.digest	= "\x0c\xc1\x75\xb9\xc0\xf1\xb6\xa8"
+			  "\x31\xc3\x99\xe2\x69\x77\x26\x61",
+	}, {
+		.plaintext = "abc",
+		.psize	= 3,
+		.digest	= "\x90\x01\x50\x98\x3c\xd2\x4f\xb0"
+			  "\xd6\x96\x3f\x7d\x28\xe1\x7f\x72",
+	}, {
+		.plaintext = "message digest",
+		.psize	= 14,
+		.digest	= "\xf9\x6b\x69\x7d\x7c\xb7\x93\x8d"
+			  "\x52\x5a\x2f\x31\xaa\xf1\x61\xd0",
+	}, {
+		.plaintext = "abcdefghijklmnopqrstuvwxyz",
+		.psize	= 26,
+		.digest	= "\xc3\xfc\xd3\xd7\x61\x92\xe4\x00"
+			  "\x7d\xfb\x49\x6c\xca\x67\xe1\x3b",
+		.np	= 2,
+		.tap	= {13, 13}
+	}, {
+		.plaintext = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
+		.psize	= 62,
+		.digest	= "\xd1\x74\xab\x98\xd2\x77\xd9\xf5"
+			  "\xa5\x61\x1c\x2c\x9f\x41\x9d\x9f",
+	}, {
+		.plaintext = "12345678901234567890123456789012345678901234567890123456789012"
+			   "345678901234567890",
+		.psize	= 80,
+		.digest	= "\x57\xed\xf4\xa2\x2b\xe3\xc9\x55"
+			  "\xac\x49\xda\x2e\x21\x07\xb6\x7a",
+	}
+
+};
+
+/*
+ * RIPEMD-128 test vectors from ISO/IEC 10118-3:2004(E)
+ */
+#define RMD128_TEST_VECTORS     10
+
+static struct hash_testvec rmd128_tv_template[] = {
+	{
+		.digest	= "\xcd\xf2\x62\x13\xa1\x50\xdc\x3e"
+			  "\xcb\x61\x0f\x18\xf6\xb3\x8b\x46",
+	}, {
+		.plaintext = "a",
+		.psize	= 1,
+		.digest	= "\x86\xbe\x7a\xfa\x33\x9d\x0f\xc7"
+			  "\xcf\xc7\x85\xe7\x2f\x57\x8d\x33",
+	}, {
+		.plaintext = "abc",
+		.psize	= 3,
+		.digest	= "\xc1\x4a\x12\x19\x9c\x66\xe4\xba"
+			  "\x84\x63\x6b\x0f\x69\x14\x4c\x77",
+	}, {
+		.plaintext = "message digest",
+		.psize	= 14,
+		.digest	= "\x9e\x32\x7b\x3d\x6e\x52\x30\x62"
+			  "\xaf\xc1\x13\x2d\x7d\xf9\xd1\xb8",
+	}, {
+		.plaintext = "abcdefghijklmnopqrstuvwxyz",
+		.psize	= 26,
+		.digest	= "\xfd\x2a\xa6\x07\xf7\x1d\xc8\xf5"
+			  "\x10\x71\x49\x22\xb3\x71\x83\x4e",
+	}, {
+		.plaintext = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcde"
+			     "fghijklmnopqrstuvwxyz0123456789",
+		.psize	= 62,
+		.digest	= "\xd1\xe9\x59\xeb\x17\x9c\x91\x1f"
+			  "\xae\xa4\x62\x4c\x60\xc5\xc7\x02",
+	}, {
+		.plaintext = "1234567890123456789012345678901234567890"
+			     "1234567890123456789012345678901234567890",
+		.psize	= 80,
+		.digest	= "\x3f\x45\xef\x19\x47\x32\xc2\xdb"
+			  "\xb2\xc4\xa2\xc7\x69\x79\x5f\xa3",
+	}, {
+		.plaintext = "abcdbcdecdefdefgefghfghighij"
+			     "hijkijkljklmklmnlmnomnopnopq",
+		.psize	= 56,
+		.digest	= "\xa1\xaa\x06\x89\xd0\xfa\xfa\x2d"
+			  "\xdc\x22\xe8\x8b\x49\x13\x3a\x06",
+		.np	= 2,
+		.tap	= { 28, 28 },
+	}, {
+		.plaintext = "abcdefghbcdefghicdefghijdefghijkefghijklfghi"
+			     "jklmghijklmnhijklmnoijklmnopjklmnopqklmnopqr"
+			     "lmnopqrsmnopqrstnopqrstu",
+		.psize	= 112,
+		.digest	= "\xd4\xec\xc9\x13\xe1\xdf\x77\x6b"
+			  "\xf4\x8d\xe9\xd5\x5b\x1f\x25\x46",
+	}, {
+		.plaintext = "abcdbcdecdefdefgefghfghighijhijk",
+		.psize	= 32,
+		.digest	= "\x13\xfc\x13\xe8\xef\xff\x34\x7d"
+			  "\xe1\x93\xff\x46\xdb\xac\xcf\xd4",
+	}
+};
+
+/*
+ * RIPEMD-160 test vectors from ISO/IEC 10118-3:2004(E)
+ */
+#define RMD160_TEST_VECTORS     10
+
+static struct hash_testvec rmd160_tv_template[] = {
+	{
+		.digest	= "\x9c\x11\x85\xa5\xc5\xe9\xfc\x54\x61\x28"
+			  "\x08\x97\x7e\xe8\xf5\x48\xb2\x25\x8d\x31",
+	}, {
+		.plaintext = "a",
+		.psize	= 1,
+		.digest	= "\x0b\xdc\x9d\x2d\x25\x6b\x3e\xe9\xda\xae"
+			  "\x34\x7b\xe6\xf4\xdc\x83\x5a\x46\x7f\xfe",
+	}, {
+		.plaintext = "abc",
+		.psize	= 3,
+		.digest	= "\x8e\xb2\x08\xf7\xe0\x5d\x98\x7a\x9b\x04"
+			  "\x4a\x8e\x98\xc6\xb0\x87\xf1\x5a\x0b\xfc",
+	}, {
+		.plaintext = "message digest",
+		.psize	= 14,
+		.digest	= "\x5d\x06\x89\xef\x49\xd2\xfa\xe5\x72\xb8"
+			  "\x81\xb1\x23\xa8\x5f\xfa\x21\x59\x5f\x36",
+	}, {
+		.plaintext = "abcdefghijklmnopqrstuvwxyz",
+		.psize	= 26,
+		.digest	= "\xf7\x1c\x27\x10\x9c\x69\x2c\x1b\x56\xbb"
+			  "\xdc\xeb\x5b\x9d\x28\x65\xb3\x70\x8d\xbc",
+	}, {
+		.plaintext = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcde"
+			     "fghijklmnopqrstuvwxyz0123456789",
+		.psize	= 62,
+		.digest	= "\xb0\xe2\x0b\x6e\x31\x16\x64\x02\x86\xed"
+			  "\x3a\x87\xa5\x71\x30\x79\xb2\x1f\x51\x89",
+	}, {
+		.plaintext = "1234567890123456789012345678901234567890"
+			     "1234567890123456789012345678901234567890",
+		.psize	= 80,
+		.digest	= "\x9b\x75\x2e\x45\x57\x3d\x4b\x39\xf4\xdb"
+			  "\xd3\x32\x3c\xab\x82\xbf\x63\x32\x6b\xfb",
+	}, {
+		.plaintext = "abcdbcdecdefdefgefghfghighij"
+			     "hijkijkljklmklmnlmnomnopnopq",
+		.psize	= 56,
+		.digest	= "\x12\xa0\x53\x38\x4a\x9c\x0c\x88\xe4\x05"
+			  "\xa0\x6c\x27\xdc\xf4\x9a\xda\x62\xeb\x2b",
+		.np	= 2,
+		.tap	= { 28, 28 },
+	}, {
+		.plaintext = "abcdefghbcdefghicdefghijdefghijkefghijklfghi"
+			     "jklmghijklmnhijklmnoijklmnopjklmnopqklmnopqr"
+			     "lmnopqrsmnopqrstnopqrstu",
+		.psize	= 112,
+		.digest	= "\x6f\x3f\xa3\x9b\x6b\x50\x3c\x38\x4f\x91"
+			  "\x9a\x49\xa7\xaa\x5c\x2c\x08\xbd\xfb\x45",
+	}, {
+		.plaintext = "abcdbcdecdefdefgefghfghighijhijk",
+		.psize	= 32,
+		.digest	= "\x94\xc2\x64\x11\x54\x04\xe6\x33\x79\x0d"
+			  "\xfc\xc8\x7b\x58\x7d\x36\x77\x06\x7d\x9f",
+	}
+};
+
+/*
+ * RIPEMD-256 test vectors
+ */
+#define RMD256_TEST_VECTORS     8
+
+static struct hash_testvec rmd256_tv_template[] = {
+	{
+		.digest	= "\x02\xba\x4c\x4e\x5f\x8e\xcd\x18"
+			  "\x77\xfc\x52\xd6\x4d\x30\xe3\x7a"
+			  "\x2d\x97\x74\xfb\x1e\x5d\x02\x63"
+			  "\x80\xae\x01\x68\xe3\xc5\x52\x2d",
+	}, {
+		.plaintext = "a",
+		.psize	= 1,
+		.digest	= "\xf9\x33\x3e\x45\xd8\x57\xf5\xd9"
+			  "\x0a\x91\xba\xb7\x0a\x1e\xba\x0c"
+			  "\xfb\x1b\xe4\xb0\x78\x3c\x9a\xcf"
+			  "\xcd\x88\x3a\x91\x34\x69\x29\x25",
+	}, {
+		.plaintext = "abc",
+		.psize	= 3,
+		.digest	= "\xaf\xbd\x6e\x22\x8b\x9d\x8c\xbb"
+			  "\xce\xf5\xca\x2d\x03\xe6\xdb\xa1"
+			  "\x0a\xc0\xbc\x7d\xcb\xe4\x68\x0e"
+			  "\x1e\x42\xd2\xe9\x75\x45\x9b\x65",
+	}, {
+		.plaintext = "message digest",
+		.psize	= 14,
+		.digest	= "\x87\xe9\x71\x75\x9a\x1c\xe4\x7a"
+			  "\x51\x4d\x5c\x91\x4c\x39\x2c\x90"
+			  "\x18\xc7\xc4\x6b\xc1\x44\x65\x55"
+			  "\x4a\xfc\xdf\x54\xa5\x07\x0c\x0e",
+	}, {
+		.plaintext = "abcdefghijklmnopqrstuvwxyz",
+		.psize	= 26,
+		.digest	= "\x64\x9d\x30\x34\x75\x1e\xa2\x16"
+			  "\x77\x6b\xf9\xa1\x8a\xcc\x81\xbc"
+			  "\x78\x96\x11\x8a\x51\x97\x96\x87"
+			  "\x82\xdd\x1f\xd9\x7d\x8d\x51\x33",
+	}, {
+		.plaintext = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcde"
+			     "fghijklmnopqrstuvwxyz0123456789",
+		.psize	= 62,
+		.digest	= "\x57\x40\xa4\x08\xac\x16\xb7\x20"
+			  "\xb8\x44\x24\xae\x93\x1c\xbb\x1f"
+			  "\xe3\x63\xd1\xd0\xbf\x40\x17\xf1"
+			  "\xa8\x9f\x7e\xa6\xde\x77\xa0\xb8",
+	}, {
+		.plaintext = "1234567890123456789012345678901234567890"
+			     "1234567890123456789012345678901234567890",
+		.psize	= 80,
+		.digest	= "\x06\xfd\xcc\x7a\x40\x95\x48\xaa"
+			  "\xf9\x13\x68\xc0\x6a\x62\x75\xb5"
+			  "\x53\xe3\xf0\x99\xbf\x0e\xa4\xed"
+			  "\xfd\x67\x78\xdf\x89\xa8\x90\xdd",
+	}, {
+		.plaintext = "abcdbcdecdefdefgefghfghighij"
+			     "hijkijkljklmklmnlmnomnopnopq",
+		.psize	= 56,
+		.digest	= "\x38\x43\x04\x55\x83\xaa\xc6\xc8"
+			  "\xc8\xd9\x12\x85\x73\xe7\xa9\x80"
+			  "\x9a\xfb\x2a\x0f\x34\xcc\xc3\x6e"
+			  "\xa9\xe7\x2f\x16\xf6\x36\x8e\x3f",
+		.np	= 2,
+		.tap	= { 28, 28 },
+	}
+};
+
+/*
+ * RIPEMD-320 test vectors
+ */
+#define RMD320_TEST_VECTORS     8
+
+static struct hash_testvec rmd320_tv_template[] = {
+	{
+		.digest	= "\x22\xd6\x5d\x56\x61\x53\x6c\xdc\x75\xc1"
+			  "\xfd\xf5\xc6\xde\x7b\x41\xb9\xf2\x73\x25"
+			  "\xeb\xc6\x1e\x85\x57\x17\x7d\x70\x5a\x0e"
+			  "\xc8\x80\x15\x1c\x3a\x32\xa0\x08\x99\xb8",
+	}, {
+		.plaintext = "a",
+		.psize	= 1,
+		.digest	= "\xce\x78\x85\x06\x38\xf9\x26\x58\xa5\xa5"
+			  "\x85\x09\x75\x79\x92\x6d\xda\x66\x7a\x57"
+			  "\x16\x56\x2c\xfc\xf6\xfb\xe7\x7f\x63\x54"
+			  "\x2f\x99\xb0\x47\x05\xd6\x97\x0d\xff\x5d",
+	}, {
+		.plaintext = "abc",
+		.psize	= 3,
+		.digest	= "\xde\x4c\x01\xb3\x05\x4f\x89\x30\xa7\x9d"
+			  "\x09\xae\x73\x8e\x92\x30\x1e\x5a\x17\x08"
+			  "\x5b\xef\xfd\xc1\xb8\xd1\x16\x71\x3e\x74"
+			  "\xf8\x2f\xa9\x42\xd6\x4c\xdb\xc4\x68\x2d",
+	}, {
+		.plaintext = "message digest",
+		.psize	= 14,
+		.digest	= "\x3a\x8e\x28\x50\x2e\xd4\x5d\x42\x2f\x68"
+			  "\x84\x4f\x9d\xd3\x16\xe7\xb9\x85\x33\xfa"
+			  "\x3f\x2a\x91\xd2\x9f\x84\xd4\x25\xc8\x8d"
+			  "\x6b\x4e\xff\x72\x7d\xf6\x6a\x7c\x01\x97",
+	}, {
+		.plaintext = "abcdefghijklmnopqrstuvwxyz",
+		.psize	= 26,
+		.digest	= "\xca\xbd\xb1\x81\x0b\x92\x47\x0a\x20\x93"
+			  "\xaa\x6b\xce\x05\x95\x2c\x28\x34\x8c\xf4"
+			  "\x3f\xf6\x08\x41\x97\x51\x66\xbb\x40\xed"
+			  "\x23\x40\x04\xb8\x82\x44\x63\xe6\xb0\x09",
+	}, {
+		.plaintext = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcde"
+			     "fghijklmnopqrstuvwxyz0123456789",
+		.psize	= 62,
+		.digest	= "\xed\x54\x49\x40\xc8\x6d\x67\xf2\x50\xd2"
+			  "\x32\xc3\x0b\x7b\x3e\x57\x70\xe0\xc6\x0c"
+			  "\x8c\xb9\xa4\xca\xfe\x3b\x11\x38\x8a\xf9"
+			  "\x92\x0e\x1b\x99\x23\x0b\x84\x3c\x86\xa4",
+	}, {
+		.plaintext = "1234567890123456789012345678901234567890"
+			     "1234567890123456789012345678901234567890",
+		.psize	= 80,
+		.digest	= "\x55\x78\x88\xaf\x5f\x6d\x8e\xd6\x2a\xb6"
+			  "\x69\x45\xc6\xd2\xa0\xa4\x7e\xcd\x53\x41"
+			  "\xe9\x15\xeb\x8f\xea\x1d\x05\x24\x95\x5f"
+			  "\x82\x5d\xc7\x17\xe4\xa0\x08\xab\x2d\x42",
+	}, {
+		.plaintext = "abcdbcdecdefdefgefghfghighij"
+			     "hijkijkljklmklmnlmnomnopnopq",
+		.psize	= 56,
+		.digest	= "\xd0\x34\xa7\x95\x0c\xf7\x22\x02\x1b\xa4"
+			  "\xb8\x4d\xf7\x69\xa5\xde\x20\x60\xe2\x59"
+			  "\xdf\x4c\x9b\xb4\xa4\x26\x8c\x0e\x93\x5b"
+			  "\xbc\x74\x70\xa9\x69\xc9\xd0\x72\xa1\xac",
+		.np	= 2,
+		.tap	= { 28, 28 },
+	}
+};
+
+/*
+ * SHA1 test vectors  from from FIPS PUB 180-1
+ */
+#define SHA1_TEST_VECTORS	2
+
+static struct hash_testvec sha1_tv_template[] = {
+	{
+		.plaintext = "abc",
+		.psize	= 3,
+		.digest	= "\xa9\x99\x3e\x36\x47\x06\x81\x6a\xba\x3e"
+			  "\x25\x71\x78\x50\xc2\x6c\x9c\xd0\xd8\x9d",
+	}, {
+		.plaintext = "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
+		.psize	= 56,
+		.digest	= "\x84\x98\x3e\x44\x1c\x3b\xd2\x6e\xba\xae"
+			  "\x4a\xa1\xf9\x51\x29\xe5\xe5\x46\x70\xf1",
+		.np	= 2,
+		.tap	= { 28, 28 }
+	}
+};
+
+
+/*
+ * SHA224 test vectors from from FIPS PUB 180-2
+ */
+#define SHA224_TEST_VECTORS     2
+
+static struct hash_testvec sha224_tv_template[] = {
+	{
+		.plaintext = "abc",
+		.psize  = 3,
+		.digest = "\x23\x09\x7D\x22\x34\x05\xD8\x22"
+			  "\x86\x42\xA4\x77\xBD\xA2\x55\xB3"
+			  "\x2A\xAD\xBC\xE4\xBD\xA0\xB3\xF7"
+			  "\xE3\x6C\x9D\xA7",
+	}, {
+		.plaintext =
+		"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
+		.psize  = 56,
+		.digest = "\x75\x38\x8B\x16\x51\x27\x76\xCC"
+			  "\x5D\xBA\x5D\xA1\xFD\x89\x01\x50"
+			  "\xB0\xC6\x45\x5C\xB4\xF5\x8B\x19"
+			  "\x52\x52\x25\x25",
+		.np     = 2,
+		.tap    = { 28, 28 }
+	}
+};
+
+/*
+ * SHA256 test vectors from from NIST
+ */
+#define SHA256_TEST_VECTORS	2
+
+static struct hash_testvec sha256_tv_template[] = {
+	{
+		.plaintext = "abc",
+		.psize	= 3,
+		.digest	= "\xba\x78\x16\xbf\x8f\x01\xcf\xea"
+			  "\x41\x41\x40\xde\x5d\xae\x22\x23"
+			  "\xb0\x03\x61\xa3\x96\x17\x7a\x9c"
+			  "\xb4\x10\xff\x61\xf2\x00\x15\xad",
+	}, {
+		.plaintext = "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
+		.psize	= 56,
+		.digest	= "\x24\x8d\x6a\x61\xd2\x06\x38\xb8"
+			  "\xe5\xc0\x26\x93\x0c\x3e\x60\x39"
+			  "\xa3\x3c\xe4\x59\x64\xff\x21\x67"
+			  "\xf6\xec\xed\xd4\x19\xdb\x06\xc1",
+		.np	= 2,
+		.tap	= { 28, 28 }
+	},
+};
+
+/*
+ * SHA384 test vectors from from NIST and kerneli
+ */
+#define SHA384_TEST_VECTORS	4
+
+static struct hash_testvec sha384_tv_template[] = {
+	{
+		.plaintext= "abc",
+		.psize	= 3,
+		.digest	= "\xcb\x00\x75\x3f\x45\xa3\x5e\x8b"
+			  "\xb5\xa0\x3d\x69\x9a\xc6\x50\x07"
+			  "\x27\x2c\x32\xab\x0e\xde\xd1\x63"
+			  "\x1a\x8b\x60\x5a\x43\xff\x5b\xed"
+			  "\x80\x86\x07\x2b\xa1\xe7\xcc\x23"
+			  "\x58\xba\xec\xa1\x34\xc8\x25\xa7",
+	}, {
+		.plaintext = "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
+		.psize	= 56,
+		.digest	= "\x33\x91\xfd\xdd\xfc\x8d\xc7\x39"
+			  "\x37\x07\xa6\x5b\x1b\x47\x09\x39"
+			  "\x7c\xf8\xb1\xd1\x62\xaf\x05\xab"
+			  "\xfe\x8f\x45\x0d\xe5\xf3\x6b\xc6"
+			  "\xb0\x45\x5a\x85\x20\xbc\x4e\x6f"
+			  "\x5f\xe9\x5b\x1f\xe3\xc8\x45\x2b",
+	}, {
+		.plaintext = "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn"
+			   "hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu",
+		.psize	= 112,
+		.digest	= "\x09\x33\x0c\x33\xf7\x11\x47\xe8"
+			  "\x3d\x19\x2f\xc7\x82\xcd\x1b\x47"
+			  "\x53\x11\x1b\x17\x3b\x3b\x05\xd2"
+			  "\x2f\xa0\x80\x86\xe3\xb0\xf7\x12"
+			  "\xfc\xc7\xc7\x1a\x55\x7e\x2d\xb9"
+			  "\x66\xc3\xe9\xfa\x91\x74\x60\x39",
+	}, {
+		.plaintext = "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcd"
+			   "efghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz",
+		.psize	= 104,
+		.digest	= "\x3d\x20\x89\x73\xab\x35\x08\xdb"
+			  "\xbd\x7e\x2c\x28\x62\xba\x29\x0a"
+			  "\xd3\x01\x0e\x49\x78\xc1\x98\xdc"
+			  "\x4d\x8f\xd0\x14\xe5\x82\x82\x3a"
+			  "\x89\xe1\x6f\x9b\x2a\x7b\xbc\x1a"
+			  "\xc9\x38\xe2\xd1\x99\xe8\xbe\xa4",
+		.np	= 4,
+		.tap	= { 26, 26, 26, 26 }
+	},
+};
+
+/*
+ * SHA512 test vectors from from NIST and kerneli
+ */
+#define SHA512_TEST_VECTORS	4
+
+static struct hash_testvec sha512_tv_template[] = {
+	{
+		.plaintext = "abc",
+		.psize	= 3,
+		.digest	= "\xdd\xaf\x35\xa1\x93\x61\x7a\xba"
+			  "\xcc\x41\x73\x49\xae\x20\x41\x31"
+			  "\x12\xe6\xfa\x4e\x89\xa9\x7e\xa2"
+			  "\x0a\x9e\xee\xe6\x4b\x55\xd3\x9a"
+			  "\x21\x92\x99\x2a\x27\x4f\xc1\xa8"
+			  "\x36\xba\x3c\x23\xa3\xfe\xeb\xbd"
+			  "\x45\x4d\x44\x23\x64\x3c\xe8\x0e"
+			  "\x2a\x9a\xc9\x4f\xa5\x4c\xa4\x9f",
+	}, {
+		.plaintext = "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
+		.psize	= 56,
+		.digest	= "\x20\x4a\x8f\xc6\xdd\xa8\x2f\x0a"
+			  "\x0c\xed\x7b\xeb\x8e\x08\xa4\x16"
+			  "\x57\xc1\x6e\xf4\x68\xb2\x28\xa8"
+			  "\x27\x9b\xe3\x31\xa7\x03\xc3\x35"
+			  "\x96\xfd\x15\xc1\x3b\x1b\x07\xf9"
+			  "\xaa\x1d\x3b\xea\x57\x78\x9c\xa0"
+			  "\x31\xad\x85\xc7\xa7\x1d\xd7\x03"
+			  "\x54\xec\x63\x12\x38\xca\x34\x45",
+	}, {
+		.plaintext = "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn"
+			   "hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu",
+		.psize	= 112,
+		.digest	= "\x8e\x95\x9b\x75\xda\xe3\x13\xda"
+			  "\x8c\xf4\xf7\x28\x14\xfc\x14\x3f"
+			  "\x8f\x77\x79\xc6\xeb\x9f\x7f\xa1"
+			  "\x72\x99\xae\xad\xb6\x88\x90\x18"
+			  "\x50\x1d\x28\x9e\x49\x00\xf7\xe4"
+			  "\x33\x1b\x99\xde\xc4\xb5\x43\x3a"
+			  "\xc7\xd3\x29\xee\xb6\xdd\x26\x54"
+			  "\x5e\x96\xe5\x5b\x87\x4b\xe9\x09",
+	}, {
+		.plaintext = "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcd"
+			   "efghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz",
+		.psize	= 104,
+		.digest	= "\x93\x0d\x0c\xef\xcb\x30\xff\x11"
+			  "\x33\xb6\x89\x81\x21\xf1\xcf\x3d"
+			  "\x27\x57\x8a\xfc\xaf\xe8\x67\x7c"
+			  "\x52\x57\xcf\x06\x99\x11\xf7\x5d"
+			  "\x8f\x58\x31\xb5\x6e\xbf\xda\x67"
+			  "\xb2\x78\xe6\x6d\xff\x8b\x84\xfe"
+			  "\x2b\x28\x70\xf7\x42\xa5\x80\xd8"
+			  "\xed\xb4\x19\x87\x23\x28\x50\xc9",
+		.np	= 4,
+		.tap	= { 26, 26, 26, 26 }
+	},
+};
+
+
+/*
+ * WHIRLPOOL test vectors from Whirlpool package
+ * by Vincent Rijmen and Paulo S. L. M. Barreto as part of the NESSIE
+ * submission
+ */
+#define WP512_TEST_VECTORS	8
+
+static struct hash_testvec wp512_tv_template[] = {
+	{
+		.plaintext = "",
+		.psize	= 0,
+		.digest	= "\x19\xFA\x61\xD7\x55\x22\xA4\x66"
+			  "\x9B\x44\xE3\x9C\x1D\x2E\x17\x26"
+			  "\xC5\x30\x23\x21\x30\xD4\x07\xF8"
+			  "\x9A\xFE\xE0\x96\x49\x97\xF7\xA7"
+			  "\x3E\x83\xBE\x69\x8B\x28\x8F\xEB"
+			  "\xCF\x88\xE3\xE0\x3C\x4F\x07\x57"
+			  "\xEA\x89\x64\xE5\x9B\x63\xD9\x37"
+			  "\x08\xB1\x38\xCC\x42\xA6\x6E\xB3",
+
+
+	}, {
+		.plaintext = "a",
+		.psize	= 1,
+		.digest	= "\x8A\xCA\x26\x02\x79\x2A\xEC\x6F"
+			  "\x11\xA6\x72\x06\x53\x1F\xB7\xD7"
+			  "\xF0\xDF\xF5\x94\x13\x14\x5E\x69"
+			  "\x73\xC4\x50\x01\xD0\x08\x7B\x42"
+			  "\xD1\x1B\xC6\x45\x41\x3A\xEF\xF6"
+			  "\x3A\x42\x39\x1A\x39\x14\x5A\x59"
+			  "\x1A\x92\x20\x0D\x56\x01\x95\xE5"
+			  "\x3B\x47\x85\x84\xFD\xAE\x23\x1A",
+	}, {
+		.plaintext = "abc",
+		.psize	= 3,
+		.digest	= "\x4E\x24\x48\xA4\xC6\xF4\x86\xBB"
+			  "\x16\xB6\x56\x2C\x73\xB4\x02\x0B"
+			  "\xF3\x04\x3E\x3A\x73\x1B\xCE\x72"
+			  "\x1A\xE1\xB3\x03\xD9\x7E\x6D\x4C"
+			  "\x71\x81\xEE\xBD\xB6\xC5\x7E\x27"
+			  "\x7D\x0E\x34\x95\x71\x14\xCB\xD6"
+			  "\xC7\x97\xFC\x9D\x95\xD8\xB5\x82"
+			  "\xD2\x25\x29\x20\x76\xD4\xEE\xF5",
+	}, {
+		.plaintext = "message digest",
+		.psize	= 14,
+		.digest	= "\x37\x8C\x84\xA4\x12\x6E\x2D\xC6"
+			  "\xE5\x6D\xCC\x74\x58\x37\x7A\xAC"
+			  "\x83\x8D\x00\x03\x22\x30\xF5\x3C"
+			  "\xE1\xF5\x70\x0C\x0F\xFB\x4D\x3B"
+			  "\x84\x21\x55\x76\x59\xEF\x55\xC1"
+			  "\x06\xB4\xB5\x2A\xC5\xA4\xAA\xA6"
+			  "\x92\xED\x92\x00\x52\x83\x8F\x33"
+			  "\x62\xE8\x6D\xBD\x37\xA8\x90\x3E",
+	}, {
+		.plaintext = "abcdefghijklmnopqrstuvwxyz",
+		.psize	= 26,
+		.digest	= "\xF1\xD7\x54\x66\x26\x36\xFF\xE9"
+			  "\x2C\x82\xEB\xB9\x21\x2A\x48\x4A"
+			  "\x8D\x38\x63\x1E\xAD\x42\x38\xF5"
+			  "\x44\x2E\xE1\x3B\x80\x54\xE4\x1B"
+			  "\x08\xBF\x2A\x92\x51\xC3\x0B\x6A"
+			  "\x0B\x8A\xAE\x86\x17\x7A\xB4\xA6"
+			  "\xF6\x8F\x67\x3E\x72\x07\x86\x5D"
+			  "\x5D\x98\x19\xA3\xDB\xA4\xEB\x3B",
+	}, {
+		.plaintext = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+			   "abcdefghijklmnopqrstuvwxyz0123456789",
+		.psize	= 62,
+		.digest	= "\xDC\x37\xE0\x08\xCF\x9E\xE6\x9B"
+			  "\xF1\x1F\x00\xED\x9A\xBA\x26\x90"
+			  "\x1D\xD7\xC2\x8C\xDE\xC0\x66\xCC"
+			  "\x6A\xF4\x2E\x40\xF8\x2F\x3A\x1E"
+			  "\x08\xEB\xA2\x66\x29\x12\x9D\x8F"
+			  "\xB7\xCB\x57\x21\x1B\x92\x81\xA6"
+			  "\x55\x17\xCC\x87\x9D\x7B\x96\x21"
+			  "\x42\xC6\x5F\x5A\x7A\xF0\x14\x67",
+	}, {
+		.plaintext = "1234567890123456789012345678901234567890"
+			   "1234567890123456789012345678901234567890",
+		.psize	= 80,
+		.digest	= "\x46\x6E\xF1\x8B\xAB\xB0\x15\x4D"
+			  "\x25\xB9\xD3\x8A\x64\x14\xF5\xC0"
+			  "\x87\x84\x37\x2B\xCC\xB2\x04\xD6"
+			  "\x54\x9C\x4A\xFA\xDB\x60\x14\x29"
+			  "\x4D\x5B\xD8\xDF\x2A\x6C\x44\xE5"
+			  "\x38\xCD\x04\x7B\x26\x81\xA5\x1A"
+			  "\x2C\x60\x48\x1E\x88\xC5\xA2\x0B"
+			  "\x2C\x2A\x80\xCF\x3A\x9A\x08\x3B",
+	}, {
+		.plaintext = "abcdbcdecdefdefgefghfghighijhijk",
+		.psize	= 32,
+		.digest	= "\x2A\x98\x7E\xA4\x0F\x91\x70\x61"
+			  "\xF5\xD6\xF0\xA0\xE4\x64\x4F\x48"
+			  "\x8A\x7A\x5A\x52\xDE\xEE\x65\x62"
+			  "\x07\xC5\x62\xF9\x88\xE9\x5C\x69"
+			  "\x16\xBD\xC8\x03\x1B\xC5\xBE\x1B"
+			  "\x7B\x94\x76\x39\xFE\x05\x0B\x56"
+			  "\x93\x9B\xAA\xA0\xAD\xFF\x9A\xE6"
+			  "\x74\x5B\x7B\x18\x1C\x3B\xE3\xFD",
+	},
+};
+
+#define WP384_TEST_VECTORS	8
+
+static struct hash_testvec wp384_tv_template[] = {
+	{
+		.plaintext = "",
+		.psize	= 0,
+		.digest	= "\x19\xFA\x61\xD7\x55\x22\xA4\x66"
+			  "\x9B\x44\xE3\x9C\x1D\x2E\x17\x26"
+			  "\xC5\x30\x23\x21\x30\xD4\x07\xF8"
+			  "\x9A\xFE\xE0\x96\x49\x97\xF7\xA7"
+			  "\x3E\x83\xBE\x69\x8B\x28\x8F\xEB"
+			  "\xCF\x88\xE3\xE0\x3C\x4F\x07\x57",
+
+
+	}, {
+		.plaintext = "a",
+		.psize	= 1,
+		.digest	= "\x8A\xCA\x26\x02\x79\x2A\xEC\x6F"
+			  "\x11\xA6\x72\x06\x53\x1F\xB7\xD7"
+			  "\xF0\xDF\xF5\x94\x13\x14\x5E\x69"
+			  "\x73\xC4\x50\x01\xD0\x08\x7B\x42"
+			  "\xD1\x1B\xC6\x45\x41\x3A\xEF\xF6"
+			  "\x3A\x42\x39\x1A\x39\x14\x5A\x59",
+	}, {
+		.plaintext = "abc",
+		.psize	= 3,
+		.digest	= "\x4E\x24\x48\xA4\xC6\xF4\x86\xBB"
+			  "\x16\xB6\x56\x2C\x73\xB4\x02\x0B"
+			  "\xF3\x04\x3E\x3A\x73\x1B\xCE\x72"
+			  "\x1A\xE1\xB3\x03\xD9\x7E\x6D\x4C"
+			  "\x71\x81\xEE\xBD\xB6\xC5\x7E\x27"
+			  "\x7D\x0E\x34\x95\x71\x14\xCB\xD6",
+	}, {
+		.plaintext = "message digest",
+		.psize	= 14,
+		.digest	= "\x37\x8C\x84\xA4\x12\x6E\x2D\xC6"
+			  "\xE5\x6D\xCC\x74\x58\x37\x7A\xAC"
+			  "\x83\x8D\x00\x03\x22\x30\xF5\x3C"
+			  "\xE1\xF5\x70\x0C\x0F\xFB\x4D\x3B"
+			  "\x84\x21\x55\x76\x59\xEF\x55\xC1"
+			  "\x06\xB4\xB5\x2A\xC5\xA4\xAA\xA6",
+	}, {
+		.plaintext = "abcdefghijklmnopqrstuvwxyz",
+		.psize	= 26,
+		.digest	= "\xF1\xD7\x54\x66\x26\x36\xFF\xE9"
+			  "\x2C\x82\xEB\xB9\x21\x2A\x48\x4A"
+			  "\x8D\x38\x63\x1E\xAD\x42\x38\xF5"
+			  "\x44\x2E\xE1\x3B\x80\x54\xE4\x1B"
+			  "\x08\xBF\x2A\x92\x51\xC3\x0B\x6A"
+			  "\x0B\x8A\xAE\x86\x17\x7A\xB4\xA6",
+	}, {
+		.plaintext = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+			   "abcdefghijklmnopqrstuvwxyz0123456789",
+		.psize	= 62,
+		.digest	= "\xDC\x37\xE0\x08\xCF\x9E\xE6\x9B"
+			  "\xF1\x1F\x00\xED\x9A\xBA\x26\x90"
+			  "\x1D\xD7\xC2\x8C\xDE\xC0\x66\xCC"
+			  "\x6A\xF4\x2E\x40\xF8\x2F\x3A\x1E"
+			  "\x08\xEB\xA2\x66\x29\x12\x9D\x8F"
+			  "\xB7\xCB\x57\x21\x1B\x92\x81\xA6",
+	}, {
+		.plaintext = "1234567890123456789012345678901234567890"
+			   "1234567890123456789012345678901234567890",
+		.psize	= 80,
+		.digest	= "\x46\x6E\xF1\x8B\xAB\xB0\x15\x4D"
+			  "\x25\xB9\xD3\x8A\x64\x14\xF5\xC0"
+			  "\x87\x84\x37\x2B\xCC\xB2\x04\xD6"
+			  "\x54\x9C\x4A\xFA\xDB\x60\x14\x29"
+			  "\x4D\x5B\xD8\xDF\x2A\x6C\x44\xE5"
+			  "\x38\xCD\x04\x7B\x26\x81\xA5\x1A",
+	}, {
+		.plaintext = "abcdbcdecdefdefgefghfghighijhijk",
+		.psize	= 32,
+		.digest	= "\x2A\x98\x7E\xA4\x0F\x91\x70\x61"
+			  "\xF5\xD6\xF0\xA0\xE4\x64\x4F\x48"
+			  "\x8A\x7A\x5A\x52\xDE\xEE\x65\x62"
+			  "\x07\xC5\x62\xF9\x88\xE9\x5C\x69"
+			  "\x16\xBD\xC8\x03\x1B\xC5\xBE\x1B"
+			  "\x7B\x94\x76\x39\xFE\x05\x0B\x56",
+	},
+};
+
+#define WP256_TEST_VECTORS	8
+
+static struct hash_testvec wp256_tv_template[] = {
+	{
+		.plaintext = "",
+		.psize	= 0,
+		.digest	= "\x19\xFA\x61\xD7\x55\x22\xA4\x66"
+			  "\x9B\x44\xE3\x9C\x1D\x2E\x17\x26"
+			  "\xC5\x30\x23\x21\x30\xD4\x07\xF8"
+			  "\x9A\xFE\xE0\x96\x49\x97\xF7\xA7",
+
+
+	}, {
+		.plaintext = "a",
+		.psize	= 1,
+		.digest	= "\x8A\xCA\x26\x02\x79\x2A\xEC\x6F"
+			  "\x11\xA6\x72\x06\x53\x1F\xB7\xD7"
+			  "\xF0\xDF\xF5\x94\x13\x14\x5E\x69"
+			  "\x73\xC4\x50\x01\xD0\x08\x7B\x42",
+	}, {
+		.plaintext = "abc",
+		.psize	= 3,
+		.digest	= "\x4E\x24\x48\xA4\xC6\xF4\x86\xBB"
+			  "\x16\xB6\x56\x2C\x73\xB4\x02\x0B"
+			  "\xF3\x04\x3E\x3A\x73\x1B\xCE\x72"
+			  "\x1A\xE1\xB3\x03\xD9\x7E\x6D\x4C",
+	}, {
+		.plaintext = "message digest",
+		.psize	= 14,
+		.digest	= "\x37\x8C\x84\xA4\x12\x6E\x2D\xC6"
+			  "\xE5\x6D\xCC\x74\x58\x37\x7A\xAC"
+			  "\x83\x8D\x00\x03\x22\x30\xF5\x3C"
+			  "\xE1\xF5\x70\x0C\x0F\xFB\x4D\x3B",
+	}, {
+		.plaintext = "abcdefghijklmnopqrstuvwxyz",
+		.psize	= 26,
+		.digest	= "\xF1\xD7\x54\x66\x26\x36\xFF\xE9"
+			  "\x2C\x82\xEB\xB9\x21\x2A\x48\x4A"
+			  "\x8D\x38\x63\x1E\xAD\x42\x38\xF5"
+			  "\x44\x2E\xE1\x3B\x80\x54\xE4\x1B",
+	}, {
+		.plaintext = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+			   "abcdefghijklmnopqrstuvwxyz0123456789",
+		.psize	= 62,
+		.digest	= "\xDC\x37\xE0\x08\xCF\x9E\xE6\x9B"
+			  "\xF1\x1F\x00\xED\x9A\xBA\x26\x90"
+			  "\x1D\xD7\xC2\x8C\xDE\xC0\x66\xCC"
+			  "\x6A\xF4\x2E\x40\xF8\x2F\x3A\x1E",
+	}, {
+		.plaintext = "1234567890123456789012345678901234567890"
+			   "1234567890123456789012345678901234567890",
+		.psize	= 80,
+		.digest	= "\x46\x6E\xF1\x8B\xAB\xB0\x15\x4D"
+			  "\x25\xB9\xD3\x8A\x64\x14\xF5\xC0"
+			  "\x87\x84\x37\x2B\xCC\xB2\x04\xD6"
+			  "\x54\x9C\x4A\xFA\xDB\x60\x14\x29",
+	}, {
+		.plaintext = "abcdbcdecdefdefgefghfghighijhijk",
+		.psize	= 32,
+		.digest	= "\x2A\x98\x7E\xA4\x0F\x91\x70\x61"
+			  "\xF5\xD6\xF0\xA0\xE4\x64\x4F\x48"
+			  "\x8A\x7A\x5A\x52\xDE\xEE\x65\x62"
+			  "\x07\xC5\x62\xF9\x88\xE9\x5C\x69",
+	},
+};
+
+/*
+ * TIGER test vectors from Tiger website
+ */
+#define TGR192_TEST_VECTORS	6
+
+static struct hash_testvec tgr192_tv_template[] = {
+	{
+		.plaintext = "",
+		.psize	= 0,
+		.digest = "\x24\xf0\x13\x0c\x63\xac\x93\x32"
+			  "\x16\x16\x6e\x76\xb1\xbb\x92\x5f"
+			  "\xf3\x73\xde\x2d\x49\x58\x4e\x7a",
+	}, {
+		.plaintext = "abc",
+		.psize	= 3,
+		.digest = "\xf2\x58\xc1\xe8\x84\x14\xab\x2a"
+			  "\x52\x7a\xb5\x41\xff\xc5\xb8\xbf"
+			  "\x93\x5f\x7b\x95\x1c\x13\x29\x51",
+	}, {
+		.plaintext = "Tiger",
+		.psize	= 5,
+		.digest = "\x9f\x00\xf5\x99\x07\x23\x00\xdd"
+			  "\x27\x6a\xbb\x38\xc8\xeb\x6d\xec"
+			  "\x37\x79\x0c\x11\x6f\x9d\x2b\xdf",
+	}, {
+		.plaintext = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-",
+		.psize	= 64,
+		.digest = "\x87\xfb\x2a\x90\x83\x85\x1c\xf7"
+			  "\x47\x0d\x2c\xf8\x10\xe6\xdf\x9e"
+			  "\xb5\x86\x44\x50\x34\xa5\xa3\x86",
+	}, {
+		.plaintext = "ABCDEFGHIJKLMNOPQRSTUVWXYZ=abcdefghijklmnopqrstuvwxyz+0123456789",
+		.psize	= 64,
+		.digest = "\x46\x7d\xb8\x08\x63\xeb\xce\x48"
+			  "\x8d\xf1\xcd\x12\x61\x65\x5d\xe9"
+			  "\x57\x89\x65\x65\x97\x5f\x91\x97",
+	}, {
+		.plaintext = "Tiger - A Fast New Hash Function, "
+			   "by Ross Anderson and Eli Biham, "
+			   "proceedings of Fast Software Encryption 3, "
+			   "Cambridge, 1996.",
+		.psize  = 125,
+		.digest = "\x3d\x9a\xeb\x03\xd1\xbd\x1a\x63"
+			  "\x57\xb2\x77\x4d\xfd\x6d\x5b\x24"
+			  "\xdd\x68\x15\x1d\x50\x39\x74\xfc",
+	},
+};
+
+#define TGR160_TEST_VECTORS	6
+
+static struct hash_testvec tgr160_tv_template[] = {
+	{
+		.plaintext = "",
+		.psize	= 0,
+		.digest = "\x24\xf0\x13\x0c\x63\xac\x93\x32"
+			  "\x16\x16\x6e\x76\xb1\xbb\x92\x5f"
+			  "\xf3\x73\xde\x2d",
+	}, {
+		.plaintext = "abc",
+		.psize	= 3,
+		.digest = "\xf2\x58\xc1\xe8\x84\x14\xab\x2a"
+			  "\x52\x7a\xb5\x41\xff\xc5\xb8\xbf"
+			  "\x93\x5f\x7b\x95",
+	}, {
+		.plaintext = "Tiger",
+		.psize	= 5,
+		.digest = "\x9f\x00\xf5\x99\x07\x23\x00\xdd"
+			  "\x27\x6a\xbb\x38\xc8\xeb\x6d\xec"
+			  "\x37\x79\x0c\x11",
+	}, {
+		.plaintext = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-",
+		.psize	= 64,
+		.digest = "\x87\xfb\x2a\x90\x83\x85\x1c\xf7"
+			  "\x47\x0d\x2c\xf8\x10\xe6\xdf\x9e"
+			  "\xb5\x86\x44\x50",
+	}, {
+		.plaintext = "ABCDEFGHIJKLMNOPQRSTUVWXYZ=abcdefghijklmnopqrstuvwxyz+0123456789",
+		.psize	= 64,
+		.digest = "\x46\x7d\xb8\x08\x63\xeb\xce\x48"
+			  "\x8d\xf1\xcd\x12\x61\x65\x5d\xe9"
+			  "\x57\x89\x65\x65",
+	}, {
+		.plaintext = "Tiger - A Fast New Hash Function, "
+			   "by Ross Anderson and Eli Biham, "
+			   "proceedings of Fast Software Encryption 3, "
+			   "Cambridge, 1996.",
+		.psize  = 125,
+		.digest = "\x3d\x9a\xeb\x03\xd1\xbd\x1a\x63"
+			  "\x57\xb2\x77\x4d\xfd\x6d\x5b\x24"
+			  "\xdd\x68\x15\x1d",
+	},
+};
+
+#define TGR128_TEST_VECTORS	6
+
+static struct hash_testvec tgr128_tv_template[] = {
+	{
+		.plaintext = "",
+		.psize	= 0,
+		.digest = "\x24\xf0\x13\x0c\x63\xac\x93\x32"
+			  "\x16\x16\x6e\x76\xb1\xbb\x92\x5f",
+	}, {
+		.plaintext = "abc",
+		.psize	= 3,
+		.digest = "\xf2\x58\xc1\xe8\x84\x14\xab\x2a"
+			  "\x52\x7a\xb5\x41\xff\xc5\xb8\xbf",
+	}, {
+		.plaintext = "Tiger",
+		.psize	= 5,
+		.digest = "\x9f\x00\xf5\x99\x07\x23\x00\xdd"
+			  "\x27\x6a\xbb\x38\xc8\xeb\x6d\xec",
+	}, {
+		.plaintext = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-",
+		.psize	= 64,
+		.digest = "\x87\xfb\x2a\x90\x83\x85\x1c\xf7"
+			  "\x47\x0d\x2c\xf8\x10\xe6\xdf\x9e",
+	}, {
+		.plaintext = "ABCDEFGHIJKLMNOPQRSTUVWXYZ=abcdefghijklmnopqrstuvwxyz+0123456789",
+		.psize	= 64,
+		.digest = "\x46\x7d\xb8\x08\x63\xeb\xce\x48"
+			  "\x8d\xf1\xcd\x12\x61\x65\x5d\xe9",
+	}, {
+		.plaintext = "Tiger - A Fast New Hash Function, "
+			   "by Ross Anderson and Eli Biham, "
+			   "proceedings of Fast Software Encryption 3, "
+			   "Cambridge, 1996.",
+		.psize  = 125,
+		.digest = "\x3d\x9a\xeb\x03\xd1\xbd\x1a\x63"
+			  "\x57\xb2\x77\x4d\xfd\x6d\x5b\x24",
+	},
+};
+
+/*
+ * HMAC-MD5 test vectors from RFC2202
+ * (These need to be fixed to not use strlen).
+ */
+#define HMAC_MD5_TEST_VECTORS	7
+
+static struct hash_testvec hmac_md5_tv_template[] =
+{
+	{
+		.key	= "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b",
+		.ksize	= 16,
+		.plaintext = "Hi There",
+		.psize	= 8,
+		.digest	= "\x92\x94\x72\x7a\x36\x38\xbb\x1c"
+			  "\x13\xf4\x8e\xf8\x15\x8b\xfc\x9d",
+	}, {
+		.key	= "Jefe",
+		.ksize	= 4,
+		.plaintext = "what do ya want for nothing?",
+		.psize	= 28,
+		.digest	= "\x75\x0c\x78\x3e\x6a\xb0\xb5\x03"
+			  "\xea\xa8\x6e\x31\x0a\x5d\xb7\x38",
+		.np	= 2,
+		.tap	= {14, 14}
+	}, {
+		.key	= "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa",
+		.ksize	= 16,
+		.plaintext = "\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd"
+			"\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd"
+			"\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd"
+			"\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd",
+		.psize	= 50,
+		.digest	= "\x56\xbe\x34\x52\x1d\x14\x4c\x88"
+			  "\xdb\xb8\xc7\x33\xf0\xe8\xb3\xf6",
+	}, {
+		.key	= "\x01\x02\x03\x04\x05\x06\x07\x08"
+			  "\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10"
+			  "\x11\x12\x13\x14\x15\x16\x17\x18\x19",
+		.ksize	= 25,
+		.plaintext = "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"
+			"\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"
+			"\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"
+			"\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd",
+		.psize	= 50,
+		.digest	= "\x69\x7e\xaf\x0a\xca\x3a\x3a\xea"
+			  "\x3a\x75\x16\x47\x46\xff\xaa\x79",
+	}, {
+		.key	= "\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c",
+		.ksize	= 16,
+		.plaintext = "Test With Truncation",
+		.psize	= 20,
+		.digest	= "\x56\x46\x1e\xf2\x34\x2e\xdc\x00"
+			  "\xf9\xba\xb9\x95\x69\x0e\xfd\x4c",
+	}, {
+		.key	= "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			"\xaa\xaa",
+		.ksize	= 80,
+		.plaintext = "Test Using Larger Than Block-Size Key - Hash Key First",
+		.psize	= 54,
+		.digest	= "\x6b\x1a\xb7\xfe\x4b\xd7\xbf\x8f"
+			  "\x0b\x62\xe6\xce\x61\xb9\xd0\xcd",
+	}, {
+		.key	= "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			"\xaa\xaa",
+		.ksize	= 80,
+		.plaintext = "Test Using Larger Than Block-Size Key and Larger Than One "
+			   "Block-Size Data",
+		.psize	= 73,
+		.digest	= "\x6f\x63\x0f\xad\x67\xcd\xa0\xee"
+			  "\x1f\xb1\xf5\x62\xdb\x3a\xa5\x3e",
+	},
+};
+
+/*
+ * HMAC-RIPEMD128 test vectors from RFC2286
+ */
+#define HMAC_RMD128_TEST_VECTORS	7
+
+static struct hash_testvec hmac_rmd128_tv_template[] = {
+	{
+		.key	= "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b",
+		.ksize	= 16,
+		.plaintext = "Hi There",
+		.psize	= 8,
+		.digest	= "\xfb\xf6\x1f\x94\x92\xaa\x4b\xbf"
+			  "\x81\xc1\x72\xe8\x4e\x07\x34\xdb",
+	}, {
+		.key	= "Jefe",
+		.ksize	= 4,
+		.plaintext = "what do ya want for nothing?",
+		.psize	= 28,
+		.digest	= "\x87\x5f\x82\x88\x62\xb6\xb3\x34"
+			  "\xb4\x27\xc5\x5f\x9f\x7f\xf0\x9b",
+		.np	= 2,
+		.tap	= { 14, 14 },
+	}, {
+		.key	= "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa",
+		.ksize	= 16,
+		.plaintext = "\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd"
+			"\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd"
+			"\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd"
+			"\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd",
+		.psize	= 50,
+		.digest	= "\x09\xf0\xb2\x84\x6d\x2f\x54\x3d"
+			  "\xa3\x63\xcb\xec\x8d\x62\xa3\x8d",
+	}, {
+		.key	= "\x01\x02\x03\x04\x05\x06\x07\x08"
+			  "\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10"
+			  "\x11\x12\x13\x14\x15\x16\x17\x18\x19",
+		.ksize	= 25,
+		.plaintext = "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"
+			"\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"
+			"\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"
+			"\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd",
+		.psize	= 50,
+		.digest	= "\xbd\xbb\xd7\xcf\x03\xe4\x4b\x5a"
+			  "\xa6\x0a\xf8\x15\xbe\x4d\x22\x94",
+	}, {
+		.key	= "\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c",
+		.ksize	= 16,
+		.plaintext = "Test With Truncation",
+		.psize	= 20,
+		.digest	= "\xe7\x98\x08\xf2\x4b\x25\xfd\x03"
+			  "\x1c\x15\x5f\x0d\x55\x1d\x9a\x3a",
+	}, {
+		.key	= "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			"\xaa\xaa",
+		.ksize	= 80,
+		.plaintext = "Test Using Larger Than Block-Size Key - Hash Key First",
+		.psize	= 54,
+		.digest	= "\xdc\x73\x29\x28\xde\x98\x10\x4a"
+			  "\x1f\x59\xd3\x73\xc1\x50\xac\xbb",
+	}, {
+		.key	= "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			"\xaa\xaa",
+		.ksize	= 80,
+		.plaintext = "Test Using Larger Than Block-Size Key and Larger Than One "
+			   "Block-Size Data",
+		.psize	= 73,
+		.digest	= "\x5c\x6b\xec\x96\x79\x3e\x16\xd4"
+			  "\x06\x90\xc2\x37\x63\x5f\x30\xc5",
+	},
+};
+
+/*
+ * HMAC-RIPEMD160 test vectors from RFC2286
+ */
+#define HMAC_RMD160_TEST_VECTORS	7
+
+static struct hash_testvec hmac_rmd160_tv_template[] = {
+	{
+		.key	= "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b",
+		.ksize	= 20,
+		.plaintext = "Hi There",
+		.psize	= 8,
+		.digest	= "\x24\xcb\x4b\xd6\x7d\x20\xfc\x1a\x5d\x2e"
+			  "\xd7\x73\x2d\xcc\x39\x37\x7f\x0a\x56\x68",
+	}, {
+		.key	= "Jefe",
+		.ksize	= 4,
+		.plaintext = "what do ya want for nothing?",
+		.psize	= 28,
+		.digest	= "\xdd\xa6\xc0\x21\x3a\x48\x5a\x9e\x24\xf4"
+			  "\x74\x20\x64\xa7\xf0\x33\xb4\x3c\x40\x69",
+		.np	= 2,
+		.tap	= { 14, 14 },
+	}, {
+		.key	= "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa",
+		.ksize	= 20,
+		.plaintext = "\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd"
+			"\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd"
+			"\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd"
+			"\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd",
+		.psize	= 50,
+		.digest	= "\xb0\xb1\x05\x36\x0d\xe7\x59\x96\x0a\xb4"
+			  "\xf3\x52\x98\xe1\x16\xe2\x95\xd8\xe7\xc1",
+	}, {
+		.key	= "\x01\x02\x03\x04\x05\x06\x07\x08"
+			  "\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10"
+			  "\x11\x12\x13\x14\x15\x16\x17\x18\x19",
+		.ksize	= 25,
+		.plaintext = "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"
+			"\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"
+			"\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"
+			"\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd",
+		.psize	= 50,
+		.digest	= "\xd5\xca\x86\x2f\x4d\x21\xd5\xe6\x10\xe1"
+			  "\x8b\x4c\xf1\xbe\xb9\x7a\x43\x65\xec\xf4",
+	}, {
+		.key	= "\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c",
+		.ksize	= 20,
+		.plaintext = "Test With Truncation",
+		.psize	= 20,
+		.digest	= "\x76\x19\x69\x39\x78\xf9\x1d\x90\x53\x9a"
+			  "\xe7\x86\x50\x0f\xf3\xd8\xe0\x51\x8e\x39",
+	}, {
+		.key	= "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			"\xaa\xaa",
+		.ksize	= 80,
+		.plaintext = "Test Using Larger Than Block-Size Key - Hash Key First",
+		.psize	= 54,
+		.digest	= "\x64\x66\xca\x07\xac\x5e\xac\x29\xe1\xbd"
+			  "\x52\x3e\x5a\xda\x76\x05\xb7\x91\xfd\x8b",
+	}, {
+		.key	= "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			"\xaa\xaa",
+		.ksize	= 80,
+		.plaintext = "Test Using Larger Than Block-Size Key and Larger Than One "
+			   "Block-Size Data",
+		.psize	= 73,
+		.digest	= "\x69\xea\x60\x79\x8d\x71\x61\x6c\xce\x5f"
+			  "\xd0\x87\x1e\x23\x75\x4c\xd7\x5d\x5a\x0a",
+	},
+};
+
+/*
+ * HMAC-SHA1 test vectors from RFC2202
+ */
+#define HMAC_SHA1_TEST_VECTORS	7
+
+static struct hash_testvec hmac_sha1_tv_template[] = {
+	{
+		.key	= "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b",
+		.ksize	= 20,
+		.plaintext = "Hi There",
+		.psize	= 8,
+		.digest	= "\xb6\x17\x31\x86\x55\x05\x72\x64"
+			  "\xe2\x8b\xc0\xb6\xfb\x37\x8c\x8e\xf1"
+			  "\x46\xbe",
+	}, {
+		.key	= "Jefe",
+		.ksize	= 4,
+		.plaintext = "what do ya want for nothing?",
+		.psize	= 28,
+		.digest	= "\xef\xfc\xdf\x6a\xe5\xeb\x2f\xa2\xd2\x74"
+			  "\x16\xd5\xf1\x84\xdf\x9c\x25\x9a\x7c\x79",
+		.np	= 2,
+		.tap	= { 14, 14 }
+	}, {
+		.key	= "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa",
+		.ksize	= 20,
+		.plaintext = "\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd"
+			"\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd"
+			"\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd"
+			"\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd",
+		.psize	= 50,
+		.digest	= "\x12\x5d\x73\x42\xb9\xac\x11\xcd\x91\xa3"
+			  "\x9a\xf4\x8a\xa1\x7b\x4f\x63\xf1\x75\xd3",
+	}, {
+		.key	= "\x01\x02\x03\x04\x05\x06\x07\x08"
+			  "\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10"
+			  "\x11\x12\x13\x14\x15\x16\x17\x18\x19",
+		.ksize	= 25,
+		.plaintext = "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"
+			"\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"
+			"\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"
+			"\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd",
+		.psize	= 50,
+		.digest	= "\x4c\x90\x07\xf4\x02\x62\x50\xc6\xbc\x84"
+			  "\x14\xf9\xbf\x50\xc8\x6c\x2d\x72\x35\xda",
+	}, {
+		.key	= "\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c",
+		.ksize	= 20,
+		.plaintext = "Test With Truncation",
+		.psize	= 20,
+		.digest	= "\x4c\x1a\x03\x42\x4b\x55\xe0\x7f\xe7\xf2"
+			  "\x7b\xe1\xd5\x8b\xb9\x32\x4a\x9a\x5a\x04",
+	}, {
+		.key	= "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			"\xaa\xaa",
+		.ksize	= 80,
+		.plaintext = "Test Using Larger Than Block-Size Key - Hash Key First",
+		.psize	= 54,
+		.digest	= "\xaa\x4a\xe5\xe1\x52\x72\xd0\x0e\x95\x70"
+			  "\x56\x37\xce\x8a\x3b\x55\xed\x40\x21\x12",
+	}, {
+		.key	= "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			"\xaa\xaa",
+		.ksize	= 80,
+		.plaintext = "Test Using Larger Than Block-Size Key and Larger Than One "
+			   "Block-Size Data",
+		.psize	= 73,
+		.digest	= "\xe8\xe9\x9d\x0f\x45\x23\x7d\x78\x6d\x6b"
+			  "\xba\xa7\x96\x5c\x78\x08\xbb\xff\x1a\x91",
+	},
+};
+
+
+/*
+ * SHA224 HMAC test vectors from RFC4231
+ */
+#define HMAC_SHA224_TEST_VECTORS    4
+
+static struct hash_testvec hmac_sha224_tv_template[] = {
+	{
+		.key    = "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b"
+			"\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b"
+			"\x0b\x0b\x0b\x0b",
+		.ksize  = 20,
+		/*  ("Hi There") */
+		.plaintext = "\x48\x69\x20\x54\x68\x65\x72\x65",
+		.psize  = 8,
+		.digest = "\x89\x6f\xb1\x12\x8a\xbb\xdf\x19"
+			"\x68\x32\x10\x7c\xd4\x9d\xf3\x3f"
+			"\x47\xb4\xb1\x16\x99\x12\xba\x4f"
+			"\x53\x68\x4b\x22",
+	}, {
+		.key    = "Jefe",
+		.ksize  = 4,
+		/* ("what do ya want for nothing?") */
+		.plaintext = "\x77\x68\x61\x74\x20\x64\x6f\x20"
+			"\x79\x61\x20\x77\x61\x6e\x74\x20"
+			"\x66\x6f\x72\x20\x6e\x6f\x74\x68"
+			"\x69\x6e\x67\x3f",
+		.psize  = 28,
+		.digest = "\xa3\x0e\x01\x09\x8b\xc6\xdb\xbf"
+			"\x45\x69\x0f\x3a\x7e\x9e\x6d\x0f"
+			"\x8b\xbe\xa2\xa3\x9e\x61\x48\x00"
+			"\x8f\xd0\x5e\x44",
+		.np = 4,
+		.tap    = { 7, 7, 7, 7 }
+	}, {
+		.key    = "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			"\xaa\xaa\xaa",
+		.ksize  = 131,
+		/* ("Test Using Larger Than Block-Size Key - Hash Key First") */
+		.plaintext = "\x54\x65\x73\x74\x20\x55\x73\x69"
+			"\x6e\x67\x20\x4c\x61\x72\x67\x65"
+			"\x72\x20\x54\x68\x61\x6e\x20\x42"
+			"\x6c\x6f\x63\x6b\x2d\x53\x69\x7a"
+			"\x65\x20\x4b\x65\x79\x20\x2d\x20"
+			"\x48\x61\x73\x68\x20\x4b\x65\x79"
+			"\x20\x46\x69\x72\x73\x74",
+		.psize  = 54,
+		.digest = "\x95\xe9\xa0\xdb\x96\x20\x95\xad"
+			"\xae\xbe\x9b\x2d\x6f\x0d\xbc\xe2"
+			"\xd4\x99\xf1\x12\xf2\xd2\xb7\x27"
+			"\x3f\xa6\x87\x0e",
+	}, {
+		.key    = "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			"\xaa\xaa\xaa",
+		.ksize  = 131,
+		/* ("This is a test using a larger than block-size key and a")
+		(" larger than block-size data. The key needs to be")
+			(" hashed before being used by the HMAC algorithm.") */
+		.plaintext = "\x54\x68\x69\x73\x20\x69\x73\x20"
+			"\x61\x20\x74\x65\x73\x74\x20\x75"
+			"\x73\x69\x6e\x67\x20\x61\x20\x6c"
+			"\x61\x72\x67\x65\x72\x20\x74\x68"
+			"\x61\x6e\x20\x62\x6c\x6f\x63\x6b"
+			"\x2d\x73\x69\x7a\x65\x20\x6b\x65"
+			"\x79\x20\x61\x6e\x64\x20\x61\x20"
+			"\x6c\x61\x72\x67\x65\x72\x20\x74"
+			"\x68\x61\x6e\x20\x62\x6c\x6f\x63"
+			"\x6b\x2d\x73\x69\x7a\x65\x20\x64"
+			"\x61\x74\x61\x2e\x20\x54\x68\x65"
+			"\x20\x6b\x65\x79\x20\x6e\x65\x65"
+			"\x64\x73\x20\x74\x6f\x20\x62\x65"
+			"\x20\x68\x61\x73\x68\x65\x64\x20"
+			"\x62\x65\x66\x6f\x72\x65\x20\x62"
+			"\x65\x69\x6e\x67\x20\x75\x73\x65"
+			"\x64\x20\x62\x79\x20\x74\x68\x65"
+			"\x20\x48\x4d\x41\x43\x20\x61\x6c"
+			"\x67\x6f\x72\x69\x74\x68\x6d\x2e",
+		.psize  = 152,
+		.digest = "\x3a\x85\x41\x66\xac\x5d\x9f\x02"
+			"\x3f\x54\xd5\x17\xd0\xb3\x9d\xbd"
+			"\x94\x67\x70\xdb\x9c\x2b\x95\xc9"
+			"\xf6\xf5\x65\xd1",
+	},
+};
+
+/*
+ * HMAC-SHA256 test vectors from
+ * draft-ietf-ipsec-ciph-sha-256-01.txt
+ */
+#define HMAC_SHA256_TEST_VECTORS	10
+
+static struct hash_testvec hmac_sha256_tv_template[] = {
+	{
+		.key	= "\x01\x02\x03\x04\x05\x06\x07\x08"
+			  "\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10"
+			  "\x11\x12\x13\x14\x15\x16\x17\x18"
+			  "\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20",
+		.ksize	= 32,
+		.plaintext = "abc",
+		.psize	= 3,
+		.digest	= "\xa2\x1b\x1f\x5d\x4c\xf4\xf7\x3a"
+			  "\x4d\xd9\x39\x75\x0f\x7a\x06\x6a"
+			  "\x7f\x98\xcc\x13\x1c\xb1\x6a\x66"
+			  "\x92\x75\x90\x21\xcf\xab\x81\x81",
+	}, {
+		.key	= "\x01\x02\x03\x04\x05\x06\x07\x08"
+			  "\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10"
+			  "\x11\x12\x13\x14\x15\x16\x17\x18"
+			  "\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20",
+		.ksize	= 32,
+		.plaintext = "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
+		.psize	= 56,
+		.digest	= "\x10\x4f\xdc\x12\x57\x32\x8f\x08"
+			  "\x18\x4b\xa7\x31\x31\xc5\x3c\xae"
+			  "\xe6\x98\xe3\x61\x19\x42\x11\x49"
+			  "\xea\x8c\x71\x24\x56\x69\x7d\x30",
+	}, {
+		.key	= "\x01\x02\x03\x04\x05\x06\x07\x08"
+			  "\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10"
+			  "\x11\x12\x13\x14\x15\x16\x17\x18"
+			  "\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20",
+		.ksize	= 32,
+		.plaintext = "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
+			   "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
+		.psize	= 112,
+		.digest	= "\x47\x03\x05\xfc\x7e\x40\xfe\x34"
+			  "\xd3\xee\xb3\xe7\x73\xd9\x5a\xab"
+			  "\x73\xac\xf0\xfd\x06\x04\x47\xa5"
+			  "\xeb\x45\x95\xbf\x33\xa9\xd1\xa3",
+	}, {
+		.key	= "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b"
+			"\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b"
+			"\x0b\x0b\x0b\x0b\x0b\x0b",
+		.ksize	= 32,
+		.plaintext = "Hi There",
+		.psize	= 8,
+		.digest	= "\x19\x8a\x60\x7e\xb4\x4b\xfb\xc6"
+			  "\x99\x03\xa0\xf1\xcf\x2b\xbd\xc5"
+			  "\xba\x0a\xa3\xf3\xd9\xae\x3c\x1c"
+			  "\x7a\x3b\x16\x96\xa0\xb6\x8c\xf7",
+	}, {
+		.key	= "Jefe",
+		.ksize	= 4,
+		.plaintext = "what do ya want for nothing?",
+		.psize	= 28,
+		.digest	= "\x5b\xdc\xc1\x46\xbf\x60\x75\x4e"
+			  "\x6a\x04\x24\x26\x08\x95\x75\xc7"
+			  "\x5a\x00\x3f\x08\x9d\x27\x39\x83"
+			  "\x9d\xec\x58\xb9\x64\xec\x38\x43",
+		.np	= 2,
+		.tap	= { 14, 14 }
+	}, {
+		.key	= "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa",
+		.ksize	= 32,
+		.plaintext = "\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd"
+			"\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd"
+			"\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd"
+			"\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd",
+		.psize	= 50,
+		.digest	= "\xcd\xcb\x12\x20\xd1\xec\xcc\xea"
+			  "\x91\xe5\x3a\xba\x30\x92\xf9\x62"
+			  "\xe5\x49\xfe\x6c\xe9\xed\x7f\xdc"
+			  "\x43\x19\x1f\xbd\xe4\x5c\x30\xb0",
+	}, {
+		.key	= "\x01\x02\x03\x04\x05\x06\x07\x08"
+			  "\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10"
+			  "\x11\x12\x13\x14\x15\x16\x17\x18"
+			  "\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20"
+			  "\x21\x22\x23\x24\x25",
+		.ksize	= 37,
+		.plaintext = "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"
+			"\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"
+			"\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"
+			"\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd",
+		.psize	= 50,
+		.digest	= "\xd4\x63\x3c\x17\xf6\xfb\x8d\x74"
+			  "\x4c\x66\xde\xe0\xf8\xf0\x74\x55"
+			  "\x6e\xc4\xaf\x55\xef\x07\x99\x85"
+			  "\x41\x46\x8e\xb4\x9b\xd2\xe9\x17",
+	}, {
+		.key	= "\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c"
+			"\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c"
+			"\x0c\x0c\x0c\x0c\x0c\x0c",
+		.ksize	= 32,
+		.plaintext = "Test With Truncation",
+		.psize	= 20,
+		.digest	= "\x75\x46\xaf\x01\x84\x1f\xc0\x9b"
+			  "\x1a\xb9\xc3\x74\x9a\x5f\x1c\x17"
+			  "\xd4\xf5\x89\x66\x8a\x58\x7b\x27"
+			  "\x00\xa9\xc9\x7c\x11\x93\xcf\x42",
+	}, {
+		.key	= "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			"\xaa\xaa",
+		.ksize	= 80,
+		.plaintext = "Test Using Larger Than Block-Size Key - Hash Key First",
+		.psize	= 54,
+		.digest	= "\x69\x53\x02\x5e\xd9\x6f\x0c\x09"
+			  "\xf8\x0a\x96\xf7\x8e\x65\x38\xdb"
+			  "\xe2\xe7\xb8\x20\xe3\xdd\x97\x0e"
+			  "\x7d\xdd\x39\x09\x1b\x32\x35\x2f",
+	}, {
+		.key	= "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			"\xaa\xaa",
+		.ksize	= 80,
+		.plaintext = "Test Using Larger Than Block-Size Key and Larger Than "
+			   "One Block-Size Data",
+		.psize	= 73,
+		.digest	= "\x63\x55\xac\x22\xe8\x90\xd0\xa3"
+			  "\xc8\x48\x1a\x5c\xa4\x82\x5b\xc8"
+			  "\x84\xd3\xe7\xa1\xff\x98\xa2\xfc"
+			  "\x2a\xc7\xd8\xe0\x64\xc3\xb2\xe6",
+	},
+};
+
+#define XCBC_AES_TEST_VECTORS 6
+
+static struct hash_testvec aes_xcbc128_tv_template[] = {
+	{
+		.key	= "\x00\x01\x02\x03\x04\x05\x06\x07"
+			  "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
+		.plaintext = zeroed_string,
+		.digest = "\x75\xf0\x25\x1d\x52\x8a\xc0\x1c"
+			  "\x45\x73\xdf\xd5\x84\xd7\x9f\x29",
+		.psize	= 0,
+		.ksize	= 16,
+	}, {
+		.key	= "\x00\x01\x02\x03\x04\x05\x06\x07"
+			  "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
+		.plaintext = "\x00\x01\x02",
+		.digest	= "\x5b\x37\x65\x80\xae\x2f\x19\xaf"
+			  "\xe7\x21\x9c\xee\xf1\x72\x75\x6f",
+		.psize	= 3,
+		.ksize	= 16,
+	} , {
+		.key	= "\x00\x01\x02\x03\x04\x05\x06\x07"
+			  "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
+		.plaintext = "\x00\x01\x02\x03\x04\x05\x06\x07"
+			     "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
+		.digest = "\xd2\xa2\x46\xfa\x34\x9b\x68\xa7"
+			  "\x99\x98\xa4\x39\x4f\xf7\xa2\x63",
+		.psize	= 16,
+		.ksize	= 16,
+	}, {
+		.key	= "\x00\x01\x02\x03\x04\x05\x06\x07"
+			  "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
+		.plaintext = "\x00\x01\x02\x03\x04\x05\x06\x07"
+			     "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+			     "\x10\x11\x12\x13",
+		.digest = "\x47\xf5\x1b\x45\x64\x96\x62\x15"
+			  "\xb8\x98\x5c\x63\x05\x5e\xd3\x08",
+		.tap	= { 10, 10 },
+		.psize	= 20,
+		.np	= 2,
+		.ksize	= 16,
+	}, {
+		.key	= "\x00\x01\x02\x03\x04\x05\x06\x07"
+			  "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
+		.plaintext = "\x00\x01\x02\x03\x04\x05\x06\x07"
+			     "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+			     "\x10\x11\x12\x13\x14\x15\x16\x17"
+			     "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f",
+		.digest = "\xf5\x4f\x0e\xc8\xd2\xb9\xf3\xd3"
+			  "\x68\x07\x73\x4b\xd5\x28\x3f\xd4",
+		.psize	= 32,
+		.ksize	= 16,
+	}, {
+		.key	= "\x00\x01\x02\x03\x04\x05\x06\x07"
+			  "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
+		.plaintext = "\x00\x01\x02\x03\x04\x05\x06\x07"
+			     "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+			     "\x10\x11\x12\x13\x14\x15\x16\x17"
+			     "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
+			     "\x20\x21",
+		.digest = "\xbe\xcb\xb3\xbc\xcd\xb5\x18\xa3"
+			  "\x06\x77\xd5\x48\x1f\xb6\xb4\xd8",
+		.tap	= { 17, 17 },
+		.psize	= 34,
+		.np	= 2,
+		.ksize	= 16,
+	}
+};
+
+/*
+ * SHA384 HMAC test vectors from RFC4231
+ */
+
+#define HMAC_SHA384_TEST_VECTORS	4
+
+static struct hash_testvec hmac_sha384_tv_template[] = {
+	{
+		.key	= "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b"
+			  "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b"
+			  "\x0b\x0b\x0b\x0b",
+		.ksize	= 20,
+		.plaintext = "Hi There",
+		.psize	= 8,
+		.digest	= "\xaf\xd0\x39\x44\xd8\x48\x95\x62"
+			  "\x6b\x08\x25\xf4\xab\x46\x90\x7f"
+			  "\x15\xf9\xda\xdb\xe4\x10\x1e\xc6"
+			  "\x82\xaa\x03\x4c\x7c\xeb\xc5\x9c"
+			  "\xfa\xea\x9e\xa9\x07\x6e\xde\x7f"
+			  "\x4a\xf1\x52\xe8\xb2\xfa\x9c\xb6",
+	}, {
+		.key	= "Jefe",
+		.ksize	= 4,
+		.plaintext = "what do ya want for nothing?",
+		.psize	= 28,
+		.digest	= "\xaf\x45\xd2\xe3\x76\x48\x40\x31"
+			  "\x61\x7f\x78\xd2\xb5\x8a\x6b\x1b"
+			  "\x9c\x7e\xf4\x64\xf5\xa0\x1b\x47"
+			  "\xe4\x2e\xc3\x73\x63\x22\x44\x5e"
+			  "\x8e\x22\x40\xca\x5e\x69\xe2\xc7"
+			  "\x8b\x32\x39\xec\xfa\xb2\x16\x49",
+		.np	= 4,
+		.tap	= { 7, 7, 7, 7 }
+	}, {
+		.key	= "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			  "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			  "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			  "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			  "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			  "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			  "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			  "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			  "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			  "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			  "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			  "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			  "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			  "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			  "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			  "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			  "\xaa\xaa\xaa",
+		.ksize	= 131,
+		.plaintext = "Test Using Larger Than Block-Siz"
+			   "e Key - Hash Key First",
+		.psize	= 54,
+		.digest	= "\x4e\xce\x08\x44\x85\x81\x3e\x90"
+			  "\x88\xd2\xc6\x3a\x04\x1b\xc5\xb4"
+			  "\x4f\x9e\xf1\x01\x2a\x2b\x58\x8f"
+			  "\x3c\xd1\x1f\x05\x03\x3a\xc4\xc6"
+			  "\x0c\x2e\xf6\xab\x40\x30\xfe\x82"
+			  "\x96\x24\x8d\xf1\x63\xf4\x49\x52",
+	}, {
+		.key	= "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			  "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			  "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			  "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			  "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			  "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			  "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			  "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			  "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			  "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			  "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			  "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			  "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			  "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			  "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			  "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			  "\xaa\xaa\xaa",
+		.ksize	= 131,
+		.plaintext = "This is a test u"
+			   "sing a larger th"
+			   "an block-size ke"
+			   "y and a larger t"
+			   "han block-size d"
+			   "ata. The key nee"
+			   "ds to be hashed "
+			   "before being use"
+			   "d by the HMAC al"
+			   "gorithm.",
+		.psize	= 152,
+		.digest	= "\x66\x17\x17\x8e\x94\x1f\x02\x0d"
+			  "\x35\x1e\x2f\x25\x4e\x8f\xd3\x2c"
+			  "\x60\x24\x20\xfe\xb0\xb8\xfb\x9a"
+			  "\xdc\xce\xbb\x82\x46\x1e\x99\xc5"
+			  "\xa6\x78\xcc\x31\xe7\x99\x17\x6d"
+			  "\x38\x60\xe6\x11\x0c\x46\x52\x3e",
+	},
+};
+
+/*
+ * SHA512 HMAC test vectors from RFC4231
+ */
+
+#define HMAC_SHA512_TEST_VECTORS	4
+
+static struct hash_testvec hmac_sha512_tv_template[] = {
+	{
+		.key	= "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b"
+			  "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b"
+			  "\x0b\x0b\x0b\x0b",
+		.ksize	= 20,
+		.plaintext = "Hi There",
+		.psize	= 8,
+		.digest	= "\x87\xaa\x7c\xde\xa5\xef\x61\x9d"
+			  "\x4f\xf0\xb4\x24\x1a\x1d\x6c\xb0"
+			  "\x23\x79\xf4\xe2\xce\x4e\xc2\x78"
+			  "\x7a\xd0\xb3\x05\x45\xe1\x7c\xde"
+			  "\xda\xa8\x33\xb7\xd6\xb8\xa7\x02"
+			  "\x03\x8b\x27\x4e\xae\xa3\xf4\xe4"
+			  "\xbe\x9d\x91\x4e\xeb\x61\xf1\x70"
+			  "\x2e\x69\x6c\x20\x3a\x12\x68\x54",
+	}, {
+		.key	= "Jefe",
+		.ksize	= 4,
+		.plaintext = "what do ya want for nothing?",
+		.psize	= 28,
+		.digest	= "\x16\x4b\x7a\x7b\xfc\xf8\x19\xe2"
+			  "\xe3\x95\xfb\xe7\x3b\x56\xe0\xa3"
+			  "\x87\xbd\x64\x22\x2e\x83\x1f\xd6"
+			  "\x10\x27\x0c\xd7\xea\x25\x05\x54"
+			  "\x97\x58\xbf\x75\xc0\x5a\x99\x4a"
+			  "\x6d\x03\x4f\x65\xf8\xf0\xe6\xfd"
+			  "\xca\xea\xb1\xa3\x4d\x4a\x6b\x4b"
+			  "\x63\x6e\x07\x0a\x38\xbc\xe7\x37",
+		.np	= 4,
+		.tap	= { 7, 7, 7, 7 }
+	}, {
+		.key	= "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			  "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			  "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			  "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			  "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			  "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			  "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			  "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			  "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			  "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			  "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			  "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			  "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			  "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			  "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			  "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			  "\xaa\xaa\xaa",
+		.ksize	= 131,
+		.plaintext = "Test Using Large"
+			   "r Than Block-Siz"
+			   "e Key - Hash Key"
+			   " First",
+		.psize	= 54,
+		.digest	= "\x80\xb2\x42\x63\xc7\xc1\xa3\xeb"
+			"\xb7\x14\x93\xc1\xdd\x7b\xe8\xb4"
+			"\x9b\x46\xd1\xf4\x1b\x4a\xee\xc1"
+			"\x12\x1b\x01\x37\x83\xf8\xf3\x52"
+			"\x6b\x56\xd0\x37\xe0\x5f\x25\x98"
+			"\xbd\x0f\xd2\x21\x5d\x6a\x1e\x52"
+			"\x95\xe6\x4f\x73\xf6\x3f\x0a\xec"
+			"\x8b\x91\x5a\x98\x5d\x78\x65\x98",
+	}, {
+		.key	= "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+			"\xaa\xaa\xaa",
+		.ksize	= 131,
+		.plaintext =
+			  "This is a test u"
+			  "sing a larger th"
+			  "an block-size ke"
+			  "y and a larger t"
+			  "han block-size d"
+			  "ata. The key nee"
+			  "ds to be hashed "
+			  "before being use"
+			  "d by the HMAC al"
+			  "gorithm.",
+		.psize	= 152,
+		.digest	= "\xe3\x7b\x6a\x77\x5d\xc8\x7d\xba"
+			"\xa4\xdf\xa9\xf9\x6e\x5e\x3f\xfd"
+			"\xde\xbd\x71\xf8\x86\x72\x89\x86"
+			"\x5d\xf5\xa3\x2d\x20\xcd\xc9\x44"
+			"\xb6\x02\x2c\xac\x3c\x49\x82\xb1"
+			"\x0d\x5e\xeb\x55\xc3\xe4\xde\x15"
+			"\x13\x46\x76\xfb\x6d\xe0\x44\x60"
+			"\x65\xc9\x74\x40\xfa\x8c\x6a\x58",
+	},
+};
+
+/*
+ * DES test vectors.
+ */
+#define DES_ENC_TEST_VECTORS		10
+#define DES_DEC_TEST_VECTORS		4
+#define DES_CBC_ENC_TEST_VECTORS	5
+#define DES_CBC_DEC_TEST_VECTORS	4
+#define DES3_EDE_ENC_TEST_VECTORS	3
+#define DES3_EDE_DEC_TEST_VECTORS	3
+#define DES3_EDE_CBC_ENC_TEST_VECTORS	1
+#define DES3_EDE_CBC_DEC_TEST_VECTORS	1
+
+static struct cipher_testvec des_enc_tv_template[] = {
+	{ /* From Applied Cryptography */
+		.key	= "\x01\x23\x45\x67\x89\xab\xcd\xef",
+		.klen	= 8,
+		.input	= "\x01\x23\x45\x67\x89\xab\xcd\xe7",
+		.ilen	= 8,
+		.result	= "\xc9\x57\x44\x25\x6a\x5e\xd3\x1d",
+		.rlen	= 8,
+	}, { /* Same key, different plaintext block */
+		.key	= "\x01\x23\x45\x67\x89\xab\xcd\xef",
+		.klen	= 8,
+		.input	= "\x22\x33\x44\x55\x66\x77\x88\x99",
+		.ilen	= 8,
+		.result	= "\xf7\x9c\x89\x2a\x33\x8f\x4a\x8b",
+		.rlen	= 8,
+	}, { /* Sbox test from NBS */
+		.key	= "\x7c\xa1\x10\x45\x4a\x1a\x6e\x57",
+		.klen	= 8,
+		.input	= "\x01\xa1\xd6\xd0\x39\x77\x67\x42",
+		.ilen	= 8,
+		.result	= "\x69\x0f\x5b\x0d\x9a\x26\x93\x9b",
+		.rlen	= 8,
+	}, { /* Three blocks */
+		.key	= "\x01\x23\x45\x67\x89\xab\xcd\xef",
+		.klen	= 8,
+		.input	= "\x01\x23\x45\x67\x89\xab\xcd\xe7"
+			  "\x22\x33\x44\x55\x66\x77\x88\x99"
+			  "\xca\xfe\xba\xbe\xfe\xed\xbe\xef",
+		.ilen	= 24,
+		.result	= "\xc9\x57\x44\x25\x6a\x5e\xd3\x1d"
+			  "\xf7\x9c\x89\x2a\x33\x8f\x4a\x8b"
+			  "\xb4\x99\x26\xf7\x1f\xe1\xd4\x90",
+		.rlen	= 24,
+	}, { /* Weak key */
+		.fail	= 1,
+		.wk	= 1,
+		.key	= "\x01\x01\x01\x01\x01\x01\x01\x01",
+		.klen	= 8,
+		.input	= "\x01\x23\x45\x67\x89\xab\xcd\xe7",
+		.ilen	= 8,
+		.result	= "\xc9\x57\x44\x25\x6a\x5e\xd3\x1d",
+		.rlen	= 8,
+	}, { /* Two blocks -- for testing encryption across pages */
+		.key	= "\x01\x23\x45\x67\x89\xab\xcd\xef",
+		.klen	= 8,
+		.input	= "\x01\x23\x45\x67\x89\xab\xcd\xe7"
+			  "\x22\x33\x44\x55\x66\x77\x88\x99",
+		.ilen	= 16,
+		.result	= "\xc9\x57\x44\x25\x6a\x5e\xd3\x1d"
+			  "\xf7\x9c\x89\x2a\x33\x8f\x4a\x8b",
+		.rlen	= 16,
+		.np	= 2,
+		.tap	= { 8, 8 }
+	}, { /* Four blocks -- for testing encryption with chunking */
+		.key	= "\x01\x23\x45\x67\x89\xab\xcd\xef",
+		.klen	= 8,
+		.input	= "\x01\x23\x45\x67\x89\xab\xcd\xe7"
+			  "\x22\x33\x44\x55\x66\x77\x88\x99"
+			  "\xca\xfe\xba\xbe\xfe\xed\xbe\xef"
+			  "\x22\x33\x44\x55\x66\x77\x88\x99",
+		.ilen	= 32,
+		.result	= "\xc9\x57\x44\x25\x6a\x5e\xd3\x1d"
+			  "\xf7\x9c\x89\x2a\x33\x8f\x4a\x8b"
+			  "\xb4\x99\x26\xf7\x1f\xe1\xd4\x90"
+			  "\xf7\x9c\x89\x2a\x33\x8f\x4a\x8b",
+		.rlen	= 32,
+		.np	= 3,
+		.tap	= { 14, 10, 8 }
+	}, {
+		.key	= "\x01\x23\x45\x67\x89\xab\xcd\xef",
+		.klen	= 8,
+		.input	= "\x01\x23\x45\x67\x89\xab\xcd\xe7"
+			  "\x22\x33\x44\x55\x66\x77\x88\x99"
+			  "\xca\xfe\xba\xbe\xfe\xed\xbe\xef",
+		.ilen	= 24,
+		.result	= "\xc9\x57\x44\x25\x6a\x5e\xd3\x1d"
+			  "\xf7\x9c\x89\x2a\x33\x8f\x4a\x8b"
+			  "\xb4\x99\x26\xf7\x1f\xe1\xd4\x90",
+		.rlen	= 24,
+		.np	= 4,
+		.tap	= { 2, 1, 3, 18 }
+	}, {
+		.key	= "\x01\x23\x45\x67\x89\xab\xcd\xef",
+		.klen	= 8,
+		.input	= "\x01\x23\x45\x67\x89\xab\xcd\xe7"
+			  "\x22\x33\x44\x55\x66\x77\x88\x99",
+		.ilen	= 16,
+		.result	= "\xc9\x57\x44\x25\x6a\x5e\xd3\x1d"
+			  "\xf7\x9c\x89\x2a\x33\x8f\x4a\x8b",
+		.rlen	= 16,
+		.np	= 5,
+		.tap	= { 2, 2, 2, 2, 8 }
+	}, {
+		.key	= "\x01\x23\x45\x67\x89\xab\xcd\xef",
+		.klen	= 8,
+		.input	= "\x01\x23\x45\x67\x89\xab\xcd\xe7",
+		.ilen	= 8,
+		.result	= "\xc9\x57\x44\x25\x6a\x5e\xd3\x1d",
+		.rlen	= 8,
+		.np	= 8,
+		.tap	= { 1, 1, 1, 1, 1, 1, 1, 1 }
+	},
+};
+
+static struct cipher_testvec des_dec_tv_template[] = {
+	{ /* From Applied Cryptography */
+		.key	= "\x01\x23\x45\x67\x89\xab\xcd\xef",
+		.klen	= 8,
+		.input	= "\xc9\x57\x44\x25\x6a\x5e\xd3\x1d",
+		.ilen	= 8,
+		.result	= "\x01\x23\x45\x67\x89\xab\xcd\xe7",
+		.rlen	= 8,
+	}, { /* Sbox test from NBS */
+		.key	= "\x7c\xa1\x10\x45\x4a\x1a\x6e\x57",
+		.klen	= 8,
+		.input	= "\x69\x0f\x5b\x0d\x9a\x26\x93\x9b",
+		.ilen	= 8,
+		.result	= "\x01\xa1\xd6\xd0\x39\x77\x67\x42",
+		.rlen	= 8,
+	}, { /* Two blocks, for chunking test */
+		.key	= "\x01\x23\x45\x67\x89\xab\xcd\xef",
+		.klen	= 8,
+		.input	= "\xc9\x57\x44\x25\x6a\x5e\xd3\x1d"
+			  "\x69\x0f\x5b\x0d\x9a\x26\x93\x9b",
+		.ilen	= 16,
+		.result	= "\x01\x23\x45\x67\x89\xab\xcd\xe7"
+			  "\xa3\x99\x7b\xca\xaf\x69\xa0\xf5",
+		.rlen	= 16,
+		.np	= 2,
+		.tap	= { 8, 8 }
+	}, {
+		.key	= "\x01\x23\x45\x67\x89\xab\xcd\xef",
+		.klen	= 8,
+		.input	= "\xc9\x57\x44\x25\x6a\x5e\xd3\x1d"
+			  "\x69\x0f\x5b\x0d\x9a\x26\x93\x9b",
+		.ilen	= 16,
+		.result	= "\x01\x23\x45\x67\x89\xab\xcd\xe7"
+			  "\xa3\x99\x7b\xca\xaf\x69\xa0\xf5",
+		.rlen	= 16,
+		.np	= 3,
+		.tap	= { 3, 12, 1 }
+	},
+};
+
+static struct cipher_testvec des_cbc_enc_tv_template[] = {
+	{ /* From OpenSSL */
+		.key	= "\x01\x23\x45\x67\x89\xab\xcd\xef",
+		.klen	= 8,
+		.iv	= "\xfe\xdc\xba\x98\x76\x54\x32\x10",
+		.input	= "\x37\x36\x35\x34\x33\x32\x31\x20"
+			  "\x4e\x6f\x77\x20\x69\x73\x20\x74"
+			  "\x68\x65\x20\x74\x69\x6d\x65\x20",
+		.ilen	= 24,
+		.result	= "\xcc\xd1\x73\xff\xab\x20\x39\xf4"
+			  "\xac\xd8\xae\xfd\xdf\xd8\xa1\xeb"
+			  "\x46\x8e\x91\x15\x78\x88\xba\x68",
+		.rlen	= 24,
+	}, { /* FIPS Pub 81 */
+		.key	= "\x01\x23\x45\x67\x89\xab\xcd\xef",
+		.klen	= 8,
+		.iv	= "\x12\x34\x56\x78\x90\xab\xcd\xef",
+		.input	= "\x4e\x6f\x77\x20\x69\x73\x20\x74",
+		.ilen	= 8,
+		.result	= "\xe5\xc7\xcd\xde\x87\x2b\xf2\x7c",
+		.rlen	= 8,
+	}, {
+		.key	= "\x01\x23\x45\x67\x89\xab\xcd\xef",
+		.klen	= 8,
+		.iv	= "\xe5\xc7\xcd\xde\x87\x2b\xf2\x7c",
+		.input	= "\x68\x65\x20\x74\x69\x6d\x65\x20",
+		.ilen	= 8,
+		.result	= "\x43\xe9\x34\x00\x8c\x38\x9c\x0f",
+		.rlen	= 8,
+	}, {
+		.key	= "\x01\x23\x45\x67\x89\xab\xcd\xef",
+		.klen	= 8,
+		.iv	= "\x43\xe9\x34\x00\x8c\x38\x9c\x0f",
+		.input	= "\x66\x6f\x72\x20\x61\x6c\x6c\x20",
+		.ilen	= 8,
+		.result	= "\x68\x37\x88\x49\x9a\x7c\x05\xf6",
+		.rlen	= 8,
+	}, { /* Copy of openssl vector for chunk testing */
+	     /* From OpenSSL */
+		.key	= "\x01\x23\x45\x67\x89\xab\xcd\xef",
+		.klen	= 8,
+		.iv	= "\xfe\xdc\xba\x98\x76\x54\x32\x10",
+		.input	= "\x37\x36\x35\x34\x33\x32\x31\x20"
+			  "\x4e\x6f\x77\x20\x69\x73\x20\x74"
+			  "\x68\x65\x20\x74\x69\x6d\x65\x20",
+		.ilen	= 24,
+		.result	= "\xcc\xd1\x73\xff\xab\x20\x39\xf4"
+			  "\xac\xd8\xae\xfd\xdf\xd8\xa1\xeb"
+			  "\x46\x8e\x91\x15\x78\x88\xba\x68",
+		.rlen	= 24,
+		.np	= 2,
+		.tap	= { 13, 11 }
+	},
+};
+
+static struct cipher_testvec des_cbc_dec_tv_template[] = {
+	{ /* FIPS Pub 81 */
+		.key	= "\x01\x23\x45\x67\x89\xab\xcd\xef",
+		.klen	= 8,
+		.iv	= "\x12\x34\x56\x78\x90\xab\xcd\xef",
+		.input	= "\xe5\xc7\xcd\xde\x87\x2b\xf2\x7c",
+		.ilen	= 8,
+		.result	= "\x4e\x6f\x77\x20\x69\x73\x20\x74",
+		.rlen	= 8,
+	}, {
+		.key	= "\x01\x23\x45\x67\x89\xab\xcd\xef",
+		.klen	= 8,
+		.iv	= "\xe5\xc7\xcd\xde\x87\x2b\xf2\x7c",
+		.input	= "\x43\xe9\x34\x00\x8c\x38\x9c\x0f",
+		.ilen	= 8,
+		.result	= "\x68\x65\x20\x74\x69\x6d\x65\x20",
+		.rlen	= 8,
+	}, {
+		.key	= "\x01\x23\x45\x67\x89\xab\xcd\xef",
+		.klen	= 8,
+		.iv	= "\x43\xe9\x34\x00\x8c\x38\x9c\x0f",
+		.input	= "\x68\x37\x88\x49\x9a\x7c\x05\xf6",
+		.ilen	= 8,
+		.result	= "\x66\x6f\x72\x20\x61\x6c\x6c\x20",
+		.rlen	= 8,
+	}, { /* Copy of above, for chunk testing */
+		.key	= "\x01\x23\x45\x67\x89\xab\xcd\xef",
+		.klen	= 8,
+		.iv	= "\x43\xe9\x34\x00\x8c\x38\x9c\x0f",
+		.input	= "\x68\x37\x88\x49\x9a\x7c\x05\xf6",
+		.ilen	= 8,
+		.result	= "\x66\x6f\x72\x20\x61\x6c\x6c\x20",
+		.rlen	= 8,
+		.np	= 2,
+		.tap	= { 4, 4 }
+	},
+};
+
+static struct cipher_testvec des3_ede_enc_tv_template[] = {
+	{ /* These are from openssl */
+		.key	= "\x01\x23\x45\x67\x89\xab\xcd\xef"
+			  "\x55\x55\x55\x55\x55\x55\x55\x55"
+			  "\xfe\xdc\xba\x98\x76\x54\x32\x10",
+		.klen	= 24,
+		.input	= "\x73\x6f\x6d\x65\x64\x61\x74\x61",
+		.ilen	= 8,
+		.result	= "\x18\xd7\x48\xe5\x63\x62\x05\x72",
+		.rlen	= 8,
+	}, {
+		.key	= "\x03\x52\x02\x07\x67\x20\x82\x17"
+			  "\x86\x02\x87\x66\x59\x08\x21\x98"
+			  "\x64\x05\x6a\xbd\xfe\xa9\x34\x57",
+		.klen	= 24,
+		.input	= "\x73\x71\x75\x69\x67\x67\x6c\x65",
+		.ilen	= 8,
+		.result	= "\xc0\x7d\x2a\x0f\xa5\x66\xfa\x30",
+		.rlen	= 8,
+	}, {
+		.key	= "\x10\x46\x10\x34\x89\x98\x80\x20"
+			  "\x91\x07\xd0\x15\x89\x19\x01\x01"
+			  "\x19\x07\x92\x10\x98\x1a\x01\x01",
+		.klen	= 24,
+		.input	= "\x00\x00\x00\x00\x00\x00\x00\x00",
+		.ilen	= 8,
+		.result	= "\xe1\xef\x62\xc3\x32\xfe\x82\x5b",
+		.rlen	= 8,
+	},
+};
+
+static struct cipher_testvec des3_ede_dec_tv_template[] = {
+	{ /* These are from openssl */
+		.key	= "\x01\x23\x45\x67\x89\xab\xcd\xef"
+			  "\x55\x55\x55\x55\x55\x55\x55\x55"
+			  "\xfe\xdc\xba\x98\x76\x54\x32\x10",
+		.klen	= 24,
+		.input	= "\x18\xd7\x48\xe5\x63\x62\x05\x72",
+		.ilen	= 8,
+		.result	= "\x73\x6f\x6d\x65\x64\x61\x74\x61",
+		.rlen	= 8,
+	}, {
+		.key	= "\x03\x52\x02\x07\x67\x20\x82\x17"
+			  "\x86\x02\x87\x66\x59\x08\x21\x98"
+			  "\x64\x05\x6a\xbd\xfe\xa9\x34\x57",
+		.klen	= 24,
+		.input	= "\xc0\x7d\x2a\x0f\xa5\x66\xfa\x30",
+		.ilen	= 8,
+		.result	= "\x73\x71\x75\x69\x67\x67\x6c\x65",
+		.rlen	= 8,
+	}, {
+		.key	= "\x10\x46\x10\x34\x89\x98\x80\x20"
+			  "\x91\x07\xd0\x15\x89\x19\x01\x01"
+			  "\x19\x07\x92\x10\x98\x1a\x01\x01",
+		.klen	= 24,
+		.input	= "\xe1\xef\x62\xc3\x32\xfe\x82\x5b",
+		.ilen	= 8,
+		.result	= "\x00\x00\x00\x00\x00\x00\x00\x00",
+		.rlen	= 8,
+	},
+};
+
+static struct cipher_testvec des3_ede_cbc_enc_tv_template[] = {
+	{ /* Generated from openssl */
+		.key	= "\xE9\xC0\xFF\x2E\x76\x0B\x64\x24"
+			  "\x44\x4D\x99\x5A\x12\xD6\x40\xC0"
+			  "\xEA\xC2\x84\xE8\x14\x95\xDB\xE8",
+		.klen	= 24,
+		.iv	= "\x7D\x33\x88\x93\x0F\x93\xB2\x42",
+		.input	= "\x6f\x54\x20\x6f\x61\x4d\x79\x6e"
+			  "\x53\x20\x63\x65\x65\x72\x73\x74"
+			  "\x54\x20\x6f\x6f\x4d\x20\x6e\x61"
+			  "\x20\x79\x65\x53\x72\x63\x74\x65"
+			  "\x20\x73\x6f\x54\x20\x6f\x61\x4d"
+			  "\x79\x6e\x53\x20\x63\x65\x65\x72"
+			  "\x73\x74\x54\x20\x6f\x6f\x4d\x20"
+			  "\x6e\x61\x20\x79\x65\x53\x72\x63"
+			  "\x74\x65\x20\x73\x6f\x54\x20\x6f"
+			  "\x61\x4d\x79\x6e\x53\x20\x63\x65"
+			  "\x65\x72\x73\x74\x54\x20\x6f\x6f"
+			  "\x4d\x20\x6e\x61\x20\x79\x65\x53"
+			  "\x72\x63\x74\x65\x20\x73\x6f\x54"
+			  "\x20\x6f\x61\x4d\x79\x6e\x53\x20"
+			  "\x63\x65\x65\x72\x73\x74\x54\x20"
+			  "\x6f\x6f\x4d\x20\x6e\x61\x0a\x79",
+		.ilen	= 128,
+		.result	= "\x0e\x2d\xb6\x97\x3c\x56\x33\xf4"
+			  "\x67\x17\x21\xc7\x6e\x8a\xd5\x49"
+			  "\x74\xb3\x49\x05\xc5\x1c\xd0\xed"
+			  "\x12\x56\x5c\x53\x96\xb6\x00\x7d"
+			  "\x90\x48\xfc\xf5\x8d\x29\x39\xcc"
+			  "\x8a\xd5\x35\x18\x36\x23\x4e\xd7"
+			  "\x76\xd1\xda\x0c\x94\x67\xbb\x04"
+			  "\x8b\xf2\x03\x6c\xa8\xcf\xb6\xea"
+			  "\x22\x64\x47\xaa\x8f\x75\x13\xbf"
+			  "\x9f\xc2\xc3\xf0\xc9\x56\xc5\x7a"
+			  "\x71\x63\x2e\x89\x7b\x1e\x12\xca"
+			  "\xe2\x5f\xaf\xd8\xa4\xf8\xc9\x7a"
+			  "\xd6\xf9\x21\x31\x62\x44\x45\xa6"
+			  "\xd6\xbc\x5a\xd3\x2d\x54\x43\xcc"
+			  "\x9d\xde\xa5\x70\xe9\x42\x45\x8a"
+			  "\x6b\xfa\xb1\x91\x13\xb0\xd9\x19",
+		.rlen	= 128,
+	},
+};
+
+static struct cipher_testvec des3_ede_cbc_dec_tv_template[] = {
+	{ /* Generated from openssl */
+		.key	= "\xE9\xC0\xFF\x2E\x76\x0B\x64\x24"
+			  "\x44\x4D\x99\x5A\x12\xD6\x40\xC0"
+			  "\xEA\xC2\x84\xE8\x14\x95\xDB\xE8",
+		.klen	= 24,
+		.iv	= "\x7D\x33\x88\x93\x0F\x93\xB2\x42",
+		.input	= "\x0e\x2d\xb6\x97\x3c\x56\x33\xf4"
+			  "\x67\x17\x21\xc7\x6e\x8a\xd5\x49"
+			  "\x74\xb3\x49\x05\xc5\x1c\xd0\xed"
+			  "\x12\x56\x5c\x53\x96\xb6\x00\x7d"
+			  "\x90\x48\xfc\xf5\x8d\x29\x39\xcc"
+			  "\x8a\xd5\x35\x18\x36\x23\x4e\xd7"
+			  "\x76\xd1\xda\x0c\x94\x67\xbb\x04"
+			  "\x8b\xf2\x03\x6c\xa8\xcf\xb6\xea"
+			  "\x22\x64\x47\xaa\x8f\x75\x13\xbf"
+			  "\x9f\xc2\xc3\xf0\xc9\x56\xc5\x7a"
+			  "\x71\x63\x2e\x89\x7b\x1e\x12\xca"
+			  "\xe2\x5f\xaf\xd8\xa4\xf8\xc9\x7a"
+			  "\xd6\xf9\x21\x31\x62\x44\x45\xa6"
+			  "\xd6\xbc\x5a\xd3\x2d\x54\x43\xcc"
+			  "\x9d\xde\xa5\x70\xe9\x42\x45\x8a"
+			  "\x6b\xfa\xb1\x91\x13\xb0\xd9\x19",
+		.ilen	= 128,
+		.result	= "\x6f\x54\x20\x6f\x61\x4d\x79\x6e"
+			  "\x53\x20\x63\x65\x65\x72\x73\x74"
+			  "\x54\x20\x6f\x6f\x4d\x20\x6e\x61"
+			  "\x20\x79\x65\x53\x72\x63\x74\x65"
+			  "\x20\x73\x6f\x54\x20\x6f\x61\x4d"
+			  "\x79\x6e\x53\x20\x63\x65\x65\x72"
+			  "\x73\x74\x54\x20\x6f\x6f\x4d\x20"
+			  "\x6e\x61\x20\x79\x65\x53\x72\x63"
+			  "\x74\x65\x20\x73\x6f\x54\x20\x6f"
+			  "\x61\x4d\x79\x6e\x53\x20\x63\x65"
+			  "\x65\x72\x73\x74\x54\x20\x6f\x6f"
+			  "\x4d\x20\x6e\x61\x20\x79\x65\x53"
+			  "\x72\x63\x74\x65\x20\x73\x6f\x54"
+			  "\x20\x6f\x61\x4d\x79\x6e\x53\x20"
+			  "\x63\x65\x65\x72\x73\x74\x54\x20"
+			  "\x6f\x6f\x4d\x20\x6e\x61\x0a\x79",
+		.rlen	= 128,
+	},
+};
+
+/*
+ * Blowfish test vectors.
+ */
+#define BF_ENC_TEST_VECTORS	6
+#define BF_DEC_TEST_VECTORS	6
+#define BF_CBC_ENC_TEST_VECTORS	1
+#define BF_CBC_DEC_TEST_VECTORS	1
+
+static struct cipher_testvec bf_enc_tv_template[] = {
+	{ /* DES test vectors from OpenSSL */
+		.key	= "\x00\x00\x00\x00\x00\x00\x00\x00",
+		.klen	= 8,
+		.input	= "\x00\x00\x00\x00\x00\x00\x00\x00",
+		.ilen	= 8,
+		.result	= "\x4e\xf9\x97\x45\x61\x98\xdd\x78",
+		.rlen	= 8,
+	}, {
+		.key	= "\x1f\x1f\x1f\x1f\x0e\x0e\x0e\x0e",
+		.klen	= 8,
+		.input	= "\x01\x23\x45\x67\x89\xab\xcd\xef",
+		.ilen	= 8,
+		.result	= "\xa7\x90\x79\x51\x08\xea\x3c\xae",
+		.rlen	= 8,
+	}, {
+		.key	= "\xf0\xe1\xd2\xc3\xb4\xa5\x96\x87",
+		.klen	= 8,
+		.input	= "\xfe\xdc\xba\x98\x76\x54\x32\x10",
+		.ilen	= 8,
+		.result	= "\xe8\x7a\x24\x4e\x2c\xc8\x5e\x82",
+		.rlen	= 8,
+	}, { /* Vary the keylength... */
+		.key	= "\xf0\xe1\xd2\xc3\xb4\xa5\x96\x87"
+			  "\x78\x69\x5a\x4b\x3c\x2d\x1e\x0f",
+		.klen	= 16,
+		.input	= "\xfe\xdc\xba\x98\x76\x54\x32\x10",
+		.ilen	= 8,
+		.result	= "\x93\x14\x28\x87\xee\x3b\xe1\x5c",
+		.rlen	= 8,
+	}, {
+		.key	= "\xf0\xe1\xd2\xc3\xb4\xa5\x96\x87"
+			  "\x78\x69\x5a\x4b\x3c\x2d\x1e\x0f"
+			  "\x00\x11\x22\x33\x44",
+		.klen	= 21,
+		.input	= "\xfe\xdc\xba\x98\x76\x54\x32\x10",
+		.ilen	= 8,
+		.result	= "\xe6\xf5\x1e\xd7\x9b\x9d\xb2\x1f",
+		.rlen	= 8,
+	}, { /* Generated with bf488 */
+		.key	= "\xf0\xe1\xd2\xc3\xb4\xa5\x96\x87"
+			  "\x78\x69\x5a\x4b\x3c\x2d\x1e\x0f"
+			  "\x00\x11\x22\x33\x44\x55\x66\x77"
+			  "\x04\x68\x91\x04\xc2\xfd\x3b\x2f"
+			  "\x58\x40\x23\x64\x1a\xba\x61\x76"
+			  "\x1f\x1f\x1f\x1f\x0e\x0e\x0e\x0e"
+			  "\xff\xff\xff\xff\xff\xff\xff\xff",
+		.klen	= 56,
+		.input	= "\xfe\xdc\xba\x98\x76\x54\x32\x10",
+		.ilen	= 8,
+		.result	= "\xc0\x45\x04\x01\x2e\x4e\x1f\x53",
+		.rlen	= 8,
+	},
+};
+
+static struct cipher_testvec bf_dec_tv_template[] = {
+	{ /* DES test vectors from OpenSSL */
+		.key	= "\x00\x00\x00\x00\x00\x00\x00\x00",
+		.klen	= 8,
+		.input	= "\x4e\xf9\x97\x45\x61\x98\xdd\x78",
+		.ilen	= 8,
+		.result	= "\x00\x00\x00\x00\x00\x00\x00\x00",
+		.rlen	= 8,
+	}, {
+		.key	= "\x1f\x1f\x1f\x1f\x0e\x0e\x0e\x0e",
+		.klen	= 8,
+		.input	= "\xa7\x90\x79\x51\x08\xea\x3c\xae",
+		.ilen	= 8,
+		.result	= "\x01\x23\x45\x67\x89\xab\xcd\xef",
+		.rlen	= 8,
+	}, {
+		.key	= "\xf0\xe1\xd2\xc3\xb4\xa5\x96\x87",
+		.klen	= 8,
+		.input	= "\xe8\x7a\x24\x4e\x2c\xc8\x5e\x82",
+		.ilen	= 8,
+		.result	= "\xfe\xdc\xba\x98\x76\x54\x32\x10",
+		.rlen	= 8,
+	}, { /* Vary the keylength... */
+		.key	= "\xf0\xe1\xd2\xc3\xb4\xa5\x96\x87"
+			  "\x78\x69\x5a\x4b\x3c\x2d\x1e\x0f",
+		.klen	= 16,
+		.input	= "\x93\x14\x28\x87\xee\x3b\xe1\x5c",
+		.ilen	= 8,
+		.result	= "\xfe\xdc\xba\x98\x76\x54\x32\x10",
+		.rlen	= 8,
+	}, {
+		.key	= "\xf0\xe1\xd2\xc3\xb4\xa5\x96\x87"
+			  "\x78\x69\x5a\x4b\x3c\x2d\x1e\x0f"
+			  "\x00\x11\x22\x33\x44",
+		.klen	= 21,
+		.input	= "\xe6\xf5\x1e\xd7\x9b\x9d\xb2\x1f",
+		.ilen	= 8,
+		.result	= "\xfe\xdc\xba\x98\x76\x54\x32\x10",
+		.rlen	= 8,
+	}, { /* Generated with bf488, using OpenSSL, Libgcrypt and Nettle */
+		.key	= "\xf0\xe1\xd2\xc3\xb4\xa5\x96\x87"
+			  "\x78\x69\x5a\x4b\x3c\x2d\x1e\x0f"
+			  "\x00\x11\x22\x33\x44\x55\x66\x77"
+			  "\x04\x68\x91\x04\xc2\xfd\x3b\x2f"
+			  "\x58\x40\x23\x64\x1a\xba\x61\x76"
+			  "\x1f\x1f\x1f\x1f\x0e\x0e\x0e\x0e"
+			  "\xff\xff\xff\xff\xff\xff\xff\xff",
+		.klen	= 56,
+		.input	= "\xc0\x45\x04\x01\x2e\x4e\x1f\x53",
+		.ilen	= 8,
+		.result	= "\xfe\xdc\xba\x98\x76\x54\x32\x10",
+		.rlen	= 8,
+	},
+};
+
+static struct cipher_testvec bf_cbc_enc_tv_template[] = {
+	{ /* From OpenSSL */
+		.key	= "\x01\x23\x45\x67\x89\xab\xcd\xef"
+			  "\xf0\xe1\xd2\xc3\xb4\xa5\x96\x87",
+		.klen	= 16,
+		.iv	= "\xfe\xdc\xba\x98\x76\x54\x32\x10",
+		.input	= "\x37\x36\x35\x34\x33\x32\x31\x20"
+			  "\x4e\x6f\x77\x20\x69\x73\x20\x74"
+			  "\x68\x65\x20\x74\x69\x6d\x65\x20"
+			  "\x66\x6f\x72\x20\x00\x00\x00\x00",
+		.ilen	= 32,
+		.result	= "\x6b\x77\xb4\xd6\x30\x06\xde\xe6"
+			  "\x05\xb1\x56\xe2\x74\x03\x97\x93"
+			  "\x58\xde\xb9\xe7\x15\x46\x16\xd9"
+			  "\x59\xf1\x65\x2b\xd5\xff\x92\xcc",
+		.rlen	= 32,
+	},
+};
+
+static struct cipher_testvec bf_cbc_dec_tv_template[] = {
+	{ /* From OpenSSL */
+		.key	= "\x01\x23\x45\x67\x89\xab\xcd\xef"
+			  "\xf0\xe1\xd2\xc3\xb4\xa5\x96\x87",
+		.klen	= 16,
+		.iv	= "\xfe\xdc\xba\x98\x76\x54\x32\x10",
+		.input	= "\x6b\x77\xb4\xd6\x30\x06\xde\xe6"
+			  "\x05\xb1\x56\xe2\x74\x03\x97\x93"
+			  "\x58\xde\xb9\xe7\x15\x46\x16\xd9"
+			  "\x59\xf1\x65\x2b\xd5\xff\x92\xcc",
+		.ilen	= 32,
+		.result	= "\x37\x36\x35\x34\x33\x32\x31\x20"
+			  "\x4e\x6f\x77\x20\x69\x73\x20\x74"
+			  "\x68\x65\x20\x74\x69\x6d\x65\x20"
+			  "\x66\x6f\x72\x20\x00\x00\x00\x00",
+		.rlen	= 32,
+	},
+};
+
+/*
+ * Twofish test vectors.
+ */
+#define TF_ENC_TEST_VECTORS		3
+#define TF_DEC_TEST_VECTORS		3
+#define TF_CBC_ENC_TEST_VECTORS		4
+#define TF_CBC_DEC_TEST_VECTORS		4
+
+static struct cipher_testvec tf_enc_tv_template[] = {
+	{
+		.key	= zeroed_string,
+		.klen	= 16,
+		.input	= zeroed_string,
+		.ilen	= 16,
+		.result	= "\x9f\x58\x9f\x5c\xf6\x12\x2c\x32"
+			  "\xb6\xbf\xec\x2f\x2a\xe8\xc3\x5a",
+		.rlen	= 16,
+	}, {
+		.key	= "\x01\x23\x45\x67\x89\xab\xcd\xef"
+			  "\xfe\xdc\xba\x98\x76\x54\x32\x10"
+			  "\x00\x11\x22\x33\x44\x55\x66\x77",
+		.klen	= 24,
+		.input	= zeroed_string,
+		.ilen	= 16,
+		.result	= "\xcf\xd1\xd2\xe5\xa9\xbe\x9c\xdf"
+			  "\x50\x1f\x13\xb8\x92\xbd\x22\x48",
+		.rlen	= 16,
+	}, {
+		.key	= "\x01\x23\x45\x67\x89\xab\xcd\xef"
+			  "\xfe\xdc\xba\x98\x76\x54\x32\x10"
+			  "\x00\x11\x22\x33\x44\x55\x66\x77"
+			  "\x88\x99\xaa\xbb\xcc\xdd\xee\xff",
+		.klen	= 32,
+		.input	= zeroed_string,
+		.ilen	= 16,
+		.result	= "\x37\x52\x7b\xe0\x05\x23\x34\xb8"
+			  "\x9f\x0c\xfc\xca\xe8\x7c\xfa\x20",
+		.rlen	= 16,
+	},
+};
+
+static struct cipher_testvec tf_dec_tv_template[] = {
+	{
+		.key	= zeroed_string,
+		.klen	= 16,
+		.input	= "\x9f\x58\x9f\x5c\xf6\x12\x2c\x32"
+			  "\xb6\xbf\xec\x2f\x2a\xe8\xc3\x5a",
+		.ilen	= 16,
+		.result	= zeroed_string,
+		.rlen	= 16,
+	}, {
+		.key	= "\x01\x23\x45\x67\x89\xab\xcd\xef"
+			  "\xfe\xdc\xba\x98\x76\x54\x32\x10"
+			  "\x00\x11\x22\x33\x44\x55\x66\x77",
+		.klen	= 24,
+		.input	= "\xcf\xd1\xd2\xe5\xa9\xbe\x9c\xdf"
+			  "\x50\x1f\x13\xb8\x92\xbd\x22\x48",
+		.ilen	= 16,
+		.result	= zeroed_string,
+		.rlen	= 16,
+	}, {
+		.key	= "\x01\x23\x45\x67\x89\xab\xcd\xef"
+			  "\xfe\xdc\xba\x98\x76\x54\x32\x10"
+			  "\x00\x11\x22\x33\x44\x55\x66\x77"
+			  "\x88\x99\xaa\xbb\xcc\xdd\xee\xff",
+		.klen	= 32,
+		.input	= "\x37\x52\x7b\xe0\x05\x23\x34\xb8"
+			  "\x9f\x0c\xfc\xca\xe8\x7c\xfa\x20",
+		.ilen	= 16,
+		.result	= zeroed_string,
+		.rlen	= 16,
+	},
+};
+
+static struct cipher_testvec tf_cbc_enc_tv_template[] = {
+	{ /* Generated with Nettle */
+		.key	= zeroed_string,
+		.klen	= 16,
+		.iv	= zeroed_string,
+		.input	= zeroed_string,
+		.ilen	= 16,
+		.result	= "\x9f\x58\x9f\x5c\xf6\x12\x2c\x32"
+			  "\xb6\xbf\xec\x2f\x2a\xe8\xc3\x5a",
+		.rlen	= 16,
+	}, {
+		.key	= zeroed_string,
+		.klen	= 16,
+		.iv	= "\x9f\x58\x9f\x5c\xf6\x12\x2c\x32"
+			  "\xb6\xbf\xec\x2f\x2a\xe8\xc3\x5a",
+		.input	= zeroed_string,
+		.ilen	= 16,
+		.result	= "\xd4\x91\xdb\x16\xe7\xb1\xc3\x9e"
+			  "\x86\xcb\x08\x6b\x78\x9f\x54\x19",
+		.rlen	= 16,
+	}, {
+		.key	= zeroed_string,
+		.klen	= 16,
+		.iv	= "\xd4\x91\xdb\x16\xe7\xb1\xc3\x9e"
+			  "\x86\xcb\x08\x6b\x78\x9f\x54\x19",
+		.input	= zeroed_string,
+		.ilen	= 16,
+		.result	= "\x05\xef\x8c\x61\xa8\x11\x58\x26"
+			  "\x34\xba\x5c\xb7\x10\x6a\xa6\x41",
+		.rlen	= 16,
+	}, {
+		.key	= zeroed_string,
+		.klen	= 16,
+		.iv	= zeroed_string,
+		.input	= zeroed_string,
+		.ilen	= 48,
+		.result	= "\x9f\x58\x9f\x5c\xf6\x12\x2c\x32"
+			  "\xb6\xbf\xec\x2f\x2a\xe8\xc3\x5a"
+			  "\xd4\x91\xdb\x16\xe7\xb1\xc3\x9e"
+			  "\x86\xcb\x08\x6b\x78\x9f\x54\x19"
+			  "\x05\xef\x8c\x61\xa8\x11\x58\x26"
+			  "\x34\xba\x5c\xb7\x10\x6a\xa6\x41",
+		.rlen	= 48,
+	},
+};
+
+static struct cipher_testvec tf_cbc_dec_tv_template[] = {
+	{ /* Reverse of the first four above */
+		.key	= zeroed_string,
+		.klen	= 16,
+		.iv	= zeroed_string,
+		.input	= "\x9f\x58\x9f\x5c\xf6\x12\x2c\x32"
+			  "\xb6\xbf\xec\x2f\x2a\xe8\xc3\x5a",
+		.ilen	= 16,
+		.result	= zeroed_string,
+		.rlen	= 16,
+	}, {
+		.key	= zeroed_string,
+		.klen	= 16,
+		.iv	= "\x9f\x58\x9f\x5c\xf6\x12\x2c\x32"
+			  "\xb6\xbf\xec\x2f\x2a\xe8\xc3\x5a",
+		.input	= "\xd4\x91\xdb\x16\xe7\xb1\xc3\x9e"
+			  "\x86\xcb\x08\x6b\x78\x9f\x54\x19",
+		.ilen	= 16,
+		.result	= zeroed_string,
+		.rlen	= 16,
+	}, {
+		.key	= zeroed_string,
+		.klen	= 16,
+		.iv	= "\xd4\x91\xdb\x16\xe7\xb1\xc3\x9e"
+			  "\x86\xcb\x08\x6b\x78\x9f\x54\x19",
+		.input	= "\x05\xef\x8c\x61\xa8\x11\x58\x26"
+			  "\x34\xba\x5c\xb7\x10\x6a\xa6\x41",
+		.ilen	= 16,
+		.result	= zeroed_string,
+		.rlen	= 16,
+	}, {
+		.key	= zeroed_string,
+		.klen	= 16,
+		.iv	= zeroed_string,
+		.input	= "\x9f\x58\x9f\x5c\xf6\x12\x2c\x32"
+			  "\xb6\xbf\xec\x2f\x2a\xe8\xc3\x5a"
+			  "\xd4\x91\xdb\x16\xe7\xb1\xc3\x9e"
+			  "\x86\xcb\x08\x6b\x78\x9f\x54\x19"
+			  "\x05\xef\x8c\x61\xa8\x11\x58\x26"
+			  "\x34\xba\x5c\xb7\x10\x6a\xa6\x41",
+		.ilen	= 48,
+		.result	= zeroed_string,
+		.rlen	= 48,
+	},
+};
+
+/*
+ * Serpent test vectors.  These are backwards because Serpent writes
+ * octet sequences in right-to-left mode.
+ */
+#define SERPENT_ENC_TEST_VECTORS	4
+#define SERPENT_DEC_TEST_VECTORS	4
+
+#define TNEPRES_ENC_TEST_VECTORS	4
+#define TNEPRES_DEC_TEST_VECTORS	4
+
+static struct cipher_testvec serpent_enc_tv_template[] = {
+	{
+		.input	= "\x00\x01\x02\x03\x04\x05\x06\x07"
+			  "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
+		.ilen	= 16,
+		.result	= "\x12\x07\xfc\xce\x9b\xd0\xd6\x47"
+			  "\x6a\xe9\x8f\xbe\xd1\x43\xa0\xe2",
+		.rlen	= 16,
+	}, {
+		.key	= "\x00\x01\x02\x03\x04\x05\x06\x07"
+			  "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
+		.klen	= 16,
+		.input	= "\x00\x01\x02\x03\x04\x05\x06\x07"
+			  "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
+		.ilen	= 16,
+		.result	= "\x4c\x7d\x8a\x32\x80\x72\xa2\x2c"
+			  "\x82\x3e\x4a\x1f\x3a\xcd\xa1\x6d",
+		.rlen	= 16,
+	}, {
+		.key	= "\x00\x01\x02\x03\x04\x05\x06\x07"
+			  "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+			  "\x10\x11\x12\x13\x14\x15\x16\x17"
+			  "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f",
+		.klen	= 32,
+		.input	= "\x00\x01\x02\x03\x04\x05\x06\x07"
+			  "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
+		.ilen	= 16,
+		.result	= "\xde\x26\x9f\xf8\x33\xe4\x32\xb8"
+			  "\x5b\x2e\x88\xd2\x70\x1c\xe7\x5c",
+		.rlen	= 16,
+	}, {
+		.key	= "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80",
+		.klen	= 16,
+		.input	= zeroed_string,
+		.ilen	= 16,
+		.result	= "\xdd\xd2\x6b\x98\xa5\xff\xd8\x2c"
+			  "\x05\x34\x5a\x9d\xad\xbf\xaf\x49",
+		.rlen	= 16,
+	},
+};
+
+static struct cipher_testvec tnepres_enc_tv_template[] = {
+	{ /* KeySize=128, PT=0, I=1 */
+		.input	= "\x00\x00\x00\x00\x00\x00\x00\x00"
+			  "\x00\x00\x00\x00\x00\x00\x00\x00",
+		.key    = "\x80\x00\x00\x00\x00\x00\x00\x00"
+			  "\x00\x00\x00\x00\x00\x00\x00\x00",
+		.klen   = 16,
+		.ilen	= 16,
+		.result	= "\x49\xaf\xbf\xad\x9d\x5a\x34\x05"
+			  "\x2c\xd8\xff\xa5\x98\x6b\xd2\xdd",
+		.rlen	= 16,
+	}, { /* KeySize=192, PT=0, I=1 */
+		.key	= "\x80\x00\x00\x00\x00\x00\x00\x00"
+			  "\x00\x00\x00\x00\x00\x00\x00\x00"
+			  "\x00\x00\x00\x00\x00\x00\x00\x00",
+		.klen	= 24,
+		.input	= "\x00\x00\x00\x00\x00\x00\x00\x00"
+			  "\x00\x00\x00\x00\x00\x00\x00\x00",
+		.ilen	= 16,
+		.result	= "\xe7\x8e\x54\x02\xc7\x19\x55\x68"
+			  "\xac\x36\x78\xf7\xa3\xf6\x0c\x66",
+		.rlen	= 16,
+	}, { /* KeySize=256, PT=0, I=1 */
+		.key	= "\x80\x00\x00\x00\x00\x00\x00\x00"
+			  "\x00\x00\x00\x00\x00\x00\x00\x00"
+			  "\x00\x00\x00\x00\x00\x00\x00\x00"
+			  "\x00\x00\x00\x00\x00\x00\x00\x00",
+		.klen	= 32,
+		.input	= "\x00\x00\x00\x00\x00\x00\x00\x00"
+			  "\x00\x00\x00\x00\x00\x00\x00\x00",
+		.ilen	= 16,
+		.result	= "\xab\xed\x96\xe7\x66\xbf\x28\xcb"
+			  "\xc0\xeb\xd2\x1a\x82\xef\x08\x19",
+		.rlen	= 16,
+	}, { /* KeySize=256, I=257 */
+		.key	= "\x1f\x1e\x1d\x1c\x1b\x1a\x19\x18"
+			  "\x17\x16\x15\x14\x13\x12\x11\x10"
+			  "\x0f\x0e\x0d\x0c\x0b\x0a\x09\x08"
+			  "\x07\x06\x05\x04\x03\x02\x01\x00",
+		.klen	= 32,
+		.input	= "\x0f\x0e\x0d\x0c\x0b\x0a\x09\x08"
+			  "\x07\x06\x05\x04\x03\x02\x01\x00",
+		.ilen	= 16,
+		.result	= "\x5c\xe7\x1c\x70\xd2\x88\x2e\x5b"
+			  "\xb8\x32\xe4\x33\xf8\x9f\x26\xde",
+		.rlen	= 16,
+	},
+};
+
+
+static struct cipher_testvec serpent_dec_tv_template[] = {
+	{
+		.input	= "\x12\x07\xfc\xce\x9b\xd0\xd6\x47"
+			  "\x6a\xe9\x8f\xbe\xd1\x43\xa0\xe2",
+		.ilen	= 16,
+		.result	= "\x00\x01\x02\x03\x04\x05\x06\x07"
+			  "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
+		.rlen	= 16,
+	}, {
+		.key	= "\x00\x01\x02\x03\x04\x05\x06\x07"
+			  "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
+		.klen	= 16,
+		.input	= "\x4c\x7d\x8a\x32\x80\x72\xa2\x2c"
+			  "\x82\x3e\x4a\x1f\x3a\xcd\xa1\x6d",
+		.ilen	= 16,
+		.result	= "\x00\x01\x02\x03\x04\x05\x06\x07"
+			  "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
+		.rlen	= 16,
+	}, {
+		.key	= "\x00\x01\x02\x03\x04\x05\x06\x07"
+			  "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+			  "\x10\x11\x12\x13\x14\x15\x16\x17"
+			  "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f",
+		.klen	= 32,
+		.input	= "\xde\x26\x9f\xf8\x33\xe4\x32\xb8"
+			  "\x5b\x2e\x88\xd2\x70\x1c\xe7\x5c",
+		.ilen	= 16,
+		.result	= "\x00\x01\x02\x03\x04\x05\x06\x07"
+			  "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
+		.rlen	= 16,
+	}, {
+		.key	= "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80",
+		.klen	= 16,
+		.input	= "\xdd\xd2\x6b\x98\xa5\xff\xd8\x2c"
+			  "\x05\x34\x5a\x9d\xad\xbf\xaf\x49",
+		.ilen	= 16,
+		.result	= zeroed_string,
+		.rlen	= 16,
+	},
+};
+
+static struct cipher_testvec tnepres_dec_tv_template[] = {
+	{
+		.input	= "\x41\xcc\x6b\x31\x59\x31\x45\x97"
+			  "\x6d\x6f\xbb\x38\x4b\x37\x21\x28",
+		.ilen	= 16,
+		.result	= "\x00\x01\x02\x03\x04\x05\x06\x07"
+			  "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
+		.rlen	= 16,
+	}, {
+		.key	= "\x00\x01\x02\x03\x04\x05\x06\x07"
+			  "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
+		.klen	= 16,
+		.input	= "\xea\xf4\xd7\xfc\xd8\x01\x34\x47"
+			  "\x81\x45\x0b\xfa\x0c\xd6\xad\x6e",
+		.ilen	= 16,
+		.result	= "\x00\x01\x02\x03\x04\x05\x06\x07"
+			  "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
+		.rlen	= 16,
+	}, {
+		.key	= "\x00\x01\x02\x03\x04\x05\x06\x07"
+			  "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+			  "\x10\x11\x12\x13\x14\x15\x16\x17"
+			  "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f",
+		.klen	= 32,
+		.input	= "\x64\xa9\x1a\x37\xed\x9f\xe7\x49"
+			  "\xa8\x4e\x76\xd6\xf5\x0d\x78\xee",
+		.ilen	= 16,
+		.result	= "\x00\x01\x02\x03\x04\x05\x06\x07"
+			  "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
+		.rlen	= 16,
+	}, { /* KeySize=128, I=121 */
+		.key	= "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80",
+		.klen	= 16,
+		.input	= "\x3d\xda\xbf\xc0\x06\xda\xab\x06"
+			  "\x46\x2a\xf4\xef\x81\x54\x4e\x26",
+		.ilen	= 16,
+		.result	= zeroed_string,
+		.rlen	= 16,
+	},
+};
+
+
+/* Cast6 test vectors from RFC 2612 */
+#define CAST6_ENC_TEST_VECTORS	3
+#define CAST6_DEC_TEST_VECTORS  3
+
+static struct cipher_testvec cast6_enc_tv_template[] = {
+	{
+		.key	= "\x23\x42\xbb\x9e\xfa\x38\x54\x2c"
+			  "\x0a\xf7\x56\x47\xf2\x9f\x61\x5d",
+		.klen	= 16,
+		.input	= zeroed_string,
+		.ilen	= 16,
+		.result	= "\xc8\x42\xa0\x89\x72\xb4\x3d\x20"
+			  "\x83\x6c\x91\xd1\xb7\x53\x0f\x6b",
+		.rlen	= 16,
+	}, {
+		.key	= "\x23\x42\xbb\x9e\xfa\x38\x54\x2c"
+			  "\xbe\xd0\xac\x83\x94\x0a\xc2\x98"
+			  "\xba\xc7\x7a\x77\x17\x94\x28\x63",
+		.klen	= 24,
+		.input	= zeroed_string,
+		.ilen	= 16,
+		.result	= "\x1b\x38\x6c\x02\x10\xdc\xad\xcb"
+			  "\xdd\x0e\x41\xaa\x08\xa7\xa7\xe8",
+		.rlen	= 16,
+	}, {
+		.key	= "\x23\x42\xbb\x9e\xfa\x38\x54\x2c"
+			  "\xbe\xd0\xac\x83\x94\x0a\xc2\x98"
+			  "\x8d\x7c\x47\xce\x26\x49\x08\x46"
+			  "\x1c\xc1\xb5\x13\x7a\xe6\xb6\x04",
+		.klen	= 32,
+		.input	= zeroed_string,
+		.ilen	= 16,
+		.result	= "\x4f\x6a\x20\x38\x28\x68\x97\xb9"
+			  "\xc9\x87\x01\x36\x55\x33\x17\xfa",
+		.rlen	= 16,
+	},
+};
+
+static struct cipher_testvec cast6_dec_tv_template[] = {
+	{
+		.key	= "\x23\x42\xbb\x9e\xfa\x38\x54\x2c"
+			  "\x0a\xf7\x56\x47\xf2\x9f\x61\x5d",
+		.klen	= 16,
+		.input	= "\xc8\x42\xa0\x89\x72\xb4\x3d\x20"
+			  "\x83\x6c\x91\xd1\xb7\x53\x0f\x6b",
+		.ilen	= 16,
+		.result	= zeroed_string,
+		.rlen	= 16,
+	}, {
+		.key	= "\x23\x42\xbb\x9e\xfa\x38\x54\x2c"
+			  "\xbe\xd0\xac\x83\x94\x0a\xc2\x98"
+			  "\xba\xc7\x7a\x77\x17\x94\x28\x63",
+		.klen	= 24,
+		.input	= "\x1b\x38\x6c\x02\x10\xdc\xad\xcb"
+			  "\xdd\x0e\x41\xaa\x08\xa7\xa7\xe8",
+		.ilen	= 16,
+		.result	= zeroed_string,
+		.rlen	= 16,
+	}, {
+		.key	= "\x23\x42\xbb\x9e\xfa\x38\x54\x2c"
+			  "\xbe\xd0\xac\x83\x94\x0a\xc2\x98"
+			  "\x8d\x7c\x47\xce\x26\x49\x08\x46"
+			  "\x1c\xc1\xb5\x13\x7a\xe6\xb6\x04",
+		.klen	= 32,
+		.input	= "\x4f\x6a\x20\x38\x28\x68\x97\xb9"
+			  "\xc9\x87\x01\x36\x55\x33\x17\xfa",
+		.ilen	= 16,
+		.result	= zeroed_string,
+		.rlen	= 16,
+	},
+};
+
+
+/*
+ * AES test vectors.
+ */
+#define AES_ENC_TEST_VECTORS 3
+#define AES_DEC_TEST_VECTORS 3
+#define AES_CBC_ENC_TEST_VECTORS 4
+#define AES_CBC_DEC_TEST_VECTORS 4
+#define AES_LRW_ENC_TEST_VECTORS 8
+#define AES_LRW_DEC_TEST_VECTORS 8
+#define AES_XTS_ENC_TEST_VECTORS 4
+#define AES_XTS_DEC_TEST_VECTORS 4
+#define AES_CTR_ENC_TEST_VECTORS 7
+#define AES_CTR_DEC_TEST_VECTORS 6
+#define AES_GCM_ENC_TEST_VECTORS 9
+#define AES_GCM_DEC_TEST_VECTORS 8
+#define AES_CCM_ENC_TEST_VECTORS 7
+#define AES_CCM_DEC_TEST_VECTORS 7
+
+static struct cipher_testvec aes_enc_tv_template[] = {
+	{ /* From FIPS-197 */
+		.key	= "\x00\x01\x02\x03\x04\x05\x06\x07"
+			  "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
+		.klen	= 16,
+		.input	= "\x00\x11\x22\x33\x44\x55\x66\x77"
+			  "\x88\x99\xaa\xbb\xcc\xdd\xee\xff",
+		.ilen	= 16,
+		.result	= "\x69\xc4\xe0\xd8\x6a\x7b\x04\x30"
+			  "\xd8\xcd\xb7\x80\x70\xb4\xc5\x5a",
+		.rlen	= 16,
+	}, {
+		.key	= "\x00\x01\x02\x03\x04\x05\x06\x07"
+			  "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+			  "\x10\x11\x12\x13\x14\x15\x16\x17",
+		.klen	= 24,
+		.input	= "\x00\x11\x22\x33\x44\x55\x66\x77"
+			  "\x88\x99\xaa\xbb\xcc\xdd\xee\xff",
+		.ilen	= 16,
+		.result	= "\xdd\xa9\x7c\xa4\x86\x4c\xdf\xe0"
+			  "\x6e\xaf\x70\xa0\xec\x0d\x71\x91",
+		.rlen	= 16,
+	}, {
+		.key	= "\x00\x01\x02\x03\x04\x05\x06\x07"
+			  "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+			  "\x10\x11\x12\x13\x14\x15\x16\x17"
+			  "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f",
+		.klen	= 32,
+		.input	= "\x00\x11\x22\x33\x44\x55\x66\x77"
+			  "\x88\x99\xaa\xbb\xcc\xdd\xee\xff",
+		.ilen	= 16,
+		.result	= "\x8e\xa2\xb7\xca\x51\x67\x45\xbf"
+			  "\xea\xfc\x49\x90\x4b\x49\x60\x89",
+		.rlen	= 16,
+	},
+};
+
+static struct cipher_testvec aes_dec_tv_template[] = {
+	{ /* From FIPS-197 */
+		.key	= "\x00\x01\x02\x03\x04\x05\x06\x07"
+			  "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
+		.klen	= 16,
+		.input	= "\x69\xc4\xe0\xd8\x6a\x7b\x04\x30"
+			  "\xd8\xcd\xb7\x80\x70\xb4\xc5\x5a",
+		.ilen	= 16,
+		.result	= "\x00\x11\x22\x33\x44\x55\x66\x77"
+			  "\x88\x99\xaa\xbb\xcc\xdd\xee\xff",
+		.rlen	= 16,
+	}, {
+		.key	= "\x00\x01\x02\x03\x04\x05\x06\x07"
+			  "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+			  "\x10\x11\x12\x13\x14\x15\x16\x17",
+		.klen	= 24,
+		.input	= "\xdd\xa9\x7c\xa4\x86\x4c\xdf\xe0"
+			  "\x6e\xaf\x70\xa0\xec\x0d\x71\x91",
+		.ilen	= 16,
+		.result	= "\x00\x11\x22\x33\x44\x55\x66\x77"
+			  "\x88\x99\xaa\xbb\xcc\xdd\xee\xff",
+		.rlen	= 16,
+	}, {
+		.key	= "\x00\x01\x02\x03\x04\x05\x06\x07"
+			  "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+			  "\x10\x11\x12\x13\x14\x15\x16\x17"
+			  "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f",
+		.klen	= 32,
+		.input	= "\x8e\xa2\xb7\xca\x51\x67\x45\xbf"
+			  "\xea\xfc\x49\x90\x4b\x49\x60\x89",
+		.ilen	= 16,
+		.result	= "\x00\x11\x22\x33\x44\x55\x66\x77"
+			  "\x88\x99\xaa\xbb\xcc\xdd\xee\xff",
+		.rlen	= 16,
+	},
+};
+
+static struct cipher_testvec aes_cbc_enc_tv_template[] = {
+	{ /* From RFC 3602 */
+		.key    = "\x06\xa9\x21\x40\x36\xb8\xa1\x5b"
+			  "\x51\x2e\x03\xd5\x34\x12\x00\x06",
+		.klen   = 16,
+		.iv	= "\x3d\xaf\xba\x42\x9d\x9e\xb4\x30"
+			  "\xb4\x22\xda\x80\x2c\x9f\xac\x41",
+		.input	= "Single block msg",
+		.ilen   = 16,
+		.result = "\xe3\x53\x77\x9c\x10\x79\xae\xb8"
+			  "\x27\x08\x94\x2d\xbe\x77\x18\x1a",
+		.rlen   = 16,
+	}, {
+		.key    = "\xc2\x86\x69\x6d\x88\x7c\x9a\xa0"
+			  "\x61\x1b\xbb\x3e\x20\x25\xa4\x5a",
+		.klen   = 16,
+		.iv     = "\x56\x2e\x17\x99\x6d\x09\x3d\x28"
+			  "\xdd\xb3\xba\x69\x5a\x2e\x6f\x58",
+		.input  = "\x00\x01\x02\x03\x04\x05\x06\x07"
+			  "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+			  "\x10\x11\x12\x13\x14\x15\x16\x17"
+			  "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f",
+		.ilen   = 32,
+		.result = "\xd2\x96\xcd\x94\xc2\xcc\xcf\x8a"
+			  "\x3a\x86\x30\x28\xb5\xe1\xdc\x0a"
+			  "\x75\x86\x60\x2d\x25\x3c\xff\xf9"
+			  "\x1b\x82\x66\xbe\xa6\xd6\x1a\xb1",
+		.rlen   = 32,
+	}, { /* From NIST SP800-38A */
+		.key	= "\x8e\x73\xb0\xf7\xda\x0e\x64\x52"
+			  "\xc8\x10\xf3\x2b\x80\x90\x79\xe5"
+			  "\x62\xf8\xea\xd2\x52\x2c\x6b\x7b",
+		.klen	= 24,
+		.iv	= "\x00\x01\x02\x03\x04\x05\x06\x07"
+			  "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
+		.input	= "\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96"
+			  "\xe9\x3d\x7e\x11\x73\x93\x17\x2a"
+			  "\xae\x2d\x8a\x57\x1e\x03\xac\x9c"
+			  "\x9e\xb7\x6f\xac\x45\xaf\x8e\x51"
+			  "\x30\xc8\x1c\x46\xa3\x5c\xe4\x11"
+			  "\xe5\xfb\xc1\x19\x1a\x0a\x52\xef"
+			  "\xf6\x9f\x24\x45\xdf\x4f\x9b\x17"
+			  "\xad\x2b\x41\x7b\xe6\x6c\x37\x10",
+		.ilen	= 64,
+		.result	= "\x4f\x02\x1d\xb2\x43\xbc\x63\x3d"
+			  "\x71\x78\x18\x3a\x9f\xa0\x71\xe8"
+			  "\xb4\xd9\xad\xa9\xad\x7d\xed\xf4"
+			  "\xe5\xe7\x38\x76\x3f\x69\x14\x5a"
+			  "\x57\x1b\x24\x20\x12\xfb\x7a\xe0"
+			  "\x7f\xa9\xba\xac\x3d\xf1\x02\xe0"
+			  "\x08\xb0\xe2\x79\x88\x59\x88\x81"
+			  "\xd9\x20\xa9\xe6\x4f\x56\x15\xcd",
+		.rlen	= 64,
+	}, {
+		.key	= "\x60\x3d\xeb\x10\x15\xca\x71\xbe"
+			  "\x2b\x73\xae\xf0\x85\x7d\x77\x81"
+			  "\x1f\x35\x2c\x07\x3b\x61\x08\xd7"
+			  "\x2d\x98\x10\xa3\x09\x14\xdf\xf4",
+		.klen	= 32,
+		.iv	= "\x00\x01\x02\x03\x04\x05\x06\x07"
+			  "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
+		.input	= "\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96"
+			  "\xe9\x3d\x7e\x11\x73\x93\x17\x2a"
+			  "\xae\x2d\x8a\x57\x1e\x03\xac\x9c"
+			  "\x9e\xb7\x6f\xac\x45\xaf\x8e\x51"
+			  "\x30\xc8\x1c\x46\xa3\x5c\xe4\x11"
+			  "\xe5\xfb\xc1\x19\x1a\x0a\x52\xef"
+			  "\xf6\x9f\x24\x45\xdf\x4f\x9b\x17"
+			  "\xad\x2b\x41\x7b\xe6\x6c\x37\x10",
+		.ilen	= 64,
+		.result	= "\xf5\x8c\x4c\x04\xd6\xe5\xf1\xba"
+			  "\x77\x9e\xab\xfb\x5f\x7b\xfb\xd6"
+			  "\x9c\xfc\x4e\x96\x7e\xdb\x80\x8d"
+			  "\x67\x9f\x77\x7b\xc6\x70\x2c\x7d"
+			  "\x39\xf2\x33\x69\xa9\xd9\xba\xcf"
+			  "\xa5\x30\xe2\x63\x04\x23\x14\x61"
+			  "\xb2\xeb\x05\xe2\xc3\x9b\xe9\xfc"
+			  "\xda\x6c\x19\x07\x8c\x6a\x9d\x1b",
+		.rlen	= 64,
+	},
+};
+
+static struct cipher_testvec aes_cbc_dec_tv_template[] = {
+	{ /* From RFC 3602 */
+		.key    = "\x06\xa9\x21\x40\x36\xb8\xa1\x5b"
+			  "\x51\x2e\x03\xd5\x34\x12\x00\x06",
+		.klen   = 16,
+		.iv     = "\x3d\xaf\xba\x42\x9d\x9e\xb4\x30"
+			  "\xb4\x22\xda\x80\x2c\x9f\xac\x41",
+		.input  = "\xe3\x53\x77\x9c\x10\x79\xae\xb8"
+			  "\x27\x08\x94\x2d\xbe\x77\x18\x1a",
+		.ilen   = 16,
+		.result = "Single block msg",
+		.rlen   = 16,
+	}, {
+		.key    = "\xc2\x86\x69\x6d\x88\x7c\x9a\xa0"
+			  "\x61\x1b\xbb\x3e\x20\x25\xa4\x5a",
+		.klen   = 16,
+		.iv     = "\x56\x2e\x17\x99\x6d\x09\x3d\x28"
+			  "\xdd\xb3\xba\x69\x5a\x2e\x6f\x58",
+		.input  = "\xd2\x96\xcd\x94\xc2\xcc\xcf\x8a"
+			  "\x3a\x86\x30\x28\xb5\xe1\xdc\x0a"
+			  "\x75\x86\x60\x2d\x25\x3c\xff\xf9"
+			  "\x1b\x82\x66\xbe\xa6\xd6\x1a\xb1",
+		.ilen   = 32,
+		.result = "\x00\x01\x02\x03\x04\x05\x06\x07"
+			  "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+			  "\x10\x11\x12\x13\x14\x15\x16\x17"
+			  "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f",
+		.rlen   = 32,
+	}, { /* From NIST SP800-38A */
+		.key	= "\x8e\x73\xb0\xf7\xda\x0e\x64\x52"
+			  "\xc8\x10\xf3\x2b\x80\x90\x79\xe5"
+			  "\x62\xf8\xea\xd2\x52\x2c\x6b\x7b",
+		.klen	= 24,
+		.iv	= "\x00\x01\x02\x03\x04\x05\x06\x07"
+			  "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
+		.input	= "\x4f\x02\x1d\xb2\x43\xbc\x63\x3d"
+			  "\x71\x78\x18\x3a\x9f\xa0\x71\xe8"
+			  "\xb4\xd9\xad\xa9\xad\x7d\xed\xf4"
+			  "\xe5\xe7\x38\x76\x3f\x69\x14\x5a"
+			  "\x57\x1b\x24\x20\x12\xfb\x7a\xe0"
+			  "\x7f\xa9\xba\xac\x3d\xf1\x02\xe0"
+			  "\x08\xb0\xe2\x79\x88\x59\x88\x81"
+			  "\xd9\x20\xa9\xe6\x4f\x56\x15\xcd",
+		.ilen	= 64,
+		.result	= "\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96"
+			  "\xe9\x3d\x7e\x11\x73\x93\x17\x2a"
+			  "\xae\x2d\x8a\x57\x1e\x03\xac\x9c"
+			  "\x9e\xb7\x6f\xac\x45\xaf\x8e\x51"
+			  "\x30\xc8\x1c\x46\xa3\x5c\xe4\x11"
+			  "\xe5\xfb\xc1\x19\x1a\x0a\x52\xef"
+			  "\xf6\x9f\x24\x45\xdf\x4f\x9b\x17"
+			  "\xad\x2b\x41\x7b\xe6\x6c\x37\x10",
+		.rlen	= 64,
+	}, {
+		.key	= "\x60\x3d\xeb\x10\x15\xca\x71\xbe"
+			  "\x2b\x73\xae\xf0\x85\x7d\x77\x81"
+			  "\x1f\x35\x2c\x07\x3b\x61\x08\xd7"
+			  "\x2d\x98\x10\xa3\x09\x14\xdf\xf4",
+		.klen	= 32,
+		.iv	= "\x00\x01\x02\x03\x04\x05\x06\x07"
+			  "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
+		.input	= "\xf5\x8c\x4c\x04\xd6\xe5\xf1\xba"
+			  "\x77\x9e\xab\xfb\x5f\x7b\xfb\xd6"
+			  "\x9c\xfc\x4e\x96\x7e\xdb\x80\x8d"
+			  "\x67\x9f\x77\x7b\xc6\x70\x2c\x7d"
+			  "\x39\xf2\x33\x69\xa9\xd9\xba\xcf"
+			  "\xa5\x30\xe2\x63\x04\x23\x14\x61"
+			  "\xb2\xeb\x05\xe2\xc3\x9b\xe9\xfc"
+			  "\xda\x6c\x19\x07\x8c\x6a\x9d\x1b",
+		.ilen	= 64,
+		.result	= "\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96"
+			  "\xe9\x3d\x7e\x11\x73\x93\x17\x2a"
+			  "\xae\x2d\x8a\x57\x1e\x03\xac\x9c"
+			  "\x9e\xb7\x6f\xac\x45\xaf\x8e\x51"
+			  "\x30\xc8\x1c\x46\xa3\x5c\xe4\x11"
+			  "\xe5\xfb\xc1\x19\x1a\x0a\x52\xef"
+			  "\xf6\x9f\x24\x45\xdf\x4f\x9b\x17"
+			  "\xad\x2b\x41\x7b\xe6\x6c\x37\x10",
+		.rlen	= 64,
+	},
+};
+
+static struct cipher_testvec aes_lrw_enc_tv_template[] = {
+	/* from http://grouper.ieee.org/groups/1619/email/pdf00017.pdf */
+	{ /* LRW-32-AES 1 */
+		.key    = "\x45\x62\xac\x25\xf8\x28\x17\x6d"
+			  "\x4c\x26\x84\x14\xb5\x68\x01\x85"
+			  "\x25\x8e\x2a\x05\xe7\x3e\x9d\x03"
+			  "\xee\x5a\x83\x0c\xcc\x09\x4c\x87",
+		.klen   = 32,
+		.iv     = "\x00\x00\x00\x00\x00\x00\x00\x00"
+			  "\x00\x00\x00\x00\x00\x00\x00\x01",
+		.input  = "\x30\x31\x32\x33\x34\x35\x36\x37"
+			  "\x38\x39\x41\x42\x43\x44\x45\x46",
+		.ilen   = 16,
+		.result = "\xf1\xb2\x73\xcd\x65\xa3\xdf\x5f"
+			  "\xe9\x5d\x48\x92\x54\x63\x4e\xb8",
+		.rlen   = 16,
+	}, { /* LRW-32-AES 2 */
+		.key    = "\x59\x70\x47\x14\xf5\x57\x47\x8c"
+			  "\xd7\x79\xe8\x0f\x54\x88\x79\x44"
+			  "\x0d\x48\xf0\xb7\xb1\x5a\x53\xea"
+			  "\x1c\xaa\x6b\x29\xc2\xca\xfb\xaf",
+		.klen   = 32,
+		.iv     = "\x00\x00\x00\x00\x00\x00\x00\x00"
+			  "\x00\x00\x00\x00\x00\x00\x00\x02",
+		.input  = "\x30\x31\x32\x33\x34\x35\x36\x37"
+			  "\x38\x39\x41\x42\x43\x44\x45\x46",
+		.ilen   = 16,
+		.result = "\x00\xc8\x2b\xae\x95\xbb\xcd\xe5"
+			  "\x27\x4f\x07\x69\xb2\x60\xe1\x36",
+		.rlen   = 16,
+	}, { /* LRW-32-AES 3 */
+		.key    = "\xd8\x2a\x91\x34\xb2\x6a\x56\x50"
+			  "\x30\xfe\x69\xe2\x37\x7f\x98\x47"
+			  "\xcd\xf9\x0b\x16\x0c\x64\x8f\xb6"
+			  "\xb0\x0d\x0d\x1b\xae\x85\x87\x1f",
+		.klen   = 32,
+		.iv     = "\x00\x00\x00\x00\x00\x00\x00\x00"
+			  "\x00\x00\x00\x02\x00\x00\x00\x00",
+		.input  = "\x30\x31\x32\x33\x34\x35\x36\x37"
+			  "\x38\x39\x41\x42\x43\x44\x45\x46",
+		.ilen   = 16,
+		.result = "\x76\x32\x21\x83\xed\x8f\xf1\x82"
+			  "\xf9\x59\x62\x03\x69\x0e\x5e\x01",
+		.rlen   = 16,
+	}, { /* LRW-32-AES 4 */
+		.key    = "\x0f\x6a\xef\xf8\xd3\xd2\xbb\x15"
+			  "\x25\x83\xf7\x3c\x1f\x01\x28\x74"
+			  "\xca\xc6\xbc\x35\x4d\x4a\x65\x54"
+			  "\x90\xae\x61\xcf\x7b\xae\xbd\xcc"
+			  "\xad\xe4\x94\xc5\x4a\x29\xae\x70",
+		.klen   = 40,
+		.iv     = "\x00\x00\x00\x00\x00\x00\x00\x00"
+			  "\x00\x00\x00\x00\x00\x00\x00\x01",
+		.input  = "\x30\x31\x32\x33\x34\x35\x36\x37"
+			  "\x38\x39\x41\x42\x43\x44\x45\x46",
+		.ilen   = 16,
+		.result = "\x9c\x0f\x15\x2f\x55\xa2\xd8\xf0"
+			  "\xd6\x7b\x8f\x9e\x28\x22\xbc\x41",
+		.rlen   = 16,
+	}, { /* LRW-32-AES 5 */
+		.key    = "\x8a\xd4\xee\x10\x2f\xbd\x81\xff"
+			  "\xf8\x86\xce\xac\x93\xc5\xad\xc6"
+			  "\xa0\x19\x07\xc0\x9d\xf7\xbb\xdd"
+			  "\x52\x13\xb2\xb7\xf0\xff\x11\xd8"
+			  "\xd6\x08\xd0\xcd\x2e\xb1\x17\x6f",
+		.klen   = 40,
+		.iv     = "\x00\x00\x00\x00\x00\x00\x00\x00"
+			  "\x00\x00\x00\x02\x00\x00\x00\x00",
+		.input  = "\x30\x31\x32\x33\x34\x35\x36\x37"
+			  "\x38\x39\x41\x42\x43\x44\x45\x46",
+		.ilen   = 16,
+		.result = "\xd4\x27\x6a\x7f\x14\x91\x3d\x65"
+			  "\xc8\x60\x48\x02\x87\xe3\x34\x06",
+		.rlen   = 16,
+	}, { /* LRW-32-AES 6 */
+		.key    = "\xf8\xd4\x76\xff\xd6\x46\xee\x6c"
+			  "\x23\x84\xcb\x1c\x77\xd6\x19\x5d"
+			  "\xfe\xf1\xa9\xf3\x7b\xbc\x8d\x21"
+			  "\xa7\x9c\x21\xf8\xcb\x90\x02\x89"
+			  "\xa8\x45\x34\x8e\xc8\xc5\xb5\xf1"
+			  "\x26\xf5\x0e\x76\xfe\xfd\x1b\x1e",
+		.klen   = 48,
+		.iv     = "\x00\x00\x00\x00\x00\x00\x00\x00"
+			  "\x00\x00\x00\x00\x00\x00\x00\x01",
+		.input  = "\x30\x31\x32\x33\x34\x35\x36\x37"
+			  "\x38\x39\x41\x42\x43\x44\x45\x46",
+		.ilen   = 16,
+		.result = "\xbd\x06\xb8\xe1\xdb\x98\x89\x9e"
+			  "\xc4\x98\xe4\x91\xcf\x1c\x70\x2b",
+		.rlen   = 16,
+	}, { /* LRW-32-AES 7 */
+		.key    = "\xfb\x76\x15\xb2\x3d\x80\x89\x1d"
+			  "\xd4\x70\x98\x0b\xc7\x95\x84\xc8"
+			  "\xb2\xfb\x64\xce\x60\x97\x87\x8d"
+			  "\x17\xfc\xe4\x5a\x49\xe8\x30\xb7"
+			  "\x6e\x78\x17\xe7\x2d\x5e\x12\xd4"
+			  "\x60\x64\x04\x7a\xf1\x2f\x9e\x0c",
+		.klen   = 48,
+		.iv     = "\x00\x00\x00\x00\x00\x00\x00\x00"
+			  "\x00\x00\x00\x02\x00\x00\x00\x00",
+		.input  = "\x30\x31\x32\x33\x34\x35\x36\x37"
+			  "\x38\x39\x41\x42\x43\x44\x45\x46",
+		.ilen   = 16,
+		.result = "\x5b\x90\x8e\xc1\xab\xdd\x67\x5f"
+			  "\x3d\x69\x8a\x95\x53\xc8\x9c\xe5",
+		.rlen   = 16,
+	}, {
+/* http://www.mail-archive.com/stds-p1619@listserv.ieee.org/msg00173.html */
+		.key    = "\xf8\xd4\x76\xff\xd6\x46\xee\x6c"
+			  "\x23\x84\xcb\x1c\x77\xd6\x19\x5d"
+			  "\xfe\xf1\xa9\xf3\x7b\xbc\x8d\x21"
+			  "\xa7\x9c\x21\xf8\xcb\x90\x02\x89"
+			  "\xa8\x45\x34\x8e\xc8\xc5\xb5\xf1"
+			  "\x26\xf5\x0e\x76\xfe\xfd\x1b\x1e",
+		.klen   = 48,
+		.iv     = "\x00\x00\x00\x00\x00\x00\x00\x00"
+			  "\x00\x00\x00\x00\x00\x00\x00\x01",
+		.input  = "\x05\x11\xb7\x18\xab\xc6\x2d\xac"
+			  "\x70\x5d\xf6\x22\x94\xcd\xe5\x6c"
+			  "\x17\x6b\xf6\x1c\xf0\xf3\x6e\xf8"
+			  "\x50\x38\x1f\x71\x49\xb6\x57\xd6"
+			  "\x8f\xcb\x8d\x6b\xe3\xa6\x29\x90"
+			  "\xfe\x2a\x62\x82\xae\x6d\x8b\xf6"
+			  "\xad\x1e\x9e\x20\x5f\x38\xbe\x04"
+			  "\xda\x10\x8e\xed\xa2\xa4\x87\xab"
+			  "\xda\x6b\xb4\x0c\x75\xba\xd3\x7c"
+			  "\xc9\xac\x42\x31\x95\x7c\xc9\x04"
+			  "\xeb\xd5\x6e\x32\x69\x8a\xdb\xa6"
+			  "\x15\xd7\x3f\x4f\x2f\x66\x69\x03"
+			  "\x9c\x1f\x54\x0f\xde\x1f\xf3\x65"
+			  "\x4c\x96\x12\xed\x7c\x92\x03\x01"
+			  "\x6f\xbc\x35\x93\xac\xf1\x27\xf1"
+			  "\xb4\x96\x82\x5a\x5f\xb0\xa0\x50"
+			  "\x89\xa4\x8e\x66\x44\x85\xcc\xfd"
+			  "\x33\x14\x70\xe3\x96\xb2\xc3\xd3"
+			  "\xbb\x54\x5a\x1a\xf9\x74\xa2\xc5"
+			  "\x2d\x64\x75\xdd\xb4\x54\xe6\x74"
+			  "\x8c\xd3\x9d\x9e\x86\xab\x51\x53"
+			  "\xb7\x93\x3e\x6f\xd0\x4e\x2c\x40"
+			  "\xf6\xa8\x2e\x3e\x9d\xf4\x66\xa5"
+			  "\x76\x12\x73\x44\x1a\x56\xd7\x72"
+			  "\x88\xcd\x21\x8c\x4c\x0f\xfe\xda"
+			  "\x95\xe0\x3a\xa6\xa5\x84\x46\xcd"
+			  "\xd5\x3e\x9d\x3a\xe2\x67\xe6\x60"
+			  "\x1a\xe2\x70\x85\x58\xc2\x1b\x09"
+			  "\xe1\xd7\x2c\xca\xad\xa8\x8f\xf9"
+			  "\xac\xb3\x0e\xdb\xca\x2e\xe2\xb8"
+			  "\x51\x71\xd9\x3c\x6c\xf1\x56\xf8"
+			  "\xea\x9c\xf1\xfb\x0c\xe6\xb7\x10"
+			  "\x1c\xf8\xa9\x7c\xe8\x53\x35\xc1"
+			  "\x90\x3e\x76\x4a\x74\xa4\x21\x2c"
+			  "\xf6\x2c\x4e\x0f\x94\x3a\x88\x2e"
+			  "\x41\x09\x6a\x33\x7d\xf6\xdd\x3f"
+			  "\x8d\x23\x31\x74\x84\xeb\x88\x6e"
+			  "\xcc\xb9\xbc\x22\x83\x19\x07\x22"
+			  "\xa5\x2d\xdf\xa5\xf3\x80\x85\x78"
+			  "\x84\x39\x6a\x6d\x6a\x99\x4f\xa5"
+			  "\x15\xfe\x46\xb0\xe4\x6c\xa5\x41"
+			  "\x3c\xce\x8f\x42\x60\x71\xa7\x75"
+			  "\x08\x40\x65\x8a\x82\xbf\xf5\x43"
+			  "\x71\x96\xa9\x4d\x44\x8a\x20\xbe"
+			  "\xfa\x4d\xbb\xc0\x7d\x31\x96\x65"
+			  "\xe7\x75\xe5\x3e\xfd\x92\x3b\xc9"
+			  "\x55\xbb\x16\x7e\xf7\xc2\x8c\xa4"
+			  "\x40\x1d\xe5\xef\x0e\xdf\xe4\x9a"
+			  "\x62\x73\x65\xfd\x46\x63\x25\x3d"
+			  "\x2b\xaf\xe5\x64\xfe\xa5\x5c\xcf"
+			  "\x24\xf3\xb4\xac\x64\xba\xdf\x4b"
+			  "\xc6\x96\x7d\x81\x2d\x8d\x97\xf7"
+			  "\xc5\x68\x77\x84\x32\x2b\xcc\x85"
+			  "\x74\x96\xf0\x12\x77\x61\xb9\xeb"
+			  "\x71\xaa\x82\xcb\x1c\xdb\x89\xc8"
+			  "\xc6\xb5\xe3\x5c\x7d\x39\x07\x24"
+			  "\xda\x39\x87\x45\xc0\x2b\xbb\x01"
+			  "\xac\xbc\x2a\x5c\x7f\xfc\xe8\xce"
+			  "\x6d\x9c\x6f\xed\xd3\xc1\xa1\xd6"
+			  "\xc5\x55\xa9\x66\x2f\xe1\xc8\x32"
+			  "\xa6\x5d\xa4\x3a\x98\x73\xe8\x45"
+			  "\xa4\xc7\xa8\xb4\xf6\x13\x03\xf6"
+			  "\xe9\x2e\xc4\x29\x0f\x84\xdb\xc4"
+			  "\x21\xc4\xc2\x75\x67\x89\x37\x0a",
+		.ilen   = 512,
+		.result = "\x1a\x1d\xa9\x30\xad\xf9\x2f\x9b"
+			  "\xb6\x1d\xae\xef\xf0\x2f\xf8\x5a"
+			  "\x39\x3c\xbf\x2a\xb2\x45\xb2\x23"
+			  "\x1b\x63\x3c\xcf\xaa\xbe\xcf\x4e"
+			  "\xfa\xe8\x29\xc2\x20\x68\x2b\x3c"
+			  "\x2e\x8b\xf7\x6e\x25\xbd\xe3\x3d"
+			  "\x66\x27\xd6\xaf\xd6\x64\x3e\xe3"
+			  "\xe8\x58\x46\x97\x39\x51\x07\xde"
+			  "\xcb\x37\xbc\xa9\xc0\x5f\x75\xc3"
+			  "\x0e\x84\x23\x1d\x16\xd4\x1c\x59"
+			  "\x9c\x1a\x02\x55\xab\x3a\x97\x1d"
+			  "\xdf\xdd\xc7\x06\x51\xd7\x70\xae"
+			  "\x23\xc6\x8c\xf5\x1e\xa0\xe5\x82"
+			  "\xb8\xb2\xbf\x04\xa0\x32\x8e\x68"
+			  "\xeb\xaf\x6e\x2d\x94\x22\x2f\xce"
+			  "\x4c\xb5\x59\xe2\xa2\x2f\xa0\x98"
+			  "\x1a\x97\xc6\xd4\xb5\x00\x59\xf2"
+			  "\x84\x14\x72\xb1\x9a\x6e\xa3\x7f"
+			  "\xea\x20\xe7\xcb\x65\x77\x3a\xdf"
+			  "\xc8\x97\x67\x15\xc2\x2a\x27\xcc"
+			  "\x18\x55\xa1\x24\x0b\x24\x24\xaf"
+			  "\x5b\xec\x68\xb8\xc8\xf5\xba\x63"
+			  "\xff\xed\x89\xce\xd5\x3d\x88\xf3"
+			  "\x25\xef\x05\x7c\x3a\xef\xeb\xd8"
+			  "\x7a\x32\x0d\xd1\x1e\x58\x59\x99"
+			  "\x90\x25\xb5\x26\xb0\xe3\x2b\x6c"
+			  "\x4c\xa9\x8b\x84\x4f\x5e\x01\x50"
+			  "\x41\x30\x58\xc5\x62\x74\x52\x1d"
+			  "\x45\x24\x6a\x42\x64\x4f\x97\x1c"
+			  "\xa8\x66\xb5\x6d\x79\xd4\x0d\x48"
+			  "\xc5\x5f\xf3\x90\x32\xdd\xdd\xe1"
+			  "\xe4\xa9\x9f\xfc\xc3\x52\x5a\x46"
+			  "\xe4\x81\x84\x95\x36\x59\x7a\x6b"
+			  "\xaa\xb3\x60\xad\xce\x9f\x9f\x28"
+			  "\xe0\x01\x75\x22\xc4\x4e\xa9\x62"
+			  "\x5c\x62\x0d\x00\xcb\x13\xe8\x43"
+			  "\x72\xd4\x2d\x53\x46\xb5\xd1\x16"
+			  "\x22\x18\xdf\x34\x33\xf5\xd6\x1c"
+			  "\xb8\x79\x78\x97\x94\xff\x72\x13"
+			  "\x4c\x27\xfc\xcb\xbf\x01\x53\xa6"
+			  "\xb4\x50\x6e\xde\xdf\xb5\x43\xa4"
+			  "\x59\xdf\x52\xf9\x7c\xe0\x11\x6f"
+			  "\x2d\x14\x8e\x24\x61\x2c\xe1\x17"
+			  "\xcc\xce\x51\x0c\x19\x8a\x82\x30"
+			  "\x94\xd5\x3d\x6a\x53\x06\x5e\xbd"
+			  "\xb7\xeb\xfa\xfd\x27\x51\xde\x85"
+			  "\x1e\x86\x53\x11\x53\x94\x00\xee"
+			  "\x2b\x8c\x08\x2a\xbf\xdd\xae\x11"
+			  "\xcb\x1e\xa2\x07\x9a\x80\xcf\x62"
+			  "\x9b\x09\xdc\x95\x3c\x96\x8e\xb1"
+			  "\x09\xbd\xe4\xeb\xdb\xca\x70\x7a"
+			  "\x9e\xfa\x31\x18\x45\x3c\x21\x33"
+			  "\xb0\xb3\x2b\xea\xf3\x71\x2d\xe1"
+			  "\x03\xad\x1b\x48\xd4\x67\x27\xf0"
+			  "\x62\xe4\x3d\xfb\x9b\x08\x76\xe7"
+			  "\xdd\x2b\x01\x39\x04\x5a\x58\x7a"
+			  "\xf7\x11\x90\xec\xbd\x51\x5c\x32"
+			  "\x6b\xd7\x35\x39\x02\x6b\xf2\xa6"
+			  "\xd0\x0d\x07\xe1\x06\xc4\x5b\x7d"
+			  "\xe4\x6a\xd7\xee\x15\x1f\x83\xb4"
+			  "\xa3\xa7\x5e\xc3\x90\xb7\xef\xd3"
+			  "\xb7\x4f\xf8\x92\x4c\xb7\x3c\x29"
+			  "\xcd\x7e\x2b\x5d\x43\xea\x42\xe7"
+			  "\x74\x3f\x7d\x58\x88\x75\xde\x3e",
+		.rlen   = 512,
+	}
+};
+
+static struct cipher_testvec aes_lrw_dec_tv_template[] = {
+	/* from http://grouper.ieee.org/groups/1619/email/pdf00017.pdf */
+	/* same as enc vectors with input and result reversed */
+	{ /* LRW-32-AES 1 */
+		.key    = "\x45\x62\xac\x25\xf8\x28\x17\x6d"
+			  "\x4c\x26\x84\x14\xb5\x68\x01\x85"
+			  "\x25\x8e\x2a\x05\xe7\x3e\x9d\x03"
+			  "\xee\x5a\x83\x0c\xcc\x09\x4c\x87",
+		.klen   = 32,
+		.iv     = "\x00\x00\x00\x00\x00\x00\x00\x00"
+			  "\x00\x00\x00\x00\x00\x00\x00\x01",
+		.input  = "\xf1\xb2\x73\xcd\x65\xa3\xdf\x5f"
+			  "\xe9\x5d\x48\x92\x54\x63\x4e\xb8",
+		.ilen   = 16,
+		.result = "\x30\x31\x32\x33\x34\x35\x36\x37"
+			  "\x38\x39\x41\x42\x43\x44\x45\x46",
+		.rlen   = 16,
+	}, { /* LRW-32-AES 2 */
+		.key    = "\x59\x70\x47\x14\xf5\x57\x47\x8c"
+			  "\xd7\x79\xe8\x0f\x54\x88\x79\x44"
+			  "\x0d\x48\xf0\xb7\xb1\x5a\x53\xea"
+			  "\x1c\xaa\x6b\x29\xc2\xca\xfb\xaf",
+		.klen   = 32,
+		.iv     = "\x00\x00\x00\x00\x00\x00\x00\x00"
+			  "\x00\x00\x00\x00\x00\x00\x00\x02",
+		.input  = "\x00\xc8\x2b\xae\x95\xbb\xcd\xe5"
+			  "\x27\x4f\x07\x69\xb2\x60\xe1\x36",
+		.ilen   = 16,
+		.result  = "\x30\x31\x32\x33\x34\x35\x36\x37"
+			   "\x38\x39\x41\x42\x43\x44\x45\x46",
+		.rlen   = 16,
+	}, { /* LRW-32-AES 3 */
+		.key    = "\xd8\x2a\x91\x34\xb2\x6a\x56\x50"
+			  "\x30\xfe\x69\xe2\x37\x7f\x98\x47"
+			  "\xcd\xf9\x0b\x16\x0c\x64\x8f\xb6"
+			  "\xb0\x0d\x0d\x1b\xae\x85\x87\x1f",
+		.klen   = 32,
+		.iv     = "\x00\x00\x00\x00\x00\x00\x00\x00"
+			  "\x00\x00\x00\x02\x00\x00\x00\x00",
+		.input  = "\x76\x32\x21\x83\xed\x8f\xf1\x82"
+			  "\xf9\x59\x62\x03\x69\x0e\x5e\x01",
+		.ilen   = 16,
+		.result = "\x30\x31\x32\x33\x34\x35\x36\x37"
+			  "\x38\x39\x41\x42\x43\x44\x45\x46",
+		.rlen   = 16,
+	}, { /* LRW-32-AES 4 */
+		.key    = "\x0f\x6a\xef\xf8\xd3\xd2\xbb\x15"
+			  "\x25\x83\xf7\x3c\x1f\x01\x28\x74"
+			  "\xca\xc6\xbc\x35\x4d\x4a\x65\x54"
+			  "\x90\xae\x61\xcf\x7b\xae\xbd\xcc"
+			  "\xad\xe4\x94\xc5\x4a\x29\xae\x70",
+		.klen   = 40,
+		.iv     = "\x00\x00\x00\x00\x00\x00\x00\x00"
+			  "\x00\x00\x00\x00\x00\x00\x00\x01",
+		.input  = "\x9c\x0f\x15\x2f\x55\xa2\xd8\xf0"
+			  "\xd6\x7b\x8f\x9e\x28\x22\xbc\x41",
+		.ilen   = 16,
+		.result = "\x30\x31\x32\x33\x34\x35\x36\x37"
+			  "\x38\x39\x41\x42\x43\x44\x45\x46",
+		.rlen   = 16,
+	}, { /* LRW-32-AES 5 */
+		.key    = "\x8a\xd4\xee\x10\x2f\xbd\x81\xff"
+			  "\xf8\x86\xce\xac\x93\xc5\xad\xc6"
+			  "\xa0\x19\x07\xc0\x9d\xf7\xbb\xdd"
+			  "\x52\x13\xb2\xb7\xf0\xff\x11\xd8"
+			  "\xd6\x08\xd0\xcd\x2e\xb1\x17\x6f",
+		.klen   = 40,
+		.iv     = "\x00\x00\x00\x00\x00\x00\x00\x00"
+			  "\x00\x00\x00\x02\x00\x00\x00\x00",
+		.input  = "\xd4\x27\x6a\x7f\x14\x91\x3d\x65"
+			  "\xc8\x60\x48\x02\x87\xe3\x34\x06",
+		.ilen   = 16,
+		.result = "\x30\x31\x32\x33\x34\x35\x36\x37"
+			  "\x38\x39\x41\x42\x43\x44\x45\x46",
+		.rlen   = 16,
+	}, { /* LRW-32-AES 6 */
+		.key    = "\xf8\xd4\x76\xff\xd6\x46\xee\x6c"
+			  "\x23\x84\xcb\x1c\x77\xd6\x19\x5d"
+			  "\xfe\xf1\xa9\xf3\x7b\xbc\x8d\x21"
+			  "\xa7\x9c\x21\xf8\xcb\x90\x02\x89"
+			  "\xa8\x45\x34\x8e\xc8\xc5\xb5\xf1"
+			  "\x26\xf5\x0e\x76\xfe\xfd\x1b\x1e",
+		.klen   = 48,
+		.iv     = "\x00\x00\x00\x00\x00\x00\x00\x00"
+			  "\x00\x00\x00\x00\x00\x00\x00\x01",
+		.input  = "\xbd\x06\xb8\xe1\xdb\x98\x89\x9e"
+			  "\xc4\x98\xe4\x91\xcf\x1c\x70\x2b",
+		.ilen   = 16,
+		.result = "\x30\x31\x32\x33\x34\x35\x36\x37"
+			  "\x38\x39\x41\x42\x43\x44\x45\x46",
+		.rlen   = 16,
+	}, { /* LRW-32-AES 7 */
+		.key    = "\xfb\x76\x15\xb2\x3d\x80\x89\x1d"
+			  "\xd4\x70\x98\x0b\xc7\x95\x84\xc8"
+			  "\xb2\xfb\x64\xce\x60\x97\x87\x8d"
+			  "\x17\xfc\xe4\x5a\x49\xe8\x30\xb7"
+			  "\x6e\x78\x17\xe7\x2d\x5e\x12\xd4"
+			  "\x60\x64\x04\x7a\xf1\x2f\x9e\x0c",
+		.klen   = 48,
+		.iv     = "\x00\x00\x00\x00\x00\x00\x00\x00"
+			  "\x00\x00\x00\x02\x00\x00\x00\x00",
+		.input  = "\x5b\x90\x8e\xc1\xab\xdd\x67\x5f"
+			  "\x3d\x69\x8a\x95\x53\xc8\x9c\xe5",
+		.ilen   = 16,
+		.result = "\x30\x31\x32\x33\x34\x35\x36\x37"
+			  "\x38\x39\x41\x42\x43\x44\x45\x46",
+		.rlen   = 16,
+	}, {
+/* http://www.mail-archive.com/stds-p1619@listserv.ieee.org/msg00173.html */
+		.key    = "\xf8\xd4\x76\xff\xd6\x46\xee\x6c"
+			  "\x23\x84\xcb\x1c\x77\xd6\x19\x5d"
+			  "\xfe\xf1\xa9\xf3\x7b\xbc\x8d\x21"
+			  "\xa7\x9c\x21\xf8\xcb\x90\x02\x89"
+			  "\xa8\x45\x34\x8e\xc8\xc5\xb5\xf1"
+			  "\x26\xf5\x0e\x76\xfe\xfd\x1b\x1e",
+		.klen   = 48,
+		.iv     = "\x00\x00\x00\x00\x00\x00\x00\x00"
+			  "\x00\x00\x00\x00\x00\x00\x00\x01",
+		.input	= "\x1a\x1d\xa9\x30\xad\xf9\x2f\x9b"
+			  "\xb6\x1d\xae\xef\xf0\x2f\xf8\x5a"
+			  "\x39\x3c\xbf\x2a\xb2\x45\xb2\x23"
+			  "\x1b\x63\x3c\xcf\xaa\xbe\xcf\x4e"
+			  "\xfa\xe8\x29\xc2\x20\x68\x2b\x3c"
+			  "\x2e\x8b\xf7\x6e\x25\xbd\xe3\x3d"
+			  "\x66\x27\xd6\xaf\xd6\x64\x3e\xe3"
+			  "\xe8\x58\x46\x97\x39\x51\x07\xde"
+			  "\xcb\x37\xbc\xa9\xc0\x5f\x75\xc3"
+			  "\x0e\x84\x23\x1d\x16\xd4\x1c\x59"
+			  "\x9c\x1a\x02\x55\xab\x3a\x97\x1d"
+			  "\xdf\xdd\xc7\x06\x51\xd7\x70\xae"
+			  "\x23\xc6\x8c\xf5\x1e\xa0\xe5\x82"
+			  "\xb8\xb2\xbf\x04\xa0\x32\x8e\x68"
+			  "\xeb\xaf\x6e\x2d\x94\x22\x2f\xce"
+			  "\x4c\xb5\x59\xe2\xa2\x2f\xa0\x98"
+			  "\x1a\x97\xc6\xd4\xb5\x00\x59\xf2"
+			  "\x84\x14\x72\xb1\x9a\x6e\xa3\x7f"
+			  "\xea\x20\xe7\xcb\x65\x77\x3a\xdf"
+			  "\xc8\x97\x67\x15\xc2\x2a\x27\xcc"
+			  "\x18\x55\xa1\x24\x0b\x24\x24\xaf"
+			  "\x5b\xec\x68\xb8\xc8\xf5\xba\x63"
+			  "\xff\xed\x89\xce\xd5\x3d\x88\xf3"
+			  "\x25\xef\x05\x7c\x3a\xef\xeb\xd8"
+			  "\x7a\x32\x0d\xd1\x1e\x58\x59\x99"
+			  "\x90\x25\xb5\x26\xb0\xe3\x2b\x6c"
+			  "\x4c\xa9\x8b\x84\x4f\x5e\x01\x50"
+			  "\x41\x30\x58\xc5\x62\x74\x52\x1d"
+			  "\x45\x24\x6a\x42\x64\x4f\x97\x1c"
+			  "\xa8\x66\xb5\x6d\x79\xd4\x0d\x48"
+			  "\xc5\x5f\xf3\x90\x32\xdd\xdd\xe1"
+			  "\xe4\xa9\x9f\xfc\xc3\x52\x5a\x46"
+			  "\xe4\x81\x84\x95\x36\x59\x7a\x6b"
+			  "\xaa\xb3\x60\xad\xce\x9f\x9f\x28"
+			  "\xe0\x01\x75\x22\xc4\x4e\xa9\x62"
+			  "\x5c\x62\x0d\x00\xcb\x13\xe8\x43"
+			  "\x72\xd4\x2d\x53\x46\xb5\xd1\x16"
+			  "\x22\x18\xdf\x34\x33\xf5\xd6\x1c"
+			  "\xb8\x79\x78\x97\x94\xff\x72\x13"
+			  "\x4c\x27\xfc\xcb\xbf\x01\x53\xa6"
+			  "\xb4\x50\x6e\xde\xdf\xb5\x43\xa4"
+			  "\x59\xdf\x52\xf9\x7c\xe0\x11\x6f"
+			  "\x2d\x14\x8e\x24\x61\x2c\xe1\x17"
+			  "\xcc\xce\x51\x0c\x19\x8a\x82\x30"
+			  "\x94\xd5\x3d\x6a\x53\x06\x5e\xbd"
+			  "\xb7\xeb\xfa\xfd\x27\x51\xde\x85"
+			  "\x1e\x86\x53\x11\x53\x94\x00\xee"
+			  "\x2b\x8c\x08\x2a\xbf\xdd\xae\x11"
+			  "\xcb\x1e\xa2\x07\x9a\x80\xcf\x62"
+			  "\x9b\x09\xdc\x95\x3c\x96\x8e\xb1"
+			  "\x09\xbd\xe4\xeb\xdb\xca\x70\x7a"
+			  "\x9e\xfa\x31\x18\x45\x3c\x21\x33"
+			  "\xb0\xb3\x2b\xea\xf3\x71\x2d\xe1"
+			  "\x03\xad\x1b\x48\xd4\x67\x27\xf0"
+			  "\x62\xe4\x3d\xfb\x9b\x08\x76\xe7"
+			  "\xdd\x2b\x01\x39\x04\x5a\x58\x7a"
+			  "\xf7\x11\x90\xec\xbd\x51\x5c\x32"
+			  "\x6b\xd7\x35\x39\x02\x6b\xf2\xa6"
+			  "\xd0\x0d\x07\xe1\x06\xc4\x5b\x7d"
+			  "\xe4\x6a\xd7\xee\x15\x1f\x83\xb4"
+			  "\xa3\xa7\x5e\xc3\x90\xb7\xef\xd3"
+			  "\xb7\x4f\xf8\x92\x4c\xb7\x3c\x29"
+			  "\xcd\x7e\x2b\x5d\x43\xea\x42\xe7"
+			  "\x74\x3f\x7d\x58\x88\x75\xde\x3e",
+		.ilen   = 512,
+		.result	= "\x05\x11\xb7\x18\xab\xc6\x2d\xac"
+			  "\x70\x5d\xf6\x22\x94\xcd\xe5\x6c"
+			  "\x17\x6b\xf6\x1c\xf0\xf3\x6e\xf8"
+			  "\x50\x38\x1f\x71\x49\xb6\x57\xd6"
+			  "\x8f\xcb\x8d\x6b\xe3\xa6\x29\x90"
+			  "\xfe\x2a\x62\x82\xae\x6d\x8b\xf6"
+			  "\xad\x1e\x9e\x20\x5f\x38\xbe\x04"
+			  "\xda\x10\x8e\xed\xa2\xa4\x87\xab"
+			  "\xda\x6b\xb4\x0c\x75\xba\xd3\x7c"
+			  "\xc9\xac\x42\x31\x95\x7c\xc9\x04"
+			  "\xeb\xd5\x6e\x32\x69\x8a\xdb\xa6"
+			  "\x15\xd7\x3f\x4f\x2f\x66\x69\x03"
+			  "\x9c\x1f\x54\x0f\xde\x1f\xf3\x65"
+			  "\x4c\x96\x12\xed\x7c\x92\x03\x01"
+			  "\x6f\xbc\x35\x93\xac\xf1\x27\xf1"
+			  "\xb4\x96\x82\x5a\x5f\xb0\xa0\x50"
+			  "\x89\xa4\x8e\x66\x44\x85\xcc\xfd"
+			  "\x33\x14\x70\xe3\x96\xb2\xc3\xd3"
+			  "\xbb\x54\x5a\x1a\xf9\x74\xa2\xc5"
+			  "\x2d\x64\x75\xdd\xb4\x54\xe6\x74"
+			  "\x8c\xd3\x9d\x9e\x86\xab\x51\x53"
+			  "\xb7\x93\x3e\x6f\xd0\x4e\x2c\x40"
+			  "\xf6\xa8\x2e\x3e\x9d\xf4\x66\xa5"
+			  "\x76\x12\x73\x44\x1a\x56\xd7\x72"
+			  "\x88\xcd\x21\x8c\x4c\x0f\xfe\xda"
+			  "\x95\xe0\x3a\xa6\xa5\x84\x46\xcd"
+			  "\xd5\x3e\x9d\x3a\xe2\x67\xe6\x60"
+			  "\x1a\xe2\x70\x85\x58\xc2\x1b\x09"
+			  "\xe1\xd7\x2c\xca\xad\xa8\x8f\xf9"
+			  "\xac\xb3\x0e\xdb\xca\x2e\xe2\xb8"
+			  "\x51\x71\xd9\x3c\x6c\xf1\x56\xf8"
+			  "\xea\x9c\xf1\xfb\x0c\xe6\xb7\x10"
+			  "\x1c\xf8\xa9\x7c\xe8\x53\x35\xc1"
+			  "\x90\x3e\x76\x4a\x74\xa4\x21\x2c"
+			  "\xf6\x2c\x4e\x0f\x94\x3a\x88\x2e"
+			  "\x41\x09\x6a\x33\x7d\xf6\xdd\x3f"
+			  "\x8d\x23\x31\x74\x84\xeb\x88\x6e"
+			  "\xcc\xb9\xbc\x22\x83\x19\x07\x22"
+			  "\xa5\x2d\xdf\xa5\xf3\x80\x85\x78"
+			  "\x84\x39\x6a\x6d\x6a\x99\x4f\xa5"
+			  "\x15\xfe\x46\xb0\xe4\x6c\xa5\x41"
+			  "\x3c\xce\x8f\x42\x60\x71\xa7\x75"
+			  "\x08\x40\x65\x8a\x82\xbf\xf5\x43"
+			  "\x71\x96\xa9\x4d\x44\x8a\x20\xbe"
+			  "\xfa\x4d\xbb\xc0\x7d\x31\x96\x65"
+			  "\xe7\x75\xe5\x3e\xfd\x92\x3b\xc9"
+			  "\x55\xbb\x16\x7e\xf7\xc2\x8c\xa4"
+			  "\x40\x1d\xe5\xef\x0e\xdf\xe4\x9a"
+			  "\x62\x73\x65\xfd\x46\x63\x25\x3d"
+			  "\x2b\xaf\xe5\x64\xfe\xa5\x5c\xcf"
+			  "\x24\xf3\xb4\xac\x64\xba\xdf\x4b"
+			  "\xc6\x96\x7d\x81\x2d\x8d\x97\xf7"
+			  "\xc5\x68\x77\x84\x32\x2b\xcc\x85"
+			  "\x74\x96\xf0\x12\x77\x61\xb9\xeb"
+			  "\x71\xaa\x82\xcb\x1c\xdb\x89\xc8"
+			  "\xc6\xb5\xe3\x5c\x7d\x39\x07\x24"
+			  "\xda\x39\x87\x45\xc0\x2b\xbb\x01"
+			  "\xac\xbc\x2a\x5c\x7f\xfc\xe8\xce"
+			  "\x6d\x9c\x6f\xed\xd3\xc1\xa1\xd6"
+			  "\xc5\x55\xa9\x66\x2f\xe1\xc8\x32"
+			  "\xa6\x5d\xa4\x3a\x98\x73\xe8\x45"
+			  "\xa4\xc7\xa8\xb4\xf6\x13\x03\xf6"
+			  "\xe9\x2e\xc4\x29\x0f\x84\xdb\xc4"
+			  "\x21\xc4\xc2\x75\x67\x89\x37\x0a",
+		.rlen   = 512,
+	}
+};
+
+static struct cipher_testvec aes_xts_enc_tv_template[] = {
+	/* http://grouper.ieee.org/groups/1619/email/pdf00086.pdf */
+	{ /* XTS-AES 1 */
+		.key    = "\x00\x00\x00\x00\x00\x00\x00\x00"
+			  "\x00\x00\x00\x00\x00\x00\x00\x00"
+			  "\x00\x00\x00\x00\x00\x00\x00\x00"
+			  "\x00\x00\x00\x00\x00\x00\x00\x00",
+		.klen   = 32,
+		.iv     = "\x00\x00\x00\x00\x00\x00\x00\x00"
+			  "\x00\x00\x00\x00\x00\x00\x00\x00",
+		.input  = "\x00\x00\x00\x00\x00\x00\x00\x00"
+			  "\x00\x00\x00\x00\x00\x00\x00\x00"
+			  "\x00\x00\x00\x00\x00\x00\x00\x00"
+			  "\x00\x00\x00\x00\x00\x00\x00\x00",
+		.ilen   = 32,
+		.result = "\x91\x7c\xf6\x9e\xbd\x68\xb2\xec"
+			  "\x9b\x9f\xe9\xa3\xea\xdd\xa6\x92"
+			  "\xcd\x43\xd2\xf5\x95\x98\xed\x85"
+			  "\x8c\x02\xc2\x65\x2f\xbf\x92\x2e",
+		.rlen   = 32,
+	}, { /* XTS-AES 2 */
+		.key    = "\x11\x11\x11\x11\x11\x11\x11\x11"
+			  "\x11\x11\x11\x11\x11\x11\x11\x11"
+			  "\x22\x22\x22\x22\x22\x22\x22\x22"
+			  "\x22\x22\x22\x22\x22\x22\x22\x22",
+		.klen   = 32,
+		.iv     = "\x33\x33\x33\x33\x33\x00\x00\x00"
+			  "\x00\x00\x00\x00\x00\x00\x00\x00",
+		.input  = "\x44\x44\x44\x44\x44\x44\x44\x44"
+			  "\x44\x44\x44\x44\x44\x44\x44\x44"
+			  "\x44\x44\x44\x44\x44\x44\x44\x44"
+			  "\x44\x44\x44\x44\x44\x44\x44\x44",
+		.ilen   = 32,
+		.result = "\xc4\x54\x18\x5e\x6a\x16\x93\x6e"
+			  "\x39\x33\x40\x38\xac\xef\x83\x8b"
+			  "\xfb\x18\x6f\xff\x74\x80\xad\xc4"
+			  "\x28\x93\x82\xec\xd6\xd3\x94\xf0",
+		.rlen   = 32,
+	}, { /* XTS-AES 3 */
+		.key    = "\xff\xfe\xfd\xfc\xfb\xfa\xf9\xf8"
+			  "\xf7\xf6\xf5\xf4\xf3\xf2\xf1\xf0"
+			  "\x22\x22\x22\x22\x22\x22\x22\x22"
+			  "\x22\x22\x22\x22\x22\x22\x22\x22",
+		.klen   = 32,
+		.iv     = "\x33\x33\x33\x33\x33\x00\x00\x00"
+			  "\x00\x00\x00\x00\x00\x00\x00\x00",
+		.input  = "\x44\x44\x44\x44\x44\x44\x44\x44"
+			  "\x44\x44\x44\x44\x44\x44\x44\x44"
+			  "\x44\x44\x44\x44\x44\x44\x44\x44"
+			  "\x44\x44\x44\x44\x44\x44\x44\x44",
+		.ilen   = 32,
+		.result = "\xaf\x85\x33\x6b\x59\x7a\xfc\x1a"
+			  "\x90\x0b\x2e\xb2\x1e\xc9\x49\xd2"
+			  "\x92\xdf\x4c\x04\x7e\x0b\x21\x53"
+			  "\x21\x86\xa5\x97\x1a\x22\x7a\x89",
+		.rlen   = 32,
+	}, { /* XTS-AES 4 */
+		.key    = "\x27\x18\x28\x18\x28\x45\x90\x45"
+			  "\x23\x53\x60\x28\x74\x71\x35\x26"
+			  "\x31\x41\x59\x26\x53\x58\x97\x93"
+			  "\x23\x84\x62\x64\x33\x83\x27\x95",
+		.klen   = 32,
+		.iv     = "\x00\x00\x00\x00\x00\x00\x00\x00"
+			  "\x00\x00\x00\x00\x00\x00\x00\x00",
+		.input  = "\x00\x01\x02\x03\x04\x05\x06\x07"
+			  "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+			  "\x10\x11\x12\x13\x14\x15\x16\x17"
+			  "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
+			  "\x20\x21\x22\x23\x24\x25\x26\x27"
+			  "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f"
+			  "\x30\x31\x32\x33\x34\x35\x36\x37"
+			  "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f"
+			  "\x40\x41\x42\x43\x44\x45\x46\x47"
+			  "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f"
+			  "\x50\x51\x52\x53\x54\x55\x56\x57"
+			  "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f"
+			  "\x60\x61\x62\x63\x64\x65\x66\x67"
+			  "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f"
+			  "\x70\x71\x72\x73\x74\x75\x76\x77"
+			  "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f"
+			  "\x80\x81\x82\x83\x84\x85\x86\x87"
+			  "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"
+			  "\x90\x91\x92\x93\x94\x95\x96\x97"
+			  "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f"
+			  "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7"
+			  "\xa8\xa9\xaa\xab\xac\xad\xae\xaf"
+			  "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7"
+			  "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf"
+			  "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7"
+			  "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf"
+			  "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7"
+			  "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf"
+			  "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7"
+			  "\xe8\xe9\xea\xeb\xec\xed\xee\xef"
+			  "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7"
+			  "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff"
+			  "\x00\x01\x02\x03\x04\x05\x06\x07"
+			  "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+			  "\x10\x11\x12\x13\x14\x15\x16\x17"
+			  "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
+			  "\x20\x21\x22\x23\x24\x25\x26\x27"
+			  "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f"
+			  "\x30\x31\x32\x33\x34\x35\x36\x37"
+			  "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f"
+			  "\x40\x41\x42\x43\x44\x45\x46\x47"
+			  "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f"
+			  "\x50\x51\x52\x53\x54\x55\x56\x57"
+			  "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f"
+			  "\x60\x61\x62\x63\x64\x65\x66\x67"
+			  "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f"
+			  "\x70\x71\x72\x73\x74\x75\x76\x77"
+			  "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f"
+			  "\x80\x81\x82\x83\x84\x85\x86\x87"
+			  "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"
+			  "\x90\x91\x92\x93\x94\x95\x96\x97"
+			  "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f"
+			  "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7"
+			  "\xa8\xa9\xaa\xab\xac\xad\xae\xaf"
+			  "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7"
+			  "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf"
+			  "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7"
+			  "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf"
+			  "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7"
+			  "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf"
+			  "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7"
+			  "\xe8\xe9\xea\xeb\xec\xed\xee\xef"
+			  "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7"
+			  "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff",
+		.ilen   = 512,
+		.result = "\x27\xa7\x47\x9b\xef\xa1\xd4\x76"
+			  "\x48\x9f\x30\x8c\xd4\xcf\xa6\xe2"
+			  "\xa9\x6e\x4b\xbe\x32\x08\xff\x25"
+			  "\x28\x7d\xd3\x81\x96\x16\xe8\x9c"
+			  "\xc7\x8c\xf7\xf5\xe5\x43\x44\x5f"
+			  "\x83\x33\xd8\xfa\x7f\x56\x00\x00"
+			  "\x05\x27\x9f\xa5\xd8\xb5\xe4\xad"
+			  "\x40\xe7\x36\xdd\xb4\xd3\x54\x12"
+			  "\x32\x80\x63\xfd\x2a\xab\x53\xe5"
+			  "\xea\x1e\x0a\x9f\x33\x25\x00\xa5"
+			  "\xdf\x94\x87\xd0\x7a\x5c\x92\xcc"
+			  "\x51\x2c\x88\x66\xc7\xe8\x60\xce"
+			  "\x93\xfd\xf1\x66\xa2\x49\x12\xb4"
+			  "\x22\x97\x61\x46\xae\x20\xce\x84"
+			  "\x6b\xb7\xdc\x9b\xa9\x4a\x76\x7a"
+			  "\xae\xf2\x0c\x0d\x61\xad\x02\x65"
+			  "\x5e\xa9\x2d\xc4\xc4\xe4\x1a\x89"
+			  "\x52\xc6\x51\xd3\x31\x74\xbe\x51"
+			  "\xa1\x0c\x42\x11\x10\xe6\xd8\x15"
+			  "\x88\xed\xe8\x21\x03\xa2\x52\xd8"
+			  "\xa7\x50\xe8\x76\x8d\xef\xff\xed"
+			  "\x91\x22\x81\x0a\xae\xb9\x9f\x91"
+			  "\x72\xaf\x82\xb6\x04\xdc\x4b\x8e"
+			  "\x51\xbc\xb0\x82\x35\xa6\xf4\x34"
+			  "\x13\x32\xe4\xca\x60\x48\x2a\x4b"
+			  "\xa1\xa0\x3b\x3e\x65\x00\x8f\xc5"
+			  "\xda\x76\xb7\x0b\xf1\x69\x0d\xb4"
+			  "\xea\xe2\x9c\x5f\x1b\xad\xd0\x3c"
+			  "\x5c\xcf\x2a\x55\xd7\x05\xdd\xcd"
+			  "\x86\xd4\x49\x51\x1c\xeb\x7e\xc3"
+			  "\x0b\xf1\x2b\x1f\xa3\x5b\x91\x3f"
+			  "\x9f\x74\x7a\x8a\xfd\x1b\x13\x0e"
+			  "\x94\xbf\xf9\x4e\xff\xd0\x1a\x91"
+			  "\x73\x5c\xa1\x72\x6a\xcd\x0b\x19"
+			  "\x7c\x4e\x5b\x03\x39\x36\x97\xe1"
+			  "\x26\x82\x6f\xb6\xbb\xde\x8e\xcc"
+			  "\x1e\x08\x29\x85\x16\xe2\xc9\xed"
+			  "\x03\xff\x3c\x1b\x78\x60\xf6\xde"
+			  "\x76\xd4\xce\xcd\x94\xc8\x11\x98"
+			  "\x55\xef\x52\x97\xca\x67\xe9\xf3"
+			  "\xe7\xff\x72\xb1\xe9\x97\x85\xca"
+			  "\x0a\x7e\x77\x20\xc5\xb3\x6d\xc6"
+			  "\xd7\x2c\xac\x95\x74\xc8\xcb\xbc"
+			  "\x2f\x80\x1e\x23\xe5\x6f\xd3\x44"
+			  "\xb0\x7f\x22\x15\x4b\xeb\xa0\xf0"
+			  "\x8c\xe8\x89\x1e\x64\x3e\xd9\x95"
+			  "\xc9\x4d\x9a\x69\xc9\xf1\xb5\xf4"
+			  "\x99\x02\x7a\x78\x57\x2a\xee\xbd"
+			  "\x74\xd2\x0c\xc3\x98\x81\xc2\x13"
+			  "\xee\x77\x0b\x10\x10\xe4\xbe\xa7"
+			  "\x18\x84\x69\x77\xae\x11\x9f\x7a"
+			  "\x02\x3a\xb5\x8c\xca\x0a\xd7\x52"
+			  "\xaf\xe6\x56\xbb\x3c\x17\x25\x6a"
+			  "\x9f\x6e\x9b\xf1\x9f\xdd\x5a\x38"
+			  "\xfc\x82\xbb\xe8\x72\xc5\x53\x9e"
+			  "\xdb\x60\x9e\xf4\xf7\x9c\x20\x3e"
+			  "\xbb\x14\x0f\x2e\x58\x3c\xb2\xad"
+			  "\x15\xb4\xaa\x5b\x65\x50\x16\xa8"
+			  "\x44\x92\x77\xdb\xd4\x77\xef\x2c"
+			  "\x8d\x6c\x01\x7d\xb7\x38\xb1\x8d"
+			  "\xeb\x4a\x42\x7d\x19\x23\xce\x3f"
+			  "\xf2\x62\x73\x57\x79\xa4\x18\xf2"
+			  "\x0a\x28\x2d\xf9\x20\x14\x7b\xea"
+			  "\xbe\x42\x1e\xe5\x31\x9d\x05\x68",
+		.rlen   = 512,
+	}
+};
+
+static struct cipher_testvec aes_xts_dec_tv_template[] = {
+	/* http://grouper.ieee.org/groups/1619/email/pdf00086.pdf */
+	{ /* XTS-AES 1 */
+		.key    = "\x00\x00\x00\x00\x00\x00\x00\x00"
+			  "\x00\x00\x00\x00\x00\x00\x00\x00"
+			  "\x00\x00\x00\x00\x00\x00\x00\x00"
+			  "\x00\x00\x00\x00\x00\x00\x00\x00",
+		.klen   = 32,
+		.iv     = "\x00\x00\x00\x00\x00\x00\x00\x00"
+			  "\x00\x00\x00\x00\x00\x00\x00\x00",
+		.input = "\x91\x7c\xf6\x9e\xbd\x68\xb2\xec"
+			 "\x9b\x9f\xe9\xa3\xea\xdd\xa6\x92"
+			 "\xcd\x43\xd2\xf5\x95\x98\xed\x85"
+			 "\x8c\x02\xc2\x65\x2f\xbf\x92\x2e",
+		.ilen   = 32,
+		.result  = "\x00\x00\x00\x00\x00\x00\x00\x00"
+			   "\x00\x00\x00\x00\x00\x00\x00\x00"
+			   "\x00\x00\x00\x00\x00\x00\x00\x00"
+			   "\x00\x00\x00\x00\x00\x00\x00\x00",
+		.rlen   = 32,
+	}, { /* XTS-AES 2 */
+		.key    = "\x11\x11\x11\x11\x11\x11\x11\x11"
+			  "\x11\x11\x11\x11\x11\x11\x11\x11"
+			  "\x22\x22\x22\x22\x22\x22\x22\x22"
+			  "\x22\x22\x22\x22\x22\x22\x22\x22",
+		.klen   = 32,
+		.iv     = "\x33\x33\x33\x33\x33\x00\x00\x00"
+			  "\x00\x00\x00\x00\x00\x00\x00\x00",
+		.input  = "\xc4\x54\x18\x5e\x6a\x16\x93\x6e"
+			  "\x39\x33\x40\x38\xac\xef\x83\x8b"
+			  "\xfb\x18\x6f\xff\x74\x80\xad\xc4"
+			  "\x28\x93\x82\xec\xd6\xd3\x94\xf0",
+		.ilen   = 32,
+		.result = "\x44\x44\x44\x44\x44\x44\x44\x44"
+			  "\x44\x44\x44\x44\x44\x44\x44\x44"
+			  "\x44\x44\x44\x44\x44\x44\x44\x44"
+			  "\x44\x44\x44\x44\x44\x44\x44\x44",
+		.rlen   = 32,
+	}, { /* XTS-AES 3 */
+		.key    = "\xff\xfe\xfd\xfc\xfb\xfa\xf9\xf8"
+			  "\xf7\xf6\xf5\xf4\xf3\xf2\xf1\xf0"
+			  "\x22\x22\x22\x22\x22\x22\x22\x22"
+			  "\x22\x22\x22\x22\x22\x22\x22\x22",
+		.klen   = 32,
+		.iv     = "\x33\x33\x33\x33\x33\x00\x00\x00"
+			  "\x00\x00\x00\x00\x00\x00\x00\x00",
+		.input = "\xaf\x85\x33\x6b\x59\x7a\xfc\x1a"
+			  "\x90\x0b\x2e\xb2\x1e\xc9\x49\xd2"
+			  "\x92\xdf\x4c\x04\x7e\x0b\x21\x53"
+			  "\x21\x86\xa5\x97\x1a\x22\x7a\x89",
+		.ilen   = 32,
+		.result  = "\x44\x44\x44\x44\x44\x44\x44\x44"
+			  "\x44\x44\x44\x44\x44\x44\x44\x44"
+			  "\x44\x44\x44\x44\x44\x44\x44\x44"
+			  "\x44\x44\x44\x44\x44\x44\x44\x44",
+		.rlen   = 32,
+	}, { /* XTS-AES 4 */
+		.key    = "\x27\x18\x28\x18\x28\x45\x90\x45"
+			  "\x23\x53\x60\x28\x74\x71\x35\x26"
+			  "\x31\x41\x59\x26\x53\x58\x97\x93"
+			  "\x23\x84\x62\x64\x33\x83\x27\x95",
+		.klen   = 32,
+		.iv     = "\x00\x00\x00\x00\x00\x00\x00\x00"
+			  "\x00\x00\x00\x00\x00\x00\x00\x00",
+		.input  = "\x27\xa7\x47\x9b\xef\xa1\xd4\x76"
+			  "\x48\x9f\x30\x8c\xd4\xcf\xa6\xe2"
+			  "\xa9\x6e\x4b\xbe\x32\x08\xff\x25"
+			  "\x28\x7d\xd3\x81\x96\x16\xe8\x9c"
+			  "\xc7\x8c\xf7\xf5\xe5\x43\x44\x5f"
+			  "\x83\x33\xd8\xfa\x7f\x56\x00\x00"
+			  "\x05\x27\x9f\xa5\xd8\xb5\xe4\xad"
+			  "\x40\xe7\x36\xdd\xb4\xd3\x54\x12"
+			  "\x32\x80\x63\xfd\x2a\xab\x53\xe5"
+			  "\xea\x1e\x0a\x9f\x33\x25\x00\xa5"
+			  "\xdf\x94\x87\xd0\x7a\x5c\x92\xcc"
+			  "\x51\x2c\x88\x66\xc7\xe8\x60\xce"
+			  "\x93\xfd\xf1\x66\xa2\x49\x12\xb4"
+			  "\x22\x97\x61\x46\xae\x20\xce\x84"
+			  "\x6b\xb7\xdc\x9b\xa9\x4a\x76\x7a"
+			  "\xae\xf2\x0c\x0d\x61\xad\x02\x65"
+			  "\x5e\xa9\x2d\xc4\xc4\xe4\x1a\x89"
+			  "\x52\xc6\x51\xd3\x31\x74\xbe\x51"
+			  "\xa1\x0c\x42\x11\x10\xe6\xd8\x15"
+			  "\x88\xed\xe8\x21\x03\xa2\x52\xd8"
+			  "\xa7\x50\xe8\x76\x8d\xef\xff\xed"
+			  "\x91\x22\x81\x0a\xae\xb9\x9f\x91"
+			  "\x72\xaf\x82\xb6\x04\xdc\x4b\x8e"
+			  "\x51\xbc\xb0\x82\x35\xa6\xf4\x34"
+			  "\x13\x32\xe4\xca\x60\x48\x2a\x4b"
+			  "\xa1\xa0\x3b\x3e\x65\x00\x8f\xc5"
+			  "\xda\x76\xb7\x0b\xf1\x69\x0d\xb4"
+			  "\xea\xe2\x9c\x5f\x1b\xad\xd0\x3c"
+			  "\x5c\xcf\x2a\x55\xd7\x05\xdd\xcd"
+			  "\x86\xd4\x49\x51\x1c\xeb\x7e\xc3"
+			  "\x0b\xf1\x2b\x1f\xa3\x5b\x91\x3f"
+			  "\x9f\x74\x7a\x8a\xfd\x1b\x13\x0e"
+			  "\x94\xbf\xf9\x4e\xff\xd0\x1a\x91"
+			  "\x73\x5c\xa1\x72\x6a\xcd\x0b\x19"
+			  "\x7c\x4e\x5b\x03\x39\x36\x97\xe1"
+			  "\x26\x82\x6f\xb6\xbb\xde\x8e\xcc"
+			  "\x1e\x08\x29\x85\x16\xe2\xc9\xed"
+			  "\x03\xff\x3c\x1b\x78\x60\xf6\xde"
+			  "\x76\xd4\xce\xcd\x94\xc8\x11\x98"
+			  "\x55\xef\x52\x97\xca\x67\xe9\xf3"
+			  "\xe7\xff\x72\xb1\xe9\x97\x85\xca"
+			  "\x0a\x7e\x77\x20\xc5\xb3\x6d\xc6"
+			  "\xd7\x2c\xac\x95\x74\xc8\xcb\xbc"
+			  "\x2f\x80\x1e\x23\xe5\x6f\xd3\x44"
+			  "\xb0\x7f\x22\x15\x4b\xeb\xa0\xf0"
+			  "\x8c\xe8\x89\x1e\x64\x3e\xd9\x95"
+			  "\xc9\x4d\x9a\x69\xc9\xf1\xb5\xf4"
+			  "\x99\x02\x7a\x78\x57\x2a\xee\xbd"
+			  "\x74\xd2\x0c\xc3\x98\x81\xc2\x13"
+			  "\xee\x77\x0b\x10\x10\xe4\xbe\xa7"
+			  "\x18\x84\x69\x77\xae\x11\x9f\x7a"
+			  "\x02\x3a\xb5\x8c\xca\x0a\xd7\x52"
+			  "\xaf\xe6\x56\xbb\x3c\x17\x25\x6a"
+			  "\x9f\x6e\x9b\xf1\x9f\xdd\x5a\x38"
+			  "\xfc\x82\xbb\xe8\x72\xc5\x53\x9e"
+			  "\xdb\x60\x9e\xf4\xf7\x9c\x20\x3e"
+			  "\xbb\x14\x0f\x2e\x58\x3c\xb2\xad"
+			  "\x15\xb4\xaa\x5b\x65\x50\x16\xa8"
+			  "\x44\x92\x77\xdb\xd4\x77\xef\x2c"
+			  "\x8d\x6c\x01\x7d\xb7\x38\xb1\x8d"
+			  "\xeb\x4a\x42\x7d\x19\x23\xce\x3f"
+			  "\xf2\x62\x73\x57\x79\xa4\x18\xf2"
+			  "\x0a\x28\x2d\xf9\x20\x14\x7b\xea"
+			  "\xbe\x42\x1e\xe5\x31\x9d\x05\x68",
+		.ilen   = 512,
+		.result = "\x00\x01\x02\x03\x04\x05\x06\x07"
+			  "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+			  "\x10\x11\x12\x13\x14\x15\x16\x17"
+			  "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
+			  "\x20\x21\x22\x23\x24\x25\x26\x27"
+			  "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f"
+			  "\x30\x31\x32\x33\x34\x35\x36\x37"
+			  "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f"
+			  "\x40\x41\x42\x43\x44\x45\x46\x47"
+			  "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f"
+			  "\x50\x51\x52\x53\x54\x55\x56\x57"
+			  "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f"
+			  "\x60\x61\x62\x63\x64\x65\x66\x67"
+			  "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f"
+			  "\x70\x71\x72\x73\x74\x75\x76\x77"
+			  "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f"
+			  "\x80\x81\x82\x83\x84\x85\x86\x87"
+			  "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"
+			  "\x90\x91\x92\x93\x94\x95\x96\x97"
+			  "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f"
+			  "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7"
+			  "\xa8\xa9\xaa\xab\xac\xad\xae\xaf"
+			  "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7"
+			  "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf"
+			  "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7"
+			  "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf"
+			  "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7"
+			  "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf"
+			  "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7"
+			  "\xe8\xe9\xea\xeb\xec\xed\xee\xef"
+			  "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7"
+			  "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff"
+			  "\x00\x01\x02\x03\x04\x05\x06\x07"
+			  "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+			  "\x10\x11\x12\x13\x14\x15\x16\x17"
+			  "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
+			  "\x20\x21\x22\x23\x24\x25\x26\x27"
+			  "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f"
+			  "\x30\x31\x32\x33\x34\x35\x36\x37"
+			  "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f"
+			  "\x40\x41\x42\x43\x44\x45\x46\x47"
+			  "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f"
+			  "\x50\x51\x52\x53\x54\x55\x56\x57"
+			  "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f"
+			  "\x60\x61\x62\x63\x64\x65\x66\x67"
+			  "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f"
+			  "\x70\x71\x72\x73\x74\x75\x76\x77"
+			  "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f"
+			  "\x80\x81\x82\x83\x84\x85\x86\x87"
+			  "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"
+			  "\x90\x91\x92\x93\x94\x95\x96\x97"
+			  "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f"
+			  "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7"
+			  "\xa8\xa9\xaa\xab\xac\xad\xae\xaf"
+			  "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7"
+			  "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf"
+			  "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7"
+			  "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf"
+			  "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7"
+			  "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf"
+			  "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7"
+			  "\xe8\xe9\xea\xeb\xec\xed\xee\xef"
+			  "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7"
+			  "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff",
+		.rlen   = 512,
+	}
+};
+
+
+static struct cipher_testvec aes_ctr_enc_tv_template[] = {
+	{ /* From RFC 3686 */
+		.key	= "\xae\x68\x52\xf8\x12\x10\x67\xcc"
+			  "\x4b\xf7\xa5\x76\x55\x77\xf3\x9e"
+			  "\x00\x00\x00\x30",
+		.klen	= 20,
+		.iv	= "\x00\x00\x00\x00\x00\x00\x00\x00",
+		.input	= "Single block msg",
+		.ilen	= 16,
+		.result = "\xe4\x09\x5d\x4f\xb7\xa7\xb3\x79"
+			  "\x2d\x61\x75\xa3\x26\x13\x11\xb8",
+		.rlen	= 16,
+	}, {
+		.key	= "\x7e\x24\x06\x78\x17\xfa\xe0\xd7"
+			  "\x43\xd6\xce\x1f\x32\x53\x91\x63"
+			  "\x00\x6c\xb6\xdb",
+		.klen	= 20,
+		.iv	= "\xc0\x54\x3b\x59\xda\x48\xd9\x0b",
+		.input	= "\x00\x01\x02\x03\x04\x05\x06\x07"
+			  "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+			  "\x10\x11\x12\x13\x14\x15\x16\x17"
+			  "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f",
+		.ilen	= 32,
+		.result = "\x51\x04\xa1\x06\x16\x8a\x72\xd9"
+			  "\x79\x0d\x41\xee\x8e\xda\xd3\x88"
+			  "\xeb\x2e\x1e\xfc\x46\xda\x57\xc8"
+			  "\xfc\xe6\x30\xdf\x91\x41\xbe\x28",
+		.rlen	= 32,
+	}, {
+		.key	= "\x16\xaf\x5b\x14\x5f\xc9\xf5\x79"
+			  "\xc1\x75\xf9\x3e\x3b\xfb\x0e\xed"
+			  "\x86\x3d\x06\xcc\xfd\xb7\x85\x15"
+			  "\x00\x00\x00\x48",
+		.klen	= 28,
+		.iv	= "\x36\x73\x3c\x14\x7d\x6d\x93\xcb",
+		.input	= "Single block msg",
+		.ilen	= 16,
+		.result	= "\x4b\x55\x38\x4f\xe2\x59\xc9\xc8"
+			  "\x4e\x79\x35\xa0\x03\xcb\xe9\x28",
+		.rlen	= 16,
+	}, {
+		.key	= "\x7c\x5c\xb2\x40\x1b\x3d\xc3\x3c"
+			  "\x19\xe7\x34\x08\x19\xe0\xf6\x9c"
+			  "\x67\x8c\x3d\xb8\xe6\xf6\xa9\x1a"
+			  "\x00\x96\xb0\x3b",
+		.klen	= 28,
+		.iv	= "\x02\x0c\x6e\xad\xc2\xcb\x50\x0d",
+		.input	= "\x00\x01\x02\x03\x04\x05\x06\x07"
+			  "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+			  "\x10\x11\x12\x13\x14\x15\x16\x17"
+			  "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f",
+		.ilen	= 32,
+		.result	= "\x45\x32\x43\xfc\x60\x9b\x23\x32"
+			  "\x7e\xdf\xaa\xfa\x71\x31\xcd\x9f"
+			  "\x84\x90\x70\x1c\x5a\xd4\xa7\x9c"
+			  "\xfc\x1f\xe0\xff\x42\xf4\xfb\x00",
+		.rlen	= 32,
+	}, {
+		.key	= "\x77\x6b\xef\xf2\x85\x1d\xb0\x6f"
+			  "\x4c\x8a\x05\x42\xc8\x69\x6f\x6c"
+			  "\x6a\x81\xaf\x1e\xec\x96\xb4\xd3"
+			  "\x7f\xc1\xd6\x89\xe6\xc1\xc1\x04"
+			  "\x00\x00\x00\x60",
+		.klen	= 36,
+		.iv	= "\xdb\x56\x72\xc9\x7a\xa8\xf0\xb2",
+		.input	= "Single block msg",
+		.ilen	= 16,
+		.result = "\x14\x5a\xd0\x1d\xbf\x82\x4e\xc7"
+			  "\x56\x08\x63\xdc\x71\xe3\xe0\xc0",
+		.rlen	= 16,
+	}, {
+		.key	= "\xf6\xd6\x6d\x6b\xd5\x2d\x59\xbb"
+			  "\x07\x96\x36\x58\x79\xef\xf8\x86"
+			  "\xc6\x6d\xd5\x1a\x5b\x6a\x99\x74"
+			  "\x4b\x50\x59\x0c\x87\xa2\x38\x84"
+			  "\x00\xfa\xac\x24",
+		.klen	= 36,
+		.iv	= "\xc1\x58\x5e\xf1\x5a\x43\xd8\x75",
+		.input	= "\x00\x01\x02\x03\x04\x05\x06\x07"
+			  "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+			  "\x10\x11\x12\x13\x14\x15\x16\x17"
+			  "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f",
+		.ilen	= 32,
+		.result = "\xf0\x5e\x23\x1b\x38\x94\x61\x2c"
+			  "\x49\xee\x00\x0b\x80\x4e\xb2\xa9"
+			  "\xb8\x30\x6b\x50\x8f\x83\x9d\x6a"
+			  "\x55\x30\x83\x1d\x93\x44\xaf\x1c",
+		.rlen	= 32,
+	}, {
+	// generated using Crypto++
+		.key = "\x00\x01\x02\x03\x04\x05\x06\x07"
+			"\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+			"\x10\x11\x12\x13\x14\x15\x16\x17"
+			"\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
+			"\x00\x00\x00\x00",
+		.klen = 32 + 4,
+		.iv = "\x00\x00\x00\x00\x00\x00\x00\x00",
+		.input =
+			"\x00\x01\x02\x03\x04\x05\x06\x07"
+			"\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+			"\x10\x11\x12\x13\x14\x15\x16\x17"
+			"\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
+			"\x20\x21\x22\x23\x24\x25\x26\x27"
+			"\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f"
+			"\x30\x31\x32\x33\x34\x35\x36\x37"
+			"\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f"
+			"\x40\x41\x42\x43\x44\x45\x46\x47"
+			"\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f"
+			"\x50\x51\x52\x53\x54\x55\x56\x57"
+			"\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f"
+			"\x60\x61\x62\x63\x64\x65\x66\x67"
+			"\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f"
+			"\x70\x71\x72\x73\x74\x75\x76\x77"
+			"\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f"
+			"\x80\x81\x82\x83\x84\x85\x86\x87"
+			"\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"
+			"\x90\x91\x92\x93\x94\x95\x96\x97"
+			"\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f"
+			"\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7"
+			"\xa8\xa9\xaa\xab\xac\xad\xae\xaf"
+			"\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7"
+			"\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf"
+			"\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7"
+			"\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf"
+			"\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7"
+			"\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf"
+			"\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7"
+			"\xe8\xe9\xea\xeb\xec\xed\xee\xef"
+			"\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7"
+			"\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff"
+			"\x00\x03\x06\x09\x0c\x0f\x12\x15"
+			"\x18\x1b\x1e\x21\x24\x27\x2a\x2d"
+			"\x30\x33\x36\x39\x3c\x3f\x42\x45"
+			"\x48\x4b\x4e\x51\x54\x57\x5a\x5d"
+			"\x60\x63\x66\x69\x6c\x6f\x72\x75"
+			"\x78\x7b\x7e\x81\x84\x87\x8a\x8d"
+			"\x90\x93\x96\x99\x9c\x9f\xa2\xa5"
+			"\xa8\xab\xae\xb1\xb4\xb7\xba\xbd"
+			"\xc0\xc3\xc6\xc9\xcc\xcf\xd2\xd5"
+			"\xd8\xdb\xde\xe1\xe4\xe7\xea\xed"
+			"\xf0\xf3\xf6\xf9\xfc\xff\x02\x05"
+			"\x08\x0b\x0e\x11\x14\x17\x1a\x1d"
+			"\x20\x23\x26\x29\x2c\x2f\x32\x35"
+			"\x38\x3b\x3e\x41\x44\x47\x4a\x4d"
+			"\x50\x53\x56\x59\x5c\x5f\x62\x65"
+			"\x68\x6b\x6e\x71\x74\x77\x7a\x7d"
+			"\x80\x83\x86\x89\x8c\x8f\x92\x95"
+			"\x98\x9b\x9e\xa1\xa4\xa7\xaa\xad"
+			"\xb0\xb3\xb6\xb9\xbc\xbf\xc2\xc5"
+			"\xc8\xcb\xce\xd1\xd4\xd7\xda\xdd"
+			"\xe0\xe3\xe6\xe9\xec\xef\xf2\xf5"
+			"\xf8\xfb\xfe\x01\x04\x07\x0a\x0d"
+			"\x10\x13\x16\x19\x1c\x1f\x22\x25"
+			"\x28\x2b\x2e\x31\x34\x37\x3a\x3d"
+			"\x40\x43\x46\x49\x4c\x4f\x52\x55"
+			"\x58\x5b\x5e\x61\x64\x67\x6a\x6d"
+			"\x70\x73\x76\x79\x7c\x7f\x82\x85"
+			"\x88\x8b\x8e\x91\x94\x97\x9a\x9d"
+			"\xa0\xa3\xa6\xa9\xac\xaf\xb2\xb5"
+			"\xb8\xbb\xbe\xc1\xc4\xc7\xca\xcd"
+			"\xd0\xd3\xd6\xd9\xdc\xdf\xe2\xe5"
+			"\xe8\xeb\xee\xf1\xf4\xf7\xfa\xfd"
+			"\x00\x05\x0a\x0f\x14\x19\x1e\x23"
+			"\x28\x2d\x32\x37\x3c\x41\x46\x4b"
+			"\x50\x55\x5a\x5f\x64\x69\x6e\x73"
+			"\x78\x7d\x82\x87\x8c\x91\x96\x9b"
+			"\xa0\xa5\xaa\xaf\xb4\xb9\xbe\xc3"
+			"\xc8\xcd\xd2\xd7\xdc\xe1\xe6\xeb"
+			"\xf0\xf5\xfa\xff\x04\x09\x0e\x13"
+			"\x18\x1d\x22\x27\x2c\x31\x36\x3b"
+			"\x40\x45\x4a\x4f\x54\x59\x5e\x63"
+			"\x68\x6d\x72\x77\x7c\x81\x86\x8b"
+			"\x90\x95\x9a\x9f\xa4\xa9\xae\xb3"
+			"\xb8\xbd\xc2\xc7\xcc\xd1\xd6\xdb"
+			"\xe0\xe5\xea\xef\xf4\xf9\xfe\x03"
+			"\x08\x0d\x12\x17\x1c\x21\x26\x2b"
+			"\x30\x35\x3a\x3f\x44\x49\x4e\x53"
+			"\x58\x5d\x62\x67\x6c\x71\x76\x7b"
+			"\x80\x85\x8a\x8f\x94\x99\x9e\xa3"
+			"\xa8\xad\xb2\xb7\xbc\xc1\xc6\xcb"
+			"\xd0\xd5\xda\xdf\xe4\xe9\xee\xf3"
+			"\xf8\xfd\x02\x07\x0c\x11\x16\x1b"
+			"\x20\x25\x2a\x2f\x34\x39\x3e\x43"
+			"\x48\x4d\x52\x57\x5c\x61\x66\x6b"
+			"\x70\x75\x7a\x7f\x84\x89\x8e\x93"
+			"\x98\x9d\xa2\xa7\xac\xb1\xb6\xbb"
+			"\xc0\xc5\xca\xcf\xd4\xd9\xde\xe3"
+			"\xe8\xed\xf2\xf7\xfc\x01\x06\x0b"
+			"\x10\x15\x1a\x1f\x24\x29\x2e\x33"
+			"\x38\x3d\x42\x47\x4c\x51\x56\x5b"
+			"\x60\x65\x6a\x6f\x74\x79\x7e\x83"
+			"\x88\x8d\x92\x97\x9c\xa1\xa6\xab"
+			"\xb0\xb5\xba\xbf\xc4\xc9\xce\xd3"
+			"\xd8\xdd\xe2\xe7\xec\xf1\xf6\xfb"
+			"\x00\x07\x0e\x15\x1c\x23\x2a\x31"
+			"\x38\x3f\x46\x4d\x54\x5b\x62\x69"
+			"\x70\x77\x7e\x85\x8c\x93\x9a\xa1"
+			"\xa8\xaf\xb6\xbd\xc4\xcb\xd2\xd9"
+			"\xe0\xe7\xee\xf5\xfc\x03\x0a\x11"
+			"\x18\x1f\x26\x2d\x34\x3b\x42\x49"
+			"\x50\x57\x5e\x65\x6c\x73\x7a\x81"
+			"\x88\x8f\x96\x9d\xa4\xab\xb2\xb9"
+			"\xc0\xc7\xce\xd5\xdc\xe3\xea\xf1"
+			"\xf8\xff\x06\x0d\x14\x1b\x22\x29"
+			"\x30\x37\x3e\x45\x4c\x53\x5a\x61"
+			"\x68\x6f\x76\x7d\x84\x8b\x92\x99"
+			"\xa0\xa7\xae\xb5\xbc\xc3\xca\xd1"
+			"\xd8\xdf\xe6\xed\xf4\xfb\x02\x09"
+			"\x10\x17\x1e\x25\x2c\x33\x3a\x41"
+			"\x48\x4f\x56\x5d\x64\x6b\x72\x79"
+			"\x80\x87\x8e\x95\x9c\xa3\xaa\xb1"
+			"\xb8\xbf\xc6\xcd\xd4\xdb\xe2\xe9"
+			"\xf0\xf7\xfe\x05\x0c\x13\x1a\x21"
+			"\x28\x2f\x36\x3d\x44\x4b\x52\x59"
+			"\x60\x67\x6e\x75\x7c\x83\x8a\x91"
+			"\x98\x9f\xa6\xad\xb4\xbb\xc2\xc9"
+			"\xd0\xd7\xde\xe5\xec\xf3\xfa\x01"
+			"\x08\x0f\x16\x1d\x24\x2b\x32\x39"
+			"\x40\x47\x4e\x55\x5c\x63\x6a\x71"
+			"\x78\x7f\x86\x8d\x94\x9b\xa2\xa9"
+			"\xb0\xb7\xbe\xc5\xcc\xd3\xda\xe1"
+			"\xe8\xef\xf6\xfd\x04\x0b\x12\x19"
+			"\x20\x27\x2e\x35\x3c\x43\x4a\x51"
+			"\x58\x5f\x66\x6d\x74\x7b\x82\x89"
+			"\x90\x97\x9e\xa5\xac\xb3\xba\xc1"
+			"\xc8\xcf\xd6\xdd\xe4\xeb\xf2\xf9"
+			"\x00\x09\x12\x1b\x24\x2d\x36\x3f"
+			"\x48\x51\x5a\x63\x6c\x75\x7e\x87"
+			"\x90\x99\xa2\xab\xb4\xbd\xc6\xcf"
+			"\xd8\xe1\xea\xf3\xfc\x05\x0e\x17"
+			"\x20\x29\x32\x3b\x44\x4d\x56\x5f"
+			"\x68\x71\x7a\x83\x8c\x95\x9e\xa7"
+			"\xb0\xb9\xc2\xcb\xd4\xdd\xe6\xef"
+			"\xf8\x01\x0a\x13\x1c\x25\x2e\x37"
+			"\x40\x49\x52\x5b\x64\x6d\x76\x7f"
+			"\x88\x91\x9a\xa3\xac\xb5\xbe\xc7"
+			"\xd0\xd9\xe2\xeb\xf4\xfd\x06\x0f"
+			"\x18\x21\x2a\x33\x3c\x45\x4e\x57"
+			"\x60\x69\x72\x7b\x84\x8d\x96\x9f"
+			"\xa8\xb1\xba\xc3\xcc\xd5\xde\xe7"
+			"\xf0\xf9\x02\x0b\x14\x1d\x26\x2f"
+			"\x38\x41\x4a\x53\x5c\x65\x6e\x77"
+			"\x80\x89\x92\x9b\xa4\xad\xb6\xbf"
+			"\xc8\xd1\xda\xe3\xec\xf5\xfe\x07"
+			"\x10\x19\x22\x2b\x34\x3d\x46\x4f"
+			"\x58\x61\x6a\x73\x7c\x85\x8e\x97"
+			"\xa0\xa9\xb2\xbb\xc4\xcd\xd6\xdf"
+			"\xe8\xf1\xfa\x03\x0c\x15\x1e\x27"
+			"\x30\x39\x42\x4b\x54\x5d\x66\x6f"
+			"\x78\x81\x8a\x93\x9c\xa5\xae\xb7"
+			"\xc0\xc9\xd2\xdb\xe4\xed\xf6\xff"
+			"\x08\x11\x1a\x23\x2c\x35\x3e\x47"
+			"\x50\x59\x62\x6b\x74\x7d\x86\x8f"
+			"\x98\xa1\xaa\xb3\xbc\xc5\xce\xd7"
+			"\xe0\xe9\xf2\xfb\x04\x0d\x16\x1f"
+			"\x28\x31\x3a\x43\x4c\x55\x5e\x67"
+			"\x70\x79\x82\x8b\x94\x9d\xa6\xaf"
+			"\xb8\xc1\xca\xd3\xdc\xe5\xee\xf7"
+			"\x00\x0b\x16\x21\x2c\x37\x42\x4d"
+			"\x58\x63\x6e\x79\x84\x8f\x9a\xa5"
+			"\xb0\xbb\xc6\xd1\xdc\xe7\xf2\xfd"
+			"\x08\x13\x1e\x29\x34\x3f\x4a\x55"
+			"\x60\x6b\x76\x81\x8c\x97\xa2\xad"
+			"\xb8\xc3\xce\xd9\xe4\xef\xfa\x05"
+			"\x10\x1b\x26\x31\x3c\x47\x52\x5d"
+			"\x68\x73\x7e\x89\x94\x9f\xaa\xb5"
+			"\xc0\xcb\xd6\xe1\xec\xf7\x02\x0d"
+			"\x18\x23\x2e\x39\x44\x4f\x5a\x65"
+			"\x70\x7b\x86\x91\x9c\xa7\xb2\xbd"
+			"\xc8\xd3\xde\xe9\xf4\xff\x0a\x15"
+			"\x20\x2b\x36\x41\x4c\x57\x62\x6d"
+			"\x78\x83\x8e\x99\xa4\xaf\xba\xc5"
+			"\xd0\xdb\xe6\xf1\xfc\x07\x12\x1d"
+			"\x28\x33\x3e\x49\x54\x5f\x6a\x75"
+			"\x80\x8b\x96\xa1\xac\xb7\xc2\xcd"
+			"\xd8\xe3\xee\xf9\x04\x0f\x1a\x25"
+			"\x30\x3b\x46\x51\x5c\x67\x72\x7d"
+			"\x88\x93\x9e\xa9\xb4\xbf\xca\xd5"
+			"\xe0\xeb\xf6\x01\x0c\x17\x22\x2d"
+			"\x38\x43\x4e\x59\x64\x6f\x7a\x85"
+			"\x90\x9b\xa6\xb1\xbc\xc7\xd2\xdd"
+			"\xe8\xf3\xfe\x09\x14\x1f\x2a\x35"
+			"\x40\x4b\x56\x61\x6c\x77\x82\x8d"
+			"\x98\xa3\xae\xb9\xc4\xcf\xda\xe5"
+			"\xf0\xfb\x06\x11\x1c\x27\x32\x3d"
+			"\x48\x53\x5e\x69\x74\x7f\x8a\x95"
+			"\xa0\xab\xb6\xc1\xcc\xd7\xe2\xed"
+			"\xf8\x03\x0e\x19\x24\x2f\x3a\x45"
+			"\x50\x5b\x66\x71\x7c\x87\x92\x9d"
+			"\xa8\xb3\xbe\xc9\xd4\xdf\xea\xf5"
+			"\x00\x0d\x1a\x27\x34\x41\x4e\x5b"
+			"\x68\x75\x82\x8f\x9c\xa9\xb6\xc3"
+			"\xd0\xdd\xea\xf7\x04\x11\x1e\x2b"
+			"\x38\x45\x52\x5f\x6c\x79\x86\x93"
+			"\xa0\xad\xba\xc7\xd4\xe1\xee\xfb"
+			"\x08\x15\x22\x2f\x3c\x49\x56\x63"
+			"\x70\x7d\x8a\x97\xa4\xb1\xbe\xcb"
+			"\xd8\xe5\xf2\xff\x0c\x19\x26\x33"
+			"\x40\x4d\x5a\x67\x74\x81\x8e\x9b"
+			"\xa8\xb5\xc2\xcf\xdc\xe9\xf6\x03"
+			"\x10\x1d\x2a\x37\x44\x51\x5e\x6b"
+			"\x78\x85\x92\x9f\xac\xb9\xc6\xd3"
+			"\xe0\xed\xfa\x07\x14\x21\x2e\x3b"
+			"\x48\x55\x62\x6f\x7c\x89\x96\xa3"
+			"\xb0\xbd\xca\xd7\xe4\xf1\xfe\x0b"
+			"\x18\x25\x32\x3f\x4c\x59\x66\x73"
+			"\x80\x8d\x9a\xa7\xb4\xc1\xce\xdb"
+			"\xe8\xf5\x02\x0f\x1c\x29\x36\x43"
+			"\x50\x5d\x6a\x77\x84\x91\x9e\xab"
+			"\xb8\xc5\xd2\xdf\xec\xf9\x06\x13"
+			"\x20\x2d\x3a\x47\x54\x61\x6e\x7b"
+			"\x88\x95\xa2\xaf\xbc\xc9\xd6\xe3"
+			"\xf0\xfd\x0a\x17\x24\x31\x3e\x4b"
+			"\x58\x65\x72\x7f\x8c\x99\xa6\xb3"
+			"\xc0\xcd\xda\xe7\xf4\x01\x0e\x1b"
+			"\x28\x35\x42\x4f\x5c\x69\x76\x83"
+			"\x90\x9d\xaa\xb7\xc4\xd1\xde\xeb"
+			"\xf8\x05\x12\x1f\x2c\x39\x46\x53"
+			"\x60\x6d\x7a\x87\x94\xa1\xae\xbb"
+			"\xc8\xd5\xe2\xef\xfc\x09\x16\x23"
+			"\x30\x3d\x4a\x57\x64\x71\x7e\x8b"
+			"\x98\xa5\xb2\xbf\xcc\xd9\xe6\xf3"
+			"\x00\x0f\x1e\x2d\x3c\x4b\x5a\x69"
+			"\x78\x87\x96\xa5\xb4\xc3\xd2\xe1"
+			"\xf0\xff\x0e\x1d\x2c\x3b\x4a\x59"
+			"\x68\x77\x86\x95\xa4\xb3\xc2\xd1"
+			"\xe0\xef\xfe\x0d\x1c\x2b\x3a\x49"
+			"\x58\x67\x76\x85\x94\xa3\xb2\xc1"
+			"\xd0\xdf\xee\xfd\x0c\x1b\x2a\x39"
+			"\x48\x57\x66\x75\x84\x93\xa2\xb1"
+			"\xc0\xcf\xde\xed\xfc\x0b\x1a\x29"
+			"\x38\x47\x56\x65\x74\x83\x92\xa1"
+			"\xb0\xbf\xce\xdd\xec\xfb\x0a\x19"
+			"\x28\x37\x46\x55\x64\x73\x82\x91"
+			"\xa0\xaf\xbe\xcd\xdc\xeb\xfa\x09"
+			"\x18\x27\x36\x45\x54\x63\x72\x81"
+			"\x90\x9f\xae\xbd\xcc\xdb\xea\xf9"
+			"\x08\x17\x26\x35\x44\x53\x62\x71"
+			"\x80\x8f\x9e\xad\xbc\xcb\xda\xe9"
+			"\xf8\x07\x16\x25\x34\x43\x52\x61"
+			"\x70\x7f\x8e\x9d\xac\xbb\xca\xd9"
+			"\xe8\xf7\x06\x15\x24\x33\x42\x51"
+			"\x60\x6f\x7e\x8d\x9c\xab\xba\xc9"
+			"\xd8\xe7\xf6\x05\x14\x23\x32\x41"
+			"\x50\x5f\x6e\x7d\x8c\x9b\xaa\xb9"
+			"\xc8\xd7\xe6\xf5\x04\x13\x22\x31"
+			"\x40\x4f\x5e\x6d\x7c\x8b\x9a\xa9"
+			"\xb8\xc7\xd6\xe5\xf4\x03\x12\x21"
+			"\x30\x3f\x4e\x5d\x6c\x7b\x8a\x99"
+			"\xa8\xb7\xc6\xd5\xe4\xf3\x02\x11"
+			"\x20\x2f\x3e\x4d\x5c\x6b\x7a\x89"
+			"\x98\xa7\xb6\xc5\xd4\xe3\xf2\x01"
+			"\x10\x1f\x2e\x3d\x4c\x5b\x6a\x79"
+			"\x88\x97\xa6\xb5\xc4\xd3\xe2\xf1"
+			"\x00\x11\x22\x33\x44\x55\x66\x77"
+			"\x88\x99\xaa\xbb\xcc\xdd\xee\xff"
+			"\x10\x21\x32\x43\x54\x65\x76\x87"
+			"\x98\xa9\xba\xcb\xdc\xed\xfe\x0f"
+			"\x20\x31\x42\x53\x64\x75\x86\x97"
+			"\xa8\xb9\xca\xdb\xec\xfd\x0e\x1f"
+			"\x30\x41\x52\x63\x74\x85\x96\xa7"
+			"\xb8\xc9\xda\xeb\xfc\x0d\x1e\x2f"
+			"\x40\x51\x62\x73\x84\x95\xa6\xb7"
+			"\xc8\xd9\xea\xfb\x0c\x1d\x2e\x3f"
+			"\x50\x61\x72\x83\x94\xa5\xb6\xc7"
+			"\xd8\xe9\xfa\x0b\x1c\x2d\x3e\x4f"
+			"\x60\x71\x82\x93\xa4\xb5\xc6\xd7"
+			"\xe8\xf9\x0a\x1b\x2c\x3d\x4e\x5f"
+			"\x70\x81\x92\xa3\xb4\xc5\xd6\xe7"
+			"\xf8\x09\x1a\x2b\x3c\x4d\x5e\x6f"
+			"\x80\x91\xa2\xb3\xc4\xd5\xe6\xf7"
+			"\x08\x19\x2a\x3b\x4c\x5d\x6e\x7f"
+			"\x90\xa1\xb2\xc3\xd4\xe5\xf6\x07"
+			"\x18\x29\x3a\x4b\x5c\x6d\x7e\x8f"
+			"\xa0\xb1\xc2\xd3\xe4\xf5\x06\x17"
+			"\x28\x39\x4a\x5b\x6c\x7d\x8e\x9f"
+			"\xb0\xc1\xd2\xe3\xf4\x05\x16\x27"
+			"\x38\x49\x5a\x6b\x7c\x8d\x9e\xaf"
+			"\xc0\xd1\xe2\xf3\x04\x15\x26\x37"
+			"\x48\x59\x6a\x7b\x8c\x9d\xae\xbf"
+			"\xd0\xe1\xf2\x03\x14\x25\x36\x47"
+			"\x58\x69\x7a\x8b\x9c\xad\xbe\xcf"
+			"\xe0\xf1\x02\x13\x24\x35\x46\x57"
+			"\x68\x79\x8a\x9b\xac\xbd\xce\xdf"
+			"\xf0\x01\x12\x23\x34\x45\x56\x67"
+			"\x78\x89\x9a\xab\xbc\xcd\xde\xef"
+			"\x00\x13\x26\x39\x4c\x5f\x72\x85"
+			"\x98\xab\xbe\xd1\xe4\xf7\x0a\x1d"
+			"\x30\x43\x56\x69\x7c\x8f\xa2\xb5"
+			"\xc8\xdb\xee\x01\x14\x27\x3a\x4d"
+			"\x60\x73\x86\x99\xac\xbf\xd2\xe5"
+			"\xf8\x0b\x1e\x31\x44\x57\x6a\x7d"
+			"\x90\xa3\xb6\xc9\xdc\xef\x02\x15"
+			"\x28\x3b\x4e\x61\x74\x87\x9a\xad"
+			"\xc0\xd3\xe6\xf9\x0c\x1f\x32\x45"
+			"\x58\x6b\x7e\x91\xa4\xb7\xca\xdd"
+			"\xf0\x03\x16\x29\x3c\x4f\x62\x75"
+			"\x88\x9b\xae\xc1\xd4\xe7\xfa\x0d"
+			"\x20\x33\x46\x59\x6c\x7f\x92\xa5"
+			"\xb8\xcb\xde\xf1\x04\x17\x2a\x3d"
+			"\x50\x63\x76\x89\x9c\xaf\xc2\xd5"
+			"\xe8\xfb\x0e\x21\x34\x47\x5a\x6d"
+			"\x80\x93\xa6\xb9\xcc\xdf\xf2\x05"
+			"\x18\x2b\x3e\x51\x64\x77\x8a\x9d"
+			"\xb0\xc3\xd6\xe9\xfc\x0f\x22\x35"
+			"\x48\x5b\x6e\x81\x94\xa7\xba\xcd"
+			"\xe0\xf3\x06\x19\x2c\x3f\x52\x65"
+			"\x78\x8b\x9e\xb1\xc4\xd7\xea\xfd"
+			"\x10\x23\x36\x49\x5c\x6f\x82\x95"
+			"\xa8\xbb\xce\xe1\xf4\x07\x1a\x2d"
+			"\x40\x53\x66\x79\x8c\x9f\xb2\xc5"
+			"\xd8\xeb\xfe\x11\x24\x37\x4a\x5d"
+			"\x70\x83\x96\xa9\xbc\xcf\xe2\xf5"
+			"\x08\x1b\x2e\x41\x54\x67\x7a\x8d"
+			"\xa0\xb3\xc6\xd9\xec\xff\x12\x25"
+			"\x38\x4b\x5e\x71\x84\x97\xaa\xbd"
+			"\xd0\xe3\xf6\x09\x1c\x2f\x42\x55"
+			"\x68\x7b\x8e\xa1\xb4\xc7\xda\xed"
+			"\x00\x15\x2a\x3f\x54\x69\x7e\x93"
+			"\xa8\xbd\xd2\xe7\xfc\x11\x26\x3b"
+			"\x50\x65\x7a\x8f\xa4\xb9\xce\xe3"
+			"\xf8\x0d\x22\x37\x4c\x61\x76\x8b"
+			"\xa0\xb5\xca\xdf\xf4\x09\x1e\x33"
+			"\x48\x5d\x72\x87\x9c\xb1\xc6\xdb"
+			"\xf0\x05\x1a\x2f\x44\x59\x6e\x83"
+			"\x98\xad\xc2\xd7\xec\x01\x16\x2b"
+			"\x40\x55\x6a\x7f\x94\xa9\xbe\xd3"
+			"\xe8\xfd\x12\x27\x3c\x51\x66\x7b"
+			"\x90\xa5\xba\xcf\xe4\xf9\x0e\x23"
+			"\x38\x4d\x62\x77\x8c\xa1\xb6\xcb"
+			"\xe0\xf5\x0a\x1f\x34\x49\x5e\x73"
+			"\x88\x9d\xb2\xc7\xdc\xf1\x06\x1b"
+			"\x30\x45\x5a\x6f\x84\x99\xae\xc3"
+			"\xd8\xed\x02\x17\x2c\x41\x56\x6b"
+			"\x80\x95\xaa\xbf\xd4\xe9\xfe\x13"
+			"\x28\x3d\x52\x67\x7c\x91\xa6\xbb"
+			"\xd0\xe5\xfa\x0f\x24\x39\x4e\x63"
+			"\x78\x8d\xa2\xb7\xcc\xe1\xf6\x0b"
+			"\x20\x35\x4a\x5f\x74\x89\x9e\xb3"
+			"\xc8\xdd\xf2\x07\x1c\x31\x46\x5b"
+			"\x70\x85\x9a\xaf\xc4\xd9\xee\x03"
+			"\x18\x2d\x42\x57\x6c\x81\x96\xab"
+			"\xc0\xd5\xea\xff\x14\x29\x3e\x53"
+			"\x68\x7d\x92\xa7\xbc\xd1\xe6\xfb"
+			"\x10\x25\x3a\x4f\x64\x79\x8e\xa3"
+			"\xb8\xcd\xe2\xf7\x0c\x21\x36\x4b"
+			"\x60\x75\x8a\x9f\xb4\xc9\xde\xf3"
+			"\x08\x1d\x32\x47\x5c\x71\x86\x9b"
+			"\xb0\xc5\xda\xef\x04\x19\x2e\x43"
+			"\x58\x6d\x82\x97\xac\xc1\xd6\xeb"
+			"\x00\x17\x2e\x45\x5c\x73\x8a\xa1"
+			"\xb8\xcf\xe6\xfd\x14\x2b\x42\x59"
+			"\x70\x87\x9e\xb5\xcc\xe3\xfa\x11"
+			"\x28\x3f\x56\x6d\x84\x9b\xb2\xc9"
+			"\xe0\xf7\x0e\x25\x3c\x53\x6a\x81"
+			"\x98\xaf\xc6\xdd\xf4\x0b\x22\x39"
+			"\x50\x67\x7e\x95\xac\xc3\xda\xf1"
+			"\x08\x1f\x36\x4d\x64\x7b\x92\xa9"
+			"\xc0\xd7\xee\x05\x1c\x33\x4a\x61"
+			"\x78\x8f\xa6\xbd\xd4\xeb\x02\x19"
+			"\x30\x47\x5e\x75\x8c\xa3\xba\xd1"
+			"\xe8\xff\x16\x2d\x44\x5b\x72\x89"
+			"\xa0\xb7\xce\xe5\xfc\x13\x2a\x41"
+			"\x58\x6f\x86\x9d\xb4\xcb\xe2\xf9"
+			"\x10\x27\x3e\x55\x6c\x83\x9a\xb1"
+			"\xc8\xdf\xf6\x0d\x24\x3b\x52\x69"
+			"\x80\x97\xae\xc5\xdc\xf3\x0a\x21"
+			"\x38\x4f\x66\x7d\x94\xab\xc2\xd9"
+			"\xf0\x07\x1e\x35\x4c\x63\x7a\x91"
+			"\xa8\xbf\xd6\xed\x04\x1b\x32\x49"
+			"\x60\x77\x8e\xa5\xbc\xd3\xea\x01"
+			"\x18\x2f\x46\x5d\x74\x8b\xa2\xb9"
+			"\xd0\xe7\xfe\x15\x2c\x43\x5a\x71"
+			"\x88\x9f\xb6\xcd\xe4\xfb\x12\x29"
+			"\x40\x57\x6e\x85\x9c\xb3\xca\xe1"
+			"\xf8\x0f\x26\x3d\x54\x6b\x82\x99"
+			"\xb0\xc7\xde\xf5\x0c\x23\x3a\x51"
+			"\x68\x7f\x96\xad\xc4\xdb\xf2\x09"
+			"\x20\x37\x4e\x65\x7c\x93\xaa\xc1"
+			"\xd8\xef\x06\x1d\x34\x4b\x62\x79"
+			"\x90\xa7\xbe\xd5\xec\x03\x1a\x31"
+			"\x48\x5f\x76\x8d\xa4\xbb\xd2\xe9"
+			"\x00\x19\x32\x4b\x64\x7d\x96\xaf"
+			"\xc8\xe1\xfa\x13\x2c\x45\x5e\x77"
+			"\x90\xa9\xc2\xdb\xf4\x0d\x26\x3f"
+			"\x58\x71\x8a\xa3\xbc\xd5\xee\x07"
+			"\x20\x39\x52\x6b\x84\x9d\xb6\xcf"
+			"\xe8\x01\x1a\x33\x4c\x65\x7e\x97"
+			"\xb0\xc9\xe2\xfb\x14\x2d\x46\x5f"
+			"\x78\x91\xaa\xc3\xdc\xf5\x0e\x27"
+			"\x40\x59\x72\x8b\xa4\xbd\xd6\xef"
+			"\x08\x21\x3a\x53\x6c\x85\x9e\xb7"
+			"\xd0\xe9\x02\x1b\x34\x4d\x66\x7f"
+			"\x98\xb1\xca\xe3\xfc\x15\x2e\x47"
+			"\x60\x79\x92\xab\xc4\xdd\xf6\x0f"
+			"\x28\x41\x5a\x73\x8c\xa5\xbe\xd7"
+			"\xf0\x09\x22\x3b\x54\x6d\x86\x9f"
+			"\xb8\xd1\xea\x03\x1c\x35\x4e\x67"
+			"\x80\x99\xb2\xcb\xe4\xfd\x16\x2f"
+			"\x48\x61\x7a\x93\xac\xc5\xde\xf7"
+			"\x10\x29\x42\x5b\x74\x8d\xa6\xbf"
+			"\xd8\xf1\x0a\x23\x3c\x55\x6e\x87"
+			"\xa0\xb9\xd2\xeb\x04\x1d\x36\x4f"
+			"\x68\x81\x9a\xb3\xcc\xe5\xfe\x17"
+			"\x30\x49\x62\x7b\x94\xad\xc6\xdf"
+			"\xf8\x11\x2a\x43\x5c\x75\x8e\xa7"
+			"\xc0\xd9\xf2\x0b\x24\x3d\x56\x6f"
+			"\x88\xa1\xba\xd3\xec\x05\x1e\x37"
+			"\x50\x69\x82\x9b\xb4\xcd\xe6\xff"
+			"\x18\x31\x4a\x63\x7c\x95\xae\xc7"
+			"\xe0\xf9\x12\x2b\x44\x5d\x76\x8f"
+			"\xa8\xc1\xda\xf3\x0c\x25\x3e\x57"
+			"\x70\x89\xa2\xbb\xd4\xed\x06\x1f"
+			"\x38\x51\x6a\x83\x9c\xb5\xce\xe7"
+			"\x00\x1b\x36\x51\x6c\x87\xa2\xbd"
+			"\xd8\xf3\x0e\x29\x44\x5f\x7a\x95"
+			"\xb0\xcb\xe6\x01\x1c\x37\x52\x6d"
+			"\x88\xa3\xbe\xd9\xf4\x0f\x2a\x45"
+			"\x60\x7b\x96\xb1\xcc\xe7\x02\x1d"
+			"\x38\x53\x6e\x89\xa4\xbf\xda\xf5"
+			"\x10\x2b\x46\x61\x7c\x97\xb2\xcd"
+			"\xe8\x03\x1e\x39\x54\x6f\x8a\xa5"
+			"\xc0\xdb\xf6\x11\x2c\x47\x62\x7d"
+			"\x98\xb3\xce\xe9\x04\x1f\x3a\x55"
+			"\x70\x8b\xa6\xc1\xdc\xf7\x12\x2d"
+			"\x48\x63\x7e\x99\xb4\xcf\xea\x05"
+			"\x20\x3b\x56\x71\x8c\xa7\xc2\xdd"
+			"\xf8\x13\x2e\x49\x64\x7f\x9a\xb5"
+			"\xd0\xeb\x06\x21\x3c\x57\x72\x8d"
+			"\xa8\xc3\xde\xf9\x14\x2f\x4a\x65"
+			"\x80\x9b\xb6\xd1\xec\x07\x22\x3d"
+			"\x58\x73\x8e\xa9\xc4\xdf\xfa\x15"
+			"\x30\x4b\x66\x81\x9c\xb7\xd2\xed"
+			"\x08\x23\x3e\x59\x74\x8f\xaa\xc5"
+			"\xe0\xfb\x16\x31\x4c\x67\x82\x9d"
+			"\xb8\xd3\xee\x09\x24\x3f\x5a\x75"
+			"\x90\xab\xc6\xe1\xfc\x17\x32\x4d"
+			"\x68\x83\x9e\xb9\xd4\xef\x0a\x25"
+			"\x40\x5b\x76\x91\xac\xc7\xe2\xfd"
+			"\x18\x33\x4e\x69\x84\x9f\xba\xd5"
+			"\xf0\x0b\x26\x41\x5c\x77\x92\xad"
+			"\xc8\xe3\xfe\x19\x34\x4f\x6a\x85"
+			"\xa0\xbb\xd6\xf1\x0c\x27\x42\x5d"
+			"\x78\x93\xae\xc9\xe4\xff\x1a\x35"
+			"\x50\x6b\x86\xa1\xbc\xd7\xf2\x0d"
+			"\x28\x43\x5e\x79\x94\xaf\xca\xe5"
+			"\x00\x1d\x3a\x57\x74\x91\xae\xcb"
+			"\xe8\x05\x22\x3f\x5c\x79\x96\xb3"
+			"\xd0\xed\x0a\x27\x44\x61\x7e\x9b"
+			"\xb8\xd5\xf2\x0f\x2c\x49\x66\x83"
+			"\xa0\xbd\xda\xf7\x14\x31\x4e\x6b"
+			"\x88\xa5\xc2\xdf\xfc\x19\x36\x53"
+			"\x70\x8d\xaa\xc7\xe4\x01\x1e\x3b"
+			"\x58\x75\x92\xaf\xcc\xe9\x06\x23"
+			"\x40\x5d\x7a\x97\xb4\xd1\xee\x0b"
+			"\x28\x45\x62\x7f\x9c\xb9\xd6\xf3"
+			"\x10\x2d\x4a\x67\x84\xa1\xbe\xdb"
+			"\xf8\x15\x32\x4f\x6c\x89\xa6\xc3"
+			"\xe0\xfd\x1a\x37\x54\x71\x8e\xab"
+			"\xc8\xe5\x02\x1f\x3c\x59\x76\x93"
+			"\xb0\xcd\xea\x07\x24\x41\x5e\x7b"
+			"\x98\xb5\xd2\xef\x0c\x29\x46\x63"
+			"\x80\x9d\xba\xd7\xf4\x11\x2e\x4b"
+			"\x68\x85\xa2\xbf\xdc\xf9\x16\x33"
+			"\x50\x6d\x8a\xa7\xc4\xe1\xfe\x1b"
+			"\x38\x55\x72\x8f\xac\xc9\xe6\x03"
+			"\x20\x3d\x5a\x77\x94\xb1\xce\xeb"
+			"\x08\x25\x42\x5f\x7c\x99\xb6\xd3"
+			"\xf0\x0d\x2a\x47\x64\x81\x9e\xbb"
+			"\xd8\xf5\x12\x2f\x4c\x69\x86\xa3"
+			"\xc0\xdd\xfa\x17\x34\x51\x6e\x8b"
+			"\xa8\xc5\xe2\xff\x1c\x39\x56\x73"
+			"\x90\xad\xca\xe7\x04\x21\x3e\x5b"
+			"\x78\x95\xb2\xcf\xec\x09\x26\x43"
+			"\x60\x7d\x9a\xb7\xd4\xf1\x0e\x2b"
+			"\x48\x65\x82\x9f\xbc\xd9\xf6\x13"
+			"\x30\x4d\x6a\x87\xa4\xc1\xde\xfb"
+			"\x18\x35\x52\x6f\x8c\xa9\xc6\xe3"
+			"\x00\x1f\x3e\x5d\x7c\x9b\xba\xd9"
+			"\xf8\x17\x36\x55\x74\x93\xb2\xd1"
+			"\xf0\x0f\x2e\x4d\x6c\x8b\xaa\xc9"
+			"\xe8\x07\x26\x45\x64\x83\xa2\xc1"
+			"\xe0\xff\x1e\x3d\x5c\x7b\x9a\xb9"
+			"\xd8\xf7\x16\x35\x54\x73\x92\xb1"
+			"\xd0\xef\x0e\x2d\x4c\x6b\x8a\xa9"
+			"\xc8\xe7\x06\x25\x44\x63\x82\xa1"
+			"\xc0\xdf\xfe\x1d\x3c\x5b\x7a\x99"
+			"\xb8\xd7\xf6\x15\x34\x53\x72\x91"
+			"\xb0\xcf\xee\x0d\x2c\x4b\x6a\x89"
+			"\xa8\xc7\xe6\x05\x24\x43\x62\x81"
+			"\xa0\xbf\xde\xfd\x1c\x3b\x5a\x79"
+			"\x98\xb7\xd6\xf5\x14\x33\x52\x71"
+			"\x90\xaf\xce\xed\x0c\x2b\x4a\x69"
+			"\x88\xa7\xc6\xe5\x04\x23\x42\x61"
+			"\x80\x9f\xbe\xdd\xfc\x1b\x3a\x59"
+			"\x78\x97\xb6\xd5\xf4\x13\x32\x51"
+			"\x70\x8f\xae\xcd\xec\x0b\x2a\x49"
+			"\x68\x87\xa6\xc5\xe4\x03\x22\x41"
+			"\x60\x7f\x9e\xbd\xdc\xfb\x1a\x39"
+			"\x58\x77\x96\xb5\xd4\xf3\x12\x31"
+			"\x50\x6f\x8e\xad\xcc\xeb\x0a\x29"
+			"\x48\x67\x86\xa5\xc4\xe3\x02\x21"
+			"\x40\x5f\x7e\x9d\xbc\xdb\xfa\x19"
+			"\x38\x57\x76\x95\xb4\xd3\xf2\x11"
+			"\x30\x4f\x6e\x8d\xac\xcb\xea\x09"
+			"\x28\x47\x66\x85\xa4\xc3\xe2\x01"
+			"\x20\x3f\x5e\x7d\x9c\xbb\xda\xf9"
+			"\x18\x37\x56\x75\x94\xb3\xd2\xf1"
+			"\x10\x2f\x4e\x6d\x8c\xab\xca\xe9"
+			"\x08\x27\x46\x65\x84\xa3\xc2\xe1"
+			"\x00\x21\x42\x63",
+		.ilen = 4100,
+		.result =
+			"\xf0\x5c\x74\xad\x4e\xbc\x99\xe2"
+			"\xae\xff\x91\x3a\x44\xcf\x38\x32"
+			"\x1e\xad\xa7\xcd\xa1\x39\x95\xaa"
+			"\x10\xb1\xb3\x2e\x04\x31\x8f\x86"
+			"\xf2\x62\x74\x70\x0c\xa4\x46\x08"
+			"\xa8\xb7\x99\xa8\xe9\xd2\x73\x79"
+			"\x7e\x6e\xd4\x8f\x1e\xc7\x8e\x31"
+			"\x0b\xfa\x4b\xce\xfd\xf3\x57\x71"
+			"\xe9\x46\x03\xa5\x3d\x34\x00\xe2"
+			"\x18\xff\x75\x6d\x06\x2d\x00\xab"
+			"\xb9\x3e\x6c\x59\xc5\x84\x06\xb5"
+			"\x8b\xd0\x89\x9c\x4a\x79\x16\xc6"
+			"\x3d\x74\x54\xfa\x44\xcd\x23\x26"
+			"\x5c\xcf\x7e\x28\x92\x32\xbf\xdf"
+			"\xa7\x20\x3c\x74\x58\x2a\x9a\xde"
+			"\x61\x00\x1c\x4f\xff\x59\xc4\x22"
+			"\xac\x3c\xd0\xe8\x6c\xf9\x97\x1b"
+			"\x58\x9b\xad\x71\xe8\xa9\xb5\x0d"
+			"\xee\x2f\x04\x1f\x7f\xbc\x99\xee"
+			"\x84\xff\x42\x60\xdc\x3a\x18\xa5"
+			"\x81\xf9\xef\xdc\x7a\x0f\x65\x41"
+			"\x2f\xa3\xd3\xf9\xc2\xcb\xc0\x4d"
+			"\x8f\xd3\x76\x96\xad\x49\x6d\x38"
+			"\x3d\x39\x0b\x6c\x80\xb7\x54\x69"
+			"\xf0\x2c\x90\x02\x29\x0d\x1c\x12"
+			"\xad\x55\xc3\x8b\x68\xd9\xcc\xb3"
+			"\xb2\x64\x33\x90\x5e\xca\x4b\xe2"
+			"\xfb\x75\xdc\x63\xf7\x9f\x82\x74"
+			"\xf0\xc9\xaa\x7f\xe9\x2a\x9b\x33"
+			"\xbc\x88\x00\x7f\xca\xb2\x1f\x14"
+			"\xdb\xc5\x8e\x7b\x11\x3c\x3e\x08"
+			"\xf3\x83\xe8\xe0\x94\x86\x2e\x92"
+			"\x78\x6b\x01\xc9\xc7\x83\xba\x21"
+			"\x6a\x25\x15\x33\x4e\x45\x08\xec"
+			"\x35\xdb\xe0\x6e\x31\x51\x79\xa9"
+			"\x42\x44\x65\xc1\xa0\xf1\xf9\x2a"
+			"\x70\xd5\xb6\xc6\xc1\x8c\x39\xfc"
+			"\x25\xa6\x55\xd9\xdd\x2d\x4c\xec"
+			"\x49\xc6\xeb\x0e\xa8\x25\x2a\x16"
+			"\x1b\x66\x84\xda\xe2\x92\xe5\xc0"
+			"\xc8\x53\x07\xaf\x80\x84\xec\xfd"
+			"\xcd\xd1\x6e\xcd\x6f\x6a\xf5\x36"
+			"\xc5\x15\xe5\x25\x7d\x77\xd1\x1a"
+			"\x93\x36\xa9\xcf\x7c\xa4\x54\x4a"
+			"\x06\x51\x48\x4e\xf6\x59\x87\xd2"
+			"\x04\x02\xef\xd3\x44\xde\x76\x31"
+			"\xb3\x34\x17\x1b\x9d\x66\x11\x9f"
+			"\x1e\xcc\x17\xe9\xc7\x3c\x1b\xe7"
+			"\xcb\x50\x08\xfc\xdc\x2b\x24\xdb"
+			"\x65\x83\xd0\x3b\xe3\x30\xea\x94"
+			"\x6c\xe7\xe8\x35\x32\xc7\xdb\x64"
+			"\xb4\x01\xab\x36\x2c\x77\x13\xaf"
+			"\xf8\x2b\x88\x3f\x54\x39\xc4\x44"
+			"\xfe\xef\x6f\x68\x34\xbe\x0f\x05"
+			"\x16\x6d\xf6\x0a\x30\xe7\xe3\xed"
+			"\xc4\xde\x3c\x1b\x13\xd8\xdb\xfe"
+			"\x41\x62\xe5\x28\xd4\x8d\xa3\xc7"
+			"\x93\x97\xc6\x48\x45\x1d\x9f\x83"
+			"\xdf\x4b\x40\x3e\x42\x25\x87\x80"
+			"\x4c\x7d\xa8\xd4\x98\x23\x95\x75"
+			"\x41\x8c\xda\x41\x9b\xd4\xa7\x06"
+			"\xb5\xf1\x71\x09\x53\xbe\xca\xbf"
+			"\x32\x03\xed\xf0\x50\x1c\x56\x39"
+			"\x5b\xa4\x75\x18\xf7\x9b\x58\xef"
+			"\x53\xfc\x2a\x38\x23\x15\x75\xcd"
+			"\x45\xe5\x5a\x82\x55\xba\x21\xfa"
+			"\xd4\xbd\xc6\x94\x7c\xc5\x80\x12"
+			"\xf7\x4b\x32\xc4\x9a\x82\xd8\x28"
+			"\x8f\xd9\xc2\x0f\x60\x03\xbe\x5e"
+			"\x21\xd6\x5f\x58\xbf\x5c\xb1\x32"
+			"\x82\x8d\xa9\xe5\xf2\x66\x1a\xc0"
+			"\xa0\xbc\x58\x2f\x71\xf5\x2f\xed"
+			"\xd1\x26\xb9\xd8\x49\x5a\x07\x19"
+			"\x01\x7c\x59\xb0\xf8\xa4\xb7\xd3"
+			"\x7b\x1a\x8c\x38\xf4\x50\xa4\x59"
+			"\xb0\xcc\x41\x0b\x88\x7f\xe5\x31"
+			"\xb3\x42\xba\xa2\x7e\xd4\x32\x71"
+			"\x45\x87\x48\xa9\xc2\xf2\x89\xb3"
+			"\xe4\xa7\x7e\x52\x15\x61\xfa\xfe"
+			"\xc9\xdd\x81\xeb\x13\xab\xab\xc3"
+			"\x98\x59\xd8\x16\x3d\x14\x7a\x1c"
+			"\x3c\x41\x9a\x16\x16\x9b\xd2\xd2"
+			"\x69\x3a\x29\x23\xac\x86\x32\xa5"
+			"\x48\x9c\x9e\xf3\x47\x77\x81\x70"
+			"\x24\xe8\x85\xd2\xf5\xb5\xfa\xff"
+			"\x59\x6a\xd3\x50\x59\x43\x59\xde"
+			"\xd9\xf1\x55\xa5\x0c\xc3\x1a\x1a"
+			"\x18\x34\x0d\x1a\x63\x33\xed\x10"
+			"\xe0\x1d\x2a\x18\xd2\xc0\x54\xa8"
+			"\xca\xb5\x9a\xd3\xdd\xca\x45\x84"
+			"\x50\xe7\x0f\xfe\xa4\x99\x5a\xbe"
+			"\x43\x2d\x9a\xcb\x92\x3f\x5a\x1d"
+			"\x85\xd8\xc9\xdf\x68\xc9\x12\x80"
+			"\x56\x0c\xdc\x00\xdc\x3a\x7d\x9d"
+			"\xa3\xa2\xe8\x4d\xbf\xf9\x70\xa0"
+			"\xa4\x13\x4f\x6b\xaf\x0a\x89\x7f"
+			"\xda\xf0\xbf\x9b\xc8\x1d\xe5\xf8"
+			"\x2e\x8b\x07\xb5\x73\x1b\xcc\xa2"
+			"\xa6\xad\x30\xbc\x78\x3c\x5b\x10"
+			"\xfa\x5e\x62\x2d\x9e\x64\xb3\x33"
+			"\xce\xf9\x1f\x86\xe7\x8b\xa2\xb8"
+			"\xe8\x99\x57\x8c\x11\xed\x66\xd9"
+			"\x3c\x72\xb9\xc3\xe6\x4e\x17\x3a"
+			"\x6a\xcb\x42\x24\x06\xed\x3e\x4e"
+			"\xa3\xe8\x6a\x94\xda\x0d\x4e\xd5"
+			"\x14\x19\xcf\xb6\x26\xd8\x2e\xcc"
+			"\x64\x76\x38\x49\x4d\xfe\x30\x6d"
+			"\xe4\xc8\x8c\x7b\xc4\xe0\x35\xba"
+			"\x22\x6e\x76\xe1\x1a\xf2\x53\xc3"
+			"\x28\xa2\x82\x1f\x61\x69\xad\xc1"
+			"\x7b\x28\x4b\x1e\x6c\x85\x95\x9b"
+			"\x51\xb5\x17\x7f\x12\x69\x8c\x24"
+			"\xd5\xc7\x5a\x5a\x11\x54\xff\x5a"
+			"\xf7\x16\xc3\x91\xa6\xf0\xdc\x0a"
+			"\xb6\xa7\x4a\x0d\x7a\x58\xfe\xa5"
+			"\xf5\xcb\x8f\x7b\x0e\xea\x57\xe7"
+			"\xbd\x79\xd6\x1c\x88\x23\x6c\xf2"
+			"\x4d\x29\x77\x53\x35\x6a\x00\x8d"
+			"\xcd\xa3\x58\xbe\x77\x99\x18\xf8"
+			"\xe6\xe1\x8f\xe9\x37\x8f\xe3\xe2"
+			"\x5a\x8a\x93\x25\xaf\xf3\x78\x80"
+			"\xbe\xa6\x1b\xc6\xac\x8b\x1c\x91"
+			"\x58\xe1\x9f\x89\x35\x9d\x1d\x21"
+			"\x29\x9f\xf4\x99\x02\x27\x0f\xa8"
+			"\x4f\x79\x94\x2b\x33\x2c\xda\xa2"
+			"\x26\x39\x83\x94\xef\x27\xd8\x53"
+			"\x8f\x66\x0d\xe4\x41\x7d\x34\xcd"
+			"\x43\x7c\x95\x0a\x53\xef\x66\xda"
+			"\x7e\x9b\xf3\x93\xaf\xd0\x73\x71"
+			"\xba\x40\x9b\x74\xf8\xd7\xd7\x41"
+			"\x6d\xaf\x72\x9c\x8d\x21\x87\x3c"
+			"\xfd\x0a\x90\xa9\x47\x96\x9e\xd3"
+			"\x88\xee\x73\xcf\x66\x2f\x52\x56"
+			"\x6d\xa9\x80\x4c\xe2\x6f\x62\x88"
+			"\x3f\x0e\x54\x17\x48\x80\x5d\xd3"
+			"\xc3\xda\x25\x3d\xa1\xc8\xcb\x9f"
+			"\x9b\x70\xb3\xa1\xeb\x04\x52\xa1"
+			"\xf2\x22\x0f\xfc\xc8\x18\xfa\xf9"
+			"\x85\x9c\xf1\xac\xeb\x0c\x02\x46"
+			"\x75\xd2\xf5\x2c\xe3\xd2\x59\x94"
+			"\x12\xf3\x3c\xfc\xd7\x92\xfa\x36"
+			"\xba\x61\x34\x38\x7c\xda\x48\x3e"
+			"\x08\xc9\x39\x23\x5e\x02\x2c\x1a"
+			"\x18\x7e\xb4\xd9\xfd\x9e\x40\x02"
+			"\xb1\x33\x37\x32\xe7\xde\xd6\xd0"
+			"\x7c\x58\x65\x4b\xf8\x34\x27\x9c"
+			"\x44\xb4\xbd\xe9\xe9\x4c\x78\x7d"
+			"\x4b\x9f\xce\xb1\xcd\x47\xa5\x37"
+			"\xe5\x6d\xbd\xb9\x43\x94\x0a\xd4"
+			"\xd6\xf9\x04\x5f\xb5\x66\x6c\x1a"
+			"\x35\x12\xe3\x36\x28\x27\x36\x58"
+			"\x01\x2b\x79\xe4\xba\x6d\x10\x7d"
+			"\x65\xdf\x84\x95\xf4\xd5\xb6\x8f"
+			"\x2b\x9f\x96\x00\x86\x60\xf0\x21"
+			"\x76\xa8\x6a\x8c\x28\x1c\xb3\x6b"
+			"\x97\xd7\xb6\x53\x2a\xcc\xab\x40"
+			"\x9d\x62\x79\x58\x52\xe6\x65\xb7"
+			"\xab\x55\x67\x9c\x89\x7c\x03\xb0"
+			"\x73\x59\xc5\x81\xf5\x18\x17\x5c"
+			"\x89\xf3\x78\x35\x44\x62\x78\x72"
+			"\xd0\x96\xeb\x31\xe7\x87\x77\x14"
+			"\x99\x51\xf2\x59\x26\x9e\xb5\xa6"
+			"\x45\xfe\x6e\xbd\x07\x4c\x94\x5a"
+			"\xa5\x7d\xfc\xf1\x2b\x77\xe2\xfe"
+			"\x17\xd4\x84\xa0\xac\xb5\xc7\xda"
+			"\xa9\x1a\xb6\xf3\x74\x11\xb4\x9d"
+			"\xfb\x79\x2e\x04\x2d\x50\x28\x83"
+			"\xbf\xc6\x52\xd3\x34\xd6\xe8\x7a"
+			"\xb6\xea\xe7\xa8\x6c\x15\x1e\x2c"
+			"\x57\xbc\x48\x4e\x5f\x5c\xb6\x92"
+			"\xd2\x49\x77\x81\x6d\x90\x70\xae"
+			"\x98\xa1\x03\x0d\x6b\xb9\x77\x14"
+			"\xf1\x4e\x23\xd3\xf8\x68\xbd\xc2"
+			"\xfe\x04\xb7\x5c\xc5\x17\x60\x8f"
+			"\x65\x54\xa4\x7a\x42\xdc\x18\x0d"
+			"\xb5\xcf\x0f\xd3\xc7\x91\x66\x1b"
+			"\x45\x42\x27\x75\x50\xe5\xee\xb8"
+			"\x7f\x33\x2c\xba\x4a\x92\x4d\x2c"
+			"\x3c\xe3\x0d\x80\x01\xba\x0d\x29"
+			"\xd8\x3c\xe9\x13\x16\x57\xe6\xea"
+			"\x94\x52\xe7\x00\x4d\x30\xb0\x0f"
+			"\x35\xb8\xb8\xa7\xb1\xb5\x3b\x44"
+			"\xe1\x2f\xfd\x88\xed\x43\xe7\x52"
+			"\x10\x93\xb3\x8a\x30\x6b\x0a\xf7"
+			"\x23\xc6\x50\x9d\x4a\xb0\xde\xc3"
+			"\xdc\x9b\x2f\x01\x56\x36\x09\xc5"
+			"\x2f\x6b\xfe\xf1\xd8\x27\x45\x03"
+			"\x30\x5e\x5c\x5b\xb4\x62\x0e\x1a"
+			"\xa9\x21\x2b\x92\x94\x87\x62\x57"
+			"\x4c\x10\x74\x1a\xf1\x0a\xc5\x84"
+			"\x3b\x9e\x72\x02\xd7\xcc\x09\x56"
+			"\xbd\x54\xc1\xf0\xc3\xe3\xb3\xf8"
+			"\xd2\x0d\x61\xcb\xef\xce\x0d\x05"
+			"\xb0\x98\xd9\x8e\x4f\xf9\xbc\x93"
+			"\xa6\xea\xc8\xcf\x10\x53\x4b\xf1"
+			"\xec\xfc\x89\xf9\x64\xb0\x22\xbf"
+			"\x9e\x55\x46\x9f\x7c\x50\x8e\x84"
+			"\x54\x20\x98\xd7\x6c\x40\x1e\xdb"
+			"\x69\x34\x78\x61\x24\x21\x9c\x8a"
+			"\xb3\x62\x31\x8b\x6e\xf5\x2a\x35"
+			"\x86\x13\xb1\x6c\x64\x2e\x41\xa5"
+			"\x05\xf2\x42\xba\xd2\x3a\x0d\x8e"
+			"\x8a\x59\x94\x3c\xcf\x36\x27\x82"
+			"\xc2\x45\xee\x58\xcd\x88\xb4\xec"
+			"\xde\xb2\x96\x0a\xaf\x38\x6f\x88"
+			"\xd7\xd8\xe1\xdf\xb9\x96\xa9\x0a"
+			"\xb1\x95\x28\x86\x20\xe9\x17\x49"
+			"\xa2\x29\x38\xaa\xa5\xe9\x6e\xf1"
+			"\x19\x27\xc0\xd5\x2a\x22\xc3\x0b"
+			"\xdb\x7c\x73\x10\xb9\xba\x89\x76"
+			"\x54\xae\x7d\x71\xb3\x93\xf6\x32"
+			"\xe6\x47\x43\x55\xac\xa0\x0d\xc2"
+			"\x93\x27\x4a\x8e\x0e\x74\x15\xc7"
+			"\x0b\x85\xd9\x0c\xa9\x30\x7a\x3e"
+			"\xea\x8f\x85\x6d\x3a\x12\x4f\x72"
+			"\x69\x58\x7a\x80\xbb\xb5\x97\xf3"
+			"\xcf\x70\xd2\x5d\xdd\x4d\x21\x79"
+			"\x54\x4d\xe4\x05\xe8\xbd\xc2\x62"
+			"\xb1\x3b\x77\x1c\xd6\x5c\xf3\xa0"
+			"\x79\x00\xa8\x6c\x29\xd9\x18\x24"
+			"\x36\xa2\x46\xc0\x96\x65\x7f\xbd"
+			"\x2a\xed\x36\x16\x0c\xaa\x9f\xf4"
+			"\xc5\xb4\xe2\x12\xed\x69\xed\x4f"
+			"\x26\x2c\x39\x52\x89\x98\xe7\x2c"
+			"\x99\xa4\x9e\xa3\x9b\x99\x46\x7a"
+			"\x3a\xdc\xa8\x59\xa3\xdb\xc3\x3b"
+			"\x95\x0d\x3b\x09\x6e\xee\x83\x5d"
+			"\x32\x4d\xed\xab\xfa\x98\x14\x4e"
+			"\xc3\x15\x45\x53\x61\xc4\x93\xbd"
+			"\x90\xf4\x99\x95\x4c\xe6\x76\x92"
+			"\x29\x90\x46\x30\x92\x69\x7d\x13"
+			"\xf2\xa5\xcd\x69\x49\x44\xb2\x0f"
+			"\x63\x40\x36\x5f\x09\xe2\x78\xf8"
+			"\x91\xe3\xe2\xfa\x10\xf7\xc8\x24"
+			"\xa8\x89\x32\x5c\x37\x25\x1d\xb2"
+			"\xea\x17\x8a\x0a\xa9\x64\xc3\x7c"
+			"\x3c\x7c\xbd\xc6\x79\x34\xe7\xe2"
+			"\x85\x8e\xbf\xf8\xde\x92\xa0\xae"
+			"\x20\xc4\xf6\xbb\x1f\x38\x19\x0e"
+			"\xe8\x79\x9c\xa1\x23\xe9\x54\x7e"
+			"\x37\x2f\xe2\x94\x32\xaf\xa0\x23"
+			"\x49\xe4\xc0\xb3\xac\x00\x8f\x36"
+			"\x05\xc4\xa6\x96\xec\x05\x98\x4f"
+			"\x96\x67\x57\x1f\x20\x86\x1b\x2d"
+			"\x69\xe4\x29\x93\x66\x5f\xaf\x6b"
+			"\x88\x26\x2c\x67\x02\x4b\x52\xd0"
+			"\x83\x7a\x43\x1f\xc0\x71\x15\x25"
+			"\x77\x65\x08\x60\x11\x76\x4c\x8d"
+			"\xed\xa9\x27\xc6\xb1\x2a\x2c\x6a"
+			"\x4a\x97\xf5\xc6\xb7\x70\x42\xd3"
+			"\x03\xd1\x24\x95\xec\x6d\xab\x38"
+			"\x72\xce\xe2\x8b\x33\xd7\x51\x09"
+			"\xdc\x45\xe0\x09\x96\x32\xf3\xc4"
+			"\x84\xdc\x73\x73\x2d\x1b\x11\x98"
+			"\xc5\x0e\x69\x28\x94\xc7\xb5\x4d"
+			"\xc8\x8a\xd0\xaa\x13\x2e\x18\x74"
+			"\xdd\xd1\x1e\xf3\x90\xe8\xfc\x9a"
+			"\x72\x4a\x0e\xd1\xe4\xfb\x0d\x96"
+			"\xd1\x0c\x79\x85\x1b\x1c\xfe\xe1"
+			"\x62\x8f\x7a\x73\x32\xab\xc8\x18"
+			"\x69\xe3\x34\x30\xdf\x13\xa6\xe5"
+			"\xe8\x0e\x67\x7f\x81\x11\xb4\x60"
+			"\xc7\xbd\x79\x65\x50\xdc\xc4\x5b"
+			"\xde\x39\xa4\x01\x72\x63\xf3\xd1"
+			"\x64\x4e\xdf\xfc\x27\x92\x37\x0d"
+			"\x57\xcd\x11\x4f\x11\x04\x8e\x1d"
+			"\x16\xf7\xcd\x92\x9a\x99\x30\x14"
+			"\xf1\x7c\x67\x1b\x1f\x41\x0b\xe8"
+			"\x32\xe8\xb8\xc1\x4f\x54\x86\x4f"
+			"\xe5\x79\x81\x73\xcd\x43\x59\x68"
+			"\x73\x02\x3b\x78\x21\x72\x43\x00"
+			"\x49\x17\xf7\x00\xaf\x68\x24\x53"
+			"\x05\x0a\xc3\x33\xe0\x33\x3f\x69"
+			"\xd2\x84\x2f\x0b\xed\xde\x04\xf4"
+			"\x11\x94\x13\x69\x51\x09\x28\xde"
+			"\x57\x5c\xef\xdc\x9a\x49\x1c\x17"
+			"\x97\xf3\x96\xc1\x7f\x5d\x2e\x7d"
+			"\x55\xb8\xb3\x02\x09\xb3\x1f\xe7"
+			"\xc9\x8d\xa3\x36\x34\x8a\x77\x13"
+			"\x30\x63\x4c\xa5\xcd\xc3\xe0\x7e"
+			"\x05\xa1\x7b\x0c\xcb\x74\x47\x31"
+			"\x62\x03\x43\xf1\x87\xb4\xb0\x85"
+			"\x87\x8e\x4b\x25\xc7\xcf\xae\x4b"
+			"\x36\x46\x3e\x62\xbc\x6f\xeb\x5f"
+			"\x73\xac\xe6\x07\xee\xc1\xa1\xd6"
+			"\xc4\xab\xc9\xd6\x89\x45\xe1\xf1"
+			"\x04\x4e\x1a\x6f\xbb\x4f\x3a\xa3"
+			"\xa0\xcb\xa3\x0a\xd8\x71\x35\x55"
+			"\xe4\xbc\x2e\x04\x06\xe6\xff\x5b"
+			"\x1c\xc0\x11\x7c\xc5\x17\xf3\x38"
+			"\xcf\xe9\xba\x0f\x0e\xef\x02\xc2"
+			"\x8d\xc6\xbc\x4b\x67\x20\x95\xd7"
+			"\x2c\x45\x5b\x86\x44\x8c\x6f\x2e"
+			"\x7e\x9f\x1c\x77\xba\x6b\x0e\xa3"
+			"\x69\xdc\xab\x24\x57\x60\x47\xc1"
+			"\xd1\xa5\x9d\x23\xe6\xb1\x37\xfe"
+			"\x93\xd2\x4c\x46\xf9\x0c\xc6\xfb"
+			"\xd6\x9d\x99\x69\xab\x7a\x07\x0c"
+			"\x65\xe7\xc4\x08\x96\xe2\xa5\x01"
+			"\x3f\x46\x07\x05\x7e\xe8\x9a\x90"
+			"\x50\xdc\xe9\x7a\xea\xa1\x39\x6e"
+			"\x66\xe4\x6f\xa5\x5f\xb2\xd9\x5b"
+			"\xf5\xdb\x2a\x32\xf0\x11\x6f\x7c"
+			"\x26\x10\x8f\x3d\x80\xe9\x58\xf7"
+			"\xe0\xa8\x57\xf8\xdb\x0e\xce\x99"
+			"\x63\x19\x3d\xd5\xec\x1b\x77\x69"
+			"\x98\xf6\xe4\x5f\x67\x17\x4b\x09"
+			"\x85\x62\x82\x70\x18\xe2\x9a\x78"
+			"\xe2\x62\xbd\xb4\xf1\x42\xc6\xfb"
+			"\x08\xd0\xbd\xeb\x4e\x09\xf2\xc8"
+			"\x1e\xdc\x3d\x32\x21\x56\x9c\x4f"
+			"\x35\xf3\x61\x06\x72\x84\xc4\x32"
+			"\xf2\xf1\xfa\x0b\x2f\xc3\xdb\x02"
+			"\x04\xc2\xde\x57\x64\x60\x8d\xcf"
+			"\xcb\x86\x5d\x97\x3e\xb1\x9c\x01"
+			"\xd6\x28\x8f\x99\xbc\x46\xeb\x05"
+			"\xaf\x7e\xb8\x21\x2a\x56\x85\x1c"
+			"\xb3\x71\xa0\xde\xca\x96\xf1\x78"
+			"\x49\xa2\x99\x81\x80\x5c\x01\xf5"
+			"\xa0\xa2\x56\x63\xe2\x70\x07\xa5"
+			"\x95\xd6\x85\xeb\x36\x9e\xa9\x51"
+			"\x66\x56\x5f\x1d\x02\x19\xe2\xf6"
+			"\x4f\x73\x38\x09\x75\x64\x48\xe0"
+			"\xf1\x7e\x0e\xe8\x9d\xf9\xed\x94"
+			"\xfe\x16\x26\x62\x49\x74\xf4\xb0"
+			"\xd4\xa9\x6c\xb0\xfd\x53\xe9\x81"
+			"\xe0\x7a\xbf\xcf\xb5\xc4\x01\x81"
+			"\x79\x99\x77\x01\x3b\xe9\xa2\xb6"
+			"\xe6\x6a\x8a\x9e\x56\x1c\x8d\x1e"
+			"\x8f\x06\x55\x2c\x6c\xdc\x92\x87"
+			"\x64\x3b\x4b\x19\xa1\x13\x64\x1d"
+			"\x4a\xe9\xc0\x00\xb8\x95\xef\x6b"
+			"\x1a\x86\x6d\x37\x52\x02\xc2\xe0"
+			"\xc8\xbb\x42\x0c\x02\x21\x4a\xc9"
+			"\xef\xa0\x54\xe4\x5e\x16\x53\x81"
+			"\x70\x62\x10\xaf\xde\xb8\xb5\xd3"
+			"\xe8\x5e\x6c\xc3\x8a\x3e\x18\x07"
+			"\xf2\x2f\x7d\xa7\xe1\x3d\x4e\xb4"
+			"\x26\xa7\xa3\x93\x86\xb2\x04\x1e"
+			"\x53\x5d\x86\xd6\xde\x65\xca\xe3"
+			"\x4e\xc1\xcf\xef\xc8\x70\x1b\x83"
+			"\x13\xdd\x18\x8b\x0d\x76\xd2\xf6"
+			"\x37\x7a\x93\x7a\x50\x11\x9f\x96"
+			"\x86\x25\xfd\xac\xdc\xbe\x18\x93"
+			"\x19\x6b\xec\x58\x4f\xb9\x75\xa7"
+			"\xdd\x3f\x2f\xec\xc8\x5a\x84\xab"
+			"\xd5\xe4\x8a\x07\xf6\x4d\x23\xd6"
+			"\x03\xfb\x03\x6a\xea\x66\xbf\xd4"
+			"\xb1\x34\xfb\x78\xe9\x55\xdc\x7c"
+			"\x3d\x9c\xe5\x9a\xac\xc3\x7a\x80"
+			"\x24\x6d\xa0\xef\x25\x7c\xb7\xea"
+			"\xce\x4d\x5f\x18\x60\xce\x87\x22"
+			"\x66\x2f\xd5\xdd\xdd\x02\x21\x75"
+			"\x82\xa0\x1f\x58\xc6\xd3\x62\xf7"
+			"\x32\xd8\xaf\x1e\x07\x77\x51\x96"
+			"\xd5\x6b\x1e\x7e\x80\x02\xe8\x67"
+			"\xea\x17\x0b\x10\xd2\x3f\x28\x25"
+			"\x4f\x05\x77\x02\x14\x69\xf0\x2c"
+			"\xbe\x0c\xf1\x74\x30\xd1\xb9\x9b"
+			"\xfc\x8c\xbb\x04\x16\xd9\xba\xc3"
+			"\xbc\x91\x8a\xc4\x30\xa4\xb0\x12"
+			"\x4c\x21\x87\xcb\xc9\x1d\x16\x96"
+			"\x07\x6f\x23\x54\xb9\x6f\x79\xe5"
+			"\x64\xc0\x64\xda\xb1\xae\xdd\x60"
+			"\x6c\x1a\x9d\xd3\x04\x8e\x45\xb0"
+			"\x92\x61\xd0\x48\x81\xed\x5e\x1d"
+			"\xa0\xc9\xa4\x33\xc7\x13\x51\x5d"
+			"\x7f\x83\x73\xb6\x70\x18\x65\x3e"
+			"\x2f\x0e\x7a\x12\x39\x98\xab\xd8"
+			"\x7e\x6f\xa3\xd1\xba\x56\xad\xbd"
+			"\xf0\x03\x01\x1c\x85\x35\x9f\xeb"
+			"\x19\x63\xa1\xaf\xfe\x2d\x35\x50"
+			"\x39\xa0\x65\x7c\x95\x7e\x6b\xfe"
+			"\xc1\xac\x07\x7c\x98\x4f\xbe\x57"
+			"\xa7\x22\xec\xe2\x7e\x29\x09\x53"
+			"\xe8\xbf\xb4\x7e\x3f\x8f\xfc\x14"
+			"\xce\x54\xf9\x18\x58\xb5\xff\x44"
+			"\x05\x9d\xce\x1b\xb6\x82\x23\xc8"
+			"\x2e\xbc\x69\xbb\x4a\x29\x0f\x65"
+			"\x94\xf0\x63\x06\x0e\xef\x8c\xbd"
+			"\xff\xfd\xb0\x21\x6e\x57\x05\x75"
+			"\xda\xd5\xc4\xeb\x8d\x32\xf7\x50"
+			"\xd3\x6f\x22\xed\x5f\x8e\xa2\x5b"
+			"\x80\x8c\xc8\x78\x40\x24\x4b\x89"
+			"\x30\xce\x7a\x97\x0e\xc4\xaf\xef"
+			"\x9b\xb4\xcd\x66\x74\x14\x04\x2b"
+			"\xf7\xce\x0b\x1c\x6e\xc2\x78\x8c"
+			"\xca\xc5\xd0\x1c\x95\x4a\x91\x2d"
+			"\xa7\x20\xeb\x86\x52\xb7\x67\xd8"
+			"\x0c\xd6\x04\x14\xde\x51\x74\x75"
+			"\xe7\x11\xb4\x87\xa3\x3d\x2d\xad"
+			"\x4f\xef\xa0\x0f\x70\x00\x6d\x13"
+			"\x19\x1d\x41\x50\xe9\xd8\xf0\x32"
+			"\x71\xbc\xd3\x11\xf2\xac\xbe\xaf"
+			"\x75\x46\x65\x4e\x07\x34\x37\xa3"
+			"\x89\xfe\x75\xd4\x70\x4c\xc6\x3f"
+			"\x69\x24\x0e\x38\x67\x43\x8c\xde"
+			"\x06\xb5\xb8\xe7\xc4\xf0\x41\x8f"
+			"\xf0\xbd\x2f\x0b\xb9\x18\xf8\xde"
+			"\x64\xb1\xdb\xee\x00\x50\x77\xe1"
+			"\xc7\xff\xa6\xfa\xdd\x70\xf4\xe3"
+			"\x93\xe9\x77\x35\x3d\x4b\x2f\x2b"
+			"\x6d\x55\xf0\xfc\x88\x54\x4e\x89"
+			"\xc1\x8a\x23\x31\x2d\x14\x2a\xb8"
+			"\x1b\x15\xdd\x9e\x6e\x7b\xda\x05"
+			"\x91\x7d\x62\x64\x96\x72\xde\xfc"
+			"\xc1\xec\xf0\x23\x51\x6f\xdb\x5b"
+			"\x1d\x08\x57\xce\x09\xb8\xf6\xcd"
+			"\x8d\x95\xf2\x20\xbf\x0f\x20\x57"
+			"\x98\x81\x84\x4f\x15\x5c\x76\xe7"
+			"\x3e\x0a\x3a\x6c\xc4\x8a\xbe\x78"
+			"\x74\x77\xc3\x09\x4b\x5d\x48\xe4"
+			"\xc8\xcb\x0b\xea\x17\x28\xcf\xcf"
+			"\x31\x32\x44\xa4\xe5\x0e\x1a\x98"
+			"\x94\xc4\xf0\xff\xae\x3e\x44\xe8"
+			"\xa5\xb3\xb5\x37\x2f\xe8\xaf\x6f"
+			"\x28\xc1\x37\x5f\x31\xd2\xb9\x33"
+			"\xb1\xb2\x52\x94\x75\x2c\x29\x59"
+			"\x06\xc2\x25\xe8\x71\x65\x4e\xed"
+			"\xc0\x9c\xb1\xbb\x25\xdc\x6c\xe7"
+			"\x4b\xa5\x7a\x54\x7a\x60\xff\x7a"
+			"\xe0\x50\x40\x96\x35\x63\xe4\x0b"
+			"\x76\xbd\xa4\x65\x00\x1b\x57\x88"
+			"\xae\xed\x39\x88\x42\x11\x3c\xed"
+			"\x85\x67\x7d\xb9\x68\x82\xe9\x43"
+			"\x3c\x47\x53\xfa\xe8\xf8\x9f\x1f"
+			"\x9f\xef\x0f\xf7\x30\xd9\x30\x0e"
+			"\xb9\x9f\x69\x18\x2f\x7e\xf8\xf8"
+			"\xf8\x8c\x0f\xd4\x02\x4d\xea\xcd"
+			"\x0a\x9c\x6f\x71\x6d\x5a\x4c\x60"
+			"\xce\x20\x56\x32\xc6\xc5\x99\x1f"
+			"\x09\xe6\x4e\x18\x1a\x15\x13\xa8"
+			"\x7d\xb1\x6b\xc0\xb2\x6d\xf8\x26"
+			"\x66\xf8\x3d\x18\x74\x70\x66\x7a"
+			"\x34\x17\xde\xba\x47\xf1\x06\x18"
+			"\xcb\xaf\xeb\x4a\x1e\x8f\xa7\x77"
+			"\xe0\x3b\x78\x62\x66\xc9\x10\xea"
+			"\x1f\xb7\x29\x0a\x45\xa1\x1d\x1e"
+			"\x1d\xe2\x65\x61\x50\x9c\xd7\x05"
+			"\xf2\x0b\x5b\x12\x61\x02\xc8\xe5"
+			"\x63\x4f\x20\x0c\x07\x17\x33\x5e"
+			"\x03\x9a\x53\x0f\x2e\x55\xfe\x50"
+			"\x43\x7d\xd0\xb6\x7e\x5a\xda\xae"
+			"\x58\xef\x15\xa9\x83\xd9\x46\xb1"
+			"\x42\xaa\xf5\x02\x6c\xce\x92\x06"
+			"\x1b\xdb\x66\x45\x91\x79\xc2\x2d"
+			"\xe6\x53\xd3\x14\xfd\xbb\x44\x63"
+			"\xc6\xd7\x3d\x7a\x0c\x75\x78\x9d"
+			"\x5c\xa6\x39\xb3\xe5\x63\xca\x8b"
+			"\xfe\xd3\xef\x60\x83\xf6\x8e\x70"
+			"\xb6\x67\xc7\x77\xed\x23\xef\x4c"
+			"\xf0\xed\x2d\x07\x59\x6f\xc1\x01"
+			"\x34\x37\x08\xab\xd9\x1f\x09\xb1"
+			"\xce\x5b\x17\xff\x74\xf8\x9c\xd5"
+			"\x2c\x56\x39\x79\x0f\x69\x44\x75"
+			"\x58\x27\x01\xc4\xbf\xa7\xa1\x1d"
+			"\x90\x17\x77\x86\x5a\x3f\xd9\xd1"
+			"\x0e\xa0\x10\xf8\xec\x1e\xa5\x7f"
+			"\x5e\x36\xd1\xe3\x04\x2c\x70\xf7"
+			"\x8e\xc0\x98\x2f\x6c\x94\x2b\x41"
+			"\xb7\x60\x00\xb7\x2e\xb8\x02\x8d"
+			"\xb8\xb0\xd3\x86\xba\x1d\xd7\x90"
+			"\xd6\xb6\xe1\xfc\xd7\xd8\x28\x06"
+			"\x63\x9b\xce\x61\x24\x79\xc0\x70"
+			"\x52\xd0\xb6\xd4\x28\x95\x24\x87"
+			"\x03\x1f\xb7\x9a\xda\xa3\xfb\x52"
+			"\x5b\x68\xe7\x4c\x8c\x24\xe1\x42"
+			"\xf7\xd5\xfd\xad\x06\x32\x9f\xba"
+			"\xc1\xfc\xdd\xc6\xfc\xfc\xb3\x38"
+			"\x74\x56\x58\x40\x02\x37\x52\x2c"
+			"\x55\xcc\xb3\x9e\x7a\xe9\xd4\x38"
+			"\x41\x5e\x0c\x35\xe2\x11\xd1\x13"
+			"\xf8\xb7\x8d\x72\x6b\x22\x2a\xb0"
+			"\xdb\x08\xba\x35\xb9\x3f\xc8\xd3"
+			"\x24\x90\xec\x58\xd2\x09\xc7\x2d"
+			"\xed\x38\x80\x36\x72\x43\x27\x49"
+			"\x4a\x80\x8a\xa2\xe8\xd3\xda\x30"
+			"\x7d\xb6\x82\x37\x86\x92\x86\x3e"
+			"\x08\xb2\x28\x5a\x55\x44\x24\x7d"
+			"\x40\x48\x8a\xb6\x89\x58\x08\xa0"
+			"\xd6\x6d\x3a\x17\xbf\xf6\x54\xa2"
+			"\xf5\xd3\x8c\x0f\x78\x12\x57\x8b"
+			"\xd5\xc2\xfd\x58\x5b\x7f\x38\xe3"
+			"\xcc\xb7\x7c\x48\xb3\x20\xe8\x81"
+			"\x14\x32\x45\x05\xe0\xdb\x9f\x75"
+			"\x85\xb4\x6a\xfc\x95\xe3\x54\x22"
+			"\x12\xee\x30\xfe\xd8\x30\xef\x34"
+			"\x50\xab\x46\x30\x98\x2f\xb7\xc0"
+			"\x15\xa2\x83\xb6\xf2\x06\x21\xa2"
+			"\xc3\x26\x37\x14\xd1\x4d\xb5\x10"
+			"\x52\x76\x4d\x6a\xee\xb5\x2b\x15"
+			"\xb7\xf9\x51\xe8\x2a\xaf\xc7\xfa"
+			"\x77\xaf\xb0\x05\x4d\xd1\x68\x8e"
+			"\x74\x05\x9f\x9d\x93\xa5\x3e\x7f"
+			"\x4e\x5f\x9d\xcb\x09\xc7\x83\xe3"
+			"\x02\x9d\x27\x1f\xef\x85\x05\x8d"
+			"\xec\x55\x88\x0f\x0d\x7c\x4c\xe8"
+			"\xa1\x75\xa0\xd8\x06\x47\x14\xef"
+			"\xaa\x61\xcf\x26\x15\xad\xd8\xa3"
+			"\xaa\x75\xf2\x78\x4a\x5a\x61\xdf"
+			"\x8b\xc7\x04\xbc\xb2\x32\xd2\x7e"
+			"\x42\xee\xb4\x2f\x51\xff\x7b\x2e"
+			"\xd3\x02\xe8\xdc\x5d\x0d\x50\xdc"
+			"\xae\xb7\x46\xf9\xa8\xe6\xd0\x16"
+			"\xcc\xe6\x2c\x81\xc7\xad\xe9\xf0"
+			"\x05\x72\x6d\x3d\x0a\x7a\xa9\x02"
+			"\xac\x82\x93\x6e\xb6\x1c\x28\xfc"
+			"\x44\x12\xfb\x73\x77\xd4\x13\x39"
+			"\x29\x88\x8a\xf3\x5c\xa6\x36\xa0"
+			"\x2a\xed\x7e\xb1\x1d\xd6\x4c\x6b"
+			"\x41\x01\x18\x5d\x5d\x07\x97\xa6"
+			"\x4b\xef\x31\x18\xea\xac\xb1\x84"
+			"\x21\xed\xda\x86",
+		.rlen = 4100,
+		.np	= 2,
+		.tap	= { 4064, 36 },
+	},
+};
+
+static struct cipher_testvec aes_ctr_dec_tv_template[] = {
+	{ /* From RFC 3686 */
+		.key	= "\xae\x68\x52\xf8\x12\x10\x67\xcc"
+			  "\x4b\xf7\xa5\x76\x55\x77\xf3\x9e"
+			  "\x00\x00\x00\x30",
+		.klen	= 20,
+		.iv	= "\x00\x00\x00\x00\x00\x00\x00\x00",
+		.input	= "\xe4\x09\x5d\x4f\xb7\xa7\xb3\x79"
+			  "\x2d\x61\x75\xa3\x26\x13\x11\xb8",
+		.ilen	= 16,
+		.result	= "Single block msg",
+		.rlen	= 16,
+	}, {
+		.key	= "\x7e\x24\x06\x78\x17\xfa\xe0\xd7"
+			  "\x43\xd6\xce\x1f\x32\x53\x91\x63"
+			  "\x00\x6c\xb6\xdb",
+		.klen	= 20,
+		.iv	= "\xc0\x54\x3b\x59\xda\x48\xd9\x0b",
+		.input	= "\x51\x04\xa1\x06\x16\x8a\x72\xd9"
+			  "\x79\x0d\x41\xee\x8e\xda\xd3\x88"
+			  "\xeb\x2e\x1e\xfc\x46\xda\x57\xc8"
+			  "\xfc\xe6\x30\xdf\x91\x41\xbe\x28",
+		.ilen	= 32,
+		.result	= "\x00\x01\x02\x03\x04\x05\x06\x07"
+			  "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+			  "\x10\x11\x12\x13\x14\x15\x16\x17"
+			  "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f",
+		.rlen	= 32,
+	}, {
+		.key	= "\x16\xaf\x5b\x14\x5f\xc9\xf5\x79"
+			  "\xc1\x75\xf9\x3e\x3b\xfb\x0e\xed"
+			  "\x86\x3d\x06\xcc\xfd\xb7\x85\x15"
+			  "\x00\x00\x00\x48",
+		.klen	= 28,
+		.iv	= "\x36\x73\x3c\x14\x7d\x6d\x93\xcb",
+		.input	= "\x4b\x55\x38\x4f\xe2\x59\xc9\xc8"
+			  "\x4e\x79\x35\xa0\x03\xcb\xe9\x28",
+		.ilen	= 16,
+		.result	= "Single block msg",
+		.rlen	= 16,
+	}, {
+		.key	= "\x7c\x5c\xb2\x40\x1b\x3d\xc3\x3c"
+			  "\x19\xe7\x34\x08\x19\xe0\xf6\x9c"
+			  "\x67\x8c\x3d\xb8\xe6\xf6\xa9\x1a"
+			  "\x00\x96\xb0\x3b",
+		.klen	= 28,
+		.iv	= "\x02\x0c\x6e\xad\xc2\xcb\x50\x0d",
+		.input	= "\x45\x32\x43\xfc\x60\x9b\x23\x32"
+			  "\x7e\xdf\xaa\xfa\x71\x31\xcd\x9f"
+			  "\x84\x90\x70\x1c\x5a\xd4\xa7\x9c"
+			  "\xfc\x1f\xe0\xff\x42\xf4\xfb\x00",
+		.ilen	= 32,
+		.result	= "\x00\x01\x02\x03\x04\x05\x06\x07"
+			  "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+			  "\x10\x11\x12\x13\x14\x15\x16\x17"
+			  "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f",
+		.rlen	= 32,
+	}, {
+		.key	= "\x77\x6b\xef\xf2\x85\x1d\xb0\x6f"
+			  "\x4c\x8a\x05\x42\xc8\x69\x6f\x6c"
+			  "\x6a\x81\xaf\x1e\xec\x96\xb4\xd3"
+			  "\x7f\xc1\xd6\x89\xe6\xc1\xc1\x04"
+			  "\x00\x00\x00\x60",
+		.klen	= 36,
+		.iv	= "\xdb\x56\x72\xc9\x7a\xa8\xf0\xb2",
+		.input	= "\x14\x5a\xd0\x1d\xbf\x82\x4e\xc7"
+			  "\x56\x08\x63\xdc\x71\xe3\xe0\xc0",
+		.ilen	= 16,
+		.result	= "Single block msg",
+		.rlen	= 16,
+	}, {
+		.key	= "\xf6\xd6\x6d\x6b\xd5\x2d\x59\xbb"
+			  "\x07\x96\x36\x58\x79\xef\xf8\x86"
+			  "\xc6\x6d\xd5\x1a\x5b\x6a\x99\x74"
+			  "\x4b\x50\x59\x0c\x87\xa2\x38\x84"
+			  "\x00\xfa\xac\x24",
+		.klen	= 36,
+		.iv	= "\xc1\x58\x5e\xf1\x5a\x43\xd8\x75",
+		.input	= "\xf0\x5e\x23\x1b\x38\x94\x61\x2c"
+			  "\x49\xee\x00\x0b\x80\x4e\xb2\xa9"
+			  "\xb8\x30\x6b\x50\x8f\x83\x9d\x6a"
+			  "\x55\x30\x83\x1d\x93\x44\xaf\x1c",
+		.ilen	= 32,
+		.result	= "\x00\x01\x02\x03\x04\x05\x06\x07"
+			  "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+			  "\x10\x11\x12\x13\x14\x15\x16\x17"
+			  "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f",
+		.rlen	= 32,
+	},
+};
+
+static struct aead_testvec aes_gcm_enc_tv_template[] = {
+	{ /* From McGrew & Viega - http://citeseer.ist.psu.edu/656989.html */
+		.key    = zeroed_string,
+		.klen	= 16,
+		.result	= "\x58\xe2\xfc\xce\xfa\x7e\x30\x61"
+			  "\x36\x7f\x1d\x57\xa4\xe7\x45\x5a",
+		.rlen	= 16,
+	}, {
+		.key    = zeroed_string,
+		.klen	= 16,
+		.input  = zeroed_string,
+		.ilen	= 16,
+		.result = "\x03\x88\xda\xce\x60\xb6\xa3\x92"
+			  "\xf3\x28\xc2\xb9\x71\xb2\xfe\x78"
+			  "\xab\x6e\x47\xd4\x2c\xec\x13\xbd"
+			  "\xf5\x3a\x67\xb2\x12\x57\xbd\xdf",
+		.rlen	= 32,
+	}, {
+		.key	= "\xfe\xff\xe9\x92\x86\x65\x73\x1c"
+			  "\x6d\x6a\x8f\x94\x67\x30\x83\x08",
+		.klen	= 16,
+		.iv	= "\xca\xfe\xba\xbe\xfa\xce\xdb\xad"
+			  "\xde\xca\xf8\x88",
+		.input	= "\xd9\x31\x32\x25\xf8\x84\x06\xe5"
+			  "\xa5\x59\x09\xc5\xaf\xf5\x26\x9a"
+			  "\x86\xa7\xa9\x53\x15\x34\xf7\xda"
+			  "\x2e\x4c\x30\x3d\x8a\x31\x8a\x72"
+			  "\x1c\x3c\x0c\x95\x95\x68\x09\x53"
+			  "\x2f\xcf\x0e\x24\x49\xa6\xb5\x25"
+			  "\xb1\x6a\xed\xf5\xaa\x0d\xe6\x57"
+			  "\xba\x63\x7b\x39\x1a\xaf\xd2\x55",
+		.ilen	= 64,
+		.result = "\x42\x83\x1e\xc2\x21\x77\x74\x24"
+			  "\x4b\x72\x21\xb7\x84\xd0\xd4\x9c"
+			  "\xe3\xaa\x21\x2f\x2c\x02\xa4\xe0"
+			  "\x35\xc1\x7e\x23\x29\xac\xa1\x2e"
+			  "\x21\xd5\x14\xb2\x54\x66\x93\x1c"
+			  "\x7d\x8f\x6a\x5a\xac\x84\xaa\x05"
+			  "\x1b\xa3\x0b\x39\x6a\x0a\xac\x97"
+			  "\x3d\x58\xe0\x91\x47\x3f\x59\x85"
+			  "\x4d\x5c\x2a\xf3\x27\xcd\x64\xa6"
+			  "\x2c\xf3\x5a\xbd\x2b\xa6\xfa\xb4",
+		.rlen	= 80,
+	}, {
+		.key	= "\xfe\xff\xe9\x92\x86\x65\x73\x1c"
+			  "\x6d\x6a\x8f\x94\x67\x30\x83\x08",
+		.klen	= 16,
+		.iv	= "\xca\xfe\xba\xbe\xfa\xce\xdb\xad"
+			  "\xde\xca\xf8\x88",
+		.input	= "\xd9\x31\x32\x25\xf8\x84\x06\xe5"
+			  "\xa5\x59\x09\xc5\xaf\xf5\x26\x9a"
+			  "\x86\xa7\xa9\x53\x15\x34\xf7\xda"
+			  "\x2e\x4c\x30\x3d\x8a\x31\x8a\x72"
+			  "\x1c\x3c\x0c\x95\x95\x68\x09\x53"
+			  "\x2f\xcf\x0e\x24\x49\xa6\xb5\x25"
+			  "\xb1\x6a\xed\xf5\xaa\x0d\xe6\x57"
+			  "\xba\x63\x7b\x39",
+		.ilen	= 60,
+		.assoc	= "\xfe\xed\xfa\xce\xde\xad\xbe\xef"
+			  "\xfe\xed\xfa\xce\xde\xad\xbe\xef"
+			  "\xab\xad\xda\xd2",
+		.alen	= 20,
+		.result = "\x42\x83\x1e\xc2\x21\x77\x74\x24"
+			  "\x4b\x72\x21\xb7\x84\xd0\xd4\x9c"
+			  "\xe3\xaa\x21\x2f\x2c\x02\xa4\xe0"
+			  "\x35\xc1\x7e\x23\x29\xac\xa1\x2e"
+			  "\x21\xd5\x14\xb2\x54\x66\x93\x1c"
+			  "\x7d\x8f\x6a\x5a\xac\x84\xaa\x05"
+			  "\x1b\xa3\x0b\x39\x6a\x0a\xac\x97"
+			  "\x3d\x58\xe0\x91"
+			  "\x5b\xc9\x4f\xbc\x32\x21\xa5\xdb"
+			  "\x94\xfa\xe9\x5a\xe7\x12\x1a\x47",
+		.rlen	= 76,
+	}, {
+		.key    = zeroed_string,
+		.klen	= 24,
+		.result	= "\xcd\x33\xb2\x8a\xc7\x73\xf7\x4b"
+			  "\xa0\x0e\xd1\xf3\x12\x57\x24\x35",
+		.rlen	= 16,
+	}, {
+		.key    = zeroed_string,
+		.klen	= 24,
+		.input  = zeroed_string,
+		.ilen	= 16,
+		.result = "\x98\xe7\x24\x7c\x07\xf0\xfe\x41"
+			  "\x1c\x26\x7e\x43\x84\xb0\xf6\x00"
+			  "\x2f\xf5\x8d\x80\x03\x39\x27\xab"
+			  "\x8e\xf4\xd4\x58\x75\x14\xf0\xfb",
+		.rlen	= 32,
+	}, {
+		.key	= "\xfe\xff\xe9\x92\x86\x65\x73\x1c"
+			  "\x6d\x6a\x8f\x94\x67\x30\x83\x08"
+			  "\xfe\xff\xe9\x92\x86\x65\x73\x1c",
+		.klen	= 24,
+		.iv	= "\xca\xfe\xba\xbe\xfa\xce\xdb\xad"
+			  "\xde\xca\xf8\x88",
+		.input	= "\xd9\x31\x32\x25\xf8\x84\x06\xe5"
+			  "\xa5\x59\x09\xc5\xaf\xf5\x26\x9a"
+			  "\x86\xa7\xa9\x53\x15\x34\xf7\xda"
+			  "\x2e\x4c\x30\x3d\x8a\x31\x8a\x72"
+			  "\x1c\x3c\x0c\x95\x95\x68\x09\x53"
+			  "\x2f\xcf\x0e\x24\x49\xa6\xb5\x25"
+			  "\xb1\x6a\xed\xf5\xaa\x0d\xe6\x57"
+			  "\xba\x63\x7b\x39\x1a\xaf\xd2\x55",
+		.ilen	= 64,
+		.result = "\x39\x80\xca\x0b\x3c\x00\xe8\x41"
+			  "\xeb\x06\xfa\xc4\x87\x2a\x27\x57"
+			  "\x85\x9e\x1c\xea\xa6\xef\xd9\x84"
+			  "\x62\x85\x93\xb4\x0c\xa1\xe1\x9c"
+			  "\x7d\x77\x3d\x00\xc1\x44\xc5\x25"
+			  "\xac\x61\x9d\x18\xc8\x4a\x3f\x47"
+			  "\x18\xe2\x44\x8b\x2f\xe3\x24\xd9"
+			  "\xcc\xda\x27\x10\xac\xad\xe2\x56"
+			  "\x99\x24\xa7\xc8\x58\x73\x36\xbf"
+			  "\xb1\x18\x02\x4d\xb8\x67\x4a\x14",
+		.rlen	= 80,
+	}, {
+		.key	= "\xfe\xff\xe9\x92\x86\x65\x73\x1c"
+			  "\x6d\x6a\x8f\x94\x67\x30\x83\x08"
+			  "\xfe\xff\xe9\x92\x86\x65\x73\x1c",
+		.klen	= 24,
+		.iv	= "\xca\xfe\xba\xbe\xfa\xce\xdb\xad"
+			  "\xde\xca\xf8\x88",
+		.input	= "\xd9\x31\x32\x25\xf8\x84\x06\xe5"
+			  "\xa5\x59\x09\xc5\xaf\xf5\x26\x9a"
+			  "\x86\xa7\xa9\x53\x15\x34\xf7\xda"
+			  "\x2e\x4c\x30\x3d\x8a\x31\x8a\x72"
+			  "\x1c\x3c\x0c\x95\x95\x68\x09\x53"
+			  "\x2f\xcf\x0e\x24\x49\xa6\xb5\x25"
+			  "\xb1\x6a\xed\xf5\xaa\x0d\xe6\x57"
+			  "\xba\x63\x7b\x39",
+		.ilen	= 60,
+		.assoc	= "\xfe\xed\xfa\xce\xde\xad\xbe\xef"
+			  "\xfe\xed\xfa\xce\xde\xad\xbe\xef"
+			  "\xab\xad\xda\xd2",
+		.alen	= 20,
+		.result = "\x39\x80\xca\x0b\x3c\x00\xe8\x41"
+			  "\xeb\x06\xfa\xc4\x87\x2a\x27\x57"
+			  "\x85\x9e\x1c\xea\xa6\xef\xd9\x84"
+			  "\x62\x85\x93\xb4\x0c\xa1\xe1\x9c"
+			  "\x7d\x77\x3d\x00\xc1\x44\xc5\x25"
+			  "\xac\x61\x9d\x18\xc8\x4a\x3f\x47"
+			  "\x18\xe2\x44\x8b\x2f\xe3\x24\xd9"
+			  "\xcc\xda\x27\x10"
+			  "\x25\x19\x49\x8e\x80\xf1\x47\x8f"
+			  "\x37\xba\x55\xbd\x6d\x27\x61\x8c",
+		.rlen	= 76,
+		.np	= 2,
+		.tap	= { 32, 28 },
+		.anp	= 2,
+		.atap	= { 8, 12 }
+	}, {
+		.key    = zeroed_string,
+		.klen	= 32,
+		.result	= "\x53\x0f\x8a\xfb\xc7\x45\x36\xb9"
+			  "\xa9\x63\xb4\xf1\xc4\xcb\x73\x8b",
+		.rlen	= 16,
+	}
+};
+
+static struct aead_testvec aes_gcm_dec_tv_template[] = {
+	{ /* From McGrew & Viega - http://citeseer.ist.psu.edu/656989.html */
+		.key    = zeroed_string,
+		.klen	= 32,
+		.input	= "\xce\xa7\x40\x3d\x4d\x60\x6b\x6e"
+			  "\x07\x4e\xc5\xd3\xba\xf3\x9d\x18"
+			  "\xd0\xd1\xc8\xa7\x99\x99\x6b\xf0"
+			  "\x26\x5b\x98\xb5\xd4\x8a\xb9\x19",
+		.ilen	= 32,
+		.result  = zeroed_string,
+		.rlen	= 16,
+	}, {
+		.key	= "\xfe\xff\xe9\x92\x86\x65\x73\x1c"
+			  "\x6d\x6a\x8f\x94\x67\x30\x83\x08"
+			  "\xfe\xff\xe9\x92\x86\x65\x73\x1c"
+			  "\x6d\x6a\x8f\x94\x67\x30\x83\x08",
+		.klen	= 32,
+		.iv	= "\xca\xfe\xba\xbe\xfa\xce\xdb\xad"
+			  "\xde\xca\xf8\x88",
+		.input	= "\x52\x2d\xc1\xf0\x99\x56\x7d\x07"
+			  "\xf4\x7f\x37\xa3\x2a\x84\x42\x7d"
+			  "\x64\x3a\x8c\xdc\xbf\xe5\xc0\xc9"
+			  "\x75\x98\xa2\xbd\x25\x55\xd1\xaa"
+			  "\x8c\xb0\x8e\x48\x59\x0d\xbb\x3d"
+			  "\xa7\xb0\x8b\x10\x56\x82\x88\x38"
+			  "\xc5\xf6\x1e\x63\x93\xba\x7a\x0a"
+			  "\xbc\xc9\xf6\x62\x89\x80\x15\xad"
+			  "\xb0\x94\xda\xc5\xd9\x34\x71\xbd"
+			  "\xec\x1a\x50\x22\x70\xe3\xcc\x6c",
+		.ilen	= 80,
+		.result = "\xd9\x31\x32\x25\xf8\x84\x06\xe5"
+			  "\xa5\x59\x09\xc5\xaf\xf5\x26\x9a"
+			  "\x86\xa7\xa9\x53\x15\x34\xf7\xda"
+			  "\x2e\x4c\x30\x3d\x8a\x31\x8a\x72"
+			  "\x1c\x3c\x0c\x95\x95\x68\x09\x53"
+			  "\x2f\xcf\x0e\x24\x49\xa6\xb5\x25"
+			  "\xb1\x6a\xed\xf5\xaa\x0d\xe6\x57"
+			  "\xba\x63\x7b\x39\x1a\xaf\xd2\x55",
+		.rlen	= 64,
+	}, {
+		.key	= "\xfe\xff\xe9\x92\x86\x65\x73\x1c"
+			  "\x6d\x6a\x8f\x94\x67\x30\x83\x08"
+			  "\xfe\xff\xe9\x92\x86\x65\x73\x1c"
+			  "\x6d\x6a\x8f\x94\x67\x30\x83\x08",
+		.klen	= 32,
+		.iv	= "\xca\xfe\xba\xbe\xfa\xce\xdb\xad"
+			  "\xde\xca\xf8\x88",
+		.input	= "\x52\x2d\xc1\xf0\x99\x56\x7d\x07"
+			  "\xf4\x7f\x37\xa3\x2a\x84\x42\x7d"
+			  "\x64\x3a\x8c\xdc\xbf\xe5\xc0\xc9"
+			  "\x75\x98\xa2\xbd\x25\x55\xd1\xaa"
+			  "\x8c\xb0\x8e\x48\x59\x0d\xbb\x3d"
+			  "\xa7\xb0\x8b\x10\x56\x82\x88\x38"
+			  "\xc5\xf6\x1e\x63\x93\xba\x7a\x0a"
+			  "\xbc\xc9\xf6\x62"
+			  "\x76\xfc\x6e\xce\x0f\x4e\x17\x68"
+			  "\xcd\xdf\x88\x53\xbb\x2d\x55\x1b",
+		.ilen	= 76,
+		.assoc	= "\xfe\xed\xfa\xce\xde\xad\xbe\xef"
+			  "\xfe\xed\xfa\xce\xde\xad\xbe\xef"
+			  "\xab\xad\xda\xd2",
+		.alen	= 20,
+		.result = "\xd9\x31\x32\x25\xf8\x84\x06\xe5"
+			  "\xa5\x59\x09\xc5\xaf\xf5\x26\x9a"
+			  "\x86\xa7\xa9\x53\x15\x34\xf7\xda"
+			  "\x2e\x4c\x30\x3d\x8a\x31\x8a\x72"
+			  "\x1c\x3c\x0c\x95\x95\x68\x09\x53"
+			  "\x2f\xcf\x0e\x24\x49\xa6\xb5\x25"
+			  "\xb1\x6a\xed\xf5\xaa\x0d\xe6\x57"
+			  "\xba\x63\x7b\x39",
+		.rlen	= 60,
+		.np     = 2,
+		.tap    = { 48, 28 },
+		.anp	= 3,
+		.atap	= { 8, 8, 4 }
+	}, {
+		.key	= "\xfe\xff\xe9\x92\x86\x65\x73\x1c"
+			  "\x6d\x6a\x8f\x94\x67\x30\x83\x08",
+		.klen	= 16,
+		.iv	= "\xca\xfe\xba\xbe\xfa\xce\xdb\xad"
+			  "\xde\xca\xf8\x88",
+		.input	= "\x42\x83\x1e\xc2\x21\x77\x74\x24"
+			  "\x4b\x72\x21\xb7\x84\xd0\xd4\x9c"
+			  "\xe3\xaa\x21\x2f\x2c\x02\xa4\xe0"
+			  "\x35\xc1\x7e\x23\x29\xac\xa1\x2e"
+			  "\x21\xd5\x14\xb2\x54\x66\x93\x1c"
+			  "\x7d\x8f\x6a\x5a\xac\x84\xaa\x05"
+			  "\x1b\xa3\x0b\x39\x6a\x0a\xac\x97"
+			  "\x3d\x58\xe0\x91\x47\x3f\x59\x85"
+			  "\x4d\x5c\x2a\xf3\x27\xcd\x64\xa6"
+			  "\x2c\xf3\x5a\xbd\x2b\xa6\xfa\xb4",
+		.ilen	= 80,
+		.result = "\xd9\x31\x32\x25\xf8\x84\x06\xe5"
+			  "\xa5\x59\x09\xc5\xaf\xf5\x26\x9a"
+			  "\x86\xa7\xa9\x53\x15\x34\xf7\xda"
+			  "\x2e\x4c\x30\x3d\x8a\x31\x8a\x72"
+			  "\x1c\x3c\x0c\x95\x95\x68\x09\x53"
+			  "\x2f\xcf\x0e\x24\x49\xa6\xb5\x25"
+			  "\xb1\x6a\xed\xf5\xaa\x0d\xe6\x57"
+			  "\xba\x63\x7b\x39\x1a\xaf\xd2\x55",
+		.rlen	= 64,
+	}, {
+		.key	= "\xfe\xff\xe9\x92\x86\x65\x73\x1c"
+			  "\x6d\x6a\x8f\x94\x67\x30\x83\x08",
+		.klen	= 16,
+		.iv	= "\xca\xfe\xba\xbe\xfa\xce\xdb\xad"
+			  "\xde\xca\xf8\x88",
+		.input	= "\x42\x83\x1e\xc2\x21\x77\x74\x24"
+			  "\x4b\x72\x21\xb7\x84\xd0\xd4\x9c"
+			  "\xe3\xaa\x21\x2f\x2c\x02\xa4\xe0"
+			  "\x35\xc1\x7e\x23\x29\xac\xa1\x2e"
+			  "\x21\xd5\x14\xb2\x54\x66\x93\x1c"
+			  "\x7d\x8f\x6a\x5a\xac\x84\xaa\x05"
+			  "\x1b\xa3\x0b\x39\x6a\x0a\xac\x97"
+			  "\x3d\x58\xe0\x91"
+			  "\x5b\xc9\x4f\xbc\x32\x21\xa5\xdb"
+			  "\x94\xfa\xe9\x5a\xe7\x12\x1a\x47",
+		.ilen	= 76,
+		.assoc	= "\xfe\xed\xfa\xce\xde\xad\xbe\xef"
+			  "\xfe\xed\xfa\xce\xde\xad\xbe\xef"
+			  "\xab\xad\xda\xd2",
+		.alen	= 20,
+		.result = "\xd9\x31\x32\x25\xf8\x84\x06\xe5"
+			  "\xa5\x59\x09\xc5\xaf\xf5\x26\x9a"
+			  "\x86\xa7\xa9\x53\x15\x34\xf7\xda"
+			  "\x2e\x4c\x30\x3d\x8a\x31\x8a\x72"
+			  "\x1c\x3c\x0c\x95\x95\x68\x09\x53"
+			  "\x2f\xcf\x0e\x24\x49\xa6\xb5\x25"
+			  "\xb1\x6a\xed\xf5\xaa\x0d\xe6\x57"
+			  "\xba\x63\x7b\x39",
+		.rlen	= 60,
+	}, {
+		.key    = zeroed_string,
+		.klen	= 24,
+		.input	= "\x98\xe7\x24\x7c\x07\xf0\xfe\x41"
+			  "\x1c\x26\x7e\x43\x84\xb0\xf6\x00"
+			  "\x2f\xf5\x8d\x80\x03\x39\x27\xab"
+			  "\x8e\xf4\xd4\x58\x75\x14\xf0\xfb",
+		.ilen	= 32,
+		.result  = zeroed_string,
+		.rlen	= 16,
+	}, {
+		.key	= "\xfe\xff\xe9\x92\x86\x65\x73\x1c"
+			  "\x6d\x6a\x8f\x94\x67\x30\x83\x08"
+			  "\xfe\xff\xe9\x92\x86\x65\x73\x1c",
+		.klen	= 24,
+		.iv	= "\xca\xfe\xba\xbe\xfa\xce\xdb\xad"
+			  "\xde\xca\xf8\x88",
+		.input	= "\x39\x80\xca\x0b\x3c\x00\xe8\x41"
+			  "\xeb\x06\xfa\xc4\x87\x2a\x27\x57"
+			  "\x85\x9e\x1c\xea\xa6\xef\xd9\x84"
+			  "\x62\x85\x93\xb4\x0c\xa1\xe1\x9c"
+			  "\x7d\x77\x3d\x00\xc1\x44\xc5\x25"
+			  "\xac\x61\x9d\x18\xc8\x4a\x3f\x47"
+			  "\x18\xe2\x44\x8b\x2f\xe3\x24\xd9"
+			  "\xcc\xda\x27\x10\xac\xad\xe2\x56"
+			  "\x99\x24\xa7\xc8\x58\x73\x36\xbf"
+			  "\xb1\x18\x02\x4d\xb8\x67\x4a\x14",
+		.ilen	= 80,
+		.result = "\xd9\x31\x32\x25\xf8\x84\x06\xe5"
+			  "\xa5\x59\x09\xc5\xaf\xf5\x26\x9a"
+			  "\x86\xa7\xa9\x53\x15\x34\xf7\xda"
+			  "\x2e\x4c\x30\x3d\x8a\x31\x8a\x72"
+			  "\x1c\x3c\x0c\x95\x95\x68\x09\x53"
+			  "\x2f\xcf\x0e\x24\x49\xa6\xb5\x25"
+			  "\xb1\x6a\xed\xf5\xaa\x0d\xe6\x57"
+			  "\xba\x63\x7b\x39\x1a\xaf\xd2\x55",
+		.rlen	= 64,
+	}, {
+		.key	= "\xfe\xff\xe9\x92\x86\x65\x73\x1c"
+			  "\x6d\x6a\x8f\x94\x67\x30\x83\x08"
+			  "\xfe\xff\xe9\x92\x86\x65\x73\x1c",
+		.klen	= 24,
+		.iv	= "\xca\xfe\xba\xbe\xfa\xce\xdb\xad"
+			  "\xde\xca\xf8\x88",
+		.input	= "\x39\x80\xca\x0b\x3c\x00\xe8\x41"
+			  "\xeb\x06\xfa\xc4\x87\x2a\x27\x57"
+			  "\x85\x9e\x1c\xea\xa6\xef\xd9\x84"
+			  "\x62\x85\x93\xb4\x0c\xa1\xe1\x9c"
+			  "\x7d\x77\x3d\x00\xc1\x44\xc5\x25"
+			  "\xac\x61\x9d\x18\xc8\x4a\x3f\x47"
+			  "\x18\xe2\x44\x8b\x2f\xe3\x24\xd9"
+			  "\xcc\xda\x27\x10"
+			  "\x25\x19\x49\x8e\x80\xf1\x47\x8f"
+			  "\x37\xba\x55\xbd\x6d\x27\x61\x8c",
+		.ilen	= 76,
+		.assoc	= "\xfe\xed\xfa\xce\xde\xad\xbe\xef"
+			  "\xfe\xed\xfa\xce\xde\xad\xbe\xef"
+			  "\xab\xad\xda\xd2",
+		.alen	= 20,
+		.result = "\xd9\x31\x32\x25\xf8\x84\x06\xe5"
+			  "\xa5\x59\x09\xc5\xaf\xf5\x26\x9a"
+			  "\x86\xa7\xa9\x53\x15\x34\xf7\xda"
+			  "\x2e\x4c\x30\x3d\x8a\x31\x8a\x72"
+			  "\x1c\x3c\x0c\x95\x95\x68\x09\x53"
+			  "\x2f\xcf\x0e\x24\x49\xa6\xb5\x25"
+			  "\xb1\x6a\xed\xf5\xaa\x0d\xe6\x57"
+			  "\xba\x63\x7b\x39",
+		.rlen	= 60,
+	}
+};
+
+static struct aead_testvec aes_ccm_enc_tv_template[] = {
+	{ /* From RFC 3610 */
+		.key	= "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7"
+			  "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf",
+		.klen	= 16,
+		.iv	= "\x01\x00\x00\x00\x03\x02\x01\x00"
+			  "\xa0\xa1\xa2\xa3\xa4\xa5\x00\x00",
+		.assoc	= "\x00\x01\x02\x03\x04\x05\x06\x07",
+		.alen	= 8,
+		.input	= "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+			  "\x10\x11\x12\x13\x14\x15\x16\x17"
+			  "\x18\x19\x1a\x1b\x1c\x1d\x1e",
+		.ilen	= 23,
+		.result	= "\x58\x8c\x97\x9a\x61\xc6\x63\xd2"
+			  "\xf0\x66\xd0\xc2\xc0\xf9\x89\x80"
+			  "\x6d\x5f\x6b\x61\xda\xc3\x84\x17"
+			  "\xe8\xd1\x2c\xfd\xf9\x26\xe0",
+		.rlen	= 31,
+	}, {
+		.key	= "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7"
+			  "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf",
+		.klen	= 16,
+		.iv	= "\x01\x00\x00\x00\x07\x06\x05\x04"
+			  "\xa0\xa1\xa2\xa3\xa4\xa5\x00\x00",
+		.assoc	= "\x00\x01\x02\x03\x04\x05\x06\x07"
+			  "\x08\x09\x0a\x0b",
+		.alen	= 12,
+		.input	= "\x0c\x0d\x0e\x0f\x10\x11\x12\x13"
+			  "\x14\x15\x16\x17\x18\x19\x1a\x1b"
+			  "\x1c\x1d\x1e\x1f",
+		.ilen	= 20,
+		.result	= "\xdc\xf1\xfb\x7b\x5d\x9e\x23\xfb"
+			  "\x9d\x4e\x13\x12\x53\x65\x8a\xd8"
+			  "\x6e\xbd\xca\x3e\x51\xe8\x3f\x07"
+			  "\x7d\x9c\x2d\x93",
+		.rlen	= 28,
+	}, {
+		.key	= "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7"
+			  "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf",
+		.klen	= 16,
+		.iv	= "\x01\x00\x00\x00\x0b\x0a\x09\x08"
+			  "\xa0\xa1\xa2\xa3\xa4\xa5\x00\x00",
+		.assoc	= "\x00\x01\x02\x03\x04\x05\x06\x07",
+		.alen	= 8,
+		.input	= "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+			  "\x10\x11\x12\x13\x14\x15\x16\x17"
+			  "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
+			  "\x20",
+		.ilen	= 25,
+		.result	= "\x82\x53\x1a\x60\xcc\x24\x94\x5a"
+			  "\x4b\x82\x79\x18\x1a\xb5\xc8\x4d"
+			  "\xf2\x1c\xe7\xf9\xb7\x3f\x42\xe1"
+			  "\x97\xea\x9c\x07\xe5\x6b\x5e\xb1"
+			  "\x7e\x5f\x4e",
+		.rlen	= 35,
+	}, {
+		.key	= "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7"
+			  "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf",
+		.klen	= 16,
+		.iv	= "\x01\x00\x00\x00\x0c\x0b\x0a\x09"
+			  "\xa0\xa1\xa2\xa3\xa4\xa5\x00\x00",
+		.assoc	= "\x00\x01\x02\x03\x04\x05\x06\x07"
+			  "\x08\x09\x0a\x0b",
+		.alen	= 12,
+		.input	= "\x0c\x0d\x0e\x0f\x10\x11\x12\x13"
+			  "\x14\x15\x16\x17\x18\x19\x1a\x1b"
+			  "\x1c\x1d\x1e",
+		.ilen	= 19,
+		.result	= "\x07\x34\x25\x94\x15\x77\x85\x15"
+			  "\x2b\x07\x40\x98\x33\x0a\xbb\x14"
+			  "\x1b\x94\x7b\x56\x6a\xa9\x40\x6b"
+			  "\x4d\x99\x99\x88\xdd",
+		.rlen	= 29,
+	}, {
+		.key	= "\xd7\x82\x8d\x13\xb2\xb0\xbd\xc3"
+			  "\x25\xa7\x62\x36\xdf\x93\xcc\x6b",
+		.klen	= 16,
+		.iv	= "\x01\x00\x33\x56\x8e\xf7\xb2\x63"
+			  "\x3c\x96\x96\x76\x6c\xfa\x00\x00",
+		.assoc	= "\x63\x01\x8f\x76\xdc\x8a\x1b\xcb",
+		.alen	= 8,
+		.input	= "\x90\x20\xea\x6f\x91\xbd\xd8\x5a"
+			  "\xfa\x00\x39\xba\x4b\xaf\xf9\xbf"
+			  "\xb7\x9c\x70\x28\x94\x9c\xd0\xec",
+		.ilen	= 24,
+		.result	= "\x4c\xcb\x1e\x7c\xa9\x81\xbe\xfa"
+			  "\xa0\x72\x6c\x55\xd3\x78\x06\x12"
+			  "\x98\xc8\x5c\x92\x81\x4a\xbc\x33"
+			  "\xc5\x2e\xe8\x1d\x7d\x77\xc0\x8a",
+		.rlen	= 32,
+	}, {
+		.key	= "\xd7\x82\x8d\x13\xb2\xb0\xbd\xc3"
+			  "\x25\xa7\x62\x36\xdf\x93\xcc\x6b",
+		.klen	= 16,
+		.iv	= "\x01\x00\xd5\x60\x91\x2d\x3f\x70"
+			  "\x3c\x96\x96\x76\x6c\xfa\x00\x00",
+		.assoc	= "\xcd\x90\x44\xd2\xb7\x1f\xdb\x81"
+			  "\x20\xea\x60\xc0",
+		.alen	= 12,
+		.input	= "\x64\x35\xac\xba\xfb\x11\xa8\x2e"
+			  "\x2f\x07\x1d\x7c\xa4\xa5\xeb\xd9"
+			  "\x3a\x80\x3b\xa8\x7f",
+		.ilen	= 21,
+		.result	= "\x00\x97\x69\xec\xab\xdf\x48\x62"
+			  "\x55\x94\xc5\x92\x51\xe6\x03\x57"
+			  "\x22\x67\x5e\x04\xc8\x47\x09\x9e"
+			  "\x5a\xe0\x70\x45\x51",
+		.rlen	= 29,
+	}, {
+		.key	= "\xd7\x82\x8d\x13\xb2\xb0\xbd\xc3"
+			  "\x25\xa7\x62\x36\xdf\x93\xcc\x6b",
+		.klen	= 16,
+		.iv	= "\x01\x00\x42\xff\xf8\xf1\x95\x1c"
+			  "\x3c\x96\x96\x76\x6c\xfa\x00\x00",
+		.assoc	= "\xd8\x5b\xc7\xe6\x9f\x94\x4f\xb8",
+		.alen	= 8,
+		.input	= "\x8a\x19\xb9\x50\xbc\xf7\x1a\x01"
+			  "\x8e\x5e\x67\x01\xc9\x17\x87\x65"
+			  "\x98\x09\xd6\x7d\xbe\xdd\x18",
+		.ilen	= 23,
+		.result	= "\xbc\x21\x8d\xaa\x94\x74\x27\xb6"
+			  "\xdb\x38\x6a\x99\xac\x1a\xef\x23"
+			  "\xad\xe0\xb5\x29\x39\xcb\x6a\x63"
+			  "\x7c\xf9\xbe\xc2\x40\x88\x97\xc6"
+			  "\xba",
+		.rlen	= 33,
+	},
+};
+
+static struct aead_testvec aes_ccm_dec_tv_template[] = {
+	{ /* From RFC 3610 */
+		.key	= "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7"
+			  "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf",
+		.klen	= 16,
+		.iv	= "\x01\x00\x00\x00\x03\x02\x01\x00"
+			  "\xa0\xa1\xa2\xa3\xa4\xa5\x00\x00",
+		.assoc	= "\x00\x01\x02\x03\x04\x05\x06\x07",
+		.alen	= 8,
+		.input	= "\x58\x8c\x97\x9a\x61\xc6\x63\xd2"
+			  "\xf0\x66\xd0\xc2\xc0\xf9\x89\x80"
+			  "\x6d\x5f\x6b\x61\xda\xc3\x84\x17"
+			  "\xe8\xd1\x2c\xfd\xf9\x26\xe0",
+		.ilen	= 31,
+		.result	= "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+			  "\x10\x11\x12\x13\x14\x15\x16\x17"
+			  "\x18\x19\x1a\x1b\x1c\x1d\x1e",
+		.rlen	= 23,
+	}, {
+		.key	= "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7"
+			  "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf",
+		.klen	= 16,
+		.iv	= "\x01\x00\x00\x00\x07\x06\x05\x04"
+			  "\xa0\xa1\xa2\xa3\xa4\xa5\x00\x00",
+		.assoc	= "\x00\x01\x02\x03\x04\x05\x06\x07"
+			  "\x08\x09\x0a\x0b",
+		.alen	= 12,
+		.input	= "\xdc\xf1\xfb\x7b\x5d\x9e\x23\xfb"
+			  "\x9d\x4e\x13\x12\x53\x65\x8a\xd8"
+			  "\x6e\xbd\xca\x3e\x51\xe8\x3f\x07"
+			  "\x7d\x9c\x2d\x93",
+		.ilen	= 28,
+		.result	= "\x0c\x0d\x0e\x0f\x10\x11\x12\x13"
+			  "\x14\x15\x16\x17\x18\x19\x1a\x1b"
+			  "\x1c\x1d\x1e\x1f",
+		.rlen	= 20,
+	}, {
+		.key	= "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7"
+			  "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf",
+		.klen	= 16,
+		.iv	= "\x01\x00\x00\x00\x0b\x0a\x09\x08"
+			  "\xa0\xa1\xa2\xa3\xa4\xa5\x00\x00",
+		.assoc	= "\x00\x01\x02\x03\x04\x05\x06\x07",
+		.alen	= 8,
+		.input	= "\x82\x53\x1a\x60\xcc\x24\x94\x5a"
+			  "\x4b\x82\x79\x18\x1a\xb5\xc8\x4d"
+			  "\xf2\x1c\xe7\xf9\xb7\x3f\x42\xe1"
+			  "\x97\xea\x9c\x07\xe5\x6b\x5e\xb1"
+			  "\x7e\x5f\x4e",
+		.ilen	= 35,
+		.result	= "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+			  "\x10\x11\x12\x13\x14\x15\x16\x17"
+			  "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
+			  "\x20",
+		.rlen	= 25,
+	}, {
+		.key	= "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7"
+			  "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf",
+		.klen	= 16,
+		.iv	= "\x01\x00\x00\x00\x0c\x0b\x0a\x09"
+			  "\xa0\xa1\xa2\xa3\xa4\xa5\x00\x00",
+		.assoc	= "\x00\x01\x02\x03\x04\x05\x06\x07"
+			  "\x08\x09\x0a\x0b",
+		.alen	= 12,
+		.input	= "\x07\x34\x25\x94\x15\x77\x85\x15"
+			  "\x2b\x07\x40\x98\x33\x0a\xbb\x14"
+			  "\x1b\x94\x7b\x56\x6a\xa9\x40\x6b"
+			  "\x4d\x99\x99\x88\xdd",
+		.ilen	= 29,
+		.result	= "\x0c\x0d\x0e\x0f\x10\x11\x12\x13"
+			  "\x14\x15\x16\x17\x18\x19\x1a\x1b"
+			  "\x1c\x1d\x1e",
+		.rlen	= 19,
+	}, {
+		.key	= "\xd7\x82\x8d\x13\xb2\xb0\xbd\xc3"
+			  "\x25\xa7\x62\x36\xdf\x93\xcc\x6b",
+		.klen	= 16,
+		.iv	= "\x01\x00\x33\x56\x8e\xf7\xb2\x63"
+			  "\x3c\x96\x96\x76\x6c\xfa\x00\x00",
+		.assoc	= "\x63\x01\x8f\x76\xdc\x8a\x1b\xcb",
+		.alen	= 8,
+		.input	= "\x4c\xcb\x1e\x7c\xa9\x81\xbe\xfa"
+			  "\xa0\x72\x6c\x55\xd3\x78\x06\x12"
+			  "\x98\xc8\x5c\x92\x81\x4a\xbc\x33"
+			  "\xc5\x2e\xe8\x1d\x7d\x77\xc0\x8a",
+		.ilen	= 32,
+		.result	= "\x90\x20\xea\x6f\x91\xbd\xd8\x5a"
+			  "\xfa\x00\x39\xba\x4b\xaf\xf9\xbf"
+			  "\xb7\x9c\x70\x28\x94\x9c\xd0\xec",
+		.rlen	= 24,
+	}, {
+		.key	= "\xd7\x82\x8d\x13\xb2\xb0\xbd\xc3"
+			  "\x25\xa7\x62\x36\xdf\x93\xcc\x6b",
+		.klen	= 16,
+		.iv	= "\x01\x00\xd5\x60\x91\x2d\x3f\x70"
+			  "\x3c\x96\x96\x76\x6c\xfa\x00\x00",
+		.assoc	= "\xcd\x90\x44\xd2\xb7\x1f\xdb\x81"
+			  "\x20\xea\x60\xc0",
+		.alen	= 12,
+		.input	= "\x00\x97\x69\xec\xab\xdf\x48\x62"
+			  "\x55\x94\xc5\x92\x51\xe6\x03\x57"
+			  "\x22\x67\x5e\x04\xc8\x47\x09\x9e"
+			  "\x5a\xe0\x70\x45\x51",
+		.ilen	= 29,
+		.result	= "\x64\x35\xac\xba\xfb\x11\xa8\x2e"
+			  "\x2f\x07\x1d\x7c\xa4\xa5\xeb\xd9"
+			  "\x3a\x80\x3b\xa8\x7f",
+		.rlen	= 21,
+	}, {
+		.key	= "\xd7\x82\x8d\x13\xb2\xb0\xbd\xc3"
+			  "\x25\xa7\x62\x36\xdf\x93\xcc\x6b",
+		.klen	= 16,
+		.iv	= "\x01\x00\x42\xff\xf8\xf1\x95\x1c"
+			  "\x3c\x96\x96\x76\x6c\xfa\x00\x00",
+		.assoc	= "\xd8\x5b\xc7\xe6\x9f\x94\x4f\xb8",
+		.alen	= 8,
+		.input	= "\xbc\x21\x8d\xaa\x94\x74\x27\xb6"
+			  "\xdb\x38\x6a\x99\xac\x1a\xef\x23"
+			  "\xad\xe0\xb5\x29\x39\xcb\x6a\x63"
+			  "\x7c\xf9\xbe\xc2\x40\x88\x97\xc6"
+			  "\xba",
+		.ilen	= 33,
+		.result	= "\x8a\x19\xb9\x50\xbc\xf7\x1a\x01"
+			  "\x8e\x5e\x67\x01\xc9\x17\x87\x65"
+			  "\x98\x09\xd6\x7d\xbe\xdd\x18",
+		.rlen	= 23,
+	},
+};
+
+/* Cast5 test vectors from RFC 2144 */
+#define CAST5_ENC_TEST_VECTORS	3
+#define CAST5_DEC_TEST_VECTORS	3
+
+static struct cipher_testvec cast5_enc_tv_template[] = {
+	{
+		.key	= "\x01\x23\x45\x67\x12\x34\x56\x78"
+			  "\x23\x45\x67\x89\x34\x56\x78\x9a",
+		.klen	= 16,
+		.input	= "\x01\x23\x45\x67\x89\xab\xcd\xef",
+		.ilen	= 8,
+		.result	= "\x23\x8b\x4f\xe5\x84\x7e\x44\xb2",
+		.rlen	= 8,
+	}, {
+		.key	= "\x01\x23\x45\x67\x12\x34\x56\x78"
+			  "\x23\x45",
+		.klen	= 10,
+		.input	= "\x01\x23\x45\x67\x89\xab\xcd\xef",
+		.ilen	= 8,
+		.result	= "\xeb\x6a\x71\x1a\x2c\x02\x27\x1b",
+		.rlen	= 8,
+	}, {
+		.key	= "\x01\x23\x45\x67\x12",
+		.klen	= 5,
+		.input	= "\x01\x23\x45\x67\x89\xab\xcd\xef",
+		.ilen	= 8,
+		.result	= "\x7a\xc8\x16\xd1\x6e\x9b\x30\x2e",
+		.rlen	= 8,
+	},
+};
+
+static struct cipher_testvec cast5_dec_tv_template[] = {
+	{
+		.key	= "\x01\x23\x45\x67\x12\x34\x56\x78"
+			  "\x23\x45\x67\x89\x34\x56\x78\x9a",
+		.klen	= 16,
+		.input	= "\x23\x8b\x4f\xe5\x84\x7e\x44\xb2",
+		.ilen	= 8,
+		.result	= "\x01\x23\x45\x67\x89\xab\xcd\xef",
+		.rlen	= 8,
+	}, {
+		.key	= "\x01\x23\x45\x67\x12\x34\x56\x78"
+			  "\x23\x45",
+		.klen	= 10,
+		.input	= "\xeb\x6a\x71\x1a\x2c\x02\x27\x1b",
+		.ilen	= 8,
+		.result	= "\x01\x23\x45\x67\x89\xab\xcd\xef",
+		.rlen	= 8,
+	}, {
+		.key	= "\x01\x23\x45\x67\x12",
+		.klen	= 5,
+		.input	= "\x7a\xc8\x16\xd1\x6e\x9b\x30\x2e",
+		.ilen	= 8,
+		.result	= "\x01\x23\x45\x67\x89\xab\xcd\xef",
+		.rlen	= 8,
+	},
+};
+
+/*
+ * ARC4 test vectors from OpenSSL
+ */
+#define ARC4_ENC_TEST_VECTORS	7
+#define ARC4_DEC_TEST_VECTORS	7
+
+static struct cipher_testvec arc4_enc_tv_template[] = {
+	{
+		.key	= "\x01\x23\x45\x67\x89\xab\xcd\xef",
+		.klen	= 8,
+		.input	= "\x01\x23\x45\x67\x89\xab\xcd\xef",
+		.ilen	= 8,
+		.result	= "\x75\xb7\x87\x80\x99\xe0\xc5\x96",
+		.rlen	= 8,
+	}, {
+		.key	= "\x01\x23\x45\x67\x89\xab\xcd\xef",
+		.klen	= 8,
+		.input	= "\x00\x00\x00\x00\x00\x00\x00\x00",
+		.ilen	= 8,
+		.result	= "\x74\x94\xc2\xe7\x10\x4b\x08\x79",
+		.rlen	= 8,
+	}, {
+		.key	= "\x00\x00\x00\x00\x00\x00\x00\x00",
+		.klen	= 8,
+		.input	= "\x00\x00\x00\x00\x00\x00\x00\x00",
+		.ilen	= 8,
+		.result	= "\xde\x18\x89\x41\xa3\x37\x5d\x3a",
+		.rlen	= 8,
+	}, {
+		.key	= "\xef\x01\x23\x45",
+		.klen	= 4,
+		.input	= "\x00\x00\x00\x00\x00\x00\x00\x00"
+			  "\x00\x00\x00\x00\x00\x00\x00\x00"
+			  "\x00\x00\x00\x00",
+		.ilen	= 20,
+		.result	= "\xd6\xa1\x41\xa7\xec\x3c\x38\xdf"
+			  "\xbd\x61\x5a\x11\x62\xe1\xc7\xba"
+			  "\x36\xb6\x78\x58",
+		.rlen	= 20,
+	}, {
+		.key	= "\x01\x23\x45\x67\x89\xab\xcd\xef",
+		.klen	= 8,
+		.input	= "\x12\x34\x56\x78\x9A\xBC\xDE\xF0"
+			  "\x12\x34\x56\x78\x9A\xBC\xDE\xF0"
+			  "\x12\x34\x56\x78\x9A\xBC\xDE\xF0"
+			  "\x12\x34\x56\x78",
+		.ilen	= 28,
+		.result	= "\x66\xa0\x94\x9f\x8a\xf7\xd6\x89"
+			  "\x1f\x7f\x83\x2b\xa8\x33\xc0\x0c"
+			  "\x89\x2e\xbe\x30\x14\x3c\xe2\x87"
+			  "\x40\x01\x1e\xcf",
+		.rlen	= 28,
+	}, {
+		.key	= "\xef\x01\x23\x45",
+		.klen	= 4,
+		.input	= "\x00\x00\x00\x00\x00\x00\x00\x00"
+			  "\x00\x00",
+		.ilen	= 10,
+		.result	= "\xd6\xa1\x41\xa7\xec\x3c\x38\xdf"
+			  "\xbd\x61",
+		.rlen	= 10,
+	}, {
+		.key	= "\x01\x23\x45\x67\x89\xAB\xCD\xEF"
+			"\x00\x00\x00\x00\x00\x00\x00\x00",
+		.klen	= 16,
+		.input	= "\x01\x23\x45\x67\x89\xAB\xCD\xEF",
+		.ilen	= 8,
+		.result	= "\x69\x72\x36\x59\x1B\x52\x42\xB1",
+		.rlen	= 8,
+	},
+};
+
+static struct cipher_testvec arc4_dec_tv_template[] = {
+	{
+		.key	= "\x01\x23\x45\x67\x89\xab\xcd\xef",
+		.klen	= 8,
+		.input	= "\x75\xb7\x87\x80\x99\xe0\xc5\x96",
+		.ilen	= 8,
+		.result	= "\x01\x23\x45\x67\x89\xab\xcd\xef",
+		.rlen	= 8,
+	}, {
+		.key	= "\x01\x23\x45\x67\x89\xab\xcd\xef",
+		.klen	= 8,
+		.input	= "\x74\x94\xc2\xe7\x10\x4b\x08\x79",
+		.ilen	= 8,
+		.result	= "\x00\x00\x00\x00\x00\x00\x00\x00",
+		.rlen	= 8,
+	}, {
+		.key	= "\x00\x00\x00\x00\x00\x00\x00\x00",
+		.klen	= 8,
+		.input	= "\xde\x18\x89\x41\xa3\x37\x5d\x3a",
+		.ilen	= 8,
+		.result	= "\x00\x00\x00\x00\x00\x00\x00\x00",
+		.rlen	= 8,
+	}, {
+		.key	= "\xef\x01\x23\x45",
+		.klen	= 4,
+		.input	= "\xd6\xa1\x41\xa7\xec\x3c\x38\xdf"
+			  "\xbd\x61\x5a\x11\x62\xe1\xc7\xba"
+			  "\x36\xb6\x78\x58",
+		.ilen	= 20,
+		.result	= "\x00\x00\x00\x00\x00\x00\x00\x00"
+			  "\x00\x00\x00\x00\x00\x00\x00\x00"
+			  "\x00\x00\x00\x00",
+		.rlen	= 20,
+	}, {
+		.key	= "\x01\x23\x45\x67\x89\xab\xcd\xef",
+		.klen	= 8,
+		.input	= "\x66\xa0\x94\x9f\x8a\xf7\xd6\x89"
+			  "\x1f\x7f\x83\x2b\xa8\x33\xc0\x0c"
+			  "\x89\x2e\xbe\x30\x14\x3c\xe2\x87"
+			  "\x40\x01\x1e\xcf",
+		.ilen	= 28,
+		.result	= "\x12\x34\x56\x78\x9A\xBC\xDE\xF0"
+			  "\x12\x34\x56\x78\x9A\xBC\xDE\xF0"
+			  "\x12\x34\x56\x78\x9A\xBC\xDE\xF0"
+			  "\x12\x34\x56\x78",
+		.rlen	= 28,
+	}, {
+		.key	= "\xef\x01\x23\x45",
+		.klen	= 4,
+		.input	= "\xd6\xa1\x41\xa7\xec\x3c\x38\xdf"
+			  "\xbd\x61",
+		.ilen	= 10,
+		.result	= "\x00\x00\x00\x00\x00\x00\x00\x00"
+			  "\x00\x00",
+		.rlen	= 10,
+	}, {
+		.key	= "\x01\x23\x45\x67\x89\xAB\xCD\xEF"
+			"\x00\x00\x00\x00\x00\x00\x00\x00",
+		.klen	= 16,
+		.input	= "\x69\x72\x36\x59\x1B\x52\x42\xB1",
+		.ilen	= 8,
+		.result	= "\x01\x23\x45\x67\x89\xAB\xCD\xEF",
+		.rlen	= 8,
+	},
+};
+
+/*
+ * TEA test vectors
+ */
+#define TEA_ENC_TEST_VECTORS	4
+#define TEA_DEC_TEST_VECTORS	4
+
+static struct cipher_testvec tea_enc_tv_template[] = {
+	{
+		.key    = zeroed_string,
+		.klen	= 16,
+		.input  = zeroed_string,
+		.ilen	= 8,
+		.result	= "\x0a\x3a\xea\x41\x40\xa9\xba\x94",
+		.rlen	= 8,
+	}, {
+		.key	= "\x2b\x02\x05\x68\x06\x14\x49\x76"
+			  "\x77\x5d\x0e\x26\x6c\x28\x78\x43",
+		.klen	= 16,
+		.input	= "\x74\x65\x73\x74\x20\x6d\x65\x2e",
+		.ilen	= 8,
+		.result	= "\x77\x5d\x2a\x6a\xf6\xce\x92\x09",
+		.rlen	= 8,
+	}, {
+		.key	= "\x09\x65\x43\x11\x66\x44\x39\x25"
+			  "\x51\x3a\x16\x10\x0a\x08\x12\x6e",
+		.klen	= 16,
+		.input	= "\x6c\x6f\x6e\x67\x65\x72\x5f\x74"
+			  "\x65\x73\x74\x5f\x76\x65\x63\x74",
+		.ilen	= 16,
+		.result	= "\xbe\x7a\xbb\x81\x95\x2d\x1f\x1e"
+			  "\xdd\x89\xa1\x25\x04\x21\xdf\x95",
+		.rlen	= 16,
+	}, {
+		.key	= "\x4d\x76\x32\x17\x05\x3f\x75\x2c"
+			  "\x5d\x04\x16\x36\x15\x72\x63\x2f",
+		.klen	= 16,
+		.input	= "\x54\x65\x61\x20\x69\x73\x20\x67"
+			  "\x6f\x6f\x64\x20\x66\x6f\x72\x20"
+			  "\x79\x6f\x75\x21\x21\x21\x20\x72"
+			  "\x65\x61\x6c\x6c\x79\x21\x21\x21",
+		.ilen	= 32,
+		.result	= "\xe0\x4d\x5d\x3c\xb7\x8c\x36\x47"
+			  "\x94\x18\x95\x91\xa9\xfc\x49\xf8"
+			  "\x44\xd1\x2d\xc2\x99\xb8\x08\x2a"
+			  "\x07\x89\x73\xc2\x45\x92\xc6\x90",
+		.rlen	= 32,
+	}
+};
+
+static struct cipher_testvec tea_dec_tv_template[] = {
+	{
+		.key    = zeroed_string,
+		.klen	= 16,
+		.input	= "\x0a\x3a\xea\x41\x40\xa9\xba\x94",
+		.ilen	= 8,
+		.result = zeroed_string,
+		.rlen	= 8,
+	}, {
+		.key	= "\x2b\x02\x05\x68\x06\x14\x49\x76"
+			  "\x77\x5d\x0e\x26\x6c\x28\x78\x43",
+		.klen	= 16,
+		.input	= "\x77\x5d\x2a\x6a\xf6\xce\x92\x09",
+		.ilen	= 8,
+		.result	= "\x74\x65\x73\x74\x20\x6d\x65\x2e",
+		.rlen	= 8,
+	}, {
+		.key	= "\x09\x65\x43\x11\x66\x44\x39\x25"
+			  "\x51\x3a\x16\x10\x0a\x08\x12\x6e",
+		.klen	= 16,
+		.input	= "\xbe\x7a\xbb\x81\x95\x2d\x1f\x1e"
+			  "\xdd\x89\xa1\x25\x04\x21\xdf\x95",
+		.ilen   = 16,
+		.result	= "\x6c\x6f\x6e\x67\x65\x72\x5f\x74"
+			  "\x65\x73\x74\x5f\x76\x65\x63\x74",
+		.rlen	= 16,
+	}, {
+		.key	= "\x4d\x76\x32\x17\x05\x3f\x75\x2c"
+			  "\x5d\x04\x16\x36\x15\x72\x63\x2f",
+		.klen	= 16,
+		.input	= "\xe0\x4d\x5d\x3c\xb7\x8c\x36\x47"
+			  "\x94\x18\x95\x91\xa9\xfc\x49\xf8"
+			  "\x44\xd1\x2d\xc2\x99\xb8\x08\x2a"
+			  "\x07\x89\x73\xc2\x45\x92\xc6\x90",
+		.ilen	= 32,
+		.result	= "\x54\x65\x61\x20\x69\x73\x20\x67"
+			  "\x6f\x6f\x64\x20\x66\x6f\x72\x20"
+			  "\x79\x6f\x75\x21\x21\x21\x20\x72"
+			  "\x65\x61\x6c\x6c\x79\x21\x21\x21",
+		.rlen	= 32,
+	}
+};
+
+/*
+ * XTEA test vectors
+ */
+#define XTEA_ENC_TEST_VECTORS	4
+#define XTEA_DEC_TEST_VECTORS	4
+
+static struct cipher_testvec xtea_enc_tv_template[] = {
+	{
+		.key    = zeroed_string,
+		.klen	= 16,
+		.input  = zeroed_string,
+		.ilen	= 8,
+		.result	= "\xd8\xd4\xe9\xde\xd9\x1e\x13\xf7",
+		.rlen	= 8,
+	}, {
+		.key	= "\x2b\x02\x05\x68\x06\x14\x49\x76"
+			  "\x77\x5d\x0e\x26\x6c\x28\x78\x43",
+		.klen	= 16,
+		.input	= "\x74\x65\x73\x74\x20\x6d\x65\x2e",
+		.ilen	= 8,
+		.result	= "\x94\xeb\xc8\x96\x84\x6a\x49\xa8",
+		.rlen	= 8,
+	}, {
+		.key	= "\x09\x65\x43\x11\x66\x44\x39\x25"
+			  "\x51\x3a\x16\x10\x0a\x08\x12\x6e",
+		.klen	= 16,
+		.input	= "\x6c\x6f\x6e\x67\x65\x72\x5f\x74"
+			  "\x65\x73\x74\x5f\x76\x65\x63\x74",
+		.ilen	= 16,
+		.result	= "\x3e\xce\xae\x22\x60\x56\xa8\x9d"
+			  "\x77\x4d\xd4\xb4\x87\x24\xe3\x9a",
+		.rlen	= 16,
+	}, {
+		.key	= "\x4d\x76\x32\x17\x05\x3f\x75\x2c"
+			  "\x5d\x04\x16\x36\x15\x72\x63\x2f",
+		.klen	= 16,
+		.input	= "\x54\x65\x61\x20\x69\x73\x20\x67"
+			  "\x6f\x6f\x64\x20\x66\x6f\x72\x20"
+			  "\x79\x6f\x75\x21\x21\x21\x20\x72"
+			  "\x65\x61\x6c\x6c\x79\x21\x21\x21",
+		.ilen	= 32,
+		.result	= "\x99\x81\x9f\x5d\x6f\x4b\x31\x3a"
+			  "\x86\xff\x6f\xd0\xe3\x87\x70\x07"
+			  "\x4d\xb8\xcf\xf3\x99\x50\xb3\xd4"
+			  "\x73\xa2\xfa\xc9\x16\x59\x5d\x81",
+		.rlen	= 32,
+	}
+};
+
+static struct cipher_testvec xtea_dec_tv_template[] = {
+	{
+		.key    = zeroed_string,
+		.klen	= 16,
+		.input	= "\xd8\xd4\xe9\xde\xd9\x1e\x13\xf7",
+		.ilen	= 8,
+		.result = zeroed_string,
+		.rlen	= 8,
+	}, {
+		.key	= "\x2b\x02\x05\x68\x06\x14\x49\x76"
+			  "\x77\x5d\x0e\x26\x6c\x28\x78\x43",
+		.klen	= 16,
+		.input	= "\x94\xeb\xc8\x96\x84\x6a\x49\xa8",
+		.ilen	= 8,
+		.result	= "\x74\x65\x73\x74\x20\x6d\x65\x2e",
+		.rlen	= 8,
+	}, {
+		.key	= "\x09\x65\x43\x11\x66\x44\x39\x25"
+			  "\x51\x3a\x16\x10\x0a\x08\x12\x6e",
+		.klen	= 16,
+		.input	= "\x3e\xce\xae\x22\x60\x56\xa8\x9d"
+			  "\x77\x4d\xd4\xb4\x87\x24\xe3\x9a",
+		.ilen	= 16,
+		.result	= "\x6c\x6f\x6e\x67\x65\x72\x5f\x74"
+			  "\x65\x73\x74\x5f\x76\x65\x63\x74",
+		.rlen	= 16,
+	}, {
+		.key	= "\x4d\x76\x32\x17\x05\x3f\x75\x2c"
+			  "\x5d\x04\x16\x36\x15\x72\x63\x2f",
+		.klen	= 16,
+		.input	= "\x99\x81\x9f\x5d\x6f\x4b\x31\x3a"
+			  "\x86\xff\x6f\xd0\xe3\x87\x70\x07"
+			  "\x4d\xb8\xcf\xf3\x99\x50\xb3\xd4"
+			  "\x73\xa2\xfa\xc9\x16\x59\x5d\x81",
+		.ilen	= 32,
+		.result	= "\x54\x65\x61\x20\x69\x73\x20\x67"
+			  "\x6f\x6f\x64\x20\x66\x6f\x72\x20"
+			  "\x79\x6f\x75\x21\x21\x21\x20\x72"
+			  "\x65\x61\x6c\x6c\x79\x21\x21\x21",
+		.rlen	= 32,
+	}
+};
+
+/*
+ * KHAZAD test vectors.
+ */
+#define KHAZAD_ENC_TEST_VECTORS 5
+#define KHAZAD_DEC_TEST_VECTORS 5
+
+static struct cipher_testvec khazad_enc_tv_template[] = {
+	{
+		.key	= "\x80\x00\x00\x00\x00\x00\x00\x00"
+			  "\x00\x00\x00\x00\x00\x00\x00\x00",
+		.klen	= 16,
+		.input	= "\x00\x00\x00\x00\x00\x00\x00\x00",
+		.ilen	= 8,
+		.result	= "\x49\xa4\xce\x32\xac\x19\x0e\x3f",
+		.rlen	= 8,
+	}, {
+		.key	= "\x38\x38\x38\x38\x38\x38\x38\x38"
+			  "\x38\x38\x38\x38\x38\x38\x38\x38",
+		.klen	= 16,
+		.input	= "\x38\x38\x38\x38\x38\x38\x38\x38",
+		.ilen	= 8,
+		.result	= "\x7e\x82\x12\xa1\xd9\x5b\xe4\xf9",
+		.rlen	= 8,
+	}, {
+		.key	= "\xa2\xa2\xa2\xa2\xa2\xa2\xa2\xa2"
+			"\xa2\xa2\xa2\xa2\xa2\xa2\xa2\xa2",
+		.klen	= 16,
+		.input	= "\xa2\xa2\xa2\xa2\xa2\xa2\xa2\xa2",
+		.ilen	= 8,
+		.result	= "\xaa\xbe\xc1\x95\xc5\x94\x1a\x9c",
+		.rlen	= 8,
+	}, {
+		.key	= "\x2f\x2f\x2f\x2f\x2f\x2f\x2f\x2f"
+			"\x2f\x2f\x2f\x2f\x2f\x2f\x2f\x2f",
+		.klen	= 16,
+		.input	= "\x2f\x2f\x2f\x2f\x2f\x2f\x2f\x2f",
+		.ilen	= 8,
+		.result = "\x04\x74\xf5\x70\x50\x16\xd3\xb8",
+		.rlen	= 8,
+	}, {
+		.key	= "\x2f\x2f\x2f\x2f\x2f\x2f\x2f\x2f"
+			"\x2f\x2f\x2f\x2f\x2f\x2f\x2f\x2f",
+		.klen	= 16,
+		.input	= "\x2f\x2f\x2f\x2f\x2f\x2f\x2f\x2f"
+			"\x2f\x2f\x2f\x2f\x2f\x2f\x2f\x2f",
+		.ilen	= 16,
+		.result = "\x04\x74\xf5\x70\x50\x16\xd3\xb8"
+			"\x04\x74\xf5\x70\x50\x16\xd3\xb8",
+		.rlen	= 16,
+	},
+};
+
+static struct cipher_testvec khazad_dec_tv_template[] = {
+	{
+		.key	= "\x80\x00\x00\x00\x00\x00\x00\x00"
+			  "\x00\x00\x00\x00\x00\x00\x00\x00",
+		.klen	= 16,
+		.input	= "\x49\xa4\xce\x32\xac\x19\x0e\x3f",
+		.ilen	= 8,
+		.result	= "\x00\x00\x00\x00\x00\x00\x00\x00",
+		.rlen	= 8,
+	}, {
+		.key	= "\x38\x38\x38\x38\x38\x38\x38\x38"
+			  "\x38\x38\x38\x38\x38\x38\x38\x38",
+		.klen	= 16,
+		.input	= "\x7e\x82\x12\xa1\xd9\x5b\xe4\xf9",
+		.ilen	= 8,
+		.result	= "\x38\x38\x38\x38\x38\x38\x38\x38",
+		.rlen	= 8,
+	}, {
+		.key	= "\xa2\xa2\xa2\xa2\xa2\xa2\xa2\xa2"
+			"\xa2\xa2\xa2\xa2\xa2\xa2\xa2\xa2",
+		.klen	= 16,
+		.input	= "\xaa\xbe\xc1\x95\xc5\x94\x1a\x9c",
+		.ilen	= 8,
+		.result	= "\xa2\xa2\xa2\xa2\xa2\xa2\xa2\xa2",
+		.rlen	= 8,
+	}, {
+		.key	= "\x2f\x2f\x2f\x2f\x2f\x2f\x2f\x2f"
+			"\x2f\x2f\x2f\x2f\x2f\x2f\x2f\x2f",
+		.klen	= 16,
+		.input  = "\x04\x74\xf5\x70\x50\x16\xd3\xb8",
+		.ilen	= 8,
+		.result	= "\x2f\x2f\x2f\x2f\x2f\x2f\x2f\x2f",
+		.rlen	= 8,
+	}, {
+		.key	= "\x2f\x2f\x2f\x2f\x2f\x2f\x2f\x2f"
+			"\x2f\x2f\x2f\x2f\x2f\x2f\x2f\x2f",
+		.klen	= 16,
+		.input  = "\x04\x74\xf5\x70\x50\x16\xd3\xb8"
+			"\x04\x74\xf5\x70\x50\x16\xd3\xb8",
+		.ilen	= 16,
+		.result	= "\x2f\x2f\x2f\x2f\x2f\x2f\x2f\x2f"
+			"\x2f\x2f\x2f\x2f\x2f\x2f\x2f\x2f",
+		.rlen	= 16,
+	},
+};
+
+/*
+ * Anubis test vectors.
+ */
+
+#define ANUBIS_ENC_TEST_VECTORS			5
+#define ANUBIS_DEC_TEST_VECTORS			5
+#define ANUBIS_CBC_ENC_TEST_VECTORS		2
+#define ANUBIS_CBC_DEC_TEST_VECTORS		2
+
+static struct cipher_testvec anubis_enc_tv_template[] = {
+	{
+		.key	= "\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe"
+			  "\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe",
+		.klen	= 16,
+		.input	= "\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe"
+			  "\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe",
+		.ilen	= 16,
+		.result	= "\x6d\xc5\xda\xa2\x26\x7d\x62\x6f"
+			  "\x08\xb7\x52\x8e\x6e\x6e\x86\x90",
+		.rlen	= 16,
+	}, {
+
+		.key	= "\x03\x03\x03\x03\x03\x03\x03\x03"
+			  "\x03\x03\x03\x03\x03\x03\x03\x03"
+			  "\x03\x03\x03\x03",
+		.klen	= 20,
+		.input	= "\x03\x03\x03\x03\x03\x03\x03\x03"
+			  "\x03\x03\x03\x03\x03\x03\x03\x03",
+		.ilen	= 16,
+		.result	= "\xdb\xf1\x42\xf4\xd1\x8a\xc7\x49"
+			  "\x87\x41\x6f\x82\x0a\x98\x64\xae",
+		.rlen	= 16,
+	}, {
+		.key	= "\x24\x24\x24\x24\x24\x24\x24\x24"
+			  "\x24\x24\x24\x24\x24\x24\x24\x24"
+			  "\x24\x24\x24\x24\x24\x24\x24\x24"
+			  "\x24\x24\x24\x24",
+		.klen	= 28,
+		.input	= "\x24\x24\x24\x24\x24\x24\x24\x24"
+			  "\x24\x24\x24\x24\x24\x24\x24\x24",
+		.ilen	= 16,
+		.result	= "\xfd\x1b\x4a\xe3\xbf\xf0\xad\x3d"
+			  "\x06\xd3\x61\x27\xfd\x13\x9e\xde",
+		.rlen	= 16,
+	}, {
+		.key	= "\x25\x25\x25\x25\x25\x25\x25\x25"
+			  "\x25\x25\x25\x25\x25\x25\x25\x25"
+			  "\x25\x25\x25\x25\x25\x25\x25\x25"
+			  "\x25\x25\x25\x25\x25\x25\x25\x25",
+		.klen	= 32,
+		.input	= "\x25\x25\x25\x25\x25\x25\x25\x25"
+			  "\x25\x25\x25\x25\x25\x25\x25\x25",
+		.ilen	= 16,
+		.result	= "\x1a\x91\xfb\x2b\xb7\x78\x6b\xc4"
+			"\x17\xd9\xff\x40\x3b\x0e\xe5\xfe",
+		.rlen	= 16,
+	}, {
+		.key	= "\x35\x35\x35\x35\x35\x35\x35\x35"
+			  "\x35\x35\x35\x35\x35\x35\x35\x35"
+			  "\x35\x35\x35\x35\x35\x35\x35\x35"
+			  "\x35\x35\x35\x35\x35\x35\x35\x35"
+			  "\x35\x35\x35\x35\x35\x35\x35\x35",
+		.klen	= 40,
+		.input	= "\x35\x35\x35\x35\x35\x35\x35\x35"
+			  "\x35\x35\x35\x35\x35\x35\x35\x35",
+		.ilen	= 16,
+		.result = "\xa5\x2c\x85\x6f\x9c\xba\xa0\x97"
+			  "\x9e\xc6\x84\x0f\x17\x21\x07\xee",
+		.rlen	= 16,
+	},
+};
+
+static struct cipher_testvec anubis_dec_tv_template[] = {
+	{
+		.key	= "\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe"
+			  "\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe",
+		.klen	= 16,
+		.input	= "\x6d\xc5\xda\xa2\x26\x7d\x62\x6f"
+			  "\x08\xb7\x52\x8e\x6e\x6e\x86\x90",
+		.ilen	= 16,
+		.result	= "\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe"
+			  "\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe",
+		.rlen	= 16,
+	}, {
+
+		.key	= "\x03\x03\x03\x03\x03\x03\x03\x03"
+			  "\x03\x03\x03\x03\x03\x03\x03\x03"
+			  "\x03\x03\x03\x03",
+		.klen	= 20,
+		.input	= "\xdb\xf1\x42\xf4\xd1\x8a\xc7\x49"
+			  "\x87\x41\x6f\x82\x0a\x98\x64\xae",
+		.ilen	= 16,
+		.result	= "\x03\x03\x03\x03\x03\x03\x03\x03"
+			  "\x03\x03\x03\x03\x03\x03\x03\x03",
+		.rlen	= 16,
+	}, {
+		.key	= "\x24\x24\x24\x24\x24\x24\x24\x24"
+			  "\x24\x24\x24\x24\x24\x24\x24\x24"
+			  "\x24\x24\x24\x24\x24\x24\x24\x24"
+			  "\x24\x24\x24\x24",
+		.klen	= 28,
+		.input	= "\xfd\x1b\x4a\xe3\xbf\xf0\xad\x3d"
+			  "\x06\xd3\x61\x27\xfd\x13\x9e\xde",
+		.ilen	= 16,
+		.result	= "\x24\x24\x24\x24\x24\x24\x24\x24"
+			  "\x24\x24\x24\x24\x24\x24\x24\x24",
+		.rlen	= 16,
+	}, {
+		.key	= "\x25\x25\x25\x25\x25\x25\x25\x25"
+			  "\x25\x25\x25\x25\x25\x25\x25\x25"
+			  "\x25\x25\x25\x25\x25\x25\x25\x25"
+			  "\x25\x25\x25\x25\x25\x25\x25\x25",
+		.klen	= 32,
+		.input	= "\x1a\x91\xfb\x2b\xb7\x78\x6b\xc4"
+			"\x17\xd9\xff\x40\x3b\x0e\xe5\xfe",
+		.ilen	= 16,
+		.result	= "\x25\x25\x25\x25\x25\x25\x25\x25"
+			  "\x25\x25\x25\x25\x25\x25\x25\x25",
+		.rlen	= 16,
+	}, {
+		.key	= "\x35\x35\x35\x35\x35\x35\x35\x35"
+			  "\x35\x35\x35\x35\x35\x35\x35\x35"
+			  "\x35\x35\x35\x35\x35\x35\x35\x35"
+			  "\x35\x35\x35\x35\x35\x35\x35\x35"
+			  "\x35\x35\x35\x35\x35\x35\x35\x35",
+		.input = "\xa5\x2c\x85\x6f\x9c\xba\xa0\x97"
+			 "\x9e\xc6\x84\x0f\x17\x21\x07\xee",
+		.klen	= 40,
+		.ilen	= 16,
+		.result	= "\x35\x35\x35\x35\x35\x35\x35\x35"
+			  "\x35\x35\x35\x35\x35\x35\x35\x35",
+		.rlen	= 16,
+	},
+};
+
+static struct cipher_testvec anubis_cbc_enc_tv_template[] = {
+	{
+		.key	= "\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe"
+			  "\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe",
+		.klen	= 16,
+		.input	= "\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe"
+			  "\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe"
+			  "\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe"
+			  "\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe",
+		.ilen	= 32,
+		.result	= "\x6d\xc5\xda\xa2\x26\x7d\x62\x6f"
+			  "\x08\xb7\x52\x8e\x6e\x6e\x86\x90"
+			  "\x86\xd8\xb5\x6f\x98\x5e\x8a\x66"
+			  "\x4f\x1f\x78\xa1\xbb\x37\xf1\xbe",
+		.rlen	= 32,
+	}, {
+		.key	= "\x35\x35\x35\x35\x35\x35\x35\x35"
+			  "\x35\x35\x35\x35\x35\x35\x35\x35"
+			  "\x35\x35\x35\x35\x35\x35\x35\x35"
+			  "\x35\x35\x35\x35\x35\x35\x35\x35"
+			  "\x35\x35\x35\x35\x35\x35\x35\x35",
+		.klen	= 40,
+		.input	= "\x35\x35\x35\x35\x35\x35\x35\x35"
+			  "\x35\x35\x35\x35\x35\x35\x35\x35"
+			  "\x35\x35\x35\x35\x35\x35\x35\x35"
+			  "\x35\x35\x35\x35\x35\x35\x35\x35",
+		.ilen	= 32,
+		.result = "\xa5\x2c\x85\x6f\x9c\xba\xa0\x97"
+			  "\x9e\xc6\x84\x0f\x17\x21\x07\xee"
+			  "\xa2\xbc\x06\x98\xc6\x4b\xda\x75"
+			  "\x2e\xaa\xbe\x58\xce\x01\x5b\xc7",
+		.rlen	= 32,
+	},
+};
+
+static struct cipher_testvec anubis_cbc_dec_tv_template[] = {
+	{
+		.key	= "\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe"
+			  "\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe",
+		.klen	= 16,
+		.input	= "\x6d\xc5\xda\xa2\x26\x7d\x62\x6f"
+			  "\x08\xb7\x52\x8e\x6e\x6e\x86\x90"
+			  "\x86\xd8\xb5\x6f\x98\x5e\x8a\x66"
+			  "\x4f\x1f\x78\xa1\xbb\x37\xf1\xbe",
+		.ilen	= 32,
+		.result	= "\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe"
+			  "\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe"
+			  "\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe"
+			  "\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe",
+		.rlen	= 32,
+	}, {
+		.key	= "\x35\x35\x35\x35\x35\x35\x35\x35"
+			  "\x35\x35\x35\x35\x35\x35\x35\x35"
+			  "\x35\x35\x35\x35\x35\x35\x35\x35"
+			  "\x35\x35\x35\x35\x35\x35\x35\x35"
+			  "\x35\x35\x35\x35\x35\x35\x35\x35",
+		.klen	= 40,
+		.input = "\xa5\x2c\x85\x6f\x9c\xba\xa0\x97"
+			  "\x9e\xc6\x84\x0f\x17\x21\x07\xee"
+			  "\xa2\xbc\x06\x98\xc6\x4b\xda\x75"
+			  "\x2e\xaa\xbe\x58\xce\x01\x5b\xc7",
+		.ilen	= 32,
+		.result	= "\x35\x35\x35\x35\x35\x35\x35\x35"
+			  "\x35\x35\x35\x35\x35\x35\x35\x35"
+			  "\x35\x35\x35\x35\x35\x35\x35\x35"
+			  "\x35\x35\x35\x35\x35\x35\x35\x35",
+		.rlen	= 32,
+	},
+};
+
+/*
+ * XETA test vectors
+ */
+#define XETA_ENC_TEST_VECTORS	4
+#define XETA_DEC_TEST_VECTORS	4
+
+static struct cipher_testvec xeta_enc_tv_template[] = {
+	{
+		.key    = zeroed_string,
+		.klen	= 16,
+		.input  = zeroed_string,
+		.ilen	= 8,
+		.result	= "\xaa\x22\x96\xe5\x6c\x61\xf3\x45",
+		.rlen	= 8,
+	}, {
+		.key	= "\x2b\x02\x05\x68\x06\x14\x49\x76"
+			  "\x77\x5d\x0e\x26\x6c\x28\x78\x43",
+		.klen	= 16,
+		.input	= "\x74\x65\x73\x74\x20\x6d\x65\x2e",
+		.ilen	= 8,
+		.result	= "\x82\x3e\xeb\x35\xdc\xdd\xd9\xc3",
+		.rlen	= 8,
+	}, {
+		.key	= "\x09\x65\x43\x11\x66\x44\x39\x25"
+			  "\x51\x3a\x16\x10\x0a\x08\x12\x6e",
+		.klen	= 16,
+		.input	= "\x6c\x6f\x6e\x67\x65\x72\x5f\x74"
+			  "\x65\x73\x74\x5f\x76\x65\x63\x74",
+		.ilen	= 16,
+		.result	= "\xe2\x04\xdb\xf2\x89\x85\x9e\xea"
+			  "\x61\x35\xaa\xed\xb5\xcb\x71\x2c",
+		.rlen	= 16,
+	}, {
+		.key	= "\x4d\x76\x32\x17\x05\x3f\x75\x2c"
+			  "\x5d\x04\x16\x36\x15\x72\x63\x2f",
+		.klen	= 16,
+		.input	= "\x54\x65\x61\x20\x69\x73\x20\x67"
+			  "\x6f\x6f\x64\x20\x66\x6f\x72\x20"
+			  "\x79\x6f\x75\x21\x21\x21\x20\x72"
+			  "\x65\x61\x6c\x6c\x79\x21\x21\x21",
+		.ilen	= 32,
+		.result	= "\x0b\x03\xcd\x8a\xbe\x95\xfd\xb1"
+			  "\xc1\x44\x91\x0b\xa5\xc9\x1b\xb4"
+			  "\xa9\xda\x1e\x9e\xb1\x3e\x2a\x8f"
+			  "\xea\xa5\x6a\x85\xd1\xf4\xa8\xa5",
+		.rlen	= 32,
+	}
+};
+
+static struct cipher_testvec xeta_dec_tv_template[] = {
+	{
+		.key    = zeroed_string,
+		.klen	= 16,
+		.input	= "\xaa\x22\x96\xe5\x6c\x61\xf3\x45",
+		.ilen	= 8,
+		.result = zeroed_string,
+		.rlen	= 8,
+	}, {
+		.key	= "\x2b\x02\x05\x68\x06\x14\x49\x76"
+			  "\x77\x5d\x0e\x26\x6c\x28\x78\x43",
+		.klen	= 16,
+		.input	= "\x82\x3e\xeb\x35\xdc\xdd\xd9\xc3",
+		.ilen	= 8,
+		.result	= "\x74\x65\x73\x74\x20\x6d\x65\x2e",
+		.rlen	= 8,
+	}, {
+		.key	= "\x09\x65\x43\x11\x66\x44\x39\x25"
+			  "\x51\x3a\x16\x10\x0a\x08\x12\x6e",
+		.klen	= 16,
+		.input	= "\xe2\x04\xdb\xf2\x89\x85\x9e\xea"
+			  "\x61\x35\xaa\xed\xb5\xcb\x71\x2c",
+		.ilen	= 16,
+		.result	= "\x6c\x6f\x6e\x67\x65\x72\x5f\x74"
+			  "\x65\x73\x74\x5f\x76\x65\x63\x74",
+		.rlen	= 16,
+	}, {
+		.key	= "\x4d\x76\x32\x17\x05\x3f\x75\x2c"
+			  "\x5d\x04\x16\x36\x15\x72\x63\x2f",
+		.klen	= 16,
+		.input	= "\x0b\x03\xcd\x8a\xbe\x95\xfd\xb1"
+			  "\xc1\x44\x91\x0b\xa5\xc9\x1b\xb4"
+			  "\xa9\xda\x1e\x9e\xb1\x3e\x2a\x8f"
+			  "\xea\xa5\x6a\x85\xd1\xf4\xa8\xa5",
+		.ilen	= 32,
+		.result	= "\x54\x65\x61\x20\x69\x73\x20\x67"
+			  "\x6f\x6f\x64\x20\x66\x6f\x72\x20"
+			  "\x79\x6f\x75\x21\x21\x21\x20\x72"
+			  "\x65\x61\x6c\x6c\x79\x21\x21\x21",
+		.rlen	= 32,
+	}
+};
+
+/*
+ * FCrypt test vectors
+ */
+#define FCRYPT_ENC_TEST_VECTORS	ARRAY_SIZE(fcrypt_pcbc_enc_tv_template)
+#define FCRYPT_DEC_TEST_VECTORS	ARRAY_SIZE(fcrypt_pcbc_dec_tv_template)
+
+static struct cipher_testvec fcrypt_pcbc_enc_tv_template[] = {
+	{ /* http://www.openafs.org/pipermail/openafs-devel/2000-December/005320.html */
+		.key	= "\x00\x00\x00\x00\x00\x00\x00\x00",
+		.klen	= 8,
+		.iv	= "\x00\x00\x00\x00\x00\x00\x00\x00",
+		.input	= "\x00\x00\x00\x00\x00\x00\x00\x00",
+		.ilen	= 8,
+		.result	= "\x0E\x09\x00\xC7\x3E\xF7\xED\x41",
+		.rlen	= 8,
+	}, {
+		.key	= "\x11\x44\x77\xAA\xDD\x00\x33\x66",
+		.klen	= 8,
+		.iv	= "\x00\x00\x00\x00\x00\x00\x00\x00",
+		.input	= "\x12\x34\x56\x78\x9A\xBC\xDE\xF0",
+		.ilen	= 8,
+		.result	= "\xD8\xED\x78\x74\x77\xEC\x06\x80",
+		.rlen	= 8,
+	}, { /* From Arla */
+		.key	= "\xf0\xe1\xd2\xc3\xb4\xa5\x96\x87",
+		.klen	= 8,
+		.iv	= "\xfe\xdc\xba\x98\x76\x54\x32\x10",
+		.input	= "The quick brown fox jumps over the lazy dogs.\0\0",
+		.ilen	= 48,
+		.result	= "\x00\xf0\x0e\x11\x75\xe6\x23\x82"
+			  "\xee\xac\x98\x62\x44\x51\xe4\x84"
+			  "\xc3\x59\xd8\xaa\x64\x60\xae\xf7"
+			  "\xd2\xd9\x13\x79\x72\xa3\x45\x03"
+			  "\x23\xb5\x62\xd7\x0c\xf5\x27\xd1"
+			  "\xf8\x91\x3c\xac\x44\x22\x92\xef",
+		.rlen	= 48,
+	}, {
+		.key	= "\xfe\xdc\xba\x98\x76\x54\x32\x10",
+		.klen	= 8,
+		.iv	= "\xf0\xe1\xd2\xc3\xb4\xa5\x96\x87",
+		.input	= "The quick brown fox jumps over the lazy dogs.\0\0",
+		.ilen	= 48,
+		.result	= "\xca\x90\xf5\x9d\xcb\xd4\xd2\x3c"
+			  "\x01\x88\x7f\x3e\x31\x6e\x62\x9d"
+			  "\xd8\xe0\x57\xa3\x06\x3a\x42\x58"
+			  "\x2a\x28\xfe\x72\x52\x2f\xdd\xe0"
+			  "\x19\x89\x09\x1c\x2a\x8e\x8c\x94"
+			  "\xfc\xc7\x68\xe4\x88\xaa\xde\x0f",
+		.rlen	= 48,
+	}, { /* split-page version */
+		.key	= "\xfe\xdc\xba\x98\x76\x54\x32\x10",
+		.klen	= 8,
+		.iv	= "\xf0\xe1\xd2\xc3\xb4\xa5\x96\x87",
+		.input	= "The quick brown fox jumps over the lazy dogs.\0\0",
+		.ilen	= 48,
+		.result	= "\xca\x90\xf5\x9d\xcb\xd4\xd2\x3c"
+			  "\x01\x88\x7f\x3e\x31\x6e\x62\x9d"
+			  "\xd8\xe0\x57\xa3\x06\x3a\x42\x58"
+			  "\x2a\x28\xfe\x72\x52\x2f\xdd\xe0"
+			  "\x19\x89\x09\x1c\x2a\x8e\x8c\x94"
+			  "\xfc\xc7\x68\xe4\x88\xaa\xde\x0f",
+		.rlen	= 48,
+		.np	= 2,
+		.tap	= { 20, 28 },
+	}
+};
+
+static struct cipher_testvec fcrypt_pcbc_dec_tv_template[] = {
+	{ /* http://www.openafs.org/pipermail/openafs-devel/2000-December/005320.html */
+		.key	= "\x00\x00\x00\x00\x00\x00\x00\x00",
+		.klen	= 8,
+		.iv	= "\x00\x00\x00\x00\x00\x00\x00\x00",
+		.input	= "\x0E\x09\x00\xC7\x3E\xF7\xED\x41",
+		.ilen	= 8,
+		.result	= "\x00\x00\x00\x00\x00\x00\x00\x00",
+		.rlen	= 8,
+	}, {
+		.key	= "\x11\x44\x77\xAA\xDD\x00\x33\x66",
+		.klen	= 8,
+		.iv	= "\x00\x00\x00\x00\x00\x00\x00\x00",
+		.input	= "\xD8\xED\x78\x74\x77\xEC\x06\x80",
+		.ilen	= 8,
+		.result	= "\x12\x34\x56\x78\x9A\xBC\xDE\xF0",
+		.rlen	= 8,
+	}, { /* From Arla */
+		.key	= "\xf0\xe1\xd2\xc3\xb4\xa5\x96\x87",
+		.klen	= 8,
+		.iv	= "\xfe\xdc\xba\x98\x76\x54\x32\x10",
+		.input	= "\x00\xf0\x0e\x11\x75\xe6\x23\x82"
+			  "\xee\xac\x98\x62\x44\x51\xe4\x84"
+			  "\xc3\x59\xd8\xaa\x64\x60\xae\xf7"
+			  "\xd2\xd9\x13\x79\x72\xa3\x45\x03"
+			  "\x23\xb5\x62\xd7\x0c\xf5\x27\xd1"
+			  "\xf8\x91\x3c\xac\x44\x22\x92\xef",
+		.ilen	= 48,
+		.result	= "The quick brown fox jumps over the lazy dogs.\0\0",
+		.rlen	= 48,
+	}, {
+		.key	= "\xfe\xdc\xba\x98\x76\x54\x32\x10",
+		.klen	= 8,
+		.iv	= "\xf0\xe1\xd2\xc3\xb4\xa5\x96\x87",
+		.input	= "\xca\x90\xf5\x9d\xcb\xd4\xd2\x3c"
+			  "\x01\x88\x7f\x3e\x31\x6e\x62\x9d"
+			  "\xd8\xe0\x57\xa3\x06\x3a\x42\x58"
+			  "\x2a\x28\xfe\x72\x52\x2f\xdd\xe0"
+			  "\x19\x89\x09\x1c\x2a\x8e\x8c\x94"
+			  "\xfc\xc7\x68\xe4\x88\xaa\xde\x0f",
+		.ilen	= 48,
+		.result	= "The quick brown fox jumps over the lazy dogs.\0\0",
+		.rlen	= 48,
+	}, { /* split-page version */
+		.key	= "\xfe\xdc\xba\x98\x76\x54\x32\x10",
+		.klen	= 8,
+		.iv	= "\xf0\xe1\xd2\xc3\xb4\xa5\x96\x87",
+		.input	= "\xca\x90\xf5\x9d\xcb\xd4\xd2\x3c"
+			  "\x01\x88\x7f\x3e\x31\x6e\x62\x9d"
+			  "\xd8\xe0\x57\xa3\x06\x3a\x42\x58"
+			  "\x2a\x28\xfe\x72\x52\x2f\xdd\xe0"
+			  "\x19\x89\x09\x1c\x2a\x8e\x8c\x94"
+			  "\xfc\xc7\x68\xe4\x88\xaa\xde\x0f",
+		.ilen	= 48,
+		.result	= "The quick brown fox jumps over the lazy dogs.\0\0",
+		.rlen	= 48,
+		.np	= 2,
+		.tap	= { 20, 28 },
+	}
+};
+
+/*
+ * CAMELLIA test vectors.
+ */
+#define CAMELLIA_ENC_TEST_VECTORS 3
+#define CAMELLIA_DEC_TEST_VECTORS 3
+#define CAMELLIA_CBC_ENC_TEST_VECTORS 2
+#define CAMELLIA_CBC_DEC_TEST_VECTORS 2
+
+static struct cipher_testvec camellia_enc_tv_template[] = {
+	{
+		.key	= "\x01\x23\x45\x67\x89\xab\xcd\xef"
+			  "\xfe\xdc\xba\x98\x76\x54\x32\x10",
+		.klen	= 16,
+		.input	= "\x01\x23\x45\x67\x89\xab\xcd\xef"
+			  "\xfe\xdc\xba\x98\x76\x54\x32\x10",
+		.ilen	= 16,
+		.result	= "\x67\x67\x31\x38\x54\x96\x69\x73"
+			  "\x08\x57\x06\x56\x48\xea\xbe\x43",
+		.rlen	= 16,
+	}, {
+		.key	= "\x01\x23\x45\x67\x89\xab\xcd\xef"
+			  "\xfe\xdc\xba\x98\x76\x54\x32\x10"
+			  "\x00\x11\x22\x33\x44\x55\x66\x77",
+		.klen	= 24,
+		.input	= "\x01\x23\x45\x67\x89\xab\xcd\xef"
+			  "\xfe\xdc\xba\x98\x76\x54\x32\x10",
+		.ilen	= 16,
+		.result	= "\xb4\x99\x34\x01\xb3\xe9\x96\xf8"
+			  "\x4e\xe5\xce\xe7\xd7\x9b\x09\xb9",
+		.rlen	= 16,
+	}, {
+		.key	= "\x01\x23\x45\x67\x89\xab\xcd\xef"
+			  "\xfe\xdc\xba\x98\x76\x54\x32\x10"
+			  "\x00\x11\x22\x33\x44\x55\x66\x77"
+			  "\x88\x99\xaa\xbb\xcc\xdd\xee\xff",
+		.klen	= 32,
+		.input	= "\x01\x23\x45\x67\x89\xab\xcd\xef"
+			  "\xfe\xdc\xba\x98\x76\x54\x32\x10",
+		.ilen	= 16,
+		.result	= "\x9a\xcc\x23\x7d\xff\x16\xd7\x6c"
+			  "\x20\xef\x7c\x91\x9e\x3a\x75\x09",
+		.rlen	= 16,
+	},
+};
+
+static struct cipher_testvec camellia_dec_tv_template[] = {
+	{
+		.key	= "\x01\x23\x45\x67\x89\xab\xcd\xef"
+			  "\xfe\xdc\xba\x98\x76\x54\x32\x10",
+		.klen	= 16,
+		.input	= "\x67\x67\x31\x38\x54\x96\x69\x73"
+			  "\x08\x57\x06\x56\x48\xea\xbe\x43",
+		.ilen	= 16,
+		.result	= "\x01\x23\x45\x67\x89\xab\xcd\xef"
+			  "\xfe\xdc\xba\x98\x76\x54\x32\x10",
+		.rlen	= 16,
+	}, {
+		.key	= "\x01\x23\x45\x67\x89\xab\xcd\xef"
+			  "\xfe\xdc\xba\x98\x76\x54\x32\x10"
+			  "\x00\x11\x22\x33\x44\x55\x66\x77",
+		.klen	= 24,
+		.input	= "\xb4\x99\x34\x01\xb3\xe9\x96\xf8"
+			  "\x4e\xe5\xce\xe7\xd7\x9b\x09\xb9",
+		.ilen	= 16,
+		.result	= "\x01\x23\x45\x67\x89\xab\xcd\xef"
+			  "\xfe\xdc\xba\x98\x76\x54\x32\x10",
+		.rlen	= 16,
+	}, {
+		.key	= "\x01\x23\x45\x67\x89\xab\xcd\xef"
+			  "\xfe\xdc\xba\x98\x76\x54\x32\x10"
+			  "\x00\x11\x22\x33\x44\x55\x66\x77"
+			  "\x88\x99\xaa\xbb\xcc\xdd\xee\xff",
+		.klen	= 32,
+		.input	= "\x9a\xcc\x23\x7d\xff\x16\xd7\x6c"
+			  "\x20\xef\x7c\x91\x9e\x3a\x75\x09",
+		.ilen	= 16,
+		.result	= "\x01\x23\x45\x67\x89\xab\xcd\xef"
+			  "\xfe\xdc\xba\x98\x76\x54\x32\x10",
+		.rlen	= 16,
+	},
+};
+
+static struct cipher_testvec camellia_cbc_enc_tv_template[] = {
+	{
+		.key    = "\x06\xa9\x21\x40\x36\xb8\xa1\x5b"
+			  "\x51\x2e\x03\xd5\x34\x12\x00\x06",
+		.klen   = 16,
+		.iv	= "\x3d\xaf\xba\x42\x9d\x9e\xb4\x30"
+			  "\xb4\x22\xda\x80\x2c\x9f\xac\x41",
+		.input	= "Single block msg",
+		.ilen   = 16,
+		.result = "\xea\x32\x12\x76\x3b\x50\x10\xe7"
+			  "\x18\xf6\xfd\x5d\xf6\x8f\x13\x51",
+		.rlen   = 16,
+	}, {
+		.key    = "\xc2\x86\x69\x6d\x88\x7c\x9a\xa0"
+			  "\x61\x1b\xbb\x3e\x20\x25\xa4\x5a",
+		.klen   = 16,
+		.iv     = "\x56\x2e\x17\x99\x6d\x09\x3d\x28"
+			  "\xdd\xb3\xba\x69\x5a\x2e\x6f\x58",
+		.input  = "\x00\x01\x02\x03\x04\x05\x06\x07"
+			  "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+			  "\x10\x11\x12\x13\x14\x15\x16\x17"
+			  "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f",
+		.ilen   = 32,
+		.result = "\xa5\xdf\x6e\x50\xda\x70\x6c\x01"
+			  "\x4a\xab\xf3\xf2\xd6\xfc\x6c\xfd"
+			  "\x19\xb4\x3e\x57\x1c\x02\x5e\xa0"
+			  "\x15\x78\xe0\x5e\xf2\xcb\x87\x16",
+		.rlen   = 32,
+	},
+};
+
+static struct cipher_testvec camellia_cbc_dec_tv_template[] = {
+	{
+		.key    = "\x06\xa9\x21\x40\x36\xb8\xa1\x5b"
+			  "\x51\x2e\x03\xd5\x34\x12\x00\x06",
+		.klen   = 16,
+		.iv	= "\x3d\xaf\xba\x42\x9d\x9e\xb4\x30"
+			  "\xb4\x22\xda\x80\x2c\x9f\xac\x41",
+		.input	= "\xea\x32\x12\x76\x3b\x50\x10\xe7"
+			  "\x18\xf6\xfd\x5d\xf6\x8f\x13\x51",
+		.ilen   = 16,
+		.result = "Single block msg",
+		.rlen   = 16,
+	}, {
+		.key    = "\xc2\x86\x69\x6d\x88\x7c\x9a\xa0"
+			  "\x61\x1b\xbb\x3e\x20\x25\xa4\x5a",
+		.klen   = 16,
+		.iv     = "\x56\x2e\x17\x99\x6d\x09\x3d\x28"
+			  "\xdd\xb3\xba\x69\x5a\x2e\x6f\x58",
+		.input = "\xa5\xdf\x6e\x50\xda\x70\x6c\x01"
+			  "\x4a\xab\xf3\xf2\xd6\xfc\x6c\xfd"
+			  "\x19\xb4\x3e\x57\x1c\x02\x5e\xa0"
+			  "\x15\x78\xe0\x5e\xf2\xcb\x87\x16",
+		.ilen   = 32,
+		.result = "\x00\x01\x02\x03\x04\x05\x06\x07"
+			  "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+			  "\x10\x11\x12\x13\x14\x15\x16\x17"
+			  "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f",
+		.rlen   = 32,
+	},
+};
+
+/*
+ * SEED test vectors
+ */
+#define SEED_ENC_TEST_VECTORS	4
+#define SEED_DEC_TEST_VECTORS	4
+
+static struct cipher_testvec seed_enc_tv_template[] = {
+	{
+		.key    = zeroed_string,
+		.klen	= 16,
+		.input  = "\x00\x01\x02\x03\x04\x05\x06\x07"
+			  "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
+		.ilen	= 16,
+		.result	= "\x5e\xba\xc6\xe0\x05\x4e\x16\x68"
+			  "\x19\xaf\xf1\xcc\x6d\x34\x6c\xdb",
+		.rlen	= 16,
+	}, {
+		.key	= "\x00\x01\x02\x03\x04\x05\x06\x07"
+			  "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
+		.klen	= 16,
+		.input	= zeroed_string,
+		.ilen	= 16,
+		.result	= "\xc1\x1f\x22\xf2\x01\x40\x50\x50"
+			  "\x84\x48\x35\x97\xe4\x37\x0f\x43",
+		.rlen	= 16,
+	}, {
+		.key	= "\x47\x06\x48\x08\x51\xe6\x1b\xe8"
+			  "\x5d\x74\xbf\xb3\xfd\x95\x61\x85",
+		.klen	= 16,
+		.input	= "\x83\xa2\xf8\xa2\x88\x64\x1f\xb9"
+			  "\xa4\xe9\xa5\xcc\x2f\x13\x1c\x7d",
+		.ilen	= 16,
+		.result	= "\xee\x54\xd1\x3e\xbc\xae\x70\x6d"
+			  "\x22\x6b\xc3\x14\x2c\xd4\x0d\x4a",
+		.rlen	= 16,
+	}, {
+		.key	= "\x28\xdb\xc3\xbc\x49\xff\xd8\x7d"
+			  "\xcf\xa5\x09\xb1\x1d\x42\x2b\xe7",
+		.klen	= 16,
+		.input	= "\xb4\x1e\x6b\xe2\xeb\xa8\x4a\x14"
+			  "\x8e\x2e\xed\x84\x59\x3c\x5e\xc7",
+		.ilen	= 16,
+		.result	= "\x9b\x9b\x7b\xfc\xd1\x81\x3c\xb9"
+			  "\x5d\x0b\x36\x18\xf4\x0f\x51\x22",
+		.rlen	= 16,
+	}
+};
+
+static struct cipher_testvec seed_dec_tv_template[] = {
+	{
+		.key    = zeroed_string,
+		.klen	= 16,
+		.input	= "\x5e\xba\xc6\xe0\x05\x4e\x16\x68"
+			  "\x19\xaf\xf1\xcc\x6d\x34\x6c\xdb",
+		.ilen	= 16,
+		.result	= "\x00\x01\x02\x03\x04\x05\x06\x07"
+			  "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
+		.rlen	= 16,
+	}, {
+		.key	= "\x00\x01\x02\x03\x04\x05\x06\x07"
+			  "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
+		.klen	= 16,
+		.input	= "\xc1\x1f\x22\xf2\x01\x40\x50\x50"
+			  "\x84\x48\x35\x97\xe4\x37\x0f\x43",
+		.ilen	= 16,
+		.result	= zeroed_string,
+		.rlen	= 16,
+	}, {
+		.key	= "\x47\x06\x48\x08\x51\xe6\x1b\xe8"
+			  "\x5d\x74\xbf\xb3\xfd\x95\x61\x85",
+		.klen	= 16,
+		.input	= "\xee\x54\xd1\x3e\xbc\xae\x70\x6d"
+			  "\x22\x6b\xc3\x14\x2c\xd4\x0d\x4a",
+		.ilen	= 16,
+		.result	= "\x83\xa2\xf8\xa2\x88\x64\x1f\xb9"
+			  "\xa4\xe9\xa5\xcc\x2f\x13\x1c\x7d",
+		.rlen	= 16,
+	}, {
+		.key	= "\x28\xdb\xc3\xbc\x49\xff\xd8\x7d"
+			  "\xcf\xa5\x09\xb1\x1d\x42\x2b\xe7",
+		.klen	= 16,
+		.input	= "\x9b\x9b\x7b\xfc\xd1\x81\x3c\xb9"
+			  "\x5d\x0b\x36\x18\xf4\x0f\x51\x22",
+		.ilen	= 16,
+		.result	= "\xb4\x1e\x6b\xe2\xeb\xa8\x4a\x14"
+			  "\x8e\x2e\xed\x84\x59\x3c\x5e\xc7",
+		.rlen	= 16,
+	}
+};
+
+#define SALSA20_STREAM_ENC_TEST_VECTORS 5
+static struct cipher_testvec salsa20_stream_enc_tv_template[] = {
+	/*
+	* Testvectors from verified.test-vectors submitted to ECRYPT.
+	* They are truncated to size 39, 64, 111, 129 to test a variety
+	* of input length.
+	*/
+	{ /* Set 3, vector 0 */
+		.key	= "\x00\x01\x02\x03\x04\x05\x06\x07"
+			"\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F",
+		.klen	= 16,
+		.iv     = "\x00\x00\x00\x00\x00\x00\x00\x00",
+		.input	= "\x00\x00\x00\x00\x00\x00\x00\x00"
+			"\x00\x00\x00\x00\x00\x00\x00\x00"
+			"\x00\x00\x00\x00\x00\x00\x00\x00"
+			"\x00\x00\x00\x00\x00\x00\x00\x00"
+			"\x00\x00\x00\x00\x00\x00\x00",
+		.ilen	= 39,
+		.result	= "\x2D\xD5\xC3\xF7\xBA\x2B\x20\xF7"
+			 "\x68\x02\x41\x0C\x68\x86\x88\x89"
+			 "\x5A\xD8\xC1\xBD\x4E\xA6\xC9\xB1"
+			 "\x40\xFB\x9B\x90\xE2\x10\x49\xBF"
+			 "\x58\x3F\x52\x79\x70\xEB\xC1",
+		.rlen	= 39,
+	}, { /* Set 5, vector 0 */
+		.key	= "\x00\x00\x00\x00\x00\x00\x00\x00"
+			"\x00\x00\x00\x00\x00\x00\x00\x00",
+		.klen	= 16,
+		.iv     = "\x80\x00\x00\x00\x00\x00\x00\x00",
+		.input	= "\x00\x00\x00\x00\x00\x00\x00\x00"
+			"\x00\x00\x00\x00\x00\x00\x00\x00"
+			"\x00\x00\x00\x00\x00\x00\x00\x00"
+			"\x00\x00\x00\x00\x00\x00\x00\x00"
+			"\x00\x00\x00\x00\x00\x00\x00\x00"
+			"\x00\x00\x00\x00\x00\x00\x00\x00"
+			"\x00\x00\x00\x00\x00\x00\x00\x00"
+			"\x00\x00\x00\x00\x00\x00\x00\x00",
+		.ilen	= 64,
+		.result	= "\xB6\x6C\x1E\x44\x46\xDD\x95\x57"
+			 "\xE5\x78\xE2\x23\xB0\xB7\x68\x01"
+			 "\x7B\x23\xB2\x67\xBB\x02\x34\xAE"
+			 "\x46\x26\xBF\x44\x3F\x21\x97\x76"
+			 "\x43\x6F\xB1\x9F\xD0\xE8\x86\x6F"
+			 "\xCD\x0D\xE9\xA9\x53\x8F\x4A\x09"
+			 "\xCA\x9A\xC0\x73\x2E\x30\xBC\xF9"
+			 "\x8E\x4F\x13\xE4\xB9\xE2\x01\xD9",
+		.rlen	= 64,
+	}, { /* Set 3, vector 27 */
+		.key	= "\x1B\x1C\x1D\x1E\x1F\x20\x21\x22"
+			"\x23\x24\x25\x26\x27\x28\x29\x2A"
+			"\x2B\x2C\x2D\x2E\x2F\x30\x31\x32"
+			"\x33\x34\x35\x36\x37\x38\x39\x3A",
+		.klen	= 32,
+		.iv     = "\x00\x00\x00\x00\x00\x00\x00\x00",
+		.input	= "\x00\x00\x00\x00\x00\x00\x00\x00"
+			"\x00\x00\x00\x00\x00\x00\x00\x00"
+			"\x00\x00\x00\x00\x00\x00\x00\x00"
+			"\x00\x00\x00\x00\x00\x00\x00\x00"
+			"\x00\x00\x00\x00\x00\x00\x00\x00"
+			"\x00\x00\x00\x00\x00\x00\x00\x00"
+			"\x00\x00\x00\x00\x00\x00\x00\x00"
+			"\x00\x00\x00\x00\x00\x00\x00\x00"
+			"\x00\x00\x00\x00\x00\x00\x00\x00"
+			"\x00\x00\x00\x00\x00\x00\x00\x00"
+			"\x00\x00\x00\x00\x00\x00\x00\x00"
+			"\x00\x00\x00\x00\x00\x00\x00\x00"
+			"\x00\x00\x00\x00\x00\x00\x00\x00"
+			"\x00\x00\x00\x00\x00\x00\x00",
+		.ilen	= 111,
+		.result	= "\xAE\x39\x50\x8E\xAC\x9A\xEC\xE7"
+			 "\xBF\x97\xBB\x20\xB9\xDE\xE4\x1F"
+			 "\x87\xD9\x47\xF8\x28\x91\x35\x98"
+			 "\xDB\x72\xCC\x23\x29\x48\x56\x5E"
+			 "\x83\x7E\x0B\xF3\x7D\x5D\x38\x7B"
+			 "\x2D\x71\x02\xB4\x3B\xB5\xD8\x23"
+			 "\xB0\x4A\xDF\x3C\xEC\xB6\xD9\x3B"
+			 "\x9B\xA7\x52\xBE\xC5\xD4\x50\x59"
+			 "\x15\x14\xB4\x0E\x40\xE6\x53\xD1"
+			 "\x83\x9C\x5B\xA0\x92\x29\x6B\x5E"
+			 "\x96\x5B\x1E\x2F\xD3\xAC\xC1\x92"
+			 "\xB1\x41\x3F\x19\x2F\xC4\x3B\xC6"
+			 "\x95\x46\x45\x54\xE9\x75\x03\x08"
+			 "\x44\xAF\xE5\x8A\x81\x12\x09",
+		.rlen	= 111,
+	}, { /* Set 5, vector 27 */
+		.key	= "\x00\x00\x00\x00\x00\x00\x00\x00"
+			"\x00\x00\x00\x00\x00\x00\x00\x00"
+			"\x00\x00\x00\x00\x00\x00\x00\x00"
+			"\x00\x00\x00\x00\x00\x00\x00\x00",
+		.klen	= 32,
+		.iv     = "\x00\x00\x00\x10\x00\x00\x00\x00",
+		.input	= "\x00\x00\x00\x00\x00\x00\x00\x00"
+			"\x00\x00\x00\x00\x00\x00\x00\x00"
+			"\x00\x00\x00\x00\x00\x00\x00\x00"
+			"\x00\x00\x00\x00\x00\x00\x00\x00"
+			"\x00\x00\x00\x00\x00\x00\x00\x00"
+			"\x00\x00\x00\x00\x00\x00\x00\x00"
+			"\x00\x00\x00\x00\x00\x00\x00\x00"
+			"\x00\x00\x00\x00\x00\x00\x00\x00"
+			"\x00\x00\x00\x00\x00\x00\x00\x00"
+			"\x00\x00\x00\x00\x00\x00\x00\x00"
+			"\x00\x00\x00\x00\x00\x00\x00\x00"
+			"\x00\x00\x00\x00\x00\x00\x00\x00"
+			"\x00\x00\x00\x00\x00\x00\x00\x00"
+			"\x00\x00\x00\x00\x00\x00\x00\x00"
+			"\x00\x00\x00\x00\x00\x00\x00\x00"
+			"\x00\x00\x00\x00\x00\x00\x00\x00"
+			"\x00",
+		.ilen	= 129,
+		.result	= "\xD2\xDB\x1A\x5C\xF1\xC1\xAC\xDB"
+			 "\xE8\x1A\x7A\x43\x40\xEF\x53\x43"
+			 "\x5E\x7F\x4B\x1A\x50\x52\x3F\x8D"
+			 "\x28\x3D\xCF\x85\x1D\x69\x6E\x60"
+			 "\xF2\xDE\x74\x56\x18\x1B\x84\x10"
+			 "\xD4\x62\xBA\x60\x50\xF0\x61\xF2"
+			 "\x1C\x78\x7F\xC1\x24\x34\xAF\x58"
+			 "\xBF\x2C\x59\xCA\x90\x77\xF3\xB0"
+			 "\x5B\x4A\xDF\x89\xCE\x2C\x2F\xFC"
+			 "\x67\xF0\xE3\x45\xE8\xB3\xB3\x75"
+			 "\xA0\x95\x71\xA1\x29\x39\x94\xCA"
+			 "\x45\x2F\xBD\xCB\x10\xB6\xBE\x9F"
+			 "\x8E\xF9\xB2\x01\x0A\x5A\x0A\xB7"
+			 "\x6B\x9D\x70\x8E\x4B\xD6\x2F\xCD"
+			 "\x2E\x40\x48\x75\xE9\xE2\x21\x45"
+			 "\x0B\xC9\xB6\xB5\x66\xBC\x9A\x59"
+			 "\x5A",
+		.rlen	= 129,
+	}, { /* large test vector generated using Crypto++ */
+		.key =  "\x00\x01\x02\x03\x04\x05\x06\x07"
+			"\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+			"\x10\x11\x12\x13\x14\x15\x16\x17"
+			"\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f",
+		.klen = 32,
+		.iv =	"\x00\x00\x00\x00\x00\x00\x00\x00"
+			"\x00\x00\x00\x00\x00\x00\x00\x00",
+		.input =
+			"\x00\x01\x02\x03\x04\x05\x06\x07"
+			"\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+			"\x10\x11\x12\x13\x14\x15\x16\x17"
+			"\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
+			"\x20\x21\x22\x23\x24\x25\x26\x27"
+			"\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f"
+			"\x30\x31\x32\x33\x34\x35\x36\x37"
+			"\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f"
+			"\x40\x41\x42\x43\x44\x45\x46\x47"
+			"\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f"
+			"\x50\x51\x52\x53\x54\x55\x56\x57"
+			"\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f"
+			"\x60\x61\x62\x63\x64\x65\x66\x67"
+			"\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f"
+			"\x70\x71\x72\x73\x74\x75\x76\x77"
+			"\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f"
+			"\x80\x81\x82\x83\x84\x85\x86\x87"
+			"\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"
+			"\x90\x91\x92\x93\x94\x95\x96\x97"
+			"\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f"
+			"\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7"
+			"\xa8\xa9\xaa\xab\xac\xad\xae\xaf"
+			"\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7"
+			"\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf"
+			"\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7"
+			"\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf"
+			"\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7"
+			"\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf"
+			"\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7"
+			"\xe8\xe9\xea\xeb\xec\xed\xee\xef"
+			"\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7"
+			"\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff"
+			"\x00\x03\x06\x09\x0c\x0f\x12\x15"
+			"\x18\x1b\x1e\x21\x24\x27\x2a\x2d"
+			"\x30\x33\x36\x39\x3c\x3f\x42\x45"
+			"\x48\x4b\x4e\x51\x54\x57\x5a\x5d"
+			"\x60\x63\x66\x69\x6c\x6f\x72\x75"
+			"\x78\x7b\x7e\x81\x84\x87\x8a\x8d"
+			"\x90\x93\x96\x99\x9c\x9f\xa2\xa5"
+			"\xa8\xab\xae\xb1\xb4\xb7\xba\xbd"
+			"\xc0\xc3\xc6\xc9\xcc\xcf\xd2\xd5"
+			"\xd8\xdb\xde\xe1\xe4\xe7\xea\xed"
+			"\xf0\xf3\xf6\xf9\xfc\xff\x02\x05"
+			"\x08\x0b\x0e\x11\x14\x17\x1a\x1d"
+			"\x20\x23\x26\x29\x2c\x2f\x32\x35"
+			"\x38\x3b\x3e\x41\x44\x47\x4a\x4d"
+			"\x50\x53\x56\x59\x5c\x5f\x62\x65"
+			"\x68\x6b\x6e\x71\x74\x77\x7a\x7d"
+			"\x80\x83\x86\x89\x8c\x8f\x92\x95"
+			"\x98\x9b\x9e\xa1\xa4\xa7\xaa\xad"
+			"\xb0\xb3\xb6\xb9\xbc\xbf\xc2\xc5"
+			"\xc8\xcb\xce\xd1\xd4\xd7\xda\xdd"
+			"\xe0\xe3\xe6\xe9\xec\xef\xf2\xf5"
+			"\xf8\xfb\xfe\x01\x04\x07\x0a\x0d"
+			"\x10\x13\x16\x19\x1c\x1f\x22\x25"
+			"\x28\x2b\x2e\x31\x34\x37\x3a\x3d"
+			"\x40\x43\x46\x49\x4c\x4f\x52\x55"
+			"\x58\x5b\x5e\x61\x64\x67\x6a\x6d"
+			"\x70\x73\x76\x79\x7c\x7f\x82\x85"
+			"\x88\x8b\x8e\x91\x94\x97\x9a\x9d"
+			"\xa0\xa3\xa6\xa9\xac\xaf\xb2\xb5"
+			"\xb8\xbb\xbe\xc1\xc4\xc7\xca\xcd"
+			"\xd0\xd3\xd6\xd9\xdc\xdf\xe2\xe5"
+			"\xe8\xeb\xee\xf1\xf4\xf7\xfa\xfd"
+			"\x00\x05\x0a\x0f\x14\x19\x1e\x23"
+			"\x28\x2d\x32\x37\x3c\x41\x46\x4b"
+			"\x50\x55\x5a\x5f\x64\x69\x6e\x73"
+			"\x78\x7d\x82\x87\x8c\x91\x96\x9b"
+			"\xa0\xa5\xaa\xaf\xb4\xb9\xbe\xc3"
+			"\xc8\xcd\xd2\xd7\xdc\xe1\xe6\xeb"
+			"\xf0\xf5\xfa\xff\x04\x09\x0e\x13"
+			"\x18\x1d\x22\x27\x2c\x31\x36\x3b"
+			"\x40\x45\x4a\x4f\x54\x59\x5e\x63"
+			"\x68\x6d\x72\x77\x7c\x81\x86\x8b"
+			"\x90\x95\x9a\x9f\xa4\xa9\xae\xb3"
+			"\xb8\xbd\xc2\xc7\xcc\xd1\xd6\xdb"
+			"\xe0\xe5\xea\xef\xf4\xf9\xfe\x03"
+			"\x08\x0d\x12\x17\x1c\x21\x26\x2b"
+			"\x30\x35\x3a\x3f\x44\x49\x4e\x53"
+			"\x58\x5d\x62\x67\x6c\x71\x76\x7b"
+			"\x80\x85\x8a\x8f\x94\x99\x9e\xa3"
+			"\xa8\xad\xb2\xb7\xbc\xc1\xc6\xcb"
+			"\xd0\xd5\xda\xdf\xe4\xe9\xee\xf3"
+			"\xf8\xfd\x02\x07\x0c\x11\x16\x1b"
+			"\x20\x25\x2a\x2f\x34\x39\x3e\x43"
+			"\x48\x4d\x52\x57\x5c\x61\x66\x6b"
+			"\x70\x75\x7a\x7f\x84\x89\x8e\x93"
+			"\x98\x9d\xa2\xa7\xac\xb1\xb6\xbb"
+			"\xc0\xc5\xca\xcf\xd4\xd9\xde\xe3"
+			"\xe8\xed\xf2\xf7\xfc\x01\x06\x0b"
+			"\x10\x15\x1a\x1f\x24\x29\x2e\x33"
+			"\x38\x3d\x42\x47\x4c\x51\x56\x5b"
+			"\x60\x65\x6a\x6f\x74\x79\x7e\x83"
+			"\x88\x8d\x92\x97\x9c\xa1\xa6\xab"
+			"\xb0\xb5\xba\xbf\xc4\xc9\xce\xd3"
+			"\xd8\xdd\xe2\xe7\xec\xf1\xf6\xfb"
+			"\x00\x07\x0e\x15\x1c\x23\x2a\x31"
+			"\x38\x3f\x46\x4d\x54\x5b\x62\x69"
+			"\x70\x77\x7e\x85\x8c\x93\x9a\xa1"
+			"\xa8\xaf\xb6\xbd\xc4\xcb\xd2\xd9"
+			"\xe0\xe7\xee\xf5\xfc\x03\x0a\x11"
+			"\x18\x1f\x26\x2d\x34\x3b\x42\x49"
+			"\x50\x57\x5e\x65\x6c\x73\x7a\x81"
+			"\x88\x8f\x96\x9d\xa4\xab\xb2\xb9"
+			"\xc0\xc7\xce\xd5\xdc\xe3\xea\xf1"
+			"\xf8\xff\x06\x0d\x14\x1b\x22\x29"
+			"\x30\x37\x3e\x45\x4c\x53\x5a\x61"
+			"\x68\x6f\x76\x7d\x84\x8b\x92\x99"
+			"\xa0\xa7\xae\xb5\xbc\xc3\xca\xd1"
+			"\xd8\xdf\xe6\xed\xf4\xfb\x02\x09"
+			"\x10\x17\x1e\x25\x2c\x33\x3a\x41"
+			"\x48\x4f\x56\x5d\x64\x6b\x72\x79"
+			"\x80\x87\x8e\x95\x9c\xa3\xaa\xb1"
+			"\xb8\xbf\xc6\xcd\xd4\xdb\xe2\xe9"
+			"\xf0\xf7\xfe\x05\x0c\x13\x1a\x21"
+			"\x28\x2f\x36\x3d\x44\x4b\x52\x59"
+			"\x60\x67\x6e\x75\x7c\x83\x8a\x91"
+			"\x98\x9f\xa6\xad\xb4\xbb\xc2\xc9"
+			"\xd0\xd7\xde\xe5\xec\xf3\xfa\x01"
+			"\x08\x0f\x16\x1d\x24\x2b\x32\x39"
+			"\x40\x47\x4e\x55\x5c\x63\x6a\x71"
+			"\x78\x7f\x86\x8d\x94\x9b\xa2\xa9"
+			"\xb0\xb7\xbe\xc5\xcc\xd3\xda\xe1"
+			"\xe8\xef\xf6\xfd\x04\x0b\x12\x19"
+			"\x20\x27\x2e\x35\x3c\x43\x4a\x51"
+			"\x58\x5f\x66\x6d\x74\x7b\x82\x89"
+			"\x90\x97\x9e\xa5\xac\xb3\xba\xc1"
+			"\xc8\xcf\xd6\xdd\xe4\xeb\xf2\xf9"
+			"\x00\x09\x12\x1b\x24\x2d\x36\x3f"
+			"\x48\x51\x5a\x63\x6c\x75\x7e\x87"
+			"\x90\x99\xa2\xab\xb4\xbd\xc6\xcf"
+			"\xd8\xe1\xea\xf3\xfc\x05\x0e\x17"
+			"\x20\x29\x32\x3b\x44\x4d\x56\x5f"
+			"\x68\x71\x7a\x83\x8c\x95\x9e\xa7"
+			"\xb0\xb9\xc2\xcb\xd4\xdd\xe6\xef"
+			"\xf8\x01\x0a\x13\x1c\x25\x2e\x37"
+			"\x40\x49\x52\x5b\x64\x6d\x76\x7f"
+			"\x88\x91\x9a\xa3\xac\xb5\xbe\xc7"
+			"\xd0\xd9\xe2\xeb\xf4\xfd\x06\x0f"
+			"\x18\x21\x2a\x33\x3c\x45\x4e\x57"
+			"\x60\x69\x72\x7b\x84\x8d\x96\x9f"
+			"\xa8\xb1\xba\xc3\xcc\xd5\xde\xe7"
+			"\xf0\xf9\x02\x0b\x14\x1d\x26\x2f"
+			"\x38\x41\x4a\x53\x5c\x65\x6e\x77"
+			"\x80\x89\x92\x9b\xa4\xad\xb6\xbf"
+			"\xc8\xd1\xda\xe3\xec\xf5\xfe\x07"
+			"\x10\x19\x22\x2b\x34\x3d\x46\x4f"
+			"\x58\x61\x6a\x73\x7c\x85\x8e\x97"
+			"\xa0\xa9\xb2\xbb\xc4\xcd\xd6\xdf"
+			"\xe8\xf1\xfa\x03\x0c\x15\x1e\x27"
+			"\x30\x39\x42\x4b\x54\x5d\x66\x6f"
+			"\x78\x81\x8a\x93\x9c\xa5\xae\xb7"
+			"\xc0\xc9\xd2\xdb\xe4\xed\xf6\xff"
+			"\x08\x11\x1a\x23\x2c\x35\x3e\x47"
+			"\x50\x59\x62\x6b\x74\x7d\x86\x8f"
+			"\x98\xa1\xaa\xb3\xbc\xc5\xce\xd7"
+			"\xe0\xe9\xf2\xfb\x04\x0d\x16\x1f"
+			"\x28\x31\x3a\x43\x4c\x55\x5e\x67"
+			"\x70\x79\x82\x8b\x94\x9d\xa6\xaf"
+			"\xb8\xc1\xca\xd3\xdc\xe5\xee\xf7"
+			"\x00\x0b\x16\x21\x2c\x37\x42\x4d"
+			"\x58\x63\x6e\x79\x84\x8f\x9a\xa5"
+			"\xb0\xbb\xc6\xd1\xdc\xe7\xf2\xfd"
+			"\x08\x13\x1e\x29\x34\x3f\x4a\x55"
+			"\x60\x6b\x76\x81\x8c\x97\xa2\xad"
+			"\xb8\xc3\xce\xd9\xe4\xef\xfa\x05"
+			"\x10\x1b\x26\x31\x3c\x47\x52\x5d"
+			"\x68\x73\x7e\x89\x94\x9f\xaa\xb5"
+			"\xc0\xcb\xd6\xe1\xec\xf7\x02\x0d"
+			"\x18\x23\x2e\x39\x44\x4f\x5a\x65"
+			"\x70\x7b\x86\x91\x9c\xa7\xb2\xbd"
+			"\xc8\xd3\xde\xe9\xf4\xff\x0a\x15"
+			"\x20\x2b\x36\x41\x4c\x57\x62\x6d"
+			"\x78\x83\x8e\x99\xa4\xaf\xba\xc5"
+			"\xd0\xdb\xe6\xf1\xfc\x07\x12\x1d"
+			"\x28\x33\x3e\x49\x54\x5f\x6a\x75"
+			"\x80\x8b\x96\xa1\xac\xb7\xc2\xcd"
+			"\xd8\xe3\xee\xf9\x04\x0f\x1a\x25"
+			"\x30\x3b\x46\x51\x5c\x67\x72\x7d"
+			"\x88\x93\x9e\xa9\xb4\xbf\xca\xd5"
+			"\xe0\xeb\xf6\x01\x0c\x17\x22\x2d"
+			"\x38\x43\x4e\x59\x64\x6f\x7a\x85"
+			"\x90\x9b\xa6\xb1\xbc\xc7\xd2\xdd"
+			"\xe8\xf3\xfe\x09\x14\x1f\x2a\x35"
+			"\x40\x4b\x56\x61\x6c\x77\x82\x8d"
+			"\x98\xa3\xae\xb9\xc4\xcf\xda\xe5"
+			"\xf0\xfb\x06\x11\x1c\x27\x32\x3d"
+			"\x48\x53\x5e\x69\x74\x7f\x8a\x95"
+			"\xa0\xab\xb6\xc1\xcc\xd7\xe2\xed"
+			"\xf8\x03\x0e\x19\x24\x2f\x3a\x45"
+			"\x50\x5b\x66\x71\x7c\x87\x92\x9d"
+			"\xa8\xb3\xbe\xc9\xd4\xdf\xea\xf5"
+			"\x00\x0d\x1a\x27\x34\x41\x4e\x5b"
+			"\x68\x75\x82\x8f\x9c\xa9\xb6\xc3"
+			"\xd0\xdd\xea\xf7\x04\x11\x1e\x2b"
+			"\x38\x45\x52\x5f\x6c\x79\x86\x93"
+			"\xa0\xad\xba\xc7\xd4\xe1\xee\xfb"
+			"\x08\x15\x22\x2f\x3c\x49\x56\x63"
+			"\x70\x7d\x8a\x97\xa4\xb1\xbe\xcb"
+			"\xd8\xe5\xf2\xff\x0c\x19\x26\x33"
+			"\x40\x4d\x5a\x67\x74\x81\x8e\x9b"
+			"\xa8\xb5\xc2\xcf\xdc\xe9\xf6\x03"
+			"\x10\x1d\x2a\x37\x44\x51\x5e\x6b"
+			"\x78\x85\x92\x9f\xac\xb9\xc6\xd3"
+			"\xe0\xed\xfa\x07\x14\x21\x2e\x3b"
+			"\x48\x55\x62\x6f\x7c\x89\x96\xa3"
+			"\xb0\xbd\xca\xd7\xe4\xf1\xfe\x0b"
+			"\x18\x25\x32\x3f\x4c\x59\x66\x73"
+			"\x80\x8d\x9a\xa7\xb4\xc1\xce\xdb"
+			"\xe8\xf5\x02\x0f\x1c\x29\x36\x43"
+			"\x50\x5d\x6a\x77\x84\x91\x9e\xab"
+			"\xb8\xc5\xd2\xdf\xec\xf9\x06\x13"
+			"\x20\x2d\x3a\x47\x54\x61\x6e\x7b"
+			"\x88\x95\xa2\xaf\xbc\xc9\xd6\xe3"
+			"\xf0\xfd\x0a\x17\x24\x31\x3e\x4b"
+			"\x58\x65\x72\x7f\x8c\x99\xa6\xb3"
+			"\xc0\xcd\xda\xe7\xf4\x01\x0e\x1b"
+			"\x28\x35\x42\x4f\x5c\x69\x76\x83"
+			"\x90\x9d\xaa\xb7\xc4\xd1\xde\xeb"
+			"\xf8\x05\x12\x1f\x2c\x39\x46\x53"
+			"\x60\x6d\x7a\x87\x94\xa1\xae\xbb"
+			"\xc8\xd5\xe2\xef\xfc\x09\x16\x23"
+			"\x30\x3d\x4a\x57\x64\x71\x7e\x8b"
+			"\x98\xa5\xb2\xbf\xcc\xd9\xe6\xf3"
+			"\x00\x0f\x1e\x2d\x3c\x4b\x5a\x69"
+			"\x78\x87\x96\xa5\xb4\xc3\xd2\xe1"
+			"\xf0\xff\x0e\x1d\x2c\x3b\x4a\x59"
+			"\x68\x77\x86\x95\xa4\xb3\xc2\xd1"
+			"\xe0\xef\xfe\x0d\x1c\x2b\x3a\x49"
+			"\x58\x67\x76\x85\x94\xa3\xb2\xc1"
+			"\xd0\xdf\xee\xfd\x0c\x1b\x2a\x39"
+			"\x48\x57\x66\x75\x84\x93\xa2\xb1"
+			"\xc0\xcf\xde\xed\xfc\x0b\x1a\x29"
+			"\x38\x47\x56\x65\x74\x83\x92\xa1"
+			"\xb0\xbf\xce\xdd\xec\xfb\x0a\x19"
+			"\x28\x37\x46\x55\x64\x73\x82\x91"
+			"\xa0\xaf\xbe\xcd\xdc\xeb\xfa\x09"
+			"\x18\x27\x36\x45\x54\x63\x72\x81"
+			"\x90\x9f\xae\xbd\xcc\xdb\xea\xf9"
+			"\x08\x17\x26\x35\x44\x53\x62\x71"
+			"\x80\x8f\x9e\xad\xbc\xcb\xda\xe9"
+			"\xf8\x07\x16\x25\x34\x43\x52\x61"
+			"\x70\x7f\x8e\x9d\xac\xbb\xca\xd9"
+			"\xe8\xf7\x06\x15\x24\x33\x42\x51"
+			"\x60\x6f\x7e\x8d\x9c\xab\xba\xc9"
+			"\xd8\xe7\xf6\x05\x14\x23\x32\x41"
+			"\x50\x5f\x6e\x7d\x8c\x9b\xaa\xb9"
+			"\xc8\xd7\xe6\xf5\x04\x13\x22\x31"
+			"\x40\x4f\x5e\x6d\x7c\x8b\x9a\xa9"
+			"\xb8\xc7\xd6\xe5\xf4\x03\x12\x21"
+			"\x30\x3f\x4e\x5d\x6c\x7b\x8a\x99"
+			"\xa8\xb7\xc6\xd5\xe4\xf3\x02\x11"
+			"\x20\x2f\x3e\x4d\x5c\x6b\x7a\x89"
+			"\x98\xa7\xb6\xc5\xd4\xe3\xf2\x01"
+			"\x10\x1f\x2e\x3d\x4c\x5b\x6a\x79"
+			"\x88\x97\xa6\xb5\xc4\xd3\xe2\xf1"
+			"\x00\x11\x22\x33\x44\x55\x66\x77"
+			"\x88\x99\xaa\xbb\xcc\xdd\xee\xff"
+			"\x10\x21\x32\x43\x54\x65\x76\x87"
+			"\x98\xa9\xba\xcb\xdc\xed\xfe\x0f"
+			"\x20\x31\x42\x53\x64\x75\x86\x97"
+			"\xa8\xb9\xca\xdb\xec\xfd\x0e\x1f"
+			"\x30\x41\x52\x63\x74\x85\x96\xa7"
+			"\xb8\xc9\xda\xeb\xfc\x0d\x1e\x2f"
+			"\x40\x51\x62\x73\x84\x95\xa6\xb7"
+			"\xc8\xd9\xea\xfb\x0c\x1d\x2e\x3f"
+			"\x50\x61\x72\x83\x94\xa5\xb6\xc7"
+			"\xd8\xe9\xfa\x0b\x1c\x2d\x3e\x4f"
+			"\x60\x71\x82\x93\xa4\xb5\xc6\xd7"
+			"\xe8\xf9\x0a\x1b\x2c\x3d\x4e\x5f"
+			"\x70\x81\x92\xa3\xb4\xc5\xd6\xe7"
+			"\xf8\x09\x1a\x2b\x3c\x4d\x5e\x6f"
+			"\x80\x91\xa2\xb3\xc4\xd5\xe6\xf7"
+			"\x08\x19\x2a\x3b\x4c\x5d\x6e\x7f"
+			"\x90\xa1\xb2\xc3\xd4\xe5\xf6\x07"
+			"\x18\x29\x3a\x4b\x5c\x6d\x7e\x8f"
+			"\xa0\xb1\xc2\xd3\xe4\xf5\x06\x17"
+			"\x28\x39\x4a\x5b\x6c\x7d\x8e\x9f"
+			"\xb0\xc1\xd2\xe3\xf4\x05\x16\x27"
+			"\x38\x49\x5a\x6b\x7c\x8d\x9e\xaf"
+			"\xc0\xd1\xe2\xf3\x04\x15\x26\x37"
+			"\x48\x59\x6a\x7b\x8c\x9d\xae\xbf"
+			"\xd0\xe1\xf2\x03\x14\x25\x36\x47"
+			"\x58\x69\x7a\x8b\x9c\xad\xbe\xcf"
+			"\xe0\xf1\x02\x13\x24\x35\x46\x57"
+			"\x68\x79\x8a\x9b\xac\xbd\xce\xdf"
+			"\xf0\x01\x12\x23\x34\x45\x56\x67"
+			"\x78\x89\x9a\xab\xbc\xcd\xde\xef"
+			"\x00\x13\x26\x39\x4c\x5f\x72\x85"
+			"\x98\xab\xbe\xd1\xe4\xf7\x0a\x1d"
+			"\x30\x43\x56\x69\x7c\x8f\xa2\xb5"
+			"\xc8\xdb\xee\x01\x14\x27\x3a\x4d"
+			"\x60\x73\x86\x99\xac\xbf\xd2\xe5"
+			"\xf8\x0b\x1e\x31\x44\x57\x6a\x7d"
+			"\x90\xa3\xb6\xc9\xdc\xef\x02\x15"
+			"\x28\x3b\x4e\x61\x74\x87\x9a\xad"
+			"\xc0\xd3\xe6\xf9\x0c\x1f\x32\x45"
+			"\x58\x6b\x7e\x91\xa4\xb7\xca\xdd"
+			"\xf0\x03\x16\x29\x3c\x4f\x62\x75"
+			"\x88\x9b\xae\xc1\xd4\xe7\xfa\x0d"
+			"\x20\x33\x46\x59\x6c\x7f\x92\xa5"
+			"\xb8\xcb\xde\xf1\x04\x17\x2a\x3d"
+			"\x50\x63\x76\x89\x9c\xaf\xc2\xd5"
+			"\xe8\xfb\x0e\x21\x34\x47\x5a\x6d"
+			"\x80\x93\xa6\xb9\xcc\xdf\xf2\x05"
+			"\x18\x2b\x3e\x51\x64\x77\x8a\x9d"
+			"\xb0\xc3\xd6\xe9\xfc\x0f\x22\x35"
+			"\x48\x5b\x6e\x81\x94\xa7\xba\xcd"
+			"\xe0\xf3\x06\x19\x2c\x3f\x52\x65"
+			"\x78\x8b\x9e\xb1\xc4\xd7\xea\xfd"
+			"\x10\x23\x36\x49\x5c\x6f\x82\x95"
+			"\xa8\xbb\xce\xe1\xf4\x07\x1a\x2d"
+			"\x40\x53\x66\x79\x8c\x9f\xb2\xc5"
+			"\xd8\xeb\xfe\x11\x24\x37\x4a\x5d"
+			"\x70\x83\x96\xa9\xbc\xcf\xe2\xf5"
+			"\x08\x1b\x2e\x41\x54\x67\x7a\x8d"
+			"\xa0\xb3\xc6\xd9\xec\xff\x12\x25"
+			"\x38\x4b\x5e\x71\x84\x97\xaa\xbd"
+			"\xd0\xe3\xf6\x09\x1c\x2f\x42\x55"
+			"\x68\x7b\x8e\xa1\xb4\xc7\xda\xed"
+			"\x00\x15\x2a\x3f\x54\x69\x7e\x93"
+			"\xa8\xbd\xd2\xe7\xfc\x11\x26\x3b"
+			"\x50\x65\x7a\x8f\xa4\xb9\xce\xe3"
+			"\xf8\x0d\x22\x37\x4c\x61\x76\x8b"
+			"\xa0\xb5\xca\xdf\xf4\x09\x1e\x33"
+			"\x48\x5d\x72\x87\x9c\xb1\xc6\xdb"
+			"\xf0\x05\x1a\x2f\x44\x59\x6e\x83"
+			"\x98\xad\xc2\xd7\xec\x01\x16\x2b"
+			"\x40\x55\x6a\x7f\x94\xa9\xbe\xd3"
+			"\xe8\xfd\x12\x27\x3c\x51\x66\x7b"
+			"\x90\xa5\xba\xcf\xe4\xf9\x0e\x23"
+			"\x38\x4d\x62\x77\x8c\xa1\xb6\xcb"
+			"\xe0\xf5\x0a\x1f\x34\x49\x5e\x73"
+			"\x88\x9d\xb2\xc7\xdc\xf1\x06\x1b"
+			"\x30\x45\x5a\x6f\x84\x99\xae\xc3"
+			"\xd8\xed\x02\x17\x2c\x41\x56\x6b"
+			"\x80\x95\xaa\xbf\xd4\xe9\xfe\x13"
+			"\x28\x3d\x52\x67\x7c\x91\xa6\xbb"
+			"\xd0\xe5\xfa\x0f\x24\x39\x4e\x63"
+			"\x78\x8d\xa2\xb7\xcc\xe1\xf6\x0b"
+			"\x20\x35\x4a\x5f\x74\x89\x9e\xb3"
+			"\xc8\xdd\xf2\x07\x1c\x31\x46\x5b"
+			"\x70\x85\x9a\xaf\xc4\xd9\xee\x03"
+			"\x18\x2d\x42\x57\x6c\x81\x96\xab"
+			"\xc0\xd5\xea\xff\x14\x29\x3e\x53"
+			"\x68\x7d\x92\xa7\xbc\xd1\xe6\xfb"
+			"\x10\x25\x3a\x4f\x64\x79\x8e\xa3"
+			"\xb8\xcd\xe2\xf7\x0c\x21\x36\x4b"
+			"\x60\x75\x8a\x9f\xb4\xc9\xde\xf3"
+			"\x08\x1d\x32\x47\x5c\x71\x86\x9b"
+			"\xb0\xc5\xda\xef\x04\x19\x2e\x43"
+			"\x58\x6d\x82\x97\xac\xc1\xd6\xeb"
+			"\x00\x17\x2e\x45\x5c\x73\x8a\xa1"
+			"\xb8\xcf\xe6\xfd\x14\x2b\x42\x59"
+			"\x70\x87\x9e\xb5\xcc\xe3\xfa\x11"
+			"\x28\x3f\x56\x6d\x84\x9b\xb2\xc9"
+			"\xe0\xf7\x0e\x25\x3c\x53\x6a\x81"
+			"\x98\xaf\xc6\xdd\xf4\x0b\x22\x39"
+			"\x50\x67\x7e\x95\xac\xc3\xda\xf1"
+			"\x08\x1f\x36\x4d\x64\x7b\x92\xa9"
+			"\xc0\xd7\xee\x05\x1c\x33\x4a\x61"
+			"\x78\x8f\xa6\xbd\xd4\xeb\x02\x19"
+			"\x30\x47\x5e\x75\x8c\xa3\xba\xd1"
+			"\xe8\xff\x16\x2d\x44\x5b\x72\x89"
+			"\xa0\xb7\xce\xe5\xfc\x13\x2a\x41"
+			"\x58\x6f\x86\x9d\xb4\xcb\xe2\xf9"
+			"\x10\x27\x3e\x55\x6c\x83\x9a\xb1"
+			"\xc8\xdf\xf6\x0d\x24\x3b\x52\x69"
+			"\x80\x97\xae\xc5\xdc\xf3\x0a\x21"
+			"\x38\x4f\x66\x7d\x94\xab\xc2\xd9"
+			"\xf0\x07\x1e\x35\x4c\x63\x7a\x91"
+			"\xa8\xbf\xd6\xed\x04\x1b\x32\x49"
+			"\x60\x77\x8e\xa5\xbc\xd3\xea\x01"
+			"\x18\x2f\x46\x5d\x74\x8b\xa2\xb9"
+			"\xd0\xe7\xfe\x15\x2c\x43\x5a\x71"
+			"\x88\x9f\xb6\xcd\xe4\xfb\x12\x29"
+			"\x40\x57\x6e\x85\x9c\xb3\xca\xe1"
+			"\xf8\x0f\x26\x3d\x54\x6b\x82\x99"
+			"\xb0\xc7\xde\xf5\x0c\x23\x3a\x51"
+			"\x68\x7f\x96\xad\xc4\xdb\xf2\x09"
+			"\x20\x37\x4e\x65\x7c\x93\xaa\xc1"
+			"\xd8\xef\x06\x1d\x34\x4b\x62\x79"
+			"\x90\xa7\xbe\xd5\xec\x03\x1a\x31"
+			"\x48\x5f\x76\x8d\xa4\xbb\xd2\xe9"
+			"\x00\x19\x32\x4b\x64\x7d\x96\xaf"
+			"\xc8\xe1\xfa\x13\x2c\x45\x5e\x77"
+			"\x90\xa9\xc2\xdb\xf4\x0d\x26\x3f"
+			"\x58\x71\x8a\xa3\xbc\xd5\xee\x07"
+			"\x20\x39\x52\x6b\x84\x9d\xb6\xcf"
+			"\xe8\x01\x1a\x33\x4c\x65\x7e\x97"
+			"\xb0\xc9\xe2\xfb\x14\x2d\x46\x5f"
+			"\x78\x91\xaa\xc3\xdc\xf5\x0e\x27"
+			"\x40\x59\x72\x8b\xa4\xbd\xd6\xef"
+			"\x08\x21\x3a\x53\x6c\x85\x9e\xb7"
+			"\xd0\xe9\x02\x1b\x34\x4d\x66\x7f"
+			"\x98\xb1\xca\xe3\xfc\x15\x2e\x47"
+			"\x60\x79\x92\xab\xc4\xdd\xf6\x0f"
+			"\x28\x41\x5a\x73\x8c\xa5\xbe\xd7"
+			"\xf0\x09\x22\x3b\x54\x6d\x86\x9f"
+			"\xb8\xd1\xea\x03\x1c\x35\x4e\x67"
+			"\x80\x99\xb2\xcb\xe4\xfd\x16\x2f"
+			"\x48\x61\x7a\x93\xac\xc5\xde\xf7"
+			"\x10\x29\x42\x5b\x74\x8d\xa6\xbf"
+			"\xd8\xf1\x0a\x23\x3c\x55\x6e\x87"
+			"\xa0\xb9\xd2\xeb\x04\x1d\x36\x4f"
+			"\x68\x81\x9a\xb3\xcc\xe5\xfe\x17"
+			"\x30\x49\x62\x7b\x94\xad\xc6\xdf"
+			"\xf8\x11\x2a\x43\x5c\x75\x8e\xa7"
+			"\xc0\xd9\xf2\x0b\x24\x3d\x56\x6f"
+			"\x88\xa1\xba\xd3\xec\x05\x1e\x37"
+			"\x50\x69\x82\x9b\xb4\xcd\xe6\xff"
+			"\x18\x31\x4a\x63\x7c\x95\xae\xc7"
+			"\xe0\xf9\x12\x2b\x44\x5d\x76\x8f"
+			"\xa8\xc1\xda\xf3\x0c\x25\x3e\x57"
+			"\x70\x89\xa2\xbb\xd4\xed\x06\x1f"
+			"\x38\x51\x6a\x83\x9c\xb5\xce\xe7"
+			"\x00\x1b\x36\x51\x6c\x87\xa2\xbd"
+			"\xd8\xf3\x0e\x29\x44\x5f\x7a\x95"
+			"\xb0\xcb\xe6\x01\x1c\x37\x52\x6d"
+			"\x88\xa3\xbe\xd9\xf4\x0f\x2a\x45"
+			"\x60\x7b\x96\xb1\xcc\xe7\x02\x1d"
+			"\x38\x53\x6e\x89\xa4\xbf\xda\xf5"
+			"\x10\x2b\x46\x61\x7c\x97\xb2\xcd"
+			"\xe8\x03\x1e\x39\x54\x6f\x8a\xa5"
+			"\xc0\xdb\xf6\x11\x2c\x47\x62\x7d"
+			"\x98\xb3\xce\xe9\x04\x1f\x3a\x55"
+			"\x70\x8b\xa6\xc1\xdc\xf7\x12\x2d"
+			"\x48\x63\x7e\x99\xb4\xcf\xea\x05"
+			"\x20\x3b\x56\x71\x8c\xa7\xc2\xdd"
+			"\xf8\x13\x2e\x49\x64\x7f\x9a\xb5"
+			"\xd0\xeb\x06\x21\x3c\x57\x72\x8d"
+			"\xa8\xc3\xde\xf9\x14\x2f\x4a\x65"
+			"\x80\x9b\xb6\xd1\xec\x07\x22\x3d"
+			"\x58\x73\x8e\xa9\xc4\xdf\xfa\x15"
+			"\x30\x4b\x66\x81\x9c\xb7\xd2\xed"
+			"\x08\x23\x3e\x59\x74\x8f\xaa\xc5"
+			"\xe0\xfb\x16\x31\x4c\x67\x82\x9d"
+			"\xb8\xd3\xee\x09\x24\x3f\x5a\x75"
+			"\x90\xab\xc6\xe1\xfc\x17\x32\x4d"
+			"\x68\x83\x9e\xb9\xd4\xef\x0a\x25"
+			"\x40\x5b\x76\x91\xac\xc7\xe2\xfd"
+			"\x18\x33\x4e\x69\x84\x9f\xba\xd5"
+			"\xf0\x0b\x26\x41\x5c\x77\x92\xad"
+			"\xc8\xe3\xfe\x19\x34\x4f\x6a\x85"
+			"\xa0\xbb\xd6\xf1\x0c\x27\x42\x5d"
+			"\x78\x93\xae\xc9\xe4\xff\x1a\x35"
+			"\x50\x6b\x86\xa1\xbc\xd7\xf2\x0d"
+			"\x28\x43\x5e\x79\x94\xaf\xca\xe5"
+			"\x00\x1d\x3a\x57\x74\x91\xae\xcb"
+			"\xe8\x05\x22\x3f\x5c\x79\x96\xb3"
+			"\xd0\xed\x0a\x27\x44\x61\x7e\x9b"
+			"\xb8\xd5\xf2\x0f\x2c\x49\x66\x83"
+			"\xa0\xbd\xda\xf7\x14\x31\x4e\x6b"
+			"\x88\xa5\xc2\xdf\xfc\x19\x36\x53"
+			"\x70\x8d\xaa\xc7\xe4\x01\x1e\x3b"
+			"\x58\x75\x92\xaf\xcc\xe9\x06\x23"
+			"\x40\x5d\x7a\x97\xb4\xd1\xee\x0b"
+			"\x28\x45\x62\x7f\x9c\xb9\xd6\xf3"
+			"\x10\x2d\x4a\x67\x84\xa1\xbe\xdb"
+			"\xf8\x15\x32\x4f\x6c\x89\xa6\xc3"
+			"\xe0\xfd\x1a\x37\x54\x71\x8e\xab"
+			"\xc8\xe5\x02\x1f\x3c\x59\x76\x93"
+			"\xb0\xcd\xea\x07\x24\x41\x5e\x7b"
+			"\x98\xb5\xd2\xef\x0c\x29\x46\x63"
+			"\x80\x9d\xba\xd7\xf4\x11\x2e\x4b"
+			"\x68\x85\xa2\xbf\xdc\xf9\x16\x33"
+			"\x50\x6d\x8a\xa7\xc4\xe1\xfe\x1b"
+			"\x38\x55\x72\x8f\xac\xc9\xe6\x03"
+			"\x20\x3d\x5a\x77\x94\xb1\xce\xeb"
+			"\x08\x25\x42\x5f\x7c\x99\xb6\xd3"
+			"\xf0\x0d\x2a\x47\x64\x81\x9e\xbb"
+			"\xd8\xf5\x12\x2f\x4c\x69\x86\xa3"
+			"\xc0\xdd\xfa\x17\x34\x51\x6e\x8b"
+			"\xa8\xc5\xe2\xff\x1c\x39\x56\x73"
+			"\x90\xad\xca\xe7\x04\x21\x3e\x5b"
+			"\x78\x95\xb2\xcf\xec\x09\x26\x43"
+			"\x60\x7d\x9a\xb7\xd4\xf1\x0e\x2b"
+			"\x48\x65\x82\x9f\xbc\xd9\xf6\x13"
+			"\x30\x4d\x6a\x87\xa4\xc1\xde\xfb"
+			"\x18\x35\x52\x6f\x8c\xa9\xc6\xe3"
+			"\x00\x1f\x3e\x5d\x7c\x9b\xba\xd9"
+			"\xf8\x17\x36\x55\x74\x93\xb2\xd1"
+			"\xf0\x0f\x2e\x4d\x6c\x8b\xaa\xc9"
+			"\xe8\x07\x26\x45\x64\x83\xa2\xc1"
+			"\xe0\xff\x1e\x3d\x5c\x7b\x9a\xb9"
+			"\xd8\xf7\x16\x35\x54\x73\x92\xb1"
+			"\xd0\xef\x0e\x2d\x4c\x6b\x8a\xa9"
+			"\xc8\xe7\x06\x25\x44\x63\x82\xa1"
+			"\xc0\xdf\xfe\x1d\x3c\x5b\x7a\x99"
+			"\xb8\xd7\xf6\x15\x34\x53\x72\x91"
+			"\xb0\xcf\xee\x0d\x2c\x4b\x6a\x89"
+			"\xa8\xc7\xe6\x05\x24\x43\x62\x81"
+			"\xa0\xbf\xde\xfd\x1c\x3b\x5a\x79"
+			"\x98\xb7\xd6\xf5\x14\x33\x52\x71"
+			"\x90\xaf\xce\xed\x0c\x2b\x4a\x69"
+			"\x88\xa7\xc6\xe5\x04\x23\x42\x61"
+			"\x80\x9f\xbe\xdd\xfc\x1b\x3a\x59"
+			"\x78\x97\xb6\xd5\xf4\x13\x32\x51"
+			"\x70\x8f\xae\xcd\xec\x0b\x2a\x49"
+			"\x68\x87\xa6\xc5\xe4\x03\x22\x41"
+			"\x60\x7f\x9e\xbd\xdc\xfb\x1a\x39"
+			"\x58\x77\x96\xb5\xd4\xf3\x12\x31"
+			"\x50\x6f\x8e\xad\xcc\xeb\x0a\x29"
+			"\x48\x67\x86\xa5\xc4\xe3\x02\x21"
+			"\x40\x5f\x7e\x9d\xbc\xdb\xfa\x19"
+			"\x38\x57\x76\x95\xb4\xd3\xf2\x11"
+			"\x30\x4f\x6e\x8d\xac\xcb\xea\x09"
+			"\x28\x47\x66\x85\xa4\xc3\xe2\x01"
+			"\x20\x3f\x5e\x7d\x9c\xbb\xda\xf9"
+			"\x18\x37\x56\x75\x94\xb3\xd2\xf1"
+			"\x10\x2f\x4e\x6d\x8c\xab\xca\xe9"
+			"\x08\x27\x46\x65\x84\xa3\xc2\xe1"
+			"\x00\x21\x42\x63",
+		.ilen = 4100,
+		.result =
+			"\xb5\x81\xf5\x64\x18\x73\xe3\xf0"
+			"\x4c\x13\xf2\x77\x18\x60\x65\x5e"
+			"\x29\x01\xce\x98\x55\x53\xf9\x0c"
+			"\x2a\x08\xd5\x09\xb3\x57\x55\x56"
+			"\xc5\xe9\x56\x90\xcb\x6a\xa3\xc0"
+			"\xff\xc4\x79\xb4\xd2\x97\x5d\xc4"
+			"\x43\xd1\xfe\x94\x7b\x88\x06\x5a"
+			"\xb2\x9e\x2c\xfc\x44\x03\xb7\x90"
+			"\xa0\xc1\xba\x6a\x33\xb8\xc7\xb2"
+			"\x9d\xe1\x12\x4f\xc0\x64\xd4\x01"
+			"\xfe\x8c\x7a\x66\xf7\xe6\x5a\x91"
+			"\xbb\xde\x56\x86\xab\x65\x21\x30"
+			"\x00\x84\x65\x24\xa5\x7d\x85\xb4"
+			"\xe3\x17\xed\x3a\xb7\x6f\xb4\x0b"
+			"\x0b\xaf\x15\xae\x5a\x8f\xf2\x0c"
+			"\x2f\x27\xf4\x09\xd8\xd2\x96\xb7"
+			"\x71\xf2\xc5\x99\x4d\x7e\x7f\x75"
+			"\x77\x89\x30\x8b\x59\xdb\xa2\xb2"
+			"\xa0\xf3\x19\x39\x2b\xc5\x7e\x3f"
+			"\x4f\xd9\xd3\x56\x28\x97\x44\xdc"
+			"\xc0\x8b\x77\x24\xd9\x52\xe7\xc5"
+			"\xaf\xf6\x7d\x59\xb2\x44\x05\x1d"
+			"\xb1\xb0\x11\xa5\x0f\xec\x33\xe1"
+			"\x6d\x1b\x4e\x1f\xff\x57\x91\xb4"
+			"\x5b\x9a\x96\xc5\x53\xbc\xae\x20"
+			"\x3c\xbb\x14\xe2\xe8\x22\x33\xc1"
+			"\x5e\x76\x9e\x46\x99\xf6\x2a\x15"
+			"\xc6\x97\x02\xa0\x66\x43\xd1\xa6"
+			"\x31\xa6\x9f\xfb\xf4\xd3\x69\xe5"
+			"\xcd\x76\x95\xb8\x7a\x82\x7f\x21"
+			"\x45\xff\x3f\xce\x55\xf6\x95\x10"
+			"\x08\x77\x10\x43\xc6\xf3\x09\xe5"
+			"\x68\xe7\x3c\xad\x00\x52\x45\x0d"
+			"\xfe\x2d\xc6\xc2\x94\x8c\x12\x1d"
+			"\xe6\x25\xae\x98\x12\x8e\x19\x9c"
+			"\x81\x68\xb1\x11\xf6\x69\xda\xe3"
+			"\x62\x08\x18\x7a\x25\x49\x28\xac"
+			"\xba\x71\x12\x0b\xe4\xa2\xe5\xc7"
+			"\x5d\x8e\xec\x49\x40\x21\xbf\x5a"
+			"\x98\xf3\x02\x68\x55\x03\x7f\x8a"
+			"\xe5\x94\x0c\x32\x5c\x07\x82\x63"
+			"\xaf\x6f\x91\x40\x84\x8e\x52\x25"
+			"\xd0\xb0\x29\x53\x05\xe2\x50\x7a"
+			"\x34\xeb\xc9\x46\x20\xa8\x3d\xde"
+			"\x7f\x16\x5f\x36\xc5\x2e\xdc\xd1"
+			"\x15\x47\xc7\x50\x40\x6d\x91\xc5"
+			"\xe7\x93\x95\x1a\xd3\x57\xbc\x52"
+			"\x33\xee\x14\x19\x22\x52\x89\xa7"
+			"\x4a\x25\x56\x77\x4b\xca\xcf\x0a"
+			"\xe1\xf5\x35\x85\x30\x7e\x59\x4a"
+			"\xbd\x14\x5b\xdf\xe3\x46\xcb\xac"
+			"\x1f\x6c\x96\x0e\xf4\x81\xd1\x99"
+			"\xca\x88\x63\x3d\x02\x58\x6b\xa9"
+			"\xe5\x9f\xb3\x00\xb2\x54\xc6\x74"
+			"\x1c\xbf\x46\xab\x97\xcc\xf8\x54"
+			"\x04\x07\x08\x52\xe6\xc0\xda\x93"
+			"\x74\x7d\x93\x99\x5d\x78\x68\xa6"
+			"\x2e\x6b\xd3\x6a\x69\xcc\x12\x6b"
+			"\xd4\xc7\xa5\xc6\xe7\xf6\x03\x04"
+			"\x5d\xcd\x61\x5e\x17\x40\xdc\xd1"
+			"\x5c\xf5\x08\xdf\x5c\x90\x85\xa4"
+			"\xaf\xf6\x78\xbb\x0d\xf1\xf4\xa4"
+			"\x54\x26\x72\x9e\x61\xfa\x86\xcf"
+			"\xe8\x9e\xa1\xe0\xc7\x48\x23\xae"
+			"\x5a\x90\xae\x75\x0a\x74\x18\x89"
+			"\x05\xb1\x92\xb2\x7f\xd0\x1b\xa6"
+			"\x62\x07\x25\x01\xc7\xc2\x4f\xf9"
+			"\xe8\xfe\x63\x95\x80\x07\xb4\x26"
+			"\xcc\xd1\x26\xb6\xc4\x3f\x9e\xcb"
+			"\x8e\x3b\x2e\x44\x16\xd3\x10\x9a"
+			"\x95\x08\xeb\xc8\xcb\xeb\xbf\x6f"
+			"\x0b\xcd\x1f\xc8\xca\x86\xaa\xec"
+			"\x33\xe6\x69\xf4\x45\x25\x86\x3a"
+			"\x22\x94\x4f\x00\x23\x6a\x44\xc2"
+			"\x49\x97\x33\xab\x36\x14\x0a\x70"
+			"\x24\xc3\xbe\x04\x3b\x79\xa0\xf9"
+			"\xb8\xe7\x76\x29\x22\x83\xd7\xf2"
+			"\x94\xf4\x41\x49\xba\x5f\x7b\x07"
+			"\xb5\xfb\xdb\x03\x1a\x9f\xb6\x4c"
+			"\xc2\x2e\x37\x40\x49\xc3\x38\x16"
+			"\xe2\x4f\x77\x82\xb0\x68\x4c\x71"
+			"\x1d\x57\x61\x9c\xd9\x4e\x54\x99"
+			"\x47\x13\x28\x73\x3c\xbb\x00\x90"
+			"\xf3\x4d\xc9\x0e\xfd\xe7\xb1\x71"
+			"\xd3\x15\x79\xbf\xcc\x26\x2f\xbd"
+			"\xad\x6c\x50\x69\x6c\x3e\x6d\x80"
+			"\x9a\xea\x78\xaf\x19\xb2\x0d\x4d"
+			"\xad\x04\x07\xae\x22\x90\x4a\x93"
+			"\x32\x0e\x36\x9b\x1b\x46\xba\x3b"
+			"\xb4\xac\xc6\xd1\xa2\x31\x53\x3b"
+			"\x2a\x3d\x45\xfe\x03\x61\x10\x85"
+			"\x17\x69\xa6\x78\xcc\x6c\x87\x49"
+			"\x53\xf9\x80\x10\xde\x80\xa2\x41"
+			"\x6a\xc3\x32\x02\xad\x6d\x3c\x56"
+			"\x00\x71\x51\x06\xa7\xbd\xfb\xef"
+			"\x3c\xb5\x9f\xfc\x48\x7d\x53\x7c"
+			"\x66\xb0\x49\x23\xc4\x47\x10\x0e"
+			"\xe5\x6c\x74\x13\xe6\xc5\x3f\xaa"
+			"\xde\xff\x07\x44\xdd\x56\x1b\xad"
+			"\x09\x77\xfb\x5b\x12\xb8\x0d\x38"
+			"\x17\x37\x35\x7b\x9b\xbc\xfe\xd4"
+			"\x7e\x8b\xda\x7e\x5b\x04\xa7\x22"
+			"\xa7\x31\xa1\x20\x86\xc7\x1b\x99"
+			"\xdb\xd1\x89\xf4\x94\xa3\x53\x69"
+			"\x8d\xe7\xe8\x74\x11\x8d\x74\xd6"
+			"\x07\x37\x91\x9f\xfd\x67\x50\x3a"
+			"\xc9\xe1\xf4\x36\xd5\xa0\x47\xd1"
+			"\xf9\xe5\x39\xa3\x31\xac\x07\x36"
+			"\x23\xf8\x66\x18\x14\x28\x34\x0f"
+			"\xb8\xd0\xe7\x29\xb3\x04\x4b\x55"
+			"\x01\x41\xb2\x75\x8d\xcb\x96\x85"
+			"\x3a\xfb\xab\x2b\x9e\xfa\x58\x20"
+			"\x44\x1f\xc0\x14\x22\x75\x61\xe8"
+			"\xaa\x19\xcf\xf1\x82\x56\xf4\xd7"
+			"\x78\x7b\x3d\x5f\xb3\x9e\x0b\x8a"
+			"\x57\x50\xdb\x17\x41\x65\x4d\xa3"
+			"\x02\xc9\x9c\x9c\x53\xfb\x39\x39"
+			"\x9b\x1d\x72\x24\xda\xb7\x39\xbe"
+			"\x13\x3b\xfa\x29\xda\x9e\x54\x64"
+			"\x6e\xba\xd8\xa1\xcb\xb3\x36\xfa"
+			"\xcb\x47\x85\xe9\x61\x38\xbc\xbe"
+			"\xc5\x00\x38\x2a\x54\xf7\xc4\xb9"
+			"\xb3\xd3\x7b\xa0\xa0\xf8\x72\x7f"
+			"\x8c\x8e\x82\x0e\xc6\x1c\x75\x9d"
+			"\xca\x8e\x61\x87\xde\xad\x80\xd2"
+			"\xf5\xf9\x80\xef\x15\x75\xaf\xf5"
+			"\x80\xfb\xff\x6d\x1e\x25\xb7\x40"
+			"\x61\x6a\x39\x5a\x6a\xb5\x31\xab"
+			"\x97\x8a\x19\x89\x44\x40\xc0\xa6"
+			"\xb4\x4e\x30\x32\x7b\x13\xe7\x67"
+			"\xa9\x8b\x57\x04\xc2\x01\xa6\xf4"
+			"\x28\x99\xad\x2c\x76\xa3\x78\xc2"
+			"\x4a\xe6\xca\x5c\x50\x6a\xc1\xb0"
+			"\x62\x4b\x10\x8e\x7c\x17\x43\xb3"
+			"\x17\x66\x1c\x3e\x8d\x69\xf0\x5a"
+			"\x71\xf5\x97\xdc\xd1\x45\xdd\x28"
+			"\xf3\x5d\xdf\x53\x7b\x11\xe5\xbc"
+			"\x4c\xdb\x1b\x51\x6b\xe9\xfb\x3d"
+			"\xc1\xc3\x2c\xb9\x71\xf5\xb6\xb2"
+			"\x13\x36\x79\x80\x53\xe8\xd3\xa6"
+			"\x0a\xaf\xfd\x56\x97\xf7\x40\x8e"
+			"\x45\xce\xf8\xb0\x9e\x5c\x33\x82"
+			"\xb0\x44\x56\xfc\x05\x09\xe9\x2a"
+			"\xac\x26\x80\x14\x1d\xc8\x3a\x35"
+			"\x4c\x82\x97\xfd\x76\xb7\xa9\x0a"
+			"\x35\x58\x79\x8e\x0f\x66\xea\xaf"
+			"\x51\x6c\x09\xa9\x6e\x9b\xcb\x9a"
+			"\x31\x47\xa0\x2f\x7c\x71\xb4\x4a"
+			"\x11\xaa\x8c\x66\xc5\x64\xe6\x3a"
+			"\x54\xda\x24\x6a\xc4\x41\x65\x46"
+			"\x82\xa0\x0a\x0f\x5f\xfb\x25\xd0"
+			"\x2c\x91\xa7\xee\xc4\x81\x07\x86"
+			"\x75\x5e\x33\x69\x97\xe4\x2c\xa8"
+			"\x9d\x9f\x0b\x6a\xbe\xad\x98\xda"
+			"\x6d\x94\x41\xda\x2c\x1e\x89\xc4"
+			"\xc2\xaf\x1e\x00\x05\x0b\x83\x60"
+			"\xbd\x43\xea\x15\x23\x7f\xb9\xac"
+			"\xee\x4f\x2c\xaf\x2a\xf3\xdf\xd0"
+			"\xf3\x19\x31\xbb\x4a\x74\x84\x17"
+			"\x52\x32\x2c\x7d\x61\xe4\xcb\xeb"
+			"\x80\x38\x15\x52\xcb\x6f\xea\xe5"
+			"\x73\x9c\xd9\x24\x69\xc6\x95\x32"
+			"\x21\xc8\x11\xe4\xdc\x36\xd7\x93"
+			"\x38\x66\xfb\xb2\x7f\x3a\xb9\xaf"
+			"\x31\xdd\x93\x75\x78\x8a\x2c\x94"
+			"\x87\x1a\x58\xec\x9e\x7d\x4d\xba"
+			"\xe1\xe5\x4d\xfc\xbc\xa4\x2a\x14"
+			"\xef\xcc\xa7\xec\xab\x43\x09\x18"
+			"\xd3\xab\x68\xd1\x07\x99\x44\x47"
+			"\xd6\x83\x85\x3b\x30\xea\xa9\x6b"
+			"\x63\xea\xc4\x07\xfb\x43\x2f\xa4"
+			"\xaa\xb0\xab\x03\x89\xce\x3f\x8c"
+			"\x02\x7c\x86\x54\xbc\x88\xaf\x75"
+			"\xd2\xdc\x63\x17\xd3\x26\xf6\x96"
+			"\xa9\x3c\xf1\x61\x8c\x11\x18\xcc"
+			"\xd6\xea\x5b\xe2\xcd\xf0\xf1\xb2"
+			"\xe5\x35\x90\x1f\x85\x4c\x76\x5b"
+			"\x66\xce\x44\xa4\x32\x9f\xe6\x7b"
+			"\x71\x6e\x9f\x58\x15\x67\x72\x87"
+			"\x64\x8e\x3a\x44\x45\xd4\x76\xfa"
+			"\xc2\xf6\xef\x85\x05\x18\x7a\x9b"
+			"\xba\x41\x54\xac\xf0\xfc\x59\x12"
+			"\x3f\xdf\xa0\xe5\x8a\x65\xfd\x3a"
+			"\x62\x8d\x83\x2c\x03\xbe\x05\x76"
+			"\x2e\x53\x49\x97\x94\x33\xae\x40"
+			"\x81\x15\xdb\x6e\xad\xaa\xf5\x4b"
+			"\xe3\x98\x70\xdf\xe0\x7c\xcd\xdb"
+			"\x02\xd4\x7d\x2f\xc1\xe6\xb4\xf3"
+			"\xd7\x0d\x7a\xd9\x23\x9e\x87\x2d"
+			"\xce\x87\xad\xcc\x72\x05\x00\x29"
+			"\xdc\x73\x7f\x64\xc1\x15\x0e\xc2"
+			"\xdf\xa7\x5f\xeb\x41\xa1\xcd\xef"
+			"\x5c\x50\x79\x2a\x56\x56\x71\x8c"
+			"\xac\xc0\x79\x50\x69\xca\x59\x32"
+			"\x65\xf2\x54\xe4\x52\x38\x76\xd1"
+			"\x5e\xde\x26\x9e\xfb\x75\x2e\x11"
+			"\xb5\x10\xf4\x17\x73\xf5\x89\xc7"
+			"\x4f\x43\x5c\x8e\x7c\xb9\x05\x52"
+			"\x24\x40\x99\xfe\x9b\x85\x0b\x6c"
+			"\x22\x3e\x8b\xae\x86\xa1\xd2\x79"
+			"\x05\x68\x6b\xab\xe3\x41\x49\xed"
+			"\x15\xa1\x8d\x40\x2d\x61\xdf\x1a"
+			"\x59\xc9\x26\x8b\xef\x30\x4c\x88"
+			"\x4b\x10\xf8\x8d\xa6\x92\x9f\x4b"
+			"\xf3\xc4\x53\x0b\x89\x5d\x28\x92"
+			"\xcf\x78\xb2\xc0\x5d\xed\x7e\xfc"
+			"\xc0\x12\x23\x5f\x5a\x78\x86\x43"
+			"\x6e\x27\xf7\x5a\xa7\x6a\xed\x19"
+			"\x04\xf0\xb3\x12\xd1\xbd\x0e\x89"
+			"\x6e\xbc\x96\xa8\xd8\x49\x39\x9f"
+			"\x7e\x67\xf0\x2e\x3e\x01\xa9\xba"
+			"\xec\x8b\x62\x8e\xcb\x4a\x70\x43"
+			"\xc7\xc2\xc4\xca\x82\x03\x73\xe9"
+			"\x11\xdf\xcf\x54\xea\xc9\xb0\x95"
+			"\x51\xc0\x13\x3d\x92\x05\xfa\xf4"
+			"\xa9\x34\xc8\xce\x6c\x3d\x54\xcc"
+			"\xc4\xaf\xf1\xdc\x11\x44\x26\xa2"
+			"\xaf\xf1\x85\x75\x7d\x03\x61\x68"
+			"\x4e\x78\xc6\x92\x7d\x86\x7d\x77"
+			"\xdc\x71\x72\xdb\xc6\xae\xa1\xcb"
+			"\x70\x9a\x0b\x19\xbe\x4a\x6c\x2a"
+			"\xe2\xba\x6c\x64\x9a\x13\x28\xdf"
+			"\x85\x75\xe6\x43\xf6\x87\x08\x68"
+			"\x6e\xba\x6e\x79\x9f\x04\xbc\x23"
+			"\x50\xf6\x33\x5c\x1f\x24\x25\xbe"
+			"\x33\x47\x80\x45\x56\xa3\xa7\xd7"
+			"\x7a\xb1\x34\x0b\x90\x3c\x9c\xad"
+			"\x44\x5f\x9e\x0e\x9d\xd4\xbd\x93"
+			"\x5e\xfa\x3c\xe0\xb0\xd9\xed\xf3"
+			"\xd6\x2e\xff\x24\xd8\x71\x6c\xed"
+			"\xaf\x55\xeb\x22\xac\x93\x68\x32"
+			"\x05\x5b\x47\xdd\xc6\x4a\xcb\xc7"
+			"\x10\xe1\x3c\x92\x1a\xf3\x23\x78"
+			"\x2b\xa1\xd2\x80\xf4\x12\xb1\x20"
+			"\x8f\xff\x26\x35\xdd\xfb\xc7\x4e"
+			"\x78\xf1\x2d\x50\x12\x77\xa8\x60"
+			"\x7c\x0f\xf5\x16\x2f\x63\x70\x2a"
+			"\xc0\x96\x80\x4e\x0a\xb4\x93\x35"
+			"\x5d\x1d\x3f\x56\xf7\x2f\xbb\x90"
+			"\x11\x16\x8f\xa2\xec\x47\xbe\xac"
+			"\x56\x01\x26\x56\xb1\x8c\xb2\x10"
+			"\xf9\x1a\xca\xf5\xd1\xb7\x39\x20"
+			"\x63\xf1\x69\x20\x4f\x13\x12\x1f"
+			"\x5b\x65\xfc\x98\xf7\xc4\x7a\xbe"
+			"\xf7\x26\x4d\x2b\x84\x7b\x42\xad"
+			"\xd8\x7a\x0a\xb4\xd8\x74\xbf\xc1"
+			"\xf0\x6e\xb4\x29\xa3\xbb\xca\x46"
+			"\x67\x70\x6a\x2d\xce\x0e\xa2\x8a"
+			"\xa9\x87\xbf\x05\xc4\xc1\x04\xa3"
+			"\xab\xd4\x45\x43\x8c\xb6\x02\xb0"
+			"\x41\xc8\xfc\x44\x3d\x59\xaa\x2e"
+			"\x44\x21\x2a\x8d\x88\x9d\x57\xf4"
+			"\xa0\x02\x77\xb8\xa6\xa0\xe6\x75"
+			"\x5c\x82\x65\x3e\x03\x5c\x29\x8f"
+			"\x38\x55\xab\x33\x26\xef\x9f\x43"
+			"\x52\xfd\x68\xaf\x36\xb4\xbb\x9a"
+			"\x58\x09\x09\x1b\xc3\x65\x46\x46"
+			"\x1d\xa7\x94\x18\x23\x50\x2c\xca"
+			"\x2c\x55\x19\x97\x01\x9d\x93\x3b"
+			"\x63\x86\xf2\x03\x67\x45\xd2\x72"
+			"\x28\x52\x6c\xf4\xe3\x1c\xb5\x11"
+			"\x13\xf1\xeb\x21\xc7\xd9\x56\x82"
+			"\x2b\x82\x39\xbd\x69\x54\xed\x62"
+			"\xc3\xe2\xde\x73\xd4\x6a\x12\xae"
+			"\x13\x21\x7f\x4b\x5b\xfc\xbf\xe8"
+			"\x2b\xbe\x56\xba\x68\x8b\x9a\xb1"
+			"\x6e\xfa\xbf\x7e\x5a\x4b\xf1\xac"
+			"\x98\x65\x85\xd1\x93\x53\xd3\x7b"
+			"\x09\xdd\x4b\x10\x6d\x84\xb0\x13"
+			"\x65\xbd\xcf\x52\x09\xc4\x85\xe2"
+			"\x84\x74\x15\x65\xb7\xf7\x51\xaf"
+			"\x55\xad\xa4\xd1\x22\x54\x70\x94"
+			"\xa0\x1c\x90\x41\xfd\x99\xd7\x5a"
+			"\x31\xef\xaa\x25\xd0\x7f\x4f\xea"
+			"\x1d\x55\x42\xe5\x49\xb0\xd0\x46"
+			"\x62\x36\x43\xb2\x82\x15\x75\x50"
+			"\xa4\x72\xeb\x54\x27\x1f\x8a\xe4"
+			"\x7d\xe9\x66\xc5\xf1\x53\xa4\xd1"
+			"\x0c\xeb\xb8\xf8\xbc\xd4\xe2\xe7"
+			"\xe1\xf8\x4b\xcb\xa9\xa1\xaf\x15"
+			"\x83\xcb\x72\xd0\x33\x79\x00\x2d"
+			"\x9f\xd7\xf1\x2e\x1e\x10\xe4\x45"
+			"\xc0\x75\x3a\x39\xea\x68\xf7\x5d"
+			"\x1b\x73\x8f\xe9\x8e\x0f\x72\x47"
+			"\xae\x35\x0a\x31\x7a\x14\x4d\x4a"
+			"\x6f\x47\xf7\x7e\x91\x6e\x74\x8b"
+			"\x26\x47\xf9\xc3\xf9\xde\x70\xf5"
+			"\x61\xab\xa9\x27\x9f\x82\xe4\x9c"
+			"\x89\x91\x3f\x2e\x6a\xfd\xb5\x49"
+			"\xe9\xfd\x59\x14\x36\x49\x40\x6d"
+			"\x32\xd8\x85\x42\xf3\xa5\xdf\x0c"
+			"\xa8\x27\xd7\x54\xe2\x63\x2f\xf2"
+			"\x7e\x8b\x8b\xe7\xf1\x9a\x95\x35"
+			"\x43\xdc\x3a\xe4\xb6\xf4\xd0\xdf"
+			"\x9c\xcb\x94\xf3\x21\xa0\x77\x50"
+			"\xe2\xc6\xc4\xc6\x5f\x09\x64\x5b"
+			"\x92\x90\xd8\xe1\xd1\xed\x4b\x42"
+			"\xd7\x37\xaf\x65\x3d\x11\x39\xb6"
+			"\x24\x8a\x60\xae\xd6\x1e\xbf\x0e"
+			"\x0d\xd7\xdc\x96\x0e\x65\x75\x4e"
+			"\x29\x06\x9d\xa4\x51\x3a\x10\x63"
+			"\x8f\x17\x07\xd5\x8e\x3c\xf4\x28"
+			"\x00\x5a\x5b\x05\x19\xd8\xc0\x6c"
+			"\xe5\x15\xe4\x9c\x9d\x71\x9d\x5e"
+			"\x94\x29\x1a\xa7\x80\xfa\x0e\x33"
+			"\x03\xdd\xb7\x3e\x9a\xa9\x26\x18"
+			"\x37\xa9\x64\x08\x4d\x94\x5a\x88"
+			"\xca\x35\xce\x81\x02\xe3\x1f\x1b"
+			"\x89\x1a\x77\x85\xe3\x41\x6d\x32"
+			"\x42\x19\x23\x7d\xc8\x73\xee\x25"
+			"\x85\x0d\xf8\x31\x25\x79\x1b\x6f"
+			"\x79\x25\xd2\xd8\xd4\x23\xfd\xf7"
+			"\x82\x36\x6a\x0c\x46\x22\x15\xe9"
+			"\xff\x72\x41\x91\x91\x7d\x3a\xb7"
+			"\xdd\x65\x99\x70\xf6\x8d\x84\xf8"
+			"\x67\x15\x20\x11\xd6\xb2\x55\x7b"
+			"\xdb\x87\xee\xef\x55\x89\x2a\x59"
+			"\x2b\x07\x8f\x43\x8a\x59\x3c\x01"
+			"\x8b\x65\x54\xa1\x66\xd5\x38\xbd"
+			"\xc6\x30\xa9\xcc\x49\xb6\xa8\x1b"
+			"\xb8\xc0\x0e\xe3\x45\x28\xe2\xff"
+			"\x41\x9f\x7e\x7c\xd1\xae\x9e\x25"
+			"\x3f\x4c\x7c\x7c\xf4\xa8\x26\x4d"
+			"\x5c\xfd\x4b\x27\x18\xf9\x61\x76"
+			"\x48\xba\x0c\x6b\xa9\x4d\xfc\xf5"
+			"\x3b\x35\x7e\x2f\x4a\xa9\xc2\x9a"
+			"\xae\xab\x86\x09\x89\xc9\xc2\x40"
+			"\x39\x2c\x81\xb3\xb8\x17\x67\xc2"
+			"\x0d\x32\x4a\x3a\x67\x81\xd7\x1a"
+			"\x34\x52\xc5\xdb\x0a\xf5\x63\x39"
+			"\xea\x1f\xe1\x7c\xa1\x9e\xc1\x35"
+			"\xe3\xb1\x18\x45\x67\xf9\x22\x38"
+			"\x95\xd9\x34\x34\x86\xc6\x41\x94"
+			"\x15\xf9\x5b\x41\xa6\x87\x8b\xf8"
+			"\xd5\xe1\x1b\xe2\x5b\xf3\x86\x10"
+			"\xff\xe6\xae\x69\x76\xbc\x0d\xb4"
+			"\x09\x90\x0c\xa2\x65\x0c\xad\x74"
+			"\xf5\xd7\xff\xda\xc1\xce\x85\xbe"
+			"\x00\xa7\xff\x4d\x2f\x65\xd3\x8c"
+			"\x86\x2d\x05\xe8\xed\x3e\x6b\x8b"
+			"\x0f\x3d\x83\x8c\xf1\x1d\x5b\x96"
+			"\x2e\xb1\x9c\xc2\x98\xe1\x70\xb9"
+			"\xba\x5c\x8a\x43\xd6\x34\xa7\x2d"
+			"\xc9\x92\xae\xf2\xa5\x7b\x05\x49"
+			"\xa7\x33\x34\x86\xca\xe4\x96\x23"
+			"\x76\x5b\xf2\xc6\xf1\x51\x28\x42"
+			"\x7b\xcc\x76\x8f\xfa\xa2\xad\x31"
+			"\xd4\xd6\x7a\x6d\x25\x25\x54\xe4"
+			"\x3f\x50\x59\xe1\x5c\x05\xb7\x27"
+			"\x48\xbf\x07\xec\x1b\x13\xbe\x2b"
+			"\xa1\x57\x2b\xd5\xab\xd7\xd0\x4c"
+			"\x1e\xcb\x71\x9b\xc5\x90\x85\xd3"
+			"\xde\x59\xec\x71\xeb\x89\xbb\xd0"
+			"\x09\x50\xe1\x16\x3f\xfd\x1c\x34"
+			"\xc3\x1c\xa1\x10\x77\x53\x98\xef"
+			"\xf2\xfd\xa5\x01\x59\xc2\x9b\x26"
+			"\xc7\x42\xd9\x49\xda\x58\x2b\x6e"
+			"\x9f\x53\x19\x76\x7e\xd9\xc9\x0e"
+			"\x68\xc8\x7f\x51\x22\x42\xef\x49"
+			"\xa4\x55\xb6\x36\xac\x09\xc7\x31"
+			"\x88\x15\x4b\x2e\x8f\x3a\x08\xf7"
+			"\xd8\xf7\xa8\xc5\xa9\x33\xa6\x45"
+			"\xe4\xc4\x94\x76\xf3\x0d\x8f\x7e"
+			"\xc8\xf6\xbc\x23\x0a\xb6\x4c\xd3"
+			"\x6a\xcd\x36\xc2\x90\x5c\x5c\x3c"
+			"\x65\x7b\xc2\xd6\xcc\xe6\x0d\x87"
+			"\x73\x2e\x71\x79\x16\x06\x63\x28"
+			"\x09\x15\xd8\x89\x38\x38\x3d\xb5"
+			"\x42\x1c\x08\x24\xf7\x2a\xd2\x9d"
+			"\xc8\xca\xef\xf9\x27\xd8\x07\x86"
+			"\xf7\x43\x0b\x55\x15\x3f\x9f\x83"
+			"\xef\xdc\x49\x9d\x2a\xc1\x54\x62"
+			"\xbd\x9b\x66\x55\x9f\xb7\x12\xf3"
+			"\x1b\x4d\x9d\x2a\x5c\xed\x87\x75"
+			"\x87\x26\xec\x61\x2c\xb4\x0f\x89"
+			"\xb0\xfb\x2e\x68\x5d\x15\xc7\x8d"
+			"\x2e\xc0\xd9\xec\xaf\x4f\xd2\x25"
+			"\x29\xe8\xd2\x26\x2b\x67\xe9\xfc"
+			"\x2b\xa8\x67\x96\x12\x1f\x5b\x96"
+			"\xc6\x14\x53\xaf\x44\xea\xd6\xe2"
+			"\x94\x98\xe4\x12\x93\x4c\x92\xe0"
+			"\x18\xa5\x8d\x2d\xe4\x71\x3c\x47"
+			"\x4c\xf7\xe6\x47\x9e\xc0\x68\xdf"
+			"\xd4\xf5\x5a\x74\xb1\x2b\x29\x03"
+			"\x19\x07\xaf\x90\x62\x5c\x68\x98"
+			"\x48\x16\x11\x02\x9d\xee\xb4\x9b"
+			"\xe5\x42\x7f\x08\xfd\x16\x32\x0b"
+			"\xd0\xb3\xfa\x2b\xb7\x99\xf9\x29"
+			"\xcd\x20\x45\x9f\xb3\x1a\x5d\xa2"
+			"\xaf\x4d\xe0\xbd\x42\x0d\xbc\x74"
+			"\x99\x9c\x8e\x53\x1a\xb4\x3e\xbd"
+			"\xa2\x9a\x2d\xf7\xf8\x39\x0f\x67"
+			"\x63\xfc\x6b\xc0\xaf\xb3\x4b\x4f"
+			"\x55\xc4\xcf\xa7\xc8\x04\x11\x3e"
+			"\x14\x32\xbb\x1b\x38\x77\xd6\x7f"
+			"\x54\x4c\xdf\x75\xf3\x07\x2d\x33"
+			"\x9b\xa8\x20\xe1\x7b\x12\xb5\xf3"
+			"\xef\x2f\xce\x72\xe5\x24\x60\xc1"
+			"\x30\xe2\xab\xa1\x8e\x11\x09\xa8"
+			"\x21\x33\x44\xfe\x7f\x35\x32\x93"
+			"\x39\xa7\xad\x8b\x79\x06\xb2\xcb"
+			"\x4e\xa9\x5f\xc7\xba\x74\x29\xec"
+			"\x93\xa0\x4e\x54\x93\xc0\xbc\x55"
+			"\x64\xf0\x48\xe5\x57\x99\xee\x75"
+			"\xd6\x79\x0f\x66\xb7\xc6\x57\x76"
+			"\xf7\xb7\xf3\x9c\xc5\x60\xe8\x7f"
+			"\x83\x76\xd6\x0e\xaa\xe6\x90\x39"
+			"\x1d\xa6\x32\x6a\x34\xe3\x55\xf8"
+			"\x58\xa0\x58\x7d\x33\xe0\x22\x39"
+			"\x44\x64\x87\x86\x5a\x2f\xa7\x7e"
+			"\x0f\x38\xea\xb0\x30\xcc\x61\xa5"
+			"\x6a\x32\xae\x1e\xf7\xe9\xd0\xa9"
+			"\x0c\x32\x4b\xb5\x49\x28\xab\x85"
+			"\x2f\x8e\x01\x36\x38\x52\xd0\xba"
+			"\xd6\x02\x78\xf8\x0e\x3e\x9c\x8b"
+			"\x6b\x45\x99\x3f\x5c\xfe\x58\xf1"
+			"\x5c\x94\x04\xe1\xf5\x18\x6d\x51"
+			"\xb2\x5d\x18\x20\xb6\xc2\x9a\x42"
+			"\x1d\xb3\xab\x3c\xb6\x3a\x13\x03"
+			"\xb2\x46\x82\x4f\xfc\x64\xbc\x4f"
+			"\xca\xfa\x9c\xc0\xd5\xa7\xbd\x11"
+			"\xb7\xe4\x5a\xf6\x6f\x4d\x4d\x54"
+			"\xea\xa4\x98\x66\xd4\x22\x3b\xd3"
+			"\x8f\x34\x47\xd9\x7c\xf4\x72\x3b"
+			"\x4d\x02\x77\xf6\xd6\xdd\x08\x0a"
+			"\x81\xe1\x86\x89\x3e\x56\x10\x3c"
+			"\xba\xd7\x81\x8c\x08\xbc\x8b\xe2"
+			"\x53\xec\xa7\x89\xee\xc8\x56\xb5"
+			"\x36\x2c\xb2\x03\xba\x99\xdd\x7c"
+			"\x48\xa0\xb0\xbc\x91\x33\xe9\xa8"
+			"\xcb\xcd\xcf\x59\x5f\x1f\x15\xe2"
+			"\x56\xf5\x4e\x01\x35\x27\x45\x77"
+			"\x47\xc8\xbc\xcb\x7e\x39\xc1\x97"
+			"\x28\xd3\x84\xfc\x2c\x3e\xc8\xad"
+			"\x9c\xf8\x8a\x61\x9c\x28\xaa\xc5"
+			"\x99\x20\x43\x85\x9d\xa5\xe2\x8b"
+			"\xb8\xae\xeb\xd0\x32\x0d\x52\x78"
+			"\x09\x56\x3f\xc7\xd8\x7e\x26\xfc"
+			"\x37\xfb\x6f\x04\xfc\xfa\x92\x10"
+			"\xac\xf8\x3e\x21\xdc\x8c\x21\x16"
+			"\x7d\x67\x6e\xf6\xcd\xda\xb6\x98"
+			"\x23\xab\x23\x3c\xb2\x10\xa0\x53"
+			"\x5a\x56\x9f\xc5\xd0\xff\xbb\xe4"
+			"\x98\x3c\x69\x1e\xdb\x38\x8f\x7e"
+			"\x0f\xd2\x98\x88\x81\x8b\x45\x67"
+			"\xea\x33\xf1\xeb\xe9\x97\x55\x2e"
+			"\xd9\xaa\xeb\x5a\xec\xda\xe1\x68"
+			"\xa8\x9d\x3c\x84\x7c\x05\x3d\x62"
+			"\x87\x8f\x03\x21\x28\x95\x0c\x89"
+			"\x25\x22\x4a\xb0\x93\xa9\x50\xa2"
+			"\x2f\x57\x6e\x18\x42\x19\x54\x0c"
+			"\x55\x67\xc6\x11\x49\xf4\x5c\xd2"
+			"\xe9\x3d\xdd\x8b\x48\x71\x21\x00"
+			"\xc3\x9a\x6c\x85\x74\x28\x83\x4a"
+			"\x1b\x31\x05\xe1\x06\x92\xe7\xda"
+			"\x85\x73\x78\x45\x20\x7f\xae\x13"
+			"\x7c\x33\x06\x22\xf4\x83\xf9\x35"
+			"\x3f\x6c\x71\xa8\x4e\x48\xbe\x9b"
+			"\xce\x8a\xba\xda\xbe\x28\x08\xf7"
+			"\xe2\x14\x8c\x71\xea\x72\xf9\x33"
+			"\xf2\x88\x3f\xd7\xbb\x69\x6c\x29"
+			"\x19\xdc\x84\xce\x1f\x12\x4f\xc8"
+			"\xaf\xa5\x04\xba\x5a\xab\xb0\xd9"
+			"\x14\x1f\x6c\x68\x98\x39\x89\x7a"
+			"\xd9\xd8\x2f\xdf\xa8\x47\x4a\x25"
+			"\xe2\xfb\x33\xf4\x59\x78\xe1\x68"
+			"\x85\xcf\xfe\x59\x20\xd4\x05\x1d"
+			"\x80\x99\xae\xbc\xca\xae\x0f\x2f"
+			"\x65\x43\x34\x8e\x7e\xac\xd3\x93"
+			"\x2f\xac\x6d\x14\x3d\x02\x07\x70"
+			"\x9d\xa4\xf3\x1b\x5c\x36\xfc\x01"
+			"\x73\x34\x85\x0c\x6c\xd6\xf1\xbd"
+			"\x3f\xdf\xee\xf5\xd9\xba\x56\xef"
+			"\xf4\x9b\x6b\xee\x9f\x5a\x78\x6d"
+			"\x32\x19\xf4\xf7\xf8\x4c\x69\x0b"
+			"\x4b\xbc\xbb\xb7\xf2\x85\xaf\x70"
+			"\x75\x24\x6c\x54\xa7\x0e\x4d\x1d"
+			"\x01\xbf\x08\xac\xcf\x7f\x2c\xe3"
+			"\x14\x89\x5e\x70\x5a\x99\x92\xcd"
+			"\x01\x84\xc8\xd2\xab\xe5\x4f\x58"
+			"\xe7\x0f\x2f\x0e\xff\x68\xea\xfd"
+			"\x15\xb3\x17\xe6\xb0\xe7\x85\xd8"
+			"\x23\x2e\x05\xc7\xc9\xc4\x46\x1f"
+			"\xe1\x9e\x49\x20\x23\x24\x4d\x7e"
+			"\x29\x65\xff\xf4\xb6\xfd\x1a\x85"
+			"\xc4\x16\xec\xfc\xea\x7b\xd6\x2c"
+			"\x43\xf8\xb7\xbf\x79\xc0\x85\xcd"
+			"\xef\xe1\x98\xd3\xa5\xf7\x90\x8c"
+			"\xe9\x7f\x80\x6b\xd2\xac\x4c\x30"
+			"\xa7\xc6\x61\x6c\xd2\xf9\x2c\xff"
+			"\x30\xbc\x22\x81\x7d\x93\x12\xe4"
+			"\x0a\xcd\xaf\xdd\xe8\xab\x0a\x1e"
+			"\x13\xa4\x27\xc3\x5f\xf7\x4b\xbb"
+			"\x37\x09\x4b\x91\x6f\x92\x4f\xaf"
+			"\x52\xee\xdf\xef\x09\x6f\xf7\x5c"
+			"\x6e\x12\x17\x72\x63\x57\xc7\xba"
+			"\x3b\x6b\x38\x32\x73\x1b\x9c\x80"
+			"\xc1\x7a\xc6\xcf\xcd\x35\xc0\x6b"
+			"\x31\x1a\x6b\xe9\xd8\x2c\x29\x3f"
+			"\x96\xfb\xb6\xcd\x13\x91\x3b\xc2"
+			"\xd2\xa3\x31\x8d\xa4\xcd\x57\xcd"
+			"\x13\x3d\x64\xfd\x06\xce\xe6\xdc"
+			"\x0c\x24\x43\x31\x40\x57\xf1\x72"
+			"\x17\xe3\x3a\x63\x6d\x35\xcf\x5d"
+			"\x97\x40\x59\xdd\xf7\x3c\x02\xf7"
+			"\x1c\x7e\x05\xbb\xa9\x0d\x01\xb1"
+			"\x8e\xc0\x30\xa9\x53\x24\xc9\x89"
+			"\x84\x6d\xaa\xd0\xcd\x91\xc2\x4d"
+			"\x91\xb0\x89\xe2\xbf\x83\x44\xaa"
+			"\x28\x72\x23\xa0\xc2\xad\xad\x1c"
+			"\xfc\x3f\x09\x7a\x0b\xdc\xc5\x1b"
+			"\x87\x13\xc6\x5b\x59\x8d\xf2\xc8"
+			"\xaf\xdf\x11\x95",
+		.rlen	= 4100,
+		.np	= 2,
+		.tap	= { 4064, 36 },
+	},
+};
+
+/*
+ * CTS (Cipher Text Stealing) mode tests
+ */
+#define CTS_MODE_ENC_TEST_VECTORS 6
+#define CTS_MODE_DEC_TEST_VECTORS 6
+static struct cipher_testvec cts_mode_enc_tv_template[] = {
+	{ /* from rfc3962 */
+		.klen	= 16,
+		.key    = "\x63\x68\x69\x63\x6b\x65\x6e\x20"
+			  "\x74\x65\x72\x69\x79\x61\x6b\x69",
+		.ilen	= 17,
+		.input  = "\x49\x20\x77\x6f\x75\x6c\x64\x20"
+			  "\x6c\x69\x6b\x65\x20\x74\x68\x65"
+			  "\x20",
+		.rlen	= 17,
+		.result	= "\xc6\x35\x35\x68\xf2\xbf\x8c\xb4"
+			  "\xd8\xa5\x80\x36\x2d\xa7\xff\x7f"
+			  "\x97",
+	}, {
+		.klen	= 16,
+		.key    = "\x63\x68\x69\x63\x6b\x65\x6e\x20"
+			  "\x74\x65\x72\x69\x79\x61\x6b\x69",
+		.ilen   = 31,
+		.input  = "\x49\x20\x77\x6f\x75\x6c\x64\x20"
+			  "\x6c\x69\x6b\x65\x20\x74\x68\x65"
+			  "\x20\x47\x65\x6e\x65\x72\x61\x6c"
+			  "\x20\x47\x61\x75\x27\x73\x20",
+		.rlen   = 31,
+		.result = "\xfc\x00\x78\x3e\x0e\xfd\xb2\xc1"
+			  "\xd4\x45\xd4\xc8\xef\xf7\xed\x22"
+			  "\x97\x68\x72\x68\xd6\xec\xcc\xc0"
+			  "\xc0\x7b\x25\xe2\x5e\xcf\xe5",
+	}, {
+		.klen	= 16,
+		.key    = "\x63\x68\x69\x63\x6b\x65\x6e\x20"
+			  "\x74\x65\x72\x69\x79\x61\x6b\x69",
+		.ilen   = 32,
+		.input  = "\x49\x20\x77\x6f\x75\x6c\x64\x20"
+			  "\x6c\x69\x6b\x65\x20\x74\x68\x65"
+			  "\x20\x47\x65\x6e\x65\x72\x61\x6c"
+			  "\x20\x47\x61\x75\x27\x73\x20\x43",
+		.rlen   = 32,
+		.result = "\x39\x31\x25\x23\xa7\x86\x62\xd5"
+			  "\xbe\x7f\xcb\xcc\x98\xeb\xf5\xa8"
+			  "\x97\x68\x72\x68\xd6\xec\xcc\xc0"
+			  "\xc0\x7b\x25\xe2\x5e\xcf\xe5\x84",
+	}, {
+		.klen	= 16,
+		.key    = "\x63\x68\x69\x63\x6b\x65\x6e\x20"
+			  "\x74\x65\x72\x69\x79\x61\x6b\x69",
+		.ilen   = 47,
+		.input  = "\x49\x20\x77\x6f\x75\x6c\x64\x20"
+			  "\x6c\x69\x6b\x65\x20\x74\x68\x65"
+			  "\x20\x47\x65\x6e\x65\x72\x61\x6c"
+			  "\x20\x47\x61\x75\x27\x73\x20\x43"
+			  "\x68\x69\x63\x6b\x65\x6e\x2c\x20"
+			  "\x70\x6c\x65\x61\x73\x65\x2c",
+		.rlen   = 47,
+		.result = "\x97\x68\x72\x68\xd6\xec\xcc\xc0"
+			  "\xc0\x7b\x25\xe2\x5e\xcf\xe5\x84"
+			  "\xb3\xff\xfd\x94\x0c\x16\xa1\x8c"
+			  "\x1b\x55\x49\xd2\xf8\x38\x02\x9e"
+			  "\x39\x31\x25\x23\xa7\x86\x62\xd5"
+			  "\xbe\x7f\xcb\xcc\x98\xeb\xf5",
+	}, {
+		.klen	= 16,
+		.key    = "\x63\x68\x69\x63\x6b\x65\x6e\x20"
+			  "\x74\x65\x72\x69\x79\x61\x6b\x69",
+		.ilen   = 48,
+		.input  = "\x49\x20\x77\x6f\x75\x6c\x64\x20"
+			  "\x6c\x69\x6b\x65\x20\x74\x68\x65"
+			  "\x20\x47\x65\x6e\x65\x72\x61\x6c"
+			  "\x20\x47\x61\x75\x27\x73\x20\x43"
+			  "\x68\x69\x63\x6b\x65\x6e\x2c\x20"
+			  "\x70\x6c\x65\x61\x73\x65\x2c\x20",
+		.rlen   = 48,
+		.result = "\x97\x68\x72\x68\xd6\xec\xcc\xc0"
+			  "\xc0\x7b\x25\xe2\x5e\xcf\xe5\x84"
+			  "\x9d\xad\x8b\xbb\x96\xc4\xcd\xc0"
+			  "\x3b\xc1\x03\xe1\xa1\x94\xbb\xd8"
+			  "\x39\x31\x25\x23\xa7\x86\x62\xd5"
+			  "\xbe\x7f\xcb\xcc\x98\xeb\xf5\xa8",
+	}, {
+		.klen	= 16,
+		.key    = "\x63\x68\x69\x63\x6b\x65\x6e\x20"
+			  "\x74\x65\x72\x69\x79\x61\x6b\x69",
+		.ilen   = 64,
+		.input  = "\x49\x20\x77\x6f\x75\x6c\x64\x20"
+			  "\x6c\x69\x6b\x65\x20\x74\x68\x65"
+			  "\x20\x47\x65\x6e\x65\x72\x61\x6c"
+			  "\x20\x47\x61\x75\x27\x73\x20\x43"
+			  "\x68\x69\x63\x6b\x65\x6e\x2c\x20"
+			  "\x70\x6c\x65\x61\x73\x65\x2c\x20"
+			  "\x61\x6e\x64\x20\x77\x6f\x6e\x74"
+			  "\x6f\x6e\x20\x73\x6f\x75\x70\x2e",
+		.rlen   = 64,
+		.result = "\x97\x68\x72\x68\xd6\xec\xcc\xc0"
+			  "\xc0\x7b\x25\xe2\x5e\xcf\xe5\x84"
+			  "\x39\x31\x25\x23\xa7\x86\x62\xd5"
+			  "\xbe\x7f\xcb\xcc\x98\xeb\xf5\xa8"
+			  "\x48\x07\xef\xe8\x36\xee\x89\xa5"
+			  "\x26\x73\x0d\xbc\x2f\x7b\xc8\x40"
+			  "\x9d\xad\x8b\xbb\x96\xc4\xcd\xc0"
+			  "\x3b\xc1\x03\xe1\xa1\x94\xbb\xd8",
+	}
+};
+
+static struct cipher_testvec cts_mode_dec_tv_template[] = {
+	{ /* from rfc3962 */
+		.klen	= 16,
+		.key    = "\x63\x68\x69\x63\x6b\x65\x6e\x20"
+			  "\x74\x65\x72\x69\x79\x61\x6b\x69",
+		.rlen	= 17,
+		.result = "\x49\x20\x77\x6f\x75\x6c\x64\x20"
+			  "\x6c\x69\x6b\x65\x20\x74\x68\x65"
+			  "\x20",
+		.ilen	= 17,
+		.input	= "\xc6\x35\x35\x68\xf2\xbf\x8c\xb4"
+			  "\xd8\xa5\x80\x36\x2d\xa7\xff\x7f"
+			  "\x97",
+	}, {
+		.klen	= 16,
+		.key    = "\x63\x68\x69\x63\x6b\x65\x6e\x20"
+			  "\x74\x65\x72\x69\x79\x61\x6b\x69",
+		.rlen   = 31,
+		.result = "\x49\x20\x77\x6f\x75\x6c\x64\x20"
+			  "\x6c\x69\x6b\x65\x20\x74\x68\x65"
+			  "\x20\x47\x65\x6e\x65\x72\x61\x6c"
+			  "\x20\x47\x61\x75\x27\x73\x20",
+		.ilen   = 31,
+		.input  = "\xfc\x00\x78\x3e\x0e\xfd\xb2\xc1"
+			  "\xd4\x45\xd4\xc8\xef\xf7\xed\x22"
+			  "\x97\x68\x72\x68\xd6\xec\xcc\xc0"
+			  "\xc0\x7b\x25\xe2\x5e\xcf\xe5",
+	}, {
+		.klen	= 16,
+		.key    = "\x63\x68\x69\x63\x6b\x65\x6e\x20"
+			  "\x74\x65\x72\x69\x79\x61\x6b\x69",
+		.rlen   = 32,
+		.result = "\x49\x20\x77\x6f\x75\x6c\x64\x20"
+			  "\x6c\x69\x6b\x65\x20\x74\x68\x65"
+			  "\x20\x47\x65\x6e\x65\x72\x61\x6c"
+			  "\x20\x47\x61\x75\x27\x73\x20\x43",
+		.ilen   = 32,
+		.input  = "\x39\x31\x25\x23\xa7\x86\x62\xd5"
+			  "\xbe\x7f\xcb\xcc\x98\xeb\xf5\xa8"
+			  "\x97\x68\x72\x68\xd6\xec\xcc\xc0"
+			  "\xc0\x7b\x25\xe2\x5e\xcf\xe5\x84",
+	}, {
+		.klen	= 16,
+		.key    = "\x63\x68\x69\x63\x6b\x65\x6e\x20"
+			  "\x74\x65\x72\x69\x79\x61\x6b\x69",
+		.rlen   = 47,
+		.result = "\x49\x20\x77\x6f\x75\x6c\x64\x20"
+			  "\x6c\x69\x6b\x65\x20\x74\x68\x65"
+			  "\x20\x47\x65\x6e\x65\x72\x61\x6c"
+			  "\x20\x47\x61\x75\x27\x73\x20\x43"
+			  "\x68\x69\x63\x6b\x65\x6e\x2c\x20"
+			  "\x70\x6c\x65\x61\x73\x65\x2c",
+		.ilen   = 47,
+		.input  = "\x97\x68\x72\x68\xd6\xec\xcc\xc0"
+			  "\xc0\x7b\x25\xe2\x5e\xcf\xe5\x84"
+			  "\xb3\xff\xfd\x94\x0c\x16\xa1\x8c"
+			  "\x1b\x55\x49\xd2\xf8\x38\x02\x9e"
+			  "\x39\x31\x25\x23\xa7\x86\x62\xd5"
+			  "\xbe\x7f\xcb\xcc\x98\xeb\xf5",
+	}, {
+		.klen	= 16,
+		.key    = "\x63\x68\x69\x63\x6b\x65\x6e\x20"
+			  "\x74\x65\x72\x69\x79\x61\x6b\x69",
+		.rlen   = 48,
+		.result = "\x49\x20\x77\x6f\x75\x6c\x64\x20"
+			  "\x6c\x69\x6b\x65\x20\x74\x68\x65"
+			  "\x20\x47\x65\x6e\x65\x72\x61\x6c"
+			  "\x20\x47\x61\x75\x27\x73\x20\x43"
+			  "\x68\x69\x63\x6b\x65\x6e\x2c\x20"
+			  "\x70\x6c\x65\x61\x73\x65\x2c\x20",
+		.ilen   = 48,
+		.input  = "\x97\x68\x72\x68\xd6\xec\xcc\xc0"
+			  "\xc0\x7b\x25\xe2\x5e\xcf\xe5\x84"
+			  "\x9d\xad\x8b\xbb\x96\xc4\xcd\xc0"
+			  "\x3b\xc1\x03\xe1\xa1\x94\xbb\xd8"
+			  "\x39\x31\x25\x23\xa7\x86\x62\xd5"
+			  "\xbe\x7f\xcb\xcc\x98\xeb\xf5\xa8",
+	}, {
+		.klen	= 16,
+		.key    = "\x63\x68\x69\x63\x6b\x65\x6e\x20"
+			  "\x74\x65\x72\x69\x79\x61\x6b\x69",
+		.rlen   = 64,
+		.result = "\x49\x20\x77\x6f\x75\x6c\x64\x20"
+			  "\x6c\x69\x6b\x65\x20\x74\x68\x65"
+			  "\x20\x47\x65\x6e\x65\x72\x61\x6c"
+			  "\x20\x47\x61\x75\x27\x73\x20\x43"
+			  "\x68\x69\x63\x6b\x65\x6e\x2c\x20"
+			  "\x70\x6c\x65\x61\x73\x65\x2c\x20"
+			  "\x61\x6e\x64\x20\x77\x6f\x6e\x74"
+			  "\x6f\x6e\x20\x73\x6f\x75\x70\x2e",
+		.ilen   = 64,
+		.input  = "\x97\x68\x72\x68\xd6\xec\xcc\xc0"
+			  "\xc0\x7b\x25\xe2\x5e\xcf\xe5\x84"
+			  "\x39\x31\x25\x23\xa7\x86\x62\xd5"
+			  "\xbe\x7f\xcb\xcc\x98\xeb\xf5\xa8"
+			  "\x48\x07\xef\xe8\x36\xee\x89\xa5"
+			  "\x26\x73\x0d\xbc\x2f\x7b\xc8\x40"
+			  "\x9d\xad\x8b\xbb\x96\xc4\xcd\xc0"
+			  "\x3b\xc1\x03\xe1\xa1\x94\xbb\xd8",
+	}
+};
+
+/*
+ * Compression stuff.
+ */
+#define COMP_BUF_SIZE           512
+
+struct comp_testvec {
+	int inlen, outlen;
+	char input[COMP_BUF_SIZE];
+	char output[COMP_BUF_SIZE];
+};
+
+/*
+ * Deflate test vectors (null-terminated strings).
+ * Params: winbits=11, Z_DEFAULT_COMPRESSION, MAX_MEM_LEVEL.
+ */
+#define DEFLATE_COMP_TEST_VECTORS 2
+#define DEFLATE_DECOMP_TEST_VECTORS 2
+
+static struct comp_testvec deflate_comp_tv_template[] = {
+	{
+		.inlen	= 70,
+		.outlen	= 38,
+		.input	= "Join us now and share the software "
+			"Join us now and share the software ",
+		.output	= "\xf3\xca\xcf\xcc\x53\x28\x2d\x56"
+			  "\xc8\xcb\x2f\x57\x48\xcc\x4b\x51"
+			  "\x28\xce\x48\x2c\x4a\x55\x28\xc9"
+			  "\x48\x55\x28\xce\x4f\x2b\x29\x07"
+			  "\x71\xbc\x08\x2b\x01\x00",
+	}, {
+		.inlen	= 191,
+		.outlen	= 122,
+		.input	= "This document describes a compression method based on the DEFLATE"
+			"compression algorithm.  This document defines the application of "
+			"the DEFLATE algorithm to the IP Payload Compression Protocol.",
+		.output	= "\x5d\x8d\x31\x0e\xc2\x30\x10\x04"
+			  "\xbf\xb2\x2f\xc8\x1f\x10\x04\x09"
+			  "\x89\xc2\x85\x3f\x70\xb1\x2f\xf8"
+			  "\x24\xdb\x67\xd9\x47\xc1\xef\x49"
+			  "\x68\x12\x51\xae\x76\x67\xd6\x27"
+			  "\x19\x88\x1a\xde\x85\xab\x21\xf2"
+			  "\x08\x5d\x16\x1e\x20\x04\x2d\xad"
+			  "\xf3\x18\xa2\x15\x85\x2d\x69\xc4"
+			  "\x42\x83\x23\xb6\x6c\x89\x71\x9b"
+			  "\xef\xcf\x8b\x9f\xcf\x33\xca\x2f"
+			  "\xed\x62\xa9\x4c\x80\xff\x13\xaf"
+			  "\x52\x37\xed\x0e\x52\x6b\x59\x02"
+			  "\xd9\x4e\xe8\x7a\x76\x1d\x02\x98"
+			  "\xfe\x8a\x87\x83\xa3\x4f\x56\x8a"
+			  "\xb8\x9e\x8e\x5c\x57\xd3\xa0\x79"
+			  "\xfa\x02",
+	},
+};
+
+static struct comp_testvec deflate_decomp_tv_template[] = {
+	{
+		.inlen	= 122,
+		.outlen	= 191,
+		.input	= "\x5d\x8d\x31\x0e\xc2\x30\x10\x04"
+			  "\xbf\xb2\x2f\xc8\x1f\x10\x04\x09"
+			  "\x89\xc2\x85\x3f\x70\xb1\x2f\xf8"
+			  "\x24\xdb\x67\xd9\x47\xc1\xef\x49"
+			  "\x68\x12\x51\xae\x76\x67\xd6\x27"
+			  "\x19\x88\x1a\xde\x85\xab\x21\xf2"
+			  "\x08\x5d\x16\x1e\x20\x04\x2d\xad"
+			  "\xf3\x18\xa2\x15\x85\x2d\x69\xc4"
+			  "\x42\x83\x23\xb6\x6c\x89\x71\x9b"
+			  "\xef\xcf\x8b\x9f\xcf\x33\xca\x2f"
+			  "\xed\x62\xa9\x4c\x80\xff\x13\xaf"
+			  "\x52\x37\xed\x0e\x52\x6b\x59\x02"
+			  "\xd9\x4e\xe8\x7a\x76\x1d\x02\x98"
+			  "\xfe\x8a\x87\x83\xa3\x4f\x56\x8a"
+			  "\xb8\x9e\x8e\x5c\x57\xd3\xa0\x79"
+			  "\xfa\x02",
+		.output	= "This document describes a compression method based on the DEFLATE"
+			"compression algorithm.  This document defines the application of "
+			"the DEFLATE algorithm to the IP Payload Compression Protocol.",
+	}, {
+		.inlen	= 38,
+		.outlen	= 70,
+		.input	= "\xf3\xca\xcf\xcc\x53\x28\x2d\x56"
+			  "\xc8\xcb\x2f\x57\x48\xcc\x4b\x51"
+			  "\x28\xce\x48\x2c\x4a\x55\x28\xc9"
+			  "\x48\x55\x28\xce\x4f\x2b\x29\x07"
+			  "\x71\xbc\x08\x2b\x01\x00",
+		.output	= "Join us now and share the software "
+			"Join us now and share the software ",
+	},
+};
+
+/*
+ * LZO test vectors (null-terminated strings).
+ */
+#define LZO_COMP_TEST_VECTORS 2
+#define LZO_DECOMP_TEST_VECTORS 2
+
+static struct comp_testvec lzo_comp_tv_template[] = {
+	{
+		.inlen	= 70,
+		.outlen	= 46,
+		.input	= "Join us now and share the software "
+			"Join us now and share the software ",
+		.output	= "\x00\x0d\x4a\x6f\x69\x6e\x20\x75"
+			"\x73\x20\x6e\x6f\x77\x20\x61\x6e"
+			"\x64\x20\x73\x68\x61\x72\x65\x20"
+			"\x74\x68\x65\x20\x73\x6f\x66\x74"
+			"\x77\x70\x01\x01\x4a\x6f\x69\x6e"
+			"\x3d\x88\x00\x11\x00\x00",
+	}, {
+		.inlen	= 159,
+		.outlen	= 133,
+		.input	= "This document describes a compression method based on the LZO "
+			"compression algorithm.  This document defines the application of "
+			"the LZO algorithm used in UBIFS.",
+		.output	= "\x00\x2b\x54\x68\x69\x73\x20\x64"
+			  "\x6f\x63\x75\x6d\x65\x6e\x74\x20"
+			  "\x64\x65\x73\x63\x72\x69\x62\x65"
+			  "\x73\x20\x61\x20\x63\x6f\x6d\x70"
+			  "\x72\x65\x73\x73\x69\x6f\x6e\x20"
+			  "\x6d\x65\x74\x68\x6f\x64\x20\x62"
+			  "\x61\x73\x65\x64\x20\x6f\x6e\x20"
+			  "\x74\x68\x65\x20\x4c\x5a\x4f\x2b"
+			  "\x8c\x00\x0d\x61\x6c\x67\x6f\x72"
+			  "\x69\x74\x68\x6d\x2e\x20\x20\x54"
+			  "\x68\x69\x73\x2a\x54\x01\x02\x66"
+			  "\x69\x6e\x65\x73\x94\x06\x05\x61"
+			  "\x70\x70\x6c\x69\x63\x61\x74\x76"
+			  "\x0a\x6f\x66\x88\x02\x60\x09\x27"
+			  "\xf0\x00\x0c\x20\x75\x73\x65\x64"
+			  "\x20\x69\x6e\x20\x55\x42\x49\x46"
+			  "\x53\x2e\x11\x00\x00",
+	},
+};
+
+static struct comp_testvec lzo_decomp_tv_template[] = {
+	{
+		.inlen	= 133,
+		.outlen	= 159,
+		.input	= "\x00\x2b\x54\x68\x69\x73\x20\x64"
+			  "\x6f\x63\x75\x6d\x65\x6e\x74\x20"
+			  "\x64\x65\x73\x63\x72\x69\x62\x65"
+			  "\x73\x20\x61\x20\x63\x6f\x6d\x70"
+			  "\x72\x65\x73\x73\x69\x6f\x6e\x20"
+			  "\x6d\x65\x74\x68\x6f\x64\x20\x62"
+			  "\x61\x73\x65\x64\x20\x6f\x6e\x20"
+			  "\x74\x68\x65\x20\x4c\x5a\x4f\x2b"
+			  "\x8c\x00\x0d\x61\x6c\x67\x6f\x72"
+			  "\x69\x74\x68\x6d\x2e\x20\x20\x54"
+			  "\x68\x69\x73\x2a\x54\x01\x02\x66"
+			  "\x69\x6e\x65\x73\x94\x06\x05\x61"
+			  "\x70\x70\x6c\x69\x63\x61\x74\x76"
+			  "\x0a\x6f\x66\x88\x02\x60\x09\x27"
+			  "\xf0\x00\x0c\x20\x75\x73\x65\x64"
+			  "\x20\x69\x6e\x20\x55\x42\x49\x46"
+			  "\x53\x2e\x11\x00\x00",
+		.output	= "This document describes a compression method based on the LZO "
+			"compression algorithm.  This document defines the application of "
+			"the LZO algorithm used in UBIFS.",
+	}, {
+		.inlen	= 46,
+		.outlen	= 70,
+		.input	= "\x00\x0d\x4a\x6f\x69\x6e\x20\x75"
+			  "\x73\x20\x6e\x6f\x77\x20\x61\x6e"
+			  "\x64\x20\x73\x68\x61\x72\x65\x20"
+			  "\x74\x68\x65\x20\x73\x6f\x66\x74"
+			  "\x77\x70\x01\x01\x4a\x6f\x69\x6e"
+			  "\x3d\x88\x00\x11\x00\x00",
+		.output	= "Join us now and share the software "
+			"Join us now and share the software ",
+	},
+};
+
+/*
+ * Michael MIC test vectors from IEEE 802.11i
+ */
+#define MICHAEL_MIC_TEST_VECTORS 6
+
+static struct hash_testvec michael_mic_tv_template[] = {
+	{
+		.key = "\x00\x00\x00\x00\x00\x00\x00\x00",
+		.ksize = 8,
+		.plaintext = zeroed_string,
+		.psize = 0,
+		.digest = "\x82\x92\x5c\x1c\xa1\xd1\x30\xb8",
+	},
+	{
+		.key = "\x82\x92\x5c\x1c\xa1\xd1\x30\xb8",
+		.ksize = 8,
+		.plaintext = "M",
+		.psize = 1,
+		.digest = "\x43\x47\x21\xca\x40\x63\x9b\x3f",
+	},
+	{
+		.key = "\x43\x47\x21\xca\x40\x63\x9b\x3f",
+		.ksize = 8,
+		.plaintext = "Mi",
+		.psize = 2,
+		.digest = "\xe8\xf9\xbe\xca\xe9\x7e\x5d\x29",
+	},
+	{
+		.key = "\xe8\xf9\xbe\xca\xe9\x7e\x5d\x29",
+		.ksize = 8,
+		.plaintext = "Mic",
+		.psize = 3,
+		.digest = "\x90\x03\x8f\xc6\xcf\x13\xc1\xdb",
+	},
+	{
+		.key = "\x90\x03\x8f\xc6\xcf\x13\xc1\xdb",
+		.ksize = 8,
+		.plaintext = "Mich",
+		.psize = 4,
+		.digest = "\xd5\x5e\x10\x05\x10\x12\x89\x86",
+	},
+	{
+		.key = "\xd5\x5e\x10\x05\x10\x12\x89\x86",
+		.ksize = 8,
+		.plaintext = "Michael",
+		.psize = 7,
+		.digest = "\x0a\x94\x2b\x12\x4e\xca\xa5\x46",
+	}
+};
+
+/*
+ * CRC32C test vectors
+ */
+#define CRC32C_TEST_VECTORS 14
+
+static struct hash_testvec crc32c_tv_template[] = {
+	{
+		.psize = 0,
+		.digest = "\x00\x00\x00\x00",
+	},
+	{
+		.key = "\x87\xa9\xcb\xed",
+		.ksize = 4,
+		.psize = 0,
+		.digest = "\x78\x56\x34\x12",
+	},
+	{
+		.key = "\xff\xff\xff\xff",
+		.ksize = 4,
+		.plaintext = "\x01\x02\x03\x04\x05\x06\x07\x08"
+			     "\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10"
+			     "\x11\x12\x13\x14\x15\x16\x17\x18"
+			     "\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20"
+			     "\x21\x22\x23\x24\x25\x26\x27\x28",
+		.psize = 40,
+		.digest = "\x7f\x15\x2c\x0e",
+	},
+	{
+		.key = "\xff\xff\xff\xff",
+		.ksize = 4,
+		.plaintext = "\x29\x2a\x2b\x2c\x2d\x2e\x2f\x30"
+			     "\x31\x32\x33\x34\x35\x36\x37\x38"
+			     "\x39\x3a\x3b\x3c\x3d\x3e\x3f\x40"
+			     "\x41\x42\x43\x44\x45\x46\x47\x48"
+			     "\x49\x4a\x4b\x4c\x4d\x4e\x4f\x50",
+		.psize = 40,
+		.digest = "\xf6\xeb\x80\xe9",
+	},
+	{
+		.key = "\xff\xff\xff\xff",
+		.ksize = 4,
+		.plaintext = "\x51\x52\x53\x54\x55\x56\x57\x58"
+			     "\x59\x5a\x5b\x5c\x5d\x5e\x5f\x60"
+			     "\x61\x62\x63\x64\x65\x66\x67\x68"
+			     "\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70"
+			     "\x71\x72\x73\x74\x75\x76\x77\x78",
+		.psize = 40,
+		.digest = "\xed\xbd\x74\xde",
+	},
+	{
+		.key = "\xff\xff\xff\xff",
+		.ksize = 4,
+		.plaintext = "\x79\x7a\x7b\x7c\x7d\x7e\x7f\x80"
+			     "\x81\x82\x83\x84\x85\x86\x87\x88"
+			     "\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90"
+			     "\x91\x92\x93\x94\x95\x96\x97\x98"
+			     "\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0",
+		.psize = 40,
+		.digest = "\x62\xc8\x79\xd5",
+	},
+	{
+		.key = "\xff\xff\xff\xff",
+		.ksize = 4,
+		.plaintext = "\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8"
+			     "\xa9\xaa\xab\xac\xad\xae\xaf\xb0"
+			     "\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8"
+			     "\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0"
+			     "\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8",
+		.psize = 40,
+		.digest = "\xd0\x9a\x97\xba",
+	},
+	{
+		.key = "\xff\xff\xff\xff",
+		.ksize = 4,
+		.plaintext = "\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0"
+			     "\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8"
+			     "\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0"
+			     "\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8"
+			     "\xe9\xea\xeb\xec\xed\xee\xef\xf0",
+		.psize = 40,
+		.digest = "\x13\xd9\x29\x2b",
+	},
+	{
+		.key = "\x80\xea\xd3\xf1",
+		.ksize = 4,
+		.plaintext = "\x29\x2a\x2b\x2c\x2d\x2e\x2f\x30"
+			     "\x31\x32\x33\x34\x35\x36\x37\x38"
+			     "\x39\x3a\x3b\x3c\x3d\x3e\x3f\x40"
+			     "\x41\x42\x43\x44\x45\x46\x47\x48"
+			     "\x49\x4a\x4b\x4c\x4d\x4e\x4f\x50",
+		.psize = 40,
+		.digest = "\x0c\xb5\xe2\xa2",
+	},
+	{
+		.key = "\xf3\x4a\x1d\x5d",
+		.ksize = 4,
+		.plaintext = "\x51\x52\x53\x54\x55\x56\x57\x58"
+			     "\x59\x5a\x5b\x5c\x5d\x5e\x5f\x60"
+			     "\x61\x62\x63\x64\x65\x66\x67\x68"
+			     "\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70"
+			     "\x71\x72\x73\x74\x75\x76\x77\x78",
+		.psize = 40,
+		.digest = "\xd1\x7f\xfb\xa6",
+	},
+	{
+		.key = "\x2e\x80\x04\x59",
+		.ksize = 4,
+		.plaintext = "\x79\x7a\x7b\x7c\x7d\x7e\x7f\x80"
+			     "\x81\x82\x83\x84\x85\x86\x87\x88"
+			     "\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90"
+			     "\x91\x92\x93\x94\x95\x96\x97\x98"
+			     "\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0",
+		.psize = 40,
+		.digest = "\x59\x33\xe6\x7a",
+	},
+	{
+		.key = "\xa6\xcc\x19\x85",
+		.ksize = 4,
+		.plaintext = "\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8"
+			     "\xa9\xaa\xab\xac\xad\xae\xaf\xb0"
+			     "\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8"
+			     "\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0"
+			     "\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8",
+		.psize = 40,
+		.digest = "\xbe\x03\x01\xd2",
+	},
+	{
+		.key = "\x41\xfc\xfe\x2d",
+		.ksize = 4,
+		.plaintext = "\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0"
+			     "\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8"
+			     "\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0"
+			     "\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8"
+			     "\xe9\xea\xeb\xec\xed\xee\xef\xf0",
+		.psize = 40,
+		.digest = "\x75\xd3\xc5\x24",
+	},
+	{
+		.key = "\xff\xff\xff\xff",
+		.ksize = 4,
+		.plaintext = "\x01\x02\x03\x04\x05\x06\x07\x08"
+			     "\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10"
+			     "\x11\x12\x13\x14\x15\x16\x17\x18"
+			     "\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20"
+			     "\x21\x22\x23\x24\x25\x26\x27\x28"
+			     "\x29\x2a\x2b\x2c\x2d\x2e\x2f\x30"
+			     "\x31\x32\x33\x34\x35\x36\x37\x38"
+			     "\x39\x3a\x3b\x3c\x3d\x3e\x3f\x40"
+			     "\x41\x42\x43\x44\x45\x46\x47\x48"
+			     "\x49\x4a\x4b\x4c\x4d\x4e\x4f\x50"
+			     "\x51\x52\x53\x54\x55\x56\x57\x58"
+			     "\x59\x5a\x5b\x5c\x5d\x5e\x5f\x60"
+			     "\x61\x62\x63\x64\x65\x66\x67\x68"
+			     "\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70"
+			     "\x71\x72\x73\x74\x75\x76\x77\x78"
+			     "\x79\x7a\x7b\x7c\x7d\x7e\x7f\x80"
+			     "\x81\x82\x83\x84\x85\x86\x87\x88"
+			     "\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90"
+			     "\x91\x92\x93\x94\x95\x96\x97\x98"
+			     "\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0"
+			     "\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8"
+			     "\xa9\xaa\xab\xac\xad\xae\xaf\xb0"
+			     "\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8"
+			     "\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0"
+			     "\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8"
+			     "\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0"
+			     "\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8"
+			     "\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0"
+			     "\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8"
+			     "\xe9\xea\xeb\xec\xed\xee\xef\xf0",
+		.psize = 240,
+		.digest = "\x75\xd3\xc5\x24",
+		.np = 2,
+		.tap = { 31, 209 }
+	},
+};
+
+#endif	/* _CRYPTO_TESTMGR_H */
diff --git a/drivers/accessibility/braille/braille_console.c b/drivers/accessibility/braille/braille_console.c
index 0a5f6b2..d672cfe 100644
--- a/drivers/accessibility/braille/braille_console.c
+++ b/drivers/accessibility/braille/braille_console.c
@@ -376,6 +376,8 @@
 	console->flags |= CON_ENABLED;
 	console->index = index;
 	braille_co = console;
+	register_keyboard_notifier(&keyboard_notifier_block);
+	register_vt_notifier(&vt_notifier_block);
 	return 0;
 }
 
@@ -383,15 +385,8 @@
 {
 	if (braille_co != console)
 		return -EINVAL;
+	unregister_keyboard_notifier(&keyboard_notifier_block);
+	unregister_vt_notifier(&vt_notifier_block);
 	braille_co = NULL;
 	return 0;
 }
-
-static int __init braille_init(void)
-{
-	register_keyboard_notifier(&keyboard_notifier_block);
-	register_vt_notifier(&vt_notifier_block);
-	return 0;
-}
-
-console_initcall(braille_init);
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index 735f5ea..da49b00 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -259,7 +259,10 @@
 
 config ACPI_TOSHIBA
 	tristate "Toshiba Laptop Extras"
-	depends on X86
+	depends on X86 && INPUT
+	select INPUT_POLLDEV
+	select NET
+	select RFKILL
 	select BACKLIGHT_CLASS_DEVICE
 	---help---
 	  This driver adds support for access to certain system settings
diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c
index 0841095..24649ad 100644
--- a/drivers/acpi/glue.c
+++ b/drivers/acpi/glue.c
@@ -165,8 +165,11 @@
 				"firmware_node");
 		ret = sysfs_create_link(&acpi_dev->dev.kobj, &dev->kobj,
 				"physical_node");
-		if (acpi_dev->wakeup.flags.valid)
+		if (acpi_dev->wakeup.flags.valid) {
 			device_set_wakeup_capable(dev, true);
+			device_set_wakeup_enable(dev,
+						acpi_dev->wakeup.state.enabled);
+		}
 	}
 
 	return 0;
@@ -257,116 +260,3 @@
 }
 
 arch_initcall(init_acpi_device_notify);
-
-
-#if defined(CONFIG_RTC_DRV_CMOS) || defined(CONFIG_RTC_DRV_CMOS_MODULE)
-
-#ifdef CONFIG_PM
-static u32 rtc_handler(void *context)
-{
-	acpi_clear_event(ACPI_EVENT_RTC);
-	acpi_disable_event(ACPI_EVENT_RTC, 0);
-	return ACPI_INTERRUPT_HANDLED;
-}
-
-static inline void rtc_wake_setup(void)
-{
-	acpi_install_fixed_event_handler(ACPI_EVENT_RTC, rtc_handler, NULL);
-	/*
-	 * After the RTC handler is installed, the Fixed_RTC event should
-	 * be disabled. Only when the RTC alarm is set will it be enabled.
-	 */
-	acpi_clear_event(ACPI_EVENT_RTC);
-	acpi_disable_event(ACPI_EVENT_RTC, 0);
-}
-
-static void rtc_wake_on(struct device *dev)
-{
-	acpi_clear_event(ACPI_EVENT_RTC);
-	acpi_enable_event(ACPI_EVENT_RTC, 0);
-}
-
-static void rtc_wake_off(struct device *dev)
-{
-	acpi_disable_event(ACPI_EVENT_RTC, 0);
-}
-#else
-#define rtc_wake_setup()	do{}while(0)
-#define rtc_wake_on		NULL
-#define rtc_wake_off		NULL
-#endif
-
-/* Every ACPI platform has a mc146818 compatible "cmos rtc".  Here we find
- * its device node and pass extra config data.  This helps its driver use
- * capabilities that the now-obsolete mc146818 didn't have, and informs it
- * that this board's RTC is wakeup-capable (per ACPI spec).
- */
-#include <linux/mc146818rtc.h>
-
-static struct cmos_rtc_board_info rtc_info;
-
-
-/* PNP devices are registered in a subsys_initcall();
- * ACPI specifies the PNP IDs to use.
- */
-#include <linux/pnp.h>
-
-static int __init pnp_match(struct device *dev, void *data)
-{
-	static const char *ids[] = { "PNP0b00", "PNP0b01", "PNP0b02", };
-	struct pnp_dev *pnp = to_pnp_dev(dev);
-	int i;
-
-	for (i = 0; i < ARRAY_SIZE(ids); i++) {
-		if (compare_pnp_id(pnp->id, ids[i]) != 0)
-			return 1;
-	}
-	return 0;
-}
-
-static struct device *__init get_rtc_dev(void)
-{
-	return bus_find_device(&pnp_bus_type, NULL, NULL, pnp_match);
-}
-
-static int __init acpi_rtc_init(void)
-{
-	struct device *dev = get_rtc_dev();
-
-	if (acpi_disabled)
-		return 0;
-
-	if (dev) {
-		rtc_wake_setup();
-		rtc_info.wake_on = rtc_wake_on;
-		rtc_info.wake_off = rtc_wake_off;
-
-		/* workaround bug in some ACPI tables */
-		if (acpi_gbl_FADT.month_alarm && !acpi_gbl_FADT.day_alarm) {
-			DBG("bogus FADT month_alarm\n");
-			acpi_gbl_FADT.month_alarm = 0;
-		}
-
-		rtc_info.rtc_day_alarm = acpi_gbl_FADT.day_alarm;
-		rtc_info.rtc_mon_alarm = acpi_gbl_FADT.month_alarm;
-		rtc_info.rtc_century = acpi_gbl_FADT.century;
-
-		/* NOTE:  S4_RTC_WAKE is NOT currently useful to Linux */
-		if (acpi_gbl_FADT.flags & ACPI_FADT_S4_RTC_WAKE)
-			printk(PREFIX "RTC can wake from S4\n");
-
-
-		dev->platform_data = &rtc_info;
-
-		/* RTC always wakes from S1/S2/S3, and often S4/STD */
-		device_init_wakeup(dev, 1);
-
-		put_device(dev);
-	} else
-		DBG("RTC unavailable?\n");
-	return 0;
-}
-/* do this between RTC subsys_initcall() and rtc_cmos driver_initcall() */
-fs_initcall(acpi_rtc_init);
-
-#endif
diff --git a/drivers/acpi/sleep/proc.c b/drivers/acpi/sleep/proc.c
index 4ebbba2..bf5b04d 100644
--- a/drivers/acpi/sleep/proc.c
+++ b/drivers/acpi/sleep/proc.c
@@ -377,6 +377,14 @@
 	return 0;
 }
 
+static void physical_device_enable_wakeup(struct acpi_device *adev)
+{
+	struct device *dev = acpi_get_physical_device(adev->handle);
+
+	if (dev && device_can_wakeup(dev))
+		device_set_wakeup_enable(dev, adev->wakeup.state.enabled);
+}
+
 static ssize_t
 acpi_system_write_wakeup_device(struct file *file,
 				const char __user * buffer,
@@ -411,6 +419,7 @@
 		}
 	}
 	if (found_dev) {
+		physical_device_enable_wakeup(found_dev);
 		list_for_each_safe(node, next, &acpi_wakeup_device_list) {
 			struct acpi_device *dev = container_of(node,
 							       struct
@@ -428,6 +437,7 @@
 				       dev->pnp.bus_id, found_dev->pnp.bus_id);
 				dev->wakeup.state.enabled =
 				    found_dev->wakeup.state.enabled;
+				physical_device_enable_wakeup(dev);
 			}
 		}
 	}
diff --git a/drivers/acpi/toshiba_acpi.c b/drivers/acpi/toshiba_acpi.c
index 0a43c8e..8a649f4 100644
--- a/drivers/acpi/toshiba_acpi.c
+++ b/drivers/acpi/toshiba_acpi.c
@@ -3,6 +3,7 @@
  *
  *
  *  Copyright (C) 2002-2004 John Belmonte
+ *  Copyright (C) 2008 Philip Langdale
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -33,7 +34,7 @@
  *
  */
 
-#define TOSHIBA_ACPI_VERSION	"0.18"
+#define TOSHIBA_ACPI_VERSION	"0.19"
 #define PROC_INTERFACE_VERSION	1
 
 #include <linux/kernel.h>
@@ -42,6 +43,9 @@
 #include <linux/types.h>
 #include <linux/proc_fs.h>
 #include <linux/backlight.h>
+#include <linux/platform_device.h>
+#include <linux/rfkill.h>
+#include <linux/input-polldev.h>
 
 #include <asm/uaccess.h>
 
@@ -90,6 +94,7 @@
 #define HCI_VIDEO_OUT			0x001c
 #define HCI_HOTKEY_EVENT		0x001e
 #define HCI_LCD_BRIGHTNESS		0x002a
+#define HCI_WIRELESS			0x0056
 
 /* field definitions */
 #define HCI_LCD_BRIGHTNESS_BITS		3
@@ -98,9 +103,14 @@
 #define HCI_VIDEO_OUT_LCD		0x1
 #define HCI_VIDEO_OUT_CRT		0x2
 #define HCI_VIDEO_OUT_TV		0x4
+#define HCI_WIRELESS_KILL_SWITCH	0x01
+#define HCI_WIRELESS_BT_PRESENT		0x0f
+#define HCI_WIRELESS_BT_ATTACH		0x40
+#define HCI_WIRELESS_BT_POWER		0x80
 
 static const struct acpi_device_id toshiba_device_ids[] = {
 	{"TOS6200", 0},
+	{"TOS6208", 0},
 	{"TOS1900", 0},
 	{"", 0},
 };
@@ -193,7 +203,7 @@
 	return status;
 }
 
-/* common hci tasks (get or set one value)
+/* common hci tasks (get or set one or two value)
  *
  * In addition to the ACPI status, the HCI system returns a result which
  * may be useful (such as "not supported").
@@ -218,6 +228,152 @@
 	return status;
 }
 
+static acpi_status hci_write2(u32 reg, u32 in1, u32 in2, u32 *result)
+{
+	u32 in[HCI_WORDS] = { HCI_SET, reg, in1, in2, 0, 0 };
+	u32 out[HCI_WORDS];
+	acpi_status status = hci_raw(in, out);
+	*result = (status == AE_OK) ? out[0] : HCI_FAILURE;
+	return status;
+}
+
+static acpi_status hci_read2(u32 reg, u32 *out1, u32 *out2, u32 *result)
+{
+	u32 in[HCI_WORDS] = { HCI_GET, reg, *out1, *out2, 0, 0 };
+	u32 out[HCI_WORDS];
+	acpi_status status = hci_raw(in, out);
+	*out1 = out[2];
+	*out2 = out[3];
+	*result = (status == AE_OK) ? out[0] : HCI_FAILURE;
+	return status;
+}
+
+struct toshiba_acpi_dev {
+	struct platform_device *p_dev;
+	struct rfkill *rfk_dev;
+	struct input_polled_dev *poll_dev;
+
+	const char *bt_name;
+	const char *rfk_name;
+
+	bool last_rfk_state;
+
+	struct mutex mutex;
+};
+
+static struct toshiba_acpi_dev toshiba_acpi = {
+	.bt_name = "Toshiba Bluetooth",
+	.rfk_name = "Toshiba RFKill Switch",
+	.last_rfk_state = false,
+};
+
+/* Bluetooth rfkill handlers */
+
+static u32 hci_get_bt_present(bool *present)
+{
+	u32 hci_result;
+	u32 value, value2;
+
+	value = 0;
+	value2 = 0;
+	hci_read2(HCI_WIRELESS, &value, &value2, &hci_result);
+	if (hci_result == HCI_SUCCESS)
+		*present = (value & HCI_WIRELESS_BT_PRESENT) ? true : false;
+
+	return hci_result;
+}
+
+static u32 hci_get_bt_on(bool *on)
+{
+	u32 hci_result;
+	u32 value, value2;
+
+	value = 0;
+	value2 = 0x0001;
+	hci_read2(HCI_WIRELESS, &value, &value2, &hci_result);
+	if (hci_result == HCI_SUCCESS)
+		*on = (value & HCI_WIRELESS_BT_POWER) &&
+		      (value & HCI_WIRELESS_BT_ATTACH);
+
+	return hci_result;
+}
+
+static u32 hci_get_radio_state(bool *radio_state)
+{
+	u32 hci_result;
+	u32 value, value2;
+
+	value = 0;
+	value2 = 0x0001;
+	hci_read2(HCI_WIRELESS, &value, &value2, &hci_result);
+
+	*radio_state = value & HCI_WIRELESS_KILL_SWITCH;
+	return hci_result;
+}
+
+static int bt_rfkill_toggle_radio(void *data, enum rfkill_state state)
+{
+	u32 result1, result2;
+	u32 value;
+	bool radio_state;
+	struct toshiba_acpi_dev *dev = data;
+
+	value = (state == RFKILL_STATE_UNBLOCKED);
+
+	if (hci_get_radio_state(&radio_state) != HCI_SUCCESS)
+		return -EFAULT;
+
+	switch (state) {
+	case RFKILL_STATE_UNBLOCKED:
+		if (!radio_state)
+			return -EPERM;
+		break;
+	case RFKILL_STATE_SOFT_BLOCKED:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	mutex_lock(&dev->mutex);
+	hci_write2(HCI_WIRELESS, value, HCI_WIRELESS_BT_POWER, &result1);
+	hci_write2(HCI_WIRELESS, value, HCI_WIRELESS_BT_ATTACH, &result2);
+	mutex_unlock(&dev->mutex);
+
+	if (result1 != HCI_SUCCESS || result2 != HCI_SUCCESS)
+		return -EFAULT;
+
+	return 0;
+}
+
+static void bt_poll_rfkill(struct input_polled_dev *poll_dev)
+{
+	bool state_changed;
+	bool new_rfk_state;
+	bool value;
+	u32 hci_result;
+	struct toshiba_acpi_dev *dev = poll_dev->private;
+
+	hci_result = hci_get_radio_state(&value);
+	if (hci_result != HCI_SUCCESS)
+		return; /* Can't do anything useful */
+
+	new_rfk_state = value;
+
+	mutex_lock(&dev->mutex);
+	state_changed = new_rfk_state != dev->last_rfk_state;
+	dev->last_rfk_state = new_rfk_state;
+	mutex_unlock(&dev->mutex);
+
+	if (unlikely(state_changed)) {
+		rfkill_force_state(dev->rfk_dev,
+				   new_rfk_state ?
+				   RFKILL_STATE_SOFT_BLOCKED :
+				   RFKILL_STATE_HARD_BLOCKED);
+		input_report_switch(poll_dev->input, SW_RFKILL_ALL,
+				    new_rfk_state);
+	}
+}
+
 static struct proc_dir_entry *toshiba_proc_dir /*= 0*/ ;
 static struct backlight_device *toshiba_backlight_device;
 static int force_fan;
@@ -547,6 +703,14 @@
 
 static void toshiba_acpi_exit(void)
 {
+	if (toshiba_acpi.poll_dev) {
+		input_unregister_polled_device(toshiba_acpi.poll_dev);
+		input_free_polled_device(toshiba_acpi.poll_dev);
+	}
+
+	if (toshiba_acpi.rfk_dev)
+		rfkill_unregister(toshiba_acpi.rfk_dev);
+
 	if (toshiba_backlight_device)
 		backlight_device_unregister(toshiba_backlight_device);
 
@@ -555,6 +719,8 @@
 	if (toshiba_proc_dir)
 		remove_proc_entry(PROC_TOSHIBA, acpi_root_dir);
 
+	platform_device_unregister(toshiba_acpi.p_dev);
+
 	return;
 }
 
@@ -562,6 +728,10 @@
 {
 	acpi_status status = AE_OK;
 	u32 hci_result;
+	bool bt_present;
+	bool bt_on;
+	bool radio_on;
+	int ret = 0;
 
 	if (acpi_disabled)
 		return -ENODEV;
@@ -578,6 +748,18 @@
 	       TOSHIBA_ACPI_VERSION);
 	printk(MY_INFO "    HCI method: %s\n", method_hci);
 
+	mutex_init(&toshiba_acpi.mutex);
+
+	toshiba_acpi.p_dev = platform_device_register_simple("toshiba_acpi",
+							      -1, NULL, 0);
+	if (IS_ERR(toshiba_acpi.p_dev)) {
+		ret = PTR_ERR(toshiba_acpi.p_dev);
+		printk(MY_ERR "unable to register platform device\n");
+		toshiba_acpi.p_dev = NULL;
+		toshiba_acpi_exit();
+		return ret;
+	}
+
 	force_fan = 0;
 	key_event_valid = 0;
 
@@ -586,19 +768,23 @@
 
 	toshiba_proc_dir = proc_mkdir(PROC_TOSHIBA, acpi_root_dir);
 	if (!toshiba_proc_dir) {
-		status = AE_ERROR;
+		toshiba_acpi_exit();
+		return -ENODEV;
 	} else {
 		toshiba_proc_dir->owner = THIS_MODULE;
 		status = add_device();
-		if (ACPI_FAILURE(status))
-			remove_proc_entry(PROC_TOSHIBA, acpi_root_dir);
+		if (ACPI_FAILURE(status)) {
+			toshiba_acpi_exit();
+			return -ENODEV;
+		}
 	}
 
-	toshiba_backlight_device = backlight_device_register("toshiba",NULL,
+	toshiba_backlight_device = backlight_device_register("toshiba",
+						&toshiba_acpi.p_dev->dev,
 						NULL,
 						&toshiba_backlight_data);
         if (IS_ERR(toshiba_backlight_device)) {
-		int ret = PTR_ERR(toshiba_backlight_device);
+		ret = PTR_ERR(toshiba_backlight_device);
 
 		printk(KERN_ERR "Could not register toshiba backlight device\n");
 		toshiba_backlight_device = NULL;
@@ -607,7 +793,66 @@
 	}
         toshiba_backlight_device->props.max_brightness = HCI_LCD_BRIGHTNESS_LEVELS - 1;
 
-	return (ACPI_SUCCESS(status)) ? 0 : -ENODEV;
+	/* Register rfkill switch for Bluetooth */
+	if (hci_get_bt_present(&bt_present) == HCI_SUCCESS && bt_present) {
+		toshiba_acpi.rfk_dev = rfkill_allocate(&toshiba_acpi.p_dev->dev,
+							RFKILL_TYPE_BLUETOOTH);
+		if (!toshiba_acpi.rfk_dev) {
+			printk(MY_ERR "unable to allocate rfkill device\n");
+			toshiba_acpi_exit();
+			return -ENOMEM;
+		}
+
+		toshiba_acpi.rfk_dev->name = toshiba_acpi.bt_name;
+		toshiba_acpi.rfk_dev->toggle_radio = bt_rfkill_toggle_radio;
+		toshiba_acpi.rfk_dev->user_claim_unsupported = 1;
+		toshiba_acpi.rfk_dev->data = &toshiba_acpi;
+
+		if (hci_get_bt_on(&bt_on) == HCI_SUCCESS && bt_on) {
+			toshiba_acpi.rfk_dev->state = RFKILL_STATE_UNBLOCKED;
+		} else if (hci_get_radio_state(&radio_on) == HCI_SUCCESS &&
+			   radio_on) {
+			toshiba_acpi.rfk_dev->state = RFKILL_STATE_SOFT_BLOCKED;
+		} else {
+			toshiba_acpi.rfk_dev->state = RFKILL_STATE_HARD_BLOCKED;
+		}
+
+		ret = rfkill_register(toshiba_acpi.rfk_dev);
+		if (ret) {
+			printk(MY_ERR "unable to register rfkill device\n");
+			toshiba_acpi_exit();
+			return -ENOMEM;
+		}
+	}
+
+	/* Register input device for kill switch */
+	toshiba_acpi.poll_dev = input_allocate_polled_device();
+	if (!toshiba_acpi.poll_dev) {
+		printk(MY_ERR "unable to allocate kill-switch input device\n");
+		toshiba_acpi_exit();
+		return -ENOMEM;
+	}
+	toshiba_acpi.poll_dev->private = &toshiba_acpi;
+	toshiba_acpi.poll_dev->poll = bt_poll_rfkill;
+	toshiba_acpi.poll_dev->poll_interval = 1000; /* msecs */
+
+	toshiba_acpi.poll_dev->input->name = toshiba_acpi.rfk_name;
+	toshiba_acpi.poll_dev->input->id.bustype = BUS_HOST;
+	toshiba_acpi.poll_dev->input->id.vendor = 0x0930; /* Toshiba USB ID */
+	set_bit(EV_SW, toshiba_acpi.poll_dev->input->evbit);
+	set_bit(SW_RFKILL_ALL, toshiba_acpi.poll_dev->input->swbit);
+	input_report_switch(toshiba_acpi.poll_dev->input, SW_RFKILL_ALL, TRUE);
+
+	ret = input_register_polled_device(toshiba_acpi.poll_dev);
+	if (ret) {
+		printk(MY_ERR "unable to register kill-switch input device\n");
+		rfkill_free(toshiba_acpi.rfk_dev);
+		toshiba_acpi.rfk_dev = NULL;
+		toshiba_acpi_exit();
+		return ret;
+	}
+
+	return 0;
 }
 
 module_init(toshiba_acpi_init);
diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig
index 11c8c19..78fbec8 100644
--- a/drivers/ata/Kconfig
+++ b/drivers/ata/Kconfig
@@ -7,7 +7,6 @@
 	depends on HAS_IOMEM
 	depends on BLOCK
 	depends on !(M32R || M68K) || BROKEN
-	depends on !SUN4 || BROKEN
 	select SCSI
 	---help---
 	  If you want to use a ATA hard disk, ATA tape drive, ATA CD-ROM or
@@ -663,7 +662,7 @@
 
 config PATA_PLATFORM
 	tristate "Generic platform device PATA support"
-	depends on EMBEDDED || ARCH_RPC || PPC || HAVE_PATA_PLATFORM
+	depends on EMBEDDED || PPC || HAVE_PATA_PLATFORM
 	help
 	  This option enables support for generic directly connected ATA
 	  devices commonly found on embedded systems.
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index 2e1a7cb..aeadd00 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -267,8 +267,8 @@
 					 	 * per PM slot */
 };
 
-static int ahci_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val);
-static int ahci_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val);
+static int ahci_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val);
+static int ahci_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val);
 static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
 static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc);
 static bool ahci_qc_fill_rtf(struct ata_queued_cmd *qc);
@@ -316,6 +316,7 @@
 
 static struct device_attribute *ahci_sdev_attrs[] = {
 	&dev_attr_sw_activity,
+	&dev_attr_unload_heads,
 	NULL
 };
 
@@ -820,10 +821,10 @@
 	return 0;
 }
 
-static int ahci_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
+static int ahci_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val)
 {
-	void __iomem *port_mmio = ahci_port_base(ap);
-	int offset = ahci_scr_offset(ap, sc_reg);
+	void __iomem *port_mmio = ahci_port_base(link->ap);
+	int offset = ahci_scr_offset(link->ap, sc_reg);
 
 	if (offset) {
 		*val = readl(port_mmio + offset);
@@ -832,10 +833,10 @@
 	return -EINVAL;
 }
 
-static int ahci_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val)
+static int ahci_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val)
 {
-	void __iomem *port_mmio = ahci_port_base(ap);
-	int offset = ahci_scr_offset(ap, sc_reg);
+	void __iomem *port_mmio = ahci_port_base(link->ap);
+	int offset = ahci_scr_offset(link->ap, sc_reg);
 
 	if (offset) {
 		writel(val, port_mmio + offset);
@@ -973,7 +974,7 @@
 	writel(PORT_IRQ_PHYRDY, port_mmio + PORT_IRQ_STAT);
 
 	/* go ahead and clean out PhyRdy Change from Serror too */
-	ahci_scr_write(ap, SCR_ERROR, ((1 << 16) | (1 << 18)));
+	ahci_scr_write(&ap->link, SCR_ERROR, ((1 << 16) | (1 << 18)));
 
 	/*
  	 * Clear flag to indicate that we should ignore all PhyRdy
@@ -1937,8 +1938,8 @@
 	ata_ehi_push_desc(host_ehi, "irq_stat 0x%08x", irq_stat);
 
 	/* AHCI needs SError cleared; otherwise, it might lock up */
-	ahci_scr_read(ap, SCR_ERROR, &serror);
-	ahci_scr_write(ap, SCR_ERROR, serror);
+	ahci_scr_read(&ap->link, SCR_ERROR, &serror);
+	ahci_scr_write(&ap->link, SCR_ERROR, serror);
 	host_ehi->serror |= serror;
 
 	/* some controllers set IRQ_IF_ERR on device errors, ignore it */
@@ -2027,7 +2028,7 @@
 	if ((hpriv->flags & AHCI_HFLAG_NO_HOTPLUG) &&
 		(status & PORT_IRQ_PHYRDY)) {
 		status &= ~PORT_IRQ_PHYRDY;
-		ahci_scr_write(ap, SCR_ERROR, ((1 << 16) | (1 << 18)));
+		ahci_scr_write(&ap->link, SCR_ERROR, ((1 << 16) | (1 << 18)));
 	}
 
 	if (unlikely(status & PORT_IRQ_ERROR)) {
diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c
index e6b4606..e9e32ed 100644
--- a/drivers/ata/ata_piix.c
+++ b/drivers/ata/ata_piix.c
@@ -165,8 +165,10 @@
 static void ich_set_dmamode(struct ata_port *ap, struct ata_device *adev);
 static int ich_pata_cable_detect(struct ata_port *ap);
 static u8 piix_vmw_bmdma_status(struct ata_port *ap);
-static int piix_sidpr_scr_read(struct ata_port *ap, unsigned int reg, u32 *val);
-static int piix_sidpr_scr_write(struct ata_port *ap, unsigned int reg, u32 val);
+static int piix_sidpr_scr_read(struct ata_link *link,
+			       unsigned int reg, u32 *val);
+static int piix_sidpr_scr_write(struct ata_link *link,
+				unsigned int reg, u32 val);
 #ifdef CONFIG_PM
 static int piix_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg);
 static int piix_pci_device_resume(struct pci_dev *pdev);
@@ -278,12 +280,15 @@
 	/* SATA Controller IDE (PCH) */
 	{ 0x8086, 0x3b20, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata },
 	/* SATA Controller IDE (PCH) */
+	{ 0x8086, 0x3b21, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata },
+	/* SATA Controller IDE (PCH) */
 	{ 0x8086, 0x3b26, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata },
 	/* SATA Controller IDE (PCH) */
+	{ 0x8086, 0x3b28, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata },
+	/* SATA Controller IDE (PCH) */
 	{ 0x8086, 0x3b2d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata },
 	/* SATA Controller IDE (PCH) */
 	{ 0x8086, 0x3b2e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata },
-
 	{ }	/* terminate list */
 };
 
@@ -582,6 +587,7 @@
 	{ 0x27DF, 0x1025, 0x0110 },	/* ICH7 on Acer 3682WLMi */
 	{ 0x27DF, 0x1043, 0x1267 },	/* ICH7 on Asus W5F */
 	{ 0x27DF, 0x103C, 0x30A1 },	/* ICH7 on HP Compaq nc2400 */
+	{ 0x27DF, 0x1071, 0xD221 },	/* ICH7 on Hercules EC-900 */
 	{ 0x24CA, 0x1025, 0x0061 },	/* ICH4 on ACER Aspire 2023WLMi */
 	{ 0x24CA, 0x1025, 0x003d },	/* ICH4 on ACER TM290 */
 	{ 0x266F, 0x1025, 0x0066 },	/* ICH6 on ACER Aspire 1694WLMi */
@@ -885,23 +891,9 @@
  * Serial ATA Index/Data Pair Superset Registers access
  *
  * Beginning from ICH8, there's a sane way to access SCRs using index
- * and data register pair located at BAR5.  This creates an
- * interesting problem of mapping two SCRs to one port.
- *
- * Although they have separate SCRs, the master and slave aren't
- * independent enough to be treated as separate links - e.g. softreset
- * resets both.  Also, there's no protocol defined for hard resetting
- * singled device sharing the virtual port (no defined way to acquire
- * device signature).  This is worked around by merging the SCR values
- * into one sensible value and requesting follow-up SRST after
- * hardreset.
- *
- * SCR merging is perfomed in nibbles which is the unit contents in
- * SCRs are organized.  If two values are equal, the value is used.
- * When they differ, merge table which lists precedence of possible
- * values is consulted and the first match or the last entry when
- * nothing matches is used.  When there's no merge table for the
- * specific nibble, value from the first port is used.
+ * and data register pair located at BAR5 which means that we have
+ * separate SCRs for master and slave.  This is handled using libata
+ * slave_link facility.
  */
 static const int piix_sidx_map[] = {
 	[SCR_STATUS]	= 0,
@@ -909,120 +901,38 @@
 	[SCR_CONTROL]	= 1,
 };
 
-static void piix_sidpr_sel(struct ata_device *dev, unsigned int reg)
+static void piix_sidpr_sel(struct ata_link *link, unsigned int reg)
 {
-	struct ata_port *ap = dev->link->ap;
+	struct ata_port *ap = link->ap;
 	struct piix_host_priv *hpriv = ap->host->private_data;
 
-	iowrite32(((ap->port_no * 2 + dev->devno) << 8) | piix_sidx_map[reg],
+	iowrite32(((ap->port_no * 2 + link->pmp) << 8) | piix_sidx_map[reg],
 		  hpriv->sidpr + PIIX_SIDPR_IDX);
 }
 
-static int piix_sidpr_read(struct ata_device *dev, unsigned int reg)
+static int piix_sidpr_scr_read(struct ata_link *link,
+			       unsigned int reg, u32 *val)
 {
-	struct piix_host_priv *hpriv = dev->link->ap->host->private_data;
-
-	piix_sidpr_sel(dev, reg);
-	return ioread32(hpriv->sidpr + PIIX_SIDPR_DATA);
-}
-
-static void piix_sidpr_write(struct ata_device *dev, unsigned int reg, u32 val)
-{
-	struct piix_host_priv *hpriv = dev->link->ap->host->private_data;
-
-	piix_sidpr_sel(dev, reg);
-	iowrite32(val, hpriv->sidpr + PIIX_SIDPR_DATA);
-}
-
-static u32 piix_merge_scr(u32 val0, u32 val1, const int * const *merge_tbl)
-{
-	u32 val = 0;
-	int i, mi;
-
-	for (i = 0, mi = 0; i < 32 / 4; i++) {
-		u8 c0 = (val0 >> (i * 4)) & 0xf;
-		u8 c1 = (val1 >> (i * 4)) & 0xf;
-		u8 merged = c0;
-		const int *cur;
-
-		/* if no merge preference, assume the first value */
-		cur = merge_tbl[mi];
-		if (!cur)
-			goto done;
-		mi++;
-
-		/* if two values equal, use it */
-		if (c0 == c1)
-			goto done;
-
-		/* choose the first match or the last from the merge table */
-		while (*cur != -1) {
-			if (c0 == *cur || c1 == *cur)
-				break;
-			cur++;
-		}
-		if (*cur == -1)
-			cur--;
-		merged = *cur;
-	done:
-		val |= merged << (i * 4);
-	}
-
-	return val;
-}
-
-static int piix_sidpr_scr_read(struct ata_port *ap, unsigned int reg, u32 *val)
-{
-	const int * const sstatus_merge_tbl[] = {
-		/* DET */ (const int []){ 1, 3, 0, 4, 3, -1 },
-		/* SPD */ (const int []){ 2, 1, 0, -1 },
-		/* IPM */ (const int []){ 6, 2, 1, 0, -1 },
-		NULL,
-	};
-	const int * const scontrol_merge_tbl[] = {
-		/* DET */ (const int []){ 1, 0, 4, 0, -1 },
-		/* SPD */ (const int []){ 0, 2, 1, 0, -1 },
-		/* IPM */ (const int []){ 0, 1, 2, 3, 0, -1 },
-		NULL,
-	};
-	u32 v0, v1;
+	struct piix_host_priv *hpriv = link->ap->host->private_data;
 
 	if (reg >= ARRAY_SIZE(piix_sidx_map))
 		return -EINVAL;
 
-	if (!(ap->flags & ATA_FLAG_SLAVE_POSS)) {
-		*val = piix_sidpr_read(&ap->link.device[0], reg);
-		return 0;
-	}
-
-	v0 = piix_sidpr_read(&ap->link.device[0], reg);
-	v1 = piix_sidpr_read(&ap->link.device[1], reg);
-
-	switch (reg) {
-	case SCR_STATUS:
-		*val = piix_merge_scr(v0, v1, sstatus_merge_tbl);
-		break;
-	case SCR_ERROR:
-		*val = v0 | v1;
-		break;
-	case SCR_CONTROL:
-		*val = piix_merge_scr(v0, v1, scontrol_merge_tbl);
-		break;
-	}
-
+	piix_sidpr_sel(link, reg);
+	*val = ioread32(hpriv->sidpr + PIIX_SIDPR_DATA);
 	return 0;
 }
 
-static int piix_sidpr_scr_write(struct ata_port *ap, unsigned int reg, u32 val)
+static int piix_sidpr_scr_write(struct ata_link *link,
+				unsigned int reg, u32 val)
 {
+	struct piix_host_priv *hpriv = link->ap->host->private_data;
+
 	if (reg >= ARRAY_SIZE(piix_sidx_map))
 		return -EINVAL;
 
-	piix_sidpr_write(&ap->link.device[0], reg, val);
-
-	if (ap->flags & ATA_FLAG_SLAVE_POSS)
-		piix_sidpr_write(&ap->link.device[1], reg, val);
-
+	piix_sidpr_sel(link, reg);
+	iowrite32(val, hpriv->sidpr + PIIX_SIDPR_DATA);
 	return 0;
 }
 
@@ -1363,28 +1273,28 @@
 	return map;
 }
 
-static void __devinit piix_init_sidpr(struct ata_host *host)
+static int __devinit piix_init_sidpr(struct ata_host *host)
 {
 	struct pci_dev *pdev = to_pci_dev(host->dev);
 	struct piix_host_priv *hpriv = host->private_data;
-	struct ata_device *dev0 = &host->ports[0]->link.device[0];
+	struct ata_link *link0 = &host->ports[0]->link;
 	u32 scontrol;
-	int i;
+	int i, rc;
 
 	/* check for availability */
 	for (i = 0; i < 4; i++)
 		if (hpriv->map[i] == IDE)
-			return;
+			return 0;
 
 	if (!(host->ports[0]->flags & PIIX_FLAG_SIDPR))
-		return;
+		return 0;
 
 	if (pci_resource_start(pdev, PIIX_SIDPR_BAR) == 0 ||
 	    pci_resource_len(pdev, PIIX_SIDPR_BAR) != PIIX_SIDPR_LEN)
-		return;
+		return 0;
 
 	if (pcim_iomap_regions(pdev, 1 << PIIX_SIDPR_BAR, DRV_NAME))
-		return;
+		return 0;
 
 	hpriv->sidpr = pcim_iomap_table(pdev)[PIIX_SIDPR_BAR];
 
@@ -1392,7 +1302,7 @@
 	 * Give it a test drive by inhibiting power save modes which
 	 * we'll do anyway.
 	 */
-	scontrol = piix_sidpr_read(dev0, SCR_CONTROL);
+	piix_sidpr_scr_read(link0, SCR_CONTROL, &scontrol);
 
 	/* if IPM is already 3, SCR access is probably working.  Don't
 	 * un-inhibit power save modes as BIOS might have inhibited
@@ -1400,18 +1310,30 @@
 	 */
 	if ((scontrol & 0xf00) != 0x300) {
 		scontrol |= 0x300;
-		piix_sidpr_write(dev0, SCR_CONTROL, scontrol);
-		scontrol = piix_sidpr_read(dev0, SCR_CONTROL);
+		piix_sidpr_scr_write(link0, SCR_CONTROL, scontrol);
+		piix_sidpr_scr_read(link0, SCR_CONTROL, &scontrol);
 
 		if ((scontrol & 0xf00) != 0x300) {
 			dev_printk(KERN_INFO, host->dev, "SCR access via "
 				   "SIDPR is available but doesn't work\n");
-			return;
+			return 0;
 		}
 	}
 
-	host->ports[0]->ops = &piix_sidpr_sata_ops;
-	host->ports[1]->ops = &piix_sidpr_sata_ops;
+	/* okay, SCRs available, set ops and ask libata for slave_link */
+	for (i = 0; i < 2; i++) {
+		struct ata_port *ap = host->ports[i];
+
+		ap->ops = &piix_sidpr_sata_ops;
+
+		if (ap->flags & ATA_FLAG_SLAVE_POSS) {
+			rc = ata_slave_link_init(ap);
+			if (rc)
+				return rc;
+		}
+	}
+
+	return 0;
 }
 
 static void piix_iocfg_bit18_quirk(struct pci_dev *pdev)
@@ -1521,7 +1443,9 @@
 	/* initialize controller */
 	if (port_flags & ATA_FLAG_SATA) {
 		piix_init_pcs(host, piix_map_db_table[ent->driver_data]);
-		piix_init_sidpr(host);
+		rc = piix_init_sidpr(host);
+		if (rc)
+			return rc;
 	}
 
 	/* apply IOCFG bit18 quirk */
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index 79e3a8e..1ee9499 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -163,6 +163,67 @@
 MODULE_VERSION(DRV_VERSION);
 
 
+/*
+ * Iterator helpers.  Don't use directly.
+ *
+ * LOCKING:
+ * Host lock or EH context.
+ */
+struct ata_link *__ata_port_next_link(struct ata_port *ap,
+				      struct ata_link *link, bool dev_only)
+{
+	/* NULL link indicates start of iteration */
+	if (!link) {
+		if (dev_only && sata_pmp_attached(ap))
+			return ap->pmp_link;
+		return &ap->link;
+	}
+
+	/* we just iterated over the host master link, what's next? */
+	if (link == &ap->link) {
+		if (!sata_pmp_attached(ap)) {
+			if (unlikely(ap->slave_link) && !dev_only)
+				return ap->slave_link;
+			return NULL;
+		}
+		return ap->pmp_link;
+	}
+
+	/* slave_link excludes PMP */
+	if (unlikely(link == ap->slave_link))
+		return NULL;
+
+	/* iterate to the next PMP link */
+	if (++link < ap->pmp_link + ap->nr_pmp_links)
+		return link;
+	return NULL;
+}
+
+/**
+ *	ata_dev_phys_link - find physical link for a device
+ *	@dev: ATA device to look up physical link for
+ *
+ *	Look up physical link which @dev is attached to.  Note that
+ *	this is different from @dev->link only when @dev is on slave
+ *	link.  For all other cases, it's the same as @dev->link.
+ *
+ *	LOCKING:
+ *	Don't care.
+ *
+ *	RETURNS:
+ *	Pointer to the found physical link.
+ */
+struct ata_link *ata_dev_phys_link(struct ata_device *dev)
+{
+	struct ata_port *ap = dev->link->ap;
+
+	if (!ap->slave_link)
+		return dev->link;
+	if (!dev->devno)
+		return &ap->link;
+	return ap->slave_link;
+}
+
 /**
  *	ata_force_cbl - force cable type according to libata.force
  *	@ap: ATA port of interest
@@ -206,7 +267,8 @@
  *	the host link and all fan-out ports connected via PMP.  If the
  *	device part is specified as 0 (e.g. 1.00:), it specifies the
  *	first fan-out link not the host link.  Device number 15 always
- *	points to the host link whether PMP is attached or not.
+ *	points to the host link whether PMP is attached or not.  If the
+ *	controller has slave link, device number 16 points to it.
  *
  *	LOCKING:
  *	EH context.
@@ -214,12 +276,11 @@
 static void ata_force_link_limits(struct ata_link *link)
 {
 	bool did_spd = false;
-	int linkno, i;
+	int linkno = link->pmp;
+	int i;
 
 	if (ata_is_host_link(link))
-		linkno = 15;
-	else
-		linkno = link->pmp;
+		linkno += 15;
 
 	for (i = ata_force_tbl_size - 1; i >= 0; i--) {
 		const struct ata_force_ent *fe = &ata_force_tbl[i];
@@ -266,9 +327,9 @@
 	int alt_devno = devno;
 	int i;
 
-	/* allow n.15 for the first device attached to host port */
-	if (ata_is_host_link(dev->link) && devno == 0)
-		alt_devno = 15;
+	/* allow n.15/16 for devices attached to host port */
+	if (ata_is_host_link(dev->link))
+		alt_devno += 15;
 
 	for (i = ata_force_tbl_size - 1; i >= 0; i--) {
 		const struct ata_force_ent *fe = &ata_force_tbl[i];
@@ -320,9 +381,9 @@
 	int alt_devno = devno;
 	int i;
 
-	/* allow n.15 for the first device attached to host port */
-	if (ata_is_host_link(dev->link) && devno == 0)
-		alt_devno = 15;
+	/* allow n.15/16 for devices attached to host port */
+	if (ata_is_host_link(dev->link))
+		alt_devno += 15;
 
 	for (i = 0; i < ata_force_tbl_size; i++) {
 		const struct ata_force_ent *fe = &ata_force_tbl[i];
@@ -2681,7 +2742,7 @@
 		return;
 	sata_scr_read(link, SCR_CONTROL, &scontrol);
 
-	if (ata_link_online(link)) {
+	if (ata_phys_link_online(link)) {
 		tmp = (sstatus >> 4) & 0xf;
 		ata_link_printk(link, KERN_INFO,
 				"SATA link up %s (SStatus %X SControl %X)\n",
@@ -3372,6 +3433,12 @@
 	unsigned long nodev_deadline = ata_deadline(start, ATA_TMOUT_FF_WAIT);
 	int warned = 0;
 
+	/* Slave readiness can't be tested separately from master.  On
+	 * M/S emulation configuration, this function should be called
+	 * only on the master and it will handle both master and slave.
+	 */
+	WARN_ON(link == link->ap->slave_link);
+
 	if (time_after(nodev_deadline, deadline))
 		nodev_deadline = deadline;
 
@@ -3593,7 +3660,7 @@
 	}
 
 	/* no point in trying softreset on offline link */
-	if (ata_link_offline(link))
+	if (ata_phys_link_offline(link))
 		ehc->i.action &= ~ATA_EH_SOFTRESET;
 
 	return 0;
@@ -3671,7 +3738,7 @@
 	if (rc)
 		goto out;
 	/* if link is offline nothing more to do */
-	if (ata_link_offline(link))
+	if (ata_phys_link_offline(link))
 		goto out;
 
 	/* Link is online.  From this point, -ENODEV too is an error. */
@@ -4868,10 +4935,8 @@
 int sata_scr_read(struct ata_link *link, int reg, u32 *val)
 {
 	if (ata_is_host_link(link)) {
-		struct ata_port *ap = link->ap;
-
 		if (sata_scr_valid(link))
-			return ap->ops->scr_read(ap, reg, val);
+			return link->ap->ops->scr_read(link, reg, val);
 		return -EOPNOTSUPP;
 	}
 
@@ -4897,10 +4962,8 @@
 int sata_scr_write(struct ata_link *link, int reg, u32 val)
 {
 	if (ata_is_host_link(link)) {
-		struct ata_port *ap = link->ap;
-
 		if (sata_scr_valid(link))
-			return ap->ops->scr_write(ap, reg, val);
+			return link->ap->ops->scr_write(link, reg, val);
 		return -EOPNOTSUPP;
 	}
 
@@ -4925,13 +4988,12 @@
 int sata_scr_write_flush(struct ata_link *link, int reg, u32 val)
 {
 	if (ata_is_host_link(link)) {
-		struct ata_port *ap = link->ap;
 		int rc;
 
 		if (sata_scr_valid(link)) {
-			rc = ap->ops->scr_write(ap, reg, val);
+			rc = link->ap->ops->scr_write(link, reg, val);
 			if (rc == 0)
-				rc = ap->ops->scr_read(ap, reg, &val);
+				rc = link->ap->ops->scr_read(link, reg, &val);
 			return rc;
 		}
 		return -EOPNOTSUPP;
@@ -4941,7 +5003,7 @@
 }
 
 /**
- *	ata_link_online - test whether the given link is online
+ *	ata_phys_link_online - test whether the given link is online
  *	@link: ATA link to test
  *
  *	Test whether @link is online.  Note that this function returns
@@ -4952,20 +5014,20 @@
  *	None.
  *
  *	RETURNS:
- *	1 if the port online status is available and online.
+ *	True if the port online status is available and online.
  */
-int ata_link_online(struct ata_link *link)
+bool ata_phys_link_online(struct ata_link *link)
 {
 	u32 sstatus;
 
 	if (sata_scr_read(link, SCR_STATUS, &sstatus) == 0 &&
 	    (sstatus & 0xf) == 0x3)
-		return 1;
-	return 0;
+		return true;
+	return false;
 }
 
 /**
- *	ata_link_offline - test whether the given link is offline
+ *	ata_phys_link_offline - test whether the given link is offline
  *	@link: ATA link to test
  *
  *	Test whether @link is offline.  Note that this function
@@ -4976,16 +5038,68 @@
  *	None.
  *
  *	RETURNS:
- *	1 if the port offline status is available and offline.
+ *	True if the port offline status is available and offline.
  */
-int ata_link_offline(struct ata_link *link)
+bool ata_phys_link_offline(struct ata_link *link)
 {
 	u32 sstatus;
 
 	if (sata_scr_read(link, SCR_STATUS, &sstatus) == 0 &&
 	    (sstatus & 0xf) != 0x3)
-		return 1;
-	return 0;
+		return true;
+	return false;
+}
+
+/**
+ *	ata_link_online - test whether the given link is online
+ *	@link: ATA link to test
+ *
+ *	Test whether @link is online.  This is identical to
+ *	ata_phys_link_online() when there's no slave link.  When
+ *	there's a slave link, this function should only be called on
+ *	the master link and will return true if any of M/S links is
+ *	online.
+ *
+ *	LOCKING:
+ *	None.
+ *
+ *	RETURNS:
+ *	True if the port online status is available and online.
+ */
+bool ata_link_online(struct ata_link *link)
+{
+	struct ata_link *slave = link->ap->slave_link;
+
+	WARN_ON(link == slave);	/* shouldn't be called on slave link */
+
+	return ata_phys_link_online(link) ||
+		(slave && ata_phys_link_online(slave));
+}
+
+/**
+ *	ata_link_offline - test whether the given link is offline
+ *	@link: ATA link to test
+ *
+ *	Test whether @link is offline.  This is identical to
+ *	ata_phys_link_offline() when there's no slave link.  When
+ *	there's a slave link, this function should only be called on
+ *	the master link and will return true if both M/S links are
+ *	offline.
+ *
+ *	LOCKING:
+ *	None.
+ *
+ *	RETURNS:
+ *	True if the port offline status is available and offline.
+ */
+bool ata_link_offline(struct ata_link *link)
+{
+	struct ata_link *slave = link->ap->slave_link;
+
+	WARN_ON(link == slave);	/* shouldn't be called on slave link */
+
+	return ata_phys_link_offline(link) &&
+		(!slave || ata_phys_link_offline(slave));
 }
 
 #ifdef CONFIG_PM
@@ -5127,11 +5241,11 @@
  */
 void ata_dev_init(struct ata_device *dev)
 {
-	struct ata_link *link = dev->link;
+	struct ata_link *link = ata_dev_phys_link(dev);
 	struct ata_port *ap = link->ap;
 	unsigned long flags;
 
-	/* SATA spd limit is bound to the first device */
+	/* SATA spd limit is bound to the attached device, reset together */
 	link->sata_spd_limit = link->hw_sata_spd_limit;
 	link->sata_spd = 0;
 
@@ -5264,6 +5378,7 @@
 	INIT_WORK(&ap->scsi_rescan_task, ata_scsi_dev_rescan);
 	INIT_LIST_HEAD(&ap->eh_done_q);
 	init_waitqueue_head(&ap->eh_wait_q);
+	init_completion(&ap->park_req_pending);
 	init_timer_deferrable(&ap->fastdrain_timer);
 	ap->fastdrain_timer.function = ata_eh_fastdrain_timerfn;
 	ap->fastdrain_timer.data = (unsigned long)ap;
@@ -5294,6 +5409,7 @@
 			scsi_host_put(ap->scsi_host);
 
 		kfree(ap->pmp_link);
+		kfree(ap->slave_link);
 		kfree(ap);
 		host->ports[i] = NULL;
 	}
@@ -5414,6 +5530,68 @@
 	return host;
 }
 
+/**
+ *	ata_slave_link_init - initialize slave link
+ *	@ap: port to initialize slave link for
+ *
+ *	Create and initialize slave link for @ap.  This enables slave
+ *	link handling on the port.
+ *
+ *	In libata, a port contains links and a link contains devices.
+ *	There is single host link but if a PMP is attached to it,
+ *	there can be multiple fan-out links.  On SATA, there's usually
+ *	a single device connected to a link but PATA and SATA
+ *	controllers emulating TF based interface can have two - master
+ *	and slave.
+ *
+ *	However, there are a few controllers which don't fit into this
+ *	abstraction too well - SATA controllers which emulate TF
+ *	interface with both master and slave devices but also have
+ *	separate SCR register sets for each device.  These controllers
+ *	need separate links for physical link handling
+ *	(e.g. onlineness, link speed) but should be treated like a
+ *	traditional M/S controller for everything else (e.g. command
+ *	issue, softreset).
+ *
+ *	slave_link is libata's way of handling this class of
+ *	controllers without impacting core layer too much.  For
+ *	anything other than physical link handling, the default host
+ *	link is used for both master and slave.  For physical link
+ *	handling, separate @ap->slave_link is used.  All dirty details
+ *	are implemented inside libata core layer.  From LLD's POV, the
+ *	only difference is that prereset, hardreset and postreset are
+ *	called once more for the slave link, so the reset sequence
+ *	looks like the following.
+ *
+ *	prereset(M) -> prereset(S) -> hardreset(M) -> hardreset(S) ->
+ *	softreset(M) -> postreset(M) -> postreset(S)
+ *
+ *	Note that softreset is called only for the master.  Softreset
+ *	resets both M/S by definition, so SRST on master should handle
+ *	both (the standard method will work just fine).
+ *
+ *	LOCKING:
+ *	Should be called before host is registered.
+ *
+ *	RETURNS:
+ *	0 on success, -errno on failure.
+ */
+int ata_slave_link_init(struct ata_port *ap)
+{
+	struct ata_link *link;
+
+	WARN_ON(ap->slave_link);
+	WARN_ON(ap->flags & ATA_FLAG_PMP);
+
+	link = kzalloc(sizeof(*link), GFP_KERNEL);
+	if (!link)
+		return -ENOMEM;
+
+	ata_link_init(ap, link, 1);
+	ap->slave_link = link;
+	return 0;
+}
+
 static void ata_host_stop(struct device *gendev, void *res)
 {
 	struct ata_host *host = dev_get_drvdata(gendev);
@@ -5640,6 +5818,8 @@
 
 		/* init sata_spd_limit to the current value */
 		sata_link_init_spd(&ap->link);
+		if (ap->slave_link)
+			sata_link_init_spd(ap->slave_link);
 
 		/* print per-port info to dmesg */
 		xfer_mask = ata_pack_xfermask(ap->pio_mask, ap->mwdma_mask,
@@ -6260,10 +6440,12 @@
 EXPORT_SYMBOL_GPL(sata_port_ops);
 EXPORT_SYMBOL_GPL(ata_dummy_port_ops);
 EXPORT_SYMBOL_GPL(ata_dummy_port_info);
+EXPORT_SYMBOL_GPL(__ata_port_next_link);
 EXPORT_SYMBOL_GPL(ata_std_bios_param);
 EXPORT_SYMBOL_GPL(ata_host_init);
 EXPORT_SYMBOL_GPL(ata_host_alloc);
 EXPORT_SYMBOL_GPL(ata_host_alloc_pinfo);
+EXPORT_SYMBOL_GPL(ata_slave_link_init);
 EXPORT_SYMBOL_GPL(ata_host_start);
 EXPORT_SYMBOL_GPL(ata_host_register);
 EXPORT_SYMBOL_GPL(ata_host_activate);
diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c
index c1db2f2..a93247c 100644
--- a/drivers/ata/libata-eh.c
+++ b/drivers/ata/libata-eh.c
@@ -33,6 +33,7 @@
  */
 
 #include <linux/kernel.h>
+#include <linux/blkdev.h>
 #include <linux/pci.h>
 #include <scsi/scsi.h>
 #include <scsi/scsi_host.h>
@@ -79,6 +80,8 @@
 	 */
 	ATA_EH_PRERESET_TIMEOUT		= 10000,
 	ATA_EH_FASTDRAIN_INTERVAL	=  3000,
+
+	ATA_EH_UA_TRIES			= 5,
 };
 
 /* The following table determines how we sequence resets.  Each entry
@@ -457,29 +460,29 @@
  *	RETURNS:
  *	EH_HANDLED or EH_NOT_HANDLED
  */
-enum scsi_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd)
+enum blk_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd)
 {
 	struct Scsi_Host *host = cmd->device->host;
 	struct ata_port *ap = ata_shost_to_port(host);
 	unsigned long flags;
 	struct ata_queued_cmd *qc;
-	enum scsi_eh_timer_return ret;
+	enum blk_eh_timer_return ret;
 
 	DPRINTK("ENTER\n");
 
 	if (ap->ops->error_handler) {
-		ret = EH_NOT_HANDLED;
+		ret = BLK_EH_NOT_HANDLED;
 		goto out;
 	}
 
-	ret = EH_HANDLED;
+	ret = BLK_EH_HANDLED;
 	spin_lock_irqsave(ap->lock, flags);
 	qc = ata_qc_from_tag(ap, ap->link.active_tag);
 	if (qc) {
 		WARN_ON(qc->scsicmd != cmd);
 		qc->flags |= ATA_QCFLAG_EH_SCHEDULED;
 		qc->err_mask |= AC_ERR_TIMEOUT;
-		ret = EH_NOT_HANDLED;
+		ret = BLK_EH_NOT_HANDLED;
 	}
 	spin_unlock_irqrestore(ap->lock, flags);
 
@@ -831,7 +834,7 @@
 	 * Note that ATA_QCFLAG_FAILED is unconditionally set after
 	 * this function completes.
 	 */
-	scsi_req_abort_cmd(qc->scsicmd);
+	blk_abort_request(qc->scsicmd->request);
 }
 
 /**
@@ -1357,6 +1360,37 @@
 }
 
 /**
+ *	atapi_eh_tur - perform ATAPI TEST_UNIT_READY
+ *	@dev: target ATAPI device
+ *	@r_sense_key: out parameter for sense_key
+ *
+ *	Perform ATAPI TEST_UNIT_READY.
+ *
+ *	LOCKING:
+ *	EH context (may sleep).
+ *
+ *	RETURNS:
+ *	0 on success, AC_ERR_* mask on failure.
+ */
+static unsigned int atapi_eh_tur(struct ata_device *dev, u8 *r_sense_key)
+{
+	u8 cdb[ATAPI_CDB_LEN] = { TEST_UNIT_READY, 0, 0, 0, 0, 0 };
+	struct ata_taskfile tf;
+	unsigned int err_mask;
+
+	ata_tf_init(dev, &tf);
+
+	tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
+	tf.command = ATA_CMD_PACKET;
+	tf.protocol = ATAPI_PROT_NODATA;
+
+	err_mask = ata_exec_internal(dev, &tf, cdb, DMA_NONE, NULL, 0, 0);
+	if (err_mask == AC_ERR_DEV)
+		*r_sense_key = tf.feature >> 4;
+	return err_mask;
+}
+
+/**
  *	atapi_eh_request_sense - perform ATAPI REQUEST_SENSE
  *	@dev: device to perform REQUEST_SENSE to
  *	@sense_buf: result sense data buffer (SCSI_SENSE_BUFFERSIZE bytes long)
@@ -1756,7 +1790,7 @@
 static unsigned int ata_eh_speed_down(struct ata_device *dev,
 				unsigned int eflags, unsigned int err_mask)
 {
-	struct ata_link *link = dev->link;
+	struct ata_link *link = ata_dev_phys_link(dev);
 	int xfer_ok = 0;
 	unsigned int verdict;
 	unsigned int action = 0;
@@ -1880,7 +1914,8 @@
 	for (tag = 0; tag < ATA_MAX_QUEUE; tag++) {
 		struct ata_queued_cmd *qc = __ata_qc_from_tag(ap, tag);
 
-		if (!(qc->flags & ATA_QCFLAG_FAILED) || qc->dev->link != link)
+		if (!(qc->flags & ATA_QCFLAG_FAILED) ||
+		    ata_dev_phys_link(qc->dev) != link)
 			continue;
 
 		/* inherit upper level err_mask */
@@ -1967,6 +2002,23 @@
 	ata_port_for_each_link(link, ap)
 		ata_eh_link_autopsy(link);
 
+	/* Handle the frigging slave link.  Autopsy is done similarly
+	 * but actions and flags are transferred over to the master
+	 * link and handled from there.
+	 */
+	if (ap->slave_link) {
+		struct ata_eh_context *mehc = &ap->link.eh_context;
+		struct ata_eh_context *sehc = &ap->slave_link->eh_context;
+
+		ata_eh_link_autopsy(ap->slave_link);
+
+		ata_eh_about_to_do(ap->slave_link, NULL, ATA_EH_ALL_ACTIONS);
+		mehc->i.action		|= sehc->i.action;
+		mehc->i.dev_action[1]	|= sehc->i.dev_action[1];
+		mehc->i.flags		|= sehc->i.flags;
+		ata_eh_done(ap->slave_link, NULL, ATA_EH_ALL_ACTIONS);
+	}
+
 	/* Autopsy of fanout ports can affect host link autopsy.
 	 * Perform host link autopsy last.
 	 */
@@ -2001,7 +2053,8 @@
 	for (tag = 0; tag < ATA_MAX_QUEUE; tag++) {
 		struct ata_queued_cmd *qc = __ata_qc_from_tag(ap, tag);
 
-		if (!(qc->flags & ATA_QCFLAG_FAILED) || qc->dev->link != link ||
+		if (!(qc->flags & ATA_QCFLAG_FAILED) ||
+		    ata_dev_phys_link(qc->dev) != link ||
 		    ((qc->flags & ATA_QCFLAG_QUIET) &&
 		     qc->err_mask == AC_ERR_DEV))
 			continue;
@@ -2068,7 +2121,7 @@
 		char cdb_buf[70] = "";
 
 		if (!(qc->flags & ATA_QCFLAG_FAILED) ||
-		    qc->dev->link != link || !qc->err_mask)
+		    ata_dev_phys_link(qc->dev) != link || !qc->err_mask)
 			continue;
 
 		if (qc->dma_dir != DMA_NONE) {
@@ -2160,12 +2213,14 @@
 }
 
 static int ata_do_reset(struct ata_link *link, ata_reset_fn_t reset,
-			unsigned int *classes, unsigned long deadline)
+			unsigned int *classes, unsigned long deadline,
+			bool clear_classes)
 {
 	struct ata_device *dev;
 
-	ata_link_for_each_dev(dev, link)
-		classes[dev->devno] = ATA_DEV_UNKNOWN;
+	if (clear_classes)
+		ata_link_for_each_dev(dev, link)
+			classes[dev->devno] = ATA_DEV_UNKNOWN;
 
 	return reset(link, classes, deadline);
 }
@@ -2187,17 +2242,20 @@
 		 ata_reset_fn_t hardreset, ata_postreset_fn_t postreset)
 {
 	struct ata_port *ap = link->ap;
+	struct ata_link *slave = ap->slave_link;
 	struct ata_eh_context *ehc = &link->eh_context;
+	struct ata_eh_context *sehc = &slave->eh_context;
 	unsigned int *classes = ehc->classes;
 	unsigned int lflags = link->flags;
 	int verbose = !(ehc->i.flags & ATA_EHI_QUIET);
 	int max_tries = 0, try = 0;
+	struct ata_link *failed_link;
 	struct ata_device *dev;
 	unsigned long deadline, now;
 	ata_reset_fn_t reset;
 	unsigned long flags;
 	u32 sstatus;
-	int nr_known, rc;
+	int nr_unknown, rc;
 
 	/*
 	 * Prepare to reset
@@ -2252,8 +2310,30 @@
 	}
 
 	if (prereset) {
-		rc = prereset(link,
-			      ata_deadline(jiffies, ATA_EH_PRERESET_TIMEOUT));
+		unsigned long deadline = ata_deadline(jiffies,
+						      ATA_EH_PRERESET_TIMEOUT);
+
+		if (slave) {
+			sehc->i.action &= ~ATA_EH_RESET;
+			sehc->i.action |= ehc->i.action;
+		}
+
+		rc = prereset(link, deadline);
+
+		/* If present, do prereset on slave link too.  Reset
+		 * is skipped iff both master and slave links report
+		 * -ENOENT or clear ATA_EH_RESET.
+		 */
+		if (slave && (rc == 0 || rc == -ENOENT)) {
+			int tmp;
+
+			tmp = prereset(slave, deadline);
+			if (tmp != -ENOENT)
+				rc = tmp;
+
+			ehc->i.action |= sehc->i.action;
+		}
+
 		if (rc) {
 			if (rc == -ENOENT) {
 				ata_link_printk(link, KERN_DEBUG,
@@ -2302,25 +2382,51 @@
 		else
 			ehc->i.flags |= ATA_EHI_DID_SOFTRESET;
 
-		rc = ata_do_reset(link, reset, classes, deadline);
-		if (rc && rc != -EAGAIN)
+		rc = ata_do_reset(link, reset, classes, deadline, true);
+		if (rc && rc != -EAGAIN) {
+			failed_link = link;
 			goto fail;
+		}
 
+		/* hardreset slave link if existent */
+		if (slave && reset == hardreset) {
+			int tmp;
+
+			if (verbose)
+				ata_link_printk(slave, KERN_INFO,
+						"hard resetting link\n");
+
+			ata_eh_about_to_do(slave, NULL, ATA_EH_RESET);
+			tmp = ata_do_reset(slave, reset, classes, deadline,
+					   false);
+			switch (tmp) {
+			case -EAGAIN:
+				rc = -EAGAIN;
+			case 0:
+				break;
+			default:
+				failed_link = slave;
+				rc = tmp;
+				goto fail;
+			}
+		}
+
+		/* perform follow-up SRST if necessary */
 		if (reset == hardreset &&
 		    ata_eh_followup_srst_needed(link, rc, classes)) {
-			/* okay, let's do follow-up softreset */
 			reset = softreset;
 
 			if (!reset) {
 				ata_link_printk(link, KERN_ERR,
 						"follow-up softreset required "
 						"but no softreset avaliable\n");
+				failed_link = link;
 				rc = -EINVAL;
 				goto fail;
 			}
 
 			ata_eh_about_to_do(link, NULL, ATA_EH_RESET);
-			rc = ata_do_reset(link, reset, classes, deadline);
+			rc = ata_do_reset(link, reset, classes, deadline, true);
 		}
 	} else {
 		if (verbose)
@@ -2341,7 +2447,7 @@
 		dev->pio_mode = XFER_PIO_0;
 		dev->flags &= ~ATA_DFLAG_SLEEPING;
 
-		if (ata_link_offline(link))
+		if (ata_phys_link_offline(ata_dev_phys_link(dev)))
 			continue;
 
 		/* apply class override */
@@ -2354,6 +2460,8 @@
 	/* record current link speed */
 	if (sata_scr_read(link, SCR_STATUS, &sstatus) == 0)
 		link->sata_spd = (sstatus >> 4) & 0xf;
+	if (slave && sata_scr_read(slave, SCR_STATUS, &sstatus) == 0)
+		slave->sata_spd = (sstatus >> 4) & 0xf;
 
 	/* thaw the port */
 	if (ata_is_host_link(link))
@@ -2366,12 +2474,17 @@
 	 * reset and here.  This race is mediated by cross checking
 	 * link onlineness and classification result later.
 	 */
-	if (postreset)
+	if (postreset) {
 		postreset(link, classes);
+		if (slave)
+			postreset(slave, classes);
+	}
 
 	/* clear cached SError */
 	spin_lock_irqsave(link->ap->lock, flags);
 	link->eh_info.serror = 0;
+	if (slave)
+		slave->eh_info.serror = 0;
 	spin_unlock_irqrestore(link->ap->lock, flags);
 
 	/* Make sure onlineness and classification result correspond.
@@ -2381,19 +2494,21 @@
 	 * link onlineness and classification result, those conditions
 	 * can be reliably detected and retried.
 	 */
-	nr_known = 0;
+	nr_unknown = 0;
 	ata_link_for_each_dev(dev, link) {
 		/* convert all ATA_DEV_UNKNOWN to ATA_DEV_NONE */
-		if (classes[dev->devno] == ATA_DEV_UNKNOWN)
+		if (classes[dev->devno] == ATA_DEV_UNKNOWN) {
 			classes[dev->devno] = ATA_DEV_NONE;
-		else
-			nr_known++;
+			if (ata_phys_link_online(ata_dev_phys_link(dev)))
+				nr_unknown++;
+		}
 	}
 
-	if (classify && !nr_known && ata_link_online(link)) {
+	if (classify && nr_unknown) {
 		if (try < max_tries) {
 			ata_link_printk(link, KERN_WARNING, "link online but "
 				       "device misclassified, retrying\n");
+			failed_link = link;
 			rc = -EAGAIN;
 			goto fail;
 		}
@@ -2404,6 +2519,8 @@
 
 	/* reset successful, schedule revalidation */
 	ata_eh_done(link, NULL, ATA_EH_RESET);
+	if (slave)
+		ata_eh_done(slave, NULL, ATA_EH_RESET);
 	ehc->last_reset = jiffies;
 	ehc->i.action |= ATA_EH_REVALIDATE;
 
@@ -2411,6 +2528,8 @@
  out:
 	/* clear hotplug flag */
 	ehc->i.flags &= ~ATA_EHI_HOTPLUGGED;
+	if (slave)
+		sehc->i.flags &= ~ATA_EHI_HOTPLUGGED;
 
 	spin_lock_irqsave(ap->lock, flags);
 	ap->pflags &= ~ATA_PFLAG_RESETTING;
@@ -2431,7 +2550,7 @@
 	if (time_before(now, deadline)) {
 		unsigned long delta = deadline - now;
 
-		ata_link_printk(link, KERN_WARNING,
+		ata_link_printk(failed_link, KERN_WARNING,
 			"reset failed (errno=%d), retrying in %u secs\n",
 			rc, DIV_ROUND_UP(jiffies_to_msecs(delta), 1000));
 
@@ -2439,13 +2558,92 @@
 			delta = schedule_timeout_uninterruptible(delta);
 	}
 
-	if (rc == -EPIPE || try == max_tries - 1)
+	if (try == max_tries - 1) {
 		sata_down_spd_limit(link);
+		if (slave)
+			sata_down_spd_limit(slave);
+	} else if (rc == -EPIPE)
+		sata_down_spd_limit(failed_link);
+
 	if (hardreset)
 		reset = hardreset;
 	goto retry;
 }
 
+static inline void ata_eh_pull_park_action(struct ata_port *ap)
+{
+	struct ata_link *link;
+	struct ata_device *dev;
+	unsigned long flags;
+
+	/*
+	 * This function can be thought of as an extended version of
+	 * ata_eh_about_to_do() specially crafted to accommodate the
+	 * requirements of ATA_EH_PARK handling. Since the EH thread
+	 * does not leave the do {} while () loop in ata_eh_recover as
+	 * long as the timeout for a park request to *one* device on
+	 * the port has not expired, and since we still want to pick
+	 * up park requests to other devices on the same port or
+	 * timeout updates for the same device, we have to pull
+	 * ATA_EH_PARK actions from eh_info into eh_context.i
+	 * ourselves at the beginning of each pass over the loop.
+	 *
+	 * Additionally, all write accesses to &ap->park_req_pending
+	 * through INIT_COMPLETION() (see below) or complete_all()
+	 * (see ata_scsi_park_store()) are protected by the host lock.
+	 * As a result we have that park_req_pending.done is zero on
+	 * exit from this function, i.e. when ATA_EH_PARK actions for
+	 * *all* devices on port ap have been pulled into the
+	 * respective eh_context structs. If, and only if,
+	 * park_req_pending.done is non-zero by the time we reach
+	 * wait_for_completion_timeout(), another ATA_EH_PARK action
+	 * has been scheduled for at least one of the devices on port
+	 * ap and we have to cycle over the do {} while () loop in
+	 * ata_eh_recover() again.
+	 */
+
+	spin_lock_irqsave(ap->lock, flags);
+	INIT_COMPLETION(ap->park_req_pending);
+	ata_port_for_each_link(link, ap) {
+		ata_link_for_each_dev(dev, link) {
+			struct ata_eh_info *ehi = &link->eh_info;
+
+			link->eh_context.i.dev_action[dev->devno] |=
+				ehi->dev_action[dev->devno] & ATA_EH_PARK;
+			ata_eh_clear_action(link, dev, ehi, ATA_EH_PARK);
+		}
+	}
+	spin_unlock_irqrestore(ap->lock, flags);
+}
+
+static void ata_eh_park_issue_cmd(struct ata_device *dev, int park)
+{
+	struct ata_eh_context *ehc = &dev->link->eh_context;
+	struct ata_taskfile tf;
+	unsigned int err_mask;
+
+	ata_tf_init(dev, &tf);
+	if (park) {
+		ehc->unloaded_mask |= 1 << dev->devno;
+		tf.command = ATA_CMD_IDLEIMMEDIATE;
+		tf.feature = 0x44;
+		tf.lbal = 0x4c;
+		tf.lbam = 0x4e;
+		tf.lbah = 0x55;
+	} else {
+		ehc->unloaded_mask &= ~(1 << dev->devno);
+		tf.command = ATA_CMD_CHK_POWER;
+	}
+
+	tf.flags |= ATA_TFLAG_DEVICE | ATA_TFLAG_ISADDR;
+	tf.protocol |= ATA_PROT_NODATA;
+	err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0, 0);
+	if (park && (err_mask || tf.lbal != 0xc4)) {
+		ata_dev_printk(dev, KERN_ERR, "head unload failed!\n");
+		ehc->unloaded_mask &= ~(1 << dev->devno);
+	}
+}
+
 static int ata_eh_revalidate_and_attach(struct ata_link *link,
 					struct ata_device **r_failed_dev)
 {
@@ -2472,7 +2670,7 @@
 		if ((action & ATA_EH_REVALIDATE) && ata_dev_enabled(dev)) {
 			WARN_ON(dev->class == ATA_DEV_PMP);
 
-			if (ata_link_offline(link)) {
+			if (ata_phys_link_offline(ata_dev_phys_link(dev))) {
 				rc = -EIO;
 				goto err;
 			}
@@ -2610,6 +2808,53 @@
 	return rc;
 }
 
+/**
+ *	atapi_eh_clear_ua - Clear ATAPI UNIT ATTENTION after reset
+ *	@dev: ATAPI device to clear UA for
+ *
+ *	Resets and other operations can make an ATAPI device raise
+ *	UNIT ATTENTION which causes the next operation to fail.  This
+ *	function clears UA.
+ *
+ *	LOCKING:
+ *	EH context (may sleep).
+ *
+ *	RETURNS:
+ *	0 on success, -errno on failure.
+ */
+static int atapi_eh_clear_ua(struct ata_device *dev)
+{
+	int i;
+
+	for (i = 0; i < ATA_EH_UA_TRIES; i++) {
+		u8 sense_buffer[SCSI_SENSE_BUFFERSIZE];
+		u8 sense_key = 0;
+		unsigned int err_mask;
+
+		err_mask = atapi_eh_tur(dev, &sense_key);
+		if (err_mask != 0 && err_mask != AC_ERR_DEV) {
+			ata_dev_printk(dev, KERN_WARNING, "TEST_UNIT_READY "
+				"failed (err_mask=0x%x)\n", err_mask);
+			return -EIO;
+		}
+
+		if (!err_mask || sense_key != UNIT_ATTENTION)
+			return 0;
+
+		err_mask = atapi_eh_request_sense(dev, sense_buffer, sense_key);
+		if (err_mask) {
+			ata_dev_printk(dev, KERN_WARNING, "failed to clear "
+				"UNIT ATTENTION (err_mask=0x%x)\n", err_mask);
+			return -EIO;
+		}
+	}
+
+	ata_dev_printk(dev, KERN_WARNING,
+		"UNIT ATTENTION persists after %d tries\n", ATA_EH_UA_TRIES);
+
+	return 0;
+}
+
 static int ata_link_nr_enabled(struct ata_link *link)
 {
 	struct ata_device *dev;
@@ -2697,7 +2942,7 @@
 			/* This is the last chance, better to slow
 			 * down than lose it.
 			 */
-			sata_down_spd_limit(dev->link);
+			sata_down_spd_limit(ata_dev_phys_link(dev));
 			ata_down_xfermask_limit(dev, ATA_DNXFER_PIO);
 		}
 	}
@@ -2707,7 +2952,7 @@
 		ata_dev_disable(dev);
 
 		/* detach if offline */
-		if (ata_link_offline(dev->link))
+		if (ata_phys_link_offline(ata_dev_phys_link(dev)))
 			ata_eh_detach_dev(dev);
 
 		/* schedule probe if necessary */
@@ -2755,7 +3000,7 @@
 	struct ata_device *dev;
 	int nr_failed_devs;
 	int rc;
-	unsigned long flags;
+	unsigned long flags, deadline;
 
 	DPRINTK("ENTER\n");
 
@@ -2829,6 +3074,56 @@
 		}
 	}
 
+	do {
+		unsigned long now;
+
+		/*
+		 * clears ATA_EH_PARK in eh_info and resets
+		 * ap->park_req_pending
+		 */
+		ata_eh_pull_park_action(ap);
+
+		deadline = jiffies;
+		ata_port_for_each_link(link, ap) {
+			ata_link_for_each_dev(dev, link) {
+				struct ata_eh_context *ehc = &link->eh_context;
+				unsigned long tmp;
+
+				if (dev->class != ATA_DEV_ATA)
+					continue;
+				if (!(ehc->i.dev_action[dev->devno] &
+				      ATA_EH_PARK))
+					continue;
+				tmp = dev->unpark_deadline;
+				if (time_before(deadline, tmp))
+					deadline = tmp;
+				else if (time_before_eq(tmp, jiffies))
+					continue;
+				if (ehc->unloaded_mask & (1 << dev->devno))
+					continue;
+
+				ata_eh_park_issue_cmd(dev, 1);
+			}
+		}
+
+		now = jiffies;
+		if (time_before_eq(deadline, now))
+			break;
+
+		deadline = wait_for_completion_timeout(&ap->park_req_pending,
+						       deadline - now);
+	} while (deadline);
+	ata_port_for_each_link(link, ap) {
+		ata_link_for_each_dev(dev, link) {
+			if (!(link->eh_context.unloaded_mask &
+			      (1 << dev->devno)))
+				continue;
+
+			ata_eh_park_issue_cmd(dev, 0);
+			ata_eh_done(link, dev, ATA_EH_PARK);
+		}
+	}
+
 	/* the rest */
 	ata_port_for_each_link(link, ap) {
 		struct ata_eh_context *ehc = &link->eh_context;
@@ -2852,6 +3147,20 @@
 			ehc->i.flags &= ~ATA_EHI_SETMODE;
 		}
 
+		/* If reset has been issued, clear UA to avoid
+		 * disrupting the current users of the device.
+		 */
+		if (ehc->i.flags & ATA_EHI_DID_RESET) {
+			ata_link_for_each_dev(dev, link) {
+				if (dev->class != ATA_DEV_ATAPI)
+					continue;
+				rc = atapi_eh_clear_ua(dev);
+				if (rc)
+					goto dev_fail;
+			}
+		}
+
+		/* configure link power saving */
 		if (ehc->i.action & ATA_EH_LPM)
 			ata_link_for_each_dev(dev, link)
 				ata_dev_enable_pm(dev, ap->pm_policy);
diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c
index b9d3ba4..5d312dc 100644
--- a/drivers/ata/libata-scsi.c
+++ b/drivers/ata/libata-scsi.c
@@ -183,6 +183,105 @@
 		ata_scsi_lpm_show, ata_scsi_lpm_put);
 EXPORT_SYMBOL_GPL(dev_attr_link_power_management_policy);
 
+static ssize_t ata_scsi_park_show(struct device *device,
+				  struct device_attribute *attr, char *buf)
+{
+	struct scsi_device *sdev = to_scsi_device(device);
+	struct ata_port *ap;
+	struct ata_link *link;
+	struct ata_device *dev;
+	unsigned long flags;
+	unsigned int uninitialized_var(msecs);
+	int rc = 0;
+
+	ap = ata_shost_to_port(sdev->host);
+
+	spin_lock_irqsave(ap->lock, flags);
+	dev = ata_scsi_find_dev(ap, sdev);
+	if (!dev) {
+		rc = -ENODEV;
+		goto unlock;
+	}
+	if (dev->flags & ATA_DFLAG_NO_UNLOAD) {
+		rc = -EOPNOTSUPP;
+		goto unlock;
+	}
+
+	link = dev->link;
+	if (ap->pflags & ATA_PFLAG_EH_IN_PROGRESS &&
+	    link->eh_context.unloaded_mask & (1 << dev->devno) &&
+	    time_after(dev->unpark_deadline, jiffies))
+		msecs = jiffies_to_msecs(dev->unpark_deadline - jiffies);
+	else
+		msecs = 0;
+
+unlock:
+	spin_unlock_irq(ap->lock);
+
+	return rc ? rc : snprintf(buf, 20, "%u\n", msecs);
+}
+
+static ssize_t ata_scsi_park_store(struct device *device,
+				   struct device_attribute *attr,
+				   const char *buf, size_t len)
+{
+	struct scsi_device *sdev = to_scsi_device(device);
+	struct ata_port *ap;
+	struct ata_device *dev;
+	long int input;
+	unsigned long flags;
+	int rc;
+
+	rc = strict_strtol(buf, 10, &input);
+	if (rc || input < -2)
+		return -EINVAL;
+	if (input > ATA_TMOUT_MAX_PARK) {
+		rc = -EOVERFLOW;
+		input = ATA_TMOUT_MAX_PARK;
+	}
+
+	ap = ata_shost_to_port(sdev->host);
+
+	spin_lock_irqsave(ap->lock, flags);
+	dev = ata_scsi_find_dev(ap, sdev);
+	if (unlikely(!dev)) {
+		rc = -ENODEV;
+		goto unlock;
+	}
+	if (dev->class != ATA_DEV_ATA) {
+		rc = -EOPNOTSUPP;
+		goto unlock;
+	}
+
+	if (input >= 0) {
+		if (dev->flags & ATA_DFLAG_NO_UNLOAD) {
+			rc = -EOPNOTSUPP;
+			goto unlock;
+		}
+
+		dev->unpark_deadline = ata_deadline(jiffies, input);
+		dev->link->eh_info.dev_action[dev->devno] |= ATA_EH_PARK;
+		ata_port_schedule_eh(ap);
+		complete(&ap->park_req_pending);
+	} else {
+		switch (input) {
+		case -1:
+			dev->flags &= ~ATA_DFLAG_NO_UNLOAD;
+			break;
+		case -2:
+			dev->flags |= ATA_DFLAG_NO_UNLOAD;
+			break;
+		}
+	}
+unlock:
+	spin_unlock_irqrestore(ap->lock, flags);
+
+	return rc ? rc : len;
+}
+DEVICE_ATTR(unload_heads, S_IRUGO | S_IWUSR,
+	    ata_scsi_park_show, ata_scsi_park_store);
+EXPORT_SYMBOL_GPL(dev_attr_unload_heads);
+
 static void ata_scsi_set_sense(struct scsi_cmnd *cmd, u8 sk, u8 asc, u8 ascq)
 {
 	cmd->result = (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
@@ -269,6 +368,12 @@
 			ata_scsi_activity_store);
 EXPORT_SYMBOL_GPL(dev_attr_sw_activity);
 
+struct device_attribute *ata_common_sdev_attrs[] = {
+	&dev_attr_unload_heads,
+	NULL
+};
+EXPORT_SYMBOL_GPL(ata_common_sdev_attrs);
+
 static void ata_scsi_invalid_field(struct scsi_cmnd *cmd,
 				   void (*done)(struct scsi_cmnd *))
 {
@@ -398,7 +503,7 @@
 	scsi_cmd[0] = ATA_16;
 
 	scsi_cmd[4] = args[2];
-	if (args[0] == WIN_SMART) { /* hack -- ide driver does this too... */
+	if (args[0] == ATA_CMD_SMART) { /* hack -- ide driver does this too */
 		scsi_cmd[6]  = args[3];
 		scsi_cmd[8]  = args[1];
 		scsi_cmd[10] = 0x4f;
@@ -954,6 +1059,9 @@
 static int ata_scsi_dev_config(struct scsi_device *sdev,
 			       struct ata_device *dev)
 {
+	if (!ata_id_has_unload(dev->id))
+		dev->flags |= ATA_DFLAG_NO_UNLOAD;
+
 	/* configure max sectors */
 	blk_queue_max_sectors(sdev->request_queue, dev->max_sectors);
 
@@ -977,6 +1085,10 @@
 
 		blk_queue_dma_drain(q, atapi_drain_needed, buf, ATAPI_MAX_DRAIN);
 	} else {
+		if (ata_id_is_ssd(dev->id))
+			queue_flag_set_unlocked(QUEUE_FLAG_NONROT,
+						sdev->request_queue);
+
 		/* ATA devices must be sector aligned */
 		blk_queue_update_dma_alignment(sdev->request_queue,
 					       ATA_SECT_SIZE - 1);
diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h
index ade5c75..fe2839e 100644
--- a/drivers/ata/libata.h
+++ b/drivers/ata/libata.h
@@ -70,6 +70,7 @@
 extern int libata_fua;
 extern int libata_noacpi;
 extern int libata_allow_tpm;
+extern struct ata_link *ata_dev_phys_link(struct ata_device *dev);
 extern void ata_force_cbl(struct ata_port *ap);
 extern u64 ata_tf_to_lba(const struct ata_taskfile *tf);
 extern u64 ata_tf_to_lba48(const struct ata_taskfile *tf);
@@ -107,6 +108,8 @@
 extern void __ata_qc_complete(struct ata_queued_cmd *qc);
 extern int atapi_check_dma(struct ata_queued_cmd *qc);
 extern void swap_buf_le16(u16 *buf, unsigned int buf_words);
+extern bool ata_phys_link_online(struct ata_link *link);
+extern bool ata_phys_link_offline(struct ata_link *link);
 extern void ata_dev_init(struct ata_device *dev);
 extern void ata_link_init(struct ata_port *ap, struct ata_link *link, int pmp);
 extern int sata_link_init_spd(struct ata_link *link);
@@ -152,7 +155,7 @@
 /* libata-eh.c */
 extern unsigned long ata_internal_cmd_timeout(struct ata_device *dev, u8 cmd);
 extern void ata_internal_cmd_timed_out(struct ata_device *dev, u8 cmd);
-extern enum scsi_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd);
+extern enum blk_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd);
 extern void ata_scsi_error(struct Scsi_Host *host);
 extern void ata_port_wait_eh(struct ata_port *ap);
 extern void ata_eh_fastdrain_timerfn(unsigned long arg);
diff --git a/drivers/ata/pata_bf54x.c b/drivers/ata/pata_bf54x.c
index d393290..1266924 100644
--- a/drivers/ata/pata_bf54x.c
+++ b/drivers/ata/pata_bf54x.c
@@ -1632,6 +1632,8 @@
 		return -ENODEV;
 	}
 
+	dev_set_drvdata(&pdev->dev, host);
+
 	return 0;
 }
 
@@ -1648,6 +1650,7 @@
 	struct ata_host *host = dev_get_drvdata(dev);
 
 	ata_host_detach(host);
+	dev_set_drvdata(&pdev->dev, NULL);
 
 	peripheral_free_list(atapi_io_port);
 
@@ -1655,27 +1658,44 @@
 }
 
 #ifdef CONFIG_PM
-int bfin_atapi_suspend(struct platform_device *pdev, pm_message_t state)
+static int bfin_atapi_suspend(struct platform_device *pdev, pm_message_t state)
 {
-	return 0;
+	struct ata_host *host = dev_get_drvdata(&pdev->dev);
+	if (host)
+		return ata_host_suspend(host, state);
+	else
+		return 0;
 }
 
-int bfin_atapi_resume(struct platform_device *pdev)
+static int bfin_atapi_resume(struct platform_device *pdev)
 {
+	struct ata_host *host = dev_get_drvdata(&pdev->dev);
+	int ret;
+
+	if (host) {
+		ret = bfin_reset_controller(host);
+		if (ret) {
+			printk(KERN_ERR DRV_NAME ": Error during HW init\n");
+			return ret;
+		}
+		ata_host_resume(host);
+	}
+
 	return 0;
 }
+#else
+#define bfin_atapi_suspend NULL
+#define bfin_atapi_resume NULL
 #endif
 
 static struct platform_driver bfin_atapi_driver = {
 	.probe			= bfin_atapi_probe,
 	.remove			= __devexit_p(bfin_atapi_remove),
+	.suspend		= bfin_atapi_suspend,
+	.resume			= bfin_atapi_resume,
 	.driver = {
 		.name		= DRV_NAME,
 		.owner		= THIS_MODULE,
-#ifdef CONFIG_PM
-		.suspend	= bfin_atapi_suspend,
-		.resume		= bfin_atapi_resume,
-#endif
 	},
 };
 
diff --git a/drivers/ata/pata_pcmcia.c b/drivers/ata/pata_pcmcia.c
index 41b4361..02b596b 100644
--- a/drivers/ata/pata_pcmcia.c
+++ b/drivers/ata/pata_pcmcia.c
@@ -148,6 +148,64 @@
 #define CS_CHECK(fn, ret) \
 do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)
 
+
+struct pcmcia_config_check {
+	unsigned long ctl_base;
+	int skip_vcc;
+	int is_kme;
+};
+
+static int pcmcia_check_one_config(struct pcmcia_device *pdev,
+				   cistpl_cftable_entry_t *cfg,
+				   cistpl_cftable_entry_t *dflt,
+				   unsigned int vcc,
+				   void *priv_data)
+{
+	struct pcmcia_config_check *stk = priv_data;
+
+	/* Check for matching Vcc, unless we're desperate */
+	if (!stk->skip_vcc) {
+		if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) {
+			if (vcc != cfg->vcc.param[CISTPL_POWER_VNOM] / 10000)
+				return -ENODEV;
+		} else if (dflt->vcc.present & (1 << CISTPL_POWER_VNOM)) {
+			if (vcc != dflt->vcc.param[CISTPL_POWER_VNOM] / 10000)
+				return -ENODEV;
+		}
+	}
+
+	if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM))
+		pdev->conf.Vpp = cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000;
+	else if (dflt->vpp1.present & (1 << CISTPL_POWER_VNOM))
+		pdev->conf.Vpp = dflt->vpp1.param[CISTPL_POWER_VNOM] / 10000;
+
+	if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) {
+		cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io;
+		pdev->io.BasePort1 = io->win[0].base;
+		pdev->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK;
+		if (!(io->flags & CISTPL_IO_16BIT))
+			pdev->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
+		if (io->nwin == 2) {
+			pdev->io.NumPorts1 = 8;
+			pdev->io.BasePort2 = io->win[1].base;
+			pdev->io.NumPorts2 = (stk->is_kme) ? 2 : 1;
+			if (pcmcia_request_io(pdev, &pdev->io) != 0)
+				return -ENODEV;
+			stk->ctl_base = pdev->io.BasePort2;
+		} else if ((io->nwin == 1) && (io->win[0].len >= 16)) {
+			pdev->io.NumPorts1 = io->win[0].len;
+			pdev->io.NumPorts2 = 0;
+			if (pcmcia_request_io(pdev, &pdev->io) != 0)
+				return -ENODEV;
+			stk->ctl_base = pdev->io.BasePort1 + 0x0e;
+		} else
+			return -ENODEV;
+		/* If we've got this far, we're done */
+		return 0;
+	}
+	return -ENODEV;
+}
+
 /**
  *	pcmcia_init_one		-	attach a PCMCIA interface
  *	@pdev: pcmcia device
@@ -161,19 +219,11 @@
 	struct ata_host *host;
 	struct ata_port *ap;
 	struct ata_pcmcia_info *info;
-	tuple_t tuple;
-	struct {
-		unsigned short buf[128];
-		cisparse_t parse;
-		config_info_t conf;
-		cistpl_cftable_entry_t dflt;
-	} *stk = NULL;
-	cistpl_cftable_entry_t *cfg;
-	int pass, last_ret = 0, last_fn = 0, is_kme = 0, ret = -ENOMEM, p;
+	struct pcmcia_config_check *stk = NULL;
+	int last_ret = 0, last_fn = 0, is_kme = 0, ret = -ENOMEM, p;
 	unsigned long io_base, ctl_base;
 	void __iomem *io_addr, *ctl_addr;
 	int n_ports = 1;
-
 	struct ata_port_operations *ops = &pcmcia_port_ops;
 
 	info = kzalloc(sizeof(*info), GFP_KERNEL);
@@ -193,96 +243,27 @@
 	pdev->conf.Attributes = CONF_ENABLE_IRQ;
 	pdev->conf.IntType = INT_MEMORY_AND_IO;
 
-	/* Allocate resoure probing structures */
-
-	stk = kzalloc(sizeof(*stk), GFP_KERNEL);
-	if (!stk)
-		goto out1;
-
-	cfg = &stk->parse.cftable_entry;
-
-	/* Tuples we are walking */
-	tuple.TupleData = (cisdata_t *)&stk->buf;
-	tuple.TupleOffset = 0;
-	tuple.TupleDataMax = 255;
-	tuple.Attributes = 0;
-
 	/* See if we have a manufacturer identifier. Use it to set is_kme for
 	   vendor quirks */
 	is_kme = ((pdev->manf_id == MANFID_KME) &&
 		  ((pdev->card_id == PRODID_KME_KXLC005_A) ||
 		   (pdev->card_id == PRODID_KME_KXLC005_B)));
 
-	/* Not sure if this is right... look up the current Vcc */
-	CS_CHECK(GetConfigurationInfo, pcmcia_get_configuration_info(pdev, &stk->conf));
-/*	link->conf.Vcc = stk->conf.Vcc; */
+	/* Allocate resoure probing structures */
 
-	pass = io_base = ctl_base = 0;
-	tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
-	tuple.Attributes = 0;
-	CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(pdev, &tuple));
+	stk = kzalloc(sizeof(*stk), GFP_KERNEL);
+	if (!stk)
+		goto out1;
+	stk->is_kme = is_kme;
+	stk->skip_vcc = io_base = ctl_base = 0;
 
-	/* Now munch the resources looking for a suitable set */
-	while (1) {
-		if (pcmcia_get_tuple_data(pdev, &tuple) != 0)
-			goto next_entry;
-		if (pcmcia_parse_tuple(pdev, &tuple, &stk->parse) != 0)
-			goto next_entry;
-		/* Check for matching Vcc, unless we're desperate */
-		if (!pass) {
-			if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) {
-				if (stk->conf.Vcc != cfg->vcc.param[CISTPL_POWER_VNOM] / 10000)
-					goto next_entry;
-			} else if (stk->dflt.vcc.present & (1 << CISTPL_POWER_VNOM)) {
-				if (stk->conf.Vcc != stk->dflt.vcc.param[CISTPL_POWER_VNOM] / 10000)
-					goto next_entry;
-			}
-		}
-
-		if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM))
-			pdev->conf.Vpp = cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000;
-		else if (stk->dflt.vpp1.present & (1 << CISTPL_POWER_VNOM))
-			pdev->conf.Vpp = stk->dflt.vpp1.param[CISTPL_POWER_VNOM] / 10000;
-
-		if ((cfg->io.nwin > 0) || (stk->dflt.io.nwin > 0)) {
-			cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &stk->dflt.io;
-			pdev->conf.ConfigIndex = cfg->index;
-			pdev->io.BasePort1 = io->win[0].base;
-			pdev->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK;
-			if (!(io->flags & CISTPL_IO_16BIT))
-				pdev->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
-			if (io->nwin == 2) {
-				pdev->io.NumPorts1 = 8;
-				pdev->io.BasePort2 = io->win[1].base;
-				pdev->io.NumPorts2 = (is_kme) ? 2 : 1;
-				if (pcmcia_request_io(pdev, &pdev->io) != 0)
-					goto next_entry;
-				io_base = pdev->io.BasePort1;
-				ctl_base = pdev->io.BasePort2;
-			} else if ((io->nwin == 1) && (io->win[0].len >= 16)) {
-				pdev->io.NumPorts1 = io->win[0].len;
-				pdev->io.NumPorts2 = 0;
-				if (pcmcia_request_io(pdev, &pdev->io) != 0)
-					goto next_entry;
-				io_base = pdev->io.BasePort1;
-				ctl_base = pdev->io.BasePort1 + 0x0e;
-			} else
-				goto next_entry;
-			/* If we've got this far, we're done */
-			break;
-		}
-next_entry:
-		if (cfg->flags & CISTPL_CFTABLE_DEFAULT)
-			memcpy(&stk->dflt, cfg, sizeof(stk->dflt));
-		if (pass) {
-			CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(pdev, &tuple));
-		} else if (pcmcia_get_next_tuple(pdev, &tuple) != 0) {
-			CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(pdev, &tuple));
-			memset(&stk->dflt, 0, sizeof(stk->dflt));
-			pass++;
-		}
+	if (pcmcia_loop_config(pdev, pcmcia_check_one_config, stk)) {
+		stk->skip_vcc = 1;
+		if (pcmcia_loop_config(pdev, pcmcia_check_one_config, stk))
+			goto failed; /* No suitable config found */
 	}
-
+	io_base = pdev->io.BasePort1;
+	ctl_base = stk->ctl_base;
 	CS_CHECK(RequestIRQ, pcmcia_request_irq(pdev, &pdev->irq));
 	CS_CHECK(RequestConfiguration, pcmcia_request_configuration(pdev, &pdev->conf));
 
@@ -384,6 +365,7 @@
 	PCMCIA_DEVICE_MANF_CARD(0x0032, 0x0704),
 	PCMCIA_DEVICE_MANF_CARD(0x0032, 0x2904),
 	PCMCIA_DEVICE_MANF_CARD(0x0045, 0x0401),	/* SanDisk CFA */
+	PCMCIA_DEVICE_MANF_CARD(0x004f, 0x0000),	/* Kingston */
 	PCMCIA_DEVICE_MANF_CARD(0x0097, 0x1620), 	/* TI emulated */
 	PCMCIA_DEVICE_MANF_CARD(0x0098, 0x0000),	/* Toshiba */
 	PCMCIA_DEVICE_MANF_CARD(0x00a4, 0x002d),
@@ -404,9 +386,9 @@
 	PCMCIA_DEVICE_PROD_ID12("EXP   ", "CD-ROM", 0x0a5c52fd, 0x66536591),
 	PCMCIA_DEVICE_PROD_ID12("EXP   ", "PnPIDE", 0x0a5c52fd, 0x0c694728),
 	PCMCIA_DEVICE_PROD_ID12("FREECOM", "PCCARD-IDE", 0x5714cbf7, 0x48e0ab8e),
-	PCMCIA_DEVICE_PROD_ID12("Hyperstone", "Model1", 0x3d5b9ef5, 0xca6ab420),
 	PCMCIA_DEVICE_PROD_ID12("HITACHI", "FLASH", 0xf4f43949, 0x9eb86aae),
 	PCMCIA_DEVICE_PROD_ID12("HITACHI", "microdrive", 0xf4f43949, 0xa6d76178),
+	PCMCIA_DEVICE_PROD_ID12("Hyperstone", "Model1", 0x3d5b9ef5, 0xca6ab420),
 	PCMCIA_DEVICE_PROD_ID12("IBM", "microdrive", 0xb569a6e5, 0xa6d76178),
 	PCMCIA_DEVICE_PROD_ID12("IBM", "IBM17JSSFP20", 0xb569a6e5, 0xf2508753),
 	PCMCIA_DEVICE_PROD_ID12("KINGSTON", "CF8GB", 0x2e6d1829, 0xacbe682e),
diff --git a/drivers/ata/pata_sil680.c b/drivers/ata/pata_sil680.c
index e970b22..a598bb3 100644
--- a/drivers/ata/pata_sil680.c
+++ b/drivers/ata/pata_sil680.c
@@ -230,7 +230,7 @@
 		tmpbyte & 1, tmpbyte & 0x30);
 
 	*try_mmio = 0;
-#ifdef CONFIG_PPC_MERGE
+#ifdef CONFIG_PPC
 	if (machine_is(cell))
 		*try_mmio = (tmpbyte & 1) || pci_resource_start(pdev, 5);
 #endif
diff --git a/drivers/ata/sata_fsl.c b/drivers/ata/sata_fsl.c
index 3924e72..1a56db9 100644
--- a/drivers/ata/sata_fsl.c
+++ b/drivers/ata/sata_fsl.c
@@ -469,10 +469,10 @@
 	return true;
 }
 
-static int sata_fsl_scr_write(struct ata_port *ap, unsigned int sc_reg_in,
-			       u32 val)
+static int sata_fsl_scr_write(struct ata_link *link,
+			      unsigned int sc_reg_in, u32 val)
 {
-	struct sata_fsl_host_priv *host_priv = ap->host->private_data;
+	struct sata_fsl_host_priv *host_priv = link->ap->host->private_data;
 	void __iomem *ssr_base = host_priv->ssr_base;
 	unsigned int sc_reg;
 
@@ -493,10 +493,10 @@
 	return 0;
 }
 
-static int sata_fsl_scr_read(struct ata_port *ap, unsigned int sc_reg_in,
-			u32 *val)
+static int sata_fsl_scr_read(struct ata_link *link,
+			     unsigned int sc_reg_in, u32 *val)
 {
-	struct sata_fsl_host_priv *host_priv = ap->host->private_data;
+	struct sata_fsl_host_priv *host_priv = link->ap->host->private_data;
 	void __iomem *ssr_base = host_priv->ssr_base;
 	unsigned int sc_reg;
 
@@ -645,12 +645,12 @@
 	 * Workaround for 8315DS board 3gbps link-up issue,
 	 * currently limit SATA port to GEN1 speed
 	 */
-	sata_fsl_scr_read(ap, SCR_CONTROL, &temp);
+	sata_fsl_scr_read(&ap->link, SCR_CONTROL, &temp);
 	temp &= ~(0xF << 4);
 	temp |= (0x1 << 4);
-	sata_fsl_scr_write(ap, SCR_CONTROL, temp);
+	sata_fsl_scr_write(&ap->link, SCR_CONTROL, temp);
 
-	sata_fsl_scr_read(ap, SCR_CONTROL, &temp);
+	sata_fsl_scr_read(&ap->link, SCR_CONTROL, &temp);
 	dev_printk(KERN_WARNING, dev, "scr_control, speed limited to %x\n",
 			temp);
 #endif
@@ -868,7 +868,7 @@
 			ioread32(CQ + hcr_base),
 			ioread32(CA + hcr_base), ioread32(CC + hcr_base));
 
-		sata_fsl_scr_read(ap, SCR_ERROR, &Serror);
+		sata_fsl_scr_read(&ap->link, SCR_ERROR, &Serror);
 
 		DPRINTK("HStatus = 0x%x\n", ioread32(hcr_base + HSTATUS));
 		DPRINTK("HControl = 0x%x\n", ioread32(hcr_base + HCONTROL));
@@ -972,9 +972,9 @@
 	 * Handle & Clear SError
 	 */
 
-	sata_fsl_scr_read(ap, SCR_ERROR, &SError);
+	sata_fsl_scr_read(&ap->link, SCR_ERROR, &SError);
 	if (unlikely(SError & 0xFFFF0000)) {
-		sata_fsl_scr_write(ap, SCR_ERROR, SError);
+		sata_fsl_scr_write(&ap->link, SCR_ERROR, SError);
 	}
 
 	DPRINTK("error_intr,hStat=0x%x,CE=0x%x,DE =0x%x,SErr=0x%x\n",
@@ -1091,7 +1091,7 @@
 
 	hstatus = ioread32(hcr_base + HSTATUS);
 
-	sata_fsl_scr_read(ap, SCR_ERROR, &SError);
+	sata_fsl_scr_read(&ap->link, SCR_ERROR, &SError);
 
 	if (unlikely(SError & 0xFFFF0000)) {
 		DPRINTK("serror @host_intr : 0x%x\n", SError);
diff --git a/drivers/ata/sata_inic162x.c b/drivers/ata/sata_inic162x.c
index 5032c32..fbbd87c 100644
--- a/drivers/ata/sata_inic162x.c
+++ b/drivers/ata/sata_inic162x.c
@@ -269,9 +269,9 @@
 	writeb(0xff, port_base + PORT_IRQ_STAT);
 }
 
-static int inic_scr_read(struct ata_port *ap, unsigned sc_reg, u32 *val)
+static int inic_scr_read(struct ata_link *link, unsigned sc_reg, u32 *val)
 {
-	void __iomem *scr_addr = inic_port_base(ap) + PORT_SCR;
+	void __iomem *scr_addr = inic_port_base(link->ap) + PORT_SCR;
 	void __iomem *addr;
 
 	if (unlikely(sc_reg >= ARRAY_SIZE(scr_map)))
@@ -286,9 +286,9 @@
 	return 0;
 }
 
-static int inic_scr_write(struct ata_port *ap, unsigned sc_reg, u32 val)
+static int inic_scr_write(struct ata_link *link, unsigned sc_reg, u32 val)
 {
-	void __iomem *scr_addr = inic_port_base(ap) + PORT_SCR;
+	void __iomem *scr_addr = inic_port_base(link->ap) + PORT_SCR;
 
 	if (unlikely(sc_reg >= ARRAY_SIZE(scr_map)))
 		return -EINVAL;
diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c
index c815f8e..2b24ae5 100644
--- a/drivers/ata/sata_mv.c
+++ b/drivers/ata/sata_mv.c
@@ -493,10 +493,10 @@
 	void (*reset_bus)(struct ata_host *host, void __iomem *mmio);
 };
 
-static int mv_scr_read(struct ata_port *ap, unsigned int sc_reg_in, u32 *val);
-static int mv_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val);
-static int mv5_scr_read(struct ata_port *ap, unsigned int sc_reg_in, u32 *val);
-static int mv5_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val);
+static int mv_scr_read(struct ata_link *link, unsigned int sc_reg_in, u32 *val);
+static int mv_scr_write(struct ata_link *link, unsigned int sc_reg_in, u32 val);
+static int mv5_scr_read(struct ata_link *link, unsigned int sc_reg_in, u32 *val);
+static int mv5_scr_write(struct ata_link *link, unsigned int sc_reg_in, u32 val);
 static int mv_port_start(struct ata_port *ap);
 static void mv_port_stop(struct ata_port *ap);
 static int mv_qc_defer(struct ata_queued_cmd *qc);
@@ -1070,23 +1070,23 @@
 	return ofs;
 }
 
-static int mv_scr_read(struct ata_port *ap, unsigned int sc_reg_in, u32 *val)
+static int mv_scr_read(struct ata_link *link, unsigned int sc_reg_in, u32 *val)
 {
 	unsigned int ofs = mv_scr_offset(sc_reg_in);
 
 	if (ofs != 0xffffffffU) {
-		*val = readl(mv_ap_base(ap) + ofs);
+		*val = readl(mv_ap_base(link->ap) + ofs);
 		return 0;
 	} else
 		return -EINVAL;
 }
 
-static int mv_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val)
+static int mv_scr_write(struct ata_link *link, unsigned int sc_reg_in, u32 val)
 {
 	unsigned int ofs = mv_scr_offset(sc_reg_in);
 
 	if (ofs != 0xffffffffU) {
-		writelfl(val, mv_ap_base(ap) + ofs);
+		writelfl(val, mv_ap_base(link->ap) + ofs);
 		return 0;
 	} else
 		return -EINVAL;
@@ -2251,11 +2251,11 @@
 	return ofs;
 }
 
-static int mv5_scr_read(struct ata_port *ap, unsigned int sc_reg_in, u32 *val)
+static int mv5_scr_read(struct ata_link *link, unsigned int sc_reg_in, u32 *val)
 {
-	struct mv_host_priv *hpriv = ap->host->private_data;
+	struct mv_host_priv *hpriv = link->ap->host->private_data;
 	void __iomem *mmio = hpriv->base;
-	void __iomem *addr = mv5_phy_base(mmio, ap->port_no);
+	void __iomem *addr = mv5_phy_base(mmio, link->ap->port_no);
 	unsigned int ofs = mv5_scr_offset(sc_reg_in);
 
 	if (ofs != 0xffffffffU) {
@@ -2265,11 +2265,11 @@
 		return -EINVAL;
 }
 
-static int mv5_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val)
+static int mv5_scr_write(struct ata_link *link, unsigned int sc_reg_in, u32 val)
 {
-	struct mv_host_priv *hpriv = ap->host->private_data;
+	struct mv_host_priv *hpriv = link->ap->host->private_data;
 	void __iomem *mmio = hpriv->base;
-	void __iomem *addr = mv5_phy_base(mmio, ap->port_no);
+	void __iomem *addr = mv5_phy_base(mmio, link->ap->port_no);
 	unsigned int ofs = mv5_scr_offset(sc_reg_in);
 
 	if (ofs != 0xffffffffU) {
diff --git a/drivers/ata/sata_nv.c b/drivers/ata/sata_nv.c
index 1e1f3f3..fae3841 100644
--- a/drivers/ata/sata_nv.c
+++ b/drivers/ata/sata_nv.c
@@ -302,13 +302,15 @@
 static irqreturn_t nv_generic_interrupt(int irq, void *dev_instance);
 static irqreturn_t nv_nf2_interrupt(int irq, void *dev_instance);
 static irqreturn_t nv_ck804_interrupt(int irq, void *dev_instance);
-static int nv_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val);
-static int nv_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val);
+static int nv_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val);
+static int nv_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val);
 
 static void nv_nf2_freeze(struct ata_port *ap);
 static void nv_nf2_thaw(struct ata_port *ap);
 static void nv_ck804_freeze(struct ata_port *ap);
 static void nv_ck804_thaw(struct ata_port *ap);
+static int nv_hardreset(struct ata_link *link, unsigned int *class,
+			unsigned long deadline);
 static int nv_adma_slave_config(struct scsi_device *sdev);
 static int nv_adma_check_atapi_dma(struct ata_queued_cmd *qc);
 static void nv_adma_qc_prep(struct ata_queued_cmd *qc);
@@ -403,28 +405,45 @@
 	.slave_configure	= nv_swncq_slave_config,
 };
 
-static struct ata_port_operations nv_generic_ops = {
+/* OSDL bz3352 reports that some nv controllers can't determine device
+ * signature reliably and nv_hardreset is implemented to work around
+ * the problem.  This was reported on nf3 and it's unclear whether any
+ * other controllers are affected.  However, the workaround has been
+ * applied to all variants and there isn't much to gain by trying to
+ * find out exactly which ones are affected at this point especially
+ * because NV has moved over to ahci for newer controllers.
+ */
+static struct ata_port_operations nv_common_ops = {
 	.inherits		= &ata_bmdma_port_ops,
-	.hardreset		= ATA_OP_NULL,
+	.hardreset		= nv_hardreset,
 	.scr_read		= nv_scr_read,
 	.scr_write		= nv_scr_write,
 };
 
+/* OSDL bz11195 reports that link doesn't come online after hardreset
+ * on generic nv's and there have been several other similar reports
+ * on linux-ide.  Disable hardreset for generic nv's.
+ */
+static struct ata_port_operations nv_generic_ops = {
+	.inherits		= &nv_common_ops,
+	.hardreset		= ATA_OP_NULL,
+};
+
 static struct ata_port_operations nv_nf2_ops = {
-	.inherits		= &nv_generic_ops,
+	.inherits		= &nv_common_ops,
 	.freeze			= nv_nf2_freeze,
 	.thaw			= nv_nf2_thaw,
 };
 
 static struct ata_port_operations nv_ck804_ops = {
-	.inherits		= &nv_generic_ops,
+	.inherits		= &nv_common_ops,
 	.freeze			= nv_ck804_freeze,
 	.thaw			= nv_ck804_thaw,
 	.host_stop		= nv_ck804_host_stop,
 };
 
 static struct ata_port_operations nv_adma_ops = {
-	.inherits		= &nv_generic_ops,
+	.inherits		= &nv_common_ops,
 
 	.check_atapi_dma	= nv_adma_check_atapi_dma,
 	.sff_tf_read		= nv_adma_tf_read,
@@ -448,7 +467,7 @@
 };
 
 static struct ata_port_operations nv_swncq_ops = {
-	.inherits		= &nv_generic_ops,
+	.inherits		= &nv_common_ops,
 
 	.qc_defer		= ata_std_qc_defer,
 	.qc_prep		= nv_swncq_qc_prep,
@@ -1492,21 +1511,21 @@
 	return ret;
 }
 
-static int nv_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
+static int nv_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val)
 {
 	if (sc_reg > SCR_CONTROL)
 		return -EINVAL;
 
-	*val = ioread32(ap->ioaddr.scr_addr + (sc_reg * 4));
+	*val = ioread32(link->ap->ioaddr.scr_addr + (sc_reg * 4));
 	return 0;
 }
 
-static int nv_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val)
+static int nv_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val)
 {
 	if (sc_reg > SCR_CONTROL)
 		return -EINVAL;
 
-	iowrite32(val, ap->ioaddr.scr_addr + (sc_reg * 4));
+	iowrite32(val, link->ap->ioaddr.scr_addr + (sc_reg * 4));
 	return 0;
 }
 
@@ -1586,6 +1605,21 @@
 	ata_sff_thaw(ap);
 }
 
+static int nv_hardreset(struct ata_link *link, unsigned int *class,
+			unsigned long deadline)
+{
+	int rc;
+
+	/* SATA hardreset fails to retrieve proper device signature on
+	 * some controllers.  Request follow up SRST.  For more info,
+	 * see http://bugzilla.kernel.org/show_bug.cgi?id=3352
+	 */
+	rc = sata_sff_hardreset(link, class, deadline);
+	if (rc)
+		return rc;
+	return -EAGAIN;
+}
+
 static void nv_adma_error_handler(struct ata_port *ap)
 {
 	struct nv_adma_port_priv *pp = ap->private_data;
@@ -2184,9 +2218,9 @@
 	if (!pp->qc_active)
 		return;
 
-	if (ap->ops->scr_read(ap, SCR_ERROR, &serror))
+	if (ap->ops->scr_read(&ap->link, SCR_ERROR, &serror))
 		return;
-	ap->ops->scr_write(ap, SCR_ERROR, serror);
+	ap->ops->scr_write(&ap->link, SCR_ERROR, serror);
 
 	if (ata_stat & ATA_ERR) {
 		ata_ehi_clear_desc(ehi);
diff --git a/drivers/ata/sata_promise.c b/drivers/ata/sata_promise.c
index 030665b..750d8cd 100644
--- a/drivers/ata/sata_promise.c
+++ b/drivers/ata/sata_promise.c
@@ -137,8 +137,8 @@
 	dma_addr_t		pkt_dma;
 };
 
-static int pdc_sata_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val);
-static int pdc_sata_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val);
+static int pdc_sata_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val);
+static int pdc_sata_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val);
 static int pdc_ata_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
 static int pdc_common_port_start(struct ata_port *ap);
 static int pdc_sata_port_start(struct ata_port *ap);
@@ -386,19 +386,21 @@
 	return ATA_CBL_SATA;
 }
 
-static int pdc_sata_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
+static int pdc_sata_scr_read(struct ata_link *link,
+			     unsigned int sc_reg, u32 *val)
 {
 	if (sc_reg > SCR_CONTROL)
 		return -EINVAL;
-	*val = readl(ap->ioaddr.scr_addr + (sc_reg * 4));
+	*val = readl(link->ap->ioaddr.scr_addr + (sc_reg * 4));
 	return 0;
 }
 
-static int pdc_sata_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val)
+static int pdc_sata_scr_write(struct ata_link *link,
+			      unsigned int sc_reg, u32 val)
 {
 	if (sc_reg > SCR_CONTROL)
 		return -EINVAL;
-	writel(val, ap->ioaddr.scr_addr + (sc_reg * 4));
+	writel(val, link->ap->ioaddr.scr_addr + (sc_reg * 4));
 	return 0;
 }
 
@@ -731,7 +733,7 @@
 	if (sata_scr_valid(&ap->link)) {
 		u32 serror;
 
-		pdc_sata_scr_read(ap, SCR_ERROR, &serror);
+		pdc_sata_scr_read(&ap->link, SCR_ERROR, &serror);
 		ehi->serror |= serror;
 	}
 
diff --git a/drivers/ata/sata_qstor.c b/drivers/ata/sata_qstor.c
index 1600107..a000c86 100644
--- a/drivers/ata/sata_qstor.c
+++ b/drivers/ata/sata_qstor.c
@@ -111,8 +111,8 @@
 	qs_state_t		state;
 };
 
-static int qs_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val);
-static int qs_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val);
+static int qs_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val);
+static int qs_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val);
 static int qs_ata_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
 static int qs_port_start(struct ata_port *ap);
 static void qs_host_stop(struct ata_host *host);
@@ -242,11 +242,11 @@
 	return ata_sff_prereset(link, deadline);
 }
 
-static int qs_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
+static int qs_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val)
 {
 	if (sc_reg > SCR_CONTROL)
 		return -EINVAL;
-	*val = readl(ap->ioaddr.scr_addr + (sc_reg * 8));
+	*val = readl(link->ap->ioaddr.scr_addr + (sc_reg * 8));
 	return 0;
 }
 
@@ -256,11 +256,11 @@
 	ata_std_error_handler(ap);
 }
 
-static int qs_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val)
+static int qs_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val)
 {
 	if (sc_reg > SCR_CONTROL)
 		return -EINVAL;
-	writel(val, ap->ioaddr.scr_addr + (sc_reg * 8));
+	writel(val, link->ap->ioaddr.scr_addr + (sc_reg * 8));
 	return 0;
 }
 
diff --git a/drivers/ata/sata_sil.c b/drivers/ata/sata_sil.c
index 88bf421..031d7b7 100644
--- a/drivers/ata/sata_sil.c
+++ b/drivers/ata/sata_sil.c
@@ -115,8 +115,8 @@
 static int sil_pci_device_resume(struct pci_dev *pdev);
 #endif
 static void sil_dev_config(struct ata_device *dev);
-static int sil_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val);
-static int sil_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val);
+static int sil_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val);
+static int sil_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val);
 static int sil_set_mode(struct ata_link *link, struct ata_device **r_failed);
 static void sil_freeze(struct ata_port *ap);
 static void sil_thaw(struct ata_port *ap);
@@ -317,9 +317,9 @@
 	return NULL;
 }
 
-static int sil_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
+static int sil_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val)
 {
-	void __iomem *mmio = sil_scr_addr(ap, sc_reg);
+	void __iomem *mmio = sil_scr_addr(link->ap, sc_reg);
 
 	if (mmio) {
 		*val = readl(mmio);
@@ -328,9 +328,9 @@
 	return -EINVAL;
 }
 
-static int sil_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val)
+static int sil_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val)
 {
-	void __iomem *mmio = sil_scr_addr(ap, sc_reg);
+	void __iomem *mmio = sil_scr_addr(link->ap, sc_reg);
 
 	if (mmio) {
 		writel(val, mmio);
@@ -352,8 +352,8 @@
 		 * controllers continue to assert IRQ as long as
 		 * SError bits are pending.  Clear SError immediately.
 		 */
-		sil_scr_read(ap, SCR_ERROR, &serror);
-		sil_scr_write(ap, SCR_ERROR, serror);
+		sil_scr_read(&ap->link, SCR_ERROR, &serror);
+		sil_scr_write(&ap->link, SCR_ERROR, serror);
 
 		/* Sometimes spurious interrupts occur, double check
 		 * it's PHYRDY CHG.
diff --git a/drivers/ata/sata_sil24.c b/drivers/ata/sata_sil24.c
index 84ffcc2..4621807 100644
--- a/drivers/ata/sata_sil24.c
+++ b/drivers/ata/sata_sil24.c
@@ -340,8 +340,8 @@
 };
 
 static void sil24_dev_config(struct ata_device *dev);
-static int sil24_scr_read(struct ata_port *ap, unsigned sc_reg, u32 *val);
-static int sil24_scr_write(struct ata_port *ap, unsigned sc_reg, u32 val);
+static int sil24_scr_read(struct ata_link *link, unsigned sc_reg, u32 *val);
+static int sil24_scr_write(struct ata_link *link, unsigned sc_reg, u32 val);
 static int sil24_qc_defer(struct ata_queued_cmd *qc);
 static void sil24_qc_prep(struct ata_queued_cmd *qc);
 static unsigned int sil24_qc_issue(struct ata_queued_cmd *qc);
@@ -504,9 +504,9 @@
 	[SCR_ACTIVE]	= 3,
 };
 
-static int sil24_scr_read(struct ata_port *ap, unsigned sc_reg, u32 *val)
+static int sil24_scr_read(struct ata_link *link, unsigned sc_reg, u32 *val)
 {
-	void __iomem *scr_addr = sil24_port_base(ap) + PORT_SCONTROL;
+	void __iomem *scr_addr = sil24_port_base(link->ap) + PORT_SCONTROL;
 
 	if (sc_reg < ARRAY_SIZE(sil24_scr_map)) {
 		void __iomem *addr;
@@ -517,9 +517,9 @@
 	return -EINVAL;
 }
 
-static int sil24_scr_write(struct ata_port *ap, unsigned sc_reg, u32 val)
+static int sil24_scr_write(struct ata_link *link, unsigned sc_reg, u32 val)
 {
-	void __iomem *scr_addr = sil24_port_base(ap) + PORT_SCONTROL;
+	void __iomem *scr_addr = sil24_port_base(link->ap) + PORT_SCONTROL;
 
 	if (sc_reg < ARRAY_SIZE(sil24_scr_map)) {
 		void __iomem *addr;
diff --git a/drivers/ata/sata_sis.c b/drivers/ata/sata_sis.c
index 1010b30..9c43b4e 100644
--- a/drivers/ata/sata_sis.c
+++ b/drivers/ata/sata_sis.c
@@ -64,8 +64,8 @@
 };
 
 static int sis_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
-static int sis_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val);
-static int sis_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val);
+static int sis_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val);
+static int sis_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val);
 
 static const struct pci_device_id sis_pci_tbl[] = {
 	{ PCI_VDEVICE(SI, 0x0180), sis_180 },	/* SiS 964/180 */
@@ -134,10 +134,11 @@
 	return addr;
 }
 
-static u32 sis_scr_cfg_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
+static u32 sis_scr_cfg_read(struct ata_link *link,
+			    unsigned int sc_reg, u32 *val)
 {
-	struct pci_dev *pdev = to_pci_dev(ap->host->dev);
-	unsigned int cfg_addr = get_scr_cfg_addr(ap, sc_reg);
+	struct pci_dev *pdev = to_pci_dev(link->ap->host->dev);
+	unsigned int cfg_addr = get_scr_cfg_addr(link->ap, sc_reg);
 	u32 val2 = 0;
 	u8 pmr;
 
@@ -158,10 +159,11 @@
 	return 0;
 }
 
-static int sis_scr_cfg_write(struct ata_port *ap, unsigned int sc_reg, u32 val)
+static int sis_scr_cfg_write(struct ata_link *link,
+			     unsigned int sc_reg, u32 val)
 {
-	struct pci_dev *pdev = to_pci_dev(ap->host->dev);
-	unsigned int cfg_addr = get_scr_cfg_addr(ap, sc_reg);
+	struct pci_dev *pdev = to_pci_dev(link->ap->host->dev);
+	unsigned int cfg_addr = get_scr_cfg_addr(link->ap, sc_reg);
 	u8 pmr;
 
 	if (sc_reg == SCR_ERROR) /* doesn't exist in PCI cfg space */
@@ -178,8 +180,9 @@
 	return 0;
 }
 
-static int sis_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
+static int sis_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val)
 {
+	struct ata_port *ap = link->ap;
 	struct pci_dev *pdev = to_pci_dev(ap->host->dev);
 	u8 pmr;
 
@@ -187,7 +190,7 @@
 		return -EINVAL;
 
 	if (ap->flags & SIS_FLAG_CFGSCR)
-		return sis_scr_cfg_read(ap, sc_reg, val);
+		return sis_scr_cfg_read(link, sc_reg, val);
 
 	pci_read_config_byte(pdev, SIS_PMR, &pmr);
 
@@ -202,8 +205,9 @@
 	return 0;
 }
 
-static int sis_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val)
+static int sis_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val)
 {
+	struct ata_port *ap = link->ap;
 	struct pci_dev *pdev = to_pci_dev(ap->host->dev);
 	u8 pmr;
 
@@ -213,7 +217,7 @@
 	pci_read_config_byte(pdev, SIS_PMR, &pmr);
 
 	if (ap->flags & SIS_FLAG_CFGSCR)
-		return sis_scr_cfg_write(ap, sc_reg, val);
+		return sis_scr_cfg_write(link, sc_reg, val);
 	else {
 		iowrite32(val, ap->ioaddr.scr_addr + (sc_reg * 4));
 		if ((pdev->device == 0x0182) || (pdev->device == 0x0183) ||
diff --git a/drivers/ata/sata_svw.c b/drivers/ata/sata_svw.c
index fb13b82..609d147 100644
--- a/drivers/ata/sata_svw.c
+++ b/drivers/ata/sata_svw.c
@@ -123,20 +123,22 @@
 	}
 }
 
-static int k2_sata_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
+static int k2_sata_scr_read(struct ata_link *link,
+			    unsigned int sc_reg, u32 *val)
 {
 	if (sc_reg > SCR_CONTROL)
 		return -EINVAL;
-	*val = readl(ap->ioaddr.scr_addr + (sc_reg * 4));
+	*val = readl(link->ap->ioaddr.scr_addr + (sc_reg * 4));
 	return 0;
 }
 
 
-static int k2_sata_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val)
+static int k2_sata_scr_write(struct ata_link *link,
+			     unsigned int sc_reg, u32 val)
 {
 	if (sc_reg > SCR_CONTROL)
 		return -EINVAL;
-	writel(val, ap->ioaddr.scr_addr + (sc_reg * 4));
+	writel(val, link->ap->ioaddr.scr_addr + (sc_reg * 4));
 	return 0;
 }
 
diff --git a/drivers/ata/sata_uli.c b/drivers/ata/sata_uli.c
index db529b8..019575b 100644
--- a/drivers/ata/sata_uli.c
+++ b/drivers/ata/sata_uli.c
@@ -57,8 +57,8 @@
 };
 
 static int uli_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
-static int uli_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val);
-static int uli_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val);
+static int uli_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val);
+static int uli_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val);
 
 static const struct pci_device_id uli_pci_tbl[] = {
 	{ PCI_VDEVICE(AL, 0x5289), uli_5289 },
@@ -107,39 +107,39 @@
 	return hpriv->scr_cfg_addr[ap->port_no] + (4 * sc_reg);
 }
 
-static u32 uli_scr_cfg_read(struct ata_port *ap, unsigned int sc_reg)
+static u32 uli_scr_cfg_read(struct ata_link *link, unsigned int sc_reg)
 {
-	struct pci_dev *pdev = to_pci_dev(ap->host->dev);
-	unsigned int cfg_addr = get_scr_cfg_addr(ap, sc_reg);
+	struct pci_dev *pdev = to_pci_dev(link->ap->host->dev);
+	unsigned int cfg_addr = get_scr_cfg_addr(link->ap, sc_reg);
 	u32 val;
 
 	pci_read_config_dword(pdev, cfg_addr, &val);
 	return val;
 }
 
-static void uli_scr_cfg_write(struct ata_port *ap, unsigned int scr, u32 val)
+static void uli_scr_cfg_write(struct ata_link *link, unsigned int scr, u32 val)
 {
-	struct pci_dev *pdev = to_pci_dev(ap->host->dev);
-	unsigned int cfg_addr = get_scr_cfg_addr(ap, scr);
+	struct pci_dev *pdev = to_pci_dev(link->ap->host->dev);
+	unsigned int cfg_addr = get_scr_cfg_addr(link->ap, scr);
 
 	pci_write_config_dword(pdev, cfg_addr, val);
 }
 
-static int uli_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
+static int uli_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val)
 {
 	if (sc_reg > SCR_CONTROL)
 		return -EINVAL;
 
-	*val = uli_scr_cfg_read(ap, sc_reg);
+	*val = uli_scr_cfg_read(link, sc_reg);
 	return 0;
 }
 
-static int uli_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val)
+static int uli_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val)
 {
 	if (sc_reg > SCR_CONTROL) //SCR_CONTROL=2, SCR_ERROR=1, SCR_STATUS=0
 		return -EINVAL;
 
-	uli_scr_cfg_write(ap, sc_reg, val);
+	uli_scr_cfg_write(link, sc_reg, val);
 	return 0;
 }
 
diff --git a/drivers/ata/sata_via.c b/drivers/ata/sata_via.c
index 96deeb3..1cfa745 100644
--- a/drivers/ata/sata_via.c
+++ b/drivers/ata/sata_via.c
@@ -68,8 +68,8 @@
 };
 
 static int svia_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
-static int svia_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val);
-static int svia_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val);
+static int svia_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val);
+static int svia_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val);
 static void svia_noop_freeze(struct ata_port *ap);
 static int vt6420_prereset(struct ata_link *link, unsigned long deadline);
 static int vt6421_pata_cable_detect(struct ata_port *ap);
@@ -152,19 +152,19 @@
 MODULE_DEVICE_TABLE(pci, svia_pci_tbl);
 MODULE_VERSION(DRV_VERSION);
 
-static int svia_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
+static int svia_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val)
 {
 	if (sc_reg > SCR_CONTROL)
 		return -EINVAL;
-	*val = ioread32(ap->ioaddr.scr_addr + (4 * sc_reg));
+	*val = ioread32(link->ap->ioaddr.scr_addr + (4 * sc_reg));
 	return 0;
 }
 
-static int svia_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val)
+static int svia_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val)
 {
 	if (sc_reg > SCR_CONTROL)
 		return -EINVAL;
-	iowrite32(val, ap->ioaddr.scr_addr + (4 * sc_reg));
+	iowrite32(val, link->ap->ioaddr.scr_addr + (4 * sc_reg));
 	return 0;
 }
 
@@ -210,20 +210,20 @@
 		goto skip_scr;
 
 	/* Resume phy.  This is the old SATA resume sequence */
-	svia_scr_write(ap, SCR_CONTROL, 0x300);
-	svia_scr_read(ap, SCR_CONTROL, &scontrol); /* flush */
+	svia_scr_write(link, SCR_CONTROL, 0x300);
+	svia_scr_read(link, SCR_CONTROL, &scontrol); /* flush */
 
 	/* wait for phy to become ready, if necessary */
 	do {
 		msleep(200);
-		svia_scr_read(ap, SCR_STATUS, &sstatus);
+		svia_scr_read(link, SCR_STATUS, &sstatus);
 		if ((sstatus & 0xf) != 1)
 			break;
 	} while (time_before(jiffies, timeout));
 
 	/* open code sata_print_link_status() */
-	svia_scr_read(ap, SCR_STATUS, &sstatus);
-	svia_scr_read(ap, SCR_CONTROL, &scontrol);
+	svia_scr_read(link, SCR_STATUS, &sstatus);
+	svia_scr_read(link, SCR_CONTROL, &scontrol);
 
 	online = (sstatus & 0xf) == 0x3;
 
@@ -232,7 +232,7 @@
 			online ? "up" : "down", sstatus, scontrol);
 
 	/* SStatus is read one more time */
-	svia_scr_read(ap, SCR_STATUS, &sstatus);
+	svia_scr_read(link, SCR_STATUS, &sstatus);
 
 	if (!online) {
 		/* tell EH to bail */
diff --git a/drivers/ata/sata_vsc.c b/drivers/ata/sata_vsc.c
index f3d635c..c57cdff 100644
--- a/drivers/ata/sata_vsc.c
+++ b/drivers/ata/sata_vsc.c
@@ -98,20 +98,22 @@
 			      VSC_SATA_INT_PHY_CHANGE),
 };
 
-static int vsc_sata_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
+static int vsc_sata_scr_read(struct ata_link *link,
+			     unsigned int sc_reg, u32 *val)
 {
 	if (sc_reg > SCR_CONTROL)
 		return -EINVAL;
-	*val = readl(ap->ioaddr.scr_addr + (sc_reg * 4));
+	*val = readl(link->ap->ioaddr.scr_addr + (sc_reg * 4));
 	return 0;
 }
 
 
-static int vsc_sata_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val)
+static int vsc_sata_scr_write(struct ata_link *link,
+			      unsigned int sc_reg, u32 val)
 {
 	if (sc_reg > SCR_CONTROL)
 		return -EINVAL;
-	writel(val, ap->ioaddr.scr_addr + (sc_reg * 4));
+	writel(val, link->ap->ioaddr.scr_addr + (sc_reg * 4));
 	return 0;
 }
 
diff --git a/drivers/atm/eni.c b/drivers/atm/eni.c
index 41b2204..5503bfc 100644
--- a/drivers/atm/eni.c
+++ b/drivers/atm/eni.c
@@ -1270,7 +1270,7 @@
 			if (*pre < 3) (*pre)++; /* else fail later */
 			div = pre_div[*pre]*-*pcr;
 			DPRINTK("max div %d\n",div);
-			*res = (TS_CLOCK+div-1)/div-1;
+			*res = DIV_ROUND_UP(TS_CLOCK, div)-1;
 		}
 		if (*res < 0) *res = 0;
 		if (*res > MID_SEG_MAX_RATE) *res = MID_SEG_MAX_RATE;
diff --git a/drivers/atm/fore200e.c b/drivers/atm/fore200e.c
index 73338d2..937c9c0 100644
--- a/drivers/atm/fore200e.c
+++ b/drivers/atm/fore200e.c
@@ -47,8 +47,9 @@
 #include <asm/atomic.h>
 
 #ifdef CONFIG_SBUS
+#include <linux/of.h>
+#include <linux/of_device.h>
 #include <asm/idprom.h>
-#include <asm/sbus.h>
 #include <asm/openprom.h>
 #include <asm/oplib.h>
 #include <asm/pgtable.h>
@@ -661,249 +662,189 @@
 
 #ifdef CONFIG_SBUS
 
-static u32
-fore200e_sba_read(volatile u32 __iomem *addr)
+static u32 fore200e_sba_read(volatile u32 __iomem *addr)
 {
     return sbus_readl(addr);
 }
 
-
-static void
-fore200e_sba_write(u32 val, volatile u32 __iomem *addr)
+static void fore200e_sba_write(u32 val, volatile u32 __iomem *addr)
 {
     sbus_writel(val, addr);
 }
 
-
-static u32
-fore200e_sba_dma_map(struct fore200e* fore200e, void* virt_addr, int size, int direction)
+static u32 fore200e_sba_dma_map(struct fore200e *fore200e, void* virt_addr, int size, int direction)
 {
-    u32 dma_addr = sbus_map_single((struct sbus_dev*)fore200e->bus_dev, virt_addr, size, direction);
+	struct of_device *op = fore200e->bus_dev;
+	u32 dma_addr;
 
-    DPRINTK(3, "SBUS DVMA mapping: virt_addr = 0x%p, size = %d, direction = %d --> dma_addr = 0x%08x\n",
-	    virt_addr, size, direction, dma_addr);
+	dma_addr = dma_map_single(&op->dev, virt_addr, size, direction);
+
+	DPRINTK(3, "SBUS DVMA mapping: virt_addr = 0x%p, size = %d, direction = %d --> dma_addr = 0x%08x\n",
+		virt_addr, size, direction, dma_addr);
     
-    return dma_addr;
+	return dma_addr;
 }
 
-
-static void
-fore200e_sba_dma_unmap(struct fore200e* fore200e, u32 dma_addr, int size, int direction)
+static void fore200e_sba_dma_unmap(struct fore200e *fore200e, u32 dma_addr, int size, int direction)
 {
-    DPRINTK(3, "SBUS DVMA unmapping: dma_addr = 0x%08x, size = %d, direction = %d,\n",
-	    dma_addr, size, direction);
+	struct of_device *op = fore200e->bus_dev;
 
-    sbus_unmap_single((struct sbus_dev*)fore200e->bus_dev, dma_addr, size, direction);
+	DPRINTK(3, "SBUS DVMA unmapping: dma_addr = 0x%08x, size = %d, direction = %d,\n",
+		dma_addr, size, direction);
+
+	dma_unmap_single(&op->dev, dma_addr, size, direction);
 }
 
-
-static void
-fore200e_sba_dma_sync_for_cpu(struct fore200e* fore200e, u32 dma_addr, int size, int direction)
+static void fore200e_sba_dma_sync_for_cpu(struct fore200e *fore200e, u32 dma_addr, int size, int direction)
 {
-    DPRINTK(3, "SBUS DVMA sync: dma_addr = 0x%08x, size = %d, direction = %d\n", dma_addr, size, direction);
+	struct of_device *op = fore200e->bus_dev;
+
+	DPRINTK(3, "SBUS DVMA sync: dma_addr = 0x%08x, size = %d, direction = %d\n", dma_addr, size, direction);
     
-    sbus_dma_sync_single_for_cpu((struct sbus_dev*)fore200e->bus_dev, dma_addr, size, direction);
+	dma_sync_single_for_cpu(&op->dev, dma_addr, size, direction);
 }
 
-static void
-fore200e_sba_dma_sync_for_device(struct fore200e* fore200e, u32 dma_addr, int size, int direction)
+static void fore200e_sba_dma_sync_for_device(struct fore200e *fore200e, u32 dma_addr, int size, int direction)
 {
-    DPRINTK(3, "SBUS DVMA sync: dma_addr = 0x%08x, size = %d, direction = %d\n", dma_addr, size, direction);
+	struct of_device *op = fore200e->bus_dev;
 
-    sbus_dma_sync_single_for_device((struct sbus_dev*)fore200e->bus_dev, dma_addr, size, direction);
+	DPRINTK(3, "SBUS DVMA sync: dma_addr = 0x%08x, size = %d, direction = %d\n", dma_addr, size, direction);
+
+	dma_sync_single_for_device(&op->dev, dma_addr, size, direction);
 }
 
-
-/* allocate a DVMA consistent chunk of memory intended to act as a communication mechanism
-   (to hold descriptors, status, queues, etc.) shared by the driver and the adapter */
-
-static int
-fore200e_sba_dma_chunk_alloc(struct fore200e* fore200e, struct chunk* chunk,
-			     int size, int nbr, int alignment)
+/* Allocate a DVMA consistent chunk of memory intended to act as a communication mechanism
+ * (to hold descriptors, status, queues, etc.) shared by the driver and the adapter.
+ */
+static int fore200e_sba_dma_chunk_alloc(struct fore200e *fore200e, struct chunk *chunk,
+					int size, int nbr, int alignment)
 {
-    chunk->alloc_size = chunk->align_size = size * nbr;
+	struct of_device *op = fore200e->bus_dev;
 
-    /* returned chunks are page-aligned */
-    chunk->alloc_addr = sbus_alloc_consistent((struct sbus_dev*)fore200e->bus_dev,
-					      chunk->alloc_size,
-					      &chunk->dma_addr);
+	chunk->alloc_size = chunk->align_size = size * nbr;
 
-    if ((chunk->alloc_addr == NULL) || (chunk->dma_addr == 0))
-	return -ENOMEM;
+	/* returned chunks are page-aligned */
+	chunk->alloc_addr = dma_alloc_coherent(&op->dev, chunk->alloc_size,
+					       &chunk->dma_addr, GFP_ATOMIC);
 
-    chunk->align_addr = chunk->alloc_addr;
+	if ((chunk->alloc_addr == NULL) || (chunk->dma_addr == 0))
+		return -ENOMEM;
+
+	chunk->align_addr = chunk->alloc_addr;
     
-    return 0;
+	return 0;
 }
 
-
 /* free a DVMA consistent chunk of memory */
-
-static void
-fore200e_sba_dma_chunk_free(struct fore200e* fore200e, struct chunk* chunk)
+static void fore200e_sba_dma_chunk_free(struct fore200e *fore200e, struct chunk *chunk)
 {
-    sbus_free_consistent((struct sbus_dev*)fore200e->bus_dev,
-			 chunk->alloc_size,
-			 chunk->alloc_addr,
-			 chunk->dma_addr);
+	struct of_device *op = fore200e->bus_dev;
+
+	dma_free_coherent(&op->dev, chunk->alloc_size,
+			  chunk->alloc_addr, chunk->dma_addr);
 }
 
-
-static void
-fore200e_sba_irq_enable(struct fore200e* fore200e)
+static void fore200e_sba_irq_enable(struct fore200e *fore200e)
 {
-    u32 hcr = fore200e->bus->read(fore200e->regs.sba.hcr) & SBA200E_HCR_STICKY;
-    fore200e->bus->write(hcr | SBA200E_HCR_INTR_ENA, fore200e->regs.sba.hcr);
+	u32 hcr = fore200e->bus->read(fore200e->regs.sba.hcr) & SBA200E_HCR_STICKY;
+	fore200e->bus->write(hcr | SBA200E_HCR_INTR_ENA, fore200e->regs.sba.hcr);
 }
 
-
-static int
-fore200e_sba_irq_check(struct fore200e* fore200e)
+static int fore200e_sba_irq_check(struct fore200e *fore200e)
 {
-    return fore200e->bus->read(fore200e->regs.sba.hcr) & SBA200E_HCR_INTR_REQ;
+	return fore200e->bus->read(fore200e->regs.sba.hcr) & SBA200E_HCR_INTR_REQ;
 }
 
-
-static void
-fore200e_sba_irq_ack(struct fore200e* fore200e)
+static void fore200e_sba_irq_ack(struct fore200e *fore200e)
 {
-    u32 hcr = fore200e->bus->read(fore200e->regs.sba.hcr) & SBA200E_HCR_STICKY;
-    fore200e->bus->write(hcr | SBA200E_HCR_INTR_CLR, fore200e->regs.sba.hcr);
+	u32 hcr = fore200e->bus->read(fore200e->regs.sba.hcr) & SBA200E_HCR_STICKY;
+	fore200e->bus->write(hcr | SBA200E_HCR_INTR_CLR, fore200e->regs.sba.hcr);
 }
 
-
-static void
-fore200e_sba_reset(struct fore200e* fore200e)
+static void fore200e_sba_reset(struct fore200e *fore200e)
 {
-    fore200e->bus->write(SBA200E_HCR_RESET, fore200e->regs.sba.hcr);
-    fore200e_spin(10);
-    fore200e->bus->write(0, fore200e->regs.sba.hcr);
+	fore200e->bus->write(SBA200E_HCR_RESET, fore200e->regs.sba.hcr);
+	fore200e_spin(10);
+	fore200e->bus->write(0, fore200e->regs.sba.hcr);
 }
 
-
-static int __init
-fore200e_sba_map(struct fore200e* fore200e)
+static int __init fore200e_sba_map(struct fore200e *fore200e)
 {
-    struct sbus_dev* sbus_dev = (struct sbus_dev*)fore200e->bus_dev;
-    unsigned int bursts;
+	struct of_device *op = fore200e->bus_dev;
+	unsigned int bursts;
 
-    /* gain access to the SBA specific registers  */
-    fore200e->regs.sba.hcr = sbus_ioremap(&sbus_dev->resource[0], 0, SBA200E_HCR_LENGTH, "SBA HCR");
-    fore200e->regs.sba.bsr = sbus_ioremap(&sbus_dev->resource[1], 0, SBA200E_BSR_LENGTH, "SBA BSR");
-    fore200e->regs.sba.isr = sbus_ioremap(&sbus_dev->resource[2], 0, SBA200E_ISR_LENGTH, "SBA ISR");
-    fore200e->virt_base    = sbus_ioremap(&sbus_dev->resource[3], 0, SBA200E_RAM_LENGTH, "SBA RAM");
+	/* gain access to the SBA specific registers  */
+	fore200e->regs.sba.hcr = of_ioremap(&op->resource[0], 0, SBA200E_HCR_LENGTH, "SBA HCR");
+	fore200e->regs.sba.bsr = of_ioremap(&op->resource[1], 0, SBA200E_BSR_LENGTH, "SBA BSR");
+	fore200e->regs.sba.isr = of_ioremap(&op->resource[2], 0, SBA200E_ISR_LENGTH, "SBA ISR");
+	fore200e->virt_base    = of_ioremap(&op->resource[3], 0, SBA200E_RAM_LENGTH, "SBA RAM");
 
-    if (fore200e->virt_base == NULL) {
-	printk(FORE200E "unable to map RAM of device %s\n", fore200e->name);
-	return -EFAULT;
-    }
-
-    DPRINTK(1, "device %s mapped to 0x%p\n", fore200e->name, fore200e->virt_base);
-    
-    fore200e->bus->write(0x02, fore200e->regs.sba.isr); /* XXX hardwired interrupt level */
-
-    /* get the supported DVMA burst sizes */
-    bursts = prom_getintdefault(sbus_dev->bus->prom_node, "burst-sizes", 0x00);
-
-    if (sbus_can_dma_64bit(sbus_dev))
-	sbus_set_sbus64(sbus_dev, bursts);
-
-    fore200e->state = FORE200E_STATE_MAP;
-    return 0;
-}
-
-
-static void
-fore200e_sba_unmap(struct fore200e* fore200e)
-{
-    sbus_iounmap(fore200e->regs.sba.hcr, SBA200E_HCR_LENGTH);
-    sbus_iounmap(fore200e->regs.sba.bsr, SBA200E_BSR_LENGTH);
-    sbus_iounmap(fore200e->regs.sba.isr, SBA200E_ISR_LENGTH);
-    sbus_iounmap(fore200e->virt_base,    SBA200E_RAM_LENGTH);
-}
-
-
-static int __init
-fore200e_sba_configure(struct fore200e* fore200e)
-{
-    fore200e->state = FORE200E_STATE_CONFIGURE;
-    return 0;
-}
-
-
-static struct fore200e* __init
-fore200e_sba_detect(const struct fore200e_bus* bus, int index)
-{
-    struct fore200e*          fore200e;
-    struct sbus_bus* sbus_bus;
-    struct sbus_dev* sbus_dev = NULL;
-    
-    unsigned int     count = 0;
-    
-    for_each_sbus (sbus_bus) {
-	for_each_sbusdev (sbus_dev, sbus_bus) {
-	    if (strcmp(sbus_dev->prom_name, SBA200E_PROM_NAME) == 0) {
-		if (count >= index)
-		    goto found;
-		count++;
-	    }
+	if (!fore200e->virt_base) {
+		printk(FORE200E "unable to map RAM of device %s\n", fore200e->name);
+		return -EFAULT;
 	}
-    }
-    return NULL;
+
+	DPRINTK(1, "device %s mapped to 0x%p\n", fore200e->name, fore200e->virt_base);
     
-  found:
-    if (sbus_dev->num_registers != 4) {
-	printk(FORE200E "this %s device has %d instead of 4 registers\n",
-	       bus->model_name, sbus_dev->num_registers);
-	return NULL;
-    }
+	fore200e->bus->write(0x02, fore200e->regs.sba.isr); /* XXX hardwired interrupt level */
 
-    fore200e = kzalloc(sizeof(struct fore200e), GFP_KERNEL);
-    if (fore200e == NULL)
-	return NULL;
+	/* get the supported DVMA burst sizes */
+	bursts = of_getintprop_default(op->node->parent, "burst-sizes", 0x00);
 
-    fore200e->bus     = bus;
-    fore200e->bus_dev = sbus_dev;
-    fore200e->irq     = sbus_dev->irqs[ 0 ];
+	if (sbus_can_dma_64bit())
+		sbus_set_sbus64(&op->dev, bursts);
 
-    fore200e->phys_base = (unsigned long)sbus_dev;
-
-    sprintf(fore200e->name, "%s-%d", bus->model_name, index - 1);
-    
-    return fore200e;
+	fore200e->state = FORE200E_STATE_MAP;
+	return 0;
 }
 
-
-static int __init
-fore200e_sba_prom_read(struct fore200e* fore200e, struct prom_data* prom)
+static void fore200e_sba_unmap(struct fore200e *fore200e)
 {
-    struct sbus_dev* sbus_dev = (struct sbus_dev*) fore200e->bus_dev;
-    int                       len;
+	struct of_device *op = fore200e->bus_dev;
 
-    len = prom_getproperty(sbus_dev->prom_node, "macaddrlo2", &prom->mac_addr[ 4 ], 4);
-    if (len < 0)
-	return -EBUSY;
-
-    len = prom_getproperty(sbus_dev->prom_node, "macaddrhi4", &prom->mac_addr[ 2 ], 4);
-    if (len < 0)
-	return -EBUSY;
-    
-    prom_getproperty(sbus_dev->prom_node, "serialnumber",
-		     (char*)&prom->serial_number, sizeof(prom->serial_number));
-    
-    prom_getproperty(sbus_dev->prom_node, "promversion",
-		     (char*)&prom->hw_revision, sizeof(prom->hw_revision));
-    
-    return 0;
+	of_iounmap(&op->resource[0], fore200e->regs.sba.hcr, SBA200E_HCR_LENGTH);
+	of_iounmap(&op->resource[1], fore200e->regs.sba.bsr, SBA200E_BSR_LENGTH);
+	of_iounmap(&op->resource[2], fore200e->regs.sba.isr, SBA200E_ISR_LENGTH);
+	of_iounmap(&op->resource[3], fore200e->virt_base,    SBA200E_RAM_LENGTH);
 }
 
-
-static int
-fore200e_sba_proc_read(struct fore200e* fore200e, char *page)
+static int __init fore200e_sba_configure(struct fore200e *fore200e)
 {
-    struct sbus_dev* sbus_dev = (struct sbus_dev*)fore200e->bus_dev;
+	fore200e->state = FORE200E_STATE_CONFIGURE;
+	return 0;
+}
 
-    return sprintf(page, "   SBUS slot/device:\t\t%d/'%s'\n", sbus_dev->slot, sbus_dev->prom_name);
+static int __init fore200e_sba_prom_read(struct fore200e *fore200e, struct prom_data *prom)
+{
+	struct of_device *op = fore200e->bus_dev;
+	const u8 *prop;
+	int len;
+
+	prop = of_get_property(op->node, "madaddrlo2", &len);
+	if (!prop)
+		return -ENODEV;
+	memcpy(&prom->mac_addr[4], prop, 4);
+
+	prop = of_get_property(op->node, "madaddrhi4", &len);
+	if (!prop)
+		return -ENODEV;
+	memcpy(&prom->mac_addr[2], prop, 4);
+
+	prom->serial_number = of_getintprop_default(op->node, "serialnumber", 0);
+	prom->hw_revision = of_getintprop_default(op->node, "promversion", 0);
+    
+	return 0;
+}
+
+static int fore200e_sba_proc_read(struct fore200e *fore200e, char *page)
+{
+	struct of_device *op = fore200e->bus_dev;
+	const struct linux_prom_registers *regs;
+
+	regs = of_get_property(op->node, "reg", NULL);
+
+	return sprintf(page, "   SBUS slot/device:\t\t%d/'%s'\n",
+		       (regs ? regs->which_io : 0), op->node->name);
 }
 #endif /* CONFIG_SBUS */
 
@@ -2572,7 +2513,7 @@
 	device = &((struct pci_dev *) fore200e->bus_dev)->dev;
 #ifdef CONFIG_SBUS
     else if (strcmp(fore200e->bus->model_name, "SBA-200E") == 0)
-	device = &((struct sbus_dev *) fore200e->bus_dev)->ofdev.dev;
+	device = &((struct of_device *) fore200e->bus_dev)->dev;
 #endif
     else
 	return err;
@@ -2701,6 +2642,66 @@
     return 0;
 }
 
+#ifdef CONFIG_SBUS
+static int __devinit fore200e_sba_probe(struct of_device *op,
+					const struct of_device_id *match)
+{
+	const struct fore200e_bus *bus = match->data;
+	struct fore200e *fore200e;
+	static int index = 0;
+	int err;
+
+	fore200e = kzalloc(sizeof(struct fore200e), GFP_KERNEL);
+	if (!fore200e)
+		return -ENOMEM;
+
+	fore200e->bus = bus;
+	fore200e->bus_dev = op;
+	fore200e->irq = op->irqs[0];
+	fore200e->phys_base = op->resource[0].start;
+
+	sprintf(fore200e->name, "%s-%d", bus->model_name, index);
+
+	err = fore200e_init(fore200e);
+	if (err < 0) {
+		fore200e_shutdown(fore200e);
+		kfree(fore200e);
+		return err;
+	}
+
+	index++;
+	dev_set_drvdata(&op->dev, fore200e);
+
+	return 0;
+}
+
+static int __devexit fore200e_sba_remove(struct of_device *op)
+{
+	struct fore200e *fore200e = dev_get_drvdata(&op->dev);
+
+	fore200e_shutdown(fore200e);
+	kfree(fore200e);
+
+	return 0;
+}
+
+static const struct of_device_id fore200e_sba_match[] = {
+	{
+		.name = SBA200E_PROM_NAME,
+		.data = (void *) &fore200e_bus[1],
+	},
+	{},
+};
+MODULE_DEVICE_TABLE(of, fore200e_sba_match);
+
+static struct of_platform_driver fore200e_sba_driver = {
+	.name		= "fore_200e",
+	.match_table	= fore200e_sba_match,
+	.probe		= fore200e_sba_probe,
+	.remove		= __devexit_p(fore200e_sba_remove),
+};
+#endif
+
 #ifdef CONFIG_PCI
 static int __devinit
 fore200e_pca_detect(struct pci_dev *pci_dev, const struct pci_device_id *pci_ent)
@@ -2784,66 +2785,39 @@
 };
 #endif
 
-
-static int __init
-fore200e_module_init(void)
+static int __init fore200e_module_init(void)
 {
-    const struct fore200e_bus* bus;
-    struct       fore200e*     fore200e;
-    int                        index;
+	int err;
 
-    printk(FORE200E "FORE Systems 200E-series ATM driver - version " FORE200E_VERSION "\n");
+	printk(FORE200E "FORE Systems 200E-series ATM driver - version " FORE200E_VERSION "\n");
 
-    /* for each configured bus interface */
-    for (bus = fore200e_bus; bus->model_name; bus++) {
-
-	/* detect all boards present on that bus */
-	for (index = 0; bus->detect && (fore200e = bus->detect(bus, index)); index++) {
-	    
-	    printk(FORE200E "device %s found at 0x%lx, IRQ %s\n",
-		   fore200e->bus->model_name, 
-		   fore200e->phys_base, fore200e_irq_itoa(fore200e->irq));
-
-	    sprintf(fore200e->name, "%s-%d", bus->model_name, index);
-
-	    if (fore200e_init(fore200e) < 0) {
-
-		fore200e_shutdown(fore200e);
-		break;
-	    }
-
-	    list_add(&fore200e->entry, &fore200e_boards);
-	}
-    }
-
-#ifdef CONFIG_PCI
-    if (!pci_register_driver(&fore200e_pca_driver))
-	return 0;
+#ifdef CONFIG_SBUS
+	err = of_register_driver(&fore200e_sba_driver, &of_bus_type);
+	if (err)
+		return err;
 #endif
 
-    if (!list_empty(&fore200e_boards))
-	return 0;
-
-    return -ENODEV;
-}
-
-
-static void __exit
-fore200e_module_cleanup(void)
-{
-    struct fore200e *fore200e, *next;
-
 #ifdef CONFIG_PCI
-    pci_unregister_driver(&fore200e_pca_driver);
+	err = pci_register_driver(&fore200e_pca_driver);
 #endif
 
-    list_for_each_entry_safe(fore200e, next, &fore200e_boards, entry) {
-	fore200e_shutdown(fore200e);
-	kfree(fore200e);
-    }
-    DPRINTK(1, "module being removed\n");
+#ifdef CONFIG_SBUS
+	if (err)
+		of_unregister_driver(&fore200e_sba_driver);
+#endif
+
+	return err;
 }
 
+static void __exit fore200e_module_cleanup(void)
+{
+#ifdef CONFIG_PCI
+	pci_unregister_driver(&fore200e_pca_driver);
+#endif
+#ifdef CONFIG_SBUS
+	of_unregister_driver(&fore200e_sba_driver);
+#endif
+}
 
 static int
 fore200e_proc_read(struct atm_dev *dev, loff_t* pos, char* page)
@@ -3163,7 +3137,6 @@
       fore200e_pca_dma_sync_for_device,
       fore200e_pca_dma_chunk_alloc,
       fore200e_pca_dma_chunk_free,
-      NULL,
       fore200e_pca_configure,
       fore200e_pca_map,
       fore200e_pca_reset,
@@ -3185,7 +3158,6 @@
       fore200e_sba_dma_sync_for_device,
       fore200e_sba_dma_chunk_alloc,
       fore200e_sba_dma_chunk_free,
-      fore200e_sba_detect, 
       fore200e_sba_configure,
       fore200e_sba_map,
       fore200e_sba_reset,
diff --git a/drivers/atm/fore200e.h b/drivers/atm/fore200e.h
index 5c6e7ad..7f97c09 100644
--- a/drivers/atm/fore200e.h
+++ b/drivers/atm/fore200e.h
@@ -778,9 +778,9 @@
 /* SBA-200E registers */
 
 typedef struct fore200e_sba_regs {
-    volatile u32 __iomem *hcr;    /* address of host control register              */
-    volatile u32 __iomem *bsr;    /* address of burst transfer size register       */
-    volatile u32 __iomem *isr;    /* address of interrupt level selection register */
+    u32 __iomem *hcr;    /* address of host control register              */
+    u32 __iomem *bsr;    /* address of burst transfer size register       */
+    u32 __iomem *isr;    /* address of interrupt level selection register */
 } fore200e_sba_regs_t;
 
 
@@ -810,7 +810,6 @@
     void                 (*dma_sync_for_device)(struct fore200e*, u32, int, int);
     int                  (*dma_chunk_alloc)(struct fore200e*, struct chunk*, int, int, int);
     void                 (*dma_chunk_free)(struct fore200e*, struct chunk*);
-    struct fore200e*     (*detect)(const struct fore200e_bus*, int);
     int                  (*configure)(struct fore200e*); 
     int                  (*map)(struct fore200e*); 
     void                 (*reset)(struct fore200e*);
diff --git a/drivers/atm/horizon.c b/drivers/atm/horizon.c
index c0ac728..6154123 100644
--- a/drivers/atm/horizon.c
+++ b/drivers/atm/horizon.c
@@ -635,7 +635,7 @@
 		// take care of rounding
 		switch (r) {
 			case round_down:
-				pre = (br+(c<<div)-1)/(c<<div);
+				pre = DIV_ROUND_UP(br, c<<div);
 				// but p must be non-zero
 				if (!pre)
 					pre = 1;
@@ -668,7 +668,7 @@
 			// take care of rounding
 			switch (r) {
 				case round_down:
-					pre = (br+(c<<div)-1)/(c<<div);
+					pre = DIV_ROUND_UP(br, c<<div);
 					break;
 				case round_nearest:
 					pre = (br+(c<<div)/2)/(c<<div);
@@ -698,7 +698,7 @@
 		if (bits)
 			*bits = (div<<CLOCK_SELECT_SHIFT) | (pre-1);
 		if (actual) {
-			*actual = (br + (pre<<div) - 1) / (pre<<div);
+			*actual = DIV_ROUND_UP(br, pre<<div);
 			PRINTD (DBG_QOS, "actual rate: %u", *actual);
 		}
 		return 0;
@@ -1967,7 +1967,7 @@
   // Set the max AAL5 cell count to be just enough to contain the
   // largest AAL5 frame that the user wants to receive
   wr_regw (dev, MAX_AAL5_CELL_COUNT_OFF,
-	   (max_rx_size + ATM_AAL5_TRAILER + ATM_CELL_PAYLOAD - 1) / ATM_CELL_PAYLOAD);
+	   DIV_ROUND_UP(max_rx_size + ATM_AAL5_TRAILER, ATM_CELL_PAYLOAD));
   
   // Enable receive
   wr_regw (dev, RX_CONFIG_OFF, rd_regw (dev, RX_CONFIG_OFF) | RX_ENABLE);
diff --git a/drivers/atm/idt77252.c b/drivers/atm/idt77252.c
index 3a504e9..e33ae00 100644
--- a/drivers/atm/idt77252.c
+++ b/drivers/atm/idt77252.c
@@ -1114,11 +1114,8 @@
 
 	rpp = &vc->rcv.rx_pool;
 
+	__skb_queue_tail(&rpp->queue, skb);
 	rpp->len += skb->len;
-	if (!rpp->count++)
-		rpp->first = skb;
-	*rpp->last = skb;
-	rpp->last = &skb->next;
 
 	if (stat & SAR_RSQE_EPDU) {
 		unsigned char *l1l2;
@@ -1145,7 +1142,7 @@
 			atomic_inc(&vcc->stats->rx_err);
 			return;
 		}
-		if (rpp->count > 1) {
+		if (skb_queue_len(&rpp->queue) > 1) {
 			struct sk_buff *sb;
 
 			skb = dev_alloc_skb(rpp->len);
@@ -1161,12 +1158,9 @@
 				dev_kfree_skb(skb);
 				return;
 			}
-			sb = rpp->first;
-			for (i = 0; i < rpp->count; i++) {
+			skb_queue_walk(&rpp->queue, sb)
 				memcpy(skb_put(skb, sb->len),
 				       sb->data, sb->len);
-				sb = sb->next;
-			}
 
 			recycle_rx_pool_skb(card, rpp);
 
@@ -1180,7 +1174,6 @@
 			return;
 		}
 
-		skb->next = NULL;
 		flush_rx_pool(card, rpp);
 
 		if (!atm_charge(vcc, skb->truesize)) {
@@ -1918,25 +1911,18 @@
 static void
 flush_rx_pool(struct idt77252_dev *card, struct rx_pool *rpp)
 {
+	skb_queue_head_init(&rpp->queue);
 	rpp->len = 0;
-	rpp->count = 0;
-	rpp->first = NULL;
-	rpp->last = &rpp->first;
 }
 
 static void
 recycle_rx_pool_skb(struct idt77252_dev *card, struct rx_pool *rpp)
 {
-	struct sk_buff *skb, *next;
-	int i;
+	struct sk_buff *skb, *tmp;
 
-	skb = rpp->first;
-	for (i = 0; i < rpp->count; i++) {
-		next = skb->next;
-		skb->next = NULL;
+	skb_queue_walk_safe(&rpp->queue, skb, tmp)
 		recycle_rx_skb(card, skb);
-		skb = next;
-	}
+
 	flush_rx_pool(card, rpp);
 }
 
@@ -2537,7 +2523,7 @@
 		waitfor_idle(card);
 		spin_unlock_irqrestore(&card->cmd_lock, flags);
 
-		if (vc->rcv.rx_pool.count) {
+		if (skb_queue_len(&vc->rcv.rx_pool.queue) != 0) {
 			DPRINTK("%s: closing a VC with pending rx buffers.\n",
 				card->name);
 
@@ -2970,7 +2956,7 @@
 			waitfor_idle(card);
 			spin_unlock_irqrestore(&card->cmd_lock, flags);
 
-			if (vc->rcv.rx_pool.count) {
+			if (skb_queue_len(&vc->rcv.rx_pool.queue) != 0) {
 				DPRINTK("%s: closing a VC "
 					"with pending rx buffers.\n",
 					card->name);
diff --git a/drivers/atm/idt77252.h b/drivers/atm/idt77252.h
index e83eaf1..5042bb2 100644
--- a/drivers/atm/idt77252.h
+++ b/drivers/atm/idt77252.h
@@ -173,10 +173,8 @@
 };
 
 struct rx_pool {
-	struct sk_buff		*first;
-	struct sk_buff		**last;
+	struct sk_buff_head	queue;
 	unsigned int		len;
-	unsigned int		count;
 };
 
 struct aal1 {
diff --git a/drivers/atm/zatm.c b/drivers/atm/zatm.c
index 58583c6..752b1ba 100644
--- a/drivers/atm/zatm.c
+++ b/drivers/atm/zatm.c
@@ -496,8 +496,8 @@
 			vcc->qos.rxtp.max_sdu = 65464;
 			/* fix this - we may want to receive 64kB SDUs
 			   later */
-		cells = (vcc->qos.rxtp.max_sdu+ATM_AAL5_TRAILER+
-		    ATM_CELL_PAYLOAD-1)/ATM_CELL_PAYLOAD;
+		cells = DIV_ROUND_UP(vcc->qos.rxtp.max_sdu + ATM_AAL5_TRAILER,
+				ATM_CELL_PAYLOAD);
 		zatm_vcc->pool = pool_index(cells*ATM_CELL_PAYLOAD);
 	}
 	else {
@@ -820,7 +820,7 @@
 			}
 			else {
 				i = 255;
-				m = (ATM_OC3_PCR*255+max-1)/max;
+				m = DIV_ROUND_UP(ATM_OC3_PCR*255, max);
 			}
 		}
 		if (i > m) {
diff --git a/drivers/base/base.h b/drivers/base/base.h
index 31dc0cd..0a5f055 100644
--- a/drivers/base/base.h
+++ b/drivers/base/base.h
@@ -54,7 +54,7 @@
  */
 struct class_private {
 	struct kset class_subsys;
-	struct list_head class_devices;
+	struct klist class_devices;
 	struct list_head class_interfaces;
 	struct kset class_dirs;
 	struct mutex class_mutex;
diff --git a/drivers/base/class.c b/drivers/base/class.c
index cc5e28c..eb85e43 100644
--- a/drivers/base/class.c
+++ b/drivers/base/class.c
@@ -135,6 +135,20 @@
 	}
 }
 
+static void klist_class_dev_get(struct klist_node *n)
+{
+	struct device *dev = container_of(n, struct device, knode_class);
+
+	get_device(dev);
+}
+
+static void klist_class_dev_put(struct klist_node *n)
+{
+	struct device *dev = container_of(n, struct device, knode_class);
+
+	put_device(dev);
+}
+
 int __class_register(struct class *cls, struct lock_class_key *key)
 {
 	struct class_private *cp;
@@ -145,7 +159,7 @@
 	cp = kzalloc(sizeof(*cp), GFP_KERNEL);
 	if (!cp)
 		return -ENOMEM;
-	INIT_LIST_HEAD(&cp->class_devices);
+	klist_init(&cp->class_devices, klist_class_dev_get, klist_class_dev_put);
 	INIT_LIST_HEAD(&cp->class_interfaces);
 	kset_init(&cp->class_dirs);
 	__mutex_init(&cp->class_mutex, "struct class mutex", key);
@@ -269,6 +283,71 @@
 #endif
 
 /**
+ * class_dev_iter_init - initialize class device iterator
+ * @iter: class iterator to initialize
+ * @class: the class we wanna iterate over
+ * @start: the device to start iterating from, if any
+ * @type: device_type of the devices to iterate over, NULL for all
+ *
+ * Initialize class iterator @iter such that it iterates over devices
+ * of @class.  If @start is set, the list iteration will start there,
+ * otherwise if it is NULL, the iteration starts at the beginning of
+ * the list.
+ */
+void class_dev_iter_init(struct class_dev_iter *iter, struct class *class,
+			 struct device *start, const struct device_type *type)
+{
+	struct klist_node *start_knode = NULL;
+
+	if (start)
+		start_knode = &start->knode_class;
+	klist_iter_init_node(&class->p->class_devices, &iter->ki, start_knode);
+	iter->type = type;
+}
+EXPORT_SYMBOL_GPL(class_dev_iter_init);
+
+/**
+ * class_dev_iter_next - iterate to the next device
+ * @iter: class iterator to proceed
+ *
+ * Proceed @iter to the next device and return it.  Returns NULL if
+ * iteration is complete.
+ *
+ * The returned device is referenced and won't be released till
+ * iterator is proceed to the next device or exited.  The caller is
+ * free to do whatever it wants to do with the device including
+ * calling back into class code.
+ */
+struct device *class_dev_iter_next(struct class_dev_iter *iter)
+{
+	struct klist_node *knode;
+	struct device *dev;
+
+	while (1) {
+		knode = klist_next(&iter->ki);
+		if (!knode)
+			return NULL;
+		dev = container_of(knode, struct device, knode_class);
+		if (!iter->type || iter->type == dev->type)
+			return dev;
+	}
+}
+EXPORT_SYMBOL_GPL(class_dev_iter_next);
+
+/**
+ * class_dev_iter_exit - finish iteration
+ * @iter: class iterator to finish
+ *
+ * Finish an iteration.  Always call this function after iteration is
+ * complete whether the iteration ran till the end or not.
+ */
+void class_dev_iter_exit(struct class_dev_iter *iter)
+{
+	klist_iter_exit(&iter->ki);
+}
+EXPORT_SYMBOL_GPL(class_dev_iter_exit);
+
+/**
  * class_for_each_device - device iterator
  * @class: the class we're iterating
  * @start: the device to start with in the list, if any.
@@ -283,13 +362,13 @@
  * We check the return of @fn each time. If it returns anything
  * other than 0, we break out and return that value.
  *
- * Note, we hold class->class_mutex in this function, so it can not be
- * re-acquired in @fn, otherwise it will self-deadlocking. For
- * example, calls to add or remove class members would be verboten.
+ * @fn is allowed to do anything including calling back into class
+ * code.  There's no locking restriction.
  */
 int class_for_each_device(struct class *class, struct device *start,
 			  void *data, int (*fn)(struct device *, void *))
 {
+	struct class_dev_iter iter;
 	struct device *dev;
 	int error = 0;
 
@@ -301,20 +380,13 @@
 		return -EINVAL;
 	}
 
-	mutex_lock(&class->p->class_mutex);
-	list_for_each_entry(dev, &class->p->class_devices, node) {
-		if (start) {
-			if (start == dev)
-				start = NULL;
-			continue;
-		}
-		dev = get_device(dev);
+	class_dev_iter_init(&iter, class, start, NULL);
+	while ((dev = class_dev_iter_next(&iter))) {
 		error = fn(dev, data);
-		put_device(dev);
 		if (error)
 			break;
 	}
-	mutex_unlock(&class->p->class_mutex);
+	class_dev_iter_exit(&iter);
 
 	return error;
 }
@@ -337,16 +409,15 @@
  *
  * Note, you will need to drop the reference with put_device() after use.
  *
- * We hold class->class_mutex in this function, so it can not be
- * re-acquired in @match, otherwise it will self-deadlocking. For
- * example, calls to add or remove class members would be verboten.
+ * @fn is allowed to do anything including calling back into class
+ * code.  There's no locking restriction.
  */
 struct device *class_find_device(struct class *class, struct device *start,
 				 void *data,
 				 int (*match)(struct device *, void *))
 {
+	struct class_dev_iter iter;
 	struct device *dev;
-	int found = 0;
 
 	if (!class)
 		return NULL;
@@ -356,29 +427,23 @@
 		return NULL;
 	}
 
-	mutex_lock(&class->p->class_mutex);
-	list_for_each_entry(dev, &class->p->class_devices, node) {
-		if (start) {
-			if (start == dev)
-				start = NULL;
-			continue;
-		}
-		dev = get_device(dev);
+	class_dev_iter_init(&iter, class, start, NULL);
+	while ((dev = class_dev_iter_next(&iter))) {
 		if (match(dev, data)) {
-			found = 1;
+			get_device(dev);
 			break;
-		} else
-			put_device(dev);
+		}
 	}
-	mutex_unlock(&class->p->class_mutex);
+	class_dev_iter_exit(&iter);
 
-	return found ? dev : NULL;
+	return dev;
 }
 EXPORT_SYMBOL_GPL(class_find_device);
 
 int class_interface_register(struct class_interface *class_intf)
 {
 	struct class *parent;
+	struct class_dev_iter iter;
 	struct device *dev;
 
 	if (!class_intf || !class_intf->class)
@@ -391,8 +456,10 @@
 	mutex_lock(&parent->p->class_mutex);
 	list_add_tail(&class_intf->node, &parent->p->class_interfaces);
 	if (class_intf->add_dev) {
-		list_for_each_entry(dev, &parent->p->class_devices, node)
+		class_dev_iter_init(&iter, parent, NULL, NULL);
+		while ((dev = class_dev_iter_next(&iter)))
 			class_intf->add_dev(dev, class_intf);
+		class_dev_iter_exit(&iter);
 	}
 	mutex_unlock(&parent->p->class_mutex);
 
@@ -402,6 +469,7 @@
 void class_interface_unregister(struct class_interface *class_intf)
 {
 	struct class *parent = class_intf->class;
+	struct class_dev_iter iter;
 	struct device *dev;
 
 	if (!parent)
@@ -410,8 +478,10 @@
 	mutex_lock(&parent->p->class_mutex);
 	list_del_init(&class_intf->node);
 	if (class_intf->remove_dev) {
-		list_for_each_entry(dev, &parent->p->class_devices, node)
+		class_dev_iter_init(&iter, parent, NULL, NULL);
+		while ((dev = class_dev_iter_next(&iter)))
 			class_intf->remove_dev(dev, class_intf);
+		class_dev_iter_exit(&iter);
 	}
 	mutex_unlock(&parent->p->class_mutex);
 
diff --git a/drivers/base/core.c b/drivers/base/core.c
index d021c98..b98cb14 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -536,7 +536,6 @@
 	klist_init(&dev->klist_children, klist_children_get,
 		   klist_children_put);
 	INIT_LIST_HEAD(&dev->dma_pools);
-	INIT_LIST_HEAD(&dev->node);
 	init_MUTEX(&dev->sem);
 	spin_lock_init(&dev->devres_lock);
 	INIT_LIST_HEAD(&dev->devres_head);
@@ -916,7 +915,8 @@
 	if (dev->class) {
 		mutex_lock(&dev->class->p->class_mutex);
 		/* tie the class to the device */
-		list_add_tail(&dev->node, &dev->class->p->class_devices);
+		klist_add_tail(&dev->knode_class,
+			       &dev->class->p->class_devices);
 
 		/* notify any interfaces that the device is here */
 		list_for_each_entry(class_intf,
@@ -1032,7 +1032,7 @@
 			if (class_intf->remove_dev)
 				class_intf->remove_dev(dev, class_intf);
 		/* remove the device from the class list */
-		list_del_init(&dev->node);
+		klist_del(&dev->knode_class);
 		mutex_unlock(&dev->class->p->class_mutex);
 	}
 	device_remove_file(dev, &uevent_attr);
diff --git a/drivers/block/aoe/aoe.h b/drivers/block/aoe/aoe.h
index 5b4c6e6..93f3690 100644
--- a/drivers/block/aoe/aoe.h
+++ b/drivers/block/aoe/aoe.h
@@ -159,11 +159,8 @@
 	sector_t ssize;
 	struct timer_list timer;
 	spinlock_t lock;
-	struct sk_buff *sendq_hd; /* packets needing to be sent, list head */
-	struct sk_buff *sendq_tl;
-	struct sk_buff *skbpool_hd;
-	struct sk_buff *skbpool_tl;
-	int nskbpool;
+	struct sk_buff_head sendq;
+	struct sk_buff_head skbpool;
 	mempool_t *bufpool;	/* for deadlock-free Buf allocation */
 	struct list_head bufq;	/* queue of bios to work on */
 	struct buf *inprocess;	/* the one we're currently working on */
@@ -199,7 +196,7 @@
 
 int aoenet_init(void);
 void aoenet_exit(void);
-void aoenet_xmit(struct sk_buff *);
+void aoenet_xmit(struct sk_buff_head *);
 int is_aoe_netif(struct net_device *ifp);
 int set_aoe_iflist(const char __user *str, size_t size);
 
diff --git a/drivers/block/aoe/aoeblk.c b/drivers/block/aoe/aoeblk.c
index 0c39782..b82654e 100644
--- a/drivers/block/aoe/aoeblk.c
+++ b/drivers/block/aoe/aoeblk.c
@@ -109,12 +109,12 @@
 static int
 aoedisk_add_sysfs(struct aoedev *d)
 {
-	return sysfs_create_group(&d->gd->dev.kobj, &attr_group);
+	return sysfs_create_group(&disk_to_dev(d->gd)->kobj, &attr_group);
 }
 void
 aoedisk_rm_sysfs(struct aoedev *d)
 {
-	sysfs_remove_group(&d->gd->dev.kobj, &attr_group);
+	sysfs_remove_group(&disk_to_dev(d->gd)->kobj, &attr_group);
 }
 
 static int
@@ -158,9 +158,9 @@
 static int
 aoeblk_make_request(struct request_queue *q, struct bio *bio)
 {
+	struct sk_buff_head queue;
 	struct aoedev *d;
 	struct buf *buf;
-	struct sk_buff *sl;
 	ulong flags;
 
 	blk_queue_bounce(q, &bio);
@@ -213,11 +213,11 @@
 	list_add_tail(&buf->bufs, &d->bufq);
 
 	aoecmd_work(d);
-	sl = d->sendq_hd;
-	d->sendq_hd = d->sendq_tl = NULL;
+	__skb_queue_head_init(&queue);
+	skb_queue_splice_init(&d->sendq, &queue);
 
 	spin_unlock_irqrestore(&d->lock, flags);
-	aoenet_xmit(sl);
+	aoenet_xmit(&queue);
 
 	return 0;
 }
@@ -276,7 +276,7 @@
 	gd->first_minor = d->sysminor * AOE_PARTITIONS;
 	gd->fops = &aoe_bdops;
 	gd->private_data = d;
-	gd->capacity = d->ssize;
+	set_capacity(gd, d->ssize);
 	snprintf(gd->disk_name, sizeof gd->disk_name, "etherd/e%ld.%d",
 		d->aoemajor, d->aoeminor);
 
diff --git a/drivers/block/aoe/aoechr.c b/drivers/block/aoe/aoechr.c
index 181ebb8..1f56d2c 100644
--- a/drivers/block/aoe/aoechr.c
+++ b/drivers/block/aoe/aoechr.c
@@ -9,6 +9,7 @@
 #include <linux/completion.h>
 #include <linux/delay.h>
 #include <linux/smp_lock.h>
+#include <linux/skbuff.h>
 #include "aoe.h"
 
 enum {
@@ -103,7 +104,12 @@
 		spin_lock_irqsave(&d->lock, flags);
 		goto loop;
 	}
-	aoenet_xmit(skb);
+	if (skb) {
+		struct sk_buff_head queue;
+		__skb_queue_head_init(&queue);
+		__skb_queue_tail(&queue, skb);
+		aoenet_xmit(&queue);
+	}
 	aoecmd_cfg(major, minor);
 	return 0;
 }
diff --git a/drivers/block/aoe/aoecmd.c b/drivers/block/aoe/aoecmd.c
index 2f17462..71ff78c9 100644
--- a/drivers/block/aoe/aoecmd.c
+++ b/drivers/block/aoe/aoecmd.c
@@ -114,29 +114,22 @@
 static void
 skb_pool_put(struct aoedev *d, struct sk_buff *skb)
 {
-	if (!d->skbpool_hd)
-		d->skbpool_hd = skb;
-	else
-		d->skbpool_tl->next = skb;
-	d->skbpool_tl = skb;
+	__skb_queue_tail(&d->skbpool, skb);
 }
 
 static struct sk_buff *
 skb_pool_get(struct aoedev *d)
 {
-	struct sk_buff *skb;
+	struct sk_buff *skb = skb_peek(&d->skbpool);
 
-	skb = d->skbpool_hd;
 	if (skb && atomic_read(&skb_shinfo(skb)->dataref) == 1) {
-		d->skbpool_hd = skb->next;
-		skb->next = NULL;
+		__skb_unlink(skb, &d->skbpool);
 		return skb;
 	}
-	if (d->nskbpool < NSKBPOOLMAX
-	&& (skb = new_skb(ETH_ZLEN))) {
-		d->nskbpool++;
+	if (skb_queue_len(&d->skbpool) < NSKBPOOLMAX &&
+	    (skb = new_skb(ETH_ZLEN)))
 		return skb;
-	}
+
 	return NULL;
 }
 
@@ -293,29 +286,22 @@
 
 	skb->dev = t->ifp->nd;
 	skb = skb_clone(skb, GFP_ATOMIC);
-	if (skb) {
-		if (d->sendq_hd)
-			d->sendq_tl->next = skb;
-		else
-			d->sendq_hd = skb;
-		d->sendq_tl = skb;
-	}
+	if (skb)
+		__skb_queue_tail(&d->sendq, skb);
 	return 1;
 }
 
 /* some callers cannot sleep, and they can call this function,
  * transmitting the packets later, when interrupts are on
  */
-static struct sk_buff *
-aoecmd_cfg_pkts(ushort aoemajor, unsigned char aoeminor, struct sk_buff **tail)
+static void
+aoecmd_cfg_pkts(ushort aoemajor, unsigned char aoeminor, struct sk_buff_head *queue)
 {
 	struct aoe_hdr *h;
 	struct aoe_cfghdr *ch;
-	struct sk_buff *skb, *sl, *sl_tail;
+	struct sk_buff *skb;
 	struct net_device *ifp;
 
-	sl = sl_tail = NULL;
-
 	read_lock(&dev_base_lock);
 	for_each_netdev(&init_net, ifp) {
 		dev_hold(ifp);
@@ -329,8 +315,7 @@
 		}
 		skb_put(skb, sizeof *h + sizeof *ch);
 		skb->dev = ifp;
-		if (sl_tail == NULL)
-			sl_tail = skb;
+		__skb_queue_tail(queue, skb);
 		h = (struct aoe_hdr *) skb_mac_header(skb);
 		memset(h, 0, sizeof *h + sizeof *ch);
 
@@ -342,16 +327,10 @@
 		h->minor = aoeminor;
 		h->cmd = AOECMD_CFG;
 
-		skb->next = sl;
-		sl = skb;
 cont:
 		dev_put(ifp);
 	}
 	read_unlock(&dev_base_lock);
-
-	if (tail != NULL)
-		*tail = sl_tail;
-	return sl;
 }
 
 static void
@@ -406,11 +385,7 @@
 	skb = skb_clone(skb, GFP_ATOMIC);
 	if (skb == NULL)
 		return;
-	if (d->sendq_hd)
-		d->sendq_tl->next = skb;
-	else
-		d->sendq_hd = skb;
-	d->sendq_tl = skb;
+	__skb_queue_tail(&d->sendq, skb);
 }
 
 static int
@@ -508,16 +483,15 @@
 static void
 rexmit_timer(ulong vp)
 {
+	struct sk_buff_head queue;
 	struct aoedev *d;
 	struct aoetgt *t, **tt, **te;
 	struct aoeif *ifp;
 	struct frame *f, *e;
-	struct sk_buff *sl;
 	register long timeout;
 	ulong flags, n;
 
 	d = (struct aoedev *) vp;
-	sl = NULL;
 
 	/* timeout is always ~150% of the moving average */
 	timeout = d->rttavg;
@@ -589,7 +563,7 @@
 		}
 	}
 
-	if (d->sendq_hd) {
+	if (!skb_queue_empty(&d->sendq)) {
 		n = d->rttavg <<= 1;
 		if (n > MAXTIMER)
 			d->rttavg = MAXTIMER;
@@ -600,15 +574,15 @@
 		aoecmd_work(d);
 	}
 
-	sl = d->sendq_hd;
-	d->sendq_hd = d->sendq_tl = NULL;
+	__skb_queue_head_init(&queue);
+	skb_queue_splice_init(&d->sendq, &queue);
 
 	d->timer.expires = jiffies + TIMERTICK;
 	add_timer(&d->timer);
 
 	spin_unlock_irqrestore(&d->lock, flags);
 
-	aoenet_xmit(sl);
+	aoenet_xmit(&queue);
 }
 
 /* enters with d->lock held */
@@ -645,7 +619,7 @@
 		unsigned long flags;
 		u64 ssize;
 
-		ssize = d->gd->capacity;
+		ssize = get_capacity(d->gd);
 		bd = bdget_disk(d->gd, 0);
 
 		if (bd) {
@@ -707,7 +681,7 @@
 	if (d->flags & (DEVFL_GDALLOC|DEVFL_NEWSIZE))
 		return;
 	if (d->gd != NULL) {
-		d->gd->capacity = ssize;
+		set_capacity(d->gd, ssize);
 		d->flags |= DEVFL_NEWSIZE;
 	} else
 		d->flags |= DEVFL_GDALLOC;
@@ -756,23 +730,28 @@
 	unsigned long n_sect = bio->bi_size >> 9;
 	const int rw = bio_data_dir(bio);
 	struct hd_struct *part;
+	int cpu;
 
-	part = get_part(disk, sector);
-	all_stat_inc(disk, part, ios[rw], sector);
-	all_stat_add(disk, part, ticks[rw], duration, sector);
-	all_stat_add(disk, part, sectors[rw], n_sect, sector);
-	all_stat_add(disk, part, io_ticks, duration, sector);
+	cpu = part_stat_lock();
+	part = disk_map_sector_rcu(disk, sector);
+
+	part_stat_inc(cpu, part, ios[rw]);
+	part_stat_add(cpu, part, ticks[rw], duration);
+	part_stat_add(cpu, part, sectors[rw], n_sect);
+	part_stat_add(cpu, part, io_ticks, duration);
+
+	part_stat_unlock();
 }
 
 void
 aoecmd_ata_rsp(struct sk_buff *skb)
 {
+	struct sk_buff_head queue;
 	struct aoedev *d;
 	struct aoe_hdr *hin, *hout;
 	struct aoe_atahdr *ahin, *ahout;
 	struct frame *f;
 	struct buf *buf;
-	struct sk_buff *sl;
 	struct aoetgt *t;
 	struct aoeif *ifp;
 	register long n;
@@ -893,21 +872,21 @@
 
 	aoecmd_work(d);
 xmit:
-	sl = d->sendq_hd;
-	d->sendq_hd = d->sendq_tl = NULL;
+	__skb_queue_head_init(&queue);
+	skb_queue_splice_init(&d->sendq, &queue);
 
 	spin_unlock_irqrestore(&d->lock, flags);
-	aoenet_xmit(sl);
+	aoenet_xmit(&queue);
 }
 
 void
 aoecmd_cfg(ushort aoemajor, unsigned char aoeminor)
 {
-	struct sk_buff *sl;
+	struct sk_buff_head queue;
 
-	sl = aoecmd_cfg_pkts(aoemajor, aoeminor, NULL);
-
-	aoenet_xmit(sl);
+	__skb_queue_head_init(&queue);
+	aoecmd_cfg_pkts(aoemajor, aoeminor, &queue);
+	aoenet_xmit(&queue);
 }
  
 struct sk_buff *
@@ -1076,7 +1055,12 @@
 
 	spin_unlock_irqrestore(&d->lock, flags);
 
-	aoenet_xmit(sl);
+	if (sl) {
+		struct sk_buff_head queue;
+		__skb_queue_head_init(&queue);
+		__skb_queue_tail(&queue, sl);
+		aoenet_xmit(&queue);
+	}
 }
 
 void
diff --git a/drivers/block/aoe/aoedev.c b/drivers/block/aoe/aoedev.c
index a1d813a..cc25057 100644
--- a/drivers/block/aoe/aoedev.c
+++ b/drivers/block/aoe/aoedev.c
@@ -91,7 +91,7 @@
 	}
 
 	if (d->gd)
-		d->gd->capacity = 0;
+		set_capacity(d->gd, 0);
 
 	d->flags &= ~DEVFL_UP;
 }
@@ -188,14 +188,12 @@
 static void
 skbpoolfree(struct aoedev *d)
 {
-	struct sk_buff *skb;
+	struct sk_buff *skb, *tmp;
 
-	while ((skb = d->skbpool_hd)) {
-		d->skbpool_hd = skb->next;
-		skb->next = NULL;
+	skb_queue_walk_safe(&d->skbpool, skb, tmp)
 		skbfree(skb);
-	}
-	d->skbpool_tl = NULL;
+
+	__skb_queue_head_init(&d->skbpool);
 }
 
 /* find it or malloc it */
@@ -217,6 +215,8 @@
 		goto out;
 	INIT_WORK(&d->work, aoecmd_sleepwork);
 	spin_lock_init(&d->lock);
+	skb_queue_head_init(&d->sendq);
+	skb_queue_head_init(&d->skbpool);
 	init_timer(&d->timer);
 	d->timer.data = (ulong) d;
 	d->timer.function = dummy_timer;
diff --git a/drivers/block/aoe/aoemain.c b/drivers/block/aoe/aoemain.c
index 7b15a5e..7f83ad9 100644
--- a/drivers/block/aoe/aoemain.c
+++ b/drivers/block/aoe/aoemain.c
@@ -7,6 +7,7 @@
 #include <linux/hdreg.h>
 #include <linux/blkdev.h>
 #include <linux/module.h>
+#include <linux/skbuff.h>
 #include "aoe.h"
 
 MODULE_LICENSE("GPL");
diff --git a/drivers/block/aoe/aoenet.c b/drivers/block/aoe/aoenet.c
index 0c81ca7..9157d64 100644
--- a/drivers/block/aoe/aoenet.c
+++ b/drivers/block/aoe/aoenet.c
@@ -95,13 +95,12 @@
 }
 
 void
-aoenet_xmit(struct sk_buff *sl)
+aoenet_xmit(struct sk_buff_head *queue)
 {
-	struct sk_buff *skb;
+	struct sk_buff *skb, *tmp;
 
-	while ((skb = sl)) {
-		sl = sl->next;
-		skb->next = skb->prev = NULL;
+	skb_queue_walk_safe(queue, skb, tmp) {
+		__skb_unlink(skb, queue);
 		dev_queue_xmit(skb);
 	}
 }
diff --git a/drivers/block/ataflop.c b/drivers/block/ataflop.c
index 49f2741..432cf40 100644
--- a/drivers/block/ataflop.c
+++ b/drivers/block/ataflop.c
@@ -1882,10 +1882,6 @@
 		/* Amiga, Mac, ... don't have Atari-compatible floppy :-) */
 		return -ENODEV;
 
-	if (MACH_IS_HADES)
-		/* Hades doesn't have Atari-compatible floppy */
-		return -ENODEV;
-
 	if (register_blkdev(FLOPPY_MAJOR,"fd"))
 		return -EBUSY;
 
diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c
index b73116e..1e1f915 100644
--- a/drivers/block/cciss.c
+++ b/drivers/block/cciss.c
@@ -3460,8 +3460,8 @@
 	       hba[i]->intr[SIMPLE_MODE_INT], dac ? "" : " not");
 
 	hba[i]->cmd_pool_bits =
-	    kmalloc(((hba[i]->nr_cmds + BITS_PER_LONG -
-		      1) / BITS_PER_LONG) * sizeof(unsigned long), GFP_KERNEL);
+	    kmalloc(DIV_ROUND_UP(hba[i]->nr_cmds, BITS_PER_LONG)
+			* sizeof(unsigned long), GFP_KERNEL);
 	hba[i]->cmd_pool = (CommandList_struct *)
 	    pci_alloc_consistent(hba[i]->pdev,
 		    hba[i]->nr_cmds * sizeof(CommandList_struct),
@@ -3493,8 +3493,8 @@
 	/* command and error info recs zeroed out before
 	   they are used */
 	memset(hba[i]->cmd_pool_bits, 0,
-	       ((hba[i]->nr_cmds + BITS_PER_LONG -
-		 1) / BITS_PER_LONG) * sizeof(unsigned long));
+	       DIV_ROUND_UP(hba[i]->nr_cmds, BITS_PER_LONG)
+			* sizeof(unsigned long));
 
 	hba[i]->num_luns = 0;
 	hba[i]->highest_lun = -1;
diff --git a/drivers/block/cciss_scsi.c b/drivers/block/cciss_scsi.c
index e1233aa..a3fd87b 100644
--- a/drivers/block/cciss_scsi.c
+++ b/drivers/block/cciss_scsi.c
@@ -365,7 +365,7 @@
 
 static int 
 cciss_scsi_add_entry(int ctlr, int hostno, 
-		unsigned char *scsi3addr, int devtype,
+		struct cciss_scsi_dev_t *device,
 		struct scsi2map *added, int *nadded)
 {
 	/* assumes hba[ctlr]->scsi_ctlr->lock is held */ 
@@ -384,12 +384,12 @@
 	lun = 0;
 	/* Is this device a non-zero lun of a multi-lun device */
 	/* byte 4 of the 8-byte LUN addr will contain the logical unit no. */
-	if (scsi3addr[4] != 0) {
+	if (device->scsi3addr[4] != 0) {
 		/* Search through our list and find the device which */
 		/* has the same 8 byte LUN address, excepting byte 4. */
 		/* Assign the same bus and target for this new LUN. */
 		/* Use the logical unit number from the firmware. */
-		memcpy(addr1, scsi3addr, 8);
+		memcpy(addr1, device->scsi3addr, 8);
 		addr1[4] = 0;
 		for (i = 0; i < n; i++) {
 			sd = &ccissscsi[ctlr].dev[i];
@@ -399,7 +399,7 @@
 			if (memcmp(addr1, addr2, 8) == 0) {
 				bus = sd->bus;
 				target = sd->target;
-				lun = scsi3addr[4];
+				lun = device->scsi3addr[4];
 				break;
 			}
 		}
@@ -420,8 +420,12 @@
 	added[*nadded].lun = sd->lun;
 	(*nadded)++;
 
-	memcpy(&sd->scsi3addr[0], scsi3addr, 8);
-	sd->devtype = devtype;
+	memcpy(sd->scsi3addr, device->scsi3addr, 8);
+	memcpy(sd->vendor, device->vendor, sizeof(sd->vendor));
+	memcpy(sd->revision, device->revision, sizeof(sd->revision));
+	memcpy(sd->device_id, device->device_id, sizeof(sd->device_id));
+	sd->devtype = device->devtype;
+
 	ccissscsi[ctlr].ndevices++;
 
 	/* initially, (before registering with scsi layer) we don't 
@@ -487,6 +491,22 @@
 	CPQ_TAPE_UNLOCK(ctlr, flags);
 }
 
+static int device_is_the_same(struct cciss_scsi_dev_t *dev1,
+	struct cciss_scsi_dev_t *dev2)
+{
+	return dev1->devtype == dev2->devtype &&
+		memcmp(dev1->scsi3addr, dev2->scsi3addr,
+			sizeof(dev1->scsi3addr)) == 0 &&
+		memcmp(dev1->device_id, dev2->device_id,
+			sizeof(dev1->device_id)) == 0 &&
+		memcmp(dev1->vendor, dev2->vendor,
+			sizeof(dev1->vendor)) == 0 &&
+		memcmp(dev1->model, dev2->model,
+			sizeof(dev1->model)) == 0 &&
+		memcmp(dev1->revision, dev2->revision,
+			sizeof(dev1->revision)) == 0;
+}
+
 static int
 adjust_cciss_scsi_table(int ctlr, int hostno,
 	struct cciss_scsi_dev_t sd[], int nsds)
@@ -532,7 +552,7 @@
 		for (j=0;j<nsds;j++) {
 			if (SCSI3ADDR_EQ(sd[j].scsi3addr,
 				csd->scsi3addr)) {
-				if (sd[j].devtype == csd->devtype)
+				if (device_is_the_same(&sd[j], csd))
 					found=2;
 				else
 					found=1;
@@ -548,22 +568,26 @@
 			cciss_scsi_remove_entry(ctlr, hostno, i,
 				removed, &nremoved);
 			/* remove ^^^, hence i not incremented */
-		} 
-		else if (found == 1) { /* device is different kind */
+		} else if (found == 1) { /* device is different in some way */
 			changes++;
-			printk("cciss%d: device c%db%dt%dl%d type changed "
-				"(device type now %s).\n",
-				ctlr, hostno, csd->bus, csd->target, csd->lun,
-					scsi_device_type(csd->devtype));
+			printk("cciss%d: device c%db%dt%dl%d has changed.\n",
+				ctlr, hostno, csd->bus, csd->target, csd->lun);
 			cciss_scsi_remove_entry(ctlr, hostno, i,
 				removed, &nremoved);
 			/* remove ^^^, hence i not incremented */
-			if (cciss_scsi_add_entry(ctlr, hostno,
-				&sd[j].scsi3addr[0], sd[j].devtype,
+			if (cciss_scsi_add_entry(ctlr, hostno, &sd[j],
 				added, &nadded) != 0)
 				/* we just removed one, so add can't fail. */
 					BUG();
 			csd->devtype = sd[j].devtype;
+			memcpy(csd->device_id, sd[j].device_id,
+				sizeof(csd->device_id));
+			memcpy(csd->vendor, sd[j].vendor,
+				sizeof(csd->vendor));
+			memcpy(csd->model, sd[j].model,
+				sizeof(csd->model));
+			memcpy(csd->revision, sd[j].revision,
+				sizeof(csd->revision));
 		} else 		/* device is same as it ever was, */
 			i++;	/* so just move along. */
 	}
@@ -577,7 +601,7 @@
 			csd = &ccissscsi[ctlr].dev[j];
 			if (SCSI3ADDR_EQ(sd[i].scsi3addr,
 				csd->scsi3addr)) {
-				if (sd[i].devtype == csd->devtype)
+				if (device_is_the_same(&sd[i], csd))
 					found=2;	/* found device */
 				else
 					found=1; 	/* found a bug. */
@@ -586,16 +610,14 @@
 		}
 		if (!found) {
 			changes++;
-			if (cciss_scsi_add_entry(ctlr, hostno, 
-
-				&sd[i].scsi3addr[0], sd[i].devtype,
+			if (cciss_scsi_add_entry(ctlr, hostno, &sd[i],
 				added, &nadded) != 0)
 				break;
 		} else if (found == 1) {
 			/* should never happen... */
 			changes++;
-			printk("cciss%d: device unexpectedly changed type\n",
-				ctlr);
+			printk(KERN_WARNING "cciss%d: device "
+				"unexpectedly changed\n", ctlr);
 			/* but if it does happen, we just ignore that device */
 		}
 	}
@@ -1012,7 +1034,8 @@
 
 static int
 cciss_scsi_do_inquiry(ctlr_info_t *c, unsigned char *scsi3addr, 
-		 unsigned char *buf, unsigned char bufsize)
+	unsigned char page, unsigned char *buf,
+	unsigned char bufsize)
 {
 	int rc;
 	CommandList_struct *cp;
@@ -1032,8 +1055,8 @@
 	ei = cp->err_info; 
 
 	cdb[0] = CISS_INQUIRY;
-	cdb[1] = 0;
-	cdb[2] = 0;
+	cdb[1] = (page != 0);
+	cdb[2] = page;
 	cdb[3] = 0;
 	cdb[4] = bufsize;
 	cdb[5] = 0;
@@ -1053,6 +1076,25 @@
 	return rc;	
 }
 
+/* Get the device id from inquiry page 0x83 */
+static int cciss_scsi_get_device_id(ctlr_info_t *c, unsigned char *scsi3addr,
+	unsigned char *device_id, int buflen)
+{
+	int rc;
+	unsigned char *buf;
+
+	if (buflen > 16)
+		buflen = 16;
+	buf = kzalloc(64, GFP_KERNEL);
+	if (!buf)
+		return -1;
+	rc = cciss_scsi_do_inquiry(c, scsi3addr, 0x83, buf, 64);
+	if (rc == 0)
+		memcpy(device_id, &buf[8], buflen);
+	kfree(buf);
+	return rc != 0;
+}
+
 static int
 cciss_scsi_do_report_phys_luns(ctlr_info_t *c, 
 		ReportLunData_struct *buf, int bufsize)
@@ -1142,25 +1184,21 @@
 	ctlr_info_t *c;
 	__u32 num_luns=0;
 	unsigned char *ch;
-	/* unsigned char found[CCISS_MAX_SCSI_DEVS_PER_HBA]; */
-	struct cciss_scsi_dev_t currentsd[CCISS_MAX_SCSI_DEVS_PER_HBA];
+	struct cciss_scsi_dev_t *currentsd, *this_device;
 	int ncurrent=0;
 	int reportlunsize = sizeof(*ld_buff) + CISS_MAX_PHYS_LUN * 8;
 	int i;
 
 	c = (ctlr_info_t *) hba[cntl_num];	
 	ld_buff = kzalloc(reportlunsize, GFP_KERNEL);
-	if (ld_buff == NULL) {
-		printk(KERN_ERR "cciss: out of memory\n");
-		return;
-	}
 	inq_buff = kmalloc(OBDR_TAPE_INQ_SIZE, GFP_KERNEL);
-        if (inq_buff == NULL) {
-                printk(KERN_ERR "cciss: out of memory\n");
-                kfree(ld_buff);
-                return;
+	currentsd = kzalloc(sizeof(*currentsd) *
+			(CCISS_MAX_SCSI_DEVS_PER_HBA+1), GFP_KERNEL);
+	if (ld_buff == NULL || inq_buff == NULL || currentsd == NULL) {
+		printk(KERN_ERR "cciss: out of memory\n");
+		goto out;
 	}
-
+	this_device = &currentsd[CCISS_MAX_SCSI_DEVS_PER_HBA];
 	if (cciss_scsi_do_report_phys_luns(c, ld_buff, reportlunsize) == 0) {
 		ch = &ld_buff->LUNListLength[0];
 		num_luns = ((ch[0]<<24) | (ch[1]<<16) | (ch[2]<<8) | ch[3]) / 8;
@@ -1179,23 +1217,34 @@
 
 
 	/* adjust our table of devices */	
-	for(i=0; i<num_luns; i++)
-	{
-		int devtype;
-
+	for (i = 0; i < num_luns; i++) {
 		/* for each physical lun, do an inquiry */
 		if (ld_buff->LUN[i][3] & 0xC0) continue;
 		memset(inq_buff, 0, OBDR_TAPE_INQ_SIZE);
 		memcpy(&scsi3addr[0], &ld_buff->LUN[i][0], 8);
 
-		if (cciss_scsi_do_inquiry(hba[cntl_num], scsi3addr, inq_buff,
-			(unsigned char) OBDR_TAPE_INQ_SIZE) != 0) {
+		if (cciss_scsi_do_inquiry(hba[cntl_num], scsi3addr, 0, inq_buff,
+			(unsigned char) OBDR_TAPE_INQ_SIZE) != 0)
 			/* Inquiry failed (msg printed already) */
-			devtype = 0; /* so we will skip this device. */
-		} else /* what kind of device is this? */
-			devtype = (inq_buff[0] & 0x1f);
+			continue; /* so we will skip this device. */
 
-		switch (devtype)
+		this_device->devtype = (inq_buff[0] & 0x1f);
+		this_device->bus = -1;
+		this_device->target = -1;
+		this_device->lun = -1;
+		memcpy(this_device->scsi3addr, scsi3addr, 8);
+		memcpy(this_device->vendor, &inq_buff[8],
+			sizeof(this_device->vendor));
+		memcpy(this_device->model, &inq_buff[16],
+			sizeof(this_device->model));
+		memcpy(this_device->revision, &inq_buff[32],
+			sizeof(this_device->revision));
+		memset(this_device->device_id, 0,
+			sizeof(this_device->device_id));
+		cciss_scsi_get_device_id(hba[cntl_num], scsi3addr,
+			this_device->device_id, sizeof(this_device->device_id));
+
+		switch (this_device->devtype)
 		{
 		  case 0x05: /* CD-ROM */ {
 
@@ -1220,15 +1269,10 @@
 			if (ncurrent >= CCISS_MAX_SCSI_DEVS_PER_HBA) {
 				printk(KERN_INFO "cciss%d: %s ignored, "
 					"too many devices.\n", cntl_num,
-					scsi_device_type(devtype));
+					scsi_device_type(this_device->devtype));
 				break;
 			}
-			memcpy(&currentsd[ncurrent].scsi3addr[0], 
-				&scsi3addr[0], 8);
-			currentsd[ncurrent].devtype = devtype;
-			currentsd[ncurrent].bus = -1;
-			currentsd[ncurrent].target = -1;
-			currentsd[ncurrent].lun = -1;
+			currentsd[ncurrent] = *this_device;
 			ncurrent++;
 			break;
 		  default: 
@@ -1240,6 +1284,7 @@
 out:
 	kfree(inq_buff);
 	kfree(ld_buff);
+	kfree(currentsd);
 	return;
 }
 
diff --git a/drivers/block/cciss_scsi.h b/drivers/block/cciss_scsi.h
index d9c2c58..7b75024 100644
--- a/drivers/block/cciss_scsi.h
+++ b/drivers/block/cciss_scsi.h
@@ -66,6 +66,10 @@
 	int devtype;
 	int bus, target, lun;		/* as presented to the OS */
 	unsigned char scsi3addr[8];	/* as presented to the HW */
+	unsigned char device_id[16];	/* from inquiry pg. 0x83 */
+	unsigned char vendor[8];	/* bytes 8-15 of inquiry data */
+	unsigned char model[16];	/* bytes 16-31 of inquiry data */
+	unsigned char revision[4];	/* bytes 32-35 of inquiry data */
 };
 
 struct cciss_scsi_hba_t {
diff --git a/drivers/block/cpqarray.c b/drivers/block/cpqarray.c
index 09c1434..3d96752 100644
--- a/drivers/block/cpqarray.c
+++ b/drivers/block/cpqarray.c
@@ -424,7 +424,7 @@
 		hba[i]->pci_dev, NR_CMDS * sizeof(cmdlist_t),
 		&(hba[i]->cmd_pool_dhandle));
 	hba[i]->cmd_pool_bits = kcalloc(
-		(NR_CMDS+BITS_PER_LONG-1)/BITS_PER_LONG, sizeof(unsigned long),
+		DIV_ROUND_UP(NR_CMDS, BITS_PER_LONG), sizeof(unsigned long),
 		GFP_KERNEL);
 
 	if (!hba[i]->cmd_pool_bits || !hba[i]->cmd_pool)
diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c
index 395f8ea..cf64ddf 100644
--- a/drivers/block/floppy.c
+++ b/drivers/block/floppy.c
@@ -423,8 +423,15 @@
  * 1581's logical side 0 is on physical side 1, whereas the Sharp's logical
  * side 0 is on physical side 0 (but with the misnamed sector IDs).
  * 'stretch' should probably be renamed to something more general, like
- * 'options'.  Other parameters should be self-explanatory (see also
- * setfdprm(8)).
+ * 'options'.
+ *
+ * Bits 2 through 9 of 'stretch' tell the number of the first sector.
+ * The LSB (bit 2) is flipped. For most disks, the first sector
+ * is 1 (represented by 0x00<<2).  For some CP/M and music sampler
+ * disks (such as Ensoniq EPS 16plus) it is 0 (represented as 0x01<<2).
+ * For Amstrad CPC disks it is 0xC1 (represented as 0xC0<<2).
+ *
+ * Other parameters should be self-explanatory (see also setfdprm(8)).
  */
 /*
 	    Size
@@ -1355,20 +1362,20 @@
 	}
 
 	/* Convert step rate from microseconds to milliseconds and 4 bits */
-	srt = 16 - (DP->srt * scale_dtr / 1000 + NOMINAL_DTR - 1) / NOMINAL_DTR;
+	srt = 16 - DIV_ROUND_UP(DP->srt * scale_dtr / 1000, NOMINAL_DTR);
 	if (slow_floppy) {
 		srt = srt / 4;
 	}
 	SUPBOUND(srt, 0xf);
 	INFBOUND(srt, 0);
 
-	hlt = (DP->hlt * scale_dtr / 2 + NOMINAL_DTR - 1) / NOMINAL_DTR;
+	hlt = DIV_ROUND_UP(DP->hlt * scale_dtr / 2, NOMINAL_DTR);
 	if (hlt < 0x01)
 		hlt = 0x01;
 	else if (hlt > 0x7f)
 		hlt = hlt_max_code;
 
-	hut = (DP->hut * scale_dtr / 16 + NOMINAL_DTR - 1) / NOMINAL_DTR;
+	hut = DIV_ROUND_UP(DP->hut * scale_dtr / 16, NOMINAL_DTR);
 	if (hut < 0x1)
 		hut = 0x1;
 	else if (hut > 0xf)
@@ -2236,9 +2243,9 @@
 			}
 		}
 	}
-	if (_floppy->stretch & FD_ZEROBASED) {
+	if (_floppy->stretch & FD_SECTBASEMASK) {
 		for (count = 0; count < F_SECT_PER_TRACK; count++)
-			here[count].sect--;
+			here[count].sect += FD_SECTBASE(_floppy) - 1;
 	}
 }
 
@@ -2385,7 +2392,7 @@
 
 #ifdef FLOPPY_SANITY_CHECK
 	if (nr_sectors / ssize >
-	    (in_sector_offset + current_count_sectors + ssize - 1) / ssize) {
+	    DIV_ROUND_UP(in_sector_offset + current_count_sectors, ssize)) {
 		DPRINT("long rw: %x instead of %lx\n",
 		       nr_sectors, current_count_sectors);
 		printk("rs=%d s=%d\n", R_SECTOR, SECTOR);
@@ -2649,7 +2656,7 @@
 	}
 	HEAD = fsector_t / _floppy->sect;
 
-	if (((_floppy->stretch & (FD_SWAPSIDES | FD_ZEROBASED)) ||
+	if (((_floppy->stretch & (FD_SWAPSIDES | FD_SECTBASEMASK)) ||
 	     TESTF(FD_NEED_TWADDLE)) && fsector_t < _floppy->sect)
 		max_sector = _floppy->sect;
 
@@ -2679,7 +2686,7 @@
 	CODE2SIZE;
 	SECT_PER_TRACK = _floppy->sect << 2 >> SIZECODE;
 	SECTOR = ((fsector_t % _floppy->sect) << 2 >> SIZECODE) +
-	    ((_floppy->stretch & FD_ZEROBASED) ? 0 : 1);
+	    FD_SECTBASE(_floppy);
 
 	/* tracksize describes the size which can be filled up with sectors
 	 * of size ssize.
@@ -3311,7 +3318,7 @@
 	    g->head <= 0 ||
 	    g->track <= 0 || g->track > UDP->tracks >> STRETCH(g) ||
 	    /* check if reserved bits are set */
-	    (g->stretch & ~(FD_STRETCH | FD_SWAPSIDES | FD_ZEROBASED)) != 0)
+	    (g->stretch & ~(FD_STRETCH | FD_SWAPSIDES | FD_SECTBASEMASK)) != 0)
 		return -EINVAL;
 	if (type) {
 		if (!capable(CAP_SYS_ADMIN))
@@ -3356,7 +3363,7 @@
 		if (DRS->maxblock > user_params[drive].sect ||
 		    DRS->maxtrack ||
 		    ((user_params[drive].sect ^ oldStretch) &
-		     (FD_SWAPSIDES | FD_ZEROBASED)))
+		     (FD_SWAPSIDES | FD_SECTBASEMASK)))
 			invalidate_drive(bdev);
 		else
 			process_fd_request();
diff --git a/drivers/block/hd.c b/drivers/block/hd.c
index 682243b..482c0c4 100644
--- a/drivers/block/hd.c
+++ b/drivers/block/hd.c
@@ -39,6 +39,7 @@
 #include <linux/ioport.h>
 #include <linux/init.h>
 #include <linux/blkpg.h>
+#include <linux/ata.h>
 #include <linux/hdreg.h>
 
 #define REALLY_SLOW_IO
@@ -370,7 +371,7 @@
 		struct hd_i_struct *disk = &hd_info[i];
 		disk->special_op = disk->recalibrate = 1;
 		hd_out(disk, disk->sect, disk->sect, disk->head-1,
-			disk->cyl, WIN_SPECIFY, &reset_hd);
+			disk->cyl, ATA_CMD_INIT_DEV_PARAMS, &reset_hd);
 		if (reset)
 			goto repeat;
 	} else
@@ -558,7 +559,7 @@
 {
 	if (disk->recalibrate) {
 		disk->recalibrate = 0;
-		hd_out(disk, disk->sect, 0, 0, 0, WIN_RESTORE, &recal_intr);
+		hd_out(disk, disk->sect, 0, 0, 0, ATA_CMD_RESTORE, &recal_intr);
 		return reset;
 	}
 	if (disk->head > 16) {
@@ -631,13 +632,13 @@
 	if (blk_fs_request(req)) {
 		switch (rq_data_dir(req)) {
 		case READ:
-			hd_out(disk, nsect, sec, head, cyl, WIN_READ,
+			hd_out(disk, nsect, sec, head, cyl, ATA_CMD_PIO_READ,
 				&read_intr);
 			if (reset)
 				goto repeat;
 			break;
 		case WRITE:
-			hd_out(disk, nsect, sec, head, cyl, WIN_WRITE,
+			hd_out(disk, nsect, sec, head, cyl, ATA_CMD_PIO_WRITE,
 				&write_intr);
 			if (reset)
 				goto repeat;
diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c
index 1778e4a..7b33512 100644
--- a/drivers/block/nbd.c
+++ b/drivers/block/nbd.c
@@ -403,7 +403,7 @@
 	BUG_ON(lo->magic != LO_MAGIC);
 
 	lo->pid = current->pid;
-	ret = sysfs_create_file(&lo->disk->dev.kobj, &pid_attr.attr);
+	ret = sysfs_create_file(&disk_to_dev(lo->disk)->kobj, &pid_attr.attr);
 	if (ret) {
 		printk(KERN_ERR "nbd: sysfs_create_file failed!");
 		return ret;
@@ -412,7 +412,7 @@
 	while ((req = nbd_read_stat(lo)) != NULL)
 		nbd_end_request(req);
 
-	sysfs_remove_file(&lo->disk->dev.kobj, &pid_attr.attr);
+	sysfs_remove_file(&disk_to_dev(lo->disk)->kobj, &pid_attr.attr);
 	return 0;
 }
 
diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c
index 29b7a64..0e07715 100644
--- a/drivers/block/pktcdvd.c
+++ b/drivers/block/pktcdvd.c
@@ -2544,7 +2544,7 @@
 		if (last_zone != zone) {
 			BUG_ON(last_zone != zone + pd->settings.size);
 			first_sectors = last_zone - bio->bi_sector;
-			bp = bio_split(bio, bio_split_pool, first_sectors);
+			bp = bio_split(bio, first_sectors);
 			BUG_ON(!bp);
 			pkt_make_request(q, &bp->bio1);
 			pkt_make_request(q, &bp->bio2);
@@ -2911,7 +2911,7 @@
 	if (!disk->queue)
 		goto out_mem2;
 
-	pd->pkt_dev = MKDEV(disk->major, disk->first_minor);
+	pd->pkt_dev = MKDEV(pktdev_major, idx);
 	ret = pkt_new_dev(pd, dev);
 	if (ret)
 		goto out_new_dev;
diff --git a/drivers/block/ps3disk.c b/drivers/block/ps3disk.c
index d797e20..936466f 100644
--- a/drivers/block/ps3disk.c
+++ b/drivers/block/ps3disk.c
@@ -199,7 +199,8 @@
 		if (blk_fs_request(req)) {
 			if (ps3disk_submit_request_sg(dev, req))
 				break;
-		} else if (req->cmd_type == REQ_TYPE_FLUSH) {
+		} else if (req->cmd_type == REQ_TYPE_LINUX_BLOCK &&
+			   req->cmd[0] == REQ_LB_OP_FLUSH) {
 			if (ps3disk_submit_flush_request(dev, req))
 				break;
 		} else {
@@ -257,7 +258,8 @@
 		return IRQ_HANDLED;
 	}
 
-	if (req->cmd_type == REQ_TYPE_FLUSH) {
+	if (req->cmd_type == REQ_TYPE_LINUX_BLOCK &&
+	    req->cmd[0] == REQ_LB_OP_FLUSH) {
 		read = 0;
 		num_sectors = req->hard_cur_sectors;
 		op = "flush";
@@ -405,7 +407,8 @@
 
 	dev_dbg(&dev->sbd.core, "%s:%u\n", __func__, __LINE__);
 
-	req->cmd_type = REQ_TYPE_FLUSH;
+	req->cmd_type = REQ_TYPE_LINUX_BLOCK;
+	req->cmd[0] = REQ_LB_OP_FLUSH;
 }
 
 static unsigned long ps3disk_mask;
@@ -538,7 +541,7 @@
 	struct ps3disk_private *priv = dev->sbd.core.driver_data;
 
 	mutex_lock(&ps3disk_mask_mutex);
-	__clear_bit(priv->gendisk->first_minor / PS3DISK_MINORS,
+	__clear_bit(MINOR(disk_devt(priv->gendisk)) / PS3DISK_MINORS,
 		    &ps3disk_mask);
 	mutex_unlock(&ps3disk_mask_mutex);
 	del_gendisk(priv->gendisk);
diff --git a/drivers/block/sunvdc.c b/drivers/block/sunvdc.c
index a8de037..953c0b8 100644
--- a/drivers/block/sunvdc.c
+++ b/drivers/block/sunvdc.c
@@ -1,6 +1,6 @@
 /* sunvdc.c: Sun LDOM Virtual Disk Client.
  *
- * Copyright (C) 2007 David S. Miller <davem@davemloft.net>
+ * Copyright (C) 2007, 2008 David S. Miller <davem@davemloft.net>
  */
 
 #include <linux/module.h>
@@ -834,7 +834,7 @@
 	return 0;
 }
 
-static struct vio_device_id vdc_port_match[] = {
+static const struct vio_device_id vdc_port_match[] = {
 	{
 		.type = "vdc-port",
 	},
diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c
index 4225109..6ec5fc0 100644
--- a/drivers/block/virtio_blk.c
+++ b/drivers/block/virtio_blk.c
@@ -47,20 +47,20 @@
 
 	spin_lock_irqsave(&vblk->lock, flags);
 	while ((vbr = vblk->vq->vq_ops->get_buf(vblk->vq, &len)) != NULL) {
-		int uptodate;
+		int error;
 		switch (vbr->status) {
 		case VIRTIO_BLK_S_OK:
-			uptodate = 1;
+			error = 0;
 			break;
 		case VIRTIO_BLK_S_UNSUPP:
-			uptodate = -ENOTTY;
+			error = -ENOTTY;
 			break;
 		default:
-			uptodate = 0;
+			error = -EIO;
 			break;
 		}
 
-		end_dequeued_request(vbr->req, uptodate);
+		__blk_end_request(vbr->req, error, blk_rq_bytes(vbr->req));
 		list_del(&vbr->list);
 		mempool_free(vbr, vblk->pool);
 	}
@@ -84,11 +84,11 @@
 	if (blk_fs_request(vbr->req)) {
 		vbr->out_hdr.type = 0;
 		vbr->out_hdr.sector = vbr->req->sector;
-		vbr->out_hdr.ioprio = vbr->req->ioprio;
+		vbr->out_hdr.ioprio = req_get_ioprio(vbr->req);
 	} else if (blk_pc_request(vbr->req)) {
 		vbr->out_hdr.type = VIRTIO_BLK_T_SCSI_CMD;
 		vbr->out_hdr.sector = 0;
-		vbr->out_hdr.ioprio = vbr->req->ioprio;
+		vbr->out_hdr.ioprio = req_get_ioprio(vbr->req);
 	} else {
 		/* We don't put anything else in the queue. */
 		BUG();
diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c
index 3ca643c..1a50ae7 100644
--- a/drivers/block/xen-blkfront.c
+++ b/drivers/block/xen-blkfront.c
@@ -105,15 +105,17 @@
 #define GRANT_INVALID_REF	0
 
 #define PARTS_PER_DISK		16
+#define PARTS_PER_EXT_DISK      256
 
 #define BLKIF_MAJOR(dev) ((dev)>>8)
 #define BLKIF_MINOR(dev) ((dev) & 0xff)
 
-#define DEV_NAME	"xvd"	/* name in /dev */
+#define EXT_SHIFT 28
+#define EXTENDED (1<<EXT_SHIFT)
+#define VDEV_IS_EXTENDED(dev) ((dev)&(EXTENDED))
+#define BLKIF_MINOR_EXT(dev) ((dev)&(~EXTENDED))
 
-/* Information about our VBDs. */
-#define MAX_VBDS 64
-static LIST_HEAD(vbds_list);
+#define DEV_NAME	"xvd"	/* name in /dev */
 
 static int get_id_from_freelist(struct blkfront_info *info)
 {
@@ -386,31 +388,60 @@
 }
 
 
-static int xlvbd_alloc_gendisk(int minor, blkif_sector_t capacity,
-			       int vdevice, u16 vdisk_info, u16 sector_size,
-			       struct blkfront_info *info)
+static int xlvbd_alloc_gendisk(blkif_sector_t capacity,
+			       struct blkfront_info *info,
+			       u16 vdisk_info, u16 sector_size)
 {
 	struct gendisk *gd;
 	int nr_minors = 1;
 	int err = -ENODEV;
+	unsigned int offset;
+	int minor;
+	int nr_parts;
 
 	BUG_ON(info->gd != NULL);
 	BUG_ON(info->rq != NULL);
 
-	if ((minor % PARTS_PER_DISK) == 0)
-		nr_minors = PARTS_PER_DISK;
+	if ((info->vdevice>>EXT_SHIFT) > 1) {
+		/* this is above the extended range; something is wrong */
+		printk(KERN_WARNING "blkfront: vdevice 0x%x is above the extended range; ignoring\n", info->vdevice);
+		return -ENODEV;
+	}
+
+	if (!VDEV_IS_EXTENDED(info->vdevice)) {
+		minor = BLKIF_MINOR(info->vdevice);
+		nr_parts = PARTS_PER_DISK;
+	} else {
+		minor = BLKIF_MINOR_EXT(info->vdevice);
+		nr_parts = PARTS_PER_EXT_DISK;
+	}
+
+	if ((minor % nr_parts) == 0)
+		nr_minors = nr_parts;
 
 	gd = alloc_disk(nr_minors);
 	if (gd == NULL)
 		goto out;
 
-	if (nr_minors > 1)
-		sprintf(gd->disk_name, "%s%c", DEV_NAME,
-			'a' + minor / PARTS_PER_DISK);
-	else
-		sprintf(gd->disk_name, "%s%c%d", DEV_NAME,
-			'a' + minor / PARTS_PER_DISK,
-			minor % PARTS_PER_DISK);
+	offset = minor / nr_parts;
+
+	if (nr_minors > 1) {
+		if (offset < 26)
+			sprintf(gd->disk_name, "%s%c", DEV_NAME, 'a' + offset);
+		else
+			sprintf(gd->disk_name, "%s%c%c", DEV_NAME,
+				'a' + ((offset / 26)-1), 'a' + (offset % 26));
+	} else {
+		if (offset < 26)
+			sprintf(gd->disk_name, "%s%c%d", DEV_NAME,
+				'a' + offset,
+				minor & (nr_parts - 1));
+		else
+			sprintf(gd->disk_name, "%s%c%c%d", DEV_NAME,
+				'a' + ((offset / 26) - 1),
+				'a' + (offset % 26),
+				minor & (nr_parts - 1));
+	}
 
 	gd->major = XENVBD_MAJOR;
 	gd->first_minor = minor;
@@ -699,8 +730,13 @@
 	err = xenbus_scanf(XBT_NIL, dev->nodename,
 			   "virtual-device", "%i", &vdevice);
 	if (err != 1) {
-		xenbus_dev_fatal(dev, err, "reading virtual-device");
-		return err;
+		/* go looking in the extended area instead */
+		err = xenbus_scanf(XBT_NIL, dev->nodename, "virtual-device-ext",
+				   "%i", &vdevice);
+		if (err != 1) {
+			xenbus_dev_fatal(dev, err, "reading virtual-device");
+			return err;
+		}
 	}
 
 	info = kzalloc(sizeof(*info), GFP_KERNEL);
@@ -861,9 +897,7 @@
 	if (err)
 		info->feature_barrier = 0;
 
-	err = xlvbd_alloc_gendisk(BLKIF_MINOR(info->vdevice),
-				  sectors, info->vdevice,
-				  binfo, sector_size, info);
+	err = xlvbd_alloc_gendisk(sectors, info, binfo, sector_size);
 	if (err) {
 		xenbus_dev_fatal(info->xbdev, err, "xlvbd_add at %s",
 				 info->xbdev->otherend);
@@ -1032,7 +1066,7 @@
 
 static int __init xlblk_init(void)
 {
-	if (!is_running_on_xen())
+	if (!xen_domain())
 		return -ENODEV;
 
 	if (register_blkdev(XENVBD_MAJOR, DEV_NAME)) {
diff --git a/drivers/bluetooth/bluecard_cs.c b/drivers/bluetooth/bluecard_cs.c
index bcf5792..e6ee21d 100644
--- a/drivers/bluetooth/bluecard_cs.c
+++ b/drivers/bluetooth/bluecard_cs.c
@@ -901,23 +901,23 @@
 	for (n = 0; n < 0x400; n += 0x40) {
 		link->io.BasePort1 = n ^ 0x300;
 		i = pcmcia_request_io(link, &link->io);
-		if (i == CS_SUCCESS)
+		if (i == 0)
 			break;
 	}
 
-	if (i != CS_SUCCESS) {
+	if (i != 0) {
 		cs_error(link, RequestIO, i);
 		goto failed;
 	}
 
 	i = pcmcia_request_irq(link, &link->irq);
-	if (i != CS_SUCCESS) {
+	if (i != 0) {
 		cs_error(link, RequestIRQ, i);
 		link->irq.AssignedIRQ = 0;
 	}
 
 	i = pcmcia_request_configuration(link, &link->conf);
-	if (i != CS_SUCCESS) {
+	if (i != 0) {
 		cs_error(link, RequestConfiguration, i);
 		goto failed;
 	}
diff --git a/drivers/bluetooth/bpa10x.c b/drivers/bluetooth/bpa10x.c
index 1e55a65..32f3a8e 100644
--- a/drivers/bluetooth/bpa10x.c
+++ b/drivers/bluetooth/bpa10x.c
@@ -256,7 +256,6 @@
 		BT_ERR("%s urb %p submission failed (%d)",
 						hdev->name, urb, -err);
 		usb_unanchor_urb(urb);
-		kfree(buf);
 	}
 
 	usb_free_urb(urb);
@@ -298,7 +297,6 @@
 		BT_ERR("%s urb %p submission failed (%d)",
 						hdev->name, urb, -err);
 		usb_unanchor_urb(urb);
-		kfree(buf);
 	}
 
 	usb_free_urb(urb);
diff --git a/drivers/bluetooth/bt3c_cs.c b/drivers/bluetooth/bt3c_cs.c
index 2705847..2cbe70b 100644
--- a/drivers/bluetooth/bt3c_cs.c
+++ b/drivers/bluetooth/bt3c_cs.c
@@ -678,101 +678,78 @@
 	kfree(info);
 }
 
-static int get_tuple(struct pcmcia_device *handle, tuple_t *tuple, cisparse_t *parse)
+static int bt3c_check_config(struct pcmcia_device *p_dev,
+			     cistpl_cftable_entry_t *cf,
+			     cistpl_cftable_entry_t *dflt,
+			     unsigned int vcc,
+			     void *priv_data)
 {
-	int i;
+	unsigned long try = (unsigned long) priv_data;
 
-	i = pcmcia_get_tuple_data(handle, tuple);
-	if (i != CS_SUCCESS)
-		return i;
-
-	return pcmcia_parse_tuple(handle, tuple, parse);
+	if (cf->vpp1.present & (1 << CISTPL_POWER_VNOM))
+		p_dev->conf.Vpp = cf->vpp1.param[CISTPL_POWER_VNOM] / 10000;
+	if ((cf->io.nwin > 0) && (cf->io.win[0].len == 8) &&
+	    (cf->io.win[0].base != 0)) {
+		p_dev->io.BasePort1 = cf->io.win[0].base;
+		p_dev->io.IOAddrLines = (try == 0) ? 16 :
+			cf->io.flags & CISTPL_IO_LINES_MASK;
+		if (!pcmcia_request_io(p_dev, &p_dev->io))
+			return 0;
+	}
+	return -ENODEV;
 }
 
-static int first_tuple(struct pcmcia_device *handle, tuple_t *tuple, cisparse_t *parse)
+static int bt3c_check_config_notpicky(struct pcmcia_device *p_dev,
+				      cistpl_cftable_entry_t *cf,
+				      cistpl_cftable_entry_t *dflt,
+				      unsigned int vcc,
+				      void *priv_data)
 {
-	if (pcmcia_get_first_tuple(handle, tuple) != CS_SUCCESS)
-		return CS_NO_MORE_ITEMS;
-	return get_tuple(handle, tuple, parse);
-}
+	static unsigned int base[5] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x0 };
+	int j;
 
-static int next_tuple(struct pcmcia_device *handle, tuple_t *tuple, cisparse_t *parse)
-{
-	if (pcmcia_get_next_tuple(handle, tuple) != CS_SUCCESS)
-		return CS_NO_MORE_ITEMS;
-	return get_tuple(handle, tuple, parse);
+	if ((cf->io.nwin > 0) && ((cf->io.flags & CISTPL_IO_LINES_MASK) <= 3)) {
+		for (j = 0; j < 5; j++) {
+			p_dev->io.BasePort1 = base[j];
+			p_dev->io.IOAddrLines = base[j] ? 16 : 3;
+			if (!pcmcia_request_io(p_dev, &p_dev->io))
+				return 0;
+		}
+	}
+	return -ENODEV;
 }
 
 static int bt3c_config(struct pcmcia_device *link)
 {
-	static unsigned int base[5] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x0 };
 	bt3c_info_t *info = link->priv;
-	tuple_t tuple;
-	u_short buf[256];
-	cisparse_t parse;
-	cistpl_cftable_entry_t *cf = &parse.cftable_entry;
-	int i, j, try;
+	int i;
+	unsigned long try;
 
-	/* First pass: look for a config entry that looks normal. */
-	tuple.TupleData = (cisdata_t *)buf;
-	tuple.TupleOffset = 0;
-	tuple.TupleDataMax = 255;
-	tuple.Attributes = 0;
-	tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
-	/* Two tries: without IO aliases, then with aliases */
-	for (try = 0; try < 2; try++) {
-		i = first_tuple(link, &tuple, &parse);
-		while (i != CS_NO_MORE_ITEMS) {
-			if (i != CS_SUCCESS)
-				goto next_entry;
-			if (cf->vpp1.present & (1 << CISTPL_POWER_VNOM))
-				link->conf.Vpp = cf->vpp1.param[CISTPL_POWER_VNOM] / 10000;
-			if ((cf->io.nwin > 0) && (cf->io.win[0].len == 8) && (cf->io.win[0].base != 0)) {
-				link->conf.ConfigIndex = cf->index;
-				link->io.BasePort1 = cf->io.win[0].base;
-				link->io.IOAddrLines = (try == 0) ? 16 : cf->io.flags & CISTPL_IO_LINES_MASK;
-				i = pcmcia_request_io(link, &link->io);
-				if (i == CS_SUCCESS)
-					goto found_port;
-			}
-next_entry:
-			i = next_tuple(link, &tuple, &parse);
-		}
-	}
+	/* First pass: look for a config entry that looks normal.
+	   Two tries: without IO aliases, then with aliases */
+	for (try = 0; try < 2; try++)
+		if (!pcmcia_loop_config(link, bt3c_check_config, (void *) try))
+			goto found_port;
 
 	/* Second pass: try to find an entry that isn't picky about
 	   its base address, then try to grab any standard serial port
 	   address, and finally try to get any free port. */
-	i = first_tuple(link, &tuple, &parse);
-	while (i != CS_NO_MORE_ITEMS) {
-		if ((i == CS_SUCCESS) && (cf->io.nwin > 0) && ((cf->io.flags & CISTPL_IO_LINES_MASK) <= 3)) {
-			link->conf.ConfigIndex = cf->index;
-			for (j = 0; j < 5; j++) {
-				link->io.BasePort1 = base[j];
-				link->io.IOAddrLines = base[j] ? 16 : 3;
-				i = pcmcia_request_io(link, &link->io);
-				if (i == CS_SUCCESS)
-					goto found_port;
-			}
-		}
-		i = next_tuple(link, &tuple, &parse);
-	}
+	if (!pcmcia_loop_config(link, bt3c_check_config_notpicky, NULL))
+		goto found_port;
+
+	BT_ERR("No usable port range found");
+	cs_error(link, RequestIO, -ENODEV);
+	goto failed;
 
 found_port:
-	if (i != CS_SUCCESS) {
-		BT_ERR("No usable port range found");
-		cs_error(link, RequestIO, i);
-		goto failed;
-	}
-
 	i = pcmcia_request_irq(link, &link->irq);
-	if (i != CS_SUCCESS) {
+	if (i != 0) {
 		cs_error(link, RequestIRQ, i);
 		link->irq.AssignedIRQ = 0;
 	}
 
 	i = pcmcia_request_configuration(link, &link->conf);
-	if (i != CS_SUCCESS) {
+	if (i != 0) {
 		cs_error(link, RequestConfiguration, i);
 		goto failed;
 	}
diff --git a/drivers/bluetooth/btuart_cs.c b/drivers/bluetooth/btuart_cs.c
index 68d1d25..8e556b7f 100644
--- a/drivers/bluetooth/btuart_cs.c
+++ b/drivers/bluetooth/btuart_cs.c
@@ -607,102 +607,78 @@
 	kfree(info);
 }
 
-static int get_tuple(struct pcmcia_device *handle, tuple_t *tuple, cisparse_t *parse)
+static int btuart_check_config(struct pcmcia_device *p_dev,
+			       cistpl_cftable_entry_t *cf,
+			       cistpl_cftable_entry_t *dflt,
+			       unsigned int vcc,
+			       void *priv_data)
 {
-	int i;
+	int *try = priv_data;
 
-	i = pcmcia_get_tuple_data(handle, tuple);
-	if (i != CS_SUCCESS)
-		return i;
-
-	return pcmcia_parse_tuple(handle, tuple, parse);
+	if (cf->vpp1.present & (1 << CISTPL_POWER_VNOM))
+		p_dev->conf.Vpp = cf->vpp1.param[CISTPL_POWER_VNOM] / 10000;
+	if ((cf->io.nwin > 0) && (cf->io.win[0].len == 8) &&
+	    (cf->io.win[0].base != 0)) {
+		p_dev->io.BasePort1 = cf->io.win[0].base;
+		p_dev->io.IOAddrLines = (*try == 0) ? 16 :
+			cf->io.flags & CISTPL_IO_LINES_MASK;
+		if (!pcmcia_request_io(p_dev, &p_dev->io))
+			return 0;
+	}
+	return -ENODEV;
 }
 
-static int first_tuple(struct pcmcia_device *handle, tuple_t *tuple, cisparse_t *parse)
+static int btuart_check_config_notpicky(struct pcmcia_device *p_dev,
+					cistpl_cftable_entry_t *cf,
+					cistpl_cftable_entry_t *dflt,
+					unsigned int vcc,
+					void *priv_data)
 {
-	if (pcmcia_get_first_tuple(handle, tuple) != CS_SUCCESS)
-		return CS_NO_MORE_ITEMS;
-	return get_tuple(handle, tuple, parse);
-}
+	static unsigned int base[5] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x0 };
+	int j;
 
-static int next_tuple(struct pcmcia_device *handle, tuple_t *tuple, cisparse_t *parse)
-{
-	if (pcmcia_get_next_tuple(handle, tuple) != CS_SUCCESS)
-		return CS_NO_MORE_ITEMS;
-	return get_tuple(handle, tuple, parse);
+	if ((cf->io.nwin > 0) && ((cf->io.flags & CISTPL_IO_LINES_MASK) <= 3)) {
+		for (j = 0; j < 5; j++) {
+			p_dev->io.BasePort1 = base[j];
+			p_dev->io.IOAddrLines = base[j] ? 16 : 3;
+			if (!pcmcia_request_io(p_dev, &p_dev->io))
+				return 0;
+		}
+	}
+	return -ENODEV;
 }
 
 static int btuart_config(struct pcmcia_device *link)
 {
-	static unsigned int base[5] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x0 };
 	btuart_info_t *info = link->priv;
-	tuple_t tuple;
-	u_short buf[256];
-	cisparse_t parse;
-	cistpl_cftable_entry_t *cf = &parse.cftable_entry;
-	int i, j, try;
+	int i;
+	int try;
 
-	/* First pass: look for a config entry that looks normal. */
-	tuple.TupleData = (cisdata_t *) buf;
-	tuple.TupleOffset = 0;
-	tuple.TupleDataMax = 255;
-	tuple.Attributes = 0;
-	tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
-	/* Two tries: without IO aliases, then with aliases */
-	for (try = 0; try < 2; try++) {
-		i = first_tuple(link, &tuple, &parse);
-		while (i != CS_NO_MORE_ITEMS) {
-			if (i != CS_SUCCESS)
-				goto next_entry;
-			if (cf->vpp1.present & (1 << CISTPL_POWER_VNOM))
-				link->conf.Vpp = cf->vpp1.param[CISTPL_POWER_VNOM] / 10000;
-			if ((cf->io.nwin > 0) && (cf->io.win[0].len == 8) && (cf->io.win[0].base != 0)) {
-				link->conf.ConfigIndex = cf->index;
-				link->io.BasePort1 = cf->io.win[0].base;
-				link->io.IOAddrLines = (try == 0) ? 16 : cf->io.flags & CISTPL_IO_LINES_MASK;
-				i = pcmcia_request_io(link, &link->io);
-				if (i == CS_SUCCESS)
-					goto found_port;
-			}
-next_entry:
-			i = next_tuple(link, &tuple, &parse);
-		}
-	}
+	/* First pass: look for a config entry that looks normal.
+	   Two tries: without IO aliases, then with aliases */
+	for (try = 0; try < 2; try++)
+		if (!pcmcia_loop_config(link, btuart_check_config, &try))
+			goto found_port;
 
 	/* Second pass: try to find an entry that isn't picky about
 	   its base address, then try to grab any standard serial port
 	   address, and finally try to get any free port. */
-	i = first_tuple(link, &tuple, &parse);
-	while (i != CS_NO_MORE_ITEMS) {
-		if ((i == CS_SUCCESS) && (cf->io.nwin > 0)
-		    && ((cf->io.flags & CISTPL_IO_LINES_MASK) <= 3)) {
-			link->conf.ConfigIndex = cf->index;
-			for (j = 0; j < 5; j++) {
-				link->io.BasePort1 = base[j];
-				link->io.IOAddrLines = base[j] ? 16 : 3;
-				i = pcmcia_request_io(link, &link->io);
-				if (i == CS_SUCCESS)
-					goto found_port;
-			}
-		}
-		i = next_tuple(link, &tuple, &parse);
-	}
+	if (!pcmcia_loop_config(link, btuart_check_config_notpicky, NULL))
+		goto found_port;
+
+	BT_ERR("No usable port range found");
+	cs_error(link, RequestIO, -ENODEV);
+	goto failed;
 
 found_port:
-	if (i != CS_SUCCESS) {
-		BT_ERR("No usable port range found");
-		cs_error(link, RequestIO, i);
-		goto failed;
-	}
-
 	i = pcmcia_request_irq(link, &link->irq);
-	if (i != CS_SUCCESS) {
+	if (i != 0) {
 		cs_error(link, RequestIRQ, i);
 		link->irq.AssignedIRQ = 0;
 	}
 
 	i = pcmcia_request_configuration(link, &link->conf);
-	if (i != CS_SUCCESS) {
+	if (i != 0) {
 		cs_error(link, RequestConfiguration, i);
 		goto failed;
 	}
diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index 6a01068..af472e0 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -102,14 +102,19 @@
 	{ USB_DEVICE(0x0a5c, 0x2101), .driver_info = BTUSB_RESET | BTUSB_WRONG_SCO_MTU },
 
 	/* Broadcom BCM2046 */
+	{ USB_DEVICE(0x0a5c, 0x2146), .driver_info = BTUSB_RESET },
 	{ USB_DEVICE(0x0a5c, 0x2151), .driver_info = BTUSB_RESET },
 
+	/* Apple MacBook Pro with Broadcom chip */
+	{ USB_DEVICE(0x05ac, 0x820f), .driver_info = BTUSB_RESET },
+
 	/* IBM/Lenovo ThinkPad with Broadcom chip */
 	{ USB_DEVICE(0x0a5c, 0x201e), .driver_info = BTUSB_RESET | BTUSB_WRONG_SCO_MTU },
 	{ USB_DEVICE(0x0a5c, 0x2110), .driver_info = BTUSB_RESET | BTUSB_WRONG_SCO_MTU },
 
 	/* Targus ACB10US */
 	{ USB_DEVICE(0x0a5c, 0x2100), .driver_info = BTUSB_RESET },
+	{ USB_DEVICE(0x0a5c, 0x2154), .driver_info = BTUSB_RESET },
 
 	/* ANYCOM Bluetooth USB-200 and USB-250 */
 	{ USB_DEVICE(0x0a5c, 0x2111), .driver_info = BTUSB_RESET },
@@ -147,6 +152,9 @@
 	{ USB_DEVICE(0x050d, 0x0012), .driver_info = BTUSB_RESET | BTUSB_WRONG_SCO_MTU },
 	{ USB_DEVICE(0x050d, 0x0013), .driver_info = BTUSB_RESET | BTUSB_WRONG_SCO_MTU },
 
+	/* Belkin F8T016 device */
+	{ USB_DEVICE(0x050d, 0x016a), .driver_info = BTUSB_RESET },
+
 	/* Digianswer devices */
 	{ USB_DEVICE(0x08fd, 0x0001), .driver_info = BTUSB_DIGIANSWER },
 	{ USB_DEVICE(0x08fd, 0x0002), .driver_info = BTUSB_IGNORE },
@@ -169,6 +177,7 @@
 struct btusb_data {
 	struct hci_dev       *hdev;
 	struct usb_device    *udev;
+	struct usb_interface *intf;
 	struct usb_interface *isoc;
 
 	spinlock_t lock;
@@ -267,7 +276,6 @@
 		BT_ERR("%s urb %p submission failed (%d)",
 						hdev->name, urb, -err);
 		usb_unanchor_urb(urb);
-		kfree(buf);
 	}
 
 	usb_free_urb(urb);
@@ -350,7 +358,6 @@
 		BT_ERR("%s urb %p submission failed (%d)",
 						hdev->name, urb, -err);
 		usb_unanchor_urb(urb);
-		kfree(buf);
 	}
 
 	usb_free_urb(urb);
@@ -471,7 +478,6 @@
 		BT_ERR("%s urb %p submission failed (%d)",
 						hdev->name, urb, -err);
 		usb_unanchor_urb(urb);
-		kfree(buf);
 	}
 
 	usb_free_urb(urb);
@@ -516,7 +522,7 @@
 
 	err = btusb_submit_intr_urb(hdev);
 	if (err < 0) {
-		clear_bit(BTUSB_INTR_RUNNING, &hdev->flags);
+		clear_bit(BTUSB_INTR_RUNNING, &data->flags);
 		clear_bit(HCI_RUNNING, &hdev->flags);
 	}
 
@@ -532,8 +538,10 @@
 	if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags))
 		return 0;
 
+	cancel_work_sync(&data->work);
+
 	clear_bit(BTUSB_ISOC_RUNNING, &data->flags);
-	usb_kill_anchored_urbs(&data->intr_anchor);
+	usb_kill_anchored_urbs(&data->isoc_anchor);
 
 	clear_bit(BTUSB_BULK_RUNNING, &data->flags);
 	usb_kill_anchored_urbs(&data->bulk_anchor);
@@ -821,6 +829,7 @@
 	}
 
 	data->udev = interface_to_usbdev(intf);
+	data->intf = intf;
 
 	spin_lock_init(&data->lock);
 
@@ -889,7 +898,7 @@
 
 	if (data->isoc) {
 		err = usb_driver_claim_interface(&btusb_driver,
-							data->isoc, NULL);
+							data->isoc, data);
 		if (err < 0) {
 			hci_free_dev(hdev);
 			kfree(data);
@@ -921,13 +930,22 @@
 
 	hdev = data->hdev;
 
-	if (data->isoc)
-		usb_driver_release_interface(&btusb_driver, data->isoc);
+	__hci_dev_hold(hdev);
 
-	usb_set_intfdata(intf, NULL);
+	usb_set_intfdata(data->intf, NULL);
+
+	if (data->isoc)
+		usb_set_intfdata(data->isoc, NULL);
 
 	hci_unregister_dev(hdev);
 
+	if (intf == data->isoc)
+		usb_driver_release_interface(&btusb_driver, data->intf);
+	else if (data->isoc)
+		usb_driver_release_interface(&btusb_driver, data->isoc);
+
+	__hci_dev_put(hdev);
+
 	hci_free_dev(hdev);
 }
 
diff --git a/drivers/bluetooth/dtl1_cs.c b/drivers/bluetooth/dtl1_cs.c
index dae45cdf..e6e6b03 100644
--- a/drivers/bluetooth/dtl1_cs.c
+++ b/drivers/bluetooth/dtl1_cs.c
@@ -590,75 +590,40 @@
 	kfree(info);
 }
 
-static int get_tuple(struct pcmcia_device *handle, tuple_t *tuple, cisparse_t *parse)
+static int dtl1_confcheck(struct pcmcia_device *p_dev,
+			  cistpl_cftable_entry_t *cf,
+			  cistpl_cftable_entry_t *dflt,
+			  unsigned int vcc,
+			  void *priv_data)
 {
-	int i;
-
-	i = pcmcia_get_tuple_data(handle, tuple);
-	if (i != CS_SUCCESS)
-		return i;
-
-	return pcmcia_parse_tuple(handle, tuple, parse);
-}
-
-static int first_tuple(struct pcmcia_device *handle, tuple_t *tuple, cisparse_t *parse)
-{
-	if (pcmcia_get_first_tuple(handle, tuple) != CS_SUCCESS)
-		return CS_NO_MORE_ITEMS;
-	return get_tuple(handle, tuple, parse);
-}
-
-static int next_tuple(struct pcmcia_device *handle, tuple_t *tuple, cisparse_t *parse)
-{
-	if (pcmcia_get_next_tuple(handle, tuple) != CS_SUCCESS)
-		return CS_NO_MORE_ITEMS;
-	return get_tuple(handle, tuple, parse);
+	if ((cf->io.nwin == 1) && (cf->io.win[0].len > 8)) {
+		p_dev->io.BasePort1 = cf->io.win[0].base;
+		p_dev->io.NumPorts1 = cf->io.win[0].len;	/*yo */
+		p_dev->io.IOAddrLines = cf->io.flags & CISTPL_IO_LINES_MASK;
+		if (!pcmcia_request_io(p_dev, &p_dev->io))
+			return 0;
+	}
+	return -ENODEV;
 }
 
 static int dtl1_config(struct pcmcia_device *link)
 {
 	dtl1_info_t *info = link->priv;
-	tuple_t tuple;
-	u_short buf[256];
-	cisparse_t parse;
-	cistpl_cftable_entry_t *cf = &parse.cftable_entry;
 	int i;
 
-	tuple.TupleData = (cisdata_t *)buf;
-	tuple.TupleOffset = 0;
-	tuple.TupleDataMax = 255;
-	tuple.Attributes = 0;
-	tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
-
 	/* Look for a generic full-sized window */
 	link->io.NumPorts1 = 8;
-	i = first_tuple(link, &tuple, &parse);
-	while (i != CS_NO_MORE_ITEMS) {
-		if ((i == CS_SUCCESS) && (cf->io.nwin == 1) && (cf->io.win[0].len > 8)) {
-			link->conf.ConfigIndex = cf->index;
-			link->io.BasePort1 = cf->io.win[0].base;
-			link->io.NumPorts1 = cf->io.win[0].len;	/*yo */
-			link->io.IOAddrLines = cf->io.flags & CISTPL_IO_LINES_MASK;
-			i = pcmcia_request_io(link, &link->io);
-			if (i == CS_SUCCESS)
-				break;
-		}
-		i = next_tuple(link, &tuple, &parse);
-	}
-
-	if (i != CS_SUCCESS) {
-		cs_error(link, RequestIO, i);
+	if (!pcmcia_loop_config(link, dtl1_confcheck, NULL))
 		goto failed;
-	}
 
 	i = pcmcia_request_irq(link, &link->irq);
-	if (i != CS_SUCCESS) {
+	if (i != 0) {
 		cs_error(link, RequestIRQ, i);
 		link->irq.AssignedIRQ = 0;
 	}
 
 	i = pcmcia_request_configuration(link, &link->conf);
-	if (i != CS_SUCCESS) {
+	if (i != 0) {
 		cs_error(link, RequestConfiguration, i);
 		goto failed;
 	}
diff --git a/drivers/bluetooth/hci_bcsp.c b/drivers/bluetooth/hci_bcsp.c
index 4d37bb3..7938062 100644
--- a/drivers/bluetooth/hci_bcsp.c
+++ b/drivers/bluetooth/hci_bcsp.c
@@ -352,14 +352,14 @@
 /* Remove ack'ed packets */
 static void bcsp_pkt_cull(struct bcsp_struct *bcsp)
 {
+	struct sk_buff *skb, *tmp;
 	unsigned long flags;
-	struct sk_buff *skb;
 	int i, pkts_to_be_removed;
 	u8 seqno;
 
 	spin_lock_irqsave(&bcsp->unack.lock, flags);
 
-	pkts_to_be_removed = bcsp->unack.qlen;
+	pkts_to_be_removed = skb_queue_len(&bcsp->unack);
 	seqno = bcsp->msgq_txseq;
 
 	while (pkts_to_be_removed) {
@@ -373,19 +373,19 @@
 		BT_ERR("Peer acked invalid packet");
 
 	BT_DBG("Removing %u pkts out of %u, up to seqno %u",
-		pkts_to_be_removed, bcsp->unack.qlen, (seqno - 1) & 0x07);
+	       pkts_to_be_removed, skb_queue_len(&bcsp->unack),
+	       (seqno - 1) & 0x07);
 
-	for (i = 0, skb = ((struct sk_buff *) &bcsp->unack)->next; i < pkts_to_be_removed
-			&& skb != (struct sk_buff *) &bcsp->unack; i++) {
-		struct sk_buff *nskb;
+	i = 0;
+	skb_queue_walk_safe(&bcsp->unack, skb, tmp) {
+		if (i++ >= pkts_to_be_removed)
+			break;
 
-		nskb = skb->next;
 		__skb_unlink(skb, &bcsp->unack);
 		kfree_skb(skb);
-		skb = nskb;
 	}
 
-	if (bcsp->unack.qlen == 0)
+	if (skb_queue_empty(&bcsp->unack))
 		del_timer(&bcsp->tbcsp);
 
 	spin_unlock_irqrestore(&bcsp->unack.lock, flags);
diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c
index 8dfcf77..4426bb5 100644
--- a/drivers/bluetooth/hci_ldisc.c
+++ b/drivers/bluetooth/hci_ldisc.c
@@ -484,7 +484,7 @@
 		return -EUNATCH;
 
 	default:
-		err = n_tty_ioctl(tty, file, cmd, arg);
+		err = n_tty_ioctl_helper(tty, file, cmd, arg);
 		break;
 	};
 
diff --git a/drivers/bluetooth/hci_usb.h b/drivers/bluetooth/hci_usb.h
index 1790cc8..8e65991 100644
--- a/drivers/bluetooth/hci_usb.h
+++ b/drivers/bluetooth/hci_usb.h
@@ -70,8 +70,8 @@
 {
 	unsigned long flags;
 	spin_lock_irqsave(&q->lock, flags);
-	/* _urb_unlink needs to know which spinlock to use, thus mb(). */
-	_urb->queue = q; mb(); list_add(&_urb->list, &q->head);
+	/* _urb_unlink needs to know which spinlock to use, thus smp_mb(). */
+	_urb->queue = q; smp_mb(); list_add(&_urb->list, &q->head);
 	spin_unlock_irqrestore(&q->lock, flags);
 }
 
@@ -79,8 +79,8 @@
 {
 	unsigned long flags;
 	spin_lock_irqsave(&q->lock, flags);
-	/* _urb_unlink needs to know which spinlock to use, thus mb(). */
-	_urb->queue = q; mb(); list_add_tail(&_urb->list, &q->head);
+	/* _urb_unlink needs to know which spinlock to use, thus smp_mb(). */
+	_urb->queue = q; smp_mb(); list_add_tail(&_urb->list, &q->head);
 	spin_unlock_irqrestore(&q->lock, flags);
 }
 
@@ -89,7 +89,7 @@
 	struct _urb_queue *q;
 	unsigned long flags;
 
-	mb();
+	smp_mb();
 	q = _urb->queue;
 	/* If q is NULL, it will die at easy-to-debug NULL pointer dereference.
 	   No need to BUG(). */
diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c
index 74031de..d47f2f8 100644
--- a/drivers/cdrom/cdrom.c
+++ b/drivers/cdrom/cdrom.c
@@ -2097,7 +2097,7 @@
 
 		len = nr * CD_FRAMESIZE_RAW;
 
-		ret = blk_rq_map_user(q, rq, ubuf, len);
+		ret = blk_rq_map_user(q, rq, NULL, ubuf, len, GFP_KERNEL);
 		if (ret)
 			break;
 
diff --git a/drivers/cdrom/gdrom.c b/drivers/cdrom/gdrom.c
index 1231d95..d6ba77a 100644
--- a/drivers/cdrom/gdrom.c
+++ b/drivers/cdrom/gdrom.c
@@ -624,14 +624,14 @@
 		ctrl_outb(1, GDROM_DMA_STATUS_REG);
 		wait_event_interruptible_timeout(request_queue,
 			gd.transfer == 0, GDROM_DEFAULT_TIMEOUT);
-		err = gd.transfer;
+		err = gd.transfer ? -EIO : 0;
 		gd.transfer = 0;
 		gd.pending = 0;
 		/* now seek to take the request spinlock
 		* before handling ending the request */
 		spin_lock(&gdrom_lock);
 		list_del_init(&req->queuelist);
-		end_dequeued_request(req, 1 - err);
+		__blk_end_request(req, err, blk_rq_bytes(req));
 	}
 	spin_unlock(&gdrom_lock);
 	kfree(read_command);
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index caff851..700ff96 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -350,7 +350,7 @@
 
 config STALLION
 	tristate "Stallion EasyIO or EC8/32 support"
-	depends on STALDRV && BROKEN_ON_SMP && (ISA || EISA || PCI)
+	depends on STALDRV && (ISA || EISA || PCI)
 	help
 	  If you have an EasyIO or EasyConnection 8/32 multiport Stallion
 	  card, then this is for you; say Y.  Make sure to read
@@ -361,7 +361,7 @@
 
 config ISTALLION
 	tristate "Stallion EC8/64, ONboard, Brumby support"
-	depends on STALDRV && BROKEN_ON_SMP && (ISA || EISA || PCI)
+	depends on STALDRV && (ISA || EISA || PCI)
 	help
 	  If you have an EasyConnection 8/64, ONboard, Brumby or Stallion
 	  serial multiport card, say Y here. Make sure to read
diff --git a/drivers/char/Makefile b/drivers/char/Makefile
index 6850f6d..1a4247d 100644
--- a/drivers/char/Makefile
+++ b/drivers/char/Makefile
@@ -7,7 +7,7 @@
 #
 FONTMAPFILE = cp437.uni
 
-obj-y	 += mem.o random.o tty_io.o n_tty.o tty_ioctl.o tty_ldisc.o 
+obj-y	 += mem.o random.o tty_io.o n_tty.o tty_ioctl.o tty_ldisc.o tty_buffer.o tty_port.o
 
 obj-$(CONFIG_LEGACY_PTYS)	+= pty.o
 obj-$(CONFIG_UNIX98_PTYS)	+= pty.o
diff --git a/drivers/char/agp/agp.h b/drivers/char/agp/agp.h
index 4bada0e..46f5075 100644
--- a/drivers/char/agp/agp.h
+++ b/drivers/char/agp/agp.h
@@ -116,7 +116,9 @@
 	struct agp_memory *(*alloc_by_type) (size_t, int);
 	void (*free_by_type)(struct agp_memory *);
 	void *(*agp_alloc_page)(struct agp_bridge_data *);
+	int (*agp_alloc_pages)(struct agp_bridge_data *, struct agp_memory *, size_t);
 	void (*agp_destroy_page)(void *, int flags);
+	void (*agp_destroy_pages)(struct agp_memory *);
 	int (*agp_type_to_mask_type) (struct agp_bridge_data *, int);
 	void (*chipset_flush)(struct agp_bridge_data *);
 };
@@ -277,7 +279,10 @@
 struct agp_memory *agp_generic_alloc_by_type(size_t page_count, int type);
 void agp_generic_free_by_type(struct agp_memory *curr);
 void *agp_generic_alloc_page(struct agp_bridge_data *bridge);
+int agp_generic_alloc_pages(struct agp_bridge_data *agp_bridge,
+			    struct agp_memory *memory, size_t page_count);
 void agp_generic_destroy_page(void *addr, int flags);
+void agp_generic_destroy_pages(struct agp_memory *memory);
 void agp_free_key(int key);
 int agp_num_entries(void);
 u32 agp_collect_device_status(struct agp_bridge_data *bridge, u32 mode, u32 command);
diff --git a/drivers/char/agp/alpha-agp.c b/drivers/char/agp/alpha-agp.c
index 5da89f6..5ea4da8 100644
--- a/drivers/char/agp/alpha-agp.c
+++ b/drivers/char/agp/alpha-agp.c
@@ -143,7 +143,9 @@
 	.alloc_by_type		= agp_generic_alloc_by_type,
 	.free_by_type		= agp_generic_free_by_type,
 	.agp_alloc_page		= agp_generic_alloc_page,
+	.agp_alloc_pages	= agp_generic_alloc_pages,
 	.agp_destroy_page	= agp_generic_destroy_page,
+	.agp_destroy_pages	= agp_generic_destroy_pages,
 	.agp_type_to_mask_type  = agp_generic_type_to_mask_type,
 };
 
diff --git a/drivers/char/agp/amd-k7-agp.c b/drivers/char/agp/amd-k7-agp.c
index e280531..603a986 100644
--- a/drivers/char/agp/amd-k7-agp.c
+++ b/drivers/char/agp/amd-k7-agp.c
@@ -386,7 +386,9 @@
 	.alloc_by_type		= agp_generic_alloc_by_type,
 	.free_by_type		= agp_generic_free_by_type,
 	.agp_alloc_page		= agp_generic_alloc_page,
+	.agp_alloc_pages	= agp_generic_alloc_pages,
 	.agp_destroy_page	= agp_generic_destroy_page,
+	.agp_destroy_pages	= agp_generic_destroy_pages,
 	.agp_type_to_mask_type  = agp_generic_type_to_mask_type,
 };
 
diff --git a/drivers/char/agp/amd64-agp.c b/drivers/char/agp/amd64-agp.c
index 7495c52..2812ee2 100644
--- a/drivers/char/agp/amd64-agp.c
+++ b/drivers/char/agp/amd64-agp.c
@@ -224,7 +224,9 @@
 	.alloc_by_type		= agp_generic_alloc_by_type,
 	.free_by_type		= agp_generic_free_by_type,
 	.agp_alloc_page		= agp_generic_alloc_page,
+	.agp_alloc_pages	= agp_generic_alloc_pages,
 	.agp_destroy_page	= agp_generic_destroy_page,
+	.agp_destroy_pages	= agp_generic_destroy_pages,
 	.agp_type_to_mask_type  = agp_generic_type_to_mask_type,
 };
 
diff --git a/drivers/char/agp/ati-agp.c b/drivers/char/agp/ati-agp.c
index 6ecbcaf..ae2791b 100644
--- a/drivers/char/agp/ati-agp.c
+++ b/drivers/char/agp/ati-agp.c
@@ -418,7 +418,9 @@
 	.alloc_by_type		= agp_generic_alloc_by_type,
 	.free_by_type		= agp_generic_free_by_type,
 	.agp_alloc_page		= agp_generic_alloc_page,
+	.agp_alloc_pages	= agp_generic_alloc_pages,
 	.agp_destroy_page	= agp_generic_destroy_page,
+	.agp_destroy_pages	= agp_generic_destroy_pages,
 	.agp_type_to_mask_type  = agp_generic_type_to_mask_type,
 };
 
diff --git a/drivers/char/agp/efficeon-agp.c b/drivers/char/agp/efficeon-agp.c
index 8ca6f26..453543a 100644
--- a/drivers/char/agp/efficeon-agp.c
+++ b/drivers/char/agp/efficeon-agp.c
@@ -335,7 +335,9 @@
 	.alloc_by_type		= agp_generic_alloc_by_type,
 	.free_by_type		= agp_generic_free_by_type,
 	.agp_alloc_page		= agp_generic_alloc_page,
+	.agp_alloc_pages	= agp_generic_alloc_pages,
 	.agp_destroy_page	= agp_generic_destroy_page,
+	.agp_destroy_pages	= agp_generic_destroy_pages,
 	.agp_type_to_mask_type  = agp_generic_type_to_mask_type,
 };
 
diff --git a/drivers/char/agp/generic.c b/drivers/char/agp/generic.c
index 118dbde..10d6cbd 100644
--- a/drivers/char/agp/generic.c
+++ b/drivers/char/agp/generic.c
@@ -201,14 +201,22 @@
 		return;
 	}
 	if (curr->page_count != 0) {
-		for (i = 0; i < curr->page_count; i++) {
-			curr->memory[i] = (unsigned long)gart_to_virt(curr->memory[i]);
-			curr->bridge->driver->agp_destroy_page((void *)curr->memory[i],
-							       AGP_PAGE_DESTROY_UNMAP);
-		}
-		for (i = 0; i < curr->page_count; i++) {
-			curr->bridge->driver->agp_destroy_page((void *)curr->memory[i],
-							       AGP_PAGE_DESTROY_FREE);
+		if (curr->bridge->driver->agp_destroy_pages) {
+			curr->bridge->driver->agp_destroy_pages(curr);
+		} else {
+
+			for (i = 0; i < curr->page_count; i++) {
+				curr->memory[i] = (unsigned long)gart_to_virt(
+					curr->memory[i]);
+				curr->bridge->driver->agp_destroy_page(
+					(void *)curr->memory[i],
+					AGP_PAGE_DESTROY_UNMAP);
+			}
+			for (i = 0; i < curr->page_count; i++) {
+				curr->bridge->driver->agp_destroy_page(
+					(void *)curr->memory[i],
+					AGP_PAGE_DESTROY_FREE);
+			}
 		}
 	}
 	agp_free_key(curr->key);
@@ -264,6 +272,15 @@
 	if (new == NULL)
 		return NULL;
 
+	if (bridge->driver->agp_alloc_pages) {
+		if (bridge->driver->agp_alloc_pages(bridge, new, page_count)) {
+			agp_free_memory(new);
+			return NULL;
+		}
+		new->bridge = bridge;
+		return new;
+	}
+
 	for (i = 0; i < page_count; i++) {
 		void *addr = bridge->driver->agp_alloc_page(bridge);
 
@@ -1203,6 +1220,39 @@
  * against a maximum value.
  */
 
+int agp_generic_alloc_pages(struct agp_bridge_data *bridge, struct agp_memory *mem, size_t num_pages)
+{
+	struct page * page;
+	int i, ret = -ENOMEM;
+
+	for (i = 0; i < num_pages; i++) {
+		page = alloc_page(GFP_KERNEL | GFP_DMA32);
+		/* agp_free_memory() needs gart address */
+		if (page == NULL)
+			goto out;
+
+#ifndef CONFIG_X86
+		map_page_into_agp(page);
+#endif
+		get_page(page);
+		atomic_inc(&agp_bridge->current_memory_agp);
+
+		/* set_memory_array_uc() needs virtual address */
+		mem->memory[i] = (unsigned long)page_address(page);
+		mem->page_count++;
+	}
+
+#ifdef CONFIG_X86
+	set_memory_array_uc(mem->memory, num_pages);
+#endif
+	ret = 0;
+out:
+	for (i = 0; i < mem->page_count; i++)
+		mem->memory[i] = virt_to_gart((void *)mem->memory[i]);
+	return ret;
+}
+EXPORT_SYMBOL(agp_generic_alloc_pages);
+
 void *agp_generic_alloc_page(struct agp_bridge_data *bridge)
 {
 	struct page * page;
@@ -1219,6 +1269,37 @@
 }
 EXPORT_SYMBOL(agp_generic_alloc_page);
 
+void agp_generic_destroy_pages(struct agp_memory *mem)
+{
+	int i;
+	void *addr;
+	struct page *page;
+
+	if (!mem)
+		return;
+
+	for (i = 0; i < mem->page_count; i++)
+		mem->memory[i] = (unsigned long)gart_to_virt(mem->memory[i]);
+
+#ifdef CONFIG_X86
+	set_memory_array_wb(mem->memory, mem->page_count);
+#endif
+
+	for (i = 0; i < mem->page_count; i++) {
+		addr = (void *)mem->memory[i];
+		page = virt_to_page(addr);
+
+#ifndef CONFIG_X86
+		unmap_page_from_agp(page);
+#endif
+
+		put_page(page);
+		free_page((unsigned long)addr);
+		atomic_dec(&agp_bridge->current_memory_agp);
+		mem->memory[i] = 0;
+	}
+}
+EXPORT_SYMBOL(agp_generic_destroy_pages);
 
 void agp_generic_destroy_page(void *addr, int flags)
 {
diff --git a/drivers/char/agp/hp-agp.c b/drivers/char/agp/hp-agp.c
index 80d7317..183ac3f 100644
--- a/drivers/char/agp/hp-agp.c
+++ b/drivers/char/agp/hp-agp.c
@@ -435,7 +435,9 @@
 	.alloc_by_type		= agp_generic_alloc_by_type,
 	.free_by_type		= agp_generic_free_by_type,
 	.agp_alloc_page		= agp_generic_alloc_page,
+	.agp_alloc_pages	= agp_generic_alloc_pages,
 	.agp_destroy_page	= agp_generic_destroy_page,
+	.agp_destroy_pages	= agp_generic_destroy_pages,
 	.agp_type_to_mask_type  = agp_generic_type_to_mask_type,
 	.cant_use_aperture	= true,
 };
diff --git a/drivers/char/agp/i460-agp.c b/drivers/char/agp/i460-agp.c
index e587eeb..10da687 100644
--- a/drivers/char/agp/i460-agp.c
+++ b/drivers/char/agp/i460-agp.c
@@ -575,7 +575,9 @@
 	.insert_memory		= i460_insert_memory_small_io_page,
 	.remove_memory		= i460_remove_memory_small_io_page,
 	.agp_alloc_page		= agp_generic_alloc_page,
+	.agp_alloc_pages	= agp_generic_alloc_pages,
 	.agp_destroy_page	= agp_generic_destroy_page,
+	.agp_destroy_pages	= agp_generic_destroy_pages,
 #endif
 	.alloc_by_type		= agp_generic_alloc_by_type,
 	.free_by_type		= agp_generic_free_by_type,
diff --git a/drivers/char/agp/intel-agp.c b/drivers/char/agp/intel-agp.c
index 016fdf0..043e366 100644
--- a/drivers/char/agp/intel-agp.c
+++ b/drivers/char/agp/intel-agp.c
@@ -1711,7 +1711,9 @@
 	.alloc_by_type		= agp_generic_alloc_by_type,
 	.free_by_type		= agp_generic_free_by_type,
 	.agp_alloc_page		= agp_generic_alloc_page,
+	.agp_alloc_pages        = agp_generic_alloc_pages,
 	.agp_destroy_page	= agp_generic_destroy_page,
+	.agp_destroy_pages      = agp_generic_destroy_pages,
 	.agp_type_to_mask_type  = agp_generic_type_to_mask_type,
 };
 
@@ -1736,7 +1738,9 @@
 	.alloc_by_type		= intel_i810_alloc_by_type,
 	.free_by_type		= intel_i810_free_by_type,
 	.agp_alloc_page		= agp_generic_alloc_page,
+	.agp_alloc_pages        = agp_generic_alloc_pages,
 	.agp_destroy_page	= agp_generic_destroy_page,
+	.agp_destroy_pages      = agp_generic_destroy_pages,
 	.agp_type_to_mask_type  = agp_generic_type_to_mask_type,
 };
 
@@ -1760,7 +1764,9 @@
 	.alloc_by_type		= agp_generic_alloc_by_type,
 	.free_by_type		= agp_generic_free_by_type,
 	.agp_alloc_page		= agp_generic_alloc_page,
+	.agp_alloc_pages        = agp_generic_alloc_pages,
 	.agp_destroy_page	= agp_generic_destroy_page,
+	.agp_destroy_pages      = agp_generic_destroy_pages,
 	.agp_type_to_mask_type	= agp_generic_type_to_mask_type,
 };
 
@@ -1785,7 +1791,9 @@
 	.alloc_by_type		= intel_i830_alloc_by_type,
 	.free_by_type		= intel_i810_free_by_type,
 	.agp_alloc_page		= agp_generic_alloc_page,
+	.agp_alloc_pages        = agp_generic_alloc_pages,
 	.agp_destroy_page	= agp_generic_destroy_page,
+	.agp_destroy_pages      = agp_generic_destroy_pages,
 	.agp_type_to_mask_type  = intel_i830_type_to_mask_type,
 	.chipset_flush		= intel_i830_chipset_flush,
 };
@@ -1810,7 +1818,9 @@
 	.alloc_by_type		= agp_generic_alloc_by_type,
 	.free_by_type		= agp_generic_free_by_type,
 	.agp_alloc_page		= agp_generic_alloc_page,
+	.agp_alloc_pages        = agp_generic_alloc_pages,
 	.agp_destroy_page	= agp_generic_destroy_page,
+	.agp_destroy_pages      = agp_generic_destroy_pages,
 	.agp_type_to_mask_type  = agp_generic_type_to_mask_type,
 };
 
@@ -1834,7 +1844,9 @@
 	.alloc_by_type		= agp_generic_alloc_by_type,
 	.free_by_type		= agp_generic_free_by_type,
 	.agp_alloc_page		= agp_generic_alloc_page,
+	.agp_alloc_pages        = agp_generic_alloc_pages,
 	.agp_destroy_page	= agp_generic_destroy_page,
+	.agp_destroy_pages      = agp_generic_destroy_pages,
 	.agp_type_to_mask_type  = agp_generic_type_to_mask_type,
 };
 
@@ -1858,7 +1870,9 @@
 	.alloc_by_type		= agp_generic_alloc_by_type,
 	.free_by_type		= agp_generic_free_by_type,
 	.agp_alloc_page		= agp_generic_alloc_page,
+	.agp_alloc_pages        = agp_generic_alloc_pages,
 	.agp_destroy_page	= agp_generic_destroy_page,
+	.agp_destroy_pages      = agp_generic_destroy_pages,
 	.agp_type_to_mask_type  = agp_generic_type_to_mask_type,
 };
 
@@ -1882,7 +1896,9 @@
 	.alloc_by_type		= agp_generic_alloc_by_type,
 	.free_by_type		= agp_generic_free_by_type,
 	.agp_alloc_page		= agp_generic_alloc_page,
+	.agp_alloc_pages        = agp_generic_alloc_pages,
 	.agp_destroy_page	= agp_generic_destroy_page,
+	.agp_destroy_pages      = agp_generic_destroy_pages,
 	.agp_type_to_mask_type  = agp_generic_type_to_mask_type,
 	.chipset_flush		= intel_i830_chipset_flush,
 };
@@ -1907,7 +1923,9 @@
 	.alloc_by_type		= agp_generic_alloc_by_type,
 	.free_by_type		= agp_generic_free_by_type,
 	.agp_alloc_page		= agp_generic_alloc_page,
+	.agp_alloc_pages        = agp_generic_alloc_pages,
 	.agp_destroy_page	= agp_generic_destroy_page,
+	.agp_destroy_pages      = agp_generic_destroy_pages,
 	.agp_type_to_mask_type  = agp_generic_type_to_mask_type,
 };
 
@@ -1931,7 +1949,9 @@
 	.alloc_by_type		= agp_generic_alloc_by_type,
 	.free_by_type		= agp_generic_free_by_type,
 	.agp_alloc_page		= agp_generic_alloc_page,
+	.agp_alloc_pages        = agp_generic_alloc_pages,
 	.agp_destroy_page	= agp_generic_destroy_page,
+	.agp_destroy_pages      = agp_generic_destroy_pages,
 	.agp_type_to_mask_type  = agp_generic_type_to_mask_type,
 };
 
@@ -1956,7 +1976,9 @@
 	.alloc_by_type		= intel_i830_alloc_by_type,
 	.free_by_type		= intel_i810_free_by_type,
 	.agp_alloc_page		= agp_generic_alloc_page,
+	.agp_alloc_pages        = agp_generic_alloc_pages,
 	.agp_destroy_page	= agp_generic_destroy_page,
+	.agp_destroy_pages      = agp_generic_destroy_pages,
 	.agp_type_to_mask_type  = intel_i830_type_to_mask_type,
 	.chipset_flush		= intel_i915_chipset_flush,
 };
@@ -1982,7 +2004,9 @@
 	.alloc_by_type		= intel_i830_alloc_by_type,
 	.free_by_type		= intel_i810_free_by_type,
 	.agp_alloc_page		= agp_generic_alloc_page,
+	.agp_alloc_pages        = agp_generic_alloc_pages,
 	.agp_destroy_page	= agp_generic_destroy_page,
+	.agp_destroy_pages      = agp_generic_destroy_pages,
 	.agp_type_to_mask_type	= intel_i830_type_to_mask_type,
 	.chipset_flush		= intel_i915_chipset_flush,
 };
@@ -2007,7 +2031,9 @@
 	.alloc_by_type		= agp_generic_alloc_by_type,
 	.free_by_type		= agp_generic_free_by_type,
 	.agp_alloc_page		= agp_generic_alloc_page,
+	.agp_alloc_pages        = agp_generic_alloc_pages,
 	.agp_destroy_page	= agp_generic_destroy_page,
+	.agp_destroy_pages      = agp_generic_destroy_pages,
 	.agp_type_to_mask_type  = agp_generic_type_to_mask_type,
 };
 
@@ -2032,7 +2058,9 @@
 	.alloc_by_type		= intel_i830_alloc_by_type,
 	.free_by_type		= intel_i810_free_by_type,
 	.agp_alloc_page		= agp_generic_alloc_page,
+	.agp_alloc_pages        = agp_generic_alloc_pages,
 	.agp_destroy_page	= agp_generic_destroy_page,
+	.agp_destroy_pages      = agp_generic_destroy_pages,
 	.agp_type_to_mask_type	= intel_i830_type_to_mask_type,
 	.chipset_flush		= intel_i915_chipset_flush,
 };
diff --git a/drivers/char/agp/nvidia-agp.c b/drivers/char/agp/nvidia-agp.c
index eaceb61..dc70d37 100644
--- a/drivers/char/agp/nvidia-agp.c
+++ b/drivers/char/agp/nvidia-agp.c
@@ -312,7 +312,9 @@
 	.alloc_by_type		= agp_generic_alloc_by_type,
 	.free_by_type		= agp_generic_free_by_type,
 	.agp_alloc_page		= agp_generic_alloc_page,
+	.agp_alloc_pages	= agp_generic_alloc_pages,
 	.agp_destroy_page	= agp_generic_destroy_page,
+	.agp_destroy_pages	= agp_generic_destroy_pages,
 	.agp_type_to_mask_type  = agp_generic_type_to_mask_type,
 };
 
diff --git a/drivers/char/agp/parisc-agp.c b/drivers/char/agp/parisc-agp.c
index 8c42dcc..f2492ec 100644
--- a/drivers/char/agp/parisc-agp.c
+++ b/drivers/char/agp/parisc-agp.c
@@ -224,7 +224,9 @@
 	.alloc_by_type		= agp_generic_alloc_by_type,
 	.free_by_type		= agp_generic_free_by_type,
 	.agp_alloc_page		= agp_generic_alloc_page,
+	.agp_alloc_pages	= agp_generic_alloc_pages,
 	.agp_destroy_page	= agp_generic_destroy_page,
+	.agp_destroy_pages	= agp_generic_destroy_pages,
 	.agp_type_to_mask_type  = agp_generic_type_to_mask_type,
 	.cant_use_aperture	= true,
 };
diff --git a/drivers/char/agp/sis-agp.c b/drivers/char/agp/sis-agp.c
index 2587ef9..6c3837a 100644
--- a/drivers/char/agp/sis-agp.c
+++ b/drivers/char/agp/sis-agp.c
@@ -140,7 +140,9 @@
 	.alloc_by_type		= agp_generic_alloc_by_type,
 	.free_by_type		= agp_generic_free_by_type,
 	.agp_alloc_page		= agp_generic_alloc_page,
+	.agp_alloc_pages	= agp_generic_alloc_pages,
 	.agp_destroy_page	= agp_generic_destroy_page,
+	.agp_destroy_pages	= agp_generic_destroy_pages,
 	.agp_type_to_mask_type  = agp_generic_type_to_mask_type,
 };
 
diff --git a/drivers/char/agp/sworks-agp.c b/drivers/char/agp/sworks-agp.c
index 2fb27fe..6224df8 100644
--- a/drivers/char/agp/sworks-agp.c
+++ b/drivers/char/agp/sworks-agp.c
@@ -437,7 +437,9 @@
 	.alloc_by_type		= agp_generic_alloc_by_type,
 	.free_by_type		= agp_generic_free_by_type,
 	.agp_alloc_page		= agp_generic_alloc_page,
+	.agp_alloc_pages	= agp_generic_alloc_pages,
 	.agp_destroy_page	= agp_generic_destroy_page,
+	.agp_destroy_pages	= agp_generic_destroy_pages,
 	.agp_type_to_mask_type  = agp_generic_type_to_mask_type,
 };
 
diff --git a/drivers/char/agp/uninorth-agp.c b/drivers/char/agp/uninorth-agp.c
index eef7270..0f004b6 100644
--- a/drivers/char/agp/uninorth-agp.c
+++ b/drivers/char/agp/uninorth-agp.c
@@ -509,7 +509,9 @@
 	.alloc_by_type		= agp_generic_alloc_by_type,
 	.free_by_type		= agp_generic_free_by_type,
 	.agp_alloc_page		= agp_generic_alloc_page,
+	.agp_alloc_pages	= agp_generic_alloc_pages,
 	.agp_destroy_page	= agp_generic_destroy_page,
+	.agp_destroy_pages	= agp_generic_destroy_pages,
 	.agp_type_to_mask_type  = agp_generic_type_to_mask_type,
 	.cant_use_aperture	= true,
 };
@@ -534,7 +536,9 @@
 	.alloc_by_type		= agp_generic_alloc_by_type,
 	.free_by_type		= agp_generic_free_by_type,
 	.agp_alloc_page		= agp_generic_alloc_page,
+	.agp_alloc_pages	= agp_generic_alloc_pages,
 	.agp_destroy_page	= agp_generic_destroy_page,
+	.agp_destroy_pages	= agp_generic_destroy_pages,
 	.agp_type_to_mask_type  = agp_generic_type_to_mask_type,
 	.cant_use_aperture	= true,
 	.needs_scratch_page	= true,
diff --git a/drivers/char/agp/via-agp.c b/drivers/char/agp/via-agp.c
index 7b36476..9f4d49e 100644
--- a/drivers/char/agp/via-agp.c
+++ b/drivers/char/agp/via-agp.c
@@ -190,7 +190,9 @@
 	.alloc_by_type		= agp_generic_alloc_by_type,
 	.free_by_type		= agp_generic_free_by_type,
 	.agp_alloc_page		= agp_generic_alloc_page,
+	.agp_alloc_pages	= agp_generic_alloc_pages,
 	.agp_destroy_page	= agp_generic_destroy_page,
+	.agp_destroy_pages	= agp_generic_destroy_pages,
 	.agp_type_to_mask_type  = agp_generic_type_to_mask_type,
 };
 
@@ -214,7 +216,9 @@
 	.alloc_by_type		= agp_generic_alloc_by_type,
 	.free_by_type		= agp_generic_free_by_type,
 	.agp_alloc_page		= agp_generic_alloc_page,
+	.agp_alloc_pages	= agp_generic_alloc_pages,
 	.agp_destroy_page	= agp_generic_destroy_page,
+	.agp_destroy_pages	= agp_generic_destroy_pages,
 	.agp_type_to_mask_type  = agp_generic_type_to_mask_type,
 };
 
diff --git a/drivers/char/amiserial.c b/drivers/char/amiserial.c
index 6e763e3..98821f9 100644
--- a/drivers/char/amiserial.c
+++ b/drivers/char/amiserial.c
@@ -837,9 +837,6 @@
 	struct async_struct *info;
 	unsigned long flags;
 
-	if (!tty)
-		return 0;
-
 	info = tty->driver_data;
 
 	if (serial_paranoia_check(info, tty->name, "rs_put_char"))
@@ -892,9 +889,6 @@
 	struct async_struct *info;
 	unsigned long flags;
 
-	if (!tty)
-		return 0;
-
 	info = tty->driver_data;
 
 	if (serial_paranoia_check(info, tty->name, "rs_write"))
diff --git a/drivers/char/applicom.c b/drivers/char/applicom.c
index 31d08b6..b899d91 100644
--- a/drivers/char/applicom.c
+++ b/drivers/char/applicom.c
@@ -712,8 +712,7 @@
 	
 	IndexCard = adgl->num_card-1;
 	 
-	if(cmd != 0 && cmd != 6 &&
-	   ((IndexCard >= MAX_BOARD) || !apbs[IndexCard].RamIO)) {
+	if(cmd != 6 && ((IndexCard >= MAX_BOARD) || !apbs[IndexCard].RamIO)) {
 		static int warncount = 10;
 		if (warncount) {
 			printk( KERN_WARNING "APPLICOM driver IOCTL, bad board number %d\n",(int)IndexCard+1);
@@ -832,8 +831,7 @@
 		}
 		break;
 	default:
-		printk(KERN_INFO "APPLICOM driver ioctl, unknown function code %d\n",cmd) ;
-		ret = -EINVAL;
+		ret = -ENOTTY;
 		break;
 	}
 	Dummy = readb(apbs[IndexCard].RamIO + VERS);
diff --git a/drivers/char/cyclades.c b/drivers/char/cyclades.c
index fe6d774..5e5b1dc 100644
--- a/drivers/char/cyclades.c
+++ b/drivers/char/cyclades.c
@@ -4993,12 +4993,14 @@
 			device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi) {
 		card_name = "Cyclom-Y";
 
-		addr0 = pci_iomap(pdev, 0, CyPCI_Yctl);
+		addr0 = ioremap_nocache(pci_resource_start(pdev, 0),
+				CyPCI_Yctl);
 		if (addr0 == NULL) {
 			dev_err(&pdev->dev, "can't remap ctl region\n");
 			goto err_reg;
 		}
-		addr2 = pci_iomap(pdev, 2, CyPCI_Ywin);
+		addr2 = ioremap_nocache(pci_resource_start(pdev, 2),
+				CyPCI_Ywin);
 		if (addr2 == NULL) {
 			dev_err(&pdev->dev, "can't remap base region\n");
 			goto err_unmap;
@@ -5013,7 +5015,8 @@
 	} else if (device_id == PCI_DEVICE_ID_CYCLOM_Z_Hi) {
 		struct RUNTIME_9060 __iomem *ctl_addr;
 
-		ctl_addr = addr0 = pci_iomap(pdev, 0, CyPCI_Zctl);
+		ctl_addr = addr0 = ioremap_nocache(pci_resource_start(pdev, 0),
+				CyPCI_Zctl);
 		if (addr0 == NULL) {
 			dev_err(&pdev->dev, "can't remap ctl region\n");
 			goto err_reg;
@@ -5026,8 +5029,8 @@
 
 		mailbox = (u32)readl(&ctl_addr->mail_box_0);
 
-		addr2 = pci_iomap(pdev, 2, mailbox == ZE_V1 ?
-				CyPCI_Ze_win : CyPCI_Zwin);
+		addr2 = ioremap_nocache(pci_resource_start(pdev, 2),
+				mailbox == ZE_V1 ? CyPCI_Ze_win : CyPCI_Zwin);
 		if (addr2 == NULL) {
 			dev_err(&pdev->dev, "can't remap base region\n");
 			goto err_unmap;
@@ -5159,9 +5162,9 @@
 	cy_card[card_no].base_addr = NULL;
 	free_irq(irq, &cy_card[card_no]);
 err_unmap:
-	pci_iounmap(pdev, addr0);
+	iounmap(addr0);
 	if (addr2)
-		pci_iounmap(pdev, addr2);
+		iounmap(addr2);
 err_reg:
 	pci_release_regions(pdev);
 err_dis:
@@ -5186,9 +5189,9 @@
 		cy_writew(cinfo->ctl_addr + 0x68,
 				readw(cinfo->ctl_addr + 0x68) & ~0x0900);
 
-	pci_iounmap(pdev, cinfo->base_addr);
+	iounmap(cinfo->base_addr);
 	if (cinfo->ctl_addr)
-		pci_iounmap(pdev, cinfo->ctl_addr);
+		iounmap(cinfo->ctl_addr);
 	if (cinfo->irq
 #ifndef CONFIG_CYZ_INTR
 		&& !IS_CYC_Z(*cinfo)
diff --git a/drivers/char/epca.c b/drivers/char/epca.c
index 456e4ed..4998b27 100644
--- a/drivers/char/epca.c
+++ b/drivers/char/epca.c
@@ -1376,6 +1376,7 @@
 		unsigned long flags;
 		u16 tseg, rseg;
 
+		tty_port_init(&ch->port);
 		ch->brdchan = bc;
 		ch->mailbox = gd;
 		INIT_WORK(&ch->tqueue, do_softint);
@@ -1510,10 +1511,6 @@
 		ch->fepstopca = 0;
 
 		ch->close_delay = 50;
-		ch->port.count = 0;
-		ch->port.blocked_open = 0;
-		init_waitqueue_head(&ch->port.open_wait);
-		init_waitqueue_head(&ch->port.close_wait);
 
 		spin_unlock_irqrestore(&epca_lock, flags);
 	}
diff --git a/drivers/char/generic_serial.c b/drivers/char/generic_serial.c
index 19d3afb..c6090f8 100644
--- a/drivers/char/generic_serial.c
+++ b/drivers/char/generic_serial.c
@@ -54,8 +54,6 @@
 
 	func_enter (); 
 
-	if (!tty) return 0;
-
 	port = tty->driver_data;
 
 	if (!port) return 0;
@@ -97,8 +95,6 @@
 
 	func_enter ();
 
-	if (!tty) return 0;
-
 	port = tty->driver_data;
 
 	if (!port) return 0;
@@ -185,7 +181,6 @@
 	struct gs_port *port;
 	func_enter ();
 
-	if (!tty) return 0;
 	port = tty->driver_data;
 
 	if (!port->rd) return 0;
@@ -274,8 +269,6 @@
 
 	func_enter ();
 
-	if (!tty) return;
-
 	port = tty->driver_data;
 
 	if (!port) return;
@@ -296,8 +289,6 @@
 
 	func_enter ();
 
-	if (!tty) return;
-
 	port = tty->driver_data;
 
 	if (!port) return;
@@ -321,8 +312,6 @@
 
 	func_enter ();
 
-	if (!tty) return;
-
 	port = tty->driver_data;
 
 	if (!port) return;
@@ -341,8 +330,6 @@
 {
 	struct gs_port *port;
 
-	if (!tty) return;
-
 	port = tty->driver_data;
 
 	if (!port) return;
@@ -393,8 +380,6 @@
 
 	func_enter ();
 
-	if (!tty) return;
-
 	port = tty->driver_data;
 	tty = port->port.tty;
 	if (!tty) 
@@ -426,8 +411,6 @@
 
 	tty = port->port.tty;
 
-	if (!tty) return 0;
-
 	gs_dprintk (GS_DEBUG_BTR, "Entering gs_block_till_ready.\n"); 
 	/*
 	 * If the device is in the middle of being closed, then block
@@ -523,8 +506,6 @@
 	
 	func_enter ();
 
-	if (!tty) return;
-
 	port = (struct gs_port *) tty->driver_data;
 
 	if (!port) return;
@@ -621,8 +602,6 @@
 
 	func_enter();
 
-	if (!tty) return;
-
 	port = tty->driver_data;
 
 	if (!port) return;
diff --git a/drivers/char/hpet.c b/drivers/char/hpet.c
index b3f5dbc..f3cfb4c 100644
--- a/drivers/char/hpet.c
+++ b/drivers/char/hpet.c
@@ -53,6 +53,11 @@
 
 #define HPET_RANGE_SIZE		1024	/* from HPET spec */
 
+
+/* WARNING -- don't get confused.  These macros are never used
+ * to write the (single) counter, and rarely to read it.
+ * They're badly named; to fix, someday.
+ */
 #if BITS_PER_LONG == 64
 #define	write_counter(V, MC)	writeq(V, MC)
 #define	read_counter(MC)	readq(MC)
@@ -77,7 +82,7 @@
         .rating         = 250,
         .read           = read_hpet,
         .mask           = CLOCKSOURCE_MASK(64),
-        .mult           = 0, /*to be caluclated*/
+	.mult		= 0, /* to be calculated */
         .shift          = 10,
         .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
 };
@@ -86,8 +91,6 @@
 
 /* A lock for concurrent access by app and isr hpet activity. */
 static DEFINE_SPINLOCK(hpet_lock);
-/* A lock for concurrent intermodule access to hpet and isr hpet activity. */
-static DEFINE_SPINLOCK(hpet_task_lock);
 
 #define	HPET_DEV_NAME	(7)
 
@@ -99,7 +102,6 @@
 	unsigned long hd_irqdata;
 	wait_queue_head_t hd_waitqueue;
 	struct fasync_struct *hd_async_queue;
-	struct hpet_task *hd_task;
 	unsigned int hd_flags;
 	unsigned int hd_irq;
 	unsigned int hd_hdwirq;
@@ -173,11 +175,6 @@
 		writel(isr, &devp->hd_hpet->hpet_isr);
 	spin_unlock(&hpet_lock);
 
-	spin_lock(&hpet_task_lock);
-	if (devp->hd_task)
-		devp->hd_task->ht_func(devp->hd_task->ht_data);
-	spin_unlock(&hpet_task_lock);
-
 	wake_up_interruptible(&devp->hd_waitqueue);
 
 	kill_fasync(&devp->hd_async_queue, SIGIO, POLL_IN);
@@ -185,6 +182,67 @@
 	return IRQ_HANDLED;
 }
 
+static void hpet_timer_set_irq(struct hpet_dev *devp)
+{
+	unsigned long v;
+	int irq, gsi;
+	struct hpet_timer __iomem *timer;
+
+	spin_lock_irq(&hpet_lock);
+	if (devp->hd_hdwirq) {
+		spin_unlock_irq(&hpet_lock);
+		return;
+	}
+
+	timer = devp->hd_timer;
+
+	/* we prefer level triggered mode */
+	v = readl(&timer->hpet_config);
+	if (!(v & Tn_INT_TYPE_CNF_MASK)) {
+		v |= Tn_INT_TYPE_CNF_MASK;
+		writel(v, &timer->hpet_config);
+	}
+	spin_unlock_irq(&hpet_lock);
+
+	v = (readq(&timer->hpet_config) & Tn_INT_ROUTE_CAP_MASK) >>
+				 Tn_INT_ROUTE_CAP_SHIFT;
+
+	/*
+	 * In PIC mode, skip IRQ0-4, IRQ6-9, IRQ12-15 which is always used by
+	 * legacy device. In IO APIC mode, we skip all the legacy IRQS.
+	 */
+	if (acpi_irq_model == ACPI_IRQ_MODEL_PIC)
+		v &= ~0xf3df;
+	else
+		v &= ~0xffff;
+
+	for (irq = find_first_bit(&v, HPET_MAX_IRQ); irq < HPET_MAX_IRQ;
+		irq = find_next_bit(&v, HPET_MAX_IRQ, 1 + irq)) {
+
+		if (irq >= NR_IRQS) {
+			irq = HPET_MAX_IRQ;
+			break;
+		}
+
+		gsi = acpi_register_gsi(irq, ACPI_LEVEL_SENSITIVE,
+					ACPI_ACTIVE_LOW);
+		if (gsi > 0)
+			break;
+
+		/* FIXME: Setup interrupt source table */
+	}
+
+	if (irq < HPET_MAX_IRQ) {
+		spin_lock_irq(&hpet_lock);
+		v = readl(&timer->hpet_config);
+		v |= irq << Tn_INT_ROUTE_CNF_SHIFT;
+		writel(v, &timer->hpet_config);
+		devp->hd_hdwirq = gsi;
+		spin_unlock_irq(&hpet_lock);
+	}
+	return;
+}
+
 static int hpet_open(struct inode *inode, struct file *file)
 {
 	struct hpet_dev *devp;
@@ -199,8 +257,7 @@
 
 	for (devp = NULL, hpetp = hpets; hpetp && !devp; hpetp = hpetp->hp_next)
 		for (i = 0; i < hpetp->hp_ntimer; i++)
-			if (hpetp->hp_dev[i].hd_flags & HPET_OPEN
-			    || hpetp->hp_dev[i].hd_task)
+			if (hpetp->hp_dev[i].hd_flags & HPET_OPEN)
 				continue;
 			else {
 				devp = &hpetp->hp_dev[i];
@@ -219,6 +276,8 @@
 	spin_unlock_irq(&hpet_lock);
 	unlock_kernel();
 
+	hpet_timer_set_irq(devp);
+
 	return 0;
 }
 
@@ -441,7 +500,11 @@
 	devp->hd_irq = irq;
 	t = devp->hd_ireqfreq;
 	v = readq(&timer->hpet_config);
-	g = v | Tn_INT_ENB_CNF_MASK;
+
+	/* 64-bit comparators are not yet supported through the ioctls,
+	 * so force this into 32-bit mode if it supports both modes
+	 */
+	g = v | Tn_32MODE_CNF_MASK | Tn_INT_ENB_CNF_MASK;
 
 	if (devp->hd_flags & HPET_PERIODIC) {
 		write_counter(t, &timer->hpet_compare);
@@ -451,6 +514,12 @@
 		v |= Tn_VAL_SET_CNF_MASK;
 		writeq(v, &timer->hpet_config);
 		local_irq_save(flags);
+
+		/* NOTE:  what we modify here is a hidden accumulator
+		 * register supported by periodic-capable comparators.
+		 * We never want to modify the (single) counter; that
+		 * would affect all the comparators.
+		 */
 		m = read_counter(&hpet->hpet_mc);
 		write_counter(t + m + hpetp->hp_delta, &timer->hpet_compare);
 	} else {
@@ -604,57 +673,6 @@
 	return 0;
 }
 
-static inline int hpet_tpcheck(struct hpet_task *tp)
-{
-	struct hpet_dev *devp;
-	struct hpets *hpetp;
-
-	devp = tp->ht_opaque;
-
-	if (!devp)
-		return -ENXIO;
-
-	for (hpetp = hpets; hpetp; hpetp = hpetp->hp_next)
-		if (devp >= hpetp->hp_dev
-		    && devp < (hpetp->hp_dev + hpetp->hp_ntimer)
-		    && devp->hd_hpet == hpetp->hp_hpet)
-			return 0;
-
-	return -ENXIO;
-}
-
-#if 0
-int hpet_unregister(struct hpet_task *tp)
-{
-	struct hpet_dev *devp;
-	struct hpet_timer __iomem *timer;
-	int err;
-
-	if ((err = hpet_tpcheck(tp)))
-		return err;
-
-	spin_lock_irq(&hpet_task_lock);
-	spin_lock(&hpet_lock);
-
-	devp = tp->ht_opaque;
-	if (devp->hd_task != tp) {
-		spin_unlock(&hpet_lock);
-		spin_unlock_irq(&hpet_task_lock);
-		return -ENXIO;
-	}
-
-	timer = devp->hd_timer;
-	writeq((readq(&timer->hpet_config) & ~Tn_INT_ENB_CNF_MASK),
-	       &timer->hpet_config);
-	devp->hd_flags &= ~(HPET_IE | HPET_PERIODIC);
-	devp->hd_task = NULL;
-	spin_unlock(&hpet_lock);
-	spin_unlock_irq(&hpet_task_lock);
-
-	return 0;
-}
-#endif  /*  0  */
-
 static ctl_table hpet_table[] = {
 	{
 	 .ctl_name = CTL_UNNUMBERED,
@@ -746,6 +764,7 @@
 	static struct hpets *last = NULL;
 	unsigned long period;
 	unsigned long long temp;
+	u32 remainder;
 
 	/*
 	 * hpet_alloc can be called by platform dependent code.
@@ -809,9 +828,13 @@
 		printk("%s %d", i > 0 ? "," : "", hdp->hd_irq[i]);
 	printk("\n");
 
-	printk(KERN_INFO "hpet%u: %u %d-bit timers, %Lu Hz\n",
-	       hpetp->hp_which, hpetp->hp_ntimer,
-	       cap & HPET_COUNTER_SIZE_MASK ? 64 : 32, hpetp->hp_tick_freq);
+	temp = hpetp->hp_tick_freq;
+	remainder = do_div(temp, 1000000);
+	printk(KERN_INFO
+		"hpet%u: %u comparators, %d-bit %u.%06u MHz counter\n",
+		hpetp->hp_which, hpetp->hp_ntimer,
+		cap & HPET_COUNTER_SIZE_MASK ? 64 : 32,
+		(unsigned) temp, remainder);
 
 	mcfg = readq(&hpet->hpet_config);
 	if ((mcfg & HPET_ENABLE_CNF_MASK) == 0) {
@@ -874,8 +897,6 @@
 		hdp->hd_address = ioremap(addr.minimum, addr.address_length);
 
 		if (hpet_is_known(hdp)) {
-			printk(KERN_DEBUG "%s: 0x%lx is busy\n",
-				__func__, hdp->hd_phys_address);
 			iounmap(hdp->hd_address);
 			return AE_ALREADY_EXISTS;
 		}
@@ -891,8 +912,6 @@
 						HPET_RANGE_SIZE);
 
 		if (hpet_is_known(hdp)) {
-			printk(KERN_DEBUG "%s: 0x%lx is busy\n",
-				__func__, hdp->hd_phys_address);
 			iounmap(hdp->hd_address);
 			return AE_ALREADY_EXISTS;
 		}
diff --git a/drivers/char/hvc_console.c b/drivers/char/hvc_console.c
index fd64137..ec7aded 100644
--- a/drivers/char/hvc_console.c
+++ b/drivers/char/hvc_console.c
@@ -819,11 +819,11 @@
 	hvc_driver = drv;
 	return 0;
 
-put_tty:
-	put_tty_driver(hvc_driver);
 stop_thread:
 	kthread_stop(hvc_task);
 	hvc_task = NULL;
+put_tty:
+	put_tty_driver(drv);
 out:
 	return err;
 }
diff --git a/drivers/char/hvc_xen.c b/drivers/char/hvc_xen.c
index 6b70aa6..538ceea 100644
--- a/drivers/char/hvc_xen.c
+++ b/drivers/char/hvc_xen.c
@@ -108,8 +108,8 @@
 {
 	struct hvc_struct *hp;
 
-	if (!is_running_on_xen() ||
-	    is_initial_xendomain() ||
+	if (!xen_pv_domain() ||
+	    xen_initial_domain() ||
 	    !xen_start_info->console.domU.evtchn)
 		return -ENODEV;
 
@@ -142,7 +142,7 @@
 
 static int xen_cons_init(void)
 {
-	if (!is_running_on_xen())
+	if (!xen_pv_domain())
 		return 0;
 
 	hvc_instantiate(HVC_COOKIE, 0, &hvc_ops);
diff --git a/drivers/char/hw_random/n2-drv.c b/drivers/char/hw_random/n2-drv.c
index 5220f54..8859aea 100644
--- a/drivers/char/hw_random/n2-drv.c
+++ b/drivers/char/hw_random/n2-drv.c
@@ -736,7 +736,7 @@
 	return 0;
 }
 
-static struct of_device_id n2rng_match[] = {
+static const struct of_device_id n2rng_match[] = {
 	{
 		.name		= "random-number-generator",
 		.compatible	= "SUNW,n2-rng",
diff --git a/drivers/char/ip2/Makefile b/drivers/char/ip2/Makefile
index 939618f..bc397d9 100644
--- a/drivers/char/ip2/Makefile
+++ b/drivers/char/ip2/Makefile
@@ -4,5 +4,5 @@
 
 obj-$(CONFIG_COMPUTONE)         += ip2.o
 
-ip2-objs			:= ip2base.o ip2main.o
+ip2-objs			:= ip2main.o
 
diff --git a/drivers/char/ip2/i2ellis.c b/drivers/char/ip2/i2ellis.c
index 3601017..29db44d 100644
--- a/drivers/char/ip2/i2ellis.c
+++ b/drivers/char/ip2/i2ellis.c
@@ -69,38 +69,6 @@
 //=======================================================
 
 //******************************************************************************
-// Function:   iiEllisInit()
-// Parameters: None
-//
-// Returns:    Nothing
-//
-// Description:
-//
-// This routine performs any required initialization of the iiEllis subsystem.
-//
-//******************************************************************************
-static void
-iiEllisInit(void)
-{
-}
-
-//******************************************************************************
-// Function:   iiEllisCleanup()
-// Parameters: None
-//
-// Returns:    Nothing
-//
-// Description:
-//
-// This routine performs any required cleanup of the iiEllis subsystem.
-//
-//******************************************************************************
-static void
-iiEllisCleanup(void)
-{
-}
-
-//******************************************************************************
 // Function:   iiSetAddress(pB, address, delay)
 // Parameters: pB      - pointer to the board structure
 //             address - the purported I/O address of the board
diff --git a/drivers/char/ip2/i2ellis.h b/drivers/char/ip2/i2ellis.h
index c88a64e..fb6df24 100644
--- a/drivers/char/ip2/i2ellis.h
+++ b/drivers/char/ip2/i2ellis.h
@@ -511,7 +511,6 @@
 //
 // Initialization of a board & structure is in four (five!) parts:
 //
-// 0) iiEllisInit()  - Initialize iiEllis subsystem.
 // 1) iiSetAddress() - Define the board address & delay function for a board.
 // 2) iiReset()      - Reset the board   (provided it exists)
 //       -- Note you may do this to several boards --
@@ -523,7 +522,6 @@
 // loadware.  To change loadware, you must begin again with step 2, resetting
 // the board again (step 1 not needed).
 
-static void iiEllisInit(void);
 static int iiSetAddress(i2eBordStrPtr, int, delayFunc_t );
 static int iiReset(i2eBordStrPtr);
 static int iiResetDelay(i2eBordStrPtr);
diff --git a/drivers/char/ip2/ip2base.c b/drivers/char/ip2/ip2base.c
deleted file mode 100644
index 8155e24..0000000
--- a/drivers/char/ip2/ip2base.c
+++ /dev/null
@@ -1,108 +0,0 @@
-// ip2.c
-// This is a dummy module to make the firmware available when needed
-// and allows it to be unloaded when not. Rumor is the __initdata 
-// macro doesn't always works on all platforms so we use this kludge.
-// If not compiled as a module it just makes fip_firm avaliable then
-//  __initdata should work as advertized
-//
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/wait.h>
-
-#ifndef __init
-#define __init
-#endif
-#ifndef __initfunc
-#define __initfunc(a) a
-#endif
-#ifndef __initdata
-#define __initdata
-#endif
-
-#include "ip2types.h"		
-
-int
-ip2_loadmain(int *, int *); // ref into ip2main.c
-
-/* Note: Add compiled in defaults to these arrays, not to the structure
-	in ip2.h any longer.  That structure WILL get overridden
-	by these values, or command line values, or insmod values!!!  =mhw=
-*/
-static int io[IP2_MAX_BOARDS]= { 0, 0, 0, 0 };
-static int irq[IP2_MAX_BOARDS] = { -1, -1, -1, -1 }; 
-
-static int poll_only = 0;
-
-MODULE_AUTHOR("Doug McNash");
-MODULE_DESCRIPTION("Computone IntelliPort Plus Driver");
-module_param_array(irq, int, NULL, 0);
-MODULE_PARM_DESC(irq,"Interrupts for IntelliPort Cards");
-module_param_array(io, int, NULL, 0);
-MODULE_PARM_DESC(io,"I/O ports for IntelliPort Cards");
-module_param(poll_only, bool, 0);
-MODULE_PARM_DESC(poll_only,"Do not use card interrupts");
-
-
-static int __init ip2_init(void)
-{
-	if( poll_only ) {
-		/* Hard lock the interrupts to zero */
-		irq[0] = irq[1] = irq[2] = irq[3] = 0;
-	}
-
-	return ip2_loadmain(io, irq);
-}
-module_init(ip2_init);
-
-MODULE_LICENSE("GPL");
-
-#ifndef MODULE
-/******************************************************************************
- *	ip2_setup:
- *		str: kernel command line string
- *
- *	Can't autoprobe the boards so user must specify configuration on
- *	kernel command line.  Sane people build it modular but the others
- *	come here.
- *
- *	Alternating pairs of io,irq for up to 4 boards.
- *		ip2=io0,irq0,io1,irq1,io2,irq2,io3,irq3
- *
- *		io=0 => No board
- *		io=1 => PCI
- *		io=2 => EISA
- *		else => ISA I/O address
- *
- *		irq=0 or invalid for ISA will revert to polling mode
- *
- *		Any value = -1, do not overwrite compiled in value.
- *
- ******************************************************************************/
-static int __init ip2_setup(char *str)
-{
-	int	ints[10];	/* 4 boards, 2 parameters + 2 */
-	int	i, j;
-
-	str = get_options (str, ARRAY_SIZE(ints), ints);
-
-	for( i = 0, j = 1; i < 4; i++ ) {
-		if( j > ints[0] ) {
-			break;
-		}
-		if( ints[j] >= 0 ) {
-			io[i] = ints[j];
-		}
-		j++;
-		if( j > ints[0] ) {
-			break;
-		}
-		if( ints[j] >= 0 ) {
-			irq[i] = ints[j];
-		}
-		j++;
-	}
-	return 1;
-}
-__setup("ip2=", ip2_setup);
-#endif /* !MODULE */
diff --git a/drivers/char/ip2/ip2main.c b/drivers/char/ip2/ip2main.c
index 689f9dc..6774572 100644
--- a/drivers/char/ip2/ip2main.c
+++ b/drivers/char/ip2/ip2main.c
@@ -150,15 +150,12 @@
 /*************/
 
 /* String constants to identify ourselves */
-static char *pcName    = "Computone IntelliPort Plus multiport driver";
-static char *pcVersion = "1.2.14";
+static const char pcName[] = "Computone IntelliPort Plus multiport driver";
+static const char pcVersion[] = "1.2.14";
 
 /* String constants for port names */
-static char *pcDriver_name   = "ip2";
-static char *pcIpl    		 = "ip2ipl";
-
-// cheezy kludge or genius - you decide?
-int ip2_loadmain(int *, int *);
+static const char pcDriver_name[] = "ip2";
+static const char pcIpl[] = "ip2ipl";
 
 /***********************/
 /* Function Prototypes */
@@ -240,8 +237,8 @@
 	.open		= ip2_ipl_open,
 }; 
 
-static unsigned long irq_counter = 0;
-static unsigned long bh_counter = 0;
+static unsigned long irq_counter;
+static unsigned long bh_counter;
 
 // Use immediate queue to service interrupts
 #define USE_IQI
@@ -252,7 +249,6 @@
  */
 #define  POLL_TIMEOUT   (jiffies + 1)
 static DEFINE_TIMER(PollTimer, ip2_poll, 0, 0);
-static char  TimerOn;
 
 #ifdef IP2DEBUG_TRACE
 /* Trace (debug) buffer data */
@@ -268,8 +264,8 @@
 /**********/
 
 #if defined(MODULE) && defined(IP2DEBUG_OPEN)
-#define DBG_CNT(s) printk(KERN_DEBUG "(%s): [%x] refc=%d, ttyc=%d, modc=%x -> %s\n", \
-		    tty->name,(pCh->flags),ip2_tty_driver->refcount, \
+#define DBG_CNT(s) printk(KERN_DEBUG "(%s): [%x] ttyc=%d, modc=%x -> %s\n", \
+		    tty->name,(pCh->flags), \
 		    tty->count,/*GET_USE_COUNT(module)*/0,s)
 #else
 #define DBG_CNT(s)
@@ -287,8 +283,9 @@
 
 MODULE_AUTHOR("Doug McNash");
 MODULE_DESCRIPTION("Computone IntelliPort Plus Driver");
+MODULE_LICENSE("GPL");
 
-static int poll_only = 0;
+static int poll_only;
 
 static int Eisa_irq;
 static int Eisa_slot;
@@ -297,34 +294,46 @@
 static char rirqs[IP2_MAX_BOARDS];
 static int Valid_Irqs[] = { 3, 4, 5, 7, 10, 11, 12, 15, 0};
 
+/* Note: Add compiled in defaults to these arrays, not to the structure
+	in ip2.h any longer.  That structure WILL get overridden
+	by these values, or command line values, or insmod values!!!  =mhw=
+*/
+static int io[IP2_MAX_BOARDS];
+static int irq[IP2_MAX_BOARDS] = { -1, -1, -1, -1 };
+
+MODULE_AUTHOR("Doug McNash");
+MODULE_DESCRIPTION("Computone IntelliPort Plus Driver");
+module_param_array(irq, int, NULL, 0);
+MODULE_PARM_DESC(irq, "Interrupts for IntelliPort Cards");
+module_param_array(io, int, NULL, 0);
+MODULE_PARM_DESC(io, "I/O ports for IntelliPort Cards");
+module_param(poll_only, bool, 0);
+MODULE_PARM_DESC(poll_only, "Do not use card interrupts");
+
 /* for sysfs class support */
 static struct class *ip2_class;
 
-// Some functions to keep track of what irq's we have
+/* Some functions to keep track of what irqs we have */
 
-static int
-is_valid_irq(int irq)
+static int __init is_valid_irq(int irq)
 {
 	int *i = Valid_Irqs;
 	
-	while ((*i != 0) && (*i != irq)) {
+	while (*i != 0 && *i != irq)
 		i++;
-	}
-	return (*i);
+
+	return *i;
 }
 
-static void
-mark_requested_irq( char irq )
+static void __init mark_requested_irq(char irq)
 {
 	rirqs[iindx++] = irq;
 }
 
-#ifdef MODULE
-static int
-clear_requested_irq( char irq )
+static int __exit clear_requested_irq(char irq)
 {
 	int i;
-	for ( i = 0; i < IP2_MAX_BOARDS; ++i ) {
+	for (i = 0; i < IP2_MAX_BOARDS; ++i) {
 		if (rirqs[i] == irq) {
 			rirqs[i] = 0;
 			return 1;
@@ -332,17 +341,15 @@
 	}
 	return 0;
 }
-#endif
 
-static int
-have_requested_irq( char irq )
+static int have_requested_irq(char irq)
 {
-	// array init to zeros so 0 irq will not be requested as a side effect
+	/* array init to zeros so 0 irq will not be requested as a side
+	 * effect */
 	int i;
-	for ( i = 0; i < IP2_MAX_BOARDS; ++i ) {
+	for (i = 0; i < IP2_MAX_BOARDS; ++i)
 		if (rirqs[i] == irq)
 			return 1;
-	}
 	return 0;
 }
 
@@ -361,53 +368,45 @@
 /* handle subsequent installations of the driver. All memory allocated by the */
 /* driver should be returned since it may be unloaded from memory.            */
 /******************************************************************************/
-#ifdef MODULE
-void __exit
-ip2_cleanup_module(void)
+static void __exit ip2_cleanup_module(void)
 {
 	int err;
 	int i;
 
-#ifdef IP2DEBUG_INIT
-	printk (KERN_DEBUG "Unloading %s: version %s\n", pcName, pcVersion );
-#endif
-	/* Stop poll timer if we had one. */
-	if ( TimerOn ) {
-		del_timer ( &PollTimer );
-		TimerOn = 0;
-	}
+	del_timer_sync(&PollTimer);
 
 	/* Reset the boards we have. */
-	for( i = 0; i < IP2_MAX_BOARDS; ++i ) {
-		if ( i2BoardPtrTable[i] ) {
-			iiReset( i2BoardPtrTable[i] );
-		}
-	}
+	for (i = 0; i < IP2_MAX_BOARDS; i++)
+		if (i2BoardPtrTable[i])
+			iiReset(i2BoardPtrTable[i]);
 
 	/* The following is done at most once, if any boards were installed. */
-	for ( i = 0; i < IP2_MAX_BOARDS; ++i ) {
-		if ( i2BoardPtrTable[i] ) {
-			iiResetDelay( i2BoardPtrTable[i] );
+	for (i = 0; i < IP2_MAX_BOARDS; i++) {
+		if (i2BoardPtrTable[i]) {
+			iiResetDelay(i2BoardPtrTable[i]);
 			/* free io addresses and Tibet */
-			release_region( ip2config.addr[i], 8 );
+			release_region(ip2config.addr[i], 8);
 			device_destroy(ip2_class, MKDEV(IP2_IPL_MAJOR, 4 * i));
-			device_destroy(ip2_class, MKDEV(IP2_IPL_MAJOR, 4 * i + 1));
+			device_destroy(ip2_class, MKDEV(IP2_IPL_MAJOR,
+						4 * i + 1));
 		}
 		/* Disable and remove interrupt handler. */
-		if ( (ip2config.irq[i] > 0) && have_requested_irq(ip2config.irq[i]) ) {	
-			free_irq ( ip2config.irq[i], (void *)&pcName);
-			clear_requested_irq( ip2config.irq[i]);
+		if (ip2config.irq[i] > 0 &&
+				have_requested_irq(ip2config.irq[i])) {
+			free_irq(ip2config.irq[i], (void *)&pcName);
+			clear_requested_irq(ip2config.irq[i]);
 		}
 	}
 	class_destroy(ip2_class);
-	if ( ( err = tty_unregister_driver ( ip2_tty_driver ) ) ) {
-		printk(KERN_ERR "IP2: failed to unregister tty driver (%d)\n", err);
-	}
+	err = tty_unregister_driver(ip2_tty_driver);
+	if (err)
+		printk(KERN_ERR "IP2: failed to unregister tty driver (%d)\n",
+				err);
 	put_tty_driver(ip2_tty_driver);
 	unregister_chrdev(IP2_IPL_MAJOR, pcIpl);
 	remove_proc_entry("ip2mem", NULL);
 
-	// free memory
+	/* free memory */
 	for (i = 0; i < IP2_MAX_BOARDS; i++) {
 		void *pB;
 #ifdef CONFIG_PCI
@@ -417,24 +416,18 @@
 			ip2config.pci_dev[i] = NULL;
 		}
 #endif
-		if ((pB = i2BoardPtrTable[i]) != 0 ) {
-			kfree ( pB );
+		pB = i2BoardPtrTable[i];
+		if (pB != NULL) {
+			kfree(pB);
 			i2BoardPtrTable[i] = NULL;
 		}
-		if ((DevTableMem[i]) != NULL ) {
-			kfree ( DevTableMem[i]  );
+		if (DevTableMem[i] != NULL) {
+			kfree(DevTableMem[i]);
 			DevTableMem[i] = NULL;
 		}
 	}
-
-	/* Cleanup the iiEllis subsystem. */
-	iiEllisCleanup();
-#ifdef IP2DEBUG_INIT
-	printk (KERN_DEBUG "IP2 Unloaded\n" );
-#endif
 }
 module_exit(ip2_cleanup_module);
-#endif /* MODULE */
 
 static const struct tty_operations ip2_ops = {
 	.open            = ip2_open,
@@ -494,139 +487,168 @@
 	return fw;
 }
 
-int
-ip2_loadmain(int *iop, int *irqp)
+#ifndef MODULE
+/******************************************************************************
+ *	ip2_setup:
+ *		str: kernel command line string
+ *
+ *	Can't autoprobe the boards so user must specify configuration on
+ *	kernel command line.  Sane people build it modular but the others
+ *	come here.
+ *
+ *	Alternating pairs of io,irq for up to 4 boards.
+ *		ip2=io0,irq0,io1,irq1,io2,irq2,io3,irq3
+ *
+ *		io=0 => No board
+ *		io=1 => PCI
+ *		io=2 => EISA
+ *		else => ISA I/O address
+ *
+ *		irq=0 or invalid for ISA will revert to polling mode
+ *
+ *		Any value = -1, do not overwrite compiled in value.
+ *
+ ******************************************************************************/
+static int __init ip2_setup(char *str)
+{
+	int j, ints[10];	/* 4 boards, 2 parameters + 2 */
+	unsigned int i;
+
+	str = get_options(str, ARRAY_SIZE(ints), ints);
+
+	for (i = 0, j = 1; i < 4; i++) {
+		if (j > ints[0])
+			break;
+		if (ints[j] >= 0)
+			io[i] = ints[j];
+		j++;
+		if (j > ints[0])
+			break;
+		if (ints[j] >= 0)
+			irq[i] = ints[j];
+		j++;
+	}
+	return 1;
+}
+__setup("ip2=", ip2_setup);
+#endif /* !MODULE */
+
+static int __init ip2_loadmain(void)
 {
 	int i, j, box;
 	int err = 0;
-	static int loaded;
 	i2eBordStrPtr pB = NULL;
 	int rc = -1;
-	static struct pci_dev *pci_dev_i = NULL;
+	struct pci_dev *pdev = NULL;
 	const struct firmware *fw = NULL;
 
-	ip2trace (ITRC_NO_PORT, ITRC_INIT, ITRC_ENTER, 0 );
+	if (poll_only) {
+		/* Hard lock the interrupts to zero */
+		irq[0] = irq[1] = irq[2] = irq[3] = poll_only = 0;
+	}
+
+	ip2trace(ITRC_NO_PORT, ITRC_INIT, ITRC_ENTER, 0);
 
 	/* process command line arguments to modprobe or
 		insmod i.e. iop & irqp */
 	/* irqp and iop should ALWAYS be specified now...  But we check
 		them individually just to be sure, anyways... */
-	for ( i = 0; i < IP2_MAX_BOARDS; ++i ) {
-		if (iop) {
-			ip2config.addr[i] = iop[i];
-			if (irqp) {
-				if( irqp[i] >= 0 ) {
-					ip2config.irq[i] = irqp[i];
-				} else {
-					ip2config.irq[i] = 0;
-				}
-	// This is a little bit of a hack.  If poll_only=1 on command
-	// line back in ip2.c OR all IRQs on all specified boards are
-	// explicitly set to 0, then drop to poll only mode and override
-	// PCI or EISA interrupts.  This superceeds the old hack of
-	// triggering if all interrupts were zero (like da default).
-	// Still a hack but less prone to random acts of terrorism.
-	//
-	// What we really should do, now that the IRQ default is set
-	// to -1, is to use 0 as a hard coded, do not probe.
-	//
-	//	/\/\|=mhw=|\/\/
-				poll_only |= irqp[i];
-			}
-		}
+	for (i = 0; i < IP2_MAX_BOARDS; ++i) {
+		ip2config.addr[i] = io[i];
+		if (irq[i] >= 0)
+			ip2config.irq[i] = irq[i];
+		else
+			ip2config.irq[i] = 0;
+	/* This is a little bit of a hack.  If poll_only=1 on command
+	   line back in ip2.c OR all IRQs on all specified boards are
+	   explicitly set to 0, then drop to poll only mode and override
+	   PCI or EISA interrupts.  This superceeds the old hack of
+	   triggering if all interrupts were zero (like da default).
+	   Still a hack but less prone to random acts of terrorism.
+
+	   What we really should do, now that the IRQ default is set
+	   to -1, is to use 0 as a hard coded, do not probe.
+
+		/\/\|=mhw=|\/\/
+	*/
+		poll_only |= irq[i];
 	}
 	poll_only = !poll_only;
 
 	/* Announce our presence */
-	printk( KERN_INFO "%s version %s\n", pcName, pcVersion );
-
-	// ip2 can be unloaded and reloaded for no good reason
-	// we can't let that happen here or bad things happen
-	// second load hoses board but not system - fixme later
-	if (loaded) {
-		printk( KERN_INFO "Still loaded\n" );
-		return 0;
-	}
-	loaded++;
+	printk(KERN_INFO "%s version %s\n", pcName, pcVersion);
 
 	ip2_tty_driver = alloc_tty_driver(IP2_MAX_PORTS);
 	if (!ip2_tty_driver)
 		return -ENOMEM;
 
-	/* Initialise the iiEllis subsystem. */
-	iiEllisInit();
-
-	/* Initialize arrays. */
-	memset( i2BoardPtrTable, 0, sizeof i2BoardPtrTable );
-	memset( DevTable, 0, sizeof DevTable );
-
 	/* Initialise all the boards we can find (up to the maximum). */
-	for ( i = 0; i < IP2_MAX_BOARDS; ++i ) {
-		switch ( ip2config.addr[i] ) { 
+	for (i = 0; i < IP2_MAX_BOARDS; ++i) {
+		switch (ip2config.addr[i]) {
 		case 0:	/* skip this slot even if card is present */
 			break;
 		default: /* ISA */
 		   /* ISA address must be specified */
-			if ( (ip2config.addr[i] < 0x100) || (ip2config.addr[i] > 0x3f8) ) {
-				printk ( KERN_ERR "IP2: Bad ISA board %d address %x\n",
-							 i, ip2config.addr[i] );
+			if (ip2config.addr[i] < 0x100 ||
+					ip2config.addr[i] > 0x3f8) {
+				printk(KERN_ERR "IP2: Bad ISA board %d "
+						"address %x\n", i,
+						ip2config.addr[i]);
 				ip2config.addr[i] = 0;
-			} else {
-				ip2config.type[i] = ISA;
+				break;
+			}
+			ip2config.type[i] = ISA;
 
-				/* Check for valid irq argument, set for polling if invalid */
-				if (ip2config.irq[i] && !is_valid_irq(ip2config.irq[i])) {
-					printk(KERN_ERR "IP2: Bad IRQ(%d) specified\n",ip2config.irq[i]);
-					ip2config.irq[i] = 0;// 0 is polling and is valid in that sense
-				}
+			/* Check for valid irq argument, set for polling if
+			 * invalid */
+			if (ip2config.irq[i] &&
+					!is_valid_irq(ip2config.irq[i])) {
+				printk(KERN_ERR "IP2: Bad IRQ(%d) specified\n",
+						ip2config.irq[i]);
+				/* 0 is polling and is valid in that sense */
+				ip2config.irq[i] = 0;
 			}
 			break;
 		case PCI:
 #ifdef CONFIG_PCI
-			{
-				int status;
+		{
+			u32 addr;
+			int status;
 
-				pci_dev_i = pci_get_device(PCI_VENDOR_ID_COMPUTONE,
-							  PCI_DEVICE_ID_COMPUTONE_IP2EX, pci_dev_i);
-				if (pci_dev_i != NULL) {
-					unsigned int addr;
-
-					if (pci_enable_device(pci_dev_i)) {
-						printk( KERN_ERR "IP2: can't enable PCI device at %s\n",
-							pci_name(pci_dev_i));
-						break;
-					}
-					ip2config.type[i] = PCI;
-					ip2config.pci_dev[i] = pci_dev_get(pci_dev_i);
-					status =
-					pci_read_config_dword(pci_dev_i, PCI_BASE_ADDRESS_1, &addr);
-					if ( addr & 1 ) {
-						ip2config.addr[i]=(USHORT)(addr&0xfffe);
-					} else {
-						printk( KERN_ERR "IP2: PCI I/O address error\n");
-					}
-
-//		If the PCI BIOS assigned it, lets try and use it.  If we
-//		can't acquire it or it screws up, deal with it then.
-
-//					if (!is_valid_irq(pci_irq)) {
-//						printk( KERN_ERR "IP2: Bad PCI BIOS IRQ(%d)\n",pci_irq);
-//						pci_irq = 0;
-//					}
-					ip2config.irq[i] = pci_dev_i->irq;
-				} else {	// ann error
-					ip2config.addr[i] = 0;
-					printk(KERN_ERR "IP2: PCI board %d not found\n", i);
-				} 
+			pdev = pci_get_device(PCI_VENDOR_ID_COMPUTONE,
+					PCI_DEVICE_ID_COMPUTONE_IP2EX, pdev);
+			if (pdev == NULL) {
+				ip2config.addr[i] = 0;
+				printk(KERN_ERR "IP2: PCI board %d not "
+						"found\n", i);
+				break;
 			}
+
+			if (pci_enable_device(pdev)) {
+				dev_err(&pdev->dev, "can't enable device\n");
+				break;
+			}
+			ip2config.type[i] = PCI;
+			ip2config.pci_dev[i] = pci_dev_get(pdev);
+			status = pci_read_config_dword(pdev, PCI_BASE_ADDRESS_1,
+					&addr);
+			if (addr & 1)
+				ip2config.addr[i] = (USHORT)(addr & 0xfffe);
+			else
+				dev_err(&pdev->dev, "I/O address error\n");
+
+			ip2config.irq[i] = pdev->irq;
+		}
 #else
-			printk( KERN_ERR "IP2: PCI card specified but PCI support not\n");
-			printk( KERN_ERR "IP2: configured in this kernel.\n");
-			printk( KERN_ERR "IP2: Recompile kernel with CONFIG_PCI defined!\n");
+			printk(KERN_ERR "IP2: PCI card specified but PCI "
+					"support not enabled.\n");
+			printk(KERN_ERR "IP2: Recompile kernel with CONFIG_PCI "
+					"defined!\n");
 #endif /* CONFIG_PCI */
 			break;
 		case EISA:
-			if ( (ip2config.addr[i] = find_eisa_board( Eisa_slot + 1 )) != 0) {
+			ip2config.addr[i] = find_eisa_board(Eisa_slot + 1);
+			if (ip2config.addr[i] != 0) {
 				/* Eisa_irq set as side effect, boo */
 				ip2config.type[i] = EISA;
 			} 
@@ -634,31 +656,32 @@
 			break;
 		}	/* switch */
 	}	/* for */
-	if (pci_dev_i)
-		pci_dev_put(pci_dev_i);
+	pci_dev_put(pdev);
 
-	for ( i = 0; i < IP2_MAX_BOARDS; ++i ) {
-		if ( ip2config.addr[i] ) {
+	for (i = 0; i < IP2_MAX_BOARDS; ++i) {
+		if (ip2config.addr[i]) {
 			pB = kzalloc(sizeof(i2eBordStr), GFP_KERNEL);
 			if (pB) {
 				i2BoardPtrTable[i] = pB;
-				iiSetAddress( pB, ip2config.addr[i], ii2DelayTimer );
-				iiReset( pB );
-			} else {
-				printk(KERN_ERR "IP2: board memory allocation error\n");
-			}
+				iiSetAddress(pB, ip2config.addr[i],
+						ii2DelayTimer);
+				iiReset(pB);
+			} else
+				printk(KERN_ERR "IP2: board memory allocation "
+						"error\n");
 		}
 	}
-	for ( i = 0; i < IP2_MAX_BOARDS; ++i ) {
-		if ( ( pB = i2BoardPtrTable[i] ) != NULL ) {
-			iiResetDelay( pB );
+	for (i = 0; i < IP2_MAX_BOARDS; ++i) {
+		pB = i2BoardPtrTable[i];
+		if (pB != NULL) {
+			iiResetDelay(pB);
 			break;
 		}
 	}
-	for ( i = 0; i < IP2_MAX_BOARDS; ++i ) {
+	for (i = 0; i < IP2_MAX_BOARDS; ++i) {
 		/* We don't want to request the firmware unless we have at
 		   least one board */
-		if ( i2BoardPtrTable[i] != NULL ) {
+		if (i2BoardPtrTable[i] != NULL) {
 			if (!fw)
 				fw = ip2_request_firmware();
 			if (!fw)
@@ -669,7 +692,7 @@
 	if (fw)
 		release_firmware(fw);
 
-	ip2trace (ITRC_NO_PORT, ITRC_INIT, 2, 0 );
+	ip2trace(ITRC_NO_PORT, ITRC_INIT, 2, 0);
 
 	ip2_tty_driver->owner		    = THIS_MODULE;
 	ip2_tty_driver->name                 = "ttyF";
@@ -680,20 +703,23 @@
 	ip2_tty_driver->subtype              = SERIAL_TYPE_NORMAL;
 	ip2_tty_driver->init_termios         = tty_std_termios;
 	ip2_tty_driver->init_termios.c_cflag = B9600|CS8|CREAD|HUPCL|CLOCAL;
-	ip2_tty_driver->flags                = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
+	ip2_tty_driver->flags                = TTY_DRIVER_REAL_RAW |
+		TTY_DRIVER_DYNAMIC_DEV;
 	tty_set_operations(ip2_tty_driver, &ip2_ops);
 
-	ip2trace (ITRC_NO_PORT, ITRC_INIT, 3, 0 );
+	ip2trace(ITRC_NO_PORT, ITRC_INIT, 3, 0);
 
-	/* Register the tty devices. */
-	if ( ( err = tty_register_driver ( ip2_tty_driver ) ) ) {
-		printk(KERN_ERR "IP2: failed to register tty driver (%d)\n", err);
+	err = tty_register_driver(ip2_tty_driver);
+	if (err) {
+		printk(KERN_ERR "IP2: failed to register tty driver\n");
 		put_tty_driver(ip2_tty_driver);
-		return -EINVAL;
-	} else
-	/* Register the IPL driver. */
-	if ( ( err = register_chrdev ( IP2_IPL_MAJOR, pcIpl, &ip2_ipl ) ) ) {
-		printk(KERN_ERR "IP2: failed to register IPL device (%d)\n", err );
+		return err; /* leaking resources */
+	}
+
+	err = register_chrdev(IP2_IPL_MAJOR, pcIpl, &ip2_ipl);
+	if (err) {
+		printk(KERN_ERR "IP2: failed to register IPL device (%d)\n",
+				err);
 	} else {
 		/* create the sysfs class */
 		ip2_class = class_create(THIS_MODULE, "ip2");
@@ -705,84 +731,86 @@
 	/* Register the read_procmem thing */
 	if (!proc_create("ip2mem",0,NULL,&ip2mem_proc_fops)) {
 		printk(KERN_ERR "IP2: failed to register read_procmem\n");
-	} else {
+		return -EIO; /* leaking resources */
+	}
 
-	ip2trace (ITRC_NO_PORT, ITRC_INIT, 4, 0 );
-		/* Register the interrupt handler or poll handler, depending upon the
-		 * specified interrupt.
-		 */
+	ip2trace(ITRC_NO_PORT, ITRC_INIT, 4, 0);
+	/* Register the interrupt handler or poll handler, depending upon the
+	 * specified interrupt.
+	 */
 
-		for( i = 0; i < IP2_MAX_BOARDS; ++i ) {
-			if ( 0 == ip2config.addr[i] ) {
-				continue;
-			}
+	for (i = 0; i < IP2_MAX_BOARDS; ++i) {
+		if (ip2config.addr[i] == 0)
+			continue;
 
-			if ( NULL != ( pB = i2BoardPtrTable[i] ) ) {
-				device_create_drvdata(ip2_class, NULL,
-						      MKDEV(IP2_IPL_MAJOR, 4 * i),
-						      NULL, "ipl%d", i);
-				device_create_drvdata(ip2_class, NULL,
-						      MKDEV(IP2_IPL_MAJOR, 4 * i + 1),
-						      NULL, "stat%d", i);
+		pB = i2BoardPtrTable[i];
+		if (pB != NULL) {
+			device_create_drvdata(ip2_class, NULL,
+					      MKDEV(IP2_IPL_MAJOR, 4 * i),
+					      NULL, "ipl%d", i);
+			device_create_drvdata(ip2_class, NULL,
+					      MKDEV(IP2_IPL_MAJOR, 4 * i + 1),
+					      NULL, "stat%d", i);
 
-			    for ( box = 0; box < ABS_MAX_BOXES; ++box )
-			    {
-			        for ( j = 0; j < ABS_BIGGEST_BOX; ++j )
-			        {
-				    if ( pB->i2eChannelMap[box] & (1 << j) )
-				    {
-				        tty_register_device(ip2_tty_driver,
-					    j + ABS_BIGGEST_BOX *
-						    (box+i*ABS_MAX_BOXES), NULL);
-			    	    }
-			        }
-			    }
-			}
-
-			if (poll_only) {
-//		Poll only forces driver to only use polling and
-//		to ignore the probed PCI or EISA interrupts.
-				ip2config.irq[i] = CIR_POLL;
-			}
-			if ( ip2config.irq[i] == CIR_POLL ) {
-retry:
-				if (!TimerOn) {
-					PollTimer.expires = POLL_TIMEOUT;
-					add_timer ( &PollTimer );
-					TimerOn = 1;
-					printk( KERN_INFO "IP2: polling\n");
-				}
-			} else {
-				if (have_requested_irq(ip2config.irq[i]))
-					continue;
-				rc = request_irq( ip2config.irq[i], ip2_interrupt,
-					IP2_SA_FLAGS | (ip2config.type[i] == PCI ? IRQF_SHARED : 0),
-					pcName, i2BoardPtrTable[i]);
-				if (rc) {
-					printk(KERN_ERR "IP2: an request_irq failed: error %d\n",rc);
-					ip2config.irq[i] = CIR_POLL;
-					printk( KERN_INFO "IP2: Polling %ld/sec.\n",
-							(POLL_TIMEOUT - jiffies));
-					goto retry;
-				} 
-				mark_requested_irq(ip2config.irq[i]);
-				/* Initialise the interrupt handler bottom half (aka slih). */
-			}
+			for (box = 0; box < ABS_MAX_BOXES; box++)
+				for (j = 0; j < ABS_BIGGEST_BOX; j++)
+					if (pB->i2eChannelMap[box] & (1 << j))
+						tty_register_device(
+							ip2_tty_driver,
+							j + ABS_BIGGEST_BOX *
+							(box+i*ABS_MAX_BOXES),
+							NULL);
 		}
-		for( i = 0; i < IP2_MAX_BOARDS; ++i ) {
-			if ( i2BoardPtrTable[i] ) {
-				set_irq( i, ip2config.irq[i] ); /* set and enable board interrupt */
+
+		if (poll_only) {
+			/* Poll only forces driver to only use polling and
+			   to ignore the probed PCI or EISA interrupts. */
+			ip2config.irq[i] = CIR_POLL;
+		}
+		if (ip2config.irq[i] == CIR_POLL) {
+retry:
+			if (!timer_pending(&PollTimer)) {
+				mod_timer(&PollTimer, POLL_TIMEOUT);
+				printk(KERN_INFO "IP2: polling\n");
 			}
+		} else {
+			if (have_requested_irq(ip2config.irq[i]))
+				continue;
+			rc = request_irq(ip2config.irq[i], ip2_interrupt,
+				IP2_SA_FLAGS |
+				(ip2config.type[i] == PCI ? IRQF_SHARED : 0),
+				pcName, i2BoardPtrTable[i]);
+			if (rc) {
+				printk(KERN_ERR "IP2: request_irq failed: "
+						"error %d\n", rc);
+				ip2config.irq[i] = CIR_POLL;
+				printk(KERN_INFO "IP2: Polling %ld/sec.\n",
+						(POLL_TIMEOUT - jiffies));
+				goto retry;
+			}
+			mark_requested_irq(ip2config.irq[i]);
+			/* Initialise the interrupt handler bottom half
+			 * (aka slih). */
 		}
 	}
-	ip2trace (ITRC_NO_PORT, ITRC_INIT, ITRC_RETURN, 0 );
-	goto out;
+
+	for (i = 0; i < IP2_MAX_BOARDS; ++i) {
+		if (i2BoardPtrTable[i]) {
+			/* set and enable board interrupt */
+			set_irq(i, ip2config.irq[i]);
+		}
+	}
+
+	ip2trace(ITRC_NO_PORT, ITRC_INIT, ITRC_RETURN, 0);
+
+	return 0;
 
 out_chrdev:
 	unregister_chrdev(IP2_IPL_MAJOR, "ip2");
-out:
+	/* unregister and put tty here */
 	return err;
 }
+module_init(ip2_loadmain);
 
 /******************************************************************************/
 /* Function:   ip2_init_board()                                               */
@@ -1199,9 +1227,8 @@
 {
 	int i;
 	i2eBordStrPtr  pB;
-	const int irq = 0;
 
-	ip2trace (ITRC_NO_PORT, ITRC_INTR, 99, 1, irq );
+	ip2trace(ITRC_NO_PORT, ITRC_INTR, 99, 1, 0);
 
 	/* Service just the boards on the list using this irq */
 	for( i = 0; i < i2nBoards; ++i ) {
@@ -1210,9 +1237,8 @@
 //		Only process those boards which match our IRQ.
 //			IRQ = 0 for polled boards, we won't poll "IRQ" boards
 
-		if ( pB && (pB->i2eUsingIrq == irq) ) {
+		if (pB && pB->i2eUsingIrq == 0)
 			ip2_irq_work(pB);
-		}
 	}
 
 	++irq_counter;
@@ -1250,16 +1276,12 @@
 {
 	ip2trace (ITRC_NO_PORT, ITRC_INTR, 100, 0 );
 
-	TimerOn = 0; // it's the truth but not checked in service
-
 	// Just polled boards, IRQ = 0 will hit all non-interrupt boards.
 	// It will NOT poll boards handled by hard interrupts.
 	// The issue of queued BH interrupts is handled in ip2_interrupt().
 	ip2_polled_interrupt();
 
-	PollTimer.expires = POLL_TIMEOUT;
-	add_timer( &PollTimer );
-	TimerOn = 1;
+	mod_timer(&PollTimer, POLL_TIMEOUT);
 
 	ip2trace (ITRC_NO_PORT, ITRC_INTR, ITRC_RETURN, 0 );
 }
@@ -2871,7 +2893,7 @@
 	case 13:
 		switch ( cmd ) {
 		case 64:	/* Driver - ip2stat */
-			rc = put_user(ip2_tty_driver->refcount, pIndex++ );
+			rc = put_user(-1, pIndex++ );
 			rc = put_user(irq_counter, pIndex++  );
 			rc = put_user(bh_counter, pIndex++  );
 			break;
diff --git a/drivers/char/isicom.c b/drivers/char/isicom.c
index 8f7cc19..7d30ee1 100644
--- a/drivers/char/isicom.c
+++ b/drivers/char/isicom.c
@@ -421,17 +421,16 @@
 	if (retries >= 100)
 		goto unlock;
 
+	tty = tty_port_tty_get(&port->port);
+	if (tty == NULL)
+		goto put_unlock;
+
 	for (; count > 0; count--, port++) {
 		/* port not active or tx disabled to force flow control */
 		if (!(port->port.flags & ASYNC_INITIALIZED) ||
 				!(port->status & ISI_TXOK))
 			continue;
 
-		tty = port->port.tty;
-
-		if (tty == NULL)
-			continue;
-
 		txcount = min_t(short, TX_SIZE, port->xmit_cnt);
 		if (txcount <= 0 || tty->stopped || tty->hw_stopped)
 			continue;
@@ -489,6 +488,8 @@
 			tty_wakeup(tty);
 	}
 
+put_unlock:
+	tty_kref_put(tty);
 unlock:
 	spin_unlock_irqrestore(&isi_card[card].card_lock, flags);
 	/*	schedule another tx for hopefully in about 10ms	*/
@@ -547,7 +548,7 @@
 		return IRQ_HANDLED;
 	}
 
-	tty = port->port.tty;
+	tty = tty_port_tty_get(&port->port);
 	if (tty == NULL) {
 		word_count = byte_count >> 1;
 		while (byte_count > 1) {
@@ -588,7 +589,7 @@
 			}
 
 			if (port->port.flags & ASYNC_CTS_FLOW) {
-				if (port->port.tty->hw_stopped) {
+				if (tty->hw_stopped) {
 					if (header & ISI_CTS) {
 						port->port.tty->hw_stopped = 0;
 						/* start tx ing */
@@ -597,7 +598,7 @@
 						tty_wakeup(tty);
 					}
 				} else if (!(header & ISI_CTS)) {
-					port->port.tty->hw_stopped = 1;
+					tty->hw_stopped = 1;
 					/* stop tx ing */
 					port->status &= ~(ISI_TXOK | ISI_CTS);
 				}
@@ -660,24 +661,21 @@
 	}
 	outw(0x0000, base+0x04); /* enable interrupts */
 	spin_unlock(&card->card_lock);
+	tty_kref_put(tty);
 
 	return IRQ_HANDLED;
 }
 
-static void isicom_config_port(struct isi_port *port)
+static void isicom_config_port(struct tty_struct *tty)
 {
+	struct isi_port *port = tty->driver_data;
 	struct isi_board *card = port->card;
-	struct tty_struct *tty;
 	unsigned long baud;
 	unsigned long base = card->base;
 	u16 channel_setup, channel = port->channel,
 		shift_count = card->shift_count;
 	unsigned char flow_ctrl;
 
-	tty = port->port.tty;
-
-	if (tty == NULL)
-		return;
 	/* FIXME: Switch to new tty baud API */
 	baud = C_BAUD(tty);
 	if (baud & CBAUDEX) {
@@ -690,7 +688,7 @@
 
 		/* 1,2,3,4 => 57.6, 115.2, 230, 460 kbps resp. */
 		if (baud < 1 || baud > 4)
-			port->port.tty->termios->c_cflag &= ~CBAUDEX;
+			tty->termios->c_cflag &= ~CBAUDEX;
 		else
 			baud += 15;
 	}
@@ -797,8 +795,9 @@
 	spin_unlock_irqrestore(&bp->card_lock, flags);
 }
 
-static int isicom_setup_port(struct isi_port *port)
+static int isicom_setup_port(struct tty_struct *tty)
 {
+	struct isi_port *port = tty->driver_data;
 	struct isi_board *card = port->card;
 	unsigned long flags;
 
@@ -808,8 +807,7 @@
 		return -ENOMEM;
 
 	spin_lock_irqsave(&card->card_lock, flags);
-	if (port->port.tty)
-		clear_bit(TTY_IO_ERROR, &port->port.tty->flags);
+	clear_bit(TTY_IO_ERROR, &tty->flags);
 	if (port->port.count == 1)
 		card->count++;
 
@@ -823,7 +821,7 @@
 		InterruptTheCard(card->base);
 	}
 
-	isicom_config_port(port);
+	isicom_config_port(tty);
 	port->port.flags |= ASYNC_INITIALIZED;
 	spin_unlock_irqrestore(&card->card_lock, flags);
 
@@ -934,8 +932,8 @@
 
 	port->port.count++;
 	tty->driver_data = port;
-	port->port.tty = tty;
-	error = isicom_setup_port(port);
+	tty_port_tty_set(&port->port, tty);
+	error = isicom_setup_port(tty);
 	if (error == 0)
 		error = block_til_ready(tty, filp, port);
 	return error;
@@ -955,15 +953,17 @@
 	struct isi_board *card = port->card;
 	struct tty_struct *tty;
 
-	tty = port->port.tty;
+	tty = tty_port_tty_get(&port->port);
 
-	if (!(port->port.flags & ASYNC_INITIALIZED))
+	if (!(port->port.flags & ASYNC_INITIALIZED)) {
+		tty_kref_put(tty);
 		return;
+	}
 
 	tty_port_free_xmit_buf(&port->port);
 	port->port.flags &= ~ASYNC_INITIALIZED;
 	/* 3rd October 2000 : Vinayak P Risbud */
-	port->port.tty = NULL;
+	tty_port_tty_set(&port->port, NULL);
 
 	/*Fix done by Anil .S on 30-04-2001
 	remote login through isi port has dtr toggle problem
@@ -1243,9 +1243,10 @@
 	return 0;
 }
 
-static int isicom_set_serial_info(struct isi_port *port,
-	struct serial_struct __user *info)
+static int isicom_set_serial_info(struct tty_struct *tty,
+					struct serial_struct __user *info)
 {
+	struct isi_port *port = tty->driver_data;
 	struct serial_struct newinfo;
 	int reconfig_port;
 
@@ -1276,7 +1277,7 @@
 	if (reconfig_port) {
 		unsigned long flags;
 		spin_lock_irqsave(&port->card->card_lock, flags);
-		isicom_config_port(port);
+		isicom_config_port(tty);
 		spin_unlock_irqrestore(&port->card->card_lock, flags);
 	}
 	unlock_kernel();
@@ -1318,7 +1319,7 @@
 		return isicom_get_serial_info(port, argp);
 
 	case TIOCSSERIAL:
-		return isicom_set_serial_info(port, argp);
+		return isicom_set_serial_info(tty, argp);
 
 	default:
 		return -ENOIOCTLCMD;
@@ -1341,7 +1342,7 @@
 		return;
 
 	spin_lock_irqsave(&port->card->card_lock, flags);
-	isicom_config_port(port);
+	isicom_config_port(tty);
 	spin_unlock_irqrestore(&port->card->card_lock, flags);
 
 	if ((old_termios->c_cflag & CRTSCTS) &&
@@ -1419,7 +1420,7 @@
 
 	port->port.count = 0;
 	port->port.flags &= ~ASYNC_NORMAL_ACTIVE;
-	port->port.tty = NULL;
+	tty_port_tty_set(&port->port, NULL);
 	wake_up_interruptible(&port->port.open_wait);
 }
 
diff --git a/drivers/char/istallion.c b/drivers/char/istallion.c
index 843a2af..505d7a1 100644
--- a/drivers/char/istallion.c
+++ b/drivers/char/istallion.c
@@ -623,24 +623,25 @@
 static void	stli_brdpoll(struct stlibrd *brdp, cdkhdr_t __iomem *hdrp);
 static void	stli_poll(unsigned long arg);
 static int	stli_hostcmd(struct stlibrd *brdp, struct stliport *portp);
-static int	stli_initopen(struct stlibrd *brdp, struct stliport *portp);
+static int	stli_initopen(struct tty_struct *tty, struct stlibrd *brdp, struct stliport *portp);
 static int	stli_rawopen(struct stlibrd *brdp, struct stliport *portp, unsigned long arg, int wait);
 static int	stli_rawclose(struct stlibrd *brdp, struct stliport *portp, unsigned long arg, int wait);
-static int	stli_waitcarrier(struct stlibrd *brdp, struct stliport *portp, struct file *filp);
-static int	stli_setport(struct stliport *portp);
+static int	stli_waitcarrier(struct tty_struct *tty, struct stlibrd *brdp,
+				struct stliport *portp, struct file *filp);
+static int	stli_setport(struct tty_struct *tty);
 static int	stli_cmdwait(struct stlibrd *brdp, struct stliport *portp, unsigned long cmd, void *arg, int size, int copyback);
 static void	stli_sendcmd(struct stlibrd *brdp, struct stliport *portp, unsigned long cmd, void *arg, int size, int copyback);
 static void	__stli_sendcmd(struct stlibrd *brdp, struct stliport *portp, unsigned long cmd, void *arg, int size, int copyback);
 static void	stli_dodelaycmd(struct stliport *portp, cdkctrl_t __iomem *cp);
-static void	stli_mkasyport(struct stliport *portp, asyport_t *pp, struct ktermios *tiosp);
+static void	stli_mkasyport(struct tty_struct *tty, struct stliport *portp, asyport_t *pp, struct ktermios *tiosp);
 static void	stli_mkasysigs(asysigs_t *sp, int dtr, int rts);
 static long	stli_mktiocm(unsigned long sigvalue);
 static void	stli_read(struct stlibrd *brdp, struct stliport *portp);
 static int	stli_getserial(struct stliport *portp, struct serial_struct __user *sp);
-static int	stli_setserial(struct stliport *portp, struct serial_struct __user *sp);
+static int	stli_setserial(struct tty_struct *tty, struct serial_struct __user *sp);
 static int	stli_getbrdstats(combrd_t __user *bp);
-static int	stli_getportstats(struct stliport *portp, comstats_t __user *cp);
-static int	stli_portcmdstats(struct stliport *portp);
+static int	stli_getportstats(struct tty_struct *tty, struct stliport *portp, comstats_t __user *cp);
+static int	stli_portcmdstats(struct tty_struct *tty, struct stliport *portp);
 static int	stli_clrportstats(struct stliport *portp, comstats_t __user *cp);
 static int	stli_getportstruct(struct stliport __user *arg);
 static int	stli_getbrdstruct(struct stlibrd __user *arg);
@@ -731,12 +732,16 @@
 {
 	struct stliport *portp;
 	unsigned int j;
+	struct tty_struct *tty;
 
 	for (j = 0; j < STL_MAXPORTS; j++) {
 		portp = brdp->ports[j];
 		if (portp != NULL) {
-			if (portp->port.tty != NULL)
-				tty_hangup(portp->port.tty);
+			tty = tty_port_tty_get(&portp->port);
+			if (tty != NULL) {
+				tty_hangup(tty);
+				tty_kref_put(tty);
+			}
 			kfree(portp);
 		}
 	}
@@ -824,7 +829,7 @@
  *	requires several commands to the board we will need to wait for any
  *	other open that is already initializing the port.
  */
-	portp->port.tty = tty;
+	tty_port_tty_set(&portp->port, tty);
 	tty->driver_data = portp;
 	portp->port.count++;
 
@@ -835,7 +840,7 @@
 
 	if ((portp->port.flags & ASYNC_INITIALIZED) == 0) {
 		set_bit(ST_INITIALIZING, &portp->state);
-		if ((rc = stli_initopen(brdp, portp)) >= 0) {
+		if ((rc = stli_initopen(tty, brdp, portp)) >= 0) {
 			portp->port.flags |= ASYNC_INITIALIZED;
 			clear_bit(TTY_IO_ERROR, &tty->flags);
 		}
@@ -864,7 +869,7 @@
  *	then also we might have to wait for carrier.
  */
 	if (!(filp->f_flags & O_NONBLOCK)) {
-		if ((rc = stli_waitcarrier(brdp, portp, filp)) != 0)
+		if ((rc = stli_waitcarrier(tty, brdp, portp, filp)) != 0)
 			return rc;
 	}
 	portp->port.flags |= ASYNC_NORMAL_ACTIVE;
@@ -930,7 +935,7 @@
 	stli_flushbuffer(tty);
 
 	tty->closing = 0;
-	portp->port.tty = NULL;
+	tty_port_tty_set(&portp->port, NULL);
 
 	if (portp->openwaitcnt) {
 		if (portp->close_delay)
@@ -952,9 +957,9 @@
  *	this still all happens pretty quickly.
  */
 
-static int stli_initopen(struct stlibrd *brdp, struct stliport *portp)
+static int stli_initopen(struct tty_struct *tty,
+				struct stlibrd *brdp, struct stliport *portp)
 {
-	struct tty_struct *tty;
 	asynotify_t nt;
 	asyport_t aport;
 	int rc;
@@ -969,10 +974,7 @@
 	    sizeof(asynotify_t), 0)) < 0)
 		return rc;
 
-	tty = portp->port.tty;
-	if (tty == NULL)
-		return -ENODEV;
-	stli_mkasyport(portp, &aport, tty->termios);
+	stli_mkasyport(tty, portp, &aport, tty->termios);
 	if ((rc = stli_cmdwait(brdp, portp, A_SETPORT, &aport,
 	    sizeof(asyport_t), 0)) < 0)
 		return rc;
@@ -1161,22 +1163,21 @@
  *	waiting for the command to complete - so must have user context.
  */
 
-static int stli_setport(struct stliport *portp)
+static int stli_setport(struct tty_struct *tty)
 {
+	struct stliport *portp = tty->driver_data;
 	struct stlibrd *brdp;
 	asyport_t aport;
 
 	if (portp == NULL)
 		return -ENODEV;
-	if (portp->port.tty == NULL)
-		return -ENODEV;
 	if (portp->brdnr >= stli_nrbrds)
 		return -ENODEV;
 	brdp = stli_brds[portp->brdnr];
 	if (brdp == NULL)
 		return -ENODEV;
 
-	stli_mkasyport(portp, &aport, portp->port.tty->termios);
+	stli_mkasyport(tty, portp, &aport, tty->termios);
 	return(stli_cmdwait(brdp, portp, A_SETPORT, &aport, sizeof(asyport_t), 0));
 }
 
@@ -1187,7 +1188,8 @@
  *	maybe because if we are clocal then we don't need to wait...
  */
 
-static int stli_waitcarrier(struct stlibrd *brdp, struct stliport *portp, struct file *filp)
+static int stli_waitcarrier(struct tty_struct *tty, struct stlibrd *brdp,
+				struct stliport *portp, struct file *filp)
 {
 	unsigned long flags;
 	int rc, doclocal;
@@ -1195,7 +1197,7 @@
 	rc = 0;
 	doclocal = 0;
 
-	if (portp->port.tty->termios->c_cflag & CLOCAL)
+	if (tty->termios->c_cflag & CLOCAL)
 		doclocal++;
 
 	spin_lock_irqsave(&stli_lock, flags);
@@ -1373,8 +1375,6 @@
 	stli_txcookrealsize = 0;
 	stli_txcooktty = NULL;
 
-	if (tty == NULL)
-		return;
 	if (cooktty == NULL)
 		return;
 	if (tty != cooktty)
@@ -1572,10 +1572,11 @@
  *	just quietly ignore any requests to change irq, etc.
  */
 
-static int stli_setserial(struct stliport *portp, struct serial_struct __user *sp)
+static int stli_setserial(struct tty_struct *tty, struct serial_struct __user *sp)
 {
 	struct serial_struct sio;
 	int rc;
+	struct stliport *portp = tty->driver_data;
 
 	if (copy_from_user(&sio, sp, sizeof(struct serial_struct)))
 		return -EFAULT;
@@ -1594,7 +1595,7 @@
 	portp->closing_wait = sio.closing_wait;
 	portp->custom_divisor = sio.custom_divisor;
 
-	if ((rc = stli_setport(portp)) < 0)
+	if ((rc = stli_setport(tty)) < 0)
 		return rc;
 	return 0;
 }
@@ -1685,17 +1686,17 @@
 		rc = stli_getserial(portp, argp);
 		break;
 	case TIOCSSERIAL:
-		rc = stli_setserial(portp, argp);
+		rc = stli_setserial(tty, argp);
 		break;
 	case STL_GETPFLAG:
 		rc = put_user(portp->pflag, (unsigned __user *)argp);
 		break;
 	case STL_SETPFLAG:
 		if ((rc = get_user(portp->pflag, (unsigned __user *)argp)) == 0)
-			stli_setport(portp);
+			stli_setport(tty);
 		break;
 	case COM_GETPORTSTATS:
-		rc = stli_getportstats(portp, argp);
+		rc = stli_getportstats(tty, portp, argp);
 		break;
 	case COM_CLRPORTSTATS:
 		rc = stli_clrportstats(portp, argp);
@@ -1729,8 +1730,6 @@
 	struct ktermios *tiosp;
 	asyport_t aport;
 
-	if (tty == NULL)
-		return;
 	portp = tty->driver_data;
 	if (portp == NULL)
 		return;
@@ -1742,7 +1741,7 @@
 
 	tiosp = tty->termios;
 
-	stli_mkasyport(portp, &aport, tiosp);
+	stli_mkasyport(tty, portp, &aport, tiosp);
 	stli_cmdwait(brdp, portp, A_SETPORT, &aport, sizeof(asyport_t), 0);
 	stli_mkasysigs(&portp->asig, ((tiosp->c_cflag & CBAUD) ? 1 : 0), -1);
 	stli_cmdwait(brdp, portp, A_SETSIGNALS, &portp->asig,
@@ -1854,7 +1853,7 @@
 	clear_bit(ST_TXBUSY, &portp->state);
 	clear_bit(ST_RXSTOP, &portp->state);
 	set_bit(TTY_IO_ERROR, &tty->flags);
-	portp->port.tty = NULL;
+	tty_port_tty_set(&portp->port, NULL);
 	portp->port.flags &= ~ASYNC_NORMAL_ACTIVE;
 	portp->port.count = 0;
 	spin_unlock_irqrestore(&stli_lock, flags);
@@ -1935,8 +1934,6 @@
 	struct stliport *portp;
 	unsigned long tend;
 
-	if (tty == NULL)
-		return;
 	portp = tty->driver_data;
 	if (portp == NULL)
 		return;
@@ -1998,7 +1995,7 @@
 	char *sp, *uart;
 	int rc, cnt;
 
-	rc = stli_portcmdstats(portp);
+	rc = stli_portcmdstats(NULL, portp);
 
 	uart = "UNKNOWN";
 	if (brdp->state & BST_STARTED) {
@@ -2188,7 +2185,7 @@
 
 	if (test_bit(ST_RXSTOP, &portp->state))
 		return;
-	tty = portp->port.tty;
+	tty = tty_port_tty_get(&portp->port);
 	if (tty == NULL)
 		return;
 
@@ -2230,6 +2227,7 @@
 		set_bit(ST_RXING, &portp->state);
 
 	tty_schedule_flip(tty);
+	tty_kref_put(tty);
 }
 
 /*****************************************************************************/
@@ -2362,7 +2360,7 @@
 	if (ap->notify) {
 		nt = ap->changed;
 		ap->notify = 0;
-		tty = portp->port.tty;
+		tty = tty_port_tty_get(&portp->port);
 
 		if (nt.signal & SG_DCD) {
 			oldsigs = portp->sigs;
@@ -2399,6 +2397,7 @@
 				tty_schedule_flip(tty);
 			}
 		}
+		tty_kref_put(tty);
 
 		if (nt.data & DT_RXBUSY) {
 			donerx++;
@@ -2535,14 +2534,15 @@
  *	the slave.
  */
 
-static void stli_mkasyport(struct stliport *portp, asyport_t *pp, struct ktermios *tiosp)
+static void stli_mkasyport(struct tty_struct *tty, struct stliport *portp,
+				asyport_t *pp, struct ktermios *tiosp)
 {
 	memset(pp, 0, sizeof(asyport_t));
 
 /*
  *	Start of by setting the baud, char size, parity and stop bit info.
  */
-	pp->baudout = tty_get_baud_rate(portp->port.tty);
+	pp->baudout = tty_get_baud_rate(tty);
 	if ((tiosp->c_cflag & CBAUD) == B38400) {
 		if ((portp->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
 			pp->baudout = 57600;
@@ -2695,7 +2695,7 @@
 			printk("STALLION: failed to allocate port structure\n");
 			continue;
 		}
-
+		tty_port_init(&portp->port);
 		portp->magic = STLI_PORTMAGIC;
 		portp->portnr = i;
 		portp->brdnr = brdp->brdnr;
@@ -4220,7 +4220,7 @@
  *	what port to get stats for (used through board control device).
  */
 
-static int stli_portcmdstats(struct stliport *portp)
+static int stli_portcmdstats(struct tty_struct *tty, struct stliport *portp)
 {
 	unsigned long	flags;
 	struct stlibrd	*brdp;
@@ -4249,15 +4249,15 @@
 	stli_comstats.flags = portp->port.flags;
 
 	spin_lock_irqsave(&brd_lock, flags);
-	if (portp->port.tty != NULL) {
-		if (portp->port.tty->driver_data == portp) {
-			stli_comstats.ttystate = portp->port.tty->flags;
+	if (tty != NULL) {
+		if (portp->port.tty == tty) {
+			stli_comstats.ttystate = tty->flags;
 			stli_comstats.rxbuffered = -1;
-			if (portp->port.tty->termios != NULL) {
-				stli_comstats.cflags = portp->port.tty->termios->c_cflag;
-				stli_comstats.iflags = portp->port.tty->termios->c_iflag;
-				stli_comstats.oflags = portp->port.tty->termios->c_oflag;
-				stli_comstats.lflags = portp->port.tty->termios->c_lflag;
+			if (tty->termios != NULL) {
+				stli_comstats.cflags = tty->termios->c_cflag;
+				stli_comstats.iflags = tty->termios->c_iflag;
+				stli_comstats.oflags = tty->termios->c_oflag;
+				stli_comstats.lflags = tty->termios->c_lflag;
 			}
 		}
 	}
@@ -4294,7 +4294,8 @@
  *	what port to get stats for (used through board control device).
  */
 
-static int stli_getportstats(struct stliport *portp, comstats_t __user *cp)
+static int stli_getportstats(struct tty_struct *tty, struct stliport *portp,
+							comstats_t __user *cp)
 {
 	struct stlibrd *brdp;
 	int rc;
@@ -4312,7 +4313,7 @@
 	if (!brdp)
 		return -ENODEV;
 
-	if ((rc = stli_portcmdstats(portp)) < 0)
+	if ((rc = stli_portcmdstats(tty, portp)) < 0)
 		return rc;
 
 	return copy_to_user(cp, &stli_comstats, sizeof(comstats_t)) ?
@@ -4427,7 +4428,7 @@
 
 	switch (cmd) {
 	case COM_GETPORTSTATS:
-		rc = stli_getportstats(NULL, argp);
+		rc = stli_getportstats(NULL, NULL, argp);
 		done++;
 		break;
 	case COM_CLRPORTSTATS:
diff --git a/drivers/char/moxa.c b/drivers/char/moxa.c
index d3d7864e..5df4003 100644
--- a/drivers/char/moxa.c
+++ b/drivers/char/moxa.c
@@ -205,7 +205,7 @@
 static void moxa_poll(unsigned long);
 static void moxa_set_tty_param(struct tty_struct *, struct ktermios *);
 static void moxa_setup_empty_event(struct tty_struct *);
-static void moxa_shut_down(struct moxa_port *);
+static void moxa_shut_down(struct tty_struct *);
 /*
  * moxa board interface functions:
  */
@@ -217,7 +217,7 @@
 static void MoxaPortFlowCtrl(struct moxa_port *, int, int, int, int, int);
 static int MoxaPortLineStatus(struct moxa_port *);
 static void MoxaPortFlushData(struct moxa_port *, int);
-static int MoxaPortWriteData(struct moxa_port *, const unsigned char *, int);
+static int MoxaPortWriteData(struct tty_struct *, const unsigned char *, int);
 static int MoxaPortReadData(struct moxa_port *);
 static int MoxaPortTxQueue(struct moxa_port *);
 static int MoxaPortRxQueue(struct moxa_port *);
@@ -332,6 +332,7 @@
 		for (i = 0; i < MAX_BOARDS; i++) {
 			p = moxa_boards[i].ports;
 			for (j = 0; j < MAX_PORTS_PER_BOARD; j++, p++, argm++) {
+				struct tty_struct *ttyp;
 				memset(&tmp, 0, sizeof(tmp));
 				if (!moxa_boards[i].ready)
 					goto copy;
@@ -344,10 +345,12 @@
 				if (status & 4)
 					tmp.dcd = 1;
 
-				if (!p->port.tty || !p->port.tty->termios)
+				ttyp = tty_port_tty_get(&p->port);
+				if (!ttyp || !ttyp->termios)
 					tmp.cflag = p->cflag;
 				else
-					tmp.cflag = p->port.tty->termios->c_cflag;
+					tmp.cflag = ttyp->termios->c_cflag;
+				tty_kref_put(tty);
 copy:
 				if (copy_to_user(argm, &tmp, sizeof(tmp))) {
 					mutex_unlock(&moxa_openlock);
@@ -880,8 +883,14 @@
 
 	/* pci hot-un-plug support */
 	for (a = 0; a < brd->numPorts; a++)
-		if (brd->ports[a].port.flags & ASYNC_INITIALIZED)
-			tty_hangup(brd->ports[a].port.tty);
+		if (brd->ports[a].port.flags & ASYNC_INITIALIZED) {
+			struct tty_struct *tty = tty_port_tty_get(
+						&brd->ports[a].port);
+			if (tty) {
+				tty_hangup(tty);
+				tty_kref_put(tty);
+			}
+		}
 	while (1) {
 		opened = 0;
 		for (a = 0; a < brd->numPorts; a++)
@@ -1096,13 +1105,14 @@
 module_init(moxa_init);
 module_exit(moxa_exit);
 
-static void moxa_close_port(struct moxa_port *ch)
+static void moxa_close_port(struct tty_struct *tty)
 {
-	moxa_shut_down(ch);
+	struct moxa_port *ch = tty->driver_data;
+	moxa_shut_down(tty);
 	MoxaPortFlushData(ch, 2);
 	ch->port.flags &= ~ASYNC_NORMAL_ACTIVE;
-	ch->port.tty->driver_data = NULL;
-	ch->port.tty = NULL;
+	tty->driver_data = NULL;
+	tty_port_tty_set(&ch->port, NULL);
 }
 
 static int moxa_block_till_ready(struct tty_struct *tty, struct file *filp,
@@ -1161,7 +1171,7 @@
 	ch = &brd->ports[port % MAX_PORTS_PER_BOARD];
 	ch->port.count++;
 	tty->driver_data = ch;
-	ch->port.tty = tty;
+	tty_port_tty_set(&ch->port, tty);
 	if (!(ch->port.flags & ASYNC_INITIALIZED)) {
 		ch->statusflags = 0;
 		moxa_set_tty_param(tty, tty->termios);
@@ -1179,7 +1189,7 @@
 	if (retval) {
 		if (ch->port.count) /* 0 means already hung up... */
 			if (--ch->port.count == 0)
-				moxa_close_port(ch);
+				moxa_close_port(tty);
 	} else
 		ch->port.flags |= ASYNC_NORMAL_ACTIVE;
 	mutex_unlock(&moxa_openlock);
@@ -1219,7 +1229,7 @@
 		tty_wait_until_sent(tty, 30 * HZ);	/* 30 seconds timeout */
 	}
 
-	moxa_close_port(ch);
+	moxa_close_port(tty);
 unlock:
 	mutex_unlock(&moxa_openlock);
 }
@@ -1234,7 +1244,7 @@
 		return 0;
 
 	spin_lock_bh(&moxa_lock);
-	len = MoxaPortWriteData(ch, buf, count);
+	len = MoxaPortWriteData(tty, buf, count);
 	spin_unlock_bh(&moxa_lock);
 
 	ch->statusflags |= LOWWAIT;
@@ -1409,7 +1419,7 @@
 		return;
 	}
 	ch->port.count = 0;
-	moxa_close_port(ch);
+	moxa_close_port(tty);
 	mutex_unlock(&moxa_openlock);
 
 	wake_up_interruptible(&ch->port.open_wait);
@@ -1417,11 +1427,14 @@
 
 static void moxa_new_dcdstate(struct moxa_port *p, u8 dcd)
 {
+	struct tty_struct *tty;
 	dcd = !!dcd;
 
-	if (dcd != p->DCDState && p->port.tty && C_CLOCAL(p->port.tty)) {
-		if (!dcd)
-			tty_hangup(p->port.tty);
+	if (dcd != p->DCDState) {
+		tty = tty_port_tty_get(&p->port);
+		if (tty && C_CLOCAL(tty) && !dcd)
+			tty_hangup(tty);
+		tty_kref_put(tty);
 	}
 	p->DCDState = dcd;
 }
@@ -1429,7 +1442,7 @@
 static int moxa_poll_port(struct moxa_port *p, unsigned int handle,
 		u16 __iomem *ip)
 {
-	struct tty_struct *tty = p->port.tty;
+	struct tty_struct *tty = tty_port_tty_get(&p->port);
 	void __iomem *ofsAddr;
 	unsigned int inited = p->port.flags & ASYNC_INITIALIZED;
 	u16 intr;
@@ -1476,6 +1489,7 @@
 		tty_insert_flip_char(tty, 0, TTY_BREAK);
 		tty_schedule_flip(tty);
 	}
+	tty_kref_put(tty);
 
 	if (intr & IntrLine)
 		moxa_new_dcdstate(p, readb(ofsAddr + FlagStat) & DCD_state);
@@ -1560,9 +1574,9 @@
 	spin_unlock_bh(&moxa_lock);
 }
 
-static void moxa_shut_down(struct moxa_port *ch)
+static void moxa_shut_down(struct tty_struct *tty)
 {
-	struct tty_struct *tp = ch->port.tty;
+	struct moxa_port *ch = tty->driver_data;
 
 	if (!(ch->port.flags & ASYNC_INITIALIZED))
 		return;
@@ -1572,7 +1586,7 @@
 	/*
 	 * If we're a modem control device and HUPCL is on, drop RTS & DTR.
 	 */
-	if (C_HUPCL(tp))
+	if (C_HUPCL(tty))
 		MoxaPortLineCtrl(ch, 0, 0);
 
 	spin_lock_bh(&moxa_lock);
@@ -1953,9 +1967,10 @@
 	return val;
 }
 
-static int MoxaPortWriteData(struct moxa_port *port,
+static int MoxaPortWriteData(struct tty_struct *tty,
 		const unsigned char *buffer, int len)
 {
+	struct moxa_port *port = tty->driver_data;
 	void __iomem *baseAddr, *ofsAddr, *ofs;
 	unsigned int c, total;
 	u16 head, tail, tx_mask, spage, epage;
diff --git a/drivers/char/mxser.c b/drivers/char/mxser.c
index b638403..8beef50 100644
--- a/drivers/char/mxser.c
+++ b/drivers/char/mxser.c
@@ -610,15 +610,13 @@
 	return 0;
 }
 
-static int mxser_set_baud(struct mxser_port *info, long newspd)
+static int mxser_set_baud(struct tty_struct *tty, long newspd)
 {
+	struct mxser_port *info = tty->driver_data;
 	int quot = 0, baud;
 	unsigned char cval;
 
-	if (!info->port.tty || !info->port.tty->termios)
-		return -1;
-
-	if (!(info->ioaddr))
+	if (!info->ioaddr)
 		return -1;
 
 	if (newspd > info->max_baud)
@@ -626,13 +624,13 @@
 
 	if (newspd == 134) {
 		quot = 2 * info->baud_base / 269;
-		tty_encode_baud_rate(info->port.tty, 134, 134);
+		tty_encode_baud_rate(tty, 134, 134);
 	} else if (newspd) {
 		quot = info->baud_base / newspd;
 		if (quot == 0)
 			quot = 1;
 		baud = info->baud_base/quot;
-		tty_encode_baud_rate(info->port.tty, baud, baud);
+		tty_encode_baud_rate(tty, baud, baud);
 	} else {
 		quot = 0;
 	}
@@ -658,7 +656,7 @@
 	outb(cval, info->ioaddr + UART_LCR);	/* reset DLAB */
 
 #ifdef BOTHER
-	if (C_BAUD(info->port.tty) == BOTHER) {
+	if (C_BAUD(tty) == BOTHER) {
 		quot = info->baud_base % newspd;
 		quot *= 8;
 		if (quot % newspd > newspd / 2) {
@@ -679,21 +677,20 @@
  * This routine is called to set the UART divisor registers to match
  * the specified baud rate for a serial port.
  */
-static int mxser_change_speed(struct mxser_port *info,
-		struct ktermios *old_termios)
+static int mxser_change_speed(struct tty_struct *tty,
+					struct ktermios *old_termios)
 {
+	struct mxser_port *info = tty->driver_data;
 	unsigned cflag, cval, fcr;
 	int ret = 0;
 	unsigned char status;
 
-	if (!info->port.tty || !info->port.tty->termios)
-		return ret;
-	cflag = info->port.tty->termios->c_cflag;
-	if (!(info->ioaddr))
+	cflag = tty->termios->c_cflag;
+	if (!info->ioaddr)
 		return ret;
 
-	if (mxser_set_baud_method[info->port.tty->index] == 0)
-		mxser_set_baud(info, tty_get_baud_rate(info->port.tty));
+	if (mxser_set_baud_method[tty->index] == 0)
+		mxser_set_baud(tty, tty_get_baud_rate(tty));
 
 	/* byte size and parity */
 	switch (cflag & CSIZE) {
@@ -762,9 +759,9 @@
 			info->MCR |= UART_MCR_AFE;
 		} else {
 			status = inb(info->ioaddr + UART_MSR);
-			if (info->port.tty->hw_stopped) {
+			if (tty->hw_stopped) {
 				if (status & UART_MSR_CTS) {
-					info->port.tty->hw_stopped = 0;
+					tty->hw_stopped = 0;
 					if (info->type != PORT_16550A &&
 							!info->board->chip_flag) {
 						outb(info->IER & ~UART_IER_THRI,
@@ -774,11 +771,11 @@
 						outb(info->IER, info->ioaddr +
 								UART_IER);
 					}
-					tty_wakeup(info->port.tty);
+					tty_wakeup(tty);
 				}
 			} else {
 				if (!(status & UART_MSR_CTS)) {
-					info->port.tty->hw_stopped = 1;
+					tty->hw_stopped = 1;
 					if ((info->type != PORT_16550A) &&
 							(!info->board->chip_flag)) {
 						info->IER &= ~UART_IER_THRI;
@@ -804,21 +801,21 @@
 	 * Set up parity check flag
 	 */
 	info->read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR;
-	if (I_INPCK(info->port.tty))
+	if (I_INPCK(tty))
 		info->read_status_mask |= UART_LSR_FE | UART_LSR_PE;
-	if (I_BRKINT(info->port.tty) || I_PARMRK(info->port.tty))
+	if (I_BRKINT(tty) || I_PARMRK(tty))
 		info->read_status_mask |= UART_LSR_BI;
 
 	info->ignore_status_mask = 0;
 
-	if (I_IGNBRK(info->port.tty)) {
+	if (I_IGNBRK(tty)) {
 		info->ignore_status_mask |= UART_LSR_BI;
 		info->read_status_mask |= UART_LSR_BI;
 		/*
 		 * If we're ignore parity and break indicators, ignore
 		 * overruns too.  (For real raw support).
 		 */
-		if (I_IGNPAR(info->port.tty)) {
+		if (I_IGNPAR(tty)) {
 			info->ignore_status_mask |=
 						UART_LSR_OE |
 						UART_LSR_PE |
@@ -830,16 +827,16 @@
 		}
 	}
 	if (info->board->chip_flag) {
-		mxser_set_must_xon1_value(info->ioaddr, START_CHAR(info->port.tty));
-		mxser_set_must_xoff1_value(info->ioaddr, STOP_CHAR(info->port.tty));
-		if (I_IXON(info->port.tty)) {
+		mxser_set_must_xon1_value(info->ioaddr, START_CHAR(tty));
+		mxser_set_must_xoff1_value(info->ioaddr, STOP_CHAR(tty));
+		if (I_IXON(tty)) {
 			mxser_enable_must_rx_software_flow_control(
 					info->ioaddr);
 		} else {
 			mxser_disable_must_rx_software_flow_control(
 					info->ioaddr);
 		}
-		if (I_IXOFF(info->port.tty)) {
+		if (I_IXOFF(tty)) {
 			mxser_enable_must_tx_software_flow_control(
 					info->ioaddr);
 		} else {
@@ -855,7 +852,8 @@
 	return ret;
 }
 
-static void mxser_check_modem_status(struct mxser_port *port, int status)
+static void mxser_check_modem_status(struct tty_struct *tty,
+				struct mxser_port *port, int status)
 {
 	/* update input line counters */
 	if (status & UART_MSR_TERI)
@@ -874,10 +872,11 @@
 			wake_up_interruptible(&port->port.open_wait);
 	}
 
+	tty = tty_port_tty_get(&port->port);
 	if (port->port.flags & ASYNC_CTS_FLOW) {
-		if (port->port.tty->hw_stopped) {
+		if (tty->hw_stopped) {
 			if (status & UART_MSR_CTS) {
-				port->port.tty->hw_stopped = 0;
+				tty->hw_stopped = 0;
 
 				if ((port->type != PORT_16550A) &&
 						(!port->board->chip_flag)) {
@@ -887,11 +886,11 @@
 					outb(port->IER, port->ioaddr +
 							UART_IER);
 				}
-				tty_wakeup(port->port.tty);
+				tty_wakeup(tty);
 			}
 		} else {
 			if (!(status & UART_MSR_CTS)) {
-				port->port.tty->hw_stopped = 1;
+				tty->hw_stopped = 1;
 				if (port->type != PORT_16550A &&
 						!port->board->chip_flag) {
 					port->IER &= ~UART_IER_THRI;
@@ -903,8 +902,9 @@
 	}
 }
 
-static int mxser_startup(struct mxser_port *info)
+static int mxser_startup(struct tty_struct *tty)
 {
+	struct mxser_port *info = tty->driver_data;
 	unsigned long page;
 	unsigned long flags;
 
@@ -921,8 +921,7 @@
 	}
 
 	if (!info->ioaddr || !info->type) {
-		if (info->port.tty)
-			set_bit(TTY_IO_ERROR, &info->port.tty->flags);
+		set_bit(TTY_IO_ERROR, &tty->flags);
 		free_page(page);
 		spin_unlock_irqrestore(&info->slock, flags);
 		return 0;
@@ -952,8 +951,8 @@
 	if (inb(info->ioaddr + UART_LSR) == 0xff) {
 		spin_unlock_irqrestore(&info->slock, flags);
 		if (capable(CAP_SYS_ADMIN)) {
-			if (info->port.tty)
-				set_bit(TTY_IO_ERROR, &info->port.tty->flags);
+			if (tty)
+				set_bit(TTY_IO_ERROR, &tty->flags);
 			return 0;
 		} else
 			return -ENODEV;
@@ -991,14 +990,13 @@
 	(void) inb(info->ioaddr + UART_IIR);
 	(void) inb(info->ioaddr + UART_MSR);
 
-	if (info->port.tty)
-		clear_bit(TTY_IO_ERROR, &info->port.tty->flags);
+	clear_bit(TTY_IO_ERROR, &tty->flags);
 	info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
 
 	/*
 	 * and set the speed of the serial port
 	 */
-	mxser_change_speed(info, NULL);
+	mxser_change_speed(tty, NULL);
 	info->port.flags |= ASYNC_INITIALIZED;
 	spin_unlock_irqrestore(&info->slock, flags);
 
@@ -1009,8 +1007,9 @@
  * This routine will shutdown a serial port; interrupts maybe disabled, and
  * DTR is dropped if the hangup on close termio flag is on.
  */
-static void mxser_shutdown(struct mxser_port *info)
+static void mxser_shutdown(struct tty_struct *tty)
 {
+	struct mxser_port *info = tty->driver_data;
 	unsigned long flags;
 
 	if (!(info->port.flags & ASYNC_INITIALIZED))
@@ -1035,7 +1034,7 @@
 	info->IER = 0;
 	outb(0x00, info->ioaddr + UART_IER);
 
-	if (!info->port.tty || (info->port.tty->termios->c_cflag & HUPCL))
+	if (tty->termios->c_cflag & HUPCL)
 		info->MCR &= ~(UART_MCR_DTR | UART_MCR_RTS);
 	outb(info->MCR, info->ioaddr + UART_MCR);
 
@@ -1051,8 +1050,7 @@
 	/* read data port to reset things */
 	(void) inb(info->ioaddr + UART_RX);
 
-	if (info->port.tty)
-		set_bit(TTY_IO_ERROR, &info->port.tty->flags);
+	set_bit(TTY_IO_ERROR, &tty->flags);
 
 	info->port.flags &= ~ASYNC_INITIALIZED;
 
@@ -1084,14 +1082,14 @@
 		return -ENODEV;
 
 	tty->driver_data = info;
-	info->port.tty = tty;
+	tty_port_tty_set(&info->port, tty);
 	/*
 	 * Start up serial port
 	 */
 	spin_lock_irqsave(&info->slock, flags);
 	info->port.count++;
 	spin_unlock_irqrestore(&info->slock, flags);
-	retval = mxser_startup(info);
+	retval = mxser_startup(tty);
 	if (retval)
 		return retval;
 
@@ -1209,13 +1207,13 @@
 				break;
 		}
 	}
-	mxser_shutdown(info);
+	mxser_shutdown(tty);
 
 	mxser_flush_buffer(tty);
 	tty_ldisc_flush(tty);
 
 	tty->closing = 0;
-	info->port.tty = NULL;
+	tty_port_tty_set(&info->port, NULL);
 	if (info->port.blocked_open) {
 		if (info->port.close_delay)
 			schedule_timeout_interruptible(info->port.close_delay);
@@ -1337,12 +1335,13 @@
  * friends of mxser_ioctl()
  * ------------------------------------------------------------
  */
-static int mxser_get_serial_info(struct mxser_port *info,
+static int mxser_get_serial_info(struct tty_struct *tty,
 		struct serial_struct __user *retinfo)
 {
+	struct mxser_port *info = tty->driver_data;
 	struct serial_struct tmp = {
 		.type = info->type,
-		.line = info->port.tty->index,
+		.line = tty->index,
 		.port = info->ioaddr,
 		.irq = info->board->irq,
 		.flags = info->port.flags,
@@ -1357,9 +1356,10 @@
 	return 0;
 }
 
-static int mxser_set_serial_info(struct mxser_port *info,
+static int mxser_set_serial_info(struct tty_struct *tty,
 		struct serial_struct __user *new_info)
 {
+	struct mxser_port *info = tty->driver_data;
 	struct serial_struct new_serial;
 	speed_t baud;
 	unsigned long sl_flags;
@@ -1393,14 +1393,14 @@
 				(new_serial.flags & ASYNC_FLAGS));
 		info->port.close_delay = new_serial.close_delay * HZ / 100;
 		info->port.closing_wait = new_serial.closing_wait * HZ / 100;
-		info->port.tty->low_latency =
-				(info->port.flags & ASYNC_LOW_LATENCY) ? 1 : 0;
+		tty->low_latency = (info->port.flags & ASYNC_LOW_LATENCY)
+								? 1 : 0;
 		if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST &&
 				(new_serial.baud_base != info->baud_base ||
 				new_serial.custom_divisor !=
 				info->custom_divisor)) {
 			baud = new_serial.baud_base / new_serial.custom_divisor;
-			tty_encode_baud_rate(info->port.tty, baud, baud);
+			tty_encode_baud_rate(tty, baud, baud);
 		}
 	}
 
@@ -1411,11 +1411,11 @@
 	if (info->port.flags & ASYNC_INITIALIZED) {
 		if (flags != (info->port.flags & ASYNC_SPD_MASK)) {
 			spin_lock_irqsave(&info->slock, sl_flags);
-			mxser_change_speed(info, NULL);
+			mxser_change_speed(tty, NULL);
 			spin_unlock_irqrestore(&info->slock, sl_flags);
 		}
 	} else
-		retval = mxser_startup(info);
+		retval = mxser_startup(tty);
 
 	return retval;
 }
@@ -1461,7 +1461,7 @@
 	spin_lock_irqsave(&info->slock, flags);
 	status = inb(info->ioaddr + UART_MSR);
 	if (status & UART_MSR_ANY_DELTA)
-		mxser_check_modem_status(info, status);
+		mxser_check_modem_status(tty, info, status);
 	spin_unlock_irqrestore(&info->slock, flags);
 	return ((control & UART_MCR_RTS) ? TIOCM_RTS : 0) |
 		    ((control & UART_MCR_DTR) ? TIOCM_DTR : 0) |
@@ -1606,6 +1606,7 @@
 static int mxser_ioctl_special(unsigned int cmd, void __user *argp)
 {
 	struct mxser_port *port;
+	struct tty_struct *tty;
 	int result, status;
 	unsigned int i, j;
 	int ret = 0;
@@ -1643,12 +1644,14 @@
 
 				if (!port->ioaddr)
 					goto copy;
+				
+				tty = tty_port_tty_get(&port->port);
 
-				if (!port->port.tty || !port->port.tty->termios)
+				if (!tty || !tty->termios)
 					ms.cflag = port->normal_termios.c_cflag;
 				else
-					ms.cflag = port->port.tty->termios->c_cflag;
-
+					ms.cflag = tty->termios->c_cflag;
+				tty_kref_put(tty);
 				status = inb(port->ioaddr + UART_MSR);
 				if (status & UART_MSR_DCD)
 					ms.dcd = 1;
@@ -1704,15 +1707,18 @@
 				me->up_txcnt[p] = port->mon_data.up_txcnt;
 				me->modem_status[p] =
 					port->mon_data.modem_status;
-				me->baudrate[p] = tty_get_baud_rate(port->port.tty);
+				tty = tty_port_tty_get(&port->port);
 
-				if (!port->port.tty || !port->port.tty->termios) {
+				if (!tty || !tty->termios) {
 					cflag = port->normal_termios.c_cflag;
 					iflag = port->normal_termios.c_iflag;
+					me->baudrate[p] = tty_termios_baud_rate(&port->normal_termios);
 				} else {
-					cflag = port->port.tty->termios->c_cflag;
-					iflag = port->port.tty->termios->c_iflag;
+					cflag = tty->termios->c_cflag;
+					iflag = tty->termios->c_iflag;
+					me->baudrate[p] = tty_get_baud_rate(tty);
 				}
+				tty_kref_put(tty);
 
 				me->databits[p] = cflag & CSIZE;
 				me->stopbits[p] = cflag & CSTOPB;
@@ -1822,12 +1828,12 @@
 	switch (cmd) {
 	case TIOCGSERIAL:
 		lock_kernel();
-		retval = mxser_get_serial_info(info, argp);
+		retval = mxser_get_serial_info(tty, argp);
 		unlock_kernel();
 		return retval;
 	case TIOCSSERIAL:
 		lock_kernel();
-		retval = mxser_set_serial_info(info, argp);
+		retval = mxser_set_serial_info(tty, argp);
 		unlock_kernel();
 		return retval;
 	case TIOCSERGETLSR:	/* Get line status register */
@@ -1896,7 +1902,7 @@
 
 		lock_kernel();
 		status = mxser_get_msr(info->ioaddr, 1, tty->index);
-		mxser_check_modem_status(info, status);
+		mxser_check_modem_status(tty, info, status);
 
 		mcr = inb(info->ioaddr + UART_MCR);
 		if (mcr & MOXA_MUST_MCR_XON_FLAG)
@@ -1909,7 +1915,7 @@
 		else
 			info->mon_data.hold_reason |= NPPI_NOTIFY_XOFFXENT;
 
-		if (info->port.tty->hw_stopped)
+		if (tty->hw_stopped)
 			info->mon_data.hold_reason |= NPPI_NOTIFY_CTSHOLD;
 		else
 			info->mon_data.hold_reason &= ~NPPI_NOTIFY_CTSHOLD;
@@ -1958,7 +1964,7 @@
 		}
 	}
 
-	if (info->port.tty->termios->c_cflag & CRTSCTS) {
+	if (tty->termios->c_cflag & CRTSCTS) {
 		info->MCR &= ~UART_MCR_RTS;
 		outb(info->MCR, info->ioaddr + UART_MCR);
 	}
@@ -1995,7 +2001,7 @@
 		}
 	}
 
-	if (info->port.tty->termios->c_cflag & CRTSCTS) {
+	if (tty->termios->c_cflag & CRTSCTS) {
 		info->MCR |= UART_MCR_RTS;
 		outb(info->MCR, info->ioaddr + UART_MCR);
 	}
@@ -2040,7 +2046,7 @@
 	unsigned long flags;
 
 	spin_lock_irqsave(&info->slock, flags);
-	mxser_change_speed(info, old_termios);
+	mxser_change_speed(tty, old_termios);
 	spin_unlock_irqrestore(&info->slock, flags);
 
 	if ((old_termios->c_cflag & CRTSCTS) &&
@@ -2138,10 +2144,10 @@
 	struct mxser_port *info = tty->driver_data;
 
 	mxser_flush_buffer(tty);
-	mxser_shutdown(info);
+	mxser_shutdown(tty);
 	info->port.count = 0;
 	info->port.flags &= ~ASYNC_NORMAL_ACTIVE;
-	info->port.tty = NULL;
+	tty_port_tty_set(&info->port, NULL);
 	wake_up_interruptible(&info->port.open_wait);
 }
 
@@ -2164,9 +2170,9 @@
 	return 0;
 }
 
-static void mxser_receive_chars(struct mxser_port *port, int *status)
+static void mxser_receive_chars(struct tty_struct *tty,
+				struct mxser_port *port, int *status)
 {
-	struct tty_struct *tty = port->port.tty;
 	unsigned char ch, gdl;
 	int ignored = 0;
 	int cnt = 0;
@@ -2174,9 +2180,8 @@
 	int max = 256;
 
 	recv_room = tty->receive_room;
-	if ((recv_room == 0) && (!port->ldisc_stop_rx))
+	if (recv_room == 0 && !port->ldisc_stop_rx)
 		mxser_stoprx(tty);
-
 	if (port->board->chip_flag != MOXA_OTHER_UART) {
 
 		if (*status & UART_LSR_SPECIAL)
@@ -2253,7 +2258,7 @@
 	} while (*status & UART_LSR_DR);
 
 end_intr:
-	mxvar_log.rxcnt[port->port.tty->index] += cnt;
+	mxvar_log.rxcnt[tty->index] += cnt;
 	port->mon_data.rxcnt += cnt;
 	port->mon_data.up_rxcnt += cnt;
 
@@ -2267,14 +2272,14 @@
 	spin_lock(&port->slock);
 }
 
-static void mxser_transmit_chars(struct mxser_port *port)
+static void mxser_transmit_chars(struct tty_struct *tty, struct mxser_port *port)
 {
 	int count, cnt;
 
 	if (port->x_char) {
 		outb(port->x_char, port->ioaddr + UART_TX);
 		port->x_char = 0;
-		mxvar_log.txcnt[port->port.tty->index]++;
+		mxvar_log.txcnt[tty->index]++;
 		port->mon_data.txcnt++;
 		port->mon_data.up_txcnt++;
 		port->icount.tx++;
@@ -2284,8 +2289,8 @@
 	if (port->port.xmit_buf == NULL)
 		return;
 
-	if ((port->xmit_cnt <= 0) || port->port.tty->stopped ||
-			(port->port.tty->hw_stopped &&
+	if (port->xmit_cnt <= 0 || tty->stopped ||
+			(tty->hw_stopped &&
 			(port->type != PORT_16550A) &&
 			(!port->board->chip_flag))) {
 		port->IER &= ~UART_IER_THRI;
@@ -2302,14 +2307,14 @@
 		if (--port->xmit_cnt <= 0)
 			break;
 	} while (--count > 0);
-	mxvar_log.txcnt[port->port.tty->index] += (cnt - port->xmit_cnt);
+	mxvar_log.txcnt[tty->index] += (cnt - port->xmit_cnt);
 
 	port->mon_data.txcnt += (cnt - port->xmit_cnt);
 	port->mon_data.up_txcnt += (cnt - port->xmit_cnt);
 	port->icount.tx += (cnt - port->xmit_cnt);
 
-	if (port->xmit_cnt < WAKEUP_CHARS)
-		tty_wakeup(port->port.tty);
+	if (port->xmit_cnt < WAKEUP_CHARS && tty)
+		tty_wakeup(tty);
 
 	if (port->xmit_cnt <= 0) {
 		port->IER &= ~UART_IER_THRI;
@@ -2328,6 +2333,7 @@
 	int max, irqbits, bits, msr;
 	unsigned int int_cnt, pass_counter = 0;
 	int handled = IRQ_NONE;
+	struct tty_struct *tty;
 
 	for (i = 0; i < MXSER_BOARDS; i++)
 		if (dev_id == &mxser_boards[i]) {
@@ -2360,13 +2366,15 @@
 				if (iir & UART_IIR_NO_INT)
 					break;
 				iir &= MOXA_MUST_IIR_MASK;
-				if (!port->port.tty ||
+				tty = tty_port_tty_get(&port->port);
+				if (!tty ||
 						(port->port.flags & ASYNC_CLOSING) ||
 						!(port->port.flags &
 							ASYNC_INITIALIZED)) {
 					status = inb(port->ioaddr + UART_LSR);
 					outb(0x27, port->ioaddr + UART_FCR);
 					inb(port->ioaddr + UART_MSR);
+					tty_kref_put(tty);
 					break;
 				}
 
@@ -2387,27 +2395,28 @@
 					    iir == MOXA_MUST_IIR_RDA ||
 					    iir == MOXA_MUST_IIR_RTO ||
 					    iir == MOXA_MUST_IIR_LSR)
-						mxser_receive_chars(port,
+						mxser_receive_chars(tty, port,
 								&status);
 
 				} else {
 					status &= port->read_status_mask;
 					if (status & UART_LSR_DR)
-						mxser_receive_chars(port,
+						mxser_receive_chars(tty, port,
 								&status);
 				}
 				msr = inb(port->ioaddr + UART_MSR);
 				if (msr & UART_MSR_ANY_DELTA)
-					mxser_check_modem_status(port, msr);
+					mxser_check_modem_status(tty, port, msr);
 
 				if (port->board->chip_flag) {
 					if (iir == 0x02 && (status &
 								UART_LSR_THRE))
-						mxser_transmit_chars(port);
+						mxser_transmit_chars(tty, port);
 				} else {
 					if (status & UART_LSR_THRE)
-						mxser_transmit_chars(port);
+						mxser_transmit_chars(tty, port);
 				}
+				tty_kref_put(tty);
 			} while (int_cnt++ < MXSER_ISR_PASS_LIMIT);
 			spin_unlock(&port->slock);
 		}
diff --git a/drivers/char/n_hdlc.c b/drivers/char/n_hdlc.c
index 69ec639..bacb3e2 100644
--- a/drivers/char/n_hdlc.c
+++ b/drivers/char/n_hdlc.c
@@ -764,7 +764,7 @@
 		break;
 
 	default:
-		error = n_tty_ioctl (tty, file, cmd, arg);
+		error = n_tty_ioctl_helper(tty, file, cmd, arg);
 		break;
 	}
 	return error;
diff --git a/drivers/char/n_r3964.c b/drivers/char/n_r3964.c
index ae377aa4..4a8215a 100644
--- a/drivers/char/n_r3964.c
+++ b/drivers/char/n_r3964.c
@@ -372,14 +372,8 @@
 static void put_char(struct r3964_info *pInfo, unsigned char ch)
 {
 	struct tty_struct *tty = pInfo->tty;
-
-	if (tty == NULL)
-		return;
-
 	/* FIXME: put_char should not be called from an IRQ */
-	if (tty->ops->put_char) {
-		tty->ops->put_char(tty, ch);
-	}
+	tty_put_char(tty, ch);
 	pInfo->bcc ^= ch;
 }
 
diff --git a/drivers/char/n_tty.c b/drivers/char/n_tty.c
index 708c2b1..efbfe961 100644
--- a/drivers/char/n_tty.c
+++ b/drivers/char/n_tty.c
@@ -26,7 +26,7 @@
  *
  * 2002/03/18   Implemented n_tty_wakeup to send SIGIO POLL_OUTs to
  *		waiting writing processes-Sapan Bhatia <sapan@corewars.org>.
- *		Also fixed a bug in BLOCKING mode where write_chan returns
+ *		Also fixed a bug in BLOCKING mode where n_tty_write returns
  *		EAGAIN
  */
 
@@ -99,6 +99,7 @@
 
 static void n_tty_set_room(struct tty_struct *tty)
 {
+	/* tty->read_cnt is not read locked ? */
 	int	left = N_TTY_BUF_SIZE - tty->read_cnt - 1;
 
 	/*
@@ -121,6 +122,16 @@
 	}
 }
 
+/**
+ *	put_tty_queue		-	add character to tty
+ *	@c: character
+ *	@tty: tty device
+ *
+ *	Add a character to the tty read_buf queue. This is done under the
+ *	read_lock to serialize character addition and also to protect us
+ *	against parallel reads or flushes
+ */
+
 static void put_tty_queue(unsigned char c, struct tty_struct *tty)
 {
 	unsigned long flags;
@@ -137,14 +148,11 @@
  *	check_unthrottle	-	allow new receive data
  *	@tty; tty device
  *
- *	Check whether to call the driver.unthrottle function.
- *	We test the TTY_THROTTLED bit first so that it always
- *	indicates the current state. The decision about whether
- *	it is worth allowing more input has been taken by the caller.
+ *	Check whether to call the driver unthrottle functions
+ *
  *	Can sleep, may be called under the atomic_read_lock mutex but
  *	this is not guaranteed.
  */
-
 static void check_unthrottle(struct tty_struct *tty)
 {
 	if (tty->count)
@@ -158,6 +166,8 @@
  *	Reset the read buffer counters, clear the flags,
  *	and make sure the driver is unthrottled. Called
  *	from n_tty_open() and n_tty_flush_buffer().
+ *
+ *	Locking: tty_read_lock for read fields.
  */
 static void reset_buffer_flags(struct tty_struct *tty)
 {
@@ -181,7 +191,7 @@
  *	at hangup) or when the N_TTY line discipline internally has to
  *	clean the pending queue (for example some signals).
  *
- *	Locking: ctrl_lock
+ *	Locking: ctrl_lock, read_lock.
  */
 
 static void n_tty_flush_buffer(struct tty_struct *tty)
@@ -207,6 +217,8 @@
  *
  *	Report the number of characters buffered to be delivered to user
  *	at this instant in time.
+ *
+ *	Locking: read_lock
  */
 
 static ssize_t n_tty_chars_in_buffer(struct tty_struct *tty)
@@ -346,7 +358,7 @@
  *	the simple cases normally found and helps to generate blocks of
  *	symbols for the console driver and thus improve performance.
  *
- *	Called from write_chan under the tty layer write lock. Relies
+ *	Called from n_tty_write under the tty layer write lock. Relies
  *	on lock_kernel for the tty->column state.
  */
 
@@ -410,6 +422,8 @@
  *
  *	Echo user input back onto the screen. This must be called only when
  *	L_ECHO(tty) is true. Called from the driver receive_buf path.
+ *
+ *	Relies on BKL for tty column locking
  */
 
 static void echo_char(unsigned char c, struct tty_struct *tty)
@@ -422,6 +436,12 @@
 		opost(c, tty);
 }
 
+/**
+ *	finsh_erasing		-	complete erase
+ *	@tty: tty doing the erase
+ *
+ *	Relies on BKL for tty column locking
+ */
 static inline void finish_erasing(struct tty_struct *tty)
 {
 	if (tty->erasing) {
@@ -439,6 +459,8 @@
  *	Perform erase and necessary output when an erase character is
  *	present in the stream from the driver layer. Handles the complexities
  *	of UTF-8 multibyte symbols.
+ *
+ *	Locking: read_lock for tty buffers, BKL for column/erasing state
  */
 
 static void eraser(unsigned char c, struct tty_struct *tty)
@@ -447,6 +469,7 @@
 	int head, seen_alnums, cnt;
 	unsigned long flags;
 
+	/* FIXME: locking needed ? */
 	if (tty->read_head == tty->canon_head) {
 		/* opost('\a', tty); */		/* what do you think? */
 		return;
@@ -481,6 +504,7 @@
 	}
 
 	seen_alnums = 0;
+	/* FIXME: Locking ?? */
 	while (tty->read_head != tty->canon_head) {
 		head = tty->read_head;
 
@@ -583,6 +607,8 @@
  *	may caus terminal flushing to take place according to the termios
  *	settings and character used. Called from the driver receive_buf
  *	path so serialized.
+ *
+ *	Locking: ctrl_lock, read_lock (both via flush buffer)
  */
 
 static inline void isig(int sig, struct tty_struct *tty, int flush)
@@ -1007,12 +1033,26 @@
  *	and is protected from re-entry by the tty layer. The user is
  *	guaranteed that this function will not be re-entered or in progress
  *	when the ldisc is closed.
+ *
+ *	Locking: Caller holds tty->termios_mutex
  */
 
 static void n_tty_set_termios(struct tty_struct *tty, struct ktermios *old)
 {
-	if (!tty)
-		return;
+	int canon_change = 1;
+	BUG_ON(!tty);
+
+	if (old)
+		canon_change = (old->c_lflag ^ tty->termios->c_lflag) & ICANON;
+	if (canon_change) {
+		memset(&tty->read_flags, 0, sizeof tty->read_flags);
+		tty->canon_head = tty->read_tail;
+		tty->canon_data = 0;
+		tty->erasing = 0;
+	}
+
+	if (canon_change && !L_ICANON(tty) && tty->read_cnt)
+		wake_up_interruptible(&tty->read_wait);
 
 	tty->icanon = (L_ICANON(tty) != 0);
 	if (test_bit(TTY_HW_COOK_IN, &tty->flags)) {
@@ -1143,7 +1183,7 @@
  *	@b: user data
  *	@nr: size of data
  *
- *	Helper function to speed up read_chan.  It is only called when
+ *	Helper function to speed up n_tty_read.  It is only called when
  *	ICANON is off; it copies characters straight from the tty queue to
  *	user space directly.  It can be profitably called twice; once to
  *	drain the space from the tail pointer to the (physical) end of the
@@ -1210,7 +1250,7 @@
 	if (file->f_op->write != redirected_tty_write &&
 	    current->signal->tty == tty) {
 		if (!tty->pgrp)
-			printk(KERN_ERR "read_chan: no tty->pgrp!\n");
+			printk(KERN_ERR "n_tty_read: no tty->pgrp!\n");
 		else if (task_pgrp(current) != tty->pgrp) {
 			if (is_ignored(SIGTTIN) ||
 			    is_current_pgrp_orphaned())
@@ -1225,7 +1265,7 @@
 
 
 /**
- *	read_chan		-	read function for tty
+ *	n_tty_read		-	read function for tty
  *	@tty: tty device
  *	@file: file object
  *	@buf: userspace buffer pointer
@@ -1239,7 +1279,7 @@
  *	This code must be sure never to sleep through a hangup.
  */
 
-static ssize_t read_chan(struct tty_struct *tty, struct file *file,
+static ssize_t n_tty_read(struct tty_struct *tty, struct file *file,
 			 unsigned char __user *buf, size_t nr)
 {
 	unsigned char __user *b = buf;
@@ -1254,10 +1294,7 @@
 
 do_it_again:
 
-	if (!tty->read_buf) {
-		printk(KERN_ERR "n_tty_read_chan: read_buf == NULL?!?\n");
-		return -EIO;
-	}
+	BUG_ON(!tty->read_buf);
 
 	c = job_control(tty, file);
 	if (c < 0)
@@ -1444,7 +1481,7 @@
 }
 
 /**
- *	write_chan		-	write function for tty
+ *	n_tty_write		-	write function for tty
  *	@tty: tty device
  *	@file: file object
  *	@buf: userspace buffer pointer
@@ -1458,7 +1495,7 @@
  *	This code must be sure never to sleep through a hangup.
  */
 
-static ssize_t write_chan(struct tty_struct *tty, struct file *file,
+static ssize_t n_tty_write(struct tty_struct *tty, struct file *file,
 			  const unsigned char *buf, size_t nr)
 {
 	const unsigned char *b = buf;
@@ -1532,7 +1569,7 @@
 }
 
 /**
- *	normal_poll		-	poll method for N_TTY
+ *	n_tty_poll		-	poll method for N_TTY
  *	@tty: terminal device
  *	@file: file accessing it
  *	@wait: poll table
@@ -1545,7 +1582,7 @@
  *	Called without the kernel lock held - fine
  */
 
-static unsigned int normal_poll(struct tty_struct *tty, struct file *file,
+static unsigned int n_tty_poll(struct tty_struct *tty, struct file *file,
 							poll_table *wait)
 {
 	unsigned int mask = 0;
@@ -1573,6 +1610,44 @@
 	return mask;
 }
 
+static unsigned long inq_canon(struct tty_struct *tty)
+{
+	int nr, head, tail;
+
+	if (!tty->canon_data)
+		return 0;
+	head = tty->canon_head;
+	tail = tty->read_tail;
+	nr = (head - tail) & (N_TTY_BUF_SIZE-1);
+	/* Skip EOF-chars.. */
+	while (head != tail) {
+		if (test_bit(tail, tty->read_flags) &&
+		    tty->read_buf[tail] == __DISABLED_CHAR)
+			nr--;
+		tail = (tail+1) & (N_TTY_BUF_SIZE-1);
+	}
+	return nr;
+}
+
+static int n_tty_ioctl(struct tty_struct *tty, struct file *file,
+		       unsigned int cmd, unsigned long arg)
+{
+	int retval;
+
+	switch (cmd) {
+	case TIOCOUTQ:
+		return put_user(tty_chars_in_buffer(tty), (int __user *) arg);
+	case TIOCINQ:
+		/* FIXME: Locking */
+		retval = tty->read_cnt;
+		if (L_ICANON(tty))
+			retval = inq_canon(tty);
+		return put_user(retval, (unsigned int __user *) arg);
+	default:
+		return n_tty_ioctl_helper(tty, file, cmd, arg);
+	}
+}
+
 struct tty_ldisc_ops tty_ldisc_N_TTY = {
 	.magic           = TTY_LDISC_MAGIC,
 	.name            = "n_tty",
@@ -1580,11 +1655,11 @@
 	.close           = n_tty_close,
 	.flush_buffer    = n_tty_flush_buffer,
 	.chars_in_buffer = n_tty_chars_in_buffer,
-	.read            = read_chan,
-	.write           = write_chan,
+	.read            = n_tty_read,
+	.write           = n_tty_write,
 	.ioctl           = n_tty_ioctl,
 	.set_termios     = n_tty_set_termios,
-	.poll            = normal_poll,
+	.poll            = n_tty_poll,
 	.receive_buf     = n_tty_receive_buf,
 	.write_wakeup    = n_tty_write_wakeup
 };
diff --git a/drivers/char/nozomi.c b/drivers/char/nozomi.c
index 66a0f93..9a34a19 100644
--- a/drivers/char/nozomi.c
+++ b/drivers/char/nozomi.c
@@ -1599,7 +1599,10 @@
 	return 0;
 }
 
-/* Called when the userspace process close the tty, /dev/noz*. */
+/* Called when the userspace process close the tty, /dev/noz*. Also
+   called immediately if ntty_open fails in which case tty->driver_data
+   will be NULL an we exit by the first return */
+
 static void ntty_close(struct tty_struct *tty, struct file *file)
 {
 	struct nozomi *dc = get_dc_by_tty(tty);
diff --git a/drivers/char/pcmcia/cm4000_cs.c b/drivers/char/pcmcia/cm4000_cs.c
index f070ae7..1c5bf9989 100644
--- a/drivers/char/pcmcia/cm4000_cs.c
+++ b/drivers/char/pcmcia/cm4000_cs.c
@@ -1759,65 +1759,40 @@
 
 /*==== Interface to PCMCIA Layer =======================================*/
 
+static int cm4000_config_check(struct pcmcia_device *p_dev,
+			       cistpl_cftable_entry_t *cfg,
+			       cistpl_cftable_entry_t *dflt,
+			       unsigned int vcc,
+			       void *priv_data)
+{
+	if (!cfg->io.nwin)
+		return -ENODEV;
+
+	/* Get the IOaddr */
+	p_dev->io.BasePort1 = cfg->io.win[0].base;
+	p_dev->io.NumPorts1 = cfg->io.win[0].len;
+	p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
+	if (!(cfg->io.flags & CISTPL_IO_8BIT))
+		p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_16;
+	if (!(cfg->io.flags & CISTPL_IO_16BIT))
+		p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
+	p_dev->io.IOAddrLines = cfg->io.flags & CISTPL_IO_LINES_MASK;
+
+	return pcmcia_request_io(p_dev, &p_dev->io);
+}
+
 static int cm4000_config(struct pcmcia_device * link, int devno)
 {
 	struct cm4000_dev *dev;
-	tuple_t tuple;
-	cisparse_t parse;
-	u_char buf[64];
-	int fail_fn, fail_rc;
-	int rc;
 
 	/* read the config-tuples */
-	tuple.Attributes = 0;
-	tuple.TupleData = buf;
-	tuple.TupleDataMax = sizeof(buf);
-	tuple.TupleOffset = 0;
-
-	link->io.BasePort2 = 0;
-	link->io.NumPorts2 = 0;
-	link->io.Attributes2 = 0;
-	tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
-	for (rc = pcmcia_get_first_tuple(link, &tuple);
-	     rc == CS_SUCCESS; rc = pcmcia_get_next_tuple(link, &tuple)) {
-
-		rc = pcmcia_get_tuple_data(link, &tuple);
-		if (rc != CS_SUCCESS)
-			continue;
-		rc = pcmcia_parse_tuple(link, &tuple, &parse);
-		if (rc != CS_SUCCESS)
-			continue;
-
-		link->conf.ConfigIndex = parse.cftable_entry.index;
-
-		if (!parse.cftable_entry.io.nwin)
-			continue;
-
-		/* Get the IOaddr */
-		link->io.BasePort1 = parse.cftable_entry.io.win[0].base;
-		link->io.NumPorts1 = parse.cftable_entry.io.win[0].len;
-		link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
-		if (!(parse.cftable_entry.io.flags & CISTPL_IO_8BIT))
-			link->io.Attributes1 = IO_DATA_PATH_WIDTH_16;
-		if (!(parse.cftable_entry.io.flags & CISTPL_IO_16BIT))
-			link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
-		link->io.IOAddrLines = parse.cftable_entry.io.flags
-		    & CISTPL_IO_LINES_MASK;
-
-		rc = pcmcia_request_io(link, &link->io);
-		if (rc == CS_SUCCESS)
-			break;	/* we are done */
-	}
-	if (rc != CS_SUCCESS)
+	if (pcmcia_loop_config(link, cm4000_config_check, NULL))
 		goto cs_release;
 
 	link->conf.IntType = 00000002;
 
-	if ((fail_rc =
-	     pcmcia_request_configuration(link, &link->conf)) != CS_SUCCESS) {
-		fail_fn = RequestConfiguration;
+	if (pcmcia_request_configuration(link, &link->conf))
 		goto cs_release;
-	}
 
 	dev = link->priv;
 	sprintf(dev->node.dev_name, DEVICE_NAME "%d", devno);
diff --git a/drivers/char/pcmcia/cm4040_cs.c b/drivers/char/pcmcia/cm4040_cs.c
index 0b5934b..2d7c906 100644
--- a/drivers/char/pcmcia/cm4040_cs.c
+++ b/drivers/char/pcmcia/cm4040_cs.c
@@ -526,65 +526,49 @@
 	return;
 }
 
+static int cm4040_config_check(struct pcmcia_device *p_dev,
+			       cistpl_cftable_entry_t *cfg,
+			       cistpl_cftable_entry_t *dflt,
+			       unsigned int vcc,
+			       void *priv_data)
+{
+	int rc;
+	if (!cfg->io.nwin)
+		return -ENODEV;
+
+	/* Get the IOaddr */
+	p_dev->io.BasePort1 = cfg->io.win[0].base;
+	p_dev->io.NumPorts1 = cfg->io.win[0].len;
+	p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
+	if (!(cfg->io.flags & CISTPL_IO_8BIT))
+		p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_16;
+	if (!(cfg->io.flags & CISTPL_IO_16BIT))
+		p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
+	p_dev->io.IOAddrLines = cfg->io.flags & CISTPL_IO_LINES_MASK;
+
+	rc = pcmcia_request_io(p_dev, &p_dev->io);
+	dev_printk(KERN_INFO, &handle_to_dev(p_dev),
+		   "pcmcia_request_io returned 0x%x\n", rc);
+	return rc;
+}
+
+
 static int reader_config(struct pcmcia_device *link, int devno)
 {
 	struct reader_dev *dev;
-	tuple_t tuple;
-	cisparse_t parse;
-	u_char buf[64];
-	int fail_fn, fail_rc;
-	int rc;
-
-	tuple.Attributes = 0;
-	tuple.TupleData = buf;
-	tuple.TupleDataMax = sizeof(buf);
- 	tuple.TupleOffset = 0;
+	int fail_rc;
 
 	link->io.BasePort2 = 0;
 	link->io.NumPorts2 = 0;
 	link->io.Attributes2 = 0;
-	tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
-	for (rc = pcmcia_get_first_tuple(link, &tuple);
-	     rc == CS_SUCCESS;
-	     rc = pcmcia_get_next_tuple(link, &tuple)) {
-		rc = pcmcia_get_tuple_data(link, &tuple);
-		if (rc != CS_SUCCESS)
-			continue;
-		rc = pcmcia_parse_tuple(link, &tuple, &parse);
-		if (rc != CS_SUCCESS)
-			continue;
 
-		link->conf.ConfigIndex = parse.cftable_entry.index;
-
-		if (!parse.cftable_entry.io.nwin)
-			continue;
-
-		link->io.BasePort1 = parse.cftable_entry.io.win[0].base;
-		link->io.NumPorts1 = parse.cftable_entry.io.win[0].len;
-		link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
-		if (!(parse.cftable_entry.io.flags & CISTPL_IO_8BIT))
-			link->io.Attributes1 = IO_DATA_PATH_WIDTH_16;
-		if (!(parse.cftable_entry.io.flags & CISTPL_IO_16BIT))
-			link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
-		link->io.IOAddrLines = parse.cftable_entry.io.flags
-						& CISTPL_IO_LINES_MASK;
-		rc = pcmcia_request_io(link, &link->io);
-
-		dev_printk(KERN_INFO, &handle_to_dev(link), "foo");
-		if (rc == CS_SUCCESS)
-			break;
-		else
-			dev_printk(KERN_INFO, &handle_to_dev(link),
-				   "pcmcia_request_io failed 0x%x\n", rc);
-	}
-	if (rc != CS_SUCCESS)
+	if (pcmcia_loop_config(link, cm4040_config_check, NULL))
 		goto cs_release;
 
 	link->conf.IntType = 00000002;
 
-	if ((fail_rc = pcmcia_request_configuration(link,&link->conf))
-								!=CS_SUCCESS) {
-		fail_fn = RequestConfiguration;
+	fail_rc = pcmcia_request_configuration(link, &link->conf);
+	if (fail_rc != 0) {
 		dev_printk(KERN_INFO, &handle_to_dev(link),
 			   "pcmcia_request_configuration failed 0x%x\n",
 			   fail_rc);
diff --git a/drivers/char/pcmcia/ipwireless/main.c b/drivers/char/pcmcia/ipwireless/main.c
index 5eca7a9..5216fce 100644
--- a/drivers/char/pcmcia/ipwireless/main.c
+++ b/drivers/char/pcmcia/ipwireless/main.c
@@ -65,9 +65,9 @@
 	struct ipw_dev *ipw = container_of(work_reboot, struct ipw_dev,
 			work_reboot);
 	struct pcmcia_device *link = ipw->link;
-	int ret = pccard_reset_card(link->socket);
+	int ret = pcmcia_reset_card(link->socket);
 
-	if (ret != CS_SUCCESS)
+	if (ret != 0)
 		cs_error(link, ResetCard, ret);
 }
 
@@ -83,7 +83,6 @@
 {
 	struct pcmcia_device *link = ipw->link;
 	int ret;
-	config_info_t conf;
 	tuple_t tuple;
 	unsigned short buf[64];
 	cisparse_t parse;
@@ -105,7 +104,7 @@
 	while (ret == 0) {
 		ret = pcmcia_get_tuple_data(link, &tuple);
 
-		if (ret != CS_SUCCESS) {
+		if (ret != 0) {
 			cs_error(link, GetTupleData, ret);
 			goto exit0;
 		}
@@ -116,21 +115,21 @@
 
 	ret = pcmcia_get_first_tuple(link, &tuple);
 
-	if (ret != CS_SUCCESS) {
+	if (ret != 0) {
 		cs_error(link, GetFirstTuple, ret);
 		goto exit0;
 	}
 
 	ret = pcmcia_get_tuple_data(link, &tuple);
 
-	if (ret != CS_SUCCESS) {
+	if (ret != 0) {
 		cs_error(link, GetTupleData, ret);
 		goto exit0;
 	}
 
-	ret = pcmcia_parse_tuple(link, &tuple, &parse);
+	ret = pcmcia_parse_tuple(&tuple, &parse);
 
-	if (ret != CS_SUCCESS) {
+	if (ret != 0) {
 		cs_error(link, ParseTuple, ret);
 		goto exit0;
 	}
@@ -152,21 +151,21 @@
 
 	ret = pcmcia_get_first_tuple(link, &tuple);
 
-	if (ret != CS_SUCCESS) {
+	if (ret != 0) {
 		cs_error(link, GetFirstTuple, ret);
 		goto exit0;
 	}
 
 	ret = pcmcia_get_tuple_data(link, &tuple);
 
-	if (ret != CS_SUCCESS) {
+	if (ret != 0) {
 		cs_error(link, GetTupleData, ret);
 		goto exit0;
 	}
 
-	ret = pcmcia_parse_tuple(link, &tuple, &parse);
+	ret = pcmcia_parse_tuple(&tuple, &parse);
 
-	if (ret != CS_SUCCESS) {
+	if (ret != 0) {
 		cs_error(link, GetTupleData, ret);
 		goto exit0;
 	}
@@ -181,7 +180,7 @@
 
 	ret = pcmcia_request_io(link, &link->io);
 
-	if (ret != CS_SUCCESS) {
+	if (ret != 0) {
 		cs_error(link, RequestIO, ret);
 		goto exit0;
 	}
@@ -195,21 +194,21 @@
 
 	ret = pcmcia_get_first_tuple(link, &tuple);
 
-	if (ret != CS_SUCCESS) {
+	if (ret != 0) {
 		cs_error(link, GetFirstTuple, ret);
 		goto exit1;
 	}
 
 	ret = pcmcia_get_tuple_data(link, &tuple);
 
-	if (ret != CS_SUCCESS) {
+	if (ret != 0) {
 		cs_error(link, GetTupleData, ret);
 		goto exit1;
 	}
 
-	ret = pcmcia_parse_tuple(link, &tuple, &parse);
+	ret = pcmcia_parse_tuple(&tuple, &parse);
 
-	if (ret != CS_SUCCESS) {
+	if (ret != 0) {
 		cs_error(link, ParseTuple, ret);
 		goto exit1;
 	}
@@ -227,7 +226,7 @@
 		ret = pcmcia_request_window(&link, &ipw->request_common_memory,
 				&ipw->handle_common_memory);
 
-		if (ret != CS_SUCCESS) {
+		if (ret != 0) {
 			cs_error(link, RequestWindow, ret);
 			goto exit1;
 		}
@@ -239,7 +238,7 @@
 		ret = pcmcia_map_mem_page(ipw->handle_common_memory,
 				&memreq_common_memory);
 
-		if (ret != CS_SUCCESS) {
+		if (ret != 0) {
 			cs_error(link, MapMemPage, ret);
 			goto exit1;
 		}
@@ -261,7 +260,7 @@
 		ret = pcmcia_request_window(&link, &ipw->request_attr_memory,
 				&ipw->handle_attr_memory);
 
-		if (ret != CS_SUCCESS) {
+		if (ret != 0) {
 			cs_error(link, RequestWindow, ret);
 			goto exit2;
 		}
@@ -272,7 +271,7 @@
 		ret = pcmcia_map_mem_page(ipw->handle_attr_memory,
 				&memreq_attr_memory);
 
-		if (ret != CS_SUCCESS) {
+		if (ret != 0) {
 			cs_error(link, MapMemPage, ret);
 			goto exit2;
 		}
@@ -292,20 +291,11 @@
 
 	ret = pcmcia_request_irq(link, &link->irq);
 
-	if (ret != CS_SUCCESS) {
+	if (ret != 0) {
 		cs_error(link, RequestIRQ, ret);
 		goto exit3;
 	}
 
-	/* Look up current Vcc */
-
-	ret = pcmcia_get_configuration_info(link, &conf);
-
-	if (ret != CS_SUCCESS) {
-		cs_error(link, GetConfigurationInfo, ret);
-		goto exit4;
-	}
-
 	printk(KERN_INFO IPWIRELESS_PCCARD_NAME ": Card type %s\n",
 			ipw->is_v2_card ? "V2/V3" : "V1");
 	printk(KERN_INFO IPWIRELESS_PCCARD_NAME
@@ -341,7 +331,7 @@
 	 */
 	ret = pcmcia_request_configuration(link, &link->conf);
 
-	if (ret != CS_SUCCESS) {
+	if (ret != 0) {
 		cs_error(link, RequestConfiguration, ret);
 		goto exit4;
 	}
diff --git a/drivers/char/pcmcia/ipwireless/tty.c b/drivers/char/pcmcia/ipwireless/tty.c
index 3a23e76..569f2f7 100644
--- a/drivers/char/pcmcia/ipwireless/tty.c
+++ b/drivers/char/pcmcia/ipwireless/tty.c
@@ -276,6 +276,7 @@
 	struct ipw_tty *tty = linux_tty->driver_data;
 	int room;
 
+	/* FIXME: Exactly how is the tty object locked here .. */
 	if (!tty)
 		return -ENODEV;
 
@@ -397,6 +398,7 @@
 static int ipw_tiocmget(struct tty_struct *linux_tty, struct file *file)
 {
 	struct ipw_tty *tty = linux_tty->driver_data;
+	/* FIXME: Exactly how is the tty object locked here .. */
 
 	if (!tty)
 		return -ENODEV;
@@ -412,6 +414,7 @@
 	     unsigned int set, unsigned int clear)
 {
 	struct ipw_tty *tty = linux_tty->driver_data;
+	/* FIXME: Exactly how is the tty object locked here .. */
 
 	if (!tty)
 		return -ENODEV;
@@ -433,6 +436,8 @@
 	if (!tty->open_count)
 		return -EINVAL;
 
+	/* FIXME: Exactly how is the tty object locked here .. */
+
 	switch (cmd) {
 	case TIOCGSERIAL:
 		return ipwireless_get_serial_info(tty, (void __user *) arg);
@@ -467,13 +472,6 @@
 			}
 			return 0;
 
-		case TCGETS:
-		case TCGETA:
-			return n_tty_ioctl(linux_tty, file, cmd, arg);
-
-		case TCFLSH:
-			return n_tty_ioctl(linux_tty, file, cmd, arg);
-
 		case FIONREAD:
 			{
 				int val = 0;
@@ -482,10 +480,11 @@
 					return -EFAULT;
 			}
 			return 0;
+		case TCFLSH:
+			return tty_perform_flush(linux_tty, arg);
 		}
 	}
-
-	return -ENOIOCTLCMD;
+	return tty_mode_ioctl(linux_tty, file, cmd , arg);
 }
 
 static int add_tty(dev_node_t *nodesp, int j,
@@ -588,6 +587,8 @@
 				tty_hangup(ttyj->linux_tty);
 				/* Wait till the tty_hangup has completed */
 				flush_scheduled_work();
+				/* FIXME: Exactly how is the tty object locked here
+				   against a parallel ioctl etc */
 				mutex_lock(&ttyj->ipw_tty_mutex);
 			}
 			while (ttyj->open_count)
diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c
index c240562..9a626e5 100644
--- a/drivers/char/pcmcia/synclink_cs.c
+++ b/drivers/char/pcmcia/synclink_cs.c
@@ -601,7 +601,7 @@
 
     cfg = &(parse.cftable_entry);
     CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple));
-    CS_CHECK(ParseTuple, pcmcia_parse_tuple(link, &tuple, &parse));
+    CS_CHECK(ParseTuple, pcmcia_parse_tuple(&tuple, &parse));
 
     if (cfg->flags & CISTPL_CFTABLE_DEFAULT) dflt = *cfg;
     if (cfg->index == 0)
diff --git a/drivers/char/pty.c b/drivers/char/pty.c
index 76b2793..6d45827 100644
--- a/drivers/char/pty.c
+++ b/drivers/char/pty.c
@@ -8,10 +8,12 @@
  *  Added TTY_DO_WRITE_WAKEUP to enable n_tty to send POLL_OUT to
  *      waiting writers -- Sapan Bhatia <sapan@corewars.org>
  *
- *
+ *  When reading this code see also fs/devpts. In particular note that the
+ *  driver_data field is used by the devpts side as a binding to the devpts
+ *  inode.
  */
 
-#include <linux/module.h>	/* For EXPORT_SYMBOL */
+#include <linux/module.h>
 
 #include <linux/errno.h>
 #include <linux/interrupt.h>
@@ -23,26 +25,25 @@
 #include <linux/mm.h>
 #include <linux/init.h>
 #include <linux/sysctl.h>
-
-#include <asm/uaccess.h>
-#include <asm/system.h>
+#include <linux/device.h>
+#include <linux/uaccess.h>
 #include <linux/bitops.h>
 #include <linux/devpts_fs.h>
 
+#include <asm/system.h>
+
 /* These are global because they are accessed in tty_io.c */
 #ifdef CONFIG_UNIX98_PTYS
 struct tty_driver *ptm_driver;
 static struct tty_driver *pts_driver;
 #endif
 
-static void pty_close(struct tty_struct * tty, struct file * filp)
+static void pty_close(struct tty_struct *tty, struct file *filp)
 {
-	if (!tty)
-		return;
-	if (tty->driver->subtype == PTY_TYPE_MASTER) {
-		if (tty->count > 1)
-			printk("master pty_close: count = %d!!\n", tty->count);
-	} else {
+	BUG_ON(!tty);
+	if (tty->driver->subtype == PTY_TYPE_MASTER)
+		WARN_ON(tty->count > 1);
+	else {
 		if (tty->count > 2)
 			return;
 	}
@@ -59,7 +60,7 @@
 		set_bit(TTY_OTHER_CLOSED, &tty->flags);
 #ifdef CONFIG_UNIX98_PTYS
 		if (tty->driver == ptm_driver)
-			devpts_pty_kill(tty->index);
+			devpts_pty_kill(tty->link);
 #endif
 		tty_vhangup(tty->link);
 	}
@@ -69,13 +70,13 @@
  * The unthrottle routine is called by the line discipline to signal
  * that it can receive more characters.  For PTY's, the TTY_THROTTLED
  * flag is always set, to force the line discipline to always call the
- * unthrottle routine when there are fewer than TTY_THRESHOLD_UNTHROTTLE 
+ * unthrottle routine when there are fewer than TTY_THRESHOLD_UNTHROTTLE
  * characters in the queue.  This is necessary since each time this
  * happens, we need to wake up any sleeping processes that could be
  * (1) trying to send data to the pty, or (2) waiting in wait_until_sent()
  * for the pty buffer to be drained.
  */
-static void pty_unthrottle(struct tty_struct * tty)
+static void pty_unthrottle(struct tty_struct *tty)
 {
 	struct tty_struct *o_tty = tty->link;
 
@@ -87,7 +88,7 @@
 }
 
 /*
- * WSH 05/24/97: modified to 
+ * WSH 05/24/97: modified to
  *   (1) use space in tty->flip instead of a shared temp buffer
  *	 The flip buffers aren't being used for a pty, so there's lots
  *	 of space available.  The buffer is protected by a per-pty
@@ -100,7 +101,8 @@
  * not our partners. We can't just take the other one blindly without
  * risking deadlocks.
  */
-static int pty_write(struct tty_struct * tty, const unsigned char *buf, int count)
+static int pty_write(struct tty_struct *tty, const unsigned char *buf,
+								int count)
 {
 	struct tty_struct *to = tty->link;
 	int	c;
@@ -112,7 +114,7 @@
 	if (c > count)
 		c = count;
 	to->ldisc.ops->receive_buf(to, buf, NULL, c);
-	
+
 	return c;
 }
 
@@ -128,17 +130,17 @@
 
 /*
  *	WSH 05/24/97:  Modified for asymmetric MASTER/SLAVE behavior
- *	The chars_in_buffer() value is used by the ldisc select() function 
+ *	The chars_in_buffer() value is used by the ldisc select() function
  *	to hold off writing when chars_in_buffer > WAKEUP_CHARS (== 256).
  *	The pty driver chars_in_buffer() Master/Slave must behave differently:
  *
  *      The Master side needs to allow typed-ahead commands to accumulate
  *      while being canonicalized, so we report "our buffer" as empty until
  *	some threshold is reached, and then report the count. (Any count >
- *	WAKEUP_CHARS is regarded by select() as "full".)  To avoid deadlock 
- *	the count returned must be 0 if no canonical data is available to be 
+ *	WAKEUP_CHARS is regarded by select() as "full".)  To avoid deadlock
+ *	the count returned must be 0 if no canonical data is available to be
  *	read. (The N_TTY ldisc.chars_in_buffer now knows this.)
- *  
+ *
  *	The Slave side passes all characters in raw mode to the Master side's
  *	buffer where they can be read immediately, so in this case we can
  *	return the true count in the buffer.
@@ -155,21 +157,22 @@
 	/* The ldisc must report 0 if no characters available to be read */
 	count = to->ldisc.ops->chars_in_buffer(to);
 
-	if (tty->driver->subtype == PTY_TYPE_SLAVE) return count;
+	if (tty->driver->subtype == PTY_TYPE_SLAVE)
+		return count;
 
-	/* Master side driver ... if the other side's read buffer is less than 
+	/* Master side driver ... if the other side's read buffer is less than
 	 * half full, return 0 to allow writers to proceed; otherwise return
-	 * the count.  This leaves a comfortable margin to avoid overflow, 
+	 * the count.  This leaves a comfortable margin to avoid overflow,
 	 * and still allows half a buffer's worth of typed-ahead commands.
 	 */
-	return ((count < N_TTY_BUF_SIZE/2) ? 0 : count);
+	return (count < N_TTY_BUF_SIZE/2) ? 0 : count;
 }
 
 /* Set the lock flag on a pty */
-static int pty_set_lock(struct tty_struct *tty, int __user * arg)
+static int pty_set_lock(struct tty_struct *tty, int __user *arg)
 {
 	int val;
-	if (get_user(val,arg))
+	if (get_user(val, arg))
 		return -EFAULT;
 	if (val)
 		set_bit(TTY_PTY_LOCK, &tty->flags);
@@ -182,13 +185,13 @@
 {
 	struct tty_struct *to = tty->link;
 	unsigned long flags;
-	
+
 	if (!to)
 		return;
-	
+
 	if (to->ldisc.ops->flush_buffer)
 		to->ldisc.ops->flush_buffer(to);
-	
+
 	if (to->packet) {
 		spin_lock_irqsave(&tty->ctrl_lock, flags);
 		tty->ctrl_status |= TIOCPKT_FLUSHWRITE;
@@ -197,7 +200,7 @@
 	}
 }
 
-static int pty_open(struct tty_struct *tty, struct file * filp)
+static int pty_open(struct tty_struct *tty, struct file *filp)
 {
 	int	retval = -ENODEV;
 
@@ -220,13 +223,65 @@
 	return retval;
 }
 
-static void pty_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
+static void pty_set_termios(struct tty_struct *tty,
+					struct ktermios *old_termios)
 {
-        tty->termios->c_cflag &= ~(CSIZE | PARENB);
-        tty->termios->c_cflag |= (CS8 | CREAD);
+	tty->termios->c_cflag &= ~(CSIZE | PARENB);
+	tty->termios->c_cflag |= (CS8 | CREAD);
 }
 
+static int pty_install(struct tty_driver *driver, struct tty_struct *tty)
+{
+	struct tty_struct *o_tty;
+	int idx = tty->index;
+	int retval;
+
+	o_tty = alloc_tty_struct();
+	if (!o_tty)
+		return -ENOMEM;
+	if (!try_module_get(driver->other->owner)) {
+		/* This cannot in fact currently happen */
+		free_tty_struct(o_tty);
+		return -ENOMEM;
+	}
+	initialize_tty_struct(o_tty, driver->other, idx);
+
+	/* We always use new tty termios data so we can do this
+	   the easy way .. */
+	retval = tty_init_termios(tty);
+	if (retval)
+		goto free_mem_out;
+
+	retval = tty_init_termios(o_tty);
+	if (retval) {
+		tty_free_termios(tty);
+		goto free_mem_out;
+	}
+
+	/*
+	 * Everything allocated ... set up the o_tty structure.
+	 */
+	driver->other->ttys[idx] = o_tty;
+	tty_driver_kref_get(driver->other);
+	if (driver->subtype == PTY_TYPE_MASTER)
+		o_tty->count++;
+	/* Establish the links in both directions */
+	tty->link   = o_tty;
+	o_tty->link = tty;
+
+	tty_driver_kref_get(driver);
+	tty->count++;
+	driver->ttys[idx] = tty;
+	return 0;
+free_mem_out:
+	module_put(o_tty->driver->owner);
+	free_tty_struct(o_tty);
+	return -ENOMEM;
+}
+
+
 static const struct tty_operations pty_ops = {
+	.install = pty_install,
 	.open = pty_open,
 	.close = pty_close,
 	.write = pty_write,
@@ -329,8 +384,11 @@
  * Otherwise one can eat up all kernel memory by opening /dev/ptmx repeatedly.
  */
 int pty_limit = NR_UNIX98_PTY_DEFAULT;
-static int pty_limit_min = 0;
+static int pty_limit_min;
 static int pty_limit_max = NR_UNIX98_PTY_MAX;
+static int pty_count;
+
+static struct cdev ptmx_cdev;
 
 static struct ctl_table pty_table[] = {
 	{
@@ -348,6 +406,7 @@
 		.procname	= "nr",
 		.maxlen		= sizeof(int),
 		.mode		= 0444,
+		.data		= &pty_count,
 		.proc_handler	= &proc_dointvec,
 	}, {
 		.ctl_name	= 0
@@ -388,7 +447,111 @@
 	return -ENOIOCTLCMD;
 }
 
-static const struct tty_operations pty_unix98_ops = {
+/**
+ *	ptm_unix98_lookup	-	find a pty master
+ *	@driver: ptm driver
+ *	@idx: tty index
+ *
+ *	Look up a pty master device. Called under the tty_mutex for now.
+ *	This provides our locking.
+ */
+
+static struct tty_struct *ptm_unix98_lookup(struct tty_driver *driver,
+		struct inode *ptm_inode, int idx)
+{
+	struct tty_struct *tty = devpts_get_tty(ptm_inode, idx);
+	if (tty)
+		tty = tty->link;
+	return tty;
+}
+
+/**
+ *	pts_unix98_lookup	-	find a pty slave
+ *	@driver: pts driver
+ *	@idx: tty index
+ *
+ *	Look up a pty master device. Called under the tty_mutex for now.
+ *	This provides our locking.
+ */
+
+static struct tty_struct *pts_unix98_lookup(struct tty_driver *driver,
+		struct inode *pts_inode, int idx)
+{
+	struct tty_struct *tty = devpts_get_tty(pts_inode, idx);
+	/* Master must be open before slave */
+	if (!tty)
+		return ERR_PTR(-EIO);
+	return tty;
+}
+
+static void pty_unix98_shutdown(struct tty_struct *tty)
+{
+	/* We have our own method as we don't use the tty index */
+	kfree(tty->termios);
+}
+
+/* We have no need to install and remove our tty objects as devpts does all
+   the work for us */
+
+static int pty_unix98_install(struct tty_driver *driver, struct tty_struct *tty)
+{
+	struct tty_struct *o_tty;
+	int idx = tty->index;
+
+	o_tty = alloc_tty_struct();
+	if (!o_tty)
+		return -ENOMEM;
+	if (!try_module_get(driver->other->owner)) {
+		/* This cannot in fact currently happen */
+		free_tty_struct(o_tty);
+		return -ENOMEM;
+	}
+	initialize_tty_struct(o_tty, driver->other, idx);
+
+	tty->termios = kzalloc(sizeof(struct ktermios[2]), GFP_KERNEL);
+	if (tty->termios == NULL)
+		goto free_mem_out;
+	*tty->termios = driver->init_termios;
+	tty->termios_locked = tty->termios + 1;
+
+	o_tty->termios = kzalloc(sizeof(struct ktermios[2]), GFP_KERNEL);
+	if (o_tty->termios == NULL)
+		goto free_mem_out;
+	*o_tty->termios = driver->other->init_termios;
+	o_tty->termios_locked = o_tty->termios + 1;
+
+	tty_driver_kref_get(driver->other);
+	if (driver->subtype == PTY_TYPE_MASTER)
+		o_tty->count++;
+	/* Establish the links in both directions */
+	tty->link   = o_tty;
+	o_tty->link = tty;
+	/*
+	 * All structures have been allocated, so now we install them.
+	 * Failures after this point use release_tty to clean up, so
+	 * there's no need to null out the local pointers.
+	 */
+	tty_driver_kref_get(driver);
+	tty->count++;
+	pty_count++;
+	return 0;
+free_mem_out:
+	kfree(o_tty->termios);
+	module_put(o_tty->driver->owner);
+	free_tty_struct(o_tty);
+	kfree(tty->termios);
+	return -ENOMEM;
+}
+
+static void pty_unix98_remove(struct tty_driver *driver, struct tty_struct *tty)
+{
+	pty_count--;
+}
+
+static const struct tty_operations ptm_unix98_ops = {
+	.lookup = ptm_unix98_lookup,
+	.install = pty_unix98_install,
+	.remove = pty_unix98_remove,
 	.open = pty_open,
 	.close = pty_close,
 	.write = pty_write,
@@ -397,9 +560,89 @@
 	.chars_in_buffer = pty_chars_in_buffer,
 	.unthrottle = pty_unthrottle,
 	.set_termios = pty_set_termios,
-	.ioctl = pty_unix98_ioctl
+	.ioctl = pty_unix98_ioctl,
+	.shutdown = pty_unix98_shutdown
 };
 
+static const struct tty_operations pty_unix98_ops = {
+	.lookup = pts_unix98_lookup,
+	.install = pty_unix98_install,
+	.remove = pty_unix98_remove,
+	.open = pty_open,
+	.close = pty_close,
+	.write = pty_write,
+	.write_room = pty_write_room,
+	.flush_buffer = pty_flush_buffer,
+	.chars_in_buffer = pty_chars_in_buffer,
+	.unthrottle = pty_unthrottle,
+	.set_termios = pty_set_termios,
+	.shutdown = pty_unix98_shutdown
+};
+
+/**
+ *	ptmx_open		-	open a unix 98 pty master
+ *	@inode: inode of device file
+ *	@filp: file pointer to tty
+ *
+ *	Allocate a unix98 pty master device from the ptmx driver.
+ *
+ *	Locking: tty_mutex protects the init_dev work. tty->count should
+ * 		protect the rest.
+ *		allocated_ptys_lock handles the list of free pty numbers
+ */
+
+static int __ptmx_open(struct inode *inode, struct file *filp)
+{
+	struct tty_struct *tty;
+	int retval;
+	int index;
+
+	nonseekable_open(inode, filp);
+
+	/* find a device that is not in use. */
+	index = devpts_new_index(inode);
+	if (index < 0)
+		return index;
+
+	mutex_lock(&tty_mutex);
+	tty = tty_init_dev(ptm_driver, index, 1);
+	mutex_unlock(&tty_mutex);
+
+	if (IS_ERR(tty)) {
+		retval = PTR_ERR(tty);
+		goto out;
+	}
+
+	set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */
+	filp->private_data = tty;
+	file_move(filp, &tty->tty_files);
+
+	retval = devpts_pty_new(inode, tty->link);
+	if (retval)
+		goto out1;
+
+	retval = ptm_driver->ops->open(tty, filp);
+	if (!retval)
+		return 0;
+out1:
+	tty_release_dev(filp);
+	return retval;
+out:
+	devpts_kill_index(inode, index);
+	return retval;
+}
+
+static int ptmx_open(struct inode *inode, struct file *filp)
+{
+	int ret;
+
+	lock_kernel();
+	ret = __ptmx_open(inode, filp);
+	unlock_kernel();
+	return ret;
+}
+
+static struct file_operations ptmx_fops;
 
 static void __init unix98_pty_init(void)
 {
@@ -427,7 +670,7 @@
 	ptm_driver->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW |
 		TTY_DRIVER_DYNAMIC_DEV | TTY_DRIVER_DEVPTS_MEM;
 	ptm_driver->other = pts_driver;
-	tty_set_operations(ptm_driver, &pty_unix98_ops);
+	tty_set_operations(ptm_driver, &ptm_unix98_ops);
 
 	pts_driver->owner = THIS_MODULE;
 	pts_driver->driver_name = "pty_slave";
@@ -443,16 +686,26 @@
 	pts_driver->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW |
 		TTY_DRIVER_DYNAMIC_DEV | TTY_DRIVER_DEVPTS_MEM;
 	pts_driver->other = ptm_driver;
-	tty_set_operations(pts_driver, &pty_ops);
-	
+	tty_set_operations(pts_driver, &pty_unix98_ops);
+
 	if (tty_register_driver(ptm_driver))
 		panic("Couldn't register Unix98 ptm driver");
 	if (tty_register_driver(pts_driver))
 		panic("Couldn't register Unix98 pts driver");
 
-	pty_table[1].data = &ptm_driver->refcount;
 	register_sysctl_table(pty_root_table);
+
+	/* Now create the /dev/ptmx special device */
+	tty_default_fops(&ptmx_fops);
+	ptmx_fops.open = ptmx_open;
+
+	cdev_init(&ptmx_cdev, &ptmx_fops);
+	if (cdev_add(&ptmx_cdev, MKDEV(TTYAUX_MAJOR, 2), 1) ||
+	    register_chrdev_region(MKDEV(TTYAUX_MAJOR, 2), 1, "/dev/ptmx") < 0)
+		panic("Couldn't register /dev/ptmx driver\n");
+	device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 2), NULL, "ptmx");
 }
+
 #else
 static inline void unix98_pty_init(void) { }
 #endif
diff --git a/drivers/char/random.c b/drivers/char/random.c
index 7ce1ac4..6af435b 100644
--- a/drivers/char/random.c
+++ b/drivers/char/random.c
@@ -661,10 +661,10 @@
 	if (!disk || !disk->random)
 		return;
 	/* first major is 1, so we get >= 0x200 here */
-	DEBUG_ENT("disk event %d:%d\n", disk->major, disk->first_minor);
+	DEBUG_ENT("disk event %d:%d\n",
+		  MAJOR(disk_devt(disk)), MINOR(disk_devt(disk)));
 
-	add_timer_randomness(disk->random,
-			     0x100 + MKDEV(disk->major, disk->first_minor));
+	add_timer_randomness(disk->random, 0x100 + disk_devt(disk));
 }
 #endif
 
diff --git a/drivers/char/rtc.c b/drivers/char/rtc.c
index f53d4d0..b47710c 100644
--- a/drivers/char/rtc.c
+++ b/drivers/char/rtc.c
@@ -88,12 +88,12 @@
 #endif
 
 #ifdef CONFIG_SPARC32
-#include <linux/pci.h>
-#include <linux/jiffies.h>
-#include <asm/ebus.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <asm/io.h>
 
 static unsigned long rtc_port;
-static int rtc_irq = PCI_IRQ_NONE;
+static int rtc_irq;
 #endif
 
 #ifdef	CONFIG_HPET_RTC_IRQ
@@ -973,8 +973,8 @@
 	char *guess = NULL;
 #endif
 #ifdef CONFIG_SPARC32
-	struct linux_ebus *ebus;
-	struct linux_ebus_device *edev;
+	struct device_node *ebus_dp;
+	struct of_device *op;
 #else
 	void *r;
 #ifdef RTC_IRQ
@@ -983,12 +983,16 @@
 #endif
 
 #ifdef CONFIG_SPARC32
-	for_each_ebus(ebus) {
-		for_each_ebusdev(edev, ebus) {
-			if (strcmp(edev->prom_node->name, "rtc") == 0) {
-				rtc_port = edev->resource[0].start;
-				rtc_irq = edev->irqs[0];
-				goto found;
+	for_each_node_by_name(ebus_dp, "ebus") {
+		struct device_node *dp;
+		for (dp = ebus_dp; dp; dp = dp->sibling) {
+			if (!strcmp(dp->name, "rtc")) {
+				op = of_find_device_by_node(dp);
+				if (op) {
+					rtc_port = op->resource[0].start;
+					rtc_irq = op->irqs[0];
+					goto found;
+				}
 			}
 		}
 	}
@@ -997,7 +1001,7 @@
 	return -EIO;
 
 found:
-	if (rtc_irq == PCI_IRQ_NONE) {
+	if (!rtc_irq) {
 		rtc_has_irq = 0;
 		goto no_irq;
 	}
diff --git a/drivers/char/stallion.c b/drivers/char/stallion.c
index 19db1eb..8b8f07a 100644
--- a/drivers/char/stallion.c
+++ b/drivers/char/stallion.c
@@ -405,9 +405,9 @@
 
 static int	stl_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, unsigned long arg);
 static int	stl_brdinit(struct stlbrd *brdp);
-static int	stl_getportstats(struct stlport *portp, comstats_t __user *cp);
+static int	stl_getportstats(struct tty_struct *tty, struct stlport *portp, comstats_t __user *cp);
 static int	stl_clrportstats(struct stlport *portp, comstats_t __user *cp);
-static int	stl_waitcarrier(struct stlport *portp, struct file *filp);
+static int	stl_waitcarrier(struct tty_struct *tty, struct stlport *portp, struct file *filp);
 
 /*
  *	CD1400 uart specific handling functions.
@@ -612,8 +612,9 @@
 static void stl_cd_change(struct stlport *portp)
 {
 	unsigned int oldsigs = portp->sigs;
+	struct tty_struct *tty = tty_port_tty_get(&portp->port);
 
-	if (!portp->port.tty)
+	if (!tty)
 		return;
 
 	portp->sigs = stl_getsignals(portp);
@@ -623,7 +624,8 @@
 
 	if ((oldsigs & TIOCM_CD) && ((portp->sigs & TIOCM_CD) == 0))
 		if (portp->port.flags & ASYNC_CHECK_CD)
-			tty_hangup(portp->port.tty);
+			tty_hangup(tty);
+	tty_kref_put(tty);
 }
 
 /*
@@ -734,7 +736,7 @@
  *	On the first open of the device setup the port hardware, and
  *	initialize the per port data structure.
  */
-	portp->port.tty = tty;
+	tty_port_tty_set(&portp->port, tty);
 	tty->driver_data = portp;
 	portp->port.count++;
 
@@ -774,7 +776,7 @@
  *	then also we might have to wait for carrier.
  */
 	if (!(filp->f_flags & O_NONBLOCK))
-		if ((rc = stl_waitcarrier(portp, filp)) != 0)
+		if ((rc = stl_waitcarrier(tty, portp, filp)) != 0)
 			return rc;
 
 	portp->port.flags |= ASYNC_NORMAL_ACTIVE;
@@ -789,7 +791,8 @@
  *	maybe because if we are clocal then we don't need to wait...
  */
 
-static int stl_waitcarrier(struct stlport *portp, struct file *filp)
+static int stl_waitcarrier(struct tty_struct *tty, struct stlport *portp,
+							struct file *filp)
 {
 	unsigned long	flags;
 	int		rc, doclocal;
@@ -801,7 +804,7 @@
 
 	spin_lock_irqsave(&stallion_lock, flags);
 
-	if (portp->port.tty->termios->c_cflag & CLOCAL)
+	if (tty->termios->c_cflag & CLOCAL)
 		doclocal++;
 
 	portp->openwaitcnt++;
@@ -846,8 +849,6 @@
 
 	pr_debug("stl_flushbuffer(tty=%p)\n", tty);
 
-	if (tty == NULL)
-		return;
 	portp = tty->driver_data;
 	if (portp == NULL)
 		return;
@@ -865,8 +866,6 @@
 
 	pr_debug("stl_waituntilsent(tty=%p,timeout=%d)\n", tty, timeout);
 
-	if (tty == NULL)
-		return;
 	portp = tty->driver_data;
 	if (portp == NULL)
 		return;
@@ -949,7 +948,7 @@
 	tty_ldisc_flush(tty);
 
 	tty->closing = 0;
-	portp->port.tty = NULL;
+	tty_port_tty_set(&portp->port, NULL);
 
 	if (portp->openwaitcnt) {
 		if (portp->close_delay)
@@ -1033,8 +1032,6 @@
 
 	pr_debug("stl_putchar(tty=%p,ch=%x)\n", tty, ch);
 
-	if (tty == NULL)
-		return -EINVAL;
 	portp = tty->driver_data;
 	if (portp == NULL)
 		return -EINVAL;
@@ -1070,8 +1067,6 @@
 
 	pr_debug("stl_flushchars(tty=%p)\n", tty);
 
-	if (tty == NULL)
-		return;
 	portp = tty->driver_data;
 	if (portp == NULL)
 		return;
@@ -1090,8 +1085,6 @@
 
 	pr_debug("stl_writeroom(tty=%p)\n", tty);
 
-	if (tty == NULL)
-		return 0;
 	portp = tty->driver_data;
 	if (portp == NULL)
 		return 0;
@@ -1122,8 +1115,6 @@
 
 	pr_debug("stl_charsinbuffer(tty=%p)\n", tty);
 
-	if (tty == NULL)
-		return 0;
 	portp = tty->driver_data;
 	if (portp == NULL)
 		return 0;
@@ -1183,8 +1174,9 @@
  *	just quietly ignore any requests to change irq, etc.
  */
 
-static int stl_setserial(struct stlport *portp, struct serial_struct __user *sp)
+static int stl_setserial(struct tty_struct *tty, struct serial_struct __user *sp)
 {
+	struct stlport *	portp = tty->driver_data;
 	struct serial_struct	sio;
 
 	pr_debug("stl_setserial(portp=%p,sp=%p)\n", portp, sp);
@@ -1205,7 +1197,7 @@
 	portp->close_delay = sio.close_delay;
 	portp->closing_wait = sio.closing_wait;
 	portp->custom_divisor = sio.custom_divisor;
-	stl_setport(portp, portp->port.tty->termios);
+	stl_setport(portp, tty->termios);
 	return 0;
 }
 
@@ -1215,8 +1207,6 @@
 {
 	struct stlport	*portp;
 
-	if (tty == NULL)
-		return -ENODEV;
 	portp = tty->driver_data;
 	if (portp == NULL)
 		return -ENODEV;
@@ -1232,8 +1222,6 @@
 	struct stlport	*portp;
 	int rts = -1, dtr = -1;
 
-	if (tty == NULL)
-		return -ENODEV;
 	portp = tty->driver_data;
 	if (portp == NULL)
 		return -ENODEV;
@@ -1262,8 +1250,6 @@
 	pr_debug("stl_ioctl(tty=%p,file=%p,cmd=%x,arg=%lx)\n", tty, file, cmd,
 			arg);
 
-	if (tty == NULL)
-		return -ENODEV;
 	portp = tty->driver_data;
 	if (portp == NULL)
 		return -ENODEV;
@@ -1282,10 +1268,10 @@
 		rc = stl_getserial(portp, argp);
 		break;
 	case TIOCSSERIAL:
-		rc = stl_setserial(portp, argp);
+		rc = stl_setserial(tty, argp);
 		break;
 	case COM_GETPORTSTATS:
-		rc = stl_getportstats(portp, argp);
+		rc = stl_getportstats(tty, portp, argp);
 		break;
 	case COM_CLRPORTSTATS:
 		rc = stl_clrportstats(portp, argp);
@@ -1317,8 +1303,6 @@
 
 	pr_debug("stl_start(tty=%p)\n", tty);
 
-	if (tty == NULL)
-		return;
 	portp = tty->driver_data;
 	if (portp == NULL)
 		return;
@@ -1334,8 +1318,6 @@
 
 	pr_debug("stl_settermios(tty=%p,old=%p)\n", tty, old);
 
-	if (tty == NULL)
-		return;
 	portp = tty->driver_data;
 	if (portp == NULL)
 		return;
@@ -1369,8 +1351,6 @@
 
 	pr_debug("stl_throttle(tty=%p)\n", tty);
 
-	if (tty == NULL)
-		return;
 	portp = tty->driver_data;
 	if (portp == NULL)
 		return;
@@ -1389,8 +1369,6 @@
 
 	pr_debug("stl_unthrottle(tty=%p)\n", tty);
 
-	if (tty == NULL)
-		return;
 	portp = tty->driver_data;
 	if (portp == NULL)
 		return;
@@ -1410,8 +1388,6 @@
 
 	pr_debug("stl_stop(tty=%p)\n", tty);
 
-	if (tty == NULL)
-		return;
 	portp = tty->driver_data;
 	if (portp == NULL)
 		return;
@@ -1432,8 +1408,6 @@
 
 	pr_debug("stl_hangup(tty=%p)\n", tty);
 
-	if (tty == NULL)
-		return;
 	portp = tty->driver_data;
 	if (portp == NULL)
 		return;
@@ -1452,7 +1426,7 @@
 		portp->tx.head = NULL;
 		portp->tx.tail = NULL;
 	}
-	portp->port.tty = NULL;
+	tty_port_tty_set(&portp->port, NULL);
 	portp->port.flags &= ~ASYNC_NORMAL_ACTIVE;
 	portp->port.count = 0;
 	wake_up_interruptible(&portp->port.open_wait);
@@ -1466,8 +1440,6 @@
 
 	pr_debug("stl_breakctl(tty=%p,state=%d)\n", tty, state);
 
-	if (tty == NULL)
-		return -EINVAL;
 	portp = tty->driver_data;
 	if (portp == NULL)
 		return -EINVAL;
@@ -1484,8 +1456,6 @@
 
 	pr_debug("stl_sendxchar(tty=%p,ch=%x)\n", tty, ch);
 
-	if (tty == NULL)
-		return;
 	portp = tty->driver_data;
 	if (portp == NULL)
 		return;
@@ -1805,7 +1775,7 @@
 				"(size=%Zd)\n", sizeof(struct stlport));
 			break;
 		}
-
+		tty_port_init(&portp->port);
 		portp->magic = STL_PORTMAGIC;
 		portp->portnr = i;
 		portp->brdnr = panelp->brdnr;
@@ -1832,6 +1802,7 @@
 	struct stlpanel *panelp;
 	struct stlport *portp;
 	unsigned int j, k;
+	struct tty_struct *tty;
 
 	for (j = 0; j < STL_MAXPANELS; j++) {
 		panelp = brdp->panels[j];
@@ -1841,8 +1812,11 @@
 			portp = panelp->ports[k];
 			if (portp == NULL)
 				continue;
-			if (portp->port.tty != NULL)
-				stl_hangup(portp->port.tty);
+			tty = tty_port_tty_get(&portp->port);
+			if (tty != NULL) {
+				stl_hangup(tty);
+				tty_kref_put(tty);
+			}
 			kfree(portp->tx.buf);
 			kfree(portp);
 		}
@@ -2498,7 +2472,7 @@
  *	what port to get stats for (used through board control device).
  */
 
-static int stl_getportstats(struct stlport *portp, comstats_t __user *cp)
+static int stl_getportstats(struct tty_struct *tty, struct stlport *portp, comstats_t __user *cp)
 {
 	comstats_t	stl_comstats;
 	unsigned char	*head, *tail;
@@ -2525,18 +2499,17 @@
 	portp->stats.rxbuffered = 0;
 
 	spin_lock_irqsave(&stallion_lock, flags);
-	if (portp->port.tty != NULL)
-		if (portp->port.tty->driver_data == portp) {
-			portp->stats.ttystate = portp->port.tty->flags;
-			/* No longer available as a statistic */
-			portp->stats.rxbuffered = 1; /*portp->port.tty->flip.count; */
-			if (portp->port.tty->termios != NULL) {
-				portp->stats.cflags = portp->port.tty->termios->c_cflag;
-				portp->stats.iflags = portp->port.tty->termios->c_iflag;
-				portp->stats.oflags = portp->port.tty->termios->c_oflag;
-				portp->stats.lflags = portp->port.tty->termios->c_lflag;
-			}
+	if (tty != NULL && portp->port.tty == tty) {
+		portp->stats.ttystate = tty->flags;
+		/* No longer available as a statistic */
+		portp->stats.rxbuffered = 1; /*tty->flip.count; */
+		if (tty->termios != NULL) {
+			portp->stats.cflags = tty->termios->c_cflag;
+			portp->stats.iflags = tty->termios->c_iflag;
+			portp->stats.oflags = tty->termios->c_oflag;
+			portp->stats.lflags = tty->termios->c_lflag;
 		}
+	}
 	spin_unlock_irqrestore(&stallion_lock, flags);
 
 	head = portp->tx.head;
@@ -2640,7 +2613,7 @@
 
 	switch (cmd) {
 	case COM_GETPORTSTATS:
-		rc = stl_getportstats(NULL, argp);
+		rc = stl_getportstats(NULL, NULL, argp);
 		break;
 	case COM_CLRPORTSTATS:
 		rc = stl_clrportstats(NULL, argp);
@@ -3243,7 +3216,7 @@
 
 	if (portp == NULL)
 		return;
-	tty = portp->port.tty;
+	tty = tty_port_tty_get(&portp->port);
 	if (tty == NULL)
 		return;
 
@@ -3288,6 +3261,7 @@
 
 	BRDDISABLE(portp->brdnr);
 	spin_unlock_irqrestore(&brd_lock, flags);
+	tty_kref_put(tty);
 }
 
 /*****************************************************************************/
@@ -3305,7 +3279,7 @@
 
 	if (portp == NULL)
 		return;
-	tty = portp->port.tty;
+	tty = tty_port_tty_get(&portp->port);
 	if (tty == NULL)
 		return;
 
@@ -3325,6 +3299,7 @@
 	}
 	BRDDISABLE(portp->brdnr);
 	spin_unlock_irqrestore(&brd_lock, flags);
+	tty_kref_put(tty);
 }
 
 /*****************************************************************************/
@@ -3478,6 +3453,7 @@
 	int		len, stlen;
 	char		*head, *tail;
 	unsigned char	ioack, srer;
+	struct tty_struct *tty;
 
 	pr_debug("stl_cd1400txisr(panelp=%p,ioaddr=%x)\n", panelp, ioaddr);
 
@@ -3504,8 +3480,11 @@
 	if ((len == 0) || ((len < STL_TXBUFLOW) &&
 	    (test_bit(ASYI_TXLOW, &portp->istate) == 0))) {
 		set_bit(ASYI_TXLOW, &portp->istate);
-		if (portp->port.tty)
-			tty_wakeup(portp->port.tty);
+		tty = tty_port_tty_get(&portp->port);
+		if (tty) {
+			tty_wakeup(tty);
+			tty_kref_put(tty);
+		}
 	}
 
 	if (len == 0) {
@@ -3569,7 +3548,7 @@
 		return;
 	}
 	portp = panelp->ports[(ioack >> 3)];
-	tty = portp->port.tty;
+	tty = tty_port_tty_get(&portp->port);
 
 	if ((ioack & ACK_TYPMASK) == ACK_TYPRXGOOD) {
 		outb((RDCR + portp->uartaddr), ioaddr);
@@ -3633,10 +3612,12 @@
 		}
 	} else {
 		printk("STALLION: bad RX interrupt ack value=%x\n", ioack);
+		tty_kref_put(tty);
 		return;
 	}
 
 stl_rxalldone:
+	tty_kref_put(tty);
 	outb((EOSRR + portp->uartaddr), ioaddr);
 	outb(0, (ioaddr + EREG_DATA));
 }
@@ -4175,7 +4156,7 @@
 
 	if (portp == NULL)
 		return;
-	tty = portp->port.tty;
+	tty = tty_port_tty_get(&portp->port);
 	if (tty == NULL)
 		return;
 
@@ -4226,6 +4207,7 @@
 
 	BRDDISABLE(portp->brdnr);
 	spin_unlock_irqrestore(&brd_lock, flags);
+	tty_kref_put(tty);
 }
 
 /*****************************************************************************/
@@ -4244,7 +4226,7 @@
 
 	if (portp == NULL)
 		return;
-	tty = portp->port.tty;
+	tty = tty_port_tty_get(&portp->port);
 	if (tty == NULL)
 		return;
 
@@ -4269,6 +4251,7 @@
 	}
 	BRDDISABLE(portp->brdnr);
 	spin_unlock_irqrestore(&brd_lock, flags);
+	tty_kref_put(tty);
 }
 
 /*****************************************************************************/
@@ -4408,6 +4391,7 @@
 
 static void stl_sc26198txisr(struct stlport *portp)
 {
+	struct tty_struct *tty;
 	unsigned int	ioaddr;
 	unsigned char	mr0;
 	int		len, stlen;
@@ -4422,8 +4406,11 @@
 	if ((len == 0) || ((len < STL_TXBUFLOW) &&
 	    (test_bit(ASYI_TXLOW, &portp->istate) == 0))) {
 		set_bit(ASYI_TXLOW, &portp->istate);
-		if (portp->port.tty)
-			tty_wakeup(portp->port.tty);
+		tty = tty_port_tty_get(&portp->port);
+		if (tty) {
+			tty_wakeup(tty);
+			tty_kref_put(tty);
+		}
 	}
 
 	if (len == 0) {
@@ -4476,7 +4463,7 @@
 
 	pr_debug("stl_sc26198rxisr(portp=%p,iack=%x)\n", portp, iack);
 
-	tty = portp->port.tty;
+	tty = tty_port_tty_get(&portp->port);
 	ioaddr = portp->ioaddr;
 	outb(GIBCR, (ioaddr + XP_ADDR));
 	len = inb(ioaddr + XP_DATA) + 1;
@@ -4515,6 +4502,7 @@
 			stl_sc26198txunflow(portp, tty);
 		}
 	}
+	tty_kref_put(tty);
 }
 
 /*****************************************************************************/
@@ -4528,7 +4516,7 @@
 	struct tty_struct	*tty;
 	unsigned int		ioaddr;
 
-	tty = portp->port.tty;
+	tty = tty_port_tty_get(&portp->port);
 	ioaddr = portp->ioaddr;
 
 	if (status & SR_RXPARITY)
@@ -4566,6 +4554,7 @@
 		if (status == 0)
 			portp->stats.rxtotal++;
 	}
+	tty_kref_put(tty);
 }
 
 /*****************************************************************************/
diff --git a/drivers/char/sx.c b/drivers/char/sx.c
index c385206..5b8d7a1 100644
--- a/drivers/char/sx.c
+++ b/drivers/char/sx.c
@@ -2504,7 +2504,7 @@
 		del_timer(&board->timer);
 		if (pdev) {
 #ifdef CONFIG_PCI
-			pci_iounmap(pdev, board->base);
+			pci_iounmap(pdev, board->base2);
 			pci_release_region(pdev, IS_CF_BOARD(board) ? 3 : 2);
 #endif
 		} else {
@@ -2703,7 +2703,7 @@
 
 	return 0;
 err_unmap:
-	pci_iounmap(pdev, board->base);
+	pci_iounmap(pdev, board->base2);
 err_reg:
 	pci_release_region(pdev, reg);
 err_flag:
diff --git a/drivers/char/tpm/Kconfig b/drivers/char/tpm/Kconfig
index 3738cfa..f5fc64f 100644
--- a/drivers/char/tpm/Kconfig
+++ b/drivers/char/tpm/Kconfig
@@ -6,6 +6,7 @@
 	tristate "TPM Hardware Support"
 	depends on HAS_IOMEM
 	depends on EXPERIMENTAL
+	select SECURITYFS
 	---help---
 	  If you have a TPM security chip in your system, which
 	  implements the Trusted Computing Group's specification,
diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c
index ae766d8..1fee703 100644
--- a/drivers/char/tpm/tpm.c
+++ b/drivers/char/tpm/tpm.c
@@ -954,72 +954,63 @@
 
 /*
  * Device file system interface to the TPM
+ *
+ * It's assured that the chip will be opened just once,
+ * by the check of is_open variable, which is protected
+ * by driver_lock.
  */
 int tpm_open(struct inode *inode, struct file *file)
 {
-	int rc = 0, minor = iminor(inode);
+	int minor = iminor(inode);
 	struct tpm_chip *chip = NULL, *pos;
 
-	lock_kernel();
-	spin_lock(&driver_lock);
-
-	list_for_each_entry(pos, &tpm_chip_list, list) {
+	rcu_read_lock();
+	list_for_each_entry_rcu(pos, &tpm_chip_list, list) {
 		if (pos->vendor.miscdev.minor == minor) {
 			chip = pos;
+			get_device(chip->dev);
 			break;
 		}
 	}
+	rcu_read_unlock();
 
-	if (chip == NULL) {
-		rc = -ENODEV;
-		goto err_out;
-	}
+	if (!chip)
+		return -ENODEV;
 
-	if (chip->num_opens) {
+	if (test_and_set_bit(0, &chip->is_open)) {
 		dev_dbg(chip->dev, "Another process owns this TPM\n");
-		rc = -EBUSY;
-		goto err_out;
+		put_device(chip->dev);
+		return -EBUSY;
 	}
 
-	chip->num_opens++;
-	get_device(chip->dev);
-
-	spin_unlock(&driver_lock);
-
 	chip->data_buffer = kmalloc(TPM_BUFSIZE * sizeof(u8), GFP_KERNEL);
 	if (chip->data_buffer == NULL) {
-		chip->num_opens--;
+		clear_bit(0, &chip->is_open);
 		put_device(chip->dev);
-		unlock_kernel();
 		return -ENOMEM;
 	}
 
 	atomic_set(&chip->data_pending, 0);
 
 	file->private_data = chip;
-	unlock_kernel();
 	return 0;
-
-err_out:
-	spin_unlock(&driver_lock);
-	unlock_kernel();
-	return rc;
 }
 EXPORT_SYMBOL_GPL(tpm_open);
 
+/*
+ * Called on file close
+ */
 int tpm_release(struct inode *inode, struct file *file)
 {
 	struct tpm_chip *chip = file->private_data;
 
-	flush_scheduled_work();
-	spin_lock(&driver_lock);
-	file->private_data = NULL;
 	del_singleshot_timer_sync(&chip->user_read_timer);
+	flush_scheduled_work();
+	file->private_data = NULL;
 	atomic_set(&chip->data_pending, 0);
-	chip->num_opens--;
-	put_device(chip->dev);
 	kfree(chip->data_buffer);
-	spin_unlock(&driver_lock);
+	clear_bit(0, &chip->is_open);
+	put_device(chip->dev);
 	return 0;
 }
 EXPORT_SYMBOL_GPL(tpm_release);
@@ -1093,13 +1084,11 @@
 	}
 
 	spin_lock(&driver_lock);
-
-	list_del(&chip->list);
-
+	list_del_rcu(&chip->list);
 	spin_unlock(&driver_lock);
+	synchronize_rcu();
 
 	misc_deregister(&chip->vendor.miscdev);
-
 	sysfs_remove_group(&dev->kobj, chip->vendor.attr_group);
 	tpm_bios_log_teardown(chip->bios_dir);
 
@@ -1144,25 +1133,33 @@
 }
 EXPORT_SYMBOL_GPL(tpm_pm_resume);
 
+/* In case vendor provided release function, call it too.*/
+
+void tpm_dev_vendor_release(struct tpm_chip *chip)
+{
+	if (chip->vendor.release)
+		chip->vendor.release(chip->dev);
+
+	clear_bit(chip->dev_num, dev_mask);
+	kfree(chip->vendor.miscdev.name);
+}
+EXPORT_SYMBOL_GPL(tpm_dev_vendor_release);
+
+
 /*
  * Once all references to platform device are down to 0,
  * release all allocated structures.
- * In case vendor provided release function,
- * call it too.
  */
 static void tpm_dev_release(struct device *dev)
 {
 	struct tpm_chip *chip = dev_get_drvdata(dev);
 
-	if (chip->vendor.release)
-		chip->vendor.release(dev);
+	tpm_dev_vendor_release(chip);
 
 	chip->release(dev);
-
-	clear_bit(chip->dev_num, dev_mask);
-	kfree(chip->vendor.miscdev.name);
 	kfree(chip);
 }
+EXPORT_SYMBOL_GPL(tpm_dev_release);
 
 /*
  * Called from tpm_<specific>.c probe function only for devices 
@@ -1171,8 +1168,8 @@
  * upon errant exit from this function specific probe function should call
  * pci_disable_device
  */
-struct tpm_chip *tpm_register_hardware(struct device *dev, const struct tpm_vendor_specific
-				       *entry)
+struct tpm_chip *tpm_register_hardware(struct device *dev,
+					const struct tpm_vendor_specific *entry)
 {
 #define DEVNAME_SIZE 7
 
@@ -1231,21 +1228,20 @@
 		return NULL;
 	}
 
-	spin_lock(&driver_lock);
-
-	list_add(&chip->list, &tpm_chip_list);
-
-	spin_unlock(&driver_lock);
-
 	if (sysfs_create_group(&dev->kobj, chip->vendor.attr_group)) {
-		list_del(&chip->list);
 		misc_deregister(&chip->vendor.miscdev);
 		put_device(chip->dev);
+
 		return NULL;
 	}
 
 	chip->bios_dir = tpm_bios_log_setup(devname);
 
+	/* Make chip available */
+	spin_lock(&driver_lock);
+	list_add_rcu(&chip->list, &tpm_chip_list);
+	spin_unlock(&driver_lock);
+
 	return chip;
 }
 EXPORT_SYMBOL_GPL(tpm_register_hardware);
diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h
index e885148..8e30df4 100644
--- a/drivers/char/tpm/tpm.h
+++ b/drivers/char/tpm/tpm.h
@@ -90,7 +90,7 @@
 	struct device *dev;	/* Device stuff */
 
 	int dev_num;		/* /dev/tpm# */
-	int num_opens;		/* only one allowed */
+	unsigned long is_open;	/* only one allowed */
 	int time_expired;
 
 	/* Data passed to and from the tpm via the read/write calls */
@@ -132,6 +132,7 @@
 				 const struct tpm_vendor_specific *);
 extern int tpm_open(struct inode *, struct file *);
 extern int tpm_release(struct inode *, struct file *);
+extern void tpm_dev_vendor_release(struct tpm_chip *);
 extern ssize_t tpm_write(struct file *, const char __user *, size_t,
 			 loff_t *);
 extern ssize_t tpm_read(struct file *, char __user *, size_t, loff_t *);
diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c
index ed1879c..717af7a 100644
--- a/drivers/char/tpm/tpm_tis.c
+++ b/drivers/char/tpm/tpm_tis.c
@@ -630,12 +630,23 @@
 	{"", 0}			/* Terminator */
 };
 
+static __devexit void tpm_tis_pnp_remove(struct pnp_dev *dev)
+{
+	struct tpm_chip *chip = pnp_get_drvdata(dev);
+
+	tpm_dev_vendor_release(chip);
+
+	kfree(chip);
+}
+
+
 static struct pnp_driver tis_pnp_driver = {
 	.name = "tpm_tis",
 	.id_table = tpm_pnp_tbl,
 	.probe = tpm_tis_pnp_init,
 	.suspend = tpm_tis_pnp_suspend,
 	.resume = tpm_tis_pnp_resume,
+	.remove = tpm_tis_pnp_remove,
 };
 
 #define TIS_HID_USR_IDX sizeof(tpm_pnp_tbl)/sizeof(struct pnp_device_id) -2
@@ -683,6 +694,7 @@
 	spin_lock(&tis_lock);
 	list_for_each_entry_safe(i, j, &tis_chips, list) {
 		chip = to_tpm_chip(i);
+		tpm_remove_hardware(chip->dev);
 		iowrite32(~TPM_GLOBAL_INT_ENABLE &
 			  ioread32(chip->vendor.iobase +
 				   TPM_INT_ENABLE(chip->vendor.
@@ -694,9 +706,9 @@
 			free_irq(chip->vendor.irq, chip);
 		iounmap(i->iobase);
 		list_del(&i->list);
-		tpm_remove_hardware(chip->dev);
 	}
 	spin_unlock(&tis_lock);
+
 	if (force) {
 		platform_device_unregister(pdev);
 		driver_unregister(&tis_drv);
diff --git a/drivers/char/tty_audit.c b/drivers/char/tty_audit.c
index 3582f43..5787249 100644
--- a/drivers/char/tty_audit.c
+++ b/drivers/char/tty_audit.c
@@ -93,7 +93,7 @@
 		get_task_comm(name, tsk);
 		audit_log_untrustedstring(ab, name);
 		audit_log_format(ab, " data=");
-		audit_log_n_untrustedstring(ab, buf->data, buf->valid);
+		audit_log_n_hex(ab, buf->data, buf->valid);
 		audit_log_end(ab);
 	}
 	buf->valid = 0;
diff --git a/drivers/char/tty_buffer.c b/drivers/char/tty_buffer.c
new file mode 100644
index 0000000..810ee25
--- /dev/null
+++ b/drivers/char/tty_buffer.c
@@ -0,0 +1,511 @@
+/*
+ * Tty buffer allocation management
+ */
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/tty.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+#include <linux/timer.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/wait.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+
+/**
+ *	tty_buffer_free_all		-	free buffers used by a tty
+ *	@tty: tty to free from
+ *
+ *	Remove all the buffers pending on a tty whether queued with data
+ *	or in the free ring. Must be called when the tty is no longer in use
+ *
+ *	Locking: none
+ */
+
+void tty_buffer_free_all(struct tty_struct *tty)
+{
+	struct tty_buffer *thead;
+	while ((thead = tty->buf.head) != NULL) {
+		tty->buf.head = thead->next;
+		kfree(thead);
+	}
+	while ((thead = tty->buf.free) != NULL) {
+		tty->buf.free = thead->next;
+		kfree(thead);
+	}
+	tty->buf.tail = NULL;
+	tty->buf.memory_used = 0;
+}
+
+/**
+ *	tty_buffer_alloc	-	allocate a tty buffer
+ *	@tty: tty device
+ *	@size: desired size (characters)
+ *
+ *	Allocate a new tty buffer to hold the desired number of characters.
+ *	Return NULL if out of memory or the allocation would exceed the
+ *	per device queue
+ *
+ *	Locking: Caller must hold tty->buf.lock
+ */
+
+static struct tty_buffer *tty_buffer_alloc(struct tty_struct *tty, size_t size)
+{
+	struct tty_buffer *p;
+
+	if (tty->buf.memory_used + size > 65536)
+		return NULL;
+	p = kmalloc(sizeof(struct tty_buffer) + 2 * size, GFP_ATOMIC);
+	if (p == NULL)
+		return NULL;
+	p->used = 0;
+	p->size = size;
+	p->next = NULL;
+	p->commit = 0;
+	p->read = 0;
+	p->char_buf_ptr = (char *)(p->data);
+	p->flag_buf_ptr = (unsigned char *)p->char_buf_ptr + size;
+	tty->buf.memory_used += size;
+	return p;
+}
+
+/**
+ *	tty_buffer_free		-	free a tty buffer
+ *	@tty: tty owning the buffer
+ *	@b: the buffer to free
+ *
+ *	Free a tty buffer, or add it to the free list according to our
+ *	internal strategy
+ *
+ *	Locking: Caller must hold tty->buf.lock
+ */
+
+static void tty_buffer_free(struct tty_struct *tty, struct tty_buffer *b)
+{
+	/* Dumb strategy for now - should keep some stats */
+	tty->buf.memory_used -= b->size;
+	WARN_ON(tty->buf.memory_used < 0);
+
+	if (b->size >= 512)
+		kfree(b);
+	else {
+		b->next = tty->buf.free;
+		tty->buf.free = b;
+	}
+}
+
+/**
+ *	__tty_buffer_flush		-	flush full tty buffers
+ *	@tty: tty to flush
+ *
+ *	flush all the buffers containing receive data. Caller must
+ *	hold the buffer lock and must have ensured no parallel flush to
+ *	ldisc is running.
+ *
+ *	Locking: Caller must hold tty->buf.lock
+ */
+
+static void __tty_buffer_flush(struct tty_struct *tty)
+{
+	struct tty_buffer *thead;
+
+	while ((thead = tty->buf.head) != NULL) {
+		tty->buf.head = thead->next;
+		tty_buffer_free(tty, thead);
+	}
+	tty->buf.tail = NULL;
+}
+
+/**
+ *	tty_buffer_flush		-	flush full tty buffers
+ *	@tty: tty to flush
+ *
+ *	flush all the buffers containing receive data. If the buffer is
+ *	being processed by flush_to_ldisc then we defer the processing
+ *	to that function
+ *
+ *	Locking: none
+ */
+
+void tty_buffer_flush(struct tty_struct *tty)
+{
+	unsigned long flags;
+	spin_lock_irqsave(&tty->buf.lock, flags);
+
+	/* If the data is being pushed to the tty layer then we can't
+	   process it here. Instead set a flag and the flush_to_ldisc
+	   path will process the flush request before it exits */
+	if (test_bit(TTY_FLUSHING, &tty->flags)) {
+		set_bit(TTY_FLUSHPENDING, &tty->flags);
+		spin_unlock_irqrestore(&tty->buf.lock, flags);
+		wait_event(tty->read_wait,
+				test_bit(TTY_FLUSHPENDING, &tty->flags) == 0);
+		return;
+	} else
+		__tty_buffer_flush(tty);
+	spin_unlock_irqrestore(&tty->buf.lock, flags);
+}
+
+/**
+ *	tty_buffer_find		-	find a free tty buffer
+ *	@tty: tty owning the buffer
+ *	@size: characters wanted
+ *
+ *	Locate an existing suitable tty buffer or if we are lacking one then
+ *	allocate a new one. We round our buffers off in 256 character chunks
+ *	to get better allocation behaviour.
+ *
+ *	Locking: Caller must hold tty->buf.lock
+ */
+
+static struct tty_buffer *tty_buffer_find(struct tty_struct *tty, size_t size)
+{
+	struct tty_buffer **tbh = &tty->buf.free;
+	while ((*tbh) != NULL) {
+		struct tty_buffer *t = *tbh;
+		if (t->size >= size) {
+			*tbh = t->next;
+			t->next = NULL;
+			t->used = 0;
+			t->commit = 0;
+			t->read = 0;
+			tty->buf.memory_used += t->size;
+			return t;
+		}
+		tbh = &((*tbh)->next);
+	}
+	/* Round the buffer size out */
+	size = (size + 0xFF) & ~0xFF;
+	return tty_buffer_alloc(tty, size);
+	/* Should possibly check if this fails for the largest buffer we
+	   have queued and recycle that ? */
+}
+
+/**
+ *	tty_buffer_request_room		-	grow tty buffer if needed
+ *	@tty: tty structure
+ *	@size: size desired
+ *
+ *	Make at least size bytes of linear space available for the tty
+ *	buffer. If we fail return the size we managed to find.
+ *
+ *	Locking: Takes tty->buf.lock
+ */
+int tty_buffer_request_room(struct tty_struct *tty, size_t size)
+{
+	struct tty_buffer *b, *n;
+	int left;
+	unsigned long flags;
+
+	spin_lock_irqsave(&tty->buf.lock, flags);
+
+	/* OPTIMISATION: We could keep a per tty "zero" sized buffer to
+	   remove this conditional if its worth it. This would be invisible
+	   to the callers */
+	if ((b = tty->buf.tail) != NULL)
+		left = b->size - b->used;
+	else
+		left = 0;
+
+	if (left < size) {
+		/* This is the slow path - looking for new buffers to use */
+		if ((n = tty_buffer_find(tty, size)) != NULL) {
+			if (b != NULL) {
+				b->next = n;
+				b->commit = b->used;
+			} else
+				tty->buf.head = n;
+			tty->buf.tail = n;
+		} else
+			size = left;
+	}
+
+	spin_unlock_irqrestore(&tty->buf.lock, flags);
+	return size;
+}
+EXPORT_SYMBOL_GPL(tty_buffer_request_room);
+
+/**
+ *	tty_insert_flip_string	-	Add characters to the tty buffer
+ *	@tty: tty structure
+ *	@chars: characters
+ *	@size: size
+ *
+ *	Queue a series of bytes to the tty buffering. All the characters
+ *	passed are marked as without error. Returns the number added.
+ *
+ *	Locking: Called functions may take tty->buf.lock
+ */
+
+int tty_insert_flip_string(struct tty_struct *tty, const unsigned char *chars,
+				size_t size)
+{
+	int copied = 0;
+	do {
+		int space = tty_buffer_request_room(tty, size - copied);
+		struct tty_buffer *tb = tty->buf.tail;
+		/* If there is no space then tb may be NULL */
+		if (unlikely(space == 0))
+			break;
+		memcpy(tb->char_buf_ptr + tb->used, chars, space);
+		memset(tb->flag_buf_ptr + tb->used, TTY_NORMAL, space);
+		tb->used += space;
+		copied += space;
+		chars += space;
+		/* There is a small chance that we need to split the data over
+		   several buffers. If this is the case we must loop */
+	} while (unlikely(size > copied));
+	return copied;
+}
+EXPORT_SYMBOL(tty_insert_flip_string);
+
+/**
+ *	tty_insert_flip_string_flags	-	Add characters to the tty buffer
+ *	@tty: tty structure
+ *	@chars: characters
+ *	@flags: flag bytes
+ *	@size: size
+ *
+ *	Queue a series of bytes to the tty buffering. For each character
+ *	the flags array indicates the status of the character. Returns the
+ *	number added.
+ *
+ *	Locking: Called functions may take tty->buf.lock
+ */
+
+int tty_insert_flip_string_flags(struct tty_struct *tty,
+		const unsigned char *chars, const char *flags, size_t size)
+{
+	int copied = 0;
+	do {
+		int space = tty_buffer_request_room(tty, size - copied);
+		struct tty_buffer *tb = tty->buf.tail;
+		/* If there is no space then tb may be NULL */
+		if (unlikely(space == 0))
+			break;
+		memcpy(tb->char_buf_ptr + tb->used, chars, space);
+		memcpy(tb->flag_buf_ptr + tb->used, flags, space);
+		tb->used += space;
+		copied += space;
+		chars += space;
+		flags += space;
+		/* There is a small chance that we need to split the data over
+		   several buffers. If this is the case we must loop */
+	} while (unlikely(size > copied));
+	return copied;
+}
+EXPORT_SYMBOL(tty_insert_flip_string_flags);
+
+/**
+ *	tty_schedule_flip	-	push characters to ldisc
+ *	@tty: tty to push from
+ *
+ *	Takes any pending buffers and transfers their ownership to the
+ *	ldisc side of the queue. It then schedules those characters for
+ *	processing by the line discipline.
+ *
+ *	Locking: Takes tty->buf.lock
+ */
+
+void tty_schedule_flip(struct tty_struct *tty)
+{
+	unsigned long flags;
+	spin_lock_irqsave(&tty->buf.lock, flags);
+	if (tty->buf.tail != NULL)
+		tty->buf.tail->commit = tty->buf.tail->used;
+	spin_unlock_irqrestore(&tty->buf.lock, flags);
+	schedule_delayed_work(&tty->buf.work, 1);
+}
+EXPORT_SYMBOL(tty_schedule_flip);
+
+/**
+ *	tty_prepare_flip_string		-	make room for characters
+ *	@tty: tty
+ *	@chars: return pointer for character write area
+ *	@size: desired size
+ *
+ *	Prepare a block of space in the buffer for data. Returns the length
+ *	available and buffer pointer to the space which is now allocated and
+ *	accounted for as ready for normal characters. This is used for drivers
+ *	that need their own block copy routines into the buffer. There is no
+ *	guarantee the buffer is a DMA target!
+ *
+ *	Locking: May call functions taking tty->buf.lock
+ */
+
+int tty_prepare_flip_string(struct tty_struct *tty, unsigned char **chars,
+								size_t size)
+{
+	int space = tty_buffer_request_room(tty, size);
+	if (likely(space)) {
+		struct tty_buffer *tb = tty->buf.tail;
+		*chars = tb->char_buf_ptr + tb->used;
+		memset(tb->flag_buf_ptr + tb->used, TTY_NORMAL, space);
+		tb->used += space;
+	}
+	return space;
+}
+EXPORT_SYMBOL_GPL(tty_prepare_flip_string);
+
+/**
+ *	tty_prepare_flip_string_flags	-	make room for characters
+ *	@tty: tty
+ *	@chars: return pointer for character write area
+ *	@flags: return pointer for status flag write area
+ *	@size: desired size
+ *
+ *	Prepare a block of space in the buffer for data. Returns the length
+ *	available and buffer pointer to the space which is now allocated and
+ *	accounted for as ready for characters. This is used for drivers
+ *	that need their own block copy routines into the buffer. There is no
+ *	guarantee the buffer is a DMA target!
+ *
+ *	Locking: May call functions taking tty->buf.lock
+ */
+
+int tty_prepare_flip_string_flags(struct tty_struct *tty,
+			unsigned char **chars, char **flags, size_t size)
+{
+	int space = tty_buffer_request_room(tty, size);
+	if (likely(space)) {
+		struct tty_buffer *tb = tty->buf.tail;
+		*chars = tb->char_buf_ptr + tb->used;
+		*flags = tb->flag_buf_ptr + tb->used;
+		tb->used += space;
+	}
+	return space;
+}
+EXPORT_SYMBOL_GPL(tty_prepare_flip_string_flags);
+
+
+
+/**
+ *	flush_to_ldisc
+ *	@work: tty structure passed from work queue.
+ *
+ *	This routine is called out of the software interrupt to flush data
+ *	from the buffer chain to the line discipline.
+ *
+ *	Locking: holds tty->buf.lock to guard buffer list. Drops the lock
+ *	while invoking the line discipline receive_buf method. The
+ *	receive_buf method is single threaded for each tty instance.
+ */
+
+static void flush_to_ldisc(struct work_struct *work)
+{
+	struct tty_struct *tty =
+		container_of(work, struct tty_struct, buf.work.work);
+	unsigned long 	flags;
+	struct tty_ldisc *disc;
+	struct tty_buffer *tbuf, *head;
+	char *char_buf;
+	unsigned char *flag_buf;
+
+	disc = tty_ldisc_ref(tty);
+	if (disc == NULL)	/*  !TTY_LDISC */
+		return;
+
+	spin_lock_irqsave(&tty->buf.lock, flags);
+	/* So we know a flush is running */
+	set_bit(TTY_FLUSHING, &tty->flags);
+	head = tty->buf.head;
+	if (head != NULL) {
+		tty->buf.head = NULL;
+		for (;;) {
+			int count = head->commit - head->read;
+			if (!count) {
+				if (head->next == NULL)
+					break;
+				tbuf = head;
+				head = head->next;
+				tty_buffer_free(tty, tbuf);
+				continue;
+			}
+			/* Ldisc or user is trying to flush the buffers
+			   we are feeding to the ldisc, stop feeding the
+			   line discipline as we want to empty the queue */
+			if (test_bit(TTY_FLUSHPENDING, &tty->flags))
+				break;
+			if (!tty->receive_room) {
+				schedule_delayed_work(&tty->buf.work, 1);
+				break;
+			}
+			if (count > tty->receive_room)
+				count = tty->receive_room;
+			char_buf = head->char_buf_ptr + head->read;
+			flag_buf = head->flag_buf_ptr + head->read;
+			head->read += count;
+			spin_unlock_irqrestore(&tty->buf.lock, flags);
+			disc->ops->receive_buf(tty, char_buf,
+							flag_buf, count);
+			spin_lock_irqsave(&tty->buf.lock, flags);
+		}
+		/* Restore the queue head */
+		tty->buf.head = head;
+	}
+	/* We may have a deferred request to flush the input buffer,
+	   if so pull the chain under the lock and empty the queue */
+	if (test_bit(TTY_FLUSHPENDING, &tty->flags)) {
+		__tty_buffer_flush(tty);
+		clear_bit(TTY_FLUSHPENDING, &tty->flags);
+		wake_up(&tty->read_wait);
+	}
+	clear_bit(TTY_FLUSHING, &tty->flags);
+	spin_unlock_irqrestore(&tty->buf.lock, flags);
+
+	tty_ldisc_deref(disc);
+}
+
+/**
+ *	tty_flip_buffer_push	-	terminal
+ *	@tty: tty to push
+ *
+ *	Queue a push of the terminal flip buffers to the line discipline. This
+ *	function must not be called from IRQ context if tty->low_latency is set.
+ *
+ *	In the event of the queue being busy for flipping the work will be
+ *	held off and retried later.
+ *
+ *	Locking: tty buffer lock. Driver locks in low latency mode.
+ */
+
+void tty_flip_buffer_push(struct tty_struct *tty)
+{
+	unsigned long flags;
+	spin_lock_irqsave(&tty->buf.lock, flags);
+	if (tty->buf.tail != NULL)
+		tty->buf.tail->commit = tty->buf.tail->used;
+	spin_unlock_irqrestore(&tty->buf.lock, flags);
+
+	if (tty->low_latency)
+		flush_to_ldisc(&tty->buf.work.work);
+	else
+		schedule_delayed_work(&tty->buf.work, 1);
+}
+EXPORT_SYMBOL(tty_flip_buffer_push);
+
+/**
+ *	tty_buffer_init		-	prepare a tty buffer structure
+ *	@tty: tty to initialise
+ *
+ *	Set up the initial state of the buffer management for a tty device.
+ *	Must be called before the other tty buffer functions are used.
+ *
+ *	Locking: none
+ */
+
+void tty_buffer_init(struct tty_struct *tty)
+{
+	spin_lock_init(&tty->buf.lock);
+	tty->buf.head = NULL;
+	tty->buf.tail = NULL;
+	tty->buf.free = NULL;
+	tty->buf.memory_used = 0;
+	INIT_DELAYED_WORK(&tty->buf.work, flush_to_ldisc);
+}
+
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
index daeb8f7..7053d63 100644
--- a/drivers/char/tty_io.c
+++ b/drivers/char/tty_io.c
@@ -49,7 +49,7 @@
  * implement CONFIG_VT and generalize console device interface.
  *	-- Marko Kohtala <Marko.Kohtala@hut.fi>, March 97
  *
- * Rewrote init_dev and release_dev to eliminate races.
+ * Rewrote tty_init_dev and tty_release_dev to eliminate races.
  *	-- Bill Hawes <whawes@star.net>, June 97
  *
  * Added devfs support.
@@ -136,13 +136,6 @@
 DEFINE_MUTEX(tty_mutex);
 EXPORT_SYMBOL(tty_mutex);
 
-#ifdef CONFIG_UNIX98_PTYS
-extern struct tty_driver *ptm_driver;	/* Unix98 pty masters; for /dev/ptmx */
-static int ptmx_open(struct inode *, struct file *);
-#endif
-
-static void initialize_tty_struct(struct tty_struct *tty);
-
 static ssize_t tty_read(struct file *, char __user *, size_t, loff_t *);
 static ssize_t tty_write(struct file *, const char __user *, size_t, loff_t *);
 ssize_t redirected_tty_write(struct file *, const char __user *,
@@ -171,13 +164,11 @@
  *	Locking: none
  */
 
-static struct tty_struct *alloc_tty_struct(void)
+struct tty_struct *alloc_tty_struct(void)
 {
 	return kzalloc(sizeof(struct tty_struct), GFP_KERNEL);
 }
 
-static void tty_buffer_free_all(struct tty_struct *);
-
 /**
  *	free_tty_struct		-	free a disused tty
  *	@tty: tty struct to free
@@ -187,7 +178,7 @@
  *	Locking: none. Must be called after tty is definitely unused
  */
 
-static inline void free_tty_struct(struct tty_struct *tty)
+void free_tty_struct(struct tty_struct *tty)
 {
 	kfree(tty->write_buf);
 	tty_buffer_free_all(tty);
@@ -263,398 +254,6 @@
 	return 0;
 }
 
-/*
- * Tty buffer allocation management
- */
-
-/**
- *	tty_buffer_free_all		-	free buffers used by a tty
- *	@tty: tty to free from
- *
- *	Remove all the buffers pending on a tty whether queued with data
- *	or in the free ring. Must be called when the tty is no longer in use
- *
- *	Locking: none
- */
-
-static void tty_buffer_free_all(struct tty_struct *tty)
-{
-	struct tty_buffer *thead;
-	while ((thead = tty->buf.head) != NULL) {
-		tty->buf.head = thead->next;
-		kfree(thead);
-	}
-	while ((thead = tty->buf.free) != NULL) {
-		tty->buf.free = thead->next;
-		kfree(thead);
-	}
-	tty->buf.tail = NULL;
-	tty->buf.memory_used = 0;
-}
-
-/**
- *	tty_buffer_init		-	prepare a tty buffer structure
- *	@tty: tty to initialise
- *
- *	Set up the initial state of the buffer management for a tty device.
- *	Must be called before the other tty buffer functions are used.
- *
- *	Locking: none
- */
-
-static void tty_buffer_init(struct tty_struct *tty)
-{
-	spin_lock_init(&tty->buf.lock);
-	tty->buf.head = NULL;
-	tty->buf.tail = NULL;
-	tty->buf.free = NULL;
-	tty->buf.memory_used = 0;
-}
-
-/**
- *	tty_buffer_alloc	-	allocate a tty buffer
- *	@tty: tty device
- *	@size: desired size (characters)
- *
- *	Allocate a new tty buffer to hold the desired number of characters.
- *	Return NULL if out of memory or the allocation would exceed the
- *	per device queue
- *
- *	Locking: Caller must hold tty->buf.lock
- */
-
-static struct tty_buffer *tty_buffer_alloc(struct tty_struct *tty, size_t size)
-{
-	struct tty_buffer *p;
-
-	if (tty->buf.memory_used + size > 65536)
-		return NULL;
-	p = kmalloc(sizeof(struct tty_buffer) + 2 * size, GFP_ATOMIC);
-	if (p == NULL)
-		return NULL;
-	p->used = 0;
-	p->size = size;
-	p->next = NULL;
-	p->commit = 0;
-	p->read = 0;
-	p->char_buf_ptr = (char *)(p->data);
-	p->flag_buf_ptr = (unsigned char *)p->char_buf_ptr + size;
-	tty->buf.memory_used += size;
-	return p;
-}
-
-/**
- *	tty_buffer_free		-	free a tty buffer
- *	@tty: tty owning the buffer
- *	@b: the buffer to free
- *
- *	Free a tty buffer, or add it to the free list according to our
- *	internal strategy
- *
- *	Locking: Caller must hold tty->buf.lock
- */
-
-static void tty_buffer_free(struct tty_struct *tty, struct tty_buffer *b)
-{
-	/* Dumb strategy for now - should keep some stats */
-	tty->buf.memory_used -= b->size;
-	WARN_ON(tty->buf.memory_used < 0);
-
-	if (b->size >= 512)
-		kfree(b);
-	else {
-		b->next = tty->buf.free;
-		tty->buf.free = b;
-	}
-}
-
-/**
- *	__tty_buffer_flush		-	flush full tty buffers
- *	@tty: tty to flush
- *
- *	flush all the buffers containing receive data. Caller must
- *	hold the buffer lock and must have ensured no parallel flush to
- *	ldisc is running.
- *
- *	Locking: Caller must hold tty->buf.lock
- */
-
-static void __tty_buffer_flush(struct tty_struct *tty)
-{
-	struct tty_buffer *thead;
-
-	while ((thead = tty->buf.head) != NULL) {
-		tty->buf.head = thead->next;
-		tty_buffer_free(tty, thead);
-	}
-	tty->buf.tail = NULL;
-}
-
-/**
- *	tty_buffer_flush		-	flush full tty buffers
- *	@tty: tty to flush
- *
- *	flush all the buffers containing receive data. If the buffer is
- *	being processed by flush_to_ldisc then we defer the processing
- *	to that function
- *
- *	Locking: none
- */
-
-static void tty_buffer_flush(struct tty_struct *tty)
-{
-	unsigned long flags;
-	spin_lock_irqsave(&tty->buf.lock, flags);
-
-	/* If the data is being pushed to the tty layer then we can't
-	   process it here. Instead set a flag and the flush_to_ldisc
-	   path will process the flush request before it exits */
-	if (test_bit(TTY_FLUSHING, &tty->flags)) {
-		set_bit(TTY_FLUSHPENDING, &tty->flags);
-		spin_unlock_irqrestore(&tty->buf.lock, flags);
-		wait_event(tty->read_wait,
-				test_bit(TTY_FLUSHPENDING, &tty->flags) == 0);
-		return;
-	} else
-		__tty_buffer_flush(tty);
-	spin_unlock_irqrestore(&tty->buf.lock, flags);
-}
-
-/**
- *	tty_buffer_find		-	find a free tty buffer
- *	@tty: tty owning the buffer
- *	@size: characters wanted
- *
- *	Locate an existing suitable tty buffer or if we are lacking one then
- *	allocate a new one. We round our buffers off in 256 character chunks
- *	to get better allocation behaviour.
- *
- *	Locking: Caller must hold tty->buf.lock
- */
-
-static struct tty_buffer *tty_buffer_find(struct tty_struct *tty, size_t size)
-{
-	struct tty_buffer **tbh = &tty->buf.free;
-	while ((*tbh) != NULL) {
-		struct tty_buffer *t = *tbh;
-		if (t->size >= size) {
-			*tbh = t->next;
-			t->next = NULL;
-			t->used = 0;
-			t->commit = 0;
-			t->read = 0;
-			tty->buf.memory_used += t->size;
-			return t;
-		}
-		tbh = &((*tbh)->next);
-	}
-	/* Round the buffer size out */
-	size = (size + 0xFF) & ~0xFF;
-	return tty_buffer_alloc(tty, size);
-	/* Should possibly check if this fails for the largest buffer we
-	   have queued and recycle that ? */
-}
-
-/**
- *	tty_buffer_request_room		-	grow tty buffer if needed
- *	@tty: tty structure
- *	@size: size desired
- *
- *	Make at least size bytes of linear space available for the tty
- *	buffer. If we fail return the size we managed to find.
- *
- *	Locking: Takes tty->buf.lock
- */
-int tty_buffer_request_room(struct tty_struct *tty, size_t size)
-{
-	struct tty_buffer *b, *n;
-	int left;
-	unsigned long flags;
-
-	spin_lock_irqsave(&tty->buf.lock, flags);
-
-	/* OPTIMISATION: We could keep a per tty "zero" sized buffer to
-	   remove this conditional if its worth it. This would be invisible
-	   to the callers */
-	if ((b = tty->buf.tail) != NULL)
-		left = b->size - b->used;
-	else
-		left = 0;
-
-	if (left < size) {
-		/* This is the slow path - looking for new buffers to use */
-		if ((n = tty_buffer_find(tty, size)) != NULL) {
-			if (b != NULL) {
-				b->next = n;
-				b->commit = b->used;
-			} else
-				tty->buf.head = n;
-			tty->buf.tail = n;
-		} else
-			size = left;
-	}
-
-	spin_unlock_irqrestore(&tty->buf.lock, flags);
-	return size;
-}
-EXPORT_SYMBOL_GPL(tty_buffer_request_room);
-
-/**
- *	tty_insert_flip_string	-	Add characters to the tty buffer
- *	@tty: tty structure
- *	@chars: characters
- *	@size: size
- *
- *	Queue a series of bytes to the tty buffering. All the characters
- *	passed are marked as without error. Returns the number added.
- *
- *	Locking: Called functions may take tty->buf.lock
- */
-
-int tty_insert_flip_string(struct tty_struct *tty, const unsigned char *chars,
-				size_t size)
-{
-	int copied = 0;
-	do {
-		int space = tty_buffer_request_room(tty, size - copied);
-		struct tty_buffer *tb = tty->buf.tail;
-		/* If there is no space then tb may be NULL */
-		if (unlikely(space == 0))
-			break;
-		memcpy(tb->char_buf_ptr + tb->used, chars, space);
-		memset(tb->flag_buf_ptr + tb->used, TTY_NORMAL, space);
-		tb->used += space;
-		copied += space;
-		chars += space;
-		/* There is a small chance that we need to split the data over
-		   several buffers. If this is the case we must loop */
-	} while (unlikely(size > copied));
-	return copied;
-}
-EXPORT_SYMBOL(tty_insert_flip_string);
-
-/**
- *	tty_insert_flip_string_flags	-	Add characters to the tty buffer
- *	@tty: tty structure
- *	@chars: characters
- *	@flags: flag bytes
- *	@size: size
- *
- *	Queue a series of bytes to the tty buffering. For each character
- *	the flags array indicates the status of the character. Returns the
- *	number added.
- *
- *	Locking: Called functions may take tty->buf.lock
- */
-
-int tty_insert_flip_string_flags(struct tty_struct *tty,
-		const unsigned char *chars, const char *flags, size_t size)
-{
-	int copied = 0;
-	do {
-		int space = tty_buffer_request_room(tty, size - copied);
-		struct tty_buffer *tb = tty->buf.tail;
-		/* If there is no space then tb may be NULL */
-		if (unlikely(space == 0))
-			break;
-		memcpy(tb->char_buf_ptr + tb->used, chars, space);
-		memcpy(tb->flag_buf_ptr + tb->used, flags, space);
-		tb->used += space;
-		copied += space;
-		chars += space;
-		flags += space;
-		/* There is a small chance that we need to split the data over
-		   several buffers. If this is the case we must loop */
-	} while (unlikely(size > copied));
-	return copied;
-}
-EXPORT_SYMBOL(tty_insert_flip_string_flags);
-
-/**
- *	tty_schedule_flip	-	push characters to ldisc
- *	@tty: tty to push from
- *
- *	Takes any pending buffers and transfers their ownership to the
- *	ldisc side of the queue. It then schedules those characters for
- *	processing by the line discipline.
- *
- *	Locking: Takes tty->buf.lock
- */
-
-void tty_schedule_flip(struct tty_struct *tty)
-{
-	unsigned long flags;
-	spin_lock_irqsave(&tty->buf.lock, flags);
-	if (tty->buf.tail != NULL)
-		tty->buf.tail->commit = tty->buf.tail->used;
-	spin_unlock_irqrestore(&tty->buf.lock, flags);
-	schedule_delayed_work(&tty->buf.work, 1);
-}
-EXPORT_SYMBOL(tty_schedule_flip);
-
-/**
- *	tty_prepare_flip_string		-	make room for characters
- *	@tty: tty
- *	@chars: return pointer for character write area
- *	@size: desired size
- *
- *	Prepare a block of space in the buffer for data. Returns the length
- *	available and buffer pointer to the space which is now allocated and
- *	accounted for as ready for normal characters. This is used for drivers
- *	that need their own block copy routines into the buffer. There is no
- *	guarantee the buffer is a DMA target!
- *
- *	Locking: May call functions taking tty->buf.lock
- */
-
-int tty_prepare_flip_string(struct tty_struct *tty, unsigned char **chars,
-								size_t size)
-{
-	int space = tty_buffer_request_room(tty, size);
-	if (likely(space)) {
-		struct tty_buffer *tb = tty->buf.tail;
-		*chars = tb->char_buf_ptr + tb->used;
-		memset(tb->flag_buf_ptr + tb->used, TTY_NORMAL, space);
-		tb->used += space;
-	}
-	return space;
-}
-
-EXPORT_SYMBOL_GPL(tty_prepare_flip_string);
-
-/**
- *	tty_prepare_flip_string_flags	-	make room for characters
- *	@tty: tty
- *	@chars: return pointer for character write area
- *	@flags: return pointer for status flag write area
- *	@size: desired size
- *
- *	Prepare a block of space in the buffer for data. Returns the length
- *	available and buffer pointer to the space which is now allocated and
- *	accounted for as ready for characters. This is used for drivers
- *	that need their own block copy routines into the buffer. There is no
- *	guarantee the buffer is a DMA target!
- *
- *	Locking: May call functions taking tty->buf.lock
- */
-
-int tty_prepare_flip_string_flags(struct tty_struct *tty,
-			unsigned char **chars, char **flags, size_t size)
-{
-	int space = tty_buffer_request_room(tty, size);
-	if (likely(space)) {
-		struct tty_buffer *tb = tty->buf.tail;
-		*chars = tb->char_buf_ptr + tb->used;
-		*flags = tb->flag_buf_ptr + tb->used;
-		tb->used += space;
-	}
-	return space;
-}
-
-EXPORT_SYMBOL_GPL(tty_prepare_flip_string_flags);
-
-
-
 /**
  *	get_tty_driver		-	find device of a tty
  *	@dev_t: device identifier
@@ -675,7 +274,7 @@
 		if (device < base || device >= base + p->num)
 			continue;
 		*index = device - base;
-		return p;
+		return tty_driver_kref_get(p);
 	}
 	return NULL;
 }
@@ -695,13 +294,23 @@
 {
 	struct tty_driver *p, *res = NULL;
 	int tty_line = 0;
+	int len;
 	char *str;
 
+	for (str = name; *str; str++)
+		if ((*str >= '0' && *str <= '9') || *str == ',')
+			break;
+	if (!*str)
+		return NULL;
+
+	len = str - name;
+	tty_line = simple_strtoul(str, &str, 10);
+
 	mutex_lock(&tty_mutex);
 	/* Search through the tty devices to look for a match */
 	list_for_each_entry(p, &tty_drivers, tty_drivers) {
-		str = name + strlen(p->name);
-		tty_line = simple_strtoul(str, &str, 10);
+		if (strncmp(name, p->name, len) != 0)
+			continue;
 		if (*str == ',')
 			str++;
 		if (*str == '\0')
@@ -709,7 +318,7 @@
 
 		if (tty_line >= 0 && tty_line <= p->num && p->ops &&
 		    p->ops->poll_init && !p->ops->poll_init(p, tty_line, str)) {
-			res = p;
+			res = tty_driver_kref_get(p);
 			*line = tty_line;
 			break;
 		}
@@ -809,20 +418,6 @@
 	.fasync		= tty_fasync,
 };
 
-#ifdef CONFIG_UNIX98_PTYS
-static const struct file_operations ptmx_fops = {
-	.llseek		= no_llseek,
-	.read		= tty_read,
-	.write		= tty_write,
-	.poll		= tty_poll,
-	.unlocked_ioctl	= tty_ioctl,
-	.compat_ioctl	= tty_compat_ioctl,
-	.open		= ptmx_open,
-	.release	= tty_release,
-	.fasync		= tty_fasync,
-};
-#endif
-
 static const struct file_operations console_fops = {
 	.llseek		= no_llseek,
 	.read		= tty_read,
@@ -943,6 +538,7 @@
 	struct tty_ldisc *ld;
 	int    closecount = 0, n;
 	unsigned long flags;
+	int refs = 0;
 
 	if (!tty)
 		return;
@@ -1009,8 +605,12 @@
 	if (tty->session) {
 		do_each_pid_task(tty->session, PIDTYPE_SID, p) {
 			spin_lock_irq(&p->sighand->siglock);
-			if (p->signal->tty == tty)
+			if (p->signal->tty == tty) {
 				p->signal->tty = NULL;
+				/* We defer the dereferences outside fo
+				   the tasklist lock */
+				refs++;
+			}
 			if (!p->signal->leader) {
 				spin_unlock_irq(&p->sighand->siglock);
 				continue;
@@ -1036,6 +636,10 @@
 	tty->ctrl_status = 0;
 	spin_unlock_irqrestore(&tty->ctrl_lock, flags);
 
+	/* Account for the p->signal references we killed */
+	while (refs--)
+		tty_kref_put(tty);
+
 	/*
 	 * If one of the devices matches a console pointer, we
 	 * cannot just call hangup() because that will cause
@@ -1105,6 +709,23 @@
 EXPORT_SYMBOL(tty_vhangup);
 
 /**
+ *	tty_vhangup_self	-	process vhangup for own ctty
+ *
+ *	Perform a vhangup on the current controlling tty
+ */
+
+void tty_vhangup_self(void)
+{
+	struct tty_struct *tty;
+
+	tty = get_current_tty();
+	if (tty) {
+		tty_vhangup(tty);
+		tty_kref_put(tty);
+	}
+}
+
+/**
  *	tty_hung_up_p		-	was tty hung up
  *	@filp: file pointer of tty
  *
@@ -1157,16 +778,14 @@
 	struct pid *tty_pgrp = NULL;
 
 
-	mutex_lock(&tty_mutex);
 	tty = get_current_tty();
 	if (tty) {
 		tty_pgrp = get_pid(tty->pgrp);
 		lock_kernel();
-		mutex_unlock(&tty_mutex);
-		/* XXX: here we race, there is nothing protecting tty */
 		if (on_exit && tty->driver->type != TTY_DRIVER_TYPE_PTY)
 			tty_vhangup(tty);
 		unlock_kernel();
+		tty_kref_put(tty);
 	} else if (on_exit) {
 		struct pid *old_pgrp;
 		spin_lock_irq(&current->sighand->siglock);
@@ -1178,7 +797,6 @@
 			kill_pgrp(old_pgrp, SIGCONT, on_exit);
 			put_pid(old_pgrp);
 		}
-		mutex_unlock(&tty_mutex);
 		return;
 	}
 	if (tty_pgrp) {
@@ -1193,8 +811,6 @@
 	current->signal->tty_old_pgrp = NULL;
 	spin_unlock_irq(&current->sighand->siglock);
 
-	mutex_lock(&tty_mutex);
-	/* It is possible that do_tty_hangup has free'd this tty */
 	tty = get_current_tty();
 	if (tty) {
 		unsigned long flags;
@@ -1204,13 +820,13 @@
 		tty->session = NULL;
 		tty->pgrp = NULL;
 		spin_unlock_irqrestore(&tty->ctrl_lock, flags);
+		tty_kref_put(tty);
 	} else {
 #ifdef TTY_DEBUG_HANGUP
 		printk(KERN_DEBUG "error attempted to write to tty [0x%p]"
 		       " = NULL", tty);
 #endif
 	}
-	mutex_unlock(&tty_mutex);
 
 	/* Now clear signal->tty under the lock */
 	read_lock(&tasklist_lock);
@@ -1410,19 +1026,19 @@
 
 	/* write_buf/write_cnt is protected by the atomic_write_lock mutex */
 	if (tty->write_cnt < chunk) {
-		unsigned char *buf;
+		unsigned char *buf_chunk;
 
 		if (chunk < 1024)
 			chunk = 1024;
 
-		buf = kmalloc(chunk, GFP_KERNEL);
-		if (!buf) {
+		buf_chunk = kmalloc(chunk, GFP_KERNEL);
+		if (!buf_chunk) {
 			ret = -ENOMEM;
 			goto out;
 		}
 		kfree(tty->write_buf);
 		tty->write_cnt = chunk;
-		tty->write_buf = buf;
+		tty->write_buf = buf_chunk;
 	}
 
 	/* Do the write .. */
@@ -1456,6 +1072,31 @@
 	return ret;
 }
 
+/**
+ * tty_write_message - write a message to a certain tty, not just the console.
+ * @tty: the destination tty_struct
+ * @msg: the message to write
+ *
+ * This is used for messages that need to be redirected to a specific tty.
+ * We don't put it into the syslog queue right now maybe in the future if
+ * really needed.
+ *
+ * We must still hold the BKL and test the CLOSING flag for the moment.
+ */
+
+void tty_write_message(struct tty_struct *tty, char *msg)
+{
+	lock_kernel();
+	if (tty) {
+		mutex_lock(&tty->atomic_write_lock);
+		if (tty->ops->write && !test_bit(TTY_CLOSING, &tty->flags))
+			tty->ops->write(tty, msg, strlen(msg));
+		tty_write_unlock(tty);
+	}
+	unlock_kernel();
+	return;
+}
+
 
 /**
  *	tty_write		-	write method for tty device file
@@ -1523,42 +1164,6 @@
 	return tty_write(file, buf, count, ppos);
 }
 
-void tty_port_init(struct tty_port *port)
-{
-	memset(port, 0, sizeof(*port));
-	init_waitqueue_head(&port->open_wait);
-	init_waitqueue_head(&port->close_wait);
-	mutex_init(&port->mutex);
-	port->close_delay = (50 * HZ) / 100;
-	port->closing_wait = (3000 * HZ) / 100;
-}
-EXPORT_SYMBOL(tty_port_init);
-
-int tty_port_alloc_xmit_buf(struct tty_port *port)
-{
-	/* We may sleep in get_zeroed_page() */
-	mutex_lock(&port->mutex);
-	if (port->xmit_buf == NULL)
-		port->xmit_buf = (unsigned char *)get_zeroed_page(GFP_KERNEL);
-	mutex_unlock(&port->mutex);
-	if (port->xmit_buf == NULL)
-		return -ENOMEM;
-	return 0;
-}
-EXPORT_SYMBOL(tty_port_alloc_xmit_buf);
-
-void tty_port_free_xmit_buf(struct tty_port *port)
-{
-	mutex_lock(&port->mutex);
-	if (port->xmit_buf != NULL) {
-		free_page((unsigned long)port->xmit_buf);
-		port->xmit_buf = NULL;
-	}
-	mutex_unlock(&port->mutex);
-}
-EXPORT_SYMBOL(tty_port_free_xmit_buf);
-
-
 static char ptychar[] = "pqrstuvwxyzabcde";
 
 /**
@@ -1582,7 +1187,7 @@
 }
 
 /**
- *	pty_line_name	-	generate name for a tty
+ *	tty_line_name	-	generate name for a tty
  *	@driver: the tty driver in use
  *	@index: the minor number
  *	@p: output buffer of at least 7 bytes
@@ -1598,10 +1203,148 @@
 }
 
 /**
- *	init_dev		-	initialise a tty device
+ *	tty_driver_lookup_tty() - find an existing tty, if any
+ *	@driver: the driver for the tty
+ *	@idx:	 the minor number
+ *
+ *	Return the tty, if found or ERR_PTR() otherwise.
+ *
+ *	Locking: tty_mutex must be held. If tty is found, the mutex must
+ *	be held until the 'fast-open' is also done. Will change once we
+ *	have refcounting in the driver and per driver locking
+ */
+struct tty_struct *tty_driver_lookup_tty(struct tty_driver *driver,
+		struct inode *inode, int idx)
+{
+	struct tty_struct *tty;
+
+	if (driver->ops->lookup)
+		return driver->ops->lookup(driver, inode, idx);
+
+	tty = driver->ttys[idx];
+	return tty;
+}
+
+/**
+ *	tty_init_termios	-  helper for termios setup
+ *	@tty: the tty to set up
+ *
+ *	Initialise the termios structures for this tty. Thus runs under
+ *	the tty_mutex currently so we can be relaxed about ordering.
+ */
+
+int tty_init_termios(struct tty_struct *tty)
+{
+	struct ktermios *tp;
+	int idx = tty->index;
+
+	tp = tty->driver->termios[idx];
+	if (tp == NULL) {
+		tp = kzalloc(sizeof(struct ktermios[2]), GFP_KERNEL);
+		if (tp == NULL)
+			return -ENOMEM;
+		memcpy(tp, &tty->driver->init_termios,
+						sizeof(struct ktermios));
+		tty->driver->termios[idx] = tp;
+	}
+	tty->termios = tp;
+	tty->termios_locked = tp + 1;
+
+	/* Compatibility until drivers always set this */
+	tty->termios->c_ispeed = tty_termios_input_baud_rate(tty->termios);
+	tty->termios->c_ospeed = tty_termios_baud_rate(tty->termios);
+	return 0;
+}
+
+/**
+ *	tty_driver_install_tty() - install a tty entry in the driver
+ *	@driver: the driver for the tty
+ *	@tty: the tty
+ *
+ *	Install a tty object into the driver tables. The tty->index field
+ *	will be set by the time this is called. This method is responsible
+ *	for ensuring any need additional structures are allocated and
+ *	configured.
+ *
+ *	Locking: tty_mutex for now
+ */
+static int tty_driver_install_tty(struct tty_driver *driver,
+						struct tty_struct *tty)
+{
+	int idx = tty->index;
+
+	if (driver->ops->install)
+		return driver->ops->install(driver, tty);
+
+	if (tty_init_termios(tty) == 0) {
+		tty_driver_kref_get(driver);
+		tty->count++;
+		driver->ttys[idx] = tty;
+		return 0;
+	}
+	return -ENOMEM;
+}
+
+/**
+ *	tty_driver_remove_tty() - remove a tty from the driver tables
+ *	@driver: the driver for the tty
+ *	@idx:	 the minor number
+ *
+ *	Remvoe a tty object from the driver tables. The tty->index field
+ *	will be set by the time this is called.
+ *
+ *	Locking: tty_mutex for now
+ */
+static void tty_driver_remove_tty(struct tty_driver *driver,
+						struct tty_struct *tty)
+{
+	if (driver->ops->remove)
+		driver->ops->remove(driver, tty);
+	else
+		driver->ttys[tty->index] = NULL;
+}
+
+/*
+ * 	tty_reopen()	- fast re-open of an open tty
+ * 	@tty	- the tty to open
+ *
+ *	Return 0 on success, -errno on error.
+ *
+ *	Locking: tty_mutex must be held from the time the tty was found
+ *		 till this open completes.
+ */
+static int tty_reopen(struct tty_struct *tty)
+{
+	struct tty_driver *driver = tty->driver;
+
+	if (test_bit(TTY_CLOSING, &tty->flags))
+		return -EIO;
+
+	if (driver->type == TTY_DRIVER_TYPE_PTY &&
+	    driver->subtype == PTY_TYPE_MASTER) {
+		/*
+		 * special case for PTY masters: only one open permitted,
+		 * and the slave side open count is incremented as well.
+		 */
+		if (tty->count)
+			return -EIO;
+
+		tty->link->count++;
+	}
+	tty->count++;
+	tty->driver = driver; /* N.B. why do this every time?? */
+
+	WARN_ON(!test_bit(TTY_LDISC, &tty->flags));
+
+	return 0;
+}
+
+/**
+ *	tty_init_dev		-	initialise a tty device
  *	@driver: tty driver we are opening a device on
  *	@idx: device index
- *	@tty: returned tty structure
+ *	@ret_tty: returned tty structure
+ *	@first_ok: ok to open a new device (used by ptmx)
  *
  *	Prepare a tty device. This may not be a "new" clean device but
  *	could also be an active device. The pty drivers require special
@@ -1621,37 +1364,16 @@
  * relaxed for the (most common) case of reopening a tty.
  */
 
-static int init_dev(struct tty_driver *driver, int idx,
-	struct tty_struct **ret_tty)
+struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx,
+								int first_ok)
 {
-	struct tty_struct *tty, *o_tty;
-	struct ktermios *tp, **tp_loc, *o_tp, **o_tp_loc;
-	struct ktermios *ltp, **ltp_loc, *o_ltp, **o_ltp_loc;
-	int retval = 0;
+	struct tty_struct *tty;
+	int retval;
 
-	/* check whether we're reopening an existing tty */
-	if (driver->flags & TTY_DRIVER_DEVPTS_MEM) {
-		tty = devpts_get_tty(idx);
-		/*
-		 * If we don't have a tty here on a slave open, it's because
-		 * the master already started the close process and there's
-		 * no relation between devpts file and tty anymore.
-		 */
-		if (!tty && driver->subtype == PTY_TYPE_SLAVE) {
-			retval = -EIO;
-			goto end_init;
-		}
-		/*
-		 * It's safe from now on because init_dev() is called with
-		 * tty_mutex held and release_dev() won't change tty->count
-		 * or tty->flags without having to grab tty_mutex
-		 */
-		if (tty && driver->subtype == PTY_TYPE_MASTER)
-			tty = tty->link;
-	} else {
-		tty = driver->ttys[idx];
-	}
-	if (tty) goto fast_track;
+	/* Check if pty master is being opened multiple times */
+	if (driver->subtype == PTY_TYPE_MASTER &&
+		(driver->flags & TTY_DRIVER_DEVPTS_MEM) && !first_ok)
+		return ERR_PTR(-EIO);
 
 	/*
 	 * First time open is complex, especially for PTY devices.
@@ -1661,189 +1383,69 @@
 	 * and locked termios may be retained.)
 	 */
 
-	if (!try_module_get(driver->owner)) {
-		retval = -ENODEV;
-		goto end_init;
-	}
-
-	o_tty = NULL;
-	tp = o_tp = NULL;
-	ltp = o_ltp = NULL;
+	if (!try_module_get(driver->owner))
+		return ERR_PTR(-ENODEV);
 
 	tty = alloc_tty_struct();
 	if (!tty)
 		goto fail_no_mem;
-	initialize_tty_struct(tty);
-	tty->driver = driver;
-	tty->ops = driver->ops;
-	tty->index = idx;
-	tty_line_name(driver, idx, tty->name);
+	initialize_tty_struct(tty, driver, idx);
 
-	if (driver->flags & TTY_DRIVER_DEVPTS_MEM) {
-		tp_loc = &tty->termios;
-		ltp_loc = &tty->termios_locked;
-	} else {
-		tp_loc = &driver->termios[idx];
-		ltp_loc = &driver->termios_locked[idx];
+	retval = tty_driver_install_tty(driver, tty);
+	if (retval < 0) {
+		free_tty_struct(tty);
+		module_put(driver->owner);
+		return ERR_PTR(retval);
 	}
 
-	if (!*tp_loc) {
-		tp = kmalloc(sizeof(struct ktermios), GFP_KERNEL);
-		if (!tp)
-			goto free_mem_out;
-		*tp = driver->init_termios;
-	}
-
-	if (!*ltp_loc) {
-		ltp = kzalloc(sizeof(struct ktermios), GFP_KERNEL);
-		if (!ltp)
-			goto free_mem_out;
-	}
-
-	if (driver->type == TTY_DRIVER_TYPE_PTY) {
-		o_tty = alloc_tty_struct();
-		if (!o_tty)
-			goto free_mem_out;
-		initialize_tty_struct(o_tty);
-		o_tty->driver = driver->other;
-		o_tty->ops = driver->ops;
-		o_tty->index = idx;
-		tty_line_name(driver->other, idx, o_tty->name);
-
-		if (driver->flags & TTY_DRIVER_DEVPTS_MEM) {
-			o_tp_loc = &o_tty->termios;
-			o_ltp_loc = &o_tty->termios_locked;
-		} else {
-			o_tp_loc = &driver->other->termios[idx];
-			o_ltp_loc = &driver->other->termios_locked[idx];
-		}
-
-		if (!*o_tp_loc) {
-			o_tp = kmalloc(sizeof(struct ktermios), GFP_KERNEL);
-			if (!o_tp)
-				goto free_mem_out;
-			*o_tp = driver->other->init_termios;
-		}
-
-		if (!*o_ltp_loc) {
-			o_ltp = kzalloc(sizeof(struct ktermios), GFP_KERNEL);
-			if (!o_ltp)
-				goto free_mem_out;
-		}
-
-		/*
-		 * Everything allocated ... set up the o_tty structure.
-		 */
-		if (!(driver->other->flags & TTY_DRIVER_DEVPTS_MEM))
-			driver->other->ttys[idx] = o_tty;
-		if (!*o_tp_loc)
-			*o_tp_loc = o_tp;
-		if (!*o_ltp_loc)
-			*o_ltp_loc = o_ltp;
-		o_tty->termios = *o_tp_loc;
-		o_tty->termios_locked = *o_ltp_loc;
-		driver->other->refcount++;
-		if (driver->subtype == PTY_TYPE_MASTER)
-			o_tty->count++;
-
-		/* Establish the links in both directions */
-		tty->link   = o_tty;
-		o_tty->link = tty;
-	}
-
-	/*
-	 * All structures have been allocated, so now we install them.
-	 * Failures after this point use release_tty to clean up, so
-	 * there's no need to null out the local pointers.
-	 */
-	if (!(driver->flags & TTY_DRIVER_DEVPTS_MEM))
-		driver->ttys[idx] = tty;
-
-	if (!*tp_loc)
-		*tp_loc = tp;
-	if (!*ltp_loc)
-		*ltp_loc = ltp;
-	tty->termios = *tp_loc;
-	tty->termios_locked = *ltp_loc;
-	/* Compatibility until drivers always set this */
-	tty->termios->c_ispeed = tty_termios_input_baud_rate(tty->termios);
-	tty->termios->c_ospeed = tty_termios_baud_rate(tty->termios);
-	driver->refcount++;
-	tty->count++;
-
 	/*
 	 * Structures all installed ... call the ldisc open routines.
 	 * If we fail here just call release_tty to clean up.  No need
 	 * to decrement the use counts, as release_tty doesn't care.
 	 */
 
-	retval = tty_ldisc_setup(tty, o_tty);
-
+	retval = tty_ldisc_setup(tty, tty->link);
 	if (retval)
 		goto release_mem_out;
-	 goto success;
-
-	/*
-	 * This fast open can be used if the tty is already open.
-	 * No memory is allocated, and the only failures are from
-	 * attempting to open a closing tty or attempting multiple
-	 * opens on a pty master.
-	 */
-fast_track:
-	if (test_bit(TTY_CLOSING, &tty->flags)) {
-		retval = -EIO;
-		goto end_init;
-	}
-	if (driver->type == TTY_DRIVER_TYPE_PTY &&
-	    driver->subtype == PTY_TYPE_MASTER) {
-		/*
-		 * special case for PTY masters: only one open permitted,
-		 * and the slave side open count is incremented as well.
-		 */
-		if (tty->count) {
-			retval = -EIO;
-			goto end_init;
-		}
-		tty->link->count++;
-	}
-	tty->count++;
-	tty->driver = driver; /* N.B. why do this every time?? */
-
-	/* FIXME */
-	if (!test_bit(TTY_LDISC, &tty->flags))
-		printk(KERN_ERR "init_dev but no ldisc\n");
-success:
-	*ret_tty = tty;
-
-	/* All paths come through here to release the mutex */
-end_init:
-	return retval;
-
-	/* Release locally allocated memory ... nothing placed in slots */
-free_mem_out:
-	kfree(o_tp);
-	if (o_tty)
-		free_tty_struct(o_tty);
-	kfree(ltp);
-	kfree(tp);
-	free_tty_struct(tty);
+	return tty;
 
 fail_no_mem:
 	module_put(driver->owner);
-	retval = -ENOMEM;
-	goto end_init;
+	return ERR_PTR(-ENOMEM);
 
 	/* call the tty release_tty routine to clean out this slot */
 release_mem_out:
 	if (printk_ratelimit())
-		printk(KERN_INFO "init_dev: ldisc open failed, "
+		printk(KERN_INFO "tty_init_dev: ldisc open failed, "
 				 "clearing slot %d\n", idx);
 	release_tty(tty, idx);
-	goto end_init;
+	return ERR_PTR(retval);
 }
 
+void tty_free_termios(struct tty_struct *tty)
+{
+	struct ktermios *tp;
+	int idx = tty->index;
+	/* Kill this flag and push into drivers for locking etc */
+	if (tty->driver->flags & TTY_DRIVER_RESET_TERMIOS) {
+		/* FIXME: Locking on ->termios array */
+		tp = tty->termios;
+		tty->driver->termios[idx] = NULL;
+		kfree(tp);
+	}
+}
+EXPORT_SYMBOL(tty_free_termios);
+
+void tty_shutdown(struct tty_struct *tty)
+{
+	tty_driver_remove_tty(tty->driver, tty);
+	tty_free_termios(tty);
+}
+EXPORT_SYMBOL(tty_shutdown);
+
 /**
  *	release_one_tty		-	release tty structure memory
+ *	@kref: kref of tty we are obliterating
  *
  *	Releases memory associated with a tty structure, and clears out the
  *	driver table slots. This function is called when a device is no longer
@@ -1853,31 +1455,19 @@
  *		tty_mutex - sometimes only
  *		takes the file list lock internally when working on the list
  *	of ttys that the driver keeps.
- *		FIXME: should we require tty_mutex is held here ??
  */
-static void release_one_tty(struct tty_struct *tty, int idx)
+static void release_one_tty(struct kref *kref)
 {
-	int devpts = tty->driver->flags & TTY_DRIVER_DEVPTS_MEM;
-	struct ktermios *tp;
+	struct tty_struct *tty = container_of(kref, struct tty_struct, kref);
+	struct tty_driver *driver = tty->driver;
 
-	if (!devpts)
-		tty->driver->ttys[idx] = NULL;
-
-	if (tty->driver->flags & TTY_DRIVER_RESET_TERMIOS) {
-		tp = tty->termios;
-		if (!devpts)
-			tty->driver->termios[idx] = NULL;
-		kfree(tp);
-
-		tp = tty->termios_locked;
-		if (!devpts)
-			tty->driver->termios_locked[idx] = NULL;
-		kfree(tp);
-	}
-
-
+	if (tty->ops->shutdown)
+		tty->ops->shutdown(tty);
+	else
+		tty_shutdown(tty);
 	tty->magic = 0;
-	tty->driver->refcount--;
+	tty_driver_kref_put(driver);
+	module_put(driver->owner);
 
 	file_list_lock();
 	list_del_init(&tty->tty_files);
@@ -1887,6 +1477,21 @@
 }
 
 /**
+ *	tty_kref_put		-	release a tty kref
+ *	@tty: tty device
+ *
+ *	Release a reference to a tty device and if need be let the kref
+ *	layer destruct the object for us
+ */
+
+void tty_kref_put(struct tty_struct *tty)
+{
+	if (tty)
+		kref_put(&tty->kref, release_one_tty);
+}
+EXPORT_SYMBOL(tty_kref_put);
+
+/**
  *	release_tty		-	release tty structure memory
  *
  *	Release both @tty and a possible linked partner (think pty pair),
@@ -1897,15 +1502,16 @@
  *		takes the file list lock internally when working on the list
  *	of ttys that the driver keeps.
  *		FIXME: should we require tty_mutex is held here ??
+ *
  */
 static void release_tty(struct tty_struct *tty, int idx)
 {
-	struct tty_driver *driver = tty->driver;
+	/* This should always be true but check for the moment */
+	WARN_ON(tty->index != idx);
 
 	if (tty->link)
-		release_one_tty(tty->link, idx);
-	release_one_tty(tty, idx);
-	module_put(driver->owner);
+		tty_kref_put(tty->link);
+	tty_kref_put(tty);
 }
 
 /*
@@ -1916,20 +1522,21 @@
  * WSH 09/09/97: rewritten to avoid some nasty race conditions that could
  * lead to double frees or releasing memory still in use.
  */
-static void release_dev(struct file *filp)
+void tty_release_dev(struct file *filp)
 {
 	struct tty_struct *tty, *o_tty;
 	int	pty_master, tty_closing, o_tty_closing, do_sleep;
 	int	devpts;
 	int	idx;
 	char	buf[64];
+	struct 	inode *inode;
 
+	inode = filp->f_path.dentry->d_inode;
 	tty = (struct tty_struct *)filp->private_data;
-	if (tty_paranoia_check(tty, filp->f_path.dentry->d_inode,
-							"release_dev"))
+	if (tty_paranoia_check(tty, inode, "tty_release_dev"))
 		return;
 
-	check_tty_count(tty, "release_dev");
+	check_tty_count(tty, "tty_release_dev");
 
 	tty_fasync(-1, filp, 0);
 
@@ -1941,33 +1548,27 @@
 
 #ifdef TTY_PARANOIA_CHECK
 	if (idx < 0 || idx >= tty->driver->num) {
-		printk(KERN_DEBUG "release_dev: bad idx when trying to "
+		printk(KERN_DEBUG "tty_release_dev: bad idx when trying to "
 				  "free (%s)\n", tty->name);
 		return;
 	}
-	if (!(tty->driver->flags & TTY_DRIVER_DEVPTS_MEM)) {
+	if (!devpts) {
 		if (tty != tty->driver->ttys[idx]) {
-			printk(KERN_DEBUG "release_dev: driver.table[%d] not tty "
+			printk(KERN_DEBUG "tty_release_dev: driver.table[%d] not tty "
 			       "for (%s)\n", idx, tty->name);
 			return;
 		}
 		if (tty->termios != tty->driver->termios[idx]) {
-			printk(KERN_DEBUG "release_dev: driver.termios[%d] not termios "
+			printk(KERN_DEBUG "tty_release_dev: driver.termios[%d] not termios "
 			       "for (%s)\n",
 			       idx, tty->name);
 			return;
 		}
-		if (tty->termios_locked != tty->driver->termios_locked[idx]) {
-			printk(KERN_DEBUG "release_dev: driver.termios_locked[%d] not "
-			       "termios_locked for (%s)\n",
-			       idx, tty->name);
-			return;
-		}
 	}
 #endif
 
 #ifdef TTY_DEBUG_HANGUP
-	printk(KERN_DEBUG "release_dev of %s (tty count=%d)...",
+	printk(KERN_DEBUG "tty_release_dev of %s (tty count=%d)...",
 	       tty_name(tty, buf), tty->count);
 #endif
 
@@ -1975,26 +1576,19 @@
 	if (tty->driver->other &&
 	     !(tty->driver->flags & TTY_DRIVER_DEVPTS_MEM)) {
 		if (o_tty != tty->driver->other->ttys[idx]) {
-			printk(KERN_DEBUG "release_dev: other->table[%d] "
+			printk(KERN_DEBUG "tty_release_dev: other->table[%d] "
 					  "not o_tty for (%s)\n",
 			       idx, tty->name);
 			return;
 		}
 		if (o_tty->termios != tty->driver->other->termios[idx]) {
-			printk(KERN_DEBUG "release_dev: other->termios[%d] "
+			printk(KERN_DEBUG "tty_release_dev: other->termios[%d] "
 					  "not o_termios for (%s)\n",
 			       idx, tty->name);
 			return;
 		}
-		if (o_tty->termios_locked !=
-		      tty->driver->other->termios_locked[idx]) {
-			printk(KERN_DEBUG "release_dev: other->termios_locked["
-					  "%d] not o_termios_locked for (%s)\n",
-			       idx, tty->name);
-			return;
-		}
 		if (o_tty->link != tty) {
-			printk(KERN_DEBUG "release_dev: bad pty pointers\n");
+			printk(KERN_DEBUG "tty_release_dev: bad pty pointers\n");
 			return;
 		}
 	}
@@ -2052,7 +1646,7 @@
 		if (!do_sleep)
 			break;
 
-		printk(KERN_WARNING "release_dev: %s: read/write wait queue "
+		printk(KERN_WARNING "tty_release_dev: %s: read/write wait queue "
 				    "active!\n", tty_name(tty, buf));
 		mutex_unlock(&tty_mutex);
 		schedule();
@@ -2065,14 +1659,14 @@
 	 */
 	if (pty_master) {
 		if (--o_tty->count < 0) {
-			printk(KERN_WARNING "release_dev: bad pty slave count "
+			printk(KERN_WARNING "tty_release_dev: bad pty slave count "
 					    "(%d) for %s\n",
 			       o_tty->count, tty_name(o_tty, buf));
 			o_tty->count = 0;
 		}
 	}
 	if (--tty->count < 0) {
-		printk(KERN_WARNING "release_dev: bad tty->count (%d) for %s\n",
+		printk(KERN_WARNING "tty_release_dev: bad tty->count (%d) for %s\n",
 		       tty->count, tty_name(tty, buf));
 		tty->count = 0;
 	}
@@ -2135,11 +1729,11 @@
 
 	/* Make this pty number available for reallocation */
 	if (devpts)
-		devpts_kill_index(idx);
+		devpts_kill_index(inode, idx);
 }
 
 /**
- *	tty_open		-	open a tty device
+ *	__tty_open		-	open a tty device
  *	@inode: inode of device file
  *	@filp: file pointer to tty
  *
@@ -2154,14 +1748,14 @@
  *	The termios state of a pty is reset on first open so that
  *	settings don't persist across reuse.
  *
- *	Locking: tty_mutex protects tty, get_tty_driver and init_dev work.
+ *	Locking: tty_mutex protects tty, get_tty_driver and tty_init_dev work.
  *		 tty->count should protect the rest.
  *		 ->siglock protects ->signal/->sighand
  */
 
 static int __tty_open(struct inode *inode, struct file *filp)
 {
-	struct tty_struct *tty;
+	struct tty_struct *tty = NULL;
 	int noctty, retval;
 	struct tty_driver *driver;
 	int index;
@@ -2183,23 +1777,25 @@
 			mutex_unlock(&tty_mutex);
 			return -ENXIO;
 		}
-		driver = tty->driver;
+		driver = tty_driver_kref_get(tty->driver);
 		index = tty->index;
 		filp->f_flags |= O_NONBLOCK; /* Don't let /dev/tty block */
 		/* noctty = 1; */
+		/* FIXME: Should we take a driver reference ? */
+		tty_kref_put(tty);
 		goto got_driver;
 	}
 #ifdef CONFIG_VT
 	if (device == MKDEV(TTY_MAJOR, 0)) {
 		extern struct tty_driver *console_driver;
-		driver = console_driver;
+		driver = tty_driver_kref_get(console_driver);
 		index = fg_console;
 		noctty = 1;
 		goto got_driver;
 	}
 #endif
 	if (device == MKDEV(TTYAUX_MAJOR, 1)) {
-		driver = console_device(&index);
+		driver = tty_driver_kref_get(console_device(&index));
 		if (driver) {
 			/* Don't let /dev/console block */
 			filp->f_flags |= O_NONBLOCK;
@@ -2216,10 +1812,25 @@
 		return -ENODEV;
 	}
 got_driver:
-	retval = init_dev(driver, index, &tty);
+	if (!tty) {
+		/* check whether we're reopening an existing tty */
+		tty = tty_driver_lookup_tty(driver, inode, index);
+
+		if (IS_ERR(tty))
+			return PTR_ERR(tty);
+	}
+
+	if (tty) {
+		retval = tty_reopen(tty);
+		if (retval)
+			tty = ERR_PTR(retval);
+	} else
+		tty = tty_init_dev(driver, index, 0);
+
 	mutex_unlock(&tty_mutex);
-	if (retval)
-		return retval;
+	tty_driver_kref_put(driver);
+	if (IS_ERR(tty))
+		return PTR_ERR(tty);
 
 	filp->private_data = tty;
 	file_move(filp, &tty->tty_files);
@@ -2247,7 +1858,7 @@
 		printk(KERN_DEBUG "error %d in opening %s...", retval,
 		       tty->name);
 #endif
-		release_dev(filp);
+		tty_release_dev(filp);
 		if (retval != -ERESTARTSYS)
 			return retval;
 		if (signal_pending(current))
@@ -2286,69 +1897,6 @@
 
 
 
-#ifdef CONFIG_UNIX98_PTYS
-/**
- *	ptmx_open		-	open a unix 98 pty master
- *	@inode: inode of device file
- *	@filp: file pointer to tty
- *
- *	Allocate a unix98 pty master device from the ptmx driver.
- *
- *	Locking: tty_mutex protects theinit_dev work. tty->count should
- * 		protect the rest.
- *		allocated_ptys_lock handles the list of free pty numbers
- */
-
-static int __ptmx_open(struct inode *inode, struct file *filp)
-{
-	struct tty_struct *tty;
-	int retval;
-	int index;
-
-	nonseekable_open(inode, filp);
-
-	/* find a device that is not in use. */
-	index = devpts_new_index();
-	if (index < 0)
-		return index;
-
-	mutex_lock(&tty_mutex);
-	retval = init_dev(ptm_driver, index, &tty);
-	mutex_unlock(&tty_mutex);
-
-	if (retval)
-		goto out;
-
-	set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */
-	filp->private_data = tty;
-	file_move(filp, &tty->tty_files);
-
-	retval = devpts_pty_new(tty->link);
-	if (retval)
-		goto out1;
-
-	check_tty_count(tty, "ptmx_open");
-	retval = ptm_driver->ops->open(tty, filp);
-	if (!retval)
-		return 0;
-out1:
-	release_dev(filp);
-	return retval;
-out:
-	devpts_kill_index(index);
-	return retval;
-}
-
-static int ptmx_open(struct inode *inode, struct file *filp)
-{
-	int ret;
-
-	lock_kernel();
-	ret = __ptmx_open(inode, filp);
-	unlock_kernel();
-	return ret;
-}
-#endif
 
 /**
  *	tty_release		-	vfs callback for close
@@ -2359,13 +1907,13 @@
  *	this tty. There may however be several such references.
  *
  *	Locking:
- *		Takes bkl. See release_dev
+ *		Takes bkl. See tty_release_dev
  */
 
 static int tty_release(struct inode *inode, struct file *filp)
 {
 	lock_kernel();
-	release_dev(filp);
+	tty_release_dev(filp);
 	unlock_kernel();
 	return 0;
 }
@@ -2514,7 +2062,7 @@
 
 	/* For a PTY we need to lock the tty side */
 	mutex_lock(&real_tty->termios_mutex);
-	if (!memcmp(ws, &tty->winsize, sizeof(*ws)))
+	if (!memcmp(ws, &real_tty->winsize, sizeof(*ws)))
 		goto done;
 	/* Get the PID values and reference them so we can
 	   avoid holding the tty ctrl lock while sending signals */
@@ -2986,7 +2534,7 @@
 	case TIOCSTI:
 		return tiocsti(tty, p);
 	case TIOCGWINSZ:
-		return tiocgwinsz(tty, p);
+		return tiocgwinsz(real_tty, p);
 	case TIOCSWINSZ:
 		return tiocswinsz(tty, real_tty, p);
 	case TIOCCONS:
@@ -3016,10 +2564,6 @@
 		return put_user(tty->ldisc.ops->num, (int __user *)p);
 	case TIOCSETD:
 		return tiocsetd(tty, p);
-#ifdef CONFIG_VT
-	case TIOCLINUX:
-		return tioclinux(tty, arg);
-#endif
 	/*
 	 * Break handling
 	 */
@@ -3210,113 +2754,6 @@
 EXPORT_SYMBOL(do_SAK);
 
 /**
- *	flush_to_ldisc
- *	@work: tty structure passed from work queue.
- *
- *	This routine is called out of the software interrupt to flush data
- *	from the buffer chain to the line discipline.
- *
- *	Locking: holds tty->buf.lock to guard buffer list. Drops the lock
- *	while invoking the line discipline receive_buf method. The
- *	receive_buf method is single threaded for each tty instance.
- */
-
-static void flush_to_ldisc(struct work_struct *work)
-{
-	struct tty_struct *tty =
-		container_of(work, struct tty_struct, buf.work.work);
-	unsigned long 	flags;
-	struct tty_ldisc *disc;
-	struct tty_buffer *tbuf, *head;
-	char *char_buf;
-	unsigned char *flag_buf;
-
-	disc = tty_ldisc_ref(tty);
-	if (disc == NULL)	/*  !TTY_LDISC */
-		return;
-
-	spin_lock_irqsave(&tty->buf.lock, flags);
-	/* So we know a flush is running */
-	set_bit(TTY_FLUSHING, &tty->flags);
-	head = tty->buf.head;
-	if (head != NULL) {
-		tty->buf.head = NULL;
-		for (;;) {
-			int count = head->commit - head->read;
-			if (!count) {
-				if (head->next == NULL)
-					break;
-				tbuf = head;
-				head = head->next;
-				tty_buffer_free(tty, tbuf);
-				continue;
-			}
-			/* Ldisc or user is trying to flush the buffers
-			   we are feeding to the ldisc, stop feeding the
-			   line discipline as we want to empty the queue */
-			if (test_bit(TTY_FLUSHPENDING, &tty->flags))
-				break;
-			if (!tty->receive_room) {
-				schedule_delayed_work(&tty->buf.work, 1);
-				break;
-			}
-			if (count > tty->receive_room)
-				count = tty->receive_room;
-			char_buf = head->char_buf_ptr + head->read;
-			flag_buf = head->flag_buf_ptr + head->read;
-			head->read += count;
-			spin_unlock_irqrestore(&tty->buf.lock, flags);
-			disc->ops->receive_buf(tty, char_buf,
-							flag_buf, count);
-			spin_lock_irqsave(&tty->buf.lock, flags);
-		}
-		/* Restore the queue head */
-		tty->buf.head = head;
-	}
-	/* We may have a deferred request to flush the input buffer,
-	   if so pull the chain under the lock and empty the queue */
-	if (test_bit(TTY_FLUSHPENDING, &tty->flags)) {
-		__tty_buffer_flush(tty);
-		clear_bit(TTY_FLUSHPENDING, &tty->flags);
-		wake_up(&tty->read_wait);
-	}
-	clear_bit(TTY_FLUSHING, &tty->flags);
-	spin_unlock_irqrestore(&tty->buf.lock, flags);
-
-	tty_ldisc_deref(disc);
-}
-
-/**
- *	tty_flip_buffer_push	-	terminal
- *	@tty: tty to push
- *
- *	Queue a push of the terminal flip buffers to the line discipline. This
- *	function must not be called from IRQ context if tty->low_latency is set.
- *
- *	In the event of the queue being busy for flipping the work will be
- *	held off and retried later.
- *
- *	Locking: tty buffer lock. Driver locks in low latency mode.
- */
-
-void tty_flip_buffer_push(struct tty_struct *tty)
-{
-	unsigned long flags;
-	spin_lock_irqsave(&tty->buf.lock, flags);
-	if (tty->buf.tail != NULL)
-		tty->buf.tail->commit = tty->buf.tail->used;
-	spin_unlock_irqrestore(&tty->buf.lock, flags);
-
-	if (tty->low_latency)
-		flush_to_ldisc(&tty->buf.work.work);
-	else
-		schedule_delayed_work(&tty->buf.work, 1);
-}
-
-EXPORT_SYMBOL(tty_flip_buffer_push);
-
-
-/**
  *	initialize_tty_struct
  *	@tty: tty to initialize
  *
@@ -3326,9 +2763,11 @@
  *	Locking: none - tty in question must not be exposed at this point
  */
 
-static void initialize_tty_struct(struct tty_struct *tty)
+void initialize_tty_struct(struct tty_struct *tty,
+		struct tty_driver *driver, int idx)
 {
 	memset(tty, 0, sizeof(struct tty_struct));
+	kref_init(&tty->kref);
 	tty->magic = TTY_MAGIC;
 	tty_ldisc_init(tty);
 	tty->session = NULL;
@@ -3336,7 +2775,6 @@
 	tty->overrun_time = jiffies;
 	tty->buf.head = tty->buf.tail = NULL;
 	tty_buffer_init(tty);
-	INIT_DELAYED_WORK(&tty->buf.work, flush_to_ldisc);
 	mutex_init(&tty->termios_mutex);
 	init_waitqueue_head(&tty->write_wait);
 	init_waitqueue_head(&tty->read_wait);
@@ -3347,6 +2785,11 @@
 	spin_lock_init(&tty->ctrl_lock);
 	INIT_LIST_HEAD(&tty->tty_files);
 	INIT_WORK(&tty->SAK_work, do_SAK_work);
+
+	tty->driver = driver;
+	tty->ops = driver->ops;
+	tty->index = idx;
+	tty_line_name(driver, idx, tty->name);
 }
 
 /**
@@ -3367,10 +2810,9 @@
 		return tty->ops->put_char(tty, ch);
 	return tty->ops->write(tty, &ch, 1);
 }
-
 EXPORT_SYMBOL_GPL(tty_put_char);
 
-static struct class *tty_class;
+struct class *tty_class;
 
 /**
  *	tty_register_device - register a tty device
@@ -3410,6 +2852,7 @@
 
 	return device_create_drvdata(tty_class, device, dev, NULL, name);
 }
+EXPORT_SYMBOL(tty_register_device);
 
 /**
  * 	tty_unregister_device - unregister a tty device
@@ -3427,8 +2870,6 @@
 	device_destroy(tty_class,
 		MKDEV(driver->major, driver->minor_start) + index);
 }
-
-EXPORT_SYMBOL(tty_register_device);
 EXPORT_SYMBOL(tty_unregister_device);
 
 struct tty_driver *alloc_tty_driver(int lines)
@@ -3437,28 +2878,66 @@
 
 	driver = kzalloc(sizeof(struct tty_driver), GFP_KERNEL);
 	if (driver) {
+		kref_init(&driver->kref);
 		driver->magic = TTY_DRIVER_MAGIC;
 		driver->num = lines;
 		/* later we'll move allocation of tables here */
 	}
 	return driver;
 }
+EXPORT_SYMBOL(alloc_tty_driver);
 
-void put_tty_driver(struct tty_driver *driver)
+static void destruct_tty_driver(struct kref *kref)
 {
+	struct tty_driver *driver = container_of(kref, struct tty_driver, kref);
+	int i;
+	struct ktermios *tp;
+	void *p;
+
+	if (driver->flags & TTY_DRIVER_INSTALLED) {
+		/*
+		 * Free the termios and termios_locked structures because
+		 * we don't want to get memory leaks when modular tty
+		 * drivers are removed from the kernel.
+		 */
+		for (i = 0; i < driver->num; i++) {
+			tp = driver->termios[i];
+			if (tp) {
+				driver->termios[i] = NULL;
+				kfree(tp);
+			}
+			if (!(driver->flags & TTY_DRIVER_DYNAMIC_DEV))
+				tty_unregister_device(driver, i);
+		}
+		p = driver->ttys;
+		proc_tty_unregister_driver(driver);
+		driver->ttys = NULL;
+		driver->termios = NULL;
+		kfree(p);
+		cdev_del(&driver->cdev);
+	}
 	kfree(driver);
 }
 
+void tty_driver_kref_put(struct tty_driver *driver)
+{
+	kref_put(&driver->kref, destruct_tty_driver);
+}
+EXPORT_SYMBOL(tty_driver_kref_put);
+
 void tty_set_operations(struct tty_driver *driver,
 			const struct tty_operations *op)
 {
 	driver->ops = op;
 };
-
-EXPORT_SYMBOL(alloc_tty_driver);
-EXPORT_SYMBOL(put_tty_driver);
 EXPORT_SYMBOL(tty_set_operations);
 
+void put_tty_driver(struct tty_driver *d)
+{
+	tty_driver_kref_put(d);
+}
+EXPORT_SYMBOL(put_tty_driver);
+
 /*
  * Called by a tty driver to register itself.
  */
@@ -3469,11 +2948,8 @@
 	dev_t dev;
 	void **p = NULL;
 
-	if (driver->flags & TTY_DRIVER_INSTALLED)
-		return 0;
-
 	if (!(driver->flags & TTY_DRIVER_DEVPTS_MEM) && driver->num) {
-		p = kzalloc(driver->num * 3 * sizeof(void *), GFP_KERNEL);
+		p = kzalloc(driver->num * 2 * sizeof(void *), GFP_KERNEL);
 		if (!p)
 			return -ENOMEM;
 	}
@@ -3497,12 +2973,9 @@
 	if (p) {
 		driver->ttys = (struct tty_struct **)p;
 		driver->termios = (struct ktermios **)(p + driver->num);
-		driver->termios_locked = (struct ktermios **)
-							(p + driver->num * 2);
 	} else {
 		driver->ttys = NULL;
 		driver->termios = NULL;
-		driver->termios_locked = NULL;
 	}
 
 	cdev_init(&driver->cdev, &tty_fops);
@@ -3511,7 +2984,7 @@
 	if (error) {
 		unregister_chrdev_region(dev, driver->num);
 		driver->ttys = NULL;
-		driver->termios = driver->termios_locked = NULL;
+		driver->termios = NULL;
 		kfree(p);
 		return error;
 	}
@@ -3525,6 +2998,7 @@
 		    tty_register_device(driver, i, NULL);
 	}
 	proc_tty_register_driver(driver);
+	driver->flags |= TTY_DRIVER_INSTALLED;
 	return 0;
 }
 
@@ -3535,46 +3009,19 @@
  */
 int tty_unregister_driver(struct tty_driver *driver)
 {
-	int i;
-	struct ktermios *tp;
-	void *p;
-
+#if 0
+	/* FIXME */
 	if (driver->refcount)
 		return -EBUSY;
-
+#endif
 	unregister_chrdev_region(MKDEV(driver->major, driver->minor_start),
 				driver->num);
 	mutex_lock(&tty_mutex);
 	list_del(&driver->tty_drivers);
 	mutex_unlock(&tty_mutex);
-
-	/*
-	 * Free the termios and termios_locked structures because
-	 * we don't want to get memory leaks when modular tty
-	 * drivers are removed from the kernel.
-	 */
-	for (i = 0; i < driver->num; i++) {
-		tp = driver->termios[i];
-		if (tp) {
-			driver->termios[i] = NULL;
-			kfree(tp);
-		}
-		tp = driver->termios_locked[i];
-		if (tp) {
-			driver->termios_locked[i] = NULL;
-			kfree(tp);
-		}
-		if (!(driver->flags & TTY_DRIVER_DYNAMIC_DEV))
-			tty_unregister_device(driver, i);
-	}
-	p = driver->ttys;
-	proc_tty_unregister_driver(driver);
-	driver->ttys = NULL;
-	driver->termios = driver->termios_locked = NULL;
-	kfree(p);
-	cdev_del(&driver->cdev);
 	return 0;
 }
+
 EXPORT_SYMBOL(tty_unregister_driver);
 
 dev_t tty_devnum(struct tty_struct *tty)
@@ -3585,9 +3032,12 @@
 
 void proc_clear_tty(struct task_struct *p)
 {
+	struct tty_struct *tty;
 	spin_lock_irq(&p->sighand->siglock);
+	tty = p->signal->tty;
 	p->signal->tty = NULL;
 	spin_unlock_irq(&p->sighand->siglock);
+	tty_kref_put(tty);
 }
 
 /* Called under the sighand lock */
@@ -3603,9 +3053,13 @@
 		tty->pgrp = get_pid(task_pgrp(tsk));
 		spin_unlock_irqrestore(&tty->ctrl_lock, flags);
 		tty->session = get_pid(task_session(tsk));
+		if (tsk->signal->tty) {
+			printk(KERN_DEBUG "tty not NULL!!\n");
+			tty_kref_put(tsk->signal->tty);
+		}
 	}
 	put_pid(tsk->signal->tty_old_pgrp);
-	tsk->signal->tty = tty;
+	tsk->signal->tty = tty_kref_get(tty);
 	tsk->signal->tty_old_pgrp = NULL;
 }
 
@@ -3619,18 +3073,20 @@
 struct tty_struct *get_current_tty(void)
 {
 	struct tty_struct *tty;
-	WARN_ON_ONCE(!mutex_is_locked(&tty_mutex));
-	tty = current->signal->tty;
-	/*
-	 * session->tty can be changed/cleared from under us, make sure we
-	 * issue the load. The obtained pointer, when not NULL, is valid as
-	 * long as we hold tty_mutex.
-	 */
-	barrier();
+	unsigned long flags;
+
+	spin_lock_irqsave(&current->sighand->siglock, flags);
+	tty = tty_kref_get(current->signal->tty);
+	spin_unlock_irqrestore(&current->sighand->siglock, flags);
 	return tty;
 }
 EXPORT_SYMBOL_GPL(get_current_tty);
 
+void tty_default_fops(struct file_operations *fops)
+{
+	*fops = tty_fops;
+}
+
 /*
  * Initialize the console device. This is called *early*, so
  * we can't necessarily depend on lots of kernel help here.
@@ -3668,12 +3124,6 @@
 /* 3/2004 jmc: why do these devices exist? */
 
 static struct cdev tty_cdev, console_cdev;
-#ifdef CONFIG_UNIX98_PTYS
-static struct cdev ptmx_cdev;
-#endif
-#ifdef CONFIG_VT
-static struct cdev vc0_cdev;
-#endif
 
 /*
  * Ok, now we can initialize the rest of the tty devices and can count
@@ -3685,32 +3135,18 @@
 	if (cdev_add(&tty_cdev, MKDEV(TTYAUX_MAJOR, 0), 1) ||
 	    register_chrdev_region(MKDEV(TTYAUX_MAJOR, 0), 1, "/dev/tty") < 0)
 		panic("Couldn't register /dev/tty driver\n");
-	device_create_drvdata(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 0), NULL,
+	device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 0), NULL,
 			      "tty");
 
 	cdev_init(&console_cdev, &console_fops);
 	if (cdev_add(&console_cdev, MKDEV(TTYAUX_MAJOR, 1), 1) ||
 	    register_chrdev_region(MKDEV(TTYAUX_MAJOR, 1), 1, "/dev/console") < 0)
 		panic("Couldn't register /dev/console driver\n");
-	device_create_drvdata(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 1), NULL,
+	device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 1), NULL,
 			      "console");
 
-#ifdef CONFIG_UNIX98_PTYS
-	cdev_init(&ptmx_cdev, &ptmx_fops);
-	if (cdev_add(&ptmx_cdev, MKDEV(TTYAUX_MAJOR, 2), 1) ||
-	    register_chrdev_region(MKDEV(TTYAUX_MAJOR, 2), 1, "/dev/ptmx") < 0)
-		panic("Couldn't register /dev/ptmx driver\n");
-	device_create_drvdata(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 2), NULL, "ptmx");
-#endif
-
 #ifdef CONFIG_VT
-	cdev_init(&vc0_cdev, &console_fops);
-	if (cdev_add(&vc0_cdev, MKDEV(TTY_MAJOR, 0), 1) ||
-	    register_chrdev_region(MKDEV(TTY_MAJOR, 0), 1, "/dev/vc/0") < 0)
-		panic("Couldn't register /dev/tty0 driver\n");
-	device_create_drvdata(tty_class, NULL, MKDEV(TTY_MAJOR, 0), NULL, "tty0");
-
-	vty_init();
+	vty_init(&console_fops);
 #endif
 	return 0;
 }
diff --git a/drivers/char/tty_ioctl.c b/drivers/char/tty_ioctl.c
index bf34e45..a408c8e 100644
--- a/drivers/char/tty_ioctl.c
+++ b/drivers/char/tty_ioctl.c
@@ -40,6 +40,15 @@
 #define TERMIOS_OLD	8
 
 
+/**
+ *	tty_chars_in_buffer	-	characters pending
+ *	@tty: terminal
+ *
+ *	Return the number of bytes of data in the device private
+ *	output queue. If no private method is supplied there is assumed
+ *	to be no queue on the device.
+ */
+
 int tty_chars_in_buffer(struct tty_struct *tty)
 {
 	if (tty->ops->chars_in_buffer)
@@ -47,26 +56,49 @@
 	else
 		return 0;
 }
-
 EXPORT_SYMBOL(tty_chars_in_buffer);
 
+/**
+ *	tty_write_room		-	write queue space
+ *	@tty: terminal
+ *
+ *	Return the number of bytes that can be queued to this device
+ *	at the present time. The result should be treated as a guarantee
+ *	and the driver cannot offer a value it later shrinks by more than
+ *	the number of bytes written. If no method is provided 2K is always
+ *	returned and data may be lost as there will be no flow control.
+ */
+ 
 int tty_write_room(struct tty_struct *tty)
 {
 	if (tty->ops->write_room)
 		return tty->ops->write_room(tty);
 	return 2048;
 }
-
 EXPORT_SYMBOL(tty_write_room);
 
+/**
+ *	tty_driver_flush_buffer	-	discard internal buffer
+ *	@tty: terminal
+ *
+ *	Discard the internal output buffer for this device. If no method
+ *	is provided then either the buffer cannot be hardware flushed or
+ *	there is no buffer driver side.
+ */
 void tty_driver_flush_buffer(struct tty_struct *tty)
 {
 	if (tty->ops->flush_buffer)
 		tty->ops->flush_buffer(tty);
 }
-
 EXPORT_SYMBOL(tty_driver_flush_buffer);
 
+/**
+ *	tty_throttle		-	flow control
+ *	@tty: terminal
+ *
+ *	Indicate that a tty should stop transmitting data down the stack.
+ */
+
 void tty_throttle(struct tty_struct *tty)
 {
 	/* check TTY_THROTTLED first so it indicates our state */
@@ -76,6 +108,13 @@
 }
 EXPORT_SYMBOL(tty_throttle);
 
+/**
+ *	tty_unthrottle		-	flow control
+ *	@tty: terminal
+ *
+ *	Indicate that a tty may continue transmitting data down the stack.
+ */
+
 void tty_unthrottle(struct tty_struct *tty)
 {
 	if (test_and_clear_bit(TTY_THROTTLED, &tty->flags) &&
@@ -112,6 +151,11 @@
 }
 EXPORT_SYMBOL(tty_wait_until_sent);
 
+
+/*
+ *		Termios Helper Methods
+ */
+
 static void unset_locked_termios(struct ktermios *termios,
 				 struct ktermios *old,
 				 struct ktermios *locked)
@@ -346,6 +390,16 @@
 }
 EXPORT_SYMBOL_GPL(tty_termios_encode_baud_rate);
 
+/**
+ *	tty_encode_baud_rate		-	set baud rate of the tty
+ *	@ibaud: input baud rate
+ *	@obad: output baud rate
+ *
+ *	Update the current termios data for the tty with the new speed
+ *	settings. The caller must hold the termios_mutex for the tty in
+ *	question.
+ */
+
 void tty_encode_baud_rate(struct tty_struct *tty, speed_t ibaud, speed_t obaud)
 {
 	tty_termios_encode_baud_rate(tty->termios, ibaud, obaud);
@@ -430,12 +484,11 @@
  *	is a bit of layering violation here with n_tty in terms of the
  *	internal knowledge of this function.
  *
- *	Locking: termios_sem
+ *	Locking: termios_mutex
  */
 
 static void change_termios(struct tty_struct *tty, struct ktermios *new_termios)
 {
-	int canon_change;
 	struct ktermios old_termios;
 	struct tty_ldisc *ld;
 	unsigned long flags;
@@ -451,18 +504,6 @@
 	old_termios = *tty->termios;
 	*tty->termios = *new_termios;
 	unset_locked_termios(tty->termios, &old_termios, tty->termios_locked);
-	canon_change = (old_termios.c_lflag ^ tty->termios->c_lflag) & ICANON;
-	if (canon_change) {
-		memset(&tty->read_flags, 0, sizeof tty->read_flags);
-		tty->canon_head = tty->read_tail;
-		tty->canon_data = 0;
-		tty->erasing = 0;
-	}
-
-	/* This bit should be in the ldisc code */
-	if (canon_change && !L_ICANON(tty) && tty->read_cnt)
-		/* Get characters left over from canonical mode. */
-		wake_up_interruptible(&tty->read_wait);
 
 	/* See if packet mode change of state. */
 	if (tty->link && tty->link->packet) {
@@ -508,7 +549,7 @@
  *	functions before using change_termios to do the actual changes.
  *
  *	Locking:
- *		Called functions take ldisc and termios_sem locks
+ *		Called functions take ldisc and termios_mutex locks
  */
 
 static int set_termios(struct tty_struct *tty, void __user *arg, int opt)
@@ -579,25 +620,51 @@
 	return 0;
 }
 
-static unsigned long inq_canon(struct tty_struct *tty)
-{
-	int nr, head, tail;
 
-	if (!tty->canon_data || !tty->read_buf)
-		return 0;
-	head = tty->canon_head;
-	tail = tty->read_tail;
-	nr = (head - tail) & (N_TTY_BUF_SIZE-1);
-	/* Skip EOF-chars.. */
-	while (head != tail) {
-		if (test_bit(tail, tty->read_flags) &&
-		    tty->read_buf[tail] == __DISABLED_CHAR)
-			nr--;
-		tail = (tail+1) & (N_TTY_BUF_SIZE-1);
+#ifdef TCGETX
+
+/**
+ *	set_termiox	-	set termiox fields if possible
+ *	@tty: terminal
+ *	@arg: termiox structure from user
+ *	@opt: option flags for ioctl type
+ *
+ *	Implement the device calling points for the SYS5 termiox ioctl
+ *	interface in Linux
+ */
+
+static int set_termiox(struct tty_struct *tty, void __user *arg, int opt)
+{
+	struct termiox tnew;
+	struct tty_ldisc *ld;
+
+	if (tty->termiox == NULL)
+		return -EINVAL;
+	if (copy_from_user(&tnew, arg, sizeof(struct termiox)))
+		return -EFAULT;
+
+	ld = tty_ldisc_ref(tty);
+	if (ld != NULL) {
+		if ((opt & TERMIOS_FLUSH) && ld->ops->flush_buffer)
+			ld->ops->flush_buffer(tty);
+		tty_ldisc_deref(ld);
 	}
-	return nr;
+	if (opt & TERMIOS_WAIT) {
+		tty_wait_until_sent(tty, 0);
+		if (signal_pending(current))
+			return -EINTR;
+	}
+
+	mutex_lock(&tty->termios_mutex);
+	if (tty->ops->set_termiox)
+		tty->ops->set_termiox(tty, &tnew);
+	mutex_unlock(&tty->termios_mutex);
+	return 0;
 }
 
+#endif
+
+
 #ifdef TIOCGETP
 /*
  * These are deprecated, but there is limited support..
@@ -671,7 +738,7 @@
  *	Updates a terminal from the legacy BSD style terminal information
  *	structure.
  *
- *	Locking: termios_sem
+ *	Locking: termios_mutex
  */
 
 static int set_sgttyb(struct tty_struct *tty, struct sgttyb __user *sgttyb)
@@ -849,6 +916,7 @@
 {
 	struct tty_struct *real_tty;
 	void __user *p = (void __user *)arg;
+	int ret = 0;
 
 	if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
 	    tty->driver->subtype == PTY_TYPE_MASTER)
@@ -884,18 +952,24 @@
 		return set_termios(real_tty, p, TERMIOS_OLD);
 #ifndef TCGETS2
 	case TCGETS:
+		mutex_lock(&real_tty->termios_mutex);
 		if (kernel_termios_to_user_termios((struct termios __user *)arg, real_tty->termios))
-			return -EFAULT;
-		return 0;
+			ret = -EFAULT;
+		mutex_unlock(&real_tty->termios_mutex);
+		return ret;
 #else
 	case TCGETS:
+		mutex_lock(&real_tty->termios_mutex);
 		if (kernel_termios_to_user_termios_1((struct termios __user *)arg, real_tty->termios))
-			return -EFAULT;
-		return 0;
+			ret = -EFAULT;
+		mutex_unlock(&real_tty->termios_mutex);
+		return ret;
 	case TCGETS2:
+		mutex_lock(&real_tty->termios_mutex);
 		if (kernel_termios_to_user_termios((struct termios2 __user *)arg, real_tty->termios))
-			return -EFAULT;
-		return 0;
+			ret = -EFAULT;
+		mutex_unlock(&real_tty->termios_mutex);
+		return ret;
 	case TCSETSF2:
 		return set_termios(real_tty, p,  TERMIOS_FLUSH | TERMIOS_WAIT);
 	case TCSETSW2:
@@ -913,34 +987,59 @@
 		return set_termios(real_tty, p, TERMIOS_TERMIO);
 #ifndef TCGETS2
 	case TIOCGLCKTRMIOS:
+		mutex_lock(&real_tty->termios_mutex);
 		if (kernel_termios_to_user_termios((struct termios __user *)arg, real_tty->termios_locked))
-			return -EFAULT;
-		return 0;
+			ret = -EFAULT;
+		mutex_unlock(&real_tty->termios_mutex);
+		return ret;
 	case TIOCSLCKTRMIOS:
 		if (!capable(CAP_SYS_ADMIN))
 			return -EPERM;
+		mutex_lock(&real_tty->termios_mutex);
 		if (user_termios_to_kernel_termios(real_tty->termios_locked,
 					       (struct termios __user *) arg))
-			return -EFAULT;
-		return 0;
+			ret = -EFAULT;
+		mutex_unlock(&real_tty->termios_mutex);
+		return ret;
 #else
 	case TIOCGLCKTRMIOS:
+		mutex_lock(&real_tty->termios_mutex);
 		if (kernel_termios_to_user_termios_1((struct termios __user *)arg, real_tty->termios_locked))
-			return -EFAULT;
-		return 0;
+			ret = -EFAULT;
+		mutex_unlock(&real_tty->termios_mutex);
+		return ret;
 	case TIOCSLCKTRMIOS:
 		if (!capable(CAP_SYS_ADMIN))
-			return -EPERM;
+			ret = -EPERM;
+		mutex_lock(&real_tty->termios_mutex);
 		if (user_termios_to_kernel_termios_1(real_tty->termios_locked,
 					       (struct termios __user *) arg))
-			return -EFAULT;
-			return 0;
+			ret = -EFAULT;
+		mutex_unlock(&real_tty->termios_mutex);
+		return ret;
 #endif
+#ifdef TCGETX
+	case TCGETX:
+		if (real_tty->termiox == NULL)
+			return -EINVAL;
+		mutex_lock(&real_tty->termios_mutex);
+		if (copy_to_user(p, real_tty->termiox, sizeof(struct termiox)))
+			ret = -EFAULT;
+		mutex_unlock(&real_tty->termios_mutex);
+		return ret;
+	case TCSETX:
+		return set_termiox(real_tty, p, 0);
+	case TCSETXW:
+		return set_termiox(real_tty, p, TERMIOS_WAIT);
+	case TCSETXF:
+		return set_termiox(real_tty, p, TERMIOS_FLUSH);
+#endif		
 	case TIOCGSOFTCAR:
-		/* FIXME: for correctness we may need to take the termios
-		   lock here - review */
-		return put_user(C_CLOCAL(real_tty) ? 1 : 0,
+		mutex_lock(&real_tty->termios_mutex);
+		ret = put_user(C_CLOCAL(real_tty) ? 1 : 0,
 						(int __user *)arg);
+		mutex_unlock(&real_tty->termios_mutex);
+		return ret;
 	case TIOCSSOFTCAR:
 		if (get_user(arg, (unsigned int __user *) arg))
 			return -EFAULT;
@@ -980,7 +1079,7 @@
 }
 EXPORT_SYMBOL_GPL(tty_perform_flush);
 
-int n_tty_ioctl(struct tty_struct *tty, struct file *file,
+int n_tty_ioctl_helper(struct tty_struct *tty, struct file *file,
 		       unsigned int cmd, unsigned long arg)
 {
 	unsigned long flags;
@@ -1018,13 +1117,6 @@
 		return 0;
 	case TCFLSH:
 		return tty_perform_flush(tty, arg);
-	case TIOCOUTQ:
-		return put_user(tty_chars_in_buffer(tty), (int __user *) arg);
-	case TIOCINQ:
-		retval = tty->read_cnt;
-		if (L_ICANON(tty))
-			retval = inq_canon(tty);
-		return put_user(retval, (unsigned int __user *) arg);
 	case TIOCPKT:
 	{
 		int pktmode;
@@ -1050,4 +1142,4 @@
 		return tty_mode_ioctl(tty, file, cmd, arg);
 	}
 }
-EXPORT_SYMBOL(n_tty_ioctl);
+EXPORT_SYMBOL(n_tty_ioctl_helper);
diff --git a/drivers/char/tty_port.c b/drivers/char/tty_port.c
new file mode 100644
index 0000000..553b0e9
--- /dev/null
+++ b/drivers/char/tty_port.c
@@ -0,0 +1,96 @@
+/*
+ * Tty port functions
+ */
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/tty.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+#include <linux/timer.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/wait.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+
+void tty_port_init(struct tty_port *port)
+{
+	memset(port, 0, sizeof(*port));
+	init_waitqueue_head(&port->open_wait);
+	init_waitqueue_head(&port->close_wait);
+	mutex_init(&port->mutex);
+	spin_lock_init(&port->lock);
+	port->close_delay = (50 * HZ) / 100;
+	port->closing_wait = (3000 * HZ) / 100;
+}
+EXPORT_SYMBOL(tty_port_init);
+
+int tty_port_alloc_xmit_buf(struct tty_port *port)
+{
+	/* We may sleep in get_zeroed_page() */
+	mutex_lock(&port->mutex);
+	if (port->xmit_buf == NULL)
+		port->xmit_buf = (unsigned char *)get_zeroed_page(GFP_KERNEL);
+	mutex_unlock(&port->mutex);
+	if (port->xmit_buf == NULL)
+		return -ENOMEM;
+	return 0;
+}
+EXPORT_SYMBOL(tty_port_alloc_xmit_buf);
+
+void tty_port_free_xmit_buf(struct tty_port *port)
+{
+	mutex_lock(&port->mutex);
+	if (port->xmit_buf != NULL) {
+		free_page((unsigned long)port->xmit_buf);
+		port->xmit_buf = NULL;
+	}
+	mutex_unlock(&port->mutex);
+}
+EXPORT_SYMBOL(tty_port_free_xmit_buf);
+
+
+/**
+ *	tty_port_tty_get	-	get a tty reference
+ *	@port: tty port
+ *
+ *	Return a refcount protected tty instance or NULL if the port is not
+ *	associated with a tty (eg due to close or hangup)
+ */
+
+struct tty_struct *tty_port_tty_get(struct tty_port *port)
+{
+	unsigned long flags;
+	struct tty_struct *tty;
+
+	spin_lock_irqsave(&port->lock, flags);
+	tty = tty_kref_get(port->tty);
+	spin_unlock_irqrestore(&port->lock, flags);
+	return tty;
+}
+EXPORT_SYMBOL(tty_port_tty_get);
+
+/**
+ *	tty_port_tty_set	-	set the tty of a port
+ *	@port: tty port
+ *	@tty: the tty
+ *
+ *	Associate the port and tty pair. Manages any internal refcounts.
+ *	Pass NULL to deassociate a port
+ */
+
+void tty_port_tty_set(struct tty_port *port, struct tty_struct *tty)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&port->lock, flags);
+	if (port->tty)
+		tty_kref_put(port->tty);
+	port->tty = tty;
+	spin_unlock_irqrestore(&port->lock, flags);
+}
+EXPORT_SYMBOL(tty_port_tty_set);
diff --git a/drivers/char/vt.c b/drivers/char/vt.c
index 60359c3..a0f7ffb 100644
--- a/drivers/char/vt.c
+++ b/drivers/char/vt.c
@@ -100,10 +100,10 @@
 #include <linux/font.h>
 #include <linux/bitops.h>
 #include <linux/notifier.h>
-
-#include <asm/io.h>
+#include <linux/device.h>
+#include <linux/io.h>
 #include <asm/system.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
 
 #define MAX_NR_CON_DRIVER 16
 
@@ -301,7 +301,7 @@
 	d = (unsigned short *)(vc->vc_origin + vc->vc_size_row * t);
 	s = (unsigned short *)(vc->vc_origin + vc->vc_size_row * (t + nr));
 	scr_memmovew(d, s, (b - t - nr) * vc->vc_size_row);
-	scr_memsetw(d + (b - t - nr) * vc->vc_cols, vc->vc_scrl_erase_char,
+	scr_memsetw(d + (b - t - nr) * vc->vc_cols, vc->vc_video_erase_char,
 		    vc->vc_size_row * nr);
 }
 
@@ -319,7 +319,7 @@
 	s = (unsigned short *)(vc->vc_origin + vc->vc_size_row * t);
 	step = vc->vc_cols * nr;
 	scr_memmovew(s + step, s, (b - t - nr) * vc->vc_size_row);
-	scr_memsetw(s, vc->vc_scrl_erase_char, 2 * step);
+	scr_memsetw(s, vc->vc_video_erase_char, 2 * step);
 }
 
 static void do_update_region(struct vc_data *vc, unsigned long start, int count)
@@ -434,7 +434,6 @@
 	              vc->vc_blink, vc->vc_underline,
 	              vc->vc_reverse ^ vc->vc_decscnm, vc->vc_italic);
 	vc->vc_video_erase_char = (build_attr(vc, vc->vc_color, 1, vc->vc_blink, 0, vc->vc_decscnm, 0) << 8) | ' ';
-	vc->vc_scrl_erase_char = (build_attr(vc, vc->vc_def_color, 1, false, false, vc->vc_decscnm, false) << 8) | ' ';
 }
 
 /* Note: inverting the screen twice should revert to the original state */
@@ -2136,27 +2135,9 @@
 	    release_console_sem();
 	    return 0;
 	}
-	release_console_sem();
-
 	orig_buf = buf;
 	orig_count = count;
 
-	/* At this point 'buf' is guaranteed to be a kernel buffer
-	 * and therefore no access to userspace (and therefore sleeping)
-	 * will be needed.  The con_buf_mtx serializes all tty based
-	 * console rendering and vcs write/read operations.  We hold
-	 * the console spinlock during the entire write.
-	 */
-
-	acquire_console_sem();
-
-	vc = tty->driver_data;
-	if (vc == NULL) {
-		printk(KERN_ERR "vt: argh, driver_data _became_ NULL !\n");
-		release_console_sem();
-		goto out;
-	}
-
 	himask = vc->vc_hi_font_mask;
 	charmask = himask ? 0x1ff : 0xff;
 
@@ -2370,8 +2351,6 @@
 	FLUSH
 	console_conditional_schedule();
 	release_console_sem();
-
-out:
 	notify_update(vc);
 	return n;
 #undef FLUSH
@@ -2583,8 +2562,6 @@
 	int lines;
 	int ret;
 
-	if (tty->driver->type != TTY_DRIVER_TYPE_CONSOLE)
-		return -EINVAL;
 	if (current->signal->tty != tty && !capable(CAP_SYS_ADMIN))
 		return -EPERM;
 	if (get_user(type, p))
@@ -2778,6 +2755,12 @@
 		ret = vc_allocate(currcons);
 		if (ret == 0) {
 			struct vc_data *vc = vc_cons[currcons].d;
+
+			/* Still being freed */
+			if (vc->vc_tty) {
+				release_console_sem();
+				return -ERESTARTSYS;
+			}
 			tty->driver_data = vc;
 			vc->vc_tty = tty;
 
@@ -2798,34 +2781,20 @@
 	return ret;
 }
 
-/*
- * We take tty_mutex in here to prevent another thread from coming in via init_dev
- * and taking a ref against the tty while we're in the process of forgetting
- * about it and cleaning things up.
- *
- * This is because vcs_remove_sysfs() can sleep and will drop the BKL.
- */
 static void con_close(struct tty_struct *tty, struct file *filp)
 {
-	mutex_lock(&tty_mutex);
-	acquire_console_sem();
-	if (tty && tty->count == 1) {
-		struct vc_data *vc = tty->driver_data;
+	/* Nothing to do - we defer to shutdown */
+}
 
-		if (vc)
-			vc->vc_tty = NULL;
-		tty->driver_data = NULL;
-		vcs_remove_sysfs(tty);
-		release_console_sem();
-		mutex_unlock(&tty_mutex);
-		/*
-		 * tty_mutex is released, but we still hold BKL, so there is
-		 * still exclusion against init_dev()
-		 */
-		return;
-	}
+static void con_shutdown(struct tty_struct *tty)
+{
+	struct vc_data *vc = tty->driver_data;
+	BUG_ON(vc == NULL);
+	acquire_console_sem();
+	vc->vc_tty = NULL;
+	vcs_remove_sysfs(tty);
 	release_console_sem();
-	mutex_unlock(&tty_mutex);
+	tty_shutdown(tty);
 }
 
 static int default_italic_color    = 2; // green (ASCII)
@@ -2950,10 +2919,19 @@
 	.throttle = con_throttle,
 	.unthrottle = con_unthrottle,
 	.resize = vt_resize,
+	.shutdown = con_shutdown
 };
 
-int __init vty_init(void)
+static struct cdev vc0_cdev;
+
+int __init vty_init(const struct file_operations *console_fops)
 {
+	cdev_init(&vc0_cdev, console_fops);
+	if (cdev_add(&vc0_cdev, MKDEV(TTY_MAJOR, 0), 1) ||
+	    register_chrdev_region(MKDEV(TTY_MAJOR, 0), 1, "/dev/vc/0") < 0)
+		panic("Couldn't register /dev/tty0 driver\n");
+	device_create(tty_class, NULL, MKDEV(TTY_MAJOR, 0), NULL, "tty0");
+
 	vcs_init();
 
 	console_driver = alloc_tty_driver(MAX_NR_CONSOLES);
@@ -2972,7 +2950,6 @@
 	tty_set_operations(console_driver, &con_ops);
 	if (tty_register_driver(console_driver))
 		panic("Couldn't register console driver\n");
-
 	kbd_init();
 	console_map_init();
 #ifdef CONFIG_PROM_CONSOLE
@@ -3466,7 +3443,7 @@
 	if (retval)
 		goto err;
 
-	con_driver->dev = device_create_drvdata(vtconsole_class, NULL,
+	con_driver->dev = device_create(vtconsole_class, NULL,
 						MKDEV(0, con_driver->node),
 						NULL, "vtcon%i",
 						con_driver->node);
@@ -3577,7 +3554,7 @@
 		struct con_driver *con = &registered_con_driver[i];
 
 		if (con->con && !con->dev) {
-			con->dev = device_create_drvdata(vtconsole_class, NULL,
+			con->dev = device_create(vtconsole_class, NULL,
 							 MKDEV(0, con->node),
 							 NULL, "vtcon%i",
 							 con->node);
diff --git a/drivers/char/vt_ioctl.c b/drivers/char/vt_ioctl.c
index c904e9a..8944ce5 100644
--- a/drivers/char/vt_ioctl.c
+++ b/drivers/char/vt_ioctl.c
@@ -395,6 +395,8 @@
  
 	kbd = kbd_table + console;
 	switch (cmd) {
+	case TIOCLINUX:
+		return tioclinux(tty, arg);
 	case KIOCSOUND:
 		if (!perm)
 			goto eperm;
diff --git a/drivers/clocksource/acpi_pm.c b/drivers/clocksource/acpi_pm.c
index 4eee533..71d2ac4 100644
--- a/drivers/clocksource/acpi_pm.c
+++ b/drivers/clocksource/acpi_pm.c
@@ -178,11 +178,13 @@
 
 /* Number of monotonicity checks to perform during initialization */
 #define ACPI_PM_MONOTONICITY_CHECKS 10
+/* Number of reads we try to get two different values */
+#define ACPI_PM_READ_CHECKS 10000
 
 static int __init init_acpi_pm_clocksource(void)
 {
 	cycle_t value1, value2;
-	unsigned int i, j, good = 0;
+	unsigned int i, j = 0;
 
 	if (!pmtmr_ioport)
 		return -ENODEV;
@@ -192,29 +194,26 @@
 
 	/* "verify" this timing source: */
 	for (j = 0; j < ACPI_PM_MONOTONICITY_CHECKS; j++) {
+		udelay(100 * j);
 		value1 = clocksource_acpi_pm.read();
-		for (i = 0; i < 10000; i++) {
+		for (i = 0; i < ACPI_PM_READ_CHECKS; i++) {
 			value2 = clocksource_acpi_pm.read();
 			if (value2 == value1)
 				continue;
 			if (value2 > value1)
-				good++;
 				break;
 			if ((value2 < value1) && ((value2) < 0xFFF))
-				good++;
 				break;
 			printk(KERN_INFO "PM-Timer had inconsistent results:"
 			       " 0x%#llx, 0x%#llx - aborting.\n",
 			       value1, value2);
 			return -EINVAL;
 		}
-		udelay(300 * i);
-	}
-
-	if (good != ACPI_PM_MONOTONICITY_CHECKS) {
-		printk(KERN_INFO "PM-Timer failed consistency check "
-		       " (0x%#llx) - aborting.\n", value1);
-		return -ENODEV;
+		if (i == ACPI_PM_READ_CHECKS) {
+			printk(KERN_INFO "PM-Timer failed consistency check "
+			       " (0x%#llx) - aborting.\n", value1);
+			return -ENODEV;
+		}
 	}
 
 	if (verify_pmtmr_rate() != 0)
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index 8a67f16..31d6f53 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -1467,25 +1467,27 @@
 			  unsigned int target_freq,
 			  unsigned int relation)
 {
-	int ret;
+	int ret = -EINVAL;
 
 	policy = cpufreq_cpu_get(policy->cpu);
 	if (!policy)
-		return -EINVAL;
+		goto no_policy;
 
 	if (unlikely(lock_policy_rwsem_write(policy->cpu)))
-		return -EINVAL;
+		goto fail;
 
 	ret = __cpufreq_driver_target(policy, target_freq, relation);
 
 	unlock_policy_rwsem_write(policy->cpu);
 
+fail:
 	cpufreq_cpu_put(policy);
+no_policy:
 	return ret;
 }
 EXPORT_SYMBOL_GPL(cpufreq_driver_target);
 
-int __cpufreq_driver_getavg(struct cpufreq_policy *policy)
+int __cpufreq_driver_getavg(struct cpufreq_policy *policy, unsigned int cpu)
 {
 	int ret = 0;
 
@@ -1493,8 +1495,8 @@
 	if (!policy)
 		return -EINVAL;
 
-	if (cpu_online(policy->cpu) && cpufreq_driver->getavg)
-		ret = cpufreq_driver->getavg(policy->cpu);
+	if (cpu_online(cpu) && cpufreq_driver->getavg)
+		ret = cpufreq_driver->getavg(policy, cpu);
 
 	cpufreq_cpu_put(policy);
 	return ret;
@@ -1717,13 +1719,17 @@
 {
 	struct cpufreq_policy *data = cpufreq_cpu_get(cpu);
 	struct cpufreq_policy policy;
-	int ret = 0;
+	int ret;
 
-	if (!data)
-		return -ENODEV;
+	if (!data) {
+		ret = -ENODEV;
+		goto no_policy;
+	}
 
-	if (unlikely(lock_policy_rwsem_write(cpu)))
-		return -EINVAL;
+	if (unlikely(lock_policy_rwsem_write(cpu))) {
+		ret = -EINVAL;
+		goto fail;
+	}
 
 	dprintk("updating policy for CPU %u\n", cpu);
 	memcpy(&policy, data, sizeof(struct cpufreq_policy));
@@ -1750,7 +1756,9 @@
 
 	unlock_policy_rwsem_write(cpu);
 
+fail:
 	cpufreq_cpu_put(data);
+no_policy:
 	return ret;
 }
 EXPORT_SYMBOL(cpufreq_update_policy);
diff --git a/drivers/cpufreq/cpufreq_conservative.c b/drivers/cpufreq/cpufreq_conservative.c
index ac0bbf2..e265783 100644
--- a/drivers/cpufreq/cpufreq_conservative.c
+++ b/drivers/cpufreq/cpufreq_conservative.c
@@ -460,6 +460,7 @@
 
 static inline void dbs_timer_init(void)
 {
+	init_timer_deferrable(&dbs_work.timer);
 	schedule_delayed_work(&dbs_work,
 			usecs_to_jiffies(dbs_tuners_ins.sampling_rate));
 	return;
@@ -575,13 +576,15 @@
 	return 0;
 }
 
+#ifndef CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE
+static
+#endif
 struct cpufreq_governor cpufreq_gov_conservative = {
 	.name			= "conservative",
 	.governor		= cpufreq_governor_dbs,
 	.max_transition_latency	= TRANSITION_LATENCY_LIMIT,
 	.owner			= THIS_MODULE,
 };
-EXPORT_SYMBOL(cpufreq_gov_conservative);
 
 static int __init cpufreq_gov_dbs_init(void)
 {
diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c
index 33855cb..2ab3c12 100644
--- a/drivers/cpufreq/cpufreq_ondemand.c
+++ b/drivers/cpufreq/cpufreq_ondemand.c
@@ -18,13 +18,19 @@
 #include <linux/jiffies.h>
 #include <linux/kernel_stat.h>
 #include <linux/mutex.h>
+#include <linux/hrtimer.h>
+#include <linux/tick.h>
+#include <linux/ktime.h>
 
 /*
  * dbs is used in this file as a shortform for demandbased switching
  * It helps to keep variable names smaller, simpler
  */
 
+#define DEF_FREQUENCY_DOWN_DIFFERENTIAL		(10)
 #define DEF_FREQUENCY_UP_THRESHOLD		(80)
+#define MICRO_FREQUENCY_DOWN_DIFFERENTIAL	(3)
+#define MICRO_FREQUENCY_UP_THRESHOLD		(95)
 #define MIN_FREQUENCY_UP_THRESHOLD		(11)
 #define MAX_FREQUENCY_UP_THRESHOLD		(100)
 
@@ -57,6 +63,7 @@
 struct cpu_dbs_info_s {
 	cputime64_t prev_cpu_idle;
 	cputime64_t prev_cpu_wall;
+	cputime64_t prev_cpu_nice;
 	struct cpufreq_policy *cur_policy;
  	struct delayed_work work;
 	struct cpufreq_frequency_table *freq_table;
@@ -86,21 +93,24 @@
 static struct dbs_tuners {
 	unsigned int sampling_rate;
 	unsigned int up_threshold;
+	unsigned int down_differential;
 	unsigned int ignore_nice;
 	unsigned int powersave_bias;
 } dbs_tuners_ins = {
 	.up_threshold = DEF_FREQUENCY_UP_THRESHOLD,
+	.down_differential = DEF_FREQUENCY_DOWN_DIFFERENTIAL,
 	.ignore_nice = 0,
 	.powersave_bias = 0,
 };
 
-static inline cputime64_t get_cpu_idle_time(unsigned int cpu)
+static inline cputime64_t get_cpu_idle_time_jiffy(unsigned int cpu,
+							cputime64_t *wall)
 {
 	cputime64_t idle_time;
-	cputime64_t cur_jiffies;
+	cputime64_t cur_wall_time;
 	cputime64_t busy_time;
 
-	cur_jiffies = jiffies64_to_cputime64(get_jiffies_64());
+	cur_wall_time = jiffies64_to_cputime64(get_jiffies_64());
 	busy_time = cputime64_add(kstat_cpu(cpu).cpustat.user,
 			kstat_cpu(cpu).cpustat.system);
 
@@ -113,7 +123,37 @@
 				kstat_cpu(cpu).cpustat.nice);
 	}
 
-	idle_time = cputime64_sub(cur_jiffies, busy_time);
+	idle_time = cputime64_sub(cur_wall_time, busy_time);
+	if (wall)
+		*wall = cur_wall_time;
+
+	return idle_time;
+}
+
+static inline cputime64_t get_cpu_idle_time(unsigned int cpu, cputime64_t *wall)
+{
+	u64 idle_time = get_cpu_idle_time_us(cpu, wall);
+
+	if (idle_time == -1ULL)
+		return get_cpu_idle_time_jiffy(cpu, wall);
+
+	if (dbs_tuners_ins.ignore_nice) {
+		cputime64_t cur_nice;
+		unsigned long cur_nice_jiffies;
+		struct cpu_dbs_info_s *dbs_info;
+
+		dbs_info = &per_cpu(cpu_dbs_info, cpu);
+		cur_nice = cputime64_sub(kstat_cpu(cpu).cpustat.nice,
+					 dbs_info->prev_cpu_nice);
+		/*
+		 * Assumption: nice time between sampling periods will be
+		 * less than 2^32 jiffies for 32 bit sys
+		 */
+		cur_nice_jiffies = (unsigned long)
+					cputime64_to_jiffies64(cur_nice);
+		dbs_info->prev_cpu_nice = kstat_cpu(cpu).cpustat.nice;
+		return idle_time + jiffies_to_usecs(cur_nice_jiffies);
+	}
 	return idle_time;
 }
 
@@ -277,8 +317,8 @@
 	for_each_online_cpu(j) {
 		struct cpu_dbs_info_s *dbs_info;
 		dbs_info = &per_cpu(cpu_dbs_info, j);
-		dbs_info->prev_cpu_idle = get_cpu_idle_time(j);
-		dbs_info->prev_cpu_wall = get_jiffies_64();
+		dbs_info->prev_cpu_idle = get_cpu_idle_time(j,
+						&dbs_info->prev_cpu_wall);
 	}
 	mutex_unlock(&dbs_mutex);
 
@@ -334,9 +374,7 @@
 
 static void dbs_check_cpu(struct cpu_dbs_info_s *this_dbs_info)
 {
-	unsigned int idle_ticks, total_ticks;
-	unsigned int load = 0;
-	cputime64_t cur_jiffies;
+	unsigned int max_load_freq;
 
 	struct cpufreq_policy *policy;
 	unsigned int j;
@@ -346,13 +384,7 @@
 
 	this_dbs_info->freq_lo = 0;
 	policy = this_dbs_info->cur_policy;
-	cur_jiffies = jiffies64_to_cputime64(get_jiffies_64());
-	total_ticks = (unsigned int) cputime64_sub(cur_jiffies,
-			this_dbs_info->prev_cpu_wall);
-	this_dbs_info->prev_cpu_wall = get_jiffies_64();
 
-	if (!total_ticks)
-		return;
 	/*
 	 * Every sampling_rate, we check, if current idle time is less
 	 * than 20% (default), then we try to increase frequency
@@ -365,27 +397,44 @@
 	 * 5% (default) of current frequency
 	 */
 
-	/* Get Idle Time */
-	idle_ticks = UINT_MAX;
+	/* Get Absolute Load - in terms of freq */
+	max_load_freq = 0;
+
 	for_each_cpu_mask_nr(j, policy->cpus) {
-		cputime64_t total_idle_ticks;
-		unsigned int tmp_idle_ticks;
 		struct cpu_dbs_info_s *j_dbs_info;
+		cputime64_t cur_wall_time, cur_idle_time;
+		unsigned int idle_time, wall_time;
+		unsigned int load, load_freq;
+		int freq_avg;
 
 		j_dbs_info = &per_cpu(cpu_dbs_info, j);
-		total_idle_ticks = get_cpu_idle_time(j);
-		tmp_idle_ticks = (unsigned int) cputime64_sub(total_idle_ticks,
-				j_dbs_info->prev_cpu_idle);
-		j_dbs_info->prev_cpu_idle = total_idle_ticks;
 
-		if (tmp_idle_ticks < idle_ticks)
-			idle_ticks = tmp_idle_ticks;
+		cur_idle_time = get_cpu_idle_time(j, &cur_wall_time);
+
+		wall_time = (unsigned int) cputime64_sub(cur_wall_time,
+				j_dbs_info->prev_cpu_wall);
+		j_dbs_info->prev_cpu_wall = cur_wall_time;
+
+		idle_time = (unsigned int) cputime64_sub(cur_idle_time,
+				j_dbs_info->prev_cpu_idle);
+		j_dbs_info->prev_cpu_idle = cur_idle_time;
+
+		if (unlikely(!wall_time || wall_time < idle_time))
+			continue;
+
+		load = 100 * (wall_time - idle_time) / wall_time;
+
+		freq_avg = __cpufreq_driver_getavg(policy, j);
+		if (freq_avg <= 0)
+			freq_avg = policy->cur;
+
+		load_freq = load * freq_avg;
+		if (load_freq > max_load_freq)
+			max_load_freq = load_freq;
 	}
-	if (likely(total_ticks > idle_ticks))
-		load = (100 * (total_ticks - idle_ticks)) / total_ticks;
 
 	/* Check for frequency increase */
-	if (load > dbs_tuners_ins.up_threshold) {
+	if (max_load_freq > dbs_tuners_ins.up_threshold * policy->cur) {
 		/* if we are already at full speed then break out early */
 		if (!dbs_tuners_ins.powersave_bias) {
 			if (policy->cur == policy->max)
@@ -412,15 +461,13 @@
 	 * can support the current CPU usage without triggering the up
 	 * policy. To be safe, we focus 10 points under the threshold.
 	 */
-	if (load < (dbs_tuners_ins.up_threshold - 10)) {
-		unsigned int freq_next, freq_cur;
-
-		freq_cur = __cpufreq_driver_getavg(policy);
-		if (!freq_cur)
-			freq_cur = policy->cur;
-
-		freq_next = (freq_cur * load) /
-			(dbs_tuners_ins.up_threshold - 10);
+	if (max_load_freq <
+	    (dbs_tuners_ins.up_threshold - dbs_tuners_ins.down_differential) *
+	     policy->cur) {
+		unsigned int freq_next;
+		freq_next = max_load_freq /
+				(dbs_tuners_ins.up_threshold -
+				 dbs_tuners_ins.down_differential);
 
 		if (!dbs_tuners_ins.powersave_bias) {
 			__cpufreq_driver_target(policy, freq_next,
@@ -526,8 +573,8 @@
 			j_dbs_info = &per_cpu(cpu_dbs_info, j);
 			j_dbs_info->cur_policy = policy;
 
-			j_dbs_info->prev_cpu_idle = get_cpu_idle_time(j);
-			j_dbs_info->prev_cpu_wall = get_jiffies_64();
+			j_dbs_info->prev_cpu_idle = get_cpu_idle_time(j,
+						&j_dbs_info->prev_cpu_wall);
 		}
 		this_dbs_info->cpu = cpu;
 		/*
@@ -579,22 +626,42 @@
 	return 0;
 }
 
+#ifndef CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND
+static
+#endif
 struct cpufreq_governor cpufreq_gov_ondemand = {
 	.name			= "ondemand",
 	.governor		= cpufreq_governor_dbs,
 	.max_transition_latency = TRANSITION_LATENCY_LIMIT,
 	.owner			= THIS_MODULE,
 };
-EXPORT_SYMBOL(cpufreq_gov_ondemand);
 
 static int __init cpufreq_gov_dbs_init(void)
 {
+	int err;
+	cputime64_t wall;
+	u64 idle_time;
+	int cpu = get_cpu();
+
+	idle_time = get_cpu_idle_time_us(cpu, &wall);
+	put_cpu();
+	if (idle_time != -1ULL) {
+		/* Idle micro accounting is supported. Use finer thresholds */
+		dbs_tuners_ins.up_threshold = MICRO_FREQUENCY_UP_THRESHOLD;
+		dbs_tuners_ins.down_differential =
+					MICRO_FREQUENCY_DOWN_DIFFERENTIAL;
+	}
+
 	kondemand_wq = create_workqueue("kondemand");
 	if (!kondemand_wq) {
 		printk(KERN_ERR "Creation of kondemand failed\n");
 		return -EFAULT;
 	}
-	return cpufreq_register_governor(&cpufreq_gov_ondemand);
+	err = cpufreq_register_governor(&cpufreq_gov_ondemand);
+	if (err)
+		destroy_workqueue(kondemand_wq);
+
+	return err;
 }
 
 static void __exit cpufreq_gov_dbs_exit(void)
diff --git a/drivers/cpufreq/cpufreq_performance.c b/drivers/cpufreq/cpufreq_performance.c
index e8e1451..7e2e515 100644
--- a/drivers/cpufreq/cpufreq_performance.c
+++ b/drivers/cpufreq/cpufreq_performance.c
@@ -36,12 +36,14 @@
 	return 0;
 }
 
+#ifdef CONFIG_CPU_FREQ_GOV_PERFORMANCE_MODULE
+static
+#endif
 struct cpufreq_governor cpufreq_gov_performance = {
 	.name		= "performance",
 	.governor	= cpufreq_governor_performance,
 	.owner		= THIS_MODULE,
 };
-EXPORT_SYMBOL(cpufreq_gov_performance);
 
 
 static int __init cpufreq_gov_performance_init(void)
diff --git a/drivers/cpufreq/cpufreq_powersave.c b/drivers/cpufreq/cpufreq_powersave.c
index 88d2f44..e6db5fa 100644
--- a/drivers/cpufreq/cpufreq_powersave.c
+++ b/drivers/cpufreq/cpufreq_powersave.c
@@ -35,12 +35,14 @@
 	return 0;
 }
 
+#ifndef CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE
+static
+#endif
 struct cpufreq_governor cpufreq_gov_powersave = {
 	.name		= "powersave",
 	.governor	= cpufreq_governor_powersave,
 	.owner		= THIS_MODULE,
 };
-EXPORT_SYMBOL(cpufreq_gov_powersave);
 
 static int __init cpufreq_gov_powersave_init(void)
 {
diff --git a/drivers/cpufreq/cpufreq_userspace.c b/drivers/cpufreq/cpufreq_userspace.c
index 32244aa..1442bba 100644
--- a/drivers/cpufreq/cpufreq_userspace.c
+++ b/drivers/cpufreq/cpufreq_userspace.c
@@ -187,6 +187,9 @@
 }
 
 
+#ifndef CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE
+static
+#endif
 struct cpufreq_governor cpufreq_gov_userspace = {
 	.name		= "userspace",
 	.governor	= cpufreq_governor_userspace,
@@ -194,7 +197,6 @@
 	.show_setspeed	= show_speed,
 	.owner		= THIS_MODULE,
 };
-EXPORT_SYMBOL(cpufreq_gov_userspace);
 
 static int __init cpufreq_gov_userspace_init(void)
 {
diff --git a/drivers/dma/dw_dmac.c b/drivers/dma/dw_dmac.c
index 94df917..0778d99 100644
--- a/drivers/dma/dw_dmac.c
+++ b/drivers/dma/dw_dmac.c
@@ -364,7 +364,7 @@
 	int i;
 
 	status_block = dma_readl(dw, RAW.BLOCK);
-	status_xfer = dma_readl(dw, RAW.BLOCK);
+	status_xfer = dma_readl(dw, RAW.XFER);
 	status_err = dma_readl(dw, RAW.ERROR);
 
 	dev_vdbg(dw->dma.dev, "tasklet: status_block=%x status_err=%x\n",
diff --git a/drivers/firmware/dmi_scan.c b/drivers/firmware/dmi_scan.c
index 455575b..3e526b6 100644
--- a/drivers/firmware/dmi_scan.c
+++ b/drivers/firmware/dmi_scan.c
@@ -15,6 +15,11 @@
  */
 static char dmi_empty_string[] = "        ";
 
+/*
+ * Catch too early calls to dmi_check_system():
+ */
+static int dmi_initialized;
+
 static const char * __init dmi_string_nosave(const struct dmi_header *dm, u8 s)
 {
 	const u8 *bp = ((u8 *) dm) + dm->length;
@@ -366,7 +371,7 @@
 
 	if (efi_enabled) {
 		if (efi.smbios == EFI_INVALID_TABLE_ADDR)
-			goto out;
+			goto error;
 
 		/* This is called as a core_initcall() because it isn't
 		 * needed during early boot.  This also means we can
@@ -374,13 +379,13 @@
 		 */
 		p = dmi_ioremap(efi.smbios, 32);
 		if (p == NULL)
-			goto out;
+			goto error;
 
 		rc = dmi_present(p + 0x10); /* offset of _DMI_ string */
 		dmi_iounmap(p, 32);
 		if (!rc) {
 			dmi_available = 1;
-			return;
+			goto out;
 		}
 	}
 	else {
@@ -391,19 +396,22 @@
 		 */
 		p = dmi_ioremap(0xF0000, 0x10000);
 		if (p == NULL)
-			goto out;
+			goto error;
 
 		for (q = p; q < p + 0x10000; q += 16) {
 			rc = dmi_present(q);
 			if (!rc) {
 				dmi_available = 1;
 				dmi_iounmap(p, 0x10000);
-				return;
+				goto out;
 			}
 		}
 		dmi_iounmap(p, 0x10000);
 	}
- out:	printk(KERN_INFO "DMI not present or invalid.\n");
+ error:
+	printk(KERN_INFO "DMI not present or invalid.\n");
+ out:
+	dmi_initialized = 1;
 }
 
 /**
@@ -424,6 +432,8 @@
 	int i, count = 0;
 	const struct dmi_system_id *d = list;
 
+	WARN(!dmi_initialized, KERN_ERR "dmi check: not initialized yet.\n");
+
 	while (d->ident) {
 		for (i = 0; i < ARRAY_SIZE(d->matches); i++) {
 			int s = d->matches[i].slot;
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index cacf89e..da64108 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -17,6 +17,25 @@
 	tristate "Generic HID support"
 	depends on INPUT
 	default y
+        select HID_A4TECH if !EMBEDDED
+        select HID_APPLE if !EMBEDDED
+        select HID_BELKIN if !EMBEDDED
+        select HID_BRIGHT if !EMBEDDED
+        select HID_CHERRY if !EMBEDDED
+        select HID_CHICONY if !EMBEDDED
+        select HID_CYPRESS if !EMBEDDED
+        select HID_DELL if !EMBEDDED
+        select HID_EZKEY if !EMBEDDED
+        select HID_GYRATION if !EMBEDDED
+        select HID_LOGITECH if !EMBEDDED
+        select HID_MICROSOFT if !EMBEDDED
+        select HID_MONTEREY if !EMBEDDED
+        select HID_PANTHERLORD if !EMBEDDED
+        select HID_PETALYNX if !EMBEDDED
+        select HID_SAMSUNG if !EMBEDDED
+        select HID_SONY if !EMBEDDED
+        select HID_SUNPLUS if !EMBEDDED
+
 	---help---
 	  A human interface device (HID) is a type of computer device that
 	  interacts directly with and takes input from humans. The term "HID"
@@ -67,4 +86,206 @@
 
 source "drivers/hid/usbhid/Kconfig"
 
+menu "Special HID drivers"
+	depends on HID
+
+config HID_COMPAT
+	bool "Load all HID drivers on hid core load"
+	default y
+	---help---
+	Compatible option for older userspace. If you have system without udev
+	support of module loading through aliases and also old
+	module-init-tools which can't handle hid bus, choose Y here. Otherwise
+	say N. If you say N and your userspace is old enough, the only
+	functionality you lose is modules autoloading.
+
+	If unsure, say Y.
+
+config HID_A4TECH
+	tristate "A4 tech"
+	default m
+	depends on USB_HID
+	---help---
+	Support for A4 tech X5 and WOP-35 / Trust 450L mice.
+
+config HID_APPLE
+	tristate "Apple"
+	default m
+	depends on (USB_HID || BT_HIDP)
+	---help---
+	Support for some Apple devices which less or more break
+	HID specification.
+
+	Say Y here if you want support for the special keys (Fn, Numlock) on
+	Apple iBooks, PowerBooks, MacBooks, MacBook Pros and aluminum USB
+	keyboards.
+
+	If unsure, say M.
+
+config HID_BELKIN
+	tristate "Belkin"
+	default m
+	depends on USB_HID
+	---help---
+	Support for Belkin Flip KVM and Wireless keyboard.
+
+config HID_BRIGHT
+	tristate "Bright"
+	default m
+	depends on USB_HID
+	---help---
+	Support for Bright ABNT-2 keyboard.
+
+config HID_CHERRY
+	tristate "Cherry"
+	default m
+	depends on USB_HID
+	---help---
+	Support for Cherry Cymotion.
+
+config HID_CHICONY
+	tristate "Chicony"
+	default m
+	depends on USB_HID
+	---help---
+	Support for Chicony Tactical pad.
+
+config HID_CYPRESS
+	tristate "Cypress"
+	default m
+	depends on USB_HID
+	---help---
+	Support for Cypress mouse and barcodes.
+
+config HID_DELL
+	tristate "Dell"
+	default m
+	depends on USB_HID
+	---help---
+	Support for Dell W7658.
+
+config HID_EZKEY
+	tristate "Ezkey"
+	default m
+	depends on USB_HID
+	---help---
+	Support for Ezkey mouse and barcodes.
+
+config HID_GYRATION
+	tristate "Gyration"
+	default m
+	depends on USB_HID
+	---help---
+	Support for Gyration remote.
+
+config HID_LOGITECH
+	tristate "Logitech"
+	default m
+	depends on USB_HID
+	---help---
+	Support for some Logitech devices which breaks less or more
+	HID specification.
+
+config LOGITECH_FF
+	bool "Logitech force feedback"
+	depends on HID_LOGITECH
+	select INPUT_FF_MEMLESS
+	help
+	  Say Y here if you have one of these devices:
+	  - Logitech WingMan Cordless RumblePad
+	  - Logitech WingMan Cordless RumblePad 2
+	  - Logitech WingMan Force 3D
+	  - Logitech Formula Force EX
+	  - Logitech MOMO Force wheel
+
+	  and if you want to enable force feedback for them.
+	  Note: if you say N here, this device will still be supported, but without
+	  force feedback.
+
+config LOGIRUMBLEPAD2_FF
+	bool "Logitech Rumblepad 2 force feedback"
+	depends on HID_LOGITECH
+	select INPUT_FF_MEMLESS
+	help
+	  Say Y here if you want to enable force feedback support for Logitech
+	  Rumblepad 2 devices.
+
+config HID_MICROSOFT
+	tristate "Microsoft"
+	default m
+	depends on USB_HID
+	---help---
+	Support for some Microsoft devices which breaks less or more
+	HID specification.
+
+config HID_MONTEREY
+	tristate "Monterey"
+	default m
+	depends on USB_HID
+	---help---
+	Support for Monterey Genius KB29E.
+
+config HID_PANTHERLORD
+	tristate "Pantherlord devices support"
+	default m
+	depends on USB_HID
+	---help---
+	Support for PantherLord/GreenAsia based device support.
+
+
+config PANTHERLORD_FF
+	bool "Pantherlord force feedback support"
+	depends on HID_PANTHERLORD
+	select INPUT_FF_MEMLESS
+	help
+	  Say Y here if you have a PantherLord/GreenAsia based game controller
+	  or adapter and want to enable force feedback support for it.
+
+config HID_PETALYNX
+	tristate "Petalynx"
+	default m
+	depends on USB_HID
+	---help---
+	Support for Petalynx Maxter remote.
+
+config HID_SAMSUNG
+	tristate "Samsung"
+	default m
+	depends on USB_HID
+	---help---
+	Support for Samsung IR remote.
+
+config HID_SONY
+	tristate "Sony"
+	default m
+	depends on USB_HID
+	---help---
+	Support for Sony PS3 controller.
+
+config HID_SUNPLUS
+	tristate "Sunplus"
+	default m
+	depends on USB_HID
+	---help---
+	Support for Sunplus WDesktop input device.
+
+config THRUSTMASTER_FF
+	tristate "ThrustMaster devices support"
+	default m
+	depends on USB_HID
+	select INPUT_FF_MEMLESS
+	help
+	  Say Y here if you have a THRUSTMASTER FireStore Dual Power 2 or
+	  a THRUSTMASTER Ferrari GT Rumble Force or Force Feedback Wheel.
+
+config ZEROPLUS_FF
+	tristate "Zeroplus based game controller support"
+	default m
+	depends on USB_HID
+	select INPUT_FF_MEMLESS
+	help
+	  Say Y here if you have a Zeroplus based game controller.
+
+endmenu
+
 endif # HID_SUPPORT
diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile
index 275dc52..b09e43e 100644
--- a/drivers/hid/Makefile
+++ b/drivers/hid/Makefile
@@ -1,13 +1,46 @@
 #
 # Makefile for the HID driver
 #
-hid-objs			:= hid-core.o hid-input.o hid-input-quirks.o
+hid-objs			:= hid-core.o hid-input.o
 
 obj-$(CONFIG_HID)		+= hid.o
 
 hid-$(CONFIG_HID_DEBUG)		+= hid-debug.o
 hid-$(CONFIG_HIDRAW)		+= hidraw.o
 
+ifdef CONFIG_HID_COMPAT
+obj-m				+= hid-dummy.o
+endif
+
+hid-logitech-objs		:= hid-lg.o
+ifdef CONFIG_LOGITECH_FF
+	hid-logitech-objs	+= hid-lgff.o
+endif
+ifdef CONFIG_LOGIRUMBLEPAD2_FF
+	hid-logitech-objs	+= hid-lg2ff.o
+endif
+
+obj-$(CONFIG_HID_A4TECH)	+= hid-a4tech.o
+obj-$(CONFIG_HID_APPLE)		+= hid-apple.o
+obj-$(CONFIG_HID_BELKIN)	+= hid-belkin.o
+obj-$(CONFIG_HID_BRIGHT)	+= hid-bright.o
+obj-$(CONFIG_HID_CHERRY)	+= hid-cherry.o
+obj-$(CONFIG_HID_CHICONY)	+= hid-chicony.o
+obj-$(CONFIG_HID_CYPRESS)	+= hid-cypress.o
+obj-$(CONFIG_HID_DELL)		+= hid-dell.o
+obj-$(CONFIG_HID_EZKEY)		+= hid-ezkey.o
+obj-$(CONFIG_HID_GYRATION)	+= hid-gyration.o
+obj-$(CONFIG_HID_LOGITECH)	+= hid-logitech.o
+obj-$(CONFIG_HID_MICROSOFT)	+= hid-microsoft.o
+obj-$(CONFIG_HID_MONTEREY)	+= hid-monterey.o
+obj-$(CONFIG_HID_PANTHERLORD)	+= hid-pl.o
+obj-$(CONFIG_HID_PETALYNX)	+= hid-petalynx.o
+obj-$(CONFIG_HID_SAMSUNG)	+= hid-samsung.o
+obj-$(CONFIG_HID_SONY)		+= hid-sony.o
+obj-$(CONFIG_HID_SUNPLUS)	+= hid-sunplus.o
+obj-$(CONFIG_THRUSTMASTER_FF)	+= hid-tmff.o
+obj-$(CONFIG_ZEROPLUS_FF)	+= hid-zpff.o
+
 obj-$(CONFIG_USB_HID)		+= usbhid/
 obj-$(CONFIG_USB_MOUSE)		+= usbhid/
 obj-$(CONFIG_USB_KBD)		+= usbhid/
diff --git a/drivers/hid/hid-a4tech.c b/drivers/hid/hid-a4tech.c
new file mode 100644
index 0000000..ebca00e
--- /dev/null
+++ b/drivers/hid/hid-a4tech.c
@@ -0,0 +1,162 @@
+/*
+ *  HID driver for some a4tech "special" devices
+ *
+ *  Copyright (c) 1999 Andreas Gal
+ *  Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
+ *  Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
+ *  Copyright (c) 2006-2007 Jiri Kosina
+ *  Copyright (c) 2007 Paul Walmsley
+ *  Copyright (c) 2008 Jiri Slaby
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or 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/device.h>
+#include <linux/input.h>
+#include <linux/hid.h>
+#include <linux/module.h>
+
+#include "hid-ids.h"
+
+#define A4_2WHEEL_MOUSE_HACK_7	0x01
+#define A4_2WHEEL_MOUSE_HACK_B8	0x02
+
+struct a4tech_sc {
+	unsigned long quirks;
+	unsigned int hw_wheel;
+	__s32 delayed_value;
+};
+
+static int a4_input_mapped(struct hid_device *hdev, struct hid_input *hi,
+		struct hid_field *field, struct hid_usage *usage,
+		unsigned long **bit, int *max)
+{
+	struct a4tech_sc *a4 = hid_get_drvdata(hdev);
+
+	if (usage->type == EV_REL && usage->code == REL_WHEEL)
+		set_bit(REL_HWHEEL, *bit);
+
+	if ((a4->quirks & A4_2WHEEL_MOUSE_HACK_7) && usage->hid == 0x00090007)
+		return -1;
+
+	return 0;
+}
+
+static int a4_event(struct hid_device *hdev, struct hid_field *field,
+		struct hid_usage *usage, __s32 value)
+{
+	struct a4tech_sc *a4 = hid_get_drvdata(hdev);
+	struct input_dev *input;
+
+	if (!(hdev->claimed & HID_CLAIMED_INPUT) || !field->hidinput ||
+			!usage->type)
+		return 0;
+
+	input = field->hidinput->input;
+
+	if (a4->quirks & A4_2WHEEL_MOUSE_HACK_B8) {
+		if (usage->type == EV_REL && usage->code == REL_WHEEL) {
+			a4->delayed_value = value;
+			return 1;
+		}
+
+		if (usage->hid == 0x000100b8) {
+			input_event(input, EV_REL, value ? REL_HWHEEL :
+					REL_WHEEL, a4->delayed_value);
+			return 1;
+		}
+	}
+
+	if ((a4->quirks & A4_2WHEEL_MOUSE_HACK_7) && usage->hid == 0x00090007) {
+		a4->hw_wheel = !!value;
+		return 1;
+	}
+
+	if (usage->code == REL_WHEEL && a4->hw_wheel) {
+		input_event(input, usage->type, REL_HWHEEL, value);
+		return 1;
+	}
+
+	return 0;
+}
+
+static int a4_probe(struct hid_device *hdev, const struct hid_device_id *id)
+{
+	struct a4tech_sc *a4;
+	int ret;
+
+	a4 = kzalloc(sizeof(*a4), GFP_KERNEL);
+	if (a4 == NULL) {
+		dev_err(&hdev->dev, "can't alloc device descriptor\n");
+		ret = -ENOMEM;
+		goto err_free;
+	}
+
+	a4->quirks = id->driver_data;
+
+	hid_set_drvdata(hdev, a4);
+
+	ret = hid_parse(hdev);
+	if (ret) {
+		dev_err(&hdev->dev, "parse failed\n");
+		goto err_free;
+	}
+
+	ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
+	if (ret) {
+		dev_err(&hdev->dev, "hw start failed\n");
+		goto err_free;
+	}
+
+	return 0;
+err_free:
+	kfree(a4);
+	return ret;
+}
+
+static void a4_remove(struct hid_device *hdev)
+{
+	struct a4tech_sc *a4 = hid_get_drvdata(hdev);
+
+	hid_hw_stop(hdev);
+	kfree(a4);
+}
+
+static const struct hid_device_id a4_devices[] = {
+	{ HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_WCP32PU),
+		.driver_data = A4_2WHEEL_MOUSE_HACK_7 },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_X5_005D),
+		.driver_data = A4_2WHEEL_MOUSE_HACK_B8 },
+	{ }
+};
+MODULE_DEVICE_TABLE(hid, a4_devices);
+
+static struct hid_driver a4_driver = {
+	.name = "a4tech",
+	.id_table = a4_devices,
+	.input_mapped = a4_input_mapped,
+	.event = a4_event,
+	.probe = a4_probe,
+	.remove = a4_remove,
+};
+
+static int a4_init(void)
+{
+	return hid_register_driver(&a4_driver);
+}
+
+static void a4_exit(void)
+{
+	hid_unregister_driver(&a4_driver);
+}
+
+module_init(a4_init);
+module_exit(a4_exit);
+MODULE_LICENSE("GPL");
+
+HID_COMPAT_LOAD_DRIVER(a4tech);
diff --git a/drivers/hid/hid-apple.c b/drivers/hid/hid-apple.c
new file mode 100644
index 0000000..fd7f896
--- /dev/null
+++ b/drivers/hid/hid-apple.c
@@ -0,0 +1,484 @@
+/*
+ *  USB HID quirks support for Linux
+ *
+ *  Copyright (c) 1999 Andreas Gal
+ *  Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
+ *  Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
+ *  Copyright (c) 2006-2007 Jiri Kosina
+ *  Copyright (c) 2007 Paul Walmsley
+ *  Copyright (c) 2008 Jiri Slaby <jirislaby@gmail.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/device.h>
+#include <linux/hid.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+
+#include "hid-ids.h"
+
+#define APPLE_RDESC_JIS		0x0001
+#define APPLE_IGNORE_MOUSE	0x0002
+#define APPLE_HAS_FN		0x0004
+#define APPLE_HIDDEV		0x0008
+#define APPLE_ISO_KEYBOARD	0x0010
+#define APPLE_MIGHTYMOUSE	0x0020
+#define APPLE_INVERT_HWHEEL	0x0040
+#define APPLE_IGNORE_HIDINPUT	0x0080
+#define APPLE_NUMLOCK_EMULATION	0x0100
+
+#define APPLE_FLAG_FKEY		0x01
+
+static unsigned int fnmode = 1;
+module_param(fnmode, uint, 0644);
+MODULE_PARM_DESC(fnmode, "Mode of fn key on Apple keyboards (0 = disabled, "
+		"[1] = fkeyslast, 2 = fkeysfirst)");
+
+struct apple_sc {
+	unsigned long quirks;
+	unsigned int fn_on;
+	DECLARE_BITMAP(pressed_fn, KEY_CNT);
+	DECLARE_BITMAP(pressed_numlock, KEY_CNT);
+};
+
+struct apple_key_translation {
+	u16 from;
+	u16 to;
+	u8 flags;
+};
+
+static struct apple_key_translation apple_fn_keys[] = {
+	{ KEY_BACKSPACE, KEY_DELETE },
+	{ KEY_F1,	KEY_BRIGHTNESSDOWN, APPLE_FLAG_FKEY },
+	{ KEY_F2,	KEY_BRIGHTNESSUP,   APPLE_FLAG_FKEY },
+	{ KEY_F3,	KEY_FN_F5,          APPLE_FLAG_FKEY }, /* Exposé */
+	{ KEY_F4,	KEY_FN_F4,          APPLE_FLAG_FKEY }, /* Dashboard */
+	{ KEY_F5,	KEY_KBDILLUMDOWN,   APPLE_FLAG_FKEY },
+	{ KEY_F6,	KEY_KBDILLUMUP,     APPLE_FLAG_FKEY },
+	{ KEY_F7,	KEY_PREVIOUSSONG,   APPLE_FLAG_FKEY },
+	{ KEY_F8,	KEY_PLAYPAUSE,      APPLE_FLAG_FKEY },
+	{ KEY_F9,	KEY_NEXTSONG,       APPLE_FLAG_FKEY },
+	{ KEY_F10,	KEY_MUTE,           APPLE_FLAG_FKEY },
+	{ KEY_F11,	KEY_VOLUMEDOWN,     APPLE_FLAG_FKEY },
+	{ KEY_F12,	KEY_VOLUMEUP,       APPLE_FLAG_FKEY },
+	{ KEY_UP,	KEY_PAGEUP },
+	{ KEY_DOWN,	KEY_PAGEDOWN },
+	{ KEY_LEFT,	KEY_HOME },
+	{ KEY_RIGHT,	KEY_END },
+	{ }
+};
+
+static struct apple_key_translation powerbook_fn_keys[] = {
+	{ KEY_BACKSPACE, KEY_DELETE },
+	{ KEY_F1,	KEY_BRIGHTNESSDOWN,     APPLE_FLAG_FKEY },
+	{ KEY_F2,	KEY_BRIGHTNESSUP,       APPLE_FLAG_FKEY },
+	{ KEY_F3,	KEY_MUTE,               APPLE_FLAG_FKEY },
+	{ KEY_F4,	KEY_VOLUMEDOWN,         APPLE_FLAG_FKEY },
+	{ KEY_F5,	KEY_VOLUMEUP,           APPLE_FLAG_FKEY },
+	{ KEY_F6,	KEY_NUMLOCK,            APPLE_FLAG_FKEY },
+	{ KEY_F7,	KEY_SWITCHVIDEOMODE,    APPLE_FLAG_FKEY },
+	{ KEY_F8,	KEY_KBDILLUMTOGGLE,     APPLE_FLAG_FKEY },
+	{ KEY_F9,	KEY_KBDILLUMDOWN,       APPLE_FLAG_FKEY },
+	{ KEY_F10,	KEY_KBDILLUMUP,         APPLE_FLAG_FKEY },
+	{ KEY_UP,	KEY_PAGEUP },
+	{ KEY_DOWN,	KEY_PAGEDOWN },
+	{ KEY_LEFT,	KEY_HOME },
+	{ KEY_RIGHT,	KEY_END },
+	{ }
+};
+
+static struct apple_key_translation powerbook_numlock_keys[] = {
+	{ KEY_J,	KEY_KP1 },
+	{ KEY_K,	KEY_KP2 },
+	{ KEY_L,	KEY_KP3 },
+	{ KEY_U,	KEY_KP4 },
+	{ KEY_I,	KEY_KP5 },
+	{ KEY_O,	KEY_KP6 },
+	{ KEY_7,	KEY_KP7 },
+	{ KEY_8,	KEY_KP8 },
+	{ KEY_9,	KEY_KP9 },
+	{ KEY_M,	KEY_KP0 },
+	{ KEY_DOT,	KEY_KPDOT },
+	{ KEY_SLASH,	KEY_KPPLUS },
+	{ KEY_SEMICOLON, KEY_KPMINUS },
+	{ KEY_P,	KEY_KPASTERISK },
+	{ KEY_MINUS,	KEY_KPEQUAL },
+	{ KEY_0,	KEY_KPSLASH },
+	{ KEY_F6,	KEY_NUMLOCK },
+	{ KEY_KPENTER,	KEY_KPENTER },
+	{ KEY_BACKSPACE, KEY_BACKSPACE },
+	{ }
+};
+
+static struct apple_key_translation apple_iso_keyboard[] = {
+	{ KEY_GRAVE,	KEY_102ND },
+	{ KEY_102ND,	KEY_GRAVE },
+	{ }
+};
+
+static struct apple_key_translation *apple_find_translation(
+		struct apple_key_translation *table, u16 from)
+{
+	struct apple_key_translation *trans;
+
+	/* Look for the translation */
+	for (trans = table; trans->from; trans++)
+		if (trans->from == from)
+			return trans;
+
+	return NULL;
+}
+
+static int hidinput_apple_event(struct hid_device *hid, struct input_dev *input,
+		struct hid_usage *usage, __s32 value)
+{
+	struct apple_sc *asc = hid_get_drvdata(hid);
+	struct apple_key_translation *trans;
+
+	if (usage->code == KEY_FN) {
+		asc->fn_on = !!value;
+		input_event(input, usage->type, usage->code, value);
+		return 1;
+	}
+
+	if (fnmode) {
+		int do_translate;
+
+		trans = apple_find_translation((hid->product < 0x220 ||
+					hid->product >= 0x300) ?
+					powerbook_fn_keys : apple_fn_keys,
+					usage->code);
+		if (trans) {
+			if (test_bit(usage->code, asc->pressed_fn))
+				do_translate = 1;
+			else if (trans->flags & APPLE_FLAG_FKEY)
+				do_translate = (fnmode == 2 && asc->fn_on) ||
+					(fnmode == 1 && !asc->fn_on);
+			else
+				do_translate = asc->fn_on;
+
+			if (do_translate) {
+				if (value)
+					set_bit(usage->code, asc->pressed_fn);
+				else
+					clear_bit(usage->code, asc->pressed_fn);
+
+				input_event(input, usage->type, trans->to,
+						value);
+
+				return 1;
+			}
+		}
+
+		if (asc->quirks & APPLE_NUMLOCK_EMULATION &&
+				(test_bit(usage->code, asc->pressed_numlock) ||
+				test_bit(LED_NUML, input->led))) {
+			trans = apple_find_translation(powerbook_numlock_keys,
+					usage->code);
+
+			if (trans) {
+				if (value)
+					set_bit(usage->code,
+							asc->pressed_numlock);
+				else
+					clear_bit(usage->code,
+							asc->pressed_numlock);
+
+				input_event(input, usage->type, trans->to,
+						value);
+			}
+
+			return 1;
+		}
+	}
+
+	if (asc->quirks & APPLE_ISO_KEYBOARD) {
+		trans = apple_find_translation(apple_iso_keyboard, usage->code);
+		if (trans) {
+			input_event(input, usage->type, trans->to, value);
+			return 1;
+		}
+	}
+
+	return 0;
+}
+
+static int apple_event(struct hid_device *hdev, struct hid_field *field,
+		struct hid_usage *usage, __s32 value)
+{
+	struct apple_sc *asc = hid_get_drvdata(hdev);
+
+	if (!(hdev->claimed & HID_CLAIMED_INPUT) || !field->hidinput ||
+			!usage->type)
+		return 0;
+
+	if ((asc->quirks & APPLE_INVERT_HWHEEL) &&
+			usage->code == REL_HWHEEL) {
+		input_event(field->hidinput->input, usage->type, usage->code,
+				-value);
+		return 1;
+	}
+
+	if ((asc->quirks & APPLE_HAS_FN) &&
+			hidinput_apple_event(hdev, field->hidinput->input,
+				usage, value))
+		return 1;
+
+
+	return 0;
+}
+
+/*
+ * MacBook JIS keyboard has wrong logical maximum
+ */
+static void apple_report_fixup(struct hid_device *hdev, __u8 *rdesc,
+		unsigned int rsize)
+{
+	struct apple_sc *asc = hid_get_drvdata(hdev);
+
+	if ((asc->quirks & APPLE_RDESC_JIS) && rsize >= 60 &&
+			rdesc[53] == 0x65 && rdesc[59] == 0x65) {
+		dev_info(&hdev->dev, "fixing up MacBook JIS keyboard report "
+				"descriptor\n");
+		rdesc[53] = rdesc[59] = 0xe7;
+	}
+}
+
+static void apple_setup_input(struct input_dev *input)
+{
+	struct apple_key_translation *trans;
+
+	set_bit(KEY_NUMLOCK, input->keybit);
+
+	/* Enable all needed keys */
+	for (trans = apple_fn_keys; trans->from; trans++)
+		set_bit(trans->to, input->keybit);
+
+	for (trans = powerbook_fn_keys; trans->from; trans++)
+		set_bit(trans->to, input->keybit);
+
+	for (trans = powerbook_numlock_keys; trans->from; trans++)
+		set_bit(trans->to, input->keybit);
+
+	for (trans = apple_iso_keyboard; trans->from; trans++)
+		set_bit(trans->to, input->keybit);
+}
+
+static int apple_input_mapping(struct hid_device *hdev, struct hid_input *hi,
+		struct hid_field *field, struct hid_usage *usage,
+		unsigned long **bit, int *max)
+{
+	if (usage->hid == (HID_UP_CUSTOM | 0x0003)) {
+		/* The fn key on Apple USB keyboards */
+		set_bit(EV_REP, hi->input->evbit);
+		hid_map_usage_clear(hi, usage, bit, max, EV_KEY, KEY_FN);
+		apple_setup_input(hi->input);
+		return 1;
+	}
+
+	/* we want the hid layer to go through standard path (set and ignore) */
+	return 0;
+}
+
+static int apple_input_mapped(struct hid_device *hdev, struct hid_input *hi,
+		struct hid_field *field, struct hid_usage *usage,
+		unsigned long **bit, int *max)
+{
+	struct apple_sc *asc = hid_get_drvdata(hdev);
+
+	if (asc->quirks & APPLE_MIGHTYMOUSE) {
+		if (usage->hid == HID_GD_Z)
+			hid_map_usage(hi, usage, bit, max, EV_REL, REL_HWHEEL);
+		else if (usage->code == BTN_1)
+			hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_2);
+		else if (usage->code == BTN_2)
+			hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_1);
+	}
+
+	return 0;
+}
+
+static int apple_probe(struct hid_device *hdev,
+		const struct hid_device_id *id)
+{
+	unsigned long quirks = id->driver_data;
+	struct apple_sc *asc;
+	unsigned int connect_mask = HID_CONNECT_DEFAULT;
+	int ret;
+
+	/* return something else or move to hid layer? device will reside
+	   allocated */
+	if (id->bus == BUS_USB && (quirks & APPLE_IGNORE_MOUSE) &&
+			to_usb_interface(hdev->dev.parent)->cur_altsetting->
+			desc.bInterfaceProtocol == USB_INTERFACE_PROTOCOL_MOUSE)
+		return -ENODEV;
+
+	asc = kzalloc(sizeof(*asc), GFP_KERNEL);
+	if (asc == NULL) {
+		dev_err(&hdev->dev, "can't alloc apple descriptor\n");
+		return -ENOMEM;
+	}
+
+	asc->quirks = quirks;
+
+	hid_set_drvdata(hdev, asc);
+
+	ret = hid_parse(hdev);
+	if (ret) {
+		dev_err(&hdev->dev, "parse failed\n");
+		goto err_free;
+	}
+
+	if (quirks & APPLE_HIDDEV)
+		connect_mask |= HID_CONNECT_HIDDEV_FORCE;
+	if (quirks & APPLE_IGNORE_HIDINPUT)
+		connect_mask &= ~HID_CONNECT_HIDINPUT;
+
+	ret = hid_hw_start(hdev, connect_mask);
+	if (ret) {
+		dev_err(&hdev->dev, "hw start failed\n");
+		goto err_free;
+	}
+
+	return 0;
+err_free:
+	kfree(asc);
+	return ret;
+}
+
+static void apple_remove(struct hid_device *hdev)
+{
+	hid_hw_stop(hdev);
+	kfree(hid_get_drvdata(hdev));
+}
+
+static const struct hid_device_id apple_devices[] = {
+	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ATV_IRCONTROL),
+		.driver_data = APPLE_HIDDEV | APPLE_IGNORE_HIDINPUT },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL4),
+		.driver_data = APPLE_HIDDEV | APPLE_IGNORE_HIDINPUT },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MIGHTYMOUSE),
+		.driver_data = APPLE_MIGHTYMOUSE | APPLE_INVERT_HWHEEL },
+
+	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ANSI),
+		.driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN |
+			APPLE_IGNORE_MOUSE },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ISO),
+		.driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN |
+			APPLE_IGNORE_MOUSE },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_ANSI),
+		.driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN |
+			APPLE_IGNORE_MOUSE },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_ISO),
+		.driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN |
+			APPLE_IGNORE_MOUSE | APPLE_ISO_KEYBOARD },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_JIS),
+		.driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN |
+			APPLE_IGNORE_MOUSE },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_ANSI),
+		.driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN |
+			APPLE_IGNORE_MOUSE },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_ISO),
+		.driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN |
+			APPLE_IGNORE_MOUSE | APPLE_ISO_KEYBOARD },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_JIS),
+		.driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN |
+			APPLE_IGNORE_MOUSE | APPLE_RDESC_JIS },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_ANSI),
+		.driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN |
+			APPLE_IGNORE_MOUSE },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_ISO),
+		.driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN |
+			APPLE_IGNORE_MOUSE | APPLE_ISO_KEYBOARD },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_JIS),
+		.driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN |
+			APPLE_IGNORE_MOUSE | APPLE_RDESC_JIS},
+	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_ANSI),
+		.driver_data = APPLE_HAS_FN },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_ISO),
+		.driver_data = APPLE_HAS_FN | APPLE_ISO_KEYBOARD },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_JIS),
+		.driver_data = APPLE_HAS_FN },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_HF_ANSI),
+		.driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN |
+			APPLE_IGNORE_MOUSE },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_HF_ISO),
+		.driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN |
+			APPLE_IGNORE_MOUSE },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_HF_JIS),
+		.driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN |
+			APPLE_IGNORE_MOUSE | APPLE_RDESC_JIS },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_ANSI),
+		.driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_ISO),
+		.driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN |
+			APPLE_ISO_KEYBOARD },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_JIS),
+		.driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING_ANSI),
+		.driver_data = APPLE_HAS_FN | APPLE_IGNORE_MOUSE },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING_ISO),
+		.driver_data = APPLE_HAS_FN | APPLE_ISO_KEYBOARD |
+			APPLE_IGNORE_MOUSE },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING_JIS),
+		.driver_data = APPLE_HAS_FN | APPLE_IGNORE_MOUSE | APPLE_RDESC_JIS },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING2_ANSI),
+		.driver_data = APPLE_HAS_FN | APPLE_IGNORE_MOUSE },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING2_ISO),
+		.driver_data = APPLE_HAS_FN | APPLE_ISO_KEYBOARD |
+			APPLE_IGNORE_MOUSE },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING2_JIS),
+		.driver_data = APPLE_HAS_FN | APPLE_IGNORE_MOUSE | APPLE_RDESC_JIS },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY),
+		.driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN |
+			APPLE_IGNORE_MOUSE },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY),
+		.driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN |
+			APPLE_IGNORE_MOUSE },
+
+	/* Apple wireless Mighty Mouse */
+	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, 0x030c),
+		.driver_data = APPLE_MIGHTYMOUSE | APPLE_INVERT_HWHEEL },
+
+	{ }
+};
+MODULE_DEVICE_TABLE(hid, apple_devices);
+
+static struct hid_driver apple_driver = {
+	.name = "apple",
+	.id_table = apple_devices,
+	.report_fixup = apple_report_fixup,
+	.probe = apple_probe,
+	.remove = apple_remove,
+	.event = apple_event,
+	.input_mapping = apple_input_mapping,
+	.input_mapped = apple_input_mapped,
+};
+
+static int apple_init(void)
+{
+	int ret;
+
+	ret = hid_register_driver(&apple_driver);
+	if (ret)
+		printk(KERN_ERR "can't register apple driver\n");
+
+	return ret;
+}
+
+static void apple_exit(void)
+{
+	hid_unregister_driver(&apple_driver);
+}
+
+module_init(apple_init);
+module_exit(apple_exit);
+MODULE_LICENSE("GPL");
+
+HID_COMPAT_LOAD_DRIVER(apple);
diff --git a/drivers/hid/hid-belkin.c b/drivers/hid/hid-belkin.c
new file mode 100644
index 0000000..12c8a9b
--- /dev/null
+++ b/drivers/hid/hid-belkin.c
@@ -0,0 +1,105 @@
+/*
+ *  HID driver for some belkin "special" devices
+ *
+ *  Copyright (c) 1999 Andreas Gal
+ *  Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
+ *  Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
+ *  Copyright (c) 2006-2007 Jiri Kosina
+ *  Copyright (c) 2007 Paul Walmsley
+ *  Copyright (c) 2008 Jiri Slaby
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or 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/device.h>
+#include <linux/hid.h>
+#include <linux/module.h>
+
+#include "hid-ids.h"
+
+#define BELKIN_HIDDEV	0x01
+#define BELKIN_WKBD	0x02
+
+#define belkin_map_key_clear(c)	hid_map_usage_clear(hi, usage, bit, max, \
+					EV_KEY, (c))
+static int belkin_input_mapping(struct hid_device *hdev, struct hid_input *hi,
+		struct hid_field *field, struct hid_usage *usage,
+		unsigned long **bit, int *max)
+{
+	unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
+
+	if ((usage->hid & HID_USAGE_PAGE) != HID_UP_CONSUMER ||
+			!(quirks & BELKIN_WKBD))
+		return 0;
+
+	switch (usage->hid & HID_USAGE) {
+	case 0x03a: belkin_map_key_clear(KEY_SOUND);		break;
+	case 0x03b: belkin_map_key_clear(KEY_CAMERA);		break;
+	case 0x03c: belkin_map_key_clear(KEY_DOCUMENTS);	break;
+	default:
+		return 0;
+	}
+	return 1;
+}
+
+static int belkin_probe(struct hid_device *hdev, const struct hid_device_id *id)
+{
+	unsigned long quirks = id->driver_data;
+	int ret;
+
+	hid_set_drvdata(hdev, (void *)quirks);
+
+	ret = hid_parse(hdev);
+	if (ret) {
+		dev_err(&hdev->dev, "parse failed\n");
+		goto err_free;
+	}
+
+	ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT |
+		((quirks & BELKIN_HIDDEV) ? HID_CONNECT_HIDDEV_FORCE : 0));
+	if (ret) {
+		dev_err(&hdev->dev, "hw start failed\n");
+		goto err_free;
+	}
+
+	return 0;
+err_free:
+	return ret;
+}
+
+static const struct hid_device_id belkin_devices[] = {
+	{ HID_USB_DEVICE(USB_VENDOR_ID_BELKIN, USB_DEVICE_ID_FLIP_KVM),
+		.driver_data = BELKIN_HIDDEV },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_LABTEC, USB_DEVICE_ID_LABTEC_WIRELESS_KEYBOARD),
+		.driver_data = BELKIN_WKBD },
+	{ }
+};
+MODULE_DEVICE_TABLE(hid, belkin_devices);
+
+static struct hid_driver belkin_driver = {
+	.name = "belkin",
+	.id_table = belkin_devices,
+	.input_mapping = belkin_input_mapping,
+	.probe = belkin_probe,
+};
+
+static int belkin_init(void)
+{
+	return hid_register_driver(&belkin_driver);
+}
+
+static void belkin_exit(void)
+{
+	hid_unregister_driver(&belkin_driver);
+}
+
+module_init(belkin_init);
+module_exit(belkin_exit);
+MODULE_LICENSE("GPL");
+
+HID_COMPAT_LOAD_DRIVER(belkin);
diff --git a/drivers/hid/hid-bright.c b/drivers/hid/hid-bright.c
new file mode 100644
index 0000000..38517a1
--- /dev/null
+++ b/drivers/hid/hid-bright.c
@@ -0,0 +1,71 @@
+/*
+ *  HID driver for some bright "special" devices
+ *
+ *  Copyright (c) 2008 Mauro Carvalho Chehab <mchehab@redhat.com>
+ *
+ * Based on hid-dell 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.
+ */
+
+#include <linux/device.h>
+#include <linux/hid.h>
+#include <linux/module.h>
+
+#include "hid-ids.h"
+
+static int bright_probe(struct hid_device *hdev, const struct hid_device_id *id)
+{
+	int ret;
+
+	ret = hid_parse(hdev);
+	if (ret) {
+		dev_err(&hdev->dev, "parse failed\n");
+		goto err_free;
+	}
+
+	ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
+	if (ret) {
+		dev_err(&hdev->dev, "hw start failed\n");
+		goto err_free;
+	}
+
+	usbhid_set_leds(hdev);
+
+	return 0;
+err_free:
+	return ret;
+}
+
+static const struct hid_device_id bright_devices[] = {
+	{ HID_USB_DEVICE(USB_VENDOR_ID_BRIGHT, USB_DEVICE_ID_BRIGHT_ABNT2) },
+	{ }
+};
+MODULE_DEVICE_TABLE(hid, bright_devices);
+
+static struct hid_driver bright_driver = {
+	.name = "bright",
+	.id_table = bright_devices,
+	.probe = bright_probe,
+};
+
+static int bright_init(void)
+{
+	return hid_register_driver(&bright_driver);
+}
+
+static void bright_exit(void)
+{
+	hid_unregister_driver(&bright_driver);
+}
+
+module_init(bright_init);
+module_exit(bright_exit);
+MODULE_LICENSE("GPL");
+
+HID_COMPAT_LOAD_DRIVER(bright);
diff --git a/drivers/hid/hid-cherry.c b/drivers/hid/hid-cherry.c
new file mode 100644
index 0000000..b833b97
--- /dev/null
+++ b/drivers/hid/hid-cherry.c
@@ -0,0 +1,87 @@
+/*
+ *  HID driver for some cherry "special" devices
+ *
+ *  Copyright (c) 1999 Andreas Gal
+ *  Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
+ *  Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
+ *  Copyright (c) 2006-2007 Jiri Kosina
+ *  Copyright (c) 2007 Paul Walmsley
+ *  Copyright (c) 2008 Jiri Slaby
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or 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/device.h>
+#include <linux/hid.h>
+#include <linux/module.h>
+
+#include "hid-ids.h"
+
+/*
+ * Cherry Cymotion keyboard have an invalid HID report descriptor,
+ * that needs fixing before we can parse it.
+ */
+static void ch_report_fixup(struct hid_device *hdev, __u8 *rdesc,
+		unsigned int rsize)
+{
+	if (rsize >= 17 && rdesc[11] == 0x3c && rdesc[12] == 0x02) {
+		dev_info(&hdev->dev, "fixing up Cherry Cymotion report "
+				"descriptor\n");
+		rdesc[11] = rdesc[16] = 0xff;
+		rdesc[12] = rdesc[17] = 0x03;
+	}
+}
+
+#define ch_map_key_clear(c)	hid_map_usage_clear(hi, usage, bit, max, \
+					EV_KEY, (c))
+static int ch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
+		struct hid_field *field, struct hid_usage *usage,
+		unsigned long **bit, int *max)
+{
+	if ((usage->hid & HID_USAGE_PAGE) != HID_UP_CONSUMER)
+		return 0;
+
+	switch (usage->hid & HID_USAGE) {
+	case 0x301: ch_map_key_clear(KEY_PROG1);	break;
+	case 0x302: ch_map_key_clear(KEY_PROG2);	break;
+	case 0x303: ch_map_key_clear(KEY_PROG3);	break;
+	default:
+		return 0;
+	}
+
+	return 1;
+}
+
+static const struct hid_device_id ch_devices[] = {
+	{ HID_USB_DEVICE(USB_VENDOR_ID_CHERRY, USB_DEVICE_ID_CHERRY_CYMOTION) },
+	{ }
+};
+MODULE_DEVICE_TABLE(hid, ch_devices);
+
+static struct hid_driver ch_driver = {
+	.name = "cherry",
+	.id_table = ch_devices,
+	.report_fixup = ch_report_fixup,
+	.input_mapping = ch_input_mapping,
+};
+
+static int ch_init(void)
+{
+	return hid_register_driver(&ch_driver);
+}
+
+static void ch_exit(void)
+{
+	hid_unregister_driver(&ch_driver);
+}
+
+module_init(ch_init);
+module_exit(ch_exit);
+MODULE_LICENSE("GPL");
+
+HID_COMPAT_LOAD_DRIVER(cherry);
diff --git a/drivers/hid/hid-chicony.c b/drivers/hid/hid-chicony.c
new file mode 100644
index 0000000..a54d409
--- /dev/null
+++ b/drivers/hid/hid-chicony.c
@@ -0,0 +1,80 @@
+/*
+ *  HID driver for some chicony "special" devices
+ *
+ *  Copyright (c) 1999 Andreas Gal
+ *  Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
+ *  Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
+ *  Copyright (c) 2006-2007 Jiri Kosina
+ *  Copyright (c) 2007 Paul Walmsley
+ *  Copyright (c) 2008 Jiri Slaby
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or 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/device.h>
+#include <linux/input.h>
+#include <linux/hid.h>
+#include <linux/module.h>
+
+#include "hid-ids.h"
+
+#define ch_map_key_clear(c)	hid_map_usage_clear(hi, usage, bit, max, \
+					EV_KEY, (c))
+static int ch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
+		struct hid_field *field, struct hid_usage *usage,
+		unsigned long **bit, int *max)
+{
+	if ((usage->hid & HID_USAGE_PAGE) != HID_UP_MSVENDOR)
+		return 0;
+
+	set_bit(EV_REP, hi->input->evbit);
+	switch (usage->hid & HID_USAGE) {
+	case 0xff01: ch_map_key_clear(BTN_1);	break;
+	case 0xff02: ch_map_key_clear(BTN_2);	break;
+	case 0xff03: ch_map_key_clear(BTN_3);	break;
+	case 0xff04: ch_map_key_clear(BTN_4);	break;
+	case 0xff05: ch_map_key_clear(BTN_5);	break;
+	case 0xff06: ch_map_key_clear(BTN_6);	break;
+	case 0xff07: ch_map_key_clear(BTN_7);	break;
+	case 0xff08: ch_map_key_clear(BTN_8);	break;
+	case 0xff09: ch_map_key_clear(BTN_9);	break;
+	case 0xff0a: ch_map_key_clear(BTN_A);	break;
+	case 0xff0b: ch_map_key_clear(BTN_B);	break;
+	default:
+		return 0;
+	}
+	return 1;
+}
+
+static const struct hid_device_id ch_devices[] = {
+	{ HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_TACTICAL_PAD) },
+	{ }
+};
+MODULE_DEVICE_TABLE(hid, ch_devices);
+
+static struct hid_driver ch_driver = {
+	.name = "chicony",
+	.id_table = ch_devices,
+	.input_mapping = ch_input_mapping,
+};
+
+static int ch_init(void)
+{
+	return hid_register_driver(&ch_driver);
+}
+
+static void ch_exit(void)
+{
+	hid_unregister_driver(&ch_driver);
+}
+
+module_init(ch_init);
+module_exit(ch_exit);
+MODULE_LICENSE("GPL");
+
+HID_COMPAT_LOAD_DRIVER(chicony);
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index 426ac5a..8a7d9db 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -33,6 +33,8 @@
 #include <linux/hid-debug.h>
 #include <linux/hidraw.h>
 
+#include "hid-ids.h"
+
 /*
  * Version Information
  */
@@ -268,9 +270,9 @@
 static u32 item_udata(struct hid_item *item)
 {
 	switch (item->size) {
-		case 1: return item->data.u8;
-		case 2: return item->data.u16;
-		case 4: return item->data.u32;
+	case 1: return item->data.u8;
+	case 2: return item->data.u16;
+	case 4: return item->data.u32;
 	}
 	return 0;
 }
@@ -278,9 +280,9 @@
 static s32 item_sdata(struct hid_item *item)
 {
 	switch (item->size) {
-		case 1: return item->data.s8;
-		case 2: return item->data.s16;
-		case 4: return item->data.s32;
+	case 1: return item->data.s8;
+	case 2: return item->data.s16;
+	case 4: return item->data.s32;
 	}
 	return 0;
 }
@@ -292,87 +294,91 @@
 static int hid_parser_global(struct hid_parser *parser, struct hid_item *item)
 {
 	switch (item->tag) {
+	case HID_GLOBAL_ITEM_TAG_PUSH:
 
-		case HID_GLOBAL_ITEM_TAG_PUSH:
-
-			if (parser->global_stack_ptr == HID_GLOBAL_STACK_SIZE) {
-				dbg_hid("global enviroment stack overflow\n");
-				return -1;
-			}
-
-			memcpy(parser->global_stack + parser->global_stack_ptr++,
-				&parser->global, sizeof(struct hid_global));
-			return 0;
-
-		case HID_GLOBAL_ITEM_TAG_POP:
-
-			if (!parser->global_stack_ptr) {
-				dbg_hid("global enviroment stack underflow\n");
-				return -1;
-			}
-
-			memcpy(&parser->global, parser->global_stack + --parser->global_stack_ptr,
-				sizeof(struct hid_global));
-			return 0;
-
-		case HID_GLOBAL_ITEM_TAG_USAGE_PAGE:
-			parser->global.usage_page = item_udata(item);
-			return 0;
-
-		case HID_GLOBAL_ITEM_TAG_LOGICAL_MINIMUM:
-			parser->global.logical_minimum = item_sdata(item);
-			return 0;
-
-		case HID_GLOBAL_ITEM_TAG_LOGICAL_MAXIMUM:
-			if (parser->global.logical_minimum < 0)
-				parser->global.logical_maximum = item_sdata(item);
-			else
-				parser->global.logical_maximum = item_udata(item);
-			return 0;
-
-		case HID_GLOBAL_ITEM_TAG_PHYSICAL_MINIMUM:
-			parser->global.physical_minimum = item_sdata(item);
-			return 0;
-
-		case HID_GLOBAL_ITEM_TAG_PHYSICAL_MAXIMUM:
-			if (parser->global.physical_minimum < 0)
-				parser->global.physical_maximum = item_sdata(item);
-			else
-				parser->global.physical_maximum = item_udata(item);
-			return 0;
-
-		case HID_GLOBAL_ITEM_TAG_UNIT_EXPONENT:
-			parser->global.unit_exponent = item_sdata(item);
-			return 0;
-
-		case HID_GLOBAL_ITEM_TAG_UNIT:
-			parser->global.unit = item_udata(item);
-			return 0;
-
-		case HID_GLOBAL_ITEM_TAG_REPORT_SIZE:
-			if ((parser->global.report_size = item_udata(item)) > 32) {
-				dbg_hid("invalid report_size %d\n", parser->global.report_size);
-				return -1;
-			}
-			return 0;
-
-		case HID_GLOBAL_ITEM_TAG_REPORT_COUNT:
-			if ((parser->global.report_count = item_udata(item)) > HID_MAX_USAGES) {
-				dbg_hid("invalid report_count %d\n", parser->global.report_count);
-				return -1;
-			}
-			return 0;
-
-		case HID_GLOBAL_ITEM_TAG_REPORT_ID:
-			if ((parser->global.report_id = item_udata(item)) == 0) {
-				dbg_hid("report_id 0 is invalid\n");
-				return -1;
-			}
-			return 0;
-
-		default:
-			dbg_hid("unknown global tag 0x%x\n", item->tag);
+		if (parser->global_stack_ptr == HID_GLOBAL_STACK_SIZE) {
+			dbg_hid("global enviroment stack overflow\n");
 			return -1;
+		}
+
+		memcpy(parser->global_stack + parser->global_stack_ptr++,
+			&parser->global, sizeof(struct hid_global));
+		return 0;
+
+	case HID_GLOBAL_ITEM_TAG_POP:
+
+		if (!parser->global_stack_ptr) {
+			dbg_hid("global enviroment stack underflow\n");
+			return -1;
+		}
+
+		memcpy(&parser->global, parser->global_stack +
+			--parser->global_stack_ptr, sizeof(struct hid_global));
+		return 0;
+
+	case HID_GLOBAL_ITEM_TAG_USAGE_PAGE:
+		parser->global.usage_page = item_udata(item);
+		return 0;
+
+	case HID_GLOBAL_ITEM_TAG_LOGICAL_MINIMUM:
+		parser->global.logical_minimum = item_sdata(item);
+		return 0;
+
+	case HID_GLOBAL_ITEM_TAG_LOGICAL_MAXIMUM:
+		if (parser->global.logical_minimum < 0)
+			parser->global.logical_maximum = item_sdata(item);
+		else
+			parser->global.logical_maximum = item_udata(item);
+		return 0;
+
+	case HID_GLOBAL_ITEM_TAG_PHYSICAL_MINIMUM:
+		parser->global.physical_minimum = item_sdata(item);
+		return 0;
+
+	case HID_GLOBAL_ITEM_TAG_PHYSICAL_MAXIMUM:
+		if (parser->global.physical_minimum < 0)
+			parser->global.physical_maximum = item_sdata(item);
+		else
+			parser->global.physical_maximum = item_udata(item);
+		return 0;
+
+	case HID_GLOBAL_ITEM_TAG_UNIT_EXPONENT:
+		parser->global.unit_exponent = item_sdata(item);
+		return 0;
+
+	case HID_GLOBAL_ITEM_TAG_UNIT:
+		parser->global.unit = item_udata(item);
+		return 0;
+
+	case HID_GLOBAL_ITEM_TAG_REPORT_SIZE:
+		parser->global.report_size = item_udata(item);
+		if (parser->global.report_size > 32) {
+			dbg_hid("invalid report_size %d\n",
+					parser->global.report_size);
+			return -1;
+		}
+		return 0;
+
+	case HID_GLOBAL_ITEM_TAG_REPORT_COUNT:
+		parser->global.report_count = item_udata(item);
+		if (parser->global.report_count > HID_MAX_USAGES) {
+			dbg_hid("invalid report_count %d\n",
+					parser->global.report_count);
+			return -1;
+		}
+		return 0;
+
+	case HID_GLOBAL_ITEM_TAG_REPORT_ID:
+		parser->global.report_id = item_udata(item);
+		if (parser->global.report_id == 0) {
+			dbg_hid("report_id 0 is invalid\n");
+			return -1;
+		}
+		return 0;
+
+	default:
+		dbg_hid("unknown global tag 0x%x\n", item->tag);
+		return -1;
 	}
 }
 
@@ -393,77 +399,76 @@
 	data = item_udata(item);
 
 	switch (item->tag) {
+	case HID_LOCAL_ITEM_TAG_DELIMITER:
 
-		case HID_LOCAL_ITEM_TAG_DELIMITER:
-
-			if (data) {
-				/*
-				 * We treat items before the first delimiter
-				 * as global to all usage sets (branch 0).
-				 * In the moment we process only these global
-				 * items and the first delimiter set.
-				 */
-				if (parser->local.delimiter_depth != 0) {
-					dbg_hid("nested delimiters\n");
-					return -1;
-				}
-				parser->local.delimiter_depth++;
-				parser->local.delimiter_branch++;
-			} else {
-				if (parser->local.delimiter_depth < 1) {
-					dbg_hid("bogus close delimiter\n");
-					return -1;
-				}
-				parser->local.delimiter_depth--;
+		if (data) {
+			/*
+			 * We treat items before the first delimiter
+			 * as global to all usage sets (branch 0).
+			 * In the moment we process only these global
+			 * items and the first delimiter set.
+			 */
+			if (parser->local.delimiter_depth != 0) {
+				dbg_hid("nested delimiters\n");
+				return -1;
 			}
-			return 1;
-
-		case HID_LOCAL_ITEM_TAG_USAGE:
-
-			if (parser->local.delimiter_branch > 1) {
-				dbg_hid("alternative usage ignored\n");
-				return 0;
+			parser->local.delimiter_depth++;
+			parser->local.delimiter_branch++;
+		} else {
+			if (parser->local.delimiter_depth < 1) {
+				dbg_hid("bogus close delimiter\n");
+				return -1;
 			}
+			parser->local.delimiter_depth--;
+		}
+		return 1;
 
-			if (item->size <= 2)
-				data = (parser->global.usage_page << 16) + data;
+	case HID_LOCAL_ITEM_TAG_USAGE:
 
-			return hid_add_usage(parser, data);
-
-		case HID_LOCAL_ITEM_TAG_USAGE_MINIMUM:
-
-			if (parser->local.delimiter_branch > 1) {
-				dbg_hid("alternative usage ignored\n");
-				return 0;
-			}
-
-			if (item->size <= 2)
-				data = (parser->global.usage_page << 16) + data;
-
-			parser->local.usage_minimum = data;
+		if (parser->local.delimiter_branch > 1) {
+			dbg_hid("alternative usage ignored\n");
 			return 0;
+		}
 
-		case HID_LOCAL_ITEM_TAG_USAGE_MAXIMUM:
+		if (item->size <= 2)
+			data = (parser->global.usage_page << 16) + data;
 
-			if (parser->local.delimiter_branch > 1) {
-				dbg_hid("alternative usage ignored\n");
-				return 0;
+		return hid_add_usage(parser, data);
+
+	case HID_LOCAL_ITEM_TAG_USAGE_MINIMUM:
+
+		if (parser->local.delimiter_branch > 1) {
+			dbg_hid("alternative usage ignored\n");
+			return 0;
+		}
+
+		if (item->size <= 2)
+			data = (parser->global.usage_page << 16) + data;
+
+		parser->local.usage_minimum = data;
+		return 0;
+
+	case HID_LOCAL_ITEM_TAG_USAGE_MAXIMUM:
+
+		if (parser->local.delimiter_branch > 1) {
+			dbg_hid("alternative usage ignored\n");
+			return 0;
+		}
+
+		if (item->size <= 2)
+			data = (parser->global.usage_page << 16) + data;
+
+		for (n = parser->local.usage_minimum; n <= data; n++)
+			if (hid_add_usage(parser, n)) {
+				dbg_hid("hid_add_usage failed\n");
+				return -1;
 			}
+		return 0;
 
-			if (item->size <= 2)
-				data = (parser->global.usage_page << 16) + data;
+	default:
 
-			for (n = parser->local.usage_minimum; n <= data; n++)
-				if (hid_add_usage(parser, n)) {
-					dbg_hid("hid_add_usage failed\n");
-					return -1;
-				}
-			return 0;
-
-		default:
-
-			dbg_hid("unknown local item tag 0x%x\n", item->tag);
-			return 0;
+		dbg_hid("unknown local item tag 0x%x\n", item->tag);
+		return 0;
 	}
 	return 0;
 }
@@ -480,24 +485,24 @@
 	data = item_udata(item);
 
 	switch (item->tag) {
-		case HID_MAIN_ITEM_TAG_BEGIN_COLLECTION:
-			ret = open_collection(parser, data & 0xff);
-			break;
-		case HID_MAIN_ITEM_TAG_END_COLLECTION:
-			ret = close_collection(parser);
-			break;
-		case HID_MAIN_ITEM_TAG_INPUT:
-			ret = hid_add_field(parser, HID_INPUT_REPORT, data);
-			break;
-		case HID_MAIN_ITEM_TAG_OUTPUT:
-			ret = hid_add_field(parser, HID_OUTPUT_REPORT, data);
-			break;
-		case HID_MAIN_ITEM_TAG_FEATURE:
-			ret = hid_add_field(parser, HID_FEATURE_REPORT, data);
-			break;
-		default:
-			dbg_hid("unknown main item tag 0x%x\n", item->tag);
-			ret = 0;
+	case HID_MAIN_ITEM_TAG_BEGIN_COLLECTION:
+		ret = open_collection(parser, data & 0xff);
+		break;
+	case HID_MAIN_ITEM_TAG_END_COLLECTION:
+		ret = close_collection(parser);
+		break;
+	case HID_MAIN_ITEM_TAG_INPUT:
+		ret = hid_add_field(parser, HID_INPUT_REPORT, data);
+		break;
+	case HID_MAIN_ITEM_TAG_OUTPUT:
+		ret = hid_add_field(parser, HID_OUTPUT_REPORT, data);
+		break;
+	case HID_MAIN_ITEM_TAG_FEATURE:
+		ret = hid_add_field(parser, HID_FEATURE_REPORT, data);
+		break;
+	default:
+		dbg_hid("unknown main item tag 0x%x\n", item->tag);
+		ret = 0;
 	}
 
 	memset(&parser->local, 0, sizeof(parser->local));	/* Reset the local parser environment */
@@ -534,9 +539,10 @@
  * Free a device structure, all reports, and all fields.
  */
 
-void hid_free_device(struct hid_device *device)
+static void hid_device_release(struct device *dev)
 {
-	unsigned i,j;
+	struct hid_device *device = container_of(dev, struct hid_device, dev);
+	unsigned i, j;
 
 	for (i = 0; i < HID_REPORT_TYPES; i++) {
 		struct hid_report_enum *report_enum = device->report_enum + i;
@@ -552,7 +558,6 @@
 	kfree(device->collection);
 	kfree(device);
 }
-EXPORT_SYMBOL_GPL(hid_free_device);
 
 /*
  * Fetch a report description item from the data stream. We support long
@@ -593,47 +598,52 @@
 	item->size = b & 3;
 
 	switch (item->size) {
+	case 0:
+		return start;
 
-		case 0:
-			return start;
+	case 1:
+		if ((end - start) < 1)
+			return NULL;
+		item->data.u8 = *start++;
+		return start;
 
-		case 1:
-			if ((end - start) < 1)
-				return NULL;
-			item->data.u8 = *start++;
-			return start;
+	case 2:
+		if ((end - start) < 2)
+			return NULL;
+		item->data.u16 = get_unaligned_le16(start);
+		start = (__u8 *)((__le16 *)start + 1);
+		return start;
 
-		case 2:
-			if ((end - start) < 2)
-				return NULL;
-			item->data.u16 = get_unaligned_le16(start);
-			start = (__u8 *)((__le16 *)start + 1);
-			return start;
-
-		case 3:
-			item->size++;
-			if ((end - start) < 4)
-				return NULL;
-			item->data.u32 = get_unaligned_le32(start);
-			start = (__u8 *)((__le32 *)start + 1);
-			return start;
+	case 3:
+		item->size++;
+		if ((end - start) < 4)
+			return NULL;
+		item->data.u32 = get_unaligned_le32(start);
+		start = (__u8 *)((__le32 *)start + 1);
+		return start;
 	}
 
 	return NULL;
 }
 
-/*
+/**
+ * hid_parse_report - parse device report
+ *
+ * @device: hid device
+ * @start: report start
+ * @size: report size
+ *
  * Parse a report description into a hid_device structure. Reports are
  * enumerated, fields are attached to these reports.
+ * 0 returned on success, otherwise nonzero error value.
  */
-
-struct hid_device *hid_parse_report(__u8 *start, unsigned size)
+int hid_parse_report(struct hid_device *device, __u8 *start,
+		unsigned size)
 {
-	struct hid_device *device;
 	struct hid_parser *parser;
 	struct hid_item item;
 	__u8 *end;
-	unsigned i;
+	int ret;
 	static int (*dispatch_type[])(struct hid_parser *parser,
 				      struct hid_item *item) = {
 		hid_parser_main,
@@ -642,76 +652,57 @@
 		hid_parser_reserved
 	};
 
-	if (!(device = kzalloc(sizeof(struct hid_device), GFP_KERNEL)))
-		return NULL;
+	if (device->driver->report_fixup)
+		device->driver->report_fixup(device, start, size);
 
-	if (!(device->collection = kzalloc(sizeof(struct hid_collection) *
-				   HID_DEFAULT_NUM_COLLECTIONS, GFP_KERNEL))) {
-		kfree(device);
-		return NULL;
-	}
-	device->collection_size = HID_DEFAULT_NUM_COLLECTIONS;
-
-	for (i = 0; i < HID_REPORT_TYPES; i++)
-		INIT_LIST_HEAD(&device->report_enum[i].report_list);
-
-	if (!(device->rdesc = kmalloc(size, GFP_KERNEL))) {
-		kfree(device->collection);
-		kfree(device);
-		return NULL;
-	}
+	device->rdesc = kmalloc(size, GFP_KERNEL);
+	if (device->rdesc == NULL)
+		return -ENOMEM;
 	memcpy(device->rdesc, start, size);
 	device->rsize = size;
 
-	if (!(parser = vmalloc(sizeof(struct hid_parser)))) {
-		kfree(device->rdesc);
-		kfree(device->collection);
-		kfree(device);
-		return NULL;
+	parser = vmalloc(sizeof(struct hid_parser));
+	if (!parser) {
+		ret = -ENOMEM;
+		goto err;
 	}
+
 	memset(parser, 0, sizeof(struct hid_parser));
 	parser->device = device;
 
 	end = start + size;
+	ret = -EINVAL;
 	while ((start = fetch_item(start, end, &item)) != NULL) {
 
 		if (item.format != HID_ITEM_FORMAT_SHORT) {
 			dbg_hid("unexpected long global item\n");
-			hid_free_device(device);
-			vfree(parser);
-			return NULL;
+			goto err;
 		}
 
 		if (dispatch_type[item.type](parser, &item)) {
 			dbg_hid("item %u %u %u %u parsing failed\n",
 				item.format, (unsigned)item.size, (unsigned)item.type, (unsigned)item.tag);
-			hid_free_device(device);
-			vfree(parser);
-			return NULL;
+			goto err;
 		}
 
 		if (start == end) {
 			if (parser->collection_stack_ptr) {
 				dbg_hid("unbalanced collection at end of report description\n");
-				hid_free_device(device);
-				vfree(parser);
-				return NULL;
+				goto err;
 			}
 			if (parser->local.delimiter_depth) {
 				dbg_hid("unbalanced delimiter at end of report description\n");
-				hid_free_device(device);
-				vfree(parser);
-				return NULL;
+				goto err;
 			}
 			vfree(parser);
-			return device;
+			return 0;
 		}
 	}
 
 	dbg_hid("item fetching failed at offset %d\n", (int)(end - start));
-	hid_free_device(device);
+err:
 	vfree(parser);
-	return NULL;
+	return ret;
 }
 EXPORT_SYMBOL_GPL(hid_parse_report);
 
@@ -724,9 +715,9 @@
 static s32 snto32(__u32 value, unsigned n)
 {
 	switch (n) {
-		case 8:  return ((__s8)value);
-		case 16: return ((__s16)value);
-		case 32: return ((__s32)value);
+	case 8:  return ((__s8)value);
+	case 16: return ((__s16)value);
+	case 32: return ((__s32)value);
 	}
 	return value & (1 << (n - 1)) ? value | (-1 << n) : value;
 }
@@ -815,9 +806,73 @@
 	return -1;
 }
 
-static void hid_process_event(struct hid_device *hid, struct hid_field *field, struct hid_usage *usage, __s32 value, int interrupt)
+/**
+ * hid_match_report - check if driver's raw_event should be called
+ *
+ * @hid: hid device
+ * @report_type: type to match against
+ *
+ * compare hid->driver->report_table->report_type to report->type
+ */
+static int hid_match_report(struct hid_device *hid, struct hid_report *report)
 {
+	const struct hid_report_id *id = hid->driver->report_table;
+
+	if (!id) /* NULL means all */
+		return 1;
+
+	for (; id->report_type != HID_TERMINATOR; id++)
+		if (id->report_type == HID_ANY_ID ||
+				id->report_type == report->type)
+			return 1;
+	return 0;
+}
+
+/**
+ * hid_match_usage - check if driver's event should be called
+ *
+ * @hid: hid device
+ * @usage: usage to match against
+ *
+ * compare hid->driver->usage_table->usage_{type,code} to
+ * usage->usage_{type,code}
+ */
+static int hid_match_usage(struct hid_device *hid, struct hid_usage *usage)
+{
+	const struct hid_usage_id *id = hid->driver->usage_table;
+
+	if (!id) /* NULL means all */
+		return 1;
+
+	for (; id->usage_type != HID_ANY_ID - 1; id++)
+		if ((id->usage_hid == HID_ANY_ID ||
+				id->usage_hid == usage->hid) &&
+				(id->usage_type == HID_ANY_ID ||
+				id->usage_type == usage->type) &&
+				(id->usage_code == HID_ANY_ID ||
+				 id->usage_code == usage->code))
+			return 1;
+	return 0;
+}
+
+static void hid_process_event(struct hid_device *hid, struct hid_field *field,
+		struct hid_usage *usage, __s32 value, int interrupt)
+{
+	struct hid_driver *hdrv = hid->driver;
+	int ret;
+
 	hid_dump_input(usage, value);
+
+	if (hdrv && hdrv->event && hid_match_usage(hid, usage)) {
+		ret = hdrv->event(hid, field, usage, value);
+		if (ret != 0) {
+			if (ret < 0)
+				dbg_hid("%s's event failed with %d\n",
+						hdrv->name, ret);
+			return;
+		}
+	}
+
 	if (hid->claimed & HID_CLAIMED_INPUT)
 		hidinput_hid_event(hid, field, usage, value);
 	if (hid->claimed & HID_CLAIMED_HIDDEV && interrupt && hid->hiddev_hid_event)
@@ -946,44 +1001,47 @@
 }
 EXPORT_SYMBOL_GPL(hid_set_field);
 
-int hid_input_report(struct hid_device *hid, int type, u8 *data, int size, int interrupt)
+static struct hid_report *hid_get_report(struct hid_report_enum *report_enum,
+		const u8 *data)
+{
+	struct hid_report *report;
+	unsigned int n = 0;	/* Normally report number is 0 */
+
+	/* Device uses numbered reports, data[0] is report number */
+	if (report_enum->numbered)
+		n = *data;
+
+	report = report_enum->report_id_hash[n];
+	if (report == NULL)
+		dbg_hid("undefined report_id %u received\n", n);
+
+	return report;
+}
+
+void hid_report_raw_event(struct hid_device *hid, int type, u8 *data, int size,
+		int interrupt)
 {
 	struct hid_report_enum *report_enum = hid->report_enum + type;
 	struct hid_report *report;
-	int n, rsize, i;
+	unsigned int a;
+	int rsize, csize = size;
+	u8 *cdata = data;
 
-	if (!hid)
-		return -ENODEV;
+	report = hid_get_report(report_enum, data);
+	if (!report)
+		return;
 
-	if (!size) {
-		dbg_hid("empty report\n");
-		return -1;
-	}
-
-	dbg_hid("report (size %u) (%snumbered)\n", size, report_enum->numbered ? "" : "un");
-
-	n = 0;                          /* Normally report number is 0 */
-	if (report_enum->numbered) {    /* Device uses numbered reports, data[0] is report number */
-		n = *data++;
-		size--;
-	}
-
-	/* dump the report */
-	dbg_hid("report %d (size %u) = ", n, size);
-	for (i = 0; i < size; i++)
-		dbg_hid_line(" %02x", data[i]);
-	dbg_hid_line("\n");
-
-	if (!(report = report_enum->report_id_hash[n])) {
-		dbg_hid("undefined report_id %d received\n", n);
-		return -1;
+	if (report_enum->numbered) {
+		cdata++;
+		csize--;
 	}
 
 	rsize = ((report->size - 1) >> 3) + 1;
 
-	if (size < rsize) {
-		dbg_hid("report %d is too short, (%d < %d)\n", report->id, size, rsize);
-		memset(data + size, 0, rsize - size);
+	if (csize < rsize) {
+		dbg_hid("report %d is too short, (%d < %d)\n", report->id,
+				csize, rsize);
+		memset(cdata + csize, 0, rsize - csize);
 	}
 
 	if ((hid->claimed & HID_CLAIMED_HIDDEV) && hid->hiddev_report_event)
@@ -996,24 +1054,661 @@
 			hidraw_report_event(hid, data, size);
 	}
 
-	for (n = 0; n < report->maxfield; n++)
-		hid_input_field(hid, report->field[n], data, interrupt);
+	for (a = 0; a < report->maxfield; a++)
+		hid_input_field(hid, report->field[a], cdata, interrupt);
 
 	if (hid->claimed & HID_CLAIMED_INPUT)
 		hidinput_report_event(hid, report);
+}
+EXPORT_SYMBOL_GPL(hid_report_raw_event);
+
+/**
+ * hid_input_report - report data from lower layer (usb, bt...)
+ *
+ * @hid: hid device
+ * @type: HID report type (HID_*_REPORT)
+ * @data: report contents
+ * @size: size of data parameter
+ * @interrupt: called from atomic?
+ *
+ * This is data entry for lower layers.
+ */
+int hid_input_report(struct hid_device *hid, int type, u8 *data, int size, int interrupt)
+{
+	struct hid_report_enum *report_enum = hid->report_enum + type;
+	struct hid_driver *hdrv = hid->driver;
+	struct hid_report *report;
+	unsigned int i;
+	int ret;
+
+	if (!hid || !hid->driver)
+		return -ENODEV;
+
+	if (!size) {
+		dbg_hid("empty report\n");
+		return -1;
+	}
+
+	dbg_hid("report (size %u) (%snumbered)\n", size, report_enum->numbered ? "" : "un");
+
+	report = hid_get_report(report_enum, data);
+	if (!report)
+		return -1;
+
+	/* dump the report */
+	dbg_hid("report %d (size %u) = ", report->id, size);
+	for (i = 0; i < size; i++)
+		dbg_hid_line(" %02x", data[i]);
+	dbg_hid_line("\n");
+
+	if (hdrv && hdrv->raw_event && hid_match_report(hid, report)) {
+		ret = hdrv->raw_event(hid, report, data, size);
+		if (ret != 0)
+			return ret < 0 ? ret : 0;
+	}
+
+	hid_report_raw_event(hid, type, data, size, interrupt);
 
 	return 0;
 }
 EXPORT_SYMBOL_GPL(hid_input_report);
 
+static bool hid_match_one_id(struct hid_device *hdev,
+		const struct hid_device_id *id)
+{
+	return id->bus == hdev->bus &&
+		(id->vendor == HID_ANY_ID || id->vendor == hdev->vendor) &&
+		(id->product == HID_ANY_ID || id->product == hdev->product);
+}
+
+static const struct hid_device_id *hid_match_id(struct hid_device *hdev,
+		const struct hid_device_id *id)
+{
+	for (; id->bus; id++)
+		if (hid_match_one_id(hdev, id))
+			return id;
+
+	return NULL;
+}
+
+static const struct hid_device_id hid_hiddev_list[] = {
+	{ HID_USB_DEVICE(USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS1) },
+	{ }
+};
+
+static bool hid_hiddev(struct hid_device *hdev)
+{
+	return !!hid_match_id(hdev, hid_hiddev_list);
+}
+
+int hid_connect(struct hid_device *hdev, unsigned int connect_mask)
+{
+	static const char *types[] = { "Device", "Pointer", "Mouse", "Device",
+		"Joystick", "Gamepad", "Keyboard", "Keypad",
+		"Multi-Axis Controller"
+	};
+	const char *type, *bus;
+	char buf[64];
+	unsigned int i;
+	int len;
+
+	if (hdev->bus != BUS_USB)
+		connect_mask &= ~HID_CONNECT_HIDDEV;
+	if (hid_hiddev(hdev))
+		connect_mask |= HID_CONNECT_HIDDEV_FORCE;
+
+	if ((connect_mask & HID_CONNECT_HIDINPUT) && !hidinput_connect(hdev,
+				connect_mask & HID_CONNECT_HIDINPUT_FORCE))
+		hdev->claimed |= HID_CLAIMED_INPUT;
+	if ((connect_mask & HID_CONNECT_HIDDEV) && hdev->hiddev_connect &&
+			!hdev->hiddev_connect(hdev,
+				connect_mask & HID_CONNECT_HIDDEV_FORCE))
+		hdev->claimed |= HID_CLAIMED_HIDDEV;
+	if ((connect_mask & HID_CONNECT_HIDRAW) && !hidraw_connect(hdev))
+		hdev->claimed |= HID_CLAIMED_HIDRAW;
+
+	if (!hdev->claimed) {
+		dev_err(&hdev->dev, "claimed by neither input, hiddev nor "
+				"hidraw\n");
+		return -ENODEV;
+	}
+
+	if ((hdev->claimed & HID_CLAIMED_INPUT) &&
+			(connect_mask & HID_CONNECT_FF) && hdev->ff_init)
+		hdev->ff_init(hdev);
+
+	len = 0;
+	if (hdev->claimed & HID_CLAIMED_INPUT)
+		len += sprintf(buf + len, "input");
+	if (hdev->claimed & HID_CLAIMED_HIDDEV)
+		len += sprintf(buf + len, "%shiddev%d", len ? "," : "",
+				hdev->minor);
+	if (hdev->claimed & HID_CLAIMED_HIDRAW)
+		len += sprintf(buf + len, "%shidraw%d", len ? "," : "",
+				((struct hidraw *)hdev->hidraw)->minor);
+
+	type = "Device";
+	for (i = 0; i < hdev->maxcollection; i++) {
+		struct hid_collection *col = &hdev->collection[i];
+		if (col->type == HID_COLLECTION_APPLICATION &&
+		   (col->usage & HID_USAGE_PAGE) == HID_UP_GENDESK &&
+		   (col->usage & 0xffff) < ARRAY_SIZE(types)) {
+			type = types[col->usage & 0xffff];
+			break;
+		}
+	}
+
+	switch (hdev->bus) {
+	case BUS_USB:
+		bus = "USB";
+		break;
+	case BUS_BLUETOOTH:
+		bus = "BLUETOOTH";
+		break;
+	default:
+		bus = "<UNKNOWN>";
+	}
+
+	dev_info(&hdev->dev, "%s: %s HID v%x.%02x %s [%s] on %s\n",
+			buf, bus, hdev->version >> 8, hdev->version & 0xff,
+			type, hdev->name, hdev->phys);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(hid_connect);
+
+static const struct hid_device_id hid_blacklist[] = {
+	{ HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_WCP32PU) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_X5_005D) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ATV_IRCONTROL) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL4) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MIGHTYMOUSE) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ANSI) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ISO) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_ANSI) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_ISO) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_JIS) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_ANSI) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_ISO) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_JIS) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_ANSI) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_ISO) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_JIS) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_ANSI) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_ISO) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_JIS) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_HF_ANSI) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_HF_ISO) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_HF_JIS) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_ANSI) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_ISO) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_JIS) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING_ANSI) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING_ISO) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING_JIS) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING2_ANSI) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING2_ISO) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING2_JIS) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_AVERMEDIA, USB_DEVICE_ID_AVER_FM_MR800) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_BELKIN, USB_DEVICE_ID_FLIP_KVM) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_BRIGHT, USB_DEVICE_ID_BRIGHT_ABNT2) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_CHERRY, USB_DEVICE_ID_CHERRY_CYMOTION) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_TACTICAL_PAD) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_1) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_2) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_MOUSE) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_DELL, USB_DEVICE_ID_DELL_W7658) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_DELL, USB_DEVICE_ID_DELL_SK8115) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_EZKEY, USB_DEVICE_ID_BTC_8193) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_GYRATION, USB_DEVICE_ID_GYRATION_REMOTE) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_LABTEC, USB_DEVICE_ID_LABTEC_WIRELESS_KEYBOARD) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_MX3000_RECEIVER) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER_2) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RECEIVER) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_DESKTOP) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_EDGE) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_MINI) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_KBD) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_ELITE_KBD) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_CORDLESS_DESKTOP_LX500) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_LX3) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_V150) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_EXTREME_3D) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WHEEL) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2_2) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_F3D) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_FORCE3D_PRO) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_SIDEWINDER_GV) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_NE4K) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_LK6K) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_PRESENTER_8K_USB) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_WIRELESS_OPTICAL_DESKTOP_3_0) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_MONTEREY, USB_DEVICE_ID_GENIUS_KB29E) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_PETALYNX, USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_IR_REMOTE) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_SUNPLUS, USB_DEVICE_ID_SUNPLUS_WDESKTOP) },
+
+	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, 0x030c) },
+	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_PRESENTER_8K_BT) },
+	{ }
+};
+
+static int hid_bus_match(struct device *dev, struct device_driver *drv)
+{
+	struct hid_driver *hdrv = container_of(drv, struct hid_driver, driver);
+	struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+
+	if (!hid_match_id(hdev, hdrv->id_table))
+		return 0;
+
+	/* generic wants all non-blacklisted */
+	if (!strncmp(hdrv->name, "generic-", 8))
+		return !hid_match_id(hdev, hid_blacklist);
+
+	return 1;
+}
+
+static int hid_device_probe(struct device *dev)
+{
+	struct hid_driver *hdrv = container_of(dev->driver,
+			struct hid_driver, driver);
+	struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+	const struct hid_device_id *id;
+	int ret = 0;
+
+	if (!hdev->driver) {
+		id = hid_match_id(hdev, hdrv->id_table);
+		if (id == NULL)
+			return -ENODEV;
+
+		hdev->driver = hdrv;
+		if (hdrv->probe) {
+			ret = hdrv->probe(hdev, id);
+		} else { /* default probe */
+			ret = hid_parse(hdev);
+			if (!ret)
+				ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
+		}
+		if (ret)
+			hdev->driver = NULL;
+	}
+	return ret;
+}
+
+static int hid_device_remove(struct device *dev)
+{
+	struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+	struct hid_driver *hdrv = hdev->driver;
+
+	if (hdrv) {
+		if (hdrv->remove)
+			hdrv->remove(hdev);
+		else /* default remove */
+			hid_hw_stop(hdev);
+		hdev->driver = NULL;
+	}
+
+	return 0;
+}
+
+static int hid_uevent(struct device *dev, struct kobj_uevent_env *env)
+{
+	struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+
+	if (add_uevent_var(env, "HID_ID=%04X:%08X:%08X",
+			hdev->bus, hdev->vendor, hdev->product))
+		return -ENOMEM;
+
+	if (add_uevent_var(env, "HID_NAME=%s", hdev->name))
+		return -ENOMEM;
+
+	if (add_uevent_var(env, "HID_PHYS=%s", hdev->phys))
+		return -ENOMEM;
+
+	if (add_uevent_var(env, "HID_UNIQ=%s", hdev->uniq))
+		return -ENOMEM;
+
+	if (add_uevent_var(env, "MODALIAS=hid:b%04Xv%08Xp%08X",
+			hdev->bus, hdev->vendor, hdev->product))
+		return -ENOMEM;
+
+	return 0;
+}
+
+static struct bus_type hid_bus_type = {
+	.name		= "hid",
+	.match		= hid_bus_match,
+	.probe		= hid_device_probe,
+	.remove		= hid_device_remove,
+	.uevent		= hid_uevent,
+};
+
+static const struct hid_device_id hid_ignore_list[] = {
+	{ HID_USB_DEVICE(USB_VENDOR_ID_ACECAD, USB_DEVICE_ID_ACECAD_FLAIR) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_ACECAD, USB_DEVICE_ID_ACECAD_302) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_ADS_TECH, USB_DEVICE_ID_ADS_TECH_RADIO_SI470X) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_01) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_10) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_20) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_21) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_22) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_23) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_24) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_AIRCABLE, USB_DEVICE_ID_AIRCABLE1) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_ALCOR, USB_DEVICE_ID_ALCOR_USBRS232) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_ASUS, USB_DEVICE_ID_ASUS_LCM)},
+	{ HID_USB_DEVICE(USB_VENDOR_ID_BERKSHIRE, USB_DEVICE_ID_BERKSHIRE_PCWD) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_CIDC, 0x0103) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_CYGNAL, USB_DEVICE_ID_CYGNAL_RADIO_SI470X) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_CMEDIA, USB_DEVICE_ID_CM109) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_HIDCOM) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_ULTRAMOUSE) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_DELORME, USB_DEVICE_ID_DELORME_EARTHMATE) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_DELORME, USB_DEVICE_ID_DELORME_EM_LT20) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_ESSENTIAL_REALITY, USB_DEVICE_ID_ESSENTIAL_REALITY_P5) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_GAMERON, USB_DEVICE_ID_GAMERON_DUAL_PSX_ADAPTOR) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, 0x0001) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, 0x0002) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, 0x0003) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, 0x0004) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_GLAB, USB_DEVICE_ID_4_PHIDGETSERVO_30) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_GLAB, USB_DEVICE_ID_1_PHIDGETSERVO_30) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_GLAB, USB_DEVICE_ID_0_0_4_IF_KIT) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_GLAB, USB_DEVICE_ID_0_16_16_IF_KIT) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_GLAB, USB_DEVICE_ID_8_8_8_IF_KIT) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_GLAB, USB_DEVICE_ID_0_8_7_IF_KIT) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_GLAB, USB_DEVICE_ID_0_8_8_IF_KIT) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_GLAB, USB_DEVICE_ID_PHIDGET_MOTORCONTROL) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_GOTOP, USB_DEVICE_ID_SUPER_Q2) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_GOTOP, USB_DEVICE_ID_GOGOPEN) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_GOTOP, USB_DEVICE_ID_PENPOWER) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_GREENASIA, 0x0003) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_GRETAGMACBETH, USB_DEVICE_ID_GRETAGMACBETH_HUEY) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_GRIFFIN, USB_DEVICE_ID_POWERMATE) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_GRIFFIN, USB_DEVICE_ID_SOUNDKNOB) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_90) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_100) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_101) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_103) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_104) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_105) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_106) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_107) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_108) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_200) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_201) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_202) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_203) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_204) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_205) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_206) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_207) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_300) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_301) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_302) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_303) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_304) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_305) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_306) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_307) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_308) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_309) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_400) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_401) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_402) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_403) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_404) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_405) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_500) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_501) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_502) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_503) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_504) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1000) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1001) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1002) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1003) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1004) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1005) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1006) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1007) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_IMATION, USB_DEVICE_ID_DISC_STAKKA) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_KBGEAR, USB_DEVICE_ID_KBGEAR_JAMSTUDIO) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_GPEN_560) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_CASSY) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_POCKETCASSY) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MOBILECASSY) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_JWM) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_DMMP) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_UMIP) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_XRAY1) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_XRAY2) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_VIDEOCOM) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_COM3LAB) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_TELEPORT) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_NETWORKANALYSER) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_POWERCONTROL) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MACHINETEST) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_MCC, USB_DEVICE_ID_MCC_PMD1024LS) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_MCC, USB_DEVICE_ID_MCC_PMD1208LS) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICKIT1) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICKIT2) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_NATIONAL_SEMICONDUCTOR, USB_DEVICE_ID_N_S_HARMONY) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 20) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 30) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 100) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 108) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 118) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 200) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 300) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 400) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 500) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_PANJIT, 0x0001) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_PANJIT, 0x0002) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_PANJIT, 0x0003) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_PANJIT, 0x0004) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_SOUNDGRAPH, USB_DEVICE_ID_SOUNDGRAPH_IMON_LCD) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_TENX, USB_DEVICE_ID_TENX_IBUDDY1) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_TENX, USB_DEVICE_ID_TENX_IBUDDY2) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb300) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb304) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb651) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb654) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_LABPRO) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_GOTEMP) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_SKIP) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_CYCLOPS) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_LCSPEC) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_WACOM, HID_ANY_ID) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_4_PHIDGETSERVO_20) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_1_PHIDGETSERVO_20) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_8_8_4_IF_KIT) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_YEALINK, USB_DEVICE_ID_YEALINK_P1K_P4K_B2K) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_ZEROPLUS, 0x0005) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_ZEROPLUS, 0x0030) },
+	{ }
+};
+
+static bool hid_ignore(struct hid_device *hdev)
+{
+	switch (hdev->vendor) {
+	case USB_VENDOR_ID_CODEMERCS:
+		/* ignore all Code Mercenaries IOWarrior devices */
+		if (hdev->product >= USB_DEVICE_ID_CODEMERCS_IOW_FIRST &&
+				hdev->product <= USB_DEVICE_ID_CODEMERCS_IOW_LAST)
+			return true;
+		break;
+	case USB_VENDOR_ID_LOGITECH:
+		if (hdev->product >= USB_DEVICE_ID_LOGITECH_HARMONY_FIRST &&
+				hdev->product <= USB_DEVICE_ID_LOGITECH_HARMONY_LAST)
+			return true;
+		break;
+	}
+
+	return !!hid_match_id(hdev, hid_ignore_list);
+}
+
+int hid_add_device(struct hid_device *hdev)
+{
+	static atomic_t id = ATOMIC_INIT(0);
+	int ret;
+
+	if (WARN_ON(hdev->status & HID_STAT_ADDED))
+		return -EBUSY;
+
+	/* we need to kill them here, otherwise they will stay allocated to
+	 * wait for coming driver */
+	if (hid_ignore(hdev))
+		return -ENODEV;
+
+	/* XXX hack, any other cleaner solution < 20 bus_id bytes? */
+	sprintf(hdev->dev.bus_id, "%04X:%04X:%04X.%04X", hdev->bus,
+			hdev->vendor, hdev->product, atomic_inc_return(&id));
+
+	ret = device_add(&hdev->dev);
+	if (!ret)
+		hdev->status |= HID_STAT_ADDED;
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(hid_add_device);
+
+/**
+ * hid_allocate_device - allocate new hid device descriptor
+ *
+ * Allocate and initialize hid device, so that hid_destroy_device might be
+ * used to free it.
+ *
+ * New hid_device pointer is returned on success, otherwise ERR_PTR encoded
+ * error value.
+ */
+struct hid_device *hid_allocate_device(void)
+{
+	struct hid_device *hdev;
+	unsigned int i;
+	int ret = -ENOMEM;
+
+	hdev = kzalloc(sizeof(*hdev), GFP_KERNEL);
+	if (hdev == NULL)
+		return ERR_PTR(ret);
+
+	device_initialize(&hdev->dev);
+	hdev->dev.release = hid_device_release;
+	hdev->dev.bus = &hid_bus_type;
+
+	hdev->collection = kcalloc(HID_DEFAULT_NUM_COLLECTIONS,
+			sizeof(struct hid_collection), GFP_KERNEL);
+	if (hdev->collection == NULL)
+		goto err;
+	hdev->collection_size = HID_DEFAULT_NUM_COLLECTIONS;
+
+	for (i = 0; i < HID_REPORT_TYPES; i++)
+		INIT_LIST_HEAD(&hdev->report_enum[i].report_list);
+
+	return hdev;
+err:
+	put_device(&hdev->dev);
+	return ERR_PTR(ret);
+}
+EXPORT_SYMBOL_GPL(hid_allocate_device);
+
+static void hid_remove_device(struct hid_device *hdev)
+{
+	if (hdev->status & HID_STAT_ADDED) {
+		device_del(&hdev->dev);
+		hdev->status &= ~HID_STAT_ADDED;
+	}
+}
+
+/**
+ * hid_destroy_device - free previously allocated device
+ *
+ * @hdev: hid device
+ *
+ * If you allocate hid_device through hid_allocate_device, you should ever
+ * free by this function.
+ */
+void hid_destroy_device(struct hid_device *hdev)
+{
+	hid_remove_device(hdev);
+	put_device(&hdev->dev);
+}
+EXPORT_SYMBOL_GPL(hid_destroy_device);
+
+int __hid_register_driver(struct hid_driver *hdrv, struct module *owner,
+		const char *mod_name)
+{
+	hdrv->driver.name = hdrv->name;
+	hdrv->driver.bus = &hid_bus_type;
+	hdrv->driver.owner = owner;
+	hdrv->driver.mod_name = mod_name;
+
+	return driver_register(&hdrv->driver);
+}
+EXPORT_SYMBOL_GPL(__hid_register_driver);
+
+void hid_unregister_driver(struct hid_driver *hdrv)
+{
+	driver_unregister(&hdrv->driver);
+}
+EXPORT_SYMBOL_GPL(hid_unregister_driver);
+
+#ifdef CONFIG_HID_COMPAT
+static void hid_compat_load(struct work_struct *ws)
+{
+	request_module("hid-dummy");
+}
+static DECLARE_WORK(hid_compat_work, hid_compat_load);
+static struct workqueue_struct *hid_compat_wq;
+#endif
+
 static int __init hid_init(void)
 {
-	return hidraw_init();
+	int ret;
+
+	ret = bus_register(&hid_bus_type);
+	if (ret) {
+		printk(KERN_ERR "HID: can't register hid bus\n");
+		goto err;
+	}
+
+	ret = hidraw_init();
+	if (ret)
+		goto err_bus;
+
+#ifdef CONFIG_HID_COMPAT
+	hid_compat_wq = create_workqueue("hid_compat");
+	if (!hid_compat_wq) {
+		hidraw_exit();
+		goto err;
+	}
+	queue_work(hid_compat_wq, &hid_compat_work);
+#endif
+
+	return 0;
+err_bus:
+	bus_unregister(&hid_bus_type);
+err:
+	return ret;
 }
 
 static void __exit hid_exit(void)
 {
+#ifdef CONFIG_HID_COMPAT
+	destroy_workqueue(hid_compat_wq);
+#endif
 	hidraw_exit();
+	bus_unregister(&hid_bus_type);
 }
 
 module_init(hid_init);
diff --git a/drivers/hid/hid-cypress.c b/drivers/hid/hid-cypress.c
new file mode 100644
index 0000000..5d69d27
--- /dev/null
+++ b/drivers/hid/hid-cypress.c
@@ -0,0 +1,158 @@
+/*
+ *  HID driver for some cypress "special" devices
+ *
+ *  Copyright (c) 1999 Andreas Gal
+ *  Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
+ *  Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
+ *  Copyright (c) 2006-2007 Jiri Kosina
+ *  Copyright (c) 2007 Paul Walmsley
+ *  Copyright (c) 2008 Jiri Slaby
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or 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/device.h>
+#include <linux/hid.h>
+#include <linux/input.h>
+#include <linux/module.h>
+
+#include "hid-ids.h"
+
+#define CP_RDESC_SWAPPED_MIN_MAX	0x01
+#define CP_2WHEEL_MOUSE_HACK		0x02
+#define CP_2WHEEL_MOUSE_HACK_ON		0x04
+
+/*
+ * Some USB barcode readers from cypress have usage min and usage max in
+ * the wrong order
+ */
+static void cp_report_fixup(struct hid_device *hdev, __u8 *rdesc,
+		unsigned int rsize)
+{
+	unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
+	unsigned int i;
+
+	if (!(quirks & CP_RDESC_SWAPPED_MIN_MAX))
+		return;
+
+	for (i = 0; i < rsize - 4; i++)
+		if (rdesc[i] == 0x29 && rdesc[i + 2] == 0x19) {
+			__u8 tmp;
+
+			rdesc[i] = 0x19;
+			rdesc[i + 2] = 0x29;
+			tmp = rdesc[i + 3];
+			rdesc[i + 3] = rdesc[i + 1];
+			rdesc[i + 1] = tmp;
+		}
+}
+
+static int cp_input_mapped(struct hid_device *hdev, struct hid_input *hi,
+		struct hid_field *field, struct hid_usage *usage,
+		unsigned long **bit, int *max)
+{
+	unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
+
+	if (!(quirks & CP_2WHEEL_MOUSE_HACK))
+		return 0;
+
+	if (usage->type == EV_REL && usage->code == REL_WHEEL)
+		set_bit(REL_HWHEEL, *bit);
+	if (usage->hid == 0x00090005)
+		return -1;
+
+	return 0;
+}
+
+static int cp_event(struct hid_device *hdev, struct hid_field *field,
+		struct hid_usage *usage, __s32 value)
+{
+	unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
+
+	if (!(hdev->claimed & HID_CLAIMED_INPUT) || !field->hidinput ||
+			!usage->type || !(quirks & CP_2WHEEL_MOUSE_HACK))
+		return 0;
+
+	if (usage->hid == 0x00090005) {
+		if (value)
+			quirks |=  CP_2WHEEL_MOUSE_HACK_ON;
+		else
+			quirks &= ~CP_2WHEEL_MOUSE_HACK_ON;
+		hid_set_drvdata(hdev, (void *)quirks);
+		return 1;
+	}
+
+	if (usage->code == REL_WHEEL && (quirks & CP_2WHEEL_MOUSE_HACK_ON)) {
+		struct input_dev *input = field->hidinput->input;
+
+		input_event(input, usage->type, REL_HWHEEL, value);
+		return 1;
+	}
+
+	return 0;
+}
+
+static int cp_probe(struct hid_device *hdev, const struct hid_device_id *id)
+{
+	unsigned long quirks = id->driver_data;
+	int ret;
+
+	hid_set_drvdata(hdev, (void *)quirks);
+
+	ret = hid_parse(hdev);
+	if (ret) {
+		dev_err(&hdev->dev, "parse failed\n");
+		goto err_free;
+	}
+
+	ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
+	if (ret) {
+		dev_err(&hdev->dev, "hw start failed\n");
+		goto err_free;
+	}
+
+	return 0;
+err_free:
+	return ret;
+}
+
+static const struct hid_device_id cp_devices[] = {
+	{ HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_1),
+		.driver_data = CP_RDESC_SWAPPED_MIN_MAX },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_2),
+		.driver_data = CP_RDESC_SWAPPED_MIN_MAX },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_MOUSE),
+		.driver_data = CP_2WHEEL_MOUSE_HACK },
+	{ }
+};
+MODULE_DEVICE_TABLE(hid, cp_devices);
+
+static struct hid_driver cp_driver = {
+	.name = "cypress",
+	.id_table = cp_devices,
+	.report_fixup = cp_report_fixup,
+	.input_mapped = cp_input_mapped,
+	.event = cp_event,
+	.probe = cp_probe,
+};
+
+static int cp_init(void)
+{
+	return hid_register_driver(&cp_driver);
+}
+
+static void cp_exit(void)
+{
+	hid_unregister_driver(&cp_driver);
+}
+
+module_init(cp_init);
+module_exit(cp_exit);
+MODULE_LICENSE("GPL");
+
+HID_COMPAT_LOAD_DRIVER(cypress);
diff --git a/drivers/hid/hid-dell.c b/drivers/hid/hid-dell.c
new file mode 100644
index 0000000..1a0d0df
--- /dev/null
+++ b/drivers/hid/hid-dell.c
@@ -0,0 +1,75 @@
+/*
+ *  HID driver for some dell "special" devices
+ *
+ *  Copyright (c) 1999 Andreas Gal
+ *  Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
+ *  Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
+ *  Copyright (c) 2006-2007 Jiri Kosina
+ *  Copyright (c) 2007 Paul Walmsley
+ *  Copyright (c) 2008 Jiri Slaby
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or 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/device.h>
+#include <linux/hid.h>
+#include <linux/module.h>
+
+#include "hid-ids.h"
+
+static int dell_probe(struct hid_device *hdev, const struct hid_device_id *id)
+{
+	int ret;
+
+	ret = hid_parse(hdev);
+	if (ret) {
+		dev_err(&hdev->dev, "parse failed\n");
+		goto err_free;
+	}
+
+	ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
+	if (ret) {
+		dev_err(&hdev->dev, "hw start failed\n");
+		goto err_free;
+	}
+
+	usbhid_set_leds(hdev);
+
+	return 0;
+err_free:
+	return ret;
+}
+
+static const struct hid_device_id dell_devices[] = {
+	{ HID_USB_DEVICE(USB_VENDOR_ID_DELL, USB_DEVICE_ID_DELL_W7658) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_DELL, USB_DEVICE_ID_DELL_SK8115) },
+	{ }
+};
+MODULE_DEVICE_TABLE(hid, dell_devices);
+
+static struct hid_driver dell_driver = {
+	.name = "dell",
+	.id_table = dell_devices,
+	.probe = dell_probe,
+};
+
+static int dell_init(void)
+{
+	return hid_register_driver(&dell_driver);
+}
+
+static void dell_exit(void)
+{
+	hid_unregister_driver(&dell_driver);
+}
+
+module_init(dell_init);
+module_exit(dell_exit);
+MODULE_LICENSE("GPL");
+
+HID_COMPAT_LOAD_DRIVER(dell);
diff --git a/drivers/hid/hid-dummy.c b/drivers/hid/hid-dummy.c
new file mode 100644
index 0000000..e148f86
--- /dev/null
+++ b/drivers/hid/hid-dummy.c
@@ -0,0 +1,72 @@
+#include <linux/autoconf.h>
+#include <linux/module.h>
+#include <linux/hid.h>
+
+static int __init hid_dummy_init(void)
+{
+#ifdef CONFIG_HID_A4TECH_MODULE
+	HID_COMPAT_CALL_DRIVER(a4tech);
+#endif
+#ifdef CONFIG_HID_APPLE_MODULE
+	HID_COMPAT_CALL_DRIVER(apple);
+#endif
+#ifdef CONFIG_HID_BELKIN_MODULE
+	HID_COMPAT_CALL_DRIVER(belkin);
+#endif
+#ifdef CONFIG_HID_BRIGHT_MODULE
+	HID_COMPAT_CALL_DRIVER(bright);
+#endif
+#ifdef CONFIG_HID_CHERRY_MODULE
+	HID_COMPAT_CALL_DRIVER(cherry);
+#endif
+#ifdef CONFIG_HID_CHICONY_MODULE
+	HID_COMPAT_CALL_DRIVER(chicony);
+#endif
+#ifdef CONFIG_HID_CYPRESS_MODULE
+	HID_COMPAT_CALL_DRIVER(cypress);
+#endif
+#ifdef CONFIG_HID_DELL_MODULE
+	HID_COMPAT_CALL_DRIVER(dell);
+#endif
+#ifdef CONFIG_HID_EZKEY_MODULE
+	HID_COMPAT_CALL_DRIVER(ezkey);
+#endif
+#ifdef CONFIG_HID_GYRATION_MODULE
+	HID_COMPAT_CALL_DRIVER(gyration);
+#endif
+#ifdef CONFIG_HID_LOGITECH_MODULE
+	HID_COMPAT_CALL_DRIVER(logitech);
+#endif
+#ifdef CONFIG_HID_MICROSOFT_MODULE
+	HID_COMPAT_CALL_DRIVER(microsoft);
+#endif
+#ifdef CONFIG_HID_MONTEREY_MODULE
+	HID_COMPAT_CALL_DRIVER(monterey);
+#endif
+#ifdef CONFIG_HID_PANTHERLORD_MODULE
+	HID_COMPAT_CALL_DRIVER(pantherlord);
+#endif
+#ifdef CONFIG_HID_PETALYNX_MODULE
+	HID_COMPAT_CALL_DRIVER(petalynx);
+#endif
+#ifdef CONFIG_HID_SAMSUNG_MODULE
+	HID_COMPAT_CALL_DRIVER(samsung);
+#endif
+#ifdef CONFIG_HID_SONY_MODULE
+	HID_COMPAT_CALL_DRIVER(sony);
+#endif
+#ifdef CONFIG_HID_SUNPLUS_MODULE
+	HID_COMPAT_CALL_DRIVER(sunplus);
+#endif
+#ifdef CONFIG_THRUSTMASTER_FF_MODULE
+	HID_COMPAT_CALL_DRIVER(thrustmaster);
+#endif
+#ifdef CONFIG_ZEROPLUS_FF_MODULE
+	HID_COMPAT_CALL_DRIVER(zeroplus);
+#endif
+
+	return -EIO;
+}
+module_init(hid_dummy_init);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/hid/hid-ezkey.c b/drivers/hid/hid-ezkey.c
new file mode 100644
index 0000000..deb42f9
--- /dev/null
+++ b/drivers/hid/hid-ezkey.c
@@ -0,0 +1,95 @@
+/*
+ *  HID driver for some ezkey "special" devices
+ *
+ *  Copyright (c) 1999 Andreas Gal
+ *  Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
+ *  Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
+ *  Copyright (c) 2006-2007 Jiri Kosina
+ *  Copyright (c) 2007 Paul Walmsley
+ *  Copyright (c) 2008 Jiri Slaby
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or 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/device.h>
+#include <linux/input.h>
+#include <linux/hid.h>
+#include <linux/module.h>
+
+#include "hid-ids.h"
+
+#define ez_map_rel(c)	hid_map_usage(hi, usage, bit, max, EV_REL, (c))
+#define ez_map_key(c)	hid_map_usage(hi, usage, bit, max, EV_KEY, (c))
+
+static int ez_input_mapping(struct hid_device *hdev, struct hid_input *hi,
+		struct hid_field *field, struct hid_usage *usage,
+		unsigned long **bit, int *max)
+{
+	if ((usage->hid & HID_USAGE_PAGE) != HID_UP_CONSUMER)
+		return 0;
+
+	switch (usage->hid & HID_USAGE) {
+	case 0x230: ez_map_key(BTN_MOUSE);	break;
+	case 0x231: ez_map_rel(REL_WHEEL);	break;
+	/*
+	 * this keyboard has a scrollwheel implemented in
+	 * totally broken way. We map this usage temporarily
+	 * to HWHEEL and handle it in the event quirk handler
+	 */
+	case 0x232: ez_map_rel(REL_HWHEEL);	break;
+	default:
+		return 0;
+	}
+	return 1;
+}
+
+static int ez_event(struct hid_device *hdev, struct hid_field *field,
+		struct hid_usage *usage, __s32 value)
+{
+	if (!(hdev->claimed & HID_CLAIMED_INPUT) || !field->hidinput ||
+			!usage->type)
+		return 0;
+
+	/* handle the temporary quirky mapping to HWHEEL */
+	if (usage->type == EV_REL && usage->code == REL_HWHEEL) {
+		struct input_dev *input = field->hidinput->input;
+		input_event(input, usage->type, REL_WHEEL, -value);
+		return 1;
+	}
+
+	return 0;
+}
+
+static const struct hid_device_id ez_devices[] = {
+	{ HID_USB_DEVICE(USB_VENDOR_ID_EZKEY, USB_DEVICE_ID_BTC_8193) },
+	{ }
+};
+MODULE_DEVICE_TABLE(hid, ez_devices);
+
+static struct hid_driver ez_driver = {
+	.name = "ezkey",
+	.id_table = ez_devices,
+	.input_mapping = ez_input_mapping,
+	.event = ez_event,
+};
+
+static int ez_init(void)
+{
+	return hid_register_driver(&ez_driver);
+}
+
+static void ez_exit(void)
+{
+	hid_unregister_driver(&ez_driver);
+}
+
+module_init(ez_init);
+module_exit(ez_exit);
+MODULE_LICENSE("GPL");
+
+HID_COMPAT_LOAD_DRIVER(ezkey);
diff --git a/drivers/hid/hid-gyration.c b/drivers/hid/hid-gyration.c
new file mode 100644
index 0000000..ac5120f
--- /dev/null
+++ b/drivers/hid/hid-gyration.c
@@ -0,0 +1,96 @@
+/*
+ *  HID driver for some gyration "special" devices
+ *
+ *  Copyright (c) 1999 Andreas Gal
+ *  Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
+ *  Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
+ *  Copyright (c) 2006-2007 Jiri Kosina
+ *  Copyright (c) 2007 Paul Walmsley
+ *  Copyright (c) 2008 Jiri Slaby
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or 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/device.h>
+#include <linux/input.h>
+#include <linux/hid.h>
+#include <linux/module.h>
+
+#include "hid-ids.h"
+
+#define gy_map_key_clear(c)	hid_map_usage_clear(hi, usage, bit, max, \
+					EV_KEY, (c))
+static int gyration_input_mapping(struct hid_device *hdev, struct hid_input *hi,
+		struct hid_field *field, struct hid_usage *usage,
+		unsigned long **bit, int *max)
+{
+	if ((usage->hid & HID_USAGE_PAGE) != HID_UP_LOGIVENDOR)
+		return 0;
+
+	set_bit(EV_REP, hi->input->evbit);
+	switch (usage->hid & HID_USAGE) {
+	/* Reported on Gyration MCE Remote */
+	case 0x00d: gy_map_key_clear(KEY_HOME);		break;
+	case 0x024: gy_map_key_clear(KEY_DVD);		break;
+	case 0x025: gy_map_key_clear(KEY_PVR);		break;
+	case 0x046: gy_map_key_clear(KEY_MEDIA);	break;
+	case 0x047: gy_map_key_clear(KEY_MP3);		break;
+	case 0x049: gy_map_key_clear(KEY_CAMERA);	break;
+	case 0x04a: gy_map_key_clear(KEY_VIDEO);	break;
+
+	default:
+		return 0;
+	}
+	return 1;
+}
+
+static int gyration_event(struct hid_device *hdev, struct hid_field *field,
+		struct hid_usage *usage, __s32 value)
+{
+	struct input_dev *input = field->hidinput->input;
+
+	if ((usage->hid & HID_USAGE_PAGE) == HID_UP_GENDESK &&
+			(usage->hid & 0xff) == 0x82) {
+		input_event(input, usage->type, usage->code, 1);
+		input_sync(input);
+		input_event(input, usage->type, usage->code, 0);
+		input_sync(input);
+		return 1;
+	}
+
+	return 0;
+}
+
+static const struct hid_device_id gyration_devices[] = {
+	{ HID_USB_DEVICE(USB_VENDOR_ID_GYRATION, USB_DEVICE_ID_GYRATION_REMOTE) },
+	{ }
+};
+MODULE_DEVICE_TABLE(hid, gyration_devices);
+
+static struct hid_driver gyration_driver = {
+	.name = "gyration",
+	.id_table = gyration_devices,
+	.input_mapping = gyration_input_mapping,
+	.event = gyration_event,
+};
+
+static int gyration_init(void)
+{
+	return hid_register_driver(&gyration_driver);
+}
+
+static void gyration_exit(void)
+{
+	hid_unregister_driver(&gyration_driver);
+}
+
+module_init(gyration_init);
+module_exit(gyration_exit);
+MODULE_LICENSE("GPL");
+
+HID_COMPAT_LOAD_DRIVER(gyration);
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
new file mode 100644
index 0000000..aad9ed1
--- /dev/null
+++ b/drivers/hid/hid-ids.h
@@ -0,0 +1,404 @@
+/*
+ *  USB HID quirks support for Linux
+ *
+ *  Copyright (c) 1999 Andreas Gal
+ *  Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
+ *  Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
+ *  Copyright (c) 2006-2007 Jiri Kosina
+ *  Copyright (c) 2007 Paul Walmsley
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or 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 HID_IDS_H_FILE
+#define HID_IDS_H_FILE
+
+#define USB_VENDOR_ID_A4TECH		0x09da
+#define USB_DEVICE_ID_A4TECH_WCP32PU	0x0006
+#define USB_DEVICE_ID_A4TECH_X5_005D	0x000a
+
+#define USB_VENDOR_ID_AASHIMA		0x06d6
+#define USB_DEVICE_ID_AASHIMA_GAMEPAD	0x0025
+#define USB_DEVICE_ID_AASHIMA_PREDATOR	0x0026
+
+#define USB_VENDOR_ID_ACECAD		0x0460
+#define USB_DEVICE_ID_ACECAD_FLAIR	0x0004
+#define USB_DEVICE_ID_ACECAD_302	0x0008
+
+#define USB_VENDOR_ID_ADS_TECH 		0x06e1
+#define USB_DEVICE_ID_ADS_TECH_RADIO_SI470X	0xa155
+
+#define USB_VENDOR_ID_AFATECH		0x15a4
+#define USB_DEVICE_ID_AFATECH_AF9016	0x9016
+
+#define USB_VENDOR_ID_AIPTEK		0x08ca
+#define USB_DEVICE_ID_AIPTEK_01		0x0001
+#define USB_DEVICE_ID_AIPTEK_10		0x0010
+#define USB_DEVICE_ID_AIPTEK_20		0x0020
+#define USB_DEVICE_ID_AIPTEK_21		0x0021
+#define USB_DEVICE_ID_AIPTEK_22		0x0022
+#define USB_DEVICE_ID_AIPTEK_23		0x0023
+#define USB_DEVICE_ID_AIPTEK_24		0x0024
+
+#define USB_VENDOR_ID_AIRCABLE		0x16CA
+#define USB_DEVICE_ID_AIRCABLE1		0x1502
+
+#define USB_VENDOR_ID_ALCOR		0x058f
+#define USB_DEVICE_ID_ALCOR_USBRS232	0x9720
+
+#define USB_VENDOR_ID_ALPS		0x0433
+#define USB_DEVICE_ID_IBM_GAMEPAD	0x1101
+
+#define USB_VENDOR_ID_APPLE		0x05ac
+#define USB_DEVICE_ID_APPLE_MIGHTYMOUSE	0x0304
+#define USB_DEVICE_ID_APPLE_FOUNTAIN_ANSI	0x020e
+#define USB_DEVICE_ID_APPLE_FOUNTAIN_ISO	0x020f
+#define USB_DEVICE_ID_APPLE_GEYSER_ANSI	0x0214
+#define USB_DEVICE_ID_APPLE_GEYSER_ISO	0x0215
+#define USB_DEVICE_ID_APPLE_GEYSER_JIS	0x0216
+#define USB_DEVICE_ID_APPLE_GEYSER3_ANSI	0x0217
+#define USB_DEVICE_ID_APPLE_GEYSER3_ISO	0x0218
+#define USB_DEVICE_ID_APPLE_GEYSER3_JIS	0x0219
+#define USB_DEVICE_ID_APPLE_GEYSER4_ANSI	0x021a
+#define USB_DEVICE_ID_APPLE_GEYSER4_ISO	0x021b
+#define USB_DEVICE_ID_APPLE_GEYSER4_JIS	0x021c
+#define USB_DEVICE_ID_APPLE_ALU_ANSI	0x0220
+#define USB_DEVICE_ID_APPLE_ALU_ISO	0x0221
+#define USB_DEVICE_ID_APPLE_ALU_JIS	0x0222
+#define USB_DEVICE_ID_APPLE_WELLSPRING_ANSI	0x0223
+#define USB_DEVICE_ID_APPLE_WELLSPRING_ISO	0x0224
+#define USB_DEVICE_ID_APPLE_WELLSPRING_JIS	0x0225
+#define USB_DEVICE_ID_APPLE_GEYSER4_HF_ANSI    0x0229
+#define USB_DEVICE_ID_APPLE_GEYSER4_HF_ISO     0x022a
+#define USB_DEVICE_ID_APPLE_GEYSER4_HF_JIS     0x022b
+#define USB_DEVICE_ID_APPLE_ALU_WIRELESS_ANSI  0x022c
+#define USB_DEVICE_ID_APPLE_ALU_WIRELESS_ISO   0x022d
+#define USB_DEVICE_ID_APPLE_ALU_WIRELESS_JIS   0x022e
+#define USB_DEVICE_ID_APPLE_WELLSPRING2_ANSI	0x0230
+#define USB_DEVICE_ID_APPLE_WELLSPRING2_ISO	0x0231
+#define USB_DEVICE_ID_APPLE_WELLSPRING2_JIS	0x0232
+#define USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY	0x030a
+#define USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY	0x030b
+#define USB_DEVICE_ID_APPLE_ATV_IRCONTROL	0x8241
+#define USB_DEVICE_ID_APPLE_IRCONTROL4	0x8242
+
+#define USB_VENDOR_ID_ASUS		0x0b05
+#define USB_DEVICE_ID_ASUS_LCM		0x1726
+
+#define USB_VENDOR_ID_ATEN		0x0557
+#define USB_DEVICE_ID_ATEN_UC100KM	0x2004
+#define USB_DEVICE_ID_ATEN_CS124U	0x2202
+#define USB_DEVICE_ID_ATEN_2PORTKVM	0x2204
+#define USB_DEVICE_ID_ATEN_4PORTKVM	0x2205
+#define USB_DEVICE_ID_ATEN_4PORTKVMC	0x2208
+
+#define USB_VENDOR_ID_AVERMEDIA		0x07ca
+#define USB_DEVICE_ID_AVER_FM_MR800	0xb800
+
+#define USB_VENDOR_ID_BELKIN           0x050d
+#define USB_DEVICE_ID_FLIP_KVM         0x3201
+
+#define USB_VENDOR_ID_BRIGHT		0x1241
+#define USB_DEVICE_ID_BRIGHT_ABNT2	0x1503
+
+#define USB_VENDOR_ID_BERKSHIRE		0x0c98
+#define USB_DEVICE_ID_BERKSHIRE_PCWD	0x1140
+
+#define USB_VENDOR_ID_CHERRY		0x046a
+#define USB_DEVICE_ID_CHERRY_CYMOTION	0x0023
+
+#define USB_VENDOR_ID_CHIC		0x05fe
+#define USB_DEVICE_ID_CHIC_GAMEPAD	0x0014
+
+#define USB_VENDOR_ID_CHICONY		0x04f2
+#define USB_DEVICE_ID_CHICONY_TACTICAL_PAD	0x0418
+
+#define USB_VENDOR_ID_CIDC		0x1677
+
+#define USB_VENDOR_ID_CMEDIA		0x0d8c
+#define USB_DEVICE_ID_CM109		0x000e
+
+#define USB_VENDOR_ID_CODEMERCS		0x07c0
+#define USB_DEVICE_ID_CODEMERCS_IOW_FIRST	0x1500
+#define USB_DEVICE_ID_CODEMERCS_IOW_LAST	0x15ff
+
+#define USB_VENDOR_ID_CYGNAL		0x10c4
+#define USB_DEVICE_ID_CYGNAL_RADIO_SI470X	0x818a
+
+#define USB_VENDOR_ID_CYPRESS		0x04b4
+#define USB_DEVICE_ID_CYPRESS_MOUSE	0x0001
+#define USB_DEVICE_ID_CYPRESS_HIDCOM	0x5500
+#define USB_DEVICE_ID_CYPRESS_ULTRAMOUSE	0x7417
+#define USB_DEVICE_ID_CYPRESS_BARCODE_1	0xde61
+#define USB_DEVICE_ID_CYPRESS_BARCODE_2	0xde64
+
+#define USB_VENDOR_ID_DELL		0x413c
+#define USB_DEVICE_ID_DELL_W7658	0x2005
+#define USB_DEVICE_ID_DELL_SK8115	0x2105
+
+#define USB_VENDOR_ID_DELORME		0x1163
+#define USB_DEVICE_ID_DELORME_EARTHMATE 0x0100
+#define USB_DEVICE_ID_DELORME_EM_LT20	0x0200
+
+#define USB_VENDOR_ID_DMI		0x0c0b
+#define USB_DEVICE_ID_DMI_ENC		0x5fab
+
+#define USB_VENDOR_ID_ELO		0x04E7
+#define USB_DEVICE_ID_ELO_TS2700	0x0020
+
+#define USB_VENDOR_ID_ESSENTIAL_REALITY	0x0d7f
+#define USB_DEVICE_ID_ESSENTIAL_REALITY_P5 0x0100
+
+#define USB_VENDOR_ID_EZKEY 		0x0518
+#define USB_DEVICE_ID_BTC_8193		0x0002
+
+#define USB_VENDOR_ID_GAMERON		0x0810
+#define USB_DEVICE_ID_GAMERON_DUAL_PSX_ADAPTOR	0x0001
+
+#define USB_VENDOR_ID_GENERAL_TOUCH	0x0dfc
+
+#define USB_VENDOR_ID_GLAB		0x06c2
+#define USB_DEVICE_ID_4_PHIDGETSERVO_30	0x0038
+#define USB_DEVICE_ID_1_PHIDGETSERVO_30	0x0039
+#define USB_DEVICE_ID_0_0_4_IF_KIT	0x0040
+#define USB_DEVICE_ID_0_16_16_IF_KIT	0x0044
+#define USB_DEVICE_ID_8_8_8_IF_KIT	0x0045
+#define USB_DEVICE_ID_0_8_7_IF_KIT	0x0051
+#define USB_DEVICE_ID_0_8_8_IF_KIT	0x0053
+#define USB_DEVICE_ID_PHIDGET_MOTORCONTROL	0x0058
+
+#define USB_VENDOR_ID_GOTOP		0x08f2
+#define USB_DEVICE_ID_SUPER_Q2		0x007f
+#define USB_DEVICE_ID_GOGOPEN		0x00ce
+#define USB_DEVICE_ID_PENPOWER		0x00f4
+
+#define USB_VENDOR_ID_GREENASIA		0x0e8f
+
+#define USB_VENDOR_ID_GRETAGMACBETH	0x0971
+#define USB_DEVICE_ID_GRETAGMACBETH_HUEY	0x2005
+
+#define USB_VENDOR_ID_GRIFFIN		0x077d
+#define USB_DEVICE_ID_POWERMATE		0x0410
+#define USB_DEVICE_ID_SOUNDKNOB		0x04AA
+
+#define USB_VENDOR_ID_GTCO		0x078c
+#define USB_DEVICE_ID_GTCO_90		0x0090
+#define USB_DEVICE_ID_GTCO_100		0x0100
+#define USB_DEVICE_ID_GTCO_101		0x0101
+#define USB_DEVICE_ID_GTCO_103		0x0103
+#define USB_DEVICE_ID_GTCO_104		0x0104
+#define USB_DEVICE_ID_GTCO_105		0x0105
+#define USB_DEVICE_ID_GTCO_106		0x0106
+#define USB_DEVICE_ID_GTCO_107		0x0107
+#define USB_DEVICE_ID_GTCO_108		0x0108
+#define USB_DEVICE_ID_GTCO_200		0x0200
+#define USB_DEVICE_ID_GTCO_201		0x0201
+#define USB_DEVICE_ID_GTCO_202		0x0202
+#define USB_DEVICE_ID_GTCO_203		0x0203
+#define USB_DEVICE_ID_GTCO_204		0x0204
+#define USB_DEVICE_ID_GTCO_205		0x0205
+#define USB_DEVICE_ID_GTCO_206		0x0206
+#define USB_DEVICE_ID_GTCO_207		0x0207
+#define USB_DEVICE_ID_GTCO_300		0x0300
+#define USB_DEVICE_ID_GTCO_301		0x0301
+#define USB_DEVICE_ID_GTCO_302		0x0302
+#define USB_DEVICE_ID_GTCO_303		0x0303
+#define USB_DEVICE_ID_GTCO_304		0x0304
+#define USB_DEVICE_ID_GTCO_305		0x0305
+#define USB_DEVICE_ID_GTCO_306		0x0306
+#define USB_DEVICE_ID_GTCO_307		0x0307
+#define USB_DEVICE_ID_GTCO_308		0x0308
+#define USB_DEVICE_ID_GTCO_309		0x0309
+#define USB_DEVICE_ID_GTCO_400		0x0400
+#define USB_DEVICE_ID_GTCO_401		0x0401
+#define USB_DEVICE_ID_GTCO_402		0x0402
+#define USB_DEVICE_ID_GTCO_403		0x0403
+#define USB_DEVICE_ID_GTCO_404		0x0404
+#define USB_DEVICE_ID_GTCO_405		0x0405
+#define USB_DEVICE_ID_GTCO_500		0x0500
+#define USB_DEVICE_ID_GTCO_501		0x0501
+#define USB_DEVICE_ID_GTCO_502		0x0502
+#define USB_DEVICE_ID_GTCO_503		0x0503
+#define USB_DEVICE_ID_GTCO_504		0x0504
+#define USB_DEVICE_ID_GTCO_1000		0x1000
+#define USB_DEVICE_ID_GTCO_1001		0x1001
+#define USB_DEVICE_ID_GTCO_1002		0x1002
+#define USB_DEVICE_ID_GTCO_1003		0x1003
+#define USB_DEVICE_ID_GTCO_1004		0x1004
+#define USB_DEVICE_ID_GTCO_1005		0x1005
+#define USB_DEVICE_ID_GTCO_1006		0x1006
+#define USB_DEVICE_ID_GTCO_1007		0x1007
+
+#define USB_VENDOR_ID_GYRATION		0x0c16
+#define USB_DEVICE_ID_GYRATION_REMOTE	0x0002
+
+#define USB_VENDOR_ID_HAPP		0x078b
+#define USB_DEVICE_ID_UGCI_DRIVING	0x0010
+#define USB_DEVICE_ID_UGCI_FLYING	0x0020
+#define USB_DEVICE_ID_UGCI_FIGHTING	0x0030
+
+#define USB_VENDOR_ID_IMATION		0x0718
+#define USB_DEVICE_ID_DISC_STAKKA	0xd000
+
+#define USB_VENDOR_ID_KBGEAR		0x084e
+#define USB_DEVICE_ID_KBGEAR_JAMSTUDIO	0x1001
+
+#define USB_VENDOR_ID_LABTEC		0x1020
+#define USB_DEVICE_ID_LABTEC_WIRELESS_KEYBOARD	0x0006
+
+#define USB_VENDOR_ID_LD		0x0f11
+#define USB_DEVICE_ID_LD_CASSY		0x1000
+#define USB_DEVICE_ID_LD_POCKETCASSY	0x1010
+#define USB_DEVICE_ID_LD_MOBILECASSY	0x1020
+#define USB_DEVICE_ID_LD_JWM		0x1080
+#define USB_DEVICE_ID_LD_DMMP		0x1081
+#define USB_DEVICE_ID_LD_UMIP		0x1090
+#define USB_DEVICE_ID_LD_XRAY1		0x1100
+#define USB_DEVICE_ID_LD_XRAY2		0x1101
+#define USB_DEVICE_ID_LD_VIDEOCOM	0x1200
+#define USB_DEVICE_ID_LD_COM3LAB	0x2000
+#define USB_DEVICE_ID_LD_TELEPORT	0x2010
+#define USB_DEVICE_ID_LD_NETWORKANALYSER 0x2020
+#define USB_DEVICE_ID_LD_POWERCONTROL	0x2030
+#define USB_DEVICE_ID_LD_MACHINETEST	0x2040
+
+#define USB_VENDOR_ID_LOGITECH		0x046d
+#define USB_DEVICE_ID_LOGITECH_LX3	0xc044
+#define USB_DEVICE_ID_LOGITECH_V150	0xc047
+#define USB_DEVICE_ID_LOGITECH_RECEIVER	0xc101
+#define USB_DEVICE_ID_LOGITECH_HARMONY_FIRST  0xc110
+#define USB_DEVICE_ID_LOGITECH_HARMONY_LAST 0xc14f
+#define USB_DEVICE_ID_LOGITECH_RUMBLEPAD	0xc211
+#define USB_DEVICE_ID_LOGITECH_EXTREME_3D	0xc215
+#define USB_DEVICE_ID_LOGITECH_RUMBLEPAD2	0xc218
+#define USB_DEVICE_ID_LOGITECH_RUMBLEPAD2_2	0xc219
+#define USB_DEVICE_ID_LOGITECH_WINGMAN_F3D	0xc283
+#define USB_DEVICE_ID_LOGITECH_FORCE3D_PRO	0xc286
+#define USB_DEVICE_ID_LOGITECH_WHEEL	0xc294
+#define USB_DEVICE_ID_LOGITECH_MOMO_WHEEL	0xc295
+#define USB_DEVICE_ID_LOGITECH_ELITE_KBD	0xc30a
+#define USB_DEVICE_ID_LOGITECH_KBD	0xc311
+#define USB_DEVICE_ID_S510_RECEIVER	0xc50c
+#define USB_DEVICE_ID_S510_RECEIVER_2	0xc517
+#define USB_DEVICE_ID_LOGITECH_CORDLESS_DESKTOP_LX500	0xc512
+#define USB_DEVICE_ID_MX3000_RECEIVER	0xc513
+#define USB_DEVICE_ID_DINOVO_DESKTOP	0xc704
+#define USB_DEVICE_ID_DINOVO_EDGE	0xc714
+#define USB_DEVICE_ID_DINOVO_MINI	0xc71f
+#define USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2	0xca03
+
+#define USB_VENDOR_ID_MCC		0x09db
+#define USB_DEVICE_ID_MCC_PMD1024LS	0x0076
+#define USB_DEVICE_ID_MCC_PMD1208LS	0x007a
+
+#define USB_VENDOR_ID_MGE		0x0463
+#define USB_DEVICE_ID_MGE_UPS		0xffff
+#define USB_DEVICE_ID_MGE_UPS1		0x0001
+
+#define USB_VENDOR_ID_MICROCHIP		0x04d8
+#define USB_DEVICE_ID_PICKIT1		0x0032
+#define USB_DEVICE_ID_PICKIT2		0x0033
+
+#define USB_VENDOR_ID_MICROSOFT		0x045e
+#define USB_DEVICE_ID_SIDEWINDER_GV	0x003b
+#define USB_DEVICE_ID_WIRELESS_OPTICAL_DESKTOP_3_0 0x009d
+#define USB_DEVICE_ID_MS_NE4K		0x00db
+#define USB_DEVICE_ID_MS_LK6K		0x00f9
+#define USB_DEVICE_ID_MS_PRESENTER_8K_BT	0x0701
+#define USB_DEVICE_ID_MS_PRESENTER_8K_USB	0x0713
+
+
+#define USB_VENDOR_ID_MONTEREY		0x0566
+#define USB_DEVICE_ID_GENIUS_KB29E	0x3004
+
+#define USB_VENDOR_ID_NCR		0x0404
+#define USB_DEVICE_ID_NCR_FIRST		0x0300
+#define USB_DEVICE_ID_NCR_LAST		0x03ff
+
+#define USB_VENDOR_ID_NATIONAL_SEMICONDUCTOR 0x0400
+#define USB_DEVICE_ID_N_S_HARMONY       0xc359
+
+#define USB_VENDOR_ID_NATSU             0x08b7
+#define USB_DEVICE_ID_NATSU_GAMEPAD     0x0001
+
+#define USB_VENDOR_ID_NEC		0x073e
+#define USB_DEVICE_ID_NEC_USB_GAME_PAD	0x0301
+
+#define USB_VENDOR_ID_ONTRAK		0x0a07
+#define USB_DEVICE_ID_ONTRAK_ADU100	0x0064
+
+#define USB_VENDOR_ID_PANJIT		0x134c
+
+#define USB_VENDOR_ID_PANTHERLORD	0x0810
+#define USB_DEVICE_ID_PANTHERLORD_TWIN_USB_JOYSTICK	0x0001
+
+#define USB_VENDOR_ID_PETALYNX		0x18b1
+#define USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE	0x0037
+
+#define USB_VENDOR_ID_PLAYDOTCOM	0x0b43
+#define USB_DEVICE_ID_PLAYDOTCOM_EMS_USBII	0x0003
+
+#define USB_VENDOR_ID_SAITEK		0x06a3
+#define USB_DEVICE_ID_SAITEK_RUMBLEPAD	0xff17
+
+#define USB_VENDOR_ID_SAMSUNG		0x0419
+#define USB_DEVICE_ID_SAMSUNG_IR_REMOTE	0x0001
+
+#define USB_VENDOR_ID_SONY			0x054c
+#define USB_DEVICE_ID_SONY_PS3_CONTROLLER	0x0268
+
+#define USB_VENDOR_ID_SOUNDGRAPH	0x15c2
+#define USB_DEVICE_ID_SOUNDGRAPH_IMON_LCD	0x0038
+
+#define USB_VENDOR_ID_SUN		0x0430
+#define USB_DEVICE_ID_RARITAN_KVM_DONGLE	0xcdab
+
+#define USB_VENDOR_ID_SUNPLUS		0x04fc
+#define USB_DEVICE_ID_SUNPLUS_WDESKTOP	0x05d8
+
+#define USB_VENDOR_ID_TENX		0x1130
+#define USB_DEVICE_ID_TENX_IBUDDY1	0x0001
+#define USB_DEVICE_ID_TENX_IBUDDY2	0x0002
+
+#define USB_VENDOR_ID_THRUSTMASTER	0x044f
+
+#define USB_VENDOR_ID_TOPMAX		0x0663
+#define USB_DEVICE_ID_TOPMAX_COBRAPAD	0x0103
+
+#define USB_VENDOR_ID_TURBOX		0x062a
+#define USB_DEVICE_ID_TURBOX_KEYBOARD	0x0201
+
+#define USB_VENDOR_ID_VERNIER		0x08f7
+#define USB_DEVICE_ID_VERNIER_LABPRO	0x0001
+#define USB_DEVICE_ID_VERNIER_GOTEMP	0x0002
+#define USB_DEVICE_ID_VERNIER_SKIP	0x0003
+#define USB_DEVICE_ID_VERNIER_CYCLOPS	0x0004
+#define USB_DEVICE_ID_VERNIER_LCSPEC	0x0006
+
+#define USB_VENDOR_ID_WACOM		0x056a
+
+#define USB_VENDOR_ID_WISEGROUP		0x0925
+#define USB_DEVICE_ID_1_PHIDGETSERVO_20	0x8101
+#define USB_DEVICE_ID_4_PHIDGETSERVO_20	0x8104
+#define USB_DEVICE_ID_8_8_4_IF_KIT	0x8201
+#define USB_DEVICE_ID_QUAD_USB_JOYPAD	0x8800
+#define USB_DEVICE_ID_DUAL_USB_JOYPAD	0x8866
+
+#define USB_VENDOR_ID_WISEGROUP_LTD	0x6666
+#define USB_VENDOR_ID_WISEGROUP_LTD2	0x6677
+#define USB_DEVICE_ID_SMARTJOY_DUAL_PLUS 0x8802
+
+#define USB_VENDOR_ID_YEALINK		0x6993
+#define USB_DEVICE_ID_YEALINK_P1K_P4K_B2K	0xb001
+
+#define USB_VENDOR_ID_ZEROPLUS		0x0c12
+
+#define USB_VENDOR_ID_KYE		0x0458
+#define USB_DEVICE_ID_KYE_GPEN_560	0x5003
+
+#endif
diff --git a/drivers/hid/hid-input-quirks.c b/drivers/hid/hid-input-quirks.c
deleted file mode 100644
index 16feea0..0000000
--- a/drivers/hid/hid-input-quirks.c
+++ /dev/null
@@ -1,484 +0,0 @@
-/*
- *  HID-input usage mapping quirks
- *
- *  This is used to handle HID-input mappings for devices violating
- *  HUT 1.12 specification.
- *
- * Copyright (c) 2007-2008 Jiri Kosina
- */
-
-/*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 2 of the License
- */
-
-#include <linux/input.h>
-#include <linux/hid.h>
-
-#define map_abs(c)      do { usage->code = c; usage->type = EV_ABS; *bit = input->absbit; *max = ABS_MAX; } while (0)
-#define map_rel(c)      do { usage->code = c; usage->type = EV_REL; *bit = input->relbit; *max = REL_MAX; } while (0)
-#define map_key(c)      do { usage->code = c; usage->type = EV_KEY; *bit = input->keybit; *max = KEY_MAX; } while (0)
-#define map_led(c)      do { usage->code = c; usage->type = EV_LED; *bit = input->ledbit; *max = LED_MAX; } while (0)
-
-#define map_abs_clear(c)        do { map_abs(c); clear_bit(c, *bit); } while (0)
-#define map_key_clear(c)        do { map_key(c); clear_bit(c, *bit); } while (0)
-
-static int quirk_belkin_wkbd(struct hid_usage *usage, struct input_dev *input,
-			      unsigned long **bit, int *max)
-{
-	if ((usage->hid & HID_USAGE_PAGE) != HID_UP_CONSUMER)
-		return 0;
-
-	switch (usage->hid & HID_USAGE) {
-		case 0x03a: map_key_clear(KEY_SOUND);		break;
-		case 0x03b: map_key_clear(KEY_CAMERA);		break;
-		case 0x03c: map_key_clear(KEY_DOCUMENTS);	break;
-		default:
-			return 0;
-	}
-	return 1;
-}
-
-static int quirk_cherry_cymotion(struct hid_usage *usage, struct input_dev *input,
-			      unsigned long **bit, int *max)
-{
-	if ((usage->hid & HID_USAGE_PAGE) != HID_UP_CONSUMER)
-		return 0;
-
-	switch (usage->hid & HID_USAGE) {
-		case 0x301: map_key_clear(KEY_PROG1);		break;
-		case 0x302: map_key_clear(KEY_PROG2);		break;
-		case 0x303: map_key_clear(KEY_PROG3);		break;
-		default:
-			return 0;
-	}
-	return 1;
-}
-
-static int quirk_logitech_ultrax_remote(struct hid_usage *usage, struct input_dev *input,
-			      unsigned long **bit, int *max)
-{
-	if ((usage->hid & HID_USAGE_PAGE) != HID_UP_LOGIVENDOR)
-		return 0;
-
-	set_bit(EV_REP, input->evbit);
-	switch(usage->hid & HID_USAGE) {
-		/* Reported on Logitech Ultra X Media Remote */
-		case 0x004: map_key_clear(KEY_AGAIN);		break;
-		case 0x00d: map_key_clear(KEY_HOME);		break;
-		case 0x024: map_key_clear(KEY_SHUFFLE);		break;
-		case 0x025: map_key_clear(KEY_TV);		break;
-		case 0x026: map_key_clear(KEY_MENU);		break;
-		case 0x031: map_key_clear(KEY_AUDIO);		break;
-		case 0x032: map_key_clear(KEY_TEXT);		break;
-		case 0x033: map_key_clear(KEY_LAST);		break;
-		case 0x047: map_key_clear(KEY_MP3);		break;
-		case 0x048: map_key_clear(KEY_DVD);		break;
-		case 0x049: map_key_clear(KEY_MEDIA);		break;
-		case 0x04a: map_key_clear(KEY_VIDEO);		break;
-		case 0x04b: map_key_clear(KEY_ANGLE);		break;
-		case 0x04c: map_key_clear(KEY_LANGUAGE);	break;
-		case 0x04d: map_key_clear(KEY_SUBTITLE);	break;
-		case 0x051: map_key_clear(KEY_RED);		break;
-		case 0x052: map_key_clear(KEY_CLOSE);		break;
-
-		default:
-			return 0;
-	}
-	return 1;
-}
-
-static int quirk_gyration_remote(struct hid_usage *usage, struct input_dev *input,
-			      unsigned long **bit, int *max)
-{
-	if ((usage->hid & HID_USAGE_PAGE) != HID_UP_LOGIVENDOR)
-		return 0;
-
-	set_bit(EV_REP, input->evbit);
-	switch(usage->hid & HID_USAGE) {
-		/* Reported on Gyration MCE Remote */
-		case 0x00d: map_key_clear(KEY_HOME);		break;
-		case 0x024: map_key_clear(KEY_DVD);		break;
-		case 0x025: map_key_clear(KEY_PVR);		break;
-		case 0x046: map_key_clear(KEY_MEDIA);		break;
-		case 0x047: map_key_clear(KEY_MP3);		break;
-		case 0x049: map_key_clear(KEY_CAMERA);		break;
-		case 0x04a: map_key_clear(KEY_VIDEO);		break;
-
-		default:
-			return 0;
-	}
-	return 1;
-}
-
-static int quirk_chicony_tactical_pad(struct hid_usage *usage, struct input_dev *input,
-			      unsigned long **bit, int *max)
-{
-	if ((usage->hid & HID_USAGE_PAGE) != HID_UP_MSVENDOR)
-		return 0;
-
-	set_bit(EV_REP, input->evbit);
-	switch (usage->hid & HID_USAGE) {
-		case 0xff01: map_key_clear(BTN_1);		break;
-		case 0xff02: map_key_clear(BTN_2);		break;
-		case 0xff03: map_key_clear(BTN_3);		break;
-		case 0xff04: map_key_clear(BTN_4);		break;
-		case 0xff05: map_key_clear(BTN_5);		break;
-		case 0xff06: map_key_clear(BTN_6);		break;
-		case 0xff07: map_key_clear(BTN_7);		break;
-		case 0xff08: map_key_clear(BTN_8);		break;
-		case 0xff09: map_key_clear(BTN_9);		break;
-		case 0xff0a: map_key_clear(BTN_A);		break;
-		case 0xff0b: map_key_clear(BTN_B);		break;
-		default:
-			return 0;
-	}
-	return 1;
-}
-
-static int quirk_microsoft_ergonomy_kb(struct hid_usage *usage, struct input_dev *input,
-			      unsigned long **bit, int *max)
-{
-	if ((usage->hid & HID_USAGE_PAGE) != HID_UP_MSVENDOR)
-		return 0;
-
-	switch(usage->hid & HID_USAGE) {
-		case 0xfd06: map_key_clear(KEY_CHAT);		break;
-		case 0xfd07: map_key_clear(KEY_PHONE);		break;
-		case 0xff05:
-			set_bit(EV_REP, input->evbit);
-			map_key_clear(KEY_F13);
-			set_bit(KEY_F14, input->keybit);
-			set_bit(KEY_F15, input->keybit);
-			set_bit(KEY_F16, input->keybit);
-			set_bit(KEY_F17, input->keybit);
-			set_bit(KEY_F18, input->keybit);
-		default:
-			return 0;
-	}
-	return 1;
-}
-
-static int quirk_microsoft_presenter_8k(struct hid_usage *usage, struct input_dev *input,
-			      unsigned long **bit, int *max)
-{
-	if ((usage->hid & HID_USAGE_PAGE) != HID_UP_MSVENDOR)
-		return 0;
-
-	set_bit(EV_REP, input->evbit);
-	switch(usage->hid & HID_USAGE) {
-		case 0xfd08: map_key_clear(KEY_FORWARD);	break;
-		case 0xfd09: map_key_clear(KEY_BACK);		break;
-		case 0xfd0b: map_key_clear(KEY_PLAYPAUSE);	break;
-		case 0xfd0e: map_key_clear(KEY_CLOSE);		break;
-		case 0xfd0f: map_key_clear(KEY_PLAY);		break;
-		default:
-			return 0;
-	}
-	return 1;
-}
-
-static int quirk_petalynx_remote(struct hid_usage *usage, struct input_dev *input,
-			      unsigned long **bit, int *max)
-{
-	if (((usage->hid & HID_USAGE_PAGE) != HID_UP_LOGIVENDOR) &&
-			((usage->hid & HID_USAGE_PAGE) != HID_UP_CONSUMER))
-		return 0;
-
-	if ((usage->hid & HID_USAGE_PAGE) == HID_UP_LOGIVENDOR)
-		switch(usage->hid & HID_USAGE) {
-			case 0x05a: map_key_clear(KEY_TEXT);		break;
-			case 0x05b: map_key_clear(KEY_RED);		break;
-			case 0x05c: map_key_clear(KEY_GREEN);		break;
-			case 0x05d: map_key_clear(KEY_YELLOW);		break;
-			case 0x05e: map_key_clear(KEY_BLUE);		break;
-			default:
-				return 0;
-		}
-
-	if ((usage->hid & HID_USAGE_PAGE) == HID_UP_CONSUMER)
-		switch(usage->hid & HID_USAGE) {
-			case 0x0f6: map_key_clear(KEY_NEXT);            break;
-			case 0x0fa: map_key_clear(KEY_BACK);            break;
-			default:
-				return 0;
-		}
-	return 1;
-}
-
-static int quirk_logitech_wireless(struct hid_usage *usage, struct input_dev *input,
-			      unsigned long **bit, int *max)
-{
-	if ((usage->hid & HID_USAGE_PAGE) != HID_UP_CONSUMER)
-		return 0;
-
-	switch (usage->hid & HID_USAGE) {
-		case 0x1001: map_key_clear(KEY_MESSENGER);	break;
-		case 0x1003: map_key_clear(KEY_SOUND);		break;
-		case 0x1004: map_key_clear(KEY_VIDEO);		break;
-		case 0x1005: map_key_clear(KEY_AUDIO);		break;
-		case 0x100a: map_key_clear(KEY_DOCUMENTS);	break;
-		case 0x1011: map_key_clear(KEY_PREVIOUSSONG);	break;
-		case 0x1012: map_key_clear(KEY_NEXTSONG);	break;
-		case 0x1013: map_key_clear(KEY_CAMERA);		break;
-		case 0x1014: map_key_clear(KEY_MESSENGER);	break;
-		case 0x1015: map_key_clear(KEY_RECORD);		break;
-		case 0x1016: map_key_clear(KEY_PLAYER);		break;
-		case 0x1017: map_key_clear(KEY_EJECTCD);	break;
-		case 0x1018: map_key_clear(KEY_MEDIA);		break;
-		case 0x1019: map_key_clear(KEY_PROG1);		break;
-		case 0x101a: map_key_clear(KEY_PROG2);		break;
-		case 0x101b: map_key_clear(KEY_PROG3);		break;
-		case 0x101f: map_key_clear(KEY_ZOOMIN);		break;
-		case 0x1020: map_key_clear(KEY_ZOOMOUT);	break;
-		case 0x1021: map_key_clear(KEY_ZOOMRESET);	break;
-		case 0x1023: map_key_clear(KEY_CLOSE);		break;
-		case 0x1027: map_key_clear(KEY_MENU);		break;
-		/* this one is marked as 'Rotate' */
-		case 0x1028: map_key_clear(KEY_ANGLE);		break;
-		case 0x1029: map_key_clear(KEY_SHUFFLE);	break;
-		case 0x102a: map_key_clear(KEY_BACK);		break;
-		case 0x102b: map_key_clear(KEY_CYCLEWINDOWS);	break;
-		case 0x1041: map_key_clear(KEY_BATTERY);	break;
-		case 0x1042: map_key_clear(KEY_WORDPROCESSOR);	break;
-		case 0x1043: map_key_clear(KEY_SPREADSHEET);	break;
-		case 0x1044: map_key_clear(KEY_PRESENTATION);	break;
-		case 0x1045: map_key_clear(KEY_UNDO);		break;
-		case 0x1046: map_key_clear(KEY_REDO);		break;
-		case 0x1047: map_key_clear(KEY_PRINT);		break;
-		case 0x1048: map_key_clear(KEY_SAVE);		break;
-		case 0x1049: map_key_clear(KEY_PROG1);		break;
-		case 0x104a: map_key_clear(KEY_PROG2);		break;
-		case 0x104b: map_key_clear(KEY_PROG3);		break;
-		case 0x104c: map_key_clear(KEY_PROG4);		break;
-
-		default:
-			return 0;
-	}
-	return 1;
-}
-
-static int quirk_cherry_genius_29e(struct hid_usage *usage, struct input_dev *input,
-			      unsigned long **bit, int *max)
-{
-	if ((usage->hid & HID_USAGE_PAGE) != HID_UP_CONSUMER)
-		return 0;
-
-	switch (usage->hid & HID_USAGE) {
-		case 0x156: map_key_clear(KEY_WORDPROCESSOR);	break;
-		case 0x157: map_key_clear(KEY_SPREADSHEET);	break;
-		case 0x158: map_key_clear(KEY_PRESENTATION);	break;
-		case 0x15c: map_key_clear(KEY_STOP);		break;
-
-		default:
-			return 0;
-	}
-	return 1;
-}
-
-static int quirk_btc_8193(struct hid_usage *usage, struct input_dev *input,
-			      unsigned long **bit, int *max)
-{
-	if ((usage->hid & HID_USAGE_PAGE) != HID_UP_CONSUMER)
-		return 0;
-
-	switch (usage->hid & HID_USAGE) {
-		case 0x230: map_key(BTN_MOUSE);			break;
-		case 0x231: map_rel(REL_WHEEL);			break;
-		/* 
-		 * this keyboard has a scrollwheel implemented in
-		 * totally broken way. We map this usage temporarily
-		 * to HWHEEL and handle it in the event quirk handler
-		 */
-		case 0x232: map_rel(REL_HWHEEL);		break;
-
-		default:
-			return 0;
-	}
-	return 1;
-}
-
-static int quirk_sunplus_wdesktop(struct hid_usage *usage, struct input_dev *input,
-			      unsigned long **bit, int *max)
-{
-	if ((usage->hid & HID_USAGE_PAGE) != HID_UP_CONSUMER)
-		return 0;
-
-	switch (usage->hid & HID_USAGE) {
-		case 0x2003: map_key_clear(KEY_ZOOMIN);		break;
-		case 0x2103: map_key_clear(KEY_ZOOMOUT);	break;
-		default:
-			return 0;
-	}
-	return 1;
-}
-
-#define VENDOR_ID_BELKIN			0x1020
-#define DEVICE_ID_BELKIN_WIRELESS_KEYBOARD	0x0006
-
-#define VENDOR_ID_CHERRY			0x046a
-#define DEVICE_ID_CHERRY_CYMOTION		0x0023
-
-#define VENDOR_ID_CHICONY			0x04f2
-#define DEVICE_ID_CHICONY_TACTICAL_PAD		0x0418
-
-#define VENDOR_ID_EZKEY				0x0518
-#define DEVICE_ID_BTC_8193			0x0002
-
-#define VENDOR_ID_GYRATION			0x0c16
-#define DEVICE_ID_GYRATION_REMOTE		0x0002
-
-#define VENDOR_ID_LOGITECH			0x046d
-#define DEVICE_ID_LOGITECH_RECEIVER		0xc101
-#define DEVICE_ID_S510_RECEIVER			0xc50c
-#define DEVICE_ID_S510_RECEIVER_2		0xc517
-#define DEVICE_ID_MX3000_RECEIVER		0xc513
-
-#define VENDOR_ID_MICROSOFT			0x045e
-#define DEVICE_ID_MS4K				0x00db
-#define DEVICE_ID_MS6K				0x00f9
-#define DEVICE_IS_MS_PRESENTER_8K_BT		0x0701
-#define DEVICE_ID_MS_PRESENTER_8K_USB		0x0713
-
-#define VENDOR_ID_MONTEREY			0x0566
-#define DEVICE_ID_GENIUS_KB29E			0x3004
-
-#define VENDOR_ID_PETALYNX			0x18b1
-#define DEVICE_ID_PETALYNX_MAXTER_REMOTE	0x0037
-
-#define VENDOR_ID_SUNPLUS			0x04fc
-#define DEVICE_ID_SUNPLUS_WDESKTOP		0x05d8
-
-static const struct hid_input_blacklist {
-	__u16 idVendor;
-	__u16 idProduct;
-	int (*quirk)(struct hid_usage *, struct input_dev *, unsigned long **, int *);
-} hid_input_blacklist[] = {
-	{ VENDOR_ID_BELKIN, DEVICE_ID_BELKIN_WIRELESS_KEYBOARD, quirk_belkin_wkbd },
-
-	{ VENDOR_ID_CHERRY, DEVICE_ID_CHERRY_CYMOTION, quirk_cherry_cymotion },
-
-	{ VENDOR_ID_CHICONY, DEVICE_ID_CHICONY_TACTICAL_PAD, quirk_chicony_tactical_pad },
-
-	{ VENDOR_ID_EZKEY, DEVICE_ID_BTC_8193, quirk_btc_8193 },
-
-	{ VENDOR_ID_GYRATION, DEVICE_ID_GYRATION_REMOTE, quirk_gyration_remote },
-
-	{ VENDOR_ID_LOGITECH, DEVICE_ID_LOGITECH_RECEIVER, quirk_logitech_ultrax_remote },
-	{ VENDOR_ID_LOGITECH, DEVICE_ID_S510_RECEIVER, quirk_logitech_wireless },
-	{ VENDOR_ID_LOGITECH, DEVICE_ID_S510_RECEIVER_2, quirk_logitech_wireless },
-	{ VENDOR_ID_LOGITECH, DEVICE_ID_MX3000_RECEIVER, quirk_logitech_wireless },
-
-	{ VENDOR_ID_MICROSOFT, DEVICE_ID_MS4K, quirk_microsoft_ergonomy_kb },
-	{ VENDOR_ID_MICROSOFT, DEVICE_ID_MS6K, quirk_microsoft_ergonomy_kb },
-	{ VENDOR_ID_MICROSOFT, DEVICE_IS_MS_PRESENTER_8K_BT, quirk_microsoft_presenter_8k },
-	{ VENDOR_ID_MICROSOFT, DEVICE_ID_MS_PRESENTER_8K_USB, quirk_microsoft_presenter_8k },
-
-	{ VENDOR_ID_MONTEREY, DEVICE_ID_GENIUS_KB29E, quirk_cherry_genius_29e },
-
-	{ VENDOR_ID_PETALYNX, DEVICE_ID_PETALYNX_MAXTER_REMOTE, quirk_petalynx_remote },
-
-	{ VENDOR_ID_SUNPLUS, DEVICE_ID_SUNPLUS_WDESKTOP, quirk_sunplus_wdesktop },
-
-	{ 0, 0, NULL }
-};
-
-int hidinput_mapping_quirks(struct hid_usage *usage, 
-				   struct input_dev *input, 
-				   unsigned long **bit, int *max)
-{
-	struct hid_device *device = input_get_drvdata(input);
-	int i = 0;
-	
-	while (hid_input_blacklist[i].quirk) {
-		if (hid_input_blacklist[i].idVendor == device->vendor &&
-				hid_input_blacklist[i].idProduct == device->product)
-			return hid_input_blacklist[i].quirk(usage, input, bit, max);
-		i++;
-	}
-	return 0;
-}
-
-int hidinput_event_quirks(struct hid_device *hid, struct hid_field *field, struct hid_usage *usage, __s32 value)
-{
-	struct input_dev *input;
-
-	input = field->hidinput->input;
-
-	if (((hid->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_5) && (usage->hid == 0x00090005))
-		|| ((hid->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_7) && (usage->hid == 0x00090007))) {
-		if (value) hid->quirks |=  HID_QUIRK_2WHEEL_MOUSE_HACK_ON;
-		else       hid->quirks &= ~HID_QUIRK_2WHEEL_MOUSE_HACK_ON;
-		return 1;
-	}
-
-	if ((hid->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_B8) &&
-			(usage->type == EV_REL) &&
-			(usage->code == REL_WHEEL)) {
-		hid->delayed_value = value;
-		return 1;
-	}
-
-	if ((hid->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_B8) &&
-			(usage->hid == 0x000100b8)) {
-		input_event(input, EV_REL, value ? REL_HWHEEL : REL_WHEEL, hid->delayed_value);
-		return 1;
-	}
-
-	if ((hid->quirks & HID_QUIRK_INVERT_HWHEEL) && (usage->code == REL_HWHEEL)) {
-		input_event(input, usage->type, usage->code, -value);
-		return 1;
-	}
-
-	if ((hid->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_ON) && (usage->code == REL_WHEEL)) {
-		input_event(input, usage->type, REL_HWHEEL, value);
-		return 1;
-	}
-
-	if ((hid->quirks & HID_QUIRK_APPLE_HAS_FN) && hidinput_apple_event(hid, input, usage, value))
-		return 1;
-
-	/* Handling MS keyboards special buttons */
-	if (hid->quirks & HID_QUIRK_MICROSOFT_KEYS && 
-			usage->hid == (HID_UP_MSVENDOR | 0xff05)) {
-		int key = 0;
-		static int last_key = 0;
-		switch (value) {
-			case 0x01: key = KEY_F14; break;
-			case 0x02: key = KEY_F15; break;
-			case 0x04: key = KEY_F16; break;
-			case 0x08: key = KEY_F17; break;
-			case 0x10: key = KEY_F18; break;
-			default: break;
-		}
-		if (key) {
-			input_event(input, usage->type, key, 1);
-			last_key = key;
-		} else {
-			input_event(input, usage->type, last_key, 0);
-		}
-	}
-
-	/* handle the temporary quirky mapping to HWHEEL */
-	if (hid->quirks & HID_QUIRK_HWHEEL_WHEEL_INVERT &&
-			usage->type == EV_REL && usage->code == REL_HWHEEL) {
-		input_event(input, usage->type, REL_WHEEL, -value);
-		return 1;
-	}
-
-	/* Gyration MCE remote "Sleep" key */
-	if (hid->vendor == VENDOR_ID_GYRATION &&
-	    hid->product == DEVICE_ID_GYRATION_REMOTE &&
-	    (usage->hid & HID_USAGE_PAGE) == HID_UP_GENDESK &&
-	    (usage->hid & 0xff) == 0x82) {
-		input_event(input, usage->type, usage->code, 1);
-		input_sync(input);
-		input_event(input, usage->type, usage->code, 0);
-		input_sync(input);
-		return 1;
-	}
-	return 0;
-}
-
-
diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c
index 1b2e8dc..7f183b7 100644
--- a/drivers/hid/hid-input.c
+++ b/drivers/hid/hid-input.c
@@ -32,11 +32,6 @@
 #include <linux/hid.h>
 #include <linux/hid-debug.h>
 
-static int hid_apple_fnmode = 1;
-module_param_named(pb_fnmode, hid_apple_fnmode, int, 0644);
-MODULE_PARM_DESC(pb_fnmode,
-		"Mode of fn key on Apple keyboards (0 = disabled, 1 = fkeyslast, 2 = fkeysfirst)");
-
 #define unk	KEY_UNKNOWN
 
 static const unsigned char hid_keyboard[256] = {
@@ -58,227 +53,20 @@
 	150,158,159,128,136,177,178,176,142,152,173,140,unk,unk,unk,unk
 };
 
-/* extended mapping for certain Logitech hardware (Logitech cordless desktop LX500) */
-#define LOGITECH_EXPANDED_KEYMAP_SIZE 80
-static int logitech_expanded_keymap[LOGITECH_EXPANDED_KEYMAP_SIZE] = {
-	  0,216,  0,213,175,156,  0,  0,  0,  0,
-	144,  0,  0,  0,  0,  0,  0,  0,  0,212,
-	174,167,152,161,112,  0,  0,  0,154,  0,
-	  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-	  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-	  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-	  0,  0,  0,  0,  0,183,184,185,186,187,
-	188,189,190,191,192,193,194,  0,  0,  0
-};
-
 static const struct {
 	__s32 x;
 	__s32 y;
 }  hid_hat_to_axis[] = {{ 0, 0}, { 0,-1}, { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1}, {-1, 1}, {-1, 0}, {-1,-1}};
 
-#define map_abs(c)	do { usage->code = c; usage->type = EV_ABS; bit = input->absbit; max = ABS_MAX; } while (0)
-#define map_rel(c)	do { usage->code = c; usage->type = EV_REL; bit = input->relbit; max = REL_MAX; } while (0)
-#define map_key(c)	do { usage->code = c; usage->type = EV_KEY; bit = input->keybit; max = KEY_MAX; } while (0)
-#define map_led(c)	do { usage->code = c; usage->type = EV_LED; bit = input->ledbit; max = LED_MAX; } while (0)
+#define map_abs(c)	hid_map_usage(hidinput, usage, &bit, &max, EV_ABS, (c))
+#define map_rel(c)	hid_map_usage(hidinput, usage, &bit, &max, EV_REL, (c))
+#define map_key(c)	hid_map_usage(hidinput, usage, &bit, &max, EV_KEY, (c))
+#define map_led(c)	hid_map_usage(hidinput, usage, &bit, &max, EV_LED, (c))
 
-#define map_abs_clear(c)	do { map_abs(c); clear_bit(c, bit); } while (0)
-#define map_key_clear(c)	do { map_key(c); clear_bit(c, bit); } while (0)
-
-#ifdef CONFIG_USB_HIDINPUT_POWERBOOK
-
-struct hidinput_key_translation {
-	u16 from;
-	u16 to;
-	u8 flags;
-};
-
-#define APPLE_FLAG_FKEY 0x01
-
-static struct hidinput_key_translation apple_fn_keys[] = {
-	{ KEY_BACKSPACE, KEY_DELETE },
-	{ KEY_F1,       KEY_BRIGHTNESSDOWN, APPLE_FLAG_FKEY },
-	{ KEY_F2,       KEY_BRIGHTNESSUP,   APPLE_FLAG_FKEY },
-	{ KEY_F3,       KEY_FN_F5,          APPLE_FLAG_FKEY }, /* Exposé */
-	{ KEY_F4,       KEY_FN_F4,          APPLE_FLAG_FKEY }, /* Dashboard */
-	{ KEY_F5,       KEY_KBDILLUMDOWN,   APPLE_FLAG_FKEY },
-	{ KEY_F6,       KEY_KBDILLUMUP,     APPLE_FLAG_FKEY },
-	{ KEY_F7,       KEY_PREVIOUSSONG,   APPLE_FLAG_FKEY },
-	{ KEY_F8,       KEY_PLAYPAUSE,      APPLE_FLAG_FKEY },
-	{ KEY_F9,       KEY_NEXTSONG,       APPLE_FLAG_FKEY },
-	{ KEY_F10,      KEY_MUTE,           APPLE_FLAG_FKEY },
-	{ KEY_F11,      KEY_VOLUMEDOWN,     APPLE_FLAG_FKEY },
-	{ KEY_F12,      KEY_VOLUMEUP,       APPLE_FLAG_FKEY },
-	{ KEY_UP,       KEY_PAGEUP },
-	{ KEY_DOWN,     KEY_PAGEDOWN },
-	{ KEY_LEFT,     KEY_HOME },
-	{ KEY_RIGHT,    KEY_END },
-	{ }
-};
-
-static struct hidinput_key_translation powerbook_fn_keys[] = {
-	{ KEY_BACKSPACE, KEY_DELETE },
-	{ KEY_F1,       KEY_BRIGHTNESSDOWN,     APPLE_FLAG_FKEY },
-	{ KEY_F2,       KEY_BRIGHTNESSUP,       APPLE_FLAG_FKEY },
-	{ KEY_F3,       KEY_MUTE,               APPLE_FLAG_FKEY },
-	{ KEY_F4,       KEY_VOLUMEDOWN,         APPLE_FLAG_FKEY },
-	{ KEY_F5,       KEY_VOLUMEUP,           APPLE_FLAG_FKEY },
-	{ KEY_F6,       KEY_NUMLOCK,            APPLE_FLAG_FKEY },
-	{ KEY_F7,       KEY_SWITCHVIDEOMODE,    APPLE_FLAG_FKEY },
-	{ KEY_F8,       KEY_KBDILLUMTOGGLE,     APPLE_FLAG_FKEY },
-	{ KEY_F9,       KEY_KBDILLUMDOWN,       APPLE_FLAG_FKEY },
-	{ KEY_F10,      KEY_KBDILLUMUP,         APPLE_FLAG_FKEY },
-	{ KEY_UP,       KEY_PAGEUP },
-	{ KEY_DOWN,     KEY_PAGEDOWN },
-	{ KEY_LEFT,     KEY_HOME },
-	{ KEY_RIGHT,    KEY_END },
-	{ }
-};
-
-static struct hidinput_key_translation powerbook_numlock_keys[] = {
-	{ KEY_J,        KEY_KP1 },
-	{ KEY_K,        KEY_KP2 },
-	{ KEY_L,        KEY_KP3 },
-	{ KEY_U,        KEY_KP4 },
-	{ KEY_I,        KEY_KP5 },
-	{ KEY_O,        KEY_KP6 },
-	{ KEY_7,        KEY_KP7 },
-	{ KEY_8,        KEY_KP8 },
-	{ KEY_9,        KEY_KP9 },
-	{ KEY_M,        KEY_KP0 },
-	{ KEY_DOT,      KEY_KPDOT },
-	{ KEY_SLASH,    KEY_KPPLUS },
-	{ KEY_SEMICOLON, KEY_KPMINUS },
-	{ KEY_P,        KEY_KPASTERISK },
-	{ KEY_MINUS,    KEY_KPEQUAL },
-	{ KEY_0,        KEY_KPSLASH },
-	{ KEY_F6,       KEY_NUMLOCK },
-	{ KEY_KPENTER,  KEY_KPENTER },
-	{ KEY_BACKSPACE, KEY_BACKSPACE },
-	{ }
-};
-
-static struct hidinput_key_translation apple_iso_keyboard[] = {
-	{ KEY_GRAVE,    KEY_102ND },
-	{ KEY_102ND,    KEY_GRAVE },
-	{ }
-};
-
-static struct hidinput_key_translation *find_translation(struct hidinput_key_translation *table, u16 from)
-{
-	struct hidinput_key_translation *trans;
-
-	/* Look for the translation */
-	for (trans = table; trans->from; trans++)
-		if (trans->from == from)
-			return trans;
-
-	return NULL;
-}
-
-int hidinput_apple_event(struct hid_device *hid, struct input_dev *input,
-		struct hid_usage *usage, __s32 value)
-{
-	struct hidinput_key_translation *trans;
-
-	if (usage->code == KEY_FN) {
-		if (value) hid->quirks |=  HID_QUIRK_APPLE_FN_ON;
-		else       hid->quirks &= ~HID_QUIRK_APPLE_FN_ON;
-
-		input_event(input, usage->type, usage->code, value);
-
-		return 1;
-	}
-
-	if (hid_apple_fnmode) {
-		int do_translate;
-
-		trans = find_translation((hid->product < 0x220 ||
-					  hid->product >= 0x300) ?
-					 powerbook_fn_keys : apple_fn_keys,
-					 usage->code);
-		if (trans) {
-			if (test_bit(usage->code, hid->apple_pressed_fn))
-				do_translate = 1;
-			else if (trans->flags & APPLE_FLAG_FKEY)
-				do_translate =
-					(hid_apple_fnmode == 2 &&  (hid->quirks & HID_QUIRK_APPLE_FN_ON)) ||
-					(hid_apple_fnmode == 1 && !(hid->quirks & HID_QUIRK_APPLE_FN_ON));
-			else
-				do_translate = (hid->quirks & HID_QUIRK_APPLE_FN_ON);
-
-			if (do_translate) {
-				if (value)
-					set_bit(usage->code, hid->apple_pressed_fn);
-				else
-					clear_bit(usage->code, hid->apple_pressed_fn);
-
-				input_event(input, usage->type, trans->to, value);
-
-				return 1;
-			}
-		}
-
-		if (hid->quirks & HID_QUIRK_APPLE_NUMLOCK_EMULATION && (
-				test_bit(usage->code, hid->pb_pressed_numlock) ||
-				test_bit(LED_NUML, input->led))) {
-			trans = find_translation(powerbook_numlock_keys, usage->code);
-
-			if (trans) {
-				if (value)
-					set_bit(usage->code, hid->pb_pressed_numlock);
-				else
-					clear_bit(usage->code, hid->pb_pressed_numlock);
-
-				input_event(input, usage->type, trans->to, value);
-			}
-
-			return 1;
-		}
-	}
-
-	if (hid->quirks & HID_QUIRK_APPLE_ISO_KEYBOARD) {
-		trans = find_translation(apple_iso_keyboard, usage->code);
-		if (trans) {
-			input_event(input, usage->type, trans->to, value);
-			return 1;
-		}
-	}
-
-	return 0;
-}
-
-static void hidinput_apple_setup(struct input_dev *input)
-{
-	struct hidinput_key_translation *trans;
-
-	set_bit(KEY_NUMLOCK, input->keybit);
-
-	/* Enable all needed keys */
-	for (trans = apple_fn_keys; trans->from; trans++)
-		set_bit(trans->to, input->keybit);
-
-	for (trans = powerbook_fn_keys; trans->from; trans++)
-		set_bit(trans->to, input->keybit);
-
-	for (trans = powerbook_numlock_keys; trans->from; trans++)
-		set_bit(trans->to, input->keybit);
-
-	for (trans = apple_iso_keyboard; trans->from; trans++)
-		set_bit(trans->to, input->keybit);
-
-}
-#else
-inline int hidinput_apple_event(struct hid_device *hid,
-				       struct input_dev *input,
-				       struct hid_usage *usage, __s32 value)
-{
-	return 0;
-}
-
-static inline void hidinput_apple_setup(struct input_dev *input)
-{
-}
-#endif
+#define map_abs_clear(c)	hid_map_usage_clear(hidinput, usage, &bit, \
+		&max, EV_ABS, (c))
+#define map_key_clear(c)	hid_map_usage_clear(hidinput, usage, &bit, \
+		&max, EV_KEY, (c))
 
 static inline int match_scancode(int code, int scancode)
 {
@@ -366,7 +154,7 @@
 {
 	struct input_dev *input = hidinput->input;
 	struct hid_device *device = input_get_drvdata(input);
-	int max = 0, code, ret;
+	int max = 0, code;
 	unsigned long *bit = NULL;
 
 	field->hidinput = hidinput;
@@ -385,406 +173,345 @@
 		goto ignore;
 	}
 
-	/* handle input mappings for quirky devices */
-	ret = hidinput_mapping_quirks(usage, input, &bit, &max);
-	if (ret)
-		goto mapped;
+	if (device->driver->input_mapping) {
+		int ret = device->driver->input_mapping(device, hidinput, field,
+				usage, &bit, &max);
+		if (ret > 0)
+			goto mapped;
+		if (ret < 0)
+			goto ignore;
+	}
 
 	switch (usage->hid & HID_USAGE_PAGE) {
+	case HID_UP_UNDEFINED:
+		goto ignore;
 
-		case HID_UP_UNDEFINED:
-			goto ignore;
+	case HID_UP_KEYBOARD:
+		set_bit(EV_REP, input->evbit);
 
-		case HID_UP_KEYBOARD:
+		if ((usage->hid & HID_USAGE) < 256) {
+			if (!hid_keyboard[usage->hid & HID_USAGE]) goto ignore;
+			map_key_clear(hid_keyboard[usage->hid & HID_USAGE]);
+		} else
+			map_key(KEY_UNKNOWN);
 
-			set_bit(EV_REP, input->evbit);
+		break;
 
-			if ((usage->hid & HID_USAGE) < 256) {
-				if (!hid_keyboard[usage->hid & HID_USAGE]) goto ignore;
-				map_key_clear(hid_keyboard[usage->hid & HID_USAGE]);
-			} else
-				map_key(KEY_UNKNOWN);
+	case HID_UP_BUTTON:
+		code = ((usage->hid - 1) & 0xf);
 
-			break;
-
-		case HID_UP_BUTTON:
-
-			code = ((usage->hid - 1) & 0xf);
-
-			switch (field->application) {
-				case HID_GD_MOUSE:
-				case HID_GD_POINTER:  code += 0x110; break;
-				case HID_GD_JOYSTICK: code += 0x120; break;
-				case HID_GD_GAMEPAD:  code += 0x130; break;
-				default:
-					switch (field->physical) {
-						case HID_GD_MOUSE:
-						case HID_GD_POINTER:  code += 0x110; break;
-						case HID_GD_JOYSTICK: code += 0x120; break;
-						case HID_GD_GAMEPAD:  code += 0x130; break;
-						default:              code += 0x100;
-					}
-			}
-
-			/* Special handling for Logitech Cordless Desktop */
-			if (field->application != HID_GD_MOUSE) {
-				if (device->quirks & HID_QUIRK_LOGITECH_EXPANDED_KEYMAP) {
-					int hid = usage->hid & HID_USAGE;
-					if (hid < LOGITECH_EXPANDED_KEYMAP_SIZE && logitech_expanded_keymap[hid] != 0)
-						code = logitech_expanded_keymap[hid];
-				}
-			} else {
-				if (device->quirks & HID_QUIRK_LOGITECH_IGNORE_DOUBLED_WHEEL) {
-					int hid = usage->hid & HID_USAGE;
-					if (hid == 7 || hid == 8)
-						goto ignore;
-				}
-			}
-
-			map_key(code);
-			break;
-
-
-		case HID_UP_SIMULATION:
-
-			switch (usage->hid & 0xffff) {
-				case 0xba: map_abs(ABS_RUDDER);   break;
-				case 0xbb: map_abs(ABS_THROTTLE); break;
-				case 0xc4: map_abs(ABS_GAS);      break;
-				case 0xc5: map_abs(ABS_BRAKE);    break;
-				case 0xc8: map_abs(ABS_WHEEL);    break;
-				default:   goto ignore;
-			}
-			break;
-
-		case HID_UP_GENDESK:
-
-			if ((usage->hid & 0xf0) == 0x80) {	/* SystemControl */
-				switch (usage->hid & 0xf) {
-					case 0x1: map_key_clear(KEY_POWER);  break;
-					case 0x2: map_key_clear(KEY_SLEEP);  break;
-					case 0x3: map_key_clear(KEY_WAKEUP); break;
-					default: goto unknown;
-				}
-				break;
-			}
-
-			if ((usage->hid & 0xf0) == 0x90) {	/* D-pad */
-				switch (usage->hid) {
-					case HID_GD_UP:	   usage->hat_dir = 1; break;
-					case HID_GD_DOWN:  usage->hat_dir = 5; break;
-					case HID_GD_RIGHT: usage->hat_dir = 3; break;
-					case HID_GD_LEFT:  usage->hat_dir = 7; break;
-					default: goto unknown;
-				}
-				if (field->dpad) {
-					map_abs(field->dpad);
-					goto ignore;
-				}
-				map_abs(ABS_HAT0X);
-				break;
-			}
-
-			switch (usage->hid) {
-
-				/* These usage IDs map directly to the usage codes. */
-				case HID_GD_X: case HID_GD_Y: case HID_GD_Z:
-				case HID_GD_RX: case HID_GD_RY: case HID_GD_RZ:
-				case HID_GD_SLIDER: case HID_GD_DIAL: case HID_GD_WHEEL:
-					if (field->flags & HID_MAIN_ITEM_RELATIVE)
-						map_rel(usage->hid & 0xf);
-					else
-						map_abs(usage->hid & 0xf);
-					break;
-
-				case HID_GD_HATSWITCH:
-					usage->hat_min = field->logical_minimum;
-					usage->hat_max = field->logical_maximum;
-					map_abs(ABS_HAT0X);
-					break;
-
-				case HID_GD_START:	map_key_clear(BTN_START);	break;
-				case HID_GD_SELECT:	map_key_clear(BTN_SELECT);	break;
-
-				default: goto unknown;
-			}
-
-			break;
-
-		case HID_UP_LED:
-
-			switch (usage->hid & 0xffff) {                        /* HID-Value:                   */
-				case 0x01:  map_led (LED_NUML);     break;    /*   "Num Lock"                 */
-				case 0x02:  map_led (LED_CAPSL);    break;    /*   "Caps Lock"                */
-				case 0x03:  map_led (LED_SCROLLL);  break;    /*   "Scroll Lock"              */
-				case 0x04:  map_led (LED_COMPOSE);  break;    /*   "Compose"                  */
-				case 0x05:  map_led (LED_KANA);     break;    /*   "Kana"                     */
-				case 0x27:  map_led (LED_SLEEP);    break;    /*   "Stand-By"                 */
-				case 0x4c:  map_led (LED_SUSPEND);  break;    /*   "System Suspend"           */
-				case 0x09:  map_led (LED_MUTE);     break;    /*   "Mute"                     */
-				case 0x4b:  map_led (LED_MISC);     break;    /*   "Generic Indicator"        */
-				case 0x19:  map_led (LED_MAIL);     break;    /*   "Message Waiting"          */
-				case 0x4d:  map_led (LED_CHARGING); break;    /*   "External Power Connected" */
-
-				default: goto ignore;
-			}
-			break;
-
-		case HID_UP_DIGITIZER:
-
-			switch (usage->hid & 0xff) {
-
-				case 0x30: /* TipPressure */
-					if (!test_bit(BTN_TOUCH, input->keybit)) {
-						device->quirks |= HID_QUIRK_NOTOUCH;
-						set_bit(EV_KEY, input->evbit);
-						set_bit(BTN_TOUCH, input->keybit);
-					}
-
-					map_abs_clear(ABS_PRESSURE);
-					break;
-
-				case 0x32: /* InRange */
-					switch (field->physical & 0xff) {
-						case 0x21: map_key(BTN_TOOL_MOUSE); break;
-						case 0x22: map_key(BTN_TOOL_FINGER); break;
-						default: map_key(BTN_TOOL_PEN); break;
-					}
-					break;
-
-				case 0x3c: /* Invert */
-					map_key_clear(BTN_TOOL_RUBBER);
-					break;
-
-				case 0x33: /* Touch */
-				case 0x42: /* TipSwitch */
-				case 0x43: /* TipSwitch2 */
-					device->quirks &= ~HID_QUIRK_NOTOUCH;
-					map_key_clear(BTN_TOUCH);
-					break;
-
-				case 0x44: /* BarrelSwitch */
-					map_key_clear(BTN_STYLUS);
-					break;
-
-				default:  goto unknown;
-			}
-			break;
-
-		case HID_UP_CONSUMER:	/* USB HUT v1.1, pages 56-62 */
-
-			switch (usage->hid & HID_USAGE) {
-				case 0x000: goto ignore;
-				case 0x034: map_key_clear(KEY_SLEEP);		break;
-				case 0x036: map_key_clear(BTN_MISC);		break;
-
-				case 0x040: map_key_clear(KEY_MENU);		break;
-				case 0x045: map_key_clear(KEY_RADIO);		break;
-
-				case 0x083: map_key_clear(KEY_LAST);		break;
-				case 0x088: map_key_clear(KEY_PC);		break;
-				case 0x089: map_key_clear(KEY_TV);		break;
-				case 0x08a: map_key_clear(KEY_WWW);		break;
-				case 0x08b: map_key_clear(KEY_DVD);		break;
-				case 0x08c: map_key_clear(KEY_PHONE);		break;
-				case 0x08d: map_key_clear(KEY_PROGRAM);		break;
-				case 0x08e: map_key_clear(KEY_VIDEOPHONE);	break;
-				case 0x08f: map_key_clear(KEY_GAMES);		break;
-				case 0x090: map_key_clear(KEY_MEMO);		break;
-				case 0x091: map_key_clear(KEY_CD);		break;
-				case 0x092: map_key_clear(KEY_VCR);		break;
-				case 0x093: map_key_clear(KEY_TUNER);		break;
-				case 0x094: map_key_clear(KEY_EXIT);		break;
-				case 0x095: map_key_clear(KEY_HELP);		break;
-				case 0x096: map_key_clear(KEY_TAPE);		break;
-				case 0x097: map_key_clear(KEY_TV2);		break;
-				case 0x098: map_key_clear(KEY_SAT);		break;
-				case 0x09a: map_key_clear(KEY_PVR);		break;
-
-				case 0x09c: map_key_clear(KEY_CHANNELUP);	break;
-				case 0x09d: map_key_clear(KEY_CHANNELDOWN);	break;
-				case 0x0a0: map_key_clear(KEY_VCR2);		break;
-
-				case 0x0b0: map_key_clear(KEY_PLAY);		break;
-				case 0x0b1: map_key_clear(KEY_PAUSE);		break;
-				case 0x0b2: map_key_clear(KEY_RECORD);		break;
-				case 0x0b3: map_key_clear(KEY_FASTFORWARD);	break;
-				case 0x0b4: map_key_clear(KEY_REWIND);		break;
-				case 0x0b5: map_key_clear(KEY_NEXTSONG);	break;
-				case 0x0b6: map_key_clear(KEY_PREVIOUSSONG);	break;
-				case 0x0b7: map_key_clear(KEY_STOPCD);		break;
-				case 0x0b8: map_key_clear(KEY_EJECTCD);		break;
-				case 0x0bc: map_key_clear(KEY_MEDIA_REPEAT);	break;
-
-				case 0x0cd: map_key_clear(KEY_PLAYPAUSE);	break;
-			        case 0x0e0: map_abs_clear(ABS_VOLUME);		break;
-				case 0x0e2: map_key_clear(KEY_MUTE);		break;
-				case 0x0e5: map_key_clear(KEY_BASSBOOST);	break;
-				case 0x0e9: map_key_clear(KEY_VOLUMEUP);	break;
-				case 0x0ea: map_key_clear(KEY_VOLUMEDOWN);	break;
-
-				case 0x182: map_key_clear(KEY_BOOKMARKS);	break;
-				case 0x183: map_key_clear(KEY_CONFIG);		break;
-				case 0x184: map_key_clear(KEY_WORDPROCESSOR);	break;
-				case 0x185: map_key_clear(KEY_EDITOR);		break;
-				case 0x186: map_key_clear(KEY_SPREADSHEET);	break;
-				case 0x187: map_key_clear(KEY_GRAPHICSEDITOR);	break;
-				case 0x188: map_key_clear(KEY_PRESENTATION);	break;
-				case 0x189: map_key_clear(KEY_DATABASE);	break;
-				case 0x18a: map_key_clear(KEY_MAIL);		break;
-				case 0x18b: map_key_clear(KEY_NEWS);		break;
-				case 0x18c: map_key_clear(KEY_VOICEMAIL);	break;
-				case 0x18d: map_key_clear(KEY_ADDRESSBOOK);	break;
-				case 0x18e: map_key_clear(KEY_CALENDAR);	break;
-				case 0x191: map_key_clear(KEY_FINANCE);		break;
-				case 0x192: map_key_clear(KEY_CALC);		break;
-				case 0x194: map_key_clear(KEY_FILE);		break;
-				case 0x196: map_key_clear(KEY_WWW);		break;
-				case 0x19c: map_key_clear(KEY_LOGOFF);		break;
-				case 0x19e: map_key_clear(KEY_COFFEE);		break;
-				case 0x1a6: map_key_clear(KEY_HELP);		break;
-				case 0x1a7: map_key_clear(KEY_DOCUMENTS);	break;
-				case 0x1ab: map_key_clear(KEY_SPELLCHECK);	break;
-				case 0x1b6: map_key_clear(KEY_MEDIA);		break;
-				case 0x1b7: map_key_clear(KEY_SOUND);		break;
-				case 0x1bc: map_key_clear(KEY_MESSENGER);	break;
-				case 0x1bd: map_key_clear(KEY_INFO);		break;
-				case 0x201: map_key_clear(KEY_NEW);		break;
-				case 0x202: map_key_clear(KEY_OPEN);		break;
-				case 0x203: map_key_clear(KEY_CLOSE);		break;
-				case 0x204: map_key_clear(KEY_EXIT);		break;
-				case 0x207: map_key_clear(KEY_SAVE);		break;
-				case 0x208: map_key_clear(KEY_PRINT);		break;
-				case 0x209: map_key_clear(KEY_PROPS);		break;
-				case 0x21a: map_key_clear(KEY_UNDO);		break;
-				case 0x21b: map_key_clear(KEY_COPY);		break;
-				case 0x21c: map_key_clear(KEY_CUT);		break;
-				case 0x21d: map_key_clear(KEY_PASTE);		break;
-				case 0x21f: map_key_clear(KEY_FIND);		break;
-				case 0x221: map_key_clear(KEY_SEARCH);		break;
-				case 0x222: map_key_clear(KEY_GOTO);		break;
-				case 0x223: map_key_clear(KEY_HOMEPAGE);	break;
-				case 0x224: map_key_clear(KEY_BACK);		break;
-				case 0x225: map_key_clear(KEY_FORWARD);		break;
-				case 0x226: map_key_clear(KEY_STOP);		break;
-				case 0x227: map_key_clear(KEY_REFRESH);		break;
-				case 0x22a: map_key_clear(KEY_BOOKMARKS);	break;
-				case 0x22d: map_key_clear(KEY_ZOOMIN);		break;
-				case 0x22e: map_key_clear(KEY_ZOOMOUT);		break;
-				case 0x22f: map_key_clear(KEY_ZOOMRESET);	break;
-				case 0x233: map_key_clear(KEY_SCROLLUP);	break;
-				case 0x234: map_key_clear(KEY_SCROLLDOWN);	break;
-				case 0x238: map_rel(REL_HWHEEL);		break;
-				case 0x25f: map_key_clear(KEY_CANCEL);		break;
-				case 0x279: map_key_clear(KEY_REDO);		break;
-
-				case 0x289: map_key_clear(KEY_REPLY);		break;
-				case 0x28b: map_key_clear(KEY_FORWARDMAIL);	break;
-				case 0x28c: map_key_clear(KEY_SEND);		break;
-
-				default:    goto ignore;
-			}
-			break;
-
-		case HID_UP_HPVENDOR:	/* Reported on a Dutch layout HP5308 */
-
-			set_bit(EV_REP, input->evbit);
-			switch (usage->hid & HID_USAGE) {
-			        case 0x021: map_key_clear(KEY_PRINT);           break;
-				case 0x070: map_key_clear(KEY_HP);		break;
-				case 0x071: map_key_clear(KEY_CAMERA);		break;
-				case 0x072: map_key_clear(KEY_SOUND);		break;
-				case 0x073: map_key_clear(KEY_QUESTION);	break;
-				case 0x080: map_key_clear(KEY_EMAIL);		break;
-				case 0x081: map_key_clear(KEY_CHAT);		break;
-				case 0x082: map_key_clear(KEY_SEARCH);		break;
-				case 0x083: map_key_clear(KEY_CONNECT);	        break;
-				case 0x084: map_key_clear(KEY_FINANCE);		break;
-				case 0x085: map_key_clear(KEY_SPORT);		break;
-				case 0x086: map_key_clear(KEY_SHOP);	        break;
-				default:    goto ignore;
-			}
-			break;
-
-		case HID_UP_MSVENDOR:
-
-			goto ignore;
-
-		case HID_UP_CUSTOM: /* Reported on Logitech and Apple USB keyboards */
-
-			set_bit(EV_REP, input->evbit);
-			switch(usage->hid & HID_USAGE) {
-				case 0x003:
-					/* The fn key on Apple USB keyboards */
-					map_key_clear(KEY_FN);
-					hidinput_apple_setup(input);
-					break;
-
-				default:    goto ignore;
-			}
-			break;
-
-		case HID_UP_LOGIVENDOR:
-
-			goto ignore;
-		
-		case HID_UP_PID:
-
-			switch(usage->hid & HID_USAGE) {
-				case 0xa4: map_key_clear(BTN_DEAD);	break;
-				default: goto ignore;
-			}
-			break;
-
+		switch (field->application) {
+		case HID_GD_MOUSE:
+		case HID_GD_POINTER:  code += 0x110; break;
+		case HID_GD_JOYSTICK: code += 0x120; break;
+		case HID_GD_GAMEPAD:  code += 0x130; break;
 		default:
-		unknown:
-			if (field->report_size == 1) {
-				if (field->report->type == HID_OUTPUT_REPORT) {
-					map_led(LED_MISC);
-					break;
-				}
-				map_key(BTN_MISC);
-				break;
+			switch (field->physical) {
+			case HID_GD_MOUSE:
+			case HID_GD_POINTER:  code += 0x110; break;
+			case HID_GD_JOYSTICK: code += 0x120; break;
+			case HID_GD_GAMEPAD:  code += 0x130; break;
+			default:              code += 0x100;
 			}
-			if (field->flags & HID_MAIN_ITEM_RELATIVE) {
-				map_rel(REL_MISC);
-				break;
+		}
+
+		map_key(code);
+		break;
+
+	case HID_UP_SIMULATION:
+		switch (usage->hid & 0xffff) {
+		case 0xba: map_abs(ABS_RUDDER);   break;
+		case 0xbb: map_abs(ABS_THROTTLE); break;
+		case 0xc4: map_abs(ABS_GAS);      break;
+		case 0xc5: map_abs(ABS_BRAKE);    break;
+		case 0xc8: map_abs(ABS_WHEEL);    break;
+		default:   goto ignore;
+		}
+		break;
+
+	case HID_UP_GENDESK:
+		if ((usage->hid & 0xf0) == 0x80) {	/* SystemControl */
+			switch (usage->hid & 0xf) {
+			case 0x1: map_key_clear(KEY_POWER);  break;
+			case 0x2: map_key_clear(KEY_SLEEP);  break;
+			case 0x3: map_key_clear(KEY_WAKEUP); break;
+			default: goto unknown;
 			}
-			map_abs(ABS_MISC);
 			break;
+		}
+
+		if ((usage->hid & 0xf0) == 0x90) {	/* D-pad */
+			switch (usage->hid) {
+			case HID_GD_UP:	   usage->hat_dir = 1; break;
+			case HID_GD_DOWN:  usage->hat_dir = 5; break;
+			case HID_GD_RIGHT: usage->hat_dir = 3; break;
+			case HID_GD_LEFT:  usage->hat_dir = 7; break;
+			default: goto unknown;
+			}
+			if (field->dpad) {
+				map_abs(field->dpad);
+				goto ignore;
+			}
+			map_abs(ABS_HAT0X);
+			break;
+		}
+
+		switch (usage->hid) {
+		/* These usage IDs map directly to the usage codes. */
+		case HID_GD_X: case HID_GD_Y: case HID_GD_Z:
+		case HID_GD_RX: case HID_GD_RY: case HID_GD_RZ:
+		case HID_GD_SLIDER: case HID_GD_DIAL: case HID_GD_WHEEL:
+			if (field->flags & HID_MAIN_ITEM_RELATIVE)
+				map_rel(usage->hid & 0xf);
+			else
+				map_abs(usage->hid & 0xf);
+			break;
+
+		case HID_GD_HATSWITCH:
+			usage->hat_min = field->logical_minimum;
+			usage->hat_max = field->logical_maximum;
+			map_abs(ABS_HAT0X);
+			break;
+
+		case HID_GD_START:	map_key_clear(BTN_START);	break;
+		case HID_GD_SELECT:	map_key_clear(BTN_SELECT);	break;
+
+		default: goto unknown;
+		}
+
+		break;
+
+	case HID_UP_LED:
+		switch (usage->hid & 0xffff) {		      /* HID-Value:                   */
+		case 0x01:  map_led (LED_NUML);     break;    /*   "Num Lock"                 */
+		case 0x02:  map_led (LED_CAPSL);    break;    /*   "Caps Lock"                */
+		case 0x03:  map_led (LED_SCROLLL);  break;    /*   "Scroll Lock"              */
+		case 0x04:  map_led (LED_COMPOSE);  break;    /*   "Compose"                  */
+		case 0x05:  map_led (LED_KANA);     break;    /*   "Kana"                     */
+		case 0x27:  map_led (LED_SLEEP);    break;    /*   "Stand-By"                 */
+		case 0x4c:  map_led (LED_SUSPEND);  break;    /*   "System Suspend"           */
+		case 0x09:  map_led (LED_MUTE);     break;    /*   "Mute"                     */
+		case 0x4b:  map_led (LED_MISC);     break;    /*   "Generic Indicator"        */
+		case 0x19:  map_led (LED_MAIL);     break;    /*   "Message Waiting"          */
+		case 0x4d:  map_led (LED_CHARGING); break;    /*   "External Power Connected" */
+
+		default: goto ignore;
+		}
+		break;
+
+	case HID_UP_DIGITIZER:
+		switch (usage->hid & 0xff) {
+		case 0x30: /* TipPressure */
+			if (!test_bit(BTN_TOUCH, input->keybit)) {
+				device->quirks |= HID_QUIRK_NOTOUCH;
+				set_bit(EV_KEY, input->evbit);
+				set_bit(BTN_TOUCH, input->keybit);
+			}
+			map_abs_clear(ABS_PRESSURE);
+			break;
+
+		case 0x32: /* InRange */
+			switch (field->physical & 0xff) {
+			case 0x21: map_key(BTN_TOOL_MOUSE); break;
+			case 0x22: map_key(BTN_TOOL_FINGER); break;
+			default: map_key(BTN_TOOL_PEN); break;
+			}
+			break;
+
+		case 0x3c: /* Invert */
+			map_key_clear(BTN_TOOL_RUBBER);
+			break;
+
+		case 0x33: /* Touch */
+		case 0x42: /* TipSwitch */
+		case 0x43: /* TipSwitch2 */
+			device->quirks &= ~HID_QUIRK_NOTOUCH;
+			map_key_clear(BTN_TOUCH);
+			break;
+
+		case 0x44: /* BarrelSwitch */
+			map_key_clear(BTN_STYLUS);
+			break;
+
+		default:  goto unknown;
+		}
+		break;
+
+	case HID_UP_CONSUMER:	/* USB HUT v1.1, pages 56-62 */
+		switch (usage->hid & HID_USAGE) {
+		case 0x000: goto ignore;
+		case 0x034: map_key_clear(KEY_SLEEP);		break;
+		case 0x036: map_key_clear(BTN_MISC);		break;
+
+		case 0x040: map_key_clear(KEY_MENU);		break;
+		case 0x045: map_key_clear(KEY_RADIO);		break;
+
+		case 0x083: map_key_clear(KEY_LAST);		break;
+		case 0x088: map_key_clear(KEY_PC);		break;
+		case 0x089: map_key_clear(KEY_TV);		break;
+		case 0x08a: map_key_clear(KEY_WWW);		break;
+		case 0x08b: map_key_clear(KEY_DVD);		break;
+		case 0x08c: map_key_clear(KEY_PHONE);		break;
+		case 0x08d: map_key_clear(KEY_PROGRAM);		break;
+		case 0x08e: map_key_clear(KEY_VIDEOPHONE);	break;
+		case 0x08f: map_key_clear(KEY_GAMES);		break;
+		case 0x090: map_key_clear(KEY_MEMO);		break;
+		case 0x091: map_key_clear(KEY_CD);		break;
+		case 0x092: map_key_clear(KEY_VCR);		break;
+		case 0x093: map_key_clear(KEY_TUNER);		break;
+		case 0x094: map_key_clear(KEY_EXIT);		break;
+		case 0x095: map_key_clear(KEY_HELP);		break;
+		case 0x096: map_key_clear(KEY_TAPE);		break;
+		case 0x097: map_key_clear(KEY_TV2);		break;
+		case 0x098: map_key_clear(KEY_SAT);		break;
+		case 0x09a: map_key_clear(KEY_PVR);		break;
+
+		case 0x09c: map_key_clear(KEY_CHANNELUP);	break;
+		case 0x09d: map_key_clear(KEY_CHANNELDOWN);	break;
+		case 0x0a0: map_key_clear(KEY_VCR2);		break;
+
+		case 0x0b0: map_key_clear(KEY_PLAY);		break;
+		case 0x0b1: map_key_clear(KEY_PAUSE);		break;
+		case 0x0b2: map_key_clear(KEY_RECORD);		break;
+		case 0x0b3: map_key_clear(KEY_FASTFORWARD);	break;
+		case 0x0b4: map_key_clear(KEY_REWIND);		break;
+		case 0x0b5: map_key_clear(KEY_NEXTSONG);	break;
+		case 0x0b6: map_key_clear(KEY_PREVIOUSSONG);	break;
+		case 0x0b7: map_key_clear(KEY_STOPCD);		break;
+		case 0x0b8: map_key_clear(KEY_EJECTCD);		break;
+		case 0x0bc: map_key_clear(KEY_MEDIA_REPEAT);	break;
+
+		case 0x0cd: map_key_clear(KEY_PLAYPAUSE);	break;
+		case 0x0e0: map_abs_clear(ABS_VOLUME);		break;
+		case 0x0e2: map_key_clear(KEY_MUTE);		break;
+		case 0x0e5: map_key_clear(KEY_BASSBOOST);	break;
+		case 0x0e9: map_key_clear(KEY_VOLUMEUP);	break;
+		case 0x0ea: map_key_clear(KEY_VOLUMEDOWN);	break;
+
+		case 0x182: map_key_clear(KEY_BOOKMARKS);	break;
+		case 0x183: map_key_clear(KEY_CONFIG);		break;
+		case 0x184: map_key_clear(KEY_WORDPROCESSOR);	break;
+		case 0x185: map_key_clear(KEY_EDITOR);		break;
+		case 0x186: map_key_clear(KEY_SPREADSHEET);	break;
+		case 0x187: map_key_clear(KEY_GRAPHICSEDITOR);	break;
+		case 0x188: map_key_clear(KEY_PRESENTATION);	break;
+		case 0x189: map_key_clear(KEY_DATABASE);	break;
+		case 0x18a: map_key_clear(KEY_MAIL);		break;
+		case 0x18b: map_key_clear(KEY_NEWS);		break;
+		case 0x18c: map_key_clear(KEY_VOICEMAIL);	break;
+		case 0x18d: map_key_clear(KEY_ADDRESSBOOK);	break;
+		case 0x18e: map_key_clear(KEY_CALENDAR);	break;
+		case 0x191: map_key_clear(KEY_FINANCE);		break;
+		case 0x192: map_key_clear(KEY_CALC);		break;
+		case 0x194: map_key_clear(KEY_FILE);		break;
+		case 0x196: map_key_clear(KEY_WWW);		break;
+		case 0x19c: map_key_clear(KEY_LOGOFF);		break;
+		case 0x19e: map_key_clear(KEY_COFFEE);		break;
+		case 0x1a6: map_key_clear(KEY_HELP);		break;
+		case 0x1a7: map_key_clear(KEY_DOCUMENTS);	break;
+		case 0x1ab: map_key_clear(KEY_SPELLCHECK);	break;
+		case 0x1b6: map_key_clear(KEY_MEDIA);		break;
+		case 0x1b7: map_key_clear(KEY_SOUND);		break;
+		case 0x1bc: map_key_clear(KEY_MESSENGER);	break;
+		case 0x1bd: map_key_clear(KEY_INFO);		break;
+		case 0x201: map_key_clear(KEY_NEW);		break;
+		case 0x202: map_key_clear(KEY_OPEN);		break;
+		case 0x203: map_key_clear(KEY_CLOSE);		break;
+		case 0x204: map_key_clear(KEY_EXIT);		break;
+		case 0x207: map_key_clear(KEY_SAVE);		break;
+		case 0x208: map_key_clear(KEY_PRINT);		break;
+		case 0x209: map_key_clear(KEY_PROPS);		break;
+		case 0x21a: map_key_clear(KEY_UNDO);		break;
+		case 0x21b: map_key_clear(KEY_COPY);		break;
+		case 0x21c: map_key_clear(KEY_CUT);		break;
+		case 0x21d: map_key_clear(KEY_PASTE);		break;
+		case 0x21f: map_key_clear(KEY_FIND);		break;
+		case 0x221: map_key_clear(KEY_SEARCH);		break;
+		case 0x222: map_key_clear(KEY_GOTO);		break;
+		case 0x223: map_key_clear(KEY_HOMEPAGE);	break;
+		case 0x224: map_key_clear(KEY_BACK);		break;
+		case 0x225: map_key_clear(KEY_FORWARD);		break;
+		case 0x226: map_key_clear(KEY_STOP);		break;
+		case 0x227: map_key_clear(KEY_REFRESH);		break;
+		case 0x22a: map_key_clear(KEY_BOOKMARKS);	break;
+		case 0x22d: map_key_clear(KEY_ZOOMIN);		break;
+		case 0x22e: map_key_clear(KEY_ZOOMOUT);		break;
+		case 0x22f: map_key_clear(KEY_ZOOMRESET);	break;
+		case 0x233: map_key_clear(KEY_SCROLLUP);	break;
+		case 0x234: map_key_clear(KEY_SCROLLDOWN);	break;
+		case 0x238: map_rel(REL_HWHEEL);		break;
+		case 0x25f: map_key_clear(KEY_CANCEL);		break;
+		case 0x279: map_key_clear(KEY_REDO);		break;
+
+		case 0x289: map_key_clear(KEY_REPLY);		break;
+		case 0x28b: map_key_clear(KEY_FORWARDMAIL);	break;
+		case 0x28c: map_key_clear(KEY_SEND);		break;
+
+		default:    goto ignore;
+		}
+		break;
+
+	case HID_UP_HPVENDOR:	/* Reported on a Dutch layout HP5308 */
+		set_bit(EV_REP, input->evbit);
+		switch (usage->hid & HID_USAGE) {
+		case 0x021: map_key_clear(KEY_PRINT);           break;
+		case 0x070: map_key_clear(KEY_HP);		break;
+		case 0x071: map_key_clear(KEY_CAMERA);		break;
+		case 0x072: map_key_clear(KEY_SOUND);		break;
+		case 0x073: map_key_clear(KEY_QUESTION);	break;
+		case 0x080: map_key_clear(KEY_EMAIL);		break;
+		case 0x081: map_key_clear(KEY_CHAT);		break;
+		case 0x082: map_key_clear(KEY_SEARCH);		break;
+		case 0x083: map_key_clear(KEY_CONNECT);	        break;
+		case 0x084: map_key_clear(KEY_FINANCE);		break;
+		case 0x085: map_key_clear(KEY_SPORT);		break;
+		case 0x086: map_key_clear(KEY_SHOP);	        break;
+		default:    goto ignore;
+		}
+		break;
+
+	case HID_UP_MSVENDOR:
+		goto ignore;
+
+	case HID_UP_CUSTOM: /* Reported on Logitech and Apple USB keyboards */
+		set_bit(EV_REP, input->evbit);
+		goto ignore;
+
+	case HID_UP_LOGIVENDOR:
+		goto ignore;
+	
+	case HID_UP_PID:
+		switch (usage->hid & HID_USAGE) {
+		case 0xa4: map_key_clear(BTN_DEAD);	break;
+		default: goto ignore;
+		}
+		break;
+
+	default:
+	unknown:
+		if (field->report_size == 1) {
+			if (field->report->type == HID_OUTPUT_REPORT) {
+				map_led(LED_MISC);
+				break;
+			}
+			map_key(BTN_MISC);
+			break;
+		}
+		if (field->flags & HID_MAIN_ITEM_RELATIVE) {
+			map_rel(REL_MISC);
+			break;
+		}
+		map_abs(ABS_MISC);
+		break;
 	}
 
 mapped:
-	if (device->quirks & HID_QUIRK_MIGHTYMOUSE) {
-		if (usage->hid == HID_GD_Z)
-			map_rel(REL_HWHEEL);
-		else if (usage->code == BTN_1)
-			map_key(BTN_2);
-		else if (usage->code == BTN_2)
-			map_key(BTN_1);
-	}
-
-	if ((device->quirks & (HID_QUIRK_2WHEEL_MOUSE_HACK_7 | HID_QUIRK_2WHEEL_MOUSE_HACK_5 |
-			HID_QUIRK_2WHEEL_MOUSE_HACK_B8)) && (usage->type == EV_REL) &&
-			(usage->code == REL_WHEEL))
-		set_bit(REL_HWHEEL, bit);
-
-	if (((device->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_5) && (usage->hid == 0x00090005))
-		|| ((device->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_7) && (usage->hid == 0x00090007)))
+	if (device->driver->input_mapped && device->driver->input_mapped(device,
+				hidinput, field, usage, &bit, &max) < 0)
 		goto ignore;
 
-	if ((device->quirks & HID_QUIRK_BAD_RELATIVE_KEYS) &&
-		usage->type == EV_KEY && (field->flags & HID_MAIN_ITEM_RELATIVE))
-		field->flags &= ~HID_MAIN_ITEM_RELATIVE;
-
 	set_bit(usage->type, input->evbit);
 
-	if (device->quirks & HID_QUIRK_DUPLICATE_USAGES &&
-			(usage->type == EV_KEY ||
-			 usage->type == EV_REL ||
-			 usage->type == EV_ABS))
-		clear_bit(usage->code, bit);
-
 	while (usage->code <= max && test_and_set_bit(usage->code, bit))
 		usage->code = find_next_zero_bit(bit, max + 1, usage->code);
 
@@ -858,10 +585,6 @@
 	if (!usage->type)
 		return;
 
-	/* handle input events for quirky devices */
-	if (hidinput_event_quirks(hid, field, usage, value))
-		return;
-
 	if (usage->hat_min < usage->hat_max || usage->hat_dir) {
 		int hat_dir = usage->hat_dir;
 		if (!hat_dir)
@@ -961,14 +684,14 @@
 {
 	struct hid_device *hid = input_get_drvdata(dev);
 
-	return hid->hid_open(hid);
+	return hid->ll_driver->open(hid);
 }
 
 static void hidinput_close(struct input_dev *dev)
 {
 	struct hid_device *hid = input_get_drvdata(dev);
 
-	hid->hid_close(hid);
+	hid->ll_driver->close(hid);
 }
 
 /*
@@ -977,7 +700,7 @@
  * Read all reports and initialize the absolute field values.
  */
 
-int hidinput_connect(struct hid_device *hid)
+int hidinput_connect(struct hid_device *hid, unsigned int force)
 {
 	struct hid_report *report;
 	struct hid_input *hidinput = NULL;
@@ -985,19 +708,20 @@
 	int i, j, k;
 	int max_report_type = HID_OUTPUT_REPORT;
 
-	if (hid->quirks & HID_QUIRK_IGNORE_HIDINPUT)
-		return -1;
-
 	INIT_LIST_HEAD(&hid->inputs);
 
-	for (i = 0; i < hid->maxcollection; i++)
-		if (hid->collection[i].type == HID_COLLECTION_APPLICATION ||
-		    hid->collection[i].type == HID_COLLECTION_PHYSICAL)
-			if (IS_INPUT_APPLICATION(hid->collection[i].usage))
-				break;
+	if (!force) {
+		for (i = 0; i < hid->maxcollection; i++) {
+			struct hid_collection *col = &hid->collection[i];
+			if (col->type == HID_COLLECTION_APPLICATION ||
+					col->type == HID_COLLECTION_PHYSICAL)
+				if (IS_INPUT_APPLICATION(col->usage))
+					break;
+		}
 
-	if (i == hid->maxcollection && (hid->quirks & HID_QUIRK_HIDINPUT) == 0)
-		return -1;
+		if (i == hid->maxcollection)
+			return -1;
+	}
 
 	if (hid->quirks & HID_QUIRK_SKIP_OUTPUT_REPORTS)
 		max_report_type = HID_INPUT_REPORT;
@@ -1019,7 +743,8 @@
 				}
 
 				input_set_drvdata(input_dev, hid);
-				input_dev->event = hid->hidinput_input_event;
+				input_dev->event =
+					hid->ll_driver->hidinput_input_event;
 				input_dev->open = hidinput_open;
 				input_dev->close = hidinput_close;
 				input_dev->setkeycode = hidinput_setkeycode;
@@ -1032,7 +757,7 @@
 				input_dev->id.vendor  = hid->vendor;
 				input_dev->id.product = hid->product;
 				input_dev->id.version = hid->version;
-				input_dev->dev.parent = hid->dev;
+				input_dev->dev.parent = hid->dev.parent;
 				hidinput->input = input_dev;
 				list_add_tail(&hidinput->list, &hid->inputs);
 			}
diff --git a/drivers/hid/hid-lg.c b/drivers/hid/hid-lg.c
new file mode 100644
index 0000000..406d8c8
--- /dev/null
+++ b/drivers/hid/hid-lg.c
@@ -0,0 +1,342 @@
+/*
+ *  HID driver for some logitech "special" devices
+ *
+ *  Copyright (c) 1999 Andreas Gal
+ *  Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
+ *  Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
+ *  Copyright (c) 2006-2007 Jiri Kosina
+ *  Copyright (c) 2007 Paul Walmsley
+ *  Copyright (c) 2008 Jiri Slaby
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or 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/device.h>
+#include <linux/hid.h>
+#include <linux/module.h>
+
+#include "hid-ids.h"
+#include "hid-lg.h"
+
+#define LG_RDESC		0x001
+#define LG_BAD_RELATIVE_KEYS	0x002
+#define LG_DUPLICATE_USAGES	0x004
+#define LG_RESET_LEDS		0x008
+#define LG_EXPANDED_KEYMAP	0x010
+#define LG_IGNORE_DOUBLED_WHEEL	0x020
+#define LG_WIRELESS		0x040
+#define LG_INVERT_HWHEEL	0x080
+#define LG_NOGET		0x100
+#define LG_FF			0x200
+#define LG_FF2			0x400
+
+/*
+ * Certain Logitech keyboards send in report #3 keys which are far
+ * above the logical maximum described in descriptor. This extends
+ * the original value of 0x28c of logical maximum to 0x104d
+ */
+static void lg_report_fixup(struct hid_device *hdev, __u8 *rdesc,
+		unsigned int rsize)
+{
+	unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
+
+	if ((quirks & LG_RDESC) && rsize >= 90 && rdesc[83] == 0x26 &&
+			rdesc[84] == 0x8c && rdesc[85] == 0x02) {
+		dev_info(&hdev->dev, "fixing up Logitech keyboard report "
+				"descriptor\n");
+		rdesc[84] = rdesc[89] = 0x4d;
+		rdesc[85] = rdesc[90] = 0x10;
+	}
+}
+
+#define lg_map_key_clear(c)	hid_map_usage_clear(hi, usage, bit, max, \
+		EV_KEY, (c))
+
+static int lg_ultrax_remote_mapping(struct hid_input *hi,
+		struct hid_usage *usage, unsigned long **bit, int *max)
+{
+	if ((usage->hid & HID_USAGE_PAGE) != HID_UP_LOGIVENDOR)
+		return 0;
+
+	set_bit(EV_REP, hi->input->evbit);
+	switch (usage->hid & HID_USAGE) {
+	/* Reported on Logitech Ultra X Media Remote */
+	case 0x004: lg_map_key_clear(KEY_AGAIN);	break;
+	case 0x00d: lg_map_key_clear(KEY_HOME);		break;
+	case 0x024: lg_map_key_clear(KEY_SHUFFLE);	break;
+	case 0x025: lg_map_key_clear(KEY_TV);		break;
+	case 0x026: lg_map_key_clear(KEY_MENU);		break;
+	case 0x031: lg_map_key_clear(KEY_AUDIO);	break;
+	case 0x032: lg_map_key_clear(KEY_TEXT);		break;
+	case 0x033: lg_map_key_clear(KEY_LAST);		break;
+	case 0x047: lg_map_key_clear(KEY_MP3);		break;
+	case 0x048: lg_map_key_clear(KEY_DVD);		break;
+	case 0x049: lg_map_key_clear(KEY_MEDIA);	break;
+	case 0x04a: lg_map_key_clear(KEY_VIDEO);	break;
+	case 0x04b: lg_map_key_clear(KEY_ANGLE);	break;
+	case 0x04c: lg_map_key_clear(KEY_LANGUAGE);	break;
+	case 0x04d: lg_map_key_clear(KEY_SUBTITLE);	break;
+	case 0x051: lg_map_key_clear(KEY_RED);		break;
+	case 0x052: lg_map_key_clear(KEY_CLOSE);	break;
+
+	default:
+		return 0;
+	}
+	return 1;
+}
+
+static int lg_wireless_mapping(struct hid_input *hi, struct hid_usage *usage,
+		unsigned long **bit, int *max)
+{
+	if ((usage->hid & HID_USAGE_PAGE) != HID_UP_CONSUMER)
+		return 0;
+
+	switch (usage->hid & HID_USAGE) {
+	case 0x1001: lg_map_key_clear(KEY_MESSENGER);		break;
+	case 0x1003: lg_map_key_clear(KEY_SOUND);		break;
+	case 0x1004: lg_map_key_clear(KEY_VIDEO);		break;
+	case 0x1005: lg_map_key_clear(KEY_AUDIO);		break;
+	case 0x100a: lg_map_key_clear(KEY_DOCUMENTS);		break;
+	case 0x1011: lg_map_key_clear(KEY_PREVIOUSSONG);	break;
+	case 0x1012: lg_map_key_clear(KEY_NEXTSONG);		break;
+	case 0x1013: lg_map_key_clear(KEY_CAMERA);		break;
+	case 0x1014: lg_map_key_clear(KEY_MESSENGER);		break;
+	case 0x1015: lg_map_key_clear(KEY_RECORD);		break;
+	case 0x1016: lg_map_key_clear(KEY_PLAYER);		break;
+	case 0x1017: lg_map_key_clear(KEY_EJECTCD);		break;
+	case 0x1018: lg_map_key_clear(KEY_MEDIA);		break;
+	case 0x1019: lg_map_key_clear(KEY_PROG1);		break;
+	case 0x101a: lg_map_key_clear(KEY_PROG2);		break;
+	case 0x101b: lg_map_key_clear(KEY_PROG3);		break;
+	case 0x101f: lg_map_key_clear(KEY_ZOOMIN);		break;
+	case 0x1020: lg_map_key_clear(KEY_ZOOMOUT);		break;
+	case 0x1021: lg_map_key_clear(KEY_ZOOMRESET);		break;
+	case 0x1023: lg_map_key_clear(KEY_CLOSE);		break;
+	case 0x1027: lg_map_key_clear(KEY_MENU);		break;
+	/* this one is marked as 'Rotate' */
+	case 0x1028: lg_map_key_clear(KEY_ANGLE);		break;
+	case 0x1029: lg_map_key_clear(KEY_SHUFFLE);		break;
+	case 0x102a: lg_map_key_clear(KEY_BACK);		break;
+	case 0x102b: lg_map_key_clear(KEY_CYCLEWINDOWS);	break;
+	case 0x1041: lg_map_key_clear(KEY_BATTERY);		break;
+	case 0x1042: lg_map_key_clear(KEY_WORDPROCESSOR);	break;
+	case 0x1043: lg_map_key_clear(KEY_SPREADSHEET);		break;
+	case 0x1044: lg_map_key_clear(KEY_PRESENTATION);	break;
+	case 0x1045: lg_map_key_clear(KEY_UNDO);		break;
+	case 0x1046: lg_map_key_clear(KEY_REDO);		break;
+	case 0x1047: lg_map_key_clear(KEY_PRINT);		break;
+	case 0x1048: lg_map_key_clear(KEY_SAVE);		break;
+	case 0x1049: lg_map_key_clear(KEY_PROG1);		break;
+	case 0x104a: lg_map_key_clear(KEY_PROG2);		break;
+	case 0x104b: lg_map_key_clear(KEY_PROG3);		break;
+	case 0x104c: lg_map_key_clear(KEY_PROG4);		break;
+
+	default:
+		return 0;
+	}
+	return 1;
+}
+
+static int lg_input_mapping(struct hid_device *hdev, struct hid_input *hi,
+		struct hid_field *field, struct hid_usage *usage,
+		unsigned long **bit, int *max)
+{
+	/* extended mapping for certain Logitech hardware (Logitech cordless
+	   desktop LX500) */
+	static const u8 e_keymap[] = {
+		  0,216,  0,213,175,156,  0,  0,  0,  0,
+		144,  0,  0,  0,  0,  0,  0,  0,  0,212,
+		174,167,152,161,112,  0,  0,  0,154,  0,
+		  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+		  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+		  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+		  0,  0,  0,  0,  0,183,184,185,186,187,
+		188,189,190,191,192,193,194,  0,  0,  0
+	};
+	unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
+	unsigned int hid = usage->hid;
+
+	if (hdev->product == USB_DEVICE_ID_LOGITECH_RECEIVER &&
+			lg_ultrax_remote_mapping(hi, usage, bit, max))
+		return 1;
+
+	if ((quirks & LG_WIRELESS) && lg_wireless_mapping(hi, usage, bit, max))
+		return 1;
+
+	if ((hid & HID_USAGE_PAGE) != HID_UP_BUTTON)
+		return 0;
+
+	hid &= HID_USAGE;
+
+	/* Special handling for Logitech Cordless Desktop */
+	if (field->application == HID_GD_MOUSE) {
+		if ((quirks & LG_IGNORE_DOUBLED_WHEEL) &&
+				(hid == 7 || hid == 8))
+			return -1;
+	} else {
+		if ((quirks & LG_EXPANDED_KEYMAP) &&
+				hid < ARRAY_SIZE(e_keymap) &&
+				e_keymap[hid] != 0) {
+			hid_map_usage(hi, usage, bit, max, EV_KEY,
+					e_keymap[hid]);
+			return 1;
+		}
+	}
+
+	return 0;
+}
+
+static int lg_input_mapped(struct hid_device *hdev, struct hid_input *hi,
+		struct hid_field *field, struct hid_usage *usage,
+		unsigned long **bit, int *max)
+{
+	unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
+
+	if ((quirks & LG_BAD_RELATIVE_KEYS) && usage->type == EV_KEY &&
+			(field->flags & HID_MAIN_ITEM_RELATIVE))
+		field->flags &= ~HID_MAIN_ITEM_RELATIVE;
+
+	if ((quirks & LG_DUPLICATE_USAGES) && (usage->type == EV_KEY ||
+			 usage->type == EV_REL || usage->type == EV_ABS))
+		clear_bit(usage->code, *bit);
+
+	return 0;
+}
+
+static int lg_event(struct hid_device *hdev, struct hid_field *field,
+		struct hid_usage *usage, __s32 value)
+{
+	unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
+
+	if ((quirks & LG_INVERT_HWHEEL) && usage->code == REL_HWHEEL) {
+		input_event(field->hidinput->input, usage->type, usage->code,
+				-value);
+		return 1;
+	}
+
+	return 0;
+}
+
+static int lg_probe(struct hid_device *hdev, const struct hid_device_id *id)
+{
+	unsigned long quirks = id->driver_data;
+	unsigned int connect_mask = HID_CONNECT_DEFAULT;
+	int ret;
+
+	hid_set_drvdata(hdev, (void *)quirks);
+
+	if (quirks & LG_NOGET)
+		hdev->quirks |= HID_QUIRK_NOGET;
+
+	ret = hid_parse(hdev);
+	if (ret) {
+		dev_err(&hdev->dev, "parse failed\n");
+		goto err_free;
+	}
+
+	if (quirks & (LG_FF | LG_FF2))
+		connect_mask &= ~HID_CONNECT_FF;
+
+	ret = hid_hw_start(hdev, connect_mask);
+	if (ret) {
+		dev_err(&hdev->dev, "hw start failed\n");
+		goto err_free;
+	}
+
+	if (quirks & LG_RESET_LEDS)
+		usbhid_set_leds(hdev);
+
+	if (quirks & LG_FF)
+		lgff_init(hdev);
+	if (quirks & LG_FF2)
+		lg2ff_init(hdev);
+
+	return 0;
+err_free:
+	return ret;
+}
+
+static const struct hid_device_id lg_devices[] = {
+	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_MX3000_RECEIVER),
+		.driver_data = LG_RDESC | LG_WIRELESS },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER),
+		.driver_data = LG_RDESC | LG_WIRELESS },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER_2),
+		.driver_data = LG_RDESC | LG_WIRELESS },
+
+	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RECEIVER),
+		.driver_data = LG_BAD_RELATIVE_KEYS },
+
+	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_DESKTOP),
+		.driver_data = LG_DUPLICATE_USAGES },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_EDGE),
+		.driver_data = LG_DUPLICATE_USAGES },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_MINI),
+		.driver_data = LG_DUPLICATE_USAGES },
+
+	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_KBD),
+		.driver_data = LG_RESET_LEDS },
+
+	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_ELITE_KBD),
+		.driver_data = LG_IGNORE_DOUBLED_WHEEL | LG_EXPANDED_KEYMAP },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_CORDLESS_DESKTOP_LX500),
+		.driver_data = LG_IGNORE_DOUBLED_WHEEL | LG_EXPANDED_KEYMAP },
+
+	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_LX3),
+		.driver_data = LG_INVERT_HWHEEL },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_V150),
+		.driver_data = LG_INVERT_HWHEEL },
+
+	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_EXTREME_3D),
+		.driver_data = LG_NOGET },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WHEEL),
+		.driver_data = LG_NOGET | LG_FF },
+
+	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD),
+		.driver_data = LG_FF },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2_2),
+		.driver_data = LG_FF },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_F3D),
+		.driver_data = LG_FF },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_FORCE3D_PRO),
+		.driver_data = LG_FF },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL),
+		.driver_data = LG_FF },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2),
+		.driver_data = LG_FF },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2),
+		.driver_data = LG_FF2 },
+	{ }
+};
+MODULE_DEVICE_TABLE(hid, lg_devices);
+
+static struct hid_driver lg_driver = {
+	.name = "logitech",
+	.id_table = lg_devices,
+	.report_fixup = lg_report_fixup,
+	.input_mapping = lg_input_mapping,
+	.input_mapped = lg_input_mapped,
+	.event = lg_event,
+	.probe = lg_probe,
+};
+
+static int lg_init(void)
+{
+	return hid_register_driver(&lg_driver);
+}
+
+static void lg_exit(void)
+{
+	hid_unregister_driver(&lg_driver);
+}
+
+module_init(lg_init);
+module_exit(lg_exit);
+MODULE_LICENSE("GPL");
+
+HID_COMPAT_LOAD_DRIVER(logitech);
diff --git a/drivers/hid/hid-lg.h b/drivers/hid/hid-lg.h
new file mode 100644
index 0000000..27ae750
--- /dev/null
+++ b/drivers/hid/hid-lg.h
@@ -0,0 +1,18 @@
+#ifndef __HID_LG_H
+#define __HID_LG_H
+
+#include <linux/autoconf.h>
+
+#ifdef CONFIG_LOGITECH_FF
+int lgff_init(struct hid_device *hdev);
+#else
+static inline int lgff_init(struct hid_device *hdev) { return -1; }
+#endif
+
+#ifdef CONFIG_LOGIRUMBLEPAD2_FF
+int lg2ff_init(struct hid_device *hdev);
+#else
+static inline int lg2ff_init(struct hid_device *hdev) { return -1; }
+#endif
+
+#endif
diff --git a/drivers/hid/hid-lg2ff.c b/drivers/hid/hid-lg2ff.c
new file mode 100644
index 0000000..4e6dc6e
--- /dev/null
+++ b/drivers/hid/hid-lg2ff.c
@@ -0,0 +1,116 @@
+/*
+ *  Force feedback support for Logitech Rumblepad 2
+ *
+ *  Copyright (c) 2008 Anssi Hannula <anssi.hannula@gmail.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/input.h>
+#include <linux/usb.h>
+#include <linux/hid.h>
+
+#include "usbhid/usbhid.h"
+#include "hid-lg.h"
+
+struct lg2ff_device {
+	struct hid_report *report;
+};
+
+static int play_effect(struct input_dev *dev, void *data,
+			 struct ff_effect *effect)
+{
+	struct hid_device *hid = input_get_drvdata(dev);
+	struct lg2ff_device *lg2ff = data;
+	int weak, strong;
+
+	strong = effect->u.rumble.strong_magnitude;
+	weak = effect->u.rumble.weak_magnitude;
+
+	if (weak || strong) {
+		weak = weak * 0xff / 0xffff;
+		strong = strong * 0xff / 0xffff;
+
+		lg2ff->report->field[0]->value[0] = 0x51;
+		lg2ff->report->field[0]->value[2] = weak;
+		lg2ff->report->field[0]->value[4] = strong;
+	} else {
+		lg2ff->report->field[0]->value[0] = 0xf3;
+		lg2ff->report->field[0]->value[2] = 0x00;
+		lg2ff->report->field[0]->value[4] = 0x00;
+	}
+
+	usbhid_submit_report(hid, lg2ff->report, USB_DIR_OUT);
+	return 0;
+}
+
+int lg2ff_init(struct hid_device *hid)
+{
+	struct lg2ff_device *lg2ff;
+	struct hid_report *report;
+	struct hid_input *hidinput = list_entry(hid->inputs.next,
+						struct hid_input, list);
+	struct list_head *report_list =
+			&hid->report_enum[HID_OUTPUT_REPORT].report_list;
+	struct input_dev *dev = hidinput->input;
+	int error;
+
+	if (list_empty(report_list)) {
+		dev_err(&hid->dev, "no output report found\n");
+		return -ENODEV;
+	}
+
+	report = list_entry(report_list->next, struct hid_report, list);
+
+	if (report->maxfield < 1) {
+		dev_err(&hid->dev, "output report is empty\n");
+		return -ENODEV;
+	}
+	if (report->field[0]->report_count < 7) {
+		dev_err(&hid->dev, "not enough values in the field\n");
+		return -ENODEV;
+	}
+
+	lg2ff = kmalloc(sizeof(struct lg2ff_device), GFP_KERNEL);
+	if (!lg2ff)
+		return -ENOMEM;
+
+	set_bit(FF_RUMBLE, dev->ffbit);
+
+	error = input_ff_create_memless(dev, lg2ff, play_effect);
+	if (error) {
+		kfree(lg2ff);
+		return error;
+	}
+
+	lg2ff->report = report;
+	report->field[0]->value[0] = 0xf3;
+	report->field[0]->value[1] = 0x00;
+	report->field[0]->value[2] = 0x00;
+	report->field[0]->value[3] = 0x00;
+	report->field[0]->value[4] = 0x00;
+	report->field[0]->value[5] = 0x00;
+	report->field[0]->value[6] = 0x00;
+
+	usbhid_submit_report(hid, report, USB_DIR_OUT);
+
+	dev_info(&hid->dev, "Force feedback for Logitech Rumblepad 2 by "
+	       "Anssi Hannula <anssi.hannula@gmail.com>\n");
+
+	return 0;
+}
diff --git a/drivers/hid/hid-lgff.c b/drivers/hid/hid-lgff.c
new file mode 100644
index 0000000..51aff08
--- /dev/null
+++ b/drivers/hid/hid-lgff.c
@@ -0,0 +1,179 @@
+/*
+ * Force feedback support for hid-compliant for some of the devices from
+ * Logitech, namely:
+ * - WingMan Cordless RumblePad
+ * - WingMan Force 3D
+ *
+ *  Copyright (c) 2002-2004 Johann Deneux
+ *  Copyright (c) 2006 Anssi Hannula <anssi.hannula@gmail.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
+ *
+ * Should you need to contact me, the author, you can do so by
+ * e-mail - mail your message to <johann.deneux@it.uu.se>
+ */
+
+#include <linux/input.h>
+#include <linux/usb.h>
+#include <linux/hid.h>
+
+#include "usbhid/usbhid.h"
+#include "hid-lg.h"
+
+struct dev_type {
+	u16 idVendor;
+	u16 idProduct;
+	const signed short *ff;
+};
+
+static const signed short ff_rumble[] = {
+	FF_RUMBLE,
+	-1
+};
+
+static const signed short ff_joystick[] = {
+	FF_CONSTANT,
+	-1
+};
+
+static const signed short ff_wheel[] = {
+	FF_CONSTANT,
+	FF_AUTOCENTER,
+	-1
+};
+
+static const struct dev_type devices[] = {
+	{ 0x046d, 0xc211, ff_rumble },
+	{ 0x046d, 0xc219, ff_rumble },
+	{ 0x046d, 0xc283, ff_joystick },
+	{ 0x046d, 0xc286, ff_joystick },
+	{ 0x046d, 0xc294, ff_joystick },
+	{ 0x046d, 0xc295, ff_joystick },
+	{ 0x046d, 0xca03, ff_wheel },
+};
+
+static int hid_lgff_play(struct input_dev *dev, void *data, struct ff_effect *effect)
+{
+	struct hid_device *hid = input_get_drvdata(dev);
+	struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list;
+	struct hid_report *report = list_entry(report_list->next, struct hid_report, list);
+	int x, y;
+	unsigned int left, right;
+
+#define CLAMP(x) if (x < 0) x = 0; if (x > 0xff) x = 0xff
+
+	switch (effect->type) {
+	case FF_CONSTANT:
+		x = effect->u.ramp.start_level + 0x7f;	/* 0x7f is center */
+		y = effect->u.ramp.end_level + 0x7f;
+		CLAMP(x);
+		CLAMP(y);
+		report->field[0]->value[0] = 0x51;
+		report->field[0]->value[1] = 0x08;
+		report->field[0]->value[2] = x;
+		report->field[0]->value[3] = y;
+		dbg_hid("(x, y)=(%04x, %04x)\n", x, y);
+		usbhid_submit_report(hid, report, USB_DIR_OUT);
+		break;
+
+	case FF_RUMBLE:
+		right = effect->u.rumble.strong_magnitude;
+		left = effect->u.rumble.weak_magnitude;
+		right = right * 0xff / 0xffff;
+		left = left * 0xff / 0xffff;
+		CLAMP(left);
+		CLAMP(right);
+		report->field[0]->value[0] = 0x42;
+		report->field[0]->value[1] = 0x00;
+		report->field[0]->value[2] = left;
+		report->field[0]->value[3] = right;
+		dbg_hid("(left, right)=(%04x, %04x)\n", left, right);
+		usbhid_submit_report(hid, report, USB_DIR_OUT);
+		break;
+	}
+	return 0;
+}
+
+static void hid_lgff_set_autocenter(struct input_dev *dev, u16 magnitude)
+{
+	struct hid_device *hid = input_get_drvdata(dev);
+	struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list;
+	struct hid_report *report = list_entry(report_list->next, struct hid_report, list);
+	__s32 *value = report->field[0]->value;
+	magnitude = (magnitude >> 12) & 0xf;
+	*value++ = 0xfe;
+	*value++ = 0x0d;
+	*value++ = magnitude;   /* clockwise strength */
+	*value++ = magnitude;   /* counter-clockwise strength */
+	*value++ = 0x80;
+	*value++ = 0x00;
+	*value = 0x00;
+	usbhid_submit_report(hid, report, USB_DIR_OUT);
+}
+
+int lgff_init(struct hid_device* hid)
+{
+	struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, list);
+	struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list;
+	struct input_dev *dev = hidinput->input;
+	struct hid_report *report;
+	struct hid_field *field;
+	const signed short *ff_bits = ff_joystick;
+	int error;
+	int i;
+
+	/* Find the report to use */
+	if (list_empty(report_list)) {
+		err_hid("No output report found");
+		return -1;
+	}
+
+	/* Check that the report looks ok */
+	report = list_entry(report_list->next, struct hid_report, list);
+	if (!report) {
+		err_hid("NULL output report");
+		return -1;
+	}
+
+	field = report->field[0];
+	if (!field) {
+		err_hid("NULL field");
+		return -1;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(devices); i++) {
+		if (dev->id.vendor == devices[i].idVendor &&
+		    dev->id.product == devices[i].idProduct) {
+			ff_bits = devices[i].ff;
+			break;
+		}
+	}
+
+	for (i = 0; ff_bits[i] >= 0; i++)
+		set_bit(ff_bits[i], dev->ffbit);
+
+	error = input_ff_create_memless(dev, NULL, hid_lgff_play);
+	if (error)
+		return error;
+
+	if ( test_bit(FF_AUTOCENTER, dev->ffbit) )
+		dev->ff->set_autocenter = hid_lgff_set_autocenter;
+
+	printk(KERN_INFO "Force feedback for Logitech force feedback devices by Johann Deneux <johann.deneux@it.uu.se>\n");
+
+	return 0;
+}
diff --git a/drivers/hid/hid-microsoft.c b/drivers/hid/hid-microsoft.c
new file mode 100644
index 0000000..d718b16
--- /dev/null
+++ b/drivers/hid/hid-microsoft.c
@@ -0,0 +1,219 @@
+/*
+ *  HID driver for some microsoft "special" devices
+ *
+ *  Copyright (c) 1999 Andreas Gal
+ *  Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
+ *  Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
+ *  Copyright (c) 2006-2007 Jiri Kosina
+ *  Copyright (c) 2007 Paul Walmsley
+ *  Copyright (c) 2008 Jiri Slaby
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or 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/device.h>
+#include <linux/input.h>
+#include <linux/hid.h>
+#include <linux/module.h>
+
+#include "hid-ids.h"
+
+#define MS_HIDINPUT	0x01
+#define MS_ERGONOMY	0x02
+#define MS_PRESENTER	0x04
+#define MS_RDESC	0x08
+#define MS_NOGET	0x10
+
+/*
+ * Microsoft Wireless Desktop Receiver (Model 1028) has several
+ * 'Usage Min/Max' where it ought to have 'Physical Min/Max'
+ */
+static void ms_report_fixup(struct hid_device *hdev, __u8 *rdesc,
+		unsigned int rsize)
+{
+	unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
+
+	if ((quirks & MS_RDESC) && rsize == 571 && rdesc[284] == 0x19 &&
+			rdesc[286] == 0x2a && rdesc[304] == 0x19 &&
+			rdesc[306] == 0x29 && rdesc[352] == 0x1a &&
+			rdesc[355] == 0x2a && rdesc[557] == 0x19 &&
+			rdesc[559] == 0x29) {
+		dev_info(&hdev->dev, "fixing up Microsoft Wireless Receiver "
+				"Model 1028 report descriptor\n");
+		rdesc[284] = rdesc[304] = rdesc[557] = 0x35;
+		rdesc[352] = 0x36;
+		rdesc[286] = rdesc[355] = 0x46;
+		rdesc[306] = rdesc[559] = 0x45;
+	}
+}
+
+#define ms_map_key_clear(c)	hid_map_usage_clear(hi, usage, bit, max, \
+					EV_KEY, (c))
+static int ms_ergonomy_kb_quirk(struct hid_input *hi, struct hid_usage *usage,
+		unsigned long **bit, int *max)
+{
+	struct input_dev *input = hi->input;
+
+	switch (usage->hid & HID_USAGE) {
+	case 0xfd06: ms_map_key_clear(KEY_CHAT);	break;
+	case 0xfd07: ms_map_key_clear(KEY_PHONE);	break;
+	case 0xff05:
+		set_bit(EV_REP, input->evbit);
+		ms_map_key_clear(KEY_F13);
+		set_bit(KEY_F14, input->keybit);
+		set_bit(KEY_F15, input->keybit);
+		set_bit(KEY_F16, input->keybit);
+		set_bit(KEY_F17, input->keybit);
+		set_bit(KEY_F18, input->keybit);
+	default:
+		return 0;
+	}
+	return 1;
+}
+
+static int ms_presenter_8k_quirk(struct hid_input *hi, struct hid_usage *usage,
+		unsigned long **bit, int *max)
+{
+	set_bit(EV_REP, hi->input->evbit);
+	switch (usage->hid & HID_USAGE) {
+	case 0xfd08: ms_map_key_clear(KEY_FORWARD);	break;
+	case 0xfd09: ms_map_key_clear(KEY_BACK);	break;
+	case 0xfd0b: ms_map_key_clear(KEY_PLAYPAUSE);	break;
+	case 0xfd0e: ms_map_key_clear(KEY_CLOSE);	break;
+	case 0xfd0f: ms_map_key_clear(KEY_PLAY);	break;
+	default:
+		return 0;
+	}
+	return 1;
+}
+
+static int ms_input_mapping(struct hid_device *hdev, struct hid_input *hi,
+		struct hid_field *field, struct hid_usage *usage,
+		unsigned long **bit, int *max)
+{
+	unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
+
+	if ((usage->hid & HID_USAGE_PAGE) != HID_UP_MSVENDOR)
+		return 0;
+
+	if (quirks & MS_ERGONOMY) {
+		int ret = ms_ergonomy_kb_quirk(hi, usage, bit, max);
+		if (ret)
+			return ret;
+	}
+
+	if ((quirks & MS_PRESENTER) &&
+			ms_presenter_8k_quirk(hi, usage, bit, max))
+		return 1;
+
+	return 0;
+}
+
+static int ms_event(struct hid_device *hdev, struct hid_field *field,
+		struct hid_usage *usage, __s32 value)
+{
+	unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
+
+	if (!(hdev->claimed & HID_CLAIMED_INPUT) || !field->hidinput ||
+			!usage->type)
+		return 0;
+
+	/* Handling MS keyboards special buttons */
+	if (quirks & MS_ERGONOMY && usage->hid == (HID_UP_MSVENDOR | 0xff05)) {
+		struct input_dev *input = field->hidinput->input;
+		static unsigned int last_key = 0;
+		unsigned int key = 0;
+		switch (value) {
+		case 0x01: key = KEY_F14; break;
+		case 0x02: key = KEY_F15; break;
+		case 0x04: key = KEY_F16; break;
+		case 0x08: key = KEY_F17; break;
+		case 0x10: key = KEY_F18; break;
+		}
+		if (key) {
+			input_event(input, usage->type, key, 1);
+			last_key = key;
+		} else
+			input_event(input, usage->type, last_key, 0);
+
+		return 1;
+	}
+
+	return 0;
+}
+
+static int ms_probe(struct hid_device *hdev, const struct hid_device_id *id)
+{
+	unsigned long quirks = id->driver_data;
+	int ret;
+
+	hid_set_drvdata(hdev, (void *)quirks);
+
+	if (quirks & MS_NOGET)
+		hdev->quirks |= HID_QUIRK_NOGET;
+
+	ret = hid_parse(hdev);
+	if (ret) {
+		dev_err(&hdev->dev, "parse failed\n");
+		goto err_free;
+	}
+
+	ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT | ((quirks & MS_HIDINPUT) ?
+				HID_CONNECT_HIDINPUT_FORCE : 0));
+	if (ret) {
+		dev_err(&hdev->dev, "hw start failed\n");
+		goto err_free;
+	}
+
+	return 0;
+err_free:
+	return ret;
+}
+
+static const struct hid_device_id ms_devices[] = {
+	{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_SIDEWINDER_GV),
+		.driver_data = MS_HIDINPUT },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_NE4K),
+		.driver_data = MS_ERGONOMY },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_LK6K),
+		.driver_data = MS_ERGONOMY | MS_RDESC },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_PRESENTER_8K_USB),
+		.driver_data = MS_PRESENTER },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_WIRELESS_OPTICAL_DESKTOP_3_0),
+		.driver_data = MS_NOGET },
+
+	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_PRESENTER_8K_BT),
+		.driver_data = MS_PRESENTER },
+	{ }
+};
+MODULE_DEVICE_TABLE(hid, ms_devices);
+
+static struct hid_driver ms_driver = {
+	.name = "microsoft",
+	.id_table = ms_devices,
+	.report_fixup = ms_report_fixup,
+	.input_mapping = ms_input_mapping,
+	.event = ms_event,
+	.probe = ms_probe,
+};
+
+static int ms_init(void)
+{
+	return hid_register_driver(&ms_driver);
+}
+
+static void ms_exit(void)
+{
+	hid_unregister_driver(&ms_driver);
+}
+
+module_init(ms_init);
+module_exit(ms_exit);
+MODULE_LICENSE("GPL");
+
+HID_COMPAT_LOAD_DRIVER(microsoft);
diff --git a/drivers/hid/hid-monterey.c b/drivers/hid/hid-monterey.c
new file mode 100644
index 0000000..f3a85a0
--- /dev/null
+++ b/drivers/hid/hid-monterey.c
@@ -0,0 +1,82 @@
+/*
+ *  HID driver for some monterey "special" devices
+ *
+ *  Copyright (c) 1999 Andreas Gal
+ *  Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
+ *  Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
+ *  Copyright (c) 2006-2007 Jiri Kosina
+ *  Copyright (c) 2007 Paul Walmsley
+ *  Copyright (c) 2008 Jiri Slaby
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or 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/device.h>
+#include <linux/hid.h>
+#include <linux/module.h>
+
+#include "hid-ids.h"
+
+static void mr_report_fixup(struct hid_device *hdev, __u8 *rdesc,
+		unsigned int rsize)
+{
+	if (rsize >= 30 && rdesc[29] == 0x05 && rdesc[30] == 0x09) {
+		dev_info(&hdev->dev, "fixing up button/consumer in HID report "
+				"descriptor\n");
+		rdesc[30] = 0x0c;
+	}
+}
+
+#define mr_map_key_clear(c)	hid_map_usage_clear(hi, usage, bit, max, \
+					EV_KEY, (c))
+static int mr_input_mapping(struct hid_device *hdev, struct hid_input *hi,
+		struct hid_field *field, struct hid_usage *usage,
+		unsigned long **bit, int *max)
+{
+	if ((usage->hid & HID_USAGE_PAGE) != HID_UP_CONSUMER)
+		return 0;
+
+	switch (usage->hid & HID_USAGE) {
+	case 0x156: mr_map_key_clear(KEY_WORDPROCESSOR);	break;
+	case 0x157: mr_map_key_clear(KEY_SPREADSHEET);		break;
+	case 0x158: mr_map_key_clear(KEY_PRESENTATION);		break;
+	case 0x15c: mr_map_key_clear(KEY_STOP);			break;
+	default:
+		return 0;
+	}
+	return 1;
+}
+
+static const struct hid_device_id mr_devices[] = {
+	{ HID_USB_DEVICE(USB_VENDOR_ID_MONTEREY, USB_DEVICE_ID_GENIUS_KB29E) },
+	{ }
+};
+MODULE_DEVICE_TABLE(hid, mr_devices);
+
+static struct hid_driver mr_driver = {
+	.name = "monterey",
+	.id_table = mr_devices,
+	.report_fixup = mr_report_fixup,
+	.input_mapping = mr_input_mapping,
+};
+
+static int mr_init(void)
+{
+	return hid_register_driver(&mr_driver);
+}
+
+static void mr_exit(void)
+{
+	hid_unregister_driver(&mr_driver);
+}
+
+module_init(mr_init);
+module_exit(mr_exit);
+MODULE_LICENSE("GPL");
+
+HID_COMPAT_LOAD_DRIVER(monterey);
diff --git a/drivers/hid/hid-petalynx.c b/drivers/hid/hid-petalynx.c
new file mode 100644
index 0000000..10945fe
--- /dev/null
+++ b/drivers/hid/hid-petalynx.c
@@ -0,0 +1,122 @@
+/*
+ *  HID driver for some petalynx "special" devices
+ *
+ *  Copyright (c) 1999 Andreas Gal
+ *  Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
+ *  Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
+ *  Copyright (c) 2006-2007 Jiri Kosina
+ *  Copyright (c) 2007 Paul Walmsley
+ *  Copyright (c) 2008 Jiri Slaby
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or 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/device.h>
+#include <linux/hid.h>
+#include <linux/module.h>
+
+#include "hid-ids.h"
+
+/* Petalynx Maxter Remote has maximum for consumer page set too low */
+static void pl_report_fixup(struct hid_device *hdev, __u8 *rdesc,
+		unsigned int rsize)
+{
+	if (rsize >= 60 && rdesc[39] == 0x2a && rdesc[40] == 0xf5 &&
+			rdesc[41] == 0x00 && rdesc[59] == 0x26 &&
+			rdesc[60] == 0xf9 && rdesc[61] == 0x00) {
+		dev_info(&hdev->dev, "fixing up Petalynx Maxter Remote report "
+				"descriptor\n");
+		rdesc[60] = 0xfa;
+		rdesc[40] = 0xfa;
+	}
+}
+
+#define pl_map_key_clear(c)	hid_map_usage_clear(hi, usage, bit, max, \
+					EV_KEY, (c))
+static int pl_input_mapping(struct hid_device *hdev, struct hid_input *hi,
+		struct hid_field *field, struct hid_usage *usage,
+		unsigned long **bit, int *max)
+{
+	if ((usage->hid & HID_USAGE_PAGE) == HID_UP_LOGIVENDOR) {
+		switch (usage->hid & HID_USAGE) {
+		case 0x05a: pl_map_key_clear(KEY_TEXT);		break;
+		case 0x05b: pl_map_key_clear(KEY_RED);		break;
+		case 0x05c: pl_map_key_clear(KEY_GREEN);	break;
+		case 0x05d: pl_map_key_clear(KEY_YELLOW);	break;
+		case 0x05e: pl_map_key_clear(KEY_BLUE);		break;
+		default:
+			return 0;
+		}
+		return 1;
+	}
+
+	if ((usage->hid & HID_USAGE_PAGE) == HID_UP_CONSUMER) {
+		switch (usage->hid & HID_USAGE) {
+		case 0x0f6: pl_map_key_clear(KEY_NEXT);		break;
+		case 0x0fa: pl_map_key_clear(KEY_BACK);		break;
+		default:
+			return 0;
+		}
+		return 1;
+	}
+
+	return 0;
+}
+
+static int pl_probe(struct hid_device *hdev, const struct hid_device_id *id)
+{
+	int ret;
+
+	hdev->quirks |= HID_QUIRK_NOGET;
+
+	ret = hid_parse(hdev);
+	if (ret) {
+		dev_err(&hdev->dev, "parse failed\n");
+		goto err_free;
+	}
+
+	ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
+	if (ret) {
+		dev_err(&hdev->dev, "hw start failed\n");
+		goto err_free;
+	}
+
+	return 0;
+err_free:
+	return ret;
+}
+
+static const struct hid_device_id pl_devices[] = {
+	{ HID_USB_DEVICE(USB_VENDOR_ID_PETALYNX, USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE) },
+	{ }
+};
+MODULE_DEVICE_TABLE(hid, pl_devices);
+
+static struct hid_driver pl_driver = {
+	.name = "petalynx",
+	.id_table = pl_devices,
+	.report_fixup = pl_report_fixup,
+	.input_mapping = pl_input_mapping,
+	.probe = pl_probe,
+};
+
+static int pl_init(void)
+{
+	return hid_register_driver(&pl_driver);
+}
+
+static void pl_exit(void)
+{
+	hid_unregister_driver(&pl_driver);
+}
+
+module_init(pl_init);
+module_exit(pl_exit);
+MODULE_LICENSE("GPL");
+
+HID_COMPAT_LOAD_DRIVER(petalynx);
diff --git a/drivers/hid/hid-pl.c b/drivers/hid/hid-pl.c
new file mode 100644
index 0000000..acd8155
--- /dev/null
+++ b/drivers/hid/hid-pl.c
@@ -0,0 +1,206 @@
+/*
+ *  Force feedback support for PantherLord/GreenAsia based devices
+ *
+ *  The devices are distributed under various names and the same USB device ID
+ *  can be used in both adapters and actual game controllers.
+ *
+ *  0810:0001 "Twin USB Joystick"
+ *   - tested with PantherLord USB/PS2 2in1 Adapter
+ *   - contains two reports, one for each port (HID_QUIRK_MULTI_INPUT)
+ *
+ *  0e8f:0003 "GreenAsia Inc.    USB Joystick     "
+ *   - tested with K??ng Gaming gamepad
+ *
+ *  Copyright (c) 2007 Anssi Hannula <anssi.hannula@gmail.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
+ */
+
+
+/* #define DEBUG */
+
+#define debug(format, arg...) pr_debug("hid-plff: " format "\n" , ## arg)
+
+#include <linux/input.h>
+#include <linux/usb.h>
+#include <linux/hid.h>
+
+#include "hid-ids.h"
+
+#ifdef CONFIG_PANTHERLORD_FF
+#include "usbhid/usbhid.h"
+
+struct plff_device {
+	struct hid_report *report;
+};
+
+static int hid_plff_play(struct input_dev *dev, void *data,
+			 struct ff_effect *effect)
+{
+	struct hid_device *hid = input_get_drvdata(dev);
+	struct plff_device *plff = data;
+	int left, right;
+
+	left = effect->u.rumble.strong_magnitude;
+	right = effect->u.rumble.weak_magnitude;
+	debug("called with 0x%04x 0x%04x", left, right);
+
+	left = left * 0x7f / 0xffff;
+	right = right * 0x7f / 0xffff;
+
+	plff->report->field[0]->value[2] = left;
+	plff->report->field[0]->value[3] = right;
+	debug("running with 0x%02x 0x%02x", left, right);
+	usbhid_submit_report(hid, plff->report, USB_DIR_OUT);
+
+	return 0;
+}
+
+static int plff_init(struct hid_device *hid)
+{
+	struct plff_device *plff;
+	struct hid_report *report;
+	struct hid_input *hidinput;
+	struct list_head *report_list =
+			&hid->report_enum[HID_OUTPUT_REPORT].report_list;
+	struct list_head *report_ptr = report_list;
+	struct input_dev *dev;
+	int error;
+
+	/* The device contains one output report per physical device, all
+	   containing 1 field, which contains 4 ff00.0002 usages and 4 16bit
+	   absolute values.
+
+	   The input reports also contain a field which contains
+	   8 ff00.0001 usages and 8 boolean values. Their meaning is
+	   currently unknown. */
+
+	if (list_empty(report_list)) {
+		dev_err(&hid->dev, "no output reports found\n");
+		return -ENODEV;
+	}
+
+	list_for_each_entry(hidinput, &hid->inputs, list) {
+
+		report_ptr = report_ptr->next;
+
+		if (report_ptr == report_list) {
+			dev_err(&hid->dev, "required output report is "
+					"missing\n");
+			return -ENODEV;
+		}
+
+		report = list_entry(report_ptr, struct hid_report, list);
+		if (report->maxfield < 1) {
+			dev_err(&hid->dev, "no fields in the report\n");
+			return -ENODEV;
+		}
+
+		if (report->field[0]->report_count < 4) {
+			dev_err(&hid->dev, "not enough values in the field\n");
+			return -ENODEV;
+		}
+
+		plff = kzalloc(sizeof(struct plff_device), GFP_KERNEL);
+		if (!plff)
+			return -ENOMEM;
+
+		dev = hidinput->input;
+
+		set_bit(FF_RUMBLE, dev->ffbit);
+
+		error = input_ff_create_memless(dev, plff, hid_plff_play);
+		if (error) {
+			kfree(plff);
+			return error;
+		}
+
+		plff->report = report;
+		plff->report->field[0]->value[0] = 0x00;
+		plff->report->field[0]->value[1] = 0x00;
+		plff->report->field[0]->value[2] = 0x00;
+		plff->report->field[0]->value[3] = 0x00;
+		usbhid_submit_report(hid, plff->report, USB_DIR_OUT);
+	}
+
+	dev_info(&hid->dev, "Force feedback for PantherLord/GreenAsia "
+	       "devices by Anssi Hannula <anssi.hannula@gmail.com>\n");
+
+	return 0;
+}
+#else
+static inline int plff_init(struct hid_device *hid)
+{
+	return 0;
+}
+#endif
+
+static int pl_probe(struct hid_device *hdev, const struct hid_device_id *id)
+{
+	int ret;
+
+	if (id->driver_data)
+		hdev->quirks |= HID_QUIRK_MULTI_INPUT;
+
+	ret = hid_parse(hdev);
+	if (ret) {
+		dev_err(&hdev->dev, "parse failed\n");
+		goto err;
+	}
+
+	ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT & ~HID_CONNECT_FF);
+	if (ret) {
+		dev_err(&hdev->dev, "hw start failed\n");
+		goto err;
+	}
+
+	plff_init(hdev);
+
+	return 0;
+err:
+	return ret;
+}
+
+static const struct hid_device_id pl_devices[] = {
+	{ HID_USB_DEVICE(USB_VENDOR_ID_GAMERON, USB_DEVICE_ID_GAMERON_DUAL_PSX_ADAPTOR),
+		.driver_data = 1 }, /* Twin USB Joystick */
+	{ HID_USB_DEVICE(USB_VENDOR_ID_GREENASIA, 0x0003), }, /* GreenAsia Inc. USB Joystick */
+	{ }
+};
+MODULE_DEVICE_TABLE(hid, pl_devices);
+
+static struct hid_driver pl_driver = {
+	.name = "pantherlord",
+	.id_table = pl_devices,
+	.probe = pl_probe,
+};
+
+static int pl_init(void)
+{
+	return hid_register_driver(&pl_driver);
+}
+
+static void pl_exit(void)
+{
+	hid_unregister_driver(&pl_driver);
+}
+
+module_init(pl_init);
+module_exit(pl_exit);
+MODULE_LICENSE("GPL");
+
+HID_COMPAT_LOAD_DRIVER(pantherlord);
diff --git a/drivers/hid/hid-samsung.c b/drivers/hid/hid-samsung.c
new file mode 100644
index 0000000..15f3c04
--- /dev/null
+++ b/drivers/hid/hid-samsung.c
@@ -0,0 +1,100 @@
+/*
+ *  HID driver for some samsung "special" devices
+ *
+ *  Copyright (c) 1999 Andreas Gal
+ *  Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
+ *  Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
+ *  Copyright (c) 2006-2007 Jiri Kosina
+ *  Copyright (c) 2007 Paul Walmsley
+ *  Copyright (c) 2008 Jiri Slaby
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or 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/device.h>
+#include <linux/hid.h>
+#include <linux/module.h>
+
+#include "hid-ids.h"
+
+/*
+ * Samsung IrDA remote controller (reports as Cypress USB Mouse).
+ *
+ * Vendor specific report #4 has a size of 48 bit,
+ * and therefore is not accepted when inspecting the descriptors.
+ * As a workaround we reinterpret the report as:
+ *   Variable type, count 6, size 8 bit, log. maximum 255
+ * The burden to reconstruct the data is moved into user space.
+ */
+static void samsung_report_fixup(struct hid_device *hdev, __u8 *rdesc,
+		unsigned int rsize)
+{
+	if (rsize >= 182 && rdesc[175] == 0x25 && rdesc[176] == 0x40 &&
+			rdesc[177] == 0x75 && rdesc[178] == 0x30 &&
+			rdesc[179] == 0x95 && rdesc[180] == 0x01 &&
+			rdesc[182] == 0x40) {
+		dev_info(&hdev->dev, "fixing up Samsung IrDA report "
+				"descriptor\n");
+		rdesc[176] = 0xff;
+		rdesc[178] = 0x08;
+		rdesc[180] = 0x06;
+		rdesc[182] = 0x42;
+	}
+}
+
+static int samsung_probe(struct hid_device *hdev,
+		const struct hid_device_id *id)
+{
+	int ret;
+
+	ret = hid_parse(hdev);
+	if (ret) {
+		dev_err(&hdev->dev, "parse failed\n");
+		goto err_free;
+	}
+
+	ret = hid_hw_start(hdev, (HID_CONNECT_DEFAULT & ~HID_CONNECT_HIDINPUT) |
+			HID_CONNECT_HIDDEV_FORCE);
+	if (ret) {
+		dev_err(&hdev->dev, "hw start failed\n");
+		goto err_free;
+	}
+
+	return 0;
+err_free:
+	return ret;
+}
+
+static const struct hid_device_id samsung_devices[] = {
+	{ HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_IR_REMOTE) },
+	{ }
+};
+MODULE_DEVICE_TABLE(hid, samsung_devices);
+
+static struct hid_driver samsung_driver = {
+	.name = "samsung",
+	.id_table = samsung_devices,
+	.report_fixup = samsung_report_fixup,
+	.probe = samsung_probe,
+};
+
+static int samsung_init(void)
+{
+	return hid_register_driver(&samsung_driver);
+}
+
+static void samsung_exit(void)
+{
+	hid_unregister_driver(&samsung_driver);
+}
+
+module_init(samsung_init);
+module_exit(samsung_exit);
+MODULE_LICENSE("GPL");
+
+HID_COMPAT_LOAD_DRIVER(samsung);
diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c
new file mode 100644
index 0000000..3af8095
--- /dev/null
+++ b/drivers/hid/hid-sony.c
@@ -0,0 +1,110 @@
+/*
+ *  HID driver for some sony "special" devices
+ *
+ *  Copyright (c) 1999 Andreas Gal
+ *  Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
+ *  Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
+ *  Copyright (c) 2006-2007 Jiri Kosina
+ *  Copyright (c) 2007 Paul Walmsley
+ *  Copyright (c) 2008 Jiri Slaby
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or 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/device.h>
+#include <linux/hid.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+
+#include "hid-ids.h"
+
+/*
+ * Sending HID_REQ_GET_REPORT changes the operation mode of the ps3 controller
+ * to "operational".  Without this, the ps3 controller will not report any
+ * events.
+ */
+static int sony_set_operational(struct hid_device *hdev)
+{
+	struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
+	struct usb_device *dev = interface_to_usbdev(intf);
+	__u16 ifnum = intf->cur_altsetting->desc.bInterfaceNumber;
+	int ret;
+	char *buf = kmalloc(18, GFP_KERNEL);
+
+	if (!buf)
+		return -ENOMEM;
+
+	ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+				 HID_REQ_GET_REPORT,
+				 USB_DIR_IN | USB_TYPE_CLASS |
+				 USB_RECIP_INTERFACE,
+				 (3 << 8) | 0xf2, ifnum, buf, 17,
+				 USB_CTRL_GET_TIMEOUT);
+	if (ret < 0)
+		dev_err(&hdev->dev, "can't set operational mode\n");
+
+	kfree(buf);
+
+	return ret;
+}
+
+static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
+{
+	int ret;
+
+	ret = hid_parse(hdev);
+	if (ret) {
+		dev_err(&hdev->dev, "parse failed\n");
+		goto err_free;
+	}
+
+	ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT |
+			HID_CONNECT_HIDDEV_FORCE);
+	if (ret) {
+		dev_err(&hdev->dev, "hw start failed\n");
+		goto err_free;
+	}
+
+	ret = sony_set_operational(hdev);
+	if (ret)
+		goto err_stop;
+
+	return 0;
+err_stop:
+	hid_hw_stop(hdev);
+err_free:
+	return ret;
+}
+
+static const struct hid_device_id sony_devices[] = {
+	{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) },
+	{ }
+};
+MODULE_DEVICE_TABLE(hid, sony_devices);
+
+static struct hid_driver sony_driver = {
+	.name = "sony",
+	.id_table = sony_devices,
+	.probe = sony_probe,
+};
+
+static int sony_init(void)
+{
+	return hid_register_driver(&sony_driver);
+}
+
+static void sony_exit(void)
+{
+	hid_unregister_driver(&sony_driver);
+}
+
+module_init(sony_init);
+module_exit(sony_exit);
+MODULE_LICENSE("GPL");
+
+HID_COMPAT_LOAD_DRIVER(sony);
diff --git a/drivers/hid/hid-sunplus.c b/drivers/hid/hid-sunplus.c
new file mode 100644
index 0000000..5ba68f7
--- /dev/null
+++ b/drivers/hid/hid-sunplus.c
@@ -0,0 +1,82 @@
+/*
+ *  HID driver for some sunplus "special" devices
+ *
+ *  Copyright (c) 1999 Andreas Gal
+ *  Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
+ *  Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
+ *  Copyright (c) 2006-2007 Jiri Kosina
+ *  Copyright (c) 2007 Paul Walmsley
+ *  Copyright (c) 2008 Jiri Slaby
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or 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/device.h>
+#include <linux/hid.h>
+#include <linux/module.h>
+
+#include "hid-ids.h"
+
+static void sp_report_fixup(struct hid_device *hdev, __u8 *rdesc,
+		unsigned int rsize)
+{
+	if (rsize >= 107 && rdesc[104] == 0x26 && rdesc[105] == 0x80 &&
+			rdesc[106] == 0x03) {
+		dev_info(&hdev->dev, "fixing up Sunplus Wireless Desktop "
+				"report descriptor\n");
+		rdesc[105] = rdesc[110] = 0x03;
+		rdesc[106] = rdesc[111] = 0x21;
+	}
+}
+
+#define sp_map_key_clear(c)	hid_map_usage_clear(hi, usage, bit, max, \
+		EV_KEY, (c))
+static int sp_input_mapping(struct hid_device *hdev, struct hid_input *hi,
+		struct hid_field *field, struct hid_usage *usage,
+		unsigned long **bit, int *max)
+{
+	if ((usage->hid & HID_USAGE_PAGE) != HID_UP_CONSUMER)
+		return 0;
+
+	switch (usage->hid & HID_USAGE) {
+	case 0x2003: sp_map_key_clear(KEY_ZOOMIN);		break;
+	case 0x2103: sp_map_key_clear(KEY_ZOOMOUT);	break;
+	default:
+		return 0;
+	}
+	return 1;
+}
+
+static const struct hid_device_id sp_devices[] = {
+	{ HID_USB_DEVICE(USB_VENDOR_ID_SUNPLUS, USB_DEVICE_ID_SUNPLUS_WDESKTOP) },
+	{ }
+};
+MODULE_DEVICE_TABLE(hid, sp_devices);
+
+static struct hid_driver sp_driver = {
+	.name = "sunplus",
+	.id_table = sp_devices,
+	.report_fixup = sp_report_fixup,
+	.input_mapping = sp_input_mapping,
+};
+
+static int sp_init(void)
+{
+	return hid_register_driver(&sp_driver);
+}
+
+static void sp_exit(void)
+{
+	hid_unregister_driver(&sp_driver);
+}
+
+module_init(sp_init);
+module_exit(sp_exit);
+MODULE_LICENSE("GPL");
+
+HID_COMPAT_LOAD_DRIVER(sunplus);
diff --git a/drivers/hid/hid-tmff.c b/drivers/hid/hid-tmff.c
new file mode 100644
index 0000000..1b7cba0
--- /dev/null
+++ b/drivers/hid/hid-tmff.c
@@ -0,0 +1,269 @@
+/*
+ * Force feedback support for various HID compliant devices by ThrustMaster:
+ *    ThrustMaster FireStorm Dual Power 2
+ * and possibly others whose device ids haven't been added.
+ *
+ *  Modified to support ThrustMaster devices by Zinx Verituse
+ *  on 2003-01-25 from the Logitech force feedback driver,
+ *  which is by Johann Deneux.
+ *
+ *  Copyright (c) 2003 Zinx Verituse <zinx@epicsol.org>
+ *  Copyright (c) 2002 Johann Deneux
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or 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/hid.h>
+#include <linux/input.h>
+#include <linux/usb.h>
+
+#include "hid-ids.h"
+
+#include "usbhid/usbhid.h"
+
+/* Usages for thrustmaster devices I know about */
+#define THRUSTMASTER_USAGE_FF	(HID_UP_GENDESK | 0xbb)
+
+static const signed short ff_rumble[] = {
+	FF_RUMBLE,
+	-1
+};
+
+static const signed short ff_joystick[] = {
+	FF_CONSTANT,
+	-1
+};
+
+struct tmff_device {
+	struct hid_report *report;
+	struct hid_field *ff_field;
+};
+
+/* Changes values from 0 to 0xffff into values from minimum to maximum */
+static inline int tmff_scale_u16(unsigned int in, int minimum, int maximum)
+{
+	int ret;
+
+	ret = (in * (maximum - minimum) / 0xffff) + minimum;
+	if (ret < minimum)
+		return minimum;
+	if (ret > maximum)
+		return maximum;
+	return ret;
+}
+
+/* Changes values from -0x80 to 0x7f into values from minimum to maximum */
+static inline int tmff_scale_s8(int in, int minimum, int maximum)
+{
+	int ret;
+
+	ret = (((in + 0x80) * (maximum - minimum)) / 0xff) + minimum;
+	if (ret < minimum)
+		return minimum;
+	if (ret > maximum)
+		return maximum;
+	return ret;
+}
+
+static int tmff_play(struct input_dev *dev, void *data,
+		struct ff_effect *effect)
+{
+	struct hid_device *hid = input_get_drvdata(dev);
+	struct tmff_device *tmff = data;
+	struct hid_field *ff_field = tmff->ff_field;
+	int x, y;
+	int left, right;	/* Rumbling */
+
+	switch (effect->type) {
+	case FF_CONSTANT:
+		x = tmff_scale_s8(effect->u.ramp.start_level,
+					ff_field->logical_minimum,
+					ff_field->logical_maximum);
+		y = tmff_scale_s8(effect->u.ramp.end_level,
+					ff_field->logical_minimum,
+					ff_field->logical_maximum);
+
+		dbg_hid("(x, y)=(%04x, %04x)\n", x, y);
+		ff_field->value[0] = x;
+		ff_field->value[1] = y;
+		usbhid_submit_report(hid, tmff->report, USB_DIR_OUT);
+		break;
+
+	case FF_RUMBLE:
+		left = tmff_scale_u16(effect->u.rumble.weak_magnitude,
+					ff_field->logical_minimum,
+					ff_field->logical_maximum);
+		right = tmff_scale_u16(effect->u.rumble.strong_magnitude,
+					ff_field->logical_minimum,
+					ff_field->logical_maximum);
+
+		dbg_hid("(left,right)=(%08x, %08x)\n", left, right);
+		ff_field->value[0] = left;
+		ff_field->value[1] = right;
+		usbhid_submit_report(hid, tmff->report, USB_DIR_OUT);
+		break;
+	}
+	return 0;
+}
+
+static int tmff_init(struct hid_device *hid, const signed short *ff_bits)
+{
+	struct tmff_device *tmff;
+	struct hid_report *report;
+	struct list_head *report_list;
+	struct hid_input *hidinput = list_entry(hid->inputs.next,
+							struct hid_input, list);
+	struct input_dev *input_dev = hidinput->input;
+	int error;
+	int i;
+
+	tmff = kzalloc(sizeof(struct tmff_device), GFP_KERNEL);
+	if (!tmff)
+		return -ENOMEM;
+
+	/* Find the report to use */
+	report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list;
+	list_for_each_entry(report, report_list, list) {
+		int fieldnum;
+
+		for (fieldnum = 0; fieldnum < report->maxfield; ++fieldnum) {
+			struct hid_field *field = report->field[fieldnum];
+
+			if (field->maxusage <= 0)
+				continue;
+
+			switch (field->usage[0].hid) {
+			case THRUSTMASTER_USAGE_FF:
+				if (field->report_count < 2) {
+					dev_warn(&hid->dev, "ignoring FF field "
+						"with report_count < 2\n");
+					continue;
+				}
+
+				if (field->logical_maximum ==
+						field->logical_minimum) {
+					dev_warn(&hid->dev, "ignoring FF field "
+							"with logical_maximum "
+							"== logical_minimum\n");
+					continue;
+				}
+
+				if (tmff->report && tmff->report != report) {
+					dev_warn(&hid->dev, "ignoring FF field "
+							"in other report\n");
+					continue;
+				}
+
+				if (tmff->ff_field && tmff->ff_field != field) {
+					dev_warn(&hid->dev, "ignoring "
+							"duplicate FF field\n");
+					continue;
+				}
+
+				tmff->report = report;
+				tmff->ff_field = field;
+
+				for (i = 0; ff_bits[i] >= 0; i++)
+					set_bit(ff_bits[i], input_dev->ffbit);
+
+				break;
+
+			default:
+				dev_warn(&hid->dev, "ignoring unknown output "
+						"usage %08x\n",
+						field->usage[0].hid);
+				continue;
+			}
+		}
+	}
+
+	if (!tmff->report) {
+		dev_err(&hid->dev, "can't find FF field in output reports\n");
+		error = -ENODEV;
+		goto fail;
+	}
+
+	error = input_ff_create_memless(input_dev, tmff, tmff_play);
+	if (error)
+		goto fail;
+
+	dev_info(&hid->dev, "force feedback for ThrustMaster devices by Zinx "
+			"Verituse <zinx@epicsol.org>");
+	return 0;
+
+fail:
+	kfree(tmff);
+	return error;
+}
+
+static int tm_probe(struct hid_device *hdev, const struct hid_device_id *id)
+{
+	int ret;
+
+	ret = hid_parse(hdev);
+	if (ret) {
+		dev_err(&hdev->dev, "parse failed\n");
+		goto err;
+	}
+
+	ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT & ~HID_CONNECT_FF);
+	if (ret) {
+		dev_err(&hdev->dev, "hw start failed\n");
+		goto err;
+	}
+
+	tmff_init(hdev, (void *)id->driver_data);
+
+	return 0;
+err:
+	return ret;
+}
+
+static const struct hid_device_id tm_devices[] = {
+	{ HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb300),
+		.driver_data = (unsigned long)ff_rumble },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb304),
+		.driver_data = (unsigned long)ff_rumble },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb651),	/* FGT Rumble Force Wheel */
+		.driver_data = (unsigned long)ff_rumble },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb654),	/* FGT Force Feedback Wheel */
+		.driver_data = (unsigned long)ff_joystick },
+	{ }
+};
+MODULE_DEVICE_TABLE(hid, tm_devices);
+
+static struct hid_driver tm_driver = {
+	.name = "thrustmaster",
+	.id_table = tm_devices,
+	.probe = tm_probe,
+};
+
+static int tm_init(void)
+{
+	return hid_register_driver(&tm_driver);
+}
+
+static void tm_exit(void)
+{
+	hid_unregister_driver(&tm_driver);
+}
+
+module_init(tm_init);
+module_exit(tm_exit);
+MODULE_LICENSE("GPL");
+
+HID_COMPAT_LOAD_DRIVER(thrustmaster);
diff --git a/drivers/hid/hid-zpff.c b/drivers/hid/hid-zpff.c
new file mode 100644
index 0000000..ea82f37
--- /dev/null
+++ b/drivers/hid/hid-zpff.c
@@ -0,0 +1,162 @@
+/*
+ *  Force feedback support for Zeroplus based devices
+ *
+ *  Copyright (c) 2005, 2006 Anssi Hannula <anssi.hannula@gmail.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/hid.h>
+#include <linux/input.h>
+#include <linux/usb.h>
+
+#include "hid-ids.h"
+
+#include "usbhid/usbhid.h"
+
+struct zpff_device {
+	struct hid_report *report;
+};
+
+static int zpff_play(struct input_dev *dev, void *data,
+			 struct ff_effect *effect)
+{
+	struct hid_device *hid = input_get_drvdata(dev);
+	struct zpff_device *zpff = data;
+	int left, right;
+
+	/*
+	 * The following is specified the other way around in the Zeroplus
+	 * datasheet but the order below is correct for the XFX Executioner;
+	 * however it is possible that the XFX Executioner is an exception
+	 */
+
+	left = effect->u.rumble.strong_magnitude;
+	right = effect->u.rumble.weak_magnitude;
+	dbg_hid("called with 0x%04x 0x%04x\n", left, right);
+
+	left = left * 0x7f / 0xffff;
+	right = right * 0x7f / 0xffff;
+
+	zpff->report->field[2]->value[0] = left;
+	zpff->report->field[3]->value[0] = right;
+	dbg_hid("running with 0x%02x 0x%02x\n", left, right);
+	usbhid_submit_report(hid, zpff->report, USB_DIR_OUT);
+
+	return 0;
+}
+
+static int zpff_init(struct hid_device *hid)
+{
+	struct zpff_device *zpff;
+	struct hid_report *report;
+	struct hid_input *hidinput = list_entry(hid->inputs.next,
+						struct hid_input, list);
+	struct list_head *report_list =
+			&hid->report_enum[HID_OUTPUT_REPORT].report_list;
+	struct input_dev *dev = hidinput->input;
+	int error;
+
+	if (list_empty(report_list)) {
+		dev_err(&hid->dev, "no output report found\n");
+		return -ENODEV;
+	}
+
+	report = list_entry(report_list->next, struct hid_report, list);
+
+	if (report->maxfield < 4) {
+		dev_err(&hid->dev, "not enough fields in report\n");
+		return -ENODEV;
+	}
+
+	zpff = kzalloc(sizeof(struct zpff_device), GFP_KERNEL);
+	if (!zpff)
+		return -ENOMEM;
+
+	set_bit(FF_RUMBLE, dev->ffbit);
+
+	error = input_ff_create_memless(dev, zpff, zpff_play);
+	if (error) {
+		kfree(zpff);
+		return error;
+	}
+
+	zpff->report = report;
+	zpff->report->field[0]->value[0] = 0x00;
+	zpff->report->field[1]->value[0] = 0x02;
+	zpff->report->field[2]->value[0] = 0x00;
+	zpff->report->field[3]->value[0] = 0x00;
+	usbhid_submit_report(hid, zpff->report, USB_DIR_OUT);
+
+	dev_info(&hid->dev, "force feedback for Zeroplus based devices by "
+	       "Anssi Hannula <anssi.hannula@gmail.com>\n");
+
+	return 0;
+}
+
+static int zp_probe(struct hid_device *hdev, const struct hid_device_id *id)
+{
+	int ret;
+
+	ret = hid_parse(hdev);
+	if (ret) {
+		dev_err(&hdev->dev, "parse failed\n");
+		goto err;
+	}
+
+	ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT & ~HID_CONNECT_FF);
+	if (ret) {
+		dev_err(&hdev->dev, "hw start failed\n");
+		goto err;
+	}
+
+	zpff_init(hdev);
+
+	return 0;
+err:
+	return ret;
+}
+
+static const struct hid_device_id zp_devices[] = {
+	{ HID_USB_DEVICE(USB_VENDOR_ID_ZEROPLUS, 0x0005) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_ZEROPLUS, 0x0030) },
+	{ }
+};
+MODULE_DEVICE_TABLE(hid, zp_devices);
+
+static struct hid_driver zp_driver = {
+	.name = "zeroplus",
+	.id_table = zp_devices,
+	.probe = zp_probe,
+};
+
+static int zp_init(void)
+{
+	return hid_register_driver(&zp_driver);
+}
+
+static void zp_exit(void)
+{
+	hid_unregister_driver(&zp_driver);
+}
+
+module_init(zp_init);
+module_exit(zp_exit);
+MODULE_LICENSE("GPL");
+
+HID_COMPAT_LOAD_DRIVER(zeroplus);
diff --git a/drivers/hid/hidraw.c b/drivers/hid/hidraw.c
index c40f040..497e0d1 100644
--- a/drivers/hid/hidraw.c
+++ b/drivers/hid/hidraw.c
@@ -113,7 +113,7 @@
 	if (!dev->hid_output_raw_report)
 		return -ENODEV;
 
-	if (count > HID_MIN_BUFFER_SIZE) {
+	if (count > HID_MAX_BUFFER_SIZE) {
 		printk(KERN_WARNING "hidraw: pid %d passed too large report\n",
 				task_pid_nr(current));
 		return -EINVAL;
@@ -181,7 +181,7 @@
 
 	dev = hidraw_table[minor];
 	if (!dev->open++)
-		dev->hid->hid_open(dev->hid);
+		dev->hid->ll_driver->open(dev->hid);
 
 out_unlock:
 	spin_unlock(&minors_lock);
@@ -207,7 +207,7 @@
 	dev = hidraw_table[minor];
 	if (!dev->open--) {
 		if (list->hidraw->exist)
-			dev->hid->hid_close(dev->hid);
+			dev->hid->ll_driver->close(dev->hid);
 		else
 			kfree(list->hidraw);
 	}
@@ -367,7 +367,7 @@
 	device_destroy(hidraw_class, MKDEV(hidraw_major, hidraw->minor));
 
 	if (hidraw->open) {
-		hid->hid_close(hid);
+		hid->ll_driver->close(hid);
 		wake_up_interruptible(&hidraw->wait);
 	} else {
 		kfree(hidraw);
diff --git a/drivers/hid/usbhid/Kconfig b/drivers/hid/usbhid/Kconfig
index 18f0910..5d9aa95 100644
--- a/drivers/hid/usbhid/Kconfig
+++ b/drivers/hid/usbhid/Kconfig
@@ -24,88 +24,13 @@
 comment "Input core support is needed for USB HID input layer or HIDBP support"
 	depends on USB_HID && INPUT=n
 
-config USB_HIDINPUT_POWERBOOK
-	bool "Enable support for Apple laptop/aluminum USB special keys"
-	default n
-	depends on USB_HID
-	help
-	  Say Y here if you want support for the special keys (Fn, Numlock) on
-	  Apple iBooks, PowerBooks, MacBooks, MacBook Pros and aluminum USB
-	  keyboards.
-
-	  If unsure, say N.
-
-config HID_FF
-	bool "Force feedback support (EXPERIMENTAL)"
-	depends on USB_HID && EXPERIMENTAL
-	help
-	  Say Y here is you want force feedback support for a few HID devices.
-	  See below for a list of supported devices.
-
-	  See <file:Documentation/input/ff.txt> for a description of the force
-	  feedback API.
-
-	  If unsure, say N.
-
 config HID_PID
 	bool "PID device support"
-	depends on HID_FF
 	help
 	  Say Y here if you have a PID-compliant device and wish to enable force
 	  feedback for it. Microsoft Sidewinder Force Feedback 2 is one of such
 	  devices.
 
-config LOGITECH_FF
-	bool "Logitech devices support"
-	depends on HID_FF
-	select INPUT_FF_MEMLESS if USB_HID
-	help
-	  Say Y here if you have one of these devices:
-	  - Logitech WingMan Cordless RumblePad
-	  - Logitech WingMan Cordless RumblePad 2
-	  - Logitech WingMan Force 3D
-	  - Logitech Formula Force EX
-	  - Logitech MOMO Force wheel
-
-	  and if you want to enable force feedback for them.
-	  Note: if you say N here, this device will still be supported, but without
-	  force feedback.
-
-config LOGIRUMBLEPAD2_FF
-	bool "Logitech Rumblepad 2 support"
-	depends on HID_FF
-	select INPUT_FF_MEMLESS if USB_HID
-	help
-	  Say Y here if you want to enable force feedback support for Logitech
-	  Rumblepad 2 devices.
-
-config PANTHERLORD_FF
-	bool "PantherLord/GreenAsia based device support"
-	depends on HID_FF
-	select INPUT_FF_MEMLESS if USB_HID
-	help
-	  Say Y here if you have a PantherLord/GreenAsia based game controller
-	  or adapter and want to enable force feedback support for it.
-
-config THRUSTMASTER_FF
-	bool "ThrustMaster devices support"
-	depends on HID_FF
-	select INPUT_FF_MEMLESS if USB_HID
-	help
-	  Say Y here if you have a THRUSTMASTER FireStore Dual Power 2 or
-	  a THRUSTMASTER Ferrari GT Rumble Force or Force Feedback Wheel,
-	  and want to enable force feedback support for it.
-	  Note: if you say N here, this device will still be supported, but without
-	  force feedback.
-
-config ZEROPLUS_FF
-	bool "Zeroplus based game controller support"
-	depends on HID_FF
-	select INPUT_FF_MEMLESS if USB_HID
-	help
-	  Say Y here if you have a Zeroplus based game controller and want to
-	  enable force feedback for it.
-
 config USB_HIDDEV
 	bool "/dev/hiddev raw HID device support"
 	depends on USB_HID
diff --git a/drivers/hid/usbhid/Makefile b/drivers/hid/usbhid/Makefile
index 00a7b70..1329ecb 100644
--- a/drivers/hid/usbhid/Makefile
+++ b/drivers/hid/usbhid/Makefile
@@ -13,24 +13,6 @@
 ifeq ($(CONFIG_HID_PID),y)
 	usbhid-objs	+= hid-pidff.o
 endif
-ifeq ($(CONFIG_LOGITECH_FF),y)
-	usbhid-objs	+= hid-lgff.o
-endif
-ifeq ($(CONFIG_LOGIRUMBLEPAD2_FF),y)
-	usbhid-objs	+= hid-lg2ff.o
-endif
-ifeq ($(CONFIG_PANTHERLORD_FF),y)
-	usbhid-objs	+= hid-plff.o
-endif
-ifeq ($(CONFIG_THRUSTMASTER_FF),y)
-	usbhid-objs	+= hid-tmff.o
-endif
-ifeq ($(CONFIG_ZEROPLUS_FF),y)
-	usbhid-objs	+= hid-zpff.o
-endif
-ifeq ($(CONFIG_HID_FF),y)
-	usbhid-objs	+= hid-ff.o
-endif
 
 obj-$(CONFIG_USB_HID)		+= usbhid.o
 obj-$(CONFIG_USB_KBD)		+= usbkbd.o
diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c
index 27fe4d8..1d3b8a3 100644
--- a/drivers/hid/usbhid/hid-core.c
+++ b/drivers/hid/usbhid/hid-core.c
@@ -44,8 +44,6 @@
 #define DRIVER_DESC "USB HID core driver"
 #define DRIVER_LICENSE "GPL"
 
-static char *hid_types[] = {"Device", "Pointer", "Mouse", "Device", "Joystick",
-				"Gamepad", "Keyboard", "Keypad", "Multi-Axis Controller"};
 /*
  * Module parameters.
  */
@@ -61,12 +59,6 @@
 		" quirks=vendorID:productID:quirks"
 		" where vendorID, productID, and quirks are all in"
 		" 0x-prefixed hex");
-static char *rdesc_quirks_param[MAX_USBHID_BOOT_QUIRKS] = { [ 0 ... (MAX_USBHID_BOOT_QUIRKS - 1) ] = NULL };
-module_param_array_named(rdesc_quirks, rdesc_quirks_param, charp, NULL, 0444);
-MODULE_PARM_DESC(rdesc_quirks, "Add/modify report descriptor quirks by specifying "
-		" rdesc_quirks=vendorID:productID:rdesc_quirks"
-		" where vendorID, productID, and rdesc_quirks are all in"
-		" 0x-prefixed hex");
 /*
  * Input submission and I/O error handler.
  */
@@ -197,31 +189,32 @@
 	int			status;
 
 	switch (urb->status) {
-		case 0:			/* success */
-			usbhid->retry_delay = 0;
-			hid_input_report(urb->context, HID_INPUT_REPORT,
-					 urb->transfer_buffer,
-					 urb->actual_length, 1);
-			break;
-		case -EPIPE:		/* stall */
-			clear_bit(HID_IN_RUNNING, &usbhid->iofl);
-			set_bit(HID_CLEAR_HALT, &usbhid->iofl);
-			schedule_work(&usbhid->reset_work);
-			return;
-		case -ECONNRESET:	/* unlink */
-		case -ENOENT:
-		case -ESHUTDOWN:	/* unplug */
-			clear_bit(HID_IN_RUNNING, &usbhid->iofl);
-			return;
-		case -EILSEQ:		/* protocol error or unplug */
-		case -EPROTO:		/* protocol error or unplug */
-		case -ETIME:		/* protocol error or unplug */
-		case -ETIMEDOUT:	/* Should never happen, but... */
-			clear_bit(HID_IN_RUNNING, &usbhid->iofl);
-			hid_io_error(hid);
-			return;
-		default:		/* error */
-			warn("input irq status %d received", urb->status);
+	case 0:			/* success */
+		usbhid->retry_delay = 0;
+		hid_input_report(urb->context, HID_INPUT_REPORT,
+				 urb->transfer_buffer,
+				 urb->actual_length, 1);
+		break;
+	case -EPIPE:		/* stall */
+		clear_bit(HID_IN_RUNNING, &usbhid->iofl);
+		set_bit(HID_CLEAR_HALT, &usbhid->iofl);
+		schedule_work(&usbhid->reset_work);
+		return;
+	case -ECONNRESET:	/* unlink */
+	case -ENOENT:
+	case -ESHUTDOWN:	/* unplug */
+		clear_bit(HID_IN_RUNNING, &usbhid->iofl);
+		return;
+	case -EILSEQ:		/* protocol error or unplug */
+	case -EPROTO:		/* protocol error or unplug */
+	case -ETIME:		/* protocol error or unplug */
+	case -ETIMEDOUT:	/* Should never happen, but... */
+		clear_bit(HID_IN_RUNNING, &usbhid->iofl);
+		hid_io_error(hid);
+		return;
+	default:		/* error */
+		dev_warn(&urb->dev->dev, "input irq status %d  "
+				"received\n", urb->status);
 	}
 
 	status = usb_submit_urb(urb, GFP_ATOMIC);
@@ -240,13 +233,16 @@
 static int hid_submit_out(struct hid_device *hid)
 {
 	struct hid_report *report;
+	char *raw_report;
 	struct usbhid_device *usbhid = hid->driver_data;
 
-	report = usbhid->out[usbhid->outtail];
+	report = usbhid->out[usbhid->outtail].report;
+	raw_report = usbhid->out[usbhid->outtail].raw_report;
 
-	hid_output_report(report, usbhid->outbuf);
 	usbhid->urbout->transfer_buffer_length = ((report->size - 1) >> 3) + 1 + (report->id > 0);
 	usbhid->urbout->dev = hid_to_usb_dev(hid);
+	memcpy(usbhid->outbuf, raw_report, usbhid->urbout->transfer_buffer_length);
+	kfree(raw_report);
 
 	dbg_hid("submitting out urb\n");
 
@@ -262,17 +258,20 @@
 {
 	struct hid_report *report;
 	unsigned char dir;
+	char *raw_report;
 	int len;
 	struct usbhid_device *usbhid = hid->driver_data;
 
 	report = usbhid->ctrl[usbhid->ctrltail].report;
+	raw_report = usbhid->ctrl[usbhid->ctrltail].raw_report;
 	dir = usbhid->ctrl[usbhid->ctrltail].dir;
 
 	len = ((report->size - 1) >> 3) + 1 + (report->id > 0);
 	if (dir == USB_DIR_OUT) {
-		hid_output_report(report, usbhid->ctrlbuf);
 		usbhid->urbctrl->pipe = usb_sndctrlpipe(hid_to_usb_dev(hid), 0);
 		usbhid->urbctrl->transfer_buffer_length = len;
+		memcpy(usbhid->ctrlbuf, raw_report, len);
+		kfree(raw_report);
 	} else {
 		int maxpacket, padlen;
 
@@ -319,17 +318,18 @@
 	int unplug = 0;
 
 	switch (urb->status) {
-		case 0:			/* success */
-			break;
-		case -ESHUTDOWN:	/* unplug */
-			unplug = 1;
-		case -EILSEQ:		/* protocol error or unplug */
-		case -EPROTO:		/* protocol error or unplug */
-		case -ECONNRESET:	/* unlink */
-		case -ENOENT:
-			break;
-		default:		/* error */
-			warn("output irq status %d received", urb->status);
+	case 0:			/* success */
+		break;
+	case -ESHUTDOWN:	/* unplug */
+		unplug = 1;
+	case -EILSEQ:		/* protocol error or unplug */
+	case -EPROTO:		/* protocol error or unplug */
+	case -ECONNRESET:	/* unlink */
+	case -ENOENT:
+		break;
+	default:		/* error */
+		dev_warn(&urb->dev->dev, "output irq status %d "
+				"received\n", urb->status);
 	}
 
 	spin_lock_irqsave(&usbhid->outlock, flags);
@@ -367,21 +367,23 @@
 	spin_lock_irqsave(&usbhid->ctrllock, flags);
 
 	switch (urb->status) {
-		case 0:			/* success */
-			if (usbhid->ctrl[usbhid->ctrltail].dir == USB_DIR_IN)
-				hid_input_report(urb->context, usbhid->ctrl[usbhid->ctrltail].report->type,
-						urb->transfer_buffer, urb->actual_length, 0);
-			break;
-		case -ESHUTDOWN:	/* unplug */
-			unplug = 1;
-		case -EILSEQ:		/* protocol error or unplug */
-		case -EPROTO:		/* protocol error or unplug */
-		case -ECONNRESET:	/* unlink */
-		case -ENOENT:
-		case -EPIPE:		/* report not available */
-			break;
-		default:		/* error */
-			warn("ctrl urb status %d received", urb->status);
+	case 0:			/* success */
+		if (usbhid->ctrl[usbhid->ctrltail].dir == USB_DIR_IN)
+			hid_input_report(urb->context,
+				usbhid->ctrl[usbhid->ctrltail].report->type,
+				urb->transfer_buffer, urb->actual_length, 0);
+		break;
+	case -ESHUTDOWN:	/* unplug */
+		unplug = 1;
+	case -EILSEQ:		/* protocol error or unplug */
+	case -EPROTO:		/* protocol error or unplug */
+	case -ECONNRESET:	/* unlink */
+	case -ENOENT:
+	case -EPIPE:		/* report not available */
+		break;
+	default:		/* error */
+		dev_warn(&urb->dev->dev, "ctrl urb status %d "
+				"received\n", urb->status);
 	}
 
 	if (unplug)
@@ -408,6 +410,7 @@
 	int head;
 	unsigned long flags;
 	struct usbhid_device *usbhid = hid->driver_data;
+	int len = ((report->size - 1) >> 3) + 1 + (report->id > 0);
 
 	if ((hid->quirks & HID_QUIRK_NOGET) && dir == USB_DIR_IN)
 		return;
@@ -418,11 +421,18 @@
 
 		if ((head = (usbhid->outhead + 1) & (HID_OUTPUT_FIFO_SIZE - 1)) == usbhid->outtail) {
 			spin_unlock_irqrestore(&usbhid->outlock, flags);
-			warn("output queue full");
+			dev_warn(&hid->dev, "output queue full\n");
 			return;
 		}
 
-		usbhid->out[usbhid->outhead] = report;
+		usbhid->out[usbhid->outhead].raw_report = kmalloc(len, GFP_ATOMIC);
+		if (!usbhid->out[usbhid->outhead].raw_report) {
+			spin_unlock_irqrestore(&usbhid->outlock, flags);
+			warn("output queueing failed");
+			return;
+		}
+		hid_output_report(report, usbhid->out[usbhid->outhead].raw_report);
+		usbhid->out[usbhid->outhead].report = report;
 		usbhid->outhead = head;
 
 		if (!test_and_set_bit(HID_OUT_RUNNING, &usbhid->iofl))
@@ -437,10 +447,19 @@
 
 	if ((head = (usbhid->ctrlhead + 1) & (HID_CONTROL_FIFO_SIZE - 1)) == usbhid->ctrltail) {
 		spin_unlock_irqrestore(&usbhid->ctrllock, flags);
-		warn("control queue full");
+		dev_warn(&hid->dev, "control queue full\n");
 		return;
 	}
 
+	if (dir == USB_DIR_OUT) {
+		usbhid->ctrl[usbhid->ctrlhead].raw_report = kmalloc(len, GFP_ATOMIC);
+		if (!usbhid->ctrl[usbhid->ctrlhead].raw_report) {
+			spin_unlock_irqrestore(&usbhid->ctrllock, flags);
+			warn("control queueing failed");
+			return;
+		}
+		hid_output_report(report, usbhid->ctrl[usbhid->ctrlhead].raw_report);
+	}
 	usbhid->ctrl[usbhid->ctrlhead].report = report;
 	usbhid->ctrl[usbhid->ctrlhead].dir = dir;
 	usbhid->ctrlhead = head;
@@ -451,6 +470,7 @@
 
 	spin_unlock_irqrestore(&usbhid->ctrllock, flags);
 }
+EXPORT_SYMBOL_GPL(usbhid_submit_report);
 
 static int usb_hidinput_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
 {
@@ -465,7 +485,7 @@
 		return -1;
 
 	if ((offset = hidinput_find_field(hid, type, code, &field)) == -1) {
-		warn("event field not found");
+		dev_warn(&dev->dev, "event field not found\n");
 		return -1;
 	}
 
@@ -568,7 +588,7 @@
 	}
 
 	if (err)
-		warn("timeout initializing reports");
+		dev_warn(&hid->dev, "timeout initializing reports\n");
 }
 
 /*
@@ -598,7 +618,7 @@
 	return -1;
 }
 
-static void usbhid_set_leds(struct hid_device *hid)
+void usbhid_set_leds(struct hid_device *hid)
 {
 	struct hid_field *field;
 	int offset;
@@ -608,6 +628,7 @@
 		usbhid_submit_report(hid, field->report, USB_DIR_OUT);
 	}
 }
+EXPORT_SYMBOL_GPL(usbhid_set_leds);
 
 /*
  * Traverse the supplied list of reports and find the longest
@@ -675,43 +696,16 @@
 	usb_buffer_free(dev, usbhid->bufsize, usbhid->ctrlbuf, usbhid->ctrlbuf_dma);
 }
 
-/*
- * Sending HID_REQ_GET_REPORT changes the operation mode of the ps3 controller
- * to "operational".  Without this, the ps3 controller will not report any
- * events.
- */
-static void hid_fixup_sony_ps3_controller(struct usb_device *dev, int ifnum)
+static int usbhid_parse(struct hid_device *hid)
 {
-	int result;
-	char *buf = kmalloc(18, GFP_KERNEL);
-
-	if (!buf)
-		return;
-
-	result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
-				 HID_REQ_GET_REPORT,
-				 USB_DIR_IN | USB_TYPE_CLASS |
-				 USB_RECIP_INTERFACE,
-				 (3 << 8) | 0xf2, ifnum, buf, 17,
-				 USB_CTRL_GET_TIMEOUT);
-
-	if (result < 0)
-		err_hid("%s failed: %d\n", __func__, result);
-
-	kfree(buf);
-}
-
-static struct hid_device *usb_hid_configure(struct usb_interface *intf)
-{
+	struct usb_interface *intf = to_usb_interface(hid->dev.parent);
 	struct usb_host_interface *interface = intf->cur_altsetting;
 	struct usb_device *dev = interface_to_usbdev (intf);
 	struct hid_descriptor *hdesc;
-	struct hid_device *hid;
 	u32 quirks = 0;
-	unsigned int insize = 0, rsize = 0;
+	unsigned int rsize = 0;
 	char *rdesc;
-	int n, len;
-	struct usbhid_device *usbhid;
+	int ret, n;
 
 	quirks = usbhid_lookup_quirk(le16_to_cpu(dev->descriptor.idVendor),
 			le16_to_cpu(dev->descriptor.idProduct));
@@ -724,63 +718,75 @@
 				quirks |= HID_QUIRK_NOGET;
 	}
 
-	if (quirks & HID_QUIRK_IGNORE)
-		return NULL;
-
-	if ((quirks & HID_QUIRK_IGNORE_MOUSE) &&
-		(interface->desc.bInterfaceProtocol == USB_INTERFACE_PROTOCOL_MOUSE))
-			return NULL;
-
-
 	if (usb_get_extra_descriptor(interface, HID_DT_HID, &hdesc) &&
 	    (!interface->desc.bNumEndpoints ||
 	     usb_get_extra_descriptor(&interface->endpoint[0], HID_DT_HID, &hdesc))) {
 		dbg_hid("class descriptor not present\n");
-		return NULL;
+		return -ENODEV;
 	}
 
+	hid->version = le16_to_cpu(hdesc->bcdHID);
+	hid->country = hdesc->bCountryCode;
+
 	for (n = 0; n < hdesc->bNumDescriptors; n++)
 		if (hdesc->desc[n].bDescriptorType == HID_DT_REPORT)
 			rsize = le16_to_cpu(hdesc->desc[n].wDescriptorLength);
 
 	if (!rsize || rsize > HID_MAX_DESCRIPTOR_SIZE) {
 		dbg_hid("weird size of report descriptor (%u)\n", rsize);
-		return NULL;
+		return -EINVAL;
 	}
 
 	if (!(rdesc = kmalloc(rsize, GFP_KERNEL))) {
 		dbg_hid("couldn't allocate rdesc memory\n");
-		return NULL;
+		return -ENOMEM;
 	}
 
 	hid_set_idle(dev, interface->desc.bInterfaceNumber, 0, 0);
 
-	if ((n = hid_get_class_descriptor(dev, interface->desc.bInterfaceNumber, HID_DT_REPORT, rdesc, rsize)) < 0) {
+	ret = hid_get_class_descriptor(dev, interface->desc.bInterfaceNumber,
+			HID_DT_REPORT, rdesc, rsize);
+	if (ret < 0) {
 		dbg_hid("reading report descriptor failed\n");
 		kfree(rdesc);
-		return NULL;
+		goto err;
 	}
 
-	usbhid_fixup_report_descriptor(le16_to_cpu(dev->descriptor.idVendor),
-			le16_to_cpu(dev->descriptor.idProduct), rdesc,
-			rsize, rdesc_quirks_param);
-
 	dbg_hid("report descriptor (size %u, read %d) = ", rsize, n);
 	for (n = 0; n < rsize; n++)
 		dbg_hid_line(" %02x", (unsigned char) rdesc[n]);
 	dbg_hid_line("\n");
 
-	if (!(hid = hid_parse_report(rdesc, n))) {
+	ret = hid_parse_report(hid, rdesc, rsize);
+	kfree(rdesc);
+	if (ret) {
 		dbg_hid("parsing report descriptor failed\n");
-		kfree(rdesc);
-		return NULL;
+		goto err;
 	}
 
-	kfree(rdesc);
 	hid->quirks = quirks;
 
-	if (!(usbhid = kzalloc(sizeof(struct usbhid_device), GFP_KERNEL)))
-		goto fail_no_usbhid;
+	return 0;
+err:
+	return ret;
+}
+
+static int usbhid_start(struct hid_device *hid)
+{
+	struct usb_interface *intf = to_usb_interface(hid->dev.parent);
+	struct usb_host_interface *interface = intf->cur_altsetting;
+	struct usb_device *dev = interface_to_usbdev(intf);
+	struct usbhid_device *usbhid;
+	unsigned int n, insize = 0;
+	int ret;
+
+	WARN_ON(hid->driver_data);
+
+	usbhid = kzalloc(sizeof(struct usbhid_device), GFP_KERNEL);
+	if (usbhid == NULL) {
+		ret = -ENOMEM;
+		goto err;
+	}
 
 	hid->driver_data = usbhid;
 	usbhid->hid = hid;
@@ -799,28 +805,11 @@
 		insize = HID_MAX_BUFFER_SIZE;
 
 	if (hid_alloc_buffers(dev, hid)) {
-		hid_free_buffers(dev, hid);
+		ret = -ENOMEM;
 		goto fail;
 	}
 
-	hid->name[0] = 0;
-
-	if (dev->manufacturer)
-		strlcpy(hid->name, dev->manufacturer, sizeof(hid->name));
-
-	if (dev->product) {
-		if (dev->manufacturer)
-			strlcat(hid->name, " ", sizeof(hid->name));
-		strlcat(hid->name, dev->product, sizeof(hid->name));
-	}
-
-	if (!strlen(hid->name))
-		snprintf(hid->name, sizeof(hid->name), "HID %04x:%04x",
-			 le16_to_cpu(dev->descriptor.idVendor),
-			 le16_to_cpu(dev->descriptor.idProduct));
-
 	for (n = 0; n < interface->desc.bNumEndpoints; n++) {
-
 		struct usb_endpoint_descriptor *endpoint;
 		int pipe;
 		int interval;
@@ -832,7 +821,7 @@
 		interval = endpoint->bInterval;
 
 		/* Some vendors give fullspeed interval on highspeed devides */
-		if (quirks & HID_QUIRK_FULLSPEED_INTERVAL  &&
+		if (hid->quirks & HID_QUIRK_FULLSPEED_INTERVAL &&
 		    dev->speed == USB_SPEED_HIGH) {
 			interval = fls(endpoint->bInterval*8);
 			printk(KERN_INFO "%s: Fixing fullspeed to highspeed interval: %d -> %d\n",
@@ -843,6 +832,7 @@
 		if (hid->collection->usage == HID_GD_MOUSE && hid_mousepoll_interval > 0)
 			interval = hid_mousepoll_interval;
 
+		ret = -ENOMEM;
 		if (usb_endpoint_dir_in(endpoint)) {
 			if (usbhid->urbin)
 				continue;
@@ -868,6 +858,7 @@
 
 	if (!usbhid->urbin) {
 		err_hid("couldn't find an input interrupt endpoint");
+		ret = -ENODEV;
 		goto fail;
 	}
 
@@ -879,44 +870,25 @@
 	spin_lock_init(&usbhid->outlock);
 	spin_lock_init(&usbhid->ctrllock);
 
-	hid->version = le16_to_cpu(hdesc->bcdHID);
-	hid->country = hdesc->bCountryCode;
-	hid->dev = &intf->dev;
 	usbhid->intf = intf;
 	usbhid->ifnum = interface->desc.bInterfaceNumber;
 
-	hid->bus = BUS_USB;
-	hid->vendor = le16_to_cpu(dev->descriptor.idVendor);
-	hid->product = le16_to_cpu(dev->descriptor.idProduct);
-
-	usb_make_path(dev, hid->phys, sizeof(hid->phys));
-	strlcat(hid->phys, "/input", sizeof(hid->phys));
-	len = strlen(hid->phys);
-	if (len < sizeof(hid->phys) - 1)
-		snprintf(hid->phys + len, sizeof(hid->phys) - len,
-			 "%d", intf->altsetting[0].desc.bInterfaceNumber);
-
-	if (usb_string(dev, dev->descriptor.iSerialNumber, hid->uniq, 64) <= 0)
-		hid->uniq[0] = 0;
-
 	usbhid->urbctrl = usb_alloc_urb(0, GFP_KERNEL);
-	if (!usbhid->urbctrl)
+	if (!usbhid->urbctrl) {
+		ret = -ENOMEM;
 		goto fail;
+	}
 
 	usb_fill_control_urb(usbhid->urbctrl, dev, 0, (void *) usbhid->cr,
 			     usbhid->ctrlbuf, 1, hid_ctrl, hid);
 	usbhid->urbctrl->setup_dma = usbhid->cr_dma;
 	usbhid->urbctrl->transfer_dma = usbhid->ctrlbuf_dma;
 	usbhid->urbctrl->transfer_flags |= (URB_NO_TRANSFER_DMA_MAP | URB_NO_SETUP_DMA_MAP);
-	hid->hidinput_input_event = usb_hidinput_input_event;
-	hid->hid_open = usbhid_open;
-	hid->hid_close = usbhid_close;
-#ifdef CONFIG_USB_HIDDEV
-	hid->hiddev_hid_event = hiddev_hid_event;
-	hid->hiddev_report_event = hiddev_report_event;
-#endif
-	hid->hid_output_raw_report = usbhid_output_raw_report;
-	return hid;
+
+	usbhid_init_reports(hid);
+	hid_dump_device(hid);
+
+	return 0;
 
 fail:
 	usb_free_urb(usbhid->urbin);
@@ -924,24 +896,18 @@
 	usb_free_urb(usbhid->urbctrl);
 	hid_free_buffers(dev, hid);
 	kfree(usbhid);
-fail_no_usbhid:
-	hid_free_device(hid);
-
-	return NULL;
+err:
+	return ret;
 }
 
-static void hid_disconnect(struct usb_interface *intf)
+static void usbhid_stop(struct hid_device *hid)
 {
-	struct hid_device *hid = usb_get_intfdata (intf);
-	struct usbhid_device *usbhid;
+	struct usbhid_device *usbhid = hid->driver_data;
 
-	if (!hid)
+	if (WARN_ON(!usbhid))
 		return;
 
-	usbhid = hid->driver_data;
-
 	spin_lock_irq(&usbhid->inlock);	/* Sync with error handler */
-	usb_set_intfdata(intf, NULL);
 	set_bit(HID_DISCONNECTED, &usbhid->iofl);
 	spin_unlock_irq(&usbhid->inlock);
 	usb_kill_urb(usbhid->urbin);
@@ -958,86 +924,100 @@
 	if (hid->claimed & HID_CLAIMED_HIDRAW)
 		hidraw_disconnect(hid);
 
+	hid->claimed = 0;
+
 	usb_free_urb(usbhid->urbin);
 	usb_free_urb(usbhid->urbctrl);
 	usb_free_urb(usbhid->urbout);
 
 	hid_free_buffers(hid_to_usb_dev(hid), hid);
 	kfree(usbhid);
-	hid_free_device(hid);
+	hid->driver_data = NULL;
 }
 
+static struct hid_ll_driver usb_hid_driver = {
+	.parse = usbhid_parse,
+	.start = usbhid_start,
+	.stop = usbhid_stop,
+	.open = usbhid_open,
+	.close = usbhid_close,
+	.hidinput_input_event = usb_hidinput_input_event,
+};
+
 static int hid_probe(struct usb_interface *intf, const struct usb_device_id *id)
 {
+	struct usb_device *dev = interface_to_usbdev(intf);
 	struct hid_device *hid;
-	char path[64];
-	int i;
-	char *c;
+	size_t len;
+	int ret;
 
 	dbg_hid("HID probe called for ifnum %d\n",
 			intf->altsetting->desc.bInterfaceNumber);
 
-	if (!(hid = usb_hid_configure(intf)))
-		return -ENODEV;
-
-	usbhid_init_reports(hid);
-	hid_dump_device(hid);
-	if (hid->quirks & HID_QUIRK_RESET_LEDS)
-		usbhid_set_leds(hid);
-
-	if (!hidinput_connect(hid))
-		hid->claimed |= HID_CLAIMED_INPUT;
-	if (!hiddev_connect(hid))
-		hid->claimed |= HID_CLAIMED_HIDDEV;
-	if (!hidraw_connect(hid))
-		hid->claimed |= HID_CLAIMED_HIDRAW;
+	hid = hid_allocate_device();
+	if (IS_ERR(hid))
+		return PTR_ERR(hid);
 
 	usb_set_intfdata(intf, hid);
+	hid->ll_driver = &usb_hid_driver;
+	hid->hid_output_raw_report = usbhid_output_raw_report;
+	hid->ff_init = hid_pidff_init;
+#ifdef CONFIG_USB_HIDDEV
+	hid->hiddev_connect = hiddev_connect;
+	hid->hiddev_hid_event = hiddev_hid_event;
+	hid->hiddev_report_event = hiddev_report_event;
+#endif
+	hid->dev.parent = &intf->dev;
+	hid->bus = BUS_USB;
+	hid->vendor = le16_to_cpu(dev->descriptor.idVendor);
+	hid->product = le16_to_cpu(dev->descriptor.idProduct);
+	hid->name[0] = 0;
 
-	if (!hid->claimed) {
-		printk ("HID device claimed by neither input, hiddev nor hidraw\n");
-		hid_disconnect(intf);
-		return -ENODEV;
+	if (dev->manufacturer)
+		strlcpy(hid->name, dev->manufacturer, sizeof(hid->name));
+
+	if (dev->product) {
+		if (dev->manufacturer)
+			strlcat(hid->name, " ", sizeof(hid->name));
+		strlcat(hid->name, dev->product, sizeof(hid->name));
 	}
 
-	if ((hid->claimed & HID_CLAIMED_INPUT))
-		hid_ff_init(hid);
+	if (!strlen(hid->name))
+		snprintf(hid->name, sizeof(hid->name), "HID %04x:%04x",
+			 le16_to_cpu(dev->descriptor.idVendor),
+			 le16_to_cpu(dev->descriptor.idProduct));
 
-	if (hid->quirks & HID_QUIRK_SONY_PS3_CONTROLLER)
-		hid_fixup_sony_ps3_controller(interface_to_usbdev(intf),
-			intf->cur_altsetting->desc.bInterfaceNumber);
+	usb_make_path(dev, hid->phys, sizeof(hid->phys));
+	strlcat(hid->phys, "/input", sizeof(hid->phys));
+	len = strlen(hid->phys);
+	if (len < sizeof(hid->phys) - 1)
+		snprintf(hid->phys + len, sizeof(hid->phys) - len,
+			 "%d", intf->altsetting[0].desc.bInterfaceNumber);
 
-	printk(KERN_INFO);
+	if (usb_string(dev, dev->descriptor.iSerialNumber, hid->uniq, 64) <= 0)
+		hid->uniq[0] = 0;
 
-	if (hid->claimed & HID_CLAIMED_INPUT)
-		printk("input");
-	if ((hid->claimed & HID_CLAIMED_INPUT) && ((hid->claimed & HID_CLAIMED_HIDDEV) ||
-				hid->claimed & HID_CLAIMED_HIDRAW))
-		printk(",");
-	if (hid->claimed & HID_CLAIMED_HIDDEV)
-		printk("hiddev%d", hid->minor);
-	if ((hid->claimed & HID_CLAIMED_INPUT) && (hid->claimed & HID_CLAIMED_HIDDEV) &&
-			(hid->claimed & HID_CLAIMED_HIDRAW))
-		printk(",");
-	if (hid->claimed & HID_CLAIMED_HIDRAW)
-		printk("hidraw%d", ((struct hidraw*)hid->hidraw)->minor);
-
-	c = "Device";
-	for (i = 0; i < hid->maxcollection; i++) {
-		if (hid->collection[i].type == HID_COLLECTION_APPLICATION &&
-		    (hid->collection[i].usage & HID_USAGE_PAGE) == HID_UP_GENDESK &&
-		    (hid->collection[i].usage & 0xffff) < ARRAY_SIZE(hid_types)) {
-			c = hid_types[hid->collection[i].usage & 0xffff];
-			break;
-		}
+	ret = hid_add_device(hid);
+	if (ret) {
+		if (ret != -ENODEV)
+			dev_err(&intf->dev, "can't add hid device: %d\n", ret);
+		goto err;
 	}
 
-	usb_make_path(interface_to_usbdev(intf), path, 63);
-
-	printk(": USB HID v%x.%02x %s [%s] on %s\n",
-		hid->version >> 8, hid->version & 0xff, c, hid->name, path);
-
 	return 0;
+err:
+	hid_destroy_device(hid);
+	return ret;
+}
+
+static void hid_disconnect(struct usb_interface *intf)
+{
+	struct hid_device *hid = usb_get_intfdata(intf);
+
+	if (WARN_ON(!hid))
+		return;
+
+	hid_destroy_device(hid);
 }
 
 static int hid_suspend(struct usb_interface *intf, pm_message_t message)
@@ -1107,9 +1087,22 @@
 	.supports_autosuspend = 1,
 };
 
+static const struct hid_device_id hid_usb_table[] = {
+	{ HID_USB_DEVICE(HID_ANY_ID, HID_ANY_ID) },
+	{ }
+};
+
+static struct hid_driver hid_usb_driver = {
+	.name = "generic-usb",
+	.id_table = hid_usb_table,
+};
+
 static int __init hid_init(void)
 {
 	int retval;
+	retval = hid_register_driver(&hid_usb_driver);
+	if (retval)
+		goto hid_register_fail;
 	retval = usbhid_quirks_init(quirks_param);
 	if (retval)
 		goto usbhid_quirks_init_fail;
@@ -1119,7 +1112,8 @@
 	retval = usb_register(&hid_driver);
 	if (retval)
 		goto usb_register_fail;
-	info(DRIVER_VERSION ":" DRIVER_DESC);
+	printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
+			DRIVER_DESC "\n");
 
 	return 0;
 usb_register_fail:
@@ -1127,6 +1121,8 @@
 hiddev_init_fail:
 	usbhid_quirks_exit();
 usbhid_quirks_init_fail:
+	hid_unregister_driver(&hid_usb_driver);
+hid_register_fail:
 	return retval;
 }
 
@@ -1135,6 +1131,7 @@
 	usb_deregister(&hid_driver);
 	hiddev_exit();
 	usbhid_quirks_exit();
+	hid_unregister_driver(&hid_usb_driver);
 }
 
 module_init(hid_init);
diff --git a/drivers/hid/usbhid/hid-ff.c b/drivers/hid/usbhid/hid-ff.c
deleted file mode 100644
index 1d0dac5..0000000
--- a/drivers/hid/usbhid/hid-ff.c
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- *  Force feedback support for hid devices.
- *  Not all hid devices use the same protocol. For example, some use PID,
- *  other use their own proprietary procotol.
- *
- *  Copyright (c) 2002-2004 Johann Deneux
- */
-
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Should you need to contact me, the author, you can do so by
- * e-mail - mail your message to <johann.deneux@it.uu.se>
- */
-
-#include <linux/input.h>
-
-#undef DEBUG
-#include <linux/usb.h>
-
-#include <linux/hid.h>
-#include "usbhid.h"
-
-/*
- * This table contains pointers to initializers. To add support for new
- * devices, you need to add the USB vendor and product ids here.
- */
-struct hid_ff_initializer {
-	u16 idVendor;
-	u16 idProduct;
-	int (*init)(struct hid_device*);
-};
-
-/*
- * We try pidff when no other driver is found because PID is the
- * standards compliant way of implementing force feedback in HID.
- * pidff_init() will quickly abort if the device doesn't appear to
- * be a PID device
- */
-static struct hid_ff_initializer inits[] = {
-#ifdef CONFIG_LOGITECH_FF
-	{ 0x46d, 0xc211, hid_lgff_init }, /* Logitech Cordless rumble pad */
-	{ 0x46d, 0xc219, hid_lgff_init }, /* Logitech Cordless rumble pad 2 */
-	{ 0x46d, 0xc283, hid_lgff_init }, /* Logitech Wingman Force 3d */
-	{ 0x46d, 0xc286, hid_lgff_init }, /* Logitech Force 3D Pro Joystick */
-	{ 0x46d, 0xc294, hid_lgff_init }, /* Logitech Formula Force EX */
-	{ 0x46d, 0xc295, hid_lgff_init }, /* Logitech MOMO force wheel */
-	{ 0x46d, 0xca03, hid_lgff_init }, /* Logitech MOMO force wheel */
-#endif
-#ifdef CONFIG_LOGIRUMBLEPAD2_FF
-	{ 0x46d, 0xc218, hid_lg2ff_init }, /* Logitech Rumblepad 2 */
-#endif
-#ifdef CONFIG_PANTHERLORD_FF
-	{ 0x810, 0x0001, hid_plff_init }, /* "Twin USB Joystick" */
-	{ 0xe8f, 0x0003, hid_plff_init }, /* "GreenAsia Inc.    USB Joystick     " */
-#endif
-#ifdef CONFIG_THRUSTMASTER_FF
-	{ 0x44f, 0xb300, hid_tmff_init },
-	{ 0x44f, 0xb304, hid_tmff_init },
-	{ 0x44f, 0xb651, hid_tmff_init }, /* FGT Rumble Force Wheel */
-	{ 0x44f, 0xb654, hid_tmff_init }, /* FGT Force Feedback Wheel */
-#endif
-#ifdef CONFIG_ZEROPLUS_FF
-	{ 0xc12, 0x0005, hid_zpff_init },
-	{ 0xc12, 0x0030, hid_zpff_init },
-#endif
-	{ 0,	 0,	 hid_pidff_init}  /* Matches anything */
-};
-
-int hid_ff_init(struct hid_device* hid)
-{
-	struct hid_ff_initializer *init;
-	int vendor = le16_to_cpu(hid_to_usb_dev(hid)->descriptor.idVendor);
-	int product = le16_to_cpu(hid_to_usb_dev(hid)->descriptor.idProduct);
-
-	for (init = inits; init->idVendor; init++)
-		if (init->idVendor == vendor && init->idProduct == product)
-			break;
-
-	return init->init(hid);
-}
-EXPORT_SYMBOL_GPL(hid_ff_init);
-
diff --git a/drivers/hid/usbhid/hid-lg2ff.c b/drivers/hid/usbhid/hid-lg2ff.c
deleted file mode 100644
index d469bd0..0000000
--- a/drivers/hid/usbhid/hid-lg2ff.c
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- *  Force feedback support for Logitech Rumblepad 2
- *
- *  Copyright (c) 2008 Anssi Hannula <anssi.hannula@gmail.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/input.h>
-#include <linux/usb.h>
-#include <linux/hid.h>
-#include "usbhid.h"
-
-struct lg2ff_device {
-	struct hid_report *report;
-};
-
-static int play_effect(struct input_dev *dev, void *data,
-			 struct ff_effect *effect)
-{
-	struct hid_device *hid = input_get_drvdata(dev);
-	struct lg2ff_device *lg2ff = data;
-	int weak, strong;
-
-	strong = effect->u.rumble.strong_magnitude;
-	weak = effect->u.rumble.weak_magnitude;
-
-	if (weak || strong) {
-		weak = weak * 0xff / 0xffff;
-		strong = strong * 0xff / 0xffff;
-
-		lg2ff->report->field[0]->value[0] = 0x51;
-		lg2ff->report->field[0]->value[2] = weak;
-		lg2ff->report->field[0]->value[4] = strong;
-	} else {
-		lg2ff->report->field[0]->value[0] = 0xf3;
-		lg2ff->report->field[0]->value[2] = 0x00;
-		lg2ff->report->field[0]->value[4] = 0x00;
-	}
-
-	usbhid_submit_report(hid, lg2ff->report, USB_DIR_OUT);
-	return 0;
-}
-
-int hid_lg2ff_init(struct hid_device *hid)
-{
-	struct lg2ff_device *lg2ff;
-	struct hid_report *report;
-	struct hid_input *hidinput = list_entry(hid->inputs.next,
-						struct hid_input, list);
-	struct list_head *report_list =
-			&hid->report_enum[HID_OUTPUT_REPORT].report_list;
-	struct input_dev *dev = hidinput->input;
-	int error;
-
-	if (list_empty(report_list)) {
-		printk(KERN_ERR "hid-lg2ff: no output report found\n");
-		return -ENODEV;
-	}
-
-	report = list_entry(report_list->next, struct hid_report, list);
-
-	if (report->maxfield < 1) {
-		printk(KERN_ERR "hid-lg2ff: output report is empty\n");
-		return -ENODEV;
-	}
-	if (report->field[0]->report_count < 7) {
-		printk(KERN_ERR "hid-lg2ff: not enough values in the field\n");
-		return -ENODEV;
-	}
-
-	lg2ff = kmalloc(sizeof(struct lg2ff_device), GFP_KERNEL);
-	if (!lg2ff)
-		return -ENOMEM;
-
-	set_bit(FF_RUMBLE, dev->ffbit);
-
-	error = input_ff_create_memless(dev, lg2ff, play_effect);
-	if (error) {
-		kfree(lg2ff);
-		return error;
-	}
-
-	lg2ff->report = report;
-	report->field[0]->value[0] = 0xf3;
-	report->field[0]->value[1] = 0x00;
-	report->field[0]->value[2] = 0x00;
-	report->field[0]->value[3] = 0x00;
-	report->field[0]->value[4] = 0x00;
-	report->field[0]->value[5] = 0x00;
-	report->field[0]->value[6] = 0x00;
-
-	usbhid_submit_report(hid, report, USB_DIR_OUT);
-
-	printk(KERN_INFO "Force feedback for Logitech Rumblepad 2 by "
-	       "Anssi Hannula <anssi.hannula@gmail.com>\n");
-
-	return 0;
-}
diff --git a/drivers/hid/usbhid/hid-lgff.c b/drivers/hid/usbhid/hid-lgff.c
deleted file mode 100644
index 4b7ab6a..0000000
--- a/drivers/hid/usbhid/hid-lgff.c
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- * Force feedback support for hid-compliant for some of the devices from
- * Logitech, namely:
- * - WingMan Cordless RumblePad
- * - WingMan Force 3D
- *
- *  Copyright (c) 2002-2004 Johann Deneux
- *  Copyright (c) 2006 Anssi Hannula <anssi.hannula@gmail.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
- *
- * Should you need to contact me, the author, you can do so by
- * e-mail - mail your message to <johann.deneux@it.uu.se>
- */
-
-#include <linux/input.h>
-#include <linux/usb.h>
-#include <linux/hid.h>
-#include "usbhid.h"
-
-struct dev_type {
-	u16 idVendor;
-	u16 idProduct;
-	const signed short *ff;
-};
-
-static const signed short ff_rumble[] = {
-	FF_RUMBLE,
-	-1
-};
-
-static const signed short ff_joystick[] = {
-	FF_CONSTANT,
-	-1
-};
-
-static const struct dev_type devices[] = {
-	{ 0x046d, 0xc211, ff_rumble },
-	{ 0x046d, 0xc219, ff_rumble },
-	{ 0x046d, 0xc283, ff_joystick },
-	{ 0x046d, 0xc286, ff_joystick },
-	{ 0x046d, 0xc294, ff_joystick },
-	{ 0x046d, 0xc295, ff_joystick },
-	{ 0x046d, 0xca03, ff_joystick },
-};
-
-static int hid_lgff_play(struct input_dev *dev, void *data, struct ff_effect *effect)
-{
-	struct hid_device *hid = input_get_drvdata(dev);
-	struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list;
-	struct hid_report *report = list_entry(report_list->next, struct hid_report, list);
-	int x, y;
-	unsigned int left, right;
-
-#define CLAMP(x) if (x < 0) x = 0; if (x > 0xff) x = 0xff
-
-	switch (effect->type) {
-	case FF_CONSTANT:
-		x = effect->u.ramp.start_level + 0x7f;	/* 0x7f is center */
-		y = effect->u.ramp.end_level + 0x7f;
-		CLAMP(x);
-		CLAMP(y);
-		report->field[0]->value[0] = 0x51;
-		report->field[0]->value[1] = 0x08;
-		report->field[0]->value[2] = x;
-		report->field[0]->value[3] = y;
-		dbg_hid("(x, y)=(%04x, %04x)\n", x, y);
-		usbhid_submit_report(hid, report, USB_DIR_OUT);
-		break;
-
-	case FF_RUMBLE:
-		right = effect->u.rumble.strong_magnitude;
-		left = effect->u.rumble.weak_magnitude;
-		right = right * 0xff / 0xffff;
-		left = left * 0xff / 0xffff;
-		CLAMP(left);
-		CLAMP(right);
-		report->field[0]->value[0] = 0x42;
-		report->field[0]->value[1] = 0x00;
-		report->field[0]->value[2] = left;
-		report->field[0]->value[3] = right;
-		dbg_hid("(left, right)=(%04x, %04x)\n", left, right);
-		usbhid_submit_report(hid, report, USB_DIR_OUT);
-		break;
-	}
-	return 0;
-}
-
-int hid_lgff_init(struct hid_device* hid)
-{
-	struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, list);
-	struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list;
-	struct input_dev *dev = hidinput->input;
-	struct hid_report *report;
-	struct hid_field *field;
-	const signed short *ff_bits = ff_joystick;
-	int error;
-	int i;
-
-	/* Find the report to use */
-	if (list_empty(report_list)) {
-		err_hid("No output report found");
-		return -1;
-	}
-
-	/* Check that the report looks ok */
-	report = list_entry(report_list->next, struct hid_report, list);
-	if (!report) {
-		err_hid("NULL output report");
-		return -1;
-	}
-
-	field = report->field[0];
-	if (!field) {
-		err_hid("NULL field");
-		return -1;
-	}
-
-	for (i = 0; i < ARRAY_SIZE(devices); i++) {
-		if (dev->id.vendor == devices[i].idVendor &&
-		    dev->id.product == devices[i].idProduct) {
-			ff_bits = devices[i].ff;
-			break;
-		}
-	}
-
-	for (i = 0; ff_bits[i] >= 0; i++)
-		set_bit(ff_bits[i], dev->ffbit);
-
-	error = input_ff_create_memless(dev, NULL, hid_lgff_play);
-	if (error)
-		return error;
-
-	printk(KERN_INFO "Force feedback for Logitech force feedback devices by Johann Deneux <johann.deneux@it.uu.se>\n");
-
-	return 0;
-}
diff --git a/drivers/hid/usbhid/hid-pidff.c b/drivers/hid/usbhid/hid-pidff.c
index 0113261..484e3ee 100644
--- a/drivers/hid/usbhid/hid-pidff.c
+++ b/drivers/hid/usbhid/hid-pidff.c
@@ -397,7 +397,6 @@
 			  effect->u.condition[i].left_saturation);
 		pidff_set(&pidff->set_condition[PID_DEAD_BAND],
 			  effect->u.condition[i].deadband);
-		usbhid_wait_io(pidff->hid);
 		usbhid_submit_report(pidff->hid, pidff->reports[PID_SET_CONDITION],
 				  USB_DIR_OUT);
 	}
@@ -512,7 +511,6 @@
 		pidff->effect_operation[PID_LOOP_COUNT].value[0] = n;
 	}
 
-	usbhid_wait_io(pidff->hid);
 	usbhid_submit_report(pidff->hid, pidff->reports[PID_EFFECT_OPERATION],
 			  USB_DIR_OUT);
 }
@@ -548,6 +546,9 @@
 	int pid_id = pidff->pid_id[effect_id];
 
 	debug("starting to erase %d/%d", effect_id, pidff->pid_id[effect_id]);
+	/* Wait for the queue to clear. We do not want a full fifo to
+	   prevent the effect removal. */
+	usbhid_wait_io(pidff->hid);
 	pidff_playback_pid(pidff, pid_id, 0);
 	pidff_erase_pid(pidff, pid_id);
 
diff --git a/drivers/hid/usbhid/hid-plff.c b/drivers/hid/usbhid/hid-plff.c
deleted file mode 100644
index 9eb83cf..0000000
--- a/drivers/hid/usbhid/hid-plff.c
+++ /dev/null
@@ -1,139 +0,0 @@
-/*
- *  Force feedback support for PantherLord/GreenAsia based devices
- *
- *  The devices are distributed under various names and the same USB device ID
- *  can be used in both adapters and actual game controllers.
- *
- *  0810:0001 "Twin USB Joystick"
- *   - tested with PantherLord USB/PS2 2in1 Adapter
- *   - contains two reports, one for each port (HID_QUIRK_MULTI_INPUT)
- *
- *  0e8f:0003 "GreenAsia Inc.    USB Joystick     "
- *   - tested with Köng Gaming gamepad
- *
- *  Copyright (c) 2007 Anssi Hannula <anssi.hannula@gmail.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
- */
-
-
-/* #define DEBUG */
-
-#define debug(format, arg...) pr_debug("hid-plff: " format "\n" , ## arg)
-
-#include <linux/input.h>
-#include <linux/usb.h>
-#include <linux/hid.h>
-#include "usbhid.h"
-
-struct plff_device {
-	struct hid_report *report;
-};
-
-static int hid_plff_play(struct input_dev *dev, void *data,
-			 struct ff_effect *effect)
-{
-	struct hid_device *hid = input_get_drvdata(dev);
-	struct plff_device *plff = data;
-	int left, right;
-
-	left = effect->u.rumble.strong_magnitude;
-	right = effect->u.rumble.weak_magnitude;
-	debug("called with 0x%04x 0x%04x", left, right);
-
-	left = left * 0x7f / 0xffff;
-	right = right * 0x7f / 0xffff;
-
-	plff->report->field[0]->value[2] = left;
-	plff->report->field[0]->value[3] = right;
-	debug("running with 0x%02x 0x%02x", left, right);
-	usbhid_submit_report(hid, plff->report, USB_DIR_OUT);
-
-	return 0;
-}
-
-int hid_plff_init(struct hid_device *hid)
-{
-	struct plff_device *plff;
-	struct hid_report *report;
-	struct hid_input *hidinput;
-	struct list_head *report_list =
-			&hid->report_enum[HID_OUTPUT_REPORT].report_list;
-	struct list_head *report_ptr = report_list;
-	struct input_dev *dev;
-	int error;
-
-	/* The device contains one output report per physical device, all
-	   containing 1 field, which contains 4 ff00.0002 usages and 4 16bit
-	   absolute values.
-
-	   The input reports also contain a field which contains
-	   8 ff00.0001 usages and 8 boolean values. Their meaning is
-	   currently unknown. */
-
-	if (list_empty(report_list)) {
-		printk(KERN_ERR "hid-plff: no output reports found\n");
-		return -ENODEV;
-	}
-
-	list_for_each_entry(hidinput, &hid->inputs, list) {
-
-		report_ptr = report_ptr->next;
-
-		if (report_ptr == report_list) {
-			printk(KERN_ERR "hid-plff: required output report is missing\n");
-			return -ENODEV;
-		}
-
-		report = list_entry(report_ptr, struct hid_report, list);
-		if (report->maxfield < 1) {
-			printk(KERN_ERR "hid-plff: no fields in the report\n");
-			return -ENODEV;
-		}
-
-		if (report->field[0]->report_count < 4) {
-			printk(KERN_ERR "hid-plff: not enough values in the field\n");
-			return -ENODEV;
-		}
-
-		plff = kzalloc(sizeof(struct plff_device), GFP_KERNEL);
-		if (!plff)
-			return -ENOMEM;
-
-		dev = hidinput->input;
-
-		set_bit(FF_RUMBLE, dev->ffbit);
-
-		error = input_ff_create_memless(dev, plff, hid_plff_play);
-		if (error) {
-			kfree(plff);
-			return error;
-		}
-
-		plff->report = report;
-		plff->report->field[0]->value[0] = 0x00;
-		plff->report->field[0]->value[1] = 0x00;
-		plff->report->field[0]->value[2] = 0x00;
-		plff->report->field[0]->value[3] = 0x00;
-		usbhid_submit_report(hid, plff->report, USB_DIR_OUT);
-	}
-
-	printk(KERN_INFO "hid-plff: Force feedback for PantherLord/GreenAsia "
-	       "devices by Anssi Hannula <anssi.hannula@gmail.com>\n");
-
-	return 0;
-}
diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c
index b15f882..47ebe04 100644
--- a/drivers/hid/usbhid/hid-quirks.c
+++ b/drivers/hid/usbhid/hid-quirks.c
@@ -17,412 +17,7 @@
 
 #include <linux/hid.h>
 
-#define USB_VENDOR_ID_A4TECH		0x09da
-#define USB_DEVICE_ID_A4TECH_WCP32PU	0x0006
-#define USB_DEVICE_ID_A4TECH_X5_005D	0x000a
-
-#define USB_VENDOR_ID_AASHIMA		0x06d6
-#define USB_DEVICE_ID_AASHIMA_GAMEPAD	0x0025
-#define USB_DEVICE_ID_AASHIMA_PREDATOR	0x0026
-
-#define USB_VENDOR_ID_ACECAD		0x0460
-#define USB_DEVICE_ID_ACECAD_FLAIR	0x0004
-#define USB_DEVICE_ID_ACECAD_302	0x0008
-
-#define USB_VENDOR_ID_ADS_TECH 		0x06e1
-#define USB_DEVICE_ID_ADS_TECH_RADIO_SI470X	0xa155
-
-#define USB_VENDOR_ID_AFATECH		0x15a4
-#define USB_DEVICE_ID_AFATECH_AF9016	0x9016
-
-#define USB_VENDOR_ID_AIPTEK		0x08ca
-#define USB_DEVICE_ID_AIPTEK_01		0x0001
-#define USB_DEVICE_ID_AIPTEK_10		0x0010
-#define USB_DEVICE_ID_AIPTEK_20		0x0020
-#define USB_DEVICE_ID_AIPTEK_21		0x0021
-#define USB_DEVICE_ID_AIPTEK_22		0x0022
-#define USB_DEVICE_ID_AIPTEK_23		0x0023
-#define USB_DEVICE_ID_AIPTEK_24		0x0024
-
-#define USB_VENDOR_ID_AIRCABLE		0x16CA
-#define USB_DEVICE_ID_AIRCABLE1		0x1502
-
-#define USB_VENDOR_ID_ALCOR		0x058f
-#define USB_DEVICE_ID_ALCOR_USBRS232	0x9720
-
-#define USB_VENDOR_ID_ALPS		0x0433
-#define USB_DEVICE_ID_IBM_GAMEPAD	0x1101
-
-#define USB_VENDOR_ID_APPLE		0x05ac
-#define USB_DEVICE_ID_APPLE_MIGHTYMOUSE	0x0304
-#define USB_DEVICE_ID_APPLE_FOUNTAIN_ANSI	0x020e
-#define USB_DEVICE_ID_APPLE_FOUNTAIN_ISO	0x020f
-#define USB_DEVICE_ID_APPLE_GEYSER_ANSI	0x0214
-#define USB_DEVICE_ID_APPLE_GEYSER_ISO	0x0215
-#define USB_DEVICE_ID_APPLE_GEYSER_JIS	0x0216
-#define USB_DEVICE_ID_APPLE_GEYSER3_ANSI	0x0217
-#define USB_DEVICE_ID_APPLE_GEYSER3_ISO	0x0218
-#define USB_DEVICE_ID_APPLE_GEYSER3_JIS	0x0219
-#define USB_DEVICE_ID_APPLE_GEYSER4_ANSI	0x021a
-#define USB_DEVICE_ID_APPLE_GEYSER4_ISO	0x021b
-#define USB_DEVICE_ID_APPLE_GEYSER4_JIS	0x021c
-#define USB_DEVICE_ID_APPLE_ALU_ANSI	0x0220
-#define USB_DEVICE_ID_APPLE_ALU_ISO	0x0221
-#define USB_DEVICE_ID_APPLE_ALU_JIS	0x0222
-#define USB_DEVICE_ID_APPLE_WELLSPRING_ANSI	0x0223
-#define USB_DEVICE_ID_APPLE_WELLSPRING_ISO	0x0224
-#define USB_DEVICE_ID_APPLE_WELLSPRING_JIS	0x0225
-#define USB_DEVICE_ID_APPLE_GEYSER4_HF_ANSI    0x0229
-#define USB_DEVICE_ID_APPLE_GEYSER4_HF_ISO     0x022a
-#define USB_DEVICE_ID_APPLE_GEYSER4_HF_JIS     0x022b
-#define USB_DEVICE_ID_APPLE_ALU_WIRELESS_ANSI  0x022c
-#define USB_DEVICE_ID_APPLE_ALU_WIRELESS_ISO   0x022d
-#define USB_DEVICE_ID_APPLE_ALU_WIRELESS_JIS   0x022e
-#define USB_DEVICE_ID_APPLE_WELLSPRING2_ANSI	0x0230
-#define USB_DEVICE_ID_APPLE_WELLSPRING2_ISO	0x0231
-#define USB_DEVICE_ID_APPLE_WELLSPRING2_JIS	0x0232
-#define USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY	0x030a
-#define USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY	0x030b
-#define USB_DEVICE_ID_APPLE_IRCONTROL4	0x8242
-
-#define USB_VENDOR_ID_ASUS		0x0b05
-#define USB_DEVICE_ID_ASUS_LCM		0x1726
-
-#define USB_VENDOR_ID_ATEN		0x0557
-#define USB_DEVICE_ID_ATEN_UC100KM	0x2004
-#define USB_DEVICE_ID_ATEN_CS124U	0x2202
-#define USB_DEVICE_ID_ATEN_2PORTKVM	0x2204
-#define USB_DEVICE_ID_ATEN_4PORTKVM	0x2205
-#define USB_DEVICE_ID_ATEN_4PORTKVMC	0x2208
-
-#define USB_VENDOR_ID_BELKIN           0x050d
-#define USB_DEVICE_ID_FLIP_KVM         0x3201
-
-#define USB_VENDOR_ID_BERKSHIRE		0x0c98
-#define USB_DEVICE_ID_BERKSHIRE_PCWD	0x1140
-
-#define USB_VENDOR_ID_CHERRY		0x046a
-#define USB_DEVICE_ID_CHERRY_CYMOTION	0x0023
-
-#define USB_VENDOR_ID_CHIC		0x05fe
-#define USB_DEVICE_ID_CHIC_GAMEPAD	0x0014
-
-#define USB_VENDOR_ID_CIDC		0x1677
-
-#define USB_VENDOR_ID_CMEDIA		0x0d8c
-#define USB_DEVICE_ID_CM109		0x000e
-
-#define USB_VENDOR_ID_CODEMERCS		0x07c0
-#define USB_DEVICE_ID_CODEMERCS_IOW_FIRST	0x1500
-#define USB_DEVICE_ID_CODEMERCS_IOW_LAST	0x15ff
-
-#define USB_VENDOR_ID_CYGNAL		0x10c4
-#define USB_DEVICE_ID_CYGNAL_RADIO_SI470X	0x818a
-
-#define USB_VENDOR_ID_CYPRESS		0x04b4
-#define USB_DEVICE_ID_CYPRESS_MOUSE	0x0001
-#define USB_DEVICE_ID_CYPRESS_HIDCOM	0x5500
-#define USB_DEVICE_ID_CYPRESS_ULTRAMOUSE	0x7417
-#define USB_DEVICE_ID_CYPRESS_BARCODE_1	0xde61
-#define USB_DEVICE_ID_CYPRESS_BARCODE_2	0xde64
-
-#define USB_VENDOR_ID_DELL		0x413c
-#define USB_DEVICE_ID_DELL_W7658	0x2005
-
-#define USB_VENDOR_ID_DELORME		0x1163
-#define USB_DEVICE_ID_DELORME_EARTHMATE 0x0100
-#define USB_DEVICE_ID_DELORME_EM_LT20	0x0200
-
-#define USB_VENDOR_ID_DMI		0x0c0b
-#define USB_DEVICE_ID_DMI_ENC		0x5fab
-
-#define USB_VENDOR_ID_ELO		0x04E7
-#define USB_DEVICE_ID_ELO_TS2700	0x0020
-
-#define USB_VENDOR_ID_ESSENTIAL_REALITY	0x0d7f
-#define USB_DEVICE_ID_ESSENTIAL_REALITY_P5 0x0100
-
-#define USB_VENDOR_ID_EZKEY 		0x0518
-#define USB_DEVICE_ID_BTC_8193		0x0002
-
-#define USB_VENDOR_ID_GAMERON		0x0810
-#define USB_DEVICE_ID_GAMERON_DUAL_PSX_ADAPTOR	0x0001
-
-#define USB_VENDOR_ID_GENERAL_TOUCH	0x0dfc
-
-#define USB_VENDOR_ID_GLAB		0x06c2
-#define USB_DEVICE_ID_4_PHIDGETSERVO_30	0x0038
-#define USB_DEVICE_ID_1_PHIDGETSERVO_30	0x0039
-#define USB_DEVICE_ID_0_0_4_IF_KIT	0x0040
-#define USB_DEVICE_ID_0_16_16_IF_KIT	0x0044
-#define USB_DEVICE_ID_8_8_8_IF_KIT	0x0045
-#define USB_DEVICE_ID_0_8_7_IF_KIT	0x0051
-#define USB_DEVICE_ID_0_8_8_IF_KIT	0x0053
-#define USB_DEVICE_ID_PHIDGET_MOTORCONTROL	0x0058
-
-#define USB_VENDOR_ID_GOTOP		0x08f2
-#define USB_DEVICE_ID_SUPER_Q2		0x007f
-#define USB_DEVICE_ID_GOGOPEN		0x00ce
-#define USB_DEVICE_ID_PENPOWER		0x00f4
-
-#define USB_VENDOR_ID_GRETAGMACBETH	0x0971
-#define USB_DEVICE_ID_GRETAGMACBETH_HUEY	0x2005
-
-#define USB_VENDOR_ID_GRIFFIN		0x077d
-#define USB_DEVICE_ID_POWERMATE		0x0410
-#define USB_DEVICE_ID_SOUNDKNOB		0x04AA
-
-#define USB_VENDOR_ID_GTCO		0x078c
-#define USB_DEVICE_ID_GTCO_90		0x0090
-#define USB_DEVICE_ID_GTCO_100		0x0100
-#define USB_DEVICE_ID_GTCO_101		0x0101
-#define USB_DEVICE_ID_GTCO_103		0x0103
-#define USB_DEVICE_ID_GTCO_104		0x0104
-#define USB_DEVICE_ID_GTCO_105		0x0105
-#define USB_DEVICE_ID_GTCO_106		0x0106
-#define USB_DEVICE_ID_GTCO_107		0x0107
-#define USB_DEVICE_ID_GTCO_108		0x0108
-#define USB_DEVICE_ID_GTCO_200		0x0200
-#define USB_DEVICE_ID_GTCO_201		0x0201
-#define USB_DEVICE_ID_GTCO_202		0x0202
-#define USB_DEVICE_ID_GTCO_203		0x0203
-#define USB_DEVICE_ID_GTCO_204		0x0204
-#define USB_DEVICE_ID_GTCO_205		0x0205
-#define USB_DEVICE_ID_GTCO_206		0x0206
-#define USB_DEVICE_ID_GTCO_207		0x0207
-#define USB_DEVICE_ID_GTCO_300		0x0300
-#define USB_DEVICE_ID_GTCO_301		0x0301
-#define USB_DEVICE_ID_GTCO_302		0x0302
-#define USB_DEVICE_ID_GTCO_303		0x0303
-#define USB_DEVICE_ID_GTCO_304		0x0304
-#define USB_DEVICE_ID_GTCO_305		0x0305
-#define USB_DEVICE_ID_GTCO_306		0x0306
-#define USB_DEVICE_ID_GTCO_307		0x0307
-#define USB_DEVICE_ID_GTCO_308		0x0308
-#define USB_DEVICE_ID_GTCO_309		0x0309
-#define USB_DEVICE_ID_GTCO_400		0x0400
-#define USB_DEVICE_ID_GTCO_401		0x0401
-#define USB_DEVICE_ID_GTCO_402		0x0402
-#define USB_DEVICE_ID_GTCO_403		0x0403
-#define USB_DEVICE_ID_GTCO_404		0x0404
-#define USB_DEVICE_ID_GTCO_405		0x0405
-#define USB_DEVICE_ID_GTCO_500		0x0500
-#define USB_DEVICE_ID_GTCO_501		0x0501
-#define USB_DEVICE_ID_GTCO_502		0x0502
-#define USB_DEVICE_ID_GTCO_503		0x0503
-#define USB_DEVICE_ID_GTCO_504		0x0504
-#define USB_DEVICE_ID_GTCO_1000		0x1000
-#define USB_DEVICE_ID_GTCO_1001		0x1001
-#define USB_DEVICE_ID_GTCO_1002		0x1002
-#define USB_DEVICE_ID_GTCO_1003		0x1003
-#define USB_DEVICE_ID_GTCO_1004		0x1004
-#define USB_DEVICE_ID_GTCO_1005		0x1005
-#define USB_DEVICE_ID_GTCO_1006		0x1006
-#define USB_DEVICE_ID_GTCO_1007		0x1007
-#define USB_VENDOR_ID_HAPP		0x078b
-#define USB_DEVICE_ID_UGCI_DRIVING	0x0010
-#define USB_DEVICE_ID_UGCI_FLYING	0x0020
-#define USB_DEVICE_ID_UGCI_FIGHTING	0x0030
-
-#define USB_VENDOR_ID_IMATION		0x0718
-#define USB_DEVICE_ID_DISC_STAKKA	0xd000
-
-#define USB_VENDOR_ID_KBGEAR		0x084e
-#define USB_DEVICE_ID_KBGEAR_JAMSTUDIO	0x1001
-
-#define USB_VENDOR_ID_LD		0x0f11
-#define USB_DEVICE_ID_LD_CASSY		0x1000
-#define USB_DEVICE_ID_LD_POCKETCASSY	0x1010
-#define USB_DEVICE_ID_LD_MOBILECASSY	0x1020
-#define USB_DEVICE_ID_LD_JWM		0x1080
-#define USB_DEVICE_ID_LD_DMMP		0x1081
-#define USB_DEVICE_ID_LD_UMIP		0x1090
-#define USB_DEVICE_ID_LD_XRAY1		0x1100
-#define USB_DEVICE_ID_LD_XRAY2		0x1101
-#define USB_DEVICE_ID_LD_VIDEOCOM	0x1200
-#define USB_DEVICE_ID_LD_COM3LAB	0x2000
-#define USB_DEVICE_ID_LD_TELEPORT	0x2010
-#define USB_DEVICE_ID_LD_NETWORKANALYSER 0x2020
-#define USB_DEVICE_ID_LD_POWERCONTROL	0x2030
-#define USB_DEVICE_ID_LD_MACHINETEST	0x2040
-
-#define USB_VENDOR_ID_LOGITECH		0x046d
-#define USB_DEVICE_ID_LOGITECH_LX3	0xc044
-#define USB_DEVICE_ID_LOGITECH_V150	0xc047
-#define USB_DEVICE_ID_LOGITECH_RECEIVER	0xc101
-#define USB_DEVICE_ID_LOGITECH_HARMONY  0xc110
-#define USB_DEVICE_ID_LOGITECH_HARMONY_2 0xc111
-#define USB_DEVICE_ID_LOGITECH_HARMONY_3 0xc112
-#define USB_DEVICE_ID_LOGITECH_HARMONY_4 0xc113
-#define USB_DEVICE_ID_LOGITECH_HARMONY_5 0xc114
-#define USB_DEVICE_ID_LOGITECH_HARMONY_6 0xc115
-#define USB_DEVICE_ID_LOGITECH_HARMONY_7 0xc116
-#define USB_DEVICE_ID_LOGITECH_HARMONY_8 0xc117
-#define USB_DEVICE_ID_LOGITECH_HARMONY_9 0xc118
-#define USB_DEVICE_ID_LOGITECH_HARMONY_10 0xc119
-#define USB_DEVICE_ID_LOGITECH_HARMONY_11 0xc11a
-#define USB_DEVICE_ID_LOGITECH_HARMONY_12 0xc11b
-#define USB_DEVICE_ID_LOGITECH_HARMONY_13 0xc11c
-#define USB_DEVICE_ID_LOGITECH_HARMONY_14 0xc11d
-#define USB_DEVICE_ID_LOGITECH_HARMONY_15 0xc11e
-#define USB_DEVICE_ID_LOGITECH_HARMONY_16 0xc11f
-#define USB_DEVICE_ID_LOGITECH_HARMONY_17 0xc120
-#define USB_DEVICE_ID_LOGITECH_HARMONY_18 0xc121
-#define USB_DEVICE_ID_LOGITECH_HARMONY_19 0xc122
-#define USB_DEVICE_ID_LOGITECH_HARMONY_20 0xc123
-#define USB_DEVICE_ID_LOGITECH_HARMONY_21 0xc124
-#define USB_DEVICE_ID_LOGITECH_HARMONY_22 0xc125
-#define USB_DEVICE_ID_LOGITECH_HARMONY_23 0xc126
-#define USB_DEVICE_ID_LOGITECH_HARMONY_24 0xc127
-#define USB_DEVICE_ID_LOGITECH_HARMONY_25 0xc128
-#define USB_DEVICE_ID_LOGITECH_HARMONY_26 0xc129
-#define USB_DEVICE_ID_LOGITECH_HARMONY_27 0xc12a
-#define USB_DEVICE_ID_LOGITECH_HARMONY_28 0xc12b
-#define USB_DEVICE_ID_LOGITECH_HARMONY_29 0xc12c
-#define USB_DEVICE_ID_LOGITECH_HARMONY_30 0xc12d
-#define USB_DEVICE_ID_LOGITECH_HARMONY_31 0xc12e
-#define USB_DEVICE_ID_LOGITECH_HARMONY_32 0xc12f
-#define USB_DEVICE_ID_LOGITECH_HARMONY_33 0xc130
-#define USB_DEVICE_ID_LOGITECH_HARMONY_34 0xc131
-#define USB_DEVICE_ID_LOGITECH_HARMONY_35 0xc132
-#define USB_DEVICE_ID_LOGITECH_HARMONY_36 0xc133
-#define USB_DEVICE_ID_LOGITECH_HARMONY_37 0xc134
-#define USB_DEVICE_ID_LOGITECH_HARMONY_38 0xc135
-#define USB_DEVICE_ID_LOGITECH_HARMONY_39 0xc136
-#define USB_DEVICE_ID_LOGITECH_HARMONY_40 0xc137
-#define USB_DEVICE_ID_LOGITECH_HARMONY_41 0xc138
-#define USB_DEVICE_ID_LOGITECH_HARMONY_42 0xc139
-#define USB_DEVICE_ID_LOGITECH_HARMONY_43 0xc13a
-#define USB_DEVICE_ID_LOGITECH_HARMONY_44 0xc13b
-#define USB_DEVICE_ID_LOGITECH_HARMONY_45 0xc13c
-#define USB_DEVICE_ID_LOGITECH_HARMONY_46 0xc13d
-#define USB_DEVICE_ID_LOGITECH_HARMONY_47 0xc13e
-#define USB_DEVICE_ID_LOGITECH_HARMONY_48 0xc13f
-#define USB_DEVICE_ID_LOGITECH_HARMONY_49 0xc140
-#define USB_DEVICE_ID_LOGITECH_HARMONY_50 0xc141
-#define USB_DEVICE_ID_LOGITECH_HARMONY_51 0xc142
-#define USB_DEVICE_ID_LOGITECH_HARMONY_52 0xc143
-#define USB_DEVICE_ID_LOGITECH_HARMONY_53 0xc144
-#define USB_DEVICE_ID_LOGITECH_HARMONY_54 0xc145
-#define USB_DEVICE_ID_LOGITECH_HARMONY_55 0xc146
-#define USB_DEVICE_ID_LOGITECH_HARMONY_56 0xc147
-#define USB_DEVICE_ID_LOGITECH_HARMONY_57 0xc148
-#define USB_DEVICE_ID_LOGITECH_HARMONY_58 0xc149
-#define USB_DEVICE_ID_LOGITECH_HARMONY_59 0xc14a
-#define USB_DEVICE_ID_LOGITECH_HARMONY_60 0xc14b
-#define USB_DEVICE_ID_LOGITECH_HARMONY_61 0xc14c
-#define USB_DEVICE_ID_LOGITECH_HARMONY_62 0xc14d
-#define USB_DEVICE_ID_LOGITECH_HARMONY_63 0xc14e
-#define USB_DEVICE_ID_LOGITECH_HARMONY_64 0xc14f
-#define USB_DEVICE_ID_LOGITECH_EXTREME_3D	0xc215
-#define USB_DEVICE_ID_LOGITECH_WHEEL	0xc294
-#define USB_DEVICE_ID_LOGITECH_ELITE_KBD	0xc30a
-#define USB_DEVICE_ID_LOGITECH_KBD	0xc311
-#define USB_DEVICE_ID_S510_RECEIVER	0xc50c
-#define USB_DEVICE_ID_S510_RECEIVER_2	0xc517
-#define USB_DEVICE_ID_LOGITECH_CORDLESS_DESKTOP_LX500	0xc512
-#define USB_DEVICE_ID_MX3000_RECEIVER	0xc513
-#define USB_DEVICE_ID_DINOVO_DESKTOP	0xc704
-#define USB_DEVICE_ID_DINOVO_EDGE	0xc714
-#define USB_DEVICE_ID_DINOVO_MINI	0xc71f
-
-#define USB_VENDOR_ID_MCC		0x09db
-#define USB_DEVICE_ID_MCC_PMD1024LS	0x0076
-#define USB_DEVICE_ID_MCC_PMD1208LS	0x007a
-
-#define USB_VENDOR_ID_MGE		0x0463
-#define USB_DEVICE_ID_MGE_UPS		0xffff
-#define USB_DEVICE_ID_MGE_UPS1		0x0001
-
-#define USB_VENDOR_ID_MICROCHIP		0x04d8
-#define USB_DEVICE_ID_PICKIT1		0x0032
-#define USB_DEVICE_ID_PICKIT2		0x0033
-
-#define USB_VENDOR_ID_MICROSOFT		0x045e
-#define USB_DEVICE_ID_SIDEWINDER_GV	0x003b
-#define USB_DEVICE_ID_WIRELESS_OPTICAL_DESKTOP_3_0 0x009d
-#define USB_DEVICE_ID_DESKTOP_RECV_1028 0x00f9
-#define USB_DEVICE_ID_MS_NE4K		0x00db
-#define USB_DEVICE_ID_MS_LK6K		0x00f9
-
-#define USB_VENDOR_ID_MONTEREY		0x0566
-#define USB_DEVICE_ID_GENIUS_KB29E	0x3004
-
-#define USB_VENDOR_ID_NCR		0x0404
-#define USB_DEVICE_ID_NCR_FIRST		0x0300
-#define USB_DEVICE_ID_NCR_LAST		0x03ff
-
-#define USB_VENDOR_ID_NATIONAL_SEMICONDUCTOR 0x0400
-#define USB_DEVICE_ID_N_S_HARMONY       0xc359
-
-#define USB_VENDOR_ID_NATSU             0x08b7
-#define USB_DEVICE_ID_NATSU_GAMEPAD     0x0001
-
-#define USB_VENDOR_ID_NEC		0x073e
-#define USB_DEVICE_ID_NEC_USB_GAME_PAD	0x0301
-
-#define USB_VENDOR_ID_ONTRAK		0x0a07
-#define USB_DEVICE_ID_ONTRAK_ADU100	0x0064
-
-#define USB_VENDOR_ID_PANJIT		0x134c
-
-#define USB_VENDOR_ID_PANTHERLORD	0x0810
-#define USB_DEVICE_ID_PANTHERLORD_TWIN_USB_JOYSTICK	0x0001
-
-#define USB_VENDOR_ID_PETALYNX		0x18b1
-#define USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE	0x0037
-
-#define USB_VENDOR_ID_PLAYDOTCOM	0x0b43
-#define USB_DEVICE_ID_PLAYDOTCOM_EMS_USBII	0x0003
-
-#define USB_VENDOR_ID_SAITEK		0x06a3
-#define USB_DEVICE_ID_SAITEK_RUMBLEPAD	0xff17
-
-#define USB_VENDOR_ID_SAMSUNG		0x0419
-#define USB_DEVICE_ID_SAMSUNG_IR_REMOTE	0x0001
-
-#define USB_VENDOR_ID_SONY			0x054c
-#define USB_DEVICE_ID_SONY_PS3_CONTROLLER	0x0268
-
-#define USB_VENDOR_ID_SOUNDGRAPH	0x15c2
-#define USB_DEVICE_ID_SOUNDGRAPH_IMON_LCD	0x0038
-
-#define USB_VENDOR_ID_SUN		0x0430
-#define USB_DEVICE_ID_RARITAN_KVM_DONGLE	0xcdab
-
-#define USB_VENDOR_ID_SUNPLUS		0x04fc
-#define USB_DEVICE_ID_SUNPLUS_WDESKTOP	0x05d8
-
-#define USB_VENDOR_ID_TOPMAX		0x0663
-#define USB_DEVICE_ID_TOPMAX_COBRAPAD	0x0103
-
-#define USB_VENDOR_ID_TURBOX		0x062a
-#define USB_DEVICE_ID_TURBOX_KEYBOARD	0x0201
-
-#define USB_VENDOR_ID_VERNIER		0x08f7
-#define USB_DEVICE_ID_VERNIER_LABPRO	0x0001
-#define USB_DEVICE_ID_VERNIER_GOTEMP	0x0002
-#define USB_DEVICE_ID_VERNIER_SKIP	0x0003
-#define USB_DEVICE_ID_VERNIER_CYCLOPS	0x0004
-#define USB_DEVICE_ID_VERNIER_LCSPEC	0x0006
-
-#define USB_VENDOR_ID_WACOM		0x056a
-
-#define USB_VENDOR_ID_WISEGROUP		0x0925
-#define USB_DEVICE_ID_1_PHIDGETSERVO_20	0x8101
-#define USB_DEVICE_ID_4_PHIDGETSERVO_20	0x8104
-#define USB_DEVICE_ID_8_8_4_IF_KIT	0x8201
-#define USB_DEVICE_ID_QUAD_USB_JOYPAD	0x8800
-#define USB_DEVICE_ID_DUAL_USB_JOYPAD	0x8866
-
-#define USB_VENDOR_ID_WISEGROUP_LTD	0x6677
-#define USB_DEVICE_ID_SMARTJOY_DUAL_PLUS 0x8802
-
-#define USB_VENDOR_ID_YEALINK		0x6993
-#define USB_DEVICE_ID_YEALINK_P1K_P4K_B2K	0xb001
-
-#define USB_VENDOR_ID_KYE		0x0458
-#define USB_DEVICE_ID_KYE_GPEN_560	0x5003
+#include "../hid-ids.h"
 
 /*
  * Alphabetically sorted blacklist by quirk type.
@@ -433,18 +28,10 @@
 	__u16 idProduct;
 	__u32 quirks;
 } hid_blacklist[] = {
-
-	{ USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_WCP32PU, HID_QUIRK_2WHEEL_MOUSE_HACK_7 },
-	{ USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_X5_005D, HID_QUIRK_2WHEEL_MOUSE_HACK_B8 },
-	{ USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_MOUSE, HID_QUIRK_2WHEEL_MOUSE_HACK_5 },
-
-	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RECEIVER, HID_QUIRK_BAD_RELATIVE_KEYS },
-
 	{ USB_VENDOR_ID_AASHIMA, USB_DEVICE_ID_AASHIMA_GAMEPAD, HID_QUIRK_BADPAD },
 	{ USB_VENDOR_ID_AASHIMA, USB_DEVICE_ID_AASHIMA_PREDATOR, HID_QUIRK_BADPAD },
 	{ USB_VENDOR_ID_ALPS, USB_DEVICE_ID_IBM_GAMEPAD, HID_QUIRK_BADPAD },
 	{ USB_VENDOR_ID_CHIC, USB_DEVICE_ID_CHIC_GAMEPAD, HID_QUIRK_BADPAD },
-	{ USB_VENDOR_ID_GAMERON, USB_DEVICE_ID_GAMERON_DUAL_PSX_ADAPTOR, HID_QUIRK_MULTI_INPUT },
 	{ USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_DRIVING, HID_QUIRK_BADPAD | HID_QUIRK_MULTI_INPUT },
 	{ USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_FLYING, HID_QUIRK_BADPAD | HID_QUIRK_MULTI_INPUT },
 	{ USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_FIGHTING, HID_QUIRK_BADPAD | HID_QUIRK_MULTI_INPUT },
@@ -453,169 +40,11 @@
 	{ USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_RUMBLEPAD, HID_QUIRK_BADPAD },
 	{ USB_VENDOR_ID_TOPMAX, USB_DEVICE_ID_TOPMAX_COBRAPAD, HID_QUIRK_BADPAD },
 
-	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_DESKTOP, HID_QUIRK_DUPLICATE_USAGES },
-	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_EDGE, HID_QUIRK_DUPLICATE_USAGES },
-	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_MINI, HID_QUIRK_DUPLICATE_USAGES },
-
 	{ USB_VENDOR_ID_AFATECH, USB_DEVICE_ID_AFATECH_AF9016, HID_QUIRK_FULLSPEED_INTERVAL },
 
-	{ USB_VENDOR_ID_BELKIN, USB_DEVICE_ID_FLIP_KVM, HID_QUIRK_HIDDEV },
-	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL4, HID_QUIRK_HIDDEV | HID_QUIRK_IGNORE_HIDINPUT },
-	{ USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_IR_REMOTE, HID_QUIRK_HIDDEV | HID_QUIRK_IGNORE_HIDINPUT },
-	{ USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_SIDEWINDER_GV, HID_QUIRK_HIDINPUT },
-
-	{ USB_VENDOR_ID_EZKEY, USB_DEVICE_ID_BTC_8193, HID_QUIRK_HWHEEL_WHEEL_INVERT },
-
-	{ USB_VENDOR_ID_ADS_TECH, USB_DEVICE_ID_ADS_TECH_RADIO_SI470X, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_01, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_10, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_20, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_21, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_22, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_23, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_24, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_AIRCABLE, USB_DEVICE_ID_AIRCABLE1, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_ALCOR, USB_DEVICE_ID_ALCOR_USBRS232, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_ASUS, USB_DEVICE_ID_ASUS_LCM, HID_QUIRK_IGNORE},
-	{ USB_VENDOR_ID_BERKSHIRE, USB_DEVICE_ID_BERKSHIRE_PCWD, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_CIDC, 0x0103, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_CYGNAL, USB_DEVICE_ID_CYGNAL_RADIO_SI470X, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_CMEDIA, USB_DEVICE_ID_CM109, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_HIDCOM, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_ULTRAMOUSE, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_DELORME, USB_DEVICE_ID_DELORME_EARTHMATE, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_DELORME, USB_DEVICE_ID_DELORME_EM_LT20, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_ESSENTIAL_REALITY, USB_DEVICE_ID_ESSENTIAL_REALITY_P5, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_GENERAL_TOUCH, 0x0001, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_GENERAL_TOUCH, 0x0002, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_GENERAL_TOUCH, 0x0003, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_GENERAL_TOUCH, 0x0004, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_GLAB, USB_DEVICE_ID_4_PHIDGETSERVO_30, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_GLAB, USB_DEVICE_ID_1_PHIDGETSERVO_30, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_GLAB, USB_DEVICE_ID_0_0_4_IF_KIT, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_GLAB, USB_DEVICE_ID_0_16_16_IF_KIT, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_GLAB, USB_DEVICE_ID_8_8_8_IF_KIT, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_GLAB, USB_DEVICE_ID_0_8_7_IF_KIT, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_GLAB, USB_DEVICE_ID_0_8_8_IF_KIT, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_GLAB, USB_DEVICE_ID_PHIDGET_MOTORCONTROL, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_GOTOP, USB_DEVICE_ID_SUPER_Q2, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_GOTOP, USB_DEVICE_ID_GOGOPEN, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_GOTOP, USB_DEVICE_ID_PENPOWER, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_GRETAGMACBETH, USB_DEVICE_ID_GRETAGMACBETH_HUEY, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_GRIFFIN, USB_DEVICE_ID_POWERMATE, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_GRIFFIN, USB_DEVICE_ID_SOUNDKNOB, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_90, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_100, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_101, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_103, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_104, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_105, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_106, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_107, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_108, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_200, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_201, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_202, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_203, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_204, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_205, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_206, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_207, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_300, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_301, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_302, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_303, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_304, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_305, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_306, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_307, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_308, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_309, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_400, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_401, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_402, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_403, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_404, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_405, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_500, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_501, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_502, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_503, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_504, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1000, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1001, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1002, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1003, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1004, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1005, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1006, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1007, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_IMATION, USB_DEVICE_ID_DISC_STAKKA, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_KBGEAR, USB_DEVICE_ID_KBGEAR_JAMSTUDIO, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_CASSY, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_POCKETCASSY, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MOBILECASSY, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_JWM, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_DMMP, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_UMIP, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_XRAY1, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_XRAY2, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_VIDEOCOM, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_COM3LAB, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_TELEPORT, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_NETWORKANALYSER, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_POWERCONTROL, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MACHINETEST, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_MCC, USB_DEVICE_ID_MCC_PMD1024LS, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_MCC, USB_DEVICE_ID_MCC_PMD1208LS, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS1, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 20, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 30, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 100, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 108, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 118, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 200, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 300, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 400, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 500, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_PANJIT, 0x0001, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_PANJIT, 0x0002, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_PANJIT, 0x0003, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_PANJIT, 0x0004, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_SOUNDGRAPH, USB_DEVICE_ID_SOUNDGRAPH_IMON_LCD, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_LABPRO, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_GOTEMP, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_SKIP, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_CYCLOPS, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_LCSPEC, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_4_PHIDGETSERVO_20, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_1_PHIDGETSERVO_20, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_8_8_4_IF_KIT, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_YEALINK, USB_DEVICE_ID_YEALINK_P1K_P4K_B2K, HID_QUIRK_IGNORE },
-
-	{ USB_VENDOR_ID_ACECAD, USB_DEVICE_ID_ACECAD_FLAIR, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_ACECAD, USB_DEVICE_ID_ACECAD_302, HID_QUIRK_IGNORE },
-
-	{ USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICKIT1, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICKIT2, HID_QUIRK_IGNORE },
-
-	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_ELITE_KBD, HID_QUIRK_LOGITECH_IGNORE_DOUBLED_WHEEL | HID_QUIRK_LOGITECH_EXPANDED_KEYMAP },
-	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_CORDLESS_DESKTOP_LX500, HID_QUIRK_LOGITECH_IGNORE_DOUBLED_WHEEL | HID_QUIRK_LOGITECH_EXPANDED_KEYMAP },
-	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_LX3, HID_QUIRK_INVERT_HWHEEL },
-	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_V150, HID_QUIRK_INVERT_HWHEEL },
-
-	{ USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_NE4K, HID_QUIRK_MICROSOFT_KEYS },
-	{ USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_LK6K, HID_QUIRK_MICROSOFT_KEYS },
-
-	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MIGHTYMOUSE, HID_QUIRK_MIGHTYMOUSE | HID_QUIRK_INVERT_HWHEEL },
-
 	{ USB_VENDOR_ID_PANTHERLORD, USB_DEVICE_ID_PANTHERLORD_TWIN_USB_JOYSTICK, HID_QUIRK_MULTI_INPUT | HID_QUIRK_SKIP_OUTPUT_REPORTS },
 	{ USB_VENDOR_ID_PLAYDOTCOM, USB_DEVICE_ID_PLAYDOTCOM_EMS_USBII, HID_QUIRK_MULTI_INPUT },
 
-	{ USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER, HID_QUIRK_SONY_PS3_CONTROLLER | HID_QUIRK_HIDDEV },
-
 	{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_UC100KM, HID_QUIRK_NOGET },
 	{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_CS124U, HID_QUIRK_NOGET },
 	{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_2PORTKVM, HID_QUIRK_NOGET },
@@ -623,144 +52,13 @@
 	{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVMC, HID_QUIRK_NOGET },
 	{ USB_VENDOR_ID_DMI, USB_DEVICE_ID_DMI_ENC, HID_QUIRK_NOGET },
 	{ USB_VENDOR_ID_ELO, USB_DEVICE_ID_ELO_TS2700, HID_QUIRK_NOGET },
-	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_EXTREME_3D, HID_QUIRK_NOGET },
-	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WHEEL, HID_QUIRK_NOGET },
-	{ USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_WIRELESS_OPTICAL_DESKTOP_3_0, HID_QUIRK_NOGET },
-	{ USB_VENDOR_ID_PETALYNX, USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE, HID_QUIRK_NOGET },
 	{ USB_VENDOR_ID_SUN, USB_DEVICE_ID_RARITAN_KVM_DONGLE, HID_QUIRK_NOGET },
 	{ USB_VENDOR_ID_TURBOX, USB_DEVICE_ID_TURBOX_KEYBOARD, HID_QUIRK_NOGET },
 	{ USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_DUAL_USB_JOYPAD, HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT | HID_QUIRK_SKIP_OUTPUT_REPORTS },
 	{ USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_QUAD_USB_JOYPAD, HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT },
 
 	{ USB_VENDOR_ID_WISEGROUP_LTD, USB_DEVICE_ID_SMARTJOY_DUAL_PLUS, HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT },
-
-	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ANSI, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
-	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ISO, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
-	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_ANSI, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
-	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_ISO, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE | HID_QUIRK_APPLE_ISO_KEYBOARD},
-	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_JIS, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
-	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_ANSI, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
-	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_ISO, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE | HID_QUIRK_APPLE_ISO_KEYBOARD},
-	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_JIS, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
-	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_ANSI, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
-	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_ISO, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE | HID_QUIRK_APPLE_ISO_KEYBOARD},
-	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_JIS, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
-	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_ANSI, HID_QUIRK_APPLE_HAS_FN },
-	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_ISO, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_APPLE_ISO_KEYBOARD },
-	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_JIS, HID_QUIRK_APPLE_HAS_FN },
-	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_HF_ANSI, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
-	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_HF_ISO, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
-	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_HF_JIS, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
-	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_ANSI, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN },
-	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_ISO, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_APPLE_ISO_KEYBOARD },
-	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_JIS, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN },
-	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING_ANSI, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
-	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING_ISO, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_APPLE_ISO_KEYBOARD | HID_QUIRK_IGNORE_MOUSE},
-	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING_JIS, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE},
-	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING2_ANSI, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE},
-	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING2_ISO, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_APPLE_ISO_KEYBOARD | HID_QUIRK_IGNORE_MOUSE },
-	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING2_JIS, HID_QUIRK_APPLE_HAS_FN  | HID_QUIRK_IGNORE_MOUSE },
-	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
-	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
-
-	{ USB_VENDOR_ID_DELL, USB_DEVICE_ID_DELL_W7658, HID_QUIRK_RESET_LEDS },
-	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_KBD, HID_QUIRK_RESET_LEDS },
-	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_2, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_3, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_4, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_5, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_6, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_7, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_8, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_9, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_10, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_11, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_12, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_13, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_14, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_15, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_16, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_17, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_18, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_19, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_20, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_21, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_22, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_23, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_24, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_25, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_26, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_27, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_28, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_29, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_30, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_31, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_32, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_33, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_34, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_35, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_36, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_37, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_38, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_39, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_40, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_41, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_42, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_43, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_44, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_45, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_46, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_47, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_48, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_49, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_50, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_51, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_52, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_53, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_54, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_55, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_56, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_57, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_58, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_59, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_60, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_61, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_62, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_63, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_64, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_NATIONAL_SEMICONDUCTOR, USB_DEVICE_ID_N_S_HARMONY, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_GPEN_560, HID_QUIRK_IGNORE },
-
-	{ 0, 0 }
-};
-
-/* Quirks for devices which require report descriptor fixup go here */
-static const struct hid_rdesc_blacklist {
-	__u16 idVendor;
-	__u16 idProduct;
-	__u32 quirks;
-} hid_rdesc_blacklist[] = {
-
-	{ USB_VENDOR_ID_CHERRY, USB_DEVICE_ID_CHERRY_CYMOTION, HID_QUIRK_RDESC_CYMOTION },
-
-	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_MX3000_RECEIVER, HID_QUIRK_RDESC_LOGITECH },
-	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER, HID_QUIRK_RDESC_LOGITECH },
-	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER_2, HID_QUIRK_RDESC_LOGITECH },
-	{ USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_DESKTOP_RECV_1028, HID_QUIRK_RDESC_MICROSOFT_RECV_1028 },
-
-	{ USB_VENDOR_ID_MONTEREY, USB_DEVICE_ID_GENIUS_KB29E, HID_QUIRK_RDESC_BUTTON_CONSUMER },
-
-	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_JIS, HID_QUIRK_RDESC_MACBOOK_JIS },
-
-	{ USB_VENDOR_ID_PETALYNX, USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE, HID_QUIRK_RDESC_PETALYNX },
-
-	{ USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_IR_REMOTE, HID_QUIRK_RDESC_SAMSUNG_REMOTE },
-
-	{ USB_VENDOR_ID_SUNPLUS, USB_DEVICE_ID_SUNPLUS_WDESKTOP, HID_QUIRK_RDESC_SUNPLUS_WDESKTOP },
-
-	{ USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_1, HID_QUIRK_RDESC_SWAPPED_MIN_MAX },
-	{ USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_2, HID_QUIRK_RDESC_SWAPPED_MIN_MAX },
+	{ USB_VENDOR_ID_WISEGROUP_LTD2, USB_DEVICE_ID_SMARTJOY_DUAL_PLUS, HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT },
 
 	{ 0, 0 }
 };
@@ -974,16 +272,6 @@
 	u32 quirks = 0;
 	const struct hid_blacklist *bl_entry = NULL;
 
-	/* Ignore all Wacom devices */
-	if (idVendor == USB_VENDOR_ID_WACOM)
-		return HID_QUIRK_IGNORE;
-
-	/* ignore all Code Mercenaries IOWarrior devices */
-	if (idVendor == USB_VENDOR_ID_CODEMERCS)
-		if (idProduct >= USB_DEVICE_ID_CODEMERCS_IOW_FIRST &&
-				idProduct <= USB_DEVICE_ID_CODEMERCS_IOW_LAST)
-			return HID_QUIRK_IGNORE;
-
 	/* NCR devices must not be queried for reports */
 	if (idVendor == USB_VENDOR_ID_NCR &&
 			idProduct >= USB_DEVICE_ID_NCR_FIRST &&
@@ -1002,221 +290,3 @@
 }
 
 EXPORT_SYMBOL_GPL(usbhid_lookup_quirk);
-
-/*
- * Cherry Cymotion keyboard have an invalid HID report descriptor,
- * that needs fixing before we can parse it.
- */
-static void usbhid_fixup_cymotion_descriptor(char *rdesc, int rsize)
-{
-	if (rsize >= 17 && rdesc[11] == 0x3c && rdesc[12] == 0x02) {
-		printk(KERN_INFO "Fixing up Cherry Cymotion report descriptor\n");
-		rdesc[11] = rdesc[16] = 0xff;
-		rdesc[12] = rdesc[17] = 0x03;
-	}
-}
-
-
-/*
- * Certain Logitech keyboards send in report #3 keys which are far
- * above the logical maximum described in descriptor. This extends
- * the original value of 0x28c of logical maximum to 0x104d
- */
-static void usbhid_fixup_logitech_descriptor(unsigned char *rdesc, int rsize)
-{
-	if (rsize >= 90 && rdesc[83] == 0x26
-			&& rdesc[84] == 0x8c
-			&& rdesc[85] == 0x02) {
-		printk(KERN_INFO "Fixing up Logitech keyboard report descriptor\n");
-		rdesc[84] = rdesc[89] = 0x4d;
-		rdesc[85] = rdesc[90] = 0x10;
-	}
-}
-
-static void usbhid_fixup_sunplus_wdesktop(unsigned char *rdesc, int rsize)
-{
-	if (rsize >= 107 && rdesc[104] == 0x26
-			 && rdesc[105] == 0x80
-			 && rdesc[106] == 0x03) {
-		printk(KERN_INFO "Fixing up Sunplus Wireless Desktop report descriptor\n");
-		rdesc[105] = rdesc[110] = 0x03;
-		rdesc[106] = rdesc[111] = 0x21;
-	}
-}
-
-/*
- * Samsung IrDA remote controller (reports as Cypress USB Mouse).
- *
- * Vendor specific report #4 has a size of 48 bit,
- * and therefore is not accepted when inspecting the descriptors.
- * As a workaround we reinterpret the report as:
- *   Variable type, count 6, size 8 bit, log. maximum 255
- * The burden to reconstruct the data is moved into user space.
- */
-static void usbhid_fixup_samsung_irda_descriptor(unsigned char *rdesc,
-						  int rsize)
-{
-	if (rsize >= 182 && rdesc[175] == 0x25
-			 && rdesc[176] == 0x40
-			 && rdesc[177] == 0x75
-			 && rdesc[178] == 0x30
-			 && rdesc[179] == 0x95
-			 && rdesc[180] == 0x01
-			 && rdesc[182] == 0x40) {
-		printk(KERN_INFO "Fixing up Samsung IrDA report descriptor\n");
-		rdesc[176] = 0xff;
-		rdesc[178] = 0x08;
-		rdesc[180] = 0x06;
-		rdesc[182] = 0x42;
-	}
-}
-
-/* Petalynx Maxter Remote has maximum for consumer page set too low */
-static void usbhid_fixup_petalynx_descriptor(unsigned char *rdesc, int rsize)
-{
-	if (rsize >= 60 && rdesc[39] == 0x2a
-			&& rdesc[40] == 0xf5
-			&& rdesc[41] == 0x00
-			&& rdesc[59] == 0x26
-			&& rdesc[60] == 0xf9
-			&& rdesc[61] == 0x00) {
-		printk(KERN_INFO "Fixing up Petalynx Maxter Remote report descriptor\n");
-		rdesc[60] = 0xfa;
-		rdesc[40] = 0xfa;
-	}
-}
-
-/*
- * Some USB barcode readers from cypress have usage min and usage max in
- * the wrong order
- */
-static void usbhid_fixup_cypress_descriptor(unsigned char *rdesc, int rsize)
-{
-	short fixed = 0;
-	int i;
-
-	for (i = 0; i < rsize - 4; i++) {
-		if (rdesc[i] == 0x29 && rdesc [i+2] == 0x19) {
-			unsigned char tmp;
-
-			rdesc[i] = 0x19; rdesc[i+2] = 0x29;
-			tmp = rdesc[i+3];
-			rdesc[i+3] = rdesc[i+1];
-			rdesc[i+1] = tmp;
-		}
-	}
-
-	if (fixed)
-		printk(KERN_INFO "Fixing up Cypress report descriptor\n");
-}
-
-/*
- * MacBook JIS keyboard has wrong logical maximum
- */
-static void usbhid_fixup_macbook_descriptor(unsigned char *rdesc, int rsize)
-{
-	if (rsize >= 60 && rdesc[53] == 0x65
-			&& rdesc[59] == 0x65) {
-		printk(KERN_INFO "Fixing up MacBook JIS keyboard report descriptor\n");
-		rdesc[53] = rdesc[59] = 0xe7;
-	}
-}
-
-static void usbhid_fixup_button_consumer_descriptor(unsigned char *rdesc, int rsize)
-{
-	if (rsize >= 30 && rdesc[29] == 0x05
-			&& rdesc[30] == 0x09) {
-		printk(KERN_INFO "Fixing up button/consumer in HID report descriptor\n");
-		rdesc[30] = 0x0c;
-	}
-}
-
-/*
- * Microsoft Wireless Desktop Receiver (Model 1028) has several
- * 'Usage Min/Max' where it ought to have 'Physical Min/Max'
- */
-static void usbhid_fixup_microsoft_descriptor(unsigned char *rdesc, int rsize)
-{
-	if (rsize == 571 && rdesc[284] == 0x19
-	                 && rdesc[286] == 0x2a
-	                 && rdesc[304] == 0x19
-	                 && rdesc[306] == 0x29
-	                 && rdesc[352] == 0x1a
-	                 && rdesc[355] == 0x2a
-			 && rdesc[557] == 0x19
-			 && rdesc[559] == 0x29) {
-		printk(KERN_INFO "Fixing up Microsoft Wireless Receiver Model 1028 report descriptor\n");
-		rdesc[284] = rdesc[304] = rdesc[557] = 0x35;
-		rdesc[352] = 0x36;
-		rdesc[286] = rdesc[355] = 0x46;
-		rdesc[306] = rdesc[559] = 0x45;
-	}
-}
-
-static void __usbhid_fixup_report_descriptor(__u32 quirks, char *rdesc, unsigned rsize)
-{
-	if ((quirks & HID_QUIRK_RDESC_CYMOTION))
-		usbhid_fixup_cymotion_descriptor(rdesc, rsize);
-
-	if (quirks & HID_QUIRK_RDESC_LOGITECH)
-		usbhid_fixup_logitech_descriptor(rdesc, rsize);
-
-	if (quirks & HID_QUIRK_RDESC_SWAPPED_MIN_MAX)
-		usbhid_fixup_cypress_descriptor(rdesc, rsize);
-
-	if (quirks & HID_QUIRK_RDESC_PETALYNX)
-		usbhid_fixup_petalynx_descriptor(rdesc, rsize);
-
-	if (quirks & HID_QUIRK_RDESC_MACBOOK_JIS)
-		usbhid_fixup_macbook_descriptor(rdesc, rsize);
-
-	if (quirks & HID_QUIRK_RDESC_BUTTON_CONSUMER)
-		usbhid_fixup_button_consumer_descriptor(rdesc, rsize);
-
-	if (quirks & HID_QUIRK_RDESC_SAMSUNG_REMOTE)
-		usbhid_fixup_samsung_irda_descriptor(rdesc, rsize);
-
-	if (quirks & HID_QUIRK_RDESC_MICROSOFT_RECV_1028)
-		usbhid_fixup_microsoft_descriptor(rdesc, rsize);
-
-	if (quirks & HID_QUIRK_RDESC_SUNPLUS_WDESKTOP)
-		usbhid_fixup_sunplus_wdesktop(rdesc, rsize);
-}
-
-/**
- * usbhid_fixup_report_descriptor: check if report descriptor needs fixup
- *
- * Description:
- *	Walks the hid_rdesc_blacklist[] array and checks whether the device
- *	is known to have broken report descriptor that needs to be fixed up
- *	prior to entering the HID parser
- *
- * Returns: nothing
- */
-void usbhid_fixup_report_descriptor(const u16 idVendor, const u16 idProduct,
-				    char *rdesc, unsigned rsize, char **quirks_param)
-{
-	int n, m;
-	u16 paramVendor, paramProduct;
-	u32 quirks;
-
-	/* static rdesc quirk entries */
-	for (n = 0; hid_rdesc_blacklist[n].idVendor; n++)
-		if (hid_rdesc_blacklist[n].idVendor == idVendor &&
-				hid_rdesc_blacklist[n].idProduct == idProduct)
-			__usbhid_fixup_report_descriptor(hid_rdesc_blacklist[n].quirks,
-					rdesc, rsize);
-
-	/* runtime rdesc quirk entries handling */
-	for (n = 0; quirks_param[n] && n < MAX_USBHID_BOOT_QUIRKS; n++) {
-		m = sscanf(quirks_param[n], "0x%hx:0x%hx:0x%x",
-				&paramVendor, &paramProduct, &quirks);
-
-		if (m != 3)
-			printk(KERN_WARNING
-				"Could not parse HID quirk module param %s\n",
-				quirks_param[n]);
-		else if (paramVendor == idVendor && paramProduct == idProduct)
-			__usbhid_fixup_report_descriptor(quirks, rdesc, rsize);
-	}
-}
diff --git a/drivers/hid/usbhid/hid-tmff.c b/drivers/hid/usbhid/hid-tmff.c
deleted file mode 100644
index 144578b..0000000
--- a/drivers/hid/usbhid/hid-tmff.c
+++ /dev/null
@@ -1,225 +0,0 @@
-/*
- * Force feedback support for various HID compliant devices by ThrustMaster:
- *    ThrustMaster FireStorm Dual Power 2
- * and possibly others whose device ids haven't been added.
- *
- *  Modified to support ThrustMaster devices by Zinx Verituse
- *  on 2003-01-25 from the Logitech force feedback driver,
- *  which is by Johann Deneux.
- *
- *  Copyright (c) 2003 Zinx Verituse <zinx@epicsol.org>
- *  Copyright (c) 2002 Johann Deneux
- */
-
-/*
- * This program is free software; you can redistribute it and/or 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/input.h>
-
-#undef DEBUG
-#include <linux/usb.h>
-
-#include <linux/hid.h>
-#include "usbhid.h"
-
-/* Usages for thrustmaster devices I know about */
-#define THRUSTMASTER_USAGE_FF	(HID_UP_GENDESK | 0xbb)
-
-struct dev_type {
-	u16 idVendor;
-	u16 idProduct;
-	const signed short *ff;
-};
-
-static const signed short ff_rumble[] = {
-	FF_RUMBLE,
-	-1
-};
-
-static const signed short ff_joystick[] = {
-	FF_CONSTANT,
-	-1
-};
-
-static const struct dev_type devices[] = {
-	{ 0x44f, 0xb300, ff_rumble },
-	{ 0x44f, 0xb304, ff_rumble },
-	{ 0x44f, 0xb651, ff_rumble },	/* FGT Rumble Force Wheel */
-	{ 0x44f, 0xb654, ff_joystick },	/* FGT Force Feedback Wheel */
-};
-
-struct tmff_device {
-	struct hid_report *report;
-	struct hid_field *ff_field;
-};
-
-/* Changes values from 0 to 0xffff into values from minimum to maximum */
-static inline int hid_tmff_scale_u16(unsigned int in,
-				int minimum, int maximum)
-{
-	int ret;
-
-	ret = (in * (maximum - minimum) / 0xffff) + minimum;
-	if (ret < minimum)
-		return minimum;
-	if (ret > maximum)
-		return maximum;
-	return ret;
-}
-
-/* Changes values from -0x80 to 0x7f into values from minimum to maximum */
-static inline int hid_tmff_scale_s8(int in,
-				    int minimum, int maximum)
-{
-	int ret;
-
-	ret = (((in + 0x80) * (maximum - minimum)) / 0xff) + minimum;
-	if (ret < minimum)
-		return minimum;
-	if (ret > maximum)
-		return maximum;
-	return ret;
-}
-
-static int hid_tmff_play(struct input_dev *dev, void *data, struct ff_effect *effect)
-{
-	struct hid_device *hid = input_get_drvdata(dev);
-	struct tmff_device *tmff = data;
-	struct hid_field *ff_field = tmff->ff_field;
-	int x, y;
-	int left, right;	/* Rumbling */
-
-	switch (effect->type) {
-	case FF_CONSTANT:
-		x = hid_tmff_scale_s8(effect->u.ramp.start_level,
-					ff_field->logical_minimum,
-					ff_field->logical_maximum);
-		y = hid_tmff_scale_s8(effect->u.ramp.end_level,
-					ff_field->logical_minimum,
-					ff_field->logical_maximum);
-
-		dbg_hid("(x, y)=(%04x, %04x)\n", x, y);
-		ff_field->value[0] = x;
-		ff_field->value[1] = y;
-		usbhid_submit_report(hid, tmff->report, USB_DIR_OUT);
-		break;
-
-	case FF_RUMBLE:
-		left = hid_tmff_scale_u16(effect->u.rumble.weak_magnitude,
-					ff_field->logical_minimum,
-					ff_field->logical_maximum);
-		right = hid_tmff_scale_u16(effect->u.rumble.strong_magnitude,
-					ff_field->logical_minimum,
-					ff_field->logical_maximum);
-
-		dbg_hid("(left,right)=(%08x, %08x)\n", left, right);
-		ff_field->value[0] = left;
-		ff_field->value[1] = right;
-		usbhid_submit_report(hid, tmff->report, USB_DIR_OUT);
-		break;
-	}
-	return 0;
-}
-
-int hid_tmff_init(struct hid_device *hid)
-{
-	struct tmff_device *tmff;
-	struct hid_report *report;
-	struct list_head *report_list;
-	struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, list);
-	struct input_dev *input_dev = hidinput->input;
-	const signed short *ff_bits = ff_joystick;
-	int error;
-	int i;
-
-	tmff = kzalloc(sizeof(struct tmff_device), GFP_KERNEL);
-	if (!tmff)
-		return -ENOMEM;
-
-	/* Find the report to use */
-	report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list;
-	list_for_each_entry(report, report_list, list) {
-		int fieldnum;
-
-		for (fieldnum = 0; fieldnum < report->maxfield; ++fieldnum) {
-			struct hid_field *field = report->field[fieldnum];
-
-			if (field->maxusage <= 0)
-				continue;
-
-			switch (field->usage[0].hid) {
-			case THRUSTMASTER_USAGE_FF:
-				if (field->report_count < 2) {
-					warn("ignoring FF field with report_count < 2");
-					continue;
-				}
-
-				if (field->logical_maximum == field->logical_minimum) {
-					warn("ignoring FF field with logical_maximum == logical_minimum");
-					continue;
-				}
-
-				if (tmff->report && tmff->report != report) {
-					warn("ignoring FF field in other report");
-					continue;
-				}
-
-				if (tmff->ff_field && tmff->ff_field != field) {
-					warn("ignoring duplicate FF field");
-					continue;
-				}
-
-				tmff->report = report;
-				tmff->ff_field = field;
-
-				for (i = 0; i < ARRAY_SIZE(devices); i++) {
-					if (input_dev->id.vendor == devices[i].idVendor &&
-					    input_dev->id.product == devices[i].idProduct) {
-						ff_bits = devices[i].ff;
-						break;
-					}
-				}
-
-				for (i = 0; ff_bits[i] >= 0; i++)
-					set_bit(ff_bits[i], input_dev->ffbit);
-
-				break;
-
-			default:
-				warn("ignoring unknown output usage %08x", field->usage[0].hid);
-				continue;
-			}
-		}
-	}
-
-	if (!tmff->report) {
-		err("cant find FF field in output reports\n");
-		error = -ENODEV;
-		goto fail;
-	}
-
-	error = input_ff_create_memless(input_dev, tmff, hid_tmff_play);
-	if (error)
-		goto fail;
-
-	info("Force feedback for ThrustMaster devices by Zinx Verituse <zinx@epicsol.org>");
-	return 0;
-
- fail:
-	kfree(tmff);
-	return error;
-}
-
diff --git a/drivers/hid/usbhid/hid-zpff.c b/drivers/hid/usbhid/hid-zpff.c
deleted file mode 100644
index 5a68827..0000000
--- a/drivers/hid/usbhid/hid-zpff.c
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- *  Force feedback support for Zeroplus based devices
- *
- *  Copyright (c) 2005, 2006 Anssi Hannula <anssi.hannula@gmail.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/input.h>
-#include <linux/usb.h>
-#include <linux/hid.h>
-#include "usbhid.h"
-
-struct zpff_device {
-	struct hid_report *report;
-};
-
-static int hid_zpff_play(struct input_dev *dev, void *data,
-			 struct ff_effect *effect)
-{
-	struct hid_device *hid = input_get_drvdata(dev);
-	struct zpff_device *zpff = data;
-	int left, right;
-
-	/*
-	 * The following is specified the other way around in the Zeroplus
-	 * datasheet but the order below is correct for the XFX Executioner;
-	 * however it is possible that the XFX Executioner is an exception
-	 */
-
-	left = effect->u.rumble.strong_magnitude;
-	right = effect->u.rumble.weak_magnitude;
-	dbg_hid("called with 0x%04x 0x%04x\n", left, right);
-
-	left = left * 0x7f / 0xffff;
-	right = right * 0x7f / 0xffff;
-
-	zpff->report->field[2]->value[0] = left;
-	zpff->report->field[3]->value[0] = right;
-	dbg_hid("running with 0x%02x 0x%02x\n", left, right);
-	usbhid_submit_report(hid, zpff->report, USB_DIR_OUT);
-
-	return 0;
-}
-
-int hid_zpff_init(struct hid_device *hid)
-{
-	struct zpff_device *zpff;
-	struct hid_report *report;
-	struct hid_input *hidinput = list_entry(hid->inputs.next,
-						struct hid_input, list);
-	struct list_head *report_list =
-			&hid->report_enum[HID_OUTPUT_REPORT].report_list;
-	struct input_dev *dev = hidinput->input;
-	int error;
-
-	if (list_empty(report_list)) {
-		printk(KERN_ERR "hid-zpff: no output report found\n");
-		return -ENODEV;
-	}
-
-	report = list_entry(report_list->next, struct hid_report, list);
-
-	if (report->maxfield < 4) {
-		printk(KERN_ERR "hid-zpff: not enough fields in report\n");
-		return -ENODEV;
-	}
-
-	zpff = kzalloc(sizeof(struct zpff_device), GFP_KERNEL);
-	if (!zpff)
-		return -ENOMEM;
-
-	set_bit(FF_RUMBLE, dev->ffbit);
-
-	error = input_ff_create_memless(dev, zpff, hid_zpff_play);
-	if (error) {
-		kfree(zpff);
-		return error;
-	}
-
-	zpff->report = report;
-	zpff->report->field[0]->value[0] = 0x00;
-	zpff->report->field[1]->value[0] = 0x02;
-	zpff->report->field[2]->value[0] = 0x00;
-	zpff->report->field[3]->value[0] = 0x00;
-	usbhid_submit_report(hid, zpff->report, USB_DIR_OUT);
-
-	printk(KERN_INFO "Force feedback for Zeroplus based devices by "
-	       "Anssi Hannula <anssi.hannula@gmail.com>\n");
-
-	return 0;
-}
diff --git a/drivers/hid/usbhid/hiddev.c b/drivers/hid/usbhid/hiddev.c
index 842e9ed..babd65d 100644
--- a/drivers/hid/usbhid/hiddev.c
+++ b/drivers/hid/usbhid/hiddev.c
@@ -790,21 +790,23 @@
 /*
  * This is where hid.c calls us to connect a hid device to the hiddev driver
  */
-int hiddev_connect(struct hid_device *hid)
+int hiddev_connect(struct hid_device *hid, unsigned int force)
 {
 	struct hiddev *hiddev;
 	struct usbhid_device *usbhid = hid->driver_data;
-	int i;
 	int retval;
 
-	for (i = 0; i < hid->maxcollection; i++)
-		if (hid->collection[i].type ==
-		    HID_COLLECTION_APPLICATION &&
-		    !IS_INPUT_APPLICATION(hid->collection[i].usage))
-			break;
+	if (!force) {
+		unsigned int i;
+		for (i = 0; i < hid->maxcollection; i++)
+			if (hid->collection[i].type ==
+			    HID_COLLECTION_APPLICATION &&
+			    !IS_INPUT_APPLICATION(hid->collection[i].usage))
+				break;
 
-	if (i == hid->maxcollection && (hid->quirks & HID_QUIRK_HIDDEV) == 0)
-		return -1;
+		if (i == hid->maxcollection)
+			return -1;
+	}
 
 	if (!(hiddev = kzalloc(sizeof(struct hiddev), GFP_KERNEL)))
 		return -1;
diff --git a/drivers/hid/usbhid/usbhid.h b/drivers/hid/usbhid/usbhid.h
index 62d2d7c..abedb13 100644
--- a/drivers/hid/usbhid/usbhid.h
+++ b/drivers/hid/usbhid/usbhid.h
@@ -67,7 +67,7 @@
 	spinlock_t ctrllock;                                            /* Control fifo spinlock */
 
 	struct urb *urbout;                                             /* Output URB */
-	struct hid_report *out[HID_CONTROL_FIFO_SIZE];                  /* Output pipe fifo */
+	struct hid_output_fifo out[HID_CONTROL_FIFO_SIZE];              /* Output pipe fifo */
 	unsigned char outhead, outtail;                                 /* Output pipe fifo head & tail */
 	char *outbuf;                                                   /* Output buffer */
 	dma_addr_t outbuf_dma;                                          /* Output buffer dma */
@@ -82,7 +82,7 @@
 };
 
 #define	hid_to_usb_dev(hid_dev) \
-	container_of(hid_dev->dev->parent, struct usb_device, dev)
+	container_of(hid_dev->dev.parent->parent, struct usb_device, dev)
 
 #endif
 
diff --git a/drivers/hid/usbhid/usbkbd.c b/drivers/hid/usbhid/usbkbd.c
index 0caaafe..b342926 100644
--- a/drivers/hid/usbhid/usbkbd.c
+++ b/drivers/hid/usbhid/usbkbd.c
@@ -105,14 +105,16 @@
 			if (usb_kbd_keycode[kbd->old[i]])
 				input_report_key(kbd->dev, usb_kbd_keycode[kbd->old[i]], 0);
 			else
-				info("Unknown key (scancode %#x) released.", kbd->old[i]);
+				dev_info(&urb->dev->dev,
+						"Unknown key (scancode %#x) released.\n", kbd->old[i]);
 		}
 
 		if (kbd->new[i] > 3 && memscan(kbd->old + 2, kbd->new[i], 6) == kbd->old + 8) {
 			if (usb_kbd_keycode[kbd->new[i]])
 				input_report_key(kbd->dev, usb_kbd_keycode[kbd->new[i]], 1);
 			else
-				info("Unknown key (scancode %#x) pressed.", kbd->new[i]);
+				dev_info(&urb->dev->dev,
+						"Unknown key (scancode %#x) released.\n", kbd->new[i]);
 		}
 	}
 
@@ -159,7 +161,8 @@
 	struct usb_kbd *kbd = urb->context;
 
 	if (urb->status)
-		warn("led urb status %d received", urb->status);
+		dev_warn(&urb->dev->dev, "led urb status %d received\n",
+			 urb->status);
 
 	if (*(kbd->leds) == kbd->newleds)
 		return;
@@ -352,7 +355,8 @@
 {
 	int result = usb_register(&usb_kbd_driver);
 	if (result == 0)
-		info(DRIVER_VERSION ":" DRIVER_DESC);
+		printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
+				DRIVER_DESC "\n");
 	return result;
 }
 
diff --git a/drivers/hid/usbhid/usbmouse.c b/drivers/hid/usbhid/usbmouse.c
index 35689ef..72ab4b2 100644
--- a/drivers/hid/usbhid/usbmouse.c
+++ b/drivers/hid/usbhid/usbmouse.c
@@ -31,6 +31,11 @@
 #include <linux/usb/input.h>
 #include <linux/hid.h>
 
+/* for apple IDs */
+#ifdef CONFIG_USB_HID_MODULE
+#include "../hid-ids.h"
+#endif
+
 /*
  * Version Information
  */
@@ -240,7 +245,8 @@
 {
 	int retval = usb_register(&usb_mouse_driver);
 	if (retval == 0)
-		info(DRIVER_VERSION ":" DRIVER_DESC);
+		printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
+				DRIVER_DESC "\n");
 	return retval;
 }
 
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index d402e8d..ebacc0a 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -540,6 +540,15 @@
 	  This driver can also be built as a module.  If so, the module
 	  will be called lm93.
 
+config SENSORS_MAX1111
+	tristate "Maxim MAX1111 Multichannel, Serial 8-bit ADC chip"
+	depends on SPI_MASTER
+	help
+	  Say y here to support Maxim's MAX1111 ADC chips.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called max1111.
+
 config SENSORS_MAX1619
 	tristate "Maxim MAX1619 sensor chip"
 	depends on I2C
@@ -791,6 +800,13 @@
 	  This driver can also be built as a module.  If so, the module
 	  will be called w83627ehf.
 
+config SENSORS_ULTRA45
+	tristate "Sun Ultra45 PIC16F747"
+	depends on SPARC64
+	help
+	  This driver provides support for the Ultra45 workstation environmental
+	  sensors.
+
 config SENSORS_HDAPS
 	tristate "IBM Hard Drive Active Protection System (hdaps)"
 	depends on INPUT && X86
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index 950134a..042d5a7 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -41,6 +41,7 @@
 obj-$(CONFIG_SENSORS_FSCPOS)	+= fscpos.o
 obj-$(CONFIG_SENSORS_GL518SM)	+= gl518sm.o
 obj-$(CONFIG_SENSORS_GL520SM)	+= gl520sm.o
+obj-$(CONFIG_SENSORS_ULTRA45)	+= ultra45_env.o
 obj-$(CONFIG_SENSORS_HDAPS)	+= hdaps.o
 obj-$(CONFIG_SENSORS_I5K_AMB)	+= i5k_amb.o
 obj-$(CONFIG_SENSORS_IBMAEM)	+= ibmaem.o
@@ -59,6 +60,7 @@
 obj-$(CONFIG_SENSORS_LM90)	+= lm90.o
 obj-$(CONFIG_SENSORS_LM92)	+= lm92.o
 obj-$(CONFIG_SENSORS_LM93)	+= lm93.o
+obj-$(CONFIG_SENSORS_MAX1111)	+= max1111.o
 obj-$(CONFIG_SENSORS_MAX1619)	+= max1619.o
 obj-$(CONFIG_SENSORS_MAX6650)	+= max6650.o
 obj-$(CONFIG_SENSORS_PC87360)	+= pc87360.o
diff --git a/drivers/hwmon/abituguru3.c b/drivers/hwmon/abituguru3.c
index d568c65..d9e7a49 100644
--- a/drivers/hwmon/abituguru3.c
+++ b/drivers/hwmon/abituguru3.c
@@ -279,7 +279,7 @@
 		{ "OTES1 Fan",		36, 2, 60, 1, 0 },
 		{ NULL, 0, 0, 0, 0, 0 } }
 	},
-	{ 0x0011, NULL /* Abit AT8 32X, need DMI string */, {
+	{ 0x0011, "AT8 32X(ATI RD580-ULI M1575)", {
 		{ "CPU Core",		 0, 0, 10, 1, 0 },
 		{ "DDR",		 1, 0, 20, 1, 0 },
 		{ "DDR VTT",		 2, 0, 10, 1, 0 },
@@ -303,6 +303,7 @@
 		{ "SYS Fan",		34, 2, 60, 1, 0 },
 		{ "AUX1 Fan",		35, 2, 60, 1, 0 },
 		{ "AUX2 Fan",		36, 2, 60, 1, 0 },
+		{ "AUX3 Fan",		37, 2, 60, 1, 0 },
 		{ NULL, 0, 0, 0, 0, 0 } }
 	},
 	{ 0x0012, NULL /* Abit AN8 32X, need DMI string */, {
diff --git a/drivers/hwmon/ad7414.c b/drivers/hwmon/ad7414.c
index ce8d94f..bfda8c8 100644
--- a/drivers/hwmon/ad7414.c
+++ b/drivers/hwmon/ad7414.c
@@ -69,7 +69,7 @@
 	return i2c_smbus_write_byte_data(client, reg, value);
 }
 
-struct ad7414_data *ad7414_update_device(struct device *dev)
+static struct ad7414_data *ad7414_update_device(struct device *dev)
 {
 	struct i2c_client *client = to_i2c_client(dev);
 	struct ad7414_data *data = i2c_get_clientdata(client);
diff --git a/drivers/hwmon/atxp1.c b/drivers/hwmon/atxp1.c
index d191118..d6b490d 100644
--- a/drivers/hwmon/atxp1.c
+++ b/drivers/hwmon/atxp1.c
@@ -31,7 +31,7 @@
 
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("System voltages control via Attansic ATXP1");
-MODULE_VERSION("0.6.2");
+MODULE_VERSION("0.6.3");
 MODULE_AUTHOR("Sebastian Witt <se.witt@gmx.net>");
 
 #define ATXP1_VID	0x00
@@ -289,16 +289,16 @@
 	if (!((i2c_smbus_read_byte_data(new_client, 0x3e) == 0) &&
 	     (i2c_smbus_read_byte_data(new_client, 0x3f) == 0) &&
 	     (i2c_smbus_read_byte_data(new_client, 0xfe) == 0) &&
-	     (i2c_smbus_read_byte_data(new_client, 0xff) == 0) )) {
+	     (i2c_smbus_read_byte_data(new_client, 0xff) == 0)))
+		return -ENODEV;
 
-		/* No vendor ID, now checking if registers 0x10,0x11 (non-existent)
-		 * showing the same as register 0x00 */
-		temp = i2c_smbus_read_byte_data(new_client, 0x00);
+	/* No vendor ID, now checking if registers 0x10,0x11 (non-existent)
+	 * showing the same as register 0x00 */
+	temp = i2c_smbus_read_byte_data(new_client, 0x00);
 
-		if (!((i2c_smbus_read_byte_data(new_client, 0x10) == temp) &&
-			 (i2c_smbus_read_byte_data(new_client, 0x11) == temp) ))
-			return -ENODEV;
-	}
+	if (!((i2c_smbus_read_byte_data(new_client, 0x10) == temp) &&
+	      (i2c_smbus_read_byte_data(new_client, 0x11) == temp)))
+		return -ENODEV;
 
 	/* Get VRM */
 	temp = vid_which_vrm();
diff --git a/drivers/hwmon/dme1737.c b/drivers/hwmon/dme1737.c
index cdb8311..27a5d39 100644
--- a/drivers/hwmon/dme1737.c
+++ b/drivers/hwmon/dme1737.c
@@ -175,11 +175,11 @@
  * Data structures and manipulation thereof
  * --------------------------------------------------------------------- */
 
-/* For ISA chips, we abuse the i2c_client addr and name fields. We also use
-   the driver field to differentiate between I2C and ISA chips. */
 struct dme1737_data {
-	struct i2c_client client;
+	struct i2c_client *client;	/* for I2C devices only */
 	struct device *hwmon_dev;
+	const char *name;
+	unsigned int addr;		/* for ISA devices only */
 
 	struct mutex update_lock;
 	int valid;			/* !=0 if following fields are valid */
@@ -512,11 +512,12 @@
  * before calling dme1737_read or dme1737_write.
  * --------------------------------------------------------------------- */
 
-static u8 dme1737_read(struct i2c_client *client, u8 reg)
+static u8 dme1737_read(const struct dme1737_data *data, u8 reg)
 {
+	struct i2c_client *client = data->client;
 	s32 val;
 
-	if (client->driver) { /* I2C device */
+	if (client) { /* I2C device */
 		val = i2c_smbus_read_byte_data(client, reg);
 
 		if (val < 0) {
@@ -525,18 +526,19 @@
 				 "maintainer.\n", reg);
 		}
 	} else { /* ISA device */
-		outb(reg, client->addr);
-		val = inb(client->addr + 1);
+		outb(reg, data->addr);
+		val = inb(data->addr + 1);
 	}
 
 	return val;
 }
 
-static s32 dme1737_write(struct i2c_client *client, u8 reg, u8 val)
+static s32 dme1737_write(const struct dme1737_data *data, u8 reg, u8 val)
 {
+	struct i2c_client *client = data->client;
 	s32 res = 0;
 
-	if (client->driver) { /* I2C device */
+	if (client) { /* I2C device */
 		res = i2c_smbus_write_byte_data(client, reg, val);
 
 		if (res < 0) {
@@ -545,8 +547,8 @@
 				 "maintainer.\n", reg);
 		}
 	} else { /* ISA device */
-		outb(reg, client->addr);
-		outb(val, client->addr + 1);
+		outb(reg, data->addr);
+		outb(val, data->addr + 1);
 	}
 
 	return res;
@@ -555,7 +557,6 @@
 static struct dme1737_data *dme1737_update_device(struct device *dev)
 {
 	struct dme1737_data *data = dev_get_drvdata(dev);
-	struct i2c_client *client = &data->client;
 	int ix;
 	u8 lsb[5];
 
@@ -563,7 +564,7 @@
 
 	/* Enable a Vbat monitoring cycle every 10 mins */
 	if (time_after(jiffies, data->last_vbat + 600 * HZ) || !data->valid) {
-		dme1737_write(client, DME1737_REG_CONFIG, dme1737_read(client,
+		dme1737_write(data, DME1737_REG_CONFIG, dme1737_read(data,
 						DME1737_REG_CONFIG) | 0x10);
 		data->last_vbat = jiffies;
 	}
@@ -571,7 +572,7 @@
 	/* Sample register contents every 1 sec */
 	if (time_after(jiffies, data->last_update + HZ) || !data->valid) {
 		if (data->type != sch5027) {
-			data->vid = dme1737_read(client, DME1737_REG_VID) &
+			data->vid = dme1737_read(data, DME1737_REG_VID) &
 				0x3f;
 		}
 
@@ -580,11 +581,11 @@
 			/* Voltage inputs are stored as 16 bit values even
 			 * though they have only 12 bits resolution. This is
 			 * to make it consistent with the temp inputs. */
-			data->in[ix] = dme1737_read(client,
+			data->in[ix] = dme1737_read(data,
 					DME1737_REG_IN(ix)) << 8;
-			data->in_min[ix] = dme1737_read(client,
+			data->in_min[ix] = dme1737_read(data,
 					DME1737_REG_IN_MIN(ix));
-			data->in_max[ix] = dme1737_read(client,
+			data->in_max[ix] = dme1737_read(data,
 					DME1737_REG_IN_MAX(ix));
 		}
 
@@ -595,14 +596,14 @@
 			 * to take advantage of implicit conversions between
 			 * register values (2's complement) and temp values
 			 * (signed decimal). */
-			data->temp[ix] = dme1737_read(client,
+			data->temp[ix] = dme1737_read(data,
 					DME1737_REG_TEMP(ix)) << 8;
-			data->temp_min[ix] = dme1737_read(client,
+			data->temp_min[ix] = dme1737_read(data,
 					DME1737_REG_TEMP_MIN(ix));
-			data->temp_max[ix] = dme1737_read(client,
+			data->temp_max[ix] = dme1737_read(data,
 					DME1737_REG_TEMP_MAX(ix));
 			if (data->type != sch5027) {
-				data->temp_offset[ix] = dme1737_read(client,
+				data->temp_offset[ix] = dme1737_read(data,
 						DME1737_REG_TEMP_OFFSET(ix));
 			}
 		}
@@ -612,7 +613,7 @@
 		 * which the registers are read (MSB first, then LSB) is
 		 * important! */
 		for (ix = 0; ix < ARRAY_SIZE(lsb); ix++) {
-			lsb[ix] = dme1737_read(client,
+			lsb[ix] = dme1737_read(data,
 					DME1737_REG_IN_TEMP_LSB(ix));
 		}
 		for (ix = 0; ix < ARRAY_SIZE(data->in); ix++) {
@@ -631,19 +632,19 @@
 			if (!(data->has_fan & (1 << ix))) {
 				continue;
 			}
-			data->fan[ix] = dme1737_read(client,
+			data->fan[ix] = dme1737_read(data,
 					DME1737_REG_FAN(ix));
-			data->fan[ix] |= dme1737_read(client,
+			data->fan[ix] |= dme1737_read(data,
 					DME1737_REG_FAN(ix) + 1) << 8;
-			data->fan_min[ix] = dme1737_read(client,
+			data->fan_min[ix] = dme1737_read(data,
 					DME1737_REG_FAN_MIN(ix));
-			data->fan_min[ix] |= dme1737_read(client,
+			data->fan_min[ix] |= dme1737_read(data,
 					DME1737_REG_FAN_MIN(ix) + 1) << 8;
-			data->fan_opt[ix] = dme1737_read(client,
+			data->fan_opt[ix] = dme1737_read(data,
 					DME1737_REG_FAN_OPT(ix));
 			/* fan_max exists only for fan[5-6] */
 			if (ix > 3) {
-				data->fan_max[ix - 4] = dme1737_read(client,
+				data->fan_max[ix - 4] = dme1737_read(data,
 					DME1737_REG_FAN_MAX(ix));
 			}
 		}
@@ -655,63 +656,63 @@
 			if (!(data->has_pwm & (1 << ix))) {
 				continue;
 			}
-			data->pwm[ix] = dme1737_read(client,
+			data->pwm[ix] = dme1737_read(data,
 					DME1737_REG_PWM(ix));
-			data->pwm_freq[ix] = dme1737_read(client,
+			data->pwm_freq[ix] = dme1737_read(data,
 					DME1737_REG_PWM_FREQ(ix));
 			/* pwm_config and pwm_min exist only for pwm[1-3] */
 			if (ix < 3) {
-				data->pwm_config[ix] = dme1737_read(client,
+				data->pwm_config[ix] = dme1737_read(data,
 						DME1737_REG_PWM_CONFIG(ix));
-				data->pwm_min[ix] = dme1737_read(client,
+				data->pwm_min[ix] = dme1737_read(data,
 						DME1737_REG_PWM_MIN(ix));
 			}
 		}
 		for (ix = 0; ix < ARRAY_SIZE(data->pwm_rr); ix++) {
-			data->pwm_rr[ix] = dme1737_read(client,
+			data->pwm_rr[ix] = dme1737_read(data,
 						DME1737_REG_PWM_RR(ix));
 		}
 
 		/* Thermal zone registers */
 		for (ix = 0; ix < ARRAY_SIZE(data->zone_low); ix++) {
-			data->zone_low[ix] = dme1737_read(client,
+			data->zone_low[ix] = dme1737_read(data,
 					DME1737_REG_ZONE_LOW(ix));
-			data->zone_abs[ix] = dme1737_read(client,
+			data->zone_abs[ix] = dme1737_read(data,
 					DME1737_REG_ZONE_ABS(ix));
 		}
 		if (data->type != sch5027) {
 			for (ix = 0; ix < ARRAY_SIZE(data->zone_hyst); ix++) {
-				data->zone_hyst[ix] = dme1737_read(client,
+				data->zone_hyst[ix] = dme1737_read(data,
 						DME1737_REG_ZONE_HYST(ix));
 			}
 		}
 
 		/* Alarm registers */
-		data->alarms = dme1737_read(client,
+		data->alarms = dme1737_read(data,
 						DME1737_REG_ALARM1);
 		/* Bit 7 tells us if the other alarm registers are non-zero and
 		 * therefore also need to be read */
 		if (data->alarms & 0x80) {
-			data->alarms |= dme1737_read(client,
+			data->alarms |= dme1737_read(data,
 						DME1737_REG_ALARM2) << 8;
-			data->alarms |= dme1737_read(client,
+			data->alarms |= dme1737_read(data,
 						DME1737_REG_ALARM3) << 16;
 		}
 
 		/* The ISA chips require explicit clearing of alarm bits.
 		 * Don't worry, an alarm will come back if the condition
 		 * that causes it still exists */
-		if (!client->driver) {
+		if (!data->client) {
 			if (data->alarms & 0xff0000) {
-				dme1737_write(client, DME1737_REG_ALARM3,
+				dme1737_write(data, DME1737_REG_ALARM3,
 					      0xff);
 			}
 			if (data->alarms & 0xff00) {
-				dme1737_write(client, DME1737_REG_ALARM2,
+				dme1737_write(data, DME1737_REG_ALARM2,
 					      0xff);
 			}
 			if (data->alarms & 0xff) {
-				dme1737_write(client, DME1737_REG_ALARM1,
+				dme1737_write(data, DME1737_REG_ALARM1,
 					      0xff);
 			}
 		}
@@ -770,7 +771,6 @@
 		      const char *buf, size_t count)
 {
 	struct dme1737_data *data = dev_get_drvdata(dev);
-	struct i2c_client *client = &data->client;
 	struct sensor_device_attribute_2
 		*sensor_attr_2 = to_sensor_dev_attr_2(attr);
 	int ix = sensor_attr_2->index;
@@ -781,12 +781,12 @@
 	switch (fn) {
 	case SYS_IN_MIN:
 		data->in_min[ix] = IN_TO_REG(val, data->in_nominal[ix]);
-		dme1737_write(client, DME1737_REG_IN_MIN(ix),
+		dme1737_write(data, DME1737_REG_IN_MIN(ix),
 			      data->in_min[ix]);
 		break;
 	case SYS_IN_MAX:
 		data->in_max[ix] = IN_TO_REG(val, data->in_nominal[ix]);
-		dme1737_write(client, DME1737_REG_IN_MAX(ix),
+		dme1737_write(data, DME1737_REG_IN_MAX(ix),
 			      data->in_max[ix]);
 		break;
 	default:
@@ -850,7 +850,6 @@
 			const char *buf, size_t count)
 {
 	struct dme1737_data *data = dev_get_drvdata(dev);
-	struct i2c_client *client = &data->client;
 	struct sensor_device_attribute_2
 		*sensor_attr_2 = to_sensor_dev_attr_2(attr);
 	int ix = sensor_attr_2->index;
@@ -861,17 +860,17 @@
 	switch (fn) {
 	case SYS_TEMP_MIN:
 		data->temp_min[ix] = TEMP_TO_REG(val);
-		dme1737_write(client, DME1737_REG_TEMP_MIN(ix),
+		dme1737_write(data, DME1737_REG_TEMP_MIN(ix),
 			      data->temp_min[ix]);
 		break;
 	case SYS_TEMP_MAX:
 		data->temp_max[ix] = TEMP_TO_REG(val);
-		dme1737_write(client, DME1737_REG_TEMP_MAX(ix),
+		dme1737_write(data, DME1737_REG_TEMP_MAX(ix),
 			      data->temp_max[ix]);
 		break;
 	case SYS_TEMP_OFFSET:
 		data->temp_offset[ix] = TEMP_TO_REG(val);
-		dme1737_write(client, DME1737_REG_TEMP_OFFSET(ix),
+		dme1737_write(data, DME1737_REG_TEMP_OFFSET(ix),
 			      data->temp_offset[ix]);
 		break;
 	default:
@@ -939,7 +938,6 @@
 			const char *buf, size_t count)
 {
 	struct dme1737_data *data = dev_get_drvdata(dev);
-	struct i2c_client *client = &data->client;
 	struct sensor_device_attribute_2
 		*sensor_attr_2 = to_sensor_dev_attr_2(attr);
 	int ix = sensor_attr_2->index;
@@ -950,37 +948,37 @@
 	switch (fn) {
 	case SYS_ZONE_AUTO_POINT1_TEMP_HYST:
 		/* Refresh the cache */
-		data->zone_low[ix] = dme1737_read(client,
+		data->zone_low[ix] = dme1737_read(data,
 						  DME1737_REG_ZONE_LOW(ix));
 		/* Modify the temp hyst value */
 		data->zone_hyst[ix == 2] = TEMP_HYST_TO_REG(
 					TEMP_FROM_REG(data->zone_low[ix], 8) -
-					val, ix, dme1737_read(client,
+					val, ix, dme1737_read(data,
 					DME1737_REG_ZONE_HYST(ix == 2)));
-		dme1737_write(client, DME1737_REG_ZONE_HYST(ix == 2),
+		dme1737_write(data, DME1737_REG_ZONE_HYST(ix == 2),
 			      data->zone_hyst[ix == 2]);
 		break;
 	case SYS_ZONE_AUTO_POINT1_TEMP:
 		data->zone_low[ix] = TEMP_TO_REG(val);
-		dme1737_write(client, DME1737_REG_ZONE_LOW(ix),
+		dme1737_write(data, DME1737_REG_ZONE_LOW(ix),
 			      data->zone_low[ix]);
 		break;
 	case SYS_ZONE_AUTO_POINT2_TEMP:
 		/* Refresh the cache */
-		data->zone_low[ix] = dme1737_read(client,
+		data->zone_low[ix] = dme1737_read(data,
 						  DME1737_REG_ZONE_LOW(ix));
 		/* Modify the temp range value (which is stored in the upper
 		 * nibble of the pwm_freq register) */
 		data->pwm_freq[ix] = TEMP_RANGE_TO_REG(val -
 					TEMP_FROM_REG(data->zone_low[ix], 8),
-					dme1737_read(client,
+					dme1737_read(data,
 					DME1737_REG_PWM_FREQ(ix)));
-		dme1737_write(client, DME1737_REG_PWM_FREQ(ix),
+		dme1737_write(data, DME1737_REG_PWM_FREQ(ix),
 			      data->pwm_freq[ix]);
 		break;
 	case SYS_ZONE_AUTO_POINT3_TEMP:
 		data->zone_abs[ix] = TEMP_TO_REG(val);
-		dme1737_write(client, DME1737_REG_ZONE_ABS(ix),
+		dme1737_write(data, DME1737_REG_ZONE_ABS(ix),
 			      data->zone_abs[ix]);
 		break;
 	default:
@@ -1046,7 +1044,6 @@
 		       const char *buf, size_t count)
 {
 	struct dme1737_data *data = dev_get_drvdata(dev);
-	struct i2c_client *client = &data->client;
 	struct sensor_device_attribute_2
 		*sensor_attr_2 = to_sensor_dev_attr_2(attr);
 	int ix = sensor_attr_2->index;
@@ -1060,21 +1057,21 @@
 			data->fan_min[ix] = FAN_TO_REG(val, 0);
 		} else {
 			/* Refresh the cache */
-			data->fan_opt[ix] = dme1737_read(client,
+			data->fan_opt[ix] = dme1737_read(data,
 						DME1737_REG_FAN_OPT(ix));
 			/* Modify the fan min value */
 			data->fan_min[ix] = FAN_TO_REG(val,
 					FAN_TPC_FROM_REG(data->fan_opt[ix]));
 		}
-		dme1737_write(client, DME1737_REG_FAN_MIN(ix),
+		dme1737_write(data, DME1737_REG_FAN_MIN(ix),
 			      data->fan_min[ix] & 0xff);
-		dme1737_write(client, DME1737_REG_FAN_MIN(ix) + 1,
+		dme1737_write(data, DME1737_REG_FAN_MIN(ix) + 1,
 			      data->fan_min[ix] >> 8);
 		break;
 	case SYS_FAN_MAX:
 		/* Only valid for fan[5-6] */
 		data->fan_max[ix - 4] = FAN_MAX_TO_REG(val);
-		dme1737_write(client, DME1737_REG_FAN_MAX(ix),
+		dme1737_write(data, DME1737_REG_FAN_MAX(ix),
 			      data->fan_max[ix - 4]);
 		break;
 	case SYS_FAN_TYPE:
@@ -1086,9 +1083,9 @@
 				 val);
 			goto exit;
 		}
-		data->fan_opt[ix] = FAN_TYPE_TO_REG(val, dme1737_read(client,
+		data->fan_opt[ix] = FAN_TYPE_TO_REG(val, dme1737_read(data,
 					DME1737_REG_FAN_OPT(ix)));
-		dme1737_write(client, DME1737_REG_FAN_OPT(ix),
+		dme1737_write(data, DME1737_REG_FAN_OPT(ix),
 			      data->fan_opt[ix]);
 		break;
 	default:
@@ -1185,7 +1182,6 @@
 		       const char *buf, size_t count)
 {
 	struct dme1737_data *data = dev_get_drvdata(dev);
-	struct i2c_client *client = &data->client;
 	struct sensor_device_attribute_2
 		*sensor_attr_2 = to_sensor_dev_attr_2(attr);
 	int ix = sensor_attr_2->index;
@@ -1196,12 +1192,12 @@
 	switch (fn) {
 	case SYS_PWM:
 		data->pwm[ix] = SENSORS_LIMIT(val, 0, 255);
-		dme1737_write(client, DME1737_REG_PWM(ix), data->pwm[ix]);
+		dme1737_write(data, DME1737_REG_PWM(ix), data->pwm[ix]);
 		break;
 	case SYS_PWM_FREQ:
-		data->pwm_freq[ix] = PWM_FREQ_TO_REG(val, dme1737_read(client,
+		data->pwm_freq[ix] = PWM_FREQ_TO_REG(val, dme1737_read(data,
 						DME1737_REG_PWM_FREQ(ix)));
-		dme1737_write(client, DME1737_REG_PWM_FREQ(ix),
+		dme1737_write(data, DME1737_REG_PWM_FREQ(ix),
 			      data->pwm_freq[ix]);
 		break;
 	case SYS_PWM_ENABLE:
@@ -1214,7 +1210,7 @@
 			goto exit;
 		}
 		/* Refresh the cache */
-		data->pwm_config[ix] = dme1737_read(client,
+		data->pwm_config[ix] = dme1737_read(data,
 						DME1737_REG_PWM_CONFIG(ix));
 		if (val == PWM_EN_FROM_REG(data->pwm_config[ix])) {
 			/* Bail out if no change */
@@ -1226,14 +1222,14 @@
 			data->pwm_acz[ix] = PWM_ACZ_FROM_REG(
 							data->pwm_config[ix]);
 			/* Save the current ramp rate state and disable it */
-			data->pwm_rr[ix > 0] = dme1737_read(client,
+			data->pwm_rr[ix > 0] = dme1737_read(data,
 						DME1737_REG_PWM_RR(ix > 0));
 			data->pwm_rr_en &= ~(1 << ix);
 			if (PWM_RR_EN_FROM_REG(data->pwm_rr[ix > 0], ix)) {
 				data->pwm_rr_en |= (1 << ix);
 				data->pwm_rr[ix > 0] = PWM_RR_EN_TO_REG(0, ix,
 							data->pwm_rr[ix > 0]);
-				dme1737_write(client,
+				dme1737_write(data,
 					      DME1737_REG_PWM_RR(ix > 0),
 					      data->pwm_rr[ix > 0]);
 			}
@@ -1247,14 +1243,14 @@
 			/* Turn fan fully on */
 			data->pwm_config[ix] = PWM_EN_TO_REG(0,
 							data->pwm_config[ix]);
-			dme1737_write(client, DME1737_REG_PWM_CONFIG(ix),
+			dme1737_write(data, DME1737_REG_PWM_CONFIG(ix),
 				      data->pwm_config[ix]);
 			break;
 		case 1:
 			/* Turn on manual mode */
 			data->pwm_config[ix] = PWM_EN_TO_REG(1,
 							data->pwm_config[ix]);
-			dme1737_write(client, DME1737_REG_PWM_CONFIG(ix),
+			dme1737_write(data, DME1737_REG_PWM_CONFIG(ix),
 				      data->pwm_config[ix]);
 			/* Change permissions of pwm[ix] to read-writeable */
 			dme1737_chmod_file(dev, dme1737_pwm_chmod_attr[ix],
@@ -1269,14 +1265,14 @@
 			data->pwm_config[ix] = PWM_ACZ_TO_REG(
 							data->pwm_acz[ix],
 							data->pwm_config[ix]);
-			dme1737_write(client, DME1737_REG_PWM_CONFIG(ix),
+			dme1737_write(data, DME1737_REG_PWM_CONFIG(ix),
 				      data->pwm_config[ix]);
 			/* Enable PWM ramp rate if previously enabled */
 			if (data->pwm_rr_en & (1 << ix)) {
 				data->pwm_rr[ix > 0] = PWM_RR_EN_TO_REG(1, ix,
-						dme1737_read(client,
+						dme1737_read(data,
 						DME1737_REG_PWM_RR(ix > 0)));
-				dme1737_write(client,
+				dme1737_write(data,
 					      DME1737_REG_PWM_RR(ix > 0),
 					      data->pwm_rr[ix > 0]);
 			}
@@ -1286,9 +1282,9 @@
 	case SYS_PWM_RAMP_RATE:
 		/* Only valid for pwm[1-3] */
 		/* Refresh the cache */
-		data->pwm_config[ix] = dme1737_read(client,
+		data->pwm_config[ix] = dme1737_read(data,
 						DME1737_REG_PWM_CONFIG(ix));
-		data->pwm_rr[ix > 0] = dme1737_read(client,
+		data->pwm_rr[ix > 0] = dme1737_read(data,
 						DME1737_REG_PWM_RR(ix > 0));
 		/* Set the ramp rate value */
 		if (val > 0) {
@@ -1301,7 +1297,7 @@
 			data->pwm_rr[ix > 0] = PWM_RR_EN_TO_REG(val > 0, ix,
 							data->pwm_rr[ix > 0]);
 		}
-		dme1737_write(client, DME1737_REG_PWM_RR(ix > 0),
+		dme1737_write(data, DME1737_REG_PWM_RR(ix > 0),
 			      data->pwm_rr[ix > 0]);
 		break;
 	case SYS_PWM_AUTO_CHANNELS_ZONE:
@@ -1315,14 +1311,14 @@
 			goto exit;
 		}
 		/* Refresh the cache */
-		data->pwm_config[ix] = dme1737_read(client,
+		data->pwm_config[ix] = dme1737_read(data,
 						DME1737_REG_PWM_CONFIG(ix));
 		if (PWM_EN_FROM_REG(data->pwm_config[ix]) == 2) {
 			/* PWM is already in auto mode so update the temp
 			 * channel assignment */
 			data->pwm_config[ix] = PWM_ACZ_TO_REG(val,
 						data->pwm_config[ix]);
-			dme1737_write(client, DME1737_REG_PWM_CONFIG(ix),
+			dme1737_write(data, DME1737_REG_PWM_CONFIG(ix),
 				      data->pwm_config[ix]);
 		} else {
 			/* PWM is not in auto mode so we save the temp
@@ -1333,7 +1329,7 @@
 	case SYS_PWM_AUTO_PWM_MIN:
 		/* Only valid for pwm[1-3] */
 		/* Refresh the cache */
-		data->pwm_min[ix] = dme1737_read(client,
+		data->pwm_min[ix] = dme1737_read(data,
 						DME1737_REG_PWM_MIN(ix));
 		/* There are only 2 values supported for the auto_pwm_min
 		 * value: 0 or auto_point1_pwm. So if the temperature drops
@@ -1341,20 +1337,20 @@
 		 * off or runs at auto_point1_pwm duty-cycle. */
 		if (val > ((data->pwm_min[ix] + 1) / 2)) {
 			data->pwm_rr[0] = PWM_OFF_TO_REG(1, ix,
-						dme1737_read(client,
+						dme1737_read(data,
 						DME1737_REG_PWM_RR(0)));
 		} else {
 			data->pwm_rr[0] = PWM_OFF_TO_REG(0, ix,
-						dme1737_read(client,
+						dme1737_read(data,
 						DME1737_REG_PWM_RR(0)));
 		}
-		dme1737_write(client, DME1737_REG_PWM_RR(0),
+		dme1737_write(data, DME1737_REG_PWM_RR(0),
 			      data->pwm_rr[0]);
 		break;
 	case SYS_PWM_AUTO_POINT1_PWM:
 		/* Only valid for pwm[1-3] */
 		data->pwm_min[ix] = SENSORS_LIMIT(val, 0, 255);
-		dme1737_write(client, DME1737_REG_PWM_MIN(ix),
+		dme1737_write(data, DME1737_REG_PWM_MIN(ix),
 			      data->pwm_min[ix]);
 		break;
 	default:
@@ -1402,7 +1398,7 @@
 {
 	struct dme1737_data *data = dev_get_drvdata(dev);
 
-	return sprintf(buf, "%s\n", data->client.name);
+	return sprintf(buf, "%s\n", data->name);
 }
 
 /* ---------------------------------------------------------------------
@@ -1908,7 +1904,7 @@
 
 	sysfs_remove_group(&dev->kobj, &dme1737_group);
 
-	if (!data->client.driver) {
+	if (!data->client) {
 		sysfs_remove_file(&dev->kobj, &dev_attr_name.attr);
 	}
 }
@@ -1919,7 +1915,7 @@
 	int err, ix;
 
 	/* Create a name attribute for ISA devices */
-	if (!data->client.driver &&
+	if (!data->client &&
 	    (err = sysfs_create_file(&dev->kobj, &dev_attr_name.attr))) {
 		goto exit;
 	}
@@ -2013,14 +2009,14 @@
 static int dme1737_init_device(struct device *dev)
 {
 	struct dme1737_data *data = dev_get_drvdata(dev);
-	struct i2c_client *client = &data->client;
+	struct i2c_client *client = data->client;
 	int ix;
 	u8 reg;
 
 	/* Point to the right nominal voltages array */
 	data->in_nominal = IN_NOMINAL(data->type);
 
-	data->config = dme1737_read(client, DME1737_REG_CONFIG);
+	data->config = dme1737_read(data, DME1737_REG_CONFIG);
 	/* Inform if part is not monitoring/started */
 	if (!(data->config & 0x01)) {
 		if (!force_start) {
@@ -2032,7 +2028,7 @@
 
 		/* Force monitoring */
 		data->config |= 0x01;
-		dme1737_write(client, DME1737_REG_CONFIG, data->config);
+		dme1737_write(data, DME1737_REG_CONFIG, data->config);
 	}
 	/* Inform if part is not ready */
 	if (!(data->config & 0x04)) {
@@ -2041,8 +2037,8 @@
 	}
 
 	/* Determine which optional fan and pwm features are enabled/present */
-	if (client->driver) {   /* I2C chip */
-		data->config2 = dme1737_read(client, DME1737_REG_CONFIG2);
+	if (client) {   /* I2C chip */
+		data->config2 = dme1737_read(data, DME1737_REG_CONFIG2);
 		/* Check if optional fan3 input is enabled */
 		if (data->config2 & 0x04) {
 			data->has_fan |= (1 << 2);
@@ -2051,7 +2047,7 @@
 		/* Fan4 and pwm3 are only available if the client's I2C address
 		 * is the default 0x2e. Otherwise the I/Os associated with
 		 * these functions are used for addr enable/select. */
-		if (data->client.addr == 0x2e) {
+		if (client->addr == 0x2e) {
 			data->has_fan |= (1 << 3);
 			data->has_pwm |= (1 << 2);
 		}
@@ -2086,16 +2082,16 @@
 		 (data->has_fan & (1 << 4)) ? "yes" : "no",
 		 (data->has_fan & (1 << 5)) ? "yes" : "no");
 
-	reg = dme1737_read(client, DME1737_REG_TACH_PWM);
+	reg = dme1737_read(data, DME1737_REG_TACH_PWM);
 	/* Inform if fan-to-pwm mapping differs from the default */
-	if (client->driver && reg != 0xa4) {   /* I2C chip */
+	if (client && reg != 0xa4) {   /* I2C chip */
 		dev_warn(dev, "Non-standard fan to pwm mapping: "
 			 "fan1->pwm%d, fan2->pwm%d, fan3->pwm%d, "
 			 "fan4->pwm%d. Please report to the driver "
 			 "maintainer.\n",
 			 (reg & 0x03) + 1, ((reg >> 2) & 0x03) + 1,
 			 ((reg >> 4) & 0x03) + 1, ((reg >> 6) & 0x03) + 1);
-	} else if (!client->driver && reg != 0x24) {   /* ISA chip */
+	} else if (!client && reg != 0x24) {   /* ISA chip */
 		dev_warn(dev, "Non-standard fan to pwm mapping: "
 			 "fan1->pwm%d, fan2->pwm%d, fan3->pwm%d. "
 			 "Please report to the driver maintainer.\n",
@@ -2108,7 +2104,7 @@
 	 * disabled). */
 	if (!(data->config & 0x02)) {
 		for (ix = 0; ix < 3; ix++) {
-			data->pwm_config[ix] = dme1737_read(client,
+			data->pwm_config[ix] = dme1737_read(data,
 						DME1737_REG_PWM_CONFIG(ix));
 			if ((data->has_pwm & (1 << ix)) &&
 			    (PWM_EN_FROM_REG(data->pwm_config[ix]) == -1)) {
@@ -2116,8 +2112,8 @@
 					 "manual mode.\n", ix + 1);
 				data->pwm_config[ix] = PWM_EN_TO_REG(1,
 							data->pwm_config[ix]);
-				dme1737_write(client, DME1737_REG_PWM(ix), 0);
-				dme1737_write(client,
+				dme1737_write(data, DME1737_REG_PWM(ix), 0);
+				dme1737_write(data,
 					      DME1737_REG_PWM_CONFIG(ix),
 					      data->pwm_config[ix]);
 			}
@@ -2191,37 +2187,24 @@
 	return err;
 }
 
-static int dme1737_i2c_detect(struct i2c_adapter *adapter, int address,
-			      int kind)
+/* Return 0 if detection is successful, -ENODEV otherwise */
+static int dme1737_i2c_detect(struct i2c_client *client, int kind,
+			      struct i2c_board_info *info)
 {
+	struct i2c_adapter *adapter = client->adapter;
+	struct device *dev = &adapter->dev;
 	u8 company, verstep = 0;
-	struct i2c_client *client;
-	struct dme1737_data *data;
-	struct device *dev;
-	int err = 0;
 	const char *name;
 
 	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
-		goto exit;
+		return -ENODEV;
 	}
 
-	if (!(data = kzalloc(sizeof(struct dme1737_data), GFP_KERNEL))) {
-		err = -ENOMEM;
-		goto exit;
-	}
-
-	client = &data->client;
-	i2c_set_clientdata(client, data);
-	client->addr = address;
-	client->adapter = adapter;
-	client->driver = &dme1737_i2c_driver;
-	dev = &client->dev;
-
 	/* A negative kind means that the driver was loaded with no force
 	 * parameter (default), so we must identify the chip. */
 	if (kind < 0) {
-		company = dme1737_read(client, DME1737_REG_COMPANY);
-		verstep = dme1737_read(client, DME1737_REG_VERSTEP);
+		company = i2c_smbus_read_byte_data(client, DME1737_REG_COMPANY);
+		verstep = i2c_smbus_read_byte_data(client, DME1737_REG_VERSTEP);
 
 		if (company == DME1737_COMPANY_SMSC &&
 		    (verstep & DME1737_VERSTEP_MASK) == DME1737_VERSTEP) {
@@ -2230,8 +2213,7 @@
 			   verstep == SCH5027_VERSTEP) {
 			kind = sch5027;
 		} else {
-			err = -ENODEV;
-			goto exit_kfree;
+			return -ENODEV;
 		}
 	}
 
@@ -2241,32 +2223,44 @@
 		kind = dme1737;
 		name = "dme1737";
 	}
-	data->type = kind;
-
-	/* Fill in the remaining client fields and put it into the global
-	 * list */
-	strlcpy(client->name, name, I2C_NAME_SIZE);
-	mutex_init(&data->update_lock);
-
-	/* Tell the I2C layer a new client has arrived */
-	if ((err = i2c_attach_client(client))) {
-		goto exit_kfree;
-	}
 
 	dev_info(dev, "Found a %s chip at 0x%02x (rev 0x%02x).\n",
 		 kind == sch5027 ? "SCH5027" : "DME1737", client->addr,
 		 verstep);
+	strlcpy(info->type, name, I2C_NAME_SIZE);
+
+	return 0;
+}
+
+static int dme1737_i2c_probe(struct i2c_client *client,
+			     const struct i2c_device_id *id)
+{
+	struct dme1737_data *data;
+	struct device *dev = &client->dev;
+	int err;
+
+	data = kzalloc(sizeof(struct dme1737_data), GFP_KERNEL);
+	if (!data) {
+		err = -ENOMEM;
+		goto exit;
+	}
+
+	i2c_set_clientdata(client, data);
+	data->type = id->driver_data;
+	data->client = client;
+	data->name = client->name;
+	mutex_init(&data->update_lock);
 
 	/* Initialize the DME1737 chip */
 	if ((err = dme1737_init_device(dev))) {
 		dev_err(dev, "Failed to initialize device.\n");
-		goto exit_detach;
+		goto exit_kfree;
 	}
 
 	/* Create sysfs files */
 	if ((err = dme1737_create_files(dev))) {
 		dev_err(dev, "Failed to create sysfs files.\n");
-		goto exit_detach;
+		goto exit_kfree;
 	}
 
 	/* Register device */
@@ -2281,45 +2275,40 @@
 
 exit_remove:
 	dme1737_remove_files(dev);
-exit_detach:
-	i2c_detach_client(client);
 exit_kfree:
 	kfree(data);
 exit:
 	return err;
 }
 
-static int dme1737_i2c_attach_adapter(struct i2c_adapter *adapter)
-{
-	if (!(adapter->class & I2C_CLASS_HWMON)) {
-		return 0;
-	}
-
-	return i2c_probe(adapter, &addr_data, dme1737_i2c_detect);
-}
-
-static int dme1737_i2c_detach_client(struct i2c_client *client)
+static int dme1737_i2c_remove(struct i2c_client *client)
 {
 	struct dme1737_data *data = i2c_get_clientdata(client);
-	int err;
 
 	hwmon_device_unregister(data->hwmon_dev);
 	dme1737_remove_files(&client->dev);
 
-	if ((err = i2c_detach_client(client))) {
-		return err;
-	}
-
 	kfree(data);
 	return 0;
 }
 
+static const struct i2c_device_id dme1737_id[] = {
+	{ "dme1737", dme1737 },
+	{ "sch5027", sch5027 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, dme1737_id);
+
 static struct i2c_driver dme1737_i2c_driver = {
+	.class = I2C_CLASS_HWMON,
 	.driver = {
 		.name = "dme1737",
 	},
-	.attach_adapter	= dme1737_i2c_attach_adapter,
-	.detach_client = dme1737_i2c_detach_client,
+	.probe = dme1737_i2c_probe,
+	.remove = dme1737_i2c_remove,
+	.id_table = dme1737_id,
+	.detect = dme1737_i2c_detect,
+	.address_data = &addr_data,
 };
 
 /* ---------------------------------------------------------------------
@@ -2403,7 +2392,6 @@
 {
 	u8 company, device;
 	struct resource *res;
-	struct i2c_client *client;
 	struct dme1737_data *data;
 	struct device *dev = &pdev->dev;
 	int err;
@@ -2422,15 +2410,13 @@
 		goto exit_release_region;
 	}
 
-	client = &data->client;
-	i2c_set_clientdata(client, data);
-	client->addr = res->start;
+	data->addr = res->start;
 	platform_set_drvdata(pdev, data);
 
 	/* Skip chip detection if module is loaded with force_id parameter */
 	if (!force_id) {
-		company = dme1737_read(client, DME1737_REG_COMPANY);
-		device = dme1737_read(client, DME1737_REG_DEVICE);
+		company = dme1737_read(data, DME1737_REG_COMPANY);
+		device = dme1737_read(data, DME1737_REG_DEVICE);
 
 		if (!((company == DME1737_COMPANY_SMSC) &&
 		      (device == SCH311X_DEVICE))) {
@@ -2441,10 +2427,10 @@
 	data->type = sch311x;
 
 	/* Fill in the remaining client fields and initialize the mutex */
-	strlcpy(client->name, "sch311x", I2C_NAME_SIZE);
+	data->name = "sch311x";
 	mutex_init(&data->update_lock);
 
-	dev_info(dev, "Found a SCH311x chip at 0x%04x\n", client->addr);
+	dev_info(dev, "Found a SCH311x chip at 0x%04x\n", data->addr);
 
 	/* Initialize the chip */
 	if ((err = dme1737_init_device(dev))) {
@@ -2485,7 +2471,7 @@
 
 	hwmon_device_unregister(data->hwmon_dev);
 	dme1737_remove_files(&pdev->dev);
-	release_region(data->client.addr, DME1737_EXTENT);
+	release_region(data->addr, DME1737_EXTENT);
 	platform_set_drvdata(pdev, NULL);
 	kfree(data);
 
diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c
index 30cdb09..d793cc0 100644
--- a/drivers/hwmon/it87.c
+++ b/drivers/hwmon/it87.c
@@ -46,6 +46,8 @@
 #include <linux/err.h>
 #include <linux/mutex.h>
 #include <linux/sysfs.h>
+#include <linux/string.h>
+#include <linux/dmi.h>
 #include <asm/io.h>
 
 #define DRVNAME "it87"
@@ -236,6 +238,8 @@
 	/* Values read from Super-I/O config space */
 	u8 revision;
 	u8 vid_value;
+	/* Values set based on DMI strings */
+	u8 skip_pwm;
 };
 
 /* For each registered chip, we need to keep some data in memory.
@@ -273,10 +277,10 @@
 static inline int has_16bit_fans(const struct it87_data *data)
 {
 	/* IT8705F Datasheet 0.4.1, 3h == Version G.
-	   IT8712F Datasheet 0.9.1, section 8.3.5 indicates 7h == Version I.
+	   IT8712F Datasheet 0.9.1, section 8.3.5 indicates 8h == Version J.
 	   These are the first revisions with 16bit tachometer support. */
 	return (data->type == it87 && data->revision >= 0x03)
-	    || (data->type == it8712 && data->revision >= 0x07)
+	    || (data->type == it8712 && data->revision >= 0x08)
 	    || data->type == it8716
 	    || data->type == it8718;
 }
@@ -964,6 +968,7 @@
 {
 	int err = -ENODEV;
 	u16 chip_type;
+	const char *board_vendor, *board_name;
 
 	superio_enter();
 	chip_type = force_id ? force_id : superio_inw(DEVID);
@@ -1022,6 +1027,24 @@
 			pr_info("it87: in7 is VCCH (+5V Stand-By)\n");
 	}
 
+	/* Disable specific features based on DMI strings */
+	board_vendor = dmi_get_system_info(DMI_BOARD_VENDOR);
+	board_name = dmi_get_system_info(DMI_BOARD_NAME);
+	if (board_vendor && board_name) {
+		if (strcmp(board_vendor, "nVIDIA") == 0
+		 && strcmp(board_name, "FN68PT") == 0) {
+			/* On the Shuttle SN68PT, FAN_CTL2 is apparently not
+			   connected to a fan, but to something else. One user
+			   has reported instant system power-off when changing
+			   the PWM2 duty cycle, so we disable it.
+			   I use the board name string as the trigger in case
+			   the same board is ever used in other systems. */
+			pr_info("it87: Disabling pwm2 due to "
+				"hardware constraints\n");
+			sio_data->skip_pwm = (1 << 1);
+		}
+	}
+
 exit:
 	superio_exit();
 	return err;
@@ -1168,25 +1191,33 @@
 	}
 
 	if (enable_pwm_interface) {
-		if ((err = device_create_file(dev,
-		     &sensor_dev_attr_pwm1_enable.dev_attr))
-		 || (err = device_create_file(dev,
-		     &sensor_dev_attr_pwm2_enable.dev_attr))
-		 || (err = device_create_file(dev,
-		     &sensor_dev_attr_pwm3_enable.dev_attr))
-		 || (err = device_create_file(dev,
-		     &sensor_dev_attr_pwm1.dev_attr))
-		 || (err = device_create_file(dev,
-		     &sensor_dev_attr_pwm2.dev_attr))
-		 || (err = device_create_file(dev,
-		     &sensor_dev_attr_pwm3.dev_attr))
-		 || (err = device_create_file(dev,
-		     &dev_attr_pwm1_freq))
-		 || (err = device_create_file(dev,
-		     &dev_attr_pwm2_freq))
-		 || (err = device_create_file(dev,
-		     &dev_attr_pwm3_freq)))
-			goto ERROR4;
+		if (!(sio_data->skip_pwm & (1 << 0))) {
+			if ((err = device_create_file(dev,
+			     &sensor_dev_attr_pwm1_enable.dev_attr))
+			 || (err = device_create_file(dev,
+			     &sensor_dev_attr_pwm1.dev_attr))
+			 || (err = device_create_file(dev,
+			     &dev_attr_pwm1_freq)))
+				goto ERROR4;
+		}
+		if (!(sio_data->skip_pwm & (1 << 1))) {
+			if ((err = device_create_file(dev,
+			     &sensor_dev_attr_pwm2_enable.dev_attr))
+			 || (err = device_create_file(dev,
+			     &sensor_dev_attr_pwm2.dev_attr))
+			 || (err = device_create_file(dev,
+			     &dev_attr_pwm2_freq)))
+				goto ERROR4;
+		}
+		if (!(sio_data->skip_pwm & (1 << 2))) {
+			if ((err = device_create_file(dev,
+			     &sensor_dev_attr_pwm3_enable.dev_attr))
+			 || (err = device_create_file(dev,
+			     &sensor_dev_attr_pwm3.dev_attr))
+			 || (err = device_create_file(dev,
+			     &dev_attr_pwm3_freq)))
+				goto ERROR4;
+		}
 	}
 
 	if (data->type == it8712 || data->type == it8716
@@ -1546,6 +1577,7 @@
 	unsigned short isa_address=0;
 	struct it87_sio_data sio_data;
 
+	memset(&sio_data, 0, sizeof(struct it87_sio_data));
 	err = it87_find(&isa_address, &sio_data);
 	if (err)
 		return err;
diff --git a/drivers/hwmon/max1111.c b/drivers/hwmon/max1111.c
new file mode 100644
index 0000000..bfaa665
--- /dev/null
+++ b/drivers/hwmon/max1111.c
@@ -0,0 +1,244 @@
+/*
+ * max1111.c - +2.7V, Low-Power, Multichannel, Serial 8-bit ADCs
+ *
+ * Based on arch/arm/mach-pxa/corgi_ssp.c
+ *
+ * Copyright (C) 2004-2005 Richard Purdie
+ *
+ * Copyright (C) 2008 Marvell International Ltd.
+ * 	Eric Miao <eric.miao@marvell.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
+ *  publishhed by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/spi/spi.h>
+
+#define MAX1111_TX_BUF_SIZE	1
+#define MAX1111_RX_BUF_SIZE	2
+
+/* MAX1111 Commands */
+#define MAX1111_CTRL_PD0      (1u << 0)
+#define MAX1111_CTRL_PD1      (1u << 1)
+#define MAX1111_CTRL_SGL      (1u << 2)
+#define MAX1111_CTRL_UNI      (1u << 3)
+#define MAX1111_CTRL_SEL_SH   (5)	/* NOTE: bit 4 is ignored */
+#define MAX1111_CTRL_STR      (1u << 7)
+
+struct max1111_data {
+	struct spi_device	*spi;
+	struct device		*hwmon_dev;
+	struct spi_message	msg;
+	struct spi_transfer	xfer[2];
+	uint8_t *tx_buf;
+	uint8_t *rx_buf;
+};
+
+static int max1111_read(struct device *dev, int channel)
+{
+	struct max1111_data *data = dev_get_drvdata(dev);
+	uint8_t v1, v2;
+	int err;
+
+	data->tx_buf[0] = (channel << MAX1111_CTRL_SEL_SH) |
+		MAX1111_CTRL_PD0 | MAX1111_CTRL_PD1 |
+		MAX1111_CTRL_SGL | MAX1111_CTRL_UNI | MAX1111_CTRL_STR;
+
+	err = spi_sync(data->spi, &data->msg);
+	if (err < 0) {
+		dev_err(dev, "spi_sync failed with %d\n", err);
+		return err;
+	}
+
+	v1 = data->rx_buf[0];
+	v2 = data->rx_buf[1];
+
+	if ((v1 & 0xc0) || (v2 & 0x3f))
+		return -EINVAL;
+
+	return (v1 << 2) | (v2 >> 6);
+}
+
+#ifdef CONFIG_SHARPSL_PM
+static struct max1111_data *the_max1111;
+
+int max1111_read_channel(int channel)
+{
+	return max1111_read(&the_max1111->spi->dev, channel);
+}
+EXPORT_SYMBOL(max1111_read_channel);
+#endif
+
+/*
+ * NOTE: SPI devices do not have a default 'name' attribute, which is
+ * likely to be used by hwmon applications to distinguish between
+ * different devices, explicitly add a name attribute here.
+ */
+static ssize_t show_name(struct device *dev,
+			 struct device_attribute *attr, char *buf)
+{
+	return sprintf(buf, "max1111\n");
+}
+
+static ssize_t show_adc(struct device *dev,
+			struct device_attribute *attr, char *buf)
+{
+	int channel = to_sensor_dev_attr(attr)->index;
+	int ret;
+
+	ret = max1111_read(dev, channel);
+	if (ret < 0)
+		return ret;
+
+	return sprintf(buf, "%d\n", ret);
+}
+
+#define MAX1111_ADC_ATTR(_id)		\
+	SENSOR_DEVICE_ATTR(adc##_id##_in, S_IRUGO, show_adc, NULL, _id)
+
+static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
+static MAX1111_ADC_ATTR(0);
+static MAX1111_ADC_ATTR(1);
+static MAX1111_ADC_ATTR(2);
+static MAX1111_ADC_ATTR(3);
+
+static struct attribute *max1111_attributes[] = {
+	&dev_attr_name.attr,
+	&sensor_dev_attr_adc0_in.dev_attr.attr,
+	&sensor_dev_attr_adc1_in.dev_attr.attr,
+	&sensor_dev_attr_adc2_in.dev_attr.attr,
+	&sensor_dev_attr_adc3_in.dev_attr.attr,
+	NULL,
+};
+
+static const struct attribute_group max1111_attr_group = {
+	.attrs	= max1111_attributes,
+};
+
+static int setup_transfer(struct max1111_data *data)
+{
+	struct spi_message *m;
+	struct spi_transfer *x;
+
+	data->tx_buf = kmalloc(MAX1111_TX_BUF_SIZE, GFP_KERNEL);
+	if (!data->tx_buf)
+		return -ENOMEM;
+
+	data->rx_buf = kmalloc(MAX1111_RX_BUF_SIZE, GFP_KERNEL);
+	if (!data->rx_buf) {
+		kfree(data->tx_buf);
+		return -ENOMEM;
+	}
+
+	m = &data->msg;
+	x = &data->xfer[0];
+
+	spi_message_init(m);
+
+	x->tx_buf = &data->tx_buf[0];
+	x->len = 1;
+	spi_message_add_tail(x, m);
+
+	x++;
+	x->rx_buf = &data->rx_buf[0];
+	x->len = 2;
+	spi_message_add_tail(x, m);
+
+	return 0;
+}
+
+static int __devinit max1111_probe(struct spi_device *spi)
+{
+	struct max1111_data *data;
+	int err;
+
+	spi->bits_per_word = 8;
+	spi->mode = SPI_MODE_0;
+	err = spi_setup(spi);
+	if (err < 0)
+		return err;
+
+	data = kzalloc(sizeof(struct max1111_data), GFP_KERNEL);
+	if (data == NULL) {
+		dev_err(&spi->dev, "failed to allocate memory\n");
+		return -ENOMEM;
+	}
+
+	err = setup_transfer(data);
+	if (err)
+		goto err_free_data;
+
+	data->spi = spi;
+	spi_set_drvdata(spi, data);
+
+	err = sysfs_create_group(&spi->dev.kobj, &max1111_attr_group);
+	if (err) {
+		dev_err(&spi->dev, "failed to create attribute group\n");
+		goto err_free_all;
+	}
+
+	data->hwmon_dev = hwmon_device_register(&spi->dev);
+	if (IS_ERR(data->hwmon_dev)) {
+		dev_err(&spi->dev, "failed to create hwmon device\n");
+		err = PTR_ERR(data->hwmon_dev);
+		goto err_remove;
+	}
+
+#ifdef CONFIG_SHARPSL_PM
+	the_max1111 = data;
+#endif
+	return 0;
+
+err_remove:
+	sysfs_remove_group(&spi->dev.kobj, &max1111_attr_group);
+err_free_all:
+	kfree(data->rx_buf);
+	kfree(data->tx_buf);
+err_free_data:
+	kfree(data);
+	return err;
+}
+
+static int __devexit max1111_remove(struct spi_device *spi)
+{
+	struct max1111_data *data = spi_get_drvdata(spi);
+
+	hwmon_device_unregister(data->hwmon_dev);
+	sysfs_remove_group(&spi->dev.kobj, &max1111_attr_group);
+	kfree(data->rx_buf);
+	kfree(data->tx_buf);
+	kfree(data);
+	return 0;
+}
+
+static struct spi_driver max1111_driver = {
+	.driver		= {
+		.name	= "max1111",
+		.owner	= THIS_MODULE,
+	},
+	.probe		= max1111_probe,
+	.remove		= __devexit_p(max1111_remove),
+};
+
+static int __init max1111_init(void)
+{
+	return spi_register_driver(&max1111_driver);
+}
+module_init(max1111_init);
+
+static void __exit max1111_exit(void)
+{
+	spi_unregister_driver(&max1111_driver);
+}
+module_exit(max1111_exit);
+
+MODULE_AUTHOR("Eric Miao <eric.miao@marvell.com>");
+MODULE_DESCRIPTION("MAX1111 ADC Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/ultra45_env.c b/drivers/hwmon/ultra45_env.c
new file mode 100644
index 0000000..68e90ab
--- /dev/null
+++ b/drivers/hwmon/ultra45_env.c
@@ -0,0 +1,320 @@
+/* ultra45_env.c: Driver for Ultra45 PIC16F747 environmental monitor.
+ *
+ * Copyright (C) 2008 David S. Miller <davem@davemloft.net>
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/of_device.h>
+#include <linux/io.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+
+#define DRV_MODULE_VERSION	"0.1"
+
+MODULE_AUTHOR("David S. Miller (davem@davemloft.net)");
+MODULE_DESCRIPTION("Ultra45 environmental monitor driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_MODULE_VERSION);
+
+/* PIC device registers */
+#define REG_CMD		0x00UL
+#define  REG_CMD_RESET	0x80
+#define  REG_CMD_ESTAR	0x01
+#define REG_STAT	0x01UL
+#define  REG_STAT_FWVER	0xf0
+#define  REG_STAT_TGOOD	0x08
+#define  REG_STAT_STALE	0x04
+#define  REG_STAT_BUSY	0x02
+#define  REG_STAT_FAULT	0x01
+#define REG_DATA	0x40UL
+#define REG_ADDR	0x41UL
+#define REG_SIZE	0x42UL
+
+/* Registers accessed indirectly via REG_DATA/REG_ADDR */
+#define IREG_FAN0		0x00
+#define IREG_FAN1		0x01
+#define IREG_FAN2		0x02
+#define IREG_FAN3		0x03
+#define IREG_FAN4		0x04
+#define IREG_FAN5		0x05
+#define IREG_LCL_TEMP		0x06
+#define IREG_RMT1_TEMP		0x07
+#define IREG_RMT2_TEMP		0x08
+#define IREG_RMT3_TEMP		0x09
+#define IREG_LM95221_TEMP	0x0a
+#define IREG_FIRE_TEMP		0x0b
+#define IREG_LSI1064_TEMP	0x0c
+#define IREG_FRONT_TEMP		0x0d
+#define IREG_FAN_STAT		0x0e
+#define IREG_VCORE0		0x0f
+#define IREG_VCORE1		0x10
+#define IREG_VMEM0		0x11
+#define IREG_VMEM1		0x12
+#define IREG_PSU_TEMP		0x13
+
+struct env {
+	void __iomem	*regs;
+	spinlock_t	lock;
+
+	struct device	*hwmon_dev;
+};
+
+static u8 env_read(struct env *p, u8 ireg)
+{
+	u8 ret;
+
+	spin_lock(&p->lock);
+	writeb(ireg, p->regs + REG_ADDR);
+	ret = readb(p->regs + REG_DATA);
+	spin_unlock(&p->lock);
+
+	return ret;
+}
+
+static void env_write(struct env *p, u8 ireg, u8 val)
+{
+	spin_lock(&p->lock);
+	writeb(ireg, p->regs + REG_ADDR);
+	writeb(val, p->regs + REG_DATA);
+	spin_unlock(&p->lock);
+}
+
+/* There seems to be a adr7462 providing these values, thus a lot
+ * of these calculations are borrowed from the adt7470 driver.
+ */
+#define FAN_PERIOD_TO_RPM(x)	((90000 * 60) / (x))
+#define FAN_RPM_TO_PERIOD	FAN_PERIOD_TO_RPM
+#define FAN_PERIOD_INVALID	(0xff << 8)
+#define FAN_DATA_VALID(x)	((x) && (x) != FAN_PERIOD_INVALID)
+
+static ssize_t show_fan_speed(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	int fan_nr = to_sensor_dev_attr(attr)->index;
+	struct env *p = dev_get_drvdata(dev);
+	int rpm, period;
+	u8 val;
+
+	val = env_read(p, IREG_FAN0 + fan_nr);
+	period = (int) val << 8;
+	if (FAN_DATA_VALID(period))
+		rpm = FAN_PERIOD_TO_RPM(period);
+	else
+		rpm = 0;
+
+	return sprintf(buf, "%d\n", rpm);
+}
+
+static ssize_t set_fan_speed(struct device *dev, struct device_attribute *attr,
+			     const char *buf, size_t count)
+{
+	int fan_nr = to_sensor_dev_attr(attr)->index;
+	int rpm = simple_strtol(buf, NULL, 10);
+	struct env *p = dev_get_drvdata(dev);
+	int period;
+	u8 val;
+
+	if (!rpm)
+		return -EINVAL;
+
+	period = FAN_RPM_TO_PERIOD(rpm);
+	val = period >> 8;
+	env_write(p, IREG_FAN0 + fan_nr, val);
+
+	return count;
+}
+
+static ssize_t show_fan_fault(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	int fan_nr = to_sensor_dev_attr(attr)->index;
+	struct env *p = dev_get_drvdata(dev);
+	u8 val = env_read(p, IREG_FAN_STAT);
+	return sprintf(buf, "%d\n", (val & (1 << fan_nr)) ? 1 : 0);
+}
+
+#define fan(index)							\
+static SENSOR_DEVICE_ATTR(fan##index##_speed, S_IRUGO | S_IWUSR,	\
+		show_fan_speed, set_fan_speed, index);			\
+static SENSOR_DEVICE_ATTR(fan##index##_fault, S_IRUGO,			\
+		show_fan_fault, NULL, index)
+
+fan(0);
+fan(1);
+fan(2);
+fan(3);
+fan(4);
+
+static SENSOR_DEVICE_ATTR(psu_fan_fault, S_IRUGO, show_fan_fault, NULL, 6);
+
+static ssize_t show_temp(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	int temp_nr = to_sensor_dev_attr(attr)->index;
+	struct env *p = dev_get_drvdata(dev);
+	s8 val;
+
+	val = env_read(p, IREG_LCL_TEMP + temp_nr);
+	return sprintf(buf, "%d\n", ((int) val) - 64);
+}
+
+static SENSOR_DEVICE_ATTR(adt7462_local_temp, S_IRUGO, show_temp, NULL, 0);
+static SENSOR_DEVICE_ATTR(cpu0_temp, S_IRUGO, show_temp, NULL, 1);
+static SENSOR_DEVICE_ATTR(cpu1_temp, S_IRUGO, show_temp, NULL, 2);
+static SENSOR_DEVICE_ATTR(motherboard_temp, S_IRUGO, show_temp, NULL, 3);
+static SENSOR_DEVICE_ATTR(lm95221_local_temp, S_IRUGO, show_temp, NULL, 4);
+static SENSOR_DEVICE_ATTR(fire_temp, S_IRUGO, show_temp, NULL, 5);
+static SENSOR_DEVICE_ATTR(lsi1064_local_temp, S_IRUGO, show_temp, NULL, 6);
+static SENSOR_DEVICE_ATTR(front_panel_temp, S_IRUGO, show_temp, NULL, 7);
+static SENSOR_DEVICE_ATTR(psu_temp, S_IRUGO, show_temp, NULL, 13);
+
+static ssize_t show_stat_bit(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	int index = to_sensor_dev_attr(attr)->index;
+	struct env *p = dev_get_drvdata(dev);
+	u8 val;
+
+	val = readb(p->regs + REG_STAT);
+	return sprintf(buf, "%d\n", (val & (1 << index)) ? 1 : 0);
+}
+
+static SENSOR_DEVICE_ATTR(fan_failure, S_IRUGO, show_stat_bit, NULL, 0);
+static SENSOR_DEVICE_ATTR(env_bus_busy, S_IRUGO, show_stat_bit, NULL, 1);
+static SENSOR_DEVICE_ATTR(env_data_stale, S_IRUGO, show_stat_bit, NULL, 2);
+static SENSOR_DEVICE_ATTR(tpm_self_test_passed, S_IRUGO, show_stat_bit, NULL, 3);
+
+static ssize_t show_fwver(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct env *p = dev_get_drvdata(dev);
+	u8 val;
+
+	val = readb(p->regs + REG_STAT);
+	return sprintf(buf, "%d\n", val >> 4);
+}
+
+static SENSOR_DEVICE_ATTR(firmware_version, S_IRUGO, show_fwver, NULL, 0);
+
+static ssize_t show_name(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	return sprintf(buf, "ultra45\n");
+}
+
+static SENSOR_DEVICE_ATTR(name, S_IRUGO, show_name, NULL, 0);
+
+static struct attribute *env_attributes[] = {
+	&sensor_dev_attr_fan0_speed.dev_attr.attr,
+	&sensor_dev_attr_fan0_fault.dev_attr.attr,
+	&sensor_dev_attr_fan1_speed.dev_attr.attr,
+	&sensor_dev_attr_fan1_fault.dev_attr.attr,
+	&sensor_dev_attr_fan2_speed.dev_attr.attr,
+	&sensor_dev_attr_fan2_fault.dev_attr.attr,
+	&sensor_dev_attr_fan3_speed.dev_attr.attr,
+	&sensor_dev_attr_fan3_fault.dev_attr.attr,
+	&sensor_dev_attr_fan4_speed.dev_attr.attr,
+	&sensor_dev_attr_fan4_fault.dev_attr.attr,
+	&sensor_dev_attr_psu_fan_fault.dev_attr.attr,
+	&sensor_dev_attr_adt7462_local_temp.dev_attr.attr,
+	&sensor_dev_attr_cpu0_temp.dev_attr.attr,
+	&sensor_dev_attr_cpu1_temp.dev_attr.attr,
+	&sensor_dev_attr_motherboard_temp.dev_attr.attr,
+	&sensor_dev_attr_lm95221_local_temp.dev_attr.attr,
+	&sensor_dev_attr_fire_temp.dev_attr.attr,
+	&sensor_dev_attr_lsi1064_local_temp.dev_attr.attr,
+	&sensor_dev_attr_front_panel_temp.dev_attr.attr,
+	&sensor_dev_attr_psu_temp.dev_attr.attr,
+	&sensor_dev_attr_fan_failure.dev_attr.attr,
+	&sensor_dev_attr_env_bus_busy.dev_attr.attr,
+	&sensor_dev_attr_env_data_stale.dev_attr.attr,
+	&sensor_dev_attr_tpm_self_test_passed.dev_attr.attr,
+	&sensor_dev_attr_firmware_version.dev_attr.attr,
+	&sensor_dev_attr_name.dev_attr.attr,
+	NULL,
+};
+
+static const struct attribute_group env_group = {
+	.attrs = env_attributes,
+};
+
+static int __devinit env_probe(struct of_device *op,
+			       const struct of_device_id *match)
+{
+	struct env *p = kzalloc(sizeof(*p), GFP_KERNEL);
+	int err = -ENOMEM;
+
+	if (!p)
+		goto out;
+
+	spin_lock_init(&p->lock);
+
+	p->regs = of_ioremap(&op->resource[0], 0, REG_SIZE, "pic16f747");
+	if (!p->regs)
+		goto out_free;
+
+	err = sysfs_create_group(&op->dev.kobj, &env_group);
+	if (err)
+		goto out_iounmap;
+
+	p->hwmon_dev = hwmon_device_register(&op->dev);
+	if (IS_ERR(p->hwmon_dev)) {
+		err = PTR_ERR(p->hwmon_dev);
+		goto out_sysfs_remove_group;
+	}
+
+	dev_set_drvdata(&op->dev, p);
+	err = 0;
+
+out:
+	return err;
+
+out_sysfs_remove_group:
+	sysfs_remove_group(&op->dev.kobj, &env_group);
+
+out_iounmap:
+	of_iounmap(&op->resource[0], p->regs, REG_SIZE);
+
+out_free:
+	kfree(p);
+	goto out;
+}
+
+static int __devexit env_remove(struct of_device *op)
+{
+	struct env *p = dev_get_drvdata(&op->dev);
+
+	if (p) {
+		sysfs_remove_group(&op->dev.kobj, &env_group);
+		hwmon_device_unregister(p->hwmon_dev);
+		of_iounmap(&op->resource[0], p->regs, REG_SIZE);
+		kfree(p);
+	}
+
+	return 0;
+}
+
+static const struct of_device_id env_match[] = {
+	{
+		.name = "env-monitor",
+		.compatible = "SUNW,ebus-pic16f747-env",
+	},
+	{},
+};
+MODULE_DEVICE_TABLE(of, env_match);
+
+static struct of_platform_driver env_driver = {
+	.name		= "ultra45_env",
+	.match_table	= env_match,
+	.probe		= env_probe,
+	.remove		= __devexit_p(env_remove),
+};
+
+static int __init env_init(void)
+{
+	return of_register_driver(&env_driver, &of_bus_type);
+}
+
+static void __exit env_exit(void)
+{
+	of_unregister_driver(&env_driver);
+}
+
+module_init(env_init);
+module_exit(env_exit);
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index 6ee997b..acadbc5 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -55,7 +55,7 @@
 
 config I2C_AMD756_S4882
 	tristate "SMBus multiplexing on the Tyan S4882"
-	depends on I2C_AMD756 && EXPERIMENTAL
+	depends on I2C_AMD756 && X86 && EXPERIMENTAL
 	help
 	  Enabling this option will add specific SMBus support for the Tyan
 	  S4882 motherboard.  On this 4-CPU board, the SMBus is multiplexed
@@ -148,7 +148,7 @@
 
 config I2C_NFORCE2_S4985
 	tristate "SMBus multiplexing on the Tyan S4985"
-	depends on I2C_NFORCE2 && EXPERIMENTAL
+	depends on I2C_NFORCE2 && X86 && EXPERIMENTAL
 	help
 	  Enabling this option will add specific SMBus support for the Tyan
 	  S4985 motherboard.  On this 4-CPU board, the SMBus is multiplexed
@@ -209,7 +209,7 @@
 	  will be called i2c-via.
 
 config I2C_VIAPRO
-	tristate "VIA VT82C596/82C686/82xx and CX700"
+	tristate "VIA VT82C596/82C686/82xx and CX700/VX800/VX820"
 	depends on PCI
 	help
 	  If you say yes to this option, support will be included for the VIA
@@ -223,6 +223,8 @@
 	    VT8237R/A/S
 	    VT8251
 	    CX700
+	    VX800
+	    VX820
 
 	  This driver can also be built as a module.  If so, the module
 	  will be called i2c-viapro.
@@ -330,6 +332,18 @@
 	  This is a very simple bitbanging I2C driver utilizing the
 	  arch-neutral GPIO API to control the SCL and SDA lines.
 
+config I2C_HIGHLANDER
+	tristate "Highlander FPGA SMBus interface"
+	depends on SH_HIGHLANDER
+	help
+	  If you say yes to this option, support will be included for
+	  the SMBus interface located in the FPGA on various Highlander
+	  boards, particularly the R0P7780LC0011RL and R0P7785LC0011RL
+	  FPGAs. This is wholly unrelated to the SoC I2C.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called i2c-highlander.
+
 config I2C_IBM_IIC
 	tristate "IBM PPC 4xx on-chip I2C interface"
 	depends on 4xx
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index 97dbfa2..0c2c4b2 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -31,6 +31,7 @@
 obj-$(CONFIG_I2C_CPM)		+= i2c-cpm.o
 obj-$(CONFIG_I2C_DAVINCI)	+= i2c-davinci.o
 obj-$(CONFIG_I2C_GPIO)		+= i2c-gpio.o
+obj-$(CONFIG_I2C_HIGHLANDER)	+= i2c-highlander.o
 obj-$(CONFIG_I2C_IBM_IIC)	+= i2c-ibm_iic.o
 obj-$(CONFIG_I2C_IOP3XX)	+= i2c-iop3xx.o
 obj-$(CONFIG_I2C_IXP2000)	+= i2c-ixp2000.o
diff --git a/drivers/i2c/busses/i2c-highlander.c b/drivers/i2c/busses/i2c-highlander.c
new file mode 100644
index 0000000..f4d22ae
--- /dev/null
+++ b/drivers/i2c/busses/i2c-highlander.c
@@ -0,0 +1,498 @@
+/*
+ * Renesas Solutions Highlander FPGA I2C/SMBus support.
+ *
+ * Supported devices: R0P7780LC0011RL, R0P7785LC0011RL
+ *
+ * Copyright (C) 2008  Paul Mundt
+ * Copyright (C) 2008  Renesas Solutions Corp.
+ * Copyright (C) 2008  Atom Create Engineering Co., Ltd.
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License version 2. See the file "COPYING" in the main directory
+ * of this archive for more details.
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/completion.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+
+#define SMCR		0x00
+#define SMCR_START	(1 << 0)
+#define SMCR_IRIC	(1 << 1)
+#define SMCR_BBSY	(1 << 2)
+#define SMCR_ACKE	(1 << 3)
+#define SMCR_RST	(1 << 4)
+#define SMCR_IEIC	(1 << 6)
+
+#define SMSMADR		0x02
+
+#define SMMR		0x04
+#define SMMR_MODE0	(1 << 0)
+#define SMMR_MODE1	(1 << 1)
+#define SMMR_CAP	(1 << 3)
+#define SMMR_TMMD	(1 << 4)
+#define SMMR_SP		(1 << 7)
+
+#define SMSADR		0x06
+#define SMTRDR		0x46
+
+struct highlander_i2c_dev {
+	struct device		*dev;
+	void __iomem		*base;
+	struct i2c_adapter	adapter;
+	struct completion	cmd_complete;
+	unsigned long		last_read_time;
+	int			irq;
+	u8			*buf;
+	size_t			buf_len;
+};
+
+static int iic_force_poll, iic_force_normal;
+static int iic_timeout = 1000, iic_read_delay;
+
+static inline void highlander_i2c_irq_enable(struct highlander_i2c_dev *dev)
+{
+	iowrite16(ioread16(dev->base + SMCR) | SMCR_IEIC, dev->base + SMCR);
+}
+
+static inline void highlander_i2c_irq_disable(struct highlander_i2c_dev *dev)
+{
+	iowrite16(ioread16(dev->base + SMCR) & ~SMCR_IEIC, dev->base + SMCR);
+}
+
+static inline void highlander_i2c_start(struct highlander_i2c_dev *dev)
+{
+	iowrite16(ioread16(dev->base + SMCR) | SMCR_START, dev->base + SMCR);
+}
+
+static inline void highlander_i2c_done(struct highlander_i2c_dev *dev)
+{
+	iowrite16(ioread16(dev->base + SMCR) | SMCR_IRIC, dev->base + SMCR);
+}
+
+static void highlander_i2c_setup(struct highlander_i2c_dev *dev)
+{
+	u16 smmr;
+
+	smmr = ioread16(dev->base + SMMR);
+	smmr |= SMMR_TMMD;
+
+	if (iic_force_normal)
+		smmr &= ~SMMR_SP;
+	else
+		smmr |= SMMR_SP;
+
+	iowrite16(smmr, dev->base + SMMR);
+}
+
+static void smbus_write_data(u8 *src, u16 *dst, int len)
+{
+	for (; len > 1; len -= 2) {
+		*dst++ = be16_to_cpup((u16 *)src);
+		src += 2;
+	}
+
+	if (len)
+		*dst = *src << 8;
+}
+
+static void smbus_read_data(u16 *src, u8 *dst, int len)
+{
+	for (; len > 1; len -= 2) {
+		*(u16 *)dst = cpu_to_be16p(src++);
+		dst += 2;
+	}
+
+	if (len)
+		*dst = *src >> 8;
+}
+
+static void highlander_i2c_command(struct highlander_i2c_dev *dev,
+				   u8 command, int len)
+{
+	unsigned int i;
+	u16 cmd = (command << 8) | command;
+
+	for (i = 0; i < len; i += 2) {
+		if (len - i == 1)
+			cmd = command << 8;
+		iowrite16(cmd, dev->base + SMSADR + i);
+		dev_dbg(dev->dev, "command data[%x] 0x%04x\n", i/2, cmd);
+	}
+}
+
+static int highlander_i2c_wait_for_bbsy(struct highlander_i2c_dev *dev)
+{
+	unsigned long timeout;
+
+	timeout = jiffies + msecs_to_jiffies(iic_timeout);
+	while (ioread16(dev->base + SMCR) & SMCR_BBSY) {
+		if (time_after(jiffies, timeout)) {
+			dev_warn(dev->dev, "timeout waiting for bus ready\n");
+			return -ETIMEDOUT;
+		}
+
+		msleep(1);
+	}
+
+	return 0;
+}
+
+static int highlander_i2c_reset(struct highlander_i2c_dev *dev)
+{
+	iowrite16(ioread16(dev->base + SMCR) | SMCR_RST, dev->base + SMCR);
+	return highlander_i2c_wait_for_bbsy(dev);
+}
+
+static int highlander_i2c_wait_for_ack(struct highlander_i2c_dev *dev)
+{
+	u16 tmp = ioread16(dev->base + SMCR);
+
+	if ((tmp & (SMCR_IRIC | SMCR_ACKE)) == SMCR_ACKE) {
+		dev_warn(dev->dev, "ack abnormality\n");
+		return highlander_i2c_reset(dev);
+	}
+
+	return 0;
+}
+
+static irqreturn_t highlander_i2c_irq(int irq, void *dev_id)
+{
+	struct highlander_i2c_dev *dev = dev_id;
+
+	highlander_i2c_done(dev);
+	complete(&dev->cmd_complete);
+
+	return IRQ_HANDLED;
+}
+
+static void highlander_i2c_poll(struct highlander_i2c_dev *dev)
+{
+	unsigned long timeout;
+	u16 smcr;
+
+	timeout = jiffies + msecs_to_jiffies(iic_timeout);
+	for (;;) {
+		smcr = ioread16(dev->base + SMCR);
+
+		/*
+		 * Don't bother checking ACKE here, this and the reset
+		 * are handled in highlander_i2c_wait_xfer_done() when
+		 * waiting for the ACK.
+		 */
+
+		if (smcr & SMCR_IRIC)
+			return;
+		if (time_after(jiffies, timeout))
+			break;
+
+		cpu_relax();
+		cond_resched();
+	}
+
+	dev_err(dev->dev, "polling timed out\n");
+}
+
+static inline int highlander_i2c_wait_xfer_done(struct highlander_i2c_dev *dev)
+{
+	if (dev->irq)
+		wait_for_completion_timeout(&dev->cmd_complete,
+					  msecs_to_jiffies(iic_timeout));
+	else
+		/* busy looping, the IRQ of champions */
+		highlander_i2c_poll(dev);
+
+	return highlander_i2c_wait_for_ack(dev);
+}
+
+static int highlander_i2c_read(struct highlander_i2c_dev *dev)
+{
+	int i, cnt;
+	u16 data[16];
+
+	if (highlander_i2c_wait_for_bbsy(dev))
+		return -EAGAIN;
+
+	highlander_i2c_start(dev);
+
+	if (highlander_i2c_wait_xfer_done(dev)) {
+		dev_err(dev->dev, "Arbitration loss\n");
+		return -EAGAIN;
+	}
+
+	/*
+	 * The R0P7780LC0011RL FPGA needs a significant delay between
+	 * data read cycles, otherwise the transciever gets confused and
+	 * garbage is returned when the read is subsequently aborted.
+	 *
+	 * It is not sufficient to wait for BBSY.
+	 *
+	 * While this generally only applies to the older SH7780-based
+	 * Highlanders, the same issue can be observed on SH7785 ones,
+	 * albeit less frequently. SH7780-based Highlanders may need
+	 * this to be as high as 1000 ms.
+	 */
+	if (iic_read_delay && time_before(jiffies, dev->last_read_time +
+				 msecs_to_jiffies(iic_read_delay)))
+		msleep(jiffies_to_msecs((dev->last_read_time +
+				msecs_to_jiffies(iic_read_delay)) - jiffies));
+
+	cnt = (dev->buf_len + 1) >> 1;
+	for (i = 0; i < cnt; i++) {
+		data[i] = ioread16(dev->base + SMTRDR + (i * sizeof(u16)));
+		dev_dbg(dev->dev, "read data[%x] 0x%04x\n", i, data[i]);
+	}
+
+	smbus_read_data(data, dev->buf, dev->buf_len);
+
+	dev->last_read_time = jiffies;
+
+	return 0;
+}
+
+static int highlander_i2c_write(struct highlander_i2c_dev *dev)
+{
+	int i, cnt;
+	u16 data[16];
+
+	smbus_write_data(dev->buf, data, dev->buf_len);
+
+	cnt = (dev->buf_len + 1) >> 1;
+	for (i = 0; i < cnt; i++) {
+		iowrite16(data[i], dev->base + SMTRDR + (i * sizeof(u16)));
+		dev_dbg(dev->dev, "write data[%x] 0x%04x\n", i, data[i]);
+	}
+
+	if (highlander_i2c_wait_for_bbsy(dev))
+		return -EAGAIN;
+
+	highlander_i2c_start(dev);
+
+	return highlander_i2c_wait_xfer_done(dev);
+}
+
+static int highlander_i2c_smbus_xfer(struct i2c_adapter *adap, u16 addr,
+				  unsigned short flags, char read_write,
+				  u8 command, int size,
+				  union i2c_smbus_data *data)
+{
+	struct highlander_i2c_dev *dev = i2c_get_adapdata(adap);
+	int read = read_write & I2C_SMBUS_READ;
+	u16 tmp;
+
+	init_completion(&dev->cmd_complete);
+
+	dev_dbg(dev->dev, "addr %04x, command %02x, read_write %d, size %d\n",
+		addr, command, read_write, size);
+
+	/*
+	 * Set up the buffer and transfer size
+	 */
+	switch (size) {
+	case I2C_SMBUS_BYTE_DATA:
+		dev->buf = &data->byte;
+		dev->buf_len = 1;
+		break;
+	case I2C_SMBUS_I2C_BLOCK_DATA:
+		dev->buf = &data->block[1];
+		dev->buf_len = data->block[0];
+		break;
+	default:
+		dev_err(dev->dev, "unsupported command %d\n", size);
+		return -EINVAL;
+	}
+
+	/*
+	 * Encode the mode setting
+	 */
+	tmp = ioread16(dev->base + SMMR);
+	tmp &= ~(SMMR_MODE0 | SMMR_MODE1);
+
+	switch (dev->buf_len) {
+	case 1:
+		/* default */
+		break;
+	case 8:
+		tmp |= SMMR_MODE0;
+		break;
+	case 16:
+		tmp |= SMMR_MODE1;
+		break;
+	case 32:
+		tmp |= (SMMR_MODE0 | SMMR_MODE1);
+		break;
+	default:
+		dev_err(dev->dev, "unsupported xfer size %d\n", dev->buf_len);
+		return -EINVAL;
+	}
+
+	iowrite16(tmp, dev->base + SMMR);
+
+	/* Ensure we're in a sane state */
+	highlander_i2c_done(dev);
+
+	/* Set slave address */
+	iowrite16((addr << 1) | read, dev->base + SMSMADR);
+
+	highlander_i2c_command(dev, command, dev->buf_len);
+
+	if (read)
+		return highlander_i2c_read(dev);
+	else
+		return highlander_i2c_write(dev);
+}
+
+static u32 highlander_i2c_func(struct i2c_adapter *adapter)
+{
+	return I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_I2C_BLOCK;
+}
+
+static const struct i2c_algorithm highlander_i2c_algo = {
+	.smbus_xfer	= highlander_i2c_smbus_xfer,
+	.functionality	= highlander_i2c_func,
+};
+
+static int __devinit highlander_i2c_probe(struct platform_device *pdev)
+{
+	struct highlander_i2c_dev *dev;
+	struct i2c_adapter *adap;
+	struct resource *res;
+	int ret;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (unlikely(!res)) {
+		dev_err(&pdev->dev, "no mem resource\n");
+		return -ENODEV;
+	}
+
+	dev = kzalloc(sizeof(struct highlander_i2c_dev), GFP_KERNEL);
+	if (unlikely(!dev))
+		return -ENOMEM;
+
+	dev->base = ioremap_nocache(res->start, res->end - res->start + 1);
+	if (unlikely(!dev->base)) {
+		ret = -ENXIO;
+		goto err;
+	}
+
+	dev->dev = &pdev->dev;
+	platform_set_drvdata(pdev, dev);
+
+	dev->irq = platform_get_irq(pdev, 0);
+	if (iic_force_poll)
+		dev->irq = 0;
+
+	if (dev->irq) {
+		ret = request_irq(dev->irq, highlander_i2c_irq, IRQF_DISABLED,
+				  pdev->name, dev);
+		if (unlikely(ret))
+			goto err_unmap;
+
+		highlander_i2c_irq_enable(dev);
+	} else {
+		dev_notice(&pdev->dev, "no IRQ, using polling mode\n");
+		highlander_i2c_irq_disable(dev);
+	}
+
+	dev->last_read_time = jiffies;	/* initial read jiffies */
+
+	highlander_i2c_setup(dev);
+
+	adap = &dev->adapter;
+	i2c_set_adapdata(adap, dev);
+	adap->owner = THIS_MODULE;
+	adap->class = I2C_CLASS_HWMON;
+	strlcpy(adap->name, "HL FPGA I2C adapter", sizeof(adap->name));
+	adap->algo = &highlander_i2c_algo;
+	adap->dev.parent = &pdev->dev;
+	adap->nr = pdev->id;
+
+	/*
+	 * Reset the adapter
+	 */
+	ret = highlander_i2c_reset(dev);
+	if (unlikely(ret)) {
+		dev_err(&pdev->dev, "controller didn't come up\n");
+		goto err_free_irq;
+	}
+
+	ret = i2c_add_numbered_adapter(adap);
+	if (unlikely(ret)) {
+		dev_err(&pdev->dev, "failure adding adapter\n");
+		goto err_free_irq;
+	}
+
+	return 0;
+
+err_free_irq:
+	if (dev->irq)
+		free_irq(dev->irq, dev);
+err_unmap:
+	iounmap(dev->base);
+err:
+	kfree(dev);
+
+	platform_set_drvdata(pdev, NULL);
+
+	return ret;
+}
+
+static int __devexit highlander_i2c_remove(struct platform_device *pdev)
+{
+	struct highlander_i2c_dev *dev = platform_get_drvdata(pdev);
+
+	i2c_del_adapter(&dev->adapter);
+
+	if (dev->irq)
+		free_irq(dev->irq, dev);
+
+	iounmap(dev->base);
+	kfree(dev);
+
+	platform_set_drvdata(pdev, NULL);
+
+	return 0;
+}
+
+static struct platform_driver highlander_i2c_driver = {
+	.driver		= {
+		.name	= "i2c-highlander",
+		.owner	= THIS_MODULE,
+	},
+
+	.probe		= highlander_i2c_probe,
+	.remove		= __devexit_p(highlander_i2c_remove),
+};
+
+static int __init highlander_i2c_init(void)
+{
+	return platform_driver_register(&highlander_i2c_driver);
+}
+
+static void __exit highlander_i2c_exit(void)
+{
+	platform_driver_unregister(&highlander_i2c_driver);
+}
+
+module_init(highlander_i2c_init);
+module_exit(highlander_i2c_exit);
+
+MODULE_AUTHOR("Paul Mundt");
+MODULE_DESCRIPTION("Renesas Highlander FPGA I2C/SMBus adapter");
+MODULE_LICENSE("GPL v2");
+
+module_param(iic_force_poll, bool, 0);
+module_param(iic_force_normal, bool, 0);
+module_param(iic_timeout, int, 0);
+module_param(iic_read_delay, int, 0);
+
+MODULE_PARM_DESC(iic_force_poll, "Force polling mode");
+MODULE_PARM_DESC(iic_force_normal,
+		 "Force normal mode (100 kHz), default is fast mode (400 kHz)");
+MODULE_PARM_DESC(iic_timeout, "Set timeout value in msecs (default 1000 ms)");
+MODULE_PARM_DESC(iic_read_delay,
+		 "Delay between data read cycles (default 0 ms)");
diff --git a/drivers/i2c/busses/i2c-parport-light.c b/drivers/i2c/busses/i2c-parport-light.c
index c6faf9b..b2b8380 100644
--- a/drivers/i2c/busses/i2c-parport-light.c
+++ b/drivers/i2c/busses/i2c-parport-light.c
@@ -123,11 +123,6 @@
 static int __devinit i2c_parport_probe(struct platform_device *pdev)
 {
 	int err;
-	struct resource *res;
-
-	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
-	if (!request_region(res->start, res->end - res->start + 1, DRVNAME))
-		return -EBUSY;
 
 	/* Reset hardware to a sane state (SCL and SDA high) */
 	parport_setsda(NULL, 1);
@@ -138,29 +133,19 @@
 
 	parport_adapter.dev.parent = &pdev->dev;
 	err = i2c_bit_add_bus(&parport_adapter);
-	if (err) {
+	if (err)
 		dev_err(&pdev->dev, "Unable to register with I2C\n");
-		goto exit_region;
-	}
-	return 0;
-
-exit_region:
-	release_region(res->start, res->end - res->start + 1);
 	return err;
 }
 
 static int __devexit i2c_parport_remove(struct platform_device *pdev)
 {
-	struct resource *res;
-
 	i2c_del_adapter(&parport_adapter);
 
 	/* Un-init if needed (power off...) */
 	if (adapter_parm[type].init.val)
 		line_set(0, &adapter_parm[type].init);
 
-	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
-	release_region(res->start, res->end - res->start + 1);
 	return 0;
 }
 
@@ -175,12 +160,6 @@
 
 static int __init i2c_parport_device_add(u16 address)
 {
-	struct resource res = {
-		.start	= address,
-		.end	= address + 2,
-		.name	= DRVNAME,
-		.flags	= IORESOURCE_IO,
-	};
 	int err;
 
 	pdev = platform_device_alloc(DRVNAME, -1);
@@ -190,13 +169,6 @@
 		goto exit;
 	}
 
-	err = platform_device_add_resources(pdev, &res, 1);
-	if (err) {
-		printk(KERN_ERR DRVNAME ": Device resource addition failed "
-		       "(%d)\n", err);
-		goto exit_device_put;
-	}
-
 	err = platform_device_add(pdev);
 	if (err) {
 		printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n",
@@ -231,13 +203,16 @@
 		base = DEFAULT_BASE;
 	}
 
+	if (!request_region(base, 3, DRVNAME))
+		return -EBUSY;
+
         if (!adapter_parm[type].getscl.val)
 		parport_algo_data.getscl = NULL;
 
 	/* Sets global pdev as a side effect */
 	err = i2c_parport_device_add(base);
 	if (err)
-		goto exit;
+		goto exit_release;
 
 	err = platform_driver_register(&i2c_parport_driver);
 	if (err)
@@ -247,7 +222,8 @@
 
 exit_device:
 	platform_device_unregister(pdev);
-exit:
+exit_release:
+	release_region(base, 3);
 	return err;
 }
 
@@ -255,6 +231,7 @@
 {
 	platform_driver_unregister(&i2c_parport_driver);
 	platform_device_unregister(pdev);
+	release_region(base, 3);
 }
 
 MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>");
diff --git a/drivers/i2c/busses/i2c-pca-isa.c b/drivers/i2c/busses/i2c-pca-isa.c
index a119784..f80df9a 100644
--- a/drivers/i2c/busses/i2c-pca-isa.c
+++ b/drivers/i2c/busses/i2c-pca-isa.c
@@ -36,8 +36,8 @@
 #define DRIVER "i2c-pca-isa"
 #define IO_SIZE 4
 
-static unsigned long base   = 0x330;
-static int irq 	  = 10;
+static unsigned long base;
+static int irq = -1;
 
 /* Data sheet recommends 59kHz for 100kHz operation due to variation
  * in the actual clock rate */
@@ -107,6 +107,19 @@
 	.timeout	= 100,
 };
 
+static int __devinit pca_isa_match(struct device *dev, unsigned int id)
+{
+	int match = base != 0;
+
+	if (match) {
+		if (irq <= -1)
+			dev_warn(dev, "Using polling mode (specify irq)\n");
+	} else
+		dev_err(dev, "Please specify I/O base\n");
+
+	return match;
+}
+
 static int __devinit pca_isa_probe(struct device *dev, unsigned int id)
 {
 	init_waitqueue_head(&pca_wait);
@@ -153,7 +166,7 @@
 {
 	i2c_del_adapter(&pca_isa_ops);
 
-	if (irq > 0) {
+	if (irq > -1) {
 		disable_irq(irq);
 		free_irq(irq, &pca_isa_ops);
 	}
@@ -163,6 +176,7 @@
 }
 
 static struct isa_driver pca_isa_driver = {
+	.match		= pca_isa_match,
 	.probe		= pca_isa_probe,
 	.remove		= __devexit_p(pca_isa_remove),
 	.driver = {
diff --git a/drivers/i2c/busses/i2c-powermac.c b/drivers/i2c/busses/i2c-powermac.c
index 22f6d5c..0e7b1c6 100644
--- a/drivers/i2c/busses/i2c-powermac.c
+++ b/drivers/i2c/busses/i2c-powermac.c
@@ -180,7 +180,7 @@
 };
 
 
-static int i2c_powermac_remove(struct platform_device *dev)
+static int __devexit i2c_powermac_remove(struct platform_device *dev)
 {
 	struct i2c_adapter	*adapter = platform_get_drvdata(dev);
 	struct pmac_i2c_bus	*bus = i2c_get_adapdata(adapter);
@@ -200,7 +200,7 @@
 }
 
 
-static int __devexit i2c_powermac_probe(struct platform_device *dev)
+static int __devinit i2c_powermac_probe(struct platform_device *dev)
 {
 	struct pmac_i2c_bus *bus = dev->dev.platform_data;
 	struct device_node *parent = NULL;
diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c
index 44d8384..906f9b9 100644
--- a/drivers/i2c/busses/i2c-pxa.c
+++ b/drivers/i2c/busses/i2c-pxa.c
@@ -38,7 +38,44 @@
 #include <asm/irq.h>
 #include <asm/io.h>
 #include <mach/i2c.h>
-#include <mach/pxa-regs.h>
+
+/*
+ * I2C registers and bit definitions
+ */
+#define IBMR		(0x00)
+#define IDBR		(0x08)
+#define ICR		(0x10)
+#define ISR		(0x18)
+#define ISAR		(0x20)
+
+#define ICR_START	(1 << 0)	   /* start bit */
+#define ICR_STOP	(1 << 1)	   /* stop bit */
+#define ICR_ACKNAK	(1 << 2)	   /* send ACK(0) or NAK(1) */
+#define ICR_TB		(1 << 3)	   /* transfer byte bit */
+#define ICR_MA		(1 << 4)	   /* master abort */
+#define ICR_SCLE	(1 << 5)	   /* master clock enable */
+#define ICR_IUE		(1 << 6)	   /* unit enable */
+#define ICR_GCD		(1 << 7)	   /* general call disable */
+#define ICR_ITEIE	(1 << 8)	   /* enable tx interrupts */
+#define ICR_IRFIE	(1 << 9)	   /* enable rx interrupts */
+#define ICR_BEIE	(1 << 10)	   /* enable bus error ints */
+#define ICR_SSDIE	(1 << 11)	   /* slave STOP detected int enable */
+#define ICR_ALDIE	(1 << 12)	   /* enable arbitration interrupt */
+#define ICR_SADIE	(1 << 13)	   /* slave address detected int enable */
+#define ICR_UR		(1 << 14)	   /* unit reset */
+#define ICR_FM		(1 << 15)	   /* fast mode */
+
+#define ISR_RWM		(1 << 0)	   /* read/write mode */
+#define ISR_ACKNAK	(1 << 1)	   /* ack/nak status */
+#define ISR_UB		(1 << 2)	   /* unit busy */
+#define ISR_IBB		(1 << 3)	   /* bus busy */
+#define ISR_SSD		(1 << 4)	   /* slave stop detected */
+#define ISR_ALD		(1 << 5)	   /* arbitration loss detected */
+#define ISR_ITE		(1 << 6)	   /* tx buffer empty */
+#define ISR_IRF		(1 << 7)	   /* rx buffer full */
+#define ISR_GCAD	(1 << 8)	   /* general call address detected */
+#define ISR_SAD		(1 << 9)	   /* slave address detected */
+#define ISR_BED		(1 << 10)	   /* bus error no ACK/NAK */
 
 struct pxa_i2c {
 	spinlock_t		lock;
@@ -60,19 +97,21 @@
 	u32			icrlog[32];
 
 	void __iomem		*reg_base;
+	unsigned int		reg_shift;
 
 	unsigned long		iobase;
 	unsigned long		iosize;
 
 	int			irq;
-	int			use_pio;
+	unsigned int		use_pio :1;
+	unsigned int		fast_mode :1;
 };
 
-#define _IBMR(i2c)	((i2c)->reg_base + 0)
-#define _IDBR(i2c)	((i2c)->reg_base + 8)
-#define _ICR(i2c)	((i2c)->reg_base + 0x10)
-#define _ISR(i2c)	((i2c)->reg_base + 0x18)
-#define _ISAR(i2c)	((i2c)->reg_base + 0x20)
+#define _IBMR(i2c)	((i2c)->reg_base + (0x0 << (i2c)->reg_shift))
+#define _IDBR(i2c)	((i2c)->reg_base + (0x4 << (i2c)->reg_shift))
+#define _ICR(i2c)	((i2c)->reg_base + (0x8 << (i2c)->reg_shift))
+#define _ISR(i2c)	((i2c)->reg_base + (0xc << (i2c)->reg_shift))
+#define _ISAR(i2c)	((i2c)->reg_base + (0x10 << (i2c)->reg_shift))
 
 /*
  * I2C Slave mode address
@@ -188,14 +227,14 @@
 
 static void i2c_pxa_abort(struct pxa_i2c *i2c)
 {
-	unsigned long timeout = jiffies + HZ/4;
+	int i = 250;
 
 	if (i2c_pxa_is_slavemode(i2c)) {
 		dev_dbg(&i2c->adap.dev, "%s: called in slave mode\n", __func__);
 		return;
 	}
 
-	while (time_before(jiffies, timeout) && (readl(_IBMR(i2c)) & 0x1) == 0) {
+	while ((i > 0) && (readl(_IBMR(i2c)) & 0x1) == 0) {
 		unsigned long icr = readl(_ICR(i2c));
 
 		icr &= ~ICR_START;
@@ -205,7 +244,8 @@
 
 		show_state(i2c);
 
-		msleep(1);
+		mdelay(1);
+		i --;
 	}
 
 	writel(readl(_ICR(i2c)) & ~(ICR_MA | ICR_START | ICR_STOP),
@@ -364,7 +404,7 @@
 	writel(i2c->slave_addr, _ISAR(i2c));
 
 	/* set control register values */
-	writel(I2C_ICR_INIT, _ICR(i2c));
+	writel(I2C_ICR_INIT | (i2c->fast_mode ? ICR_FM : 0), _ICR(i2c));
 
 #ifdef CONFIG_I2C_PXA_SLAVE
 	dev_info(&i2c->adap.dev, "Enabling slave mode\n");
@@ -907,12 +947,6 @@
 	struct pxa_i2c *i2c = adap->algo_data;
 	int ret, i;
 
-	/* If the I2C controller is disabled we need to reset it (probably due
- 	   to a suspend/resume destroying state). We do this here as we can then
- 	   avoid worrying about resuming the controller before its users. */
-	if (!(readl(_ICR(i2c)) & ICR_IUE))
-		i2c_pxa_reset(i2c);
-
 	for (i = adap->retries; i >= 0; i--) {
 		ret = i2c_pxa_do_xfer(i2c, msgs, num);
 		if (ret != I2C_RETRY)
@@ -993,6 +1027,7 @@
 		ret = -EIO;
 		goto eremap;
 	}
+	i2c->reg_shift = (cpu_is_pxa3xx() && (dev->id == 1)) ? 0 : 1;
 
 	i2c->iobase = res->start;
 	i2c->iosize = res_len(res);
@@ -1013,6 +1048,7 @@
 	if (plat) {
 		i2c->adap.class = plat->class;
 		i2c->use_pio = plat->use_pio;
+		i2c->fast_mode = plat->fast_mode;
 	}
 
 	if (i2c->use_pio) {
@@ -1082,9 +1118,33 @@
 	return 0;
 }
 
+#ifdef CONFIG_PM
+static int i2c_pxa_suspend_late(struct platform_device *dev, pm_message_t state)
+{
+	struct pxa_i2c *i2c = platform_get_drvdata(dev);
+	clk_disable(i2c->clk);
+	return 0;
+}
+
+static int i2c_pxa_resume_early(struct platform_device *dev)
+{
+	struct pxa_i2c *i2c = platform_get_drvdata(dev);
+
+	clk_enable(i2c->clk);
+	i2c_pxa_reset(i2c);
+
+	return 0;
+}
+#else
+#define i2c_pxa_suspend_late NULL
+#define i2c_pxa_resume_early NULL
+#endif
+
 static struct platform_driver i2c_pxa_driver = {
 	.probe		= i2c_pxa_probe,
 	.remove		= __exit_p(i2c_pxa_remove),
+	.suspend_late	= i2c_pxa_suspend_late,
+	.resume_early	= i2c_pxa_resume_early,
 	.driver		= {
 		.name	= "pxa2xx-i2c",
 		.owner	= THIS_MODULE,
diff --git a/drivers/i2c/busses/i2c-viapro.c b/drivers/i2c/busses/i2c-viapro.c
index 862eb35..73dc52e 100644
--- a/drivers/i2c/busses/i2c-viapro.c
+++ b/drivers/i2c/busses/i2c-viapro.c
@@ -36,6 +36,7 @@
    VT8237S            0x3372             yes
    VT8251             0x3287             yes
    CX700              0x8324             yes
+   VX800/VX820        0x8353             yes
 
    Note: we assume there can only be one device, with one SMBus interface.
 */
@@ -82,6 +83,7 @@
 #define VT596_BYTE		0x04
 #define VT596_BYTE_DATA		0x08
 #define VT596_WORD_DATA		0x0C
+#define VT596_PROC_CALL		0x10
 #define VT596_BLOCK_DATA	0x14
 #define VT596_I2C_BLOCK_DATA	0x34
 
@@ -232,6 +234,12 @@
 		}
 		size = VT596_WORD_DATA;
 		break;
+	case I2C_SMBUS_PROC_CALL:
+		outb_p(command, SMBHSTCMD);
+		outb_p(data->word & 0xff, SMBHSTDAT0);
+		outb_p((data->word & 0xff00) >> 8, SMBHSTDAT1);
+		size = VT596_PROC_CALL;
+		break;
 	case I2C_SMBUS_I2C_BLOCK_DATA:
 		if (!(vt596_features & FEATURE_I2CBLOCK))
 			goto exit_unsupported;
@@ -262,6 +270,9 @@
 	if (status)
 		return status;
 
+	if (size == VT596_PROC_CALL)
+		read_write = I2C_SMBUS_READ;
+
 	if ((read_write == I2C_SMBUS_WRITE) || (size == VT596_QUICK))
 		return 0;
 
@@ -271,6 +282,7 @@
 		data->byte = inb_p(SMBHSTDAT0);
 		break;
 	case VT596_WORD_DATA:
+	case VT596_PROC_CALL:
 		data->word = inb_p(SMBHSTDAT0) + (inb_p(SMBHSTDAT1) << 8);
 		break;
 	case VT596_I2C_BLOCK_DATA:
@@ -295,7 +307,7 @@
 {
 	u32 func = I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
 	    I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
-	    I2C_FUNC_SMBUS_BLOCK_DATA;
+	    I2C_SMBUS_PROC_CALL | I2C_FUNC_SMBUS_BLOCK_DATA;
 
 	if (vt596_features & FEATURE_I2CBLOCK)
 		func |= I2C_FUNC_SMBUS_I2C_BLOCK;
@@ -396,6 +408,7 @@
 
 	switch (pdev->device) {
 	case PCI_DEVICE_ID_VIA_CX700:
+	case PCI_DEVICE_ID_VIA_VX800:
 	case PCI_DEVICE_ID_VIA_8251:
 	case PCI_DEVICE_ID_VIA_8237:
 	case PCI_DEVICE_ID_VIA_8237A:
@@ -459,6 +472,8 @@
 	  .driver_data = SMBBA3 },
 	{ PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_CX700),
 	  .driver_data = SMBBA3 },
+	{ PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VX800),
+	  .driver_data = SMBBA3 },
 	{ 0, }
 };
 
diff --git a/drivers/i2c/chips/isp1301_omap.c b/drivers/i2c/chips/isp1301_omap.c
index 4655b79..28902eb 100644
--- a/drivers/i2c/chips/isp1301_omap.c
+++ b/drivers/i2c/chips/isp1301_omap.c
@@ -49,10 +49,9 @@
 
 struct isp1301 {
 	struct otg_transceiver	otg;
-	struct i2c_client	client;
+	struct i2c_client	*client;
 	void			(*i2c_release)(struct device *dev);
 
-	int			irq;
 	int			irq_type;
 
 	u32			last_otg_ctrl;
@@ -138,14 +137,6 @@
 
 /*-------------------------------------------------------------------------*/
 
-/* only two addresses possible */
-#define	ISP_BASE		0x2c
-static unsigned short normal_i2c[] = {
-	ISP_BASE, ISP_BASE + 1,
-	I2C_CLIENT_END };
-
-I2C_CLIENT_INSMOD;
-
 static struct i2c_driver isp1301_driver;
 
 /* smbus apis are used for portability */
@@ -153,25 +144,25 @@
 static inline u8
 isp1301_get_u8(struct isp1301 *isp, u8 reg)
 {
-	return i2c_smbus_read_byte_data(&isp->client, reg + 0);
+	return i2c_smbus_read_byte_data(isp->client, reg + 0);
 }
 
 static inline int
 isp1301_get_u16(struct isp1301 *isp, u8 reg)
 {
-	return i2c_smbus_read_word_data(&isp->client, reg);
+	return i2c_smbus_read_word_data(isp->client, reg);
 }
 
 static inline int
 isp1301_set_bits(struct isp1301 *isp, u8 reg, u8 bits)
 {
-	return i2c_smbus_write_byte_data(&isp->client, reg + 0, bits);
+	return i2c_smbus_write_byte_data(isp->client, reg + 0, bits);
 }
 
 static inline int
 isp1301_clear_bits(struct isp1301 *isp, u8 reg, u8 bits)
 {
-	return i2c_smbus_write_byte_data(&isp->client, reg + 1, bits);
+	return i2c_smbus_write_byte_data(isp->client, reg + 1, bits);
 }
 
 /*-------------------------------------------------------------------------*/
@@ -349,10 +340,10 @@
 	int status;
 
 	if (isp && !test_and_set_bit(work, &isp->todo)) {
-		(void) get_device(&isp->client.dev);
+		(void) get_device(&isp->client->dev);
 		status = schedule_work(&isp->work);
 		if (!status && !isp->working)
-			dev_vdbg(&isp->client.dev,
+			dev_vdbg(&isp->client->dev,
 				"work item %d may be lost\n", work);
 	}
 }
@@ -1135,7 +1126,7 @@
 		/* transfer state from otg engine to isp1301 */
 		if (test_and_clear_bit(WORK_UPDATE_ISP, &isp->todo)) {
 			otg_update_isp(isp);
-			put_device(&isp->client.dev);
+			put_device(&isp->client->dev);
 		}
 #endif
 		/* transfer state from isp1301 to otg engine */
@@ -1143,7 +1134,7 @@
 			u8		stat = isp1301_clear_latch(isp);
 
 			isp_update_otg(isp, stat);
-			put_device(&isp->client.dev);
+			put_device(&isp->client->dev);
 		}
 
 		if (test_and_clear_bit(WORK_HOST_RESUME, &isp->todo)) {
@@ -1178,7 +1169,7 @@
 			}
 			host_resume(isp);
 			// mdelay(10);
-			put_device(&isp->client.dev);
+			put_device(&isp->client->dev);
 		}
 
 		if (test_and_clear_bit(WORK_TIMER, &isp->todo)) {
@@ -1187,15 +1178,15 @@
 			if (!stop)
 				mod_timer(&isp->timer, jiffies + TIMER_JIFFIES);
 #endif
-			put_device(&isp->client.dev);
+			put_device(&isp->client->dev);
 		}
 
 		if (isp->todo)
-			dev_vdbg(&isp->client.dev,
+			dev_vdbg(&isp->client->dev,
 				"work done, todo = 0x%lx\n",
 				isp->todo);
 		if (stop) {
-			dev_dbg(&isp->client.dev, "stop\n");
+			dev_dbg(&isp->client->dev, "stop\n");
 			break;
 		}
 	} while (isp->todo);
@@ -1219,7 +1210,7 @@
 {
 	struct isp1301	*isp;
 
-	isp = container_of(dev, struct isp1301, client.dev);
+	isp = dev_get_drvdata(dev);
 
 	/* ugly -- i2c hijacks our memory hook to wait_for_completion() */
 	if (isp->i2c_release)
@@ -1229,15 +1220,15 @@
 
 static struct isp1301 *the_transceiver;
 
-static int isp1301_detach_client(struct i2c_client *i2c)
+static int __exit isp1301_remove(struct i2c_client *i2c)
 {
 	struct isp1301	*isp;
 
-	isp = container_of(i2c, struct isp1301, client);
+	isp = i2c_get_clientdata(i2c);
 
 	isp1301_clear_bits(isp, ISP1301_INTERRUPT_FALLING, ~0);
 	isp1301_clear_bits(isp, ISP1301_INTERRUPT_RISING, ~0);
-	free_irq(isp->irq, isp);
+	free_irq(i2c->irq, isp);
 #ifdef	CONFIG_USB_OTG
 	otg_unbind(isp);
 #endif
@@ -1252,7 +1243,7 @@
 	put_device(&i2c->dev);
 	the_transceiver = 0;
 
-	return i2c_detach_client(i2c);
+	return 0;
 }
 
 /*-------------------------------------------------------------------------*/
@@ -1285,7 +1276,7 @@
 	isp1301_set_bits(isp, ISP1301_INTERRUPT_FALLING,
 		INTR_VBUS_VLD | INTR_SESS_VLD | INTR_ID_GND);
 
-	dev_info(&isp->client.dev, "ready for dual-role USB ...\n");
+	dev_info(&isp->client->dev, "ready for dual-role USB ...\n");
 
 	return 0;
 }
@@ -1310,7 +1301,7 @@
 
 #ifdef	CONFIG_USB_OTG
 	isp->otg.host = host;
-	dev_dbg(&isp->client.dev, "registered host\n");
+	dev_dbg(&isp->client->dev, "registered host\n");
 	host_suspend(isp);
 	if (isp->otg.gadget)
 		return isp1301_otg_enable(isp);
@@ -1325,7 +1316,7 @@
 	if (machine_is_omap_h2())
 		isp1301_set_bits(isp, ISP1301_MODE_CONTROL_1, MC1_DAT_SE0);
 
-	dev_info(&isp->client.dev, "A-Host sessions ok\n");
+	dev_info(&isp->client->dev, "A-Host sessions ok\n");
 	isp1301_set_bits(isp, ISP1301_INTERRUPT_RISING,
 		INTR_ID_GND);
 	isp1301_set_bits(isp, ISP1301_INTERRUPT_FALLING,
@@ -1343,7 +1334,7 @@
 	return 0;
 
 #else
-	dev_dbg(&isp->client.dev, "host sessions not allowed\n");
+	dev_dbg(&isp->client->dev, "host sessions not allowed\n");
 	return -EINVAL;
 #endif
 
@@ -1370,7 +1361,7 @@
 
 #ifdef	CONFIG_USB_OTG
 	isp->otg.gadget = gadget;
-	dev_dbg(&isp->client.dev, "registered gadget\n");
+	dev_dbg(&isp->client->dev, "registered gadget\n");
 	/* gadget driver may be suspended until vbus_connect () */
 	if (isp->otg.host)
 		return isp1301_otg_enable(isp);
@@ -1395,7 +1386,7 @@
 		INTR_SESS_VLD);
 	isp1301_set_bits(isp, ISP1301_INTERRUPT_FALLING,
 		INTR_VBUS_VLD);
-	dev_info(&isp->client.dev, "B-Peripheral sessions ok\n");
+	dev_info(&isp->client->dev, "B-Peripheral sessions ok\n");
 	dump_regs(isp, __func__);
 
 	/* If this has a Mini-AB connector, this mode is highly
@@ -1408,7 +1399,7 @@
 	return 0;
 
 #else
-	dev_dbg(&isp->client.dev, "peripheral sessions not allowed\n");
+	dev_dbg(&isp->client->dev, "peripheral sessions not allowed\n");
 	return -EINVAL;
 #endif
 }
@@ -1508,12 +1499,10 @@
 
 /*-------------------------------------------------------------------------*/
 
-/* no error returns, they'd just make bus scanning stop */
-static int isp1301_probe(struct i2c_adapter *bus, int address, int kind)
+static int __init isp1301_probe(struct i2c_client *i2c)
 {
 	int			status;
 	struct isp1301		*isp;
-	struct i2c_client	*i2c;
 
 	if (the_transceiver)
 		return 0;
@@ -1527,37 +1516,19 @@
 	isp->timer.function = isp1301_timer;
 	isp->timer.data = (unsigned long) isp;
 
-	isp->irq = -1;
-	isp->client.addr = address;
-	i2c_set_clientdata(&isp->client, isp);
-	isp->client.adapter = bus;
-	isp->client.driver = &isp1301_driver;
-	strlcpy(isp->client.name, DRIVER_NAME, I2C_NAME_SIZE);
-	i2c = &isp->client;
+	i2c_set_clientdata(i2c, isp);
+	isp->client = i2c;
 
-	/* if this is a true probe, verify the chip ... */
-	if (kind < 0) {
-		status = isp1301_get_u16(isp, ISP1301_VENDOR_ID);
-		if (status != I2C_VENDOR_ID_PHILIPS) {
-			dev_dbg(&bus->dev, "addr %d not philips id: %d\n",
-				address, status);
-			goto fail1;
-		}
-		status = isp1301_get_u16(isp, ISP1301_PRODUCT_ID);
-		if (status != I2C_PRODUCT_ID_PHILIPS_1301) {
-			dev_dbg(&bus->dev, "%d not isp1301, %d\n",
-				address, status);
-			goto fail1;
-		}
+	/* verify the chip (shouldn't be necesary) */
+	status = isp1301_get_u16(isp, ISP1301_VENDOR_ID);
+	if (status != I2C_VENDOR_ID_PHILIPS) {
+		dev_dbg(&i2c->dev, "not philips id: %d\n", status);
+		goto fail;
 	}
-
-	status = i2c_attach_client(i2c);
-	if (status < 0) {
-		dev_dbg(&bus->dev, "can't attach %s to device %d, err %d\n",
-				DRIVER_NAME, address, status);
-fail1:
-		kfree(isp);
-		return 0;
+	status = isp1301_get_u16(isp, ISP1301_PRODUCT_ID);
+	if (status != I2C_PRODUCT_ID_PHILIPS_1301) {
+		dev_dbg(&i2c->dev, "not isp1301, %d\n", status);
+		goto fail;
 	}
 	isp->i2c_release = i2c->dev.release;
 	i2c->dev.release = isp1301_release;
@@ -1586,7 +1557,7 @@
 	status = otg_bind(isp);
 	if (status < 0) {
 		dev_dbg(&i2c->dev, "can't bind OTG\n");
-		goto fail2;
+		goto fail;
 	}
 #endif
 
@@ -1599,26 +1570,21 @@
 
 		/* IRQ wired at M14 */
 		omap_cfg_reg(M14_1510_GPIO2);
-		isp->irq = OMAP_GPIO_IRQ(2);
 		if (gpio_request(2, "isp1301") == 0)
 			gpio_direction_input(2);
 		isp->irq_type = IRQF_TRIGGER_FALLING;
 	}
 
 	isp->irq_type |= IRQF_SAMPLE_RANDOM;
-	status = request_irq(isp->irq, isp1301_irq,
+	status = request_irq(i2c->irq, isp1301_irq,
 			isp->irq_type, DRIVER_NAME, isp);
 	if (status < 0) {
 		dev_dbg(&i2c->dev, "can't get IRQ %d, err %d\n",
-				isp->irq, status);
-#ifdef	CONFIG_USB_OTG
-fail2:
-#endif
-		i2c_detach_client(i2c);
-		goto fail1;
+				i2c->irq, status);
+		goto fail;
 	}
 
-	isp->otg.dev = &isp->client.dev;
+	isp->otg.dev = &i2c->dev;
 	isp->otg.label = DRIVER_NAME;
 
 	isp->otg.set_host = isp1301_set_host,
@@ -1649,22 +1615,25 @@
 			status);
 
 	return 0;
+
+fail:
+	kfree(isp);
+	return -ENODEV;
 }
 
-static int isp1301_scan_bus(struct i2c_adapter *bus)
-{
-	if (!i2c_check_functionality(bus, I2C_FUNC_SMBUS_BYTE_DATA
-			| I2C_FUNC_SMBUS_READ_WORD_DATA))
-		return -EINVAL;
-	return i2c_probe(bus, &addr_data, isp1301_probe);
-}
+static const struct i2c_device_id isp1301_id[] = {
+	{ "isp1301_omap", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, isp1301_id);
 
 static struct i2c_driver isp1301_driver = {
 	.driver = {
 		.name	= "isp1301_omap",
 	},
-	.attach_adapter	= isp1301_scan_bus,
-	.detach_client	= isp1301_detach_client,
+	.probe		= isp1301_probe,
+	.remove		= __exit_p(isp1301_remove),
+	.id_table	= isp1301_id,
 };
 
 /*-------------------------------------------------------------------------*/
diff --git a/drivers/i2c/chips/tps65010.c b/drivers/i2c/chips/tps65010.c
index cf02e8f..acf8b9d 100644
--- a/drivers/i2c/chips/tps65010.c
+++ b/drivers/i2c/chips/tps65010.c
@@ -456,14 +456,17 @@
 
 /* offsets 0..3 == GPIO1..GPIO4
  * offsets 4..5 == LED1/nPG, LED2 (we set one of the non-BLINK modes)
+ * offset 6 == vibrator motor driver
  */
 static void
 tps65010_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
 {
 	if (offset < 4)
 		tps65010_set_gpio_out_value(offset + 1, value);
-	else
+	else if (offset < 6)
 		tps65010_set_led(offset - 3, value ? ON : OFF);
+	else
+		tps65010_set_vib(value);
 }
 
 static int
@@ -477,8 +480,10 @@
 		if (!(tps->outmask & (1 << offset)))
 			return -EINVAL;
 		tps65010_set_gpio_out_value(offset + 1, value);
-	} else
+	} else if (offset < 6)
 		tps65010_set_led(offset - 3, value ? ON : OFF);
+	else
+		tps65010_set_vib(value);
 
 	return 0;
 }
@@ -646,7 +651,7 @@
 		tps->chip.get = tps65010_gpio_get;
 
 		tps->chip.base = board->base;
-		tps->chip.ngpio = 6;
+		tps->chip.ngpio = 7;
 		tps->chip.can_sleep = 1;
 
 		status = gpiochip_add(&tps->chip);
@@ -675,6 +680,7 @@
 	{ "tps65011", TPS65011 },
 	{ "tps65012", TPS65012 },
 	{ "tps65013", TPS65013 },
+	{ "tps65014", TPS65011 },	/* tps65011 charging at 6.5V max */
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, tps65010_id);
diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
index b346a68..42e852d 100644
--- a/drivers/i2c/i2c-core.c
+++ b/drivers/i2c/i2c-core.c
@@ -437,6 +437,10 @@
 {
 	int res = 0, dummy;
 
+	/* Can't register until after driver model init */
+	if (unlikely(WARN_ON(!i2c_bus_type.p)))
+		return -EAGAIN;
+
 	mutex_init(&adap->bus_lock);
 	mutex_init(&adap->clist_lock);
 	INIT_LIST_HEAD(&adap->clients);
@@ -696,6 +700,10 @@
 {
 	int res;
 
+	/* Can't register until after driver model init */
+	if (unlikely(WARN_ON(!i2c_bus_type.p)))
+		return -EAGAIN;
+
 	/* new style driver methods can't mix with legacy ones */
 	if (is_newstyle_driver(driver)) {
 		if (driver->attach_adapter || driver->detach_adapter
@@ -978,7 +986,10 @@
 	bus_unregister(&i2c_bus_type);
 }
 
-subsys_initcall(i2c_init);
+/* We must initialize early, because some subsystems register i2c drivers
+ * in subsys_initcall() code, but are linked (and initialized) before i2c.
+ */
+postcore_initcall(i2c_init);
 module_exit(i2c_exit);
 
 /* ----------------------------------------------------
@@ -1677,6 +1688,28 @@
 EXPORT_SYMBOL(i2c_smbus_write_word_data);
 
 /**
+ * i2c_smbus_process_call - SMBus "process call" protocol
+ * @client: Handle to slave device
+ * @command: Byte interpreted by slave
+ * @value: 16-bit "word" being written
+ *
+ * This executes the SMBus "process call" protocol, returning negative errno
+ * else a 16-bit unsigned "word" received from the device.
+ */
+s32 i2c_smbus_process_call(struct i2c_client *client, u8 command, u16 value)
+{
+	union i2c_smbus_data data;
+	int status;
+	data.word = value;
+
+	status = i2c_smbus_xfer(client->adapter, client->addr, client->flags,
+				I2C_SMBUS_WRITE, command,
+				I2C_SMBUS_PROC_CALL, &data);
+	return (status < 0) ? status : data.word;
+}
+EXPORT_SYMBOL(i2c_smbus_process_call);
+
+/**
  * i2c_smbus_read_block_data - SMBus "block read" protocol
  * @client: Handle to slave device
  * @command: Byte interpreted by slave
diff --git a/drivers/i2c/i2c-dev.c b/drivers/i2c/i2c-dev.c
index af4491f..307d976 100644
--- a/drivers/i2c/i2c-dev.c
+++ b/drivers/i2c/i2c-dev.c
@@ -583,8 +583,10 @@
 		goto out;
 
 	i2c_dev_class = class_create(THIS_MODULE, "i2c-dev");
-	if (IS_ERR(i2c_dev_class))
+	if (IS_ERR(i2c_dev_class)) {
+		res = PTR_ERR(i2c_dev_class);
 		goto out_unreg_chrdev;
+	}
 
 	res = i2c_add_driver(&i2cdev_driver);
 	if (res)
diff --git a/drivers/ide/Kconfig b/drivers/ide/Kconfig
index fc735ab..6c6dd2f 100644
--- a/drivers/ide/Kconfig
+++ b/drivers/ide/Kconfig
@@ -54,38 +54,6 @@
 
 if IDE
 
-config BLK_DEV_IDE
-	tristate "Enhanced IDE/MFM/RLL disk/cdrom/tape/floppy support"
-	---help---
-	  If you say Y here, you will use the full-featured IDE driver to
-	  control up to ten ATA/IDE interfaces, each being able to serve a
-	  "master" and a "slave" device, for a total of up to twenty ATA/IDE
-	  disk/cdrom/tape/floppy drives.
-
-	  Useful information about large (>540 MB) IDE disks, multiple
-	  interfaces, what to do if ATA/IDE devices are not automatically
-	  detected, sound card ATA/IDE ports, module support, and other
-	  topics, is contained in <file:Documentation/ide/ide.txt>. For detailed
-	  information about hard drives, consult the Disk-HOWTO and the
-	  Multi-Disk-HOWTO, available from
-	  <http://www.tldp.org/docs.html#howto>.
-
-	  To fine-tune ATA/IDE drive/interface parameters for improved
-	  performance, look for the hdparm package at
-	  <ftp://ibiblio.org/pub/Linux/system/hardware/>.
-
-	  To compile this driver as a module, choose M here and read
-	  <file:Documentation/ide/ide.txt>. The module will be called ide-mod.
-	  Do not compile this driver as a module if your root file system (the
-	  one containing the directory /) is located on an IDE device.
-
-	  If you have one or more IDE drives, say Y or M here. If your system
-	  has no IDE drives, or if memory requirements are really tight, you
-	  could say N here, and select the "Old hard disk driver" below
-	  instead to save about 13 KB of memory in the kernel.
-
-if BLK_DEV_IDE
-
 comment "Please see Documentation/ide/ide.txt for help/info on IDE drives"
 
 config IDE_TIMINGS
@@ -131,29 +99,6 @@
 
 	  If unsure, say Y.
 
-config IDEDISK_MULTI_MODE
-	bool "Use multiple sector mode for Programmed Input/Output by default"
-	help
-	  This setting is irrelevant for most IDE disks, with direct memory
-	  access, to which multiple sector mode does not apply. Multiple sector
-	  mode is a feature of most modern IDE hard drives, permitting the
-	  transfer of multiple sectors per Programmed Input/Output interrupt,
-	  rather than the usual one sector per interrupt. When this feature is
-	  enabled, it can reduce operating system overhead for disk Programmed
-	  Input/Output. On some systems, it also can increase the data
-	  throughput of Programmed Input/Output. Some drives, however, seemed
-	  to run slower with multiple sector mode enabled. Some drives claimed
-	  to support multiple sector mode, but lost data at some settings.
-	  Under rare circumstances, such failures could result in massive
-	  filesystem corruption.
-
-	  If you get the following error, try to say Y here:
-
-	  hda: set_multmode: status=0x51 { DriveReady SeekComplete Error }
-	  hda: set_multmode: error=0x04 { DriveStatusError }
-
-	  If in doubt, say N.
-
 config BLK_DEV_IDECS
 	tristate "PCMCIA IDE support"
 	depends on PCMCIA
@@ -292,6 +237,20 @@
 	tristate "generic/default IDE chipset support"
 	depends on ALPHA || X86 || IA64 || M32R || MIPS
 	help
+	  This is the generic IDE driver.  This driver attaches to the
+	  fixed legacy ports (e.g. on PCs 0x1f0/0x170, 0x1e8/0x168 and
+	  so on).  Please note that if this driver is built into the
+	  kernel or loaded before other ATA (IDE or libata) drivers
+	  and the controller is located at legacy ports, this driver
+	  may grab those ports and thus can prevent the controller
+	  specific driver from attaching.
+
+	  Also, currently, IDE generic doesn't allow IRQ sharing
+	  meaning that the IRQs it grabs won't be available to other
+	  controllers sharing those IRQs which usually makes drivers
+	  for those controllers fail.  Generally, it's not a good idea
+	  to load IDE generic driver on modern systems.
+
 	  If unsure, say N.
 
 config BLK_DEV_PLATFORM
@@ -357,7 +316,7 @@
 
 config IDEPCI_PCIBUS_ORDER
 	bool "Probe IDE PCI devices in the PCI bus order (DEPRECATED)"
-	depends on BLK_DEV_IDE=y && BLK_DEV_IDEPCI
+	depends on IDE=y && BLK_DEV_IDEPCI
 	default y
 	help
 	  Probe IDE PCI devices in the order in which they appear on the
@@ -738,7 +697,7 @@
 
 config BLK_DEV_IDE_PMAC
 	tristate "PowerMac on-board IDE support"
-	depends on PPC_PMAC && IDE=y && BLK_DEV_IDE=y
+	depends on PPC_PMAC && IDE=y
 	select IDE_TIMINGS
 	help
 	  This driver provides support for the on-board IDE controller on
@@ -766,10 +725,6 @@
 	  to transfer data to and from memory.  Saying Y is safe and improves
 	  performance.
 
-config BLK_DEV_IDE_SWARM
-	tristate "IDE for Sibyte evaluation boards"
-	depends on SIBYTE_SB1xxx_SOC
-
 config BLK_DEV_IDE_AU1XXX
        bool "IDE for AMD Alchemy Au1200"
        depends on SOC_AU1200
@@ -976,6 +931,4 @@
 	def_bool BLK_DEV_IDEDMA_SFF || BLK_DEV_IDEDMA_PMAC || \
 		 BLK_DEV_IDEDMA_ICS || BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA
 
-endif
-
 endif # IDE
diff --git a/drivers/ide/Makefile b/drivers/ide/Makefile
index 64e0ecd..ceaf779 100644
--- a/drivers/ide/Makefile
+++ b/drivers/ide/Makefile
@@ -4,25 +4,26 @@
 
 EXTRA_CFLAGS				+= -Idrivers/ide
 
-ide-core-y += ide.o ide-io.o ide-iops.o ide-lib.o ide-probe.o ide-taskfile.o \
-	      ide-pio-blacklist.o
+ide-core-y += ide.o ide-ioctls.o ide-io.o ide-iops.o ide-lib.o ide-probe.o \
+	      ide-taskfile.o ide-park.o ide-pio-blacklist.o
 
 # core IDE code
 ide-core-$(CONFIG_IDE_TIMINGS)		+= ide-timings.o
 ide-core-$(CONFIG_IDE_ATAPI)		+= ide-atapi.o
 ide-core-$(CONFIG_BLK_DEV_IDEPCI)	+= setup-pci.o
 ide-core-$(CONFIG_BLK_DEV_IDEDMA)	+= ide-dma.o
+ide-core-$(CONFIG_BLK_DEV_IDEDMA_SFF)	+= ide-dma-sff.o
 ide-core-$(CONFIG_IDE_PROC_FS)		+= ide-proc.o
 ide-core-$(CONFIG_BLK_DEV_IDEACPI)	+= ide-acpi.o
 
-obj-$(CONFIG_BLK_DEV_IDE)		+= ide-core.o
+obj-$(CONFIG_IDE)			+= ide-core.o
 
 ifeq ($(CONFIG_IDE_ARM), y)
 	ide-arm-core-y += arm/ide_arm.o
 	obj-y += ide-arm-core.o
 endif
 
-obj-$(CONFIG_BLK_DEV_IDE)		+= legacy/ pci/
+obj-$(CONFIG_IDE)			+= legacy/ pci/
 
 obj-$(CONFIG_IDEPCI_PCIBUS_ORDER)	+= ide-scan-pci.o
 
@@ -31,17 +32,24 @@
 	obj-y += cmd640-core.o
 endif
 
-obj-$(CONFIG_BLK_DEV_IDE)		+= ppc/
+obj-$(CONFIG_IDE)			+= ppc/
 obj-$(CONFIG_IDE_H8300)			+= h8300/
 obj-$(CONFIG_IDE_GENERIC)		+= ide-generic.o
 obj-$(CONFIG_BLK_DEV_IDEPNP)		+= ide-pnp.o
 
+ide-disk_mod-y += ide-disk.o ide-disk_ioctl.o
 ide-cd_mod-y += ide-cd.o ide-cd_ioctl.o ide-cd_verbose.o
+ide-floppy_mod-y += ide-floppy.o ide-floppy_ioctl.o
 
-obj-$(CONFIG_BLK_DEV_IDEDISK)		+= ide-disk.o
+ifeq ($(CONFIG_IDE_PROC_FS), y)
+	ide-disk_mod-y += ide-disk_proc.o
+	ide-floppy_mod-y += ide-floppy_proc.o
+endif
+
+obj-$(CONFIG_BLK_DEV_IDEDISK)		+= ide-disk_mod.o
 obj-$(CONFIG_BLK_DEV_IDECD)		+= ide-cd_mod.o
+obj-$(CONFIG_BLK_DEV_IDEFLOPPY)		+= ide-floppy_mod.o
 obj-$(CONFIG_BLK_DEV_IDETAPE)		+= ide-tape.o
-obj-$(CONFIG_BLK_DEV_IDEFLOPPY)		+= ide-floppy.o
 
 ifeq ($(CONFIG_BLK_DEV_IDECS), y)
 	ide-cs-core-y += legacy/ide-cs.o
@@ -53,4 +61,4 @@
 	obj-y += ide-platform-core.o
 endif
 
-obj-$(CONFIG_BLK_DEV_IDE)		+= arm/ mips/
+obj-$(CONFIG_IDE)			+= arm/ mips/
diff --git a/drivers/ide/arm/icside.c b/drivers/ide/arm/icside.c
index df4af40..76bdc9a 100644
--- a/drivers/ide/arm/icside.c
+++ b/drivers/ide/arm/icside.c
@@ -10,7 +10,6 @@
 #include <linux/slab.h>
 #include <linux/blkdev.h>
 #include <linux/errno.h>
-#include <linux/hdreg.h>
 #include <linux/ide.h>
 #include <linux/dma-mapping.h>
 #include <linux/device.h>
@@ -265,8 +264,8 @@
 	 * If we're going to be doing MW_DMA_1 or MW_DMA_2, we should
 	 * take care to note the values in the ID...
 	 */
-	if (use_dma_info && drive->id->eide_dma_time > cycle_time)
-		cycle_time = drive->id->eide_dma_time;
+	if (use_dma_info && drive->id[ATA_ID_EIDE_DMA_TIME] > cycle_time)
+		cycle_time = drive->id[ATA_ID_EIDE_DMA_TIME];
 
 	drive->drive_data = cycle_time;
 
@@ -373,25 +372,6 @@
 			ICS_ARCIN_V6_INTRSTAT_1)) & 1;
 }
 
-static void icside_dma_timeout(ide_drive_t *drive)
-{
-	ide_hwif_t *hwif = drive->hwif;
-
-	printk(KERN_ERR "%s: DMA timeout occurred: ", drive->name);
-
-	if (icside_dma_test_irq(drive))
-		return;
-
-	ide_dump_status(drive, "DMA timeout", hwif->tp_ops->read_status(hwif));
-
-	icside_dma_end(drive);
-}
-
-static void icside_dma_lost_irq(ide_drive_t *drive)
-{
-	printk(KERN_ERR "%s: IRQ lost\n", drive->name);
-}
-
 static int icside_dma_init(ide_hwif_t *hwif, const struct ide_port_info *d)
 {
 	hwif->dmatable_cpu	= NULL;
@@ -407,8 +387,8 @@
 	.dma_start		= icside_dma_start,
 	.dma_end		= icside_dma_end,
 	.dma_test_irq		= icside_dma_test_irq,
-	.dma_timeout		= icside_dma_timeout,
-	.dma_lost_irq		= icside_dma_lost_irq,
+	.dma_timeout		= ide_dma_timeout,
+	.dma_lost_irq		= ide_dma_lost_irq,
 };
 #else
 #define icside_v6_dma_ops NULL
diff --git a/drivers/ide/arm/palm_bk3710.c b/drivers/ide/arm/palm_bk3710.c
index 4fd91dc..122ed3c 100644
--- a/drivers/ide/arm/palm_bk3710.c
+++ b/drivers/ide/arm/palm_bk3710.c
@@ -27,7 +27,6 @@
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/ioport.h>
-#include <linux/hdreg.h>
 #include <linux/ide.h>
 #include <linux/delay.h>
 #include <linux/init.h>
@@ -180,7 +179,7 @@
 	val32 |= (t2i << (dev ? 8 : 0));
 	writel(val32, base + BK3710_DATRCVR);
 
-	if (mate && mate->present) {
+	if (mate) {
 		u8 mode2 = ide_get_best_pio_mode(mate, 255, 4);
 
 		if (mode2 < mode)
@@ -213,7 +212,8 @@
 		palm_bk3710_setudmamode(base, is_slave,
 					xferspeed - XFER_UDMA_0);
 	} else {
-		palm_bk3710_setdmamode(base, is_slave, drive->id->eide_dma_min,
+		palm_bk3710_setdmamode(base, is_slave,
+				       drive->id[ATA_ID_EIDE_DMA_MIN],
 				       xferspeed);
 	}
 }
@@ -229,7 +229,7 @@
 	 * Obtain the drive PIO data for tuning the Palm Chip registers
 	 */
 	cycle_time = ide_pio_cycle_time(drive, pio);
-	mate = ide_get_paired_drive(drive);
+	mate = ide_get_pair_dev(drive);
 	palm_bk3710_setpiomode(base, mate, is_slave, cycle_time, pio);
 }
 
diff --git a/drivers/ide/h8300/ide-h8300.c b/drivers/ide/h8300/ide-h8300.c
index bde7a58..e2cdd2e 100644
--- a/drivers/ide/h8300/ide-h8300.c
+++ b/drivers/ide/h8300/ide-h8300.c
@@ -80,7 +80,7 @@
 		outb(tf->lbah, io_ports->lbah_addr);
 
 	if (task->tf_flags & IDE_TFLAG_OUT_DEVICE)
-		outb((tf->device & HIHI) | drive->select.all,
+		outb((tf->device & HIHI) | drive->select,
 		     io_ports->device_addr);
 }
 
diff --git a/drivers/ide/ide-acpi.c b/drivers/ide/ide-acpi.c
index 6f70462..244a8a0 100644
--- a/drivers/ide/ide-acpi.c
+++ b/drivers/ide/ide-acpi.c
@@ -290,7 +290,7 @@
 	DEBPRINT("ENTER: %s at %s, port#: %d, hard_port#: %d\n",
 		 hwif->name, dev->bus_id, port, hwif->channel);
 
-	if (!drive->present) {
+	if ((drive->dev_flags & IDE_DFLAG_PRESENT) == 0) {
 		DEBPRINT("%s drive %d:%d not present\n",
 			 hwif->name, hwif->channel, port);
 		goto out;
@@ -420,8 +420,9 @@
 
 	DEBPRINT("ENTER: %s, hard_port#: %d\n", drive->name, drive->dn);
 
-	if (!drive->present)
+	if ((drive->dev_flags & IDE_DFLAG_PRESENT) == 0)
 		goto out;
+
 	if (!gtf_count)		/* shouldn't be here */
 		goto out;
 
@@ -584,7 +585,7 @@
  * This function executes the _STM ACPI method for the target channel.
  *
  * _STM requires Identify Drive data, which has to passed as an argument.
- * Unfortunately hd_driveid is a mangled version which we can't readily
+ * Unfortunately drive->id is a mangled version which we can't readily
  * use; hence we'll get the information afresh.
  */
 void ide_acpi_push_timing(ide_hwif_t *hwif)
@@ -614,10 +615,10 @@
 	in_params[0].buffer.length = sizeof(struct GTM_buffer);
 	in_params[0].buffer.pointer = (u8 *)&hwif->acpidata->gtm;
 	in_params[1].type = ACPI_TYPE_BUFFER;
-	in_params[1].buffer.length = sizeof(struct hd_driveid);
+	in_params[1].buffer.length = sizeof(ATA_ID_WORDS * 2);
 	in_params[1].buffer.pointer = (u8 *)&master->idbuff;
 	in_params[2].type = ACPI_TYPE_BUFFER;
-	in_params[2].buffer.length = sizeof(struct hd_driveid);
+	in_params[2].buffer.length = sizeof(ATA_ID_WORDS * 2);
 	in_params[2].buffer.pointer = (u8 *)&slave->idbuff;
 	/* Output buffer: _STM has no output */
 
@@ -660,7 +661,8 @@
 		if (!drive->acpidata->obj_handle)
 			drive->acpidata->obj_handle = ide_acpi_drive_get_handle(drive);
 
-		if (drive->acpidata->obj_handle && drive->present) {
+		if (drive->acpidata->obj_handle &&
+		    (drive->dev_flags & IDE_DFLAG_PRESENT)) {
 			acpi_bus_set_power(drive->acpidata->obj_handle,
 				on? ACPI_STATE_D0: ACPI_STATE_D3);
 		}
@@ -720,7 +722,7 @@
 
 		memset(drive->acpidata, 0, sizeof(*drive->acpidata));
 
-		if (!drive->present)
+		if ((drive->dev_flags & IDE_DFLAG_PRESENT) == 0)
 			continue;
 
 		err = taskfile_lib_get_identify(drive, drive->acpidata->idbuff);
@@ -745,7 +747,7 @@
 	for (i = 0; i < MAX_DRIVES; i++) {
 		drive = &hwif->drives[i];
 
-		if (drive->present)
+		if (drive->dev_flags & IDE_DFLAG_PRESENT)
 			/* Execute ACPI startup code */
 			ide_acpi_exec_tfs(drive);
 	}
diff --git a/drivers/ide/ide-atapi.c b/drivers/ide/ide-atapi.c
index adf04f9..2e30571 100644
--- a/drivers/ide/ide-atapi.c
+++ b/drivers/ide/ide-atapi.c
@@ -14,25 +14,268 @@
 #define debug_log(fmt, args...) do {} while (0)
 #endif
 
-/* TODO: unify the code thus making some arguments go away */
-ide_startstop_t ide_pc_intr(ide_drive_t *drive, struct ide_atapi_pc *pc,
-	ide_handler_t *handler, unsigned int timeout, ide_expiry_t *expiry,
-	void (*update_buffers)(ide_drive_t *, struct ide_atapi_pc *),
-	void (*retry_pc)(ide_drive_t *), void (*dsc_handle)(ide_drive_t *),
-	void (*io_buffers)(ide_drive_t *, struct ide_atapi_pc *, unsigned, int))
+/*
+ * Check whether we can support a device,
+ * based on the ATAPI IDENTIFY command results.
+ */
+int ide_check_atapi_device(ide_drive_t *drive, const char *s)
 {
+	u16 *id = drive->id;
+	u8 gcw[2], protocol, device_type, removable, drq_type, packet_size;
+
+	*((u16 *)&gcw) = id[ATA_ID_CONFIG];
+
+	protocol    = (gcw[1] & 0xC0) >> 6;
+	device_type =  gcw[1] & 0x1F;
+	removable   = (gcw[0] & 0x80) >> 7;
+	drq_type    = (gcw[0] & 0x60) >> 5;
+	packet_size =  gcw[0] & 0x03;
+
+#ifdef CONFIG_PPC
+	/* kludge for Apple PowerBook internal zip */
+	if (drive->media == ide_floppy && device_type == 5 &&
+	    !strstr((char *)&id[ATA_ID_PROD], "CD-ROM") &&
+	    strstr((char *)&id[ATA_ID_PROD], "ZIP"))
+		device_type = 0;
+#endif
+
+	if (protocol != 2)
+		printk(KERN_ERR "%s: %s: protocol (0x%02x) is not ATAPI\n",
+			s, drive->name, protocol);
+	else if ((drive->media == ide_floppy && device_type != 0) ||
+		 (drive->media == ide_tape && device_type != 1))
+		printk(KERN_ERR "%s: %s: invalid device type (0x%02x)\n",
+			s, drive->name, device_type);
+	else if (removable == 0)
+		printk(KERN_ERR "%s: %s: the removable flag is not set\n",
+			s, drive->name);
+	else if (drive->media == ide_floppy && drq_type == 3)
+		printk(KERN_ERR "%s: %s: sorry, DRQ type (0x%02x) not "
+			"supported\n", s, drive->name, drq_type);
+	else if (packet_size != 0)
+		printk(KERN_ERR "%s: %s: packet size (0x%02x) is not 12 "
+			"bytes\n", s, drive->name, packet_size);
+	else
+		return 1;
+	return 0;
+}
+EXPORT_SYMBOL_GPL(ide_check_atapi_device);
+
+/* PIO data transfer routine using the scatter gather table. */
+int ide_io_buffers(ide_drive_t *drive, struct ide_atapi_pc *pc,
+		    unsigned int bcount, int write)
+{
+	ide_hwif_t *hwif = drive->hwif;
+	const struct ide_tp_ops *tp_ops = hwif->tp_ops;
+	xfer_func_t *xf = write ? tp_ops->output_data : tp_ops->input_data;
+	struct scatterlist *sg = pc->sg;
+	char *buf;
+	int count, done = 0;
+
+	while (bcount) {
+		count = min(sg->length - pc->b_count, bcount);
+
+		if (PageHighMem(sg_page(sg))) {
+			unsigned long flags;
+
+			local_irq_save(flags);
+			buf = kmap_atomic(sg_page(sg), KM_IRQ0) + sg->offset;
+			xf(drive, NULL, buf + pc->b_count, count);
+			kunmap_atomic(buf - sg->offset, KM_IRQ0);
+			local_irq_restore(flags);
+		} else {
+			buf = sg_virt(sg);
+			xf(drive, NULL, buf + pc->b_count, count);
+		}
+
+		bcount -= count;
+		pc->b_count += count;
+		done += count;
+
+		if (pc->b_count == sg->length) {
+			if (!--pc->sg_cnt)
+				break;
+			pc->sg = sg = sg_next(sg);
+			pc->b_count = 0;
+		}
+	}
+
+	if (bcount) {
+		printk(KERN_ERR "%s: %d leftover bytes, %s\n", drive->name,
+			bcount, write ? "padding with zeros"
+				      : "discarding data");
+		ide_pad_transfer(drive, write, bcount);
+	}
+
+	return done;
+}
+EXPORT_SYMBOL_GPL(ide_io_buffers);
+
+void ide_init_pc(struct ide_atapi_pc *pc)
+{
+	memset(pc, 0, sizeof(*pc));
+	pc->buf = pc->pc_buf;
+	pc->buf_size = IDE_PC_BUFFER_SIZE;
+}
+EXPORT_SYMBOL_GPL(ide_init_pc);
+
+/*
+ * Generate a new packet command request in front of the request queue, before
+ * the current request, so that it will be processed immediately, on the next
+ * pass through the driver.
+ */
+static void ide_queue_pc_head(ide_drive_t *drive, struct gendisk *disk,
+			      struct ide_atapi_pc *pc, struct request *rq)
+{
+	blk_rq_init(NULL, rq);
+	rq->cmd_type = REQ_TYPE_SPECIAL;
+	rq->cmd_flags |= REQ_PREEMPT;
+	rq->buffer = (char *)pc;
+	rq->rq_disk = disk;
+	memcpy(rq->cmd, pc->c, 12);
+	if (drive->media == ide_tape)
+		rq->cmd[13] = REQ_IDETAPE_PC1;
+	ide_do_drive_cmd(drive, rq);
+}
+
+/*
+ * Add a special packet command request to the tail of the request queue,
+ * and wait for it to be serviced.
+ */
+int ide_queue_pc_tail(ide_drive_t *drive, struct gendisk *disk,
+		      struct ide_atapi_pc *pc)
+{
+	struct request *rq;
+	int error;
+
+	rq = blk_get_request(drive->queue, READ, __GFP_WAIT);
+	rq->cmd_type = REQ_TYPE_SPECIAL;
+	rq->buffer = (char *)pc;
+	memcpy(rq->cmd, pc->c, 12);
+	if (drive->media == ide_tape)
+		rq->cmd[13] = REQ_IDETAPE_PC1;
+	error = blk_execute_rq(drive->queue, disk, rq, 0);
+	blk_put_request(rq);
+
+	return error;
+}
+EXPORT_SYMBOL_GPL(ide_queue_pc_tail);
+
+int ide_do_test_unit_ready(ide_drive_t *drive, struct gendisk *disk)
+{
+	struct ide_atapi_pc pc;
+
+	ide_init_pc(&pc);
+	pc.c[0] = TEST_UNIT_READY;
+
+	return ide_queue_pc_tail(drive, disk, &pc);
+}
+EXPORT_SYMBOL_GPL(ide_do_test_unit_ready);
+
+int ide_do_start_stop(ide_drive_t *drive, struct gendisk *disk, int start)
+{
+	struct ide_atapi_pc pc;
+
+	ide_init_pc(&pc);
+	pc.c[0] = START_STOP;
+	pc.c[4] = start;
+
+	if (drive->media == ide_tape)
+		pc.flags |= PC_FLAG_WAIT_FOR_DSC;
+
+	return ide_queue_pc_tail(drive, disk, &pc);
+}
+EXPORT_SYMBOL_GPL(ide_do_start_stop);
+
+int ide_set_media_lock(ide_drive_t *drive, struct gendisk *disk, int on)
+{
+	struct ide_atapi_pc pc;
+
+	if (drive->atapi_flags & IDE_AFLAG_NO_DOORLOCK)
+		return 0;
+
+	ide_init_pc(&pc);
+	pc.c[0] = ALLOW_MEDIUM_REMOVAL;
+	pc.c[4] = on;
+
+	return ide_queue_pc_tail(drive, disk, &pc);
+}
+EXPORT_SYMBOL_GPL(ide_set_media_lock);
+
+void ide_create_request_sense_cmd(ide_drive_t *drive, struct ide_atapi_pc *pc)
+{
+	ide_init_pc(pc);
+	pc->c[0] = REQUEST_SENSE;
+	if (drive->media == ide_floppy) {
+		pc->c[4] = 255;
+		pc->req_xfer = 18;
+	} else {
+		pc->c[4] = 20;
+		pc->req_xfer = 20;
+	}
+}
+EXPORT_SYMBOL_GPL(ide_create_request_sense_cmd);
+
+/*
+ * Called when an error was detected during the last packet command.
+ * We queue a request sense packet command in the head of the request list.
+ */
+void ide_retry_pc(ide_drive_t *drive, struct gendisk *disk)
+{
+	struct request *rq = &drive->request_sense_rq;
+	struct ide_atapi_pc *pc = &drive->request_sense_pc;
+
+	(void)ide_read_error(drive);
+	ide_create_request_sense_cmd(drive, pc);
+	if (drive->media == ide_tape)
+		set_bit(IDE_AFLAG_IGNORE_DSC, &drive->atapi_flags);
+	ide_queue_pc_head(drive, disk, pc, rq);
+}
+EXPORT_SYMBOL_GPL(ide_retry_pc);
+
+int ide_scsi_expiry(ide_drive_t *drive)
+{
+	struct ide_atapi_pc *pc = drive->pc;
+
+	debug_log("%s called for %lu at %lu\n", __func__,
+		  pc->scsi_cmd->serial_number, jiffies);
+
+	pc->flags |= PC_FLAG_TIMEDOUT;
+
+	return 0; /* we do not want the IDE subsystem to retry */
+}
+EXPORT_SYMBOL_GPL(ide_scsi_expiry);
+
+/*
+ * This is the usual interrupt handler which will be called during a packet
+ * command.  We will transfer some of the data (as requested by the drive)
+ * and will re-point interrupt handler to us.
+ */
+static ide_startstop_t ide_pc_intr(ide_drive_t *drive)
+{
+	struct ide_atapi_pc *pc = drive->pc;
 	ide_hwif_t *hwif = drive->hwif;
 	struct request *rq = hwif->hwgroup->rq;
 	const struct ide_tp_ops *tp_ops = hwif->tp_ops;
 	xfer_func_t *xferfunc;
-	unsigned int temp;
+	ide_expiry_t *expiry;
+	unsigned int timeout, temp;
 	u16 bcount;
-	u8 stat, ireason, scsi = drive->scsi;
+	u8 stat, ireason, scsi = !!(drive->dev_flags & IDE_DFLAG_SCSI), dsc = 0;
 
 	debug_log("Enter %s - interrupt handler\n", __func__);
 
+	if (scsi) {
+		timeout = ide_scsi_get_timeout(pc);
+		expiry = ide_scsi_expiry;
+	} else {
+		timeout = (drive->media == ide_floppy) ? WAIT_FLOPPY_CMD
+						       : WAIT_TAPE_CMD;
+		expiry = NULL;
+	}
+
 	if (pc->flags & PC_FLAG_TIMEDOUT) {
-		drive->pc_callback(drive);
+		drive->pc_callback(drive, 0);
 		return ide_stopped;
 	}
 
@@ -41,7 +284,7 @@
 
 	if (pc->flags & PC_FLAG_DMA_IN_PROGRESS) {
 		if (hwif->dma_ops->dma_end(drive) ||
-		    (drive->media == ide_tape && !scsi && (stat & ERR_STAT))) {
+		    (drive->media == ide_tape && !scsi && (stat & ATA_ERR))) {
 			if (drive->media == ide_floppy && !scsi)
 				printk(KERN_ERR "%s: DMA %s error\n",
 					drive->name, rq_data_dir(pc->rq)
@@ -49,14 +292,14 @@
 			pc->flags |= PC_FLAG_DMA_ERROR;
 		} else {
 			pc->xferred = pc->req_xfer;
-			if (update_buffers)
-				update_buffers(drive, pc);
+			if (drive->pc_update_buffers)
+				drive->pc_update_buffers(drive, pc);
 		}
 		debug_log("%s: DMA finished\n", drive->name);
 	}
 
 	/* No more interrupts */
-	if ((stat & DRQ_STAT) == 0) {
+	if ((stat & ATA_DRQ) == 0) {
 		debug_log("Packet command completed, %d bytes transferred\n",
 			  pc->xferred);
 
@@ -65,10 +308,10 @@
 		local_irq_enable_in_hardirq();
 
 		if (drive->media == ide_tape && !scsi &&
-		    (stat & ERR_STAT) && rq->cmd[0] == REQUEST_SENSE)
-			stat &= ~ERR_STAT;
+		    (stat & ATA_ERR) && rq->cmd[0] == REQUEST_SENSE)
+			stat &= ~ATA_ERR;
 
-		if ((stat & ERR_STAT) || (pc->flags & PC_FLAG_DMA_ERROR)) {
+		if ((stat & ATA_ERR) || (pc->flags & PC_FLAG_DMA_ERROR)) {
 			/* Error detected */
 			debug_log("%s: I/O error\n", drive->name);
 
@@ -87,21 +330,19 @@
 			debug_log("[cmd %x]: check condition\n", rq->cmd[0]);
 
 			/* Retry operation */
-			retry_pc(drive);
+			ide_retry_pc(drive, rq->rq_disk);
 
 			/* queued, but not started */
 			return ide_stopped;
 		}
 cmd_finished:
 		pc->error = 0;
-		if ((pc->flags & PC_FLAG_WAIT_FOR_DSC) &&
-		    (stat & SEEK_STAT) == 0) {
-			dsc_handle(drive);
-			return ide_stopped;
-		}
+
+		if ((pc->flags & PC_FLAG_WAIT_FOR_DSC) && (stat & ATA_DSC) == 0)
+			dsc = 1;
 
 		/* Command finished - Call the callback function */
-		drive->pc_callback(drive);
+		drive->pc_callback(drive, dsc);
 
 		return ide_stopped;
 	}
@@ -117,17 +358,18 @@
 	/* Get the number of bytes to transfer on this interrupt. */
 	ide_read_bcount_and_ireason(drive, &bcount, &ireason);
 
-	if (ireason & CD) {
+	if (ireason & ATAPI_COD) {
 		printk(KERN_ERR "%s: CoD != 0 in %s\n", drive->name, __func__);
 		return ide_do_reset(drive);
 	}
 
-	if (((ireason & IO) == IO) == !!(pc->flags & PC_FLAG_WRITING)) {
+	if (((ireason & ATAPI_IO) == ATAPI_IO) ==
+		!!(pc->flags & PC_FLAG_WRITING)) {
 		/* Hopefully, we will never get here */
 		printk(KERN_ERR "%s: We wanted to %s, but the device wants us "
 				"to %s!\n", drive->name,
-				(ireason & IO) ? "Write" : "Read",
-				(ireason & IO) ? "Read" : "Write");
+				(ireason & ATAPI_IO) ? "Write" : "Read",
+				(ireason & ATAPI_IO) ? "Read" : "Write");
 		return ide_do_reset(drive);
 	}
 
@@ -146,7 +388,8 @@
 					temp = 0;
 				if (temp) {
 					if (pc->sg)
-						io_buffers(drive, pc, temp, 0);
+						drive->pc_io_buffers(drive, pc,
+								     temp, 0);
 					else
 						tp_ops->input_data(drive, NULL,
 							pc->cur_pos, temp);
@@ -158,9 +401,7 @@
 				pc->xferred += temp;
 				pc->cur_pos += temp;
 				ide_pad_transfer(drive, 0, bcount - temp);
-				ide_set_handler(drive, handler, timeout,
-						expiry);
-				return ide_started;
+				goto next_irq;
 			}
 			debug_log("The device wants to send us more data than "
 				  "expected - allowing transfer\n");
@@ -171,9 +412,14 @@
 
 	if ((drive->media == ide_floppy && !scsi && !pc->buf) ||
 	    (drive->media == ide_tape && !scsi && pc->bh) ||
-	    (scsi && pc->sg))
-		io_buffers(drive, pc, bcount, !!(pc->flags & PC_FLAG_WRITING));
-	else
+	    (scsi && pc->sg)) {
+		int done = drive->pc_io_buffers(drive, pc, bcount,
+				  !!(pc->flags & PC_FLAG_WRITING));
+
+		/* FIXME: don't do partial completions */
+		if (drive->media == ide_floppy && !scsi)
+			ide_end_request(drive, 1, done >> 9);
+	} else
 		xferfunc(drive, NULL, pc->cur_pos, bcount);
 
 	/* Update the current position */
@@ -182,12 +428,11 @@
 
 	debug_log("[cmd %x] transferred %d bytes on that intr.\n",
 		  rq->cmd[0], bcount);
-
+next_irq:
 	/* And set the interrupt handler again */
-	ide_set_handler(drive, handler, timeout, expiry);
+	ide_set_handler(drive, ide_pc_intr, timeout, expiry);
 	return ide_started;
 }
-EXPORT_SYMBOL_GPL(ide_pc_intr);
 
 static u8 ide_read_ireason(ide_drive_t *drive)
 {
@@ -205,7 +450,8 @@
 {
 	int retries = 100;
 
-	while (retries-- && ((ireason & CD) == 0 || (ireason & IO))) {
+	while (retries-- && ((ireason & ATAPI_COD) == 0 ||
+		(ireason & ATAPI_IO))) {
 		printk(KERN_ERR "%s: (IO,CoD != (0,1) while issuing "
 				"a packet command, retrying\n", drive->name);
 		udelay(100);
@@ -214,41 +460,71 @@
 			printk(KERN_ERR "%s: (IO,CoD != (0,1) while issuing "
 					"a packet command, ignoring\n",
 					drive->name);
-			ireason |= CD;
-			ireason &= ~IO;
+			ireason |= ATAPI_COD;
+			ireason &= ~ATAPI_IO;
 		}
 	}
 
 	return ireason;
 }
 
-ide_startstop_t ide_transfer_pc(ide_drive_t *drive, struct ide_atapi_pc *pc,
-				ide_handler_t *handler, unsigned int timeout,
-				ide_expiry_t *expiry)
+static int ide_delayed_transfer_pc(ide_drive_t *drive)
 {
+	/* Send the actual packet */
+	drive->hwif->tp_ops->output_data(drive, NULL, drive->pc->c, 12);
+
+	/* Timeout for the packet command */
+	return WAIT_FLOPPY_CMD;
+}
+
+static ide_startstop_t ide_transfer_pc(ide_drive_t *drive)
+{
+	struct ide_atapi_pc *pc = drive->pc;
 	ide_hwif_t *hwif = drive->hwif;
 	struct request *rq = hwif->hwgroup->rq;
+	ide_expiry_t *expiry;
+	unsigned int timeout;
 	ide_startstop_t startstop;
 	u8 ireason;
 
-	if (ide_wait_stat(&startstop, drive, DRQ_STAT, BUSY_STAT, WAIT_READY)) {
+	if (ide_wait_stat(&startstop, drive, ATA_DRQ, ATA_BUSY, WAIT_READY)) {
 		printk(KERN_ERR "%s: Strange, packet command initiated yet "
 				"DRQ isn't asserted\n", drive->name);
 		return startstop;
 	}
 
 	ireason = ide_read_ireason(drive);
-	if (drive->media == ide_tape && !drive->scsi)
+	if (drive->media == ide_tape &&
+	    (drive->dev_flags & IDE_DFLAG_SCSI) == 0)
 		ireason = ide_wait_ireason(drive, ireason);
 
-	if ((ireason & CD) == 0 || (ireason & IO)) {
+	if ((ireason & ATAPI_COD) == 0 || (ireason & ATAPI_IO)) {
 		printk(KERN_ERR "%s: (IO,CoD) != (0,1) while issuing "
 				"a packet command\n", drive->name);
 		return ide_do_reset(drive);
 	}
 
+	/*
+	 * If necessary schedule the packet transfer to occur 'timeout'
+	 * miliseconds later in ide_delayed_transfer_pc() after the device
+	 * says it's ready for a packet.
+	 */
+	if (drive->atapi_flags & IDE_AFLAG_ZIP_DRIVE) {
+		timeout = drive->pc_delay;
+		expiry = &ide_delayed_transfer_pc;
+	} else {
+		if (drive->dev_flags & IDE_DFLAG_SCSI) {
+			timeout = ide_scsi_get_timeout(pc);
+			expiry = ide_scsi_expiry;
+		} else {
+			timeout = (drive->media == ide_floppy) ? WAIT_FLOPPY_CMD
+							       : WAIT_TAPE_CMD;
+			expiry = NULL;
+		}
+	}
+
 	/* Set the interrupt routine */
-	ide_set_handler(drive, handler, timeout, expiry);
+	ide_set_handler(drive, ide_pc_intr, timeout, expiry);
 
 	/* Begin DMA, if necessary */
 	if (pc->flags & PC_FLAG_DMA_OK) {
@@ -262,22 +538,22 @@
 
 	return ide_started;
 }
-EXPORT_SYMBOL_GPL(ide_transfer_pc);
 
-ide_startstop_t ide_issue_pc(ide_drive_t *drive, struct ide_atapi_pc *pc,
-			     ide_handler_t *handler, unsigned int timeout,
+ide_startstop_t ide_issue_pc(ide_drive_t *drive, unsigned int timeout,
 			     ide_expiry_t *expiry)
 {
+	struct ide_atapi_pc *pc = drive->pc;
 	ide_hwif_t *hwif = drive->hwif;
+	u32 tf_flags;
 	u16 bcount;
-	u8 dma = 0;
+	u8 scsi = !!(drive->dev_flags & IDE_DFLAG_SCSI);
 
 	/* We haven't transferred any data yet */
 	pc->xferred = 0;
 	pc->cur_pos = pc->buf;
 
 	/* Request to transfer the entire buffer at once */
-	if (drive->media == ide_tape && !drive->scsi)
+	if (drive->media == ide_tape && scsi == 0)
 		bcount = pc->req_xfer;
 	else
 		bcount = min(pc->req_xfer, 63 * 1024);
@@ -287,28 +563,35 @@
 		ide_dma_off(drive);
 	}
 
-	if ((pc->flags & PC_FLAG_DMA_OK) && drive->using_dma) {
-		if (drive->scsi)
+	if ((pc->flags & PC_FLAG_DMA_OK) &&
+	    (drive->dev_flags & IDE_DFLAG_USING_DMA)) {
+		if (scsi)
 			hwif->sg_mapped = 1;
-		dma = !hwif->dma_ops->dma_setup(drive);
-		if (drive->scsi)
+		drive->dma = !hwif->dma_ops->dma_setup(drive);
+		if (scsi)
 			hwif->sg_mapped = 0;
 	}
 
-	if (!dma)
+	if (!drive->dma)
 		pc->flags &= ~PC_FLAG_DMA_OK;
 
-	ide_pktcmd_tf_load(drive, drive->scsi ? 0 : IDE_TFLAG_OUT_DEVICE,
-			   bcount, dma);
+	if (scsi)
+		tf_flags = 0;
+	else if (drive->media == ide_cdrom || drive->media == ide_optical)
+		tf_flags = IDE_TFLAG_OUT_NSECT | IDE_TFLAG_OUT_LBAL;
+	else
+		tf_flags = IDE_TFLAG_OUT_DEVICE;
+
+	ide_pktcmd_tf_load(drive, tf_flags, bcount, drive->dma);
 
 	/* Issue the packet command */
 	if (drive->atapi_flags & IDE_AFLAG_DRQ_INTERRUPT) {
-		ide_execute_command(drive, WIN_PACKETCMD, handler,
+		ide_execute_command(drive, ATA_CMD_PACKET, ide_transfer_pc,
 				    timeout, NULL);
 		return ide_started;
 	} else {
 		ide_execute_pkt_cmd(drive);
-		return (*handler)(drive);
+		return ide_transfer_pc(drive);
 	}
 }
 EXPORT_SYMBOL_GPL(ide_issue_pc);
diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c
index 49a8c58..3308b1c 100644
--- a/drivers/ide/ide-cd.c
+++ b/drivers/ide/ide-cd.c
@@ -23,6 +23,9 @@
  *	Documentation/ide/ChangeLog.ide-cd.1994-2004
  */
 
+#define DRV_NAME "ide-cd"
+#define PFX DRV_NAME ": "
+
 #define IDECD_VERSION "5.00"
 
 #include <linux/module.h>
@@ -50,13 +53,16 @@
 
 #include "ide-cd.h"
 
+#define IDECD_DEBUG_LOG		1
+
+#if IDECD_DEBUG_LOG
+#define ide_debug_log(lvl, fmt, args...) __ide_debug_log(lvl, fmt, args)
+#else
+#define ide_debug_log(lvl, fmt, args...) do {} while (0)
+#endif
+
 static DEFINE_MUTEX(idecd_ref_mutex);
 
-#define to_ide_cd(obj) container_of(obj, struct cdrom_info, kref)
-
-#define ide_cd_g(disk) \
-	container_of((disk)->private_data, struct cdrom_info, driver)
-
 static void ide_cd_release(struct kref *);
 
 static struct cdrom_info *ide_cd_get(struct gendisk *disk)
@@ -64,7 +70,7 @@
 	struct cdrom_info *cd = NULL;
 
 	mutex_lock(&idecd_ref_mutex);
-	cd = ide_cd_g(disk);
+	cd = ide_drv_g(disk, cdrom_info);
 	if (cd) {
 		if (ide_device_get(cd->drive))
 			cd = NULL;
@@ -102,6 +108,9 @@
 {
 	int log = 0;
 
+	ide_debug_log(IDE_DBG_SENSE, "Call %s, sense_key: 0x%x\n", __func__,
+		      sense->sense_key);
+
 	if (!sense || !rq || (rq->cmd_flags & REQ_QUIET))
 		return 0;
 
@@ -150,6 +159,14 @@
 	unsigned long bio_sectors;
 	struct cdrom_info *info = drive->driver_data;
 
+	ide_debug_log(IDE_DBG_SENSE, "Call %s, error_code: 0x%x, "
+			"sense_key: 0x%x\n", __func__, sense->error_code,
+			sense->sense_key);
+
+	if (failed_command)
+		ide_debug_log(IDE_DBG_SENSE, "%s: failed cmd: 0x%x\n",
+				__func__, failed_command->cmd[0]);
+
 	if (!cdrom_log_sense(drive, failed_command, sense))
 		return;
 
@@ -200,6 +217,8 @@
 	struct cdrom_info *info		= drive->driver_data;
 	struct request *rq		= &info->request_sense_request;
 
+	ide_debug_log(IDE_DBG_SENSE, "Call %s\n", __func__);
+
 	if (sense == NULL)
 		sense = &info->sense_data;
 
@@ -219,6 +238,10 @@
 	/* NOTE! Save the failed command in "rq->buffer" */
 	rq->buffer = (void *) failed_command;
 
+	if (failed_command)
+		ide_debug_log(IDE_DBG_SENSE, "failed_cmd: 0x%x\n",
+			      failed_command->cmd[0]);
+
 	ide_do_drive_cmd(drive, rq);
 }
 
@@ -227,6 +250,10 @@
 	struct request *rq = HWGROUP(drive)->rq;
 	int nsectors = rq->hard_cur_sectors;
 
+	ide_debug_log(IDE_DBG_FUNC, "Call %s, cmd: 0x%x, uptodate: 0x%x, "
+		      "nsectors: %d\n", __func__, rq->cmd[0], uptodate,
+		      nsectors);
+
 	if (blk_sense_request(rq) && uptodate) {
 		/*
 		 * For REQ_TYPE_SENSE, "rq->buffer" points to the original
@@ -269,6 +296,9 @@
 	if (!nsectors)
 		nsectors = 1;
 
+	ide_debug_log(IDE_DBG_FUNC, "Exit %s, uptodate: 0x%x, nsectors: %d\n",
+		      __func__, uptodate, nsectors);
+
 	ide_end_request(drive, uptodate, nsectors);
 }
 
@@ -304,11 +334,15 @@
 	sense_key = err >> 4;
 
 	if (rq == NULL) {
-		printk(KERN_ERR "%s: missing rq in %s\n",
+		printk(KERN_ERR PFX "%s: missing rq in %s\n",
 				drive->name, __func__);
 		return 1;
 	}
 
+	ide_debug_log(IDE_DBG_RQ, "%s: stat: 0x%x, good_stat: 0x%x, "
+		      "rq->cmd_type: 0x%x, err: 0x%x\n", __func__, stat,
+		      good_stat, rq->cmd_type, err);
+
 	if (blk_sense_request(rq)) {
 		/*
 		 * We got an error trying to get sense info from the drive
@@ -374,7 +408,8 @@
 				cdrom_saw_media_change(drive);
 
 				/* fail the request */
-				printk(KERN_ERR "%s: tray open\n", drive->name);
+				printk(KERN_ERR PFX "%s: tray open\n",
+						drive->name);
 				do_end_request = 1;
 			} else {
 				struct cdrom_info *info = drive->driver_data;
@@ -436,7 +471,7 @@
 			ide_dump_status_no_sense(drive, "media error (blank)",
 						 stat);
 			do_end_request = 1;
-		} else if ((err & ~ABRT_ERR) != 0) {
+		} else if ((err & ~ATA_ABORTED) != 0) {
 			/* go to the default handler for other errors */
 			ide_error(drive, "cdrom_decode_status", stat);
 			return 1;
@@ -457,10 +492,10 @@
 		 * If we got a CHECK_CONDITION status, queue
 		 * a request sense command.
 		 */
-		if (stat & ERR_STAT)
+		if (stat & ATA_ERR)
 			cdrom_queue_request_sense(drive, NULL, NULL);
 	} else {
-		blk_dump_rq_flags(rq, "ide-cd: bad rq");
+		blk_dump_rq_flags(rq, PFX "bad rq");
 		cdrom_end_request(drive, 0);
 	}
 
@@ -468,7 +503,7 @@
 	return 1;
 
 end_request:
-	if (stat & ERR_STAT) {
+	if (stat & ATA_ERR) {
 		unsigned long flags;
 
 		spin_lock_irqsave(&ide_lock, flags);
@@ -488,6 +523,9 @@
 	struct request *rq = HWGROUP(drive)->rq;
 	unsigned long wait = 0;
 
+	ide_debug_log(IDE_DBG_RQ, "Call %s: rq->cmd[0]: 0x%x\n", __func__,
+		      rq->cmd[0]);
+
 	/*
 	 * Some commands are *slow* and normally take a long time to complete.
 	 * Usually we can use the ATAPI "disconnect" to bypass this, but not all
@@ -504,7 +542,7 @@
 		break;
 	default:
 		if (!(rq->cmd_flags & REQ_QUIET))
-			printk(KERN_INFO "ide-cd: cmd 0x%x timed out\n",
+			printk(KERN_INFO PFX "cmd 0x%x timed out\n",
 					 rq->cmd[0]);
 		wait = 0;
 		break;
@@ -524,24 +562,25 @@
 						  int xferlen,
 						  ide_handler_t *handler)
 {
-	struct cdrom_info *info = drive->driver_data;
 	ide_hwif_t *hwif = drive->hwif;
 
+	ide_debug_log(IDE_DBG_PC, "Call %s, xferlen: %d\n", __func__, xferlen);
+
 	/* FIXME: for Virtual DMA we must check harder */
-	if (info->dma)
-		info->dma = !hwif->dma_ops->dma_setup(drive);
+	if (drive->dma)
+		drive->dma = !hwif->dma_ops->dma_setup(drive);
 
 	/* set up the controller registers */
 	ide_pktcmd_tf_load(drive, IDE_TFLAG_OUT_NSECT | IDE_TFLAG_OUT_LBAL,
-			   xferlen, info->dma);
+			   xferlen, drive->dma);
 
 	if (drive->atapi_flags & IDE_AFLAG_DRQ_INTERRUPT) {
 		/* waiting for CDB interrupt, not DMA yet. */
-		if (info->dma)
+		if (drive->dma)
 			drive->waiting_for_dma = 0;
 
 		/* packet command */
-		ide_execute_command(drive, WIN_PACKETCMD, handler,
+		ide_execute_command(drive, ATA_CMD_PACKET, handler,
 				    ATAPI_WAIT_PC, cdrom_timer_expiry);
 		return ide_started;
 	} else {
@@ -564,9 +603,10 @@
 {
 	ide_hwif_t *hwif = drive->hwif;
 	int cmd_len;
-	struct cdrom_info *info = drive->driver_data;
 	ide_startstop_t startstop;
 
+	ide_debug_log(IDE_DBG_PC, "Call %s\n", __func__);
+
 	if (drive->atapi_flags & IDE_AFLAG_DRQ_INTERRUPT) {
 		/*
 		 * Here we should have been called after receiving an interrupt
@@ -574,16 +614,16 @@
 		 */
 
 		/* check for errors */
-		if (cdrom_decode_status(drive, DRQ_STAT, NULL))
+		if (cdrom_decode_status(drive, ATA_DRQ, NULL))
 			return ide_stopped;
 
 		/* ok, next interrupt will be DMA interrupt */
-		if (info->dma)
+		if (drive->dma)
 			drive->waiting_for_dma = 1;
 	} else {
 		/* otherwise, we must wait for DRQ to get set */
-		if (ide_wait_stat(&startstop, drive, DRQ_STAT,
-				BUSY_STAT, WAIT_READY))
+		if (ide_wait_stat(&startstop, drive, ATA_DRQ,
+				  ATA_BUSY, WAIT_READY))
 			return startstop;
 	}
 
@@ -599,7 +639,7 @@
 	hwif->tp_ops->output_data(drive, NULL, rq->cmd, cmd_len);
 
 	/* start the DMA if need be */
-	if (info->dma)
+	if (drive->dma)
 		hwif->dma_ops->dma_start(drive);
 
 	return ide_started;
@@ -615,6 +655,9 @@
 {
 	ide_hwif_t *hwif = drive->hwif;
 
+	ide_debug_log(IDE_DBG_FUNC, "Call %s, ireason: 0x%x, rw: 0x%x\n",
+		      __func__, ireason, rw);
+
 	/*
 	 * ireason == 0: the drive wants to receive data from us
 	 * ireason == 2: the drive is expecting to transfer data to us
@@ -624,7 +667,7 @@
 	else if (ireason == (rw << 1)) {
 
 		/* whoops... */
-		printk(KERN_ERR "%s: %s: wrong transfer direction!\n",
+		printk(KERN_ERR PFX "%s: %s: wrong transfer direction!\n",
 				drive->name, __func__);
 
 		ide_pad_transfer(drive, rw, len);
@@ -637,7 +680,7 @@
 		return 0;
 	} else {
 		/* drive wants a command packet, or invalid ireason... */
-		printk(KERN_ERR "%s: %s: bad interrupt reason 0x%02x\n",
+		printk(KERN_ERR PFX "%s: %s: bad interrupt reason 0x%02x\n",
 				drive->name, __func__, ireason);
 	}
 
@@ -654,17 +697,19 @@
  */
 static int ide_cd_check_transfer_size(ide_drive_t *drive, int len)
 {
+	ide_debug_log(IDE_DBG_FUNC, "Call %s, len: %d\n", __func__, len);
+
 	if ((len % SECTOR_SIZE) == 0)
 		return 0;
 
-	printk(KERN_ERR "%s: %s: Bad transfer size %d\n",
-			drive->name, __func__, len);
+	printk(KERN_ERR PFX "%s: %s: Bad transfer size %d\n", drive->name,
+			__func__, len);
 
 	if (drive->atapi_flags & IDE_AFLAG_LIMIT_NFRAMES)
-		printk(KERN_ERR "  This drive is not supported by "
-				"this version of the driver\n");
+		printk(KERN_ERR PFX "This drive is not supported by this "
+				"version of the driver\n");
 	else {
-		printk(KERN_ERR "  Trying to limit transfer sizes\n");
+		printk(KERN_ERR PFX "Trying to limit transfer sizes\n");
 		drive->atapi_flags |= IDE_AFLAG_LIMIT_NFRAMES;
 	}
 
@@ -676,6 +721,9 @@
 static ide_startstop_t ide_cd_prepare_rw_request(ide_drive_t *drive,
 						 struct request *rq)
 {
+	ide_debug_log(IDE_DBG_RQ, "Call %s: rq->cmd_flags: 0x%x\n", __func__,
+		      rq->cmd_flags);
+
 	if (rq_data_dir(rq) == READ) {
 		unsigned short sectors_per_frame =
 			queue_hardsect_size(drive->queue) >> SECTOR_BITS;
@@ -695,7 +743,7 @@
 			/* sanity check... */
 			if (rq->current_nr_sectors !=
 			    bio_cur_sectors(rq->bio)) {
-				printk(KERN_ERR "%s: %s: buffer botch (%u)\n",
+				printk(KERN_ERR PFX "%s: %s: buffer botch (%u)\n",
 						drive->name, __func__,
 						rq->current_nr_sectors);
 				cdrom_end_request(drive, 0);
@@ -704,11 +752,7 @@
 			rq->current_nr_sectors += nskip;
 		}
 	}
-#if 0
-	else
-		/* the immediate bit */
-		rq->cmd[1] = 1 << 3;
-#endif
+
 	/* set up the command */
 	rq->timeout = ATAPI_WAIT_PC;
 
@@ -739,6 +783,8 @@
 	int stat;
 	static int retry = 10;
 
+	ide_debug_log(IDE_DBG_FUNC, "Call %s\n", __func__);
+
 	if (cdrom_decode_status(drive, 0, &stat))
 		return ide_stopped;
 
@@ -746,7 +792,7 @@
 
 	if (retry && time_after(jiffies, info->start_seek + IDECD_SEEK_TIMER)) {
 		if (--retry == 0)
-			drive->dsc_overlap = 0;
+			drive->dev_flags &= ~IDE_DFLAG_DSC_OVERLAP;
 	}
 	return ide_stopped;
 }
@@ -755,6 +801,8 @@
 {
 	sector_t frame = rq->sector;
 
+	ide_debug_log(IDE_DBG_FUNC, "Call %s\n", __func__);
+
 	sector_div(frame, queue_hardsect_size(drive->queue) >> SECTOR_BITS);
 
 	memset(rq->cmd, 0, BLK_MAX_CDB);
@@ -775,8 +823,11 @@
  * Fix up a possibly partially-processed request so that we can start it over
  * entirely, or even put it back on the request queue.
  */
-static void restore_request(struct request *rq)
+static void ide_cd_restore_request(ide_drive_t *drive, struct request *rq)
 {
+
+	ide_debug_log(IDE_DBG_FUNC, "Call %s\n", __func__);
+
 	if (rq->buffer != bio_data(rq->bio)) {
 		sector_t n =
 			(rq->buffer - (char *)bio_data(rq->bio)) / SECTOR_SIZE;
@@ -795,8 +846,11 @@
 /*
  * All other packet commands.
  */
-static void ide_cd_request_sense_fixup(struct request *rq)
+static void ide_cd_request_sense_fixup(ide_drive_t *drive, struct request *rq)
 {
+
+	ide_debug_log(IDE_DBG_FUNC, "Call %s\n", __func__);
+
 	/*
 	 * Some of the trailing request sense fields are optional,
 	 * and some drives don't send them.  Sigh.
@@ -822,6 +876,10 @@
 	if (!sense)
 		sense = &local_sense;
 
+	ide_debug_log(IDE_DBG_PC, "Call %s, rq->cmd[0]: 0x%x, write: 0x%x, "
+		      "timeout: %d, cmd_flags: 0x%x\n", __func__, cmd[0], write,
+		      timeout, cmd_flags);
+
 	/* start of retry loop */
 	do {
 		struct request *rq;
@@ -895,7 +953,6 @@
 static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive)
 {
 	ide_hwif_t *hwif = drive->hwif;
-	struct cdrom_info *info = drive->driver_data;
 	struct request *rq = HWGROUP(drive)->rq;
 	xfer_func_t *xferfunc;
 	ide_expiry_t *expiry = NULL;
@@ -905,13 +962,16 @@
 	u16 len;
 	u8 ireason;
 
+	ide_debug_log(IDE_DBG_PC, "Call %s, rq->cmd[0]: 0x%x, write: 0x%x\n",
+		      __func__, rq->cmd[0], write);
+
 	/* check for errors */
-	dma = info->dma;
+	dma = drive->dma;
 	if (dma) {
-		info->dma = 0;
+		drive->dma = 0;
 		dma_error = hwif->dma_ops->dma_end(drive);
 		if (dma_error) {
-			printk(KERN_ERR "%s: DMA %s error\n", drive->name,
+			printk(KERN_ERR PFX "%s: DMA %s error\n", drive->name,
 					write ? "write" : "read");
 			ide_dma_off(drive);
 		}
@@ -937,8 +997,11 @@
 	if (thislen > len)
 		thislen = len;
 
+	ide_debug_log(IDE_DBG_PC, "%s: DRQ: stat: 0x%x, thislen: %d\n",
+		      __func__, stat, thislen);
+
 	/* If DRQ is clear, the command has completed. */
-	if ((stat & DRQ_STAT) == 0) {
+	if ((stat & ATA_DRQ) == 0) {
 		if (blk_fs_request(rq)) {
 			/*
 			 * If we're not done reading/writing, complain.
@@ -946,7 +1009,7 @@
 			 */
 			uptodate = 1;
 			if (rq->current_nr_sectors > 0) {
-				printk(KERN_ERR "%s: %s: data underrun "
+				printk(KERN_ERR PFX "%s: %s: data underrun "
 						"(%d blocks)\n",
 						drive->name, __func__,
 						rq->current_nr_sectors);
@@ -957,7 +1020,7 @@
 			cdrom_end_request(drive, uptodate);
 			return ide_stopped;
 		} else if (!blk_pc_request(rq)) {
-			ide_cd_request_sense_fixup(rq);
+			ide_cd_request_sense_fixup(drive, rq);
 			/* complain if we still have data left to transfer */
 			uptodate = rq->data_len ? 0 : 1;
 		}
@@ -1000,6 +1063,9 @@
 		xferfunc = hwif->tp_ops->input_data;
 	}
 
+	ide_debug_log(IDE_DBG_PC, "%s: data transfer, rq->cmd_type: 0x%x, "
+		      "ireason: 0x%x\n", __func__, rq->cmd_type, ireason);
+
 	/* transfer data */
 	while (thislen > 0) {
 		u8 *ptr = blk_fs_request(rq) ? NULL : rq->data;
@@ -1024,7 +1090,7 @@
 				 */
 				ide_pad_transfer(drive, 0, thislen);
 			else {
-				printk(KERN_ERR "%s: confused, missing data\n",
+				printk(KERN_ERR PFX "%s: confused, missing data\n",
 						drive->name);
 				blk_dump_rq_flags(rq, rq_data_dir(rq)
 						  ? "cdrom_newpc_intr, write"
@@ -1111,9 +1177,12 @@
 	unsigned short sectors_per_frame =
 		queue_hardsect_size(drive->queue) >> SECTOR_BITS;
 
+	ide_debug_log(IDE_DBG_RQ, "Call %s, write: 0x%x, secs_per_frame: %u\n",
+		      __func__, write, sectors_per_frame);
+
 	if (write) {
 		/* disk has become write protected */
-		if (cd->disk->policy) {
+		if (get_disk_ro(cd->disk)) {
 			cdrom_end_request(drive, 0);
 			return ide_stopped;
 		}
@@ -1122,7 +1191,7 @@
 		 * We may be retrying this request after an error.  Fix up any
 		 * weirdness which might be present in the request packet.
 		 */
-		restore_request(rq);
+		ide_cd_restore_request(drive, rq);
 	}
 
 	/* use DMA, if possible / writes *must* be hardware frame aligned */
@@ -1132,9 +1201,9 @@
 			cdrom_end_request(drive, 0);
 			return ide_stopped;
 		}
-		cd->dma = 0;
+		drive->dma = 0;
 	} else
-		cd->dma = drive->using_dma;
+		drive->dma = !!(drive->dev_flags & IDE_DFLAG_USING_DMA);
 
 	if (write)
 		cd->devinfo.media_written = 1;
@@ -1151,28 +1220,29 @@
 
 static void cdrom_do_block_pc(ide_drive_t *drive, struct request *rq)
 {
-	struct cdrom_info *info = drive->driver_data;
+
+	ide_debug_log(IDE_DBG_PC, "Call %s, rq->cmd_type: 0x%x\n", __func__,
+		      rq->cmd_type);
 
 	if (blk_pc_request(rq))
 		rq->cmd_flags |= REQ_QUIET;
 	else
 		rq->cmd_flags &= ~REQ_FAILED;
 
-	info->dma = 0;
+	drive->dma = 0;
 
 	/* sg request */
 	if (rq->bio || ((rq->cmd_type == REQ_TYPE_ATA_PC) && rq->data_len)) {
 		struct request_queue *q = drive->queue;
 		unsigned int alignment;
-		unsigned long addr;
-		unsigned long stack_mask = ~(THREAD_SIZE - 1);
+		char *buf;
 
 		if (rq->bio)
-			addr = (unsigned long)bio_data(rq->bio);
+			buf = bio_data(rq->bio);
 		else
-			addr = (unsigned long)rq->data;
+			buf = rq->data;
 
-		info->dma = drive->using_dma;
+		drive->dma = !!(drive->dev_flags & IDE_DFLAG_USING_DMA);
 
 		/*
 		 * check if dma is safe
@@ -1181,12 +1251,9 @@
 		 * separate masks.
 		 */
 		alignment = queue_dma_alignment(q) | q->dma_pad_mask;
-		if (addr & alignment || rq->data_len & alignment)
-			info->dma = 0;
-
-		if (!((addr & stack_mask) ^
-		      ((unsigned long)current->stack & stack_mask)))
-			info->dma = 0;
+		if ((unsigned long)buf & alignment || rq->data_len & alignment
+		    || object_is_on_stack(buf))
+			drive->dma = 0;
 	}
 }
 
@@ -1200,19 +1267,22 @@
 	ide_handler_t *fn;
 	int xferlen;
 
+	ide_debug_log(IDE_DBG_RQ, "Call %s, rq->cmd_type: 0x%x, block: %llu\n",
+		      __func__, rq->cmd_type, (unsigned long long)block);
+
 	if (blk_fs_request(rq)) {
 		if (drive->atapi_flags & IDE_AFLAG_SEEKING) {
 			ide_hwif_t *hwif = drive->hwif;
 			unsigned long elapsed = jiffies - info->start_seek;
 			int stat = hwif->tp_ops->read_status(hwif);
 
-			if ((stat & SEEK_STAT) != SEEK_STAT) {
+			if ((stat & ATA_DSC) != ATA_DSC) {
 				if (elapsed < IDECD_SEEK_TIMEOUT) {
 					ide_stall_queue(drive,
 							IDECD_SEEK_TIMER);
 					return ide_stopped;
 				}
-				printk(KERN_ERR "%s: DSC timeout\n",
+				printk(KERN_ERR PFX "%s: DSC timeout\n",
 						drive->name);
 			}
 			drive->atapi_flags &= ~IDE_AFLAG_SEEKING;
@@ -1220,11 +1290,11 @@
 		if (rq_data_dir(rq) == READ &&
 		    IDE_LARGE_SEEK(info->last_block, block,
 			    IDECD_SEEK_THRESHOLD) &&
-		    drive->dsc_overlap) {
+		    (drive->dev_flags & IDE_DFLAG_DSC_OVERLAP)) {
 			xferlen = 0;
 			fn = cdrom_start_seek_continuation;
 
-			info->dma = 0;
+			drive->dma = 0;
 			info->start_seek = jiffies;
 
 			ide_cd_prepare_seek_request(drive, rq);
@@ -1253,7 +1323,7 @@
 		cdrom_end_request(drive, 1);
 		return ide_stopped;
 	} else {
-		blk_dump_rq_flags(rq, "ide-cd bad flags");
+		blk_dump_rq_flags(rq, DRV_NAME " bad flags");
 		cdrom_end_request(drive, 0);
 		return ide_stopped;
 	}
@@ -1283,6 +1353,8 @@
 	struct cdrom_device_info *cdi = &info->devinfo;
 	unsigned char cmd[BLK_MAX_CDB];
 
+	ide_debug_log(IDE_DBG_FUNC, "Call %s\n", __func__);
+
 	memset(cmd, 0, BLK_MAX_CDB);
 	cmd[0] = GPCMD_TEST_UNIT_READY;
 
@@ -1309,6 +1381,8 @@
 	unsigned len = sizeof(capbuf);
 	u32 blocklen;
 
+	ide_debug_log(IDE_DBG_FUNC, "Call %s\n", __func__);
+
 	memset(cmd, 0, BLK_MAX_CDB);
 	cmd[0] = GPCMD_READ_CDVD_CAPACITY;
 
@@ -1328,10 +1402,10 @@
 	case 4096:
 		break;
 	default:
-		printk(KERN_ERR "%s: weird block size %u\n",
-			drive->name, blocklen);
-		printk(KERN_ERR "%s: default to 2kb block size\n",
-			drive->name);
+		printk(KERN_ERR PFX "%s: weird block size %u\n",
+				drive->name, blocklen);
+		printk(KERN_ERR PFX "%s: default to 2kb block size\n",
+				drive->name);
 		blocklen = 2048;
 		break;
 	}
@@ -1347,6 +1421,8 @@
 {
 	unsigned char cmd[BLK_MAX_CDB];
 
+	ide_debug_log(IDE_DBG_FUNC, "Call %s\n", __func__);
+
 	memset(cmd, 0, BLK_MAX_CDB);
 
 	cmd[0] = GPCMD_READ_TOC_PMA_ATIP;
@@ -1375,11 +1451,13 @@
 	long last_written;
 	unsigned long sectors_per_frame = SECTORS_PER_FRAME;
 
+	ide_debug_log(IDE_DBG_FUNC, "Call %s\n", __func__);
+
 	if (toc == NULL) {
 		/* try to allocate space */
 		toc = kmalloc(sizeof(struct atapi_toc), GFP_KERNEL);
 		if (toc == NULL) {
-			printk(KERN_ERR "%s: No cdrom TOC buffer!\n",
+			printk(KERN_ERR PFX "%s: No cdrom TOC buffer!\n",
 					drive->name);
 			return -ENOMEM;
 		}
@@ -1535,6 +1613,8 @@
 	struct packet_command cgc;
 	int stat, attempts = 3, size = ATAPI_CAPABILITIES_PAGE_SIZE;
 
+	ide_debug_log(IDE_DBG_FUNC, "Call %s\n", __func__);
+
 	if ((drive->atapi_flags & IDE_AFLAG_FULL_CAPS_PAGE) == 0)
 		size -= ATAPI_CAPABILITIES_PAGE_PAD_SIZE;
 
@@ -1553,6 +1633,8 @@
 	struct cdrom_info *cd = drive->driver_data;
 	u16 curspeed, maxspeed;
 
+	ide_debug_log(IDE_DBG_FUNC, "Call %s\n", __func__);
+
 	if (drive->atapi_flags & IDE_AFLAG_LE_SPEED_FIELDS) {
 		curspeed = le16_to_cpup((__le16 *)&buf[8 + 14]);
 		maxspeed = le16_to_cpup((__le16 *)&buf[8 + 8]);
@@ -1593,6 +1675,8 @@
 	struct cdrom_info *info = drive->driver_data;
 	struct cdrom_device_info *devinfo = &info->devinfo;
 
+	ide_debug_log(IDE_DBG_PROBE, "Call %s, nslots: %d\n", __func__, nslots);
+
 	devinfo->ops = &ide_cdrom_dops;
 	devinfo->speed = info->current_speed;
 	devinfo->capacity = nslots;
@@ -1614,13 +1698,17 @@
 	mechtype_t mechtype;
 	int nslots = 1;
 
+	ide_debug_log(IDE_DBG_PROBE, "Call %s, drive->media: 0x%x, "
+		      "drive->atapi_flags: 0x%lx\n", __func__, drive->media,
+		      drive->atapi_flags);
+
 	cdi->mask = (CDC_CD_R | CDC_CD_RW | CDC_DVD | CDC_DVD_R |
 		     CDC_DVD_RAM | CDC_SELECT_DISC | CDC_PLAY_AUDIO |
 		     CDC_MO_DRIVE | CDC_RAM);
 
 	if (drive->media == ide_optical) {
 		cdi->mask &= ~(CDC_MO_DRIVE | CDC_RAM);
-		printk(KERN_ERR "%s: ATAPI magneto-optical drive\n",
+		printk(KERN_ERR PFX "%s: ATAPI magneto-optical drive\n",
 				drive->name);
 		return nslots;
 	}
@@ -1661,7 +1749,9 @@
 		cdi->mask &= ~CDC_PLAY_AUDIO;
 
 	mechtype = buf[8 + 6] >> 5;
-	if (mechtype == mechtype_caddy || mechtype == mechtype_popup)
+	if (mechtype == mechtype_caddy ||
+	    mechtype == mechtype_popup ||
+	    (drive->atapi_flags & IDE_AFLAG_NO_AUTOCLOSE))
 		cdi->mask |= CDC_CLOSE_TRAY;
 
 	if (cdi->sanyo_slot > 0) {
@@ -1676,7 +1766,7 @@
 
 	ide_cdrom_update_speed(drive, buf);
 
-	printk(KERN_INFO "%s: ATAPI", drive->name);
+	printk(KERN_INFO PFX "%s: ATAPI", drive->name);
 
 	/* don't print speed if the drive reported 0 */
 	if (cd->max_speed)
@@ -1699,7 +1789,8 @@
 	else
 		printk(KERN_CONT " drive");
 
-	printk(KERN_CONT ", %dkB Cache\n", be16_to_cpup((__be16 *)&buf[8 + 12]));
+	printk(KERN_CONT ", %dkB Cache\n",
+			 be16_to_cpup((__be16 *)&buf[8 + 12]));
 
 	return nslots;
 }
@@ -1811,13 +1902,12 @@
 	{ NULL, 0, NULL, NULL }
 };
 
-static void ide_cdrom_add_settings(ide_drive_t *drive)
-{
-	ide_add_setting(drive, "dsc_overlap", SETTING_RW, TYPE_BYTE, 0, 1, 1, 1,
-			&drive->dsc_overlap, NULL);
-}
-#else
-static inline void ide_cdrom_add_settings(ide_drive_t *drive) { ; }
+ide_devset_rw_flag(dsc_overlap, IDE_DFLAG_DSC_OVERLAP);
+
+static const struct ide_proc_devset idecd_settings[] = {
+	IDE_PROC_DEVSET(dsc_overlap, 0, 1),
+	{ 0 },
+};
 #endif
 
 static const struct cd_list_entry ide_cd_quirks_list[] = {
@@ -1859,17 +1949,19 @@
 	{ "MATSHITADVD-ROM SR-8176", NULL,   IDE_AFLAG_PLAY_AUDIO_OK	     },
 	{ "MATSHITADVD-ROM SR-8174", NULL,   IDE_AFLAG_PLAY_AUDIO_OK	     },
 	{ "Optiarc DVD RW AD-5200A", NULL,   IDE_AFLAG_PLAY_AUDIO_OK	     },
+	{ "Optiarc DVD RW AD-7200A", NULL,   IDE_AFLAG_PLAY_AUDIO_OK	     },
+	{ "Optiarc DVD RW AD-7543A", NULL,   IDE_AFLAG_NO_AUTOCLOSE	     },
 	{ NULL, NULL, 0 }
 };
 
-static unsigned int ide_cd_flags(struct hd_driveid *id)
+static unsigned int ide_cd_flags(u16 *id)
 {
 	const struct cd_list_entry *cle = ide_cd_quirks_list;
 
 	while (cle->id_model) {
-		if (strcmp(cle->id_model, id->model) == 0 &&
+		if (strcmp(cle->id_model, (char *)&id[ATA_ID_PROD]) == 0 &&
 		    (cle->id_firmware == NULL ||
-		     strstr(id->fw_rev, cle->id_firmware)))
+		     strstr((char *)&id[ATA_ID_FW_REV], cle->id_firmware)))
 			return cle->cd_flags;
 		cle++;
 	}
@@ -1881,9 +1973,12 @@
 {
 	struct cdrom_info *cd = drive->driver_data;
 	struct cdrom_device_info *cdi = &cd->devinfo;
-	struct hd_driveid *id = drive->id;
+	u16 *id = drive->id;
+	char *fw_rev = (char *)&id[ATA_ID_FW_REV];
 	int nslots;
 
+	ide_debug_log(IDE_DBG_PROBE, "Call %s\n", __func__);
+
 	blk_queue_prep_rq(drive->queue, ide_cdrom_prep_fn);
 	blk_queue_dma_alignment(drive->queue, 31);
 	blk_queue_update_dma_pad(drive->queue, 15);
@@ -1891,20 +1986,15 @@
 	if (!drive->queue->unplug_delay)
 		drive->queue->unplug_delay = 1;
 
-	drive->special.all	= 0;
-
 	drive->atapi_flags = IDE_AFLAG_MEDIA_CHANGED | IDE_AFLAG_NO_EJECT |
 		       ide_cd_flags(id);
 
-	if ((id->config & 0x0060) == 0x20)
-		drive->atapi_flags |= IDE_AFLAG_DRQ_INTERRUPT;
-
 	if ((drive->atapi_flags & IDE_AFLAG_VERTOS_300_SSD) &&
-	    id->fw_rev[4] == '1' && id->fw_rev[6] <= '2')
+	    fw_rev[4] == '1' && fw_rev[6] <= '2')
 		drive->atapi_flags |= (IDE_AFLAG_TOCTRACKS_AS_BCD |
 				     IDE_AFLAG_TOCADDR_AS_BCD);
 	else if ((drive->atapi_flags & IDE_AFLAG_VERTOS_600_ESD) &&
-		 id->fw_rev[4] == '1' && id->fw_rev[6] <= '2')
+		 fw_rev[4] == '1' && fw_rev[6] <= '2')
 		drive->atapi_flags |= IDE_AFLAG_TOCTRACKS_AS_BCD;
 	else if (drive->atapi_flags & IDE_AFLAG_SANYO_3CD)
 		/* 3 => use CD in slot 0 */
@@ -1915,15 +2005,19 @@
 	/* set correct block size */
 	blk_queue_hardsect_size(drive->queue, CD_FRAMESIZE);
 
-	drive->dsc_overlap = (drive->next != drive);
+	if (drive->next != drive)
+		drive->dev_flags |= IDE_DFLAG_DSC_OVERLAP;
+	else
+		drive->dev_flags &= ~IDE_DFLAG_DSC_OVERLAP;
 
 	if (ide_cdrom_register(drive, nslots)) {
-		printk(KERN_ERR "%s: %s failed to register device with the"
+		printk(KERN_ERR PFX "%s: %s failed to register device with the"
 				" cdrom driver.\n", drive->name, __func__);
 		cd->devinfo.handle = NULL;
 		return 1;
 	}
-	ide_cdrom_add_settings(drive);
+
+	ide_proc_register_driver(drive, cd->driver);
 	return 0;
 }
 
@@ -1931,6 +2025,8 @@
 {
 	struct cdrom_info *info = drive->driver_data;
 
+	ide_debug_log(IDE_DBG_FUNC, "Call %s\n", __func__);
+
 	ide_proc_unregister_driver(drive, info->driver);
 
 	del_gendisk(info->disk);
@@ -1940,15 +2036,17 @@
 
 static void ide_cd_release(struct kref *kref)
 {
-	struct cdrom_info *info = to_ide_cd(kref);
+	struct cdrom_info *info = to_ide_drv(kref, cdrom_info);
 	struct cdrom_device_info *devinfo = &info->devinfo;
 	ide_drive_t *drive = info->drive;
 	struct gendisk *g = info->disk;
 
+	ide_debug_log(IDE_DBG_FUNC, "Call %s\n", __func__);
+
 	kfree(info->toc);
 	if (devinfo->handle == drive)
 		unregister_cdrom(devinfo);
-	drive->dsc_overlap = 0;
+	drive->dev_flags &= ~IDE_DFLAG_DSC_OVERLAP;
 	drive->driver_data = NULL;
 	blk_queue_prep_rq(drive->queue, NULL);
 	g->private_data = NULL;
@@ -1967,13 +2065,12 @@
 	.probe			= ide_cd_probe,
 	.remove			= ide_cd_remove,
 	.version		= IDECD_VERSION,
-	.media			= ide_cdrom,
-	.supports_dsc_overlap	= 1,
 	.do_request		= ide_cd_do_request,
 	.end_request		= ide_end_request,
 	.error			= __ide_error,
 #ifdef CONFIG_IDE_PROC_FS
 	.proc			= idecd_proc,
+	.settings		= idecd_settings,
 #endif
 };
 
@@ -1998,7 +2095,7 @@
 static int idecd_release(struct inode *inode, struct file *file)
 {
 	struct gendisk *disk = inode->i_bdev->bd_disk;
-	struct cdrom_info *info = ide_cd_g(disk);
+	struct cdrom_info *info = ide_drv_g(disk, cdrom_info);
 
 	cdrom_release(&info->devinfo, file);
 
@@ -2050,7 +2147,7 @@
 			unsigned int cmd, unsigned long arg)
 {
 	struct block_device *bdev = inode->i_bdev;
-	struct cdrom_info *info = ide_cd_g(bdev->bd_disk);
+	struct cdrom_info *info = ide_drv_g(bdev->bd_disk, cdrom_info);
 	int err;
 
 	switch (cmd) {
@@ -2071,13 +2168,13 @@
 
 static int idecd_media_changed(struct gendisk *disk)
 {
-	struct cdrom_info *info = ide_cd_g(disk);
+	struct cdrom_info *info = ide_drv_g(disk, cdrom_info);
 	return cdrom_media_changed(&info->devinfo);
 }
 
 static int idecd_revalidate_disk(struct gendisk *disk)
 {
-	struct cdrom_info *info = ide_cd_g(disk);
+	struct cdrom_info *info = ide_drv_g(disk, cdrom_info);
 	struct request_sense sense;
 
 	ide_cd_read_toc(info->drive, &sense);
@@ -2096,8 +2193,11 @@
 
 /* module options */
 static char *ignore;
-
 module_param(ignore, charp, 0400);
+
+static unsigned long debug_mask;
+module_param(debug_mask, ulong, 0644);
+
 MODULE_DESCRIPTION("ATAPI CD-ROM Driver");
 
 static int ide_cd_probe(ide_drive_t *drive)
@@ -2106,23 +2206,30 @@
 	struct gendisk *g;
 	struct request_sense sense;
 
+	ide_debug_log(IDE_DBG_PROBE, "Call %s, drive->driver_req: %s, "
+		      "drive->media: 0x%x\n", __func__, drive->driver_req,
+		      drive->media);
+
 	if (!strstr("ide-cdrom", drive->driver_req))
 		goto failed;
-	if (!drive->present)
-		goto failed;
+
 	if (drive->media != ide_cdrom && drive->media != ide_optical)
 		goto failed;
+
 	/* skip drives that we were told to ignore */
 	if (ignore != NULL) {
 		if (strstr(ignore, drive->name)) {
-			printk(KERN_INFO "ide-cd: ignoring drive %s\n",
+			printk(KERN_INFO PFX "ignoring drive %s\n",
 					 drive->name);
 			goto failed;
 		}
 	}
+
+	drive->debug_mask = debug_mask;
+
 	info = kzalloc(sizeof(struct cdrom_info), GFP_KERNEL);
 	if (info == NULL) {
-		printk(KERN_ERR "%s: Can't allocate a cdrom structure\n",
+		printk(KERN_ERR PFX "%s: Can't allocate a cdrom structure\n",
 				drive->name);
 		goto failed;
 	}
@@ -2133,8 +2240,6 @@
 
 	ide_init_disk(g, drive);
 
-	ide_proc_register_driver(drive, &ide_cdrom_driver);
-
 	kref_init(&info->kref);
 
 	info->drive = drive;
@@ -2149,7 +2254,6 @@
 	g->driverfs_dev = &drive->gendev;
 	g->flags = GENHD_FL_CD | GENHD_FL_REMOVABLE;
 	if (ide_cdrom_setup(drive)) {
-		ide_proc_unregister_driver(drive, &ide_cdrom_driver);
 		ide_cd_release(&info->kref);
 		goto failed;
 	}
@@ -2173,6 +2277,7 @@
 
 static int __init ide_cdrom_init(void)
 {
+	printk(KERN_INFO DRV_NAME " driver " IDECD_VERSION "\n");
 	return driver_register(&ide_cdrom_driver.gen_driver);
 }
 
diff --git a/drivers/ide/ide-cd.h b/drivers/ide/ide-cd.h
index 61a4599..5882b9a 100644
--- a/drivers/ide/ide-cd.h
+++ b/drivers/ide/ide-cd.h
@@ -88,7 +88,6 @@
 	struct request_sense sense_data;
 
 	struct request request_sense_request;
-	int dma;
 	unsigned long last_block;
 	unsigned long start_seek;
 
diff --git a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c
index 07ef88b..3853bde 100644
--- a/drivers/ide/ide-disk.c
+++ b/drivers/ide/ide-disk.c
@@ -30,10 +30,8 @@
 #include <linux/delay.h>
 #include <linux/mutex.h>
 #include <linux/leds.h>
-
-#define _IDE_DISK
-
 #include <linux/ide.h>
+#include <linux/hdreg.h>
 
 #include <asm/byteorder.h>
 #include <asm/irq.h>
@@ -41,21 +39,18 @@
 #include <asm/io.h>
 #include <asm/div64.h>
 
-struct ide_disk_obj {
-	ide_drive_t	*drive;
-	ide_driver_t	*driver;
-	struct gendisk	*disk;
-	struct kref	kref;
-	unsigned int	openers;	/* protected by BKL for now */
-};
+#if !defined(CONFIG_DEBUG_BLOCK_EXT_DEVT)
+#define IDE_DISK_MINORS		(1 << PARTN_BITS)
+#else
+#define IDE_DISK_MINORS		0
+#endif
+
+#include "ide-disk.h"
 
 static DEFINE_MUTEX(idedisk_ref_mutex);
 
 #define to_ide_disk(obj) container_of(obj, struct ide_disk_obj, kref)
 
-#define ide_disk_g(disk) \
-	container_of((disk)->private_data, struct ide_disk_obj, driver)
-
 static void ide_disk_release(struct kref *);
 
 static struct ide_disk_obj *ide_disk_get(struct gendisk *disk)
@@ -84,68 +79,19 @@
 	mutex_unlock(&idedisk_ref_mutex);
 }
 
-/*
- * lba_capacity_is_ok() performs a sanity check on the claimed "lba_capacity"
- * value for this drive (from its reported identification information).
- *
- * Returns:	1 if lba_capacity looks sensible
- *		0 otherwise
- *
- * It is called only once for each drive.
- */
-static int lba_capacity_is_ok(struct hd_driveid *id)
-{
-	unsigned long lba_sects, chs_sects, head, tail;
-
-	/* No non-LBA info .. so valid! */
-	if (id->cyls == 0)
-		return 1;
-
-	/*
-	 * The ATA spec tells large drives to return
-	 * C/H/S = 16383/16/63 independent of their size.
-	 * Some drives can be jumpered to use 15 heads instead of 16.
-	 * Some drives can be jumpered to use 4092 cyls instead of 16383.
-	 */
-	if ((id->cyls == 16383
-	     || (id->cyls == 4092 && id->cur_cyls == 16383)) &&
-	    id->sectors == 63 &&
-	    (id->heads == 15 || id->heads == 16) &&
-	    (id->lba_capacity >= 16383*63*id->heads))
-		return 1;
-
-	lba_sects   = id->lba_capacity;
-	chs_sects   = id->cyls * id->heads * id->sectors;
-
-	/* perform a rough sanity check on lba_sects:  within 10% is OK */
-	if ((lba_sects - chs_sects) < chs_sects/10)
-		return 1;
-
-	/* some drives have the word order reversed */
-	head = ((lba_sects >> 16) & 0xffff);
-	tail = (lba_sects & 0xffff);
-	lba_sects = (head | (tail << 16));
-	if ((lba_sects - chs_sects) < chs_sects/10) {
-		id->lba_capacity = lba_sects;
-		return 1;	/* lba_capacity is (now) good */
-	}
-
-	return 0;	/* lba_capacity value may be bad */
-}
-
 static const u8 ide_rw_cmds[] = {
-	WIN_MULTREAD,
-	WIN_MULTWRITE,
-	WIN_MULTREAD_EXT,
-	WIN_MULTWRITE_EXT,
-	WIN_READ,
-	WIN_WRITE,
-	WIN_READ_EXT,
-	WIN_WRITE_EXT,
-	WIN_READDMA,
-	WIN_WRITEDMA,
-	WIN_READDMA_EXT,
-	WIN_WRITEDMA_EXT,
+	ATA_CMD_READ_MULTI,
+	ATA_CMD_WRITE_MULTI,
+	ATA_CMD_READ_MULTI_EXT,
+	ATA_CMD_WRITE_MULTI_EXT,
+	ATA_CMD_PIO_READ,
+	ATA_CMD_PIO_WRITE,
+	ATA_CMD_PIO_READ_EXT,
+	ATA_CMD_PIO_WRITE_EXT,
+	ATA_CMD_READ,
+	ATA_CMD_WRITE,
+	ATA_CMD_READ_EXT,
+	ATA_CMD_WRITE_EXT,
 };
 
 static const u8 ide_data_phases[] = {
@@ -185,9 +131,9 @@
 					sector_t block)
 {
 	ide_hwif_t *hwif	= HWIF(drive);
-	unsigned int dma	= drive->using_dma;
 	u16 nsectors		= (u16)rq->nr_sectors;
-	u8 lba48		= (drive->addressing == 1) ? 1 : 0;
+	u8 lba48		= !!(drive->dev_flags & IDE_DFLAG_LBA48);
+	u8 dma			= !!(drive->dev_flags & IDE_DFLAG_USING_DMA);
 	ide_task_t		task;
 	struct ide_taskfile	*tf = &task.tf;
 	ide_startstop_t		rc;
@@ -207,7 +153,7 @@
 	memset(&task, 0, sizeof(task));
 	task.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
 
-	if (drive->select.b.lba) {
+	if (drive->dev_flags & IDE_DFLAG_LBA) {
 		if (lba48) {
 			pr_debug("%s: LBA=0x%012llx\n", drive->name,
 					(unsigned long long)block);
@@ -232,6 +178,8 @@
 			tf->lbah   = block >>= 8;
 			tf->device = (block >> 8) & 0xf;
 		}
+
+		tf->device |= ATA_LBA;
 	} else {
 		unsigned int sect, head, cyl, track;
 
@@ -282,7 +230,7 @@
 {
 	ide_hwif_t *hwif = HWIF(drive);
 
-	BUG_ON(drive->blocked);
+	BUG_ON(drive->dev_flags & IDE_DFLAG_BLOCKED);
 
 	if (!blk_fs_request(rq)) {
 		blk_dump_rq_flags(rq, "ide_do_rw_disk - bad command");
@@ -316,9 +264,9 @@
 	/* Create IDE/ATA command request structure */
 	memset(&args, 0, sizeof(ide_task_t));
 	if (lba48)
-		tf->command = WIN_READ_NATIVE_MAX_EXT;
+		tf->command = ATA_CMD_READ_NATIVE_MAX_EXT;
 	else
-		tf->command = WIN_READ_NATIVE_MAX;
+		tf->command = ATA_CMD_READ_NATIVE_MAX;
 	tf->device  = ATA_LBA;
 	args.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
 	if (lba48)
@@ -353,10 +301,10 @@
 		tf->hob_lbal = (addr_req >>= 8) & 0xff;
 		tf->hob_lbam = (addr_req >>= 8) & 0xff;
 		tf->hob_lbah = (addr_req >>= 8) & 0xff;
-		tf->command  = WIN_SET_MAX_EXT;
+		tf->command  = ATA_CMD_SET_MAX_EXT;
 	} else {
 		tf->device   = (addr_req >>= 8) & 0x0f;
-		tf->command  = WIN_SET_MAX;
+		tf->command  = ATA_CMD_SET_MAX;
 	}
 	tf->device |= ATA_LBA;
 	args.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
@@ -379,25 +327,6 @@
 }
 
 /*
- * Bits 10 of command_set_1 and cfs_enable_1 must be equal,
- * so on non-buggy drives we need test only one.
- * However, we should also check whether these fields are valid.
- */
-static inline int idedisk_supports_hpa(const struct hd_driveid *id)
-{
-	return (id->command_set_1 & 0x0400) && (id->cfs_enable_1 & 0x0400);
-}
-
-/*
- * The same here.
- */
-static inline int idedisk_supports_lba48(const struct hd_driveid *id)
-{
-	return (id->command_set_2 & 0x0400) && (id->cfs_enable_2 & 0x0400)
-	       && id->lba_capacity_2;
-}
-
-/*
  * Some disks report total number of sectors instead of
  * maximum sector address.  We list them here.
  */
@@ -411,7 +340,7 @@
 static void idedisk_check_hpa(ide_drive_t *drive)
 {
 	unsigned long long capacity, set_max;
-	int lba48 = idedisk_supports_lba48(drive->id);
+	int lba48 = ata_id_lba48_enabled(drive->id);
 
 	capacity = drive->capacity64;
 
@@ -447,139 +376,40 @@
 
 static void init_idedisk_capacity(ide_drive_t *drive)
 {
-	struct hd_driveid *id = drive->id;
-	/*
-	 * If this drive supports the Host Protected Area feature set,
-	 * then we may need to change our opinion about the drive's capacity.
-	 */
-	int hpa = idedisk_supports_hpa(id);
+	u16 *id = drive->id;
+	int lba;
 
-	if (idedisk_supports_lba48(id)) {
+	if (ata_id_lba48_enabled(id)) {
 		/* drive speaks 48-bit LBA */
-		drive->select.b.lba = 1;
-		drive->capacity64 = id->lba_capacity_2;
-		if (hpa)
-			idedisk_check_hpa(drive);
-	} else if ((id->capability & 2) && lba_capacity_is_ok(id)) {
+		lba = 1;
+		drive->capacity64 = ata_id_u64(id, ATA_ID_LBA_CAPACITY_2);
+	} else if (ata_id_has_lba(id) && ata_id_is_lba_capacity_ok(id)) {
 		/* drive speaks 28-bit LBA */
-		drive->select.b.lba = 1;
-		drive->capacity64 = id->lba_capacity;
-		if (hpa)
-			idedisk_check_hpa(drive);
+		lba = 1;
+		drive->capacity64 = ata_id_u32(id, ATA_ID_LBA_CAPACITY);
 	} else {
 		/* drive speaks boring old 28-bit CHS */
+		lba = 0;
 		drive->capacity64 = drive->cyl * drive->head * drive->sect;
 	}
-}
 
-static sector_t idedisk_capacity(ide_drive_t *drive)
-{
-	return drive->capacity64 - drive->sect0;
-}
+	if (lba) {
+		drive->dev_flags |= IDE_DFLAG_LBA;
 
-#ifdef CONFIG_IDE_PROC_FS
-static int smart_enable(ide_drive_t *drive)
-{
-	ide_task_t args;
-	struct ide_taskfile *tf = &args.tf;
-
-	memset(&args, 0, sizeof(ide_task_t));
-	tf->feature = SMART_ENABLE;
-	tf->lbam    = SMART_LCYL_PASS;
-	tf->lbah    = SMART_HCYL_PASS;
-	tf->command = WIN_SMART;
-	args.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
-	return ide_no_data_taskfile(drive, &args);
-}
-
-static int get_smart_data(ide_drive_t *drive, u8 *buf, u8 sub_cmd)
-{
-	ide_task_t args;
-	struct ide_taskfile *tf = &args.tf;
-
-	memset(&args, 0, sizeof(ide_task_t));
-	tf->feature = sub_cmd;
-	tf->nsect   = 0x01;
-	tf->lbam    = SMART_LCYL_PASS;
-	tf->lbah    = SMART_HCYL_PASS;
-	tf->command = WIN_SMART;
-	args.tf_flags	= IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
-	args.data_phase	= TASKFILE_IN;
-	(void) smart_enable(drive);
-	return ide_raw_taskfile(drive, &args, buf, 1);
-}
-
-static int proc_idedisk_read_cache
-	(char *page, char **start, off_t off, int count, int *eof, void *data)
-{
-	ide_drive_t	*drive = (ide_drive_t *) data;
-	char		*out = page;
-	int		len;
-
-	if (drive->id_read)
-		len = sprintf(out, "%i\n", drive->id->buf_size / 2);
-	else
-		len = sprintf(out, "(none)\n");
-
-	PROC_IDE_READ_RETURN(page, start, off, count, eof, len);
-}
-
-static int proc_idedisk_read_capacity
-	(char *page, char **start, off_t off, int count, int *eof, void *data)
-{
-	ide_drive_t*drive = (ide_drive_t *)data;
-	int len;
-
-	len = sprintf(page, "%llu\n", (long long)idedisk_capacity(drive));
-
-	PROC_IDE_READ_RETURN(page, start, off, count, eof, len);
-}
-
-static int proc_idedisk_read_smart(char *page, char **start, off_t off,
-				   int count, int *eof, void *data, u8 sub_cmd)
-{
-	ide_drive_t	*drive = (ide_drive_t *)data;
-	int		len = 0, i = 0;
-
-	if (get_smart_data(drive, page, sub_cmd) == 0) {
-		unsigned short *val = (unsigned short *) page;
-		char *out = ((char *)val) + (SECTOR_WORDS * 4);
-		page = out;
-		do {
-			out += sprintf(out, "%04x%c", le16_to_cpu(*val),
-				       (++i & 7) ? ' ' : '\n');
-			val += 1;
-		} while (i < (SECTOR_WORDS * 2));
-		len = out - page;
+		/*
+		* If this device supports the Host Protected Area feature set,
+		* then we may need to change our opinion about its capacity.
+		*/
+		if (ata_id_hpa_enabled(id))
+			idedisk_check_hpa(drive);
 	}
-
-	PROC_IDE_READ_RETURN(page, start, off, count, eof, len);
 }
 
-static int proc_idedisk_read_sv
-	(char *page, char **start, off_t off, int count, int *eof, void *data)
+sector_t ide_disk_capacity(ide_drive_t *drive)
 {
-	return proc_idedisk_read_smart(page, start, off, count, eof, data,
-				       SMART_READ_VALUES);
+	return drive->capacity64;
 }
 
-static int proc_idedisk_read_st
-	(char *page, char **start, off_t off, int count, int *eof, void *data)
-{
-	return proc_idedisk_read_smart(page, start, off, count, eof, data,
-				       SMART_READ_THRESHOLDS);
-}
-
-static ide_proc_entry_t idedisk_proc[] = {
-	{ "cache",	  S_IFREG|S_IRUGO, proc_idedisk_read_cache,    NULL },
-	{ "capacity",	  S_IFREG|S_IRUGO, proc_idedisk_read_capacity, NULL },
-	{ "geometry",	  S_IFREG|S_IRUGO, proc_ide_read_geometry,     NULL },
-	{ "smart_values", S_IFREG|S_IRUSR, proc_idedisk_read_sv,       NULL },
-	{ "smart_thresholds", S_IFREG|S_IRUSR, proc_idedisk_read_st,   NULL },
-	{ NULL, 0, NULL, NULL }
-};
-#endif	/* CONFIG_IDE_PROC_FS */
-
 static void idedisk_prepare_flush(struct request_queue *q, struct request *rq)
 {
 	ide_drive_t *drive = q->queuedata;
@@ -589,11 +419,11 @@
 	BUG_ON(task == NULL);
 
 	memset(task, 0, sizeof(*task));
-	if (ide_id_has_flush_cache_ext(drive->id) &&
+	if (ata_id_flush_ext_enabled(drive->id) &&
 	    (drive->capacity64 >= (1UL << 28)))
-		task->tf.command = WIN_FLUSH_CACHE_EXT;
+		task->tf.command = ATA_CMD_FLUSH_EXT;
 	else
-		task->tf.command = WIN_FLUSH_CACHE;
+		task->tf.command = ATA_CMD_FLUSH;
 	task->tf_flags	 = IDE_TFLAG_OUT_TF | IDE_TFLAG_OUT_DEVICE |
 			   IDE_TFLAG_DYN;
 	task->data_phase = TASKFILE_NO_DATA;
@@ -603,6 +433,8 @@
 	rq->special = task;
 }
 
+ide_devset_get(multcount, mult_count);
+
 /*
  * This is tightly woven into the driver->do_special can not touch.
  * DON'T do it again until a total personality rewrite is committed.
@@ -612,7 +444,7 @@
 	struct request *rq;
 	int error;
 
-	if (arg < 0 || arg > drive->id->max_multsect)
+	if (arg < 0 || arg > (drive->id[ATA_ID_MAX_MULTSECT] & 0xff))
 		return -EINVAL;
 
 	if (drive->special.b.set_multmode)
@@ -629,26 +461,43 @@
 	return (drive->mult_count == arg) ? 0 : -EIO;
 }
 
+ide_devset_get_flag(nowerr, IDE_DFLAG_NOWERR);
+
 static int set_nowerr(ide_drive_t *drive, int arg)
 {
 	if (arg < 0 || arg > 1)
 		return -EINVAL;
 
-	if (ide_spin_wait_hwgroup(drive))
-		return -EBUSY;
-	drive->nowerr = arg;
+	if (arg)
+		drive->dev_flags |= IDE_DFLAG_NOWERR;
+	else
+		drive->dev_flags &= ~IDE_DFLAG_NOWERR;
+
 	drive->bad_wstat = arg ? BAD_R_STAT : BAD_W_STAT;
-	spin_unlock_irq(&ide_lock);
+
 	return 0;
 }
 
+static int ide_do_setfeature(ide_drive_t *drive, u8 feature, u8 nsect)
+{
+	ide_task_t task;
+
+	memset(&task, 0, sizeof(task));
+	task.tf.feature = feature;
+	task.tf.nsect   = nsect;
+	task.tf.command = ATA_CMD_SET_FEATURES;
+	task.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
+
+	return ide_no_data_taskfile(drive, &task);
+}
+
 static void update_ordered(ide_drive_t *drive)
 {
-	struct hd_driveid *id = drive->id;
+	u16 *id = drive->id;
 	unsigned ordered = QUEUE_ORDERED_NONE;
 	prepare_flush_fn *prep_fn = NULL;
 
-	if (drive->wcache) {
+	if (drive->dev_flags & IDE_DFLAG_WCACHE) {
 		unsigned long long capacity;
 		int barrier;
 		/*
@@ -659,10 +508,12 @@
 		 * time we have trimmed the drive capacity if LBA48 is
 		 * not available so we don't need to recheck that.
 		 */
-		capacity = idedisk_capacity(drive);
-		barrier = ide_id_has_flush_cache(id) && !drive->noflush &&
-			(drive->addressing == 0 || capacity <= (1ULL << 28) ||
-			 ide_id_has_flush_cache_ext(id));
+		capacity = ide_disk_capacity(drive);
+		barrier = ata_id_flush_enabled(id) &&
+			(drive->dev_flags & IDE_DFLAG_NOFLUSH) == 0 &&
+			((drive->dev_flags & IDE_DFLAG_LBA48) == 0 ||
+			 capacity <= (1ULL << 28) ||
+			 ata_id_flush_ext_enabled(id));
 
 		printk(KERN_INFO "%s: cache flushes %ssupported\n",
 		       drive->name, barrier ? "" : "not ");
@@ -677,23 +528,24 @@
 	blk_queue_ordered(drive->queue, ordered, prep_fn);
 }
 
-static int write_cache(ide_drive_t *drive, int arg)
+ide_devset_get_flag(wcache, IDE_DFLAG_WCACHE);
+
+static int set_wcache(ide_drive_t *drive, int arg)
 {
-	ide_task_t args;
 	int err = 1;
 
 	if (arg < 0 || arg > 1)
 		return -EINVAL;
 
-	if (ide_id_has_flush_cache(drive->id)) {
-		memset(&args, 0, sizeof(ide_task_t));
-		args.tf.feature = arg ?
-			SETFEATURES_EN_WCACHE : SETFEATURES_DIS_WCACHE;
-		args.tf.command = WIN_SETFEATURES;
-		args.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
-		err = ide_no_data_taskfile(drive, &args);
-		if (err == 0)
-			drive->wcache = arg;
+	if (ata_id_flush_enabled(drive->id)) {
+		err = ide_do_setfeature(drive,
+			arg ? SETFEATURES_WC_ON : SETFEATURES_WC_OFF, 0);
+		if (err == 0) {
+			if (arg)
+				drive->dev_flags |= IDE_DFLAG_WCACHE;
+			else
+				drive->dev_flags &= ~IDE_DFLAG_WCACHE;
+		}
 	}
 
 	update_ordered(drive);
@@ -706,108 +558,88 @@
 	ide_task_t args;
 
 	memset(&args, 0, sizeof(ide_task_t));
-	if (ide_id_has_flush_cache_ext(drive->id))
-		args.tf.command = WIN_FLUSH_CACHE_EXT;
+	if (ata_id_flush_ext_enabled(drive->id))
+		args.tf.command = ATA_CMD_FLUSH_EXT;
 	else
-		args.tf.command = WIN_FLUSH_CACHE;
+		args.tf.command = ATA_CMD_FLUSH;
 	args.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
 	return ide_no_data_taskfile(drive, &args);
 }
 
+ide_devset_get(acoustic, acoustic);
+
 static int set_acoustic(ide_drive_t *drive, int arg)
 {
-	ide_task_t args;
-
 	if (arg < 0 || arg > 254)
 		return -EINVAL;
 
-	memset(&args, 0, sizeof(ide_task_t));
-	args.tf.feature = arg ? SETFEATURES_EN_AAM : SETFEATURES_DIS_AAM;
-	args.tf.nsect   = arg;
-	args.tf.command = WIN_SETFEATURES;
-	args.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
-	ide_no_data_taskfile(drive, &args);
+	ide_do_setfeature(drive,
+		arg ? SETFEATURES_AAM_ON : SETFEATURES_AAM_OFF, arg);
+
 	drive->acoustic = arg;
+
 	return 0;
 }
 
+ide_devset_get_flag(addressing, IDE_DFLAG_LBA48);
+
 /*
  * drive->addressing:
  *	0: 28-bit
  *	1: 48-bit
  *	2: 48-bit capable doing 28-bit
  */
-static int set_lba_addressing(ide_drive_t *drive, int arg)
+static int set_addressing(ide_drive_t *drive, int arg)
 {
 	if (arg < 0 || arg > 2)
 		return -EINVAL;
 
-	drive->addressing =  0;
-
-	if (drive->hwif->host_flags & IDE_HFLAG_NO_LBA48)
-		return 0;
-
-	if (!idedisk_supports_lba48(drive->id))
+	if (arg && ((drive->hwif->host_flags & IDE_HFLAG_NO_LBA48) ||
+	    ata_id_lba48_enabled(drive->id) == 0))
 		return -EIO;
-	drive->addressing = arg;
+
+	if (arg == 2)
+		arg = 0;
+
+	if (arg)
+		drive->dev_flags |= IDE_DFLAG_LBA48;
+	else
+		drive->dev_flags &= ~IDE_DFLAG_LBA48;
+
 	return 0;
 }
 
-#ifdef CONFIG_IDE_PROC_FS
-static void idedisk_add_settings(ide_drive_t *drive)
-{
-	struct hd_driveid *id = drive->id;
+ide_ext_devset_rw(acoustic, acoustic);
+ide_ext_devset_rw(address, addressing);
+ide_ext_devset_rw(multcount, multcount);
+ide_ext_devset_rw(wcache, wcache);
 
-	ide_add_setting(drive, "bios_cyl", SETTING_RW, TYPE_INT, 0, 65535, 1, 1,
-			&drive->bios_cyl, NULL);
-	ide_add_setting(drive, "bios_head", SETTING_RW, TYPE_BYTE, 0, 255, 1, 1,
-			&drive->bios_head, NULL);
-	ide_add_setting(drive, "bios_sect", SETTING_RW, TYPE_BYTE, 0, 63, 1, 1,
-			&drive->bios_sect, NULL);
-	ide_add_setting(drive, "address", SETTING_RW, TYPE_BYTE, 0, 2, 1, 1,
-			&drive->addressing, set_lba_addressing);
-	ide_add_setting(drive, "multcount", SETTING_RW, TYPE_BYTE, 0,
-			id->max_multsect, 1, 1, &drive->mult_count,
-			set_multcount);
-	ide_add_setting(drive, "nowerr", SETTING_RW, TYPE_BYTE, 0, 1, 1, 1,
-			&drive->nowerr, set_nowerr);
-	ide_add_setting(drive, "lun", SETTING_RW, TYPE_INT, 0, 7, 1, 1,
-			&drive->lun, NULL);
-	ide_add_setting(drive, "wcache", SETTING_RW, TYPE_BYTE, 0, 1, 1, 1,
-			&drive->wcache, write_cache);
-	ide_add_setting(drive, "acoustic", SETTING_RW, TYPE_BYTE, 0, 254, 1, 1,
-			&drive->acoustic, set_acoustic);
-	ide_add_setting(drive, "failures", SETTING_RW, TYPE_INT, 0, 65535, 1, 1,
-			&drive->failures, NULL);
-	ide_add_setting(drive, "max_failures", SETTING_RW, TYPE_INT, 0, 65535,
-			1, 1, &drive->max_failures, NULL);
-}
-#else
-static inline void idedisk_add_settings(ide_drive_t *drive) { ; }
-#endif
+ide_ext_devset_rw_sync(nowerr, nowerr);
 
 static void idedisk_setup(ide_drive_t *drive)
 {
+	struct ide_disk_obj *idkp = drive->driver_data;
 	ide_hwif_t *hwif = drive->hwif;
-	struct hd_driveid *id = drive->id;
+	u16 *id = drive->id;
+	char *m = (char *)&id[ATA_ID_PROD];
 	unsigned long long capacity;
 
-	idedisk_add_settings(drive);
+	ide_proc_register_driver(drive, idkp->driver);
 
-	if (drive->id_read == 0)
+	if ((drive->dev_flags & IDE_DFLAG_ID_READ) == 0)
 		return;
 
-	if (drive->removable) {
+	if (drive->dev_flags & IDE_DFLAG_REMOVABLE) {
 		/*
 		 * Removable disks (eg. SYQUEST); ignore 'WD' drives
 		 */
-		if (id->model[0] != 'W' || id->model[1] != 'D')
-			drive->doorlocking = 1;
+		if (m[0] != 'W' || m[1] != 'D')
+			drive->dev_flags |= IDE_DFLAG_DOORLOCKING;
 	}
 
-	(void)set_lba_addressing(drive, 1);
+	(void)set_addressing(drive, 1);
 
-	if (drive->addressing == 1) {
+	if (drive->dev_flags & IDE_DFLAG_LBA48) {
 		int max_s = 2048;
 
 		if (max_s > hwif->rqsize)
@@ -823,7 +655,8 @@
 	init_idedisk_capacity(drive);
 
 	/* limit drive capacity to 137GB if LBA48 cannot be used */
-	if (drive->addressing == 0 && drive->capacity64 > 1ULL << 28) {
+	if ((drive->dev_flags & IDE_DFLAG_LBA48) == 0 &&
+	    drive->capacity64 > 1ULL << 28) {
 		printk(KERN_WARNING "%s: cannot use LBA48 - full capacity "
 		       "%llu sectors (%llu MB)\n",
 		       drive->name, (unsigned long long)drive->capacity64,
@@ -831,24 +664,24 @@
 		drive->capacity64 = 1ULL << 28;
 	}
 
-	if ((hwif->host_flags & IDE_HFLAG_NO_LBA48_DMA) && drive->addressing) {
+	if ((hwif->host_flags & IDE_HFLAG_NO_LBA48_DMA) &&
+	    (drive->dev_flags & IDE_DFLAG_LBA48)) {
 		if (drive->capacity64 > 1ULL << 28) {
 			printk(KERN_INFO "%s: cannot use LBA48 DMA - PIO mode"
 					 " will be used for accessing sectors "
 					 "> %u\n", drive->name, 1 << 28);
 		} else
-			drive->addressing = 0;
+			drive->dev_flags &= ~IDE_DFLAG_LBA48;
 	}
 
 	/*
 	 * if possible, give fdisk access to more of the drive,
 	 * by correcting bios_cyls:
 	 */
-	capacity = idedisk_capacity(drive);
+	capacity = ide_disk_capacity(drive);
 
-	if (!drive->forced_geom) {
-
-		if (idedisk_supports_lba48(drive->id)) {
+	if ((drive->dev_flags & IDE_DFLAG_FORCED_GEOM) == 0) {
+		if (ata_id_lba48_enabled(drive->id)) {
 			/* compatibility */
 			drive->bios_sect = 63;
 			drive->bios_head = 255;
@@ -874,22 +707,23 @@
 			 drive->name, capacity, sectors_to_MB(capacity));
 
 	/* Only print cache size when it was specified */
-	if (id->buf_size)
-		printk(KERN_CONT " w/%dKiB Cache", id->buf_size / 2);
+	if (id[ATA_ID_BUF_SIZE])
+		printk(KERN_CONT " w/%dKiB Cache", id[ATA_ID_BUF_SIZE] / 2);
 
 	printk(KERN_CONT ", CHS=%d/%d/%d\n",
 			 drive->bios_cyl, drive->bios_head, drive->bios_sect);
 
 	/* write cache enabled? */
-	if ((id->csfo & 1) || (id->cfs_enable_1 & (1 << 5)))
-		drive->wcache = 1;
+	if ((id[ATA_ID_CSFO] & 1) || ata_id_wcache_enabled(id))
+		drive->dev_flags |= IDE_DFLAG_WCACHE;
 
-	write_cache(drive, 1);
+	set_wcache(drive, 1);
 }
 
 static void ide_cacheflush_p(ide_drive_t *drive)
 {
-	if (!drive->wcache || !ide_id_has_flush_cache(drive->id))
+	if (ata_id_flush_enabled(drive->id) == 0 ||
+	    (drive->dev_flags & IDE_DFLAG_WCACHE) == 0)
 		return;
 
 	if (do_idedisk_flushcache(drive))
@@ -931,7 +765,7 @@
  */
 static void ide_disk_resume(ide_drive_t *drive)
 {
-	if (idedisk_supports_hpa(drive->id))
+	if (ata_id_hpa_enabled(drive->id))
 		init_idedisk_capacity(drive);
 }
 
@@ -973,13 +807,12 @@
 	.resume			= ide_disk_resume,
 	.shutdown		= ide_device_shutdown,
 	.version		= IDEDISK_VERSION,
-	.media			= ide_disk,
-	.supports_dsc_overlap	= 0,
 	.do_request		= ide_do_rw_disk,
 	.end_request		= ide_end_request,
 	.error			= __ide_error,
 #ifdef CONFIG_IDE_PROC_FS
-	.proc			= idedisk_proc,
+	.proc			= ide_disk_proc,
+	.settings		= ide_disk_settings,
 #endif
 };
 
@@ -988,7 +821,7 @@
 	ide_task_t task;
 
 	memset(&task, 0, sizeof(task));
-	task.tf.command = on ? WIN_DOORLOCK : WIN_DOORUNLOCK;
+	task.tf.command = on ? ATA_CMD_MEDIA_LOCK : ATA_CMD_MEDIA_UNLOCK;
 	task.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
 
 	return ide_no_data_taskfile(drive, &task);
@@ -1008,15 +841,16 @@
 
 	idkp->openers++;
 
-	if (drive->removable && idkp->openers == 1) {
+	if ((drive->dev_flags & IDE_DFLAG_REMOVABLE) && idkp->openers == 1) {
 		check_disk_change(inode->i_bdev);
 		/*
 		 * Ignore the return code from door_lock,
 		 * since the open() has already succeeded,
 		 * and the door_lock is irrelevant at this point.
 		 */
-		if (drive->doorlocking && idedisk_set_doorlock(drive, 1))
-			drive->doorlocking = 0;
+		if ((drive->dev_flags & IDE_DFLAG_DOORLOCKING) &&
+		    idedisk_set_doorlock(drive, 1))
+			drive->dev_flags &= ~IDE_DFLAG_DOORLOCKING;
 	}
 	return 0;
 }
@@ -1030,9 +864,10 @@
 	if (idkp->openers == 1)
 		ide_cacheflush_p(drive);
 
-	if (drive->removable && idkp->openers == 1) {
-		if (drive->doorlocking && idedisk_set_doorlock(drive, 0))
-			drive->doorlocking = 0;
+	if ((drive->dev_flags & IDE_DFLAG_REMOVABLE) && idkp->openers == 1) {
+		if ((drive->dev_flags & IDE_DFLAG_DOORLOCKING) &&
+		    idedisk_set_doorlock(drive, 0))
+			drive->dev_flags &= ~IDE_DFLAG_DOORLOCKING;
 	}
 
 	idkp->openers--;
@@ -1053,72 +888,25 @@
 	return 0;
 }
 
-static int idedisk_ioctl(struct inode *inode, struct file *file,
-			unsigned int cmd, unsigned long arg)
-{
-	unsigned long flags;
-	struct block_device *bdev = inode->i_bdev;
-	struct ide_disk_obj *idkp = ide_disk_g(bdev->bd_disk);
-	ide_drive_t *drive = idkp->drive;
-	int err, (*setfunc)(ide_drive_t *, int);
-	u8 *val;
-
-	switch (cmd) {
-	case HDIO_GET_ADDRESS:	 val = &drive->addressing;	goto read_val;
-	case HDIO_GET_MULTCOUNT: val = &drive->mult_count;	goto read_val;
-	case HDIO_GET_NOWERR:	 val = &drive->nowerr;		goto read_val;
-	case HDIO_GET_WCACHE:	 val = &drive->wcache;		goto read_val;
-	case HDIO_GET_ACOUSTIC:	 val = &drive->acoustic;	goto read_val;
-	case HDIO_SET_ADDRESS:	 setfunc = set_lba_addressing;	goto set_val;
-	case HDIO_SET_MULTCOUNT: setfunc = set_multcount;	goto set_val;
-	case HDIO_SET_NOWERR:	 setfunc = set_nowerr;		goto set_val;
-	case HDIO_SET_WCACHE:	 setfunc = write_cache;		goto set_val;
-	case HDIO_SET_ACOUSTIC:	 setfunc = set_acoustic;	goto set_val;
-	}
-
-	return generic_ide_ioctl(drive, file, bdev, cmd, arg);
-
-read_val:
-	mutex_lock(&ide_setting_mtx);
-	spin_lock_irqsave(&ide_lock, flags);
-	err = *val;
-	spin_unlock_irqrestore(&ide_lock, flags);
-	mutex_unlock(&ide_setting_mtx);
-	return err >= 0 ? put_user(err, (long __user *)arg) : err;
-
-set_val:
-	if (bdev != bdev->bd_contains)
-		err = -EINVAL;
-	else {
-		if (!capable(CAP_SYS_ADMIN))
-			err = -EACCES;
-		else {
-			mutex_lock(&ide_setting_mtx);
-			err = setfunc(drive, arg);
-			mutex_unlock(&ide_setting_mtx);
-		}
-	}
-	return err;
-}
-
 static int idedisk_media_changed(struct gendisk *disk)
 {
 	struct ide_disk_obj *idkp = ide_disk_g(disk);
 	ide_drive_t *drive = idkp->drive;
 
 	/* do not scan partitions twice if this is a removable device */
-	if (drive->attach) {
-		drive->attach = 0;
+	if (drive->dev_flags & IDE_DFLAG_ATTACH) {
+		drive->dev_flags &= ~IDE_DFLAG_ATTACH;
 		return 0;
 	}
+
 	/* if removable, always assume it was changed */
-	return drive->removable;
+	return !!(drive->dev_flags & IDE_DFLAG_REMOVABLE);
 }
 
 static int idedisk_revalidate_disk(struct gendisk *disk)
 {
 	struct ide_disk_obj *idkp = ide_disk_g(disk);
-	set_capacity(disk, idedisk_capacity(idkp->drive));
+	set_capacity(disk, ide_disk_capacity(idkp->drive));
 	return 0;
 }
 
@@ -1126,7 +914,7 @@
 	.owner			= THIS_MODULE,
 	.open			= idedisk_open,
 	.release		= idedisk_release,
-	.ioctl			= idedisk_ioctl,
+	.ioctl			= ide_disk_ioctl,
 	.getgeo			= idedisk_getgeo,
 	.media_changed		= idedisk_media_changed,
 	.revalidate_disk	= idedisk_revalidate_disk
@@ -1142,8 +930,7 @@
 	/* strstr("foo", "") is non-NULL */
 	if (!strstr("ide-disk", drive->driver_req))
 		goto failed;
-	if (!drive->present)
-		goto failed;
+
 	if (drive->media != ide_disk)
 		goto failed;
 
@@ -1151,15 +938,12 @@
 	if (!idkp)
 		goto failed;
 
-	g = alloc_disk_node(1 << PARTN_BITS,
-			hwif_to_node(drive->hwif));
+	g = alloc_disk_node(IDE_DISK_MINORS, hwif_to_node(drive->hwif));
 	if (!g)
 		goto out_free_idkp;
 
 	ide_init_disk(g, drive);
 
-	ide_proc_register_driver(drive, &idedisk_driver);
-
 	kref_init(&idkp->kref);
 
 	idkp->drive = drive;
@@ -1171,17 +955,20 @@
 	drive->driver_data = idkp;
 
 	idedisk_setup(drive);
-	if ((!drive->head || drive->head > 16) && !drive->select.b.lba) {
+	if ((drive->dev_flags & IDE_DFLAG_LBA) == 0 &&
+	    (drive->head == 0 || drive->head > 16)) {
 		printk(KERN_ERR "%s: INVALID GEOMETRY: %d PHYSICAL HEADS?\n",
 			drive->name, drive->head);
-		drive->attach = 0;
+		drive->dev_flags &= ~IDE_DFLAG_ATTACH;
 	} else
-		drive->attach = 1;
+		drive->dev_flags |= IDE_DFLAG_ATTACH;
 
-	g->minors = 1 << PARTN_BITS;
+	g->minors = IDE_DISK_MINORS;
 	g->driverfs_dev = &drive->gendev;
-	g->flags = drive->removable ? GENHD_FL_REMOVABLE : 0;
-	set_capacity(g, idedisk_capacity(drive));
+	g->flags |= GENHD_FL_EXT_DEVT;
+	if (drive->dev_flags & IDE_DFLAG_REMOVABLE)
+		g->flags = GENHD_FL_REMOVABLE;
+	set_capacity(g, ide_disk_capacity(drive));
 	g->fops = &idedisk_ops;
 	add_disk(g);
 	return 0;
@@ -1203,6 +990,7 @@
 }
 
 MODULE_ALIAS("ide:*m-disk*");
+MODULE_ALIAS("ide-disk");
 module_init(idedisk_init);
 module_exit(idedisk_exit);
 MODULE_LICENSE("GPL");
diff --git a/drivers/ide/ide-disk.h b/drivers/ide/ide-disk.h
new file mode 100644
index 0000000..a82fa43
--- /dev/null
+++ b/drivers/ide/ide-disk.h
@@ -0,0 +1,32 @@
+#ifndef __IDE_DISK_H
+#define __IDE_DISK_H
+
+struct ide_disk_obj {
+	ide_drive_t	*drive;
+	ide_driver_t	*driver;
+	struct gendisk	*disk;
+	struct kref	kref;
+	unsigned int	openers;	/* protected by BKL for now */
+};
+
+#define ide_disk_g(disk) \
+	container_of((disk)->private_data, struct ide_disk_obj, driver)
+
+/* ide-disk.c */
+sector_t ide_disk_capacity(ide_drive_t *);
+ide_decl_devset(address);
+ide_decl_devset(multcount);
+ide_decl_devset(nowerr);
+ide_decl_devset(wcache);
+ide_decl_devset(acoustic);
+
+/* ide-disk_ioctl.c */
+int ide_disk_ioctl(struct inode *, struct file *, unsigned int, unsigned long);
+
+#ifdef CONFIG_IDE_PROC_FS
+/* ide-disk_proc.c */
+extern ide_proc_entry_t ide_disk_proc[];
+extern const struct ide_proc_devset ide_disk_settings[];
+#endif
+
+#endif /* __IDE_DISK_H */
diff --git a/drivers/ide/ide-disk_ioctl.c b/drivers/ide/ide-disk_ioctl.c
new file mode 100644
index 0000000..a6cf1a03
--- /dev/null
+++ b/drivers/ide/ide-disk_ioctl.c
@@ -0,0 +1,29 @@
+#include <linux/kernel.h>
+#include <linux/ide.h>
+#include <linux/hdreg.h>
+
+#include "ide-disk.h"
+
+static const struct ide_ioctl_devset ide_disk_ioctl_settings[] = {
+{ HDIO_GET_ADDRESS,	HDIO_SET_ADDRESS,   &ide_devset_address   },
+{ HDIO_GET_MULTCOUNT,	HDIO_SET_MULTCOUNT, &ide_devset_multcount },
+{ HDIO_GET_NOWERR,	HDIO_SET_NOWERR,    &ide_devset_nowerr	  },
+{ HDIO_GET_WCACHE,	HDIO_SET_WCACHE,    &ide_devset_wcache	  },
+{ HDIO_GET_ACOUSTIC,	HDIO_SET_ACOUSTIC,  &ide_devset_acoustic  },
+{ 0 }
+};
+
+int ide_disk_ioctl(struct inode *inode, struct file *file,
+		   unsigned int cmd, unsigned long arg)
+{
+	struct block_device *bdev = inode->i_bdev;
+	struct ide_disk_obj *idkp = ide_disk_g(bdev->bd_disk);
+	ide_drive_t *drive = idkp->drive;
+	int err;
+
+	err = ide_setting_ioctl(drive, bdev, cmd, arg, ide_disk_ioctl_settings);
+	if (err != -EOPNOTSUPP)
+		return err;
+
+	return generic_ide_ioctl(drive, file, bdev, cmd, arg);
+}
diff --git a/drivers/ide/ide-disk_proc.c b/drivers/ide/ide-disk_proc.c
new file mode 100644
index 0000000..4724976
--- /dev/null
+++ b/drivers/ide/ide-disk_proc.c
@@ -0,0 +1,129 @@
+#include <linux/kernel.h>
+#include <linux/ide.h>
+#include <linux/hdreg.h>
+
+#include "ide-disk.h"
+
+static int smart_enable(ide_drive_t *drive)
+{
+	ide_task_t args;
+	struct ide_taskfile *tf = &args.tf;
+
+	memset(&args, 0, sizeof(ide_task_t));
+	tf->feature = ATA_SMART_ENABLE;
+	tf->lbam    = ATA_SMART_LBAM_PASS;
+	tf->lbah    = ATA_SMART_LBAH_PASS;
+	tf->command = ATA_CMD_SMART;
+	args.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
+	return ide_no_data_taskfile(drive, &args);
+}
+
+static int get_smart_data(ide_drive_t *drive, u8 *buf, u8 sub_cmd)
+{
+	ide_task_t args;
+	struct ide_taskfile *tf = &args.tf;
+
+	memset(&args, 0, sizeof(ide_task_t));
+	tf->feature = sub_cmd;
+	tf->nsect   = 0x01;
+	tf->lbam    = ATA_SMART_LBAM_PASS;
+	tf->lbah    = ATA_SMART_LBAH_PASS;
+	tf->command = ATA_CMD_SMART;
+	args.tf_flags	= IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
+	args.data_phase	= TASKFILE_IN;
+	(void) smart_enable(drive);
+	return ide_raw_taskfile(drive, &args, buf, 1);
+}
+
+static int proc_idedisk_read_cache
+	(char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+	ide_drive_t	*drive = (ide_drive_t *) data;
+	char		*out = page;
+	int		len;
+
+	if (drive->dev_flags & IDE_DFLAG_ID_READ)
+		len = sprintf(out, "%i\n", drive->id[ATA_ID_BUF_SIZE] / 2);
+	else
+		len = sprintf(out, "(none)\n");
+
+	PROC_IDE_READ_RETURN(page, start, off, count, eof, len);
+}
+
+static int proc_idedisk_read_capacity
+	(char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+	ide_drive_t*drive = (ide_drive_t *)data;
+	int len;
+
+	len = sprintf(page, "%llu\n", (long long)ide_disk_capacity(drive));
+
+	PROC_IDE_READ_RETURN(page, start, off, count, eof, len);
+}
+
+static int proc_idedisk_read_smart(char *page, char **start, off_t off,
+				   int count, int *eof, void *data, u8 sub_cmd)
+{
+	ide_drive_t	*drive = (ide_drive_t *)data;
+	int		len = 0, i = 0;
+
+	if (get_smart_data(drive, page, sub_cmd) == 0) {
+		unsigned short *val = (unsigned short *) page;
+		char *out = (char *)val + SECTOR_SIZE;
+
+		page = out;
+		do {
+			out += sprintf(out, "%04x%c", le16_to_cpu(*val),
+				       (++i & 7) ? ' ' : '\n');
+			val += 1;
+		} while (i < SECTOR_SIZE / 2);
+		len = out - page;
+	}
+
+	PROC_IDE_READ_RETURN(page, start, off, count, eof, len);
+}
+
+static int proc_idedisk_read_sv
+	(char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+	return proc_idedisk_read_smart(page, start, off, count, eof, data,
+				       ATA_SMART_READ_VALUES);
+}
+
+static int proc_idedisk_read_st
+	(char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+	return proc_idedisk_read_smart(page, start, off, count, eof, data,
+				       ATA_SMART_READ_THRESHOLDS);
+}
+
+ide_proc_entry_t ide_disk_proc[] = {
+	{ "cache",	  S_IFREG|S_IRUGO, proc_idedisk_read_cache,    NULL },
+	{ "capacity",	  S_IFREG|S_IRUGO, proc_idedisk_read_capacity, NULL },
+	{ "geometry",	  S_IFREG|S_IRUGO, proc_ide_read_geometry,     NULL },
+	{ "smart_values", S_IFREG|S_IRUSR, proc_idedisk_read_sv,       NULL },
+	{ "smart_thresholds", S_IFREG|S_IRUSR, proc_idedisk_read_st,   NULL },
+	{ NULL, 0, NULL, NULL }
+};
+
+ide_devset_rw_field(bios_cyl, bios_cyl);
+ide_devset_rw_field(bios_head, bios_head);
+ide_devset_rw_field(bios_sect, bios_sect);
+ide_devset_rw_field(failures, failures);
+ide_devset_rw_field(lun, lun);
+ide_devset_rw_field(max_failures, max_failures);
+
+const struct ide_proc_devset ide_disk_settings[] = {
+	IDE_PROC_DEVSET(acoustic,	0,   254),
+	IDE_PROC_DEVSET(address,	0,     2),
+	IDE_PROC_DEVSET(bios_cyl,	0, 65535),
+	IDE_PROC_DEVSET(bios_head,	0,   255),
+	IDE_PROC_DEVSET(bios_sect,	0,    63),
+	IDE_PROC_DEVSET(failures,	0, 65535),
+	IDE_PROC_DEVSET(lun,		0,     7),
+	IDE_PROC_DEVSET(max_failures,	0, 65535),
+	IDE_PROC_DEVSET(multcount,	0,    16),
+	IDE_PROC_DEVSET(nowerr,		0,     1),
+	IDE_PROC_DEVSET(wcache,		0,     1),
+	{ 0 },
+};
diff --git a/drivers/ide/ide-dma-sff.c b/drivers/ide/ide-dma-sff.c
new file mode 100644
index 0000000..0903782
--- /dev/null
+++ b/drivers/ide/ide-dma-sff.c
@@ -0,0 +1,356 @@
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/ide.h>
+#include <linux/scatterlist.h>
+#include <linux/dma-mapping.h>
+#include <linux/io.h>
+
+/**
+ *	config_drive_for_dma	-	attempt to activate IDE DMA
+ *	@drive: the drive to place in DMA mode
+ *
+ *	If the drive supports at least mode 2 DMA or UDMA of any kind
+ *	then attempt to place it into DMA mode. Drives that are known to
+ *	support DMA but predate the DMA properties or that are known
+ *	to have DMA handling bugs are also set up appropriately based
+ *	on the good/bad drive lists.
+ */
+
+int config_drive_for_dma(ide_drive_t *drive)
+{
+	ide_hwif_t *hwif = drive->hwif;
+	u16 *id = drive->id;
+
+	if (drive->media != ide_disk) {
+		if (hwif->host_flags & IDE_HFLAG_NO_ATAPI_DMA)
+			return 0;
+	}
+
+	/*
+	 * Enable DMA on any drive that has
+	 * UltraDMA (mode 0/1/2/3/4/5/6) enabled
+	 */
+	if ((id[ATA_ID_FIELD_VALID] & 4) &&
+	    ((id[ATA_ID_UDMA_MODES] >> 8) & 0x7f))
+		return 1;
+
+	/*
+	 * Enable DMA on any drive that has mode2 DMA
+	 * (multi or single) enabled
+	 */
+	if (id[ATA_ID_FIELD_VALID] & 2)	/* regular DMA */
+		if ((id[ATA_ID_MWDMA_MODES] & 0x404) == 0x404 ||
+		    (id[ATA_ID_SWDMA_MODES] & 0x404) == 0x404)
+			return 1;
+
+	/* Consult the list of known "good" drives */
+	if (ide_dma_good_drive(drive))
+		return 1;
+
+	return 0;
+}
+
+/**
+ *	ide_dma_host_set	-	Enable/disable DMA on a host
+ *	@drive: drive to control
+ *
+ *	Enable/disable DMA on an IDE controller following generic
+ *	bus-mastering IDE controller behaviour.
+ */
+
+void ide_dma_host_set(ide_drive_t *drive, int on)
+{
+	ide_hwif_t *hwif = drive->hwif;
+	u8 unit = drive->dn & 1;
+	u8 dma_stat = hwif->tp_ops->read_sff_dma_status(hwif);
+
+	if (on)
+		dma_stat |= (1 << (5 + unit));
+	else
+		dma_stat &= ~(1 << (5 + unit));
+
+	if (hwif->host_flags & IDE_HFLAG_MMIO)
+		writeb(dma_stat,
+		       (void __iomem *)(hwif->dma_base + ATA_DMA_STATUS));
+	else
+		outb(dma_stat, hwif->dma_base + ATA_DMA_STATUS);
+}
+EXPORT_SYMBOL_GPL(ide_dma_host_set);
+
+/**
+ *	ide_build_dmatable	-	build IDE DMA table
+ *
+ *	ide_build_dmatable() prepares a dma request. We map the command
+ *	to get the pci bus addresses of the buffers and then build up
+ *	the PRD table that the IDE layer wants to be fed.
+ *
+ *	Most chipsets correctly interpret a length of 0x0000 as 64KB,
+ *	but at least one (e.g. CS5530) misinterprets it as zero (!).
+ *	So we break the 64KB entry into two 32KB entries instead.
+ *
+ *	Returns the number of built PRD entries if all went okay,
+ *	returns 0 otherwise.
+ *
+ *	May also be invoked from trm290.c
+ */
+
+int ide_build_dmatable(ide_drive_t *drive, struct request *rq)
+{
+	ide_hwif_t *hwif = drive->hwif;
+	__le32 *table = (__le32 *)hwif->dmatable_cpu;
+	unsigned int is_trm290	= (hwif->chipset == ide_trm290) ? 1 : 0;
+	unsigned int count = 0;
+	int i;
+	struct scatterlist *sg;
+
+	hwif->sg_nents = ide_build_sglist(drive, rq);
+	if (hwif->sg_nents == 0)
+		return 0;
+
+	for_each_sg(hwif->sg_table, sg, hwif->sg_nents, i) {
+		u32 cur_addr, cur_len, xcount, bcount;
+
+		cur_addr = sg_dma_address(sg);
+		cur_len = sg_dma_len(sg);
+
+		/*
+		 * Fill in the dma table, without crossing any 64kB boundaries.
+		 * Most hardware requires 16-bit alignment of all blocks,
+		 * but the trm290 requires 32-bit alignment.
+		 */
+
+		while (cur_len) {
+			if (count++ >= PRD_ENTRIES)
+				goto use_pio_instead;
+
+			bcount = 0x10000 - (cur_addr & 0xffff);
+			if (bcount > cur_len)
+				bcount = cur_len;
+			*table++ = cpu_to_le32(cur_addr);
+			xcount = bcount & 0xffff;
+			if (is_trm290)
+				xcount = ((xcount >> 2) - 1) << 16;
+			if (xcount == 0x0000) {
+				if (count++ >= PRD_ENTRIES)
+					goto use_pio_instead;
+				*table++ = cpu_to_le32(0x8000);
+				*table++ = cpu_to_le32(cur_addr + 0x8000);
+				xcount = 0x8000;
+			}
+			*table++ = cpu_to_le32(xcount);
+			cur_addr += bcount;
+			cur_len -= bcount;
+		}
+	}
+
+	if (count) {
+		if (!is_trm290)
+			*--table |= cpu_to_le32(0x80000000);
+		return count;
+	}
+
+use_pio_instead:
+	printk(KERN_ERR "%s: %s\n", drive->name,
+		count ? "DMA table too small" : "empty DMA table?");
+
+	ide_destroy_dmatable(drive);
+
+	return 0; /* revert to PIO for this request */
+}
+EXPORT_SYMBOL_GPL(ide_build_dmatable);
+
+/**
+ *	ide_dma_setup	-	begin a DMA phase
+ *	@drive: target device
+ *
+ *	Build an IDE DMA PRD (IDE speak for scatter gather table)
+ *	and then set up the DMA transfer registers for a device
+ *	that follows generic IDE PCI DMA behaviour. Controllers can
+ *	override this function if they need to
+ *
+ *	Returns 0 on success. If a PIO fallback is required then 1
+ *	is returned.
+ */
+
+int ide_dma_setup(ide_drive_t *drive)
+{
+	ide_hwif_t *hwif = drive->hwif;
+	struct request *rq = hwif->hwgroup->rq;
+	unsigned int reading;
+	u8 mmio = (hwif->host_flags & IDE_HFLAG_MMIO) ? 1 : 0;
+	u8 dma_stat;
+
+	if (rq_data_dir(rq))
+		reading = 0;
+	else
+		reading = 1 << 3;
+
+	/* fall back to pio! */
+	if (!ide_build_dmatable(drive, rq)) {
+		ide_map_sg(drive, rq);
+		return 1;
+	}
+
+	/* PRD table */
+	if (hwif->host_flags & IDE_HFLAG_MMIO)
+		writel(hwif->dmatable_dma,
+		       (void __iomem *)(hwif->dma_base + ATA_DMA_TABLE_OFS));
+	else
+		outl(hwif->dmatable_dma, hwif->dma_base + ATA_DMA_TABLE_OFS);
+
+	/* specify r/w */
+	if (mmio)
+		writeb(reading, (void __iomem *)(hwif->dma_base + ATA_DMA_CMD));
+	else
+		outb(reading, hwif->dma_base + ATA_DMA_CMD);
+
+	/* read DMA status for INTR & ERROR flags */
+	dma_stat = hwif->tp_ops->read_sff_dma_status(hwif);
+
+	/* clear INTR & ERROR flags */
+	if (mmio)
+		writeb(dma_stat | 6,
+		       (void __iomem *)(hwif->dma_base + ATA_DMA_STATUS));
+	else
+		outb(dma_stat | 6, hwif->dma_base + ATA_DMA_STATUS);
+
+	drive->waiting_for_dma = 1;
+	return 0;
+}
+EXPORT_SYMBOL_GPL(ide_dma_setup);
+
+/**
+ *	dma_timer_expiry	-	handle a DMA timeout
+ *	@drive: Drive that timed out
+ *
+ *	An IDE DMA transfer timed out. In the event of an error we ask
+ *	the driver to resolve the problem, if a DMA transfer is still
+ *	in progress we continue to wait (arguably we need to add a
+ *	secondary 'I don't care what the drive thinks' timeout here)
+ *	Finally if we have an interrupt we let it complete the I/O.
+ *	But only one time - we clear expiry and if it's still not
+ *	completed after WAIT_CMD, we error and retry in PIO.
+ *	This can occur if an interrupt is lost or due to hang or bugs.
+ */
+
+static int dma_timer_expiry(ide_drive_t *drive)
+{
+	ide_hwif_t *hwif = drive->hwif;
+	u8 dma_stat = hwif->tp_ops->read_sff_dma_status(hwif);
+
+	printk(KERN_WARNING "%s: %s: DMA status (0x%02x)\n",
+		drive->name, __func__, dma_stat);
+
+	if ((dma_stat & 0x18) == 0x18)	/* BUSY Stupid Early Timer !! */
+		return WAIT_CMD;
+
+	hwif->hwgroup->expiry = NULL;	/* one free ride for now */
+
+	/* 1 dmaing, 2 error, 4 intr */
+	if (dma_stat & 2)	/* ERROR */
+		return -1;
+
+	if (dma_stat & 1)	/* DMAing */
+		return WAIT_CMD;
+
+	if (dma_stat & 4)	/* Got an Interrupt */
+		return WAIT_CMD;
+
+	return 0;	/* Status is unknown -- reset the bus */
+}
+
+void ide_dma_exec_cmd(ide_drive_t *drive, u8 command)
+{
+	/* issue cmd to drive */
+	ide_execute_command(drive, command, &ide_dma_intr, 2 * WAIT_CMD,
+			    dma_timer_expiry);
+}
+EXPORT_SYMBOL_GPL(ide_dma_exec_cmd);
+
+void ide_dma_start(ide_drive_t *drive)
+{
+	ide_hwif_t *hwif = drive->hwif;
+	u8 dma_cmd;
+
+	/* Note that this is done *after* the cmd has
+	 * been issued to the drive, as per the BM-IDE spec.
+	 * The Promise Ultra33 doesn't work correctly when
+	 * we do this part before issuing the drive cmd.
+	 */
+	if (hwif->host_flags & IDE_HFLAG_MMIO) {
+		dma_cmd = readb((void __iomem *)(hwif->dma_base + ATA_DMA_CMD));
+		/* start DMA */
+		writeb(dma_cmd | 1,
+		       (void __iomem *)(hwif->dma_base + ATA_DMA_CMD));
+	} else {
+		dma_cmd = inb(hwif->dma_base + ATA_DMA_CMD);
+		outb(dma_cmd | 1, hwif->dma_base + ATA_DMA_CMD);
+	}
+
+	wmb();
+}
+EXPORT_SYMBOL_GPL(ide_dma_start);
+
+/* returns 1 on error, 0 otherwise */
+int ide_dma_end(ide_drive_t *drive)
+{
+	ide_hwif_t *hwif = drive->hwif;
+	u8 mmio = (hwif->host_flags & IDE_HFLAG_MMIO) ? 1 : 0;
+	u8 dma_stat = 0, dma_cmd = 0;
+
+	drive->waiting_for_dma = 0;
+
+	if (mmio) {
+		/* get DMA command mode */
+		dma_cmd = readb((void __iomem *)(hwif->dma_base + ATA_DMA_CMD));
+		/* stop DMA */
+		writeb(dma_cmd & ~1,
+		       (void __iomem *)(hwif->dma_base + ATA_DMA_CMD));
+	} else {
+		dma_cmd = inb(hwif->dma_base + ATA_DMA_CMD);
+		outb(dma_cmd & ~1, hwif->dma_base + ATA_DMA_CMD);
+	}
+
+	/* get DMA status */
+	dma_stat = hwif->tp_ops->read_sff_dma_status(hwif);
+
+	if (mmio)
+		/* clear the INTR & ERROR bits */
+		writeb(dma_stat | 6,
+		       (void __iomem *)(hwif->dma_base + ATA_DMA_STATUS));
+	else
+		outb(dma_stat | 6, hwif->dma_base + ATA_DMA_STATUS);
+
+	/* purge DMA mappings */
+	ide_destroy_dmatable(drive);
+	/* verify good DMA status */
+	wmb();
+	return (dma_stat & 7) != 4 ? (0x10 | dma_stat) : 0;
+}
+EXPORT_SYMBOL_GPL(ide_dma_end);
+
+/* returns 1 if dma irq issued, 0 otherwise */
+int ide_dma_test_irq(ide_drive_t *drive)
+{
+	ide_hwif_t *hwif = drive->hwif;
+	u8 dma_stat = hwif->tp_ops->read_sff_dma_status(hwif);
+
+	/* return 1 if INTR asserted */
+	if ((dma_stat & 4) == 4)
+		return 1;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(ide_dma_test_irq);
+
+const struct ide_dma_ops sff_dma_ops = {
+	.dma_host_set		= ide_dma_host_set,
+	.dma_setup		= ide_dma_setup,
+	.dma_exec_cmd		= ide_dma_exec_cmd,
+	.dma_start		= ide_dma_start,
+	.dma_end		= ide_dma_end,
+	.dma_test_irq		= ide_dma_test_irq,
+	.dma_timeout		= ide_dma_timeout,
+	.dma_lost_irq		= ide_dma_lost_irq,
+};
+EXPORT_SYMBOL_GPL(sff_dma_ops);
diff --git a/drivers/ide/ide-dma.c b/drivers/ide/ide-dma.c
index adc6827..fffd117 100644
--- a/drivers/ide/ide-dma.c
+++ b/drivers/ide/ide-dma.c
@@ -28,24 +28,13 @@
  * for supplying a Promise UDMA board & WD UDMA drive for this work!
  */
 
-#include <linux/module.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-#include <linux/pci.h>
-#include <linux/init.h>
 #include <linux/ide.h>
-#include <linux/delay.h>
 #include <linux/scatterlist.h>
 #include <linux/dma-mapping.h>
 
-#include <asm/io.h>
-#include <asm/irq.h>
-
-static const struct drive_list_entry drive_whitelist [] = {
-
+static const struct drive_list_entry drive_whitelist[] = {
 	{ "Micropolis 2112A"	,       NULL		},
 	{ "CONNER CTMA 4000"	,       NULL		},
 	{ "CONNER CTT8000-A"	,       NULL		},
@@ -53,8 +42,7 @@
 	{ NULL			,	NULL		}
 };
 
-static const struct drive_list_entry drive_blacklist [] = {
-
+static const struct drive_list_entry drive_blacklist[] = {
 	{ "WDC AC11000H"	,	NULL 		},
 	{ "WDC AC22100H"	,	NULL 		},
 	{ "WDC AC32500H"	,	NULL 		},
@@ -94,11 +82,11 @@
  *	ide_dma_intr	-	IDE DMA interrupt handler
  *	@drive: the drive the interrupt is for
  *
- *	Handle an interrupt completing a read/write DMA transfer on an 
+ *	Handle an interrupt completing a read/write DMA transfer on an
  *	IDE device
  */
- 
-ide_startstop_t ide_dma_intr (ide_drive_t *drive)
+
+ide_startstop_t ide_dma_intr(ide_drive_t *drive)
 {
 	ide_hwif_t *hwif = drive->hwif;
 	u8 stat = 0, dma_stat = 0;
@@ -106,22 +94,21 @@
 	dma_stat = hwif->dma_ops->dma_end(drive);
 	stat = hwif->tp_ops->read_status(hwif);
 
-	if (OK_STAT(stat,DRIVE_READY,drive->bad_wstat|DRQ_STAT)) {
+	if (OK_STAT(stat, DRIVE_READY, drive->bad_wstat | ATA_DRQ)) {
 		if (!dma_stat) {
-			struct request *rq = HWGROUP(drive)->rq;
+			struct request *rq = hwif->hwgroup->rq;
 
 			task_end_request(drive, rq, stat);
 			return ide_stopped;
 		}
-		printk(KERN_ERR "%s: dma_intr: bad DMA status (dma_stat=%x)\n", 
-		       drive->name, dma_stat);
+		printk(KERN_ERR "%s: %s: bad DMA status (0x%02x)\n",
+			drive->name, __func__, dma_stat);
 	}
 	return ide_error(drive, "dma_intr", stat);
 }
-
 EXPORT_SYMBOL_GPL(ide_dma_intr);
 
-static int ide_dma_good_drive(ide_drive_t *drive)
+int ide_dma_good_drive(ide_drive_t *drive)
 {
 	return ide_in_drive_list(drive->id, drive_whitelist);
 }
@@ -139,7 +126,7 @@
 
 int ide_build_sglist(ide_drive_t *drive, struct request *rq)
 {
-	ide_hwif_t *hwif = HWIF(drive);
+	ide_hwif_t *hwif = drive->hwif;
 	struct scatterlist *sg = hwif->sg_table;
 
 	ide_map_sg(drive, rq);
@@ -152,106 +139,8 @@
 	return dma_map_sg(hwif->dev, sg, hwif->sg_nents,
 			  hwif->sg_dma_direction);
 }
-
 EXPORT_SYMBOL_GPL(ide_build_sglist);
 
-#ifdef CONFIG_BLK_DEV_IDEDMA_SFF
-/**
- *	ide_build_dmatable	-	build IDE DMA table
- *
- *	ide_build_dmatable() prepares a dma request. We map the command
- *	to get the pci bus addresses of the buffers and then build up
- *	the PRD table that the IDE layer wants to be fed. The code
- *	knows about the 64K wrap bug in the CS5530.
- *
- *	Returns the number of built PRD entries if all went okay,
- *	returns 0 otherwise.
- *
- *	May also be invoked from trm290.c
- */
- 
-int ide_build_dmatable (ide_drive_t *drive, struct request *rq)
-{
-	ide_hwif_t *hwif	= HWIF(drive);
-	__le32 *table = (__le32 *)hwif->dmatable_cpu;
-	unsigned int is_trm290	= (hwif->chipset == ide_trm290) ? 1 : 0;
-	unsigned int count = 0;
-	int i;
-	struct scatterlist *sg;
-
-	hwif->sg_nents = i = ide_build_sglist(drive, rq);
-
-	if (!i)
-		return 0;
-
-	sg = hwif->sg_table;
-	while (i) {
-		u32 cur_addr;
-		u32 cur_len;
-
-		cur_addr = sg_dma_address(sg);
-		cur_len = sg_dma_len(sg);
-
-		/*
-		 * Fill in the dma table, without crossing any 64kB boundaries.
-		 * Most hardware requires 16-bit alignment of all blocks,
-		 * but the trm290 requires 32-bit alignment.
-		 */
-
-		while (cur_len) {
-			if (count++ >= PRD_ENTRIES) {
-				printk(KERN_ERR "%s: DMA table too small\n", drive->name);
-				goto use_pio_instead;
-			} else {
-				u32 xcount, bcount = 0x10000 - (cur_addr & 0xffff);
-
-				if (bcount > cur_len)
-					bcount = cur_len;
-				*table++ = cpu_to_le32(cur_addr);
-				xcount = bcount & 0xffff;
-				if (is_trm290)
-					xcount = ((xcount >> 2) - 1) << 16;
-				if (xcount == 0x0000) {
-	/* 
-	 * Most chipsets correctly interpret a length of 0x0000 as 64KB,
-	 * but at least one (e.g. CS5530) misinterprets it as zero (!).
-	 * So here we break the 64KB entry into two 32KB entries instead.
-	 */
-					if (count++ >= PRD_ENTRIES) {
-						printk(KERN_ERR "%s: DMA table too small\n", drive->name);
-						goto use_pio_instead;
-					}
-					*table++ = cpu_to_le32(0x8000);
-					*table++ = cpu_to_le32(cur_addr + 0x8000);
-					xcount = 0x8000;
-				}
-				*table++ = cpu_to_le32(xcount);
-				cur_addr += bcount;
-				cur_len -= bcount;
-			}
-		}
-
-		sg = sg_next(sg);
-		i--;
-	}
-
-	if (count) {
-		if (!is_trm290)
-			*--table |= cpu_to_le32(0x80000000);
-		return count;
-	}
-
-	printk(KERN_ERR "%s: empty DMA table?\n", drive->name);
-
-use_pio_instead:
-	ide_destroy_dmatable(drive);
-
-	return 0; /* revert to PIO for this request */
-}
-
-EXPORT_SYMBOL_GPL(ide_build_dmatable);
-#endif
-
 /**
  *	ide_destroy_dmatable	-	clean up DMA mapping
  *	@drive: The drive to unmap
@@ -262,146 +151,30 @@
  *	an oops as only one mapping can be live for each target at a given
  *	time.
  */
- 
-void ide_destroy_dmatable (ide_drive_t *drive)
+
+void ide_destroy_dmatable(ide_drive_t *drive)
 {
 	ide_hwif_t *hwif = drive->hwif;
 
 	dma_unmap_sg(hwif->dev, hwif->sg_table, hwif->sg_nents,
 		     hwif->sg_dma_direction);
 }
-
 EXPORT_SYMBOL_GPL(ide_destroy_dmatable);
 
-#ifdef CONFIG_BLK_DEV_IDEDMA_SFF
-/**
- *	config_drive_for_dma	-	attempt to activate IDE DMA
- *	@drive: the drive to place in DMA mode
- *
- *	If the drive supports at least mode 2 DMA or UDMA of any kind
- *	then attempt to place it into DMA mode. Drives that are known to
- *	support DMA but predate the DMA properties or that are known
- *	to have DMA handling bugs are also set up appropriately based
- *	on the good/bad drive lists.
- */
- 
-static int config_drive_for_dma (ide_drive_t *drive)
-{
-	ide_hwif_t *hwif = drive->hwif;
-	struct hd_driveid *id = drive->id;
-
-	if (drive->media != ide_disk) {
-		if (hwif->host_flags & IDE_HFLAG_NO_ATAPI_DMA)
-			return 0;
-	}
-
-	/*
-	 * Enable DMA on any drive that has
-	 * UltraDMA (mode 0/1/2/3/4/5/6) enabled
-	 */
-	if ((id->field_valid & 4) && ((id->dma_ultra >> 8) & 0x7f))
-		return 1;
-
-	/*
-	 * Enable DMA on any drive that has mode2 DMA
-	 * (multi or single) enabled
-	 */
-	if (id->field_valid & 2)	/* regular DMA */
-		if ((id->dma_mword & 0x404) == 0x404 ||
-		    (id->dma_1word & 0x404) == 0x404)
-			return 1;
-
-	/* Consult the list of known "good" drives */
-	if (ide_dma_good_drive(drive))
-		return 1;
-
-	return 0;
-}
-
-/**
- *	dma_timer_expiry	-	handle a DMA timeout
- *	@drive: Drive that timed out
- *
- *	An IDE DMA transfer timed out. In the event of an error we ask
- *	the driver to resolve the problem, if a DMA transfer is still
- *	in progress we continue to wait (arguably we need to add a 
- *	secondary 'I don't care what the drive thinks' timeout here)
- *	Finally if we have an interrupt we let it complete the I/O.
- *	But only one time - we clear expiry and if it's still not
- *	completed after WAIT_CMD, we error and retry in PIO.
- *	This can occur if an interrupt is lost or due to hang or bugs.
- */
- 
-static int dma_timer_expiry (ide_drive_t *drive)
-{
-	ide_hwif_t *hwif	= HWIF(drive);
-	u8 dma_stat		= hwif->tp_ops->read_sff_dma_status(hwif);
-
-	printk(KERN_WARNING "%s: dma_timer_expiry: dma status == 0x%02x\n",
-		drive->name, dma_stat);
-
-	if ((dma_stat & 0x18) == 0x18)	/* BUSY Stupid Early Timer !! */
-		return WAIT_CMD;
-
-	HWGROUP(drive)->expiry = NULL;	/* one free ride for now */
-
-	/* 1 dmaing, 2 error, 4 intr */
-	if (dma_stat & 2)	/* ERROR */
-		return -1;
-
-	if (dma_stat & 1)	/* DMAing */
-		return WAIT_CMD;
-
-	if (dma_stat & 4)	/* Got an Interrupt */
-		return WAIT_CMD;
-
-	return 0;	/* Status is unknown -- reset the bus */
-}
-
-/**
- *	ide_dma_host_set	-	Enable/disable DMA on a host
- *	@drive: drive to control
- *
- *	Enable/disable DMA on an IDE controller following generic
- *	bus-mastering IDE controller behaviour.
- */
-
-void ide_dma_host_set(ide_drive_t *drive, int on)
-{
-	ide_hwif_t *hwif	= HWIF(drive);
-	u8 unit			= (drive->select.b.unit & 0x01);
-	u8 dma_stat		= hwif->tp_ops->read_sff_dma_status(hwif);
-
-	if (on)
-		dma_stat |= (1 << (5 + unit));
-	else
-		dma_stat &= ~(1 << (5 + unit));
-
-	if (hwif->host_flags & IDE_HFLAG_MMIO)
-		writeb(dma_stat,
-		       (void __iomem *)(hwif->dma_base + ATA_DMA_STATUS));
-	else
-		outb(dma_stat, hwif->dma_base + ATA_DMA_STATUS);
-}
-
-EXPORT_SYMBOL_GPL(ide_dma_host_set);
-#endif /* CONFIG_BLK_DEV_IDEDMA_SFF  */
-
 /**
  *	ide_dma_off_quietly	-	Generic DMA kill
  *	@drive: drive to control
  *
- *	Turn off the current DMA on this IDE controller. 
+ *	Turn off the current DMA on this IDE controller.
  */
 
 void ide_dma_off_quietly(ide_drive_t *drive)
 {
-	drive->using_dma = 0;
+	drive->dev_flags &= ~IDE_DFLAG_USING_DMA;
 	ide_toggle_bounce(drive, 0);
 
 	drive->hwif->dma_ops->dma_host_set(drive, 0);
 }
-
 EXPORT_SYMBOL(ide_dma_off_quietly);
 
 /**
@@ -417,7 +190,6 @@
 	printk(KERN_INFO "%s: DMA disabled\n", drive->name);
 	ide_dma_off_quietly(drive);
 }
-
 EXPORT_SYMBOL(ide_dma_off);
 
 /**
@@ -429,179 +201,24 @@
 
 void ide_dma_on(ide_drive_t *drive)
 {
-	drive->using_dma = 1;
+	drive->dev_flags |= IDE_DFLAG_USING_DMA;
 	ide_toggle_bounce(drive, 1);
 
 	drive->hwif->dma_ops->dma_host_set(drive, 1);
 }
 
-#ifdef CONFIG_BLK_DEV_IDEDMA_SFF
-/**
- *	ide_dma_setup	-	begin a DMA phase
- *	@drive: target device
- *
- *	Build an IDE DMA PRD (IDE speak for scatter gather table)
- *	and then set up the DMA transfer registers for a device
- *	that follows generic IDE PCI DMA behaviour. Controllers can
- *	override this function if they need to
- *
- *	Returns 0 on success. If a PIO fallback is required then 1
- *	is returned. 
- */
-
-int ide_dma_setup(ide_drive_t *drive)
+int __ide_dma_bad_drive(ide_drive_t *drive)
 {
-	ide_hwif_t *hwif = drive->hwif;
-	struct request *rq = HWGROUP(drive)->rq;
-	unsigned int reading;
-	u8 mmio = (hwif->host_flags & IDE_HFLAG_MMIO) ? 1 : 0;
-	u8 dma_stat;
-
-	if (rq_data_dir(rq))
-		reading = 0;
-	else
-		reading = 1 << 3;
-
-	/* fall back to pio! */
-	if (!ide_build_dmatable(drive, rq)) {
-		ide_map_sg(drive, rq);
-		return 1;
-	}
-
-	/* PRD table */
-	if (hwif->host_flags & IDE_HFLAG_MMIO)
-		writel(hwif->dmatable_dma,
-		       (void __iomem *)(hwif->dma_base + ATA_DMA_TABLE_OFS));
-	else
-		outl(hwif->dmatable_dma, hwif->dma_base + ATA_DMA_TABLE_OFS);
-
-	/* specify r/w */
-	if (mmio)
-		writeb(reading, (void __iomem *)(hwif->dma_base + ATA_DMA_CMD));
-	else
-		outb(reading, hwif->dma_base + ATA_DMA_CMD);
-
-	/* read DMA status for INTR & ERROR flags */
-	dma_stat = hwif->tp_ops->read_sff_dma_status(hwif);
-
-	/* clear INTR & ERROR flags */
-	if (mmio)
-		writeb(dma_stat | 6,
-		       (void __iomem *)(hwif->dma_base + ATA_DMA_STATUS));
-	else
-		outb(dma_stat | 6, hwif->dma_base + ATA_DMA_STATUS);
-
-	drive->waiting_for_dma = 1;
-	return 0;
-}
-
-EXPORT_SYMBOL_GPL(ide_dma_setup);
-
-void ide_dma_exec_cmd(ide_drive_t *drive, u8 command)
-{
-	/* issue cmd to drive */
-	ide_execute_command(drive, command, &ide_dma_intr, 2*WAIT_CMD, dma_timer_expiry);
-}
-EXPORT_SYMBOL_GPL(ide_dma_exec_cmd);
-
-void ide_dma_start(ide_drive_t *drive)
-{
-	ide_hwif_t *hwif = drive->hwif;
-	u8 dma_cmd;
-
-	/* Note that this is done *after* the cmd has
-	 * been issued to the drive, as per the BM-IDE spec.
-	 * The Promise Ultra33 doesn't work correctly when
-	 * we do this part before issuing the drive cmd.
-	 */
-	if (hwif->host_flags & IDE_HFLAG_MMIO) {
-		dma_cmd = readb((void __iomem *)(hwif->dma_base + ATA_DMA_CMD));
-		/* start DMA */
-		writeb(dma_cmd | 1,
-		       (void __iomem *)(hwif->dma_base + ATA_DMA_CMD));
-	} else {
-		dma_cmd = inb(hwif->dma_base + ATA_DMA_CMD);
-		outb(dma_cmd | 1, hwif->dma_base + ATA_DMA_CMD);
-	}
-
-	hwif->dma = 1;
-	wmb();
-}
-
-EXPORT_SYMBOL_GPL(ide_dma_start);
-
-/* returns 1 on error, 0 otherwise */
-int __ide_dma_end (ide_drive_t *drive)
-{
-	ide_hwif_t *hwif = drive->hwif;
-	u8 mmio = (hwif->host_flags & IDE_HFLAG_MMIO) ? 1 : 0;
-	u8 dma_stat = 0, dma_cmd = 0;
-
-	drive->waiting_for_dma = 0;
-
-	if (mmio) {
-		/* get DMA command mode */
-		dma_cmd = readb((void __iomem *)(hwif->dma_base + ATA_DMA_CMD));
-		/* stop DMA */
-		writeb(dma_cmd & ~1,
-		       (void __iomem *)(hwif->dma_base + ATA_DMA_CMD));
-	} else {
-		dma_cmd = inb(hwif->dma_base + ATA_DMA_CMD);
-		outb(dma_cmd & ~1, hwif->dma_base + ATA_DMA_CMD);
-	}
-
-	/* get DMA status */
-	dma_stat = hwif->tp_ops->read_sff_dma_status(hwif);
-
-	if (mmio)
-		/* clear the INTR & ERROR bits */
-		writeb(dma_stat | 6,
-		       (void __iomem *)(hwif->dma_base + ATA_DMA_STATUS));
-	else
-		outb(dma_stat | 6, hwif->dma_base + ATA_DMA_STATUS);
-
-	/* purge DMA mappings */
-	ide_destroy_dmatable(drive);
-	/* verify good DMA status */
-	hwif->dma = 0;
-	wmb();
-	return (dma_stat & 7) != 4 ? (0x10 | dma_stat) : 0;
-}
-
-EXPORT_SYMBOL(__ide_dma_end);
-
-/* returns 1 if dma irq issued, 0 otherwise */
-int ide_dma_test_irq(ide_drive_t *drive)
-{
-	ide_hwif_t *hwif	= HWIF(drive);
-	u8 dma_stat		= hwif->tp_ops->read_sff_dma_status(hwif);
-
-	/* return 1 if INTR asserted */
-	if ((dma_stat & 4) == 4)
-		return 1;
-	if (!drive->waiting_for_dma)
-		printk(KERN_WARNING "%s: (%s) called while not waiting\n",
-			drive->name, __func__);
-	return 0;
-}
-EXPORT_SYMBOL_GPL(ide_dma_test_irq);
-#else
-static inline int config_drive_for_dma(ide_drive_t *drive) { return 0; }
-#endif /* CONFIG_BLK_DEV_IDEDMA_SFF */
-
-int __ide_dma_bad_drive (ide_drive_t *drive)
-{
-	struct hd_driveid *id = drive->id;
+	u16 *id = drive->id;
 
 	int blacklist = ide_in_drive_list(id, drive_blacklist);
 	if (blacklist) {
 		printk(KERN_WARNING "%s: Disabling (U)DMA for %s (blacklisted)\n",
-				    drive->name, id->model);
+				    drive->name, (char *)&id[ATA_ID_PROD]);
 		return blacklist;
 	}
 	return 0;
 }
-
 EXPORT_SYMBOL(__ide_dma_bad_drive);
 
 static const u8 xfer_mode_bases[] = {
@@ -612,21 +229,21 @@
 
 static unsigned int ide_get_mode_mask(ide_drive_t *drive, u8 base, u8 req_mode)
 {
-	struct hd_driveid *id = drive->id;
+	u16 *id = drive->id;
 	ide_hwif_t *hwif = drive->hwif;
 	const struct ide_port_ops *port_ops = hwif->port_ops;
 	unsigned int mask = 0;
 
-	switch(base) {
+	switch (base) {
 	case XFER_UDMA_0:
-		if ((id->field_valid & 4) == 0)
+		if ((id[ATA_ID_FIELD_VALID] & 4) == 0)
 			break;
 
 		if (port_ops && port_ops->udma_filter)
 			mask = port_ops->udma_filter(drive);
 		else
 			mask = hwif->ultra_mask;
-		mask &= id->dma_ultra;
+		mask &= id[ATA_ID_UDMA_MODES];
 
 		/*
 		 * avoid false cable warning from eighty_ninty_three()
@@ -637,19 +254,19 @@
 		}
 		break;
 	case XFER_MW_DMA_0:
-		if ((id->field_valid & 2) == 0)
+		if ((id[ATA_ID_FIELD_VALID] & 2) == 0)
 			break;
 		if (port_ops && port_ops->mdma_filter)
 			mask = port_ops->mdma_filter(drive);
 		else
 			mask = hwif->mwdma_mask;
-		mask &= id->dma_mword;
+		mask &= id[ATA_ID_MWDMA_MODES];
 		break;
 	case XFER_SW_DMA_0:
-		if (id->field_valid & 2) {
-			mask = id->dma_1word & hwif->swdma_mask;
-		} else if (id->tDMA) {
-			u8 mode = id->tDMA;
+		if (id[ATA_ID_FIELD_VALID] & 2) {
+			mask = id[ATA_ID_SWDMA_MODES] & hwif->swdma_mask;
+		} else if (id[ATA_ID_OLD_DMA_MODES] >> 8) {
+			u8 mode = id[ATA_ID_OLD_DMA_MODES] >> 8;
 
 			/*
 			 * if the mode is valid convert it to the mask
@@ -706,7 +323,8 @@
 		/*
 		 * is this correct?
 		 */
-		if (ide_dma_good_drive(drive) && drive->id->eide_dma_time < 150)
+		if (ide_dma_good_drive(drive) &&
+		    drive->id[ATA_ID_EIDE_DMA_TIME] < 150)
 			mode = XFER_MW_DMA_1;
 	}
 
@@ -717,7 +335,6 @@
 
 	return mode;
 }
-
 EXPORT_SYMBOL_GPL(ide_find_dma_mode);
 
 static int ide_tune_dma(ide_drive_t *drive)
@@ -725,7 +342,8 @@
 	ide_hwif_t *hwif = drive->hwif;
 	u8 speed;
 
-	if (drive->nodma || (drive->id->capability & 1) == 0)
+	if (ata_id_has_dma(drive->id) == 0 ||
+	    (drive->dev_flags & IDE_DFLAG_NODMA))
 		return 0;
 
 	/* consult the list of known "bad" drives */
@@ -767,13 +385,15 @@
 
 int ide_id_dma_bug(ide_drive_t *drive)
 {
-	struct hd_driveid *id = drive->id;
+	u16 *id = drive->id;
 
-	if (id->field_valid & 4) {
-		if ((id->dma_ultra >> 8) && (id->dma_mword >> 8))
+	if (id[ATA_ID_FIELD_VALID] & 4) {
+		if ((id[ATA_ID_UDMA_MODES] >> 8) &&
+		    (id[ATA_ID_MWDMA_MODES] >> 8))
 			goto err_out;
-	} else if (id->field_valid & 2) {
-		if ((id->dma_mword >> 8) && (id->dma_1word >> 8))
+	} else if (id[ATA_ID_FIELD_VALID] & 2) {
+		if ((id[ATA_ID_MWDMA_MODES] >> 8) &&
+		    (id[ATA_ID_SWDMA_MODES] >> 8))
 			goto err_out;
 	}
 	return 0;
@@ -823,66 +443,59 @@
 		ide_dma_on(drive);
 }
 
-#ifdef CONFIG_BLK_DEV_IDEDMA_SFF
-void ide_dma_lost_irq (ide_drive_t *drive)
+void ide_dma_lost_irq(ide_drive_t *drive)
 {
-	printk("%s: DMA interrupt recovery\n", drive->name);
+	printk(KERN_ERR "%s: DMA interrupt recovery\n", drive->name);
 }
+EXPORT_SYMBOL_GPL(ide_dma_lost_irq);
 
-EXPORT_SYMBOL(ide_dma_lost_irq);
-
-void ide_dma_timeout (ide_drive_t *drive)
+void ide_dma_timeout(ide_drive_t *drive)
 {
-	ide_hwif_t *hwif = HWIF(drive);
+	ide_hwif_t *hwif = drive->hwif;
 
 	printk(KERN_ERR "%s: timeout waiting for DMA\n", drive->name);
 
 	if (hwif->dma_ops->dma_test_irq(drive))
 		return;
 
+	ide_dump_status(drive, "DMA timeout", hwif->tp_ops->read_status(hwif));
+
 	hwif->dma_ops->dma_end(drive);
 }
-
-EXPORT_SYMBOL(ide_dma_timeout);
+EXPORT_SYMBOL_GPL(ide_dma_timeout);
 
 void ide_release_dma_engine(ide_hwif_t *hwif)
 {
 	if (hwif->dmatable_cpu) {
-		struct pci_dev *pdev = to_pci_dev(hwif->dev);
+		int prd_size = hwif->prd_max_nents * hwif->prd_ent_size;
 
-		pci_free_consistent(pdev, PRD_ENTRIES * PRD_BYTES,
-				    hwif->dmatable_cpu, hwif->dmatable_dma);
+		dma_free_coherent(hwif->dev, prd_size,
+				  hwif->dmatable_cpu, hwif->dmatable_dma);
 		hwif->dmatable_cpu = NULL;
 	}
 }
+EXPORT_SYMBOL_GPL(ide_release_dma_engine);
 
 int ide_allocate_dma_engine(ide_hwif_t *hwif)
 {
-	struct pci_dev *pdev = to_pci_dev(hwif->dev);
+	int prd_size;
 
-	hwif->dmatable_cpu = pci_alloc_consistent(pdev,
-						  PRD_ENTRIES * PRD_BYTES,
-						  &hwif->dmatable_dma);
+	if (hwif->prd_max_nents == 0)
+		hwif->prd_max_nents = PRD_ENTRIES;
+	if (hwif->prd_ent_size == 0)
+		hwif->prd_ent_size = PRD_BYTES;
 
-	if (hwif->dmatable_cpu)
-		return 0;
+	prd_size = hwif->prd_max_nents * hwif->prd_ent_size;
 
-	printk(KERN_ERR "%s: -- Error, unable to allocate DMA table.\n",
+	hwif->dmatable_cpu = dma_alloc_coherent(hwif->dev, prd_size,
+						&hwif->dmatable_dma,
+						GFP_ATOMIC);
+	if (hwif->dmatable_cpu == NULL) {
+		printk(KERN_ERR "%s: unable to allocate PRD table\n",
 			hwif->name);
+		return -ENOMEM;
+	}
 
-	return 1;
+	return 0;
 }
 EXPORT_SYMBOL_GPL(ide_allocate_dma_engine);
-
-const struct ide_dma_ops sff_dma_ops = {
-	.dma_host_set		= ide_dma_host_set,
-	.dma_setup		= ide_dma_setup,
-	.dma_exec_cmd		= ide_dma_exec_cmd,
-	.dma_start		= ide_dma_start,
-	.dma_end		= __ide_dma_end,
-	.dma_test_irq		= ide_dma_test_irq,
-	.dma_timeout		= ide_dma_timeout,
-	.dma_lost_irq		= ide_dma_lost_irq,
-};
-EXPORT_SYMBOL_GPL(sff_dma_ops);
-#endif /* CONFIG_BLK_DEV_IDEDMA_SFF */
diff --git a/drivers/ide/ide-floppy.c b/drivers/ide/ide-floppy.c
index e9034c0..cf0aa25 100644
--- a/drivers/ide/ide-floppy.c
+++ b/drivers/ide/ide-floppy.c
@@ -15,6 +15,9 @@
  * Documentation/ide/ChangeLog.ide-floppy.1996-2002
  */
 
+#define DRV_NAME "ide-floppy"
+#define PFX DRV_NAME ": "
+
 #define IDEFLOPPY_VERSION "1.00"
 
 #include <linux/module.h>
@@ -31,8 +34,10 @@
 #include <linux/slab.h>
 #include <linux/cdrom.h>
 #include <linux/ide.h>
+#include <linux/hdreg.h>
 #include <linux/bitops.h>
 #include <linux/mutex.h>
+#include <linux/scatterlist.h>
 
 #include <scsi/scsi_ioctl.h>
 
@@ -42,42 +47,27 @@
 #include <linux/io.h>
 #include <asm/unaligned.h>
 
-/* define to see debug info */
-#define IDEFLOPPY_DEBUG_LOG		0
+#include "ide-floppy.h"
 
-/* #define IDEFLOPPY_DEBUG(fmt, args...) printk(KERN_INFO fmt, ## args) */
-#define IDEFLOPPY_DEBUG(fmt, args...)
+/* module parameters */
+static unsigned long debug_mask;
+module_param(debug_mask, ulong, 0644);
+
+/* define to see debug info */
+#define IDEFLOPPY_DEBUG_LOG	0
 
 #if IDEFLOPPY_DEBUG_LOG
-#define debug_log(fmt, args...) \
-	printk(KERN_INFO "ide-floppy: " fmt, ## args)
+#define ide_debug_log(lvl, fmt, args...) __ide_debug_log(lvl, fmt, args)
 #else
-#define debug_log(fmt, args...) do {} while (0)
+#define ide_debug_log(lvl, fmt, args...) do {} while (0)
 #endif
 
-
-/* Some drives require a longer irq timeout. */
-#define IDEFLOPPY_WAIT_CMD		(5 * WAIT_CMD)
-
 /*
  * After each failed packet command we issue a request sense command and retry
  * the packet command IDEFLOPPY_MAX_PC_RETRIES times.
  */
 #define IDEFLOPPY_MAX_PC_RETRIES	3
 
-/*
- * With each packet command, we allocate a buffer of IDEFLOPPY_PC_BUFFER_SIZE
- * bytes.
- */
-#define IDEFLOPPY_PC_BUFFER_SIZE	256
-
-/*
- * In various places in the driver, we need to allocate storage for packet
- * commands and requests, which will remain valid while	we leave the driver to
- * wait for an interrupt or a timeout event.
- */
-#define IDEFLOPPY_PC_STACK		(10 + IDEFLOPPY_MAX_PC_RETRIES)
-
 /* format capacities descriptor codes */
 #define CAPACITY_INVALID	0x00
 #define CAPACITY_UNFORMATTED	0x01
@@ -85,79 +75,16 @@
 #define CAPACITY_NO_CARTRIDGE	0x03
 
 /*
- * Most of our global data which we need to save even as we leave the driver
- * due to an interrupt or a timer event is stored in a variable of type
- * idefloppy_floppy_t, defined below.
+ * The following delay solves a problem with ATAPI Zip 100 drive where BSY bit
+ * was apparently being deasserted before the unit was ready to receive data.
  */
-typedef struct ide_floppy_obj {
-	ide_drive_t	*drive;
-	ide_driver_t	*driver;
-	struct gendisk	*disk;
-	struct kref	kref;
-	unsigned int	openers;	/* protected by BKL for now */
-
-	/* Current packet command */
-	struct ide_atapi_pc *pc;
-	/* Last failed packet command */
-	struct ide_atapi_pc *failed_pc;
-	/* Packet command stack */
-	struct ide_atapi_pc pc_stack[IDEFLOPPY_PC_STACK];
-	/* Next free packet command storage space */
-	int pc_stack_index;
-	struct request rq_stack[IDEFLOPPY_PC_STACK];
-	/* We implement a circular array */
-	int rq_stack_index;
-
-	/* Last error information */
-	u8 sense_key, asc, ascq;
-	/* delay this long before sending packet command */
-	u8 ticks;
-	int progress_indication;
-
-	/* Device information */
-	/* Current format */
-	int blocks, block_size, bs_factor;
-	/* Last format capacity descriptor */
-	u8 cap_desc[8];
-	/* Copy of the flexible disk page */
-	u8 flexible_disk_page[32];
-	/* Write protect */
-	int wp;
-	/* Supports format progress report */
-	int srfp;
-} idefloppy_floppy_t;
-
-#define IDEFLOPPY_TICKS_DELAY	HZ/20	/* default delay for ZIP 100 (50ms) */
-
-/* Defines for the MODE SENSE command */
-#define MODE_SENSE_CURRENT		0x00
-#define MODE_SENSE_CHANGEABLE		0x01
-#define MODE_SENSE_DEFAULT		0x02
-#define MODE_SENSE_SAVED		0x03
-
-/* IOCTLs used in low-level formatting. */
-#define	IDEFLOPPY_IOCTL_FORMAT_SUPPORTED	0x4600
-#define	IDEFLOPPY_IOCTL_FORMAT_GET_CAPACITY	0x4601
-#define	IDEFLOPPY_IOCTL_FORMAT_START		0x4602
-#define IDEFLOPPY_IOCTL_FORMAT_GET_PROGRESS	0x4603
+#define IDEFLOPPY_PC_DELAY	(HZ/20)	/* default delay for ZIP 100 (50ms) */
 
 /* Error code returned in rq->errors to the higher part of the driver. */
 #define	IDEFLOPPY_ERROR_GENERAL		101
 
-/*
- * Pages of the SELECT SENSE / MODE SENSE packet commands.
- * See SFF-8070i spec.
- */
-#define	IDEFLOPPY_CAPABILITIES_PAGE	0x1b
-#define IDEFLOPPY_FLEXIBLE_DISK_PAGE	0x05
-
 static DEFINE_MUTEX(idefloppy_ref_mutex);
 
-#define to_ide_floppy(obj) container_of(obj, struct ide_floppy_obj, kref)
-
-#define ide_floppy_g(disk) \
-	container_of((disk)->private_data, struct ide_floppy_obj, driver)
-
 static void idefloppy_cleanup_obj(struct kref *);
 
 static struct ide_floppy_obj *ide_floppy_get(struct gendisk *disk)
@@ -165,7 +92,7 @@
 	struct ide_floppy_obj *floppy = NULL;
 
 	mutex_lock(&idefloppy_ref_mutex);
-	floppy = ide_floppy_g(disk);
+	floppy = ide_drv_g(disk, ide_floppy_obj);
 	if (floppy) {
 		if (ide_device_get(floppy->drive))
 			floppy = NULL;
@@ -196,13 +123,21 @@
 	struct request *rq = HWGROUP(drive)->rq;
 	int error;
 
-	debug_log("Reached %s\n", __func__);
+	ide_debug_log(IDE_DBG_FUNC, "Call %s\n", __func__);
 
 	switch (uptodate) {
-	case 0: error = IDEFLOPPY_ERROR_GENERAL; break;
-	case 1: error = 0; break;
-	default: error = uptodate;
+	case 0:
+		error = IDEFLOPPY_ERROR_GENERAL;
+		break;
+
+	case 1:
+		error = 0;
+		break;
+
+	default:
+		error = uptodate;
 	}
+
 	if (error)
 		floppy->failed_pc = NULL;
 	/* Why does this happen? */
@@ -219,44 +154,6 @@
 	return 0;
 }
 
-static void ide_floppy_io_buffers(ide_drive_t *drive, struct ide_atapi_pc *pc,
-				  unsigned int bcount, int direction)
-{
-	ide_hwif_t *hwif = drive->hwif;
-	struct request *rq = pc->rq;
-	struct req_iterator iter;
-	struct bio_vec *bvec;
-	unsigned long flags;
-	int count, done = 0;
-	char *data;
-
-	rq_for_each_segment(bvec, rq, iter) {
-		if (!bcount)
-			break;
-
-		count = min(bvec->bv_len, bcount);
-
-		data = bvec_kmap_irq(bvec, &flags);
-		if (direction)
-			hwif->tp_ops->output_data(drive, NULL, data, count);
-		else
-			hwif->tp_ops->input_data(drive, NULL, data, count);
-		bvec_kunmap_irq(data, &flags);
-
-		bcount -= count;
-		pc->b_count += count;
-		done += count;
-	}
-
-	idefloppy_end_request(drive, 1, done >> 9);
-
-	if (bcount) {
-		printk(KERN_ERR "%s: leftover data in %s, bcount == %d\n",
-				drive->name, __func__, bcount);
-		ide_pad_transfer(drive, direction, bcount);
-	}
-}
-
 static void idefloppy_update_buffers(ide_drive_t *drive,
 				struct ide_atapi_pc *pc)
 {
@@ -267,50 +164,13 @@
 		idefloppy_end_request(drive, 1, 0);
 }
 
-/*
- * Generate a new packet command request in front of the request queue, before
- * the current request so that it will be processed immediately, on the next
- * pass through the driver.
- */
-static void idefloppy_queue_pc_head(ide_drive_t *drive, struct ide_atapi_pc *pc,
-		struct request *rq)
-{
-	struct ide_floppy_obj *floppy = drive->driver_data;
-
-	blk_rq_init(NULL, rq);
-	rq->buffer = (char *) pc;
-	rq->cmd_type = REQ_TYPE_SPECIAL;
-	rq->cmd_flags |= REQ_PREEMPT;
-	rq->rq_disk = floppy->disk;
-	memcpy(rq->cmd, pc->c, 12);
-	ide_do_drive_cmd(drive, rq);
-}
-
-static struct ide_atapi_pc *idefloppy_next_pc_storage(ide_drive_t *drive)
+static void ide_floppy_callback(ide_drive_t *drive, int dsc)
 {
 	idefloppy_floppy_t *floppy = drive->driver_data;
-
-	if (floppy->pc_stack_index == IDEFLOPPY_PC_STACK)
-		floppy->pc_stack_index = 0;
-	return (&floppy->pc_stack[floppy->pc_stack_index++]);
-}
-
-static struct request *idefloppy_next_rq_storage(ide_drive_t *drive)
-{
-	idefloppy_floppy_t *floppy = drive->driver_data;
-
-	if (floppy->rq_stack_index == IDEFLOPPY_PC_STACK)
-		floppy->rq_stack_index = 0;
-	return (&floppy->rq_stack[floppy->rq_stack_index++]);
-}
-
-static void ide_floppy_callback(ide_drive_t *drive)
-{
-	idefloppy_floppy_t *floppy = drive->driver_data;
-	struct ide_atapi_pc *pc = floppy->pc;
+	struct ide_atapi_pc *pc = drive->pc;
 	int uptodate = pc->error ? 0 : 1;
 
-	debug_log("Reached %s\n", __func__);
+	ide_debug_log(IDE_DBG_FUNC, "Call %s\n", __func__);
 
 	if (floppy->failed_pc == pc)
 		floppy->failed_pc = NULL;
@@ -319,7 +179,7 @@
 	    (pc->rq && blk_pc_request(pc->rq)))
 		uptodate = 1; /* FIXME */
 	else if (pc->c[0] == GPCMD_REQUEST_SENSE) {
-		u8 *buf = floppy->pc->buf;
+		u8 *buf = pc->buf;
 
 		if (!pc->error) {
 			floppy->sense_key = buf[2] & 0x0F;
@@ -329,108 +189,20 @@
 				(u16)get_unaligned((u16 *)&buf[16]) : 0x10000;
 
 			if (floppy->failed_pc)
-				debug_log("pc = %x, ", floppy->failed_pc->c[0]);
+				ide_debug_log(IDE_DBG_PC, "pc = %x, ",
+					      floppy->failed_pc->c[0]);
 
-			debug_log("sense key = %x, asc = %x, ascq = %x\n",
-				  floppy->sense_key, floppy->asc, floppy->ascq);
+			ide_debug_log(IDE_DBG_SENSE, "sense key = %x, asc = %x,"
+				      "ascq = %x\n", floppy->sense_key,
+				      floppy->asc, floppy->ascq);
 		} else
-			printk(KERN_ERR "Error in REQUEST SENSE itself - "
-					"Aborting request!\n");
+			printk(KERN_ERR PFX "Error in REQUEST SENSE itself - "
+			       "Aborting request!\n");
 	}
 
 	idefloppy_end_request(drive, uptodate, 0);
 }
 
-static void idefloppy_init_pc(struct ide_atapi_pc *pc)
-{
-	memset(pc, 0, sizeof(*pc));
-	pc->buf = pc->pc_buf;
-	pc->buf_size = IDEFLOPPY_PC_BUFFER_SIZE;
-}
-
-static void idefloppy_create_request_sense_cmd(struct ide_atapi_pc *pc)
-{
-	idefloppy_init_pc(pc);
-	pc->c[0] = GPCMD_REQUEST_SENSE;
-	pc->c[4] = 255;
-	pc->req_xfer = 18;
-}
-
-/*
- * Called when an error was detected during the last packet command. We queue a
- * request sense packet command in the head of the request list.
- */
-static void idefloppy_retry_pc(ide_drive_t *drive)
-{
-	struct ide_atapi_pc *pc;
-	struct request *rq;
-
-	(void)ide_read_error(drive);
-	pc = idefloppy_next_pc_storage(drive);
-	rq = idefloppy_next_rq_storage(drive);
-	idefloppy_create_request_sense_cmd(pc);
-	idefloppy_queue_pc_head(drive, pc, rq);
-}
-
-/* The usual interrupt handler called during a packet command. */
-static ide_startstop_t idefloppy_pc_intr(ide_drive_t *drive)
-{
-	idefloppy_floppy_t *floppy = drive->driver_data;
-
-	return ide_pc_intr(drive, floppy->pc, idefloppy_pc_intr,
-			   IDEFLOPPY_WAIT_CMD, NULL, idefloppy_update_buffers,
-			   idefloppy_retry_pc, NULL, ide_floppy_io_buffers);
-}
-
-/*
- * What we have here is a classic case of a top half / bottom half interrupt
- * service routine. In interrupt mode, the device sends an interrupt to signal
- * that it is ready to receive a packet. However, we need to delay about 2-3
- * ticks before issuing the packet or we gets in trouble.
- */
-static int idefloppy_transfer_pc(ide_drive_t *drive)
-{
-	idefloppy_floppy_t *floppy = drive->driver_data;
-
-	/* Send the actual packet */
-	drive->hwif->tp_ops->output_data(drive, NULL, floppy->pc->c, 12);
-
-	/* Timeout for the packet command */
-	return IDEFLOPPY_WAIT_CMD;
-}
-
-
-/*
- * Called as an interrupt (or directly). When the device says it's ready for a
- * packet, we schedule the packet transfer to occur about 2-3 ticks later in
- * transfer_pc.
- */
-static ide_startstop_t idefloppy_start_pc_transfer(ide_drive_t *drive)
-{
-	idefloppy_floppy_t *floppy = drive->driver_data;
-	struct ide_atapi_pc *pc = floppy->pc;
-	ide_expiry_t *expiry;
-	unsigned int timeout;
-
-	/*
-	 * The following delay solves a problem with ATAPI Zip 100 drives
-	 * where the Busy flag was apparently being deasserted before the
-	 * unit was ready to receive data. This was happening on a
-	 * 1200 MHz Athlon system. 10/26/01 25msec is too short,
-	 * 40 and 50msec work well. idefloppy_pc_intr will not be actually
-	 * used until after the packet is moved in about 50 msec.
-	 */
-	if (drive->atapi_flags & IDE_AFLAG_ZIP_DRIVE) {
-		timeout = floppy->ticks;
-		expiry = &idefloppy_transfer_pc;
-	} else {
-		timeout = IDEFLOPPY_WAIT_CMD;
-		expiry = NULL;
-	}
-
-	return ide_transfer_pc(drive, pc, idefloppy_pc_intr, timeout, expiry);
-}
-
 static void ide_floppy_report_error(idefloppy_floppy_t *floppy,
 				    struct ide_atapi_pc *pc)
 {
@@ -440,7 +212,7 @@
 	    floppy->ascq      == 0x00)
 		return;
 
-	printk(KERN_ERR "ide-floppy: %s: I/O error, pc = %2x, key = %2x, "
+	printk(KERN_ERR PFX "%s: I/O error, pc = %2x, key = %2x, "
 			"asc = %2x, ascq = %2x\n",
 			floppy->drive->name, pc->c[0], floppy->sense_key,
 			floppy->asc, floppy->ascq);
@@ -455,8 +227,9 @@
 	if (floppy->failed_pc == NULL &&
 	    pc->c[0] != GPCMD_REQUEST_SENSE)
 		floppy->failed_pc = pc;
+
 	/* Set the current packet command */
-	floppy->pc = pc;
+	drive->pc = pc;
 
 	if (pc->retries > IDEFLOPPY_MAX_PC_RETRIES) {
 		if (!(pc->flags & PC_FLAG_SUPPRESS_ERROR))
@@ -465,67 +238,35 @@
 		pc->error = IDEFLOPPY_ERROR_GENERAL;
 
 		floppy->failed_pc = NULL;
-		drive->pc_callback(drive);
+		drive->pc_callback(drive, 0);
 		return ide_stopped;
 	}
 
-	debug_log("Retry number - %d\n", pc->retries);
+	ide_debug_log(IDE_DBG_FUNC, "%s: Retry #%d\n", __func__, pc->retries);
 
 	pc->retries++;
 
-	return ide_issue_pc(drive, pc, idefloppy_start_pc_transfer,
-			    IDEFLOPPY_WAIT_CMD, NULL);
+	return ide_issue_pc(drive, WAIT_FLOPPY_CMD, NULL);
 }
 
-static void idefloppy_create_prevent_cmd(struct ide_atapi_pc *pc, int prevent)
+void ide_floppy_create_read_capacity_cmd(struct ide_atapi_pc *pc)
 {
-	debug_log("creating prevent removal command, prevent = %d\n", prevent);
-
-	idefloppy_init_pc(pc);
-	pc->c[0] = GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL;
-	pc->c[4] = prevent;
-}
-
-static void idefloppy_create_read_capacity_cmd(struct ide_atapi_pc *pc)
-{
-	idefloppy_init_pc(pc);
+	ide_init_pc(pc);
 	pc->c[0] = GPCMD_READ_FORMAT_CAPACITIES;
 	pc->c[7] = 255;
 	pc->c[8] = 255;
 	pc->req_xfer = 255;
 }
 
-static void idefloppy_create_format_unit_cmd(struct ide_atapi_pc *pc, int b,
-		int l, int flags)
-{
-	idefloppy_init_pc(pc);
-	pc->c[0] = GPCMD_FORMAT_UNIT;
-	pc->c[1] = 0x17;
-
-	memset(pc->buf, 0, 12);
-	pc->buf[1] = 0xA2;
-	/* Default format list header, u8 1: FOV/DCRT/IMM bits set */
-
-	if (flags & 1)				/* Verify bit on... */
-		pc->buf[1] ^= 0x20;		/* ... turn off DCRT bit */
-	pc->buf[3] = 8;
-
-	put_unaligned(cpu_to_be32(b), (unsigned int *)(&pc->buf[4]));
-	put_unaligned(cpu_to_be32(l), (unsigned int *)(&pc->buf[8]));
-	pc->buf_size = 12;
-	pc->flags |= PC_FLAG_WRITING;
-}
-
 /* A mode sense command is used to "sense" floppy parameters. */
-static void idefloppy_create_mode_sense_cmd(struct ide_atapi_pc *pc,
-		u8 page_code, u8 type)
+void ide_floppy_create_mode_sense_cmd(struct ide_atapi_pc *pc, u8 page_code)
 {
 	u16 length = 8; /* sizeof(Mode Parameter Header) = 8 Bytes */
 
-	idefloppy_init_pc(pc);
+	ide_init_pc(pc);
 	pc->c[0] = GPCMD_MODE_SENSE_10;
 	pc->c[1] = 0;
-	pc->c[2] = page_code + (type << 6);
+	pc->c[2] = page_code;
 
 	switch (page_code) {
 	case IDEFLOPPY_CAPABILITIES_PAGE:
@@ -535,32 +276,25 @@
 		length += 32;
 		break;
 	default:
-		printk(KERN_ERR "ide-floppy: unsupported page code "
-				"in create_mode_sense_cmd\n");
+		printk(KERN_ERR PFX "unsupported page code in %s\n", __func__);
 	}
 	put_unaligned(cpu_to_be16(length), (u16 *) &pc->c[7]);
 	pc->req_xfer = length;
 }
 
-static void idefloppy_create_start_stop_cmd(struct ide_atapi_pc *pc, int start)
-{
-	idefloppy_init_pc(pc);
-	pc->c[0] = GPCMD_START_STOP_UNIT;
-	pc->c[4] = start;
-}
-
-static void idefloppy_create_rw_cmd(idefloppy_floppy_t *floppy,
+static void idefloppy_create_rw_cmd(ide_drive_t *drive,
 				    struct ide_atapi_pc *pc, struct request *rq,
 				    unsigned long sector)
 {
+	idefloppy_floppy_t *floppy = drive->driver_data;
 	int block = sector / floppy->bs_factor;
 	int blocks = rq->nr_sectors / floppy->bs_factor;
 	int cmd = rq_data_dir(rq);
 
-	debug_log("create_rw10_cmd: block == %d, blocks == %d\n",
-		block, blocks);
+	ide_debug_log(IDE_DBG_FUNC, "%s: block: %d, blocks: %d\n", __func__,
+		      block, blocks);
 
-	idefloppy_init_pc(pc);
+	ide_init_pc(pc);
 	pc->c[0] = cmd == READ ? GPCMD_READ_10 : GPCMD_WRITE_10;
 	put_unaligned(cpu_to_be16(blocks), (unsigned short *)&pc->c[7]);
 	put_unaligned(cpu_to_be32(block), (unsigned int *) &pc->c[2]);
@@ -568,7 +302,7 @@
 	memcpy(rq->cmd, pc->c, 12);
 
 	pc->rq = rq;
-	pc->b_count = cmd == READ ? 0 : rq->bio->bi_size;
+	pc->b_count = 0;
 	if (rq->cmd_flags & REQ_RW)
 		pc->flags |= PC_FLAG_WRITING;
 	pc->buf = NULL;
@@ -579,10 +313,10 @@
 static void idefloppy_blockpc_cmd(idefloppy_floppy_t *floppy,
 		struct ide_atapi_pc *pc, struct request *rq)
 {
-	idefloppy_init_pc(pc);
+	ide_init_pc(pc);
 	memcpy(pc->c, rq->cmd, sizeof(pc->c));
 	pc->rq = rq;
-	pc->b_count = rq->data_len;
+	pc->b_count = 0;
 	if (rq->data_len && rq_data_dir(rq) == WRITE)
 		pc->flags |= PC_FLAG_WRITING;
 	pc->buf = rq->data;
@@ -599,95 +333,89 @@
 		struct request *rq, sector_t block_s)
 {
 	idefloppy_floppy_t *floppy = drive->driver_data;
+	ide_hwif_t *hwif = drive->hwif;
 	struct ide_atapi_pc *pc;
 	unsigned long block = (unsigned long)block_s;
 
-	debug_log("dev: %s, cmd_type: %x, errors: %d\n",
-			rq->rq_disk ? rq->rq_disk->disk_name : "?",
-			rq->cmd_type, rq->errors);
-	debug_log("sector: %ld, nr_sectors: %ld, "
-			"current_nr_sectors: %d\n", (long)rq->sector,
-			rq->nr_sectors, rq->current_nr_sectors);
+	ide_debug_log(IDE_DBG_FUNC, "%s: dev: %s, cmd: 0x%x, cmd_type: %x, "
+		      "errors: %d\n",
+		      __func__, rq->rq_disk ? rq->rq_disk->disk_name : "?",
+		      rq->cmd[0], rq->cmd_type, rq->errors);
+
+	ide_debug_log(IDE_DBG_FUNC, "%s: sector: %ld, nr_sectors: %ld, "
+		      "current_nr_sectors: %d\n",
+		      __func__, (long)rq->sector, rq->nr_sectors,
+		      rq->current_nr_sectors);
 
 	if (rq->errors >= ERROR_MAX) {
 		if (floppy->failed_pc)
 			ide_floppy_report_error(floppy, floppy->failed_pc);
 		else
-			printk(KERN_ERR "ide-floppy: %s: I/O error\n",
-				drive->name);
+			printk(KERN_ERR PFX "%s: I/O error\n", drive->name);
+
 		idefloppy_end_request(drive, 0, 0);
 		return ide_stopped;
 	}
 	if (blk_fs_request(rq)) {
 		if (((long)rq->sector % floppy->bs_factor) ||
 		    (rq->nr_sectors % floppy->bs_factor)) {
-			printk(KERN_ERR "%s: unsupported r/w request size\n",
-					drive->name);
+			printk(KERN_ERR PFX "%s: unsupported r/w rq size\n",
+				drive->name);
 			idefloppy_end_request(drive, 0, 0);
 			return ide_stopped;
 		}
-		pc = idefloppy_next_pc_storage(drive);
-		idefloppy_create_rw_cmd(floppy, pc, rq, block);
+		pc = &floppy->queued_pc;
+		idefloppy_create_rw_cmd(drive, pc, rq, block);
 	} else if (blk_special_request(rq)) {
 		pc = (struct ide_atapi_pc *) rq->buffer;
 	} else if (blk_pc_request(rq)) {
-		pc = idefloppy_next_pc_storage(drive);
+		pc = &floppy->queued_pc;
 		idefloppy_blockpc_cmd(floppy, pc, rq);
 	} else {
-		blk_dump_rq_flags(rq,
-			"ide-floppy: unsupported command in queue");
+		blk_dump_rq_flags(rq, PFX "unsupported command in queue");
 		idefloppy_end_request(drive, 0, 0);
 		return ide_stopped;
 	}
 
+	ide_init_sg_cmd(drive, rq);
+	ide_map_sg(drive, rq);
+
+	pc->sg = hwif->sg_table;
+	pc->sg_cnt = hwif->sg_nents;
+
 	pc->rq = rq;
 
 	return idefloppy_issue_pc(drive, pc);
 }
 
 /*
- * Add a special packet command request to the tail of the request queue,
- * and wait for it to be serviced.
- */
-static int idefloppy_queue_pc_tail(ide_drive_t *drive, struct ide_atapi_pc *pc)
-{
-	struct ide_floppy_obj *floppy = drive->driver_data;
-	struct request *rq;
-	int error;
-
-	rq = blk_get_request(drive->queue, READ, __GFP_WAIT);
-	rq->buffer = (char *) pc;
-	rq->cmd_type = REQ_TYPE_SPECIAL;
-	memcpy(rq->cmd, pc->c, 12);
-	error = blk_execute_rq(drive->queue, floppy->disk, rq, 0);
-	blk_put_request(rq);
-
-	return error;
-}
-
-/*
  * Look at the flexible disk page parameters. We ignore the CHS capacity
  * parameters and use the LBA parameters instead.
  */
 static int ide_floppy_get_flexible_disk_page(ide_drive_t *drive)
 {
 	idefloppy_floppy_t *floppy = drive->driver_data;
+	struct gendisk *disk = floppy->disk;
 	struct ide_atapi_pc pc;
 	u8 *page;
 	int capacity, lba_capacity;
 	u16 transfer_rate, sector_size, cyls, rpm;
 	u8 heads, sectors;
 
-	idefloppy_create_mode_sense_cmd(&pc, IDEFLOPPY_FLEXIBLE_DISK_PAGE,
-					MODE_SENSE_CURRENT);
+	ide_floppy_create_mode_sense_cmd(&pc, IDEFLOPPY_FLEXIBLE_DISK_PAGE);
 
-	if (idefloppy_queue_pc_tail(drive, &pc)) {
-		printk(KERN_ERR "ide-floppy: Can't get flexible disk page"
-				" parameters\n");
+	if (ide_queue_pc_tail(drive, disk, &pc)) {
+		printk(KERN_ERR PFX "Can't get flexible disk page params\n");
 		return 1;
 	}
-	floppy->wp = !!(pc.buf[3] & 0x80);
-	set_disk_ro(floppy->disk, floppy->wp);
+
+	if (pc.buf[3] & 0x80)
+		drive->atapi_flags |= IDE_AFLAG_WP;
+	else
+		drive->atapi_flags &= ~IDE_AFLAG_WP;
+
+	set_disk_ro(disk, !!(drive->atapi_flags & IDE_AFLAG_WP));
+
 	page = &pc.buf[8];
 
 	transfer_rate = be16_to_cpup((__be16 *)&pc.buf[8 + 2]);
@@ -700,7 +428,7 @@
 	capacity = cyls * heads * sectors * sector_size;
 
 	if (memcmp(page, &floppy->flexible_disk_page, 32))
-		printk(KERN_INFO "%s: %dkB, %d/%d/%d CHS, %d kBps, "
+		printk(KERN_INFO PFX "%s: %dkB, %d/%d/%d CHS, %d kBps, "
 				"%d sector size, %d rpm\n",
 				drive->name, capacity / 1024, cyls, heads,
 				sectors, transfer_rate / 8, sector_size, rpm);
@@ -712,7 +440,7 @@
 	lba_capacity = floppy->blocks * floppy->block_size;
 
 	if (capacity < lba_capacity) {
-		printk(KERN_NOTICE "%s: The disk reports a capacity of %d "
+		printk(KERN_NOTICE PFX "%s: The disk reports a capacity of %d "
 			"bytes, but the drive only handles %d\n",
 			drive->name, lba_capacity, capacity);
 		floppy->blocks = floppy->block_size ?
@@ -721,23 +449,6 @@
 	return 0;
 }
 
-static int idefloppy_get_sfrp_bit(ide_drive_t *drive)
-{
-	idefloppy_floppy_t *floppy = drive->driver_data;
-	struct ide_atapi_pc pc;
-
-	floppy->srfp = 0;
-	idefloppy_create_mode_sense_cmd(&pc, IDEFLOPPY_CAPABILITIES_PAGE,
-						 MODE_SENSE_CURRENT);
-
-	pc.flags |= PC_FLAG_SUPPRESS_ERROR;
-	if (idefloppy_queue_pc_tail(drive, &pc))
-		return 1;
-
-	floppy->srfp = pc.buf[8 + 2] & 0x40;
-	return (0);
-}
-
 /*
  * Determine if a media is present in the floppy drive, and if so, its LBA
  * capacity.
@@ -745,6 +456,7 @@
 static int ide_floppy_get_capacity(ide_drive_t *drive)
 {
 	idefloppy_floppy_t *floppy = drive->driver_data;
+	struct gendisk *disk = floppy->disk;
 	struct ide_atapi_pc pc;
 	u8 *cap_desc;
 	u8 header_len, desc_cnt;
@@ -756,9 +468,9 @@
 	floppy->bs_factor = 1;
 	set_capacity(floppy->disk, 0);
 
-	idefloppy_create_read_capacity_cmd(&pc);
-	if (idefloppy_queue_pc_tail(drive, &pc)) {
-		printk(KERN_ERR "ide-floppy: Can't get floppy parameters\n");
+	ide_floppy_create_read_capacity_cmd(&pc);
+	if (ide_queue_pc_tail(drive, disk, &pc)) {
+		printk(KERN_ERR PFX "Can't get floppy parameters\n");
 		return 1;
 	}
 	header_len = pc.buf[3];
@@ -771,8 +483,9 @@
 		blocks = be32_to_cpup((__be32 *)&pc.buf[desc_start]);
 		length = be16_to_cpup((__be16 *)&pc.buf[desc_start + 6]);
 
-		debug_log("Descriptor %d: %dkB, %d blocks, %d sector size\n",
-				i, blocks * length / 1024, blocks, length);
+		ide_debug_log(IDE_DBG_PROBE, "Descriptor %d: %dkB, %d blocks, "
+			      "%d sector size\n",
+			      i, blocks * length / 1024, blocks, length);
 
 		if (i)
 			continue;
@@ -792,23 +505,24 @@
 		case CAPACITY_CURRENT:
 			/* Normal Zip/LS-120 disks */
 			if (memcmp(cap_desc, &floppy->cap_desc, 8))
-				printk(KERN_INFO "%s: %dkB, %d blocks, %d "
-					"sector size\n", drive->name,
-					blocks * length / 1024, blocks, length);
+				printk(KERN_INFO PFX "%s: %dkB, %d blocks, %d "
+				       "sector size\n",
+				       drive->name, blocks * length / 1024,
+				       blocks, length);
 			memcpy(&floppy->cap_desc, cap_desc, 8);
 
 			if (!length || length % 512) {
-				printk(KERN_NOTICE "%s: %d bytes block size "
-					"not supported\n", drive->name, length);
+				printk(KERN_NOTICE PFX "%s: %d bytes block size"
+				       " not supported\n", drive->name, length);
 			} else {
 				floppy->blocks = blocks;
 				floppy->block_size = length;
 				floppy->bs_factor = length / 512;
 				if (floppy->bs_factor != 1)
-					printk(KERN_NOTICE "%s: warning: non "
-						"512 bytes block size not "
-						"fully supported\n",
-						drive->name);
+					printk(KERN_NOTICE PFX "%s: Warning: "
+					       "non 512 bytes block size not "
+					       "fully supported\n",
+					       drive->name);
 				rc = 0;
 			}
 			break;
@@ -817,143 +531,28 @@
 			 * This is a KERN_ERR so it appears on screen
 			 * for the user to see
 			 */
-			printk(KERN_ERR "%s: No disk in drive\n", drive->name);
+			printk(KERN_ERR PFX "%s: No disk in drive\n",
+			       drive->name);
 			break;
 		case CAPACITY_INVALID:
-			printk(KERN_ERR "%s: Invalid capacity for disk "
+			printk(KERN_ERR PFX "%s: Invalid capacity for disk "
 				"in drive\n", drive->name);
 			break;
 		}
-		debug_log("Descriptor 0 Code: %d\n",
-			  pc.buf[desc_start + 4] & 0x03);
+		ide_debug_log(IDE_DBG_PROBE, "Descriptor 0 Code: %d\n",
+			      pc.buf[desc_start + 4] & 0x03);
 	}
 
 	/* Clik! disk does not support get_flexible_disk_page */
 	if (!(drive->atapi_flags & IDE_AFLAG_CLIK_DRIVE))
 		(void) ide_floppy_get_flexible_disk_page(drive);
 
-	set_capacity(floppy->disk, floppy->blocks * floppy->bs_factor);
+	set_capacity(disk, floppy->blocks * floppy->bs_factor);
+
 	return rc;
 }
 
-/*
- * Obtain the list of formattable capacities.
- * Very similar to ide_floppy_get_capacity, except that we push the capacity
- * descriptors to userland, instead of our own structures.
- *
- * Userland gives us the following structure:
- *
- * struct idefloppy_format_capacities {
- *	int nformats;
- *	struct {
- *		int nblocks;
- *		int blocksize;
- *	} formats[];
- * };
- *
- * userland initializes nformats to the number of allocated formats[] records.
- * On exit we set nformats to the number of records we've actually initialized.
- */
-
-static int ide_floppy_get_format_capacities(ide_drive_t *drive, int __user *arg)
-{
-	struct ide_atapi_pc pc;
-	u8 header_len, desc_cnt;
-	int i, blocks, length, u_array_size, u_index;
-	int __user *argp;
-
-	if (get_user(u_array_size, arg))
-		return (-EFAULT);
-
-	if (u_array_size <= 0)
-		return (-EINVAL);
-
-	idefloppy_create_read_capacity_cmd(&pc);
-	if (idefloppy_queue_pc_tail(drive, &pc)) {
-		printk(KERN_ERR "ide-floppy: Can't get floppy parameters\n");
-		return (-EIO);
-	}
-	header_len = pc.buf[3];
-	desc_cnt = header_len / 8; /* capacity descriptor of 8 bytes */
-
-	u_index = 0;
-	argp = arg + 1;
-
-	/*
-	 * We always skip the first capacity descriptor.  That's the current
-	 * capacity.  We are interested in the remaining descriptors, the
-	 * formattable capacities.
-	 */
-	for (i = 1; i < desc_cnt; i++) {
-		unsigned int desc_start = 4 + i*8;
-
-		if (u_index >= u_array_size)
-			break;	/* User-supplied buffer too small */
-
-		blocks = be32_to_cpup((__be32 *)&pc.buf[desc_start]);
-		length = be16_to_cpup((__be16 *)&pc.buf[desc_start + 6]);
-
-		if (put_user(blocks, argp))
-			return(-EFAULT);
-		++argp;
-
-		if (put_user(length, argp))
-			return (-EFAULT);
-		++argp;
-
-		++u_index;
-	}
-
-	if (put_user(u_index, arg))
-		return (-EFAULT);
-	return (0);
-}
-
-/*
- * Get ATAPI_FORMAT_UNIT progress indication.
- *
- * Userland gives a pointer to an int.  The int is set to a progress
- * indicator 0-65536, with 65536=100%.
- *
- * If the drive does not support format progress indication, we just check
- * the dsc bit, and return either 0 or 65536.
- */
-
-static int idefloppy_get_format_progress(ide_drive_t *drive, int __user *arg)
-{
-	idefloppy_floppy_t *floppy = drive->driver_data;
-	struct ide_atapi_pc pc;
-	int progress_indication = 0x10000;
-
-	if (floppy->srfp) {
-		idefloppy_create_request_sense_cmd(&pc);
-		if (idefloppy_queue_pc_tail(drive, &pc))
-			return (-EIO);
-
-		if (floppy->sense_key == 2 &&
-		    floppy->asc == 4 &&
-		    floppy->ascq == 4)
-			progress_indication = floppy->progress_indication;
-
-		/* Else assume format_unit has finished, and we're at 0x10000 */
-	} else {
-		ide_hwif_t *hwif = drive->hwif;
-		unsigned long flags;
-		u8 stat;
-
-		local_irq_save(flags);
-		stat = hwif->tp_ops->read_status(hwif);
-		local_irq_restore(flags);
-
-		progress_indication = ((stat & SEEK_STAT) == 0) ? 0 : 0x10000;
-	}
-	if (put_user(progress_indication, arg))
-		return (-EFAULT);
-
-	return (0);
-}
-
-static sector_t idefloppy_capacity(ide_drive_t *drive)
+sector_t ide_floppy_capacity(ide_drive_t *drive)
 {
 	idefloppy_floppy_t *floppy = drive->driver_data;
 	unsigned long capacity = floppy->blocks * floppy->bs_factor;
@@ -961,77 +560,14 @@
 	return capacity;
 }
 
-/*
- * Check whether we can support a drive, based on the ATAPI IDENTIFY command
- * results.
- */
-static int idefloppy_identify_device(ide_drive_t *drive, struct hd_driveid *id)
-{
-	u8 gcw[2];
-	u8 device_type, protocol, removable, drq_type, packet_size;
-
-	*((u16 *) &gcw) = id->config;
-
-	device_type =  gcw[1] & 0x1F;
-	removable   = (gcw[0] & 0x80) >> 7;
-	protocol    = (gcw[1] & 0xC0) >> 6;
-	drq_type    = (gcw[0] & 0x60) >> 5;
-	packet_size =  gcw[0] & 0x03;
-
-#ifdef CONFIG_PPC
-	/* kludge for Apple PowerBook internal zip */
-	if (device_type == 5 &&
-	    !strstr(id->model, "CD-ROM") && strstr(id->model, "ZIP"))
-		device_type = 0;
-#endif
-
-	if (protocol != 2)
-		printk(KERN_ERR "ide-floppy: Protocol (0x%02x) is not ATAPI\n",
-			protocol);
-	else if (device_type != 0)
-		printk(KERN_ERR "ide-floppy: Device type (0x%02x) is not set "
-				"to floppy\n", device_type);
-	else if (!removable)
-		printk(KERN_ERR "ide-floppy: The removable flag is not set\n");
-	else if (drq_type == 3)
-		printk(KERN_ERR "ide-floppy: Sorry, DRQ type (0x%02x) not "
-				"supported\n", drq_type);
-	else if (packet_size != 0)
-		printk(KERN_ERR "ide-floppy: Packet size (0x%02x) is not 12 "
-				"bytes\n", packet_size);
-	else
-		return 1;
-	return 0;
-}
-
-#ifdef CONFIG_IDE_PROC_FS
-static void idefloppy_add_settings(ide_drive_t *drive)
-{
-	idefloppy_floppy_t *floppy = drive->driver_data;
-
-	ide_add_setting(drive, "bios_cyl", SETTING_RW, TYPE_INT, 0, 1023, 1, 1,
-			&drive->bios_cyl, NULL);
-	ide_add_setting(drive, "bios_head", SETTING_RW, TYPE_BYTE, 0, 255, 1, 1,
-			&drive->bios_head, NULL);
-	ide_add_setting(drive, "bios_sect", SETTING_RW,	TYPE_BYTE, 0,  63, 1, 1,
-			&drive->bios_sect, NULL);
-	ide_add_setting(drive, "ticks",	   SETTING_RW, TYPE_BYTE, 0, 255, 1, 1,
-			&floppy->ticks,	 NULL);
-}
-#else
-static inline void idefloppy_add_settings(ide_drive_t *drive) { ; }
-#endif
-
 static void idefloppy_setup(ide_drive_t *drive, idefloppy_floppy_t *floppy)
 {
-	u8 gcw[2];
+	u16 *id = drive->id;
 
-	*((u16 *) &gcw) = drive->id->config;
-	floppy->pc = floppy->pc_stack;
-	drive->pc_callback = ide_floppy_callback;
+	drive->pc_callback	 = ide_floppy_callback;
+	drive->pc_update_buffers = idefloppy_update_buffers;
+	drive->pc_io_buffers	 = ide_io_buffers;
 
-	if (((gcw[0] & 0x60) >> 5) == 1)
-		drive->atapi_flags |= IDE_AFLAG_DRQ_INTERRUPT;
 	/*
 	 * We used to check revisions here. At this point however I'm giving up.
 	 * Just assume they are all broken, its easier.
@@ -1041,10 +577,10 @@
 	 * it. It should be fixed as of version 1.9, but to be on the safe side
 	 * we'll leave the limitation below for the 2.2.x tree.
 	 */
-	if (!strncmp(drive->id->model, "IOMEGA ZIP 100 ATAPI", 20)) {
+	if (!strncmp((char *)&id[ATA_ID_PROD], "IOMEGA ZIP 100 ATAPI", 20)) {
 		drive->atapi_flags |= IDE_AFLAG_ZIP_DRIVE;
 		/* This value will be visible in the /proc/ide/hdx/settings */
-		floppy->ticks = IDEFLOPPY_TICKS_DELAY;
+		drive->pc_delay = IDEFLOPPY_PC_DELAY;
 		blk_queue_max_sectors(drive->queue, 64);
 	}
 
@@ -1052,13 +588,16 @@
 	 * Guess what? The IOMEGA Clik! drive also needs the above fix. It makes
 	 * nasty clicking noises without it, so please don't remove this.
 	 */
-	if (strncmp(drive->id->model, "IOMEGA Clik!", 11) == 0) {
+	if (strncmp((char *)&id[ATA_ID_PROD], "IOMEGA Clik!", 11) == 0) {
 		blk_queue_max_sectors(drive->queue, 64);
 		drive->atapi_flags |= IDE_AFLAG_CLIK_DRIVE;
+		/* IOMEGA Clik! drives do not support lock/unlock commands */
+		drive->atapi_flags |= IDE_AFLAG_NO_DOORLOCK;
 	}
 
 	(void) ide_floppy_get_capacity(drive);
-	idefloppy_add_settings(drive);
+
+	ide_proc_register_driver(drive, floppy->driver);
 }
 
 static void ide_floppy_remove(ide_drive_t *drive)
@@ -1075,7 +614,7 @@
 
 static void idefloppy_cleanup_obj(struct kref *kref)
 {
-	struct ide_floppy_obj *floppy = to_ide_floppy(kref);
+	struct ide_floppy_obj *floppy = to_ide_drv(kref, ide_floppy_obj);
 	ide_drive_t *drive = floppy->drive;
 	struct gendisk *g = floppy->disk;
 
@@ -1085,24 +624,6 @@
 	kfree(floppy);
 }
 
-#ifdef CONFIG_IDE_PROC_FS
-static int proc_idefloppy_read_capacity(char *page, char **start, off_t off,
-		int count, int *eof, void *data)
-{
-	ide_drive_t*drive = (ide_drive_t *)data;
-	int len;
-
-	len = sprintf(page, "%llu\n", (long long)idefloppy_capacity(drive));
-	PROC_IDE_READ_RETURN(page, start, off, count, eof, len);
-}
-
-static ide_proc_entry_t idefloppy_proc[] = {
-	{ "capacity",	S_IFREG|S_IRUGO, proc_idefloppy_read_capacity,	NULL },
-	{ "geometry",	S_IFREG|S_IRUGO, proc_ide_read_geometry,	NULL },
-	{ NULL, 0, NULL, NULL }
-};
-#endif	/* CONFIG_IDE_PROC_FS */
-
 static int ide_floppy_probe(ide_drive_t *);
 
 static ide_driver_t idefloppy_driver = {
@@ -1114,13 +635,12 @@
 	.probe			= ide_floppy_probe,
 	.remove			= ide_floppy_remove,
 	.version		= IDEFLOPPY_VERSION,
-	.media			= ide_floppy,
-	.supports_dsc_overlap	= 0,
 	.do_request		= idefloppy_do_request,
 	.end_request		= idefloppy_end_request,
 	.error			= __ide_error,
 #ifdef CONFIG_IDE_PROC_FS
-	.proc			= idefloppy_proc,
+	.proc			= ide_floppy_proc,
+	.settings		= ide_floppy_settings,
 #endif
 };
 
@@ -1129,30 +649,24 @@
 	struct gendisk *disk = inode->i_bdev->bd_disk;
 	struct ide_floppy_obj *floppy;
 	ide_drive_t *drive;
-	struct ide_atapi_pc pc;
 	int ret = 0;
 
-	debug_log("Reached %s\n", __func__);
-
 	floppy = ide_floppy_get(disk);
 	if (!floppy)
 		return -ENXIO;
 
 	drive = floppy->drive;
 
+	ide_debug_log(IDE_DBG_FUNC, "Call %s\n", __func__);
+
 	floppy->openers++;
 
 	if (floppy->openers == 1) {
 		drive->atapi_flags &= ~IDE_AFLAG_FORMAT_IN_PROGRESS;
 		/* Just in case */
 
-		idefloppy_init_pc(&pc);
-		pc.c[0] = GPCMD_TEST_UNIT_READY;
-
-		if (idefloppy_queue_pc_tail(drive, &pc)) {
-			idefloppy_create_start_stop_cmd(&pc, 1);
-			(void) idefloppy_queue_pc_tail(drive, &pc);
-		}
+		if (ide_do_test_unit_ready(drive, disk))
+			ide_do_start_stop(drive, disk, 1);
 
 		if (ide_floppy_get_capacity(drive)
 		   && (filp->f_flags & O_NDELAY) == 0
@@ -1166,16 +680,13 @@
 			goto out_put_floppy;
 		}
 
-		if (floppy->wp && (filp->f_mode & 2)) {
+		if ((drive->atapi_flags & IDE_AFLAG_WP) && (filp->f_mode & 2)) {
 			ret = -EROFS;
 			goto out_put_floppy;
 		}
+
 		drive->atapi_flags |= IDE_AFLAG_MEDIA_CHANGED;
-		/* IOMEGA Clik! drives do not support lock/unlock commands */
-		if (!(drive->atapi_flags & IDE_AFLAG_CLIK_DRIVE)) {
-			idefloppy_create_prevent_cmd(&pc, 1);
-			(void) idefloppy_queue_pc_tail(drive, &pc);
-		}
+		ide_set_media_lock(drive, disk, 1);
 		check_disk_change(inode->i_bdev);
 	} else if (drive->atapi_flags & IDE_AFLAG_FORMAT_IN_PROGRESS) {
 		ret = -EBUSY;
@@ -1192,19 +703,13 @@
 static int idefloppy_release(struct inode *inode, struct file *filp)
 {
 	struct gendisk *disk = inode->i_bdev->bd_disk;
-	struct ide_floppy_obj *floppy = ide_floppy_g(disk);
+	struct ide_floppy_obj *floppy = ide_drv_g(disk, ide_floppy_obj);
 	ide_drive_t *drive = floppy->drive;
-	struct ide_atapi_pc pc;
 
-	debug_log("Reached %s\n", __func__);
+	ide_debug_log(IDE_DBG_FUNC, "Call %s\n", __func__);
 
 	if (floppy->openers == 1) {
-		/* IOMEGA Clik! drives do not support lock/unlock commands */
-		if (!(drive->atapi_flags & IDE_AFLAG_CLIK_DRIVE)) {
-			idefloppy_create_prevent_cmd(&pc, 0);
-			(void) idefloppy_queue_pc_tail(drive, &pc);
-		}
-
+		ide_set_media_lock(drive, disk, 0);
 		drive->atapi_flags &= ~IDE_AFLAG_FORMAT_IN_PROGRESS;
 	}
 
@@ -1217,7 +722,8 @@
 
 static int idefloppy_getgeo(struct block_device *bdev, struct hd_geometry *geo)
 {
-	struct ide_floppy_obj *floppy = ide_floppy_g(bdev->bd_disk);
+	struct ide_floppy_obj *floppy = ide_drv_g(bdev->bd_disk,
+						     ide_floppy_obj);
 	ide_drive_t *drive = floppy->drive;
 
 	geo->heads = drive->bios_head;
@@ -1226,137 +732,15 @@
 	return 0;
 }
 
-static int ide_floppy_lockdoor(ide_drive_t *drive, struct ide_atapi_pc *pc,
-			       unsigned long arg, unsigned int cmd)
-{
-	idefloppy_floppy_t *floppy = drive->driver_data;
-
-	if (floppy->openers > 1)
-		return -EBUSY;
-
-	/* The IOMEGA Clik! Drive doesn't support this command -
-	 * no room for an eject mechanism */
-	if (!(drive->atapi_flags & IDE_AFLAG_CLIK_DRIVE)) {
-		int prevent = arg ? 1 : 0;
-
-		if (cmd == CDROMEJECT)
-			prevent = 0;
-
-		idefloppy_create_prevent_cmd(pc, prevent);
-		(void) idefloppy_queue_pc_tail(floppy->drive, pc);
-	}
-
-	if (cmd == CDROMEJECT) {
-		idefloppy_create_start_stop_cmd(pc, 2);
-		(void) idefloppy_queue_pc_tail(floppy->drive, pc);
-	}
-
-	return 0;
-}
-
-static int ide_floppy_format_unit(idefloppy_floppy_t *floppy,
-				  int __user *arg)
-{
-	struct ide_atapi_pc pc;
-	ide_drive_t *drive = floppy->drive;
-	int blocks, length, flags, err = 0;
-
-	if (floppy->openers > 1) {
-		/* Don't format if someone is using the disk */
-		drive->atapi_flags &= ~IDE_AFLAG_FORMAT_IN_PROGRESS;
-		return -EBUSY;
-	}
-
-	drive->atapi_flags |= IDE_AFLAG_FORMAT_IN_PROGRESS;
-
-	/*
-	 * Send ATAPI_FORMAT_UNIT to the drive.
-	 *
-	 * Userland gives us the following structure:
-	 *
-	 * struct idefloppy_format_command {
-	 *        int nblocks;
-	 *        int blocksize;
-	 *        int flags;
-	 *        } ;
-	 *
-	 * flags is a bitmask, currently, the only defined flag is:
-	 *
-	 *        0x01 - verify media after format.
-	 */
-	if (get_user(blocks, arg) ||
-			get_user(length, arg+1) ||
-			get_user(flags, arg+2)) {
-		err = -EFAULT;
-		goto out;
-	}
-
-	(void) idefloppy_get_sfrp_bit(drive);
-	idefloppy_create_format_unit_cmd(&pc, blocks, length, flags);
-
-	if (idefloppy_queue_pc_tail(drive, &pc))
-		err = -EIO;
-
-out:
-	if (err)
-		drive->atapi_flags &= ~IDE_AFLAG_FORMAT_IN_PROGRESS;
-	return err;
-}
-
-
-static int idefloppy_ioctl(struct inode *inode, struct file *file,
-			unsigned int cmd, unsigned long arg)
-{
-	struct block_device *bdev = inode->i_bdev;
-	struct ide_floppy_obj *floppy = ide_floppy_g(bdev->bd_disk);
-	ide_drive_t *drive = floppy->drive;
-	struct ide_atapi_pc pc;
-	void __user *argp = (void __user *)arg;
-	int err;
-
-	switch (cmd) {
-	case CDROMEJECT:
-		/* fall through */
-	case CDROM_LOCKDOOR:
-		return ide_floppy_lockdoor(drive, &pc, arg, cmd);
-	case IDEFLOPPY_IOCTL_FORMAT_SUPPORTED:
-		return 0;
-	case IDEFLOPPY_IOCTL_FORMAT_GET_CAPACITY:
-		return ide_floppy_get_format_capacities(drive, argp);
-	case IDEFLOPPY_IOCTL_FORMAT_START:
-		if (!(file->f_mode & 2))
-			return -EPERM;
-
-		return ide_floppy_format_unit(floppy, (int __user *)arg);
-	case IDEFLOPPY_IOCTL_FORMAT_GET_PROGRESS:
-		return idefloppy_get_format_progress(drive, argp);
-	}
-
-	/*
-	 * skip SCSI_IOCTL_SEND_COMMAND (deprecated)
-	 * and CDROM_SEND_PACKET (legacy) ioctls
-	 */
-	if (cmd != CDROM_SEND_PACKET && cmd != SCSI_IOCTL_SEND_COMMAND)
-		err = scsi_cmd_ioctl(file, bdev->bd_disk->queue,
-					bdev->bd_disk, cmd, argp);
-	else
-		err = -ENOTTY;
-
-	if (err == -ENOTTY)
-		err = generic_ide_ioctl(drive, file, bdev, cmd, arg);
-
-	return err;
-}
-
 static int idefloppy_media_changed(struct gendisk *disk)
 {
-	struct ide_floppy_obj *floppy = ide_floppy_g(disk);
+	struct ide_floppy_obj *floppy = ide_drv_g(disk, ide_floppy_obj);
 	ide_drive_t *drive = floppy->drive;
 	int ret;
 
 	/* do not scan partitions twice if this is a removable device */
-	if (drive->attach) {
-		drive->attach = 0;
+	if (drive->dev_flags & IDE_DFLAG_ATTACH) {
+		drive->dev_flags &= ~IDE_DFLAG_ATTACH;
 		return 0;
 	}
 	ret = !!(drive->atapi_flags & IDE_AFLAG_MEDIA_CHANGED);
@@ -1366,8 +750,8 @@
 
 static int idefloppy_revalidate_disk(struct gendisk *disk)
 {
-	struct ide_floppy_obj *floppy = ide_floppy_g(disk);
-	set_capacity(disk, idefloppy_capacity(floppy->drive));
+	struct ide_floppy_obj *floppy = ide_drv_g(disk, ide_floppy_obj);
+	set_capacity(disk, ide_floppy_capacity(floppy->drive));
 	return 0;
 }
 
@@ -1375,7 +759,7 @@
 	.owner			= THIS_MODULE,
 	.open			= idefloppy_open,
 	.release		= idefloppy_release,
-	.ioctl			= idefloppy_ioctl,
+	.ioctl			= ide_floppy_ioctl,
 	.getgeo			= idefloppy_getgeo,
 	.media_changed		= idefloppy_media_changed,
 	.revalidate_disk	= idefloppy_revalidate_disk
@@ -1388,19 +772,19 @@
 
 	if (!strstr("ide-floppy", drive->driver_req))
 		goto failed;
-	if (!drive->present)
-		goto failed;
+
 	if (drive->media != ide_floppy)
 		goto failed;
-	if (!idefloppy_identify_device(drive, drive->id)) {
-		printk(KERN_ERR "ide-floppy: %s: not supported by this version"
-				" of ide-floppy\n", drive->name);
+
+	if (!ide_check_atapi_device(drive, DRV_NAME)) {
+		printk(KERN_ERR PFX "%s: not supported by this version of "
+		       DRV_NAME "\n", drive->name);
 		goto failed;
 	}
 	floppy = kzalloc(sizeof(idefloppy_floppy_t), GFP_KERNEL);
 	if (!floppy) {
-		printk(KERN_ERR "ide-floppy: %s: Can't allocate a floppy"
-				" structure\n", drive->name);
+		printk(KERN_ERR PFX "%s: Can't allocate a floppy structure\n",
+		       drive->name);
 		goto failed;
 	}
 
@@ -1410,8 +794,6 @@
 
 	ide_init_disk(g, drive);
 
-	ide_proc_register_driver(drive, &idefloppy_driver);
-
 	kref_init(&floppy->kref);
 
 	floppy->drive = drive;
@@ -1422,13 +804,16 @@
 
 	drive->driver_data = floppy;
 
+	drive->debug_mask = debug_mask;
+
 	idefloppy_setup(drive, floppy);
+	drive->dev_flags |= IDE_DFLAG_ATTACH;
 
 	g->minors = 1 << PARTN_BITS;
 	g->driverfs_dev = &drive->gendev;
-	g->flags = drive->removable ? GENHD_FL_REMOVABLE : 0;
+	if (drive->dev_flags & IDE_DFLAG_REMOVABLE)
+		g->flags = GENHD_FL_REMOVABLE;
 	g->fops = &idefloppy_ops;
-	drive->attach = 1;
 	add_disk(g);
 	return 0;
 
@@ -1445,11 +830,12 @@
 
 static int __init idefloppy_init(void)
 {
-	printk("ide-floppy driver " IDEFLOPPY_VERSION "\n");
+	printk(KERN_INFO DRV_NAME " driver " IDEFLOPPY_VERSION "\n");
 	return driver_register(&idefloppy_driver.gen_driver);
 }
 
 MODULE_ALIAS("ide:*m-floppy*");
+MODULE_ALIAS("ide-floppy");
 module_init(idefloppy_init);
 module_exit(idefloppy_exit);
 MODULE_LICENSE("GPL");
diff --git a/drivers/ide/ide-floppy.h b/drivers/ide/ide-floppy.h
new file mode 100644
index 0000000..17cf865
--- /dev/null
+++ b/drivers/ide/ide-floppy.h
@@ -0,0 +1,62 @@
+#ifndef __IDE_FLOPPY_H
+#define __IDE_FLOPPY_H
+
+/*
+ * Most of our global data which we need to save even as we leave the driver
+ * due to an interrupt or a timer event is stored in a variable of type
+ * idefloppy_floppy_t, defined below.
+ */
+typedef struct ide_floppy_obj {
+	ide_drive_t	*drive;
+	ide_driver_t	*driver;
+	struct gendisk	*disk;
+	struct kref	kref;
+	unsigned int	openers;	/* protected by BKL for now */
+
+	/* Last failed packet command */
+	struct ide_atapi_pc *failed_pc;
+	/* used for blk_{fs,pc}_request() requests */
+	struct ide_atapi_pc queued_pc;
+
+	/* Last error information */
+	u8 sense_key, asc, ascq;
+
+	int progress_indication;
+
+	/* Device information */
+	/* Current format */
+	int blocks, block_size, bs_factor;
+	/* Last format capacity descriptor */
+	u8 cap_desc[8];
+	/* Copy of the flexible disk page */
+	u8 flexible_disk_page[32];
+} idefloppy_floppy_t;
+
+/*
+ * Pages of the SELECT SENSE / MODE SENSE packet commands.
+ * See SFF-8070i spec.
+ */
+#define	IDEFLOPPY_CAPABILITIES_PAGE	0x1b
+#define IDEFLOPPY_FLEXIBLE_DISK_PAGE	0x05
+
+/* IOCTLs used in low-level formatting. */
+#define	IDEFLOPPY_IOCTL_FORMAT_SUPPORTED	0x4600
+#define	IDEFLOPPY_IOCTL_FORMAT_GET_CAPACITY	0x4601
+#define	IDEFLOPPY_IOCTL_FORMAT_START		0x4602
+#define IDEFLOPPY_IOCTL_FORMAT_GET_PROGRESS	0x4603
+
+/* ide-floppy.c */
+void ide_floppy_create_mode_sense_cmd(struct ide_atapi_pc *, u8);
+void ide_floppy_create_read_capacity_cmd(struct ide_atapi_pc *);
+sector_t ide_floppy_capacity(ide_drive_t *);
+
+/* ide-floppy_ioctl.c */
+int ide_floppy_ioctl(struct inode *, struct file *, unsigned, unsigned long);
+
+#ifdef CONFIG_IDE_PROC_FS
+/* ide-floppy_proc.c */
+extern ide_proc_entry_t ide_floppy_proc[];
+extern const struct ide_proc_devset ide_floppy_settings[];
+#endif
+
+#endif /*__IDE_FLOPPY_H */
diff --git a/drivers/ide/ide-floppy_ioctl.c b/drivers/ide/ide-floppy_ioctl.c
new file mode 100644
index 0000000..a3a7a08
--- /dev/null
+++ b/drivers/ide/ide-floppy_ioctl.c
@@ -0,0 +1,293 @@
+/*
+ * ide-floppy IOCTLs handling.
+ */
+
+#include <linux/kernel.h>
+#include <linux/ide.h>
+#include <linux/cdrom.h>
+
+#include <asm/unaligned.h>
+
+#include <scsi/scsi_ioctl.h>
+
+#include "ide-floppy.h"
+
+/*
+ * Obtain the list of formattable capacities.
+ * Very similar to ide_floppy_get_capacity, except that we push the capacity
+ * descriptors to userland, instead of our own structures.
+ *
+ * Userland gives us the following structure:
+ *
+ * struct idefloppy_format_capacities {
+ *	int nformats;
+ *	struct {
+ *		int nblocks;
+ *		int blocksize;
+ *	} formats[];
+ * };
+ *
+ * userland initializes nformats to the number of allocated formats[] records.
+ * On exit we set nformats to the number of records we've actually initialized.
+ */
+
+static int ide_floppy_get_format_capacities(ide_drive_t *drive, int __user *arg)
+{
+	struct ide_floppy_obj *floppy = drive->driver_data;
+	struct ide_atapi_pc pc;
+	u8 header_len, desc_cnt;
+	int i, blocks, length, u_array_size, u_index;
+	int __user *argp;
+
+	if (get_user(u_array_size, arg))
+		return -EFAULT;
+
+	if (u_array_size <= 0)
+		return -EINVAL;
+
+	ide_floppy_create_read_capacity_cmd(&pc);
+	if (ide_queue_pc_tail(drive, floppy->disk, &pc)) {
+		printk(KERN_ERR "ide-floppy: Can't get floppy parameters\n");
+		return -EIO;
+	}
+
+	header_len = pc.buf[3];
+	desc_cnt = header_len / 8; /* capacity descriptor of 8 bytes */
+
+	u_index = 0;
+	argp = arg + 1;
+
+	/*
+	 * We always skip the first capacity descriptor.  That's the current
+	 * capacity.  We are interested in the remaining descriptors, the
+	 * formattable capacities.
+	 */
+	for (i = 1; i < desc_cnt; i++) {
+		unsigned int desc_start = 4 + i*8;
+
+		if (u_index >= u_array_size)
+			break;	/* User-supplied buffer too small */
+
+		blocks = be32_to_cpup((__be32 *)&pc.buf[desc_start]);
+		length = be16_to_cpup((__be16 *)&pc.buf[desc_start + 6]);
+
+		if (put_user(blocks, argp))
+			return -EFAULT;
+
+		++argp;
+
+		if (put_user(length, argp))
+			return -EFAULT;
+
+		++argp;
+
+		++u_index;
+	}
+
+	if (put_user(u_index, arg))
+		return -EFAULT;
+
+	return 0;
+}
+
+static void ide_floppy_create_format_unit_cmd(struct ide_atapi_pc *pc, int b,
+		int l, int flags)
+{
+	ide_init_pc(pc);
+	pc->c[0] = GPCMD_FORMAT_UNIT;
+	pc->c[1] = 0x17;
+
+	memset(pc->buf, 0, 12);
+	pc->buf[1] = 0xA2;
+	/* Default format list header, u8 1: FOV/DCRT/IMM bits set */
+
+	if (flags & 1)				/* Verify bit on... */
+		pc->buf[1] ^= 0x20;		/* ... turn off DCRT bit */
+	pc->buf[3] = 8;
+
+	put_unaligned(cpu_to_be32(b), (unsigned int *)(&pc->buf[4]));
+	put_unaligned(cpu_to_be32(l), (unsigned int *)(&pc->buf[8]));
+	pc->buf_size = 12;
+	pc->flags |= PC_FLAG_WRITING;
+}
+
+static int ide_floppy_get_sfrp_bit(ide_drive_t *drive)
+{
+	idefloppy_floppy_t *floppy = drive->driver_data;
+	struct ide_atapi_pc pc;
+
+	drive->atapi_flags &= ~IDE_AFLAG_SRFP;
+
+	ide_floppy_create_mode_sense_cmd(&pc, IDEFLOPPY_CAPABILITIES_PAGE);
+	pc.flags |= PC_FLAG_SUPPRESS_ERROR;
+
+	if (ide_queue_pc_tail(drive, floppy->disk, &pc))
+		return 1;
+
+	if (pc.buf[8 + 2] & 0x40)
+		drive->atapi_flags |= IDE_AFLAG_SRFP;
+
+	return 0;
+}
+
+static int ide_floppy_format_unit(ide_drive_t *drive, int __user *arg)
+{
+	idefloppy_floppy_t *floppy = drive->driver_data;
+	struct ide_atapi_pc pc;
+	int blocks, length, flags, err = 0;
+
+	if (floppy->openers > 1) {
+		/* Don't format if someone is using the disk */
+		drive->atapi_flags &= ~IDE_AFLAG_FORMAT_IN_PROGRESS;
+		return -EBUSY;
+	}
+
+	drive->atapi_flags |= IDE_AFLAG_FORMAT_IN_PROGRESS;
+
+	/*
+	 * Send ATAPI_FORMAT_UNIT to the drive.
+	 *
+	 * Userland gives us the following structure:
+	 *
+	 * struct idefloppy_format_command {
+	 *        int nblocks;
+	 *        int blocksize;
+	 *        int flags;
+	 *        } ;
+	 *
+	 * flags is a bitmask, currently, the only defined flag is:
+	 *
+	 *        0x01 - verify media after format.
+	 */
+	if (get_user(blocks, arg) ||
+			get_user(length, arg+1) ||
+			get_user(flags, arg+2)) {
+		err = -EFAULT;
+		goto out;
+	}
+
+	(void)ide_floppy_get_sfrp_bit(drive);
+	ide_floppy_create_format_unit_cmd(&pc, blocks, length, flags);
+
+	if (ide_queue_pc_tail(drive, floppy->disk, &pc))
+		err = -EIO;
+
+out:
+	if (err)
+		drive->atapi_flags &= ~IDE_AFLAG_FORMAT_IN_PROGRESS;
+	return err;
+}
+
+/*
+ * Get ATAPI_FORMAT_UNIT progress indication.
+ *
+ * Userland gives a pointer to an int.  The int is set to a progress
+ * indicator 0-65536, with 65536=100%.
+ *
+ * If the drive does not support format progress indication, we just check
+ * the dsc bit, and return either 0 or 65536.
+ */
+
+static int ide_floppy_get_format_progress(ide_drive_t *drive, int __user *arg)
+{
+	idefloppy_floppy_t *floppy = drive->driver_data;
+	struct ide_atapi_pc pc;
+	int progress_indication = 0x10000;
+
+	if (drive->atapi_flags & IDE_AFLAG_SRFP) {
+		ide_create_request_sense_cmd(drive, &pc);
+		if (ide_queue_pc_tail(drive, floppy->disk, &pc))
+			return -EIO;
+
+		if (floppy->sense_key == 2 &&
+		    floppy->asc == 4 &&
+		    floppy->ascq == 4)
+			progress_indication = floppy->progress_indication;
+
+		/* Else assume format_unit has finished, and we're at 0x10000 */
+	} else {
+		ide_hwif_t *hwif = drive->hwif;
+		unsigned long flags;
+		u8 stat;
+
+		local_irq_save(flags);
+		stat = hwif->tp_ops->read_status(hwif);
+		local_irq_restore(flags);
+
+		progress_indication = ((stat & ATA_DSC) == 0) ? 0 : 0x10000;
+	}
+
+	if (put_user(progress_indication, arg))
+		return -EFAULT;
+
+	return 0;
+}
+
+static int ide_floppy_lockdoor(ide_drive_t *drive, struct ide_atapi_pc *pc,
+			       unsigned long arg, unsigned int cmd)
+{
+	idefloppy_floppy_t *floppy = drive->driver_data;
+	struct gendisk *disk = floppy->disk;
+	int prevent = (arg && cmd != CDROMEJECT) ? 1 : 0;
+
+	if (floppy->openers > 1)
+		return -EBUSY;
+
+	ide_set_media_lock(drive, disk, prevent);
+
+	if (cmd == CDROMEJECT)
+		ide_do_start_stop(drive, disk, 2);
+
+	return 0;
+}
+
+static int ide_floppy_format_ioctl(ide_drive_t *drive, struct file *file,
+				   unsigned int cmd, void __user *argp)
+{
+	switch (cmd) {
+	case IDEFLOPPY_IOCTL_FORMAT_SUPPORTED:
+		return 0;
+	case IDEFLOPPY_IOCTL_FORMAT_GET_CAPACITY:
+		return ide_floppy_get_format_capacities(drive, argp);
+	case IDEFLOPPY_IOCTL_FORMAT_START:
+		if (!(file->f_mode & 2))
+			return -EPERM;
+		return ide_floppy_format_unit(drive, (int __user *)argp);
+	case IDEFLOPPY_IOCTL_FORMAT_GET_PROGRESS:
+		return ide_floppy_get_format_progress(drive, argp);
+	default:
+		return -ENOTTY;
+	}
+}
+
+int ide_floppy_ioctl(struct inode *inode, struct file *file,
+		    unsigned int cmd, unsigned long arg)
+{
+	struct block_device *bdev = inode->i_bdev;
+	struct ide_floppy_obj *floppy = ide_drv_g(bdev->bd_disk,
+						     ide_floppy_obj);
+	ide_drive_t *drive = floppy->drive;
+	struct ide_atapi_pc pc;
+	void __user *argp = (void __user *)arg;
+	int err;
+
+	if (cmd == CDROMEJECT || cmd == CDROM_LOCKDOOR)
+		return ide_floppy_lockdoor(drive, &pc, arg, cmd);
+
+	err = ide_floppy_format_ioctl(drive, file, cmd, argp);
+	if (err != -ENOTTY)
+		return err;
+
+	/*
+	 * skip SCSI_IOCTL_SEND_COMMAND (deprecated)
+	 * and CDROM_SEND_PACKET (legacy) ioctls
+	 */
+	if (cmd != CDROM_SEND_PACKET && cmd != SCSI_IOCTL_SEND_COMMAND)
+		err = scsi_cmd_ioctl(file, bdev->bd_disk->queue,
+					bdev->bd_disk, cmd, argp);
+
+	if (err == -ENOTTY)
+		err = generic_ide_ioctl(drive, file, bdev, cmd, arg);
+
+	return err;
+}
diff --git a/drivers/ide/ide-floppy_proc.c b/drivers/ide/ide-floppy_proc.c
new file mode 100644
index 0000000..76f0c6c
--- /dev/null
+++ b/drivers/ide/ide-floppy_proc.c
@@ -0,0 +1,33 @@
+#include <linux/kernel.h>
+#include <linux/ide.h>
+
+#include "ide-floppy.h"
+
+static int proc_idefloppy_read_capacity(char *page, char **start, off_t off,
+		int count, int *eof, void *data)
+{
+	ide_drive_t*drive = (ide_drive_t *)data;
+	int len;
+
+	len = sprintf(page, "%llu\n", (long long)ide_floppy_capacity(drive));
+	PROC_IDE_READ_RETURN(page, start, off, count, eof, len);
+}
+
+ide_proc_entry_t ide_floppy_proc[] = {
+	{ "capacity",	S_IFREG|S_IRUGO, proc_idefloppy_read_capacity,	NULL },
+	{ "geometry",	S_IFREG|S_IRUGO, proc_ide_read_geometry,	NULL },
+	{ NULL, 0, NULL, NULL }
+};
+
+ide_devset_rw_field(bios_cyl, bios_cyl);
+ide_devset_rw_field(bios_head, bios_head);
+ide_devset_rw_field(bios_sect, bios_sect);
+ide_devset_rw_field(ticks, pc_delay);
+
+const struct ide_proc_devset ide_floppy_settings[] = {
+	IDE_PROC_DEVSET(bios_cyl,  0, 1023),
+	IDE_PROC_DEVSET(bios_head, 0,  255),
+	IDE_PROC_DEVSET(bios_sect, 0,   63),
+	IDE_PROC_DEVSET(ticks,	   0,  255),
+	{ 0 },
+};
diff --git a/drivers/ide/ide-generic.c b/drivers/ide/ide-generic.c
index 8fe8b5b..81a5282 100644
--- a/drivers/ide/ide-generic.c
+++ b/drivers/ide/ide-generic.c
@@ -19,6 +19,7 @@
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/ide.h>
+#include <linux/pci_ids.h>
 
 /* FIXME: convert m32r to use ide_platform host driver */
 #ifdef CONFIG_M32R
@@ -27,7 +28,7 @@
 
 #define DRV_NAME	"ide_generic"
 
-static int probe_mask = 0x03;
+static int probe_mask;
 module_param(probe_mask, int, 0);
 MODULE_PARM_DESC(probe_mask, "probe mask for legacy ISA IDE ports");
 
@@ -100,27 +101,64 @@
 static const int legacy_irqs[]  = { 14, 15, 11, 10, 8, 12 };
 #endif
 
+static void ide_generic_check_pci_legacy_iobases(int *primary, int *secondary)
+{
+	struct pci_dev *p = NULL;
+	u16 val;
+
+	for_each_pci_dev(p) {
+
+		if (pci_resource_start(p, 0) == 0x1f0)
+			*primary = 1;
+		if (pci_resource_start(p, 2) == 0x170)
+			*secondary = 1;
+
+		/* Cyrix CS55{1,2}0 pre SFF MWDMA ATA on the bridge */
+		if (p->vendor == PCI_VENDOR_ID_CYRIX &&
+		    (p->device == PCI_DEVICE_ID_CYRIX_5510 ||
+		     p->device == PCI_DEVICE_ID_CYRIX_5520))
+			*primary = *secondary = 1;
+
+		/* Intel MPIIX - PIO ATA on non PCI side of bridge */
+		if (p->vendor == PCI_VENDOR_ID_INTEL &&
+		    p->device == PCI_DEVICE_ID_INTEL_82371MX) {
+
+			pci_read_config_word(p, 0x6C, &val);
+			if (val & 0x8000) {
+				/* ATA port enabled */
+				if (val & 0x4000)
+					*secondary = 1;
+				else
+					*primary = 1;
+			}
+		}
+	}
+}
+
 static int __init ide_generic_init(void)
 {
-	hw_regs_t hw[MAX_HWIFS], *hws[MAX_HWIFS];
-	struct ide_host *host;
+	hw_regs_t hw, *hws[] = { &hw, NULL, NULL, NULL };
 	unsigned long io_addr;
-	int i, rc;
+	int i, rc = 0, primary = 0, secondary = 0;
 
-#ifdef CONFIG_MIPS
-	if (!ide_probe_legacy())
-		return -ENODEV;
-#endif
-	printk(KERN_INFO DRV_NAME ": please use \"probe_mask=0x3f\" module "
-			 "parameter for probing all legacy ISA IDE ports\n");
+	ide_generic_check_pci_legacy_iobases(&primary, &secondary);
 
-	memset(hws, 0, sizeof(hw_regs_t *) * MAX_HWIFS);
+	if (!probe_mask) {
+		printk(KERN_INFO DRV_NAME ": please use \"probe_mask=0x3f\" "
+		     "module parameter for probing all legacy ISA IDE ports\n");
+
+		if (primary == 0)
+			probe_mask |= 0x1;
+
+		if (secondary == 0)
+			probe_mask |= 0x2;
+	} else
+		printk(KERN_INFO DRV_NAME ": enforcing probing of I/O ports "
+			"upon user request\n");
 
 	for (i = 0; i < ARRAY_SIZE(legacy_bases); i++) {
 		io_addr = legacy_bases[i];
 
-		hws[i] = NULL;
-
 		if ((probe_mask & (1 << i)) && io_addr) {
 			if (!request_region(io_addr, 8, DRV_NAME)) {
 				printk(KERN_ERR "%s: I/O resource 0x%lX-0x%lX "
@@ -137,45 +175,27 @@
 				continue;
 			}
 
-			memset(&hw[i], 0, sizeof(hw[i]));
-			ide_std_init_ports(&hw[i], io_addr, io_addr + 0x206);
+			memset(&hw, 0, sizeof(hw));
+			ide_std_init_ports(&hw, io_addr, io_addr + 0x206);
 #ifdef CONFIG_IA64
-			hw[i].irq = isa_irq_to_vector(legacy_irqs[i]);
+			hw.irq = isa_irq_to_vector(legacy_irqs[i]);
 #else
-			hw[i].irq = legacy_irqs[i];
+			hw.irq = legacy_irqs[i];
 #endif
-			hw[i].chipset = ide_generic;
+			hw.chipset = ide_generic;
 
-			hws[i] = &hw[i];
+			rc = ide_host_add(NULL, hws, NULL);
+			if (rc) {
+				release_region(io_addr + 0x206, 1);
+				release_region(io_addr, 8);
+			}
 		}
 	}
 
-	host = ide_host_alloc_all(NULL, hws);
-	if (host == NULL) {
-		rc = -ENOMEM;
-		goto err;
-	}
-
-	rc = ide_host_register(host, NULL, hws);
-	if (rc)
-		goto err_free;
-
 	if (ide_generic_sysfs_init())
 		printk(KERN_ERR DRV_NAME ": failed to create ide_generic "
 					 "class\n");
 
-	return 0;
-err_free:
-	ide_host_free(host);
-err:
-	for (i = 0; i < MAX_HWIFS; i++) {
-		if (hws[i] == NULL)
-			continue;
-
-		io_addr = hws[i]->io_ports.data_addr;
-		release_region(io_addr + 0x206, 1);
-		release_region(io_addr, 8);
-	}
 	return rc;
 }
 
diff --git a/drivers/ide/ide-io.c b/drivers/ide/ide-io.c
index a896a28..77c6eae 100644
--- a/drivers/ide/ide-io.c
+++ b/drivers/ide/ide-io.c
@@ -40,6 +40,7 @@
 #include <linux/pci.h>
 #include <linux/delay.h>
 #include <linux/ide.h>
+#include <linux/hdreg.h>
 #include <linux/completion.h>
 #include <linux/reboot.h>
 #include <linux/cdrom.h>
@@ -77,8 +78,9 @@
 	 * decide whether to reenable DMA -- 3 is a random magic for now,
 	 * if we DMA timeout more than 3 times, just stay in PIO
 	 */
-	if (drive->state == DMA_PIO_RETRY && drive->retry_pio <= 3) {
-		drive->state = 0;
+	if ((drive->dev_flags & IDE_DFLAG_DMA_PIO_RETRY) &&
+	    drive->retry_pio <= 3) {
+		drive->dev_flags &= ~IDE_DFLAG_DMA_PIO_RETRY;
 		ide_dma_on(drive);
 	}
 
@@ -130,21 +132,6 @@
 }
 EXPORT_SYMBOL(ide_end_request);
 
-/*
- * Power Management state machine. This one is rather trivial for now,
- * we should probably add more, like switching back to PIO on suspend
- * to help some BIOSes, re-do the door locking on resume, etc...
- */
-
-enum {
-	ide_pm_flush_cache	= ide_pm_state_start_suspend,
-	idedisk_pm_standby,
-
-	idedisk_pm_restore_pio	= ide_pm_state_start_resume,
-	idedisk_pm_idle,
-	ide_pm_restore_dma,
-};
-
 static void ide_complete_power_step(ide_drive_t *drive, struct request *rq, u8 stat, u8 error)
 {
 	struct request_pm_state *pm = rq->data;
@@ -153,20 +140,20 @@
 		return;
 
 	switch (pm->pm_step) {
-	case ide_pm_flush_cache:	/* Suspend step 1 (flush cache) complete */
+	case IDE_PM_FLUSH_CACHE:	/* Suspend step 1 (flush cache) */
 		if (pm->pm_state == PM_EVENT_FREEZE)
-			pm->pm_step = ide_pm_state_completed;
+			pm->pm_step = IDE_PM_COMPLETED;
 		else
-			pm->pm_step = idedisk_pm_standby;
+			pm->pm_step = IDE_PM_STANDBY;
 		break;
-	case idedisk_pm_standby:	/* Suspend step 2 (standby) complete */
-		pm->pm_step = ide_pm_state_completed;
+	case IDE_PM_STANDBY:		/* Suspend step 2 (standby) */
+		pm->pm_step = IDE_PM_COMPLETED;
 		break;
-	case idedisk_pm_restore_pio:	/* Resume step 1 complete */
-		pm->pm_step = idedisk_pm_idle;
+	case IDE_PM_RESTORE_PIO:	/* Resume step 1 (restore PIO) */
+		pm->pm_step = IDE_PM_IDLE;
 		break;
-	case idedisk_pm_idle:		/* Resume step 2 (idle) complete */
-		pm->pm_step = ide_pm_restore_dma;
+	case IDE_PM_IDLE:		/* Resume step 2 (idle)*/
+		pm->pm_step = IDE_PM_RESTORE_DMA;
 		break;
 	}
 }
@@ -179,40 +166,37 @@
 	memset(args, 0, sizeof(*args));
 
 	switch (pm->pm_step) {
-	case ide_pm_flush_cache:	/* Suspend step 1 (flush cache) */
+	case IDE_PM_FLUSH_CACHE:	/* Suspend step 1 (flush cache) */
 		if (drive->media != ide_disk)
 			break;
 		/* Not supported? Switch to next step now. */
-		if (!drive->wcache || !ide_id_has_flush_cache(drive->id)) {
+		if (ata_id_flush_enabled(drive->id) == 0 ||
+		    (drive->dev_flags & IDE_DFLAG_WCACHE) == 0) {
 			ide_complete_power_step(drive, rq, 0, 0);
 			return ide_stopped;
 		}
-		if (ide_id_has_flush_cache_ext(drive->id))
-			args->tf.command = WIN_FLUSH_CACHE_EXT;
+		if (ata_id_flush_ext_enabled(drive->id))
+			args->tf.command = ATA_CMD_FLUSH_EXT;
 		else
-			args->tf.command = WIN_FLUSH_CACHE;
+			args->tf.command = ATA_CMD_FLUSH;
 		goto out_do_tf;
-
-	case idedisk_pm_standby:	/* Suspend step 2 (standby) */
-		args->tf.command = WIN_STANDBYNOW1;
+	case IDE_PM_STANDBY:		/* Suspend step 2 (standby) */
+		args->tf.command = ATA_CMD_STANDBYNOW1;
 		goto out_do_tf;
-
-	case idedisk_pm_restore_pio:	/* Resume step 1 (restore PIO) */
+	case IDE_PM_RESTORE_PIO:	/* Resume step 1 (restore PIO) */
 		ide_set_max_pio(drive);
 		/*
-		 * skip idedisk_pm_idle for ATAPI devices
+		 * skip IDE_PM_IDLE for ATAPI devices
 		 */
 		if (drive->media != ide_disk)
-			pm->pm_step = ide_pm_restore_dma;
+			pm->pm_step = IDE_PM_RESTORE_DMA;
 		else
 			ide_complete_power_step(drive, rq, 0, 0);
 		return ide_stopped;
-
-	case idedisk_pm_idle:		/* Resume step 2 (idle) */
-		args->tf.command = WIN_IDLEIMMEDIATE;
+	case IDE_PM_IDLE:		/* Resume step 2 (idle) */
+		args->tf.command = ATA_CMD_IDLEIMMEDIATE;
 		goto out_do_tf;
-
-	case ide_pm_restore_dma:	/* Resume step 3 (restore DMA) */
+	case IDE_PM_RESTORE_DMA:	/* Resume step 3 (restore DMA) */
 		/*
 		 * Right now, all we do is call ide_set_dma(drive),
 		 * we could be smarter and check for current xfer_speed
@@ -221,12 +205,13 @@
 		if (drive->hwif->dma_ops == NULL)
 			break;
 		/*
-		 * TODO: respect ->using_dma setting
+		 * TODO: respect IDE_DFLAG_USING_DMA
 		 */
 		ide_set_dma(drive);
 		break;
 	}
-	pm->pm_step = ide_pm_state_completed;
+
+	pm->pm_step = IDE_PM_COMPLETED;
 	return ide_stopped;
 
 out_do_tf:
@@ -286,7 +271,7 @@
 	if (blk_pm_suspend_request(rq)) {
 		blk_stop_queue(drive->queue);
 	} else {
-		drive->blocked = 0;
+		drive->dev_flags &= ~IDE_DFLAG_BLOCKED;
 		blk_start_queue(drive->queue);
 	}
 	HWGROUP(drive)->rq = NULL;
@@ -322,7 +307,7 @@
 		ide_task_t *task = (ide_task_t *)rq->special;
 
 		if (rq->errors == 0)
-			rq->errors = !OK_STAT(stat, READY_STAT, BAD_STAT);
+			rq->errors = !OK_STAT(stat, ATA_DRDY, BAD_STAT);
 
 		if (task) {
 			struct ide_taskfile *tf = &task->tf;
@@ -342,7 +327,7 @@
 			drive->name, rq->pm->pm_step, stat, err);
 #endif
 		ide_complete_power_step(drive, rq, stat, err);
-		if (pm->pm_step == ide_pm_state_completed)
+		if (pm->pm_step == IDE_PM_COMPLETED)
 			ide_complete_pm_request(drive, rq);
 		return;
 	}
@@ -373,29 +358,30 @@
 {
 	ide_hwif_t *hwif = drive->hwif;
 
-	if (stat & BUSY_STAT || ((stat & WRERR_STAT) && !drive->nowerr)) {
+	if ((stat & ATA_BUSY) ||
+	    ((stat & ATA_DF) && (drive->dev_flags & IDE_DFLAG_NOWERR) == 0)) {
 		/* other bits are useless when BUSY */
 		rq->errors |= ERROR_RESET;
-	} else if (stat & ERR_STAT) {
+	} else if (stat & ATA_ERR) {
 		/* err has different meaning on cdrom and tape */
-		if (err == ABRT_ERR) {
-			if (drive->select.b.lba &&
-			    /* some newer drives don't support WIN_SPECIFY */
-			    hwif->tp_ops->read_status(hwif) == WIN_SPECIFY)
+		if (err == ATA_ABORTED) {
+			if ((drive->dev_flags & IDE_DFLAG_LBA) &&
+			    /* some newer drives don't support ATA_CMD_INIT_DEV_PARAMS */
+			    hwif->tp_ops->read_status(hwif) == ATA_CMD_INIT_DEV_PARAMS)
 				return ide_stopped;
 		} else if ((err & BAD_CRC) == BAD_CRC) {
 			/* UDMA crc error, just retry the operation */
 			drive->crc_count++;
-		} else if (err & (BBD_ERR | ECC_ERR)) {
+		} else if (err & (ATA_BBK | ATA_UNC)) {
 			/* retries won't help these */
 			rq->errors = ERROR_MAX;
-		} else if (err & TRK0_ERR) {
+		} else if (err & ATA_TRK0NF) {
 			/* help it find track zero */
 			rq->errors |= ERROR_RECAL;
 		}
 	}
 
-	if ((stat & DRQ_STAT) && rq_data_dir(rq) == READ &&
+	if ((stat & ATA_DRQ) && rq_data_dir(rq) == READ &&
 	    (hwif->host_flags & IDE_HFLAG_ERROR_STOPS_FIFO) == 0) {
 		int nsect = drive->mult_count ? drive->mult_count : 1;
 
@@ -407,7 +393,7 @@
 		return ide_stopped;
 	}
 
-	if (hwif->tp_ops->read_status(hwif) & (BUSY_STAT | DRQ_STAT))
+	if (hwif->tp_ops->read_status(hwif) & (ATA_BUSY | ATA_DRQ))
 		rq->errors |= ERROR_RESET;
 
 	if ((rq->errors & ERROR_RESET) == ERROR_RESET) {
@@ -427,16 +413,17 @@
 {
 	ide_hwif_t *hwif = drive->hwif;
 
-	if (stat & BUSY_STAT || ((stat & WRERR_STAT) && !drive->nowerr)) {
+	if ((stat & ATA_BUSY) ||
+	    ((stat & ATA_DF) && (drive->dev_flags & IDE_DFLAG_NOWERR) == 0)) {
 		/* other bits are useless when BUSY */
 		rq->errors |= ERROR_RESET;
 	} else {
 		/* add decoding error stuff */
 	}
 
-	if (hwif->tp_ops->read_status(hwif) & (BUSY_STAT | DRQ_STAT))
+	if (hwif->tp_ops->read_status(hwif) & (ATA_BUSY | ATA_DRQ))
 		/* force an abort */
-		hwif->tp_ops->exec_command(hwif, WIN_IDLEIMMEDIATE);
+		hwif->tp_ops->exec_command(hwif, ATA_CMD_IDLEIMMEDIATE);
 
 	if (rq->errors >= ERROR_MAX) {
 		ide_kill_rq(drive, rq);
@@ -508,20 +495,20 @@
 	tf->lbal    = drive->sect;
 	tf->lbam    = drive->cyl;
 	tf->lbah    = drive->cyl >> 8;
-	tf->device  = ((drive->head - 1) | drive->select.all) & ~ATA_LBA;
-	tf->command = WIN_SPECIFY;
+	tf->device  = (drive->head - 1) | drive->select;
+	tf->command = ATA_CMD_INIT_DEV_PARAMS;
 }
 
 static void ide_tf_set_restore_cmd(ide_drive_t *drive, struct ide_taskfile *tf)
 {
 	tf->nsect   = drive->sect;
-	tf->command = WIN_RESTORE;
+	tf->command = ATA_CMD_RESTORE;
 }
 
 static void ide_tf_set_setmult_cmd(ide_drive_t *drive, struct ide_taskfile *tf)
 {
 	tf->nsect   = drive->mult_req;
-	tf->command = WIN_SETMULT;
+	tf->command = ATA_CMD_SET_MULTI;
 }
 
 static ide_startstop_t ide_disk_special(ide_drive_t *drive)
@@ -540,8 +527,6 @@
 		ide_tf_set_restore_cmd(drive, &args.tf);
 	} else if (s->b.set_multmode) {
 		s->b.set_multmode = 0;
-		if (drive->mult_req > drive->id->max_multsect)
-			drive->mult_req = drive->id->max_multsect;
 		ide_tf_set_setmult_cmd(drive, &args.tf);
 	} else if (s->all) {
 		int special = s->all;
@@ -558,37 +543,14 @@
 	return ide_started;
 }
 
-/*
- * handle HDIO_SET_PIO_MODE ioctl abusers here, eventually it will go away
- */
-static int set_pio_mode_abuse(ide_hwif_t *hwif, u8 req_pio)
-{
-	switch (req_pio) {
-	case 202:
-	case 201:
-	case 200:
-	case 102:
-	case 101:
-	case 100:
-		return (hwif->host_flags & IDE_HFLAG_ABUSE_DMA_MODES) ? 1 : 0;
-	case 9:
-	case 8:
-		return (hwif->host_flags & IDE_HFLAG_ABUSE_PREFETCH) ? 1 : 0;
-	case 7:
-	case 6:
-		return (hwif->host_flags & IDE_HFLAG_ABUSE_FAST_DEVSEL) ? 1 : 0;
-	default:
-		return 0;
-	}
-}
-
 /**
  *	do_special		-	issue some special commands
  *	@drive: drive the command is for
  *
- *	do_special() is used to issue WIN_SPECIFY, WIN_RESTORE, and WIN_SETMULT
- *	commands to a drive.  It used to do much more, but has been scaled
- *	back.
+ *	do_special() is used to issue ATA_CMD_INIT_DEV_PARAMS,
+ *	ATA_CMD_RESTORE and ATA_CMD_SET_MULTI commands to a drive.
+ *
+ *	It used to do much more, but has been scaled back.
  */
 
 static ide_startstop_t do_special (ide_drive_t *drive)
@@ -598,45 +560,12 @@
 #ifdef DEBUG
 	printk("%s: do_special: 0x%02x\n", drive->name, s->all);
 #endif
-	if (s->b.set_tune) {
-		ide_hwif_t *hwif = drive->hwif;
-		const struct ide_port_ops *port_ops = hwif->port_ops;
-		u8 req_pio = drive->tune_req;
+	if (drive->media == ide_disk)
+		return ide_disk_special(drive);
 
-		s->b.set_tune = 0;
-
-		if (set_pio_mode_abuse(drive->hwif, req_pio)) {
-			/*
-			 * take ide_lock for drive->[no_]unmask/[no_]io_32bit
-			 */
-			if (req_pio == 8 || req_pio == 9) {
-				unsigned long flags;
-
-				spin_lock_irqsave(&ide_lock, flags);
-				port_ops->set_pio_mode(drive, req_pio);
-				spin_unlock_irqrestore(&ide_lock, flags);
-			} else
-				port_ops->set_pio_mode(drive, req_pio);
-		} else {
-			int keep_dma = drive->using_dma;
-
-			ide_set_pio(drive, req_pio);
-
-			if (hwif->host_flags & IDE_HFLAG_SET_PIO_MODE_KEEP_DMA) {
-				if (keep_dma)
-					ide_dma_on(drive);
-			}
-		}
-
-		return ide_stopped;
-	} else {
-		if (drive->media == ide_disk)
-			return ide_disk_special(drive);
-
-		s->all = 0;
-		drive->mult_req = 0;
-		return ide_stopped;
-	}
+	s->all = 0;
+	drive->mult_req = 0;
+	return ide_stopped;
 }
 
 void ide_map_sg(ide_drive_t *drive, struct request *rq)
@@ -716,9 +645,71 @@
  	return ide_stopped;
 }
 
+int ide_devset_execute(ide_drive_t *drive, const struct ide_devset *setting,
+		       int arg)
+{
+	struct request_queue *q = drive->queue;
+	struct request *rq;
+	int ret = 0;
+
+	if (!(setting->flags & DS_SYNC))
+		return setting->set(drive, arg);
+
+	rq = blk_get_request(q, READ, __GFP_WAIT);
+	rq->cmd_type = REQ_TYPE_SPECIAL;
+	rq->cmd_len = 5;
+	rq->cmd[0] = REQ_DEVSET_EXEC;
+	*(int *)&rq->cmd[1] = arg;
+	rq->special = setting->set;
+
+	if (blk_execute_rq(q, NULL, rq, 0))
+		ret = rq->errors;
+	blk_put_request(rq);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(ide_devset_execute);
+
 static ide_startstop_t ide_special_rq(ide_drive_t *drive, struct request *rq)
 {
-	switch (rq->cmd[0]) {
+	u8 cmd = rq->cmd[0];
+
+	if (cmd == REQ_PARK_HEADS || cmd == REQ_UNPARK_HEADS) {
+		ide_task_t task;
+		struct ide_taskfile *tf = &task.tf;
+
+		memset(&task, 0, sizeof(task));
+		if (cmd == REQ_PARK_HEADS) {
+			drive->sleep = *(unsigned long *)rq->special;
+			drive->dev_flags |= IDE_DFLAG_SLEEPING;
+			tf->command = ATA_CMD_IDLEIMMEDIATE;
+			tf->feature = 0x44;
+			tf->lbal = 0x4c;
+			tf->lbam = 0x4e;
+			tf->lbah = 0x55;
+			task.tf_flags |= IDE_TFLAG_CUSTOM_HANDLER;
+		} else		/* cmd == REQ_UNPARK_HEADS */
+			tf->command = ATA_CMD_CHK_POWER;
+
+		task.tf_flags |= IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
+		task.rq = rq;
+		drive->hwif->data_phase = task.data_phase = TASKFILE_NO_DATA;
+		return do_rw_taskfile(drive, &task);
+	}
+
+	switch (cmd) {
+	case REQ_DEVSET_EXEC:
+	{
+		int err, (*setfunc)(ide_drive_t *, int) = rq->special;
+
+		err = setfunc(drive, *(int *)&rq->cmd[1]);
+		if (err)
+			rq->errors = err;
+		else
+			err = 1;
+		ide_end_request(drive, err, 0);
+		return ide_stopped;
+	}
 	case REQ_DRIVE_RESET:
 		return ide_do_reset(drive);
 	default:
@@ -733,11 +724,11 @@
 	struct request_pm_state *pm = rq->data;
 
 	if (blk_pm_suspend_request(rq) &&
-	    pm->pm_step == ide_pm_state_start_suspend)
+	    pm->pm_step == IDE_PM_START_SUSPEND)
 		/* Mark drive blocked when starting the suspend sequence. */
-		drive->blocked = 1;
+		drive->dev_flags |= IDE_DFLAG_BLOCKED;
 	else if (blk_pm_resume_request(rq) &&
-		 pm->pm_step == ide_pm_state_start_resume) {
+		 pm->pm_step == IDE_PM_START_RESUME) {
 		/* 
 		 * The first thing we do on wakeup is to wait for BSY bit to
 		 * go away (with a looong timeout) as a drive on this hwif may
@@ -766,9 +757,7 @@
  *	start_request	-	start of I/O and command issuing for IDE
  *
  *	start_request() initiates handling of a new I/O request. It
- *	accepts commands and I/O (read/write) requests. It also does
- *	the final remapping for weird stuff like EZDrive. Once 
- *	device mapper can work sector level the EZDrive stuff can go away
+ *	accepts commands and I/O (read/write) requests.
  *
  *	FIXME: this function needs a rename
  */
@@ -776,7 +765,6 @@
 static ide_startstop_t start_request (ide_drive_t *drive, struct request *rq)
 {
 	ide_startstop_t startstop;
-	sector_t block;
 
 	BUG_ON(!blk_rq_started(rq));
 
@@ -791,21 +779,12 @@
 		goto kill_rq;
 	}
 
-	block    = rq->sector;
-	if (blk_fs_request(rq) &&
-	    (drive->media == ide_disk || drive->media == ide_floppy)) {
-		block += drive->sect0;
-	}
-	/* Yecch - this will shift the entire interval,
-	   possibly killing some innocent following sector */
-	if (block == 0 && drive->remap_0_to_1 == 1)
-		block = 1;  /* redirect MBR access to EZ-Drive partn table */
-
 	if (blk_pm_request(rq))
 		ide_check_pm_state(drive, rq);
 
 	SELECT_DRIVE(drive);
-	if (ide_wait_stat(&startstop, drive, drive->ready_stat, BUSY_STAT|DRQ_STAT, WAIT_READY)) {
+	if (ide_wait_stat(&startstop, drive, drive->ready_stat,
+			  ATA_BUSY | ATA_DRQ, WAIT_READY)) {
 		printk(KERN_ERR "%s: drive not ready for command\n", drive->name);
 		return startstop;
 	}
@@ -829,7 +808,7 @@
 #endif
 			startstop = ide_start_power_step(drive, rq);
 			if (startstop == ide_stopped &&
-			    pm->pm_step == ide_pm_state_completed)
+			    pm->pm_step == IDE_PM_COMPLETED)
 				ide_complete_pm_request(drive, rq);
 			return startstop;
 		} else if (!rq->rq_disk && blk_special_request(rq))
@@ -844,7 +823,8 @@
 			return ide_special_rq(drive, rq);
 
 		drv = *(ide_driver_t **)rq->rq_disk->private_data;
-		return drv->do_request(drive, rq, block);
+
+		return drv->do_request(drive, rq, rq->sector);
 	}
 	return do_special(drive);
 kill_rq:
@@ -866,7 +846,7 @@
 	if (timeout > WAIT_WORSTCASE)
 		timeout = WAIT_WORSTCASE;
 	drive->sleep = timeout + jiffies;
-	drive->sleeping = 1;
+	drive->dev_flags |= IDE_DFLAG_SLEEPING;
 }
 
 EXPORT_SYMBOL(ide_stall_queue);
@@ -906,18 +886,23 @@
 	}
 
 	do {
-		if ((!drive->sleeping || time_after_eq(jiffies, drive->sleep))
-		    && !elv_queue_empty(drive->queue)) {
-			if (!best
-			 || (drive->sleeping && (!best->sleeping || time_before(drive->sleep, best->sleep)))
-			 || (!best->sleeping && time_before(WAKEUP(drive), WAKEUP(best))))
-			{
+		u8 dev_s = !!(drive->dev_flags & IDE_DFLAG_SLEEPING);
+		u8 best_s = (best && !!(best->dev_flags & IDE_DFLAG_SLEEPING));
+
+		if ((dev_s == 0 || time_after_eq(jiffies, drive->sleep)) &&
+		    !elv_queue_empty(drive->queue)) {
+			if (best == NULL ||
+			    (dev_s && (best_s == 0 || time_before(drive->sleep, best->sleep))) ||
+			    (best_s == 0 && time_before(WAKEUP(drive), WAKEUP(best)))) {
 				if (!blk_queue_plugged(drive->queue))
 					best = drive;
 			}
 		}
 	} while ((drive = drive->next) != hwgroup->drive);
-	if (best && best->nice1 && !best->sleeping && best != hwgroup->drive && best->service_time > WAIT_MIN_SLEEP) {
+
+	if (best && (best->dev_flags & IDE_DFLAG_NICE1) &&
+	    (best->dev_flags & IDE_DFLAG_SLEEPING) == 0 &&
+	    best != hwgroup->drive && best->service_time > WAIT_MIN_SLEEP) {
 		long t = (signed long)(WAKEUP(best) - jiffies);
 		if (t >= WAIT_MIN_SLEEP) {
 		/*
@@ -926,7 +911,7 @@
 		 */
 			drive = best->next;
 			do {
-				if (!drive->sleeping
+				if ((drive->dev_flags & IDE_DFLAG_SLEEPING) == 0
 				 && time_before(jiffies - best->service_time, WAKEUP(drive))
 				 && time_before(WAKEUP(drive), jiffies + t))
 				{
@@ -997,7 +982,9 @@
 			hwgroup->rq = NULL;
 			drive = hwgroup->drive;
 			do {
-				if (drive->sleeping && (!sleeping || time_before(drive->sleep, sleep))) {
+				if ((drive->dev_flags & IDE_DFLAG_SLEEPING) &&
+				    (sleeping == 0 ||
+				     time_before(drive->sleep, sleep))) {
 					sleeping = 1;
 					sleep = drive->sleep;
 				}
@@ -1046,7 +1033,7 @@
 		}
 		hwgroup->hwif = hwif;
 		hwgroup->drive = drive;
-		drive->sleeping = 0;
+		drive->dev_flags &= ~(IDE_DFLAG_SLEEPING | IDE_DFLAG_PARKED);
 		drive->service_start = jiffies;
 
 		if (blk_queue_plugged(drive->queue)) {
@@ -1080,7 +1067,9 @@
 		 * We count how many times we loop here to make sure we service
 		 * all drives in the hwgroup without looping for ever
 		 */
-		if (drive->blocked && !blk_pm_request(rq) && !(rq->cmd_flags & REQ_PREEMPT)) {
+		if ((drive->dev_flags & IDE_DFLAG_BLOCKED) &&
+		    blk_pm_request(rq) == 0 &&
+		    (rq->cmd_flags & REQ_PREEMPT) == 0) {
 			drive = drive->next ? drive->next : hwgroup->drive;
 			if (loops++ < 4 && !blk_queue_plugged(drive->queue))
 				goto again;
@@ -1153,8 +1142,8 @@
 	 * a timeout -- we'll reenable after we finish this next request
 	 * (or rather the first chunk of it) in pio.
 	 */
+	drive->dev_flags |= IDE_DFLAG_DMA_PIO_RETRY;
 	drive->retry_pio++;
-	drive->state = DMA_PIO_RETRY;
 	ide_dma_off_quietly(drive);
 
 	/*
@@ -1325,7 +1314,7 @@
 		if (hwif->irq == irq) {
 			stat = hwif->tp_ops->read_status(hwif);
 
-			if (!OK_STAT(stat, READY_STAT, BAD_STAT)) {
+			if (!OK_STAT(stat, ATA_DRDY, BAD_STAT)) {
 				/* Try to not flood the console with msgs */
 				static unsigned long last_msgtime, count;
 				++count;
@@ -1451,23 +1440,16 @@
 	del_timer(&hwgroup->timer);
 	spin_unlock(&ide_lock);
 
-	/* Some controllers might set DMA INTR no matter DMA or PIO;
-	 * bmdma status might need to be cleared even for
-	 * PIO interrupts to prevent spurious/lost irq.
-	 */
-	if (hwif->ide_dma_clear_irq && !(drive->waiting_for_dma))
-		/* ide_dma_end() needs bmdma status for error checking.
-		 * So, skip clearing bmdma status here and leave it
-		 * to ide_dma_end() if this is dma interrupt.
-		 */
-		hwif->ide_dma_clear_irq(drive);
+	if (hwif->port_ops && hwif->port_ops->clear_irq)
+		hwif->port_ops->clear_irq(drive);
 
-	if (drive->unmask)
+	if (drive->dev_flags & IDE_DFLAG_UNMASK)
 		local_irq_enable_in_hardirq();
+
 	/* service this interrupt, may set handler for next interrupt */
 	startstop = handler(drive);
-	spin_lock_irq(&ide_lock);
 
+	spin_lock_irq(&ide_lock);
 	/*
 	 * Note that handler() may have set things up for another
 	 * interrupt to occur soon, but it cannot happen until
diff --git a/drivers/ide/ide-ioctls.c b/drivers/ide/ide-ioctls.c
new file mode 100644
index 0000000..a90945f
--- /dev/null
+++ b/drivers/ide/ide-ioctls.c
@@ -0,0 +1,299 @@
+/*
+ * IDE ioctls handling.
+ */
+
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+
+static const struct ide_ioctl_devset ide_ioctl_settings[] = {
+{ HDIO_GET_32BIT,	 HDIO_SET_32BIT,	&ide_devset_io_32bit  },
+{ HDIO_GET_KEEPSETTINGS, HDIO_SET_KEEPSETTINGS,	&ide_devset_keepsettings },
+{ HDIO_GET_UNMASKINTR,	 HDIO_SET_UNMASKINTR,	&ide_devset_unmaskirq },
+{ HDIO_GET_DMA,		 HDIO_SET_DMA,		&ide_devset_using_dma },
+{ -1,			 HDIO_SET_PIO_MODE,	&ide_devset_pio_mode  },
+{ 0 }
+};
+
+int ide_setting_ioctl(ide_drive_t *drive, struct block_device *bdev,
+		      unsigned int cmd, unsigned long arg,
+		      const struct ide_ioctl_devset *s)
+{
+	const struct ide_devset *ds;
+	unsigned long flags;
+	int err = -EOPNOTSUPP;
+
+	for (; (ds = s->setting); s++) {
+		if (ds->get && s->get_ioctl == cmd)
+			goto read_val;
+		else if (ds->set && s->set_ioctl == cmd)
+			goto set_val;
+	}
+
+	return err;
+
+read_val:
+	mutex_lock(&ide_setting_mtx);
+	spin_lock_irqsave(&ide_lock, flags);
+	err = ds->get(drive);
+	spin_unlock_irqrestore(&ide_lock, flags);
+	mutex_unlock(&ide_setting_mtx);
+	return err >= 0 ? put_user(err, (long __user *)arg) : err;
+
+set_val:
+	if (bdev != bdev->bd_contains)
+		err = -EINVAL;
+	else {
+		if (!capable(CAP_SYS_ADMIN))
+			err = -EACCES;
+		else {
+			mutex_lock(&ide_setting_mtx);
+			err = ide_devset_execute(drive, ds, arg);
+			mutex_unlock(&ide_setting_mtx);
+		}
+	}
+	return err;
+}
+EXPORT_SYMBOL_GPL(ide_setting_ioctl);
+
+static int ide_get_identity_ioctl(ide_drive_t *drive, unsigned int cmd,
+				  unsigned long arg)
+{
+	u16 *id = NULL;
+	int size = (cmd == HDIO_GET_IDENTITY) ? (ATA_ID_WORDS * 2) : 142;
+	int rc = 0;
+
+	if ((drive->dev_flags & IDE_DFLAG_ID_READ) == 0) {
+		rc = -ENOMSG;
+		goto out;
+	}
+
+	id = kmalloc(size, GFP_KERNEL);
+	if (id == NULL) {
+		rc = -ENOMEM;
+		goto out;
+	}
+
+	memcpy(id, drive->id, size);
+	ata_id_to_hd_driveid(id);
+
+	if (copy_to_user((void __user *)arg, id, size))
+		rc = -EFAULT;
+
+	kfree(id);
+out:
+	return rc;
+}
+
+static int ide_get_nice_ioctl(ide_drive_t *drive, unsigned long arg)
+{
+	return put_user((!!(drive->dev_flags & IDE_DFLAG_DSC_OVERLAP)
+			 << IDE_NICE_DSC_OVERLAP) |
+			(!!(drive->dev_flags & IDE_DFLAG_NICE1)
+			 << IDE_NICE_1), (long __user *)arg);
+}
+
+static int ide_set_nice_ioctl(ide_drive_t *drive, unsigned long arg)
+{
+	if (arg != (arg & ((1 << IDE_NICE_DSC_OVERLAP) | (1 << IDE_NICE_1))))
+		return -EPERM;
+
+	if (((arg >> IDE_NICE_DSC_OVERLAP) & 1) &&
+	    (drive->media == ide_disk || drive->media == ide_floppy ||
+	     (drive->dev_flags & IDE_DFLAG_SCSI)))
+		return -EPERM;
+
+	if ((arg >> IDE_NICE_DSC_OVERLAP) & 1)
+		drive->dev_flags |= IDE_DFLAG_DSC_OVERLAP;
+	else
+		drive->dev_flags &= ~IDE_DFLAG_DSC_OVERLAP;
+
+	if ((arg >> IDE_NICE_1) & 1)
+		drive->dev_flags |= IDE_DFLAG_NICE1;
+	else
+		drive->dev_flags &= ~IDE_DFLAG_NICE1;
+
+	return 0;
+}
+
+static int ide_cmd_ioctl(ide_drive_t *drive, unsigned cmd, unsigned long arg)
+{
+	u8 *buf = NULL;
+	int bufsize = 0, err = 0;
+	u8 args[4], xfer_rate = 0;
+	ide_task_t tfargs;
+	struct ide_taskfile *tf = &tfargs.tf;
+	u16 *id = drive->id;
+
+	if (NULL == (void *) arg) {
+		struct request *rq;
+
+		rq = blk_get_request(drive->queue, READ, __GFP_WAIT);
+		rq->cmd_type = REQ_TYPE_ATA_TASKFILE;
+		err = blk_execute_rq(drive->queue, NULL, rq, 0);
+		blk_put_request(rq);
+
+		return err;
+	}
+
+	if (copy_from_user(args, (void __user *)arg, 4))
+		return -EFAULT;
+
+	memset(&tfargs, 0, sizeof(ide_task_t));
+	tf->feature = args[2];
+	if (args[0] == ATA_CMD_SMART) {
+		tf->nsect = args[3];
+		tf->lbal  = args[1];
+		tf->lbam  = 0x4f;
+		tf->lbah  = 0xc2;
+		tfargs.tf_flags = IDE_TFLAG_OUT_TF | IDE_TFLAG_IN_NSECT;
+	} else {
+		tf->nsect = args[1];
+		tfargs.tf_flags = IDE_TFLAG_OUT_FEATURE |
+				  IDE_TFLAG_OUT_NSECT | IDE_TFLAG_IN_NSECT;
+	}
+	tf->command = args[0];
+	tfargs.data_phase = args[3] ? TASKFILE_IN : TASKFILE_NO_DATA;
+
+	if (args[3]) {
+		tfargs.tf_flags |= IDE_TFLAG_IO_16BIT;
+		bufsize = SECTOR_SIZE * args[3];
+		buf = kzalloc(bufsize, GFP_KERNEL);
+		if (buf == NULL)
+			return -ENOMEM;
+	}
+
+	if (tf->command == ATA_CMD_SET_FEATURES &&
+	    tf->feature == SETFEATURES_XFER &&
+	    tf->nsect >= XFER_SW_DMA_0 &&
+	    (id[ATA_ID_UDMA_MODES] ||
+	     id[ATA_ID_MWDMA_MODES] ||
+	     id[ATA_ID_SWDMA_MODES])) {
+		xfer_rate = args[1];
+		if (tf->nsect > XFER_UDMA_2 && !eighty_ninty_three(drive)) {
+			printk(KERN_WARNING "%s: UDMA speeds >UDMA33 cannot "
+					    "be set\n", drive->name);
+			goto abort;
+		}
+	}
+
+	err = ide_raw_taskfile(drive, &tfargs, buf, args[3]);
+
+	args[0] = tf->status;
+	args[1] = tf->error;
+	args[2] = tf->nsect;
+
+	if (!err && xfer_rate) {
+		/* active-retuning-calls future */
+		ide_set_xfer_rate(drive, xfer_rate);
+		ide_driveid_update(drive);
+	}
+abort:
+	if (copy_to_user((void __user *)arg, &args, 4))
+		err = -EFAULT;
+	if (buf) {
+		if (copy_to_user((void __user *)(arg + 4), buf, bufsize))
+			err = -EFAULT;
+		kfree(buf);
+	}
+	return err;
+}
+
+static int ide_task_ioctl(ide_drive_t *drive, unsigned cmd, unsigned long arg)
+{
+	void __user *p = (void __user *)arg;
+	int err = 0;
+	u8 args[7];
+	ide_task_t task;
+
+	if (copy_from_user(args, p, 7))
+		return -EFAULT;
+
+	memset(&task, 0, sizeof(task));
+	memcpy(&task.tf_array[7], &args[1], 6);
+	task.tf.command = args[0];
+	task.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
+
+	err = ide_no_data_taskfile(drive, &task);
+
+	args[0] = task.tf.command;
+	memcpy(&args[1], &task.tf_array[7], 6);
+
+	if (copy_to_user(p, args, 7))
+		err = -EFAULT;
+
+	return err;
+}
+
+static int generic_drive_reset(ide_drive_t *drive)
+{
+	struct request *rq;
+	int ret = 0;
+
+	rq = blk_get_request(drive->queue, READ, __GFP_WAIT);
+	rq->cmd_type = REQ_TYPE_SPECIAL;
+	rq->cmd_len = 1;
+	rq->cmd[0] = REQ_DRIVE_RESET;
+	rq->cmd_flags |= REQ_SOFTBARRIER;
+	if (blk_execute_rq(drive->queue, NULL, rq, 1))
+		ret = rq->errors;
+	blk_put_request(rq);
+	return ret;
+}
+
+int generic_ide_ioctl(ide_drive_t *drive, struct file *file,
+		      struct block_device *bdev,
+		      unsigned int cmd, unsigned long arg)
+{
+	int err;
+
+	err = ide_setting_ioctl(drive, bdev, cmd, arg, ide_ioctl_settings);
+	if (err != -EOPNOTSUPP)
+		return err;
+
+	switch (cmd) {
+	case HDIO_OBSOLETE_IDENTITY:
+	case HDIO_GET_IDENTITY:
+		if (bdev != bdev->bd_contains)
+			return -EINVAL;
+		return ide_get_identity_ioctl(drive, cmd, arg);
+	case HDIO_GET_NICE:
+		return ide_get_nice_ioctl(drive, arg);
+	case HDIO_SET_NICE:
+		if (!capable(CAP_SYS_ADMIN))
+			return -EACCES;
+		return ide_set_nice_ioctl(drive, arg);
+#ifdef CONFIG_IDE_TASK_IOCTL
+	case HDIO_DRIVE_TASKFILE:
+		if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
+			return -EACCES;
+		if (drive->media == ide_disk)
+			return ide_taskfile_ioctl(drive, cmd, arg);
+		return -ENOMSG;
+#endif
+	case HDIO_DRIVE_CMD:
+		if (!capable(CAP_SYS_RAWIO))
+			return -EACCES;
+		return ide_cmd_ioctl(drive, cmd, arg);
+	case HDIO_DRIVE_TASK:
+		if (!capable(CAP_SYS_RAWIO))
+			return -EACCES;
+		return ide_task_ioctl(drive, cmd, arg);
+	case HDIO_DRIVE_RESET:
+		if (!capable(CAP_SYS_ADMIN))
+			return -EACCES;
+		return generic_drive_reset(drive);
+	case HDIO_GET_BUSSTATE:
+		if (!capable(CAP_SYS_ADMIN))
+			return -EACCES;
+		if (put_user(BUSSTATE_ON, (long __user *)arg))
+			return -EFAULT;
+		return 0;
+	case HDIO_SET_BUSSTATE:
+		if (!capable(CAP_SYS_ADMIN))
+			return -EACCES;
+		return -EOPNOTSUPP;
+	default:
+		return -EINVAL;
+	}
+}
+EXPORT_SYMBOL(generic_ide_ioctl);
diff --git a/drivers/ide/ide-iops.c b/drivers/ide/ide-iops.c
index 2cbadff..b762deb 100644
--- a/drivers/ide/ide-iops.c
+++ b/drivers/ide/ide-iops.c
@@ -18,7 +18,6 @@
 #include <linux/slab.h>
 #include <linux/pci.h>
 #include <linux/delay.h>
-#include <linux/hdreg.h>
 #include <linux/ide.h>
 #include <linux/bitops.h>
 #include <linux/nmi.h>
@@ -182,7 +181,7 @@
 		tf_outb(tf->lbah, io_ports->lbah_addr);
 
 	if (task->tf_flags & IDE_TFLAG_OUT_DEVICE)
-		tf_outb((tf->device & HIHI) | drive->select.all,
+		tf_outb((tf->device & HIHI) | drive->select,
 			 io_ports->device_addr);
 }
 EXPORT_SYMBOL_GPL(ide_tf_load);
@@ -400,97 +399,14 @@
 	.output_data		= ide_output_data,
 };
 
-void ide_fix_driveid (struct hd_driveid *id)
+void ide_fix_driveid(u16 *id)
 {
 #ifndef __LITTLE_ENDIAN
 # ifdef __BIG_ENDIAN
 	int i;
-	u16 *stringcast;
 
-	id->config         = __le16_to_cpu(id->config);
-	id->cyls           = __le16_to_cpu(id->cyls);
-	id->reserved2      = __le16_to_cpu(id->reserved2);
-	id->heads          = __le16_to_cpu(id->heads);
-	id->track_bytes    = __le16_to_cpu(id->track_bytes);
-	id->sector_bytes   = __le16_to_cpu(id->sector_bytes);
-	id->sectors        = __le16_to_cpu(id->sectors);
-	id->vendor0        = __le16_to_cpu(id->vendor0);
-	id->vendor1        = __le16_to_cpu(id->vendor1);
-	id->vendor2        = __le16_to_cpu(id->vendor2);
-	stringcast = (u16 *)&id->serial_no[0];
-	for (i = 0; i < (20/2); i++)
-		stringcast[i] = __le16_to_cpu(stringcast[i]);
-	id->buf_type       = __le16_to_cpu(id->buf_type);
-	id->buf_size       = __le16_to_cpu(id->buf_size);
-	id->ecc_bytes      = __le16_to_cpu(id->ecc_bytes);
-	stringcast = (u16 *)&id->fw_rev[0];
-	for (i = 0; i < (8/2); i++)
-		stringcast[i] = __le16_to_cpu(stringcast[i]);
-	stringcast = (u16 *)&id->model[0];
-	for (i = 0; i < (40/2); i++)
-		stringcast[i] = __le16_to_cpu(stringcast[i]);
-	id->dword_io       = __le16_to_cpu(id->dword_io);
-	id->reserved50     = __le16_to_cpu(id->reserved50);
-	id->field_valid    = __le16_to_cpu(id->field_valid);
-	id->cur_cyls       = __le16_to_cpu(id->cur_cyls);
-	id->cur_heads      = __le16_to_cpu(id->cur_heads);
-	id->cur_sectors    = __le16_to_cpu(id->cur_sectors);
-	id->cur_capacity0  = __le16_to_cpu(id->cur_capacity0);
-	id->cur_capacity1  = __le16_to_cpu(id->cur_capacity1);
-	id->lba_capacity   = __le32_to_cpu(id->lba_capacity);
-	id->dma_1word      = __le16_to_cpu(id->dma_1word);
-	id->dma_mword      = __le16_to_cpu(id->dma_mword);
-	id->eide_pio_modes = __le16_to_cpu(id->eide_pio_modes);
-	id->eide_dma_min   = __le16_to_cpu(id->eide_dma_min);
-	id->eide_dma_time  = __le16_to_cpu(id->eide_dma_time);
-	id->eide_pio       = __le16_to_cpu(id->eide_pio);
-	id->eide_pio_iordy = __le16_to_cpu(id->eide_pio_iordy);
-	for (i = 0; i < 2; ++i)
-		id->words69_70[i] = __le16_to_cpu(id->words69_70[i]);
-	for (i = 0; i < 4; ++i)
-		id->words71_74[i] = __le16_to_cpu(id->words71_74[i]);
-	id->queue_depth    = __le16_to_cpu(id->queue_depth);
-	for (i = 0; i < 4; ++i)
-		id->words76_79[i] = __le16_to_cpu(id->words76_79[i]);
-	id->major_rev_num  = __le16_to_cpu(id->major_rev_num);
-	id->minor_rev_num  = __le16_to_cpu(id->minor_rev_num);
-	id->command_set_1  = __le16_to_cpu(id->command_set_1);
-	id->command_set_2  = __le16_to_cpu(id->command_set_2);
-	id->cfsse          = __le16_to_cpu(id->cfsse);
-	id->cfs_enable_1   = __le16_to_cpu(id->cfs_enable_1);
-	id->cfs_enable_2   = __le16_to_cpu(id->cfs_enable_2);
-	id->csf_default    = __le16_to_cpu(id->csf_default);
-	id->dma_ultra      = __le16_to_cpu(id->dma_ultra);
-	id->trseuc         = __le16_to_cpu(id->trseuc);
-	id->trsEuc         = __le16_to_cpu(id->trsEuc);
-	id->CurAPMvalues   = __le16_to_cpu(id->CurAPMvalues);
-	id->mprc           = __le16_to_cpu(id->mprc);
-	id->hw_config      = __le16_to_cpu(id->hw_config);
-	id->acoustic       = __le16_to_cpu(id->acoustic);
-	id->msrqs          = __le16_to_cpu(id->msrqs);
-	id->sxfert         = __le16_to_cpu(id->sxfert);
-	id->sal            = __le16_to_cpu(id->sal);
-	id->spg            = __le32_to_cpu(id->spg);
-	id->lba_capacity_2 = __le64_to_cpu(id->lba_capacity_2);
-	for (i = 0; i < 22; i++)
-		id->words104_125[i]   = __le16_to_cpu(id->words104_125[i]);
-	id->last_lun       = __le16_to_cpu(id->last_lun);
-	id->word127        = __le16_to_cpu(id->word127);
-	id->dlf            = __le16_to_cpu(id->dlf);
-	id->csfo           = __le16_to_cpu(id->csfo);
-	for (i = 0; i < 26; i++)
-		id->words130_155[i] = __le16_to_cpu(id->words130_155[i]);
-	id->word156        = __le16_to_cpu(id->word156);
-	for (i = 0; i < 3; i++)
-		id->words157_159[i] = __le16_to_cpu(id->words157_159[i]);
-	id->cfa_power      = __le16_to_cpu(id->cfa_power);
-	for (i = 0; i < 15; i++)
-		id->words161_175[i] = __le16_to_cpu(id->words161_175[i]);
-	for (i = 0; i < 30; i++)
-		id->words176_205[i] = __le16_to_cpu(id->words176_205[i]);
-	for (i = 0; i < 49; i++)
-		id->words206_254[i] = __le16_to_cpu(id->words206_254[i]);
-	id->integrity_word  = __le16_to_cpu(id->integrity_word);
+	for (i = 0; i < 256; i++)
+		id[i] = __le16_to_cpu(id[i]);
 # else
 #  error "Please fix <asm/byteorder.h>"
 # endif
@@ -501,19 +417,21 @@
  * ide_fixstring() cleans up and (optionally) byte-swaps a text string,
  * removing leading/trailing blanks and compressing internal blanks.
  * It is primarily used to tidy up the model name/number fields as
- * returned by the WIN_[P]IDENTIFY commands.
+ * returned by the ATA_CMD_ID_ATA[PI] commands.
  */
 
 void ide_fixstring (u8 *s, const int bytecount, const int byteswap)
 {
-	u8 *p = s, *end = &s[bytecount & ~1]; /* bytecount must be even */
+	u8 *p, *end = &s[bytecount & ~1]; /* bytecount must be even */
 
 	if (byteswap) {
 		/* convert from big-endian to host byte order */
-		for (p = end ; p != s;)
-			be16_to_cpus((u16 *)(p -= 2));
+		for (p = s ; p != end ; p += 2)
+			be16_to_cpus((u16 *) p);
 	}
+
 	/* strip leading blanks */
+	p = s;
 	while (s != end && *s == ' ')
 		++s;
 	/* compress internal blanks and strip trailing blanks */
@@ -556,7 +474,7 @@
 		/* Note: this may clear a pending IRQ!! */
 		stat = hwif->tp_ops->read_status(hwif);
 
-	if (stat & BUSY_STAT)
+	if (stat & ATA_BUSY)
 		/* drive busy:  definitely not interrupting */
 		return 0;
 
@@ -588,10 +506,10 @@
 	udelay(1);	/* spec allows drive 400ns to assert "BUSY" */
 	stat = tp_ops->read_status(hwif);
 
-	if (stat & BUSY_STAT) {
+	if (stat & ATA_BUSY) {
 		local_irq_set(flags);
 		timeout += jiffies;
-		while ((stat = tp_ops->read_status(hwif)) & BUSY_STAT) {
+		while ((stat = tp_ops->read_status(hwif)) & ATA_BUSY) {
 			if (time_after(jiffies, timeout)) {
 				/*
 				 * One last read after the timeout in case
@@ -599,7 +517,7 @@
 				 * progress during the timeout..
 				 */
 				stat = tp_ops->read_status(hwif);
-				if (!(stat & BUSY_STAT))
+				if ((stat & ATA_BUSY) == 0)
 					break;
 
 				local_irq_restore(flags);
@@ -660,18 +578,18 @@
 /**
  *	ide_in_drive_list	-	look for drive in black/white list
  *	@id: drive identifier
- *	@drive_table: list to inspect
+ *	@table: list to inspect
  *
  *	Look for a drive in the blacklist and the whitelist tables
  *	Returns 1 if the drive is found in the table.
  */
 
-int ide_in_drive_list(struct hd_driveid *id, const struct drive_list_entry *drive_table)
+int ide_in_drive_list(u16 *id, const struct drive_list_entry *table)
 {
-	for ( ; drive_table->id_model; drive_table++)
-		if ((!strcmp(drive_table->id_model, id->model)) &&
-		    (!drive_table->id_firmware ||
-		     strstr(id->fw_rev, drive_table->id_firmware)))
+	for ( ; table->id_model; table++)
+		if ((!strcmp(table->id_model, (char *)&id[ATA_ID_PROD])) &&
+		    (!table->id_firmware ||
+		     strstr((char *)&id[ATA_ID_FW_REV], table->id_firmware)))
 			return 1;
 	return 0;
 }
@@ -702,7 +620,7 @@
 u8 eighty_ninty_three (ide_drive_t *drive)
 {
 	ide_hwif_t *hwif = drive->hwif;
-	struct hd_driveid *id = drive->id;
+	u16 *id = drive->id;
 	int ivb = ide_in_drive_list(id, ivb_list);
 
 	if (hwif->cbl == ATA_CBL_PATA40_SHORT)
@@ -712,7 +630,7 @@
 		printk(KERN_DEBUG "%s: skipping word 93 validity check\n",
 				  drive->name);
 
-	if (ide_dev_is_sata(id) && !ivb)
+	if (ata_id_is_sata(id) && !ivb)
 		return 1;
 
 	if (hwif->cbl != ATA_CBL_PATA80 && !ivb)
@@ -724,11 +642,12 @@
 	 * - force bit13 (80c cable present) check also for !ivb devices
 	 *   (unless the slave device is pre-ATA3)
 	 */
-	if ((id->hw_config & 0x4000) || (ivb && (id->hw_config & 0x2000)))
+	if ((id[ATA_ID_HW_CONFIG] & 0x4000) ||
+	    (ivb && (id[ATA_ID_HW_CONFIG] & 0x2000)))
 		return 1;
 
 no_80w:
-	if (drive->udma33_warned == 1)
+	if (drive->dev_flags & IDE_DFLAG_UDMA33_WARNED)
 		return 0;
 
 	printk(KERN_WARNING "%s: %s side 80-wire cable detection failed, "
@@ -736,7 +655,7 @@
 			    drive->name,
 			    hwif->cbl == ATA_CBL_PATA80 ? "drive" : "host");
 
-	drive->udma33_warned = 1;
+	drive->dev_flags |= IDE_DFLAG_UDMA33_WARNED;
 
 	return 0;
 }
@@ -745,8 +664,8 @@
 {
 	ide_hwif_t *hwif = drive->hwif;
 	const struct ide_tp_ops *tp_ops = hwif->tp_ops;
-	struct hd_driveid *id;
-	unsigned long timeout, flags;
+	u16 *id;
+	unsigned long flags;
 	u8 stat;
 
 	/*
@@ -757,29 +676,24 @@
 	SELECT_MASK(drive, 1);
 	tp_ops->set_irq(hwif, 0);
 	msleep(50);
-	tp_ops->exec_command(hwif, WIN_IDENTIFY);
-	timeout = jiffies + WAIT_WORSTCASE;
-	do {
-		if (time_after(jiffies, timeout)) {
-			SELECT_MASK(drive, 0);
-			return 0;	/* drive timed-out */
-		}
+	tp_ops->exec_command(hwif, ATA_CMD_ID_ATA);
 
-		msleep(50);	/* give drive a breather */
-		stat = tp_ops->read_altstatus(hwif);
-	} while (stat & BUSY_STAT);
+	if (ide_busy_sleep(hwif, WAIT_WORSTCASE, 1)) {
+		SELECT_MASK(drive, 0);
+		return 0;
+	}
 
-	msleep(50);	/* wait for IRQ and DRQ_STAT */
+	msleep(50);	/* wait for IRQ and ATA_DRQ */
 	stat = tp_ops->read_status(hwif);
 
-	if (!OK_STAT(stat, DRQ_STAT, BAD_R_STAT)) {
+	if (!OK_STAT(stat, ATA_DRQ, BAD_R_STAT)) {
 		SELECT_MASK(drive, 0);
 		printk("%s: CHECK for good STATUS\n", drive->name);
 		return 0;
 	}
 	local_irq_save(flags);
 	SELECT_MASK(drive, 0);
-	id = kmalloc(SECTOR_WORDS*4, GFP_ATOMIC);
+	id = kmalloc(SECTOR_SIZE, GFP_ATOMIC);
 	if (!id) {
 		local_irq_restore(flags);
 		return 0;
@@ -789,16 +703,16 @@
 	local_irq_enable();
 	local_irq_restore(flags);
 	ide_fix_driveid(id);
-	if (id) {
-		drive->id->dma_ultra = id->dma_ultra;
-		drive->id->dma_mword = id->dma_mword;
-		drive->id->dma_1word = id->dma_1word;
-		/* anything more ? */
-		kfree(id);
 
-		if (drive->using_dma && ide_id_dma_bug(drive))
-			ide_dma_off(drive);
-	}
+	drive->id[ATA_ID_UDMA_MODES]  = id[ATA_ID_UDMA_MODES];
+	drive->id[ATA_ID_MWDMA_MODES] = id[ATA_ID_MWDMA_MODES];
+	drive->id[ATA_ID_SWDMA_MODES] = id[ATA_ID_SWDMA_MODES];
+	/* anything more ? */
+
+	kfree(id);
+
+	if ((drive->dev_flags & IDE_DFLAG_USING_DMA) && ide_id_dma_bug(drive))
+		ide_dma_off(drive);
 
 	return 1;
 }
@@ -807,6 +721,7 @@
 {
 	ide_hwif_t *hwif = drive->hwif;
 	const struct ide_tp_ops *tp_ops = hwif->tp_ops;
+	u16 *id = drive->id, i;
 	int error = 0;
 	u8 stat;
 	ide_task_t task;
@@ -817,7 +732,7 @@
 #endif
 
 	/* Skip setting PIO flow-control modes on pre-EIDE drives */
-	if ((speed & 0xf8) == XFER_PIO_0 && !(drive->id->capability & 0x08))
+	if ((speed & 0xf8) == XFER_PIO_0 && ata_id_has_iordy(drive->id) == 0)
 		goto skip;
 
 	/*
@@ -851,13 +766,13 @@
 
 	tp_ops->tf_load(drive, &task);
 
-	tp_ops->exec_command(hwif, WIN_SETFEATURES);
+	tp_ops->exec_command(hwif, ATA_CMD_SET_FEATURES);
 
 	if (drive->quirk_list == 2)
 		tp_ops->set_irq(hwif, 1);
 
 	error = __ide_wait_stat(drive, drive->ready_stat,
-				BUSY_STAT|DRQ_STAT|ERR_STAT,
+				ATA_BUSY | ATA_DRQ | ATA_ERR,
 				WAIT_CMD, &stat);
 
 	SELECT_MASK(drive, 0);
@@ -869,35 +784,29 @@
 		return error;
 	}
 
-	drive->id->dma_ultra &= ~0xFF00;
-	drive->id->dma_mword &= ~0x0F00;
-	drive->id->dma_1word &= ~0x0F00;
+	id[ATA_ID_UDMA_MODES]  &= ~0xFF00;
+	id[ATA_ID_MWDMA_MODES] &= ~0x0F00;
+	id[ATA_ID_SWDMA_MODES] &= ~0x0F00;
 
  skip:
 #ifdef CONFIG_BLK_DEV_IDEDMA
-	if (speed >= XFER_SW_DMA_0 && drive->using_dma)
+	if (speed >= XFER_SW_DMA_0 && (drive->dev_flags & IDE_DFLAG_USING_DMA))
 		hwif->dma_ops->dma_host_set(drive, 1);
 	else if (hwif->dma_ops)	/* check if host supports DMA */
 		ide_dma_off_quietly(drive);
 #endif
 
-	switch(speed) {
-		case XFER_UDMA_7:   drive->id->dma_ultra |= 0x8080; break;
-		case XFER_UDMA_6:   drive->id->dma_ultra |= 0x4040; break;
-		case XFER_UDMA_5:   drive->id->dma_ultra |= 0x2020; break;
-		case XFER_UDMA_4:   drive->id->dma_ultra |= 0x1010; break;
-		case XFER_UDMA_3:   drive->id->dma_ultra |= 0x0808; break;
-		case XFER_UDMA_2:   drive->id->dma_ultra |= 0x0404; break;
-		case XFER_UDMA_1:   drive->id->dma_ultra |= 0x0202; break;
-		case XFER_UDMA_0:   drive->id->dma_ultra |= 0x0101; break;
-		case XFER_MW_DMA_2: drive->id->dma_mword |= 0x0404; break;
-		case XFER_MW_DMA_1: drive->id->dma_mword |= 0x0202; break;
-		case XFER_MW_DMA_0: drive->id->dma_mword |= 0x0101; break;
-		case XFER_SW_DMA_2: drive->id->dma_1word |= 0x0404; break;
-		case XFER_SW_DMA_1: drive->id->dma_1word |= 0x0202; break;
-		case XFER_SW_DMA_0: drive->id->dma_1word |= 0x0101; break;
-		default: break;
+	if (speed >= XFER_UDMA_0) {
+		i = 1 << (speed - XFER_UDMA_0);
+		id[ATA_ID_UDMA_MODES] |= (i << 8 | i);
+	} else if (speed >= XFER_MW_DMA_0) {
+		i = 1 << (speed - XFER_MW_DMA_0);
+		id[ATA_ID_MWDMA_MODES] |= (i << 8 | i);
+	} else if (speed >= XFER_SW_DMA_0) {
+		i = 1 << (speed - XFER_SW_DMA_0);
+		id[ATA_ID_SWDMA_MODES] |= (i << 8 | i);
 	}
+
 	if (!drive->init_speed)
 		drive->init_speed = speed;
 	drive->current_speed = speed;
@@ -977,7 +886,7 @@
 	unsigned long flags;
 
 	spin_lock_irqsave(&ide_lock, flags);
-	hwif->tp_ops->exec_command(hwif, WIN_PACKETCMD);
+	hwif->tp_ops->exec_command(hwif, ATA_CMD_PACKET);
 	ndelay(400);
 	spin_unlock_irqrestore(&ide_lock, flags);
 }
@@ -1010,7 +919,7 @@
 	udelay (10);
 	stat = hwif->tp_ops->read_status(hwif);
 
-	if (OK_STAT(stat, 0, BUSY_STAT))
+	if (OK_STAT(stat, 0, ATA_BUSY))
 		printk("%s: ATAPI reset complete\n", drive->name);
 	else {
 		if (time_before(jiffies, hwgroup->poll_timeout)) {
@@ -1031,6 +940,25 @@
 	return ide_stopped;
 }
 
+static void ide_reset_report_error(ide_hwif_t *hwif, u8 err)
+{
+	static const char *err_master_vals[] =
+		{ NULL, "passed", "formatter device error",
+		  "sector buffer error", "ECC circuitry error",
+		  "controlling MPU error" };
+
+	u8 err_master = err & 0x7f;
+
+	printk(KERN_ERR "%s: reset: master: ", hwif->name);
+	if (err_master && err_master < 6)
+		printk(KERN_CONT "%s", err_master_vals[err_master]);
+	else
+		printk(KERN_CONT "error (0x%02x?)", err);
+	if (err & 0x80)
+		printk(KERN_CONT "; slave: failed");
+	printk(KERN_CONT "\n");
+}
+
 /*
  * reset_pollfunc() gets invoked to poll the interface for completion every 50ms
  * during an ide reset operation. If the drives have not yet responded,
@@ -1056,7 +984,7 @@
 
 	tmp = hwif->tp_ops->read_status(hwif);
 
-	if (!OK_STAT(tmp, 0, BUSY_STAT)) {
+	if (!OK_STAT(tmp, 0, ATA_BUSY)) {
 		if (time_before(jiffies, hwgroup->poll_timeout)) {
 			ide_set_handler(drive, &reset_pollfunc, HZ/20, NULL);
 			/* continue polling */
@@ -1066,31 +994,14 @@
 		drive->failures++;
 		err = -EIO;
 	} else  {
-		printk("%s: reset: ", hwif->name);
 		tmp = ide_read_error(drive);
 
 		if (tmp == 1) {
-			printk("success\n");
+			printk(KERN_INFO "%s: reset: success\n", hwif->name);
 			drive->failures = 0;
 		} else {
+			ide_reset_report_error(hwif, tmp);
 			drive->failures++;
-			printk("master: ");
-			switch (tmp & 0x7f) {
-				case 1: printk("passed");
-					break;
-				case 2: printk("formatter device error");
-					break;
-				case 3: printk("sector buffer error");
-					break;
-				case 4: printk("ECC circuitry error");
-					break;
-				case 5: printk("controlling MPU error");
-					break;
-				default:printk("error (0x%02x?)", tmp);
-			}
-			if (tmp & 0x80)
-				printk("; slave: failed");
-			printk("\n");
 			err = -EIO;
 		}
 	}
@@ -1102,14 +1013,19 @@
 
 static void ide_disk_pre_reset(ide_drive_t *drive)
 {
-	int legacy = (drive->id->cfs_enable_2 & 0x0400) ? 0 : 1;
+	int legacy = (drive->id[ATA_ID_CFS_ENABLE_2] & 0x0400) ? 0 : 1;
 
 	drive->special.all = 0;
 	drive->special.b.set_geometry = legacy;
 	drive->special.b.recalibrate  = legacy;
+
 	drive->mult_count = 0;
-	if (!drive->keep_settings && !drive->using_dma)
+	drive->dev_flags &= ~IDE_DFLAG_PARKED;
+
+	if ((drive->dev_flags & IDE_DFLAG_KEEP_SETTINGS) == 0 &&
+	    (drive->dev_flags & IDE_DFLAG_USING_DMA) == 0)
 		drive->mult_req = 0;
+
 	if (drive->mult_req != drive->mult_count)
 		drive->special.b.set_multmode = 1;
 }
@@ -1121,18 +1037,18 @@
 	if (drive->media == ide_disk)
 		ide_disk_pre_reset(drive);
 	else
-		drive->post_reset = 1;
+		drive->dev_flags |= IDE_DFLAG_POST_RESET;
 
-	if (drive->using_dma) {
+	if (drive->dev_flags & IDE_DFLAG_USING_DMA) {
 		if (drive->crc_count)
 			ide_check_dma_crc(drive);
 		else
 			ide_dma_off(drive);
 	}
 
-	if (!drive->keep_settings) {
-		if (!drive->using_dma) {
-			drive->unmask = 0;
+	if ((drive->dev_flags & IDE_DFLAG_KEEP_SETTINGS) == 0) {
+		if ((drive->dev_flags & IDE_DFLAG_USING_DMA) == 0) {
+			drive->dev_flags &= ~IDE_DFLAG_UNMASK;
 			drive->io_32bit = 0;
 		}
 		return;
@@ -1164,12 +1080,13 @@
 static ide_startstop_t do_reset1 (ide_drive_t *drive, int do_not_try_atapi)
 {
 	unsigned int unit;
-	unsigned long flags;
+	unsigned long flags, timeout;
 	ide_hwif_t *hwif;
 	ide_hwgroup_t *hwgroup;
 	struct ide_io_ports *io_ports;
 	const struct ide_tp_ops *tp_ops;
 	const struct ide_port_ops *port_ops;
+	DEFINE_WAIT(wait);
 
 	spin_lock_irqsave(&ide_lock, flags);
 	hwif = HWIF(drive);
@@ -1187,7 +1104,7 @@
 		pre_reset(drive);
 		SELECT_DRIVE(drive);
 		udelay (20);
-		tp_ops->exec_command(hwif, WIN_SRST);
+		tp_ops->exec_command(hwif, ATA_CMD_DEV_RESET);
 		ndelay(400);
 		hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
 		hwgroup->polling = 1;
@@ -1196,6 +1113,31 @@
 		return ide_started;
 	}
 
+	/* We must not disturb devices in the IDE_DFLAG_PARKED state. */
+	do {
+		unsigned long now;
+
+		prepare_to_wait(&ide_park_wq, &wait, TASK_UNINTERRUPTIBLE);
+		timeout = jiffies;
+		for (unit = 0; unit < MAX_DRIVES; unit++) {
+			ide_drive_t *tdrive = &hwif->drives[unit];
+
+			if (tdrive->dev_flags & IDE_DFLAG_PRESENT &&
+			    tdrive->dev_flags & IDE_DFLAG_PARKED &&
+			    time_after(tdrive->sleep, timeout))
+				timeout = tdrive->sleep;
+		}
+
+		now = jiffies;
+		if (time_before_eq(timeout, now))
+			break;
+
+		spin_unlock_irqrestore(&ide_lock, flags);
+		timeout = schedule_timeout_uninterruptible(timeout - now);
+		spin_lock_irqsave(&ide_lock, flags);
+	} while (timeout);
+	finish_wait(&ide_park_wq, &wait);
+
 	/*
 	 * First, reset any device state data we were maintaining
 	 * for any of the drives on this interface.
@@ -1270,7 +1212,7 @@
 		 */
 		mdelay(1);
 		stat = hwif->tp_ops->read_status(hwif);
-		if ((stat & BUSY_STAT) == 0)
+		if ((stat & ATA_BUSY) == 0)
 			return 0;
 		/*
 		 * Assume a value of 0xff means nothing is connected to
diff --git a/drivers/ide/ide-lib.c b/drivers/ide/ide-lib.c
index 97fefab..9fc4cfb 100644
--- a/drivers/ide/ide-lib.c
+++ b/drivers/ide/ide-lib.c
@@ -2,7 +2,6 @@
 #include <linux/string.h>
 #include <linux/kernel.h>
 #include <linux/interrupt.h>
-#include <linux/hdreg.h>
 #include <linux/ide.h>
 #include <linux/bitops.h>
 
@@ -90,29 +89,31 @@
 
 u8 ide_get_best_pio_mode (ide_drive_t *drive, u8 mode_wanted, u8 max_mode)
 {
-	int pio_mode;
-	struct hd_driveid* id = drive->id;
-	int overridden  = 0;
+	u16 *id = drive->id;
+	int pio_mode = -1, overridden = 0;
 
 	if (mode_wanted != 255)
 		return min_t(u8, mode_wanted, max_mode);
 
-	if ((drive->hwif->host_flags & IDE_HFLAG_PIO_NO_BLACKLIST) == 0 &&
-	    (pio_mode = ide_scan_pio_blacklist(id->model)) != -1) {
+	if ((drive->hwif->host_flags & IDE_HFLAG_PIO_NO_BLACKLIST) == 0)
+		pio_mode = ide_scan_pio_blacklist((char *)&id[ATA_ID_PROD]);
+
+	if (pio_mode != -1) {
 		printk(KERN_INFO "%s: is on PIO blacklist\n", drive->name);
 	} else {
-		pio_mode = id->tPIO;
+		pio_mode = id[ATA_ID_OLD_PIO_MODES] >> 8;
 		if (pio_mode > 2) {	/* 2 is maximum allowed tPIO value */
 			pio_mode = 2;
 			overridden = 1;
 		}
-		if (id->field_valid & 2) {	  /* drive implements ATA2? */
-			if (id->capability & 8) { /* IORDY supported? */
-				if (id->eide_pio_modes & 7) {
+
+		if (id[ATA_ID_FIELD_VALID] & 2) {	      /* ATA2? */
+			if (ata_id_has_iordy(id)) {
+				if (id[ATA_ID_PIO_MODES] & 7) {
 					overridden = 0;
-					if (id->eide_pio_modes & 4)
+					if (id[ATA_ID_PIO_MODES] & 4)
 						pio_mode = 5;
-					else if (id->eide_pio_modes & 2)
+					else if (id[ATA_ID_PIO_MODES] & 2)
 						pio_mode = 4;
 					else
 						pio_mode = 3;
@@ -316,7 +317,7 @@
 {
 	ide_task_t task;
 	struct ide_taskfile *tf = &task.tf;
-	int lba48 = (drive->addressing == 1) ? 1 : 0;
+	u8 lba48 = !!(drive->dev_flags & IDE_DFLAG_LBA48);
 
 	memset(&task, 0, sizeof(task));
 	if (lba48)
@@ -338,16 +339,16 @@
 static void ide_dump_ata_error(ide_drive_t *drive, u8 err)
 {
 	printk("{ ");
-	if (err & ABRT_ERR)	printk("DriveStatusError ");
-	if (err & ICRC_ERR)
-		printk((err & ABRT_ERR) ? "BadCRC " : "BadSector ");
-	if (err & ECC_ERR)	printk("UncorrectableError ");
-	if (err & ID_ERR)	printk("SectorIdNotFound ");
-	if (err & TRK0_ERR)	printk("TrackZeroNotFound ");
-	if (err & MARK_ERR)	printk("AddrMarkNotFound ");
+	if (err & ATA_ABORTED)	printk("DriveStatusError ");
+	if (err & ATA_ICRC)
+		printk((err & ATA_ABORTED) ? "BadCRC " : "BadSector ");
+	if (err & ATA_UNC)	printk("UncorrectableError ");
+	if (err & ATA_IDNF)	printk("SectorIdNotFound ");
+	if (err & ATA_TRK0NF)	printk("TrackZeroNotFound ");
+	if (err & ATA_AMNF)	printk("AddrMarkNotFound ");
 	printk("}");
-	if ((err & (BBD_ERR | ABRT_ERR)) == BBD_ERR ||
-	    (err & (ECC_ERR|ID_ERR|MARK_ERR))) {
+	if ((err & (ATA_BBK | ATA_ABORTED)) == ATA_BBK ||
+	    (err & (ATA_UNC | ATA_IDNF | ATA_AMNF))) {
 		ide_dump_sector(drive);
 		if (HWGROUP(drive) && HWGROUP(drive)->rq)
 			printk(", sector=%llu",
@@ -359,12 +360,12 @@
 static void ide_dump_atapi_error(ide_drive_t *drive, u8 err)
 {
 	printk("{ ");
-	if (err & ILI_ERR)	printk("IllegalLengthIndication ");
-	if (err & EOM_ERR)	printk("EndOfMedia ");
-	if (err & ABRT_ERR)	printk("AbortedCommand ");
-	if (err & MCR_ERR)	printk("MediaChangeRequested ");
-	if (err & LFS_ERR)	printk("LastFailedSense=0x%02x ",
-				       (err & LFS_ERR) >> 4);
+	if (err & ATAPI_ILI)	printk("IllegalLengthIndication ");
+	if (err & ATAPI_EOM)	printk("EndOfMedia ");
+	if (err & ATA_ABORTED)	printk("AbortedCommand ");
+	if (err & ATA_MCR)	printk("MediaChangeRequested ");
+	if (err & ATAPI_LFS)	printk("LastFailedSense=0x%02x ",
+				       (err & ATAPI_LFS) >> 4);
 	printk("}\n");
 }
 
@@ -386,19 +387,19 @@
 
 	local_irq_save(flags);
 	printk("%s: %s: status=0x%02x { ", drive->name, msg, stat);
-	if (stat & BUSY_STAT)
+	if (stat & ATA_BUSY)
 		printk("Busy ");
 	else {
-		if (stat & READY_STAT)	printk("DriveReady ");
-		if (stat & WRERR_STAT)	printk("DeviceFault ");
-		if (stat & SEEK_STAT)	printk("SeekComplete ");
-		if (stat & DRQ_STAT)	printk("DataRequest ");
-		if (stat & ECC_STAT)	printk("CorrectedError ");
-		if (stat & INDEX_STAT)	printk("Index ");
-		if (stat & ERR_STAT)	printk("Error ");
+		if (stat & ATA_DRDY)	printk("DriveReady ");
+		if (stat & ATA_DF)	printk("DeviceFault ");
+		if (stat & ATA_DSC)	printk("SeekComplete ");
+		if (stat & ATA_DRQ)	printk("DataRequest ");
+		if (stat & ATA_CORR)	printk("CorrectedError ");
+		if (stat & ATA_IDX)	printk("Index ");
+		if (stat & ATA_ERR)	printk("Error ");
 	}
 	printk("}\n");
-	if ((stat & (BUSY_STAT|ERR_STAT)) == ERR_STAT) {
+	if ((stat & (ATA_BUSY | ATA_ERR)) == ATA_ERR) {
 		err = ide_read_error(drive);
 		printk("%s: %s: error=0x%02x ", drive->name, msg, err);
 		if (drive->media == ide_disk)
diff --git a/drivers/ide/ide-park.c b/drivers/ide/ide-park.c
new file mode 100644
index 0000000..03b00e5
--- /dev/null
+++ b/drivers/ide/ide-park.c
@@ -0,0 +1,121 @@
+#include <linux/kernel.h>
+#include <linux/ide.h>
+#include <linux/jiffies.h>
+#include <linux/blkdev.h>
+
+DECLARE_WAIT_QUEUE_HEAD(ide_park_wq);
+
+static void issue_park_cmd(ide_drive_t *drive, unsigned long timeout)
+{
+	struct request_queue *q = drive->queue;
+	struct request *rq;
+	int rc;
+
+	timeout += jiffies;
+	spin_lock_irq(&ide_lock);
+	if (drive->dev_flags & IDE_DFLAG_PARKED) {
+		ide_hwgroup_t *hwgroup = drive->hwif->hwgroup;
+		int reset_timer;
+
+		reset_timer = time_before(timeout, drive->sleep);
+		drive->sleep = timeout;
+		wake_up_all(&ide_park_wq);
+		if (reset_timer && hwgroup->sleeping &&
+		    del_timer(&hwgroup->timer)) {
+			hwgroup->sleeping = 0;
+			hwgroup->busy = 0;
+			blk_start_queueing(q);
+		}
+		spin_unlock_irq(&ide_lock);
+		return;
+	}
+	spin_unlock_irq(&ide_lock);
+
+	rq = blk_get_request(q, READ, __GFP_WAIT);
+	rq->cmd[0] = REQ_PARK_HEADS;
+	rq->cmd_len = 1;
+	rq->cmd_type = REQ_TYPE_SPECIAL;
+	rq->special = &timeout;
+	rc = blk_execute_rq(q, NULL, rq, 1);
+	blk_put_request(rq);
+	if (rc)
+		goto out;
+
+	/*
+	 * Make sure that *some* command is sent to the drive after the
+	 * timeout has expired, so power management will be reenabled.
+	 */
+	rq = blk_get_request(q, READ, GFP_NOWAIT);
+	if (unlikely(!rq))
+		goto out;
+
+	rq->cmd[0] = REQ_UNPARK_HEADS;
+	rq->cmd_len = 1;
+	rq->cmd_type = REQ_TYPE_SPECIAL;
+	elv_add_request(q, rq, ELEVATOR_INSERT_FRONT, 1);
+
+out:
+	return;
+}
+
+ssize_t ide_park_show(struct device *dev, struct device_attribute *attr,
+		      char *buf)
+{
+	ide_drive_t *drive = to_ide_device(dev);
+	unsigned long now;
+	unsigned int msecs;
+
+	if (drive->dev_flags & IDE_DFLAG_NO_UNLOAD)
+		return -EOPNOTSUPP;
+
+	spin_lock_irq(&ide_lock);
+	now = jiffies;
+	if (drive->dev_flags & IDE_DFLAG_PARKED &&
+	    time_after(drive->sleep, now))
+		msecs = jiffies_to_msecs(drive->sleep - now);
+	else
+		msecs = 0;
+	spin_unlock_irq(&ide_lock);
+
+	return snprintf(buf, 20, "%u\n", msecs);
+}
+
+ssize_t ide_park_store(struct device *dev, struct device_attribute *attr,
+		       const char *buf, size_t len)
+{
+#define MAX_PARK_TIMEOUT 30000
+	ide_drive_t *drive = to_ide_device(dev);
+	long int input;
+	int rc;
+
+	rc = strict_strtol(buf, 10, &input);
+	if (rc || input < -2)
+		return -EINVAL;
+	if (input > MAX_PARK_TIMEOUT) {
+		input = MAX_PARK_TIMEOUT;
+		rc = -EOVERFLOW;
+	}
+
+	mutex_lock(&ide_setting_mtx);
+	if (input >= 0) {
+		if (drive->dev_flags & IDE_DFLAG_NO_UNLOAD)
+			rc = -EOPNOTSUPP;
+		else if (input || drive->dev_flags & IDE_DFLAG_PARKED)
+			issue_park_cmd(drive, msecs_to_jiffies(input));
+	} else {
+		if (drive->media == ide_disk)
+			switch (input) {
+			case -1:
+				drive->dev_flags &= ~IDE_DFLAG_NO_UNLOAD;
+				break;
+			case -2:
+				drive->dev_flags |= IDE_DFLAG_NO_UNLOAD;
+				break;
+			}
+		else
+			rc = -EOPNOTSUPP;
+	}
+	mutex_unlock(&ide_setting_mtx);
+
+	return rc ? rc : len;
+}
diff --git a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c
index 994e410..f27baa5 100644
--- a/drivers/ide/ide-probe.c
+++ b/drivers/ide/ide-probe.c
@@ -50,59 +50,54 @@
  
 static void generic_id(ide_drive_t *drive)
 {
-	drive->id->cyls = drive->cyl;
-	drive->id->heads = drive->head;
-	drive->id->sectors = drive->sect;
-	drive->id->cur_cyls = drive->cyl;
-	drive->id->cur_heads = drive->head;
-	drive->id->cur_sectors = drive->sect;
+	u16 *id = drive->id;
+
+	id[ATA_ID_CUR_CYLS]	= id[ATA_ID_CYLS]	= drive->cyl;
+	id[ATA_ID_CUR_HEADS]	= id[ATA_ID_HEADS]	= drive->head;
+	id[ATA_ID_CUR_SECTORS]	= id[ATA_ID_SECTORS]	= drive->sect;
 }
 
 static void ide_disk_init_chs(ide_drive_t *drive)
 {
-	struct hd_driveid *id = drive->id;
+	u16 *id = drive->id;
 
 	/* Extract geometry if we did not already have one for the drive */
 	if (!drive->cyl || !drive->head || !drive->sect) {
-		drive->cyl  = drive->bios_cyl  = id->cyls;
-		drive->head = drive->bios_head = id->heads;
-		drive->sect = drive->bios_sect = id->sectors;
+		drive->cyl  = drive->bios_cyl  = id[ATA_ID_CYLS];
+		drive->head = drive->bios_head = id[ATA_ID_HEADS];
+		drive->sect = drive->bios_sect = id[ATA_ID_SECTORS];
 	}
 
 	/* Handle logical geometry translation by the drive */
-	if ((id->field_valid & 1) && id->cur_cyls &&
-	    id->cur_heads && (id->cur_heads <= 16) && id->cur_sectors) {
-		drive->cyl  = id->cur_cyls;
-		drive->head = id->cur_heads;
-		drive->sect = id->cur_sectors;
+	if (ata_id_current_chs_valid(id)) {
+		drive->cyl  = id[ATA_ID_CUR_CYLS];
+		drive->head = id[ATA_ID_CUR_HEADS];
+		drive->sect = id[ATA_ID_CUR_SECTORS];
 	}
 
 	/* Use physical geometry if what we have still makes no sense */
-	if (drive->head > 16 && id->heads && id->heads <= 16) {
-		drive->cyl  = id->cyls;
-		drive->head = id->heads;
-		drive->sect = id->sectors;
+	if (drive->head > 16 && id[ATA_ID_HEADS] && id[ATA_ID_HEADS] <= 16) {
+		drive->cyl  = id[ATA_ID_CYLS];
+		drive->head = id[ATA_ID_HEADS];
+		drive->sect = id[ATA_ID_SECTORS];
 	}
 }
 
 static void ide_disk_init_mult_count(ide_drive_t *drive)
 {
-	struct hd_driveid *id = drive->id;
+	u16 *id = drive->id;
+	u8 max_multsect = id[ATA_ID_MAX_MULTSECT] & 0xff;
 
-	drive->mult_count = 0;
-	if (id->max_multsect) {
-#ifdef CONFIG_IDEDISK_MULTI_MODE
-		id->multsect = ((id->max_multsect/2) > 1) ? id->max_multsect : 0;
-		id->multsect_valid = id->multsect ? 1 : 0;
-		drive->mult_req = id->multsect_valid ? id->max_multsect : 0;
-		drive->special.b.set_multmode = drive->mult_req ? 1 : 0;
-#else	/* original, pre IDE-NFG, per request of AC */
-		drive->mult_req = 0;
-		if (drive->mult_req > id->max_multsect)
-			drive->mult_req = id->max_multsect;
-		if (drive->mult_req || ((id->multsect_valid & 1) && id->multsect))
+	if (max_multsect) {
+		if ((max_multsect / 2) > 1)
+			id[ATA_ID_MULTSECT] = max_multsect | 0x100;
+		else
+			id[ATA_ID_MULTSECT] &= ~0x1ff;
+
+		drive->mult_req = id[ATA_ID_MULTSECT] & 0xff;
+
+		if (drive->mult_req)
 			drive->special.b.set_multmode = 1;
-#endif
 	}
 }
 
@@ -119,14 +114,15 @@
 static inline void do_identify (ide_drive_t *drive, u8 cmd)
 {
 	ide_hwif_t *hwif = HWIF(drive);
-	int bswap = 1;
-	struct hd_driveid *id;
+	u16 *id = drive->id;
+	char *m = (char *)&id[ATA_ID_PROD];
+	int bswap = 1, is_cfa;
 
-	id = drive->id;
 	/* read 512 bytes of id info */
 	hwif->tp_ops->input_data(drive, NULL, id, SECTOR_SIZE);
 
-	drive->id_read = 1;
+	drive->dev_flags |= IDE_DFLAG_ID_READ;
+
 	local_irq_enable();
 #ifdef DEBUG
 	printk(KERN_INFO "%s: dumping identify data\n", drive->name);
@@ -135,59 +131,59 @@
 	ide_fix_driveid(id);
 
 	/*
-	 *  WIN_IDENTIFY returns little-endian info,
-	 *  WIN_PIDENTIFY *usually* returns little-endian info.
+	 *  ATA_CMD_ID_ATA returns little-endian info,
+	 *  ATA_CMD_ID_ATAPI *usually* returns little-endian info.
 	 */
-	if (cmd == WIN_PIDENTIFY) {
-		if ((id->model[0] == 'N' && id->model[1] == 'E') /* NEC */
-		 || (id->model[0] == 'F' && id->model[1] == 'X') /* Mitsumi */
-		 || (id->model[0] == 'P' && id->model[1] == 'i'))/* Pioneer */
+	if (cmd == ATA_CMD_ID_ATAPI) {
+		if ((m[0] == 'N' && m[1] == 'E') ||  /* NEC */
+		    (m[0] == 'F' && m[1] == 'X') ||  /* Mitsumi */
+		    (m[0] == 'P' && m[1] == 'i'))    /* Pioneer */
 			/* Vertos drives may still be weird */
-			bswap ^= 1;	
+			bswap ^= 1;
 	}
-	ide_fixstring(id->model,     sizeof(id->model),     bswap);
-	ide_fixstring(id->fw_rev,    sizeof(id->fw_rev),    bswap);
-	ide_fixstring(id->serial_no, sizeof(id->serial_no), bswap);
+
+	ide_fixstring(m, ATA_ID_PROD_LEN, bswap);
+	ide_fixstring((char *)&id[ATA_ID_FW_REV], ATA_ID_FW_REV_LEN, bswap);
+	ide_fixstring((char *)&id[ATA_ID_SERNO], ATA_ID_SERNO_LEN, bswap);
 
 	/* we depend on this a lot! */
-	id->model[sizeof(id->model)-1] = '\0';
+	m[ATA_ID_PROD_LEN - 1] = '\0';
 
-	if (strstr(id->model, "E X A B Y T E N E S T"))
+	if (strstr(m, "E X A B Y T E N E S T"))
 		goto err_misc;
 
-	printk(KERN_INFO "%s: %s, ", drive->name, id->model);
+	printk(KERN_INFO "%s: %s, ", drive->name, m);
 
-	drive->present = 1;
-	drive->dead = 0;
+	drive->dev_flags |= IDE_DFLAG_PRESENT;
+	drive->dev_flags &= ~IDE_DFLAG_DEAD;
 
 	/*
 	 * Check for an ATAPI device
 	 */
-	if (cmd == WIN_PIDENTIFY) {
-		u8 type = (id->config >> 8) & 0x1f;
+	if (cmd == ATA_CMD_ID_ATAPI) {
+		u8 type = (id[ATA_ID_CONFIG] >> 8) & 0x1f;
 
 		printk(KERN_CONT "ATAPI ");
 		switch (type) {
 			case ide_floppy:
-				if (!strstr(id->model, "CD-ROM")) {
-					if (!strstr(id->model, "oppy") &&
-					    !strstr(id->model, "poyp") &&
-					    !strstr(id->model, "ZIP"))
+				if (!strstr(m, "CD-ROM")) {
+					if (!strstr(m, "oppy") &&
+					    !strstr(m, "poyp") &&
+					    !strstr(m, "ZIP"))
 						printk(KERN_CONT "cdrom or floppy?, assuming ");
 					if (drive->media != ide_cdrom) {
 						printk(KERN_CONT "FLOPPY");
-						drive->removable = 1;
+						drive->dev_flags |= IDE_DFLAG_REMOVABLE;
 						break;
 					}
 				}
 				/* Early cdrom models used zero */
 				type = ide_cdrom;
 			case ide_cdrom:
-				drive->removable = 1;
+				drive->dev_flags |= IDE_DFLAG_REMOVABLE;
 #ifdef CONFIG_PPC
 				/* kludge for Apple PowerBook internal zip */
-				if (!strstr(id->model, "CD-ROM") &&
-				    strstr(id->model, "ZIP")) {
+				if (!strstr(m, "CD-ROM") && strstr(m, "ZIP")) {
 					printk(KERN_CONT "FLOPPY");
 					type = ide_floppy;
 					break;
@@ -200,7 +196,7 @@
 				break;
 			case ide_optical:
 				printk(KERN_CONT "OPTICAL");
-				drive->removable = 1;
+				drive->dev_flags |= IDE_DFLAG_REMOVABLE;
 				break;
 			default:
 				printk(KERN_CONT "UNKNOWN (type %d)", type);
@@ -210,6 +206,10 @@
 		drive->media = type;
 		/* an ATAPI device ignores DRDY */
 		drive->ready_stat = 0;
+		if (ata_id_cdb_intr(id))
+			drive->atapi_flags |= IDE_AFLAG_DRQ_INTERRUPT;
+		/* we don't do head unloading on ATAPI devices */
+		drive->dev_flags |= IDE_DFLAG_NO_UNLOAD;
 		return;
 	}
 
@@ -217,24 +217,24 @@
 	 * Not an ATAPI device: looks like a "regular" hard disk
 	 */
 
-	/*
-	 * 0x848a = CompactFlash device
-	 * These are *not* removable in Linux definition of the term
-	 */
+	is_cfa = ata_id_is_cfa(id);
 
-	if ((id->config != 0x848a) && (id->config & (1<<7)))
-		drive->removable = 1;
+	/* CF devices are *not* removable in Linux definition of the term */
+	if (is_cfa == 0 && (id[ATA_ID_CONFIG] & (1 << 7)))
+		drive->dev_flags |= IDE_DFLAG_REMOVABLE;
 
 	drive->media = ide_disk;
 
-	printk(KERN_CONT "%s DISK drive\n",
-		(id->config == 0x848a) ? "CFA" : "ATA");
+	if (!ata_id_has_unload(drive->id))
+		drive->dev_flags |= IDE_DFLAG_NO_UNLOAD;
+
+	printk(KERN_CONT "%s DISK drive\n", is_cfa ? "CFA" : "ATA");
 
 	return;
 
 err_misc:
 	kfree(id);
-	drive->present = 0;
+	drive->dev_flags &= ~IDE_DFLAG_PRESENT;
 	return;
 }
 
@@ -268,7 +268,7 @@
 	if (io_ports->ctl_addr) {
 		a = tp_ops->read_altstatus(hwif);
 		s = tp_ops->read_status(hwif);
-		if ((a ^ s) & ~INDEX_STAT)
+		if ((a ^ s) & ~ATA_IDX)
 			/* ancient Seagate drives, broken interfaces */
 			printk(KERN_INFO "%s: probing with STATUS(0x%02x) "
 					 "instead of ALTSTATUS(0x%02x)\n",
@@ -281,7 +281,7 @@
 	/* set features register for atapi
 	 * identify command to be sure of reply
 	 */
-	if (cmd == WIN_PIDENTIFY) {
+	if (cmd == ATA_CMD_ID_ATAPI) {
 		ide_task_t task;
 
 		memset(&task, 0, sizeof(task));
@@ -294,24 +294,16 @@
 	/* ask drive for ID */
 	tp_ops->exec_command(hwif, cmd);
 
-	timeout = ((cmd == WIN_IDENTIFY) ? WAIT_WORSTCASE : WAIT_PIDENTIFY) / 2;
-	timeout += jiffies;
-	do {
-		if (time_after(jiffies, timeout)) {
-			/* drive timed-out */
-			return 1;
-		}
-		/* give drive a breather */
-		msleep(50);
-		s = use_altstatus ? tp_ops->read_altstatus(hwif)
-				  : tp_ops->read_status(hwif);
-	} while (s & BUSY_STAT);
+	timeout = ((cmd == ATA_CMD_ID_ATA) ? WAIT_WORSTCASE : WAIT_PIDENTIFY) / 2;
 
-	/* wait for IRQ and DRQ_STAT */
+	if (ide_busy_sleep(hwif, timeout, use_altstatus))
+		return 1;
+
+	/* wait for IRQ and ATA_DRQ */
 	msleep(50);
 	s = tp_ops->read_status(hwif);
 
-	if (OK_STAT(s, DRQ_STAT, BAD_R_STAT)) {
+	if (OK_STAT(s, ATA_DRQ, BAD_R_STAT)) {
 		unsigned long flags;
 
 		/* local CPU only; some systems need this */
@@ -387,19 +379,21 @@
 	return retval;
 }
 
-static int ide_busy_sleep(ide_hwif_t *hwif)
+int ide_busy_sleep(ide_hwif_t *hwif, unsigned long timeout, int altstatus)
 {
-	unsigned long timeout = jiffies + WAIT_WORSTCASE;
 	u8 stat;
 
+	timeout += jiffies;
+
 	do {
-		msleep(50);
-		stat = hwif->tp_ops->read_status(hwif);
-		if ((stat & BUSY_STAT) == 0)
+		msleep(50);	/* give drive a breather */
+		stat = altstatus ? hwif->tp_ops->read_altstatus(hwif)
+				 : hwif->tp_ops->read_status(hwif);
+		if ((stat & ATA_BUSY) == 0)
 			return 0;
 	} while (time_before(jiffies, timeout));
 
-	return 1;
+	return 1;	/* drive timed-out */
 }
 
 static u8 ide_read_device(ide_drive_t *drive)
@@ -440,17 +434,16 @@
 	ide_hwif_t *hwif = HWIF(drive);
 	const struct ide_tp_ops *tp_ops = hwif->tp_ops;
 	int rc;
-	u8 stat;
+	u8 present = !!(drive->dev_flags & IDE_DFLAG_PRESENT), stat;
 
-	if (drive->present) {
-		/* avoid waiting for inappropriate probes */
-		if ((drive->media != ide_disk) && (cmd == WIN_IDENTIFY))
-			return 4;
-	}
+	/* avoid waiting for inappropriate probes */
+	if (present && drive->media != ide_disk && cmd == ATA_CMD_ID_ATA)
+		return 4;
+
 #ifdef DEBUG
 	printk(KERN_INFO "probing for %s: present=%d, media=%d, probetype=%s\n",
-		drive->name, drive->present, drive->media,
-		(cmd == WIN_IDENTIFY) ? "ATA" : "ATAPI");
+		drive->name, present, drive->media,
+		(cmd == ATA_CMD_ID_ATA) ? "ATA" : "ATAPI");
 #endif
 
 	/* needed for some systems
@@ -460,11 +453,11 @@
 	SELECT_DRIVE(drive);
 	msleep(50);
 
-	if (ide_read_device(drive) != drive->select.all && !drive->present) {
-		if (drive->select.b.unit != 0) {
+	if (ide_read_device(drive) != drive->select && present == 0) {
+		if (drive->dn & 1) {
 			/* exit with drive0 selected */
 			SELECT_DRIVE(&hwif->drives[0]);
-			/* allow BUSY_STAT to assert & clear */
+			/* allow ATA_BUSY to assert & clear */
 			msleep(50);
 		}
 		/* no i/f present: mmm.. this should be a 4 -ml */
@@ -473,8 +466,8 @@
 
 	stat = tp_ops->read_status(hwif);
 
-	if (OK_STAT(stat, READY_STAT, BUSY_STAT) ||
-	    drive->present || cmd == WIN_PIDENTIFY) {
+	if (OK_STAT(stat, ATA_DRDY, ATA_BUSY) ||
+	    present || cmd == ATA_CMD_ID_ATAPI) {
 		/* send cmd and wait */
 		if ((rc = try_to_identify(drive, cmd))) {
 			/* failed: try again */
@@ -483,17 +476,17 @@
 
 		stat = tp_ops->read_status(hwif);
 
-		if (stat == (BUSY_STAT | READY_STAT))
+		if (stat == (ATA_BUSY | ATA_DRDY))
 			return 4;
 
-		if (rc == 1 && cmd == WIN_PIDENTIFY) {
+		if (rc == 1 && cmd == ATA_CMD_ID_ATAPI) {
 			printk(KERN_ERR "%s: no response (status = 0x%02x), "
 					"resetting drive\n", drive->name, stat);
 			msleep(50);
 			SELECT_DRIVE(drive);
 			msleep(50);
-			tp_ops->exec_command(hwif, WIN_SRST);
-			(void)ide_busy_sleep(hwif);
+			tp_ops->exec_command(hwif, ATA_CMD_DEV_RESET);
+			(void)ide_busy_sleep(hwif, WAIT_WORSTCASE, 0);
 			rc = try_to_identify(drive, cmd);
 		}
 
@@ -507,7 +500,7 @@
 		/* not present or maybe ATAPI */
 		rc = 3;
 	}
-	if (drive->select.b.unit != 0) {
+	if (drive->dn & 1) {
 		/* exit with drive0 selected */
 		SELECT_DRIVE(&hwif->drives[0]);
 		msleep(50);
@@ -526,13 +519,14 @@
 	const struct ide_tp_ops *tp_ops = hwif->tp_ops;
 	u8 stat;
 
-	printk(KERN_INFO "%s: enabling %s -- ", hwif->name, drive->id->model);
+	printk(KERN_INFO "%s: enabling %s -- ",
+		hwif->name, (char *)&drive->id[ATA_ID_PROD]);
 
 	SELECT_DRIVE(drive);
 	msleep(50);
-	tp_ops->exec_command(hwif, EXABYTE_ENABLE_NEST);
+	tp_ops->exec_command(hwif, ATA_EXABYTE_ENABLE_NEST);
 
-	if (ide_busy_sleep(hwif)) {
+	if (ide_busy_sleep(hwif, WAIT_WORSTCASE, 0)) {
 		printk(KERN_CONT "failed (timeout)\n");
 		return;
 	}
@@ -545,12 +539,6 @@
 		printk(KERN_CONT "failed (status = 0x%02x)\n", stat);
 	else
 		printk(KERN_CONT "success\n");
-
-	/* if !(success||timed-out) */
-	if (do_probe(drive, WIN_IDENTIFY) >= 2) {
-		/* look for ATAPI device */
-		(void) do_probe(drive, WIN_PIDENTIFY);
-	}
 }
 
 /**
@@ -561,12 +549,14 @@
  *	and presents things to the user as needed.
  *
  *	Returns:	0  no device was found
- *			1  device was found (note: drive->present might
- *			   still be 0)
+ *			1  device was found
+ *			   (note: IDE_DFLAG_PRESENT might still be not set)
  */
  
 static inline u8 probe_for_drive (ide_drive_t *drive)
 {
+	char *m;
+
 	/*
 	 *	In order to keep things simple we have an id
 	 *	block for all drives at all times. If the device
@@ -576,31 +566,36 @@
 	 *	Also note that 0 everywhere means "can't do X"
 	 */
  
-	drive->id = kzalloc(SECTOR_WORDS *4, GFP_KERNEL);
-	drive->id_read = 0;
-	if(drive->id == NULL)
-	{
+	drive->dev_flags &= ~IDE_DFLAG_ID_READ;
+
+	drive->id = kzalloc(SECTOR_SIZE, GFP_KERNEL);
+	if (drive->id == NULL) {
 		printk(KERN_ERR "ide: out of memory for id data.\n");
 		return 0;
 	}
-	strcpy(drive->id->model, "UNKNOWN");
-	
+
+	m = (char *)&drive->id[ATA_ID_PROD];
+	strcpy(m, "UNKNOWN");
+
 	/* skip probing? */
-	if (!drive->noprobe)
-	{
+	if ((drive->dev_flags & IDE_DFLAG_NOPROBE) == 0) {
+retry:
 		/* if !(success||timed-out) */
-		if (do_probe(drive, WIN_IDENTIFY) >= 2) {
+		if (do_probe(drive, ATA_CMD_ID_ATA) >= 2)
 			/* look for ATAPI device */
-			(void) do_probe(drive, WIN_PIDENTIFY);
-		}
-		if (!drive->present)
+			(void)do_probe(drive, ATA_CMD_ID_ATAPI);
+
+		if ((drive->dev_flags & IDE_DFLAG_PRESENT) == 0)
 			/* drive not found */
 			return 0;
-		if (strstr(drive->id->model, "E X A B Y T E N E S T"))
+
+		if (strstr(m, "E X A B Y T E N E S T")) {
 			enable_nest(drive);
-	
+			goto retry;
+		}
+
 		/* identification failed? */
-		if (!drive->id_read) {
+		if ((drive->dev_flags & IDE_DFLAG_ID_READ) == 0) {
 			if (drive->media == ide_disk) {
 				printk(KERN_INFO "%s: non-IDE drive, CHS=%d/%d/%d\n",
 					drive->name, drive->cyl,
@@ -610,15 +605,17 @@
 			} else {
 				/* nuke it */
 				printk(KERN_WARNING "%s: Unknown device on bus refused identification. Ignoring.\n", drive->name);
-				drive->present = 0;
+				drive->dev_flags &= ~IDE_DFLAG_PRESENT;
 			}
 		}
 		/* drive was found */
 	}
-	if(!drive->present)
+
+	if ((drive->dev_flags & IDE_DFLAG_PRESENT) == 0)
 		return 0;
+
 	/* The drive wasn't being helpful. Add generic info only */
-	if (drive->id_read == 0) {
+	if ((drive->dev_flags & IDE_DFLAG_ID_READ) == 0) {
 		generic_id(drive);
 		return 1;
 	}
@@ -628,7 +625,7 @@
 		ide_disk_init_mult_count(drive);
 	}
 
-	return drive->present;
+	return !!(drive->dev_flags & IDE_DFLAG_PRESENT);
 }
 
 static void hwif_release_dev(struct device *dev)
@@ -719,7 +716,8 @@
 		ide_drive_t *drive = &hwif->drives[unit];
 
 		/* Ignore disks that we will not probe for later. */
-		if (!drive->noprobe || drive->present) {
+		if ((drive->dev_flags & IDE_DFLAG_NOPROBE) == 0 ||
+		    (drive->dev_flags & IDE_DFLAG_PRESENT)) {
 			SELECT_DRIVE(drive);
 			hwif->tp_ops->set_irq(hwif, 1);
 			mdelay(2);
@@ -740,36 +738,38 @@
 
 /**
  *	ide_undecoded_slave	-	look for bad CF adapters
- *	@drive1: drive
+ *	@dev1: slave device
  *
  *	Analyse the drives on the interface and attempt to decide if we
  *	have the same drive viewed twice. This occurs with crap CF adapters
  *	and PCMCIA sometimes.
  */
 
-void ide_undecoded_slave(ide_drive_t *drive1)
+void ide_undecoded_slave(ide_drive_t *dev1)
 {
-	ide_drive_t *drive0 = &drive1->hwif->drives[0];
+	ide_drive_t *dev0 = &dev1->hwif->drives[0];
 
-	if ((drive1->dn & 1) == 0 || drive0->present == 0)
+	if ((dev1->dn & 1) == 0 || (dev0->dev_flags & IDE_DFLAG_PRESENT) == 0)
 		return;
 
 	/* If the models don't match they are not the same product */
-	if (strcmp(drive0->id->model, drive1->id->model))
+	if (strcmp((char *)&dev0->id[ATA_ID_PROD],
+		   (char *)&dev1->id[ATA_ID_PROD]))
 		return;
 
 	/* Serial numbers do not match */
-	if (strncmp(drive0->id->serial_no, drive1->id->serial_no, 20))
+	if (strncmp((char *)&dev0->id[ATA_ID_SERNO],
+		    (char *)&dev1->id[ATA_ID_SERNO], ATA_ID_SERNO_LEN))
 		return;
 
 	/* No serial number, thankfully very rare for CF */
-	if (drive0->id->serial_no[0] == 0)
+	if (*(char *)&dev0->id[ATA_ID_SERNO] == 0)
 		return;
 
 	/* Appears to be an IDE flash adapter with decode bugs */
 	printk(KERN_WARNING "ide-probe: ignoring undecoded slave\n");
 
-	drive1->present = 0;
+	dev1->dev_flags &= ~IDE_DFLAG_PRESENT;
 }
 
 EXPORT_SYMBOL_GPL(ide_undecoded_slave);
@@ -782,7 +782,8 @@
 
 	BUG_ON(hwif->present);
 
-	if (hwif->drives[0].noprobe && hwif->drives[1].noprobe)
+	if ((hwif->drives[0].dev_flags & IDE_DFLAG_NOPROBE) &&
+	    (hwif->drives[1].dev_flags & IDE_DFLAG_NOPROBE))
 		return -EACCES;
 
 	/*
@@ -804,9 +805,9 @@
 	 */
 	for (unit = 0; unit < MAX_DRIVES; ++unit) {
 		ide_drive_t *drive = &hwif->drives[unit];
-		drive->dn = (hwif->channel ? 2 : 0) + unit;
+
 		(void) probe_for_drive(drive);
-		if (drive->present)
+		if (drive->dev_flags & IDE_DFLAG_PRESENT)
 			rc = 0;
 	}
 
@@ -830,17 +831,19 @@
 	for (unit = 0; unit < MAX_DRIVES; unit++) {
 		ide_drive_t *drive = &hwif->drives[unit];
 
-		if (drive->present && port_ops && port_ops->quirkproc)
-			port_ops->quirkproc(drive);
+		if (drive->dev_flags & IDE_DFLAG_PRESENT) {
+			if (port_ops && port_ops->quirkproc)
+				port_ops->quirkproc(drive);
+		}
 	}
 
 	for (unit = 0; unit < MAX_DRIVES; ++unit) {
 		ide_drive_t *drive = &hwif->drives[unit];
 
-		if (drive->present) {
+		if (drive->dev_flags & IDE_DFLAG_PRESENT) {
 			ide_set_max_pio(drive);
 
-			drive->nice1 = 1;
+			drive->dev_flags |= IDE_DFLAG_NICE1;
 
 			if (hwif->dma_ops)
 				ide_set_dma(drive);
@@ -850,14 +853,14 @@
 	for (unit = 0; unit < MAX_DRIVES; ++unit) {
 		ide_drive_t *drive = &hwif->drives[unit];
 
-		if (hwif->host_flags & IDE_HFLAG_NO_IO_32BIT)
-			drive->no_io_32bit = 1;
+		if ((hwif->host_flags & IDE_HFLAG_NO_IO_32BIT) ||
+		    drive->id[ATA_ID_DWORD_IO])
+			drive->dev_flags |= IDE_DFLAG_NO_IO_32BIT;
 		else
-			drive->no_io_32bit = drive->id->dword_io ? 1 : 0;
+			drive->dev_flags &= ~IDE_DFLAG_NO_IO_32BIT;
 	}
 }
 
-#if MAX_HWIFS > 1
 /*
  * save_match() is used to simplify logic in init_irq() below.
  *
@@ -882,7 +885,6 @@
 	if (!m || m->irq != hwif->irq) /* don't undo a prior perfect match */
 		*match = new;
 }
-#endif /* MAX_HWIFS > 1 */
 
 /*
  * init request queue
@@ -961,26 +963,33 @@
  * - allocate the block device queue
  * - link drive into the hwgroup
  */
-static void ide_port_setup_devices(ide_hwif_t *hwif)
+static int ide_port_setup_devices(ide_hwif_t *hwif)
 {
-	int i;
+	int i, j = 0;
 
 	mutex_lock(&ide_cfg_mtx);
 	for (i = 0; i < MAX_DRIVES; i++) {
 		ide_drive_t *drive = &hwif->drives[i];
 
-		if (!drive->present)
+		if ((drive->dev_flags & IDE_DFLAG_PRESENT) == 0)
 			continue;
 
 		if (ide_init_queue(drive)) {
 			printk(KERN_ERR "ide: failed to init %s\n",
 					drive->name);
+			kfree(drive->id);
+			drive->id = NULL;
+			drive->dev_flags &= ~IDE_DFLAG_PRESENT;
 			continue;
 		}
 
+		j++;
+
 		ide_add_drive_to_hwgroup(drive);
 	}
 	mutex_unlock(&ide_cfg_mtx);
+
+	return j;
 }
 
 static ide_hwif_t *ide_ports[MAX_HWIFS];
@@ -1037,14 +1046,9 @@
 	ide_hwgroup_t *hwgroup;
 	ide_hwif_t *match = NULL;
 
-
-	BUG_ON(in_interrupt());
-	BUG_ON(irqs_disabled());	
-	BUG_ON(hwif == NULL);
-
 	mutex_lock(&ide_cfg_mtx);
 	hwif->hwgroup = NULL;
-#if MAX_HWIFS > 1
+
 	/*
 	 * Group up with any other hwifs that share our irq(s).
 	 */
@@ -1069,7 +1073,7 @@
 			}
 		}
 	}
-#endif /* MAX_HWIFS > 1 */
+
 	/*
 	 * If we are still without a hwgroup, then form a new one
 	 */
@@ -1116,7 +1120,8 @@
 		sa = IRQF_SHARED;
 #endif /* __mc68000__ */
 
-		if (IDE_CHIPSET_IS_PCI(hwif->chipset))
+		if (hwif->chipset == ide_pci || hwif->chipset == ide_cmd646 ||
+		    hwif->chipset == ide_ali14xx)
 			sa = IRQF_SHARED;
 
 		if (io_ports->ctl_addr)
@@ -1167,12 +1172,13 @@
 	ide_hwif_t *hwif = data;
 	int unit = *part >> PARTN_BITS;
 	ide_drive_t *drive = &hwif->drives[unit];
-	if (!drive->present)
+
+	if ((drive->dev_flags & IDE_DFLAG_PRESENT) == 0)
 		return NULL;
 
 	if (drive->media == ide_disk)
 		request_module("ide-disk");
-	if (drive->scsi)
+	if (drive->dev_flags & IDE_DFLAG_SCSI)
 		request_module("ide-scsi");
 	if (drive->media == ide_cdrom || drive->media == ide_optical)
 		request_module("ide-cd");
@@ -1188,7 +1194,7 @@
 {
 	struct gendisk *p = data;
 	*part &= (1 << PARTN_BITS) - 1;
-	return &p->dev.kobj;
+	return &disk_to_dev(p)->kobj;
 }
 
 static int exact_lock(dev_t dev, void *data)
@@ -1219,7 +1225,7 @@
 void ide_init_disk(struct gendisk *disk, ide_drive_t *drive)
 {
 	ide_hwif_t *hwif = drive->hwif;
-	unsigned int unit = (drive->select.all >> 4) & 1;
+	unsigned int unit = drive->dn & 1;
 
 	disk->major = hwif->major;
 	disk->first_minor = unit << PARTN_BITS;
@@ -1262,7 +1268,7 @@
 	ide_remove_drive_from_hwgroup(drive);
 	kfree(drive->id);
 	drive->id = NULL;
-	drive->present = 0;
+	drive->dev_flags &= ~IDE_DFLAG_PRESENT;
 	/* Messed up locking ... */
 	spin_unlock_irq(&ide_lock);
 	blk_cleanup_queue(drive->queue);
@@ -1341,11 +1347,9 @@
 		struct device *dev = &drive->gendev;
 		int ret;
 
-		if (!drive->present)
+		if ((drive->dev_flags & IDE_DFLAG_PRESENT) == 0)
 			continue;
 
-		ide_add_generic_settings(drive);
-
 		snprintf(dev->bus_id, BUS_ID_SIZE, "%u.%u", hwif->index, i);
 		dev->parent = &hwif->gendev;
 		dev->bus = &ide_bus_type;
@@ -1367,12 +1371,14 @@
 	for (i = 0; i < MAX_DRIVES; i++) {
 		ide_drive_t *drive = &hwif->drives[i];
 
+		drive->dn = i + hwif->channel * 2;
+
 		if (hwif->host_flags & IDE_HFLAG_IO_32BIT)
 			drive->io_32bit = 1;
 		if (hwif->host_flags & IDE_HFLAG_UNMASK_IRQS)
-			drive->unmask = 1;
+			drive->dev_flags |= IDE_DFLAG_UNMASK;
 		if (hwif->host_flags & IDE_HFLAG_NO_UNMASK_IRQS)
-			drive->no_unmask = 1;
+			drive->dev_flags |= IDE_DFLAG_NO_UNMASK;
 
 		if (port_ops && port_ops->init_dev)
 			port_ops->init_dev(drive);
@@ -1492,7 +1498,7 @@
 
 static int ide_sysfs_register_port(ide_hwif_t *hwif)
 {
-	int i, rc;
+	int i, uninitialized_var(rc);
 
 	for (i = 0; ide_port_attrs[i]; i++) {
 		rc = device_create_file(hwif->portdev, ide_port_attrs[i]);
@@ -1529,19 +1535,14 @@
 	 * ports 0x1f0/0x170 (the ide0/ide1 defaults).
 	 */
 	mutex_lock(&ide_cfg_mtx);
-	if (MAX_HWIFS == 1) {
-		if (ide_indexes == 0 && i == 0)
-			idx = 1;
+	if (bootable) {
+		if ((ide_indexes | i) != (1 << MAX_HWIFS) - 1)
+			idx = ffz(ide_indexes | i);
 	} else {
-		if (bootable) {
-			if ((ide_indexes | i) != (1 << MAX_HWIFS) - 1)
-				idx = ffz(ide_indexes | i);
-		} else {
-			if ((ide_indexes | 3) != (1 << MAX_HWIFS) - 1)
-				idx = ffz(ide_indexes | 3);
-			else if ((ide_indexes & 3) != 3)
-				idx = ffz(ide_indexes);
-		}
+		if ((ide_indexes | 3) != (1 << MAX_HWIFS) - 1)
+			idx = ffz(ide_indexes | 3);
+		else if ((ide_indexes & 3) != 3)
+			idx = ffz(ide_indexes);
 	}
 	if (idx >= 0)
 		ide_indexes |= (1 << idx);
@@ -1557,8 +1558,7 @@
 	mutex_unlock(&ide_cfg_mtx);
 }
 
-struct ide_host *ide_host_alloc_all(const struct ide_port_info *d,
-				    hw_regs_t **hws)
+struct ide_host *ide_host_alloc(const struct ide_port_info *d, hw_regs_t **hws)
 {
 	struct ide_host *host;
 	int i;
@@ -1567,7 +1567,7 @@
 	if (host == NULL)
 		return NULL;
 
-	for (i = 0; i < MAX_HWIFS; i++) {
+	for (i = 0; i < MAX_HOST_PORTS; i++) {
 		ide_hwif_t *hwif;
 		int idx;
 
@@ -1602,23 +1602,13 @@
 	if (hws[0])
 		host->dev[0] = hws[0]->dev;
 
-	if (d)
+	if (d) {
+		host->init_chipset = d->init_chipset;
 		host->host_flags = d->host_flags;
+	}
 
 	return host;
 }
-EXPORT_SYMBOL_GPL(ide_host_alloc_all);
-
-struct ide_host *ide_host_alloc(const struct ide_port_info *d, hw_regs_t **hws)
-{
-	hw_regs_t *hws_all[MAX_HWIFS];
-	int i;
-
-	for (i = 0; i < MAX_HWIFS; i++)
-		hws_all[i] = (i < 4) ? hws[i] : NULL;
-
-	return ide_host_alloc_all(d, hws_all);
-}
 EXPORT_SYMBOL_GPL(ide_host_alloc);
 
 int ide_host_register(struct ide_host *host, const struct ide_port_info *d,
@@ -1627,7 +1617,7 @@
 	ide_hwif_t *hwif, *mate = NULL;
 	int i, j = 0;
 
-	for (i = 0; i < MAX_HWIFS; i++) {
+	for (i = 0; i < MAX_HOST_PORTS; i++) {
 		hwif = host->ports[i];
 
 		if (hwif == NULL) {
@@ -1640,22 +1630,22 @@
 
 		if (d == NULL) {
 			mate = NULL;
-			continue;
+		} else {
+			if ((i & 1) && mate) {
+				hwif->mate = mate;
+				mate->mate = hwif;
+			}
+
+			mate = (i & 1) ? NULL : hwif;
+
+			ide_init_port(hwif, i & 1, d);
+			ide_port_cable_detect(hwif);
 		}
 
-		if ((i & 1) && mate) {
-			hwif->mate = mate;
-			mate->mate = hwif;
-		}
-
-		mate = (i & 1) ? NULL : hwif;
-
-		ide_init_port(hwif, i & 1, d);
-		ide_port_cable_detect(hwif);
 		ide_port_init_devices(hwif);
 	}
 
-	for (i = 0; i < MAX_HWIFS; i++) {
+	for (i = 0; i < MAX_HOST_PORTS; i++) {
 		hwif = host->ports[i];
 
 		if (hwif == NULL)
@@ -1672,7 +1662,7 @@
 			ide_port_tune_devices(hwif);
 	}
 
-	for (i = 0; i < MAX_HWIFS; i++) {
+	for (i = 0; i < MAX_HOST_PORTS; i++) {
 		hwif = host->ports[i];
 
 		if (hwif == NULL)
@@ -1685,10 +1675,13 @@
 			continue;
 		}
 
-		j++;
-
 		if (hwif->present)
-			ide_port_setup_devices(hwif);
+			if (ide_port_setup_devices(hwif) == 0) {
+				hwif->present = 0;
+				continue;
+			}
+
+		j++;
 
 		ide_acpi_init(hwif);
 
@@ -1696,7 +1689,7 @@
 			ide_acpi_port_init_devices(hwif);
 	}
 
-	for (i = 0; i < MAX_HWIFS; i++) {
+	for (i = 0; i < MAX_HOST_PORTS; i++) {
 		hwif = host->ports[i];
 
 		if (hwif == NULL)
@@ -1709,7 +1702,7 @@
 			hwif_register_devices(hwif);
 	}
 
-	for (i = 0; i < MAX_HWIFS; i++) {
+	for (i = 0; i < MAX_HOST_PORTS; i++) {
 		hwif = host->ports[i];
 
 		if (hwif == NULL)
@@ -1754,7 +1747,7 @@
 	ide_hwif_t *hwif;
 	int i;
 
-	for (i = 0; i < MAX_HWIFS; i++) {
+	for (i = 0; i < MAX_HOST_PORTS; i++) {
 		hwif = host->ports[i];
 
 		if (hwif == NULL)
@@ -1772,7 +1765,7 @@
 {
 	int i;
 
-	for (i = 0; i < MAX_HWIFS; i++) {
+	for (i = 0; i < MAX_HOST_PORTS; i++) {
 		if (host->ports[i])
 			ide_unregister(host->ports[i]);
 	}
diff --git a/drivers/ide/ide-proc.c b/drivers/ide/ide-proc.c
index f66c9c3..b269264 100644
--- a/drivers/ide/ide-proc.c
+++ b/drivers/ide/ide-proc.c
@@ -12,14 +12,6 @@
  * "settings" files.  e.g.    "cat /proc/ide0/hda/settings"
  * To write a new value "val" into a specific setting "name", use:
  *   echo "name:val" >/proc/ide/ide0/hda/settings
- *
- * Also useful, "cat /proc/ide0/hda/[identify, smart_values,
- * smart_thresholds, capabilities]" will issue an IDENTIFY /
- * PACKET_IDENTIFY / SMART_READ_VALUES / SMART_READ_THRESHOLDS /
- * SENSE CAPABILITIES command to /dev/hda, and then dump out the
- * returned data as 256 16-bit words.  The "hdparm" utility will
- * be updated someday soon to use this mechanism.
- *
  */
 
 #include <linux/module.h>
@@ -31,7 +23,6 @@
 #include <linux/mm.h>
 #include <linux/pci.h>
 #include <linux/ctype.h>
-#include <linux/hdreg.h>
 #include <linux/ide.h>
 #include <linux/seq_file.h>
 
@@ -109,13 +100,14 @@
 
 		err = taskfile_lib_get_identify(drive, page);
 		if (!err) {
-			char *out = ((char *)page) + (SECTOR_WORDS * 4);
+			char *out = (char *)page + SECTOR_SIZE;
+
 			page = out;
 			do {
 				out += sprintf(out, "%04x%c",
 					le16_to_cpup(val), (++i & 7) ? ' ' : '\n');
 				val += 1;
-			} while (i < (SECTOR_WORDS * 2));
+			} while (i < SECTOR_SIZE / 2);
 			len = out - page;
 		}
 	}
@@ -123,140 +115,25 @@
 }
 
 /**
- *	__ide_add_setting	-	add an ide setting option
- *	@drive: drive to use
- *	@name: setting name
- *	@rw: true if the function is read write
- *	@data_type: type of data
- *	@min: range minimum
- *	@max: range maximum
- *	@mul_factor: multiplication scale
- *	@div_factor: divison scale
- *	@data: private data field
- *	@set: setting
- *	@auto_remove: setting auto removal flag
- *
- *	Removes the setting named from the device if it is present.
- *	The function takes the settings_lock to protect against
- *	parallel changes. This function must not be called from IRQ
- *	context. Returns 0 on success or -1 on failure.
- *
- *	BUGS: This code is seriously over-engineered. There is also
- *	magic about how the driver specific features are setup. If
- *	a driver is attached we assume the driver settings are auto
- *	remove.
- */
-
-static int __ide_add_setting(ide_drive_t *drive, const char *name, int rw, int data_type, int min, int max, int mul_factor, int div_factor, void *data, ide_procset_t *set, int auto_remove)
-{
-	ide_settings_t **p = (ide_settings_t **) &drive->settings, *setting = NULL;
-
-	mutex_lock(&ide_setting_mtx);
-	while ((*p) && strcmp((*p)->name, name) < 0)
-		p = &((*p)->next);
-	if ((setting = kzalloc(sizeof(*setting), GFP_KERNEL)) == NULL)
-		goto abort;
-	if ((setting->name = kmalloc(strlen(name) + 1, GFP_KERNEL)) == NULL)
-		goto abort;
-	strcpy(setting->name, name);
-	setting->rw = rw;
-	setting->data_type = data_type;
-	setting->min = min;
-	setting->max = max;
-	setting->mul_factor = mul_factor;
-	setting->div_factor = div_factor;
-	setting->data = data;
-	setting->set = set;
-
-	setting->next = *p;
-	if (auto_remove)
-		setting->auto_remove = 1;
-	*p = setting;
-	mutex_unlock(&ide_setting_mtx);
-	return 0;
-abort:
-	mutex_unlock(&ide_setting_mtx);
-	kfree(setting);
-	return -1;
-}
-
-int ide_add_setting(ide_drive_t *drive, const char *name, int rw, int data_type, int min, int max, int mul_factor, int div_factor, void *data, ide_procset_t *set)
-{
-	return __ide_add_setting(drive, name, rw, data_type, min, max, mul_factor, div_factor, data, set, 1);
-}
-
-EXPORT_SYMBOL(ide_add_setting);
-
-/**
- *	__ide_remove_setting	-	remove an ide setting option
- *	@drive: drive to use
+ *	ide_find_setting	-	find a specific setting
+ *	@st: setting table pointer
  *	@name: setting name
  *
- *	Removes the setting named from the device if it is present.
- *	The caller must hold the setting semaphore.
- */
-
-static void __ide_remove_setting(ide_drive_t *drive, char *name)
-{
-	ide_settings_t **p, *setting;
-
-	p = (ide_settings_t **) &drive->settings;
-
-	while ((*p) && strcmp((*p)->name, name))
-		p = &((*p)->next);
-	setting = (*p);
-	if (setting == NULL)
-		return;
-
-	(*p) = setting->next;
-
-	kfree(setting->name);
-	kfree(setting);
-}
-
-/**
- *	auto_remove_settings	-	remove driver specific settings
- *	@drive: drive
- *
- *	Automatically remove all the driver specific settings for this
- *	drive. This function may not be called from IRQ context. The
- *	caller must hold ide_setting_mtx.
- */
-
-static void auto_remove_settings(ide_drive_t *drive)
-{
-	ide_settings_t *setting;
-repeat:
-	setting = drive->settings;
-	while (setting) {
-		if (setting->auto_remove) {
-			__ide_remove_setting(drive, setting->name);
-			goto repeat;
-		}
-		setting = setting->next;
-	}
-}
-
-/**
- *	ide_find_setting_by_name	-	find a drive specific setting
- *	@drive: drive to scan
- *	@name: setting name
- *
- *	Scan's the device setting table for a matching entry and returns
+ *	Scan's the setting table for a matching entry and returns
  *	this or NULL if no entry is found. The caller must hold the
  *	setting semaphore
  */
 
-static ide_settings_t *ide_find_setting_by_name(ide_drive_t *drive, char *name)
+static
+const struct ide_proc_devset *ide_find_setting(const struct ide_proc_devset *st,
+					       char *name)
 {
-	ide_settings_t *setting = drive->settings;
-
-	while (setting) {
-		if (strcmp(setting->name, name) == 0)
+	while (st->name) {
+		if (strcmp(st->name, name) == 0)
 			break;
-		setting = setting->next;
+		st++;
 	}
-	return setting;
+	return st->name ? st : NULL;
 }
 
 /**
@@ -272,26 +149,20 @@
  *	be told apart
  */
 
-static int ide_read_setting(ide_drive_t *drive, ide_settings_t *setting)
+static int ide_read_setting(ide_drive_t *drive,
+			    const struct ide_proc_devset *setting)
 {
-	int		val = -EINVAL;
-	unsigned long	flags;
+	const struct ide_devset *ds = setting->setting;
+	int val = -EINVAL;
 
-	if ((setting->rw & SETTING_READ)) {
+	if (ds->get) {
+		unsigned long flags;
+
 		spin_lock_irqsave(&ide_lock, flags);
-		switch (setting->data_type) {
-		case TYPE_BYTE:
-			val = *((u8 *) setting->data);
-			break;
-		case TYPE_SHORT:
-			val = *((u16 *) setting->data);
-			break;
-		case TYPE_INT:
-			val = *((u32 *) setting->data);
-			break;
-		}
+		val = ds->get(drive);
 		spin_unlock_irqrestore(&ide_lock, flags);
 	}
+
 	return val;
 }
 
@@ -313,33 +184,23 @@
  *	The current scheme of polling is kludgy, though safe enough.
  */
 
-static int ide_write_setting(ide_drive_t *drive, ide_settings_t *setting, int val)
+static int ide_write_setting(ide_drive_t *drive,
+			     const struct ide_proc_devset *setting, int val)
 {
+	const struct ide_devset *ds = setting->setting;
+
 	if (!capable(CAP_SYS_ADMIN))
 		return -EACCES;
-	if (setting->set)
-		return setting->set(drive, val);
-	if (!(setting->rw & SETTING_WRITE))
+	if (!ds->set)
 		return -EPERM;
-	if (val < setting->min || val > setting->max)
+	if ((ds->flags & DS_SYNC)
+	    && (val < setting->min || val > setting->max))
 		return -EINVAL;
-	if (ide_spin_wait_hwgroup(drive))
-		return -EBUSY;
-	switch (setting->data_type) {
-	case TYPE_BYTE:
-		*((u8 *) setting->data) = val;
-		break;
-	case TYPE_SHORT:
-		*((u16 *) setting->data) = val;
-		break;
-	case TYPE_INT:
-		*((u32 *) setting->data) = val;
-		break;
-	}
-	spin_unlock_irq(&ide_lock);
-	return 0;
+	return ide_devset_execute(drive, ds, val);
 }
 
+ide_devset_get(xfer_rate, current_speed);
+
 static int set_xfer_rate (ide_drive_t *drive, int arg)
 {
 	ide_task_t task;
@@ -349,7 +210,7 @@
 		return -EINVAL;
 
 	memset(&task, 0, sizeof(task));
-	task.tf.command = WIN_SETFEATURES;
+	task.tf.command = ATA_CMD_SET_FEATURES;
 	task.tf.feature = SETFEATURES_XFER;
 	task.tf.nsect   = (u8)arg;
 	task.tf_flags = IDE_TFLAG_OUT_FEATURE | IDE_TFLAG_OUT_NSECT |
@@ -364,29 +225,23 @@
 	return err;
 }
 
-/**
- *	ide_add_generic_settings	-	generic ide settings
- *	@drive: drive being configured
- *
- *	Add the generic parts of the system settings to the /proc files.
- *	The caller must not be holding the ide_setting_mtx.
- */
+ide_devset_rw(current_speed, xfer_rate);
+ide_devset_rw_field(init_speed, init_speed);
+ide_devset_rw_flag(nice1, IDE_DFLAG_NICE1);
+ide_devset_rw_field(number, dn);
 
-void ide_add_generic_settings (ide_drive_t *drive)
-{
-/*
- *			  drive		setting name		read/write access				data type	min	max				mul_factor	div_factor	data pointer			set function
- */
-	__ide_add_setting(drive,	"io_32bit",		drive->no_io_32bit ? SETTING_READ : SETTING_RW,	TYPE_BYTE,	0,	1 + (SUPPORT_VLB_SYNC << 1),	1,		1,		&drive->io_32bit,		set_io_32bit,	0);
-	__ide_add_setting(drive,	"keepsettings",		SETTING_RW,					TYPE_BYTE,	0,	1,				1,		1,		&drive->keep_settings,		NULL,		0);
-	__ide_add_setting(drive,	"nice1",		SETTING_RW,					TYPE_BYTE,	0,	1,				1,		1,		&drive->nice1,			NULL,		0);
-	__ide_add_setting(drive,	"pio_mode",		SETTING_WRITE,					TYPE_BYTE,	0,	255,				1,		1,		NULL,				set_pio_mode,	0);
-	__ide_add_setting(drive,	"unmaskirq",		drive->no_unmask ? SETTING_READ : SETTING_RW,	TYPE_BYTE,	0,	1,				1,		1,		&drive->unmask,			NULL,		0);
-	__ide_add_setting(drive,	"using_dma",		SETTING_RW,					TYPE_BYTE,	0,	1,				1,		1,		&drive->using_dma,		set_using_dma,	0);
-	__ide_add_setting(drive,	"init_speed",		SETTING_RW,					TYPE_BYTE,	0,	70,				1,		1,		&drive->init_speed,		NULL,		0);
-	__ide_add_setting(drive,	"current_speed",	SETTING_RW,					TYPE_BYTE,	0,	70,				1,		1,		&drive->current_speed,		set_xfer_rate,	0);
-	__ide_add_setting(drive,	"number",		SETTING_RW,					TYPE_BYTE,	0,	3,				1,		1,		&drive->dn,			NULL,		0);
-}
+static const struct ide_proc_devset ide_generic_settings[] = {
+	IDE_PROC_DEVSET(current_speed, 0, 70),
+	IDE_PROC_DEVSET(init_speed, 0, 70),
+	IDE_PROC_DEVSET(io_32bit,  0, 1 + (SUPPORT_VLB_SYNC << 1)),
+	IDE_PROC_DEVSET(keepsettings, 0, 1),
+	IDE_PROC_DEVSET(nice1, 0, 1),
+	IDE_PROC_DEVSET(number, 0, 3),
+	IDE_PROC_DEVSET(pio_mode, 0, 255),
+	IDE_PROC_DEVSET(unmaskirq, 0, 1),
+	IDE_PROC_DEVSET(using_dma, 0, 1),
+	{ 0 },
+};
 
 static void proc_ide_settings_warn(void)
 {
@@ -403,19 +258,32 @@
 static int proc_ide_read_settings
 	(char *page, char **start, off_t off, int count, int *eof, void *data)
 {
+	const struct ide_proc_devset *setting, *g, *d;
+	const struct ide_devset *ds;
 	ide_drive_t	*drive = (ide_drive_t *) data;
-	ide_settings_t	*setting = (ide_settings_t *) drive->settings;
 	char		*out = page;
 	int		len, rc, mul_factor, div_factor;
 
 	proc_ide_settings_warn();
 
 	mutex_lock(&ide_setting_mtx);
+	g = ide_generic_settings;
+	d = drive->settings;
 	out += sprintf(out, "name\t\t\tvalue\t\tmin\t\tmax\t\tmode\n");
 	out += sprintf(out, "----\t\t\t-----\t\t---\t\t---\t\t----\n");
-	while (setting) {
-		mul_factor = setting->mul_factor;
-		div_factor = setting->div_factor;
+	while (g->name || (d && d->name)) {
+		/* read settings in the alphabetical order */
+		if (g->name && d && d->name) {
+			if (strcmp(d->name, g->name) < 0)
+				setting = d++;
+			else
+				setting = g++;
+		} else if (d && d->name) {
+			setting = d++;
+		} else
+			setting = g++;
+		mul_factor = setting->mulf ? setting->mulf(drive) : 1;
+		div_factor = setting->divf ? setting->divf(drive) : 1;
 		out += sprintf(out, "%-24s", setting->name);
 		rc = ide_read_setting(drive, setting);
 		if (rc >= 0)
@@ -423,12 +291,12 @@
 		else
 			out += sprintf(out, "%-16s", "write-only");
 		out += sprintf(out, "%-16d%-16d", (setting->min * mul_factor + div_factor - 1) / div_factor, setting->max * mul_factor / div_factor);
-		if (setting->rw & SETTING_READ)
+		ds = setting->setting;
+		if (ds->get)
 			out += sprintf(out, "r");
-		if (setting->rw & SETTING_WRITE)
+		if (ds->set)
 			out += sprintf(out, "w");
 		out += sprintf(out, "\n");
-		setting = setting->next;
 	}
 	len = out - page;
 	mutex_unlock(&ide_setting_mtx);
@@ -442,9 +310,10 @@
 {
 	ide_drive_t	*drive = (ide_drive_t *) data;
 	char		name[MAX_LEN + 1];
-	int		for_real = 0;
+	int		for_real = 0, mul_factor, div_factor;
 	unsigned long	n;
-	ide_settings_t	*setting;
+
+	const struct ide_proc_devset *setting;
 	char *buf, *s;
 
 	if (!capable(CAP_SYS_ADMIN))
@@ -512,13 +381,21 @@
 			}
 
 			mutex_lock(&ide_setting_mtx);
-			setting = ide_find_setting_by_name(drive, name);
+			/* generic settings first, then driver specific ones */
+			setting = ide_find_setting(ide_generic_settings, name);
 			if (!setting) {
-				mutex_unlock(&ide_setting_mtx);
-				goto parse_error;
+				if (drive->settings)
+					setting = ide_find_setting(drive->settings, name);
+				if (!setting) {
+					mutex_unlock(&ide_setting_mtx);
+					goto parse_error;
+				}
 			}
-			if (for_real)
-				ide_write_setting(drive, setting, val * setting->div_factor / setting->mul_factor);
+			if (for_real) {
+				mul_factor = setting->mulf ? setting->mulf(drive) : 1;
+				div_factor = setting->divf ? setting->divf(drive) : 1;
+				ide_write_setting(drive, setting, val * div_factor / mul_factor);
+			}
 			mutex_unlock(&ide_setting_mtx);
 		}
 	} while (!for_real++);
@@ -561,11 +438,10 @@
 	(char *page, char **start, off_t off, int count, int *eof, void *data)
 {
 	ide_drive_t	*drive = (ide_drive_t *) data;
-	struct hd_driveid *id = drive->id;
+	char		*m = (char *)&drive->id[ATA_ID_PROD];
 	int		len;
 
-	len = sprintf(page, "%.40s\n",
-		(id && id->model[0]) ? (char *)id->model : "(none)");
+	len = sprintf(page, "%.40s\n", m[0] ? m : "(none)");
 	PROC_IDE_READ_RETURN(page, start, off, count, eof, len);
 }
 
@@ -690,6 +566,10 @@
 
 void ide_proc_register_driver(ide_drive_t *drive, ide_driver_t *driver)
 {
+	mutex_lock(&ide_setting_mtx);
+	drive->settings = driver->settings;
+	mutex_unlock(&ide_setting_mtx);
+
 	ide_add_proc_entries(drive->proc, driver->proc, drive);
 }
 
@@ -726,7 +606,7 @@
 	 * OTOH both ide_{read,write}_setting are only ever used under
 	 * ide_setting_mtx.
 	 */
-	auto_remove_settings(drive);
+	drive->settings = NULL;
 	spin_unlock_irqrestore(&ide_lock, flags);
 	mutex_unlock(&ide_setting_mtx);
 }
@@ -742,9 +622,7 @@
 	for (d = 0; d < MAX_DRIVES; d++) {
 		ide_drive_t *drive = &hwif->drives[d];
 
-		if (!drive->present)
-			continue;
-		if (drive->proc)
+		if ((drive->dev_flags & IDE_DFLAG_PRESENT) == 0 || drive->proc)
 			continue;
 
 		drive->proc = proc_mkdir(drive->name, parent);
diff --git a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c
index 1bce84b..25ac60f 100644
--- a/drivers/ide/ide-tape.c
+++ b/drivers/ide/ide-tape.c
@@ -15,6 +15,8 @@
  * Documentation/ide/ChangeLog.ide-tape.1995-2002
  */
 
+#define DRV_NAME "ide-tape"
+
 #define IDETAPE_VERSION "1.20"
 
 #include <linux/module.h>
@@ -54,8 +56,6 @@
 	DBG_CHRDEV =		(1 << 2),
 	/* all remaining procedures */
 	DBG_PROCS =		(1 << 3),
-	/* buffer alloc info (pc_stack & rq_stack) */
-	DBG_PCRQ_STACK =	(1 << 4),
 };
 
 /* define to see debug info */
@@ -81,26 +81,6 @@
 #define IDETAPE_MAX_PC_RETRIES		3
 
 /*
- * With each packet command, we allocate a buffer of IDETAPE_PC_BUFFER_SIZE
- * bytes. This is used for several packet commands (Not for READ/WRITE commands)
- */
-#define IDETAPE_PC_BUFFER_SIZE		256
-
-/*
- *	In various places in the driver, we need to allocate storage
- *	for packet commands and requests, which will remain valid while
- *	we leave the driver to wait for an interrupt or a timeout event.
- */
-#define IDETAPE_PC_STACK		(10 + IDETAPE_MAX_PC_RETRIES)
-
-/*
- * Some drives (for example, Seagate STT3401A Travan) require a very long
- * timeout, because they don't return an interrupt or clear their busy bit
- * until after the command completes (even retension commands).
- */
-#define IDETAPE_WAIT_CMD		(900*HZ)
-
-/*
  * The following parameter is used to select the point in the internal tape fifo
  * in which we will start to refill the buffer. Decreasing the following
  * parameter will improve the system's latency and interactive response, while
@@ -172,20 +152,6 @@
 #define IDETAPE_LU_RETENSION_MASK	2
 #define IDETAPE_LU_EOT_MASK		4
 
-/*
- * Special requests for our block device strategy routine.
- *
- * In order to service a character device command, we add special requests to
- * the tail of our block device request queue and wait for their completion.
- */
-
-enum {
-	REQ_IDETAPE_PC1		= (1 << 0), /* packet command (first stage) */
-	REQ_IDETAPE_PC2		= (1 << 1), /* packet command (second stage) */
-	REQ_IDETAPE_READ	= (1 << 2),
-	REQ_IDETAPE_WRITE	= (1 << 3),
-};
-
 /* Error codes returned in rq->errors to the higher part of the driver. */
 #define IDETAPE_ERROR_GENERAL		101
 #define IDETAPE_ERROR_FILEMARK		102
@@ -206,31 +172,15 @@
 	struct kref	kref;
 
 	/*
-	 *	Since a typical character device operation requires more
-	 *	than one packet command, we provide here enough memory
-	 *	for the maximum of interconnected packet commands.
-	 *	The packet commands are stored in the circular array pc_stack.
-	 *	pc_stack_index points to the last used entry, and warps around
-	 *	to the start when we get to the last array entry.
-	 *
-	 *	pc points to the current processed packet command.
-	 *
 	 *	failed_pc points to the last failed packet command, or contains
 	 *	NULL if we do not need to retry any packet command. This is
 	 *	required since an additional packet command is needed before the
 	 *	retry, to get detailed information on what went wrong.
 	 */
-	/* Current packet command */
-	struct ide_atapi_pc *pc;
 	/* Last failed packet command */
 	struct ide_atapi_pc *failed_pc;
-	/* Packet command stack */
-	struct ide_atapi_pc pc_stack[IDETAPE_PC_STACK];
-	/* Next free packet command storage space */
-	int pc_stack_index;
-	struct request rq_stack[IDETAPE_PC_STACK];
-	/* We implement a circular array */
-	int rq_stack_index;
+	/* used by REQ_IDETAPE_{READ,WRITE} requests */
+	struct ide_atapi_pc queued_pc;
 
 	/*
 	 * DSC polling variables.
@@ -317,11 +267,6 @@
 
 static struct class *idetape_sysfs_class;
 
-#define to_ide_tape(obj) container_of(obj, struct ide_tape_obj, kref)
-
-#define ide_tape_g(disk) \
-	container_of((disk)->private_data, struct ide_tape_obj, driver)
-
 static void ide_tape_release(struct kref *);
 
 static struct ide_tape_obj *ide_tape_get(struct gendisk *disk)
@@ -329,7 +274,7 @@
 	struct ide_tape_obj *tape = NULL;
 
 	mutex_lock(&idetape_ref_mutex);
-	tape = ide_tape_g(disk);
+	tape = ide_drv_g(disk, ide_tape_obj);
 	if (tape) {
 		if (ide_device_get(tape->drive))
 			tape = NULL;
@@ -356,8 +301,6 @@
  */
 static struct ide_tape_obj *idetape_devs[MAX_HWIFS * MAX_DRIVES];
 
-#define ide_tape_f(file) ((file)->private_data)
-
 static struct ide_tape_obj *ide_tape_chrdev_get(unsigned int i)
 {
 	struct ide_tape_obj *tape = NULL;
@@ -451,47 +394,6 @@
 }
 
 /*
- *	idetape_next_pc_storage returns a pointer to a place in which we can
- *	safely store a packet command, even though we intend to leave the
- *	driver. A storage space for a maximum of IDETAPE_PC_STACK packet
- *	commands is allocated at initialization time.
- */
-static struct ide_atapi_pc *idetape_next_pc_storage(ide_drive_t *drive)
-{
-	idetape_tape_t *tape = drive->driver_data;
-
-	debug_log(DBG_PCRQ_STACK, "pc_stack_index=%d\n", tape->pc_stack_index);
-
-	if (tape->pc_stack_index == IDETAPE_PC_STACK)
-		tape->pc_stack_index = 0;
-	return (&tape->pc_stack[tape->pc_stack_index++]);
-}
-
-/*
- *	idetape_next_rq_storage is used along with idetape_next_pc_storage.
- *	Since we queue packet commands in the request queue, we need to
- *	allocate a request, along with the allocation of a packet command.
- */
-
-/**************************************************************
- *                                                            *
- *  This should get fixed to use kmalloc(.., GFP_ATOMIC)      *
- *  followed later on by kfree().   -ml                       *
- *                                                            *
- **************************************************************/
-
-static struct request *idetape_next_rq_storage(ide_drive_t *drive)
-{
-	idetape_tape_t *tape = drive->driver_data;
-
-	debug_log(DBG_PCRQ_STACK, "rq_stack_index=%d\n", tape->rq_stack_index);
-
-	if (tape->rq_stack_index == IDETAPE_PC_STACK)
-		tape->rq_stack_index = 0;
-	return (&tape->rq_stack[tape->rq_stack_index++]);
-}
-
-/*
  * called on each failed packet command retry to analyze the request sense. We
  * currently do not utilize this information.
  */
@@ -606,14 +508,19 @@
 	return 0;
 }
 
-static void ide_tape_callback(ide_drive_t *drive)
+static void ide_tape_handle_dsc(ide_drive_t *);
+
+static void ide_tape_callback(ide_drive_t *drive, int dsc)
 {
 	idetape_tape_t *tape = drive->driver_data;
-	struct ide_atapi_pc *pc = tape->pc;
+	struct ide_atapi_pc *pc = drive->pc;
 	int uptodate = pc->error ? 0 : 1;
 
 	debug_log(DBG_PROCS, "Enter %s\n", __func__);
 
+	if (dsc)
+		ide_tape_handle_dsc(drive);
+
 	if (tape->failed_pc == pc)
 		tape->failed_pc = NULL;
 
@@ -642,7 +549,7 @@
 		if (pc->error)
 			uptodate = pc->error;
 	} else if (pc->c[0] == READ_POSITION && uptodate) {
-		u8 *readpos = tape->pc->buf;
+		u8 *readpos = pc->buf;
 
 		debug_log(DBG_SENSE, "BOP - %s\n",
 				(readpos[0] & 0x80) ? "Yes" : "No");
@@ -667,79 +574,6 @@
 	idetape_end_request(drive, uptodate, 0);
 }
 
-static void idetape_init_pc(struct ide_atapi_pc *pc)
-{
-	memset(pc->c, 0, 12);
-	pc->retries = 0;
-	pc->flags = 0;
-	pc->req_xfer = 0;
-	pc->buf = pc->pc_buf;
-	pc->buf_size = IDETAPE_PC_BUFFER_SIZE;
-	pc->bh = NULL;
-	pc->b_data = NULL;
-}
-
-static void idetape_create_request_sense_cmd(struct ide_atapi_pc *pc)
-{
-	idetape_init_pc(pc);
-	pc->c[0] = REQUEST_SENSE;
-	pc->c[4] = 20;
-	pc->req_xfer = 20;
-}
-
-static void idetape_init_rq(struct request *rq, u8 cmd)
-{
-	blk_rq_init(NULL, rq);
-	rq->cmd_type = REQ_TYPE_SPECIAL;
-	rq->cmd[13] = cmd;
-}
-
-/*
- * Generate a new packet command request in front of the request queue, before
- * the current request, so that it will be processed immediately, on the next
- * pass through the driver. The function below is called from the request
- * handling part of the driver (the "bottom" part). Safe storage for the request
- * should be allocated with ide_tape_next_{pc,rq}_storage() prior to that.
- *
- * Memory for those requests is pre-allocated at initialization time, and is
- * limited to IDETAPE_PC_STACK requests. We assume that we have enough space for
- * the maximum possible number of inter-dependent packet commands.
- *
- * The higher level of the driver - The ioctl handler and the character device
- * handling functions should queue request to the lower level part and wait for
- * their completion using idetape_queue_pc_tail or idetape_queue_rw_tail.
- */
-static void idetape_queue_pc_head(ide_drive_t *drive, struct ide_atapi_pc *pc,
-				  struct request *rq)
-{
-	struct ide_tape_obj *tape = drive->driver_data;
-
-	idetape_init_rq(rq, REQ_IDETAPE_PC1);
-	rq->cmd_flags |= REQ_PREEMPT;
-	rq->buffer = (char *) pc;
-	rq->rq_disk = tape->disk;
-	memcpy(rq->cmd, pc->c, 12);
-	ide_do_drive_cmd(drive, rq);
-}
-
-/*
- *	idetape_retry_pc is called when an error was detected during the
- *	last packet command. We queue a request sense packet command in
- *	the head of the request list.
- */
-static void idetape_retry_pc(ide_drive_t *drive)
-{
-	struct ide_atapi_pc *pc;
-	struct request *rq;
-
-	(void)ide_read_error(drive);
-	pc = idetape_next_pc_storage(drive);
-	rq = idetape_next_rq_storage(drive);
-	idetape_create_request_sense_cmd(pc);
-	set_bit(IDE_AFLAG_IGNORE_DSC, &drive->atapi_flags);
-	idetape_queue_pc_head(drive, pc, rq);
-}
-
 /*
  * Postpone the current request so that ide.c will be able to service requests
  * from another device on the same hwgroup while we are polling for DSC.
@@ -766,44 +600,30 @@
 	idetape_postpone_request(drive);
 }
 
-static void ide_tape_io_buffers(ide_drive_t *drive, struct ide_atapi_pc *pc,
+static int ide_tape_io_buffers(ide_drive_t *drive, struct ide_atapi_pc *pc,
 				unsigned int bcount, int write)
 {
 	if (write)
 		idetape_output_buffers(drive, pc, bcount);
 	else
 		idetape_input_buffers(drive, pc, bcount);
-}
 
-/*
- * This is the usual interrupt handler which will be called during a packet
- * command. We will transfer some of the data (as requested by the drive) and
- * will re-point interrupt handler to us. When data transfer is finished, we
- * will act according to the algorithm described before
- * idetape_issue_pc.
- */
-static ide_startstop_t idetape_pc_intr(ide_drive_t *drive)
-{
-	idetape_tape_t *tape = drive->driver_data;
-
-	return ide_pc_intr(drive, tape->pc, idetape_pc_intr, IDETAPE_WAIT_CMD,
-			   NULL, idetape_update_buffers, idetape_retry_pc,
-			   ide_tape_handle_dsc, ide_tape_io_buffers);
+	return bcount;
 }
 
 /*
  * Packet Command Interface
  *
- * The current Packet Command is available in tape->pc, and will not change
+ * The current Packet Command is available in drive->pc, and will not change
  * until we finish handling it. Each packet command is associated with a
  * callback function that will be called when the command is finished.
  *
  * The handling will be done in three stages:
  *
  * 1. idetape_issue_pc will send the packet command to the drive, and will set
- * the interrupt handler to idetape_pc_intr.
+ * the interrupt handler to ide_pc_intr.
  *
- * 2. On each interrupt, idetape_pc_intr will be called. This step will be
+ * 2. On each interrupt, ide_pc_intr will be called. This step will be
  * repeated until the device signals us that no more interrupts will be issued.
  *
  * 3. ATAPI Tape media access commands have immediate status with a delayed
@@ -827,20 +647,13 @@
  * again, the callback function will be called and then we will handle the next
  * request.
  */
-static ide_startstop_t idetape_transfer_pc(ide_drive_t *drive)
-{
-	idetape_tape_t *tape = drive->driver_data;
-
-	return ide_transfer_pc(drive, tape->pc, idetape_pc_intr,
-			       IDETAPE_WAIT_CMD, NULL);
-}
 
 static ide_startstop_t idetape_issue_pc(ide_drive_t *drive,
 		struct ide_atapi_pc *pc)
 {
 	idetape_tape_t *tape = drive->driver_data;
 
-	if (tape->pc->c[0] == REQUEST_SENSE &&
+	if (drive->pc->c[0] == REQUEST_SENSE &&
 	    pc->c[0] == REQUEST_SENSE) {
 		printk(KERN_ERR "ide-tape: possible ide-tape.c bug - "
 			"Two request sense in serial were issued\n");
@@ -848,8 +661,9 @@
 
 	if (tape->failed_pc == NULL && pc->c[0] != REQUEST_SENSE)
 		tape->failed_pc = pc;
+
 	/* Set the current packet command */
-	tape->pc = pc;
+	drive->pc = pc;
 
 	if (pc->retries > IDETAPE_MAX_PC_RETRIES ||
 		(pc->flags & PC_FLAG_ABORT)) {
@@ -873,21 +687,20 @@
 			pc->error = IDETAPE_ERROR_GENERAL;
 		}
 		tape->failed_pc = NULL;
-		drive->pc_callback(drive);
+		drive->pc_callback(drive, 0);
 		return ide_stopped;
 	}
 	debug_log(DBG_SENSE, "Retry #%d, cmd = %02X\n", pc->retries, pc->c[0]);
 
 	pc->retries++;
 
-	return ide_issue_pc(drive, pc, idetape_transfer_pc,
-			    IDETAPE_WAIT_CMD, NULL);
+	return ide_issue_pc(drive, WAIT_TAPE_CMD, NULL);
 }
 
 /* A mode sense command is used to "sense" tape parameters. */
 static void idetape_create_mode_sense_cmd(struct ide_atapi_pc *pc, u8 page_code)
 {
-	idetape_init_pc(pc);
+	ide_init_pc(pc);
 	pc->c[0] = MODE_SENSE;
 	if (page_code != IDETAPE_BLOCK_DESCRIPTOR)
 		/* DBD = 1 - Don't return block descriptors */
@@ -915,19 +728,19 @@
 {
 	ide_hwif_t *hwif = drive->hwif;
 	idetape_tape_t *tape = drive->driver_data;
-	struct ide_atapi_pc *pc = tape->pc;
+	struct ide_atapi_pc *pc = drive->pc;
 	u8 stat;
 
 	stat = hwif->tp_ops->read_status(hwif);
 
-	if (stat & SEEK_STAT) {
-		if (stat & ERR_STAT) {
+	if (stat & ATA_DSC) {
+		if (stat & ATA_ERR) {
 			/* Error detected */
 			if (pc->c[0] != TEST_UNIT_READY)
 				printk(KERN_ERR "ide-tape: %s: I/O error, ",
 						tape->name);
 			/* Retry operation */
-			idetape_retry_pc(drive);
+			ide_retry_pc(drive, tape->disk);
 			return ide_stopped;
 		}
 		pc->error = 0;
@@ -935,7 +748,7 @@
 		pc->error = IDETAPE_ERROR_GENERAL;
 		tape->failed_pc = NULL;
 	}
-	drive->pc_callback(drive);
+	drive->pc_callback(drive, 0);
 	return ide_stopped;
 }
 
@@ -946,7 +759,7 @@
 	struct idetape_bh *bh = (struct idetape_bh *)rq->special;
 	unsigned int length = rq->current_nr_sectors;
 
-	idetape_init_pc(pc);
+	ide_init_pc(pc);
 	put_unaligned(cpu_to_be32(length), (unsigned int *) &pc->c[1]);
 	pc->c[1] = 1;
 	pc->bh = bh;
@@ -978,9 +791,10 @@
 	struct request *postponed_rq = tape->postponed_rq;
 	u8 stat;
 
-	debug_log(DBG_SENSE, "sector: %ld, nr_sectors: %ld,"
-			" current_nr_sectors: %d\n",
-			rq->sector, rq->nr_sectors, rq->current_nr_sectors);
+	debug_log(DBG_SENSE, "sector: %llu, nr_sectors: %lu,"
+			" current_nr_sectors: %u\n",
+			(unsigned long long)rq->sector, rq->nr_sectors,
+			rq->current_nr_sectors);
 
 	if (!blk_special_request(rq)) {
 		/* We do not support buffer cache originated requests. */
@@ -991,7 +805,7 @@
 	}
 
 	/* Retry a failed packet command */
-	if (tape->failed_pc && tape->pc->c[0] == REQUEST_SENSE) {
+	if (tape->failed_pc && drive->pc->c[0] == REQUEST_SENSE) {
 		pc = tape->failed_pc;
 		goto out;
 	}
@@ -1012,16 +826,17 @@
 	 */
 	stat = hwif->tp_ops->read_status(hwif);
 
-	if (!drive->dsc_overlap && !(rq->cmd[13] & REQ_IDETAPE_PC2))
+	if ((drive->dev_flags & IDE_DFLAG_DSC_OVERLAP) == 0 &&
+	    (rq->cmd[13] & REQ_IDETAPE_PC2) == 0)
 		set_bit(IDE_AFLAG_IGNORE_DSC, &drive->atapi_flags);
 
-	if (drive->post_reset == 1) {
+	if (drive->dev_flags & IDE_DFLAG_POST_RESET) {
 		set_bit(IDE_AFLAG_IGNORE_DSC, &drive->atapi_flags);
-		drive->post_reset = 0;
+		drive->dev_flags &= ~IDE_DFLAG_POST_RESET;
 	}
 
 	if (!test_and_clear_bit(IDE_AFLAG_IGNORE_DSC, &drive->atapi_flags) &&
-	    (stat & SEEK_STAT) == 0) {
+	    (stat & ATA_DSC) == 0) {
 		if (postponed_rq == NULL) {
 			tape->dsc_polling_start = jiffies;
 			tape->dsc_poll_freq = tape->best_dsc_rw_freq;
@@ -1043,12 +858,12 @@
 		return ide_stopped;
 	}
 	if (rq->cmd[13] & REQ_IDETAPE_READ) {
-		pc = idetape_next_pc_storage(drive);
+		pc = &tape->queued_pc;
 		ide_tape_create_rw_cmd(tape, pc, rq, READ_6);
 		goto out;
 	}
 	if (rq->cmd[13] & REQ_IDETAPE_WRITE) {
-		pc = idetape_next_pc_storage(drive);
+		pc = &tape->queued_pc;
 		ide_tape_create_rw_cmd(tape, pc, rq, WRITE_6);
 		goto out;
 	}
@@ -1235,77 +1050,30 @@
 static void idetape_create_write_filemark_cmd(ide_drive_t *drive,
 		struct ide_atapi_pc *pc, int write_filemark)
 {
-	idetape_init_pc(pc);
+	ide_init_pc(pc);
 	pc->c[0] = WRITE_FILEMARKS;
 	pc->c[4] = write_filemark;
 	pc->flags |= PC_FLAG_WAIT_FOR_DSC;
 }
 
-static void idetape_create_test_unit_ready_cmd(struct ide_atapi_pc *pc)
-{
-	idetape_init_pc(pc);
-	pc->c[0] = TEST_UNIT_READY;
-}
-
-/*
- * We add a special packet command request to the tail of the request queue, and
- * wait for it to be serviced. This is not to be called from within the request
- * handling part of the driver! We allocate here data on the stack and it is
- * valid until the request is finished. This is not the case for the bottom part
- * of the driver, where we are always leaving the functions to wait for an
- * interrupt or a timer event.
- *
- * From the bottom part of the driver, we should allocate safe memory using
- * idetape_next_pc_storage() and ide_tape_next_rq_storage(), and add the request
- * to the request list without waiting for it to be serviced! In that case, we
- * usually use idetape_queue_pc_head().
- */
-static int idetape_queue_pc_tail(ide_drive_t *drive, struct ide_atapi_pc *pc)
-{
-	struct ide_tape_obj *tape = drive->driver_data;
-	struct request *rq;
-	int error;
-
-	rq = blk_get_request(drive->queue, READ, __GFP_WAIT);
-	rq->cmd_type = REQ_TYPE_SPECIAL;
-	rq->cmd[13] = REQ_IDETAPE_PC1;
-	rq->buffer = (char *)pc;
-	memcpy(rq->cmd, pc->c, 12);
-	error = blk_execute_rq(drive->queue, tape->disk, rq, 0);
-	blk_put_request(rq);
-	return error;
-}
-
-static void idetape_create_load_unload_cmd(ide_drive_t *drive,
-		struct ide_atapi_pc *pc, int cmd)
-{
-	idetape_init_pc(pc);
-	pc->c[0] = START_STOP;
-	pc->c[4] = cmd;
-	pc->flags |= PC_FLAG_WAIT_FOR_DSC;
-}
-
 static int idetape_wait_ready(ide_drive_t *drive, unsigned long timeout)
 {
 	idetape_tape_t *tape = drive->driver_data;
-	struct ide_atapi_pc pc;
+	struct gendisk *disk = tape->disk;
 	int load_attempted = 0;
 
 	/* Wait for the tape to become ready */
 	set_bit(IDE_AFLAG_MEDIUM_PRESENT, &drive->atapi_flags);
 	timeout += jiffies;
 	while (time_before(jiffies, timeout)) {
-		idetape_create_test_unit_ready_cmd(&pc);
-		if (!idetape_queue_pc_tail(drive, &pc))
+		if (ide_do_test_unit_ready(drive, disk) == 0)
 			return 0;
 		if ((tape->sense_key == 2 && tape->asc == 4 && tape->ascq == 2)
 		    || (tape->asc == 0x3A)) {
 			/* no media */
 			if (load_attempted)
 				return -ENOMEDIUM;
-			idetape_create_load_unload_cmd(drive, &pc,
-							IDETAPE_LU_LOAD_MASK);
-			idetape_queue_pc_tail(drive, &pc);
+			ide_do_start_stop(drive, disk, IDETAPE_LU_LOAD_MASK);
 			load_attempted = 1;
 		/* not about to be ready */
 		} else if (!(tape->sense_key == 2 && tape->asc == 4 &&
@@ -1318,11 +1086,12 @@
 
 static int idetape_flush_tape_buffers(ide_drive_t *drive)
 {
+	struct ide_tape_obj *tape = drive->driver_data;
 	struct ide_atapi_pc pc;
 	int rc;
 
 	idetape_create_write_filemark_cmd(drive, &pc, 0);
-	rc = idetape_queue_pc_tail(drive, &pc);
+	rc = ide_queue_pc_tail(drive, tape->disk, &pc);
 	if (rc)
 		return rc;
 	idetape_wait_ready(drive, 60 * 5 * HZ);
@@ -1331,7 +1100,7 @@
 
 static void idetape_create_read_position_cmd(struct ide_atapi_pc *pc)
 {
-	idetape_init_pc(pc);
+	ide_init_pc(pc);
 	pc->c[0] = READ_POSITION;
 	pc->req_xfer = 20;
 }
@@ -1345,7 +1114,7 @@
 	debug_log(DBG_PROCS, "Enter %s\n", __func__);
 
 	idetape_create_read_position_cmd(&pc);
-	if (idetape_queue_pc_tail(drive, &pc))
+	if (ide_queue_pc_tail(drive, tape->disk, &pc))
 		return -1;
 	position = tape->first_frame;
 	return position;
@@ -1355,7 +1124,7 @@
 		struct ide_atapi_pc *pc,
 		unsigned int block, u8 partition, int skip)
 {
-	idetape_init_pc(pc);
+	ide_init_pc(pc);
 	pc->c[0] = POSITION_TO_ELEMENT;
 	pc->c[1] = 2;
 	put_unaligned(cpu_to_be32(block), (unsigned int *) &pc->c[3]);
@@ -1363,21 +1132,6 @@
 	pc->flags |= PC_FLAG_WAIT_FOR_DSC;
 }
 
-static int idetape_create_prevent_cmd(ide_drive_t *drive,
-		struct ide_atapi_pc *pc, int prevent)
-{
-	idetape_tape_t *tape = drive->driver_data;
-
-	/* device supports locking according to capabilities page */
-	if (!(tape->caps[6] & 0x01))
-		return 0;
-
-	idetape_init_pc(pc);
-	pc->c[0] = ALLOW_MEDIUM_REMOVAL;
-	pc->c[4] = prevent;
-	return 1;
-}
-
 static void __ide_tape_discard_merge_buffer(ide_drive_t *drive)
 {
 	idetape_tape_t *tape = drive->driver_data;
@@ -1405,6 +1159,7 @@
 		u8 partition, int skip)
 {
 	idetape_tape_t *tape = drive->driver_data;
+	struct gendisk *disk = tape->disk;
 	int retval;
 	struct ide_atapi_pc pc;
 
@@ -1412,12 +1167,12 @@
 		__ide_tape_discard_merge_buffer(drive);
 	idetape_wait_ready(drive, 60 * 5 * HZ);
 	idetape_create_locate_cmd(drive, &pc, block, partition, skip);
-	retval = idetape_queue_pc_tail(drive, &pc);
+	retval = ide_queue_pc_tail(drive, disk, &pc);
 	if (retval)
 		return (retval);
 
 	idetape_create_read_position_cmd(&pc);
-	return (idetape_queue_pc_tail(drive, &pc));
+	return ide_queue_pc_tail(drive, disk, &pc);
 }
 
 static void ide_tape_discard_merge_buffer(ide_drive_t *drive,
@@ -1477,7 +1232,7 @@
 
 static void idetape_create_inquiry_cmd(struct ide_atapi_pc *pc)
 {
-	idetape_init_pc(pc);
+	ide_init_pc(pc);
 	pc->c[0] = INQUIRY;
 	pc->c[4] = 254;
 	pc->req_xfer = 254;
@@ -1486,14 +1241,14 @@
 static void idetape_create_rewind_cmd(ide_drive_t *drive,
 		struct ide_atapi_pc *pc)
 {
-	idetape_init_pc(pc);
+	ide_init_pc(pc);
 	pc->c[0] = REZERO_UNIT;
 	pc->flags |= PC_FLAG_WAIT_FOR_DSC;
 }
 
 static void idetape_create_erase_cmd(struct ide_atapi_pc *pc)
 {
-	idetape_init_pc(pc);
+	ide_init_pc(pc);
 	pc->c[0] = ERASE;
 	pc->c[1] = 1;
 	pc->flags |= PC_FLAG_WAIT_FOR_DSC;
@@ -1501,7 +1256,7 @@
 
 static void idetape_create_space_cmd(struct ide_atapi_pc *pc, int count, u8 cmd)
 {
-	idetape_init_pc(pc);
+	ide_init_pc(pc);
 	pc->c[0] = SPACE;
 	put_unaligned(cpu_to_be32(count), (unsigned int *) &pc->c[1]);
 	pc->c[1] = cmd;
@@ -1600,7 +1355,7 @@
 		 * No point in issuing this if DSC overlap isn't supported, some
 		 * drives (Seagate STT3401A) will return an error.
 		 */
-		if (drive->dsc_overlap) {
+		if (drive->dev_flags & IDE_DFLAG_DSC_OVERLAP) {
 			bytes_read = idetape_queue_rw_tail(drive,
 							REQ_IDETAPE_READ, 0,
 							tape->merge_bh);
@@ -1664,20 +1419,20 @@
  */
 static int idetape_rewind_tape(ide_drive_t *drive)
 {
+	struct ide_tape_obj *tape = drive->driver_data;
+	struct gendisk *disk = tape->disk;
 	int retval;
 	struct ide_atapi_pc pc;
-	idetape_tape_t *tape;
-	tape = drive->driver_data;
 
 	debug_log(DBG_SENSE, "Enter %s\n", __func__);
 
 	idetape_create_rewind_cmd(drive, &pc);
-	retval = idetape_queue_pc_tail(drive, &pc);
+	retval = ide_queue_pc_tail(drive, disk, &pc);
 	if (retval)
 		return retval;
 
 	idetape_create_read_position_cmd(&pc);
-	retval = idetape_queue_pc_tail(drive, &pc);
+	retval = ide_queue_pc_tail(drive, disk, &pc);
 	if (retval)
 		return retval;
 	return 0;
@@ -1720,6 +1475,7 @@
 					int mt_count)
 {
 	idetape_tape_t *tape = drive->driver_data;
+	struct gendisk *disk = tape->disk;
 	struct ide_atapi_pc pc;
 	int retval, count = 0;
 	int sprev = !!(tape->caps[4] & 0x20);
@@ -1744,7 +1500,7 @@
 	case MTBSF:
 		idetape_create_space_cmd(&pc, mt_count - count,
 					 IDETAPE_SPACE_OVER_FILEMARK);
-		return idetape_queue_pc_tail(drive, &pc);
+		return ide_queue_pc_tail(drive, disk, &pc);
 	case MTFSFM:
 	case MTBSFM:
 		if (!sprev)
@@ -1780,7 +1536,7 @@
 static ssize_t idetape_chrdev_read(struct file *file, char __user *buf,
 				   size_t count, loff_t *ppos)
 {
-	struct ide_tape_obj *tape = ide_tape_f(file);
+	struct ide_tape_obj *tape = file->private_data;
 	ide_drive_t *drive = tape->drive;
 	ssize_t bytes_read, temp, actually_read = 0, rc;
 	ssize_t ret = 0;
@@ -1842,7 +1598,7 @@
 static ssize_t idetape_chrdev_write(struct file *file, const char __user *buf,
 				     size_t count, loff_t *ppos)
 {
-	struct ide_tape_obj *tape = ide_tape_f(file);
+	struct ide_tape_obj *tape = file->private_data;
 	ide_drive_t *drive = tape->drive;
 	ssize_t actually_written = 0;
 	ssize_t ret = 0;
@@ -1875,7 +1631,7 @@
 		 * point in issuing this if DSC overlap isn't supported, some
 		 * drives (Seagate STT3401A) will return an error.
 		 */
-		if (drive->dsc_overlap) {
+		if (drive->dev_flags & IDE_DFLAG_DSC_OVERLAP) {
 			ssize_t retval = idetape_queue_rw_tail(drive,
 							REQ_IDETAPE_WRITE, 0,
 							tape->merge_bh);
@@ -1933,11 +1689,12 @@
 
 static int idetape_write_filemark(ide_drive_t *drive)
 {
+	struct ide_tape_obj *tape = drive->driver_data;
 	struct ide_atapi_pc pc;
 
 	/* Write a filemark */
 	idetape_create_write_filemark_cmd(drive, &pc, 1);
-	if (idetape_queue_pc_tail(drive, &pc)) {
+	if (ide_queue_pc_tail(drive, tape->disk, &pc)) {
 		printk(KERN_ERR "ide-tape: Couldn't write a filemark\n");
 		return -EIO;
 	}
@@ -1960,6 +1717,7 @@
 static int idetape_mtioctop(ide_drive_t *drive, short mt_op, int mt_count)
 {
 	idetape_tape_t *tape = drive->driver_data;
+	struct gendisk *disk = tape->disk;
 	struct ide_atapi_pc pc;
 	int i, retval;
 
@@ -1996,9 +1754,7 @@
 		return 0;
 	case MTLOAD:
 		ide_tape_discard_merge_buffer(drive, 0);
-		idetape_create_load_unload_cmd(drive, &pc,
-					       IDETAPE_LU_LOAD_MASK);
-		return idetape_queue_pc_tail(drive, &pc);
+		return ide_do_start_stop(drive, disk, IDETAPE_LU_LOAD_MASK);
 	case MTUNLOAD:
 	case MTOFFL:
 		/*
@@ -2006,14 +1762,11 @@
 		 * attempting to eject.
 		 */
 		if (tape->door_locked) {
-			if (idetape_create_prevent_cmd(drive, &pc, 0))
-				if (!idetape_queue_pc_tail(drive, &pc))
-					tape->door_locked = DOOR_UNLOCKED;
+			if (!ide_set_media_lock(drive, disk, 0))
+				tape->door_locked = DOOR_UNLOCKED;
 		}
 		ide_tape_discard_merge_buffer(drive, 0);
-		idetape_create_load_unload_cmd(drive, &pc,
-					      !IDETAPE_LU_LOAD_MASK);
-		retval = idetape_queue_pc_tail(drive, &pc);
+		retval = ide_do_start_stop(drive, disk, !IDETAPE_LU_LOAD_MASK);
 		if (!retval)
 			clear_bit(IDE_AFLAG_MEDIUM_PRESENT, &drive->atapi_flags);
 		return retval;
@@ -2022,16 +1775,15 @@
 		return idetape_flush_tape_buffers(drive);
 	case MTRETEN:
 		ide_tape_discard_merge_buffer(drive, 0);
-		idetape_create_load_unload_cmd(drive, &pc,
+		return ide_do_start_stop(drive, disk,
 			IDETAPE_LU_RETENSION_MASK | IDETAPE_LU_LOAD_MASK);
-		return idetape_queue_pc_tail(drive, &pc);
 	case MTEOM:
 		idetape_create_space_cmd(&pc, 0, IDETAPE_SPACE_TO_EOD);
-		return idetape_queue_pc_tail(drive, &pc);
+		return ide_queue_pc_tail(drive, disk, &pc);
 	case MTERASE:
 		(void)idetape_rewind_tape(drive);
 		idetape_create_erase_cmd(&pc);
-		return idetape_queue_pc_tail(drive, &pc);
+		return ide_queue_pc_tail(drive, disk, &pc);
 	case MTSETBLK:
 		if (mt_count) {
 			if (mt_count < tape->blk_size ||
@@ -2052,17 +1804,13 @@
 	case MTFSR:
 	case MTBSR:
 	case MTLOCK:
-		if (!idetape_create_prevent_cmd(drive, &pc, 1))
-			return 0;
-		retval = idetape_queue_pc_tail(drive, &pc);
+		retval = ide_set_media_lock(drive, disk, 1);
 		if (retval)
 			return retval;
 		tape->door_locked = DOOR_EXPLICITLY_LOCKED;
 		return 0;
 	case MTUNLOCK:
-		if (!idetape_create_prevent_cmd(drive, &pc, 0))
-			return 0;
-		retval = idetape_queue_pc_tail(drive, &pc);
+		retval = ide_set_media_lock(drive, disk, 0);
 		if (retval)
 			return retval;
 		tape->door_locked = DOOR_UNLOCKED;
@@ -2082,7 +1830,7 @@
 static int idetape_chrdev_ioctl(struct inode *inode, struct file *file,
 				unsigned int cmd, unsigned long arg)
 {
-	struct ide_tape_obj *tape = ide_tape_f(file);
+	struct ide_tape_obj *tape = file->private_data;
 	ide_drive_t *drive = tape->drive;
 	struct mtop mtop;
 	struct mtget mtget;
@@ -2144,7 +1892,7 @@
 	struct ide_atapi_pc pc;
 
 	idetape_create_mode_sense_cmd(&pc, IDETAPE_BLOCK_DESCRIPTOR);
-	if (idetape_queue_pc_tail(drive, &pc)) {
+	if (ide_queue_pc_tail(drive, tape->disk, &pc)) {
 		printk(KERN_ERR "ide-tape: Can't get block descriptor\n");
 		if (tape->blk_size == 0) {
 			printk(KERN_WARNING "ide-tape: Cannot deal with zero "
@@ -2164,7 +1912,6 @@
 	unsigned int minor = iminor(inode), i = minor & ~0xc0;
 	ide_drive_t *drive;
 	idetape_tape_t *tape;
-	struct ide_atapi_pc pc;
 	int retval;
 
 	if (i >= MAX_HWIFS * MAX_DRIVES)
@@ -2227,11 +1974,9 @@
 
 	/* Lock the tape drive door so user can't eject. */
 	if (tape->chrdev_dir == IDETAPE_DIR_NONE) {
-		if (idetape_create_prevent_cmd(drive, &pc, 1)) {
-			if (!idetape_queue_pc_tail(drive, &pc)) {
-				if (tape->door_locked != DOOR_EXPLICITLY_LOCKED)
-					tape->door_locked = DOOR_LOCKED;
-			}
+		if (!ide_set_media_lock(drive, tape->disk, 1)) {
+			if (tape->door_locked != DOOR_EXPLICITLY_LOCKED)
+				tape->door_locked = DOOR_LOCKED;
 		}
 	}
 	unlock_kernel();
@@ -2262,9 +2007,8 @@
 
 static int idetape_chrdev_release(struct inode *inode, struct file *filp)
 {
-	struct ide_tape_obj *tape = ide_tape_f(filp);
+	struct ide_tape_obj *tape = filp->private_data;
 	ide_drive_t *drive = tape->drive;
-	struct ide_atapi_pc pc;
 	unsigned int minor = iminor(inode);
 
 	lock_kernel();
@@ -2283,10 +2027,8 @@
 		(void) idetape_rewind_tape(drive);
 	if (tape->chrdev_dir == IDETAPE_DIR_NONE) {
 		if (tape->door_locked == DOOR_LOCKED) {
-			if (idetape_create_prevent_cmd(drive, &pc, 0)) {
-				if (!idetape_queue_pc_tail(drive, &pc))
-					tape->door_locked = DOOR_UNLOCKED;
-			}
+			if (!ide_set_media_lock(drive, tape->disk, 0))
+				tape->door_locked = DOOR_UNLOCKED;
 		}
 	}
 	clear_bit(IDE_AFLAG_BUSY, &drive->atapi_flags);
@@ -2295,53 +2037,14 @@
 	return 0;
 }
 
-/*
- * check the contents of the ATAPI IDENTIFY command results. We return:
- *
- * 1 - If the tape can be supported by us, based on the information we have so
- * far.
- *
- * 0 - If this tape driver is not currently supported by us.
- */
-static int idetape_identify_device(ide_drive_t *drive)
-{
-	u8 gcw[2], protocol, device_type, removable, packet_size;
-
-	if (drive->id_read == 0)
-		return 1;
-
-	*((unsigned short *) &gcw) = drive->id->config;
-
-	protocol	=   (gcw[1] & 0xC0) >> 6;
-	device_type	=    gcw[1] & 0x1F;
-	removable	= !!(gcw[0] & 0x80);
-	packet_size	=    gcw[0] & 0x3;
-
-	/* Check that we can support this device */
-	if (protocol != 2)
-		printk(KERN_ERR "ide-tape: Protocol (0x%02x) is not ATAPI\n",
-				protocol);
-	else if (device_type != 1)
-		printk(KERN_ERR "ide-tape: Device type (0x%02x) is not set "
-				"to tape\n", device_type);
-	else if (!removable)
-		printk(KERN_ERR "ide-tape: The removable flag is not set\n");
-	else if (packet_size != 0) {
-		printk(KERN_ERR "ide-tape: Packet size (0x%02x) is not 12"
-				" bytes\n", packet_size);
-	} else
-		return 1;
-	return 0;
-}
-
 static void idetape_get_inquiry_results(ide_drive_t *drive)
 {
 	idetape_tape_t *tape = drive->driver_data;
 	struct ide_atapi_pc pc;
-	char fw_rev[6], vendor_id[10], product_id[18];
+	char fw_rev[4], vendor_id[8], product_id[16];
 
 	idetape_create_inquiry_cmd(&pc);
-	if (idetape_queue_pc_tail(drive, &pc)) {
+	if (ide_queue_pc_tail(drive, tape->disk, &pc)) {
 		printk(KERN_ERR "ide-tape: %s: can't get INQUIRY results\n",
 				tape->name);
 		return;
@@ -2350,11 +2053,11 @@
 	memcpy(product_id, &pc.buf[16], 16);
 	memcpy(fw_rev, &pc.buf[32], 4);
 
-	ide_fixstring(vendor_id, 10, 0);
-	ide_fixstring(product_id, 18, 0);
-	ide_fixstring(fw_rev, 6, 0);
+	ide_fixstring(vendor_id, 8, 0);
+	ide_fixstring(product_id, 16, 0);
+	ide_fixstring(fw_rev, 4, 0);
 
-	printk(KERN_INFO "ide-tape: %s <-> %s: %s %s rev %s\n",
+	printk(KERN_INFO "ide-tape: %s <-> %s: %.8s %.16s rev %.4s\n",
 			drive->name, tape->name, vendor_id, product_id, fw_rev);
 }
 
@@ -2370,7 +2073,7 @@
 	u8 speed, max_speed;
 
 	idetape_create_mode_sense_cmd(&pc, IDETAPE_CAPABILITIES_PAGE);
-	if (idetape_queue_pc_tail(drive, &pc)) {
+	if (ide_queue_pc_tail(drive, tape->disk, &pc)) {
 		printk(KERN_ERR "ide-tape: Can't get tape parameters - assuming"
 				" some default values\n");
 		tape->blk_size = 512;
@@ -2402,6 +2105,11 @@
 	}
 
 	memcpy(&tape->caps, caps, 20);
+
+	/* device lacks locking support according to capabilities page */
+	if ((caps[6] & 1) == 0)
+		drive->atapi_flags |= IDE_AFLAG_NO_DOORLOCK;
+
 	if (caps[7] & 0x02)
 		tape->blk_size = 512;
 	else if (caps[7] & 0x04)
@@ -2409,28 +2117,56 @@
 }
 
 #ifdef CONFIG_IDE_PROC_FS
-static void idetape_add_settings(ide_drive_t *drive)
-{
-	idetape_tape_t *tape = drive->driver_data;
-
-	ide_add_setting(drive, "buffer", SETTING_READ, TYPE_SHORT, 0, 0xffff,
-			1, 2, (u16 *)&tape->caps[16], NULL);
-	ide_add_setting(drive, "speed", SETTING_READ, TYPE_SHORT, 0, 0xffff,
-			1, 1, (u16 *)&tape->caps[14], NULL);
-	ide_add_setting(drive, "buffer_size", SETTING_READ, TYPE_INT, 0, 0xffff,
-			1, 1024, &tape->buffer_size, NULL);
-	ide_add_setting(drive, "tdsc", SETTING_RW, TYPE_INT, IDETAPE_DSC_RW_MIN,
-			IDETAPE_DSC_RW_MAX, 1000, HZ, &tape->best_dsc_rw_freq,
-			NULL);
-	ide_add_setting(drive, "dsc_overlap", SETTING_RW, TYPE_BYTE, 0, 1, 1,
-			1, &drive->dsc_overlap, NULL);
-	ide_add_setting(drive, "avg_speed", SETTING_READ, TYPE_INT, 0, 0xffff,
-			1, 1, &tape->avg_speed, NULL);
-	ide_add_setting(drive, "debug_mask", SETTING_RW, TYPE_INT, 0, 0xffff, 1,
-			1, &tape->debug_mask, NULL);
+#define ide_tape_devset_get(name, field) \
+static int get_##name(ide_drive_t *drive) \
+{ \
+	idetape_tape_t *tape = drive->driver_data; \
+	return tape->field; \
 }
-#else
-static inline void idetape_add_settings(ide_drive_t *drive) { ; }
+
+#define ide_tape_devset_set(name, field) \
+static int set_##name(ide_drive_t *drive, int arg) \
+{ \
+	idetape_tape_t *tape = drive->driver_data; \
+	tape->field = arg; \
+	return 0; \
+}
+
+#define ide_tape_devset_rw_field(_name, _field) \
+ide_tape_devset_get(_name, _field) \
+ide_tape_devset_set(_name, _field) \
+IDE_DEVSET(_name, DS_SYNC, get_##_name, set_##_name)
+
+#define ide_tape_devset_r_field(_name, _field) \
+ide_tape_devset_get(_name, _field) \
+IDE_DEVSET(_name, 0, get_##_name, NULL)
+
+static int mulf_tdsc(ide_drive_t *drive)	{ return 1000; }
+static int divf_tdsc(ide_drive_t *drive)	{ return   HZ; }
+static int divf_buffer(ide_drive_t *drive)	{ return    2; }
+static int divf_buffer_size(ide_drive_t *drive)	{ return 1024; }
+
+ide_devset_rw_flag(dsc_overlap, IDE_DFLAG_DSC_OVERLAP);
+
+ide_tape_devset_rw_field(debug_mask, debug_mask);
+ide_tape_devset_rw_field(tdsc, best_dsc_rw_freq);
+
+ide_tape_devset_r_field(avg_speed, avg_speed);
+ide_tape_devset_r_field(speed, caps[14]);
+ide_tape_devset_r_field(buffer, caps[16]);
+ide_tape_devset_r_field(buffer_size, buffer_size);
+
+static const struct ide_proc_devset idetape_settings[] = {
+	__IDE_PROC_DEVSET(avg_speed,	0, 0xffff, NULL, NULL),
+	__IDE_PROC_DEVSET(buffer,	0, 0xffff, NULL, divf_buffer),
+	__IDE_PROC_DEVSET(buffer_size,	0, 0xffff, NULL, divf_buffer_size),
+	__IDE_PROC_DEVSET(debug_mask,	0, 0xffff, NULL, NULL),
+	__IDE_PROC_DEVSET(dsc_overlap,	0,      1, NULL, NULL),
+	__IDE_PROC_DEVSET(speed,	0, 0xffff, NULL, NULL),
+	__IDE_PROC_DEVSET(tdsc,		IDETAPE_DSC_RW_MIN, IDETAPE_DSC_RW_MAX,
+					mulf_tdsc, divf_tdsc),
+	{ 0 },
+};
 #endif
 
 /*
@@ -2449,32 +2185,31 @@
 	unsigned long t;
 	int speed;
 	int buffer_size;
-	u8 gcw[2];
 	u16 *ctl = (u16 *)&tape->caps[12];
 
-	drive->pc_callback = ide_tape_callback;
+	drive->pc_callback	 = ide_tape_callback;
+	drive->pc_update_buffers = idetape_update_buffers;
+	drive->pc_io_buffers	 = ide_tape_io_buffers;
 
 	spin_lock_init(&tape->lock);
-	drive->dsc_overlap = 1;
+
+	drive->dev_flags |= IDE_DFLAG_DSC_OVERLAP;
+
 	if (drive->hwif->host_flags & IDE_HFLAG_NO_DSC) {
 		printk(KERN_INFO "ide-tape: %s: disabling DSC overlap\n",
 				 tape->name);
-		drive->dsc_overlap = 0;
+		drive->dev_flags &= ~IDE_DFLAG_DSC_OVERLAP;
 	}
+
 	/* Seagate Travan drives do not support DSC overlap. */
-	if (strstr(drive->id->model, "Seagate STT3401"))
-		drive->dsc_overlap = 0;
+	if (strstr((char *)&drive->id[ATA_ID_PROD], "Seagate STT3401"))
+		drive->dev_flags &= ~IDE_DFLAG_DSC_OVERLAP;
+
 	tape->minor = minor;
 	tape->name[0] = 'h';
 	tape->name[1] = 't';
 	tape->name[2] = '0' + minor;
 	tape->chrdev_dir = IDETAPE_DIR_NONE;
-	tape->pc = tape->pc_stack;
-	*((unsigned short *) &gcw) = drive->id->config;
-
-	/* Command packet DRQ type */
-	if (((gcw[0] & 0x60) >> 5) == 1)
-		set_bit(IDE_AFLAG_DRQ_INTERRUPT, &drive->atapi_flags);
 
 	idetape_get_inquiry_results(drive);
 	idetape_get_mode_sense_results(drive);
@@ -2510,9 +2245,9 @@
 		(*(u16 *)&tape->caps[16] * 512) / tape->buffer_size,
 		tape->buffer_size / 1024,
 		tape->best_dsc_rw_freq * 1000 / HZ,
-		drive->using_dma ? ", DMA":"");
+		(drive->dev_flags & IDE_DFLAG_USING_DMA) ? ", DMA" : "");
 
-	idetape_add_settings(drive);
+	ide_proc_register_driver(drive, tape->driver);
 }
 
 static void ide_tape_remove(ide_drive_t *drive)
@@ -2528,13 +2263,13 @@
 
 static void ide_tape_release(struct kref *kref)
 {
-	struct ide_tape_obj *tape = to_ide_tape(kref);
+	struct ide_tape_obj *tape = to_ide_drv(kref, ide_tape_obj);
 	ide_drive_t *drive = tape->drive;
 	struct gendisk *g = tape->disk;
 
 	BUG_ON(tape->merge_bh_size);
 
-	drive->dsc_overlap = 0;
+	drive->dev_flags &= ~IDE_DFLAG_DSC_OVERLAP;
 	drive->driver_data = NULL;
 	device_destroy(idetape_sysfs_class, MKDEV(IDETAPE_MAJOR, tape->minor));
 	device_destroy(idetape_sysfs_class,
@@ -2576,13 +2311,12 @@
 	.probe			= ide_tape_probe,
 	.remove			= ide_tape_remove,
 	.version		= IDETAPE_VERSION,
-	.media			= ide_tape,
-	.supports_dsc_overlap 	= 1,
 	.do_request		= idetape_do_request,
 	.end_request		= idetape_end_request,
 	.error			= __ide_error,
 #ifdef CONFIG_IDE_PROC_FS
 	.proc			= idetape_proc,
+	.settings		= idetape_settings,
 #endif
 };
 
@@ -2611,7 +2345,7 @@
 static int idetape_release(struct inode *inode, struct file *filp)
 {
 	struct gendisk *disk = inode->i_bdev->bd_disk;
-	struct ide_tape_obj *tape = ide_tape_g(disk);
+	struct ide_tape_obj *tape = ide_drv_g(disk, ide_tape_obj);
 
 	ide_tape_put(tape);
 
@@ -2622,7 +2356,7 @@
 			unsigned int cmd, unsigned long arg)
 {
 	struct block_device *bdev = inode->i_bdev;
-	struct ide_tape_obj *tape = ide_tape_g(bdev->bd_disk);
+	struct ide_tape_obj *tape = ide_drv_g(bdev->bd_disk, ide_tape_obj);
 	ide_drive_t *drive = tape->drive;
 	int err = generic_ide_ioctl(drive, file, bdev, cmd, arg);
 	if (err == -EINVAL)
@@ -2645,11 +2379,12 @@
 
 	if (!strstr("ide-tape", drive->driver_req))
 		goto failed;
-	if (!drive->present)
-		goto failed;
+
 	if (drive->media != ide_tape)
 		goto failed;
-	if (!idetape_identify_device(drive)) {
+
+	if ((drive->dev_flags & IDE_DFLAG_ID_READ) &&
+	    ide_check_atapi_device(drive, DRV_NAME) == 0) {
 		printk(KERN_ERR "ide-tape: %s: not supported by this version of"
 				" the driver\n", drive->name);
 		goto failed;
@@ -2667,8 +2402,6 @@
 
 	ide_init_disk(g, drive);
 
-	ide_proc_register_driver(drive, &idetape_driver);
-
 	kref_init(&tape->kref);
 
 	tape->drive = drive;
diff --git a/drivers/ide/ide-taskfile.c b/drivers/ide/ide-taskfile.c
index 7fb6f1c..bf4fb9d 100644
--- a/drivers/ide/ide-taskfile.c
+++ b/drivers/ide/ide-taskfile.c
@@ -44,18 +44,15 @@
 	memset(&args, 0, sizeof(ide_task_t));
 	args.tf.nsect = 0x01;
 	if (drive->media == ide_disk)
-		args.tf.command = WIN_IDENTIFY;
+		args.tf.command = ATA_CMD_ID_ATA;
 	else
-		args.tf.command = WIN_PIDENTIFY;
+		args.tf.command = ATA_CMD_ID_ATAPI;
 	args.tf_flags	= IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
 	args.data_phase	= TASKFILE_IN;
 	return ide_raw_taskfile(drive, &args, buf, 1);
 }
 
 static ide_startstop_t task_no_data_intr(ide_drive_t *);
-static ide_startstop_t set_geometry_intr(ide_drive_t *);
-static ide_startstop_t recal_intr(ide_drive_t *);
-static ide_startstop_t set_multmode_intr(ide_drive_t *);
 static ide_startstop_t pre_task_out_intr(ide_drive_t *, struct request *);
 static ide_startstop_t task_in_intr(ide_drive_t *);
 
@@ -79,6 +76,8 @@
 	if (task->tf_flags & IDE_TFLAG_FLAGGED)
 		task->tf_flags |= IDE_TFLAG_FLAGGED_SET_IN_FLAGS;
 
+	memcpy(&hwif->task, task, sizeof(*task));
+
 	if ((task->tf_flags & IDE_TFLAG_DMA_PIO_FALLBACK) == 0) {
 		ide_tf_dump(drive->name, tf);
 		tp_ops->set_irq(hwif, 1);
@@ -99,19 +98,12 @@
 	case TASKFILE_NO_DATA:
 		if (handler == NULL)
 			handler = task_no_data_intr;
-		/* WIN_{SPECIFY,RESTORE,SETMULT} use custom handlers */
-		if (task->tf_flags & IDE_TFLAG_CUSTOM_HANDLER) {
-			switch (tf->command) {
-			case WIN_SPECIFY: handler = set_geometry_intr;	break;
-			case WIN_RESTORE: handler = recal_intr;		break;
-			case WIN_SETMULT: handler = set_multmode_intr;	break;
-			}
-		}
 		ide_execute_command(drive, tf->command, handler,
 				    WAIT_WORSTCASE, NULL);
 		return ide_started;
 	default:
-		if (drive->using_dma == 0 || dma_ops->dma_setup(drive))
+		if ((drive->dev_flags & IDE_DFLAG_USING_DMA) == 0 ||
+		    dma_ops->dma_setup(drive))
 			return ide_stopped;
 		dma_ops->dma_exec_cmd(drive, tf->command);
 		dma_ops->dma_start(drive);
@@ -121,88 +113,56 @@
 EXPORT_SYMBOL_GPL(do_rw_taskfile);
 
 /*
- * set_multmode_intr() is invoked on completion of a WIN_SETMULT cmd.
+ * Handler for commands without a data phase
  */
-static ide_startstop_t set_multmode_intr(ide_drive_t *drive)
+static ide_startstop_t task_no_data_intr(ide_drive_t *drive)
 {
 	ide_hwif_t *hwif = drive->hwif;
-	u8 stat;
-
-	local_irq_enable_in_hardirq();
-	stat = hwif->tp_ops->read_status(hwif);
-
-	if (OK_STAT(stat, READY_STAT, BAD_STAT))
-		drive->mult_count = drive->mult_req;
-	else {
-		drive->mult_req = drive->mult_count = 0;
-		drive->special.b.recalibrate = 1;
-		(void) ide_dump_status(drive, "set_multmode", stat);
-	}
-	return ide_stopped;
-}
-
-/*
- * set_geometry_intr() is invoked on completion of a WIN_SPECIFY cmd.
- */
-static ide_startstop_t set_geometry_intr(ide_drive_t *drive)
-{
-	ide_hwif_t *hwif = drive->hwif;
-	int retries = 5;
+	ide_task_t *task = &hwif->task;
+	struct ide_taskfile *tf = &task->tf;
+	int custom = (task->tf_flags & IDE_TFLAG_CUSTOM_HANDLER) ? 1 : 0;
+	int retries = (custom && tf->command == ATA_CMD_INIT_DEV_PARAMS) ? 5 : 1;
 	u8 stat;
 
 	local_irq_enable_in_hardirq();
 
 	while (1) {
 		stat = hwif->tp_ops->read_status(hwif);
-		if ((stat & BUSY_STAT) == 0 || retries-- == 0)
+		if ((stat & ATA_BUSY) == 0 || retries-- == 0)
 			break;
 		udelay(10);
 	};
 
-	if (OK_STAT(stat, READY_STAT, BAD_STAT))
-		return ide_stopped;
-
-	if (stat & (ERR_STAT|DRQ_STAT))
-		return ide_error(drive, "set_geometry_intr", stat);
-
-	ide_set_handler(drive, &set_geometry_intr, WAIT_WORSTCASE, NULL);
-	return ide_started;
-}
-
-/*
- * recal_intr() is invoked on completion of a WIN_RESTORE (recalibrate) cmd.
- */
-static ide_startstop_t recal_intr(ide_drive_t *drive)
-{
-	ide_hwif_t *hwif = drive->hwif;
-	u8 stat;
-
-	local_irq_enable_in_hardirq();
-	stat = hwif->tp_ops->read_status(hwif);
-
-	if (!OK_STAT(stat, READY_STAT, BAD_STAT))
-		return ide_error(drive, "recal_intr", stat);
-	return ide_stopped;
-}
-
-/*
- * Handler for commands without a data phase
- */
-static ide_startstop_t task_no_data_intr(ide_drive_t *drive)
-{
-	ide_hwif_t *hwif = drive->hwif;
-	ide_task_t *args = hwif->hwgroup->rq->special;
-	u8 stat;
-
-	local_irq_enable_in_hardirq();
-	stat = hwif->tp_ops->read_status(hwif);
-
-	if (!OK_STAT(stat, READY_STAT, BAD_STAT))
+	if (!OK_STAT(stat, ATA_DRDY, BAD_STAT)) {
+		if (custom && tf->command == ATA_CMD_SET_MULTI) {
+			drive->mult_req = drive->mult_count = 0;
+			drive->special.b.recalibrate = 1;
+			(void)ide_dump_status(drive, __func__, stat);
+			return ide_stopped;
+		} else if (custom && tf->command == ATA_CMD_INIT_DEV_PARAMS) {
+			if ((stat & (ATA_ERR | ATA_DRQ)) == 0) {
+				ide_set_handler(drive, &task_no_data_intr,
+						WAIT_WORSTCASE, NULL);
+				return ide_started;
+			}
+		}
 		return ide_error(drive, "task_no_data_intr", stat);
 		/* calls ide_end_drive_cmd */
+	}
 
-	if (args)
+	if (!custom)
 		ide_end_drive_cmd(drive, stat, ide_read_error(drive));
+	else if (tf->command == ATA_CMD_IDLEIMMEDIATE) {
+		hwif->tp_ops->tf_read(drive, task);
+		if (tf->lbal != 0xc4) {
+			printk(KERN_ERR "%s: head unload failed!\n",
+			       drive->name);
+			ide_tf_dump(drive->name, tf);
+		} else
+			drive->dev_flags |= IDE_DFLAG_PARKED;
+		ide_end_drive_cmd(drive, stat, ide_read_error(drive));
+	} else if (tf->command == ATA_CMD_SET_MULTI)
+		drive->mult_count = drive->mult_req;
 
 	return ide_stopped;
 }
@@ -220,13 +180,13 @@
 	for (retries = 0; retries < 1000; retries++) {
 		stat = hwif->tp_ops->read_status(hwif);
 
-		if (stat & BUSY_STAT)
+		if (stat & ATA_BUSY)
 			udelay(10);
 		else
 			break;
 	}
 
-	if (stat & BUSY_STAT)
+	if (stat & ATA_BUSY)
 		printk(KERN_ERR "%s: drive still BUSY!\n", drive->name);
 
 	return stat;
@@ -385,7 +345,7 @@
 static ide_startstop_t task_in_unexpected(ide_drive_t *drive, struct request *rq, u8 stat)
 {
 	/* Command all done? */
-	if (OK_STAT(stat, READY_STAT, BUSY_STAT)) {
+	if (OK_STAT(stat, ATA_DRDY, ATA_BUSY)) {
 		task_end_request(drive, rq, stat);
 		return ide_stopped;
 	}
@@ -405,11 +365,11 @@
 	u8 stat = hwif->tp_ops->read_status(hwif);
 
 	/* Error? */
-	if (stat & ERR_STAT)
+	if (stat & ATA_ERR)
 		return task_error(drive, rq, __func__, stat);
 
 	/* Didn't want any data? Odd. */
-	if (!(stat & DRQ_STAT))
+	if ((stat & ATA_DRQ) == 0)
 		return task_in_unexpected(drive, rq, stat);
 
 	ide_pio_datablock(drive, rq, 0);
@@ -442,7 +402,7 @@
 		return task_error(drive, rq, __func__, stat);
 
 	/* Deal with unexpected ATA data phase. */
-	if (((stat & DRQ_STAT) == 0) ^ !hwif->nleft)
+	if (((stat & ATA_DRQ) == 0) ^ !hwif->nleft)
 		return task_error(drive, rq, __func__, stat);
 
 	if (!hwif->nleft) {
@@ -461,16 +421,15 @@
 {
 	ide_startstop_t startstop;
 
-	if (ide_wait_stat(&startstop, drive, DRQ_STAT,
+	if (ide_wait_stat(&startstop, drive, ATA_DRQ,
 			  drive->bad_wstat, WAIT_DRQ)) {
 		printk(KERN_ERR "%s: no DRQ after issuing %sWRITE%s\n",
-				drive->name,
-				drive->hwif->data_phase ? "MULT" : "",
-				drive->addressing ? "_EXT" : "");
+			drive->name, drive->hwif->data_phase ? "MULT" : "",
+			(drive->dev_flags & IDE_DFLAG_LBA48) ? "_EXT" : "");
 		return startstop;
 	}
 
-	if (!drive->unmask)
+	if ((drive->dev_flags & IDE_DFLAG_UNMASK) == 0)
 		local_irq_disable();
 
 	ide_set_handler(drive, &task_out_intr, WAIT_WORSTCASE, NULL);
@@ -586,7 +545,7 @@
 
 	args.tf_flags = IDE_TFLAG_IO_16BIT | IDE_TFLAG_DEVICE |
 			IDE_TFLAG_IN_TF;
-	if (drive->addressing == 1)
+	if (drive->dev_flags & IDE_DFLAG_LBA48)
 		args.tf_flags |= (IDE_TFLAG_LBA48 | IDE_TFLAG_IN_HOB);
 
 	if (req_task->out_flags.all) {
@@ -689,7 +648,7 @@
 	if ((args.tf_flags & IDE_TFLAG_FLAGGED_SET_IN_FLAGS) &&
 	    req_task->in_flags.all == 0) {
 		req_task->in_flags.all = IDE_TASKFILE_STD_IN_FLAGS;
-		if (drive->addressing == 1)
+		if (drive->dev_flags & IDE_DFLAG_LBA48)
 			req_task->in_flags.all |= (IDE_HOB_STD_IN_FLAGS << 8);
 	}
 
@@ -721,110 +680,3 @@
 	return err;
 }
 #endif
-
-int ide_cmd_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg)
-{
-	u8 *buf = NULL;
-	int bufsize = 0, err = 0;
-	u8 args[4], xfer_rate = 0;
-	ide_task_t tfargs;
-	struct ide_taskfile *tf = &tfargs.tf;
-	struct hd_driveid *id = drive->id;
-
-	if (NULL == (void *) arg) {
-		struct request *rq;
-
-		rq = blk_get_request(drive->queue, READ, __GFP_WAIT);
-		rq->cmd_type = REQ_TYPE_ATA_TASKFILE;
-		err = blk_execute_rq(drive->queue, NULL, rq, 0);
-		blk_put_request(rq);
-
-		return err;
-	}
-
-	if (copy_from_user(args, (void __user *)arg, 4))
-		return -EFAULT;
-
-	memset(&tfargs, 0, sizeof(ide_task_t));
-	tf->feature = args[2];
-	if (args[0] == WIN_SMART) {
-		tf->nsect = args[3];
-		tf->lbal  = args[1];
-		tf->lbam  = 0x4f;
-		tf->lbah  = 0xc2;
-		tfargs.tf_flags = IDE_TFLAG_OUT_TF | IDE_TFLAG_IN_NSECT;
-	} else {
-		tf->nsect = args[1];
-		tfargs.tf_flags = IDE_TFLAG_OUT_FEATURE |
-				  IDE_TFLAG_OUT_NSECT | IDE_TFLAG_IN_NSECT;
-	}
-	tf->command = args[0];
-	tfargs.data_phase = args[3] ? TASKFILE_IN : TASKFILE_NO_DATA;
-
-	if (args[3]) {
-		tfargs.tf_flags |= IDE_TFLAG_IO_16BIT;
-		bufsize = SECTOR_WORDS * 4 * args[3];
-		buf = kzalloc(bufsize, GFP_KERNEL);
-		if (buf == NULL)
-			return -ENOMEM;
-	}
-
-	if (tf->command == WIN_SETFEATURES &&
-	    tf->feature == SETFEATURES_XFER &&
-	    tf->nsect >= XFER_SW_DMA_0 &&
-	    (id->dma_ultra || id->dma_mword || id->dma_1word)) {
-		xfer_rate = args[1];
-		if (tf->nsect > XFER_UDMA_2 && !eighty_ninty_three(drive)) {
-			printk(KERN_WARNING "%s: UDMA speeds >UDMA33 cannot "
-					    "be set\n", drive->name);
-			goto abort;
-		}
-	}
-
-	err = ide_raw_taskfile(drive, &tfargs, buf, args[3]);
-
-	args[0] = tf->status;
-	args[1] = tf->error;
-	args[2] = tf->nsect;
-
-	if (!err && xfer_rate) {
-		/* active-retuning-calls future */
-		ide_set_xfer_rate(drive, xfer_rate);
-		ide_driveid_update(drive);
-	}
-abort:
-	if (copy_to_user((void __user *)arg, &args, 4))
-		err = -EFAULT;
-	if (buf) {
-		if (copy_to_user((void __user *)(arg + 4), buf, bufsize))
-			err = -EFAULT;
-		kfree(buf);
-	}
-	return err;
-}
-
-int ide_task_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg)
-{
-	void __user *p = (void __user *)arg;
-	int err = 0;
-	u8 args[7];
-	ide_task_t task;
-
-	if (copy_from_user(args, p, 7))
-		return -EFAULT;
-
-	memset(&task, 0, sizeof(task));
-	memcpy(&task.tf_array[7], &args[1], 6);
-	task.tf.command = args[0];
-	task.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
-
-	err = ide_no_data_taskfile(drive, &task);
-
-	args[0] = task.tf.command;
-	memcpy(&args[1], &task.tf_array[7], 6);
-
-	if (copy_to_user(p, args, 7))
-		err = -EFAULT;
-
-	return err;
-}
diff --git a/drivers/ide/ide-timings.c b/drivers/ide/ide-timings.c
index 8c2f832..81f527a 100644
--- a/drivers/ide/ide-timings.c
+++ b/drivers/ide/ide-timings.c
@@ -22,7 +22,6 @@
  */
 
 #include <linux/kernel.h>
-#include <linux/hdreg.h>
 #include <linux/ide.h>
 #include <linux/module.h>
 
@@ -78,15 +77,15 @@
 
 u16 ide_pio_cycle_time(ide_drive_t *drive, u8 pio)
 {
-	struct hd_driveid *id = drive->id;
+	u16 *id = drive->id;
 	struct ide_timing *t = ide_timing_find_mode(XFER_PIO_0 + pio);
 	u16 cycle = 0;
 
-	if (id->field_valid & 2) {
-		if (id->capability & 8)
-			cycle = id->eide_pio_iordy;
+	if (id[ATA_ID_FIELD_VALID] & 2) {
+		if (ata_id_has_iordy(drive->id))
+			cycle = id[ATA_ID_EIDE_PIO_IORDY];
 		else
-			cycle = id->eide_pio;
+			cycle = id[ATA_ID_EIDE_PIO];
 
 		/* conservative "downgrade" for all pre-ATA2 drives */
 		if (pio < 3 && cycle < t->cycle)
@@ -138,7 +137,7 @@
 int ide_timing_compute(ide_drive_t *drive, u8 speed,
 		       struct ide_timing *t, int T, int UT)
 {
-	struct hd_driveid *id = drive->id;
+	u16 *id = drive->id;
 	struct ide_timing *s, p;
 
 	/*
@@ -157,16 +156,15 @@
 	 * If the drive is an EIDE drive, it can tell us it needs extended
 	 * PIO/MWDMA cycle timing.
 	 */
-	if (id && id->field_valid & 2) {	/* EIDE drive */
-
+	if (id[ATA_ID_FIELD_VALID] & 2) {	/* EIDE drive */
 		memset(&p, 0, sizeof(p));
 
 		if (speed <= XFER_PIO_2)
-			p.cycle = p.cyc8b = id->eide_pio;
+			p.cycle = p.cyc8b = id[ATA_ID_EIDE_PIO];
 		else if (speed <= XFER_PIO_5)
-			p.cycle = p.cyc8b = id->eide_pio_iordy;
+			p.cycle = p.cyc8b = id[ATA_ID_EIDE_PIO_IORDY];
 		else if (speed >= XFER_MW_DMA_0 && speed <= XFER_MW_DMA_2)
-			p.cycle = id->eide_dma_min;
+			p.cycle = id[ATA_ID_EIDE_DMA_MIN];
 
 		ide_timing_merge(&p, t, t, IDE_TIMING_CYCLE | IDE_TIMING_CYC8B);
 	}
diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c
index 7724516..04f8f13 100644
--- a/drivers/ide/ide.c
+++ b/drivers/ide/ide.c
@@ -44,8 +44,6 @@
  *  inspiration from lots of linux users, esp.  hamish@zot.apana.org.au
  */
 
-#define _IDE_C			/* Tell ide.h it's really us */
-
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/string.h>
@@ -58,6 +56,7 @@
 #include <linux/init.h>
 #include <linux/pci.h>
 #include <linux/ide.h>
+#include <linux/hdreg.h>
 #include <linux/completion.h>
 #include <linux/device.h>
 
@@ -97,8 +96,6 @@
 	hwif->name[2]	= 'e';
 	hwif->name[3]	= '0' + index;
 
-	hwif->bus_state	= BUSSTATE_ON;
-
 	init_completion(&hwif->gendev_rel_comp);
 
 	hwif->tp_ops = &default_tp_ops;
@@ -117,9 +114,9 @@
 		memset(drive, 0, sizeof(*drive));
 
 		drive->media			= ide_disk;
-		drive->select.all		= (unit<<4)|0xa0;
+		drive->select			= (unit << 4) | ATA_DEVICE_OBS;
 		drive->hwif			= hwif;
-		drive->ready_stat		= READY_STAT;
+		drive->ready_stat		= ATA_DRDY;
 		drive->bad_wstat		= BAD_W_STAT;
 		drive->special.b.recalibrate	= 1;
 		drive->special.b.set_geometry	= 1;
@@ -141,7 +138,7 @@
 	for (i = 0; i < MAX_DRIVES; i++) {
 		ide_drive_t *drive = &hwif->drives[i];
 
-		if (drive->present) {
+		if (drive->dev_flags & IDE_DFLAG_PRESENT) {
 			spin_unlock_irq(&ide_lock);
 			device_unregister(&drive->gendev);
 			wait_for_completion(&drive->gendev_rel_comp);
@@ -230,8 +227,7 @@
 	kfree(hwif->sg_table);
 	unregister_blkdev(hwif->major, hwif->name);
 
-	if (hwif->dma_base)
-		ide_release_dma_engine(hwif);
+	ide_release_dma_engine(hwif);
 
 	mutex_unlock(&ide_cfg_mtx);
 }
@@ -253,96 +249,52 @@
 
 DEFINE_MUTEX(ide_setting_mtx);
 
-EXPORT_SYMBOL_GPL(ide_setting_mtx);
+ide_devset_get(io_32bit, io_32bit);
 
-/**
- *	ide_spin_wait_hwgroup	-	wait for group
- *	@drive: drive in the group
- *
- *	Wait for an IDE device group to go non busy and then return
- *	holding the ide_lock which guards the hwgroup->busy status
- *	and right to use it.
- */
-
-int ide_spin_wait_hwgroup (ide_drive_t *drive)
+static int set_io_32bit(ide_drive_t *drive, int arg)
 {
-	ide_hwgroup_t *hwgroup = HWGROUP(drive);
-	unsigned long timeout = jiffies + (3 * HZ);
-
-	spin_lock_irq(&ide_lock);
-
-	while (hwgroup->busy) {
-		unsigned long lflags;
-		spin_unlock_irq(&ide_lock);
-		local_irq_set(lflags);
-		if (time_after(jiffies, timeout)) {
-			local_irq_restore(lflags);
-			printk(KERN_ERR "%s: channel busy\n", drive->name);
-			return -EBUSY;
-		}
-		local_irq_restore(lflags);
-		spin_lock_irq(&ide_lock);
-	}
-	return 0;
-}
-
-EXPORT_SYMBOL(ide_spin_wait_hwgroup);
-
-int set_io_32bit(ide_drive_t *drive, int arg)
-{
-	if (drive->no_io_32bit)
+	if (drive->dev_flags & IDE_DFLAG_NO_IO_32BIT)
 		return -EPERM;
 
 	if (arg < 0 || arg > 1 + (SUPPORT_VLB_SYNC << 1))
 		return -EINVAL;
 
-	if (ide_spin_wait_hwgroup(drive))
-		return -EBUSY;
-
 	drive->io_32bit = arg;
 
-	spin_unlock_irq(&ide_lock);
-
 	return 0;
 }
 
+ide_devset_get_flag(ksettings, IDE_DFLAG_KEEP_SETTINGS);
+
 static int set_ksettings(ide_drive_t *drive, int arg)
 {
 	if (arg < 0 || arg > 1)
 		return -EINVAL;
 
-	if (ide_spin_wait_hwgroup(drive))
-		return -EBUSY;
-	drive->keep_settings = arg;
-	spin_unlock_irq(&ide_lock);
+	if (arg)
+		drive->dev_flags |= IDE_DFLAG_KEEP_SETTINGS;
+	else
+		drive->dev_flags &= ~IDE_DFLAG_KEEP_SETTINGS;
 
 	return 0;
 }
 
-int set_using_dma(ide_drive_t *drive, int arg)
+ide_devset_get_flag(using_dma, IDE_DFLAG_USING_DMA);
+
+static int set_using_dma(ide_drive_t *drive, int arg)
 {
 #ifdef CONFIG_BLK_DEV_IDEDMA
-	ide_hwif_t *hwif = drive->hwif;
 	int err = -EPERM;
 
 	if (arg < 0 || arg > 1)
 		return -EINVAL;
 
-	if (!drive->id || !(drive->id->capability & 1))
+	if (ata_id_has_dma(drive->id) == 0)
 		goto out;
 
-	if (hwif->dma_ops == NULL)
+	if (drive->hwif->dma_ops == NULL)
 		goto out;
 
-	err = -EBUSY;
-	if (ide_spin_wait_hwgroup(drive))
-		goto out;
-	/*
-	 * set ->busy flag, unlock and let it ride
-	 */
-	hwif->hwgroup->busy = 1;
-	spin_unlock_irq(&ide_lock);
-
 	err = 0;
 
 	if (arg) {
@@ -351,12 +303,6 @@
 	} else
 		ide_dma_off(drive);
 
-	/*
-	 * lock, clear ->busy flag and unlock before leaving
-	 */
-	spin_lock_irq(&ide_lock);
-	hwif->hwgroup->busy = 0;
-	spin_unlock_irq(&ide_lock);
 out:
 	return err;
 #else
@@ -367,9 +313,32 @@
 #endif
 }
 
-int set_pio_mode(ide_drive_t *drive, int arg)
+/*
+ * handle HDIO_SET_PIO_MODE ioctl abusers here, eventually it will go away
+ */
+static int set_pio_mode_abuse(ide_hwif_t *hwif, u8 req_pio)
 {
-	struct request *rq;
+	switch (req_pio) {
+	case 202:
+	case 201:
+	case 200:
+	case 102:
+	case 101:
+	case 100:
+		return (hwif->host_flags & IDE_HFLAG_ABUSE_DMA_MODES) ? 1 : 0;
+	case 9:
+	case 8:
+		return (hwif->host_flags & IDE_HFLAG_ABUSE_PREFETCH) ? 1 : 0;
+	case 7:
+	case 6:
+		return (hwif->host_flags & IDE_HFLAG_ABUSE_FAST_DEVSEL) ? 1 : 0;
+	default:
+		return 0;
+	}
+}
+
+static int set_pio_mode(ide_drive_t *drive, int arg)
+{
 	ide_hwif_t *hwif = drive->hwif;
 	const struct ide_port_ops *port_ops = hwif->port_ops;
 
@@ -380,48 +349,65 @@
 	    (hwif->host_flags & IDE_HFLAG_NO_SET_MODE))
 		return -ENOSYS;
 
-	if (drive->special.b.set_tune)
-		return -EBUSY;
+	if (set_pio_mode_abuse(drive->hwif, arg)) {
+		if (arg == 8 || arg == 9) {
+			unsigned long flags;
 
-	rq = blk_get_request(drive->queue, READ, __GFP_WAIT);
-	rq->cmd_type = REQ_TYPE_ATA_TASKFILE;
+			/* take lock for IDE_DFLAG_[NO_]UNMASK/[NO_]IO_32BIT */
+			spin_lock_irqsave(&ide_lock, flags);
+			port_ops->set_pio_mode(drive, arg);
+			spin_unlock_irqrestore(&ide_lock, flags);
+		} else
+			port_ops->set_pio_mode(drive, arg);
+	} else {
+		int keep_dma = !!(drive->dev_flags & IDE_DFLAG_USING_DMA);
 
-	drive->tune_req = (u8) arg;
-	drive->special.b.set_tune = 1;
+		ide_set_pio(drive, arg);
 
-	blk_execute_rq(drive->queue, NULL, rq, 0);
-	blk_put_request(rq);
+		if (hwif->host_flags & IDE_HFLAG_SET_PIO_MODE_KEEP_DMA) {
+			if (keep_dma)
+				ide_dma_on(drive);
+		}
+	}
 
 	return 0;
 }
 
+ide_devset_get_flag(unmaskirq, IDE_DFLAG_UNMASK);
+
 static int set_unmaskirq(ide_drive_t *drive, int arg)
 {
-	if (drive->no_unmask)
+	if (drive->dev_flags & IDE_DFLAG_NO_UNMASK)
 		return -EPERM;
 
 	if (arg < 0 || arg > 1)
 		return -EINVAL;
 
-	if (ide_spin_wait_hwgroup(drive))
-		return -EBUSY;
-	drive->unmask = arg;
-	spin_unlock_irq(&ide_lock);
+	if (arg)
+		drive->dev_flags |= IDE_DFLAG_UNMASK;
+	else
+		drive->dev_flags &= ~IDE_DFLAG_UNMASK;
 
 	return 0;
 }
 
+ide_ext_devset_rw_sync(io_32bit, io_32bit);
+ide_ext_devset_rw_sync(keepsettings, ksettings);
+ide_ext_devset_rw_sync(unmaskirq, unmaskirq);
+ide_ext_devset_rw_sync(using_dma, using_dma);
+__IDE_DEVSET(pio_mode, DS_SYNC, NULL, set_pio_mode);
+
 static int generic_ide_suspend(struct device *dev, pm_message_t mesg)
 {
-	ide_drive_t *drive = dev->driver_data;
+	ide_drive_t *drive = dev->driver_data, *pair = ide_get_pair_dev(drive);
 	ide_hwif_t *hwif = HWIF(drive);
 	struct request *rq;
 	struct request_pm_state rqpm;
 	ide_task_t args;
 	int ret;
 
-	/* Call ACPI _GTM only once */
-	if (!(drive->dn % 2))
+	/* call ACPI _GTM only once */
+	if ((drive->dn & 1) == 0 || pair == NULL)
 		ide_acpi_get_timing(hwif);
 
 	memset(&rqpm, 0, sizeof(rqpm));
@@ -430,33 +416,32 @@
 	rq->cmd_type = REQ_TYPE_PM_SUSPEND;
 	rq->special = &args;
 	rq->data = &rqpm;
-	rqpm.pm_step = ide_pm_state_start_suspend;
+	rqpm.pm_step = IDE_PM_START_SUSPEND;
 	if (mesg.event == PM_EVENT_PRETHAW)
 		mesg.event = PM_EVENT_FREEZE;
 	rqpm.pm_state = mesg.event;
 
 	ret = blk_execute_rq(drive->queue, NULL, rq, 0);
 	blk_put_request(rq);
-	/* only call ACPI _PS3 after both drivers are suspended */
-	if (!ret && (((drive->dn % 2) && hwif->drives[0].present
-		 && hwif->drives[1].present)
-		 || !hwif->drives[0].present
-		 || !hwif->drives[1].present))
+
+	/* call ACPI _PS3 only after both devices are suspended */
+	if (ret == 0 && ((drive->dn & 1) || pair == NULL))
 		ide_acpi_set_state(hwif, 0);
+
 	return ret;
 }
 
 static int generic_ide_resume(struct device *dev)
 {
-	ide_drive_t *drive = dev->driver_data;
+	ide_drive_t *drive = dev->driver_data, *pair = ide_get_pair_dev(drive);
 	ide_hwif_t *hwif = HWIF(drive);
 	struct request *rq;
 	struct request_pm_state rqpm;
 	ide_task_t args;
 	int err;
 
-	/* Call ACPI _STM only once */
-	if (!(drive->dn % 2)) {
+	/* call ACPI _PS0 / _STM only once */
+	if ((drive->dn & 1) == 0 || pair == NULL) {
 		ide_acpi_set_state(hwif, 1);
 		ide_acpi_push_timing(hwif);
 	}
@@ -470,7 +455,7 @@
 	rq->cmd_flags |= REQ_PREEMPT;
 	rq->special = &args;
 	rq->data = &rqpm;
-	rqpm.pm_step = ide_pm_state_start_resume;
+	rqpm.pm_step = IDE_PM_START_RESUME;
 	rqpm.pm_state = PM_EVENT_ON;
 
 	err = blk_execute_rq(drive->queue, NULL, rq, 1);
@@ -486,138 +471,6 @@
 	return err;
 }
 
-static int generic_drive_reset(ide_drive_t *drive)
-{
-	struct request *rq;
-	int ret = 0;
-
-	rq = blk_get_request(drive->queue, READ, __GFP_WAIT);
-	rq->cmd_type = REQ_TYPE_SPECIAL;
-	rq->cmd_len = 1;
-	rq->cmd[0] = REQ_DRIVE_RESET;
-	rq->cmd_flags |= REQ_SOFTBARRIER;
-	if (blk_execute_rq(drive->queue, NULL, rq, 1))
-		ret = rq->errors;
-	blk_put_request(rq);
-	return ret;
-}
-
-int generic_ide_ioctl(ide_drive_t *drive, struct file *file, struct block_device *bdev,
-			unsigned int cmd, unsigned long arg)
-{
-	unsigned long flags;
-	ide_driver_t *drv;
-	void __user *p = (void __user *)arg;
-	int err = 0, (*setfunc)(ide_drive_t *, int);
-	u8 *val;
-
-	switch (cmd) {
-	case HDIO_GET_32BIT:	    val = &drive->io_32bit;	 goto read_val;
-	case HDIO_GET_KEEPSETTINGS: val = &drive->keep_settings; goto read_val;
-	case HDIO_GET_UNMASKINTR:   val = &drive->unmask;	 goto read_val;
-	case HDIO_GET_DMA:	    val = &drive->using_dma;	 goto read_val;
-	case HDIO_SET_32BIT:	    setfunc = set_io_32bit;	 goto set_val;
-	case HDIO_SET_KEEPSETTINGS: setfunc = set_ksettings;	 goto set_val;
-	case HDIO_SET_PIO_MODE:	    setfunc = set_pio_mode;	 goto set_val;
-	case HDIO_SET_UNMASKINTR:   setfunc = set_unmaskirq;	 goto set_val;
-	case HDIO_SET_DMA:	    setfunc = set_using_dma;	 goto set_val;
-	}
-
-	switch (cmd) {
-		case HDIO_OBSOLETE_IDENTITY:
-		case HDIO_GET_IDENTITY:
-			if (bdev != bdev->bd_contains)
-				return -EINVAL;
-			if (drive->id_read == 0)
-				return -ENOMSG;
-			if (copy_to_user(p, drive->id, (cmd == HDIO_GET_IDENTITY) ? sizeof(*drive->id) : 142))
-				return -EFAULT;
-			return 0;
-
-		case HDIO_GET_NICE:
-			return put_user(drive->dsc_overlap	<<	IDE_NICE_DSC_OVERLAP	|
-					drive->atapi_overlap	<<	IDE_NICE_ATAPI_OVERLAP	|
-					drive->nice1 << IDE_NICE_1,
-					(long __user *) arg);
-#ifdef CONFIG_IDE_TASK_IOCTL
-		case HDIO_DRIVE_TASKFILE:
-		        if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
-				return -EACCES;
-			switch(drive->media) {
-				case ide_disk:
-					return ide_taskfile_ioctl(drive, cmd, arg);
-				default:
-					return -ENOMSG;
-			}
-#endif /* CONFIG_IDE_TASK_IOCTL */
-
-		case HDIO_DRIVE_CMD:
-			if (!capable(CAP_SYS_RAWIO))
-				return -EACCES;
-			return ide_cmd_ioctl(drive, cmd, arg);
-
-		case HDIO_DRIVE_TASK:
-			if (!capable(CAP_SYS_RAWIO))
-				return -EACCES;
-			return ide_task_ioctl(drive, cmd, arg);
-		case HDIO_SET_NICE:
-			if (!capable(CAP_SYS_ADMIN)) return -EACCES;
-			if (arg != (arg & ((1 << IDE_NICE_DSC_OVERLAP) | (1 << IDE_NICE_1))))
-				return -EPERM;
-			drive->dsc_overlap = (arg >> IDE_NICE_DSC_OVERLAP) & 1;
-			drv = *(ide_driver_t **)bdev->bd_disk->private_data;
-			if (drive->dsc_overlap && !drv->supports_dsc_overlap) {
-				drive->dsc_overlap = 0;
-				return -EPERM;
-			}
-			drive->nice1 = (arg >> IDE_NICE_1) & 1;
-			return 0;
-		case HDIO_DRIVE_RESET:
-			if (!capable(CAP_SYS_ADMIN))
-				return -EACCES;
-
-			return generic_drive_reset(drive);
-
-		case HDIO_GET_BUSSTATE:
-			if (!capable(CAP_SYS_ADMIN))
-				return -EACCES;
-			if (put_user(HWIF(drive)->bus_state, (long __user *)arg))
-				return -EFAULT;
-			return 0;
-
-		case HDIO_SET_BUSSTATE:
-			if (!capable(CAP_SYS_ADMIN))
-				return -EACCES;
-			return -EOPNOTSUPP;
-		default:
-			return -EINVAL;
-	}
-
-read_val:
-	mutex_lock(&ide_setting_mtx);
-	spin_lock_irqsave(&ide_lock, flags);
-	err = *val;
-	spin_unlock_irqrestore(&ide_lock, flags);
-	mutex_unlock(&ide_setting_mtx);
-	return err >= 0 ? put_user(err, (long __user *)arg) : err;
-
-set_val:
-	if (bdev != bdev->bd_contains)
-		err = -EINVAL;
-	else {
-		if (!capable(CAP_SYS_ADMIN))
-			err = -EACCES;
-		else {
-			mutex_lock(&ide_setting_mtx);
-			err = setfunc(drive, arg);
-			mutex_unlock(&ide_setting_mtx);
-		}
-	}
-	return err;
-}
-
-EXPORT_SYMBOL(generic_ide_ioctl);
-
 /**
  * ide_device_get	-	get an additional reference to a ide_drive_t
  * @drive:	device to get a reference to
@@ -710,21 +563,21 @@
 			  char *buf)
 {
 	ide_drive_t *drive = to_ide_device(dev);
-	return sprintf(buf, "%s\n", drive->id->model);
+	return sprintf(buf, "%s\n", (char *)&drive->id[ATA_ID_PROD]);
 }
 
 static ssize_t firmware_show(struct device *dev, struct device_attribute *attr,
 			     char *buf)
 {
 	ide_drive_t *drive = to_ide_device(dev);
-	return sprintf(buf, "%s\n", drive->id->fw_rev);
+	return sprintf(buf, "%s\n", (char *)&drive->id[ATA_ID_FW_REV]);
 }
 
 static ssize_t serial_show(struct device *dev, struct device_attribute *attr,
 			   char *buf)
 {
 	ide_drive_t *drive = to_ide_device(dev);
-	return sprintf(buf, "%s\n", drive->id->serial_no);
+	return sprintf(buf, "%s\n", (char *)&drive->id[ATA_ID_SERNO]);
 }
 
 static struct device_attribute ide_dev_attrs[] = {
@@ -734,6 +587,7 @@
 	__ATTR_RO(model),
 	__ATTR_RO(firmware),
 	__ATTR(serial, 0400, serial_show, NULL),
+	__ATTR(unload_heads, 0644, ide_park_show, ide_park_store),
 	__ATTR_NULL
 };
 
@@ -841,7 +695,7 @@
 static unsigned int ide_nowerr;
 
 module_param_call(nowerr, ide_set_dev_param_mask, NULL, &ide_nowerr, 0);
-MODULE_PARM_DESC(nowerr, "ignore the WRERR_STAT bit for a device");
+MODULE_PARM_DESC(nowerr, "ignore the ATA_DF bit for a device");
 
 static unsigned int ide_cdroms;
 
@@ -888,31 +742,31 @@
 module_param_call(chs, ide_set_disk_chs, NULL, NULL, 0);
 MODULE_PARM_DESC(chs, "force device as a disk (using CHS)");
 
-static void ide_dev_apply_params(ide_drive_t *drive)
+static void ide_dev_apply_params(ide_drive_t *drive, u8 unit)
 {
-	int i = drive->hwif->index * MAX_DRIVES + drive->select.b.unit;
+	int i = drive->hwif->index * MAX_DRIVES + unit;
 
 	if (ide_nodma & (1 << i)) {
 		printk(KERN_INFO "ide: disallowing DMA for %s\n", drive->name);
-		drive->nodma = 1;
+		drive->dev_flags |= IDE_DFLAG_NODMA;
 	}
 	if (ide_noflush & (1 << i)) {
 		printk(KERN_INFO "ide: disabling flush requests for %s\n",
 				 drive->name);
-		drive->noflush = 1;
+		drive->dev_flags |= IDE_DFLAG_NOFLUSH;
 	}
 	if (ide_noprobe & (1 << i)) {
 		printk(KERN_INFO "ide: skipping probe for %s\n", drive->name);
-		drive->noprobe = 1;
+		drive->dev_flags |= IDE_DFLAG_NOPROBE;
 	}
 	if (ide_nowerr & (1 << i)) {
-		printk(KERN_INFO "ide: ignoring the WRERR_STAT bit for %s\n",
+		printk(KERN_INFO "ide: ignoring the ATA_DF bit for %s\n",
 				 drive->name);
 		drive->bad_wstat = BAD_R_STAT;
 	}
 	if (ide_cdroms & (1 << i)) {
 		printk(KERN_INFO "ide: forcing %s as a CD-ROM\n", drive->name);
-		drive->present = 1;
+		drive->dev_flags |= IDE_DFLAG_PRESENT;
 		drive->media = ide_cdrom;
 		/* an ATAPI device ignores DRDY */
 		drive->ready_stat = 0;
@@ -921,13 +775,14 @@
 		drive->cyl  = drive->bios_cyl  = ide_disks_chs[i].cyl;
 		drive->head = drive->bios_head = ide_disks_chs[i].head;
 		drive->sect = drive->bios_sect = ide_disks_chs[i].sect;
-		drive->forced_geom = 1;
+
 		printk(KERN_INFO "ide: forcing %s as a disk (%d/%d/%d)\n",
 				 drive->name,
 				 drive->cyl, drive->head, drive->sect);
-		drive->present = 1;
+
+		drive->dev_flags |= IDE_DFLAG_FORCED_GEOM | IDE_DFLAG_PRESENT;
 		drive->media = ide_disk;
-		drive->ready_stat = READY_STAT;
+		drive->ready_stat = ATA_DRDY;
 	}
 }
 
@@ -965,7 +820,7 @@
 	}
 
 	for (i = 0; i < MAX_DRIVES; i++)
-		ide_dev_apply_params(&hwif->drives[i]);
+		ide_dev_apply_params(&hwif->drives[i], i);
 }
 
 /*
diff --git a/drivers/ide/legacy/ali14xx.c b/drivers/ide/legacy/ali14xx.c
index 4ec1973..90da1f9 100644
--- a/drivers/ide/legacy/ali14xx.c
+++ b/drivers/ide/legacy/ali14xx.c
@@ -43,7 +43,6 @@
 #include <linux/mm.h>
 #include <linux/ioport.h>
 #include <linux/blkdev.h>
-#include <linux/hdreg.h>
 #include <linux/ide.h>
 #include <linux/init.h>
 
@@ -132,7 +131,7 @@
 		drive->name, pio, time1, time2, param1, param2, param3, param4);
 
 	/* stuff timing parameters into controller registers */
-	driveNum = (HWIF(drive)->index << 1) + drive->select.b.unit;
+	driveNum = (drive->hwif->index << 1) + (drive->dn & 1);
 	spin_lock_irqsave(&ali14xx_lock, flags);
 	outb_p(regOn, basePort);
 	outReg(param1, regTab[driveNum].reg1);
diff --git a/drivers/ide/legacy/buddha.c b/drivers/ide/legacy/buddha.c
index 7c2afa9..c5a3c9e 100644
--- a/drivers/ide/legacy/buddha.c
+++ b/drivers/ide/legacy/buddha.c
@@ -20,7 +20,6 @@
 #include <linux/mm.h>
 #include <linux/interrupt.h>
 #include <linux/blkdev.h>
-#include <linux/hdreg.h>
 #include <linux/zorro.h>
 #include <linux/ide.h>
 #include <linux/init.h>
diff --git a/drivers/ide/legacy/dtc2278.c b/drivers/ide/legacy/dtc2278.c
index af791a0..689b2e4 100644
--- a/drivers/ide/legacy/dtc2278.c
+++ b/drivers/ide/legacy/dtc2278.c
@@ -10,7 +10,6 @@
 #include <linux/mm.h>
 #include <linux/ioport.h>
 #include <linux/blkdev.h>
-#include <linux/hdreg.h>
 #include <linux/ide.h>
 #include <linux/init.h>
 
diff --git a/drivers/ide/legacy/falconide.c b/drivers/ide/legacy/falconide.c
index 724f950..39d500d 100644
--- a/drivers/ide/legacy/falconide.c
+++ b/drivers/ide/legacy/falconide.c
@@ -13,7 +13,6 @@
 #include <linux/mm.h>
 #include <linux/interrupt.h>
 #include <linux/blkdev.h>
-#include <linux/hdreg.h>
 #include <linux/ide.h>
 #include <linux/init.h>
 
diff --git a/drivers/ide/legacy/gayle.c b/drivers/ide/legacy/gayle.c
index 51ba085..6915068 100644
--- a/drivers/ide/legacy/gayle.c
+++ b/drivers/ide/legacy/gayle.c
@@ -12,7 +12,6 @@
 #include <linux/mm.h>
 #include <linux/interrupt.h>
 #include <linux/blkdev.h>
-#include <linux/hdreg.h>
 #include <linux/ide.h>
 #include <linux/init.h>
 #include <linux/zorro.h>
diff --git a/drivers/ide/legacy/ht6560b.c b/drivers/ide/legacy/ht6560b.c
index 98f7c95e..c7e5c22 100644
--- a/drivers/ide/legacy/ht6560b.c
+++ b/drivers/ide/legacy/ht6560b.c
@@ -24,7 +24,6 @@
 #include <linux/mm.h>
 #include <linux/ioport.h>
 #include <linux/blkdev.h>
-#include <linux/hdreg.h>
 #include <linux/ide.h>
 #include <linux/init.h>
 
@@ -121,7 +120,8 @@
 	 * Need to enforce prefetch sometimes because otherwise
 	 * it'll hang (hard).
 	 */
-	if (drive->media != ide_disk || !drive->present)
+	if (drive->media != ide_disk ||
+	    (drive->dev_flags & IDE_DFLAG_PRESENT) == 0)
 		select |= HT_PREFETCH_MODE;
 
 	if (select != current_select || timing != current_timing) {
@@ -250,11 +250,11 @@
 	 */
 	if (state) {
 		drive->drive_data |= t;   /* enable prefetch mode */
-		drive->no_unmask = 1;
-		drive->unmask = 0;
+		drive->dev_flags |= IDE_DFLAG_NO_UNMASK;
+		drive->dev_flags &= ~IDE_DFLAG_UNMASK;
 	} else {
 		drive->drive_data &= ~t;  /* disable prefetch mode */
-		drive->no_unmask = 0;
+		drive->dev_flags &= ~IDE_DFLAG_NO_UNMASK;
 	}
 
 	spin_unlock_irqrestore(&ht6560b_lock, flags);
diff --git a/drivers/ide/legacy/ide-4drives.c b/drivers/ide/legacy/ide-4drives.c
index c76d55d..9e85b1e 100644
--- a/drivers/ide/legacy/ide-4drives.c
+++ b/drivers/ide/legacy/ide-4drives.c
@@ -14,7 +14,7 @@
 static void ide_4drives_init_dev(ide_drive_t *drive)
 {
 	if (drive->hwif->channel)
-		drive->select.all ^= 0x20;
+		drive->select ^= 0x20;
 }
 
 static const struct ide_port_ops ide_4drives_port_ops = {
diff --git a/drivers/ide/legacy/ide-cs.c b/drivers/ide/legacy/ide-cs.c
index 21bfac1..cb199c8 100644
--- a/drivers/ide/legacy/ide-cs.c
+++ b/drivers/ide/legacy/ide-cs.c
@@ -38,7 +38,6 @@
 #include <linux/timer.h>
 #include <linux/ioport.h>
 #include <linux/ide.h>
-#include <linux/hdreg.h>
 #include <linux/major.h>
 #include <linux/delay.h>
 #include <asm/io.h>
@@ -220,103 +219,91 @@
 #define CS_CHECK(fn, ret) \
 do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)
 
+struct pcmcia_config_check {
+	unsigned long ctl_base;
+	int skip_vcc;
+	int is_kme;
+};
+
+static int pcmcia_check_one_config(struct pcmcia_device *pdev,
+				   cistpl_cftable_entry_t *cfg,
+				   cistpl_cftable_entry_t *dflt,
+				   unsigned int vcc,
+				   void *priv_data)
+{
+	struct pcmcia_config_check *stk = priv_data;
+
+	/* Check for matching Vcc, unless we're desperate */
+	if (!stk->skip_vcc) {
+		if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) {
+			if (vcc != cfg->vcc.param[CISTPL_POWER_VNOM] / 10000)
+				return -ENODEV;
+		} else if (dflt->vcc.present & (1 << CISTPL_POWER_VNOM)) {
+			if (vcc != dflt->vcc.param[CISTPL_POWER_VNOM] / 10000)
+				return -ENODEV;
+		}
+	}
+
+	if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM))
+		pdev->conf.Vpp = cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000;
+	else if (dflt->vpp1.present & (1 << CISTPL_POWER_VNOM))
+		pdev->conf.Vpp = dflt->vpp1.param[CISTPL_POWER_VNOM] / 10000;
+
+	if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) {
+		cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io;
+		pdev->conf.ConfigIndex = cfg->index;
+		pdev->io.BasePort1 = io->win[0].base;
+		pdev->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK;
+		if (!(io->flags & CISTPL_IO_16BIT))
+			pdev->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
+		if (io->nwin == 2) {
+			pdev->io.NumPorts1 = 8;
+			pdev->io.BasePort2 = io->win[1].base;
+			pdev->io.NumPorts2 = (stk->is_kme) ? 2 : 1;
+			if (pcmcia_request_io(pdev, &pdev->io) != 0)
+				return -ENODEV;
+			stk->ctl_base = pdev->io.BasePort2;
+		} else if ((io->nwin == 1) && (io->win[0].len >= 16)) {
+			pdev->io.NumPorts1 = io->win[0].len;
+			pdev->io.NumPorts2 = 0;
+			if (pcmcia_request_io(pdev, &pdev->io) != 0)
+				return -ENODEV;
+			stk->ctl_base = pdev->io.BasePort1 + 0x0e;
+		} else
+			return -ENODEV;
+		/* If we've got this far, we're done */
+		return 0;
+	}
+	return -ENODEV;
+}
+
 static int ide_config(struct pcmcia_device *link)
 {
     ide_info_t *info = link->priv;
-    tuple_t tuple;
-    struct {
-	u_short		buf[128];
-	cisparse_t	parse;
-	config_info_t	conf;
-	cistpl_cftable_entry_t dflt;
-    } *stk = NULL;
-    cistpl_cftable_entry_t *cfg;
-    int pass, last_ret = 0, last_fn = 0, is_kme = 0;
+    struct pcmcia_config_check *stk = NULL;
+    int last_ret = 0, last_fn = 0, is_kme = 0;
     unsigned long io_base, ctl_base;
     struct ide_host *host;
 
     DEBUG(0, "ide_config(0x%p)\n", link);
 
-    stk = kzalloc(sizeof(*stk), GFP_KERNEL);
-    if (!stk) goto err_mem;
-    cfg = &stk->parse.cftable_entry;
-
-    tuple.TupleData = (cisdata_t *)&stk->buf;
-    tuple.TupleOffset = 0;
-    tuple.TupleDataMax = 255;
-    tuple.Attributes = 0;
-
     is_kme = ((link->manf_id == MANFID_KME) &&
 	      ((link->card_id == PRODID_KME_KXLC005_A) ||
 	       (link->card_id == PRODID_KME_KXLC005_B)));
 
-    /* Not sure if this is right... look up the current Vcc */
-    CS_CHECK(GetConfigurationInfo, pcmcia_get_configuration_info(link, &stk->conf));
+    stk = kzalloc(sizeof(*stk), GFP_KERNEL);
+    if (!stk)
+	    goto err_mem;
+    stk->is_kme = is_kme;
+    stk->skip_vcc = io_base = ctl_base = 0;
 
-    pass = io_base = ctl_base = 0;
-    tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
-    tuple.Attributes = 0;
-    CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple));
-    while (1) {
-    	if (pcmcia_get_tuple_data(link, &tuple) != 0) goto next_entry;
-	if (pcmcia_parse_tuple(link, &tuple, &stk->parse) != 0) goto next_entry;
-
-	/* Check for matching Vcc, unless we're desperate */
-	if (!pass) {
-	    if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) {
-		if (stk->conf.Vcc != cfg->vcc.param[CISTPL_POWER_VNOM] / 10000)
-		    goto next_entry;
-	    } else if (stk->dflt.vcc.present & (1 << CISTPL_POWER_VNOM)) {
-		if (stk->conf.Vcc != stk->dflt.vcc.param[CISTPL_POWER_VNOM] / 10000)
-		    goto next_entry;
-	    }
-	}
-
-	if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM))
-	    link->conf.Vpp =
-		cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000;
-	else if (stk->dflt.vpp1.present & (1 << CISTPL_POWER_VNOM))
-	    link->conf.Vpp =
-		stk->dflt.vpp1.param[CISTPL_POWER_VNOM] / 10000;
-
-	if ((cfg->io.nwin > 0) || (stk->dflt.io.nwin > 0)) {
-	    cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &stk->dflt.io;
-	    link->conf.ConfigIndex = cfg->index;
-	    link->io.BasePort1 = io->win[0].base;
-	    link->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK;
-	    if (!(io->flags & CISTPL_IO_16BIT))
-		link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
-	    if (io->nwin == 2) {
-		link->io.NumPorts1 = 8;
-		link->io.BasePort2 = io->win[1].base;
-		link->io.NumPorts2 = (is_kme) ? 2 : 1;
-		if (pcmcia_request_io(link, &link->io) != 0)
-			goto next_entry;
-		io_base = link->io.BasePort1;
-		ctl_base = link->io.BasePort2;
-	    } else if ((io->nwin == 1) && (io->win[0].len >= 16)) {
-		link->io.NumPorts1 = io->win[0].len;
-		link->io.NumPorts2 = 0;
-		if (pcmcia_request_io(link, &link->io) != 0)
-			goto next_entry;
-		io_base = link->io.BasePort1;
-		ctl_base = link->io.BasePort1 + 0x0e;
-	    } else goto next_entry;
-	    /* If we've got this far, we're done */
-	    break;
-	}
-
-    next_entry:
-	if (cfg->flags & CISTPL_CFTABLE_DEFAULT)
-	    memcpy(&stk->dflt, cfg, sizeof(stk->dflt));
-	if (pass) {
-	    CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(link, &tuple));
-	} else if (pcmcia_get_next_tuple(link, &tuple) != 0) {
-	    CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple));
-	    memset(&stk->dflt, 0, sizeof(stk->dflt));
-	    pass++;
-	}
+    if (pcmcia_loop_config(link, pcmcia_check_one_config, stk)) {
+	    stk->skip_vcc = 1;
+	    if (pcmcia_loop_config(link, pcmcia_check_one_config, stk))
+		    goto failed; /* No suitable config found */
     }
+    io_base = link->io.BasePort1;
+    ctl_base = stk->ctl_base;
 
     CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq));
     CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf));
@@ -404,8 +391,10 @@
 	PCMCIA_DEVICE_MANF_CARD(0x000a, 0x0000),	/* I-O Data CFA */
 	PCMCIA_DEVICE_MANF_CARD(0x001c, 0x0001),	/* Mitsubishi CFA */
 	PCMCIA_DEVICE_MANF_CARD(0x0032, 0x0704),
+	PCMCIA_DEVICE_MANF_CARD(0x0032, 0x2904),
 	PCMCIA_DEVICE_MANF_CARD(0x0045, 0x0401),	/* SanDisk CFA */
 	PCMCIA_DEVICE_MANF_CARD(0x004f, 0x0000),	/* Kingston */
+	PCMCIA_DEVICE_MANF_CARD(0x0097, 0x1620), 	/* TI emulated */
 	PCMCIA_DEVICE_MANF_CARD(0x0098, 0x0000),	/* Toshiba */
 	PCMCIA_DEVICE_MANF_CARD(0x00a4, 0x002d),
 	PCMCIA_DEVICE_MANF_CARD(0x00ce, 0x0000),	/* Samsung */
diff --git a/drivers/ide/legacy/macide.c b/drivers/ide/legacy/macide.c
index a0bb167..43f97cc 100644
--- a/drivers/ide/legacy/macide.c
+++ b/drivers/ide/legacy/macide.c
@@ -15,7 +15,6 @@
 #include <linux/mm.h>
 #include <linux/interrupt.h>
 #include <linux/blkdev.h>
-#include <linux/hdreg.h>
 #include <linux/delay.h>
 #include <linux/ide.h>
 
diff --git a/drivers/ide/legacy/q40ide.c b/drivers/ide/legacy/q40ide.c
index 4abd8fc..4af4a8c 100644
--- a/drivers/ide/legacy/q40ide.c
+++ b/drivers/ide/legacy/q40ide.c
@@ -14,8 +14,6 @@
 #include <linux/mm.h>
 #include <linux/interrupt.h>
 #include <linux/blkdev.h>
-#include <linux/hdreg.h>
-
 #include <linux/ide.h>
 
     /*
diff --git a/drivers/ide/legacy/qd65xx.c b/drivers/ide/legacy/qd65xx.c
index 2338f34..bc27c7a 100644
--- a/drivers/ide/legacy/qd65xx.c
+++ b/drivers/ide/legacy/qd65xx.c
@@ -27,7 +27,6 @@
 #include <linux/mm.h>
 #include <linux/ioport.h>
 #include <linux/blkdev.h>
-#include <linux/hdreg.h>
 #include <linux/ide.h>
 #include <linux/init.h>
 #include <asm/system.h>
@@ -151,12 +150,14 @@
 		int *active_time, int *recovery_time)
 {
 	struct qd65xx_timing_s *p;
-	char model[40];
+	char *m = (char *)&drive->id[ATA_ID_PROD];
+	char model[ATA_ID_PROD_LEN];
 
-	if (!*drive->id->model) return 0;
+	if (*m == 0)
+		return 0;
 
-	strncpy(model,drive->id->model,40);
-	ide_fixstring(model,40,1); /* byte-swap */
+	strncpy(model, m, ATA_ID_PROD_LEN);
+	ide_fixstring(model, ATA_ID_PROD_LEN, 1); /* byte-swap */
 
 	for (p = qd65xx_timing ; p->offset != -1 ; p++) {
 		if (!strncmp(p->model, model+p->offset, 4)) {
@@ -185,20 +186,20 @@
 
 static void qd6500_set_pio_mode(ide_drive_t *drive, const u8 pio)
 {
+	u16 *id = drive->id;
 	int active_time   = 175;
 	int recovery_time = 415; /* worst case values from the dos driver */
 
 	/*
 	 * FIXME: use "pio" value
 	 */
-	if (drive->id && !qd_find_disk_type(drive, &active_time, &recovery_time)
-		&& drive->id->tPIO && (drive->id->field_valid & 0x02)
-		&& drive->id->eide_pio >= 240) {
-
+	if (!qd_find_disk_type(drive, &active_time, &recovery_time) &&
+	    (id[ATA_ID_OLD_PIO_MODES] & 0xff) && (id[ATA_ID_FIELD_VALID] & 2) &&
+	    id[ATA_ID_EIDE_PIO] >= 240) {
 		printk(KERN_INFO "%s: PIO mode%d\n", drive->name,
-				drive->id->tPIO);
+			id[ATA_ID_OLD_PIO_MODES] & 0xff);
 		active_time = 110;
-		recovery_time = drive->id->eide_pio - 120;
+		recovery_time = drive->id[ATA_ID_EIDE_PIO] - 120;
 	}
 
 	qd_set_timing(drive, qd6500_compute_timing(HWIF(drive), active_time, recovery_time));
@@ -304,7 +305,7 @@
 	} else
 		t2 = t1 = hwif->channel ? QD6580_DEF_DATA2 : QD6580_DEF_DATA;
 
-	drive->drive_data = drive->select.b.unit ? t2 : t1;
+	drive->drive_data = (drive->dn & 1) ? t2 : t1;
 }
 
 static const struct ide_port_ops qd6500_port_ops = {
diff --git a/drivers/ide/legacy/umc8672.c b/drivers/ide/legacy/umc8672.c
index b54a14a..1da076e 100644
--- a/drivers/ide/legacy/umc8672.c
+++ b/drivers/ide/legacy/umc8672.c
@@ -45,7 +45,6 @@
 #include <linux/mm.h>
 #include <linux/ioport.h>
 #include <linux/blkdev.h>
-#include <linux/hdreg.h>
 #include <linux/ide.h>
 #include <linux/init.h>
 
diff --git a/drivers/ide/mips/Makefile b/drivers/ide/mips/Makefile
index 677c7b2..5873fa0 100644
--- a/drivers/ide/mips/Makefile
+++ b/drivers/ide/mips/Makefile
@@ -1,4 +1,3 @@
-obj-$(CONFIG_BLK_DEV_IDE_SWARM)		+= swarm.o
 obj-$(CONFIG_BLK_DEV_IDE_AU1XXX)	+= au1xxx-ide.o
 
 EXTRA_CFLAGS    := -Idrivers/ide
diff --git a/drivers/ide/mips/au1xxx-ide.c b/drivers/ide/mips/au1xxx-ide.c
index 11b7f61..0ec8fd1 100644
--- a/drivers/ide/mips/au1xxx-ide.c
+++ b/drivers/ide/mips/au1xxx-ide.c
@@ -322,11 +322,7 @@
 }
 
 static int auide_dma_test_irq(ide_drive_t *drive)
-{	
-	if (drive->waiting_for_dma == 0)
-		printk(KERN_WARNING "%s: ide_dma_test_irq \
-                                     called while not waiting\n", drive->name);
-
+{
 	/* If dbdma didn't execute the STOP command yet, the
 	 * active bit is still set
 	 */
@@ -344,11 +340,6 @@
 {
 }
 
-static void auide_dma_lost_irq(ide_drive_t *drive)
-{
-	printk(KERN_ERR "%s: IRQ lost\n", drive->name);
-}
-
 static void auide_ddma_tx_callback(int irq, void *param)
 {
 	_auide_hwif *ahwif = (_auide_hwif*)param;
@@ -375,18 +366,6 @@
 }
 
 #ifdef CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA
-static void auide_dma_timeout(ide_drive_t *drive)
-{
-	ide_hwif_t *hwif = HWIF(drive);
-
-	printk(KERN_ERR "%s: DMA timeout occurred: ", drive->name);
-
-	if (auide_dma_test_irq(drive))
-		return;
-
-	auide_dma_end(drive);
-}
-
 static const struct ide_dma_ops au1xxx_dma_ops = {
 	.dma_host_set		= auide_dma_host_set,
 	.dma_setup		= auide_dma_setup,
@@ -394,8 +373,8 @@
 	.dma_start		= auide_dma_start,
 	.dma_end		= auide_dma_end,
 	.dma_test_irq		= auide_dma_test_irq,
-	.dma_lost_irq		= auide_dma_lost_irq,
-	.dma_timeout		= auide_dma_timeout,
+	.dma_lost_irq		= ide_dma_lost_irq,
+	.dma_timeout		= ide_dma_timeout,
 };
 
 static int auide_ddma_init(ide_hwif_t *hwif, const struct ide_port_info *d)
@@ -448,10 +427,9 @@
 							     NUM_DESCRIPTORS);
 	auide->rx_desc_head = (void*)au1xxx_dbdma_ring_alloc(auide->rx_chan,
 							     NUM_DESCRIPTORS);
- 
-	hwif->dmatable_cpu = dma_alloc_coherent(hwif->dev,
-						PRD_ENTRIES * PRD_BYTES,        /* 1 Page */
-						&hwif->dmatable_dma, GFP_KERNEL);
+
+	/* FIXME: check return value */
+	(void)ide_allocate_dma_engine(hwif);
 	
 	au1xxx_dbdma_start( auide->tx_chan );
 	au1xxx_dbdma_start( auide->rx_chan );
diff --git a/drivers/ide/mips/swarm.c b/drivers/ide/mips/swarm.c
deleted file mode 100644
index badf79f..0000000
--- a/drivers/ide/mips/swarm.c
+++ /dev/null
@@ -1,196 +0,0 @@
-/*
- * Copyright (C) 2001, 2002, 2003 Broadcom Corporation
- * Copyright (C) 2004 MontaVista Software Inc.
- *	Author:	Manish Lachwani, mlachwani@mvista.com
- * Copyright (C) 2004  MIPS Technologies, Inc.  All rights reserved.
- *	Author: Maciej W. Rozycki <macro@mips.com>
- * Copyright (c) 2006, 2008  Maciej W. Rozycki
- *
- * This program is free software; you can redistribute it and/or
- * 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.
- */
-
-/*
- *  Derived loosely from ide-pmac.c, so:
- *  Copyright (C) 1998 Paul Mackerras.
- *  Copyright (C) 1995-1998 Mark Lord
- */
-
-/*
- * Boards with SiByte processors so far have supported IDE devices via
- * the Generic Bus, PCI bus, and built-in PCMCIA interface.  In all
- * cases, byte-swapping must be avoided for these devices (whereas
- * other PCI devices, for example, will require swapping).  Any
- * SiByte-targetted kernel including IDE support will include this
- * file.  Probing of a Generic Bus for an IDE device is controlled by
- * the definition of "SIBYTE_HAVE_IDE", which is provided by
- * <asm/sibyte/board.h> for Broadcom boards.
- */
-
-#include <linux/ide.h>
-#include <linux/ioport.h>
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/platform_device.h>
-
-#include <asm/io.h>
-
-#include <asm/sibyte/board.h>
-#include <asm/sibyte/sb1250_genbus.h>
-#include <asm/sibyte/sb1250_regs.h>
-
-#define DRV_NAME "ide-swarm"
-
-static char swarm_ide_string[] = DRV_NAME;
-
-static struct resource swarm_ide_resource = {
-	.name	= "SWARM GenBus IDE",
-	.flags	= IORESOURCE_MEM,
-};
-
-static struct platform_device *swarm_ide_dev;
-
-static const struct ide_port_info swarm_port_info = {
-	.name			= DRV_NAME,
-	.host_flags		= IDE_HFLAG_MMIO | IDE_HFLAG_NO_DMA,
-};
-
-/*
- * swarm_ide_probe - if the board header indicates the existence of
- * Generic Bus IDE, allocate a HWIF for it.
- */
-static int __devinit swarm_ide_probe(struct device *dev)
-{
-	u8 __iomem *base;
-	struct ide_host *host;
-	phys_t offset, size;
-	int i, rc;
-	hw_regs_t hw, *hws[] = { &hw, NULL, NULL, NULL };
-
-	if (!SIBYTE_HAVE_IDE)
-		return -ENODEV;
-
-	base = ioremap(A_IO_EXT_BASE, 0x800);
-	offset = __raw_readq(base + R_IO_EXT_REG(R_IO_EXT_START_ADDR, IDE_CS));
-	size = __raw_readq(base + R_IO_EXT_REG(R_IO_EXT_MULT_SIZE, IDE_CS));
-	iounmap(base);
-
-	offset = G_IO_START_ADDR(offset) << S_IO_ADDRBASE;
-	size = (G_IO_MULT_SIZE(size) + 1) << S_IO_REGSIZE;
-	if (offset < A_PHYS_GENBUS || offset >= A_PHYS_GENBUS_END) {
-		printk(KERN_INFO DRV_NAME
-		       ": IDE interface at GenBus disabled\n");
-		return -EBUSY;
-	}
-
-	printk(KERN_INFO DRV_NAME ": IDE interface at GenBus slot %i\n",
-	       IDE_CS);
-
-	swarm_ide_resource.start = offset;
-	swarm_ide_resource.end = offset + size - 1;
-	if (request_resource(&iomem_resource, &swarm_ide_resource)) {
-		printk(KERN_ERR DRV_NAME
-		       ": can't request I/O memory resource\n");
-		return -EBUSY;
-	}
-
-	base = ioremap(offset, size);
-
-	for (i = 0; i <= 7; i++)
-		hw.io_ports_array[i] =
-				(unsigned long)(base + ((0x1f0 + i) << 5));
-	hw.io_ports.ctl_addr =
-				(unsigned long)(base + (0x3f6 << 5));
-	hw.irq = K_INT_GB_IDE;
-	hw.chipset = ide_generic;
-
-	rc = ide_host_add(&swarm_port_info, hws, &host);
-	if (rc)
-		goto err;
-
-	dev_set_drvdata(dev, host);
-
-	return 0;
-err:
-	release_resource(&swarm_ide_resource);
-	iounmap(base);
-	return rc;
-}
-
-static struct device_driver swarm_ide_driver = {
-	.name	= swarm_ide_string,
-	.bus	= &platform_bus_type,
-	.probe	= swarm_ide_probe,
-};
-
-static void swarm_ide_platform_release(struct device *device)
-{
-	struct platform_device *pldev;
-
-	/* free device */
-	pldev = to_platform_device(device);
-	kfree(pldev);
-}
-
-static int __devinit swarm_ide_init_module(void)
-{
-	struct platform_device *pldev;
-	int err;
-
-	printk(KERN_INFO "SWARM IDE driver\n");
-
-	if (driver_register(&swarm_ide_driver)) {
-		printk(KERN_ERR "Driver registration failed\n");
-		err = -ENODEV;
-		goto out;
-	}
-
-        if (!(pldev = kzalloc(sizeof (*pldev), GFP_KERNEL))) {
-		err = -ENOMEM;
-		goto out_unregister_driver;
-	}
-
-	pldev->name		= swarm_ide_string;
-	pldev->id		= 0;
-	pldev->dev.release	= swarm_ide_platform_release;
-
-	if (platform_device_register(pldev)) {
-		err = -ENODEV;
-		goto out_free_pldev;
-	}
-
-        if (!pldev->dev.driver) {
-		/*
-		 * The driver was not bound to this device, there was
-                 * no hardware at this address. Unregister it, as the
-		 * release fuction will take care of freeing the
-		 * allocated structure
-		 */
-		platform_device_unregister (pldev);
-	}
-
-	swarm_ide_dev = pldev;
-
-	return 0;
-
-out_free_pldev:
-	kfree(pldev);
-
-out_unregister_driver:
-	driver_unregister(&swarm_ide_driver);
-out:
-	return err;
-}
-
-module_init(swarm_ide_init_module);
diff --git a/drivers/ide/pci/aec62xx.c b/drivers/ide/pci/aec62xx.c
index 3187215..4142c69 100644
--- a/drivers/ide/pci/aec62xx.c
+++ b/drivers/ide/pci/aec62xx.c
@@ -7,7 +7,6 @@
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/pci.h>
-#include <linux/hdreg.h>
 #include <linux/ide.h>
 #include <linux/init.h>
 
@@ -116,7 +115,7 @@
 	struct pci_dev *dev	= to_pci_dev(hwif->dev);
 	struct ide_host *host	= pci_get_drvdata(dev);
 	struct chipset_bus_clock_list_entry *bus_clock = host->host_priv;
-	u8 unit		= (drive->select.b.unit & 0x01);
+	u8 unit			= drive->dn & 1;
 	u8 tmp1 = 0, tmp2 = 0;
 	u8 ultra = 0, drive_conf = 0, ultra_conf = 0;
 	unsigned long flags;
@@ -140,7 +139,7 @@
 	drive->hwif->port_ops->set_dma_mode(drive, pio + XFER_PIO_0);
 }
 
-static unsigned int __devinit init_chipset_aec62xx(struct pci_dev *dev)
+static unsigned int init_chipset_aec62xx(struct pci_dev *dev)
 {
 	/* These are necessary to get AEC6280 Macintosh cards to work */
 	if ((dev->device == PCI_DEVICE_ID_ARTOP_ATP865) ||
@@ -303,21 +302,23 @@
 };
 MODULE_DEVICE_TABLE(pci, aec62xx_pci_tbl);
 
-static struct pci_driver driver = {
+static struct pci_driver aec62xx_pci_driver = {
 	.name		= "AEC62xx_IDE",
 	.id_table	= aec62xx_pci_tbl,
 	.probe		= aec62xx_init_one,
 	.remove		= __devexit_p(aec62xx_remove),
+	.suspend	= ide_pci_suspend,
+	.resume		= ide_pci_resume,
 };
 
 static int __init aec62xx_ide_init(void)
 {
-	return ide_pci_register_driver(&driver);
+	return ide_pci_register_driver(&aec62xx_pci_driver);
 }
 
 static void __exit aec62xx_ide_exit(void)
 {
-	pci_unregister_driver(&driver);
+	pci_unregister_driver(&aec62xx_pci_driver);
 }
 
 module_init(aec62xx_ide_init);
diff --git a/drivers/ide/pci/alim15x3.c b/drivers/ide/pci/alim15x3.c
index d647526..daf9dce 100644
--- a/drivers/ide/pci/alim15x3.c
+++ b/drivers/ide/pci/alim15x3.c
@@ -31,7 +31,6 @@
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/pci.h>
-#include <linux/hdreg.h>
 #include <linux/ide.h>
 #include <linux/init.h>
 #include <linux/dmi.h>
@@ -78,8 +77,7 @@
 	int bus_speed = ide_pci_clk ? ide_pci_clk : 33;
 	int port = hwif->channel ? 0x5c : 0x58;
 	int portFIFO = hwif->channel ? 0x55 : 0x54;
-	u8 cd_dma_fifo = 0;
-	int unit = drive->select.b.unit & 1;
+	u8 cd_dma_fifo = 0, unit = drive->dn & 1;
 
 	if ((s_clc = (s_time * bus_speed + 999) / 1000) >= 8)
 		s_clc = 0;
@@ -113,7 +111,7 @@
 	}
 	
 	pci_write_config_byte(dev, port, s_clc);
-	pci_write_config_byte(dev, port+drive->select.b.unit+2, (a_clc << 4) | r_clc);
+	pci_write_config_byte(dev, port + unit + 2, (a_clc << 4) | r_clc);
 	local_irq_restore(flags);
 }
 
@@ -134,8 +132,8 @@
 	if (m5229_revision > 0x20 && m5229_revision < 0xC2) {
 		if (drive->media != ide_disk)
 			return 0;
-		if (chip_is_1543c_e && strstr(drive->id->model, "WDC ") &&
-		    wdc_udma == 0)
+		if (wdc_udma == 0 && chip_is_1543c_e &&
+		    strstr((char *)&drive->id[ATA_ID_PROD], "WDC "))
 			return 0;
 	}
 
@@ -155,7 +153,7 @@
 	ide_hwif_t *hwif	= HWIF(drive);
 	struct pci_dev *dev	= to_pci_dev(hwif->dev);
 	u8 speed1		= speed;
-	u8 unit			= (drive->select.b.unit & 0x01);
+	u8 unit			= drive->dn & 1;
 	u8 tmpbyte		= 0x00;
 	int m5229_udma		= (hwif->channel) ? 0x57 : 0x56;
 
@@ -214,7 +212,7 @@
  *	appropriate also sets up the 1533 southbridge.
  */
 
-static unsigned int __devinit init_chipset_ali15x3(struct pci_dev *dev)
+static unsigned int init_chipset_ali15x3(struct pci_dev *dev)
 {
 	unsigned long flags;
 	u8 tmpbyte;
@@ -509,7 +507,7 @@
 	.dma_setup		= ali15x3_dma_setup,
 	.dma_exec_cmd		= ide_dma_exec_cmd,
 	.dma_start		= ide_dma_start,
-	.dma_end		= __ide_dma_end,
+	.dma_end		= ide_dma_end,
 	.dma_test_irq		= ide_dma_test_irq,
 	.dma_lost_irq		= ide_dma_lost_irq,
 	.dma_timeout		= ide_dma_timeout,
@@ -577,21 +575,23 @@
 };
 MODULE_DEVICE_TABLE(pci, alim15x3_pci_tbl);
 
-static struct pci_driver driver = {
+static struct pci_driver alim15x3_pci_driver = {
 	.name		= "ALI15x3_IDE",
 	.id_table	= alim15x3_pci_tbl,
 	.probe		= alim15x3_init_one,
 	.remove		= ide_pci_remove,
+	.suspend	= ide_pci_suspend,
+	.resume		= ide_pci_resume,
 };
 
 static int __init ali15x3_ide_init(void)
 {
-	return ide_pci_register_driver(&driver);
+	return ide_pci_register_driver(&alim15x3_pci_driver);
 }
 
 static void __exit ali15x3_ide_exit(void)
 {
-	return pci_unregister_driver(&driver);
+	return pci_unregister_driver(&alim15x3_pci_driver);
 }
 
 module_init(ali15x3_ide_init);
diff --git a/drivers/ide/pci/amd74xx.c b/drivers/ide/pci/amd74xx.c
index 1e66a96..81ec731 100644
--- a/drivers/ide/pci/amd74xx.c
+++ b/drivers/ide/pci/amd74xx.c
@@ -92,7 +92,7 @@
 
 	ide_timing_compute(drive, speed, &t, T, UT);
 
-	if (peer->present) {
+	if (peer->dev_flags & IDE_DFLAG_PRESENT) {
 		ide_timing_compute(peer, peer->current_speed, &p, T, UT);
 		ide_timing_merge(&p, &t, &t, IDE_TIMING_8BIT);
 	}
@@ -112,13 +112,13 @@
 	amd_set_drive(drive, XFER_PIO_0 + pio);
 }
 
-static void __devinit amd7409_cable_detect(struct pci_dev *dev)
+static void amd7409_cable_detect(struct pci_dev *dev)
 {
 	/* no host side cable detection */
 	amd_80w = 0x03;
 }
 
-static void __devinit amd7411_cable_detect(struct pci_dev *dev)
+static void amd7411_cable_detect(struct pci_dev *dev)
 {
 	int i;
 	u32 u = 0;
@@ -140,7 +140,7 @@
  * The initialization callback.  Initialize drive independent registers.
  */
 
-static unsigned int __devinit init_chipset_amd74xx(struct pci_dev *dev)
+static unsigned int init_chipset_amd74xx(struct pci_dev *dev)
 {
 	u8 t = 0, offset = amd_offset(dev);
 
@@ -319,21 +319,23 @@
 };
 MODULE_DEVICE_TABLE(pci, amd74xx_pci_tbl);
 
-static struct pci_driver driver = {
+static struct pci_driver amd74xx_pci_driver = {
 	.name		= "AMD_IDE",
 	.id_table	= amd74xx_pci_tbl,
 	.probe		= amd74xx_probe,
 	.remove		= ide_pci_remove,
+	.suspend	= ide_pci_suspend,
+	.resume		= ide_pci_resume,
 };
 
 static int __init amd74xx_ide_init(void)
 {
-	return ide_pci_register_driver(&driver);
+	return ide_pci_register_driver(&amd74xx_pci_driver);
 }
 
 static void __exit amd74xx_ide_exit(void)
 {
-	pci_unregister_driver(&driver);
+	pci_unregister_driver(&amd74xx_pci_driver);
 }
 
 module_init(amd74xx_ide_init);
diff --git a/drivers/ide/pci/atiixp.c b/drivers/ide/pci/atiixp.c
index 41f6cb6..b2735d2 100644
--- a/drivers/ide/pci/atiixp.c
+++ b/drivers/ide/pci/atiixp.c
@@ -7,7 +7,6 @@
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/pci.h>
-#include <linux/hdreg.h>
 #include <linux/ide.h>
 #include <linux/init.h>
 
@@ -183,21 +182,23 @@
 };
 MODULE_DEVICE_TABLE(pci, atiixp_pci_tbl);
 
-static struct pci_driver driver = {
+static struct pci_driver atiixp_pci_driver = {
 	.name		= "ATIIXP_IDE",
 	.id_table	= atiixp_pci_tbl,
 	.probe		= atiixp_init_one,
 	.remove		= ide_pci_remove,
+	.suspend	= ide_pci_suspend,
+	.resume		= ide_pci_resume,
 };
 
 static int __init atiixp_ide_init(void)
 {
-	return ide_pci_register_driver(&driver);
+	return ide_pci_register_driver(&atiixp_pci_driver);
 }
 
 static void __exit atiixp_ide_exit(void)
 {
-	pci_unregister_driver(&driver);
+	pci_unregister_driver(&atiixp_pci_driver);
 }
 
 module_init(atiixp_ide_init);
diff --git a/drivers/ide/pci/cmd640.c b/drivers/ide/pci/cmd640.c
index e6c6200..e430664 100644
--- a/drivers/ide/pci/cmd640.c
+++ b/drivers/ide/pci/cmd640.c
@@ -103,7 +103,6 @@
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/delay.h>
-#include <linux/hdreg.h>
 #include <linux/ide.h>
 #include <linux/init.h>
 
@@ -375,6 +374,21 @@
 }
 #endif
 
+static void __set_prefetch_mode(ide_drive_t *drive, int mode)
+{
+	if (mode) {	/* want prefetch on? */
+#if CMD640_PREFETCH_MASKS
+		drive->dev_flags |= IDE_DFLAG_NO_UNMASK;
+		drive->dev_flags &= ~IDE_DFLAG_UNMASK;
+#endif
+		drive->dev_flags &= ~IDE_DFLAG_NO_IO_32BIT;
+	} else {
+		drive->dev_flags &= ~IDE_DFLAG_NO_UNMASK;
+		drive->dev_flags |= IDE_DFLAG_NO_IO_32BIT;
+		drive->io_32bit = 0;
+	}
+}
+
 #ifndef CONFIG_BLK_DEV_CMD640_ENHANCED
 /*
  * Check whether prefetch is on for a drive,
@@ -384,19 +398,10 @@
 {
 	u8 b = get_cmd640_reg(prefetch_regs[index]);
 
-	if (b & prefetch_masks[index]) {	/* is prefetch off? */
-		drive->no_unmask = 0;
-		drive->no_io_32bit = 1;
-		drive->io_32bit = 0;
-	} else {
-#if CMD640_PREFETCH_MASKS
-		drive->no_unmask = 1;
-		drive->unmask = 0;
-#endif
-		drive->no_io_32bit = 0;
-	}
+	__set_prefetch_mode(drive, (b & prefetch_masks[index]) ? 0 : 1);
 }
 #else
+
 /*
  * Sets prefetch mode for a drive.
  */
@@ -408,19 +413,11 @@
 
 	spin_lock_irqsave(&cmd640_lock, flags);
 	b = __get_cmd640_reg(reg);
-	if (mode) {	/* want prefetch on? */
-#if CMD640_PREFETCH_MASKS
-		drive->no_unmask = 1;
-		drive->unmask = 0;
-#endif
-		drive->no_io_32bit = 0;
+	__set_prefetch_mode(drive, mode);
+	if (mode)
 		b &= ~prefetch_masks[index];	/* enable prefetch */
-	} else {
-		drive->no_unmask = 0;
-		drive->no_io_32bit = 1;
-		drive->io_32bit = 0;
+	else
 		b |= prefetch_masks[index];	/* disable prefetch */
-	}
 	__put_cmd640_reg(reg, b);
 	spin_unlock_irqrestore(&cmd640_lock, flags);
 }
@@ -471,10 +468,10 @@
 	 */
 	if (index > 1) {
 		ide_hwif_t *hwif = drive->hwif;
-		ide_drive_t *peer = &hwif->drives[!drive->select.b.unit];
+		ide_drive_t *peer = &hwif->drives[!(drive->dn & 1)];
 		unsigned int mate = index ^ 1;
 
-		if (peer->present) {
+		if (peer->dev_flags & IDE_DFLAG_PRESENT) {
 			if (setup_count < setup_counts[mate])
 				setup_count = setup_counts[mate];
 			if (active_count < active_counts[mate])
@@ -610,7 +607,7 @@
 
 static void cmd640_init_dev(ide_drive_t *drive)
 {
-	unsigned int i = drive->hwif->channel * 2 + drive->select.b.unit;
+	unsigned int i = drive->hwif->channel * 2 + (drive->dn & 1);
 
 #ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
 	/*
@@ -629,7 +626,7 @@
 	 */
 	check_prefetch(drive, i);
 	printk(KERN_INFO DRV_NAME ": drive%d timings/prefetch(%s) preserved\n",
-				  i, drive->no_io_32bit ? "off" : "on");
+		i, (drive->dev_flags & IDE_DFLAG_NO_IO_32BIT) ? "off" : "on");
 #endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
 }
 
diff --git a/drivers/ide/pci/cmd64x.c b/drivers/ide/pci/cmd64x.c
index e064398..935385c 100644
--- a/drivers/ide/pci/cmd64x.c
+++ b/drivers/ide/pci/cmd64x.c
@@ -13,7 +13,6 @@
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/pci.h>
-#include <linux/hdreg.h>
 #include <linux/ide.h>
 #include <linux/init.h>
 
@@ -229,7 +228,7 @@
 {
 	ide_hwif_t *hwif	= HWIF(drive);
 	unsigned long base	= hwif->dma_base - (hwif->channel * 8);
-	int err			= __ide_dma_end(drive);
+	int err			= ide_dma_end(drive);
 	u8  irq_mask		= hwif->channel ? MRDMODE_INTR_CH1 :
 						  MRDMODE_INTR_CH0;
 	u8  mrdmode		= inb(base + 1);
@@ -249,7 +248,7 @@
 	u8  irq_mask		= hwif->channel ? ARTTIM23_INTR_CH1 :
 						  CFR_INTR_CH0;
 	u8  irq_stat		= 0;
-	int err			= __ide_dma_end(drive);
+	int err			= ide_dma_end(drive);
 
 	(void) pci_read_config_byte(dev, irq_reg, &irq_stat);
 	/* clear the interrupt bit */
@@ -332,7 +331,7 @@
 	return (dma_stat & 7) != 4;
 }
 
-static unsigned int __devinit init_chipset_cmd64x(struct pci_dev *dev)
+static unsigned int init_chipset_cmd64x(struct pci_dev *dev)
 {
 	u8 mrdmode = 0;
 
@@ -506,21 +505,23 @@
 };
 MODULE_DEVICE_TABLE(pci, cmd64x_pci_tbl);
 
-static struct pci_driver driver = {
+static struct pci_driver cmd64x_pci_driver = {
 	.name		= "CMD64x_IDE",
 	.id_table	= cmd64x_pci_tbl,
 	.probe		= cmd64x_init_one,
 	.remove		= ide_pci_remove,
+	.suspend	= ide_pci_suspend,
+	.resume		= ide_pci_resume,
 };
 
 static int __init cmd64x_ide_init(void)
 {
-	return ide_pci_register_driver(&driver);
+	return ide_pci_register_driver(&cmd64x_pci_driver);
 }
 
 static void __exit cmd64x_ide_exit(void)
 {
-	pci_unregister_driver(&driver);
+	pci_unregister_driver(&cmd64x_pci_driver);
 }
 
 module_init(cmd64x_ide_init);
diff --git a/drivers/ide/pci/cs5520.c b/drivers/ide/pci/cs5520.c
index 151844f..5efb467 100644
--- a/drivers/ide/pci/cs5520.c
+++ b/drivers/ide/pci/cs5520.c
@@ -35,7 +35,6 @@
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
-#include <linux/hdreg.h>
 #include <linux/init.h>
 #include <linux/pci.h>
 #include <linux/ide.h>
@@ -146,15 +145,17 @@
 };
 MODULE_DEVICE_TABLE(pci, cs5520_pci_tbl);
 
-static struct pci_driver driver = {
+static struct pci_driver cs5520_pci_driver = {
 	.name		= "Cyrix_IDE",
 	.id_table	= cs5520_pci_tbl,
 	.probe		= cs5520_init_one,
+	.suspend	= ide_pci_suspend,
+	.resume		= ide_pci_resume,
 };
 
 static int __init cs5520_ide_init(void)
 {
-	return ide_pci_register_driver(&driver);
+	return ide_pci_register_driver(&cs5520_pci_driver);
 }
 
 module_init(cs5520_ide_init);
diff --git a/drivers/ide/pci/cs5530.c b/drivers/ide/pci/cs5530.c
index f235db8..53f079c 100644
--- a/drivers/ide/pci/cs5530.c
+++ b/drivers/ide/pci/cs5530.c
@@ -15,7 +15,6 @@
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
-#include <linux/hdreg.h>
 #include <linux/pci.h>
 #include <linux/init.h>
 #include <linux/ide.h>
@@ -81,17 +80,19 @@
 static u8 cs5530_udma_filter(ide_drive_t *drive)
 {
 	ide_hwif_t *hwif = drive->hwif;
-	ide_drive_t *mate = &hwif->drives[(drive->dn & 1) ^ 1];
-	struct hd_driveid *mateid = mate->id;
+	ide_drive_t *mate = ide_get_pair_dev(drive);
+	u16 *mateid = mate->id;
 	u8 mask = hwif->ultra_mask;
 
-	if (mate->present == 0)
+	if (mate == NULL)
 		goto out;
 
-	if ((mateid->capability & 1) && __ide_dma_bad_drive(mate) == 0) {
-		if ((mateid->field_valid & 4) && (mateid->dma_ultra & 7))
+	if (ata_id_has_dma(mateid) && __ide_dma_bad_drive(mate) == 0) {
+		if ((mateid[ATA_ID_FIELD_VALID] & 4) &&
+		    (mateid[ATA_ID_UDMA_MODES] & 7))
 			goto out;
-		if ((mateid->field_valid & 2) && (mateid->dma_mword & 7))
+		if ((mateid[ATA_ID_FIELD_VALID] & 2) &&
+		    (mateid[ATA_ID_MWDMA_MODES] & 7))
 			mask = 0;
 	}
 out:
@@ -133,7 +134,7 @@
  *	Initialize the cs5530 bridge for reliable IDE DMA operation.
  */
 
-static unsigned int __devinit init_chipset_cs5530(struct pci_dev *dev)
+static unsigned int init_chipset_cs5530(struct pci_dev *dev)
 {
 	struct pci_dev *master_0 = NULL, *cs5530_0 = NULL;
 
@@ -266,21 +267,23 @@
 };
 MODULE_DEVICE_TABLE(pci, cs5530_pci_tbl);
 
-static struct pci_driver driver = {
+static struct pci_driver cs5530_pci_driver = {
 	.name		= "CS5530 IDE",
 	.id_table	= cs5530_pci_tbl,
 	.probe		= cs5530_init_one,
 	.remove		= ide_pci_remove,
+	.suspend	= ide_pci_suspend,
+	.resume		= ide_pci_resume,
 };
 
 static int __init cs5530_ide_init(void)
 {
-	return ide_pci_register_driver(&driver);
+	return ide_pci_register_driver(&cs5530_pci_driver);
 }
 
 static void __exit cs5530_ide_exit(void)
 {
-	pci_unregister_driver(&driver);
+	pci_unregister_driver(&cs5530_pci_driver);
 }
 
 module_init(cs5530_ide_init);
diff --git a/drivers/ide/pci/cs5535.c b/drivers/ide/pci/cs5535.c
index dd3dc23..983d957 100644
--- a/drivers/ide/pci/cs5535.c
+++ b/drivers/ide/pci/cs5535.c
@@ -76,16 +76,16 @@
 static void cs5535_set_speed(ide_drive_t *drive, const u8 speed)
 {
 	u32 reg = 0, dummy;
-	int unit = drive->select.b.unit;
+	u8 unit = drive->dn & 1;
 
 	/* Set the PIO timings */
 	if (speed < XFER_SW_DMA_0) {
-		ide_drive_t *pair = ide_get_paired_drive(drive);
+		ide_drive_t *pair = ide_get_pair_dev(drive);
 		u8 cmd, pioa;
 
 		cmd = pioa = speed - XFER_PIO_0;
 
-		if (pair->present) {
+		if (pair) {
 			u8 piob = ide_get_best_pio_mode(pair, 255, 4);
 
 			if (piob < cmd)
@@ -192,21 +192,23 @@
 
 MODULE_DEVICE_TABLE(pci, cs5535_pci_tbl);
 
-static struct pci_driver driver = {
-	.name       = "CS5535_IDE",
-	.id_table   = cs5535_pci_tbl,
-	.probe      = cs5535_init_one,
-	.remove     = ide_pci_remove,
+static struct pci_driver cs5535_pci_driver = {
+	.name		= "CS5535_IDE",
+	.id_table	= cs5535_pci_tbl,
+	.probe		= cs5535_init_one,
+	.remove		= ide_pci_remove,
+	.suspend	= ide_pci_suspend,
+	.resume		= ide_pci_resume,
 };
 
 static int __init cs5535_ide_init(void)
 {
-	return ide_pci_register_driver(&driver);
+	return ide_pci_register_driver(&cs5535_pci_driver);
 }
 
 static void __exit cs5535_ide_exit(void)
 {
-	pci_unregister_driver(&driver);
+	pci_unregister_driver(&cs5535_pci_driver);
 }
 
 module_init(cs5535_ide_init);
diff --git a/drivers/ide/pci/cy82c693.c b/drivers/ide/pci/cy82c693.c
index e6d8ee8..5297f07 100644
--- a/drivers/ide/pci/cy82c693.c
+++ b/drivers/ide/pci/cy82c693.c
@@ -50,18 +50,11 @@
 
 #define DRV_NAME "cy82c693"
 
-/* the current version */
-#define CY82_VERSION	"CY82C693U driver v0.34 99-13-12 Andreas S. Krebs (akrebs@altavista.net)"
-
 /*
  *	The following are used to debug the driver.
  */
-#define CY82C693_DEBUG_LOGS	0
 #define CY82C693_DEBUG_INFO	0
 
-/* define CY82C693_SETDMA_CLOCK to set DMA Controller Clock Speed to ATCLK */
-#undef CY82C693_SETDMA_CLOCK
-
 /*
  *	NOTE: the value for busmaster timeout is tricky and I got it by
  *	trial and error!  By using a to low value will cause DMA timeouts
@@ -89,7 +82,6 @@
 #define CY82_INDEX_PORT		0x22
 #define CY82_DATA_PORT		0x23
 
-#define CY82_INDEX_CTRLREG1	0x01
 #define CY82_INDEX_CHANNEL0	0x30
 #define CY82_INDEX_CHANNEL1	0x31
 #define CY82_INDEX_TIMEOUT	0x32
@@ -179,17 +171,6 @@
 
 	index = hwif->channel ? CY82_INDEX_CHANNEL1 : CY82_INDEX_CHANNEL0;
 
-#if CY82C693_DEBUG_LOGS
-	/* for debug let's show the previous values */
-
-	outb(index, CY82_INDEX_PORT);
-	data = inb(CY82_DATA_PORT);
-
-	printk(KERN_INFO "%s (ch=%d, dev=%d): DMA mode is %d (single=%d)\n",
-		drive->name, HWIF(drive)->channel, drive->select.b.unit,
-		(data&0x3), ((data>>2)&1));
-#endif /* CY82C693_DEBUG_LOGS */
-
 	data = (mode & 3) | (single << 2);
 
 	outb(index, CY82_INDEX_PORT);
@@ -197,8 +178,7 @@
 
 #if CY82C693_DEBUG_INFO
 	printk(KERN_INFO "%s (ch=%d, dev=%d): set DMA mode to %d (single=%d)\n",
-		drive->name, HWIF(drive)->channel, drive->select.b.unit,
-		mode & 3, single);
+		drive->name, hwif->channel, drive->dn & 1, mode & 3, single);
 #endif /* CY82C693_DEBUG_INFO */
 
 	/*
@@ -239,50 +219,11 @@
 		}
 	}
 
-#if CY82C693_DEBUG_LOGS
-	/* for debug let's show the register values */
-
-	if (drive->select.b.unit == 0) {
-		/*
-		 * get master drive registers
-		 * address setup control register
-		 * is 32 bit !!!
-		 */
-		pci_read_config_dword(dev, CY82_IDE_ADDRSETUP, &addrCtrl);
-		addrCtrl &= 0x0F;
-
-		/* now let's get the remaining registers */
-		pci_read_config_byte(dev, CY82_IDE_MASTER_IOR, &pclk.time_16r);
-		pci_read_config_byte(dev, CY82_IDE_MASTER_IOW, &pclk.time_16w);
-		pci_read_config_byte(dev, CY82_IDE_MASTER_8BIT, &pclk.time_8);
-	} else {
-		/*
-		 * set slave drive registers
-		 * address setup control register
-		 * is 32 bit !!!
-		 */
-		pci_read_config_dword(dev, CY82_IDE_ADDRSETUP, &addrCtrl);
-
-		addrCtrl &= 0xF0;
-		addrCtrl >>= 4;
-
-		/* now let's get the remaining registers */
-		pci_read_config_byte(dev, CY82_IDE_SLAVE_IOR, &pclk.time_16r);
-		pci_read_config_byte(dev, CY82_IDE_SLAVE_IOW, &pclk.time_16w);
-		pci_read_config_byte(dev, CY82_IDE_SLAVE_8BIT, &pclk.time_8);
-	}
-
-	printk(KERN_INFO "%s (ch=%d, dev=%d): PIO timing is "
-		"(addr=0x%X, ior=0x%X, iow=0x%X, 8bit=0x%X)\n",
-		drive->name, hwif->channel, drive->select.b.unit,
-		addrCtrl, pclk.time_16r, pclk.time_16w, pclk.time_8);
-#endif /* CY82C693_DEBUG_LOGS */
-
 	/* let's calc the values for this PIO mode */
 	compute_clocks(pio, &pclk);
 
 	/* now let's write  the clocks registers */
-	if (drive->select.b.unit == 0) {
+	if ((drive->dn & 1) == 0) {
 		/*
 		 * set master drive
 		 * address setup control register
@@ -324,63 +265,11 @@
 #if CY82C693_DEBUG_INFO
 	printk(KERN_INFO "%s (ch=%d, dev=%d): set PIO timing to "
 		"(addr=0x%X, ior=0x%X, iow=0x%X, 8bit=0x%X)\n",
-		drive->name, hwif->channel, drive->select.b.unit,
+		drive->name, hwif->channel, drive->dn & 1,
 		addrCtrl, pclk.time_16r, pclk.time_16w, pclk.time_8);
 #endif /* CY82C693_DEBUG_INFO */
 }
 
-/*
- * this function is called during init and is used to setup the cy82c693 chip
- */
-static unsigned int __devinit init_chipset_cy82c693(struct pci_dev *dev)
-{
-	if (PCI_FUNC(dev->devfn) != 1)
-		return 0;
-
-#ifdef CY82C693_SETDMA_CLOCK
-	u8 data = 0;
-#endif /* CY82C693_SETDMA_CLOCK */
-
-	/* write info about this verion of the driver */
-	printk(KERN_INFO CY82_VERSION "\n");
-
-#ifdef CY82C693_SETDMA_CLOCK
-       /* okay let's set the DMA clock speed */
-
-	outb(CY82_INDEX_CTRLREG1, CY82_INDEX_PORT);
-	data = inb(CY82_DATA_PORT);
-
-#if CY82C693_DEBUG_INFO
-	printk(KERN_INFO DRV_NAME ": Peripheral Configuration Register: 0x%X\n",
-		data);
-#endif /* CY82C693_DEBUG_INFO */
-
-	/*
-	 * for some reason sometimes the DMA controller
-	 * speed is set to ATCLK/2 ???? - we fix this here
-	 *
-	 * note: i don't know what causes this strange behaviour,
-	 *       but even changing the dma speed doesn't solve it :-(
-	 *       the ide performance is still only half the normal speed
-	 *
-	 *       if anybody knows what goes wrong with my machine, please
-	 *       let me know - ASK
-	 */
-
-	data |= 0x03;
-
-	outb(CY82_INDEX_CTRLREG1, CY82_INDEX_PORT);
-	outb(data, CY82_DATA_PORT);
-
-#if CY82C693_DEBUG_INFO
-	printk(KERN_INFO ": New Peripheral Configuration Register: 0x%X\n",
-		data);
-#endif /* CY82C693_DEBUG_INFO */
-
-#endif /* CY82C693_SETDMA_CLOCK */
-	return 0;
-}
-
 static void __devinit init_iops_cy82c693(ide_hwif_t *hwif)
 {
 	static ide_hwif_t *primary;
@@ -401,7 +290,6 @@
 
 static const struct ide_port_info cy82c693_chipset __devinitdata = {
 	.name		= DRV_NAME,
-	.init_chipset	= init_chipset_cy82c693,
 	.init_iops	= init_iops_cy82c693,
 	.port_ops	= &cy82c693_port_ops,
 	.chipset	= ide_cy82c693,
@@ -443,21 +331,23 @@
 };
 MODULE_DEVICE_TABLE(pci, cy82c693_pci_tbl);
 
-static struct pci_driver driver = {
+static struct pci_driver cy82c693_pci_driver = {
 	.name		= "Cypress_IDE",
 	.id_table	= cy82c693_pci_tbl,
 	.probe		= cy82c693_init_one,
 	.remove		= __devexit_p(cy82c693_remove),
+	.suspend	= ide_pci_suspend,
+	.resume		= ide_pci_resume,
 };
 
 static int __init cy82c693_ide_init(void)
 {
-	return ide_pci_register_driver(&driver);
+	return ide_pci_register_driver(&cy82c693_pci_driver);
 }
 
 static void __exit cy82c693_ide_exit(void)
 {
-	pci_unregister_driver(&driver);
+	pci_unregister_driver(&cy82c693_pci_driver);
 }
 
 module_init(cy82c693_ide_init);
diff --git a/drivers/ide/pci/delkin_cb.c b/drivers/ide/pci/delkin_cb.c
index f84bfb4..8689a70 100644
--- a/drivers/ide/pci/delkin_cb.c
+++ b/drivers/ide/pci/delkin_cb.c
@@ -19,7 +19,6 @@
 
 #include <linux/types.h>
 #include <linux/module.h>
-#include <linux/hdreg.h>
 #include <linux/ide.h>
 #include <linux/init.h>
 #include <linux/pci.h>
@@ -118,7 +117,7 @@
 };
 MODULE_DEVICE_TABLE(pci, delkin_cb_pci_tbl);
 
-static struct pci_driver driver = {
+static struct pci_driver delkin_cb_pci_driver = {
 	.name		= "Delkin-ASKA-Workbit Cardbus IDE",
 	.id_table	= delkin_cb_pci_tbl,
 	.probe		= delkin_cb_probe,
@@ -127,12 +126,12 @@
 
 static int __init delkin_cb_init(void)
 {
-	return pci_register_driver(&driver);
+	return pci_register_driver(&delkin_cb_pci_driver);
 }
 
 static void __exit delkin_cb_exit(void)
 {
-	pci_unregister_driver(&driver);
+	pci_unregister_driver(&delkin_cb_pci_driver);
 }
 
 module_init(delkin_cb_init);
diff --git a/drivers/ide/pci/generic.c b/drivers/ide/pci/generic.c
index b07d4f4..474f96a 100644
--- a/drivers/ide/pci/generic.c
+++ b/drivers/ide/pci/generic.c
@@ -22,7 +22,6 @@
 #include <linux/types.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
-#include <linux/hdreg.h>
 #include <linux/pci.h>
 #include <linux/ide.h>
 #include <linux/init.h>
@@ -167,21 +166,23 @@
 };
 MODULE_DEVICE_TABLE(pci, generic_pci_tbl);
 
-static struct pci_driver driver = {
+static struct pci_driver generic_pci_driver = {
 	.name		= "PCI_IDE",
 	.id_table	= generic_pci_tbl,
 	.probe		= generic_init_one,
 	.remove		= ide_pci_remove,
+	.suspend	= ide_pci_suspend,
+	.resume		= ide_pci_resume,
 };
 
 static int __init generic_ide_init(void)
 {
-	return ide_pci_register_driver(&driver);
+	return ide_pci_register_driver(&generic_pci_driver);
 }
 
 static void __exit generic_ide_exit(void)
 {
-	pci_unregister_driver(&driver);
+	pci_unregister_driver(&generic_pci_driver);
 }
 
 module_init(generic_ide_init);
diff --git a/drivers/ide/pci/hpt34x.c b/drivers/ide/pci/hpt34x.c
index 6009b0b..fb1a3aa 100644
--- a/drivers/ide/pci/hpt34x.c
+++ b/drivers/ide/pci/hpt34x.c
@@ -27,7 +27,6 @@
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/ioport.h>
-#include <linux/hdreg.h>
 #include <linux/interrupt.h>
 #include <linux/pci.h>
 #include <linux/init.h>
@@ -79,7 +78,7 @@
  */
 #define	HPT34X_PCI_INIT_REG		0x80
 
-static unsigned int __devinit init_chipset_hpt34x(struct pci_dev *dev)
+static unsigned int init_chipset_hpt34x(struct pci_dev *dev)
 {
 	int i = 0;
 	unsigned long hpt34xIoBase = pci_resource_start(dev, 4);
@@ -167,21 +166,23 @@
 };
 MODULE_DEVICE_TABLE(pci, hpt34x_pci_tbl);
 
-static struct pci_driver driver = {
+static struct pci_driver hpt34x_pci_driver = {
 	.name		= "HPT34x_IDE",
 	.id_table	= hpt34x_pci_tbl,
 	.probe		= hpt34x_init_one,
 	.remove		= ide_pci_remove,
+	.suspend	= ide_pci_suspend,
+	.resume		= ide_pci_resume,
 };
 
 static int __init hpt34x_ide_init(void)
 {
-	return ide_pci_register_driver(&driver);
+	return ide_pci_register_driver(&hpt34x_pci_driver);
 }
 
 static void __exit hpt34x_ide_exit(void)
 {
-	pci_unregister_driver(&driver);
+	pci_unregister_driver(&hpt34x_pci_driver);
 }
 
 module_init(hpt34x_ide_init);
diff --git a/drivers/ide/pci/hpt366.c b/drivers/ide/pci/hpt366.c
index c37ab17..9cf171c 100644
--- a/drivers/ide/pci/hpt366.c
+++ b/drivers/ide/pci/hpt366.c
@@ -122,7 +122,6 @@
 #include <linux/kernel.h>
 #include <linux/delay.h>
 #include <linux/blkdev.h>
-#include <linux/hdreg.h>
 #include <linux/interrupt.h>
 #include <linux/pci.h>
 #include <linux/init.h>
@@ -605,10 +604,10 @@
 
 static int check_in_drive_list(ide_drive_t *drive, const char **list)
 {
-	struct hd_driveid *id = drive->id;
+	char *m = (char *)&drive->id[ATA_ID_PROD];
 
 	while (*list)
-		if (!strcmp(*list++,id->model))
+		if (!strcmp(*list++, m))
 			return 1;
 	return 0;
 }
@@ -655,7 +654,7 @@
 	case HPT372A:
 	case HPT372N:
 	case HPT374 :
-		if (ide_dev_is_sata(drive->id))
+		if (ata_id_is_sata(drive->id))
 			mask &= ~0x0e;
 		/* Fall thru */
 	default:
@@ -675,7 +674,7 @@
 	case HPT372A:
 	case HPT372N:
 	case HPT374 :
-		if (ide_dev_is_sata(drive->id))
+		if (ata_id_is_sata(drive->id))
 			return 0x00;
 		/* Fall thru */
 	default:
@@ -731,11 +730,11 @@
 
 static void hpt3xx_quirkproc(ide_drive_t *drive)
 {
-	struct hd_driveid *id	= drive->id;
+	char *m			= (char *)&drive->id[ATA_ID_PROD];
 	const  char **list	= quirk_drives;
 
 	while (*list)
-		if (strstr(id->model, *list++)) {
+		if (strstr(m, *list++)) {
 			drive->quirk_list = 1;
 			return;
 		}
@@ -836,7 +835,7 @@
 		if (dma_stat & 0x01)
 			hpt370_irq_timeout(drive);
 	}
-	return __ide_dma_end(drive);
+	return ide_dma_end(drive);
 }
 
 static void hpt370_dma_timeout(ide_drive_t *drive)
@@ -864,9 +863,6 @@
 	if (dma_stat & 4)
 		return 1;
 
-	if (!drive->waiting_for_dma)
-		printk(KERN_WARNING "%s: (%s) called while not waiting\n",
-				drive->name, __func__);
 	return 0;
 }
 
@@ -881,7 +877,7 @@
 	pci_read_config_byte(dev, mcr_addr, &mcr);
 	if (bwsr & mask)
 		pci_write_config_byte(dev, mcr_addr, mcr | 0x30);
-	return __ide_dma_end(drive);
+	return ide_dma_end(drive);
 }
 
 /**
@@ -944,7 +940,7 @@
  *	Perform a calibration cycle on the DPLL.
  *	Returns 1 if this succeeds
  */
-static int __devinit hpt37x_calibrate_dpll(struct pci_dev *dev, u16 f_low, u16 f_high)
+static int hpt37x_calibrate_dpll(struct pci_dev *dev, u16 f_low, u16 f_high)
 {
 	u32 dpll = (f_high << 16) | f_low | 0x100;
 	u8  scr2;
@@ -972,7 +968,37 @@
 	return 1;
 }
 
-static unsigned int __devinit init_chipset_hpt366(struct pci_dev *dev)
+static void hpt3xx_disable_fast_irq(struct pci_dev *dev, u8 mcr_addr)
+{
+	struct ide_host *host	= pci_get_drvdata(dev);
+	struct hpt_info *info	= host->host_priv + (&dev->dev == host->dev[1]);
+	u8  chip_type		= info->chip_type;
+	u8  new_mcr, old_mcr	= 0;
+
+	/*
+	 * Disable the "fast interrupt" prediction.  Don't hold off
+	 * on interrupts. (== 0x01 despite what the docs say)
+	 */
+	pci_read_config_byte(dev, mcr_addr + 1, &old_mcr);
+
+	if (chip_type >= HPT374)
+		new_mcr = old_mcr & ~0x07;
+	else if (chip_type >= HPT370) {
+		new_mcr = old_mcr;
+		new_mcr &= ~0x02;
+#ifdef HPT_DELAY_INTERRUPT
+		new_mcr &= ~0x01;
+#else
+		new_mcr |=  0x01;
+#endif
+	} else					/* HPT366 and HPT368  */
+		new_mcr = old_mcr & ~0x80;
+
+	if (new_mcr != old_mcr)
+		pci_write_config_byte(dev, mcr_addr + 1, new_mcr);
+}
+
+static unsigned int init_chipset_hpt366(struct pci_dev *dev)
 {
 	unsigned long io_base	= pci_resource_start(dev, 4);
 	struct hpt_info *info	= hpt3xx_get_info(&dev->dev);
@@ -1209,9 +1235,11 @@
 	 * NOTE: This register is only writeable via I/O space.
 	 */
 	if (chip_type == HPT371N && clock == ATA_CLOCK_66MHZ)
-
 		outb(inb(io_base + 0x9c) | 0x04, io_base + 0x9c);
 
+	hpt3xx_disable_fast_irq(dev, 0x50);
+	hpt3xx_disable_fast_irq(dev, 0x54);
+
 	return dev->irq;
 }
 
@@ -1265,7 +1293,6 @@
 	struct hpt_info *info	= hpt3xx_get_info(hwif->dev);
 	int serialize		= HPT_SERIALIZE_IO;
 	u8  chip_type		= info->chip_type;
-	u8  new_mcr, old_mcr	= 0;
 
 	/* Cache the channel's MISC. control registers' offset */
 	hwif->select_data	= hwif->channel ? 0x54 : 0x50;
@@ -1288,29 +1315,6 @@
 	/* Serialize access to this device if needed */
 	if (serialize && hwif->mate)
 		hwif->serialized = hwif->mate->serialized = 1;
-
-	/*
-	 * Disable the "fast interrupt" prediction.  Don't hold off
-	 * on interrupts. (== 0x01 despite what the docs say)
-	 */
-	pci_read_config_byte(dev, hwif->select_data + 1, &old_mcr);
-
-	if (info->chip_type >= HPT374)
-		new_mcr = old_mcr & ~0x07;
-	else if (info->chip_type >= HPT370) {
-		new_mcr = old_mcr;
-		new_mcr &= ~0x02;
-
-#ifdef HPT_DELAY_INTERRUPT
-		new_mcr &= ~0x01;
-#else
-		new_mcr |=  0x01;
-#endif
-	} else					/* HPT366 and HPT368  */
-		new_mcr = old_mcr & ~0x80;
-
-	if (new_mcr != old_mcr)
-		pci_write_config_byte(dev, hwif->select_data + 1, new_mcr);
 }
 
 static int __devinit init_dma_hpt366(ide_hwif_t *hwif,
@@ -1449,7 +1453,7 @@
 	.dma_setup		= ide_dma_setup,
 	.dma_exec_cmd		= ide_dma_exec_cmd,
 	.dma_start		= ide_dma_start,
-	.dma_end		= __ide_dma_end,
+	.dma_end		= ide_dma_end,
 	.dma_test_irq		= ide_dma_test_irq,
 	.dma_lost_irq		= hpt366_dma_lost_irq,
 	.dma_timeout		= ide_dma_timeout,
@@ -1615,21 +1619,23 @@
 };
 MODULE_DEVICE_TABLE(pci, hpt366_pci_tbl);
 
-static struct pci_driver driver = {
+static struct pci_driver hpt366_pci_driver = {
 	.name		= "HPT366_IDE",
 	.id_table	= hpt366_pci_tbl,
 	.probe		= hpt366_init_one,
 	.remove		= __devexit_p(hpt366_remove),
+	.suspend	= ide_pci_suspend,
+	.resume		= ide_pci_resume,
 };
 
 static int __init hpt366_ide_init(void)
 {
-	return ide_pci_register_driver(&driver);
+	return ide_pci_register_driver(&hpt366_pci_driver);
 }
 
 static void __exit hpt366_ide_exit(void)
 {
-	pci_unregister_driver(&driver);
+	pci_unregister_driver(&hpt366_pci_driver);
 }
 
 module_init(hpt366_ide_init);
diff --git a/drivers/ide/pci/it8213.c b/drivers/ide/pci/it8213.c
index 652e47d..7c2feeb 100644
--- a/drivers/ide/pci/it8213.c
+++ b/drivers/ide/pci/it8213.c
@@ -10,7 +10,6 @@
 #include <linux/types.h>
 #include <linux/module.h>
 #include <linux/pci.h>
-#include <linux/hdreg.h>
 #include <linux/ide.h>
 #include <linux/init.h>
 
@@ -190,21 +189,23 @@
 
 MODULE_DEVICE_TABLE(pci, it8213_pci_tbl);
 
-static struct pci_driver driver = {
+static struct pci_driver it8213_pci_driver = {
 	.name		= "ITE8213_IDE",
 	.id_table	= it8213_pci_tbl,
 	.probe		= it8213_init_one,
 	.remove		= ide_pci_remove,
+	.suspend	= ide_pci_suspend,
+	.resume		= ide_pci_resume,
 };
 
 static int __init it8213_ide_init(void)
 {
-	return ide_pci_register_driver(&driver);
+	return ide_pci_register_driver(&it8213_pci_driver);
 }
 
 static void __exit it8213_ide_exit(void)
 {
-	pci_unregister_driver(&driver);
+	pci_unregister_driver(&it8213_pci_driver);
 }
 
 module_init(it8213_ide_init);
diff --git a/drivers/ide/pci/it821x.c b/drivers/ide/pci/it821x.c
index 4a1508a..995e18b 100644
--- a/drivers/ide/pci/it821x.c
+++ b/drivers/ide/pci/it821x.c
@@ -63,7 +63,6 @@
 #include <linux/types.h>
 #include <linux/module.h>
 #include <linux/pci.h>
-#include <linux/hdreg.h>
 #include <linux/ide.h>
 #include <linux/init.h>
 
@@ -139,8 +138,7 @@
 	struct pci_dev *dev = to_pci_dev(hwif->dev);
 	struct it821x_dev *itdev = ide_get_hwifdata(hwif);
 	int channel = hwif->channel;
-	int unit = drive->select.b.unit;
-	u8 conf;
+	u8 unit = drive->dn & 1, conf;
 
 	/* Program UDMA timing bits */
 	if(itdev->clock_mode == ATA_66)
@@ -169,13 +167,11 @@
 	ide_hwif_t *hwif = drive->hwif;
 	struct pci_dev *dev = to_pci_dev(hwif->dev);
 	struct it821x_dev *itdev = ide_get_hwifdata(hwif);
+	ide_drive_t *pair;
+	int clock, altclock, sel = 0;
+	u8 unit = drive->dn & 1, v;
 
-	u8 unit = drive->select.b.unit;
-	ide_drive_t *pair = &hwif->drives[1-unit];
-
-	int clock, altclock;
-	u8 v;
-	int sel = 0;
+	pair = &hwif->drives[1 - unit];
 
 	if(itdev->want[0][0] > itdev->want[1][0]) {
 		clock = itdev->want[0][1];
@@ -241,16 +237,17 @@
 
 static void it821x_set_pio_mode(ide_drive_t *drive, const u8 pio)
 {
-	ide_hwif_t *hwif	= drive->hwif;
+	ide_hwif_t *hwif = drive->hwif;
 	struct it821x_dev *itdev = ide_get_hwifdata(hwif);
-	int unit = drive->select.b.unit;
-	ide_drive_t *pair = &hwif->drives[1 - unit];
-	u8 set_pio = pio;
+	ide_drive_t *pair;
+	u8 unit = drive->dn & 1, set_pio = pio;
 
 	/* Spec says 89 ref driver uses 88 */
 	static u16 pio_timings[]= { 0xAA88, 0xA382, 0xA181, 0x3332, 0x3121 };
 	static u8 pio_want[]    = { ATA_66, ATA_66, ATA_66, ATA_66, ATA_ANY };
 
+	pair = &hwif->drives[1 - unit];
+
 	/*
 	 * Compute the best PIO mode we can for a given device. We must
 	 * pick a speed that does not cause problems with the other device
@@ -287,9 +284,7 @@
 	ide_hwif_t *hwif = drive->hwif;
 	struct pci_dev *dev = to_pci_dev(hwif->dev);
 	struct it821x_dev *itdev = (void *)ide_get_hwifdata(hwif);
-	int unit = drive->select.b.unit;
-	int channel = hwif->channel;
-	u8 conf;
+	u8 unit = drive->dn & 1, channel = hwif->channel, conf;
 
 	static u16 dma[]	= { 0x8866, 0x3222, 0x3121 };
 	static u8 mwdma_want[]	= { ATA_ANY, ATA_66, ATA_ANY };
@@ -326,9 +321,7 @@
 	ide_hwif_t *hwif = drive->hwif;
 	struct pci_dev *dev = to_pci_dev(hwif->dev);
 	struct it821x_dev *itdev = ide_get_hwifdata(hwif);
-	int unit = drive->select.b.unit;
-	int channel = hwif->channel;
-	u8 conf;
+	u8 unit = drive->dn & 1, channel = hwif->channel, conf;
 
 	static u16 udma[]	= { 0x4433, 0x4231, 0x3121, 0x2121, 0x1111, 0x2211, 0x1111 };
 	static u8 udma_want[]	= { ATA_ANY, ATA_50, ATA_ANY, ATA_66, ATA_66, ATA_50, ATA_66 };
@@ -370,7 +363,8 @@
 {
 	ide_hwif_t *hwif = drive->hwif;
 	struct it821x_dev *itdev = ide_get_hwifdata(hwif);
-	int unit = drive->select.b.unit;
+	u8 unit = drive->dn & 1;
+
 	if(itdev->mwdma[unit] != MWDMA_OFF)
 		it821x_program(drive, itdev->mwdma[unit]);
 	else if(itdev->udma[unit] != UDMA_OFF && itdev->timing10)
@@ -390,9 +384,10 @@
 static int it821x_dma_end(ide_drive_t *drive)
 {
 	ide_hwif_t *hwif = drive->hwif;
-	int unit = drive->select.b.unit;
 	struct it821x_dev *itdev = ide_get_hwifdata(hwif);
-	int ret = __ide_dma_end(drive);
+	int ret = ide_dma_end(drive);
+	u8 unit = drive->dn & 1;
+
 	if(itdev->mwdma[unit] != MWDMA_OFF)
 		it821x_program(drive, itdev->pio[unit]);
 	return ret;
@@ -446,8 +441,7 @@
 static void it821x_quirkproc(ide_drive_t *drive)
 {
 	struct it821x_dev *itdev = ide_get_hwifdata(drive->hwif);
-	struct hd_driveid *id = drive->id;
-	u16 *idbits = (u16 *)drive->id;
+	u16 *id = drive->id;
 
 	if (!itdev->smart) {
 		/*
@@ -456,7 +450,7 @@
 		 *	IRQ mask as we may well be in PIO (eg rev 0x10)
 		 *	for now and we know unmasking is safe on this chipset.
 		 */
-		drive->unmask = 1;
+		drive->dev_flags |= IDE_DFLAG_UNMASK;
 	} else {
 	/*
 	 *	Perform fixups on smart mode. We need to "lose" some
@@ -466,36 +460,36 @@
 	 */
 
 		/* Check for RAID v native */
-		if(strstr(id->model, "Integrated Technology Express")) {
+		if (strstr((char *)&id[ATA_ID_PROD],
+			   "Integrated Technology Express")) {
 			/* In raid mode the ident block is slightly buggy
 			   We need to set the bits so that the IDE layer knows
 			   LBA28. LBA48 and DMA ar valid */
-			id->capability |= 3;		/* LBA28, DMA */
-			id->command_set_2 |= 0x0400;	/* LBA48 valid */
-			id->cfs_enable_2 |= 0x0400;	/* LBA48 on */
+			id[ATA_ID_CAPABILITY]    |= (3 << 8); /* LBA28, DMA */
+			id[ATA_ID_COMMAND_SET_2] |= 0x0400;   /* LBA48 valid */
+			id[ATA_ID_CFS_ENABLE_2]  |= 0x0400;   /* LBA48 on */
 			/* Reporting logic */
 			printk(KERN_INFO "%s: IT8212 %sRAID %d volume",
-				drive->name,
-				idbits[147] ? "Bootable ":"",
-				idbits[129]);
-				if(idbits[129] != 1)
-					printk("(%dK stripe)", idbits[146]);
-				printk(".\n");
+				drive->name, id[147] ? "Bootable " : "",
+				id[ATA_ID_CSFO]);
+			if (id[ATA_ID_CSFO] != 1)
+				printk(KERN_CONT "(%dK stripe)", id[146]);
+			printk(KERN_CONT ".\n");
 		} else {
 			/* Non RAID volume. Fixups to stop the core code
 			   doing unsupported things */
-			id->field_valid &= 3;
-			id->queue_depth = 0;
-			id->command_set_1 = 0;
-			id->command_set_2 &= 0xC400;
-			id->cfsse &= 0xC000;
-			id->cfs_enable_1 = 0;
-			id->cfs_enable_2 &= 0xC400;
-			id->csf_default &= 0xC000;
-			id->word127 = 0;
-			id->dlf = 0;
-			id->csfo = 0;
-			id->cfa_power = 0;
+			id[ATA_ID_FIELD_VALID]	 &= 3;
+			id[ATA_ID_QUEUE_DEPTH]	  = 0;
+			id[ATA_ID_COMMAND_SET_1]  = 0;
+			id[ATA_ID_COMMAND_SET_2] &= 0xC400;
+			id[ATA_ID_CFSSE]	 &= 0xC000;
+			id[ATA_ID_CFS_ENABLE_1]	  = 0;
+			id[ATA_ID_CFS_ENABLE_2]	 &= 0xC400;
+			id[ATA_ID_CSF_DEFAULT]	 &= 0xC000;
+			id[127]			  = 0;
+			id[ATA_ID_DLF]		  = 0;
+			id[ATA_ID_CSFO]		  = 0;
+			id[ATA_ID_CFA_POWER]	  = 0;
 			printk(KERN_INFO "%s: Performing identify fixups.\n",
 				drive->name);
 		}
@@ -505,8 +499,8 @@
 		 * IDE core that DMA is supported (it821x hardware
 		 * takes care of DMA mode programming).
 		 */
-		if (id->capability & 1) {
-			id->dma_mword |= 0x0101;
+		if (ata_id_has_dma(id)) {
+			id[ATA_ID_MWDMA_MODES] |= 0x0101;
 			drive->current_speed = XFER_MW_DMA_0;
 		}
 	}
@@ -588,7 +582,7 @@
 	hwif->mwdma_mask = ATA_MWDMA2;
 }
 
-static void __devinit it8212_disable_raid(struct pci_dev *dev)
+static void it8212_disable_raid(struct pci_dev *dev)
 {
 	/* Reset local CPU, and set BIOS not ready */
 	pci_write_config_byte(dev, 0x5E, 0x01);
@@ -605,7 +599,7 @@
 	pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x20);
 }
 
-static unsigned int __devinit init_chipset_it821x(struct pci_dev *dev)
+static unsigned int init_chipset_it821x(struct pci_dev *dev)
 {
 	u8 conf;
 	static char *mode[2] = { "pass through", "smart" };
@@ -682,21 +676,23 @@
 
 MODULE_DEVICE_TABLE(pci, it821x_pci_tbl);
 
-static struct pci_driver driver = {
+static struct pci_driver it821x_pci_driver = {
 	.name		= "ITE821x IDE",
 	.id_table	= it821x_pci_tbl,
 	.probe		= it821x_init_one,
 	.remove		= __devexit_p(it821x_remove),
+	.suspend	= ide_pci_suspend,
+	.resume		= ide_pci_resume,
 };
 
 static int __init it821x_ide_init(void)
 {
-	return ide_pci_register_driver(&driver);
+	return ide_pci_register_driver(&it821x_pci_driver);
 }
 
 static void __exit it821x_ide_exit(void)
 {
-	pci_unregister_driver(&driver);
+	pci_unregister_driver(&it821x_pci_driver);
 }
 
 module_init(it821x_ide_init);
diff --git a/drivers/ide/pci/jmicron.c b/drivers/ide/pci/jmicron.c
index bb9d09d..9a68433 100644
--- a/drivers/ide/pci/jmicron.c
+++ b/drivers/ide/pci/jmicron.c
@@ -8,7 +8,6 @@
 #include <linux/types.h>
 #include <linux/module.h>
 #include <linux/pci.h>
-#include <linux/hdreg.h>
 #include <linux/ide.h>
 #include <linux/init.h>
 
@@ -150,21 +149,23 @@
 
 MODULE_DEVICE_TABLE(pci, jmicron_pci_tbl);
 
-static struct pci_driver driver = {
+static struct pci_driver jmicron_pci_driver = {
 	.name		= "JMicron IDE",
 	.id_table	= jmicron_pci_tbl,
 	.probe		= jmicron_init_one,
 	.remove		= ide_pci_remove,
+	.suspend	= ide_pci_suspend,
+	.resume		= ide_pci_resume,
 };
 
 static int __init jmicron_ide_init(void)
 {
-	return ide_pci_register_driver(&driver);
+	return ide_pci_register_driver(&jmicron_pci_driver);
 }
 
 static void __exit jmicron_ide_exit(void)
 {
-	pci_unregister_driver(&driver);
+	pci_unregister_driver(&jmicron_pci_driver);
 }
 
 module_init(jmicron_ide_init);
diff --git a/drivers/ide/pci/ns87415.c b/drivers/ide/pci/ns87415.c
index ffefcd1..1378906 100644
--- a/drivers/ide/pci/ns87415.c
+++ b/drivers/ide/pci/ns87415.c
@@ -11,7 +11,6 @@
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/interrupt.h>
-#include <linux/hdreg.h>
 #include <linux/pci.h>
 #include <linux/delay.h>
 #include <linux/ide.h>
@@ -138,7 +137,7 @@
 static unsigned int ns87415_count = 0, ns87415_control[MAX_HWIFS] = { 0 };
 
 /*
- * This routine either enables/disables (according to drive->present)
+ * This routine either enables/disables (according to IDE_DFLAG_PRESENT)
  * the IRQ associated with the port (HWIF(drive)),
  * and selects either PIO or DMA handshaking for the next I/O operation.
  */
@@ -154,11 +153,15 @@
 
 	/* Adjust IRQ enable bit */
 	bit = 1 << (8 + hwif->channel);
-	new = drive->present ? (new & ~bit) : (new | bit);
+
+	if (drive->dev_flags & IDE_DFLAG_PRESENT)
+		new &= ~bit;
+	else
+		new |= bit;
 
 	/* Select PIO or DMA, DMA may only be selected for one drive/channel. */
-	bit   = 1 << (20 + drive->select.b.unit       + (hwif->channel << 1));
-	other = 1 << (20 + (1 - drive->select.b.unit) + (hwif->channel << 1));
+	bit   = 1 << (20 + (drive->dn & 1) + (hwif->channel << 1));
+	other = 1 << (20 + (1 - (drive->dn & 1)) + (hwif->channel << 1));
 	new = use_dma ? ((new & ~other) | bit) : (new & ~bit);
 
 	if (new != *old) {
@@ -188,7 +191,8 @@
 
 static void ns87415_selectproc (ide_drive_t *drive)
 {
-	ns87415_prepare_drive (drive, drive->using_dma);
+	ns87415_prepare_drive(drive,
+			      !!(drive->dev_flags & IDE_DFLAG_USING_DMA));
 }
 
 static int ns87415_dma_end(ide_drive_t *drive)
@@ -274,9 +278,9 @@
 		do {
 			udelay(50);
 			stat = hwif->tp_ops->read_status(hwif);
-                	if (stat == 0xff)
-                        	break;
-        	} while ((stat & BUSY_STAT) && --timeout);
+			if (stat == 0xff)
+				break;
+		} while ((stat & ATA_BUSY) && --timeout);
 #endif
 	}
 
@@ -335,21 +339,23 @@
 };
 MODULE_DEVICE_TABLE(pci, ns87415_pci_tbl);
 
-static struct pci_driver driver = {
+static struct pci_driver ns87415_pci_driver = {
 	.name		= "NS87415_IDE",
 	.id_table	= ns87415_pci_tbl,
 	.probe		= ns87415_init_one,
 	.remove		= ide_pci_remove,
+	.suspend	= ide_pci_suspend,
+	.resume		= ide_pci_resume,
 };
 
 static int __init ns87415_ide_init(void)
 {
-	return ide_pci_register_driver(&driver);
+	return ide_pci_register_driver(&ns87415_pci_driver);
 }
 
 static void __exit ns87415_ide_exit(void)
 {
-	pci_unregister_driver(&driver);
+	pci_unregister_driver(&ns87415_pci_driver);
 }
 
 module_init(ns87415_ide_init);
diff --git a/drivers/ide/pci/opti621.c b/drivers/ide/pci/opti621.c
index e28e672..6048eda 100644
--- a/drivers/ide/pci/opti621.c
+++ b/drivers/ide/pci/opti621.c
@@ -85,7 +85,6 @@
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/pci.h>
-#include <linux/hdreg.h>
 #include <linux/ide.h>
 
 #include <asm/io.h>
@@ -137,7 +136,7 @@
 static void opti621_set_pio_mode(ide_drive_t *drive, const u8 pio)
 {
 	ide_hwif_t *hwif = drive->hwif;
-	ide_drive_t *pair = ide_get_paired_drive(drive);
+	ide_drive_t *pair = ide_get_pair_dev(drive);
 	unsigned long flags;
 	u8 tim, misc, addr_pio = pio, clk;
 
@@ -153,7 +152,7 @@
 
 	drive->drive_data = XFER_PIO_0 + pio;
 
-	if (pair->present) {
+	if (pair) {
 		if (pair->drive_data && pair->drive_data < drive->drive_data)
 			addr_pio = pair->drive_data - XFER_PIO_0;
 	}
@@ -180,7 +179,7 @@
 	misc = addr_timings[clk][addr_pio];
 
 	/* select Index-0/1 for Register-A/B */
-	write_reg(drive->select.b.unit, MISC_REG);
+	write_reg(drive->dn & 1, MISC_REG);
 	/* set read cycle timings */
 	write_reg(tim, READ_REG);
 	/* set write cycle timings */
@@ -221,21 +220,23 @@
 };
 MODULE_DEVICE_TABLE(pci, opti621_pci_tbl);
 
-static struct pci_driver driver = {
+static struct pci_driver opti621_pci_driver = {
 	.name		= "Opti621_IDE",
 	.id_table	= opti621_pci_tbl,
 	.probe		= opti621_init_one,
 	.remove		= ide_pci_remove,
+	.suspend	= ide_pci_suspend,
+	.resume		= ide_pci_resume,
 };
 
 static int __init opti621_ide_init(void)
 {
-	return ide_pci_register_driver(&driver);
+	return ide_pci_register_driver(&opti621_pci_driver);
 }
 
 static void __exit opti621_ide_exit(void)
 {
-	pci_unregister_driver(&driver);
+	pci_unregister_driver(&opti621_pci_driver);
 }
 
 module_init(opti621_ide_init);
diff --git a/drivers/ide/pci/pdc202xx_new.c b/drivers/ide/pci/pdc202xx_new.c
index d477da6..211ae46 100644
--- a/drivers/ide/pci/pdc202xx_new.c
+++ b/drivers/ide/pci/pdc202xx_new.c
@@ -19,7 +19,6 @@
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/delay.h>
-#include <linux/hdreg.h>
 #include <linux/pci.h>
 #include <linux/init.h>
 #include <linux/ide.h>
@@ -203,10 +202,10 @@
 
 static void pdcnew_quirkproc(ide_drive_t *drive)
 {
-	const char **list, *model = drive->id->model;
+	const char **list, *m = (char *)&drive->id[ATA_ID_PROD];
 
 	for (list = pdc_quirk_drives; *list != NULL; list++)
-		if (strstr(model, *list) != NULL) {
+		if (strstr(m, *list) != NULL) {
 			drive->quirk_list = 2;
 			return;
 		}
@@ -227,7 +226,7 @@
  * read_counter - Read the byte count registers
  * @dma_base: for the port address
  */
-static long __devinit read_counter(u32 dma_base)
+static long read_counter(u32 dma_base)
 {
 	u32  pri_dma_base = dma_base, sec_dma_base = dma_base + 0x08;
 	u8   cnt0, cnt1, cnt2, cnt3;
@@ -267,7 +266,7 @@
  * @dma_base: for the port address
  * E.g. 16949000 on 33 MHz PCI bus, i.e. half of the PCI clock.
  */
-static long __devinit detect_pll_input_clock(unsigned long dma_base)
+static long detect_pll_input_clock(unsigned long dma_base)
 {
 	struct timeval start_time, end_time;
 	long start_count, end_count;
@@ -310,7 +309,7 @@
 }
 
 #ifdef CONFIG_PPC_PMAC
-static void __devinit apple_kiwi_init(struct pci_dev *pdev)
+static void apple_kiwi_init(struct pci_dev *pdev)
 {
 	struct device_node *np = pci_device_to_OF_node(pdev);
 	u8 conf;
@@ -326,7 +325,7 @@
 }
 #endif /* CONFIG_PPC_PMAC */
 
-static unsigned int __devinit init_chipset_pdcnew(struct pci_dev *dev)
+static unsigned int init_chipset_pdcnew(struct pci_dev *dev)
 {
 	const char *name = DRV_NAME;
 	unsigned long dma_base = pci_resource_start(dev, 4);
@@ -562,21 +561,23 @@
 };
 MODULE_DEVICE_TABLE(pci, pdc202new_pci_tbl);
 
-static struct pci_driver driver = {
+static struct pci_driver pdc202new_pci_driver = {
 	.name		= "Promise_IDE",
 	.id_table	= pdc202new_pci_tbl,
 	.probe		= pdc202new_init_one,
 	.remove		= __devexit_p(pdc202new_remove),
+	.suspend	= ide_pci_suspend,
+	.resume		= ide_pci_resume,
 };
 
 static int __init pdc202new_ide_init(void)
 {
-	return ide_pci_register_driver(&driver);
+	return ide_pci_register_driver(&pdc202new_pci_driver);
 }
 
 static void __exit pdc202new_ide_exit(void)
 {
-	pci_unregister_driver(&driver);
+	pci_unregister_driver(&pdc202new_pci_driver);
 }
 
 module_init(pdc202new_ide_init);
diff --git a/drivers/ide/pci/pdc202xx_old.c b/drivers/ide/pci/pdc202xx_old.c
index de9a274..799557c 100644
--- a/drivers/ide/pci/pdc202xx_old.c
+++ b/drivers/ide/pci/pdc202xx_old.c
@@ -13,7 +13,6 @@
 #include <linux/kernel.h>
 #include <linux/delay.h>
 #include <linux/blkdev.h>
-#include <linux/hdreg.h>
 #include <linux/pci.h>
 #include <linux/init.h>
 #include <linux/ide.h>
@@ -86,7 +85,7 @@
 		 * Prefetch_EN / IORDY_EN / PA[3:0] bits of register A
 		 */
 		AP &= ~0x3f;
-		if (drive->id->capability & 4)
+		if (ata_id_iordy_disable(drive->id))
 			AP |= 0x20;	/* set IORDY_EN bit */
 		if (drive->media == ide_disk)
 			AP |= 0x10;	/* set Prefetch_EN bit */
@@ -154,10 +153,10 @@
 
 static void pdc202xx_quirkproc(ide_drive_t *drive)
 {
-	const char **list, *model = drive->id->model;
+	const char **list, *m = (char *)&drive->id[ATA_ID_PROD];
 
 	for (list = pdc_quirk_drives; *list != NULL; list++)
-		if (strstr(model, *list) != NULL) {
+		if (strstr(m, *list) != NULL) {
 			drive->quirk_list = 2;
 			return;
 		}
@@ -169,7 +168,7 @@
 {
 	if (drive->current_speed > XFER_UDMA_2)
 		pdc_old_enable_66MHz_clock(drive->hwif);
-	if (drive->media != ide_disk || drive->addressing == 1) {
+	if (drive->media != ide_disk || (drive->dev_flags & IDE_DFLAG_LBA48)) {
 		struct request *rq	= HWGROUP(drive)->rq;
 		ide_hwif_t *hwif	= HWIF(drive);
 		unsigned long high_16	= hwif->extra_base - 16;
@@ -189,7 +188,7 @@
 
 static int pdc202xx_dma_end(ide_drive_t *drive)
 {
-	if (drive->media != ide_disk || drive->addressing == 1) {
+	if (drive->media != ide_disk || (drive->dev_flags & IDE_DFLAG_LBA48)) {
 		ide_hwif_t *hwif	= HWIF(drive);
 		unsigned long high_16	= hwif->extra_base - 16;
 		unsigned long atapi_reg	= high_16 + (hwif->channel ? 0x24 : 0x20);
@@ -201,7 +200,7 @@
 	}
 	if (drive->current_speed > XFER_UDMA_2)
 		pdc_old_disable_66MHz_clock(drive->hwif);
-	return __ide_dma_end(drive);
+	return ide_dma_end(drive);
 }
 
 static int pdc202xx_dma_test_irq(ide_drive_t *drive)
@@ -265,7 +264,7 @@
 	ide_dma_timeout(drive);
 }
 
-static unsigned int __devinit init_chipset_pdc202xx(struct pci_dev *dev)
+static unsigned int init_chipset_pdc202xx(struct pci_dev *dev)
 {
 	unsigned long dmabase = pci_resource_start(dev, 4);
 	u8 udma_speed_flag = 0, primary_mode = 0, secondary_mode = 0;
@@ -334,7 +333,7 @@
 	.dma_setup		= ide_dma_setup,
 	.dma_exec_cmd		= ide_dma_exec_cmd,
 	.dma_start		= ide_dma_start,
-	.dma_end		= __ide_dma_end,
+	.dma_end		= ide_dma_end,
 	.dma_test_irq		= pdc202xx_dma_test_irq,
 	.dma_lost_irq		= pdc202xx_dma_lost_irq,
 	.dma_timeout		= pdc202xx_dma_timeout,
@@ -427,21 +426,23 @@
 };
 MODULE_DEVICE_TABLE(pci, pdc202xx_pci_tbl);
 
-static struct pci_driver driver = {
+static struct pci_driver pdc202xx_pci_driver = {
 	.name		= "Promise_Old_IDE",
 	.id_table	= pdc202xx_pci_tbl,
 	.probe		= pdc202xx_init_one,
 	.remove		= ide_pci_remove,
+	.suspend	= ide_pci_suspend,
+	.resume		= ide_pci_resume,
 };
 
 static int __init pdc202xx_ide_init(void)
 {
-	return ide_pci_register_driver(&driver);
+	return ide_pci_register_driver(&pdc202xx_pci_driver);
 }
 
 static void __exit pdc202xx_ide_exit(void)
 {
-	pci_unregister_driver(&driver);
+	pci_unregister_driver(&pdc202xx_pci_driver);
 }
 
 module_init(pdc202xx_ide_init);
diff --git a/drivers/ide/pci/piix.c b/drivers/ide/pci/piix.c
index 30cfc81..d63f9fd 100644
--- a/drivers/ide/pci/piix.c
+++ b/drivers/ide/pci/piix.c
@@ -48,7 +48,6 @@
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/pci.h>
-#include <linux/hdreg.h>
 #include <linux/ide.h>
 #include <linux/init.h>
 
@@ -205,7 +204,7 @@
  *	out to be nice and simple.
  */
 
-static unsigned int __devinit init_chipset_ich(struct pci_dev *dev)
+static unsigned int init_chipset_ich(struct pci_dev *dev)
 {
 	u32 extra = 0;
 
@@ -216,17 +215,26 @@
 }
 
 /**
- *	piix_dma_clear_irq	-	clear BMDMA status
- *	@drive: IDE drive to clear
+ *	ich_clear_irq	-	clear BMDMA status
+ *	@drive: IDE drive
  *
- *	Called from ide_intr() for PIO interrupts
- *	to clear BMDMA status as needed by ICHx
+ *	ICHx contollers set DMA INTR no matter DMA or PIO.
+ *	BMDMA status might need to be cleared even for
+ *	PIO interrupts to prevent spurious/lost IRQ.
  */
-static void piix_dma_clear_irq(ide_drive_t *drive)
+static void ich_clear_irq(ide_drive_t *drive)
 {
 	ide_hwif_t *hwif = HWIF(drive);
 	u8 dma_stat;
 
+	/*
+	 * ide_dma_end() needs BMDMA status for error checking.
+	 * So, skip clearing BMDMA status here and leave it
+	 * to ide_dma_end() if this is DMA interrupt.
+	 */
+	if (drive->waiting_for_dma || hwif->dma_base == 0)
+		return;
+
 	/* clear the INTR & ERROR bits */
 	dma_stat = inb(hwif->dma_base + ATA_DMA_STATUS);
 	/* Should we force the bit as well ? */
@@ -250,6 +258,7 @@
 	{ 0x27DF, 0x1025, 0x0110 },	/* ICH7 on Acer 3682WLMi */
 	{ 0x27DF, 0x1043, 0x1267 },	/* ICH7 on Asus W5F */
 	{ 0x27DF, 0x103C, 0x30A1 },	/* ICH7 on HP Compaq nc2400 */
+	{ 0x27DF, 0x1071, 0xD221 },	/* ICH7 on Hercules EC-900 */
 	{ 0x24CA, 0x1025, 0x0061 },	/* ICH4 on Acer Aspire 2023WLMi */
 	{ 0x2653, 0x1043, 0x82D8 },	/* ICH6M on Asus Eee 701 */
 	/* end marker */
@@ -294,21 +303,19 @@
 		hwif->ultra_mask = hwif->mwdma_mask = hwif->swdma_mask = 0;
 }
 
-static void __devinit init_hwif_ich(ide_hwif_t *hwif)
-{
-	init_hwif_piix(hwif);
-
-	/* ICHx need to clear the BMDMA status for all interrupts */
-	if (hwif->dma_base)
-		hwif->ide_dma_clear_irq = &piix_dma_clear_irq;
-}
-
 static const struct ide_port_ops piix_port_ops = {
 	.set_pio_mode		= piix_set_pio_mode,
 	.set_dma_mode		= piix_set_dma_mode,
 	.cable_detect		= piix_cable_detect,
 };
 
+static const struct ide_port_ops ich_port_ops = {
+	.set_pio_mode		= piix_set_pio_mode,
+	.set_dma_mode		= piix_set_dma_mode,
+	.clear_irq		= ich_clear_irq,
+	.cable_detect		= piix_cable_detect,
+};
+
 #ifndef CONFIG_IA64
  #define IDE_HFLAGS_PIIX IDE_HFLAG_LEGACY_IRQS
 #else
@@ -332,9 +339,9 @@
 	{ \
 		.name		= DRV_NAME, \
 		.init_chipset	= init_chipset_ich, \
-		.init_hwif	= init_hwif_ich, \
+		.init_hwif	= init_hwif_piix, \
 		.enablebits	= {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, \
-		.port_ops	= &piix_port_ops, \
+		.port_ops	= &ich_port_ops, \
 		.host_flags	= IDE_HFLAGS_PIIX, \
 		.pio_mask	= ATA_PIO4, \
 		.swdma_mask	= ATA_SWDMA2_ONLY, \
@@ -445,22 +452,24 @@
 };
 MODULE_DEVICE_TABLE(pci, piix_pci_tbl);
 
-static struct pci_driver driver = {
+static struct pci_driver piix_pci_driver = {
 	.name		= "PIIX_IDE",
 	.id_table	= piix_pci_tbl,
 	.probe		= piix_init_one,
 	.remove		= ide_pci_remove,
+	.suspend	= ide_pci_suspend,
+	.resume		= ide_pci_resume,
 };
 
 static int __init piix_ide_init(void)
 {
 	piix_check_450nx();
-	return ide_pci_register_driver(&driver);
+	return ide_pci_register_driver(&piix_pci_driver);
 }
 
 static void __exit piix_ide_exit(void)
 {
-	pci_unregister_driver(&driver);
+	pci_unregister_driver(&piix_pci_driver);
 }
 
 module_init(piix_ide_init);
diff --git a/drivers/ide/pci/rz1000.c b/drivers/ide/pci/rz1000.c
index 8d11ee8..7daf013 100644
--- a/drivers/ide/pci/rz1000.c
+++ b/drivers/ide/pci/rz1000.c
@@ -16,7 +16,6 @@
 #include <linux/types.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
-#include <linux/hdreg.h>
 #include <linux/pci.h>
 #include <linux/ide.h>
 #include <linux/init.h>
@@ -60,7 +59,7 @@
 };
 MODULE_DEVICE_TABLE(pci, rz1000_pci_tbl);
 
-static struct pci_driver driver = {
+static struct pci_driver rz1000_pci_driver = {
 	.name		= "RZ1000_IDE",
 	.id_table	= rz1000_pci_tbl,
 	.probe		= rz1000_init_one,
@@ -69,12 +68,12 @@
 
 static int __init rz1000_ide_init(void)
 {
-	return ide_pci_register_driver(&driver);
+	return ide_pci_register_driver(&rz1000_pci_driver);
 }
 
 static void __exit rz1000_ide_exit(void)
 {
-	pci_unregister_driver(&driver);
+	pci_unregister_driver(&rz1000_pci_driver);
 }
 
 module_init(rz1000_ide_init);
diff --git a/drivers/ide/pci/sc1200.c b/drivers/ide/pci/sc1200.c
index 8efaed1..f1a8758 100644
--- a/drivers/ide/pci/sc1200.c
+++ b/drivers/ide/pci/sc1200.c
@@ -14,7 +14,6 @@
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
-#include <linux/hdreg.h>
 #include <linux/pci.h>
 #include <linux/init.h>
 #include <linux/ide.h>
@@ -104,17 +103,19 @@
 static u8 sc1200_udma_filter(ide_drive_t *drive)
 {
 	ide_hwif_t *hwif = drive->hwif;
-	ide_drive_t *mate = &hwif->drives[(drive->dn & 1) ^ 1];
-	struct hd_driveid *mateid = mate->id;
+	ide_drive_t *mate = ide_get_pair_dev(drive);
+	u16 *mateid = mate->id;
 	u8 mask = hwif->ultra_mask;
 
-	if (mate->present == 0)
+	if (mate == NULL)
 		goto out;
 
-	if ((mateid->capability & 1) && __ide_dma_bad_drive(mate) == 0) {
-		if ((mateid->field_valid & 4) && (mateid->dma_ultra & 7))
+	if (ata_id_has_dma(mateid) && __ide_dma_bad_drive(mate) == 0) {
+		if ((mateid[ATA_ID_FIELD_VALID] & 4) &&
+		    (mateid[ATA_ID_UDMA_MODES] & 7))
 			goto out;
-		if ((mateid->field_valid & 2) && (mateid->dma_mword & 7))
+		if ((mateid[ATA_ID_FIELD_VALID] & 2) &&
+		    (mateid[ATA_ID_MWDMA_MODES] & 7))
 			mask = 0;
 	}
 out:
@@ -125,7 +126,6 @@
 {
 	ide_hwif_t		*hwif = HWIF(drive);
 	struct pci_dev		*dev = to_pci_dev(hwif->dev);
-	int			unit = drive->select.b.unit;
 	unsigned int		reg, timings;
 	unsigned short		pci_clock;
 	unsigned int		basereg = hwif->channel ? 0x50 : 0x40;
@@ -154,7 +154,7 @@
 	else
 		timings = mwdma_timing[pci_clock][mode - XFER_MW_DMA_0];
 
-	if (unit == 0) {			/* are we configuring drive0? */
+	if ((drive->dn & 1) == 0) {
 		pci_read_config_dword(dev, basereg + 4, &reg);
 		timings |= reg & 0x80000000;	/* preserve PIO format bit */
 		pci_write_config_dword(dev, basereg + 4, timings);
@@ -215,7 +215,8 @@
 	if (mode != -1) {
 		printk("SC1200: %s: changing (U)DMA mode\n", drive->name);
 		ide_dma_off_quietly(drive);
-		if (ide_set_dma_mode(drive, mode) == 0 && drive->using_dma)
+		if (ide_set_dma_mode(drive, mode) == 0 &&
+		    (drive->dev_flags & IDE_DFLAG_USING_DMA))
 			hwif->dma_ops->dma_host_set(drive, 1);
 		return;
 	}
@@ -327,7 +328,7 @@
 };
 MODULE_DEVICE_TABLE(pci, sc1200_pci_tbl);
 
-static struct pci_driver driver = {
+static struct pci_driver sc1200_pci_driver = {
 	.name		= "SC1200_IDE",
 	.id_table	= sc1200_pci_tbl,
 	.probe		= sc1200_init_one,
@@ -340,12 +341,12 @@
 
 static int __init sc1200_ide_init(void)
 {
-	return ide_pci_register_driver(&driver);
+	return ide_pci_register_driver(&sc1200_pci_driver);
 }
 
 static void __exit sc1200_ide_exit(void)
 {
-	pci_unregister_driver(&driver);
+	pci_unregister_driver(&sc1200_pci_driver);
 }
 
 module_init(sc1200_ide_init);
diff --git a/drivers/ide/pci/scc_pata.c b/drivers/ide/pci/scc_pata.c
index 44cccd1..9ce1d80 100644
--- a/drivers/ide/pci/scc_pata.c
+++ b/drivers/ide/pci/scc_pata.c
@@ -26,7 +26,6 @@
 #include <linux/module.h>
 #include <linux/pci.h>
 #include <linux/delay.h>
-#include <linux/hdreg.h>
 #include <linux/ide.h>
 #include <linux/init.h>
 
@@ -292,7 +291,7 @@
 static void scc_dma_host_set(ide_drive_t *drive, int on)
 {
 	ide_hwif_t *hwif = drive->hwif;
-	u8 unit = (drive->select.b.unit & 0x01);
+	u8 unit = drive->dn & 1;
 	u8 dma_stat = scc_ide_inb(hwif->dma_base + 4);
 
 	if (on)
@@ -354,7 +353,6 @@
 
 	/* start DMA */
 	scc_ide_outb(dma_cmd | 1, hwif->dma_base);
-	hwif->dma = 1;
 	wmb();
 }
 
@@ -375,7 +373,6 @@
 	/* purge DMA mappings */
 	ide_destroy_dmatable(drive);
 	/* verify good DMA status */
-	hwif->dma = 0;
 	wmb();
 	return (dma_stat & 7) != 4 ? (0x10 | dma_stat) : 0;
 }
@@ -400,7 +397,7 @@
 	/* errata A308 workaround: Step5 (check data loss) */
 	/* We don't check non ide_disk because it is limited to UDMA4 */
 	if (!(in_be32((void __iomem *)hwif->io_ports.ctl_addr)
-	      & ERR_STAT) &&
+	      & ATA_ERR) &&
 	    drive->media == ide_disk && drive->current_speed > XFER_UDMA_4) {
 		reg = in_be32((void __iomem *)intsts_port);
 		if (!(reg & INTSTS_ACTEINT)) {
@@ -504,7 +501,7 @@
 
 	/* SCC errata A252,A308 workaround: Step4 */
 	if ((in_be32((void __iomem *)hwif->io_ports.ctl_addr)
-	     & ERR_STAT) &&
+	     & ATA_ERR) &&
 	    (int_stat & INTSTS_INTRQ))
 		return 1;
 
@@ -512,9 +509,6 @@
 	if (int_stat & INTSTS_IOIRQS)
 		return 1;
 
-	if (!drive->waiting_for_dma)
-		printk(KERN_WARNING "%s: (%s) called while not waiting\n",
-			drive->name, __func__);
 	return 0;
 }
 
@@ -711,7 +705,7 @@
 		scc_ide_outb(tf->lbah, io_ports->lbah_addr);
 
 	if (task->tf_flags & IDE_TFLAG_OUT_DEVICE)
-		scc_ide_outb((tf->device & HIHI) | drive->select.all,
+		scc_ide_outb((tf->device & HIHI) | drive->select,
 			     io_ports->device_addr);
 }
 
@@ -827,6 +821,12 @@
 	init_mmio_iops_scc(hwif);
 }
 
+static int __devinit scc_init_dma(ide_hwif_t *hwif,
+				  const struct ide_port_info *d)
+{
+	return ide_allocate_dma_engine(hwif);
+}
+
 static u8 scc_cable_detect(ide_hwif_t *hwif)
 {
 	return ATA_CBL_PATA80;
@@ -891,6 +891,7 @@
   {							\
       .name		= name_str,			\
       .init_iops	= init_iops_scc,		\
+      .init_dma		= scc_init_dma,			\
       .init_hwif	= init_hwif_scc,		\
       .tp_ops		= &scc_tp_ops,		\
       .port_ops		= &scc_port_ops,		\
@@ -928,13 +929,6 @@
 {
 	struct scc_ports *ports = pci_get_drvdata(dev);
 	struct ide_host *host = ports->host;
-	ide_hwif_t *hwif = host->ports[0];
-
-	if (hwif->dmatable_cpu) {
-		pci_free_consistent(dev, PRD_ENTRIES * PRD_BYTES,
-				    hwif->dmatable_cpu, hwif->dmatable_dma);
-		hwif->dmatable_cpu = NULL;
-	}
 
 	ide_host_remove(host);
 
@@ -950,7 +944,7 @@
 };
 MODULE_DEVICE_TABLE(pci, scc_pci_tbl);
 
-static struct pci_driver driver = {
+static struct pci_driver scc_pci_driver = {
 	.name = "SCC IDE",
 	.id_table = scc_pci_tbl,
 	.probe = scc_init_one,
@@ -959,14 +953,14 @@
 
 static int scc_ide_init(void)
 {
-	return ide_pci_register_driver(&driver);
+	return ide_pci_register_driver(&scc_pci_driver);
 }
 
 module_init(scc_ide_init);
 /* -- No exit code?
 static void scc_ide_exit(void)
 {
-	ide_pci_unregister_driver(&driver);
+	ide_pci_unregister_driver(&scc_pci_driver);
 }
 module_exit(scc_ide_exit);
  */
diff --git a/drivers/ide/pci/serverworks.c b/drivers/ide/pci/serverworks.c
index c3bdc6e..437bc91 100644
--- a/drivers/ide/pci/serverworks.c
+++ b/drivers/ide/pci/serverworks.c
@@ -32,7 +32,6 @@
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/pci.h>
-#include <linux/hdreg.h>
 #include <linux/ide.h>
 #include <linux/init.h>
 
@@ -57,8 +56,10 @@
 
 static int check_in_drive_lists (ide_drive_t *drive, const char **list)
 {
+	char *m = (char *)&drive->id[ATA_ID_PROD];
+
 	while (*list)
-		if (!strcmp(*list++, drive->id->model))
+		if (!strcmp(*list++, m))
 			return 1;
 	return 0;
 }
@@ -152,7 +153,7 @@
 
 	ide_hwif_t *hwif	= HWIF(drive);
 	struct pci_dev *dev	= to_pci_dev(hwif->dev);
-	u8 unit			= (drive->select.b.unit & 0x01);
+	u8 unit			= drive->dn & 1;
 
 	u8 ultra_enable	 = 0, ultra_timing = 0, dma_timing = 0;
 
@@ -174,7 +175,7 @@
 	pci_write_config_byte(dev, 0x54, ultra_enable);
 }
 
-static unsigned int __devinit init_chipset_svwks(struct pci_dev *dev)
+static unsigned int init_chipset_svwks(struct pci_dev *dev)
 {
 	unsigned int reg;
 	u8 btr;
@@ -442,21 +443,23 @@
 };
 MODULE_DEVICE_TABLE(pci, svwks_pci_tbl);
 
-static struct pci_driver driver = {
+static struct pci_driver svwks_pci_driver = {
 	.name		= "Serverworks_IDE",
 	.id_table	= svwks_pci_tbl,
 	.probe		= svwks_init_one,
 	.remove		= ide_pci_remove,
+	.suspend	= ide_pci_suspend,
+	.resume		= ide_pci_resume,
 };
 
 static int __init svwks_ide_init(void)
 {
-	return ide_pci_register_driver(&driver);
+	return ide_pci_register_driver(&svwks_pci_driver);
 }
 
 static void __exit svwks_ide_exit(void)
 {
-	pci_unregister_driver(&driver);
+	pci_unregister_driver(&svwks_pci_driver);
 }
 
 module_init(svwks_ide_init);
diff --git a/drivers/ide/pci/sgiioc4.c b/drivers/ide/pci/sgiioc4.c
index 681306c..dd63454 100644
--- a/drivers/ide/pci/sgiioc4.c
+++ b/drivers/ide/pci/sgiioc4.c
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2003-2006 Silicon Graphics, Inc.  All Rights Reserved.
+ * Copyright (C) 2008 MontaVista Software, Inc.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of version 2 of the GNU General Public License
@@ -22,7 +23,6 @@
 #include <linux/types.h>
 #include <linux/pci.h>
 #include <linux/delay.h>
-#include <linux/hdreg.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/ioport.h>
@@ -151,7 +151,7 @@
 		int count = 0;
 
 		stat = sgiioc4_read_status(hwif);
-		while ((stat & 0x80) && (count++ < 100)) {
+		while ((stat & ATA_BUSY) && (count++ < 100)) {
 			udelay(1);
 			stat = sgiioc4_read_status(hwif);
 		}
@@ -311,7 +311,7 @@
 	u8 reg = (u8) readb((void __iomem *) port);
 
 	if ((port & 0xFFF) == 0x11C) {	/* Status register of IOC4 */
-		if (reg & 0x51) {	/* Not busy...check for interrupt */
+		if (!(reg & ATA_BUSY)) { /* Not busy... check for interrupt */
 			unsigned long other_ir = port - 0x110;
 			unsigned int intr_reg = (u32) readl((void __iomem *) other_ir);
 
@@ -339,36 +339,32 @@
 	if (dma_base == 0)
 		return -1;
 
-	printk(KERN_INFO "%s: BM-DMA at 0x%04lx-0x%04lx\n", hwif->name,
-	       dma_base, dma_base + num_ports - 1);
+	printk(KERN_INFO "    %s: MMIO-DMA\n", hwif->name);
 
-	if (!request_mem_region(dma_base, num_ports, hwif->name)) {
-		printk(KERN_ERR
-		       "%s(%s) -- ERROR, Addresses 0x%p to 0x%p "
-		       "ALREADY in use\n",
-		       __func__, hwif->name, (void *) dma_base,
-		       (void *) dma_base + num_ports - 1);
+	if (request_mem_region(dma_base, num_ports, hwif->name) == NULL) {
+		printk(KERN_ERR "%s(%s) -- ERROR: addresses 0x%08lx to 0x%08lx "
+		       "already in use\n", __func__, hwif->name,
+		       dma_base, dma_base + num_ports - 1);
 		return -1;
 	}
 
 	virt_dma_base = ioremap(dma_base, num_ports);
 	if (virt_dma_base == NULL) {
-		printk(KERN_ERR
-		       "%s(%s) -- ERROR, Unable to map addresses 0x%lx to 0x%lx\n",
-		       __func__, hwif->name, dma_base, dma_base + num_ports - 1);
+		printk(KERN_ERR "%s(%s) -- ERROR: unable to map addresses "
+		       "0x%lx to 0x%lx\n", __func__, hwif->name,
+		       dma_base, dma_base + num_ports - 1);
 		goto dma_remap_failure;
 	}
 	hwif->dma_base = (unsigned long) virt_dma_base;
 
-	hwif->dmatable_cpu = pci_alloc_consistent(dev,
-					  IOC4_PRD_ENTRIES * IOC4_PRD_BYTES,
-					  &hwif->dmatable_dma);
-
-	if (!hwif->dmatable_cpu)
-		goto dma_pci_alloc_failure;
-
 	hwif->sg_max_nents = IOC4_PRD_ENTRIES;
 
+	hwif->prd_max_nents = IOC4_PRD_ENTRIES;
+	hwif->prd_ent_size = IOC4_PRD_BYTES;
+
+	if (ide_allocate_dma_engine(hwif))
+		goto dma_pci_alloc_failure;
+
 	pad = pci_alloc_consistent(dev, IOC4_IDE_CACHELINE_SIZE,
 				   (dma_addr_t *)&hwif->extra_base);
 	if (pad) {
@@ -376,13 +372,11 @@
 		return 0;
 	}
 
-	pci_free_consistent(dev, IOC4_PRD_ENTRIES * IOC4_PRD_BYTES,
-			    hwif->dmatable_cpu, hwif->dmatable_dma);
-	printk(KERN_INFO
-	       "%s() -- Error! Unable to allocate DMA Maps for drive %s\n",
+	ide_release_dma_engine(hwif);
+
+	printk(KERN_ERR "%s(%s) -- ERROR: Unable to allocate DMA maps\n",
 	       __func__, hwif->name);
-	printk(KERN_INFO
-	       "Changing from DMA to PIO mode for Drive %s\n", hwif->name);
+	printk(KERN_INFO "%s: changing from DMA to PIO mode", hwif->name);
 
 dma_pci_alloc_failure:
 	iounmap(virt_dma_base);
@@ -618,14 +612,12 @@
 	irqport = (unsigned long) virt_base + IOC4_INTR_OFFSET;
 
 	cmd_phys_base = bar0 + IOC4_CMD_OFFSET;
-	if (!request_mem_region(cmd_phys_base, IOC4_CMD_CTL_BLK_SIZE,
-	    DRV_NAME)) {
-		printk(KERN_ERR
-			"%s %s: -- ERROR, Addresses "
-			"0x%p to 0x%p ALREADY in use\n",
-		       DRV_NAME, pci_name(dev), (void *)cmd_phys_base,
-		       (void *) cmd_phys_base + IOC4_CMD_CTL_BLK_SIZE);
-		return -ENOMEM;
+	if (request_mem_region(cmd_phys_base, IOC4_CMD_CTL_BLK_SIZE,
+			       DRV_NAME) == NULL) {
+		printk(KERN_ERR "%s %s -- ERROR: addresses 0x%08lx to 0x%08lx "
+		       "already in use\n", DRV_NAME, pci_name(dev),
+		       cmd_phys_base, cmd_phys_base + IOC4_CMD_CTL_BLK_SIZE);
+		return -EBUSY;
 	}
 
 	/* Initialize the IO registers */
diff --git a/drivers/ide/pci/siimage.c b/drivers/ide/pci/siimage.c
index db2b88a..eb4faf9 100644
--- a/drivers/ide/pci/siimage.c
+++ b/drivers/ide/pci/siimage.c
@@ -39,7 +39,6 @@
 #include <linux/types.h>
 #include <linux/module.h>
 #include <linux/pci.h>
-#include <linux/hdreg.h>
 #include <linux/ide.h>
 #include <linux/init.h>
 #include <linux/io.h>
@@ -117,13 +116,14 @@
 {
 	ide_hwif_t *hwif	= HWIF(drive);
 	unsigned long base	= (unsigned long)hwif->hwif_data;
+	u8 unit			= drive->dn & 1;
 
 	base += 0xA0 + r;
 	if (hwif->host_flags & IDE_HFLAG_MMIO)
 		base += hwif->channel << 6;
 	else
 		base += hwif->channel << 4;
-	base |= drive->select.b.unit << drive->select.b.unit;
+	base |= unit << unit;
 	return base;
 }
 
@@ -223,7 +223,9 @@
 
 static u8 sil_sata_udma_filter(ide_drive_t *drive)
 {
-	return strstr(drive->id->model, "Maxtor") ? ATA_UDMA5 : ATA_UDMA6;
+	char *m = (char *)&drive->id[ATA_ID_PROD];
+
+	return strstr(m, "Maxtor") ? ATA_UDMA5 : ATA_UDMA6;
 }
 
 /**
@@ -243,7 +245,7 @@
 
 	ide_hwif_t *hwif	= HWIF(drive);
 	struct pci_dev *dev	= to_pci_dev(hwif->dev);
-	ide_drive_t *pair	= ide_get_paired_drive(drive);
+	ide_drive_t *pair	= ide_get_pair_dev(drive);
 	u32 speedt		= 0;
 	u16 speedp		= 0;
 	unsigned long addr	= siimage_seldev(drive, 0x04);
@@ -254,10 +256,10 @@
 	u8 addr_mask		= hwif->channel ? (mmio ? 0xF4 : 0x84)
 						: (mmio ? 0xB4 : 0x80);
 	u8 mode			= 0;
-	u8 unit			= drive->select.b.unit;
+	u8 unit			= drive->dn & 1;
 
 	/* trim *taskfile* PIO to the slowest of the master/slave */
-	if (pair->present) {
+	if (pair) {
 		u8 pair_pio = ide_get_best_pio_mode(pair, 255, 4);
 
 		if (pair_pio < tf_pio)
@@ -300,9 +302,9 @@
 
 	ide_hwif_t *hwif	= HWIF(drive);
 	struct pci_dev *dev	= to_pci_dev(hwif->dev);
-	u16 ultra = 0, multi	= 0;
-	u8 mode = 0, unit	= drive->select.b.unit;
 	unsigned long base	= (unsigned long)hwif->hwif_data;
+	u16 ultra = 0, multi	= 0;
+	u8 mode = 0, unit	= drive->dn & 1;
 	u8 mmio			= (hwif->host_flags & IDE_HFLAG_MMIO) ? 1 : 0;
 	u8 scsc = 0, addr_mask	= hwif->channel ? (mmio ? 0xF4 : 0x84)
 						: (mmio ? 0xB4 : 0x80);
@@ -462,7 +464,7 @@
  *	to 133 MHz clocking if the system isn't already set up to do it.
  */
 
-static unsigned int __devinit init_chipset_siimage(struct pci_dev *dev)
+static unsigned int init_chipset_siimage(struct pci_dev *dev)
 {
 	struct ide_host *host = pci_get_drvdata(dev);
 	void __iomem *ioaddr = host->host_priv;
@@ -616,8 +618,8 @@
 
 static int is_dev_seagate_sata(ide_drive_t *drive)
 {
-	const char *s	= &drive->id->model[0];
-	unsigned len	= strnlen(s, sizeof(drive->id->model));
+	const char *s	= (const char *)&drive->id[ATA_ID_PROD];
+	unsigned len	= strnlen(s, ATA_ID_PROD_LEN);
 
 	if ((len > 4) && (!memcmp(s, "ST", 2)))
 		if ((!memcmp(s + len - 2, "AS", 2)) ||
@@ -711,7 +713,7 @@
 	.dma_setup		= ide_dma_setup,
 	.dma_exec_cmd		= ide_dma_exec_cmd,
 	.dma_start		= ide_dma_start,
-	.dma_end		= __ide_dma_end,
+	.dma_end		= ide_dma_end,
 	.dma_test_irq		= siimage_dma_test_irq,
 	.dma_timeout		= ide_dma_timeout,
 	.dma_lost_irq		= ide_dma_lost_irq,
@@ -828,21 +830,23 @@
 };
 MODULE_DEVICE_TABLE(pci, siimage_pci_tbl);
 
-static struct pci_driver driver = {
+static struct pci_driver siimage_pci_driver = {
 	.name		= "SiI_IDE",
 	.id_table	= siimage_pci_tbl,
 	.probe		= siimage_init_one,
 	.remove		= __devexit_p(siimage_remove),
+	.suspend	= ide_pci_suspend,
+	.resume		= ide_pci_resume,
 };
 
 static int __init siimage_ide_init(void)
 {
-	return ide_pci_register_driver(&driver);
+	return ide_pci_register_driver(&siimage_pci_driver);
 }
 
 static void __exit siimage_ide_exit(void)
 {
-	pci_unregister_driver(&driver);
+	pci_unregister_driver(&siimage_pci_driver);
 }
 
 module_init(siimage_ide_init);
diff --git a/drivers/ide/pci/sis5513.c b/drivers/ide/pci/sis5513.c
index 5efe21d..ad32e18 100644
--- a/drivers/ide/pci/sis5513.c
+++ b/drivers/ide/pci/sis5513.c
@@ -47,7 +47,6 @@
 #include <linux/types.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
-#include <linux/hdreg.h>
 #include <linux/pci.h>
 #include <linux/init.h>
 #include <linux/ide.h>
@@ -448,7 +447,7 @@
 	return chipset_family;
 }
 
-static unsigned int __devinit init_chipset_sis5513(struct pci_dev *dev)
+static unsigned int init_chipset_sis5513(struct pci_dev *dev)
 {
 	/* Make general config ops here
 	   1/ tell IDE channels to operate in Compatibility mode only
@@ -606,21 +605,23 @@
 };
 MODULE_DEVICE_TABLE(pci, sis5513_pci_tbl);
 
-static struct pci_driver driver = {
+static struct pci_driver sis5513_pci_driver = {
 	.name		= "SIS_IDE",
 	.id_table	= sis5513_pci_tbl,
 	.probe		= sis5513_init_one,
 	.remove		= __devexit_p(sis5513_remove),
+	.suspend	= ide_pci_suspend,
+	.resume		= ide_pci_resume,
 };
 
 static int __init sis5513_ide_init(void)
 {
-	return ide_pci_register_driver(&driver);
+	return ide_pci_register_driver(&sis5513_pci_driver);
 }
 
 static void __exit sis5513_ide_exit(void)
 {
-	pci_unregister_driver(&driver);
+	pci_unregister_driver(&sis5513_pci_driver);
 }
 
 module_init(sis5513_ide_init);
diff --git a/drivers/ide/pci/sl82c105.c b/drivers/ide/pci/sl82c105.c
index 73905bc..84dc336 100644
--- a/drivers/ide/pci/sl82c105.c
+++ b/drivers/ide/pci/sl82c105.c
@@ -17,7 +17,6 @@
 #include <linux/types.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
-#include <linux/hdreg.h>
 #include <linux/pci.h>
 #include <linux/ide.h>
 
@@ -62,7 +61,7 @@
 	if (cmd_off == 0)
 		cmd_off = 1;
 
-	if (pio > 2 || ide_dev_has_iordy(drive->id))
+	if (pio > 2 || ata_id_has_iordy(drive->id))
 		iordy = 0x40;
 
 	return (cmd_on - 1) << 8 | (cmd_off - 1) | iordy;
@@ -208,7 +207,7 @@
 
 	DBG(("%s(drive:%s)\n", __func__, drive->name));
 
-	ret = __ide_dma_end(drive);
+	ret = ide_dma_end(drive);
 
 	pci_write_config_word(dev, reg, drive->drive_data);
 
@@ -272,7 +271,7 @@
  * channel 0 here at least, but channel 1 has to be enabled by
  * firmware or arch code. We still set both to 16 bits mode.
  */
-static unsigned int __devinit init_chipset_sl82c105(struct pci_dev *dev)
+static unsigned int init_chipset_sl82c105(struct pci_dev *dev)
 {
 	u32 val;
 
@@ -346,21 +345,23 @@
 };
 MODULE_DEVICE_TABLE(pci, sl82c105_pci_tbl);
 
-static struct pci_driver driver = {
+static struct pci_driver sl82c105_pci_driver = {
 	.name		= "W82C105_IDE",
 	.id_table	= sl82c105_pci_tbl,
 	.probe		= sl82c105_init_one,
 	.remove		= ide_pci_remove,
+	.suspend	= ide_pci_suspend,
+	.resume		= ide_pci_resume,
 };
 
 static int __init sl82c105_ide_init(void)
 {
-	return ide_pci_register_driver(&driver);
+	return ide_pci_register_driver(&sl82c105_pci_driver);
 }
 
 static void __exit sl82c105_ide_exit(void)
 {
-	pci_unregister_driver(&driver);
+	pci_unregister_driver(&sl82c105_pci_driver);
 }
 
 module_init(sl82c105_ide_init);
diff --git a/drivers/ide/pci/slc90e66.c b/drivers/ide/pci/slc90e66.c
index 866d6c6..0f759e4 100644
--- a/drivers/ide/pci/slc90e66.c
+++ b/drivers/ide/pci/slc90e66.c
@@ -11,7 +11,6 @@
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/pci.h>
-#include <linux/hdreg.h>
 #include <linux/ide.h>
 #include <linux/init.h>
 
@@ -155,21 +154,23 @@
 };
 MODULE_DEVICE_TABLE(pci, slc90e66_pci_tbl);
 
-static struct pci_driver driver = {
+static struct pci_driver slc90e66_pci_driver = {
 	.name		= "SLC90e66_IDE",
 	.id_table	= slc90e66_pci_tbl,
 	.probe		= slc90e66_init_one,
 	.remove		= ide_pci_remove,
+	.suspend	= ide_pci_suspend,
+	.resume		= ide_pci_resume,
 };
 
 static int __init slc90e66_ide_init(void)
 {
-	return ide_pci_register_driver(&driver);
+	return ide_pci_register_driver(&slc90e66_pci_driver);
 }
 
 static void __exit slc90e66_ide_exit(void)
 {
-	pci_unregister_driver(&driver);
+	pci_unregister_driver(&slc90e66_pci_driver);
 }
 
 module_init(slc90e66_ide_init);
diff --git a/drivers/ide/pci/tc86c001.c b/drivers/ide/pci/tc86c001.c
index 927277c..93e2cce 100644
--- a/drivers/ide/pci/tc86c001.c
+++ b/drivers/ide/pci/tc86c001.c
@@ -186,7 +186,7 @@
 	.dma_setup		= ide_dma_setup,
 	.dma_exec_cmd		= ide_dma_exec_cmd,
 	.dma_start		= tc86c001_dma_start,
-	.dma_end		= __ide_dma_end,
+	.dma_end		= ide_dma_end,
 	.dma_test_irq		= ide_dma_test_irq,
 	.dma_lost_irq		= ide_dma_lost_irq,
 	.dma_timeout		= ide_dma_timeout,
@@ -245,7 +245,7 @@
 };
 MODULE_DEVICE_TABLE(pci, tc86c001_pci_tbl);
 
-static struct pci_driver driver = {
+static struct pci_driver tc86c001_pci_driver = {
 	.name		= "TC86C001",
 	.id_table	= tc86c001_pci_tbl,
 	.probe		= tc86c001_init_one,
@@ -254,12 +254,12 @@
 
 static int __init tc86c001_ide_init(void)
 {
-	return ide_pci_register_driver(&driver);
+	return ide_pci_register_driver(&tc86c001_pci_driver);
 }
 
 static void __exit tc86c001_ide_exit(void)
 {
-	pci_unregister_driver(&driver);
+	pci_unregister_driver(&tc86c001_pci_driver);
 }
 
 module_init(tc86c001_ide_init);
diff --git a/drivers/ide/pci/triflex.c b/drivers/ide/pci/triflex.c
index b77ec35..b6ff403 100644
--- a/drivers/ide/pci/triflex.c
+++ b/drivers/ide/pci/triflex.c
@@ -28,7 +28,6 @@
 #include <linux/types.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
-#include <linux/hdreg.h>
 #include <linux/pci.h>
 #include <linux/ide.h>
 #include <linux/init.h>
@@ -39,13 +38,12 @@
 {
 	ide_hwif_t *hwif = HWIF(drive);
 	struct pci_dev *dev = to_pci_dev(hwif->dev);
-	u8 channel_offset = hwif->channel ? 0x74 : 0x70;
-	u16 timing = 0;
 	u32 triflex_timings = 0;
-	u8 unit = (drive->select.b.unit & 0x01);
-	
+	u16 timing = 0;
+	u8 channel_offset = hwif->channel ? 0x74 : 0x70, unit = drive->dn & 1;
+
 	pci_read_config_dword(dev, channel_offset, &triflex_timings);
-	
+
 	switch(speed) {
 		case XFER_MW_DMA_2:
 			timing = 0x0103; 
@@ -115,21 +113,23 @@
 };
 MODULE_DEVICE_TABLE(pci, triflex_pci_tbl);
 
-static struct pci_driver driver = {
+static struct pci_driver triflex_pci_driver = {
 	.name		= "TRIFLEX_IDE",
 	.id_table	= triflex_pci_tbl,
 	.probe		= triflex_init_one,
 	.remove		= ide_pci_remove,
+	.suspend	= ide_pci_suspend,
+	.resume		= ide_pci_resume,
 };
 
 static int __init triflex_ide_init(void)
 {
-	return ide_pci_register_driver(&driver);
+	return ide_pci_register_driver(&triflex_pci_driver);
 }
 
 static void __exit triflex_ide_exit(void)
 {
-	pci_unregister_driver(&driver);
+	pci_unregister_driver(&triflex_pci_driver);
 }
 
 module_init(triflex_ide_init);
diff --git a/drivers/ide/pci/trm290.c b/drivers/ide/pci/trm290.c
index fd28b49..75ea615 100644
--- a/drivers/ide/pci/trm290.c
+++ b/drivers/ide/pci/trm290.c
@@ -135,7 +135,6 @@
 #include <linux/interrupt.h>
 #include <linux/blkdev.h>
 #include <linux/init.h>
-#include <linux/hdreg.h>
 #include <linux/pci.h>
 #include <linux/ide.h>
 
@@ -162,7 +161,7 @@
 	}
 
 	/* enable IRQ if not probing */
-	if (drive->present) {
+	if (drive->dev_flags & IDE_DFLAG_PRESENT) {
 		reg = inw(hwif->config_data + 3);
 		reg &= 0x13;
 		reg &= ~(1 << hwif->channel);
@@ -174,7 +173,7 @@
 
 static void trm290_selectproc (ide_drive_t *drive)
 {
-	trm290_prepare_drive(drive, drive->using_dma);
+	trm290_prepare_drive(drive, !!(drive->dev_flags & IDE_DFLAG_USING_DMA));
 }
 
 static void trm290_dma_exec_cmd(ide_drive_t *drive, u8 command)
@@ -351,7 +350,7 @@
 };
 MODULE_DEVICE_TABLE(pci, trm290_pci_tbl);
 
-static struct pci_driver driver = {
+static struct pci_driver trm290_pci_driver = {
 	.name		= "TRM290_IDE",
 	.id_table	= trm290_pci_tbl,
 	.probe		= trm290_init_one,
@@ -360,12 +359,12 @@
 
 static int __init trm290_ide_init(void)
 {
-	return ide_pci_register_driver(&driver);
+	return ide_pci_register_driver(&trm290_pci_driver);
 }
 
 static void __exit trm290_ide_exit(void)
 {
-	pci_unregister_driver(&driver);
+	pci_unregister_driver(&trm290_pci_driver);
 }
 
 module_init(trm290_ide_init);
diff --git a/drivers/ide/pci/via82cxxx.c b/drivers/ide/pci/via82cxxx.c
index 94fb9ab..2a812d3 100644
--- a/drivers/ide/pci/via82cxxx.c
+++ b/drivers/ide/pci/via82cxxx.c
@@ -154,7 +154,7 @@
 static void via_set_drive(ide_drive_t *drive, const u8 speed)
 {
 	ide_hwif_t *hwif = drive->hwif;
-	ide_drive_t *peer = hwif->drives + (~drive->dn & 1);
+	ide_drive_t *peer = ide_get_pair_dev(drive);
 	struct pci_dev *dev = to_pci_dev(hwif->dev);
 	struct ide_host *host = pci_get_drvdata(dev);
 	struct via82cxxx_dev *vdev = host->host_priv;
@@ -173,7 +173,7 @@
 
 	ide_timing_compute(drive, speed, &t, T, UT);
 
-	if (peer->present) {
+	if (peer) {
 		ide_timing_compute(peer, peer->current_speed, &p, T, UT);
 		ide_timing_merge(&p, &t, &t, IDE_TIMING_8BIT);
 	}
@@ -215,7 +215,7 @@
 /*
  * Check and handle 80-wire cable presence
  */
-static void __devinit via_cable_detect(struct via82cxxx_dev *vdev, u32 u)
+static void via_cable_detect(struct via82cxxx_dev *vdev, u32 u)
 {
 	int i;
 
@@ -267,7 +267,7 @@
  *	and initialize its drive independent registers.
  */
 
-static unsigned int __devinit init_chipset_via82cxxx(struct pci_dev *dev)
+static unsigned int init_chipset_via82cxxx(struct pci_dev *dev)
 {
 	struct ide_host *host = pci_get_drvdata(dev);
 	struct via82cxxx_dev *vdev = host->host_priv;
@@ -487,21 +487,23 @@
 };
 MODULE_DEVICE_TABLE(pci, via_pci_tbl);
 
-static struct pci_driver driver = {
+static struct pci_driver via_pci_driver = {
 	.name 		= "VIA_IDE",
 	.id_table 	= via_pci_tbl,
 	.probe 		= via_init_one,
 	.remove		= __devexit_p(via_remove),
+	.suspend	= ide_pci_suspend,
+	.resume		= ide_pci_resume,
 };
 
 static int __init via_ide_init(void)
 {
-	return ide_pci_register_driver(&driver);
+	return ide_pci_register_driver(&via_pci_driver);
 }
 
 static void __exit via_ide_exit(void)
 {
-	pci_unregister_driver(&driver);
+	pci_unregister_driver(&via_pci_driver);
 }
 
 module_init(via_ide_init);
diff --git a/drivers/ide/ppc/pmac.c b/drivers/ide/ppc/pmac.c
index fa2be26..2e19d62 100644
--- a/drivers/ide/ppc/pmac.c
+++ b/drivers/ide/ppc/pmac.c
@@ -430,10 +430,7 @@
 	pmac_ide_hwif_t *pmif =
 		(pmac_ide_hwif_t *)dev_get_drvdata(hwif->gendev.parent);
 
-	if (pmif == NULL)
-		return;
-
-	if (drive->select.b.unit & 0x01)
+	if (drive->dn & 1)
 		writel(pmif->timings[1], PMAC_IDE_REG(IDE_TIMING_CONFIG));
 	else
 		writel(pmif->timings[0], PMAC_IDE_REG(IDE_TIMING_CONFIG));
@@ -452,10 +449,7 @@
 	pmac_ide_hwif_t *pmif =
 		(pmac_ide_hwif_t *)dev_get_drvdata(hwif->gendev.parent);
 
-	if (pmif == NULL)
-		return;
-
-	if (drive->select.b.unit & 0x01) {
+	if (drive->dn & 1) {
 		writel(pmif->timings[1], PMAC_IDE_REG(IDE_KAUAI_PIO_CONFIG));
 		writel(pmif->timings[3], PMAC_IDE_REG(IDE_KAUAI_ULTRA_CONFIG));
 	} else {
@@ -475,9 +469,6 @@
 	pmac_ide_hwif_t *pmif =
 		(pmac_ide_hwif_t *)dev_get_drvdata(hwif->gendev.parent);
 
-	if (pmif == NULL)
-		return;
-
 	if (pmif->kind == controller_sh_ata6 ||
 	    pmif->kind == controller_un_ata6 ||
 	    pmif->kind == controller_k2_ata6)
@@ -524,11 +515,8 @@
 	unsigned accessTime, recTime;
 	unsigned int cycle_time;
 
-	if (pmif == NULL)
-		return;
-		
 	/* which drive is it ? */
-	timings = &pmif->timings[drive->select.b.unit & 0x01];
+	timings = &pmif->timings[drive->dn & 1];
 	t = *timings;
 
 	cycle_time = ide_pio_cycle_time(drive, pio);
@@ -669,9 +657,9 @@
 set_timings_mdma(ide_drive_t *drive, int intf_type, u32 *timings, u32 *timings2,
 		 	u8 speed)
 {
+	u16 *id = drive->id;
 	int cycleTime, accessTime = 0, recTime = 0;
 	unsigned accessTicks, recTicks;
-	struct hd_driveid *id = drive->id;
 	struct mdma_timings_t* tm = NULL;
 	int i;
 
@@ -686,8 +674,8 @@
 	}
 
 	/* Check if drive provides explicit DMA cycle time */
-	if ((id->field_valid & 2) && id->eide_dma_time)
-		cycleTime = max_t(int, id->eide_dma_time, cycleTime);
+	if ((id[ATA_ID_FIELD_VALID] & 2) && id[ATA_ID_EIDE_DMA_TIME])
+		cycleTime = max_t(int, id[ATA_ID_EIDE_DMA_TIME], cycleTime);
 
 	/* OHare limits according to some old Apple sources */	
 	if ((intf_type == controller_ohare) && (cycleTime < 150))
@@ -805,9 +793,9 @@
 	ide_hwif_t *hwif = drive->hwif;
 	pmac_ide_hwif_t *pmif =
 		(pmac_ide_hwif_t *)dev_get_drvdata(hwif->gendev.parent);
-	int unit = (drive->select.b.unit & 0x01);
 	int ret = 0;
 	u32 *timings, *timings2, tl[2];
+	u8 unit = drive->dn & 1;
 
 	timings = &pmif->timings[unit];
 	timings2 = &pmif->timings[unit+2];
@@ -966,11 +954,11 @@
 	if (pmif->mediabay) {
 #ifdef CONFIG_PMAC_MEDIABAY
 		if (check_media_bay_by_base(pmif->regbase, MB_CD) == 0) {
-			drive->noprobe = 0;
+			drive->dev_flags &= ~IDE_DFLAG_NOPROBE;
 			return;
 		}
 #endif
-		drive->noprobe = 1;
+		drive->dev_flags |= IDE_DFLAG_NOPROBE;
 	}
 }
 
@@ -1535,18 +1523,6 @@
 	return 0; /* revert to PIO for this request */
 }
 
-/* Teardown mappings after DMA has completed.  */
-static void
-pmac_ide_destroy_dmatable (ide_drive_t *drive)
-{
-	ide_hwif_t *hwif = drive->hwif;
-
-	if (hwif->sg_nents) {
-		ide_destroy_dmatable(drive);
-		hwif->sg_nents = 0;
-	}
-}
-
 /*
  * Prepare a DMA transfer. We build the DMA table, adjust the timings for
  * a read on KeyLargo ATA/66 and mark us as waiting for DMA completion
@@ -1558,12 +1534,7 @@
 	pmac_ide_hwif_t *pmif =
 		(pmac_ide_hwif_t *)dev_get_drvdata(hwif->gendev.parent);
 	struct request *rq = HWGROUP(drive)->rq;
-	u8 unit = (drive->select.b.unit & 0x01);
-	u8 ata4;
-
-	if (pmif == NULL)
-		return 1;
-	ata4 = (pmif->kind == controller_kl_ata4);	
+	u8 unit = drive->dn & 1, ata4 = (pmif->kind == controller_kl_ata4);
 
 	if (!pmac_ide_build_dmatable(drive, rq)) {
 		ide_map_sg(drive, rq);
@@ -1617,17 +1588,15 @@
 	ide_hwif_t *hwif = drive->hwif;
 	pmac_ide_hwif_t *pmif =
 		(pmac_ide_hwif_t *)dev_get_drvdata(hwif->gendev.parent);
-	volatile struct dbdma_regs __iomem *dma;
+	volatile struct dbdma_regs __iomem *dma = pmif->dma_regs;
 	u32 dstat;
-	
-	if (pmif == NULL)
-		return 0;
-	dma = pmif->dma_regs;
 
 	drive->waiting_for_dma = 0;
 	dstat = readl(&dma->status);
 	writel(((RUN|WAKE|DEAD) << 16), &dma->control);
-	pmac_ide_destroy_dmatable(drive);
+
+	ide_destroy_dmatable(drive);
+
 	/* verify good dma status. we don't check for ACTIVE beeing 0. We should...
 	 * in theory, but with ATAPI decices doing buffer underruns, that would
 	 * cause us to disable DMA, which isn't what we want
@@ -1647,13 +1616,9 @@
 	ide_hwif_t *hwif = drive->hwif;
 	pmac_ide_hwif_t *pmif =
 		(pmac_ide_hwif_t *)dev_get_drvdata(hwif->gendev.parent);
-	volatile struct dbdma_regs __iomem *dma;
+	volatile struct dbdma_regs __iomem *dma = pmif->dma_regs;
 	unsigned long status, timeout;
 
-	if (pmif == NULL)
-		return 0;
-	dma = pmif->dma_regs;
-
 	/* We have to things to deal with here:
 	 * 
 	 * - The dbdma won't stop if the command was started
@@ -1672,9 +1637,6 @@
 	status = readl(&dma->status);
 	if (!(status & ACTIVE))
 		return 1;
-	if (!drive->waiting_for_dma)
-		printk(KERN_WARNING "ide%d, ide_dma_test_irq \
-			called while not waiting\n", HWIF(drive)->index);
 
 	/* If dbdma didn't execute the STOP command yet, the
 	 * active bit is still set. We consider that we aren't
@@ -1709,14 +1671,9 @@
 	ide_hwif_t *hwif = drive->hwif;
 	pmac_ide_hwif_t *pmif =
 		(pmac_ide_hwif_t *)dev_get_drvdata(hwif->gendev.parent);
-	volatile struct dbdma_regs __iomem *dma;
-	unsigned long status;
+	volatile struct dbdma_regs __iomem *dma = pmif->dma_regs;
+	unsigned long status = readl(&dma->status);
 
-	if (pmif == NULL)
-		return;
-	dma = pmif->dma_regs;
-
-	status = readl(&dma->status);
 	printk(KERN_ERR "ide-pmac lost interrupt, dma status: %lx\n", status);
 }
 
diff --git a/drivers/ide/setup-pci.c b/drivers/ide/setup-pci.c
index a8e9e8a..9f1f9163 100644
--- a/drivers/ide/setup-pci.c
+++ b/drivers/ide/setup-pci.c
@@ -659,3 +659,36 @@
 	pci_disable_device(dev);
 }
 EXPORT_SYMBOL_GPL(ide_pci_remove);
+
+#ifdef CONFIG_PM
+int ide_pci_suspend(struct pci_dev *dev, pm_message_t state)
+{
+	pci_save_state(dev);
+	pci_disable_device(dev);
+	pci_set_power_state(dev, pci_choose_state(dev, state));
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(ide_pci_suspend);
+
+int ide_pci_resume(struct pci_dev *dev)
+{
+	struct ide_host *host = pci_get_drvdata(dev);
+	int rc;
+
+	pci_set_power_state(dev, PCI_D0);
+
+	rc = pci_enable_device(dev);
+	if (rc)
+		return rc;
+
+	pci_restore_state(dev);
+	pci_set_master(dev);
+
+	if (host->init_chipset)
+		host->init_chipset(dev);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(ide_pci_resume);
+#endif
diff --git a/drivers/infiniband/core/cm.c b/drivers/infiniband/core/cm.c
index 922d35f..3cab0ce 100644
--- a/drivers/infiniband/core/cm.c
+++ b/drivers/infiniband/core/cm.c
@@ -3748,6 +3748,7 @@
 		cm_remove_port_fs(port);
 	}
 	device_unregister(cm_dev->device);
+	kfree(cm_dev);
 }
 
 static void cm_remove_one(struct ib_device *ib_device)
@@ -3776,6 +3777,7 @@
 		cm_remove_port_fs(port);
 	}
 	device_unregister(cm_dev->device);
+	kfree(cm_dev);
 }
 
 static int __init ib_cm_init(void)
diff --git a/drivers/infiniband/core/mad.c b/drivers/infiniband/core/mad.c
index 1adf2ef..49c45fe 100644
--- a/drivers/infiniband/core/mad.c
+++ b/drivers/infiniband/core/mad.c
@@ -1697,9 +1697,8 @@
 	u8 port_num = mad_agent_priv->agent.port_num;
 	u8 lmc;
 
-	send_resp = ((struct ib_mad *)(wr->send_buf.mad))->
-		     mad_hdr.method & IB_MGMT_METHOD_RESP;
-	rcv_resp = rwc->recv_buf.mad->mad_hdr.method & IB_MGMT_METHOD_RESP;
+	send_resp = ib_response_mad((struct ib_mad *)wr->send_buf.mad);
+	rcv_resp = ib_response_mad(rwc->recv_buf.mad);
 
 	if (send_resp == rcv_resp)
 		/* both requests, or both responses. GIDs different */
diff --git a/drivers/infiniband/hw/amso1100/c2_provider.c b/drivers/infiniband/hw/amso1100/c2_provider.c
index 2acf9b6..69580e2 100644
--- a/drivers/infiniband/hw/amso1100/c2_provider.c
+++ b/drivers/infiniband/hw/amso1100/c2_provider.c
@@ -272,7 +272,6 @@
 		pr_debug("%s: Invalid QP type: %d\n", __func__,
 			init_attr->qp_type);
 		return ERR_PTR(-EINVAL);
-		break;
 	}
 
 	if (err) {
diff --git a/drivers/infiniband/hw/cxgb3/iwch_provider.c b/drivers/infiniband/hw/cxgb3/iwch_provider.c
index eb778bfd..ecff980 100644
--- a/drivers/infiniband/hw/cxgb3/iwch_provider.c
+++ b/drivers/infiniband/hw/cxgb3/iwch_provider.c
@@ -1155,13 +1155,11 @@
 			   u8 port, struct ib_port_attr *props)
 {
 	PDBG("%s ibdev %p\n", __func__, ibdev);
+
+	memset(props, 0, sizeof(struct ib_port_attr));
 	props->max_mtu = IB_MTU_4096;
-	props->lid = 0;
-	props->lmc = 0;
-	props->sm_lid = 0;
-	props->sm_sl = 0;
+	props->active_mtu = IB_MTU_2048;
 	props->state = IB_PORT_ACTIVE;
-	props->phys_state = 0;
 	props->port_cap_flags =
 	    IB_PORT_CM_SUP |
 	    IB_PORT_SNMP_TUNNEL_SUP |
@@ -1170,7 +1168,6 @@
 	    IB_PORT_VENDOR_CLASS_SUP | IB_PORT_BOOT_MGMT_SUP;
 	props->gid_tbl_len = 1;
 	props->pkey_tbl_len = 1;
-	props->qkey_viol_cntr = 0;
 	props->active_width = 2;
 	props->active_speed = 2;
 	props->max_msg_sz = -1;
diff --git a/drivers/infiniband/hw/ehca/ehca_classes.h b/drivers/infiniband/hw/ehca/ehca_classes.h
index 1ab919f..5d7b785 100644
--- a/drivers/infiniband/hw/ehca/ehca_classes.h
+++ b/drivers/infiniband/hw/ehca/ehca_classes.h
@@ -164,6 +164,13 @@
 	u16 reported;
 };
 
+struct ehca_queue_map {
+	struct ehca_qmap_entry *map;
+	unsigned int entries;
+	unsigned int tail;
+	unsigned int left_to_poll;
+};
+
 struct ehca_qp {
 	union {
 		struct ib_qp ib_qp;
@@ -173,8 +180,9 @@
 	enum ehca_ext_qp_type ext_type;
 	enum ib_qp_state state;
 	struct ipz_queue ipz_squeue;
-	struct ehca_qmap_entry *sq_map;
+	struct ehca_queue_map sq_map;
 	struct ipz_queue ipz_rqueue;
+	struct ehca_queue_map rq_map;
 	struct h_galpas galpas;
 	u32 qkey;
 	u32 real_qp_num;
@@ -204,6 +212,8 @@
 	atomic_t nr_events; /* events seen */
 	wait_queue_head_t wait_completion;
 	int mig_armed;
+	struct list_head sq_err_node;
+	struct list_head rq_err_node;
 };
 
 #define IS_SRQ(qp) (qp->ext_type == EQPT_SRQ)
@@ -233,6 +243,8 @@
 	/* mmap counter for resources mapped into user space */
 	u32 mm_count_queue;
 	u32 mm_count_galpa;
+	struct list_head sqp_err_list;
+	struct list_head rqp_err_list;
 };
 
 enum ehca_mr_flag {
diff --git a/drivers/infiniband/hw/ehca/ehca_cq.c b/drivers/infiniband/hw/ehca/ehca_cq.c
index 5540b27..33647a9 100644
--- a/drivers/infiniband/hw/ehca/ehca_cq.c
+++ b/drivers/infiniband/hw/ehca/ehca_cq.c
@@ -276,6 +276,9 @@
 	for (i = 0; i < QP_HASHTAB_LEN; i++)
 		INIT_HLIST_HEAD(&my_cq->qp_hashtab[i]);
 
+	INIT_LIST_HEAD(&my_cq->sqp_err_list);
+	INIT_LIST_HEAD(&my_cq->rqp_err_list);
+
 	if (context) {
 		struct ipz_queue *ipz_queue = &my_cq->ipz_queue;
 		struct ehca_create_cq_resp resp;
diff --git a/drivers/infiniband/hw/ehca/ehca_iverbs.h b/drivers/infiniband/hw/ehca/ehca_iverbs.h
index a8a2ea5..8f7f282 100644
--- a/drivers/infiniband/hw/ehca/ehca_iverbs.h
+++ b/drivers/infiniband/hw/ehca/ehca_iverbs.h
@@ -197,6 +197,8 @@
 int ehca_calc_ipd(struct ehca_shca *shca, int port,
 		  enum ib_rate path_rate, u32 *ipd);
 
+void ehca_add_to_err_list(struct ehca_qp *qp, int on_sq);
+
 #ifdef CONFIG_PPC_64K_PAGES
 void *ehca_alloc_fw_ctrlblock(gfp_t flags);
 void ehca_free_fw_ctrlblock(void *ptr);
diff --git a/drivers/infiniband/hw/ehca/ehca_qp.c b/drivers/infiniband/hw/ehca/ehca_qp.c
index b6bcee0..4dbe287 100644
--- a/drivers/infiniband/hw/ehca/ehca_qp.c
+++ b/drivers/infiniband/hw/ehca/ehca_qp.c
@@ -396,6 +396,50 @@
 	queue->is_small = (queue->page_size != 0);
 }
 
+/* needs to be called with cq->spinlock held */
+void ehca_add_to_err_list(struct ehca_qp *qp, int on_sq)
+{
+	struct list_head *list, *node;
+
+	/* TODO: support low latency QPs */
+	if (qp->ext_type == EQPT_LLQP)
+		return;
+
+	if (on_sq) {
+		list = &qp->send_cq->sqp_err_list;
+		node = &qp->sq_err_node;
+	} else {
+		list = &qp->recv_cq->rqp_err_list;
+		node = &qp->rq_err_node;
+	}
+
+	if (list_empty(node))
+		list_add_tail(node, list);
+
+	return;
+}
+
+static void del_from_err_list(struct ehca_cq *cq, struct list_head *node)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&cq->spinlock, flags);
+
+	if (!list_empty(node))
+		list_del_init(node);
+
+	spin_unlock_irqrestore(&cq->spinlock, flags);
+}
+
+static void reset_queue_map(struct ehca_queue_map *qmap)
+{
+	int i;
+
+	qmap->tail = 0;
+	for (i = 0; i < qmap->entries; i++)
+		qmap->map[i].reported = 1;
+}
+
 /*
  * Create an ib_qp struct that is either a QP or an SRQ, depending on
  * the value of the is_srq parameter. If init_attr and srq_init_attr share
@@ -407,12 +451,11 @@
 	struct ib_srq_init_attr *srq_init_attr,
 	struct ib_udata *udata, int is_srq)
 {
-	struct ehca_qp *my_qp;
+	struct ehca_qp *my_qp, *my_srq = NULL;
 	struct ehca_pd *my_pd = container_of(pd, struct ehca_pd, ib_pd);
 	struct ehca_shca *shca = container_of(pd->device, struct ehca_shca,
 					      ib_device);
 	struct ib_ucontext *context = NULL;
-	u32 nr_qes;
 	u64 h_ret;
 	int is_llqp = 0, has_srq = 0;
 	int qp_type, max_send_sge, max_recv_sge, ret;
@@ -457,8 +500,7 @@
 
 	/* handle SRQ base QPs */
 	if (init_attr->srq) {
-		struct ehca_qp *my_srq =
-			container_of(init_attr->srq, struct ehca_qp, ib_srq);
+		my_srq = container_of(init_attr->srq, struct ehca_qp, ib_srq);
 
 		has_srq = 1;
 		parms.ext_type = EQPT_SRQBASE;
@@ -716,15 +758,19 @@
 				 "and pages ret=%i", ret);
 			goto create_qp_exit2;
 		}
-		nr_qes = my_qp->ipz_squeue.queue_length /
+
+		my_qp->sq_map.entries = my_qp->ipz_squeue.queue_length /
 			 my_qp->ipz_squeue.qe_size;
-		my_qp->sq_map = vmalloc(nr_qes *
+		my_qp->sq_map.map = vmalloc(my_qp->sq_map.entries *
 					sizeof(struct ehca_qmap_entry));
-		if (!my_qp->sq_map) {
+		if (!my_qp->sq_map.map) {
 			ehca_err(pd->device, "Couldn't allocate squeue "
 				 "map ret=%i", ret);
 			goto create_qp_exit3;
 		}
+		INIT_LIST_HEAD(&my_qp->sq_err_node);
+		/* to avoid the generation of bogus flush CQEs */
+		reset_queue_map(&my_qp->sq_map);
 	}
 
 	if (HAS_RQ(my_qp)) {
@@ -736,6 +782,25 @@
 				 "and pages ret=%i", ret);
 			goto create_qp_exit4;
 		}
+
+		my_qp->rq_map.entries = my_qp->ipz_rqueue.queue_length /
+			my_qp->ipz_rqueue.qe_size;
+		my_qp->rq_map.map = vmalloc(my_qp->rq_map.entries *
+				sizeof(struct ehca_qmap_entry));
+		if (!my_qp->rq_map.map) {
+			ehca_err(pd->device, "Couldn't allocate squeue "
+					"map ret=%i", ret);
+			goto create_qp_exit5;
+		}
+		INIT_LIST_HEAD(&my_qp->rq_err_node);
+		/* to avoid the generation of bogus flush CQEs */
+		reset_queue_map(&my_qp->rq_map);
+	} else if (init_attr->srq) {
+		/* this is a base QP, use the queue map of the SRQ */
+		my_qp->rq_map = my_srq->rq_map;
+		INIT_LIST_HEAD(&my_qp->rq_err_node);
+
+		my_qp->ipz_rqueue = my_srq->ipz_rqueue;
 	}
 
 	if (is_srq) {
@@ -799,7 +864,7 @@
 		if (ret) {
 			ehca_err(pd->device,
 				 "Couldn't assign qp to send_cq ret=%i", ret);
-			goto create_qp_exit6;
+			goto create_qp_exit7;
 		}
 	}
 
@@ -825,25 +890,29 @@
 		if (ib_copy_to_udata(udata, &resp, sizeof resp)) {
 			ehca_err(pd->device, "Copy to udata failed");
 			ret = -EINVAL;
-			goto create_qp_exit7;
+			goto create_qp_exit8;
 		}
 	}
 
 	return my_qp;
 
-create_qp_exit7:
+create_qp_exit8:
 	ehca_cq_unassign_qp(my_qp->send_cq, my_qp->real_qp_num);
 
-create_qp_exit6:
+create_qp_exit7:
 	kfree(my_qp->mod_qp_parm);
 
+create_qp_exit6:
+	if (HAS_RQ(my_qp))
+		vfree(my_qp->rq_map.map);
+
 create_qp_exit5:
 	if (HAS_RQ(my_qp))
 		ipz_queue_dtor(my_pd, &my_qp->ipz_rqueue);
 
 create_qp_exit4:
 	if (HAS_SQ(my_qp))
-		vfree(my_qp->sq_map);
+		vfree(my_qp->sq_map.map);
 
 create_qp_exit3:
 	if (HAS_SQ(my_qp))
@@ -1035,6 +1104,101 @@
 	return 0;
 }
 
+static int calc_left_cqes(u64 wqe_p, struct ipz_queue *ipz_queue,
+			  struct ehca_queue_map *qmap)
+{
+	void *wqe_v;
+	u64 q_ofs;
+	u32 wqe_idx;
+
+	/* convert real to abs address */
+	wqe_p = wqe_p & (~(1UL << 63));
+
+	wqe_v = abs_to_virt(wqe_p);
+
+	if (ipz_queue_abs_to_offset(ipz_queue, wqe_p, &q_ofs)) {
+		ehca_gen_err("Invalid offset for calculating left cqes "
+				"wqe_p=%#lx wqe_v=%p\n", wqe_p, wqe_v);
+		return -EFAULT;
+	}
+
+	wqe_idx = q_ofs / ipz_queue->qe_size;
+	if (wqe_idx < qmap->tail)
+		qmap->left_to_poll = (qmap->entries - qmap->tail) + wqe_idx;
+	else
+		qmap->left_to_poll = wqe_idx - qmap->tail;
+
+	return 0;
+}
+
+static int check_for_left_cqes(struct ehca_qp *my_qp, struct ehca_shca *shca)
+{
+	u64 h_ret;
+	void *send_wqe_p, *recv_wqe_p;
+	int ret;
+	unsigned long flags;
+	int qp_num = my_qp->ib_qp.qp_num;
+
+	/* this hcall is not supported on base QPs */
+	if (my_qp->ext_type != EQPT_SRQBASE) {
+		/* get send and receive wqe pointer */
+		h_ret = hipz_h_disable_and_get_wqe(shca->ipz_hca_handle,
+				my_qp->ipz_qp_handle, &my_qp->pf,
+				&send_wqe_p, &recv_wqe_p, 4);
+		if (h_ret != H_SUCCESS) {
+			ehca_err(&shca->ib_device, "disable_and_get_wqe() "
+				 "failed ehca_qp=%p qp_num=%x h_ret=%li",
+				 my_qp, qp_num, h_ret);
+			return ehca2ib_return_code(h_ret);
+		}
+
+		/*
+		 * acquire lock to ensure that nobody is polling the cq which
+		 * could mean that the qmap->tail pointer is in an
+		 * inconsistent state.
+		 */
+		spin_lock_irqsave(&my_qp->send_cq->spinlock, flags);
+		ret = calc_left_cqes((u64)send_wqe_p, &my_qp->ipz_squeue,
+				&my_qp->sq_map);
+		spin_unlock_irqrestore(&my_qp->send_cq->spinlock, flags);
+		if (ret)
+			return ret;
+
+
+		spin_lock_irqsave(&my_qp->recv_cq->spinlock, flags);
+		ret = calc_left_cqes((u64)recv_wqe_p, &my_qp->ipz_rqueue,
+				&my_qp->rq_map);
+		spin_unlock_irqrestore(&my_qp->recv_cq->spinlock, flags);
+		if (ret)
+			return ret;
+	} else {
+		spin_lock_irqsave(&my_qp->send_cq->spinlock, flags);
+		my_qp->sq_map.left_to_poll = 0;
+		spin_unlock_irqrestore(&my_qp->send_cq->spinlock, flags);
+
+		spin_lock_irqsave(&my_qp->recv_cq->spinlock, flags);
+		my_qp->rq_map.left_to_poll = 0;
+		spin_unlock_irqrestore(&my_qp->recv_cq->spinlock, flags);
+	}
+
+	/* this assures flush cqes being generated only for pending wqes */
+	if ((my_qp->sq_map.left_to_poll == 0) &&
+				(my_qp->rq_map.left_to_poll == 0)) {
+		spin_lock_irqsave(&my_qp->send_cq->spinlock, flags);
+		ehca_add_to_err_list(my_qp, 1);
+		spin_unlock_irqrestore(&my_qp->send_cq->spinlock, flags);
+
+		if (HAS_RQ(my_qp)) {
+			spin_lock_irqsave(&my_qp->recv_cq->spinlock, flags);
+			ehca_add_to_err_list(my_qp, 0);
+			spin_unlock_irqrestore(&my_qp->recv_cq->spinlock,
+					flags);
+		}
+	}
+
+	return 0;
+}
+
 /*
  * internal_modify_qp with circumvention to handle aqp0 properly
  * smi_reset2init indicates if this is an internal reset-to-init-call for
@@ -1539,10 +1703,27 @@
 			goto modify_qp_exit2;
 		}
 	}
+	if ((qp_new_state == IB_QPS_ERR) && (qp_cur_state != IB_QPS_ERR)) {
+		ret = check_for_left_cqes(my_qp, shca);
+		if (ret)
+			goto modify_qp_exit2;
+	}
 
 	if (statetrans == IB_QPST_ANY2RESET) {
 		ipz_qeit_reset(&my_qp->ipz_rqueue);
 		ipz_qeit_reset(&my_qp->ipz_squeue);
+
+		if (qp_cur_state == IB_QPS_ERR) {
+			del_from_err_list(my_qp->send_cq, &my_qp->sq_err_node);
+
+			if (HAS_RQ(my_qp))
+				del_from_err_list(my_qp->recv_cq,
+						  &my_qp->rq_err_node);
+		}
+		reset_queue_map(&my_qp->sq_map);
+
+		if (HAS_RQ(my_qp))
+			reset_queue_map(&my_qp->rq_map);
 	}
 
 	if (attr_mask & IB_QP_QKEY)
@@ -1958,6 +2139,16 @@
 	idr_remove(&ehca_qp_idr, my_qp->token);
 	write_unlock_irqrestore(&ehca_qp_idr_lock, flags);
 
+	/*
+	 * SRQs will never get into an error list and do not have a recv_cq,
+	 * so we need to skip them here.
+	 */
+	if (HAS_RQ(my_qp) && !IS_SRQ(my_qp))
+		del_from_err_list(my_qp->recv_cq, &my_qp->rq_err_node);
+
+	if (HAS_SQ(my_qp))
+		del_from_err_list(my_qp->send_cq, &my_qp->sq_err_node);
+
 	/* now wait until all pending events have completed */
 	wait_event(my_qp->wait_completion, !atomic_read(&my_qp->nr_events));
 
@@ -1983,7 +2174,7 @@
 	if (qp_type == IB_QPT_GSI) {
 		struct ib_event event;
 		ehca_info(dev, "device %s: port %x is inactive.",
-			  shca->ib_device.name, port_num);
+				shca->ib_device.name, port_num);
 		event.device = &shca->ib_device;
 		event.event = IB_EVENT_PORT_ERR;
 		event.element.port_num = port_num;
@@ -1991,11 +2182,15 @@
 		ib_dispatch_event(&event);
 	}
 
-	if (HAS_RQ(my_qp))
+	if (HAS_RQ(my_qp)) {
 		ipz_queue_dtor(my_pd, &my_qp->ipz_rqueue);
+
+		vfree(my_qp->rq_map.map);
+	}
 	if (HAS_SQ(my_qp)) {
 		ipz_queue_dtor(my_pd, &my_qp->ipz_squeue);
-		vfree(my_qp->sq_map);
+
+		vfree(my_qp->sq_map.map);
 	}
 	kmem_cache_free(qp_cache, my_qp);
 	atomic_dec(&shca->num_qps);
diff --git a/drivers/infiniband/hw/ehca/ehca_reqs.c b/drivers/infiniband/hw/ehca/ehca_reqs.c
index 4426d82..6492807 100644
--- a/drivers/infiniband/hw/ehca/ehca_reqs.c
+++ b/drivers/infiniband/hw/ehca/ehca_reqs.c
@@ -53,9 +53,25 @@
 /* in RC traffic, insert an empty RDMA READ every this many packets */
 #define ACK_CIRC_THRESHOLD 2000000
 
+static u64 replace_wr_id(u64 wr_id, u16 idx)
+{
+	u64 ret;
+
+	ret = wr_id & ~QMAP_IDX_MASK;
+	ret |= idx & QMAP_IDX_MASK;
+
+	return ret;
+}
+
+static u16 get_app_wr_id(u64 wr_id)
+{
+	return wr_id & QMAP_IDX_MASK;
+}
+
 static inline int ehca_write_rwqe(struct ipz_queue *ipz_rqueue,
 				  struct ehca_wqe *wqe_p,
-				  struct ib_recv_wr *recv_wr)
+				  struct ib_recv_wr *recv_wr,
+				  u32 rq_map_idx)
 {
 	u8 cnt_ds;
 	if (unlikely((recv_wr->num_sge < 0) ||
@@ -69,7 +85,7 @@
 	/* clear wqe header until sglist */
 	memset(wqe_p, 0, offsetof(struct ehca_wqe, u.ud_av.sg_list));
 
-	wqe_p->work_request_id = recv_wr->wr_id;
+	wqe_p->work_request_id = replace_wr_id(recv_wr->wr_id, rq_map_idx);
 	wqe_p->nr_of_data_seg = recv_wr->num_sge;
 
 	for (cnt_ds = 0; cnt_ds < recv_wr->num_sge; cnt_ds++) {
@@ -146,6 +162,7 @@
 	u64 dma_length;
 	struct ehca_av *my_av;
 	u32 remote_qkey = send_wr->wr.ud.remote_qkey;
+	struct ehca_qmap_entry *qmap_entry = &qp->sq_map.map[sq_map_idx];
 
 	if (unlikely((send_wr->num_sge < 0) ||
 		     (send_wr->num_sge > qp->ipz_squeue.act_nr_of_sg))) {
@@ -158,11 +175,10 @@
 	/* clear wqe header until sglist */
 	memset(wqe_p, 0, offsetof(struct ehca_wqe, u.ud_av.sg_list));
 
-	wqe_p->work_request_id = send_wr->wr_id & ~QMAP_IDX_MASK;
-	wqe_p->work_request_id |= sq_map_idx & QMAP_IDX_MASK;
+	wqe_p->work_request_id = replace_wr_id(send_wr->wr_id, sq_map_idx);
 
-	qp->sq_map[sq_map_idx].app_wr_id = send_wr->wr_id & QMAP_IDX_MASK;
-	qp->sq_map[sq_map_idx].reported = 0;
+	qmap_entry->app_wr_id = get_app_wr_id(send_wr->wr_id);
+	qmap_entry->reported = 0;
 
 	switch (send_wr->opcode) {
 	case IB_WR_SEND:
@@ -496,7 +512,9 @@
 	struct ehca_wqe *wqe_p;
 	int wqe_cnt = 0;
 	int ret = 0;
+	u32 rq_map_idx;
 	unsigned long flags;
+	struct ehca_qmap_entry *qmap_entry;
 
 	if (unlikely(!HAS_RQ(my_qp))) {
 		ehca_err(dev, "QP has no RQ  ehca_qp=%p qp_num=%x ext_type=%d",
@@ -524,8 +542,15 @@
 			}
 			goto post_recv_exit0;
 		}
+		/*
+		 * Get the index of the WQE in the recv queue. The same index
+		 * is used for writing into the rq_map.
+		 */
+		rq_map_idx = start_offset / my_qp->ipz_rqueue.qe_size;
+
 		/* write a RECV WQE into the QUEUE */
-		ret = ehca_write_rwqe(&my_qp->ipz_rqueue, wqe_p, cur_recv_wr);
+		ret = ehca_write_rwqe(&my_qp->ipz_rqueue, wqe_p, cur_recv_wr,
+				rq_map_idx);
 		/*
 		 * if something failed,
 		 * reset the free entry pointer to the start value
@@ -540,6 +565,11 @@
 			}
 			goto post_recv_exit0;
 		}
+
+		qmap_entry = &my_qp->rq_map.map[rq_map_idx];
+		qmap_entry->app_wr_id = get_app_wr_id(cur_recv_wr->wr_id);
+		qmap_entry->reported = 0;
+
 		wqe_cnt++;
 	} /* eof for cur_recv_wr */
 
@@ -596,10 +626,12 @@
 /* internal function to poll one entry of cq */
 static inline int ehca_poll_cq_one(struct ib_cq *cq, struct ib_wc *wc)
 {
-	int ret = 0;
+	int ret = 0, qmap_tail_idx;
 	struct ehca_cq *my_cq = container_of(cq, struct ehca_cq, ib_cq);
 	struct ehca_cqe *cqe;
 	struct ehca_qp *my_qp;
+	struct ehca_qmap_entry *qmap_entry;
+	struct ehca_queue_map *qmap;
 	int cqe_count = 0, is_error;
 
 repoll:
@@ -674,27 +706,52 @@
 		goto repoll;
 	wc->qp = &my_qp->ib_qp;
 
-	if (!(cqe->w_completion_flags & WC_SEND_RECEIVE_BIT)) {
-		struct ehca_qmap_entry *qmap_entry;
+	if (is_error) {
 		/*
-		 * We got a send completion and need to restore the original
-		 * wr_id.
+		 * set left_to_poll to 0 because in error state, we will not
+		 * get any additional CQEs
 		 */
-		qmap_entry = &my_qp->sq_map[cqe->work_request_id &
-					    QMAP_IDX_MASK];
+		ehca_add_to_err_list(my_qp, 1);
+		my_qp->sq_map.left_to_poll = 0;
 
-		if (qmap_entry->reported) {
-			ehca_warn(cq->device, "Double cqe on qp_num=%#x",
-				  my_qp->real_qp_num);
-			/* found a double cqe, discard it and read next one */
-			goto repoll;
-		}
-		wc->wr_id = cqe->work_request_id & ~QMAP_IDX_MASK;
-		wc->wr_id |= qmap_entry->app_wr_id;
-		qmap_entry->reported = 1;
-	} else
+		if (HAS_RQ(my_qp))
+			ehca_add_to_err_list(my_qp, 0);
+		my_qp->rq_map.left_to_poll = 0;
+	}
+
+	qmap_tail_idx = get_app_wr_id(cqe->work_request_id);
+	if (!(cqe->w_completion_flags & WC_SEND_RECEIVE_BIT))
+		/* We got a send completion. */
+		qmap = &my_qp->sq_map;
+	else
 		/* We got a receive completion. */
-		wc->wr_id = cqe->work_request_id;
+		qmap = &my_qp->rq_map;
+
+	qmap_entry = &qmap->map[qmap_tail_idx];
+	if (qmap_entry->reported) {
+		ehca_warn(cq->device, "Double cqe on qp_num=%#x",
+				my_qp->real_qp_num);
+		/* found a double cqe, discard it and read next one */
+		goto repoll;
+	}
+
+	wc->wr_id = replace_wr_id(cqe->work_request_id, qmap_entry->app_wr_id);
+	qmap_entry->reported = 1;
+
+	/* this is a proper completion, we need to advance the tail pointer */
+	if (++qmap->tail == qmap->entries)
+		qmap->tail = 0;
+
+	/* if left_to_poll is decremented to 0, add the QP to the error list */
+	if (qmap->left_to_poll > 0) {
+		qmap->left_to_poll--;
+		if ((my_qp->sq_map.left_to_poll == 0) &&
+				(my_qp->rq_map.left_to_poll == 0)) {
+			ehca_add_to_err_list(my_qp, 1);
+			if (HAS_RQ(my_qp))
+				ehca_add_to_err_list(my_qp, 0);
+		}
+	}
 
 	/* eval ib_wc_opcode */
 	wc->opcode = ib_wc_opcode[cqe->optype]-1;
@@ -733,13 +790,88 @@
 	return ret;
 }
 
+static int generate_flush_cqes(struct ehca_qp *my_qp, struct ib_cq *cq,
+			       struct ib_wc *wc, int num_entries,
+			       struct ipz_queue *ipz_queue, int on_sq)
+{
+	int nr = 0;
+	struct ehca_wqe *wqe;
+	u64 offset;
+	struct ehca_queue_map *qmap;
+	struct ehca_qmap_entry *qmap_entry;
+
+	if (on_sq)
+		qmap = &my_qp->sq_map;
+	else
+		qmap = &my_qp->rq_map;
+
+	qmap_entry = &qmap->map[qmap->tail];
+
+	while ((nr < num_entries) && (qmap_entry->reported == 0)) {
+		/* generate flush CQE */
+		memset(wc, 0, sizeof(*wc));
+
+		offset = qmap->tail * ipz_queue->qe_size;
+		wqe = (struct ehca_wqe *)ipz_qeit_calc(ipz_queue, offset);
+		if (!wqe) {
+			ehca_err(cq->device, "Invalid wqe offset=%#lx on "
+				 "qp_num=%#x", offset, my_qp->real_qp_num);
+			return nr;
+		}
+
+		wc->wr_id = replace_wr_id(wqe->work_request_id,
+					  qmap_entry->app_wr_id);
+
+		if (on_sq) {
+			switch (wqe->optype) {
+			case WQE_OPTYPE_SEND:
+				wc->opcode = IB_WC_SEND;
+				break;
+			case WQE_OPTYPE_RDMAWRITE:
+				wc->opcode = IB_WC_RDMA_WRITE;
+				break;
+			case WQE_OPTYPE_RDMAREAD:
+				wc->opcode = IB_WC_RDMA_READ;
+				break;
+			default:
+				ehca_err(cq->device, "Invalid optype=%x",
+						wqe->optype);
+				return nr;
+			}
+		} else
+			wc->opcode = IB_WC_RECV;
+
+		if (wqe->wr_flag & WQE_WRFLAG_IMM_DATA_PRESENT) {
+			wc->ex.imm_data = wqe->immediate_data;
+			wc->wc_flags |= IB_WC_WITH_IMM;
+		}
+
+		wc->status = IB_WC_WR_FLUSH_ERR;
+
+		wc->qp = &my_qp->ib_qp;
+
+		/* mark as reported and advance tail pointer */
+		qmap_entry->reported = 1;
+		if (++qmap->tail == qmap->entries)
+			qmap->tail = 0;
+		qmap_entry = &qmap->map[qmap->tail];
+
+		wc++; nr++;
+	}
+
+	return nr;
+
+}
+
 int ehca_poll_cq(struct ib_cq *cq, int num_entries, struct ib_wc *wc)
 {
 	struct ehca_cq *my_cq = container_of(cq, struct ehca_cq, ib_cq);
 	int nr;
+	struct ehca_qp *err_qp;
 	struct ib_wc *current_wc = wc;
 	int ret = 0;
 	unsigned long flags;
+	int entries_left = num_entries;
 
 	if (num_entries < 1) {
 		ehca_err(cq->device, "Invalid num_entries=%d ehca_cq=%p "
@@ -749,15 +881,40 @@
 	}
 
 	spin_lock_irqsave(&my_cq->spinlock, flags);
-	for (nr = 0; nr < num_entries; nr++) {
+
+	/* generate flush cqes for send queues */
+	list_for_each_entry(err_qp, &my_cq->sqp_err_list, sq_err_node) {
+		nr = generate_flush_cqes(err_qp, cq, current_wc, entries_left,
+				&err_qp->ipz_squeue, 1);
+		entries_left -= nr;
+		current_wc += nr;
+
+		if (entries_left == 0)
+			break;
+	}
+
+	/* generate flush cqes for receive queues */
+	list_for_each_entry(err_qp, &my_cq->rqp_err_list, rq_err_node) {
+		nr = generate_flush_cqes(err_qp, cq, current_wc, entries_left,
+				&err_qp->ipz_rqueue, 0);
+		entries_left -= nr;
+		current_wc += nr;
+
+		if (entries_left == 0)
+			break;
+	}
+
+	for (nr = 0; nr < entries_left; nr++) {
 		ret = ehca_poll_cq_one(cq, current_wc);
 		if (ret)
 			break;
 		current_wc++;
 	} /* eof for nr */
+	entries_left -= nr;
+
 	spin_unlock_irqrestore(&my_cq->spinlock, flags);
 	if (ret == -EAGAIN  || !ret)
-		ret = nr;
+		ret = num_entries - entries_left;
 
 poll_cq_exit0:
 	return ret;
diff --git a/drivers/infiniband/hw/ipath/ipath_rc.c b/drivers/infiniband/hw/ipath/ipath_rc.c
index 9771052..7b93cda 100644
--- a/drivers/infiniband/hw/ipath/ipath_rc.c
+++ b/drivers/infiniband/hw/ipath/ipath_rc.c
@@ -675,7 +675,8 @@
 	hdr.lrh[0] = cpu_to_be16(lrh0);
 	hdr.lrh[1] = cpu_to_be16(qp->remote_ah_attr.dlid);
 	hdr.lrh[2] = cpu_to_be16(hwords + SIZE_OF_CRC);
-	hdr.lrh[3] = cpu_to_be16(dd->ipath_lid);
+	hdr.lrh[3] = cpu_to_be16(dd->ipath_lid |
+				 qp->remote_ah_attr.src_path_bits);
 	ohdr->bth[0] = cpu_to_be32(bth0);
 	ohdr->bth[1] = cpu_to_be32(qp->remote_qpn);
 	ohdr->bth[2] = cpu_to_be32(qp->r_ack_psn & IPATH_PSN_MASK);
diff --git a/drivers/infiniband/hw/ipath/ipath_ruc.c b/drivers/infiniband/hw/ipath/ipath_ruc.c
index af051f7..fc0f6d9 100644
--- a/drivers/infiniband/hw/ipath/ipath_ruc.c
+++ b/drivers/infiniband/hw/ipath/ipath_ruc.c
@@ -618,7 +618,8 @@
 	qp->s_hdr.lrh[0] = cpu_to_be16(lrh0);
 	qp->s_hdr.lrh[1] = cpu_to_be16(qp->remote_ah_attr.dlid);
 	qp->s_hdr.lrh[2] = cpu_to_be16(qp->s_hdrwords + nwords + SIZE_OF_CRC);
-	qp->s_hdr.lrh[3] = cpu_to_be16(dev->dd->ipath_lid);
+	qp->s_hdr.lrh[3] = cpu_to_be16(dev->dd->ipath_lid |
+				       qp->remote_ah_attr.src_path_bits);
 	bth0 |= ipath_get_pkey(dev->dd, qp->s_pkey_index);
 	bth0 |= extra_bytes << 20;
 	ohdr->bth[0] = cpu_to_be32(bth0 | (1 << 22));
diff --git a/drivers/infiniband/hw/ipath/ipath_verbs.c b/drivers/infiniband/hw/ipath/ipath_verbs.c
index b766e40..eabc424 100644
--- a/drivers/infiniband/hw/ipath/ipath_verbs.c
+++ b/drivers/infiniband/hw/ipath/ipath_verbs.c
@@ -340,9 +340,16 @@
 	int acc;
 	int ret;
 	unsigned long flags;
+	struct ipath_devdata *dd = to_idev(qp->ibqp.device)->dd;
 
 	spin_lock_irqsave(&qp->s_lock, flags);
 
+	if (qp->ibqp.qp_type != IB_QPT_SMI &&
+	    !(dd->ipath_flags & IPATH_LINKACTIVE)) {
+		ret = -ENETDOWN;
+		goto bail;
+	}
+
 	/* Check that state is OK to post send. */
 	if (unlikely(!(ib_ipath_state_ops[qp->state] & IPATH_POST_SEND_OK)))
 		goto bail_inval;
diff --git a/drivers/infiniband/hw/mlx4/qp.c b/drivers/infiniband/hw/mlx4/qp.c
index f29dbb7..baa01de 100644
--- a/drivers/infiniband/hw/mlx4/qp.c
+++ b/drivers/infiniband/hw/mlx4/qp.c
@@ -1058,6 +1058,9 @@
 	else
 		sqd_event = 0;
 
+	if (!ibqp->uobject && cur_state == IB_QPS_RESET && new_state == IB_QPS_INIT)
+		context->rlkey |= (1 << 4);
+
 	/*
 	 * Before passing a kernel QP to the HW, make sure that the
 	 * ownership bits of the send queue are set and the SQ
@@ -1342,6 +1345,12 @@
 static void set_fmr_seg(struct mlx4_wqe_fmr_seg *fseg, struct ib_send_wr *wr)
 {
 	struct mlx4_ib_fast_reg_page_list *mfrpl = to_mfrpl(wr->wr.fast_reg.page_list);
+	int i;
+
+	for (i = 0; i < wr->wr.fast_reg.page_list_len; ++i)
+		wr->wr.fast_reg.page_list->page_list[i] =
+			cpu_to_be64(wr->wr.fast_reg.page_list->page_list[i] |
+				    MLX4_MTT_FLAG_PRESENT);
 
 	fseg->flags		= convert_access(wr->wr.fast_reg.access_flags);
 	fseg->mem_key		= cpu_to_be32(wr->wr.fast_reg.rkey);
diff --git a/drivers/infiniband/hw/mthca/mthca_catas.c b/drivers/infiniband/hw/mthca/mthca_catas.c
index cc440f9..65ad359 100644
--- a/drivers/infiniband/hw/mthca/mthca_catas.c
+++ b/drivers/infiniband/hw/mthca/mthca_catas.c
@@ -149,18 +149,10 @@
 		((pci_resource_len(dev->pdev, 0) - 1) &
 		 dev->catas_err.addr);
 
-	if (!request_mem_region(addr, dev->catas_err.size * 4,
-				DRV_NAME)) {
-		mthca_warn(dev, "couldn't request catastrophic error region "
-			   "at 0x%lx/0x%x\n", addr, dev->catas_err.size * 4);
-		return;
-	}
-
 	dev->catas_err.map = ioremap(addr, dev->catas_err.size * 4);
 	if (!dev->catas_err.map) {
 		mthca_warn(dev, "couldn't map catastrophic error region "
 			   "at 0x%lx/0x%x\n", addr, dev->catas_err.size * 4);
-		release_mem_region(addr, dev->catas_err.size * 4);
 		return;
 	}
 
@@ -175,13 +167,8 @@
 {
 	del_timer_sync(&dev->catas_err.timer);
 
-	if (dev->catas_err.map) {
+	if (dev->catas_err.map)
 		iounmap(dev->catas_err.map);
-		release_mem_region(pci_resource_start(dev->pdev, 0) +
-				   ((pci_resource_len(dev->pdev, 0) - 1) &
-				    dev->catas_err.addr),
-				   dev->catas_err.size * 4);
-	}
 
 	spin_lock_irq(&catas_lock);
 	list_del(&dev->catas_err.list);
diff --git a/drivers/infiniband/hw/mthca/mthca_eq.c b/drivers/infiniband/hw/mthca/mthca_eq.c
index cc6858f..28f0e0c 100644
--- a/drivers/infiniband/hw/mthca/mthca_eq.c
+++ b/drivers/infiniband/hw/mthca/mthca_eq.c
@@ -652,27 +652,13 @@
 {
 	unsigned long base = pci_resource_start(dev->pdev, 0);
 
-	if (!request_mem_region(base + offset, size, DRV_NAME))
-		return -EBUSY;
-
 	*map = ioremap(base + offset, size);
-	if (!*map) {
-		release_mem_region(base + offset, size);
+	if (!*map)
 		return -ENOMEM;
-	}
 
 	return 0;
 }
 
-static void mthca_unmap_reg(struct mthca_dev *dev, unsigned long offset,
-			    unsigned long size, void __iomem *map)
-{
-	unsigned long base = pci_resource_start(dev->pdev, 0);
-
-	release_mem_region(base + offset, size);
-	iounmap(map);
-}
-
 static int mthca_map_eq_regs(struct mthca_dev *dev)
 {
 	if (mthca_is_memfree(dev)) {
@@ -699,9 +685,7 @@
 					dev->fw.arbel.eq_arm_base) + 4, 4,
 				  &dev->eq_regs.arbel.eq_arm)) {
 			mthca_err(dev, "Couldn't map EQ arm register, aborting.\n");
-			mthca_unmap_reg(dev, (pci_resource_len(dev->pdev, 0) - 1) &
-					dev->fw.arbel.clr_int_base, MTHCA_CLR_INT_SIZE,
-					dev->clr_base);
+			iounmap(dev->clr_base);
 			return -ENOMEM;
 		}
 
@@ -710,12 +694,8 @@
 				  MTHCA_EQ_SET_CI_SIZE,
 				  &dev->eq_regs.arbel.eq_set_ci_base)) {
 			mthca_err(dev, "Couldn't map EQ CI register, aborting.\n");
-			mthca_unmap_reg(dev, ((pci_resource_len(dev->pdev, 0) - 1) &
-					      dev->fw.arbel.eq_arm_base) + 4, 4,
-					dev->eq_regs.arbel.eq_arm);
-			mthca_unmap_reg(dev, (pci_resource_len(dev->pdev, 0) - 1) &
-					dev->fw.arbel.clr_int_base, MTHCA_CLR_INT_SIZE,
-					dev->clr_base);
+			iounmap(dev->eq_regs.arbel.eq_arm);
+			iounmap(dev->clr_base);
 			return -ENOMEM;
 		}
 	} else {
@@ -731,8 +711,7 @@
 				  &dev->eq_regs.tavor.ecr_base)) {
 			mthca_err(dev, "Couldn't map ecr register, "
 				  "aborting.\n");
-			mthca_unmap_reg(dev, MTHCA_CLR_INT_BASE, MTHCA_CLR_INT_SIZE,
-					dev->clr_base);
+			iounmap(dev->clr_base);
 			return -ENOMEM;
 		}
 	}
@@ -744,22 +723,12 @@
 static void mthca_unmap_eq_regs(struct mthca_dev *dev)
 {
 	if (mthca_is_memfree(dev)) {
-		mthca_unmap_reg(dev, (pci_resource_len(dev->pdev, 0) - 1) &
-				dev->fw.arbel.eq_set_ci_base,
-				MTHCA_EQ_SET_CI_SIZE,
-				dev->eq_regs.arbel.eq_set_ci_base);
-		mthca_unmap_reg(dev, ((pci_resource_len(dev->pdev, 0) - 1) &
-				      dev->fw.arbel.eq_arm_base) + 4, 4,
-				dev->eq_regs.arbel.eq_arm);
-		mthca_unmap_reg(dev, (pci_resource_len(dev->pdev, 0) - 1) &
-				dev->fw.arbel.clr_int_base, MTHCA_CLR_INT_SIZE,
-				dev->clr_base);
+		iounmap(dev->eq_regs.arbel.eq_set_ci_base);
+		iounmap(dev->eq_regs.arbel.eq_arm);
+		iounmap(dev->clr_base);
 	} else {
-		mthca_unmap_reg(dev, MTHCA_ECR_BASE,
-				MTHCA_ECR_SIZE + MTHCA_ECR_CLR_SIZE,
-				dev->eq_regs.tavor.ecr_base);
-		mthca_unmap_reg(dev, MTHCA_CLR_INT_BASE, MTHCA_CLR_INT_SIZE,
-				dev->clr_base);
+		iounmap(dev->eq_regs.tavor.ecr_base);
+		iounmap(dev->clr_base);
 	}
 }
 
diff --git a/drivers/infiniband/hw/mthca/mthca_main.c b/drivers/infiniband/hw/mthca/mthca_main.c
index fb9f91b..52f60f4 100644
--- a/drivers/infiniband/hw/mthca/mthca_main.c
+++ b/drivers/infiniband/hw/mthca/mthca_main.c
@@ -921,58 +921,6 @@
 	return err;
 }
 
-static int mthca_request_regions(struct pci_dev *pdev, int ddr_hidden)
-{
-	int err;
-
-	/*
-	 * We can't just use pci_request_regions() because the MSI-X
-	 * table is right in the middle of the first BAR.  If we did
-	 * pci_request_region and grab all of the first BAR, then
-	 * setting up MSI-X would fail, since the PCI core wants to do
-	 * request_mem_region on the MSI-X vector table.
-	 *
-	 * So just request what we need right now, and request any
-	 * other regions we need when setting up EQs.
-	 */
-	if (!request_mem_region(pci_resource_start(pdev, 0) + MTHCA_HCR_BASE,
-				MTHCA_HCR_SIZE, DRV_NAME))
-		return -EBUSY;
-
-	err = pci_request_region(pdev, 2, DRV_NAME);
-	if (err)
-		goto err_bar2_failed;
-
-	if (!ddr_hidden) {
-		err = pci_request_region(pdev, 4, DRV_NAME);
-		if (err)
-			goto err_bar4_failed;
-	}
-
-	return 0;
-
-err_bar4_failed:
-	pci_release_region(pdev, 2);
-
-err_bar2_failed:
-	release_mem_region(pci_resource_start(pdev, 0) + MTHCA_HCR_BASE,
-			   MTHCA_HCR_SIZE);
-
-	return err;
-}
-
-static void mthca_release_regions(struct pci_dev *pdev,
-				  int ddr_hidden)
-{
-	if (!ddr_hidden)
-		pci_release_region(pdev, 4);
-
-	pci_release_region(pdev, 2);
-
-	release_mem_region(pci_resource_start(pdev, 0) + MTHCA_HCR_BASE,
-			   MTHCA_HCR_SIZE);
-}
-
 static int mthca_enable_msi_x(struct mthca_dev *mdev)
 {
 	struct msix_entry entries[3];
@@ -1059,7 +1007,7 @@
 	if (!(pci_resource_flags(pdev, 4) & IORESOURCE_MEM))
 		ddr_hidden = 1;
 
-	err = mthca_request_regions(pdev, ddr_hidden);
+	err = pci_request_regions(pdev, DRV_NAME);
 	if (err) {
 		dev_err(&pdev->dev, "Cannot obtain PCI resources, "
 			"aborting.\n");
@@ -1196,7 +1144,7 @@
 	ib_dealloc_device(&mdev->ib_dev);
 
 err_free_res:
-	mthca_release_regions(pdev, ddr_hidden);
+	pci_release_regions(pdev);
 
 err_disable_pdev:
 	pci_disable_device(pdev);
@@ -1240,8 +1188,7 @@
 			pci_disable_msix(pdev);
 
 		ib_dealloc_device(&mdev->ib_dev);
-		mthca_release_regions(pdev, mdev->mthca_flags &
-				      MTHCA_FLAG_DDR_HIDDEN);
+		pci_release_regions(pdev);
 		pci_disable_device(pdev);
 		pci_set_drvdata(pdev, NULL);
 	}
diff --git a/drivers/infiniband/hw/nes/nes.c b/drivers/infiniband/hw/nes/nes.c
index b0cab64..a2b04d6 100644
--- a/drivers/infiniband/hw/nes/nes.c
+++ b/drivers/infiniband/hw/nes/nes.c
@@ -70,27 +70,31 @@
 
 /* Interoperability */
 int mpa_version = 1;
-module_param(mpa_version, int, 0);
+module_param(mpa_version, int, 0644);
 MODULE_PARM_DESC(mpa_version, "MPA version to be used int MPA Req/Resp (0 or 1)");
 
 /* Interoperability */
 int disable_mpa_crc = 0;
-module_param(disable_mpa_crc, int, 0);
+module_param(disable_mpa_crc, int, 0644);
 MODULE_PARM_DESC(disable_mpa_crc, "Disable checking of MPA CRC");
 
 unsigned int send_first = 0;
-module_param(send_first, int, 0);
+module_param(send_first, int, 0644);
 MODULE_PARM_DESC(send_first, "Send RDMA Message First on Active Connection");
 
 
 unsigned int nes_drv_opt = 0;
-module_param(nes_drv_opt, int, 0);
+module_param(nes_drv_opt, int, 0644);
 MODULE_PARM_DESC(nes_drv_opt, "Driver option parameters");
 
 unsigned int nes_debug_level = 0;
 module_param_named(debug_level, nes_debug_level, uint, 0644);
 MODULE_PARM_DESC(debug_level, "Enable debug output level");
 
+unsigned int wqm_quanta = 0x10000;
+module_param(wqm_quanta, int, 0644);
+MODULE_PARM_DESC(wqm_quanta, "WQM quanta");
+
 LIST_HEAD(nes_adapter_list);
 static LIST_HEAD(nes_dev_list);
 
@@ -557,12 +561,32 @@
 		goto bail5;
 	}
 	nesdev->nesadapter->et_rx_coalesce_usecs_irq = interrupt_mod_interval;
+	nesdev->nesadapter->wqm_quanta = wqm_quanta;
 
 	/* nesdev->base_doorbell_index =
 			nesdev->nesadapter->pd_config_base[PCI_FUNC(nesdev->pcidev->devfn)]; */
 	nesdev->base_doorbell_index = 1;
 	nesdev->doorbell_start = nesdev->nesadapter->doorbell_start;
-	nesdev->mac_index = PCI_FUNC(nesdev->pcidev->devfn) % nesdev->nesadapter->port_count;
+	if (nesdev->nesadapter->phy_type[0] == NES_PHY_TYPE_PUMA_1G) {
+		switch (PCI_FUNC(nesdev->pcidev->devfn) %
+			nesdev->nesadapter->port_count) {
+		case 1:
+			nesdev->mac_index = 2;
+			break;
+		case 2:
+			nesdev->mac_index = 1;
+			break;
+		case 3:
+			nesdev->mac_index = 3;
+			break;
+		case 0:
+		default:
+			nesdev->mac_index = 0;
+		}
+	} else {
+		nesdev->mac_index = PCI_FUNC(nesdev->pcidev->devfn) %
+						nesdev->nesadapter->port_count;
+	}
 
 	tasklet_init(&nesdev->dpc_tasklet, nes_dpc, (unsigned long)nesdev);
 
@@ -581,7 +605,7 @@
 	nesdev->int_req = (0x101 << PCI_FUNC(nesdev->pcidev->devfn)) |
 			(1 << (PCI_FUNC(nesdev->pcidev->devfn)+16));
 	if (PCI_FUNC(nesdev->pcidev->devfn) < 4) {
-		nesdev->int_req |= (1 << (PCI_FUNC(nesdev->pcidev->devfn)+24));
+		nesdev->int_req |= (1 << (PCI_FUNC(nesdev->mac_index)+24));
 	}
 
 	/* TODO: This really should be the first driver to load, not function 0 */
@@ -772,14 +796,14 @@
 
 	list_for_each_entry(nesdev, &nes_dev_list, list) {
 		if (i == ee_flsh_adapter) {
-			devfn      = nesdev->nesadapter->devfn;
-			bus_number = nesdev->nesadapter->bus_number;
+			devfn = nesdev->pcidev->devfn;
+			bus_number = nesdev->pcidev->bus->number;
 			break;
 		}
 		i++;
 	}
 
-	return snprintf(buf, PAGE_SIZE, "%x:%x", bus_number, devfn);
+	return snprintf(buf, PAGE_SIZE, "%x:%x\n", bus_number, devfn);
 }
 
 static ssize_t nes_store_adapter(struct device_driver *ddp,
@@ -1050,6 +1074,55 @@
 	return strnlen(buf, count);
 }
 
+
+/**
+ * nes_show_wqm_quanta
+ */
+static ssize_t nes_show_wqm_quanta(struct device_driver *ddp, char *buf)
+{
+	u32 wqm_quanta_value = 0xdead;
+	u32 i = 0;
+	struct nes_device *nesdev;
+
+	list_for_each_entry(nesdev, &nes_dev_list, list) {
+		if (i == ee_flsh_adapter) {
+			wqm_quanta_value = nesdev->nesadapter->wqm_quanta;
+			break;
+		}
+		i++;
+	}
+
+	return  snprintf(buf, PAGE_SIZE, "0x%X\n", wqm_quanta);
+}
+
+
+/**
+ * nes_store_wqm_quanta
+ */
+static ssize_t nes_store_wqm_quanta(struct device_driver *ddp,
+					const char *buf, size_t count)
+{
+	unsigned long wqm_quanta_value;
+	u32 wqm_config1;
+	u32 i = 0;
+	struct nes_device *nesdev;
+
+	strict_strtoul(buf, 0, &wqm_quanta_value);
+	list_for_each_entry(nesdev, &nes_dev_list, list) {
+		if (i == ee_flsh_adapter) {
+			nesdev->nesadapter->wqm_quanta = wqm_quanta_value;
+			wqm_config1 = nes_read_indexed(nesdev,
+						NES_IDX_WQM_CONFIG1);
+			nes_write_indexed(nesdev, NES_IDX_WQM_CONFIG1,
+					((wqm_quanta_value << 1) |
+					(wqm_config1 & 0x00000001)));
+			break;
+		}
+		i++;
+	}
+	return strnlen(buf, count);
+}
+
 static DRIVER_ATTR(adapter, S_IRUSR | S_IWUSR,
 		   nes_show_adapter, nes_store_adapter);
 static DRIVER_ATTR(eeprom_cmd, S_IRUSR | S_IWUSR,
@@ -1068,6 +1141,8 @@
 		   nes_show_idx_addr, nes_store_idx_addr);
 static DRIVER_ATTR(idx_data, S_IRUSR | S_IWUSR,
 		   nes_show_idx_data, nes_store_idx_data);
+static DRIVER_ATTR(wqm_quanta, S_IRUSR | S_IWUSR,
+		   nes_show_wqm_quanta, nes_store_wqm_quanta);
 
 static int nes_create_driver_sysfs(struct pci_driver *drv)
 {
@@ -1081,6 +1156,7 @@
 	error |= driver_create_file(&drv->driver, &driver_attr_nonidx_data);
 	error |= driver_create_file(&drv->driver, &driver_attr_idx_addr);
 	error |= driver_create_file(&drv->driver, &driver_attr_idx_data);
+	error |= driver_create_file(&drv->driver, &driver_attr_wqm_quanta);
 	return error;
 }
 
@@ -1095,6 +1171,7 @@
 	driver_remove_file(&drv->driver, &driver_attr_nonidx_data);
 	driver_remove_file(&drv->driver, &driver_attr_idx_addr);
 	driver_remove_file(&drv->driver, &driver_attr_idx_data);
+	driver_remove_file(&drv->driver, &driver_attr_wqm_quanta);
 }
 
 /**
diff --git a/drivers/infiniband/hw/nes/nes.h b/drivers/infiniband/hw/nes/nes.h
index 8eb7ae9..1595dc7 100644
--- a/drivers/infiniband/hw/nes/nes.h
+++ b/drivers/infiniband/hw/nes/nes.h
@@ -169,7 +169,7 @@
 extern unsigned int send_first;
 extern unsigned int nes_drv_opt;
 extern unsigned int nes_debug_level;
-
+extern unsigned int wqm_quanta;
 extern struct list_head nes_adapter_list;
 
 extern atomic_t cm_connects;
diff --git a/drivers/infiniband/hw/nes/nes_cm.c b/drivers/infiniband/hw/nes/nes_cm.c
index 9f0b964..2caf9da 100644
--- a/drivers/infiniband/hw/nes/nes_cm.c
+++ b/drivers/infiniband/hw/nes/nes_cm.c
@@ -52,7 +52,7 @@
 #include <linux/random.h>
 #include <linux/list.h>
 #include <linux/threads.h>
-
+#include <net/arp.h>
 #include <net/neighbour.h>
 #include <net/route.h>
 #include <net/ip_fib.h>
@@ -1019,23 +1019,43 @@
 
 
 /**
- * nes_addr_send_arp
+ * nes_addr_resolve_neigh
  */
-static void nes_addr_send_arp(u32 dst_ip)
+static int nes_addr_resolve_neigh(struct nes_vnic *nesvnic, u32 dst_ip)
 {
 	struct rtable *rt;
 	struct flowi fl;
+	struct neighbour *neigh;
+	int rc = -1;
+	DECLARE_MAC_BUF(mac);
 
 	memset(&fl, 0, sizeof fl);
 	fl.nl_u.ip4_u.daddr = htonl(dst_ip);
 	if (ip_route_output_key(&init_net, &rt, &fl)) {
 		printk("%s: ip_route_output_key failed for 0x%08X\n",
 				__func__, dst_ip);
-		return;
+		return rc;
 	}
 
-	neigh_event_send(rt->u.dst.neighbour, NULL);
+	neigh = neigh_lookup(&arp_tbl, &rt->rt_gateway, nesvnic->netdev);
+	if (neigh) {
+		if (neigh->nud_state & NUD_VALID) {
+			nes_debug(NES_DBG_CM, "Neighbor MAC address for 0x%08X"
+				  " is %s, Gateway is 0x%08X \n", dst_ip,
+				  print_mac(mac, neigh->ha), ntohl(rt->rt_gateway));
+			nes_manage_arp_cache(nesvnic->netdev, neigh->ha,
+					     dst_ip, NES_ARP_ADD);
+			rc = nes_arp_table(nesvnic->nesdev, dst_ip, NULL,
+					   NES_ARP_RESOLVE);
+		}
+		neigh_release(neigh);
+	}
+
+	if ((neigh == NULL) || (!(neigh->nud_state & NUD_VALID)))
+		neigh_event_send(rt->u.dst.neighbour, NULL);
+
 	ip_rt_put(rt);
+	return rc;
 }
 
 
@@ -1108,9 +1128,11 @@
 	/* get the mac addr for the remote node */
 	arpindex = nes_arp_table(nesdev, cm_node->rem_addr, NULL, NES_ARP_RESOLVE);
 	if (arpindex < 0) {
-		kfree(cm_node);
-		nes_addr_send_arp(cm_info->rem_addr);
-		return NULL;
+		arpindex = nes_addr_resolve_neigh(nesvnic, cm_info->rem_addr);
+		if (arpindex < 0) {
+			kfree(cm_node);
+			return NULL;
+		}
 	}
 
 	/* copy the mac addr to node context */
@@ -1826,7 +1848,7 @@
 /**
  * mini_cm_connect - make a connection node with params
  */
-struct nes_cm_node *mini_cm_connect(struct nes_cm_core *cm_core,
+static struct nes_cm_node *mini_cm_connect(struct nes_cm_core *cm_core,
 	struct nes_vnic *nesvnic, u16 private_data_len,
 	void *private_data, struct nes_cm_info *cm_info)
 {
@@ -1956,13 +1978,6 @@
 		return ret;
 	cleanup_retrans_entry(cm_node);
 	cm_node->state = NES_CM_STATE_CLOSED;
-	ret = send_fin(cm_node, NULL);
-
-	if (cm_node->accept_pend) {
-		BUG_ON(!cm_node->listener);
-		atomic_dec(&cm_node->listener->pend_accepts_cnt);
-		BUG_ON(atomic_read(&cm_node->listener->pend_accepts_cnt) < 0);
-	}
 
 	ret = send_reset(cm_node, NULL);
 	return ret;
@@ -2014,7 +2029,6 @@
 		ret = rem_ref_cm_node(cm_core, cm_node);
 		break;
 	}
-	cm_node->cm_id = NULL;
 	return ret;
 }
 
@@ -2383,6 +2397,7 @@
 			atomic_inc(&cm_disconnects);
 			cm_event.event = IW_CM_EVENT_DISCONNECT;
 			if (last_ae == NES_AEQE_AEID_LLP_CONNECTION_RESET) {
+				issued_disconnect_reset = 1;
 				cm_event.status = IW_CM_EVENT_STATUS_RESET;
 				nes_debug(NES_DBG_CM, "Generating a CM "
 					"Disconnect Event (status reset) for "
@@ -2508,7 +2523,6 @@
 		nes_debug(NES_DBG_CM, "Call close API\n");
 
 		g_cm_core->api->close(g_cm_core, nesqp->cm_node);
-		nesqp->cm_node = NULL;
 	}
 
 	return ret;
@@ -2837,6 +2851,7 @@
 	cm_node->apbvt_set = 1;
 	nesqp->cm_node = cm_node;
 	cm_node->nesqp = nesqp;
+	nes_add_ref(&nesqp->ibqp);
 
 	return 0;
 }
@@ -3167,7 +3182,6 @@
 	if (ret)
 		printk(KERN_ERR "%s[%u] OFA CM event_handler returned, "
 			"ret=%d\n", __func__, __LINE__, ret);
-	nes_rem_ref(&nesqp->ibqp);
 	cm_id->rem_ref(cm_id);
 
 	rem_ref_cm_node(event->cm_node->cm_core, event->cm_node);
diff --git a/drivers/infiniband/hw/nes/nes_hw.c b/drivers/infiniband/hw/nes/nes_hw.c
index 1513d40..7c49cc8 100644
--- a/drivers/infiniband/hw/nes/nes_hw.c
+++ b/drivers/infiniband/hw/nes/nes_hw.c
@@ -55,18 +55,19 @@
 u32 int_mod_cq_depth_16;
 u32 int_mod_cq_depth_4;
 u32 int_mod_cq_depth_1;
-
+static const u8 nes_max_critical_error_count = 100;
 #include "nes_cm.h"
 
 static void nes_cqp_ce_handler(struct nes_device *nesdev, struct nes_hw_cq *cq);
 static void nes_init_csr_ne020(struct nes_device *nesdev, u8 hw_rev, u8 port_count);
 static int nes_init_serdes(struct nes_device *nesdev, u8 hw_rev, u8 port_count,
-			   u8 OneG_Mode);
+				struct nes_adapter *nesadapter, u8  OneG_Mode);
 static void nes_nic_napi_ce_handler(struct nes_device *nesdev, struct nes_hw_nic_cq *cq);
 static void nes_process_aeq(struct nes_device *nesdev, struct nes_hw_aeq *aeq);
 static void nes_process_ceq(struct nes_device *nesdev, struct nes_hw_ceq *ceq);
 static void nes_process_iwarp_aeqe(struct nes_device *nesdev,
 				   struct nes_hw_aeqe *aeqe);
+static void process_critical_error(struct nes_device *nesdev);
 static void nes_process_mac_intr(struct nes_device *nesdev, u32 mac_number);
 static unsigned int nes_reset_adapter_ne020(struct nes_device *nesdev, u8 *OneG_Mode);
 
@@ -222,11 +223,10 @@
 	}
 
 	/* boundary checking */
-	if (shared_timer->timer_in_use > NES_NIC_FAST_TIMER_HIGH)
-		shared_timer->timer_in_use = NES_NIC_FAST_TIMER_HIGH;
-	else if (shared_timer->timer_in_use < NES_NIC_FAST_TIMER_LOW) {
-		shared_timer->timer_in_use = NES_NIC_FAST_TIMER_LOW;
-	}
+	if (shared_timer->timer_in_use > shared_timer->threshold_high)
+		shared_timer->timer_in_use = shared_timer->threshold_high;
+	else if (shared_timer->timer_in_use < shared_timer->threshold_low)
+		shared_timer->timer_in_use = shared_timer->threshold_low;
 
 	nesdev->currcq_count = 0;
 
@@ -292,9 +292,6 @@
 
 	if ((port_count = nes_reset_adapter_ne020(nesdev, &OneG_Mode)) == 0)
 		return NULL;
-	if (nes_init_serdes(nesdev, hw_rev, port_count, OneG_Mode))
-		return NULL;
-	nes_init_csr_ne020(nesdev, hw_rev, port_count);
 
 	max_qp = nes_read_indexed(nesdev, NES_IDX_QP_CTX_SIZE);
 	nes_debug(NES_DBG_INIT, "QP_CTX_SIZE=%u\n", max_qp);
@@ -353,6 +350,22 @@
 	nes_debug(NES_DBG_INIT, "Allocating new nesadapter @ %p, size = %u (actual size = %u).\n",
 			nesadapter, (u32)sizeof(struct nes_adapter), adapter_size);
 
+	if (nes_read_eeprom_values(nesdev, nesadapter)) {
+		printk(KERN_ERR PFX "Unable to read EEPROM data.\n");
+		kfree(nesadapter);
+		return NULL;
+	}
+
+	if (nes_init_serdes(nesdev, hw_rev, port_count, nesadapter,
+							OneG_Mode)) {
+		kfree(nesadapter);
+		return NULL;
+	}
+	nes_init_csr_ne020(nesdev, hw_rev, port_count);
+
+	memset(nesadapter->pft_mcast_map, 255,
+	       sizeof nesadapter->pft_mcast_map);
+
 	/* populate the new nesadapter */
 	nesadapter->devfn = nesdev->pcidev->devfn;
 	nesadapter->bus_number = nesdev->pcidev->bus->number;
@@ -468,20 +481,25 @@
 
 	/* setup port configuration */
 	if (nesadapter->port_count == 1) {
-		u32temp = 0x00000000;
+		nesadapter->log_port = 0x00000000;
 		if (nes_drv_opt & NES_DRV_OPT_DUAL_LOGICAL_PORT)
 			nes_write_indexed(nesdev, NES_IDX_TX_POOL_SIZE, 0x00000002);
 		else
 			nes_write_indexed(nesdev, NES_IDX_TX_POOL_SIZE, 0x00000003);
 	} else {
-		if (nesadapter->port_count == 2)
-			u32temp = 0x00000044;
-		else
-			u32temp = 0x000000e4;
+		if (nesadapter->phy_type[0] == NES_PHY_TYPE_PUMA_1G) {
+			nesadapter->log_port = 0x000000D8;
+		} else {
+			if (nesadapter->port_count == 2)
+				nesadapter->log_port = 0x00000044;
+			else
+				nesadapter->log_port = 0x000000e4;
+		}
 		nes_write_indexed(nesdev, NES_IDX_TX_POOL_SIZE, 0x00000003);
 	}
 
-	nes_write_indexed(nesdev, NES_IDX_NIC_LOGPORT_TO_PHYPORT, u32temp);
+	nes_write_indexed(nesdev, NES_IDX_NIC_LOGPORT_TO_PHYPORT,
+						nesadapter->log_port);
 	nes_debug(NES_DBG_INIT, "Probe time, LOG2PHY=%u\n",
 			nes_read_indexed(nesdev, NES_IDX_NIC_LOGPORT_TO_PHYPORT));
 
@@ -706,23 +724,43 @@
  * nes_init_serdes
  */
 static int nes_init_serdes(struct nes_device *nesdev, u8 hw_rev, u8 port_count,
-			   u8 OneG_Mode)
+				struct nes_adapter *nesadapter, u8  OneG_Mode)
 {
 	int i;
 	u32 u32temp;
+	u32 serdes_common_control;
 
 	if (hw_rev != NE020_REV) {
 		/* init serdes 0 */
 
 		nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_CDR_CONTROL0, 0x000000FF);
-		if (!OneG_Mode)
+		if (nesadapter->phy_type[0] == NES_PHY_TYPE_PUMA_1G) {
+			serdes_common_control = nes_read_indexed(nesdev,
+					NES_IDX_ETH_SERDES_COMMON_CONTROL0);
+			serdes_common_control |= 0x000000100;
+			nes_write_indexed(nesdev,
+					NES_IDX_ETH_SERDES_COMMON_CONTROL0,
+					serdes_common_control);
+		} else if (!OneG_Mode) {
 			nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_TX_HIGHZ_LANE_MODE0, 0x11110000);
-		if (port_count > 1) {
+		}
+		if (((port_count > 1) &&
+			(nesadapter->phy_type[0] != NES_PHY_TYPE_PUMA_1G)) ||
+			((port_count > 2) &&
+			(nesadapter->phy_type[0] == NES_PHY_TYPE_PUMA_1G))) {
 			/* init serdes 1 */
 			nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_CDR_CONTROL1, 0x000000FF);
-			if (!OneG_Mode)
+			if (nesadapter->phy_type[0] == NES_PHY_TYPE_PUMA_1G) {
+				serdes_common_control = nes_read_indexed(nesdev,
+					NES_IDX_ETH_SERDES_COMMON_CONTROL1);
+				serdes_common_control |= 0x000000100;
+				nes_write_indexed(nesdev,
+					NES_IDX_ETH_SERDES_COMMON_CONTROL1,
+					serdes_common_control);
+			} else if (!OneG_Mode) {
 				nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_TX_HIGHZ_LANE_MODE1, 0x11110000);
 			}
+		}
 	} else {
 		/* init serdes 0 */
 		nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_CONTROL0, 0x00000008);
@@ -826,7 +864,8 @@
 
 	nes_write_indexed(nesdev, 0x00005000, 0x00018000);
 	/* nes_write_indexed(nesdev, 0x00005000, 0x00010000); */
-	nes_write_indexed(nesdev, 0x00005004, 0x00020001);
+	nes_write_indexed(nesdev, NES_IDX_WQM_CONFIG1, (wqm_quanta << 1) |
+							 0x00000001);
 	nes_write_indexed(nesdev, 0x00005008, 0x1F1F1F1F);
 	nes_write_indexed(nesdev, 0x00005010, 0x1F1F1F1F);
 	nes_write_indexed(nesdev, 0x00005018, 0x1F1F1F1F);
@@ -1226,6 +1265,7 @@
 		if (nesadapter->phy_type[mac_index] == NES_PHY_TYPE_1G) {
 			printk(PFX "%s: Programming mdc config for 1G\n", __func__);
 			tx_config = nes_read_indexed(nesdev, NES_IDX_MAC_TX_CONFIG);
+			tx_config &= 0xFFFFFFE3;
 			tx_config |= 0x04;
 			nes_write_indexed(nesdev, NES_IDX_MAC_TX_CONFIG, tx_config);
 		}
@@ -1291,7 +1331,8 @@
 		    (nesadapter->phy_type[mac_index] == NES_PHY_TYPE_ARGUS)) {
 			/* setup 10G MDIO operation */
 			tx_config = nes_read_indexed(nesdev, NES_IDX_MAC_TX_CONFIG);
-			tx_config |= 0x14;
+			tx_config &= 0xFFFFFFE3;
+			tx_config |= 0x15;
 			nes_write_indexed(nesdev, NES_IDX_MAC_TX_CONFIG, tx_config);
 		}
 		if ((nesadapter->phy_type[mac_index] == NES_PHY_TYPE_ARGUS)) {
@@ -1315,7 +1356,7 @@
 				nes_write_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x1, 0xc319, 0x0008);
 				nes_write_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x1, 0xc31a, 0x0098);
 				nes_write_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x3, 0x0026, 0x0E00);
-				nes_write_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x3, 0x0027, 0x0000);
+				nes_write_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x3, 0x0027, 0x0001);
 				nes_write_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x3, 0x0028, 0xA528);
 
 				/*
@@ -1759,9 +1800,14 @@
  */
 void nes_destroy_nic_qp(struct nes_vnic *nesvnic)
 {
+	u64 u64temp;
+	dma_addr_t bus_address;
 	struct nes_device *nesdev = nesvnic->nesdev;
 	struct nes_hw_cqp_wqe *cqp_wqe;
+	struct nes_hw_nic_sq_wqe *nic_sqe;
 	struct nes_hw_nic_rq_wqe *nic_rqe;
+	__le16 *wqe_fragment_length;
+	u16  wqe_fragment_index;
 	u64 wqe_frag;
 	u32 cqp_head;
 	unsigned long flags;
@@ -1770,14 +1816,69 @@
 	/* Free remaining NIC receive buffers */
 	while (nesvnic->nic.rq_head != nesvnic->nic.rq_tail) {
 		nic_rqe   = &nesvnic->nic.rq_vbase[nesvnic->nic.rq_tail];
-		wqe_frag  = (u64)le32_to_cpu(nic_rqe->wqe_words[NES_NIC_RQ_WQE_FRAG0_LOW_IDX]);
-		wqe_frag |= ((u64)le32_to_cpu(nic_rqe->wqe_words[NES_NIC_RQ_WQE_FRAG0_HIGH_IDX])) << 32;
+		wqe_frag  = (u64)le32_to_cpu(
+			nic_rqe->wqe_words[NES_NIC_RQ_WQE_FRAG0_LOW_IDX]);
+		wqe_frag |= ((u64)le32_to_cpu(
+			nic_rqe->wqe_words[NES_NIC_RQ_WQE_FRAG0_HIGH_IDX]))<<32;
 		pci_unmap_single(nesdev->pcidev, (dma_addr_t)wqe_frag,
 				nesvnic->max_frame_size, PCI_DMA_FROMDEVICE);
 		dev_kfree_skb(nesvnic->nic.rx_skb[nesvnic->nic.rq_tail++]);
 		nesvnic->nic.rq_tail &= (nesvnic->nic.rq_size - 1);
 	}
 
+	/* Free remaining NIC transmit buffers */
+	while (nesvnic->nic.sq_head != nesvnic->nic.sq_tail) {
+		nic_sqe = &nesvnic->nic.sq_vbase[nesvnic->nic.sq_tail];
+		wqe_fragment_index = 1;
+		wqe_fragment_length = (__le16 *)
+			&nic_sqe->wqe_words[NES_NIC_SQ_WQE_LENGTH_0_TAG_IDX];
+		/* bump past the vlan tag */
+		wqe_fragment_length++;
+		if (le16_to_cpu(wqe_fragment_length[wqe_fragment_index]) != 0) {
+			u64temp = (u64)le32_to_cpu(
+				nic_sqe->wqe_words[NES_NIC_SQ_WQE_FRAG0_LOW_IDX+
+				wqe_fragment_index*2]);
+			u64temp += ((u64)le32_to_cpu(
+				nic_sqe->wqe_words[NES_NIC_SQ_WQE_FRAG0_HIGH_IDX
+				+ wqe_fragment_index*2]))<<32;
+			bus_address = (dma_addr_t)u64temp;
+			if (test_and_clear_bit(nesvnic->nic.sq_tail,
+					nesvnic->nic.first_frag_overflow)) {
+				pci_unmap_single(nesdev->pcidev,
+						bus_address,
+						le16_to_cpu(wqe_fragment_length[
+							wqe_fragment_index++]),
+						PCI_DMA_TODEVICE);
+			}
+			for (; wqe_fragment_index < 5; wqe_fragment_index++) {
+				if (wqe_fragment_length[wqe_fragment_index]) {
+					u64temp = le32_to_cpu(
+						nic_sqe->wqe_words[
+						NES_NIC_SQ_WQE_FRAG0_LOW_IDX+
+						wqe_fragment_index*2]);
+					u64temp += ((u64)le32_to_cpu(
+						nic_sqe->wqe_words[
+						NES_NIC_SQ_WQE_FRAG0_HIGH_IDX+
+						wqe_fragment_index*2]))<<32;
+					bus_address = (dma_addr_t)u64temp;
+					pci_unmap_page(nesdev->pcidev,
+							bus_address,
+							le16_to_cpu(
+							wqe_fragment_length[
+							wqe_fragment_index]),
+							PCI_DMA_TODEVICE);
+				} else
+					break;
+			}
+		}
+		if (nesvnic->nic.tx_skb[nesvnic->nic.sq_tail])
+			dev_kfree_skb(
+				nesvnic->nic.tx_skb[nesvnic->nic.sq_tail]);
+
+		nesvnic->nic.sq_tail = (++nesvnic->nic.sq_tail)
+					& (nesvnic->nic.sq_size - 1);
+	}
+
 	spin_lock_irqsave(&nesdev->cqp.lock, flags);
 
 	/* Destroy NIC QP */
@@ -1894,7 +1995,30 @@
 	}
 }
 
+static void process_critical_error(struct nes_device *nesdev)
+{
+	u32 debug_error;
+	u32 nes_idx_debug_error_masks0 = 0;
+	u16 error_module = 0;
 
+	debug_error = nes_read_indexed(nesdev, NES_IDX_DEBUG_ERROR_CONTROL_STATUS);
+	printk(KERN_ERR PFX "Critical Error reported by device!!! 0x%02X\n",
+			(u16)debug_error);
+	nes_write_indexed(nesdev, NES_IDX_DEBUG_ERROR_CONTROL_STATUS,
+			0x01010000 | (debug_error & 0x0000ffff));
+	if (crit_err_count++ > 10)
+		nes_write_indexed(nesdev, NES_IDX_DEBUG_ERROR_MASKS1, 1 << 0x17);
+	error_module = (u16) (debug_error & 0x1F00) >> 8;
+	if (++nesdev->nesadapter->crit_error_count[error_module-1] >=
+			nes_max_critical_error_count) {
+		printk(KERN_ERR PFX "Masking off critical error for module "
+			"0x%02X\n", (u16)error_module);
+		nes_idx_debug_error_masks0 = nes_read_indexed(nesdev,
+			NES_IDX_DEBUG_ERROR_MASKS0);
+		nes_write_indexed(nesdev, NES_IDX_DEBUG_ERROR_MASKS0,
+			nes_idx_debug_error_masks0 | (1 << error_module));
+	}
+}
 /**
  * nes_dpc
  */
@@ -1909,7 +2033,6 @@
 	u32 timer_stat;
 	u32 temp_int_stat;
 	u32 intf_int_stat;
-	u32 debug_error;
 	u32 processed_intf_int = 0;
 	u16 processed_timer_int = 0;
 	u16 completion_ints = 0;
@@ -1987,14 +2110,7 @@
 				intf_int_stat = nes_read32(nesdev->regs+NES_INTF_INT_STAT);
 				intf_int_stat &= nesdev->intf_int_req;
 				if (NES_INTF_INT_CRITERR & intf_int_stat) {
-					debug_error = nes_read_indexed(nesdev, NES_IDX_DEBUG_ERROR_CONTROL_STATUS);
-					printk(KERN_ERR PFX "Critical Error reported by device!!! 0x%02X\n",
-							(u16)debug_error);
-					nes_write_indexed(nesdev, NES_IDX_DEBUG_ERROR_CONTROL_STATUS,
-							0x01010000 | (debug_error & 0x0000ffff));
-					/* BUG(); */
-					if (crit_err_count++ > 10)
-						nes_write_indexed(nesdev, NES_IDX_DEBUG_ERROR_MASKS1, 1 << 0x17);
+					process_critical_error(nesdev);
 				}
 				if (NES_INTF_INT_PCIERR & intf_int_stat) {
 					printk(KERN_ERR PFX "PCI Error reported by device!!!\n");
@@ -2258,7 +2374,8 @@
 			spin_unlock_irqrestore(&nesadapter->phy_lock, flags);
 		}
 		/* read the PHY interrupt status register */
-		if (nesadapter->OneG_Mode) {
+		if ((nesadapter->OneG_Mode) &&
+		(nesadapter->phy_type[mac_index] != NES_PHY_TYPE_PUMA_1G)) {
 			do {
 				nes_read_1G_phy_reg(nesdev, 0x1a,
 						nesadapter->phy_index[mac_index], &phy_data);
@@ -3077,6 +3194,22 @@
 			nes_cm_disconn(nesqp);
 			break;
 			/* TODO: additional AEs need to be here */
+		case NES_AEQE_AEID_AMP_BOUNDS_VIOLATION:
+			nesqp = *((struct nes_qp **)&context);
+			spin_lock_irqsave(&nesqp->lock, flags);
+			nesqp->hw_iwarp_state = iwarp_state;
+			nesqp->hw_tcp_state = tcp_state;
+			nesqp->last_aeq = async_event_id;
+			spin_unlock_irqrestore(&nesqp->lock, flags);
+			if (nesqp->ibqp.event_handler) {
+				ibevent.device = nesqp->ibqp.device;
+				ibevent.element.qp = &nesqp->ibqp;
+				ibevent.event = IB_EVENT_QP_ACCESS_ERR;
+				nesqp->ibqp.event_handler(&ibevent,
+						nesqp->ibqp.qp_context);
+			}
+			nes_cm_disconn(nesqp);
+			break;
 		default:
 			nes_debug(NES_DBG_AEQ, "Processing an iWARP related AE for QP, misc = 0x%04X\n",
 					async_event_id);
diff --git a/drivers/infiniband/hw/nes/nes_hw.h b/drivers/infiniband/hw/nes/nes_hw.h
index 7b81e0a..610b9d8 100644
--- a/drivers/infiniband/hw/nes/nes_hw.h
+++ b/drivers/infiniband/hw/nes/nes_hw.h
@@ -156,6 +156,7 @@
 	NES_IDX_ENDNODE0_NSTAT_TX_OCTETS_HI = 0x7004,
 	NES_IDX_ENDNODE0_NSTAT_TX_FRAMES_LO = 0x7008,
 	NES_IDX_ENDNODE0_NSTAT_TX_FRAMES_HI = 0x700c,
+	NES_IDX_WQM_CONFIG1 = 0x5004,
 	NES_IDX_CM_CONFIG = 0x5100,
 	NES_IDX_NIC_LOGPORT_TO_PHYPORT = 0x6000,
 	NES_IDX_NIC_PHYPORT_TO_USW = 0x6008,
@@ -967,6 +968,7 @@
 #define DEFAULT_JUMBO_NES_QL_TARGET 40
 #define DEFAULT_JUMBO_NES_QL_HIGH   128
 #define NES_NIC_CQ_DOWNWARD_TREND   16
+#define NES_PFT_SIZE		    48
 
 struct nes_hw_tune_timer {
     /* u16 cq_count; */
@@ -1079,6 +1081,7 @@
 	u32 et_rx_max_coalesced_frames_high;
 	u32 et_rate_sample_interval;
 	u32 timer_int_limit;
+	u32 wqm_quanta;
 
 	/* Adapter base MAC address */
 	u32 mac_addr_low;
@@ -1094,12 +1097,14 @@
 	u16 pd_config_base[4];
 
 	u16 link_interrupt_count[4];
+	u8 crit_error_count[32];
 
 	/* the phy index for each port */
 	u8  phy_index[4];
 	u8  mac_sw_state[4];
 	u8  mac_link_down[4];
 	u8  phy_type[4];
+	u8  log_port;
 
 	/* PCI information */
 	unsigned int  devfn;
@@ -1113,6 +1118,7 @@
 	u8            virtwq;
 	u8            et_use_adaptive_rx_coalesce;
 	u8            adapter_fcn_count;
+	u8 pft_mcast_map[NES_PFT_SIZE];
 };
 
 struct nes_pbl {
diff --git a/drivers/infiniband/hw/nes/nes_nic.c b/drivers/infiniband/hw/nes/nes_nic.c
index 1b0938c..7303586 100644
--- a/drivers/infiniband/hw/nes/nes_nic.c
+++ b/drivers/infiniband/hw/nes/nes_nic.c
@@ -91,6 +91,7 @@
 static const u32 default_msg = NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK
 		| NETIF_MSG_IFUP | NETIF_MSG_IFDOWN;
 static int debug = -1;
+static int nics_per_function = 1;
 
 /**
  * nes_netdev_poll
@@ -201,7 +202,8 @@
 		nes_debug(NES_DBG_NETDEV, "i=%d, perfect filter table index= %d, PERF FILTER LOW"
 				" (Addr:%08X) = %08X, HIGH = %08X.\n",
 				i, nesvnic->qp_nic_index[i],
-				NES_IDX_PERFECT_FILTER_LOW+((nesvnic->perfect_filter_index + i) * 8),
+				NES_IDX_PERFECT_FILTER_LOW+
+					(nesvnic->qp_nic_index[i] * 8),
 				macaddr_low,
 				(u32)macaddr_high | NES_MAC_ADDR_VALID |
 				((((u32)nesvnic->nic_index) << 16)));
@@ -272,14 +274,18 @@
 			break;
 	}
 
-	if (first_nesvnic->netdev_open == 0)
+	if ((first_nesvnic->netdev_open == 1) && (first_nesvnic != nesvnic)  &&
+		(PCI_FUNC(first_nesvnic->nesdev->pcidev->devfn) !=
+		PCI_FUNC(nesvnic->nesdev->pcidev->devfn))) {
+			nes_write_indexed(nesdev, NES_IDX_MAC_INT_MASK+
+				(0x200*nesdev->mac_index), 0xffffffff);
+			nes_write_indexed(first_nesvnic->nesdev,
+				NES_IDX_MAC_INT_MASK+
+				(0x200*first_nesvnic->nesdev->mac_index),
+			~(NES_MAC_INT_LINK_STAT_CHG | NES_MAC_INT_XGMII_EXT |
+			NES_MAC_INT_TX_UNDERFLOW | NES_MAC_INT_TX_ERROR));
+	} else {
 		nes_write_indexed(nesdev, NES_IDX_MAC_INT_MASK+(0x200*nesdev->mac_index), 0xffffffff);
-	else if ((first_nesvnic != nesvnic) &&
-		 (PCI_FUNC(first_nesvnic->nesdev->pcidev->devfn) != PCI_FUNC(nesvnic->nesdev->pcidev->devfn))) {
-		nes_write_indexed(nesdev, NES_IDX_MAC_INT_MASK + (0x200 * nesdev->mac_index), 0xffffffff);
-		nes_write_indexed(first_nesvnic->nesdev, NES_IDX_MAC_INT_MASK + (0x200 * first_nesvnic->nesdev->mac_index),
-				~(NES_MAC_INT_LINK_STAT_CHG | NES_MAC_INT_XGMII_EXT |
-				NES_MAC_INT_TX_UNDERFLOW | NES_MAC_INT_TX_ERROR));
 	}
 
 	nic_active_mask = ~((u32)(1 << nesvnic->nic_index));
@@ -437,7 +443,7 @@
 	struct nes_hw_nic_sq_wqe *nic_sqe;
 	struct tcphdr *tcph;
 	/* struct udphdr *udph; */
-#define NES_MAX_TSO_FRAGS 18
+#define NES_MAX_TSO_FRAGS MAX_SKB_FRAGS
 	/* 64K segment plus overflow on each side */
 	dma_addr_t tso_bus_address[NES_MAX_TSO_FRAGS];
 	dma_addr_t bus_address;
@@ -605,6 +611,8 @@
 					wqe_fragment_length[wqe_fragment_index] = 0;
 					set_wqe_64bit_value(nic_sqe->wqe_words, NES_NIC_SQ_WQE_FRAG1_LOW_IDX,
 									bus_address);
+					tso_wqe_length += skb_headlen(skb) -
+							original_first_length;
 				}
 				while (wqe_fragment_index < 5) {
 					wqe_fragment_length[wqe_fragment_index] =
@@ -827,6 +835,7 @@
 {
 	struct nes_vnic *nesvnic = netdev_priv(netdev);
 	struct nes_device *nesdev = nesvnic->nesdev;
+	struct nes_adapter *nesadapter = nesvnic->nesdev->nesadapter;
 	struct dev_mc_list *multicast_addr;
 	u32 nic_active_bit;
 	u32 nic_active;
@@ -836,7 +845,12 @@
 	u8 mc_all_on = 0;
 	u8 mc_index;
 	int mc_nic_index = -1;
+	u8 pft_entries_preallocated = max(nesadapter->adapter_fcn_count *
+					nics_per_function, 4);
+	u8 max_pft_entries_avaiable = NES_PFT_SIZE - pft_entries_preallocated;
+	unsigned long flags;
 
+	spin_lock_irqsave(&nesadapter->resource_lock, flags);
 	nic_active_bit = 1 << nesvnic->nic_index;
 
 	if (netdev->flags & IFF_PROMISC) {
@@ -847,7 +861,7 @@
 		nic_active |= nic_active_bit;
 		nes_write_indexed(nesdev, NES_IDX_NIC_UNICAST_ALL, nic_active);
 		mc_all_on = 1;
-	} else if ((netdev->flags & IFF_ALLMULTI) || (netdev->mc_count > NES_MULTICAST_PF_MAX) ||
+	} else if ((netdev->flags & IFF_ALLMULTI) ||
 			   (nesvnic->nic_index > 3)) {
 		nic_active = nes_read_indexed(nesdev, NES_IDX_NIC_MULTICAST_ALL);
 		nic_active |= nic_active_bit;
@@ -866,17 +880,34 @@
 	}
 
 	nes_debug(NES_DBG_NIC_RX, "Number of MC entries = %d, Promiscous = %d, All Multicast = %d.\n",
-			  netdev->mc_count, (netdev->flags & IFF_PROMISC)?1:0,
-			  (netdev->flags & IFF_ALLMULTI)?1:0);
+		  netdev->mc_count, !!(netdev->flags & IFF_PROMISC),
+		  !!(netdev->flags & IFF_ALLMULTI));
 	if (!mc_all_on) {
 		multicast_addr = netdev->mc_list;
-		perfect_filter_register_address = NES_IDX_PERFECT_FILTER_LOW + 0x80;
-		perfect_filter_register_address += nesvnic->nic_index*0x40;
-		for (mc_index=0; mc_index < NES_MULTICAST_PF_MAX; mc_index++) {
-			while (multicast_addr && nesvnic->mcrq_mcast_filter && ((mc_nic_index = nesvnic->mcrq_mcast_filter(nesvnic, multicast_addr->dmi_addr)) == 0))
+		perfect_filter_register_address = NES_IDX_PERFECT_FILTER_LOW +
+						pft_entries_preallocated * 0x8;
+		for (mc_index = 0; mc_index < max_pft_entries_avaiable;
+		mc_index++) {
+			while (multicast_addr && nesvnic->mcrq_mcast_filter &&
+			((mc_nic_index = nesvnic->mcrq_mcast_filter(nesvnic,
+					multicast_addr->dmi_addr)) == 0)) {
 				multicast_addr = multicast_addr->next;
+			}
 			if (mc_nic_index < 0)
 				mc_nic_index = nesvnic->nic_index;
+			while (nesadapter->pft_mcast_map[mc_index] < 16 &&
+				nesadapter->pft_mcast_map[mc_index] !=
+					nesvnic->nic_index &&
+					mc_index < max_pft_entries_avaiable) {
+						nes_debug(NES_DBG_NIC_RX,
+					"mc_index=%d skipping nic_index=%d,\
+					used for=%d \n", mc_index,
+					nesvnic->nic_index,
+					nesadapter->pft_mcast_map[mc_index]);
+				mc_index++;
+			}
+			if (mc_index >= max_pft_entries_avaiable)
+				break;
 			if (multicast_addr) {
 				DECLARE_MAC_BUF(mac);
 				nes_debug(NES_DBG_NIC_RX, "Assigning MC Address %s to register 0x%04X nic_idx=%d\n",
@@ -897,15 +928,33 @@
 						(u32)macaddr_high | NES_MAC_ADDR_VALID |
 						((((u32)(1<<mc_nic_index)) << 16)));
 				multicast_addr = multicast_addr->next;
+				nesadapter->pft_mcast_map[mc_index] =
+							nesvnic->nic_index;
 			} else {
 				nes_debug(NES_DBG_NIC_RX, "Clearing MC Address at register 0x%04X\n",
 						  perfect_filter_register_address+(mc_index * 8));
 				nes_write_indexed(nesdev,
 						perfect_filter_register_address+4+(mc_index * 8),
 						0);
+				nesadapter->pft_mcast_map[mc_index] = 255;
 			}
 		}
+		/* PFT is not large enough */
+		if (multicast_addr && multicast_addr->next) {
+			nic_active = nes_read_indexed(nesdev,
+						NES_IDX_NIC_MULTICAST_ALL);
+			nic_active |= nic_active_bit;
+			nes_write_indexed(nesdev, NES_IDX_NIC_MULTICAST_ALL,
+								nic_active);
+			nic_active = nes_read_indexed(nesdev,
+						NES_IDX_NIC_UNICAST_ALL);
+			nic_active &= ~nic_active_bit;
+			nes_write_indexed(nesdev, NES_IDX_NIC_UNICAST_ALL,
+								nic_active);
+		}
 	}
+
+	spin_unlock_irqrestore(&nesadapter->resource_lock, flags);
 }
 
 
@@ -918,6 +967,10 @@
 	struct nes_device *nesdev = nesvnic->nesdev;
 	int ret = 0;
 	u8 jumbomode = 0;
+	u32 nic_active;
+	u32 nic_active_bit;
+	u32 uc_all_active;
+	u32 mc_all_active;
 
 	if ((new_mtu < ETH_ZLEN) || (new_mtu > max_mtu))
 		return -EINVAL;
@@ -931,8 +984,24 @@
 	nes_nic_init_timer_defaults(nesdev, jumbomode);
 
 	if (netif_running(netdev)) {
+		nic_active_bit = 1 << nesvnic->nic_index;
+		mc_all_active = nes_read_indexed(nesdev,
+				NES_IDX_NIC_MULTICAST_ALL) & nic_active_bit;
+		uc_all_active = nes_read_indexed(nesdev,
+				NES_IDX_NIC_UNICAST_ALL)  & nic_active_bit;
+
 		nes_netdev_stop(netdev);
 		nes_netdev_open(netdev);
+
+		nic_active = nes_read_indexed(nesdev,
+					NES_IDX_NIC_MULTICAST_ALL);
+		nic_active |= mc_all_active;
+		nes_write_indexed(nesdev, NES_IDX_NIC_MULTICAST_ALL,
+							nic_active);
+
+		nic_active = nes_read_indexed(nesdev, NES_IDX_NIC_UNICAST_ALL);
+		nic_active |= uc_all_active;
+		nes_write_indexed(nesdev, NES_IDX_NIC_UNICAST_ALL, nic_active);
 	}
 
 	return ret;
@@ -1208,10 +1277,12 @@
 		struct ethtool_drvinfo *drvinfo)
 {
 	struct nes_vnic *nesvnic = netdev_priv(netdev);
+	struct nes_adapter *nesadapter = nesvnic->nesdev->nesadapter;
 
 	strcpy(drvinfo->driver, DRV_NAME);
 	strcpy(drvinfo->bus_info, pci_name(nesvnic->nesdev->pcidev));
-	strcpy(drvinfo->fw_version, "TBD");
+	sprintf(drvinfo->fw_version, "%u.%u", nesadapter->firmware_version>>16,
+				nesadapter->firmware_version & 0x000000ff);
 	strcpy(drvinfo->version, DRV_VERSION);
 	drvinfo->n_stats = nes_netdev_get_stats_count(netdev);
 	drvinfo->testinfo_len = 0;
@@ -1587,7 +1658,9 @@
 			nesvnic, (unsigned long)netdev->features, nesvnic->nic.qp_id,
 			nesvnic->nic_index, nesvnic->logical_port,  nesdev->mac_index);
 
-	if (nesvnic->nesdev->nesadapter->port_count == 1) {
+	if (nesvnic->nesdev->nesadapter->port_count == 1 &&
+		nesvnic->nesdev->nesadapter->adapter_fcn_count == 1) {
+
 		nesvnic->qp_nic_index[0] = nesvnic->nic_index;
 		nesvnic->qp_nic_index[1] = nesvnic->nic_index + 1;
 		if (nes_drv_opt & NES_DRV_OPT_DUAL_LOGICAL_PORT) {
@@ -1598,11 +1671,14 @@
 			nesvnic->qp_nic_index[3] = nesvnic->nic_index + 3;
 		}
 	} else {
-		if (nesvnic->nesdev->nesadapter->port_count == 2) {
-			nesvnic->qp_nic_index[0] = nesvnic->nic_index;
-			nesvnic->qp_nic_index[1] = nesvnic->nic_index + 2;
-			nesvnic->qp_nic_index[2] = 0xf;
-			nesvnic->qp_nic_index[3] = 0xf;
+		if (nesvnic->nesdev->nesadapter->port_count == 2 ||
+			(nesvnic->nesdev->nesadapter->port_count == 1 &&
+			nesvnic->nesdev->nesadapter->adapter_fcn_count == 2)) {
+				nesvnic->qp_nic_index[0] = nesvnic->nic_index;
+				nesvnic->qp_nic_index[1] = nesvnic->nic_index
+									+ 2;
+				nesvnic->qp_nic_index[2] = 0xf;
+				nesvnic->qp_nic_index[3] = 0xf;
 		} else {
 			nesvnic->qp_nic_index[0] = nesvnic->nic_index;
 			nesvnic->qp_nic_index[1] = 0xf;
diff --git a/drivers/infiniband/hw/nes/nes_verbs.c b/drivers/infiniband/hw/nes/nes_verbs.c
index d79942e..932e56f 100644
--- a/drivers/infiniband/hw/nes/nes_verbs.c
+++ b/drivers/infiniband/hw/nes/nes_verbs.c
@@ -1467,7 +1467,6 @@
 		default:
 			nes_debug(NES_DBG_QP, "Invalid QP type: %d\n", init_attr->qp_type);
 			return ERR_PTR(-EINVAL);
-			break;
 	}
 
 	/* update the QP table */
@@ -2498,7 +2497,6 @@
 			nes_debug(NES_DBG_MR, "Leaving, ibmr=%p", ibmr);
 
 			return ibmr;
-			break;
 		case IWNES_MEMREG_TYPE_QP:
 		case IWNES_MEMREG_TYPE_CQ:
 			nespbl = kzalloc(sizeof(*nespbl), GFP_KERNEL);
@@ -2572,7 +2570,6 @@
 			nesmr->ibmr.lkey = -1;
 			nesmr->mode = req.reg_type;
 			return &nesmr->ibmr;
-			break;
 	}
 
 	return ERR_PTR(-ENOSYS);
diff --git a/drivers/infiniband/ulp/ipoib/ipoib.h b/drivers/infiniband/ulp/ipoib/ipoib.h
index b0ffc9a..68ba5c3 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib.h
+++ b/drivers/infiniband/ulp/ipoib/ipoib.h
@@ -268,10 +268,9 @@
 };
 
 /*
- * Device private locking: tx_lock protects members used in TX fast
- * path (and we use LLTX so upper layers don't do extra locking).
- * lock protects everything else.  lock nests inside of tx_lock (ie
- * tx_lock must be acquired first if needed).
+ * Device private locking: network stack tx_lock protects members used
+ * in TX fast path, lock protects everything else.  lock nests inside
+ * of tx_lock (ie tx_lock must be acquired first if needed).
  */
 struct ipoib_dev_priv {
 	spinlock_t lock;
@@ -293,6 +292,7 @@
 
 	struct delayed_work pkey_poll_task;
 	struct delayed_work mcast_task;
+	struct work_struct carrier_on_task;
 	struct work_struct flush_light;
 	struct work_struct flush_normal;
 	struct work_struct flush_heavy;
@@ -319,7 +319,6 @@
 
 	struct ipoib_rx_buf *rx_ring;
 
-	spinlock_t	     tx_lock;
 	struct ipoib_tx_buf *tx_ring;
 	unsigned	     tx_head;
 	unsigned	     tx_tail;
@@ -464,6 +463,7 @@
 void ipoib_dev_cleanup(struct net_device *dev);
 
 void ipoib_mcast_join_task(struct work_struct *work);
+void ipoib_mcast_carrier_on_task(struct work_struct *work);
 void ipoib_mcast_send(struct net_device *dev, void *mgid, struct sk_buff *skb);
 
 void ipoib_mcast_restart_task(struct work_struct *work);
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_cm.c b/drivers/infiniband/ulp/ipoib/ipoib_cm.c
index 341ffed..7b14c2c 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_cm.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_cm.c
@@ -786,7 +786,8 @@
 
 	dev_kfree_skb_any(tx_req->skb);
 
-	spin_lock_irqsave(&priv->tx_lock, flags);
+	netif_tx_lock(dev);
+
 	++tx->tx_tail;
 	if (unlikely(--priv->tx_outstanding == ipoib_sendq_size >> 1) &&
 	    netif_queue_stopped(dev) &&
@@ -801,7 +802,7 @@
 			   "(status=%d, wrid=%d vend_err %x)\n",
 			   wc->status, wr_id, wc->vendor_err);
 
-		spin_lock(&priv->lock);
+		spin_lock_irqsave(&priv->lock, flags);
 		neigh = tx->neigh;
 
 		if (neigh) {
@@ -821,10 +822,10 @@
 
 		clear_bit(IPOIB_FLAG_OPER_UP, &tx->flags);
 
-		spin_unlock(&priv->lock);
+		spin_unlock_irqrestore(&priv->lock, flags);
 	}
 
-	spin_unlock_irqrestore(&priv->tx_lock, flags);
+	netif_tx_unlock(dev);
 }
 
 int ipoib_cm_dev_open(struct net_device *dev)
@@ -1149,7 +1150,6 @@
 {
 	struct ipoib_dev_priv *priv = netdev_priv(p->dev);
 	struct ipoib_cm_tx_buf *tx_req;
-	unsigned long flags;
 	unsigned long begin;
 
 	ipoib_dbg(priv, "Destroy active connection 0x%x head 0x%x tail 0x%x\n",
@@ -1180,12 +1180,12 @@
 				    DMA_TO_DEVICE);
 		dev_kfree_skb_any(tx_req->skb);
 		++p->tx_tail;
-		spin_lock_irqsave(&priv->tx_lock, flags);
+		netif_tx_lock_bh(p->dev);
 		if (unlikely(--priv->tx_outstanding == ipoib_sendq_size >> 1) &&
 		    netif_queue_stopped(p->dev) &&
 		    test_bit(IPOIB_FLAG_ADMIN_UP, &priv->flags))
 			netif_wake_queue(p->dev);
-		spin_unlock_irqrestore(&priv->tx_lock, flags);
+		netif_tx_unlock_bh(p->dev);
 	}
 
 	if (p->qp)
@@ -1202,6 +1202,7 @@
 	struct ipoib_dev_priv *priv = netdev_priv(tx->dev);
 	struct net_device *dev = priv->dev;
 	struct ipoib_neigh *neigh;
+	unsigned long flags;
 	int ret;
 
 	switch (event->event) {
@@ -1220,8 +1221,8 @@
 	case IB_CM_REJ_RECEIVED:
 	case IB_CM_TIMEWAIT_EXIT:
 		ipoib_dbg(priv, "CM error %d.\n", event->event);
-		spin_lock_irq(&priv->tx_lock);
-		spin_lock(&priv->lock);
+		netif_tx_lock_bh(dev);
+		spin_lock_irqsave(&priv->lock, flags);
 		neigh = tx->neigh;
 
 		if (neigh) {
@@ -1239,8 +1240,8 @@
 			queue_work(ipoib_workqueue, &priv->cm.reap_task);
 		}
 
-		spin_unlock(&priv->lock);
-		spin_unlock_irq(&priv->tx_lock);
+		spin_unlock_irqrestore(&priv->lock, flags);
+		netif_tx_unlock_bh(dev);
 		break;
 	default:
 		break;
@@ -1294,19 +1295,24 @@
 	struct ib_sa_path_rec pathrec;
 	u32 qpn;
 
-	spin_lock_irqsave(&priv->tx_lock, flags);
-	spin_lock(&priv->lock);
+	netif_tx_lock_bh(dev);
+	spin_lock_irqsave(&priv->lock, flags);
+
 	while (!list_empty(&priv->cm.start_list)) {
 		p = list_entry(priv->cm.start_list.next, typeof(*p), list);
 		list_del_init(&p->list);
 		neigh = p->neigh;
 		qpn = IPOIB_QPN(neigh->neighbour->ha);
 		memcpy(&pathrec, &p->path->pathrec, sizeof pathrec);
-		spin_unlock(&priv->lock);
-		spin_unlock_irqrestore(&priv->tx_lock, flags);
+
+		spin_unlock_irqrestore(&priv->lock, flags);
+		netif_tx_unlock_bh(dev);
+
 		ret = ipoib_cm_tx_init(p, qpn, &pathrec);
-		spin_lock_irqsave(&priv->tx_lock, flags);
-		spin_lock(&priv->lock);
+
+		netif_tx_lock_bh(dev);
+		spin_lock_irqsave(&priv->lock, flags);
+
 		if (ret) {
 			neigh = p->neigh;
 			if (neigh) {
@@ -1320,44 +1326,52 @@
 			kfree(p);
 		}
 	}
-	spin_unlock(&priv->lock);
-	spin_unlock_irqrestore(&priv->tx_lock, flags);
+
+	spin_unlock_irqrestore(&priv->lock, flags);
+	netif_tx_unlock_bh(dev);
 }
 
 static void ipoib_cm_tx_reap(struct work_struct *work)
 {
 	struct ipoib_dev_priv *priv = container_of(work, struct ipoib_dev_priv,
 						   cm.reap_task);
+	struct net_device *dev = priv->dev;
 	struct ipoib_cm_tx *p;
+	unsigned long flags;
 
-	spin_lock_irq(&priv->tx_lock);
-	spin_lock(&priv->lock);
+	netif_tx_lock_bh(dev);
+	spin_lock_irqsave(&priv->lock, flags);
+
 	while (!list_empty(&priv->cm.reap_list)) {
 		p = list_entry(priv->cm.reap_list.next, typeof(*p), list);
 		list_del(&p->list);
-		spin_unlock(&priv->lock);
-		spin_unlock_irq(&priv->tx_lock);
+		spin_unlock_irqrestore(&priv->lock, flags);
+		netif_tx_unlock_bh(dev);
 		ipoib_cm_tx_destroy(p);
-		spin_lock_irq(&priv->tx_lock);
-		spin_lock(&priv->lock);
+		netif_tx_lock_bh(dev);
+		spin_lock_irqsave(&priv->lock, flags);
 	}
-	spin_unlock(&priv->lock);
-	spin_unlock_irq(&priv->tx_lock);
+
+	spin_unlock_irqrestore(&priv->lock, flags);
+	netif_tx_unlock_bh(dev);
 }
 
 static void ipoib_cm_skb_reap(struct work_struct *work)
 {
 	struct ipoib_dev_priv *priv = container_of(work, struct ipoib_dev_priv,
 						   cm.skb_task);
+	struct net_device *dev = priv->dev;
 	struct sk_buff *skb;
-
+	unsigned long flags;
 	unsigned mtu = priv->mcast_mtu;
 
-	spin_lock_irq(&priv->tx_lock);
-	spin_lock(&priv->lock);
+	netif_tx_lock_bh(dev);
+	spin_lock_irqsave(&priv->lock, flags);
+
 	while ((skb = skb_dequeue(&priv->cm.skb_queue))) {
-		spin_unlock(&priv->lock);
-		spin_unlock_irq(&priv->tx_lock);
+		spin_unlock_irqrestore(&priv->lock, flags);
+		netif_tx_unlock_bh(dev);
+
 		if (skb->protocol == htons(ETH_P_IP))
 			icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, htonl(mtu));
 #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
@@ -1365,11 +1379,13 @@
 			icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu, priv->dev);
 #endif
 		dev_kfree_skb_any(skb);
-		spin_lock_irq(&priv->tx_lock);
-		spin_lock(&priv->lock);
+
+		netif_tx_lock_bh(dev);
+		spin_lock_irqsave(&priv->lock, flags);
 	}
-	spin_unlock(&priv->lock);
-	spin_unlock_irq(&priv->tx_lock);
+
+	spin_unlock_irqrestore(&priv->lock, flags);
+	netif_tx_unlock_bh(dev);
 }
 
 void ipoib_cm_skb_too_long(struct net_device *dev, struct sk_buff *skb,
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_ib.c b/drivers/infiniband/ulp/ipoib/ipoib_ib.c
index 66cafa2..0e748ae 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_ib.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_ib.c
@@ -468,21 +468,22 @@
 static void drain_tx_cq(struct net_device *dev)
 {
 	struct ipoib_dev_priv *priv = netdev_priv(dev);
-	unsigned long flags;
 
-	spin_lock_irqsave(&priv->tx_lock, flags);
+	netif_tx_lock(dev);
 	while (poll_tx(priv))
 		; /* nothing */
 
 	if (netif_queue_stopped(dev))
 		mod_timer(&priv->poll_timer, jiffies + 1);
 
-	spin_unlock_irqrestore(&priv->tx_lock, flags);
+	netif_tx_unlock(dev);
 }
 
 void ipoib_send_comp_handler(struct ib_cq *cq, void *dev_ptr)
 {
-	drain_tx_cq((struct net_device *)dev_ptr);
+	struct ipoib_dev_priv *priv = netdev_priv(dev_ptr);
+
+	mod_timer(&priv->poll_timer, jiffies);
 }
 
 static inline int post_send(struct ipoib_dev_priv *priv,
@@ -614,17 +615,20 @@
 	struct ipoib_dev_priv *priv = netdev_priv(dev);
 	struct ipoib_ah *ah, *tah;
 	LIST_HEAD(remove_list);
+	unsigned long flags;
 
-	spin_lock_irq(&priv->tx_lock);
-	spin_lock(&priv->lock);
+	netif_tx_lock_bh(dev);
+	spin_lock_irqsave(&priv->lock, flags);
+
 	list_for_each_entry_safe(ah, tah, &priv->dead_ahs, list)
 		if ((int) priv->tx_tail - (int) ah->last_send >= 0) {
 			list_del(&ah->list);
 			ib_destroy_ah(ah->ah);
 			kfree(ah);
 		}
-	spin_unlock(&priv->lock);
-	spin_unlock_irq(&priv->tx_lock);
+
+	spin_unlock_irqrestore(&priv->lock, flags);
+	netif_tx_unlock_bh(dev);
 }
 
 void ipoib_reap_ah(struct work_struct *work)
@@ -761,6 +765,14 @@
 {
 	struct ipoib_dev_priv *priv = netdev_priv(dev);
 	int i, n;
+
+	/*
+	 * We call completion handling routines that expect to be
+	 * called from the BH-disabled NAPI poll context, so disable
+	 * BHs here too.
+	 */
+	local_bh_disable();
+
 	do {
 		n = ib_poll_cq(priv->recv_cq, IPOIB_NUM_WC, priv->ibwc);
 		for (i = 0; i < n; ++i) {
@@ -784,6 +796,8 @@
 
 	while (poll_tx(priv))
 		; /* nothing */
+
+	local_bh_enable();
 }
 
 int ipoib_ib_dev_stop(struct net_device *dev, int flush)
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c
index 7e9e218..c0ee5143 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_main.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c
@@ -373,9 +373,10 @@
 	struct ipoib_dev_priv *priv = netdev_priv(dev);
 	struct ipoib_path *path, *tp;
 	LIST_HEAD(remove_list);
+	unsigned long flags;
 
-	spin_lock_irq(&priv->tx_lock);
-	spin_lock(&priv->lock);
+	netif_tx_lock_bh(dev);
+	spin_lock_irqsave(&priv->lock, flags);
 
 	list_splice_init(&priv->path_list, &remove_list);
 
@@ -385,15 +386,16 @@
 	list_for_each_entry_safe(path, tp, &remove_list, list) {
 		if (path->query)
 			ib_sa_cancel_query(path->query_id, path->query);
-		spin_unlock(&priv->lock);
-		spin_unlock_irq(&priv->tx_lock);
+		spin_unlock_irqrestore(&priv->lock, flags);
+		netif_tx_unlock_bh(dev);
 		wait_for_completion(&path->done);
 		path_free(dev, path);
-		spin_lock_irq(&priv->tx_lock);
-		spin_lock(&priv->lock);
+		netif_tx_lock_bh(dev);
+		spin_lock_irqsave(&priv->lock, flags);
 	}
-	spin_unlock(&priv->lock);
-	spin_unlock_irq(&priv->tx_lock);
+
+	spin_unlock_irqrestore(&priv->lock, flags);
+	netif_tx_unlock_bh(dev);
 }
 
 static void path_rec_completion(int status,
@@ -404,7 +406,7 @@
 	struct net_device *dev = path->dev;
 	struct ipoib_dev_priv *priv = netdev_priv(dev);
 	struct ipoib_ah *ah = NULL;
-	struct ipoib_ah *old_ah;
+	struct ipoib_ah *old_ah = NULL;
 	struct ipoib_neigh *neigh, *tn;
 	struct sk_buff_head skqueue;
 	struct sk_buff *skb;
@@ -428,12 +430,12 @@
 
 	spin_lock_irqsave(&priv->lock, flags);
 
-	old_ah   = path->ah;
-	path->ah = ah;
-
 	if (ah) {
 		path->pathrec = *pathrec;
 
+		old_ah   = path->ah;
+		path->ah = ah;
+
 		ipoib_dbg(priv, "created address handle %p for LID 0x%04x, SL %d\n",
 			  ah, be16_to_cpu(pathrec->dlid), pathrec->sl);
 
@@ -555,6 +557,7 @@
 	struct ipoib_dev_priv *priv = netdev_priv(dev);
 	struct ipoib_path *path;
 	struct ipoib_neigh *neigh;
+	unsigned long flags;
 
 	neigh = ipoib_neigh_alloc(skb->dst->neighbour, skb->dev);
 	if (!neigh) {
@@ -563,11 +566,7 @@
 		return;
 	}
 
-	/*
-	 * We can only be called from ipoib_start_xmit, so we're
-	 * inside tx_lock -- no need to save/restore flags.
-	 */
-	spin_lock(&priv->lock);
+	spin_lock_irqsave(&priv->lock, flags);
 
 	path = __path_find(dev, skb->dst->neighbour->ha + 4);
 	if (!path) {
@@ -614,7 +613,7 @@
 		__skb_queue_tail(&neigh->queue, skb);
 	}
 
-	spin_unlock(&priv->lock);
+	spin_unlock_irqrestore(&priv->lock, flags);
 	return;
 
 err_list:
@@ -626,7 +625,7 @@
 	++dev->stats.tx_dropped;
 	dev_kfree_skb_any(skb);
 
-	spin_unlock(&priv->lock);
+	spin_unlock_irqrestore(&priv->lock, flags);
 }
 
 static void ipoib_path_lookup(struct sk_buff *skb, struct net_device *dev)
@@ -650,12 +649,9 @@
 {
 	struct ipoib_dev_priv *priv = netdev_priv(dev);
 	struct ipoib_path *path;
+	unsigned long flags;
 
-	/*
-	 * We can only be called from ipoib_start_xmit, so we're
-	 * inside tx_lock -- no need to save/restore flags.
-	 */
-	spin_lock(&priv->lock);
+	spin_lock_irqsave(&priv->lock, flags);
 
 	path = __path_find(dev, phdr->hwaddr + 4);
 	if (!path || !path->valid) {
@@ -667,7 +663,7 @@
 			__skb_queue_tail(&path->queue, skb);
 
 			if (path_rec_start(dev, path)) {
-				spin_unlock(&priv->lock);
+				spin_unlock_irqrestore(&priv->lock, flags);
 				path_free(dev, path);
 				return;
 			} else
@@ -677,7 +673,7 @@
 			dev_kfree_skb_any(skb);
 		}
 
-		spin_unlock(&priv->lock);
+		spin_unlock_irqrestore(&priv->lock, flags);
 		return;
 	}
 
@@ -696,7 +692,7 @@
 		dev_kfree_skb_any(skb);
 	}
 
-	spin_unlock(&priv->lock);
+	spin_unlock_irqrestore(&priv->lock, flags);
 }
 
 static int ipoib_start_xmit(struct sk_buff *skb, struct net_device *dev)
@@ -705,13 +701,10 @@
 	struct ipoib_neigh *neigh;
 	unsigned long flags;
 
-	if (unlikely(!spin_trylock_irqsave(&priv->tx_lock, flags)))
-		return NETDEV_TX_LOCKED;
-
 	if (likely(skb->dst && skb->dst->neighbour)) {
 		if (unlikely(!*to_ipoib_neigh(skb->dst->neighbour))) {
 			ipoib_path_lookup(skb, dev);
-			goto out;
+			return NETDEV_TX_OK;
 		}
 
 		neigh = *to_ipoib_neigh(skb->dst->neighbour);
@@ -721,7 +714,7 @@
 					    skb->dst->neighbour->ha + 4,
 					    sizeof(union ib_gid))) ||
 					 (neigh->dev != dev))) {
-				spin_lock(&priv->lock);
+				spin_lock_irqsave(&priv->lock, flags);
 				/*
 				 * It's safe to call ipoib_put_ah() inside
 				 * priv->lock here, because we know that
@@ -732,25 +725,25 @@
 				ipoib_put_ah(neigh->ah);
 				list_del(&neigh->list);
 				ipoib_neigh_free(dev, neigh);
-				spin_unlock(&priv->lock);
+				spin_unlock_irqrestore(&priv->lock, flags);
 				ipoib_path_lookup(skb, dev);
-				goto out;
+				return NETDEV_TX_OK;
 			}
 
 		if (ipoib_cm_get(neigh)) {
 			if (ipoib_cm_up(neigh)) {
 				ipoib_cm_send(dev, skb, ipoib_cm_get(neigh));
-				goto out;
+				return NETDEV_TX_OK;
 			}
 		} else if (neigh->ah) {
 			ipoib_send(dev, skb, neigh->ah, IPOIB_QPN(skb->dst->neighbour->ha));
-			goto out;
+			return NETDEV_TX_OK;
 		}
 
 		if (skb_queue_len(&neigh->queue) < IPOIB_MAX_PATH_REC_QUEUE) {
-			spin_lock(&priv->lock);
+			spin_lock_irqsave(&priv->lock, flags);
 			__skb_queue_tail(&neigh->queue, skb);
-			spin_unlock(&priv->lock);
+			spin_unlock_irqrestore(&priv->lock, flags);
 		} else {
 			++dev->stats.tx_dropped;
 			dev_kfree_skb_any(skb);
@@ -779,16 +772,13 @@
 					   IPOIB_GID_RAW_ARG(phdr->hwaddr + 4));
 				dev_kfree_skb_any(skb);
 				++dev->stats.tx_dropped;
-				goto out;
+				return NETDEV_TX_OK;
 			}
 
 			unicast_arp_send(skb, dev, phdr);
 		}
 	}
 
-out:
-	spin_unlock_irqrestore(&priv->tx_lock, flags);
-
 	return NETDEV_TX_OK;
 }
 
@@ -1052,7 +1042,6 @@
 	dev->type		 = ARPHRD_INFINIBAND;
 	dev->tx_queue_len	 = ipoib_sendq_size * 2;
 	dev->features		 = (NETIF_F_VLAN_CHALLENGED	|
-				    NETIF_F_LLTX		|
 				    NETIF_F_HIGHDMA);
 
 	memcpy(dev->broadcast, ipv4_bcast_addr, INFINIBAND_ALEN);
@@ -1064,7 +1053,6 @@
 	ipoib_lro_setup(priv);
 
 	spin_lock_init(&priv->lock);
-	spin_lock_init(&priv->tx_lock);
 
 	mutex_init(&priv->vlan_mutex);
 
@@ -1075,6 +1063,7 @@
 
 	INIT_DELAYED_WORK(&priv->pkey_poll_task, ipoib_pkey_poll);
 	INIT_DELAYED_WORK(&priv->mcast_task,   ipoib_mcast_join_task);
+	INIT_WORK(&priv->carrier_on_task, ipoib_mcast_carrier_on_task);
 	INIT_WORK(&priv->flush_light,   ipoib_ib_dev_flush_light);
 	INIT_WORK(&priv->flush_normal,   ipoib_ib_dev_flush_normal);
 	INIT_WORK(&priv->flush_heavy,   ipoib_ib_dev_flush_heavy);
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
index ac33c8f..d9d1223 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
@@ -69,14 +69,13 @@
 	struct net_device *dev = mcast->dev;
 	struct ipoib_dev_priv *priv = netdev_priv(dev);
 	struct ipoib_neigh *neigh, *tmp;
-	unsigned long flags;
 	int tx_dropped = 0;
 
 	ipoib_dbg_mcast(netdev_priv(dev),
 			"deleting multicast group " IPOIB_GID_FMT "\n",
 			IPOIB_GID_ARG(mcast->mcmember.mgid));
 
-	spin_lock_irqsave(&priv->lock, flags);
+	spin_lock_irq(&priv->lock);
 
 	list_for_each_entry_safe(neigh, tmp, &mcast->neigh_list, list) {
 		/*
@@ -90,7 +89,7 @@
 		ipoib_neigh_free(dev, neigh);
 	}
 
-	spin_unlock_irqrestore(&priv->lock, flags);
+	spin_unlock_irq(&priv->lock);
 
 	if (mcast->ah)
 		ipoib_put_ah(mcast->ah);
@@ -100,9 +99,9 @@
 		dev_kfree_skb_any(skb_dequeue(&mcast->pkt_queue));
 	}
 
-	spin_lock_irqsave(&priv->tx_lock, flags);
+	netif_tx_lock_bh(dev);
 	dev->stats.tx_dropped += tx_dropped;
-	spin_unlock_irqrestore(&priv->tx_lock, flags);
+	netif_tx_unlock_bh(dev);
 
 	kfree(mcast);
 }
@@ -259,10 +258,10 @@
 	}
 
 	/* actually send any queued packets */
-	spin_lock_irq(&priv->tx_lock);
+	netif_tx_lock_bh(dev);
 	while (!skb_queue_empty(&mcast->pkt_queue)) {
 		struct sk_buff *skb = skb_dequeue(&mcast->pkt_queue);
-		spin_unlock_irq(&priv->tx_lock);
+		netif_tx_unlock_bh(dev);
 
 		skb->dev = dev;
 
@@ -273,9 +272,9 @@
 
 		if (dev_queue_xmit(skb))
 			ipoib_warn(priv, "dev_queue_xmit failed to requeue packet\n");
-		spin_lock_irq(&priv->tx_lock);
+		netif_tx_lock_bh(dev);
 	}
-	spin_unlock_irq(&priv->tx_lock);
+	netif_tx_unlock_bh(dev);
 
 	return 0;
 }
@@ -286,7 +285,6 @@
 {
 	struct ipoib_mcast *mcast = multicast->context;
 	struct net_device *dev = mcast->dev;
-	struct ipoib_dev_priv *priv = netdev_priv(dev);
 
 	/* We trap for port events ourselves. */
 	if (status == -ENETRESET)
@@ -302,12 +300,12 @@
 					IPOIB_GID_ARG(mcast->mcmember.mgid), status);
 
 		/* Flush out any queued packets */
-		spin_lock_irq(&priv->tx_lock);
+		netif_tx_lock_bh(dev);
 		while (!skb_queue_empty(&mcast->pkt_queue)) {
 			++dev->stats.tx_dropped;
 			dev_kfree_skb_any(skb_dequeue(&mcast->pkt_queue));
 		}
-		spin_unlock_irq(&priv->tx_lock);
+		netif_tx_unlock_bh(dev);
 
 		/* Clear the busy flag so we try again */
 		status = test_and_clear_bit(IPOIB_MCAST_FLAG_BUSY,
@@ -366,6 +364,21 @@
 	return ret;
 }
 
+void ipoib_mcast_carrier_on_task(struct work_struct *work)
+{
+	struct ipoib_dev_priv *priv = container_of(work, struct ipoib_dev_priv,
+						   carrier_on_task);
+
+	/*
+	 * Take rtnl_lock to avoid racing with ipoib_stop() and
+	 * turning the carrier back on while a device is being
+	 * removed.
+	 */
+	rtnl_lock();
+	netif_carrier_on(priv->dev);
+	rtnl_unlock();
+}
+
 static int ipoib_mcast_join_complete(int status,
 				     struct ib_sa_multicast *multicast)
 {
@@ -392,16 +405,12 @@
 					   &priv->mcast_task, 0);
 		mutex_unlock(&mcast_mutex);
 
-		if (mcast == priv->broadcast) {
-			/*
-			 * Take RTNL lock here to avoid racing with
-			 * ipoib_stop() and turning the carrier back
-			 * on while a device is being removed.
-			 */
-			rtnl_lock();
-			netif_carrier_on(dev);
-			rtnl_unlock();
-		}
+		/*
+		 * Defer carrier on work to ipoib_workqueue to avoid a
+		 * deadlock on rtnl_lock here.
+		 */
+		if (mcast == priv->broadcast)
+			queue_work(ipoib_workqueue, &priv->carrier_on_task);
 
 		return 0;
 	}
@@ -651,12 +660,9 @@
 {
 	struct ipoib_dev_priv *priv = netdev_priv(dev);
 	struct ipoib_mcast *mcast;
+	unsigned long flags;
 
-	/*
-	 * We can only be called from ipoib_start_xmit, so we're
-	 * inside tx_lock -- no need to save/restore flags.
-	 */
-	spin_lock(&priv->lock);
+	spin_lock_irqsave(&priv->lock, flags);
 
 	if (!test_bit(IPOIB_FLAG_OPER_UP, &priv->flags)		||
 	    !priv->broadcast					||
@@ -727,7 +733,7 @@
 	}
 
 unlock:
-	spin_unlock(&priv->lock);
+	spin_unlock_irqrestore(&priv->lock, flags);
 }
 
 void ipoib_mcast_dev_flush(struct net_device *dev)
diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c
index ed7c5f7..5b8b533 100644
--- a/drivers/infiniband/ulp/srp/ib_srp.c
+++ b/drivers/infiniband/ulp/srp/ib_srp.c
@@ -1683,7 +1683,7 @@
 				   SRP_OPT_SERVICE_ID),
 };
 
-static match_table_t srp_opt_tokens = {
+static const match_table_t srp_opt_tokens = {
 	{ SRP_OPT_ID_EXT,		"id_ext=%s" 		},
 	{ SRP_OPT_IOC_GUID,		"ioc_guid=%s" 		},
 	{ SRP_OPT_DGID,			"dgid=%s" 		},
diff --git a/drivers/input/keyboard/corgikbd.c b/drivers/input/keyboard/corgikbd.c
index 134e67b..c8ed065 100644
--- a/drivers/input/keyboard/corgikbd.c
+++ b/drivers/input/keyboard/corgikbd.c
@@ -80,9 +80,9 @@
 #define KB_ACTIVATE_DELAY	10
 
 /* Helper functions for reading the keyboard matrix
- * Note: We should really be using pxa_gpio_mode to alter GPDR but it
- *       requires a function call per GPIO bit which is excessive
- *       when we need to access 12 bits at once multiple times.
+ * Note: We should really be using the generic gpio functions to alter
+ *       GPDR but it requires a function call per GPIO bit which is
+ *       excessive when we need to access 12 bits at once, multiple times.
  * These functions must be called within local_irq_save()/local_irq_restore()
  * or similar.
  */
diff --git a/drivers/input/keyboard/spitzkbd.c b/drivers/input/keyboard/spitzkbd.c
index de67b8e..c48b76a 100644
--- a/drivers/input/keyboard/spitzkbd.c
+++ b/drivers/input/keyboard/spitzkbd.c
@@ -101,9 +101,9 @@
 #define KB_ACTIVATE_DELAY	10
 
 /* Helper functions for reading the keyboard matrix
- * Note: We should really be using pxa_gpio_mode to alter GPDR but it
- *       requires a function call per GPIO bit which is excessive
- *       when we need to access 11 bits at once, multiple times.
+ * Note: We should really be using the generic gpio functions to alter
+ *       GPDR but it requires a function call per GPIO bit which is
+ *       excessive when we need to access 11 bits at once, multiple times.
  * These functions must be called within local_irq_save()/local_irq_restore()
  * or similar.
  */
diff --git a/drivers/input/keyboard/tosakbd.c b/drivers/input/keyboard/tosakbd.c
index 44cb50a..677276b 100644
--- a/drivers/input/keyboard/tosakbd.c
+++ b/drivers/input/keyboard/tosakbd.c
@@ -59,9 +59,9 @@
 
 
 /* Helper functions for reading the keyboard matrix
- * Note: We should really be using pxa_gpio_mode to alter GPDR but it
- *       requires a function call per GPIO bit which is excessive
- *       when we need to access 12 bits at once, multiple times.
+ * Note: We should really be using the generic gpio functions to alter
+ *       GPDR but it requires a function call per GPIO bit which is
+ *       excessive when we need to access 12 bits at once, multiple times.
  * These functions must be called within local_irq_save()/local_irq_restore()
  * or similar.
  */
diff --git a/drivers/input/misc/hp_sdc_rtc.c b/drivers/input/misc/hp_sdc_rtc.c
index daa9d42..82ec6b1 100644
--- a/drivers/input/misc/hp_sdc_rtc.c
+++ b/drivers/input/misc/hp_sdc_rtc.c
@@ -458,35 +458,35 @@
 		p += sprintf(p, "i8042 rtc\t: READ FAILED!\n");
 	} else {
 		p += sprintf(p, "i8042 rtc\t: %ld.%02d seconds\n", 
-			     tv.tv_sec, tv.tv_usec/1000);
+			     tv.tv_sec, (int)tv.tv_usec/1000);
 	}
 
 	if (hp_sdc_rtc_read_fhs(&tv)) {
 		p += sprintf(p, "handshake\t: READ FAILED!\n");
 	} else {
         	p += sprintf(p, "handshake\t: %ld.%02d seconds\n", 
-			     tv.tv_sec, tv.tv_usec/1000);
+			     tv.tv_sec, (int)tv.tv_usec/1000);
 	}
 
 	if (hp_sdc_rtc_read_mt(&tv)) {
 		p += sprintf(p, "alarm\t\t: READ FAILED!\n");
 	} else {
 		p += sprintf(p, "alarm\t\t: %ld.%02d seconds\n", 
-			     tv.tv_sec, tv.tv_usec/1000);
+			     tv.tv_sec, (int)tv.tv_usec/1000);
 	}
 
 	if (hp_sdc_rtc_read_dt(&tv)) {
 		p += sprintf(p, "delay\t\t: READ FAILED!\n");
 	} else {
 		p += sprintf(p, "delay\t\t: %ld.%02d seconds\n", 
-			     tv.tv_sec, tv.tv_usec/1000);
+			     tv.tv_sec, (int)tv.tv_usec/1000);
 	}
 
 	if (hp_sdc_rtc_read_ct(&tv)) {
 		p += sprintf(p, "periodic\t: READ FAILED!\n");
 	} else {
 		p += sprintf(p, "periodic\t: %ld.%02d seconds\n", 
-			     tv.tv_sec, tv.tv_usec/1000);
+			     tv.tv_sec, (int)tv.tv_usec/1000);
 	}
 
         p += sprintf(p,
diff --git a/drivers/input/misc/sparcspkr.c b/drivers/input/misc/sparcspkr.c
index d8765cc..c4f4231 100644
--- a/drivers/input/misc/sparcspkr.c
+++ b/drivers/input/misc/sparcspkr.c
@@ -249,7 +249,7 @@
 	return 0;
 }
 
-static struct of_device_id bbc_beep_match[] = {
+static const struct of_device_id bbc_beep_match[] = {
 	{
 		.name = "beep",
 		.compatible = "SUNW,bbc-beep",
@@ -328,7 +328,7 @@
 	return 0;
 }
 
-static struct of_device_id grover_beep_match[] = {
+static const struct of_device_id grover_beep_match[] = {
 	{
 		.name = "beep",
 		.compatible = "SUNW,smbus-beep",
diff --git a/drivers/input/mouse/bcm5974.c b/drivers/input/mouse/bcm5974.c
index 18f4d7f..2998a6a 100644
--- a/drivers/input/mouse/bcm5974.c
+++ b/drivers/input/mouse/bcm5974.c
@@ -351,8 +351,9 @@
 #define BCM5974_WELLSPRING_MODE_REQUEST_VALUE		0x300
 #define BCM5974_WELLSPRING_MODE_REQUEST_INDEX		0
 #define BCM5974_WELLSPRING_MODE_VENDOR_VALUE		0x01
+#define BCM5974_WELLSPRING_MODE_NORMAL_VALUE		0x08
 
-static int bcm5974_wellspring_mode(struct bcm5974 *dev)
+static int bcm5974_wellspring_mode(struct bcm5974 *dev, bool on)
 {
 	char *data = kmalloc(8, GFP_KERNEL);
 	int retval = 0, size;
@@ -377,7 +378,9 @@
 	}
 
 	/* apply the mode switch */
-	data[0] = BCM5974_WELLSPRING_MODE_VENDOR_VALUE;
+	data[0] = on ?
+		BCM5974_WELLSPRING_MODE_VENDOR_VALUE :
+		BCM5974_WELLSPRING_MODE_NORMAL_VALUE;
 
 	/* write configuration */
 	size = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0),
@@ -392,7 +395,8 @@
 		goto out;
 	}
 
-	dprintk(2, "bcm5974: switched to wellspring mode.\n");
+	dprintk(2, "bcm5974: switched to %s mode.\n",
+		on ? "wellspring" : "normal");
 
  out:
 	kfree(data);
@@ -481,7 +485,7 @@
  */
 static int bcm5974_start_traffic(struct bcm5974 *dev)
 {
-	if (bcm5974_wellspring_mode(dev)) {
+	if (bcm5974_wellspring_mode(dev, true)) {
 		dprintk(1, "bcm5974: mode switch failed\n");
 		goto error;
 	}
@@ -504,6 +508,7 @@
 {
 	usb_kill_urb(dev->tp_urb);
 	usb_kill_urb(dev->bt_urb);
+	bcm5974_wellspring_mode(dev, false);
 }
 
 /*
diff --git a/drivers/input/serio/hp_sdc.c b/drivers/input/serio/hp_sdc.c
index 0d39597..bfe4924 100644
--- a/drivers/input/serio/hp_sdc.c
+++ b/drivers/input/serio/hp_sdc.c
@@ -323,7 +323,7 @@
 			 * it back to the application. and be less verbose.
 			 */
 			printk(KERN_WARNING PREFIX "read timeout (%ius)!\n",
-			       tv.tv_usec - hp_sdc.rtv.tv_usec);
+			       (int)(tv.tv_usec - hp_sdc.rtv.tv_usec));
 			curr->idx += hp_sdc.rqty;
 			hp_sdc.rqty = 0;
 			tmp = curr->seq[curr->actidx];
diff --git a/drivers/input/serio/i8042-sparcio.h b/drivers/input/serio/i8042-sparcio.h
index 692a79e..5071af2 100644
--- a/drivers/input/serio/i8042-sparcio.h
+++ b/drivers/input/serio/i8042-sparcio.h
@@ -87,7 +87,7 @@
 	return 0;
 }
 
-static struct of_device_id sparc_i8042_match[] = {
+static const struct of_device_id sparc_i8042_match[] = {
 	{
 		.name = "8042",
 	},
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index 25287e8..6e1e8c6 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -220,6 +220,7 @@
 config TOUCHSCREEN_UCB1400
 	tristate "Philips UCB1400 touchscreen"
 	select AC97_BUS
+	depends on UCB1400_CORE
 	help
 	  This enables support for the Philips UCB1400 touchscreen interface.
 	  The UCB1400 is an AC97 audio codec.  The touchscreen interface
diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c
index ce6f48c..8583c76 100644
--- a/drivers/input/touchscreen/ads7846.c
+++ b/drivers/input/touchscreen/ads7846.c
@@ -24,6 +24,7 @@
 #include <linux/input.h>
 #include <linux/interrupt.h>
 #include <linux/slab.h>
+#include <linux/gpio.h>
 #include <linux/spi/spi.h>
 #include <linux/spi/ads7846.h>
 #include <asm/irq.h>
@@ -116,6 +117,7 @@
 	void			*filter_data;
 	void			(*filter_cleanup)(void *data);
 	int			(*get_pendown_state)(void);
+	int			gpio_pendown;
 };
 
 /* leave chip selected when we're done, for quicker re-select? */
@@ -491,6 +493,14 @@
 
 /*--------------------------------------------------------------------------*/
 
+static int get_pendown_state(struct ads7846 *ts)
+{
+	if (ts->get_pendown_state)
+		return ts->get_pendown_state();
+
+	return !gpio_get_value(ts->gpio_pendown);
+}
+
 /*
  * PENIRQ only kicks the timer.  The timer only reissues the SPI transfer,
  * to retrieve touchscreen status.
@@ -550,7 +560,7 @@
 	 */
 	if (ts->penirq_recheck_delay_usecs) {
 		udelay(ts->penirq_recheck_delay_usecs);
-		if (!ts->get_pendown_state())
+		if (!get_pendown_state(ts))
 			Rt = 0;
 	}
 
@@ -677,7 +687,7 @@
 
 	spin_lock_irq(&ts->lock);
 
-	if (unlikely(!ts->get_pendown_state() ||
+	if (unlikely(!get_pendown_state(ts) ||
 		     device_suspended(&ts->spi->dev))) {
 		if (ts->pendown) {
 			struct input_dev *input = ts->input;
@@ -716,7 +726,7 @@
 	unsigned long flags;
 
 	spin_lock_irqsave(&ts->lock, flags);
-	if (likely(ts->get_pendown_state())) {
+	if (likely(get_pendown_state(ts))) {
 		if (!ts->irq_disabled) {
 			/* The ARM do_simple_IRQ() dispatcher doesn't act
 			 * like the other dispatchers:  it will report IRQs
@@ -806,6 +816,36 @@
 	return 0;
 }
 
+static int __devinit setup_pendown(struct spi_device *spi, struct ads7846 *ts)
+{
+	struct ads7846_platform_data *pdata = spi->dev.platform_data;
+	int err;
+
+	/* REVISIT when the irq can be triggered active-low, or if for some
+	 * reason the touchscreen isn't hooked up, we don't need to access
+	 * the pendown state.
+	 */
+	if (!pdata->get_pendown_state && !gpio_is_valid(pdata->gpio_pendown)) {
+		dev_err(&spi->dev, "no get_pendown_state nor gpio_pendown?\n");
+		return -EINVAL;
+	}
+
+	if (pdata->get_pendown_state) {
+		ts->get_pendown_state = pdata->get_pendown_state;
+		return 0;
+	}
+
+	err = gpio_request(pdata->gpio_pendown, "ads7846_pendown");
+	if (err) {
+		dev_err(&spi->dev, "failed to request pendown GPIO%d\n",
+				pdata->gpio_pendown);
+		return err;
+	}
+
+	ts->gpio_pendown = pdata->gpio_pendown;
+	return 0;
+}
+
 static int __devinit ads7846_probe(struct spi_device *spi)
 {
 	struct ads7846			*ts;
@@ -833,15 +873,6 @@
 		return -EINVAL;
 	}
 
-	/* REVISIT when the irq can be triggered active-low, or if for some
-	 * reason the touchscreen isn't hooked up, we don't need to access
-	 * the pendown state.
-	 */
-	if (pdata->get_pendown_state == NULL) {
-		dev_dbg(&spi->dev, "no get_pendown_state function?\n");
-		return -EINVAL;
-	}
-
 	/* We'd set TX wordsize 8 bits and RX wordsize to 13 bits ... except
 	 * that even if the hardware can do that, the SPI controller driver
 	 * may not.  So we stick to very-portable 8 bit words, both RX and TX.
@@ -893,7 +924,10 @@
 		ts->filter_data = ts;
 	} else
 		ts->filter = ads7846_no_filter;
-	ts->get_pendown_state = pdata->get_pendown_state;
+
+	err = setup_pendown(spi, ts);
+	if (err)
+		goto err_cleanup_filter;
 
 	if (pdata->penirq_recheck_delay_usecs)
 		ts->penirq_recheck_delay_usecs =
@@ -1085,7 +1119,7 @@
 			spi->dev.driver->name, ts)) {
 		dev_dbg(&spi->dev, "irq %d busy?\n", spi->irq);
 		err = -EBUSY;
-		goto err_cleanup_filter;
+		goto err_free_gpio;
 	}
 
 	err = ads784x_hwmon_register(spi, ts);
@@ -1116,6 +1150,9 @@
 	ads784x_hwmon_unregister(spi, ts);
  err_free_irq:
 	free_irq(spi->irq, ts);
+ err_free_gpio:
+	if (ts->gpio_pendown != -1)
+		gpio_free(ts->gpio_pendown);
  err_cleanup_filter:
 	if (ts->filter_cleanup)
 		ts->filter_cleanup(ts->filter_data);
@@ -1140,6 +1177,9 @@
 	/* suspend left the IRQ disabled */
 	enable_irq(ts->spi->irq);
 
+	if (ts->gpio_pendown != -1)
+		gpio_free(ts->gpio_pendown);
+
 	if (ts->filter_cleanup)
 		ts->filter_cleanup(ts->filter_data);
 
diff --git a/drivers/input/touchscreen/jornada720_ts.c b/drivers/input/touchscreen/jornada720_ts.c
index bf44f9d..c8b7e8a 100644
--- a/drivers/input/touchscreen/jornada720_ts.c
+++ b/drivers/input/touchscreen/jornada720_ts.c
@@ -119,8 +119,8 @@
 	input_dev->id.bustype = BUS_HOST;
 	input_dev->dev.parent = &pdev->dev;
 
-	input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
-	input_dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH);
+	input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
+	input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
 	input_set_abs_params(input_dev, ABS_X, 270, 3900, 0, 0);
 	input_set_abs_params(input_dev, ABS_Y, 180, 3700, 0, 0);
 
diff --git a/drivers/input/touchscreen/ucb1400_ts.c b/drivers/input/touchscreen/ucb1400_ts.c
index bce018e..5498662 100644
--- a/drivers/input/touchscreen/ucb1400_ts.c
+++ b/drivers/input/touchscreen/ucb1400_ts.c
@@ -5,6 +5,10 @@
  *  Created:	September 25, 2006
  *  Copyright:	MontaVista Software, Inc.
  *
+ * Spliting done by: Marek Vasut <marek.vasut@gmail.com>
+ * If something doesnt work and it worked before spliting, e-mail me,
+ * dont bother Nicolas please ;-)
+ *
  * 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.
@@ -25,124 +29,16 @@
 #include <linux/slab.h>
 #include <linux/kthread.h>
 #include <linux/freezer.h>
-
-#include <sound/core.h>
-#include <sound/ac97_codec.h>
-
-
-/*
- * Interesting UCB1400 AC-link registers
- */
-
-#define UCB_IE_RIS		0x5e
-#define UCB_IE_FAL		0x60
-#define UCB_IE_STATUS		0x62
-#define UCB_IE_CLEAR		0x62
-#define UCB_IE_ADC		(1 << 11)
-#define UCB_IE_TSPX		(1 << 12)
-
-#define UCB_TS_CR		0x64
-#define UCB_TS_CR_TSMX_POW	(1 << 0)
-#define UCB_TS_CR_TSPX_POW	(1 << 1)
-#define UCB_TS_CR_TSMY_POW	(1 << 2)
-#define UCB_TS_CR_TSPY_POW	(1 << 3)
-#define UCB_TS_CR_TSMX_GND	(1 << 4)
-#define UCB_TS_CR_TSPX_GND	(1 << 5)
-#define UCB_TS_CR_TSMY_GND	(1 << 6)
-#define UCB_TS_CR_TSPY_GND	(1 << 7)
-#define UCB_TS_CR_MODE_INT	(0 << 8)
-#define UCB_TS_CR_MODE_PRES	(1 << 8)
-#define UCB_TS_CR_MODE_POS	(2 << 8)
-#define UCB_TS_CR_BIAS_ENA	(1 << 11)
-#define UCB_TS_CR_TSPX_LOW	(1 << 12)
-#define UCB_TS_CR_TSMX_LOW	(1 << 13)
-
-#define UCB_ADC_CR		0x66
-#define UCB_ADC_SYNC_ENA	(1 << 0)
-#define UCB_ADC_VREFBYP_CON	(1 << 1)
-#define UCB_ADC_INP_TSPX	(0 << 2)
-#define UCB_ADC_INP_TSMX	(1 << 2)
-#define UCB_ADC_INP_TSPY	(2 << 2)
-#define UCB_ADC_INP_TSMY	(3 << 2)
-#define UCB_ADC_INP_AD0		(4 << 2)
-#define UCB_ADC_INP_AD1		(5 << 2)
-#define UCB_ADC_INP_AD2		(6 << 2)
-#define UCB_ADC_INP_AD3		(7 << 2)
-#define UCB_ADC_EXT_REF		(1 << 5)
-#define UCB_ADC_START		(1 << 7)
-#define UCB_ADC_ENA		(1 << 15)
-
-#define UCB_ADC_DATA		0x68
-#define UCB_ADC_DAT_VALID	(1 << 15)
-#define UCB_ADC_DAT_VALUE(x)	((x) & 0x3ff)
-
-#define UCB_ID			0x7e
-#define UCB_ID_1400             0x4304
-
-
-struct ucb1400 {
-	struct snd_ac97		*ac97;
-	struct input_dev	*ts_idev;
-
-	int			irq;
-
-	wait_queue_head_t	ts_wait;
-	struct task_struct	*ts_task;
-
-	unsigned int		irq_pending;	/* not bit field shared */
-	unsigned int		ts_restart:1;
-	unsigned int		adcsync:1;
-};
+#include <linux/ucb1400.h>
 
 static int adcsync;
 static int ts_delay = 55; /* us */
 static int ts_delay_pressure;	/* us */
 
-static inline u16 ucb1400_reg_read(struct ucb1400 *ucb, u16 reg)
-{
-	return ucb->ac97->bus->ops->read(ucb->ac97, reg);
-}
-
-static inline void ucb1400_reg_write(struct ucb1400 *ucb, u16 reg, u16 val)
-{
-	ucb->ac97->bus->ops->write(ucb->ac97, reg, val);
-}
-
-static inline void ucb1400_adc_enable(struct ucb1400 *ucb)
-{
-	ucb1400_reg_write(ucb, UCB_ADC_CR, UCB_ADC_ENA);
-}
-
-static unsigned int ucb1400_adc_read(struct ucb1400 *ucb, u16 adc_channel)
-{
-	unsigned int val;
-
-	if (ucb->adcsync)
-		adc_channel |= UCB_ADC_SYNC_ENA;
-
-	ucb1400_reg_write(ucb, UCB_ADC_CR, UCB_ADC_ENA | adc_channel);
-	ucb1400_reg_write(ucb, UCB_ADC_CR, UCB_ADC_ENA | adc_channel | UCB_ADC_START);
-
-	for (;;) {
-		val = ucb1400_reg_read(ucb, UCB_ADC_DATA);
-		if (val & UCB_ADC_DAT_VALID)
-			break;
-		/* yield to other processes */
-		schedule_timeout_uninterruptible(1);
-	}
-
-	return UCB_ADC_DAT_VALUE(val);
-}
-
-static inline void ucb1400_adc_disable(struct ucb1400 *ucb)
-{
-	ucb1400_reg_write(ucb, UCB_ADC_CR, 0);
-}
-
 /* Switch to interrupt mode. */
-static inline void ucb1400_ts_mode_int(struct ucb1400 *ucb)
+static inline void ucb1400_ts_mode_int(struct snd_ac97 *ac97)
 {
-	ucb1400_reg_write(ucb, UCB_TS_CR,
+	ucb1400_reg_write(ac97, UCB_TS_CR,
 			UCB_TS_CR_TSMX_POW | UCB_TS_CR_TSPX_POW |
 			UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_GND |
 			UCB_TS_CR_MODE_INT);
@@ -152,14 +48,14 @@
  * Switch to pressure mode, and read pressure.  We don't need to wait
  * here, since both plates are being driven.
  */
-static inline unsigned int ucb1400_ts_read_pressure(struct ucb1400 *ucb)
+static inline unsigned int ucb1400_ts_read_pressure(struct ucb1400_ts *ucb)
 {
-	ucb1400_reg_write(ucb, UCB_TS_CR,
+	ucb1400_reg_write(ucb->ac97, UCB_TS_CR,
 			UCB_TS_CR_TSMX_POW | UCB_TS_CR_TSPX_POW |
 			UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_GND |
 			UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA);
 	udelay(ts_delay_pressure);
-	return ucb1400_adc_read(ucb, UCB_ADC_INP_TSPY);
+	return ucb1400_adc_read(ucb->ac97, UCB_ADC_INP_TSPY, adcsync);
 }
 
 /*
@@ -168,21 +64,21 @@
  * gives a faster response time.  Even so, we need to wait about 55us
  * for things to stabilise.
  */
-static inline unsigned int ucb1400_ts_read_xpos(struct ucb1400 *ucb)
+static inline unsigned int ucb1400_ts_read_xpos(struct ucb1400_ts *ucb)
 {
-	ucb1400_reg_write(ucb, UCB_TS_CR,
+	ucb1400_reg_write(ucb->ac97, UCB_TS_CR,
 			UCB_TS_CR_TSMX_GND | UCB_TS_CR_TSPX_POW |
 			UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA);
-	ucb1400_reg_write(ucb, UCB_TS_CR,
+	ucb1400_reg_write(ucb->ac97, UCB_TS_CR,
 			UCB_TS_CR_TSMX_GND | UCB_TS_CR_TSPX_POW |
 			UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA);
-	ucb1400_reg_write(ucb, UCB_TS_CR,
+	ucb1400_reg_write(ucb->ac97, UCB_TS_CR,
 			UCB_TS_CR_TSMX_GND | UCB_TS_CR_TSPX_POW |
 			UCB_TS_CR_MODE_POS | UCB_TS_CR_BIAS_ENA);
 
 	udelay(ts_delay);
 
-	return ucb1400_adc_read(ucb, UCB_ADC_INP_TSPY);
+	return ucb1400_adc_read(ucb->ac97, UCB_ADC_INP_TSPY, adcsync);
 }
 
 /*
@@ -191,63 +87,63 @@
  * gives a faster response time.  Even so, we need to wait about 55us
  * for things to stabilise.
  */
-static inline unsigned int ucb1400_ts_read_ypos(struct ucb1400 *ucb)
+static inline unsigned int ucb1400_ts_read_ypos(struct ucb1400_ts *ucb)
 {
-	ucb1400_reg_write(ucb, UCB_TS_CR,
+	ucb1400_reg_write(ucb->ac97, UCB_TS_CR,
 			UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_POW |
 			UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA);
-	ucb1400_reg_write(ucb, UCB_TS_CR,
+	ucb1400_reg_write(ucb->ac97, UCB_TS_CR,
 			UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_POW |
 			UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA);
-	ucb1400_reg_write(ucb, UCB_TS_CR,
+	ucb1400_reg_write(ucb->ac97, UCB_TS_CR,
 			UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_POW |
 			UCB_TS_CR_MODE_POS | UCB_TS_CR_BIAS_ENA);
 
 	udelay(ts_delay);
 
-	return ucb1400_adc_read(ucb, UCB_ADC_INP_TSPX);
+	return ucb1400_adc_read(ucb->ac97, UCB_ADC_INP_TSPX, adcsync);
 }
 
 /*
  * Switch to X plate resistance mode.  Set MX to ground, PX to
  * supply.  Measure current.
  */
-static inline unsigned int ucb1400_ts_read_xres(struct ucb1400 *ucb)
+static inline unsigned int ucb1400_ts_read_xres(struct ucb1400_ts *ucb)
 {
-	ucb1400_reg_write(ucb, UCB_TS_CR,
+	ucb1400_reg_write(ucb->ac97, UCB_TS_CR,
 			UCB_TS_CR_TSMX_GND | UCB_TS_CR_TSPX_POW |
 			UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA);
-	return ucb1400_adc_read(ucb, 0);
+	return ucb1400_adc_read(ucb->ac97, 0, adcsync);
 }
 
 /*
  * Switch to Y plate resistance mode.  Set MY to ground, PY to
  * supply.  Measure current.
  */
-static inline unsigned int ucb1400_ts_read_yres(struct ucb1400 *ucb)
+static inline unsigned int ucb1400_ts_read_yres(struct ucb1400_ts *ucb)
 {
-	ucb1400_reg_write(ucb, UCB_TS_CR,
+	ucb1400_reg_write(ucb->ac97, UCB_TS_CR,
 			UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_POW |
 			UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA);
-	return ucb1400_adc_read(ucb, 0);
+	return ucb1400_adc_read(ucb->ac97, 0, adcsync);
 }
 
-static inline int ucb1400_ts_pen_down(struct ucb1400 *ucb)
+static inline int ucb1400_ts_pen_down(struct snd_ac97 *ac97)
 {
-	unsigned short val = ucb1400_reg_read(ucb, UCB_TS_CR);
-	return (val & (UCB_TS_CR_TSPX_LOW | UCB_TS_CR_TSMX_LOW));
+	unsigned short val = ucb1400_reg_read(ac97, UCB_TS_CR);
+	return val & (UCB_TS_CR_TSPX_LOW | UCB_TS_CR_TSMX_LOW);
 }
 
-static inline void ucb1400_ts_irq_enable(struct ucb1400 *ucb)
+static inline void ucb1400_ts_irq_enable(struct snd_ac97 *ac97)
 {
-	ucb1400_reg_write(ucb, UCB_IE_CLEAR, UCB_IE_TSPX);
-	ucb1400_reg_write(ucb, UCB_IE_CLEAR, 0);
-	ucb1400_reg_write(ucb, UCB_IE_FAL, UCB_IE_TSPX);
+	ucb1400_reg_write(ac97, UCB_IE_CLEAR, UCB_IE_TSPX);
+	ucb1400_reg_write(ac97, UCB_IE_CLEAR, 0);
+	ucb1400_reg_write(ac97, UCB_IE_FAL, UCB_IE_TSPX);
 }
 
-static inline void ucb1400_ts_irq_disable(struct ucb1400 *ucb)
+static inline void ucb1400_ts_irq_disable(struct snd_ac97 *ac97)
 {
-	ucb1400_reg_write(ucb, UCB_IE_FAL, 0);
+	ucb1400_reg_write(ac97, UCB_IE_FAL, 0);
 }
 
 static void ucb1400_ts_evt_add(struct input_dev *idev, u16 pressure, u16 x, u16 y)
@@ -264,25 +160,24 @@
 	input_sync(idev);
 }
 
-static void ucb1400_handle_pending_irq(struct ucb1400 *ucb)
+static void ucb1400_handle_pending_irq(struct ucb1400_ts *ucb)
 {
 	unsigned int isr;
 
-	isr = ucb1400_reg_read(ucb, UCB_IE_STATUS);
-	ucb1400_reg_write(ucb, UCB_IE_CLEAR, isr);
-	ucb1400_reg_write(ucb, UCB_IE_CLEAR, 0);
+	isr = ucb1400_reg_read(ucb->ac97, UCB_IE_STATUS);
+	ucb1400_reg_write(ucb->ac97, UCB_IE_CLEAR, isr);
+	ucb1400_reg_write(ucb->ac97, UCB_IE_CLEAR, 0);
 
-	if (isr & UCB_IE_TSPX)
-		ucb1400_ts_irq_disable(ucb);
-	else
+	if (isr & UCB_IE_TSPX) {
+		ucb1400_ts_irq_disable(ucb->ac97);
+		enable_irq(ucb->irq);
+	} else
 		printk(KERN_ERR "ucb1400: unexpected IE_STATUS = %#x\n", isr);
-
-	enable_irq(ucb->irq);
 }
 
 static int ucb1400_ts_thread(void *_ucb)
 {
-	struct ucb1400 *ucb = _ucb;
+	struct ucb1400_ts *ucb = _ucb;
 	struct task_struct *tsk = current;
 	int valid = 0;
 	struct sched_param param = { .sched_priority = 1 };
@@ -301,19 +196,19 @@
 			ucb1400_handle_pending_irq(ucb);
 		}
 
-		ucb1400_adc_enable(ucb);
+		ucb1400_adc_enable(ucb->ac97);
 		x = ucb1400_ts_read_xpos(ucb);
 		y = ucb1400_ts_read_ypos(ucb);
 		p = ucb1400_ts_read_pressure(ucb);
-		ucb1400_adc_disable(ucb);
+		ucb1400_adc_disable(ucb->ac97);
 
 		/* Switch back to interrupt mode. */
-		ucb1400_ts_mode_int(ucb);
+		ucb1400_ts_mode_int(ucb->ac97);
 
 		msleep(10);
 
-		if (ucb1400_ts_pen_down(ucb)) {
-			ucb1400_ts_irq_enable(ucb);
+		if (ucb1400_ts_pen_down(ucb->ac97)) {
+			ucb1400_ts_irq_enable(ucb->ac97);
 
 			/*
 			 * If we spat out a valid sample set last time,
@@ -332,8 +227,8 @@
 		}
 
 		wait_event_freezable_timeout(ucb->ts_wait,
-			ucb->irq_pending || ucb->ts_restart || kthread_should_stop(),
-			timeout);
+			ucb->irq_pending || ucb->ts_restart ||
+			kthread_should_stop(), timeout);
 	}
 
 	/* Send the "pen off" if we are stopping with the pen still active */
@@ -356,7 +251,7 @@
  */
 static irqreturn_t ucb1400_hard_irq(int irqnr, void *devid)
 {
-	struct ucb1400 *ucb = devid;
+	struct ucb1400_ts *ucb = devid;
 
 	if (irqnr == ucb->irq) {
 		disable_irq(ucb->irq);
@@ -369,7 +264,7 @@
 
 static int ucb1400_ts_open(struct input_dev *idev)
 {
-	struct ucb1400 *ucb = input_get_drvdata(idev);
+	struct ucb1400_ts *ucb = input_get_drvdata(idev);
 	int ret = 0;
 
 	BUG_ON(ucb->ts_task);
@@ -385,19 +280,143 @@
 
 static void ucb1400_ts_close(struct input_dev *idev)
 {
-	struct ucb1400 *ucb = input_get_drvdata(idev);
+	struct ucb1400_ts *ucb = input_get_drvdata(idev);
 
 	if (ucb->ts_task)
 		kthread_stop(ucb->ts_task);
 
-	ucb1400_ts_irq_disable(ucb);
-	ucb1400_reg_write(ucb, UCB_TS_CR, 0);
+	ucb1400_ts_irq_disable(ucb->ac97);
+	ucb1400_reg_write(ucb->ac97, UCB_TS_CR, 0);
+}
+
+#ifndef NO_IRQ
+#define NO_IRQ	0
+#endif
+
+/*
+ * Try to probe our interrupt, rather than relying on lots of
+ * hard-coded machine dependencies.
+ */
+static int ucb1400_ts_detect_irq(struct ucb1400_ts *ucb)
+{
+	unsigned long mask, timeout;
+
+	mask = probe_irq_on();
+
+	/* Enable the ADC interrupt. */
+	ucb1400_reg_write(ucb->ac97, UCB_IE_RIS, UCB_IE_ADC);
+	ucb1400_reg_write(ucb->ac97, UCB_IE_FAL, UCB_IE_ADC);
+	ucb1400_reg_write(ucb->ac97, UCB_IE_CLEAR, 0xffff);
+	ucb1400_reg_write(ucb->ac97, UCB_IE_CLEAR, 0);
+
+	/* Cause an ADC interrupt. */
+	ucb1400_reg_write(ucb->ac97, UCB_ADC_CR, UCB_ADC_ENA);
+	ucb1400_reg_write(ucb->ac97, UCB_ADC_CR, UCB_ADC_ENA | UCB_ADC_START);
+
+	/* Wait for the conversion to complete. */
+	timeout = jiffies + HZ/2;
+	while (!(ucb1400_reg_read(ucb->ac97, UCB_ADC_DATA) &
+						UCB_ADC_DAT_VALID)) {
+		cpu_relax();
+		if (time_after(jiffies, timeout)) {
+			printk(KERN_ERR "ucb1400: timed out in IRQ probe\n");
+			probe_irq_off(mask);
+			return -ENODEV;
+		}
+	}
+	ucb1400_reg_write(ucb->ac97, UCB_ADC_CR, 0);
+
+	/* Disable and clear interrupt. */
+	ucb1400_reg_write(ucb->ac97, UCB_IE_RIS, 0);
+	ucb1400_reg_write(ucb->ac97, UCB_IE_FAL, 0);
+	ucb1400_reg_write(ucb->ac97, UCB_IE_CLEAR, 0xffff);
+	ucb1400_reg_write(ucb->ac97, UCB_IE_CLEAR, 0);
+
+	/* Read triggered interrupt. */
+	ucb->irq = probe_irq_off(mask);
+	if (ucb->irq < 0 || ucb->irq == NO_IRQ)
+		return -ENODEV;
+
+	return 0;
+}
+
+static int ucb1400_ts_probe(struct platform_device *dev)
+{
+	int error, x_res, y_res;
+	struct ucb1400_ts *ucb = dev->dev.platform_data;
+
+	ucb->ts_idev = input_allocate_device();
+	if (!ucb->ts_idev) {
+		error = -ENOMEM;
+		goto err;
+	}
+
+	error = ucb1400_ts_detect_irq(ucb);
+	if (error) {
+		printk(KERN_ERR "UCB1400: IRQ probe failed\n");
+		goto err_free_devs;
+	}
+
+	init_waitqueue_head(&ucb->ts_wait);
+
+	error = request_irq(ucb->irq, ucb1400_hard_irq, IRQF_TRIGGER_RISING,
+				"UCB1400", ucb);
+	if (error) {
+		printk(KERN_ERR "ucb1400: unable to grab irq%d: %d\n",
+				ucb->irq, error);
+		goto err_free_devs;
+	}
+	printk(KERN_DEBUG "UCB1400: found IRQ %d\n", ucb->irq);
+
+	input_set_drvdata(ucb->ts_idev, ucb);
+
+	ucb->ts_idev->dev.parent	= &dev->dev;
+	ucb->ts_idev->name		= "UCB1400 touchscreen interface";
+	ucb->ts_idev->id.vendor		= ucb1400_reg_read(ucb->ac97,
+						AC97_VENDOR_ID1);
+	ucb->ts_idev->id.product	= ucb->id;
+	ucb->ts_idev->open		= ucb1400_ts_open;
+	ucb->ts_idev->close		= ucb1400_ts_close;
+	ucb->ts_idev->evbit[0]		= BIT_MASK(EV_ABS);
+
+	ucb1400_adc_enable(ucb->ac97);
+	x_res = ucb1400_ts_read_xres(ucb);
+	y_res = ucb1400_ts_read_yres(ucb);
+	ucb1400_adc_disable(ucb->ac97);
+	printk(KERN_DEBUG "UCB1400: x/y = %d/%d\n", x_res, y_res);
+
+	input_set_abs_params(ucb->ts_idev, ABS_X, 0, x_res, 0, 0);
+	input_set_abs_params(ucb->ts_idev, ABS_Y, 0, y_res, 0, 0);
+	input_set_abs_params(ucb->ts_idev, ABS_PRESSURE, 0, 0, 0, 0);
+
+	error = input_register_device(ucb->ts_idev);
+	if (error)
+		goto err_free_irq;
+
+	return 0;
+
+err_free_irq:
+	free_irq(ucb->irq, ucb);
+err_free_devs:
+	input_free_device(ucb->ts_idev);
+err:
+	return error;
+
+}
+
+static int ucb1400_ts_remove(struct platform_device *dev)
+{
+	struct ucb1400_ts *ucb = dev->dev.platform_data;
+
+	free_irq(ucb->irq, ucb);
+	input_unregister_device(ucb->ts_idev);
+	return 0;
 }
 
 #ifdef CONFIG_PM
-static int ucb1400_ts_resume(struct device *dev)
+static int ucb1400_ts_resume(struct platform_device *dev)
 {
-	struct ucb1400 *ucb = dev_get_drvdata(dev);
+	struct ucb1400_ts *ucb = platform_get_drvdata(dev);
 
 	if (ucb->ts_task) {
 		/*
@@ -414,169 +433,36 @@
 #define ucb1400_ts_resume NULL
 #endif
 
-#ifndef NO_IRQ
-#define NO_IRQ	0
-#endif
-
-/*
- * Try to probe our interrupt, rather than relying on lots of
- * hard-coded machine dependencies.
- */
-static int ucb1400_detect_irq(struct ucb1400 *ucb)
-{
-	unsigned long mask, timeout;
-
-	mask = probe_irq_on();
-
-	/* Enable the ADC interrupt. */
-	ucb1400_reg_write(ucb, UCB_IE_RIS, UCB_IE_ADC);
-	ucb1400_reg_write(ucb, UCB_IE_FAL, UCB_IE_ADC);
-	ucb1400_reg_write(ucb, UCB_IE_CLEAR, 0xffff);
-	ucb1400_reg_write(ucb, UCB_IE_CLEAR, 0);
-
-	/* Cause an ADC interrupt. */
-	ucb1400_reg_write(ucb, UCB_ADC_CR, UCB_ADC_ENA);
-	ucb1400_reg_write(ucb, UCB_ADC_CR, UCB_ADC_ENA | UCB_ADC_START);
-
-	/* Wait for the conversion to complete. */
-	timeout = jiffies + HZ/2;
-	while (!(ucb1400_reg_read(ucb, UCB_ADC_DATA) & UCB_ADC_DAT_VALID)) {
-		cpu_relax();
-		if (time_after(jiffies, timeout)) {
-			printk(KERN_ERR "ucb1400: timed out in IRQ probe\n");
-			probe_irq_off(mask);
-			return -ENODEV;
-		}
-	}
-	ucb1400_reg_write(ucb, UCB_ADC_CR, 0);
-
-	/* Disable and clear interrupt. */
-	ucb1400_reg_write(ucb, UCB_IE_RIS, 0);
-	ucb1400_reg_write(ucb, UCB_IE_FAL, 0);
-	ucb1400_reg_write(ucb, UCB_IE_CLEAR, 0xffff);
-	ucb1400_reg_write(ucb, UCB_IE_CLEAR, 0);
-
-	/* Read triggered interrupt. */
-	ucb->irq = probe_irq_off(mask);
-	if (ucb->irq < 0 || ucb->irq == NO_IRQ)
-		return -ENODEV;
-
-	return 0;
-}
-
-static int ucb1400_ts_probe(struct device *dev)
-{
-	struct ucb1400 *ucb;
-	struct input_dev *idev;
-	int error, id, x_res, y_res;
-
-	ucb = kzalloc(sizeof(struct ucb1400), GFP_KERNEL);
-	idev = input_allocate_device();
-	if (!ucb || !idev) {
-		error = -ENOMEM;
-		goto err_free_devs;
-	}
-
-	ucb->ts_idev = idev;
-	ucb->adcsync = adcsync;
-	ucb->ac97 = to_ac97_t(dev);
-	init_waitqueue_head(&ucb->ts_wait);
-
-	id = ucb1400_reg_read(ucb, UCB_ID);
-	if (id != UCB_ID_1400) {
-		error = -ENODEV;
-		goto err_free_devs;
-	}
-
-	error = ucb1400_detect_irq(ucb);
-	if (error) {
-		printk(KERN_ERR "UCB1400: IRQ probe failed\n");
-		goto err_free_devs;
-	}
-
-	error = request_irq(ucb->irq, ucb1400_hard_irq, IRQF_TRIGGER_RISING,
-				"UCB1400", ucb);
-	if (error) {
-		printk(KERN_ERR "ucb1400: unable to grab irq%d: %d\n",
-				ucb->irq, error);
-		goto err_free_devs;
-	}
-	printk(KERN_DEBUG "UCB1400: found IRQ %d\n", ucb->irq);
-
-	input_set_drvdata(idev, ucb);
-
-	idev->dev.parent	= dev;
-	idev->name		= "UCB1400 touchscreen interface";
-	idev->id.vendor		= ucb1400_reg_read(ucb, AC97_VENDOR_ID1);
-	idev->id.product	= id;
-	idev->open		= ucb1400_ts_open;
-	idev->close		= ucb1400_ts_close;
-	idev->evbit[0]		= BIT_MASK(EV_ABS);
-
-	ucb1400_adc_enable(ucb);
-	x_res = ucb1400_ts_read_xres(ucb);
-	y_res = ucb1400_ts_read_yres(ucb);
-	ucb1400_adc_disable(ucb);
-	printk(KERN_DEBUG "UCB1400: x/y = %d/%d\n", x_res, y_res);
-
-	input_set_abs_params(idev, ABS_X, 0, x_res, 0, 0);
-	input_set_abs_params(idev, ABS_Y, 0, y_res, 0, 0);
-	input_set_abs_params(idev, ABS_PRESSURE, 0, 0, 0, 0);
-
-	error = input_register_device(idev);
-	if (error)
-		goto err_free_irq;
-
-	dev_set_drvdata(dev, ucb);
-	return 0;
-
- err_free_irq:
-	free_irq(ucb->irq, ucb);
- err_free_devs:
-	input_free_device(idev);
-	kfree(ucb);
-	return error;
-}
-
-static int ucb1400_ts_remove(struct device *dev)
-{
-	struct ucb1400 *ucb = dev_get_drvdata(dev);
-
-	free_irq(ucb->irq, ucb);
-	input_unregister_device(ucb->ts_idev);
-	dev_set_drvdata(dev, NULL);
-	kfree(ucb);
-	return 0;
-}
-
-static struct device_driver ucb1400_ts_driver = {
-	.name		= "ucb1400_ts",
-	.owner		= THIS_MODULE,
-	.bus		= &ac97_bus_type,
-	.probe		= ucb1400_ts_probe,
-	.remove		= ucb1400_ts_remove,
-	.resume		= ucb1400_ts_resume,
+static struct platform_driver ucb1400_ts_driver = {
+	.probe	= ucb1400_ts_probe,
+	.remove	= ucb1400_ts_remove,
+	.resume	= ucb1400_ts_resume,
+	.driver	= {
+		.name	= "ucb1400_ts",
+	},
 };
 
 static int __init ucb1400_ts_init(void)
 {
-	return driver_register(&ucb1400_ts_driver);
+	return platform_driver_register(&ucb1400_ts_driver);
 }
 
 static void __exit ucb1400_ts_exit(void)
 {
-	driver_unregister(&ucb1400_ts_driver);
+	platform_driver_unregister(&ucb1400_ts_driver);
 }
 
 module_param(adcsync, bool, 0444);
 MODULE_PARM_DESC(adcsync, "Synchronize touch readings with ADCSYNC pin.");
 
 module_param(ts_delay, int, 0444);
-MODULE_PARM_DESC(ts_delay, "Delay between panel setup and position read. Default = 55us.");
+MODULE_PARM_DESC(ts_delay, "Delay between panel setup and"
+			    " position read. Default = 55us.");
 
 module_param(ts_delay_pressure, int, 0444);
 MODULE_PARM_DESC(ts_delay_pressure,
-		  "delay between panel setup and pressure read.  Default = 0us.");
+		"delay between panel setup and pressure read."
+		"  Default = 0us.");
 
 module_init(ucb1400_ts_init);
 module_exit(ucb1400_ts_exit);
diff --git a/drivers/input/xen-kbdfront.c b/drivers/input/xen-kbdfront.c
index 9ce3b3b..3ab6362 100644
--- a/drivers/input/xen-kbdfront.c
+++ b/drivers/input/xen-kbdfront.c
@@ -335,11 +335,11 @@
 
 static int __init xenkbd_init(void)
 {
-	if (!is_running_on_xen())
+	if (!xen_domain())
 		return -ENODEV;
 
 	/* Nothing to do if running in dom0. */
-	if (is_initial_xendomain())
+	if (xen_initial_domain())
 		return -ENODEV;
 
 	return xenbus_register_frontend(&xenkbd);
diff --git a/drivers/isdn/capi/capi.c b/drivers/isdn/capi/capi.c
index 871b0cbc..798d7f3 100644
--- a/drivers/isdn/capi/capi.c
+++ b/drivers/isdn/capi/capi.c
@@ -1231,7 +1231,7 @@
 	int error = 0;
 	switch (cmd) {
 	default:
-		error = n_tty_ioctl (tty, file, cmd, arg);
+		error = n_tty_ioctl_helper(tty, file, cmd, arg);
 		break;
 	}
 	return error;
diff --git a/drivers/isdn/capi/kcapi.c b/drivers/isdn/capi/kcapi.c
index 75726ea..5360c4f 100644
--- a/drivers/isdn/capi/kcapi.c
+++ b/drivers/isdn/capi/kcapi.c
@@ -828,15 +828,18 @@
 			return -ESRCH;
 		if (card->load_firmware == NULL) {
 			printk(KERN_DEBUG "kcapi: load: no load function\n");
+			capi_ctr_put(card);
 			return -ESRCH;
 		}
 
 		if (ldef.t4file.len <= 0) {
 			printk(KERN_DEBUG "kcapi: load: invalid parameter: length of t4file is %d ?\n", ldef.t4file.len);
+			capi_ctr_put(card);
 			return -EINVAL;
 		}
 		if (ldef.t4file.data == NULL) {
 			printk(KERN_DEBUG "kcapi: load: invalid parameter: dataptr is 0\n");
+			capi_ctr_put(card);
 			return -EINVAL;
 		}
 
@@ -849,6 +852,7 @@
 
 		if (card->cardstate != CARD_DETECTED) {
 			printk(KERN_INFO "kcapi: load: contr=%d not in detect state\n", ldef.contr);
+			capi_ctr_put(card);
 			return -EBUSY;
 		}
 		card->cardstate = CARD_LOADING;
diff --git a/drivers/isdn/gigaset/ser-gigaset.c b/drivers/isdn/gigaset/ser-gigaset.c
index 5e89fa1..07052ed 100644
--- a/drivers/isdn/gigaset/ser-gigaset.c
+++ b/drivers/isdn/gigaset/ser-gigaset.c
@@ -571,6 +571,7 @@
 	}
 
 	/* prevent other callers from entering ldisc methods */
+	/* FIXME: should use the tty state flags */
 	tty->disc_data = NULL;
 
 	if (!cs->hw.ser)
@@ -642,10 +643,11 @@
 		return -ENXIO;
 
 	switch (cmd) {
-	case TCGETS:
-	case TCGETA:
-		/* pass through to underlying serial device */
-		rc = n_tty_ioctl(tty, file, cmd, arg);
+
+	case FIONREAD:
+		/* unused, always return zero */
+		val = 0;
+		rc = put_user(val, p);
 		break;
 
 	case TCFLSH:
@@ -659,20 +661,13 @@
 			flush_send_queue(cs);
 			break;
 		}
-		/* flush the serial port's buffer */
-		rc = n_tty_ioctl(tty, file, cmd, arg);
-		break;
-
-	case FIONREAD:
-		/* unused, always return zero */
-		val = 0;
-		rc = put_user(val, p);
-		break;
+		/* Pass through */
 
 	default:
-		rc = -ENOIOCTLCMD;
+		/* pass through to underlying serial device */
+		rc = n_tty_ioctl_helper(tty, file, cmd, arg);
+		break;
 	}
-
 	cs_put(cs);
 	return rc;
 }
@@ -680,6 +675,8 @@
 /*
  * Poll on the tty.
  * Unused, always return zero.
+ *
+ * FIXME: should probably return an exception - especially on hangup
  */
 static unsigned int
 gigaset_tty_poll(struct tty_struct *tty, struct file *file, poll_table *wait)
diff --git a/drivers/isdn/hardware/avm/avm_cs.c b/drivers/isdn/hardware/avm/avm_cs.c
index a5b941c..c725655 100644
--- a/drivers/isdn/hardware/avm/avm_cs.c
+++ b/drivers/isdn/hardware/avm/avm_cs.c
@@ -154,83 +154,50 @@
     
 ======================================================================*/
 
-static int get_tuple(struct pcmcia_device *handle, tuple_t *tuple,
-		     cisparse_t *parse)
+static int avmcs_configcheck(struct pcmcia_device *p_dev,
+			     cistpl_cftable_entry_t *cf,
+			     cistpl_cftable_entry_t *dflt,
+			     unsigned int vcc,
+			     void *priv_data)
 {
-    int i = pcmcia_get_tuple_data(handle, tuple);
-    if (i != CS_SUCCESS) return i;
-    return pcmcia_parse_tuple(handle, tuple, parse);
-}
+	if (cf->io.nwin <= 0)
+		return -ENODEV;
 
-static int first_tuple(struct pcmcia_device *handle, tuple_t *tuple,
-		     cisparse_t *parse)
-{
-    int i = pcmcia_get_first_tuple(handle, tuple);
-    if (i != CS_SUCCESS) return i;
-    return get_tuple(handle, tuple, parse);
-}
-
-static int next_tuple(struct pcmcia_device *handle, tuple_t *tuple,
-		     cisparse_t *parse)
-{
-    int i = pcmcia_get_next_tuple(handle, tuple);
-    if (i != CS_SUCCESS) return i;
-    return get_tuple(handle, tuple, parse);
+	p_dev->io.BasePort1 = cf->io.win[0].base;
+	p_dev->io.NumPorts1 = cf->io.win[0].len;
+	p_dev->io.NumPorts2 = 0;
+	printk(KERN_INFO "avm_cs: testing i/o %#x-%#x\n",
+	       p_dev->io.BasePort1,
+	       p_dev->io.BasePort1+p_dev->io.NumPorts1-1);
+	return pcmcia_request_io(p_dev, &p_dev->io);
 }
 
 static int avmcs_config(struct pcmcia_device *link)
 {
-    tuple_t tuple;
-    cisparse_t parse;
-    cistpl_cftable_entry_t *cf = &parse.cftable_entry;
     local_info_t *dev;
     int i;
-    u_char buf[64];
     char devname[128];
     int cardtype;
     int (*addcard)(unsigned int port, unsigned irq);
 
     dev = link->priv;
 
+    devname[0] = 0;
+    if (link->prod_id[1])
+	    strlcpy(devname, link->prod_id[1], sizeof(devname));
+
+    /*
+     * find IO port
+     */
+    if (pcmcia_loop_config(link, avmcs_configcheck, NULL))
+	    return -ENODEV;
+
     do {
-	devname[0] = 0;
-	if (link->prod_id[1])
-		strlcpy(devname, link->prod_id[1], sizeof(devname));
-
-	/*
-         * find IO port
-         */
-	tuple.TupleData = (cisdata_t *)buf;
-	tuple.TupleOffset = 0; tuple.TupleDataMax = 255;
-	tuple.Attributes = 0;
-	tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
-	i = first_tuple(link, &tuple, &parse);
-	while (i == CS_SUCCESS) {
-	    if (cf->io.nwin > 0) {
-		link->conf.ConfigIndex = cf->index;
-		link->io.BasePort1 = cf->io.win[0].base;
-		link->io.NumPorts1 = cf->io.win[0].len;
-		link->io.NumPorts2 = 0;
-                printk(KERN_INFO "avm_cs: testing i/o %#x-%#x\n",
-			link->io.BasePort1,
-		        link->io.BasePort1+link->io.NumPorts1-1);
-		i = pcmcia_request_io(link, &link->io);
-		if (i == CS_SUCCESS) goto found_port;
-	    }
-	    i = next_tuple(link, &tuple, &parse);
-	}
-
-found_port:
-	if (i != CS_SUCCESS) {
-	    cs_error(link, RequestIO, i);
-	    break;
-	}
-
 	/*
 	 * allocate an interrupt line
 	 */
 	i = pcmcia_request_irq(link, &link->irq);
-	if (i != CS_SUCCESS) {
+	if (i != 0) {
 	    cs_error(link, RequestIRQ, i);
 	    /* undo */
 	    pcmcia_disable_device(link);
@@ -241,7 +208,7 @@
          * configure the PCMCIA socket
 	  */
 	i = pcmcia_request_configuration(link, &link->conf);
-	if (i != CS_SUCCESS) {
+	if (i != 0) {
 	    cs_error(link, RequestConfiguration, i);
 	    pcmcia_disable_device(link);
 	    break;
diff --git a/drivers/isdn/hardware/mISDN/hfc_pci.h b/drivers/isdn/hardware/mISDN/hfc_pci.h
index fd2c9be..5783d22 100644
--- a/drivers/isdn/hardware/mISDN/hfc_pci.h
+++ b/drivers/isdn/hardware/mISDN/hfc_pci.h
@@ -183,8 +183,8 @@
 #define D_FREG_MASK  0xF
 
 struct zt {
-	unsigned short z1;  /* Z1 pointer 16 Bit */
-	unsigned short z2;  /* Z2 pointer 16 Bit */
+	__le16 z1;  /* Z1 pointer 16 Bit */
+	__le16 z2;  /* Z2 pointer 16 Bit */
 };
 
 struct dfifo {
diff --git a/drivers/isdn/hardware/mISDN/hfcpci.c b/drivers/isdn/hardware/mISDN/hfcpci.c
index 9cf5edb..cd8302a 100644
--- a/drivers/isdn/hardware/mISDN/hfcpci.c
+++ b/drivers/isdn/hardware/mISDN/hfcpci.c
@@ -43,7 +43,7 @@
 module_param(debug, uint, 0);
 
 static LIST_HEAD(HFClist);
-DEFINE_RWLOCK(HFClock);
+static DEFINE_RWLOCK(HFClock);
 
 enum {
 	HFC_CCD_2BD0,
@@ -88,7 +88,7 @@
 	unsigned char		bswapped;
 	unsigned char		protocol;
 	int			nt_timer;
-	unsigned char		*pci_io; /* start of PCI IO memory */
+	unsigned char __iomem 	*pci_io; /* start of PCI IO memory */
 	dma_addr_t		dmahandle;
 	void			*fifos; /* FIFO memory */
 	int			last_bfifo_cnt[2];
@@ -153,7 +153,7 @@
 	pci_write_config_word(hc->pdev, PCI_COMMAND, 0);
 	del_timer(&hc->hw.timer);
 	pci_free_consistent(hc->pdev, 0x8000, hc->hw.fifos, hc->hw.dmahandle);
-	iounmap((void *)hc->hw.pci_io);
+	iounmap(hc->hw.pci_io);
 }
 
 /*
@@ -366,8 +366,7 @@
 	bzt->f2 = MAX_B_FRAMES;
 	bzt->f1 = bzt->f2;	/* init F pointers to remain constant */
 	bzt->za[MAX_B_FRAMES].z1 = cpu_to_le16(B_FIFO_SIZE + B_SUB_VAL - 1);
-	bzt->za[MAX_B_FRAMES].z2 = cpu_to_le16(
-	    le16_to_cpu(bzt->za[MAX_B_FRAMES].z1 - 1));
+	bzt->za[MAX_B_FRAMES].z2 = cpu_to_le16(B_FIFO_SIZE + B_SUB_VAL - 2);
 	if (fifo_state)
 		hc->hw.fifo_en |= fifo_state;
 	Write_hfc(hc, HFCPCI_FIFO_EN, hc->hw.fifo_en);
@@ -482,7 +481,7 @@
 			df->f2 = ((df->f2 + 1) & MAX_D_FRAMES) |
 			    (MAX_D_FRAMES + 1);	/* next buffer */
 			df->za[df->f2 & D_FREG_MASK].z2 =
-			    cpu_to_le16((zp->z2 + rcnt) & (D_FIFO_SIZE - 1));
+			    cpu_to_le16((le16_to_cpu(zp->z2) + rcnt) & (D_FIFO_SIZE - 1));
 		} else {
 			dch->rx_skb = mI_alloc_skb(rcnt - 3, GFP_ATOMIC);
 			if (!dch->rx_skb) {
@@ -523,10 +522,10 @@
 /*
  * check for transparent receive data and read max one threshold size if avail
  */
-int
+static int
 hfcpci_empty_fifo_trans(struct bchannel *bch, struct bzfifo *bz, u_char *bdata)
 {
-	unsigned short	*z1r, *z2r;
+	 __le16 *z1r, *z2r;
 	int		new_z2, fcnt, maxlen;
 	u_char		*ptr, *ptr1;
 
@@ -576,7 +575,7 @@
 /*
  * B-channel main receive routine
  */
-void
+static void
 main_rec_hfcpci(struct bchannel *bch)
 {
 	struct hfc_pci	*hc = bch->hw;
@@ -724,7 +723,7 @@
 	struct bzfifo	*bz;
 	u_char		*bdata;
 	u_char		new_f1, *src, *dst;
-	unsigned short	*z1t, *z2t;
+	__le16 *z1t, *z2t;
 
 	if ((bch->debug & DEBUG_HW_BCHANNEL) && !(bch->debug & DEBUG_HW_BFIFO))
 		printk(KERN_DEBUG "%s\n", __func__);
@@ -1679,7 +1678,7 @@
  * called for card init message
  */
 
-void
+static void
 inithfcpci(struct hfc_pci *hc)
 {
 	printk(KERN_DEBUG "inithfcpci: entered\n");
@@ -1966,7 +1965,7 @@
 		printk(KERN_WARNING "HFC-PCI: No IRQ for PCI card found\n");
 		return 1;
 	}
-	hc->hw.pci_io = (char *)(ulong)hc->pdev->resource[1].start;
+	hc->hw.pci_io = (char __iomem *)(unsigned long)hc->pdev->resource[1].start;
 
 	if (!hc->hw.pci_io) {
 		printk(KERN_WARNING "HFC-PCI: No IO-Mem for PCI card found\n");
diff --git a/drivers/isdn/hisax/avma1_cs.c b/drivers/isdn/hisax/avma1_cs.c
index fc6cc2c..23560c8 100644
--- a/drivers/isdn/hisax/avma1_cs.c
+++ b/drivers/isdn/hisax/avma1_cs.c
@@ -174,38 +174,29 @@
     
 ======================================================================*/
 
-static int get_tuple(struct pcmcia_device *handle, tuple_t *tuple,
-		     cisparse_t *parse)
+static int avma1cs_configcheck(struct pcmcia_device *p_dev,
+			       cistpl_cftable_entry_t *cf,
+			       cistpl_cftable_entry_t *dflt,
+			       unsigned int vcc,
+			       void *priv_data)
 {
-    int i = pcmcia_get_tuple_data(handle, tuple);
-    if (i != CS_SUCCESS) return i;
-    return pcmcia_parse_tuple(handle, tuple, parse);
+	if (cf->io.nwin <= 0)
+		return -ENODEV;
+
+	p_dev->io.BasePort1 = cf->io.win[0].base;
+	p_dev->io.NumPorts1 = cf->io.win[0].len;
+	p_dev->io.NumPorts2 = 0;
+	printk(KERN_INFO "avma1_cs: testing i/o %#x-%#x\n",
+	       p_dev->io.BasePort1,
+	       p_dev->io.BasePort1+p_dev->io.NumPorts1-1);
+	return pcmcia_request_io(p_dev, &p_dev->io);
 }
 
-static int first_tuple(struct pcmcia_device *handle, tuple_t *tuple,
-		     cisparse_t *parse)
-{
-    int i = pcmcia_get_first_tuple(handle, tuple);
-    if (i != CS_SUCCESS) return i;
-    return get_tuple(handle, tuple, parse);
-}
-
-static int next_tuple(struct pcmcia_device *handle, tuple_t *tuple,
-		     cisparse_t *parse)
-{
-    int i = pcmcia_get_next_tuple(handle, tuple);
-    if (i != CS_SUCCESS) return i;
-    return get_tuple(handle, tuple, parse);
-}
 
 static int avma1cs_config(struct pcmcia_device *link)
 {
-    tuple_t tuple;
-    cisparse_t parse;
-    cistpl_cftable_entry_t *cf = &parse.cftable_entry;
     local_info_t *dev;
     int i;
-    u_char buf[64];
     char devname[128];
     IsdnCard_t	icard;
     int busy = 0;
@@ -214,45 +205,19 @@
 
     DEBUG(0, "avma1cs_config(0x%p)\n", link);
 
+    devname[0] = 0;
+    if (link->prod_id[1])
+	    strlcpy(devname, link->prod_id[1], sizeof(devname));
+
+    if (pcmcia_loop_config(link, avma1cs_configcheck, NULL))
+	    return -ENODEV;
+
     do {
-	devname[0] = 0;
-	if (link->prod_id[1])
-		strlcpy(devname, link->prod_id[1], sizeof(devname));
-
-	/*
-         * find IO port
-         */
-	tuple.TupleData = (cisdata_t *)buf;
-	tuple.TupleOffset = 0; tuple.TupleDataMax = 255;
-	tuple.Attributes = 0;
-	tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
-	i = first_tuple(link, &tuple, &parse);
-	while (i == CS_SUCCESS) {
-	    if (cf->io.nwin > 0) {
-		link->conf.ConfigIndex = cf->index;
-		link->io.BasePort1 = cf->io.win[0].base;
-		link->io.NumPorts1 = cf->io.win[0].len;
-		link->io.NumPorts2 = 0;
-		printk(KERN_INFO "avma1_cs: testing i/o %#x-%#x\n",
-			link->io.BasePort1,
-			link->io.BasePort1+link->io.NumPorts1 - 1);
-		i = pcmcia_request_io(link, &link->io);
-		if (i == CS_SUCCESS) goto found_port;
-	    }
-	    i = next_tuple(link, &tuple, &parse);
-	}
-
-found_port:
-	if (i != CS_SUCCESS) {
-	    cs_error(link, RequestIO, i);
-	    break;
-	}
-	
 	/*
 	 * allocate an interrupt line
 	 */
 	i = pcmcia_request_irq(link, &link->irq);
-	if (i != CS_SUCCESS) {
+	if (i != 0) {
 	    cs_error(link, RequestIRQ, i);
 	    /* undo */
 	    pcmcia_disable_device(link);
@@ -263,7 +228,7 @@
 	 * configure the PCMCIA socket
 	 */
 	i = pcmcia_request_configuration(link, &link->conf);
-	if (i != CS_SUCCESS) {
+	if (i != 0) {
 	    cs_error(link, RequestConfiguration, i);
 	    pcmcia_disable_device(link);
 	    break;
diff --git a/drivers/isdn/hisax/elsa_cs.c b/drivers/isdn/hisax/elsa_cs.c
index db7e644..f4d0fe2 100644
--- a/drivers/isdn/hisax/elsa_cs.c
+++ b/drivers/isdn/hisax/elsa_cs.c
@@ -203,82 +203,55 @@
     device available to the system.
 
 ======================================================================*/
-static int get_tuple(struct pcmcia_device *handle, tuple_t *tuple,
-                     cisparse_t *parse)
-{
-    int i = pcmcia_get_tuple_data(handle, tuple);
-    if (i != CS_SUCCESS) return i;
-    return pcmcia_parse_tuple(handle, tuple, parse);
-}
 
-static int first_tuple(struct pcmcia_device *handle, tuple_t *tuple,
-                     cisparse_t *parse)
+static int elsa_cs_configcheck(struct pcmcia_device *p_dev,
+			       cistpl_cftable_entry_t *cf,
+			       cistpl_cftable_entry_t *dflt,
+			       unsigned int vcc,
+			       void *priv_data)
 {
-    int i = pcmcia_get_first_tuple(handle, tuple);
-    if (i != CS_SUCCESS) return i;
-    return get_tuple(handle, tuple, parse);
-}
+	int j;
 
-static int next_tuple(struct pcmcia_device *handle, tuple_t *tuple,
-                     cisparse_t *parse)
-{
-    int i = pcmcia_get_next_tuple(handle, tuple);
-    if (i != CS_SUCCESS) return i;
-    return get_tuple(handle, tuple, parse);
+	if ((cf->io.nwin > 0) && cf->io.win[0].base) {
+		printk(KERN_INFO "(elsa_cs: looks like the 96 model)\n");
+		p_dev->io.BasePort1 = cf->io.win[0].base;
+		if (!pcmcia_request_io(p_dev, &p_dev->io))
+			return 0;
+	} else {
+		printk(KERN_INFO "(elsa_cs: looks like the 97 model)\n");
+		for (j = 0x2f0; j > 0x100; j -= 0x10) {
+			p_dev->io.BasePort1 = j;
+			if (!pcmcia_request_io(p_dev, &p_dev->io))
+				return 0;
+		}
+	}
+	return -ENODEV;
 }
 
 static int elsa_cs_config(struct pcmcia_device *link)
 {
-    tuple_t tuple;
-    cisparse_t parse;
     local_info_t *dev;
-    int i, j, last_fn;
-    u_short buf[128];
-    cistpl_cftable_entry_t *cf = &parse.cftable_entry;
+    int i, last_fn;
     IsdnCard_t icard;
 
     DEBUG(0, "elsa_config(0x%p)\n", link);
     dev = link->priv;
 
-    tuple.TupleData = (cisdata_t *)buf;
-    tuple.TupleOffset = 0; tuple.TupleDataMax = 255;
-    tuple.Attributes = 0;
-    tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
-    i = first_tuple(link, &tuple, &parse);
-    while (i == CS_SUCCESS) {
-        if ( (cf->io.nwin > 0) && cf->io.win[0].base) {
-            printk(KERN_INFO "(elsa_cs: looks like the 96 model)\n");
-            link->conf.ConfigIndex = cf->index;
-            link->io.BasePort1 = cf->io.win[0].base;
-            i = pcmcia_request_io(link, &link->io);
-            if (i == CS_SUCCESS) break;
-        } else {
-          printk(KERN_INFO "(elsa_cs: looks like the 97 model)\n");
-          link->conf.ConfigIndex = cf->index;
-          for (i = 0, j = 0x2f0; j > 0x100; j -= 0x10) {
-            link->io.BasePort1 = j;
-            i = pcmcia_request_io(link, &link->io);
-            if (i == CS_SUCCESS) break;
-          }
-          break;
-        }
-        i = next_tuple(link, &tuple, &parse);
-    }
-
-    if (i != CS_SUCCESS) {
+    i = pcmcia_loop_config(link, elsa_cs_configcheck, NULL);
+    if (i != 0) {
 	last_fn = RequestIO;
 	goto cs_failed;
     }
 
     i = pcmcia_request_irq(link, &link->irq);
-    if (i != CS_SUCCESS) {
+    if (i != 0) {
         link->irq.AssignedIRQ = 0;
 	last_fn = RequestIRQ;
         goto cs_failed;
     }
 
     i = pcmcia_request_configuration(link, &link->conf);
-    if (i != CS_SUCCESS) {
+    if (i != 0) {
       last_fn = RequestConfiguration;
       goto cs_failed;
     }
diff --git a/drivers/isdn/hisax/sedlbauer_cs.c b/drivers/isdn/hisax/sedlbauer_cs.c
index 439cb53..9a3c9f5 100644
--- a/drivers/isdn/hisax/sedlbauer_cs.c
+++ b/drivers/isdn/hisax/sedlbauer_cs.c
@@ -217,101 +217,61 @@
 #define CS_CHECK(fn, ret) \
 do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)
 
-static int sedlbauer_config(struct pcmcia_device *link)
+static int sedlbauer_config_check(struct pcmcia_device *p_dev,
+				  cistpl_cftable_entry_t *cfg,
+				  cistpl_cftable_entry_t *dflt,
+				  unsigned int vcc,
+				  void *priv_data)
 {
-    local_info_t *dev = link->priv;
-    tuple_t tuple;
-    cisparse_t parse;
-    int last_fn, last_ret;
-    u8 buf[64];
-    config_info_t conf;
-    win_req_t req;
-    memreq_t map;
-    IsdnCard_t  icard;
+	win_req_t *req = priv_data;
 
-    DEBUG(0, "sedlbauer_config(0x%p)\n", link);
+	if (cfg->index == 0)
+		return -ENODEV;
 
-    tuple.Attributes = 0;
-    tuple.TupleData = buf;
-    tuple.TupleDataMax = sizeof(buf);
-    tuple.TupleOffset = 0;
-
-    CS_CHECK(GetConfigurationInfo, pcmcia_get_configuration_info(link, &conf));
-
-    /*
-      In this loop, we scan the CIS for configuration table entries,
-      each of which describes a valid card configuration, including
-      voltage, IO window, memory window, and interrupt settings.
-
-      We make no assumptions about the card to be configured: we use
-      just the information available in the CIS.  In an ideal world,
-      this would work for any PCMCIA card, but it requires a complete
-      and accurate CIS.  In practice, a driver usually "knows" most of
-      these things without consulting the CIS, and most client drivers
-      will only use the CIS to fill in implementation-defined details.
-    */
-    tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
-    CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple));
-    while (1) {
-	cistpl_cftable_entry_t dflt = { 0 };
-	cistpl_cftable_entry_t *cfg = &(parse.cftable_entry);
-	if (pcmcia_get_tuple_data(link, &tuple) != 0 ||
-		pcmcia_parse_tuple(link, &tuple, &parse) != 0)
-	    goto next_entry;
-
-	if (cfg->flags & CISTPL_CFTABLE_DEFAULT) dflt = *cfg;
-	if (cfg->index == 0) goto next_entry;
-	link->conf.ConfigIndex = cfg->index;
-	
 	/* Does this card need audio output? */
 	if (cfg->flags & CISTPL_CFTABLE_AUDIO) {
-	    link->conf.Attributes |= CONF_ENABLE_SPKR;
-	    link->conf.Status = CCSR_AUDIO_ENA;
+		p_dev->conf.Attributes |= CONF_ENABLE_SPKR;
+		p_dev->conf.Status = CCSR_AUDIO_ENA;
 	}
-	
+
 	/* Use power settings for Vcc and Vpp if present */
 	/*  Note that the CIS values need to be rescaled */
 	if (cfg->vcc.present & (1<<CISTPL_POWER_VNOM)) {
-	    if (conf.Vcc != cfg->vcc.param[CISTPL_POWER_VNOM]/10000)
-		goto next_entry;
-	} else if (dflt.vcc.present & (1<<CISTPL_POWER_VNOM)) {
-	    if (conf.Vcc != dflt.vcc.param[CISTPL_POWER_VNOM]/10000)
-		goto next_entry;
+		if (vcc != cfg->vcc.param[CISTPL_POWER_VNOM]/10000)
+			return -ENODEV;
+	} else if (dflt->vcc.present & (1<<CISTPL_POWER_VNOM)) {
+		if (vcc != dflt->vcc.param[CISTPL_POWER_VNOM]/10000)
+			return -ENODEV;
 	}
-	    
+
 	if (cfg->vpp1.present & (1<<CISTPL_POWER_VNOM))
-	    link->conf.Vpp =
-		cfg->vpp1.param[CISTPL_POWER_VNOM]/10000;
-	else if (dflt.vpp1.present & (1<<CISTPL_POWER_VNOM))
-	    link->conf.Vpp =
-		dflt.vpp1.param[CISTPL_POWER_VNOM]/10000;
-	
+		p_dev->conf.Vpp = cfg->vpp1.param[CISTPL_POWER_VNOM]/10000;
+	else if (dflt->vpp1.present & (1<<CISTPL_POWER_VNOM))
+		p_dev->conf.Vpp = dflt->vpp1.param[CISTPL_POWER_VNOM]/10000;
+
 	/* Do we need to allocate an interrupt? */
-	if (cfg->irq.IRQInfo1 || dflt.irq.IRQInfo1)
-	    link->conf.Attributes |= CONF_ENABLE_IRQ;
-	
+	if (cfg->irq.IRQInfo1 || dflt->irq.IRQInfo1)
+		p_dev->conf.Attributes |= CONF_ENABLE_IRQ;
+
 	/* IO window settings */
-	link->io.NumPorts1 = link->io.NumPorts2 = 0;
-	if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) {
-	    cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt.io;
-	    link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
-	    if (!(io->flags & CISTPL_IO_8BIT))
-		link->io.Attributes1 = IO_DATA_PATH_WIDTH_16;
-	    if (!(io->flags & CISTPL_IO_16BIT))
-		link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
-/* new in dummy.cs 2001/01/28 MN 
-            link->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK;
-*/
-	    link->io.BasePort1 = io->win[0].base;
-	    link->io.NumPorts1 = io->win[0].len;
-	    if (io->nwin > 1) {
-		link->io.Attributes2 = link->io.Attributes1;
-		link->io.BasePort2 = io->win[1].base;
-		link->io.NumPorts2 = io->win[1].len;
-	    }
-	    /* This reserves IO space but doesn't actually enable it */
-	    if (pcmcia_request_io(link, &link->io) != 0)
-		goto next_entry;
+	p_dev->io.NumPorts1 = p_dev->io.NumPorts2 = 0;
+	if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) {
+		cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io;
+		p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
+		if (!(io->flags & CISTPL_IO_8BIT))
+			p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_16;
+		if (!(io->flags & CISTPL_IO_16BIT))
+			p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
+		p_dev->io.BasePort1 = io->win[0].base;
+		p_dev->io.NumPorts1 = io->win[0].len;
+		if (io->nwin > 1) {
+			p_dev->io.Attributes2 = p_dev->io.Attributes1;
+			p_dev->io.BasePort2 = io->win[1].base;
+			p_dev->io.NumPorts2 = io->win[1].len;
+		}
+		/* This reserves IO space but doesn't actually enable it */
+		if (pcmcia_request_io(p_dev, &p_dev->io) != 0)
+			return -ENODEV;
 	}
 
 	/*
@@ -325,30 +285,54 @@
 	  needs to be mapped to virtual space with ioremap() before it
 	  is used.
 	*/
-	if ((cfg->mem.nwin > 0) || (dflt.mem.nwin > 0)) {
-	    cistpl_mem_t *mem =
-		(cfg->mem.nwin) ? &cfg->mem : &dflt.mem;
-	    req.Attributes = WIN_DATA_WIDTH_16|WIN_MEMORY_TYPE_CM;
-	    req.Attributes |= WIN_ENABLE;
-	    req.Base = mem->win[0].host_addr;
-	    req.Size = mem->win[0].len;
-/* new in dummy.cs 2001/01/28 MN 
-            if (req.Size < 0x1000)
-                req.Size = 0x1000;
-*/
-	    req.AccessSpeed = 0;
-	    if (pcmcia_request_window(&link, &req, &link->win) != 0)
-		goto next_entry;
-	    map.Page = 0; map.CardOffset = mem->win[0].card_addr;
-	    if (pcmcia_map_mem_page(link->win, &map) != 0)
-		goto next_entry;
+	if ((cfg->mem.nwin > 0) || (dflt->mem.nwin > 0)) {
+		cistpl_mem_t *mem = (cfg->mem.nwin) ? &cfg->mem : &dflt->mem;
+		memreq_t map;
+		req->Attributes = WIN_DATA_WIDTH_16|WIN_MEMORY_TYPE_CM;
+		req->Attributes |= WIN_ENABLE;
+		req->Base = mem->win[0].host_addr;
+		req->Size = mem->win[0].len;
+		req->AccessSpeed = 0;
+		if (pcmcia_request_window(&p_dev, req, &p_dev->win) != 0)
+			return -ENODEV;
+		map.Page = 0;
+		map.CardOffset = mem->win[0].card_addr;
+		if (pcmcia_map_mem_page(p_dev->win, &map) != 0)
+			return -ENODEV;
 	}
-	/* If we got this far, we're cool! */
-	break;
+	return 0;
+}
 
-    next_entry:
-	CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(link, &tuple));
-    }
+
+
+static int sedlbauer_config(struct pcmcia_device *link)
+{
+    local_info_t *dev = link->priv;
+    win_req_t *req;
+    int last_fn, last_ret;
+    IsdnCard_t  icard;
+
+    DEBUG(0, "sedlbauer_config(0x%p)\n", link);
+
+    req = kzalloc(sizeof(win_req_t), GFP_KERNEL);
+    if (!req)
+	    return -ENOMEM;
+
+    /*
+      In this loop, we scan the CIS for configuration table entries,
+      each of which describes a valid card configuration, including
+      voltage, IO window, memory window, and interrupt settings.
+
+      We make no assumptions about the card to be configured: we use
+      just the information available in the CIS.  In an ideal world,
+      this would work for any PCMCIA card, but it requires a complete
+      and accurate CIS.  In practice, a driver usually "knows" most of
+      these things without consulting the CIS, and most client drivers
+      will only use the CIS to fill in implementation-defined details.
+    */
+    last_ret = pcmcia_loop_config(link, sedlbauer_config_check, req);
+    if (last_ret)
+	    goto failed;
 
     /*
        Allocate an interrupt line.  Note that this does not assign a
@@ -387,8 +371,8 @@
 	printk(" & 0x%04x-0x%04x", link->io.BasePort2,
 	       link->io.BasePort2+link->io.NumPorts2-1);
     if (link->win)
-	printk(", mem 0x%06lx-0x%06lx", req.Base,
-	       req.Base+req.Size-1);
+	printk(", mem 0x%06lx-0x%06lx", req->Base,
+	       req->Base+req->Size-1);
     printk("\n");
 
     icard.para[0] = link->irq.AssignedIRQ;
@@ -409,6 +393,7 @@
 
 cs_failed:
     cs_error(link, last_fn, last_ret);
+failed:
     sedlbauer_release(link);
     return -ENODEV;
 
diff --git a/drivers/isdn/hisax/teles_cs.c b/drivers/isdn/hisax/teles_cs.c
index ab4bd45..623d111 100644
--- a/drivers/isdn/hisax/teles_cs.c
+++ b/drivers/isdn/hisax/teles_cs.c
@@ -193,82 +193,55 @@
     device available to the system.
 
 ======================================================================*/
-static int get_tuple(struct pcmcia_device *handle, tuple_t *tuple,
-                     cisparse_t *parse)
-{
-    int i = pcmcia_get_tuple_data(handle, tuple);
-    if (i != CS_SUCCESS) return i;
-    return pcmcia_parse_tuple(handle, tuple, parse);
-}
 
-static int first_tuple(struct pcmcia_device *handle, tuple_t *tuple,
-                     cisparse_t *parse)
+static int teles_cs_configcheck(struct pcmcia_device *p_dev,
+				cistpl_cftable_entry_t *cf,
+				cistpl_cftable_entry_t *dflt,
+				unsigned int vcc,
+				void *priv_data)
 {
-    int i = pcmcia_get_first_tuple(handle, tuple);
-    if (i != CS_SUCCESS) return i;
-    return get_tuple(handle, tuple, parse);
-}
+	int j;
 
-static int next_tuple(struct pcmcia_device *handle, tuple_t *tuple,
-                     cisparse_t *parse)
-{
-    int i = pcmcia_get_next_tuple(handle, tuple);
-    if (i != CS_SUCCESS) return i;
-    return get_tuple(handle, tuple, parse);
+	if ((cf->io.nwin > 0) && cf->io.win[0].base) {
+		printk(KERN_INFO "(teles_cs: looks like the 96 model)\n");
+		p_dev->io.BasePort1 = cf->io.win[0].base;
+		if (!pcmcia_request_io(p_dev, &p_dev->io))
+			return 0;
+	} else {
+		printk(KERN_INFO "(teles_cs: looks like the 97 model)\n");
+		for (j = 0x2f0; j > 0x100; j -= 0x10) {
+			p_dev->io.BasePort1 = j;
+			if (!pcmcia_request_io(p_dev, &p_dev->io))
+				return 0;
+		}
+	}
+	return -ENODEV;
 }
 
 static int teles_cs_config(struct pcmcia_device *link)
 {
-    tuple_t tuple;
-    cisparse_t parse;
     local_info_t *dev;
-    int i, j, last_fn;
-    u_short buf[128];
-    cistpl_cftable_entry_t *cf = &parse.cftable_entry;
+    int i, last_fn;
     IsdnCard_t icard;
 
     DEBUG(0, "teles_config(0x%p)\n", link);
     dev = link->priv;
 
-    tuple.TupleData = (cisdata_t *)buf;
-    tuple.TupleOffset = 0; tuple.TupleDataMax = 255;
-    tuple.Attributes = 0;
-    tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
-    i = first_tuple(link, &tuple, &parse);
-    while (i == CS_SUCCESS) {
-        if ( (cf->io.nwin > 0) && cf->io.win[0].base) {
-            printk(KERN_INFO "(teles_cs: looks like the 96 model)\n");
-            link->conf.ConfigIndex = cf->index;
-            link->io.BasePort1 = cf->io.win[0].base;
-            i = pcmcia_request_io(link, &link->io);
-            if (i == CS_SUCCESS) break;
-        } else {
-          printk(KERN_INFO "(teles_cs: looks like the 97 model)\n");
-          link->conf.ConfigIndex = cf->index;
-          for (i = 0, j = 0x2f0; j > 0x100; j -= 0x10) {
-            link->io.BasePort1 = j;
-            i = pcmcia_request_io(link, &link->io);
-            if (i == CS_SUCCESS) break;
-          }
-          break;
-        }
-        i = next_tuple(link, &tuple, &parse);
-    }
-
-    if (i != CS_SUCCESS) {
+    i = pcmcia_loop_config(link, teles_cs_configcheck, NULL);
+    if (i != 0) {
 	last_fn = RequestIO;
 	goto cs_failed;
     }
 
     i = pcmcia_request_irq(link, &link->irq);
-    if (i != CS_SUCCESS) {
+    if (i != 0) {
         link->irq.AssignedIRQ = 0;
 	last_fn = RequestIRQ;
         goto cs_failed;
     }
 
     i = pcmcia_request_configuration(link, &link->conf);
-    if (i != CS_SUCCESS) {
+    if (i != 0) {
       last_fn = RequestConfiguration;
       goto cs_failed;
     }
diff --git a/drivers/isdn/i4l/isdn_ppp.c b/drivers/isdn/i4l/isdn_ppp.c
index 127cfda..77c280e 100644
--- a/drivers/isdn/i4l/isdn_ppp.c
+++ b/drivers/isdn/i4l/isdn_ppp.c
@@ -1533,8 +1533,10 @@
 	int sz = ISDN_MAX_CHANNELS*sizeof(ippp_bundle);
 	if( (isdn_ppp_bundle_arr = kzalloc(sz, GFP_KERNEL)) == NULL )
 		return -ENOMEM;
-	for( i = 0; i < ISDN_MAX_CHANNELS; i++ )
+	for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
 		spin_lock_init(&isdn_ppp_bundle_arr[i].lock);
+		skb_queue_head_init(&isdn_ppp_bundle_arr[i].frags);
+	}
 	return 0;
 }
 
@@ -1567,7 +1569,7 @@
 		if ((lp->netdev->pb = isdn_ppp_mp_bundle_alloc()) == NULL)
 			return -ENOMEM;
 		lp->next = lp->last = lp;	/* nobody else in a queue */
-		lp->netdev->pb->frags = NULL;
+		skb_queue_head_init(&lp->netdev->pb->frags);
 		lp->netdev->pb->frames = 0;
 		lp->netdev->pb->seq = UINT_MAX;
 	}
@@ -1579,28 +1581,29 @@
 
 static u32 isdn_ppp_mp_get_seq( int short_seq, 
 					struct sk_buff * skb, u32 last_seq );
-static struct sk_buff * isdn_ppp_mp_discard( ippp_bundle * mp,
-			struct sk_buff * from, struct sk_buff * to );
-static void isdn_ppp_mp_reassembly( isdn_net_dev * net_dev, isdn_net_local * lp,
-				struct sk_buff * from, struct sk_buff * to );
-static void isdn_ppp_mp_free_skb( ippp_bundle * mp, struct sk_buff * skb );
+static void isdn_ppp_mp_discard(ippp_bundle *mp, struct sk_buff *from,
+				struct sk_buff *to);
+static void isdn_ppp_mp_reassembly(isdn_net_dev *net_dev, isdn_net_local *lp,
+				   struct sk_buff *from, struct sk_buff *to,
+				   u32 lastseq);
+static void isdn_ppp_mp_free_skb(ippp_bundle *mp, struct sk_buff *skb);
 static void isdn_ppp_mp_print_recv_pkt( int slot, struct sk_buff * skb );
 
 static void isdn_ppp_mp_receive(isdn_net_dev * net_dev, isdn_net_local * lp, 
-							struct sk_buff *skb)
+				struct sk_buff *skb)
 {
-	struct ippp_struct *is;
-	isdn_net_local * lpq;
-	ippp_bundle * mp;
-	isdn_mppp_stats * stats;
-	struct sk_buff * newfrag, * frag, * start, *nextf;
+	struct sk_buff *newfrag, *frag, *start, *nextf;
 	u32 newseq, minseq, thisseq;
+	isdn_mppp_stats *stats;
+	struct ippp_struct *is;
 	unsigned long flags;
+	isdn_net_local *lpq;
+	ippp_bundle *mp;
 	int slot;
 
 	spin_lock_irqsave(&net_dev->pb->lock, flags);
-    	mp = net_dev->pb;
-        stats = &mp->stats;
+	mp = net_dev->pb;
+	stats = &mp->stats;
 	slot = lp->ppp_slot;
 	if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {
 		printk(KERN_ERR "%s: lp->ppp_slot(%d)\n",
@@ -1611,20 +1614,19 @@
 		return;
 	}
 	is = ippp_table[slot];
-    	if( ++mp->frames > stats->max_queue_len )
+	if (++mp->frames > stats->max_queue_len)
 		stats->max_queue_len = mp->frames;
-	
+
 	if (is->debug & 0x8)
 		isdn_ppp_mp_print_recv_pkt(lp->ppp_slot, skb);
 
-	newseq = isdn_ppp_mp_get_seq(is->mpppcfg & SC_IN_SHORT_SEQ, 
-						skb, is->last_link_seqno);
-
+	newseq = isdn_ppp_mp_get_seq(is->mpppcfg & SC_IN_SHORT_SEQ,
+				     skb, is->last_link_seqno);
 
 	/* if this packet seq # is less than last already processed one,
 	 * toss it right away, but check for sequence start case first 
 	 */
-	if( mp->seq > MP_LONGSEQ_MAX && (newseq & MP_LONGSEQ_MAXBIT) ) {
+	if (mp->seq > MP_LONGSEQ_MAX && (newseq & MP_LONGSEQ_MAXBIT)) {
 		mp->seq = newseq;	/* the first packet: required for
 					 * rfc1990 non-compliant clients --
 					 * prevents constant packet toss */
@@ -1634,7 +1636,7 @@
 		spin_unlock_irqrestore(&mp->lock, flags);
 		return;
 	}
-	
+
 	/* find the minimum received sequence number over all links */
 	is->last_link_seqno = minseq = newseq;
 	for (lpq = net_dev->queue;;) {
@@ -1655,22 +1657,31 @@
 					 * packets */
 	newfrag = skb;
 
-  	/* if this new fragment is before the first one, then enqueue it now. */
-  	if ((frag = mp->frags) == NULL || MP_LT(newseq, MP_SEQ(frag))) {
-		newfrag->next = frag;
-    		mp->frags = frag = newfrag;
-    		newfrag = NULL;
-  	}
+	/* Insert new fragment into the proper sequence slot.  */
+	skb_queue_walk(&mp->frags, frag) {
+		if (MP_SEQ(frag) == newseq) {
+			isdn_ppp_mp_free_skb(mp, newfrag);
+			newfrag = NULL;
+			break;
+		}
+		if (MP_LT(newseq, MP_SEQ(frag))) {
+			__skb_queue_before(&mp->frags, frag, newfrag);
+			newfrag = NULL;
+			break;
+		}
+	}
+	if (newfrag)
+		__skb_queue_tail(&mp->frags, newfrag);
 
-  	start = MP_FLAGS(frag) & MP_BEGIN_FRAG &&
-				MP_SEQ(frag) == mp->seq ? frag : NULL;
+	frag = skb_peek(&mp->frags);
+	start = ((MP_FLAGS(frag) & MP_BEGIN_FRAG) &&
+		 (MP_SEQ(frag) == mp->seq)) ? frag : NULL;
+	if (!start)
+		goto check_overflow;
 
-	/* 
-	 * main fragment traversing loop
+	/* main fragment traversing loop
 	 *
 	 * try to accomplish several tasks:
-	 * - insert new fragment into the proper sequence slot (once that's done
-	 *   newfrag will be set to NULL)
 	 * - reassemble any complete fragment sequence (non-null 'start'
 	 *   indicates there is a continguous sequence present)
 	 * - discard any incomplete sequences that are below minseq -- due
@@ -1679,71 +1690,46 @@
 	 *   come to complete such sequence and it should be discarded
 	 *
 	 * loop completes when we accomplished the following tasks:
-	 * - new fragment is inserted in the proper sequence ('newfrag' is 
-	 *   set to NULL)
 	 * - we hit a gap in the sequence, so no reassembly/processing is 
 	 *   possible ('start' would be set to NULL)
 	 *
 	 * algorithm for this code is derived from code in the book
 	 * 'PPP Design And Debugging' by James Carlson (Addison-Wesley)
 	 */
-  	while (start != NULL || newfrag != NULL) {
+	skb_queue_walk_safe(&mp->frags, frag, nextf) {
+		thisseq = MP_SEQ(frag);
 
-    		thisseq = MP_SEQ(frag);
-    		nextf = frag->next;
-
-    		/* drop any duplicate fragments */
-    		if (newfrag != NULL && thisseq == newseq) {
-      			isdn_ppp_mp_free_skb(mp, newfrag);
-      			newfrag = NULL;
-    		}
-
-    		/* insert new fragment before next element if possible. */
-    		if (newfrag != NULL && (nextf == NULL || 
-						MP_LT(newseq, MP_SEQ(nextf)))) {
-      			newfrag->next = nextf;
-      			frag->next = nextf = newfrag;
-      			newfrag = NULL;
-    		}
-
-    		if (start != NULL) {
-	    		/* check for misplaced start */
-      			if (start != frag && (MP_FLAGS(frag) & MP_BEGIN_FRAG)) {
-				printk(KERN_WARNING"isdn_mppp(seq %d): new "
-				      "BEGIN flag with no prior END", thisseq);
-				stats->seqerrs++;
-				stats->frame_drops++;
-				start = isdn_ppp_mp_discard(mp, start,frag);
-				nextf = frag->next;
-      			}
-    		} else if (MP_LE(thisseq, minseq)) {		
-      			if (MP_FLAGS(frag) & MP_BEGIN_FRAG)
+		/* check for misplaced start */
+		if (start != frag && (MP_FLAGS(frag) & MP_BEGIN_FRAG)) {
+			printk(KERN_WARNING"isdn_mppp(seq %d): new "
+			       "BEGIN flag with no prior END", thisseq);
+			stats->seqerrs++;
+			stats->frame_drops++;
+			isdn_ppp_mp_discard(mp, start, frag);
+			start = frag;
+		} else if (MP_LE(thisseq, minseq)) {		
+			if (MP_FLAGS(frag) & MP_BEGIN_FRAG)
 				start = frag;
-      			else {
+			else {
 				if (MP_FLAGS(frag) & MP_END_FRAG)
-	  				stats->frame_drops++;
-				if( mp->frags == frag )
-					mp->frags = nextf;	
+					stats->frame_drops++;
+				__skb_unlink(skb, &mp->frags);
 				isdn_ppp_mp_free_skb(mp, frag);
-				frag = nextf;
 				continue;
-      			}
+			}
 		}
-		
-		/* if start is non-null and we have end fragment, then
-		 * we have full reassembly sequence -- reassemble 
-		 * and process packet now
-		 */
-    		if (start != NULL && (MP_FLAGS(frag) & MP_END_FRAG)) {
-      			minseq = mp->seq = (thisseq+1) & MP_LONGSEQ_MASK;
-      			/* Reassemble the packet then dispatch it */
-			isdn_ppp_mp_reassembly(net_dev, lp, start, nextf);
-      
-      			start = NULL;
-      			frag = NULL;
 
-      			mp->frags = nextf;
-    		}
+		/* if we have end fragment, then we have full reassembly
+		 * sequence -- reassemble and process packet now
+		 */
+		if (MP_FLAGS(frag) & MP_END_FRAG) {
+			minseq = mp->seq = (thisseq+1) & MP_LONGSEQ_MASK;
+			/* Reassemble the packet then dispatch it */
+			isdn_ppp_mp_reassembly(net_dev, lp, start, frag, thisseq);
+
+			start = NULL;
+			frag = NULL;
+		}
 
 		/* check if need to update start pointer: if we just
 		 * reassembled the packet and sequence is contiguous
@@ -1754,26 +1740,25 @@
 		 * below low watermark and set start to the next frag or
 		 * clear start ptr.
 		 */ 
-    		if (nextf != NULL && 
+		if (nextf != (struct sk_buff *)&mp->frags && 
 		    ((thisseq+1) & MP_LONGSEQ_MASK) == MP_SEQ(nextf)) {
-      			/* if we just reassembled and the next one is here, 
-			 * then start another reassembly. */
-
-      			if (frag == NULL) {
+			/* if we just reassembled and the next one is here, 
+			 * then start another reassembly.
+			 */
+			if (frag == NULL) {
 				if (MP_FLAGS(nextf) & MP_BEGIN_FRAG)
-	  				start = nextf;
-				else
-				{
-	  				printk(KERN_WARNING"isdn_mppp(seq %d):"
-						" END flag with no following "
-						"BEGIN", thisseq);
+					start = nextf;
+				else {
+					printk(KERN_WARNING"isdn_mppp(seq %d):"
+					       " END flag with no following "
+					       "BEGIN", thisseq);
 					stats->seqerrs++;
 				}
 			}
-
-    		} else {
-			if ( nextf != NULL && frag != NULL &&
-						MP_LT(thisseq, minseq)) {
+		} else {
+			if (nextf != (struct sk_buff *)&mp->frags &&
+			    frag != NULL &&
+			    MP_LT(thisseq, minseq)) {
 				/* we've got a break in the sequence
 				 * and we not at the end yet
 				 * and we did not just reassembled
@@ -1782,41 +1767,39 @@
 			 	 * discard all the frames below low watermark 
 				 * and start over */
 				stats->frame_drops++;
-				mp->frags = isdn_ppp_mp_discard(mp,start,nextf);
+				isdn_ppp_mp_discard(mp, start, nextf);
 			}
 			/* break in the sequence, no reassembly */
-      			start = NULL;
-    		}
-	  			
-    		frag = nextf;
-  	}	/* while -- main loop */
-	
-  	if (mp->frags == NULL)
-    		mp->frags = frag;
-		
+			start = NULL;
+		}
+		if (!start)
+			break;
+	}
+
+check_overflow:
 	/* rather straighforward way to deal with (not very) possible 
-	 * queue overflow */
+	 * queue overflow
+	 */
 	if (mp->frames > MP_MAX_QUEUE_LEN) {
 		stats->overflows++;
-		while (mp->frames > MP_MAX_QUEUE_LEN) {
-			frag = mp->frags->next;
-			isdn_ppp_mp_free_skb(mp, mp->frags);
-			mp->frags = frag;
+		skb_queue_walk_safe(&mp->frags, frag, nextf) {
+			if (mp->frames <= MP_MAX_QUEUE_LEN)
+				break;
+			__skb_unlink(frag, &mp->frags);
+			isdn_ppp_mp_free_skb(mp, frag);
 		}
 	}
 	spin_unlock_irqrestore(&mp->lock, flags);
 }
 
-static void isdn_ppp_mp_cleanup( isdn_net_local * lp )
+static void isdn_ppp_mp_cleanup(isdn_net_local *lp)
 {
-	struct sk_buff * frag = lp->netdev->pb->frags;
-	struct sk_buff * nextfrag;
-    	while( frag ) {
-		nextfrag = frag->next;
-		isdn_ppp_mp_free_skb(lp->netdev->pb, frag);
-		frag = nextfrag;
+	struct sk_buff *skb, *tmp;
+
+	skb_queue_walk_safe(&lp->netdev->pb->frags, skb, tmp) {
+		__skb_unlink(skb, &lp->netdev->pb->frags);
+		isdn_ppp_mp_free_skb(lp->netdev->pb, skb);
 	}
-	lp->netdev->pb->frags = NULL;
 }
 
 static u32 isdn_ppp_mp_get_seq( int short_seq, 
@@ -1853,72 +1836,115 @@
 	return seq;
 }
 
-struct sk_buff * isdn_ppp_mp_discard( ippp_bundle * mp,
-			struct sk_buff * from, struct sk_buff * to )
+static void isdn_ppp_mp_discard(ippp_bundle *mp, struct sk_buff *from,
+				struct sk_buff *to)
 {
-	if( from )
-		while (from != to) {
-	  		struct sk_buff * next = from->next;
-			isdn_ppp_mp_free_skb(mp, from);
-	  		from = next;
+	if (from) {
+		struct sk_buff *skb, *tmp;
+		int freeing = 0;
+
+		skb_queue_walk_safe(&mp->frags, skb, tmp) {
+			if (skb == to)
+				break;
+			if (skb == from)
+				freeing = 1;
+			if (!freeing)
+				continue;
+			__skb_unlink(skb, &mp->frags);
+			isdn_ppp_mp_free_skb(mp, skb);
 		}
-	return from;
+	}
 }
 
-void isdn_ppp_mp_reassembly( isdn_net_dev * net_dev, isdn_net_local * lp,
-				struct sk_buff * from, struct sk_buff * to )
+static unsigned int calc_tot_len(struct sk_buff_head *queue,
+				 struct sk_buff *from, struct sk_buff *to)
 {
-	ippp_bundle * mp = net_dev->pb;
-	int proto;
-	struct sk_buff * skb;
+	unsigned int tot_len = 0;
+	struct sk_buff *skb;
+	int found_start = 0;
+
+	skb_queue_walk(queue, skb) {
+		if (skb == from)
+			found_start = 1;
+		if (!found_start)
+			continue;
+		tot_len += skb->len - MP_HEADER_LEN;
+		if (skb == to)
+			break;
+	}
+	return tot_len;
+}
+
+/* Reassemble packet using fragments in the reassembly queue from
+ * 'from' until 'to', inclusive.
+ */
+static void isdn_ppp_mp_reassembly(isdn_net_dev *net_dev, isdn_net_local *lp,
+				   struct sk_buff *from, struct sk_buff *to,
+				   u32 lastseq)
+{
+	ippp_bundle *mp = net_dev->pb;
 	unsigned int tot_len;
+	struct sk_buff *skb;
+	int proto;
 
 	if (lp->ppp_slot < 0 || lp->ppp_slot >= ISDN_MAX_CHANNELS) {
 		printk(KERN_ERR "%s: lp->ppp_slot(%d) out of range\n",
 			__func__, lp->ppp_slot);
 		return;
 	}
-	if( MP_FLAGS(from) == (MP_BEGIN_FRAG | MP_END_FRAG) ) {
-		if( ippp_table[lp->ppp_slot]->debug & 0x40 )
+
+	tot_len = calc_tot_len(&mp->frags, from, to);
+
+	if (MP_FLAGS(from) == (MP_BEGIN_FRAG | MP_END_FRAG)) {
+		if (ippp_table[lp->ppp_slot]->debug & 0x40)
 			printk(KERN_DEBUG "isdn_mppp: reassembly: frame %d, "
-					"len %d\n", MP_SEQ(from), from->len );
+			       "len %d\n", MP_SEQ(from), from->len);
 		skb = from;
 		skb_pull(skb, MP_HEADER_LEN);
+		__skb_unlink(skb, &mp->frags);
 		mp->frames--;	
 	} else {
-		struct sk_buff * frag;
-		int n;
+		struct sk_buff *walk, *tmp;
+		int found_start = 0;
 
-		for(tot_len=n=0, frag=from; frag != to; frag=frag->next, n++)
-			tot_len += frag->len - MP_HEADER_LEN;
-
-		if( ippp_table[lp->ppp_slot]->debug & 0x40 )
+		if (ippp_table[lp->ppp_slot]->debug & 0x40)
 			printk(KERN_DEBUG"isdn_mppp: reassembling frames %d "
-				"to %d, len %d\n", MP_SEQ(from), 
-				(MP_SEQ(from)+n-1) & MP_LONGSEQ_MASK, tot_len );
-		if( (skb = dev_alloc_skb(tot_len)) == NULL ) {
+			       "to %d, len %d\n", MP_SEQ(from), lastseq,
+			       tot_len);
+
+		skb = dev_alloc_skb(tot_len);
+		if (!skb)
 			printk(KERN_ERR "isdn_mppp: cannot allocate sk buff "
-					"of size %d\n", tot_len);
-			isdn_ppp_mp_discard(mp, from, to);
-			return;
-		}
+			       "of size %d\n", tot_len);
 
-		while( from != to ) {
-			unsigned int len = from->len - MP_HEADER_LEN;
+		found_start = 0;
+		skb_queue_walk_safe(&mp->frags, walk, tmp) {
+			if (walk == from)
+				found_start = 1;
+			if (!found_start)
+				continue;
 
-			skb_copy_from_linear_data_offset(from, MP_HEADER_LEN,
-							 skb_put(skb,len),
-							 len);
-			frag = from->next;
-			isdn_ppp_mp_free_skb(mp, from);
-			from = frag; 
+			if (skb) {
+				unsigned int len = walk->len - MP_HEADER_LEN;
+				skb_copy_from_linear_data_offset(walk, MP_HEADER_LEN,
+								 skb_put(skb, len),
+								 len);
+			}
+			__skb_unlink(walk, &mp->frags);
+			isdn_ppp_mp_free_skb(mp, walk);
+
+			if (walk == to)
+				break;
 		}
 	}
+	if (!skb)
+		return;
+
    	proto = isdn_ppp_strip_proto(skb);
 	isdn_ppp_push_higher(net_dev, lp, skb, proto);
 }
 
-static void isdn_ppp_mp_free_skb(ippp_bundle * mp, struct sk_buff * skb)
+static void isdn_ppp_mp_free_skb(ippp_bundle *mp, struct sk_buff *skb)
 {
 	dev_kfree_skb(skb);
 	mp->frames--;
diff --git a/drivers/isdn/mISDN/dsp_cmx.c b/drivers/isdn/mISDN/dsp_cmx.c
index e92b1ba..c2f51cc 100644
--- a/drivers/isdn/mISDN/dsp_cmx.c
+++ b/drivers/isdn/mISDN/dsp_cmx.c
@@ -452,10 +452,10 @@
 			if (finddsp->features.pcm_id == dsp->features.pcm_id) {
 				if (finddsp->pcm_slot_rx >= 0 &&
 				    finddsp->pcm_slot_rx < sizeof(freeslots))
-					freeslots[finddsp->pcm_slot_tx] = 0;
+					freeslots[finddsp->pcm_slot_rx] = 0;
 				if (finddsp->pcm_slot_tx >= 0 &&
 				    finddsp->pcm_slot_tx < sizeof(freeslots))
-					freeslots[finddsp->pcm_slot_rx] = 0;
+					freeslots[finddsp->pcm_slot_tx] = 0;
 			}
 		}
 		i = 0;
diff --git a/drivers/isdn/mISDN/timerdev.c b/drivers/isdn/mISDN/timerdev.c
index b5fabc7..875fabe 100644
--- a/drivers/isdn/mISDN/timerdev.c
+++ b/drivers/isdn/mISDN/timerdev.c
@@ -61,7 +61,7 @@
 	init_waitqueue_head(&dev->wait);
 	filep->private_data = dev;
 	__module_get(THIS_MODULE);
-	return 0;
+	return nonseekable_open(ino, filep);
 }
 
 static int
@@ -124,18 +124,6 @@
 	return ret;
 }
 
-static loff_t
-mISDN_llseek(struct file *filep, loff_t offset, int orig)
-{
-	return -ESPIPE;
-}
-
-static ssize_t
-mISDN_write(struct file *filep, const char *buf, size_t count, loff_t *off)
-{
-	return -EOPNOTSUPP;
-}
-
 static unsigned int
 mISDN_poll(struct file *filep, poll_table *wait)
 {
@@ -157,8 +145,9 @@
 }
 
 static void
-dev_expire_timer(struct mISDNtimer *timer)
+dev_expire_timer(unsigned long data)
 {
+	struct mISDNtimer *timer = (void *)data;
 	u_long			flags;
 
 	spin_lock_irqsave(&timer->dev->lock, flags);
@@ -191,7 +180,7 @@
 		spin_unlock_irqrestore(&dev->lock, flags);
 		timer->dev = dev;
 		timer->tl.data = (long)timer;
-		timer->tl.function = (void *) dev_expire_timer;
+		timer->tl.function = dev_expire_timer;
 		init_timer(&timer->tl);
 		timer->tl.expires = jiffies + ((HZ * (u_long)timeout) / 1000);
 		add_timer(&timer->tl);
@@ -211,6 +200,9 @@
 	list_for_each_entry(timer, &dev->pending, list) {
 		if (timer->id == id) {
 			list_del_init(&timer->list);
+			/* RED-PEN AK: race -- timer can be still running on
+			 * other CPU. Needs reference count I think
+			 */
 			del_timer(&timer->tl);
 			ret = timer->id;
 			kfree(timer);
@@ -268,9 +260,7 @@
 }
 
 static struct file_operations mISDN_fops = {
-	.llseek		= mISDN_llseek,
 	.read		= mISDN_read,
-	.write		= mISDN_write,
 	.poll		= mISDN_poll,
 	.ioctl		= mISDN_ioctl,
 	.open		= mISDN_open,
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index 9556262..e3e4042 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -24,13 +24,6 @@
 	  This option enables support for LEDs driven using outputs
 	  of the dedicated PWM controller found on newer Atmel SOCs.
 
-config LEDS_CORGI
-	tristate "LED Support for the Sharp SL-C7x0 series"
-	depends on LEDS_CLASS && PXA_SHARP_C7xx
-	help
-	  This option enables support for the LEDs on Sharp Zaurus
-	  SL-C7x0 series (C700, C750, C760, C860).
-
 config LEDS_LOCOMO
 	tristate "LED Support for Locomo device"
 	depends on LEDS_CLASS && SHARP_LOCOMO
@@ -38,13 +31,6 @@
 	  This option enables support for the LEDs on Sharp Locomo.
 	  Zaurus models SL-5500 and SL-5600.
 
-config LEDS_SPITZ
-	tristate "LED Support for the Sharp SL-Cxx00 series"
-	depends on LEDS_CLASS && PXA_SHARP_Cxx00
-	help
-	  This option enables support for the LEDs on Sharp Zaurus
-	  SL-Cxx00 series (C1000, C3000, C3100).
-
 config LEDS_S3C24XX
 	tristate "LED Support for Samsung S3C24XX GPIO LEDs"
 	depends on LEDS_CLASS && ARCH_S3C2410
@@ -96,6 +82,14 @@
 	help
 	  This option enables support for the Cobalt Raq series LEDs.
 
+config LEDS_SUNFIRE
+	tristate "LED support for SunFire servers."
+	depends on LEDS_CLASS && SPARC64
+	select LEDS_TRIGGERS
+	help
+	  This option enables support for the Left, Middle, and Right
+	  LEDs on the I/O and CPU boards of SunFire UltraSPARC servers.
+
 config LEDS_HP6XX
 	tristate "LED Support for the HP Jornada 6xx"
 	depends on LEDS_CLASS && SH_HP6XX
diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
index ff7982b..eb186c3 100644
--- a/drivers/leds/Makefile
+++ b/drivers/leds/Makefile
@@ -6,9 +6,7 @@
 
 # LED Platform Drivers
 obj-$(CONFIG_LEDS_ATMEL_PWM)		+= leds-atmel-pwm.o
-obj-$(CONFIG_LEDS_CORGI)		+= leds-corgi.o
 obj-$(CONFIG_LEDS_LOCOMO)		+= leds-locomo.o
-obj-$(CONFIG_LEDS_SPITZ)		+= leds-spitz.o
 obj-$(CONFIG_LEDS_S3C24XX)		+= leds-s3c24xx.o
 obj-$(CONFIG_LEDS_AMS_DELTA)		+= leds-ams-delta.o
 obj-$(CONFIG_LEDS_NET48XX)		+= leds-net48xx.o
@@ -16,6 +14,7 @@
 obj-$(CONFIG_LEDS_H1940)		+= leds-h1940.o
 obj-$(CONFIG_LEDS_COBALT_QUBE)		+= leds-cobalt-qube.o
 obj-$(CONFIG_LEDS_COBALT_RAQ)		+= leds-cobalt-raq.o
+obj-$(CONFIG_LEDS_SUNFIRE)		+= leds-sunfire.o
 obj-$(CONFIG_LEDS_PCA9532)		+= leds-pca9532.o
 obj-$(CONFIG_LEDS_GPIO)			+= leds-gpio.o
 obj-$(CONFIG_LEDS_CM_X270)              += leds-cm-x270.o
diff --git a/drivers/leds/leds-corgi.c b/drivers/leds/leds-corgi.c
deleted file mode 100644
index bc2dcd8..0000000
--- a/drivers/leds/leds-corgi.c
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- * LED Triggers Core
- *
- * Copyright 2005-2006 Openedhand Ltd.
- *
- * Author: Richard Purdie <rpurdie@openedhand.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/kernel.h>
-#include <linux/init.h>
-#include <linux/platform_device.h>
-#include <linux/leds.h>
-#include <mach/corgi.h>
-#include <mach/hardware.h>
-#include <mach/pxa-regs.h>
-#include <asm/hardware/scoop.h>
-
-static void corgiled_amber_set(struct led_classdev *led_cdev,
-			       enum led_brightness value)
-{
-	if (value)
-		GPSR0 = GPIO_bit(CORGI_GPIO_LED_ORANGE);
-	else
-		GPCR0 = GPIO_bit(CORGI_GPIO_LED_ORANGE);
-}
-
-static void corgiled_green_set(struct led_classdev *led_cdev,
-			       enum led_brightness value)
-{
-	if (value)
-		set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_LED_GREEN);
-	else
-		reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_LED_GREEN);
-}
-
-static struct led_classdev corgi_amber_led = {
-	.name			= "corgi:amber:charge",
-	.default_trigger	= "sharpsl-charge",
-	.brightness_set		= corgiled_amber_set,
-};
-
-static struct led_classdev corgi_green_led = {
-	.name			= "corgi:green:mail",
-	.default_trigger	= "nand-disk",
-	.brightness_set		= corgiled_green_set,
-};
-
-#ifdef CONFIG_PM
-static int corgiled_suspend(struct platform_device *dev, pm_message_t state)
-{
-#ifdef CONFIG_LEDS_TRIGGERS
-	if (corgi_amber_led.trigger &&
-	    strcmp(corgi_amber_led.trigger->name, "sharpsl-charge"))
-#endif
-		led_classdev_suspend(&corgi_amber_led);
-	led_classdev_suspend(&corgi_green_led);
-	return 0;
-}
-
-static int corgiled_resume(struct platform_device *dev)
-{
-	led_classdev_resume(&corgi_amber_led);
-	led_classdev_resume(&corgi_green_led);
-	return 0;
-}
-#endif
-
-static int corgiled_probe(struct platform_device *pdev)
-{
-	int ret;
-
-	ret = led_classdev_register(&pdev->dev, &corgi_amber_led);
-	if (ret < 0)
-		return ret;
-
-	ret = led_classdev_register(&pdev->dev, &corgi_green_led);
-	if (ret < 0)
-		led_classdev_unregister(&corgi_amber_led);
-
-	return ret;
-}
-
-static int corgiled_remove(struct platform_device *pdev)
-{
-	led_classdev_unregister(&corgi_amber_led);
-	led_classdev_unregister(&corgi_green_led);
-	return 0;
-}
-
-static struct platform_driver corgiled_driver = {
-	.probe		= corgiled_probe,
-	.remove		= corgiled_remove,
-#ifdef CONFIG_PM
-	.suspend	= corgiled_suspend,
-	.resume		= corgiled_resume,
-#endif
-	.driver		= {
-		.name		= "corgi-led",
-		.owner		= THIS_MODULE,
-	},
-};
-
-static int __init corgiled_init(void)
-{
-	return platform_driver_register(&corgiled_driver);
-}
-
-static void __exit corgiled_exit(void)
-{
-	platform_driver_unregister(&corgiled_driver);
-}
-
-module_init(corgiled_init);
-module_exit(corgiled_exit);
-
-MODULE_AUTHOR("Richard Purdie <rpurdie@openedhand.com>");
-MODULE_DESCRIPTION("Corgi LED driver");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:corgi-led");
diff --git a/drivers/leds/leds-fsg.c b/drivers/leds/leds-fsg.c
index be0e121..3493515 100644
--- a/drivers/leds/leds-fsg.c
+++ b/drivers/leds/leds-fsg.c
@@ -161,6 +161,16 @@
 {
 	int ret;
 
+	/* Map the LED chip select address space */
+	latch_address = (unsigned short *) ioremap(IXP4XX_EXP_BUS_BASE(2), 512);
+	if (!latch_address) {
+		ret = -ENOMEM;
+		goto failremap;
+	}
+
+	latch_value = 0xffff;
+	*latch_address = latch_value;
+
 	ret = led_classdev_register(&pdev->dev, &fsg_wlan_led);
 	if (ret < 0)
 		goto failwlan;
@@ -185,20 +195,8 @@
 	if (ret < 0)
 		goto failring;
 
-	/* Map the LED chip select address space */
-	latch_address = (unsigned short *) ioremap(IXP4XX_EXP_BUS_BASE(2), 512);
-	if (!latch_address) {
-		ret = -ENOMEM;
-		goto failremap;
-	}
-
-	latch_value = 0xffff;
-	*latch_address = latch_value;
-
 	return ret;
 
- failremap:
-	led_classdev_unregister(&fsg_ring_led);
  failring:
 	led_classdev_unregister(&fsg_sync_led);
  failsync:
@@ -210,14 +208,14 @@
  failwan:
 	led_classdev_unregister(&fsg_wlan_led);
  failwlan:
+	iounmap(latch_address);
+ failremap:
 
 	return ret;
 }
 
 static int fsg_led_remove(struct platform_device *pdev)
 {
-	iounmap(latch_address);
-
 	led_classdev_unregister(&fsg_wlan_led);
 	led_classdev_unregister(&fsg_wan_led);
 	led_classdev_unregister(&fsg_sata_led);
@@ -225,6 +223,8 @@
 	led_classdev_unregister(&fsg_sync_led);
 	led_classdev_unregister(&fsg_ring_led);
 
+	iounmap(latch_address);
+
 	return 0;
 }
 
diff --git a/drivers/leds/leds-pca955x.c b/drivers/leds/leds-pca955x.c
index 146c069..f508729 100644
--- a/drivers/leds/leds-pca955x.c
+++ b/drivers/leds/leds-pca955x.c
@@ -248,11 +248,10 @@
 					const struct i2c_device_id *id)
 {
 	struct pca955x_led *pca955x;
-	int i;
-	int err = -ENODEV;
 	struct pca955x_chipdef *chip;
 	struct i2c_adapter *adapter;
 	struct led_platform_data *pdata;
+	int i, err;
 
 	chip = &pca955x_chipdefs[id->driver_data];
 	adapter = to_i2c_adapter(client->dev.parent);
@@ -282,43 +281,41 @@
 		}
 	}
 
-	for (i = 0; i < chip->bits; i++) {
-		pca955x = kzalloc(sizeof(struct pca955x_led), GFP_KERNEL);
-		if (!pca955x) {
-			err = -ENOMEM;
-			goto exit;
-		}
+	pca955x = kzalloc(sizeof(*pca955x) * chip->bits, GFP_KERNEL);
+	if (!pca955x)
+		return -ENOMEM;
 
-		pca955x->chipdef = chip;
-		pca955x->client = client;
-		pca955x->led_num = i;
+	i2c_set_clientdata(client, pca955x);
+
+	for (i = 0; i < chip->bits; i++) {
+		pca955x[i].chipdef = chip;
+		pca955x[i].client = client;
+		pca955x[i].led_num = i;
+
 		/* Platform data can specify LED names and default triggers */
 		if (pdata) {
 			if (pdata->leds[i].name)
-				snprintf(pca955x->name, 32, "pca955x:%s",
-							pdata->leds[i].name);
+				snprintf(pca955x[i].name,
+					 sizeof(pca955x[i].name), "pca955x:%s",
+					 pdata->leds[i].name);
 			if (pdata->leds[i].default_trigger)
-				pca955x->led_cdev.default_trigger =
+				pca955x[i].led_cdev.default_trigger =
 					pdata->leds[i].default_trigger;
 		} else {
-			snprintf(pca955x->name, 32, "pca955x:%d", i);
+			snprintf(pca955x[i].name, sizeof(pca955x[i].name),
+				 "pca955x:%d", i);
 		}
-		spin_lock_init(&pca955x->lock);
 
-		pca955x->led_cdev.name = pca955x->name;
-		pca955x->led_cdev.brightness_set =
-				pca955x_led_set;
+		spin_lock_init(&pca955x[i].lock);
 
-		/*
-		 * Client data is a pointer to the _first_ pca955x_led
-		 * struct
-		 */
-		if (i == 0)
-			i2c_set_clientdata(client, pca955x);
+		pca955x[i].led_cdev.name = pca955x[i].name;
+		pca955x[i].led_cdev.brightness_set = pca955x_led_set;
 
-		INIT_WORK(&(pca955x->work), pca955x_led_work);
+		INIT_WORK(&pca955x[i].work, pca955x_led_work);
 
-		led_classdev_register(&client->dev, &(pca955x->led_cdev));
+		err = led_classdev_register(&client->dev, &pca955x[i].led_cdev);
+		if (err < 0)
+			goto exit;
 	}
 
 	/* Turn off LEDs */
@@ -336,23 +333,32 @@
 	pca955x_write_psc(client, 1, 0);
 
 	return 0;
+
 exit:
+	while (i--) {
+		led_classdev_unregister(&pca955x[i].led_cdev);
+		cancel_work_sync(&pca955x[i].work);
+	}
+
+	kfree(pca955x);
+	i2c_set_clientdata(client, NULL);
+
 	return err;
 }
 
 static int __devexit pca955x_remove(struct i2c_client *client)
 {
 	struct pca955x_led *pca955x = i2c_get_clientdata(client);
-	int leds = pca955x->chipdef->bits;
 	int i;
 
-	for (i = 0; i < leds; i++) {
-		led_classdev_unregister(&(pca955x->led_cdev));
-		cancel_work_sync(&(pca955x->work));
-		kfree(pca955x);
-		pca955x = pca955x + 1;
+	for (i = 0; i < pca955x->chipdef->bits; i++) {
+		led_classdev_unregister(&pca955x[i].led_cdev);
+		cancel_work_sync(&pca955x[i].work);
 	}
 
+	kfree(pca955x);
+	i2c_set_clientdata(client, NULL);
+
 	return 0;
 }
 
diff --git a/drivers/leds/leds-spitz.c b/drivers/leds/leds-spitz.c
deleted file mode 100644
index 178831c..0000000
--- a/drivers/leds/leds-spitz.c
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * LED Triggers Core
- *
- * Copyright 2005-2006 Openedhand Ltd.
- *
- * Author: Richard Purdie <rpurdie@openedhand.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/kernel.h>
-#include <linux/init.h>
-#include <linux/platform_device.h>
-#include <linux/leds.h>
-#include <asm/hardware/scoop.h>
-#include <asm/mach-types.h>
-#include <mach/hardware.h>
-#include <mach/pxa-regs.h>
-#include <mach/spitz.h>
-
-static void spitzled_amber_set(struct led_classdev *led_cdev,
-			       enum led_brightness value)
-{
-	if (value)
-		set_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_LED_ORANGE);
-	else
-		reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_LED_ORANGE);
-}
-
-static void spitzled_green_set(struct led_classdev *led_cdev,
-			       enum led_brightness value)
-{
-	if (value)
-		set_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_LED_GREEN);
-	else
-		reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_LED_GREEN);
-}
-
-static struct led_classdev spitz_amber_led = {
-	.name			= "spitz:amber:charge",
-	.default_trigger	= "sharpsl-charge",
-	.brightness_set		= spitzled_amber_set,
-};
-
-static struct led_classdev spitz_green_led = {
-	.name			= "spitz:green:hddactivity",
-	.default_trigger	= "ide-disk",
-	.brightness_set		= spitzled_green_set,
-};
-
-#ifdef CONFIG_PM
-static int spitzled_suspend(struct platform_device *dev, pm_message_t state)
-{
-#ifdef CONFIG_LEDS_TRIGGERS
-	if (spitz_amber_led.trigger &&
-	    strcmp(spitz_amber_led.trigger->name, "sharpsl-charge"))
-#endif
-		led_classdev_suspend(&spitz_amber_led);
-	led_classdev_suspend(&spitz_green_led);
-	return 0;
-}
-
-static int spitzled_resume(struct platform_device *dev)
-{
-	led_classdev_resume(&spitz_amber_led);
-	led_classdev_resume(&spitz_green_led);
-	return 0;
-}
-#endif
-
-static int spitzled_probe(struct platform_device *pdev)
-{
-	int ret;
-
-	if (machine_is_akita()) {
-		spitz_green_led.name = "spitz:green:mail";
-		spitz_green_led.default_trigger = "nand-disk";
-	}
-
-	ret = led_classdev_register(&pdev->dev, &spitz_amber_led);
-	if (ret < 0)
-		return ret;
-
-	ret = led_classdev_register(&pdev->dev, &spitz_green_led);
-	if (ret < 0)
-		led_classdev_unregister(&spitz_amber_led);
-
-	return ret;
-}
-
-static int spitzled_remove(struct platform_device *pdev)
-{
-	led_classdev_unregister(&spitz_amber_led);
-	led_classdev_unregister(&spitz_green_led);
-
-	return 0;
-}
-
-static struct platform_driver spitzled_driver = {
-	.probe		= spitzled_probe,
-	.remove		= spitzled_remove,
-#ifdef CONFIG_PM
-	.suspend	= spitzled_suspend,
-	.resume		= spitzled_resume,
-#endif
-	.driver		= {
-		.name		= "spitz-led",
-		.owner		= THIS_MODULE,
-	},
-};
-
-static int __init spitzled_init(void)
-{
-	return platform_driver_register(&spitzled_driver);
-}
-
-static void __exit spitzled_exit(void)
-{
-	platform_driver_unregister(&spitzled_driver);
-}
-
-module_init(spitzled_init);
-module_exit(spitzled_exit);
-
-MODULE_AUTHOR("Richard Purdie <rpurdie@openedhand.com>");
-MODULE_DESCRIPTION("Spitz LED driver");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:spitz-led");
diff --git a/drivers/leds/leds-sunfire.c b/drivers/leds/leds-sunfire.c
new file mode 100644
index 0000000..6b008f0
--- /dev/null
+++ b/drivers/leds/leds-sunfire.c
@@ -0,0 +1,273 @@
+/* leds-sunfire.c: SUNW,Ultra-Enterprise LED driver.
+ *
+ * Copyright (C) 2008 David S. Miller <davem@davemloft.net>
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/leds.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+
+#include <asm/fhc.h>
+#include <asm/upa.h>
+
+#define DRIVER_NAME	"leds-sunfire"
+#define PFX		DRIVER_NAME ": "
+
+MODULE_AUTHOR("David S. Miller (davem@davemloft.net)");
+MODULE_DESCRIPTION("Sun Fire LED driver");
+MODULE_LICENSE("GPL");
+
+struct sunfire_led {
+	struct led_classdev	led_cdev;
+	void __iomem		*reg;
+};
+#define	to_sunfire_led(d) container_of(d, struct sunfire_led, led_cdev)
+
+static void __clockboard_set(struct led_classdev *led_cdev,
+			     enum led_brightness led_val, u8 bit)
+{
+	struct sunfire_led *p = to_sunfire_led(led_cdev);
+	u8 reg = upa_readb(p->reg);
+
+	switch (bit) {
+	case CLOCK_CTRL_LLED:
+		if (led_val)
+			reg &= ~bit;
+		else
+			reg |= bit;
+		break;
+
+	default:
+		if (led_val)
+			reg |= bit;
+		else
+			reg &= ~bit;
+		break;
+	}
+	upa_writeb(reg, p->reg);
+}
+
+static void clockboard_left_set(struct led_classdev *led_cdev,
+				enum led_brightness led_val)
+{
+	__clockboard_set(led_cdev, led_val, CLOCK_CTRL_LLED);
+}
+
+static void clockboard_middle_set(struct led_classdev *led_cdev,
+				  enum led_brightness led_val)
+{
+	__clockboard_set(led_cdev, led_val, CLOCK_CTRL_MLED);
+}
+
+static void clockboard_right_set(struct led_classdev *led_cdev,
+				 enum led_brightness led_val)
+{
+	__clockboard_set(led_cdev, led_val, CLOCK_CTRL_RLED);
+}
+
+static void __fhc_set(struct led_classdev *led_cdev,
+			     enum led_brightness led_val, u32 bit)
+{
+	struct sunfire_led *p = to_sunfire_led(led_cdev);
+	u32 reg = upa_readl(p->reg);
+
+	switch (bit) {
+	case FHC_CONTROL_LLED:
+		if (led_val)
+			reg &= ~bit;
+		else
+			reg |= bit;
+		break;
+
+	default:
+		if (led_val)
+			reg |= bit;
+		else
+			reg &= ~bit;
+		break;
+	}
+	upa_writel(reg, p->reg);
+}
+
+static void fhc_left_set(struct led_classdev *led_cdev,
+			 enum led_brightness led_val)
+{
+	__fhc_set(led_cdev, led_val, FHC_CONTROL_LLED);
+}
+
+static void fhc_middle_set(struct led_classdev *led_cdev,
+			   enum led_brightness led_val)
+{
+	__fhc_set(led_cdev, led_val, FHC_CONTROL_MLED);
+}
+
+static void fhc_right_set(struct led_classdev *led_cdev,
+			  enum led_brightness led_val)
+{
+	__fhc_set(led_cdev, led_val, FHC_CONTROL_RLED);
+}
+
+typedef void (*set_handler)(struct led_classdev *, enum led_brightness);
+struct led_type {
+	const char	*name;
+	set_handler	handler;
+	const char	*default_trigger;
+};
+
+#define NUM_LEDS_PER_BOARD	3
+struct sunfire_drvdata {
+	struct sunfire_led	leds[NUM_LEDS_PER_BOARD];
+};
+
+static int __devinit sunfire_led_generic_probe(struct platform_device *pdev,
+					       struct led_type *types)
+{
+	struct sunfire_drvdata *p;
+	int i, err = -EINVAL;
+
+	if (pdev->num_resources != 1) {
+		printk(KERN_ERR PFX "Wrong number of resources %d, should be 1\n",
+		       pdev->num_resources);
+		goto out;
+	}
+
+	p = kzalloc(sizeof(*p), GFP_KERNEL);
+	if (!p) {
+		printk(KERN_ERR PFX "Could not allocate struct sunfire_drvdata\n");
+		goto out;
+	}
+
+	for (i = 0; i < NUM_LEDS_PER_BOARD; i++) {
+		struct led_classdev *lp = &p->leds[i].led_cdev;
+
+		p->leds[i].reg = (void __iomem *) pdev->resource[0].start;
+		lp->name = types[i].name;
+		lp->brightness = LED_FULL;
+		lp->brightness_set = types[i].handler;
+		lp->default_trigger = types[i].default_trigger;
+
+		err = led_classdev_register(&pdev->dev, lp);
+		if (err) {
+			printk(KERN_ERR PFX "Could not register %s LED\n",
+			       lp->name);
+			goto out_unregister_led_cdevs;
+		}
+	}
+
+	dev_set_drvdata(&pdev->dev, p);
+
+	err = 0;
+out:
+	return err;
+
+out_unregister_led_cdevs:
+	for (i--; i >= 0; i--)
+		led_classdev_unregister(&p->leds[i].led_cdev);
+	goto out;
+}
+
+static int __devexit sunfire_led_generic_remove(struct platform_device *pdev)
+{
+	struct sunfire_drvdata *p = dev_get_drvdata(&pdev->dev);
+	int i;
+
+	for (i = 0; i < NUM_LEDS_PER_BOARD; i++)
+		led_classdev_unregister(&p->leds[i].led_cdev);
+
+	kfree(p);
+
+	return 0;
+}
+
+static struct led_type clockboard_led_types[NUM_LEDS_PER_BOARD] = {
+	{
+		.name		= "clockboard-left",
+		.handler	= clockboard_left_set,
+	},
+	{
+		.name		= "clockboard-middle",
+		.handler	= clockboard_middle_set,
+	},
+	{
+		.name		= "clockboard-right",
+		.handler	= clockboard_right_set,
+		.default_trigger= "heartbeat",
+	},
+};
+
+static int __devinit sunfire_clockboard_led_probe(struct platform_device *pdev)
+{
+	return sunfire_led_generic_probe(pdev, clockboard_led_types);
+}
+
+static struct led_type fhc_led_types[NUM_LEDS_PER_BOARD] = {
+	{
+		.name		= "fhc-left",
+		.handler	= fhc_left_set,
+	},
+	{
+		.name		= "fhc-middle",
+		.handler	= fhc_middle_set,
+	},
+	{
+		.name		= "fhc-right",
+		.handler	= fhc_right_set,
+		.default_trigger= "heartbeat",
+	},
+};
+
+static int __devinit sunfire_fhc_led_probe(struct platform_device *pdev)
+{
+	return sunfire_led_generic_probe(pdev, fhc_led_types);
+}
+
+MODULE_ALIAS("platform:sunfire-clockboard-leds");
+MODULE_ALIAS("platform:sunfire-fhc-leds");
+
+static struct platform_driver sunfire_clockboard_led_driver = {
+	.probe		= sunfire_clockboard_led_probe,
+	.remove		= __devexit_p(sunfire_led_generic_remove),
+	.driver		= {
+		.name	= "sunfire-clockboard-leds",
+		.owner	= THIS_MODULE,
+	},
+};
+
+static struct platform_driver sunfire_fhc_led_driver = {
+	.probe		= sunfire_fhc_led_probe,
+	.remove		= __devexit_p(sunfire_led_generic_remove),
+	.driver		= {
+		.name	= "sunfire-fhc-leds",
+		.owner	= THIS_MODULE,
+	},
+};
+
+static int __init sunfire_leds_init(void)
+{
+	int err = platform_driver_register(&sunfire_clockboard_led_driver);
+
+	if (err) {
+		printk(KERN_ERR PFX "Could not register clock board LED driver\n");
+		return err;
+	}
+
+	err = platform_driver_register(&sunfire_fhc_led_driver);
+	if (err) {
+		printk(KERN_ERR PFX "Could not register FHC LED driver\n");
+		platform_driver_unregister(&sunfire_clockboard_led_driver);
+	}
+
+	return err;
+}
+
+static void __exit sunfire_leds_exit(void)
+{
+	platform_driver_unregister(&sunfire_clockboard_led_driver);
+	platform_driver_unregister(&sunfire_fhc_led_driver);
+}
+
+module_init(sunfire_leds_init);
+module_exit(sunfire_leds_exit);
diff --git a/drivers/md/Kconfig b/drivers/md/Kconfig
index 07d92c1..2281b50 100644
--- a/drivers/md/Kconfig
+++ b/drivers/md/Kconfig
@@ -30,6 +30,20 @@
 
 	  If unsure, say N.
 
+config MD_AUTODETECT
+	bool "Autodetect RAID arrays during kernel boot"
+	depends on BLK_DEV_MD=y
+	default y
+	---help---
+	  If you say Y here, then the kernel will try to autodetect raid
+	  arrays as part of its boot process. 
+
+	  If you don't use raid and say Y, this autodetection can cause 
+	  a several-second delay in the boot time due to various
+	  synchronisation steps that are part of this step.
+
+	  If unsure, say Y.
+
 config MD_LINEAR
 	tristate "Linear (append) mode"
 	depends on BLK_DEV_MD
diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c
index 1395643..682ef9e 100644
--- a/drivers/md/dm-crypt.c
+++ b/drivers/md/dm-crypt.c
@@ -333,7 +333,6 @@
 	ctx->idx_out = bio_out ? bio_out->bi_idx : 0;
 	ctx->sector = sector + cc->iv_offset;
 	init_completion(&ctx->restart);
-	atomic_set(&ctx->pending, 1);
 }
 
 static int crypt_convert_block(struct crypt_config *cc,
@@ -408,6 +407,8 @@
 {
 	int r;
 
+	atomic_set(&ctx->pending, 1);
+
 	while(ctx->idx_in < ctx->bio_in->bi_vcnt &&
 	      ctx->idx_out < ctx->bio_out->bi_vcnt) {
 
@@ -456,9 +457,11 @@
 /*
  * Generate a new unfragmented bio with the given size
  * This should never violate the device limitations
- * May return a smaller bio when running out of pages
+ * May return a smaller bio when running out of pages, indicated by
+ * *out_of_pages set to 1.
  */
-static struct bio *crypt_alloc_buffer(struct dm_crypt_io *io, unsigned size)
+static struct bio *crypt_alloc_buffer(struct dm_crypt_io *io, unsigned size,
+				      unsigned *out_of_pages)
 {
 	struct crypt_config *cc = io->target->private;
 	struct bio *clone;
@@ -472,11 +475,14 @@
 		return NULL;
 
 	clone_init(io, clone);
+	*out_of_pages = 0;
 
 	for (i = 0; i < nr_iovecs; i++) {
 		page = mempool_alloc(cc->page_pool, gfp_mask);
-		if (!page)
+		if (!page) {
+			*out_of_pages = 1;
 			break;
+		}
 
 		/*
 		 * if additional pages cannot be allocated without waiting,
@@ -517,6 +523,27 @@
 	}
 }
 
+static struct dm_crypt_io *crypt_io_alloc(struct dm_target *ti,
+					  struct bio *bio, sector_t sector)
+{
+	struct crypt_config *cc = ti->private;
+	struct dm_crypt_io *io;
+
+	io = mempool_alloc(cc->io_pool, GFP_NOIO);
+	io->target = ti;
+	io->base_bio = bio;
+	io->sector = sector;
+	io->error = 0;
+	atomic_set(&io->pending, 0);
+
+	return io;
+}
+
+static void crypt_inc_pending(struct dm_crypt_io *io)
+{
+	atomic_inc(&io->pending);
+}
+
 /*
  * One of the bios was finished. Check for completion of
  * the whole request and correctly clean up the buffer.
@@ -591,7 +618,7 @@
 	struct bio *base_bio = io->base_bio;
 	struct bio *clone;
 
-	atomic_inc(&io->pending);
+	crypt_inc_pending(io);
 
 	/*
 	 * The block layer might modify the bvec array, so always
@@ -653,6 +680,7 @@
 		crypt_free_buffer_pages(cc, clone);
 		bio_put(clone);
 		io->error = -EIO;
+		crypt_dec_pending(io);
 		return;
 	}
 
@@ -664,28 +692,34 @@
 
 	if (async)
 		kcryptd_queue_io(io);
-	else {
-		atomic_inc(&io->pending);
+	else
 		generic_make_request(clone);
-	}
 }
 
-static void kcryptd_crypt_write_convert_loop(struct dm_crypt_io *io)
+static void kcryptd_crypt_write_convert(struct dm_crypt_io *io)
 {
 	struct crypt_config *cc = io->target->private;
 	struct bio *clone;
+	int crypt_finished;
+	unsigned out_of_pages = 0;
 	unsigned remaining = io->base_bio->bi_size;
 	int r;
 
 	/*
+	 * Prevent io from disappearing until this function completes.
+	 */
+	crypt_inc_pending(io);
+	crypt_convert_init(cc, &io->ctx, NULL, io->base_bio, io->sector);
+
+	/*
 	 * The allocated buffers can be smaller than the whole bio,
 	 * so repeat the whole process until all the data can be handled.
 	 */
 	while (remaining) {
-		clone = crypt_alloc_buffer(io, remaining);
+		clone = crypt_alloc_buffer(io, remaining, &out_of_pages);
 		if (unlikely(!clone)) {
 			io->error = -ENOMEM;
-			return;
+			break;
 		}
 
 		io->ctx.bio_out = clone;
@@ -693,37 +727,32 @@
 
 		remaining -= clone->bi_size;
 
+		crypt_inc_pending(io);
 		r = crypt_convert(cc, &io->ctx);
+		crypt_finished = atomic_dec_and_test(&io->ctx.pending);
 
-		if (atomic_dec_and_test(&io->ctx.pending)) {
-			/* processed, no running async crypto  */
+		/* Encryption was already finished, submit io now */
+		if (crypt_finished) {
 			kcryptd_crypt_write_io_submit(io, r, 0);
+
+			/*
+			 * If there was an error, do not try next fragments.
+			 * For async, error is processed in async handler.
+			 */
 			if (unlikely(r < 0))
-				return;
-		} else
-			atomic_inc(&io->pending);
-
-		/* out of memory -> run queues */
-		if (unlikely(remaining)) {
-			/* wait for async crypto then reinitialize pending */
-			wait_event(cc->writeq, !atomic_read(&io->ctx.pending));
-			atomic_set(&io->ctx.pending, 1);
-			congestion_wait(WRITE, HZ/100);
+				break;
 		}
+
+		/*
+		 * Out of memory -> run queues
+		 * But don't wait if split was due to the io size restriction
+		 */
+		if (unlikely(out_of_pages))
+			congestion_wait(WRITE, HZ/100);
+
+		if (unlikely(remaining))
+			wait_event(cc->writeq, !atomic_read(&io->ctx.pending));
 	}
-}
-
-static void kcryptd_crypt_write_convert(struct dm_crypt_io *io)
-{
-	struct crypt_config *cc = io->target->private;
-
-	/*
-	 * Prevent io from disappearing until this function completes.
-	 */
-	atomic_inc(&io->pending);
-
-	crypt_convert_init(cc, &io->ctx, NULL, io->base_bio, io->sector);
-	kcryptd_crypt_write_convert_loop(io);
 
 	crypt_dec_pending(io);
 }
@@ -741,7 +770,7 @@
 	struct crypt_config *cc = io->target->private;
 	int r = 0;
 
-	atomic_inc(&io->pending);
+	crypt_inc_pending(io);
 
 	crypt_convert_init(cc, &io->ctx, io->base_bio, io->base_bio,
 			   io->sector);
@@ -1108,15 +1137,9 @@
 static int crypt_map(struct dm_target *ti, struct bio *bio,
 		     union map_info *map_context)
 {
-	struct crypt_config *cc = ti->private;
 	struct dm_crypt_io *io;
 
-	io = mempool_alloc(cc->io_pool, GFP_NOIO);
-	io->target = ti;
-	io->base_bio = bio;
-	io->sector = bio->bi_sector - ti->begin;
-	io->error = 0;
-	atomic_set(&io->pending, 0);
+	io = crypt_io_alloc(ti, bio, bio->bi_sector - ti->begin);
 
 	if (bio_data_dir(io->base_bio) == READ)
 		kcryptd_queue_io(io);
diff --git a/drivers/md/dm-exception-store.c b/drivers/md/dm-exception-store.c
index 41f4080..769ab67 100644
--- a/drivers/md/dm-exception-store.c
+++ b/drivers/md/dm-exception-store.c
@@ -108,12 +108,12 @@
 	 * Used to keep track of which metadata area the data in
 	 * 'chunk' refers to.
 	 */
-	uint32_t current_area;
+	chunk_t current_area;
 
 	/*
 	 * The next free chunk for an exception.
 	 */
-	uint32_t next_free;
+	chunk_t next_free;
 
 	/*
 	 * The index of next free exception in the current
@@ -175,7 +175,7 @@
 /*
  * Read or write a chunk aligned and sized block of data from a device.
  */
-static int chunk_io(struct pstore *ps, uint32_t chunk, int rw, int metadata)
+static int chunk_io(struct pstore *ps, chunk_t chunk, int rw, int metadata)
 {
 	struct dm_io_region where = {
 		.bdev = ps->snap->cow->bdev,
@@ -209,16 +209,23 @@
 }
 
 /*
+ * Convert a metadata area index to a chunk index.
+ */
+static chunk_t area_location(struct pstore *ps, chunk_t area)
+{
+	return 1 + ((ps->exceptions_per_area + 1) * area);
+}
+
+/*
  * Read or write a metadata area.  Remembering to skip the first
  * chunk which holds the header.
  */
-static int area_io(struct pstore *ps, uint32_t area, int rw)
+static int area_io(struct pstore *ps, chunk_t area, int rw)
 {
 	int r;
-	uint32_t chunk;
+	chunk_t chunk;
 
-	/* convert a metadata area index to a chunk index */
-	chunk = 1 + ((ps->exceptions_per_area + 1) * area);
+	chunk = area_location(ps, area);
 
 	r = chunk_io(ps, chunk, rw, 0);
 	if (r)
@@ -228,7 +235,7 @@
 	return 0;
 }
 
-static int zero_area(struct pstore *ps, uint32_t area)
+static int zero_area(struct pstore *ps, chunk_t area)
 {
 	memset(ps->area, 0, ps->snap->chunk_size << SECTOR_SHIFT);
 	return area_io(ps, area, WRITE);
@@ -404,7 +411,7 @@
 
 static int read_exceptions(struct pstore *ps)
 {
-	uint32_t area;
+	chunk_t area;
 	int r, full = 1;
 
 	/*
@@ -517,6 +524,7 @@
 {
 	struct pstore *ps = get_info(store);
 	uint32_t stride;
+	chunk_t next_free;
 	sector_t size = get_dev_size(store->snap->cow->bdev);
 
 	/* Is there enough room ? */
@@ -530,7 +538,8 @@
 	 * into account the location of the metadata chunks.
 	 */
 	stride = (ps->exceptions_per_area + 1);
-	if ((++ps->next_free % stride) == 1)
+	next_free = ++ps->next_free;
+	if (sector_div(next_free, stride) == 1)
 		ps->next_free++;
 
 	atomic_inc(&ps->pending_count);
diff --git a/drivers/md/dm-ioctl.c b/drivers/md/dm-ioctl.c
index b262c00..dca401d 100644
--- a/drivers/md/dm-ioctl.c
+++ b/drivers/md/dm-ioctl.c
@@ -426,7 +426,7 @@
 				old_nl->next = (uint32_t) ((void *) nl -
 							   (void *) old_nl);
 			disk = dm_disk(hc->md);
-			nl->dev = huge_encode_dev(MKDEV(disk->major, disk->first_minor));
+			nl->dev = huge_encode_dev(disk_devt(disk));
 			nl->next = 0;
 			strcpy(nl->name, hc->name);
 
@@ -539,7 +539,7 @@
 	if (dm_suspended(md))
 		param->flags |= DM_SUSPEND_FLAG;
 
-	param->dev = huge_encode_dev(MKDEV(disk->major, disk->first_minor));
+	param->dev = huge_encode_dev(disk_devt(disk));
 
 	/*
 	 * Yes, this will be out of date by the time it gets back
@@ -548,7 +548,7 @@
 	 */
 	param->open_count = dm_open_count(md);
 
-	if (disk->policy)
+	if (get_disk_ro(disk))
 		param->flags |= DM_READONLY_FLAG;
 
 	param->event_nr = dm_get_event_nr(md);
@@ -1131,7 +1131,7 @@
 	unsigned int count = 0;
 	struct list_head *tmp;
 	size_t len, needed;
-	struct dm_dev *dd;
+	struct dm_dev_internal *dd;
 	struct dm_target_deps *deps;
 
 	deps = get_result_buffer(param, param_size, &len);
@@ -1157,7 +1157,7 @@
 	deps->count = count;
 	count = 0;
 	list_for_each_entry (dd, dm_table_get_devices(table), list)
-		deps->dev[count++] = huge_encode_dev(dd->bdev->bd_dev);
+		deps->dev[count++] = huge_encode_dev(dd->dm_dev.bdev->bd_dev);
 
 	param->data_size = param->data_start + needed;
 }
diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c
index 71dd65a..103304c 100644
--- a/drivers/md/dm-mpath.c
+++ b/drivers/md/dm-mpath.c
@@ -30,9 +30,11 @@
 	struct list_head list;
 
 	struct priority_group *pg;	/* Owning PG */
+	unsigned is_active;		/* Path status */
 	unsigned fail_count;		/* Cumulative failure count */
 
 	struct dm_path path;
+	struct work_struct deactivate_path;
 };
 
 #define path_to_pgpath(__pgp) container_of((__pgp), struct pgpath, path)
@@ -63,6 +65,7 @@
 
 	const char *hw_handler_name;
 	struct work_struct activate_path;
+	struct pgpath *pgpath_to_activate;
 	unsigned nr_priority_groups;
 	struct list_head priority_groups;
 	unsigned pg_init_required;	/* pg_init needs calling? */
@@ -111,6 +114,7 @@
 static void process_queued_ios(struct work_struct *work);
 static void trigger_event(struct work_struct *work);
 static void activate_path(struct work_struct *work);
+static void deactivate_path(struct work_struct *work);
 
 
 /*-----------------------------------------------
@@ -121,8 +125,10 @@
 {
 	struct pgpath *pgpath = kzalloc(sizeof(*pgpath), GFP_KERNEL);
 
-	if (pgpath)
-		pgpath->path.is_active = 1;
+	if (pgpath) {
+		pgpath->is_active = 1;
+		INIT_WORK(&pgpath->deactivate_path, deactivate_path);
+	}
 
 	return pgpath;
 }
@@ -132,6 +138,14 @@
 	kfree(pgpath);
 }
 
+static void deactivate_path(struct work_struct *work)
+{
+	struct pgpath *pgpath =
+		container_of(work, struct pgpath, deactivate_path);
+
+	blk_abort_queue(pgpath->path.dev->bdev->bd_disk->queue);
+}
+
 static struct priority_group *alloc_priority_group(void)
 {
 	struct priority_group *pg;
@@ -146,6 +160,7 @@
 
 static void free_pgpaths(struct list_head *pgpaths, struct dm_target *ti)
 {
+	unsigned long flags;
 	struct pgpath *pgpath, *tmp;
 	struct multipath *m = ti->private;
 
@@ -154,6 +169,10 @@
 		if (m->hw_handler_name)
 			scsi_dh_detach(bdev_get_queue(pgpath->path.dev->bdev));
 		dm_put_device(ti, pgpath->path.dev);
+		spin_lock_irqsave(&m->lock, flags);
+		if (m->pgpath_to_activate == pgpath)
+			m->pgpath_to_activate = NULL;
+		spin_unlock_irqrestore(&m->lock, flags);
 		free_pgpath(pgpath);
 	}
 }
@@ -421,6 +440,7 @@
 		__choose_pgpath(m);
 
 	pgpath = m->current_pgpath;
+	m->pgpath_to_activate = m->current_pgpath;
 
 	if ((pgpath && !m->queue_io) ||
 	    (!pgpath && !m->queue_if_no_path))
@@ -556,12 +576,12 @@
 	/* we need at least a path arg */
 	if (as->argc < 1) {
 		ti->error = "no device given";
-		return NULL;
+		return ERR_PTR(-EINVAL);
 	}
 
 	p = alloc_pgpath();
 	if (!p)
-		return NULL;
+		return ERR_PTR(-ENOMEM);
 
 	r = dm_get_device(ti, shift(as), ti->begin, ti->len,
 			  dm_table_get_mode(ti->table), &p->path.dev);
@@ -589,7 +609,7 @@
 
  bad:
 	free_pgpath(p);
-	return NULL;
+	return ERR_PTR(r);
 }
 
 static struct priority_group *parse_priority_group(struct arg_set *as,
@@ -607,14 +627,14 @@
 
 	if (as->argc < 2) {
 		as->argc = 0;
-		ti->error = "not enough priority group aruments";
-		return NULL;
+		ti->error = "not enough priority group arguments";
+		return ERR_PTR(-EINVAL);
 	}
 
 	pg = alloc_priority_group();
 	if (!pg) {
 		ti->error = "couldn't allocate priority group";
-		return NULL;
+		return ERR_PTR(-ENOMEM);
 	}
 	pg->m = m;
 
@@ -647,8 +667,10 @@
 		path_args.argv = as->argv;
 
 		pgpath = parse_path(&path_args, &pg->ps, ti);
-		if (!pgpath)
+		if (IS_ERR(pgpath)) {
+			r = PTR_ERR(pgpath);
 			goto bad;
+		}
 
 		pgpath->pg = pg;
 		list_add_tail(&pgpath->list, &pg->pgpaths);
@@ -659,7 +681,7 @@
 
  bad:
 	free_priority_group(pg, ti);
-	return NULL;
+	return ERR_PTR(r);
 }
 
 static int parse_hw_handler(struct arg_set *as, struct multipath *m)
@@ -778,8 +800,8 @@
 		struct priority_group *pg;
 
 		pg = parse_priority_group(&as, m);
-		if (!pg) {
-			r = -EINVAL;
+		if (IS_ERR(pg)) {
+			r = PTR_ERR(pg);
 			goto bad;
 		}
 
@@ -845,13 +867,13 @@
 
 	spin_lock_irqsave(&m->lock, flags);
 
-	if (!pgpath->path.is_active)
+	if (!pgpath->is_active)
 		goto out;
 
 	DMWARN("Failing path %s.", pgpath->path.dev->name);
 
 	pgpath->pg->ps.type->fail_path(&pgpath->pg->ps, &pgpath->path);
-	pgpath->path.is_active = 0;
+	pgpath->is_active = 0;
 	pgpath->fail_count++;
 
 	m->nr_valid_paths--;
@@ -863,6 +885,7 @@
 		      pgpath->path.dev->name, m->nr_valid_paths);
 
 	queue_work(kmultipathd, &m->trigger_event);
+	queue_work(kmultipathd, &pgpath->deactivate_path);
 
 out:
 	spin_unlock_irqrestore(&m->lock, flags);
@@ -881,7 +904,7 @@
 
 	spin_lock_irqsave(&m->lock, flags);
 
-	if (pgpath->path.is_active)
+	if (pgpath->is_active)
 		goto out;
 
 	if (!pgpath->pg->ps.type->reinstate_path) {
@@ -895,7 +918,7 @@
 	if (r)
 		goto out;
 
-	pgpath->path.is_active = 1;
+	pgpath->is_active = 1;
 
 	m->current_pgpath = NULL;
 	if (!m->nr_valid_paths++ && m->queue_size)
@@ -1093,8 +1116,15 @@
 	int ret;
 	struct multipath *m =
 		container_of(work, struct multipath, activate_path);
-	struct dm_path *path = &m->current_pgpath->path;
+	struct dm_path *path;
+	unsigned long flags;
 
+	spin_lock_irqsave(&m->lock, flags);
+	path = &m->pgpath_to_activate->path;
+	m->pgpath_to_activate = NULL;
+	spin_unlock_irqrestore(&m->lock, flags);
+	if (!path)
+		return;
 	ret = scsi_dh_activate(bdev_get_queue(path->dev->bdev));
 	pg_init_done(path, ret);
 }
@@ -1276,7 +1306,7 @@
 
 			list_for_each_entry(p, &pg->pgpaths, list) {
 				DMEMIT("%s %s %u ", p->path.dev->name,
-				       p->path.is_active ? "A" : "F",
+				       p->is_active ? "A" : "F",
 				       p->fail_count);
 				if (pg->ps.type->status)
 					sz += pg->ps.type->status(&pg->ps,
diff --git a/drivers/md/dm-mpath.h b/drivers/md/dm-mpath.h
index c198b85..e230f71 100644
--- a/drivers/md/dm-mpath.h
+++ b/drivers/md/dm-mpath.h
@@ -13,8 +13,6 @@
 
 struct dm_path {
 	struct dm_dev *dev;	/* Read-only */
-	unsigned is_active;	/* Read-only */
-
 	void *pscontext;	/* For path-selector use */
 };
 
diff --git a/drivers/md/dm-raid1.c b/drivers/md/dm-raid1.c
index ff05fe8..29913e4 100644
--- a/drivers/md/dm-raid1.c
+++ b/drivers/md/dm-raid1.c
@@ -842,7 +842,9 @@
 	}
 
 	/* hand to kcopyd */
-	set_bit(DM_KCOPYD_IGNORE_ERROR, &flags);
+	if (!errors_handled(ms))
+		set_bit(DM_KCOPYD_IGNORE_ERROR, &flags);
+
 	r = dm_kcopyd_copy(ms->kcopyd_client, &from, ms->nr_mirrors - 1, to,
 			   flags, recovery_complete, reg);
 
diff --git a/drivers/md/dm-stripe.c b/drivers/md/dm-stripe.c
index 4de90ab..b745d8a 100644
--- a/drivers/md/dm-stripe.c
+++ b/drivers/md/dm-stripe.c
@@ -284,8 +284,8 @@
 
 	memset(major_minor, 0, sizeof(major_minor));
 	sprintf(major_minor, "%d:%d",
-		bio->bi_bdev->bd_disk->major,
-		bio->bi_bdev->bd_disk->first_minor);
+		MAJOR(disk_devt(bio->bi_bdev->bd_disk)),
+		MINOR(disk_devt(bio->bi_bdev->bd_disk)));
 
 	/*
 	 * Test to see which stripe drive triggered the event
diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c
index 61f4414..a740a69 100644
--- a/drivers/md/dm-table.c
+++ b/drivers/md/dm-table.c
@@ -250,7 +250,8 @@
 	struct list_head *tmp, *next;
 
 	list_for_each_safe(tmp, next, devices) {
-		struct dm_dev *dd = list_entry(tmp, struct dm_dev, list);
+		struct dm_dev_internal *dd =
+		    list_entry(tmp, struct dm_dev_internal, list);
 		kfree(dd);
 	}
 }
@@ -327,12 +328,12 @@
 /*
  * See if we've already got a device in the list.
  */
-static struct dm_dev *find_device(struct list_head *l, dev_t dev)
+static struct dm_dev_internal *find_device(struct list_head *l, dev_t dev)
 {
-	struct dm_dev *dd;
+	struct dm_dev_internal *dd;
 
 	list_for_each_entry (dd, l, list)
-		if (dd->bdev->bd_dev == dev)
+		if (dd->dm_dev.bdev->bd_dev == dev)
 			return dd;
 
 	return NULL;
@@ -341,45 +342,47 @@
 /*
  * Open a device so we can use it as a map destination.
  */
-static int open_dev(struct dm_dev *d, dev_t dev, struct mapped_device *md)
+static int open_dev(struct dm_dev_internal *d, dev_t dev,
+		    struct mapped_device *md)
 {
 	static char *_claim_ptr = "I belong to device-mapper";
 	struct block_device *bdev;
 
 	int r;
 
-	BUG_ON(d->bdev);
+	BUG_ON(d->dm_dev.bdev);
 
-	bdev = open_by_devnum(dev, d->mode);
+	bdev = open_by_devnum(dev, d->dm_dev.mode);
 	if (IS_ERR(bdev))
 		return PTR_ERR(bdev);
 	r = bd_claim_by_disk(bdev, _claim_ptr, dm_disk(md));
 	if (r)
 		blkdev_put(bdev);
 	else
-		d->bdev = bdev;
+		d->dm_dev.bdev = bdev;
 	return r;
 }
 
 /*
  * Close a device that we've been using.
  */
-static void close_dev(struct dm_dev *d, struct mapped_device *md)
+static void close_dev(struct dm_dev_internal *d, struct mapped_device *md)
 {
-	if (!d->bdev)
+	if (!d->dm_dev.bdev)
 		return;
 
-	bd_release_from_disk(d->bdev, dm_disk(md));
-	blkdev_put(d->bdev);
-	d->bdev = NULL;
+	bd_release_from_disk(d->dm_dev.bdev, dm_disk(md));
+	blkdev_put(d->dm_dev.bdev);
+	d->dm_dev.bdev = NULL;
 }
 
 /*
  * If possible, this checks an area of a destination device is valid.
  */
-static int check_device_area(struct dm_dev *dd, sector_t start, sector_t len)
+static int check_device_area(struct dm_dev_internal *dd, sector_t start,
+			     sector_t len)
 {
-	sector_t dev_size = dd->bdev->bd_inode->i_size >> SECTOR_SHIFT;
+	sector_t dev_size = dd->dm_dev.bdev->bd_inode->i_size >> SECTOR_SHIFT;
 
 	if (!dev_size)
 		return 1;
@@ -392,16 +395,17 @@
  * careful to leave things as they were if we fail to reopen the
  * device.
  */
-static int upgrade_mode(struct dm_dev *dd, int new_mode, struct mapped_device *md)
+static int upgrade_mode(struct dm_dev_internal *dd, int new_mode,
+			struct mapped_device *md)
 {
 	int r;
-	struct dm_dev dd_copy;
-	dev_t dev = dd->bdev->bd_dev;
+	struct dm_dev_internal dd_copy;
+	dev_t dev = dd->dm_dev.bdev->bd_dev;
 
 	dd_copy = *dd;
 
-	dd->mode |= new_mode;
-	dd->bdev = NULL;
+	dd->dm_dev.mode |= new_mode;
+	dd->dm_dev.bdev = NULL;
 	r = open_dev(dd, dev, md);
 	if (!r)
 		close_dev(&dd_copy, md);
@@ -421,7 +425,7 @@
 {
 	int r;
 	dev_t uninitialized_var(dev);
-	struct dm_dev *dd;
+	struct dm_dev_internal *dd;
 	unsigned int major, minor;
 
 	BUG_ON(!t);
@@ -443,20 +447,20 @@
 		if (!dd)
 			return -ENOMEM;
 
-		dd->mode = mode;
-		dd->bdev = NULL;
+		dd->dm_dev.mode = mode;
+		dd->dm_dev.bdev = NULL;
 
 		if ((r = open_dev(dd, dev, t->md))) {
 			kfree(dd);
 			return r;
 		}
 
-		format_dev_t(dd->name, dev);
+		format_dev_t(dd->dm_dev.name, dev);
 
 		atomic_set(&dd->count, 0);
 		list_add(&dd->list, &t->devices);
 
-	} else if (dd->mode != (mode | dd->mode)) {
+	} else if (dd->dm_dev.mode != (mode | dd->dm_dev.mode)) {
 		r = upgrade_mode(dd, mode, t->md);
 		if (r)
 			return r;
@@ -465,11 +469,11 @@
 
 	if (!check_device_area(dd, start, len)) {
 		DMWARN("device %s too small for target", path);
-		dm_put_device(ti, dd);
+		dm_put_device(ti, &dd->dm_dev);
 		return -EINVAL;
 	}
 
-	*result = dd;
+	*result = &dd->dm_dev;
 
 	return 0;
 }
@@ -478,6 +482,13 @@
 {
 	struct request_queue *q = bdev_get_queue(bdev);
 	struct io_restrictions *rs = &ti->limits;
+	char b[BDEVNAME_SIZE];
+
+	if (unlikely(!q)) {
+		DMWARN("%s: Cannot set limits for nonexistent device %s",
+		       dm_device_name(ti->table->md), bdevname(bdev, b));
+		return;
+	}
 
 	/*
 	 * Combine the device limits low.
@@ -540,8 +551,11 @@
 /*
  * Decrement a devices use count and remove it if necessary.
  */
-void dm_put_device(struct dm_target *ti, struct dm_dev *dd)
+void dm_put_device(struct dm_target *ti, struct dm_dev *d)
 {
+	struct dm_dev_internal *dd = container_of(d, struct dm_dev_internal,
+						  dm_dev);
+
 	if (atomic_dec_and_test(&dd->count)) {
 		close_dev(dd, ti->table->md);
 		list_del(&dd->list);
@@ -937,13 +951,20 @@
 
 int dm_table_any_congested(struct dm_table *t, int bdi_bits)
 {
-	struct dm_dev *dd;
+	struct dm_dev_internal *dd;
 	struct list_head *devices = dm_table_get_devices(t);
 	int r = 0;
 
 	list_for_each_entry(dd, devices, list) {
-		struct request_queue *q = bdev_get_queue(dd->bdev);
-		r |= bdi_congested(&q->backing_dev_info, bdi_bits);
+		struct request_queue *q = bdev_get_queue(dd->dm_dev.bdev);
+		char b[BDEVNAME_SIZE];
+
+		if (likely(q))
+			r |= bdi_congested(&q->backing_dev_info, bdi_bits);
+		else
+			DMWARN_LIMIT("%s: any_congested: nonexistent device %s",
+				     dm_device_name(t->md),
+				     bdevname(dd->dm_dev.bdev, b));
 	}
 
 	return r;
@@ -951,13 +972,19 @@
 
 void dm_table_unplug_all(struct dm_table *t)
 {
-	struct dm_dev *dd;
+	struct dm_dev_internal *dd;
 	struct list_head *devices = dm_table_get_devices(t);
 
 	list_for_each_entry(dd, devices, list) {
-		struct request_queue *q = bdev_get_queue(dd->bdev);
+		struct request_queue *q = bdev_get_queue(dd->dm_dev.bdev);
+		char b[BDEVNAME_SIZE];
 
-		blk_unplug(q);
+		if (likely(q))
+			blk_unplug(q);
+		else
+			DMWARN_LIMIT("%s: Cannot unplug nonexistent device %s",
+				     dm_device_name(t->md),
+				     bdevname(dd->dm_dev.bdev, b));
 	}
 }
 
diff --git a/drivers/md/dm.c b/drivers/md/dm.c
index bca448e..327de03 100644
--- a/drivers/md/dm.c
+++ b/drivers/md/dm.c
@@ -377,13 +377,14 @@
 static void start_io_acct(struct dm_io *io)
 {
 	struct mapped_device *md = io->md;
+	int cpu;
 
 	io->start_time = jiffies;
 
-	preempt_disable();
-	disk_round_stats(dm_disk(md));
-	preempt_enable();
-	dm_disk(md)->in_flight = atomic_inc_return(&md->pending);
+	cpu = part_stat_lock();
+	part_round_stats(cpu, &dm_disk(md)->part0);
+	part_stat_unlock();
+	dm_disk(md)->part0.in_flight = atomic_inc_return(&md->pending);
 }
 
 static int end_io_acct(struct dm_io *io)
@@ -391,15 +392,16 @@
 	struct mapped_device *md = io->md;
 	struct bio *bio = io->bio;
 	unsigned long duration = jiffies - io->start_time;
-	int pending;
+	int pending, cpu;
 	int rw = bio_data_dir(bio);
 
-	preempt_disable();
-	disk_round_stats(dm_disk(md));
-	preempt_enable();
-	dm_disk(md)->in_flight = pending = atomic_dec_return(&md->pending);
+	cpu = part_stat_lock();
+	part_round_stats(cpu, &dm_disk(md)->part0);
+	part_stat_add(cpu, &dm_disk(md)->part0, ticks[rw], duration);
+	part_stat_unlock();
 
-	disk_stat_add(dm_disk(md), ticks[rw], duration);
+	dm_disk(md)->part0.in_flight = pending =
+		atomic_dec_return(&md->pending);
 
 	return !pending;
 }
@@ -837,12 +839,14 @@
 	struct dm_table *map = dm_get_table(md);
 	struct dm_target *ti;
 	sector_t max_sectors;
-	int max_size;
+	int max_size = 0;
 
 	if (unlikely(!map))
-		return 0;
+		goto out;
 
 	ti = dm_table_find_target(map, bvm->bi_sector);
+	if (!dm_target_is_valid(ti))
+		goto out_table;
 
 	/*
 	 * Find maximum amount of I/O that won't need splitting
@@ -861,14 +865,16 @@
 	if (max_size && ti->type->merge)
 		max_size = ti->type->merge(ti, bvm, biovec, max_size);
 
+out_table:
+	dm_table_put(map);
+
+out:
 	/*
 	 * Always allow an entire first page
 	 */
 	if (max_size <= biovec->bv_len && !(bvm->bi_size >> SECTOR_SHIFT))
 		max_size = biovec->bv_len;
 
-	dm_table_put(map);
-
 	return max_size;
 }
 
@@ -881,6 +887,7 @@
 	int r = -EIO;
 	int rw = bio_data_dir(bio);
 	struct mapped_device *md = q->queuedata;
+	int cpu;
 
 	/*
 	 * There is no use in forwarding any barrier request since we can't
@@ -893,8 +900,10 @@
 
 	down_read(&md->io_lock);
 
-	disk_stat_inc(dm_disk(md), ios[rw]);
-	disk_stat_add(dm_disk(md), sectors[rw], bio_sectors(bio));
+	cpu = part_stat_lock();
+	part_stat_inc(cpu, &dm_disk(md)->part0, ios[rw]);
+	part_stat_add(cpu, &dm_disk(md)->part0, sectors[rw], bio_sectors(bio));
+	part_stat_unlock();
 
 	/*
 	 * If we're suspended we have to queue
@@ -1142,7 +1151,7 @@
 
 static void free_dev(struct mapped_device *md)
 {
-	int minor = md->disk->first_minor;
+	int minor = MINOR(disk_devt(md->disk));
 
 	if (md->suspended_bdev) {
 		unlock_fs(md);
@@ -1178,7 +1187,7 @@
 	list_splice_init(&md->uevent_list, &uevents);
 	spin_unlock_irqrestore(&md->uevent_lock, flags);
 
-	dm_send_uevents(&uevents, &md->disk->dev.kobj);
+	dm_send_uevents(&uevents, &disk_to_dev(md->disk)->kobj);
 
 	atomic_inc(&md->event_nr);
 	wake_up(&md->eventq);
@@ -1263,7 +1272,7 @@
 
 	md = idr_find(&_minor_idr, minor);
 	if (md && (md == MINOR_ALLOCED ||
-		   (dm_disk(md)->first_minor != minor) ||
+		   (MINOR(disk_devt(dm_disk(md))) != minor) ||
 		   test_bit(DMF_FREEING, &md->flags))) {
 		md = NULL;
 		goto out;
@@ -1314,7 +1323,8 @@
 
 	if (atomic_dec_and_lock(&md->holders, &_minor_lock)) {
 		map = dm_get_table(md);
-		idr_replace(&_minor_idr, MINOR_ALLOCED, dm_disk(md)->first_minor);
+		idr_replace(&_minor_idr, MINOR_ALLOCED,
+			    MINOR(disk_devt(dm_disk(md))));
 		set_bit(DMF_FREEING, &md->flags);
 		spin_unlock(&_minor_lock);
 		if (!dm_suspended(md)) {
@@ -1634,7 +1644,7 @@
  *---------------------------------------------------------------*/
 void dm_kobject_uevent(struct mapped_device *md)
 {
-	kobject_uevent(&md->disk->dev.kobj, KOBJ_CHANGE);
+	kobject_uevent(&disk_to_dev(md->disk)->kobj, KOBJ_CHANGE);
 }
 
 uint32_t dm_next_uevent_seq(struct mapped_device *md)
diff --git a/drivers/md/dm.h b/drivers/md/dm.h
index 1e59a0b..cd189da 100644
--- a/drivers/md/dm.h
+++ b/drivers/md/dm.h
@@ -25,13 +25,10 @@
 /*
  * List of devices that a metadevice uses and should open/close.
  */
-struct dm_dev {
+struct dm_dev_internal {
 	struct list_head list;
-
 	atomic_t count;
-	int mode;
-	struct block_device *bdev;
-	char name[16];
+	struct dm_dev dm_dev;
 };
 
 struct dm_table;
@@ -49,7 +46,6 @@
 void dm_table_postsuspend_targets(struct dm_table *t);
 int dm_table_resume_targets(struct dm_table *t);
 int dm_table_any_congested(struct dm_table *t, int bdi_bits);
-void dm_table_unplug_all(struct dm_table *t);
 
 /*
  * To check the return value from dm_table_find_target().
@@ -93,8 +89,6 @@
 int dm_stripe_init(void);
 void dm_stripe_exit(void);
 
-void *dm_vcalloc(unsigned long nmemb, unsigned long elem_size);
-union map_info *dm_get_mapinfo(struct bio *bio);
 int dm_open_count(struct mapped_device *md);
 int dm_lock_for_deletion(struct mapped_device *md);
 
diff --git a/drivers/md/linear.c b/drivers/md/linear.c
index b1eebf8..b9cbee68 100644
--- a/drivers/md/linear.c
+++ b/drivers/md/linear.c
@@ -318,14 +318,18 @@
 	mddev_t *mddev = q->queuedata;
 	dev_info_t *tmp_dev;
 	sector_t block;
+	int cpu;
 
 	if (unlikely(bio_barrier(bio))) {
 		bio_endio(bio, -EOPNOTSUPP);
 		return 0;
 	}
 
-	disk_stat_inc(mddev->gendisk, ios[rw]);
-	disk_stat_add(mddev->gendisk, sectors[rw], bio_sectors(bio));
+	cpu = part_stat_lock();
+	part_stat_inc(cpu, &mddev->gendisk->part0, ios[rw]);
+	part_stat_add(cpu, &mddev->gendisk->part0, sectors[rw],
+		      bio_sectors(bio));
+	part_stat_unlock();
 
 	tmp_dev = which_dev(mddev, bio->bi_sector);
 	block = bio->bi_sector >> 1;
@@ -349,7 +353,7 @@
 		 * split it.
 		 */
 		struct bio_pair *bp;
-		bp = bio_split(bio, bio_split_pool,
+		bp = bio_split(bio,
 			       ((tmp_dev->offset + tmp_dev->size)<<1) - bio->bi_sector);
 		if (linear_make_request(q, &bp->bio1))
 			generic_make_request(&bp->bio1);
diff --git a/drivers/md/md.c b/drivers/md/md.c
index 4790c83..0a3a4bd 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -1464,10 +1464,7 @@
 	if ((err = kobject_add(&rdev->kobj, &mddev->kobj, "dev-%s", b)))
 		goto fail;
 
-	if (rdev->bdev->bd_part)
-		ko = &rdev->bdev->bd_part->dev.kobj;
-	else
-		ko = &rdev->bdev->bd_disk->dev.kobj;
+	ko = &part_to_dev(rdev->bdev->bd_part)->kobj;
 	if ((err = sysfs_create_link(&rdev->kobj, ko, "block"))) {
 		kobject_del(&rdev->kobj);
 		goto fail;
@@ -3470,8 +3467,8 @@
 	disk->queue = mddev->queue;
 	add_disk(disk);
 	mddev->gendisk = disk;
-	error = kobject_init_and_add(&mddev->kobj, &md_ktype, &disk->dev.kobj,
-				     "%s", "md");
+	error = kobject_init_and_add(&mddev->kobj, &md_ktype,
+				     &disk_to_dev(disk)->kobj, "%s", "md");
 	mutex_unlock(&disks_mutex);
 	if (error)
 		printk(KERN_WARNING "md: cannot register %s/md - name in use\n",
@@ -3761,7 +3758,7 @@
 	sysfs_notify(&mddev->kobj, NULL, "array_state");
 	sysfs_notify(&mddev->kobj, NULL, "sync_action");
 	sysfs_notify(&mddev->kobj, NULL, "degraded");
-	kobject_uevent(&mddev->gendisk->dev.kobj, KOBJ_CHANGE);
+	kobject_uevent(&disk_to_dev(mddev->gendisk)->kobj, KOBJ_CHANGE);
 	return 0;
 }
 
@@ -5549,8 +5546,8 @@
 	rcu_read_lock();
 	rdev_for_each_rcu(rdev, mddev) {
 		struct gendisk *disk = rdev->bdev->bd_contains->bd_disk;
-		curr_events = disk_stat_read(disk, sectors[0]) + 
-				disk_stat_read(disk, sectors[1]) - 
+		curr_events = part_stat_read(&disk->part0, sectors[0]) +
+				part_stat_read(&disk->part0, sectors[1]) -
 				atomic_read(&disk->sync_io);
 		/* sync IO will cause sync_io to increase before the disk_stats
 		 * as sync_io is counted when a request starts, and
@@ -5761,7 +5758,11 @@
 					 * time 'round when curr_resync == 2
 					 */
 					continue;
-				prepare_to_wait(&resync_wait, &wq, TASK_UNINTERRUPTIBLE);
+				/* We need to wait 'interruptible' so as not to
+				 * contribute to the load average, and not to
+				 * be caught by 'softlockup'
+				 */
+				prepare_to_wait(&resync_wait, &wq, TASK_INTERRUPTIBLE);
 				if (!kthread_should_stop() &&
 				    mddev2->curr_resync >= mddev->curr_resync) {
 					printk(KERN_INFO "md: delaying %s of %s"
@@ -5769,6 +5770,8 @@
 					       " share one or more physical units)\n",
 					       desc, mdname(mddev), mdname(mddev2));
 					mddev_put(mddev2);
+					if (signal_pending(current))
+						flush_signals(current);
 					schedule();
 					finish_wait(&resync_wait, &wq);
 					goto try_again;
diff --git a/drivers/md/multipath.c b/drivers/md/multipath.c
index c4779cc..8bb8794 100644
--- a/drivers/md/multipath.c
+++ b/drivers/md/multipath.c
@@ -147,6 +147,7 @@
 	struct multipath_bh * mp_bh;
 	struct multipath_info *multipath;
 	const int rw = bio_data_dir(bio);
+	int cpu;
 
 	if (unlikely(bio_barrier(bio))) {
 		bio_endio(bio, -EOPNOTSUPP);
@@ -158,8 +159,11 @@
 	mp_bh->master_bio = bio;
 	mp_bh->mddev = mddev;
 
-	disk_stat_inc(mddev->gendisk, ios[rw]);
-	disk_stat_add(mddev->gendisk, sectors[rw], bio_sectors(bio));
+	cpu = part_stat_lock();
+	part_stat_inc(cpu, &mddev->gendisk->part0, ios[rw]);
+	part_stat_add(cpu, &mddev->gendisk->part0, sectors[rw],
+		      bio_sectors(bio));
+	part_stat_unlock();
 
 	mp_bh->path = multipath_map(conf);
 	if (mp_bh->path < 0) {
diff --git a/drivers/md/raid0.c b/drivers/md/raid0.c
index 1836106..53508a8 100644
--- a/drivers/md/raid0.c
+++ b/drivers/md/raid0.c
@@ -399,14 +399,18 @@
 	sector_t chunk;
 	sector_t block, rsect;
 	const int rw = bio_data_dir(bio);
+	int cpu;
 
 	if (unlikely(bio_barrier(bio))) {
 		bio_endio(bio, -EOPNOTSUPP);
 		return 0;
 	}
 
-	disk_stat_inc(mddev->gendisk, ios[rw]);
-	disk_stat_add(mddev->gendisk, sectors[rw], bio_sectors(bio));
+	cpu = part_stat_lock();
+	part_stat_inc(cpu, &mddev->gendisk->part0, ios[rw]);
+	part_stat_add(cpu, &mddev->gendisk->part0, sectors[rw],
+		      bio_sectors(bio));
+	part_stat_unlock();
 
 	chunk_size = mddev->chunk_size >> 10;
 	chunk_sects = mddev->chunk_size >> 9;
@@ -423,7 +427,7 @@
 		/* This is a one page bio that upper layers
 		 * refuse to split for us, so we need to split it.
 		 */
-		bp = bio_split(bio, bio_split_pool, chunk_sects - (bio->bi_sector & (chunk_sects - 1)) );
+		bp = bio_split(bio, chunk_sects - (bio->bi_sector & (chunk_sects - 1)));
 		if (raid0_make_request(q, &bp->bio1))
 			generic_make_request(&bp->bio1);
 		if (raid0_make_request(q, &bp->bio2))
diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
index 03a5ab7..b976442 100644
--- a/drivers/md/raid1.c
+++ b/drivers/md/raid1.c
@@ -779,7 +779,7 @@
 	struct page **behind_pages = NULL;
 	const int rw = bio_data_dir(bio);
 	const int do_sync = bio_sync(bio);
-	int do_barriers;
+	int cpu, do_barriers;
 	mdk_rdev_t *blocked_rdev;
 
 	/*
@@ -804,8 +804,11 @@
 
 	bitmap = mddev->bitmap;
 
-	disk_stat_inc(mddev->gendisk, ios[rw]);
-	disk_stat_add(mddev->gendisk, sectors[rw], bio_sectors(bio));
+	cpu = part_stat_lock();
+	part_stat_inc(cpu, &mddev->gendisk->part0, ios[rw]);
+	part_stat_add(cpu, &mddev->gendisk->part0, sectors[rw],
+		      bio_sectors(bio));
+	part_stat_unlock();
 
 	/*
 	 * make_request() can abort the operation when READA is being
@@ -1302,9 +1305,6 @@
 					sbio->bi_size = r1_bio->sectors << 9;
 					sbio->bi_idx = 0;
 					sbio->bi_phys_segments = 0;
-					sbio->bi_hw_segments = 0;
-					sbio->bi_hw_front_size = 0;
-					sbio->bi_hw_back_size = 0;
 					sbio->bi_flags &= ~(BIO_POOL_MASK - 1);
 					sbio->bi_flags |= 1 << BIO_UPTODATE;
 					sbio->bi_next = NULL;
@@ -1790,7 +1790,6 @@
 		bio->bi_vcnt = 0;
 		bio->bi_idx = 0;
 		bio->bi_phys_segments = 0;
-		bio->bi_hw_segments = 0;
 		bio->bi_size = 0;
 		bio->bi_end_io = NULL;
 		bio->bi_private = NULL;
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
index e34cd0e..8bdc9bf 100644
--- a/drivers/md/raid10.c
+++ b/drivers/md/raid10.c
@@ -789,6 +789,7 @@
 	mirror_info_t *mirror;
 	r10bio_t *r10_bio;
 	struct bio *read_bio;
+	int cpu;
 	int i;
 	int chunk_sects = conf->chunk_mask + 1;
 	const int rw = bio_data_dir(bio);
@@ -816,7 +817,7 @@
 		/* This is a one page bio that upper layers
 		 * refuse to split for us, so we need to split it.
 		 */
-		bp = bio_split(bio, bio_split_pool,
+		bp = bio_split(bio,
 			       chunk_sects - (bio->bi_sector & (chunk_sects - 1)) );
 		if (make_request(q, &bp->bio1))
 			generic_make_request(&bp->bio1);
@@ -843,8 +844,11 @@
 	 */
 	wait_barrier(conf);
 
-	disk_stat_inc(mddev->gendisk, ios[rw]);
-	disk_stat_add(mddev->gendisk, sectors[rw], bio_sectors(bio));
+	cpu = part_stat_lock();
+	part_stat_inc(cpu, &mddev->gendisk->part0, ios[rw]);
+	part_stat_add(cpu, &mddev->gendisk->part0, sectors[rw],
+		      bio_sectors(bio));
+	part_stat_unlock();
 
 	r10_bio = mempool_alloc(conf->r10bio_pool, GFP_NOIO);
 
@@ -1345,9 +1349,6 @@
 		tbio->bi_size = r10_bio->sectors << 9;
 		tbio->bi_idx = 0;
 		tbio->bi_phys_segments = 0;
-		tbio->bi_hw_segments = 0;
-		tbio->bi_hw_front_size = 0;
-		tbio->bi_hw_back_size = 0;
 		tbio->bi_flags &= ~(BIO_POOL_MASK - 1);
 		tbio->bi_flags |= 1 << BIO_UPTODATE;
 		tbio->bi_next = NULL;
@@ -1947,7 +1948,6 @@
 		bio->bi_vcnt = 0;
 		bio->bi_idx = 0;
 		bio->bi_phys_segments = 0;
-		bio->bi_hw_segments = 0;
 		bio->bi_size = 0;
 	}
 
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
index 224de02..ae16794 100644
--- a/drivers/md/raid5.c
+++ b/drivers/md/raid5.c
@@ -101,6 +101,40 @@
 const char raid6_empty_zero_page[PAGE_SIZE] __attribute__((aligned(256)));
 #endif
 
+/*
+ * We maintain a biased count of active stripes in the bottom 16 bits of
+ * bi_phys_segments, and a count of processed stripes in the upper 16 bits
+ */
+static inline int raid5_bi_phys_segments(struct bio *bio)
+{
+	return bio->bi_phys_segments & 0xffff;
+}
+
+static inline int raid5_bi_hw_segments(struct bio *bio)
+{
+	return (bio->bi_phys_segments >> 16) & 0xffff;
+}
+
+static inline int raid5_dec_bi_phys_segments(struct bio *bio)
+{
+	--bio->bi_phys_segments;
+	return raid5_bi_phys_segments(bio);
+}
+
+static inline int raid5_dec_bi_hw_segments(struct bio *bio)
+{
+	unsigned short val = raid5_bi_hw_segments(bio);
+
+	--val;
+	bio->bi_phys_segments = (val << 16) | raid5_bi_phys_segments(bio);
+	return val;
+}
+
+static inline void raid5_set_bi_hw_segments(struct bio *bio, unsigned int cnt)
+{
+	bio->bi_phys_segments = raid5_bi_phys_segments(bio) || (cnt << 16);
+}
+
 static inline int raid6_next_disk(int disk, int raid_disks)
 {
 	disk++;
@@ -507,7 +541,7 @@
 			while (rbi && rbi->bi_sector <
 				dev->sector + STRIPE_SECTORS) {
 				rbi2 = r5_next_bio(rbi, dev->sector);
-				if (--rbi->bi_phys_segments == 0) {
+				if (!raid5_dec_bi_phys_segments(rbi)) {
 					rbi->bi_next = return_bi;
 					return_bi = rbi;
 				}
@@ -1725,7 +1759,7 @@
 	if (*bip)
 		bi->bi_next = *bip;
 	*bip = bi;
-	bi->bi_phys_segments ++;
+	bi->bi_phys_segments++;
 	spin_unlock_irq(&conf->device_lock);
 	spin_unlock(&sh->lock);
 
@@ -1819,7 +1853,7 @@
 			sh->dev[i].sector + STRIPE_SECTORS) {
 			struct bio *nextbi = r5_next_bio(bi, sh->dev[i].sector);
 			clear_bit(BIO_UPTODATE, &bi->bi_flags);
-			if (--bi->bi_phys_segments == 0) {
+			if (!raid5_dec_bi_phys_segments(bi)) {
 				md_write_end(conf->mddev);
 				bi->bi_next = *return_bi;
 				*return_bi = bi;
@@ -1834,7 +1868,7 @@
 		       sh->dev[i].sector + STRIPE_SECTORS) {
 			struct bio *bi2 = r5_next_bio(bi, sh->dev[i].sector);
 			clear_bit(BIO_UPTODATE, &bi->bi_flags);
-			if (--bi->bi_phys_segments == 0) {
+			if (!raid5_dec_bi_phys_segments(bi)) {
 				md_write_end(conf->mddev);
 				bi->bi_next = *return_bi;
 				*return_bi = bi;
@@ -1858,7 +1892,7 @@
 				struct bio *nextbi =
 					r5_next_bio(bi, sh->dev[i].sector);
 				clear_bit(BIO_UPTODATE, &bi->bi_flags);
-				if (--bi->bi_phys_segments == 0) {
+				if (!raid5_dec_bi_phys_segments(bi)) {
 					bi->bi_next = *return_bi;
 					*return_bi = bi;
 				}
@@ -2033,7 +2067,7 @@
 				while (wbi && wbi->bi_sector <
 					dev->sector + STRIPE_SECTORS) {
 					wbi2 = r5_next_bio(wbi, dev->sector);
-					if (--wbi->bi_phys_segments == 0) {
+					if (!raid5_dec_bi_phys_segments(wbi)) {
 						md_write_end(conf->mddev);
 						wbi->bi_next = *return_bi;
 						*return_bi = wbi;
@@ -2814,7 +2848,7 @@
 				copy_data(0, rbi, dev->page, dev->sector);
 				rbi2 = r5_next_bio(rbi, dev->sector);
 				spin_lock_irq(&conf->device_lock);
-				if (--rbi->bi_phys_segments == 0) {
+				if (!raid5_dec_bi_phys_segments(rbi)) {
 					rbi->bi_next = return_bi;
 					return_bi = rbi;
 				}
@@ -3155,8 +3189,11 @@
 	if(bi) {
 		conf->retry_read_aligned_list = bi->bi_next;
 		bi->bi_next = NULL;
+		/*
+		 * this sets the active strip count to 1 and the processed
+		 * strip count to zero (upper 8 bits)
+		 */
 		bi->bi_phys_segments = 1; /* biased count of active stripes */
-		bi->bi_hw_segments = 0; /* count of processed stripes */
 	}
 
 	return bi;
@@ -3206,8 +3243,7 @@
 	if ((bi->bi_size>>9) > q->max_sectors)
 		return 0;
 	blk_recount_segments(q, bi);
-	if (bi->bi_phys_segments > q->max_phys_segments ||
-	    bi->bi_hw_segments > q->max_hw_segments)
+	if (bi->bi_phys_segments > q->max_phys_segments)
 		return 0;
 
 	if (q->merge_bvec_fn)
@@ -3351,7 +3387,7 @@
 	sector_t logical_sector, last_sector;
 	struct stripe_head *sh;
 	const int rw = bio_data_dir(bi);
-	int remaining;
+	int cpu, remaining;
 
 	if (unlikely(bio_barrier(bi))) {
 		bio_endio(bi, -EOPNOTSUPP);
@@ -3360,8 +3396,11 @@
 
 	md_write_start(mddev, bi);
 
-	disk_stat_inc(mddev->gendisk, ios[rw]);
-	disk_stat_add(mddev->gendisk, sectors[rw], bio_sectors(bi));
+	cpu = part_stat_lock();
+	part_stat_inc(cpu, &mddev->gendisk->part0, ios[rw]);
+	part_stat_add(cpu, &mddev->gendisk->part0, sectors[rw],
+		      bio_sectors(bi));
+	part_stat_unlock();
 
 	if (rw == READ &&
 	     mddev->reshape_position == MaxSector &&
@@ -3468,7 +3507,7 @@
 			
 	}
 	spin_lock_irq(&conf->device_lock);
-	remaining = --bi->bi_phys_segments;
+	remaining = raid5_dec_bi_phys_segments(bi);
 	spin_unlock_irq(&conf->device_lock);
 	if (remaining == 0) {
 
@@ -3752,7 +3791,7 @@
 		     sector += STRIPE_SECTORS,
 		     scnt++) {
 
-		if (scnt < raid_bio->bi_hw_segments)
+		if (scnt < raid5_bi_hw_segments(raid_bio))
 			/* already done this stripe */
 			continue;
 
@@ -3760,7 +3799,7 @@
 
 		if (!sh) {
 			/* failed to get a stripe - must wait */
-			raid_bio->bi_hw_segments = scnt;
+			raid5_set_bi_hw_segments(raid_bio, scnt);
 			conf->retry_read_aligned = raid_bio;
 			return handled;
 		}
@@ -3768,7 +3807,7 @@
 		set_bit(R5_ReadError, &sh->dev[dd_idx].flags);
 		if (!add_stripe_bio(sh, raid_bio, dd_idx, 0)) {
 			release_stripe(sh);
-			raid_bio->bi_hw_segments = scnt;
+			raid5_set_bi_hw_segments(raid_bio, scnt);
 			conf->retry_read_aligned = raid_bio;
 			return handled;
 		}
@@ -3778,7 +3817,7 @@
 		handled++;
 	}
 	spin_lock_irq(&conf->device_lock);
-	remaining = --raid_bio->bi_phys_segments;
+	remaining = raid5_dec_bi_phys_segments(raid_bio);
 	spin_unlock_irq(&conf->device_lock);
 	if (remaining == 0)
 		bio_endio(raid_bio, 0);
diff --git a/drivers/media/common/ir-keymaps.c b/drivers/media/common/ir-keymaps.c
index 8fa91f8..4952aeb 100644
--- a/drivers/media/common/ir-keymaps.c
+++ b/drivers/media/common/ir-keymaps.c
@@ -103,6 +103,56 @@
 
 EXPORT_SYMBOL_GPL(ir_codes_avermedia_dvbt);
 
+/* Mauro Carvalho Chehab <mchehab@infradead.org> */
+IR_KEYTAB_TYPE ir_codes_avermedia_m135a[IR_KEYTAB_SIZE] = {
+	[0x00] = KEY_POWER2,
+	[0x2e] = KEY_DOT,		/* '.' */
+	[0x01] = KEY_MODE,		/* TV/FM */
+
+	[0x05] = KEY_1,
+	[0x06] = KEY_2,
+	[0x07] = KEY_3,
+	[0x09] = KEY_4,
+	[0x0a] = KEY_5,
+	[0x0b] = KEY_6,
+	[0x0d] = KEY_7,
+	[0x0e] = KEY_8,
+	[0x0f] = KEY_9,
+	[0x11] = KEY_0,
+
+	[0x13] = KEY_RIGHT,		/* -> */
+	[0x12] = KEY_LEFT,		/* <- */
+
+	[0x17] = KEY_SLEEP,		/* Capturar Imagem */
+	[0x10] = KEY_SHUFFLE,		/* Amostra */
+
+	/* FIXME: The keys bellow aren't ok */
+
+	[0x43] = KEY_CHANNELUP,
+	[0x42] = KEY_CHANNELDOWN,
+	[0x1f] = KEY_VOLUMEUP,
+	[0x1e] = KEY_VOLUMEDOWN,
+	[0x0c] = KEY_ENTER,
+
+	[0x14] = KEY_MUTE,
+	[0x08] = KEY_AUDIO,
+
+	[0x03] = KEY_TEXT,
+	[0x04] = KEY_EPG,
+	[0x2b] = KEY_TV2,		/* TV2 */
+
+	[0x1d] = KEY_RED,
+	[0x1c] = KEY_YELLOW,
+	[0x41] = KEY_GREEN,
+	[0x40] = KEY_BLUE,
+
+	[0x1a] = KEY_PLAYPAUSE,
+	[0x19] = KEY_RECORD,
+	[0x18] = KEY_PLAY,
+	[0x1b] = KEY_STOP,
+};
+EXPORT_SYMBOL_GPL(ir_codes_avermedia_m135a);
+
 /* Attila Kondoros <attila.kondoros@chello.hu> */
 IR_KEYTAB_TYPE ir_codes_apac_viewcomp[IR_KEYTAB_SIZE] = {
 
@@ -467,7 +517,8 @@
 
 /* ---------------------------------------------------------------------- */
 
-/* MSI TV@nywhere remote */
+/* MSI TV@nywhere MASTER remote */
+
 IR_KEYTAB_TYPE ir_codes_msi_tvanywhere[IR_KEYTAB_SIZE] = {
 	/* Keys 0 to 9 */
 	[ 0x00 ] = KEY_0,
@@ -501,6 +552,95 @@
 
 /* ---------------------------------------------------------------------- */
 
+/*
+  Keycodes for remote on the MSI TV@nywhere Plus. The controller IC on the card
+  is marked "KS003". The controller is I2C at address 0x30, but does not seem
+  to respond to probes until a read is performed from a valid device.
+  I don't know why...
+
+  Note: This remote may be of similar or identical design to the
+  Pixelview remote (?).  The raw codes and duplicate button codes
+  appear to be the same.
+
+  Henry Wong <henry@stuffedcow.net>
+  Some changes to formatting and keycodes by Mark Schultz <n9xmj@yahoo.com>
+
+*/
+
+IR_KEYTAB_TYPE ir_codes_msi_tvanywhere_plus[IR_KEYTAB_SIZE] = {
+
+/*  ---- Remote Button Layout ----
+
+    POWER   SOURCE  SCAN    MUTE
+    TV/FM   1       2       3
+    |>      4       5       6
+    <|      7       8       9
+    ^^UP    0       +       RECALL
+    vvDN    RECORD  STOP    PLAY
+
+	MINIMIZE          ZOOM
+
+		  CH+
+      VOL-                   VOL+
+		  CH-
+
+	SNAPSHOT           MTS
+
+     <<      FUNC    >>     RESET
+*/
+
+	[0x01] = KEY_KP1,             /* 1 */
+	[0x0b] = KEY_KP2,             /* 2 */
+	[0x1b] = KEY_KP3,             /* 3 */
+	[0x05] = KEY_KP4,             /* 4 */
+	[0x09] = KEY_KP5,             /* 5 */
+	[0x15] = KEY_KP6,             /* 6 */
+	[0x06] = KEY_KP7,             /* 7 */
+	[0x0a] = KEY_KP8,             /* 8 */
+	[0x12] = KEY_KP9,             /* 9 */
+	[0x02] = KEY_KP0,             /* 0 */
+	[0x10] = KEY_KPPLUS,          /* + */
+	[0x13] = KEY_AGAIN,           /* Recall */
+
+	[0x1e] = KEY_POWER,           /* Power */
+	[0x07] = KEY_TUNER,           /* Source */
+	[0x1c] = KEY_SEARCH,          /* Scan */
+	[0x18] = KEY_MUTE,            /* Mute */
+
+	[0x03] = KEY_RADIO,           /* TV/FM */
+	/* The next four keys are duplicates that appear to send the
+	   same IR code as Ch+, Ch-, >>, and << .  The raw code assigned
+	   to them is the actual code + 0x20 - they will never be
+	   detected as such unless some way is discovered to distinguish
+	   these buttons from those that have the same code. */
+	[0x3f] = KEY_RIGHT,           /* |> and Ch+ */
+	[0x37] = KEY_LEFT,            /* <| and Ch- */
+	[0x2c] = KEY_UP,              /* ^^Up and >> */
+	[0x24] = KEY_DOWN,            /* vvDn and << */
+
+	[0x00] = KEY_RECORD,          /* Record */
+	[0x08] = KEY_STOP,            /* Stop */
+	[0x11] = KEY_PLAY,            /* Play */
+
+	[0x0f] = KEY_CLOSE,           /* Minimize */
+	[0x19] = KEY_ZOOM,            /* Zoom */
+	[0x1a] = KEY_SHUFFLE,         /* Snapshot */
+	[0x0d] = KEY_LANGUAGE,        /* MTS */
+
+	[0x14] = KEY_VOLUMEDOWN,      /* Vol- */
+	[0x16] = KEY_VOLUMEUP,        /* Vol+ */
+	[0x17] = KEY_CHANNELDOWN,     /* Ch- */
+	[0x1f] = KEY_CHANNELUP,       /* Ch+ */
+
+	[0x04] = KEY_REWIND,          /* << */
+	[0x0e] = KEY_MENU,            /* Function */
+	[0x0c] = KEY_FASTFORWARD,     /* >> */
+	[0x1d] = KEY_RESTART,         /* Reset */
+};
+EXPORT_SYMBOL_GPL(ir_codes_msi_tvanywhere_plus);
+
+/* ---------------------------------------------------------------------- */
+
 /* Cinergy 1400 DVB-T */
 IR_KEYTAB_TYPE ir_codes_cinergy_1400[IR_KEYTAB_SIZE] = {
 	[ 0x01 ] = KEY_POWER,
@@ -1792,12 +1932,61 @@
 	[ 0x41 ] = KEY_GREEN,		/* AP2 */
 	[ 0x47 ] = KEY_YELLOW,		/* AP3 */
 	[ 0x57 ] = KEY_BLUE,		/* AP4 */
-
-
 };
-
 EXPORT_SYMBOL_GPL(ir_codes_encore_enltv);
 
+/* Encore ENLTV2-FM  - silver plastic - "Wand Media" written at the botton
+    Mauro Carvalho Chehab <mchehab@infradead.org> */
+IR_KEYTAB_TYPE ir_codes_encore_enltv2[IR_KEYTAB_SIZE] = {
+	[0x4c] = KEY_POWER2,
+	[0x4a] = KEY_TUNER,
+	[0x40] = KEY_1,
+	[0x60] = KEY_2,
+	[0x50] = KEY_3,
+	[0x70] = KEY_4,
+	[0x48] = KEY_5,
+	[0x68] = KEY_6,
+	[0x58] = KEY_7,
+	[0x78] = KEY_8,
+	[0x44] = KEY_9,
+	[0x54] = KEY_0,
+
+	[0x64] = KEY_LAST,		/* +100 */
+	[0x4e] = KEY_AGAIN,		/* Recall */
+
+	[0x6c] = KEY_SWITCHVIDEOMODE,	/* Video Source */
+	[0x5e] = KEY_MENU,
+	[0x56] = KEY_SCREEN,
+	[0x7a] = KEY_SETUP,
+
+	[0x46] = KEY_MUTE,
+	[0x5c] = KEY_MODE,		/* Stereo */
+	[0x74] = KEY_INFO,
+	[0x7c] = KEY_CLEAR,
+
+	[0x55] = KEY_UP,
+	[0x49] = KEY_DOWN,
+	[0x7e] = KEY_LEFT,
+	[0x59] = KEY_RIGHT,
+	[0x6a] = KEY_ENTER,
+
+	[0x42] = KEY_VOLUMEUP,
+	[0x62] = KEY_VOLUMEDOWN,
+	[0x52] = KEY_CHANNELUP,
+	[0x72] = KEY_CHANNELDOWN,
+
+	[0x41] = KEY_RECORD,
+	[0x51] = KEY_SHUFFLE,	/* Snapshot */
+	[0x75] = KEY_TIME,	/* Timeshift */
+	[0x71] = KEY_TV2,	/* PIP */
+
+	[0x45] = KEY_REWIND,
+	[0x6f] = KEY_PAUSE,
+	[0x7d] = KEY_FORWARD,
+	[0x79] = KEY_STOP,
+};
+EXPORT_SYMBOL_GPL(ir_codes_encore_enltv2);
+
 /* for the Technotrend 1500 bundled remotes (grey and black): */
 IR_KEYTAB_TYPE ir_codes_tt_1500[IR_KEYTAB_SIZE] = {
 	[ 0x01 ] = KEY_POWER,
@@ -2239,3 +2428,86 @@
 	[0x2a] = KEY_MENU,
 };
 EXPORT_SYMBOL_GPL(ir_codes_avermedia_a16d);
+
+/* Encore ENLTV-FM v5.3
+   Mauro Carvalho Chehab <mchehab@infradead.org>
+ */
+IR_KEYTAB_TYPE ir_codes_encore_enltv_fm53[IR_KEYTAB_SIZE] = {
+	[0x10] = KEY_POWER2,
+	[0x06] = KEY_MUTE,
+
+	[0x09] = KEY_1,
+	[0x1d] = KEY_2,
+	[0x1f] = KEY_3,
+	[0x19] = KEY_4,
+	[0x1b] = KEY_5,
+	[0x11] = KEY_6,
+	[0x17] = KEY_7,
+	[0x12] = KEY_8,
+	[0x16] = KEY_9,
+	[0x48] = KEY_0,
+
+	[0x04] = KEY_LIST,		/* -/-- */
+	[0x40] = KEY_LAST,		/* recall */
+
+	[0x02] = KEY_MODE,		/* TV/AV */
+	[0x05] = KEY_SHUFFLE,		/* SNAPSHOT */
+
+	[0x4c] = KEY_CHANNELUP,		/* UP */
+	[0x00] = KEY_CHANNELDOWN,	/* DOWN */
+	[0x0d] = KEY_VOLUMEUP,		/* RIGHT */
+	[0x15] = KEY_VOLUMEDOWN,	/* LEFT */
+	[0x49] = KEY_ENTER,		/* OK */
+
+	[0x54] = KEY_RECORD,
+	[0x4d] = KEY_PLAY,		/* pause */
+
+	[0x1e] = KEY_UP,		/* video setting */
+	[0x0e] = KEY_RIGHT,		/* <- */
+	[0x1a] = KEY_LEFT,		/* -> */
+
+	[0x0a] = KEY_DOWN,		/* video default */
+	[0x0c] = KEY_ZOOM,		/* hide pannel */
+	[0x47] = KEY_SLEEP,		/* shutdown */
+};
+EXPORT_SYMBOL_GPL(ir_codes_encore_enltv_fm53);
+
+/* Zogis Real Audio 220 - 32 keys IR */
+IR_KEYTAB_TYPE ir_codes_real_audio_220_32_keys[IR_KEYTAB_SIZE] = {
+	[0x1c] = KEY_RADIO,
+	[0x12] = KEY_POWER2,
+
+	[0x01] = KEY_1,
+	[0x02] = KEY_2,
+	[0x03] = KEY_3,
+	[0x04] = KEY_4,
+	[0x05] = KEY_5,
+	[0x06] = KEY_6,
+	[0x07] = KEY_7,
+	[0x08] = KEY_8,
+	[0x09] = KEY_9,
+	[0x00] = KEY_0,
+
+	[0x0c] = KEY_VOLUMEUP,
+	[0x18] = KEY_VOLUMEDOWN,
+	[0x0b] = KEY_CHANNELUP,
+	[0x15] = KEY_CHANNELDOWN,
+	[0x16] = KEY_ENTER,
+
+	[0x11] = KEY_LIST,		/* Source */
+	[0x0d] = KEY_AUDIO,		/* stereo */
+
+	[0x0f] = KEY_PREVIOUS,		/* Prev */
+	[0x1b] = KEY_PAUSE,		/* Timeshift */
+	[0x1a] = KEY_NEXT,		/* Next */
+
+	[0x0e] = KEY_STOP,
+	[0x1f] = KEY_PLAY,
+	[0x1e] = KEY_PLAYPAUSE,		/* Pause */
+
+	[0x1d] = KEY_RECORD,
+	[0x13] = KEY_MUTE,
+	[0x19] = KEY_SHUFFLE,		/* Snapshot */
+
+};
+EXPORT_SYMBOL_GPL(ir_codes_real_audio_220_32_keys);
diff --git a/drivers/media/common/saa7146_core.c b/drivers/media/common/saa7146_core.c
index d01965e..d599d36 100644
--- a/drivers/media/common/saa7146_core.c
+++ b/drivers/media/common/saa7146_core.c
@@ -234,7 +234,7 @@
 int saa7146_pgtable_alloc(struct pci_dev *pci, struct saa7146_pgtable *pt)
 {
 	__le32       *cpu;
-	dma_addr_t   dma_addr;
+	dma_addr_t   dma_addr = 0;
 
 	cpu = pci_alloc_consistent(pci, PAGE_SIZE, &dma_addr);
 	if (NULL == cpu) {
diff --git a/drivers/media/common/saa7146_fops.c b/drivers/media/common/saa7146_fops.c
index cf6a817..5b34c13 100644
--- a/drivers/media/common/saa7146_fops.c
+++ b/drivers/media/common/saa7146_fops.c
@@ -533,7 +533,7 @@
 	memcpy(vfd, &device_template, sizeof(struct video_device));
 	strlcpy(vfd->name, name, sizeof(vfd->name));
 	vfd->release = video_device_release;
-	vfd->priv = dev;
+	video_set_drvdata(vfd, dev);
 
 	// fixme: -1 should be an insmod parameter *for the extension* (like "video_nr");
 	if (video_register_device(vfd, type, -1) < 0) {
diff --git a/drivers/media/common/tuners/mt2060.c b/drivers/media/common/tuners/mt2060.c
index 1305b0e6..12206d7 100644
--- a/drivers/media/common/tuners/mt2060.c
+++ b/drivers/media/common/tuners/mt2060.c
@@ -170,6 +170,9 @@
 	b[0] = REG_LO1B1;
 	b[1] = 0xFF;
 
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */
+
 	mt2060_writeregs(priv,b,2);
 
 	freq = params->frequency / 1000; // Hz -> kHz
@@ -233,6 +236,9 @@
 		i++;
 	} while (i<10);
 
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */
+
 	return ret;
 }
 
@@ -296,13 +302,35 @@
 static int mt2060_init(struct dvb_frontend *fe)
 {
 	struct mt2060_priv *priv = fe->tuner_priv;
-	return mt2060_writereg(priv, REG_VGAG, (priv->cfg->clock_out << 6) | 0x33);
+	int ret;
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */
+
+	ret = mt2060_writereg(priv, REG_VGAG,
+			      (priv->cfg->clock_out << 6) | 0x33);
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */
+
+	return ret;
 }
 
 static int mt2060_sleep(struct dvb_frontend *fe)
 {
 	struct mt2060_priv *priv = fe->tuner_priv;
-	return mt2060_writereg(priv, REG_VGAG, (priv->cfg->clock_out << 6) | 0x30);
+	int ret;
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */
+
+	ret = mt2060_writereg(priv, REG_VGAG,
+			      (priv->cfg->clock_out << 6) | 0x30);
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */
+
+	return ret;
 }
 
 static int mt2060_release(struct dvb_frontend *fe)
@@ -344,6 +372,9 @@
 	priv->i2c      = i2c;
 	priv->if1_freq = if1;
 
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */
+
 	if (mt2060_readreg(priv,REG_PART_REV,&id) != 0) {
 		kfree(priv);
 		return NULL;
@@ -360,6 +391,9 @@
 
 	mt2060_calibrate(priv);
 
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */
+
 	return fe;
 }
 EXPORT_SYMBOL(mt2060_attach);
diff --git a/drivers/media/common/tuners/mxl5007t.c b/drivers/media/common/tuners/mxl5007t.c
index cb25e43..64379f2 100644
--- a/drivers/media/common/tuners/mxl5007t.c
+++ b/drivers/media/common/tuners/mxl5007t.c
@@ -979,7 +979,6 @@
 	switch (instance) {
 	case 0:
 		goto fail;
-		break;
 	case 1:
 		/* new tuner instance */
 		state->config = cfg;
diff --git a/drivers/media/common/tuners/tda18271-fe.c b/drivers/media/common/tuners/tda18271-fe.c
index 93063c6..1b48b5d 100644
--- a/drivers/media/common/tuners/tda18271-fe.c
+++ b/drivers/media/common/tuners/tda18271-fe.c
@@ -1155,7 +1155,6 @@
 	switch (instance) {
 	case 0:
 		goto fail;
-		break;
 	case 1:
 		/* new tuner instance */
 		priv->gate = (cfg) ? cfg->gate : TDA18271_GATE_AUTO;
diff --git a/drivers/media/common/tuners/tda827x.c b/drivers/media/common/tuners/tda827x.c
index 8555d9c..4a74f65 100644
--- a/drivers/media/common/tuners/tda827x.c
+++ b/drivers/media/common/tuners/tda827x.c
@@ -447,17 +447,19 @@
 			else
 				arg = 0;
 		}
-		if (priv->cfg->tuner_callback)
-			priv->cfg->tuner_callback(priv->i2c_adap->algo_data,
-								gp_func, arg);
+		if (fe->callback)
+			fe->callback(priv->i2c_adap->algo_data,
+				     DVB_FRONTEND_COMPONENT_TUNER,
+				     gp_func, arg);
 		buf[1] = high ? 0 : 1;
 		if (priv->cfg->config == 2)
 			buf[1] = high ? 1 : 0;
 		i2c_transfer(priv->i2c_adap, &msg, 1);
 		break;
 	case 3: /* switch with GPIO of saa713x */
-		if (priv->cfg->tuner_callback)
-			priv->cfg->tuner_callback(priv->i2c_adap->algo_data, 0, high);
+		if (fe->callback)
+			fe->callback(priv->i2c_adap->algo_data,
+				     DVB_FRONTEND_COMPONENT_TUNER, 0, high);
 		break;
 	}
 }
diff --git a/drivers/media/common/tuners/tda827x.h b/drivers/media/common/tuners/tda827x.h
index 7850a9a..7d72ce0 100644
--- a/drivers/media/common/tuners/tda827x.h
+++ b/drivers/media/common/tuners/tda827x.h
@@ -36,7 +36,6 @@
 	/* interface to tda829x driver */
 	unsigned int config;
 	int 	     switch_addr;
-	int (*tuner_callback) (void *dev, int command, int arg);
 
 	void (*agcf)(struct dvb_frontend *fe);
 };
diff --git a/drivers/media/common/tuners/tda8290.c b/drivers/media/common/tuners/tda8290.c
index 91204d3..c112bdd 100644
--- a/drivers/media/common/tuners/tda8290.c
+++ b/drivers/media/common/tuners/tda8290.c
@@ -672,10 +672,8 @@
 	priv->i2c_props.addr     = i2c_addr;
 	priv->i2c_props.adap     = i2c_adap;
 	priv->i2c_props.name     = "tda829x";
-	if (cfg) {
+	if (cfg)
 		priv->cfg.config         = cfg->lna_cfg;
-		priv->cfg.tuner_callback = cfg->tuner_callback;
-	}
 
 	if (tda8290_probe(&priv->i2c_props) == 0) {
 		priv->ver = TDA8290;
diff --git a/drivers/media/common/tuners/tda8290.h b/drivers/media/common/tuners/tda8290.h
index aa074f3..7e288b2 100644
--- a/drivers/media/common/tuners/tda8290.h
+++ b/drivers/media/common/tuners/tda8290.h
@@ -22,7 +22,6 @@
 
 struct tda829x_config {
 	unsigned int lna_cfg;
-	int (*tuner_callback) (void *dev, int command, int arg);
 
 	unsigned int probe_tuner:1;
 #define TDA829X_PROBE_TUNER 0
diff --git a/drivers/media/common/tuners/tda9887.c b/drivers/media/common/tuners/tda9887.c
index 72abf0b..ff1788c 100644
--- a/drivers/media/common/tuners/tda9887.c
+++ b/drivers/media/common/tuners/tda9887.c
@@ -686,7 +686,6 @@
 	case 0:
 		mutex_unlock(&tda9887_list_mutex);
 		return NULL;
-		break;
 	case 1:
 		fe->analog_demod_priv = priv;
 		priv->mode = T_STANDBY;
diff --git a/drivers/media/common/tuners/tuner-simple.c b/drivers/media/common/tuners/tuner-simple.c
index aa773a6..2a1aac1 100644
--- a/drivers/media/common/tuners/tuner-simple.c
+++ b/drivers/media/common/tuners/tuner-simple.c
@@ -142,6 +142,7 @@
 	case TUNER_PHILIPS_FM1236_MK3:
 	case TUNER_PHILIPS_FM1256_IH3:
 	case TUNER_LG_NTSC_TAPE:
+	case TUNER_TCL_MF02GIP_5N:
 		return ((status & TUNER_SIGNAL) == TUNER_STEREO_MK3);
 	default:
 		return status & TUNER_STEREO;
@@ -494,6 +495,7 @@
 	case TUNER_PHILIPS_FMD1216ME_MK3:
 	case TUNER_LG_NTSC_TAPE:
 	case TUNER_PHILIPS_FM1256_IH3:
+	case TUNER_TCL_MF02GIP_5N:
 		buffer[3] = 0x19;
 		break;
 	case TUNER_TNF_5335MF:
@@ -1038,7 +1040,6 @@
 	case 0:
 		mutex_unlock(&tuner_simple_list_mutex);
 		return NULL;
-		break;
 	case 1:
 		fe->tuner_priv = priv;
 
diff --git a/drivers/media/common/tuners/tuner-types.c b/drivers/media/common/tuners/tuner-types.c
index 10dddca..04961a1 100644
--- a/drivers/media/common/tuners/tuner-types.c
+++ b/drivers/media/common/tuners/tuner-types.c
@@ -1216,6 +1216,23 @@
 	},
 };
 
+/* ------------ TUNER_TCL_MF02GIP-5N-E - TCL MF02GIP-5N ------------ */
+
+static struct tuner_range tuner_tcl_mf02gip_5n_ntsc_ranges[] = {
+	{ 16 * 172.00 /*MHz*/, 0x8e, 0x01, },
+	{ 16 * 448.00 /*MHz*/, 0x8e, 0x02, },
+	{ 16 * 999.99        , 0x8e, 0x04, },
+};
+
+static struct tuner_params tuner_tcl_mf02gip_5n_params[] = {
+	{
+		.type   = TUNER_PARAM_TYPE_NTSC,
+		.ranges = tuner_tcl_mf02gip_5n_ntsc_ranges,
+		.count  = ARRAY_SIZE(tuner_tcl_mf02gip_5n_ntsc_ranges),
+		.cb_first_if_lower_freq = 1,
+	},
+};
+
 /* --------------------------------------------------------------------- */
 
 struct tunertype tuners[] = {
@@ -1641,6 +1658,11 @@
 		.name   = "Xceive 5000 tuner",
 		/* see xc5000.c for details */
 	},
+	[TUNER_TCL_MF02GIP_5N] = { /* TCL tuner MF02GIP-5N-E */
+		.name   = "TCL tuner MF02GIP-5N-E",
+		.params = tuner_tcl_mf02gip_5n_params,
+		.count  = ARRAY_SIZE(tuner_tcl_mf02gip_5n_params),
+	},
 };
 EXPORT_SYMBOL(tuners);
 
diff --git a/drivers/media/common/tuners/tuner-xc2028.c b/drivers/media/common/tuners/tuner-xc2028.c
index 4dd1d24..b65e680 100644
--- a/drivers/media/common/tuners/tuner-xc2028.c
+++ b/drivers/media/common/tuners/tuner-xc2028.c
@@ -71,9 +71,6 @@
 struct xc2028_data {
 	struct list_head        hybrid_tuner_instance_list;
 	struct tuner_i2c_props  i2c_props;
-	int                     (*tuner_callback) (void *dev,
-						   int command, int arg);
-	void			*video_dev;
 	__u32			frequency;
 
 	struct firmware_description *firm;
@@ -492,6 +489,23 @@
 	return i;
 }
 
+static inline int do_tuner_callback(struct dvb_frontend *fe, int cmd, int arg)
+{
+	struct xc2028_data *priv = fe->tuner_priv;
+
+	/* analog side (tuner-core) uses i2c_adap->algo_data.
+	 * digital side is not guaranteed to have algo_data defined.
+	 *
+	 * digital side will always have fe->dvb defined.
+	 * analog side (tuner-core) doesn't (yet) define fe->dvb.
+	 */
+
+	return (!fe->callback) ? -EINVAL :
+		fe->callback(((fe->dvb) && (fe->dvb->priv)) ?
+				fe->dvb->priv : priv->i2c_props.adap->algo_data,
+			     DVB_FRONTEND_COMPONENT_TUNER, cmd, arg);
+}
+
 static int load_firmware(struct dvb_frontend *fe, unsigned int type,
 			 v4l2_std_id *id)
 {
@@ -530,8 +544,7 @@
 
 		if (!size) {
 			/* Special callback command received */
-			rc = priv->tuner_callback(priv->video_dev,
-						  XC2028_TUNER_RESET, 0);
+			rc = do_tuner_callback(fe, XC2028_TUNER_RESET, 0);
 			if (rc < 0) {
 				tuner_err("Error at RESET code %d\n",
 					   (*p) & 0x7f);
@@ -542,8 +555,7 @@
 		if (size >= 0xff00) {
 			switch (size) {
 			case 0xff00:
-				rc = priv->tuner_callback(priv->video_dev,
-							XC2028_RESET_CLK, 0);
+				rc = do_tuner_callback(fe, XC2028_RESET_CLK, 0);
 				if (rc < 0) {
 					tuner_err("Error at RESET code %d\n",
 						  (*p) & 0x7f);
@@ -715,8 +727,7 @@
 	memset(&priv->cur_fw, 0, sizeof(priv->cur_fw));
 
 	/* Reset is needed before loading firmware */
-	rc = priv->tuner_callback(priv->video_dev,
-				  XC2028_TUNER_RESET, 0);
+	rc = do_tuner_callback(fe, XC2028_TUNER_RESET, 0);
 	if (rc < 0)
 		goto fail;
 
@@ -933,7 +944,7 @@
 	   The reset CLK is needed only with tm6000.
 	   Driver should work fine even if this fails.
 	 */
-	priv->tuner_callback(priv->video_dev, XC2028_RESET_CLK, 1);
+	do_tuner_callback(fe, XC2028_RESET_CLK, 1);
 
 	msleep(10);
 
@@ -1002,11 +1013,6 @@
 
 	tuner_dbg("%s called\n", __func__);
 
-	if (priv->ctrl.d2633)
-		type |= D2633;
-	else
-		type |= D2620;
-
 	switch(fe->ops.info.type) {
 	case FE_OFDM:
 		bw = p->u.ofdm.bandwidth;
@@ -1021,10 +1027,8 @@
 		break;
 	case FE_ATSC:
 		bw = BANDWIDTH_6_MHZ;
-		/* The only ATSC firmware (at least on v2.7) is D2633,
-		   so overrides ctrl->d2633 */
-		type |= ATSC| D2633;
-		type &= ~D2620;
+		/* The only ATSC firmware (at least on v2.7) is D2633 */
+		type |= ATSC | D2633;
 		break;
 	/* DVB-S is not supported */
 	default:
@@ -1057,6 +1061,28 @@
 		tuner_err("error: bandwidth not supported.\n");
 	};
 
+	/*
+	  Selects between D2633 or D2620 firmware.
+	  It doesn't make sense for ATSC, since it should be D2633 on all cases
+	 */
+	if (fe->ops.info.type != FE_ATSC) {
+		switch (priv->ctrl.type) {
+		case XC2028_D2633:
+			type |= D2633;
+			break;
+		case XC2028_D2620:
+			type |= D2620;
+			break;
+		case XC2028_AUTO:
+		default:
+			/* Zarlink seems to need D2633 */
+			if (priv->ctrl.demod == XC3028_FE_ZARLINK456)
+				type |= D2633;
+			else
+				type |= D2620;
+		}
+	}
+
 	/* All S-code tables need a 200kHz shift */
 	if (priv->ctrl.demod)
 		demod = priv->ctrl.demod + 200;
@@ -1177,20 +1203,10 @@
 		break;
 	case 1:
 		/* new tuner instance */
-		priv->tuner_callback = cfg->callback;
 		priv->ctrl.max_len = 13;
 
 		mutex_init(&priv->lock);
 
-		/* analog side (tuner-core) uses i2c_adap->algo_data.
-		 * digital side is not guaranteed to have algo_data defined.
-		 *
-		 * digital side will always have fe->dvb defined.
-		 * analog side (tuner-core) doesn't (yet) define fe->dvb.
-		 */
-		priv->video_dev = ((fe->dvb) && (fe->dvb->priv)) ?
-				   fe->dvb->priv : cfg->i2c_adap->algo_data;
-
 		fe->tuner_priv = priv;
 		break;
 	case 2:
diff --git a/drivers/media/common/tuners/tuner-xc2028.h b/drivers/media/common/tuners/tuner-xc2028.h
index 216025c..19de792 100644
--- a/drivers/media/common/tuners/tuner-xc2028.h
+++ b/drivers/media/common/tuners/tuner-xc2028.h
@@ -10,6 +10,7 @@
 #include "dvb_frontend.h"
 
 #define XC2028_DEFAULT_FIRMWARE "xc3028-v27.fw"
+#define XC3028L_DEFAULT_FIRMWARE "xc3028L-v36.fw"
 
 /*      Dmoduler		IF (kHz) */
 #define	XC3028_FE_DEFAULT	0		/* Don't load SCODE */
@@ -23,24 +24,28 @@
 #define	XC3028_FE_ZARLINK456	4560
 #define	XC3028_FE_CHINA		5200
 
+enum firmware_type {
+	XC2028_AUTO = 0,        /* By default, auto-detects */
+	XC2028_D2633,
+	XC2028_D2620,
+};
+
 struct xc2028_ctrl {
 	char			*fname;
 	int			max_len;
 	unsigned int		scode_table;
 	unsigned int		mts   :1;
-	unsigned int		d2633 :1;
 	unsigned int		input1:1;
 	unsigned int		vhfbw7:1;
 	unsigned int		uhfbw8:1;
 	unsigned int		demod;
+	enum firmware_type	type:2;
 };
 
 struct xc2028_config {
 	struct i2c_adapter *i2c_adap;
 	u8 		   i2c_addr;
-	void               *video_dev;
 	struct xc2028_ctrl *ctrl;
-	int                (*callback) (void *dev, int command, int arg);
 };
 
 /* xc2028 commands for callback */
diff --git a/drivers/media/common/tuners/xc5000.c b/drivers/media/common/tuners/xc5000.c
index dcddfa8..f9c2bb9 100644
--- a/drivers/media/common/tuners/xc5000.c
+++ b/drivers/media/common/tuners/xc5000.c
@@ -30,7 +30,7 @@
 #include "dvb_frontend.h"
 
 #include "xc5000.h"
-#include "xc5000_priv.h"
+#include "tuner-i2c.h"
 
 static int debug;
 module_param(debug, int, 0644);
@@ -40,12 +40,26 @@
 module_param_named(init_fw, xc5000_load_fw_on_attach, int, 0644);
 MODULE_PARM_DESC(init_fw, "Load firmware during driver initialization.");
 
+static DEFINE_MUTEX(xc5000_list_mutex);
+static LIST_HEAD(hybrid_tuner_instance_list);
+
 #define dprintk(level,fmt, arg...) if (debug >= level) \
 	printk(KERN_INFO "%s: " fmt, "xc5000", ## arg)
 
 #define XC5000_DEFAULT_FIRMWARE "dvb-fe-xc5000-1.1.fw"
 #define XC5000_DEFAULT_FIRMWARE_SIZE 12332
 
+struct xc5000_priv {
+	struct tuner_i2c_props i2c_props;
+	struct list_head hybrid_tuner_instance_list;
+
+	u32 if_khz;
+	u32 freq_hz;
+	u32 bandwidth;
+	u8  video_standard;
+	u8  rf_mode;
+};
+
 /* Misc Defines */
 #define MAX_TV_STANDARD			23
 #define XC_MAX_I2C_WRITE_LENGTH		64
@@ -216,9 +230,12 @@
 
 	dprintk(1, "%s()\n", __func__);
 
-	if (priv->cfg->tuner_callback) {
-		ret = priv->cfg->tuner_callback(priv->devptr,
-						XC5000_TUNER_RESET, 0);
+	if (fe->callback) {
+		ret = fe->callback(((fe->dvb) && (fe->dvb->priv)) ?
+					   fe->dvb->priv :
+					   priv->i2c_props.adap->algo_data,
+					   DVB_FRONTEND_COMPONENT_TUNER,
+					   XC5000_TUNER_RESET, 0);
 		if (ret)
 			printk(KERN_ERR "xc5000: reset failed\n");
 	} else
@@ -509,13 +526,13 @@
 	u8 buf[2] = { reg >> 8, reg & 0xff };
 	u8 bval[2] = { 0, 0 };
 	struct i2c_msg msg[2] = {
-		{ .addr = priv->cfg->i2c_address,
+		{ .addr = priv->i2c_props.addr,
 			.flags = 0, .buf = &buf[0], .len = 2 },
-		{ .addr = priv->cfg->i2c_address,
+		{ .addr = priv->i2c_props.addr,
 			.flags = I2C_M_RD, .buf = &bval[0], .len = 2 },
 	};
 
-	if (i2c_transfer(priv->i2c, msg, 2) != 2) {
+	if (i2c_transfer(priv->i2c_props.adap, msg, 2) != 2) {
 		printk(KERN_WARNING "xc5000: I2C read failed\n");
 		return -EREMOTEIO;
 	}
@@ -526,10 +543,10 @@
 
 static int xc5000_writeregs(struct xc5000_priv *priv, u8 *buf, u8 len)
 {
-	struct i2c_msg msg = { .addr = priv->cfg->i2c_address,
+	struct i2c_msg msg = { .addr = priv->i2c_props.addr,
 		.flags = 0, .buf = buf, .len = len };
 
-	if (i2c_transfer(priv->i2c, &msg, 1) != 1) {
+	if (i2c_transfer(priv->i2c_props.adap, &msg, 1) != 1) {
 		printk(KERN_ERR "xc5000: I2C write failed (len=%i)\n",
 			(int)len);
 		return -EREMOTEIO;
@@ -539,10 +556,10 @@
 
 static int xc5000_readregs(struct xc5000_priv *priv, u8 *buf, u8 len)
 {
-	struct i2c_msg msg = { .addr = priv->cfg->i2c_address,
+	struct i2c_msg msg = { .addr = priv->i2c_props.addr,
 		.flags = I2C_M_RD, .buf = buf, .len = len };
 
-	if (i2c_transfer(priv->i2c, &msg, 1) != 1) {
+	if (i2c_transfer(priv->i2c_props.adap, &msg, 1) != 1) {
 		printk(KERN_ERR "xc5000 I2C read failed (len=%i)\n",(int)len);
 		return -EREMOTEIO;
 	}
@@ -559,7 +576,7 @@
 	printk(KERN_INFO "xc5000: waiting for firmware upload (%s)...\n",
 		XC5000_DEFAULT_FIRMWARE);
 
-	ret = request_firmware(&fw, XC5000_DEFAULT_FIRMWARE, &priv->i2c->dev);
+	ret = request_firmware(&fw, XC5000_DEFAULT_FIRMWARE, &priv->i2c_props.adap->dev);
 	if (ret) {
 		printk(KERN_ERR "xc5000: Upload failed. (file not found?)\n");
 		ret = XC_RESULT_RESET_FAILURE;
@@ -675,10 +692,10 @@
 		return -EREMOTEIO;
 	}
 
-	ret = xc_set_IF_frequency(priv, priv->cfg->if_khz);
+	ret = xc_set_IF_frequency(priv, priv->if_khz);
 	if (ret != XC_RESULT_SUCCESS) {
 		printk(KERN_ERR "xc5000: xc_Set_IF_frequency(%d) failed\n",
-			priv->cfg->if_khz);
+		       priv->if_khz);
 		return -EIO;
 	}
 
@@ -897,9 +914,19 @@
 
 static int xc5000_release(struct dvb_frontend *fe)
 {
+	struct xc5000_priv *priv = fe->tuner_priv;
+
 	dprintk(1, "%s()\n", __func__);
-	kfree(fe->tuner_priv);
+
+	mutex_lock(&xc5000_list_mutex);
+
+	if (priv)
+		hybrid_tuner_release_state(priv);
+
+	mutex_unlock(&xc5000_list_mutex);
+
 	fe->tuner_priv = NULL;
+
 	return 0;
 }
 
@@ -924,29 +951,43 @@
 
 struct dvb_frontend *xc5000_attach(struct dvb_frontend *fe,
 				   struct i2c_adapter *i2c,
-				   struct xc5000_config *cfg, void *devptr)
+				   struct xc5000_config *cfg)
 {
 	struct xc5000_priv *priv = NULL;
+	int instance;
 	u16 id = 0;
 
-	dprintk(1, "%s()\n", __func__);
+	dprintk(1, "%s(%d-%04x)\n", __func__,
+		i2c ? i2c_adapter_id(i2c) : -1,
+		cfg ? cfg->i2c_address : -1);
 
-	priv = kzalloc(sizeof(struct xc5000_priv), GFP_KERNEL);
-	if (priv == NULL)
-		return NULL;
+	mutex_lock(&xc5000_list_mutex);
 
-	priv->cfg = cfg;
-	priv->bandwidth = BANDWIDTH_6_MHZ;
-	priv->i2c = i2c;
-	priv->devptr = devptr;
+	instance = hybrid_tuner_request_state(struct xc5000_priv, priv,
+					      hybrid_tuner_instance_list,
+					      i2c, cfg->i2c_address, "xc5000");
+	switch (instance) {
+	case 0:
+		goto fail;
+		break;
+	case 1:
+		/* new tuner instance */
+		priv->bandwidth = BANDWIDTH_6_MHZ;
+		priv->if_khz = cfg->if_khz;
+
+		fe->tuner_priv = priv;
+		break;
+	default:
+		/* existing tuner instance */
+		fe->tuner_priv = priv;
+		break;
+	}
 
 	/* Check if firmware has been loaded. It is possible that another
 	   instance of the driver has loaded the firmware.
 	 */
-	if (xc5000_readreg(priv, XREG_PRODUCT_ID, &id) != 0) {
-		kfree(priv);
-		return NULL;
-	}
+	if (xc5000_readreg(priv, XREG_PRODUCT_ID, &id) != 0)
+		goto fail;
 
 	switch(id) {
 	case XC_PRODUCT_ID_FW_LOADED:
@@ -967,19 +1008,23 @@
 		printk(KERN_ERR
 			"xc5000: Device not found at addr 0x%02x (0x%x)\n",
 			cfg->i2c_address, id);
-		kfree(priv);
-		return NULL;
+		goto fail;
 	}
 
+	mutex_unlock(&xc5000_list_mutex);
+
 	memcpy(&fe->ops.tuner_ops, &xc5000_tuner_ops,
 		sizeof(struct dvb_tuner_ops));
 
-	fe->tuner_priv = priv;
-
 	if (xc5000_load_fw_on_attach)
 		xc5000_init(fe);
 
 	return fe;
+fail:
+	mutex_unlock(&xc5000_list_mutex);
+
+	xc5000_release(fe);
+	return NULL;
 }
 EXPORT_SYMBOL(xc5000_attach);
 
diff --git a/drivers/media/common/tuners/xc5000.h b/drivers/media/common/tuners/xc5000.h
index 5389f74..cf1a558 100644
--- a/drivers/media/common/tuners/xc5000.h
+++ b/drivers/media/common/tuners/xc5000.h
@@ -30,8 +30,6 @@
 struct xc5000_config {
 	u8   i2c_address;
 	u32  if_khz;
-
-	int  (*tuner_callback) (void *priv, int command, int arg);
 };
 
 /* xc5000 callback command */
@@ -49,13 +47,11 @@
     (defined(CONFIG_MEDIA_TUNER_XC5000_MODULE) && defined(MODULE))
 extern struct dvb_frontend* xc5000_attach(struct dvb_frontend *fe,
 					  struct i2c_adapter *i2c,
-					  struct xc5000_config *cfg,
-					  void *devptr);
+					  struct xc5000_config *cfg);
 #else
 static inline struct dvb_frontend* xc5000_attach(struct dvb_frontend *fe,
 						 struct i2c_adapter *i2c,
-						 struct xc5000_config *cfg,
-						 void *devptr)
+						 struct xc5000_config *cfg)
 {
 	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
 	return NULL;
diff --git a/drivers/media/common/tuners/xc5000_priv.h b/drivers/media/common/tuners/xc5000_priv.h
deleted file mode 100644
index b2a0074..0000000
--- a/drivers/media/common/tuners/xc5000_priv.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- *  Driver for Xceive XC5000 "QAM/8VSB single chip tuner"
- *
- *  Copyright (c) 2007 Steven Toth <stoth@linuxtv.org>
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#ifndef XC5000_PRIV_H
-#define XC5000_PRIV_H
-
-struct xc5000_priv {
-	struct xc5000_config *cfg;
-	struct i2c_adapter   *i2c;
-
-	u32 freq_hz;
-	u32 bandwidth;
-	u8  video_standard;
-	u8  rf_mode;
-
-	void *devptr;
-};
-
-#endif
diff --git a/drivers/media/dvb/Kconfig b/drivers/media/dvb/Kconfig
index 8bc1445..0bcd852 100644
--- a/drivers/media/dvb/Kconfig
+++ b/drivers/media/dvb/Kconfig
@@ -20,7 +20,6 @@
 source "drivers/media/dvb/dvb-usb/Kconfig"
 source "drivers/media/dvb/ttusb-budget/Kconfig"
 source "drivers/media/dvb/ttusb-dec/Kconfig"
-source "drivers/media/dvb/cinergyT2/Kconfig"
 source "drivers/media/dvb/siano/Kconfig"
 
 comment "Supported FlexCopII (B2C2) Adapters"
@@ -35,6 +34,10 @@
 	depends on DVB_CORE && PCI && I2C
 source "drivers/media/dvb/pluto2/Kconfig"
 
+comment "Supported SDMC DM1105 Adapters"
+	depends on DVB_CORE && PCI && I2C
+source "drivers/media/dvb/dm1105/Kconfig"
+
 comment "Supported DVB Frontends"
 	depends on DVB_CORE
 source "drivers/media/dvb/frontends/Kconfig"
diff --git a/drivers/media/dvb/Makefile b/drivers/media/dvb/Makefile
index d6ba4d1..f91e9eb 100644
--- a/drivers/media/dvb/Makefile
+++ b/drivers/media/dvb/Makefile
@@ -2,4 +2,4 @@
 # Makefile for the kernel multimedia device drivers.
 #
 
-obj-y        := dvb-core/ frontends/ ttpci/ ttusb-dec/ ttusb-budget/ b2c2/ bt8xx/ cinergyT2/ dvb-usb/ pluto2/ siano/
+obj-y        := dvb-core/ frontends/ ttpci/ ttusb-dec/ ttusb-budget/ b2c2/ bt8xx/ dvb-usb/ pluto2/ siano/ dm1105/
diff --git a/drivers/media/dvb/b2c2/flexcop-dma.c b/drivers/media/dvb/b2c2/flexcop-dma.c
index a91ed28..26f0011 100644
--- a/drivers/media/dvb/b2c2/flexcop-dma.c
+++ b/drivers/media/dvb/b2c2/flexcop-dma.c
@@ -10,7 +10,7 @@
 int flexcop_dma_allocate(struct pci_dev *pdev, struct flexcop_dma *dma, u32 size)
 {
 	u8 *tcpu;
-	dma_addr_t tdma;
+	dma_addr_t tdma = 0;
 
 	if (size % 2) {
 		err("dma buffersize has to be even.");
diff --git a/drivers/media/dvb/b2c2/flexcop-fe-tuner.c b/drivers/media/dvb/b2c2/flexcop-fe-tuner.c
index 4eed783..a127a41 100644
--- a/drivers/media/dvb/b2c2/flexcop-fe-tuner.c
+++ b/drivers/media/dvb/b2c2/flexcop-fe-tuner.c
@@ -491,6 +491,7 @@
 	.demod_address = 0x53,
 	.invert = 1,
 	.repeated_start_workaround = 1,
+	.serial_mpeg = 1,
 };
 
 static struct itd1000_config skystar2_rev2_7_itd1000_config = {
diff --git a/drivers/media/dvb/bt8xx/dvb-bt8xx.c b/drivers/media/dvb/bt8xx/dvb-bt8xx.c
index 6afbfbb..48762a2 100644
--- a/drivers/media/dvb/bt8xx/dvb-bt8xx.c
+++ b/drivers/media/dvb/bt8xx/dvb-bt8xx.c
@@ -702,7 +702,7 @@
 	}
 
 	if (card->fe == NULL)
-		printk("dvb-bt8xx: A frontend driver was not found for device %04x/%04x subsystem %04x/%04x\n",
+		printk("dvb-bt8xx: A frontend driver was not found for device [%04x:%04x] subsystem [%04x:%04x]\n",
 		       card->bt->dev->vendor,
 		       card->bt->dev->device,
 		       card->bt->dev->subsystem_vendor,
diff --git a/drivers/media/dvb/cinergyT2/Kconfig b/drivers/media/dvb/cinergyT2/Kconfig
deleted file mode 100644
index c03513b..0000000
--- a/drivers/media/dvb/cinergyT2/Kconfig
+++ /dev/null
@@ -1,85 +0,0 @@
-config DVB_CINERGYT2
-	tristate "Terratec CinergyT2/qanu USB2 DVB-T receiver"
-	depends on DVB_CORE && USB && INPUT
-	help
-	  Support for "TerraTec CinergyT2" USB2.0 Highspeed DVB Receivers
-
-	  Say Y if you own such a device and want to use it.
-
-
-config DVB_CINERGYT2_TUNING
-	bool "sophisticated fine-tuning for CinergyT2 cards"
-	depends on DVB_CINERGYT2
-	help
-	  Here you can fine-tune some parameters of the CinergyT2 driver.
-
-	  Normally you don't need to touch this, but in exotic setups you
-	  may fine-tune your setup and adjust e.g. DMA buffer sizes for
-	  a particular application.
-
-
-config DVB_CINERGYT2_STREAM_URB_COUNT
-	int "Number of queued USB Request Blocks for Highspeed Stream Transfers"
-	depends on DVB_CINERGYT2_TUNING
-	default "32"
-	help
-	  USB Request Blocks for Highspeed Stream transfers are scheduled in
-	  a queue for the Host Controller.
-
-	  Usually the default value is a safe choice.
-
-	  You may increase this number if you are using this device in a
-	  Server Environment with many high-traffic USB Highspeed devices
-	  sharing the same USB bus.
-
-
-config DVB_CINERGYT2_STREAM_BUF_SIZE
-	int "Size of URB Stream Buffers for Highspeed Transfers"
-	depends on DVB_CINERGYT2_TUNING
-	default "512"
-	help
-	  Should be a multiple of native buffer size of 512 bytes.
-	  Default value is a safe choice.
-
-	  You may increase this number if you are using this device in a
-	  Server Environment with many high-traffic USB Highspeed devices
-	  sharing the same USB bus.
-
-
-config DVB_CINERGYT2_QUERY_INTERVAL
-	int "Status update interval [milliseconds]"
-	depends on DVB_CINERGYT2_TUNING
-	default "250"
-	help
-	  This is the interval for status readouts from the demodulator.
-	  You may try lower values if you need more responsive signal quality
-	  measurements.
-
-	  Please keep in mind that these updates cause traffic on the tuner
-	  control bus and thus may or may not affect reception sensitivity.
-
-	  The default value should be a safe choice for common applications.
-
-
-config DVB_CINERGYT2_ENABLE_RC_INPUT_DEVICE
-	bool "Register the onboard IR Remote Control Receiver as Input Device"
-	depends on DVB_CINERGYT2_TUNING
-	default y
-	help
-	  Enable this option if you want to use the onboard Infrared Remote
-	  Control Receiver as Linux-Input device.
-
-	  Right now only the keycode table for the default Remote Control
-	  delivered with the device is supported, please see the driver
-	  source code to find out how to add support for other controls.
-
-
-config DVB_CINERGYT2_RC_QUERY_INTERVAL
-	int "Infrared Remote Controller update interval [milliseconds]"
-	depends on DVB_CINERGYT2_TUNING && DVB_CINERGYT2_ENABLE_RC_INPUT_DEVICE
-	default "50"
-	help
-	  If you have a very fast-repeating remote control you can try lower
-	  values, for normal consumer receivers the default value should be
-	  a safe choice.
-
diff --git a/drivers/media/dvb/cinergyT2/Makefile b/drivers/media/dvb/cinergyT2/Makefile
deleted file mode 100644
index d762d8c..0000000
--- a/drivers/media/dvb/cinergyT2/Makefile
+++ /dev/null
@@ -1,3 +0,0 @@
-obj-$(CONFIG_DVB_CINERGYT2) += cinergyT2.o
-
-EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/
diff --git a/drivers/media/dvb/cinergyT2/cinergyT2.c b/drivers/media/dvb/cinergyT2/cinergyT2.c
deleted file mode 100644
index a824f37..0000000
--- a/drivers/media/dvb/cinergyT2/cinergyT2.c
+++ /dev/null
@@ -1,1105 +0,0 @@
-/*
- * TerraTec Cinergy T²/qanu USB2 DVB-T adapter.
- *
- * Copyright (C) 2004 Daniel Mack <daniel@qanu.de> and
- *		    Holger Waechtler <holger@qanu.de>
- *
- *  Protocol Spec published on http://qanu.de/specs/terratec_cinergyT2.pdf
- *
- * This program is free software; you can redistribute it and/or 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/init.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/usb.h>
-#include <linux/input.h>
-#include <linux/dvb/frontend.h>
-#include <linux/mutex.h>
-#include <linux/mm.h>
-#include <asm/io.h>
-
-#include "dmxdev.h"
-#include "dvb_demux.h"
-#include "dvb_net.h"
-
-#ifdef CONFIG_DVB_CINERGYT2_TUNING
-	#define STREAM_URB_COUNT (CONFIG_DVB_CINERGYT2_STREAM_URB_COUNT)
-	#define STREAM_BUF_SIZE (CONFIG_DVB_CINERGYT2_STREAM_BUF_SIZE)
-	#define QUERY_INTERVAL (CONFIG_DVB_CINERGYT2_QUERY_INTERVAL)
-	#ifdef CONFIG_DVB_CINERGYT2_ENABLE_RC_INPUT_DEVICE
-		#define RC_QUERY_INTERVAL (CONFIG_DVB_CINERGYT2_RC_QUERY_INTERVAL)
-		#define ENABLE_RC (1)
-	#endif
-#else
-	#define STREAM_URB_COUNT (32)
-	#define STREAM_BUF_SIZE (512)	/* bytes */
-	#define ENABLE_RC (1)
-	#define RC_QUERY_INTERVAL (50)	/* milliseconds */
-	#define QUERY_INTERVAL (333)	/* milliseconds */
-#endif
-
-#define DRIVER_NAME "TerraTec/qanu USB2.0 Highspeed DVB-T Receiver"
-
-static int debug;
-module_param_named(debug, debug, int, 0644);
-MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
-
-DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
-
-#define dprintk(level, args...)						\
-do {									\
-	if ((debug & level)) {						\
-		printk("%s: %s(): ", KBUILD_MODNAME,			\
-		       __func__);					\
-		printk(args); }						\
-} while (0)
-
-enum cinergyt2_ep1_cmd {
-	CINERGYT2_EP1_PID_TABLE_RESET		= 0x01,
-	CINERGYT2_EP1_PID_SETUP			= 0x02,
-	CINERGYT2_EP1_CONTROL_STREAM_TRANSFER	= 0x03,
-	CINERGYT2_EP1_SET_TUNER_PARAMETERS	= 0x04,
-	CINERGYT2_EP1_GET_TUNER_STATUS		= 0x05,
-	CINERGYT2_EP1_START_SCAN		= 0x06,
-	CINERGYT2_EP1_CONTINUE_SCAN		= 0x07,
-	CINERGYT2_EP1_GET_RC_EVENTS		= 0x08,
-	CINERGYT2_EP1_SLEEP_MODE		= 0x09
-};
-
-struct dvbt_set_parameters_msg {
-	uint8_t cmd;
-	__le32 freq;
-	uint8_t bandwidth;
-	__le16 tps;
-	uint8_t flags;
-} __attribute__((packed));
-
-struct dvbt_get_status_msg {
-	__le32 freq;
-	uint8_t bandwidth;
-	__le16 tps;
-	uint8_t flags;
-	__le16 gain;
-	uint8_t snr;
-	__le32 viterbi_error_rate;
-	__le32 rs_error_rate;
-	__le32 uncorrected_block_count;
-	uint8_t lock_bits;
-	uint8_t prev_lock_bits;
-} __attribute__((packed));
-
-static struct dvb_frontend_info cinergyt2_fe_info = {
-	.name = DRIVER_NAME,
-	.type = FE_OFDM,
-	.frequency_min = 174000000,
-	.frequency_max = 862000000,
-	.frequency_stepsize = 166667,
-	.caps = FE_CAN_INVERSION_AUTO | FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 |
-		FE_CAN_FEC_3_4 | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 |
-		FE_CAN_FEC_AUTO |
-		FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
-		FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO |
-		FE_CAN_HIERARCHY_AUTO | FE_CAN_RECOVER | FE_CAN_MUTE_TS
-};
-
-struct cinergyt2 {
-	struct dvb_demux demux;
-	struct usb_device *udev;
-	struct mutex sem;
-	struct mutex wq_sem;
-	struct dvb_adapter adapter;
-	struct dvb_device *fedev;
-	struct dmxdev dmxdev;
-	struct dvb_net dvbnet;
-
-	int streaming;
-	int sleeping;
-
-	struct dvbt_set_parameters_msg param;
-	struct dvbt_get_status_msg status;
-	struct delayed_work query_work;
-
-	wait_queue_head_t poll_wq;
-	int pending_fe_events;
-	int disconnect_pending;
-	unsigned int uncorrected_block_count;
-	atomic_t inuse;
-
-	void *streambuf;
-	dma_addr_t streambuf_dmahandle;
-	struct urb *stream_urb [STREAM_URB_COUNT];
-
-#ifdef ENABLE_RC
-	struct input_dev *rc_input_dev;
-	char phys[64];
-	struct delayed_work rc_query_work;
-	int rc_input_event;
-	__le32 rc_last_code;
-	unsigned long last_event_jiffies;
-#endif
-};
-
-enum {
-	CINERGYT2_RC_EVENT_TYPE_NONE = 0x00,
-	CINERGYT2_RC_EVENT_TYPE_NEC  = 0x01,
-	CINERGYT2_RC_EVENT_TYPE_RC5  = 0x02
-};
-
-struct cinergyt2_rc_event {
-	char type;
-	__le32 value;
-} __attribute__((packed));
-
-static const uint32_t rc_keys[] = {
-	CINERGYT2_RC_EVENT_TYPE_NEC,	0xfe01eb04,	KEY_POWER,
-	CINERGYT2_RC_EVENT_TYPE_NEC,	0xfd02eb04,	KEY_1,
-	CINERGYT2_RC_EVENT_TYPE_NEC,	0xfc03eb04,	KEY_2,
-	CINERGYT2_RC_EVENT_TYPE_NEC,	0xfb04eb04,	KEY_3,
-	CINERGYT2_RC_EVENT_TYPE_NEC,	0xfa05eb04,	KEY_4,
-	CINERGYT2_RC_EVENT_TYPE_NEC,	0xf906eb04,	KEY_5,
-	CINERGYT2_RC_EVENT_TYPE_NEC,	0xf807eb04,	KEY_6,
-	CINERGYT2_RC_EVENT_TYPE_NEC,	0xf708eb04,	KEY_7,
-	CINERGYT2_RC_EVENT_TYPE_NEC,	0xf609eb04,	KEY_8,
-	CINERGYT2_RC_EVENT_TYPE_NEC,	0xf50aeb04,	KEY_9,
-	CINERGYT2_RC_EVENT_TYPE_NEC,	0xf30ceb04,	KEY_0,
-	CINERGYT2_RC_EVENT_TYPE_NEC,	0xf40beb04,	KEY_VIDEO,
-	CINERGYT2_RC_EVENT_TYPE_NEC,	0xf20deb04,	KEY_REFRESH,
-	CINERGYT2_RC_EVENT_TYPE_NEC,	0xf10eeb04,	KEY_SELECT,
-	CINERGYT2_RC_EVENT_TYPE_NEC,	0xf00feb04,	KEY_EPG,
-	CINERGYT2_RC_EVENT_TYPE_NEC,	0xef10eb04,	KEY_UP,
-	CINERGYT2_RC_EVENT_TYPE_NEC,	0xeb14eb04,	KEY_DOWN,
-	CINERGYT2_RC_EVENT_TYPE_NEC,	0xee11eb04,	KEY_LEFT,
-	CINERGYT2_RC_EVENT_TYPE_NEC,	0xec13eb04,	KEY_RIGHT,
-	CINERGYT2_RC_EVENT_TYPE_NEC,	0xed12eb04,	KEY_OK,
-	CINERGYT2_RC_EVENT_TYPE_NEC,	0xea15eb04,	KEY_TEXT,
-	CINERGYT2_RC_EVENT_TYPE_NEC,	0xe916eb04,	KEY_INFO,
-	CINERGYT2_RC_EVENT_TYPE_NEC,	0xe817eb04,	KEY_RED,
-	CINERGYT2_RC_EVENT_TYPE_NEC,	0xe718eb04,	KEY_GREEN,
-	CINERGYT2_RC_EVENT_TYPE_NEC,	0xe619eb04,	KEY_YELLOW,
-	CINERGYT2_RC_EVENT_TYPE_NEC,	0xe51aeb04,	KEY_BLUE,
-	CINERGYT2_RC_EVENT_TYPE_NEC,	0xe31ceb04,	KEY_VOLUMEUP,
-	CINERGYT2_RC_EVENT_TYPE_NEC,	0xe11eeb04,	KEY_VOLUMEDOWN,
-	CINERGYT2_RC_EVENT_TYPE_NEC,	0xe21deb04,	KEY_MUTE,
-	CINERGYT2_RC_EVENT_TYPE_NEC,	0xe41beb04,	KEY_CHANNELUP,
-	CINERGYT2_RC_EVENT_TYPE_NEC,	0xe01feb04,	KEY_CHANNELDOWN,
-	CINERGYT2_RC_EVENT_TYPE_NEC,	0xbf40eb04,	KEY_PAUSE,
-	CINERGYT2_RC_EVENT_TYPE_NEC,	0xb34ceb04,	KEY_PLAY,
-	CINERGYT2_RC_EVENT_TYPE_NEC,	0xa758eb04,	KEY_RECORD,
-	CINERGYT2_RC_EVENT_TYPE_NEC,	0xab54eb04,	KEY_PREVIOUS,
-	CINERGYT2_RC_EVENT_TYPE_NEC,	0xb748eb04,	KEY_STOP,
-	CINERGYT2_RC_EVENT_TYPE_NEC,	0xa35ceb04,	KEY_NEXT
-};
-
-static int cinergyt2_command (struct cinergyt2 *cinergyt2,
-			      char *send_buf, int send_buf_len,
-			      char *recv_buf, int recv_buf_len)
-{
-	int actual_len;
-	char dummy;
-	int ret;
-
-	ret = usb_bulk_msg(cinergyt2->udev, usb_sndbulkpipe(cinergyt2->udev, 1),
-			   send_buf, send_buf_len, &actual_len, 1000);
-
-	if (ret)
-		dprintk(1, "usb_bulk_msg (send) failed, err %i\n", ret);
-
-	if (!recv_buf)
-		recv_buf = &dummy;
-
-	ret = usb_bulk_msg(cinergyt2->udev, usb_rcvbulkpipe(cinergyt2->udev, 1),
-			   recv_buf, recv_buf_len, &actual_len, 1000);
-
-	if (ret)
-		dprintk(1, "usb_bulk_msg (read) failed, err %i\n", ret);
-
-	return ret ? ret : actual_len;
-}
-
-static void cinergyt2_control_stream_transfer (struct cinergyt2 *cinergyt2, int enable)
-{
-	char buf [] = { CINERGYT2_EP1_CONTROL_STREAM_TRANSFER, enable ? 1 : 0 };
-	cinergyt2_command(cinergyt2, buf, sizeof(buf), NULL, 0);
-}
-
-static void cinergyt2_sleep (struct cinergyt2 *cinergyt2, int sleep)
-{
-	char buf [] = { CINERGYT2_EP1_SLEEP_MODE, sleep ? 1 : 0 };
-	cinergyt2_command(cinergyt2, buf, sizeof(buf), NULL, 0);
-	cinergyt2->sleeping = sleep;
-}
-
-static void cinergyt2_stream_irq (struct urb *urb);
-
-static int cinergyt2_submit_stream_urb (struct cinergyt2 *cinergyt2, struct urb *urb)
-{
-	int err;
-
-	usb_fill_bulk_urb(urb,
-			  cinergyt2->udev,
-			  usb_rcvbulkpipe(cinergyt2->udev, 0x2),
-			  urb->transfer_buffer,
-			  STREAM_BUF_SIZE,
-			  cinergyt2_stream_irq,
-			  cinergyt2);
-
-	if ((err = usb_submit_urb(urb, GFP_ATOMIC)))
-		dprintk(1, "urb submission failed (err = %i)!\n", err);
-
-	return err;
-}
-
-static void cinergyt2_stream_irq (struct urb *urb)
-{
-	struct cinergyt2 *cinergyt2 = urb->context;
-
-	if (urb->actual_length > 0)
-		dvb_dmx_swfilter(&cinergyt2->demux,
-				 urb->transfer_buffer, urb->actual_length);
-
-	if (cinergyt2->streaming)
-		cinergyt2_submit_stream_urb(cinergyt2, urb);
-}
-
-static void cinergyt2_free_stream_urbs (struct cinergyt2 *cinergyt2)
-{
-	int i;
-
-	for (i=0; i<STREAM_URB_COUNT; i++)
-		usb_free_urb(cinergyt2->stream_urb[i]);
-
-	usb_buffer_free(cinergyt2->udev, STREAM_URB_COUNT*STREAM_BUF_SIZE,
-			    cinergyt2->streambuf, cinergyt2->streambuf_dmahandle);
-}
-
-static int cinergyt2_alloc_stream_urbs (struct cinergyt2 *cinergyt2)
-{
-	int i;
-
-	cinergyt2->streambuf = usb_buffer_alloc(cinergyt2->udev, STREAM_URB_COUNT*STREAM_BUF_SIZE,
-					      GFP_KERNEL, &cinergyt2->streambuf_dmahandle);
-	if (!cinergyt2->streambuf) {
-		dprintk(1, "failed to alloc consistent stream memory area, bailing out!\n");
-		return -ENOMEM;
-	}
-
-	memset(cinergyt2->streambuf, 0, STREAM_URB_COUNT*STREAM_BUF_SIZE);
-
-	for (i=0; i<STREAM_URB_COUNT; i++) {
-		struct urb *urb;
-
-		if (!(urb = usb_alloc_urb(0, GFP_ATOMIC))) {
-			dprintk(1, "failed to alloc consistent stream urbs, bailing out!\n");
-			cinergyt2_free_stream_urbs(cinergyt2);
-			return -ENOMEM;
-		}
-
-		urb->transfer_buffer = cinergyt2->streambuf + i * STREAM_BUF_SIZE;
-		urb->transfer_buffer_length = STREAM_BUF_SIZE;
-
-		cinergyt2->stream_urb[i] = urb;
-	}
-
-	return 0;
-}
-
-static void cinergyt2_stop_stream_xfer (struct cinergyt2 *cinergyt2)
-{
-	int i;
-
-	cinergyt2_control_stream_transfer(cinergyt2, 0);
-
-	for (i=0; i<STREAM_URB_COUNT; i++)
-		usb_kill_urb(cinergyt2->stream_urb[i]);
-}
-
-static int cinergyt2_start_stream_xfer (struct cinergyt2 *cinergyt2)
-{
-	int i, err;
-
-	for (i=0; i<STREAM_URB_COUNT; i++) {
-		if ((err = cinergyt2_submit_stream_urb(cinergyt2, cinergyt2->stream_urb[i]))) {
-			cinergyt2_stop_stream_xfer(cinergyt2);
-			dprintk(1, "failed urb submission (%i: err = %i)!\n", i, err);
-			return err;
-		}
-	}
-
-	cinergyt2_control_stream_transfer(cinergyt2, 1);
-	return 0;
-}
-
-static int cinergyt2_start_feed(struct dvb_demux_feed *dvbdmxfeed)
-{
-	struct dvb_demux *demux = dvbdmxfeed->demux;
-	struct cinergyt2 *cinergyt2 = demux->priv;
-
-	if (cinergyt2->disconnect_pending)
-		return -EAGAIN;
-	if (mutex_lock_interruptible(&cinergyt2->sem))
-		return -ERESTARTSYS;
-
-	if (cinergyt2->streaming == 0)
-		cinergyt2_start_stream_xfer(cinergyt2);
-
-	cinergyt2->streaming++;
-	mutex_unlock(&cinergyt2->sem);
-	return 0;
-}
-
-static int cinergyt2_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
-{
-	struct dvb_demux *demux = dvbdmxfeed->demux;
-	struct cinergyt2 *cinergyt2 = demux->priv;
-
-	if (cinergyt2->disconnect_pending)
-		return -EAGAIN;
-	if (mutex_lock_interruptible(&cinergyt2->sem))
-		return -ERESTARTSYS;
-
-	if (--cinergyt2->streaming == 0)
-		cinergyt2_stop_stream_xfer(cinergyt2);
-
-	mutex_unlock(&cinergyt2->sem);
-	return 0;
-}
-
-/**
- *  convert linux-dvb frontend parameter set into TPS.
- *  See ETSI ETS-300744, section 4.6.2, table 9 for details.
- *
- *  This function is probably reusable and may better get placed in a support
- *  library.
- *
- *  We replace errornous fields by default TPS fields (the ones with value 0).
- */
-static uint16_t compute_tps (struct dvb_frontend_parameters *p)
-{
-	struct dvb_ofdm_parameters *op = &p->u.ofdm;
-	uint16_t tps = 0;
-
-	switch (op->code_rate_HP) {
-		case FEC_2_3:
-			tps |= (1 << 7);
-			break;
-		case FEC_3_4:
-			tps |= (2 << 7);
-			break;
-		case FEC_5_6:
-			tps |= (3 << 7);
-			break;
-		case FEC_7_8:
-			tps |= (4 << 7);
-			break;
-		case FEC_1_2:
-		case FEC_AUTO:
-		default:
-			/* tps |= (0 << 7) */;
-	}
-
-	switch (op->code_rate_LP) {
-		case FEC_2_3:
-			tps |= (1 << 4);
-			break;
-		case FEC_3_4:
-			tps |= (2 << 4);
-			break;
-		case FEC_5_6:
-			tps |= (3 << 4);
-			break;
-		case FEC_7_8:
-			tps |= (4 << 4);
-			break;
-		case FEC_1_2:
-		case FEC_AUTO:
-		default:
-			/* tps |= (0 << 4) */;
-	}
-
-	switch (op->constellation) {
-		case QAM_16:
-			tps |= (1 << 13);
-			break;
-		case QAM_64:
-			tps |= (2 << 13);
-			break;
-		case QPSK:
-		default:
-			/* tps |= (0 << 13) */;
-	}
-
-	switch (op->transmission_mode) {
-		case TRANSMISSION_MODE_8K:
-			tps |= (1 << 0);
-			break;
-		case TRANSMISSION_MODE_2K:
-		default:
-			/* tps |= (0 << 0) */;
-	}
-
-	switch (op->guard_interval) {
-		case GUARD_INTERVAL_1_16:
-			tps |= (1 << 2);
-			break;
-		case GUARD_INTERVAL_1_8:
-			tps |= (2 << 2);
-			break;
-		case GUARD_INTERVAL_1_4:
-			tps |= (3 << 2);
-			break;
-		case GUARD_INTERVAL_1_32:
-		default:
-			/* tps |= (0 << 2) */;
-	}
-
-	switch (op->hierarchy_information) {
-		case HIERARCHY_1:
-			tps |= (1 << 10);
-			break;
-		case HIERARCHY_2:
-			tps |= (2 << 10);
-			break;
-		case HIERARCHY_4:
-			tps |= (3 << 10);
-			break;
-		case HIERARCHY_NONE:
-		default:
-			/* tps |= (0 << 10) */;
-	}
-
-	return tps;
-}
-
-static int cinergyt2_open (struct inode *inode, struct file *file)
-{
-	struct dvb_device *dvbdev = file->private_data;
-	struct cinergyt2 *cinergyt2 = dvbdev->priv;
-	int err = -EAGAIN;
-
-	if (cinergyt2->disconnect_pending)
-		goto out;
-	err = mutex_lock_interruptible(&cinergyt2->wq_sem);
-	if (err)
-		goto out;
-
-	err = mutex_lock_interruptible(&cinergyt2->sem);
-	if (err)
-		goto out_unlock1;
-
-	if ((err = dvb_generic_open(inode, file)))
-		goto out_unlock2;
-
-	if ((file->f_flags & O_ACCMODE) != O_RDONLY) {
-		cinergyt2_sleep(cinergyt2, 0);
-		schedule_delayed_work(&cinergyt2->query_work, HZ/2);
-	}
-
-	atomic_inc(&cinergyt2->inuse);
-
-out_unlock2:
-	mutex_unlock(&cinergyt2->sem);
-out_unlock1:
-	mutex_unlock(&cinergyt2->wq_sem);
-out:
-	return err;
-}
-
-static void cinergyt2_unregister(struct cinergyt2 *cinergyt2)
-{
-	dvb_net_release(&cinergyt2->dvbnet);
-	dvb_dmxdev_release(&cinergyt2->dmxdev);
-	dvb_dmx_release(&cinergyt2->demux);
-	dvb_unregister_device(cinergyt2->fedev);
-	dvb_unregister_adapter(&cinergyt2->adapter);
-
-	cinergyt2_free_stream_urbs(cinergyt2);
-	kfree(cinergyt2);
-}
-
-static int cinergyt2_release (struct inode *inode, struct file *file)
-{
-	struct dvb_device *dvbdev = file->private_data;
-	struct cinergyt2 *cinergyt2 = dvbdev->priv;
-
-	mutex_lock(&cinergyt2->wq_sem);
-
-	if (!cinergyt2->disconnect_pending && (file->f_flags & O_ACCMODE) != O_RDONLY) {
-		cancel_rearming_delayed_work(&cinergyt2->query_work);
-
-		mutex_lock(&cinergyt2->sem);
-		cinergyt2_sleep(cinergyt2, 1);
-		mutex_unlock(&cinergyt2->sem);
-	}
-
-	mutex_unlock(&cinergyt2->wq_sem);
-
-	if (atomic_dec_and_test(&cinergyt2->inuse) && cinergyt2->disconnect_pending) {
-		warn("delayed unregister in release");
-		cinergyt2_unregister(cinergyt2);
-	}
-
-	return dvb_generic_release(inode, file);
-}
-
-static unsigned int cinergyt2_poll (struct file *file, struct poll_table_struct *wait)
-{
-	struct dvb_device *dvbdev = file->private_data;
-	struct cinergyt2 *cinergyt2 = dvbdev->priv;
-	unsigned int mask = 0;
-
-	if (cinergyt2->disconnect_pending)
-		return -EAGAIN;
-	if (mutex_lock_interruptible(&cinergyt2->sem))
-		return -ERESTARTSYS;
-
-	poll_wait(file, &cinergyt2->poll_wq, wait);
-
-	if (cinergyt2->pending_fe_events != 0)
-		mask |= (POLLIN | POLLRDNORM | POLLPRI);
-
-	mutex_unlock(&cinergyt2->sem);
-
-	return mask;
-}
-
-
-static int cinergyt2_ioctl (struct inode *inode, struct file *file,
-		     unsigned cmd, unsigned long arg)
-{
-	struct dvb_device *dvbdev = file->private_data;
-	struct cinergyt2 *cinergyt2 = dvbdev->priv;
-	struct dvbt_get_status_msg *stat = &cinergyt2->status;
-	fe_status_t status = 0;
-
-	switch (cmd) {
-	case FE_GET_INFO:
-		return copy_to_user((void __user*) arg, &cinergyt2_fe_info,
-				    sizeof(struct dvb_frontend_info));
-
-	case FE_READ_STATUS:
-		if (0xffff - le16_to_cpu(stat->gain) > 30)
-			status |= FE_HAS_SIGNAL;
-		if (stat->lock_bits & (1 << 6))
-			status |= FE_HAS_LOCK;
-		if (stat->lock_bits & (1 << 5))
-			status |= FE_HAS_SYNC;
-		if (stat->lock_bits & (1 << 4))
-			status |= FE_HAS_CARRIER;
-		if (stat->lock_bits & (1 << 1))
-			status |= FE_HAS_VITERBI;
-
-		return copy_to_user((void  __user*) arg, &status, sizeof(status));
-
-	case FE_READ_BER:
-		return put_user(le32_to_cpu(stat->viterbi_error_rate),
-				(__u32 __user *) arg);
-
-	case FE_READ_SIGNAL_STRENGTH:
-		return put_user(0xffff - le16_to_cpu(stat->gain),
-				(__u16 __user *) arg);
-
-	case FE_READ_SNR:
-		return put_user((stat->snr << 8) | stat->snr,
-				(__u16 __user *) arg);
-
-	case FE_READ_UNCORRECTED_BLOCKS:
-	{
-		uint32_t unc_count;
-
-		if (mutex_lock_interruptible(&cinergyt2->sem))
-			return -ERESTARTSYS;
-		unc_count = cinergyt2->uncorrected_block_count;
-		cinergyt2->uncorrected_block_count = 0;
-		mutex_unlock(&cinergyt2->sem);
-
-		/* UNC are already converted to host byte order... */
-		return put_user(unc_count,(__u32 __user *) arg);
-	}
-	case FE_SET_FRONTEND:
-	{
-		struct dvbt_set_parameters_msg *param = &cinergyt2->param;
-		struct dvb_frontend_parameters p;
-		int err;
-
-		if ((file->f_flags & O_ACCMODE) == O_RDONLY)
-			return -EPERM;
-
-		if (copy_from_user(&p, (void  __user*) arg, sizeof(p)))
-			return -EFAULT;
-
-		if (cinergyt2->disconnect_pending)
-			return -EAGAIN;
-		if (mutex_lock_interruptible(&cinergyt2->sem))
-			return -ERESTARTSYS;
-
-		param->cmd = CINERGYT2_EP1_SET_TUNER_PARAMETERS;
-		param->tps = cpu_to_le16(compute_tps(&p));
-		param->freq = cpu_to_le32(p.frequency / 1000);
-		param->bandwidth = 8 - p.u.ofdm.bandwidth - BANDWIDTH_8_MHZ;
-
-		stat->lock_bits = 0;
-		cinergyt2->pending_fe_events++;
-		wake_up_interruptible(&cinergyt2->poll_wq);
-
-		err = cinergyt2_command(cinergyt2,
-					(char *) param, sizeof(*param),
-					NULL, 0);
-
-		mutex_unlock(&cinergyt2->sem);
-
-		return (err < 0) ? err : 0;
-	}
-
-	case FE_GET_FRONTEND:
-		/**
-		 *  trivial to implement (see struct dvbt_get_status_msg).
-		 *  equivalent to FE_READ ioctls, but needs
-		 *  TPS -> linux-dvb parameter set conversion. Feel free
-		 *  to implement this and send us a patch if you need this
-		 *  functionality.
-		 */
-		break;
-
-	case FE_GET_EVENT:
-	{
-		/**
-		 *  for now we only fill the status field. the parameters
-		 *  are trivial to fill as soon FE_GET_FRONTEND is done.
-		 */
-		struct dvb_frontend_event __user *e = (void __user *) arg;
-		if (cinergyt2->pending_fe_events == 0) {
-			if (file->f_flags & O_NONBLOCK)
-				return -EWOULDBLOCK;
-			wait_event_interruptible(cinergyt2->poll_wq,
-						 cinergyt2->pending_fe_events > 0);
-		}
-		cinergyt2->pending_fe_events = 0;
-		return cinergyt2_ioctl(inode, file, FE_READ_STATUS,
-					(unsigned long) &e->status);
-	}
-
-	default:
-		;
-	}
-
-	return -EINVAL;
-}
-
-static int cinergyt2_mmap(struct file *file, struct vm_area_struct *vma)
-{
-	struct dvb_device *dvbdev = file->private_data;
-	struct cinergyt2 *cinergyt2 = dvbdev->priv;
-	int ret = 0;
-
-	lock_kernel();
-
-	if (vma->vm_flags & (VM_WRITE | VM_EXEC)) {
-		ret = -EPERM;
-		goto bailout;
-	}
-
-	if (vma->vm_end > vma->vm_start + STREAM_URB_COUNT * STREAM_BUF_SIZE) {
-		ret = -EINVAL;
-		goto bailout;
-	}
-
-	vma->vm_flags |= (VM_IO | VM_DONTCOPY);
-	vma->vm_file = file;
-
-	ret = remap_pfn_range(vma, vma->vm_start,
-			      virt_to_phys(cinergyt2->streambuf) >> PAGE_SHIFT,
-			      vma->vm_end - vma->vm_start,
-			      vma->vm_page_prot) ? -EAGAIN : 0;
-bailout:
-	unlock_kernel();
-	return ret;
-}
-
-static struct file_operations cinergyt2_fops = {
-	.owner          = THIS_MODULE,
-	.ioctl		= cinergyt2_ioctl,
-	.poll           = cinergyt2_poll,
-	.open           = cinergyt2_open,
-	.release        = cinergyt2_release,
-	.mmap		= cinergyt2_mmap
-};
-
-static struct dvb_device cinergyt2_fe_template = {
-	.users = ~0,
-	.writers = 1,
-	.readers = (~0)-1,
-	.fops = &cinergyt2_fops
-};
-
-#ifdef ENABLE_RC
-
-static void cinergyt2_query_rc (struct work_struct *work)
-{
-	struct cinergyt2 *cinergyt2 =
-		container_of(work, struct cinergyt2, rc_query_work.work);
-	char buf[1] = { CINERGYT2_EP1_GET_RC_EVENTS };
-	struct cinergyt2_rc_event rc_events[12];
-	int n, len, i;
-
-	if (cinergyt2->disconnect_pending || mutex_lock_interruptible(&cinergyt2->sem))
-		return;
-
-	len = cinergyt2_command(cinergyt2, buf, sizeof(buf),
-				(char *) rc_events, sizeof(rc_events));
-	if (len < 0)
-		goto out;
-	if (len == 0) {
-		if (time_after(jiffies, cinergyt2->last_event_jiffies +
-			       msecs_to_jiffies(150))) {
-			/* stop key repeat */
-			if (cinergyt2->rc_input_event != KEY_MAX) {
-				dprintk(1, "rc_input_event=%d Up\n", cinergyt2->rc_input_event);
-				input_report_key(cinergyt2->rc_input_dev,
-						 cinergyt2->rc_input_event, 0);
-				input_sync(cinergyt2->rc_input_dev);
-				cinergyt2->rc_input_event = KEY_MAX;
-			}
-			cinergyt2->rc_last_code = cpu_to_le32(~0);
-		}
-		goto out;
-	}
-	cinergyt2->last_event_jiffies = jiffies;
-
-	for (n = 0; n < (len / sizeof(rc_events[0])); n++) {
-		dprintk(1, "rc_events[%d].value = %x, type=%x\n",
-			n, le32_to_cpu(rc_events[n].value), rc_events[n].type);
-
-		if (rc_events[n].type == CINERGYT2_RC_EVENT_TYPE_NEC &&
-		    rc_events[n].value == cpu_to_le32(~0)) {
-			/* keyrepeat bit -> just repeat last rc_input_event */
-		} else {
-			cinergyt2->rc_input_event = KEY_MAX;
-			for (i = 0; i < ARRAY_SIZE(rc_keys); i += 3) {
-				if (rc_keys[i + 0] == rc_events[n].type &&
-				    rc_keys[i + 1] == le32_to_cpu(rc_events[n].value)) {
-					cinergyt2->rc_input_event = rc_keys[i + 2];
-					break;
-				}
-			}
-		}
-
-		if (cinergyt2->rc_input_event != KEY_MAX) {
-			if (rc_events[n].value == cinergyt2->rc_last_code &&
-			    cinergyt2->rc_last_code != cpu_to_le32(~0)) {
-				/* emit a key-up so the double event is recognized */
-				dprintk(1, "rc_input_event=%d UP\n", cinergyt2->rc_input_event);
-				input_report_key(cinergyt2->rc_input_dev,
-						 cinergyt2->rc_input_event, 0);
-			}
-			dprintk(1, "rc_input_event=%d\n", cinergyt2->rc_input_event);
-			input_report_key(cinergyt2->rc_input_dev,
-					 cinergyt2->rc_input_event, 1);
-			input_sync(cinergyt2->rc_input_dev);
-			cinergyt2->rc_last_code = rc_events[n].value;
-		}
-	}
-
-out:
-	schedule_delayed_work(&cinergyt2->rc_query_work,
-			      msecs_to_jiffies(RC_QUERY_INTERVAL));
-
-	mutex_unlock(&cinergyt2->sem);
-}
-
-static int cinergyt2_register_rc(struct cinergyt2 *cinergyt2)
-{
-	struct input_dev *input_dev;
-	int i;
-	int err;
-
-	input_dev = input_allocate_device();
-	if (!input_dev)
-		return -ENOMEM;
-
-	usb_make_path(cinergyt2->udev, cinergyt2->phys, sizeof(cinergyt2->phys));
-	strlcat(cinergyt2->phys, "/input0", sizeof(cinergyt2->phys));
-	cinergyt2->rc_input_event = KEY_MAX;
-	cinergyt2->rc_last_code = cpu_to_le32(~0);
-	INIT_DELAYED_WORK(&cinergyt2->rc_query_work, cinergyt2_query_rc);
-
-	input_dev->name = DRIVER_NAME " remote control";
-	input_dev->phys = cinergyt2->phys;
-	input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP);
-	for (i = 0; i < ARRAY_SIZE(rc_keys); i += 3)
-		set_bit(rc_keys[i + 2], input_dev->keybit);
-	input_dev->keycodesize = 0;
-	input_dev->keycodemax = 0;
-	input_dev->id.bustype = BUS_USB;
-	input_dev->id.vendor = le16_to_cpu(cinergyt2->udev->descriptor.idVendor);
-	input_dev->id.product = le16_to_cpu(cinergyt2->udev->descriptor.idProduct);
-	input_dev->id.version = 1;
-	input_dev->dev.parent = &cinergyt2->udev->dev;
-
-	err = input_register_device(input_dev);
-	if (err) {
-		input_free_device(input_dev);
-		return err;
-	}
-
-	cinergyt2->rc_input_dev = input_dev;
-	schedule_delayed_work(&cinergyt2->rc_query_work, HZ/2);
-
-	return 0;
-}
-
-static void cinergyt2_unregister_rc(struct cinergyt2 *cinergyt2)
-{
-	cancel_rearming_delayed_work(&cinergyt2->rc_query_work);
-	input_unregister_device(cinergyt2->rc_input_dev);
-}
-
-static inline void cinergyt2_suspend_rc(struct cinergyt2 *cinergyt2)
-{
-	cancel_rearming_delayed_work(&cinergyt2->rc_query_work);
-}
-
-static inline void cinergyt2_resume_rc(struct cinergyt2 *cinergyt2)
-{
-	schedule_delayed_work(&cinergyt2->rc_query_work, HZ/2);
-}
-
-#else
-
-static inline int cinergyt2_register_rc(struct cinergyt2 *cinergyt2) { return 0; }
-static inline void cinergyt2_unregister_rc(struct cinergyt2 *cinergyt2) { }
-static inline void cinergyt2_suspend_rc(struct cinergyt2 *cinergyt2) { }
-static inline void cinergyt2_resume_rc(struct cinergyt2 *cinergyt2) { }
-
-#endif /* ENABLE_RC */
-
-static void cinergyt2_query (struct work_struct *work)
-{
-	struct cinergyt2 *cinergyt2 =
-		container_of(work, struct cinergyt2, query_work.work);
-	char cmd [] = { CINERGYT2_EP1_GET_TUNER_STATUS };
-	struct dvbt_get_status_msg *s = &cinergyt2->status;
-	uint8_t lock_bits;
-
-	if (cinergyt2->disconnect_pending || mutex_lock_interruptible(&cinergyt2->sem))
-		return;
-
-	lock_bits = s->lock_bits;
-
-	cinergyt2_command(cinergyt2, cmd, sizeof(cmd), (char *) s, sizeof(*s));
-
-	cinergyt2->uncorrected_block_count +=
-		le32_to_cpu(s->uncorrected_block_count);
-
-	if (lock_bits != s->lock_bits) {
-		wake_up_interruptible(&cinergyt2->poll_wq);
-		cinergyt2->pending_fe_events++;
-	}
-
-	schedule_delayed_work(&cinergyt2->query_work,
-			      msecs_to_jiffies(QUERY_INTERVAL));
-
-	mutex_unlock(&cinergyt2->sem);
-}
-
-static int cinergyt2_probe (struct usb_interface *intf,
-		  const struct usb_device_id *id)
-{
-	struct cinergyt2 *cinergyt2;
-	int err;
-
-	if (!(cinergyt2 = kzalloc (sizeof(struct cinergyt2), GFP_KERNEL))) {
-		dprintk(1, "out of memory?!?\n");
-		return -ENOMEM;
-	}
-
-	usb_set_intfdata (intf, (void *) cinergyt2);
-
-	mutex_init(&cinergyt2->sem);
-	mutex_init(&cinergyt2->wq_sem);
-	init_waitqueue_head (&cinergyt2->poll_wq);
-	INIT_DELAYED_WORK(&cinergyt2->query_work, cinergyt2_query);
-
-	cinergyt2->udev = interface_to_usbdev(intf);
-	cinergyt2->param.cmd = CINERGYT2_EP1_SET_TUNER_PARAMETERS;
-
-	if (cinergyt2_alloc_stream_urbs (cinergyt2) < 0) {
-		dprintk(1, "unable to allocate stream urbs\n");
-		kfree(cinergyt2);
-		return -ENOMEM;
-	}
-
-	err = dvb_register_adapter(&cinergyt2->adapter, DRIVER_NAME,
-				   THIS_MODULE, &cinergyt2->udev->dev,
-				   adapter_nr);
-	if (err < 0) {
-		kfree(cinergyt2);
-		return err;
-	}
-
-	cinergyt2->demux.priv = cinergyt2;
-	cinergyt2->demux.filternum = 256;
-	cinergyt2->demux.feednum = 256;
-	cinergyt2->demux.start_feed = cinergyt2_start_feed;
-	cinergyt2->demux.stop_feed = cinergyt2_stop_feed;
-	cinergyt2->demux.dmx.capabilities = DMX_TS_FILTERING |
-					    DMX_SECTION_FILTERING |
-					    DMX_MEMORY_BASED_FILTERING;
-
-	if ((err = dvb_dmx_init(&cinergyt2->demux)) < 0) {
-		dprintk(1, "dvb_dmx_init() failed (err = %d)\n", err);
-		goto bailout;
-	}
-
-	cinergyt2->dmxdev.filternum = cinergyt2->demux.filternum;
-	cinergyt2->dmxdev.demux = &cinergyt2->demux.dmx;
-	cinergyt2->dmxdev.capabilities = 0;
-
-	if ((err = dvb_dmxdev_init(&cinergyt2->dmxdev, &cinergyt2->adapter)) < 0) {
-		dprintk(1, "dvb_dmxdev_init() failed (err = %d)\n", err);
-		goto bailout;
-	}
-
-	if (dvb_net_init(&cinergyt2->adapter, &cinergyt2->dvbnet, &cinergyt2->demux.dmx))
-		dprintk(1, "dvb_net_init() failed!\n");
-
-	dvb_register_device(&cinergyt2->adapter, &cinergyt2->fedev,
-			    &cinergyt2_fe_template, cinergyt2,
-			    DVB_DEVICE_FRONTEND);
-
-	err = cinergyt2_register_rc(cinergyt2);
-	if (err)
-		goto bailout;
-
-	return 0;
-
-bailout:
-	dvb_net_release(&cinergyt2->dvbnet);
-	dvb_dmxdev_release(&cinergyt2->dmxdev);
-	dvb_dmx_release(&cinergyt2->demux);
-	dvb_unregister_adapter(&cinergyt2->adapter);
-	cinergyt2_free_stream_urbs(cinergyt2);
-	kfree(cinergyt2);
-	return -ENOMEM;
-}
-
-static void cinergyt2_disconnect (struct usb_interface *intf)
-{
-	struct cinergyt2 *cinergyt2 = usb_get_intfdata (intf);
-
-	cinergyt2_unregister_rc(cinergyt2);
-	cancel_rearming_delayed_work(&cinergyt2->query_work);
-	wake_up_interruptible(&cinergyt2->poll_wq);
-
-	cinergyt2->demux.dmx.close(&cinergyt2->demux.dmx);
-	cinergyt2->disconnect_pending = 1;
-
-	if (!atomic_read(&cinergyt2->inuse))
-		cinergyt2_unregister(cinergyt2);
-}
-
-static int cinergyt2_suspend (struct usb_interface *intf, pm_message_t state)
-{
-	struct cinergyt2 *cinergyt2 = usb_get_intfdata (intf);
-
-	if (cinergyt2->disconnect_pending)
-		return -EAGAIN;
-	if (mutex_lock_interruptible(&cinergyt2->wq_sem))
-		return -ERESTARTSYS;
-
-	cinergyt2_suspend_rc(cinergyt2);
-	cancel_rearming_delayed_work(&cinergyt2->query_work);
-
-	mutex_lock(&cinergyt2->sem);
-	if (cinergyt2->streaming)
-		cinergyt2_stop_stream_xfer(cinergyt2);
-	cinergyt2_sleep(cinergyt2, 1);
-	mutex_unlock(&cinergyt2->sem);
-
-	mutex_unlock(&cinergyt2->wq_sem);
-
-	return 0;
-}
-
-static int cinergyt2_resume (struct usb_interface *intf)
-{
-	struct cinergyt2 *cinergyt2 = usb_get_intfdata (intf);
-	struct dvbt_set_parameters_msg *param = &cinergyt2->param;
-	int err = -EAGAIN;
-
-	if (cinergyt2->disconnect_pending)
-		goto out;
-	err = mutex_lock_interruptible(&cinergyt2->wq_sem);
-	if (err)
-		goto out;
-
-	err = mutex_lock_interruptible(&cinergyt2->sem);
-	if (err)
-		goto out_unlock1;
-
-	if (!cinergyt2->sleeping) {
-		cinergyt2_sleep(cinergyt2, 0);
-		cinergyt2_command(cinergyt2, (char *) param, sizeof(*param), NULL, 0);
-		if (cinergyt2->streaming)
-			cinergyt2_start_stream_xfer(cinergyt2);
-		schedule_delayed_work(&cinergyt2->query_work, HZ/2);
-	}
-
-	cinergyt2_resume_rc(cinergyt2);
-
-	mutex_unlock(&cinergyt2->sem);
-out_unlock1:
-	mutex_unlock(&cinergyt2->wq_sem);
-out:
-	return err;
-}
-
-static const struct usb_device_id cinergyt2_table [] __devinitdata = {
-	{ USB_DEVICE(0x0ccd, 0x0038) },
-	{ 0 }
-};
-
-MODULE_DEVICE_TABLE(usb, cinergyt2_table);
-
-static struct usb_driver cinergyt2_driver = {
-	.name	= "cinergyT2",
-	.probe	= cinergyt2_probe,
-	.disconnect	= cinergyt2_disconnect,
-	.suspend	= cinergyt2_suspend,
-	.resume		= cinergyt2_resume,
-	.id_table	= cinergyt2_table
-};
-
-static int __init cinergyt2_init (void)
-{
-	int err;
-
-	if ((err = usb_register(&cinergyt2_driver)) < 0)
-		dprintk(1, "usb_register() failed! (err %i)\n", err);
-
-	return err;
-}
-
-static void __exit cinergyt2_exit (void)
-{
-	usb_deregister(&cinergyt2_driver);
-}
-
-module_init (cinergyt2_init);
-module_exit (cinergyt2_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Holger Waechtler, Daniel Mack");
diff --git a/drivers/media/dvb/dm1105/Kconfig b/drivers/media/dvb/dm1105/Kconfig
new file mode 100644
index 0000000..1332301
--- /dev/null
+++ b/drivers/media/dvb/dm1105/Kconfig
@@ -0,0 +1,18 @@
+config DVB_DM1105
+	tristate "SDMC DM1105 based PCI cards"
+	depends on DVB_CORE && PCI && I2C
+	select DVB_PLL if !DVB_FE_CUSTOMISE
+	select DVB_STV0299 if !DVB_FE_CUSTOMISE
+	select DVB_STV0288 if !DVB_FE_CUSTOMISE
+	select DVB_STB6000 if !DVB_FE_CUSTOMISE
+	select DVB_CX24116 if !DVB_FE_CUSTOMISE
+	select DVB_SI21XX if !DVB_FE_CUSTOMISE
+	help
+	  Support for cards based on the SDMC DM1105 PCI chip like
+	  DvbWorld 2002
+
+	  Since these cards have no MPEG decoder onboard, they transmit
+	  only compressed MPEG data over the PCI bus, so you need
+	  an external software decoder to watch TV on your computer.
+
+	  Say Y or M if you own such a device and want to use it.
diff --git a/drivers/media/dvb/dm1105/Makefile b/drivers/media/dvb/dm1105/Makefile
new file mode 100644
index 0000000..8ac28b0
--- /dev/null
+++ b/drivers/media/dvb/dm1105/Makefile
@@ -0,0 +1,3 @@
+obj-$(CONFIG_DVB_DM1105) += dm1105.o
+
+EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends
diff --git a/drivers/media/dvb/dm1105/dm1105.c b/drivers/media/dvb/dm1105/dm1105.c
new file mode 100644
index 0000000..f732144
--- /dev/null
+++ b/drivers/media/dvb/dm1105/dm1105.c
@@ -0,0 +1,911 @@
+/*
+ * dm1105.c - driver for DVB cards based on SDMC DM1105 PCI chip
+ *
+ * Copyright (C) 2008 Igor M. Liplianin <liplianin@me.by>
+ *
+ * This program is free software; you can redistribute it and/or 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/version.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/proc_fs.h>
+#include <linux/pci.h>
+#include <linux/dma-mapping.h>
+#include <linux/input.h>
+#include <media/ir-common.h>
+
+#include "demux.h"
+#include "dmxdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "dvb_net.h"
+#include "dvbdev.h"
+#include "dvb-pll.h"
+
+#include "stv0299.h"
+#include "stv0288.h"
+#include "stb6000.h"
+#include "si21xx.h"
+#include "cx24116.h"
+#include "z0194a.h"
+
+/* ----------------------------------------------- */
+/*
+ * PCI ID's
+ */
+#ifndef PCI_VENDOR_ID_TRIGEM
+#define PCI_VENDOR_ID_TRIGEM	0x109f
+#endif
+#ifndef PCI_DEVICE_ID_DM1105
+#define PCI_DEVICE_ID_DM1105	0x036f
+#endif
+#ifndef PCI_DEVICE_ID_DW2002
+#define PCI_DEVICE_ID_DW2002	0x2002
+#endif
+#ifndef PCI_DEVICE_ID_DW2004
+#define PCI_DEVICE_ID_DW2004	0x2004
+#endif
+/* ----------------------------------------------- */
+/* sdmc dm1105 registers */
+
+/* TS Control */
+#define DM1105_TSCTR				0x00
+#define DM1105_DTALENTH				0x04
+
+/* GPIO Interface */
+#define DM1105_GPIOVAL				0x08
+#define DM1105_GPIOCTR				0x0c
+
+/* PID serial number */
+#define DM1105_PIDN				0x10
+
+/* Odd-even secret key select */
+#define DM1105_CWSEL				0x14
+
+/* Host Command Interface */
+#define DM1105_HOST_CTR				0x18
+#define DM1105_HOST_AD				0x1c
+
+/* PCI Interface */
+#define DM1105_CR				0x30
+#define DM1105_RST				0x34
+#define DM1105_STADR				0x38
+#define DM1105_RLEN				0x3c
+#define DM1105_WRP				0x40
+#define DM1105_INTCNT				0x44
+#define DM1105_INTMAK				0x48
+#define DM1105_INTSTS				0x4c
+
+/* CW Value */
+#define DM1105_ODD				0x50
+#define DM1105_EVEN				0x58
+
+/* PID Value */
+#define DM1105_PID				0x60
+
+/* IR Control */
+#define DM1105_IRCTR				0x64
+#define DM1105_IRMODE				0x68
+#define DM1105_SYSTEMCODE			0x6c
+#define DM1105_IRCODE				0x70
+
+/* Unknown Values */
+#define DM1105_ENCRYPT				0x74
+#define DM1105_VER				0x7c
+
+/* I2C Interface */
+#define DM1105_I2CCTR				0x80
+#define DM1105_I2CSTS				0x81
+#define DM1105_I2CDAT				0x82
+#define DM1105_I2C_RA				0x83
+/* ----------------------------------------------- */
+/* Interrupt Mask Bits */
+
+#define INTMAK_TSIRQM				0x01
+#define INTMAK_HIRQM				0x04
+#define INTMAK_IRM				0x08
+#define INTMAK_ALLMASK				(INTMAK_TSIRQM | \
+						INTMAK_HIRQM | \
+						INTMAK_IRM)
+#define INTMAK_NONEMASK				0x00
+
+/* Interrupt Status Bits */
+#define INTSTS_TSIRQ				0x01
+#define INTSTS_HIRQ				0x04
+#define INTSTS_IR				0x08
+
+/* IR Control Bits */
+#define DM1105_IR_EN				0x01
+#define DM1105_SYS_CHK				0x02
+#define DM1105_REP_FLG				0x08
+
+/* EEPROM addr */
+#define IIC_24C01_addr				0xa0
+/* Max board count */
+#define DM1105_MAX				0x04
+
+#define DRIVER_NAME				"dm1105"
+
+#define DM1105_DMA_PACKETS			47
+#define DM1105_DMA_PACKET_LENGTH		(128*4)
+#define DM1105_DMA_BYTES			(128 * 4 * DM1105_DMA_PACKETS)
+
+/* GPIO's for LNB power control */
+#define DM1105_LNB_MASK				0x00000000
+#define DM1105_LNB_13V				0x00010100
+#define DM1105_LNB_18V				0x00000100
+
+static int ir_debug;
+module_param(ir_debug, int, 0644);
+MODULE_PARM_DESC(ir_debug, "enable debugging information for IR decoding");
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+static u16 ir_codes_dm1105_nec[128] = {
+	[0x0a] = KEY_Q,		/*power*/
+	[0x0c] = KEY_M,		/*mute*/
+	[0x11] = KEY_1,
+	[0x12] = KEY_2,
+	[0x13] = KEY_3,
+	[0x14] = KEY_4,
+	[0x15] = KEY_5,
+	[0x16] = KEY_6,
+	[0x17] = KEY_7,
+	[0x18] = KEY_8,
+	[0x19] = KEY_9,
+	[0x10] = KEY_0,
+	[0x1c] = KEY_PAGEUP,	/*ch+*/
+	[0x0f] = KEY_PAGEDOWN,	/*ch-*/
+	[0x1a] = KEY_O,		/*vol+*/
+	[0x0e] = KEY_Z,		/*vol-*/
+	[0x04] = KEY_R,		/*rec*/
+	[0x09] = KEY_D,		/*fav*/
+	[0x08] = KEY_BACKSPACE,	/*rewind*/
+	[0x07] = KEY_A,		/*fast*/
+	[0x0b] = KEY_P,		/*pause*/
+	[0x02] = KEY_ESC,	/*cancel*/
+	[0x03] = KEY_G,		/*tab*/
+	[0x00] = KEY_UP,	/*up*/
+	[0x1f] = KEY_ENTER,	/*ok*/
+	[0x01] = KEY_DOWN,	/*down*/
+	[0x05] = KEY_C,		/*cap*/
+	[0x06] = KEY_S,		/*stop*/
+	[0x40] = KEY_F,		/*full*/
+	[0x1e] = KEY_W,		/*tvmode*/
+	[0x1b] = KEY_B,		/*recall*/
+};
+
+/* infrared remote control */
+struct infrared {
+	u16	key_map[128];
+	struct input_dev	*input_dev;
+	char			input_phys[32];
+	struct tasklet_struct	ir_tasklet;
+	u32			ir_command;
+};
+
+struct dm1105dvb {
+	/* pci */
+	struct pci_dev *pdev;
+	u8 __iomem *io_mem;
+
+	/* ir */
+	struct infrared ir;
+
+	/* dvb */
+	struct dmx_frontend hw_frontend;
+	struct dmx_frontend mem_frontend;
+	struct dmxdev dmxdev;
+	struct dvb_adapter dvb_adapter;
+	struct dvb_demux demux;
+	struct dvb_frontend *fe;
+	struct dvb_net dvbnet;
+	unsigned int full_ts_users;
+
+	/* i2c */
+	struct i2c_adapter i2c_adap;
+
+	/* dma */
+	dma_addr_t dma_addr;
+	unsigned char *ts_buf;
+	u32 wrp;
+	u32 buffer_size;
+	unsigned int	PacketErrorCount;
+	unsigned int dmarst;
+	spinlock_t lock;
+
+};
+
+#define dm_io_mem(reg)	((unsigned long)(&dm1105dvb->io_mem[reg]))
+
+static struct dm1105dvb *dm1105dvb_local;
+
+static int dm1105_i2c_xfer(struct i2c_adapter *i2c_adap,
+			    struct i2c_msg *msgs, int num)
+{
+	struct dm1105dvb *dm1105dvb ;
+
+	int addr, rc, i, j, k, len, byte, data;
+	u8 status;
+
+	dm1105dvb = i2c_adap->algo_data;
+	for (i = 0; i < num; i++) {
+		outb(0x00, dm_io_mem(DM1105_I2CCTR));
+		if (msgs[i].flags & I2C_M_RD) {
+			/* read bytes */
+			addr  = msgs[i].addr << 1;
+			addr |= 1;
+			outb(addr, dm_io_mem(DM1105_I2CDAT));
+			for (byte = 0; byte < msgs[i].len; byte++)
+				outb(0, dm_io_mem(DM1105_I2CDAT + byte + 1));
+
+			outb(0x81 + msgs[i].len, dm_io_mem(DM1105_I2CCTR));
+			for (j = 0; j < 55; j++) {
+				mdelay(10);
+				status = inb(dm_io_mem(DM1105_I2CSTS));
+				if ((status & 0xc0) == 0x40)
+					break;
+			}
+			if (j >= 55)
+				return -1;
+
+			for (byte = 0; byte < msgs[i].len; byte++) {
+				rc = inb(dm_io_mem(DM1105_I2CDAT + byte + 1));
+				if (rc < 0)
+					goto err;
+				msgs[i].buf[byte] = rc;
+			}
+		} else {
+			if ((msgs[i].buf[0] == 0xf7) && (msgs[i].addr == 0x55)) {
+				/* prepaired for cx24116 firmware */
+				/* Write in small blocks */
+				len = msgs[i].len - 1;
+				k = 1;
+				do {
+					outb(msgs[i].addr << 1, dm_io_mem(DM1105_I2CDAT));
+					outb(0xf7, dm_io_mem(DM1105_I2CDAT + 1));
+					for (byte = 0; byte < (len > 48 ? 48 : len); byte++) {
+						data = msgs[i].buf[k+byte];
+						outb(data, dm_io_mem(DM1105_I2CDAT + byte + 2));
+					}
+					outb(0x82 + (len > 48 ? 48 : len), dm_io_mem(DM1105_I2CCTR));
+					for (j = 0; j < 25; j++) {
+						mdelay(10);
+						status = inb(dm_io_mem(DM1105_I2CSTS));
+						if ((status & 0xc0) == 0x40)
+							break;
+					}
+
+					if (j >= 25)
+						return -1;
+
+					k += 48;
+					len -= 48;
+				} while (len > 0);
+			} else {
+				/* write bytes */
+				outb(msgs[i].addr<<1, dm_io_mem(DM1105_I2CDAT));
+				for (byte = 0; byte < msgs[i].len; byte++) {
+					data = msgs[i].buf[byte];
+					outb(data, dm_io_mem(DM1105_I2CDAT + byte + 1));
+				}
+				outb(0x81 + msgs[i].len, dm_io_mem(DM1105_I2CCTR));
+				for (j = 0; j < 25; j++) {
+					mdelay(10);
+					status = inb(dm_io_mem(DM1105_I2CSTS));
+					if ((status & 0xc0) == 0x40)
+						break;
+				}
+
+				if (j >= 25)
+					return -1;
+			}
+		}
+	}
+	return num;
+ err:
+	return rc;
+}
+
+static u32 functionality(struct i2c_adapter *adap)
+{
+	return I2C_FUNC_I2C;
+}
+
+static struct i2c_algorithm dm1105_algo = {
+	.master_xfer   = dm1105_i2c_xfer,
+	.functionality = functionality,
+};
+
+static inline struct dm1105dvb *feed_to_dm1105dvb(struct dvb_demux_feed *feed)
+{
+	return container_of(feed->demux, struct dm1105dvb, demux);
+}
+
+static inline struct dm1105dvb *frontend_to_dm1105dvb(struct dvb_frontend *fe)
+{
+	return container_of(fe->dvb, struct dm1105dvb, dvb_adapter);
+}
+
+static int dm1105dvb_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
+{
+	struct dm1105dvb *dm1105dvb = frontend_to_dm1105dvb(fe);
+
+		if (voltage == SEC_VOLTAGE_18) {
+			outl(DM1105_LNB_MASK, dm_io_mem(DM1105_GPIOCTR));
+			outl(DM1105_LNB_18V, dm_io_mem(DM1105_GPIOVAL));
+		} else	{
+		/*LNB ON-13V by default!*/
+			outl(DM1105_LNB_MASK, dm_io_mem(DM1105_GPIOCTR));
+			outl(DM1105_LNB_13V, dm_io_mem(DM1105_GPIOVAL));
+		}
+
+	return 0;
+}
+
+static void dm1105dvb_set_dma_addr(struct dm1105dvb *dm1105dvb)
+{
+	outl(cpu_to_le32(dm1105dvb->dma_addr), dm_io_mem(DM1105_STADR));
+}
+
+static int __devinit dm1105dvb_dma_map(struct dm1105dvb *dm1105dvb)
+{
+	dm1105dvb->ts_buf = pci_alloc_consistent(dm1105dvb->pdev, 6*DM1105_DMA_BYTES, &dm1105dvb->dma_addr);
+
+	return pci_dma_mapping_error(dm1105dvb->pdev, dm1105dvb->dma_addr);
+}
+
+static void dm1105dvb_dma_unmap(struct dm1105dvb *dm1105dvb)
+{
+	pci_free_consistent(dm1105dvb->pdev, 6*DM1105_DMA_BYTES, dm1105dvb->ts_buf, dm1105dvb->dma_addr);
+}
+
+static void __devinit dm1105dvb_enable_irqs(struct dm1105dvb *dm1105dvb)
+{
+	outb(INTMAK_ALLMASK, dm_io_mem(DM1105_INTMAK));
+	outb(1, dm_io_mem(DM1105_CR));
+}
+
+static void dm1105dvb_disable_irqs(struct dm1105dvb *dm1105dvb)
+{
+	outb(INTMAK_IRM, dm_io_mem(DM1105_INTMAK));
+	outb(0, dm_io_mem(DM1105_CR));
+}
+
+static int dm1105dvb_start_feed(struct dvb_demux_feed *f)
+{
+	struct dm1105dvb *dm1105dvb = feed_to_dm1105dvb(f);
+
+	if (dm1105dvb->full_ts_users++ == 0)
+		dm1105dvb_enable_irqs(dm1105dvb);
+
+	return 0;
+}
+
+static int dm1105dvb_stop_feed(struct dvb_demux_feed *f)
+{
+	struct dm1105dvb *dm1105dvb = feed_to_dm1105dvb(f);
+
+	if (--dm1105dvb->full_ts_users == 0)
+		dm1105dvb_disable_irqs(dm1105dvb);
+
+	return 0;
+}
+
+/* ir tasklet */
+static void dm1105_emit_key(unsigned long parm)
+{
+	struct infrared *ir = (struct infrared *) parm;
+	u32 ircom = ir->ir_command;
+	u8 data;
+	u16 keycode;
+
+	data = (ircom >> 8) & 0x7f;
+
+	input_event(ir->input_dev, EV_MSC, MSC_RAW, (0x0000f8 << 16) | data);
+	input_event(ir->input_dev, EV_MSC, MSC_SCAN, data);
+	keycode = ir->key_map[data];
+
+	if (!keycode)
+		return;
+
+	input_event(ir->input_dev, EV_KEY, keycode, 1);
+	input_sync(ir->input_dev);
+	input_event(ir->input_dev, EV_KEY, keycode, 0);
+	input_sync(ir->input_dev);
+
+}
+
+static irqreturn_t dm1105dvb_irq(int irq, void *dev_id)
+{
+	struct dm1105dvb *dm1105dvb = dev_id;
+	unsigned int piece;
+	unsigned int nbpackets;
+	u32 command;
+	u32 nextwrp;
+	u32 oldwrp;
+
+	/* Read-Write INSTS Ack's Interrupt for DM1105 chip 16.03.2008 */
+	unsigned int intsts = inb(dm_io_mem(DM1105_INTSTS));
+	outb(intsts, dm_io_mem(DM1105_INTSTS));
+
+	switch (intsts) {
+	case INTSTS_TSIRQ:
+	case (INTSTS_TSIRQ | INTSTS_IR):
+		nextwrp = inl(dm_io_mem(DM1105_WRP)) -
+			inl(dm_io_mem(DM1105_STADR)) ;
+		oldwrp = dm1105dvb->wrp;
+		spin_lock(&dm1105dvb->lock);
+		if (!((dm1105dvb->ts_buf[oldwrp] == 0x47) &&
+				(dm1105dvb->ts_buf[oldwrp + 188] == 0x47) &&
+				(dm1105dvb->ts_buf[oldwrp + 188 * 2] == 0x47))) {
+			dm1105dvb->PacketErrorCount++;
+			/* bad packet found */
+			if ((dm1105dvb->PacketErrorCount >= 2) &&
+					(dm1105dvb->dmarst == 0)) {
+				outb(1, dm_io_mem(DM1105_RST));
+				dm1105dvb->wrp = 0;
+				dm1105dvb->PacketErrorCount = 0;
+				dm1105dvb->dmarst = 0;
+				spin_unlock(&dm1105dvb->lock);
+				return IRQ_HANDLED;
+			}
+		}
+		if (nextwrp < oldwrp) {
+			piece = dm1105dvb->buffer_size - oldwrp;
+			memcpy(dm1105dvb->ts_buf + dm1105dvb->buffer_size, dm1105dvb->ts_buf, nextwrp);
+			nbpackets = (piece + nextwrp)/188;
+		} else	{
+			nbpackets = (nextwrp - oldwrp)/188;
+		}
+		dvb_dmx_swfilter_packets(&dm1105dvb->demux, &dm1105dvb->ts_buf[oldwrp], nbpackets);
+		dm1105dvb->wrp = nextwrp;
+		spin_unlock(&dm1105dvb->lock);
+		break;
+	case INTSTS_IR:
+		command = inl(dm_io_mem(DM1105_IRCODE));
+		if (ir_debug)
+			printk("dm1105: received byte 0x%04x\n", command);
+
+		dm1105dvb->ir.ir_command = command;
+		tasklet_schedule(&dm1105dvb->ir.ir_tasklet);
+		break;
+	}
+	return IRQ_HANDLED;
+
+
+}
+
+/* register with input layer */
+static void input_register_keys(struct infrared *ir)
+{
+	int i;
+
+	memset(ir->input_dev->keybit, 0, sizeof(ir->input_dev->keybit));
+
+	for (i = 0; i < ARRAY_SIZE(ir->key_map); i++)
+			set_bit(ir->key_map[i], ir->input_dev->keybit);
+
+	ir->input_dev->keycode = ir->key_map;
+	ir->input_dev->keycodesize = sizeof(ir->key_map[0]);
+	ir->input_dev->keycodemax = ARRAY_SIZE(ir->key_map);
+}
+
+int __devinit dm1105_ir_init(struct dm1105dvb *dm1105)
+{
+	struct input_dev *input_dev;
+	int err;
+
+	dm1105dvb_local = dm1105;
+
+	input_dev = input_allocate_device();
+	if (!input_dev)
+		return -ENOMEM;
+
+	dm1105->ir.input_dev = input_dev;
+	snprintf(dm1105->ir.input_phys, sizeof(dm1105->ir.input_phys),
+		"pci-%s/ir0", pci_name(dm1105->pdev));
+
+	input_dev->evbit[0] = BIT(EV_KEY);
+	input_dev->name = "DVB on-card IR receiver";
+
+	input_dev->phys = dm1105->ir.input_phys;
+	input_dev->id.bustype = BUS_PCI;
+	input_dev->id.version = 2;
+	if (dm1105->pdev->subsystem_vendor) {
+		input_dev->id.vendor = dm1105->pdev->subsystem_vendor;
+		input_dev->id.product = dm1105->pdev->subsystem_device;
+	} else {
+		input_dev->id.vendor = dm1105->pdev->vendor;
+		input_dev->id.product = dm1105->pdev->device;
+	}
+	input_dev->dev.parent = &dm1105->pdev->dev;
+	/* initial keymap */
+	memcpy(dm1105->ir.key_map, ir_codes_dm1105_nec, sizeof dm1105->ir.key_map);
+	input_register_keys(&dm1105->ir);
+	err = input_register_device(input_dev);
+	if (err) {
+		input_free_device(input_dev);
+		return err;
+	}
+
+	tasklet_init(&dm1105->ir.ir_tasklet, dm1105_emit_key, (unsigned long) &dm1105->ir);
+
+	return 0;
+}
+
+
+void __devexit dm1105_ir_exit(struct dm1105dvb *dm1105)
+{
+	tasklet_kill(&dm1105->ir.ir_tasklet);
+	input_unregister_device(dm1105->ir.input_dev);
+
+}
+
+static int __devinit dm1105dvb_hw_init(struct dm1105dvb *dm1105dvb)
+{
+	dm1105dvb_disable_irqs(dm1105dvb);
+
+	outb(0, dm_io_mem(DM1105_HOST_CTR));
+
+	/*DATALEN 188,*/
+	outb(188, dm_io_mem(DM1105_DTALENTH));
+	/*TS_STRT TS_VALP MSBFIRST TS_MODE ALPAS TSPES*/
+	outw(0xc10a, dm_io_mem(DM1105_TSCTR));
+
+	/* map DMA and set address */
+	dm1105dvb_dma_map(dm1105dvb);
+	dm1105dvb_set_dma_addr(dm1105dvb);
+	/* big buffer */
+	outl(5*DM1105_DMA_BYTES, dm_io_mem(DM1105_RLEN));
+	outb(47, dm_io_mem(DM1105_INTCNT));
+
+	/* IR NEC mode enable */
+	outb((DM1105_IR_EN | DM1105_SYS_CHK), dm_io_mem(DM1105_IRCTR));
+	outb(0, dm_io_mem(DM1105_IRMODE));
+	outw(0, dm_io_mem(DM1105_SYSTEMCODE));
+
+	return 0;
+}
+
+static void dm1105dvb_hw_exit(struct dm1105dvb *dm1105dvb)
+{
+	dm1105dvb_disable_irqs(dm1105dvb);
+
+	/* IR disable */
+	outb(0, dm_io_mem(DM1105_IRCTR));
+	outb(INTMAK_NONEMASK, dm_io_mem(DM1105_INTMAK));
+
+	dm1105dvb_dma_unmap(dm1105dvb);
+}
+
+static struct stv0288_config earda_config = {
+	.demod_address = 0x68,
+	.min_delay_ms = 100,
+};
+
+static struct si21xx_config serit_config = {
+	.demod_address = 0x68,
+	.min_delay_ms = 100,
+
+};
+
+static struct cx24116_config serit_sp2633_config = {
+	.demod_address = 0x55,
+};
+
+static int __devinit frontend_init(struct dm1105dvb *dm1105dvb)
+{
+	int ret;
+
+	switch (dm1105dvb->pdev->subsystem_device) {
+	case PCI_DEVICE_ID_DW2002:
+		dm1105dvb->fe = dvb_attach(
+			stv0299_attach, &sharp_z0194a_config,
+			&dm1105dvb->i2c_adap);
+
+		if (dm1105dvb->fe) {
+			dm1105dvb->fe->ops.set_voltage =
+							dm1105dvb_set_voltage;
+			dvb_attach(dvb_pll_attach, dm1105dvb->fe, 0x60,
+					&dm1105dvb->i2c_adap, DVB_PLL_OPERA1);
+		}
+
+		if (!dm1105dvb->fe) {
+			dm1105dvb->fe = dvb_attach(
+				stv0288_attach, &earda_config,
+				&dm1105dvb->i2c_adap);
+			if (dm1105dvb->fe) {
+				dm1105dvb->fe->ops.set_voltage =
+							dm1105dvb_set_voltage;
+				dvb_attach(stb6000_attach, dm1105dvb->fe, 0x61,
+						&dm1105dvb->i2c_adap);
+			}
+		}
+
+		if (!dm1105dvb->fe) {
+			dm1105dvb->fe = dvb_attach(
+				si21xx_attach, &serit_config,
+				&dm1105dvb->i2c_adap);
+			if (dm1105dvb->fe)
+				dm1105dvb->fe->ops.set_voltage =
+							dm1105dvb_set_voltage;
+		}
+		break;
+	case PCI_DEVICE_ID_DW2004:
+		dm1105dvb->fe = dvb_attach(
+			cx24116_attach, &serit_sp2633_config,
+			&dm1105dvb->i2c_adap);
+		if (dm1105dvb->fe)
+			dm1105dvb->fe->ops.set_voltage = dm1105dvb_set_voltage;
+		break;
+	}
+
+	if (!dm1105dvb->fe) {
+		dev_err(&dm1105dvb->pdev->dev, "could not attach frontend\n");
+		return -ENODEV;
+	}
+
+	ret = dvb_register_frontend(&dm1105dvb->dvb_adapter, dm1105dvb->fe);
+	if (ret < 0) {
+		if (dm1105dvb->fe->ops.release)
+			dm1105dvb->fe->ops.release(dm1105dvb->fe);
+		dm1105dvb->fe = NULL;
+		return ret;
+	}
+
+	return 0;
+}
+
+static void __devinit dm1105dvb_read_mac(struct dm1105dvb *dm1105dvb, u8 *mac)
+{
+	static u8 command[1] = { 0x28 };
+
+	struct i2c_msg msg[] = {
+		{ .addr = IIC_24C01_addr >> 1, .flags = 0,
+				.buf = command, .len = 1 },
+		{ .addr = IIC_24C01_addr >> 1, .flags = I2C_M_RD,
+				.buf = mac, .len = 6 },
+	};
+
+	dm1105_i2c_xfer(&dm1105dvb->i2c_adap, msg , 2);
+	dev_info(&dm1105dvb->pdev->dev, "MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
+			mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
+}
+
+static int __devinit dm1105_probe(struct pci_dev *pdev,
+				  const struct pci_device_id *ent)
+{
+	struct dm1105dvb *dm1105dvb;
+	struct dvb_adapter *dvb_adapter;
+	struct dvb_demux *dvbdemux;
+	struct dmx_demux *dmx;
+	int ret = -ENOMEM;
+
+	dm1105dvb = kzalloc(sizeof(struct dm1105dvb), GFP_KERNEL);
+	if (!dm1105dvb)
+		goto out;
+
+	dm1105dvb->pdev = pdev;
+	dm1105dvb->buffer_size = 5 * DM1105_DMA_BYTES;
+	dm1105dvb->PacketErrorCount = 0;
+	dm1105dvb->dmarst = 0;
+
+	ret = pci_enable_device(pdev);
+	if (ret < 0)
+		goto err_kfree;
+
+	ret = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
+	if (ret < 0)
+		goto err_pci_disable_device;
+
+	pci_set_master(pdev);
+
+	ret = pci_request_regions(pdev, DRIVER_NAME);
+	if (ret < 0)
+		goto err_pci_disable_device;
+
+	dm1105dvb->io_mem = pci_iomap(pdev, 0, pci_resource_len(pdev, 0));
+	if (!dm1105dvb->io_mem) {
+		ret = -EIO;
+		goto err_pci_release_regions;
+	}
+
+	spin_lock_init(&dm1105dvb->lock);
+	pci_set_drvdata(pdev, dm1105dvb);
+
+	ret = request_irq(pdev->irq, dm1105dvb_irq, IRQF_SHARED, DRIVER_NAME, dm1105dvb);
+	if (ret < 0)
+		goto err_pci_iounmap;
+
+	ret = dm1105dvb_hw_init(dm1105dvb);
+	if (ret < 0)
+		goto err_free_irq;
+
+	/* i2c */
+	i2c_set_adapdata(&dm1105dvb->i2c_adap, dm1105dvb);
+	strcpy(dm1105dvb->i2c_adap.name, DRIVER_NAME);
+	dm1105dvb->i2c_adap.owner = THIS_MODULE;
+	dm1105dvb->i2c_adap.class = I2C_CLASS_TV_DIGITAL;
+	dm1105dvb->i2c_adap.dev.parent = &pdev->dev;
+	dm1105dvb->i2c_adap.algo = &dm1105_algo;
+	dm1105dvb->i2c_adap.algo_data = dm1105dvb;
+	ret = i2c_add_adapter(&dm1105dvb->i2c_adap);
+
+	if (ret < 0)
+		goto err_dm1105dvb_hw_exit;
+
+	/* dvb */
+	ret = dvb_register_adapter(&dm1105dvb->dvb_adapter, DRIVER_NAME,
+					THIS_MODULE, &pdev->dev, adapter_nr);
+	if (ret < 0)
+		goto err_i2c_del_adapter;
+
+	dvb_adapter = &dm1105dvb->dvb_adapter;
+
+	dm1105dvb_read_mac(dm1105dvb, dvb_adapter->proposed_mac);
+
+	dvbdemux = &dm1105dvb->demux;
+	dvbdemux->filternum = 256;
+	dvbdemux->feednum = 256;
+	dvbdemux->start_feed = dm1105dvb_start_feed;
+	dvbdemux->stop_feed = dm1105dvb_stop_feed;
+	dvbdemux->dmx.capabilities = (DMX_TS_FILTERING |
+			DMX_SECTION_FILTERING | DMX_MEMORY_BASED_FILTERING);
+	ret = dvb_dmx_init(dvbdemux);
+	if (ret < 0)
+		goto err_dvb_unregister_adapter;
+
+	dmx = &dvbdemux->dmx;
+	dm1105dvb->dmxdev.filternum = 256;
+	dm1105dvb->dmxdev.demux = dmx;
+	dm1105dvb->dmxdev.capabilities = 0;
+
+	ret = dvb_dmxdev_init(&dm1105dvb->dmxdev, dvb_adapter);
+	if (ret < 0)
+		goto err_dvb_dmx_release;
+
+	dm1105dvb->hw_frontend.source = DMX_FRONTEND_0;
+
+	ret = dmx->add_frontend(dmx, &dm1105dvb->hw_frontend);
+	if (ret < 0)
+		goto err_dvb_dmxdev_release;
+
+	dm1105dvb->mem_frontend.source = DMX_MEMORY_FE;
+
+	ret = dmx->add_frontend(dmx, &dm1105dvb->mem_frontend);
+	if (ret < 0)
+		goto err_remove_hw_frontend;
+
+	ret = dmx->connect_frontend(dmx, &dm1105dvb->hw_frontend);
+	if (ret < 0)
+		goto err_remove_mem_frontend;
+
+	ret = frontend_init(dm1105dvb);
+	if (ret < 0)
+		goto err_disconnect_frontend;
+
+	dvb_net_init(dvb_adapter, &dm1105dvb->dvbnet, dmx);
+	dm1105_ir_init(dm1105dvb);
+out:
+	return ret;
+
+err_disconnect_frontend:
+	dmx->disconnect_frontend(dmx);
+err_remove_mem_frontend:
+	dmx->remove_frontend(dmx, &dm1105dvb->mem_frontend);
+err_remove_hw_frontend:
+	dmx->remove_frontend(dmx, &dm1105dvb->hw_frontend);
+err_dvb_dmxdev_release:
+	dvb_dmxdev_release(&dm1105dvb->dmxdev);
+err_dvb_dmx_release:
+	dvb_dmx_release(dvbdemux);
+err_dvb_unregister_adapter:
+	dvb_unregister_adapter(dvb_adapter);
+err_i2c_del_adapter:
+	i2c_del_adapter(&dm1105dvb->i2c_adap);
+err_dm1105dvb_hw_exit:
+	dm1105dvb_hw_exit(dm1105dvb);
+err_free_irq:
+	free_irq(pdev->irq, dm1105dvb);
+err_pci_iounmap:
+	pci_iounmap(pdev, dm1105dvb->io_mem);
+err_pci_release_regions:
+	pci_release_regions(pdev);
+err_pci_disable_device:
+	pci_disable_device(pdev);
+err_kfree:
+	pci_set_drvdata(pdev, NULL);
+	kfree(dm1105dvb);
+	goto out;
+}
+
+static void __devexit dm1105_remove(struct pci_dev *pdev)
+{
+	struct dm1105dvb *dm1105dvb = pci_get_drvdata(pdev);
+	struct dvb_adapter *dvb_adapter = &dm1105dvb->dvb_adapter;
+	struct dvb_demux *dvbdemux = &dm1105dvb->demux;
+	struct dmx_demux *dmx = &dvbdemux->dmx;
+
+	dm1105_ir_exit(dm1105dvb);
+	dmx->close(dmx);
+	dvb_net_release(&dm1105dvb->dvbnet);
+	if (dm1105dvb->fe)
+		dvb_unregister_frontend(dm1105dvb->fe);
+
+	dmx->disconnect_frontend(dmx);
+	dmx->remove_frontend(dmx, &dm1105dvb->mem_frontend);
+	dmx->remove_frontend(dmx, &dm1105dvb->hw_frontend);
+	dvb_dmxdev_release(&dm1105dvb->dmxdev);
+	dvb_dmx_release(dvbdemux);
+	dvb_unregister_adapter(dvb_adapter);
+	if (&dm1105dvb->i2c_adap)
+		i2c_del_adapter(&dm1105dvb->i2c_adap);
+
+	dm1105dvb_hw_exit(dm1105dvb);
+	synchronize_irq(pdev->irq);
+	free_irq(pdev->irq, dm1105dvb);
+	pci_iounmap(pdev, dm1105dvb->io_mem);
+	pci_release_regions(pdev);
+	pci_disable_device(pdev);
+	pci_set_drvdata(pdev, NULL);
+	kfree(dm1105dvb);
+}
+
+static struct pci_device_id dm1105_id_table[] __devinitdata = {
+	{
+		.vendor = PCI_VENDOR_ID_TRIGEM,
+		.device = PCI_DEVICE_ID_DM1105,
+		.subvendor = PCI_ANY_ID,
+		.subdevice = PCI_DEVICE_ID_DW2002,
+	}, {
+		.vendor = PCI_VENDOR_ID_TRIGEM,
+		.device = PCI_DEVICE_ID_DM1105,
+		.subvendor = PCI_ANY_ID,
+		.subdevice = PCI_DEVICE_ID_DW2004,
+	}, {
+		/* empty */
+	},
+};
+
+MODULE_DEVICE_TABLE(pci, dm1105_id_table);
+
+static struct pci_driver dm1105_driver = {
+	.name = DRIVER_NAME,
+	.id_table = dm1105_id_table,
+	.probe = dm1105_probe,
+	.remove = __devexit_p(dm1105_remove),
+};
+
+static int __init dm1105_init(void)
+{
+	return pci_register_driver(&dm1105_driver);
+}
+
+static void __exit dm1105_exit(void)
+{
+	pci_unregister_driver(&dm1105_driver);
+}
+
+module_init(dm1105_init);
+module_exit(dm1105_exit);
+
+MODULE_AUTHOR("Igor M. Liplianin <liplianin@me.by>");
+MODULE_DESCRIPTION("SDMC DM1105 DVB driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-core/dmxdev.c b/drivers/media/dvb/dvb-core/dmxdev.c
index 069d847..0c733c6 100644
--- a/drivers/media/dvb/dvb-core/dmxdev.c
+++ b/drivers/media/dvb/dvb-core/dmxdev.c
@@ -364,15 +364,16 @@
 				       enum dmx_success success)
 {
 	struct dmxdev_filter *dmxdevfilter = filter->priv;
+	unsigned long flags;
 	int ret;
 
 	if (dmxdevfilter->buffer.error) {
 		wake_up(&dmxdevfilter->buffer.queue);
 		return 0;
 	}
-	spin_lock(&dmxdevfilter->dev->lock);
+	spin_lock_irqsave(&dmxdevfilter->dev->lock, flags);
 	if (dmxdevfilter->state != DMXDEV_STATE_GO) {
-		spin_unlock(&dmxdevfilter->dev->lock);
+		spin_unlock_irqrestore(&dmxdevfilter->dev->lock, flags);
 		return 0;
 	}
 	del_timer(&dmxdevfilter->timer);
@@ -391,7 +392,7 @@
 	}
 	if (dmxdevfilter->params.sec.flags & DMX_ONESHOT)
 		dmxdevfilter->state = DMXDEV_STATE_DONE;
-	spin_unlock(&dmxdevfilter->dev->lock);
+	spin_unlock_irqrestore(&dmxdevfilter->dev->lock, flags);
 	wake_up(&dmxdevfilter->buffer.queue);
 	return 0;
 }
@@ -403,11 +404,12 @@
 {
 	struct dmxdev_filter *dmxdevfilter = feed->priv;
 	struct dvb_ringbuffer *buffer;
+	unsigned long flags;
 	int ret;
 
-	spin_lock(&dmxdevfilter->dev->lock);
+	spin_lock_irqsave(&dmxdevfilter->dev->lock, flags);
 	if (dmxdevfilter->params.pes.output == DMX_OUT_DECODER) {
-		spin_unlock(&dmxdevfilter->dev->lock);
+		spin_unlock_irqrestore(&dmxdevfilter->dev->lock, flags);
 		return 0;
 	}
 
@@ -417,7 +419,7 @@
 	else
 		buffer = &dmxdevfilter->dev->dvr_buffer;
 	if (buffer->error) {
-		spin_unlock(&dmxdevfilter->dev->lock);
+		spin_unlock_irqrestore(&dmxdevfilter->dev->lock, flags);
 		wake_up(&buffer->queue);
 		return 0;
 	}
@@ -428,7 +430,7 @@
 		dvb_ringbuffer_flush(buffer);
 		buffer->error = ret;
 	}
-	spin_unlock(&dmxdevfilter->dev->lock);
+	spin_unlock_irqrestore(&dmxdevfilter->dev->lock, flags);
 	wake_up(&buffer->queue);
 	return 0;
 }
diff --git a/drivers/media/dvb/dvb-core/dvb_demux.c b/drivers/media/dvb/dvb-core/dvb_demux.c
index e2eca0b..a2c1fd5 100644
--- a/drivers/media/dvb/dvb-core/dvb_demux.c
+++ b/drivers/media/dvb/dvb-core/dvb_demux.c
@@ -399,7 +399,9 @@
 void dvb_dmx_swfilter_packets(struct dvb_demux *demux, const u8 *buf,
 			      size_t count)
 {
-	spin_lock(&demux->lock);
+	unsigned long flags;
+
+	spin_lock_irqsave(&demux->lock, flags);
 
 	while (count--) {
 		if (buf[0] == 0x47)
@@ -407,16 +409,17 @@
 		buf += 188;
 	}
 
-	spin_unlock(&demux->lock);
+	spin_unlock_irqrestore(&demux->lock, flags);
 }
 
 EXPORT_SYMBOL(dvb_dmx_swfilter_packets);
 
 void dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf, size_t count)
 {
+	unsigned long flags;
 	int p = 0, i, j;
 
-	spin_lock(&demux->lock);
+	spin_lock_irqsave(&demux->lock, flags);
 
 	if (demux->tsbufp) {
 		i = demux->tsbufp;
@@ -449,17 +452,18 @@
 	}
 
 bailout:
-	spin_unlock(&demux->lock);
+	spin_unlock_irqrestore(&demux->lock, flags);
 }
 
 EXPORT_SYMBOL(dvb_dmx_swfilter);
 
 void dvb_dmx_swfilter_204(struct dvb_demux *demux, const u8 *buf, size_t count)
 {
+	unsigned long flags;
 	int p = 0, i, j;
 	u8 tmppack[188];
 
-	spin_lock(&demux->lock);
+	spin_lock_irqsave(&demux->lock, flags);
 
 	if (demux->tsbufp) {
 		i = demux->tsbufp;
@@ -500,7 +504,7 @@
 	}
 
 bailout:
-	spin_unlock(&demux->lock);
+	spin_unlock_irqrestore(&demux->lock, flags);
 }
 
 EXPORT_SYMBOL(dvb_dmx_swfilter_204);
diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c
index 3526e3e..f170e82 100644
--- a/drivers/media/dvb/dvb-core/dvb_frontend.c
+++ b/drivers/media/dvb/dvb-core/dvb_frontend.c
@@ -40,6 +40,7 @@
 
 #include "dvb_frontend.h"
 #include "dvbdev.h"
+#include <linux/dvb/version.h>
 
 static int dvb_frontend_debug;
 static int dvb_shutdown_timeout;
@@ -755,6 +756,539 @@
 	return 0;
 }
 
+struct dtv_cmds_h dtv_cmds[] = {
+	[DTV_TUNE] = {
+		.name	= "DTV_TUNE",
+		.cmd	= DTV_TUNE,
+		.set	= 1,
+	},
+	[DTV_CLEAR] = {
+		.name	= "DTV_CLEAR",
+		.cmd	= DTV_CLEAR,
+		.set	= 1,
+	},
+
+	/* Set */
+	[DTV_FREQUENCY] = {
+		.name	= "DTV_FREQUENCY",
+		.cmd	= DTV_FREQUENCY,
+		.set	= 1,
+	},
+	[DTV_BANDWIDTH_HZ] = {
+		.name	= "DTV_BANDWIDTH_HZ",
+		.cmd	= DTV_BANDWIDTH_HZ,
+		.set	= 1,
+	},
+	[DTV_MODULATION] = {
+		.name	= "DTV_MODULATION",
+		.cmd	= DTV_MODULATION,
+		.set	= 1,
+	},
+	[DTV_INVERSION] = {
+		.name	= "DTV_INVERSION",
+		.cmd	= DTV_INVERSION,
+		.set	= 1,
+	},
+	[DTV_DISEQC_MASTER] = {
+		.name	= "DTV_DISEQC_MASTER",
+		.cmd	= DTV_DISEQC_MASTER,
+		.set	= 1,
+		.buffer	= 1,
+	},
+	[DTV_SYMBOL_RATE] = {
+		.name	= "DTV_SYMBOL_RATE",
+		.cmd	= DTV_SYMBOL_RATE,
+		.set	= 1,
+	},
+	[DTV_INNER_FEC] = {
+		.name	= "DTV_INNER_FEC",
+		.cmd	= DTV_INNER_FEC,
+		.set	= 1,
+	},
+	[DTV_VOLTAGE] = {
+		.name	= "DTV_VOLTAGE",
+		.cmd	= DTV_VOLTAGE,
+		.set	= 1,
+	},
+	[DTV_TONE] = {
+		.name	= "DTV_TONE",
+		.cmd	= DTV_TONE,
+		.set	= 1,
+	},
+	[DTV_PILOT] = {
+		.name	= "DTV_PILOT",
+		.cmd	= DTV_PILOT,
+		.set	= 1,
+	},
+	[DTV_ROLLOFF] = {
+		.name	= "DTV_ROLLOFF",
+		.cmd	= DTV_ROLLOFF,
+		.set	= 1,
+	},
+	[DTV_DELIVERY_SYSTEM] = {
+		.name	= "DTV_DELIVERY_SYSTEM",
+		.cmd	= DTV_DELIVERY_SYSTEM,
+		.set	= 1,
+	},
+	[DTV_HIERARCHY] = {
+		.name	= "DTV_HIERARCHY",
+		.cmd	= DTV_HIERARCHY,
+		.set	= 1,
+	},
+	[DTV_CODE_RATE_HP] = {
+		.name	= "DTV_CODE_RATE_HP",
+		.cmd	= DTV_CODE_RATE_HP,
+		.set	= 1,
+	},
+	[DTV_CODE_RATE_LP] = {
+		.name	= "DTV_CODE_RATE_LP",
+		.cmd	= DTV_CODE_RATE_LP,
+		.set	= 1,
+	},
+	[DTV_GUARD_INTERVAL] = {
+		.name	= "DTV_GUARD_INTERVAL",
+		.cmd	= DTV_GUARD_INTERVAL,
+		.set	= 1,
+	},
+	[DTV_TRANSMISSION_MODE] = {
+		.name	= "DTV_TRANSMISSION_MODE",
+		.cmd	= DTV_TRANSMISSION_MODE,
+		.set	= 1,
+	},
+	/* Get */
+	[DTV_DISEQC_SLAVE_REPLY] = {
+		.name	= "DTV_DISEQC_SLAVE_REPLY",
+		.cmd	= DTV_DISEQC_SLAVE_REPLY,
+		.set	= 0,
+		.buffer	= 1,
+	},
+	[DTV_API_VERSION] = {
+		.name	= "DTV_API_VERSION",
+		.cmd	= DTV_API_VERSION,
+		.set	= 0,
+	},
+	[DTV_CODE_RATE_HP] = {
+		.name	= "DTV_CODE_RATE_HP",
+		.cmd	= DTV_CODE_RATE_HP,
+		.set	= 0,
+	},
+	[DTV_CODE_RATE_LP] = {
+		.name	= "DTV_CODE_RATE_LP",
+		.cmd	= DTV_CODE_RATE_LP,
+		.set	= 0,
+	},
+	[DTV_GUARD_INTERVAL] = {
+		.name	= "DTV_GUARD_INTERVAL",
+		.cmd	= DTV_GUARD_INTERVAL,
+		.set	= 0,
+	},
+	[DTV_TRANSMISSION_MODE] = {
+		.name	= "DTV_TRANSMISSION_MODE",
+		.cmd	= DTV_TRANSMISSION_MODE,
+		.set	= 0,
+	},
+	[DTV_HIERARCHY] = {
+		.name	= "DTV_HIERARCHY",
+		.cmd	= DTV_HIERARCHY,
+		.set	= 0,
+	},
+};
+
+void dtv_property_dump(struct dtv_property *tvp)
+{
+	int i;
+
+	if (tvp->cmd <= 0 || tvp->cmd > DTV_MAX_COMMAND) {
+		printk("%s: tvp.cmd = 0x%08x (undefined/unknown/invalid)\n",
+			__func__, tvp->cmd);
+		return;
+	}
+
+	printk("%s() tvp.cmd    = 0x%08x (%s)\n"
+		,__FUNCTION__
+		,tvp->cmd
+		,dtv_cmds[ tvp->cmd ].name);
+
+	if(dtv_cmds[ tvp->cmd ].buffer) {
+
+		printk("%s() tvp.u.buffer.len = 0x%02x\n"
+			,__FUNCTION__
+			,tvp->u.buffer.len);
+
+		for(i = 0; i < tvp->u.buffer.len; i++)
+			printk("%s() tvp.u.buffer.data[0x%02x] = 0x%02x\n"
+				,__FUNCTION__
+				,i
+				,tvp->u.buffer.data[i]);
+
+	} else
+		printk("%s() tvp.u.data = 0x%08x\n", __FUNCTION__, tvp->u.data);
+}
+
+int is_legacy_delivery_system(fe_delivery_system_t s)
+{
+	if((s == SYS_UNDEFINED) || (s == SYS_DVBC_ANNEX_AC) ||
+		(s == SYS_DVBC_ANNEX_B) || (s == SYS_DVBT) || (s == SYS_DVBS))
+		return 1;
+
+	return 0;
+}
+
+/* Synchronise the legacy tuning parameters into the cache, so that demodulator
+ * drivers can use a single set_frontend tuning function, regardless of whether
+ * it's being used for the legacy or new API, reducing code and complexity.
+ */
+void dtv_property_cache_sync(struct dvb_frontend *fe, struct dvb_frontend_parameters *p)
+{
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+
+	printk("%s()\n", __FUNCTION__);
+
+	c->frequency = p->frequency;
+	c->inversion = p->inversion;
+
+	switch (fe->ops.info.type) {
+	case FE_QPSK:
+		c->modulation = QPSK;   /* implied for DVB-S in legacy API */
+		c->rolloff = ROLLOFF_35;/* implied for DVB-S */
+		c->symbol_rate = p->u.qpsk.symbol_rate;
+		c->fec_inner = p->u.qpsk.fec_inner;
+		c->delivery_system = SYS_DVBS;
+		break;
+	case FE_QAM:
+		c->symbol_rate = p->u.qam.symbol_rate;
+		c->fec_inner = p->u.qam.fec_inner;
+		c->modulation = p->u.qam.modulation;
+		c->delivery_system = SYS_DVBC_ANNEX_AC;
+		break;
+	case FE_OFDM:
+		if (p->u.ofdm.bandwidth == BANDWIDTH_6_MHZ)
+			c->bandwidth_hz = 6000000;
+		else if (p->u.ofdm.bandwidth == BANDWIDTH_7_MHZ)
+			c->bandwidth_hz = 7000000;
+		else if (p->u.ofdm.bandwidth == BANDWIDTH_8_MHZ)
+			c->bandwidth_hz = 8000000;
+		else
+			/* Including BANDWIDTH_AUTO */
+			c->bandwidth_hz = 0;
+		c->code_rate_HP = p->u.ofdm.code_rate_HP;
+		c->code_rate_LP = p->u.ofdm.code_rate_LP;
+		c->modulation = p->u.ofdm.constellation;
+		c->transmission_mode = p->u.ofdm.transmission_mode;
+		c->guard_interval = p->u.ofdm.guard_interval;
+		c->hierarchy = p->u.ofdm.hierarchy_information;
+		c->delivery_system = SYS_DVBT;
+		break;
+	case FE_ATSC:
+		c->modulation = p->u.vsb.modulation;
+		if ((c->modulation == VSB_8) || (c->modulation == VSB_16))
+			c->delivery_system = SYS_ATSC;
+		else
+			c->delivery_system = SYS_DVBC_ANNEX_B;
+		break;
+	}
+}
+
+/* Ensure the cached values are set correctly in the frontend
+ * legacy tuning structures, for the advanced tuning API.
+ */
+void dtv_property_legacy_params_sync(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+	struct dvb_frontend_private *fepriv = fe->frontend_priv;
+	struct dvb_frontend_parameters *p = &fepriv->parameters;
+
+	printk("%s()\n", __FUNCTION__);
+
+	p->frequency = c->frequency;
+	p->inversion = c->inversion;
+
+	switch (fe->ops.info.type) {
+	case FE_QPSK:
+		printk("%s() Preparing QPSK req\n", __FUNCTION__);
+		p->u.qpsk.symbol_rate = c->symbol_rate;
+		p->u.qpsk.fec_inner = c->fec_inner;
+		c->delivery_system = SYS_DVBS;
+		break;
+	case FE_QAM:
+		printk("%s() Preparing QAM req\n", __FUNCTION__);
+		p->u.qam.symbol_rate = c->symbol_rate;
+		p->u.qam.fec_inner = c->fec_inner;
+		p->u.qam.modulation = c->modulation;
+		c->delivery_system = SYS_DVBC_ANNEX_AC;
+		break;
+	case FE_OFDM:
+		printk("%s() Preparing OFDM req\n", __FUNCTION__);
+		if (c->bandwidth_hz == 6000000)
+			p->u.ofdm.bandwidth = BANDWIDTH_6_MHZ;
+		else if (c->bandwidth_hz == 7000000)
+			p->u.ofdm.bandwidth = BANDWIDTH_7_MHZ;
+		else if (c->bandwidth_hz == 8000000)
+			p->u.ofdm.bandwidth = BANDWIDTH_8_MHZ;
+		else
+			p->u.ofdm.bandwidth = BANDWIDTH_AUTO;
+		p->u.ofdm.code_rate_HP = c->code_rate_HP;
+		p->u.ofdm.code_rate_LP = c->code_rate_LP;
+		p->u.ofdm.constellation = c->modulation;
+		p->u.ofdm.transmission_mode = c->transmission_mode;
+		p->u.ofdm.guard_interval = c->guard_interval;
+		p->u.ofdm.hierarchy_information = c->hierarchy;
+		c->delivery_system = SYS_DVBT;
+		break;
+	case FE_ATSC:
+		printk("%s() Preparing VSB req\n", __FUNCTION__);
+		p->u.vsb.modulation = c->modulation;
+		if ((c->modulation == VSB_8) || (c->modulation == VSB_16))
+			c->delivery_system = SYS_ATSC;
+		else
+			c->delivery_system = SYS_DVBC_ANNEX_B;
+		break;
+	}
+}
+
+/* Ensure the cached values are set correctly in the frontend
+ * legacy tuning structures, for the legacy tuning API.
+ */
+void dtv_property_adv_params_sync(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+	struct dvb_frontend_private *fepriv = fe->frontend_priv;
+	struct dvb_frontend_parameters *p = &fepriv->parameters;
+
+	printk("%s()\n", __FUNCTION__);
+
+	p->frequency = c->frequency;
+	p->inversion = c->inversion;
+
+	switch(c->modulation) {
+	case PSK_8:
+	case APSK_16:
+	case QPSK:
+		p->u.qpsk.symbol_rate = c->symbol_rate;
+		p->u.qpsk.fec_inner = c->fec_inner;
+		break;
+	default:
+		break;
+	}
+
+	if(c->delivery_system == SYS_ISDBT) {
+		/* Fake out a generic DVB-T request so we pass validation in the ioctl */
+		p->frequency = c->frequency;
+		p->inversion = INVERSION_AUTO;
+		p->u.ofdm.constellation = QAM_AUTO;
+		p->u.ofdm.code_rate_HP = FEC_AUTO;
+		p->u.ofdm.code_rate_LP = FEC_AUTO;
+		p->u.ofdm.bandwidth = BANDWIDTH_AUTO;
+		p->u.ofdm.transmission_mode = TRANSMISSION_MODE_AUTO;
+		p->u.ofdm.guard_interval = GUARD_INTERVAL_AUTO;
+		p->u.ofdm.hierarchy_information = HIERARCHY_AUTO;
+	}
+}
+
+void dtv_property_cache_submit(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+
+	printk("%s()\n", __FUNCTION__);
+
+	/* For legacy delivery systems we don't need the delivery_system to
+	 * be specified, but we populate the older structures from the cache
+	 * so we can call set_frontend on older drivers.
+	 */
+	if(is_legacy_delivery_system(c->delivery_system)) {
+
+		printk("%s() legacy, modulation = %d\n", __FUNCTION__, c->modulation);
+		dtv_property_legacy_params_sync(fe);
+
+	} else {
+		printk("%s() adv, modulation = %d\n", __FUNCTION__, c->modulation);
+
+		/* For advanced delivery systems / modulation types ...
+		 * we seed the lecacy dvb_frontend_parameters structure
+		 * so that the sanity checking code later in the IOCTL processing
+		 * can validate our basic frequency ranges, symbolrates, modulation
+		 * etc.
+		 */
+		dtv_property_adv_params_sync(fe);
+	}
+}
+
+static int dvb_frontend_ioctl_legacy(struct inode *inode, struct file *file,
+			unsigned int cmd, void *parg);
+static int dvb_frontend_ioctl_properties(struct inode *inode, struct file *file,
+			unsigned int cmd, void *parg);
+
+int dtv_property_process_get(struct dvb_frontend *fe, struct dtv_property *tvp,
+	struct inode *inode, struct file *file)
+{
+	int r = 0;
+
+	printk("%s()\n", __FUNCTION__);
+
+	dtv_property_dump(tvp);
+
+	/* Allow the frontend to validate incoming properties */
+	if (fe->ops.get_property)
+		r = fe->ops.get_property(fe, tvp);
+
+	if (r < 0)
+		return r;
+
+	switch(tvp->cmd) {
+	case DTV_FREQUENCY:
+		tvp->u.data = fe->dtv_property_cache.frequency;
+		break;
+	case DTV_MODULATION:
+		tvp->u.data = fe->dtv_property_cache.modulation;
+		break;
+	case DTV_BANDWIDTH_HZ:
+		tvp->u.data = fe->dtv_property_cache.bandwidth_hz;
+		break;
+	case DTV_INVERSION:
+		tvp->u.data = fe->dtv_property_cache.inversion;
+		break;
+	case DTV_SYMBOL_RATE:
+		tvp->u.data = fe->dtv_property_cache.symbol_rate;
+		break;
+	case DTV_INNER_FEC:
+		tvp->u.data = fe->dtv_property_cache.fec_inner;
+		break;
+	case DTV_PILOT:
+		tvp->u.data = fe->dtv_property_cache.pilot;
+		break;
+	case DTV_ROLLOFF:
+		tvp->u.data = fe->dtv_property_cache.rolloff;
+		break;
+	case DTV_DELIVERY_SYSTEM:
+		tvp->u.data = fe->dtv_property_cache.delivery_system;
+		break;
+	case DTV_VOLTAGE:
+		tvp->u.data = fe->dtv_property_cache.voltage;
+		break;
+	case DTV_TONE:
+		tvp->u.data = fe->dtv_property_cache.sectone;
+		break;
+	case DTV_API_VERSION:
+		tvp->u.data = (DVB_API_VERSION << 8) | DVB_API_VERSION_MINOR;
+		break;
+	case DTV_CODE_RATE_HP:
+		tvp->u.data = fe->dtv_property_cache.code_rate_HP;
+		break;
+	case DTV_CODE_RATE_LP:
+		tvp->u.data = fe->dtv_property_cache.code_rate_LP;
+		break;
+	case DTV_GUARD_INTERVAL:
+		tvp->u.data = fe->dtv_property_cache.guard_interval;
+		break;
+	case DTV_TRANSMISSION_MODE:
+		tvp->u.data = fe->dtv_property_cache.transmission_mode;
+		break;
+	case DTV_HIERARCHY:
+		tvp->u.data = fe->dtv_property_cache.hierarchy;
+		break;
+	default:
+		r = -1;
+	}
+
+	return r;
+}
+
+int dtv_property_process_set(struct dvb_frontend *fe, struct dtv_property *tvp,
+	struct inode *inode, struct file *file)
+{
+	int r = 0;
+	struct dvb_frontend_private *fepriv = fe->frontend_priv;
+	printk("%s()\n", __FUNCTION__);
+	dtv_property_dump(tvp);
+
+	/* Allow the frontend to validate incoming properties */
+	if (fe->ops.set_property)
+		r = fe->ops.set_property(fe, tvp);
+
+	if (r < 0)
+		return r;
+
+	switch(tvp->cmd) {
+	case DTV_CLEAR:
+		/* Reset a cache of data specific to the frontend here. This does
+		 * not effect hardware.
+		 */
+		printk("%s() Flushing property cache\n", __FUNCTION__);
+		memset(&fe->dtv_property_cache, 0, sizeof(struct dtv_frontend_properties));
+		fe->dtv_property_cache.state = tvp->cmd;
+		fe->dtv_property_cache.delivery_system = SYS_UNDEFINED;
+		break;
+	case DTV_TUNE:
+		/* interpret the cache of data, build either a traditional frontend
+		 * tunerequest so we can pass validation in the FE_SET_FRONTEND
+		 * ioctl.
+		 */
+		fe->dtv_property_cache.state = tvp->cmd;
+		printk("%s() Finalised property cache\n", __FUNCTION__);
+		dtv_property_cache_submit(fe);
+
+		r |= dvb_frontend_ioctl_legacy(inode, file, FE_SET_FRONTEND,
+			&fepriv->parameters);
+		break;
+	case DTV_FREQUENCY:
+		fe->dtv_property_cache.frequency = tvp->u.data;
+		break;
+	case DTV_MODULATION:
+		fe->dtv_property_cache.modulation = tvp->u.data;
+		break;
+	case DTV_BANDWIDTH_HZ:
+		fe->dtv_property_cache.bandwidth_hz = tvp->u.data;
+		break;
+	case DTV_INVERSION:
+		fe->dtv_property_cache.inversion = tvp->u.data;
+		break;
+	case DTV_SYMBOL_RATE:
+		fe->dtv_property_cache.symbol_rate = tvp->u.data;
+		break;
+	case DTV_INNER_FEC:
+		fe->dtv_property_cache.fec_inner = tvp->u.data;
+		break;
+	case DTV_PILOT:
+		fe->dtv_property_cache.pilot = tvp->u.data;
+		break;
+	case DTV_ROLLOFF:
+		fe->dtv_property_cache.rolloff = tvp->u.data;
+		break;
+	case DTV_DELIVERY_SYSTEM:
+		fe->dtv_property_cache.delivery_system = tvp->u.data;
+		break;
+	case DTV_VOLTAGE:
+		fe->dtv_property_cache.voltage = tvp->u.data;
+		r = dvb_frontend_ioctl_legacy(inode, file, FE_SET_VOLTAGE,
+			(void *)fe->dtv_property_cache.voltage);
+		break;
+	case DTV_TONE:
+		fe->dtv_property_cache.sectone = tvp->u.data;
+		r = dvb_frontend_ioctl_legacy(inode, file, FE_SET_TONE,
+			(void *)fe->dtv_property_cache.sectone);
+		break;
+	case DTV_CODE_RATE_HP:
+		fe->dtv_property_cache.code_rate_HP = tvp->u.data;
+		break;
+	case DTV_CODE_RATE_LP:
+		fe->dtv_property_cache.code_rate_LP = tvp->u.data;
+		break;
+	case DTV_GUARD_INTERVAL:
+		fe->dtv_property_cache.guard_interval = tvp->u.data;
+		break;
+	case DTV_TRANSMISSION_MODE:
+		fe->dtv_property_cache.transmission_mode = tvp->u.data;
+		break;
+	case DTV_HIERARCHY:
+		fe->dtv_property_cache.hierarchy = tvp->u.data;
+		break;
+	default:
+		r = -1;
+	}
+
+	return r;
+}
+
 static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
 			unsigned int cmd, void *parg)
 {
@@ -776,6 +1310,116 @@
 	if (down_interruptible (&fepriv->sem))
 		return -ERESTARTSYS;
 
+	if ((cmd == FE_SET_PROPERTY) || (cmd == FE_GET_PROPERTY))
+		err = dvb_frontend_ioctl_properties(inode, file, cmd, parg);
+	else {
+		fe->dtv_property_cache.state = DTV_UNDEFINED;
+		err = dvb_frontend_ioctl_legacy(inode, file, cmd, parg);
+	}
+
+	up(&fepriv->sem);
+	return err;
+}
+
+static int dvb_frontend_ioctl_properties(struct inode *inode, struct file *file,
+			unsigned int cmd, void *parg)
+{
+	struct dvb_device *dvbdev = file->private_data;
+	struct dvb_frontend *fe = dvbdev->priv;
+	int err = 0;
+
+	struct dtv_properties *tvps = NULL;
+	struct dtv_property *tvp = NULL;
+	int i;
+
+	dprintk("%s\n", __func__);
+
+	if(cmd == FE_SET_PROPERTY) {
+		printk("%s() FE_SET_PROPERTY\n", __FUNCTION__);
+
+		tvps = (struct dtv_properties __user *)parg;
+
+		printk("%s() properties.num = %d\n", __FUNCTION__, tvps->num);
+		printk("%s() properties.props = %p\n", __FUNCTION__, tvps->props);
+
+		/* Put an arbitrary limit on the number of messages that can
+		 * be sent at once */
+		if ((tvps->num == 0) || (tvps->num > DTV_IOCTL_MAX_MSGS))
+			return -EINVAL;
+
+		tvp = (struct dtv_property *) kmalloc(tvps->num *
+			sizeof(struct dtv_property), GFP_KERNEL);
+		if (!tvp) {
+			err = -ENOMEM;
+			goto out;
+		}
+
+		if (copy_from_user(tvp, tvps->props, tvps->num * sizeof(struct dtv_property))) {
+			err = -EFAULT;
+			goto out;
+		}
+
+		for (i = 0; i < tvps->num; i++) {
+			(tvp + i)->result = dtv_property_process_set(fe, tvp + i, inode, file);
+			err |= (tvp + i)->result;
+		}
+
+		if(fe->dtv_property_cache.state == DTV_TUNE) {
+			printk("%s() Property cache is full, tuning\n", __FUNCTION__);
+		}
+
+	} else
+	if(cmd == FE_GET_PROPERTY) {
+		printk("%s() FE_GET_PROPERTY\n", __FUNCTION__);
+
+		tvps = (struct dtv_properties __user *)parg;
+
+		printk("%s() properties.num = %d\n", __FUNCTION__, tvps->num);
+		printk("%s() properties.props = %p\n", __FUNCTION__, tvps->props);
+
+		/* Put an arbitrary limit on the number of messages that can
+		 * be sent at once */
+		if ((tvps->num == 0) || (tvps->num > DTV_IOCTL_MAX_MSGS))
+			return -EINVAL;
+
+		tvp = (struct dtv_property *) kmalloc(tvps->num *
+			sizeof(struct dtv_property), GFP_KERNEL);
+		if (!tvp) {
+			err = -ENOMEM;
+			goto out;
+		}
+
+		if (copy_from_user(tvp, tvps->props, tvps->num * sizeof(struct dtv_property))) {
+			err = -EFAULT;
+			goto out;
+		}
+
+		for (i = 0; i < tvps->num; i++) {
+			(tvp + i)->result = dtv_property_process_get(fe, tvp + i, inode, file);
+			err |= (tvp + i)->result;
+		}
+
+		if (copy_to_user(tvps->props, tvp, tvps->num * sizeof(struct dtv_property))) {
+			err = -EFAULT;
+			goto out;
+		}
+
+	} else
+		err = -EOPNOTSUPP;
+
+out:
+	kfree(tvp);
+	return err;
+}
+
+static int dvb_frontend_ioctl_legacy(struct inode *inode, struct file *file,
+			unsigned int cmd, void *parg)
+{
+	struct dvb_device *dvbdev = file->private_data;
+	struct dvb_frontend *fe = dvbdev->priv;
+	struct dvb_frontend_private *fepriv = fe->frontend_priv;
+	int err = -EOPNOTSUPP;
+
 	switch (cmd) {
 	case FE_GET_INFO: {
 		struct dvb_frontend_info* info = parg;
@@ -942,13 +1586,21 @@
 	case FE_SET_FRONTEND: {
 		struct dvb_frontend_tune_settings fetunesettings;
 
-		if (dvb_frontend_check_parameters(fe, parg) < 0) {
-			err = -EINVAL;
-			break;
-		}
+		if(fe->dtv_property_cache.state == DTV_TUNE) {
+			if (dvb_frontend_check_parameters(fe, &fepriv->parameters) < 0) {
+				err = -EINVAL;
+				break;
+			}
+		} else {
+			if (dvb_frontend_check_parameters(fe, parg) < 0) {
+				err = -EINVAL;
+				break;
+			}
 
-		memcpy (&fepriv->parameters, parg,
-			sizeof (struct dvb_frontend_parameters));
+			memcpy (&fepriv->parameters, parg,
+				sizeof (struct dvb_frontend_parameters));
+			dtv_property_cache_sync(fe, &fepriv->parameters);
+		}
 
 		memset(&fetunesettings, 0, sizeof(struct dvb_frontend_tune_settings));
 		memcpy(&fetunesettings.parameters, parg,
@@ -1027,10 +1679,10 @@
 		break;
 	};
 
-	up (&fepriv->sem);
 	return err;
 }
 
+
 static unsigned int dvb_frontend_poll(struct file *file, struct poll_table_struct *wait)
 {
 	struct dvb_device *dvbdev = file->private_data;
diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.h b/drivers/media/dvb/dvb-core/dvb_frontend.h
index aa4133f..3055301 100644
--- a/drivers/media/dvb/dvb-core/dvb_frontend.h
+++ b/drivers/media/dvb/dvb-core/dvb_frontend.h
@@ -169,6 +169,9 @@
 
 	struct dvb_tuner_ops tuner_ops;
 	struct analog_demod_ops analog_ops;
+
+	int (*set_property)(struct dvb_frontend* fe, struct dtv_property* tvp);
+	int (*get_property)(struct dvb_frontend* fe, struct dtv_property* tvp);
 };
 
 #define MAX_EVENT 8
@@ -182,6 +185,32 @@
 	struct mutex		  mtx;
 };
 
+struct dtv_frontend_properties {
+
+	/* Cache State */
+	u32			state;
+
+	u32			frequency;
+	fe_modulation_t		modulation;
+
+	fe_sec_voltage_t	voltage;
+	fe_sec_tone_mode_t	sectone;
+	fe_spectral_inversion_t	inversion;
+	fe_code_rate_t		fec_inner;
+	fe_transmit_mode_t	transmission_mode;
+	u32			bandwidth_hz;	/* 0 = AUTO */
+	fe_guard_interval_t	guard_interval;
+	fe_hierarchy_t		hierarchy;
+	u32			symbol_rate;
+	fe_code_rate_t		code_rate_HP;
+	fe_code_rate_t		code_rate_LP;
+
+	fe_pilot_t		pilot;
+	fe_rolloff_t		rolloff;
+
+	fe_delivery_system_t	delivery_system;
+};
+
 struct dvb_frontend {
 	struct dvb_frontend_ops ops;
 	struct dvb_adapter *dvb;
@@ -190,6 +219,9 @@
 	void *frontend_priv;
 	void *sec_priv;
 	void *analog_demod_priv;
+	struct dtv_frontend_properties dtv_property_cache;
+#define DVB_FRONTEND_COMPONENT_TUNER 0
+	int (*callback)(void *adapter_priv, int component, int cmd, int arg);
 };
 
 extern int dvb_register_frontend(struct dvb_adapter *dvb,
diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig
index e84152b..3c13bcf 100644
--- a/drivers/media/dvb/dvb-usb/Kconfig
+++ b/drivers/media/dvb/dvb-usb/Kconfig
@@ -72,9 +72,11 @@
 	select DVB_DIB7000P
 	select DVB_DIB7000M
 	select DVB_DIB3000MC
+	select DVB_S5H1411 if !DVB_FE_CUSTOMISE
 	select MEDIA_TUNER_MT2060 if !DVB_FE_CUSTOMISE
 	select MEDIA_TUNER_MT2266 if !DVB_FE_CUSTOMISE
 	select MEDIA_TUNER_XC2028 if !DVB_FE_CUSTOMISE
+	select MEDIA_TUNER_XC5000 if !DVB_FE_CUSTOMIZE
 	select DVB_TUNER_DIB0070
 	help
 	  Support for USB2.0/1.1 DVB receivers based on the DiB0700 USB bridge. The
@@ -108,6 +110,8 @@
 	select MEDIA_TUNER_SIMPLE if !DVB_FE_CUSTOMISE
 	select MEDIA_TUNER_XC2028 if !DVB_FE_CUSTOMISE
 	select MEDIA_TUNER_MXL5005S if !DVB_FE_CUSTOMISE
+	select DVB_DIB7000P if !DVB_FE_CUSTOMISE
+	select DVB_TUNER_DIB0070 if !DVB_FE_CUSTOMISE
 	help
 	  Say Y here to support the Conexant USB2.0 hybrid reference design.
 	  Currently, only DVB and ATSC modes are supported, analog mode
@@ -245,12 +249,25 @@
 	  Afatech AF9005 based receiver.
 
 config DVB_USB_DW2102
-	tristate "DvbWorld 2102 DVB-S USB2.0 receiver"
+	tristate "DvbWorld DVB-S/S2 USB2.0 support"
 	depends on DVB_USB
-	select DVB_STV0299 if !DVB_FE_CUSTOMISE
 	select DVB_PLL if !DVB_FE_CUSTOMISE
+	select DVB_STV0299 if !DVB_FE_CUSTOMISE
+	select DVB_STV0288 if !DVB_FE_CUSTOMISE
+	select DVB_STB6000 if !DVB_FE_CUSTOMISE
+	select DVB_CX24116 if !DVB_FE_CUSTOMISE
+	select DVB_SI21XX if !DVB_FE_CUSTOMISE
 	help
-	   Say Y here to support the DvbWorld 2102 DVB-S USB2.0 receiver.
+	  Say Y here to support the DvbWorld DVB-S/S2 USB2.0 receivers
+	  and the TeVii S650.
+
+config 	DVB_USB_CINERGY_T2
+	tristate "Terratec CinergyT2/qanu USB 2.0 DVB-T receiver"
+	depends on DVB_USB
+	help
+	  Support for "TerraTec CinergyT2" USB2.0 Highspeed DVB Receivers
+
+	  Say Y if you own such a device and want to use it.
 
 config DVB_USB_ANYSEE
 	tristate "Anysee DVB-T/C USB2.0 support"
@@ -262,3 +279,22 @@
 	help
 	  Say Y here to support the Anysee E30, Anysee E30 Plus or
 	  Anysee E30 C Plus DVB USB2.0 receiver.
+
+config DVB_USB_DTV5100
+	tristate "AME DTV-5100 USB2.0 DVB-T support"
+	depends on DVB_USB
+	select MEDIA_TUNER_QT1010 if !DVB_FE_CUSTOMISE
+	help
+	  Say Y here to support the AME DTV-5100 USB2.0 DVB-T receiver.
+
+config DVB_USB_AF9015
+	tristate "Afatech AF9015 DVB-T USB2.0 support"
+	depends on DVB_USB && EXPERIMENTAL
+	select DVB_AF9013
+	select DVB_PLL              if !DVB_FE_CUSTOMISE
+	select MEDIA_TUNER_MT2060   if !DVB_FE_CUSTOMISE
+	select MEDIA_TUNER_QT1010   if !DVB_FE_CUSTOMISE
+	select MEDIA_TUNER_TDA18271 if !DVB_FE_CUSTOMISE
+	select MEDIA_TUNER_MXL5005S if !DVB_FE_CUSTOMISE
+	help
+	  Say Y here to support the Afatech AF9015 based DVB-T USB2.0 receiver
diff --git a/drivers/media/dvb/dvb-usb/Makefile b/drivers/media/dvb/dvb-usb/Makefile
index e206f1e..3122b7c 100644
--- a/drivers/media/dvb/dvb-usb/Makefile
+++ b/drivers/media/dvb/dvb-usb/Makefile
@@ -67,6 +67,16 @@
 dvb-usb-dw2102-objs = dw2102.o
 obj-$(CONFIG_DVB_USB_DW2102) += dvb-usb-dw2102.o
 
+dvb-usb-dtv5100-objs = dtv5100.o
+obj-$(CONFIG_DVB_USB_DTV5100) += dvb-usb-dtv5100.o
+
+dvb-usb-af9015-objs = af9015.o
+obj-$(CONFIG_DVB_USB_AF9015) += dvb-usb-af9015.o
+
+dvb-usb-cinergyT2-objs = cinergyT2-core.o cinergyT2-fe.o
+obj-$(CONFIG_DVB_USB_CINERGY_T2) += dvb-usb-cinergyT2.o
+
+
 EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
 # due to tuner-xc3028
 EXTRA_CFLAGS += -Idrivers/media/common/tuners
diff --git a/drivers/media/dvb/dvb-usb/af9005-remote.c b/drivers/media/dvb/dvb-usb/af9005-remote.c
index ff00c0e..7c596f9 100644
--- a/drivers/media/dvb/dvb-usb/af9005-remote.c
+++ b/drivers/media/dvb/dvb-usb/af9005-remote.c
@@ -25,7 +25,7 @@
  */
 #include "af9005.h"
 /* debug */
-int dvb_usb_af9005_remote_debug;
+static int dvb_usb_af9005_remote_debug;
 module_param_named(debug, dvb_usb_af9005_remote_debug, int, 0644);
 MODULE_PARM_DESC(debug,
 		 "enable (1) or disable (0) debug messages."
diff --git a/drivers/media/dvb/dvb-usb/af9005-script.h b/drivers/media/dvb/dvb-usb/af9005-script.h
index 6eeaae5..4d69045 100644
--- a/drivers/media/dvb/dvb-usb/af9005-script.h
+++ b/drivers/media/dvb/dvb-usb/af9005-script.h
@@ -14,7 +14,7 @@
 	u8 val;
 } RegDesc;
 
-RegDesc script[] = {
+static RegDesc script[] = {
 	{0xa180, 0x0, 0x8, 0xa},
 	{0xa181, 0x0, 0x8, 0xd7},
 	{0xa182, 0x0, 0x8, 0xa3},
diff --git a/drivers/media/dvb/dvb-usb/af9005.c b/drivers/media/dvb/dvb-usb/af9005.c
index cfe71fe..ca5a0a4 100644
--- a/drivers/media/dvb/dvb-usb/af9005.c
+++ b/drivers/media/dvb/dvb-usb/af9005.c
@@ -35,17 +35,17 @@
 MODULE_PARM_DESC(led, "enable led (default: 1).");
 
 /* eeprom dump */
-int dvb_usb_af9005_dump_eeprom = 0;
+static int dvb_usb_af9005_dump_eeprom;
 module_param_named(dump_eeprom, dvb_usb_af9005_dump_eeprom, int, 0);
 MODULE_PARM_DESC(dump_eeprom, "dump contents of the eeprom.");
 
 DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
 
 /* remote control decoder */
-int (*rc_decode) (struct dvb_usb_device * d, u8 * data, int len, u32 * event,
-		  int *state);
-void *rc_keys;
-int *rc_keys_size;
+static int (*rc_decode) (struct dvb_usb_device *d, u8 *data, int len,
+		u32 *event, int *state);
+static void *rc_keys;
+static int *rc_keys_size;
 
 u8 regmask[8] = { 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff };
 
@@ -54,8 +54,8 @@
 	int led_state;
 };
 
-int af9005_usb_generic_rw(struct dvb_usb_device *d, u8 * wbuf, u16 wlen,
-			  u8 * rbuf, u16 rlen, int delay_ms)
+static int af9005_usb_generic_rw(struct dvb_usb_device *d, u8 *wbuf, u16 wlen,
+			  u8 *rbuf, u16 rlen, int delay_ms)
 {
 	int actlen, ret = -ENOMEM;
 
@@ -98,12 +98,7 @@
 	return ret;
 }
 
-int af9005_usb_generic_write(struct dvb_usb_device *d, u8 * buf, u16 len)
-{
-	return af9005_usb_generic_rw(d, buf, len, NULL, 0, 0);
-}
-
-int af9005_generic_read_write(struct dvb_usb_device *d, u16 reg,
+static int af9005_generic_read_write(struct dvb_usb_device *d, u16 reg,
 			      int readwrite, int type, u8 * values, int len)
 {
 	struct af9005_device_state *st = d->priv;
@@ -765,7 +760,7 @@
 	return 0;
 }
 
-int af9005_download_firmware(struct usb_device *udev, const struct firmware *fw)
+static int af9005_download_firmware(struct usb_device *udev, const struct firmware *fw)
 {
 	int i, packets, ret, act_len;
 
diff --git a/drivers/media/dvb/dvb-usb/af9015.c b/drivers/media/dvb/dvb-usb/af9015.c
new file mode 100644
index 0000000..cb0829c
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/af9015.c
@@ -0,0 +1,1474 @@
+/*
+ * DVB USB Linux driver for Afatech AF9015 DVB-T USB2.0 receiver
+ *
+ * Copyright (C) 2007 Antti Palosaari <crope@iki.fi>
+ *
+ * Thanks to Afatech who kindly provided information.
+ *
+ *    This program is free software; you can redistribute it and/or 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 "af9015.h"
+#include "af9013.h"
+#include "mt2060.h"
+#include "qt1010.h"
+#include "tda18271.h"
+#include "mxl5005s.h"
+#if 0
+#include "mc44s80x.h"
+#endif
+
+int dvb_usb_af9015_debug;
+module_param_named(debug, dvb_usb_af9015_debug, int, 0644);
+MODULE_PARM_DESC(debug, "set debugging level" DVB_USB_DEBUG_STATUS);
+int dvb_usb_af9015_remote;
+module_param_named(remote, dvb_usb_af9015_remote, int, 0644);
+MODULE_PARM_DESC(remote, "select remote");
+int dvb_usb_af9015_dual_mode;
+module_param_named(dual_mode, dvb_usb_af9015_dual_mode, int, 0644);
+MODULE_PARM_DESC(dual_mode, "enable dual mode");
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+static DEFINE_MUTEX(af9015_usb_mutex);
+
+static struct af9015_config af9015_config;
+static struct dvb_usb_device_properties af9015_properties[2];
+int af9015_properties_count = ARRAY_SIZE(af9015_properties);
+
+static struct af9013_config af9015_af9013_config[] = {
+	{
+		.demod_address = AF9015_I2C_DEMOD,
+		.output_mode = AF9013_OUTPUT_MODE_USB,
+		.api_version = { 0, 1, 9, 0 },
+		.gpio[0] = AF9013_GPIO_HI,
+		.gpio[3] = AF9013_GPIO_TUNER_ON,
+
+	}, {
+		.output_mode = AF9013_OUTPUT_MODE_SERIAL,
+		.api_version = { 0, 1, 9, 0 },
+		.gpio[0] = AF9013_GPIO_TUNER_ON,
+		.gpio[1] = AF9013_GPIO_LO,
+	}
+};
+
+static int af9015_rw_udev(struct usb_device *udev, struct req_t *req)
+{
+	int act_len, ret;
+	u8 buf[64];
+	u8 write = 1;
+	u8 msg_len = 8;
+	static u8 seq; /* packet sequence number */
+
+	if (mutex_lock_interruptible(&af9015_usb_mutex) < 0)
+		return -EAGAIN;
+
+	buf[0] = req->cmd;
+	buf[1] = seq++;
+	buf[2] = req->i2c_addr;
+	buf[3] = req->addr >> 8;
+	buf[4] = req->addr & 0xff;
+	buf[5] = req->mbox;
+	buf[6] = req->addr_len;
+	buf[7] = req->data_len;
+
+	switch (req->cmd) {
+	case GET_CONFIG:
+	case BOOT:
+	case READ_MEMORY:
+	case RECONNECT_USB:
+	case GET_IR_CODE:
+		write = 0;
+		break;
+	case READ_I2C:
+		write = 0;
+		buf[2] |= 0x01; /* set I2C direction */
+	case WRITE_I2C:
+		buf[0] = READ_WRITE_I2C;
+		break;
+	case WRITE_MEMORY:
+		if (((req->addr & 0xff00) == 0xff00) ||
+		    ((req->addr & 0xae00) == 0xae00))
+			buf[0] = WRITE_VIRTUAL_MEMORY;
+	case WRITE_VIRTUAL_MEMORY:
+	case COPY_FIRMWARE:
+	case DOWNLOAD_FIRMWARE:
+		break;
+	default:
+		err("unknown command:%d", req->cmd);
+		ret = -1;
+		goto error_unlock;
+	}
+
+	/* write requested */
+	if (write) {
+		memcpy(&buf[8], req->data, req->data_len);
+		msg_len += req->data_len;
+	}
+	deb_xfer(">>> ");
+	debug_dump(buf, msg_len, deb_xfer);
+
+	/* send req */
+	ret = usb_bulk_msg(udev, usb_sndbulkpipe(udev, 0x02), buf, msg_len,
+	&act_len, AF9015_USB_TIMEOUT);
+	if (ret)
+		err("bulk message failed:%d (%d/%d)", ret, msg_len, act_len);
+	else
+		if (act_len != msg_len)
+			ret = -1; /* all data is not send */
+	if (ret)
+		goto error_unlock;
+
+	/* no ack for those packets */
+	if (req->cmd == DOWNLOAD_FIRMWARE || req->cmd == RECONNECT_USB)
+		goto exit_unlock;
+
+	/* receive ack and data if read req */
+	msg_len = 1 + 1 + req->data_len;  /* seq + status + data len */
+	ret = usb_bulk_msg(udev, usb_rcvbulkpipe(udev, 0x81), buf, msg_len,
+			   &act_len, AF9015_USB_TIMEOUT);
+	if (ret) {
+		err("recv bulk message failed:%d", ret);
+		ret = -1;
+		goto error_unlock;
+	}
+
+	deb_xfer("<<< ");
+	debug_dump(buf, act_len, deb_xfer);
+
+	/* remote controller query status is 1 if remote code is not received */
+	if (req->cmd == GET_IR_CODE && buf[1] == 1) {
+		buf[1] = 0; /* clear command "error" status */
+		memset(&buf[2], 0, req->data_len);
+		buf[3] = 1; /* no remote code received mark */
+	}
+
+	/* check status */
+	if (buf[1]) {
+		err("command failed:%d", buf[1]);
+		ret = -1;
+		goto error_unlock;
+	}
+
+	/* read request, copy returned data to return buf */
+	if (!write)
+		memcpy(req->data, &buf[2], req->data_len);
+
+error_unlock:
+exit_unlock:
+	mutex_unlock(&af9015_usb_mutex);
+
+	return ret;
+}
+
+static int af9015_ctrl_msg(struct dvb_usb_device *d, struct req_t *req)
+{
+	return af9015_rw_udev(d->udev, req);
+}
+
+static int af9015_write_regs(struct dvb_usb_device *d, u16 addr, u8 *val,
+	u8 len)
+{
+	struct req_t req = {WRITE_MEMORY, AF9015_I2C_DEMOD, addr, 0, 0, len,
+		val};
+	return af9015_ctrl_msg(d, &req);
+}
+
+static int af9015_write_reg(struct dvb_usb_device *d, u16 addr, u8 val)
+{
+	return af9015_write_regs(d, addr, &val, 1);
+}
+
+static int af9015_read_reg(struct dvb_usb_device *d, u16 addr, u8 *val)
+{
+	struct req_t req = {READ_MEMORY, AF9015_I2C_DEMOD, addr, 0, 0, 1, val};
+	return af9015_ctrl_msg(d, &req);
+}
+
+static int af9015_write_reg_i2c(struct dvb_usb_device *d, u8 addr, u16 reg,
+	u8 val)
+{
+	struct req_t req = {WRITE_I2C, addr, reg, 1, 1, 1, &val};
+
+	if (addr == af9015_af9013_config[0].demod_address ||
+	    addr == af9015_af9013_config[1].demod_address)
+		req.addr_len = 3;
+
+	return af9015_ctrl_msg(d, &req);
+}
+
+static int af9015_read_reg_i2c(struct dvb_usb_device *d, u8 addr, u16 reg,
+	u8 *val)
+{
+	struct req_t req = {READ_I2C, addr, reg, 0, 1, 1, val};
+
+	if (addr == af9015_af9013_config[0].demod_address ||
+	    addr == af9015_af9013_config[1].demod_address)
+		req.addr_len = 3;
+
+	return af9015_ctrl_msg(d, &req);
+}
+
+static int af9015_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
+	int num)
+{
+	struct dvb_usb_device *d = i2c_get_adapdata(adap);
+	int ret = 0, i = 0;
+	u16 addr;
+	u8 mbox, addr_len;
+	struct req_t req;
+
+/* TODO: implement bus lock
+
+The bus lock is needed because there is two tuners both using same I2C-address.
+Due to that the only way to select correct tuner is use demodulator I2C-gate.
+
+................................................
+. AF9015 includes integrated AF9013 demodulator.
+. ____________                   ____________  .                ____________
+.|     uC     |                 |   demod    | .               |    tuner   |
+.|------------|                 |------------| .               |------------|
+.|   AF9015   |                 |  AF9013/5  | .               |   MXL5003  |
+.|            |--+----I2C-------|-----/ -----|-.-----I2C-------|            |
+.|            |  |              | addr 0x38  | .               |  addr 0xc6 |
+.|____________|  |              |____________| .               |____________|
+.................|..............................
+		 |               ____________                   ____________
+		 |              |   demod    |                 |    tuner   |
+		 |              |------------|                 |------------|
+		 |              |   AF9013   |                 |   MXL5003  |
+		 +----I2C-------|-----/ -----|-------I2C-------|            |
+				| addr 0x3a  |                 |  addr 0xc6 |
+				|____________|                 |____________|
+*/
+	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+		return -EAGAIN;
+
+	while (i < num) {
+		if (msg[i].addr == af9015_af9013_config[0].demod_address ||
+		    msg[i].addr == af9015_af9013_config[1].demod_address) {
+			addr = msg[i].buf[0] << 8;
+			addr += msg[i].buf[1];
+			mbox = msg[i].buf[2];
+			addr_len = 3;
+		} else {
+			addr = msg[i].buf[0];
+			addr_len = 1;
+			mbox = 0;
+		}
+
+		if (num > i + 1 && (msg[i+1].flags & I2C_M_RD)) {
+			if (msg[i].addr ==
+				af9015_af9013_config[0].demod_address)
+				req.cmd = READ_MEMORY;
+			else
+				req.cmd = READ_I2C;
+			req.i2c_addr = msg[i].addr;
+			req.addr = addr;
+			req.mbox = mbox;
+			req.addr_len = addr_len;
+			req.data_len = msg[i+1].len;
+			req.data = &msg[i+1].buf[0];
+			ret = af9015_ctrl_msg(d, &req);
+			i += 2;
+		} else {
+			if (msg[i].addr ==
+				af9015_af9013_config[0].demod_address)
+				req.cmd = WRITE_MEMORY;
+			else
+				req.cmd = WRITE_I2C;
+			req.i2c_addr = msg[i].addr;
+			req.addr = addr;
+			req.mbox = mbox;
+			req.addr_len = addr_len;
+			req.data_len = msg[i].len-addr_len;
+			req.data = &msg[i].buf[addr_len];
+			ret = af9015_ctrl_msg(d, &req);
+			i += 1;
+		}
+		if (ret)
+			goto error;
+
+	}
+	ret = i;
+
+error:
+	mutex_unlock(&d->i2c_mutex);
+
+	return ret;
+}
+
+static u32 af9015_i2c_func(struct i2c_adapter *adapter)
+{
+	return I2C_FUNC_I2C;
+}
+
+static struct i2c_algorithm af9015_i2c_algo = {
+	.master_xfer = af9015_i2c_xfer,
+	.functionality = af9015_i2c_func,
+};
+
+static int af9015_do_reg_bit(struct dvb_usb_device *d, u16 addr, u8 bit, u8 op)
+{
+	int ret;
+	u8 val, mask = 0x01;
+
+	ret = af9015_read_reg(d, addr, &val);
+	if (ret)
+		return ret;
+
+	mask <<= bit;
+	if (op) {
+		/* set bit */
+		val |= mask;
+	} else {
+		/* clear bit */
+		mask ^= 0xff;
+		val &= mask;
+	}
+
+	return af9015_write_reg(d, addr, val);
+}
+
+static int af9015_set_reg_bit(struct dvb_usb_device *d, u16 addr, u8 bit)
+{
+	return af9015_do_reg_bit(d, addr, bit, 1);
+}
+
+static int af9015_clear_reg_bit(struct dvb_usb_device *d, u16 addr, u8 bit)
+{
+	return af9015_do_reg_bit(d, addr, bit, 0);
+}
+
+static int af9015_init_endpoint(struct dvb_usb_device *d)
+{
+	int ret;
+	u16 frame_size;
+	u8  packet_size;
+	deb_info("%s: USB speed:%d\n", __func__, d->udev->speed);
+
+#define TS_PACKET_SIZE            188
+
+#define TS_USB20_PACKET_COUNT     348
+#define TS_USB20_FRAME_SIZE       (TS_PACKET_SIZE*TS_USB20_PACKET_COUNT)
+
+#define TS_USB11_PACKET_COUNT      21
+#define TS_USB11_FRAME_SIZE       (TS_PACKET_SIZE*TS_USB11_PACKET_COUNT)
+
+#define TS_USB20_MAX_PACKET_SIZE  512
+#define TS_USB11_MAX_PACKET_SIZE   64
+
+	if (d->udev->speed == USB_SPEED_FULL) {
+		frame_size = TS_USB11_FRAME_SIZE/4;
+		packet_size = TS_USB11_MAX_PACKET_SIZE/4;
+	} else {
+		frame_size = TS_USB20_FRAME_SIZE/4;
+		packet_size = TS_USB20_MAX_PACKET_SIZE/4;
+	}
+
+	ret = af9015_set_reg_bit(d, 0xd507, 2); /* assert EP4 reset */
+	if (ret)
+		goto error;
+	ret = af9015_set_reg_bit(d, 0xd50b, 1); /* assert EP5 reset */
+	if (ret)
+		goto error;
+	ret = af9015_clear_reg_bit(d, 0xdd11, 5); /* disable EP4 */
+	if (ret)
+		goto error;
+	ret = af9015_clear_reg_bit(d, 0xdd11, 6); /* disable EP5 */
+	if (ret)
+		goto error;
+	ret = af9015_set_reg_bit(d, 0xdd11, 5); /* enable EP4 */
+	if (ret)
+		goto error;
+	if (af9015_config.dual_mode) {
+		ret = af9015_set_reg_bit(d, 0xdd11, 6); /* enable EP5 */
+		if (ret)
+			goto error;
+	}
+	ret = af9015_clear_reg_bit(d, 0xdd13, 5); /* disable EP4 NAK */
+	if (ret)
+		goto error;
+	if (af9015_config.dual_mode) {
+		ret = af9015_clear_reg_bit(d, 0xdd13, 6); /* disable EP5 NAK */
+		if (ret)
+			goto error;
+	}
+	/* EP4 xfer length */
+	ret = af9015_write_reg(d, 0xdd88, frame_size & 0xff);
+	if (ret)
+		goto error;
+	ret = af9015_write_reg(d, 0xdd89, frame_size >> 8);
+	if (ret)
+		goto error;
+	/* EP5 xfer length */
+	ret = af9015_write_reg(d, 0xdd8a, frame_size & 0xff);
+	if (ret)
+		goto error;
+	ret = af9015_write_reg(d, 0xdd8b, frame_size >> 8);
+	if (ret)
+		goto error;
+	ret = af9015_write_reg(d, 0xdd0c, packet_size); /* EP4 packet size */
+	if (ret)
+		goto error;
+	ret = af9015_write_reg(d, 0xdd0d, packet_size); /* EP5 packet size */
+	if (ret)
+		goto error;
+	ret = af9015_clear_reg_bit(d, 0xd507, 2); /* negate EP4 reset */
+	if (ret)
+		goto error;
+	if (af9015_config.dual_mode) {
+		ret = af9015_clear_reg_bit(d, 0xd50b, 1); /* negate EP5 reset */
+		if (ret)
+			goto error;
+	}
+
+	/* enable / disable mp2if2 */
+	if (af9015_config.dual_mode)
+		ret = af9015_set_reg_bit(d, 0xd50b, 0);
+	else
+		ret = af9015_clear_reg_bit(d, 0xd50b, 0);
+error:
+	if (ret)
+		err("endpoint init failed:%d", ret);
+	return ret;
+}
+
+static int af9015_copy_firmware(struct dvb_usb_device *d)
+{
+	int ret;
+	u8 fw_params[4];
+	u8 val, i;
+	struct req_t req = {COPY_FIRMWARE, 0, 0x5100, 0, 0, sizeof(fw_params),
+		fw_params };
+	deb_info("%s:\n", __func__);
+
+	fw_params[0] = af9015_config.firmware_size >> 8;
+	fw_params[1] = af9015_config.firmware_size & 0xff;
+	fw_params[2] = af9015_config.firmware_checksum >> 8;
+	fw_params[3] = af9015_config.firmware_checksum & 0xff;
+
+	/* wait 2nd demodulator ready */
+	msleep(100);
+
+	ret = af9015_read_reg_i2c(d, 0x3a, 0x98be, &val);
+	if (ret)
+		goto error;
+	else
+		deb_info("%s: firmware status:%02x\n", __func__, val);
+
+	if (val == 0x0c) /* fw is running, no need for download */
+		goto exit;
+
+	/* set I2C master clock to fast (to speed up firmware copy) */
+	ret = af9015_write_reg(d, 0xd416, 0x04); /* 0x04 * 400ns */
+	if (ret)
+		goto error;
+
+	msleep(50);
+
+	/* copy firmware */
+	ret = af9015_ctrl_msg(d, &req);
+	if (ret)
+		err("firmware copy cmd failed:%d", ret);
+	deb_info("%s: firmware copy done\n", __func__);
+
+	/* set I2C master clock back to normal */
+	ret = af9015_write_reg(d, 0xd416, 0x14); /* 0x14 * 400ns */
+	if (ret)
+		goto error;
+
+	/* request boot firmware */
+	ret = af9015_write_reg_i2c(d, af9015_af9013_config[1].demod_address,
+		0xe205, 1);
+	deb_info("%s: firmware boot cmd status:%d\n", __func__, ret);
+	if (ret)
+		goto error;
+
+	for (i = 0; i < 15; i++) {
+		msleep(100);
+
+		/* check firmware status */
+		ret = af9015_read_reg_i2c(d,
+			af9015_af9013_config[1].demod_address, 0x98be, &val);
+		deb_info("%s: firmware status cmd status:%d fw status:%02x\n",
+			__func__, ret, val);
+		if (ret)
+			goto error;
+
+		if (val == 0x0c || val == 0x04) /* success or fail */
+			break;
+	}
+
+	if (val == 0x04) {
+		err("firmware did not run");
+		ret = -1;
+	} else if (val != 0x0c) {
+		err("firmware boot timeout");
+		ret = -1;
+	}
+
+error:
+exit:
+	return ret;
+}
+
+/* dump eeprom */
+static int af9015_eeprom_dump(struct dvb_usb_device *d)
+{
+	char buf[52], buf2[4];
+	u8 reg, val;
+
+	for (reg = 0; ; reg++) {
+		if (reg % 16 == 0) {
+			if (reg)
+				deb_info("%s\n", buf);
+			sprintf(buf, "%02x: ", reg);
+		}
+		if (af9015_read_reg_i2c(d, AF9015_I2C_EEPROM, reg, &val) == 0)
+			sprintf(buf2, "%02x ", val);
+		else
+			strcpy(buf2, "-- ");
+		strcat(buf, buf2);
+		if (reg == 0xff)
+			break;
+	}
+	deb_info("%s\n", buf);
+	return 0;
+}
+
+int af9015_download_ir_table(struct dvb_usb_device *d)
+{
+	int i, packets = 0, ret;
+	u16 addr = 0x9a56; /* ir-table start address */
+	struct req_t req = {WRITE_MEMORY, 0, 0, 0, 0, 1, NULL};
+	u8 *data = NULL;
+	deb_info("%s:\n", __func__);
+
+	data = af9015_config.ir_table;
+	packets = af9015_config.ir_table_size;
+
+	/* no remote */
+	if (!packets)
+		goto exit;
+
+	/* load remote ir-table */
+	for (i = 0; i < packets; i++) {
+		req.addr = addr + i;
+		req.data = &data[i];
+		ret = af9015_ctrl_msg(d, &req);
+		if (ret) {
+			err("ir-table download failed at packet %d with " \
+				"code %d", i, ret);
+			return ret;
+		}
+	}
+
+exit:
+	return 0;
+}
+
+static int af9015_init(struct dvb_usb_device *d)
+{
+	int ret;
+	deb_info("%s:\n", __func__);
+
+	ret = af9015_init_endpoint(d);
+	if (ret)
+		goto error;
+
+	ret = af9015_download_ir_table(d);
+	if (ret)
+		goto error;
+
+error:
+	return ret;
+}
+
+static int af9015_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff)
+{
+	int ret;
+	deb_info("%s: onoff:%d\n", __func__, onoff);
+
+	if (onoff)
+		ret = af9015_set_reg_bit(adap->dev, 0xd503, 0);
+	else
+		ret = af9015_clear_reg_bit(adap->dev, 0xd503, 0);
+
+	return ret;
+}
+
+static int af9015_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid,
+	int onoff)
+{
+	int ret;
+	u8 idx;
+
+	deb_info("%s: set pid filter, index %d, pid %x, onoff %d\n",
+		__func__, index, pid, onoff);
+
+	ret = af9015_write_reg(adap->dev, 0xd505, (pid & 0xff));
+	if (ret)
+		goto error;
+
+	ret = af9015_write_reg(adap->dev, 0xd506, (pid >> 8));
+	if (ret)
+		goto error;
+
+	idx = ((index & 0x1f) | (1 << 5));
+	ret = af9015_write_reg(adap->dev, 0xd504, idx);
+
+error:
+	return ret;
+}
+
+static int af9015_download_firmware(struct usb_device *udev,
+	const struct firmware *fw)
+{
+	int i, len, packets, remainder, ret;
+	struct req_t req = {DOWNLOAD_FIRMWARE, 0, 0, 0, 0, 0, NULL};
+	u16 addr = 0x5100; /* firmware start address */
+	u16 checksum = 0;
+
+	deb_info("%s:\n", __func__);
+
+	/* calc checksum */
+	for (i = 0; i < fw->size; i++)
+		checksum += fw->data[i];
+
+	af9015_config.firmware_size = fw->size;
+	af9015_config.firmware_checksum = checksum;
+
+	#define FW_PACKET_MAX_DATA  55
+
+	packets = fw->size / FW_PACKET_MAX_DATA;
+	remainder = fw->size % FW_PACKET_MAX_DATA;
+	len = FW_PACKET_MAX_DATA;
+	for (i = 0; i <= packets; i++) {
+		if (i == packets)  /* set size of the last packet */
+			len = remainder;
+
+		req.data_len = len;
+		req.data = (u8 *)(fw->data + i * FW_PACKET_MAX_DATA);
+		req.addr = addr;
+		addr += FW_PACKET_MAX_DATA;
+
+		ret = af9015_rw_udev(udev, &req);
+		if (ret) {
+			err("firmware download failed at packet %d with " \
+				"code %d", i, ret);
+			goto error;
+		}
+	}
+
+	/* firmware loaded, request boot */
+	req.cmd = BOOT;
+	ret = af9015_rw_udev(udev, &req);
+	if (ret) {
+		err("firmware boot failed:%d", ret);
+		goto error;
+	}
+
+	/* firmware is running, reconnect device in the usb bus */
+	req.cmd = RECONNECT_USB;
+	ret = af9015_rw_udev(udev, &req);
+	if (ret)
+		err("reconnect failed: %d", ret);
+
+error:
+	return ret;
+}
+
+static int af9015_read_config(struct usb_device *udev)
+{
+	int ret;
+	u8 val, i, offset = 0;
+	struct req_t req = {READ_I2C, AF9015_I2C_EEPROM, 0, 0, 1, 1, &val};
+	char manufacturer[10];
+
+	/* IR remote controller */
+	req.addr = AF9015_EEPROM_IR_MODE;
+	ret = af9015_rw_udev(udev, &req);
+	if (ret)
+		goto error;
+	deb_info("%s: IR mode:%d\n", __func__, val);
+	for (i = 0; i < af9015_properties_count; i++) {
+		if (val == AF9015_IR_MODE_DISABLED || val == 0x04) {
+			af9015_properties[i].rc_key_map = NULL;
+			af9015_properties[i].rc_key_map_size  = 0;
+		} else if (dvb_usb_af9015_remote) {
+			/* load remote defined as module param */
+			switch (dvb_usb_af9015_remote) {
+			case AF9015_REMOTE_A_LINK_DTU_M:
+				af9015_properties[i].rc_key_map =
+				  af9015_rc_keys_a_link;
+				af9015_properties[i].rc_key_map_size =
+				  ARRAY_SIZE(af9015_rc_keys_a_link);
+				af9015_config.ir_table = af9015_ir_table_a_link;
+				af9015_config.ir_table_size =
+				  ARRAY_SIZE(af9015_ir_table_a_link);
+				break;
+			case AF9015_REMOTE_MSI_DIGIVOX_MINI_II_V3:
+				af9015_properties[i].rc_key_map =
+				  af9015_rc_keys_msi;
+				af9015_properties[i].rc_key_map_size =
+				  ARRAY_SIZE(af9015_rc_keys_msi);
+				af9015_config.ir_table = af9015_ir_table_msi;
+				af9015_config.ir_table_size =
+				  ARRAY_SIZE(af9015_ir_table_msi);
+				break;
+			case AF9015_REMOTE_MYGICTV_U718:
+				af9015_properties[i].rc_key_map =
+				  af9015_rc_keys_mygictv;
+				af9015_properties[i].rc_key_map_size =
+				  ARRAY_SIZE(af9015_rc_keys_mygictv);
+				af9015_config.ir_table =
+				  af9015_ir_table_mygictv;
+				af9015_config.ir_table_size =
+				  ARRAY_SIZE(af9015_ir_table_mygictv);
+				break;
+			}
+		} else {
+			switch (udev->descriptor.idVendor) {
+			case USB_VID_LEADTEK:
+				af9015_properties[i].rc_key_map =
+				  af9015_rc_keys_leadtek;
+				af9015_properties[i].rc_key_map_size =
+				  ARRAY_SIZE(af9015_rc_keys_leadtek);
+				af9015_config.ir_table =
+				  af9015_ir_table_leadtek;
+				af9015_config.ir_table_size =
+				  ARRAY_SIZE(af9015_ir_table_leadtek);
+				break;
+			case USB_VID_VISIONPLUS:
+				if (udev->descriptor.idProduct ==
+				USB_PID_AZUREWAVE_AD_TU700) {
+					af9015_properties[i].rc_key_map =
+					  af9015_rc_keys_twinhan;
+					af9015_properties[i].rc_key_map_size =
+					  ARRAY_SIZE(af9015_rc_keys_twinhan);
+					af9015_config.ir_table =
+					  af9015_ir_table_twinhan;
+					af9015_config.ir_table_size =
+					  ARRAY_SIZE(af9015_ir_table_twinhan);
+				}
+				break;
+			case USB_VID_KWORLD_2:
+				/* TODO: use correct rc keys */
+				af9015_properties[i].rc_key_map =
+				  af9015_rc_keys_twinhan;
+				af9015_properties[i].rc_key_map_size =
+				  ARRAY_SIZE(af9015_rc_keys_twinhan);
+				af9015_config.ir_table = af9015_ir_table_kworld;
+				af9015_config.ir_table_size =
+				  ARRAY_SIZE(af9015_ir_table_kworld);
+				break;
+			/* Check USB manufacturer and product strings and try
+			   to determine correct remote in case of chip vendor
+			   reference IDs are used. */
+			case USB_VID_AFATECH:
+				memset(manufacturer, 0, sizeof(manufacturer));
+				usb_string(udev, udev->descriptor.iManufacturer,
+					manufacturer, sizeof(manufacturer));
+				if (!strcmp("Geniatech", manufacturer)) {
+					/* iManufacturer 1 Geniatech
+					   iProduct      2 AF9015 */
+					af9015_properties[i].rc_key_map =
+					  af9015_rc_keys_mygictv;
+					af9015_properties[i].rc_key_map_size =
+					  ARRAY_SIZE(af9015_rc_keys_mygictv);
+					af9015_config.ir_table =
+					  af9015_ir_table_mygictv;
+					af9015_config.ir_table_size =
+					  ARRAY_SIZE(af9015_ir_table_mygictv);
+				} else if (!strcmp("MSI", manufacturer)) {
+					/* iManufacturer 1 MSI
+					   iProduct      2 MSI K-VOX */
+					af9015_properties[i].rc_key_map =
+					  af9015_rc_keys_msi;
+					af9015_properties[i].rc_key_map_size =
+					  ARRAY_SIZE(af9015_rc_keys_msi);
+					af9015_config.ir_table =
+					  af9015_ir_table_msi;
+					af9015_config.ir_table_size =
+					  ARRAY_SIZE(af9015_ir_table_msi);
+				}
+				break;
+			}
+		}
+	}
+
+	/* TS mode - one or two receivers */
+	req.addr = AF9015_EEPROM_TS_MODE;
+	ret = af9015_rw_udev(udev, &req);
+	if (ret)
+		goto error;
+	af9015_config.dual_mode = val;
+	deb_info("%s: TS mode:%d\n", __func__, af9015_config.dual_mode);
+	/* disable dual mode by default because it is buggy */
+	if (!dvb_usb_af9015_dual_mode)
+		af9015_config.dual_mode = 0;
+
+	/* set buffer size according to USB port speed */
+	for (i = 0; i < af9015_properties_count; i++) {
+		/* USB1.1 set smaller buffersize and disable 2nd adapter */
+		if (udev->speed == USB_SPEED_FULL) {
+			af9015_properties[i].adapter->stream.u.bulk.buffersize =
+				TS_USB11_MAX_PACKET_SIZE;
+			/* disable 2nd adapter because we don't have
+			   PID-filters */
+			af9015_config.dual_mode = 0;
+		} else {
+			af9015_properties[i].adapter->stream.u.bulk.buffersize =
+				TS_USB20_MAX_PACKET_SIZE;
+		}
+	}
+
+	if (af9015_config.dual_mode) {
+		/* read 2nd demodulator I2C address */
+		req.addr = AF9015_EEPROM_DEMOD2_I2C;
+		ret = af9015_rw_udev(udev, &req);
+		if (ret)
+			goto error;
+		af9015_af9013_config[1].demod_address = val;
+
+		/* enable 2nd adapter */
+		for (i = 0; i < af9015_properties_count; i++)
+			af9015_properties[i].num_adapters = 2;
+
+	} else {
+		 /* disable 2nd adapter */
+		for (i = 0; i < af9015_properties_count; i++)
+			af9015_properties[i].num_adapters = 1;
+	}
+
+	for (i = 0; i < af9015_properties[0].num_adapters; i++) {
+		if (i == 1)
+			offset = AF9015_EEPROM_OFFSET;
+		/* xtal */
+		req.addr = AF9015_EEPROM_XTAL_TYPE1 + offset;
+		ret = af9015_rw_udev(udev, &req);
+		if (ret)
+			goto error;
+		switch (val) {
+		case 0:
+			af9015_af9013_config[i].adc_clock = 28800;
+			break;
+		case 1:
+			af9015_af9013_config[i].adc_clock = 20480;
+			break;
+		case 2:
+			af9015_af9013_config[i].adc_clock = 28000;
+			break;
+		case 3:
+			af9015_af9013_config[i].adc_clock = 25000;
+			break;
+		};
+		deb_info("%s: [%d] xtal:%d set adc_clock:%d\n", __func__, i,
+			val, af9015_af9013_config[i].adc_clock);
+
+		/* tuner IF */
+		req.addr = AF9015_EEPROM_IF1H + offset;
+		ret = af9015_rw_udev(udev, &req);
+		if (ret)
+			goto error;
+		af9015_af9013_config[i].tuner_if = val << 8;
+		req.addr = AF9015_EEPROM_IF1L + offset;
+		ret = af9015_rw_udev(udev, &req);
+		if (ret)
+			goto error;
+		af9015_af9013_config[i].tuner_if += val;
+		deb_info("%s: [%d] IF1:%d\n", __func__, i,
+			af9015_af9013_config[0].tuner_if);
+
+		/* MT2060 IF1 */
+		req.addr = AF9015_EEPROM_MT2060_IF1H  + offset;
+		ret = af9015_rw_udev(udev, &req);
+		if (ret)
+			goto error;
+		af9015_config.mt2060_if1[i] = val << 8;
+		req.addr = AF9015_EEPROM_MT2060_IF1L + offset;
+		ret = af9015_rw_udev(udev, &req);
+		if (ret)
+			goto error;
+		af9015_config.mt2060_if1[i] += val;
+		deb_info("%s: [%d] MT2060 IF1:%d\n", __func__, i,
+			af9015_config.mt2060_if1[i]);
+
+		/* tuner */
+		req.addr =  AF9015_EEPROM_TUNER_ID1 + offset;
+		ret = af9015_rw_udev(udev, &req);
+		if (ret)
+			goto error;
+		switch (val) {
+		case AF9013_TUNER_ENV77H11D5:
+		case AF9013_TUNER_MT2060:
+		case AF9013_TUNER_MC44S803:
+		case AF9013_TUNER_QT1010:
+		case AF9013_TUNER_UNKNOWN:
+		case AF9013_TUNER_MT2060_2:
+		case AF9013_TUNER_TDA18271:
+		case AF9013_TUNER_QT1010A:
+			af9015_af9013_config[i].rf_spec_inv = 1;
+			break;
+		case AF9013_TUNER_MXL5003D:
+		case AF9013_TUNER_MXL5005D:
+		case AF9013_TUNER_MXL5005R:
+			af9015_af9013_config[i].rf_spec_inv = 0;
+			break;
+		default:
+			warn("tuner id:%d not supported, please report!", val);
+			return -ENODEV;
+		};
+
+		af9015_af9013_config[i].tuner = val;
+		deb_info("%s: [%d] tuner id:%d\n", __func__, i, val);
+	}
+
+error:
+	if (ret)
+		err("eeprom read failed:%d", ret);
+
+	return ret;
+}
+
+static int af9015_identify_state(struct usb_device *udev,
+				 struct dvb_usb_device_properties *props,
+				 struct dvb_usb_device_description **desc,
+				 int *cold)
+{
+	int ret;
+	u8 reply;
+	struct req_t req = {GET_CONFIG, 0, 0, 0, 0, 1, &reply};
+
+	ret = af9015_rw_udev(udev, &req);
+	if (ret)
+		return ret;
+
+	deb_info("%s: reply:%02x\n", __func__, reply);
+	if (reply == 0x02)
+		*cold = 0;
+	else
+		*cold = 1;
+
+	return ret;
+}
+
+static int af9015_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
+{
+	u8 buf[8];
+	struct req_t req = {GET_IR_CODE, 0, 0, 0, 0, sizeof(buf), buf};
+	struct dvb_usb_rc_key *keymap = d->props.rc_key_map;
+	int i, ret;
+
+	memset(buf, 0, sizeof(buf));
+
+	ret = af9015_ctrl_msg(d, &req);
+	if (ret)
+		return ret;
+
+	*event = 0;
+	*state = REMOTE_NO_KEY_PRESSED;
+
+	for (i = 0; i < d->props.rc_key_map_size; i++) {
+		if (!buf[1] && keymap[i].custom == buf[0] &&
+		    keymap[i].data == buf[2]) {
+			*event = keymap[i].event;
+			*state = REMOTE_KEY_PRESSED;
+			break;
+		}
+	}
+	if (!buf[1])
+		deb_rc("%s: %02x %02x %02x %02x %02x %02x %02x %02x\n",
+			__func__, buf[0], buf[1], buf[2], buf[3], buf[4],
+			buf[5], buf[6], buf[7]);
+
+	return 0;
+}
+
+/* init 2nd I2C adapter */
+int af9015_i2c_init(struct dvb_usb_device *d)
+{
+	int ret;
+	struct af9015_state *state = d->priv;
+	deb_info("%s:\n", __func__);
+
+	strncpy(state->i2c_adap.name, d->desc->name,
+		sizeof(state->i2c_adap.name));
+#ifdef I2C_ADAP_CLASS_TV_DIGITAL
+	state->i2c_adap.class = I2C_ADAP_CLASS_TV_DIGITAL,
+#else
+	state->i2c_adap.class = I2C_CLASS_TV_DIGITAL,
+#endif
+	state->i2c_adap.algo      = d->props.i2c_algo;
+	state->i2c_adap.algo_data = NULL;
+	state->i2c_adap.dev.parent = &d->udev->dev;
+
+	i2c_set_adapdata(&state->i2c_adap, d);
+
+	ret = i2c_add_adapter(&state->i2c_adap);
+	if (ret < 0)
+		err("could not add i2c adapter");
+
+	return ret;
+}
+
+static int af9015_af9013_frontend_attach(struct dvb_usb_adapter *adap)
+{
+	int ret;
+	struct af9015_state *state = adap->dev->priv;
+	struct i2c_adapter *i2c_adap;
+
+	if (adap->id == 0) {
+		/* select I2C adapter */
+		i2c_adap = &adap->dev->i2c_adap;
+
+		deb_info("%s: init I2C\n", __func__);
+		ret = af9015_i2c_init(adap->dev);
+
+		/* dump eeprom (debug) */
+		ret = af9015_eeprom_dump(adap->dev);
+		if (ret)
+			return ret;
+	} else {
+		/* select I2C adapter */
+		i2c_adap = &state->i2c_adap;
+
+		/* copy firmware to 2nd demodulator */
+		if (af9015_config.dual_mode) {
+			ret = af9015_copy_firmware(adap->dev);
+			if (ret) {
+				err("firmware copy to 2nd frontend " \
+					"failed, will disable it");
+				af9015_config.dual_mode = 0;
+				return -ENODEV;
+			}
+		} else {
+			return -ENODEV;
+		}
+	}
+
+	/* attach demodulator */
+	adap->fe = dvb_attach(af9013_attach, &af9015_af9013_config[adap->id],
+		i2c_adap);
+
+	return adap->fe == NULL ? -ENODEV : 0;
+}
+
+static struct mt2060_config af9015_mt2060_config = {
+	.i2c_address = 0xc0,
+	.clock_out = 0,
+};
+
+static struct qt1010_config af9015_qt1010_config = {
+	.i2c_address = 0xc4,
+};
+
+static struct tda18271_config af9015_tda18271_config = {
+	.gate = TDA18271_GATE_DIGITAL,
+	.small_i2c = 1,
+};
+
+static struct mxl5005s_config af9015_mxl5003_config = {
+	.i2c_address     = 0xc6,
+	.if_freq         = IF_FREQ_4570000HZ,
+	.xtal_freq       = CRYSTAL_FREQ_16000000HZ,
+	.agc_mode        = MXL_SINGLE_AGC,
+	.tracking_filter = MXL_TF_DEFAULT,
+	.rssi_enable     = MXL_RSSI_ENABLE,
+	.cap_select      = MXL_CAP_SEL_ENABLE,
+	.div_out         = MXL_DIV_OUT_4,
+	.clock_out       = MXL_CLOCK_OUT_DISABLE,
+	.output_load     = MXL5005S_IF_OUTPUT_LOAD_200_OHM,
+	.top		 = MXL5005S_TOP_25P2,
+	.mod_mode        = MXL_DIGITAL_MODE,
+	.if_mode         = MXL_ZERO_IF,
+	.AgcMasterByte   = 0x00,
+};
+
+static struct mxl5005s_config af9015_mxl5005_config = {
+	.i2c_address     = 0xc6,
+	.if_freq         = IF_FREQ_4570000HZ,
+	.xtal_freq       = CRYSTAL_FREQ_16000000HZ,
+	.agc_mode        = MXL_SINGLE_AGC,
+	.tracking_filter = MXL_TF_OFF,
+	.rssi_enable     = MXL_RSSI_ENABLE,
+	.cap_select      = MXL_CAP_SEL_ENABLE,
+	.div_out         = MXL_DIV_OUT_4,
+	.clock_out       = MXL_CLOCK_OUT_DISABLE,
+	.output_load     = MXL5005S_IF_OUTPUT_LOAD_200_OHM,
+	.top		 = MXL5005S_TOP_25P2,
+	.mod_mode        = MXL_DIGITAL_MODE,
+	.if_mode         = MXL_ZERO_IF,
+	.AgcMasterByte   = 0x00,
+};
+
+static int af9015_tuner_attach(struct dvb_usb_adapter *adap)
+{
+	struct af9015_state *state = adap->dev->priv;
+	struct i2c_adapter *i2c_adap;
+	int ret;
+	deb_info("%s: \n", __func__);
+
+	/* select I2C adapter */
+	if (adap->id == 0)
+		i2c_adap = &adap->dev->i2c_adap;
+	else
+		i2c_adap = &state->i2c_adap;
+
+	switch (af9015_af9013_config[adap->id].tuner) {
+	case AF9013_TUNER_MT2060:
+	case AF9013_TUNER_MT2060_2:
+		ret = dvb_attach(mt2060_attach, adap->fe, i2c_adap,
+			&af9015_mt2060_config,
+			af9015_config.mt2060_if1[adap->id])
+			== NULL ? -ENODEV : 0;
+		break;
+	case AF9013_TUNER_QT1010:
+	case AF9013_TUNER_QT1010A:
+		ret = dvb_attach(qt1010_attach, adap->fe, i2c_adap,
+			&af9015_qt1010_config) == NULL ? -ENODEV : 0;
+		break;
+	case AF9013_TUNER_TDA18271:
+		ret = dvb_attach(tda18271_attach, adap->fe, 0xc0, i2c_adap,
+			&af9015_tda18271_config) == NULL ? -ENODEV : 0;
+		break;
+	case AF9013_TUNER_MXL5003D:
+		ret = dvb_attach(mxl5005s_attach, adap->fe, i2c_adap,
+			&af9015_mxl5003_config) == NULL ? -ENODEV : 0;
+		break;
+	case AF9013_TUNER_MXL5005D:
+	case AF9013_TUNER_MXL5005R:
+		ret = dvb_attach(mxl5005s_attach, adap->fe, i2c_adap,
+			&af9015_mxl5005_config) == NULL ? -ENODEV : 0;
+		break;
+	case AF9013_TUNER_ENV77H11D5:
+		ret = dvb_attach(dvb_pll_attach, adap->fe, 0xc0, i2c_adap,
+			DVB_PLL_TDA665X) == NULL ? -ENODEV : 0;
+		break;
+	case AF9013_TUNER_MC44S803:
+#if 0
+		ret = dvb_attach(mc44s80x_attach, adap->fe, i2c_adap)
+			== NULL ? -ENODEV : 0;
+#else
+		ret = -ENODEV;
+		info("Freescale MC44S803 tuner found but no driver for that" \
+			"tuner. Look at the Linuxtv.org for tuner driver" \
+			"status.");
+#endif
+		break;
+	case AF9013_TUNER_UNKNOWN:
+	default:
+		ret = -ENODEV;
+		err("Unknown tuner id:%d",
+			af9015_af9013_config[adap->id].tuner);
+	}
+	return ret;
+}
+
+static struct usb_device_id af9015_usb_table[] = {
+/*  0 */{USB_DEVICE(USB_VID_AFATECH,   USB_PID_AFATECH_AF9015_9015)},
+	{USB_DEVICE(USB_VID_AFATECH,   USB_PID_AFATECH_AF9015_9016)},
+	{USB_DEVICE(USB_VID_LEADTEK,   USB_PID_WINFAST_DTV_DONGLE_GOLD)},
+	{USB_DEVICE(USB_VID_PINNACLE,  USB_PID_PINNACLE_PCTV71E)},
+	{USB_DEVICE(USB_VID_KWORLD_2,  USB_PID_KWORLD_399U)},
+/*  5 */{USB_DEVICE(USB_VID_VISIONPLUS,
+		USB_PID_TINYTWIN)},
+	{USB_DEVICE(USB_VID_VISIONPLUS,
+		USB_PID_AZUREWAVE_AD_TU700)},
+	{USB_DEVICE(USB_VID_TERRATEC,  USB_PID_TERRATEC_CINERGY_T_USB_XE_REV2)},
+	{USB_DEVICE(USB_VID_KWORLD_2,  USB_PID_KWORLD_PC160_2T)},
+	{USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_X)},
+/* 10 */{USB_DEVICE(USB_VID_XTENSIONS, USB_PID_XTENSIONS_XD_380)},
+	{USB_DEVICE(USB_VID_MSI_2,     USB_PID_MSI_DIGIVOX_DUO)},
+	{USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_X_2)},
+	{USB_DEVICE(USB_VID_TELESTAR,  USB_PID_TELESTAR_STARSTICK_2)},
+	{USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A309)},
+/* 15 */{USB_DEVICE(USB_VID_MSI_2,     USB_PID_MSI_DIGI_VOX_MINI_III)},
+	{0},
+};
+MODULE_DEVICE_TABLE(usb, af9015_usb_table);
+
+static struct dvb_usb_device_properties af9015_properties[] = {
+	{
+		.caps = DVB_USB_IS_AN_I2C_ADAPTER,
+
+		.usb_ctrl = DEVICE_SPECIFIC,
+		.download_firmware = af9015_download_firmware,
+		.firmware = "dvb-usb-af9015.fw",
+
+		.size_of_priv = sizeof(struct af9015_state), \
+
+		.num_adapters = 2,
+		.adapter = {
+			{
+				.caps = DVB_USB_ADAP_HAS_PID_FILTER |
+				DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
+
+				.pid_filter_count = 32,
+				.pid_filter       = af9015_pid_filter,
+				.pid_filter_ctrl  = af9015_pid_filter_ctrl,
+
+				.frontend_attach =
+					af9015_af9013_frontend_attach,
+				.tuner_attach    = af9015_tuner_attach,
+				.stream = {
+					.type = USB_BULK,
+					.count = 6,
+					.endpoint = 0x84,
+				},
+			},
+			{
+				.frontend_attach =
+					af9015_af9013_frontend_attach,
+				.tuner_attach    = af9015_tuner_attach,
+				.stream = {
+					.type = USB_BULK,
+					.count = 6,
+					.endpoint = 0x85,
+				},
+			}
+		},
+
+		.identify_state = af9015_identify_state,
+
+		.rc_query         = af9015_rc_query,
+		.rc_interval      = 150,
+
+		.i2c_algo = &af9015_i2c_algo,
+
+		.num_device_descs = 9,
+		.devices = {
+			{
+				.name = "Afatech AF9015 DVB-T USB2.0 stick",
+				.cold_ids = {&af9015_usb_table[0],
+					     &af9015_usb_table[1], NULL},
+				.warm_ids = {NULL},
+			},
+			{
+				.name = "Leadtek WinFast DTV Dongle Gold",
+				.cold_ids = {&af9015_usb_table[2], NULL},
+				.warm_ids = {NULL},
+			},
+			{
+				.name = "Pinnacle PCTV 71e",
+				.cold_ids = {&af9015_usb_table[3], NULL},
+				.warm_ids = {NULL},
+			},
+			{
+				.name = "KWorld PlusTV Dual DVB-T Stick " \
+					"(DVB-T 399U)",
+				.cold_ids = {&af9015_usb_table[4], NULL},
+				.warm_ids = {NULL},
+			},
+			{
+				.name = "DigitalNow TinyTwin DVB-T Receiver",
+				.cold_ids = {&af9015_usb_table[5], NULL},
+				.warm_ids = {NULL},
+			},
+			{
+				.name = "TwinHan AzureWave AD-TU700(704J)",
+				.cold_ids = {&af9015_usb_table[6], NULL},
+				.warm_ids = {NULL},
+			},
+			{
+				.name = "TerraTec Cinergy T USB XE",
+				.cold_ids = {&af9015_usb_table[7], NULL},
+				.warm_ids = {NULL},
+			},
+			{
+				.name = "KWorld PlusTV Dual DVB-T PCI " \
+					"(DVB-T PC160-2T)",
+				.cold_ids = {&af9015_usb_table[8], NULL},
+				.warm_ids = {NULL},
+			},
+			{
+				.name = "AVerMedia AVerTV DVB-T Volar X",
+				.cold_ids = {&af9015_usb_table[9], NULL},
+				.warm_ids = {NULL},
+			},
+		}
+	}, {
+		.caps = DVB_USB_IS_AN_I2C_ADAPTER,
+
+		.usb_ctrl = DEVICE_SPECIFIC,
+		.download_firmware = af9015_download_firmware,
+		.firmware = "dvb-usb-af9015.fw",
+
+		.size_of_priv = sizeof(struct af9015_state), \
+
+		.num_adapters = 2,
+		.adapter = {
+			{
+				.caps = DVB_USB_ADAP_HAS_PID_FILTER |
+				DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
+
+				.pid_filter_count = 32,
+				.pid_filter       = af9015_pid_filter,
+				.pid_filter_ctrl  = af9015_pid_filter_ctrl,
+
+				.frontend_attach =
+					af9015_af9013_frontend_attach,
+				.tuner_attach    = af9015_tuner_attach,
+				.stream = {
+					.type = USB_BULK,
+					.count = 6,
+					.endpoint = 0x84,
+				},
+			},
+			{
+				.frontend_attach =
+					af9015_af9013_frontend_attach,
+				.tuner_attach    = af9015_tuner_attach,
+				.stream = {
+					.type = USB_BULK,
+					.count = 6,
+					.endpoint = 0x85,
+				},
+			}
+		},
+
+		.identify_state = af9015_identify_state,
+
+		.rc_query         = af9015_rc_query,
+		.rc_interval      = 150,
+
+		.i2c_algo = &af9015_i2c_algo,
+
+		.num_device_descs = 6,
+		.devices = {
+			{
+				.name = "Xtensions XD-380",
+				.cold_ids = {&af9015_usb_table[10], NULL},
+				.warm_ids = {NULL},
+			},
+			{
+				.name = "MSI DIGIVOX Duo",
+				.cold_ids = {&af9015_usb_table[11], NULL},
+				.warm_ids = {NULL},
+			},
+			{
+				.name = "Fujitsu-Siemens Slim Mobile USB DVB-T",
+				.cold_ids = {&af9015_usb_table[12], NULL},
+				.warm_ids = {NULL},
+			},
+			{
+				.name = "Telestar Starstick 2",
+				.cold_ids = {&af9015_usb_table[13], NULL},
+				.warm_ids = {NULL},
+			},
+			{
+				.name = "AVerMedia A309",
+				.cold_ids = {&af9015_usb_table[14], NULL},
+				.warm_ids = {NULL},
+			},
+			{
+				.name = "MSI Digi VOX mini III",
+				.cold_ids = {&af9015_usb_table[15], NULL},
+				.warm_ids = {NULL},
+			},
+		}
+	}
+};
+
+static int af9015_usb_probe(struct usb_interface *intf,
+			    const struct usb_device_id *id)
+{
+	int ret = 0;
+	struct dvb_usb_device *d = NULL;
+	struct usb_device *udev = interface_to_usbdev(intf);
+	u8 i;
+
+	deb_info("%s: interface:%d\n", __func__,
+		intf->cur_altsetting->desc.bInterfaceNumber);
+
+	/* interface 0 is used by DVB-T receiver and
+	   interface 1 is for remote controller (HID) */
+	if (intf->cur_altsetting->desc.bInterfaceNumber == 0) {
+		ret = af9015_read_config(udev);
+		if (ret)
+			return ret;
+
+		for (i = 0; i < af9015_properties_count; i++) {
+			ret = dvb_usb_device_init(intf, &af9015_properties[i],
+				THIS_MODULE, &d, adapter_nr);
+			if (!ret)
+				break;
+			if (ret != -ENODEV)
+				return ret;
+		}
+		if (ret)
+			return ret;
+
+		if (d)
+			ret = af9015_init(d);
+	}
+
+	return ret;
+}
+
+void af9015_i2c_exit(struct dvb_usb_device *d)
+{
+	struct af9015_state *state = d->priv;
+	deb_info("%s: \n", __func__);
+
+	/* remove 2nd I2C adapter */
+	if (d->state & DVB_USB_STATE_I2C)
+		i2c_del_adapter(&state->i2c_adap);
+}
+
+static void af9015_usb_device_exit(struct usb_interface *intf)
+{
+	struct dvb_usb_device *d = usb_get_intfdata(intf);
+	deb_info("%s: \n", __func__);
+
+	/* remove 2nd I2C adapter */
+	if (d != NULL && d->desc != NULL)
+		af9015_i2c_exit(d);
+
+	dvb_usb_device_exit(intf);
+}
+
+/* usb specific object needed to register this driver with the usb subsystem */
+static struct usb_driver af9015_usb_driver = {
+	.name = "dvb_usb_af9015",
+	.probe = af9015_usb_probe,
+	.disconnect = af9015_usb_device_exit,
+	.id_table = af9015_usb_table,
+};
+
+/* module stuff */
+static int __init af9015_usb_module_init(void)
+{
+	int ret;
+	ret = usb_register(&af9015_usb_driver);
+	if (ret)
+		err("module init failed:%d", ret);
+
+	return ret;
+}
+
+static void __exit af9015_usb_module_exit(void)
+{
+	/* deregister this driver from the USB subsystem */
+	usb_deregister(&af9015_usb_driver);
+}
+
+module_init(af9015_usb_module_init);
+module_exit(af9015_usb_module_exit);
+
+MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
+MODULE_DESCRIPTION("Driver for Afatech AF9015 DVB-T");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/af9015.h b/drivers/media/dvb/dvb-usb/af9015.h
new file mode 100644
index 0000000..882e8a4
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/af9015.h
@@ -0,0 +1,524 @@
+/*
+ * DVB USB Linux driver for Afatech AF9015 DVB-T USB2.0 receiver
+ *
+ * Copyright (C) 2007 Antti Palosaari <crope@iki.fi>
+ *
+ * Thanks to Afatech who kindly provided information.
+ *
+ *    This program is free software; you can redistribute it and/or 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 _DVB_USB_AF9015_H_
+#define _DVB_USB_AF9015_H_
+
+#define DVB_USB_LOG_PREFIX "af9015"
+#include "dvb-usb.h"
+
+extern int dvb_usb_af9015_debug;
+#define deb_info(args...) dprintk(dvb_usb_af9015_debug, 0x01, args)
+#define deb_rc(args...)   dprintk(dvb_usb_af9015_debug, 0x02, args)
+#define deb_xfer(args...) dprintk(dvb_usb_af9015_debug, 0x04, args)
+#define deb_reg(args...)  dprintk(dvb_usb_af9015_debug, 0x08, args)
+#define deb_i2c(args...)  dprintk(dvb_usb_af9015_debug, 0x10, args)
+#define deb_fw(args...)   dprintk(dvb_usb_af9015_debug, 0x20, args)
+
+#define AF9015_I2C_EEPROM  0xa0
+#define AF9015_I2C_DEMOD   0x38
+#define AF9015_USB_TIMEOUT 2000
+
+/* EEPROM locations */
+#define AF9015_EEPROM_IR_MODE        0x18
+#define AF9015_EEPROM_IR_REMOTE_TYPE 0x34
+#define AF9015_EEPROM_TS_MODE        0x31
+#define AF9015_EEPROM_DEMOD2_I2C     0x32
+
+#define AF9015_EEPROM_SAW_BW1        0x35
+#define AF9015_EEPROM_XTAL_TYPE1     0x36
+#define AF9015_EEPROM_SPEC_INV1      0x37
+#define AF9015_EEPROM_IF1L           0x38
+#define AF9015_EEPROM_IF1H           0x39
+#define AF9015_EEPROM_MT2060_IF1L    0x3a
+#define AF9015_EEPROM_MT2060_IF1H    0x3b
+#define AF9015_EEPROM_TUNER_ID1      0x3c
+
+#define AF9015_EEPROM_SAW_BW2        0x45
+#define AF9015_EEPROM_XTAL_TYPE2     0x46
+#define AF9015_EEPROM_SPEC_INV2      0x47
+#define AF9015_EEPROM_IF2L           0x48
+#define AF9015_EEPROM_IF2H           0x49
+#define AF9015_EEPROM_MT2060_IF2L    0x4a
+#define AF9015_EEPROM_MT2060_IF2H    0x4b
+#define AF9015_EEPROM_TUNER_ID2      0x4c
+
+#define AF9015_EEPROM_OFFSET (AF9015_EEPROM_SAW_BW2 - AF9015_EEPROM_SAW_BW1)
+
+#define AF9015_GPIO_ON (1 << 0)
+#define AF9015_GPIO_EN (1 << 1)
+#define AF9015_GPIO_O  (1 << 2)
+#define AF9015_GPIO_I  (1 << 3)
+
+#define AF9015_GPIO_TUNER_ON  (AF9015_GPIO_ON|AF9015_GPIO_EN)
+#define AF9015_GPIO_TUNER_OFF (AF9015_GPIO_ON|AF9015_GPIO_EN|AF9015_GPIO_O)
+
+struct req_t {
+	u8  cmd;       /* [0] */
+	/*  seq */     /* [1] */
+	u8  i2c_addr;  /* [2] */
+	u16 addr;      /* [3|4] */
+	u8  mbox;      /* [5] */
+	u8  addr_len;  /* [6] */
+	u8  data_len;  /* [7] */
+	u8  *data;
+};
+
+enum af9015_cmd {
+	GET_CONFIG           = 0x10,
+	DOWNLOAD_FIRMWARE    = 0x11,
+	BOOT                 = 0x13,
+	READ_MEMORY          = 0x20,
+	WRITE_MEMORY         = 0x21,
+	READ_WRITE_I2C       = 0x22,
+	COPY_FIRMWARE        = 0x23,
+	RECONNECT_USB        = 0x5a,
+	WRITE_VIRTUAL_MEMORY = 0x26,
+	GET_IR_CODE          = 0x27,
+	READ_I2C,
+	WRITE_I2C,
+};
+
+enum af9015_ir_mode {
+	AF9015_IR_MODE_DISABLED = 0,
+	AF9015_IR_MODE_HID,
+	AF9015_IR_MODE_RLC,
+	AF9015_IR_MODE_RC6,
+};
+
+struct af9015_state {
+	struct i2c_adapter i2c_adap; /* I2C adapter for 2nd FE */
+};
+
+struct af9015_config {
+	u8  dual_mode:1;
+	u16 mt2060_if1[2];
+	u16 firmware_size;
+	u16 firmware_checksum;
+	u8  *ir_table;
+	u16 ir_table_size;
+};
+
+enum af9015_remote {
+	AF9015_REMOTE_NONE                    = 0,
+	AF9015_REMOTE_A_LINK_DTU_M,
+	AF9015_REMOTE_MSI_DIGIVOX_MINI_II_V3,
+	AF9015_REMOTE_MYGICTV_U718,
+};
+
+/* Leadtek WinFast DTV Dongle Gold */
+static struct dvb_usb_rc_key af9015_rc_keys_leadtek[] = {
+	{ 0x00, 0x1e, KEY_1 },
+	{ 0x00, 0x1f, KEY_2 },
+	{ 0x00, 0x20, KEY_3 },
+	{ 0x00, 0x21, KEY_4 },
+	{ 0x00, 0x22, KEY_5 },
+	{ 0x00, 0x23, KEY_6 },
+	{ 0x00, 0x24, KEY_7 },
+	{ 0x00, 0x25, KEY_8 },
+	{ 0x00, 0x26, KEY_9 },
+	{ 0x00, 0x27, KEY_0 },
+	{ 0x00, 0x28, KEY_ENTER },
+	{ 0x00, 0x4f, KEY_VOLUMEUP },
+	{ 0x00, 0x50, KEY_VOLUMEDOWN },
+	{ 0x00, 0x51, KEY_CHANNELDOWN },
+	{ 0x00, 0x52, KEY_CHANNELUP },
+};
+
+static u8 af9015_ir_table_leadtek[] = {
+	0x03, 0xfc, 0x00, 0xff, 0x1a, 0x01, 0x00,
+	0x03, 0xfc, 0x56, 0xa9, 0x00, 0x00, 0x00,
+	0x03, 0xfc, 0x4b, 0xb4, 0x00, 0x00, 0x00,
+	0x03, 0xfc, 0x4c, 0xb3, 0xb2, 0x04, 0x00,
+	0x03, 0xfc, 0x4d, 0xb2, 0x00, 0x00, 0x00,
+	0x03, 0xfc, 0x4e, 0xb1, 0x00, 0x00, 0x00,
+	0x03, 0xfc, 0x1f, 0xe0, 0x3d, 0x00, 0x00,
+	0x03, 0xfc, 0x40, 0xbf, 0x13, 0x01, 0x00,
+	0x03, 0xfc, 0x14, 0xeb, 0x10, 0x00, 0x00,
+	0x03, 0xfc, 0x49, 0xb6, 0x05, 0x01, 0x00,
+	0x03, 0xfc, 0x50, 0xaf, 0x29, 0x00, 0x00,
+	0x03, 0xfc, 0x0c, 0xf3, 0x52, 0x00, 0x00,
+	0x03, 0xfc, 0x03, 0xfc, 0x09, 0x00, 0x00,
+	0x03, 0xfc, 0x08, 0xf7, 0x50, 0x00, 0x00,
+	0x03, 0xfc, 0x13, 0xec, 0x28, 0x00, 0x00,
+	0x03, 0xfc, 0x04, 0xfb, 0x4f, 0x00, 0x00,
+	0x03, 0xfc, 0x4f, 0xb0, 0x0f, 0x01, 0x00,
+	0x03, 0xfc, 0x10, 0xef, 0x51, 0x00, 0x00,
+	0x03, 0xfc, 0x51, 0xae, 0x3f, 0x00, 0x00,
+	0x03, 0xfc, 0x42, 0xbd, 0x13, 0x00, 0x00,
+	0x03, 0xfc, 0x43, 0xbc, 0x00, 0x00, 0x00,
+	0x03, 0xfc, 0x44, 0xbb, 0x11, 0x00, 0x00,
+	0x03, 0xfc, 0x52, 0xad, 0x19, 0x00, 0x00,
+	0x03, 0xfc, 0x54, 0xab, 0x05, 0x00, 0x00,
+	0x03, 0xfc, 0x46, 0xb9, 0x29, 0x00, 0x00,
+	0x03, 0xfc, 0x55, 0xaa, 0x2b, 0x00, 0x00,
+	0x03, 0xfc, 0x53, 0xac, 0x41, 0x00, 0x00,
+	0x03, 0xfc, 0x05, 0xfa, 0x1e, 0x00, 0x00,
+	0x03, 0xfc, 0x06, 0xf9, 0x1f, 0x00, 0x00,
+	0x03, 0xfc, 0x07, 0xf8, 0x20, 0x00, 0x00,
+	0x03, 0xfc, 0x1e, 0xe1, 0x19, 0x00, 0x00,
+	0x03, 0xfc, 0x09, 0xf6, 0x21, 0x00, 0x00,
+	0x03, 0xfc, 0x0a, 0xf5, 0x22, 0x00, 0x00,
+	0x03, 0xfc, 0x0b, 0xf4, 0x23, 0x00, 0x00,
+	0x03, 0xfc, 0x1b, 0xe4, 0x16, 0x00, 0x00,
+	0x03, 0xfc, 0x0d, 0xf2, 0x24, 0x00, 0x00,
+	0x03, 0xfc, 0x0e, 0xf1, 0x25, 0x00, 0x00,
+	0x03, 0xfc, 0x0f, 0xf0, 0x26, 0x00, 0x00,
+	0x03, 0xfc, 0x16, 0xe9, 0x28, 0x00, 0x00,
+	0x03, 0xfc, 0x41, 0xbe, 0x37, 0x00, 0x00,
+	0x03, 0xfc, 0x12, 0xed, 0x27, 0x00, 0x00,
+	0x03, 0xfc, 0x11, 0xee, 0x2a, 0x00, 0x00,
+	0x03, 0xfc, 0x48, 0xb7, 0x2c, 0x00, 0x00,
+	0x03, 0xfc, 0x4a, 0xb5, 0x3c, 0x00, 0x00,
+	0x03, 0xfc, 0x47, 0xb8, 0x15, 0x01, 0x00,
+	0x03, 0xfc, 0x45, 0xba, 0x0b, 0x01, 0x00,
+	0x03, 0xfc, 0x5e, 0xa1, 0x43, 0x00, 0x00,
+	0x03, 0xfc, 0x5a, 0xa5, 0x42, 0x00, 0x00,
+	0x03, 0xfc, 0x5b, 0xa4, 0x4b, 0x00, 0x00,
+	0x03, 0xfc, 0x5f, 0xa0, 0x4e, 0x00, 0x00,
+};
+
+/* TwinHan AzureWave AD-TU700(704J) */
+static struct dvb_usb_rc_key af9015_rc_keys_twinhan[] = {
+	{ 0x05, 0x3f, KEY_POWER },
+	{ 0x00, 0x19, KEY_FAVORITES },    /* Favorite List */
+	{ 0x00, 0x04, KEY_TEXT },         /* Teletext */
+	{ 0x00, 0x0e, KEY_POWER },
+	{ 0x00, 0x0e, KEY_INFO },         /* Preview */
+	{ 0x00, 0x08, KEY_EPG },          /* Info/EPG */
+	{ 0x00, 0x0f, KEY_LIST },         /* Record List */
+	{ 0x00, 0x1e, KEY_1 },
+	{ 0x00, 0x1f, KEY_2 },
+	{ 0x00, 0x20, KEY_3 },
+	{ 0x00, 0x21, KEY_4 },
+	{ 0x00, 0x22, KEY_5 },
+	{ 0x00, 0x23, KEY_6 },
+	{ 0x00, 0x24, KEY_7 },
+	{ 0x00, 0x25, KEY_8 },
+	{ 0x00, 0x26, KEY_9 },
+	{ 0x00, 0x27, KEY_0 },
+	{ 0x00, 0x29, KEY_CANCEL },       /* Cancel */
+	{ 0x00, 0x4c, KEY_CLEAR },        /* Clear */
+	{ 0x00, 0x2a, KEY_BACK },         /* Back */
+	{ 0x00, 0x2b, KEY_TAB },          /* Tab */
+	{ 0x00, 0x52, KEY_UP },           /* up arrow */
+	{ 0x00, 0x51, KEY_DOWN },         /* down arrow */
+	{ 0x00, 0x4f, KEY_RIGHT },        /* right arrow */
+	{ 0x00, 0x50, KEY_LEFT },         /* left arrow */
+	{ 0x00, 0x28, KEY_ENTER },        /* Enter / ok */
+	{ 0x02, 0x52, KEY_VOLUMEUP },
+	{ 0x02, 0x51, KEY_VOLUMEDOWN },
+	{ 0x00, 0x4e, KEY_CHANNELDOWN },
+	{ 0x00, 0x4b, KEY_CHANNELUP },
+	{ 0x00, 0x4a, KEY_RECORD },
+	{ 0x01, 0x11, KEY_PLAY },
+	{ 0x00, 0x17, KEY_PAUSE },
+	{ 0x00, 0x0c, KEY_REWIND },       /* FR << */
+	{ 0x00, 0x11, KEY_FASTFORWARD },  /* FF >> */
+	{ 0x01, 0x15, KEY_PREVIOUS },     /* Replay */
+	{ 0x01, 0x0e, KEY_NEXT },         /* Skip */
+	{ 0x00, 0x13, KEY_CAMERA },       /* Capture */
+	{ 0x01, 0x0f, KEY_LANGUAGE },     /* SAP */
+	{ 0x01, 0x13, KEY_TV2 },          /* PIP */
+	{ 0x00, 0x1d, KEY_ZOOM },         /* Full Screen */
+	{ 0x01, 0x17, KEY_SUBTITLE },     /* Subtitle / CC */
+	{ 0x00, 0x10, KEY_MUTE },
+	{ 0x01, 0x19, KEY_AUDIO },        /* L/R */ /* TODO better event */
+	{ 0x01, 0x16, KEY_SLEEP },        /* Hibernate */
+	{ 0x01, 0x16, KEY_SWITCHVIDEOMODE },
+					  /* A/V */ /* TODO does not work */
+	{ 0x00, 0x06, KEY_AGAIN },        /* Recall */
+	{ 0x01, 0x16, KEY_KPPLUS },       /* Zoom+ */ /* TODO does not work */
+	{ 0x01, 0x16, KEY_KPMINUS },      /* Zoom- */ /* TODO does not work */
+	{ 0x02, 0x15, KEY_RED },
+	{ 0x02, 0x0a, KEY_GREEN },
+	{ 0x02, 0x1c, KEY_YELLOW },
+	{ 0x02, 0x05, KEY_BLUE },
+};
+
+static u8 af9015_ir_table_twinhan[] = {
+	0x00, 0xff, 0x16, 0xe9, 0x3f, 0x05, 0x00,
+	0x00, 0xff, 0x07, 0xf8, 0x16, 0x01, 0x00,
+	0x00, 0xff, 0x14, 0xeb, 0x11, 0x01, 0x00,
+	0x00, 0xff, 0x1a, 0xe5, 0x4d, 0x00, 0x00,
+	0x00, 0xff, 0x4c, 0xb3, 0x17, 0x00, 0x00,
+	0x00, 0xff, 0x12, 0xed, 0x11, 0x00, 0x00,
+	0x00, 0xff, 0x40, 0xbf, 0x0c, 0x00, 0x00,
+	0x00, 0xff, 0x11, 0xee, 0x4a, 0x00, 0x00,
+	0x00, 0xff, 0x54, 0xab, 0x13, 0x00, 0x00,
+	0x00, 0xff, 0x41, 0xbe, 0x15, 0x01, 0x00,
+	0x00, 0xff, 0x42, 0xbd, 0x0e, 0x01, 0x00,
+	0x00, 0xff, 0x43, 0xbc, 0x17, 0x01, 0x00,
+	0x00, 0xff, 0x50, 0xaf, 0x0f, 0x01, 0x00,
+	0x00, 0xff, 0x4d, 0xb2, 0x1d, 0x00, 0x00,
+	0x00, 0xff, 0x47, 0xb8, 0x13, 0x01, 0x00,
+	0x00, 0xff, 0x05, 0xfa, 0x4b, 0x00, 0x00,
+	0x00, 0xff, 0x02, 0xfd, 0x4e, 0x00, 0x00,
+	0x00, 0xff, 0x0e, 0xf1, 0x06, 0x00, 0x00,
+	0x00, 0xff, 0x1e, 0xe1, 0x52, 0x02, 0x00,
+	0x00, 0xff, 0x0a, 0xf5, 0x51, 0x02, 0x00,
+	0x00, 0xff, 0x10, 0xef, 0x10, 0x00, 0x00,
+	0x00, 0xff, 0x49, 0xb6, 0x19, 0x01, 0x00,
+	0x00, 0xff, 0x15, 0xea, 0x27, 0x00, 0x00,
+	0x00, 0xff, 0x03, 0xfc, 0x1e, 0x00, 0x00,
+	0x00, 0xff, 0x01, 0xfe, 0x1f, 0x00, 0x00,
+	0x00, 0xff, 0x06, 0xf9, 0x20, 0x00, 0x00,
+	0x00, 0xff, 0x09, 0xf6, 0x21, 0x00, 0x00,
+	0x00, 0xff, 0x1d, 0xe2, 0x22, 0x00, 0x00,
+	0x00, 0xff, 0x1f, 0xe0, 0x23, 0x00, 0x00,
+	0x00, 0xff, 0x0d, 0xf2, 0x24, 0x00, 0x00,
+	0x00, 0xff, 0x19, 0xe6, 0x25, 0x00, 0x00,
+	0x00, 0xff, 0x1b, 0xe4, 0x26, 0x00, 0x00,
+	0x00, 0xff, 0x00, 0xff, 0x2b, 0x00, 0x00,
+	0x00, 0xff, 0x4a, 0xb5, 0x4c, 0x00, 0x00,
+	0x00, 0xff, 0x4b, 0xb4, 0x52, 0x00, 0x00,
+	0x00, 0xff, 0x51, 0xae, 0x51, 0x00, 0x00,
+	0x00, 0xff, 0x52, 0xad, 0x4f, 0x00, 0x00,
+	0x00, 0xff, 0x4e, 0xb1, 0x50, 0x00, 0x00,
+	0x00, 0xff, 0x0c, 0xf3, 0x29, 0x00, 0x00,
+	0x00, 0xff, 0x4f, 0xb0, 0x28, 0x00, 0x00,
+	0x00, 0xff, 0x13, 0xec, 0x2a, 0x00, 0x00,
+	0x00, 0xff, 0x17, 0xe8, 0x19, 0x00, 0x00,
+	0x00, 0xff, 0x04, 0xfb, 0x0f, 0x00, 0x00,
+	0x00, 0xff, 0x48, 0xb7, 0x0e, 0x00, 0x00,
+	0x00, 0xff, 0x0f, 0xf0, 0x04, 0x00, 0x00,
+	0x00, 0xff, 0x1c, 0xe3, 0x08, 0x00, 0x00,
+	0x00, 0xff, 0x18, 0xe7, 0x15, 0x02, 0x00,
+	0x00, 0xff, 0x53, 0xac, 0x0a, 0x02, 0x00,
+	0x00, 0xff, 0x5e, 0xa1, 0x1c, 0x02, 0x00,
+	0x00, 0xff, 0x5f, 0xa0, 0x05, 0x02, 0x00,
+};
+
+/* A-Link DTU(m) */
+static struct dvb_usb_rc_key af9015_rc_keys_a_link[] = {
+	{ 0x00, 0x1e, KEY_1 },
+	{ 0x00, 0x1f, KEY_2 },
+	{ 0x00, 0x20, KEY_3 },
+	{ 0x00, 0x21, KEY_4 },
+	{ 0x00, 0x22, KEY_5 },
+	{ 0x00, 0x23, KEY_6 },
+	{ 0x00, 0x24, KEY_7 },
+	{ 0x00, 0x25, KEY_8 },
+	{ 0x00, 0x26, KEY_9 },
+	{ 0x00, 0x27, KEY_0 },
+	{ 0x00, 0x2e, KEY_CHANNELUP },
+	{ 0x00, 0x2d, KEY_CHANNELDOWN },
+	{ 0x04, 0x28, KEY_ZOOM },
+	{ 0x00, 0x41, KEY_MUTE },
+	{ 0x00, 0x42, KEY_VOLUMEDOWN },
+	{ 0x00, 0x43, KEY_VOLUMEUP },
+	{ 0x00, 0x44, KEY_GOTO },         /* jump */
+	{ 0x05, 0x45, KEY_POWER },
+};
+
+static u8 af9015_ir_table_a_link[] = {
+	0x08, 0xf7, 0x12, 0xed, 0x45, 0x05, 0x00, /* power */
+	0x08, 0xf7, 0x1a, 0xe5, 0x41, 0x00, 0x00, /* mute */
+	0x08, 0xf7, 0x01, 0xfe, 0x1e, 0x00, 0x00, /* 1 */
+	0x08, 0xf7, 0x1c, 0xe3, 0x21, 0x00, 0x00, /* 4 */
+	0x08, 0xf7, 0x03, 0xfc, 0x24, 0x00, 0x00, /* 7 */
+	0x08, 0xf7, 0x05, 0xfa, 0x28, 0x04, 0x00, /* zoom */
+	0x08, 0xf7, 0x00, 0xff, 0x43, 0x00, 0x00, /* volume up */
+	0x08, 0xf7, 0x16, 0xe9, 0x42, 0x00, 0x00, /* volume down */
+	0x08, 0xf7, 0x0f, 0xf0, 0x1f, 0x00, 0x00, /* 2 */
+	0x08, 0xf7, 0x0d, 0xf2, 0x22, 0x00, 0x00, /* 5 */
+	0x08, 0xf7, 0x1b, 0xe4, 0x25, 0x00, 0x00, /* 8 */
+	0x08, 0xf7, 0x06, 0xf9, 0x27, 0x00, 0x00, /* 0 */
+	0x08, 0xf7, 0x14, 0xeb, 0x2e, 0x00, 0x00, /* channel up */
+	0x08, 0xf7, 0x1d, 0xe2, 0x2d, 0x00, 0x00, /* channel down */
+	0x08, 0xf7, 0x02, 0xfd, 0x20, 0x00, 0x00, /* 3 */
+	0x08, 0xf7, 0x18, 0xe7, 0x23, 0x00, 0x00, /* 6 */
+	0x08, 0xf7, 0x04, 0xfb, 0x26, 0x00, 0x00, /* 9 */
+	0x08, 0xf7, 0x07, 0xf8, 0x44, 0x00, 0x00, /* jump */
+};
+
+/* MSI DIGIVOX mini II V3.0 */
+static struct dvb_usb_rc_key af9015_rc_keys_msi[] = {
+	{ 0x00, 0x1e, KEY_1 },
+	{ 0x00, 0x1f, KEY_2 },
+	{ 0x00, 0x20, KEY_3 },
+	{ 0x00, 0x21, KEY_4 },
+	{ 0x00, 0x22, KEY_5 },
+	{ 0x00, 0x23, KEY_6 },
+	{ 0x00, 0x24, KEY_7 },
+	{ 0x00, 0x25, KEY_8 },
+	{ 0x00, 0x26, KEY_9 },
+	{ 0x00, 0x27, KEY_0 },
+	{ 0x03, 0x0f, KEY_CHANNELUP },
+	{ 0x03, 0x0e, KEY_CHANNELDOWN },
+	{ 0x00, 0x42, KEY_VOLUMEDOWN },
+	{ 0x00, 0x43, KEY_VOLUMEUP },
+	{ 0x05, 0x45, KEY_POWER },
+	{ 0x00, 0x52, KEY_UP },           /* up */
+	{ 0x00, 0x51, KEY_DOWN },         /* down */
+	{ 0x00, 0x28, KEY_ENTER },
+};
+
+static u8 af9015_ir_table_msi[] = {
+	0x03, 0xfc, 0x17, 0xe8, 0x45, 0x05, 0x00, /* power */
+	0x03, 0xfc, 0x0d, 0xf2, 0x51, 0x00, 0x00, /* down */
+	0x03, 0xfc, 0x03, 0xfc, 0x52, 0x00, 0x00, /* up */
+	0x03, 0xfc, 0x1a, 0xe5, 0x1e, 0x00, 0x00, /* 1 */
+	0x03, 0xfc, 0x02, 0xfd, 0x1f, 0x00, 0x00, /* 2 */
+	0x03, 0xfc, 0x04, 0xfb, 0x20, 0x00, 0x00, /* 3 */
+	0x03, 0xfc, 0x1c, 0xe3, 0x21, 0x00, 0x00, /* 4 */
+	0x03, 0xfc, 0x08, 0xf7, 0x22, 0x00, 0x00, /* 5 */
+	0x03, 0xfc, 0x1d, 0xe2, 0x23, 0x00, 0x00, /* 6 */
+	0x03, 0xfc, 0x11, 0xee, 0x24, 0x00, 0x00, /* 7 */
+	0x03, 0xfc, 0x0b, 0xf4, 0x25, 0x00, 0x00, /* 8 */
+	0x03, 0xfc, 0x10, 0xef, 0x26, 0x00, 0x00, /* 9 */
+	0x03, 0xfc, 0x09, 0xf6, 0x27, 0x00, 0x00, /* 0 */
+	0x03, 0xfc, 0x14, 0xeb, 0x43, 0x00, 0x00, /* volume up */
+	0x03, 0xfc, 0x1f, 0xe0, 0x42, 0x00, 0x00, /* volume down */
+	0x03, 0xfc, 0x15, 0xea, 0x0f, 0x03, 0x00, /* channel up */
+	0x03, 0xfc, 0x05, 0xfa, 0x0e, 0x03, 0x00, /* channel down */
+	0x03, 0xfc, 0x16, 0xe9, 0x28, 0x00, 0x00, /* enter */
+};
+
+/* MYGICTV U718 */
+static struct dvb_usb_rc_key af9015_rc_keys_mygictv[] = {
+	{ 0x00, 0x3d, KEY_SWITCHVIDEOMODE },
+					  /* TV / AV */
+	{ 0x05, 0x45, KEY_POWER },
+	{ 0x00, 0x1e, KEY_1 },
+	{ 0x00, 0x1f, KEY_2 },
+	{ 0x00, 0x20, KEY_3 },
+	{ 0x00, 0x21, KEY_4 },
+	{ 0x00, 0x22, KEY_5 },
+	{ 0x00, 0x23, KEY_6 },
+	{ 0x00, 0x24, KEY_7 },
+	{ 0x00, 0x25, KEY_8 },
+	{ 0x00, 0x26, KEY_9 },
+	{ 0x00, 0x27, KEY_0 },
+	{ 0x00, 0x41, KEY_MUTE },
+	{ 0x00, 0x2a, KEY_ESC },          /* Esc */
+	{ 0x00, 0x2e, KEY_CHANNELUP },
+	{ 0x00, 0x2d, KEY_CHANNELDOWN },
+	{ 0x00, 0x42, KEY_VOLUMEDOWN },
+	{ 0x00, 0x43, KEY_VOLUMEUP },
+	{ 0x00, 0x52, KEY_UP },           /* up arrow */
+	{ 0x00, 0x51, KEY_DOWN },         /* down arrow */
+	{ 0x00, 0x4f, KEY_RIGHT },        /* right arrow */
+	{ 0x00, 0x50, KEY_LEFT },         /* left arrow */
+	{ 0x00, 0x28, KEY_ENTER },        /* ok */
+	{ 0x01, 0x15, KEY_RECORD },
+	{ 0x03, 0x13, KEY_PLAY },
+	{ 0x01, 0x13, KEY_PAUSE },
+	{ 0x01, 0x16, KEY_STOP },
+	{ 0x03, 0x07, KEY_REWIND },       /* FR << */
+	{ 0x03, 0x09, KEY_FASTFORWARD },  /* FF >> */
+	{ 0x00, 0x3b, KEY_TIME },         /* TimeShift */
+	{ 0x00, 0x3e, KEY_CAMERA },       /* Snapshot */
+	{ 0x03, 0x16, KEY_CYCLEWINDOWS }, /* yellow, min / max */
+	{ 0x00, 0x00, KEY_ZOOM },         /* 'select' (?) */
+	{ 0x03, 0x16, KEY_SHUFFLE },      /* Shuffle */
+	{ 0x03, 0x45, KEY_POWER },
+};
+
+static u8 af9015_ir_table_mygictv[] = {
+	0x02, 0xbd, 0x0c, 0xf3, 0x3d, 0x00, 0x00, /* TV / AV */
+	0x02, 0xbd, 0x14, 0xeb, 0x45, 0x05, 0x00, /* power */
+	0x02, 0xbd, 0x00, 0xff, 0x1e, 0x00, 0x00, /* 1 */
+	0x02, 0xbd, 0x01, 0xfe, 0x1f, 0x00, 0x00, /* 2 */
+	0x02, 0xbd, 0x02, 0xfd, 0x20, 0x00, 0x00, /* 3 */
+	0x02, 0xbd, 0x03, 0xfc, 0x21, 0x00, 0x00, /* 4 */
+	0x02, 0xbd, 0x04, 0xfb, 0x22, 0x00, 0x00, /* 5 */
+	0x02, 0xbd, 0x05, 0xfa, 0x23, 0x00, 0x00, /* 6 */
+	0x02, 0xbd, 0x06, 0xf9, 0x24, 0x00, 0x00, /* 7 */
+	0x02, 0xbd, 0x07, 0xf8, 0x25, 0x00, 0x00, /* 8 */
+	0x02, 0xbd, 0x08, 0xf7, 0x26, 0x00, 0x00, /* 9 */
+	0x02, 0xbd, 0x09, 0xf6, 0x27, 0x00, 0x00, /* 0 */
+	0x02, 0xbd, 0x0a, 0xf5, 0x41, 0x00, 0x00, /* mute */
+	0x02, 0xbd, 0x1c, 0xe3, 0x2a, 0x00, 0x00, /* esc */
+	0x02, 0xbd, 0x1f, 0xe0, 0x43, 0x00, 0x00, /* volume up */
+	0x02, 0xbd, 0x12, 0xed, 0x52, 0x00, 0x00, /* up arrow */
+	0x02, 0xbd, 0x11, 0xee, 0x50, 0x00, 0x00, /* left arrow */
+	0x02, 0xbd, 0x15, 0xea, 0x28, 0x00, 0x00, /* ok */
+	0x02, 0xbd, 0x10, 0xef, 0x4f, 0x00, 0x00, /* right arrow */
+	0x02, 0xbd, 0x13, 0xec, 0x51, 0x00, 0x00, /* down arrow */
+	0x02, 0xbd, 0x0e, 0xf1, 0x42, 0x00, 0x00, /* volume down */
+	0x02, 0xbd, 0x19, 0xe6, 0x15, 0x01, 0x00, /* record */
+	0x02, 0xbd, 0x1e, 0xe1, 0x13, 0x03, 0x00, /* play */
+	0x02, 0xbd, 0x16, 0xe9, 0x16, 0x01, 0x00, /* stop */
+	0x02, 0xbd, 0x0b, 0xf4, 0x28, 0x04, 0x00, /* yellow, min / max */
+	0x02, 0xbd, 0x0f, 0xf0, 0x3b, 0x00, 0x00, /* time shift */
+	0x02, 0xbd, 0x18, 0xe7, 0x2e, 0x00, 0x00, /* channel up */
+	0x02, 0xbd, 0x1a, 0xe5, 0x2d, 0x00, 0x00, /* channel down */
+	0x02, 0xbd, 0x17, 0xe8, 0x3e, 0x00, 0x00, /* snapshot */
+	0x02, 0xbd, 0x40, 0xbf, 0x13, 0x01, 0x00, /* pause */
+	0x02, 0xbd, 0x41, 0xbe, 0x09, 0x03, 0x00, /* FF >> */
+	0x02, 0xbd, 0x42, 0xbd, 0x07, 0x03, 0x00, /* FR << */
+	0x02, 0xbd, 0x43, 0xbc, 0x00, 0x00, 0x00, /* 'select' (?) */
+	0x02, 0xbd, 0x44, 0xbb, 0x16, 0x03, 0x00, /* shuffle */
+	0x02, 0xbd, 0x45, 0xba, 0x45, 0x03, 0x00, /* power */
+};
+
+/* KWorld PlusTV Dual DVB-T Stick (DVB-T 399U) */
+static u8 af9015_ir_table_kworld[] = {
+	0x86, 0x6b, 0x0c, 0xf3, 0x2e, 0x07, 0x00,
+	0x86, 0x6b, 0x16, 0xe9, 0x2d, 0x07, 0x00,
+	0x86, 0x6b, 0x1d, 0xe2, 0x37, 0x07, 0x00,
+	0x86, 0x6b, 0x00, 0xff, 0x1e, 0x07, 0x00,
+	0x86, 0x6b, 0x01, 0xfe, 0x1f, 0x07, 0x00,
+	0x86, 0x6b, 0x02, 0xfd, 0x20, 0x07, 0x00,
+	0x86, 0x6b, 0x03, 0xfc, 0x21, 0x07, 0x00,
+	0x86, 0x6b, 0x04, 0xfb, 0x22, 0x07, 0x00,
+	0x86, 0x6b, 0x05, 0xfa, 0x23, 0x07, 0x00,
+	0x86, 0x6b, 0x06, 0xf9, 0x24, 0x07, 0x00,
+	0x86, 0x6b, 0x07, 0xf8, 0x25, 0x07, 0x00,
+	0x86, 0x6b, 0x08, 0xf7, 0x26, 0x07, 0x00,
+	0x86, 0x6b, 0x09, 0xf6, 0x4d, 0x07, 0x00,
+	0x86, 0x6b, 0x0a, 0xf5, 0x4e, 0x07, 0x00,
+	0x86, 0x6b, 0x14, 0xeb, 0x4f, 0x07, 0x00,
+	0x86, 0x6b, 0x1e, 0xe1, 0x50, 0x07, 0x00,
+	0x86, 0x6b, 0x17, 0xe8, 0x52, 0x07, 0x00,
+	0x86, 0x6b, 0x1f, 0xe0, 0x51, 0x07, 0x00,
+	0x86, 0x6b, 0x0e, 0xf1, 0x0b, 0x07, 0x00,
+	0x86, 0x6b, 0x20, 0xdf, 0x0c, 0x07, 0x00,
+	0x86, 0x6b, 0x42, 0xbd, 0x0d, 0x07, 0x00,
+	0x86, 0x6b, 0x0b, 0xf4, 0x0e, 0x07, 0x00,
+	0x86, 0x6b, 0x43, 0xbc, 0x0f, 0x07, 0x00,
+	0x86, 0x6b, 0x10, 0xef, 0x10, 0x07, 0x00,
+	0x86, 0x6b, 0x21, 0xde, 0x11, 0x07, 0x00,
+	0x86, 0x6b, 0x13, 0xec, 0x12, 0x07, 0x00,
+	0x86, 0x6b, 0x11, 0xee, 0x13, 0x07, 0x00,
+	0x86, 0x6b, 0x12, 0xed, 0x14, 0x07, 0x00,
+	0x86, 0x6b, 0x19, 0xe6, 0x15, 0x07, 0x00,
+	0x86, 0x6b, 0x1a, 0xe5, 0x16, 0x07, 0x00,
+	0x86, 0x6b, 0x1b, 0xe4, 0x17, 0x07, 0x00,
+	0x86, 0x6b, 0x4b, 0xb4, 0x18, 0x07, 0x00,
+	0x86, 0x6b, 0x40, 0xbf, 0x19, 0x07, 0x00,
+	0x86, 0x6b, 0x44, 0xbb, 0x1a, 0x07, 0x00,
+	0x86, 0x6b, 0x41, 0xbe, 0x1b, 0x07, 0x00,
+	0x86, 0x6b, 0x22, 0xdd, 0x1c, 0x07, 0x00,
+	0x86, 0x6b, 0x15, 0xea, 0x1d, 0x07, 0x00,
+	0x86, 0x6b, 0x0f, 0xf0, 0x3f, 0x07, 0x00,
+	0x86, 0x6b, 0x1c, 0xe3, 0x40, 0x07, 0x00,
+	0x86, 0x6b, 0x4a, 0xb5, 0x41, 0x07, 0x00,
+	0x86, 0x6b, 0x48, 0xb7, 0x42, 0x07, 0x00,
+	0x86, 0x6b, 0x49, 0xb6, 0x43, 0x07, 0x00,
+	0x86, 0x6b, 0x18, 0xe7, 0x44, 0x07, 0x00,
+	0x86, 0x6b, 0x23, 0xdc, 0x45, 0x07, 0x00,
+};
+
+#endif
diff --git a/drivers/media/dvb/dvb-usb/anysee.c b/drivers/media/dvb/dvb-usb/anysee.c
index 2f408d2..c786359 100644
--- a/drivers/media/dvb/dvb-usb/anysee.c
+++ b/drivers/media/dvb/dvb-usb/anysee.c
@@ -41,6 +41,9 @@
 static int dvb_usb_anysee_debug;
 module_param_named(debug, dvb_usb_anysee_debug, int, 0644);
 MODULE_PARM_DESC(debug, "set debugging level" DVB_USB_DEBUG_STATUS);
+int dvb_usb_anysee_delsys;
+module_param_named(delsys, dvb_usb_anysee_delsys, int, 0644);
+MODULE_PARM_DESC(delsys, "select delivery mode (0=DVB-C, 1=DVB-T)");
 DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
 
 static struct mutex anysee_usb_mutex;
@@ -178,14 +181,14 @@
 			inc = 1;
 		}
 		if (ret)
-			return ret;
+			break;
 
 		i += inc;
 	}
 
 	mutex_unlock(&d->i2c_mutex);
 
-	return i;
+	return ret ? ret : i;
 }
 
 static u32 anysee_i2c_func(struct i2c_adapter *adapter)
@@ -272,9 +275,11 @@
 	      model      demod     hw  firmware
 	   1. E30        MT352     02  0.2.1
 	   2. E30        ZL10353   02  0.2.1
-	   3. E30 Plus   ZL10353   06  0.1.0
-	   4. E30C Plus  TDA10023  0a  0.1.0    rev 0.2
-	   4. E30C Plus  TDA10023  0f  0.1.2    rev 0.4
+	   3. E30 Combo  ZL10353   0f  0.1.2    DVB-T/C combo
+	   4. E30 Plus   ZL10353   06  0.1.0
+	   5. E30C Plus  TDA10023  0a  0.1.0    rev 0.2
+	      E30C Plus  TDA10023  0f  0.1.2    rev 0.4
+	      E30 Combo  TDA10023  0f  0.1.2    DVB-T/C combo
 	*/
 
 	/* Zarlink MT352 DVB-T demod inside of Samsung DNOS404ZH102A NIM */
@@ -293,6 +298,21 @@
 		return 0;
 	}
 
+	/* for E30 Combo Plus DVB-T demodulator */
+	if (dvb_usb_anysee_delsys) {
+		ret = anysee_write_reg(adap->dev, 0xb0, 0x01);
+		if (ret)
+			return ret;
+
+		/* Zarlink ZL10353 DVB-T demod */
+		adap->fe = dvb_attach(zl10353_attach, &anysee_zl10353_config,
+				      &adap->dev->i2c_adap);
+		if (adap->fe != NULL) {
+			state->tuner = DVB_PLL_SAMSUNG_DTOS403IH102A;
+			return 0;
+		}
+	}
+
 	/* connect demod on IO port D for TDA10023 & ZL10353 */
 	ret = anysee_write_reg(adap->dev, 0xb0, 0x25);
 	if (ret)
diff --git a/drivers/media/dvb/dvb-usb/cinergyT2-core.c b/drivers/media/dvb/dvb-usb/cinergyT2-core.c
new file mode 100644
index 0000000..3ac9f74
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/cinergyT2-core.c
@@ -0,0 +1,268 @@
+/*
+ * TerraTec Cinergy T2/qanu USB2 DVB-T adapter.
+ *
+ * Copyright (C) 2007 Tomi Orava (tomimo@ncircle.nullnet.fi)
+ *
+ * Based on the dvb-usb-framework code and the
+ * original Terratec Cinergy T2 driver by:
+ *
+ * Copyright (C) 2004 Daniel Mack <daniel@qanu.de> and
+ *		    Holger Waechtler <holger@qanu.de>
+ *
+ *  Protocol Spec published on http://qanu.de/specs/terratec_cinergyT2.pdf
+ *
+ * This program is free software; you can redistribute it and/or 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 "cinergyT2.h"
+
+
+/* debug */
+int dvb_usb_cinergyt2_debug;
+int disable_remote;
+
+module_param_named(debug, dvb_usb_cinergyt2_debug, int, 0644);
+MODULE_PARM_DESC(debug, "set debugging level (1=info, xfer=2, rc=4 "
+		"(or-able)).");
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+struct cinergyt2_state {
+	u8 rc_counter;
+};
+
+/* We are missing a release hook with usb_device data */
+struct dvb_usb_device *cinergyt2_usb_device;
+
+static struct dvb_usb_device_properties cinergyt2_properties;
+
+static int cinergyt2_streaming_ctrl(struct dvb_usb_adapter *adap, int enable)
+{
+	char buf[] = { CINERGYT2_EP1_CONTROL_STREAM_TRANSFER, enable ? 1 : 0 };
+	char result[64];
+	return dvb_usb_generic_rw(adap->dev, buf, sizeof(buf), result,
+				sizeof(result), 0);
+}
+
+static int cinergyt2_power_ctrl(struct dvb_usb_device *d, int enable)
+{
+	char buf[] = { CINERGYT2_EP1_SLEEP_MODE, enable ? 0 : 1 };
+	char state[3];
+	return dvb_usb_generic_rw(d, buf, sizeof(buf), state, sizeof(state), 0);
+}
+
+static int cinergyt2_frontend_attach(struct dvb_usb_adapter *adap)
+{
+	char query[] = { CINERGYT2_EP1_GET_FIRMWARE_VERSION };
+	char state[3];
+	int ret;
+
+	adap->fe = cinergyt2_fe_attach(adap->dev);
+
+	ret = dvb_usb_generic_rw(adap->dev, query, sizeof(query), state,
+				sizeof(state), 0);
+	if (ret < 0) {
+		deb_rc("cinergyt2_power_ctrl() Failed to retrieve sleep "
+			"state info\n");
+	}
+
+	/* Copy this pointer as we are gonna need it in the release phase */
+	cinergyt2_usb_device = adap->dev;
+
+	return 0;
+}
+
+static struct dvb_usb_rc_key cinergyt2_rc_keys[] = {
+	{ 0x04,	0x01,	KEY_POWER },
+	{ 0x04,	0x02,	KEY_1 },
+	{ 0x04,	0x03,	KEY_2 },
+	{ 0x04,	0x04,	KEY_3 },
+	{ 0x04,	0x05,	KEY_4 },
+	{ 0x04,	0x06,	KEY_5 },
+	{ 0x04,	0x07,	KEY_6 },
+	{ 0x04,	0x08,	KEY_7 },
+	{ 0x04,	0x09,	KEY_8 },
+	{ 0x04,	0x0a,	KEY_9 },
+	{ 0x04,	0x0c,	KEY_0 },
+	{ 0x04,	0x0b,	KEY_VIDEO },
+	{ 0x04,	0x0d,	KEY_REFRESH },
+	{ 0x04,	0x0e,	KEY_SELECT },
+	{ 0x04,	0x0f,	KEY_EPG },
+	{ 0x04,	0x10,	KEY_UP },
+	{ 0x04,	0x14,	KEY_DOWN },
+	{ 0x04,	0x11,	KEY_LEFT },
+	{ 0x04,	0x13,	KEY_RIGHT },
+	{ 0x04,	0x12,	KEY_OK },
+	{ 0x04,	0x15,	KEY_TEXT },
+	{ 0x04,	0x16,	KEY_INFO },
+	{ 0x04,	0x17,	KEY_RED },
+	{ 0x04,	0x18,	KEY_GREEN },
+	{ 0x04,	0x19,	KEY_YELLOW },
+	{ 0x04,	0x1a,	KEY_BLUE },
+	{ 0x04,	0x1c,	KEY_VOLUMEUP },
+	{ 0x04,	0x1e,	KEY_VOLUMEDOWN },
+	{ 0x04,	0x1d,	KEY_MUTE },
+	{ 0x04,	0x1b,	KEY_CHANNELUP },
+	{ 0x04,	0x1f,	KEY_CHANNELDOWN },
+	{ 0x04,	0x40,	KEY_PAUSE },
+	{ 0x04,	0x4c,	KEY_PLAY },
+	{ 0x04,	0x58,	KEY_RECORD },
+	{ 0x04,	0x54,	KEY_PREVIOUS },
+	{ 0x04,	0x48,	KEY_STOP },
+	{ 0x04,	0x5c,	KEY_NEXT }
+};
+
+/* Number of keypresses to ignore before detect repeating */
+#define RC_REPEAT_DELAY 3
+
+static int repeatable_keys[] = {
+	KEY_UP,
+	KEY_DOWN,
+	KEY_LEFT,
+	KEY_RIGHT,
+	KEY_VOLUMEUP,
+	KEY_VOLUMEDOWN,
+	KEY_CHANNELUP,
+	KEY_CHANNELDOWN
+};
+
+static int cinergyt2_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
+{
+	struct cinergyt2_state *st = d->priv;
+	u8 key[5] = {0, 0, 0, 0, 0}, cmd = CINERGYT2_EP1_GET_RC_EVENTS;
+	int i;
+
+	*state = REMOTE_NO_KEY_PRESSED;
+
+	dvb_usb_generic_rw(d, &cmd, 1, key, sizeof(key), 0);
+	if (key[4] == 0xff) {
+		/* key repeat */
+		st->rc_counter++;
+		if (st->rc_counter > RC_REPEAT_DELAY) {
+			for (i = 0; i < ARRAY_SIZE(repeatable_keys); i++) {
+				if (d->last_event == repeatable_keys[i]) {
+					*state = REMOTE_KEY_REPEAT;
+					*event = d->last_event;
+					deb_rc("repeat key, event %x\n",
+						   *event);
+					return 0;
+				}
+			}
+			deb_rc("repeated key (non repeatable)\n");
+		}
+		return 0;
+	}
+
+	/* hack to pass checksum on the custom field */
+	key[2] = ~key[1];
+	dvb_usb_nec_rc_key_to_event(d, key, event, state);
+	if (key[0] != 0) {
+		if (*event != d->last_event)
+			st->rc_counter = 0;
+
+		deb_rc("key: %x %x %x %x %x\n",
+		       key[0], key[1], key[2], key[3], key[4]);
+	}
+	return 0;
+}
+
+static int cinergyt2_usb_probe(struct usb_interface *intf,
+				const struct usb_device_id *id)
+{
+	return dvb_usb_device_init(intf, &cinergyt2_properties,
+					THIS_MODULE, NULL, adapter_nr);
+}
+
+
+static struct usb_device_id cinergyt2_usb_table[] = {
+	{ USB_DEVICE(USB_VID_TERRATEC, 0x0038) },
+	{ 0 }
+};
+
+MODULE_DEVICE_TABLE(usb, cinergyt2_usb_table);
+
+static struct dvb_usb_device_properties cinergyt2_properties = {
+	.size_of_priv = sizeof(struct cinergyt2_state),
+	.num_adapters = 1,
+	.adapter = {
+		{
+			.streaming_ctrl   = cinergyt2_streaming_ctrl,
+			.frontend_attach  = cinergyt2_frontend_attach,
+
+			/* parameter for the MPEG2-data transfer */
+			.stream = {
+				.type = USB_BULK,
+				.count = 5,
+				.endpoint = 0x02,
+				.u = {
+					.bulk = {
+						.buffersize = 512,
+					}
+				}
+			},
+		}
+	},
+
+	.power_ctrl       = cinergyt2_power_ctrl,
+
+	.rc_interval      = 50,
+	.rc_key_map       = cinergyt2_rc_keys,
+	.rc_key_map_size  = ARRAY_SIZE(cinergyt2_rc_keys),
+	.rc_query         = cinergyt2_rc_query,
+
+	.generic_bulk_ctrl_endpoint = 1,
+
+	.num_device_descs = 1,
+	.devices = {
+		{ .name = "TerraTec/qanu USB2.0 Highspeed DVB-T Receiver",
+		  .cold_ids = {NULL},
+		  .warm_ids = { &cinergyt2_usb_table[0], NULL },
+		},
+		{ NULL },
+	}
+};
+
+
+static struct usb_driver cinergyt2_driver = {
+	.name		= "cinergyT2",
+	.probe		= cinergyt2_usb_probe,
+	.disconnect	= dvb_usb_device_exit,
+	.id_table	= cinergyt2_usb_table
+};
+
+static int __init cinergyt2_usb_init(void)
+{
+	int err;
+
+	err = usb_register(&cinergyt2_driver);
+	if (err) {
+		err("usb_register() failed! (err %i)\n", err);
+		return err;
+	}
+	return 0;
+}
+
+static void __exit cinergyt2_usb_exit(void)
+{
+	usb_deregister(&cinergyt2_driver);
+}
+
+module_init(cinergyt2_usb_init);
+module_exit(cinergyt2_usb_exit);
+
+MODULE_DESCRIPTION("Terratec Cinergy T2 DVB-T driver");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Tomi Orava");
diff --git a/drivers/media/dvb/dvb-usb/cinergyT2-fe.c b/drivers/media/dvb/dvb-usb/cinergyT2-fe.c
new file mode 100644
index 0000000..649f25c
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/cinergyT2-fe.c
@@ -0,0 +1,351 @@
+/*
+ * TerraTec Cinergy T2/qanu USB2 DVB-T adapter.
+ *
+ * Copyright (C) 2007 Tomi Orava (tomimo@ncircle.nullnet.fi)
+ *
+ * Based on the dvb-usb-framework code and the
+ * original Terratec Cinergy T2 driver by:
+ *
+ * Copyright (C) 2004 Daniel Mack <daniel@qanu.de> and
+ *                  Holger Waechtler <holger@qanu.de>
+ *
+ *  Protocol Spec published on http://qanu.de/specs/terratec_cinergyT2.pdf
+ *
+ * This program is free software; you can redistribute it and/or 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 "cinergyT2.h"
+
+
+/**
+ *  convert linux-dvb frontend parameter set into TPS.
+ *  See ETSI ETS-300744, section 4.6.2, table 9 for details.
+ *
+ *  This function is probably reusable and may better get placed in a support
+ *  library.
+ *
+ *  We replace errornous fields by default TPS fields (the ones with value 0).
+ */
+
+static uint16_t compute_tps(struct dvb_frontend_parameters *p)
+{
+	struct dvb_ofdm_parameters *op = &p->u.ofdm;
+	uint16_t tps = 0;
+
+	switch (op->code_rate_HP) {
+	case FEC_2_3:
+		tps |= (1 << 7);
+		break;
+	case FEC_3_4:
+		tps |= (2 << 7);
+		break;
+	case FEC_5_6:
+		tps |= (3 << 7);
+		break;
+	case FEC_7_8:
+		tps |= (4 << 7);
+		break;
+	case FEC_1_2:
+	case FEC_AUTO:
+	default:
+		/* tps |= (0 << 7) */;
+	}
+
+	switch (op->code_rate_LP) {
+	case FEC_2_3:
+		tps |= (1 << 4);
+		break;
+	case FEC_3_4:
+		tps |= (2 << 4);
+		break;
+	case FEC_5_6:
+		tps |= (3 << 4);
+		break;
+	case FEC_7_8:
+		tps |= (4 << 4);
+		break;
+	case FEC_1_2:
+	case FEC_AUTO:
+	default:
+		/* tps |= (0 << 4) */;
+	}
+
+	switch (op->constellation) {
+	case QAM_16:
+		tps |= (1 << 13);
+		break;
+	case QAM_64:
+		tps |= (2 << 13);
+		break;
+	case QPSK:
+	default:
+		/* tps |= (0 << 13) */;
+	}
+
+	switch (op->transmission_mode) {
+	case TRANSMISSION_MODE_8K:
+		tps |= (1 << 0);
+		break;
+	case TRANSMISSION_MODE_2K:
+	default:
+		/* tps |= (0 << 0) */;
+	}
+
+	switch (op->guard_interval) {
+	case GUARD_INTERVAL_1_16:
+		tps |= (1 << 2);
+		break;
+	case GUARD_INTERVAL_1_8:
+		tps |= (2 << 2);
+		break;
+	case GUARD_INTERVAL_1_4:
+		tps |= (3 << 2);
+		break;
+	case GUARD_INTERVAL_1_32:
+	default:
+		/* tps |= (0 << 2) */;
+	}
+
+	switch (op->hierarchy_information) {
+	case HIERARCHY_1:
+		tps |= (1 << 10);
+		break;
+	case HIERARCHY_2:
+		tps |= (2 << 10);
+		break;
+	case HIERARCHY_4:
+		tps |= (3 << 10);
+		break;
+	case HIERARCHY_NONE:
+	default:
+		/* tps |= (0 << 10) */;
+	}
+
+	return tps;
+}
+
+struct cinergyt2_fe_state {
+	struct dvb_frontend fe;
+	struct dvb_usb_device *d;
+};
+
+static int cinergyt2_fe_read_status(struct dvb_frontend *fe,
+					fe_status_t *status)
+{
+	struct cinergyt2_fe_state *state = fe->demodulator_priv;
+	struct dvbt_get_status_msg result;
+	u8 cmd[] = { CINERGYT2_EP1_GET_TUNER_STATUS };
+	int ret;
+
+	ret = dvb_usb_generic_rw(state->d, cmd, sizeof(cmd), (u8 *)&result,
+			sizeof(result), 0);
+	if (ret < 0)
+		return ret;
+
+	*status = 0;
+
+	if (0xffff - le16_to_cpu(result.gain) > 30)
+		*status |= FE_HAS_SIGNAL;
+	if (result.lock_bits & (1 << 6))
+		*status |= FE_HAS_LOCK;
+	if (result.lock_bits & (1 << 5))
+		*status |= FE_HAS_SYNC;
+	if (result.lock_bits & (1 << 4))
+		*status |= FE_HAS_CARRIER;
+	if (result.lock_bits & (1 << 1))
+		*status |= FE_HAS_VITERBI;
+
+	if ((*status & (FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC)) !=
+			(FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC))
+		*status &= ~FE_HAS_LOCK;
+
+	return 0;
+}
+
+static int cinergyt2_fe_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+	struct cinergyt2_fe_state *state = fe->demodulator_priv;
+	struct dvbt_get_status_msg status;
+	char cmd[] = { CINERGYT2_EP1_GET_TUNER_STATUS };
+	int ret;
+
+	ret = dvb_usb_generic_rw(state->d, cmd, sizeof(cmd), (char *)&status,
+				sizeof(status), 0);
+	if (ret < 0)
+		return ret;
+
+	*ber = le32_to_cpu(status.viterbi_error_rate);
+	return 0;
+}
+
+static int cinergyt2_fe_read_unc_blocks(struct dvb_frontend *fe, u32 *unc)
+{
+	struct cinergyt2_fe_state *state = fe->demodulator_priv;
+	struct dvbt_get_status_msg status;
+	u8 cmd[] = { CINERGYT2_EP1_GET_TUNER_STATUS };
+	int ret;
+
+	ret = dvb_usb_generic_rw(state->d, cmd, sizeof(cmd), (u8 *)&status,
+				sizeof(status), 0);
+	if (ret < 0) {
+		err("cinergyt2_fe_read_unc_blocks() Failed! (Error=%d)\n",
+			ret);
+		return ret;
+	}
+	*unc = le32_to_cpu(status.uncorrected_block_count);
+	return 0;
+}
+
+static int cinergyt2_fe_read_signal_strength(struct dvb_frontend *fe,
+						u16 *strength)
+{
+	struct cinergyt2_fe_state *state = fe->demodulator_priv;
+	struct dvbt_get_status_msg status;
+	char cmd[] = { CINERGYT2_EP1_GET_TUNER_STATUS };
+	int ret;
+
+	ret = dvb_usb_generic_rw(state->d, cmd, sizeof(cmd), (char *)&status,
+				sizeof(status), 0);
+	if (ret < 0) {
+		err("cinergyt2_fe_read_signal_strength() Failed!"
+			" (Error=%d)\n", ret);
+		return ret;
+	}
+	*strength = (0xffff - le16_to_cpu(status.gain));
+	return 0;
+}
+
+static int cinergyt2_fe_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+	struct cinergyt2_fe_state *state = fe->demodulator_priv;
+	struct dvbt_get_status_msg status;
+	char cmd[] = { CINERGYT2_EP1_GET_TUNER_STATUS };
+	int ret;
+
+	ret = dvb_usb_generic_rw(state->d, cmd, sizeof(cmd), (char *)&status,
+				sizeof(status), 0);
+	if (ret < 0) {
+		err("cinergyt2_fe_read_snr() Failed! (Error=%d)\n", ret);
+		return ret;
+	}
+	*snr = (status.snr << 8) | status.snr;
+	return 0;
+}
+
+static int cinergyt2_fe_init(struct dvb_frontend *fe)
+{
+	return 0;
+}
+
+static int cinergyt2_fe_sleep(struct dvb_frontend *fe)
+{
+	deb_info("cinergyt2_fe_sleep() Called\n");
+	return 0;
+}
+
+static int cinergyt2_fe_get_tune_settings(struct dvb_frontend *fe,
+				struct dvb_frontend_tune_settings *tune)
+{
+	tune->min_delay_ms = 800;
+	return 0;
+}
+
+static int cinergyt2_fe_set_frontend(struct dvb_frontend *fe,
+				  struct dvb_frontend_parameters *fep)
+{
+	struct cinergyt2_fe_state *state = fe->demodulator_priv;
+	struct dvbt_set_parameters_msg param;
+	char result[2];
+	int err;
+
+	param.cmd = CINERGYT2_EP1_SET_TUNER_PARAMETERS;
+	param.tps = cpu_to_le16(compute_tps(fep));
+	param.freq = cpu_to_le32(fep->frequency / 1000);
+	param.bandwidth = 8 - fep->u.ofdm.bandwidth - BANDWIDTH_8_MHZ;
+
+	err = dvb_usb_generic_rw(state->d,
+			(char *)&param, sizeof(param),
+			result, sizeof(result), 0);
+	if (err < 0)
+		err("cinergyt2_fe_set_frontend() Failed! err=%d\n", err);
+
+	return (err < 0) ? err : 0;
+}
+
+static int cinergyt2_fe_get_frontend(struct dvb_frontend *fe,
+				  struct dvb_frontend_parameters *fep)
+{
+	return 0;
+}
+
+static void cinergyt2_fe_release(struct dvb_frontend *fe)
+{
+	struct cinergyt2_fe_state *state = fe->demodulator_priv;
+	if (state != NULL)
+		kfree(state);
+}
+
+static struct dvb_frontend_ops cinergyt2_fe_ops;
+
+struct dvb_frontend *cinergyt2_fe_attach(struct dvb_usb_device *d)
+{
+	struct cinergyt2_fe_state *s = kzalloc(sizeof(
+					struct cinergyt2_fe_state), GFP_KERNEL);
+	if (s == NULL)
+		return NULL;
+
+	s->d = d;
+	memcpy(&s->fe.ops, &cinergyt2_fe_ops, sizeof(struct dvb_frontend_ops));
+	s->fe.demodulator_priv = s;
+	return &s->fe;
+}
+
+
+static struct dvb_frontend_ops cinergyt2_fe_ops = {
+	.info = {
+		.name			= DRIVER_NAME,
+		.type			= FE_OFDM,
+		.frequency_min		= 174000000,
+		.frequency_max		= 862000000,
+		.frequency_stepsize	= 166667,
+		.caps = FE_CAN_INVERSION_AUTO | FE_CAN_FEC_1_2
+			| FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4
+			| FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8
+			| FE_CAN_FEC_AUTO | FE_CAN_QPSK
+			| FE_CAN_QAM_16 | FE_CAN_QAM_64
+			| FE_CAN_QAM_AUTO
+			| FE_CAN_TRANSMISSION_MODE_AUTO
+			| FE_CAN_GUARD_INTERVAL_AUTO
+			| FE_CAN_HIERARCHY_AUTO
+			| FE_CAN_RECOVER
+			| FE_CAN_MUTE_TS
+	},
+
+	.release		= cinergyt2_fe_release,
+
+	.init			= cinergyt2_fe_init,
+	.sleep			= cinergyt2_fe_sleep,
+
+	.set_frontend		= cinergyt2_fe_set_frontend,
+	.get_frontend		= cinergyt2_fe_get_frontend,
+	.get_tune_settings	= cinergyt2_fe_get_tune_settings,
+
+	.read_status		= cinergyt2_fe_read_status,
+	.read_ber		= cinergyt2_fe_read_ber,
+	.read_signal_strength	= cinergyt2_fe_read_signal_strength,
+	.read_snr		= cinergyt2_fe_read_snr,
+	.read_ucblocks		= cinergyt2_fe_read_unc_blocks,
+};
diff --git a/drivers/media/dvb/dvb-usb/cinergyT2.h b/drivers/media/dvb/dvb-usb/cinergyT2.h
new file mode 100644
index 0000000..11d79eb
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/cinergyT2.h
@@ -0,0 +1,95 @@
+/*
+ * TerraTec Cinergy T2/qanu USB2 DVB-T adapter.
+ *
+ * Copyright (C) 2007 Tomi Orava (tomimo@ncircle.nullnet.fi)
+ *
+ * Based on the dvb-usb-framework code and the
+ * original Terratec Cinergy T2 driver by:
+ *
+ * Copyright (C) 2004 Daniel Mack <daniel@qanu.de> and
+ *                  Holger Waechtler <holger@qanu.de>
+ *
+ *  Protocol Spec published on http://qanu.de/specs/terratec_cinergyT2.pdf
+ *
+ * This program is free software; you can redistribute it and/or 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 _DVB_USB_CINERGYT2_H_
+#define _DVB_USB_CINERGYT2_H_
+
+#include <linux/usb/input.h>
+
+#define DVB_USB_LOG_PREFIX "cinergyT2"
+#include "dvb-usb.h"
+
+#define DRIVER_NAME "TerraTec/qanu USB2.0 Highspeed DVB-T Receiver"
+
+extern int dvb_usb_cinergyt2_debug;
+
+#define deb_info(args...)  dprintk(dvb_usb_cinergyt2_debug,  0x001, args)
+#define deb_xfer(args...)  dprintk(dvb_usb_cinergyt2_debug,  0x002, args)
+#define deb_pll(args...)   dprintk(dvb_usb_cinergyt2_debug,  0x004, args)
+#define deb_ts(args...)    dprintk(dvb_usb_cinergyt2_debug,  0x008, args)
+#define deb_err(args...)   dprintk(dvb_usb_cinergyt2_debug,  0x010, args)
+#define deb_rc(args...)    dprintk(dvb_usb_cinergyt2_debug,  0x020, args)
+#define deb_fw(args...)    dprintk(dvb_usb_cinergyt2_debug,  0x040, args)
+#define deb_mem(args...)   dprintk(dvb_usb_cinergyt2_debug,  0x080, args)
+#define deb_uxfer(args...) dprintk(dvb_usb_cinergyt2_debug,  0x100, args)
+
+
+
+enum cinergyt2_ep1_cmd {
+	CINERGYT2_EP1_PID_TABLE_RESET		= 0x01,
+	CINERGYT2_EP1_PID_SETUP			= 0x02,
+	CINERGYT2_EP1_CONTROL_STREAM_TRANSFER	= 0x03,
+	CINERGYT2_EP1_SET_TUNER_PARAMETERS	= 0x04,
+	CINERGYT2_EP1_GET_TUNER_STATUS		= 0x05,
+	CINERGYT2_EP1_START_SCAN		= 0x06,
+	CINERGYT2_EP1_CONTINUE_SCAN		= 0x07,
+	CINERGYT2_EP1_GET_RC_EVENTS		= 0x08,
+	CINERGYT2_EP1_SLEEP_MODE		= 0x09,
+	CINERGYT2_EP1_GET_FIRMWARE_VERSION	= 0x0A
+};
+
+
+struct dvbt_get_status_msg {
+	uint32_t freq;
+	uint8_t bandwidth;
+	uint16_t tps;
+	uint8_t flags;
+	uint16_t gain;
+	uint8_t snr;
+	uint32_t viterbi_error_rate;
+	uint32_t rs_error_rate;
+	uint32_t uncorrected_block_count;
+	uint8_t lock_bits;
+	uint8_t prev_lock_bits;
+} __attribute__((packed));
+
+
+struct dvbt_set_parameters_msg {
+	uint8_t cmd;
+	uint32_t freq;
+	uint8_t bandwidth;
+	uint16_t tps;
+	uint8_t flags;
+} __attribute__((packed));
+
+
+extern struct dvb_frontend *cinergyt2_fe_attach(struct dvb_usb_device *d);
+
+#endif /* _DVB_USB_CINERGYT2_H_ */
+
diff --git a/drivers/media/dvb/dvb-usb/cxusb.c b/drivers/media/dvb/dvb-usb/cxusb.c
index 5634002..406d7fb 100644
--- a/drivers/media/dvb/dvb-usb/cxusb.c
+++ b/drivers/media/dvb/dvb-usb/cxusb.c
@@ -36,6 +36,9 @@
 #include "tuner-xc2028.h"
 #include "tuner-simple.h"
 #include "mxl5005s.h"
+#include "dib7000p.h"
+#include "dib0070.h"
+#include "lgs8gl5.h"
 
 /* debug */
 static int dvb_usb_cxusb_debug;
@@ -109,6 +112,25 @@
 	cxusb_bluebird_gpio_rw(d, 0x40, onoff ? 0 : 0x40);
 }
 
+static int cxusb_d680_dmb_gpio_tuner(struct dvb_usb_device *d,
+		u8 addr, int onoff)
+{
+	u8  o[2] = {addr, onoff};
+	u8  i;
+	int rc;
+
+	rc = cxusb_ctrl_msg(d, CMD_GPIO_WRITE, o, 2, &i, 1);
+
+	if (rc < 0)
+		return rc;
+	if (i == 0x01)
+		return 0;
+	else {
+		deb_info("gpio_write failed.\n");
+		return -EIO;
+	}
+}
+
 /* I2C */
 static int cxusb_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
 			  int num)
@@ -262,6 +284,20 @@
 	return rc;
 }
 
+static int cxusb_d680_dmb_power_ctrl(struct dvb_usb_device *d, int onoff)
+{
+	int ret;
+	u8  b;
+	ret = cxusb_power_ctrl(d, onoff);
+	if (!onoff)
+		return ret;
+
+	msleep(128);
+	cxusb_ctrl_msg(d, CMD_DIGITAL, NULL, 0, &b, 1);
+	msleep(100);
+	return ret;
+}
+
 static int cxusb_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
 {
 	u8 buf[2] = { 0x03, 0x00 };
@@ -283,6 +319,67 @@
 	return 0;
 }
 
+static void cxusb_d680_dmb_drain_message(struct dvb_usb_device *d)
+{
+	int       ep = d->props.generic_bulk_ctrl_endpoint;
+	const int timeout = 100;
+	const int junk_len = 32;
+	u8        *junk;
+	int       rd_count;
+
+	/* Discard remaining data in video pipe */
+	junk = kmalloc(junk_len, GFP_KERNEL);
+	if (!junk)
+		return;
+	while (1) {
+		if (usb_bulk_msg(d->udev,
+			usb_rcvbulkpipe(d->udev, ep),
+			junk, junk_len, &rd_count, timeout) < 0)
+			break;
+		if (!rd_count)
+			break;
+	}
+	kfree(junk);
+}
+
+static void cxusb_d680_dmb_drain_video(struct dvb_usb_device *d)
+{
+	struct usb_data_stream_properties *p = &d->props.adapter[0].stream;
+	const int timeout = 100;
+	const int junk_len = p->u.bulk.buffersize;
+	u8        *junk;
+	int       rd_count;
+
+	/* Discard remaining data in video pipe */
+	junk = kmalloc(junk_len, GFP_KERNEL);
+	if (!junk)
+		return;
+	while (1) {
+		if (usb_bulk_msg(d->udev,
+			usb_rcvbulkpipe(d->udev, p->endpoint),
+			junk, junk_len, &rd_count, timeout) < 0)
+			break;
+		if (!rd_count)
+			break;
+	}
+	kfree(junk);
+}
+
+static int cxusb_d680_dmb_streaming_ctrl(
+		struct dvb_usb_adapter *adap, int onoff)
+{
+	if (onoff) {
+		u8 buf[2] = { 0x03, 0x00 };
+		cxusb_d680_dmb_drain_video(adap->dev);
+		return cxusb_ctrl_msg(adap->dev, CMD_STREAMING_ON,
+			buf, sizeof(buf), NULL, 0);
+	} else {
+		int ret = cxusb_ctrl_msg(adap->dev,
+			CMD_STREAMING_OFF, NULL, 0, NULL, 0);
+		return ret;
+	}
+}
+
 static int cxusb_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
 {
 	struct dvb_usb_rc_key *keymap = d->props.rc_key_map;
@@ -335,6 +432,32 @@
 	return 0;
 }
 
+static int cxusb_d680_dmb_rc_query(struct dvb_usb_device *d, u32 *event,
+		int *state)
+{
+	struct dvb_usb_rc_key *keymap = d->props.rc_key_map;
+	u8 ircode[2];
+	int i;
+
+	*event = 0;
+	*state = REMOTE_NO_KEY_PRESSED;
+
+	if (cxusb_ctrl_msg(d, 0x10, NULL, 0, ircode, 2) < 0)
+		return 0;
+
+	for (i = 0; i < d->props.rc_key_map_size; i++) {
+		if (keymap[i].custom == ircode[0] &&
+		    keymap[i].data == ircode[1]) {
+			*event = keymap[i].event;
+			*state = REMOTE_KEY_PRESSED;
+
+			return 0;
+		}
+	}
+
+	return 0;
+}
+
 static struct dvb_usb_rc_key dvico_mce_rc_keys[] = {
 	{ 0xfe, 0x02, KEY_TV },
 	{ 0xfe, 0x0e, KEY_MP3 },
@@ -422,6 +545,44 @@
 	{ 0xfc, 0x00, KEY_UNKNOWN },    /* HD */
 };
 
+static struct dvb_usb_rc_key d680_dmb_rc_keys[] = {
+	{ 0x00, 0x38, KEY_UNKNOWN },	/* TV/AV */
+	{ 0x08, 0x0c, KEY_ZOOM },
+	{ 0x08, 0x00, KEY_0 },
+	{ 0x00, 0x01, KEY_1 },
+	{ 0x08, 0x02, KEY_2 },
+	{ 0x00, 0x03, KEY_3 },
+	{ 0x08, 0x04, KEY_4 },
+	{ 0x00, 0x05, KEY_5 },
+	{ 0x08, 0x06, KEY_6 },
+	{ 0x00, 0x07, KEY_7 },
+	{ 0x08, 0x08, KEY_8 },
+	{ 0x00, 0x09, KEY_9 },
+	{ 0x00, 0x0a, KEY_MUTE },
+	{ 0x08, 0x29, KEY_BACK },
+	{ 0x00, 0x12, KEY_CHANNELUP },
+	{ 0x08, 0x13, KEY_CHANNELDOWN },
+	{ 0x00, 0x2b, KEY_VOLUMEUP },
+	{ 0x08, 0x2c, KEY_VOLUMEDOWN },
+	{ 0x00, 0x20, KEY_UP },
+	{ 0x08, 0x21, KEY_DOWN },
+	{ 0x00, 0x11, KEY_LEFT },
+	{ 0x08, 0x10, KEY_RIGHT },
+	{ 0x00, 0x0d, KEY_OK },
+	{ 0x08, 0x1f, KEY_RECORD },
+	{ 0x00, 0x17, KEY_PLAYPAUSE },
+	{ 0x08, 0x16, KEY_PLAYPAUSE },
+	{ 0x00, 0x0b, KEY_STOP },
+	{ 0x08, 0x27, KEY_FASTFORWARD },
+	{ 0x00, 0x26, KEY_REWIND },
+	{ 0x08, 0x1e, KEY_UNKNOWN },    /* Time Shift */
+	{ 0x00, 0x0e, KEY_UNKNOWN },    /* Snapshot */
+	{ 0x08, 0x2d, KEY_UNKNOWN },    /* Mouse Cursor */
+	{ 0x00, 0x0f, KEY_UNKNOWN },    /* Minimize/Maximize */
+	{ 0x08, 0x14, KEY_UNKNOWN },    /* Shuffle */
+	{ 0x00, 0x25, KEY_POWER },
+};
+
 static int cxusb_dee1601_demod_init(struct dvb_frontend* fe)
 {
 	static u8 clock_config []  = { CLOCK_CTL,  0x38, 0x28 };
@@ -527,6 +688,24 @@
 	.AgcMasterByte   = 0x00,
 };
 
+/* FIXME: needs tweaking */
+static struct mxl5005s_config d680_dmb_tuner = {
+	.i2c_address     = 0x63,
+	.if_freq         = 36125000UL,
+	.xtal_freq       = CRYSTAL_FREQ_16000000HZ,
+	.agc_mode        = MXL_SINGLE_AGC,
+	.tracking_filter = MXL_TF_C,
+	.rssi_enable     = MXL_RSSI_ENABLE,
+	.cap_select      = MXL_CAP_SEL_ENABLE,
+	.div_out         = MXL_DIV_OUT_4,
+	.clock_out       = MXL_CLOCK_OUT_DISABLE,
+	.output_load     = MXL5005S_IF_OUTPUT_LOAD_200_OHM,
+	.top		 = MXL5005S_TOP_25P2,
+	.mod_mode        = MXL_DIGITAL_MODE,
+	.if_mode         = MXL_ZERO_IF,
+	.AgcMasterByte   = 0x00,
+};
+
 /* Callbacks for DVB USB */
 static int cxusb_fmd1216me_tuner_attach(struct dvb_usb_adapter *adap)
 {
@@ -563,7 +742,8 @@
 	return 0;
 }
 
-static int dvico_bluebird_xc2028_callback(void *ptr, int command, int arg)
+static int dvico_bluebird_xc2028_callback(void *ptr, int component,
+					  int command, int arg)
 {
 	struct dvb_usb_adapter *adap = ptr;
 	struct dvb_usb_device *d = adap->dev;
@@ -591,14 +771,16 @@
 	struct xc2028_config	  cfg = {
 		.i2c_adap  = &adap->dev->i2c_adap,
 		.i2c_addr  = 0x61,
-		.callback  = dvico_bluebird_xc2028_callback,
 	};
 	static struct xc2028_ctrl ctl = {
-		.fname       = "xc3028-v27.fw",
+		.fname       = XC2028_DEFAULT_FIRMWARE,
 		.max_len     = 64,
 		.demod       = XC3028_FE_ZARLINK456,
 	};
 
+	/* FIXME: generalize & move to common area */
+	adap->fe->callback = dvico_bluebird_xc2028_callback;
+
 	fe = dvb_attach(xc2028_attach, adap->fe, &cfg);
 	if (fe == NULL || fe->ops.tuner_ops.set_config == NULL)
 		return -EIO;
@@ -615,6 +797,14 @@
 	return 0;
 }
 
+static int cxusb_d680_dmb_tuner_attach(struct dvb_usb_adapter *adap)
+{
+	struct dvb_frontend *fe;
+	fe = dvb_attach(mxl5005s_attach, adap->fe,
+			&adap->dev->i2c_adap, &d680_dmb_tuner);
+	return (fe == NULL) ? -EIO : 0;
+}
+
 static int cxusb_cx22702_frontend_attach(struct dvb_usb_adapter *adap)
 {
 	u8 b;
@@ -726,6 +916,159 @@
 	return 0;
 }
 
+static struct dibx000_agc_config dib7070_agc_config = {
+	.band_caps = BAND_UHF | BAND_VHF | BAND_LBAND | BAND_SBAND,
+
+	/*
+	 * P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=5,
+	 * P_agc_inv_pwm1=0, P_agc_inv_pwm2=0, P_agc_inh_dc_rv_est=0,
+	 * P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=5, P_agc_write=0
+	 */
+	.setup = (0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) |
+		 (0 << 8) | (3 << 5) | (0 << 4) | (5 << 1) | (0 << 0),
+	.inv_gain = 600,
+	.time_stabiliz = 10,
+	.alpha_level = 0,
+	.thlock = 118,
+	.wbd_inv = 0,
+	.wbd_ref = 3530,
+	.wbd_sel = 1,
+	.wbd_alpha = 5,
+	.agc1_max = 65535,
+	.agc1_min = 0,
+	.agc2_max = 65535,
+	.agc2_min = 0,
+	.agc1_pt1 = 0,
+	.agc1_pt2 = 40,
+	.agc1_pt3 = 183,
+	.agc1_slope1 = 206,
+	.agc1_slope2 = 255,
+	.agc2_pt1 = 72,
+	.agc2_pt2 = 152,
+	.agc2_slope1 = 88,
+	.agc2_slope2 = 90,
+	.alpha_mant = 17,
+	.alpha_exp = 27,
+	.beta_mant = 23,
+	.beta_exp = 51,
+	.perform_agc_softsplit = 0,
+};
+
+static struct dibx000_bandwidth_config dib7070_bw_config_12_mhz = {
+	.internal = 60000,
+	.sampling = 15000,
+	.pll_prediv = 1,
+	.pll_ratio = 20,
+	.pll_range = 3,
+	.pll_reset = 1,
+	.pll_bypass = 0,
+	.enable_refdiv = 0,
+	.bypclk_div = 0,
+	.IO_CLK_en_core = 1,
+	.ADClkSrc = 1,
+	.modulo = 2,
+	/* refsel, sel, freq_15k */
+	.sad_cfg = (3 << 14) | (1 << 12) | (524 << 0),
+	.ifreq = (0 << 25) | 0,
+	.timf = 20452225,
+	.xtal_hz = 12000000,
+};
+
+static struct dib7000p_config cxusb_dualdig4_rev2_config = {
+	.output_mode = OUTMODE_MPEG2_PAR_GATED_CLK,
+	.output_mpeg2_in_188_bytes = 1,
+
+	.agc_config_count = 1,
+	.agc = &dib7070_agc_config,
+	.bw  = &dib7070_bw_config_12_mhz,
+	.tuner_is_baseband = 1,
+	.spur_protect = 1,
+
+	.gpio_dir = 0xfcef,
+	.gpio_val = 0x0110,
+
+	.gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS,
+
+	.hostbus_diversity = 1,
+};
+
+static int cxusb_dualdig4_rev2_frontend_attach(struct dvb_usb_adapter *adap)
+{
+	if (usb_set_interface(adap->dev->udev, 0, 1) < 0)
+		err("set interface failed");
+
+	cxusb_ctrl_msg(adap->dev, CMD_DIGITAL, NULL, 0, NULL, 0);
+
+	cxusb_bluebird_gpio_pulse(adap->dev, 0x02, 1);
+
+	dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 1, 18,
+				 &cxusb_dualdig4_rev2_config);
+
+	adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80,
+			      &cxusb_dualdig4_rev2_config);
+	if (adap->fe == NULL)
+		return -EIO;
+
+	return 0;
+}
+
+static int dib7070_tuner_reset(struct dvb_frontend *fe, int onoff)
+{
+	return dib7000p_set_gpio(fe, 8, 0, !onoff);
+}
+
+static int dib7070_tuner_sleep(struct dvb_frontend *fe, int onoff)
+{
+	return 0;
+}
+
+static struct dib0070_config dib7070p_dib0070_config = {
+	.i2c_address = DEFAULT_DIB0070_I2C_ADDRESS,
+	.reset = dib7070_tuner_reset,
+	.sleep = dib7070_tuner_sleep,
+	.clock_khz = 12000,
+};
+
+struct dib0700_adapter_state {
+	int (*set_param_save) (struct dvb_frontend *,
+			       struct dvb_frontend_parameters *);
+};
+
+static int dib7070_set_param_override(struct dvb_frontend *fe,
+				      struct dvb_frontend_parameters *fep)
+{
+	struct dvb_usb_adapter *adap = fe->dvb->priv;
+	struct dib0700_adapter_state *state = adap->priv;
+
+	u16 offset;
+	u8 band = BAND_OF_FREQUENCY(fep->frequency/1000);
+	switch (band) {
+	case BAND_VHF: offset = 950; break;
+	default:
+	case BAND_UHF: offset = 550; break;
+	}
+
+	dib7000p_set_wbd_ref(fe, offset + dib0070_wbd_offset(fe));
+
+	return state->set_param_save(fe, fep);
+}
+
+static int cxusb_dualdig4_rev2_tuner_attach(struct dvb_usb_adapter *adap)
+{
+	struct dib0700_adapter_state *st = adap->priv;
+	struct i2c_adapter *tun_i2c =
+		dib7000p_get_i2c_master(adap->fe,
+					DIBX000_I2C_INTERFACE_TUNER, 1);
+
+	if (dvb_attach(dib0070_attach, adap->fe, tun_i2c,
+	    &dib7070p_dib0070_config) == NULL)
+		return -ENODEV;
+
+	st->set_param_save = adap->fe->ops.tuner_ops.set_params;
+	adap->fe->ops.tuner_ops.set_params = dib7070_set_param_override;
+	return 0;
+}
+
 static int cxusb_nano2_frontend_attach(struct dvb_usb_adapter *adap)
 {
 	if (usb_set_interface(adap->dev->udev, 0, 1) < 0)
@@ -751,6 +1094,54 @@
 	return -EIO;
 }
 
+static struct lgs8gl5_config lgs8gl5_cfg = {
+	.demod_address = 0x19,
+};
+
+static int cxusb_d680_dmb_frontend_attach(struct dvb_usb_adapter *adap)
+{
+	struct dvb_usb_device *d = adap->dev;
+	int n;
+
+	/* Select required USB configuration */
+	if (usb_set_interface(d->udev, 0, 0) < 0)
+		err("set interface failed");
+
+	/* Unblock all USB pipes */
+	usb_clear_halt(d->udev,
+		usb_sndbulkpipe(d->udev, d->props.generic_bulk_ctrl_endpoint));
+	usb_clear_halt(d->udev,
+		usb_rcvbulkpipe(d->udev, d->props.generic_bulk_ctrl_endpoint));
+	usb_clear_halt(d->udev,
+		usb_rcvbulkpipe(d->udev, d->props.adapter[0].stream.endpoint));
+
+	/* Drain USB pipes to avoid hang after reboot */
+	for (n = 0;  n < 5;  n++) {
+		cxusb_d680_dmb_drain_message(d);
+		cxusb_d680_dmb_drain_video(d);
+		msleep(200);
+	}
+
+	/* Reset the tuner */
+	if (cxusb_d680_dmb_gpio_tuner(d, 0x07, 0) < 0) {
+		err("clear tuner gpio failed");
+		return -EIO;
+	}
+	msleep(100);
+	if (cxusb_d680_dmb_gpio_tuner(d, 0x07, 1) < 0) {
+		err("set tuner gpio failed");
+		return -EIO;
+	}
+	msleep(100);
+
+	/* Attach frontend */
+	adap->fe = dvb_attach(lgs8gl5_attach, &lgs8gl5_cfg, &d->i2c_adap);
+	if (adap->fe == NULL)
+		return -EIO;
+
+	return 0;
+}
+
 /*
  * DViCO has shipped two devices with the same USB ID, but only one of them
  * needs a firmware download.  Check the device class details to see if they
@@ -826,9 +1217,11 @@
 static struct dvb_usb_device_properties cxusb_bluebird_lgz201_properties;
 static struct dvb_usb_device_properties cxusb_bluebird_dtt7579_properties;
 static struct dvb_usb_device_properties cxusb_bluebird_dualdig4_properties;
+static struct dvb_usb_device_properties cxusb_bluebird_dualdig4_rev2_properties;
 static struct dvb_usb_device_properties cxusb_bluebird_nano2_properties;
 static struct dvb_usb_device_properties cxusb_bluebird_nano2_needsfirmware_properties;
 static struct dvb_usb_device_properties cxusb_aver_a868r_properties;
+static struct dvb_usb_device_properties cxusb_d680_dmb_properties;
 
 static int cxusb_probe(struct usb_interface *intf,
 		       const struct usb_device_id *id)
@@ -852,6 +1245,11 @@
 				     THIS_MODULE, NULL, adapter_nr) ||
 	    0 == dvb_usb_device_init(intf, &cxusb_aver_a868r_properties,
 				     THIS_MODULE, NULL, adapter_nr) ||
+	    0 == dvb_usb_device_init(intf,
+				     &cxusb_bluebird_dualdig4_rev2_properties,
+				     THIS_MODULE, NULL, adapter_nr) ||
+	    0 == dvb_usb_device_init(intf, &cxusb_d680_dmb_properties,
+				     THIS_MODULE, NULL, adapter_nr) ||
 	    0)
 		return 0;
 
@@ -876,6 +1274,8 @@
 	{ USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DVB_T_NANO_2) },
 	{ USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DVB_T_NANO_2_NFW_WARM) },
 	{ USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_A868R) },
+	{ USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_4_REV_2) },
+	{ USB_DEVICE(USB_VID_CONEXANT, USB_PID_CONEXANT_D680_DMB) },
 	{}		/* Terminating entry */
 };
 MODULE_DEVICE_TABLE (usb, cxusb_table);
@@ -1321,6 +1721,104 @@
 	}
 };
 
+static
+struct dvb_usb_device_properties cxusb_bluebird_dualdig4_rev2_properties = {
+	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
+
+	.usb_ctrl         = CYPRESS_FX2,
+
+	.size_of_priv     = sizeof(struct cxusb_state),
+
+	.num_adapters = 1,
+	.adapter = {
+		{
+			.streaming_ctrl  = cxusb_streaming_ctrl,
+			.frontend_attach = cxusb_dualdig4_rev2_frontend_attach,
+			.tuner_attach    = cxusb_dualdig4_rev2_tuner_attach,
+			.size_of_priv    = sizeof(struct dib0700_adapter_state),
+			/* parameter for the MPEG2-data transfer */
+			.stream = {
+				.type = USB_BULK,
+				.count = 7,
+				.endpoint = 0x02,
+				.u = {
+					.bulk = {
+						.buffersize = 4096,
+					}
+				}
+			},
+		},
+	},
+
+	.power_ctrl       = cxusb_bluebird_power_ctrl,
+
+	.i2c_algo         = &cxusb_i2c_algo,
+
+	.generic_bulk_ctrl_endpoint = 0x01,
+
+	.rc_interval      = 100,
+	.rc_key_map       = dvico_mce_rc_keys,
+	.rc_key_map_size  = ARRAY_SIZE(dvico_mce_rc_keys),
+	.rc_query         = cxusb_rc_query,
+
+	.num_device_descs = 1,
+	.devices = {
+		{   "DViCO FusionHDTV DVB-T Dual Digital 4 (rev 2)",
+			{ NULL },
+			{ &cxusb_table[17], NULL },
+		},
+	}
+};
+
+static struct dvb_usb_device_properties cxusb_d680_dmb_properties = {
+	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
+
+	.usb_ctrl         = CYPRESS_FX2,
+
+	.size_of_priv     = sizeof(struct cxusb_state),
+
+	.num_adapters = 1,
+	.adapter = {
+		{
+			.streaming_ctrl   = cxusb_d680_dmb_streaming_ctrl,
+			.frontend_attach  = cxusb_d680_dmb_frontend_attach,
+			.tuner_attach     = cxusb_d680_dmb_tuner_attach,
+
+			/* parameter for the MPEG2-data transfer */
+			.stream = {
+				.type = USB_BULK,
+				.count = 5,
+				.endpoint = 0x02,
+				.u = {
+					.bulk = {
+						.buffersize = 8192,
+					}
+				}
+			},
+		},
+	},
+
+	.power_ctrl       = cxusb_d680_dmb_power_ctrl,
+
+	.i2c_algo         = &cxusb_i2c_algo,
+
+	.generic_bulk_ctrl_endpoint = 0x01,
+
+	.rc_interval      = 100,
+	.rc_key_map       = d680_dmb_rc_keys,
+	.rc_key_map_size  = ARRAY_SIZE(d680_dmb_rc_keys),
+	.rc_query         = cxusb_d680_dmb_rc_query,
+
+	.num_device_descs = 1,
+	.devices = {
+		{
+			"Conexant DMB-TH Stick",
+			{ NULL },
+			{ &cxusb_table[18], NULL },
+		},
+	}
+};
+
 static struct usb_driver cxusb_driver = {
 	.name		= "dvb_usb_cxusb",
 	.probe		= cxusb_probe,
diff --git a/drivers/media/dvb/dvb-usb/dib0700.h b/drivers/media/dvb/dvb-usb/dib0700.h
index 66d4dc6..7391939 100644
--- a/drivers/media/dvb/dvb-usb/dib0700.h
+++ b/drivers/media/dvb/dvb-usb/dib0700.h
@@ -31,6 +31,8 @@
 	// 2 Byte: MPEG2 mode:  4MSB(1 = Master Mode, 0 = Slave Mode) 4LSB(Channel 1 = bit0, Channel 2 = bit1)
 	// 2 Byte: Analog mode: 4MSB(0 = 625 lines, 1 = 525 lines)    4LSB(     "                "           )
 #define REQUEST_SET_RC       0x11
+#define REQUEST_NEW_I2C_READ 0x12
+#define REQUEST_NEW_I2C_WRITE 0x13
 #define REQUEST_GET_VERSION  0x15
 
 struct dib0700_state {
@@ -39,6 +41,8 @@
 	u8 rc_toggle;
 	u8 rc_counter;
 	u8 is_dib7000pc;
+	u8 fw_use_new_i2c_api;
+	u8 disable_streaming_master_mode;
 };
 
 extern int dib0700_set_gpio(struct dvb_usb_device *, enum dib07x0_gpios gpio, u8 gpio_dir, u8 gpio_val);
diff --git a/drivers/media/dvb/dvb-usb/dib0700_core.c b/drivers/media/dvb/dvb-usb/dib0700_core.c
index 595a046..dd53cee 100644
--- a/drivers/media/dvb/dvb-usb/dib0700_core.c
+++ b/drivers/media/dvb/dvb-usb/dib0700_core.c
@@ -82,9 +82,98 @@
 }
 
 /*
- * I2C master xfer function
+ * I2C master xfer function (supported in 1.20 firmware)
  */
-static int dib0700_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg *msg,int num)
+static int dib0700_i2c_xfer_new(struct i2c_adapter *adap, struct i2c_msg *msg,
+				int num)
+{
+	/* The new i2c firmware messages are more reliable and in particular
+	   properly support i2c read calls not preceded by a write */
+
+	struct dvb_usb_device *d = i2c_get_adapdata(adap);
+	uint8_t bus_mode = 1;  /* 0=eeprom bus, 1=frontend bus */
+	uint8_t gen_mode = 0; /* 0=master i2c, 1=gpio i2c */
+	uint8_t en_start = 0;
+	uint8_t en_stop = 0;
+	uint8_t buf[255]; /* TBV: malloc ? */
+	int result, i;
+
+	/* Ensure nobody else hits the i2c bus while we're sending our
+	   sequence of messages, (such as the remote control thread) */
+	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+		return -EAGAIN;
+
+	for (i = 0; i < num; i++) {
+		if (i == 0) {
+			/* First message in the transaction */
+			en_start = 1;
+		} else if (!(msg[i].flags & I2C_M_NOSTART)) {
+			/* Device supports repeated-start */
+			en_start = 1;
+		} else {
+			/* Not the first packet and device doesn't support
+			   repeated start */
+			en_start = 0;
+		}
+		if (i == (num - 1)) {
+			/* Last message in the transaction */
+			en_stop = 1;
+		}
+
+		if (msg[i].flags & I2C_M_RD) {
+			/* Read request */
+			u16 index, value;
+			uint8_t i2c_dest;
+
+			i2c_dest = (msg[i].addr << 1);
+			value = ((en_start << 7) | (en_stop << 6) |
+				 (msg[i].len & 0x3F)) << 8 | i2c_dest;
+			/* I2C ctrl + FE bus; */
+			index = ((gen_mode<<6)&0xC0) | ((bus_mode<<4)&0x30);
+
+			result = usb_control_msg(d->udev,
+						 usb_rcvctrlpipe(d->udev, 0),
+						 REQUEST_NEW_I2C_READ,
+						 USB_TYPE_VENDOR | USB_DIR_IN,
+						 value, index, msg[i].buf,
+						 msg[i].len,
+						 USB_CTRL_GET_TIMEOUT);
+			if (result < 0) {
+				err("i2c read error (status = %d)\n", result);
+				break;
+			}
+		} else {
+			/* Write request */
+			buf[0] = REQUEST_NEW_I2C_WRITE;
+			buf[1] = (msg[i].addr << 1);
+			buf[2] = (en_start << 7) | (en_stop << 6) |
+				(msg[i].len & 0x3F);
+			/* I2C ctrl + FE bus; */
+			buf[3] = ((gen_mode<<6)&0xC0) | ((bus_mode<<4)&0x30);
+			/* The Actual i2c payload */
+			memcpy(&buf[4], msg[i].buf, msg[i].len);
+
+			result = usb_control_msg(d->udev,
+						 usb_sndctrlpipe(d->udev, 0),
+						 REQUEST_NEW_I2C_WRITE,
+						 USB_TYPE_VENDOR | USB_DIR_OUT,
+						 0, 0, buf, msg[i].len + 4,
+						 USB_CTRL_GET_TIMEOUT);
+			if (result < 0) {
+				err("i2c write error (status = %d)\n", result);
+				break;
+			}
+		}
+	}
+	mutex_unlock(&d->i2c_mutex);
+	return i;
+}
+
+/*
+ * I2C master xfer function (pre-1.20 firmware)
+ */
+static int dib0700_i2c_xfer_legacy(struct i2c_adapter *adap,
+				   struct i2c_msg *msg, int num)
 {
 	struct dvb_usb_device *d = i2c_get_adapdata(adap);
 	int i,len;
@@ -124,6 +213,21 @@
 	return i;
 }
 
+static int dib0700_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msg,
+			    int num)
+{
+	struct dvb_usb_device *d = i2c_get_adapdata(adap);
+	struct dib0700_state *st = d->priv;
+
+	if (st->fw_use_new_i2c_api == 1) {
+		/* User running at least fw 1.20 */
+		return dib0700_i2c_xfer_new(adap, msg, num);
+	} else {
+		/* Use legacy calls */
+		return dib0700_i2c_xfer_legacy(adap, msg, num);
+	}
+}
+
 static u32 dib0700_i2c_func(struct i2c_adapter *adapter)
 {
 	return I2C_FUNC_I2C;
@@ -246,7 +350,12 @@
 
 	b[0] = REQUEST_ENABLE_VIDEO;
 	b[1] = (onoff << 4) | 0x00; /* this bit gives a kind of command, rather than enabling something or not */
-	b[2] = (0x01 << 4); /* Master mode */
+
+	if (st->disable_streaming_master_mode == 1)
+		b[2] = 0x00;
+	else
+		b[2] = (0x01 << 4); /* Master mode */
+
 	b[3] = 0x00;
 
 	deb_info("modifying (%d) streaming state for %d\n", onoff, adap->id);
diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c
index 6c0e5c5..0cfccc24 100644
--- a/drivers/media/dvb/dvb-usb/dib0700_devices.c
+++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c
@@ -14,6 +14,8 @@
 #include "mt2060.h"
 #include "mt2266.h"
 #include "tuner-xc2028.h"
+#include "xc5000.h"
+#include "s5h1411.h"
 #include "dib0070.h"
 
 static int force_lna_activation;
@@ -366,7 +368,8 @@
 	.gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS,
 };
 
-static int stk7700ph_xc3028_callback(void *ptr, int command, int arg)
+static int stk7700ph_xc3028_callback(void *ptr, int component,
+				     int command, int arg)
 {
 	struct dvb_usb_adapter *adap = ptr;
 
@@ -394,7 +397,6 @@
 
 static struct xc2028_config stk7700ph_xc3028_config = {
 	.i2c_addr = 0x61,
-	.callback = stk7700ph_xc3028_callback,
 	.ctrl = &stk7700ph_xc3028_ctrl,
 };
 
@@ -435,7 +437,9 @@
 		DIBX000_I2C_INTERFACE_TUNER, 1);
 
 	stk7700ph_xc3028_config.i2c_adap = tun_i2c;
-	stk7700ph_xc3028_config.video_dev = adap;
+
+	/* FIXME: generalize & move to common area */
+	adap->fe->callback = stk7700ph_xc3028_callback;
 
 	return dvb_attach(xc2028_attach, adap->fe, &stk7700ph_xc3028_config)
 		== NULL ? -ENODEV : 0;
@@ -677,6 +681,43 @@
 	{ 0x01, 0x7d, KEY_VOLUMEDOWN },
 	{ 0x02, 0x42, KEY_CHANNELUP },
 	{ 0x00, 0x7d, KEY_CHANNELDOWN },
+
+	/* Key codes for Nova-TD "credit card" remote control. */
+	{ 0x1d, 0x00, KEY_0 },
+	{ 0x1d, 0x01, KEY_1 },
+	{ 0x1d, 0x02, KEY_2 },
+	{ 0x1d, 0x03, KEY_3 },
+	{ 0x1d, 0x04, KEY_4 },
+	{ 0x1d, 0x05, KEY_5 },
+	{ 0x1d, 0x06, KEY_6 },
+	{ 0x1d, 0x07, KEY_7 },
+	{ 0x1d, 0x08, KEY_8 },
+	{ 0x1d, 0x09, KEY_9 },
+	{ 0x1d, 0x0a, KEY_TEXT },
+	{ 0x1d, 0x0d, KEY_MENU },
+	{ 0x1d, 0x0f, KEY_MUTE },
+	{ 0x1d, 0x10, KEY_VOLUMEUP },
+	{ 0x1d, 0x11, KEY_VOLUMEDOWN },
+	{ 0x1d, 0x12, KEY_CHANNEL },
+	{ 0x1d, 0x14, KEY_UP },
+	{ 0x1d, 0x15, KEY_DOWN },
+	{ 0x1d, 0x16, KEY_LEFT },
+	{ 0x1d, 0x17, KEY_RIGHT },
+	{ 0x1d, 0x1c, KEY_TV },
+	{ 0x1d, 0x1e, KEY_NEXT },
+	{ 0x1d, 0x1f, KEY_BACK },
+	{ 0x1d, 0x20, KEY_CHANNELUP },
+	{ 0x1d, 0x21, KEY_CHANNELDOWN },
+	{ 0x1d, 0x24, KEY_LAST },
+	{ 0x1d, 0x25, KEY_OK },
+	{ 0x1d, 0x30, KEY_PAUSE },
+	{ 0x1d, 0x32, KEY_REWIND },
+	{ 0x1d, 0x34, KEY_FASTFORWARD },
+	{ 0x1d, 0x35, KEY_PLAY },
+	{ 0x1d, 0x36, KEY_STOP },
+	{ 0x1d, 0x37, KEY_RECORD },
+	{ 0x1d, 0x3b, KEY_GOTO },
+	{ 0x1d, 0x3d, KEY_POWER },
 };
 
 /* STK7700P: Hauppauge Nova-T Stick, AVerMedia Volar */
@@ -1078,6 +1119,97 @@
 	return adap->fe == NULL ? -ENODEV : 0;
 }
 
+/* S5H1411 */
+static struct s5h1411_config pinnacle_801e_config = {
+	.output_mode   = S5H1411_PARALLEL_OUTPUT,
+	.gpio          = S5H1411_GPIO_OFF,
+	.mpeg_timing   = S5H1411_MPEGTIMING_NONCONTINOUS_NONINVERTING_CLOCK,
+	.qam_if        = S5H1411_IF_44000,
+	.vsb_if        = S5H1411_IF_44000,
+	.inversion     = S5H1411_INVERSION_OFF,
+	.status_mode   = S5H1411_DEMODLOCKING
+};
+
+/* Pinnacle PCTV HD Pro 801e GPIOs map:
+   GPIO0  - currently unknown
+   GPIO1  - xc5000 tuner reset
+   GPIO2  - CX25843 sleep
+   GPIO3  - currently unknown
+   GPIO4  - currently unknown
+   GPIO6  - currently unknown
+   GPIO7  - currently unknown
+   GPIO9  - currently unknown
+   GPIO10 - CX25843 reset
+ */
+static int s5h1411_frontend_attach(struct dvb_usb_adapter *adap)
+{
+	struct dib0700_state *st = adap->dev->priv;
+
+	/* Make use of the new i2c functions from FW 1.20 */
+	st->fw_use_new_i2c_api = 1;
+
+	/* The s5h1411 requires the dib0700 to not be in master mode */
+	st->disable_streaming_master_mode = 1;
+
+	/* All msleep values taken from Windows USB trace */
+	dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 0);
+	dib0700_set_gpio(adap->dev, GPIO3, GPIO_OUT, 0);
+	dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1);
+	msleep(400);
+	dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0);
+	msleep(60);
+	dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1);
+	msleep(30);
+	dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);
+	dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1);
+	dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1);
+	dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1);
+	dib0700_set_gpio(adap->dev, GPIO2, GPIO_OUT, 0);
+	msleep(30);
+
+	/* Put the CX25843 to sleep for now since we're in digital mode */
+	dib0700_set_gpio(adap->dev, GPIO2, GPIO_OUT, 1);
+
+	/* GPIOs are initialized, do the attach */
+	adap->fe = dvb_attach(s5h1411_attach, &pinnacle_801e_config,
+			      &adap->dev->i2c_adap);
+	return adap->fe == NULL ? -ENODEV : 0;
+}
+
+static int dib0700_xc5000_tuner_callback(void *priv, int component,
+					 int command, int arg)
+{
+	struct dvb_usb_adapter *adap = priv;
+
+	if (command == XC5000_TUNER_RESET) {
+		/* Reset the tuner */
+		dib0700_set_gpio(adap->dev, GPIO1, GPIO_OUT, 0);
+		msleep(330); /* from Windows USB trace */
+		dib0700_set_gpio(adap->dev, GPIO1, GPIO_OUT, 1);
+		msleep(330); /* from Windows USB trace */
+	} else {
+		err("xc5000: unknown tuner callback command: %d\n", command);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static struct xc5000_config s5h1411_xc5000_tunerconfig = {
+	.i2c_address      = 0x64,
+	.if_khz           = 5380,
+};
+
+static int xc5000_tuner_attach(struct dvb_usb_adapter *adap)
+{
+	/* FIXME: generalize & move to common area */
+	adap->fe->callback = dib0700_xc5000_tuner_callback;
+
+	return dvb_attach(xc5000_attach, adap->fe, &adap->dev->i2c_adap,
+			  &s5h1411_xc5000_tunerconfig)
+		== NULL ? -ENODEV : 0;
+}
+
 /* DVB-USB and USB stuff follows */
 struct usb_device_id dib0700_usb_id_table[] = {
 /* 0 */	{ USB_DEVICE(USB_VID_DIBCOM,    USB_PID_DIBCOM_STK7700P) },
@@ -1119,6 +1251,11 @@
 	{ USB_DEVICE(USB_VID_LEADTEK,   USB_PID_WINFAST_DTV_DONGLE_STK7700P_2) },
 /* 35 */{ USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_TD_STICK_52009) },
 	{ USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_500_3) },
+	{ USB_DEVICE(USB_VID_GIGABYTE,  USB_PID_GIGABYTE_U8000) },
+	{ USB_DEVICE(USB_VID_YUAN,      USB_PID_YUAN_STK7700PH) },
+	{ USB_DEVICE(USB_VID_ASUS,	USB_PID_ASUS_U3000H) },
+/* 40 */{ USB_DEVICE(USB_VID_PINNACLE,  USB_PID_PINNACLE_PCTV801E) },
+	{ USB_DEVICE(USB_VID_PINNACLE,  USB_PID_PINNACLE_PCTV801E_SE) },
 	{ 0 }		/* Terminating entry */
 };
 MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table);
@@ -1126,7 +1263,7 @@
 #define DIB0700_DEFAULT_DEVICE_PROPERTIES \
 	.caps              = DVB_USB_IS_AN_I2C_ADAPTER, \
 	.usb_ctrl          = DEVICE_SPECIFIC, \
-	.firmware          = "dvb-usb-dib0700-1.10.fw", \
+	.firmware          = "dvb-usb-dib0700-1.20.fw", \
 	.download_firmware = dib0700_download_firmware, \
 	.no_reconnect      = 1, \
 	.size_of_priv      = sizeof(struct dib0700_state), \
@@ -1293,7 +1430,12 @@
 				{ &dib0700_usb_id_table[31], NULL },
 				{ NULL },
 			}
-		}
+		},
+
+		.rc_interval      = DEFAULT_RC_INTERVAL,
+		.rc_key_map       = dib0700_rc_keys,
+		.rc_key_map_size  = ARRAY_SIZE(dib0700_rc_keys),
+		.rc_query         = dib0700_rc_query
 	}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
 
 		.num_adapters = 1,
@@ -1408,7 +1550,7 @@
 			},
 		},
 
-		.num_device_descs = 3,
+		.num_device_descs = 5,
 		.devices = {
 			{   "Terratec Cinergy HT USB XE",
 				{ &dib0700_usb_id_table[27], NULL },
@@ -1422,6 +1564,47 @@
 				{ &dib0700_usb_id_table[32], NULL },
 				{ NULL },
 			},
+			{   "Gigabyte U8000-RH",
+				{ &dib0700_usb_id_table[37], NULL },
+				{ NULL },
+			},
+			{   "YUAN High-Tech STK7700PH",
+				{ &dib0700_usb_id_table[38], NULL },
+				{ NULL },
+			},
+			{   "Asus My Cinema-U3000Hybrid",
+				{ &dib0700_usb_id_table[39], NULL },
+				{ NULL },
+			},
+		},
+		.rc_interval      = DEFAULT_RC_INTERVAL,
+		.rc_key_map       = dib0700_rc_keys,
+		.rc_key_map_size  = ARRAY_SIZE(dib0700_rc_keys),
+		.rc_query         = dib0700_rc_query
+	}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
+		.num_adapters = 1,
+		.adapter = {
+			{
+				.frontend_attach  = s5h1411_frontend_attach,
+				.tuner_attach     = xc5000_tuner_attach,
+
+				DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
+
+				.size_of_priv = sizeof(struct
+						dib0700_adapter_state),
+			},
+		},
+
+		.num_device_descs = 2,
+		.devices = {
+			{   "Pinnacle PCTV HD Pro USB Stick",
+				{ &dib0700_usb_id_table[40], NULL },
+				{ NULL },
+			},
+			{   "Pinnacle PCTV HD USB Stick",
+				{ &dib0700_usb_id_table[41], NULL },
+				{ NULL },
+			},
 		},
 		.rc_interval      = DEFAULT_RC_INTERVAL,
 		.rc_key_map       = dib0700_rc_keys,
diff --git a/drivers/media/dvb/dvb-usb/dtv5100.c b/drivers/media/dvb/dvb-usb/dtv5100.c
new file mode 100644
index 0000000..078ce92
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/dtv5100.c
@@ -0,0 +1,240 @@
+/*
+ * DVB USB Linux driver for AME DTV-5100 USB2.0 DVB-T
+ *
+ * Copyright (C) 2008  Antoine Jacquet <royale@zerezo.com>
+ * http://royale.zerezo.com/dtv5100/
+ *
+ * Inspired by gl861.c and au6610.c drivers
+ *
+ * This program is free software; you can redistribute it and/or 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 "dtv5100.h"
+#include "zl10353.h"
+#include "qt1010.h"
+
+/* debug */
+static int dvb_usb_dtv5100_debug;
+module_param_named(debug, dvb_usb_dtv5100_debug, int, 0644);
+MODULE_PARM_DESC(debug, "set debugging level" DVB_USB_DEBUG_STATUS);
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+static int dtv5100_i2c_msg(struct dvb_usb_device *d, u8 addr,
+			   u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen)
+{
+	u8 request;
+	u8 type;
+	u16 value;
+	u16 index;
+
+	switch (wlen) {
+	case 1:
+		/* write { reg }, read { value } */
+		request = (addr == DTV5100_DEMOD_ADDR ? DTV5100_DEMOD_READ :
+							DTV5100_TUNER_READ);
+		type = USB_TYPE_VENDOR | USB_DIR_IN;
+		value = 0;
+		break;
+	case 2:
+		/* write { reg, value } */
+		request = (addr == DTV5100_DEMOD_ADDR ? DTV5100_DEMOD_WRITE :
+							DTV5100_TUNER_WRITE);
+		type = USB_TYPE_VENDOR | USB_DIR_OUT;
+		value = wbuf[1];
+		break;
+	default:
+		warn("wlen = %x, aborting.", wlen);
+		return -EINVAL;
+	}
+	index = (addr << 8) + wbuf[0];
+
+	msleep(1); /* avoid I2C errors */
+	return usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0), request,
+			       type, value, index, rbuf, rlen,
+			       DTV5100_USB_TIMEOUT);
+}
+
+/* I2C */
+static int dtv5100_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
+			    int num)
+{
+	struct dvb_usb_device *d = i2c_get_adapdata(adap);
+	int i;
+
+	if (num > 2)
+		return -EINVAL;
+
+	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+		return -EAGAIN;
+
+	for (i = 0; i < num; i++) {
+		/* write/read request */
+		if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) {
+			if (dtv5100_i2c_msg(d, msg[i].addr, msg[i].buf,
+					    msg[i].len, msg[i+1].buf,
+					    msg[i+1].len) < 0)
+				break;
+			i++;
+		} else if (dtv5100_i2c_msg(d, msg[i].addr, msg[i].buf,
+					   msg[i].len, NULL, 0) < 0)
+				break;
+	}
+
+	mutex_unlock(&d->i2c_mutex);
+	return i;
+}
+
+static u32 dtv5100_i2c_func(struct i2c_adapter *adapter)
+{
+	return I2C_FUNC_I2C;
+}
+
+static struct i2c_algorithm dtv5100_i2c_algo = {
+	.master_xfer   = dtv5100_i2c_xfer,
+	.functionality = dtv5100_i2c_func,
+};
+
+/* Callbacks for DVB USB */
+static struct zl10353_config dtv5100_zl10353_config = {
+	.demod_address = DTV5100_DEMOD_ADDR,
+	.no_tuner = 1,
+	.parallel_ts = 1,
+};
+
+static int dtv5100_frontend_attach(struct dvb_usb_adapter *adap)
+{
+	adap->fe = dvb_attach(zl10353_attach, &dtv5100_zl10353_config,
+			      &adap->dev->i2c_adap);
+	if (adap->fe == NULL)
+		return -EIO;
+
+	/* disable i2c gate, or it won't work... is this safe? */
+	adap->fe->ops.i2c_gate_ctrl = NULL;
+
+	return 0;
+}
+
+static struct qt1010_config dtv5100_qt1010_config = {
+	.i2c_address = DTV5100_TUNER_ADDR
+};
+
+static int dtv5100_tuner_attach(struct dvb_usb_adapter *adap)
+{
+	return dvb_attach(qt1010_attach,
+			  adap->fe, &adap->dev->i2c_adap,
+			  &dtv5100_qt1010_config) == NULL ? -ENODEV : 0;
+}
+
+/* DVB USB Driver stuff */
+static struct dvb_usb_device_properties dtv5100_properties;
+
+static int dtv5100_probe(struct usb_interface *intf,
+			 const struct usb_device_id *id)
+{
+	int i, ret;
+	struct usb_device *udev = interface_to_usbdev(intf);
+
+	/* initialize non qt1010/zl10353 part? */
+	for (i = 0; dtv5100_init[i].request; i++) {
+		ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
+				      dtv5100_init[i].request,
+				      USB_TYPE_VENDOR | USB_DIR_OUT,
+				      dtv5100_init[i].value,
+				      dtv5100_init[i].index, NULL, 0,
+				      DTV5100_USB_TIMEOUT);
+		if (ret)
+			return ret;
+	}
+
+	ret = dvb_usb_device_init(intf, &dtv5100_properties,
+				  THIS_MODULE, NULL, adapter_nr);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static struct usb_device_id dtv5100_table[] = {
+	{ USB_DEVICE(0x06be, 0xa232) },
+	{ }		/* Terminating entry */
+};
+MODULE_DEVICE_TABLE(usb, dtv5100_table);
+
+static struct dvb_usb_device_properties dtv5100_properties = {
+	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
+	.usb_ctrl = DEVICE_SPECIFIC,
+
+	.size_of_priv = 0,
+
+	.num_adapters = 1,
+	.adapter = {{
+		.frontend_attach = dtv5100_frontend_attach,
+		.tuner_attach    = dtv5100_tuner_attach,
+
+		.stream = {
+			.type = USB_BULK,
+			.count = 8,
+			.endpoint = 0x82,
+			.u = {
+				.bulk = {
+					.buffersize = 4096,
+				}
+			}
+		},
+	} },
+
+	.i2c_algo = &dtv5100_i2c_algo,
+
+	.num_device_descs = 1,
+	.devices = {
+		{
+			.name = "AME DTV-5100 USB2.0 DVB-T",
+			.cold_ids = { NULL },
+			.warm_ids = { &dtv5100_table[0], NULL },
+		},
+	}
+};
+
+static struct usb_driver dtv5100_driver = {
+	.name		= "dvb_usb_dtv5100",
+	.probe		= dtv5100_probe,
+	.disconnect	= dvb_usb_device_exit,
+	.id_table	= dtv5100_table,
+};
+
+/* module stuff */
+static int __init dtv5100_module_init(void)
+{
+	int ret;
+
+	ret = usb_register(&dtv5100_driver);
+	if (ret)
+		err("usb_register failed. Error number %d", ret);
+
+	return ret;
+}
+
+static void __exit dtv5100_module_exit(void)
+{
+	/* deregister this driver from the USB subsystem */
+	usb_deregister(&dtv5100_driver);
+}
+
+module_init(dtv5100_module_init);
+module_exit(dtv5100_module_exit);
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/dtv5100.h b/drivers/media/dvb/dvb-usb/dtv5100.h
new file mode 100644
index 0000000..93e96e0
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/dtv5100.h
@@ -0,0 +1,51 @@
+/*
+ * DVB USB Linux driver for AME DTV-5100 USB2.0 DVB-T
+ *
+ * Copyright (C) 2008  Antoine Jacquet <royale@zerezo.com>
+ * http://royale.zerezo.com/dtv5100/
+ *
+ * This program is free software; you can redistribute it and/or 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 _DVB_USB_DTV5100_H_
+#define _DVB_USB_DTV5100_H_
+
+#define DVB_USB_LOG_PREFIX "dtv5100"
+#include "dvb-usb.h"
+
+#define DTV5100_USB_TIMEOUT 500
+
+#define DTV5100_DEMOD_ADDR	0x00
+#define DTV5100_DEMOD_WRITE	0xc0
+#define DTV5100_DEMOD_READ	0xc1
+
+#define DTV5100_TUNER_ADDR	0xc4
+#define DTV5100_TUNER_WRITE	0xc7
+#define DTV5100_TUNER_READ	0xc8
+
+#define DRIVER_AUTHOR "Antoine Jacquet, http://royale.zerezo.com/"
+#define DRIVER_DESC "AME DTV-5100 USB2.0 DVB-T"
+
+static struct {
+	u8 request;
+	u8 value;
+	u16 index;
+} dtv5100_init[] = {
+	{ 0x000000c5, 0x00000000, 0x00000001 },
+	{ 0x000000c5, 0x00000001, 0x00000001 },
+	{ }		/* Terminating entry */
+};
+
+#endif
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
index 03dfb9f..7380b94 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
@@ -22,6 +22,7 @@
 #define USB_VID_AVERMEDIA			0x07ca
 #define USB_VID_COMPRO				0x185b
 #define USB_VID_COMPRO_UNK			0x145f
+#define USB_VID_CONEXANT			0x0572
 #define USB_VID_CYPRESS				0x04b4
 #define USB_VID_DIBCOM				0x10b8
 #define USB_VID_DPOSH				0x1498
@@ -33,16 +34,19 @@
 #define USB_VID_HAUPPAUGE			0x2040
 #define USB_VID_HYPER_PALTEK			0x1025
 #define USB_VID_KWORLD				0xeb2a
+#define USB_VID_KWORLD_2			0x1b80
 #define USB_VID_KYE				0x0458
 #define USB_VID_LEADTEK				0x0413
 #define USB_VID_LITEON				0x04ca
 #define USB_VID_MEDION				0x1660
 #define USB_VID_MIGLIA				0x18f3
 #define USB_VID_MSI				0x0db0
+#define USB_VID_MSI_2				0x1462
 #define USB_VID_OPERA1				0x695c
 #define USB_VID_PINNACLE			0x2304
 #define USB_VID_TECHNOTREND			0x0b48
 #define USB_VID_TERRATEC			0x0ccd
+#define USB_VID_TELESTAR			0x10b9
 #define USB_VID_VISIONPLUS			0x13d3
 #define USB_VID_TWINHAN				0x1822
 #define USB_VID_ULTIMA_ELECTRONIC		0x05d8
@@ -50,15 +54,18 @@
 #define USB_VID_WIDEVIEW			0x14aa
 #define USB_VID_GIGABYTE			0x1044
 #define USB_VID_YUAN				0x1164
-
+#define USB_VID_XTENSIONS			0x1ae7
 
 /* Product IDs */
 #define USB_PID_ADSTECH_USB2_COLD			0xa333
 #define USB_PID_ADSTECH_USB2_WARM			0xa334
 #define USB_PID_AFATECH_AF9005				0x9020
+#define USB_PID_AFATECH_AF9015_9015			0x9015
+#define USB_PID_AFATECH_AF9015_9016			0x9016
 #define USB_VID_ALINK_DTU				0xf170
 #define USB_PID_ANSONIC_DVBT_USB			0x6000
 #define USB_PID_ANYSEE					0x861f
+#define USB_PID_AZUREWAVE_AD_TU700			0x3237
 #define USB_PID_AVERMEDIA_DVBT_USB_COLD			0x0001
 #define USB_PID_AVERMEDIA_DVBT_USB_WARM			0x0002
 #define USB_PID_AVERMEDIA_DVBT_USB2_COLD		0xa800
@@ -69,6 +76,7 @@
 #define USB_PID_COMPRO_DVBU2000_UNK_WARM		0x010d
 #define USB_PID_COMPRO_VIDEOMATE_U500			0x1e78
 #define USB_PID_COMPRO_VIDEOMATE_U500_PC		0x1e80
+#define USB_PID_CONEXANT_D680_DMB			0x86d6
 #define USB_PID_DIBCOM_HOOK_DEFAULT			0x0064
 #define USB_PID_DIBCOM_HOOK_DEFAULT_REENUM		0x0065
 #define USB_PID_DIBCOM_MOD3000_COLD			0x0bb8
@@ -87,9 +95,12 @@
 #define USB_PID_UNIWILL_STK7700P			0x6003
 #define USB_PID_GRANDTEC_DVBT_USB_COLD			0x0fa0
 #define USB_PID_GRANDTEC_DVBT_USB_WARM			0x0fa1
+#define USB_PID_KWORLD_399U				0xe399
+#define USB_PID_KWORLD_PC160_2T				0xc160
 #define USB_PID_KWORLD_VSTREAM_COLD			0x17de
 #define USB_PID_KWORLD_VSTREAM_WARM			0x17df
 #define USB_PID_TERRATEC_CINERGY_T_USB_XE		0x0055
+#define USB_PID_TERRATEC_CINERGY_T_USB_XE_REV2		0x0069
 #define USB_PID_TWINHAN_VP7041_COLD			0x3201
 #define USB_PID_TWINHAN_VP7041_WARM			0x3202
 #define USB_PID_TWINHAN_VP7020_COLD			0x3203
@@ -98,6 +109,7 @@
 #define USB_PID_TWINHAN_VP7045_WARM			0x3206
 #define USB_PID_TWINHAN_VP7021_COLD			0x3207
 #define USB_PID_TWINHAN_VP7021_WARM			0x3208
+#define USB_PID_TINYTWIN				0x3226
 #define USB_PID_DNTV_TINYUSB2_COLD			0x3223
 #define USB_PID_DNTV_TINYUSB2_WARM			0x3224
 #define USB_PID_ULTIMA_TVBOX_COLD			0x8105
@@ -144,6 +156,9 @@
 #define USB_PID_AVERMEDIA_HYBRID_ULTRA_USB_M039R	0x0039
 #define USB_PID_AVERMEDIA_HYBRID_ULTRA_USB_M039R_ATSC	0x1039
 #define USB_PID_AVERMEDIA_HYBRID_ULTRA_USB_M039R_DVBT	0x2039
+#define USB_PID_AVERMEDIA_VOLAR_X			0xa815
+#define USB_PID_AVERMEDIA_VOLAR_X_2			0x8150
+#define USB_PID_AVERMEDIA_A309				0xa309
 #define USB_PID_TECHNOTREND_CONNECT_S2400               0x3006
 #define USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY	0x005a
 #define USB_PID_TERRATEC_CINERGY_HT_USB_XE		0x0058
@@ -153,8 +168,11 @@
 #define USB_PID_PINNACLE_PCTV2000E			0x022c
 #define USB_PID_PINNACLE_PCTV_DVB_T_FLASH		0x0228
 #define USB_PID_PINNACLE_PCTV_DUAL_DIVERSITY_DVB_T	0x0229
+#define USB_PID_PINNACLE_PCTV71E			0x022b
 #define USB_PID_PINNACLE_PCTV72E			0x0236
 #define USB_PID_PINNACLE_PCTV73E			0x0237
+#define USB_PID_PINNACLE_PCTV801E			0x023a
+#define USB_PID_PINNACLE_PCTV801E_SE			0x023b
 #define USB_PID_PCTV_200E				0x020e
 #define USB_PID_PCTV_400E				0x020f
 #define USB_PID_PCTV_450E				0x0222
@@ -171,6 +189,7 @@
 #define USB_PID_DVICO_BLUEBIRD_DUAL_2_COLD		0xdb58
 #define USB_PID_DVICO_BLUEBIRD_DUAL_2_WARM		0xdb59
 #define USB_PID_DVICO_BLUEBIRD_DUAL_4			0xdb78
+#define USB_PID_DVICO_BLUEBIRD_DUAL_4_REV_2		0xdb98
 #define USB_PID_DVICO_BLUEBIRD_DVB_T_NANO_2		0xdb70
 #define USB_PID_DVICO_BLUEBIRD_DVB_T_NANO_2_NFW_WARM	0xdb71
 #define USB_PID_DIGITALNOW_BLUEBIRD_DUAL_1_COLD		0xdb54
@@ -190,6 +209,7 @@
 #define USB_PID_WINFAST_DTV_DONGLE_WARM			0x6026
 #define USB_PID_WINFAST_DTV_DONGLE_STK7700P		0x6f00
 #define USB_PID_WINFAST_DTV_DONGLE_STK7700P_2		0x6f01
+#define USB_PID_WINFAST_DTV_DONGLE_GOLD			0x6029
 #define USB_PID_GENPIX_8PSK_REV_1_COLD			0x0200
 #define USB_PID_GENPIX_8PSK_REV_1_WARM			0x0201
 #define USB_PID_GENPIX_8PSK_REV_2			0x0202
@@ -197,14 +217,21 @@
 #define USB_PID_GENPIX_SKYWALKER_CW3K			0x0204
 #define USB_PID_SIGMATEK_DVB_110			0x6610
 #define USB_PID_MSI_DIGI_VOX_MINI_II			0x1513
+#define USB_PID_MSI_DIGIVOX_DUO				0x8801
 #define USB_PID_OPERA1_COLD				0x2830
 #define USB_PID_OPERA1_WARM				0x3829
 #define USB_PID_LIFEVIEW_TV_WALKER_TWIN_COLD		0x0514
 #define USB_PID_LIFEVIEW_TV_WALKER_TWIN_WARM		0x0513
 #define USB_PID_GIGABYTE_U7000				0x7001
+#define USB_PID_GIGABYTE_U8000				0x7002
 #define USB_PID_ASUS_U3000				0x171f
+#define USB_PID_ASUS_U3000H				0x1736
 #define USB_PID_ASUS_U3100				0x173f
 #define USB_PID_YUAN_EC372S				0x1edc
+#define USB_PID_YUAN_STK7700PH				0x1f08
 #define USB_PID_DW2102					0x2102
+#define USB_PID_XTENSIONS_XD_380			0x0381
+#define USB_PID_TELESTAR_STARSTICK_2			0x8000
+#define USB_PID_MSI_DIGI_VOX_MINI_III                   0x8807
 
 #endif
diff --git a/drivers/media/dvb/dvb-usb/dw2102.c b/drivers/media/dvb/dvb-usb/dw2102.c
index a4d898b..ca53df6 100644
--- a/drivers/media/dvb/dvb-usb/dw2102.c
+++ b/drivers/media/dvb/dvb-usb/dw2102.c
@@ -1,4 +1,5 @@
-/* DVB USB framework compliant Linux driver for the DVBWorld DVB-S 2102 Card
+/* DVB USB framework compliant Linux driver for the
+*	DVBWorld DVB-S 2101, 2102, DVB-S2 2104 Card
 *
 * Copyright (C) 2008 Igor M. Liplianin (liplianin@me.by)
 *
@@ -10,62 +11,74 @@
 */
 #include <linux/version.h>
 #include "dw2102.h"
+#include "si21xx.h"
 #include "stv0299.h"
 #include "z0194a.h"
+#include "stv0288.h"
+#include "stb6000.h"
+#include "eds1547.h"
+#include "cx24116.h"
 
 #ifndef USB_PID_DW2102
 #define USB_PID_DW2102 0x2102
 #endif
 
-#define DW2102_READ_MSG 0
-#define DW2102_WRITE_MSG 1
+#ifndef USB_PID_DW2104
+#define USB_PID_DW2104 0x2104
+#endif
+
+#define DW210X_READ_MSG 0
+#define DW210X_WRITE_MSG 1
 
 #define REG_1F_SYMBOLRATE_BYTE0 0x1f
 #define REG_20_SYMBOLRATE_BYTE1 0x20
 #define REG_21_SYMBOLRATE_BYTE2 0x21
-
+/* on my own*/
 #define DW2102_VOLTAGE_CTRL (0x1800)
 #define DW2102_RC_QUERY (0x1a00)
 
-struct dw2102_state {
+struct dw210x_state {
 	u32 last_key_pressed;
 };
-struct dw2102_rc_keys {
+struct dw210x_rc_keys {
 	u32 keycode;
 	u32 event;
 };
 
+/* debug */
+static int dvb_usb_dw2102_debug;
+module_param_named(debug, dvb_usb_dw2102_debug, int, 0644);
+MODULE_PARM_DESC(debug, "set debugging level (1=info 2=xfer (or-able))." DVB_USB_DEBUG_STATUS);
+
 DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
 
-static int dw2102_op_rw(struct usb_device *dev, u8 request, u16 value,
-		u8 *data, u16 len, int flags)
+static int dw210x_op_rw(struct usb_device *dev, u8 request, u16 value,
+			u16 index, u8 * data, u16 len, int flags)
 {
 	int ret;
 	u8 u8buf[len];
 
-	unsigned int pipe = (flags == DW2102_READ_MSG) ?
-		usb_rcvctrlpipe(dev, 0) : usb_sndctrlpipe(dev, 0);
-	u8 request_type = (flags == DW2102_READ_MSG) ? USB_DIR_IN : USB_DIR_OUT;
+	unsigned int pipe = (flags == DW210X_READ_MSG) ?
+				usb_rcvctrlpipe(dev, 0) : usb_sndctrlpipe(dev, 0);
+	u8 request_type = (flags == DW210X_READ_MSG) ? USB_DIR_IN : USB_DIR_OUT;
 
-	if (flags == DW2102_WRITE_MSG)
+	if (flags == DW210X_WRITE_MSG)
 		memcpy(u8buf, data, len);
-	ret = usb_control_msg(dev, pipe, request,
-		request_type | USB_TYPE_VENDOR, value, 0 , u8buf, len, 2000);
+	ret = usb_control_msg(dev, pipe, request, request_type | USB_TYPE_VENDOR,
+				value, index , u8buf, len, 2000);
 
-	if (flags == DW2102_READ_MSG)
+	if (flags == DW210X_READ_MSG)
 		memcpy(data, u8buf, len);
 	return ret;
 }
 
 /* I2C */
-
 static int dw2102_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
 		int num)
 {
 struct dvb_usb_device *d = i2c_get_adapdata(adap);
 	int i = 0, ret = 0;
 	u8 buf6[] = {0x2c, 0x05, 0xc0, 0, 0, 0, 0};
-	u8 request;
 	u16 value;
 
 	if (!d)
@@ -76,14 +89,12 @@
 	switch (num) {
 	case 2:
 		/* read stv0299 register */
-		request = 0xb5;
 		value = msg[0].buf[0];/* register */
 		for (i = 0; i < msg[1].len; i++) {
 			value = value + i;
-			ret = dw2102_op_rw(d->udev, 0xb5,
-				value, buf6, 2, DW2102_READ_MSG);
+			ret = dw210x_op_rw(d->udev, 0xb5, value, 0,
+					buf6, 2, DW210X_READ_MSG);
 			msg[1].buf[i] = buf6[0];
-
 		}
 		break;
 	case 1:
@@ -93,8 +104,8 @@
 			buf6[0] = 0x2a;
 			buf6[1] = msg[0].buf[0];
 			buf6[2] = msg[0].buf[1];
-			ret = dw2102_op_rw(d->udev, 0xb2,
-				0, buf6, 3, DW2102_WRITE_MSG);
+			ret = dw210x_op_rw(d->udev, 0xb2, 0, 0,
+					buf6, 3, DW210X_WRITE_MSG);
 			break;
 		case 0x60:
 			if (msg[0].flags == 0) {
@@ -106,26 +117,26 @@
 				buf6[4] = msg[0].buf[1];
 				buf6[5] = msg[0].buf[2];
 				buf6[6] = msg[0].buf[3];
-				ret = dw2102_op_rw(d->udev, 0xb2,
-				0, buf6, 7, DW2102_WRITE_MSG);
+				ret = dw210x_op_rw(d->udev, 0xb2, 0, 0,
+						buf6, 7, DW210X_WRITE_MSG);
 			} else {
-			/* write to tuner pll */
-				ret = dw2102_op_rw(d->udev, 0xb5,
-				0, buf6, 1, DW2102_READ_MSG);
+			/* read from tuner */
+				ret = dw210x_op_rw(d->udev, 0xb5, 0, 0,
+						buf6, 1, DW210X_READ_MSG);
 				msg[0].buf[0] = buf6[0];
 			}
 			break;
 		case (DW2102_RC_QUERY):
-			ret  = dw2102_op_rw(d->udev, 0xb8,
-				0, buf6, 2, DW2102_READ_MSG);
+			ret  = dw210x_op_rw(d->udev, 0xb8, 0, 0,
+					buf6, 2, DW210X_READ_MSG);
 			msg[0].buf[0] = buf6[0];
 			msg[0].buf[1] = buf6[1];
 			break;
 		case (DW2102_VOLTAGE_CTRL):
 			buf6[0] = 0x30;
 			buf6[1] = msg[0].buf[0];
-			ret = dw2102_op_rw(d->udev, 0xb2,
-				0, buf6, 2, DW2102_WRITE_MSG);
+			ret = dw210x_op_rw(d->udev, 0xb2, 0, 0,
+					buf6, 2, DW210X_WRITE_MSG);
 			break;
 		}
 
@@ -136,17 +147,265 @@
 	return num;
 }
 
-static u32 dw2102_i2c_func(struct i2c_adapter *adapter)
+static int dw2102_serit_i2c_transfer(struct i2c_adapter *adap,
+						struct i2c_msg msg[], int num)
+{
+	struct dvb_usb_device *d = i2c_get_adapdata(adap);
+	int ret = 0;
+	u8 buf6[] = {0, 0, 0, 0, 0, 0, 0};
+
+	if (!d)
+		return -ENODEV;
+	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+		return -EAGAIN;
+
+	switch (num) {
+	case 2:
+		/* read si2109 register by number */
+		buf6[0] = 0xd0;
+		buf6[1] = msg[0].len;
+		buf6[2] = msg[0].buf[0];
+		ret = dw210x_op_rw(d->udev, 0xc2, 0, 0,
+				buf6, msg[0].len + 2, DW210X_WRITE_MSG);
+		/* read si2109 register */
+		ret = dw210x_op_rw(d->udev, 0xc3, 0xd0, 0,
+				buf6, msg[1].len + 2, DW210X_READ_MSG);
+		memcpy(msg[1].buf, buf6 + 2, msg[1].len);
+
+		break;
+	case 1:
+		switch (msg[0].addr) {
+		case 0x68:
+			/* write to si2109 register */
+			buf6[0] = 0xd0;
+			buf6[1] = msg[0].len;
+			memcpy(buf6 + 2, msg[0].buf, msg[0].len);
+			ret = dw210x_op_rw(d->udev, 0xc2, 0, 0, buf6,
+					msg[0].len + 2, DW210X_WRITE_MSG);
+			break;
+		case(DW2102_RC_QUERY):
+			ret  = dw210x_op_rw(d->udev, 0xb8, 0, 0,
+					buf6, 2, DW210X_READ_MSG);
+			msg[0].buf[0] = buf6[0];
+			msg[0].buf[1] = buf6[1];
+			break;
+		case(DW2102_VOLTAGE_CTRL):
+			buf6[0] = 0x30;
+			buf6[1] = msg[0].buf[0];
+			ret = dw210x_op_rw(d->udev, 0xb2, 0, 0,
+					buf6, 2, DW210X_WRITE_MSG);
+			break;
+		}
+		break;
+	}
+
+	mutex_unlock(&d->i2c_mutex);
+	return num;
+}
+static int dw2102_earda_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], int num)
+{
+	struct dvb_usb_device *d = i2c_get_adapdata(adap);
+	int ret = 0;
+
+	if (!d)
+		return -ENODEV;
+	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+		return -EAGAIN;
+
+	switch (num) {
+	case 2: {
+		/* read */
+		/* first write first register number */
+		u8 ibuf [msg[1].len + 2], obuf[3];
+		obuf[0] = 0xd0;
+		obuf[1] = msg[0].len;
+		obuf[2] = msg[0].buf[0];
+		ret = dw210x_op_rw(d->udev, 0xc2, 0, 0,
+				obuf, msg[0].len + 2, DW210X_WRITE_MSG);
+		/* second read registers */
+		ret = dw210x_op_rw(d->udev, 0xc3, 0xd1 , 0,
+				ibuf, msg[1].len + 2, DW210X_READ_MSG);
+		memcpy(msg[1].buf, ibuf + 2, msg[1].len);
+
+		break;
+	}
+	case 1:
+		switch (msg[0].addr) {
+		case 0x68: {
+			/* write to register */
+			u8 obuf[msg[0].len + 2];
+			obuf[0] = 0xd0;
+			obuf[1] = msg[0].len;
+			memcpy(obuf + 2, msg[0].buf, msg[0].len);
+			ret = dw210x_op_rw(d->udev, 0xc2, 0, 0,
+					obuf, msg[0].len + 2, DW210X_WRITE_MSG);
+			break;
+		}
+		case 0x61: {
+			/* write to tuner */
+			u8 obuf[msg[0].len + 2];
+			obuf[0] = 0xc2;
+			obuf[1] = msg[0].len;
+			memcpy(obuf + 2, msg[0].buf, msg[0].len);
+			ret = dw210x_op_rw(d->udev, 0xc2, 0, 0,
+					obuf, msg[0].len + 2, DW210X_WRITE_MSG);
+			break;
+		}
+		case(DW2102_RC_QUERY): {
+			u8 ibuf[2];
+			ret  = dw210x_op_rw(d->udev, 0xb8, 0, 0,
+					ibuf, 2, DW210X_READ_MSG);
+			memcpy(msg[0].buf, ibuf , 2);
+			break;
+		}
+		case(DW2102_VOLTAGE_CTRL): {
+			u8 obuf[2];
+			obuf[0] = 0x30;
+			obuf[1] = msg[0].buf[0];
+			ret = dw210x_op_rw(d->udev, 0xb2, 0, 0,
+					obuf, 2, DW210X_WRITE_MSG);
+			break;
+		}
+		}
+
+		break;
+	}
+
+	mutex_unlock(&d->i2c_mutex);
+	return num;
+}
+
+static int dw2104_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], int num)
+{
+	struct dvb_usb_device *d = i2c_get_adapdata(adap);
+	int ret = 0;
+	int len, i;
+
+	if (!d)
+		return -ENODEV;
+	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+		return -EAGAIN;
+
+	switch (num) {
+	case 2: {
+		/* read */
+		/* first write first register number */
+		u8 ibuf [msg[1].len + 2], obuf[3];
+		obuf[0] = 0xaa;
+		obuf[1] = msg[0].len;
+		obuf[2] = msg[0].buf[0];
+		ret = dw210x_op_rw(d->udev, 0xc2, 0, 0,
+				obuf, msg[0].len + 2, DW210X_WRITE_MSG);
+		/* second read registers */
+		ret = dw210x_op_rw(d->udev, 0xc3, 0xab , 0,
+				ibuf, msg[1].len + 2, DW210X_READ_MSG);
+		memcpy(msg[1].buf, ibuf + 2, msg[1].len);
+
+		break;
+	}
+	case 1:
+		switch (msg[0].addr) {
+		case 0x55: {
+			if (msg[0].buf[0] == 0xf7) {
+				/* firmware */
+				/* Write in small blocks */
+				u8 obuf[19];
+				obuf[0] = 0xaa;
+				obuf[1] = 0x11;
+				obuf[2] = 0xf7;
+				len = msg[0].len - 1;
+				i = 1;
+				do {
+					memcpy(obuf + 3, msg[0].buf + i, (len > 16 ? 16 : len));
+					ret = dw210x_op_rw(d->udev, 0xc2, 0, 0,
+						obuf, (len > 16 ? 16 : len) + 3, DW210X_WRITE_MSG);
+					i += 16;
+					len -= 16;
+				} while (len > 0);
+			} else {
+				/* write to register */
+				u8 obuf[msg[0].len + 2];
+				obuf[0] = 0xaa;
+				obuf[1] = msg[0].len;
+				memcpy(obuf + 2, msg[0].buf, msg[0].len);
+				ret = dw210x_op_rw(d->udev, 0xc2, 0, 0,
+						obuf, msg[0].len + 2, DW210X_WRITE_MSG);
+			}
+			break;
+		}
+		case(DW2102_RC_QUERY): {
+			u8 ibuf[2];
+			ret  = dw210x_op_rw(d->udev, 0xb8, 0, 0,
+					ibuf, 2, DW210X_READ_MSG);
+			memcpy(msg[0].buf, ibuf , 2);
+			break;
+		}
+		case(DW2102_VOLTAGE_CTRL): {
+			u8 obuf[2];
+			obuf[0] = 0x30;
+			obuf[1] = msg[0].buf[0];
+			ret = dw210x_op_rw(d->udev, 0xb2, 0, 0,
+					obuf, 2, DW210X_WRITE_MSG);
+			break;
+		}
+		}
+
+		break;
+	}
+
+	mutex_unlock(&d->i2c_mutex);
+	return num;
+}
+
+static u32 dw210x_i2c_func(struct i2c_adapter *adapter)
 {
 	return I2C_FUNC_I2C;
 }
 
 static struct i2c_algorithm dw2102_i2c_algo = {
 	.master_xfer = dw2102_i2c_transfer,
-	.functionality = dw2102_i2c_func,
+	.functionality = dw210x_i2c_func,
 };
 
-static int dw2102_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
+static struct i2c_algorithm dw2102_serit_i2c_algo = {
+	.master_xfer = dw2102_serit_i2c_transfer,
+	.functionality = dw210x_i2c_func,
+};
+
+static struct i2c_algorithm dw2102_earda_i2c_algo = {
+	.master_xfer = dw2102_earda_i2c_transfer,
+	.functionality = dw210x_i2c_func,
+};
+
+static struct i2c_algorithm dw2104_i2c_algo = {
+	.master_xfer = dw2104_i2c_transfer,
+	.functionality = dw210x_i2c_func,
+};
+
+static int dw210x_read_mac_address(struct dvb_usb_device *d, u8 mac[6])
+{
+	int i;
+	u8 ibuf[] = {0, 0};
+	u8 eeprom[256], eepromline[16];
+
+	for (i = 0; i < 256; i++) {
+		if (dw210x_op_rw(d->udev, 0xb6, 0xa0 , i, ibuf, 2, DW210X_READ_MSG) < 0) {
+			err("read eeprom failed.");
+			return -1;
+		} else {
+			eepromline[i%16] = ibuf[0];
+			eeprom[i] = ibuf[0];
+		}
+		if ((i % 16) == 15) {
+			deb_xfer("%02x: ", i - 15);
+			debug_dump(eepromline, 16, deb_xfer);
+		}
+	}
+	memcpy(mac, eeprom + 8, 6);
+	return 0;
+};
+
+static int dw210x_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
 {
 	static u8 command_13v[1] = {0x00};
 	static u8 command_18v[1] = {0x01};
@@ -163,14 +422,62 @@
 	return 0;
 }
 
+static struct cx24116_config dw2104_config = {
+	.demod_address = 0x55,
+	.mpg_clk_pos_pol = 0x01,
+};
+
+static struct si21xx_config serit_sp1511lhb_config = {
+	.demod_address = 0x68,
+	.min_delay_ms = 100,
+
+};
+
+static int dw2104_frontend_attach(struct dvb_usb_adapter *d)
+{
+	if ((d->fe = dvb_attach(cx24116_attach, &dw2104_config,
+			&d->dev->i2c_adap)) != NULL) {
+		d->fe->ops.set_voltage = dw210x_set_voltage;
+		info("Attached cx24116!\n");
+		return 0;
+	}
+	return -EIO;
+}
+
+static struct dvb_usb_device_properties dw2102_properties;
+
 static int dw2102_frontend_attach(struct dvb_usb_adapter *d)
 {
-	d->fe = dvb_attach(stv0299_attach, &sharp_z0194a_config,
-		&d->dev->i2c_adap);
-	if (d->fe != NULL) {
-		d->fe->ops.set_voltage = dw2102_set_voltage;
-		info("Attached stv0299!\n");
-		return 0;
+	if (dw2102_properties.i2c_algo == &dw2102_serit_i2c_algo) {
+		/*dw2102_properties.adapter->tuner_attach = NULL;*/
+		d->fe = dvb_attach(si21xx_attach, &serit_sp1511lhb_config,
+					&d->dev->i2c_adap);
+		if (d->fe != NULL) {
+			d->fe->ops.set_voltage = dw210x_set_voltage;
+			info("Attached si21xx!\n");
+			return 0;
+		}
+	}
+	if (dw2102_properties.i2c_algo == &dw2102_earda_i2c_algo) {
+		/*dw2102_properties.adapter->tuner_attach = dw2102_tuner_attach;*/
+		d->fe = dvb_attach(stv0288_attach, &earda_config,
+					&d->dev->i2c_adap);
+		if (d->fe != NULL) {
+			d->fe->ops.set_voltage = dw210x_set_voltage;
+			info("Attached stv0288!\n");
+			return 0;
+		}
+	}
+
+	if (dw2102_properties.i2c_algo == &dw2102_i2c_algo) {
+		/*dw2102_properties.adapter->tuner_attach = dw2102_tuner_attach;*/
+		d->fe = dvb_attach(stv0299_attach, &sharp_z0194a_config,
+					&d->dev->i2c_adap);
+		if (d->fe != NULL) {
+			d->fe->ops.set_voltage = dw210x_set_voltage;
+			info("Attached stv0299!\n");
+			return 0;
+		}
 	}
 	return -EIO;
 }
@@ -182,7 +489,15 @@
 	return 0;
 }
 
-static struct dvb_usb_rc_key dw2102_rc_keys[] = {
+static int dw2102_earda_tuner_attach(struct dvb_usb_adapter *adap)
+{
+	dvb_attach(stb6000_attach, adap->fe, 0x61,
+		&adap->dev->i2c_adap);
+
+	return 0;
+}
+
+static struct dvb_usb_rc_key dw210x_rc_keys[] = {
 	{ 0xf8,	0x0a, KEY_Q },		/*power*/
 	{ 0xf8,	0x0c, KEY_M },		/*mute*/
 	{ 0xf8,	0x11, KEY_1 },
@@ -221,7 +536,7 @@
 
 static int dw2102_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
 {
-	struct dw2102_state *st = d->priv;
+	struct dw210x_state *st = d->priv;
 	u8 key[2];
 	struct i2c_msg msg[] = {
 		{.addr = DW2102_RC_QUERY, .flags = I2C_M_RD, .buf = key,
@@ -231,12 +546,12 @@
 
 	*state = REMOTE_NO_KEY_PRESSED;
 	if (dw2102_i2c_transfer(&d->i2c_adap, msg, 1) == 1) {
-		for (i = 0; i < ARRAY_SIZE(dw2102_rc_keys); i++) {
-			if (dw2102_rc_keys[i].data == msg[0].buf[0]) {
+		for (i = 0; i < ARRAY_SIZE(dw210x_rc_keys); i++) {
+			if (dw210x_rc_keys[i].data == msg[0].buf[0]) {
 				*state = REMOTE_KEY_PRESSED;
-				*event = dw2102_rc_keys[i].event;
+				*event = dw210x_rc_keys[i].event;
 				st->last_key_pressed =
-					dw2102_rc_keys[i].event;
+					dw210x_rc_keys[i].event;
 				break;
 			}
 		st->last_key_pressed = 0;
@@ -249,6 +564,8 @@
 static struct usb_device_id dw2102_table[] = {
 	{USB_DEVICE(USB_VID_CYPRESS, USB_PID_DW2102)},
 	{USB_DEVICE(USB_VID_CYPRESS, 0x2101)},
+	{USB_DEVICE(USB_VID_CYPRESS, 0x2104)},
+	{USB_DEVICE(0x9022, 0xd650)},
 	{ }
 };
 
@@ -260,7 +577,7 @@
 	u8 *b, *p;
 	int ret = 0, i;
 	u8 reset;
-	u8 reset16 [] = {0, 0, 0, 0, 0, 0, 0};
+	u8 reset16[] = {0, 0, 0, 0, 0, 0, 0};
 	const struct firmware *fw;
 	const char *filename = "dvb-usb-dw2101.fw";
 	switch (dev->descriptor.idProduct) {
@@ -273,25 +590,23 @@
 			return ret;
 		}
 		break;
-	case USB_PID_DW2102:
+	default:
 		fw = frmwr;
 		break;
 	}
-	info("start downloading DW2102 firmware");
+	info("start downloading DW210X firmware");
 	p = kmalloc(fw->size, GFP_KERNEL);
 	reset = 1;
 	/*stop the CPU*/
-	dw2102_op_rw(dev, 0xa0, 0x7f92, &reset, 1, DW2102_WRITE_MSG);
-	dw2102_op_rw(dev, 0xa0, 0xe600, &reset, 1, DW2102_WRITE_MSG);
+	dw210x_op_rw(dev, 0xa0, 0x7f92, 0, &reset, 1, DW210X_WRITE_MSG);
+	dw210x_op_rw(dev, 0xa0, 0xe600, 0, &reset, 1, DW210X_WRITE_MSG);
 
 	if (p != NULL) {
 		memcpy(p, fw->data, fw->size);
 		for (i = 0; i < fw->size; i += 0x40) {
 			b = (u8 *) p + i;
-			if (dw2102_op_rw
-				(dev, 0xa0, i, b , 0x40,
-					DW2102_WRITE_MSG) != 0x40
-				) {
+			if (dw210x_op_rw(dev, 0xa0, i, 0, b , 0x40,
+					DW210X_WRITE_MSG) != 0x40) {
 				err("error while transferring firmware");
 				ret = -EINVAL;
 				break;
@@ -299,43 +614,66 @@
 		}
 		/* restart the CPU */
 		reset = 0;
-		if (ret || dw2102_op_rw
-			(dev, 0xa0, 0x7f92, &reset, 1,
-			DW2102_WRITE_MSG) != 1) {
+		if (ret || dw210x_op_rw(dev, 0xa0, 0x7f92, 0, &reset, 1,
+					DW210X_WRITE_MSG) != 1) {
 			err("could not restart the USB controller CPU.");
 			ret = -EINVAL;
 		}
-		if (ret || dw2102_op_rw
-			(dev, 0xa0, 0xe600, &reset, 1,
-			DW2102_WRITE_MSG) != 1) {
+		if (ret || dw210x_op_rw(dev, 0xa0, 0xe600, 0, &reset, 1,
+					DW210X_WRITE_MSG) != 1) {
 			err("could not restart the USB controller CPU.");
 			ret = -EINVAL;
 		}
 		/* init registers */
 		switch (dev->descriptor.idProduct) {
-		case USB_PID_DW2102:
-			dw2102_op_rw
-				(dev, 0xbf, 0x0040, &reset, 0,
-				DW2102_WRITE_MSG);
-			dw2102_op_rw
-				(dev, 0xb9, 0x0000, &reset16[0], 2,
-				DW2102_READ_MSG);
+		case USB_PID_DW2104:
+		case 0xd650:
+			reset = 1;
+			dw210x_op_rw(dev, 0xc4, 0x0000, 0, &reset, 1,
+					DW210X_WRITE_MSG);
+			reset = 0;
+			dw210x_op_rw(dev, 0xbf, 0x0040, 0, &reset, 0,
+					DW210X_WRITE_MSG);
 			break;
+		case USB_PID_DW2102:
+			dw210x_op_rw(dev, 0xbf, 0x0040, 0, &reset, 0,
+					DW210X_WRITE_MSG);
+			dw210x_op_rw(dev, 0xb9, 0x0000, 0, &reset16[0], 2,
+					DW210X_READ_MSG);
+			/* check STV0299 frontend  */
+			dw210x_op_rw(dev, 0xb5, 0, 0, &reset16[0], 2,
+					DW210X_READ_MSG);
+			if (reset16[0] == 0xa1) {
+				dw2102_properties.i2c_algo = &dw2102_i2c_algo;
+				dw2102_properties.adapter->tuner_attach = &dw2102_tuner_attach;
+				break;
+			} else {
+				/* check STV0288 frontend  */
+				reset16[0] = 0xd0;
+				reset16[1] = 1;
+				reset16[2] = 0;
+				dw210x_op_rw(dev, 0xc2, 0, 0, &reset16[0], 3,
+						DW210X_WRITE_MSG);
+				dw210x_op_rw(dev, 0xc3, 0xd1, 0, &reset16[0], 3,
+						DW210X_READ_MSG);
+				if (reset16[2] == 0x11) {
+					dw2102_properties.i2c_algo = &dw2102_earda_i2c_algo;
+					dw2102_properties.adapter->tuner_attach = &dw2102_earda_tuner_attach;
+					break;
+				}
+			}
 		case 0x2101:
-			dw2102_op_rw
-				(dev, 0xbc, 0x0030, &reset16[0], 2,
-				DW2102_READ_MSG);
-			dw2102_op_rw
-				(dev, 0xba, 0x0000, &reset16[0], 7,
-				DW2102_READ_MSG);
-			dw2102_op_rw
-				(dev, 0xba, 0x0000, &reset16[0], 7,
-				DW2102_READ_MSG);
-			dw2102_op_rw
-				(dev, 0xb9, 0x0000, &reset16[0], 2,
-				DW2102_READ_MSG);
+			dw210x_op_rw(dev, 0xbc, 0x0030, 0, &reset16[0], 2,
+					DW210X_READ_MSG);
+			dw210x_op_rw(dev, 0xba, 0x0000, 0, &reset16[0], 7,
+					DW210X_READ_MSG);
+			dw210x_op_rw(dev, 0xba, 0x0000, 0, &reset16[0], 7,
+					DW210X_READ_MSG);
+			dw210x_op_rw(dev, 0xb9, 0x0000, 0, &reset16[0], 2,
+					DW210X_READ_MSG);
 			break;
 		}
+		msleep(100);
 		kfree(p);
 	}
 	return ret;
@@ -345,12 +683,12 @@
 	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
 	.usb_ctrl = DEVICE_SPECIFIC,
 	.firmware = "dvb-usb-dw2102.fw",
-	.size_of_priv = sizeof(struct dw2102_state),
+	.size_of_priv = sizeof(struct dw210x_state),
 	.no_reconnect = 1,
 
-	.i2c_algo = &dw2102_i2c_algo,
-	.rc_key_map = dw2102_rc_keys,
-	.rc_key_map_size = ARRAY_SIZE(dw2102_rc_keys),
+	.i2c_algo = &dw2102_serit_i2c_algo,
+	.rc_key_map = dw210x_rc_keys,
+	.rc_key_map_size = ARRAY_SIZE(dw210x_rc_keys),
 	.rc_interval = 150,
 	.rc_query = dw2102_rc_query,
 
@@ -358,11 +696,12 @@
 	/* parameter for the MPEG2-data transfer */
 	.num_adapters = 1,
 	.download_firmware = dw2102_load_firmware,
-	.adapter = {
+	.read_mac_address = dw210x_read_mac_address,
+		.adapter = {
 		{
 			.frontend_attach = dw2102_frontend_attach,
 			.streaming_ctrl = NULL,
-			.tuner_attach = dw2102_tuner_attach,
+			.tuner_attach = NULL,
 			.stream = {
 				.type = USB_BULK,
 				.count = 8,
@@ -388,11 +727,64 @@
 	}
 };
 
+static struct dvb_usb_device_properties dw2104_properties = {
+	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
+	.usb_ctrl = DEVICE_SPECIFIC,
+	.firmware = "dvb-usb-dw2104.fw",
+	.size_of_priv = sizeof(struct dw210x_state),
+	.no_reconnect = 1,
+
+	.i2c_algo = &dw2104_i2c_algo,
+	.rc_key_map = dw210x_rc_keys,
+	.rc_key_map_size = ARRAY_SIZE(dw210x_rc_keys),
+	.rc_interval = 150,
+	.rc_query = dw2102_rc_query,
+
+	.generic_bulk_ctrl_endpoint = 0x81,
+	/* parameter for the MPEG2-data transfer */
+	.num_adapters = 1,
+	.download_firmware = dw2102_load_firmware,
+	.read_mac_address = dw210x_read_mac_address,
+	.adapter = {
+		{
+			.frontend_attach = dw2104_frontend_attach,
+			.streaming_ctrl = NULL,
+			/*.tuner_attach = dw2104_tuner_attach,*/
+			.stream = {
+				.type = USB_BULK,
+				.count = 8,
+				.endpoint = 0x82,
+				.u = {
+					.bulk = {
+						.buffersize = 4096,
+					}
+				}
+			},
+		}
+	},
+	.num_device_descs = 2,
+	.devices = {
+		{ "DVBWorld DW2104 USB2.0",
+			{&dw2102_table[2], NULL},
+			{NULL},
+		},
+		{ "TeVii S650 USB2.0",
+			{&dw2102_table[3], NULL},
+			{NULL},
+		},
+	}
+};
+
 static int dw2102_probe(struct usb_interface *intf,
 		const struct usb_device_id *id)
 {
-	return dvb_usb_device_init(intf, &dw2102_properties,
-		THIS_MODULE, NULL, adapter_nr);
+	if (0 == dvb_usb_device_init(intf, &dw2102_properties,
+			THIS_MODULE, NULL, adapter_nr) ||
+	    0 == dvb_usb_device_init(intf, &dw2104_properties,
+			THIS_MODULE, NULL, adapter_nr)) {
+		return 0;
+	}
+	return -ENODEV;
 }
 
 static struct usb_driver dw2102_driver = {
@@ -420,6 +812,6 @@
 module_exit(dw2102_module_exit);
 
 MODULE_AUTHOR("Igor M. Liplianin (c) liplianin@me.by");
-MODULE_DESCRIPTION("Driver for DVBWorld DVB-S 2101 2102 USB2.0 device");
+MODULE_DESCRIPTION("Driver for DVBWorld DVB-S 2101, 2102, DVB-S2 2104 USB2.0 device");
 MODULE_VERSION("0.1");
 MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/dw2102.h b/drivers/media/dvb/dvb-usb/dw2102.h
index 7a310f9..e337073 100644
--- a/drivers/media/dvb/dvb-usb/dw2102.h
+++ b/drivers/media/dvb/dvb-usb/dw2102.h
@@ -4,6 +4,5 @@
 #define DVB_USB_LOG_PREFIX "dw2102"
 #include "dvb-usb.h"
 
-extern int dvb_usb_dw2102_debug;
 #define deb_xfer(args...) dprintk(dvb_usb_dw2102_debug, 0x02, args)
 #endif
diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig
index 7dbb4a2..96b93e2 100644
--- a/drivers/media/dvb/frontends/Kconfig
+++ b/drivers/media/dvb/frontends/Kconfig
@@ -43,6 +43,20 @@
 	help
 	  A DVB-S tuner module. Say Y when you want to support this frontend.
 
+config DVB_STV0288
+	tristate "ST STV0288 based"
+	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
+	help
+	  A DVB-S tuner module. Say Y when you want to support this frontend.
+
+config DVB_STB6000
+	tristate "ST STB6000 silicon tuner"
+	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
+	  help
+	  A DVB-S silicon tuner module. Say Y when you want to support this tuner.
+
 config DVB_STV0299
 	tristate "ST STV0299 based"
 	depends on DVB_CORE && I2C
@@ -92,6 +106,20 @@
 	help
 	  A DVB-S PLL chip.
 
+config DVB_CX24116
+	tristate "Conexant CX24116 based"
+	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
+	help
+	  A DVB-S/S2 tuner module. Say Y when you want to support this frontend.
+
+config DVB_SI21XX
+	tristate "Silicon Labs SI21XX based"
+	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
+	help
+	  A DVB-S tuner module. Say Y when you want to support this frontend.
+
 comment "DVB-T (terrestrial) frontends"
 	depends on DVB_CORE
 
@@ -385,4 +413,23 @@
 	help
 	  An SEC control chip.
 
+config DVB_LGS8GL5
+	tristate "Silicon Legend LGS-8GL5 demodulator (OFDM)"
+	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
+	help
+	  A DMB-TH tuner module. Say Y when you want to support this frontend.
+
+comment "Tools to develop new frontends"
+
+config DVB_DUMMY_FE
+	tristate "Dummy frontend driver"
+	default n
+
+config DVB_AF9013
+	tristate "Afatech AF9013 demodulator"
+	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
+	help
+	  Say Y when you want to support this frontend.
 endmenu
diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile
index 028da55..aba79f4 100644
--- a/drivers/media/dvb/frontends/Makefile
+++ b/drivers/media/dvb/frontends/Makefile
@@ -48,3 +48,10 @@
 obj-$(CONFIG_DVB_AU8522) += au8522.o
 obj-$(CONFIG_DVB_TDA10048) += tda10048.o
 obj-$(CONFIG_DVB_S5H1411) += s5h1411.o
+obj-$(CONFIG_DVB_LGS8GL5) += lgs8gl5.o
+obj-$(CONFIG_DVB_DUMMY_FE) += dvb_dummy_fe.o
+obj-$(CONFIG_DVB_AF9013) += af9013.o
+obj-$(CONFIG_DVB_CX24116) += cx24116.o
+obj-$(CONFIG_DVB_SI21XX) += si21xx.o
+obj-$(CONFIG_DVB_STV0288) += stv0288.o
+obj-$(CONFIG_DVB_STB6000) += stb6000.o
diff --git a/drivers/media/dvb/frontends/af9013.c b/drivers/media/dvb/frontends/af9013.c
new file mode 100644
index 0000000..21c1060
--- /dev/null
+++ b/drivers/media/dvb/frontends/af9013.c
@@ -0,0 +1,1685 @@
+/*
+ * DVB USB Linux driver for Afatech AF9015 DVB-T USB2.0 receiver
+ *
+ * Copyright (C) 2007 Antti Palosaari <crope@iki.fi>
+ *
+ * Thanks to Afatech who kindly provided information.
+ *
+ *    This program is free software; you can redistribute it and/or 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/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/firmware.h>
+
+#include "dvb_frontend.h"
+#include "af9013_priv.h"
+#include "af9013.h"
+
+int af9013_debug;
+
+struct af9013_state {
+	struct i2c_adapter *i2c;
+	struct dvb_frontend frontend;
+
+	struct af9013_config config;
+
+	u16 signal_strength;
+	u32 ber;
+	u32 ucblocks;
+	u16 snr;
+	u32 frequency;
+	unsigned long next_statistics_check;
+};
+
+static u8 regmask[8] = { 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff };
+
+static int af9013_write_regs(struct af9013_state *state, u8 mbox, u16 reg,
+	u8 *val, u8 len)
+{
+	u8 buf[3+len];
+	struct i2c_msg msg = {
+		.addr = state->config.demod_address,
+		.flags = 0,
+		.len = sizeof(buf),
+		.buf = buf };
+
+	buf[0] = reg >> 8;
+	buf[1] = reg & 0xff;
+	buf[2] = mbox;
+	memcpy(&buf[3], val, len);
+
+	if (i2c_transfer(state->i2c, &msg, 1) != 1) {
+		warn("I2C write failed reg:%04x len:%d", reg, len);
+		return -EREMOTEIO;
+	}
+	return 0;
+}
+
+static int af9013_write_ofdm_regs(struct af9013_state *state, u16 reg, u8 *val,
+	u8 len)
+{
+	u8 mbox = (1 << 0)|(1 << 1)|((len - 1) << 2)|(0 << 6)|(0 << 7);
+	return af9013_write_regs(state, mbox, reg, val, len);
+}
+
+static int af9013_write_ofsm_regs(struct af9013_state *state, u16 reg, u8 *val,
+	u8 len)
+{
+	u8 mbox = (1 << 0)|(1 << 1)|((len - 1) << 2)|(1 << 6)|(1 << 7);
+	return af9013_write_regs(state, mbox, reg, val, len);
+}
+
+/* write single register */
+static int af9013_write_reg(struct af9013_state *state, u16 reg, u8 val)
+{
+	return af9013_write_ofdm_regs(state, reg, &val, 1);
+}
+
+/* read single register */
+static int af9013_read_reg(struct af9013_state *state, u16 reg, u8 *val)
+{
+	u8 obuf[3] = { reg >> 8, reg & 0xff, 0 };
+	u8 ibuf[1];
+	struct i2c_msg msg[2] = {
+		{
+			.addr = state->config.demod_address,
+			.flags = 0,
+			.len = sizeof(obuf),
+			.buf = obuf
+		}, {
+			.addr = state->config.demod_address,
+			.flags = I2C_M_RD,
+			.len = sizeof(ibuf),
+			.buf = ibuf
+		}
+	};
+
+	if (i2c_transfer(state->i2c, msg, 2) != 2) {
+		warn("I2C read failed reg:%04x", reg);
+		return -EREMOTEIO;
+	}
+	*val = ibuf[0];
+	return 0;
+}
+
+static int af9013_write_reg_bits(struct af9013_state *state, u16 reg, u8 pos,
+	u8 len, u8 val)
+{
+	int ret;
+	u8 tmp, mask;
+
+	ret = af9013_read_reg(state, reg, &tmp);
+	if (ret)
+		return ret;
+
+	mask = regmask[len - 1] << pos;
+	tmp = (tmp & ~mask) | ((val << pos) & mask);
+
+	return af9013_write_reg(state, reg, tmp);
+}
+
+static int af9013_read_reg_bits(struct af9013_state *state, u16 reg, u8 pos,
+	u8 len, u8 *val)
+{
+	int ret;
+	u8 tmp;
+
+	ret = af9013_read_reg(state, reg, &tmp);
+	if (ret)
+		return ret;
+	*val = (tmp >> pos) & regmask[len - 1];
+	return 0;
+}
+
+static int af9013_set_gpio(struct af9013_state *state, u8 gpio, u8 gpioval)
+{
+	int ret;
+	u8 pos;
+	u16 addr;
+	deb_info("%s: gpio:%d gpioval:%02x\n", __func__, gpio, gpioval);
+
+/* GPIO0 & GPIO1 0xd735
+   GPIO2 & GPIO3 0xd736 */
+
+	switch (gpio) {
+	case 0:
+	case 1:
+		addr = 0xd735;
+		break;
+	case 2:
+	case 3:
+		addr = 0xd736;
+		break;
+
+	default:
+		err("invalid gpio:%d\n", gpio);
+		ret = -EINVAL;
+		goto error;
+	};
+
+	switch (gpio) {
+	case 0:
+	case 2:
+		pos = 0;
+		break;
+	case 1:
+	case 3:
+	default:
+		pos = 4;
+		break;
+	};
+
+	ret = af9013_write_reg_bits(state, addr, pos, 4, gpioval);
+
+error:
+	return ret;
+}
+
+static u32 af913_div(u32 a, u32 b, u32 x)
+{
+	u32 r = 0, c = 0, i;
+	deb_info("%s: a:%d b:%d x:%d\n", __func__, a, b, x);
+
+	if (a > b) {
+		c = a / b;
+		a = a - c * b;
+	}
+
+	for (i = 0; i < x; i++) {
+		if (a >= b) {
+			r += 1;
+			a -= b;
+		}
+		a <<= 1;
+		r <<= 1;
+	}
+	r = (c << (u32)x) + r;
+
+	deb_info("%s: a:%d b:%d x:%d r:%d r:%x\n", __func__, a, b, x, r, r);
+	return r;
+}
+
+static int af9013_set_coeff(struct af9013_state *state, fe_bandwidth_t bw)
+{
+	int ret = 0;
+	u8 i = 0;
+	u8 buf[24];
+	u32 ns_coeff1_2048nu;
+	u32 ns_coeff1_8191nu;
+	u32 ns_coeff1_8192nu;
+	u32 ns_coeff1_8193nu;
+	u32 ns_coeff2_2k;
+	u32 ns_coeff2_8k;
+
+	deb_info("%s: adc_clock:%d bw:%d\n", __func__,
+		state->config.adc_clock, bw);
+
+	switch (state->config.adc_clock) {
+	case 28800: /* 28.800 MHz */
+		switch (bw) {
+		case BANDWIDTH_6_MHZ:
+			ns_coeff1_2048nu = 0x01e79e7a;
+			ns_coeff1_8191nu = 0x0079eb6e;
+			ns_coeff1_8192nu = 0x0079e79e;
+			ns_coeff1_8193nu = 0x0079e3cf;
+			ns_coeff2_2k     = 0x00f3cf3d;
+			ns_coeff2_8k     = 0x003cf3cf;
+			break;
+		case BANDWIDTH_7_MHZ:
+			ns_coeff1_2048nu = 0x0238e38e;
+			ns_coeff1_8191nu = 0x008e3d55;
+			ns_coeff1_8192nu = 0x008e38e4;
+			ns_coeff1_8193nu = 0x008e3472;
+			ns_coeff2_2k     = 0x011c71c7;
+			ns_coeff2_8k     = 0x00471c72;
+			break;
+		case BANDWIDTH_8_MHZ:
+			ns_coeff1_2048nu = 0x028a28a3;
+			ns_coeff1_8191nu = 0x00a28f3d;
+			ns_coeff1_8192nu = 0x00a28a29;
+			ns_coeff1_8193nu = 0x00a28514;
+			ns_coeff2_2k     = 0x01451451;
+			ns_coeff2_8k     = 0x00514514;
+			break;
+		default:
+			ret = -EINVAL;
+		}
+		break;
+	case 20480: /* 20.480 MHz */
+		switch (bw) {
+		case BANDWIDTH_6_MHZ:
+			ns_coeff1_2048nu = 0x02adb6dc;
+			ns_coeff1_8191nu = 0x00ab7313;
+			ns_coeff1_8192nu = 0x00ab6db7;
+			ns_coeff1_8193nu = 0x00ab685c;
+			ns_coeff2_2k     = 0x0156db6e;
+			ns_coeff2_8k     = 0x0055b6dc;
+			break;
+		case BANDWIDTH_7_MHZ:
+			ns_coeff1_2048nu = 0x03200001;
+			ns_coeff1_8191nu = 0x00c80640;
+			ns_coeff1_8192nu = 0x00c80000;
+			ns_coeff1_8193nu = 0x00c7f9c0;
+			ns_coeff2_2k     = 0x01900000;
+			ns_coeff2_8k     = 0x00640000;
+			break;
+		case BANDWIDTH_8_MHZ:
+			ns_coeff1_2048nu = 0x03924926;
+			ns_coeff1_8191nu = 0x00e4996e;
+			ns_coeff1_8192nu = 0x00e49249;
+			ns_coeff1_8193nu = 0x00e48b25;
+			ns_coeff2_2k     = 0x01c92493;
+			ns_coeff2_8k     = 0x00724925;
+			break;
+		default:
+			ret = -EINVAL;
+		}
+		break;
+	case 28000: /* 28.000 MHz */
+		switch (bw) {
+		case BANDWIDTH_6_MHZ:
+			ns_coeff1_2048nu = 0x01f58d10;
+			ns_coeff1_8191nu = 0x007d672f;
+			ns_coeff1_8192nu = 0x007d6344;
+			ns_coeff1_8193nu = 0x007d5f59;
+			ns_coeff2_2k     = 0x00fac688;
+			ns_coeff2_8k     = 0x003eb1a2;
+			break;
+		case BANDWIDTH_7_MHZ:
+			ns_coeff1_2048nu = 0x02492492;
+			ns_coeff1_8191nu = 0x00924db7;
+			ns_coeff1_8192nu = 0x00924925;
+			ns_coeff1_8193nu = 0x00924492;
+			ns_coeff2_2k     = 0x01249249;
+			ns_coeff2_8k     = 0x00492492;
+			break;
+		case BANDWIDTH_8_MHZ:
+			ns_coeff1_2048nu = 0x029cbc15;
+			ns_coeff1_8191nu = 0x00a7343f;
+			ns_coeff1_8192nu = 0x00a72f05;
+			ns_coeff1_8193nu = 0x00a729cc;
+			ns_coeff2_2k     = 0x014e5e0a;
+			ns_coeff2_8k     = 0x00539783;
+			break;
+		default:
+			ret = -EINVAL;
+		}
+		break;
+	case 25000: /* 25.000 MHz */
+		switch (bw) {
+		case BANDWIDTH_6_MHZ:
+			ns_coeff1_2048nu = 0x0231bcb5;
+			ns_coeff1_8191nu = 0x008c7391;
+			ns_coeff1_8192nu = 0x008c6f2d;
+			ns_coeff1_8193nu = 0x008c6aca;
+			ns_coeff2_2k     = 0x0118de5b;
+			ns_coeff2_8k     = 0x00463797;
+			break;
+		case BANDWIDTH_7_MHZ:
+			ns_coeff1_2048nu = 0x028f5c29;
+			ns_coeff1_8191nu = 0x00a3dc29;
+			ns_coeff1_8192nu = 0x00a3d70a;
+			ns_coeff1_8193nu = 0x00a3d1ec;
+			ns_coeff2_2k     = 0x0147ae14;
+			ns_coeff2_8k     = 0x0051eb85;
+			break;
+		case BANDWIDTH_8_MHZ:
+			ns_coeff1_2048nu = 0x02ecfb9d;
+			ns_coeff1_8191nu = 0x00bb44c1;
+			ns_coeff1_8192nu = 0x00bb3ee7;
+			ns_coeff1_8193nu = 0x00bb390d;
+			ns_coeff2_2k     = 0x01767dce;
+			ns_coeff2_8k     = 0x005d9f74;
+			break;
+		default:
+			ret = -EINVAL;
+		}
+		break;
+	default:
+		err("invalid xtal");
+		return -EINVAL;
+	}
+	if (ret) {
+		err("invalid bandwidth");
+		return ret;
+	}
+
+	buf[i++] = (u8) ((ns_coeff1_2048nu & 0x03000000) >> 24);
+	buf[i++] = (u8) ((ns_coeff1_2048nu & 0x00ff0000) >> 16);
+	buf[i++] = (u8) ((ns_coeff1_2048nu & 0x0000ff00) >> 8);
+	buf[i++] = (u8) ((ns_coeff1_2048nu & 0x000000ff));
+	buf[i++] = (u8) ((ns_coeff2_2k     & 0x01c00000) >> 22);
+	buf[i++] = (u8) ((ns_coeff2_2k     & 0x003fc000) >> 14);
+	buf[i++] = (u8) ((ns_coeff2_2k     & 0x00003fc0) >> 6);
+	buf[i++] = (u8) ((ns_coeff2_2k     & 0x0000003f));
+	buf[i++] = (u8) ((ns_coeff1_8191nu & 0x03000000) >> 24);
+	buf[i++] = (u8) ((ns_coeff1_8191nu & 0x00ffc000) >> 16);
+	buf[i++] = (u8) ((ns_coeff1_8191nu & 0x0000ff00) >> 8);
+	buf[i++] = (u8) ((ns_coeff1_8191nu & 0x000000ff));
+	buf[i++] = (u8) ((ns_coeff1_8192nu & 0x03000000) >> 24);
+	buf[i++] = (u8) ((ns_coeff1_8192nu & 0x00ffc000) >> 16);
+	buf[i++] = (u8) ((ns_coeff1_8192nu & 0x0000ff00) >> 8);
+	buf[i++] = (u8) ((ns_coeff1_8192nu & 0x000000ff));
+	buf[i++] = (u8) ((ns_coeff1_8193nu & 0x03000000) >> 24);
+	buf[i++] = (u8) ((ns_coeff1_8193nu & 0x00ffc000) >> 16);
+	buf[i++] = (u8) ((ns_coeff1_8193nu & 0x0000ff00) >> 8);
+	buf[i++] = (u8) ((ns_coeff1_8193nu & 0x000000ff));
+	buf[i++] = (u8) ((ns_coeff2_8k     & 0x01c00000) >> 22);
+	buf[i++] = (u8) ((ns_coeff2_8k     & 0x003fc000) >> 14);
+	buf[i++] = (u8) ((ns_coeff2_8k     & 0x00003fc0) >> 6);
+	buf[i++] = (u8) ((ns_coeff2_8k     & 0x0000003f));
+
+	deb_info("%s: coeff:", __func__);
+	debug_dump(buf, sizeof(buf), deb_info);
+
+	/* program */
+	for (i = 0; i < sizeof(buf); i++) {
+		ret = af9013_write_reg(state, 0xae00 + i, buf[i]);
+		if (ret)
+			break;
+	}
+
+	return ret;
+}
+
+static int af9013_set_adc_ctrl(struct af9013_state *state)
+{
+	int ret;
+	u8 buf[3], tmp, i;
+	u32 adc_cw;
+
+	deb_info("%s: adc_clock:%d\n", __func__, state->config.adc_clock);
+
+	/* adc frequency type */
+	switch (state->config.adc_clock) {
+	case 28800: /* 28.800 MHz */
+		tmp = 0;
+		break;
+	case 20480: /* 20.480 MHz */
+		tmp = 1;
+		break;
+	case 28000: /* 28.000 MHz */
+		tmp = 2;
+		break;
+	case 25000: /* 25.000 MHz */
+		tmp = 3;
+		break;
+	default:
+		err("invalid xtal");
+		return -EINVAL;
+	}
+
+	adc_cw = af913_div(state->config.adc_clock*1000, 1000000ul, 19ul);
+
+	buf[0] = (u8) ((adc_cw & 0x000000ff));
+	buf[1] = (u8) ((adc_cw & 0x0000ff00) >> 8);
+	buf[2] = (u8) ((adc_cw & 0x00ff0000) >> 16);
+
+	deb_info("%s: adc_cw:", __func__);
+	debug_dump(buf, sizeof(buf), deb_info);
+
+	/* program */
+	for (i = 0; i < sizeof(buf); i++) {
+		ret = af9013_write_reg(state, 0xd180 + i, buf[i]);
+		if (ret)
+			goto error;
+	}
+	ret = af9013_write_reg_bits(state, 0x9bd2, 0, 4, tmp);
+error:
+	return ret;
+}
+
+static int af9013_set_freq_ctrl(struct af9013_state *state, fe_bandwidth_t bw)
+{
+	int ret;
+	u16 addr;
+	u8 buf[3], i, j;
+	u32 adc_freq, freq_cw;
+	s8 bfs_spec_inv;
+	int if_sample_freq;
+
+	for (j = 0; j < 3; j++) {
+		if (j == 0) {
+			addr = 0xd140; /* fcw normal */
+			bfs_spec_inv = state->config.rf_spec_inv ? -1 : 1;
+		} else if (j == 1) {
+			addr = 0x9be7; /* fcw dummy ram */
+			bfs_spec_inv = state->config.rf_spec_inv ? -1 : 1;
+		} else {
+			addr = 0x9bea; /* fcw inverted */
+			bfs_spec_inv = state->config.rf_spec_inv ? 1 : -1;
+		}
+
+		adc_freq       = state->config.adc_clock * 1000;
+		if_sample_freq = state->config.tuner_if * 1000;
+
+		/* TDA18271 uses different sampling freq for every bw */
+		if (state->config.tuner == AF9013_TUNER_TDA18271) {
+			switch (bw) {
+			case BANDWIDTH_6_MHZ:
+				if_sample_freq = 3300000; /* 3.3 MHz */
+				break;
+			case BANDWIDTH_7_MHZ:
+				if_sample_freq = 3800000; /* 3.8 MHz */
+				break;
+			case BANDWIDTH_8_MHZ:
+			default:
+				if_sample_freq = 4300000; /* 4.3 MHz */
+				break;
+			}
+		}
+
+		while (if_sample_freq > (adc_freq / 2))
+			if_sample_freq = if_sample_freq - adc_freq;
+
+		if (if_sample_freq >= 0)
+			bfs_spec_inv = bfs_spec_inv * (-1);
+		else
+			if_sample_freq = if_sample_freq * (-1);
+
+		freq_cw = af913_div(if_sample_freq, adc_freq, 23ul);
+
+		if (bfs_spec_inv == -1)
+			freq_cw = 0x00800000 - freq_cw;
+
+		buf[0] = (u8) ((freq_cw & 0x000000ff));
+		buf[1] = (u8) ((freq_cw & 0x0000ff00) >> 8);
+		buf[2] = (u8) ((freq_cw & 0x007f0000) >> 16);
+
+
+		deb_info("%s: freq_cw:", __func__);
+		debug_dump(buf, sizeof(buf), deb_info);
+
+		/* program */
+		for (i = 0; i < sizeof(buf); i++) {
+			ret = af9013_write_reg(state, addr++, buf[i]);
+			if (ret)
+				goto error;
+		}
+	}
+error:
+	return ret;
+}
+
+static int af9013_set_ofdm_params(struct af9013_state *state,
+	struct dvb_ofdm_parameters *params, u8 *auto_mode)
+{
+	int ret;
+	u8 i, buf[3] = {0, 0, 0};
+	*auto_mode = 0; /* set if parameters are requested to auto set */
+
+	switch (params->transmission_mode) {
+	case TRANSMISSION_MODE_AUTO:
+		*auto_mode = 1;
+	case TRANSMISSION_MODE_2K:
+		break;
+	case TRANSMISSION_MODE_8K:
+		buf[0] |= (1 << 0);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (params->guard_interval) {
+	case GUARD_INTERVAL_AUTO:
+		*auto_mode = 1;
+	case GUARD_INTERVAL_1_32:
+		break;
+	case GUARD_INTERVAL_1_16:
+		buf[0] |= (1 << 2);
+		break;
+	case GUARD_INTERVAL_1_8:
+		buf[0] |= (2 << 2);
+		break;
+	case GUARD_INTERVAL_1_4:
+		buf[0] |= (3 << 2);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (params->hierarchy_information) {
+	case HIERARCHY_AUTO:
+		*auto_mode = 1;
+	case HIERARCHY_NONE:
+		break;
+	case HIERARCHY_1:
+		buf[0] |= (1 << 4);
+		break;
+	case HIERARCHY_2:
+		buf[0] |= (2 << 4);
+		break;
+	case HIERARCHY_4:
+		buf[0] |= (3 << 4);
+		break;
+	default:
+		return -EINVAL;
+	};
+
+	switch (params->constellation) {
+	case QAM_AUTO:
+		*auto_mode = 1;
+	case QPSK:
+		break;
+	case QAM_16:
+		buf[1] |= (1 << 6);
+		break;
+	case QAM_64:
+		buf[1] |= (2 << 6);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* Use HP. How and which case we can switch to LP? */
+	buf[1] |= (1 << 4);
+
+	switch (params->code_rate_HP) {
+	case FEC_AUTO:
+		*auto_mode = 1;
+	case FEC_1_2:
+		break;
+	case FEC_2_3:
+		buf[2] |= (1 << 0);
+		break;
+	case FEC_3_4:
+		buf[2] |= (2 << 0);
+		break;
+	case FEC_5_6:
+		buf[2] |= (3 << 0);
+		break;
+	case FEC_7_8:
+		buf[2] |= (4 << 0);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (params->code_rate_LP) {
+	case FEC_AUTO:
+	/* if HIERARCHY_NONE and FEC_NONE then LP FEC is set to FEC_AUTO
+	   by dvb_frontend.c for compatibility */
+		if (params->hierarchy_information != HIERARCHY_NONE)
+			*auto_mode = 1;
+	case FEC_1_2:
+		break;
+	case FEC_2_3:
+		buf[2] |= (1 << 3);
+		break;
+	case FEC_3_4:
+		buf[2] |= (2 << 3);
+		break;
+	case FEC_5_6:
+		buf[2] |= (3 << 3);
+		break;
+	case FEC_7_8:
+		buf[2] |= (4 << 3);
+		break;
+	case FEC_NONE:
+		if (params->hierarchy_information == HIERARCHY_AUTO)
+			break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (params->bandwidth) {
+	case BANDWIDTH_6_MHZ:
+		break;
+	case BANDWIDTH_7_MHZ:
+		buf[1] |= (1 << 2);
+		break;
+	case BANDWIDTH_8_MHZ:
+		buf[1] |= (2 << 2);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* program */
+	for (i = 0; i < sizeof(buf); i++) {
+		ret = af9013_write_reg(state, 0xd3c0 + i, buf[i]);
+		if (ret)
+			break;
+	}
+
+	return ret;
+}
+
+static int af9013_reset(struct af9013_state *state, u8 sleep)
+{
+	int ret;
+	u8 tmp, i;
+	deb_info("%s\n", __func__);
+
+	/* enable OFDM reset */
+	ret = af9013_write_reg_bits(state, 0xd417, 4, 1, 1);
+	if (ret)
+		goto error;
+
+	/* start reset mechanism */
+	ret = af9013_write_reg(state, 0xaeff, 1);
+	if (ret)
+		goto error;
+
+	/* reset is done when bit 1 is set */
+	for (i = 0; i < 150; i++) {
+		ret = af9013_read_reg_bits(state, 0xd417, 1, 1, &tmp);
+		if (ret)
+			goto error;
+		if (tmp)
+			break; /* reset done */
+		msleep(10);
+	}
+	if (!tmp)
+		return -ETIMEDOUT;
+
+	/* don't clear reset when going to sleep */
+	if (!sleep) {
+		/* clear OFDM reset */
+		ret = af9013_write_reg_bits(state, 0xd417, 1, 1, 0);
+		if (ret)
+			goto error;
+
+		/* disable OFDM reset */
+		ret = af9013_write_reg_bits(state, 0xd417, 4, 1, 0);
+	}
+error:
+	return ret;
+}
+
+static int af9013_power_ctrl(struct af9013_state *state, u8 onoff)
+{
+	int ret;
+	deb_info("%s: onoff:%d\n", __func__, onoff);
+
+	if (onoff) {
+		/* power on */
+		ret = af9013_write_reg_bits(state, 0xd73a, 3, 1, 0);
+		if (ret)
+			goto error;
+		ret = af9013_write_reg_bits(state, 0xd417, 1, 1, 0);
+		if (ret)
+			goto error;
+		ret = af9013_write_reg_bits(state, 0xd417, 4, 1, 0);
+	} else {
+		/* power off */
+		ret = af9013_reset(state, 1);
+		if (ret)
+			goto error;
+		ret = af9013_write_reg_bits(state, 0xd73a, 3, 1, 1);
+	}
+error:
+	return ret;
+}
+
+static int af9013_lock_led(struct af9013_state *state, u8 onoff)
+{
+	deb_info("%s: onoff:%d\n", __func__, onoff);
+
+	return af9013_write_reg_bits(state, 0xd730, 0, 1, onoff);
+}
+
+static int af9013_set_frontend(struct dvb_frontend *fe,
+	struct dvb_frontend_parameters *params)
+{
+	struct af9013_state *state = fe->demodulator_priv;
+	int ret;
+	u8 auto_mode; /* auto set TPS */
+
+	deb_info("%s: freq:%d bw:%d\n", __func__, params->frequency,
+		params->u.ofdm.bandwidth);
+
+	state->frequency = params->frequency;
+
+	/* program CFOE coefficients */
+	ret = af9013_set_coeff(state, params->u.ofdm.bandwidth);
+	if (ret)
+		goto error;
+
+	/* program frequency control */
+	ret = af9013_set_freq_ctrl(state, params->u.ofdm.bandwidth);
+	if (ret)
+		goto error;
+
+	/* clear TPS lock flag (inverted flag) */
+	ret = af9013_write_reg_bits(state, 0xd330, 3, 1, 1);
+	if (ret)
+		goto error;
+
+	/* clear MPEG2 lock flag */
+	ret = af9013_write_reg_bits(state, 0xd507, 6, 1, 0);
+	if (ret)
+		goto error;
+
+	/* empty channel function */
+	ret = af9013_write_reg_bits(state, 0x9bfe, 0, 1, 0);
+	if (ret)
+		goto error;
+
+	/* empty DVB-T channel function */
+	ret = af9013_write_reg_bits(state, 0x9bc2, 0, 1, 0);
+	if (ret)
+		goto error;
+
+	/* program tuner */
+	if (fe->ops.tuner_ops.set_params)
+		fe->ops.tuner_ops.set_params(fe, params);
+
+	/* program TPS and bandwidth, check if auto mode needed */
+	ret = af9013_set_ofdm_params(state, &params->u.ofdm, &auto_mode);
+	if (ret)
+		goto error;
+
+	if (auto_mode) {
+		/* clear easy mode flag */
+		ret = af9013_write_reg(state, 0xaefd, 0);
+		deb_info("%s: auto TPS\n", __func__);
+	} else {
+		/* set easy mode flag */
+		ret = af9013_write_reg(state, 0xaefd, 1);
+		if (ret)
+			goto error;
+		ret = af9013_write_reg(state, 0xaefe, 0);
+		deb_info("%s: manual TPS\n", __func__);
+	}
+	if (ret)
+		goto error;
+
+	/* everything is set, lets try to receive channel - OFSM GO! */
+	ret = af9013_write_reg(state, 0xffff, 0);
+	if (ret)
+		goto error;
+
+error:
+	return ret;
+}
+
+static int af9013_get_frontend(struct dvb_frontend *fe,
+	struct dvb_frontend_parameters *p)
+{
+	struct af9013_state *state = fe->demodulator_priv;
+	int ret;
+	u8 i, buf[3];
+	deb_info("%s\n", __func__);
+
+	/* read TPS registers */
+	for (i = 0; i < 3; i++) {
+		ret = af9013_read_reg(state, 0xd3c0 + i, &buf[i]);
+		if (ret)
+			goto error;
+	}
+
+	switch ((buf[1] >> 6) & 3) {
+	case 0:
+		p->u.ofdm.constellation = QPSK;
+		break;
+	case 1:
+		p->u.ofdm.constellation = QAM_16;
+		break;
+	case 2:
+		p->u.ofdm.constellation = QAM_64;
+		break;
+	}
+
+	switch ((buf[0] >> 0) & 3) {
+	case 0:
+		p->u.ofdm.transmission_mode = TRANSMISSION_MODE_2K;
+		break;
+	case 1:
+		p->u.ofdm.transmission_mode = TRANSMISSION_MODE_8K;
+	}
+
+	switch ((buf[0] >> 2) & 3) {
+	case 0:
+		p->u.ofdm.guard_interval = GUARD_INTERVAL_1_32;
+		break;
+	case 1:
+		p->u.ofdm.guard_interval = GUARD_INTERVAL_1_16;
+		break;
+	case 2:
+		p->u.ofdm.guard_interval = GUARD_INTERVAL_1_8;
+		break;
+	case 3:
+		p->u.ofdm.guard_interval = GUARD_INTERVAL_1_4;
+		break;
+	}
+
+	switch ((buf[0] >> 4) & 7) {
+	case 0:
+		p->u.ofdm.hierarchy_information = HIERARCHY_NONE;
+		break;
+	case 1:
+		p->u.ofdm.hierarchy_information = HIERARCHY_1;
+		break;
+	case 2:
+		p->u.ofdm.hierarchy_information = HIERARCHY_2;
+		break;
+	case 3:
+		p->u.ofdm.hierarchy_information = HIERARCHY_4;
+		break;
+	}
+
+	switch ((buf[2] >> 0) & 7) {
+	case 0:
+		p->u.ofdm.code_rate_HP = FEC_1_2;
+		break;
+	case 1:
+		p->u.ofdm.code_rate_HP = FEC_2_3;
+		break;
+	case 2:
+		p->u.ofdm.code_rate_HP = FEC_3_4;
+		break;
+	case 3:
+		p->u.ofdm.code_rate_HP = FEC_5_6;
+		break;
+	case 4:
+		p->u.ofdm.code_rate_HP = FEC_7_8;
+		break;
+	}
+
+	switch ((buf[2] >> 3) & 7) {
+	case 0:
+		p->u.ofdm.code_rate_LP = FEC_1_2;
+		break;
+	case 1:
+		p->u.ofdm.code_rate_LP = FEC_2_3;
+		break;
+	case 2:
+		p->u.ofdm.code_rate_LP = FEC_3_4;
+		break;
+	case 3:
+		p->u.ofdm.code_rate_LP = FEC_5_6;
+		break;
+	case 4:
+		p->u.ofdm.code_rate_LP = FEC_7_8;
+		break;
+	}
+
+	switch ((buf[1] >> 2) & 3) {
+	case 0:
+		p->u.ofdm.bandwidth = BANDWIDTH_6_MHZ;
+		break;
+	case 1:
+		p->u.ofdm.bandwidth = BANDWIDTH_7_MHZ;
+		break;
+	case 2:
+		p->u.ofdm.bandwidth = BANDWIDTH_8_MHZ;
+		break;
+	}
+
+	p->inversion = INVERSION_AUTO;
+	p->frequency = state->frequency;
+
+error:
+	return ret;
+}
+
+static int af9013_update_ber_unc(struct dvb_frontend *fe)
+{
+	struct af9013_state *state = fe->demodulator_priv;
+	int ret;
+	u8 buf[3], i;
+	u32 error_bit_count = 0;
+	u32 total_bit_count = 0;
+	u32 abort_packet_count = 0;
+
+	state->ber = 0;
+
+	/* check if error bit count is ready */
+	ret = af9013_read_reg_bits(state, 0xd391, 4, 1, &buf[0]);
+	if (ret)
+		goto error;
+	if (!buf[0])
+		goto exit;
+
+	/* get RSD packet abort count */
+	for (i = 0; i < 2; i++) {
+		ret = af9013_read_reg(state, 0xd38a + i, &buf[i]);
+		if (ret)
+			goto error;
+	}
+	abort_packet_count = (buf[1] << 8) + buf[0];
+
+	/* get error bit count */
+	for (i = 0; i < 3; i++) {
+		ret = af9013_read_reg(state, 0xd387 + i, &buf[i]);
+		if (ret)
+			goto error;
+	}
+	error_bit_count = (buf[2] << 16) + (buf[1] << 8) + buf[0];
+	error_bit_count = error_bit_count - abort_packet_count * 8 * 8;
+
+	/* get used RSD counting period (10000 RSD packets used) */
+	for (i = 0; i < 2; i++) {
+		ret = af9013_read_reg(state, 0xd385 + i, &buf[i]);
+		if (ret)
+			goto error;
+	}
+	total_bit_count = (buf[1] << 8) + buf[0];
+	total_bit_count = total_bit_count - abort_packet_count;
+	total_bit_count = total_bit_count * 204 * 8;
+
+	if (total_bit_count)
+		state->ber = error_bit_count * 1000000000 / total_bit_count;
+
+	state->ucblocks += abort_packet_count;
+
+	deb_info("%s: err bits:%d total bits:%d abort count:%d\n", __func__,
+		error_bit_count, total_bit_count, abort_packet_count);
+
+	/* set BER counting range */
+	ret = af9013_write_reg(state, 0xd385, 10000 & 0xff);
+	if (ret)
+		goto error;
+	ret = af9013_write_reg(state, 0xd386, 10000 >> 8);
+	if (ret)
+		goto error;
+	/* reset and start BER counter */
+	ret = af9013_write_reg_bits(state, 0xd391, 4, 1, 1);
+	if (ret)
+		goto error;
+
+exit:
+error:
+	return ret;
+}
+
+static int af9013_update_snr(struct dvb_frontend *fe)
+{
+	struct af9013_state *state = fe->demodulator_priv;
+	int ret;
+	u8 buf[3], i, len;
+	u32 quant = 0;
+	struct snr_table *snr_table;
+
+	/* check if quantizer ready (for snr) */
+	ret = af9013_read_reg_bits(state, 0xd2e1, 3, 1, &buf[0]);
+	if (ret)
+		goto error;
+	if (buf[0]) {
+		/* quantizer ready - read it */
+		for (i = 0; i < 3; i++) {
+			ret = af9013_read_reg(state, 0xd2e3 + i, &buf[i]);
+			if (ret)
+				goto error;
+		}
+		quant = (buf[2] << 16) + (buf[1] << 8) + buf[0];
+
+		/* read current constellation */
+		ret = af9013_read_reg(state, 0xd3c1, &buf[0]);
+		if (ret)
+			goto error;
+
+		switch ((buf[0] >> 6) & 3) {
+		case 0:
+			len = ARRAY_SIZE(qpsk_snr_table);
+			snr_table = qpsk_snr_table;
+			break;
+		case 1:
+			len = ARRAY_SIZE(qam16_snr_table);
+			snr_table = qam16_snr_table;
+			break;
+		case 2:
+			len = ARRAY_SIZE(qam64_snr_table);
+			snr_table = qam64_snr_table;
+			break;
+		default:
+			len = 0;
+			break;
+		}
+
+		if (len) {
+			for (i = 0; i < len; i++) {
+				if (quant < snr_table[i].val) {
+					state->snr = snr_table[i].snr * 10;
+					break;
+				}
+			}
+		}
+
+		/* set quantizer super frame count */
+		ret = af9013_write_reg(state, 0xd2e2, 1);
+		if (ret)
+			goto error;
+
+		/* check quantizer availability */
+		for (i = 0; i < 10; i++) {
+			msleep(10);
+			ret = af9013_read_reg_bits(state, 0xd2e6, 0, 1,
+				&buf[0]);
+			if (ret)
+				goto error;
+			if (!buf[0])
+				break;
+		}
+
+		/* reset quantizer */
+		ret = af9013_write_reg_bits(state, 0xd2e1, 3, 1, 1);
+		if (ret)
+			goto error;
+	}
+
+error:
+	return ret;
+}
+
+static int af9013_update_signal_strength(struct dvb_frontend *fe)
+{
+	struct af9013_state *state = fe->demodulator_priv;
+	int ret;
+	u8 tmp0;
+	u8 rf_gain, rf_50, rf_80, if_gain, if_50, if_80;
+	int signal_strength;
+
+	deb_info("%s\n", __func__);
+
+	state->signal_strength = 0;
+
+	ret = af9013_read_reg_bits(state, 0x9bee, 0, 1, &tmp0);
+	if (ret)
+		goto error;
+	if (tmp0) {
+		ret = af9013_read_reg(state, 0x9bbd, &rf_50);
+		if (ret)
+			goto error;
+		ret = af9013_read_reg(state, 0x9bd0, &rf_80);
+		if (ret)
+			goto error;
+		ret = af9013_read_reg(state, 0x9be2, &if_50);
+		if (ret)
+			goto error;
+		ret = af9013_read_reg(state, 0x9be4, &if_80);
+		if (ret)
+			goto error;
+		ret = af9013_read_reg(state, 0xd07c, &rf_gain);
+		if (ret)
+			goto error;
+		ret = af9013_read_reg(state, 0xd07d, &if_gain);
+		if (ret)
+			goto error;
+		signal_strength = (0xffff / (9 * (rf_50 + if_50) - \
+			11 * (rf_80 + if_80))) * (10 * (rf_gain + if_gain) - \
+			11 * (rf_80 + if_80));
+		if (signal_strength < 0)
+			signal_strength = 0;
+		else if (signal_strength > 0xffff)
+			signal_strength = 0xffff;
+
+		state->signal_strength = signal_strength;
+	}
+
+error:
+	return ret;
+}
+
+static int af9013_update_statistics(struct dvb_frontend *fe)
+{
+	struct af9013_state *state = fe->demodulator_priv;
+	int ret;
+
+	if (time_before(jiffies, state->next_statistics_check))
+		return 0;
+
+	/* set minimum statistic update interval */
+	state->next_statistics_check = jiffies + msecs_to_jiffies(1200);
+
+	ret = af9013_update_signal_strength(fe);
+	if (ret)
+		goto error;
+	ret = af9013_update_snr(fe);
+	if (ret)
+		goto error;
+	ret = af9013_update_ber_unc(fe);
+	if (ret)
+		goto error;
+
+error:
+	return ret;
+}
+
+static int af9013_get_tune_settings(struct dvb_frontend *fe,
+	struct dvb_frontend_tune_settings *fesettings)
+{
+	fesettings->min_delay_ms = 800;
+	fesettings->step_size = 0;
+	fesettings->max_drift = 0;
+
+	return 0;
+}
+
+static int af9013_read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+	struct af9013_state *state = fe->demodulator_priv;
+	int ret = 0;
+	u8 tmp;
+	*status = 0;
+
+	/* TPS lock */
+	ret = af9013_read_reg_bits(state, 0xd330, 3, 1, &tmp);
+	if (ret)
+		goto error;
+	if (tmp)
+		*status |= FE_HAS_VITERBI | FE_HAS_CARRIER | FE_HAS_SIGNAL;
+
+	/* MPEG2 lock */
+	ret = af9013_read_reg_bits(state, 0xd507, 6, 1, &tmp);
+	if (ret)
+		goto error;
+	if (tmp)
+		*status |= FE_HAS_SYNC | FE_HAS_LOCK;
+
+	if (!*status & FE_HAS_SIGNAL) {
+		/* AGC lock */
+		ret = af9013_read_reg_bits(state, 0xd1a0, 6, 1, &tmp);
+		if (ret)
+			goto error;
+		if (tmp)
+			*status |= FE_HAS_SIGNAL;
+	}
+
+	if (!*status & FE_HAS_CARRIER) {
+		/* CFO lock */
+		ret = af9013_read_reg_bits(state, 0xd333, 7, 1, &tmp);
+		if (ret)
+			goto error;
+		if (tmp)
+			*status |= FE_HAS_CARRIER;
+	}
+
+	if (!*status & FE_HAS_CARRIER) {
+		/* SFOE lock */
+		ret = af9013_read_reg_bits(state, 0xd334, 6, 1, &tmp);
+		if (ret)
+			goto error;
+		if (tmp)
+			*status |= FE_HAS_CARRIER;
+	}
+
+	ret = af9013_update_statistics(fe);
+
+error:
+	return ret;
+}
+
+
+static int af9013_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+	struct af9013_state *state = fe->demodulator_priv;
+	int ret;
+	ret = af9013_update_statistics(fe);
+	*ber = state->ber;
+	return ret;
+}
+
+static int af9013_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
+{
+	struct af9013_state *state = fe->demodulator_priv;
+	int ret;
+	ret = af9013_update_statistics(fe);
+	*strength = state->signal_strength;
+	return ret;
+}
+
+static int af9013_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+	struct af9013_state *state = fe->demodulator_priv;
+	int ret;
+	ret = af9013_update_statistics(fe);
+	*snr = state->snr;
+	return ret;
+}
+
+static int af9013_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
+{
+	struct af9013_state *state = fe->demodulator_priv;
+	int ret;
+	ret = af9013_update_statistics(fe);
+	*ucblocks = state->ucblocks;
+	return ret;
+}
+
+static int af9013_sleep(struct dvb_frontend *fe)
+{
+	struct af9013_state *state = fe->demodulator_priv;
+	int ret;
+	deb_info("%s\n", __func__);
+
+	ret = af9013_lock_led(state, 0);
+	if (ret)
+		goto error;
+
+	ret = af9013_power_ctrl(state, 0);
+error:
+	return ret;
+}
+
+static int af9013_init(struct dvb_frontend *fe)
+{
+	struct af9013_state *state = fe->demodulator_priv;
+	int ret, i, len;
+	u8 tmp0, tmp1;
+	struct regdesc *init;
+	deb_info("%s\n", __func__);
+
+	/* reset OFDM */
+	ret = af9013_reset(state, 0);
+	if (ret)
+		goto error;
+
+	/* power on */
+	ret = af9013_power_ctrl(state, 1);
+	if (ret)
+		goto error;
+
+	/* enable ADC */
+	ret = af9013_write_reg(state, 0xd73a, 0xa4);
+	if (ret)
+		goto error;
+
+	/* write API version to firmware */
+	for (i = 0; i < sizeof(state->config.api_version); i++) {
+		ret = af9013_write_reg(state, 0x9bf2 + i,
+			state->config.api_version[i]);
+		if (ret)
+			goto error;
+	}
+
+	/* program ADC control */
+	ret = af9013_set_adc_ctrl(state);
+	if (ret)
+		goto error;
+
+	/* set I2C master clock */
+	ret = af9013_write_reg(state, 0xd416, 0x14);
+	if (ret)
+		goto error;
+
+	/* set 16 embx */
+	ret = af9013_write_reg_bits(state, 0xd700, 1, 1, 1);
+	if (ret)
+		goto error;
+
+	/* set no trigger */
+	ret = af9013_write_reg_bits(state, 0xd700, 2, 1, 0);
+	if (ret)
+		goto error;
+
+	/* set read-update bit for constellation */
+	ret = af9013_write_reg_bits(state, 0xd371, 1, 1, 1);
+	if (ret)
+		goto error;
+
+	/* enable FEC monitor */
+	ret = af9013_write_reg_bits(state, 0xd392, 1, 1, 1);
+	if (ret)
+		goto error;
+
+	/* load OFSM settings */
+	deb_info("%s: load ofsm settings\n", __func__);
+	len = ARRAY_SIZE(ofsm_init);
+	init = ofsm_init;
+	for (i = 0; i < len; i++) {
+		ret = af9013_write_reg_bits(state, init[i].addr, init[i].pos,
+			init[i].len, init[i].val);
+		if (ret)
+			goto error;
+	}
+
+	/* load tuner specific settings */
+	deb_info("%s: load tuner specific settings\n", __func__);
+	switch (state->config.tuner) {
+	case AF9013_TUNER_MXL5003D:
+		len = ARRAY_SIZE(tuner_init_mxl5003d);
+		init = tuner_init_mxl5003d;
+		break;
+	case AF9013_TUNER_MXL5005D:
+	case AF9013_TUNER_MXL5005R:
+		len = ARRAY_SIZE(tuner_init_mxl5005);
+		init = tuner_init_mxl5005;
+		break;
+	case AF9013_TUNER_ENV77H11D5:
+		len = ARRAY_SIZE(tuner_init_env77h11d5);
+		init = tuner_init_env77h11d5;
+		break;
+	case AF9013_TUNER_MT2060:
+		len = ARRAY_SIZE(tuner_init_mt2060);
+		init = tuner_init_mt2060;
+		break;
+	case AF9013_TUNER_MC44S803:
+		len = ARRAY_SIZE(tuner_init_mc44s803);
+		init = tuner_init_mc44s803;
+		break;
+	case AF9013_TUNER_QT1010:
+	case AF9013_TUNER_QT1010A:
+		len = ARRAY_SIZE(tuner_init_qt1010);
+		init = tuner_init_qt1010;
+		break;
+	case AF9013_TUNER_MT2060_2:
+		len = ARRAY_SIZE(tuner_init_mt2060_2);
+		init = tuner_init_mt2060_2;
+		break;
+	case AF9013_TUNER_TDA18271:
+		len = ARRAY_SIZE(tuner_init_tda18271);
+		init = tuner_init_tda18271;
+		break;
+	case AF9013_TUNER_UNKNOWN:
+	default:
+		len = ARRAY_SIZE(tuner_init_unknown);
+		init = tuner_init_unknown;
+		break;
+	}
+
+	for (i = 0; i < len; i++) {
+		ret = af9013_write_reg_bits(state, init[i].addr, init[i].pos,
+			init[i].len, init[i].val);
+		if (ret)
+			goto error;
+	}
+
+	/* set TS mode */
+	deb_info("%s: setting ts mode\n", __func__);
+	tmp0 = 0; /* parallel mode */
+	tmp1 = 0; /* serial mode */
+	switch (state->config.output_mode) {
+	case AF9013_OUTPUT_MODE_PARALLEL:
+		tmp0 = 1;
+		break;
+	case AF9013_OUTPUT_MODE_SERIAL:
+		tmp1 = 1;
+		break;
+	case AF9013_OUTPUT_MODE_USB:
+		/* usb mode for AF9015 */
+	default:
+		break;
+	}
+	ret = af9013_write_reg_bits(state, 0xd500, 1, 1, tmp0); /* parallel */
+	if (ret)
+		goto error;
+	ret = af9013_write_reg_bits(state, 0xd500, 2, 1, tmp1); /* serial */
+	if (ret)
+		goto error;
+
+	/* enable lock led */
+	ret = af9013_lock_led(state, 1);
+	if (ret)
+		goto error;
+
+error:
+	return ret;
+}
+
+static struct dvb_frontend_ops af9013_ops;
+
+static int af9013_download_firmware(struct af9013_state *state)
+{
+	int i, len, packets, remainder, ret;
+	const struct firmware *fw;
+	u16 addr = 0x5100; /* firmware start address */
+	u16 checksum = 0;
+	u8 val;
+	u8 fw_params[4];
+	u8 *data;
+	u8 *fw_file = AF9013_DEFAULT_FIRMWARE;
+
+	msleep(100);
+	/* check whether firmware is already running */
+	ret = af9013_read_reg(state, 0x98be, &val);
+	if (ret)
+		goto error;
+	else
+		deb_info("%s: firmware status:%02x\n", __func__, val);
+
+	if (val == 0x0c) /* fw is running, no need for download */
+		goto exit;
+
+	info("found a '%s' in cold state, will try to load a firmware",
+		af9013_ops.info.name);
+
+	/* request the firmware, this will block and timeout */
+	ret = request_firmware(&fw, fw_file,  &state->i2c->dev);
+	if (ret) {
+		err("did not find the firmware file. (%s) "
+			"Please see linux/Documentation/dvb/ for more details" \
+			" on firmware-problems. (%d)",
+			fw_file, ret);
+		goto error;
+	}
+
+	info("downloading firmware from file '%s'", fw_file);
+
+	/* calc checksum */
+	for (i = 0; i < fw->size; i++)
+		checksum += fw->data[i];
+
+	fw_params[0] = checksum >> 8;
+	fw_params[1] = checksum & 0xff;
+	fw_params[2] = fw->size >> 8;
+	fw_params[3] = fw->size & 0xff;
+
+	/* write fw checksum & size */
+	ret = af9013_write_ofsm_regs(state, 0x50fc,
+		fw_params, sizeof(fw_params));
+	if (ret)
+		goto error_release;
+
+	#define FW_PACKET_MAX_DATA  16
+
+	packets = fw->size / FW_PACKET_MAX_DATA;
+	remainder = fw->size % FW_PACKET_MAX_DATA;
+	len = FW_PACKET_MAX_DATA;
+	for (i = 0; i <= packets; i++) {
+		if (i == packets)  /* set size of the last packet */
+			len = remainder;
+
+		data = (u8 *)(fw->data + i * FW_PACKET_MAX_DATA);
+		ret = af9013_write_ofsm_regs(state, addr, data, len);
+		addr += FW_PACKET_MAX_DATA;
+
+		if (ret) {
+			err("firmware download failed at %d with %d", i, ret);
+			goto error_release;
+		}
+	}
+
+	/* request boot firmware */
+	ret = af9013_write_reg(state, 0xe205, 1);
+	if (ret)
+		goto error_release;
+
+	for (i = 0; i < 15; i++) {
+		msleep(100);
+
+		/* check firmware status */
+		ret = af9013_read_reg(state, 0x98be, &val);
+		if (ret)
+			goto error_release;
+
+		deb_info("%s: firmware status:%02x\n", __func__, val);
+
+		if (val == 0x0c || val == 0x04) /* success or fail */
+			break;
+	}
+
+	if (val == 0x04) {
+		err("firmware did not run");
+		ret = -1;
+	} else if (val != 0x0c) {
+		err("firmware boot timeout");
+		ret = -1;
+	}
+
+error_release:
+	release_firmware(fw);
+error:
+exit:
+	if (!ret)
+		info("found a '%s' in warm state.", af9013_ops.info.name);
+	return ret;
+}
+
+static int af9013_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
+{
+	int ret;
+	struct af9013_state *state = fe->demodulator_priv;
+	deb_info("%s: enable:%d\n", __func__, enable);
+
+	if (state->config.output_mode == AF9013_OUTPUT_MODE_USB)
+		ret = af9013_write_reg_bits(state, 0xd417, 3, 1, enable);
+	else
+		ret = af9013_write_reg_bits(state, 0xd607, 2, 1, enable);
+
+	return ret;
+}
+
+static void af9013_release(struct dvb_frontend *fe)
+{
+	struct af9013_state *state = fe->demodulator_priv;
+	kfree(state);
+}
+
+static struct dvb_frontend_ops af9013_ops;
+
+struct dvb_frontend *af9013_attach(const struct af9013_config *config,
+	struct i2c_adapter *i2c)
+{
+	int ret;
+	struct af9013_state *state = NULL;
+	u8 buf[3], i;
+
+	/* allocate memory for the internal state */
+	state = kzalloc(sizeof(struct af9013_state), GFP_KERNEL);
+	if (state == NULL)
+		goto error;
+
+	/* setup the state */
+	state->i2c = i2c;
+	memcpy(&state->config, config, sizeof(struct af9013_config));
+
+	/* chip version */
+	ret = af9013_read_reg_bits(state, 0xd733, 4, 4, &buf[2]);
+	if (ret)
+		goto error;
+
+	/* ROM version */
+	for (i = 0; i < 2; i++) {
+		ret = af9013_read_reg(state, 0x116b + i, &buf[i]);
+		if (ret)
+			goto error;
+	}
+	deb_info("%s: chip version:%d ROM version:%d.%d\n", __func__,
+		buf[2], buf[0], buf[1]);
+
+	/* download firmware */
+	if (state->config.output_mode != AF9013_OUTPUT_MODE_USB) {
+		ret = af9013_download_firmware(state);
+		if (ret)
+			goto error;
+	}
+
+	/* firmware version */
+	for (i = 0; i < 3; i++) {
+		ret = af9013_read_reg(state, 0x5103 + i, &buf[i]);
+		if (ret)
+			goto error;
+	}
+	info("firmware version:%d.%d.%d", buf[0], buf[1], buf[2]);
+
+	/* settings for mp2if */
+	if (state->config.output_mode == AF9013_OUTPUT_MODE_USB) {
+		/* AF9015 split PSB to 1.5k + 0.5k */
+		ret = af9013_write_reg_bits(state, 0xd50b, 2, 1, 1);
+	} else {
+		/* AF9013 change the output bit to data7 */
+		ret = af9013_write_reg_bits(state, 0xd500, 3, 1, 1);
+		if (ret)
+			goto error;
+		/* AF9013 set mpeg to full speed */
+		ret = af9013_write_reg_bits(state, 0xd502, 4, 1, 1);
+	}
+	if (ret)
+		goto error;
+	ret = af9013_write_reg_bits(state, 0xd520, 4, 1, 1);
+	if (ret)
+		goto error;
+
+	/* set GPIOs */
+	for (i = 0; i < sizeof(state->config.gpio); i++) {
+		ret = af9013_set_gpio(state, i, state->config.gpio[i]);
+		if (ret)
+			goto error;
+	}
+
+	/* create dvb_frontend */
+	memcpy(&state->frontend.ops, &af9013_ops,
+		sizeof(struct dvb_frontend_ops));
+	state->frontend.demodulator_priv = state;
+
+	return &state->frontend;
+error:
+	kfree(state);
+	return NULL;
+}
+EXPORT_SYMBOL(af9013_attach);
+
+static struct dvb_frontend_ops af9013_ops = {
+	.info = {
+		.name = "Afatech AF9013 DVB-T",
+		.type = FE_OFDM,
+		.frequency_min = 174000000,
+		.frequency_max = 862000000,
+		.frequency_stepsize = 250000,
+		.frequency_tolerance = 0,
+		.caps =
+			FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+			FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
+			FE_CAN_QPSK | FE_CAN_QAM_16 |
+			FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
+			FE_CAN_TRANSMISSION_MODE_AUTO |
+			FE_CAN_GUARD_INTERVAL_AUTO |
+			FE_CAN_HIERARCHY_AUTO |
+			FE_CAN_RECOVER |
+			FE_CAN_MUTE_TS
+	},
+
+	.release = af9013_release,
+	.init = af9013_init,
+	.sleep = af9013_sleep,
+	.i2c_gate_ctrl = af9013_i2c_gate_ctrl,
+
+	.set_frontend = af9013_set_frontend,
+	.get_frontend = af9013_get_frontend,
+
+	.get_tune_settings = af9013_get_tune_settings,
+
+	.read_status = af9013_read_status,
+	.read_ber = af9013_read_ber,
+	.read_signal_strength = af9013_read_signal_strength,
+	.read_snr = af9013_read_snr,
+	.read_ucblocks = af9013_read_ucblocks,
+};
+
+module_param_named(debug, af9013_debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
+
+MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
+MODULE_DESCRIPTION("Afatech AF9013 DVB-T demodulator driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/af9013.h b/drivers/media/dvb/frontends/af9013.h
new file mode 100644
index 0000000..28b90c9
--- /dev/null
+++ b/drivers/media/dvb/frontends/af9013.h
@@ -0,0 +1,107 @@
+/*
+ * DVB USB Linux driver for Afatech AF9015 DVB-T USB2.0 receiver
+ *
+ * Copyright (C) 2007 Antti Palosaari <crope@iki.fi>
+ *
+ * Thanks to Afatech who kindly provided information.
+ *
+ *    This program is free software; you can redistribute it and/or 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 _AF9013_H_
+#define _AF9013_H_
+
+#include <linux/dvb/frontend.h>
+
+enum af9013_ts_mode {
+	AF9013_OUTPUT_MODE_PARALLEL,
+	AF9013_OUTPUT_MODE_SERIAL,
+	AF9013_OUTPUT_MODE_USB, /* only for AF9015 */
+};
+
+enum af9013_tuner {
+	AF9013_TUNER_MXL5003D   =   3, /* MaxLinear */
+	AF9013_TUNER_MXL5005D   =  13, /* MaxLinear */
+	AF9013_TUNER_MXL5005R   =  30, /* MaxLinear */
+	AF9013_TUNER_ENV77H11D5 = 129, /* Panasonic */
+	AF9013_TUNER_MT2060     = 130, /* Microtune */
+	AF9013_TUNER_MC44S803   = 133, /* Freescale */
+	AF9013_TUNER_QT1010     = 134, /* Quantek */
+	AF9013_TUNER_UNKNOWN    = 140, /* for can tuners ? */
+	AF9013_TUNER_MT2060_2   = 147, /* Microtune */
+	AF9013_TUNER_TDA18271   = 156, /* NXP */
+	AF9013_TUNER_QT1010A    = 162, /* Quantek */
+};
+
+/* AF9013/5 GPIOs (mostly guessed)
+   demod#1-gpio#0 - set demod#2 i2c-addr for dual devices
+   demod#1-gpio#1 - xtal setting (?)
+   demod#1-gpio#3 - tuner#1
+   demod#2-gpio#0 - tuner#2
+   demod#2-gpio#1 - xtal setting (?)
+*/
+#define AF9013_GPIO_ON (1 << 0)
+#define AF9013_GPIO_EN (1 << 1)
+#define AF9013_GPIO_O  (1 << 2)
+#define AF9013_GPIO_I  (1 << 3)
+
+#define AF9013_GPIO_LO (AF9013_GPIO_ON|AF9013_GPIO_EN)
+#define AF9013_GPIO_HI (AF9013_GPIO_ON|AF9013_GPIO_EN|AF9013_GPIO_O)
+
+#define AF9013_GPIO_TUNER_ON  (AF9013_GPIO_ON|AF9013_GPIO_EN)
+#define AF9013_GPIO_TUNER_OFF (AF9013_GPIO_ON|AF9013_GPIO_EN|AF9013_GPIO_O)
+
+struct af9013_config {
+	/* demodulator's I2C address */
+	u8 demod_address;
+
+	/* frequencies in kHz */
+	u32 adc_clock;
+
+	/* tuner ID */
+	u8 tuner;
+
+	/* tuner IF */
+	u16 tuner_if;
+
+	/* TS data output mode */
+	u8 output_mode:2;
+
+	/* RF spectrum inversion */
+	u8 rf_spec_inv:1;
+
+	/* API version */
+	u8 api_version[4];
+
+	/* GPIOs */
+	u8 gpio[4];
+};
+
+
+#if defined(CONFIG_DVB_AF9013) || \
+	(defined(CONFIG_DVB_AF9013_MODULE) && defined(MODULE))
+extern struct dvb_frontend *af9013_attach(const struct af9013_config *config,
+	struct i2c_adapter *i2c);
+#else
+static inline struct dvb_frontend *af9013_attach(
+const struct af9013_config *config, struct i2c_adapter *i2c)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+#endif /* CONFIG_DVB_AF9013 */
+
+#endif /* _AF9013_H_ */
diff --git a/drivers/media/dvb/frontends/af9013_priv.h b/drivers/media/dvb/frontends/af9013_priv.h
new file mode 100644
index 0000000..163e251
--- /dev/null
+++ b/drivers/media/dvb/frontends/af9013_priv.h
@@ -0,0 +1,869 @@
+/*
+ * DVB USB Linux driver for Afatech AF9015 DVB-T USB2.0 receiver
+ *
+ * Copyright (C) 2007 Antti Palosaari <crope@iki.fi>
+ *
+ * Thanks to Afatech who kindly provided information.
+ *
+ *    This program is free software; you can redistribute it and/or 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 _AF9013_PRIV_
+#define _AF9013_PRIV_
+
+#define LOG_PREFIX "af9013"
+extern int af9013_debug;
+
+#define dprintk(var, level, args...) \
+	    do { if ((var & level)) printk(args); } while (0)
+
+#define debug_dump(b, l, func) {\
+	int loop_; \
+	for (loop_ = 0; loop_ < l; loop_++) \
+		func("%02x ", b[loop_]); \
+	func("\n");\
+}
+
+#define deb_info(args...) dprintk(af9013_debug, 0x01, args)
+
+#undef err
+#define err(f, arg...)  printk(KERN_ERR     LOG_PREFIX": " f "\n" , ## arg)
+#undef info
+#define info(f, arg...) printk(KERN_INFO    LOG_PREFIX": " f "\n" , ## arg)
+#undef warn
+#define warn(f, arg...) printk(KERN_WARNING LOG_PREFIX": " f "\n" , ## arg)
+
+#define AF9013_DEFAULT_FIRMWARE     "dvb-fe-af9013.fw"
+
+struct regdesc {
+	u16 addr;
+	u8  pos:4;
+	u8  len:4;
+	u8  val;
+};
+
+struct snr_table {
+	u32 val;
+	u8 snr;
+};
+
+/* QPSK SNR lookup table */
+static struct snr_table qpsk_snr_table[] = {
+	{ 0x0b4771,  0 },
+	{ 0x0c1aed,  1 },
+	{ 0x0d0d27,  2 },
+	{ 0x0e4d19,  3 },
+	{ 0x0e5da8,  4 },
+	{ 0x107097,  5 },
+	{ 0x116975,  6 },
+	{ 0x1252d9,  7 },
+	{ 0x131fa4,  8 },
+	{ 0x13d5e1,  9 },
+	{ 0x148e53, 10 },
+	{ 0x15358b, 11 },
+	{ 0x15dd29, 12 },
+	{ 0x168112, 13 },
+	{ 0x170b61, 14 },
+	{ 0xffffff, 15 },
+};
+
+/* QAM16 SNR lookup table */
+static struct snr_table qam16_snr_table[] = {
+	{ 0x05eb62,  5 },
+	{ 0x05fecf,  6 },
+	{ 0x060b80,  7 },
+	{ 0x062501,  8 },
+	{ 0x064865,  9 },
+	{ 0x069604, 10 },
+	{ 0x06f356, 11 },
+	{ 0x07706a, 12 },
+	{ 0x0804d3, 13 },
+	{ 0x089d1a, 14 },
+	{ 0x093e3d, 15 },
+	{ 0x09e35d, 16 },
+	{ 0x0a7c3c, 17 },
+	{ 0x0afaf8, 18 },
+	{ 0x0b719d, 19 },
+	{ 0xffffff, 20 },
+};
+
+/* QAM64 SNR lookup table */
+static struct snr_table qam64_snr_table[] = {
+	{ 0x03109b, 12 },
+	{ 0x0310d4, 13 },
+	{ 0x031920, 14 },
+	{ 0x0322d0, 15 },
+	{ 0x0339fc, 16 },
+	{ 0x0364a1, 17 },
+	{ 0x038bcc, 18 },
+	{ 0x03c7d3, 19 },
+	{ 0x0408cc, 20 },
+	{ 0x043bed, 21 },
+	{ 0x048061, 22 },
+	{ 0x04be95, 23 },
+	{ 0x04fa7d, 24 },
+	{ 0x052405, 25 },
+	{ 0x05570d, 26 },
+	{ 0xffffff, 27 },
+};
+
+static struct regdesc ofsm_init[] = {
+	{ 0xd73a, 0, 8, 0xa1 },
+	{ 0xd73b, 0, 8, 0x1f },
+	{ 0xd73c, 4, 4, 0x0a },
+	{ 0xd732, 3, 1, 0x00 },
+	{ 0xd731, 4, 2, 0x03 },
+	{ 0xd73d, 7, 1, 0x01 },
+	{ 0xd740, 0, 1, 0x00 },
+	{ 0xd740, 1, 1, 0x00 },
+	{ 0xd740, 2, 1, 0x00 },
+	{ 0xd740, 3, 1, 0x01 },
+	{ 0xd3c1, 4, 1, 0x01 },
+	{ 0xd3a2, 0, 8, 0x00 },
+	{ 0xd3a3, 0, 8, 0x04 },
+	{ 0xd305, 0, 8, 0x32 },
+	{ 0xd306, 0, 8, 0x10 },
+	{ 0xd304, 0, 8, 0x04 },
+	{ 0x9112, 0, 1, 0x01 },
+	{ 0x911d, 0, 1, 0x01 },
+	{ 0x911a, 0, 1, 0x01 },
+	{ 0x911b, 0, 1, 0x01 },
+	{ 0x9bce, 0, 4, 0x02 },
+	{ 0x9116, 0, 1, 0x01 },
+	{ 0x9bd1, 0, 1, 0x01 },
+	{ 0xd2e0, 0, 8, 0xd0 },
+	{ 0xd2e9, 0, 4, 0x0d },
+	{ 0xd38c, 0, 8, 0xfc },
+	{ 0xd38d, 0, 8, 0x00 },
+	{ 0xd38e, 0, 8, 0x7e },
+	{ 0xd38f, 0, 8, 0x00 },
+	{ 0xd390, 0, 8, 0x2f },
+	{ 0xd145, 4, 1, 0x01 },
+	{ 0xd1a9, 4, 1, 0x01 },
+	{ 0xd158, 5, 3, 0x01 },
+	{ 0xd159, 0, 6, 0x06 },
+	{ 0xd167, 0, 8, 0x00 },
+	{ 0xd168, 0, 4, 0x07 },
+	{ 0xd1c3, 5, 3, 0x00 },
+	{ 0xd1c4, 0, 6, 0x00 },
+	{ 0xd1c5, 0, 7, 0x10 },
+	{ 0xd1c6, 0, 3, 0x02 },
+	{ 0xd080, 2, 5, 0x03 },
+	{ 0xd081, 4, 4, 0x09 },
+	{ 0xd098, 4, 4, 0x0f },
+	{ 0xd098, 0, 4, 0x03 },
+	{ 0xdbc0, 3, 1, 0x01 },
+	{ 0xdbc0, 4, 1, 0x01 },
+	{ 0xdbc7, 0, 8, 0x08 },
+	{ 0xdbc8, 4, 4, 0x00 },
+	{ 0xdbc9, 0, 5, 0x01 },
+	{ 0xd280, 0, 8, 0xe0 },
+	{ 0xd281, 0, 8, 0xff },
+	{ 0xd282, 0, 8, 0xff },
+	{ 0xd283, 0, 8, 0xc3 },
+	{ 0xd284, 0, 8, 0xff },
+	{ 0xd285, 0, 4, 0x01 },
+	{ 0xd0f0, 0, 7, 0x1a },
+	{ 0xd0f1, 4, 1, 0x01 },
+	{ 0xd0f2, 0, 8, 0x0c },
+	{ 0xd103, 0, 4, 0x08 },
+	{ 0xd0f8, 0, 7, 0x20 },
+	{ 0xd111, 5, 1, 0x00 },
+	{ 0xd111, 6, 1, 0x00 },
+	{ 0x910b, 0, 8, 0x0a },
+	{ 0x9115, 0, 8, 0x02 },
+	{ 0x910c, 0, 8, 0x02 },
+	{ 0x910d, 0, 8, 0x08 },
+	{ 0x910e, 0, 8, 0x0a },
+	{ 0x9bf6, 0, 8, 0x06 },
+	{ 0x9bf8, 0, 8, 0x02 },
+	{ 0x9bf7, 0, 8, 0x05 },
+	{ 0x9bf9, 0, 8, 0x0f },
+	{ 0x9bfc, 0, 8, 0x13 },
+	{ 0x9bd3, 0, 8, 0xff },
+	{ 0x9bbe, 0, 1, 0x01 },
+	{ 0x9bcc, 0, 1, 0x01 },
+};
+
+/* Panasonic ENV77H11D5 tuner init
+   AF9013_TUNER_ENV77H11D5 = 129 */
+static struct regdesc tuner_init_env77h11d5[] = {
+	{ 0x9bd5, 0, 8, 0x01 },
+	{ 0x9bd6, 0, 8, 0x03 },
+	{ 0x9bbe, 0, 8, 0x01 },
+	{ 0xd1a0, 1, 1, 0x01 },
+	{ 0xd000, 0, 1, 0x01 },
+	{ 0xd000, 1, 1, 0x00 },
+	{ 0xd001, 1, 1, 0x01 },
+	{ 0xd001, 0, 1, 0x00 },
+	{ 0xd001, 5, 1, 0x00 },
+	{ 0xd002, 0, 5, 0x19 },
+	{ 0xd003, 0, 5, 0x1a },
+	{ 0xd004, 0, 5, 0x19 },
+	{ 0xd005, 0, 5, 0x1a },
+	{ 0xd00e, 0, 5, 0x10 },
+	{ 0xd00f, 0, 3, 0x04 },
+	{ 0xd00f, 3, 3, 0x05 },
+	{ 0xd010, 0, 3, 0x04 },
+	{ 0xd010, 3, 3, 0x05 },
+	{ 0xd016, 4, 4, 0x03 },
+	{ 0xd01f, 0, 6, 0x0a },
+	{ 0xd020, 0, 6, 0x0a },
+	{ 0x9bda, 0, 8, 0x00 },
+	{ 0x9be3, 0, 8, 0x00 },
+	{ 0xd015, 0, 8, 0x50 },
+	{ 0xd016, 0, 1, 0x00 },
+	{ 0xd044, 0, 8, 0x46 },
+	{ 0xd045, 0, 1, 0x00 },
+	{ 0xd008, 0, 8, 0xdf },
+	{ 0xd009, 0, 2, 0x02 },
+	{ 0xd006, 0, 8, 0x44 },
+	{ 0xd007, 0, 2, 0x01 },
+	{ 0xd00c, 0, 8, 0xeb },
+	{ 0xd00d, 0, 2, 0x02 },
+	{ 0xd00a, 0, 8, 0xf4 },
+	{ 0xd00b, 0, 2, 0x01 },
+	{ 0x9bba, 0, 8, 0xf9 },
+	{ 0x9bc3, 0, 8, 0xdf },
+	{ 0x9bc4, 0, 8, 0x02 },
+	{ 0x9bc5, 0, 8, 0xeb },
+	{ 0x9bc6, 0, 8, 0x02 },
+	{ 0x9bc9, 0, 8, 0x52 },
+	{ 0xd011, 0, 8, 0x3c },
+	{ 0xd012, 0, 2, 0x01 },
+	{ 0xd013, 0, 8, 0xf7 },
+	{ 0xd014, 0, 2, 0x02 },
+	{ 0xd040, 0, 8, 0x0b },
+	{ 0xd041, 0, 2, 0x02 },
+	{ 0xd042, 0, 8, 0x4d },
+	{ 0xd043, 0, 2, 0x00 },
+	{ 0xd045, 1, 1, 0x00 },
+	{ 0x9bcf, 0, 1, 0x01 },
+	{ 0xd045, 2, 1, 0x01 },
+	{ 0xd04f, 0, 8, 0x9a },
+	{ 0xd050, 0, 1, 0x01 },
+	{ 0xd051, 0, 8, 0x5a },
+	{ 0xd052, 0, 1, 0x01 },
+	{ 0xd053, 0, 8, 0x50 },
+	{ 0xd054, 0, 8, 0x46 },
+	{ 0x9bd7, 0, 8, 0x0a },
+	{ 0x9bd8, 0, 8, 0x14 },
+	{ 0x9bd9, 0, 8, 0x08 },
+};
+
+/* Microtune MT2060 tuner init
+   AF9013_TUNER_MT2060     = 130 */
+static struct regdesc tuner_init_mt2060[] = {
+	{ 0x9bd5, 0, 8, 0x01 },
+	{ 0x9bd6, 0, 8, 0x07 },
+	{ 0xd1a0, 1, 1, 0x01 },
+	{ 0xd000, 0, 1, 0x01 },
+	{ 0xd000, 1, 1, 0x00 },
+	{ 0xd001, 1, 1, 0x01 },
+	{ 0xd001, 0, 1, 0x00 },
+	{ 0xd001, 5, 1, 0x00 },
+	{ 0xd002, 0, 5, 0x19 },
+	{ 0xd003, 0, 5, 0x1a },
+	{ 0xd004, 0, 5, 0x19 },
+	{ 0xd005, 0, 5, 0x1a },
+	{ 0xd00e, 0, 5, 0x10 },
+	{ 0xd00f, 0, 3, 0x04 },
+	{ 0xd00f, 3, 3, 0x05 },
+	{ 0xd010, 0, 3, 0x04 },
+	{ 0xd010, 3, 3, 0x05 },
+	{ 0xd016, 4, 4, 0x03 },
+	{ 0xd01f, 0, 6, 0x0a },
+	{ 0xd020, 0, 6, 0x0a },
+	{ 0x9bda, 0, 8, 0x00 },
+	{ 0x9be3, 0, 8, 0x00 },
+	{ 0x9bbe, 0, 1, 0x00 },
+	{ 0x9bcc, 0, 1, 0x00 },
+	{ 0x9bb9, 0, 8, 0x75 },
+	{ 0x9bcd, 0, 8, 0x24 },
+	{ 0x9bff, 0, 8, 0x30 },
+	{ 0xd015, 0, 8, 0x46 },
+	{ 0xd016, 0, 1, 0x00 },
+	{ 0xd044, 0, 8, 0x46 },
+	{ 0xd045, 0, 1, 0x00 },
+	{ 0xd008, 0, 8, 0x0f },
+	{ 0xd009, 0, 2, 0x02 },
+	{ 0xd006, 0, 8, 0x32 },
+	{ 0xd007, 0, 2, 0x01 },
+	{ 0xd00c, 0, 8, 0x36 },
+	{ 0xd00d, 0, 2, 0x03 },
+	{ 0xd00a, 0, 8, 0x35 },
+	{ 0xd00b, 0, 2, 0x01 },
+	{ 0x9bc7, 0, 8, 0x07 },
+	{ 0x9bc8, 0, 8, 0x90 },
+	{ 0x9bc3, 0, 8, 0x0f },
+	{ 0x9bc4, 0, 8, 0x02 },
+	{ 0x9bc5, 0, 8, 0x36 },
+	{ 0x9bc6, 0, 8, 0x03 },
+	{ 0x9bba, 0, 8, 0xc9 },
+	{ 0x9bc9, 0, 8, 0x79 },
+	{ 0xd011, 0, 8, 0x10 },
+	{ 0xd012, 0, 2, 0x01 },
+	{ 0xd013, 0, 8, 0x45 },
+	{ 0xd014, 0, 2, 0x03 },
+	{ 0xd040, 0, 8, 0x98 },
+	{ 0xd041, 0, 2, 0x00 },
+	{ 0xd042, 0, 8, 0xcf },
+	{ 0xd043, 0, 2, 0x03 },
+	{ 0xd045, 1, 1, 0x00 },
+	{ 0x9bcf, 0, 1, 0x01 },
+	{ 0xd045, 2, 1, 0x01 },
+	{ 0xd04f, 0, 8, 0x9a },
+	{ 0xd050, 0, 1, 0x01 },
+	{ 0xd051, 0, 8, 0x5a },
+	{ 0xd052, 0, 1, 0x01 },
+	{ 0xd053, 0, 8, 0x50 },
+	{ 0xd054, 0, 8, 0x46 },
+	{ 0x9bd7, 0, 8, 0x0a },
+	{ 0x9bd8, 0, 8, 0x14 },
+	{ 0x9bd9, 0, 8, 0x08 },
+	{ 0x9bd0, 0, 8, 0xcc },
+	{ 0x9be4, 0, 8, 0xa0 },
+	{ 0x9bbd, 0, 8, 0x8e },
+	{ 0x9be2, 0, 8, 0x4d },
+	{ 0x9bee, 0, 1, 0x01 },
+};
+
+/* Microtune MT2060 tuner init
+   AF9013_TUNER_MT2060_2   = 147 */
+static struct regdesc tuner_init_mt2060_2[] = {
+	{ 0x9bd5, 0, 8, 0x01 },
+	{ 0x9bd6, 0, 8, 0x06 },
+	{ 0x9bbe, 0, 8, 0x01 },
+	{ 0xd1a0, 1, 1, 0x01 },
+	{ 0xd000, 0, 1, 0x01 },
+	{ 0xd000, 1, 1, 0x00 },
+	{ 0xd001, 1, 1, 0x01 },
+	{ 0xd001, 0, 1, 0x00 },
+	{ 0xd001, 5, 1, 0x00 },
+	{ 0xd002, 0, 5, 0x19 },
+	{ 0xd003, 0, 5, 0x1a },
+	{ 0xd004, 0, 5, 0x19 },
+	{ 0xd005, 0, 5, 0x1a },
+	{ 0xd00e, 0, 5, 0x10 },
+	{ 0xd00f, 0, 3, 0x04 },
+	{ 0xd00f, 3, 3, 0x05 },
+	{ 0xd010, 0, 3, 0x04 },
+	{ 0xd010, 3, 3, 0x05 },
+	{ 0xd016, 4, 4, 0x03 },
+	{ 0xd01f, 0, 6, 0x0a },
+	{ 0xd020, 0, 6, 0x0a },
+	{ 0xd015, 0, 8, 0x46 },
+	{ 0xd016, 0, 1, 0x00 },
+	{ 0xd044, 0, 8, 0x46 },
+	{ 0xd045, 0, 1, 0x00 },
+	{ 0xd008, 0, 8, 0x0f },
+	{ 0xd009, 0, 2, 0x02 },
+	{ 0xd006, 0, 8, 0x32 },
+	{ 0xd007, 0, 2, 0x01 },
+	{ 0xd00c, 0, 8, 0x36 },
+	{ 0xd00d, 0, 2, 0x03 },
+	{ 0xd00a, 0, 8, 0x35 },
+	{ 0xd00b, 0, 2, 0x01 },
+	{ 0x9bc7, 0, 8, 0x07 },
+	{ 0x9bc8, 0, 8, 0x90 },
+	{ 0x9bc3, 0, 8, 0x0f },
+	{ 0x9bc4, 0, 8, 0x02 },
+	{ 0x9bc5, 0, 8, 0x36 },
+	{ 0x9bc6, 0, 8, 0x03 },
+	{ 0x9bba, 0, 8, 0xc9 },
+	{ 0x9bc9, 0, 8, 0x79 },
+	{ 0xd011, 0, 8, 0x10 },
+	{ 0xd012, 0, 2, 0x01 },
+	{ 0xd013, 0, 8, 0x45 },
+	{ 0xd014, 0, 2, 0x03 },
+	{ 0xd040, 0, 8, 0x98 },
+	{ 0xd041, 0, 2, 0x00 },
+	{ 0xd042, 0, 8, 0xcf },
+	{ 0xd043, 0, 2, 0x03 },
+	{ 0xd045, 1, 1, 0x00 },
+	{ 0x9bcf, 0, 8, 0x01 },
+	{ 0xd045, 2, 1, 0x01 },
+	{ 0xd04f, 0, 8, 0x9a },
+	{ 0xd050, 0, 1, 0x01 },
+	{ 0xd051, 0, 8, 0x5a },
+	{ 0xd052, 0, 1, 0x01 },
+	{ 0xd053, 0, 8, 0x96 },
+	{ 0xd054, 0, 8, 0x46 },
+	{ 0xd045, 7, 1, 0x00 },
+	{ 0x9bd7, 0, 8, 0x0a },
+	{ 0x9bd8, 0, 8, 0x14 },
+	{ 0x9bd9, 0, 8, 0x08 },
+};
+
+/* MaxLinear MXL5003 tuner init
+   AF9013_TUNER_MXL5003D   =   3 */
+static struct regdesc tuner_init_mxl5003d[] = {
+	{ 0x9bd5, 0, 8, 0x01 },
+	{ 0x9bd6, 0, 8, 0x09 },
+	{ 0xd1a0, 1, 1, 0x01 },
+	{ 0xd000, 0, 1, 0x01 },
+	{ 0xd000, 1, 1, 0x00 },
+	{ 0xd001, 1, 1, 0x01 },
+	{ 0xd001, 0, 1, 0x00 },
+	{ 0xd001, 5, 1, 0x00 },
+	{ 0xd002, 0, 5, 0x19 },
+	{ 0xd003, 0, 5, 0x1a },
+	{ 0xd004, 0, 5, 0x19 },
+	{ 0xd005, 0, 5, 0x1a },
+	{ 0xd00e, 0, 5, 0x10 },
+	{ 0xd00f, 0, 3, 0x04 },
+	{ 0xd00f, 3, 3, 0x05 },
+	{ 0xd010, 0, 3, 0x04 },
+	{ 0xd010, 3, 3, 0x05 },
+	{ 0xd016, 4, 4, 0x03 },
+	{ 0xd01f, 0, 6, 0x0a },
+	{ 0xd020, 0, 6, 0x0a },
+	{ 0x9bda, 0, 8, 0x00 },
+	{ 0x9be3, 0, 8, 0x00 },
+	{ 0x9bfc, 0, 8, 0x0f },
+	{ 0x9bf6, 0, 8, 0x01 },
+	{ 0x9bbe, 0, 1, 0x01 },
+	{ 0xd015, 0, 8, 0x33 },
+	{ 0xd016, 0, 1, 0x00 },
+	{ 0xd044, 0, 8, 0x40 },
+	{ 0xd045, 0, 1, 0x00 },
+	{ 0xd008, 0, 8, 0x0f },
+	{ 0xd009, 0, 2, 0x02 },
+	{ 0xd006, 0, 8, 0x6c },
+	{ 0xd007, 0, 2, 0x00 },
+	{ 0xd00c, 0, 8, 0x3d },
+	{ 0xd00d, 0, 2, 0x00 },
+	{ 0xd00a, 0, 8, 0x45 },
+	{ 0xd00b, 0, 2, 0x01 },
+	{ 0x9bc7, 0, 8, 0x07 },
+	{ 0x9bc8, 0, 8, 0x52 },
+	{ 0x9bc3, 0, 8, 0x0f },
+	{ 0x9bc4, 0, 8, 0x02 },
+	{ 0x9bc5, 0, 8, 0x3d },
+	{ 0x9bc6, 0, 8, 0x00 },
+	{ 0x9bba, 0, 8, 0xa2 },
+	{ 0x9bc9, 0, 8, 0xa0 },
+	{ 0xd011, 0, 8, 0x56 },
+	{ 0xd012, 0, 2, 0x00 },
+	{ 0xd013, 0, 8, 0x50 },
+	{ 0xd014, 0, 2, 0x00 },
+	{ 0xd040, 0, 8, 0x56 },
+	{ 0xd041, 0, 2, 0x00 },
+	{ 0xd042, 0, 8, 0x50 },
+	{ 0xd043, 0, 2, 0x00 },
+	{ 0xd045, 1, 1, 0x00 },
+	{ 0x9bcf, 0, 8, 0x01 },
+	{ 0xd045, 2, 1, 0x01 },
+	{ 0xd04f, 0, 8, 0x9a },
+	{ 0xd050, 0, 1, 0x01 },
+	{ 0xd051, 0, 8, 0x5a },
+	{ 0xd052, 0, 1, 0x01 },
+	{ 0xd053, 0, 8, 0x50 },
+	{ 0xd054, 0, 8, 0x46 },
+	{ 0x9bd7, 0, 8, 0x0a },
+	{ 0x9bd8, 0, 8, 0x14 },
+	{ 0x9bd9, 0, 8, 0x08 },
+};
+
+/* MaxLinear MXL5005 tuner init
+   AF9013_TUNER_MXL5005D   =  13
+   AF9013_TUNER_MXL5005R   =  30 */
+static struct regdesc tuner_init_mxl5005[] = {
+	{ 0x9bd5, 0, 8, 0x01 },
+	{ 0x9bd6, 0, 8, 0x07 },
+	{ 0xd1a0, 1, 1, 0x01 },
+	{ 0xd000, 0, 1, 0x01 },
+	{ 0xd000, 1, 1, 0x00 },
+	{ 0xd001, 1, 1, 0x01 },
+	{ 0xd001, 0, 1, 0x00 },
+	{ 0xd001, 5, 1, 0x00 },
+	{ 0xd002, 0, 5, 0x19 },
+	{ 0xd003, 0, 5, 0x1a },
+	{ 0xd004, 0, 5, 0x19 },
+	{ 0xd005, 0, 5, 0x1a },
+	{ 0xd00e, 0, 5, 0x10 },
+	{ 0xd00f, 0, 3, 0x04 },
+	{ 0xd00f, 3, 3, 0x05 },
+	{ 0xd010, 0, 3, 0x04 },
+	{ 0xd010, 3, 3, 0x05 },
+	{ 0xd016, 4, 4, 0x03 },
+	{ 0xd01f, 0, 6, 0x0a },
+	{ 0xd020, 0, 6, 0x0a },
+	{ 0x9bda, 0, 8, 0x01 },
+	{ 0x9be3, 0, 8, 0x01 },
+	{ 0x9bbe, 0, 1, 0x01 },
+	{ 0x9bcc, 0, 1, 0x01 },
+	{ 0x9bb9, 0, 8, 0x00 },
+	{ 0x9bcd, 0, 8, 0x28 },
+	{ 0x9bff, 0, 8, 0x24 },
+	{ 0xd015, 0, 8, 0x40 },
+	{ 0xd016, 0, 1, 0x00 },
+	{ 0xd044, 0, 8, 0x40 },
+	{ 0xd045, 0, 1, 0x00 },
+	{ 0xd008, 0, 8, 0x0f },
+	{ 0xd009, 0, 2, 0x02 },
+	{ 0xd006, 0, 8, 0x73 },
+	{ 0xd007, 0, 2, 0x01 },
+	{ 0xd00c, 0, 8, 0xfa },
+	{ 0xd00d, 0, 2, 0x01 },
+	{ 0xd00a, 0, 8, 0xff },
+	{ 0xd00b, 0, 2, 0x01 },
+	{ 0x9bc7, 0, 8, 0x23 },
+	{ 0x9bc8, 0, 8, 0x55 },
+	{ 0x9bc3, 0, 8, 0x01 },
+	{ 0x9bc4, 0, 8, 0x02 },
+	{ 0x9bc5, 0, 8, 0xfa },
+	{ 0x9bc6, 0, 8, 0x01 },
+	{ 0x9bba, 0, 8, 0xff },
+	{ 0x9bc9, 0, 8, 0xff },
+	{ 0x9bd3, 0, 8, 0x95 },
+	{ 0xd011, 0, 8, 0x70 },
+	{ 0xd012, 0, 2, 0x01 },
+	{ 0xd013, 0, 8, 0xfb },
+	{ 0xd014, 0, 2, 0x01 },
+	{ 0xd040, 0, 8, 0x70 },
+	{ 0xd041, 0, 2, 0x01 },
+	{ 0xd042, 0, 8, 0xfb },
+	{ 0xd043, 0, 2, 0x01 },
+	{ 0xd045, 1, 1, 0x00 },
+	{ 0x9bcf, 0, 1, 0x01 },
+	{ 0xd045, 2, 1, 0x01 },
+	{ 0xd04f, 0, 8, 0x9a },
+	{ 0xd050, 0, 1, 0x01 },
+	{ 0xd051, 0, 8, 0x5a },
+	{ 0xd052, 0, 1, 0x01 },
+	{ 0xd053, 0, 8, 0x50 },
+	{ 0xd054, 0, 8, 0x46 },
+	{ 0x9bd7, 0, 8, 0x0a },
+	{ 0x9bd8, 0, 8, 0x14 },
+	{ 0x9bd9, 0, 8, 0x08 },
+	{ 0x9bd0, 0, 8, 0x93 },
+	{ 0x9be4, 0, 8, 0xfe },
+	{ 0x9bbd, 0, 8, 0x63 },
+	{ 0x9be2, 0, 8, 0xfe },
+	{ 0x9bee, 0, 1, 0x01 },
+};
+
+/* Quantek QT1010 tuner init
+   AF9013_TUNER_QT1010     = 134
+   AF9013_TUNER_QT1010A    = 162 */
+static struct regdesc tuner_init_qt1010[] = {
+	{ 0x9bd5, 0, 8, 0x01 },
+	{ 0x9bd6, 0, 8, 0x09 },
+	{ 0xd1a0, 1, 1, 0x01 },
+	{ 0xd000, 0, 1, 0x01 },
+	{ 0xd000, 1, 1, 0x00 },
+	{ 0xd001, 1, 1, 0x01 },
+	{ 0xd001, 0, 1, 0x00 },
+	{ 0xd001, 5, 1, 0x00 },
+	{ 0xd002, 0, 5, 0x19 },
+	{ 0xd003, 0, 5, 0x1a },
+	{ 0xd004, 0, 5, 0x19 },
+	{ 0xd005, 0, 5, 0x1a },
+	{ 0xd00e, 0, 5, 0x10 },
+	{ 0xd00f, 0, 3, 0x04 },
+	{ 0xd00f, 3, 3, 0x05 },
+	{ 0xd010, 0, 3, 0x04 },
+	{ 0xd010, 3, 3, 0x05 },
+	{ 0xd016, 4, 4, 0x03 },
+	{ 0xd01f, 0, 6, 0x0a },
+	{ 0xd020, 0, 6, 0x0a },
+	{ 0x9bda, 0, 8, 0x01 },
+	{ 0x9be3, 0, 8, 0x01 },
+	{ 0xd015, 0, 8, 0x46 },
+	{ 0xd016, 0, 1, 0x00 },
+	{ 0xd044, 0, 8, 0x46 },
+	{ 0xd045, 0, 1, 0x00 },
+	{ 0x9bbe, 0, 1, 0x01 },
+	{ 0x9bcc, 0, 1, 0x01 },
+	{ 0x9bb9, 0, 8, 0x00 },
+	{ 0x9bcd, 0, 8, 0x28 },
+	{ 0x9bff, 0, 8, 0x20 },
+	{ 0xd008, 0, 8, 0x0f },
+	{ 0xd009, 0, 2, 0x02 },
+	{ 0xd006, 0, 8, 0x99 },
+	{ 0xd007, 0, 2, 0x01 },
+	{ 0xd00c, 0, 8, 0x0f },
+	{ 0xd00d, 0, 2, 0x02 },
+	{ 0xd00a, 0, 8, 0x50 },
+	{ 0xd00b, 0, 2, 0x01 },
+	{ 0x9bc7, 0, 8, 0x00 },
+	{ 0x9bc8, 0, 8, 0x00 },
+	{ 0x9bc3, 0, 8, 0x0f },
+	{ 0x9bc4, 0, 8, 0x02 },
+	{ 0x9bc5, 0, 8, 0x0f },
+	{ 0x9bc6, 0, 8, 0x02 },
+	{ 0x9bba, 0, 8, 0xc5 },
+	{ 0x9bc9, 0, 8, 0xff },
+	{ 0xd011, 0, 8, 0x58 },
+	{ 0xd012, 0, 2, 0x02 },
+	{ 0xd013, 0, 8, 0x89 },
+	{ 0xd014, 0, 2, 0x01 },
+	{ 0xd040, 0, 8, 0x58 },
+	{ 0xd041, 0, 2, 0x02 },
+	{ 0xd042, 0, 8, 0x89 },
+	{ 0xd043, 0, 2, 0x01 },
+	{ 0xd045, 1, 1, 0x00 },
+	{ 0x9bcf, 0, 1, 0x01 },
+	{ 0xd045, 2, 1, 0x01 },
+	{ 0xd04f, 0, 8, 0x9a },
+	{ 0xd050, 0, 1, 0x01 },
+	{ 0xd051, 0, 8, 0x5a },
+	{ 0xd052, 0, 1, 0x01 },
+	{ 0xd053, 0, 8, 0x50 },
+	{ 0xd054, 0, 8, 0x46 },
+	{ 0x9bd7, 0, 8, 0x0a },
+	{ 0x9bd8, 0, 8, 0x14 },
+	{ 0x9bd9, 0, 8, 0x08 },
+	{ 0x9bd0, 0, 8, 0xcd },
+	{ 0x9be4, 0, 8, 0xbb },
+	{ 0x9bbd, 0, 8, 0x93 },
+	{ 0x9be2, 0, 8, 0x80 },
+	{ 0x9bee, 0, 1, 0x01 },
+};
+
+/* Freescale MC44S803 tuner init
+   AF9013_TUNER_MC44S803   = 133 */
+static struct regdesc tuner_init_mc44s803[] = {
+	{ 0x9bd5, 0, 8, 0x01 },
+	{ 0x9bd6, 0, 8, 0x06 },
+	{ 0xd1a0, 1, 1, 0x01 },
+	{ 0xd000, 0, 1, 0x01 },
+	{ 0xd000, 1, 1, 0x00 },
+	{ 0xd001, 1, 1, 0x01 },
+	{ 0xd001, 0, 1, 0x00 },
+	{ 0xd001, 5, 1, 0x00 },
+	{ 0xd002, 0, 5, 0x19 },
+	{ 0xd003, 0, 5, 0x1a },
+	{ 0xd004, 0, 5, 0x19 },
+	{ 0xd005, 0, 5, 0x1a },
+	{ 0xd00e, 0, 5, 0x10 },
+	{ 0xd00f, 0, 3, 0x04 },
+	{ 0xd00f, 3, 3, 0x05 },
+	{ 0xd010, 0, 3, 0x04 },
+	{ 0xd010, 3, 3, 0x05 },
+	{ 0xd016, 4, 4, 0x03 },
+	{ 0xd01f, 0, 6, 0x0a },
+	{ 0xd020, 0, 6, 0x0a },
+	{ 0x9bda, 0, 8, 0x00 },
+	{ 0x9be3, 0, 8, 0x00 },
+	{ 0x9bf6, 0, 8, 0x01 },
+	{ 0x9bf8, 0, 8, 0x02 },
+	{ 0x9bf9, 0, 8, 0x02 },
+	{ 0x9bfc, 0, 8, 0x1f },
+	{ 0x9bbe, 0, 1, 0x01 },
+	{ 0x9bcc, 0, 1, 0x01 },
+	{ 0x9bb9, 0, 8, 0x00 },
+	{ 0x9bcd, 0, 8, 0x24 },
+	{ 0x9bff, 0, 8, 0x24 },
+	{ 0xd015, 0, 8, 0x46 },
+	{ 0xd016, 0, 1, 0x00 },
+	{ 0xd044, 0, 8, 0x46 },
+	{ 0xd045, 0, 1, 0x00 },
+	{ 0xd008, 0, 8, 0x01 },
+	{ 0xd009, 0, 2, 0x02 },
+	{ 0xd006, 0, 8, 0x7b },
+	{ 0xd007, 0, 2, 0x00 },
+	{ 0xd00c, 0, 8, 0x7c },
+	{ 0xd00d, 0, 2, 0x02 },
+	{ 0xd00a, 0, 8, 0xfe },
+	{ 0xd00b, 0, 2, 0x01 },
+	{ 0x9bc7, 0, 8, 0x08 },
+	{ 0x9bc8, 0, 8, 0x9a },
+	{ 0x9bc3, 0, 8, 0x01 },
+	{ 0x9bc4, 0, 8, 0x02 },
+	{ 0x9bc5, 0, 8, 0x7c },
+	{ 0x9bc6, 0, 8, 0x02 },
+	{ 0x9bba, 0, 8, 0xfc },
+	{ 0x9bc9, 0, 8, 0xaa },
+	{ 0xd011, 0, 8, 0x6b },
+	{ 0xd012, 0, 2, 0x00 },
+	{ 0xd013, 0, 8, 0x88 },
+	{ 0xd014, 0, 2, 0x02 },
+	{ 0xd040, 0, 8, 0x6b },
+	{ 0xd041, 0, 2, 0x00 },
+	{ 0xd042, 0, 8, 0x7c },
+	{ 0xd043, 0, 2, 0x02 },
+	{ 0xd045, 1, 1, 0x00 },
+	{ 0x9bcf, 0, 1, 0x01 },
+	{ 0xd045, 2, 1, 0x01 },
+	{ 0xd04f, 0, 8, 0x9a },
+	{ 0xd050, 0, 1, 0x01 },
+	{ 0xd051, 0, 8, 0x5a },
+	{ 0xd052, 0, 1, 0x01 },
+	{ 0xd053, 0, 8, 0x50 },
+	{ 0xd054, 0, 8, 0x46 },
+	{ 0x9bd7, 0, 8, 0x0a },
+	{ 0x9bd8, 0, 8, 0x14 },
+	{ 0x9bd9, 0, 8, 0x08 },
+	{ 0x9bd0, 0, 8, 0x9e },
+	{ 0x9be4, 0, 8, 0xff },
+	{ 0x9bbd, 0, 8, 0x9e },
+	{ 0x9be2, 0, 8, 0x25 },
+	{ 0x9bee, 0, 1, 0x01 },
+	{ 0xd73b, 3, 1, 0x00 },
+};
+
+/* unknown, probably for tin can tuner, tuner init
+   AF9013_TUNER_UNKNOWN   = 140 */
+static struct regdesc tuner_init_unknown[] = {
+	{ 0x9bd5, 0, 8, 0x01 },
+	{ 0x9bd6, 0, 8, 0x02 },
+	{ 0xd1a0, 1, 1, 0x01 },
+	{ 0xd000, 0, 1, 0x01 },
+	{ 0xd000, 1, 1, 0x00 },
+	{ 0xd001, 1, 1, 0x01 },
+	{ 0xd001, 0, 1, 0x00 },
+	{ 0xd001, 5, 1, 0x00 },
+	{ 0xd002, 0, 5, 0x19 },
+	{ 0xd003, 0, 5, 0x1a },
+	{ 0xd004, 0, 5, 0x19 },
+	{ 0xd005, 0, 5, 0x1a },
+	{ 0xd00e, 0, 5, 0x10 },
+	{ 0xd00f, 0, 3, 0x04 },
+	{ 0xd00f, 3, 3, 0x05 },
+	{ 0xd010, 0, 3, 0x04 },
+	{ 0xd010, 3, 3, 0x05 },
+	{ 0xd016, 4, 4, 0x03 },
+	{ 0xd01f, 0, 6, 0x0a },
+	{ 0xd020, 0, 6, 0x0a },
+	{ 0x9bda, 0, 8, 0x01 },
+	{ 0x9be3, 0, 8, 0x01 },
+	{ 0xd1a0, 1, 1, 0x00 },
+	{ 0x9bbe, 0, 1, 0x01 },
+	{ 0x9bcc, 0, 1, 0x01 },
+	{ 0x9bb9, 0, 8, 0x00 },
+	{ 0x9bcd, 0, 8, 0x18 },
+	{ 0x9bff, 0, 8, 0x2c },
+	{ 0xd015, 0, 8, 0x46 },
+	{ 0xd016, 0, 1, 0x00 },
+	{ 0xd044, 0, 8, 0x46 },
+	{ 0xd045, 0, 1, 0x00 },
+	{ 0xd008, 0, 8, 0xdf },
+	{ 0xd009, 0, 2, 0x02 },
+	{ 0xd006, 0, 8, 0x44 },
+	{ 0xd007, 0, 2, 0x01 },
+	{ 0xd00c, 0, 8, 0x00 },
+	{ 0xd00d, 0, 2, 0x02 },
+	{ 0xd00a, 0, 8, 0xf6 },
+	{ 0xd00b, 0, 2, 0x01 },
+	{ 0x9bba, 0, 8, 0xf9 },
+	{ 0x9bc8, 0, 8, 0xaa },
+	{ 0x9bc3, 0, 8, 0xdf },
+	{ 0x9bc4, 0, 8, 0x02 },
+	{ 0x9bc5, 0, 8, 0x00 },
+	{ 0x9bc6, 0, 8, 0x02 },
+	{ 0x9bc9, 0, 8, 0xf0 },
+	{ 0xd011, 0, 8, 0x3c },
+	{ 0xd012, 0, 2, 0x01 },
+	{ 0xd013, 0, 8, 0xf7 },
+	{ 0xd014, 0, 2, 0x02 },
+	{ 0xd040, 0, 8, 0x0b },
+	{ 0xd041, 0, 2, 0x02 },
+	{ 0xd042, 0, 8, 0x4d },
+	{ 0xd043, 0, 2, 0x00 },
+	{ 0xd045, 1, 1, 0x00 },
+	{ 0x9bcf, 0, 1, 0x01 },
+	{ 0xd045, 2, 1, 0x01 },
+	{ 0xd04f, 0, 8, 0x9a },
+	{ 0xd050, 0, 1, 0x01 },
+	{ 0xd051, 0, 8, 0x5a },
+	{ 0xd052, 0, 1, 0x01 },
+	{ 0xd053, 0, 8, 0x50 },
+	{ 0xd054, 0, 8, 0x46 },
+	{ 0x9bd7, 0, 8, 0x0a },
+	{ 0x9bd8, 0, 8, 0x14 },
+	{ 0x9bd9, 0, 8, 0x08 },
+};
+
+/* NXP TDA18271 tuner init
+   AF9013_TUNER_TDA18271   = 156 */
+static struct regdesc tuner_init_tda18271[] = {
+	{ 0x9bd5, 0, 8, 0x01 },
+	{ 0x9bd6, 0, 8, 0x04 },
+	{ 0xd1a0, 1, 1, 0x01 },
+	{ 0xd000, 0, 1, 0x01 },
+	{ 0xd000, 1, 1, 0x00 },
+	{ 0xd001, 1, 1, 0x01 },
+	{ 0xd001, 0, 1, 0x00 },
+	{ 0xd001, 5, 1, 0x00 },
+	{ 0xd002, 0, 5, 0x19 },
+	{ 0xd003, 0, 5, 0x1a },
+	{ 0xd004, 0, 5, 0x19 },
+	{ 0xd005, 0, 5, 0x1a },
+	{ 0xd00e, 0, 5, 0x10 },
+	{ 0xd00f, 0, 3, 0x04 },
+	{ 0xd00f, 3, 3, 0x05 },
+	{ 0xd010, 0, 3, 0x04 },
+	{ 0xd010, 3, 3, 0x05 },
+	{ 0xd016, 4, 4, 0x03 },
+	{ 0xd01f, 0, 6, 0x0a },
+	{ 0xd020, 0, 6, 0x0a },
+	{ 0x9bda, 0, 8, 0x01 },
+	{ 0x9be3, 0, 8, 0x01 },
+	{ 0xd1a0, 1, 1, 0x00 },
+	{ 0x9bbe, 0, 1, 0x01 },
+	{ 0x9bcc, 0, 1, 0x01 },
+	{ 0x9bb9, 0, 8, 0x00 },
+	{ 0x9bcd, 0, 8, 0x18 },
+	{ 0x9bff, 0, 8, 0x2c },
+	{ 0xd015, 0, 8, 0x46 },
+	{ 0xd016, 0, 1, 0x00 },
+	{ 0xd044, 0, 8, 0x46 },
+	{ 0xd045, 0, 1, 0x00 },
+	{ 0xd008, 0, 8, 0xdf },
+	{ 0xd009, 0, 2, 0x02 },
+	{ 0xd006, 0, 8, 0x44 },
+	{ 0xd007, 0, 2, 0x01 },
+	{ 0xd00c, 0, 8, 0x00 },
+	{ 0xd00d, 0, 2, 0x02 },
+	{ 0xd00a, 0, 8, 0xf6 },
+	{ 0xd00b, 0, 2, 0x01 },
+	{ 0x9bba, 0, 8, 0xf9 },
+	{ 0x9bc8, 0, 8, 0xaa },
+	{ 0x9bc3, 0, 8, 0xdf },
+	{ 0x9bc4, 0, 8, 0x02 },
+	{ 0x9bc5, 0, 8, 0x00 },
+	{ 0x9bc6, 0, 8, 0x02 },
+	{ 0x9bc9, 0, 8, 0xf0 },
+	{ 0xd011, 0, 8, 0x3c },
+	{ 0xd012, 0, 2, 0x01 },
+	{ 0xd013, 0, 8, 0xf7 },
+	{ 0xd014, 0, 2, 0x02 },
+	{ 0xd040, 0, 8, 0x0b },
+	{ 0xd041, 0, 2, 0x02 },
+	{ 0xd042, 0, 8, 0x4d },
+	{ 0xd043, 0, 2, 0x00 },
+	{ 0xd045, 1, 1, 0x00 },
+	{ 0x9bcf, 0, 1, 0x01 },
+	{ 0xd045, 2, 1, 0x01 },
+	{ 0xd04f, 0, 8, 0x9a },
+	{ 0xd050, 0, 1, 0x01 },
+	{ 0xd051, 0, 8, 0x5a },
+	{ 0xd052, 0, 1, 0x01 },
+	{ 0xd053, 0, 8, 0x50 },
+	{ 0xd054, 0, 8, 0x46 },
+	{ 0x9bd7, 0, 8, 0x0a },
+	{ 0x9bd8, 0, 8, 0x14 },
+	{ 0x9bd9, 0, 8, 0x08 },
+	{ 0x9bd0, 0, 8, 0xa8 },
+	{ 0x9be4, 0, 8, 0x7f },
+	{ 0x9bbd, 0, 8, 0xa8 },
+	{ 0x9be2, 0, 8, 0x20 },
+	{ 0x9bee, 0, 1, 0x01 },
+};
+
+#endif /* _AF9013_PRIV_ */
diff --git a/drivers/media/dvb/frontends/au8522.c b/drivers/media/dvb/frontends/au8522.c
index 0b82cc2..eabf9a6 100644
--- a/drivers/media/dvb/frontends/au8522.c
+++ b/drivers/media/dvb/frontends/au8522.c
@@ -40,6 +40,8 @@
 	u32 current_frequency;
 	fe_modulation_t current_modulation;
 
+	u32 fe_status;
+	unsigned int led_state;
 };
 
 static int debug;
@@ -538,11 +540,98 @@
 	return 0;
 }
 
+static int au8522_led_gpio_enable(struct au8522_state *state, int onoff)
+{
+	struct au8522_led_config *led_config = state->config->led_cfg;
+	u8 val;
+
+	/* bail out if we cant control an LED */
+	if (!led_config || !led_config->gpio_output ||
+	    !led_config->gpio_output_enable || !led_config->gpio_output_disable)
+		return 0;
+
+	val = au8522_readreg(state, 0x4000 |
+			     (led_config->gpio_output & ~0xc000));
+	if (onoff) {
+		/* enable GPIO output */
+		val &= ~((led_config->gpio_output_enable >> 8) & 0xff);
+		val |=  (led_config->gpio_output_enable & 0xff);
+	} else {
+		/* disable GPIO output */
+		val &= ~((led_config->gpio_output_disable >> 8) & 0xff);
+		val |=  (led_config->gpio_output_disable & 0xff);
+	}
+	return au8522_writereg(state, 0x8000 |
+			       (led_config->gpio_output & ~0xc000), val);
+}
+
+/* led = 0 | off
+ * led = 1 | signal ok
+ * led = 2 | signal strong
+ * led < 0 | only light led if leds are currently off
+ */
+static int au8522_led_ctrl(struct au8522_state *state, int led)
+{
+	struct au8522_led_config *led_config = state->config->led_cfg;
+	int i, ret = 0;
+
+	/* bail out if we cant control an LED */
+	if (!led_config || !led_config->gpio_leds ||
+	    !led_config->num_led_states || !led_config->led_states)
+		return 0;
+
+	if (led < 0) {
+		/* if LED is already lit, then leave it as-is */
+		if (state->led_state)
+			return 0;
+		else
+			led *= -1;
+	}
+
+	/* toggle LED if changing state */
+	if (state->led_state != led) {
+		u8 val;
+
+		dprintk("%s: %d\n", __func__, led);
+
+		au8522_led_gpio_enable(state, 1);
+
+		val = au8522_readreg(state, 0x4000 |
+				     (led_config->gpio_leds & ~0xc000));
+
+		/* start with all leds off */
+		for (i = 0; i < led_config->num_led_states; i++)
+			val &= ~led_config->led_states[i];
+
+		/* set selected LED state */
+		if (led < led_config->num_led_states)
+			val |= led_config->led_states[led];
+		else if (led_config->num_led_states)
+			val |=
+			led_config->led_states[led_config->num_led_states - 1];
+
+		ret = au8522_writereg(state, 0x8000 |
+				      (led_config->gpio_leds & ~0xc000), val);
+		if (ret < 0)
+			return ret;
+
+		state->led_state = led;
+
+		if (led == 0)
+			au8522_led_gpio_enable(state, 0);
+	}
+
+	return 0;
+}
+
 static int au8522_sleep(struct dvb_frontend *fe)
 {
 	struct au8522_state *state = fe->demodulator_priv;
 	dprintk("%s()\n", __func__);
 
+	/* turn off led */
+	au8522_led_ctrl(state, 0);
+
 	state->current_frequency = 0;
 
 	return 0;
@@ -592,12 +681,53 @@
 			*status |= FE_HAS_CARRIER | FE_HAS_SIGNAL;
 		break;
 	}
+	state->fe_status = *status;
+
+	if (*status & FE_HAS_LOCK)
+		/* turn on LED, if it isn't on already */
+		au8522_led_ctrl(state, -1);
+	else
+		/* turn off LED */
+		au8522_led_ctrl(state, 0);
 
 	dprintk("%s() status 0x%08x\n", __func__, *status);
 
 	return 0;
 }
 
+static int au8522_led_status(struct au8522_state *state, const u16 *snr)
+{
+	struct au8522_led_config *led_config = state->config->led_cfg;
+	int led;
+	u16 strong;
+
+	/* bail out if we cant control an LED */
+	if (!led_config)
+		return 0;
+
+	if (0 == (state->fe_status & FE_HAS_LOCK))
+		return au8522_led_ctrl(state, 0);
+	else if (state->current_modulation == QAM_256)
+		strong = led_config->qam256_strong;
+	else if (state->current_modulation == QAM_64)
+		strong = led_config->qam64_strong;
+	else /* (state->current_modulation == VSB_8) */
+		strong = led_config->vsb8_strong;
+
+	if (*snr >= strong)
+		led = 2;
+	else
+		led = 1;
+
+	if ((state->led_state) &&
+	    (((strong < *snr) ? (*snr - strong) : (strong - *snr)) <= 10))
+		/* snr didn't change enough to bother
+		 * changing the color of the led */
+		return 0;
+
+	return au8522_led_ctrl(state, led);
+}
+
 static int au8522_read_snr(struct dvb_frontend *fe, u16 *snr)
 {
 	struct au8522_state *state = fe->demodulator_priv;
@@ -621,6 +751,9 @@
 					    au8522_readreg(state, 0x4311),
 					    snr);
 
+	if (state->config->led_cfg)
+		au8522_led_status(state, snr);
+
 	return ret;
 }
 
diff --git a/drivers/media/dvb/frontends/au8522.h b/drivers/media/dvb/frontends/au8522.h
index 595915a..7b94f55 100644
--- a/drivers/media/dvb/frontends/au8522.h
+++ b/drivers/media/dvb/frontends/au8522.h
@@ -30,6 +30,21 @@
 	AU8522_IF_3_25MHZ,
 };
 
+struct au8522_led_config {
+	u16 vsb8_strong;
+	u16 qam64_strong;
+	u16 qam256_strong;
+
+	u16 gpio_output;
+	/* unset hi bits, set low bits */
+	u16 gpio_output_enable;
+	u16 gpio_output_disable;
+
+	u16 gpio_leds;
+	u8 *led_states;
+	unsigned int num_led_states;
+};
+
 struct au8522_config {
 	/* the demodulator's i2c address */
 	u8 demod_address;
@@ -39,6 +54,8 @@
 #define AU8522_DEMODLOCKING 1
 	u8 status_mode;
 
+	struct au8522_led_config *led_cfg;
+
 	enum au8522_if_freq vsb_if;
 	enum au8522_if_freq qam_if;
 };
diff --git a/drivers/media/dvb/frontends/cx24110.h b/drivers/media/dvb/frontends/cx24110.h
index 1792adb..fdcceee 100644
--- a/drivers/media/dvb/frontends/cx24110.h
+++ b/drivers/media/dvb/frontends/cx24110.h
@@ -33,12 +33,17 @@
 	u8 demod_address;
 };
 
-static inline int cx24110_pll_write(struct dvb_frontend *fe, u32 val) {
-	int r = 0;
-	u8 buf[] = {(u8) (val>>24), (u8) (val>>16), (u8) (val>>8)};
+static inline int cx24110_pll_write(struct dvb_frontend *fe, u32 val)
+{
+	u8 buf[] = {
+		(u8)((val >> 24) & 0xff),
+		(u8)((val >> 16) & 0xff),
+		(u8)((val >> 8) & 0xff)
+	};
+
 	if (fe->ops.write)
-		r = fe->ops.write(fe, buf, 3);
-	return r;
+		return fe->ops.write(fe, buf, 3);
+	return 0;
 }
 
 #if defined(CONFIG_DVB_CX24110) || (defined(CONFIG_DVB_CX24110_MODULE) && defined(MODULE))
diff --git a/drivers/media/dvb/frontends/cx24116.c b/drivers/media/dvb/frontends/cx24116.c
new file mode 100644
index 0000000..deb36f4
--- /dev/null
+++ b/drivers/media/dvb/frontends/cx24116.c
@@ -0,0 +1,1423 @@
+/*
+    Conexant cx24116/cx24118 - DVBS/S2 Satellite demod/tuner driver
+
+    Copyright (C) 2006-2008 Steven Toth <stoth@hauppauge.com>
+    Copyright (C) 2006-2007 Georg Acher
+    Copyright (C) 2007-2008 Darron Broad
+	March 2007
+	    Fixed some bugs.
+	    Added diseqc support.
+	    Added corrected signal strength support.
+	August 2007
+	    Sync with legacy version.
+	    Some clean ups.
+    Copyright (C) 2008 Igor Liplianin
+	September, 9th 2008
+	    Fixed locking on high symbol rates (>30000).
+	    Implement MPEG initialization parameter.
+
+    This program is free software; you can redistribute it and/or 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/slab.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/firmware.h>
+
+#include "dvb_frontend.h"
+#include "cx24116.h"
+
+static int debug = 0;
+#define dprintk(args...) \
+	do { \
+		if (debug) printk ("cx24116: " args); \
+	} while (0)
+
+#define CX24116_DEFAULT_FIRMWARE "dvb-fe-cx24116.fw"
+#define CX24116_SEARCH_RANGE_KHZ 5000
+
+/* known registers */
+#define CX24116_REG_COMMAND (0x00)      /* command args 0x00..0x1e */
+#define CX24116_REG_EXECUTE (0x1f)      /* execute command */
+#define CX24116_REG_MAILBOX (0x96)      /* FW or multipurpose mailbox? */
+#define CX24116_REG_RESET   (0x20)      /* reset status > 0     */
+#define CX24116_REG_SIGNAL  (0x9e)      /* signal low           */
+#define CX24116_REG_SSTATUS (0x9d)      /* signal high / status */
+#define CX24116_REG_QUALITY8 (0xa3)
+#define CX24116_REG_QSTATUS (0xbc)
+#define CX24116_REG_QUALITY0 (0xd5)
+#define CX24116_REG_BER0    (0xc9)
+#define CX24116_REG_BER8    (0xc8)
+#define CX24116_REG_BER16   (0xc7)
+#define CX24116_REG_BER24   (0xc6)
+#define CX24116_REG_UCB0    (0xcb)
+#define CX24116_REG_UCB8    (0xca)
+#define CX24116_REG_CLKDIV  (0xf3)
+#define CX24116_REG_RATEDIV (0xf9)
+#define CX24116_REG_FECSTATUS (0x9c)    /* configured fec (not tuned) or actual FEC (tuned) 1=1/2 2=2/3 etc */
+
+/* FECSTATUS bits */
+#define CX24116_FEC_FECMASK   (0x1f)    /* mask to determine configured fec (not tuned) or actual fec (tuned) */
+#define CX24116_FEC_DVBS      (0x20)    /* Select DVB-S demodulator, else DVB-S2 */
+#define CX24116_FEC_UNKNOWN   (0x40)    /* Unknown/unused */
+#define CX24116_FEC_PILOT     (0x80)    /* Pilot mode requested when tuning else always reset when tuned */
+
+/* arg buffer size */
+#define CX24116_ARGLEN (0x1e)
+
+/* rolloff */
+#define CX24116_ROLLOFF_020 (0x00)
+#define CX24116_ROLLOFF_025 (0x01)
+#define CX24116_ROLLOFF_035 (0x02)
+
+/* pilot bit */
+#define CX24116_PILOT_OFF (0x00)
+#define CX24116_PILOT_ON (0x40)
+
+/* signal status */
+#define CX24116_HAS_SIGNAL   (0x01)
+#define CX24116_HAS_CARRIER  (0x02)
+#define CX24116_HAS_VITERBI  (0x04)
+#define CX24116_HAS_SYNCLOCK (0x08)
+#define CX24116_HAS_UNKNOWN1 (0x10)
+#define CX24116_HAS_UNKNOWN2 (0x20)
+#define CX24116_STATUS_MASK  (0x3f)
+#define CX24116_SIGNAL_MASK  (0xc0)
+
+#define CX24116_DISEQC_TONEOFF   (0)    /* toneburst never sent */
+#define CX24116_DISEQC_TONECACHE (1)    /* toneburst cached     */
+#define CX24116_DISEQC_MESGCACHE (2)    /* message cached       */
+
+/* arg offset for DiSEqC */
+#define CX24116_DISEQC_BURST  (1)
+#define CX24116_DISEQC_ARG2_2 (2)   /* unknown value=2 */
+#define CX24116_DISEQC_ARG3_0 (3)   /* unknown value=0 */
+#define CX24116_DISEQC_ARG4_0 (4)   /* unknown value=0 */
+#define CX24116_DISEQC_MSGLEN (5)
+#define CX24116_DISEQC_MSGOFS (6)
+
+/* DiSEqC burst */
+#define CX24116_DISEQC_MINI_A (0)
+#define CX24116_DISEQC_MINI_B (1)
+
+/* DiSEqC tone burst */
+static int toneburst = 1;
+
+/* SNR measurements */
+static int esno_snr = 0;
+
+enum cmds
+{
+	CMD_SET_VCO     = 0x10,
+	CMD_TUNEREQUEST = 0x11,
+	CMD_MPEGCONFIG  = 0x13,
+	CMD_TUNERINIT   = 0x14,
+	CMD_BANDWIDTH   = 0x15,
+	CMD_GETAGC      = 0x19,
+	CMD_LNBCONFIG   = 0x20,
+	CMD_LNBSEND     = 0x21, /* Formerly CMD_SEND_DISEQC */
+	CMD_SET_TONEPRE = 0x22,
+	CMD_SET_TONE    = 0x23,
+	CMD_UPDFWVERS   = 0x35,
+	CMD_TUNERSLEEP  = 0x36,
+	CMD_AGCCONTROL  = 0x3b, /* Unknown */
+};
+
+/* The Demod/Tuner can't easily provide these, we cache them */
+struct cx24116_tuning
+{
+	u32 frequency;
+	u32 symbol_rate;
+	fe_spectral_inversion_t inversion;
+	fe_code_rate_t fec;
+
+	fe_modulation_t modulation;
+	fe_pilot_t pilot;
+	fe_rolloff_t rolloff;
+
+	/* Demod values */
+	u8 fec_val;
+	u8 fec_mask;
+	u8 inversion_val;
+	u8 pilot_val;
+	u8 rolloff_val;
+};
+
+/* Basic commands that are sent to the firmware */
+struct cx24116_cmd
+{
+	u8 len;
+	u8 args[CX24116_ARGLEN];
+};
+
+struct cx24116_state
+{
+	struct i2c_adapter* i2c;
+	const struct cx24116_config* config;
+
+	struct dvb_frontend frontend;
+
+	struct cx24116_tuning dcur;
+	struct cx24116_tuning dnxt;
+
+	u8 skip_fw_load;
+	u8 burst;
+	struct cx24116_cmd dsec_cmd;
+};
+
+static int cx24116_writereg(struct cx24116_state* state, int reg, int data)
+{
+	u8 buf[] = { reg, data };
+	struct i2c_msg msg = { .addr = state->config->demod_address,
+		.flags = 0, .buf = buf, .len = 2 };
+	int err;
+
+	if (debug>1)
+		printk("cx24116: %s: write reg 0x%02x, value 0x%02x\n",
+						__func__,reg, data);
+
+	if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) {
+		printk("%s: writereg error(err == %i, reg == 0x%02x,"
+			 " value == 0x%02x)\n", __func__, err, reg, data);
+		return -EREMOTEIO;
+	}
+
+	return 0;
+}
+
+/* Bulk byte writes to a single I2C address, for 32k firmware load */
+static int cx24116_writeregN(struct cx24116_state* state, int reg, u8 *data, u16 len)
+{
+	int ret = -EREMOTEIO;
+	struct i2c_msg msg;
+	u8 *buf;
+
+	buf = kmalloc(len + 1, GFP_KERNEL);
+	if (buf == NULL) {
+		printk("Unable to kmalloc\n");
+		ret = -ENOMEM;
+		goto error;
+	}
+
+	*(buf) = reg;
+	memcpy(buf + 1, data, len);
+
+	msg.addr = state->config->demod_address;
+	msg.flags = 0;
+	msg.buf = buf;
+	msg.len = len + 1;
+
+	if (debug>1)
+		printk("cx24116: %s:  write regN 0x%02x, len = %d\n",
+						__func__,reg, len);
+
+	if ((ret = i2c_transfer(state->i2c, &msg, 1)) != 1) {
+		printk("%s: writereg error(err == %i, reg == 0x%02x\n",
+			 __func__, ret, reg);
+		ret = -EREMOTEIO;
+	}
+
+error:
+	kfree(buf);
+
+	return ret;
+}
+
+static int cx24116_readreg(struct cx24116_state* state, u8 reg)
+{
+	int ret;
+	u8 b0[] = { reg };
+	u8 b1[] = { 0 };
+	struct i2c_msg msg[] = {
+		{ .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 1 },
+		{ .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 }
+	};
+
+	ret = i2c_transfer(state->i2c, msg, 2);
+
+	if (ret != 2) {
+		printk("%s: reg=0x%x (error=%d)\n", __func__, reg, ret);
+		return ret;
+	}
+
+	if (debug>1)
+		printk("cx24116: read reg 0x%02x, value 0x%02x\n",reg, b1[0]);
+
+	return b1[0];
+}
+
+static int cx24116_set_inversion(struct cx24116_state* state, fe_spectral_inversion_t inversion)
+{
+	dprintk("%s(%d)\n", __func__, inversion);
+
+	switch (inversion) {
+	case INVERSION_OFF:
+		state->dnxt.inversion_val = 0x00;
+		break;
+	case INVERSION_ON:
+		state->dnxt.inversion_val = 0x04;
+		break;
+	case INVERSION_AUTO:
+		state->dnxt.inversion_val = 0x0C;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	state->dnxt.inversion = inversion;
+
+	return 0;
+}
+
+/*
+ * modfec (modulation and FEC)
+ * ===========================
+ *
+ * MOD          FEC             mask/val    standard
+ * ----         --------        ----------- --------
+ * QPSK         FEC_1_2         0x02 0x02+X DVB-S
+ * QPSK         FEC_2_3         0x04 0x02+X DVB-S
+ * QPSK         FEC_3_4         0x08 0x02+X DVB-S
+ * QPSK         FEC_4_5         0x10 0x02+X DVB-S (?)
+ * QPSK         FEC_5_6         0x20 0x02+X DVB-S
+ * QPSK         FEC_6_7         0x40 0x02+X DVB-S
+ * QPSK         FEC_7_8         0x80 0x02+X DVB-S
+ * QPSK         FEC_8_9         0x01 0x02+X DVB-S (?) (NOT SUPPORTED?)
+ * QPSK         AUTO            0xff 0x02+X DVB-S
+ *
+ * For DVB-S high byte probably represents FEC
+ * and low byte selects the modulator. The high
+ * byte is search range mask. Bit 5 may turn
+ * on DVB-S and remaining bits represent some
+ * kind of calibration (how/what i do not know).
+ *
+ * Eg.(2/3) szap "Zone Horror"
+ *
+ * mask/val = 0x04, 0x20
+ * status 1f | signal c3c0 | snr a333 | ber 00000098 | unc 00000000 | FE_HAS_LOCK
+ *
+ * mask/val = 0x04, 0x30
+ * status 1f | signal c3c0 | snr a333 | ber 00000000 | unc 00000000 | FE_HAS_LOCK
+ *
+ * After tuning FECSTATUS contains actual FEC
+ * in use numbered 1 through to 8 for 1/2 .. 2/3 etc
+ *
+ * NBC=NOT/NON BACKWARD COMPATIBLE WITH DVB-S (DVB-S2 only)
+ *
+ * NBC-QPSK     FEC_1_2         0x00, 0x04      DVB-S2
+ * NBC-QPSK     FEC_3_5         0x00, 0x05      DVB-S2
+ * NBC-QPSK     FEC_2_3         0x00, 0x06      DVB-S2
+ * NBC-QPSK     FEC_3_4         0x00, 0x07      DVB-S2
+ * NBC-QPSK     FEC_4_5         0x00, 0x08      DVB-S2
+ * NBC-QPSK     FEC_5_6         0x00, 0x09      DVB-S2
+ * NBC-QPSK     FEC_8_9         0x00, 0x0a      DVB-S2
+ * NBC-QPSK     FEC_9_10        0x00, 0x0b      DVB-S2
+ *
+ * NBC-8PSK     FEC_3_5         0x00, 0x0c      DVB-S2
+ * NBC-8PSK     FEC_2_3         0x00, 0x0d      DVB-S2
+ * NBC-8PSK     FEC_3_4         0x00, 0x0e      DVB-S2
+ * NBC-8PSK     FEC_5_6         0x00, 0x0f      DVB-S2
+ * NBC-8PSK     FEC_8_9         0x00, 0x10      DVB-S2
+ * NBC-8PSK     FEC_9_10        0x00, 0x11      DVB-S2
+ *
+ * For DVB-S2 low bytes selects both modulator
+ * and FEC. High byte is meaningless here. To
+ * set pilot, bit 6 (0x40) is set. When inspecting
+ * FECSTATUS bit 7 (0x80) represents the pilot
+ * selection whilst not tuned. When tuned, actual FEC
+ * in use is found in FECSTATUS as per above. Pilot
+ * value is reset.
+ */
+
+/* A table of modulation, fec and configuration bytes for the demod.
+ * Not all S2 mmodulation schemes are support and not all rates with
+ * a scheme are support. Especially, no auto detect when in S2 mode.
+ */
+struct cx24116_modfec {
+	fe_delivery_system_t delivery_system;
+	fe_modulation_t modulation;
+	fe_code_rate_t fec;
+	u8 mask;	/* In DVBS mode this is used to autodetect */
+	u8 val;		/* Passed to the firmware to indicate mode selection */
+} CX24116_MODFEC_MODES[] = {
+ /* QPSK. For unknown rates we set hardware to auto detect 0xfe 0x30 */
+
+ /*mod   fec       mask  val */
+ { SYS_DVBS, QPSK, FEC_NONE, 0xfe, 0x30 },
+ { SYS_DVBS, QPSK, FEC_1_2,  0x02, 0x2e }, /* 00000010 00101110 */
+ { SYS_DVBS, QPSK, FEC_2_3,  0x04, 0x2f }, /* 00000100 00101111 */
+ { SYS_DVBS, QPSK, FEC_3_4,  0x08, 0x30 }, /* 00001000 00110000 */
+ { SYS_DVBS, QPSK, FEC_4_5,  0xfe, 0x30 }, /* 000?0000 ?        */
+ { SYS_DVBS, QPSK, FEC_5_6,  0x20, 0x31 }, /* 00100000 00110001 */
+ { SYS_DVBS, QPSK, FEC_6_7,  0xfe, 0x30 }, /* 0?000000 ?        */
+ { SYS_DVBS, QPSK, FEC_7_8,  0x80, 0x32 }, /* 10000000 00110010 */
+ { SYS_DVBS, QPSK, FEC_8_9,  0xfe, 0x30 }, /* 0000000? ?        */
+ { SYS_DVBS, QPSK, FEC_AUTO, 0xfe, 0x30 },
+ /* NBC-QPSK */
+ { SYS_DVBS2, QPSK, FEC_1_2,  0x00, 0x04 },
+ { SYS_DVBS2, QPSK, FEC_3_5,  0x00, 0x05 },
+ { SYS_DVBS2, QPSK, FEC_2_3,  0x00, 0x06 },
+ { SYS_DVBS2, QPSK, FEC_3_4,  0x00, 0x07 },
+ { SYS_DVBS2, QPSK, FEC_4_5,  0x00, 0x08 },
+ { SYS_DVBS2, QPSK, FEC_5_6,  0x00, 0x09 },
+ { SYS_DVBS2, QPSK, FEC_8_9,  0x00, 0x0a },
+ { SYS_DVBS2, QPSK, FEC_9_10, 0x00, 0x0b },
+ /* 8PSK */
+ { SYS_DVBS2, PSK_8, FEC_3_5,  0x00, 0x0c },
+ { SYS_DVBS2, PSK_8, FEC_2_3,  0x00, 0x0d },
+ { SYS_DVBS2, PSK_8, FEC_3_4,  0x00, 0x0e },
+ { SYS_DVBS2, PSK_8, FEC_5_6,  0x00, 0x0f },
+ { SYS_DVBS2, PSK_8, FEC_8_9,  0x00, 0x10 },
+ { SYS_DVBS2, PSK_8, FEC_9_10, 0x00, 0x11 },
+ /*
+  * `val' can be found in the FECSTATUS register when tuning.
+  * FECSTATUS will give the actual FEC in use if tuning was successful.
+  */
+};
+
+static int cx24116_lookup_fecmod(struct cx24116_state* state,
+	fe_modulation_t m, fe_code_rate_t f)
+{
+	int i, ret = -EOPNOTSUPP;
+
+	dprintk("%s(0x%02x,0x%02x)\n", __func__, m, f);
+
+	for(i=0 ; i < sizeof(CX24116_MODFEC_MODES) / sizeof(struct cx24116_modfec) ; i++)
+	{
+		if( (m == CX24116_MODFEC_MODES[i].modulation) &&
+			(f == CX24116_MODFEC_MODES[i].fec) )
+			{
+				ret = i;
+				break;
+			}
+	}
+
+	return ret;
+}
+
+static int cx24116_set_fec(struct cx24116_state* state, fe_modulation_t mod, fe_code_rate_t fec)
+{
+	int ret = 0;
+
+	dprintk("%s(0x%02x,0x%02x)\n", __func__, mod, fec);
+
+	ret = cx24116_lookup_fecmod(state, mod, fec);
+
+	if(ret < 0)
+		return ret;
+
+	state->dnxt.fec = fec;
+	state->dnxt.fec_val = CX24116_MODFEC_MODES[ret].val;
+	state->dnxt.fec_mask = CX24116_MODFEC_MODES[ret].mask;
+	dprintk("%s() mask/val = 0x%02x/0x%02x\n", __func__,
+		state->dnxt.fec_mask, state->dnxt.fec_val);
+
+	return 0;
+}
+
+static int cx24116_set_symbolrate(struct cx24116_state* state, u32 rate)
+{
+	dprintk("%s(%d)\n", __func__, rate);
+
+	/*  check if symbol rate is within limits */
+	if ((rate > state->frontend.ops.info.symbol_rate_max) ||
+	    (rate < state->frontend.ops.info.symbol_rate_min)) {
+		dprintk("%s() unsupported symbol_rate = %d\n", __func__, rate);
+		return -EOPNOTSUPP;
+	}
+
+	state->dnxt.symbol_rate = rate;
+	dprintk("%s() symbol_rate = %d\n", __func__, rate);
+
+	return 0;
+}
+
+static int cx24116_load_firmware (struct dvb_frontend* fe, const struct firmware *fw);
+
+static int cx24116_firmware_ondemand(struct dvb_frontend* fe)
+{
+	struct cx24116_state *state = fe->demodulator_priv;
+	const struct firmware *fw;
+	int ret = 0;
+
+	dprintk("%s()\n",__func__);
+
+	if (cx24116_readreg(state, 0x20) > 0)
+	{
+
+		if (state->skip_fw_load)
+			return 0;
+
+		/* Load firmware */
+		/* request the firmware, this will block until someone uploads it */
+		printk("%s: Waiting for firmware upload (%s)...\n", __func__, CX24116_DEFAULT_FIRMWARE);
+		ret = request_firmware(&fw, CX24116_DEFAULT_FIRMWARE, &state->i2c->dev);
+		printk("%s: Waiting for firmware upload(2)...\n", __func__);
+		if (ret) {
+			printk("%s: No firmware uploaded (timeout or file not found?)\n", __func__);
+			return ret;
+		}
+
+		/* Make sure we don't recurse back through here during loading */
+		state->skip_fw_load = 1;
+
+		ret = cx24116_load_firmware(fe, fw);
+		if (ret)
+			printk("%s: Writing firmware to device failed\n", __func__);
+
+		release_firmware(fw);
+
+		printk("%s: Firmware upload %s\n", __func__, ret == 0 ? "complete" : "failed");
+
+		/* Ensure firmware is always loaded if required */
+		state->skip_fw_load = 0;
+	}
+
+	return ret;
+}
+
+/* Take a basic firmware command structure, format it and forward it for processing */
+static int cx24116_cmd_execute(struct dvb_frontend* fe, struct cx24116_cmd *cmd)
+{
+	struct cx24116_state *state = fe->demodulator_priv;
+	int i, ret;
+
+	dprintk("%s()\n", __func__);
+
+	/* Load the firmware if required */
+	if ( (ret = cx24116_firmware_ondemand(fe)) != 0)
+	{
+		printk("%s(): Unable initialise the firmware\n", __func__);
+		return ret;
+	}
+
+	/* Write the command */
+	for(i = 0; i < cmd->len ; i++)
+	{
+		dprintk("%s: 0x%02x == 0x%02x\n", __func__, i, cmd->args[i]);
+		cx24116_writereg(state, i, cmd->args[i]);
+	}
+
+	/* Start execution and wait for cmd to terminate */
+	cx24116_writereg(state, CX24116_REG_EXECUTE, 0x01);
+	while( cx24116_readreg(state, CX24116_REG_EXECUTE) )
+	{
+		msleep(10);
+		if(i++ > 64)
+		{
+			/* Avoid looping forever if the firmware does no respond */
+			printk("%s() Firmware not responding\n", __func__);
+			return -EREMOTEIO;
+		}
+	}
+	return 0;
+}
+
+static int cx24116_load_firmware (struct dvb_frontend* fe, const struct firmware *fw)
+{
+	struct cx24116_state* state = fe->demodulator_priv;
+	struct cx24116_cmd cmd;
+	int i, ret;
+	unsigned char vers[4];
+
+	dprintk("%s\n", __func__);
+	dprintk("Firmware is %zu bytes (%02x %02x .. %02x %02x)\n"
+			,fw->size
+			,fw->data[0]
+			,fw->data[1]
+			,fw->data[ fw->size-2 ]
+			,fw->data[ fw->size-1 ]
+			);
+
+	/* Toggle 88x SRST pin to reset demod */
+	if (state->config->reset_device)
+		state->config->reset_device(fe);
+
+	/* Begin the firmware load process */
+	/* Prepare the demod, load the firmware, cleanup after load */
+
+	/* Init PLL */
+	cx24116_writereg(state, 0xE5, 0x00);
+	cx24116_writereg(state, 0xF1, 0x08);
+	cx24116_writereg(state, 0xF2, 0x13);
+
+	/* Start PLL */
+	cx24116_writereg(state, 0xe0, 0x03);
+	cx24116_writereg(state, 0xe0, 0x00);
+
+	/* Unknown */
+	cx24116_writereg(state, CX24116_REG_CLKDIV, 0x46);
+	cx24116_writereg(state, CX24116_REG_RATEDIV, 0x00);
+
+	/* Unknown */
+	cx24116_writereg(state, 0xF0, 0x03);
+	cx24116_writereg(state, 0xF4, 0x81);
+	cx24116_writereg(state, 0xF5, 0x00);
+	cx24116_writereg(state, 0xF6, 0x00);
+
+	/* write the entire firmware as one transaction */
+	cx24116_writeregN(state, 0xF7, fw->data, fw->size);
+
+	cx24116_writereg(state, 0xF4, 0x10);
+	cx24116_writereg(state, 0xF0, 0x00);
+	cx24116_writereg(state, 0xF8, 0x06);
+
+	/* Firmware CMD 10: VCO config */
+	cmd.args[0x00] = CMD_SET_VCO;
+	cmd.args[0x01] = 0x05;
+	cmd.args[0x02] = 0xdc;
+	cmd.args[0x03] = 0xda;
+	cmd.args[0x04] = 0xae;
+	cmd.args[0x05] = 0xaa;
+	cmd.args[0x06] = 0x04;
+	cmd.args[0x07] = 0x9d;
+	cmd.args[0x08] = 0xfc;
+	cmd.args[0x09] = 0x06;
+	cmd.len= 0x0a;
+	ret = cx24116_cmd_execute(fe, &cmd);
+	if (ret != 0)
+		return ret;
+
+	cx24116_writereg(state, CX24116_REG_SSTATUS, 0x00);
+
+	/* Firmware CMD 14: Tuner config */
+	cmd.args[0x00] = CMD_TUNERINIT;
+	cmd.args[0x01] = 0x00;
+	cmd.args[0x02] = 0x00;
+	cmd.len= 0x03;
+	ret = cx24116_cmd_execute(fe, &cmd);
+	if (ret != 0)
+		return ret;
+
+	cx24116_writereg(state, 0xe5, 0x00);
+
+	/* Firmware CMD 13: MPEG config */
+	cmd.args[0x00] = CMD_MPEGCONFIG;
+	cmd.args[0x01] = 0x01;
+	cmd.args[0x02] = 0x75;
+	cmd.args[0x03] = 0x00;
+	if (state->config->mpg_clk_pos_pol)
+		cmd.args[0x04] = state->config->mpg_clk_pos_pol;
+	else
+		cmd.args[0x04] = 0x02;
+	cmd.args[0x05] = 0x00;
+	cmd.len= 0x06;
+	ret = cx24116_cmd_execute(fe, &cmd);
+	if (ret != 0)
+		return ret;
+
+	/* Firmware CMD 35: Get firmware version */
+	cmd.args[0x00] = CMD_UPDFWVERS;
+	cmd.len= 0x02;
+	for(i=0; i<4; i++) {
+		cmd.args[0x01] = i;
+		ret = cx24116_cmd_execute(fe, &cmd);
+		if (ret != 0)
+			return ret;
+		vers[i]= cx24116_readreg(state, CX24116_REG_MAILBOX);
+	}
+	printk("%s: FW version %i.%i.%i.%i\n", __func__,
+		vers[0], vers[1], vers[2], vers[3]);
+
+	return 0;
+}
+
+static int cx24116_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage)
+{
+	/* The isl6421 module will override this function in the fops. */
+	dprintk("%s() This should never appear if the isl6421 module is loaded correctly\n",__func__);
+
+	return -EOPNOTSUPP;
+}
+
+static int cx24116_read_status(struct dvb_frontend* fe, fe_status_t* status)
+{
+	struct cx24116_state *state = fe->demodulator_priv;
+
+	int lock = cx24116_readreg(state, CX24116_REG_SSTATUS);
+
+	dprintk("%s: status = 0x%02x\n", __func__, lock);
+
+	*status = 0;
+
+	if (lock & CX24116_HAS_SIGNAL)
+		*status |= FE_HAS_SIGNAL;
+	if (lock & CX24116_HAS_CARRIER)
+		*status |= FE_HAS_CARRIER;
+	if (lock & CX24116_HAS_VITERBI)
+		*status |= FE_HAS_VITERBI;
+	if (lock & CX24116_HAS_SYNCLOCK)
+		*status |= FE_HAS_SYNC | FE_HAS_LOCK;
+
+	return 0;
+}
+
+static int cx24116_read_ber(struct dvb_frontend* fe, u32* ber)
+{
+	struct cx24116_state *state = fe->demodulator_priv;
+
+	dprintk("%s()\n", __func__);
+
+	*ber =  ( cx24116_readreg(state, CX24116_REG_BER24) << 24 ) |
+		( cx24116_readreg(state, CX24116_REG_BER16) << 16 ) |
+		( cx24116_readreg(state, CX24116_REG_BER8 ) << 8  ) |
+		  cx24116_readreg(state, CX24116_REG_BER0 );
+
+	return 0;
+}
+
+/* TODO Determine function and scale appropriately */
+static int cx24116_read_signal_strength(struct dvb_frontend* fe, u16* signal_strength)
+{
+	struct cx24116_state *state = fe->demodulator_priv;
+	struct cx24116_cmd cmd;
+	int ret;
+	u16 sig_reading;
+
+	dprintk("%s()\n", __func__);
+
+	/* Firmware CMD 19: Get AGC */
+	cmd.args[0x00] = CMD_GETAGC;
+	cmd.len= 0x01;
+	ret = cx24116_cmd_execute(fe, &cmd);
+	if (ret != 0)
+		return ret;
+
+	sig_reading = ( cx24116_readreg(state, CX24116_REG_SSTATUS) & CX24116_SIGNAL_MASK ) |
+		( cx24116_readreg(state, CX24116_REG_SIGNAL) << 6 );
+	*signal_strength= 0 - sig_reading;
+
+	dprintk("%s: raw / cooked = 0x%04x / 0x%04x\n", __func__, sig_reading, *signal_strength);
+
+	return 0;
+}
+
+/* SNR (0..100)% = (sig & 0xf0) * 10 + (sig & 0x0f) * 10 / 16 */
+static int cx24116_read_snr_pct(struct dvb_frontend* fe, u16* snr)
+{
+	struct cx24116_state *state = fe->demodulator_priv;
+	u8 snr_reading;
+	static const u32 snr_tab[] = { /* 10 x Table (rounded up) */
+		0x00000,0x0199A,0x03333,0x04ccD,0x06667,
+			0x08000,0x0999A,0x0b333,0x0cccD,0x0e667,
+		0x10000,0x1199A,0x13333,0x14ccD,0x16667,0x18000 };
+
+	dprintk("%s()\n", __func__);
+
+	snr_reading = cx24116_readreg(state, CX24116_REG_QUALITY0);
+
+	if(snr_reading >= 0xa0 /* 100% */)
+		*snr = 0xffff;
+	else
+		*snr = snr_tab [ ( snr_reading & 0xf0 )   >> 4 ] +
+			( snr_tab [ ( snr_reading & 0x0f ) ] >> 4 );
+
+	dprintk("%s: raw / cooked = 0x%02x / 0x%04x\n", __func__,
+		snr_reading, *snr);
+
+	return 0;
+}
+
+/* The reelbox patches show the value in the registers represents
+ * ESNO, from 0->30db (values 0->300). We provide this value by
+ * default.
+ */
+static int cx24116_read_snr_esno(struct dvb_frontend* fe, u16* snr)
+{
+	struct cx24116_state *state = fe->demodulator_priv;
+
+	dprintk("%s()\n", __func__);
+
+	*snr = cx24116_readreg(state, CX24116_REG_QUALITY8) << 8 |
+		cx24116_readreg(state, CX24116_REG_QUALITY0);
+
+	dprintk("%s: raw 0x%04x\n", __func__, *snr);
+
+	return 0;
+}
+
+static int cx24116_read_snr(struct dvb_frontend* fe, u16* snr)
+{
+	if (esno_snr == 1)
+		return cx24116_read_snr_esno(fe, snr);
+	else
+		return cx24116_read_snr_pct(fe, snr);
+}
+
+static int cx24116_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
+{
+	struct cx24116_state *state = fe->demodulator_priv;
+
+	dprintk("%s()\n", __func__);
+
+	*ucblocks = ( cx24116_readreg(state, CX24116_REG_UCB8) << 8 ) |
+		cx24116_readreg(state, CX24116_REG_UCB0);
+
+	return 0;
+}
+
+/* Overwrite the current tuning params, we are about to tune */
+static void cx24116_clone_params(struct dvb_frontend* fe)
+{
+	struct cx24116_state *state = fe->demodulator_priv;
+	memcpy(&state->dcur, &state->dnxt, sizeof(state->dcur));
+}
+
+/* Wait for LNB */
+static int cx24116_wait_for_lnb(struct dvb_frontend* fe)
+{
+	struct cx24116_state *state = fe->demodulator_priv;
+	int i;
+
+	dprintk("%s() qstatus = 0x%02x\n", __func__,
+		cx24116_readreg(state, CX24116_REG_QSTATUS));
+
+	/* Wait for up to 300 ms */
+	for(i = 0; i < 30 ; i++) {
+		if (cx24116_readreg(state, CX24116_REG_QSTATUS) & 0x20)
+			return 0;
+		msleep(10);
+	}
+
+	dprintk("%s(): LNB not ready\n", __func__);
+
+	return -ETIMEDOUT; /* -EBUSY ? */
+}
+
+static int cx24116_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
+{
+	struct cx24116_cmd cmd;
+	int ret;
+
+	dprintk("%s(%d)\n", __func__, tone);
+	if ( (tone != SEC_TONE_ON) && (tone != SEC_TONE_OFF) ) {
+		printk("%s: Invalid, tone=%d\n", __func__, tone);
+		return -EINVAL;
+	}
+
+	/* Wait for LNB ready */
+	ret = cx24116_wait_for_lnb(fe);
+	if(ret != 0)
+		return ret;
+
+	/* Min delay time after DiSEqC send */
+	msleep(15); /* XXX determine is FW does this, see send_diseqc/burst */
+
+	/* This is always done before the tone is set */
+	cmd.args[0x00] = CMD_SET_TONEPRE;
+	cmd.args[0x01] = 0x00;
+	cmd.len= 0x02;
+	ret = cx24116_cmd_execute(fe, &cmd);
+	if (ret != 0)
+		return ret;
+
+	/* Now we set the tone */
+	cmd.args[0x00] = CMD_SET_TONE;
+	cmd.args[0x01] = 0x00;
+	cmd.args[0x02] = 0x00;
+
+	switch (tone) {
+	case SEC_TONE_ON:
+		dprintk("%s: setting tone on\n", __func__);
+		cmd.args[0x03] = 0x01;
+		break;
+	case SEC_TONE_OFF:
+		dprintk("%s: setting tone off\n",__func__);
+		cmd.args[0x03] = 0x00;
+		break;
+	}
+	cmd.len= 0x04;
+
+	/* Min delay time before DiSEqC send */
+	msleep(15); /* XXX determine is FW does this, see send_diseqc/burst */
+
+	return cx24116_cmd_execute(fe, &cmd);
+}
+
+/* Initialise DiSEqC */
+static int cx24116_diseqc_init(struct dvb_frontend* fe)
+{
+	struct cx24116_state *state = fe->demodulator_priv;
+	struct cx24116_cmd cmd;
+	int ret;
+
+	/* Firmware CMD 20: LNB/DiSEqC config */
+	cmd.args[0x00] = CMD_LNBCONFIG;
+	cmd.args[0x01] = 0x00;
+	cmd.args[0x02] = 0x10;
+	cmd.args[0x03] = 0x00;
+	cmd.args[0x04] = 0x8f;
+	cmd.args[0x05] = 0x28;
+	cmd.args[0x06] = (toneburst == CX24116_DISEQC_TONEOFF) ? 0x00 : 0x01;
+	cmd.args[0x07] = 0x01;
+	cmd.len= 0x08;
+	ret = cx24116_cmd_execute(fe, &cmd);
+	if (ret != 0)
+		return ret;
+
+	/* Prepare a DiSEqC command */
+	state->dsec_cmd.args[0x00] = CMD_LNBSEND;
+
+	/* DiSEqC burst */
+	state->dsec_cmd.args[CX24116_DISEQC_BURST]  = CX24116_DISEQC_MINI_A;
+
+	/* Unknown */
+	state->dsec_cmd.args[CX24116_DISEQC_ARG2_2] = 0x02;
+	state->dsec_cmd.args[CX24116_DISEQC_ARG3_0] = 0x00;
+	state->dsec_cmd.args[CX24116_DISEQC_ARG4_0] = 0x00; /* Continuation flag? */
+
+	/* DiSEqC message length */
+	state->dsec_cmd.args[CX24116_DISEQC_MSGLEN] = 0x00;
+
+	/* Command length */
+	state->dsec_cmd.len= CX24116_DISEQC_MSGOFS;
+
+	return 0;
+}
+
+/* Send DiSEqC message with derived burst (hack) || previous burst */
+static int cx24116_send_diseqc_msg(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd *d)
+{
+	struct cx24116_state *state = fe->demodulator_priv;
+	int i, ret;
+
+	/* Dump DiSEqC message */
+	if (debug) {
+		printk("cx24116: %s(", __func__);
+		for(i = 0 ; i < d->msg_len ;) {
+			printk("0x%02x", d->msg[i]);
+			if(++i < d->msg_len)
+				printk(", ");
+			}
+		printk(") toneburst=%d\n", toneburst);
+	}
+
+	/* Validate length */
+	if(d->msg_len > (CX24116_ARGLEN - CX24116_DISEQC_MSGOFS))
+		return -EINVAL;
+
+	/* DiSEqC message */
+	for (i = 0; i < d->msg_len; i++)
+		state->dsec_cmd.args[CX24116_DISEQC_MSGOFS + i] = d->msg[i];
+
+	/* DiSEqC message length */
+	state->dsec_cmd.args[CX24116_DISEQC_MSGLEN] = d->msg_len;
+
+	/* Command length */
+	state->dsec_cmd.len= CX24116_DISEQC_MSGOFS + state->dsec_cmd.args[CX24116_DISEQC_MSGLEN];
+
+	/* DiSEqC toneburst */
+	if(toneburst == CX24116_DISEQC_MESGCACHE)
+		/* Message is cached */
+		return 0;
+
+	else if(toneburst == CX24116_DISEQC_TONEOFF)
+		/* Message is sent without burst */
+		state->dsec_cmd.args[CX24116_DISEQC_BURST] = 0;
+
+	else if(toneburst == CX24116_DISEQC_TONECACHE) {
+		/*
+		 * Message is sent with derived else cached burst
+		 *
+		 * WRITE PORT GROUP COMMAND 38
+		 *
+		 * 0/A/A: E0 10 38 F0..F3
+		 * 1/B/B: E0 10 38 F4..F7
+		 * 2/C/A: E0 10 38 F8..FB
+		 * 3/D/B: E0 10 38 FC..FF
+		 *
+		 * databyte[3]= 8421:8421
+		 *              ABCD:WXYZ
+		 *              CLR :SET
+		 *
+		 *              WX= PORT SELECT 0..3    (X=TONEBURST)
+		 *              Y = VOLTAGE             (0=13V, 1=18V)
+		 *              Z = BAND                (0=LOW, 1=HIGH(22K))
+		 */
+		if(d->msg_len >= 4 && d->msg[2] == 0x38)
+			state->dsec_cmd.args[CX24116_DISEQC_BURST] = ((d->msg[3] & 4) >> 2);
+		if(debug)
+			dprintk("%s burst=%d\n", __func__, state->dsec_cmd.args[CX24116_DISEQC_BURST]);
+	}
+
+	/* Wait for LNB ready */
+	ret = cx24116_wait_for_lnb(fe);
+	if(ret != 0)
+		return ret;
+
+	/* Wait for voltage/min repeat delay */
+	msleep(100);
+
+	/* Command */
+	ret = cx24116_cmd_execute(fe, &state->dsec_cmd);
+	if(ret != 0)
+		return ret;
+	/*
+	 * Wait for send
+	 *
+	 * Eutelsat spec:
+	 * >15ms delay          + (XXX determine if FW does this, see set_tone)
+	 *  13.5ms per byte     +
+	 * >15ms delay          +
+	 *  12.5ms burst        +
+	 * >15ms delay            (XXX determine if FW does this, see set_tone)
+	 */
+	msleep( (state->dsec_cmd.args[CX24116_DISEQC_MSGLEN] << 4) + ((toneburst == CX24116_DISEQC_TONEOFF) ? 30 : 60) );
+
+	return 0;
+}
+
+/* Send DiSEqC burst */
+static int cx24116_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t burst)
+{
+	struct cx24116_state *state = fe->demodulator_priv;
+	int ret;
+
+	dprintk("%s(%d) toneburst=%d\n",__func__, burst, toneburst);
+
+	/* DiSEqC burst */
+	if (burst == SEC_MINI_A)
+		state->dsec_cmd.args[CX24116_DISEQC_BURST] = CX24116_DISEQC_MINI_A;
+	else if(burst == SEC_MINI_B)
+		state->dsec_cmd.args[CX24116_DISEQC_BURST] = CX24116_DISEQC_MINI_B;
+	else
+		return -EINVAL;
+
+	/* DiSEqC toneburst */
+	if(toneburst != CX24116_DISEQC_MESGCACHE)
+		/* Burst is cached */
+		return 0;
+
+	/* Burst is to be sent with cached message */
+
+	/* Wait for LNB ready */
+	ret = cx24116_wait_for_lnb(fe);
+	if(ret != 0)
+		return ret;
+
+	/* Wait for voltage/min repeat delay */
+	msleep(100);
+
+	/* Command */
+	ret = cx24116_cmd_execute(fe, &state->dsec_cmd);
+	if(ret != 0)
+		return ret;
+
+	/*
+	 * Wait for send
+	 *
+	 * Eutelsat spec:
+	 * >15ms delay          + (XXX determine if FW does this, see set_tone)
+	 *  13.5ms per byte     +
+	 * >15ms delay          +
+	 *  12.5ms burst        +
+	 * >15ms delay            (XXX determine if FW does this, see set_tone)
+	 */
+	msleep( (state->dsec_cmd.args[CX24116_DISEQC_MSGLEN] << 4) + 60 );
+
+	return 0;
+}
+
+static void cx24116_release(struct dvb_frontend* fe)
+{
+	struct cx24116_state* state = fe->demodulator_priv;
+	dprintk("%s\n",__func__);
+	kfree(state);
+}
+
+static struct dvb_frontend_ops cx24116_ops;
+
+struct dvb_frontend* cx24116_attach(const struct cx24116_config* config,
+				    struct i2c_adapter* i2c)
+{
+	struct cx24116_state* state = NULL;
+	int ret;
+
+	dprintk("%s\n",__func__);
+
+	/* allocate memory for the internal state */
+	state = kmalloc(sizeof(struct cx24116_state), GFP_KERNEL);
+	if (state == NULL) {
+		printk("Unable to kmalloc\n");
+		goto error1;
+	}
+
+	/* setup the state */
+	memset(state, 0, sizeof(struct cx24116_state));
+
+	state->config = config;
+	state->i2c = i2c;
+
+	/* check if the demod is present */
+	ret = (cx24116_readreg(state, 0xFF) << 8) | cx24116_readreg(state, 0xFE);
+	if (ret != 0x0501) {
+		printk("Invalid probe, probably not a CX24116 device\n");
+		goto error2;
+	}
+
+	/* create dvb_frontend */
+	memcpy(&state->frontend.ops, &cx24116_ops, sizeof(struct dvb_frontend_ops));
+	state->frontend.demodulator_priv = state;
+	return &state->frontend;
+
+error2: kfree(state);
+error1: return NULL;
+}
+/*
+ * Initialise or wake up device
+ *
+ * Power config will reset and load initial firmware if required
+ */
+static int cx24116_initfe(struct dvb_frontend* fe)
+{
+	struct cx24116_state* state = fe->demodulator_priv;
+	struct cx24116_cmd cmd;
+	int ret;
+
+	dprintk("%s()\n",__func__);
+
+	/* Power on */
+	cx24116_writereg(state, 0xe0, 0);
+	cx24116_writereg(state, 0xe1, 0);
+	cx24116_writereg(state, 0xea, 0);
+
+	/* Firmware CMD 36: Power config */
+	cmd.args[0x00] = CMD_TUNERSLEEP;
+	cmd.args[0x01] = 0;
+	cmd.len= 0x02;
+	ret = cx24116_cmd_execute(fe, &cmd);
+	if(ret != 0)
+		return ret;
+
+	return cx24116_diseqc_init(fe);
+}
+
+/*
+ * Put device to sleep
+ */
+static int cx24116_sleep(struct dvb_frontend* fe)
+{
+	struct cx24116_state* state = fe->demodulator_priv;
+	struct cx24116_cmd cmd;
+	int ret;
+
+	dprintk("%s()\n",__func__);
+
+	/* Firmware CMD 36: Power config */
+	cmd.args[0x00] = CMD_TUNERSLEEP;
+	cmd.args[0x01] = 1;
+	cmd.len= 0x02;
+	ret = cx24116_cmd_execute(fe, &cmd);
+	if(ret != 0)
+		return ret;
+
+	/* Power off (Shutdown clocks) */
+	cx24116_writereg(state, 0xea, 0xff);
+	cx24116_writereg(state, 0xe1, 1);
+	cx24116_writereg(state, 0xe0, 1);
+
+	return 0;
+}
+
+static int cx24116_set_property(struct dvb_frontend *fe, struct dtv_property* tvp)
+{
+	dprintk("%s(..)\n", __func__);
+	return 0;
+}
+
+static int cx24116_get_property(struct dvb_frontend *fe, struct dtv_property* tvp)
+{
+	dprintk("%s(..)\n", __func__);
+	return 0;
+}
+
+/* dvb-core told us to tune, the tv property cache will be complete,
+ * it's safe for is to pull values and use them for tuning purposes.
+ */
+static int cx24116_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
+{
+	struct cx24116_state *state = fe->demodulator_priv;
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+	struct cx24116_cmd cmd;
+	fe_status_t tunerstat;
+	int i, status, ret, retune;
+
+	dprintk("%s()\n",__func__);
+
+	switch(c->delivery_system) {
+		case SYS_DVBS:
+			dprintk("%s: DVB-S delivery system selected\n",__func__);
+
+			/* Only QPSK is supported for DVB-S */
+			if(c->modulation != QPSK) {
+				dprintk("%s: unsupported modulation selected (%d)\n",
+					__func__, c->modulation);
+				return -EOPNOTSUPP;
+			}
+
+			/* Pilot doesn't exist in DVB-S, turn bit off */
+			state->dnxt.pilot_val = CX24116_PILOT_OFF;
+			retune = 1;
+
+			/* DVB-S only supports 0.35 */
+			if(c->rolloff != ROLLOFF_35) {
+				dprintk("%s: unsupported rolloff selected (%d)\n",
+					__func__, c->rolloff);
+				return -EOPNOTSUPP;
+			}
+			state->dnxt.rolloff_val = CX24116_ROLLOFF_035;
+			break;
+
+		case SYS_DVBS2:
+			dprintk("%s: DVB-S2 delivery system selected\n",__func__);
+
+			/*
+			 * NBC 8PSK/QPSK with DVB-S is supported for DVB-S2,
+			 * but not hardware auto detection
+			 */
+			if(c->modulation != PSK_8 && c->modulation != QPSK) {
+				dprintk("%s: unsupported modulation selected (%d)\n",
+					__func__, c->modulation);
+				return -EOPNOTSUPP;
+			}
+
+			switch(c->pilot) {
+				case PILOT_AUTO:	/* Not supported but emulated */
+					retune = 2;	/* Fall-through */
+				case PILOT_OFF:
+					state->dnxt.pilot_val = CX24116_PILOT_OFF;
+					break;
+				case PILOT_ON:
+					state->dnxt.pilot_val = CX24116_PILOT_ON;
+					break;
+				default:
+					dprintk("%s: unsupported pilot mode selected (%d)\n",
+						__func__, c->pilot);
+					return -EOPNOTSUPP;
+			}
+
+			switch(c->rolloff) {
+				case ROLLOFF_20:
+					state->dnxt.rolloff_val= CX24116_ROLLOFF_020;
+					break;
+				case ROLLOFF_25:
+					state->dnxt.rolloff_val= CX24116_ROLLOFF_025;
+					break;
+				case ROLLOFF_35:
+					state->dnxt.rolloff_val= CX24116_ROLLOFF_035;
+					break;
+				case ROLLOFF_AUTO:	/* Rolloff must be explicit */
+				default:
+					dprintk("%s: unsupported rolloff selected (%d)\n",
+						__func__, c->rolloff);
+					return -EOPNOTSUPP;
+			}
+			break;
+
+		default:
+			dprintk("%s: unsupported delivery system selected (%d)\n",
+				__func__, c->delivery_system);
+			return -EOPNOTSUPP;
+	}
+	state->dnxt.modulation = c->modulation;
+	state->dnxt.frequency = c->frequency;
+	state->dnxt.pilot = c->pilot;
+	state->dnxt.rolloff = c->rolloff;
+
+	if ((ret = cx24116_set_inversion(state, c->inversion)) !=  0)
+		return ret;
+
+	/* FEC_NONE/AUTO for DVB-S2 is not supported and detected here */
+	if ((ret = cx24116_set_fec(state, c->modulation, c->fec_inner)) !=  0)
+		return ret;
+
+	if ((ret = cx24116_set_symbolrate(state, c->symbol_rate)) !=  0)
+		return ret;
+
+	/* discard the 'current' tuning parameters and prepare to tune */
+	cx24116_clone_params(fe);
+
+	dprintk("%s:   modulation  = %d\n", __func__, state->dcur.modulation);
+	dprintk("%s:   frequency   = %d\n", __func__, state->dcur.frequency);
+	dprintk("%s:   pilot       = %d (val = 0x%02x)\n", __func__,
+		state->dcur.pilot, state->dcur.pilot_val);
+	dprintk("%s:   retune      = %d\n", __func__, retune);
+	dprintk("%s:   rolloff     = %d (val = 0x%02x)\n", __func__,
+		state->dcur.rolloff, state->dcur.rolloff_val);
+	dprintk("%s:   symbol_rate = %d\n", __func__, state->dcur.symbol_rate);
+	dprintk("%s:   FEC         = %d (mask/val = 0x%02x/0x%02x)\n", __func__,
+		state->dcur.fec, state->dcur.fec_mask, state->dcur.fec_val);
+	dprintk("%s:   Inversion   = %d (val = 0x%02x)\n", __func__,
+		state->dcur.inversion, state->dcur.inversion_val);
+
+	/* This is also done in advise/acquire on HVR4000 but not on LITE */
+	if (state->config->set_ts_params)
+		state->config->set_ts_params(fe, 0);
+
+	/* Set/Reset B/W */
+	cmd.args[0x00] = CMD_BANDWIDTH;
+	cmd.args[0x01] = 0x01;
+	cmd.len= 0x02;
+	ret = cx24116_cmd_execute(fe, &cmd);
+	if (ret != 0)
+		return ret;
+
+	/* Prepare a tune request */
+	cmd.args[0x00] = CMD_TUNEREQUEST;
+
+	/* Frequency */
+	cmd.args[0x01] = (state->dcur.frequency & 0xff0000) >> 16;
+	cmd.args[0x02] = (state->dcur.frequency & 0x00ff00) >> 8;
+	cmd.args[0x03] = (state->dcur.frequency & 0x0000ff);
+
+	/* Symbol Rate */
+	cmd.args[0x04] = ((state->dcur.symbol_rate / 1000) & 0xff00) >> 8;
+	cmd.args[0x05] = ((state->dcur.symbol_rate / 1000) & 0x00ff);
+
+	/* Automatic Inversion */
+	cmd.args[0x06] = state->dcur.inversion_val;
+
+	/* Modulation / FEC / Pilot */
+	cmd.args[0x07] = state->dcur.fec_val | state->dcur.pilot_val;
+
+	cmd.args[0x08] = CX24116_SEARCH_RANGE_KHZ >> 8;
+	cmd.args[0x09] = CX24116_SEARCH_RANGE_KHZ & 0xff;
+	cmd.args[0x0a] = 0x00;
+	cmd.args[0x0b] = 0x00;
+	cmd.args[0x0c] = state->dcur.rolloff_val;
+	cmd.args[0x0d] = state->dcur.fec_mask;
+
+	if (state->dcur.symbol_rate > 30000000) {
+		cmd.args[0x0e] = 0x04;
+		cmd.args[0x0f] = 0x00;
+		cmd.args[0x10] = 0x01;
+		cmd.args[0x11] = 0x77;
+		cmd.args[0x12] = 0x36;
+		cx24116_writereg(state, CX24116_REG_CLKDIV, 0x44);
+		cx24116_writereg(state, CX24116_REG_RATEDIV, 0x01);
+	} else {
+		cmd.args[0x0e] = 0x06;
+		cmd.args[0x0f] = 0x00;
+		cmd.args[0x10] = 0x00;
+		cmd.args[0x11] = 0xFA;
+		cmd.args[0x12] = 0x24;
+		cx24116_writereg(state, CX24116_REG_CLKDIV, 0x46);
+		cx24116_writereg(state, CX24116_REG_RATEDIV, 0x00);
+	}
+
+	cmd.len= 0x13;
+
+	/* We need to support pilot and non-pilot tuning in the
+	 * driver automatically. This is a workaround for because
+	 * the demod does not support autodetect.
+	 */
+	do {
+		/* Reset status register */
+		status = cx24116_readreg(state, CX24116_REG_SSTATUS) & CX24116_SIGNAL_MASK;
+		cx24116_writereg(state, CX24116_REG_SSTATUS, status);
+
+		/* Tune */
+		ret = cx24116_cmd_execute(fe, &cmd);
+		if( ret != 0 )
+			break;
+
+		/*
+		 * Wait for up to 500 ms before retrying
+		 *
+		 * If we are able to tune then generally it occurs within 100ms.
+		 * If it takes longer, try a different toneburst setting.
+		 */
+		for(i = 0; i < 50 ; i++) {
+			cx24116_read_status(fe, &tunerstat);
+			status = tunerstat & (FE_HAS_SIGNAL | FE_HAS_SYNC);
+			if(status == (FE_HAS_SIGNAL | FE_HAS_SYNC)) {
+				dprintk("%s: Tuned\n",__func__);
+				goto tuned;
+			}
+			msleep(10);
+		}
+
+		dprintk("%s: Not tuned\n",__func__);
+
+		/* Toggle pilot bit when in auto-pilot */
+		if(state->dcur.pilot == PILOT_AUTO)
+			cmd.args[0x07] ^= CX24116_PILOT_ON;
+	}
+	while(--retune);
+
+tuned:  /* Set/Reset B/W */
+	cmd.args[0x00] = CMD_BANDWIDTH;
+	cmd.args[0x01] = 0x00;
+	cmd.len= 0x02;
+	ret = cx24116_cmd_execute(fe, &cmd);
+	if (ret != 0)
+		return ret;
+
+	return ret;
+}
+
+static struct dvb_frontend_ops cx24116_ops = {
+
+	.info = {
+		.name = "Conexant CX24116/CX24118",
+		.type = FE_QPSK,
+		.frequency_min = 950000,
+		.frequency_max = 2150000,
+		.frequency_stepsize = 1011, /* kHz for QPSK frontends */
+		.frequency_tolerance = 5000,
+		.symbol_rate_min = 1000000,
+		.symbol_rate_max = 45000000,
+		.caps = FE_CAN_INVERSION_AUTO |
+			FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+			FE_CAN_FEC_4_5 | FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 |
+			FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
+			FE_CAN_QPSK | FE_CAN_RECOVER
+	},
+
+	.release = cx24116_release,
+
+	.init = cx24116_initfe,
+	.sleep = cx24116_sleep,
+	.read_status = cx24116_read_status,
+	.read_ber = cx24116_read_ber,
+	.read_signal_strength = cx24116_read_signal_strength,
+	.read_snr = cx24116_read_snr,
+	.read_ucblocks = cx24116_read_ucblocks,
+	.set_tone = cx24116_set_tone,
+	.set_voltage = cx24116_set_voltage,
+	.diseqc_send_master_cmd = cx24116_send_diseqc_msg,
+	.diseqc_send_burst = cx24116_diseqc_send_burst,
+
+	.set_property = cx24116_set_property,
+	.get_property = cx24116_get_property,
+	.set_frontend = cx24116_set_frontend,
+};
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Activates frontend debugging (default:0)");
+
+module_param(toneburst, int, 0644);
+MODULE_PARM_DESC(toneburst, "DiSEqC toneburst 0=OFF, 1=TONE CACHE, 2=MESSAGE CACHE (default:1)");
+
+module_param(esno_snr, int, 0644);
+MODULE_PARM_DESC(debug, "SNR return units, 0=PERCENTAGE 0-100, 1=ESNO(db * 10) (default:0)");
+
+MODULE_DESCRIPTION("DVB Frontend module for Conexant cx24116/cx24118 hardware");
+MODULE_AUTHOR("Steven Toth");
+MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(cx24116_attach);
diff --git a/drivers/media/dvb/frontends/cx24116.h b/drivers/media/dvb/frontends/cx24116.h
new file mode 100644
index 0000000..8dbcec2
--- /dev/null
+++ b/drivers/media/dvb/frontends/cx24116.h
@@ -0,0 +1,53 @@
+/*
+    Conexant cx24116/cx24118 - DVBS/S2 Satellite demod/tuner driver
+
+    Copyright (C) 2006 Steven Toth <stoth@linuxtv.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.
+*/
+
+#ifndef CX24116_H
+#define CX24116_H
+
+#include <linux/dvb/frontend.h>
+
+struct cx24116_config
+{
+	/* the demodulator's i2c address */
+	u8 demod_address;
+
+	/* Need to set device param for start_dma */
+	int (*set_ts_params)(struct dvb_frontend* fe, int is_punctured);
+
+	/* Need to reset device during firmware loading */
+	int (*reset_device)(struct dvb_frontend* fe);
+
+	/* Need to set MPEG parameters */
+	u8 mpg_clk_pos_pol:0x02;
+};
+
+#if defined(CONFIG_DVB_CX24116) || defined(CONFIG_DVB_CX24116_MODULE)
+extern struct dvb_frontend* cx24116_attach(const struct cx24116_config* config,
+					   struct i2c_adapter* i2c);
+#else
+static inline struct dvb_frontend* cx24116_attach(const struct cx24116_config* config,
+						  struct i2c_adapter* i2c)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+	return NULL;
+}
+#endif // CONFIG_DVB_CX24116
+
+#endif /* CX24116_H */
diff --git a/drivers/media/dvb/frontends/dib0070.h b/drivers/media/dvb/frontends/dib0070.h
index 3eedfdf..21f2c51 100644
--- a/drivers/media/dvb/frontends/dib0070.h
+++ b/drivers/media/dvb/frontends/dib0070.h
@@ -41,6 +41,7 @@
 extern struct dvb_frontend *dib0070_attach(struct dvb_frontend *fe,
 					   struct i2c_adapter *i2c,
 					   struct dib0070_config *cfg);
+extern u16 dib0070_wbd_offset(struct dvb_frontend *);
 #else
 static inline struct dvb_frontend *dib0070_attach(struct dvb_frontend *fe,
 						  struct i2c_adapter *i2c,
@@ -49,9 +50,14 @@
 	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
 	return NULL;
 }
+
+static inline u16 dib0070_wbd_offset(struct dvb_frontend *fe)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return -ENODEV;
+}
 #endif
 
 extern void dib0070_ctrl_agc_filter(struct dvb_frontend *, uint8_t open);
-extern u16 dib0070_wbd_offset(struct dvb_frontend *);
 
 #endif
diff --git a/drivers/media/dvb/frontends/dib7000m.c b/drivers/media/dvb/frontends/dib7000m.c
index 5f1375e..0109720 100644
--- a/drivers/media/dvb/frontends/dib7000m.c
+++ b/drivers/media/dvb/frontends/dib7000m.c
@@ -1284,7 +1284,10 @@
 }
 EXPORT_SYMBOL(dib7000m_get_i2c_master);
 
-int dib7000m_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, struct dib7000m_config cfg[])
+#if 0
+/* used with some prototype boards */
+int dib7000m_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods,
+		u8 default_addr, struct dib7000m_config cfg[])
 {
 	struct dib7000m_state st = { .i2c_adap = i2c };
 	int k = 0;
@@ -1329,6 +1332,7 @@
 	return 0;
 }
 EXPORT_SYMBOL(dib7000m_i2c_enumeration);
+#endif
 
 static struct dvb_frontend_ops dib7000m_ops;
 struct dvb_frontend * dib7000m_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib7000m_config *cfg)
diff --git a/drivers/media/dvb/frontends/dib7000p.c b/drivers/media/dvb/frontends/dib7000p.c
index 1a0142e..8217e5b 100644
--- a/drivers/media/dvb/frontends/dib7000p.c
+++ b/drivers/media/dvb/frontends/dib7000p.c
@@ -1333,7 +1333,8 @@
 	/* Ensure the output mode remains at the previous default if it's
 	 * not specifically set by the caller.
 	 */
-	if (st->cfg.output_mode != OUTMODE_MPEG2_SERIAL)
+	if ((st->cfg.output_mode != OUTMODE_MPEG2_SERIAL) &&
+	    (st->cfg.output_mode != OUTMODE_MPEG2_PAR_GATED_CLK))
 		st->cfg.output_mode = OUTMODE_MPEG2_FIFO;
 
 	demod                   = &st->demod;
diff --git a/drivers/media/dvb/frontends/dib7000p.h b/drivers/media/dvb/frontends/dib7000p.h
index 07c4d12..3e81268 100644
--- a/drivers/media/dvb/frontends/dib7000p.h
+++ b/drivers/media/dvb/frontends/dib7000p.h
@@ -41,6 +41,14 @@
 extern struct dvb_frontend *dib7000p_attach(struct i2c_adapter *i2c_adap,
 					    u8 i2c_addr,
 					    struct dib7000p_config *cfg);
+extern struct i2c_adapter *dib7000p_get_i2c_master(struct dvb_frontend *,
+						   enum dibx000_i2c_interface,
+						   int);
+extern int dib7000p_i2c_enumeration(struct i2c_adapter *i2c,
+				    int no_of_demods, u8 default_addr,
+				    struct dib7000p_config cfg[]);
+extern int dib7000p_set_gpio(struct dvb_frontend *, u8 num, u8 dir, u8 val);
+extern int dib7000p_set_wbd_ref(struct dvb_frontend *, u16 value);
 #else
 static inline struct dvb_frontend *dib7000p_attach(struct i2c_adapter *i2c_adap,
 						   u8 i2c_addr,
@@ -49,13 +57,36 @@
 	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
 	return NULL;
 }
+
+static inline
+struct i2c_adapter *dib7000p_get_i2c_master(struct dvb_frontend *fe,
+					    enum dibx000_i2c_interface i, int x)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+
+extern int dib7000p_i2c_enumeration(struct i2c_adapter *i2c,
+				    int no_of_demods, u8 default_addr,
+				    struct dib7000p_config cfg[])
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return -ENODEV;
+}
+
+extern int dib7000p_set_gpio(struct dvb_frontend *fe, u8 num, u8 dir, u8 val)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return -ENODEV;
+}
+
+extern int dib7000p_set_wbd_ref(struct dvb_frontend *fe, u16 value)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return -ENODEV;
+}
 #endif
 
-extern int dib7000p_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, struct dib7000p_config cfg[]);
-
-extern struct i2c_adapter * dib7000p_get_i2c_master(struct dvb_frontend *, enum dibx000_i2c_interface, int);
 extern int dib7000pc_detection(struct i2c_adapter *i2c_adap);
-extern int dib7000p_set_gpio(struct dvb_frontend *, u8 num, u8 dir, u8 val);
-extern int dib7000p_set_wbd_ref(struct dvb_frontend *, u16 value);
 
 #endif
diff --git a/drivers/media/dvb/frontends/drx397xD.c b/drivers/media/dvb/frontends/drx397xD.c
index 3cbed87..b9ca5c8 100644
--- a/drivers/media/dvb/frontends/drx397xD.c
+++ b/drivers/media/dvb/frontends/drx397xD.c
@@ -38,35 +38,32 @@
 #define F_SET_0D0h	1
 #define F_SET_0D4h	2
 
-typedef enum fw_ix {
+enum fw_ix {
 #define _FW_ENTRY(a, b)		b
 #include "drx397xD_fw.h"
-} fw_ix_t;
+};
 
 /* chip specifics */
 struct drx397xD_state {
 	struct i2c_adapter *i2c;
 	struct dvb_frontend frontend;
 	struct drx397xD_config config;
-	fw_ix_t chip_rev;
+	enum fw_ix chip_rev;
 	int flags;
 	u32 bandwidth_parm;	/* internal bandwidth conversions */
 	u32 f_osc;		/* w90: actual osc frequency [Hz] */
 };
 
-/*******************************************************************************
- * Firmware
- ******************************************************************************/
-
+/* Firmware */
 static const char *blob_name[] = {
 #define _BLOB_ENTRY(a, b)		a
 #include "drx397xD_fw.h"
 };
 
-typedef enum blob_ix {
+enum blob_ix {
 #define _BLOB_ENTRY(a, b)		b
 #include "drx397xD_fw.h"
-} blob_ix_t;
+};
 
 static struct {
 	const char *name;
@@ -85,7 +82,7 @@
 };
 
 /* use only with writer lock aquired */
-static void _drx_release_fw(struct drx397xD_state *s, fw_ix_t ix)
+static void _drx_release_fw(struct drx397xD_state *s, enum fw_ix ix)
 {
 	memset(&fw[ix].data[0], 0, sizeof(fw[0].data));
 	if (fw[ix].file)
@@ -94,9 +91,9 @@
 
 static void drx_release_fw(struct drx397xD_state *s)
 {
-	fw_ix_t ix = s->chip_rev;
+	enum fw_ix ix = s->chip_rev;
 
-	pr_debug("%s\n", __FUNCTION__);
+	pr_debug("%s\n", __func__);
 
 	write_lock(&fw[ix].lock);
 	if (fw[ix].refcnt) {
@@ -107,13 +104,13 @@
 	write_unlock(&fw[ix].lock);
 }
 
-static int drx_load_fw(struct drx397xD_state *s, fw_ix_t ix)
+static int drx_load_fw(struct drx397xD_state *s, enum fw_ix ix)
 {
 	const u8 *data;
 	size_t size, len;
 	int i = 0, j, rc = -EINVAL;
 
-	pr_debug("%s\n", __FUNCTION__);
+	pr_debug("%s\n", __func__);
 
 	if (ix < 0 || ix >= ARRAY_SIZE(fw))
 		return -EINVAL;
@@ -175,32 +172,34 @@
 			goto exit_corrupt;
 		}
 	} while (i < size);
-      exit_corrupt:
+
+exit_corrupt:
 	printk(KERN_ERR "%s: Firmware is corrupt\n", mod_name);
-      exit_err:
+exit_err:
 	_drx_release_fw(s, ix);
 	fw[ix].refcnt--;
-      exit_ok:
+exit_ok:
 	fw[ix].refcnt++;
 	write_unlock(&fw[ix].lock);
+
 	return rc;
 }
 
-/*******************************************************************************
- * i2c bus IO
- ******************************************************************************/
-
-static int write_fw(struct drx397xD_state *s, blob_ix_t ix)
+/* i2c bus IO */
+static int write_fw(struct drx397xD_state *s, enum blob_ix ix)
 {
-	struct i2c_msg msg = {.addr = s->config.demod_address,.flags = 0 };
 	const u8 *data;
 	int len, rc = 0, i = 0;
+	struct i2c_msg msg = {
+		.addr = s->config.demod_address,
+		.flags = 0
+	};
 
 	if (ix < 0 || ix >= ARRAY_SIZE(blob_name)) {
-		pr_debug("%s drx_fw_ix_t out of range\n", __FUNCTION__);
+		pr_debug("%s drx_fw_ix_t out of range\n", __func__);
 		return -EINVAL;
 	}
-	pr_debug("%s %s\n", __FUNCTION__, blob_name[ix]);
+	pr_debug("%s %s\n", __func__, blob_name[ix]);
 
 	read_lock(&fw[s->chip_rev].lock);
 	data = fw[s->chip_rev].data[ix];
@@ -229,33 +228,33 @@
 			goto exit_rc;
 		}
 	}
-      exit_rc:
+exit_rc:
 	read_unlock(&fw[s->chip_rev].lock);
+
 	return 0;
 }
 
 /* Function is not endian safe, use the RD16 wrapper below */
-static int _read16(struct drx397xD_state *s, u32 i2c_adr)
+static int _read16(struct drx397xD_state *s, __le32 i2c_adr)
 {
 	int rc;
 	u8 a[4];
-	u16 v;
+	__le16 v;
 	struct i2c_msg msg[2] = {
 		{
-		 .addr = s->config.demod_address,
-		 .flags = 0,
-		 .buf = a,
-		 .len = sizeof(a)
-		 }
-		, {
-		   .addr = s->config.demod_address,
-		   .flags = I2C_M_RD,
-		   .buf = (u8 *) & v,
-		   .len = sizeof(v)
-		   }
+			.addr = s->config.demod_address,
+			.flags = 0,
+			.buf = a,
+			.len = sizeof(a)
+		}, {
+			.addr = s->config.demod_address,
+			.flags = I2C_M_RD,
+			.buf = (u8 *)&v,
+			.len = sizeof(v)
+		}
 	};
 
-	*(u32 *) a = i2c_adr;
+	*(__le32 *) a = i2c_adr;
 
 	rc = i2c_transfer(s->i2c, msg, 2);
 	if (rc != 2)
@@ -265,7 +264,7 @@
 }
 
 /* Function is not endian safe, use the WR16.. wrappers below */
-static int _write16(struct drx397xD_state *s, u32 i2c_adr, u16 val)
+static int _write16(struct drx397xD_state *s, __le32 i2c_adr, __le16 val)
 {
 	u8 a[6];
 	int rc;
@@ -276,28 +275,28 @@
 		.len = sizeof(a)
 	};
 
-	*(u32 *) a = i2c_adr;
-	*(u16 *) & a[4] = val;
+	*(__le32 *)a = i2c_adr;
+	*(__le16 *)&a[4] = val;
 
 	rc = i2c_transfer(s->i2c, &msg, 1);
 	if (rc != 1)
 		return -EIO;
+
 	return 0;
 }
 
-#define WR16(ss,adr, val) \
+#define WR16(ss, adr, val) \
 		_write16(ss, I2C_ADR_C0(adr), cpu_to_le16(val))
-#define WR16_E0(ss,adr, val) \
+#define WR16_E0(ss, adr, val) \
 		_write16(ss, I2C_ADR_E0(adr), cpu_to_le16(val))
-#define RD16(ss,adr) \
+#define RD16(ss, adr) \
 		_read16(ss, I2C_ADR_C0(adr))
 
-#define EXIT_RC( cmd )	if ( (rc = (cmd)) < 0) goto exit_rc
+#define EXIT_RC(cmd)	\
+	if ((rc = (cmd)) < 0)	\
+		goto exit_rc
 
-/*******************************************************************************
- * Tuner callback
- ******************************************************************************/
-
+/* Tuner callback */
 static int PLL_Set(struct drx397xD_state *s,
 		   struct dvb_frontend_parameters *fep, int *df_tuner)
 {
@@ -305,7 +304,7 @@
 	u32 f_tuner, f = fep->frequency;
 	int rc;
 
-	pr_debug("%s\n", __FUNCTION__);
+	pr_debug("%s\n", __func__);
 
 	if ((f > s->frontend.ops.tuner_ops.info.frequency_max) ||
 	    (f < s->frontend.ops.tuner_ops.info.frequency_min))
@@ -325,28 +324,26 @@
 		return rc;
 
 	*df_tuner = f_tuner - f;
-	pr_debug("%s requested %d [Hz] tuner %d [Hz]\n", __FUNCTION__, f,
+	pr_debug("%s requested %d [Hz] tuner %d [Hz]\n", __func__, f,
 		 f_tuner);
 
 	return 0;
 }
 
-/*******************************************************************************
- * Demodulator helper functions
- ******************************************************************************/
-
+/* Demodulator helper functions */
 static int SC_WaitForReady(struct drx397xD_state *s)
 {
 	int cnt = 1000;
 	int rc;
 
-	pr_debug("%s\n", __FUNCTION__);
+	pr_debug("%s\n", __func__);
 
 	while (cnt--) {
 		rc = RD16(s, 0x820043);
 		if (rc == 0)
 			return 0;
 	}
+
 	return -1;
 }
 
@@ -354,13 +351,14 @@
 {
 	int rc;
 
-	pr_debug("%s\n", __FUNCTION__);
+	pr_debug("%s\n", __func__);
 
 	WR16(s, 0x820043, cmd);
 	SC_WaitForReady(s);
 	rc = RD16(s, 0x820042);
 	if ((rc & 0xffff) == 0xffff)
 		return -1;
+
 	return 0;
 }
 
@@ -368,7 +366,7 @@
 {
 	int rc, cnt = 1000;
 
-	pr_debug("%s\n", __FUNCTION__);
+	pr_debug("%s\n", __func__);
 
 	rc = WR16(s, 0x420032, cmd);
 	if (rc < 0)
@@ -383,22 +381,24 @@
 		if (rc < 0)
 			return rc;
 	} while (--cnt);
+
 	return rc;
 }
 
 static int HI_CfgCommand(struct drx397xD_state *s)
 {
 
-	pr_debug("%s\n", __FUNCTION__);
+	pr_debug("%s\n", __func__);
 
 	WR16(s, 0x420033, 0x3973);
-	WR16(s, 0x420034, s->config.w50);	// code 4, log 4
-	WR16(s, 0x420035, s->config.w52);	// code 15,  log 9
+	WR16(s, 0x420034, s->config.w50);	/* code 4, log 4 */
+	WR16(s, 0x420035, s->config.w52);	/* code 15,  log 9 */
 	WR16(s, 0x420036, s->config.demod_address << 1);
-	WR16(s, 0x420037, s->config.w56);	// code (set_i2c ??  initX 1 ), log 1
-//      WR16(s, 0x420033, 0x3973);
+	WR16(s, 0x420037, s->config.w56);	/* code (set_i2c ??  initX 1 ), log 1 */
+	/* WR16(s, 0x420033, 0x3973); */
 	if ((s->config.w56 & 8) == 0)
 		return HI_Command(s, 3);
+
 	return WR16(s, 0x420032, 0x3);
 }
 
@@ -419,7 +419,7 @@
 	u16 w0C = agc->w0C;
 	int quot, rem, i, rc = -EINVAL;
 
-	pr_debug("%s\n", __FUNCTION__);
+	pr_debug("%s\n", __func__);
 
 	if (agc->w04 > 0x3ff)
 		goto exit_rc;
@@ -468,7 +468,7 @@
 	i = slowIncrDecLUT_15272[rem / 28];
 	EXIT_RC(WR16(s, 0x0c2002b, i));
 	rc = WR16(s, 0x0c2002c, i);
-      exit_rc:
+exit_rc:
 	return rc;
 }
 
@@ -478,7 +478,7 @@
 	u16 w06 = agc->w06;
 	int rc = -1;
 
-	pr_debug("%s %d 0x%x 0x%x\n", __FUNCTION__, agc->d00, w04, w06);
+	pr_debug("%s %d 0x%x 0x%x\n", __func__, agc->d00, w04, w06);
 
 	if (w04 > 0x3ff)
 		goto exit_rc;
@@ -498,7 +498,7 @@
 		rc &= ~2;
 		break;
 	case 0:
-		// loc_8000659
+		/* loc_8000659 */
 		s->config.w9C &= ~2;
 		EXIT_RC(WR16(s, 0x0c20015, s->config.w9C));
 		EXIT_RC(RD16(s, 0x0c20010));
@@ -522,7 +522,8 @@
 		rc |= 2;
 	}
 	rc = WR16(s, 0x0c20013, rc);
-      exit_rc:
+
+exit_rc:
 	return rc;
 }
 
@@ -554,7 +555,7 @@
 	int lockstat;
 	u32 clk, clk_limit;
 
-	pr_debug("%s\n", __FUNCTION__);
+	pr_debug("%s\n", __func__);
 
 	if (s->config.d5C == 0) {
 		EXIT_RC(WR16(s, 0x08200e8, 0x010));
@@ -598,11 +599,12 @@
 
 	if (clk - s->config.f_osc * 1000 + clk_limit <= 2 * clk_limit) {
 		s->f_osc = clk;
-		pr_debug("%s: osc %d %d [Hz]\n", __FUNCTION__,
+		pr_debug("%s: osc %d %d [Hz]\n", __func__,
 			 s->config.f_osc * 1000, clk - s->config.f_osc * 1000);
 	}
 	rc = WR16(s, 0x08200e8, 0);
-      exit_rc:
+
+exit_rc:
 	return rc;
 }
 
@@ -610,7 +612,7 @@
 {
 	int rc, si, bp;
 
-	pr_debug("%s\n", __FUNCTION__);
+	pr_debug("%s\n", __func__);
 
 	si = s->config.wA0;
 	if (s->config.w98 == 0) {
@@ -620,17 +622,17 @@
 		si &= ~1;
 		bp = 0x200;
 	}
-	if (s->config.w9A == 0) {
+	if (s->config.w9A == 0)
 		si |= 0x80;
-	} else {
+	else
 		si &= ~0x80;
-	}
 
 	EXIT_RC(WR16(s, 0x2150045, 0));
 	EXIT_RC(WR16(s, 0x2150010, si));
 	EXIT_RC(WR16(s, 0x2150011, bp));
 	rc = WR16(s, 0x2150012, (type == 0 ? 0xfff : 0));
-      exit_rc:
+
+exit_rc:
 	return rc;
 }
 
@@ -646,7 +648,7 @@
 
 	int rc, df_tuner;
 	int a, b, c, d;
-	pr_debug("%s %d\n", __FUNCTION__, s->config.d60);
+	pr_debug("%s %d\n", __func__, s->config.d60);
 
 	if (s->config.d60 != 2)
 		goto set_tuner;
@@ -658,7 +660,7 @@
 	rc = ConfigureMPEGOutput(s, 0);
 	if (rc < 0)
 		goto set_tuner;
-      set_tuner:
+set_tuner:
 
 	rc = PLL_Set(s, fep, &df_tuner);
 	if (rc < 0) {
@@ -835,16 +837,16 @@
 		rc = WR16(s, 0x2010012, 0);
 		if (rc < 0)
 			goto exit_rc;
-		//              QPSK    QAM16   QAM64
-		ebx = 0x19f;	//                 62
-		ebp = 0x1fb;	//                 15
-		v20 = 0x16a;	//  62
-		v1E = 0x195;	//         62
-		v16 = 0x1bb;	//  15
-		v14 = 0x1ef;	//         15
-		v12 = 5;	//  16
-		v10 = 5;	//         16
-		v0E = 5;	//                 16
+				/* QPSK    QAM16  QAM64	*/
+		ebx = 0x19f;	/*                 62	*/
+		ebp = 0x1fb;	/*                 15	*/
+		v20 = 0x16a;	/*  62			*/
+		v1E = 0x195;	/*         62		*/
+		v16 = 0x1bb;	/*  15			*/
+		v14 = 0x1ef;	/*         15		*/
+		v12 = 5;	/*  16			*/
+		v10 = 5;	/*         16		*/
+		v0E = 5;	/*                 16	*/
 	}
 
 	switch (fep->u.ofdm.constellation) {
@@ -997,17 +999,17 @@
 	case BANDWIDTH_8_MHZ:	/* 0 */
 	case BANDWIDTH_AUTO:
 		rc = WR16(s, 0x0c2003f, 0x32);
-		s->bandwidth_parm = ebx = 0x8b8249;	// 9142857
+		s->bandwidth_parm = ebx = 0x8b8249;
 		edx = 0;
 		break;
 	case BANDWIDTH_7_MHZ:
 		rc = WR16(s, 0x0c2003f, 0x3b);
-		s->bandwidth_parm = ebx = 0x7a1200;	// 8000000
+		s->bandwidth_parm = ebx = 0x7a1200;
 		edx = 0x4807;
 		break;
 	case BANDWIDTH_6_MHZ:
 		rc = WR16(s, 0x0c2003f, 0x47);
-		s->bandwidth_parm = ebx = 0x68a1b6;	// 6857142
+		s->bandwidth_parm = ebx = 0x68a1b6;
 		edx = 0x0f07;
 		break;
 	};
@@ -1060,8 +1062,6 @@
 	WR16(s, 0x0820040, 1);
 	SC_SendCommand(s, 1);
 
-//      rc = WR16(s, 0x2150000, 1);
-//      if (rc < 0) goto exit_rc;
 
 	rc = WR16(s, 0x2150000, 2);
 	rc = WR16(s, 0x2150016, a);
@@ -1069,7 +1069,8 @@
 	rc = WR16(s, 0x2150036, 0);
 	rc = WR16(s, 0x2150000, 1);
 	s->config.d60 = 2;
-      exit_rc:
+
+exit_rc:
 	return rc;
 }
 
@@ -1082,7 +1083,7 @@
 	struct drx397xD_state *s = fe->demodulator_priv;
 	int rc;
 
-	pr_debug("%s\n", __FUNCTION__);
+	pr_debug("%s\n", __func__);
 
 	s->config.rfagc.d00 = 2;	/* 0x7c */
 	s->config.rfagc.w04 = 0;
@@ -1102,18 +1103,18 @@
 
 	/* HI_CfgCommand */
 	s->config.w50 = 4;
-	s->config.w52 = 9;	// 0xf;
+	s->config.w52 = 9;
 
-	s->config.f_if = 42800000;	/* d14: intermediate frequency [Hz]     */
-	s->config.f_osc = 48000;	/* s66 : oscillator frequency [kHz]     */
-	s->config.w92 = 12000;	// 20000;
+	s->config.f_if = 42800000;	/* d14: intermediate frequency [Hz] */
+	s->config.f_osc = 48000;	/* s66 : oscillator frequency [kHz] */
+	s->config.w92 = 12000;
 
 	s->config.w9C = 0x000e;
 	s->config.w9E = 0x0000;
 
 	/* ConfigureMPEGOutput params */
 	s->config.wA0 = 4;
-	s->config.w98 = 1;	// 0;
+	s->config.w98 = 1;
 	s->config.w9A = 1;
 
 	/* get chip revision */
@@ -1248,7 +1249,7 @@
 		rc = WR16(s, 0x0c20012, 1);
 	}
 
-      write_DRXD_InitFE_1:
+write_DRXD_InitFE_1:
 
 	rc = write_fw(s, DRXD_InitFE_1);
 	if (rc < 0)
@@ -1311,7 +1312,8 @@
 	s->config.d5C = 0;
 	s->config.d60 = 1;
 	s->config.d48 = 1;
-      error:
+
+error:
 	return rc;
 }
 
@@ -1326,7 +1328,8 @@
 {
 	struct drx397xD_state *s = fe->demodulator_priv;
 
-	s->config.s20d24 = 1;	// 0;
+	s->config.s20d24 = 1;
+
 	return drx_tune(s, params);
 }
 
@@ -1337,18 +1340,16 @@
 	fe_tune_settings->min_delay_ms = 10000;
 	fe_tune_settings->step_size = 0;
 	fe_tune_settings->max_drift = 0;
+
 	return 0;
 }
 
-static int drx397x_read_status(struct dvb_frontend *fe, fe_status_t * status)
+static int drx397x_read_status(struct dvb_frontend *fe, fe_status_t *status)
 {
 	struct drx397xD_state *s = fe->demodulator_priv;
 	int lockstat;
 
 	GetLockStatus(s, &lockstat);
-	/* TODO */
-//      if (lockstat & 1)
-//      CorrectSysClockDeviation(s);
 
 	*status = 0;
 	if (lockstat & 2) {
@@ -1356,9 +1357,8 @@
 		ConfigureMPEGOutput(s, 1);
 		*status = FE_HAS_LOCK | FE_HAS_SYNC | FE_HAS_VITERBI;
 	}
-	if (lockstat & 4) {
+	if (lockstat & 4)
 		*status |= FE_HAS_CARRIER | FE_HAS_SIGNAL;
-	}
 
 	return 0;
 }
@@ -1366,16 +1366,18 @@
 static int drx397x_read_ber(struct dvb_frontend *fe, unsigned int *ber)
 {
 	*ber = 0;
+
 	return 0;
 }
 
-static int drx397x_read_snr(struct dvb_frontend *fe, u16 * snr)
+static int drx397x_read_snr(struct dvb_frontend *fe, u16 *snr)
 {
 	*snr = 0;
+
 	return 0;
 }
 
-static int drx397x_read_signal_strength(struct dvb_frontend *fe, u16 * strength)
+static int drx397x_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
 {
 	struct drx397xD_state *s = fe->demodulator_priv;
 	int rc;
@@ -1401,6 +1403,7 @@
 	 * The following does the same but with less rounding errors:
 	 */
 	*strength = ~(7720 + (rc * 30744 >> 10));
+
 	return 0;
 }
 
@@ -1408,6 +1411,7 @@
 				 unsigned int *ucblocks)
 {
 	*ucblocks = 0;
+
 	return 0;
 }
 
@@ -1436,22 +1440,22 @@
 		 .frequency_max		= 855250000,
 		 .frequency_stepsize	= 166667,
 		 .frequency_tolerance	= 0,
-		 .caps =					/* 0x0C01B2EAE */
-			 FE_CAN_FEC_1_2			|	// = 0x2,
-			 FE_CAN_FEC_2_3			|	// = 0x4,
-			 FE_CAN_FEC_3_4			|	// = 0x8,
-			 FE_CAN_FEC_5_6			|	// = 0x20,
-			 FE_CAN_FEC_7_8			|	// = 0x80,
-			 FE_CAN_FEC_AUTO		|	// = 0x200,
-			 FE_CAN_QPSK			|	// = 0x400,
-			 FE_CAN_QAM_16			|	// = 0x800,
-			 FE_CAN_QAM_64			|	// = 0x2000,
-			 FE_CAN_QAM_AUTO		|	// = 0x10000,
-			 FE_CAN_TRANSMISSION_MODE_AUTO	|	// = 0x20000,
-			 FE_CAN_GUARD_INTERVAL_AUTO	|	// = 0x80000,
-			 FE_CAN_HIERARCHY_AUTO		|	// = 0x100000,
-			 FE_CAN_RECOVER			|	// = 0x40000000,
-			 FE_CAN_MUTE_TS				// = 0x80000000
+		 .caps =				  /* 0x0C01B2EAE */
+			 FE_CAN_FEC_1_2			| /* = 0x2, */
+			 FE_CAN_FEC_2_3			| /* = 0x4, */
+			 FE_CAN_FEC_3_4			| /* = 0x8, */
+			 FE_CAN_FEC_5_6			| /* = 0x20, */
+			 FE_CAN_FEC_7_8			| /* = 0x80, */
+			 FE_CAN_FEC_AUTO		| /* = 0x200, */
+			 FE_CAN_QPSK			| /* = 0x400, */
+			 FE_CAN_QAM_16			| /* = 0x800, */
+			 FE_CAN_QAM_64			| /* = 0x2000, */
+			 FE_CAN_QAM_AUTO		| /* = 0x10000, */
+			 FE_CAN_TRANSMISSION_MODE_AUTO	| /* = 0x20000, */
+			 FE_CAN_GUARD_INTERVAL_AUTO	| /* = 0x80000, */
+			 FE_CAN_HIERARCHY_AUTO		| /* = 0x100000, */
+			 FE_CAN_RECOVER			| /* = 0x40000000, */
+			 FE_CAN_MUTE_TS			  /* = 0x80000000 */
 	 },
 
 	.release = drx397x_release,
@@ -1472,33 +1476,35 @@
 struct dvb_frontend *drx397xD_attach(const struct drx397xD_config *config,
 				     struct i2c_adapter *i2c)
 {
-	struct drx397xD_state *s = NULL;
+	struct drx397xD_state *state;
 
 	/* allocate memory for the internal state */
-	s = kzalloc(sizeof(struct drx397xD_state), GFP_KERNEL);
-	if (s == NULL)
+	state = kzalloc(sizeof(struct drx397xD_state), GFP_KERNEL);
+	if (!state)
 		goto error;
 
 	/* setup the state */
-	s->i2c = i2c;
-	memcpy(&s->config, config, sizeof(struct drx397xD_config));
+	state->i2c = i2c;
+	memcpy(&state->config, config, sizeof(struct drx397xD_config));
 
 	/* check if the demod is there */
-	if (RD16(s, 0x2410019) < 0)
+	if (RD16(state, 0x2410019) < 0)
 		goto error;
 
 	/* create dvb_frontend */
-	memcpy(&s->frontend.ops, &drx397x_ops, sizeof(struct dvb_frontend_ops));
-	s->frontend.demodulator_priv = s;
+	memcpy(&state->frontend.ops, &drx397x_ops,
+			sizeof(struct dvb_frontend_ops));
+	state->frontend.demodulator_priv = state;
 
-	return &s->frontend;
-      error:
-	kfree(s);
+	return &state->frontend;
+error:
+	kfree(state);
+
 	return NULL;
 }
+EXPORT_SYMBOL(drx397xD_attach);
 
 MODULE_DESCRIPTION("Micronas DRX397xD DVB-T Frontend");
 MODULE_AUTHOR("Henk Vergonet");
 MODULE_LICENSE("GPL");
 
-EXPORT_SYMBOL(drx397xD_attach);
diff --git a/drivers/media/dvb/frontends/drx397xD.h b/drivers/media/dvb/frontends/drx397xD.h
index ddc7a07..ba05d17 100644
--- a/drivers/media/dvb/frontends/drx397xD.h
+++ b/drivers/media/dvb/frontends/drx397xD.h
@@ -28,7 +28,7 @@
 #define DRX_F_OFFSET	36000000
 
 #define I2C_ADR_C0(x) \
-(	(u32)cpu_to_le32( \
+(	cpu_to_le32( \
 		(u32)( \
 			(((u32)(x) & (u32)0x000000ffUL)      ) | \
 			(((u32)(x) & (u32)0x0000ff00UL) << 16) | \
@@ -38,7 +38,7 @@
 )
 
 #define I2C_ADR_E0(x) \
-(	(u32)cpu_to_le32( \
+(	cpu_to_le32( \
 		(u32)( \
 			(((u32)(x) & (u32)0x000000ffUL)      ) | \
 			(((u32)(x) & (u32)0x0000ff00UL) << 16) | \
@@ -122,7 +122,7 @@
 static inline struct dvb_frontend* drx397xD_attach(const struct drx397xD_config *config,
 					   struct i2c_adapter *i2c)
 {
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
 	return NULL;
 }
 #endif /* CONFIG_DVB_DRX397XD */
diff --git a/drivers/media/dvb/frontends/dvb_dummy_fe.c b/drivers/media/dvb/frontends/dvb_dummy_fe.c
index fed09df..db8a937 100644
--- a/drivers/media/dvb/frontends/dvb_dummy_fe.c
+++ b/drivers/media/dvb/frontends/dvb_dummy_fe.c
@@ -75,9 +75,10 @@
 
 static int dvb_dummy_fe_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
 {
-	if (fe->ops->tuner_ops->set_params) {
-		fe->ops->tuner_ops->set_params(fe, p);
-		if (fe->ops->i2c_gate_ctrl) fe->ops->i2c_gate_ctrl(fe, 0);
+	if (fe->ops.tuner_ops.set_params) {
+		fe->ops.tuner_ops.set_params(fe, p);
+		if (fe->ops.i2c_gate_ctrl)
+			fe->ops.i2c_gate_ctrl(fe, 0);
 	}
 
 	return 0;
@@ -131,7 +132,7 @@
 
 static struct dvb_frontend_ops dvb_dummy_fe_qpsk_ops;
 
-struct dvb_frontend* dvb_dummy_fe_qpsk_attach()
+struct dvb_frontend *dvb_dummy_fe_qpsk_attach(void)
 {
 	struct dvb_dummy_fe_state* state = NULL;
 
@@ -151,7 +152,7 @@
 
 static struct dvb_frontend_ops dvb_dummy_fe_qam_ops;
 
-struct dvb_frontend* dvb_dummy_fe_qam_attach()
+struct dvb_frontend *dvb_dummy_fe_qam_attach(void)
 {
 	struct dvb_dummy_fe_state* state = NULL;
 
diff --git a/drivers/media/dvb/frontends/eds1547.h b/drivers/media/dvb/frontends/eds1547.h
new file mode 100644
index 0000000..fa79b7c
--- /dev/null
+++ b/drivers/media/dvb/frontends/eds1547.h
@@ -0,0 +1,133 @@
+/* eds1547.h Earda EDS-1547 tuner support
+*
+* Copyright (C) 2008 Igor M. Liplianin (liplianin@me.by)
+*
+*	This program is free software; you can redistribute it and/or modify it
+*	under the terms of the GNU General Public License as published by the
+*	Free Software Foundation, version 2.
+*
+* see Documentation/dvb/README.dvb-usb for more information
+*/
+
+#ifndef EDS1547
+#define EDS1547
+
+static u8 stv0288_earda_inittab[] = {
+	0x01, 0x57,
+	0x02, 0x20,
+	0x03, 0x8e,
+	0x04, 0x8e,
+	0x05, 0x12,
+	0x06, 0x00,
+	0x07, 0x00,
+	0x09, 0x00,
+	0x0a, 0x04,
+	0x0b, 0x00,
+	0x0c, 0x00,
+	0x0d, 0x00,
+	0x0e, 0xd4,
+	0x0f, 0x30,
+	0x11, 0x44,
+	0x12, 0x03,
+	0x13, 0x48,
+	0x14, 0x84,
+	0x15, 0x45,
+	0x16, 0xb7,
+	0x17, 0x9c,
+	0x18, 0x00,
+	0x19, 0xa6,
+	0x1a, 0x88,
+	0x1b, 0x8f,
+	0x1c, 0xf0,
+	0x20, 0x0b,
+	0x21, 0x54,
+	0x22, 0x00,
+	0x23, 0x00,
+	0x2b, 0xff,
+	0x2c, 0xf7,
+	0x30, 0x00,
+	0x31, 0x1e,
+	0x32, 0x14,
+	0x33, 0x0f,
+	0x34, 0x09,
+	0x35, 0x0c,
+	0x36, 0x05,
+	0x37, 0x2f,
+	0x38, 0x16,
+	0x39, 0xbd,
+	0x3a, 0x00,
+	0x3b, 0x13,
+	0x3c, 0x11,
+	0x3d, 0x30,
+	0x40, 0x63,
+	0x41, 0x04,
+	0x42, 0x60,
+	0x43, 0x00,
+	0x44, 0x00,
+	0x45, 0x00,
+	0x46, 0x00,
+	0x47, 0x00,
+	0x4a, 0x00,
+	0x50, 0x10,
+	0x51, 0x36,
+	0x52, 0x09,
+	0x53, 0x94,
+	0x54, 0x62,
+	0x55, 0x29,
+	0x56, 0x64,
+	0x57, 0x2b,
+	0x58, 0x54,
+	0x59, 0x86,
+	0x5a, 0x00,
+	0x5b, 0x9b,
+	0x5c, 0x08,
+	0x5d, 0x7f,
+	0x5e, 0x00,
+	0x5f, 0xff,
+	0x70, 0x00,
+	0x71, 0x00,
+	0x72, 0x00,
+	0x74, 0x00,
+	0x75, 0x00,
+	0x76, 0x00,
+	0x81, 0x00,
+	0x82, 0x3f,
+	0x83, 0x3f,
+	0x84, 0x00,
+	0x85, 0x00,
+	0x88, 0x00,
+	0x89, 0x00,
+	0x8a, 0x00,
+	0x8b, 0x00,
+	0x8c, 0x00,
+	0x90, 0x00,
+	0x91, 0x00,
+	0x92, 0x00,
+	0x93, 0x00,
+	0x94, 0x1c,
+	0x97, 0x00,
+	0xa0, 0x48,
+	0xa1, 0x00,
+	0xb0, 0xb8,
+	0xb1, 0x3a,
+	0xb2, 0x10,
+	0xb3, 0x82,
+	0xb4, 0x80,
+	0xb5, 0x82,
+	0xb6, 0x82,
+	0xb7, 0x82,
+	0xb8, 0x20,
+	0xb9, 0x00,
+	0xf0, 0x00,
+	0xf1, 0x00,
+	0xf2, 0xc0,
+	0xff,0xff,
+};
+
+static struct stv0288_config earda_config = {
+	.demod_address = 0x68,
+	.min_delay_ms = 100,
+	.inittab = stv0288_earda_inittab,
+};
+
+#endif
diff --git a/drivers/media/dvb/frontends/lgs8gl5.c b/drivers/media/dvb/frontends/lgs8gl5.c
new file mode 100644
index 0000000..855852f
--- /dev/null
+++ b/drivers/media/dvb/frontends/lgs8gl5.c
@@ -0,0 +1,454 @@
+/*
+    Legend Silicon LGS-8GL5 DMB-TH OFDM demodulator driver
+
+    Copyright (C) 2008 Sirius International (Hong Kong) Limited
+	Timothy Lee <timothy.lee@siriushk.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.
+
+*/
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include "dvb_frontend.h"
+#include "lgs8gl5.h"
+
+
+#define REG_RESET		0x02
+#define REG_RESET_OFF			0x01
+#define REG_03			0x03
+#define REG_04			0x04
+#define REG_07			0x07
+#define REG_09			0x09
+#define REG_0A			0x0a
+#define REG_0B			0x0b
+#define REG_0C			0x0c
+#define REG_37			0x37
+#define REG_STRENGTH		0x4b
+#define REG_STRENGTH_MASK		0x7f
+#define REG_STRENGTH_CARRIER		0x80
+#define REG_INVERSION		0x7c
+#define REG_INVERSION_ON		0x80
+#define REG_7D			0x7d
+#define REG_7E			0x7e
+#define REG_A2			0xa2
+#define REG_STATUS		0xa4
+#define REG_STATUS_SYNC		0x04
+#define REG_STATUS_LOCK		0x01
+
+
+struct lgs8gl5_state {
+	struct i2c_adapter *i2c;
+	const struct lgs8gl5_config *config;
+	struct dvb_frontend frontend;
+};
+
+
+static int debug;
+#define dprintk(args...) \
+	do { \
+		if (debug) \
+			printk(KERN_DEBUG "lgs8gl5: " args); \
+	} while (0)
+
+
+/* Writes into demod's register */
+static int
+lgs8gl5_write_reg(struct lgs8gl5_state *state, u8 reg, u8 data)
+{
+	int ret;
+	u8 buf[] = {reg, data};
+	struct i2c_msg msg = {
+		.addr  = state->config->demod_address,
+		.flags = 0,
+		.buf   = buf,
+		.len   = 2
+	};
+
+	ret = i2c_transfer(state->i2c, &msg, 1);
+	if (ret != 1)
+		dprintk("%s: error (reg=0x%02x, val=0x%02x, ret=%i)\n",
+			__func__, reg, data, ret);
+	return (ret != 1) ? -1 : 0;
+}
+
+
+/* Reads from demod's register */
+static int
+lgs8gl5_read_reg(struct lgs8gl5_state *state, u8 reg)
+{
+	int ret;
+	u8 b0[] = {reg};
+	u8 b1[] = {0};
+	struct i2c_msg msg[2] = {
+		{
+			.addr  = state->config->demod_address,
+			.flags = 0,
+			.buf   = b0,
+			.len   = 1
+		},
+		{
+			.addr  = state->config->demod_address,
+			.flags = I2C_M_RD,
+			.buf   = b1,
+			.len   = 1
+		}
+	};
+
+	ret = i2c_transfer(state->i2c, msg, 2);
+	if (ret != 2)
+		return -EIO;
+
+	return b1[0];
+}
+
+
+static int
+lgs8gl5_update_reg(struct lgs8gl5_state *state, u8 reg, u8 data)
+{
+	lgs8gl5_read_reg(state, reg);
+	lgs8gl5_write_reg(state, reg, data);
+	return 0;
+}
+
+
+/* Writes into alternate device's register */
+/* TODO:  Find out what that device is for! */
+static int
+lgs8gl5_update_alt_reg(struct lgs8gl5_state *state, u8 reg, u8 data)
+{
+	int ret;
+	u8 b0[] = {reg};
+	u8 b1[] = {0};
+	u8 b2[] = {reg, data};
+	struct i2c_msg msg[3] = {
+		{
+			.addr  = state->config->demod_address + 2,
+			.flags = 0,
+			.buf   = b0,
+			.len   = 1
+		},
+		{
+			.addr  = state->config->demod_address + 2,
+			.flags = I2C_M_RD,
+			.buf   = b1,
+			.len   = 1
+		},
+		{
+			.addr  = state->config->demod_address + 2,
+			.flags = 0,
+			.buf   = b2,
+			.len   = 2
+		},
+	};
+
+	ret = i2c_transfer(state->i2c, msg, 3);
+	return (ret != 3) ? -1 : 0;
+}
+
+
+static void
+lgs8gl5_soft_reset(struct lgs8gl5_state *state)
+{
+	u8 val;
+
+	dprintk("%s\n", __func__);
+
+	val = lgs8gl5_read_reg(state, REG_RESET);
+	lgs8gl5_write_reg(state, REG_RESET, val & ~REG_RESET_OFF);
+	lgs8gl5_write_reg(state, REG_RESET, val | REG_RESET_OFF);
+	msleep(5);
+}
+
+
+/* Starts demodulation */
+static void
+lgs8gl5_start_demod(struct lgs8gl5_state *state)
+{
+	u8  val;
+	int n;
+
+	dprintk("%s\n", __func__);
+
+	lgs8gl5_update_alt_reg(state, 0xc2, 0x28);
+	lgs8gl5_soft_reset(state);
+	lgs8gl5_update_reg(state, REG_07, 0x10);
+	lgs8gl5_update_reg(state, REG_07, 0x10);
+	lgs8gl5_write_reg(state, REG_09, 0x0e);
+	lgs8gl5_write_reg(state, REG_0A, 0xe5);
+	lgs8gl5_write_reg(state, REG_0B, 0x35);
+	lgs8gl5_write_reg(state, REG_0C, 0x30);
+
+	lgs8gl5_update_reg(state, REG_03, 0x00);
+	lgs8gl5_update_reg(state, REG_7E, 0x01);
+	lgs8gl5_update_alt_reg(state, 0xc5, 0x00);
+	lgs8gl5_update_reg(state, REG_04, 0x02);
+	lgs8gl5_update_reg(state, REG_37, 0x01);
+	lgs8gl5_soft_reset(state);
+
+	/* Wait for carrier */
+	for (n = 0;  n < 10;  n++) {
+		val = lgs8gl5_read_reg(state, REG_STRENGTH);
+		dprintk("Wait for carrier[%d] 0x%02X\n", n, val);
+		if (val & REG_STRENGTH_CARRIER)
+			break;
+		msleep(4);
+	}
+	if (!(val & REG_STRENGTH_CARRIER))
+		return;
+
+	/* Wait for lock */
+	for (n = 0;  n < 20;  n++) {
+		val = lgs8gl5_read_reg(state, REG_STATUS);
+		dprintk("Wait for lock[%d] 0x%02X\n", n, val);
+		if (val & REG_STATUS_LOCK)
+			break;
+		msleep(12);
+	}
+	if (!(val & REG_STATUS_LOCK))
+		return;
+
+	lgs8gl5_write_reg(state, REG_7D, lgs8gl5_read_reg(state, REG_A2));
+	lgs8gl5_soft_reset(state);
+}
+
+
+static int
+lgs8gl5_init(struct dvb_frontend *fe)
+{
+	struct lgs8gl5_state *state = fe->demodulator_priv;
+
+	dprintk("%s\n", __func__);
+
+	lgs8gl5_update_alt_reg(state, 0xc2, 0x28);
+	lgs8gl5_soft_reset(state);
+	lgs8gl5_update_reg(state, REG_07, 0x10);
+	lgs8gl5_update_reg(state, REG_07, 0x10);
+	lgs8gl5_write_reg(state, REG_09, 0x0e);
+	lgs8gl5_write_reg(state, REG_0A, 0xe5);
+	lgs8gl5_write_reg(state, REG_0B, 0x35);
+	lgs8gl5_write_reg(state, REG_0C, 0x30);
+
+	return 0;
+}
+
+
+static int
+lgs8gl5_read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+	struct lgs8gl5_state *state = fe->demodulator_priv;
+	u8 level = lgs8gl5_read_reg(state, REG_STRENGTH);
+	u8 flags = lgs8gl5_read_reg(state, REG_STATUS);
+
+	*status = 0;
+
+	if ((level & REG_STRENGTH_MASK) > 0)
+		*status |= FE_HAS_SIGNAL;
+	if (level & REG_STRENGTH_CARRIER)
+		*status |= FE_HAS_CARRIER;
+	if (flags & REG_STATUS_SYNC)
+		*status |= FE_HAS_SYNC;
+	if (flags & REG_STATUS_LOCK)
+		*status |= FE_HAS_LOCK;
+
+	return 0;
+}
+
+
+static int
+lgs8gl5_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+	*ber = 0;
+
+	return 0;
+}
+
+
+static int
+lgs8gl5_read_signal_strength(struct dvb_frontend *fe, u16 *signal_strength)
+{
+	struct lgs8gl5_state *state = fe->demodulator_priv;
+	u8 level = lgs8gl5_read_reg(state, REG_STRENGTH);
+	*signal_strength = (level & REG_STRENGTH_MASK) << 8;
+
+	return 0;
+}
+
+
+static int
+lgs8gl5_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+	struct lgs8gl5_state *state = fe->demodulator_priv;
+	u8 level = lgs8gl5_read_reg(state, REG_STRENGTH);
+	*snr = (level & REG_STRENGTH_MASK) << 8;
+
+	return 0;
+}
+
+
+static int
+lgs8gl5_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
+{
+	*ucblocks = 0;
+
+	return 0;
+}
+
+
+static int
+lgs8gl5_set_frontend(struct dvb_frontend *fe,
+		struct dvb_frontend_parameters *p)
+{
+	struct lgs8gl5_state *state = fe->demodulator_priv;
+
+	dprintk("%s\n", __func__);
+
+	if (p->u.ofdm.bandwidth != BANDWIDTH_8_MHZ)
+		return -EINVAL;
+
+	if (fe->ops.tuner_ops.set_params) {
+		fe->ops.tuner_ops.set_params(fe, p);
+		if (fe->ops.i2c_gate_ctrl)
+			fe->ops.i2c_gate_ctrl(fe, 0);
+	}
+
+	/* lgs8gl5_set_inversion(state, p->inversion); */
+
+	lgs8gl5_start_demod(state);
+
+	return 0;
+}
+
+
+static int
+lgs8gl5_get_frontend(struct dvb_frontend *fe,
+		struct dvb_frontend_parameters *p)
+{
+	struct lgs8gl5_state *state = fe->demodulator_priv;
+	u8 inv = lgs8gl5_read_reg(state, REG_INVERSION);
+	struct dvb_ofdm_parameters *o = &p->u.ofdm;
+
+	p->inversion = (inv & REG_INVERSION_ON) ? INVERSION_ON : INVERSION_OFF;
+
+	o->code_rate_HP = FEC_1_2;
+	o->code_rate_LP = FEC_7_8;
+	o->guard_interval = GUARD_INTERVAL_1_32;
+	o->transmission_mode = TRANSMISSION_MODE_2K;
+	o->constellation = QAM_64;
+	o->hierarchy_information = HIERARCHY_NONE;
+	o->bandwidth = BANDWIDTH_8_MHZ;
+
+	return 0;
+}
+
+
+static int
+lgs8gl5_get_tune_settings(struct dvb_frontend *fe,
+		struct dvb_frontend_tune_settings *fesettings)
+{
+	fesettings->min_delay_ms = 240;
+	fesettings->step_size    = 0;
+	fesettings->max_drift    = 0;
+	return 0;
+}
+
+
+static void
+lgs8gl5_release(struct dvb_frontend *fe)
+{
+	struct lgs8gl5_state *state = fe->demodulator_priv;
+	kfree(state);
+}
+
+
+static struct dvb_frontend_ops lgs8gl5_ops;
+
+
+struct dvb_frontend*
+lgs8gl5_attach(const struct lgs8gl5_config *config, struct i2c_adapter *i2c)
+{
+	struct lgs8gl5_state *state = NULL;
+
+	dprintk("%s\n", __func__);
+
+	/* Allocate memory for the internal state */
+	state = kmalloc(sizeof(struct lgs8gl5_state), GFP_KERNEL);
+	if (state == NULL)
+		goto error;
+
+	/* Setup the state */
+	state->config = config;
+	state->i2c    = i2c;
+
+	/* Check if the demod is there */
+	if (lgs8gl5_read_reg(state, REG_RESET) < 0)
+		goto error;
+
+	/* Create dvb_frontend */
+	memcpy(&state->frontend.ops, &lgs8gl5_ops,
+		sizeof(struct dvb_frontend_ops));
+	state->frontend.demodulator_priv = state;
+	return &state->frontend;
+
+error:
+	kfree(state);
+	return NULL;
+}
+EXPORT_SYMBOL(lgs8gl5_attach);
+
+
+static struct dvb_frontend_ops lgs8gl5_ops = {
+	.info = {
+		.name			= "Legend Silicon LGS-8GL5 DMB-TH",
+		.type			= FE_OFDM,
+		.frequency_min		= 474000000,
+		.frequency_max		= 858000000,
+		.frequency_stepsize	= 10000,
+		.frequency_tolerance	= 0,
+		.caps = FE_CAN_FEC_AUTO |
+			FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_32 |
+			FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
+			FE_CAN_TRANSMISSION_MODE_AUTO |
+			FE_CAN_BANDWIDTH_AUTO |
+			FE_CAN_GUARD_INTERVAL_AUTO |
+			FE_CAN_HIERARCHY_AUTO |
+			FE_CAN_RECOVER
+	},
+
+	.release = lgs8gl5_release,
+
+	.init = lgs8gl5_init,
+
+	.set_frontend = lgs8gl5_set_frontend,
+	.get_frontend = lgs8gl5_get_frontend,
+	.get_tune_settings = lgs8gl5_get_tune_settings,
+
+	.read_status = lgs8gl5_read_status,
+	.read_ber = lgs8gl5_read_ber,
+	.read_signal_strength = lgs8gl5_read_signal_strength,
+	.read_snr = lgs8gl5_read_snr,
+	.read_ucblocks = lgs8gl5_read_ucblocks,
+};
+
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
+
+MODULE_DESCRIPTION("Legend Silicon LGS-8GL5 DMB-TH Demodulator driver");
+MODULE_AUTHOR("Timothy Lee");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/lgs8gl5.h b/drivers/media/dvb/frontends/lgs8gl5.h
new file mode 100644
index 0000000..d1417678
--- /dev/null
+++ b/drivers/media/dvb/frontends/lgs8gl5.h
@@ -0,0 +1,45 @@
+/*
+    Legend Silicon LGS-8GL5 DMB-TH OFDM demodulator driver
+
+    Copyright (C) 2008 Sirius International (Hong Kong) Limited
+	Timothy Lee <timothy.lee@siriushk.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.
+
+*/
+
+#ifndef LGS8GL5_H
+#define LGS8GL5_H
+
+#include <linux/dvb/frontend.h>
+
+struct lgs8gl5_config {
+	/* the demodulator's i2c address */
+	u8 demod_address;
+};
+
+#if defined(CONFIG_DVB_LGS8GL5) || \
+	(defined(CONFIG_DVB_LGS8GL5_MODULE) && defined(MODULE))
+extern struct dvb_frontend *lgs8gl5_attach(
+	const struct lgs8gl5_config *config, struct i2c_adapter *i2c);
+#else
+static inline struct dvb_frontend *lgs8gl5_attach(
+	const struct lgs8gl5_config *config, struct i2c_adapter *i2c) {
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+#endif /* CONFIG_DVB_LGS8GL5 */
+
+#endif /* LGS8GL5_H */
diff --git a/drivers/media/dvb/frontends/nxt200x.c b/drivers/media/dvb/frontends/nxt200x.c
index af29835..a8429eb 100644
--- a/drivers/media/dvb/frontends/nxt200x.c
+++ b/drivers/media/dvb/frontends/nxt200x.c
@@ -80,7 +80,7 @@
 	return 0;
 }
 
-static u8 i2c_readbytes (struct nxt200x_state* state, u8 addr, u8* buf, u8 len)
+static int i2c_readbytes(struct nxt200x_state *state, u8 addr, u8 *buf, u8 len)
 {
 	int err;
 	struct i2c_msg msg = { .addr = addr, .flags = I2C_M_RD, .buf = buf, .len = len };
@@ -111,7 +111,7 @@
 	return 0;
 }
 
-static u8 nxt200x_readbytes (struct nxt200x_state* state, u8 reg, u8* buf, u8 len)
+static int nxt200x_readbytes(struct nxt200x_state *state, u8 reg, u8 *buf, u8 len)
 {
 	u8 reg2 [] = { reg };
 
diff --git a/drivers/media/dvb/frontends/or51211.c b/drivers/media/dvb/frontends/or51211.c
index 6afe12a..16cf2fdd 100644
--- a/drivers/media/dvb/frontends/or51211.c
+++ b/drivers/media/dvb/frontends/or51211.c
@@ -88,7 +88,7 @@
 	return 0;
 }
 
-static u8 i2c_readbytes (struct or51211_state* state, u8 reg, u8* buf, int len)
+static int i2c_readbytes(struct or51211_state *state, u8 reg, u8 *buf, int len)
 {
 	int err;
 	struct i2c_msg msg;
diff --git a/drivers/media/dvb/frontends/s5h1420.c b/drivers/media/dvb/frontends/s5h1420.c
index 747d3fa..2e9fd28 100644
--- a/drivers/media/dvb/frontends/s5h1420.c
+++ b/drivers/media/dvb/frontends/s5h1420.c
@@ -59,7 +59,7 @@
 	 * it does not support repeated-start, workaround: write addr-1
 	 * and then read
 	 */
-	u8 shadow[255];
+	u8 shadow[256];
 };
 
 static u32 s5h1420_getsymbolrate(struct s5h1420_state* state);
@@ -94,8 +94,11 @@
 		if (ret != 3)
 			return ret;
 	} else {
-		ret = i2c_transfer(state->i2c, &msg[1], 2);
-		if (ret != 2)
+		ret = i2c_transfer(state->i2c, &msg[1], 1);
+		if (ret != 1)
+			return ret;
+		ret = i2c_transfer(state->i2c, &msg[2], 1);
+		if (ret != 1)
 			return ret;
 	}
 
@@ -823,7 +826,7 @@
 	struct s5h1420_state* state = fe->demodulator_priv;
 
 	/* disable power down and do reset */
-	state->CON_1_val = 0x10;
+	state->CON_1_val = state->config->serial_mpeg << 4;
 	s5h1420_writereg(state, 0x02, state->CON_1_val);
 	msleep(10);
 	s5h1420_reset(state);
diff --git a/drivers/media/dvb/frontends/s5h1420.h b/drivers/media/dvb/frontends/s5h1420.h
index 4c913f1..ff30813 100644
--- a/drivers/media/dvb/frontends/s5h1420.h
+++ b/drivers/media/dvb/frontends/s5h1420.h
@@ -32,10 +32,12 @@
 	u8 demod_address;
 
 	/* does the inversion require inversion? */
-	u8 invert : 1;
+	u8 invert:1;
 
-	u8 repeated_start_workaround : 1;
-	u8 cdclk_polarity : 1; /* 1 == falling edge, 0 == raising edge */
+	u8 repeated_start_workaround:1;
+	u8 cdclk_polarity:1; /* 1 == falling edge, 0 == raising edge */
+
+	u8 serial_mpeg:1;
 };
 
 #if defined(CONFIG_DVB_S5H1420) || (defined(CONFIG_DVB_S5H1420_MODULE) && defined(MODULE))
diff --git a/drivers/media/dvb/frontends/si21xx.c b/drivers/media/dvb/frontends/si21xx.c
new file mode 100644
index 0000000..3ddbe69
--- /dev/null
+++ b/drivers/media/dvb/frontends/si21xx.c
@@ -0,0 +1,974 @@
+/* DVB compliant Linux driver for the DVB-S si2109/2110 demodulator
+*
+* Copyright (C) 2008 Igor M. Liplianin (liplianin@me.by)
+*
+*	This program is free software; you can redistribute it and/or 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/version.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/jiffies.h>
+#include <asm/div64.h>
+
+#include "dvb_frontend.h"
+#include "si21xx.h"
+
+#define	REVISION_REG			0x00
+#define	SYSTEM_MODE_REG			0x01
+#define	TS_CTRL_REG_1			0x02
+#define	TS_CTRL_REG_2			0x03
+#define	PIN_CTRL_REG_1			0x04
+#define	PIN_CTRL_REG_2			0x05
+#define	LOCK_STATUS_REG_1		0x0f
+#define	LOCK_STATUS_REG_2		0x10
+#define	ACQ_STATUS_REG			0x11
+#define	ACQ_CTRL_REG_1			0x13
+#define	ACQ_CTRL_REG_2			0x14
+#define	PLL_DIVISOR_REG			0x15
+#define	COARSE_TUNE_REG			0x16
+#define	FINE_TUNE_REG_L			0x17
+#define	FINE_TUNE_REG_H			0x18
+
+#define	ANALOG_AGC_POWER_LEVEL_REG	0x28
+#define	CFO_ESTIMATOR_CTRL_REG_1	0x29
+#define	CFO_ESTIMATOR_CTRL_REG_2	0x2a
+#define	CFO_ESTIMATOR_CTRL_REG_3	0x2b
+
+#define	SYM_RATE_ESTIMATE_REG_L		0x31
+#define	SYM_RATE_ESTIMATE_REG_M		0x32
+#define	SYM_RATE_ESTIMATE_REG_H		0x33
+
+#define	CFO_ESTIMATOR_OFFSET_REG_L	0x36
+#define	CFO_ESTIMATOR_OFFSET_REG_H	0x37
+#define	CFO_ERROR_REG_L			0x38
+#define	CFO_ERROR_REG_H			0x39
+#define	SYM_RATE_ESTIMATOR_CTRL_REG	0x3a
+
+#define	SYM_RATE_REG_L			0x3f
+#define	SYM_RATE_REG_M			0x40
+#define	SYM_RATE_REG_H			0x41
+#define	SYM_RATE_ESTIMATOR_MAXIMUM_REG	0x42
+#define	SYM_RATE_ESTIMATOR_MINIMUM_REG	0x43
+
+#define	C_N_ESTIMATOR_CTRL_REG		0x7c
+#define	C_N_ESTIMATOR_THRSHLD_REG	0x7d
+#define	C_N_ESTIMATOR_LEVEL_REG_L	0x7e
+#define	C_N_ESTIMATOR_LEVEL_REG_H	0x7f
+
+#define	BLIND_SCAN_CTRL_REG		0x80
+
+#define	LSA_CTRL_REG_1			0x8D
+#define	SPCTRM_TILT_CORR_THRSHLD_REG	0x8f
+#define	ONE_DB_BNDWDTH_THRSHLD_REG	0x90
+#define	TWO_DB_BNDWDTH_THRSHLD_REG	0x91
+#define	THREE_DB_BNDWDTH_THRSHLD_REG	0x92
+#define	INBAND_POWER_THRSHLD_REG	0x93
+#define	REF_NOISE_LVL_MRGN_THRSHLD_REG	0x94
+
+#define	VIT_SRCH_CTRL_REG_1		0xa0
+#define	VIT_SRCH_CTRL_REG_2		0xa1
+#define	VIT_SRCH_CTRL_REG_3		0xa2
+#define	VIT_SRCH_STATUS_REG		0xa3
+#define	VITERBI_BER_COUNT_REG_L		0xab
+#define	REED_SOLOMON_CTRL_REG		0xb0
+#define	REED_SOLOMON_ERROR_COUNT_REG_L	0xb1
+#define	PRBS_CTRL_REG			0xb5
+
+#define	LNB_CTRL_REG_1			0xc0
+#define	LNB_CTRL_REG_2			0xc1
+#define	LNB_CTRL_REG_3			0xc2
+#define	LNB_CTRL_REG_4			0xc3
+#define	LNB_CTRL_STATUS_REG		0xc4
+#define	LNB_FIFO_REGS_0			0xc5
+#define	LNB_FIFO_REGS_1			0xc6
+#define	LNB_FIFO_REGS_2			0xc7
+#define	LNB_FIFO_REGS_3			0xc8
+#define	LNB_FIFO_REGS_4			0xc9
+#define	LNB_FIFO_REGS_5			0xca
+#define	LNB_SUPPLY_CTRL_REG_1		0xcb
+#define	LNB_SUPPLY_CTRL_REG_2		0xcc
+#define	LNB_SUPPLY_CTRL_REG_3		0xcd
+#define	LNB_SUPPLY_CTRL_REG_4		0xce
+#define	LNB_SUPPLY_STATUS_REG		0xcf
+
+#define FALSE	0
+#define TRUE	1
+#define FAIL	-1
+#define PASS	0
+
+#define ALLOWABLE_FS_COUNT	10
+#define STATUS_BER		0
+#define STATUS_UCBLOCKS		1
+
+static int debug;
+#define dprintk(args...) \
+	do { \
+		if (debug) \
+			printk(KERN_DEBUG "si21xx: " args); \
+	} while (0)
+
+enum {
+	ACTIVE_HIGH,
+	ACTIVE_LOW
+};
+enum {
+	BYTE_WIDE,
+	BIT_WIDE
+};
+enum {
+	CLK_GAPPED_MODE,
+	CLK_CONTINUOUS_MODE
+};
+enum {
+	RISING_EDGE,
+	FALLING_EDGE
+};
+enum {
+	MSB_FIRST,
+	LSB_FIRST
+};
+enum {
+	SERIAL,
+	PARALLEL
+};
+
+struct si21xx_state {
+	struct i2c_adapter *i2c;
+	const struct si21xx_config *config;
+	struct dvb_frontend frontend;
+	u8 initialised:1;
+	int errmode;
+	int fs;			/*Sampling rate of the ADC in MHz*/
+};
+
+/*	register default initialization */
+static u8 serit_sp1511lhb_inittab[] = {
+	0x01, 0x28,	/* set i2c_inc_disable */
+	0x20, 0x03,
+	0x27, 0x20,
+	0xe0, 0x45,
+	0xe1, 0x08,
+	0xfe, 0x01,
+	0x01, 0x28,
+	0x89, 0x09,
+	0x04, 0x80,
+	0x05, 0x01,
+	0x06, 0x00,
+	0x20, 0x03,
+	0x24, 0x88,
+	0x29, 0x09,
+	0x2a, 0x0f,
+	0x2c, 0x10,
+	0x2d, 0x19,
+	0x2e, 0x08,
+	0x2f, 0x10,
+	0x30, 0x19,
+	0x34, 0x20,
+	0x35, 0x03,
+	0x45, 0x02,
+	0x46, 0x45,
+	0x47, 0xd0,
+	0x48, 0x00,
+	0x49, 0x40,
+	0x4a, 0x03,
+	0x4c, 0xfd,
+	0x4f, 0x2e,
+	0x50, 0x2e,
+	0x51, 0x10,
+	0x52, 0x10,
+	0x56, 0x92,
+	0x59, 0x00,
+	0x5a, 0x2d,
+	0x5b, 0x33,
+	0x5c, 0x1f,
+	0x5f, 0x76,
+	0x62, 0xc0,
+	0x63, 0xc0,
+	0x64, 0xf3,
+	0x65, 0xf3,
+	0x79, 0x40,
+	0x6a, 0x40,
+	0x6b, 0x0a,
+	0x6c, 0x80,
+	0x6d, 0x27,
+	0x71, 0x06,
+	0x75, 0x60,
+	0x78, 0x00,
+	0x79, 0xb5,
+	0x7c, 0x05,
+	0x7d, 0x1a,
+	0x87, 0x55,
+	0x88, 0x72,
+	0x8f, 0x08,
+	0x90, 0xe0,
+	0x94, 0x40,
+	0xa0, 0x3f,
+	0xa1, 0xc0,
+	0xa4, 0xcc,
+	0xa5, 0x66,
+	0xa6, 0x66,
+	0xa7, 0x7b,
+	0xa8, 0x7b,
+	0xa9, 0x7b,
+	0xaa, 0x9a,
+	0xed, 0x04,
+	0xad, 0x00,
+	0xae, 0x03,
+	0xcc, 0xab,
+	0x01, 0x08,
+	0xff, 0xff
+};
+
+/*	low level read/writes */
+static int si21_writeregs(struct si21xx_state *state, u8 reg1,
+							u8 *data, int len)
+{
+	int ret;
+	u8 buf[60];/* = { reg1, data };*/
+	struct i2c_msg msg = {
+				.addr = state->config->demod_address,
+				.flags = 0,
+				.buf = buf,
+				.len = len + 1
+	};
+
+	msg.buf[0] =  reg1;
+	memcpy(msg.buf + 1, data, len);
+
+	ret = i2c_transfer(state->i2c, &msg, 1);
+
+	if (ret != 1)
+		dprintk("%s: writereg error (reg1 == 0x%02x, data == 0x%02x, "
+			"ret == %i)\n", __func__, reg1, data[0], ret);
+
+	return (ret != 1) ? -EREMOTEIO : 0;
+}
+
+static int si21_writereg(struct si21xx_state *state, u8 reg, u8 data)
+{
+	int ret;
+	u8 buf[] = { reg, data };
+	struct i2c_msg msg = {
+				.addr = state->config->demod_address,
+				.flags = 0,
+				.buf = buf,
+				.len = 2
+	};
+
+	ret = i2c_transfer(state->i2c, &msg, 1);
+
+	if (ret != 1)
+		dprintk("%s: writereg error (reg == 0x%02x, data == 0x%02x, "
+			"ret == %i)\n", __func__, reg, data, ret);
+
+	return (ret != 1) ? -EREMOTEIO : 0;
+}
+
+static int si21_write(struct dvb_frontend *fe, u8 *buf, int len)
+{
+	struct si21xx_state *state = fe->demodulator_priv;
+
+	if (len != 2)
+		return -EINVAL;
+
+	return si21_writereg(state, buf[0], buf[1]);
+}
+
+static u8 si21_readreg(struct si21xx_state *state, u8 reg)
+{
+	int ret;
+	u8 b0[] = { reg };
+	u8 b1[] = { 0 };
+	struct i2c_msg msg[] = {
+		{
+			.addr = state->config->demod_address,
+			.flags = 0,
+			.buf = b0,
+			.len = 1
+		}, {
+			.addr = state->config->demod_address,
+			.flags = I2C_M_RD,
+			.buf = b1,
+			.len = 1
+		}
+	};
+
+	ret = i2c_transfer(state->i2c, msg, 2);
+
+	if (ret != 2)
+		dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n",
+			__func__, reg, ret);
+
+	return b1[0];
+}
+
+static int si21_readregs(struct si21xx_state *state, u8 reg1, u8 *b, u8 len)
+{
+	int ret;
+	struct i2c_msg msg[] = {
+		{
+			.addr = state->config->demod_address,
+			.flags = 0,
+			.buf = &reg1,
+			.len = 1
+		}, {
+			.addr = state->config->demod_address,
+			.flags = I2C_M_RD,
+			.buf = b,
+			.len = len
+		}
+	};
+
+	ret = i2c_transfer(state->i2c, msg, 2);
+
+	if (ret != 2)
+		dprintk("%s: readreg error (ret == %i)\n", __func__, ret);
+
+	return ret == 2 ? 0 : -1;
+}
+
+static int si21xx_wait_diseqc_idle(struct si21xx_state *state, int timeout)
+{
+	unsigned long start = jiffies;
+
+	dprintk("%s\n", __func__);
+
+	while ((si21_readreg(state, LNB_CTRL_REG_1) & 0x8) == 8) {
+		if (jiffies - start > timeout) {
+			dprintk("%s: timeout!!\n", __func__);
+			return -ETIMEDOUT;
+		}
+		msleep(10);
+	};
+
+	return 0;
+}
+
+static int si21xx_set_symbolrate(struct dvb_frontend *fe, u32 srate)
+{
+	struct si21xx_state *state = fe->demodulator_priv;
+	u32 sym_rate, data_rate;
+	int i;
+	u8 sym_rate_bytes[3];
+
+	dprintk("%s : srate = %i\n", __func__ , srate);
+
+	if ((srate < 1000000) || (srate > 45000000))
+		return -EINVAL;
+
+	data_rate = srate;
+	sym_rate = 0;
+
+	for (i = 0; i < 4; ++i) {
+		sym_rate /= 100;
+		sym_rate = sym_rate + ((data_rate % 100) * 0x800000) /
+								state->fs;
+		data_rate /= 100;
+	}
+	for (i = 0; i < 3; ++i)
+		sym_rate_bytes[i] = (u8)((sym_rate >> (i * 8)) & 0xff);
+
+	si21_writeregs(state, SYM_RATE_REG_L, sym_rate_bytes, 0x03);
+
+	return 0;
+}
+
+static int si21xx_send_diseqc_msg(struct dvb_frontend *fe,
+					struct dvb_diseqc_master_cmd *m)
+{
+	struct si21xx_state *state = fe->demodulator_priv;
+	u8 lnb_status;
+	u8 LNB_CTRL_1;
+	int status;
+
+	dprintk("%s\n", __func__);
+
+	status = PASS;
+	LNB_CTRL_1 = 0;
+
+	status |= si21_readregs(state, LNB_CTRL_STATUS_REG, &lnb_status, 0x01);
+	status |= si21_readregs(state, LNB_CTRL_REG_1, &lnb_status, 0x01);
+
+	/*fill the FIFO*/
+	status |= si21_writeregs(state, LNB_FIFO_REGS_0, m->msg, m->msg_len);
+
+	LNB_CTRL_1 = (lnb_status & 0x70);
+	LNB_CTRL_1 |= m->msg_len;
+
+	LNB_CTRL_1 |= 0x80;	/* begin LNB signaling */
+
+	status |= si21_writeregs(state, LNB_CTRL_REG_1, &LNB_CTRL_1, 0x01);
+
+	return status;
+}
+
+static int si21xx_send_diseqc_burst(struct dvb_frontend *fe,
+						fe_sec_mini_cmd_t burst)
+{
+	struct si21xx_state *state = fe->demodulator_priv;
+	u8 val;
+
+	dprintk("%s\n", __func__);
+
+	if (si21xx_wait_diseqc_idle(state, 100) < 0)
+		return -ETIMEDOUT;
+
+	val = (0x80 | si21_readreg(state, 0xc1));
+	if (si21_writereg(state, LNB_CTRL_REG_1,
+			burst == SEC_MINI_A ? (val & ~0x10) : (val | 0x10)))
+		return -EREMOTEIO;
+
+	if (si21xx_wait_diseqc_idle(state, 100) < 0)
+		return -ETIMEDOUT;
+
+	if (si21_writereg(state, LNB_CTRL_REG_1, val))
+		return -EREMOTEIO;
+
+	return 0;
+}
+/*	30.06.2008 */
+static int si21xx_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone)
+{
+	struct si21xx_state *state = fe->demodulator_priv;
+	u8 val;
+
+	dprintk("%s\n", __func__);
+	val = (0x80 | si21_readreg(state, LNB_CTRL_REG_1));
+
+	switch (tone) {
+	case SEC_TONE_ON:
+		return si21_writereg(state, LNB_CTRL_REG_1, val | 0x20);
+
+	case SEC_TONE_OFF:
+		return si21_writereg(state, LNB_CTRL_REG_1, (val & ~0x20));
+
+	default:
+		return -EINVAL;
+	}
+}
+
+static int si21xx_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t volt)
+{
+	struct si21xx_state *state = fe->demodulator_priv;
+
+	u8 val;
+	dprintk("%s: %s\n", __func__,
+		volt == SEC_VOLTAGE_13 ? "SEC_VOLTAGE_13" :
+		volt == SEC_VOLTAGE_18 ? "SEC_VOLTAGE_18" : "??");
+
+
+	val = (0x80 | si21_readreg(state, LNB_CTRL_REG_1));
+
+	switch (volt) {
+	case SEC_VOLTAGE_18:
+		return si21_writereg(state, LNB_CTRL_REG_1, val | 0x40);
+		break;
+	case SEC_VOLTAGE_13:
+		return si21_writereg(state, LNB_CTRL_REG_1, (val & ~0x40));
+		break;
+	default:
+		return -EINVAL;
+	};
+}
+
+static int si21xx_init(struct dvb_frontend *fe)
+{
+	struct si21xx_state *state = fe->demodulator_priv;
+	int i;
+	int status = 0;
+	u8 reg1;
+	u8 val;
+	u8 reg2[2];
+
+	dprintk("%s\n", __func__);
+
+	for (i = 0; ; i += 2) {
+		reg1 = serit_sp1511lhb_inittab[i];
+		val = serit_sp1511lhb_inittab[i+1];
+		if (reg1 == 0xff && val == 0xff)
+			break;
+		si21_writeregs(state, reg1, &val, 1);
+	}
+
+	/*DVB QPSK SYSTEM MODE REG*/
+	reg1 = 0x08;
+	si21_writeregs(state, SYSTEM_MODE_REG, &reg1, 0x01);
+
+	/*transport stream config*/
+	/*
+	mode = PARALLEL;
+	sdata_form = LSB_FIRST;
+	clk_edge = FALLING_EDGE;
+	clk_mode = CLK_GAPPED_MODE;
+	strt_len = BYTE_WIDE;
+	sync_pol = ACTIVE_HIGH;
+	val_pol = ACTIVE_HIGH;
+	err_pol = ACTIVE_HIGH;
+	sclk_rate = 0x00;
+	parity = 0x00 ;
+	data_delay = 0x00;
+	clk_delay = 0x00;
+	pclk_smooth = 0x00;
+	*/
+	reg2[0] =
+		PARALLEL + (LSB_FIRST << 1)
+		+ (FALLING_EDGE << 2) + (CLK_GAPPED_MODE << 3)
+		+ (BYTE_WIDE << 4) + (ACTIVE_HIGH << 5)
+		+ (ACTIVE_HIGH << 6) + (ACTIVE_HIGH << 7);
+
+	reg2[1] = 0;
+	/*	sclk_rate + (parity << 2)
+		+ (data_delay << 3) + (clk_delay << 4)
+		+ (pclk_smooth << 5);
+	*/
+	status |= si21_writeregs(state, TS_CTRL_REG_1, reg2, 0x02);
+	if (status != 0)
+		dprintk(" %s : TS Set Error\n", __func__);
+
+	return 0;
+
+}
+
+static int si21_read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+	struct si21xx_state *state = fe->demodulator_priv;
+	u8 regs_read[2];
+	u8 reg_read;
+	u8 i;
+	u8 lock;
+	u8 signal = si21_readreg(state, ANALOG_AGC_POWER_LEVEL_REG);
+
+	si21_readregs(state, LOCK_STATUS_REG_1, regs_read, 0x02);
+	reg_read = 0;
+
+	for (i = 0; i < 7; ++i)
+		reg_read |= ((regs_read[0] >> i) & 0x01) << (6 - i);
+
+	lock = ((reg_read & 0x7f) | (regs_read[1] & 0x80));
+
+	dprintk("%s : FE_READ_STATUS : VSTATUS: 0x%02x\n", __func__, lock);
+	*status = 0;
+
+	if (signal > 10)
+		*status |= FE_HAS_SIGNAL;
+
+	if (lock & 0x2)
+		*status |= FE_HAS_CARRIER;
+
+	if (lock & 0x20)
+		*status |= FE_HAS_VITERBI;
+
+	if (lock & 0x40)
+		*status |= FE_HAS_SYNC;
+
+	if ((lock & 0x7b) == 0x7b)
+		*status |= FE_HAS_LOCK;
+
+	return 0;
+}
+
+static int si21_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
+{
+	struct si21xx_state *state = fe->demodulator_priv;
+
+	/*status = si21_readreg(state, ANALOG_AGC_POWER_LEVEL_REG,
+						(u8*)agclevel, 0x01);*/
+
+	u16 signal = (3 * si21_readreg(state, 0x27) *
+					si21_readreg(state, 0x28));
+
+	dprintk("%s : AGCPWR: 0x%02x%02x, signal=0x%04x\n", __func__,
+		si21_readreg(state, 0x27),
+		si21_readreg(state, 0x28), (int) signal);
+
+	signal  <<= 4;
+	*strength = signal;
+
+	return 0;
+}
+
+static int si21_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+	struct si21xx_state *state = fe->demodulator_priv;
+
+	dprintk("%s\n", __func__);
+
+	if (state->errmode != STATUS_BER)
+		return 0;
+
+	*ber = (si21_readreg(state, 0x1d) << 8) |
+				si21_readreg(state, 0x1e);
+
+	return 0;
+}
+
+static int si21_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+	struct si21xx_state *state = fe->demodulator_priv;
+
+	s32 xsnr = 0xffff - ((si21_readreg(state, 0x24) << 8) |
+					si21_readreg(state, 0x25));
+	xsnr = 3 * (xsnr - 0xa100);
+	*snr = (xsnr > 0xffff) ? 0xffff : (xsnr < 0) ? 0 : xsnr;
+
+	dprintk("%s\n", __func__);
+
+	return 0;
+}
+
+static int si21_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
+{
+	struct si21xx_state *state = fe->demodulator_priv;
+
+	dprintk("%s\n", __func__);
+
+	if (state->errmode != STATUS_UCBLOCKS)
+		*ucblocks = 0;
+	else
+		*ucblocks = (si21_readreg(state, 0x1d) << 8) |
+					si21_readreg(state, 0x1e);
+
+	return 0;
+}
+
+/*	initiates a channel acquisition sequence
+	using the specified symbol rate and code rate */
+static int si21xx_setacquire(struct dvb_frontend *fe, int symbrate,
+						fe_code_rate_t crate)
+{
+
+	struct si21xx_state *state = fe->demodulator_priv;
+	u8 coderates[] = {
+				0x0, 0x01, 0x02, 0x04, 0x00,
+				0x8, 0x10, 0x20, 0x00, 0x3f
+	};
+
+	u8 coderate_ptr;
+	int status;
+	u8 start_acq = 0x80;
+	u8 reg, regs[3];
+
+	dprintk("%s\n", __func__);
+
+	status = PASS;
+	coderate_ptr = coderates[crate];
+
+	si21xx_set_symbolrate(fe, symbrate);
+
+	/* write code rates to use in the Viterbi search */
+	status |= si21_writeregs(state,
+				VIT_SRCH_CTRL_REG_1,
+				&coderate_ptr, 0x01);
+
+	/* clear acq_start bit */
+	status |= si21_readregs(state, ACQ_CTRL_REG_2, &reg, 0x01);
+	reg &= ~start_acq;
+	status |= si21_writeregs(state, ACQ_CTRL_REG_2, &reg, 0x01);
+
+	/* use new Carrier Frequency Offset Estimator (QuickLock) */
+	regs[0] = 0xCB;
+	regs[1] = 0x40;
+	regs[2] = 0xCB;
+
+	status |= si21_writeregs(state,
+				TWO_DB_BNDWDTH_THRSHLD_REG,
+				&regs[0], 0x03);
+	reg = 0x56;
+	status |= si21_writeregs(state,
+				LSA_CTRL_REG_1, &reg, 1);
+	reg = 0x05;
+	status |= si21_writeregs(state,
+				BLIND_SCAN_CTRL_REG, &reg, 1);
+	/* start automatic acq */
+	status |= si21_writeregs(state,
+				ACQ_CTRL_REG_2, &start_acq, 0x01);
+
+	return status;
+}
+
+static int si21xx_set_property(struct dvb_frontend *fe, struct dtv_property *p)
+{
+	dprintk("%s(..)\n", __func__);
+	return 0;
+}
+
+static int si21xx_get_property(struct dvb_frontend *fe, struct dtv_property *p)
+{
+	dprintk("%s(..)\n", __func__);
+	return 0;
+}
+
+static int si21xx_set_frontend(struct dvb_frontend *fe,
+					struct dvb_frontend_parameters *dfp)
+{
+	struct si21xx_state *state = fe->demodulator_priv;
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+
+	/* freq		Channel carrier frequency in KHz (i.e. 1550000 KHz)
+	 datarate	Channel symbol rate in Sps (i.e. 22500000 Sps)*/
+
+	/* in MHz */
+	unsigned char coarse_tune_freq;
+	int fine_tune_freq;
+	unsigned char sample_rate = 0;
+	/* boolean */
+	unsigned int inband_interferer_ind;
+
+	/* INTERMEDIATE VALUES */
+	int icoarse_tune_freq; /* MHz */
+	int ifine_tune_freq; /* MHz */
+	unsigned int band_high;
+	unsigned int band_low;
+	unsigned int x1;
+	unsigned int x2;
+	int i;
+	unsigned int inband_interferer_div2[ALLOWABLE_FS_COUNT] = {
+			FALSE, FALSE, FALSE, FALSE, FALSE,
+			FALSE, FALSE, FALSE, FALSE, FALSE
+	};
+	unsigned int inband_interferer_div4[ALLOWABLE_FS_COUNT] = {
+			FALSE, FALSE, FALSE, FALSE, FALSE,
+			FALSE, FALSE, FALSE, FALSE, FALSE
+	};
+
+	int status;
+
+	/* allowable sample rates for ADC in MHz */
+	int afs[ALLOWABLE_FS_COUNT] = { 200, 192, 193, 194, 195,
+					196, 204, 205, 206, 207
+	};
+	/* in MHz */
+	int if_limit_high;
+	int if_limit_low;
+	int lnb_lo;
+	int lnb_uncertanity;
+
+	int rf_freq;
+	int data_rate;
+	unsigned char regs[4];
+
+	dprintk("%s : FE_SET_FRONTEND\n", __func__);
+
+	if (c->delivery_system != SYS_DVBS) {
+			dprintk("%s: unsupported delivery system selected (%d)\n",
+				__func__, c->delivery_system);
+			return -EOPNOTSUPP;
+	}
+
+	for (i = 0; i < ALLOWABLE_FS_COUNT; ++i)
+		inband_interferer_div2[i] = inband_interferer_div4[i] = FALSE;
+
+	if_limit_high = -700000;
+	if_limit_low = -100000;
+	/* in MHz */
+	lnb_lo = 0;
+	lnb_uncertanity = 0;
+
+	rf_freq = 10 * c->frequency ;
+	data_rate = c->symbol_rate / 100;
+
+	status = PASS;
+
+	band_low = (rf_freq - lnb_lo) - ((lnb_uncertanity * 200)
+					+ (data_rate * 135)) / 200;
+
+	band_high = (rf_freq - lnb_lo) + ((lnb_uncertanity * 200)
+					+ (data_rate * 135)) / 200;
+
+
+	icoarse_tune_freq = 100000 *
+				(((rf_freq - lnb_lo) -
+					(if_limit_low + if_limit_high) / 2)
+								/ 100000);
+
+	ifine_tune_freq = (rf_freq - lnb_lo) - icoarse_tune_freq ;
+
+	for (i = 0; i < ALLOWABLE_FS_COUNT; ++i) {
+		x1 = ((rf_freq - lnb_lo) / (afs[i] * 2500)) *
+					(afs[i] * 2500) + afs[i] * 2500;
+
+		x2 = ((rf_freq - lnb_lo) / (afs[i] * 2500)) *
+							(afs[i] * 2500);
+
+		if (((band_low < x1) && (x1 < band_high)) ||
+					((band_low < x2) && (x2 < band_high)))
+					inband_interferer_div4[i] = TRUE;
+
+	}
+
+	for (i = 0; i < ALLOWABLE_FS_COUNT; ++i) {
+		x1 = ((rf_freq - lnb_lo) / (afs[i] * 5000)) *
+					(afs[i] * 5000) + afs[i] * 5000;
+
+		x2 = ((rf_freq - lnb_lo) / (afs[i] * 5000)) *
+					(afs[i] * 5000);
+
+		if (((band_low < x1) && (x1 < band_high)) ||
+					((band_low < x2) && (x2 < band_high)))
+					inband_interferer_div2[i] = TRUE;
+	}
+
+	inband_interferer_ind = TRUE;
+	for (i = 0; i < ALLOWABLE_FS_COUNT; ++i)
+		inband_interferer_ind &= inband_interferer_div2[i] |
+						inband_interferer_div4[i];
+
+	if (inband_interferer_ind) {
+		for (i = 0; i < ALLOWABLE_FS_COUNT; ++i) {
+			if (inband_interferer_div2[i] == FALSE) {
+				sample_rate = (u8) afs[i];
+				break;
+			}
+		}
+	} else {
+		for (i = 0; i < ALLOWABLE_FS_COUNT; ++i) {
+			if ((inband_interferer_div2[i] |
+					inband_interferer_div4[i]) == FALSE) {
+				sample_rate = (u8) afs[i];
+				break;
+			}
+		}
+
+	}
+
+	if (sample_rate > 207 || sample_rate < 192)
+		sample_rate = 200;
+
+	fine_tune_freq = ((0x4000 * (ifine_tune_freq / 10)) /
+					((sample_rate) * 1000));
+
+	coarse_tune_freq = (u8)(icoarse_tune_freq / 100000);
+
+	regs[0] = sample_rate;
+	regs[1] = coarse_tune_freq;
+	regs[2] = fine_tune_freq & 0xFF;
+	regs[3] = fine_tune_freq >> 8 & 0xFF;
+
+	status |= si21_writeregs(state, PLL_DIVISOR_REG, &regs[0], 0x04);
+
+	state->fs = sample_rate;/*ADC MHz*/
+	si21xx_setacquire(fe, c->symbol_rate, c->fec_inner);
+
+	return 0;
+}
+
+static int si21xx_sleep(struct dvb_frontend *fe)
+{
+	struct si21xx_state *state = fe->demodulator_priv;
+	u8 regdata;
+
+	dprintk("%s\n", __func__);
+
+	si21_readregs(state, SYSTEM_MODE_REG, &regdata, 0x01);
+	regdata |= 1 << 6;
+	si21_writeregs(state, SYSTEM_MODE_REG, &regdata, 0x01);
+	state->initialised = 0;
+
+	return 0;
+}
+
+static void si21xx_release(struct dvb_frontend *fe)
+{
+	struct si21xx_state *state = fe->demodulator_priv;
+
+	dprintk("%s\n", __func__);
+
+	kfree(state);
+}
+
+static struct dvb_frontend_ops si21xx_ops = {
+
+	.info = {
+		.name			= "SL SI21XX DVB-S",
+		.type			= FE_QPSK,
+		.frequency_min		= 950000,
+		.frequency_max		= 2150000,
+		.frequency_stepsize	= 125,	 /* kHz for QPSK frontends */
+		.frequency_tolerance	= 0,
+		.symbol_rate_min	= 1000000,
+		.symbol_rate_max	= 45000000,
+		.symbol_rate_tolerance	= 500,	/* ppm */
+		.caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+		FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 |
+		FE_CAN_QPSK |
+		FE_CAN_FEC_AUTO
+	},
+
+	.release = si21xx_release,
+	.init = si21xx_init,
+	.sleep = si21xx_sleep,
+	.write = si21_write,
+	.read_status = si21_read_status,
+	.read_ber = si21_read_ber,
+	.read_signal_strength = si21_read_signal_strength,
+	.read_snr = si21_read_snr,
+	.read_ucblocks = si21_read_ucblocks,
+	.diseqc_send_master_cmd = si21xx_send_diseqc_msg,
+	.diseqc_send_burst = si21xx_send_diseqc_burst,
+	.set_tone = si21xx_set_tone,
+	.set_voltage = si21xx_set_voltage,
+
+	.set_property = si21xx_set_property,
+	.get_property = si21xx_get_property,
+	.set_frontend = si21xx_set_frontend,
+};
+
+struct dvb_frontend *si21xx_attach(const struct si21xx_config *config,
+						struct i2c_adapter *i2c)
+{
+	struct si21xx_state *state = NULL;
+	int id;
+
+	dprintk("%s\n", __func__);
+
+	/* allocate memory for the internal state */
+	state = kmalloc(sizeof(struct si21xx_state), GFP_KERNEL);
+	if (state == NULL)
+		goto error;
+
+	/* setup the state */
+	state->config = config;
+	state->i2c = i2c;
+	state->initialised = 0;
+	state->errmode = STATUS_BER;
+
+	/* check if the demod is there */
+	id = si21_readreg(state, SYSTEM_MODE_REG);
+	si21_writereg(state, SYSTEM_MODE_REG, id | 0x40); /* standby off */
+	msleep(200);
+	id = si21_readreg(state, 0x00);
+
+	/* register 0x00 contains:
+		0x34 for SI2107
+		0x24 for SI2108
+		0x14 for SI2109
+		0x04 for SI2110
+	*/
+	if (id != 0x04 && id != 0x14)
+		goto error;
+
+	/* create dvb_frontend */
+	memcpy(&state->frontend.ops, &si21xx_ops,
+					sizeof(struct dvb_frontend_ops));
+	state->frontend.demodulator_priv = state;
+	return &state->frontend;
+
+error:
+	kfree(state);
+	return NULL;
+}
+EXPORT_SYMBOL(si21xx_attach);
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
+
+MODULE_DESCRIPTION("SL SI21XX DVB Demodulator driver");
+MODULE_AUTHOR("Igor M. Liplianin");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/si21xx.h b/drivers/media/dvb/frontends/si21xx.h
new file mode 100644
index 0000000..141b5b8
--- /dev/null
+++ b/drivers/media/dvb/frontends/si21xx.h
@@ -0,0 +1,37 @@
+#ifndef SI21XX_H
+#define SI21XX_H
+
+#include <linux/dvb/frontend.h>
+#include "dvb_frontend.h"
+
+struct si21xx_config {
+	/* the demodulator's i2c address */
+	u8 demod_address;
+
+	/* minimum delay before retuning */
+	int min_delay_ms;
+};
+
+#if defined(CONFIG_DVB_SI21XX) || \
+		(defined(CONFIG_DVB_SI21XX_MODULE) && defined(MODULE))
+extern struct dvb_frontend *si21xx_attach(const struct si21xx_config *config,
+						struct i2c_adapter *i2c);
+#else
+static inline struct dvb_frontend *si21xx_attach(
+		const struct si21xx_config *config, struct i2c_adapter *i2c)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+#endif
+
+static inline int si21xx_writeregister(struct dvb_frontend *fe, u8 reg, u8 val)
+{
+	int r = 0;
+	u8 buf[] = {reg, val};
+	if (fe->ops.write)
+		r = fe->ops.write(fe, buf, 2);
+	return r;
+}
+
+#endif
diff --git a/drivers/media/dvb/frontends/sp887x.c b/drivers/media/dvb/frontends/sp887x.c
index 4543609..559509a 100644
--- a/drivers/media/dvb/frontends/sp887x.c
+++ b/drivers/media/dvb/frontends/sp887x.c
@@ -337,7 +337,8 @@
 					     struct dvb_frontend_parameters *p)
 {
 	struct sp887x_state* state = fe->demodulator_priv;
-	int actual_freq, err;
+	unsigned actual_freq;
+	int err;
 	u16 val, reg0xc05;
 
 	if (p->u.ofdm.bandwidth != BANDWIDTH_8_MHZ &&
diff --git a/drivers/media/dvb/frontends/stb6000.c b/drivers/media/dvb/frontends/stb6000.c
new file mode 100644
index 0000000..0e2cb0d
--- /dev/null
+++ b/drivers/media/dvb/frontends/stb6000.c
@@ -0,0 +1,255 @@
+  /*
+     Driver for ST STB6000 DVBS Silicon tuner
+
+     Copyright (C) 2008 Igor M. Liplianin (liplianin@me.by)
+
+     This program is free software; you can redistribute it and/or modify
+     it under the terms of the GNU General Public License as published by
+     the Free Software Foundation; either version 2 of the License, or
+     (at your option) any later version.
+
+     This program is distributed in the hope that it will be useful,
+     but WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+
+     GNU General Public License for more details.
+
+     You should have received a copy of the GNU General Public License
+     along with this program; if not, write to the Free Software
+     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+  */
+
+#include <linux/module.h>
+#include <linux/dvb/frontend.h>
+#include <asm/types.h>
+
+#include "stb6000.h"
+
+static int debug;
+#define dprintk(args...) \
+	do { \
+		if (debug) \
+			printk(KERN_DEBUG "stb6000: " args); \
+	} while (0)
+
+struct stb6000_priv {
+	/* i2c details */
+	int i2c_address;
+	struct i2c_adapter *i2c;
+	u32 frequency;
+};
+
+static int stb6000_release(struct dvb_frontend *fe)
+{
+	kfree(fe->tuner_priv);
+	fe->tuner_priv = NULL;
+	return 0;
+}
+
+static int stb6000_sleep(struct dvb_frontend *fe)
+{
+	struct stb6000_priv *priv = fe->tuner_priv;
+	int ret;
+	u8 buf[] = { 10, 0 };
+	struct i2c_msg msg = {
+		.addr = priv->i2c_address,
+		.flags = 0,
+		.buf = buf,
+		.len = 2
+	};
+
+	dprintk("%s:\n", __func__);
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+
+	ret = i2c_transfer(priv->i2c, &msg, 1);
+	if (ret != 1)
+		dprintk("%s: i2c error\n", __func__);
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 0);
+
+	return (ret == 1) ? 0 : ret;
+}
+
+static int stb6000_set_params(struct dvb_frontend *fe,
+				struct dvb_frontend_parameters *params)
+{
+	struct stb6000_priv *priv = fe->tuner_priv;
+	unsigned int n, m;
+	int ret;
+	u32 freq_mhz;
+	int bandwidth;
+	u8 buf[12];
+	struct i2c_msg msg = {
+		.addr = priv->i2c_address,
+		.flags = 0,
+		.buf = buf,
+		.len = 12
+	};
+
+	dprintk("%s:\n", __func__);
+
+	freq_mhz = params->frequency / 1000;
+	bandwidth = params->u.qpsk.symbol_rate / 1000000;
+
+	if (bandwidth > 31)
+		bandwidth = 31;
+
+	if ((freq_mhz > 949) && (freq_mhz < 2151)) {
+		buf[0] = 0x01;
+		buf[1] = 0xac;
+		if (freq_mhz < 1950)
+			buf[1] = 0xaa;
+		if (freq_mhz < 1800)
+			buf[1] = 0xa8;
+		if (freq_mhz < 1650)
+			buf[1] = 0xa6;
+		if (freq_mhz < 1530)
+			buf[1] = 0xa5;
+		if (freq_mhz < 1470)
+			buf[1] = 0xa4;
+		if (freq_mhz < 1370)
+			buf[1] = 0xa2;
+		if (freq_mhz < 1300)
+			buf[1] = 0xa1;
+		if (freq_mhz < 1200)
+			buf[1] = 0xa0;
+		if (freq_mhz < 1075)
+			buf[1] = 0xbc;
+		if (freq_mhz < 1000)
+			buf[1] = 0xba;
+		if (freq_mhz < 1075) {
+			n = freq_mhz / 8; /* vco=lo*4 */
+			m = 2;
+		} else {
+			n = freq_mhz / 16; /* vco=lo*2 */
+			m = 1;
+		}
+		buf[2] = n >> 1;
+		buf[3] = (unsigned char)(((n & 1) << 7) |
+					(m * freq_mhz - n * 16) | 0x60);
+		buf[4] = 0x04;
+		buf[5] = 0x0e;
+
+		buf[6] = (unsigned char)(bandwidth);
+
+		buf[7] = 0xd8;
+		buf[8] = 0xd0;
+		buf[9] = 0x50;
+		buf[10] = 0xeb;
+		buf[11] = 0x4f;
+
+		if (fe->ops.i2c_gate_ctrl)
+			fe->ops.i2c_gate_ctrl(fe, 1);
+
+		ret = i2c_transfer(priv->i2c, &msg, 1);
+		if (ret != 1)
+			dprintk("%s: i2c error\n", __func__);
+
+		udelay(10);
+		if (fe->ops.i2c_gate_ctrl)
+			fe->ops.i2c_gate_ctrl(fe, 0);
+
+		buf[0] = 0x07;
+		buf[1] = 0xdf;
+		buf[2] = 0xd0;
+		buf[3] = 0x50;
+		buf[4] = 0xfb;
+		msg.len = 5;
+
+		if (fe->ops.i2c_gate_ctrl)
+			fe->ops.i2c_gate_ctrl(fe, 1);
+
+		ret = i2c_transfer(priv->i2c, &msg, 1);
+		if (ret != 1)
+			dprintk("%s: i2c error\n", __func__);
+
+		udelay(10);
+		if (fe->ops.i2c_gate_ctrl)
+			fe->ops.i2c_gate_ctrl(fe, 0);
+
+		priv->frequency = freq_mhz * 1000;
+
+		return (ret == 1) ? 0 : ret;
+	}
+	return -1;
+}
+
+static int stb6000_get_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+	struct stb6000_priv *priv = fe->tuner_priv;
+	*frequency = priv->frequency;
+	return 0;
+}
+
+static struct dvb_tuner_ops stb6000_tuner_ops = {
+	.info = {
+		.name = "ST STB6000",
+		.frequency_min = 950000,
+		.frequency_max = 2150000
+	},
+	.release = stb6000_release,
+	.sleep = stb6000_sleep,
+	.set_params = stb6000_set_params,
+	.get_frequency = stb6000_get_frequency,
+};
+
+struct dvb_frontend *stb6000_attach(struct dvb_frontend *fe, int addr,
+						struct i2c_adapter *i2c)
+{
+	struct stb6000_priv *priv = NULL;
+	u8 b0[] = { 0 };
+	u8 b1[] = { 0, 0 };
+	struct i2c_msg msg[2] = {
+		{
+			.addr = addr,
+			.flags = 0,
+			.buf = b0,
+			.len = 0
+		}, {
+			.addr = addr,
+			.flags = I2C_M_RD,
+			.buf = b1,
+			.len = 2
+		}
+	};
+	int ret;
+
+	dprintk("%s:\n", __func__);
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+
+	/* is some i2c device here ? */
+	ret = i2c_transfer(i2c, msg, 2);
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 0);
+
+	if (ret != 2)
+		return NULL;
+
+	priv = kzalloc(sizeof(struct stb6000_priv), GFP_KERNEL);
+	if (priv == NULL)
+		return NULL;
+
+	priv->i2c_address = addr;
+	priv->i2c = i2c;
+
+	memcpy(&fe->ops.tuner_ops, &stb6000_tuner_ops,
+				sizeof(struct dvb_tuner_ops));
+
+	fe->tuner_priv = priv;
+
+	return fe;
+}
+EXPORT_SYMBOL(stb6000_attach);
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
+
+MODULE_DESCRIPTION("DVB STB6000 driver");
+MODULE_AUTHOR("Igor M. Liplianin <liplianin@me.by>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/stb6000.h b/drivers/media/dvb/frontends/stb6000.h
new file mode 100644
index 0000000..7be479c
--- /dev/null
+++ b/drivers/media/dvb/frontends/stb6000.h
@@ -0,0 +1,51 @@
+  /*
+     Driver for ST stb6000 DVBS Silicon tuner
+
+     Copyright (C) 2008 Igor M. Liplianin (liplianin@me.by)
+
+     This program is free software; you can redistribute it and/or 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 __DVB_STB6000_H__
+#define __DVB_STB6000_H__
+
+#include <linux/i2c.h>
+#include "dvb_frontend.h"
+
+/**
+ * Attach a stb6000 tuner to the supplied frontend structure.
+ *
+ * @param fe Frontend to attach to.
+ * @param addr i2c address of the tuner.
+ * @param i2c i2c adapter to use.
+ * @return FE pointer on success, NULL on failure.
+ */
+#if defined(CONFIG_DVB_STB6000) || (defined(CONFIG_DVB_STB6000_MODULE) \
+							&& defined(MODULE))
+extern struct dvb_frontend *stb6000_attach(struct dvb_frontend *fe, int addr,
+					   struct i2c_adapter *i2c);
+#else
+static inline struct dvb_frontend *stb6000_attach(struct dvb_frontend *fe,
+						  int addr,
+						  struct i2c_adapter *i2c)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+#endif /* CONFIG_DVB_STB6000 */
+
+#endif /* __DVB_STB6000_H__ */
diff --git a/drivers/media/dvb/frontends/stv0288.c b/drivers/media/dvb/frontends/stv0288.c
new file mode 100644
index 0000000..ff1194d
--- /dev/null
+++ b/drivers/media/dvb/frontends/stv0288.c
@@ -0,0 +1,618 @@
+/*
+	Driver for ST STV0288 demodulator
+	Copyright (C) 2006 Georg Acher, BayCom GmbH, acher (at) baycom (dot) de
+		for Reel Multimedia
+	Copyright (C) 2008 TurboSight.com, Bob Liu <bob@turbosight.com>
+	Copyright (C) 2008 Igor M. Liplianin <liplianin@me.by>
+		Removed stb6000 specific tuner code and revised some
+		procedures.
+
+	This program is free software; you can redistribute it and/or 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/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/jiffies.h>
+#include <asm/div64.h>
+
+#include "dvb_frontend.h"
+#include "stv0288.h"
+
+struct stv0288_state {
+	struct i2c_adapter *i2c;
+	const struct stv0288_config *config;
+	struct dvb_frontend frontend;
+
+	u8 initialised:1;
+	u32 tuner_frequency;
+	u32 symbol_rate;
+	fe_code_rate_t fec_inner;
+	int errmode;
+};
+
+#define STATUS_BER 0
+#define STATUS_UCBLOCKS 1
+
+static int debug;
+static int debug_legacy_dish_switch;
+#define dprintk(args...) \
+	do { \
+		if (debug) \
+			printk(KERN_DEBUG "stv0288: " args); \
+	} while (0)
+
+
+static int stv0288_writeregI(struct stv0288_state *state, u8 reg, u8 data)
+{
+	int ret;
+	u8 buf[] = { reg, data };
+	struct i2c_msg msg = {
+		.addr = state->config->demod_address,
+		.flags = 0,
+		.buf = buf,
+		.len = 2
+	};
+
+	ret = i2c_transfer(state->i2c, &msg, 1);
+
+	if (ret != 1)
+		dprintk("%s: writereg error (reg == 0x%02x, val == 0x%02x, "
+			"ret == %i)\n", __func__, reg, data, ret);
+
+	return (ret != 1) ? -EREMOTEIO : 0;
+}
+
+static int stv0288_write(struct dvb_frontend *fe, u8 *buf, int len)
+{
+	struct stv0288_state *state = fe->demodulator_priv;
+
+	if (len != 2)
+		return -EINVAL;
+
+	return stv0288_writeregI(state, buf[0], buf[1]);
+}
+
+static u8 stv0288_readreg(struct stv0288_state *state, u8 reg)
+{
+	int ret;
+	u8 b0[] = { reg };
+	u8 b1[] = { 0 };
+	struct i2c_msg msg[] = {
+		{
+			.addr = state->config->demod_address,
+			.flags = 0,
+			.buf = b0,
+			.len = 1
+		}, {
+			.addr = state->config->demod_address,
+			.flags = I2C_M_RD,
+			.buf = b1,
+			.len = 1
+		}
+	};
+
+	ret = i2c_transfer(state->i2c, msg, 2);
+
+	if (ret != 2)
+		dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n",
+				__func__, reg, ret);
+
+	return b1[0];
+}
+
+static int stv0288_set_symbolrate(struct dvb_frontend *fe, u32 srate)
+{
+	struct stv0288_state *state = fe->demodulator_priv;
+	unsigned int temp;
+	unsigned char b[3];
+
+	if ((srate < 1000000) || (srate > 45000000))
+		return -EINVAL;
+
+	temp = (unsigned int)srate / 1000;
+
+		temp = temp * 32768;
+		temp = temp / 25;
+		temp = temp / 125;
+		b[0] = (unsigned char)((temp >> 12) & 0xff);
+		b[1] = (unsigned char)((temp >> 4) & 0xff);
+		b[2] = (unsigned char)((temp << 4) & 0xf0);
+		stv0288_writeregI(state, 0x28, 0x80); /* SFRH */
+		stv0288_writeregI(state, 0x29, 0); /* SFRM */
+		stv0288_writeregI(state, 0x2a, 0); /* SFRL */
+
+		stv0288_writeregI(state, 0x28, b[0]);
+		stv0288_writeregI(state, 0x29, b[1]);
+		stv0288_writeregI(state, 0x2a, b[2]);
+		dprintk("stv0288: stv0288_set_symbolrate\n");
+
+	return 0;
+}
+
+static int stv0288_send_diseqc_msg(struct dvb_frontend *fe,
+				    struct dvb_diseqc_master_cmd *m)
+{
+	struct stv0288_state *state = fe->demodulator_priv;
+
+	int i;
+
+	dprintk("%s\n", __func__);
+
+	stv0288_writeregI(state, 0x09, 0);
+	msleep(30);
+	stv0288_writeregI(state, 0x05, 0x16);
+
+	for (i = 0; i < m->msg_len; i++) {
+		if (stv0288_writeregI(state, 0x06, m->msg[i]))
+			return -EREMOTEIO;
+		msleep(12);
+	}
+
+	return 0;
+}
+
+static int stv0288_send_diseqc_burst(struct dvb_frontend *fe,
+						fe_sec_mini_cmd_t burst)
+{
+	struct stv0288_state *state = fe->demodulator_priv;
+
+	dprintk("%s\n", __func__);
+
+	if (stv0288_writeregI(state, 0x05, 0x16))/* burst mode */
+		return -EREMOTEIO;
+
+	if (stv0288_writeregI(state, 0x06, burst == SEC_MINI_A ? 0x00 : 0xff))
+		return -EREMOTEIO;
+
+	if (stv0288_writeregI(state, 0x06, 0x12))
+		return -EREMOTEIO;
+
+	return 0;
+}
+
+static int stv0288_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone)
+{
+	struct stv0288_state *state = fe->demodulator_priv;
+
+	switch (tone) {
+	case SEC_TONE_ON:
+		if (stv0288_writeregI(state, 0x05, 0x10))/* burst mode */
+			return -EREMOTEIO;
+		return stv0288_writeregI(state, 0x06, 0xff);
+
+	case SEC_TONE_OFF:
+		if (stv0288_writeregI(state, 0x05, 0x13))/* burst mode */
+			return -EREMOTEIO;
+		return stv0288_writeregI(state, 0x06, 0x00);
+
+	default:
+		return -EINVAL;
+	}
+}
+
+static u8 stv0288_inittab[] = {
+	0x01, 0x15,
+	0x02, 0x20,
+	0x09, 0x0,
+	0x0a, 0x4,
+	0x0b, 0x0,
+	0x0c, 0x0,
+	0x0d, 0x0,
+	0x0e, 0xd4,
+	0x0f, 0x30,
+	0x11, 0x80,
+	0x12, 0x03,
+	0x13, 0x48,
+	0x14, 0x84,
+	0x15, 0x45,
+	0x16, 0xb7,
+	0x17, 0x9c,
+	0x18, 0x0,
+	0x19, 0xa6,
+	0x1a, 0x88,
+	0x1b, 0x8f,
+	0x1c, 0xf0,
+	0x20, 0x0b,
+	0x21, 0x54,
+	0x22, 0x0,
+	0x23, 0x0,
+	0x2b, 0xff,
+	0x2c, 0xf7,
+	0x30, 0x0,
+	0x31, 0x1e,
+	0x32, 0x14,
+	0x33, 0x0f,
+	0x34, 0x09,
+	0x35, 0x0c,
+	0x36, 0x05,
+	0x37, 0x2f,
+	0x38, 0x16,
+	0x39, 0xbe,
+	0x3a, 0x0,
+	0x3b, 0x13,
+	0x3c, 0x11,
+	0x3d, 0x30,
+	0x40, 0x63,
+	0x41, 0x04,
+	0x42, 0x60,
+	0x43, 0x00,
+	0x44, 0x00,
+	0x45, 0x00,
+	0x46, 0x00,
+	0x47, 0x00,
+	0x4a, 0x00,
+	0x50, 0x10,
+	0x51, 0x38,
+	0x52, 0x21,
+	0x58, 0x54,
+	0x59, 0x86,
+	0x5a, 0x0,
+	0x5b, 0x9b,
+	0x5c, 0x08,
+	0x5d, 0x7f,
+	0x5e, 0x0,
+	0x5f, 0xff,
+	0x70, 0x0,
+	0x71, 0x0,
+	0x72, 0x0,
+	0x74, 0x0,
+	0x75, 0x0,
+	0x76, 0x0,
+	0x81, 0x0,
+	0x82, 0x3f,
+	0x83, 0x3f,
+	0x84, 0x0,
+	0x85, 0x0,
+	0x88, 0x0,
+	0x89, 0x0,
+	0x8a, 0x0,
+	0x8b, 0x0,
+	0x8c, 0x0,
+	0x90, 0x0,
+	0x91, 0x0,
+	0x92, 0x0,
+	0x93, 0x0,
+	0x94, 0x1c,
+	0x97, 0x0,
+	0xa0, 0x48,
+	0xa1, 0x0,
+	0xb0, 0xb8,
+	0xb1, 0x3a,
+	0xb2, 0x10,
+	0xb3, 0x82,
+	0xb4, 0x80,
+	0xb5, 0x82,
+	0xb6, 0x82,
+	0xb7, 0x82,
+	0xb8, 0x20,
+	0xb9, 0x0,
+	0xf0, 0x0,
+	0xf1, 0x0,
+	0xf2, 0xc0,
+	0x51, 0x36,
+	0x52, 0x09,
+	0x53, 0x94,
+	0x54, 0x62,
+	0x55, 0x29,
+	0x56, 0x64,
+	0x57, 0x2b,
+	0xff, 0xff,
+};
+
+static int stv0288_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t volt)
+{
+	dprintk("%s: %s\n", __func__,
+		volt == SEC_VOLTAGE_13 ? "SEC_VOLTAGE_13" :
+		volt == SEC_VOLTAGE_18 ? "SEC_VOLTAGE_18" : "??");
+
+	return 0;
+}
+
+static int stv0288_init(struct dvb_frontend *fe)
+{
+	struct stv0288_state *state = fe->demodulator_priv;
+	int i;
+	u8 reg;
+	u8 val;
+
+	dprintk("stv0288: init chip\n");
+	stv0288_writeregI(state, 0x41, 0x04);
+	msleep(50);
+
+	/* we have default inittab */
+	if (state->config->inittab == NULL) {
+		for (i = 0; !(stv0288_inittab[i] == 0xff &&
+				stv0288_inittab[i + 1] == 0xff); i += 2)
+			stv0288_writeregI(state, stv0288_inittab[i],
+					stv0288_inittab[i + 1]);
+	} else {
+		for (i = 0; ; i += 2)  {
+			reg = state->config->inittab[i];
+			val = state->config->inittab[i+1];
+			if (reg == 0xff && val == 0xff)
+				break;
+			stv0288_writeregI(state, reg, val);
+		}
+	}
+	return 0;
+}
+
+static int stv0288_read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+	struct stv0288_state *state = fe->demodulator_priv;
+
+	u8 sync = stv0288_readreg(state, 0x24);
+	if (sync == 255)
+		sync = 0;
+
+	dprintk("%s : FE_READ_STATUS : VSTATUS: 0x%02x\n", __func__, sync);
+
+	*status = 0;
+
+	if ((sync & 0x08) == 0x08) {
+		*status |= FE_HAS_LOCK;
+		dprintk("stv0288 has locked\n");
+	}
+
+	return 0;
+}
+
+static int stv0288_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+	struct stv0288_state *state = fe->demodulator_priv;
+
+	if (state->errmode != STATUS_BER)
+		return 0;
+	*ber = (stv0288_readreg(state, 0x26) << 8) |
+					stv0288_readreg(state, 0x27);
+	dprintk("stv0288_read_ber %d\n", *ber);
+
+	return 0;
+}
+
+
+static int stv0288_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
+{
+	struct stv0288_state *state = fe->demodulator_priv;
+
+	s32 signal =  0xffff - ((stv0288_readreg(state, 0x10) << 8));
+
+
+	signal = signal * 5 / 4;
+	*strength = (signal > 0xffff) ? 0xffff : (signal < 0) ? 0 : signal;
+	dprintk("stv0288_read_signal_strength %d\n", *strength);
+
+	return 0;
+}
+static int stv0288_sleep(struct dvb_frontend *fe)
+{
+	struct stv0288_state *state = fe->demodulator_priv;
+
+	stv0288_writeregI(state, 0x41, 0x84);
+	state->initialised = 0;
+
+	return 0;
+}
+static int stv0288_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+	struct stv0288_state *state = fe->demodulator_priv;
+
+	s32 xsnr = 0xffff - ((stv0288_readreg(state, 0x2d) << 8)
+			   | stv0288_readreg(state, 0x2e));
+	xsnr = 3 * (xsnr - 0xa100);
+	*snr = (xsnr > 0xffff) ? 0xffff : (xsnr < 0) ? 0 : xsnr;
+	dprintk("stv0288_read_snr %d\n", *snr);
+
+	return 0;
+}
+
+static int stv0288_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
+{
+	struct stv0288_state *state = fe->demodulator_priv;
+
+	if (state->errmode != STATUS_BER)
+		return 0;
+	*ucblocks = (stv0288_readreg(state, 0x26) << 8) |
+					stv0288_readreg(state, 0x27);
+	dprintk("stv0288_read_ber %d\n", *ucblocks);
+
+	return 0;
+}
+
+static int stv0288_set_property(struct dvb_frontend *fe, struct dtv_property *p)
+{
+	dprintk("%s(..)\n", __func__);
+	return 0;
+}
+
+static int stv0288_get_property(struct dvb_frontend *fe, struct dtv_property *p)
+{
+	dprintk("%s(..)\n", __func__);
+	return 0;
+}
+
+static int stv0288_set_frontend(struct dvb_frontend *fe,
+					struct dvb_frontend_parameters *dfp)
+{
+	struct stv0288_state *state = fe->demodulator_priv;
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+
+	char tm;
+	unsigned char tda[3];
+
+	dprintk("%s : FE_SET_FRONTEND\n", __func__);
+
+	if (c->delivery_system != SYS_DVBS) {
+			dprintk("%s: unsupported delivery "
+				"system selected (%d)\n",
+				__func__, c->delivery_system);
+			return -EOPNOTSUPP;
+	}
+
+	if (state->config->set_ts_params)
+		state->config->set_ts_params(fe, 0);
+
+	/* only frequency & symbol_rate are used for tuner*/
+	dfp->frequency = c->frequency;
+	dfp->u.qpsk.symbol_rate = c->symbol_rate;
+	if (fe->ops.tuner_ops.set_params) {
+		fe->ops.tuner_ops.set_params(fe, dfp);
+		if (fe->ops.i2c_gate_ctrl)
+			fe->ops.i2c_gate_ctrl(fe, 0);
+	}
+
+	udelay(10);
+	stv0288_set_symbolrate(fe, c->symbol_rate);
+	/* Carrier lock control register */
+	stv0288_writeregI(state, 0x15, 0xc5);
+
+	tda[0] = 0x2b; /* CFRM */
+	tda[2] = 0x0; /* CFRL */
+	for (tm = -6; tm < 7;) {
+		/* Viterbi status */
+		if (stv0288_readreg(state, 0x24) & 0x80)
+			break;
+
+		tda[2] += 40;
+		if (tda[2] < 40)
+			tm++;
+		tda[1] = (unsigned char)tm;
+		stv0288_writeregI(state, 0x2b, tda[1]);
+		stv0288_writeregI(state, 0x2c, tda[2]);
+		udelay(30);
+	}
+
+	state->tuner_frequency = c->frequency;
+	state->fec_inner = FEC_AUTO;
+	state->symbol_rate = c->symbol_rate;
+
+	return 0;
+}
+
+static int stv0288_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
+{
+	struct stv0288_state *state = fe->demodulator_priv;
+
+	if (enable)
+		stv0288_writeregI(state, 0x01, 0xb5);
+	else
+		stv0288_writeregI(state, 0x01, 0x35);
+
+	udelay(1);
+
+	return 0;
+}
+
+static void stv0288_release(struct dvb_frontend *fe)
+{
+	struct stv0288_state *state = fe->demodulator_priv;
+	kfree(state);
+}
+
+static struct dvb_frontend_ops stv0288_ops = {
+
+	.info = {
+		.name			= "ST STV0288 DVB-S",
+		.type			= FE_QPSK,
+		.frequency_min		= 950000,
+		.frequency_max		= 2150000,
+		.frequency_stepsize	= 1000,	 /* kHz for QPSK frontends */
+		.frequency_tolerance	= 0,
+		.symbol_rate_min	= 1000000,
+		.symbol_rate_max	= 45000000,
+		.symbol_rate_tolerance	= 500,	/* ppm */
+		.caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+		      FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 |
+		      FE_CAN_QPSK |
+		      FE_CAN_FEC_AUTO
+	},
+
+	.release = stv0288_release,
+	.init = stv0288_init,
+	.sleep = stv0288_sleep,
+	.write = stv0288_write,
+	.i2c_gate_ctrl = stv0288_i2c_gate_ctrl,
+	.read_status = stv0288_read_status,
+	.read_ber = stv0288_read_ber,
+	.read_signal_strength = stv0288_read_signal_strength,
+	.read_snr = stv0288_read_snr,
+	.read_ucblocks = stv0288_read_ucblocks,
+	.diseqc_send_master_cmd = stv0288_send_diseqc_msg,
+	.diseqc_send_burst = stv0288_send_diseqc_burst,
+	.set_tone = stv0288_set_tone,
+	.set_voltage = stv0288_set_voltage,
+
+	.set_property = stv0288_set_property,
+	.get_property = stv0288_get_property,
+	.set_frontend = stv0288_set_frontend,
+};
+
+struct dvb_frontend *stv0288_attach(const struct stv0288_config *config,
+				    struct i2c_adapter *i2c)
+{
+	struct stv0288_state *state = NULL;
+	int id;
+
+	/* allocate memory for the internal state */
+	state = kmalloc(sizeof(struct stv0288_state), GFP_KERNEL);
+	if (state == NULL)
+		goto error;
+
+	/* setup the state */
+	state->config = config;
+	state->i2c = i2c;
+	state->initialised = 0;
+	state->tuner_frequency = 0;
+	state->symbol_rate = 0;
+	state->fec_inner = 0;
+	state->errmode = STATUS_BER;
+
+	stv0288_writeregI(state, 0x41, 0x04);
+	msleep(200);
+	id = stv0288_readreg(state, 0x00);
+	dprintk("stv0288 id %x\n", id);
+
+	/* register 0x00 contains 0x11 for STV0288  */
+	if (id != 0x11)
+		goto error;
+
+	/* create dvb_frontend */
+	memcpy(&state->frontend.ops, &stv0288_ops,
+			sizeof(struct dvb_frontend_ops));
+	state->frontend.demodulator_priv = state;
+	return &state->frontend;
+
+error:
+	kfree(state);
+
+	return NULL;
+}
+EXPORT_SYMBOL(stv0288_attach);
+
+module_param(debug_legacy_dish_switch, int, 0444);
+MODULE_PARM_DESC(debug_legacy_dish_switch,
+		"Enable timing analysis for Dish Network legacy switches");
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
+
+MODULE_DESCRIPTION("ST STV0288 DVB Demodulator driver");
+MODULE_AUTHOR("Georg Acher, Bob Liu, Igor liplianin");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/media/dvb/frontends/stv0288.h b/drivers/media/dvb/frontends/stv0288.h
new file mode 100644
index 0000000..f2b53db
--- /dev/null
+++ b/drivers/media/dvb/frontends/stv0288.h
@@ -0,0 +1,67 @@
+/*
+	Driver for ST STV0288 demodulator
+
+	Copyright (C) 2006 Georg Acher, BayCom GmbH, acher (at) baycom (dot) de
+		for Reel Multimedia
+	Copyright (C) 2008 TurboSight.com, <bob@turbosight.com>
+	Copyright (C) 2008 Igor M. Liplianin <liplianin@me.by>
+		Removed stb6000 specific tuner code and revised some
+		procedures.
+
+	This program is free software; you can redistribute it and/or 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 STV0288_H
+#define STV0288_H
+
+#include <linux/dvb/frontend.h>
+#include "dvb_frontend.h"
+
+struct stv0288_config {
+	/* the demodulator's i2c address */
+	u8 demod_address;
+
+	u8* inittab;
+
+	/* minimum delay before retuning */
+	int min_delay_ms;
+
+	int (*set_ts_params)(struct dvb_frontend *fe, int is_punctured);
+};
+
+#if defined(CONFIG_DVB_STV0288) || (defined(CONFIG_DVB_STV0288_MODULE) && \
+							defined(MODULE))
+extern struct dvb_frontend *stv0288_attach(const struct stv0288_config *config,
+					   struct i2c_adapter *i2c);
+#else
+static inline struct dvb_frontend *stv0288_attach(const struct stv0288_config *config,
+					   struct i2c_adapter *i2c)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+#endif /* CONFIG_DVB_STV0288 */
+
+static inline int stv0288_writereg(struct dvb_frontend *fe, u8 reg, u8 val)
+{
+	int r = 0;
+	u8 buf[] = { reg, val };
+	if (fe->ops.write)
+		r = fe->ops.write(fe, buf, 2);
+	return r;
+}
+
+#endif /* STV0288_H */
diff --git a/drivers/media/dvb/frontends/stv0299.c b/drivers/media/dvb/frontends/stv0299.c
index 35435be..6c1cb19 100644
--- a/drivers/media/dvb/frontends/stv0299.c
+++ b/drivers/media/dvb/frontends/stv0299.c
@@ -559,6 +559,8 @@
 	int invval = 0;
 
 	dprintk ("%s : FE_SET_FRONTEND\n", __func__);
+	if (state->config->set_ts_params)
+		state->config->set_ts_params(fe, 0);
 
 	// set the inversion
 	if (p->inversion == INVERSION_OFF) invval = 0;
diff --git a/drivers/media/dvb/frontends/stv0299.h b/drivers/media/dvb/frontends/stv0299.h
index 3282f43..0fd96e2 100644
--- a/drivers/media/dvb/frontends/stv0299.h
+++ b/drivers/media/dvb/frontends/stv0299.h
@@ -89,15 +89,18 @@
 	int min_delay_ms;
 
 	/* Set the symbol rate */
-	int (*set_symbol_rate)(struct dvb_frontend* fe, u32 srate, u32 ratio);
+	int (*set_symbol_rate)(struct dvb_frontend *fe, u32 srate, u32 ratio);
+
+	/* Set device param to start dma */
+	int (*set_ts_params)(struct dvb_frontend *fe, int is_punctured);
 };
 
 #if defined(CONFIG_DVB_STV0299) || (defined(CONFIG_DVB_STV0299_MODULE) && defined(MODULE))
-extern struct dvb_frontend* stv0299_attach(const struct stv0299_config* config,
-					   struct i2c_adapter* i2c);
+extern struct dvb_frontend *stv0299_attach(const struct stv0299_config *config,
+					   struct i2c_adapter *i2c);
 #else
-static inline struct dvb_frontend* stv0299_attach(const struct stv0299_config* config,
-					   struct i2c_adapter* i2c)
+static inline struct dvb_frontend *stv0299_attach(const struct stv0299_config *config,
+					   struct i2c_adapter *i2c)
 {
 	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
 	return NULL;
diff --git a/drivers/media/dvb/frontends/tdhd1.h b/drivers/media/dvb/frontends/tdhd1.h
new file mode 100644
index 0000000..51f1706
--- /dev/null
+++ b/drivers/media/dvb/frontends/tdhd1.h
@@ -0,0 +1,73 @@
+/*
+ * tdhd1.h - ALPS TDHD1-204A tuner support
+ *
+ * Copyright (C) 2008 Oliver Endriss <o.endriss@gmx.de>
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ *
+ *
+ * The project's page is at http://www.linuxtv.org
+ */
+
+#ifndef TDHD1_H
+#define TDHD1_H
+
+#include "tda1004x.h"
+
+static int alps_tdhd1_204_request_firmware(struct dvb_frontend *fe, const struct firmware **fw, char *name);
+
+static struct tda1004x_config alps_tdhd1_204a_config = {
+	.demod_address = 0x8,
+	.invert = 1,
+	.invert_oclk = 0,
+	.xtal_freq = TDA10046_XTAL_4M,
+	.agc_config = TDA10046_AGC_DEFAULT,
+	.if_freq = TDA10046_FREQ_3617,
+	.request_firmware = alps_tdhd1_204_request_firmware
+};
+
+static int alps_tdhd1_204a_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+{
+	struct i2c_adapter *i2c = fe->tuner_priv;
+	u8 data[4];
+	struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) };
+	u32 div;
+
+	div = (params->frequency + 36166666) / 166666;
+
+	data[0] = (div >> 8) & 0x7f;
+	data[1] = div & 0xff;
+	data[2] = 0x85;
+
+	if (params->frequency >= 174000000 && params->frequency <= 230000000)
+		data[3] = 0x02;
+	else if (params->frequency >= 470000000 && params->frequency <= 823000000)
+		data[3] = 0x0C;
+	else if (params->frequency > 823000000 && params->frequency <= 862000000)
+		data[3] = 0x8C;
+	else
+		return -EINVAL;
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+	if (i2c_transfer(i2c, &msg, 1) != 1)
+		return -EIO;
+
+	return 0;
+}
+
+#endif /* TDHD1_H */
diff --git a/drivers/media/dvb/siano/sms-cards.c b/drivers/media/dvb/siano/sms-cards.c
index cc5efb6..9da260f 100644
--- a/drivers/media/dvb/siano/sms-cards.c
+++ b/drivers/media/dvb/siano/sms-cards.c
@@ -40,6 +40,8 @@
 		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_OKEMO_B },
 	{ USB_DEVICE(0x2040, 0x5500),
 		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
+	{ USB_DEVICE(0x2040, 0x5510),
+		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
 	{ USB_DEVICE(0x2040, 0x5580),
 		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
 	{ USB_DEVICE(0x2040, 0x5590),
@@ -87,7 +89,7 @@
 		.fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-nova-b-dvbt-01.fw",
 	},
 	[SMS1XXX_BOARD_HAUPPAUGE_WINDHAM] = {
-		.name	= "Hauppauge WinTV-Nova-T-MiniStick",
+		.name	= "Hauppauge WinTV MiniStick",
 		.type	= SMS_NOVA_B0,
 		.fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-hcw-55xxx-dvbt-01.fw",
 	},
diff --git a/drivers/media/dvb/ttpci/Kconfig b/drivers/media/dvb/ttpci/Kconfig
index 41b5a98..867027c 100644
--- a/drivers/media/dvb/ttpci/Kconfig
+++ b/drivers/media/dvb/ttpci/Kconfig
@@ -86,6 +86,7 @@
 	select DVB_TDA10086 if !DVB_FE_CUSTOMISE
 	select DVB_TDA826X if !DVB_FE_CUSTOMISE
 	select DVB_LNBP21 if !DVB_FE_CUSTOMISE
+	select DVB_TDA1004X if !DVB_FE_CUSTOMISE
 	help
 	  Support for simple SAA7146 based DVB cards (so called Budget-
 	  or Nova-PCI cards) without onboard MPEG2 decoder, and without
diff --git a/drivers/media/dvb/ttpci/av7110.c b/drivers/media/dvb/ttpci/av7110.c
index 0777e8f..c7c770c 100644
--- a/drivers/media/dvb/ttpci/av7110.c
+++ b/drivers/media/dvb/ttpci/av7110.c
@@ -88,6 +88,7 @@
 static int wss_cfg_4_3 = 0x4008;
 static int wss_cfg_16_9 = 0x0007;
 static int tv_standard;
+static int full_ts;
 
 module_param_named(debug, av7110_debug, int, 0644);
 MODULE_PARM_DESC(debug, "debug level (bitmask, default 0)");
@@ -106,6 +107,8 @@
 MODULE_PARM_DESC(volume, "initial volume: default 255 (range 0-255)");
 module_param(budgetpatch, int, 0444);
 MODULE_PARM_DESC(budgetpatch, "use budget-patch hardware modification: default 0 (0 no, 1 autodetect, 2 always)");
+module_param(full_ts, int, 0444);
+MODULE_PARM_DESC(full_ts, "enable code for full-ts hardware modification: 0 disable (default), 1 enable");
 module_param(wss_cfg_4_3, int, 0444);
 MODULE_PARM_DESC(wss_cfg_4_3, "WSS 4:3 - default 0x4008 - bit 15: disable, 14: burst mode, 13..0: wss data");
 module_param(wss_cfg_16_9, int, 0444);
@@ -116,6 +119,8 @@
 DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
 
 static void restart_feeds(struct av7110 *av7110);
+static int budget_start_feed(struct dvb_demux_feed *feed);
+static int budget_stop_feed(struct dvb_demux_feed *feed);
 
 static int av7110_num;
 
@@ -376,9 +381,9 @@
 		irdebi(av7110, DEBISWAB, addr, 0, len);
 }
 
-static void debiirq(unsigned long data)
+static void debiirq(unsigned long cookie)
 {
-	struct av7110 *av7110 = (struct av7110 *) data;
+	struct av7110 *av7110 = (struct av7110 *)cookie;
 	int type = av7110->debitype;
 	int handle = (type >> 8) & 0x1f;
 	unsigned int xfer = 0;
@@ -487,9 +492,9 @@
 }
 
 /* irq from av7110 firmware writing the mailbox register in the DPRAM */
-static void gpioirq(unsigned long data)
+static void gpioirq(unsigned long cookie)
 {
-	struct av7110 *av7110 = (struct av7110 *) data;
+	struct av7110 *av7110 = (struct av7110 *)cookie;
 	u32 rxbuf, txbuf;
 	int len;
 
@@ -806,6 +811,9 @@
 
 	dprintk(4, "%p\n", av7110);
 
+	if (av7110->full_ts)
+		return 0;
+
 	if (dvbdmxfilter->type == DMX_TYPE_SEC) {
 		if (hw_sections) {
 			buf[4] = (dvbdmxfilter->filter.filter_value[0] << 8) |
@@ -854,6 +862,9 @@
 
 	dprintk(4, "%p\n", av7110);
 
+	if (av7110->full_ts)
+		return 0;
+
 	handle = dvbdmxfilter->hw_handle;
 	if (handle >= 32) {
 		printk("%s tried to stop invalid filter %04x, filter type = %x\n",
@@ -913,7 +924,7 @@
 				return ret;
 		}
 
-	if ((dvbdmxfeed->ts_type & TS_PACKET)) {
+	if ((dvbdmxfeed->ts_type & TS_PACKET) && !av7110->full_ts) {
 		if (dvbdmxfeed->pes_type == 0 && !(dvbdmx->pids[0] & 0x8000))
 			ret = av7110_av_start_record(av7110, RP_AUDIO, dvbdmxfeed);
 		if (dvbdmxfeed->pes_type == 1 && !(dvbdmx->pids[1] & 0x8000))
@@ -974,7 +985,7 @@
 	if (!demux->dmx.frontend)
 		return -EINVAL;
 
-	if (feed->pid > 0x1fff)
+	if (!av7110->full_ts && feed->pid > 0x1fff)
 		return -EINVAL;
 
 	if (feed->type == DMX_TYPE_TS) {
@@ -1003,7 +1014,12 @@
 		}
 	}
 
-	else if (feed->type == DMX_TYPE_SEC) {
+	if (av7110->full_ts) {
+		budget_start_feed(feed);
+		return ret;
+	}
+
+	if (feed->type == DMX_TYPE_SEC) {
 		int i;
 
 		for (i = 0; i < demux->filternum; i++) {
@@ -1050,7 +1066,12 @@
 				ret = StopHWFilter(feed->filter);
 	}
 
-	if (!ret && feed->type == DMX_TYPE_SEC) {
+	if (av7110->full_ts) {
+		budget_stop_feed(feed);
+		return ret;
+	}
+
+	if (feed->type == DMX_TYPE_SEC) {
 		for (i = 0; i<demux->filternum; i++) {
 			if (demux->filter[i].state == DMX_STATE_GO &&
 			    demux->filter[i].filter.parent == &feed->feed.sec) {
@@ -1074,6 +1095,7 @@
 	struct dvb_demux *dvbdmx = &av7110->demux;
 	struct dvb_demux_feed *feed;
 	int mode;
+	int feeding;
 	int i, j;
 
 	dprintk(4, "%p\n", av7110);
@@ -1082,6 +1104,8 @@
 	av7110->playing = 0;
 	av7110->rec_mode = 0;
 
+	feeding = av7110->feeding1; /* full_ts mod */
+
 	for (i = 0; i < dvbdmx->feednum; i++) {
 		feed = &dvbdmx->feed[i];
 		if (feed->state == DMX_STATE_GO) {
@@ -1099,6 +1123,8 @@
 		}
 	}
 
+	av7110->feeding1 = feeding; /* full_ts mod */
+
 	if (mode)
 		av7110_av_start_play(av7110, mode);
 }
@@ -1197,8 +1223,9 @@
 
 	if (budget->feeding1)
 		return ++budget->feeding1;
-	memset(budget->grabbing, 0x00, TS_HEIGHT * TS_WIDTH);
+	memset(budget->grabbing, 0x00, TS_BUFLEN);
 	budget->ttbp = 0;
+	SAA7146_ISR_CLEAR(budget->dev, MASK_10);  /* VPE */
 	SAA7146_IER_ENABLE(budget->dev, MASK_10); /* VPE */
 	saa7146_write(budget->dev, MC1, (MASK_04 | MASK_20)); /* DMA3 on */
 	return ++budget->feeding1;
@@ -1233,18 +1260,14 @@
 	return status;
 }
 
-static void vpeirq(unsigned long data)
+static void vpeirq(unsigned long cookie)
 {
-	struct av7110 *budget = (struct av7110 *) data;
+	struct av7110 *budget = (struct av7110 *)cookie;
 	u8 *mem = (u8 *) (budget->grabbing);
 	u32 olddma = budget->ttbp;
 	u32 newdma = saa7146_read(budget->dev, PCI_VDP3);
+	struct dvb_demux *demux = budget->full_ts ? &budget->demux : &budget->demux1;
 
-	if (!budgetpatch) {
-		printk("av7110.c: vpeirq() called while budgetpatch disabled!"
-		       " check saa7146 IER register\n");
-		BUG();
-	}
 	/* nearest lower position divisible by 188 */
 	newdma -= newdma % 188;
 
@@ -1268,11 +1291,11 @@
 
 	if (newdma > olddma)
 		/* no wraparound, dump olddma..newdma */
-		dvb_dmx_swfilter_packets(&budget->demux1, mem + olddma, (newdma - olddma) / 188);
+		dvb_dmx_swfilter_packets(demux, mem + olddma, (newdma - olddma) / 188);
 	else {
 		/* wraparound, dump olddma..buflen and 0..newdma */
-		dvb_dmx_swfilter_packets(&budget->demux1, mem + olddma, (TS_BUFLEN - olddma) / 188);
-		dvb_dmx_swfilter_packets(&budget->demux1, mem, newdma / 188);
+		dvb_dmx_swfilter_packets(demux, mem + olddma, (TS_BUFLEN - olddma) / 188);
+		dvb_dmx_swfilter_packets(demux, mem, newdma / 188);
 	}
 }
 
@@ -1294,8 +1317,8 @@
 	for (i = 0; i < 32; i++)
 		av7110->handle2filter[i] = NULL;
 
-	dvbdemux->filternum = 32;
-	dvbdemux->feednum = 32;
+	dvbdemux->filternum = (av7110->full_ts) ? 256 : 32;
+	dvbdemux->feednum = (av7110->full_ts) ? 256 : 32;
 	dvbdemux->start_feed = av7110_start_feed;
 	dvbdemux->stop_feed = av7110_stop_feed;
 	dvbdemux->write_to_decoder = av7110_write_to_decoder;
@@ -1305,7 +1328,7 @@
 	dvb_dmx_init(&av7110->demux);
 	av7110->demux.dmx.get_stc = dvb_get_stc;
 
-	av7110->dmxdev.filternum = 32;
+	av7110->dmxdev.filternum = (av7110->full_ts) ? 256 : 32;
 	av7110->dmxdev.demux = &dvbdemux->dmx;
 	av7110->dmxdev.capabilities = 0;
 
@@ -1422,7 +1445,6 @@
 	return i2c_transfer(&av7110->i2c_adap, &msgs, 1);
 }
 
-#if 0
 u8 i2c_readreg(struct av7110 *av7110, u8 id, u8 reg)
 {
 	u8 mm1[] = {0x00};
@@ -1439,7 +1461,6 @@
 
 	return mm2[0];
 }
-#endif
 
 /****************************************************************************
  * INITIALIZATION
@@ -2256,7 +2277,7 @@
 	if (!av7110->fe) {
 		/* FIXME: propagate the failure code from the lower layers */
 		ret = -ENOMEM;
-		printk("dvb-ttpci: A frontend driver was not found for device %04x/%04x subsystem %04x/%04x\n",
+		printk("dvb-ttpci: A frontend driver was not found for device [%04x:%04x] subsystem [%04x:%04x]\n",
 		       av7110->dev->pci->vendor,
 		       av7110->dev->pci->device,
 		       av7110->dev->pci->subsystem_vendor,
@@ -2484,7 +2505,47 @@
 			       av7110->dvb_adapter.proposed_mac);
 	ret = -ENOMEM;
 
-	if (budgetpatch) {
+	/* full-ts mod? */
+	if (full_ts)
+		av7110->full_ts = true;
+
+	/* check for full-ts flag in eeprom */
+	if (i2c_readreg(av7110, 0xaa, 0) == 0x4f && i2c_readreg(av7110, 0xaa, 1) == 0x45) {
+		u8 flags = i2c_readreg(av7110, 0xaa, 2);
+		if (flags != 0xff && (flags & 0x01))
+			av7110->full_ts = true;
+	}
+
+	if (av7110->full_ts) {
+		printk(KERN_INFO "dvb-ttpci: full-ts mode enabled for saa7146 port B\n");
+		spin_lock_init(&av7110->feedlock1);
+		av7110->grabbing = saa7146_vmalloc_build_pgtable(pdev, length,
+								 &av7110->pt);
+		if (!av7110->grabbing)
+			goto err_i2c_del_3;
+
+		saa7146_write(dev, DD1_STREAM_B, 0x00000000);
+		saa7146_write(dev, MC2, (MASK_10 | MASK_26));
+
+		saa7146_write(dev, DD1_INIT, 0x00000600);
+		saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26));
+
+		saa7146_write(dev, BRS_CTRL, 0x60000000);
+		saa7146_write(dev, MC2, MASK_08 | MASK_24);
+
+		/* dma3 */
+		saa7146_write(dev, PCI_BT_V1, 0x001c0000 | (saa7146_read(dev, PCI_BT_V1) & ~0x001f0000));
+		saa7146_write(dev, BASE_ODD3, 0);
+		saa7146_write(dev, BASE_EVEN3, 0);
+		saa7146_write(dev, PROT_ADDR3, TS_WIDTH * TS_HEIGHT);
+		saa7146_write(dev, PITCH3, TS_WIDTH);
+		saa7146_write(dev, BASE_PAGE3, av7110->pt.dma | ME1 | 0x90);
+		saa7146_write(dev, NUM_LINE_BYTE3, (TS_HEIGHT << 16) | TS_WIDTH);
+		saa7146_write(dev, MC2, MASK_04 | MASK_20);
+
+		tasklet_init(&av7110->vpe_tasklet, vpeirq, (unsigned long) av7110);
+
+	} else if (budgetpatch) {
 		spin_lock_init(&av7110->feedlock1);
 		av7110->grabbing = saa7146_vmalloc_build_pgtable(pdev, length,
 								 &av7110->pt);
@@ -2710,11 +2771,13 @@
 #if defined(CONFIG_INPUT_EVDEV) || defined(CONFIG_INPUT_EVDEV_MODULE)
 	av7110_ir_exit(av7110);
 #endif
-	if (budgetpatch) {
-		/* Disable RPS1 */
-		saa7146_write(saa, MC1, MASK_29);
-		/* VSYNC LOW (inactive) */
-		saa7146_setgpio(saa, 3, SAA7146_GPIO_OUTLO);
+	if (budgetpatch || av7110->full_ts) {
+		if (budgetpatch) {
+			/* Disable RPS1 */
+			saa7146_write(saa, MC1, MASK_29);
+			/* VSYNC LOW (inactive) */
+			saa7146_setgpio(saa, 3, SAA7146_GPIO_OUTLO);
+		}
 		saa7146_write(saa, MC1, MASK_20);	/* DMA3 off */
 		SAA7146_IER_DISABLE(saa, MASK_10);
 		SAA7146_ISR_CLEAR(saa, MASK_10);
@@ -2794,7 +2857,7 @@
 		tasklet_schedule(&av7110->gpio_tasklet);
 	}
 
-	if ((*isr & MASK_10) && budgetpatch)
+	if (*isr & MASK_10)
 		tasklet_schedule(&av7110->vpe_tasklet);
 }
 
diff --git a/drivers/media/dvb/ttpci/av7110.h b/drivers/media/dvb/ttpci/av7110.h
index 55f23dd..d85b851 100644
--- a/drivers/media/dvb/ttpci/av7110.h
+++ b/drivers/media/dvb/ttpci/av7110.h
@@ -192,6 +192,7 @@
 	unsigned char           *grabbing;
 	struct saa7146_pgtable  pt;
 	struct tasklet_struct   vpe_tasklet;
+	bool			full_ts;
 
 	int			fe_synced;
 	struct mutex		pid_mutex;
diff --git a/drivers/media/dvb/ttpci/av7110_av.c b/drivers/media/dvb/ttpci/av7110_av.c
index 184647ad..bdc62ac 100644
--- a/drivers/media/dvb/ttpci/av7110_av.c
+++ b/drivers/media/dvb/ttpci/av7110_av.c
@@ -788,6 +788,9 @@
 
 	dprintk(2, "av7110:%p, \n", av7110);
 
+	if (av7110->full_ts && demux->dmx.frontend->source != DMX_MEMORY_FE)
+		return 0;
+
 	switch (feed->pes_type) {
 	case 0:
 		if (av7110->audiostate.stream_source == AUDIO_SOURCE_MEMORY)
diff --git a/drivers/media/dvb/ttpci/budget-av.c b/drivers/media/dvb/ttpci/budget-av.c
index b7d1f2f..1032ea7 100644
--- a/drivers/media/dvb/ttpci/budget-av.c
+++ b/drivers/media/dvb/ttpci/budget-av.c
@@ -57,6 +57,8 @@
 #define SLOTSTATUS_READY        8
 #define SLOTSTATUS_OCCUPIED     (SLOTSTATUS_PRESENT|SLOTSTATUS_RESET|SLOTSTATUS_READY)
 
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
 struct budget_av {
 	struct budget budget;
 	struct video_device *vd;
@@ -1049,7 +1051,7 @@
 
 	if (fe == NULL) {
 		printk(KERN_ERR "budget-av: A frontend driver was not found "
-				"for device %04x/%04x subsystem %04x/%04x\n",
+				"for device [%04x:%04x] subsystem [%04x:%04x]\n",
 		       saa->pci->vendor,
 		       saa->pci->device,
 		       saa->pci->subsystem_vendor,
@@ -1127,7 +1129,9 @@
 
 	dev->ext_priv = budget_av;
 
-	if ((err = ttpci_budget_init(&budget_av->budget, dev, info, THIS_MODULE))) {
+	err = ttpci_budget_init(&budget_av->budget, dev, info, THIS_MODULE,
+				adapter_nr);
+	if (err) {
 		kfree(budget_av);
 		return err;
 	}
diff --git a/drivers/media/dvb/ttpci/budget-ci.c b/drivers/media/dvb/ttpci/budget-ci.c
index 060e7c7..0a5aad4 100644
--- a/drivers/media/dvb/ttpci/budget-ci.c
+++ b/drivers/media/dvb/ttpci/budget-ci.c
@@ -92,6 +92,8 @@
 module_param(ir_debug, int, 0644);
 MODULE_PARM_DESC(ir_debug, "enable debugging information for IR decoding");
 
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
 struct budget_ci_ir {
 	struct input_dev *dev;
 	struct tasklet_struct msp430_irq_tasklet;
@@ -1153,7 +1155,7 @@
 	}
 
 	if (budget_ci->budget.dvb_frontend == NULL) {
-		printk("budget-ci: A frontend driver was not found for device %04x/%04x subsystem %04x/%04x\n",
+		printk("budget-ci: A frontend driver was not found for device [%04x:%04x] subsystem [%04x:%04x]\n",
 		       budget_ci->budget.dev->pci->vendor,
 		       budget_ci->budget.dev->pci->device,
 		       budget_ci->budget.dev->pci->subsystem_vendor,
@@ -1183,7 +1185,8 @@
 
 	dev->ext_priv = budget_ci;
 
-	err = ttpci_budget_init(&budget_ci->budget, dev, info, THIS_MODULE);
+	err = ttpci_budget_init(&budget_ci->budget, dev, info, THIS_MODULE,
+				adapter_nr);
 	if (err)
 		goto out2;
 
diff --git a/drivers/media/dvb/ttpci/budget-core.c b/drivers/media/dvb/ttpci/budget-core.c
index 6f4ddb6..ba18e56 100644
--- a/drivers/media/dvb/ttpci/budget-core.c
+++ b/drivers/media/dvb/ttpci/budget-core.c
@@ -57,8 +57,6 @@
 MODULE_PARM_DESC(debug, "Turn on/off budget debugging (default:off).");
 MODULE_PARM_DESC(bufsize, "DMA buffer size in KB, default: 188, min: 188, max: 1410 (Activy: 564)");
 
-DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
-
 /****************************************************************************
  * TT budget / WinTV Nova
  ****************************************************************************/
@@ -411,7 +409,7 @@
 
 int ttpci_budget_init(struct budget *budget, struct saa7146_dev *dev,
 		      struct saa7146_pci_extension_data *info,
-		      struct module *owner)
+		      struct module *owner, short *adapter_nums)
 {
 	int ret = 0;
 	struct budget_info *bi = info->ext_priv;
@@ -474,7 +472,7 @@
 	printk("%s: dma buffer size %u\n", budget->dev->name, budget->buffer_size);
 
 	ret = dvb_register_adapter(&budget->dvb_adapter, budget->card->name,
-				   owner, &budget->dev->pci->dev, adapter_nr);
+				   owner, &budget->dev->pci->dev, adapter_nums);
 	if (ret < 0)
 		return ret;
 
diff --git a/drivers/media/dvb/ttpci/budget-patch.c b/drivers/media/dvb/ttpci/budget-patch.c
index aa5ed4e..60136688 100644
--- a/drivers/media/dvb/ttpci/budget-patch.c
+++ b/drivers/media/dvb/ttpci/budget-patch.c
@@ -39,6 +39,8 @@
 
 #include "bsru6.h"
 
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
 #define budget_patch budget
 
 static struct saa7146_extension budget_extension;
@@ -360,7 +362,7 @@
 	}
 
 	if (budget->dvb_frontend == NULL) {
-		printk("dvb-ttpci: A frontend driver was not found for device %04x/%04x subsystem %04x/%04x\n",
+		printk("dvb-ttpci: A frontend driver was not found for device [%04x:%04x] subsystem [%04x:%04x]\n",
 		       budget->dev->pci->vendor,
 		       budget->dev->pci->device,
 		       budget->dev->pci->subsystem_vendor,
@@ -592,8 +594,9 @@
 
 	dprintk(2, "budget: %p\n", budget);
 
-	if ((err = ttpci_budget_init (budget, dev, info, THIS_MODULE))) {
-		kfree (budget);
+	err = ttpci_budget_init(budget, dev, info, THIS_MODULE, adapter_nr);
+	if (err) {
+		kfree(budget);
 		return err;
 	}
 
diff --git a/drivers/media/dvb/ttpci/budget.c b/drivers/media/dvb/ttpci/budget.c
index f006899..1638e1d 100644
--- a/drivers/media/dvb/ttpci/budget.c
+++ b/drivers/media/dvb/ttpci/budget.c
@@ -46,11 +46,14 @@
 #include "lnbp21.h"
 #include "bsru6.h"
 #include "bsbe1.h"
+#include "tdhd1.h"
 
 static int diseqc_method;
 module_param(diseqc_method, int, 0444);
 MODULE_PARM_DESC(diseqc_method, "Select DiSEqC method for subsystem id 13c2:1003, 0: default, 1: more reliable (for newer revisions only)");
 
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
 static void Set22K (struct budget *budget, int state)
 {
 	struct saa7146_dev *dev=budget->dev;
@@ -390,6 +393,13 @@
 	.set_symbol_rate = alps_bsbe1_set_symbol_rate,
 };
 
+static int alps_tdhd1_204_request_firmware(struct dvb_frontend *fe, const struct firmware **fw, char *name)
+{
+	struct budget *budget = (struct budget *)fe->dvb->priv;
+
+	return request_firmware(fw, name, &budget->dev->pci->dev);
+}
+
 
 static int i2c_readreg(struct i2c_adapter *i2c, u8 adr, u8 reg)
 {
@@ -511,6 +521,14 @@
 		}
 		break;
 
+	case 0x5f60: /* Fujitsu Siemens Activy Budget-T PCI rev AL (tda10046/ALPS TDHD1-204A) */
+		budget->dvb_frontend = dvb_attach(tda10046_attach, &alps_tdhd1_204a_config, &budget->i2c_adap);
+		if (budget->dvb_frontend) {
+			budget->dvb_frontend->ops.tuner_ops.set_params = alps_tdhd1_204a_tuner_set_params;
+			budget->dvb_frontend->tuner_priv = &budget->i2c_adap;
+		}
+		break;
+
 	case 0x5f61: /* Fujitsu Siemens Activy Budget-T PCI rev GR (L64781/Grundig 29504-401(tsa5060)) */
 		budget->dvb_frontend = dvb_attach(l64781_attach, &grundig_29504_401_config_activy, &budget->i2c_adap);
 		if (budget->dvb_frontend) {
@@ -550,7 +568,7 @@
 	}
 
 	if (budget->dvb_frontend == NULL) {
-		printk("budget: A frontend driver was not found for device %04x/%04x subsystem %04x/%04x\n",
+		printk("budget: A frontend driver was not found for device [%04x:%04x] subsystem [%04x:%04x]\n",
 		       budget->dev->pci->vendor,
 		       budget->dev->pci->device,
 		       budget->dev->pci->subsystem_vendor,
@@ -582,7 +600,8 @@
 
 	dev->ext_priv = budget;
 
-	if ((err = ttpci_budget_init (budget, dev, info, THIS_MODULE))) {
+	err = ttpci_budget_init(budget, dev, info, THIS_MODULE, adapter_nr);
+	if (err) {
 		printk("==> failed\n");
 		kfree (budget);
 		return err;
@@ -624,6 +643,7 @@
 MAKE_BUDGET_INFO(fsacs0, "Fujitsu Siemens Activy Budget-S PCI (rev GR/grundig frontend)", BUDGET_FS_ACTIVY);
 MAKE_BUDGET_INFO(fsacs1, "Fujitsu Siemens Activy Budget-S PCI (rev AL/alps frontend)", BUDGET_FS_ACTIVY);
 MAKE_BUDGET_INFO(fsact,	 "Fujitsu Siemens Activy Budget-T PCI (rev GR/Grundig frontend)", BUDGET_FS_ACTIVY);
+MAKE_BUDGET_INFO(fsact1, "Fujitsu Siemens Activy Budget-T PCI (rev AL/ALPS TDHD1-204A)", BUDGET_FS_ACTIVY);
 
 static struct pci_device_id pci_tbl[] = {
 	MAKE_EXTENSION_PCI(ttbs,  0x13c2, 0x1003),
@@ -634,6 +654,7 @@
 	MAKE_EXTENSION_PCI(ttbs1401, 0x13c2, 0x1018),
 	MAKE_EXTENSION_PCI(fsacs1,0x1131, 0x4f60),
 	MAKE_EXTENSION_PCI(fsacs0,0x1131, 0x4f61),
+	MAKE_EXTENSION_PCI(fsact1, 0x1131, 0x5f60),
 	MAKE_EXTENSION_PCI(fsact, 0x1131, 0x5f61),
 	{
 		.vendor    = 0,
diff --git a/drivers/media/dvb/ttpci/budget.h b/drivers/media/dvb/ttpci/budget.h
index dd450b7..86435bf 100644
--- a/drivers/media/dvb/ttpci/budget.h
+++ b/drivers/media/dvb/ttpci/budget.h
@@ -109,7 +109,7 @@
 
 extern int ttpci_budget_init(struct budget *budget, struct saa7146_dev *dev,
 			     struct saa7146_pci_extension_data *info,
-			     struct module *owner);
+			     struct module *owner, short *adapter_nums);
 extern void ttpci_budget_init_hooks(struct budget *budget);
 extern int ttpci_budget_deinit(struct budget *budget);
 extern void ttpci_budget_irq10_handler(struct saa7146_dev *dev, u32 * isr);
diff --git a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c b/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c
index e6c9cd2..66ab0c6 100644
--- a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c
+++ b/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c
@@ -1614,7 +1614,7 @@
 	}
 
 	if (ttusb->fe == NULL) {
-		printk("dvb-ttusb-budget: A frontend driver was not found for device %04x/%04x\n",
+		printk("dvb-ttusb-budget: A frontend driver was not found for device [%04x:%04x]\n",
 		       le16_to_cpu(ttusb->dev->descriptor.idVendor),
 		       le16_to_cpu(ttusb->dev->descriptor.idProduct));
 	} else {
diff --git a/drivers/media/dvb/ttusb-dec/ttusb_dec.c b/drivers/media/dvb/ttusb-dec/ttusb_dec.c
index de5829b..ab33fec 100644
--- a/drivers/media/dvb/ttusb-dec/ttusb_dec.c
+++ b/drivers/media/dvb/ttusb-dec/ttusb_dec.c
@@ -1665,7 +1665,7 @@
 	}
 
 	if (dec->fe == NULL) {
-		printk("dvb-ttusb-dec: A frontend driver was not found for device %04x/%04x\n",
+		printk("dvb-ttusb-dec: A frontend driver was not found for device [%04x:%04x]\n",
 		       le16_to_cpu(dec->udev->descriptor.idVendor),
 		       le16_to_cpu(dec->udev->descriptor.idProduct));
 	} else {
diff --git a/drivers/media/dvb/ttusb-dec/ttusbdecfe.c b/drivers/media/dvb/ttusb-dec/ttusbdecfe.c
index 443af24..21260aa 100644
--- a/drivers/media/dvb/ttusb-dec/ttusbdecfe.c
+++ b/drivers/media/dvb/ttusb-dec/ttusbdecfe.c
@@ -38,7 +38,17 @@
 };
 
 
-static int ttusbdecfe_read_status(struct dvb_frontend* fe, fe_status_t* status)
+static int ttusbdecfe_dvbs_read_status(struct dvb_frontend *fe,
+	fe_status_t *status)
+{
+	*status = FE_HAS_SIGNAL | FE_HAS_VITERBI |
+		FE_HAS_SYNC | FE_HAS_CARRIER | FE_HAS_LOCK;
+	return 0;
+}
+
+
+static int ttusbdecfe_dvbt_read_status(struct dvb_frontend *fe,
+	fe_status_t *status)
 {
 	struct ttusbdecfe_state* state = fe->demodulator_priv;
 	u8 b[] = { 0x00, 0x00, 0x00, 0x00,
@@ -251,7 +261,7 @@
 
 	.get_tune_settings = ttusbdecfe_dvbt_get_tune_settings,
 
-	.read_status = ttusbdecfe_read_status,
+	.read_status = ttusbdecfe_dvbt_read_status,
 };
 
 static struct dvb_frontend_ops ttusbdecfe_dvbs_ops = {
@@ -273,7 +283,7 @@
 
 	.set_frontend = ttusbdecfe_dvbs_set_frontend,
 
-	.read_status = ttusbdecfe_read_status,
+	.read_status = ttusbdecfe_dvbs_read_status,
 
 	.diseqc_send_master_cmd = ttusbdecfe_dvbs_diseqc_send_master_cmd,
 	.set_voltage = ttusbdecfe_dvbs_set_voltage,
diff --git a/drivers/media/radio/Kconfig b/drivers/media/radio/Kconfig
index 1b41b3f..e51d707 100644
--- a/drivers/media/radio/Kconfig
+++ b/drivers/media/radio/Kconfig
@@ -361,4 +361,16 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called radio-silabs.
 
+config USB_MR800
+	tristate "AverMedia MR 800 USB FM radio support"
+	depends on USB && VIDEO_V4L2
+	---help---
+	  Say Y here if you want to connect this type of radio to your
+	  computer's USB port. Note that the audio is not digital, and
+	  you must connect the line out connector to a sound card or a
+	  set of speakers.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called radio-mr800.
+
 endif # RADIO_ADAPTERS
diff --git a/drivers/media/radio/Makefile b/drivers/media/radio/Makefile
index 7ca71ab..240ec63c 100644
--- a/drivers/media/radio/Makefile
+++ b/drivers/media/radio/Makefile
@@ -18,5 +18,6 @@
 obj-$(CONFIG_RADIO_MAESTRO) += radio-maestro.o
 obj-$(CONFIG_USB_DSBR) += dsbr100.o
 obj-$(CONFIG_USB_SI470X) += radio-si470x.o
+obj-$(CONFIG_USB_MR800) += radio-mr800.o
 
 EXTRA_CFLAGS += -Isound
diff --git a/drivers/media/radio/dsbr100.c b/drivers/media/radio/dsbr100.c
index 70c65a7..66783ff 100644
--- a/drivers/media/radio/dsbr100.c
+++ b/drivers/media/radio/dsbr100.c
@@ -274,7 +274,7 @@
 static int vidioc_g_tuner(struct file *file, void *priv,
 				struct v4l2_tuner *v)
 {
-	struct dsbr100_device *radio = video_get_drvdata(video_devdata(file));
+	struct dsbr100_device *radio = video_drvdata(file);
 
 	if (v->index > 0)
 		return -EINVAL;
@@ -306,7 +306,7 @@
 static int vidioc_s_frequency(struct file *file, void *priv,
 				struct v4l2_frequency *f)
 {
-	struct dsbr100_device *radio = video_get_drvdata(video_devdata(file));
+	struct dsbr100_device *radio = video_drvdata(file);
 
 	radio->curfreq = f->frequency;
 	if (dsbr100_setfreq(radio, radio->curfreq)==-1)
@@ -317,7 +317,7 @@
 static int vidioc_g_frequency(struct file *file, void *priv,
 				struct v4l2_frequency *f)
 {
-	struct dsbr100_device *radio = video_get_drvdata(video_devdata(file));
+	struct dsbr100_device *radio = video_drvdata(file);
 
 	f->type = V4L2_TUNER_RADIO;
 	f->frequency = radio->curfreq;
@@ -342,7 +342,7 @@
 static int vidioc_g_ctrl(struct file *file, void *priv,
 				struct v4l2_control *ctrl)
 {
-	struct dsbr100_device *radio = video_get_drvdata(video_devdata(file));
+	struct dsbr100_device *radio = video_drvdata(file);
 
 	switch (ctrl->id) {
 	case V4L2_CID_AUDIO_MUTE:
@@ -355,16 +355,20 @@
 static int vidioc_s_ctrl(struct file *file, void *priv,
 				struct v4l2_control *ctrl)
 {
-	struct dsbr100_device *radio = video_get_drvdata(video_devdata(file));
+	struct dsbr100_device *radio = video_drvdata(file);
 
 	switch (ctrl->id) {
 	case V4L2_CID_AUDIO_MUTE:
 		if (ctrl->value) {
-			if (dsbr100_stop(radio)==-1)
+			if (dsbr100_stop(radio) == -1) {
 				warn("Radio did not respond properly");
+				return -EBUSY;
+			}
 		} else {
-			if (dsbr100_start(radio)==-1)
+			if (dsbr100_start(radio) == -1) {
 				warn("Radio did not respond properly");
+				return -EBUSY;
+			}
 		}
 		return 0;
 	}
@@ -405,23 +409,26 @@
 
 static int usb_dsbr100_open(struct inode *inode, struct file *file)
 {
-	struct dsbr100_device *radio=video_get_drvdata(video_devdata(file));
+	struct dsbr100_device *radio = video_drvdata(file);
 
+	lock_kernel();
 	radio->users = 1;
 	radio->muted = 1;
 
 	if (dsbr100_start(radio)<0) {
 		warn("Radio did not start up properly");
 		radio->users = 0;
+		unlock_kernel();
 		return -EIO;
 	}
 	dsbr100_setfreq(radio, radio->curfreq);
+	unlock_kernel();
 	return 0;
 }
 
 static int usb_dsbr100_close(struct inode *inode, struct file *file)
 {
-	struct dsbr100_device *radio=video_get_drvdata(video_devdata(file));
+	struct dsbr100_device *radio = video_drvdata(file);
 
 	if (!radio)
 		return -ENODEV;
@@ -507,7 +514,8 @@
 static int __init dsbr100_init(void)
 {
 	int retval = usb_register(&usb_dsbr100_driver);
-	info(DRIVER_VERSION ":" DRIVER_DESC);
+	printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
+	       DRIVER_DESC "\n");
 	return retval;
 }
 
diff --git a/drivers/media/radio/radio-aimslab.c b/drivers/media/radio/radio-aimslab.c
index 1f064f4..9305e95 100644
--- a/drivers/media/radio/radio-aimslab.c
+++ b/drivers/media/radio/radio-aimslab.c
@@ -51,6 +51,7 @@
 
 struct rt_device
 {
+	unsigned long in_use;
 	int port;
 	int curvol;
 	unsigned long curfreq;
@@ -245,8 +246,7 @@
 static int vidioc_g_tuner(struct file *file, void *priv,
 					struct v4l2_tuner *v)
 {
-	struct video_device *dev = video_devdata(file);
-	struct rt_device *rt = dev->priv;
+	struct rt_device *rt = video_drvdata(file);
 
 	if (v->index > 0)
 		return -EINVAL;
@@ -273,8 +273,7 @@
 static int vidioc_s_frequency(struct file *file, void *priv,
 					struct v4l2_frequency *f)
 {
-	struct video_device *dev = video_devdata(file);
-	struct rt_device *rt = dev->priv;
+	struct rt_device *rt = video_drvdata(file);
 
 	rt->curfreq = f->frequency;
 	rt_setfreq(rt, rt->curfreq);
@@ -284,8 +283,7 @@
 static int vidioc_g_frequency(struct file *file, void *priv,
 					struct v4l2_frequency *f)
 {
-	struct video_device *dev = video_devdata(file);
-	struct rt_device *rt = dev->priv;
+	struct rt_device *rt = video_drvdata(file);
 
 	f->type = V4L2_TUNER_RADIO;
 	f->frequency = rt->curfreq;
@@ -310,8 +308,7 @@
 static int vidioc_g_ctrl(struct file *file, void *priv,
 					struct v4l2_control *ctrl)
 {
-	struct video_device *dev = video_devdata(file);
-	struct rt_device *rt = dev->priv;
+	struct rt_device *rt = video_drvdata(file);
 
 	switch (ctrl->id) {
 	case V4L2_CID_AUDIO_MUTE:
@@ -327,8 +324,7 @@
 static int vidioc_s_ctrl(struct file *file, void *priv,
 					struct v4l2_control *ctrl)
 {
-	struct video_device *dev = video_devdata(file);
-	struct rt_device *rt = dev->priv;
+	struct rt_device *rt = video_drvdata(file);
 
 	switch (ctrl->id) {
 	case V4L2_CID_AUDIO_MUTE:
@@ -378,10 +374,21 @@
 
 static struct rt_device rtrack_unit;
 
+static int rtrack_exclusive_open(struct inode *inode, struct file *file)
+{
+	return test_and_set_bit(0, &rtrack_unit.in_use) ? -EBUSY : 0;
+}
+
+static int rtrack_exclusive_release(struct inode *inode, struct file *file)
+{
+	clear_bit(0, &rtrack_unit.in_use);
+	return 0;
+}
+
 static const struct file_operations rtrack_fops = {
 	.owner		= THIS_MODULE,
-	.open           = video_exclusive_open,
-	.release        = video_exclusive_release,
+	.open           = rtrack_exclusive_open,
+	.release        = rtrack_exclusive_release,
 	.ioctl		= video_ioctl2,
 #ifdef CONFIG_COMPAT
 	.compat_ioctl	= v4l_compat_ioctl32,
@@ -408,6 +415,7 @@
 	.name		= "RadioTrack radio",
 	.fops           = &rtrack_fops,
 	.ioctl_ops 	= &rtrack_ioctl_ops,
+	.release	= video_device_release_empty,
 };
 
 static int __init rtrack_init(void)
@@ -424,7 +432,7 @@
 		return -EBUSY;
 	}
 
-	rtrack_radio.priv=&rtrack_unit;
+	video_set_drvdata(&rtrack_radio, &rtrack_unit);
 
 	if (video_register_device(&rtrack_radio, VFL_TYPE_RADIO, radio_nr) < 0) {
 		release_region(io, 2);
diff --git a/drivers/media/radio/radio-aztech.c b/drivers/media/radio/radio-aztech.c
index 628c689..d784895 100644
--- a/drivers/media/radio/radio-aztech.c
+++ b/drivers/media/radio/radio-aztech.c
@@ -70,6 +70,7 @@
 
 struct az_device
 {
+	unsigned long in_use;
 	int curvol;
 	unsigned long curfreq;
 	int stereo;
@@ -195,8 +196,7 @@
 static int vidioc_g_tuner (struct file *file, void *priv,
 				struct v4l2_tuner *v)
 {
-	struct video_device *dev = video_devdata(file);
-	struct az_device *az = dev->priv;
+	struct az_device *az = video_drvdata(file);
 
 	if (v->index > 0)
 		return -EINVAL;
@@ -264,8 +264,7 @@
 static int vidioc_s_frequency (struct file *file, void *priv,
 				struct v4l2_frequency *f)
 {
-	struct video_device *dev = video_devdata(file);
-	struct az_device *az = dev->priv;
+	struct az_device *az = video_drvdata(file);
 
 	az->curfreq = f->frequency;
 	az_setfreq(az, az->curfreq);
@@ -275,8 +274,7 @@
 static int vidioc_g_frequency (struct file *file, void *priv,
 				struct v4l2_frequency *f)
 {
-	struct video_device *dev = video_devdata(file);
-	struct az_device *az = dev->priv;
+	struct az_device *az = video_drvdata(file);
 
 	f->type = V4L2_TUNER_RADIO;
 	f->frequency = az->curfreq;
@@ -302,8 +300,7 @@
 static int vidioc_g_ctrl (struct file *file, void *priv,
 			    struct v4l2_control *ctrl)
 {
-	struct video_device *dev = video_devdata(file);
-	struct az_device *az = dev->priv;
+	struct az_device *az = video_drvdata(file);
 
 	switch (ctrl->id) {
 		case V4L2_CID_AUDIO_MUTE:
@@ -322,8 +319,7 @@
 static int vidioc_s_ctrl (struct file *file, void *priv,
 			    struct v4l2_control *ctrl)
 {
-	struct video_device *dev = video_devdata(file);
-	struct az_device *az = dev->priv;
+	struct az_device *az = video_drvdata(file);
 
 	switch (ctrl->id) {
 		case V4L2_CID_AUDIO_MUTE:
@@ -342,10 +338,21 @@
 
 static struct az_device aztech_unit;
 
+static int aztech_exclusive_open(struct inode *inode, struct file *file)
+{
+	return test_and_set_bit(0, &aztech_unit.in_use) ? -EBUSY : 0;
+}
+
+static int aztech_exclusive_release(struct inode *inode, struct file *file)
+{
+	clear_bit(0, &aztech_unit.in_use);
+	return 0;
+}
+
 static const struct file_operations aztech_fops = {
 	.owner		= THIS_MODULE,
-	.open           = video_exclusive_open,
-	.release        = video_exclusive_release,
+	.open           = aztech_exclusive_open,
+	.release        = aztech_exclusive_release,
 	.ioctl		= video_ioctl2,
 #ifdef CONFIG_COMPAT
 	.compat_ioctl	= v4l_compat_ioctl32,
@@ -369,9 +376,10 @@
 };
 
 static struct video_device aztech_radio = {
-	.name		    = "Aztech radio",
-	.fops               = &aztech_fops,
-	.ioctl_ops 	    = &aztech_ioctl_ops,
+	.name		= "Aztech radio",
+	.fops           = &aztech_fops,
+	.ioctl_ops 	= &aztech_ioctl_ops,
+	.release	= video_device_release_empty,
 };
 
 module_param_named(debug,aztech_radio.debug, int, 0644);
@@ -392,7 +400,7 @@
 	}
 
 	mutex_init(&lock);
-	aztech_radio.priv=&aztech_unit;
+	video_set_drvdata(&aztech_radio, &aztech_unit);
 
 	if (video_register_device(&aztech_radio, VFL_TYPE_RADIO, radio_nr) < 0) {
 		release_region(io,2);
diff --git a/drivers/media/radio/radio-cadet.c b/drivers/media/radio/radio-cadet.c
index 04c3698..0490a1f 100644
--- a/drivers/media/radio/radio-cadet.c
+++ b/drivers/media/radio/radio-cadet.c
@@ -589,6 +589,7 @@
 	.name		= "Cadet radio",
 	.fops           = &cadet_fops,
 	.ioctl_ops 	= &cadet_ioctl_ops,
+	.release	= video_device_release_empty,
 };
 
 #ifdef CONFIG_PNP
diff --git a/drivers/media/radio/radio-gemtek-pci.c b/drivers/media/radio/radio-gemtek-pci.c
index 5cd7f03..e15bee6 100644
--- a/drivers/media/radio/radio-gemtek-pci.c
+++ b/drivers/media/radio/radio-gemtek-pci.c
@@ -100,9 +100,8 @@
 	u8  mute;
 };
 
-static const char rcsid[] = "$Id: radio-gemtek-pci.c,v 1.1 2001/07/23 08:08:16 ted Exp ted $";
-
 static int nr_radio = -1;
+static unsigned long in_use;
 
 static inline u8 gemtek_pci_out( u16 value, u32 port )
 {
@@ -205,8 +204,7 @@
 static int vidioc_g_tuner(struct file *file, void *priv,
 					struct v4l2_tuner *v)
 {
-	struct video_device *dev = video_devdata(file);
-	struct gemtek_pci_card *card = dev->priv;
+	struct gemtek_pci_card *card = video_drvdata(file);
 
 	if (v->index > 0)
 		return -EINVAL;
@@ -233,8 +231,7 @@
 static int vidioc_s_frequency(struct file *file, void *priv,
 					struct v4l2_frequency *f)
 {
-	struct video_device *dev = video_devdata(file);
-	struct gemtek_pci_card *card = dev->priv;
+	struct gemtek_pci_card *card = video_drvdata(file);
 
 	if ( (f->frequency < GEMTEK_PCI_RANGE_LOW) ||
 			(f->frequency > GEMTEK_PCI_RANGE_HIGH) )
@@ -248,8 +245,7 @@
 static int vidioc_g_frequency(struct file *file, void *priv,
 					struct v4l2_frequency *f)
 {
-	struct video_device *dev = video_devdata(file);
-	struct gemtek_pci_card *card = dev->priv;
+	struct gemtek_pci_card *card = video_drvdata(file);
 
 	f->type = V4L2_TUNER_RADIO;
 	f->frequency = card->current_frequency;
@@ -273,8 +269,7 @@
 static int vidioc_g_ctrl(struct file *file, void *priv,
 					struct v4l2_control *ctrl)
 {
-	struct video_device *dev = video_devdata(file);
-	struct gemtek_pci_card *card = dev->priv;
+	struct gemtek_pci_card *card = video_drvdata(file);
 
 	switch (ctrl->id) {
 	case V4L2_CID_AUDIO_MUTE:
@@ -293,8 +288,7 @@
 static int vidioc_s_ctrl(struct file *file, void *priv,
 					struct v4l2_control *ctrl)
 {
-	struct video_device *dev = video_devdata(file);
-	struct gemtek_pci_card *card = dev->priv;
+	struct gemtek_pci_card *card = video_drvdata(file);
 
 	switch (ctrl->id) {
 	case V4L2_CID_AUDIO_MUTE:
@@ -364,10 +358,21 @@
 
 static int mx = 1;
 
+static int gemtek_pci_exclusive_open(struct inode *inode, struct file *file)
+{
+	return test_and_set_bit(0, &in_use) ? -EBUSY : 0;
+}
+
+static int gemtek_pci_exclusive_release(struct inode *inode, struct file *file)
+{
+	clear_bit(0, &in_use);
+	return 0;
+}
+
 static const struct file_operations gemtek_pci_fops = {
 	.owner		= THIS_MODULE,
-	.open           = video_exclusive_open,
-	.release        = video_exclusive_release,
+	.open           = gemtek_pci_exclusive_open,
+	.release        = gemtek_pci_exclusive_release,
 	.ioctl		= video_ioctl2,
 #ifdef CONFIG_COMPAT
 	.compat_ioctl	= v4l_compat_ioctl32,
@@ -391,9 +396,10 @@
 };
 
 static struct video_device vdev_template = {
-	.name          = "Gemtek PCI Radio",
-	.fops          = &gemtek_pci_fops,
-	.ioctl_ops     = &gemtek_pci_ioctl_ops,
+	.name          	= "Gemtek PCI Radio",
+	.fops          	= &gemtek_pci_fops,
+	.ioctl_ops 	= &gemtek_pci_ioctl_ops,
+	.release	= video_device_release_empty,
 };
 
 static int __devinit gemtek_pci_probe( struct pci_dev *pci_dev, const struct pci_device_id *pci_id )
@@ -431,7 +437,7 @@
 	}
 
 	card->videodev = devradio;
-	devradio->priv = card;
+	video_set_drvdata(devradio, card);
 	gemtek_pci_mute( card );
 
 	printk( KERN_INFO "Gemtek PCI Radio (rev. %d) found at 0x%04x-0x%04x.\n",
diff --git a/drivers/media/radio/radio-gemtek.c b/drivers/media/radio/radio-gemtek.c
index 0a0f956..d131a5d 100644
--- a/drivers/media/radio/radio-gemtek.c
+++ b/drivers/media/radio/radio-gemtek.c
@@ -57,6 +57,7 @@
 static int keepmuted	= 1;
 static int initmute	= 1;
 static int radio_nr	= -1;
+static unsigned long in_use;
 
 module_param(io, int, 0444);
 MODULE_PARM_DESC(io, "Force I/O port for the GemTek Radio card if automatic "
@@ -393,10 +394,21 @@
 	}
 };
 
+static int gemtek_exclusive_open(struct inode *inode, struct file *file)
+{
+	return test_and_set_bit(0, &in_use) ? -EBUSY : 0;
+}
+
+static int gemtek_exclusive_release(struct inode *inode, struct file *file)
+{
+	clear_bit(0, &in_use);
+	return 0;
+}
+
 static const struct file_operations gemtek_fops = {
 	.owner		= THIS_MODULE,
-	.open		= video_exclusive_open,
-	.release	= video_exclusive_release,
+	.open		= gemtek_exclusive_open,
+	.release	= gemtek_exclusive_release,
 	.ioctl		= video_ioctl2,
 #ifdef CONFIG_COMPAT
 	.compat_ioctl	= v4l_compat_ioctl32,
@@ -447,8 +459,7 @@
 static int vidioc_s_frequency(struct file *file, void *priv,
 			      struct v4l2_frequency *f)
 {
-	struct video_device *dev = video_devdata(file);
-	struct gemtek_device *rt = dev->priv;
+	struct gemtek_device *rt = video_drvdata(file);
 
 	gemtek_setfreq(rt, f->frequency);
 
@@ -458,8 +469,7 @@
 static int vidioc_g_frequency(struct file *file, void *priv,
 			      struct v4l2_frequency *f)
 {
-	struct video_device *dev = video_devdata(file);
-	struct gemtek_device *rt = dev->priv;
+	struct gemtek_device *rt = video_drvdata(file);
 
 	f->type = V4L2_TUNER_RADIO;
 	f->frequency = rt->lastfreq;
@@ -483,8 +493,7 @@
 static int vidioc_g_ctrl(struct file *file, void *priv,
 			 struct v4l2_control *ctrl)
 {
-	struct video_device *dev = video_devdata(file);
-	struct gemtek_device *rt = dev->priv;
+	struct gemtek_device *rt = video_drvdata(file);
 
 	switch (ctrl->id) {
 	case V4L2_CID_AUDIO_MUTE:
@@ -503,8 +512,7 @@
 static int vidioc_s_ctrl(struct file *file, void *priv,
 			 struct v4l2_control *ctrl)
 {
-	struct video_device *dev = video_devdata(file);
-	struct gemtek_device *rt = dev->priv;
+	struct gemtek_device *rt = video_drvdata(file);
 
 	switch (ctrl->id) {
 	case V4L2_CID_AUDIO_MUTE:
@@ -569,9 +577,10 @@
 };
 
 static struct video_device gemtek_radio = {
-	.name			= "GemTek Radio card",
-	.fops			= &gemtek_fops,
-	.ioctl_ops 		= &gemtek_ioctl_ops,
+	.name		= "GemTek Radio card",
+	.fops		= &gemtek_fops,
+	.ioctl_ops 	= &gemtek_ioctl_ops,
+	.release	= video_device_release_empty,
 };
 
 /*
@@ -610,7 +619,7 @@
 		return -EINVAL;
 	}
 
-	gemtek_radio.priv = &gemtek_unit;
+	video_set_drvdata(&gemtek_radio, &gemtek_unit);
 
 	if (video_register_device(&gemtek_radio, VFL_TYPE_RADIO, radio_nr) < 0) {
 		release_region(io, 1);
diff --git a/drivers/media/radio/radio-maestro.c b/drivers/media/radio/radio-maestro.c
index 9ef0a76..4bf4d00 100644
--- a/drivers/media/radio/radio-maestro.c
+++ b/drivers/media/radio/radio-maestro.c
@@ -75,7 +75,21 @@
 static int radio_nr = -1;
 module_param(radio_nr, int, 0);
 
+static unsigned long in_use;
+
 static int maestro_probe(struct pci_dev *pdev, const struct pci_device_id *ent);
+
+static int maestro_exclusive_open(struct inode *inode, struct file *file)
+{
+	return test_and_set_bit(0, &in_use) ? -EBUSY : 0;
+}
+
+static int maestro_exclusive_release(struct inode *inode, struct file *file)
+{
+	clear_bit(0, &in_use);
+	return 0;
+}
+
 static void maestro_remove(struct pci_dev *pdev);
 
 static struct pci_device_id maestro_r_pci_tbl[] = {
@@ -98,8 +112,8 @@
 
 static const struct file_operations maestro_fops = {
 	.owner		= THIS_MODULE,
-	.open           = video_exclusive_open,
-	.release        = video_exclusive_release,
+	.open           = maestro_exclusive_open,
+	.release        = maestro_exclusive_release,
 	.ioctl		= video_ioctl2,
 #ifdef CONFIG_COMPAT
 	.compat_ioctl	= v4l_compat_ioctl32,
@@ -196,8 +210,7 @@
 static int vidioc_g_tuner(struct file *file, void *priv,
 					struct v4l2_tuner *v)
 {
-	struct video_device *dev = video_devdata(file);
-	struct radio_device *card = video_get_drvdata(dev);
+	struct radio_device *card = video_drvdata(file);
 
 	if (v->index > 0)
 		return -EINVAL;
@@ -229,8 +242,7 @@
 static int vidioc_s_frequency(struct file *file, void *priv,
 					struct v4l2_frequency *f)
 {
-	struct video_device *dev = video_devdata(file);
-	struct radio_device *card = video_get_drvdata(dev);
+	struct radio_device *card = video_drvdata(file);
 
 	if (f->frequency < FREQ_LO || f->frequency > FREQ_HI)
 		return -EINVAL;
@@ -241,8 +253,7 @@
 static int vidioc_g_frequency(struct file *file, void *priv,
 					struct v4l2_frequency *f)
 {
-	struct video_device *dev = video_devdata(file);
-	struct radio_device *card = video_get_drvdata(dev);
+	struct radio_device *card = video_drvdata(file);
 
 	f->type = V4L2_TUNER_RADIO;
 	f->frequency = BITS2FREQ(radio_bits_get(card));
@@ -267,8 +278,7 @@
 static int vidioc_g_ctrl(struct file *file, void *priv,
 					struct v4l2_control *ctrl)
 {
-	struct video_device *dev = video_devdata(file);
-	struct radio_device *card = video_get_drvdata(dev);
+	struct radio_device *card = video_drvdata(file);
 
 	switch (ctrl->id) {
 	case V4L2_CID_AUDIO_MUTE:
@@ -281,8 +291,7 @@
 static int vidioc_s_ctrl(struct file *file, void *priv,
 					struct v4l2_control *ctrl)
 {
-	struct video_device *dev = video_devdata(file);
-	struct radio_device *card = video_get_drvdata(dev);
+	struct radio_device *card = video_drvdata(file);
 	register u16 io = card->io;
 	register u16 omask = inw(io + IO_MASK);
 
@@ -374,6 +383,7 @@
 	.name           = "Maestro radio",
 	.fops           = &maestro_fops,
 	.ioctl_ops 	= &maestro_ioctl_ops,
+	.release	= video_device_release,
 };
 
 static int __devinit maestro_probe(struct pci_dev *pdev,
diff --git a/drivers/media/radio/radio-maxiradio.c b/drivers/media/radio/radio-maxiradio.c
index 0cc6fcb..c777a17 100644
--- a/drivers/media/radio/radio-maxiradio.c
+++ b/drivers/media/radio/radio-maxiradio.c
@@ -85,6 +85,7 @@
 static int radio_nr = -1;
 module_param(radio_nr, int, 0);
 
+static unsigned long in_use;
 
 #define FREQ_LO		 50*16000
 #define FREQ_HI		150*16000
@@ -99,10 +100,21 @@
 #define BITS2FREQ(x)	((x) * FREQ_STEP - FREQ_IF)
 
 
+static int maxiradio_exclusive_open(struct inode *inode, struct file *file)
+{
+	return test_and_set_bit(0, &in_use) ? -EBUSY : 0;
+}
+
+static int maxiradio_exclusive_release(struct inode *inode, struct file *file)
+{
+	clear_bit(0, &in_use);
+	return 0;
+}
+
 static const struct file_operations maxiradio_fops = {
 	.owner		= THIS_MODULE,
-	.open           = video_exclusive_open,
-	.release        = video_exclusive_release,
+	.open           = maxiradio_exclusive_open,
+	.release        = maxiradio_exclusive_release,
 	.ioctl          = video_ioctl2,
 #ifdef CONFIG_COMPAT
 	.compat_ioctl	= v4l_compat_ioctl32,
@@ -219,8 +231,7 @@
 static int vidioc_g_tuner (struct file *file, void *priv,
 			   struct v4l2_tuner *v)
 {
-	struct video_device *dev = video_devdata(file);
-	struct radio_device *card=dev->priv;
+	struct radio_device *card = video_drvdata(file);
 
 	if (v->index > 0)
 		return -EINVAL;
@@ -290,8 +301,7 @@
 static int vidioc_s_frequency (struct file *file, void *priv,
 			       struct v4l2_frequency *f)
 {
-	struct video_device *dev = video_devdata(file);
-	struct radio_device *card=dev->priv;
+	struct radio_device *card = video_drvdata(file);
 
 	if (f->frequency < FREQ_LO || f->frequency > FREQ_HI) {
 		dprintk(1, "radio freq (%d.%02d MHz) out of range (%d-%d)\n",
@@ -312,8 +322,7 @@
 static int vidioc_g_frequency (struct file *file, void *priv,
 			       struct v4l2_frequency *f)
 {
-	struct video_device *dev = video_devdata(file);
-	struct radio_device *card=dev->priv;
+	struct radio_device *card = video_drvdata(file);
 
 	f->type = V4L2_TUNER_RADIO;
 	f->frequency = card->freq;
@@ -343,8 +352,7 @@
 static int vidioc_g_ctrl (struct file *file, void *priv,
 			    struct v4l2_control *ctrl)
 {
-	struct video_device *dev = video_devdata(file);
-	struct radio_device *card=dev->priv;
+	struct radio_device *card = video_drvdata(file);
 
 	switch (ctrl->id) {
 		case V4L2_CID_AUDIO_MUTE:
@@ -358,8 +366,7 @@
 static int vidioc_s_ctrl (struct file *file, void *priv,
 			  struct v4l2_control *ctrl)
 {
-	struct video_device *dev = video_devdata(file);
-	struct radio_device *card=dev->priv;
+	struct radio_device *card = video_drvdata(file);
 
 	switch (ctrl->id) {
 		case V4L2_CID_AUDIO_MUTE:
@@ -390,9 +397,10 @@
 };
 
 static struct video_device maxiradio_radio = {
-	.name		    = "Maxi Radio FM2000 radio",
-	.fops               = &maxiradio_fops,
-	.ioctl_ops 	    = &maxiradio_ioctl_ops,
+	.name		= "Maxi Radio FM2000 radio",
+	.fops           = &maxiradio_fops,
+	.ioctl_ops 	= &maxiradio_ioctl_ops,
+	.release	= video_device_release_empty,
 };
 
 static int __devinit maxiradio_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
@@ -408,7 +416,7 @@
 
 	radio_unit.io = pci_resource_start(pdev, 0);
 	mutex_init(&radio_unit.lock);
-	maxiradio_radio.priv = &radio_unit;
+	video_set_drvdata(&maxiradio_radio, &radio_unit);
 
 	if (video_register_device(&maxiradio_radio, VFL_TYPE_RADIO, radio_nr) < 0) {
 		printk("radio-maxiradio: can't register device!");
diff --git a/drivers/media/radio/radio-mr800.c b/drivers/media/radio/radio-mr800.c
new file mode 100644
index 0000000..a33717c
--- /dev/null
+++ b/drivers/media/radio/radio-mr800.c
@@ -0,0 +1,628 @@
+/*
+ * A driver for the AverMedia MR 800 USB FM radio. This device plugs
+ * into both the USB and an analog audio input, so this thing
+ * only deals with initialization and frequency setting, the
+ * audio data has to be handled by a sound driver.
+ *
+ * Copyright (c) 2008 Alexey Klimov <klimov.linux@gmail.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
+ */
+
+/*
+ * Big thanks to authors of dsbr100.c and radio-si470x.c
+ *
+ * When work was looked pretty good, i discover this:
+ * http://av-usbradio.sourceforge.net/index.php
+ * http://sourceforge.net/projects/av-usbradio/
+ * Latest release of theirs project was in 2005.
+ * Probably, this driver could be improved trough using their
+ * achievements (specifications given).
+ * So, we have smth to begin with.
+ *
+ * History:
+ * Version 0.01:	First working version.
+ * 			It's required to blacklist AverMedia USB Radio
+ * 			in usbhid/hid-quirks.c
+ *
+ * Many things to do:
+ * 	- Correct power managment of device (suspend & resume)
+ * 	- Make x86 independance (little-endian and big-endian stuff)
+ * 	- Add code for scanning and smooth tuning
+ * 	- Checked and add stereo&mono stuff
+ * 	- Add code for sensitivity value
+ * 	- Correct mistakes
+ * 	- In Japan another FREQ_MIN and FREQ_MAX
+ */
+
+/* kernel includes */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-ioctl.h>
+#include <linux/usb.h>
+#include <linux/version.h>	/* for KERNEL_VERSION MACRO */
+
+/* driver and module definitions */
+#define DRIVER_AUTHOR "Alexey Klimov <klimov.linux@gmail.com>"
+#define DRIVER_DESC "AverMedia MR 800 USB FM radio driver"
+#define DRIVER_VERSION "0.01"
+#define RADIO_VERSION KERNEL_VERSION(0, 0, 1)
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+
+#define USB_AMRADIO_VENDOR 0x07ca
+#define USB_AMRADIO_PRODUCT 0xb800
+
+/* Probably USB_TIMEOUT should be modified in module parameter */
+#define BUFFER_LENGTH 8
+#define USB_TIMEOUT 500
+
+/* Frequency limits in MHz -- these are European values.  For Japanese
+devices, that would be 76 and 91.  */
+#define FREQ_MIN  87.5
+#define FREQ_MAX 108.0
+#define FREQ_MUL 16000
+
+/* module parameter */
+static int radio_nr = -1;
+module_param(radio_nr, int, 0);
+MODULE_PARM_DESC(radio_nr, "Radio Nr");
+
+static struct v4l2_queryctrl radio_qctrl[] = {
+	{
+		.id            = V4L2_CID_AUDIO_MUTE,
+		.name          = "Mute",
+		.minimum       = 0,
+		.maximum       = 1,
+		.step	       = 1,
+		.default_value = 1,
+		.type          = V4L2_CTRL_TYPE_BOOLEAN,
+	},
+/* HINT: the disabled controls are only here to satify kradio and such apps */
+	{	.id		= V4L2_CID_AUDIO_VOLUME,
+		.flags		= V4L2_CTRL_FLAG_DISABLED,
+	},
+	{
+		.id		= V4L2_CID_AUDIO_BALANCE,
+		.flags		= V4L2_CTRL_FLAG_DISABLED,
+	},
+	{
+		.id		= V4L2_CID_AUDIO_BASS,
+		.flags		= V4L2_CTRL_FLAG_DISABLED,
+	},
+	{
+		.id		= V4L2_CID_AUDIO_TREBLE,
+		.flags		= V4L2_CTRL_FLAG_DISABLED,
+	},
+	{
+		.id		= V4L2_CID_AUDIO_LOUDNESS,
+		.flags		= V4L2_CTRL_FLAG_DISABLED,
+	},
+};
+
+static int usb_amradio_probe(struct usb_interface *intf,
+			     const struct usb_device_id *id);
+static void usb_amradio_disconnect(struct usb_interface *intf);
+static int usb_amradio_open(struct inode *inode, struct file *file);
+static int usb_amradio_close(struct inode *inode, struct file *file);
+static int usb_amradio_suspend(struct usb_interface *intf,
+				pm_message_t message);
+static int usb_amradio_resume(struct usb_interface *intf);
+
+/* Data for one (physical) device */
+struct amradio_device {
+	/* reference to USB and video device */
+	struct usb_device *usbdev;
+	struct video_device *videodev;
+
+	unsigned char *buffer;
+	struct mutex lock;	/* buffer locking */
+	int curfreq;
+	int stereo;
+	int users;
+	int removed;
+	int muted;
+};
+
+/* USB Device ID List */
+static struct usb_device_id usb_amradio_device_table[] = {
+	{USB_DEVICE_AND_INTERFACE_INFO(USB_AMRADIO_VENDOR, USB_AMRADIO_PRODUCT,
+							USB_CLASS_HID, 0, 0) },
+	{ }						/* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE(usb, usb_amradio_device_table);
+
+/* USB subsystem interface */
+static struct usb_driver usb_amradio_driver = {
+	.name			= "radio-mr800",
+	.probe			= usb_amradio_probe,
+	.disconnect		= usb_amradio_disconnect,
+	.suspend		= usb_amradio_suspend,
+	.resume			= usb_amradio_resume,
+	.reset_resume		= usb_amradio_resume,
+	.id_table		= usb_amradio_device_table,
+	.supports_autosuspend	= 1,
+};
+
+/* switch on radio. Send 8 bytes to device. */
+static int amradio_start(struct amradio_device *radio)
+{
+	int retval;
+	int size;
+
+	mutex_lock(&radio->lock);
+
+	radio->buffer[0] = 0x00;
+	radio->buffer[1] = 0x55;
+	radio->buffer[2] = 0xaa;
+	radio->buffer[3] = 0x00;
+	radio->buffer[4] = 0xab;
+	radio->buffer[5] = 0x00;
+	radio->buffer[6] = 0x00;
+	radio->buffer[7] = 0x00;
+
+	retval = usb_bulk_msg(radio->usbdev, usb_sndintpipe(radio->usbdev, 2),
+		(void *) (radio->buffer), BUFFER_LENGTH, &size, USB_TIMEOUT);
+
+	if (retval) {
+		mutex_unlock(&radio->lock);
+		return retval;
+	}
+
+	mutex_unlock(&radio->lock);
+
+	radio->muted = 0;
+
+	return retval;
+}
+
+/* switch off radio */
+static int amradio_stop(struct amradio_device *radio)
+{
+	int retval;
+	int size;
+
+	mutex_lock(&radio->lock);
+
+	radio->buffer[0] = 0x00;
+	radio->buffer[1] = 0x55;
+	radio->buffer[2] = 0xaa;
+	radio->buffer[3] = 0x00;
+	radio->buffer[4] = 0xab;
+	radio->buffer[5] = 0x01;
+	radio->buffer[6] = 0x00;
+	radio->buffer[7] = 0x00;
+
+	retval = usb_bulk_msg(radio->usbdev, usb_sndintpipe(radio->usbdev, 2),
+		(void *) (radio->buffer), BUFFER_LENGTH, &size, USB_TIMEOUT);
+
+	if (retval) {
+		mutex_unlock(&radio->lock);
+		return retval;
+	}
+
+	mutex_unlock(&radio->lock);
+
+	radio->muted = 1;
+
+	return retval;
+}
+
+/* set a frequency, freq is defined by v4l's TUNER_LOW, i.e. 1/16th kHz */
+static int amradio_setfreq(struct amradio_device *radio, int freq)
+{
+	int retval;
+	int size;
+	unsigned short freq_send = 0x13 + (freq >> 3) / 25;
+
+	mutex_lock(&radio->lock);
+
+	radio->buffer[0] = 0x00;
+	radio->buffer[1] = 0x55;
+	radio->buffer[2] = 0xaa;
+	radio->buffer[3] = 0x03;
+	radio->buffer[4] = 0xa4;
+	radio->buffer[5] = 0x00;
+	radio->buffer[6] = 0x00;
+	radio->buffer[7] = 0x08;
+
+	retval = usb_bulk_msg(radio->usbdev, usb_sndintpipe(radio->usbdev, 2),
+		(void *) (radio->buffer), BUFFER_LENGTH, &size, USB_TIMEOUT);
+
+	if (retval) {
+		mutex_unlock(&radio->lock);
+		return retval;
+	}
+
+	/* frequency is calculated from freq_send and placed in first 2 bytes */
+	radio->buffer[0] = (freq_send >> 8) & 0xff;
+	radio->buffer[1] = freq_send & 0xff;
+	radio->buffer[2] = 0x01;
+	radio->buffer[3] = 0x00;
+	radio->buffer[4] = 0x00;
+	/* 5 and 6 bytes of buffer already = 0x00 */
+	radio->buffer[7] = 0x00;
+
+	retval = usb_bulk_msg(radio->usbdev, usb_sndintpipe(radio->usbdev, 2),
+		(void *) (radio->buffer), BUFFER_LENGTH, &size, USB_TIMEOUT);
+
+	if (retval) {
+		mutex_unlock(&radio->lock);
+		return retval;
+	}
+
+	mutex_unlock(&radio->lock);
+
+	radio->stereo = 0;
+
+	return retval;
+}
+
+/* USB subsystem interface begins here */
+
+/* handle unplugging of the device, release data structures
+if nothing keeps us from doing it.  If something is still
+keeping us busy, the release callback of v4l will take care
+of releasing it. */
+static void usb_amradio_disconnect(struct usb_interface *intf)
+{
+	struct amradio_device *radio = usb_get_intfdata(intf);
+
+	usb_set_intfdata(intf, NULL);
+
+	if (radio) {
+		video_unregister_device(radio->videodev);
+		radio->videodev = NULL;
+		if (radio->users) {
+			kfree(radio->buffer);
+			kfree(radio);
+		} else {
+			radio->removed = 1;
+		}
+	}
+}
+
+/* vidioc_querycap - query device capabilities */
+static int vidioc_querycap(struct file *file, void *priv,
+					struct v4l2_capability *v)
+{
+	strlcpy(v->driver, "radio-mr800", sizeof(v->driver));
+	strlcpy(v->card, "AverMedia MR 800 USB FM Radio", sizeof(v->card));
+	sprintf(v->bus_info, "USB");
+	v->version = RADIO_VERSION;
+	v->capabilities = V4L2_CAP_TUNER;
+	return 0;
+}
+
+/* vidioc_g_tuner - get tuner attributes */
+static int vidioc_g_tuner(struct file *file, void *priv,
+				struct v4l2_tuner *v)
+{
+	struct amradio_device *radio = video_get_drvdata(video_devdata(file));
+
+	if (v->index > 0)
+		return -EINVAL;
+
+/* TODO: Add function which look is signal stereo or not
+ * 	amradio_getstat(radio);
+ */
+	radio->stereo = -1;
+	strcpy(v->name, "FM");
+	v->type = V4L2_TUNER_RADIO;
+	v->rangelow = FREQ_MIN * FREQ_MUL;
+	v->rangehigh = FREQ_MAX * FREQ_MUL;
+	v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
+	v->capability = V4L2_TUNER_CAP_LOW;
+	if (radio->stereo)
+		v->audmode = V4L2_TUNER_MODE_STEREO;
+	else
+		v->audmode = V4L2_TUNER_MODE_MONO;
+	v->signal = 0xffff;     /* Can't get the signal strength, sad.. */
+	v->afc = 0; /* Don't know what is this */
+	return 0;
+}
+
+/* vidioc_s_tuner - set tuner attributes */
+static int vidioc_s_tuner(struct file *file, void *priv,
+				struct v4l2_tuner *v)
+{
+	if (v->index > 0)
+		return -EINVAL;
+	return 0;
+}
+
+/* vidioc_s_frequency - set tuner radio frequency */
+static int vidioc_s_frequency(struct file *file, void *priv,
+				struct v4l2_frequency *f)
+{
+	struct amradio_device *radio = video_get_drvdata(video_devdata(file));
+
+	radio->curfreq = f->frequency;
+	if (amradio_setfreq(radio, radio->curfreq) < 0)
+		warn("Set frequency failed");
+	return 0;
+}
+
+/* vidioc_g_frequency - get tuner radio frequency */
+static int vidioc_g_frequency(struct file *file, void *priv,
+				struct v4l2_frequency *f)
+{
+	struct amradio_device *radio = video_get_drvdata(video_devdata(file));
+
+	f->type = V4L2_TUNER_RADIO;
+	f->frequency = radio->curfreq;
+	return 0;
+}
+
+/* vidioc_queryctrl - enumerate control items */
+static int vidioc_queryctrl(struct file *file, void *priv,
+				struct v4l2_queryctrl *qc)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
+		if (qc->id && qc->id == radio_qctrl[i].id) {
+			memcpy(qc, &(radio_qctrl[i]),
+						sizeof(*qc));
+			return 0;
+		}
+	}
+	return -EINVAL;
+}
+
+/* vidioc_g_ctrl - get the value of a control */
+static int vidioc_g_ctrl(struct file *file, void *priv,
+				struct v4l2_control *ctrl)
+{
+	struct amradio_device *radio = video_get_drvdata(video_devdata(file));
+
+	switch (ctrl->id) {
+	case V4L2_CID_AUDIO_MUTE:
+		ctrl->value = radio->muted;
+		return 0;
+	}
+	return -EINVAL;
+}
+
+/* vidioc_s_ctrl - set the value of a control */
+static int vidioc_s_ctrl(struct file *file, void *priv,
+				struct v4l2_control *ctrl)
+{
+	struct amradio_device *radio = video_get_drvdata(video_devdata(file));
+
+	switch (ctrl->id) {
+	case V4L2_CID_AUDIO_MUTE:
+		if (ctrl->value) {
+			if (amradio_stop(radio) < 0) {
+				warn("amradio_stop() failed");
+				return -1;
+			}
+		} else {
+			if (amradio_start(radio) < 0) {
+				warn("amradio_start() failed");
+				return -1;
+			}
+		}
+		return 0;
+	}
+	return -EINVAL;
+}
+
+/* vidioc_g_audio - get audio attributes */
+static int vidioc_g_audio(struct file *file, void *priv,
+				struct v4l2_audio *a)
+{
+	if (a->index > 1)
+		return -EINVAL;
+
+	strcpy(a->name, "Radio");
+	a->capability = V4L2_AUDCAP_STEREO;
+	return 0;
+}
+
+/* vidioc_s_audio - set audio attributes  */
+static int vidioc_s_audio(struct file *file, void *priv,
+					struct v4l2_audio *a)
+{
+	if (a->index != 0)
+		return -EINVAL;
+	return 0;
+}
+
+/* vidioc_g_input - get input */
+static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
+{
+	*i = 0;
+	return 0;
+}
+
+/* vidioc_s_input - set input */
+static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
+{
+	if (i != 0)
+		return -EINVAL;
+	return 0;
+}
+
+/* open device - amradio_start() and amradio_setfreq() */
+static int usb_amradio_open(struct inode *inode, struct file *file)
+{
+	struct amradio_device *radio = video_get_drvdata(video_devdata(file));
+
+	radio->users = 1;
+	radio->muted = 1;
+
+	if (amradio_start(radio) < 0) {
+		warn("Radio did not start up properly");
+		radio->users = 0;
+		return -EIO;
+	}
+	if (amradio_setfreq(radio, radio->curfreq) < 0)
+		warn("Set frequency failed");
+	return 0;
+}
+
+/*close device - free driver structures */
+static int usb_amradio_close(struct inode *inode, struct file *file)
+{
+	struct amradio_device *radio = video_get_drvdata(video_devdata(file));
+
+	if (!radio)
+		return -ENODEV;
+	radio->users = 0;
+	if (radio->removed) {
+		kfree(radio->buffer);
+		kfree(radio);
+	}
+	return 0;
+}
+
+/* Suspend device - stop device. Need to be checked and fixed */
+static int usb_amradio_suspend(struct usb_interface *intf, pm_message_t message)
+{
+	struct amradio_device *radio = usb_get_intfdata(intf);
+
+	if (amradio_stop(radio) < 0)
+		warn("amradio_stop() failed");
+
+	info("radio-mr800: Going into suspend..");
+
+	return 0;
+}
+
+/* Resume device - start device. Need to be checked and fixed */
+static int usb_amradio_resume(struct usb_interface *intf)
+{
+	struct amradio_device *radio = usb_get_intfdata(intf);
+
+	if (amradio_start(radio) < 0)
+		warn("amradio_start() failed");
+
+	info("radio-mr800: Coming out of suspend..");
+
+	return 0;
+}
+
+/* File system interface */
+static const struct file_operations usb_amradio_fops = {
+	.owner		= THIS_MODULE,
+	.open		= usb_amradio_open,
+	.release	= usb_amradio_close,
+	.ioctl		= video_ioctl2,
+#ifdef CONFIG_COMPAT
+	.compat_ioctl	= v4l_compat_ioctl32,
+#endif
+	.llseek		= no_llseek,
+};
+
+static const struct v4l2_ioctl_ops usb_amradio_ioctl_ops = {
+	.vidioc_querycap    = vidioc_querycap,
+	.vidioc_g_tuner     = vidioc_g_tuner,
+	.vidioc_s_tuner     = vidioc_s_tuner,
+	.vidioc_g_frequency = vidioc_g_frequency,
+	.vidioc_s_frequency = vidioc_s_frequency,
+	.vidioc_queryctrl   = vidioc_queryctrl,
+	.vidioc_g_ctrl      = vidioc_g_ctrl,
+	.vidioc_s_ctrl      = vidioc_s_ctrl,
+	.vidioc_g_audio     = vidioc_g_audio,
+	.vidioc_s_audio     = vidioc_s_audio,
+	.vidioc_g_input     = vidioc_g_input,
+	.vidioc_s_input     = vidioc_s_input,
+};
+
+/* V4L2 interface */
+static struct video_device amradio_videodev_template = {
+	.name		= "AverMedia MR 800 USB FM Radio",
+	.fops		= &usb_amradio_fops,
+	.ioctl_ops 	= &usb_amradio_ioctl_ops,
+	.release	= video_device_release,
+};
+
+/* check if the device is present and register with v4l and
+usb if it is */
+static int usb_amradio_probe(struct usb_interface *intf,
+				const struct usb_device_id *id)
+{
+	struct amradio_device *radio;
+
+	radio = kmalloc(sizeof(struct amradio_device), GFP_KERNEL);
+
+	if (!(radio))
+		return -ENOMEM;
+
+	radio->buffer = kmalloc(BUFFER_LENGTH, GFP_KERNEL);
+
+	if (!(radio->buffer)) {
+		kfree(radio);
+		return -ENOMEM;
+	}
+
+	radio->videodev = video_device_alloc();
+
+	if (!(radio->videodev)) {
+		kfree(radio->buffer);
+		kfree(radio);
+		return -ENOMEM;
+	}
+
+	memcpy(radio->videodev, &amradio_videodev_template,
+		sizeof(amradio_videodev_template));
+
+	radio->removed = 0;
+	radio->users = 0;
+	radio->usbdev = interface_to_usbdev(intf);
+	radio->curfreq = 95.16 * FREQ_MUL;
+
+	mutex_init(&radio->lock);
+
+	video_set_drvdata(radio->videodev, radio);
+	if (video_register_device(radio->videodev, VFL_TYPE_RADIO, radio_nr)) {
+		warn("Could not register video device");
+		video_device_release(radio->videodev);
+		kfree(radio->buffer);
+		kfree(radio);
+		return -EIO;
+	}
+
+	usb_set_intfdata(intf, radio);
+	return 0;
+}
+
+static int __init amradio_init(void)
+{
+	int retval = usb_register(&usb_amradio_driver);
+
+	info(DRIVER_VERSION " " DRIVER_DESC);
+	if (retval)
+		err("usb_register failed. Error number %d", retval);
+	return retval;
+}
+
+static void __exit amradio_exit(void)
+{
+	usb_deregister(&usb_amradio_driver);
+}
+
+module_init(amradio_init);
+module_exit(amradio_exit);
+
diff --git a/drivers/media/radio/radio-rtrack2.c b/drivers/media/radio/radio-rtrack2.c
index 6d820e2..a670797 100644
--- a/drivers/media/radio/radio-rtrack2.c
+++ b/drivers/media/radio/radio-rtrack2.c
@@ -52,6 +52,7 @@
 
 struct rt_device
 {
+	unsigned long in_use;
 	int port;
 	unsigned long curfreq;
 	int muted;
@@ -153,8 +154,7 @@
 static int vidioc_g_tuner(struct file *file, void *priv,
 				struct v4l2_tuner *v)
 {
-	struct video_device *dev = video_devdata(file);
-	struct rt_device *rt = dev->priv;
+	struct rt_device *rt = video_drvdata(file);
 
 	if (v->index > 0)
 		return -EINVAL;
@@ -173,8 +173,7 @@
 static int vidioc_s_frequency(struct file *file, void *priv,
 				struct v4l2_frequency *f)
 {
-	struct video_device *dev = video_devdata(file);
-	struct rt_device *rt = dev->priv;
+	struct rt_device *rt = video_drvdata(file);
 
 	rt->curfreq = f->frequency;
 	rt_setfreq(rt, rt->curfreq);
@@ -184,8 +183,7 @@
 static int vidioc_g_frequency(struct file *file, void *priv,
 				struct v4l2_frequency *f)
 {
-	struct video_device *dev = video_devdata(file);
-	struct rt_device *rt = dev->priv;
+	struct rt_device *rt = video_drvdata(file);
 
 	f->type = V4L2_TUNER_RADIO;
 	f->frequency = rt->curfreq;
@@ -210,8 +208,7 @@
 static int vidioc_g_ctrl(struct file *file, void *priv,
 				struct v4l2_control *ctrl)
 {
-	struct video_device *dev = video_devdata(file);
-	struct rt_device *rt = dev->priv;
+	struct rt_device *rt = video_drvdata(file);
 
 	switch (ctrl->id) {
 	case V4L2_CID_AUDIO_MUTE:
@@ -230,8 +227,7 @@
 static int vidioc_s_ctrl(struct file *file, void *priv,
 				struct v4l2_control *ctrl)
 {
-	struct video_device *dev = video_devdata(file);
-	struct rt_device *rt = dev->priv;
+	struct rt_device *rt = video_drvdata(file);
 
 	switch (ctrl->id) {
 	case V4L2_CID_AUDIO_MUTE:
@@ -284,10 +280,21 @@
 
 static struct rt_device rtrack2_unit;
 
+static int rtrack2_exclusive_open(struct inode *inode, struct file *file)
+{
+	return test_and_set_bit(0, &rtrack2_unit.in_use) ? -EBUSY : 0;
+}
+
+static int rtrack2_exclusive_release(struct inode *inode, struct file *file)
+{
+	clear_bit(0, &rtrack2_unit.in_use);
+	return 0;
+}
+
 static const struct file_operations rtrack2_fops = {
 	.owner		= THIS_MODULE,
-	.open           = video_exclusive_open,
-	.release        = video_exclusive_release,
+	.open           = rtrack2_exclusive_open,
+	.release        = rtrack2_exclusive_release,
 	.ioctl		= video_ioctl2,
 #ifdef CONFIG_COMPAT
 	.compat_ioctl	= v4l_compat_ioctl32,
@@ -314,6 +321,7 @@
 	.name		= "RadioTrack II radio",
 	.fops           = &rtrack2_fops,
 	.ioctl_ops 	= &rtrack2_ioctl_ops,
+	.release	= video_device_release_empty,
 };
 
 static int __init rtrack2_init(void)
@@ -329,7 +337,7 @@
 		return -EBUSY;
 	}
 
-	rtrack2_radio.priv=&rtrack2_unit;
+	video_set_drvdata(&rtrack2_radio, &rtrack2_unit);
 
 	spin_lock_init(&lock);
 	if (video_register_device(&rtrack2_radio, VFL_TYPE_RADIO, radio_nr) < 0) {
diff --git a/drivers/media/radio/radio-sf16fmi.c b/drivers/media/radio/radio-sf16fmi.c
index 0d478f5..329c90b 100644
--- a/drivers/media/radio/radio-sf16fmi.c
+++ b/drivers/media/radio/radio-sf16fmi.c
@@ -45,6 +45,7 @@
 
 struct fmi_device
 {
+	unsigned long in_use;
 	int port;
 	int curvol; /* 1 or 0 */
 	unsigned long curfreq; /* freq in kHz */
@@ -146,8 +147,7 @@
 					struct v4l2_tuner *v)
 {
 	int mult;
-	struct video_device *dev = video_devdata(file);
-	struct fmi_device *fmi = dev->priv;
+	struct fmi_device *fmi = video_drvdata(file);
 
 	if (v->index > 0)
 		return -EINVAL;
@@ -175,8 +175,7 @@
 static int vidioc_s_frequency(struct file *file, void *priv,
 					struct v4l2_frequency *f)
 {
-	struct video_device *dev = video_devdata(file);
-	struct fmi_device *fmi = dev->priv;
+	struct fmi_device *fmi = video_drvdata(file);
 
 	if (!(fmi->flags & V4L2_TUNER_CAP_LOW))
 		f->frequency *= 1000;
@@ -193,8 +192,7 @@
 static int vidioc_g_frequency(struct file *file, void *priv,
 					struct v4l2_frequency *f)
 {
-	struct video_device *dev = video_devdata(file);
-	struct fmi_device *fmi = dev->priv;
+	struct fmi_device *fmi = video_drvdata(file);
 
 	f->type = V4L2_TUNER_RADIO;
 	f->frequency = fmi->curfreq;
@@ -221,8 +219,7 @@
 static int vidioc_g_ctrl(struct file *file, void *priv,
 					struct v4l2_control *ctrl)
 {
-	struct video_device *dev = video_devdata(file);
-	struct fmi_device *fmi = dev->priv;
+	struct fmi_device *fmi = video_drvdata(file);
 
 	switch (ctrl->id) {
 	case V4L2_CID_AUDIO_MUTE:
@@ -235,8 +232,7 @@
 static int vidioc_s_ctrl(struct file *file, void *priv,
 					struct v4l2_control *ctrl)
 {
-	struct video_device *dev = video_devdata(file);
-	struct fmi_device *fmi = dev->priv;
+	struct fmi_device *fmi = video_drvdata(file);
 
 	switch (ctrl->id) {
 	case V4L2_CID_AUDIO_MUTE:
@@ -284,10 +280,21 @@
 
 static struct fmi_device fmi_unit;
 
+static int fmi_exclusive_open(struct inode *inode, struct file *file)
+{
+	return test_and_set_bit(0, &fmi_unit.in_use) ? -EBUSY : 0;
+}
+
+static int fmi_exclusive_release(struct inode *inode, struct file *file)
+{
+	clear_bit(0, &fmi_unit.in_use);
+	return 0;
+}
+
 static const struct file_operations fmi_fops = {
 	.owner		= THIS_MODULE,
-	.open           = video_exclusive_open,
-	.release        = video_exclusive_release,
+	.open           = fmi_exclusive_open,
+	.release        = fmi_exclusive_release,
 	.ioctl		= video_ioctl2,
 #ifdef CONFIG_COMPAT
 	.compat_ioctl	= v4l_compat_ioctl32,
@@ -314,6 +321,7 @@
 	.name		= "SF16FMx radio",
 	.fops           = &fmi_fops,
 	.ioctl_ops 	= &fmi_ioctl_ops,
+	.release	= video_device_release_empty,
 };
 
 /* ladis: this is my card. does any other types exist? */
@@ -373,7 +381,7 @@
 	fmi_unit.curvol = 0;
 	fmi_unit.curfreq = 0;
 	fmi_unit.flags = V4L2_TUNER_CAP_LOW;
-	fmi_radio.priv = &fmi_unit;
+	video_set_drvdata(&fmi_radio, &fmi_unit);
 
 	mutex_init(&lock);
 
diff --git a/drivers/media/radio/radio-sf16fmr2.c b/drivers/media/radio/radio-sf16fmr2.c
index 6290553..b1f47c3 100644
--- a/drivers/media/radio/radio-sf16fmr2.c
+++ b/drivers/media/radio/radio-sf16fmr2.c
@@ -64,6 +64,7 @@
 /* this should be static vars for module size */
 struct fmr2_device
 {
+	unsigned long in_use;
 	int port;
 	int curvol; /* 0-15 */
 	int mute;
@@ -229,8 +230,7 @@
 					struct v4l2_tuner *v)
 {
 	int mult;
-	struct video_device *dev = video_devdata(file);
-	struct fmr2_device *fmr2 = dev->priv;
+	struct fmr2_device *fmr2 = video_drvdata(file);
 
 	if (v->index > 0)
 		return -EINVAL;
@@ -262,8 +262,7 @@
 static int vidioc_s_frequency(struct file *file, void *priv,
 					struct v4l2_frequency *f)
 {
-	struct video_device *dev = video_devdata(file);
-	struct fmr2_device *fmr2 = dev->priv;
+	struct fmr2_device *fmr2 = video_drvdata(file);
 
 	if (!(fmr2->flags & V4L2_TUNER_CAP_LOW))
 		f->frequency *= 1000;
@@ -286,8 +285,7 @@
 static int vidioc_g_frequency(struct file *file, void *priv,
 					struct v4l2_frequency *f)
 {
-	struct video_device *dev = video_devdata(file);
-	struct fmr2_device *fmr2 = dev->priv;
+	struct fmr2_device *fmr2 = video_drvdata(file);
 
 	f->type = V4L2_TUNER_RADIO;
 	f->frequency = fmr2->curfreq;
@@ -313,8 +311,7 @@
 static int vidioc_g_ctrl(struct file *file, void *priv,
 					struct v4l2_control *ctrl)
 {
-	struct video_device *dev = video_devdata(file);
-	struct fmr2_device *fmr2 = dev->priv;
+	struct fmr2_device *fmr2 = video_drvdata(file);
 
 	switch (ctrl->id) {
 	case V4L2_CID_AUDIO_MUTE:
@@ -330,8 +327,7 @@
 static int vidioc_s_ctrl(struct file *file, void *priv,
 					struct v4l2_control *ctrl)
 {
-	struct video_device *dev = video_devdata(file);
-	struct fmr2_device *fmr2 = dev->priv;
+	struct fmr2_device *fmr2 = video_drvdata(file);
 
 	switch (ctrl->id) {
 	case V4L2_CID_AUDIO_MUTE:
@@ -400,10 +396,21 @@
 
 static struct fmr2_device fmr2_unit;
 
+static int fmr2_exclusive_open(struct inode *inode, struct file *file)
+{
+	return test_and_set_bit(0, &fmr2_unit.in_use) ? -EBUSY : 0;
+}
+
+static int fmr2_exclusive_release(struct inode *inode, struct file *file)
+{
+	clear_bit(0, &fmr2_unit.in_use);
+	return 0;
+}
+
 static const struct file_operations fmr2_fops = {
 	.owner          = THIS_MODULE,
-	.open           = video_exclusive_open,
-	.release        = video_exclusive_release,
+	.open           = fmr2_exclusive_open,
+	.release        = fmr2_exclusive_release,
 	.ioctl          = video_ioctl2,
 #ifdef CONFIG_COMPAT
 	.compat_ioctl	= v4l_compat_ioctl32,
@@ -430,6 +437,7 @@
 	.name		= "SF16FMR2 radio",
 	.fops		= &fmr2_fops,
 	.ioctl_ops 	= &fmr2_ioctl_ops,
+	.release	= video_device_release_empty,
 };
 
 static int __init fmr2_init(void)
@@ -441,7 +449,7 @@
 	fmr2_unit.stereo = 1;
 	fmr2_unit.flags = V4L2_TUNER_CAP_LOW;
 	fmr2_unit.card_type = 0;
-	fmr2_radio.priv = &fmr2_unit;
+	video_set_drvdata(&fmr2_radio, &fmr2_unit);
 
 	mutex_init(&lock);
 
diff --git a/drivers/media/radio/radio-si470x.c b/drivers/media/radio/radio-si470x.c
index 16c7ef2..f6cedcd 100644
--- a/drivers/media/radio/radio-si470x.c
+++ b/drivers/media/radio/radio-si470x.c
@@ -986,7 +986,7 @@
 static ssize_t si470x_fops_read(struct file *file, char __user *buf,
 		size_t count, loff_t *ppos)
 {
-	struct si470x_device *radio = video_get_drvdata(video_devdata(file));
+	struct si470x_device *radio = video_drvdata(file);
 	int retval = 0;
 	unsigned int block_count = 0;
 
@@ -1047,7 +1047,7 @@
 static unsigned int si470x_fops_poll(struct file *file,
 		struct poll_table_struct *pts)
 {
-	struct si470x_device *radio = video_get_drvdata(video_devdata(file));
+	struct si470x_device *radio = video_drvdata(file);
 	int retval = 0;
 
 	/* switch on rds reception */
@@ -1071,9 +1071,10 @@
  */
 static int si470x_fops_open(struct inode *inode, struct file *file)
 {
-	struct si470x_device *radio = video_get_drvdata(video_devdata(file));
+	struct si470x_device *radio = video_drvdata(file);
 	int retval;
 
+	lock_kernel();
 	radio->users++;
 
 	retval = usb_autopm_get_interface(radio->intf);
@@ -1090,6 +1091,7 @@
 	}
 
 done:
+	unlock_kernel();
 	return retval;
 }
 
@@ -1099,7 +1101,7 @@
  */
 static int si470x_fops_release(struct inode *inode, struct file *file)
 {
-	struct si470x_device *radio = video_get_drvdata(video_devdata(file));
+	struct si470x_device *radio = video_drvdata(file);
 	int retval = 0;
 
 	/* safety check */
@@ -1282,7 +1284,7 @@
 static int si470x_vidioc_g_ctrl(struct file *file, void *priv,
 		struct v4l2_control *ctrl)
 {
-	struct si470x_device *radio = video_get_drvdata(video_devdata(file));
+	struct si470x_device *radio = video_drvdata(file);
 	int retval = 0;
 
 	/* safety checks */
@@ -1318,7 +1320,7 @@
 static int si470x_vidioc_s_ctrl(struct file *file, void *priv,
 		struct v4l2_control *ctrl)
 {
-	struct si470x_device *radio = video_get_drvdata(video_devdata(file));
+	struct si470x_device *radio = video_drvdata(file);
 	int retval = 0;
 
 	/* safety checks */
@@ -1405,7 +1407,7 @@
 static int si470x_vidioc_g_tuner(struct file *file, void *priv,
 		struct v4l2_tuner *tuner)
 {
-	struct si470x_device *radio = video_get_drvdata(video_devdata(file));
+	struct si470x_device *radio = video_drvdata(file);
 	int retval = 0;
 
 	/* safety checks */
@@ -1471,7 +1473,7 @@
 static int si470x_vidioc_s_tuner(struct file *file, void *priv,
 		struct v4l2_tuner *tuner)
 {
-	struct si470x_device *radio = video_get_drvdata(video_devdata(file));
+	struct si470x_device *radio = video_drvdata(file);
 	int retval = 0;
 
 	/* safety checks */
@@ -1505,7 +1507,7 @@
 static int si470x_vidioc_g_frequency(struct file *file, void *priv,
 		struct v4l2_frequency *freq)
 {
-	struct si470x_device *radio = video_get_drvdata(video_devdata(file));
+	struct si470x_device *radio = video_drvdata(file);
 	int retval = 0;
 
 	/* safety checks */
@@ -1534,7 +1536,7 @@
 static int si470x_vidioc_s_frequency(struct file *file, void *priv,
 		struct v4l2_frequency *freq)
 {
-	struct si470x_device *radio = video_get_drvdata(video_devdata(file));
+	struct si470x_device *radio = video_drvdata(file);
 	int retval = 0;
 
 	/* safety checks */
@@ -1563,7 +1565,7 @@
 static int si470x_vidioc_s_hw_freq_seek(struct file *file, void *priv,
 		struct v4l2_hw_freq_seek *seek)
 {
-	struct si470x_device *radio = video_get_drvdata(video_devdata(file));
+	struct si470x_device *radio = video_drvdata(file);
 	int retval = 0;
 
 	/* safety checks */
diff --git a/drivers/media/radio/radio-terratec.c b/drivers/media/radio/radio-terratec.c
index 0876fec..0abb186 100644
--- a/drivers/media/radio/radio-terratec.c
+++ b/drivers/media/radio/radio-terratec.c
@@ -79,6 +79,7 @@
 
 struct tt_device
 {
+	unsigned long in_use;
 	int port;
 	int curvol;
 	unsigned long curfreq;
@@ -220,8 +221,7 @@
 static int vidioc_g_tuner(struct file *file, void *priv,
 					struct v4l2_tuner *v)
 {
-	struct video_device *dev = video_devdata(file);
-	struct tt_device *tt = dev->priv;
+	struct tt_device *tt = video_drvdata(file);
 
 	if (v->index > 0)
 		return -EINVAL;
@@ -248,8 +248,7 @@
 static int vidioc_s_frequency(struct file *file, void *priv,
 					struct v4l2_frequency *f)
 {
-	struct video_device *dev = video_devdata(file);
-	struct tt_device *tt = dev->priv;
+	struct tt_device *tt = video_drvdata(file);
 
 	tt->curfreq = f->frequency;
 	tt_setfreq(tt, tt->curfreq);
@@ -259,8 +258,7 @@
 static int vidioc_g_frequency(struct file *file, void *priv,
 					struct v4l2_frequency *f)
 {
-	struct video_device *dev = video_devdata(file);
-	struct tt_device *tt = dev->priv;
+	struct tt_device *tt = video_drvdata(file);
 
 	f->type = V4L2_TUNER_RADIO;
 	f->frequency = tt->curfreq;
@@ -285,8 +283,7 @@
 static int vidioc_g_ctrl(struct file *file, void *priv,
 					struct v4l2_control *ctrl)
 {
-	struct video_device *dev = video_devdata(file);
-	struct tt_device *tt = dev->priv;
+	struct tt_device *tt = video_drvdata(file);
 
 	switch (ctrl->id) {
 	case V4L2_CID_AUDIO_MUTE:
@@ -305,8 +302,7 @@
 static int vidioc_s_ctrl(struct file *file, void *priv,
 					struct v4l2_control *ctrl)
 {
-	struct video_device *dev = video_devdata(file);
-	struct tt_device *tt = dev->priv;
+	struct tt_device *tt = video_drvdata(file);
 
 	switch (ctrl->id) {
 	case V4L2_CID_AUDIO_MUTE:
@@ -356,10 +352,21 @@
 
 static struct tt_device terratec_unit;
 
+static int terratec_exclusive_open(struct inode *inode, struct file *file)
+{
+	return test_and_set_bit(0, &terratec_unit.in_use) ? -EBUSY : 0;
+}
+
+static int terratec_exclusive_release(struct inode *inode, struct file *file)
+{
+	clear_bit(0, &terratec_unit.in_use);
+	return 0;
+}
+
 static const struct file_operations terratec_fops = {
 	.owner		= THIS_MODULE,
-	.open           = video_exclusive_open,
-	.release        = video_exclusive_release,
+	.open           = terratec_exclusive_open,
+	.release        = terratec_exclusive_release,
 	.ioctl		= video_ioctl2,
 #ifdef CONFIG_COMPAT
 	.compat_ioctl	= v4l_compat_ioctl32,
@@ -386,6 +393,7 @@
 	.name		= "TerraTec ActiveRadio",
 	.fops           = &terratec_fops,
 	.ioctl_ops 	= &terratec_ioctl_ops,
+	.release	= video_device_release_empty,
 };
 
 static int __init terratec_init(void)
@@ -401,7 +409,7 @@
 		return -EBUSY;
 	}
 
-	terratec_radio.priv=&terratec_unit;
+	video_set_drvdata(&terratec_radio, &terratec_unit);
 
 	spin_lock_init(&lock);
 
diff --git a/drivers/media/radio/radio-trust.c b/drivers/media/radio/radio-trust.c
index 1931619..e7b111f 100644
--- a/drivers/media/radio/radio-trust.c
+++ b/drivers/media/radio/radio-trust.c
@@ -78,6 +78,7 @@
 static unsigned long curfreq;
 static int curstereo;
 static int curmute;
+static unsigned long in_use;
 
 /* i2c addresses */
 #define TDA7318_ADDR 0x88
@@ -336,10 +337,21 @@
 	return 0;
 }
 
+static int trust_exclusive_open(struct inode *inode, struct file *file)
+{
+	return test_and_set_bit(0, &in_use) ? -EBUSY : 0;
+}
+
+static int trust_exclusive_release(struct inode *inode, struct file *file)
+{
+	clear_bit(0, &in_use);
+	return 0;
+}
+
 static const struct file_operations trust_fops = {
 	.owner		= THIS_MODULE,
-	.open           = video_exclusive_open,
-	.release        = video_exclusive_release,
+	.open           = trust_exclusive_open,
+	.release        = trust_exclusive_release,
 	.ioctl		= video_ioctl2,
 #ifdef CONFIG_COMPAT
 	.compat_ioctl	= v4l_compat_ioctl32,
@@ -366,6 +378,7 @@
 	.name		= "Trust FM Radio",
 	.fops           = &trust_fops,
 	.ioctl_ops 	= &trust_ioctl_ops,
+	.release	= video_device_release_empty,
 };
 
 static int __init trust_init(void)
diff --git a/drivers/media/radio/radio-typhoon.c b/drivers/media/radio/radio-typhoon.c
index f8d62cf..952ec35 100644
--- a/drivers/media/radio/radio-typhoon.c
+++ b/drivers/media/radio/radio-typhoon.c
@@ -79,7 +79,7 @@
 #endif
 
 struct typhoon_device {
-	int users;
+	unsigned long in_use;
 	int iobase;
 	int curvol;
 	int muted;
@@ -223,8 +223,7 @@
 static int vidioc_s_frequency(struct file *file, void *priv,
 					struct v4l2_frequency *f)
 {
-	struct video_device *dev = video_devdata(file);
-	struct typhoon_device *typhoon = dev->priv;
+	struct typhoon_device *typhoon = video_drvdata(file);
 
 	typhoon->curfreq = f->frequency;
 	typhoon_setfreq(typhoon, typhoon->curfreq);
@@ -234,8 +233,7 @@
 static int vidioc_g_frequency(struct file *file, void *priv,
 					struct v4l2_frequency *f)
 {
-	struct video_device *dev = video_devdata(file);
-	struct typhoon_device *typhoon = dev->priv;
+	struct typhoon_device *typhoon = video_drvdata(file);
 
 	f->type = V4L2_TUNER_RADIO;
 	f->frequency = typhoon->curfreq;
@@ -261,8 +259,7 @@
 static int vidioc_g_ctrl(struct file *file, void *priv,
 					struct v4l2_control *ctrl)
 {
-	struct video_device *dev = video_devdata(file);
-	struct typhoon_device *typhoon = dev->priv;
+	struct typhoon_device *typhoon = video_drvdata(file);
 
 	switch (ctrl->id) {
 	case V4L2_CID_AUDIO_MUTE:
@@ -278,8 +275,7 @@
 static int vidioc_s_ctrl (struct file *file, void *priv,
 					struct v4l2_control *ctrl)
 {
-	struct video_device *dev = video_devdata(file);
-	struct typhoon_device *typhoon = dev->priv;
+	struct typhoon_device *typhoon = video_drvdata(file);
 
 	switch (ctrl->id) {
 	case V4L2_CID_AUDIO_MUTE:
@@ -334,10 +330,21 @@
 	.mutefreq	= CONFIG_RADIO_TYPHOON_MUTEFREQ,
 };
 
+static int typhoon_exclusive_open(struct inode *inode, struct file *file)
+{
+	return test_and_set_bit(0, &typhoon_unit.in_use) ? -EBUSY : 0;
+}
+
+static int typhoon_exclusive_release(struct inode *inode, struct file *file)
+{
+	clear_bit(0, &typhoon_unit.in_use);
+	return 0;
+}
+
 static const struct file_operations typhoon_fops = {
 	.owner		= THIS_MODULE,
-	.open           = video_exclusive_open,
-	.release        = video_exclusive_release,
+	.open           = typhoon_exclusive_open,
+	.release        = typhoon_exclusive_release,
 	.ioctl		= video_ioctl2,
 #ifdef CONFIG_COMPAT
 	.compat_ioctl	= v4l_compat_ioctl32,
@@ -364,6 +371,7 @@
 	.name		= "Typhoon Radio",
 	.fops           = &typhoon_fops,
 	.ioctl_ops 	= &typhoon_ioctl_ops,
+	.release	= video_device_release_empty,
 };
 
 #ifdef CONFIG_RADIO_TYPHOON_PROC_FS
@@ -446,9 +454,8 @@
 		return -EBUSY;
 	}
 
-	typhoon_radio.priv = &typhoon_unit;
-	if (video_register_device(&typhoon_radio, VFL_TYPE_RADIO, radio_nr) == -1)
-	{
+	video_set_drvdata(&typhoon_radio, &typhoon_unit);
+	if (video_register_device(&typhoon_radio, VFL_TYPE_RADIO, radio_nr) < 0) {
 		release_region(io, 8);
 		return -EINVAL;
 	}
diff --git a/drivers/media/radio/radio-zoltrix.c b/drivers/media/radio/radio-zoltrix.c
index 51d57ed..15b10ba 100644
--- a/drivers/media/radio/radio-zoltrix.c
+++ b/drivers/media/radio/radio-zoltrix.c
@@ -69,6 +69,7 @@
 static int radio_nr = -1;
 
 struct zol_device {
+	unsigned long in_use;
 	int port;
 	int curvol;
 	unsigned long curfreq;
@@ -122,8 +123,11 @@
 	unsigned int stereo = dev->stereo;
 	int i;
 
-	if (freq == 0)
-		return 1;
+	if (freq == 0) {
+		printk(KERN_WARNING "zoltrix: received zero freq. Failed to set.\n");
+		return -EINVAL;
+	}
+
 	m = (freq / 160 - 8800) * 2;
 	f = (unsigned long long) m + 0x4d1c;
 
@@ -245,8 +249,7 @@
 static int vidioc_g_tuner(struct file *file, void *priv,
 					struct v4l2_tuner *v)
 {
-	struct video_device *dev = video_devdata(file);
-	struct zol_device *zol = dev->priv;
+	struct zol_device *zol = video_drvdata(file);
 
 	if (v->index > 0)
 		return -EINVAL;
@@ -276,19 +279,20 @@
 static int vidioc_s_frequency(struct file *file, void *priv,
 					struct v4l2_frequency *f)
 {
-	struct video_device *dev = video_devdata(file);
-	struct zol_device *zol = dev->priv;
+	struct zol_device *zol = video_drvdata(file);
 
 	zol->curfreq = f->frequency;
-	zol_setfreq(zol, zol->curfreq);
+	if (zol_setfreq(zol, zol->curfreq) != 0) {
+		printk(KERN_WARNING "zoltrix: Set frequency failed.\n");
+		return -EINVAL;
+	}
 	return 0;
 }
 
 static int vidioc_g_frequency(struct file *file, void *priv,
 					struct v4l2_frequency *f)
 {
-	struct video_device *dev = video_devdata(file);
-	struct zol_device *zol = dev->priv;
+	struct zol_device *zol = video_drvdata(file);
 
 	f->type = V4L2_TUNER_RADIO;
 	f->frequency = zol->curfreq;
@@ -313,8 +317,7 @@
 static int vidioc_g_ctrl(struct file *file, void *priv,
 				struct v4l2_control *ctrl)
 {
-	struct video_device *dev = video_devdata(file);
-	struct zol_device *zol = dev->priv;
+	struct zol_device *zol = video_drvdata(file);
 
 	switch (ctrl->id) {
 	case V4L2_CID_AUDIO_MUTE:
@@ -330,8 +333,7 @@
 static int vidioc_s_ctrl(struct file *file, void *priv,
 				struct v4l2_control *ctrl)
 {
-	struct video_device *dev = video_devdata(file);
-	struct zol_device *zol = dev->priv;
+	struct zol_device *zol = video_drvdata(file);
 
 	switch (ctrl->id) {
 	case V4L2_CID_AUDIO_MUTE:
@@ -347,7 +349,10 @@
 		return 0;
 	}
 	zol->stereo = 1;
-	zol_setfreq(zol, zol->curfreq);
+	if (zol_setfreq(zol, zol->curfreq) != 0) {
+		printk(KERN_WARNING "zoltrix: Set frequency failed.\n");
+		return -EINVAL;
+	}
 #if 0
 /* FIXME: Implement stereo/mono switch on V4L2 */
 			if (v->mode & VIDEO_SOUND_STEREO) {
@@ -396,11 +401,22 @@
 
 static struct zol_device zoltrix_unit;
 
+static int zoltrix_exclusive_open(struct inode *inode, struct file *file)
+{
+	return test_and_set_bit(0, &zoltrix_unit.in_use) ? -EBUSY : 0;
+}
+
+static int zoltrix_exclusive_release(struct inode *inode, struct file *file)
+{
+	clear_bit(0, &zoltrix_unit.in_use);
+	return 0;
+}
+
 static const struct file_operations zoltrix_fops =
 {
 	.owner		= THIS_MODULE,
-	.open           = video_exclusive_open,
-	.release        = video_exclusive_release,
+	.open           = zoltrix_exclusive_open,
+	.release        = zoltrix_exclusive_release,
 	.ioctl		= video_ioctl2,
 #ifdef CONFIG_COMPAT
 	.compat_ioctl	= v4l_compat_ioctl32,
@@ -427,6 +443,7 @@
 	.name		= "Zoltrix Radio Plus",
 	.fops           = &zoltrix_fops,
 	.ioctl_ops 	= &zoltrix_ioctl_ops,
+	.release	= video_device_release_empty,
 };
 
 static int __init zoltrix_init(void)
@@ -440,7 +457,7 @@
 		return -ENXIO;
 	}
 
-	zoltrix_radio.priv = &zoltrix_unit;
+	video_set_drvdata(&zoltrix_radio, &zoltrix_unit);
 	if (!request_region(io, 2, "zoltrix")) {
 		printk(KERN_ERR "zoltrix: port 0x%x already in use\n", io);
 		return -EBUSY;
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
index 3e9e0dc..47102c2 100644
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -34,6 +34,7 @@
 	select VIDEOBUF_GEN
 
 config VIDEO_BTCX
+	depends on PCI
 	tristate
 
 config VIDEO_IR
@@ -71,6 +72,15 @@
 	  V4L devices.
 	  In doubt, say N.
 
+config VIDEO_FIXED_MINOR_RANGES
+	bool "Enable old-style fixed minor ranges for video devices"
+	default n
+	---help---
+	  Say Y here to enable the old-style fixed-range minor assignments.
+	  Only useful if you rely on the old behavior and use mknod instead of udev.
+
+	  When in doubt, say N.
+
 config VIDEO_HELPER_CHIPS_AUTO
 	bool "Autoselect pertinent encoders/decoders and other helper chips"
 	default y
@@ -578,13 +588,6 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called saa5249.
 
-config TUNER_3036
-	tristate "SAB3036 tuner"
-	depends on I2C && VIDEO_V4L1
-	help
-	  Say Y here to include support for Philips SAB3036 compatible tuners.
-	  If in doubt, say N.
-
 config VIDEO_VINO
 	tristate "SGI Vino Video For Linux (EXPERIMENTAL)"
 	depends on I2C && SGI_IP22 && EXPERIMENTAL && VIDEO_V4L2
@@ -602,79 +605,7 @@
 	  driver for PCI.  There is a product page at
 	  <http://www.stradis.com/>.
 
-config VIDEO_ZORAN
-	tristate "Zoran ZR36057/36067 Video For Linux"
-	depends on PCI && I2C_ALGOBIT && VIDEO_V4L1 && VIRT_TO_BUS
-	help
-	  Say Y for support for MJPEG capture cards based on the Zoran
-	  36057/36067 PCI controller chipset. This includes the Iomega
-	  Buz, Pinnacle DC10+ and the Linux Media Labs LML33. There is
-	  a driver homepage at <http://mjpeg.sf.net/driver-zoran/>. For
-	  more information, check <file:Documentation/video4linux/Zoran>.
-
-	  To compile this driver as a module, choose M here: the
-	  module will be called zr36067.
-
-config VIDEO_ZORAN_DC30
-	tristate "Pinnacle/Miro DC30(+) support"
-	depends on VIDEO_ZORAN
-	select VIDEO_ADV7175 if VIDEO_HELPER_CHIPS_AUTO
-	select VIDEO_VPX3220 if VIDEO_HELPER_CHIPS_AUTO
-	help
-	  Support for the Pinnacle/Miro DC30(+) MJPEG capture/playback
-	  card. This also supports really old DC10 cards based on the
-	  zr36050 MJPEG codec and zr36016 VFE.
-
-config VIDEO_ZORAN_ZR36060
-	tristate "Zoran ZR36060"
-	depends on VIDEO_ZORAN
-	help
-	  Say Y to support Zoran boards based on 36060 chips.
-	  This includes Iomega Buz, Pinnacle DC10, Linux media Labs 33
-	  and 33 R10 and AverMedia 6 boards.
-
-config VIDEO_ZORAN_BUZ
-	tristate "Iomega Buz support"
-	depends on VIDEO_ZORAN_ZR36060
-	select VIDEO_SAA7111 if VIDEO_HELPER_CHIPS_AUTO
-	select VIDEO_SAA7185 if VIDEO_HELPER_CHIPS_AUTO
-	help
-	  Support for the Iomega Buz MJPEG capture/playback card.
-
-config VIDEO_ZORAN_DC10
-	tristate "Pinnacle/Miro DC10(+) support"
-	depends on VIDEO_ZORAN_ZR36060
-	select VIDEO_SAA7110 if VIDEO_HELPER_CHIPS_AUTO
-	select VIDEO_ADV7175 if VIDEO_HELPER_CHIPS_AUTO
-	help
-	  Support for the Pinnacle/Miro DC10(+) MJPEG capture/playback
-	  card.
-
-config VIDEO_ZORAN_LML33
-	tristate "Linux Media Labs LML33 support"
-	depends on VIDEO_ZORAN_ZR36060
-	select VIDEO_BT819 if VIDEO_HELPER_CHIPS_AUTO
-	select VIDEO_BT856 if VIDEO_HELPER_CHIPS_AUTO
-	help
-	  Support for the Linux Media Labs LML33 MJPEG capture/playback
-	  card.
-
-config VIDEO_ZORAN_LML33R10
-	tristate "Linux Media Labs LML33R10 support"
-	depends on VIDEO_ZORAN_ZR36060
-	select VIDEO_SAA7114 if VIDEO_HELPER_CHIPS_AUTO
-	select VIDEO_ADV7170 if VIDEO_HELPER_CHIPS_AUTO
-	help
-	  support for the Linux Media Labs LML33R10 MJPEG capture/playback
-	  card.
-
-config VIDEO_ZORAN_AVS6EYES
-	tristate "AverMedia 6 Eyes support (EXPERIMENTAL)"
-	depends on VIDEO_ZORAN_ZR36060 && EXPERIMENTAL && VIDEO_V4L1
-	select VIDEO_BT856 if VIDEO_HELPER_CHIPS_AUTO
-	select VIDEO_KS0127 if VIDEO_HELPER_CHIPS_AUTO
-	help
-	  Support for the AverMedia 6 Eyes video surveillance card.
+source "drivers/media/video/zoran/Kconfig"
 
 config VIDEO_MEYE
 	tristate "Sony Vaio Picturebook Motion Eye Video For Linux"
@@ -697,7 +628,7 @@
 	depends on PCI && VIDEO_V4L1 && I2C
 	select VIDEO_SAA7146_VV
 	select VIDEO_TUNER
-	select VIDEO_SAA7111 if VIDEO_HELPER_CHIPS_AUTO
+	select VIDEO_SAA7115 if VIDEO_HELPER_CHIPS_AUTO
 	select VIDEO_TDA9840 if VIDEO_HELPER_CHIPS_AUTO
 	select VIDEO_TEA6415C if VIDEO_HELPER_CHIPS_AUTO
 	select VIDEO_TEA6420 if VIDEO_HELPER_CHIPS_AUTO
@@ -708,21 +639,6 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called mxb.
 
-config VIDEO_DPC
-	tristate "Philips-Semiconductors 'dpc7146 demonstration board'"
-	depends on PCI && VIDEO_V4L1 && I2C
-	select VIDEO_SAA7146_VV
-	select VIDEO_SAA7111 if VIDEO_HELPER_CHIPS_AUTO
-	---help---
-	  This is a video4linux driver for the 'dpc7146 demonstration
-	  board' by Philips-Semiconductors. It's the reference design
-	  for SAA7146 bases boards, so if you have some unsupported
-	  saa7146 based, analog video card, chances are good that it
-	  will work with this skeleton driver.
-
-	  To compile this driver as a module, choose M here: the
-	  module will be called dpc7146.
-
 config VIDEO_HEXIUM_ORION
 	tristate "Hexium HV-PCI6 and Orion frame grabber"
 	depends on PCI && VIDEO_V4L2 && I2C
@@ -784,6 +700,70 @@
 	  CMOS camera controller.  This is the controller found on first-
 	  generation OLPC systems.
 
+config SOC_CAMERA
+	tristate "SoC camera support"
+	depends on VIDEO_V4L2 && HAS_DMA
+	select VIDEOBUF_GEN
+	help
+	  SoC Camera is a common API to several cameras, not connecting
+	  over a bus like PCI or USB. For example some i2c camera connected
+	  directly to the data bus of an SoC.
+
+config SOC_CAMERA_MT9M001
+	tristate "mt9m001 support"
+	depends on SOC_CAMERA && I2C
+	select GPIO_PCA953X if MT9M001_PCA9536_SWITCH
+	help
+	  This driver supports MT9M001 cameras from Micron, monochrome
+	  and colour models.
+
+config MT9M001_PCA9536_SWITCH
+	bool "pca9536 datawidth switch for mt9m001"
+	depends on SOC_CAMERA_MT9M001 && GENERIC_GPIO
+	help
+	  Select this if your MT9M001 camera uses a PCA9536 I2C GPIO
+	  extender to switch between 8 and 10 bit datawidth modes
+
+config SOC_CAMERA_MT9M111
+	tristate "mt9m111 support"
+	depends on SOC_CAMERA && I2C
+	help
+	  This driver supports MT9M111 cameras from Micron
+
+config SOC_CAMERA_MT9V022
+	tristate "mt9v022 support"
+	depends on SOC_CAMERA && I2C
+	select GPIO_PCA953X if MT9V022_PCA9536_SWITCH
+	help
+	  This driver supports MT9V022 cameras from Micron
+
+config MT9V022_PCA9536_SWITCH
+	bool "pca9536 datawidth switch for mt9v022"
+	depends on SOC_CAMERA_MT9V022 && GENERIC_GPIO
+	help
+	  Select this if your MT9V022 camera uses a PCA9536 I2C GPIO
+	  extender to switch between 8 and 10 bit datawidth modes
+
+config SOC_CAMERA_PLATFORM
+	tristate "platform camera support"
+	depends on SOC_CAMERA
+	help
+	  This is a generic SoC camera platform driver, useful for testing
+
+config VIDEO_PXA27x
+	tristate "PXA27x Quick Capture Interface driver"
+	depends on VIDEO_DEV && PXA27x && SOC_CAMERA
+	select VIDEOBUF_DMA_SG
+	---help---
+	  This is a v4l2 driver for the PXA27x Quick Capture Interface
+
+config VIDEO_SH_MOBILE_CEU
+	tristate "SuperH Mobile CEU Interface driver"
+	depends on VIDEO_DEV && SOC_CAMERA && HAS_DMA
+	select VIDEOBUF_DMA_CONTIG
+	---help---
+	  This is a v4l2 driver for the SuperH Mobile CEU Interface
+
 #
 # USB Multimedia device configuration
 #
@@ -822,8 +802,7 @@
 
 config USB_W9968CF
 	tristate "USB W996[87]CF JPEG Dual Mode Camera support"
-	depends on VIDEO_V4L1 && I2C
-	select VIDEO_OVCAMCHIP
+	depends on VIDEO_V4L1 && I2C && VIDEO_OVCAMCHIP
 	---help---
 	  Say Y here if you want support for cameras based on OV681 or
 	  Winbond W9967CF/W9968CF JPEG USB Dual Mode Camera Chips.
@@ -914,64 +893,4 @@
 
 endif # V4L_USB_DRIVERS
 
-config SOC_CAMERA
-	tristate "SoC camera support"
-	depends on VIDEO_V4L2 && HAS_DMA
-	select VIDEOBUF_GEN
-	help
-	  SoC Camera is a common API to several cameras, not connecting
-	  over a bus like PCI or USB. For example some i2c camera connected
-	  directly to the data bus of an SoC.
-
-config SOC_CAMERA_MT9M001
-	tristate "mt9m001 support"
-	depends on SOC_CAMERA && I2C
-	select GPIO_PCA953X if MT9M001_PCA9536_SWITCH
-	help
-	  This driver supports MT9M001 cameras from Micron, monochrome
-	  and colour models.
-
-config MT9M001_PCA9536_SWITCH
-	bool "pca9536 datawidth switch for mt9m001"
-	depends on SOC_CAMERA_MT9M001 && GENERIC_GPIO
-	help
-	  Select this if your MT9M001 camera uses a PCA9536 I2C GPIO
-	  extender to switch between 8 and 10 bit datawidth modes
-
-config SOC_CAMERA_MT9V022
-	tristate "mt9v022 support"
-	depends on SOC_CAMERA && I2C
-	select GPIO_PCA953X if MT9V022_PCA9536_SWITCH
-	help
-	  This driver supports MT9V022 cameras from Micron
-
-config MT9V022_PCA9536_SWITCH
-	bool "pca9536 datawidth switch for mt9v022"
-	depends on SOC_CAMERA_MT9V022 && GENERIC_GPIO
-	help
-	  Select this if your MT9V022 camera uses a PCA9536 I2C GPIO
-	  extender to switch between 8 and 10 bit datawidth modes
-
-config SOC_CAMERA_PLATFORM
-	tristate "platform camera support"
-	depends on SOC_CAMERA
-	help
-	  This is a generic SoC camera platform driver, useful for testing
-
-config VIDEO_PXA27x
-	tristate "PXA27x Quick Capture Interface driver"
-	depends on VIDEO_DEV && PXA27x
-	select SOC_CAMERA
-	select VIDEOBUF_DMA_SG
-	---help---
-	  This is a v4l2 driver for the PXA27x Quick Capture Interface
-
-config VIDEO_SH_MOBILE_CEU
-	tristate "SuperH Mobile CEU Interface driver"
-	depends on VIDEO_DEV && HAS_DMA
-	select SOC_CAMERA
-	select VIDEOBUF_DMA_CONTIG
-	---help---
-	  This is a v4l2 driver for the SuperH Mobile CEU Interface
-
 endif # VIDEO_CAPTURE_DRIVERS
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
index ef7c8d3..16962f3 100644
--- a/drivers/media/video/Makefile
+++ b/drivers/media/video/Makefile
@@ -2,8 +2,6 @@
 # Makefile for the video capture/playback device drivers.
 #
 
-zr36067-objs	:=	zoran_procfs.o zoran_device.o \
-			zoran_driver.o zoran_card.o
 tuner-objs	:=	tuner-core.o
 
 msp3400-objs	:=	msp3400-driver.o msp3400-kthreads.o
@@ -54,9 +52,7 @@
 obj-$(CONFIG_VIDEO_BT866) += bt866.o
 obj-$(CONFIG_VIDEO_KS0127) += ks0127.o
 
-obj-$(CONFIG_VIDEO_ZORAN) += zr36067.o videocodec.o
-obj-$(CONFIG_VIDEO_ZORAN_DC30) += zr36050.o zr36016.o
-obj-$(CONFIG_VIDEO_ZORAN_ZR36060) += zr36060.o
+obj-$(CONFIG_VIDEO_ZORAN) += zoran/
 
 obj-$(CONFIG_VIDEO_PMS) += pms.o
 obj-$(CONFIG_VIDEO_VINO) += vino.o indycam.o
@@ -84,8 +80,6 @@
 obj-$(CONFIG_VIDEO_MXB) += mxb.o
 obj-$(CONFIG_VIDEO_HEXIUM_ORION) += hexium_orion.o
 obj-$(CONFIG_VIDEO_HEXIUM_GEMINI) += hexium_gemini.o
-obj-$(CONFIG_VIDEO_DPC) += dpc7146.o
-obj-$(CONFIG_TUNER_3036) += tuner-3036.o
 
 obj-$(CONFIG_VIDEOBUF_GEN) += videobuf-core.o
 obj-$(CONFIG_VIDEOBUF_DMA_SG) += videobuf-dma-sg.o
@@ -137,6 +131,7 @@
 obj-$(CONFIG_VIDEO_SH_MOBILE_CEU)	+= sh_mobile_ceu_camera.o
 obj-$(CONFIG_SOC_CAMERA)	+= soc_camera.o
 obj-$(CONFIG_SOC_CAMERA_MT9M001)	+= mt9m001.o
+obj-$(CONFIG_SOC_CAMERA_MT9M111)	+= mt9m111.o
 obj-$(CONFIG_SOC_CAMERA_MT9V022)	+= mt9v022.o
 obj-$(CONFIG_SOC_CAMERA_PLATFORM)	+= soc_camera_platform.o
 
diff --git a/drivers/media/video/arv.c b/drivers/media/video/arv.c
index 9e436ad..218754b 100644
--- a/drivers/media/video/arv.c
+++ b/drivers/media/video/arv.c
@@ -116,6 +116,7 @@
 	int width, height;
 	int frame_bytes, line_bytes;
 	wait_queue_head_t wait;
+	unsigned long in_use;
 	struct mutex lock;
 };
 
@@ -269,7 +270,7 @@
 static ssize_t ar_read(struct file *file, char *buf, size_t count, loff_t *ppos)
 {
 	struct video_device *v = video_devdata(file);
-	struct ar_device *ar = v->priv;
+	struct ar_device *ar = video_get_drvdata(v);
 	long ret = ar->frame_bytes;		/* return read bytes */
 	unsigned long arvcr1 = 0;
 	unsigned long flags;
@@ -399,7 +400,7 @@
 		       unsigned int cmd, void *arg)
 {
 	struct video_device *dev = video_devdata(file);
-	struct ar_device *ar = dev->priv;
+	struct ar_device *ar = video_get_drvdata(dev);
 
 	DEBUG(1, "ar_ioctl()\n");
 	switch(cmd) {
@@ -625,7 +626,7 @@
  */
 static int ar_initialize(struct video_device *dev)
 {
-	struct ar_device *ar = dev->priv;
+	struct ar_device *ar = video_get_drvdata(dev);
 	unsigned long cr = 0;
 	int i,found=0;
 
@@ -732,7 +733,7 @@
 
 void ar_release(struct video_device *vfd)
 {
-	struct ar_device *ar = vfd->priv;
+	struct ar_device *ar = video_get_drvdata(vfd);
 	mutex_lock(&ar->lock);
 	video_device_release(vfd);
 }
@@ -742,10 +743,23 @@
  * Video4Linux Module functions
  *
  ****************************************************************************/
+static struct ar_device ardev;
+
+static int ar_exclusive_open(struct inode *inode, struct file *file)
+{
+	return test_and_set_bit(0, &ardev.in_use) ? -EBUSY : 0;
+}
+
+static int ar_exclusive_release(struct inode *inode, struct file *file)
+{
+	clear_bit(0, &ardev.in_use);
+	return 0;
+}
+
 static const struct file_operations ar_fops = {
 	.owner		= THIS_MODULE,
-	.open		= video_exclusive_open,
-	.release	= video_exclusive_release,
+	.open		= ar_exclusive_open,
+	.release	= ar_exclusive_release,
 	.read		= ar_read,
 	.ioctl		= ar_ioctl,
 #ifdef CONFIG_COMPAT
@@ -762,7 +776,6 @@
 };
 
 #define ALIGN4(x)	((((int)(x)) & 0x3) == 0)
-static struct ar_device ardev;
 
 static int __init ar_init(void)
 {
@@ -802,7 +815,7 @@
 		return -ENOMEM;
 	}
 	memcpy(ar->vdev, &ar_template, sizeof(ar_template));
-	ar->vdev->priv = ar;
+	video_set_drvdata(ar->vdev, ar);
 
 	if (vga) {
 		ar->width 	= AR_WIDTH_VGA;
diff --git a/drivers/media/video/au0828/au0828-cards.c b/drivers/media/video/au0828/au0828-cards.c
index ed48908..5f07a8a 100644
--- a/drivers/media/video/au0828/au0828-cards.c
+++ b/drivers/media/video/au0828/au0828-cards.c
@@ -46,7 +46,7 @@
 /* Tuner callback function for au0828 boards. Currently only needed
  * for HVR1500Q, which has an xc5000 tuner.
  */
-int au0828_tuner_callback(void *priv, int command, int arg)
+int au0828_tuner_callback(void *priv, int component, int command, int arg)
 {
 	struct au0828_dev *dev = priv;
 
diff --git a/drivers/media/video/au0828/au0828-dvb.c b/drivers/media/video/au0828/au0828-dvb.c
index ba94be7..f0fcdb4 100644
--- a/drivers/media/video/au0828/au0828-dvb.c
+++ b/drivers/media/video/au0828/au0828-dvb.c
@@ -36,11 +36,39 @@
 #define _AU0828_BULKPIPE 0x83
 #define _BULKPIPESIZE 0xe522
 
+static u8 hauppauge_hvr950q_led_states[] = {
+	0x00, /* off */
+	0x02, /* yellow */
+	0x04, /* green */
+};
+
+static struct au8522_led_config hauppauge_hvr950q_led_cfg = {
+	.gpio_output = 0x00e0,
+	.gpio_output_enable  = 0x6006,
+	.gpio_output_disable = 0x0660,
+
+	.gpio_leds = 0x00e2,
+	.led_states  = hauppauge_hvr950q_led_states,
+	.num_led_states = sizeof(hauppauge_hvr950q_led_states),
+
+	.vsb8_strong   = 20 /* dB */ * 10,
+	.qam64_strong  = 25 /* dB */ * 10,
+	.qam256_strong = 32 /* dB */ * 10,
+};
+
 static struct au8522_config hauppauge_hvr950q_config = {
 	.demod_address = 0x8e >> 1,
 	.status_mode   = AU8522_DEMODLOCKING,
 	.qam_if        = AU8522_IF_6MHZ,
 	.vsb_if        = AU8522_IF_6MHZ,
+	.led_cfg       = &hauppauge_hvr950q_led_cfg,
+};
+
+static struct au8522_config fusionhdtv7usb_config = {
+	.demod_address = 0x8e >> 1,
+	.status_mode   = AU8522_DEMODLOCKING,
+	.qam_if        = AU8522_IF_6MHZ,
+	.vsb_if        = AU8522_IF_6MHZ,
 };
 
 static struct au8522_config hauppauge_woodbury_config = {
@@ -53,7 +81,6 @@
 static struct xc5000_config hauppauge_hvr950q_tunerconfig = {
 	.i2c_address      = 0x61,
 	.if_khz           = 6000,
-	.tuner_callback   = au0828_tuner_callback
 };
 
 static struct mxl5007t_config mxl5007t_hvr950q_config = {
@@ -353,14 +380,12 @@
 	switch (dev->board) {
 	case AU0828_BOARD_HAUPPAUGE_HVR850:
 	case AU0828_BOARD_HAUPPAUGE_HVR950Q:
-	case AU0828_BOARD_DVICO_FUSIONHDTV7:
 		dvb->frontend = dvb_attach(au8522_attach,
 				&hauppauge_hvr950q_config,
 				&dev->i2c_adap);
 		if (dvb->frontend != NULL)
-			dvb_attach(xc5000_attach, dvb->frontend,
-				&dev->i2c_adap,
-				&hauppauge_hvr950q_tunerconfig, dev);
+			dvb_attach(xc5000_attach, dvb->frontend, &dev->i2c_adap,
+				   &hauppauge_hvr950q_tunerconfig);
 		break;
 	case AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL:
 		dvb->frontend = dvb_attach(au8522_attach,
@@ -380,6 +405,16 @@
 				   0x60, &dev->i2c_adap,
 				   &hauppauge_woodbury_tunerconfig);
 		break;
+	case AU0828_BOARD_DVICO_FUSIONHDTV7:
+		dvb->frontend = dvb_attach(au8522_attach,
+				&fusionhdtv7usb_config,
+				&dev->i2c_adap);
+		if (dvb->frontend != NULL) {
+			dvb_attach(xc5000_attach, dvb->frontend,
+				&dev->i2c_adap,
+				&hauppauge_hvr950q_tunerconfig);
+		}
+		break;
 	default:
 		printk(KERN_WARNING "The frontend of your DVB/ATSC card "
 		       "isn't supported yet\n");
@@ -390,6 +425,8 @@
 		       __func__);
 		return -1;
 	}
+	/* define general-purpose callback pointer */
+	dvb->frontend->callback = au0828_tuner_callback;
 
 	/* register everything */
 	ret = dvb_register(dev);
diff --git a/drivers/media/video/au0828/au0828.h b/drivers/media/video/au0828/au0828.h
index 4f10ff3..9d6a116 100644
--- a/drivers/media/video/au0828/au0828.h
+++ b/drivers/media/video/au0828/au0828.h
@@ -103,7 +103,8 @@
 extern struct au0828_board au0828_boards[];
 extern struct usb_device_id au0828_usb_id_table[];
 extern void au0828_gpio_setup(struct au0828_dev *dev);
-extern int au0828_tuner_callback(void *priv, int command, int arg);
+extern int au0828_tuner_callback(void *priv, int component,
+				 int command, int arg);
 extern void au0828_card_setup(struct au0828_dev *dev);
 
 /* ----------------------------------------------------------- */
diff --git a/drivers/media/video/bt856.c b/drivers/media/video/bt856.c
index 98ee2d8..ab2ce4d 100644
--- a/drivers/media/video/bt856.c
+++ b/drivers/media/video/bt856.c
@@ -68,8 +68,8 @@
 
 /* ----------------------------------------------------------------------- */
 
-#define REG_OFFSET	0xDA
-#define BT856_NR_REG	6
+#define BT856_REG_OFFSET	0xDA
+#define BT856_NR_REG		6
 
 struct bt856 {
 	unsigned char reg[BT856_NR_REG];
@@ -89,7 +89,7 @@
 {
 	struct bt856 *encoder = i2c_get_clientdata(client);
 
-	encoder->reg[reg - REG_OFFSET] = value;
+	encoder->reg[reg - BT856_REG_OFFSET] = value;
 	return i2c_smbus_write_byte_data(client, reg, value);
 }
 
@@ -103,7 +103,7 @@
 
 	return bt856_write(client, reg,
 			   (encoder->
-			    reg[reg - REG_OFFSET] & ~(1 << bit)) |
+			    reg[reg - BT856_REG_OFFSET] & ~(1 << bit)) |
 			    (value ? (1 << bit) : 0));
 }
 
diff --git a/drivers/media/video/bt8xx/bttv-cards.c b/drivers/media/video/bt8xx/bttv-cards.c
index 6081edc..13742b0 100644
--- a/drivers/media/video/bt8xx/bttv-cards.c
+++ b/drivers/media/video/bt8xx/bttv-cards.c
@@ -305,7 +305,7 @@
 	{ 0x00261822, BTTV_BOARD_TWINHAN_DST,	"DNTV Live! Mini "},
 	{ 0xd200dbc0, BTTV_BOARD_DVICO_FUSIONHDTV_2,	"DViCO FusionHDTV 2" },
 	{ 0x763c008a, BTTV_BOARD_GEOVISION_GV600,	"GeoVision GV-600" },
-
+	{ 0x18011000, BTTV_BOARD_ENLTV_FM_2,	"Encore ENL TV-FM-2" },
 	{ 0, -1, NULL }
 };
 
@@ -3037,6 +3037,31 @@
 		.has_radio      = 1,
 		.has_remote     = 1,
 	},
+	[BTTV_BOARD_ENLTV_FM_2] = {
+		/* Encore TV Tuner Pro ENL TV-FM-2
+		   Mauro Carvalho Chehab <mchehab@infradead.org */
+		.name           = "Encore ENL TV-FM-2",
+		.video_inputs   = 3,
+		.audio_inputs   = 1,
+		.tuner          = 0,
+		.svhs           = 2,
+		/* bit 6          -> IR disabled
+		   bit 18/17 = 00 -> mute
+			       01 -> enable external audio input
+			       10 -> internal audio input (mono?)
+			       11 -> internal audio input
+		 */
+		.gpiomask       = 0x060040,
+		.muxsel         = { 2, 3, 3 },
+		.gpiomux        = { 0x60000, 0x60000, 0x20000, 0x20000 },
+		.gpiomute 	= 0,
+		.tuner_type	= TUNER_TCL_MF02GIP_5N,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.pll            = PLL_28,
+		.has_radio      = 1,
+		.has_remote     = 1,
+	}
 };
 
 static const unsigned int bttv_num_tvcards = ARRAY_SIZE(bttv_tvcards);
diff --git a/drivers/media/video/bt8xx/bttv-driver.c b/drivers/media/video/bt8xx/bttv-driver.c
index 6ae4cc8..5858bf5 100644
--- a/drivers/media/video/bt8xx/bttv-driver.c
+++ b/drivers/media/video/bt8xx/bttv-driver.c
@@ -76,9 +76,9 @@
 static unsigned int gbufsize = 0x208000;
 static unsigned int reset_crop = 1;
 
-static int video_nr = -1;
-static int radio_nr = -1;
-static int vbi_nr = -1;
+static int video_nr[BTTV_MAX] = { [0 ... (BTTV_MAX-1)] = -1 };
+static int radio_nr[BTTV_MAX] = { [0 ... (BTTV_MAX-1)] = -1 };
+static int vbi_nr[BTTV_MAX] = { [0 ... (BTTV_MAX-1)] = -1 };
 static int debug_latency;
 
 static unsigned int fdsr;
@@ -108,9 +108,6 @@
 module_param(debug_latency,     int, 0644);
 
 module_param(fdsr,              int, 0444);
-module_param(video_nr,          int, 0444);
-module_param(radio_nr,          int, 0444);
-module_param(vbi_nr,            int, 0444);
 module_param(gbuffers,          int, 0444);
 module_param(gbufsize,          int, 0444);
 module_param(reset_crop,        int, 0444);
@@ -130,7 +127,10 @@
 module_param(full_luma_range,   int, 0444);
 module_param(coring,            int, 0444);
 
-module_param_array(radio, int, NULL, 0444);
+module_param_array(radio,       int, NULL, 0444);
+module_param_array(video_nr,    int, NULL, 0444);
+module_param_array(radio_nr,    int, NULL, 0444);
+module_param_array(vbi_nr,      int, NULL, 0444);
 
 MODULE_PARM_DESC(radio,"The TV card supports radio, default is 0 (no)");
 MODULE_PARM_DESC(bigendian,"byte order of the framebuffer, default is native endian");
@@ -152,6 +152,9 @@
 MODULE_PARM_DESC(uv_ratio,"ratio between u and v gains, default is 50");
 MODULE_PARM_DESC(full_luma_range,"use the full luma range, default is 0 (no)");
 MODULE_PARM_DESC(coring,"set the luma coring level, default is 0 (no)");
+MODULE_PARM_DESC(video_nr, "video device numbers");
+MODULE_PARM_DESC(vbi_nr, "vbi device numbers");
+MODULE_PARM_DESC(radio_nr, "radio device numbers");
 
 MODULE_DESCRIPTION("bttv - v4l/v4l2 driver module for bt848/878 based cards");
 MODULE_AUTHOR("Ralph Metzler & Marcus Metzler & Gerd Knorr");
@@ -1367,7 +1370,7 @@
 			(btv->gpioirq ? BT848_INT_GPINT : 0) |
 			BT848_INT_SCERR |
 			(fdsr ? BT848_INT_FDSR : 0) |
-			BT848_INT_RISCI|BT848_INT_OCERR|BT848_INT_VPRES|
+			BT848_INT_RISCI | BT848_INT_OCERR |
 			BT848_INT_FMTCHG|BT848_INT_HLOCK|
 			BT848_INT_I2CDONE,
 			BT848_INT_MASK);
@@ -2661,18 +2664,6 @@
 	return 0;
 }
 
-static int bttv_enum_fmt_vbi_cap(struct file *file, void  *priv,
-				struct v4l2_fmtdesc *f)
-{
-	if (0 != f->index)
-		return -EINVAL;
-
-	f->pixelformat = V4L2_PIX_FMT_GREY;
-	strcpy(f->description, "vbi data");
-
-	return 0;
-}
-
 static int bttv_enum_fmt_cap_ovr(struct v4l2_fmtdesc *f)
 {
 	int index = -1, i;
@@ -3227,6 +3218,7 @@
 
 	dprintk(KERN_DEBUG "bttv: open minor=%d\n",minor);
 
+	lock_kernel();
 	for (i = 0; i < bttv_num; i++) {
 		if (bttvs[i].video_dev &&
 		    bttvs[i].video_dev->minor == minor) {
@@ -3241,16 +3233,20 @@
 			break;
 		}
 	}
-	if (NULL == btv)
+	if (NULL == btv) {
+		unlock_kernel();
 		return -ENODEV;
+	}
 
 	dprintk(KERN_DEBUG "bttv%d: open called (type=%s)\n",
 		btv->c.nr,v4l2_type_names[type]);
 
 	/* allocate per filehandle data */
 	fh = kmalloc(sizeof(*fh),GFP_KERNEL);
-	if (NULL == fh)
+	if (NULL == fh) {
+		unlock_kernel();
 		return -ENOMEM;
+	}
 	file->private_data = fh;
 	*fh = btv->init;
 	fh->type = type;
@@ -3270,6 +3266,7 @@
 			    sizeof(struct bttv_buffer),
 			    fh);
 	set_tvnorm(btv,btv->tvnorm);
+	set_input(btv, btv->input, btv->tvnorm);
 
 	btv->users++;
 
@@ -3290,6 +3287,7 @@
 	bttv_vbi_fmt_reset(&fh->vbi_fmt, btv->tvnorm);
 
 	bttv_field_count(btv);
+	unlock_kernel();
 	return 0;
 }
 
@@ -3330,6 +3328,10 @@
 
 	btv->users--;
 	bttv_field_count(btv);
+
+	if (!btv->users)
+		audio_mute(btv, 1);
+
 	return 0;
 }
 
@@ -3367,7 +3369,6 @@
 	.vidioc_g_fmt_vid_overlay       = bttv_g_fmt_vid_overlay,
 	.vidioc_try_fmt_vid_overlay     = bttv_try_fmt_vid_overlay,
 	.vidioc_s_fmt_vid_overlay       = bttv_s_fmt_vid_overlay,
-	.vidioc_enum_fmt_vbi_cap        = bttv_enum_fmt_vbi_cap,
 	.vidioc_g_fmt_vbi_cap           = bttv_g_fmt_vbi_cap,
 	.vidioc_try_fmt_vbi_cap         = bttv_try_fmt_vbi_cap,
 	.vidioc_s_fmt_vbi_cap           = bttv_s_fmt_vbi_cap,
@@ -3430,21 +3431,26 @@
 
 	dprintk("bttv: open minor=%d\n",minor);
 
+	lock_kernel();
 	for (i = 0; i < bttv_num; i++) {
-		if (bttvs[i].radio_dev->minor == minor) {
+		if (bttvs[i].radio_dev && bttvs[i].radio_dev->minor == minor) {
 			btv = &bttvs[i];
 			break;
 		}
 	}
-	if (NULL == btv)
+	if (NULL == btv) {
+		unlock_kernel();
 		return -ENODEV;
+	}
 
 	dprintk("bttv%d: open called (radio)\n",btv->c.nr);
 
 	/* allocate per filehandle data */
 	fh = kmalloc(sizeof(*fh), GFP_KERNEL);
-	if (NULL == fh)
+	if (NULL == fh) {
+		unlock_kernel();
 		return -ENOMEM;
+	}
 	file->private_data = fh;
 	*fh = btv->init;
 	v4l2_prio_open(&btv->prio, &fh->prio);
@@ -3457,6 +3463,7 @@
 	audio_input(btv,TVAUDIO_INPUT_RADIO);
 
 	mutex_unlock(&btv->lock);
+	unlock_kernel();
 	return 0;
 }
 
@@ -4235,7 +4242,8 @@
 
 	if (NULL == btv->video_dev)
 		goto err;
-	if (video_register_device(btv->video_dev,VFL_TYPE_GRABBER,video_nr)<0)
+	if (video_register_device(btv->video_dev, VFL_TYPE_GRABBER,
+				  video_nr[btv->c.nr]) < 0)
 		goto err;
 	printk(KERN_INFO "bttv%d: registered device video%d\n",
 	       btv->c.nr,btv->video_dev->minor & 0x1f);
@@ -4251,7 +4259,8 @@
 
 	if (NULL == btv->vbi_dev)
 		goto err;
-	if (video_register_device(btv->vbi_dev,VFL_TYPE_VBI,vbi_nr)<0)
+	if (video_register_device(btv->vbi_dev, VFL_TYPE_VBI,
+				  vbi_nr[btv->c.nr]) < 0)
 		goto err;
 	printk(KERN_INFO "bttv%d: registered device vbi%d\n",
 	       btv->c.nr,btv->vbi_dev->minor & 0x1f);
@@ -4262,7 +4271,8 @@
 	btv->radio_dev = vdev_init(btv, &radio_template, "radio");
 	if (NULL == btv->radio_dev)
 		goto err;
-	if (video_register_device(btv->radio_dev, VFL_TYPE_RADIO,radio_nr)<0)
+	if (video_register_device(btv->radio_dev, VFL_TYPE_RADIO,
+				  radio_nr[btv->c.nr]) < 0)
 		goto err;
 	printk(KERN_INFO "bttv%d: registered device radio%d\n",
 	       btv->c.nr,btv->radio_dev->minor & 0x1f);
diff --git a/drivers/media/video/bt8xx/bttv-input.c b/drivers/media/video/bt8xx/bttv-input.c
index a38af98..2f289d9 100644
--- a/drivers/media/video/bt8xx/bttv-input.c
+++ b/drivers/media/video/bt8xx/bttv-input.c
@@ -28,8 +28,8 @@
 #include "bttvp.h"
 
 
-static int debug;
-module_param(debug, int, 0644);    /* debug level (0,1,2) */
+static int ir_debug;
+module_param(ir_debug, int, 0644);
 static int repeat_delay = 500;
 module_param(repeat_delay, int, 0644);
 static int repeat_period = 33;
@@ -40,6 +40,12 @@
 static int ir_rc5_key_timeout = 200;
 module_param(ir_rc5_key_timeout, int, 0644);
 
+#undef dprintk
+#define dprintk(arg...) do {	\
+	if (ir_debug >= 1)	\
+		printk(arg);	\
+} while (0)
+
 #define DEVNAME "bttv-input"
 
 /* ---------------------------------------------------------------------- */
@@ -79,6 +85,45 @@
 
 }
 
+static void ir_enltv_handle_key(struct bttv *btv)
+{
+	struct card_ir *ir = btv->remote;
+	u32 gpio, data, keyup;
+
+	/* read gpio value */
+	gpio = bttv_gpio_read(&btv->c);
+
+	/* extract data */
+	data = ir_extract_bits(gpio, ir->mask_keycode);
+
+	/* Check if it is keyup */
+	keyup = (gpio & ir->mask_keyup) ? 1 << 31 : 0;
+
+	if ((ir->last_gpio & 0x7f) != data) {
+		dprintk(KERN_INFO DEVNAME ": gpio=0x%x code=%d | %s\n",
+			gpio, data,
+			(gpio & ir->mask_keyup) ? " up" : "up/down");
+
+		ir_input_keydown(ir->dev, &ir->ir, data, data);
+		if (keyup)
+			ir_input_nokey(ir->dev, &ir->ir);
+	} else {
+		if ((ir->last_gpio & 1 << 31) == keyup)
+			return;
+
+		dprintk(KERN_INFO DEVNAME ":(cnt) gpio=0x%x code=%d | %s\n",
+			gpio, data,
+			(gpio & ir->mask_keyup) ? " up" : "down");
+
+		if (keyup)
+			ir_input_nokey(ir->dev, &ir->ir);
+		else
+			ir_input_keydown(ir->dev, &ir->ir, data, data);
+	}
+
+	ir->last_gpio = data | keyup;
+}
+
 void bttv_input_irq(struct bttv *btv)
 {
 	struct card_ir *ir = btv->remote;
@@ -92,7 +137,10 @@
 	struct bttv *btv = (struct bttv*)data;
 	struct card_ir *ir = btv->remote;
 
-	ir_handle_key(btv);
+	if (btv->c.type == BTTV_BOARD_ENLTV_FM_2)
+		ir_enltv_handle_key(btv);
+	else
+		ir_handle_key(btv);
 	mod_timer(&ir->timer, jiffies + msecs_to_jiffies(ir->polling));
 }
 
@@ -284,6 +332,14 @@
 		ir->mask_keyup   = 0x006000;
 		ir->polling      = 50; /* ms */
 		break;
+	case BTTV_BOARD_ENLTV_FM_2:
+		ir_codes         = ir_codes_encore_enltv2;
+		ir->mask_keycode = 0x00fd00;
+		ir->mask_keyup   = 0x000080;
+		ir->polling      = 1; /* ms */
+		ir->last_gpio    = ir_extract_bits(bttv_gpio_read(&btv->c),
+						   ir->mask_keycode);
+		break;
 	}
 	if (NULL == ir_codes) {
 		dprintk(KERN_INFO "Ooops: IR config error [card=%d]\n", btv->c.type);
diff --git a/drivers/media/video/bt8xx/bttv.h b/drivers/media/video/bt8xx/bttv.h
index 6d93d16c..46cb90e 100644
--- a/drivers/media/video/bt8xx/bttv.h
+++ b/drivers/media/video/bt8xx/bttv.h
@@ -176,7 +176,7 @@
 #define BTTV_BOARD_TYPHOON_TVTUNERPCI	   0x95
 #define BTTV_BOARD_GEOVISION_GV600	   0x96
 #define BTTV_BOARD_KOZUMI_KTV_01C          0x97
-
+#define BTTV_BOARD_ENLTV_FM_2		   0x98
 
 /* more card-specific defines */
 #define PT2254_L_CHANNEL 0x10
diff --git a/drivers/media/video/btcx-risc.c b/drivers/media/video/btcx-risc.c
index 3324ab3..ac1b268 100644
--- a/drivers/media/video/btcx-risc.c
+++ b/drivers/media/video/btcx-risc.c
@@ -64,7 +64,7 @@
 		       unsigned int size)
 {
 	__le32 *cpu;
-	dma_addr_t dma;
+	dma_addr_t dma = 0;
 
 	if (NULL != risc->cpu && risc->size < size)
 		btcx_riscmem_free(pci,risc);
diff --git a/drivers/media/video/bw-qcam.c b/drivers/media/video/bw-qcam.c
index 6e39e25..ace4ff9 100644
--- a/drivers/media/video/bw-qcam.c
+++ b/drivers/media/video/bw-qcam.c
@@ -495,7 +495,7 @@
 		val2 = (((q->port_mode & QC_MODE_MASK) == QC_BIDIR) ? 24 : 8) *
 		    q->transfer_scale;
 	}
-	val = (val + val2 - 1) / val2;
+	val = DIV_ROUND_UP(val, val2);
 	qc_command(q, 0x13);
 	qc_command(q, val);
 
@@ -651,7 +651,7 @@
 	transperline = q->width * q->bpp;
 	divisor = (((q->port_mode & QC_MODE_MASK) == QC_BIDIR) ? 24 : 8) *
 	    q->transfer_scale;
-	transperline = (transperline + divisor - 1) / divisor;
+	transperline = DIV_ROUND_UP(transperline, divisor);
 
 	for (i = 0, yield = yieldlines; i < linestotrans; i++)
 	{
@@ -894,10 +894,27 @@
 	return len;
 }
 
+static int qcam_exclusive_open(struct inode *inode, struct file *file)
+{
+	struct video_device *dev = video_devdata(file);
+	struct qcam_device *qcam = (struct qcam_device *)dev;
+
+	return test_and_set_bit(0, &qcam->in_use) ? -EBUSY : 0;
+}
+
+static int qcam_exclusive_release(struct inode *inode, struct file *file)
+{
+	struct video_device *dev = video_devdata(file);
+	struct qcam_device *qcam = (struct qcam_device *)dev;
+
+	clear_bit(0, &qcam->in_use);
+	return 0;
+}
+
 static const struct file_operations qcam_fops = {
 	.owner		= THIS_MODULE,
-	.open           = video_exclusive_open,
-	.release        = video_exclusive_release,
+	.open           = qcam_exclusive_open,
+	.release        = qcam_exclusive_release,
 	.ioctl          = qcam_ioctl,
 #ifdef CONFIG_COMPAT
 	.compat_ioctl	= v4l_compat_ioctl32,
@@ -909,6 +926,7 @@
 {
 	.name		= "Connectix Quickcam",
 	.fops           = &qcam_fops,
+	.release 	= video_device_release_empty,
 };
 
 #define MAX_CAMS 4
diff --git a/drivers/media/video/bw-qcam.h b/drivers/media/video/bw-qcam.h
index 6701daf..8a60c5d 100644
--- a/drivers/media/video/bw-qcam.h
+++ b/drivers/media/video/bw-qcam.h
@@ -65,4 +65,5 @@
 	int top, left;
 	int status;
 	unsigned int saved_bits;
+	unsigned long in_use;
 };
diff --git a/drivers/media/video/c-qcam.c b/drivers/media/video/c-qcam.c
index 7f6c6b4..17aa0ad 100644
--- a/drivers/media/video/c-qcam.c
+++ b/drivers/media/video/c-qcam.c
@@ -51,6 +51,7 @@
 	int contrast, brightness, whitebal;
 	int top, left;
 	unsigned int bidirectional;
+	unsigned long in_use;
 	struct mutex lock;
 };
 
@@ -687,11 +688,28 @@
 	return len;
 }
 
+static int qcam_exclusive_open(struct inode *inode, struct file *file)
+{
+	struct video_device *dev = video_devdata(file);
+	struct qcam_device *qcam = (struct qcam_device *)dev;
+
+	return test_and_set_bit(0, &qcam->in_use) ? -EBUSY : 0;
+}
+
+static int qcam_exclusive_release(struct inode *inode, struct file *file)
+{
+	struct video_device *dev = video_devdata(file);
+	struct qcam_device *qcam = (struct qcam_device *)dev;
+
+	clear_bit(0, &qcam->in_use);
+	return 0;
+}
+
 /* video device template */
 static const struct file_operations qcam_fops = {
 	.owner		= THIS_MODULE,
-	.open           = video_exclusive_open,
-	.release        = video_exclusive_release,
+	.open           = qcam_exclusive_open,
+	.release        = qcam_exclusive_release,
 	.ioctl          = qcam_ioctl,
 #ifdef CONFIG_COMPAT
 	.compat_ioctl	= v4l_compat_ioctl32,
@@ -704,6 +722,7 @@
 {
 	.name		= "Colour QuickCam",
 	.fops           = &qcam_fops,
+	.release 	= video_device_release_empty,
 };
 
 /* Initialize the QuickCam driver control structure. */
diff --git a/drivers/media/video/cafe_ccic.c b/drivers/media/video/cafe_ccic.c
index c149b7d..fc9497b 100644
--- a/drivers/media/video/cafe_ccic.c
+++ b/drivers/media/video/cafe_ccic.c
@@ -19,6 +19,7 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/fs.h>
+#include <linux/mm.h>
 #include <linux/pci.h>
 #include <linux/i2c.h>
 #include <linux/interrupt.h>
@@ -1475,9 +1476,12 @@
 {
 	struct cafe_camera *cam;
 
+	lock_kernel();
 	cam = cafe_find_dev(iminor(inode));
-	if (cam == NULL)
+	if (cam == NULL) {
+		unlock_kernel();
 		return -ENODEV;
+	}
 	filp->private_data = cam;
 
 	mutex_lock(&cam->s_mutex);
@@ -1489,6 +1493,7 @@
 	}
 	(cam->users)++;
 	mutex_unlock(&cam->s_mutex);
+	unlock_kernel();
 	return 0;
 }
 
@@ -2091,15 +2096,8 @@
 		const struct pci_device_id *id)
 {
 	int ret;
-	u16 classword;
 	struct cafe_camera *cam;
-	/*
-	 * Make sure we have a camera here - we'll get calls for
-	 * the other cafe devices as well.
-	 */
-	pci_read_config_word(pdev, PCI_CLASS_DEVICE, &classword);
-	if (classword != PCI_CLASS_MULTIMEDIA_VIDEO)
-		return -ENODEV;
+
 	/*
 	 * Start putting together one of our big camera structures.
 	 */
@@ -2287,8 +2285,8 @@
 
 
 static struct pci_device_id cafe_ids[] = {
-	{ PCI_DEVICE(0x11ab, 0x4100) }, /* Eventual real ID */
-	{ PCI_DEVICE(0x11ab, 0x4102) }, /* Really eventual real ID */
+	{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL,
+		     PCI_DEVICE_ID_MARVELL_88ALP01_CCIC) },
 	{ 0, }
 };
 
diff --git a/drivers/media/video/cpia.c b/drivers/media/video/cpia.c
index a661800..c325e92 100644
--- a/drivers/media/video/cpia.c
+++ b/drivers/media/video/cpia.c
@@ -3155,7 +3155,7 @@
 static int cpia_open(struct inode *inode, struct file *file)
 {
 	struct video_device *dev = video_devdata(file);
-	struct cam_data *cam = dev->priv;
+	struct cam_data *cam = video_get_drvdata(dev);
 	int err;
 
 	if (!cam) {
@@ -3202,7 +3202,7 @@
 
 	/* Set ownership of /proc/cpia/videoX to current user */
 	if(cam->proc_entry)
-		cam->proc_entry->uid = current->uid;
+		cam->proc_entry->uid = current_uid();
 
 	/* set mark for loading first frame uncompressed */
 	cam->first_frame = 1;
@@ -3232,7 +3232,7 @@
 static int cpia_close(struct inode *inode, struct file *file)
 {
 	struct  video_device *dev = file->private_data;
-	struct cam_data *cam = dev->priv;
+	struct cam_data *cam = video_get_drvdata(dev);
 
 	if (cam->ops) {
 		/* Return ownership of /proc/cpia/videoX to root */
@@ -3284,7 +3284,7 @@
 			 size_t count, loff_t *ppos)
 {
 	struct video_device *dev = file->private_data;
-	struct cam_data *cam = dev->priv;
+	struct cam_data *cam = video_get_drvdata(dev);
 	int err;
 
 	/* make this _really_ smp and multithread-safe */
@@ -3341,7 +3341,7 @@
 			 unsigned int ioctlnr, void *arg)
 {
 	struct video_device *dev = file->private_data;
-	struct cam_data *cam = dev->priv;
+	struct cam_data *cam = video_get_drvdata(dev);
 	int retval = 0;
 
 	if (!cam || !cam->ops)
@@ -3739,7 +3739,7 @@
 	unsigned long start = vma->vm_start;
 	unsigned long size  = vma->vm_end - vma->vm_start;
 	unsigned long page, pos;
-	struct cam_data *cam = dev->priv;
+	struct cam_data *cam = video_get_drvdata(dev);
 	int retval;
 
 	if (!cam || !cam->ops)
@@ -3801,6 +3801,7 @@
 static struct video_device cpia_template = {
 	.name		= "CPiA Camera",
 	.fops           = &cpia_fops,
+	.release 	= video_device_release_empty,
 };
 
 /* initialise cam_data structure  */
@@ -3928,7 +3929,7 @@
 	cam->proc_entry = NULL;
 
 	memcpy(&cam->vdev, &cpia_template, sizeof(cpia_template));
-	cam->vdev.priv = cam;
+	video_set_drvdata(&cam->vdev, cam);
 
 	cam->curframe = 0;
 	for (i = 0; i < FRAME_NUM; i++) {
diff --git a/drivers/media/video/cpia2/cpia2_core.c b/drivers/media/video/cpia2/cpia2_core.c
index af8b9ec..7e791b6 100644
--- a/drivers/media/video/cpia2/cpia2_core.c
+++ b/drivers/media/video/cpia2/cpia2_core.c
@@ -1537,7 +1537,7 @@
  *
  *  This sets all user changeable properties to the values in cam->params.
  *****************************************************************************/
-int set_all_properties(struct camera_data *cam)
+static int set_all_properties(struct camera_data *cam)
 {
 	/**
 	 * Don't set target_kb here, it will be set later.
@@ -1588,7 +1588,7 @@
  *  get_color_params
  *
  *****************************************************************************/
-void get_color_params(struct camera_data *cam)
+static void get_color_params(struct camera_data *cam)
 {
 	cpia2_do_command(cam, CPIA2_CMD_GET_VP_BRIGHTNESS, TRANSFER_READ, 0);
 	cpia2_do_command(cam, CPIA2_CMD_GET_VP_SATURATION, TRANSFER_READ, 0);
@@ -1881,7 +1881,7 @@
  *  wake_system
  *
  *****************************************************************************/
-void wake_system(struct camera_data *cam)
+static void wake_system(struct camera_data *cam)
 {
 	cpia2_do_command(cam, CPIA2_CMD_SET_WAKEUP, TRANSFER_WRITE, 0);
 }
@@ -1892,7 +1892,7 @@
  *
  *  Valid for STV500 sensor only
  *****************************************************************************/
-void set_lowlight_boost(struct camera_data *cam)
+static void set_lowlight_boost(struct camera_data *cam)
 {
 	struct cpia2_command cmd;
 
@@ -2169,7 +2169,7 @@
  *
  *  Sets all values to the defaults
  *****************************************************************************/
-void reset_camera_struct(struct camera_data *cam)
+static void reset_camera_struct(struct camera_data *cam)
 {
 	/***
 	 * The following parameter values are the defaults from the register map.
diff --git a/drivers/media/video/cpia2/cpia2_usb.c b/drivers/media/video/cpia2/cpia2_usb.c
index a4574740..73511a5 100644
--- a/drivers/media/video/cpia2/cpia2_usb.c
+++ b/drivers/media/video/cpia2/cpia2_usb.c
@@ -478,7 +478,7 @@
  * set_alternate
  *
  *****************************************************************************/
-int set_alternate(struct camera_data *cam, unsigned int alt)
+static int set_alternate(struct camera_data *cam, unsigned int alt)
 {
 	int ret = 0;
 
@@ -632,7 +632,7 @@
 static int submit_urbs(struct camera_data *cam)
 {
 	struct urb *urb;
-	int fx, err, i;
+	int fx, err, i, j;
 
 	for(i=0; i<NUM_SBUF; ++i) {
 		if (cam->sbuf[i].data)
@@ -657,6 +657,9 @@
 		}
 		urb = usb_alloc_urb(FRAMES_PER_DESC, GFP_KERNEL);
 		if (!urb) {
+			ERR("%s: usb_alloc_urb error!\n", __func__);
+			for (j = 0; j < i; j++)
+				usb_free_urb(cam->sbuf[j].urb);
 			return -ENOMEM;
 		}
 
diff --git a/drivers/media/video/cpia2/cpia2_v4l.c b/drivers/media/video/cpia2/cpia2_v4l.c
index eb9f15c..897e8d1 100644
--- a/drivers/media/video/cpia2/cpia2_v4l.c
+++ b/drivers/media/video/cpia2/cpia2_v4l.c
@@ -241,8 +241,7 @@
  *****************************************************************************/
 static int cpia2_open(struct inode *inode, struct file *file)
 {
-	struct video_device *dev = video_devdata(file);
-	struct camera_data *cam = video_get_drvdata(dev);
+	struct camera_data *cam = video_drvdata(file);
 	int retval = 0;
 
 	if (!cam) {
@@ -357,8 +356,7 @@
 static ssize_t cpia2_v4l_read(struct file *file, char __user *buf, size_t count,
 			      loff_t *off)
 {
-	struct video_device *dev = video_devdata(file);
-	struct camera_data *cam = video_get_drvdata(dev);
+	struct camera_data *cam = video_drvdata(file);
 	int noblock = file->f_flags&O_NONBLOCK;
 
 	struct cpia2_fh *fh = file->private_data;
@@ -382,9 +380,7 @@
  *****************************************************************************/
 static unsigned int cpia2_v4l_poll(struct file *filp, struct poll_table_struct *wait)
 {
-	struct video_device *dev = video_devdata(filp);
-	struct camera_data *cam = video_get_drvdata(dev);
-
+	struct camera_data *cam = video_drvdata(filp);
 	struct cpia2_fh *fh = filp->private_data;
 
 	if(!cam)
@@ -1579,8 +1575,7 @@
 static int cpia2_do_ioctl(struct inode *inode, struct file *file,
 			  unsigned int ioctl_nr, void *arg)
 {
-	struct video_device *dev = video_devdata(file);
-	struct camera_data *cam = video_get_drvdata(dev);
+	struct camera_data *cam = video_drvdata(file);
 	int retval = 0;
 
 	if (!cam)
@@ -1860,9 +1855,8 @@
  *****************************************************************************/
 static int cpia2_mmap(struct file *file, struct vm_area_struct *area)
 {
+	struct camera_data *cam = video_drvdata(file);
 	int retval;
-	struct video_device *dev = video_devdata(file);
-	struct camera_data *cam = video_get_drvdata(dev);
 
 	/* Priority check */
 	struct cpia2_fh *fh = file->private_data;
diff --git a/drivers/media/video/cx18/Makefile b/drivers/media/video/cx18/Makefile
index b23d2e2..f7bf0ed 100644
--- a/drivers/media/video/cx18/Makefile
+++ b/drivers/media/video/cx18/Makefile
@@ -2,7 +2,7 @@
 	cx18-queue.o cx18-streams.o cx18-fileops.o cx18-ioctl.o cx18-controls.o \
 	cx18-mailbox.o cx18-vbi.o cx18-audio.o cx18-video.o cx18-irq.o \
 	cx18-av-core.o cx18-av-audio.o cx18-av-firmware.o cx18-av-vbi.o cx18-scb.o \
-	cx18-dvb.o
+	cx18-dvb.o cx18-io.o
 
 obj-$(CONFIG_VIDEO_CX18) += cx18.o
 
diff --git a/drivers/media/video/cx18/cx18-audio.c b/drivers/media/video/cx18/cx18-audio.c
index 6d5b94f..57beddf 100644
--- a/drivers/media/video/cx18/cx18-audio.c
+++ b/drivers/media/video/cx18/cx18-audio.c
@@ -22,6 +22,7 @@
  */
 
 #include "cx18-driver.h"
+#include "cx18-io.h"
 #include "cx18-i2c.h"
 #include "cx18-cards.h"
 #include "cx18-audio.h"
@@ -60,10 +61,10 @@
 	if (err)
 		return err;
 
-	val = read_reg(CX18_AUDIO_ENABLE) & ~0x30;
+	val = cx18_read_reg(cx, CX18_AUDIO_ENABLE) & ~0x30;
 	val |= (audio_input > CX18_AV_AUDIO_SERIAL2) ? 0x20 :
 					(audio_input << 4);
-	write_reg(val | 0xb00, CX18_AUDIO_ENABLE);
+	cx18_write_reg(cx, val | 0xb00, CX18_AUDIO_ENABLE);
 	cx18_vapi(cx, CX18_APU_RESETAI, 1, 0);
 	return 0;
 }
diff --git a/drivers/media/video/cx18/cx18-av-core.c b/drivers/media/video/cx18/cx18-av-core.c
index 3b0a2c4..73f5141 100644
--- a/drivers/media/video/cx18/cx18-av-core.c
+++ b/drivers/media/video/cx18/cx18-av-core.c
@@ -22,27 +22,35 @@
  */
 
 #include "cx18-driver.h"
+#include "cx18-io.h"
 
 int cx18_av_write(struct cx18 *cx, u16 addr, u8 value)
 {
-	u32 x = readl(cx->reg_mem + 0xc40000 + (addr & ~3));
+	u32 reg = 0xc40000 + (addr & ~3);
 	u32 mask = 0xff;
 	int shift = (addr & 3) * 8;
+	u32 x = cx18_read_reg(cx, reg);
 
 	x = (x & ~(mask << shift)) | ((u32)value << shift);
-	writel(x, cx->reg_mem + 0xc40000 + (addr & ~3));
+	cx18_write_reg(cx, x, reg);
 	return 0;
 }
 
 int cx18_av_write4(struct cx18 *cx, u16 addr, u32 value)
 {
-	writel(value, cx->reg_mem + 0xc40000 + addr);
+	cx18_write_reg(cx, value, 0xc40000 + addr);
+	return 0;
+}
+
+int cx18_av_write4_noretry(struct cx18 *cx, u16 addr, u32 value)
+{
+	cx18_write_reg_noretry(cx, value, 0xc40000 + addr);
 	return 0;
 }
 
 u8 cx18_av_read(struct cx18 *cx, u16 addr)
 {
-	u32 x = readl(cx->reg_mem + 0xc40000 + (addr & ~3));
+	u32 x = cx18_read_reg(cx, 0xc40000 + (addr & ~3));
 	int shift = (addr & 3) * 8;
 
 	return (x >> shift) & 0xff;
@@ -50,7 +58,12 @@
 
 u32 cx18_av_read4(struct cx18 *cx, u16 addr)
 {
-	return readl(cx->reg_mem + 0xc40000 + addr);
+	return cx18_read_reg(cx, 0xc40000 + addr);
+}
+
+u32 cx18_av_read4_noretry(struct cx18 *cx, u16 addr)
+{
+	return cx18_read_reg_noretry(cx, 0xc40000 + addr);
 }
 
 int cx18_av_and_or(struct cx18 *cx, u16 addr, unsigned and_mask,
diff --git a/drivers/media/video/cx18/cx18-av-core.h b/drivers/media/video/cx18/cx18-av-core.h
index eb61fa1..b67d8df 100644
--- a/drivers/media/video/cx18/cx18-av-core.h
+++ b/drivers/media/video/cx18/cx18-av-core.h
@@ -301,8 +301,10 @@
 /* cx18_av-core.c 							   */
 int cx18_av_write(struct cx18 *cx, u16 addr, u8 value);
 int cx18_av_write4(struct cx18 *cx, u16 addr, u32 value);
+int cx18_av_write4_noretry(struct cx18 *cx, u16 addr, u32 value);
 u8 cx18_av_read(struct cx18 *cx, u16 addr);
 u32 cx18_av_read4(struct cx18 *cx, u16 addr);
+u32 cx18_av_read4_noretry(struct cx18 *cx, u16 addr);
 int cx18_av_and_or(struct cx18 *cx, u16 addr, unsigned mask, u8 value);
 int cx18_av_and_or4(struct cx18 *cx, u16 addr, u32 mask, u32 value);
 int cx18_av_cmd(struct cx18 *cx, unsigned int cmd, void *arg);
diff --git a/drivers/media/video/cx18/cx18-av-firmware.c b/drivers/media/video/cx18/cx18-av-firmware.c
index e996a4e..522a035 100644
--- a/drivers/media/video/cx18/cx18-av-firmware.c
+++ b/drivers/media/video/cx18/cx18-av-firmware.c
@@ -20,6 +20,7 @@
  */
 
 #include "cx18-driver.h"
+#include "cx18-io.h"
 #include <linux/firmware.h>
 
 #define CX18_AUDIO_ENABLE 0xc72014
@@ -49,7 +50,7 @@
 		cx18_av_write4(cx, 0x8100, 0x00010000);
 
 		/* Put the 8051 in reset and enable firmware upload */
-		cx18_av_write4(cx, CXADEC_DL_CTL, 0x0F000000);
+		cx18_av_write4_noretry(cx, CXADEC_DL_CTL, 0x0F000000);
 
 		ptr = fw->data;
 		size = fw->size;
@@ -58,22 +59,28 @@
 			u32 dl_control = 0x0F000000 | i | ((u32)ptr[i] << 16);
 			u32 value = 0;
 			int retries2;
+			int unrec_err = 0;
 
-			for (retries2 = 0; retries2 < 5; retries2++) {
-				cx18_av_write4(cx, CXADEC_DL_CTL, dl_control);
+			for (retries2 = 0; retries2 < CX18_MAX_MMIO_RETRIES;
+			     retries2++) {
+				cx18_av_write4_noretry(cx, CXADEC_DL_CTL,
+						       dl_control);
 				udelay(10);
-				value = cx18_av_read4(cx, CXADEC_DL_CTL);
+				value = cx18_av_read4_noretry(cx,
+							      CXADEC_DL_CTL);
 				if (value == dl_control)
 					break;
 				/* Check if we can correct the byte by changing
 				   the address.  We can only write the lower
 				   address byte of the address. */
 				if ((value & 0x3F00) != (dl_control & 0x3F00)) {
-					retries2 = 5;
+					unrec_err = 1;
 					break;
 				}
 			}
-			if (retries2 >= 5)
+			cx18_log_write_retries(cx, retries2,
+					cx->reg_mem + 0xc40000 + CXADEC_DL_CTL);
+			if (unrec_err || retries2 >= CX18_MAX_MMIO_RETRIES)
 				break;
 		}
 		if (i == size)
@@ -119,10 +126,10 @@
 	   have a name in the spec. */
 	cx18_av_write4(cx, 0x09CC, 1);
 
-	v = read_reg(CX18_AUDIO_ENABLE);
-	/* If bit 11 is 1 */
+	v = cx18_read_reg(cx, CX18_AUDIO_ENABLE);
+	/* If bit 11 is 1, clear bit 10 */
 	if (v & 0x800)
-		write_reg(v & 0xFFFFFBFF, CX18_AUDIO_ENABLE); /* Clear bit 10 */
+		cx18_write_reg(cx, v & 0xFFFFFBFF, CX18_AUDIO_ENABLE);
 
 	/* Enable WW auto audio standard detection */
 	v = cx18_av_read4(cx, CXADEC_STD_DET_CTL);
diff --git a/drivers/media/video/cx18/cx18-cards.c b/drivers/media/video/cx18/cx18-cards.c
index 8fe5f38..5efe01e 100644
--- a/drivers/media/video/cx18/cx18-cards.c
+++ b/drivers/media/video/cx18/cx18-cards.c
@@ -163,7 +163,7 @@
 	},
 	.audio_inputs = {
 		{ CX18_CARD_INPUT_AUD_TUNER,
-		  CX18_AV_AUDIO8, 0 },
+		  CX18_AV_AUDIO5, 0 },
 		{ CX18_CARD_INPUT_LINE_IN1,
 		  CX18_AV_AUDIO_SERIAL1, 0 },
 	},
@@ -292,12 +292,111 @@
 
 /* ------------------------------------------------------------------------- */
 
+/* Toshiba Qosmio laptop internal DVB-T/Analog Hybrid Tuner */
+
+static const struct cx18_card_pci_info cx18_pci_toshiba_qosmio_dvbt[] = {
+	{ PCI_DEVICE_ID_CX23418, CX18_PCI_ID_TOSHIBA, 0x0110 },
+	{ 0, 0, 0 }
+};
+
+static const struct cx18_card cx18_card_toshiba_qosmio_dvbt = {
+	.type = CX18_CARD_TOSHIBA_QOSMIO_DVBT,
+	.name = "Toshiba Qosmio DVB-T/Analog",
+	.comment = "Experimenters and photos needed for device to work well.\n"
+		  "\tTo help, mail the ivtv-devel list (www.ivtvdriver.org).\n",
+	.v4l2_capabilities = CX18_CAP_ENCODER,
+	.hw_audio_ctrl = CX18_HW_CX23418,
+	.hw_all = CX18_HW_TUNER,
+	.video_inputs = {
+		{ CX18_CARD_INPUT_VID_TUNER,  0, CX18_AV_COMPOSITE6 },
+		{ CX18_CARD_INPUT_SVIDEO1,    1,
+			CX18_AV_SVIDEO_LUMA3 | CX18_AV_SVIDEO_CHROMA4 },
+		{ CX18_CARD_INPUT_COMPOSITE1, 1, CX18_AV_COMPOSITE1 },
+	},
+	.audio_inputs = {
+		{ CX18_CARD_INPUT_AUD_TUNER, CX18_AV_AUDIO5, 	    0 },
+		{ CX18_CARD_INPUT_LINE_IN1,  CX18_AV_AUDIO_SERIAL1, 1 },
+	},
+	.tuners = {
+		{ .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 },
+	},
+	.ddr = {
+		.chip_config = 0x202,
+		.refresh = 0x3bb,
+		.timing1 = 0x33320a63,
+		.timing2 = 0x0a,
+		.tune_lane = 0,
+		.initial_emrs = 0x42,
+	},
+	.xceive_pin = 15,
+	.pci_list = cx18_pci_toshiba_qosmio_dvbt,
+	.i2c = &cx18_i2c_std,
+};
+
+/* ------------------------------------------------------------------------- */
+
+/* Leadtek WinFast PVR2100 */
+
+static const struct cx18_card_pci_info cx18_pci_leadtek_pvr2100[] = {
+	{ PCI_DEVICE_ID_CX23418, CX18_PCI_ID_LEADTEK, 0x6f27 },
+	{ 0, 0, 0 }
+};
+
+static const struct cx18_card cx18_card_leadtek_pvr2100 = {
+	.type = CX18_CARD_LEADTEK_PVR2100,
+	.name = "Leadtek WinFast PVR2100",
+	.comment = "Experimenters and photos needed for device to work well.\n"
+		  "\tTo help, mail the ivtv-devel list (www.ivtvdriver.org).\n",
+	.v4l2_capabilities = CX18_CAP_ENCODER,
+	.hw_audio_ctrl = CX18_HW_CX23418,
+	.hw_muxer = CX18_HW_GPIO,
+	.hw_all = CX18_HW_TUNER | CX18_HW_GPIO,
+	.video_inputs = {
+		{ CX18_CARD_INPUT_VID_TUNER,  0, CX18_AV_COMPOSITE2 },
+		{ CX18_CARD_INPUT_SVIDEO1,    1,
+			CX18_AV_SVIDEO_LUMA3 | CX18_AV_SVIDEO_CHROMA4 },
+		{ CX18_CARD_INPUT_COMPOSITE1, 1, CX18_AV_COMPOSITE7 },
+	},
+	.audio_inputs = {
+		{ CX18_CARD_INPUT_AUD_TUNER, CX18_AV_AUDIO5, 	    0 },
+		{ CX18_CARD_INPUT_LINE_IN1,  CX18_AV_AUDIO_SERIAL1, 1 },
+	},
+	.tuners = {
+		/* XC3028 tuner */
+		{ .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 },
+	},
+	.radio_input = { CX18_CARD_INPUT_AUD_TUNER, CX18_AV_AUDIO5, 2 },
+	.ddr = {
+		/*
+		 * Pointer to proper DDR config values provided by
+		 * Terry Wu <terrywu at leadtek.com.tw>
+		 */
+		.chip_config = 0x303,
+		.refresh = 0x3bb,
+		.timing1 = 0x24220e83,
+		.timing2 = 0x1f,
+		.tune_lane = 0,
+		.initial_emrs = 0x2,
+	},
+	.gpio_init.initial_value = 0x6,
+	.gpio_init.direction = 0x7,
+	.gpio_audio_input = { .mask   = 0x7,
+			      .tuner  = 0x6, .linein = 0x2, .radio  = 0x2 },
+	.xceive_pin = 15,
+	.pci_list = cx18_pci_leadtek_pvr2100,
+	.i2c = &cx18_i2c_std,
+};
+
+/* ------------------------------------------------------------------------- */
+
 static const struct cx18_card *cx18_card_list[] = {
 	&cx18_card_hvr1600_esmt,
 	&cx18_card_hvr1600_samsung,
 	&cx18_card_h900,
 	&cx18_card_mpc718,
 	&cx18_card_cnxt_raptor_pal,
+	&cx18_card_toshiba_qosmio_dvbt,
+	&cx18_card_leadtek_pvr2100,
 };
 
 const struct cx18_card *cx18_get_card(u16 index)
diff --git a/drivers/media/video/cx18/cx18-driver.c b/drivers/media/video/cx18/cx18-driver.c
index bd18afe..085121c 100644
--- a/drivers/media/video/cx18/cx18-driver.c
+++ b/drivers/media/video/cx18/cx18-driver.c
@@ -4,6 +4,7 @@
  *  Derived from ivtv-driver.c
  *
  *  Copyright (C) 2007  Hans Verkuil <hverkuil@xs4all.nl>
+ *  Copyright (C) 2008  Andy Walls <awalls@radix.net>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -22,6 +23,7 @@
  */
 
 #include "cx18-driver.h"
+#include "cx18-io.h"
 #include "cx18-version.h"
 #include "cx18-cards.h"
 #include "cx18-i2c.h"
@@ -73,10 +75,14 @@
 				     -1, -1, -1, -1, -1, -1, -1, -1,
 				     -1, -1, -1, -1, -1, -1, -1, -1,
 				     -1, -1, -1, -1, -1, -1, -1, -1 };
-
+static int mmio_ndelay[CX18_MAX_CARDS] = { -1, -1, -1, -1, -1, -1, -1, -1,
+					   -1, -1, -1, -1, -1, -1, -1, -1,
+					   -1, -1, -1, -1, -1, -1, -1, -1,
+					   -1, -1, -1, -1, -1, -1, -1, -1 };
 static unsigned cardtype_c = 1;
 static unsigned tuner_c = 1;
 static unsigned radio_c = 1;
+static unsigned mmio_ndelay_c = 1;
 static char pal[] = "--";
 static char secam[] = "--";
 static char ntsc[] = "-";
@@ -90,15 +96,18 @@
 
 static int cx18_pci_latency = 1;
 
+int cx18_retry_mmio = 1;
 int cx18_debug;
 
 module_param_array(tuner, int, &tuner_c, 0644);
 module_param_array(radio, bool, &radio_c, 0644);
 module_param_array(cardtype, int, &cardtype_c, 0644);
+module_param_array(mmio_ndelay, int, &mmio_ndelay_c, 0644);
 module_param_string(pal, pal, sizeof(pal), 0644);
 module_param_string(secam, secam, sizeof(secam), 0644);
 module_param_string(ntsc, ntsc, sizeof(ntsc), 0644);
 module_param_named(debug, cx18_debug, int, 0644);
+module_param_named(retry_mmio, cx18_retry_mmio, int, 0644);
 module_param(cx18_pci_latency, int, 0644);
 module_param(cx18_first_minor, int, 0644);
 
@@ -121,6 +130,8 @@
 		 "\t\t\t 3 = Compro VideoMate H900\n"
 		 "\t\t\t 4 = Yuan MPC718\n"
 		 "\t\t\t 5 = Conexant Raptor PAL/SECAM\n"
+		 "\t\t\t 6 = Toshiba Qosmio DVB-T/Analog\n"
+		 "\t\t\t 7 = Leadtek WinFast PVR2100\n"
 		 "\t\t\t 0 = Autodetect (default)\n"
 		 "\t\t\t-1 = Ignore this card\n\t\t");
 MODULE_PARM_DESC(pal, "Set PAL standard: B, G, H, D, K, I, M, N, Nc, 60");
@@ -140,6 +151,14 @@
 MODULE_PARM_DESC(cx18_pci_latency,
 		 "Change the PCI latency to 64 if lower: 0 = No, 1 = Yes,\n"
 		 "\t\t\tDefault: Yes");
+MODULE_PARM_DESC(retry_mmio,
+		 "Check and retry memory mapped IO accesses\n"
+		 "\t\t\tDefault: 1 [Yes]");
+MODULE_PARM_DESC(mmio_ndelay,
+		 "Delay (ns) for each CX23418 memory mapped IO access.\n"
+		 "\t\t\tTry larger values that are close to a multiple of the\n"
+		 "\t\t\tPCI clock period, 30.3 ns, if your card doesn't work.\n"
+		 "\t\t\tDefault: " __stringify(CX18_DEFAULT_MMIO_NDELAY));
 MODULE_PARM_DESC(enc_mpg_buffers,
 		 "Encoder MPG Buffers (in MB)\n"
 		 "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_MPG_BUFFERS));
@@ -156,7 +175,7 @@
 		 "Encoder PCM buffers (in MB)\n"
 		 "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_PCM_BUFFERS));
 
-MODULE_PARM_DESC(cx18_first_minor, "Set minor assigned to first card");
+MODULE_PARM_DESC(cx18_first_minor, "Set kernel number assigned to first card");
 
 MODULE_AUTHOR("Hans Verkuil");
 MODULE_DESCRIPTION("CX23418 driver");
@@ -356,6 +375,11 @@
 	cx->options.tuner = tuner[cx->num];
 	cx->options.radio = radio[cx->num];
 
+	if (mmio_ndelay[cx->num] < 0)
+		cx->options.mmio_ndelay = CX18_DEFAULT_MMIO_NDELAY;
+	else
+		cx->options.mmio_ndelay = mmio_ndelay[cx->num];
+
 	cx->std = cx18_parse_std(cx);
 	if (cx->options.cardtype == -1) {
 		CX18_INFO("Ignore card\n");
@@ -395,9 +419,9 @@
 
 	if (cx->card == NULL) {
 		cx->card = cx18_get_card(CX18_CARD_HVR_1600_ESMT);
-		CX18_ERR("Unknown card: vendor/device: %04x/%04x\n",
+		CX18_ERR("Unknown card: vendor/device: [%04x:%04x]\n",
 		     cx->dev->vendor, cx->dev->device);
-		CX18_ERR("              subsystem vendor/device: %04x/%04x\n",
+		CX18_ERR("              subsystem vendor/device: [%04x:%04x]\n",
 		     cx->dev->subsystem_vendor, cx->dev->subsystem_device);
 		CX18_ERR("Defaulting to %s card\n", cx->card->name);
 		CX18_ERR("Please mail the vendor/device and subsystem vendor/device IDs and what kind of\n");
@@ -511,9 +535,9 @@
 		return -EIO;
 	}
 
-	/* Check for bus mastering */
+	/* Enable bus mastering and memory mapped IO for the CX23418 */
 	pci_read_config_word(dev, PCI_COMMAND, &cmd);
-	cmd |= PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER;
+	cmd |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER;
 	pci_write_config_word(dev, PCI_COMMAND, cmd);
 
 	pci_read_config_byte(dev, PCI_CLASS_REVISION, &cx->card_rev);
@@ -525,11 +549,6 @@
 		pci_write_config_byte(dev, PCI_LATENCY_TIMER, 64);
 		pci_read_config_byte(dev, PCI_LATENCY_TIMER, &pci_latency);
 	}
-	/* This config space value relates to DMA latencies. The
-	   default value 0x8080 is too low however and will lead
-	   to DMA errors. 0xffff is the max value which solves
-	   these problems. */
-	pci_write_config_dword(dev, 0x40, 0xffff);
 
 	CX18_DEBUG_INFO("cx%d (rev %d) at %02x:%02x.%x, "
 		   "irq: %d, latency: %d, memory: 0x%lx\n",
@@ -656,7 +675,7 @@
 		goto free_mem;
 	}
 	cx->reg_mem = cx->enc_mem + CX18_REG_OFFSET;
-	devtype = read_reg(0xC72028);
+	devtype = cx18_read_reg(cx, 0xC72028);
 	switch (devtype & 0xff000000) {
 	case 0xff000000:
 		CX18_INFO("cx23418 revision %08x (A)\n", devtype);
@@ -815,6 +834,7 @@
 	if (retval == 0)
 		retval = -ENODEV;
 	CX18_ERR("Error %d on initialization\n", retval);
+	cx18_log_statistics(cx);
 
 	kfree(cx18_cards[cx18_cards_active]);
 	cx18_cards[cx18_cards_active] = NULL;
@@ -902,8 +922,8 @@
 		cx18_stop_all_captures(cx);
 
 	/* Interrupts */
-	sw1_irq_disable(IRQ_CPU_TO_EPU | IRQ_APU_TO_EPU);
-	sw2_irq_disable(IRQ_CPU_TO_EPU_ACK | IRQ_APU_TO_EPU_ACK);
+	cx18_sw1_irq_disable(cx, IRQ_CPU_TO_EPU | IRQ_APU_TO_EPU);
+	cx18_sw2_irq_disable(cx, IRQ_CPU_TO_EPU_ACK | IRQ_APU_TO_EPU_ACK);
 
 	cx18_halt_firmware(cx);
 
@@ -919,6 +939,7 @@
 
 	pci_disable_device(cx->dev);
 
+	cx18_log_statistics(cx);
 	CX18_INFO("Removed %s, card #%d\n", cx->card_name, cx->num);
 }
 
@@ -938,7 +959,7 @@
 
 	/* Validate parameters */
 	if (cx18_first_minor < 0 || cx18_first_minor >= CX18_MAX_CARDS) {
-		printk(KERN_ERR "cx18:  Exiting, ivtv_first_minor must be between 0 and %d\n",
+		printk(KERN_ERR "cx18:  Exiting, cx18_first_minor must be between 0 and %d\n",
 		     CX18_MAX_CARDS - 1);
 		return -1;
 	}
diff --git a/drivers/media/video/cx18/cx18-driver.h b/drivers/media/video/cx18/cx18-driver.h
index 4801bc7..fa8be07 100644
--- a/drivers/media/video/cx18/cx18-driver.h
+++ b/drivers/media/video/cx18/cx18-driver.h
@@ -38,7 +38,6 @@
 #include <linux/i2c-algo-bit.h>
 #include <linux/list.h>
 #include <linux/unistd.h>
-#include <linux/byteorder/swab.h>
 #include <linux/pagemap.h>
 #include <linux/workqueue.h>
 #include <linux/mutex.h>
@@ -64,6 +63,9 @@
 #  error "This driver requires kernel PCI support."
 #endif
 
+/* Default delay to throttle mmio access to the CX23418 */
+#define CX18_DEFAULT_MMIO_NDELAY 0 /* 0 ns = 0 PCI clock(s) / 33 MHz */
+
 #define CX18_MEM_OFFSET	0x00000000
 #define CX18_MEM_SIZE	0x04000000
 #define CX18_REG_OFFSET	0x02000000
@@ -77,7 +79,9 @@
 #define CX18_CARD_COMPRO_H900 	      2	/* Compro VideoMate H900 */
 #define CX18_CARD_YUAN_MPC718 	      3	/* Yuan MPC718 */
 #define CX18_CARD_CNXT_RAPTOR_PAL     4	/* Conexant Raptor PAL */
-#define CX18_CARD_LAST 		      4
+#define CX18_CARD_TOSHIBA_QOSMIO_DVBT 5 /* Toshiba Qosmio Interal DVB-T/Analog*/
+#define CX18_CARD_LEADTEK_PVR2100     6 /* Leadtek WinFast PVR2100 */
+#define CX18_CARD_LAST 		      6
 
 #define CX18_ENC_STREAM_TYPE_MPG  0
 #define CX18_ENC_STREAM_TYPE_TS   1
@@ -97,6 +101,8 @@
 #define CX18_PCI_ID_COMPRO 		0x185b
 #define CX18_PCI_ID_YUAN 		0x12ab
 #define CX18_PCI_ID_CONEXANT		0x14f1
+#define CX18_PCI_ID_TOSHIBA		0x1179
+#define CX18_PCI_ID_LEADTEK		0x107D
 
 /* ======================================================================== */
 /* ========================== START USER SETTABLE DMA VARIABLES =========== */
@@ -169,6 +175,7 @@
 
 #define CX18_MAX_PGM_INDEX (400)
 
+extern int cx18_retry_mmio;	/* enable check & retry of mmio accesses */
 extern int cx18_debug;
 
 
@@ -177,6 +184,7 @@
 	int cardtype;		/* force card type on load */
 	int tuner;		/* set tuner on load */
 	int radio;		/* enable/disable radio */
+	unsigned long mmio_ndelay; /* delay in ns after every PCI mmio access */
 };
 
 /* per-buffer bit flags */
@@ -216,8 +224,7 @@
 
 struct cx18_queue {
 	struct list_head list;
-	u32 buffers;
-	u32 length;
+	atomic_t buffers;
 	u32 bytesused;
 };
 
@@ -237,6 +244,8 @@
 struct cx18;	 /* forward reference */
 struct cx18_scb; /* forward reference */
 
+#define CX18_INVALID_TASK_HANDLE 0xffffffff
+
 struct cx18_stream {
 	/* These first four fields are always set, even if the stream
 	   is not actually created. */
@@ -259,7 +268,6 @@
 	/* Buffer Stats */
 	u32 buffers;
 	u32 buf_size;
-	u32 buffers_stolen;
 
 	/* Buffer Queues */
 	struct cx18_queue q_free;	/* free buffers */
@@ -341,6 +349,13 @@
 	int bus_index;   /* 0 or 1 for the cx23418's 1st or 2nd I2C bus */
 };
 
+#define CX18_MAX_MMIO_RETRIES 10
+
+struct cx18_mmio_stats {
+	atomic_t retried_write[CX18_MAX_MMIO_RETRIES+1];
+	atomic_t retried_read[CX18_MAX_MMIO_RETRIES+1];
+};
+
 /* Struct to hold info about cx18 cards */
 struct cx18 {
 	int num;		/* board number, -1 during init! */
@@ -430,6 +445,9 @@
 	u32 gpio_val;
 	struct mutex gpio_lock;
 
+	/* Statistics */
+	struct cx18_mmio_stats mmio_stats;
+
 	/* v4l2 and User settings */
 
 	/* codec settings */
@@ -458,47 +476,4 @@
 /* First-open initialization: load firmware, etc. */
 int cx18_init_on_first_open(struct cx18 *cx);
 
-/* This is a PCI post thing, where if the pci register is not read, then
-   the write doesn't always take effect right away. By reading back the
-   register any pending PCI writes will be performed (in order), and so
-   you can be sure that the writes are guaranteed to be done.
-
-   Rarely needed, only in some timing sensitive cases.
-   Apparently if this is not done some motherboards seem
-   to kill the firmware and get into the broken state until computer is
-   rebooted. */
-#define write_sync(val, reg) \
-	do { writel(val, reg); readl(reg); } while (0)
-
-#define read_reg(reg) readl(cx->reg_mem + (reg))
-#define write_reg(val, reg) writel(val, cx->reg_mem + (reg))
-#define write_reg_sync(val, reg) \
-	do { write_reg(val, reg); read_reg(reg); } while (0)
-
-#define read_enc(addr) readl(cx->enc_mem + (u32)(addr))
-#define write_enc(val, addr) writel(val, cx->enc_mem + (u32)(addr))
-#define write_enc_sync(val, addr) \
-	do { write_enc(val, addr); read_enc(addr); } while (0)
-
-#define sw1_irq_enable(val) do { \
-	write_reg(val, SW1_INT_STATUS); \
-	write_reg(read_reg(SW1_INT_ENABLE_PCI) | (val), SW1_INT_ENABLE_PCI); \
-} while (0)
-
-#define sw1_irq_disable(val) \
-	write_reg(read_reg(SW1_INT_ENABLE_PCI) & ~(val), SW1_INT_ENABLE_PCI);
-
-#define sw2_irq_enable(val) do { \
-	write_reg(val, SW2_INT_STATUS); \
-	write_reg(read_reg(SW2_INT_ENABLE_PCI) | (val), SW2_INT_ENABLE_PCI); \
-} while (0)
-
-#define sw2_irq_disable(val) \
-	write_reg(read_reg(SW2_INT_ENABLE_PCI) & ~(val), SW2_INT_ENABLE_PCI);
-
-#define setup_page(addr) do { \
-    u32 val = read_reg(0xD000F8) & ~0x1f00; \
-    write_reg(val | (((addr) >> 17) & 0x1f00), 0xD000F8); \
-} while (0)
-
 #endif /* CX18_DRIVER_H */
diff --git a/drivers/media/video/cx18/cx18-dvb.c b/drivers/media/video/cx18/cx18-dvb.c
index 1e420a8..afc694e 100644
--- a/drivers/media/video/cx18/cx18-dvb.c
+++ b/drivers/media/video/cx18/cx18-dvb.c
@@ -21,6 +21,7 @@
 
 #include "cx18-version.h"
 #include "cx18-dvb.h"
+#include "cx18-io.h"
 #include "cx18-streams.h"
 #include "cx18-cards.h"
 #include "s5h1409.h"
@@ -87,13 +88,13 @@
 	switch (cx->card->type) {
 	case CX18_CARD_HVR_1600_ESMT:
 	case CX18_CARD_HVR_1600_SAMSUNG:
-		v = read_reg(CX18_REG_DMUX_NUM_PORT_0_CONTROL);
+		v = cx18_read_reg(cx, CX18_REG_DMUX_NUM_PORT_0_CONTROL);
 		v |= 0x00400000; /* Serial Mode */
 		v |= 0x00002000; /* Data Length - Byte */
 		v |= 0x00010000; /* Error - Polarity */
 		v |= 0x00020000; /* Error - Passthru */
 		v |= 0x000c0000; /* Error - Ignore */
-		write_reg(v, CX18_REG_DMUX_NUM_PORT_0_CONTROL);
+		cx18_write_reg(cx, v, CX18_REG_DMUX_NUM_PORT_0_CONTROL);
 		break;
 
 	default:
diff --git a/drivers/media/video/cx18/cx18-fileops.c b/drivers/media/video/cx18/cx18-fileops.c
index 1e537fe..5f90899 100644
--- a/drivers/media/video/cx18/cx18-fileops.c
+++ b/drivers/media/video/cx18/cx18-fileops.c
@@ -132,6 +132,7 @@
 	u16 new_stereo_mode;
 	const u16 stereo_mask = 0x0300;
 	const u16 dual = 0x0200;
+	u32 h;
 
 	new_stereo_mode = cx->params.audio_properties & stereo_mask;
 	memset(&vt, 0, sizeof(vt));
@@ -143,13 +144,21 @@
 	if (new_stereo_mode == cx->dualwatch_stereo_mode)
 		return;
 
-	new_bitmap = new_stereo_mode | (cx->params.audio_properties & ~stereo_mask);
+	new_bitmap = new_stereo_mode
+			| (cx->params.audio_properties & ~stereo_mask);
 
-	CX18_DEBUG_INFO("dualwatch: change stereo flag from 0x%x to 0x%x. new audio_bitmask=0x%ux\n",
-			   cx->dualwatch_stereo_mode, new_stereo_mode, new_bitmap);
+	CX18_DEBUG_INFO("dualwatch: change stereo flag from 0x%x to 0x%x. "
+			"new audio_bitmask=0x%ux\n",
+			cx->dualwatch_stereo_mode, new_stereo_mode, new_bitmap);
 
-	if (cx18_vapi(cx, CX18_CPU_SET_AUDIO_PARAMETERS, 2,
-				cx18_find_handle(cx), new_bitmap) == 0) {
+	h = cx18_find_handle(cx);
+	if (h == CX18_INVALID_TASK_HANDLE) {
+		CX18_DEBUG_INFO("dualwatch: can't find valid task handle\n");
+		return;
+	}
+
+	if (cx18_vapi(cx,
+		      CX18_CPU_SET_AUDIO_PARAMETERS, 2, h, new_bitmap) == 0) {
 		cx->dualwatch_stereo_mode = new_stereo_mode;
 		return;
 	}
@@ -223,7 +232,7 @@
 		prepare_to_wait(&s->waitq, &wait, TASK_INTERRUPTIBLE);
 		/* New buffers might have become available before we were added
 		   to the waitqueue */
-		if (!s->q_full.buffers)
+		if (!atomic_read(&s->q_full.buffers))
 			schedule();
 		finish_wait(&s->waitq, &wait);
 		if (signal_pending(current)) {
@@ -509,7 +518,7 @@
 	CX18_DEBUG_HI_FILE("Encoder poll\n");
 	poll_wait(filp, &s->waitq, wait);
 
-	if (s->q_full.length || s->q_io.length)
+	if (atomic_read(&s->q_full.buffers) || atomic_read(&s->q_io.buffers))
 		return POLLIN | POLLRDNORM;
 	if (eof)
 		return POLLHUP;
@@ -695,20 +704,28 @@
 
 void cx18_mute(struct cx18 *cx)
 {
-	if (atomic_read(&cx->ana_capturing))
-		cx18_vapi(cx, CX18_CPU_SET_AUDIO_MUTE, 2,
-				cx18_find_handle(cx), 1);
+	u32 h;
+	if (atomic_read(&cx->ana_capturing)) {
+		h = cx18_find_handle(cx);
+		if (h != CX18_INVALID_TASK_HANDLE)
+			cx18_vapi(cx, CX18_CPU_SET_AUDIO_MUTE, 2, h, 1);
+		else
+			CX18_ERR("Can't find valid task handle for mute\n");
+	}
 	CX18_DEBUG_INFO("Mute\n");
 }
 
 void cx18_unmute(struct cx18 *cx)
 {
+	u32 h;
 	if (atomic_read(&cx->ana_capturing)) {
-		cx18_msleep_timeout(100, 0);
-		cx18_vapi(cx, CX18_CPU_SET_MISC_PARAMETERS, 2,
-				cx18_find_handle(cx), 12);
-		cx18_vapi(cx, CX18_CPU_SET_AUDIO_MUTE, 2,
-				cx18_find_handle(cx), 0);
+		h = cx18_find_handle(cx);
+		if (h != CX18_INVALID_TASK_HANDLE) {
+			cx18_msleep_timeout(100, 0);
+			cx18_vapi(cx, CX18_CPU_SET_MISC_PARAMETERS, 2, h, 12);
+			cx18_vapi(cx, CX18_CPU_SET_AUDIO_MUTE, 2, h, 0);
+		} else
+			CX18_ERR("Can't find valid task handle for unmute\n");
 	}
 	CX18_DEBUG_INFO("Unmute\n");
 }
diff --git a/drivers/media/video/cx18/cx18-firmware.c b/drivers/media/video/cx18/cx18-firmware.c
index 78fadd2..5153442 100644
--- a/drivers/media/video/cx18/cx18-firmware.c
+++ b/drivers/media/video/cx18/cx18-firmware.c
@@ -20,6 +20,7 @@
  */
 
 #include "cx18-driver.h"
+#include "cx18-io.h"
 #include "cx18-scb.h"
 #include "cx18-irq.h"
 #include "cx18-firmware.h"
@@ -113,11 +114,11 @@
 	src = (const u32 *)fw->data;
 
 	for (i = 0; i < fw->size; i += 4096) {
-		setup_page(i);
+		cx18_setup_page(cx, i);
 		for (j = i; j < fw->size && j < i + 4096; j += 4) {
 			/* no need for endianness conversion on the ppc */
-			__raw_writel(*src, dst);
-			if (__raw_readl(dst) != *src) {
+			cx18_raw_writel(cx, *src, dst);
+			if (cx18_raw_readl(cx, dst) != *src) {
 				CX18_ERR("Mismatch at offset %x\n", i);
 				release_firmware(fw);
 				return -EIO;
@@ -170,12 +171,15 @@
 		if (offset + seghdr.size > sz)
 			break;
 		for (i = 0; i < seghdr.size; i += 4096) {
-			setup_page(offset + i);
+			cx18_setup_page(cx, offset + i);
 			for (j = i; j < seghdr.size && j < i + 4096; j += 4) {
 				/* no need for endianness conversion on the ppc */
-				__raw_writel(src[(offset + j) / 4], dst + seghdr.addr + j);
-				if (__raw_readl(dst + seghdr.addr + j) != src[(offset + j) / 4]) {
-					CX18_ERR("Mismatch at offset %x\n", offset + j);
+				cx18_raw_writel(cx, src[(offset + j) / 4],
+						dst + seghdr.addr + j);
+				if (cx18_raw_readl(cx, dst + seghdr.addr + j)
+				    != src[(offset + j) / 4]) {
+					CX18_ERR("Mismatch at offset %x\n",
+						 offset + j);
 					release_firmware(fw);
 					return -EIO;
 				}
@@ -189,43 +193,45 @@
 	size = fw->size;
 	release_firmware(fw);
 	/* Clear bit0 for APU to start from 0 */
-	write_reg(read_reg(0xc72030) & ~1, 0xc72030);
+	cx18_write_reg(cx, cx18_read_reg(cx, 0xc72030) & ~1, 0xc72030);
 	return size;
 }
 
 void cx18_halt_firmware(struct cx18 *cx)
 {
 	CX18_DEBUG_INFO("Preparing for firmware halt.\n");
-	write_reg(0x000F000F, CX18_PROC_SOFT_RESET); /* stop the fw */
-	write_reg(0x00020002, CX18_ADEC_CONTROL);
+	cx18_write_reg(cx, 0x000F000F, CX18_PROC_SOFT_RESET); /* stop the fw */
+	cx18_write_reg(cx, 0x00020002, CX18_ADEC_CONTROL);
 }
 
 void cx18_init_power(struct cx18 *cx, int lowpwr)
 {
 	/* power-down Spare and AOM PLLs */
 	/* power-up fast, slow and mpeg PLLs */
-	write_reg(0x00000008, CX18_PLL_POWER_DOWN);
+	cx18_write_reg(cx, 0x00000008, CX18_PLL_POWER_DOWN);
 
 	/* ADEC out of sleep */
-	write_reg(0x00020000, CX18_ADEC_CONTROL);
+	cx18_write_reg(cx, 0x00020000, CX18_ADEC_CONTROL);
 
 	/* The fast clock is at 200/245 MHz */
-	write_reg(lowpwr ? 0xD : 0x11, CX18_FAST_CLOCK_PLL_INT);
-	write_reg(lowpwr ? 0x1EFBF37 : 0x038E3D7, CX18_FAST_CLOCK_PLL_FRAC);
+	cx18_write_reg(cx, lowpwr ? 0xD : 0x11, CX18_FAST_CLOCK_PLL_INT);
+	cx18_write_reg(cx, lowpwr ? 0x1EFBF37 : 0x038E3D7,
+						CX18_FAST_CLOCK_PLL_FRAC);
 
-	write_reg(2, CX18_FAST_CLOCK_PLL_POST);
-	write_reg(1, CX18_FAST_CLOCK_PLL_PRESCALE);
-	write_reg(4, CX18_FAST_CLOCK_PLL_ADJUST_BANDWIDTH);
+	cx18_write_reg(cx, 2, CX18_FAST_CLOCK_PLL_POST);
+	cx18_write_reg(cx, 1, CX18_FAST_CLOCK_PLL_PRESCALE);
+	cx18_write_reg(cx, 4, CX18_FAST_CLOCK_PLL_ADJUST_BANDWIDTH);
 
 	/* set slow clock to 125/120 MHz */
-	write_reg(lowpwr ? 0x11 : 0x10, CX18_SLOW_CLOCK_PLL_INT);
-	write_reg(lowpwr ? 0xEBAF05 : 0x18618A8, CX18_SLOW_CLOCK_PLL_FRAC);
-	write_reg(4, CX18_SLOW_CLOCK_PLL_POST);
+	cx18_write_reg(cx, lowpwr ? 0x11 : 0x10, CX18_SLOW_CLOCK_PLL_INT);
+	cx18_write_reg(cx, lowpwr ? 0xEBAF05 : 0x18618A8,
+						CX18_SLOW_CLOCK_PLL_FRAC);
+	cx18_write_reg(cx, 4, CX18_SLOW_CLOCK_PLL_POST);
 
 	/* mpeg clock pll 54MHz */
-	write_reg(0xF, CX18_MPEG_CLOCK_PLL_INT);
-	write_reg(0x2BCFEF, CX18_MPEG_CLOCK_PLL_FRAC);
-	write_reg(8, CX18_MPEG_CLOCK_PLL_POST);
+	cx18_write_reg(cx, 0xF, CX18_MPEG_CLOCK_PLL_INT);
+	cx18_write_reg(cx, 0x2BCFEF, CX18_MPEG_CLOCK_PLL_FRAC);
+	cx18_write_reg(cx, 8, CX18_MPEG_CLOCK_PLL_POST);
 
 	/* Defaults */
 	/* APU = SC or SC/2 = 125/62.5 */
@@ -242,81 +248,84 @@
 	/* VFC = disabled */
 	/* USB = disabled */
 
-	write_reg(lowpwr ? 0xFFFF0020 : 0x00060004, CX18_CLOCK_SELECT1);
-	write_reg(lowpwr ? 0xFFFF0004 : 0x00060006, CX18_CLOCK_SELECT2);
+	cx18_write_reg(cx, lowpwr ? 0xFFFF0020 : 0x00060004,
+							CX18_CLOCK_SELECT1);
+	cx18_write_reg(cx, lowpwr ? 0xFFFF0004 : 0x00060006,
+							CX18_CLOCK_SELECT2);
 
-	write_reg(0xFFFF0002, CX18_HALF_CLOCK_SELECT1);
-	write_reg(0xFFFF0104, CX18_HALF_CLOCK_SELECT2);
+	cx18_write_reg(cx, 0xFFFF0002, CX18_HALF_CLOCK_SELECT1);
+	cx18_write_reg(cx, 0xFFFF0104, CX18_HALF_CLOCK_SELECT2);
 
-	write_reg(0xFFFF9026, CX18_CLOCK_ENABLE1);
-	write_reg(0xFFFF3105, CX18_CLOCK_ENABLE2);
+	cx18_write_reg(cx, 0xFFFF9026, CX18_CLOCK_ENABLE1);
+	cx18_write_reg(cx, 0xFFFF3105, CX18_CLOCK_ENABLE2);
 }
 
 void cx18_init_memory(struct cx18 *cx)
 {
 	cx18_msleep_timeout(10, 0);
-	write_reg(0x10000, CX18_DDR_SOFT_RESET);
+	cx18_write_reg(cx, 0x10000, CX18_DDR_SOFT_RESET);
 	cx18_msleep_timeout(10, 0);
 
-	write_reg(cx->card->ddr.chip_config, CX18_DDR_CHIP_CONFIG);
+	cx18_write_reg(cx, cx->card->ddr.chip_config, CX18_DDR_CHIP_CONFIG);
 
 	cx18_msleep_timeout(10, 0);
 
-	write_reg(cx->card->ddr.refresh, CX18_DDR_REFRESH);
-	write_reg(cx->card->ddr.timing1, CX18_DDR_TIMING1);
-	write_reg(cx->card->ddr.timing2, CX18_DDR_TIMING2);
+	cx18_write_reg(cx, cx->card->ddr.refresh, CX18_DDR_REFRESH);
+	cx18_write_reg(cx, cx->card->ddr.timing1, CX18_DDR_TIMING1);
+	cx18_write_reg(cx, cx->card->ddr.timing2, CX18_DDR_TIMING2);
 
 	cx18_msleep_timeout(10, 0);
 
 	/* Initialize DQS pad time */
-	write_reg(cx->card->ddr.tune_lane, CX18_DDR_TUNE_LANE);
-	write_reg(cx->card->ddr.initial_emrs, CX18_DDR_INITIAL_EMRS);
+	cx18_write_reg(cx, cx->card->ddr.tune_lane, CX18_DDR_TUNE_LANE);
+	cx18_write_reg(cx, cx->card->ddr.initial_emrs, CX18_DDR_INITIAL_EMRS);
 
 	cx18_msleep_timeout(10, 0);
 
-	write_reg(0x20000, CX18_DDR_SOFT_RESET);
+	cx18_write_reg(cx, 0x20000, CX18_DDR_SOFT_RESET);
 	cx18_msleep_timeout(10, 0);
 
 	/* use power-down mode when idle */
-	write_reg(0x00000010, CX18_DDR_POWER_REG);
+	cx18_write_reg(cx, 0x00000010, CX18_DDR_POWER_REG);
 
-	write_reg(0x10001, CX18_REG_BUS_TIMEOUT_EN);
+	cx18_write_reg(cx, 0x10001, CX18_REG_BUS_TIMEOUT_EN);
 
-	write_reg(0x48, CX18_DDR_MB_PER_ROW_7);
-	write_reg(0xE0000, CX18_DDR_BASE_63_ADDR);
+	cx18_write_reg(cx, 0x48, CX18_DDR_MB_PER_ROW_7);
+	cx18_write_reg(cx, 0xE0000, CX18_DDR_BASE_63_ADDR);
 
-	write_reg(0x00000101, CX18_WMB_CLIENT02);  /* AO */
-	write_reg(0x00000101, CX18_WMB_CLIENT09);  /* AI2 */
-	write_reg(0x00000101, CX18_WMB_CLIENT05);  /* VIM1 */
-	write_reg(0x00000101, CX18_WMB_CLIENT06);  /* AI1 */
-	write_reg(0x00000101, CX18_WMB_CLIENT07);  /* 3D comb */
-	write_reg(0x00000101, CX18_WMB_CLIENT10);  /* ME */
-	write_reg(0x00000101, CX18_WMB_CLIENT12);  /* ENC */
-	write_reg(0x00000101, CX18_WMB_CLIENT13);  /* PK */
-	write_reg(0x00000101, CX18_WMB_CLIENT11);  /* RC */
-	write_reg(0x00000101, CX18_WMB_CLIENT14);  /* AVO */
+	cx18_write_reg(cx, 0x00000101, CX18_WMB_CLIENT02);  /* AO */
+	cx18_write_reg(cx, 0x00000101, CX18_WMB_CLIENT09);  /* AI2 */
+	cx18_write_reg(cx, 0x00000101, CX18_WMB_CLIENT05);  /* VIM1 */
+	cx18_write_reg(cx, 0x00000101, CX18_WMB_CLIENT06);  /* AI1 */
+	cx18_write_reg(cx, 0x00000101, CX18_WMB_CLIENT07);  /* 3D comb */
+	cx18_write_reg(cx, 0x00000101, CX18_WMB_CLIENT10);  /* ME */
+	cx18_write_reg(cx, 0x00000101, CX18_WMB_CLIENT12);  /* ENC */
+	cx18_write_reg(cx, 0x00000101, CX18_WMB_CLIENT13);  /* PK */
+	cx18_write_reg(cx, 0x00000101, CX18_WMB_CLIENT11);  /* RC */
+	cx18_write_reg(cx, 0x00000101, CX18_WMB_CLIENT14);  /* AVO */
 }
 
 int cx18_firmware_init(struct cx18 *cx)
 {
 	/* Allow chip to control CLKRUN */
-	write_reg(0x5, CX18_DSP0_INTERRUPT_MASK);
+	cx18_write_reg(cx, 0x5, CX18_DSP0_INTERRUPT_MASK);
 
-	write_reg(0x000F000F, CX18_PROC_SOFT_RESET); /* stop the fw */
+	cx18_write_reg(cx, 0x000F000F, CX18_PROC_SOFT_RESET); /* stop the fw */
 
 	cx18_msleep_timeout(1, 0);
 
-	sw1_irq_enable(IRQ_CPU_TO_EPU | IRQ_APU_TO_EPU);
-	sw2_irq_enable(IRQ_CPU_TO_EPU_ACK | IRQ_APU_TO_EPU_ACK);
+	cx18_sw1_irq_enable(cx, IRQ_CPU_TO_EPU | IRQ_APU_TO_EPU);
+	cx18_sw2_irq_enable(cx, IRQ_CPU_TO_EPU_ACK | IRQ_APU_TO_EPU_ACK);
 
 	/* Only if the processor is not running */
-	if (read_reg(CX18_PROC_SOFT_RESET) & 8) {
+	if (cx18_read_reg(cx, CX18_PROC_SOFT_RESET) & 8) {
 		int sz = load_apu_fw_direct("v4l-cx23418-apu.fw",
 			       cx->enc_mem, cx);
 
-		write_enc(0xE51FF004, 0);
-		write_enc(0xa00000, 4);  /* todo: not hardcoded */
-		write_reg(0x00010000, CX18_PROC_SOFT_RESET); /* Start APU */
+		cx18_write_enc(cx, 0xE51FF004, 0);
+		cx18_write_enc(cx, 0xa00000, 4);  /* todo: not hardcoded */
+		/* Start APU */
+		cx18_write_reg(cx, 0x00010000, CX18_PROC_SOFT_RESET);
 		cx18_msleep_timeout(500, 0);
 
 		sz = sz <= 0 ? sz : load_cpu_fw_direct("v4l-cx23418-cpu.fw",
@@ -326,9 +335,10 @@
 			int retries = 0;
 
 			/* start the CPU */
-			write_reg(0x00080000, CX18_PROC_SOFT_RESET);
+			cx18_write_reg(cx, 0x00080000, CX18_PROC_SOFT_RESET);
 			while (retries++ < 50) { /* Loop for max 500mS */
-				if ((read_reg(CX18_PROC_SOFT_RESET) & 1) == 0)
+				if ((cx18_read_reg(cx, CX18_PROC_SOFT_RESET)
+				     & 1) == 0)
 					break;
 				cx18_msleep_timeout(10, 0);
 			}
@@ -342,6 +352,6 @@
 			return -EIO;
 	}
 	/* initialize GPIO */
-	write_reg(0x14001400, 0xC78110);
+	cx18_write_reg(cx, 0x14001400, 0xC78110);
 	return 0;
 }
diff --git a/drivers/media/video/cx18/cx18-gpio.c b/drivers/media/video/cx18/cx18-gpio.c
index 3d495db..0e56042 100644
--- a/drivers/media/video/cx18/cx18-gpio.c
+++ b/drivers/media/video/cx18/cx18-gpio.c
@@ -22,6 +22,7 @@
  */
 
 #include "cx18-driver.h"
+#include "cx18-io.h"
 #include "cx18-cards.h"
 #include "cx18-gpio.h"
 #include "tuner-xc2028.h"
@@ -49,11 +50,11 @@
 	u32 dir = cx->gpio_dir;
 	u32 val = cx->gpio_val;
 
-	write_reg((dir & 0xffff) << 16, CX18_REG_GPIO_DIR1);
-	write_reg(((dir & 0xffff) << 16) | (val & 0xffff),
+	cx18_write_reg(cx, (dir & 0xffff) << 16, CX18_REG_GPIO_DIR1);
+	cx18_write_reg(cx, ((dir & 0xffff) << 16) | (val & 0xffff),
 			CX18_REG_GPIO_OUT1);
-	write_reg(dir & 0xffff0000, CX18_REG_GPIO_DIR2);
-	write_reg_sync((dir & 0xffff0000) | ((val & 0xffff0000) >> 16),
+	cx18_write_reg(cx, dir & 0xffff0000, CX18_REG_GPIO_DIR2);
+	cx18_write_reg_sync(cx, (dir & 0xffff0000) | ((val & 0xffff0000) >> 16),
 			CX18_REG_GPIO_OUT2);
 }
 
@@ -141,15 +142,17 @@
 	}
 
 	CX18_DEBUG_INFO("GPIO initial dir: %08x/%08x out: %08x/%08x\n",
-		   read_reg(CX18_REG_GPIO_DIR1), read_reg(CX18_REG_GPIO_DIR2),
-		   read_reg(CX18_REG_GPIO_OUT1), read_reg(CX18_REG_GPIO_OUT2));
+			cx18_read_reg(cx, CX18_REG_GPIO_DIR1),
+			cx18_read_reg(cx, CX18_REG_GPIO_DIR2),
+			cx18_read_reg(cx, CX18_REG_GPIO_OUT1),
+			cx18_read_reg(cx, CX18_REG_GPIO_OUT2));
 
 	gpio_write(cx);
 	mutex_unlock(&cx->gpio_lock);
 }
 
 /* Xceive tuner reset function */
-int cx18_reset_tuner_gpio(void *dev, int cmd, int value)
+int cx18_reset_tuner_gpio(void *dev, int component, int cmd, int value)
 {
 	struct i2c_algo_bit_data *algo = dev;
 	struct cx18_i2c_algo_callback_data *cb_data = algo->data;
diff --git a/drivers/media/video/cx18/cx18-gpio.h b/drivers/media/video/cx18/cx18-gpio.h
index 22cd7dd..beb7424 100644
--- a/drivers/media/video/cx18/cx18-gpio.h
+++ b/drivers/media/video/cx18/cx18-gpio.h
@@ -23,5 +23,5 @@
 void cx18_gpio_init(struct cx18 *cx);
 void cx18_reset_i2c_slaves_gpio(struct cx18 *cx);
 void cx18_reset_ir_gpio(void *data);
-int cx18_reset_tuner_gpio(void *dev, int cmd, int value);
+int cx18_reset_tuner_gpio(void *dev, int component, int cmd, int value);
 int cx18_gpio(struct cx18 *cx, unsigned int command, void *arg);
diff --git a/drivers/media/video/cx18/cx18-i2c.c b/drivers/media/video/cx18/cx18-i2c.c
index 6023ba3..aa09e55 100644
--- a/drivers/media/video/cx18/cx18-i2c.c
+++ b/drivers/media/video/cx18/cx18-i2c.c
@@ -22,13 +22,12 @@
  */
 
 #include "cx18-driver.h"
+#include "cx18-io.h"
 #include "cx18-cards.h"
 #include "cx18-gpio.h"
 #include "cx18-av-core.h"
 #include "cx18-i2c.h"
 
-#include <media/ir-kbd-i2c.h>
-
 #define CX18_REG_I2C_1_WR   0xf15000
 #define CX18_REG_I2C_1_RD   0xf15008
 #define CX18_REG_I2C_2_WR   0xf25100
@@ -158,12 +157,12 @@
 	struct cx18 *cx = ((struct cx18_i2c_algo_callback_data *)data)->cx;
 	int bus_index = ((struct cx18_i2c_algo_callback_data *)data)->bus_index;
 	u32 addr = bus_index ? CX18_REG_I2C_2_WR : CX18_REG_I2C_1_WR;
-	u32 r = read_reg(addr);
+	u32 r = cx18_read_reg(cx, addr);
 
 	if (state)
-		write_reg_sync(r | SETSCL_BIT, addr);
+		cx18_write_reg_sync(cx, r | SETSCL_BIT, addr);
 	else
-		write_reg_sync(r & ~SETSCL_BIT, addr);
+		cx18_write_reg_sync(cx, r & ~SETSCL_BIT, addr);
 }
 
 static void cx18_setsda(void *data, int state)
@@ -171,12 +170,12 @@
 	struct cx18 *cx = ((struct cx18_i2c_algo_callback_data *)data)->cx;
 	int bus_index = ((struct cx18_i2c_algo_callback_data *)data)->bus_index;
 	u32 addr = bus_index ? CX18_REG_I2C_2_WR : CX18_REG_I2C_1_WR;
-	u32 r = read_reg(addr);
+	u32 r = cx18_read_reg(cx, addr);
 
 	if (state)
-		write_reg_sync(r | SETSDL_BIT, addr);
+		cx18_write_reg_sync(cx, r | SETSDL_BIT, addr);
 	else
-		write_reg_sync(r & ~SETSDL_BIT, addr);
+		cx18_write_reg_sync(cx, r & ~SETSDL_BIT, addr);
 }
 
 static int cx18_getscl(void *data)
@@ -185,7 +184,7 @@
 	int bus_index = ((struct cx18_i2c_algo_callback_data *)data)->bus_index;
 	u32 addr = bus_index ? CX18_REG_I2C_2_RD : CX18_REG_I2C_1_RD;
 
-	return read_reg(addr) & GETSCL_BIT;
+	return cx18_read_reg(cx, addr) & GETSCL_BIT;
 }
 
 static int cx18_getsda(void *data)
@@ -194,7 +193,7 @@
 	int bus_index = ((struct cx18_i2c_algo_callback_data *)data)->bus_index;
 	u32 addr = bus_index ? CX18_REG_I2C_2_RD : CX18_REG_I2C_1_RD;
 
-	return read_reg(addr) & GETSDL_BIT;
+	return cx18_read_reg(cx, addr) & GETSDL_BIT;
 }
 
 /* template for i2c-bit-algo */
@@ -394,29 +393,33 @@
 		cx->i2c_adap[i].dev.parent = &cx->dev->dev;
 	}
 
-	if (read_reg(CX18_REG_I2C_2_WR) != 0x0003c02f) {
+	if (cx18_read_reg(cx, CX18_REG_I2C_2_WR) != 0x0003c02f) {
 		/* Reset/Unreset I2C hardware block */
-		write_reg(0x10000000, 0xc71004); /* Clock select 220MHz */
-		write_reg_sync(0x10001000, 0xc71024); /* Clock Enable */
+		/* Clock select 220MHz */
+		cx18_write_reg(cx, 0x10000000, 0xc71004);
+		/* Clock Enable */
+		cx18_write_reg_sync(cx, 0x10001000, 0xc71024);
 	}
 	/* courtesy of Steven Toth <stoth@hauppauge.com> */
-	write_reg_sync(0x00c00000, 0xc7001c);
+	cx18_write_reg_sync(cx, 0x00c00000, 0xc7001c);
 	mdelay(10);
-	write_reg_sync(0x00c000c0, 0xc7001c);
+	cx18_write_reg_sync(cx, 0x00c000c0, 0xc7001c);
 	mdelay(10);
-	write_reg_sync(0x00c00000, 0xc7001c);
+	cx18_write_reg_sync(cx, 0x00c00000, 0xc7001c);
 	mdelay(10);
 
-	write_reg_sync(0x00c00000, 0xc730c8); /* Set to edge-triggered intrs. */
-	write_reg_sync(0x00c00000, 0xc730c4); /* Clear any stale intrs */
+	/* Set to edge-triggered intrs. */
+	cx18_write_reg_sync(cx, 0x00c00000, 0xc730c8);
+	/* Clear any stale intrs */
+	cx18_write_reg_sync(cx, 0x00c00000, 0xc730c4);
 
 	/* Hw I2C1 Clock Freq ~100kHz */
-	write_reg_sync(0x00021c0f & ~4, CX18_REG_I2C_1_WR);
+	cx18_write_reg_sync(cx, 0x00021c0f & ~4, CX18_REG_I2C_1_WR);
 	cx18_setscl(&cx->i2c_algo_cb_data[0], 1);
 	cx18_setsda(&cx->i2c_algo_cb_data[0], 1);
 
 	/* Hw I2C2 Clock Freq ~100kHz */
-	write_reg_sync(0x00021c0f & ~4, CX18_REG_I2C_2_WR);
+	cx18_write_reg_sync(cx, 0x00021c0f & ~4, CX18_REG_I2C_2_WR);
 	cx18_setscl(&cx->i2c_algo_cb_data[1], 1);
 	cx18_setsda(&cx->i2c_algo_cb_data[1], 1);
 
@@ -430,8 +433,10 @@
 {
 	int i;
 	CX18_DEBUG_I2C("i2c exit\n");
-	write_reg(read_reg(CX18_REG_I2C_1_WR) | 4, CX18_REG_I2C_1_WR);
-	write_reg(read_reg(CX18_REG_I2C_2_WR) | 4, CX18_REG_I2C_2_WR);
+	cx18_write_reg(cx, cx18_read_reg(cx, CX18_REG_I2C_1_WR) | 4,
+							CX18_REG_I2C_1_WR);
+	cx18_write_reg(cx, cx18_read_reg(cx, CX18_REG_I2C_2_WR) | 4,
+							CX18_REG_I2C_2_WR);
 
 	for (i = 0; i < 2; i++) {
 		i2c_del_adapter(&cx->i2c_adap[i]);
diff --git a/drivers/media/video/cx18/cx18-io.c b/drivers/media/video/cx18/cx18-io.c
new file mode 100644
index 0000000..700ab94
--- /dev/null
+++ b/drivers/media/video/cx18/cx18-io.c
@@ -0,0 +1,254 @@
+/*
+ *  cx18 driver PCI memory mapped IO access routines
+ *
+ *  Copyright (C) 2007  Hans Verkuil <hverkuil@xs4all.nl>
+ *  Copyright (C) 2008  Andy Walls <awalls@radix.net>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU 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 "cx18-driver.h"
+#include "cx18-io.h"
+#include "cx18-irq.h"
+
+void cx18_log_statistics(struct cx18 *cx)
+{
+	int i;
+
+	if (!(cx18_debug & CX18_DBGFLG_INFO))
+		return;
+
+	for (i = 0; i <= CX18_MAX_MMIO_RETRIES; i++)
+		CX18_DEBUG_INFO("retried_write[%d] = %d\n", i,
+				atomic_read(&cx->mmio_stats.retried_write[i]));
+	for (i = 0; i <= CX18_MAX_MMIO_RETRIES; i++)
+		CX18_DEBUG_INFO("retried_read[%d] = %d\n", i,
+				atomic_read(&cx->mmio_stats.retried_read[i]));
+	return;
+}
+
+void cx18_raw_writel_retry(struct cx18 *cx, u32 val, void __iomem *addr)
+{
+	int i;
+	for (i = 0; i < CX18_MAX_MMIO_RETRIES; i++) {
+		cx18_raw_writel_noretry(cx, val, addr);
+		if (val == cx18_raw_readl_noretry(cx, addr))
+			break;
+	}
+	cx18_log_write_retries(cx, i, addr);
+}
+
+u32 cx18_raw_readl_retry(struct cx18 *cx, const void __iomem *addr)
+{
+	int i;
+	u32 val;
+	for (i = 0; i < CX18_MAX_MMIO_RETRIES; i++) {
+		val = cx18_raw_readl_noretry(cx, addr);
+		if (val != 0xffffffff) /* PCI bus read error */
+			break;
+	}
+	cx18_log_read_retries(cx, i, addr);
+	return val;
+}
+
+u16 cx18_raw_readw_retry(struct cx18 *cx, const void __iomem *addr)
+{
+	int i;
+	u16 val;
+	for (i = 0; i < CX18_MAX_MMIO_RETRIES; i++) {
+		val = cx18_raw_readw_noretry(cx, addr);
+		if (val != 0xffff) /* PCI bus read error */
+			break;
+	}
+	cx18_log_read_retries(cx, i, addr);
+	return val;
+}
+
+void cx18_writel_retry(struct cx18 *cx, u32 val, void __iomem *addr)
+{
+	int i;
+	for (i = 0; i < CX18_MAX_MMIO_RETRIES; i++) {
+		cx18_writel_noretry(cx, val, addr);
+		if (val == cx18_readl_noretry(cx, addr))
+			break;
+	}
+	cx18_log_write_retries(cx, i, addr);
+}
+
+void cx18_writew_retry(struct cx18 *cx, u16 val, void __iomem *addr)
+{
+	int i;
+	for (i = 0; i < CX18_MAX_MMIO_RETRIES; i++) {
+		cx18_writew_noretry(cx, val, addr);
+		if (val == cx18_readw_noretry(cx, addr))
+			break;
+	}
+	cx18_log_write_retries(cx, i, addr);
+}
+
+void cx18_writeb_retry(struct cx18 *cx, u8 val, void __iomem *addr)
+{
+	int i;
+	for (i = 0; i < CX18_MAX_MMIO_RETRIES; i++) {
+		cx18_writeb_noretry(cx, val, addr);
+		if (val == cx18_readb_noretry(cx, addr))
+			break;
+	}
+	cx18_log_write_retries(cx, i, addr);
+}
+
+u32 cx18_readl_retry(struct cx18 *cx, const void __iomem *addr)
+{
+	int i;
+	u32 val;
+	for (i = 0; i < CX18_MAX_MMIO_RETRIES; i++) {
+		val = cx18_readl_noretry(cx, addr);
+		if (val != 0xffffffff) /* PCI bus read error */
+			break;
+	}
+	cx18_log_read_retries(cx, i, addr);
+	return val;
+}
+
+u16 cx18_readw_retry(struct cx18 *cx, const void __iomem *addr)
+{
+	int i;
+	u16 val;
+	for (i = 0; i < CX18_MAX_MMIO_RETRIES; i++) {
+		val = cx18_readw_noretry(cx, addr);
+		if (val != 0xffff) /* PCI bus read error */
+			break;
+	}
+	cx18_log_read_retries(cx, i, addr);
+	return val;
+}
+
+u8 cx18_readb_retry(struct cx18 *cx, const void __iomem *addr)
+{
+	int i;
+	u8 val;
+	for (i = 0; i < CX18_MAX_MMIO_RETRIES; i++) {
+		val = cx18_readb_noretry(cx, addr);
+		if (val != 0xff) /* PCI bus read error */
+			break;
+	}
+	cx18_log_read_retries(cx, i, addr);
+	return val;
+}
+
+void cx18_memcpy_fromio(struct cx18 *cx, void *to,
+			const void __iomem *from, unsigned int len)
+{
+	const u8 __iomem *src = from;
+	u8 *dst = to;
+
+	/* Align reads on the CX23418's addresses */
+	if ((len > 0) && ((unsigned long) src & 1)) {
+		*dst = cx18_readb(cx, src);
+		len--;
+		dst++;
+		src++;
+	}
+	if ((len > 1) && ((unsigned long) src & 2)) {
+		*((u16 *)dst) = cx18_raw_readw(cx, src);
+		len -= 2;
+		dst += 2;
+		src += 2;
+	}
+	while (len > 3) {
+		*((u32 *)dst) = cx18_raw_readl(cx, src);
+		len -= 4;
+		dst += 4;
+		src += 4;
+	}
+	if (len > 1) {
+		*((u16 *)dst) = cx18_raw_readw(cx, src);
+		len -= 2;
+		dst += 2;
+		src += 2;
+	}
+	if (len > 0)
+		*dst = cx18_readb(cx, src);
+}
+
+void cx18_memset_io(struct cx18 *cx, void __iomem *addr, int val, size_t count)
+{
+	u8 __iomem *dst = addr;
+	u16 val2 = val | (val << 8);
+	u32 val4 = val2 | (val2 << 16);
+
+	/* Align writes on the CX23418's addresses */
+	if ((count > 0) && ((unsigned long)dst & 1)) {
+		cx18_writeb(cx, (u8) val, dst);
+		count--;
+		dst++;
+	}
+	if ((count > 1) && ((unsigned long)dst & 2)) {
+		cx18_writew(cx, val2, dst);
+		count -= 2;
+		dst += 2;
+	}
+	while (count > 3) {
+		cx18_writel(cx, val4, dst);
+		count -= 4;
+		dst += 4;
+	}
+	if (count > 1) {
+		cx18_writew(cx, val2, dst);
+		count -= 2;
+		dst += 2;
+	}
+	if (count > 0)
+		cx18_writeb(cx, (u8) val, dst);
+}
+
+void cx18_sw1_irq_enable(struct cx18 *cx, u32 val)
+{
+	u32 r;
+	cx18_write_reg(cx, val, SW1_INT_STATUS);
+	r = cx18_read_reg(cx, SW1_INT_ENABLE_PCI);
+	cx18_write_reg(cx, r | val, SW1_INT_ENABLE_PCI);
+}
+
+void cx18_sw1_irq_disable(struct cx18 *cx, u32 val)
+{
+	u32 r;
+	r = cx18_read_reg(cx, SW1_INT_ENABLE_PCI);
+	cx18_write_reg(cx, r & ~val, SW1_INT_ENABLE_PCI);
+}
+
+void cx18_sw2_irq_enable(struct cx18 *cx, u32 val)
+{
+	u32 r;
+	cx18_write_reg(cx, val, SW2_INT_STATUS);
+	r = cx18_read_reg(cx, SW2_INT_ENABLE_PCI);
+	cx18_write_reg(cx, r | val, SW2_INT_ENABLE_PCI);
+}
+
+void cx18_sw2_irq_disable(struct cx18 *cx, u32 val)
+{
+	u32 r;
+	r = cx18_read_reg(cx, SW2_INT_ENABLE_PCI);
+	cx18_write_reg(cx, r & ~val, SW2_INT_ENABLE_PCI);
+}
+
+void cx18_setup_page(struct cx18 *cx, u32 addr)
+{
+	u32 val;
+	val = cx18_read_reg(cx, 0xD000F8);
+	val = (val & ~0x1f00) | ((addr >> 17) & 0x1f00);
+	cx18_write_reg(cx, val, 0xD000F8);
+}
diff --git a/drivers/media/video/cx18/cx18-io.h b/drivers/media/video/cx18/cx18-io.h
new file mode 100644
index 0000000..197d4fbd
--- /dev/null
+++ b/drivers/media/video/cx18/cx18-io.h
@@ -0,0 +1,378 @@
+/*
+ *  cx18 driver PCI memory mapped IO access routines
+ *
+ *  Copyright (C) 2007  Hans Verkuil <hverkuil@xs4all.nl>
+ *  Copyright (C) 2008  Andy Walls <awalls@radix.net>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU 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 CX18_IO_H
+#define CX18_IO_H
+
+#include "cx18-driver.h"
+
+static inline void cx18_io_delay(struct cx18 *cx)
+{
+	if (cx->options.mmio_ndelay)
+		ndelay(cx->options.mmio_ndelay);
+}
+
+/*
+ * Readback and retry of MMIO access for reliability:
+ * The concept was suggested by Steve Toth <stoth@linuxtv.org>.
+ * The implmentation is the fault of Andy Walls <awalls@radix.net>.
+ */
+
+/* Statistics gathering */
+static inline
+void cx18_log_write_retries(struct cx18 *cx, int i, const void *addr)
+{
+	if (i > CX18_MAX_MMIO_RETRIES)
+		i = CX18_MAX_MMIO_RETRIES;
+	atomic_inc(&cx->mmio_stats.retried_write[i]);
+	return;
+}
+
+static inline
+void cx18_log_read_retries(struct cx18 *cx, int i, const void *addr)
+{
+	if (i > CX18_MAX_MMIO_RETRIES)
+		i = CX18_MAX_MMIO_RETRIES;
+	atomic_inc(&cx->mmio_stats.retried_read[i]);
+	return;
+}
+
+void cx18_log_statistics(struct cx18 *cx);
+
+/* Non byteswapping memory mapped IO */
+static inline
+void cx18_raw_writel_noretry(struct cx18 *cx, u32 val, void __iomem *addr)
+{
+	__raw_writel(val, addr);
+	cx18_io_delay(cx);
+}
+
+void cx18_raw_writel_retry(struct cx18 *cx, u32 val, void __iomem *addr);
+
+static inline void cx18_raw_writel(struct cx18 *cx, u32 val, void __iomem *addr)
+{
+	if (cx18_retry_mmio)
+		cx18_raw_writel_retry(cx, val, addr);
+	else
+		cx18_raw_writel_noretry(cx, val, addr);
+}
+
+
+static inline
+u32 cx18_raw_readl_noretry(struct cx18 *cx, const void __iomem *addr)
+{
+	u32 ret = __raw_readl(addr);
+	cx18_io_delay(cx);
+	return ret;
+}
+
+u32 cx18_raw_readl_retry(struct cx18 *cx, const void __iomem *addr);
+
+static inline u32 cx18_raw_readl(struct cx18 *cx, const void __iomem *addr)
+{
+	if (cx18_retry_mmio)
+		return cx18_raw_readl_retry(cx, addr);
+
+	return cx18_raw_readl_noretry(cx, addr);
+}
+
+
+static inline
+u16 cx18_raw_readw_noretry(struct cx18 *cx, const void __iomem *addr)
+{
+	u16 ret = __raw_readw(addr);
+	cx18_io_delay(cx);
+	return ret;
+}
+
+u16 cx18_raw_readw_retry(struct cx18 *cx, const void __iomem *addr);
+
+static inline u16 cx18_raw_readw(struct cx18 *cx, const void __iomem *addr)
+{
+	if (cx18_retry_mmio)
+		return cx18_raw_readw_retry(cx, addr);
+
+	return cx18_raw_readw_noretry(cx, addr);
+}
+
+
+/* Normal memory mapped IO */
+static inline
+void cx18_writel_noretry(struct cx18 *cx, u32 val, void __iomem *addr)
+{
+	writel(val, addr);
+	cx18_io_delay(cx);
+}
+
+void cx18_writel_retry(struct cx18 *cx, u32 val, void __iomem *addr);
+
+static inline void cx18_writel(struct cx18 *cx, u32 val, void __iomem *addr)
+{
+	if (cx18_retry_mmio)
+		cx18_writel_retry(cx, val, addr);
+	else
+		cx18_writel_noretry(cx, val, addr);
+}
+
+
+static inline
+void cx18_writew_noretry(struct cx18 *cx, u16 val, void __iomem *addr)
+{
+	writew(val, addr);
+	cx18_io_delay(cx);
+}
+
+void cx18_writew_retry(struct cx18 *cx, u16 val, void __iomem *addr);
+
+static inline void cx18_writew(struct cx18 *cx, u16 val, void __iomem *addr)
+{
+	if (cx18_retry_mmio)
+		cx18_writew_retry(cx, val, addr);
+	else
+		cx18_writew_noretry(cx, val, addr);
+}
+
+
+static inline
+void cx18_writeb_noretry(struct cx18 *cx, u8 val, void __iomem *addr)
+{
+	writeb(val, addr);
+	cx18_io_delay(cx);
+}
+
+void cx18_writeb_retry(struct cx18 *cx, u8 val, void __iomem *addr);
+
+static inline void cx18_writeb(struct cx18 *cx, u8 val, void __iomem *addr)
+{
+	if (cx18_retry_mmio)
+		cx18_writeb_retry(cx, val, addr);
+	else
+		cx18_writeb_noretry(cx, val, addr);
+}
+
+
+static inline u32 cx18_readl_noretry(struct cx18 *cx, const void __iomem *addr)
+{
+	u32 ret = readl(addr);
+	cx18_io_delay(cx);
+	return ret;
+}
+
+u32 cx18_readl_retry(struct cx18 *cx, const void __iomem *addr);
+
+static inline u32 cx18_readl(struct cx18 *cx, const void __iomem *addr)
+{
+	if (cx18_retry_mmio)
+		return cx18_readl_retry(cx, addr);
+
+	return cx18_readl_noretry(cx, addr);
+}
+
+
+static inline u16 cx18_readw_noretry(struct cx18 *cx, const void __iomem *addr)
+{
+	u16 ret = readw(addr);
+	cx18_io_delay(cx);
+	return ret;
+}
+
+u16 cx18_readw_retry(struct cx18 *cx, const void __iomem *addr);
+
+static inline u16 cx18_readw(struct cx18 *cx, const void __iomem *addr)
+{
+	if (cx18_retry_mmio)
+		return cx18_readw_retry(cx, addr);
+
+	return cx18_readw_noretry(cx, addr);
+}
+
+
+static inline u8 cx18_readb_noretry(struct cx18 *cx, const void __iomem *addr)
+{
+	u8 ret = readb(addr);
+	cx18_io_delay(cx);
+	return ret;
+}
+
+u8 cx18_readb_retry(struct cx18 *cx, const void __iomem *addr);
+
+static inline u8 cx18_readb(struct cx18 *cx, const void __iomem *addr)
+{
+	if (cx18_retry_mmio)
+		return cx18_readb_retry(cx, addr);
+
+	return cx18_readb_noretry(cx, addr);
+}
+
+
+static inline
+u32 cx18_write_sync_noretry(struct cx18 *cx, u32 val, void __iomem *addr)
+{
+	cx18_writel_noretry(cx, val, addr);
+	return cx18_readl_noretry(cx, addr);
+}
+
+static inline
+u32 cx18_write_sync_retry(struct cx18 *cx, u32 val, void __iomem *addr)
+{
+	cx18_writel_retry(cx, val, addr);
+	return cx18_readl_retry(cx, addr);
+}
+
+static inline u32 cx18_write_sync(struct cx18 *cx, u32 val, void __iomem *addr)
+{
+	if (cx18_retry_mmio)
+		return cx18_write_sync_retry(cx, val, addr);
+
+	return cx18_write_sync_noretry(cx, val, addr);
+}
+
+
+void cx18_memcpy_fromio(struct cx18 *cx, void *to,
+			const void __iomem *from, unsigned int len);
+void cx18_memset_io(struct cx18 *cx, void __iomem *addr, int val, size_t count);
+
+
+/* Access "register" region of CX23418 memory mapped I/O */
+static inline void cx18_write_reg_noretry(struct cx18 *cx, u32 val, u32 reg)
+{
+	cx18_writel_noretry(cx, val, cx->reg_mem + reg);
+}
+
+static inline void cx18_write_reg_retry(struct cx18 *cx, u32 val, u32 reg)
+{
+	cx18_writel_retry(cx, val, cx->reg_mem + reg);
+}
+
+static inline void cx18_write_reg(struct cx18 *cx, u32 val, u32 reg)
+{
+	if (cx18_retry_mmio)
+		cx18_write_reg_retry(cx, val, reg);
+	else
+		cx18_write_reg_noretry(cx, val, reg);
+}
+
+
+static inline u32 cx18_read_reg_noretry(struct cx18 *cx, u32 reg)
+{
+	return cx18_readl_noretry(cx, cx->reg_mem + reg);
+}
+
+static inline u32 cx18_read_reg_retry(struct cx18 *cx, u32 reg)
+{
+	return cx18_readl_retry(cx, cx->reg_mem + reg);
+}
+
+static inline u32 cx18_read_reg(struct cx18 *cx, u32 reg)
+{
+	if (cx18_retry_mmio)
+		return cx18_read_reg_retry(cx, reg);
+
+	return cx18_read_reg_noretry(cx, reg);
+}
+
+
+static inline u32 cx18_write_reg_sync_noretry(struct cx18 *cx, u32 val, u32 reg)
+{
+	return cx18_write_sync_noretry(cx, val, cx->reg_mem + reg);
+}
+
+static inline u32 cx18_write_reg_sync_retry(struct cx18 *cx, u32 val, u32 reg)
+{
+	return cx18_write_sync_retry(cx, val, cx->reg_mem + reg);
+}
+
+static inline u32 cx18_write_reg_sync(struct cx18 *cx, u32 val, u32 reg)
+{
+	if (cx18_retry_mmio)
+		return cx18_write_reg_sync_retry(cx, val, reg);
+
+	return cx18_write_reg_sync_noretry(cx, val, reg);
+}
+
+
+/* Access "encoder memory" region of CX23418 memory mapped I/O */
+static inline void cx18_write_enc_noretry(struct cx18 *cx, u32 val, u32 addr)
+{
+	cx18_writel_noretry(cx, val, cx->enc_mem + addr);
+}
+
+static inline void cx18_write_enc_retry(struct cx18 *cx, u32 val, u32 addr)
+{
+	cx18_writel_retry(cx, val, cx->enc_mem + addr);
+}
+
+static inline void cx18_write_enc(struct cx18 *cx, u32 val, u32 addr)
+{
+	if (cx18_retry_mmio)
+		cx18_write_enc_retry(cx, val, addr);
+	else
+		cx18_write_enc_noretry(cx, val, addr);
+}
+
+
+static inline u32 cx18_read_enc_noretry(struct cx18 *cx, u32 addr)
+{
+	return cx18_readl_noretry(cx, cx->enc_mem + addr);
+}
+
+static inline u32 cx18_read_enc_retry(struct cx18 *cx, u32 addr)
+{
+	return cx18_readl_retry(cx, cx->enc_mem + addr);
+}
+
+static inline u32 cx18_read_enc(struct cx18 *cx, u32 addr)
+{
+	if (cx18_retry_mmio)
+		return cx18_read_enc_retry(cx, addr);
+
+	return cx18_read_enc_noretry(cx, addr);
+}
+
+static inline
+u32 cx18_write_enc_sync_noretry(struct cx18 *cx, u32 val, u32 addr)
+{
+	return cx18_write_sync_noretry(cx, val, cx->enc_mem + addr);
+}
+
+static inline
+u32 cx18_write_enc_sync_retry(struct cx18 *cx, u32 val, u32 addr)
+{
+	return cx18_write_sync_retry(cx, val, cx->enc_mem + addr);
+}
+
+static inline
+u32 cx18_write_enc_sync(struct cx18 *cx, u32 val, u32 addr)
+{
+	if (cx18_retry_mmio)
+		return cx18_write_enc_sync_retry(cx, val, addr);
+
+	return cx18_write_enc_sync_noretry(cx, val, addr);
+}
+
+void cx18_sw1_irq_enable(struct cx18 *cx, u32 val);
+void cx18_sw1_irq_disable(struct cx18 *cx, u32 val);
+void cx18_sw2_irq_enable(struct cx18 *cx, u32 val);
+void cx18_sw2_irq_disable(struct cx18 *cx, u32 val);
+void cx18_setup_page(struct cx18 *cx, u32 addr);
+
+#endif /* CX18_IO_H */
diff --git a/drivers/media/video/cx18/cx18-ioctl.c b/drivers/media/video/cx18/cx18-ioctl.c
index a7f8396..f0ca50f 100644
--- a/drivers/media/video/cx18/cx18-ioctl.c
+++ b/drivers/media/video/cx18/cx18-ioctl.c
@@ -22,6 +22,7 @@
  */
 
 #include "cx18-driver.h"
+#include "cx18-io.h"
 #include "cx18-version.h"
 #include "cx18-mailbox.h"
 #include "cx18-i2c.h"
@@ -170,7 +171,6 @@
 {
 	struct cx18_open_id *id = fh;
 	struct cx18 *cx = id->cx;
-
 	int w = fmt->fmt.pix.width;
 	int h = fmt->fmt.pix.height;
 
@@ -202,8 +202,7 @@
 	struct cx18_open_id *id = fh;
 	struct cx18 *cx = id->cx;
 	int ret;
-	int w = fmt->fmt.pix.width;
-	int h = fmt->fmt.pix.height;
+	int w, h;
 
 	ret = v4l2_prio_check(&cx->prio, &id->prio);
 	if (ret)
@@ -212,6 +211,8 @@
 	ret = cx18_try_fmt_vid_cap(file, fh, fmt);
 	if (ret)
 		return ret;
+	w = fmt->fmt.pix.width;
+	h = fmt->fmt.pix.height;
 
 	if (cx->params.width == w && cx->params.height == h)
 		return 0;
@@ -286,9 +287,9 @@
 
 	spin_lock_irqsave(&cx18_cards_lock, flags);
 	if (cmd == VIDIOC_DBG_G_REGISTER)
-		regs->val = read_enc(regs->reg);
+		regs->val = cx18_read_enc(cx, regs->reg);
 	else
-		write_enc(regs->val, regs->reg);
+		cx18_write_enc(cx, regs->val, regs->reg);
 	spin_unlock_irqrestore(&cx18_cards_lock, flags);
 	return 0;
 }
@@ -345,7 +346,7 @@
 
 	strlcpy(vcap->driver, CX18_DRIVER_NAME, sizeof(vcap->driver));
 	strlcpy(vcap->card, cx->card_name, sizeof(vcap->card));
-	strlcpy(vcap->bus_info, pci_name(cx->dev), sizeof(vcap->bus_info));
+	snprintf(vcap->bus_info, sizeof(vcap->bus_info), "PCI:%s", pci_name(cx->dev));
 	vcap->version = CX18_DRIVER_VERSION; 	    /* version */
 	vcap->capabilities = cx->v4l2_cap; 	    /* capabilities */
 	return 0;
@@ -622,6 +623,7 @@
 {
 	struct cx18_open_id *id = fh;
 	struct cx18 *cx = id->cx;
+	u32 h;
 
 	switch (enc->cmd) {
 	case V4L2_ENC_CMD_START:
@@ -643,8 +645,14 @@
 			return -EPERM;
 		if (test_and_set_bit(CX18_F_I_ENC_PAUSED, &cx->i_flags))
 			return 0;
+		h = cx18_find_handle(cx);
+		if (h == CX18_INVALID_TASK_HANDLE) {
+			CX18_ERR("Can't find valid task handle for "
+				 "V4L2_ENC_CMD_PAUSE\n");
+			return -EBADFD;
+		}
 		cx18_mute(cx);
-		cx18_vapi(cx, CX18_CPU_CAPTURE_PAUSE, 1, cx18_find_handle(cx));
+		cx18_vapi(cx, CX18_CPU_CAPTURE_PAUSE, 1, h);
 		break;
 
 	case V4L2_ENC_CMD_RESUME:
@@ -654,7 +662,13 @@
 			return -EPERM;
 		if (!test_and_clear_bit(CX18_F_I_ENC_PAUSED, &cx->i_flags))
 			return 0;
-		cx18_vapi(cx, CX18_CPU_CAPTURE_RESUME, 1, cx18_find_handle(cx));
+		h = cx18_find_handle(cx);
+		if (h == CX18_INVALID_TASK_HANDLE) {
+			CX18_ERR("Can't find valid task handle for "
+				 "V4L2_ENC_CMD_RESUME\n");
+			return -EBADFD;
+		}
+		cx18_vapi(cx, CX18_CPU_CAPTURE_RESUME, 1, h);
 		cx18_unmute(cx);
 		break;
 
@@ -731,12 +745,14 @@
 			continue;
 		CX18_INFO("Stream %s: status 0x%04lx, %d%% of %d KiB (%d buffers) in use\n",
 			  s->name, s->s_flags,
-			  (s->buffers - s->q_free.buffers) * 100 / s->buffers,
+			  (s->buffers - atomic_read(&s->q_free.buffers))
+				* 100 / s->buffers,
 			  (s->buffers * s->buf_size) / 1024, s->buffers);
 	}
 	CX18_INFO("Read MPEG/VBI: %lld/%lld bytes\n",
 			(long long)cx->mpg_data_received,
 			(long long)cx->vbi_data_inserted);
+	cx18_log_statistics(cx);
 	CX18_INFO("==================  END STATUS CARD #%d  ==================\n", cx->num);
 	return 0;
 }
diff --git a/drivers/media/video/cx18/cx18-irq.c b/drivers/media/video/cx18/cx18-irq.c
index ab21831..360330f 100644
--- a/drivers/media/video/cx18/cx18-irq.c
+++ b/drivers/media/video/cx18/cx18-irq.c
@@ -20,6 +20,7 @@
  */
 
 #include "cx18-driver.h"
+#include "cx18-io.h"
 #include "cx18-firmware.h"
 #include "cx18-fileops.h"
 #include "cx18-queue.h"
@@ -48,8 +49,8 @@
 			break;
 	}
 	if (i == CX18_MAX_STREAMS) {
-		CX18_WARN("DMA done for unknown handle %d for stream %s\n",
-			handle, s->name);
+		CX18_WARN("Got DMA done notification for unknown/inactive"
+			  " handle %d\n", handle);
 		mb->error = CXERR_NOT_OPEN;
 		mb->cmd = 0;
 		cx18_mb_ack(cx, mb);
@@ -60,8 +61,8 @@
 	if (mb->args[2] != 1)
 		CX18_WARN("Ack struct = %d for %s\n",
 			mb->args[2], s->name);
-	id = read_enc(off);
-	buf = cx18_queue_get_buf_irq(s, id, read_enc(off + 4));
+	id = cx18_read_enc(cx, off);
+	buf = cx18_queue_get_buf_irq(s, id, cx18_read_enc(cx, off + 4));
 	CX18_DEBUG_HI_DMA("DMA DONE for %s (buffer %d)\n", s->name, id);
 	if (buf) {
 		cx18_buf_sync_for_cpu(s, buf);
@@ -81,7 +82,7 @@
 			set_bit(CX18_F_B_NEED_BUF_SWAP, &buf->b_flags);
 	} else {
 		CX18_WARN("Could not find buf %d for stream %s\n",
-				read_enc(off), s->name);
+				cx18_read_enc(cx, off), s->name);
 	}
 	mb->error = 0;
 	mb->cmd = 0;
@@ -97,8 +98,8 @@
 	char *p;
 
 	if (mb->args[1]) {
-		setup_page(mb->args[1]);
-		memcpy_fromio(str, cx->enc_mem + mb->args[1], 252);
+		cx18_setup_page(cx, mb->args[1]);
+		cx18_memcpy_fromio(cx, str, cx->enc_mem + mb->args[1], 252);
 		str[252] = 0;
 	}
 	cx18_mb_ack(cx, mb);
@@ -113,7 +114,7 @@
 	struct cx18_mailbox mb;
 
 	if (sw1 & IRQ_CPU_TO_EPU) {
-		memcpy_fromio(&mb, &cx->scb->cpu2epu_mb, sizeof(mb));
+		cx18_memcpy_fromio(cx, &mb, &cx->scb->cpu2epu_mb, sizeof(mb));
 		mb.error = 0;
 
 		switch (mb.cmd) {
@@ -141,16 +142,16 @@
 
 	spin_lock(&cx->dma_reg_lock);
 
-	hw2_mask = read_reg(HW2_INT_MASK5_PCI);
-	hw2 = read_reg(HW2_INT_CLR_STATUS) & hw2_mask;
-	sw2_mask = read_reg(SW2_INT_ENABLE_PCI) | IRQ_EPU_TO_HPU_ACK;
-	sw2 = read_reg(SW2_INT_STATUS) & sw2_mask;
-	sw1_mask = read_reg(SW1_INT_ENABLE_PCI) | IRQ_EPU_TO_HPU;
-	sw1 = read_reg(SW1_INT_STATUS) & sw1_mask;
+	hw2_mask = cx18_read_reg(cx, HW2_INT_MASK5_PCI);
+	hw2 = cx18_read_reg(cx, HW2_INT_CLR_STATUS) & hw2_mask;
+	sw2_mask = cx18_read_reg(cx, SW2_INT_ENABLE_PCI) | IRQ_EPU_TO_HPU_ACK;
+	sw2 = cx18_read_reg(cx, SW2_INT_STATUS) & sw2_mask;
+	sw1_mask = cx18_read_reg(cx, SW1_INT_ENABLE_PCI) | IRQ_EPU_TO_HPU;
+	sw1 = cx18_read_reg(cx, SW1_INT_STATUS) & sw1_mask;
 
-	write_reg(sw2&sw2_mask, SW2_INT_STATUS);
-	write_reg(sw1&sw1_mask, SW1_INT_STATUS);
-	write_reg(hw2&hw2_mask, HW2_INT_CLR_STATUS);
+	cx18_write_reg(cx, sw2&sw2_mask, SW2_INT_STATUS);
+	cx18_write_reg(cx, sw1&sw1_mask, SW1_INT_STATUS);
+	cx18_write_reg(cx, hw2&hw2_mask, HW2_INT_CLR_STATUS);
 
 	if (sw1 || sw2 || hw2)
 		CX18_DEBUG_HI_IRQ("SW1: %x  SW2: %x  HW2: %x\n", sw1, sw2, hw2);
@@ -161,15 +162,15 @@
 	*/
 
 	if (sw2) {
-		if (sw2 & (readl(&cx->scb->cpu2hpu_irq_ack) |
-			   readl(&cx->scb->cpu2epu_irq_ack)))
+		if (sw2 & (cx18_readl(cx, &cx->scb->cpu2hpu_irq_ack) |
+			   cx18_readl(cx, &cx->scb->cpu2epu_irq_ack)))
 			wake_up(&cx->mb_cpu_waitq);
-		if (sw2 & (readl(&cx->scb->apu2hpu_irq_ack) |
-			   readl(&cx->scb->apu2epu_irq_ack)))
+		if (sw2 & (cx18_readl(cx, &cx->scb->apu2hpu_irq_ack) |
+			   cx18_readl(cx, &cx->scb->apu2epu_irq_ack)))
 			wake_up(&cx->mb_apu_waitq);
-		if (sw2 & readl(&cx->scb->epu2hpu_irq_ack))
+		if (sw2 & cx18_readl(cx, &cx->scb->epu2hpu_irq_ack))
 			wake_up(&cx->mb_epu_waitq);
-		if (sw2 & readl(&cx->scb->hpu2epu_irq_ack))
+		if (sw2 & cx18_readl(cx, &cx->scb->hpu2epu_irq_ack))
 			wake_up(&cx->mb_hpu_waitq);
 	}
 
diff --git a/drivers/media/video/cx18/cx18-mailbox.c b/drivers/media/video/cx18/cx18-mailbox.c
index 9317751..9d18dd2 100644
--- a/drivers/media/video/cx18/cx18-mailbox.c
+++ b/drivers/media/video/cx18/cx18-mailbox.c
@@ -22,6 +22,7 @@
 #include <stdarg.h>
 
 #include "cx18-driver.h"
+#include "cx18-io.h"
 #include "cx18-scb.h"
 #include "cx18-irq.h"
 #include "cx18-mailbox.h"
@@ -82,6 +83,7 @@
 	API_ENTRY(CPU, CX18_CPU_DE_SET_MDL_ACK,			0),
 	API_ENTRY(CPU, CX18_CPU_DE_SET_MDL,			API_FAST),
 	API_ENTRY(CPU, CX18_APU_RESETAI,			API_FAST),
+	API_ENTRY(CPU, CX18_CPU_DE_RELEASE_MDL,			0),
 	API_ENTRY(0, 0,						0),
 };
 
@@ -105,20 +107,20 @@
 	switch (rpu) {
 	case APU:
 		mb = &cx->scb->epu2apu_mb;
-		*state = readl(&cx->scb->apu_state);
-		*irq = readl(&cx->scb->epu2apu_irq);
+		*state = cx18_readl(cx, &cx->scb->apu_state);
+		*irq = cx18_readl(cx, &cx->scb->epu2apu_irq);
 		break;
 
 	case CPU:
 		mb = &cx->scb->epu2cpu_mb;
-		*state = readl(&cx->scb->cpu_state);
-		*irq = readl(&cx->scb->epu2cpu_irq);
+		*state = cx18_readl(cx, &cx->scb->cpu_state);
+		*irq = cx18_readl(cx, &cx->scb->epu2cpu_irq);
 		break;
 
 	case HPU:
 		mb = &cx->scb->epu2hpu_mb;
-		*state = readl(&cx->scb->hpu_state);
-		*irq = readl(&cx->scb->epu2hpu_irq);
+		*state = cx18_readl(cx, &cx->scb->hpu_state);
+		*irq = cx18_readl(cx, &cx->scb->epu2hpu_irq);
 		break;
 	}
 
@@ -126,8 +128,8 @@
 		return mb;
 
 	do {
-		*req = readl(&mb->request);
-		ack = readl(&mb->ack);
+		*req = cx18_readl(cx, &mb->request);
+		ack = cx18_readl(cx, &mb->ack);
 		wait_count++;
 	} while (*req != ack && wait_count < 600);
 
@@ -172,9 +174,9 @@
 		return -EINVAL;
 	}
 
-	setup_page(SCB_OFFSET);
-	write_sync(mb->request, &ack_mb->ack);
-	write_reg(ack_irq, SW2_INT_SET);
+	cx18_setup_page(cx, SCB_OFFSET);
+	cx18_write_sync(cx, mb->request, &ack_mb->ack);
+	cx18_write_reg(cx, ack_irq, SW2_INT_SET);
 	return 0;
 }
 
@@ -199,7 +201,7 @@
 		CX18_DEBUG_HI_API("%s\n", info->name);
 	else
 		CX18_DEBUG_API("%s\n", info->name);
-	setup_page(SCB_OFFSET);
+	cx18_setup_page(cx, SCB_OFFSET);
 	mb = cx18_mb_is_complete(cx, info->rpu, &state, &irq, &req);
 
 	if (mb == NULL) {
@@ -208,11 +210,11 @@
 	}
 
 	oldreq = req - 1;
-	writel(cmd, &mb->cmd);
+	cx18_writel(cx, cmd, &mb->cmd);
 	for (i = 0; i < args; i++)
-		writel(data[i], &mb->args[i]);
-	writel(0, &mb->error);
-	writel(req, &mb->request);
+		cx18_writel(cx, data[i], &mb->args[i]);
+	cx18_writel(cx, 0, &mb->error);
+	cx18_writel(cx, req, &mb->request);
 
 	switch (info->rpu) {
 	case APU: waitq = &cx->mb_apu_waitq; break;
@@ -223,9 +225,10 @@
 	}
 	if (info->flags & API_FAST)
 		timeout /= 2;
-	write_reg(irq, SW1_INT_SET);
+	cx18_write_reg(cx, irq, SW1_INT_SET);
 
-	while (!sig && readl(&mb->ack) != readl(&mb->request) && cnt < 660) {
+	while (!sig && cx18_readl(cx, &mb->ack) != cx18_readl(cx, &mb->request)
+	       && cnt < 660) {
 		if (cnt > 200 && !in_atomic())
 			sig = cx18_msleep_timeout(10, 1);
 		cnt++;
@@ -233,13 +236,13 @@
 	if (sig)
 		return -EINTR;
 	if (cnt == 660) {
-		writel(oldreq, &mb->request);
+		cx18_writel(cx, oldreq, &mb->request);
 		CX18_ERR("mb %s failed\n", info->name);
 		return -EINVAL;
 	}
 	for (i = 0; i < MAX_MB_ARGUMENTS; i++)
-		data[i] = readl(&mb->args[i]);
-	err = readl(&mb->error);
+		data[i] = cx18_readl(cx, &mb->args[i]);
+	err = cx18_readl(cx, &mb->error);
 	if (!in_atomic() && (info->flags & API_SLOW))
 		cx18_msleep_timeout(300, 0);
 	if (err)
diff --git a/drivers/media/video/cx18/cx18-queue.c b/drivers/media/video/cx18/cx18-queue.c
index dbe792a..a33ba04 100644
--- a/drivers/media/video/cx18/cx18-queue.c
+++ b/drivers/media/video/cx18/cx18-queue.c
@@ -37,8 +37,7 @@
 void cx18_queue_init(struct cx18_queue *q)
 {
 	INIT_LIST_HEAD(&q->list);
-	q->buffers = 0;
-	q->length = 0;
+	atomic_set(&q->buffers, 0);
 	q->bytesused = 0;
 }
 
@@ -55,8 +54,7 @@
 	}
 	spin_lock_irqsave(&s->qlock, flags);
 	list_add_tail(&buf->list, &q->list);
-	q->buffers++;
-	q->length += s->buf_size;
+	atomic_inc(&q->buffers);
 	q->bytesused += buf->bytesused - buf->readpos;
 	spin_unlock_irqrestore(&s->qlock, flags);
 }
@@ -70,8 +68,7 @@
 	if (!list_empty(&q->list)) {
 		buf = list_entry(q->list.next, struct cx18_buffer, list);
 		list_del_init(q->list.next);
-		q->buffers--;
-		q->length -= s->buf_size;
+		atomic_dec(&q->buffers);
 		q->bytesused -= buf->bytesused - buf->readpos;
 	}
 	spin_unlock_irqrestore(&s->qlock, flags);
@@ -95,10 +92,8 @@
 		/* the transport buffers are handled differently,
 		   they are not moved to the full queue */
 		if (s->type != CX18_ENC_STREAM_TYPE_TS) {
-			s->q_free.buffers--;
-			s->q_free.length -= s->buf_size;
-			s->q_full.buffers++;
-			s->q_full.length += s->buf_size;
+			atomic_dec(&s->q_free.buffers);
+			atomic_inc(&s->q_full.buffers);
 			s->q_full.bytesused += buf->bytesused;
 			list_move_tail(&buf->list, &s->q_full.list);
 		}
@@ -124,8 +119,7 @@
 		buf = list_entry(q->list.next, struct cx18_buffer, list);
 		list_move_tail(q->list.next, &s->q_free.list);
 		buf->bytesused = buf->readpos = buf->b_flags = 0;
-		s->q_free.buffers++;
-		s->q_free.length += s->buf_size;
+		atomic_inc(&s->q_free.buffers);
 	}
 	cx18_queue_init(q);
 	spin_unlock_irqrestore(&s->qlock, flags);
diff --git a/drivers/media/video/cx18/cx18-scb.c b/drivers/media/video/cx18/cx18-scb.c
index 30bc803..f56d377 100644
--- a/drivers/media/video/cx18/cx18-scb.c
+++ b/drivers/media/video/cx18/cx18-scb.c
@@ -20,102 +20,103 @@
  */
 
 #include "cx18-driver.h"
+#include "cx18-io.h"
 #include "cx18-scb.h"
 
 void cx18_init_scb(struct cx18 *cx)
 {
-	setup_page(SCB_OFFSET);
-	memset_io(cx->scb, 0, 0x10000);
+	cx18_setup_page(cx, SCB_OFFSET);
+	cx18_memset_io(cx, cx->scb, 0, 0x10000);
 
-	writel(IRQ_APU_TO_CPU,     &cx->scb->apu2cpu_irq);
-	writel(IRQ_CPU_TO_APU_ACK, &cx->scb->cpu2apu_irq_ack);
-	writel(IRQ_HPU_TO_CPU,     &cx->scb->hpu2cpu_irq);
-	writel(IRQ_CPU_TO_HPU_ACK, &cx->scb->cpu2hpu_irq_ack);
-	writel(IRQ_PPU_TO_CPU,     &cx->scb->ppu2cpu_irq);
-	writel(IRQ_CPU_TO_PPU_ACK, &cx->scb->cpu2ppu_irq_ack);
-	writel(IRQ_EPU_TO_CPU,     &cx->scb->epu2cpu_irq);
-	writel(IRQ_CPU_TO_EPU_ACK, &cx->scb->cpu2epu_irq_ack);
+	cx18_writel(cx, IRQ_APU_TO_CPU,     &cx->scb->apu2cpu_irq);
+	cx18_writel(cx, IRQ_CPU_TO_APU_ACK, &cx->scb->cpu2apu_irq_ack);
+	cx18_writel(cx, IRQ_HPU_TO_CPU,     &cx->scb->hpu2cpu_irq);
+	cx18_writel(cx, IRQ_CPU_TO_HPU_ACK, &cx->scb->cpu2hpu_irq_ack);
+	cx18_writel(cx, IRQ_PPU_TO_CPU,     &cx->scb->ppu2cpu_irq);
+	cx18_writel(cx, IRQ_CPU_TO_PPU_ACK, &cx->scb->cpu2ppu_irq_ack);
+	cx18_writel(cx, IRQ_EPU_TO_CPU,     &cx->scb->epu2cpu_irq);
+	cx18_writel(cx, IRQ_CPU_TO_EPU_ACK, &cx->scb->cpu2epu_irq_ack);
 
-	writel(IRQ_CPU_TO_APU,     &cx->scb->cpu2apu_irq);
-	writel(IRQ_APU_TO_CPU_ACK, &cx->scb->apu2cpu_irq_ack);
-	writel(IRQ_HPU_TO_APU,     &cx->scb->hpu2apu_irq);
-	writel(IRQ_APU_TO_HPU_ACK, &cx->scb->apu2hpu_irq_ack);
-	writel(IRQ_PPU_TO_APU,     &cx->scb->ppu2apu_irq);
-	writel(IRQ_APU_TO_PPU_ACK, &cx->scb->apu2ppu_irq_ack);
-	writel(IRQ_EPU_TO_APU,     &cx->scb->epu2apu_irq);
-	writel(IRQ_APU_TO_EPU_ACK, &cx->scb->apu2epu_irq_ack);
+	cx18_writel(cx, IRQ_CPU_TO_APU,     &cx->scb->cpu2apu_irq);
+	cx18_writel(cx, IRQ_APU_TO_CPU_ACK, &cx->scb->apu2cpu_irq_ack);
+	cx18_writel(cx, IRQ_HPU_TO_APU,     &cx->scb->hpu2apu_irq);
+	cx18_writel(cx, IRQ_APU_TO_HPU_ACK, &cx->scb->apu2hpu_irq_ack);
+	cx18_writel(cx, IRQ_PPU_TO_APU,     &cx->scb->ppu2apu_irq);
+	cx18_writel(cx, IRQ_APU_TO_PPU_ACK, &cx->scb->apu2ppu_irq_ack);
+	cx18_writel(cx, IRQ_EPU_TO_APU,     &cx->scb->epu2apu_irq);
+	cx18_writel(cx, IRQ_APU_TO_EPU_ACK, &cx->scb->apu2epu_irq_ack);
 
-	writel(IRQ_CPU_TO_HPU,     &cx->scb->cpu2hpu_irq);
-	writel(IRQ_HPU_TO_CPU_ACK, &cx->scb->hpu2cpu_irq_ack);
-	writel(IRQ_APU_TO_HPU,     &cx->scb->apu2hpu_irq);
-	writel(IRQ_HPU_TO_APU_ACK, &cx->scb->hpu2apu_irq_ack);
-	writel(IRQ_PPU_TO_HPU,     &cx->scb->ppu2hpu_irq);
-	writel(IRQ_HPU_TO_PPU_ACK, &cx->scb->hpu2ppu_irq_ack);
-	writel(IRQ_EPU_TO_HPU,     &cx->scb->epu2hpu_irq);
-	writel(IRQ_HPU_TO_EPU_ACK, &cx->scb->hpu2epu_irq_ack);
+	cx18_writel(cx, IRQ_CPU_TO_HPU,     &cx->scb->cpu2hpu_irq);
+	cx18_writel(cx, IRQ_HPU_TO_CPU_ACK, &cx->scb->hpu2cpu_irq_ack);
+	cx18_writel(cx, IRQ_APU_TO_HPU,     &cx->scb->apu2hpu_irq);
+	cx18_writel(cx, IRQ_HPU_TO_APU_ACK, &cx->scb->hpu2apu_irq_ack);
+	cx18_writel(cx, IRQ_PPU_TO_HPU,     &cx->scb->ppu2hpu_irq);
+	cx18_writel(cx, IRQ_HPU_TO_PPU_ACK, &cx->scb->hpu2ppu_irq_ack);
+	cx18_writel(cx, IRQ_EPU_TO_HPU,     &cx->scb->epu2hpu_irq);
+	cx18_writel(cx, IRQ_HPU_TO_EPU_ACK, &cx->scb->hpu2epu_irq_ack);
 
-	writel(IRQ_CPU_TO_PPU,     &cx->scb->cpu2ppu_irq);
-	writel(IRQ_PPU_TO_CPU_ACK, &cx->scb->ppu2cpu_irq_ack);
-	writel(IRQ_APU_TO_PPU,     &cx->scb->apu2ppu_irq);
-	writel(IRQ_PPU_TO_APU_ACK, &cx->scb->ppu2apu_irq_ack);
-	writel(IRQ_HPU_TO_PPU,     &cx->scb->hpu2ppu_irq);
-	writel(IRQ_PPU_TO_HPU_ACK, &cx->scb->ppu2hpu_irq_ack);
-	writel(IRQ_EPU_TO_PPU,     &cx->scb->epu2ppu_irq);
-	writel(IRQ_PPU_TO_EPU_ACK, &cx->scb->ppu2epu_irq_ack);
+	cx18_writel(cx, IRQ_CPU_TO_PPU,     &cx->scb->cpu2ppu_irq);
+	cx18_writel(cx, IRQ_PPU_TO_CPU_ACK, &cx->scb->ppu2cpu_irq_ack);
+	cx18_writel(cx, IRQ_APU_TO_PPU,     &cx->scb->apu2ppu_irq);
+	cx18_writel(cx, IRQ_PPU_TO_APU_ACK, &cx->scb->ppu2apu_irq_ack);
+	cx18_writel(cx, IRQ_HPU_TO_PPU,     &cx->scb->hpu2ppu_irq);
+	cx18_writel(cx, IRQ_PPU_TO_HPU_ACK, &cx->scb->ppu2hpu_irq_ack);
+	cx18_writel(cx, IRQ_EPU_TO_PPU,     &cx->scb->epu2ppu_irq);
+	cx18_writel(cx, IRQ_PPU_TO_EPU_ACK, &cx->scb->ppu2epu_irq_ack);
 
-	writel(IRQ_CPU_TO_EPU,     &cx->scb->cpu2epu_irq);
-	writel(IRQ_EPU_TO_CPU_ACK, &cx->scb->epu2cpu_irq_ack);
-	writel(IRQ_APU_TO_EPU,     &cx->scb->apu2epu_irq);
-	writel(IRQ_EPU_TO_APU_ACK, &cx->scb->epu2apu_irq_ack);
-	writel(IRQ_HPU_TO_EPU,     &cx->scb->hpu2epu_irq);
-	writel(IRQ_EPU_TO_HPU_ACK, &cx->scb->epu2hpu_irq_ack);
-	writel(IRQ_PPU_TO_EPU,     &cx->scb->ppu2epu_irq);
-	writel(IRQ_EPU_TO_PPU_ACK, &cx->scb->epu2ppu_irq_ack);
+	cx18_writel(cx, IRQ_CPU_TO_EPU,     &cx->scb->cpu2epu_irq);
+	cx18_writel(cx, IRQ_EPU_TO_CPU_ACK, &cx->scb->epu2cpu_irq_ack);
+	cx18_writel(cx, IRQ_APU_TO_EPU,     &cx->scb->apu2epu_irq);
+	cx18_writel(cx, IRQ_EPU_TO_APU_ACK, &cx->scb->epu2apu_irq_ack);
+	cx18_writel(cx, IRQ_HPU_TO_EPU,     &cx->scb->hpu2epu_irq);
+	cx18_writel(cx, IRQ_EPU_TO_HPU_ACK, &cx->scb->epu2hpu_irq_ack);
+	cx18_writel(cx, IRQ_PPU_TO_EPU,     &cx->scb->ppu2epu_irq);
+	cx18_writel(cx, IRQ_EPU_TO_PPU_ACK, &cx->scb->epu2ppu_irq_ack);
 
-	writel(SCB_OFFSET + offsetof(struct cx18_scb, apu2cpu_mb),
+	cx18_writel(cx, SCB_OFFSET + offsetof(struct cx18_scb, apu2cpu_mb),
 			&cx->scb->apu2cpu_mb_offset);
-	writel(SCB_OFFSET + offsetof(struct cx18_scb, hpu2cpu_mb),
+	cx18_writel(cx, SCB_OFFSET + offsetof(struct cx18_scb, hpu2cpu_mb),
 			&cx->scb->hpu2cpu_mb_offset);
-	writel(SCB_OFFSET + offsetof(struct cx18_scb, ppu2cpu_mb),
+	cx18_writel(cx, SCB_OFFSET + offsetof(struct cx18_scb, ppu2cpu_mb),
 			&cx->scb->ppu2cpu_mb_offset);
-	writel(SCB_OFFSET + offsetof(struct cx18_scb, epu2cpu_mb),
+	cx18_writel(cx, SCB_OFFSET + offsetof(struct cx18_scb, epu2cpu_mb),
 			&cx->scb->epu2cpu_mb_offset);
-	writel(SCB_OFFSET + offsetof(struct cx18_scb, cpu2apu_mb),
+	cx18_writel(cx, SCB_OFFSET + offsetof(struct cx18_scb, cpu2apu_mb),
 			&cx->scb->cpu2apu_mb_offset);
-	writel(SCB_OFFSET + offsetof(struct cx18_scb, hpu2apu_mb),
+	cx18_writel(cx, SCB_OFFSET + offsetof(struct cx18_scb, hpu2apu_mb),
 			&cx->scb->hpu2apu_mb_offset);
-	writel(SCB_OFFSET + offsetof(struct cx18_scb, ppu2apu_mb),
+	cx18_writel(cx, SCB_OFFSET + offsetof(struct cx18_scb, ppu2apu_mb),
 			&cx->scb->ppu2apu_mb_offset);
-	writel(SCB_OFFSET + offsetof(struct cx18_scb, epu2apu_mb),
+	cx18_writel(cx, SCB_OFFSET + offsetof(struct cx18_scb, epu2apu_mb),
 			&cx->scb->epu2apu_mb_offset);
-	writel(SCB_OFFSET + offsetof(struct cx18_scb, cpu2hpu_mb),
+	cx18_writel(cx, SCB_OFFSET + offsetof(struct cx18_scb, cpu2hpu_mb),
 			&cx->scb->cpu2hpu_mb_offset);
-	writel(SCB_OFFSET + offsetof(struct cx18_scb, apu2hpu_mb),
+	cx18_writel(cx, SCB_OFFSET + offsetof(struct cx18_scb, apu2hpu_mb),
 			&cx->scb->apu2hpu_mb_offset);
-	writel(SCB_OFFSET + offsetof(struct cx18_scb, ppu2hpu_mb),
+	cx18_writel(cx, SCB_OFFSET + offsetof(struct cx18_scb, ppu2hpu_mb),
 			&cx->scb->ppu2hpu_mb_offset);
-	writel(SCB_OFFSET + offsetof(struct cx18_scb, epu2hpu_mb),
+	cx18_writel(cx, SCB_OFFSET + offsetof(struct cx18_scb, epu2hpu_mb),
 			&cx->scb->epu2hpu_mb_offset);
-	writel(SCB_OFFSET + offsetof(struct cx18_scb, cpu2ppu_mb),
+	cx18_writel(cx, SCB_OFFSET + offsetof(struct cx18_scb, cpu2ppu_mb),
 			&cx->scb->cpu2ppu_mb_offset);
-	writel(SCB_OFFSET + offsetof(struct cx18_scb, apu2ppu_mb),
+	cx18_writel(cx, SCB_OFFSET + offsetof(struct cx18_scb, apu2ppu_mb),
 			&cx->scb->apu2ppu_mb_offset);
-	writel(SCB_OFFSET + offsetof(struct cx18_scb, hpu2ppu_mb),
+	cx18_writel(cx, SCB_OFFSET + offsetof(struct cx18_scb, hpu2ppu_mb),
 			&cx->scb->hpu2ppu_mb_offset);
-	writel(SCB_OFFSET + offsetof(struct cx18_scb, epu2ppu_mb),
+	cx18_writel(cx, SCB_OFFSET + offsetof(struct cx18_scb, epu2ppu_mb),
 			&cx->scb->epu2ppu_mb_offset);
-	writel(SCB_OFFSET + offsetof(struct cx18_scb, cpu2epu_mb),
+	cx18_writel(cx, SCB_OFFSET + offsetof(struct cx18_scb, cpu2epu_mb),
 			&cx->scb->cpu2epu_mb_offset);
-	writel(SCB_OFFSET + offsetof(struct cx18_scb, apu2epu_mb),
+	cx18_writel(cx, SCB_OFFSET + offsetof(struct cx18_scb, apu2epu_mb),
 			&cx->scb->apu2epu_mb_offset);
-	writel(SCB_OFFSET + offsetof(struct cx18_scb, hpu2epu_mb),
+	cx18_writel(cx, SCB_OFFSET + offsetof(struct cx18_scb, hpu2epu_mb),
 			&cx->scb->hpu2epu_mb_offset);
-	writel(SCB_OFFSET + offsetof(struct cx18_scb, ppu2epu_mb),
+	cx18_writel(cx, SCB_OFFSET + offsetof(struct cx18_scb, ppu2epu_mb),
 			&cx->scb->ppu2epu_mb_offset);
 
-	writel(SCB_OFFSET + offsetof(struct cx18_scb, cpu_state),
+	cx18_writel(cx, SCB_OFFSET + offsetof(struct cx18_scb, cpu_state),
 			&cx->scb->ipc_offset);
 
-	writel(1, &cx->scb->hpu_state);
-	writel(1, &cx->scb->epu_state);
+	cx18_writel(cx, 1, &cx->scb->hpu_state);
+	cx18_writel(cx, 1, &cx->scb->epu_state);
 }
diff --git a/drivers/media/video/cx18/cx18-streams.c b/drivers/media/video/cx18/cx18-streams.c
index 0da57f5..0c8e754 100644
--- a/drivers/media/video/cx18/cx18-streams.c
+++ b/drivers/media/video/cx18/cx18-streams.c
@@ -22,6 +22,7 @@
  */
 
 #include "cx18-driver.h"
+#include "cx18-io.h"
 #include "cx18-fileops.h"
 #include "cx18-mailbox.h"
 #include "cx18-i2c.h"
@@ -56,7 +57,7 @@
 static struct {
 	const char *name;
 	int vfl_type;
-	int minor_offset;
+	int num_offset;
 	int dma;
 	enum v4l2_buf_type buf_type;
 	struct file_operations *fops;
@@ -119,7 +120,7 @@
 	s->cx = cx;
 	s->type = type;
 	s->name = cx18_stream_info[type].name;
-	s->handle = 0xffffffff;
+	s->handle = CX18_INVALID_TASK_HANDLE;
 
 	s->dma = cx18_stream_info[type].dma;
 	s->buf_size = cx->stream_buf_size[type];
@@ -143,8 +144,8 @@
 {
 	struct cx18_stream *s = &cx->streams[type];
 	u32 cap = cx->v4l2_cap;
-	int minor_offset = cx18_stream_info[type].minor_offset;
-	int minor;
+	int num_offset = cx18_stream_info[type].num_offset;
+	int num = cx->num + cx18_first_minor + num_offset;
 
 	/* These four fields are always initialized. If v4l2dev == NULL, then
 	   this stream is not in use. In that case no other fields but these
@@ -163,9 +164,6 @@
 	    !(cap & (V4L2_CAP_VBI_CAPTURE | V4L2_CAP_SLICED_VBI_CAPTURE)))
 		return 0;
 
-	/* card number + user defined offset + device offset */
-	minor = cx->num + cx18_first_minor + minor_offset;
-
 	/* User explicitly selected 0 buffers for these streams, so don't
 	   create them. */
 	if (cx18_stream_info[type].dma != PCI_DMA_NONE &&
@@ -176,7 +174,7 @@
 
 	cx18_stream_init(cx, type);
 
-	if (minor_offset == -1)
+	if (num_offset == -1)
 		return 0;
 
 	/* allocate and initialize the v4l2 video device structure */
@@ -190,7 +188,7 @@
 	snprintf(s->v4l2dev->name, sizeof(s->v4l2dev->name), "cx18-%d",
 			cx->num);
 
-	s->v4l2dev->minor = minor;
+	s->v4l2dev->num = num;
 	s->v4l2dev->parent = &cx->dev->dev;
 	s->v4l2dev->fops = cx18_stream_info[type].fops;
 	s->v4l2dev->release = video_device_release;
@@ -226,7 +224,7 @@
 {
 	struct cx18_stream *s = &cx->streams[type];
 	int vfl_type = cx18_stream_info[type].vfl_type;
-	int minor;
+	int num;
 
 	/* TODO: Shouldn't this be a VFL_TYPE_TRANSPORT or something?
 	 * We need a VFL_TYPE_TS defined.
@@ -244,38 +242,44 @@
 	if (s->v4l2dev == NULL)
 		return 0;
 
-	minor = s->v4l2dev->minor;
+	num = s->v4l2dev->num;
+	/* card number + user defined offset + device offset */
+	if (type != CX18_ENC_STREAM_TYPE_MPG) {
+		struct cx18_stream *s_mpg = &cx->streams[CX18_ENC_STREAM_TYPE_MPG];
+
+		if (s_mpg->v4l2dev)
+			num = s_mpg->v4l2dev->num + cx18_stream_info[type].num_offset;
+	}
 
 	/* Register device. First try the desired minor, then any free one. */
-	if (video_register_device(s->v4l2dev, vfl_type, minor) &&
-			video_register_device(s->v4l2dev, vfl_type, -1)) {
-		CX18_ERR("Couldn't register v4l2 device for %s minor %d\n",
-			s->name, minor);
+	if (video_register_device(s->v4l2dev, vfl_type, num)) {
+		CX18_ERR("Couldn't register v4l2 device for %s kernel number %d\n",
+			s->name, num);
 		video_device_release(s->v4l2dev);
 		s->v4l2dev = NULL;
 		return -ENOMEM;
 	}
-	minor = s->v4l2dev->minor;
+	num = s->v4l2dev->num;
 
 	switch (vfl_type) {
 	case VFL_TYPE_GRABBER:
 		CX18_INFO("Registered device video%d for %s (%d MB)\n",
-			minor, s->name, cx->options.megabytes[type]);
+			num, s->name, cx->options.megabytes[type]);
 		break;
 
 	case VFL_TYPE_RADIO:
 		CX18_INFO("Registered device radio%d for %s\n",
-			minor - MINOR_VFL_TYPE_RADIO_MIN, s->name);
+			num, s->name);
 		break;
 
 	case VFL_TYPE_VBI:
 		if (cx->options.megabytes[type])
 			CX18_INFO("Registered device vbi%d for %s (%d MB)\n",
-				minor - MINOR_VFL_TYPE_VBI_MIN,
+				num,
 				s->name, cx->options.megabytes[type]);
 		else
 			CX18_INFO("Registered device vbi%d for %s\n",
-				minor - MINOR_VFL_TYPE_VBI_MIN, s->name);
+				num, s->name);
 		break;
 	}
 
@@ -432,7 +436,6 @@
 	default:
 		return -EINVAL;
 	}
-	s->buffers_stolen = 0;
 
 	/* mute/unmute video */
 	cx18_vapi(cx, CX18_CPU_SET_VIDEO_MUTE, 2,
@@ -470,7 +473,7 @@
 
 	if (atomic_read(&cx->tot_capturing) == 0) {
 		clear_bit(CX18_F_I_EOS, &cx->i_flags);
-		write_reg(7, CX18_DSP0_INTERRUPT_MASK);
+		cx18_write_reg(cx, 7, CX18_DSP0_INTERRUPT_MASK);
 	}
 
 	cx18_vapi(cx, CX18_CPU_DE_SET_MDL_ACK, 3, s->handle,
@@ -480,8 +483,9 @@
 	list_for_each(p, &s->q_free.list) {
 		struct cx18_buffer *buf = list_entry(p, struct cx18_buffer, list);
 
-		writel(buf->dma_handle, &cx->scb->cpu_mdl[buf->id].paddr);
-		writel(s->buf_size, &cx->scb->cpu_mdl[buf->id].length);
+		cx18_writel(cx, buf->dma_handle,
+					&cx->scb->cpu_mdl[buf->id].paddr);
+		cx18_writel(cx, s->buf_size, &cx->scb->cpu_mdl[buf->id].length);
 		cx18_vapi(cx, CX18_CPU_DE_SET_MDL, 5, s->handle,
 			(void __iomem *)&cx->scb->cpu_mdl[buf->id] - cx->enc_mem,
 			1, buf->id, s->buf_size);
@@ -489,7 +493,14 @@
 	/* begin_capture */
 	if (cx18_vapi(cx, CX18_CPU_CAPTURE_START, 1, s->handle)) {
 		CX18_DEBUG_WARN("Error starting capture!\n");
+		/* Ensure we're really not capturing before releasing MDLs */
+		if (s->type == CX18_ENC_STREAM_TYPE_MPG)
+			cx18_vapi(cx, CX18_CPU_CAPTURE_STOP, 2, s->handle, 1);
+		else
+			cx18_vapi(cx, CX18_CPU_CAPTURE_STOP, 1, s->handle);
+		cx18_vapi(cx, CX18_CPU_DE_RELEASE_MDL, 1, s->handle);
 		cx18_vapi(cx, CX18_DESTROY_TASK, 1, s->handle);
+		/* FIXME - clean-up DSP0_INT mask, i_flags, s_flags, etc. */
 		return -EINVAL;
 	}
 
@@ -541,6 +552,9 @@
 		CX18_INFO("ignoring gop_end: not (yet?) supported by the firmware\n");
 	}
 
+	/* Tell the CX23418 it can't use our buffers anymore */
+	cx18_vapi(cx, CX18_CPU_DE_RELEASE_MDL, 1, s->handle);
+
 	if (s->type != CX18_ENC_STREAM_TYPE_TS)
 		atomic_dec(&cx->ana_capturing);
 	atomic_dec(&cx->tot_capturing);
@@ -549,12 +563,12 @@
 	clear_bit(CX18_F_S_STREAMING, &s->s_flags);
 
 	cx18_vapi(cx, CX18_DESTROY_TASK, 1, s->handle);
-	s->handle = 0xffffffff;
+	s->handle = CX18_INVALID_TASK_HANDLE;
 
 	if (atomic_read(&cx->tot_capturing) > 0)
 		return 0;
 
-	write_reg(5, CX18_DSP0_INTERRUPT_MASK);
+	cx18_write_reg(cx, 5, CX18_DSP0_INTERRUPT_MASK);
 	wake_up(&s->waitq);
 
 	return 0;
@@ -568,8 +582,8 @@
 	for (i = 0; i < CX18_MAX_STREAMS; i++) {
 		struct cx18_stream *s = &cx->streams[i];
 
-		if (s->v4l2dev && s->handle)
+		if (s->v4l2dev && (s->handle != CX18_INVALID_TASK_HANDLE))
 			return s->handle;
 	}
-	return 0;
+	return CX18_INVALID_TASK_HANDLE;
 }
diff --git a/drivers/media/video/cx18/cx18-version.h b/drivers/media/video/cx18/cx18-version.h
index d5c7a6f..9f6be2d 100644
--- a/drivers/media/video/cx18/cx18-version.h
+++ b/drivers/media/video/cx18/cx18-version.h
@@ -25,7 +25,7 @@
 #define CX18_DRIVER_NAME "cx18"
 #define CX18_DRIVER_VERSION_MAJOR 1
 #define CX18_DRIVER_VERSION_MINOR 0
-#define CX18_DRIVER_VERSION_PATCHLEVEL 0
+#define CX18_DRIVER_VERSION_PATCHLEVEL 1
 
 #define CX18_VERSION __stringify(CX18_DRIVER_VERSION_MAJOR) "." __stringify(CX18_DRIVER_VERSION_MINOR) "." __stringify(CX18_DRIVER_VERSION_PATCHLEVEL)
 #define CX18_DRIVER_VERSION KERNEL_VERSION(CX18_DRIVER_VERSION_MAJOR, \
diff --git a/drivers/media/video/cx18/cx23418.h b/drivers/media/video/cx18/cx23418.h
index e7ed053..668f968 100644
--- a/drivers/media/video/cx18/cx23418.h
+++ b/drivers/media/video/cx18/cx23418.h
@@ -351,7 +351,7 @@
    Descriptor Lists to the driver
    IN[0] - Task handle. Handle of the task to start
    ReturnCode - One of the ERR_DE_... */
-/* #define CX18_CPU_DE_ReleaseMDL               (CPU_CMD_MASK_DE | 0x0006) */
+#define CX18_CPU_DE_RELEASE_MDL               	(CPU_CMD_MASK_DE | 0x0006)
 
 /* Description: This command signals the cpu that the dat buffer has been
    consumed and ready for re-use.
diff --git a/drivers/media/video/cx2341x.c b/drivers/media/video/cx2341x.c
index 22847a0..cbbe47f 100644
--- a/drivers/media/video/cx2341x.c
+++ b/drivers/media/video/cx2341x.c
@@ -508,7 +508,10 @@
 		/* this setting is read-only for the cx2341x since the
 		   V4L2_CID_MPEG_STREAM_TYPE really determines the
 		   MPEG-1/2 setting */
-		err = v4l2_ctrl_query_fill_std(qctrl);
+		err = v4l2_ctrl_query_fill(qctrl,
+					   V4L2_MPEG_VIDEO_ENCODING_MPEG_1,
+					   V4L2_MPEG_VIDEO_ENCODING_MPEG_2, 1,
+					   V4L2_MPEG_VIDEO_ENCODING_MPEG_2);
 		if (err == 0)
 			qctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
 		return err;
diff --git a/drivers/media/video/cx23885/Kconfig b/drivers/media/video/cx23885/Kconfig
index e60bd31..8c1b7fa4 100644
--- a/drivers/media/video/cx23885/Kconfig
+++ b/drivers/media/video/cx23885/Kconfig
@@ -15,6 +15,7 @@
 	select DVB_S5H1409 if !DVB_FE_CUSTOMISE
 	select DVB_S5H1411 if !DVB_FE_CUSTOMISE
 	select DVB_LGDT330X if !DVB_FE_CUSTOMISE
+	select DVB_ZL10353 if !DVB_FE_CUSTOMISE
 	select MEDIA_TUNER_XC2028 if !DVB_FE_CUSTOMIZE
 	select MEDIA_TUNER_TDA8290 if !DVB_FE_CUSTOMIZE
 	select MEDIA_TUNER_TDA18271 if !DVB_FE_CUSTOMIZE
diff --git a/drivers/media/video/cx23885/cx23885-417.c b/drivers/media/video/cx23885/cx23885-417.c
index 7b0e8c0..395c11f 100644
--- a/drivers/media/video/cx23885/cx23885-417.c
+++ b/drivers/media/video/cx23885/cx23885-417.c
@@ -36,7 +36,6 @@
 #include <media/cx2341x.h>
 
 #include "cx23885.h"
-#include "media/cx2341x.h"
 
 #define CX23885_FIRM_IMAGE_SIZE 376836
 #define CX23885_FIRM_IMAGE_NAME "v4l-cx23885-enc.fw"
@@ -632,7 +631,7 @@
 /* ------------------------------------------------------------------ */
 
 /* MPEG encoder API */
-char *cmd_to_str(int cmd)
+static char *cmd_to_str(int cmd)
 {
 	switch (cmd) {
 	case CX2341X_ENC_PING_FW:
@@ -1583,6 +1582,7 @@
 
 	dprintk(2, "%s()\n", __func__);
 
+	lock_kernel();
 	list_for_each(list, &cx23885_devlist) {
 		h = list_entry(list, struct cx23885_dev, devlist);
 		if (h->v4l_device->minor == minor) {
@@ -1591,13 +1591,17 @@
 		}
 	}
 
-	if (dev == NULL)
+	if (dev == NULL) {
+		unlock_kernel();
 		return -ENODEV;
+	}
 
 	/* allocate + initialize per filehandle data */
 	fh = kzalloc(sizeof(*fh), GFP_KERNEL);
-	if (NULL == fh)
+	if (NULL == fh) {
+		unlock_kernel();
 		return -ENOMEM;
+	}
 
 	file->private_data = fh;
 	fh->dev      = dev;
@@ -1608,6 +1612,7 @@
 			    V4L2_FIELD_INTERLACED,
 			    sizeof(struct cx23885_buffer),
 			    fh);
+	unlock_kernel();
 
 	return 0;
 }
diff --git a/drivers/media/video/cx23885/cx23885-cards.c b/drivers/media/video/cx23885/cx23885-cards.c
index c36d3f6..2cda15f 100644
--- a/drivers/media/video/cx23885/cx23885-cards.c
+++ b/drivers/media/video/cx23885/cx23885-cards.c
@@ -26,6 +26,7 @@
 #include <media/cx25840.h>
 
 #include "cx23885.h"
+#include "tuner-xc2028.h"
 
 /* ------------------------------------------------------------------ */
 /* board config info                                                  */
@@ -148,6 +149,15 @@
 		.portb		= CX23885_MPEG_DVB,
 		.portc		= CX23885_MPEG_DVB,
 	},
+	[CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP] = {
+		.name		= "DViCO FusionHDTV DVB-T Dual Express",
+		.portb		= CX23885_MPEG_DVB,
+		.portc		= CX23885_MPEG_DVB,
+	},
+	[CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H] = {
+		.name		= "Leadtek Winfast PxDVR3200 H",
+		.portc		= CX23885_MPEG_DVB,
+	},
 };
 const unsigned int cx23885_bcount = ARRAY_SIZE(cx23885_boards);
 
@@ -219,6 +229,14 @@
 		.subvendor = 0x18ac,
 		.subdevice = 0xd618,
 		.card      = CX23885_BOARD_DVICO_FUSIONHDTV_7_DUAL_EXP,
+	},{
+		.subvendor = 0x18ac,
+		.subdevice = 0xdb78,
+		.card      = CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP,
+	}, {
+		.subvendor = 0x107d,
+		.subdevice = 0x6681,
+		.card      = CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H,
 	},
 };
 const unsigned int cx23885_idcount = ARRAY_SIZE(cx23885_subids);
@@ -319,15 +337,15 @@
 			dev->name, tv.model);
 }
 
-/* Tuner callback function for cx23885 boards. Currently only needed
- * for HVR1500Q, which has an xc5000 tuner.
- */
-int cx23885_tuner_callback(void *priv, int command, int arg)
+int cx23885_tuner_callback(void *priv, int component, int command, int arg)
 {
-	struct cx23885_i2c *bus = priv;
-	struct cx23885_dev *dev = bus->dev;
+	struct cx23885_tsport *port = priv;
+	struct cx23885_dev *dev = port->dev;
 	u32 bitmask = 0;
 
+	if (command == XC2028_RESET_CLK)
+		return 0;
+
 	if (command != 0) {
 		printk(KERN_ERR "%s(): Unknown command 0x%x.\n",
 			__func__, command);
@@ -335,21 +353,21 @@
 	}
 
 	switch(dev->board) {
+	case CX23885_BOARD_HAUPPAUGE_HVR1400:
+	case CX23885_BOARD_HAUPPAUGE_HVR1500:
 	case CX23885_BOARD_HAUPPAUGE_HVR1500Q:
-		/* Tuner Reset Command from xc5000 */
-		if (command == 0)
-			bitmask = 0x04;
+	case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H:
+		/* Tuner Reset Command */
+		bitmask = 0x04;
 		break;
 	case CX23885_BOARD_DVICO_FUSIONHDTV_7_DUAL_EXP:
-		if (command == 0) {
-
-			/* Two identical tuners on two different i2c buses,
-			 * we need to reset the correct gpio. */
-			if (bus->nr == 0)
-				bitmask = 0x01;
-			else if (bus->nr == 1)
-				bitmask = 0x04;
-		}
+	case CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP:
+		/* Two identical tuners on two different i2c buses,
+		 * we need to reset the correct gpio. */
+		if (port->nr == 0)
+			bitmask = 0x01;
+		else if (port->nr == 1)
+			bitmask = 0x04;
 		break;
 	}
 
@@ -465,6 +483,32 @@
 		mdelay(20);
 		cx_set(GP0_IO, 0x000f000f);
 		break;
+	case CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP:
+		/* GPIO-0 portb xc3028 reset */
+		/* GPIO-1 portb zl10353 reset */
+		/* GPIO-2 portc xc3028 reset */
+		/* GPIO-3 portc zl10353 reset */
+
+		/* Put the parts into reset and back */
+		cx_set(GP0_IO, 0x000f0000);
+		mdelay(20);
+		cx_clear(GP0_IO, 0x0000000f);
+		mdelay(20);
+		cx_set(GP0_IO, 0x000f000f);
+		break;
+	case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H:
+		/* GPIO-2  xc3028 tuner reset */
+
+		/* The following GPIO's are on the internal AVCore (cx25840) */
+		/* GPIO-?  zl10353 demod reset */
+
+		/* Put the parts into reset and back */
+		cx_set(GP0_IO, 0x00040000);
+		mdelay(20);
+		cx_clear(GP0_IO, 0x00000004);
+		mdelay(20);
+		cx_set(GP0_IO, 0x00040004);
+		break;
 	}
 }
 
@@ -479,6 +523,9 @@
 	case CX23885_BOARD_HAUPPAUGE_HVR1400:
 		/* FIXME: Implement me */
 		break;
+	case CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP:
+		request_module("ir-kbd-i2c");
+		break;
 	}
 
 	return 0;
@@ -516,6 +563,7 @@
 
 	switch (dev->board) {
 	case CX23885_BOARD_DVICO_FUSIONHDTV_7_DUAL_EXP:
+	case CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP:
 		ts2->gen_ctrl_val  = 0xc; /* Serial bus + punctured clock */
 		ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */
 		ts2->src_sel_val   = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
@@ -548,6 +596,7 @@
 	case CX23885_BOARD_HAUPPAUGE_HVR1200:
 	case CX23885_BOARD_HAUPPAUGE_HVR1700:
 	case CX23885_BOARD_HAUPPAUGE_HVR1400:
+	case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H:
 	default:
 		ts2->gen_ctrl_val  = 0xc; /* Serial bus + punctured clock */
 		ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */
@@ -561,6 +610,7 @@
 	case CX23885_BOARD_HAUPPAUGE_HVR1800:
 	case CX23885_BOARD_HAUPPAUGE_HVR1800lp:
 	case CX23885_BOARD_HAUPPAUGE_HVR1700:
+	case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H:
 		request_module("cx25840");
 		break;
 	}
diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c
index 25fb099..beb3e61 100644
--- a/drivers/media/video/cx23885/cx23885-core.c
+++ b/drivers/media/video/cx23885/cx23885-core.c
@@ -1442,7 +1442,7 @@
 	struct cx23885_dev *dev = port->dev;
 	struct cx23885_dmaqueue *q = &port->mpegq;
 
-	dprintk(1, "%s()\n", __FUNCTION__);
+	dprintk(1, "%s()\n", __func__);
 	del_timer_sync(&q->timeout);
 	cx23885_stop_dma(port);
 	do_cancel_buffers(port, "cancel", 0);
diff --git a/drivers/media/video/cx23885/cx23885-dvb.c b/drivers/media/video/cx23885/cx23885-dvb.c
index 291b9d0..24bd183 100644
--- a/drivers/media/video/cx23885/cx23885-dvb.c
+++ b/drivers/media/video/cx23885/cx23885-dvb.c
@@ -42,6 +42,7 @@
 #include "tuner-simple.h"
 #include "dib7000p.h"
 #include "dibx000_common.h"
+#include "zl10353.h"
 
 static unsigned int debug;
 
@@ -188,13 +189,11 @@
 static struct xc5000_config hauppauge_hvr1500q_tunerconfig = {
 	.i2c_address      = 0x61,
 	.if_khz           = 5380,
-	.tuner_callback   = cx23885_tuner_callback
 };
 
 static struct xc5000_config dvico_xc5000_tunerconfig = {
 	.i2c_address      = 0x64,
 	.if_khz           = 5380,
-	.tuner_callback   = cx23885_tuner_callback
 };
 
 static struct tda829x_config tda829x_no_probe = {
@@ -303,35 +302,11 @@
 	.output_mode = OUTMODE_MPEG2_SERIAL,
 };
 
-static int cx23885_hvr1500_xc3028_callback(void *ptr, int command, int arg)
-{
-	struct cx23885_tsport *port = ptr;
-	struct cx23885_dev *dev = port->dev;
-
-	switch (command) {
-	case XC2028_TUNER_RESET:
-		/* Send the tuner in then out of reset */
-		/* GPIO-2 xc3028 tuner */
-		dprintk(1, "%s: XC2028_TUNER_RESET %d\n", __func__, arg);
-
-		cx_set(GP0_IO, 0x00040000);
-		cx_clear(GP0_IO, 0x00000004);
-		msleep(5);
-
-		cx_set(GP0_IO, 0x00040004);
-		msleep(5);
-		break;
-	case XC2028_RESET_CLK:
-		dprintk(1, "%s: XC2028_RESET_CLK %d\n", __func__, arg);
-		break;
-	default:
-		dprintk(1, "%s: unknown command %d, arg %d\n", __func__,
-			command, arg);
-		return -EINVAL;
-	}
-
-	return 0;
-}
+static struct zl10353_config dvico_fusionhdtv_xc3028 = {
+	.demod_address = 0x0f,
+	.if2           = 45600,
+	.no_tuner      = 1,
+};
 
 static int dvb_register(struct cx23885_tsport *port)
 {
@@ -413,8 +388,8 @@
 						&dev->i2c_bus[0].i2c_adap);
 		if (port->dvb.frontend != NULL)
 			dvb_attach(xc5000_attach, port->dvb.frontend,
-				&i2c_bus->i2c_adap,
-				&hauppauge_hvr1500q_tunerconfig, i2c_bus);
+				   &i2c_bus->i2c_adap,
+				   &hauppauge_hvr1500q_tunerconfig);
 		break;
 	case CX23885_BOARD_HAUPPAUGE_HVR1500:
 		i2c_bus = &dev->i2c_bus[1];
@@ -426,10 +401,9 @@
 			struct xc2028_config cfg = {
 				.i2c_adap  = &i2c_bus->i2c_adap,
 				.i2c_addr  = 0x61,
-				.callback  = cx23885_hvr1500_xc3028_callback,
 			};
 			static struct xc2028_ctrl ctl = {
-				.fname       = "xc3028-v27.fw",
+				.fname       = XC2028_DEFAULT_FIRMWARE,
 				.max_len     = 64,
 				.scode_table = XC3028_FE_OREN538,
 			};
@@ -465,13 +439,13 @@
 			struct xc2028_config cfg = {
 				.i2c_adap  = &dev->i2c_bus[1].i2c_adap,
 				.i2c_addr  = 0x64,
-				.callback  = cx23885_hvr1500_xc3028_callback,
 			};
 			static struct xc2028_ctrl ctl = {
-				.fname   = "xc3028L-v36.fw",
+				.fname   = XC3028L_DEFAULT_FIRMWARE,
 				.max_len = 64,
 				.demod   = 5000,
-				.d2633   = 1
+				/* This is true for all demods with v36 firmware? */
+				.type    = XC2028_D2633,
 			};
 
 			fe = dvb_attach(xc2028_attach,
@@ -492,8 +466,57 @@
 							&i2c_bus->i2c_adap);
 		if (port->dvb.frontend != NULL)
 			dvb_attach(xc5000_attach, port->dvb.frontend,
-				&i2c_bus->i2c_adap,
-				&dvico_xc5000_tunerconfig, i2c_bus);
+				   &i2c_bus->i2c_adap,
+				   &dvico_xc5000_tunerconfig);
+		break;
+	case CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP: {
+		i2c_bus = &dev->i2c_bus[port->nr - 1];
+
+		port->dvb.frontend = dvb_attach(zl10353_attach,
+					       &dvico_fusionhdtv_xc3028,
+					       &i2c_bus->i2c_adap);
+		if (port->dvb.frontend != NULL) {
+			struct dvb_frontend      *fe;
+			struct xc2028_config	  cfg = {
+				.i2c_adap  = &i2c_bus->i2c_adap,
+				.i2c_addr  = 0x61,
+			};
+			static struct xc2028_ctrl ctl = {
+				.fname       = XC2028_DEFAULT_FIRMWARE,
+				.max_len     = 64,
+				.demod       = XC3028_FE_ZARLINK456,
+			};
+
+			fe = dvb_attach(xc2028_attach, port->dvb.frontend,
+					&cfg);
+			if (fe != NULL && fe->ops.tuner_ops.set_config != NULL)
+				fe->ops.tuner_ops.set_config(fe, &ctl);
+		}
+		break;
+	}
+	case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H:
+		i2c_bus = &dev->i2c_bus[0];
+
+		port->dvb.frontend = dvb_attach(zl10353_attach,
+			&dvico_fusionhdtv_xc3028,
+			&i2c_bus->i2c_adap);
+		if (port->dvb.frontend != NULL) {
+			struct dvb_frontend      *fe;
+			struct xc2028_config	  cfg = {
+				.i2c_adap  = &dev->i2c_bus[1].i2c_adap,
+				.i2c_addr  = 0x61,
+			};
+			static struct xc2028_ctrl ctl = {
+				.fname       = XC2028_DEFAULT_FIRMWARE,
+				.max_len     = 64,
+				.demod       = XC3028_FE_ZARLINK456,
+			};
+
+			fe = dvb_attach(xc2028_attach, port->dvb.frontend,
+				&cfg);
+			if (fe != NULL && fe->ops.tuner_ops.set_config != NULL)
+				fe->ops.tuner_ops.set_config(fe, &ctl);
+		}
 		break;
 	default:
 		printk("%s: The frontend of your DVB/ATSC card isn't supported yet\n",
@@ -504,6 +527,8 @@
 		printk("%s: frontend initialization failed\n", dev->name);
 		return -1;
 	}
+	/* define general-purpose callback pointer */
+	port->dvb.frontend->callback = cx23885_tuner_callback;
 
 	/* Put the analog decoder in standby to keep it quiet */
 	cx23885_call_i2c_clients(i2c_bus, TUNER_SET_STANDBY, NULL);
diff --git a/drivers/media/video/cx23885/cx23885-vbi.c b/drivers/media/video/cx23885/cx23885-vbi.c
index 35e61cd..5b297f0 100644
--- a/drivers/media/video/cx23885/cx23885-vbi.c
+++ b/drivers/media/video/cx23885/cx23885-vbi.c
@@ -85,18 +85,8 @@
 	return 0;
 }
 
-int cx23885_stop_vbi_dma(struct cx23885_dev *dev)
-{
-	/* stop dma */
-	cx_clear(VID_A_DMA_CTL, 0x00000022);
 
-	/* disable irqs */
-	cx_clear(PCI_INT_MSK, 0x000001);
-	cx_clear(VID_A_INT_MSK, 0x00000022);
-	return 0;
-}
-
-int cx23885_restart_vbi_queue(struct cx23885_dev    *dev,
+static int cx23885_restart_vbi_queue(struct cx23885_dev    *dev,
 			     struct cx23885_dmaqueue *q)
 {
 	struct cx23885_buffer *buf;
diff --git a/drivers/media/video/cx23885/cx23885-video.c b/drivers/media/video/cx23885/cx23885-video.c
index 6047c78..f75ed1c 100644
--- a/drivers/media/video/cx23885/cx23885-video.c
+++ b/drivers/media/video/cx23885/cx23885-video.c
@@ -244,7 +244,7 @@
 };
 static const int CX23885_CTLS = ARRAY_SIZE(cx23885_ctls);
 
-const u32 cx23885_user_ctrls[] = {
+static const u32 cx23885_user_ctrls[] = {
 	V4L2_CID_USER_CLASS,
 	V4L2_CID_BRIGHTNESS,
 	V4L2_CID_CONTRAST,
@@ -254,14 +254,13 @@
 	V4L2_CID_AUDIO_MUTE,
 	0
 };
-EXPORT_SYMBOL(cx23885_user_ctrls);
 
 static const u32 *ctrl_classes[] = {
 	cx23885_user_ctrls,
 	NULL
 };
 
-void cx23885_video_wakeup(struct cx23885_dev *dev,
+static void cx23885_video_wakeup(struct cx23885_dev *dev,
 		 struct cx23885_dmaqueue *q, u32 count)
 {
 	struct cx23885_buffer *buf;
@@ -296,7 +295,7 @@
 			__func__, bc);
 }
 
-int cx23885_set_tvnorm(struct cx23885_dev *dev, v4l2_std_id norm)
+static int cx23885_set_tvnorm(struct cx23885_dev *dev, v4l2_std_id norm)
 {
 	dprintk(1, "%s(norm = 0x%08x) name: [%s]\n",
 		__func__,
@@ -314,7 +313,7 @@
 	return 0;
 }
 
-struct video_device *cx23885_vdev_init(struct cx23885_dev *dev,
+static struct video_device *cx23885_vdev_init(struct cx23885_dev *dev,
 				    struct pci_dev *pci,
 				    struct video_device *template,
 				    char *type)
@@ -334,7 +333,7 @@
 	return vfd;
 }
 
-int cx23885_ctrl_query(struct v4l2_queryctrl *qctrl)
+static int cx23885_ctrl_query(struct v4l2_queryctrl *qctrl)
 {
 	int i;
 
@@ -351,7 +350,6 @@
 	*qctrl = cx23885_ctls[i].v;
 	return 0;
 }
-EXPORT_SYMBOL(cx23885_ctrl_query);
 
 /* ------------------------------------------------------------------- */
 /* resource management                                                 */
@@ -402,7 +400,7 @@
 	mutex_unlock(&dev->lock);
 }
 
-int cx23885_video_mux(struct cx23885_dev *dev, unsigned int input)
+static int cx23885_video_mux(struct cx23885_dev *dev, unsigned int input)
 {
 	struct v4l2_routing route;
 	memset(&route, 0, sizeof(route));
@@ -422,10 +420,9 @@
 
 	return 0;
 }
-EXPORT_SYMBOL(cx23885_video_mux);
 
 /* ------------------------------------------------------------------ */
-int cx23885_set_scale(struct cx23885_dev *dev, unsigned int width,
+static int cx23885_set_scale(struct cx23885_dev *dev, unsigned int width,
 	unsigned int height, enum v4l2_field field)
 {
 	dprintk(1, "%s()\n", __func__);
@@ -731,6 +728,7 @@
 	enum v4l2_buf_type type = 0;
 	int radio = 0;
 
+	lock_kernel();
 	list_for_each(list, &cx23885_devlist) {
 		h = list_entry(list, struct cx23885_dev, devlist);
 		if (h->video_dev->minor == minor) {
@@ -748,16 +746,20 @@
 			dev   = h;
 		}
 	}
-	if (NULL == dev)
+	if (NULL == dev) {
+		unlock_kernel();
 		return -ENODEV;
+	}
 
 	dprintk(1, "open minor=%d radio=%d type=%s\n",
 		minor, radio, v4l2_type_names[type]);
 
 	/* allocate + initialize per filehandle data */
 	fh = kzalloc(sizeof(*fh), GFP_KERNEL);
-	if (NULL == fh)
+	if (NULL == fh) {
+		unlock_kernel();
 		return -ENOMEM;
+	}
 	file->private_data = fh;
 	fh->dev      = dev;
 	fh->radio    = radio;
@@ -775,6 +777,7 @@
 
 	dprintk(1, "post videobuf_queue_init()\n");
 
+	unlock_kernel();
 
 	return 0;
 }
@@ -884,21 +887,19 @@
 /* ------------------------------------------------------------------ */
 /* VIDEO CTRL IOCTLS                                                  */
 
-int cx23885_get_control(struct cx23885_dev *dev, struct v4l2_control *ctl)
+static int cx23885_get_control(struct cx23885_dev *dev, struct v4l2_control *ctl)
 {
 	dprintk(1, "%s() calling cx25840(VIDIOC_G_CTRL)\n", __func__);
 	cx23885_call_i2c_clients(&dev->i2c_bus[2], VIDIOC_G_CTRL, ctl);
 	return 0;
 }
-EXPORT_SYMBOL(cx23885_get_control);
 
-int cx23885_set_control(struct cx23885_dev *dev, struct v4l2_control *ctl)
+static int cx23885_set_control(struct cx23885_dev *dev, struct v4l2_control *ctl)
 {
 	dprintk(1, "%s() calling cx25840(VIDIOC_S_CTRL)"
 		" (disabled - no action)\n", __func__);
 	return 0;
 }
-EXPORT_SYMBOL(cx23885_set_control);
 
 static void init_controls(struct cx23885_dev *dev)
 {
@@ -1146,7 +1147,7 @@
 	return 0;
 }
 
-int cx23885_enum_input(struct cx23885_dev *dev, struct v4l2_input *i)
+static int cx23885_enum_input(struct cx23885_dev *dev, struct v4l2_input *i)
 {
 	static const char *iname[] = {
 		[CX23885_VMUX_COMPOSITE1] = "Composite1",
@@ -1179,7 +1180,6 @@
 		i->std = CX23885_NORMS;
 	return 0;
 }
-EXPORT_SYMBOL(cx23885_enum_input);
 
 static int vidioc_enum_input(struct file *file, void *priv,
 				struct v4l2_input *i)
@@ -1288,7 +1288,7 @@
 	return 0;
 }
 
-int cx23885_set_freq(struct cx23885_dev *dev, struct v4l2_frequency *f)
+static int cx23885_set_freq(struct cx23885_dev *dev, struct v4l2_frequency *f)
 {
 	if (unlikely(UNSET == dev->tuner_type))
 		return -EINVAL;
@@ -1307,7 +1307,6 @@
 
 	return 0;
 }
-EXPORT_SYMBOL(cx23885_set_freq);
 
 static int vidioc_s_frequency(struct file *file, void *priv,
 				struct v4l2_frequency *f)
diff --git a/drivers/media/video/cx23885/cx23885.h b/drivers/media/video/cx23885/cx23885.h
index e23d97c0..ba4e0aa 100644
--- a/drivers/media/video/cx23885/cx23885.h
+++ b/drivers/media/video/cx23885/cx23885.h
@@ -64,6 +64,8 @@
 #define CX23885_BOARD_HAUPPAUGE_HVR1700        8
 #define CX23885_BOARD_HAUPPAUGE_HVR1400        9
 #define CX23885_BOARD_DVICO_FUSIONHDTV_7_DUAL_EXP 10
+#define CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP 11
+#define CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H 12
 
 /* Currently unsupported by the driver: PAL/H, NTSC/Kr, SECAM B/G/H/LC */
 #define CX23885_NORMS (\
@@ -409,7 +411,7 @@
 extern struct cx23885_subid cx23885_subids[];
 extern const unsigned int cx23885_idcount;
 
-extern int cx23885_tuner_callback(void *priv, int command, int arg);
+extern int cx23885_tuner_callback(void *priv, int component, int command, int arg);
 extern void cx23885_card_list(struct cx23885_dev *dev);
 extern int  cx23885_ir_init(struct cx23885_dev *dev);
 extern void cx23885_gpio_setup(struct cx23885_dev *dev);
diff --git a/drivers/media/video/cx25840/cx25840-vbi.c b/drivers/media/video/cx25840/cx25840-vbi.c
index 69f2bbd..58e6ef1 100644
--- a/drivers/media/video/cx25840/cx25840-vbi.c
+++ b/drivers/media/video/cx25840/cx25840-vbi.c
@@ -141,10 +141,11 @@
 		u8 lcr[24];
 
 		fmt = arg;
-		if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE)
+		if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE &&
+		    fmt->type != V4L2_BUF_TYPE_VBI_CAPTURE)
 			return -EINVAL;
 		svbi = &fmt->fmt.sliced;
-		if (svbi->service_set == 0) {
+		if (fmt->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
 			/* raw VBI */
 			memset(svbi, 0, sizeof(*svbi));
 
diff --git a/drivers/media/video/cx88/Kconfig b/drivers/media/video/cx88/Kconfig
index 9dd7bdf..0b9e5fa 100644
--- a/drivers/media/video/cx88/Kconfig
+++ b/drivers/media/video/cx88/Kconfig
@@ -58,6 +58,10 @@
 	select DVB_ISL6421 if !DVB_FE_CUSTOMISE
 	select MEDIA_TUNER_SIMPLE if !DVB_FE_CUSTOMISE
 	select DVB_S5H1411 if !DVB_FE_CUSTOMISE
+	select DVB_CX24116 if !DVB_FE_CUSTOMISE
+	select DVB_STV0299 if !DVB_FE_CUSTOMISE
+	select DVB_STV0288 if !DVB_FE_CUSTOMISE
+	select DVB_STB6000 if !DVB_FE_CUSTOMISE
 	---help---
 	  This adds support for DVB/ATSC cards based on the
 	  Conexant 2388x chip.
diff --git a/drivers/media/video/cx88/cx88-blackbird.c b/drivers/media/video/cx88/cx88-blackbird.c
index 9a1374a..e713697 100644
--- a/drivers/media/video/cx88/cx88-blackbird.c
+++ b/drivers/media/video/cx88/cx88-blackbird.c
@@ -1057,12 +1057,15 @@
 	struct cx8802_driver *drv = NULL;
 	int err;
 
+	lock_kernel();
 	dev = cx8802_get_device(inode);
 
 	dprintk( 1, "%s\n", __func__);
 
-	if (dev == NULL)
+	if (dev == NULL) {
+		unlock_kernel();
 		return -ENODEV;
+	}
 
 	/* Make sure we can acquire the hardware */
 	drv = cx8802_get_driver(dev, CX88_MPEG_BLACKBIRD);
@@ -1070,6 +1073,7 @@
 		err = drv->request_acquire(drv);
 		if(err != 0) {
 			dprintk(1,"%s: Unable to acquire hardware, %d\n", __func__, err);
+			unlock_kernel();
 			return err;
 		}
 	}
@@ -1077,6 +1081,7 @@
 	if (blackbird_initialize_codec(dev) < 0) {
 		if (drv)
 			drv->request_release(drv);
+		unlock_kernel();
 		return -EINVAL;
 	}
 	dprintk(1,"open minor=%d\n",minor);
@@ -1086,6 +1091,7 @@
 	if (NULL == fh) {
 		if (drv)
 			drv->request_release(drv);
+		unlock_kernel();
 		return -ENOMEM;
 	}
 	file->private_data = fh;
@@ -1101,6 +1107,7 @@
 	/* FIXME: locking against other video device */
 	cx88_set_scale(dev->core, dev->width, dev->height,
 			fh->mpegq.field);
+	unlock_kernel();
 
 	return 0;
 }
diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c
index de199a2..5da04e81 100644
--- a/drivers/media/video/cx88/cx88-cards.c
+++ b/drivers/media/video/cx88/cx88-cards.c
@@ -1349,27 +1349,30 @@
 		.radio_addr	= ADDR_UNSET,
 		.tda9887_conf   = TDA9887_PRESENT,
 		.audio_chip     = V4L2_IDENT_WM8775,
+		/*
+		 * gpio0 as reported by Mike Crash <mike AT mikecrash.com>
+		 */
 		.input		= {{
 			.type   = CX88_VMUX_TELEVISION,
 			.vmux   = 0,
-			.gpio0	= 0xe780,
+			.gpio0	= 0xef88,
 			.audioroute = 1,
 		},{
 			.type	= CX88_VMUX_COMPOSITE1,
 			.vmux	= 1,
-			.gpio0	= 0xe780,
+			.gpio0	= 0xef88,
 			.audioroute = 2,
 		},{
 			.type	= CX88_VMUX_SVIDEO,
 			.vmux	= 2,
-			.gpio0	= 0xe780,
+			.gpio0	= 0xef88,
 			.audioroute = 2,
 		}},
 		/* fixme: Add radio support */
 		.mpeg           = CX88_MPEG_DVB | CX88_MPEG_BLACKBIRD,
 		.radio = {
 			.type   = CX88_RADIO,
-			.gpio0	= 0xe780,
+			.gpio0	= 0xef88,
 		},
 	},
 	[CX88_BOARD_ADSTECH_PTV_390] = {
@@ -1446,15 +1449,26 @@
 		.name           = "Pinnacle Hybrid PCTV",
 		.tuner_type     = TUNER_XC2028,
 		.tuner_addr     = 0x61,
+		.radio_type     = TUNER_XC2028,
+		.radio_addr     = 0x61,
 		.input          = { {
 			.type   = CX88_VMUX_TELEVISION,
 			.vmux   = 0,
+			.gpio0  = 0x004ff,
+			.gpio1  = 0x010ff,
+			.gpio2  = 0x00001,
 		}, {
 			.type   = CX88_VMUX_COMPOSITE1,
 			.vmux   = 1,
+			.gpio0  = 0x004fb,
+			.gpio1  = 0x010ef,
+			.audioroute = 1,
 		}, {
 			.type   = CX88_VMUX_SVIDEO,
 			.vmux   = 2,
+			.gpio0  = 0x004fb,
+			.gpio1  = 0x010ef,
+			.audioroute = 1,
 		} },
 		.radio = {
 			.type   = CX88_RADIO,
@@ -1462,6 +1476,7 @@
 			.gpio1  = 0x010ff,
 			.gpio2  = 0x0ff,
 		},
+		.mpeg           = CX88_MPEG_DVB,
 	},
 	[CX88_BOARD_WINFAST_TV2000_XP_GLOBAL] = {
 		.name           = "Winfast TV2000 XP Global",
@@ -1566,9 +1581,9 @@
 	},
 	[CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PRO] = {
 		.name           = "DViCO FusionHDTV DVB-T PRO",
-		.tuner_type     = TUNER_ABSENT, /* XXX: Has XC3028 */
+		.tuner_type     = TUNER_XC2028,
+		.tuner_addr     = 0x61,
 		.radio_type     = UNSET,
-		.tuner_addr     = ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
 		.input          = { {
 			.type   = CX88_VMUX_COMPOSITE1,
@@ -1625,6 +1640,36 @@
 			.gpio2 = 0x0cfb,
 		},
 	},
+	[CX88_BOARD_PROLINK_PV_GLOBAL_XTREME] = {
+		.name           = "Prolink Pixelview Global Extreme",
+		.tuner_type     = TUNER_XC2028,
+		.tuner_addr     = 0x61,
+		.input          = { {
+			.type   = CX88_VMUX_TELEVISION,
+			.vmux   = 0,
+			.gpio0 = 0x04fb,
+			.gpio1 = 0x04080,
+			.gpio2 = 0x0cf7,
+		}, {
+			.type   = CX88_VMUX_COMPOSITE1,
+			.vmux   = 1,
+			.gpio0 = 0x04fb,
+			.gpio1 = 0x04080,
+			.gpio2 = 0x0cfb,
+		}, {
+			.type   = CX88_VMUX_SVIDEO,
+			.vmux   = 2,
+			.gpio0 = 0x04fb,
+			.gpio1 = 0x04080,
+			.gpio2 = 0x0cfb,
+		} },
+		.radio = {
+			.type   = CX88_RADIO,
+			.gpio0 = 0x04ff,
+			.gpio1 = 0x04080,
+			.gpio2 = 0x0cf7,
+		},
+	},
 	/* Both radio, analog and ATSC work with this board.
 	   However, for analog to work, s5h1409 gate should be open,
 	   otherwise, tuner-xc3028 won't be detected.
@@ -1664,6 +1709,131 @@
 		},
 		.mpeg           = CX88_MPEG_DVB,
 	},
+	[CX88_BOARD_HAUPPAUGE_HVR4000] = {
+		.name           = "Hauppauge WinTV-HVR4000 DVB-S/S2/T/Hybrid",
+		.tuner_type     = TUNER_PHILIPS_FMD1216ME_MK3,
+		.radio_type     = UNSET,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.tda9887_conf   = TDA9887_PRESENT,
+		/*
+		 * GPIO0 (WINTV2000)
+		 *
+		 * Analogue     SAT     DVB-T
+		 * Antenna      0xc4bf  0xc4bb
+		 * Composite    0xc4bf  0xc4bb
+		 * S-Video      0xc4bf  0xc4bb
+		 * Composite1   0xc4ff  0xc4fb
+		 * S-Video1     0xc4ff  0xc4fb
+		 *
+		 * BIT  VALUE   FUNCTION GP{x}_IO
+		 * 0    1       I:?
+		 * 1    1       I:?
+		 * 2    1       O:DVB-T DEMOD ENABLE LOW/ANALOG DEMOD ENABLE HIGH
+		 * 3    1       I:?
+		 * 4    1       I:?
+		 * 5    1       I:?
+		 * 6    0       O:INPUT SELECTOR 0=INTERNAL 1=EXPANSION
+		 * 7    1       O:DVB-T DEMOD RESET LOW
+		 *
+		 * BIT  VALUE   FUNCTION GP{x}_OE
+		 * 8    0       I
+		 * 9    0       I
+		 * a    1       O
+		 * b    0       I
+		 * c    0       I
+		 * d    0       I
+		 * e    1       O
+		 * f    1       O
+		 */
+		.input          = {{
+			.type   = CX88_VMUX_TELEVISION,
+			.vmux   = 0,
+			.gpio0  = 0xc4bf,
+		}, {
+			.type   = CX88_VMUX_COMPOSITE1,
+			.vmux   = 1,
+			.gpio0  = 0xc4bf,
+		}, {
+			.type   = CX88_VMUX_SVIDEO,
+			.vmux   = 2,
+			.gpio0  = 0xc4bf,
+		} },
+		/* fixme: Add radio support */
+		.mpeg           = CX88_MPEG_DVB,
+	},
+	[CX88_BOARD_HAUPPAUGE_HVR4000LITE] = {
+		.name           = "Hauppauge WinTV-HVR4000(Lite) DVB-S/S2",
+		.tuner_type     = UNSET,
+		.radio_type     = UNSET,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.input          = {{
+			.type   = CX88_VMUX_DVB,
+			.vmux   = 0,
+		} },
+		.mpeg           = CX88_MPEG_DVB,
+	},
+	[CX88_BOARD_TEVII_S420] = {
+		.name           = "TeVii S420 DVB-S",
+		.tuner_type     = UNSET,
+		.radio_type     = UNSET,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.input          = {{
+			.type   = CX88_VMUX_DVB,
+			.vmux   = 0,
+		} },
+		.mpeg           = CX88_MPEG_DVB,
+	},
+	[CX88_BOARD_TEVII_S460] = {
+		.name           = "TeVii S460 DVB-S/S2",
+		.tuner_type     = UNSET,
+		.radio_type     = UNSET,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.input          = {{
+			.type   = CX88_VMUX_DVB,
+			.vmux   = 0,
+		} },
+		.mpeg           = CX88_MPEG_DVB,
+	},
+	[CX88_BOARD_OMICOM_SS4_PCI] = {
+		.name           = "Omicom SS4 DVB-S/S2 PCI",
+		.tuner_type     = UNSET,
+		.radio_type     = UNSET,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.input          = {{
+			.type   = CX88_VMUX_DVB,
+			.vmux   = 0,
+		} },
+		.mpeg           = CX88_MPEG_DVB,
+	},
+	[CX88_BOARD_TBS_8920] = {
+		.name           = "TBS 8920 DVB-S/S2",
+		.tuner_type     = TUNER_ABSENT,
+		.radio_type     = UNSET,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.input          = {{
+			.type   = CX88_VMUX_DVB,
+			.vmux   = 1,
+		} },
+		.mpeg           = CX88_MPEG_DVB,
+	},
+	[CX88_BOARD_PROF_7300] = {
+		.name           = "PROF 7300 DVB-S/S2",
+		.tuner_type     = UNSET,
+		.radio_type     = UNSET,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.input          = {{
+			.type   = CX88_VMUX_DVB,
+			.vmux   = 0,
+		} },
+		.mpeg           = CX88_MPEG_DVB,
+	},
 };
 
 /* ------------------------------------------------------------------ */
@@ -2010,9 +2180,53 @@
 		.subdevice = 0x4935,
 		.card      = CX88_BOARD_PROLINK_PV_8000GT,
 	}, {
+		.subvendor = 0x1554,
+		.subdevice = 0x4976,
+		.card      = CX88_BOARD_PROLINK_PV_GLOBAL_XTREME,
+	}, {
 		.subvendor = 0x17de,
 		.subdevice = 0x08c1,
 		.card      = CX88_BOARD_KWORLD_ATSC_120,
+	}, {
+		.subvendor = 0x0070,
+		.subdevice = 0x6900,
+		.card      = CX88_BOARD_HAUPPAUGE_HVR4000,
+	}, {
+		.subvendor = 0x0070,
+		.subdevice = 0x6904,
+		.card      = CX88_BOARD_HAUPPAUGE_HVR4000,
+	}, {
+		.subvendor = 0x0070,
+		.subdevice = 0x6902,
+		.card      = CX88_BOARD_HAUPPAUGE_HVR4000,
+	}, {
+		.subvendor = 0x0070,
+		.subdevice = 0x6905,
+		.card      = CX88_BOARD_HAUPPAUGE_HVR4000LITE,
+	}, {
+		.subvendor = 0x0070,
+		.subdevice = 0x6906,
+		.card      = CX88_BOARD_HAUPPAUGE_HVR4000LITE,
+	}, {
+		.subvendor = 0xd420,
+		.subdevice = 0x9022,
+		.card      = CX88_BOARD_TEVII_S420,
+	}, {
+		.subvendor = 0xd460,
+		.subdevice = 0x9022,
+		.card      = CX88_BOARD_TEVII_S460,
+	}, {
+		.subvendor = 0xA044,
+		.subdevice = 0x2011,
+		.card      = CX88_BOARD_OMICOM_SS4_PCI,
+	}, {
+		.subvendor = 0x8920,
+		.subdevice = 0x8888,
+		.card      = CX88_BOARD_TBS_8920,
+	}, {
+		.subvendor = 0xB033,
+		.subdevice = 0x3033,
+		.card      = CX88_BOARD_PROF_7300,
 	},
 };
 
@@ -2065,6 +2279,13 @@
 	case 14669: /* WinTV-HVR3000 (OEM, no IR, no b/panel video - Low profile) */
 	case 28552: /* WinTV-PVR 'Roslyn' (No IR) */
 	case 34519: /* WinTV-PCI-FM */
+	case 69009:
+		/* WinTV-HVR4000 (DVBS/S2/T, Video and IR, back panel inputs) */
+	case 69100: /* WinTV-HVR4000LITE (DVBS/S2, IR) */
+	case 69500: /* WinTV-HVR4000LITE (DVBS/S2, No IR) */
+	case 69559:
+		/* WinTV-HVR4000 (DVBS/S2/T, Video no IR, back panel inputs) */
+	case 69569: /* WinTV-HVR4000 (DVBS/S2/T, Video no IR) */
 	case 90002: /* Nova-T-PCI (9002) */
 	case 92001: /* Nova-S-Plus (Video and IR) */
 	case 92002: /* Nova-S-Plus (Video and IR) */
@@ -2149,9 +2370,21 @@
 {
 	switch (command) {
 	case XC2028_TUNER_RESET:
-		cx_write(MO_GP0_IO, 0x101000);
-		mdelay(5);
-		cx_set(MO_GP0_IO, 0x101010);
+		switch (core->boardnr) {
+		case CX88_BOARD_DVICO_FUSIONHDTV_5_PCI_NANO:
+			/* GPIO-4 xc3028 tuner */
+
+			cx_set(MO_GP0_IO, 0x00001000);
+			cx_clear(MO_GP0_IO, 0x00000010);
+			msleep(100);
+			cx_set(MO_GP0_IO, 0x00000010);
+			msleep(100);
+			break;
+		default:
+			cx_write(MO_GP0_IO, 0x101000);
+			mdelay(5);
+			cx_set(MO_GP0_IO, 0x101010);
+		}
 		break;
 	default:
 		return -EINVAL;
@@ -2258,8 +2491,10 @@
 		return cx88_xc3028_geniatech_tuner_callback(core,
 							command, arg);
 	case CX88_BOARD_PROLINK_PV_8000GT:
+	case CX88_BOARD_PROLINK_PV_GLOBAL_XTREME:
 		return cx88_pv_8000gt_callback(core, command, arg);
 	case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PRO:
+	case CX88_BOARD_DVICO_FUSIONHDTV_5_PCI_NANO:
 		return cx88_dvico_xc2028_callback(core, command, arg);
 	}
 
@@ -2327,7 +2562,7 @@
 	return 0; /* Should never be here */
 }
 
-int cx88_tuner_callback(void *priv, int command, int arg)
+int cx88_tuner_callback(void *priv, int component, int command, int arg)
 {
 	struct i2c_algo_bit_data *i2c_algo = priv;
 	struct cx88_core *core;
@@ -2344,6 +2579,9 @@
 		return -EINVAL;
 	}
 
+	if (component != DVB_FRONTEND_COMPONENT_TUNER)
+		return -EINVAL;
+
 	switch (core->board.tuner_type) {
 		case TUNER_XC2028:
 			info_printk(core, "Calling XC2028/3028 callback\n");
@@ -2392,16 +2630,22 @@
 {
 	switch (core->boardnr) {
 	case CX88_BOARD_HAUPPAUGE_HVR1300:
-		/* Bring the 702 demod up before i2c scanning/attach or devices are hidden */
-		/* We leave here with the 702 on the bus */
-		cx_write(MO_GP0_IO, 0x0000e780);
+		/*
+		 * Bring the 702 demod up before i2c scanning/attach or devices are hidden
+		 * We leave here with the 702 on the bus
+		 *
+		 * "reset the IR receiver on GPIO[3]"
+		 * Reported by Mike Crash <mike AT mikecrash.com>
+		 */
+		cx_write(MO_GP0_IO, 0x0000ef88);
 		udelay(1000);
-		cx_clear(MO_GP0_IO, 0x00000080);
+		cx_clear(MO_GP0_IO, 0x00000088);
 		udelay(50);
-		cx_set(MO_GP0_IO, 0x00000080); /* 702 out of reset */
+		cx_set(MO_GP0_IO, 0x00000088); /* 702 out of reset */
 		udelay(1000);
 		break;
 
+	case CX88_BOARD_PROLINK_PV_GLOBAL_XTREME:
 	case CX88_BOARD_PROLINK_PV_8000GT:
 		cx_write(MO_GP2_IO, 0xcf7);
 		mdelay(50);
@@ -2411,10 +2655,18 @@
 		msleep(10);
 		break;
 
-	 case CX88_BOARD_DVICO_FUSIONHDTV_7_GOLD:
+	case CX88_BOARD_DVICO_FUSIONHDTV_7_GOLD:
 		/* Enable the xc5000 tuner */
 		cx_set(MO_GP0_IO, 0x00001010);
 		break;
+
+	case CX88_BOARD_HAUPPAUGE_HVR3000:
+	case CX88_BOARD_HAUPPAUGE_HVR4000:
+	case CX88_BOARD_HAUPPAUGE_HVR4000LITE:
+		/* Init GPIO */
+		cx_write(MO_GP0_IO, core->board.input[0].gpio0);
+		udelay(1000);
+		break;
 	}
 }
 
@@ -2435,17 +2687,22 @@
 			core->i2c_algo.udelay = 16;
 		break;
 	case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PRO:
-		ctl->scode_table = XC3028_FE_ZARLINK456;
+		ctl->demod = XC3028_FE_ZARLINK456;
 		break;
 	case CX88_BOARD_KWORLD_ATSC_120:
 	case CX88_BOARD_DVICO_FUSIONHDTV_5_PCI_NANO:
 		ctl->demod = XC3028_FE_OREN538;
 		break;
+	case CX88_BOARD_PROLINK_PV_GLOBAL_XTREME:
 	case CX88_BOARD_PROLINK_PV_8000GT:
 		/*
-		 * This board uses non-MTS firmware
+		 * Those boards uses non-MTS firmware
 		 */
 		break;
+	case CX88_BOARD_PINNACLE_HYBRID_PCTV:
+		ctl->demod = XC3028_FE_ZARLINK456;
+		ctl->mts = 1;
+		break;
 	default:
 		ctl->demod = XC3028_FE_OREN538;
 		ctl->mts = 1;
@@ -2489,6 +2746,8 @@
 	case CX88_BOARD_HAUPPAUGE_HVR1100LP:
 	case CX88_BOARD_HAUPPAUGE_HVR3000:
 	case CX88_BOARD_HAUPPAUGE_HVR1300:
+	case CX88_BOARD_HAUPPAUGE_HVR4000:
+	case CX88_BOARD_HAUPPAUGE_HVR4000LITE:
 		if (0 == core->i2c_rc)
 			hauppauge_eeprom(core, eeprom);
 		break;
@@ -2570,7 +2829,18 @@
 		tea5767_cfg.priv  = &ctl;
 
 		cx88_call_i2c_clients(core, TUNER_SET_CONFIG, &tea5767_cfg);
+		break;
 	}
+	case  CX88_BOARD_TEVII_S420:
+	case  CX88_BOARD_TEVII_S460:
+	case  CX88_BOARD_OMICOM_SS4_PCI:
+	case  CX88_BOARD_TBS_8920:
+	case  CX88_BOARD_PROF_7300:
+		cx_write(MO_SRST_IO, 0);
+		msleep(100);
+		cx_write(MO_SRST_IO, 1);
+		msleep(100);
+		break;
 	} /*end switch() */
 
 
diff --git a/drivers/media/video/cx88/cx88-dvb.c b/drivers/media/video/cx88/cx88-dvb.c
index d96173f..344ed26 100644
--- a/drivers/media/video/cx88/cx88-dvb.c
+++ b/drivers/media/video/cx88/cx88-dvb.c
@@ -48,6 +48,11 @@
 #include "tuner-simple.h"
 #include "tda9887.h"
 #include "s5h1411.h"
+#include "stv0299.h"
+#include "z0194a.h"
+#include "stv0288.h"
+#include "stb6000.h"
+#include "cx24116.h"
 
 MODULE_DESCRIPTION("driver for cx2388x based DVB cards");
 MODULE_AUTHOR("Chris Pascoe <c.pascoe@itee.uq.edu.au>");
@@ -375,37 +380,28 @@
 	return 0;
 }
 
-static int cx88_pci_nano_callback(void *ptr, int command, int arg)
+static int tevii_dvbs_set_voltage(struct dvb_frontend *fe,
+				      fe_sec_voltage_t voltage)
 {
-	struct cx88_core *core = ptr;
+	struct cx8802_dev *dev= fe->dvb->priv;
+	struct cx88_core *core = dev->core;
 
-	switch (command) {
-	case XC2028_TUNER_RESET:
-		/* Send the tuner in then out of reset */
-		dprintk(1, "%s: XC2028_TUNER_RESET %d\n", __func__, arg);
-
-		switch (core->boardnr) {
-		case CX88_BOARD_DVICO_FUSIONHDTV_5_PCI_NANO:
-			/* GPIO-4 xc3028 tuner */
-
-			cx_set(MO_GP0_IO, 0x00001000);
-			cx_clear(MO_GP0_IO, 0x00000010);
-			msleep(100);
-			cx_set(MO_GP0_IO, 0x00000010);
-			msleep(100);
+	switch (voltage) {
+		case SEC_VOLTAGE_13:
+			printk("LNB Voltage SEC_VOLTAGE_13\n");
+			cx_write(MO_GP0_IO, 0x00006040);
 			break;
-		}
-
-		break;
-	case XC2028_RESET_CLK:
-		dprintk(1, "%s: XC2028_RESET_CLK %d\n", __func__, arg);
-		break;
-	default:
-		dprintk(1, "%s: unknown command %d, arg %d\n", __func__,
-			command, arg);
-		return -EINVAL;
+		case SEC_VOLTAGE_18:
+			printk("LNB Voltage SEC_VOLTAGE_18\n");
+			cx_write(MO_GP0_IO, 0x00006060);
+			break;
+		case SEC_VOLTAGE_OFF:
+			printk("LNB Voltage SEC_VOLTAGE_off\n");
+			break;
 	}
 
+	if (core->prev_set_voltage)
+		return core->prev_set_voltage(fe, voltage);
 	return 0;
 }
 
@@ -456,7 +452,12 @@
 static struct xc5000_config pinnacle_pctv_hd_800i_tuner_config = {
 	.i2c_address	= 0x64,
 	.if_khz		= 5380,
-	.tuner_callback	= cx88_tuner_callback,
+};
+
+static struct zl10353_config cx88_pinnacle_hybrid_pctv = {
+	.demod_address = (0x1e >> 1),
+	.no_tuner      = 1,
+	.if2           = 45600,
 };
 
 static struct zl10353_config cx88_geniatech_x8000_mt = {
@@ -477,7 +478,6 @@
 static struct xc5000_config dvico_fusionhdtv7_tuner_config = {
 	.i2c_address    = 0xc2 >> 1,
 	.if_khz         = 5380,
-	.tuner_callback = cx88_tuner_callback,
 };
 
 static int attach_xc3028(u8 addr, struct cx8802_dev *dev)
@@ -488,7 +488,6 @@
 		.i2c_adap  = &dev->core->i2c_adap,
 		.i2c_addr  = addr,
 		.ctrl      = &ctl,
-		.callback  = cx88_tuner_callback,
 	};
 
 	if (!dev->dvb.frontend) {
@@ -518,6 +517,60 @@
 	return 0;
 }
 
+static int cx24116_set_ts_param(struct dvb_frontend *fe,
+	int is_punctured)
+{
+	struct cx8802_dev *dev = fe->dvb->priv;
+	dev->ts_gen_cntrl = 0x2;
+
+	return 0;
+}
+
+static int cx24116_reset_device(struct dvb_frontend *fe)
+{
+	struct cx8802_dev *dev = fe->dvb->priv;
+	struct cx88_core *core = dev->core;
+
+	/* Reset the part */
+	cx_write(MO_SRST_IO, 0);
+	msleep(10);
+	cx_write(MO_SRST_IO, 1);
+	msleep(10);
+
+	return 0;
+}
+
+static struct cx24116_config hauppauge_hvr4000_config = {
+	.demod_address          = 0x05,
+	.set_ts_params          = cx24116_set_ts_param,
+	.reset_device           = cx24116_reset_device,
+};
+
+static struct cx24116_config tevii_s460_config = {
+	.demod_address = 0x55,
+	.set_ts_params = cx24116_set_ts_param,
+	.reset_device  = cx24116_reset_device,
+};
+
+static struct stv0299_config tevii_tuner_sharp_config = {
+	.demod_address = 0x68,
+	.inittab = sharp_z0194a__inittab,
+	.mclk = 88000000UL,
+	.invert = 1,
+	.skip_reinit = 0,
+	.lock_output = 1,
+	.volt13_op0_op1 = STV0299_VOLT13_OP1,
+	.min_delay_ms = 100,
+	.set_symbol_rate = sharp_z0194a__set_symbol_rate,
+	.set_ts_params = cx24116_set_ts_param,
+};
+
+static struct stv0288_config tevii_tuner_earda_config = {
+	.demod_address = 0x68,
+	.min_delay_ms = 100,
+	.set_ts_params = cx24116_set_ts_param,
+};
+
 static int dvb_register(struct cx8802_dev *dev)
 {
 	struct cx88_core *core = dev->core;
@@ -786,7 +839,7 @@
 					       &core->i2c_adap);
 		if (dev->dvb.frontend) {
 			if (!dvb_attach(isl6421_attach, dev->dvb.frontend,
-					&core->i2c_adap, 0x08, 0x00, 0x00))
+					&core->i2c_adap, 0x08, ISL6421_DCL, 0x00))
 				goto frontend_detach;
 		}
 		break;
@@ -813,13 +866,9 @@
 					       &pinnacle_pctv_hd_800i_config,
 					       &core->i2c_adap);
 		if (dev->dvb.frontend != NULL) {
-			/* tuner_config.video_dev must point to
-			 * i2c_adap.algo_data
-			 */
 			if (!dvb_attach(xc5000_attach, dev->dvb.frontend,
 					&core->i2c_adap,
-					&pinnacle_pctv_hd_800i_tuner_config,
-					core->i2c_adap.algo_data))
+					&pinnacle_pctv_hd_800i_tuner_config))
 				goto frontend_detach;
 		}
 		break;
@@ -832,10 +881,9 @@
 			struct xc2028_config cfg = {
 				.i2c_adap  = &core->i2c_adap,
 				.i2c_addr  = 0x61,
-				.callback  = cx88_pci_nano_callback,
 			};
 			static struct xc2028_ctrl ctl = {
-				.fname       = "xc3028-v27.fw",
+				.fname       = XC2028_DEFAULT_FIRMWARE,
 				.max_len     = 64,
 				.scode_table = XC3028_FE_OREN538,
 			};
@@ -848,10 +896,13 @@
 		break;
 	 case CX88_BOARD_PINNACLE_HYBRID_PCTV:
 		dev->dvb.frontend = dvb_attach(zl10353_attach,
-					       &cx88_geniatech_x8000_mt,
+					       &cx88_pinnacle_hybrid_pctv,
 					       &core->i2c_adap);
-		if (attach_xc3028(0x61, dev) < 0)
-			goto frontend_detach;
+		if (dev->dvb.frontend) {
+			dev->dvb.frontend->ops.i2c_gate_ctrl = NULL;
+			if (attach_xc3028(0x61, dev) < 0)
+				goto frontend_detach;
+		}
 		break;
 	 case CX88_BOARD_GENIATECH_X8000_MT:
 		dev->ts_gen_cntrl = 0x00;
@@ -874,16 +925,69 @@
 					       &dvico_fusionhdtv7_config,
 					       &core->i2c_adap);
 		if (dev->dvb.frontend != NULL) {
-			/* tuner_config.video_dev must point to
-			 * i2c_adap.algo_data
-			 */
 			if (!dvb_attach(xc5000_attach, dev->dvb.frontend,
 					&core->i2c_adap,
-					&dvico_fusionhdtv7_tuner_config,
-					core->i2c_adap.algo_data))
+					&dvico_fusionhdtv7_tuner_config))
 				goto frontend_detach;
 		}
 		break;
+	case CX88_BOARD_HAUPPAUGE_HVR4000:
+	case CX88_BOARD_HAUPPAUGE_HVR4000LITE:
+		/* Support for DVB-S only, not DVB-T support */
+		dev->dvb.frontend = dvb_attach(cx24116_attach,
+			&hauppauge_hvr4000_config,
+			&dev->core->i2c_adap);
+		if (dev->dvb.frontend) {
+			dvb_attach(isl6421_attach, dev->dvb.frontend,
+				&dev->core->i2c_adap,
+				0x08, ISL6421_DCL, 0x00);
+		}
+		break;
+	case CX88_BOARD_TEVII_S420:
+		dev->dvb.frontend = dvb_attach(stv0299_attach,
+						&tevii_tuner_sharp_config,
+						&core->i2c_adap);
+		if (dev->dvb.frontend != NULL) {
+			if (!dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x60,
+					&core->i2c_adap, DVB_PLL_OPERA1))
+				goto frontend_detach;
+			core->prev_set_voltage = dev->dvb.frontend->ops.set_voltage;
+			dev->dvb.frontend->ops.set_voltage = tevii_dvbs_set_voltage;
+
+		} else {
+			dev->dvb.frontend = dvb_attach(stv0288_attach,
+							    &tevii_tuner_earda_config,
+							    &core->i2c_adap);
+				if (dev->dvb.frontend != NULL) {
+					if (!dvb_attach(stb6000_attach, dev->dvb.frontend, 0x61,
+						&core->i2c_adap))
+					goto frontend_detach;
+				core->prev_set_voltage = dev->dvb.frontend->ops.set_voltage;
+				dev->dvb.frontend->ops.set_voltage = tevii_dvbs_set_voltage;
+
+			}
+		}
+		break;
+	case CX88_BOARD_TEVII_S460:
+		dev->dvb.frontend = dvb_attach(cx24116_attach,
+					       &tevii_s460_config,
+					       &core->i2c_adap);
+		if (dev->dvb.frontend != NULL) {
+			core->prev_set_voltage = dev->dvb.frontend->ops.set_voltage;
+			dev->dvb.frontend->ops.set_voltage = tevii_dvbs_set_voltage;
+		}
+		break;
+	case CX88_BOARD_OMICOM_SS4_PCI:
+	case CX88_BOARD_TBS_8920:
+	case CX88_BOARD_PROF_7300:
+		dev->dvb.frontend = dvb_attach(cx24116_attach,
+					       &hauppauge_hvr4000_config,
+					       &core->i2c_adap);
+		if (dev->dvb.frontend != NULL) {
+			core->prev_set_voltage = dev->dvb.frontend->ops.set_voltage;
+			dev->dvb.frontend->ops.set_voltage = tevii_dvbs_set_voltage;
+		}
+		break;
 	default:
 		printk(KERN_ERR "%s/2: The frontend of your DVB/ATSC card isn't supported yet\n",
 		       core->name);
@@ -895,6 +999,8 @@
 		       core->name);
 		return -EINVAL;
 	}
+	/* define general-purpose callback pointer */
+	dev->dvb.frontend->callback = cx88_tuner_callback;
 
 	/* Ensure all frontends negotiate bus access */
 	dev->dvb.frontend->ops.ts_bus_ctrl = cx88_dvb_bus_ctrl;
diff --git a/drivers/media/video/cx88/cx88-i2c.c b/drivers/media/video/cx88/cx88-i2c.c
index d7406a9..8e74d64 100644
--- a/drivers/media/video/cx88/cx88-i2c.c
+++ b/drivers/media/video/cx88/cx88-i2c.c
@@ -201,7 +201,23 @@
 
 	core->i2c_rc = i2c_bit_add_bus(&core->i2c_adap);
 	if (0 == core->i2c_rc) {
+		static u8 tuner_data[] =
+			{ 0x0b, 0xdc, 0x86, 0x52 };
+		static struct i2c_msg tuner_msg =
+			{ .flags = 0, .addr = 0xc2 >> 1, .buf = tuner_data, .len = 4 };
+
 		dprintk(1, "i2c register ok\n");
+		switch( core->boardnr ) {
+			case CX88_BOARD_HAUPPAUGE_HVR1300:
+			case CX88_BOARD_HAUPPAUGE_HVR3000:
+			case CX88_BOARD_HAUPPAUGE_HVR4000:
+				printk("%s: i2c init: enabling analog demod on HVR1300/3000/4000 tuner\n",
+					core->name);
+				i2c_transfer(core->i2c_client.adapter, &tuner_msg, 1);
+				break;
+			default:
+				break;
+		}
 		if (i2c_scan)
 			do_i2c_scan(core->name,&core->i2c_client);
 	} else
diff --git a/drivers/media/video/cx88/cx88-input.c b/drivers/media/video/cx88/cx88-input.c
index 53526d9..8683d10 100644
--- a/drivers/media/video/cx88/cx88-input.c
+++ b/drivers/media/video/cx88/cx88-input.c
@@ -224,6 +224,8 @@
 	case CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1:
 	case CX88_BOARD_HAUPPAUGE_HVR1100:
 	case CX88_BOARD_HAUPPAUGE_HVR3000:
+	case CX88_BOARD_HAUPPAUGE_HVR4000:
+	case CX88_BOARD_HAUPPAUGE_HVR4000LITE:
 		ir_codes = ir_codes_hauppauge_new;
 		ir_type = IR_TYPE_RC5;
 		ir->sampling = 1;
@@ -259,6 +261,7 @@
 		ir->polling = 1; /* ms */
 		break;
 	case CX88_BOARD_PROLINK_PV_8000GT:
+	case CX88_BOARD_PROLINK_PV_GLOBAL_XTREME:
 		ir_codes = ir_codes_pixelview_new;
 		ir->gpio_addr = MO_GP1_IO;
 		ir->mask_keycode = 0x3f;
@@ -392,7 +395,7 @@
 {
 	struct cx88_IR *ir = core->ir;
 	u32 samples, ircode;
-	int i;
+	int i, start, range, toggle, dev, code;
 
 	if (NULL == ir)
 		return;
@@ -461,6 +464,34 @@
 	case CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1:
 	case CX88_BOARD_HAUPPAUGE_HVR1100:
 	case CX88_BOARD_HAUPPAUGE_HVR3000:
+	case CX88_BOARD_HAUPPAUGE_HVR4000:
+	case CX88_BOARD_HAUPPAUGE_HVR4000LITE:
+		ircode = ir_decode_biphase(ir->samples, ir->scount, 5, 7);
+		ir_dprintk("biphase decoded: %x\n", ircode);
+		/*
+		 * RC5 has an extension bit which adds a new range
+		 * of available codes, this is detected here. Also
+		 * hauppauge remotes (black/silver) always use
+		 * specific device ids. If we do not filter the
+		 * device ids then messages destined for devices
+		 * such as TVs (id=0) will get through to the
+		 * device causing mis-fired events.
+		 */
+		/* split rc5 data block ... */
+		start = (ircode & 0x2000) >> 13;
+		range = (ircode & 0x1000) >> 12;
+		toggle= (ircode & 0x0800) >> 11;
+		dev   = (ircode & 0x07c0) >> 6;
+		code  = (ircode & 0x003f) | ((range << 6) ^ 0x0040);
+		if( start != 1)
+			/* no key pressed */
+			break;
+		if ( dev != 0x1e && dev != 0x1f )
+			/* not a hauppauge remote */
+			break;
+		ir_input_keydown(ir->input, &ir->ir, code, ircode);
+		ir->release = jiffies + msecs_to_jiffies(120);
+		break;
 	case CX88_BOARD_PINNACLE_PCTV_HD_800i:
 		ircode = ir_decode_biphase(ir->samples, ir->scount, 5, 7);
 		ir_dprintk("biphase decoded: %x\n", ircode);
diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c
index ef4d56e..be45955 100644
--- a/drivers/media/video/cx88/cx88-video.c
+++ b/drivers/media/video/cx88/cx88-video.c
@@ -773,6 +773,7 @@
 	enum v4l2_buf_type type = 0;
 	int radio = 0;
 
+	lock_kernel();
 	list_for_each_entry(h, &cx8800_devlist, devlist) {
 		if (h->video_dev->minor == minor) {
 			dev  = h;
@@ -788,8 +789,10 @@
 			dev   = h;
 		}
 	}
-	if (NULL == dev)
+	if (NULL == dev) {
+		unlock_kernel();
 		return -ENODEV;
+	}
 
 	core = dev->core;
 
@@ -798,8 +801,10 @@
 
 	/* allocate + initialize per filehandle data */
 	fh = kzalloc(sizeof(*fh),GFP_KERNEL);
-	if (NULL == fh)
+	if (NULL == fh) {
+		unlock_kernel();
 		return -ENOMEM;
+	}
 	file->private_data = fh;
 	fh->dev      = dev;
 	fh->radio    = radio;
@@ -832,6 +837,9 @@
 		cx88_set_stereo(core,V4L2_TUNER_MODE_STEREO,1);
 		cx88_call_i2c_clients(core,AUDC_SET_RADIO,NULL);
 	}
+	unlock_kernel();
+
+	atomic_inc(&core->users);
 
 	return 0;
 }
@@ -920,7 +928,8 @@
 	file->private_data = NULL;
 	kfree(fh);
 
-	cx88_call_i2c_clients (dev->core, TUNER_SET_STANDBY, NULL);
+	if(atomic_dec_and_test(&dev->core->users))
+		cx88_call_i2c_clients (dev->core, TUNER_SET_STANDBY, NULL);
 
 	return 0;
 }
diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h
index 54fe650..dbf01b8 100644
--- a/drivers/media/video/cx88/cx88.h
+++ b/drivers/media/video/cx88/cx88.h
@@ -221,6 +221,14 @@
 #define CX88_BOARD_DVICO_FUSIONHDTV_7_GOLD 65
 #define CX88_BOARD_PROLINK_PV_8000GT       66
 #define CX88_BOARD_KWORLD_ATSC_120         67
+#define CX88_BOARD_HAUPPAUGE_HVR4000       68
+#define CX88_BOARD_HAUPPAUGE_HVR4000LITE   69
+#define CX88_BOARD_TEVII_S460              70
+#define CX88_BOARD_OMICOM_SS4_PCI          71
+#define CX88_BOARD_TBS_8920                72
+#define CX88_BOARD_TEVII_S420              73
+#define CX88_BOARD_PROLINK_PV_GLOBAL_XTREME 74
+#define CX88_BOARD_PROF_7300               75
 
 enum cx88_itype {
 	CX88_VMUX_COMPOSITE1 = 1,
@@ -342,6 +350,7 @@
 	struct mutex               lock;
 	/* various v4l controls */
 	u32                        freq;
+	atomic_t		   users;
 
 	/* cx88-video needs to access cx8802 for hybrid tuner pll access. */
 	struct cx8802_dev          *dvbdev;
@@ -601,7 +610,7 @@
 /* ----------------------------------------------------------- */
 /* cx88-cards.c                                                */
 
-extern int cx88_tuner_callback(void *dev, int command, int arg);
+extern int cx88_tuner_callback(void *dev, int component, int command, int arg);
 extern int cx88_get_resources(const struct cx88_core *core,
 			      struct pci_dev *pci);
 extern struct cx88_core *cx88_core_create(struct pci_dev *pci, int nr);
diff --git a/drivers/media/video/dabusb.c b/drivers/media/video/dabusb.c
index 79faedf5..3aa538a 100644
--- a/drivers/media/video/dabusb.c
+++ b/drivers/media/video/dabusb.c
@@ -866,7 +866,8 @@
 
 	dbg("dabusb_init: driver registered");
 
-	info(DRIVER_VERSION ":" DRIVER_DESC);
+	printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
+	       DRIVER_DESC "\n");
 
 out:
 	return retval;
diff --git a/drivers/media/video/dpc7146.c b/drivers/media/video/dpc7146.c
deleted file mode 100644
index 88d6df7..0000000
--- a/drivers/media/video/dpc7146.c
+++ /dev/null
@@ -1,408 +0,0 @@
-/*
-    dpc7146.c - v4l2 driver for the dpc7146 demonstration board
-
-    Copyright (C) 2000-2003 Michael Hunold <michael@mihu.de>
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#define DEBUG_VARIABLE debug
-
-#include <media/saa7146_vv.h>
-#include <linux/video_decoder.h>	/* for saa7111a */
-
-#define I2C_SAA7111A            0x24
-
-/* All unused bytes are reserverd. */
-#define SAA711X_CHIP_VERSION            0x00
-#define SAA711X_ANALOG_INPUT_CONTROL_1  0x02
-#define SAA711X_ANALOG_INPUT_CONTROL_2  0x03
-#define SAA711X_ANALOG_INPUT_CONTROL_3  0x04
-#define SAA711X_ANALOG_INPUT_CONTROL_4  0x05
-#define SAA711X_HORIZONTAL_SYNC_START   0x06
-#define SAA711X_HORIZONTAL_SYNC_STOP    0x07
-#define SAA711X_SYNC_CONTROL            0x08
-#define SAA711X_LUMINANCE_CONTROL       0x09
-#define SAA711X_LUMINANCE_BRIGHTNESS    0x0A
-#define SAA711X_LUMINANCE_CONTRAST      0x0B
-#define SAA711X_CHROMA_SATURATION       0x0C
-#define SAA711X_CHROMA_HUE_CONTROL      0x0D
-#define SAA711X_CHROMA_CONTROL          0x0E
-#define SAA711X_FORMAT_DELAY_CONTROL    0x10
-#define SAA711X_OUTPUT_CONTROL_1        0x11
-#define SAA711X_OUTPUT_CONTROL_2        0x12
-#define SAA711X_OUTPUT_CONTROL_3        0x13
-#define SAA711X_V_GATE_1_START          0x15
-#define SAA711X_V_GATE_1_STOP           0x16
-#define SAA711X_V_GATE_1_MSB            0x17
-#define SAA711X_TEXT_SLICER_STATUS      0x1A
-#define SAA711X_DECODED_BYTES_OF_TS_1   0x1B
-#define SAA711X_DECODED_BYTES_OF_TS_2   0x1C
-#define SAA711X_STATUS_BYTE             0x1F
-
-#define DPC_BOARD_CAN_DO_VBI(dev)   (dev->revision != 0)
-
-static int debug;
-module_param(debug, int, 0);
-MODULE_PARM_DESC(debug, "debug verbosity");
-
-static int dpc_num;
-
-#define DPC_INPUTS	2
-static struct v4l2_input dpc_inputs[DPC_INPUTS] = {
-	{ 0, "Port A",	V4L2_INPUT_TYPE_CAMERA,	2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
-	{ 1, "Port B",	V4L2_INPUT_TYPE_CAMERA,	2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
-};
-
-#define DPC_AUDIOS	0
-
-static struct saa7146_extension_ioctls ioctls[] = {
-	{ VIDIOC_G_INPUT,	SAA7146_EXCLUSIVE },
-	{ VIDIOC_S_INPUT,	SAA7146_EXCLUSIVE },
-	{ VIDIOC_ENUMINPUT, 	SAA7146_EXCLUSIVE },
-	{ VIDIOC_S_STD,		SAA7146_AFTER },
-	{ 0,			0 }
-};
-
-struct dpc
-{
-	struct video_device	*video_dev;
-	struct video_device	*vbi_dev;
-
-	struct i2c_adapter	i2c_adapter;
-	struct i2c_client	*saa7111a;
-
-	int cur_input;	/* current input */
-};
-
-static int dpc_check_clients(struct device *dev, void *data)
-{
-	struct dpc* dpc = data;
-	struct i2c_client *client = i2c_verify_client(dev);
-
-	if( !client )
-		return 0;
-
-	if( I2C_SAA7111A == client->addr )
-		dpc->saa7111a = client;
-
-	return 0;
-}
-
-/* fixme: add vbi stuff here */
-static int dpc_probe(struct saa7146_dev* dev)
-{
-	struct dpc* dpc = NULL;
-
-	dpc = kzalloc(sizeof(struct dpc), GFP_KERNEL);
-	if( NULL == dpc ) {
-		printk("dpc_v4l2.o: dpc_probe: not enough kernel memory.\n");
-		return -ENOMEM;
-	}
-
-	/* FIXME: enable i2c-port pins, video-port-pins
-	   video port pins should be enabled here ?! */
-	saa7146_write(dev, MC1, (MASK_08 | MASK_24 | MASK_10 | MASK_26));
-
-	dpc->i2c_adapter = (struct i2c_adapter) {
-		.class = I2C_CLASS_TV_ANALOG,
-		.name = "dpc7146",
-	};
-	saa7146_i2c_adapter_prepare(dev, &dpc->i2c_adapter, SAA7146_I2C_BUS_BIT_RATE_480);
-	if(i2c_add_adapter(&dpc->i2c_adapter) < 0) {
-		DEB_S(("cannot register i2c-device. skipping.\n"));
-		kfree(dpc);
-		return -EFAULT;
-	}
-
-	/* loop through all i2c-devices on the bus and look who is there */
-	device_for_each_child(&dpc->i2c_adapter.dev, dpc, dpc_check_clients);
-
-	/* check if all devices are present */
-	if (!dpc->saa7111a) {
-		DEB_D(("dpc_v4l2.o: dpc_attach failed for this device.\n"));
-		i2c_del_adapter(&dpc->i2c_adapter);
-		kfree(dpc);
-		return -ENODEV;
-	}
-
-	/* all devices are present, probe was successful */
-	DEB_D(("dpc_v4l2.o: dpc_probe succeeded for this device.\n"));
-
-	/* we store the pointer in our private data field */
-	dev->ext_priv = dpc;
-
-	return 0;
-}
-
-/* bring hardware to a sane state. this has to be done, just in case someone
-   wants to capture from this device before it has been properly initialized.
-   the capture engine would badly fail, because no valid signal arrives on the
-   saa7146, thus leading to timeouts and stuff. */
-static int dpc_init_done(struct saa7146_dev* dev)
-{
-	struct dpc* dpc = (struct dpc*)dev->ext_priv;
-
-	DEB_D(("dpc_v4l2.o: dpc_init_done called.\n"));
-
-	/* initialize the helper ics to useful values */
-	i2c_smbus_write_byte_data(dpc->saa7111a, 0x00, 0x11);
-
-	i2c_smbus_write_byte_data(dpc->saa7111a, 0x02, 0xc0);
-	i2c_smbus_write_byte_data(dpc->saa7111a, 0x03, 0x30);
-	i2c_smbus_write_byte_data(dpc->saa7111a, 0x04, 0x00);
-	i2c_smbus_write_byte_data(dpc->saa7111a, 0x05, 0x00);
-	i2c_smbus_write_byte_data(dpc->saa7111a, 0x06, 0xde);
-	i2c_smbus_write_byte_data(dpc->saa7111a, 0x07, 0xad);
-	i2c_smbus_write_byte_data(dpc->saa7111a, 0x08, 0xa8);
-	i2c_smbus_write_byte_data(dpc->saa7111a, 0x09, 0x00);
-	i2c_smbus_write_byte_data(dpc->saa7111a, 0x0a, 0x80);
-	i2c_smbus_write_byte_data(dpc->saa7111a, 0x0b, 0x47);
-	i2c_smbus_write_byte_data(dpc->saa7111a, 0x0c, 0x40);
-	i2c_smbus_write_byte_data(dpc->saa7111a, 0x0d, 0x00);
-	i2c_smbus_write_byte_data(dpc->saa7111a, 0x0e, 0x03);
-
-	i2c_smbus_write_byte_data(dpc->saa7111a, 0x10, 0xd0);
-	i2c_smbus_write_byte_data(dpc->saa7111a, 0x11, 0x1c);
-	i2c_smbus_write_byte_data(dpc->saa7111a, 0x12, 0xc1);
-	i2c_smbus_write_byte_data(dpc->saa7111a, 0x13, 0x30);
-
-	i2c_smbus_write_byte_data(dpc->saa7111a, 0x1f, 0x81);
-
-	return 0;
-}
-
-static struct saa7146_ext_vv vv_data;
-
-/* this function only gets called when the probing was successful */
-static int dpc_attach(struct saa7146_dev* dev, struct saa7146_pci_extension_data *info)
-{
-	struct dpc* dpc = (struct dpc*)dev->ext_priv;
-
-	DEB_D(("dpc_v4l2.o: dpc_attach called.\n"));
-
-	/* checking for i2c-devices can be omitted here, because we
-	   already did this in "dpc_vl42_probe" */
-
-	saa7146_vv_init(dev,&vv_data);
-	if( 0 != saa7146_register_device(&dpc->video_dev, dev, "dpc", VFL_TYPE_GRABBER)) {
-		ERR(("cannot register capture v4l2 device. skipping.\n"));
-		return -1;
-	}
-
-	/* initialization stuff (vbi) (only for revision > 0 and for extensions which want it)*/
-	if( 0 != DPC_BOARD_CAN_DO_VBI(dev)) {
-		if( 0 != saa7146_register_device(&dpc->vbi_dev, dev, "dpc", VFL_TYPE_VBI)) {
-			ERR(("cannot register vbi v4l2 device. skipping.\n"));
-		}
-	}
-
-	i2c_use_client(dpc->saa7111a);
-
-	printk("dpc: found 'dpc7146 demonstration board'-%d.\n",dpc_num);
-	dpc_num++;
-
-	/* the rest */
-	dpc->cur_input = 0;
-	dpc_init_done(dev);
-
-	return 0;
-}
-
-static int dpc_detach(struct saa7146_dev* dev)
-{
-	struct dpc* dpc = (struct dpc*)dev->ext_priv;
-
-	DEB_EE(("dev:%p\n",dev));
-
-	i2c_release_client(dpc->saa7111a);
-
-	saa7146_unregister_device(&dpc->video_dev,dev);
-	if( 0 != DPC_BOARD_CAN_DO_VBI(dev)) {
-		saa7146_unregister_device(&dpc->vbi_dev,dev);
-	}
-	saa7146_vv_release(dev);
-
-	dpc_num--;
-
-	i2c_del_adapter(&dpc->i2c_adapter);
-	kfree(dpc);
-	return 0;
-}
-
-#ifdef axa
-int dpc_vbi_bypass(struct saa7146_dev* dev)
-{
-	struct dpc* dpc = (struct dpc*)dev->ext_priv;
-
-	int i = 1;
-
-	/* switch bypass in saa7111a */
-	if ( 0 != dpc->saa7111a->driver->command(dpc->saa7111a,SAA711X_VBI_BYPASS, &i)) {
-		printk("dpc_v4l2.o: VBI_BYPASS: could not address saa7111a.\n");
-		return -1;
-	}
-
-	return 0;
-}
-#endif
-
-static int dpc_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
-{
-	struct saa7146_dev *dev = fh->dev;
-	struct dpc* dpc = (struct dpc*)dev->ext_priv;
-/*
-	struct saa7146_vv *vv = dev->vv_data;
-*/
-	switch(cmd)
-	{
-	case VIDIOC_ENUMINPUT:
-	{
-		struct v4l2_input *i = arg;
-		DEB_EE(("VIDIOC_ENUMINPUT %d.\n",i->index));
-
-		if( i->index < 0 || i->index >= DPC_INPUTS) {
-			return -EINVAL;
-		}
-
-		memcpy(i, &dpc_inputs[i->index], sizeof(struct v4l2_input));
-
-		DEB_D(("dpc_v4l2.o: v4l2_ioctl: VIDIOC_ENUMINPUT %d.\n",i->index));
-		return 0;
-	}
-	case VIDIOC_G_INPUT:
-	{
-		int *input = (int *)arg;
-		*input = dpc->cur_input;
-
-		DEB_D(("dpc_v4l2.o: VIDIOC_G_INPUT: %d\n",*input));
-		return 0;
-	}
-	case VIDIOC_S_INPUT:
-	{
-		int	input = *(int *)arg;
-
-		if (input < 0 || input >= DPC_INPUTS) {
-			return -EINVAL;
-		}
-
-		dpc->cur_input = input;
-
-		/* fixme: switch input here, switch audio, too! */
-//		saa7146_set_hps_source_and_sync(dev, input_port_selection[input].hps_source, input_port_selection[input].hps_sync);
-		printk("dpc_v4l2.o: VIDIOC_S_INPUT: fixme switch input.\n");
-
-		return 0;
-	}
-	default:
-/*
-		DEB_D(("dpc_v4l2.o: v4l2_ioctl does not handle this ioctl.\n"));
-*/
-		return -ENOIOCTLCMD;
-	}
-	return 0;
-}
-
-static int std_callback(struct saa7146_dev* dev, struct saa7146_standard *std)
-{
-	return 0;
-}
-
-static struct saa7146_standard standard[] = {
-	{
-		.name	= "PAL", 	.id	= V4L2_STD_PAL,
-		.v_offset	= 0x17,	.v_field 	= 288,
-		.h_offset	= 0x14,	.h_pixels 	= 680,
-		.v_max_out	= 576,	.h_max_out	= 768,
-	}, {
-		.name	= "NTSC", 	.id	= V4L2_STD_NTSC,
-		.v_offset	= 0x16,	.v_field 	= 240,
-		.h_offset	= 0x06,	.h_pixels 	= 708,
-		.v_max_out	= 480,	.h_max_out	= 640,
-	}, {
-		.name	= "SECAM", 	.id	= V4L2_STD_SECAM,
-		.v_offset	= 0x14,	.v_field 	= 288,
-		.h_offset	= 0x14,	.h_pixels 	= 720,
-		.v_max_out	= 576,	.h_max_out	= 768,
-	}
-};
-
-static struct saa7146_extension extension;
-
-static struct saa7146_pci_extension_data dpc = {
-	.ext_priv = "Multimedia eXtension Board",
-	.ext = &extension,
-};
-
-static struct pci_device_id pci_tbl[] = {
-	{
-		.vendor    = PCI_VENDOR_ID_PHILIPS,
-		.device	   = PCI_DEVICE_ID_PHILIPS_SAA7146,
-		.subvendor = 0x0000,
-		.subdevice = 0x0000,
-		.driver_data = (unsigned long)&dpc,
-	}, {
-		.vendor = 0,
-	}
-};
-
-MODULE_DEVICE_TABLE(pci, pci_tbl);
-
-static struct saa7146_ext_vv vv_data = {
-	.inputs		= DPC_INPUTS,
-	.capabilities	= V4L2_CAP_VBI_CAPTURE,
-	.stds		= &standard[0],
-	.num_stds	= sizeof(standard)/sizeof(struct saa7146_standard),
-	.std_callback	= &std_callback,
-	.ioctls		= &ioctls[0],
-	.ioctl		= dpc_ioctl,
-};
-
-static struct saa7146_extension extension = {
-	.name		= "dpc7146 demonstration board",
-	.flags		= SAA7146_USE_I2C_IRQ,
-
-	.pci_tbl	= &pci_tbl[0],
-	.module		= THIS_MODULE,
-
-	.probe		= dpc_probe,
-	.attach		= dpc_attach,
-	.detach		= dpc_detach,
-
-	.irq_mask	= 0,
-	.irq_func	= NULL,
-};
-
-static int __init dpc_init_module(void)
-{
-	if( 0 != saa7146_register_extension(&extension)) {
-		DEB_S(("failed to register extension.\n"));
-		return -ENODEV;
-	}
-
-	return 0;
-}
-
-static void __exit dpc_cleanup_module(void)
-{
-	saa7146_unregister_extension(&extension);
-}
-
-module_init(dpc_init_module);
-module_exit(dpc_cleanup_module);
-
-MODULE_DESCRIPTION("video4linux-2 driver for the 'dpc7146 demonstration board'");
-MODULE_AUTHOR("Michael Hunold <michael@mihu.de>");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/em28xx/em28xx-audio.c b/drivers/media/video/em28xx/em28xx-audio.c
index 3c00610..ac3292d 100644
--- a/drivers/media/video/em28xx/em28xx-audio.c
+++ b/drivers/media/video/em28xx/em28xx-audio.c
@@ -117,10 +117,10 @@
 
 			if (oldptr + length >= runtime->buffer_size) {
 				unsigned int cnt =
-				    runtime->buffer_size - oldptr - 1;
+				    runtime->buffer_size - oldptr;
 				memcpy(runtime->dma_area + oldptr * stride, cp,
 				       cnt * stride);
-				memcpy(runtime->dma_area, cp + cnt,
+				memcpy(runtime->dma_area, cp + cnt * stride,
 				       length * stride - cnt * stride);
 			} else {
 				memcpy(runtime->dma_area + oldptr * stride, cp,
@@ -161,8 +161,14 @@
 
 		memset(dev->adev->transfer_buffer[i], 0x80, sb_size);
 		urb = usb_alloc_urb(EM28XX_NUM_AUDIO_PACKETS, GFP_ATOMIC);
-		if (!urb)
+		if (!urb) {
+			em28xx_errdev("usb_alloc_urb failed!\n");
+			for (j = 0; j < i; j++) {
+				usb_free_urb(dev->adev->urb[j]);
+				kfree(dev->adev->transfer_buffer[j]);
+			}
 			return -ENOMEM;
+		}
 
 		urb->dev = dev->udev;
 		urb->context = dev;
diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c
index 452da70..d65d057 100644
--- a/drivers/media/video/em28xx/em28xx-cards.c
+++ b/drivers/media/video/em28xx/em28xx-cards.c
@@ -93,28 +93,6 @@
 			.amux     = 0,
 		} },
 	},
-	[EM2800_BOARD_KWORLD_USB2800] = {
-		.name         = "Kworld USB2800",
-		.valid        = EM28XX_BOARD_NOT_VALIDATED,
-		.is_em2800    = 1,
-		.vchannels    = 3,
-		.tuner_type   = TUNER_PHILIPS_FCV1236D,
-		.tda9887_conf = TDA9887_PRESENT,
-		.decoder      = EM28XX_SAA7113,
-		.input          = { {
-			.type     = EM28XX_VMUX_TELEVISION,
-			.vmux     = SAA7115_COMPOSITE2,
-			.amux     = 0,
-		}, {
-			.type     = EM28XX_VMUX_COMPOSITE1,
-			.vmux     = SAA7115_COMPOSITE0,
-			.amux     = 1,
-		}, {
-			.type     = EM28XX_VMUX_SVIDEO,
-			.vmux     = SAA7115_SVIDEO3,
-			.amux     = 1,
-		} },
-	},
 	[EM2820_BOARD_KWORLD_PVRTV2800RF] = {
 		.name         = "Kworld PVR TV 2800 RF",
 		.is_em2800    = 0,
@@ -599,7 +577,7 @@
 		}, {
 			.type     = EM28XX_VMUX_COMPOSITE1,
 			.vmux     = TVP5150_COMPOSITE1,
-			.amux     = 1,
+			.amux     = 3,
 		}, {
 			.type     = EM28XX_VMUX_SVIDEO,
 			.vmux     = TVP5150_SVIDEO,
@@ -952,22 +930,23 @@
 	},
 	[EM2880_BOARD_KWORLD_DVB_310U] = {
 		.name	      = "KWorld DVB-T 310U",
-		.valid        = EM28XX_BOARD_NOT_VALIDATED,
 		.vchannels    = 3,
 		.tuner_type   = TUNER_XC2028,
+		.has_dvb      = 1,
+		.mts_firmware = 1,
 		.decoder      = EM28XX_TVP5150,
 		.input          = { {
 			.type     = EM28XX_VMUX_TELEVISION,
 			.vmux     = TVP5150_COMPOSITE0,
-			.amux     = 0,
+			.amux     = EM28XX_AMUX_VIDEO,
 		}, {
 			.type     = EM28XX_VMUX_COMPOSITE1,
 			.vmux     = TVP5150_COMPOSITE1,
-			.amux     = 1,
-		}, {
+			.amux     = EM28XX_AMUX_AC97_LINE_IN,
+		}, {	/* S-video has not been tested yet */
 			.type     = EM28XX_VMUX_SVIDEO,
 			.vmux     = TVP5150_SVIDEO,
-			.amux     = 1,
+			.amux     = EM28XX_AMUX_AC97_LINE_IN,
 		} },
 	},
 	[EM2881_BOARD_DNT_DA2_HYBRID] = {
@@ -1122,7 +1101,7 @@
 	{ USB_DEVICE(0xeb1a, 0x2820),
 			.driver_info = EM2820_BOARD_UNKNOWN },
 	{ USB_DEVICE(0xeb1a, 0x2821),
-			.driver_info = EM2820_BOARD_UNKNOWN },
+			.driver_info = EM2820_BOARD_PROLINK_PLAYTV_USB2 },
 	{ USB_DEVICE(0xeb1a, 0x2860),
 			.driver_info = EM2820_BOARD_UNKNOWN },
 	{ USB_DEVICE(0xeb1a, 0x2861),
@@ -1282,6 +1261,7 @@
 static struct em28xx_hash_table em28xx_eeprom_hash [] = {
 	/* P/N: SA 60002070465 Tuner: TVF7533-MF */
 	{0x6ce05a8f, EM2820_BOARD_PROLINK_PLAYTV_USB2, TUNER_YMEC_TVF_5533MF},
+	{0x966a0441, EM2880_BOARD_KWORLD_DVB_310U, TUNER_XC2028},
 };
 
 /* I2C devicelist hash table for devices with generic USB IDs */
@@ -1291,7 +1271,7 @@
 	{0x1ba50080, EM2860_BOARD_POINTNIX_INTRAORAL_CAMERA, TUNER_ABSENT},
 };
 
-int em28xx_tuner_callback(void *ptr, int command, int arg)
+int em28xx_tuner_callback(void *ptr, int component, int command, int arg)
 {
 	int rc = 0;
 	struct em28xx *dev = ptr;
@@ -1552,9 +1532,12 @@
 		/* djh - Not sure which demod we need here */
 		ctl->demod = XC3028_FE_DEFAULT;
 		break;
+	case EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600:
+		ctl->demod = XC3028_FE_DEFAULT;
+		ctl->fname = XC3028L_DEFAULT_FIRMWARE;
+		break;
 	case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950:
 	case EM2880_BOARD_PINNACLE_PCTV_HD_PRO:
-	case EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600:
 		/* FIXME: Better to specify the needed IF */
 		ctl->demod = XC3028_FE_DEFAULT;
 		break;
@@ -1764,6 +1747,20 @@
 		break;
 	case EM2820_BOARD_UNKNOWN:
 	case EM2800_BOARD_UNKNOWN:
+		/*
+		 * The K-WORLD DVB-T 310U is detected as an MSI Digivox AD.
+		 *
+		 * This occurs because they share identical USB vendor and
+		 * product IDs.
+		 *
+		 * What we do here is look up the EEPROM hash of the K-WORLD
+		 * and if it is found then we decide that we do not have
+		 * a DIGIVOX and reset the device to the K-WORLD instead.
+		 *
+		 * This solution is only valid if they do not share eeprom
+		 * hash identities which has not been determined as yet.
+		 */
+	case EM2880_BOARD_MSI_DIGIVOX_AD:
 		if (!em28xx_hint_board(dev))
 			em28xx_set_model(dev);
 		break;
diff --git a/drivers/media/video/em28xx/em28xx-dvb.c b/drivers/media/video/em28xx/em28xx-dvb.c
index 4b992bc..c99e238 100644
--- a/drivers/media/video/em28xx/em28xx-dvb.c
+++ b/drivers/media/video/em28xx/em28xx-dvb.c
@@ -249,7 +249,6 @@
 	memset(&cfg, 0, sizeof(cfg));
 	cfg.i2c_adap  = &dev->i2c_adap;
 	cfg.i2c_addr  = addr;
-	cfg.callback  = em28xx_tuner_callback;
 
 	if (!dev->dvb->frontend) {
 		printk(KERN_ERR "%s/2: dvb frontend not attached. "
@@ -274,7 +273,7 @@
 
 /* ------------------------------------------------------------------ */
 
-int register_dvb(struct em28xx_dvb *dvb,
+static int register_dvb(struct em28xx_dvb *dvb,
 		 struct module *module,
 		 struct em28xx *dev,
 		 struct device *device)
@@ -422,6 +421,8 @@
 		}
 		break;
 	case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900:
+	case EM2880_BOARD_TERRATEC_HYBRID_XS:
+	case EM2880_BOARD_KWORLD_DVB_310U:
 		dvb->frontend = dvb_attach(zl10353_attach,
 					   &em28xx_zl10353_with_xc3028,
 					   &dev->i2c_adap);
@@ -443,15 +444,6 @@
 		}
 		break;
 #endif
-	case EM2880_BOARD_TERRATEC_HYBRID_XS:
-		dvb->frontend = dvb_attach(zl10353_attach,
-						&em28xx_zl10353_with_xc3028,
-						&dev->i2c_adap);
-		if (attach_xc3028(0x61, dev) < 0) {
-			 result = -EINVAL;
-			goto out_free;
-		}
-		break;
 	default:
 		printk(KERN_ERR "%s/2: The frontend of your DVB/ATSC card"
 				" isn't supported yet\n",
@@ -465,6 +457,8 @@
 		result = -EINVAL;
 		goto out_free;
 	}
+	/* define general-purpose callback pointer */
+	dvb->frontend->callback = em28xx_tuner_callback;
 
 	/* register everything */
 	result = register_dvb(dvb, THIS_MODULE, dev, &dev->udev->dev);
diff --git a/drivers/media/video/em28xx/em28xx-i2c.c b/drivers/media/video/em28xx/em28xx-i2c.c
index 9785338..3bab56b 100644
--- a/drivers/media/video/em28xx/em28xx-i2c.c
+++ b/drivers/media/video/em28xx/em28xx-i2c.c
@@ -143,10 +143,11 @@
 	}
 	for (write_timeout = EM2800_I2C_WRITE_TIMEOUT; write_timeout > 0;
 	     write_timeout -= 5) {
-		unsigned msg = dev->em28xx_read_reg(dev, 0x5);
-		if (msg == 0x94)
+		unsigned reg = dev->em28xx_read_reg(dev, 0x5);
+
+		if (reg == 0x94)
 			return -ENODEV;
-		else if (msg == 0x84)
+		else if (reg == 0x84)
 			return 0;
 		msleep(5);
 	}
@@ -335,8 +336,11 @@
 
 	/* Check if board has eeprom */
 	err = i2c_master_recv(&dev->i2c_client, &buf, 0);
-	if (err < 0)
-		return -1;
+	if (err < 0) {
+		em28xx_errdev("%s: i2c_master_recv failed! err [%d]\n",
+			__func__, err);
+		return err;
+	}
 
 	buf = 0;
 
@@ -344,7 +348,7 @@
 	if (err != 1) {
 		printk(KERN_INFO "%s: Huh, no eeprom present (err=%d)?\n",
 		       dev->name, err);
-		return -1;
+		return err;
 	}
 	while (size > 0) {
 		if (size > 16)
@@ -357,7 +361,7 @@
 			printk(KERN_WARNING
 			       "%s: i2c eeprom read error (err=%d)\n",
 			       dev->name, err);
-			return -1;
+			return err;
 		}
 		size -= block;
 		p += block;
@@ -585,18 +589,31 @@
  */
 int em28xx_i2c_register(struct em28xx *dev)
 {
+	int retval;
+
 	BUG_ON(!dev->em28xx_write_regs || !dev->em28xx_read_reg);
 	BUG_ON(!dev->em28xx_write_regs_req || !dev->em28xx_read_reg_req);
 	dev->i2c_adap = em28xx_adap_template;
 	dev->i2c_adap.dev.parent = &dev->udev->dev;
 	strcpy(dev->i2c_adap.name, dev->name);
 	dev->i2c_adap.algo_data = dev;
-	i2c_add_adapter(&dev->i2c_adap);
+
+	retval = i2c_add_adapter(&dev->i2c_adap);
+	if (retval < 0) {
+		em28xx_errdev("%s: i2c_add_adapter failed! retval [%d]\n",
+			__func__, retval);
+		return retval;
+	}
 
 	dev->i2c_client = em28xx_client_template;
 	dev->i2c_client.adapter = &dev->i2c_adap;
 
-	em28xx_i2c_eeprom(dev, dev->eedata, sizeof(dev->eedata));
+	retval = em28xx_i2c_eeprom(dev, dev->eedata, sizeof(dev->eedata));
+	if (retval < 0) {
+		em28xx_errdev("%s: em28xx_i2_eeprom failed! retval [%d]\n",
+			__func__, retval);
+		return retval;
+	}
 
 	if (i2c_scan)
 		em28xx_do_i2c_scan(dev);
diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c
index 49ab062..c53649e 100644
--- a/drivers/media/video/em28xx/em28xx-video.c
+++ b/drivers/media/video/em28xx/em28xx-video.c
@@ -513,10 +513,17 @@
  */
 static int em28xx_config(struct em28xx *dev)
 {
+	int retval;
 
 	/* Sets I2C speed to 100 KHz */
-	if (!dev->is_em2800)
-		em28xx_write_regs_req(dev, 0x00, 0x06, "\x40", 1);
+	if (!dev->is_em2800) {
+		retval = em28xx_write_regs_req(dev, 0x00, 0x06, "\x40", 1);
+		if (retval < 0) {
+			em28xx_errdev("%s: em28xx_write_regs_req failed! retval [%d]\n",
+				__func__, retval);
+			return retval;
+		}
+	}
 
 	/* enable vbi capturing */
 
@@ -1512,6 +1519,7 @@
 	struct em28xx_fh *fh;
 	enum v4l2_buf_type fh_type = 0;
 
+	lock_kernel();
 	list_for_each_entry(h, &em28xx_devlist, devlist) {
 		if (h->vdev->minor == minor) {
 			dev  = h;
@@ -1527,8 +1535,10 @@
 			dev   = h;
 		}
 	}
-	if (NULL == dev)
+	if (NULL == dev) {
+		unlock_kernel();
 		return -ENODEV;
+	}
 
 	em28xx_videodbg("open minor=%d type=%s users=%d\n",
 				minor, v4l2_type_names[fh_type], dev->users);
@@ -1537,6 +1547,7 @@
 	fh = kzalloc(sizeof(struct em28xx_fh), GFP_KERNEL);
 	if (!fh) {
 		em28xx_errdev("em28xx-video.c: Out of memory?!\n");
+		unlock_kernel();
 		return -ENOMEM;
 	}
 	mutex_lock(&dev->lock);
@@ -1573,6 +1584,7 @@
 			sizeof(struct em28xx_buffer), fh);
 
 	mutex_unlock(&dev->lock);
+	unlock_kernel();
 
 	return errCode;
 }
@@ -1588,8 +1600,7 @@
 	/*FIXME: I2C IR should be disconnected */
 
 	em28xx_info("V4L2 devices /dev/video%d and /dev/vbi%d deregistered\n",
-				dev->vdev->minor-MINOR_VFL_TYPE_GRABBER_MIN,
-				dev->vbi_dev->minor-MINOR_VFL_TYPE_VBI_MIN);
+				dev->vdev->num, dev->vbi_dev->num);
 	list_del(&dev->devlist);
 	if (dev->sbutton_input_dev)
 		em28xx_deregister_snapshot_button(dev);
@@ -1948,13 +1959,23 @@
 	}
 
 	/* register i2c bus */
-	em28xx_i2c_register(dev);
+	errCode = em28xx_i2c_register(dev);
+	if (errCode < 0) {
+		em28xx_errdev("%s: em28xx_i2c_register - errCode [%d]!\n",
+			__func__, errCode);
+		return errCode;
+	}
 
 	/* Do board specific init and eeprom reading */
 	em28xx_card_setup(dev);
 
 	/* Configure audio */
-	em28xx_audio_analog_set(dev);
+	errCode = em28xx_audio_analog_set(dev);
+	if (errCode < 0) {
+		em28xx_errdev("%s: em28xx_audio_analog_set - errCode [%d]!\n",
+			__func__, errCode);
+		return errCode;
+	}
 
 	/* configure the device */
 	em28xx_config_i2c(dev);
@@ -1974,6 +1995,11 @@
 	dev->ctl_input = 2;
 
 	errCode = em28xx_config(dev);
+	if (errCode < 0) {
+		em28xx_errdev("%s: em28xx_config - errCode [%d]!\n",
+			__func__, errCode);
+		return errCode;
+	}
 
 	list_add_tail(&dev->devlist, &em28xx_devlist);
 
@@ -2026,17 +2052,27 @@
 
 	if (dev->has_msp34xx) {
 		/* Send a reset to other chips via gpio */
-		em28xx_write_regs_req(dev, 0x00, 0x08, "\xf7", 1);
+		errCode = em28xx_write_regs_req(dev, 0x00, 0x08, "\xf7", 1);
+		if (errCode < 0) {
+			em28xx_errdev("%s: em28xx_write_regs_req - msp34xx(1) failed! errCode [%d]\n",
+				__func__, errCode);
+			return errCode;
+		}
 		msleep(3);
-		em28xx_write_regs_req(dev, 0x00, 0x08, "\xff", 1);
+
+		errCode = em28xx_write_regs_req(dev, 0x00, 0x08, "\xff", 1);
+		if (errCode < 0) {
+			em28xx_errdev("%s: em28xx_write_regs_req - msp34xx(2) failed! errCode [%d]\n",
+				__func__, errCode);
+			return errCode;
+		}
 		msleep(3);
 	}
 
 	video_mux(dev, 0);
 
 	em28xx_info("V4L2 device registered as /dev/video%d and /dev/vbi%d\n",
-				dev->vdev->minor-MINOR_VFL_TYPE_GRABBER_MIN,
-				dev->vbi_dev->minor-MINOR_VFL_TYPE_VBI_MIN);
+				dev->vdev->num, dev->vbi_dev->num);
 
 	mutex_lock(&em28xx_extension_devlist_lock);
 	if (!list_empty(&em28xx_extension_devlist)) {
@@ -2236,7 +2272,7 @@
 		em28xx_warn
 		    ("device /dev/video%d is open! Deregistration and memory "
 		     "deallocation are deferred on close.\n",
-				dev->vdev->minor-MINOR_VFL_TYPE_GRABBER_MIN);
+				dev->vdev->num);
 
 		dev->state |= DEV_MISCONFIGURED;
 		em28xx_uninit_isoc(dev);
diff --git a/drivers/media/video/em28xx/em28xx.h b/drivers/media/video/em28xx/em28xx.h
index 9a33107..8278117 100644
--- a/drivers/media/video/em28xx/em28xx.h
+++ b/drivers/media/video/em28xx/em28xx.h
@@ -411,8 +411,8 @@
 	/* frame properties */
 	int width;		/* current frame width */
 	int height;		/* current frame height */
-	int hscale;		/* horizontal scale factor (see datasheet) */
-	int vscale;		/* vertical scale factor (see datasheet) */
+	unsigned hscale;	/* horizontal scale factor (see datasheet) */
+	unsigned vscale;	/* vertical scale factor (see datasheet) */
 	int interlaced;		/* 1=interlace fileds, 0=just top fileds */
 	unsigned int video_bytesread;	/* Number of bytes read */
 
@@ -528,7 +528,7 @@
 extern struct usb_device_id em28xx_id_table[];
 extern const unsigned int em28xx_bcount;
 void em28xx_set_ir(struct em28xx *dev, struct IR_i2c *ir);
-int em28xx_tuner_callback(void *ptr, int command, int arg);
+int em28xx_tuner_callback(void *ptr, int component, int command, int arg);
 
 /* Provided by em28xx-input.c */
 /* TODO: Check if the standard get_key handlers on ir-common can be used */
diff --git a/drivers/media/video/et61x251/et61x251_core.c b/drivers/media/video/et61x251/et61x251_core.c
index 8db2a05..7a85c41 100644
--- a/drivers/media/video/et61x251/et61x251_core.c
+++ b/drivers/media/video/et61x251/et61x251_core.c
@@ -1214,7 +1214,7 @@
 	if (!down_read_trylock(&et61x251_dev_lock))
 		return -ERESTARTSYS;
 
-	cam = video_get_drvdata(video_devdata(filp));
+	cam = video_drvdata(filp);
 
 	if (wait_for_completion_interruptible(&cam->probe)) {
 		up_read(&et61x251_dev_lock);
@@ -1297,7 +1297,7 @@
 
 	down_write(&et61x251_dev_lock);
 
-	cam = video_get_drvdata(video_devdata(filp));
+	cam = video_drvdata(filp);
 
 	et61x251_stop_transfer(cam);
 	et61x251_release_buffers(cam);
@@ -1318,7 +1318,7 @@
 et61x251_read(struct file* filp, char __user * buf,
 	      size_t count, loff_t* f_pos)
 {
-	struct et61x251_device* cam = video_get_drvdata(video_devdata(filp));
+	struct et61x251_device *cam = video_drvdata(filp);
 	struct et61x251_frame_t* f, * i;
 	unsigned long lock_flags;
 	long timeout;
@@ -1426,7 +1426,7 @@
 
 static unsigned int et61x251_poll(struct file *filp, poll_table *wait)
 {
-	struct et61x251_device* cam = video_get_drvdata(video_devdata(filp));
+	struct et61x251_device *cam = video_drvdata(filp);
 	struct et61x251_frame_t* f;
 	unsigned long lock_flags;
 	unsigned int mask = 0;
@@ -1502,7 +1502,7 @@
 
 static int et61x251_mmap(struct file* filp, struct vm_area_struct *vma)
 {
-	struct et61x251_device* cam = video_get_drvdata(video_devdata(filp));
+	struct et61x251_device *cam = video_drvdata(filp);
 	unsigned long size = vma->vm_end - vma->vm_start,
 		      start = vma->vm_start;
 	void *pos;
@@ -2395,7 +2395,7 @@
 static int et61x251_ioctl_v4l2(struct inode* inode, struct file* filp,
 			       unsigned int cmd, void __user * arg)
 {
-	struct et61x251_device* cam = video_get_drvdata(video_devdata(filp));
+	struct et61x251_device *cam = video_drvdata(filp);
 
 	switch (cmd) {
 
@@ -2490,7 +2490,7 @@
 static int et61x251_ioctl(struct inode* inode, struct file* filp,
 			 unsigned int cmd, unsigned long arg)
 {
-	struct et61x251_device* cam = video_get_drvdata(video_devdata(filp));
+	struct et61x251_device *cam = video_drvdata(filp);
 	int err = 0;
 
 	if (mutex_lock_interruptible(&cam->fileop_mutex))
diff --git a/drivers/media/video/gspca/Kconfig b/drivers/media/video/gspca/Kconfig
index 42b9074..4d08174 100644
--- a/drivers/media/video/gspca/Kconfig
+++ b/drivers/media/video/gspca/Kconfig
@@ -1,13 +1,212 @@
-config USB_GSPCA
-	tristate "USB GSPCA driver"
+menuconfig USB_GSPCA
+	tristate "GSPCA based webcams"
 	depends on VIDEO_V4L2
+	default m
 	---help---
-	  Say Y here if you want support for various USB webcams.
+	Say Y here if you want to enable selecting webcams based
+	on the GSPCA framework.
 
-	  See <file:Documentation/video4linux/gspca.txt> for more info.
+	See <file:Documentation/video4linux/gspca.txt> for more info.
 
-	  This driver uses the Video For Linux API. You must say Y or M to
-	  "Video For Linux" to use this driver.
+	This driver uses the Video For Linux API. You must say Y or M to
+	"Video For Linux" to use this driver.
 
-	  To compile this driver as modules, choose M here: the
-	  modules will be called gspca_xxxx.
+	To compile this driver as modules, choose M here: the
+	modules will be called gspca_main.
+
+
+if USB_GSPCA && VIDEO_V4L2
+
+source "drivers/media/video/gspca/m5602/Kconfig"
+
+config USB_GSPCA_CONEX
+	tristate "Conexant Camera Driver"
+	depends on VIDEO_V4L2 && USB_GSPCA
+	help
+	Say Y here if you want support for cameras based on the Conexant chip.
+
+	To compile this driver as a module, choose M here: the
+	module will be called gspca_conex.
+
+config USB_GSPCA_ETOMS
+	tristate "Etoms USB Camera Driver"
+	depends on VIDEO_V4L2 && USB_GSPCA
+	help
+	Say Y here if you want support for cameras based on the Etoms chip.
+
+	To compile this driver as a module, choose M here: the
+	module will be called gspca_etoms.
+
+config USB_GSPCA_FINEPIX
+	tristate "Fujifilm FinePix USB V4L2 driver"
+	depends on VIDEO_V4L2 && USB_GSPCA
+	help
+	Say Y here if you want support for cameras based on the FinePix chip.
+
+	To compile this driver as a module, choose M here: the
+	module will be called gspca_finepix.
+
+config USB_GSPCA_MARS
+	tristate "Mars USB Camera Driver"
+	depends on VIDEO_V4L2 && USB_GSPCA
+	help
+	Say Y here if you want support for cameras based on the Mars chip.
+
+	To compile this driver as a module, choose M here: the
+	module will be called gspca_mars.
+
+config USB_GSPCA_OV519
+	tristate "OV519 USB Camera Driver"
+	depends on VIDEO_V4L2 && USB_GSPCA
+	help
+	Say Y here if you want support for cameras based on the OV519 chip.
+
+	To compile this driver as a module, choose M here: the
+	module will be called gspca_ov519.
+
+config USB_GSPCA_PAC207
+	tristate "Pixart PAC207 USB Camera Driver"
+	depends on VIDEO_V4L2 && USB_GSPCA
+	help
+	Say Y here if you want support for cameras based on the PAC207 chip.
+
+	To compile this driver as a module, choose M here: the
+	module will be called gspca_pac207.
+
+config USB_GSPCA_PAC7311
+	tristate "Pixart PAC7311 USB Camera Driver"
+	depends on VIDEO_V4L2 && USB_GSPCA
+	help
+	Say Y here if you want support for cameras based on the PAC7311 chip.
+
+	To compile this driver as a module, choose M here: the
+	module will be called gspca_pac7311.
+
+config USB_GSPCA_SONIXB
+	tristate "SN9C102 USB Camera Driver"
+	depends on VIDEO_V4L2 && USB_GSPCA
+	help
+	Say Y here if you want support for cameras based on the SONIXB chip.
+
+	To compile this driver as a module, choose M here: the
+	module will be called gspca_sonixb.
+
+config USB_GSPCA_SONIXJ
+	tristate "SONIX JPEG USB Camera Driver"
+	depends on VIDEO_V4L2 && USB_GSPCA
+	help
+	Say Y here if you want support for cameras based on the SONIXJ chip.
+
+	To compile this driver as a module, choose M here: the
+	module will be called gspca_sonixj
+
+config USB_GSPCA_SPCA500
+	tristate "SPCA500 USB Camera Driver"
+	depends on VIDEO_V4L2 && USB_GSPCA
+	help
+	Say Y here if you want support for cameras based on the SPCA500 chip.
+
+	To compile this driver as a module, choose M here: the
+	module will be called gspca_spca500.
+
+config USB_GSPCA_SPCA501
+	tristate "SPCA501 USB Camera Driver"
+	depends on VIDEO_V4L2 && USB_GSPCA
+	help
+	Say Y here if you want support for cameras based on the SPCA501 chip.
+
+	To compile this driver as a module, choose M here: the
+	module will be called gspca_spca501.
+
+config USB_GSPCA_SPCA505
+	tristate "SPCA505 USB Camera Driver"
+	depends on VIDEO_V4L2 && USB_GSPCA
+	help
+	Say Y here if you want support for cameras based on the SPCA505 chip.
+
+	To compile this driver as a module, choose M here: the
+	module will be called gspca_spca505.
+
+config USB_GSPCA_SPCA506
+	tristate "SPCA506 USB Camera Driver"
+	depends on VIDEO_V4L2 && USB_GSPCA
+	help
+	Say Y here if you want support for cameras based on the SPCA506 chip.
+
+	To compile this driver as a module, choose M here: the
+	module will be called gspca_spca506.
+
+config USB_GSPCA_SPCA508
+	tristate "SPCA508 USB Camera Driver"
+	depends on VIDEO_V4L2 && USB_GSPCA
+	help
+	Say Y here if you want support for cameras based on the SPCA508 chip.
+
+	To compile this driver as a module, choose M here: the
+	module will be called gspca_spca508.
+
+config USB_GSPCA_SPCA561
+	tristate "SPCA561 USB Camera Driver"
+	depends on VIDEO_V4L2 && USB_GSPCA
+	help
+	Say Y here if you want support for cameras based on the SPCA561 chip.
+
+	To compile this driver as a module, choose M here: the
+	module will be called gspca_spca561.
+
+config USB_GSPCA_STK014
+	tristate "Syntek DV4000 (STK014) USB Camera Driver"
+	depends on VIDEO_V4L2 && USB_GSPCA
+	help
+	Say Y here if you want support for cameras based on the STK014 chip.
+
+	To compile this driver as a module, choose M here: the
+	module will be called gspca_stk014.
+
+config USB_GSPCA_SUNPLUS
+	tristate "SUNPLUS USB Camera Driver"
+	depends on VIDEO_V4L2 && USB_GSPCA
+	help
+	Say Y here if you want support for cameras based on the Sunplus
+	SPCA504(abc) SPCA533 SPCA536 chips.
+
+	To compile this driver as a module, choose M here: the
+	module will be called gspca_spca5xx.
+
+config USB_GSPCA_T613
+	tristate "T613 (JPEG Compliance) USB Camera Driver"
+	depends on VIDEO_V4L2 && USB_GSPCA
+	help
+	Say Y here if you want support for cameras based on the T613 chip.
+
+	To compile this driver as a module, choose M here: the
+	module will be called gspca_t613.
+
+config USB_GSPCA_TV8532
+	tristate "TV8532 USB Camera Driver"
+	depends on VIDEO_V4L2 && USB_GSPCA
+	help
+	Say Y here if you want support for cameras based on the TV8531 chip.
+
+	To compile this driver as a module, choose M here: the
+	module will be called gspca_tv8532.
+
+config USB_GSPCA_VC032X
+	tristate "VC032X USB Camera Driver"
+	depends on VIDEO_V4L2 && USB_GSPCA
+	help
+	Say Y here if you want support for cameras based on the VC032X chip.
+
+	To compile this driver as a module, choose M here: the
+	module will be called gspca_vc032x.
+
+config USB_GSPCA_ZC3XX
+	tristate "VC3xx USB Camera Driver"
+	depends on VIDEO_V4L2 && USB_GSPCA
+	help
+	Say Y here if you want support for cameras based on the ZC3XX chip.
+
+	To compile this driver as a module, choose M here: the
+	module will be called gspca_zc3xx.
+
+endif
diff --git a/drivers/media/video/gspca/Makefile b/drivers/media/video/gspca/Makefile
index e68a896..22734f5 100644
--- a/drivers/media/video/gspca/Makefile
+++ b/drivers/media/video/gspca/Makefile
@@ -1,29 +1,48 @@
-obj-$(CONFIG_USB_GSPCA)	+= gspca_main.o \
-	gspca_conex.o gspca_etoms.o gspca_mars.o \
-	gspca_ov519.o gspca_pac207.o gspca_pac7311.o \
-	gspca_sonixb.o gspca_sonixj.o gspca_spca500.o gspca_spca501.o \
-	gspca_spca505.o gspca_spca506.o gspca_spca508.o gspca_spca561.o \
-	gspca_sunplus.o gspca_stk014.o gspca_t613.o gspca_tv8532.o \
-	gspca_vc032x.o gspca_zc3xx.o
+obj-$(CONFIG_USB_GSPCA)		+= gspca_main.o
+obj-$(CONFIG_USB_GSPCA_CONEX)	+= gspca_conex.o
+obj-$(CONFIG_USB_GSPCA_ETOMS)	+= gspca_etoms.o
+obj-$(CONFIG_USB_GSPCA_FINEPIX)	+= gspca_finepix.o
+obj-$(CONFIG_USB_GSPCA_MARS)	+= gspca_mars.o
+obj-$(CONFIG_USB_GSPCA_OV519)	+= gspca_ov519.o
+obj-$(CONFIG_USB_GSPCA_PAC207)	+= gspca_pac207.o
+obj-$(CONFIG_USB_GSPCA_PAC7311) += gspca_pac7311.o
+obj-$(CONFIG_USB_GSPCA_SONIXB)	+= gspca_sonixb.o
+obj-$(CONFIG_USB_GSPCA_SONIXJ)	+= gspca_sonixj.o
+obj-$(CONFIG_USB_GSPCA_SPCA500) += gspca_spca500.o
+obj-$(CONFIG_USB_GSPCA_SPCA501) += gspca_spca501.o
+obj-$(CONFIG_USB_GSPCA_SPCA505) += gspca_spca505.o
+obj-$(CONFIG_USB_GSPCA_SPCA506) += gspca_spca506.o
+obj-$(CONFIG_USB_GSPCA_SPCA508) += gspca_spca508.o
+obj-$(CONFIG_USB_GSPCA_SPCA561) += gspca_spca561.o
+obj-$(CONFIG_USB_GSPCA_SUNPLUS) += gspca_sunplus.o
+obj-$(CONFIG_USB_GSPCA_STK014)	+= gspca_stk014.o
+obj-$(CONFIG_USB_GSPCA_T613)	+= gspca_t613.o
+obj-$(CONFIG_USB_GSPCA_TV8532)	+= gspca_tv8532.o
+obj-$(CONFIG_USB_GSPCA_VC032X)	+= gspca_vc032x.o
+obj-$(CONFIG_USB_GSPCA_ZC3XX)	+= gspca_zc3xx.o
 
-gspca_main-objs := gspca.o
-gspca_conex-objs := conex.o
-gspca_etoms-objs := etoms.o
-gspca_mars-objs := mars.o
-gspca_ov519-objs := ov519.o
-gspca_pac207-objs := pac207.o
-gspca_pac7311-objs := pac7311.o
-gspca_sonixb-objs := sonixb.o
-gspca_sonixj-objs := sonixj.o
-gspca_spca500-objs := spca500.o
-gspca_spca501-objs := spca501.o
-gspca_spca505-objs := spca505.o
-gspca_spca506-objs := spca506.o
-gspca_spca508-objs := spca508.o
-gspca_spca561-objs := spca561.o
-gspca_stk014-objs := stk014.o
-gspca_sunplus-objs := sunplus.o
-gspca_t613-objs := t613.o
-gspca_tv8532-objs := tv8532.o
-gspca_vc032x-objs := vc032x.o
-gspca_zc3xx-objs := zc3xx.o
+gspca_main-objs			:= gspca.o
+gspca_conex-objs		:= conex.o
+gspca_etoms-objs		:= etoms.o
+gspca_finepix-objs		:= finepix.o
+gspca_mars-objs			:= mars.o
+gspca_ov519-objs		:= ov519.o
+gspca_pac207-objs		:= pac207.o
+gspca_pac7311-objs		:= pac7311.o
+gspca_sonixb-objs		:= sonixb.o
+gspca_sonixj-objs		:= sonixj.o
+gspca_spca500-objs		:= spca500.o
+gspca_spca501-objs		:= spca501.o
+gspca_spca505-objs		:= spca505.o
+gspca_spca506-objs		:= spca506.o
+gspca_spca508-objs		:= spca508.o
+gspca_spca561-objs		:= spca561.o
+gspca_stk014-objs		:= stk014.o
+gspca_sunplus-objs		:= sunplus.o
+gspca_t613-objs			:= t613.o
+gspca_tv8532-objs		:= tv8532.o
+gspca_vc032x-objs		:= vc032x.o
+gspca_zc3xx-objs		:= zc3xx.o
+
+obj-$(CONFIG_USB_M5602)		+= m5602/
+
diff --git a/drivers/media/video/gspca/conex.c b/drivers/media/video/gspca/conex.c
index 4d9f4cc..a9d51ba 100644
--- a/drivers/media/video/gspca/conex.c
+++ b/drivers/media/video/gspca/conex.c
@@ -837,12 +837,13 @@
 	return 0;
 }
 
-static void sd_start(struct gspca_dev *gspca_dev)
+static int sd_start(struct gspca_dev *gspca_dev)
 {
 	cx11646_initsize(gspca_dev);
 	cx11646_fw(gspca_dev);
 	cx_sensor(gspca_dev);
 	cx11646_jpeg(gspca_dev);
+	return 0;
 }
 
 static void sd_stop0(struct gspca_dev *gspca_dev)
diff --git a/drivers/media/video/gspca/etoms.c b/drivers/media/video/gspca/etoms.c
index 4ff0e38..3be30b4 100644
--- a/drivers/media/video/gspca/etoms.c
+++ b/drivers/media/video/gspca/etoms.c
@@ -691,7 +691,7 @@
 }
 
 /* -- start the camera -- */
-static void sd_start(struct gspca_dev *gspca_dev)
+static int sd_start(struct gspca_dev *gspca_dev)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
 
@@ -704,6 +704,7 @@
 
 	reg_w_val(gspca_dev, ET_RESET_ALL, 0x08);
 	et_video(gspca_dev, 1);		/* video on */
+	return 0;
 }
 
 static void sd_stopN(struct gspca_dev *gspca_dev)
diff --git a/drivers/media/video/gspca/finepix.c b/drivers/media/video/gspca/finepix.c
new file mode 100644
index 0000000..65d3cbf
--- /dev/null
+++ b/drivers/media/video/gspca/finepix.c
@@ -0,0 +1,466 @@
+/*
+ * Fujifilm Finepix subdriver
+ *
+ * Copyright (C) 2008 Frank Zago
+ *
+ * This program is free software; you can redistribute it and/or 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
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#define MODULE_NAME "finepix"
+
+#include "gspca.h"
+
+MODULE_AUTHOR("Frank Zago <frank@zago.net>");
+MODULE_DESCRIPTION("Fujifilm FinePix USB V4L2 driver");
+MODULE_LICENSE("GPL");
+
+/* Default timeout, in ms */
+#define FPIX_TIMEOUT (HZ / 10)
+
+/* Maximum transfer size to use. The windows driver reads by chunks of
+ * 0x2000 bytes, so do the same. Note: reading more seems to work
+ * too. */
+#define FPIX_MAX_TRANSFER 0x2000
+
+/* Structure to hold all of our device specific stuff */
+struct usb_fpix {
+	struct gspca_dev gspca_dev;	/* !! must be the first item */
+
+	/*
+	 * USB stuff
+	 */
+	struct usb_ctrlrequest ctrlreq;
+	struct urb *control_urb;
+	struct timer_list bulk_timer;
+
+	enum {
+		FPIX_NOP,	/* inactive, else streaming */
+		FPIX_RESET,	/* must reset */
+		FPIX_REQ_FRAME,	/* requesting a frame */
+		FPIX_READ_FRAME,	/* reading frame */
+	} state;
+
+	/*
+	 * Driver stuff
+	 */
+	struct delayed_work wqe;
+	struct completion can_close;
+	int streaming;
+};
+
+/* Delay after which claim the next frame. If the delay is too small,
+ * the camera will return old frames. On the 4800Z, 20ms is bad, 25ms
+ * will fail every 4 or 5 frames, but 30ms is perfect. */
+#define NEXT_FRAME_DELAY  (((HZ * 30) + 999) / 1000)
+
+#define dev_new_state(new_state) {				\
+		PDEBUG(D_STREAM, "new state from %d to %d at %s:%d",	\
+			dev->state, new_state, __func__, __LINE__);	\
+		dev->state = new_state;					\
+}
+
+/* These cameras only support 320x200. */
+static struct v4l2_pix_format fpix_mode[1] = {
+	{ 320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+		.bytesperline = 320,
+		.sizeimage = 320 * 240 * 3 / 8 + 590,
+		.colorspace = V4L2_COLORSPACE_SRGB,
+		.priv = 0}
+};
+
+/* Reads part of a frame */
+static void read_frame_part(struct usb_fpix *dev)
+{
+	int ret;
+
+	PDEBUG(D_STREAM, "read_frame_part");
+
+	/* Reads part of a frame */
+	ret = usb_submit_urb(dev->gspca_dev.urb[0], GFP_ATOMIC);
+	if (ret) {
+		dev_new_state(FPIX_RESET);
+		schedule_delayed_work(&dev->wqe, 1);
+		PDEBUG(D_STREAM, "usb_submit_urb failed with %d",
+			ret);
+	} else {
+		/* Sometimes we never get a callback, so use a timer.
+		 * Is this masking a bug somewhere else? */
+		dev->bulk_timer.expires = jiffies + msecs_to_jiffies(150);
+		add_timer(&dev->bulk_timer);
+	}
+}
+
+/* Callback for URBs. */
+static void urb_callback(struct urb *urb)
+{
+	struct gspca_dev *gspca_dev = urb->context;
+	struct usb_fpix *dev = (struct usb_fpix *) gspca_dev;
+
+	PDEBUG(D_PACK,
+		"enter urb_callback - status=%d, length=%d",
+		urb->status, urb->actual_length);
+
+	if (dev->state == FPIX_READ_FRAME)
+		del_timer(&dev->bulk_timer);
+
+	if (urb->status != 0) {
+		/* We kill a stuck urb every 50 frames on average, so don't
+		 * display a log message for that. */
+		if (urb->status != -ECONNRESET)
+			PDEBUG(D_STREAM, "bad URB status %d", urb->status);
+		dev_new_state(FPIX_RESET);
+		schedule_delayed_work(&dev->wqe, 1);
+	}
+
+	switch (dev->state) {
+	case FPIX_REQ_FRAME:
+		dev_new_state(FPIX_READ_FRAME);
+		read_frame_part(dev);
+		break;
+
+	case FPIX_READ_FRAME: {
+		unsigned char *data = urb->transfer_buffer;
+		struct gspca_frame *frame;
+
+		frame = gspca_get_i_frame(&dev->gspca_dev);
+		if (frame == NULL)
+			gspca_dev->last_packet_type = DISCARD_PACKET;
+		if (urb->actual_length < FPIX_MAX_TRANSFER ||
+			(data[urb->actual_length-2] == 0xff &&
+				data[urb->actual_length-1] == 0xd9)) {
+
+			/* If the result is less than what was asked
+			 * for, then it's the end of the
+			 * frame. Sometime the jpeg is not complete,
+			 * but there's nothing we can do. We also end
+			 * here if the the jpeg ends right at the end
+			 * of the frame. */
+			if (frame)
+				gspca_frame_add(gspca_dev, LAST_PACKET,
+						frame,
+						data, urb->actual_length);
+			dev_new_state(FPIX_REQ_FRAME);
+			schedule_delayed_work(&dev->wqe, NEXT_FRAME_DELAY);
+		} else {
+
+			/* got a partial image */
+			if (frame)
+				gspca_frame_add(gspca_dev,
+						gspca_dev->last_packet_type
+								== LAST_PACKET
+						? FIRST_PACKET : INTER_PACKET,
+						frame,
+					data, urb->actual_length);
+			read_frame_part(dev);
+		}
+		break;
+	    }
+
+	case FPIX_NOP:
+	case FPIX_RESET:
+		PDEBUG(D_STREAM, "invalid state %d", dev->state);
+		break;
+	}
+}
+
+/* Request a new frame */
+static void request_frame(struct usb_fpix *dev)
+{
+	int ret;
+	struct gspca_dev *gspca_dev = &dev->gspca_dev;
+
+	/* Setup command packet */
+	memset(gspca_dev->usb_buf, 0, 12);
+	gspca_dev->usb_buf[0] = 0xd3;
+	gspca_dev->usb_buf[7] = 0x01;
+
+	/* Request a frame */
+	dev->ctrlreq.bRequestType =
+		USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE;
+	dev->ctrlreq.bRequest = USB_REQ_GET_STATUS;
+	dev->ctrlreq.wValue = 0;
+	dev->ctrlreq.wIndex = 0;
+	dev->ctrlreq.wLength = cpu_to_le16(12);
+
+	usb_fill_control_urb(dev->control_urb,
+			     gspca_dev->dev,
+			     usb_sndctrlpipe(gspca_dev->dev, 0),
+			     (unsigned char *) &dev->ctrlreq,
+			     gspca_dev->usb_buf,
+			     12, urb_callback, gspca_dev);
+
+	ret = usb_submit_urb(dev->control_urb, GFP_ATOMIC);
+	if (ret) {
+		dev_new_state(FPIX_RESET);
+		schedule_delayed_work(&dev->wqe, 1);
+		PDEBUG(D_STREAM, "usb_submit_urb failed with %d", ret);
+	}
+}
+
+/*--------------------------------------------------------------------------*/
+
+/* State machine. */
+static void fpix_sm(struct work_struct *work)
+{
+	struct usb_fpix *dev = container_of(work, struct usb_fpix, wqe.work);
+
+	PDEBUG(D_STREAM, "fpix_sm state %d", dev->state);
+
+	/* verify that the device wasn't unplugged */
+	if (!dev->gspca_dev.present) {
+		PDEBUG(D_STREAM, "device is gone");
+		dev_new_state(FPIX_NOP);
+		complete(&dev->can_close);
+		return;
+	}
+
+	if (!dev->streaming) {
+		PDEBUG(D_STREAM, "stopping state machine");
+		dev_new_state(FPIX_NOP);
+		complete(&dev->can_close);
+		return;
+	}
+
+	switch (dev->state) {
+	case FPIX_RESET:
+		dev_new_state(FPIX_REQ_FRAME);
+		schedule_delayed_work(&dev->wqe, HZ / 10);
+		break;
+
+	case FPIX_REQ_FRAME:
+		/* get an image */
+		request_frame(dev);
+		break;
+
+	case FPIX_NOP:
+	case FPIX_READ_FRAME:
+		PDEBUG(D_STREAM, "invalid state %d", dev->state);
+		break;
+	}
+}
+
+/* this function is called at probe time */
+static int sd_config(struct gspca_dev *gspca_dev,
+		const struct usb_device_id *id)
+{
+	struct cam *cam = &gspca_dev->cam;
+
+	cam->cam_mode = fpix_mode;
+	cam->nmodes = 1;
+	cam->epaddr = 0x01;	/* todo: correct for all cams? */
+	cam->bulk_size = FPIX_MAX_TRANSFER;
+
+/*	gspca_dev->nbalt = 1;	 * use bulk transfer */
+	return 0;
+}
+
+/* Stop streaming and free the ressources allocated by sd_start. */
+static void sd_stopN(struct gspca_dev *gspca_dev)
+{
+	struct usb_fpix *dev = (struct usb_fpix *) gspca_dev;
+
+	dev->streaming = 0;
+
+	/* Stop the state machine */
+	if (dev->state != FPIX_NOP)
+		wait_for_completion(&dev->can_close);
+
+	usb_free_urb(dev->control_urb);
+	dev->control_urb = NULL;
+}
+
+/* Kill an URB that hasn't completed. */
+static void timeout_kill(unsigned long data)
+{
+	struct urb *urb = (struct urb *) data;
+
+	usb_unlink_urb(urb);
+}
+
+/* this function is called at probe and resume time */
+static int sd_init(struct gspca_dev *gspca_dev)
+{
+	struct usb_fpix *dev = (struct usb_fpix *) gspca_dev;
+
+	INIT_DELAYED_WORK(&dev->wqe, fpix_sm);
+
+	init_timer(&dev->bulk_timer);
+	dev->bulk_timer.function = timeout_kill;
+
+	return 0;
+}
+
+static int sd_start(struct gspca_dev *gspca_dev)
+{
+	struct usb_fpix *dev = (struct usb_fpix *) gspca_dev;
+	int ret;
+	int size_ret;
+
+	/* Reset bulk in endpoint */
+	usb_clear_halt(gspca_dev->dev, gspca_dev->cam.epaddr);
+
+	/* Init the device */
+	memset(gspca_dev->usb_buf, 0, 12);
+	gspca_dev->usb_buf[0] = 0xc6;
+	gspca_dev->usb_buf[8] = 0x20;
+
+	ret = usb_control_msg(gspca_dev->dev,
+			usb_sndctrlpipe(gspca_dev->dev, 0),
+			USB_REQ_GET_STATUS,
+			USB_DIR_OUT | USB_TYPE_CLASS |
+			USB_RECIP_INTERFACE, 0, 0, gspca_dev->usb_buf,
+			12, FPIX_TIMEOUT);
+
+	if (ret != 12) {
+		PDEBUG(D_STREAM, "usb_control_msg failed (%d)", ret);
+		ret = -EIO;
+		goto error;
+	}
+
+	/* Read the result of the command. Ignore the result, for it
+	 * varies with the device. */
+	ret = usb_bulk_msg(gspca_dev->dev,
+			usb_rcvbulkpipe(gspca_dev->dev,
+					gspca_dev->cam.epaddr),
+			gspca_dev->usb_buf, FPIX_MAX_TRANSFER, &size_ret,
+			FPIX_TIMEOUT);
+	if (ret != 0) {
+		PDEBUG(D_STREAM, "usb_bulk_msg failed (%d)", ret);
+		ret = -EIO;
+		goto error;
+	}
+
+	/* Request a frame, but don't read it */
+	memset(gspca_dev->usb_buf, 0, 12);
+	gspca_dev->usb_buf[0] = 0xd3;
+	gspca_dev->usb_buf[7] = 0x01;
+
+	ret = usb_control_msg(gspca_dev->dev,
+			usb_sndctrlpipe(gspca_dev->dev, 0),
+			USB_REQ_GET_STATUS,
+			USB_DIR_OUT | USB_TYPE_CLASS |
+			USB_RECIP_INTERFACE, 0, 0, gspca_dev->usb_buf,
+			12, FPIX_TIMEOUT);
+	if (ret != 12) {
+		PDEBUG(D_STREAM, "usb_control_msg failed (%d)", ret);
+		ret = -EIO;
+		goto error;
+	}
+
+	/* Again, reset bulk in endpoint */
+	usb_clear_halt(gspca_dev->dev, gspca_dev->cam.epaddr);
+
+	/* Allocate a control URB */
+	dev->control_urb = usb_alloc_urb(0, GFP_KERNEL);
+	if (!dev->control_urb) {
+		PDEBUG(D_STREAM, "No free urbs available");
+		ret = -EIO;
+		goto error;
+	}
+
+	/* Various initializations. */
+	init_completion(&dev->can_close);
+	dev->bulk_timer.data = (unsigned long)dev->gspca_dev.urb[0];
+	dev->gspca_dev.urb[0]->complete = urb_callback;
+	dev->streaming = 1;
+
+	/* Schedule a frame request. */
+	dev_new_state(FPIX_REQ_FRAME);
+	schedule_delayed_work(&dev->wqe, 1);
+
+	return 0;
+
+error:
+	/* Free the ressources */
+	sd_stopN(gspca_dev);
+	return ret;
+}
+
+/* Table of supported USB devices */
+static const __devinitdata struct usb_device_id device_table[] = {
+	{USB_DEVICE(0x04cb, 0x0104)},
+	{USB_DEVICE(0x04cb, 0x0109)},
+	{USB_DEVICE(0x04cb, 0x010b)},
+	{USB_DEVICE(0x04cb, 0x010f)},
+	{USB_DEVICE(0x04cb, 0x0111)},
+	{USB_DEVICE(0x04cb, 0x0113)},
+	{USB_DEVICE(0x04cb, 0x0115)},
+	{USB_DEVICE(0x04cb, 0x0117)},
+	{USB_DEVICE(0x04cb, 0x0119)},
+	{USB_DEVICE(0x04cb, 0x011b)},
+	{USB_DEVICE(0x04cb, 0x011d)},
+	{USB_DEVICE(0x04cb, 0x0121)},
+	{USB_DEVICE(0x04cb, 0x0123)},
+	{USB_DEVICE(0x04cb, 0x0125)},
+	{USB_DEVICE(0x04cb, 0x0127)},
+	{USB_DEVICE(0x04cb, 0x0129)},
+	{USB_DEVICE(0x04cb, 0x012b)},
+	{USB_DEVICE(0x04cb, 0x012d)},
+	{USB_DEVICE(0x04cb, 0x012f)},
+	{USB_DEVICE(0x04cb, 0x0131)},
+	{USB_DEVICE(0x04cb, 0x013b)},
+	{USB_DEVICE(0x04cb, 0x013d)},
+	{USB_DEVICE(0x04cb, 0x013f)},
+	{}
+};
+
+MODULE_DEVICE_TABLE(usb, device_table);
+
+/* sub-driver description */
+static const struct sd_desc sd_desc = {
+	.name = MODULE_NAME,
+	.config = sd_config,
+	.init = sd_init,
+	.start = sd_start,
+	.stopN = sd_stopN,
+};
+
+/* -- device connect -- */
+static int sd_probe(struct usb_interface *intf,
+		const struct usb_device_id *id)
+{
+	return gspca_dev_probe(intf, id,
+			&sd_desc,
+			sizeof(struct usb_fpix),
+			THIS_MODULE);
+}
+
+static struct usb_driver sd_driver = {
+	.name = MODULE_NAME,
+	.id_table = device_table,
+	.probe = sd_probe,
+	.disconnect = gspca_disconnect,
+#ifdef CONFIG_PM
+	.suspend = gspca_suspend,
+	.resume = gspca_resume,
+#endif
+};
+
+/* -- module insert / remove -- */
+static int __init sd_mod_init(void)
+{
+	if (usb_register(&sd_driver) < 0)
+		return -1;
+	PDEBUG(D_PROBE, "registered");
+	return 0;
+}
+static void __exit sd_mod_exit(void)
+{
+	usb_deregister(&sd_driver);
+	PDEBUG(D_PROBE, "deregistered");
+}
+
+module_init(sd_mod_init);
+module_exit(sd_mod_exit);
diff --git a/drivers/media/video/gspca/gspca.c b/drivers/media/video/gspca/gspca.c
index 7be6928..c21af31 100644
--- a/drivers/media/video/gspca/gspca.c
+++ b/drivers/media/video/gspca/gspca.c
@@ -29,6 +29,7 @@
 #include <linux/string.h>
 #include <linux/pagemap.h>
 #include <linux/io.h>
+#include <linux/kref.h>
 #include <asm/page.h>
 #include <linux/uaccess.h>
 #include <linux/jiffies.h>
@@ -43,7 +44,7 @@
 MODULE_DESCRIPTION("GSPCA USB Camera Driver");
 MODULE_LICENSE("GPL");
 
-#define DRIVER_VERSION_NUMBER	KERNEL_VERSION(2, 2, 0)
+#define DRIVER_VERSION_NUMBER	KERNEL_VERSION(2, 3, 0)
 
 static int video_nr = -1;
 
@@ -102,6 +103,22 @@
 	.close		= gspca_vm_close,
 };
 
+/* get the current input frame buffer */
+struct gspca_frame *gspca_get_i_frame(struct gspca_dev *gspca_dev)
+{
+	struct gspca_frame *frame;
+	int i;
+
+	i = gspca_dev->fr_i;
+	i = gspca_dev->fr_queue[i];
+	frame = &gspca_dev->frame[i];
+	if ((frame->v4l2_buf.flags & BUF_ALL_FLAGS)
+				!= V4L2_BUF_FLAG_QUEUED)
+		return NULL;
+	return frame;
+}
+EXPORT_SYMBOL(gspca_get_i_frame);
+
 /*
  * fill a video frame from an URB and resubmit
  */
@@ -110,7 +127,7 @@
 {
 	struct gspca_frame *frame;
 	__u8 *data;		/* address of data in the iso message */
-	int i, j, len, st;
+	int i, len, st;
 	cam_pkt_op pkt_scan;
 
 	if (urb->status != 0) {
@@ -124,11 +141,8 @@
 	for (i = 0; i < urb->number_of_packets; i++) {
 
 		/* check the availability of the frame buffer */
-		j = gspca_dev->fr_i;
-		j = gspca_dev->fr_queue[j];
-		frame = &gspca_dev->frame[j];
-		if ((frame->v4l2_buf.flags & BUF_ALL_FLAGS)
-					!= V4L2_BUF_FLAG_QUEUED) {
+		frame = gspca_get_i_frame(gspca_dev);
+		if (!frame) {
 			gspca_dev->last_packet_type = DISCARD_PACKET;
 			break;
 		}
@@ -178,6 +192,39 @@
 }
 
 /*
+ * bulk message interrupt from the USB device
+ */
+static void bulk_irq(struct urb *urb
+)
+{
+	struct gspca_dev *gspca_dev = (struct gspca_dev *) urb->context;
+	struct gspca_frame *frame;
+
+	PDEBUG(D_PACK, "bulk irq");
+	if (!gspca_dev->streaming)
+		return;
+	if (urb->status != 0 && urb->status != -ECONNRESET) {
+#ifdef CONFIG_PM
+		if (!gspca_dev->frozen)
+#endif
+			PDEBUG(D_ERR|D_PACK, "urb status: %d", urb->status);
+		return;		/* disconnection ? */
+	}
+
+	/* check the availability of the frame buffer */
+	frame = gspca_get_i_frame(gspca_dev);
+	if (!frame) {
+		gspca_dev->last_packet_type = DISCARD_PACKET;
+	} else {
+		PDEBUG(D_PACK, "packet l:%d", urb->actual_length);
+		gspca_dev->sd_desc->pkt_scan(gspca_dev,
+					frame,
+					urb->transfer_buffer,
+					urb->actual_length);
+	}
+}
+
+/*
  * add data to the current frame
  *
  * This function is called by the subdrivers at interrupt level.
@@ -190,7 +237,7 @@
  * On LAST_PACKET, a new frame is returned.
  */
 struct gspca_frame *gspca_frame_add(struct gspca_dev *gspca_dev,
-				    int packet_type,
+				    enum gspca_packet_type packet_type,
 				    struct gspca_frame *frame,
 				    const __u8 *data,
 				    int len)
@@ -232,7 +279,7 @@
 	}
 	gspca_dev->last_packet_type = packet_type;
 
-	/* if last packet, wake the application and advance in the queue */
+	/* if last packet, wake up the application and advance in the queue */
 	if (packet_type == LAST_PACKET) {
 		frame->v4l2_buf.bytesused = frame->data_end - frame->data;
 		frame->v4l2_buf.flags &= ~V4L2_BUF_FLAG_QUEUED;
@@ -270,7 +317,6 @@
 	void *mem;
 	unsigned long adr;
 
-/*	size = PAGE_ALIGN(size);	(already done) */
 	mem = vmalloc_32(size);
 	if (mem != NULL) {
 		adr = (unsigned long) mem;
@@ -374,10 +420,11 @@
 }
 
 /*
- * search an input isochronous endpoint in an alternate setting
+ * look for an input transfer endpoint in an alternate setting
  */
-static struct usb_host_endpoint *alt_isoc(struct usb_host_interface *alt,
-					  __u8 epaddr)
+static struct usb_host_endpoint *alt_xfer(struct usb_host_interface *alt,
+					  __u8 epaddr,
+					  __u8 xfer)
 {
 	struct usb_host_endpoint *ep;
 	int i, attr;
@@ -388,7 +435,7 @@
 		if (ep->desc.bEndpointAddress == epaddr) {
 			attr = ep->desc.bmAttributes
 						& USB_ENDPOINT_XFERTYPE_MASK;
-			if (attr == USB_ENDPOINT_XFER_ISOC)
+			if (attr == xfer)
 				return ep;
 			break;
 		}
@@ -397,14 +444,14 @@
 }
 
 /*
- * search an input isochronous endpoint
+ * look for an input (isoc or bulk) endpoint
  *
  * The endpoint is defined by the subdriver.
  * Use only the first isoc (some Zoran - 0x0572:0x0001 - have two such ep).
  * This routine may be called many times when the bandwidth is too small
  * (the bandwidth is checked on urb submit).
  */
-static struct usb_host_endpoint *get_isoc_ep(struct gspca_dev *gspca_dev)
+static struct usb_host_endpoint *get_ep(struct gspca_dev *gspca_dev)
 {
 	struct usb_interface *intf;
 	struct usb_host_endpoint *ep;
@@ -413,28 +460,41 @@
 	intf = usb_ifnum_to_if(gspca_dev->dev, gspca_dev->iface);
 	ep = NULL;
 	i = gspca_dev->alt;			/* previous alt setting */
+
+	/* try isoc */
 	while (--i > 0) {			/* alt 0 is unusable */
-		ep = alt_isoc(&intf->altsetting[i], gspca_dev->cam.epaddr);
+		ep = alt_xfer(&intf->altsetting[i],
+				gspca_dev->cam.epaddr,
+				USB_ENDPOINT_XFER_ISOC);
 		if (ep)
 			break;
 	}
+
+	/* if no isoc, try bulk */
 	if (ep == NULL) {
-		err("no ISOC endpoint found");
-		return NULL;
+		ep = alt_xfer(&intf->altsetting[0],
+				gspca_dev->cam.epaddr,
+				USB_ENDPOINT_XFER_BULK);
+		if (ep == NULL) {
+			err("no transfer endpoint found");
+			return NULL;
+		}
 	}
-	PDEBUG(D_STREAM, "use ISOC alt %d ep 0x%02x",
+	PDEBUG(D_STREAM, "use alt %d ep 0x%02x",
 			i, ep->desc.bEndpointAddress);
-	ret = usb_set_interface(gspca_dev->dev, gspca_dev->iface, i);
-	if (ret < 0) {
-		err("set interface err %d", ret);
-		return NULL;
+	if (i > 0) {
+		ret = usb_set_interface(gspca_dev->dev, gspca_dev->iface, i);
+		if (ret < 0) {
+			err("set interface err %d", ret);
+			return NULL;
+		}
 	}
 	gspca_dev->alt = i;		/* memorize the current alt setting */
 	return ep;
 }
 
 /*
- * create the isochronous URBs
+ * create the URBs for image transfer
  */
 static int create_urbs(struct gspca_dev *gspca_dev,
 			struct usb_host_endpoint *ep)
@@ -445,20 +505,33 @@
 	/* calculate the packet size and the number of packets */
 	psize = le16_to_cpu(ep->desc.wMaxPacketSize);
 
-	/* See paragraph 5.9 / table 5-11 of the usb 2.0 spec. */
-	psize = (psize & 0x07ff) * (1 + ((psize >> 11) & 3));
-	npkt = ISO_MAX_SIZE / psize;
-	if (npkt > ISO_MAX_PKT)
-		npkt = ISO_MAX_PKT;
-	bsize = psize * npkt;
-	PDEBUG(D_STREAM,
-		"isoc %d pkts size %d (bsize:%d)", npkt, psize, bsize);
-	nurbs = DEF_NURBS;
+	if (gspca_dev->alt != 0) {		/* isoc */
+
+		/* See paragraph 5.9 / table 5-11 of the usb 2.0 spec. */
+		psize = (psize & 0x07ff) * (1 + ((psize >> 11) & 3));
+		npkt = ISO_MAX_SIZE / psize;
+		if (npkt > ISO_MAX_PKT)
+			npkt = ISO_MAX_PKT;
+		bsize = psize * npkt;
+		PDEBUG(D_STREAM,
+			"isoc %d pkts size %d = bsize:%d",
+			npkt, psize, bsize);
+		nurbs = DEF_NURBS;
+	} else {				/* bulk */
+		npkt = 0;
+		bsize = gspca_dev->cam.	bulk_size;
+		if (bsize == 0)
+			bsize = psize;
+		PDEBUG(D_STREAM, "bulk bsize:%d", bsize);
+		nurbs = 1;
+	}
+
 	gspca_dev->nurbs = nurbs;
 	for (n = 0; n < nurbs; n++) {
 		urb = usb_alloc_urb(npkt, GFP_KERNEL);
 		if (!urb) {
 			err("usb_alloc_urb failed");
+			destroy_urbs(gspca_dev);
 			return -ENOMEM;
 		}
 		urb->transfer_buffer = usb_buffer_alloc(gspca_dev->dev,
@@ -468,24 +541,31 @@
 
 		if (urb->transfer_buffer == NULL) {
 			usb_free_urb(urb);
-			destroy_urbs(gspca_dev);
 			err("usb_buffer_urb failed");
+			destroy_urbs(gspca_dev);
 			return -ENOMEM;
 		}
 		gspca_dev->urb[n] = urb;
 		urb->dev = gspca_dev->dev;
 		urb->context = gspca_dev;
-		urb->pipe = usb_rcvisocpipe(gspca_dev->dev,
-					    ep->desc.bEndpointAddress);
-		urb->transfer_flags = URB_ISO_ASAP
-					| URB_NO_TRANSFER_DMA_MAP;
-		urb->interval = ep->desc.bInterval;
-		urb->complete = isoc_irq;
-		urb->number_of_packets = npkt;
 		urb->transfer_buffer_length = bsize;
-		for (i = 0; i < npkt; i++) {
-			urb->iso_frame_desc[i].length = psize;
-			urb->iso_frame_desc[i].offset = psize * i;
+		if (npkt != 0) {		/* ISOC */
+			urb->pipe = usb_rcvisocpipe(gspca_dev->dev,
+						    ep->desc.bEndpointAddress);
+			urb->transfer_flags = URB_ISO_ASAP
+					| URB_NO_TRANSFER_DMA_MAP;
+			urb->interval = ep->desc.bInterval;
+			urb->complete = isoc_irq;
+			urb->number_of_packets = npkt;
+			for (i = 0; i < npkt; i++) {
+				urb->iso_frame_desc[i].length = psize;
+				urb->iso_frame_desc[i].offset = psize * i;
+			}
+		} else {		/* bulk */
+			urb->pipe = usb_rcvbulkpipe(gspca_dev->dev,
+						ep->desc.bEndpointAddress),
+			urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP;
+			urb->complete = bulk_irq;
 		}
 	}
 	return 0;
@@ -507,7 +587,7 @@
 	gspca_dev->alt = gspca_dev->nbalt;
 	for (;;) {
 		PDEBUG(D_STREAM, "init transfer alt %d", gspca_dev->alt);
-		ep = get_isoc_ep(gspca_dev);
+		ep = get_ep(gspca_dev);
 		if (ep == NULL) {
 			ret = -EIO;
 			goto out;
@@ -517,10 +597,18 @@
 			goto out;
 
 		/* start the cam */
-		gspca_dev->sd_desc->start(gspca_dev);
+		ret = gspca_dev->sd_desc->start(gspca_dev);
+		if (ret < 0) {
+			destroy_urbs(gspca_dev);
+			goto out;
+		}
 		gspca_dev->streaming = 1;
 		atomic_set(&gspca_dev->nevent, 0);
 
+		/* bulk transfers are started by the subdriver */
+		if (gspca_dev->alt == 0)
+			break;
+
 		/* submit the URBs */
 		for (n = 0; n < gspca_dev->nurbs; n++) {
 			ret = usb_submit_urb(gspca_dev->urb[n], GFP_KERNEL);
@@ -552,7 +640,7 @@
 	return ret;
 }
 
-/* Note both the queue and the usb lock should be hold when calling this */
+/* Note: both the queue and the usb locks should be held when calling this */
 static void gspca_stream_off(struct gspca_dev *gspca_dev)
 {
 	gspca_dev->streaming = 0;
@@ -758,6 +846,16 @@
 	return ret;
 }
 
+static void gspca_delete(struct kref *kref)
+{
+	struct gspca_dev *gspca_dev = container_of(kref, struct gspca_dev, kref);
+
+	PDEBUG(D_STREAM, "device deleted");
+
+	kfree(gspca_dev->usb_buf);
+	kfree(gspca_dev);
+}
+
 static int dev_open(struct inode *inode, struct file *file)
 {
 	struct gspca_dev *gspca_dev;
@@ -777,13 +875,19 @@
 		goto out;
 	}
 	gspca_dev->users++;
+
+	/* one more user */
+	kref_get(&gspca_dev->kref);
+
 	file->private_data = gspca_dev;
 #ifdef GSPCA_DEBUG
 	/* activate the v4l2 debug */
 	if (gspca_debug & D_V4L2)
-		gspca_dev->vdev.debug |= 3;
+		gspca_dev->vdev.debug |= V4L2_DEBUG_IOCTL
+					| V4L2_DEBUG_IOCTL_ARG;
 	else
-		gspca_dev->vdev.debug &= ~3;
+		gspca_dev->vdev.debug &= ~(V4L2_DEBUG_IOCTL
+					| V4L2_DEBUG_IOCTL_ARG);
 #endif
 	ret = 0;
 out:
@@ -817,7 +921,11 @@
 	}
 	file->private_data = NULL;
 	mutex_unlock(&gspca_dev->queue_lock);
+
 	PDEBUG(D_STREAM, "close done");
+
+	kref_put(&gspca_dev->kref, gspca_delete);
+
 	return 0;
 }
 
@@ -828,7 +936,6 @@
 
 	memset(cap, 0, sizeof *cap);
 	strncpy(cap->driver, gspca_dev->sd_desc->name, sizeof cap->driver);
-/*	strncpy(cap->card, gspca_dev->cam.dev_name, sizeof cap->card); */
 	if (gspca_dev->dev->product != NULL) {
 		strncpy(cap->card, gspca_dev->dev->product,
 			sizeof cap->card);
@@ -1462,7 +1569,6 @@
 	}
 
 	frame->v4l2_buf.flags |= V4L2_BUF_FLAG_QUEUED;
-/*	frame->v4l2_buf.flags &= ~V4L2_BUF_FLAG_DONE; */
 
 	if (frame->v4l2_buf.memory == V4L2_MEMORY_USERPTR) {
 		frame->v4l2_buf.m.userptr = v4l2_buf->m.userptr;
@@ -1609,7 +1715,7 @@
 		}
 
 		/* if the process slept for more than 1 second,
-		 * get anewer frame */
+		 * get a newer frame */
 		frame = &gspca_dev->frame[v4l2_buf.index];
 		if (--n < 0)
 			break;			/* avoid infinite loop */
@@ -1727,21 +1833,21 @@
 	if (dev_size < sizeof *gspca_dev)
 		dev_size = sizeof *gspca_dev;
 	gspca_dev = kzalloc(dev_size, GFP_KERNEL);
-	if (gspca_dev == NULL) {
+	if (!gspca_dev) {
 		err("couldn't kzalloc gspca struct");
-		return -EIO;
+		return -ENOMEM;
 	}
+	kref_init(&gspca_dev->kref);
 	gspca_dev->usb_buf = kmalloc(USB_BUF_SZ, GFP_KERNEL);
 	if (!gspca_dev->usb_buf) {
 		err("out of memory");
-		ret = -EIO;
+		ret = -ENOMEM;
 		goto out;
 	}
 	gspca_dev->dev = dev;
 	gspca_dev->iface = interface->bInterfaceNumber;
 	gspca_dev->nbalt = intf->num_altsetting;
 	gspca_dev->sd_desc = sd_desc;
-/*	gspca_dev->users = 0;			(done by kzalloc) */
 	gspca_dev->nbufread = 2;
 
 	/* configure the subdriver and initialize the USB device */
@@ -1780,8 +1886,7 @@
 	PDEBUG(D_PROBE, "probe ok");
 	return 0;
 out:
-	kfree(gspca_dev->usb_buf);
-	kfree(gspca_dev);
+	kref_put(&gspca_dev->kref, gspca_delete);
 	return ret;
 }
 EXPORT_SYMBOL(gspca_dev_probe);
@@ -1796,25 +1901,16 @@
 {
 	struct gspca_dev *gspca_dev = usb_get_intfdata(intf);
 
-	if (!gspca_dev)
-		return;
-	gspca_dev->present = 0;
-	mutex_lock(&gspca_dev->queue_lock);
-	mutex_lock(&gspca_dev->usb_lock);
-	gspca_dev->streaming = 0;
-	destroy_urbs(gspca_dev);
-	mutex_unlock(&gspca_dev->usb_lock);
-	mutex_unlock(&gspca_dev->queue_lock);
-	while (gspca_dev->users != 0) {		/* wait until fully closed */
-		atomic_inc(&gspca_dev->nevent);
-		wake_up_interruptible(&gspca_dev->wq);	/* wake processes */
-		schedule();
-	}
+	usb_set_intfdata(intf, NULL);
+
 /* We don't want people trying to open up the device */
 	video_unregister_device(&gspca_dev->vdev);
-/* Free the memory */
-	kfree(gspca_dev->usb_buf);
-	kfree(gspca_dev);
+
+	gspca_dev->present = 0;
+	gspca_dev->streaming = 0;
+
+	kref_put(&gspca_dev->kref, gspca_delete);
+
 	PDEBUG(D_PROBE, "disconnect complete");
 }
 EXPORT_SYMBOL(gspca_disconnect);
diff --git a/drivers/media/video/gspca/gspca.h b/drivers/media/video/gspca/gspca.h
index c17625c..4779dd0 100644
--- a/drivers/media/video/gspca/gspca.h
+++ b/drivers/media/video/gspca/gspca.h
@@ -49,13 +49,14 @@
 	} while (0)
 
 #define GSPCA_MAX_FRAMES 16	/* maximum number of video frame buffers */
-/* ISOC transfers */
-#define MAX_NURBS 16		/* max number of URBs */
+/* image transfers */
+#define MAX_NURBS 4		/* max number of URBs */
 #define ISO_MAX_PKT 32		/* max number of packets in an ISOC transfer */
 #define ISO_MAX_SIZE 0x8000	/* max size of one URB buffer (32 Kb) */
 
 /* device information - set at probe time */
 struct cam {
+	int bulk_size;		/* buffer size when image transfer by bulk */
 	struct v4l2_pix_format *cam_mode;	/* size nmodes */
 	char nmodes;
 	__u8 epaddr;
@@ -93,7 +94,7 @@
 /* mandatory operations */
 	cam_cf_op config;	/* called on probe */
 	cam_op init;		/* called on probe and resume */
-	cam_v_op start;		/* called on stream on */
+	cam_op start;		/* called on stream on */
 	cam_pkt_op pkt_scan;
 /* optional operations */
 	cam_v_op stopN;		/* called on stream off - main alt */
@@ -105,10 +106,12 @@
 };
 
 /* packet types when moving from iso buf to frame buf */
-#define DISCARD_PACKET	0
-#define FIRST_PACKET	1
-#define INTER_PACKET	2
-#define LAST_PACKET	3
+enum gspca_packet_type {
+	DISCARD_PACKET,
+	FIRST_PACKET,
+	INTER_PACKET,
+	LAST_PACKET
+};
 
 struct gspca_frame {
 	__u8 *data;			/* frame buffer */
@@ -121,6 +124,7 @@
 	struct video_device vdev;	/* !! must be the first item */
 	struct file_operations fops;
 	struct usb_device *dev;
+	struct kref kref;
 	struct file *capt_file;		/* file doing video capture */
 
 	struct cam cam;				/* device information */
@@ -173,10 +177,11 @@
 		struct module *module);
 void gspca_disconnect(struct usb_interface *intf);
 struct gspca_frame *gspca_frame_add(struct gspca_dev *gspca_dev,
-				    int packet_type,
+				    enum gspca_packet_type packet_type,
 				    struct gspca_frame *frame,
 				    const __u8 *data,
 				    int len);
+struct gspca_frame *gspca_get_i_frame(struct gspca_dev *gspca_dev);
 #ifdef CONFIG_PM
 int gspca_suspend(struct usb_interface *intf, pm_message_t message);
 int gspca_resume(struct usb_interface *intf);
diff --git a/drivers/media/video/gspca/m5602/Kconfig b/drivers/media/video/gspca/m5602/Kconfig
new file mode 100644
index 0000000..5a69016
--- /dev/null
+++ b/drivers/media/video/gspca/m5602/Kconfig
@@ -0,0 +1,11 @@
+config USB_M5602
+	tristate "ALi USB m5602 Camera Driver"
+	depends on VIDEO_V4L2 && USB_GSPCA
+	help
+	  Say Y here if you want support for cameras based on the
+	  ALi m5602 connected to various image sensors.
+
+	  See <file:Documentation/video4linux/m5602.txt> for more info.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called gspca_m5602.
diff --git a/drivers/media/video/gspca/m5602/Makefile b/drivers/media/video/gspca/m5602/Makefile
new file mode 100644
index 0000000..226ab4f
--- /dev/null
+++ b/drivers/media/video/gspca/m5602/Makefile
@@ -0,0 +1,11 @@
+obj-$(CONFIG_USB_M5602) += gspca_m5602.o
+
+gspca_m5602-objs := m5602_core.o \
+		    m5602_ov9650.o \
+		    m5602_mt9m111.o \
+		    m5602_po1030.o \
+		    m5602_s5k83a.o \
+		    m5602_s5k4aa.o
+
+EXTRA_CFLAGS += -Idrivers/media/video/gspca
+
diff --git a/drivers/media/video/gspca/m5602/m5602_bridge.h b/drivers/media/video/gspca/m5602/m5602_bridge.h
new file mode 100644
index 0000000..c786d7d
--- /dev/null
+++ b/drivers/media/video/gspca/m5602/m5602_bridge.h
@@ -0,0 +1,170 @@
+/*
+ * USB Driver for ALi m5602 based webcams
+ *
+ * Copyright (C) 2008 Erik Andren
+ * Copyright (C) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project.
+ * Copyright (C) 2005 m5603x Linux Driver Project <m5602@x3ng.com.br>
+ *
+ * Portions of code to USB interface and ALi driver software,
+ * Copyright (c) 2006 Willem Duinker
+ * v4l2 interface modeled after the V4L2 driver
+ * for SN9C10x PC Camera Controllers
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2.
+ *
+ */
+
+#ifndef M5602_BRIDGE_H_
+#define M5602_BRIDGE_H_
+
+#include "gspca.h"
+
+#define MODULE_NAME "ALi m5602"
+
+/*****************************************************************************/
+
+#undef PDEBUG
+#undef info
+#undef err
+
+#define err(format, arg...) printk(KERN_ERR KBUILD_MODNAME ": " \
+	format "\n" , ## arg)
+#define info(format, arg...) printk(KERN_INFO KBUILD_MODNAME ": " \
+	format "\n" , ## arg)
+
+/* Debug parameters */
+#define DBG_INIT 0x1
+#define DBG_PROBE 0x2
+#define DBG_V4L2 0x4
+#define DBG_TRACE 0x8
+#define DBG_DATA 0x10
+#define DBG_V4L2_CID 0x20
+#define DBG_GSPCA 0x40
+
+#define PDEBUG(level, fmt, args...) \
+	do { \
+		if (m5602_debug & level)     \
+			info("[%s:%d] " fmt, __func__, __LINE__ , \
+			## args); \
+	} while (0)
+
+/*****************************************************************************/
+
+#define M5602_XB_SENSOR_TYPE 0x00
+#define M5602_XB_SENSOR_CTRL 0x01
+#define M5602_XB_LINE_OF_FRAME_H 0x02
+#define M5602_XB_LINE_OF_FRAME_L 0x03
+#define M5602_XB_PIX_OF_LINE_H 0x04
+#define M5602_XB_PIX_OF_LINE_L 0x05
+#define M5602_XB_VSYNC_PARA 0x06
+#define M5602_XB_HSYNC_PARA 0x07
+#define M5602_XB_TEST_MODE_1 0x08
+#define M5602_XB_TEST_MODE_2 0x09
+#define M5602_XB_SIG_INI 0x0a
+#define M5602_XB_DS_PARA 0x0e
+#define M5602_XB_TRIG_PARA 0x0f
+#define M5602_XB_CLK_PD 0x10
+#define M5602_XB_MCU_CLK_CTRL 0x12
+#define M5602_XB_MCU_CLK_DIV 0x13
+#define M5602_XB_SEN_CLK_CTRL 0x14
+#define M5602_XB_SEN_CLK_DIV 0x15
+#define M5602_XB_AUD_CLK_CTRL 0x16
+#define M5602_XB_AUD_CLK_DIV 0x17
+#define M5602_XB_DEVCTR1 0x41
+#define M5602_XB_EPSETR0 0x42
+#define M5602_XB_EPAFCTR 0x47
+#define M5602_XB_EPBFCTR 0x49
+#define M5602_XB_EPEFCTR 0x4f
+#define M5602_XB_TEST_REG 0x53
+#define M5602_XB_ALT2SIZE 0x54
+#define M5602_XB_ALT3SIZE 0x55
+#define M5602_XB_OBSFRAME 0x56
+#define M5602_XB_PWR_CTL 0x59
+#define M5602_XB_ADC_CTRL 0x60
+#define M5602_XB_ADC_DATA 0x61
+#define M5602_XB_MISC_CTRL 0x62
+#define M5602_XB_SNAPSHOT 0x63
+#define M5602_XB_SCRATCH_1 0x64
+#define M5602_XB_SCRATCH_2 0x65
+#define M5602_XB_SCRATCH_3 0x66
+#define M5602_XB_SCRATCH_4 0x67
+#define M5602_XB_I2C_CTRL 0x68
+#define M5602_XB_I2C_CLK_DIV 0x69
+#define M5602_XB_I2C_DEV_ADDR 0x6a
+#define M5602_XB_I2C_REG_ADDR 0x6b
+#define M5602_XB_I2C_DATA 0x6c
+#define M5602_XB_I2C_STATUS 0x6d
+#define M5602_XB_GPIO_DAT_H 0x70
+#define M5602_XB_GPIO_DAT_L 0x71
+#define M5602_XB_GPIO_DIR_H 0x72
+#define M5602_XB_GPIO_DIR_L 0x73
+#define M5602_XB_GPIO_EN_H 0x74
+#define M5602_XB_GPIO_EN_L 0x75
+#define M5602_XB_GPIO_DAT 0x76
+#define M5602_XB_GPIO_DIR 0x77
+#define M5602_XB_MISC_CTL 0x70
+
+#define I2C_BUSY 0x80
+
+/*****************************************************************************/
+
+/* Driver info */
+#define DRIVER_AUTHOR "ALi m5602 Linux Driver Project"
+#define DRIVER_DESC "ALi m5602 webcam driver"
+
+#define M5602_ISOC_ENDPOINT_ADDR 0x81
+#define M5602_INTR_ENDPOINT_ADDR 0x82
+
+#define M5602_MAX_FRAMES	32
+#define M5602_URBS		2
+#define M5602_ISOC_PACKETS	14
+
+#define M5602_URB_TIMEOUT	msecs_to_jiffies(2 * M5602_ISOC_PACKETS)
+#define M5602_URB_MSG_TIMEOUT   5000
+#define M5602_FRAME_TIMEOUT	2
+
+/*****************************************************************************/
+
+/* A skeleton used for sending messages to the m5602 bridge */
+static const unsigned char bridge_urb_skeleton[] = {
+	0x13, 0x00, 0x81, 0x00
+};
+
+/* A skeleton used for sending messages to the sensor */
+static const unsigned char sensor_urb_skeleton[] = {
+	0x23, M5602_XB_GPIO_EN_H, 0x81, 0x06,
+	0x23, M5602_XB_MISC_CTRL, 0x81, 0x80,
+	0x13, M5602_XB_I2C_DEV_ADDR, 0x81, 0x00,
+	0x13, M5602_XB_I2C_REG_ADDR, 0x81, 0x00,
+	0x13, M5602_XB_I2C_DATA, 0x81, 0x00,
+	0x13, M5602_XB_I2C_CTRL, 0x81, 0x11
+};
+
+/* m5602 device descriptor, currently it just wraps the m5602_camera struct */
+struct sd {
+	struct gspca_dev gspca_dev;
+
+	/* The name of the m5602 camera */
+	char *name;
+
+	/* A pointer to the currently connected sensor */
+	struct m5602_sensor *sensor;
+
+	struct sd_desc *desc;
+
+	/* The current frame's id, used to detect frame boundaries */
+	u8 frame_id;
+
+	/* The current frame count */
+	u32 frame_count;
+};
+
+int m5602_read_bridge(
+	struct sd *sd, u8 address, u8 *i2c_data);
+
+int m5602_write_bridge(
+	struct sd *sd, u8 address, u8 i2c_data);
+
+#endif
diff --git a/drivers/media/video/gspca/m5602/m5602_core.c b/drivers/media/video/gspca/m5602/m5602_core.c
new file mode 100644
index 0000000..19d5e35
--- /dev/null
+++ b/drivers/media/video/gspca/m5602/m5602_core.c
@@ -0,0 +1,313 @@
+/*
+ * USB Driver for ALi m5602 based webcams
+ *
+ * Copyright (C) 2008 Erik Andren
+ * Copyright (C) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project.
+ * Copyright (C) 2005 m5603x Linux Driver Project <m5602@x3ng.com.br>
+ *
+ * Portions of code to USB interface and ALi driver software,
+ * Copyright (c) 2006 Willem Duinker
+ * v4l2 interface modeled after the V4L2 driver
+ * for SN9C10x PC Camera Controllers
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2.
+ *
+ */
+
+#include "m5602_ov9650.h"
+#include "m5602_mt9m111.h"
+#include "m5602_po1030.h"
+#include "m5602_s5k83a.h"
+#include "m5602_s5k4aa.h"
+
+/* Kernel module parameters */
+int force_sensor;
+int dump_bridge;
+int dump_sensor;
+unsigned int m5602_debug;
+
+static const __devinitdata struct usb_device_id m5602_table[] = {
+	{USB_DEVICE(0x0402, 0x5602)},
+	{}
+};
+
+MODULE_DEVICE_TABLE(usb, m5602_table);
+
+/* Reads a byte from the m5602 */
+int m5602_read_bridge(struct sd *sd, u8 address, u8 *i2c_data)
+{
+	int err;
+	struct usb_device *udev = sd->gspca_dev.dev;
+	__u8 *buf = sd->gspca_dev.usb_buf;
+
+	err = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
+			      0x04, 0xc0, 0x14,
+			      0x8100 + address, buf,
+			      1, M5602_URB_MSG_TIMEOUT);
+	*i2c_data = buf[0];
+
+	PDEBUG(DBG_TRACE, "Reading bridge register 0x%x containing 0x%x",
+	       address, *i2c_data);
+
+	/* usb_control_msg(...) returns the number of bytes sent upon success,
+	mask that and return zero upon success instead*/
+	return (err < 0) ? err : 0;
+}
+
+/* Writes a byte to to the m5602 */
+int m5602_write_bridge(struct sd *sd, u8 address, u8 i2c_data)
+{
+	int err;
+	struct usb_device *udev = sd->gspca_dev.dev;
+	__u8 *buf = sd->gspca_dev.usb_buf;
+
+	PDEBUG(DBG_TRACE, "Writing bridge register 0x%x with 0x%x",
+	       address, i2c_data);
+
+	memcpy(buf, bridge_urb_skeleton,
+	       sizeof(bridge_urb_skeleton));
+	buf[1] = address;
+	buf[3] = i2c_data;
+
+	err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+				0x04, 0x40, 0x19,
+				0x0000, buf,
+				4, M5602_URB_MSG_TIMEOUT);
+
+	/* usb_control_msg(...) returns the number of bytes sent upon success,
+	   mask that and return zero upon success instead */
+	return (err < 0) ? err : 0;
+}
+
+/* Dump all the registers of the m5602 bridge,
+   unfortunately this breaks the camera until it's power cycled */
+static void m5602_dump_bridge(struct sd *sd)
+{
+	int i;
+	for (i = 0; i < 0x80; i++) {
+		unsigned char val = 0;
+		m5602_read_bridge(sd, i, &val);
+		info("ALi m5602 address 0x%x contains 0x%x", i, val);
+	}
+	info("Warning: The camera probably won't work until it's power cycled");
+}
+
+static int m5602_probe_sensor(struct sd *sd)
+{
+	/* Try the po1030 */
+	sd->sensor = &po1030;
+	if (!sd->sensor->probe(sd))
+		return 0;
+
+	/* Try the mt9m111 sensor */
+	sd->sensor = &mt9m111;
+	if (!sd->sensor->probe(sd))
+		return 0;
+
+	/* Try the s5k4aa */
+	sd->sensor = &s5k4aa;
+	if (!sd->sensor->probe(sd))
+		return 0;
+
+	/* Try the ov9650 */
+	sd->sensor = &ov9650;
+	if (!sd->sensor->probe(sd))
+		return 0;
+
+	/* Try the s5k83a */
+	sd->sensor = &s5k83a;
+	if (!sd->sensor->probe(sd))
+		return 0;
+
+	/* More sensor probe function goes here */
+	info("Failed to find a sensor");
+	sd->sensor = NULL;
+	return -ENODEV;
+}
+
+static int m5602_configure(struct gspca_dev *gspca_dev,
+			   const struct usb_device_id *id);
+
+static int m5602_init(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	int err;
+
+	PDEBUG(DBG_TRACE, "Initializing ALi m5602 webcam");
+	/* Run the init sequence */
+	err = sd->sensor->init(sd);
+
+	return err;
+}
+
+static int m5602_start_transfer(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	__u8 *buf = sd->gspca_dev.usb_buf;
+
+	/* Send start command to the camera */
+	const u8 buffer[4] = {0x13, 0xf9, 0x0f, 0x01};
+	memcpy(buf, buffer, sizeof(buffer));
+	usb_control_msg(gspca_dev->dev, usb_sndctrlpipe(gspca_dev->dev, 0),
+			0x04, 0x40, 0x19, 0x0000, buf,
+			4, M5602_URB_MSG_TIMEOUT);
+
+	PDEBUG(DBG_V4L2, "Transfer started");
+	return 0;
+}
+
+static void m5602_urb_complete(struct gspca_dev *gspca_dev,
+			struct gspca_frame *frame,
+			__u8 *data, int len)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	if (len < 6) {
+		PDEBUG(DBG_DATA, "Packet is less than 6 bytes");
+		return;
+	}
+
+	/* Frame delimiter: ff xx xx xx ff ff */
+	if (data[0] == 0xff && data[4] == 0xff && data[5] == 0xff &&
+	    data[2] != sd->frame_id) {
+		PDEBUG(DBG_DATA, "Frame delimiter detected");
+		sd->frame_id = data[2];
+
+		/* Remove the extra fluff appended on each header */
+		data += 6;
+		len -= 6;
+
+		/* Complete the last frame (if any) */
+		frame = gspca_frame_add(gspca_dev, LAST_PACKET,
+					frame, data, 0);
+		sd->frame_count++;
+
+		/* Create a new frame */
+		gspca_frame_add(gspca_dev, FIRST_PACKET, frame, data, len);
+
+		PDEBUG(DBG_V4L2, "Starting new frame %d",
+		       sd->frame_count);
+
+	} else {
+		int cur_frame_len = frame->data_end - frame->data;
+
+		/* Remove urb header */
+		data += 4;
+		len -= 4;
+
+		if (cur_frame_len + len <= frame->v4l2_buf.length) {
+			PDEBUG(DBG_DATA, "Continuing frame %d copying %d bytes",
+			       sd->frame_count, len);
+
+			gspca_frame_add(gspca_dev, INTER_PACKET, frame,
+					data, len);
+		} else if (frame->v4l2_buf.length - cur_frame_len > 0) {
+			/* Add the remaining data up to frame size */
+			gspca_frame_add(gspca_dev, INTER_PACKET, frame, data,
+					frame->v4l2_buf.length - cur_frame_len);
+		}
+	}
+}
+
+static void m5602_stop_transfer(struct gspca_dev *gspca_dev)
+{
+	/* Is there are a command to stop a data transfer? */
+}
+
+/* sub-driver description, the ctrl and nctrl is filled at probe time */
+static struct sd_desc sd_desc = {
+	.name		= MODULE_NAME,
+	.config		= m5602_configure,
+	.init		= m5602_init,
+	.start		= m5602_start_transfer,
+	.stopN		= m5602_stop_transfer,
+	.pkt_scan	= m5602_urb_complete
+};
+
+/* this function is called at probe time */
+static int m5602_configure(struct gspca_dev *gspca_dev,
+			   const struct usb_device_id *id)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	struct cam *cam;
+	int err;
+
+	PDEBUG(DBG_GSPCA, "m5602_configure start");
+
+	cam = &gspca_dev->cam;
+	cam->epaddr = M5602_ISOC_ENDPOINT_ADDR;
+	sd->desc = &sd_desc;
+
+	if (dump_bridge)
+		m5602_dump_bridge(sd);
+
+	/* Probe sensor */
+	err = m5602_probe_sensor(sd);
+	if (err)
+		goto fail;
+
+	PDEBUG(DBG_GSPCA, "m5602_configure end");
+	return 0;
+
+fail:
+	PDEBUG(DBG_GSPCA, "m5602_configure failed");
+	cam->cam_mode = NULL;
+	cam->nmodes = 0;
+
+	return err;
+}
+
+static int m5602_probe(struct usb_interface *intf,
+		       const struct usb_device_id *id)
+{
+	return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
+			       THIS_MODULE);
+}
+
+static struct usb_driver sd_driver = {
+	.name = MODULE_NAME,
+	.id_table = m5602_table,
+	.probe = m5602_probe,
+#ifdef CONFIG_PM
+	.suspend = gspca_suspend,
+	.resume = gspca_resume,
+#endif
+	.disconnect = gspca_disconnect
+};
+
+/* -- module insert / remove -- */
+static int __init mod_m5602_init(void)
+{
+	if (usb_register(&sd_driver) < 0)
+		return -1;
+	PDEBUG(D_PROBE, "m5602 module registered");
+	return 0;
+}
+static void __exit mod_m5602_exit(void)
+{
+	usb_deregister(&sd_driver);
+	PDEBUG(D_PROBE, "m5602 module deregistered");
+}
+
+module_init(mod_m5602_init);
+module_exit(mod_m5602_exit);
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+module_param_named(debug, m5602_debug, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "toggles debug on/off");
+
+module_param(force_sensor, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(force_sensor,
+		"force detection of sensor, "
+		"1 = OV9650, 2 = S5K83A, 3 = S5K4AA, 4 = MT9M111, 5 = PO1030");
+
+module_param(dump_bridge, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(dump_bridge, "Dumps all usb bridge registers at startup");
+
+module_param(dump_sensor, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(dump_sensor, "Dumps all usb sensor registers "
+		"at startup providing a sensor is found");
diff --git a/drivers/media/video/gspca/m5602/m5602_mt9m111.c b/drivers/media/video/gspca/m5602/m5602_mt9m111.c
new file mode 100644
index 0000000..566d492
--- /dev/null
+++ b/drivers/media/video/gspca/m5602/m5602_mt9m111.c
@@ -0,0 +1,345 @@
+/*
+ * Driver for the mt9m111 sensor
+ *
+ * Copyright (C) 2008 Erik Andren
+ * Copyright (C) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project.
+ * Copyright (C) 2005 m5603x Linux Driver Project <m5602@x3ng.com.br>
+ *
+ * Portions of code to USB interface and ALi driver software,
+ * Copyright (c) 2006 Willem Duinker
+ * v4l2 interface modeled after the V4L2 driver
+ * for SN9C10x PC Camera Controllers
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2.
+ *
+ */
+
+#include "m5602_mt9m111.h"
+
+int mt9m111_probe(struct sd *sd)
+{
+	u8 data[2] = {0x00, 0x00};
+	int i;
+
+	if (force_sensor) {
+		if (force_sensor == MT9M111_SENSOR) {
+			info("Forcing a %s sensor", mt9m111.name);
+			goto sensor_found;
+		}
+		/* If we want to force another sensor, don't try to probe this
+		 * one */
+		return -ENODEV;
+	}
+
+	info("Probing for a mt9m111 sensor");
+
+	/* Do the preinit */
+	for (i = 0; i < ARRAY_SIZE(preinit_mt9m111); i++) {
+		if (preinit_mt9m111[i][0] == BRIDGE) {
+			m5602_write_bridge(sd,
+				preinit_mt9m111[i][1],
+				preinit_mt9m111[i][2]);
+		} else {
+			data[0] = preinit_mt9m111[i][2];
+			data[1] = preinit_mt9m111[i][3];
+			mt9m111_write_sensor(sd,
+				preinit_mt9m111[i][1], data, 2);
+		}
+	}
+
+	if (mt9m111_read_sensor(sd, MT9M111_SC_CHIPVER, data, 2))
+		return -ENODEV;
+
+	if ((data[0] == 0x14) && (data[1] == 0x3a)) {
+		info("Detected a mt9m111 sensor");
+		goto sensor_found;
+	}
+
+	return -ENODEV;
+
+sensor_found:
+	sd->gspca_dev.cam.cam_mode = mt9m111.modes;
+	sd->gspca_dev.cam.nmodes = mt9m111.nmodes;
+	sd->desc->ctrls = mt9m111.ctrls;
+	sd->desc->nctrls = mt9m111.nctrls;
+	return 0;
+}
+
+int mt9m111_init(struct sd *sd)
+{
+	int i, err = 0;
+
+	/* Init the sensor */
+	for (i = 0; i < ARRAY_SIZE(init_mt9m111); i++) {
+		u8 data[2];
+
+		if (init_mt9m111[i][0] == BRIDGE) {
+			err = m5602_write_bridge(sd,
+				init_mt9m111[i][1],
+				init_mt9m111[i][2]);
+		} else {
+			data[0] = init_mt9m111[i][2];
+			data[1] = init_mt9m111[i][3];
+			err = mt9m111_write_sensor(sd,
+				init_mt9m111[i][1], data, 2);
+		}
+	}
+
+	if (dump_sensor)
+		mt9m111_dump_registers(sd);
+
+	return (err < 0) ? err : 0;
+}
+
+int mt9m111_power_down(struct sd *sd)
+{
+	return 0;
+}
+
+int mt9m111_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	int err;
+	u8 data[2] = {0x00, 0x00};
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	err = mt9m111_read_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B,
+				  data, 2);
+	*val = data[0] & MT9M111_RMB_MIRROR_ROWS;
+	PDEBUG(DBG_V4L2_CID, "Read vertical flip %d", *val);
+
+	return (err < 0) ? err : 0;
+}
+
+int mt9m111_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
+{
+	int err;
+	u8 data[2] = {0x00, 0x00};
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	PDEBUG(DBG_V4L2_CID, "Set vertical flip to %d", val);
+
+	/* Set the correct page map */
+	err = mt9m111_write_sensor(sd, MT9M111_PAGE_MAP, data, 2);
+	if (err < 0)
+		goto out;
+
+	err = mt9m111_read_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B, data, 2);
+	if (err < 0)
+		goto out;
+
+	data[0] = (data[0] & 0xfe) | val;
+	err = mt9m111_write_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B,
+				   data, 2);
+out:
+	return (err < 0) ? err : 0;
+}
+
+int mt9m111_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	int err;
+	u8 data[2] = {0x00, 0x00};
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	err = mt9m111_read_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B,
+				  data, 2);
+	*val = data[0] & MT9M111_RMB_MIRROR_COLS;
+	PDEBUG(DBG_V4L2_CID, "Read horizontal flip %d", *val);
+
+	return (err < 0) ? err : 0;
+}
+
+int mt9m111_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
+{
+	int err;
+	u8 data[2] = {0x00, 0x00};
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	PDEBUG(DBG_V4L2_CID, "Set horizontal flip to %d", val);
+
+	/* Set the correct page map */
+	err = mt9m111_write_sensor(sd, MT9M111_PAGE_MAP, data, 2);
+	if (err < 0)
+		goto out;
+
+	err = mt9m111_read_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B, data, 2);
+	if (err < 0)
+		goto out;
+
+	data[0] = (data[0] & 0xfd) | ((val << 1) & 0x02);
+	err = mt9m111_write_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B,
+					data, 2);
+out:
+	return (err < 0) ? err : 0;
+}
+
+int mt9m111_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	int err, tmp;
+	u8 data[2] = {0x00, 0x00};
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	err = mt9m111_read_sensor(sd, MT9M111_SC_GLOBAL_GAIN, data, 2);
+	tmp = ((data[1] << 8) | data[0]);
+
+	*val = ((tmp & (1 << 10)) * 2) |
+	      ((tmp & (1 <<  9)) * 2) |
+	      ((tmp & (1 <<  8)) * 2) |
+	       (tmp & 0x7f);
+
+	PDEBUG(DBG_V4L2_CID, "Read gain %d", *val);
+
+	return (err < 0) ? err : 0;
+}
+
+int mt9m111_set_gain(struct gspca_dev *gspca_dev, __s32 val)
+{
+	int err, tmp;
+	u8 data[2] = {0x00, 0x00};
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	/* Set the correct page map */
+	err = mt9m111_write_sensor(sd, MT9M111_PAGE_MAP, data, 2);
+	if (err < 0)
+		goto out;
+
+	if (val >= INITIAL_MAX_GAIN * 2 * 2 * 2)
+		return -EINVAL;
+
+	if ((val >= INITIAL_MAX_GAIN * 2 * 2) &&
+	    (val < (INITIAL_MAX_GAIN - 1) * 2 * 2 * 2))
+		tmp = (1 << 10) | (val << 9) |
+				(val << 8) | (val / 8);
+	else if ((val >= INITIAL_MAX_GAIN * 2) &&
+		 (val <  INITIAL_MAX_GAIN * 2 * 2))
+		tmp = (1 << 9) | (1 << 8) | (val / 4);
+	else if ((val >= INITIAL_MAX_GAIN) &&
+		 (val < INITIAL_MAX_GAIN * 2))
+		tmp = (1 << 8) | (val / 2);
+	else
+		tmp = val;
+
+	data[1] = (tmp & 0xff00) >> 8;
+	data[0] = (tmp & 0xff);
+	PDEBUG(DBG_V4L2_CID, "tmp=%d, data[1]=%d, data[0]=%d", tmp,
+	       data[1], data[0]);
+
+	err = mt9m111_write_sensor(sd, MT9M111_SC_GLOBAL_GAIN,
+				   data, 2);
+out:
+	return (err < 0) ? err : 0;
+}
+
+int mt9m111_read_sensor(struct sd *sd, const u8 address,
+			u8 *i2c_data, const u8 len) {
+	int err, i;
+
+	do {
+		err = m5602_read_bridge(sd, M5602_XB_I2C_STATUS, i2c_data);
+	} while ((*i2c_data & I2C_BUSY) && !err);
+	if (err < 0)
+		goto out;
+
+	err = m5602_write_bridge(sd, M5602_XB_I2C_DEV_ADDR,
+				 sd->sensor->i2c_slave_id);
+	if (err < 0)
+		goto out;
+
+	err = m5602_write_bridge(sd, M5602_XB_I2C_REG_ADDR, address);
+	if (err < 0)
+		goto out;
+
+	err = m5602_write_bridge(sd, M5602_XB_I2C_CTRL, 0x1a);
+	if (err < 0)
+		goto out;
+
+	for (i = 0; i < len && !err; i++) {
+		err = m5602_read_bridge(sd, M5602_XB_I2C_DATA, &(i2c_data[i]));
+
+		PDEBUG(DBG_TRACE, "Reading sensor register "
+		       "0x%x contains 0x%x ", address, *i2c_data);
+	}
+out:
+	return (err < 0) ? err : 0;
+}
+
+int mt9m111_write_sensor(struct sd *sd, const u8 address,
+				u8 *i2c_data, const u8 len)
+{
+	int err, i;
+	u8 *p;
+	struct usb_device *udev = sd->gspca_dev.dev;
+	__u8 *buf = sd->gspca_dev.usb_buf;
+
+	/* No sensor with a data width larger
+	   than 16 bits has yet been seen, nor with 0 :p*/
+	if (len > 2 || !len)
+		return -EINVAL;
+
+	memcpy(buf, sensor_urb_skeleton,
+	       sizeof(sensor_urb_skeleton));
+
+	buf[11] = sd->sensor->i2c_slave_id;
+	buf[15] = address;
+
+	p = buf + 16;
+
+	/* Copy a four byte write sequence for each byte to be written to */
+	for (i = 0; i < len; i++) {
+		memcpy(p, sensor_urb_skeleton + 16, 4);
+		p[3] = i2c_data[i];
+		p += 4;
+		PDEBUG(DBG_TRACE, "Writing sensor register 0x%x with 0x%x",
+		       address, i2c_data[i]);
+	}
+
+	/* Copy the tailer */
+	memcpy(p, sensor_urb_skeleton + 20, 4);
+
+	/* Set the total length */
+	p[3] = 0x10 + len;
+
+	err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+			      0x04, 0x40, 0x19,
+			      0x0000, buf,
+			      20 + len * 4, M5602_URB_MSG_TIMEOUT);
+
+	return (err < 0) ? err : 0;
+}
+
+void mt9m111_dump_registers(struct sd *sd)
+{
+	u8 address, value[2] = {0x00, 0x00};
+
+	info("Dumping the mt9m111 register state");
+
+	info("Dumping the mt9m111 sensor core registers");
+	value[1] = MT9M111_SENSOR_CORE;
+	mt9m111_write_sensor(sd, MT9M111_PAGE_MAP, value, 2);
+	for (address = 0; address < 0xff; address++) {
+		mt9m111_read_sensor(sd, address, value, 2);
+		info("register 0x%x contains 0x%x%x",
+		     address, value[0], value[1]);
+	}
+
+	info("Dumping the mt9m111 color pipeline registers");
+	value[1] = MT9M111_COLORPIPE;
+	mt9m111_write_sensor(sd, MT9M111_PAGE_MAP, value, 2);
+	for (address = 0; address < 0xff; address++) {
+		mt9m111_read_sensor(sd, address, value, 2);
+		info("register 0x%x contains 0x%x%x",
+		     address, value[0], value[1]);
+	}
+
+	info("Dumping the mt9m111 camera control registers");
+	value[1] = MT9M111_CAMERA_CONTROL;
+	mt9m111_write_sensor(sd, MT9M111_PAGE_MAP, value, 2);
+	for (address = 0; address < 0xff; address++) {
+		mt9m111_read_sensor(sd, address, value, 2);
+		info("register 0x%x contains 0x%x%x",
+		     address, value[0], value[1]);
+	}
+
+	info("mt9m111 register state dump complete");
+}
diff --git a/drivers/media/video/gspca/m5602/m5602_mt9m111.h b/drivers/media/video/gspca/m5602/m5602_mt9m111.h
new file mode 100644
index 0000000..79a5d88
--- /dev/null
+++ b/drivers/media/video/gspca/m5602/m5602_mt9m111.h
@@ -0,0 +1,1020 @@
+/*
+ * Driver for the mt9m111 sensor
+ *
+ * Copyright (C) 2008 Erik Andren
+ * Copyright (C) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project.
+ * Copyright (C) 2005 m5603x Linux Driver Project <m5602@x3ng.com.br>
+ *
+ * Portions of code to USB interface and ALi driver software,
+ * Copyright (c) 2006 Willem Duinker
+ * v4l2 interface modeled after the V4L2 driver
+ * for SN9C10x PC Camera Controllers
+ *
+ * Some defines taken from the mt9m111 sensor driver
+ * Copyright (C) 2008, Robert Jarzmik <robert.jarzmik@free.fr>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2.
+ *
+ */
+
+#ifndef M5602_MT9M111_H_
+#define M5602_MT9M111_H_
+
+#include "m5602_sensor.h"
+
+/*****************************************************************************/
+
+#define MT9M111_SC_CHIPVER			0x00
+#define MT9M111_SC_ROWSTART			0x01
+#define MT9M111_SC_COLSTART			0x02
+#define MT9M111_SC_WINDOW_HEIGHT		0x03
+#define MT9M111_SC_WINDOW_WIDTH			0x04
+#define MT9M111_SC_HBLANK_CONTEXT_B		0x05
+#define MT9M111_SC_VBLANK_CONTEXT_B		0x06
+#define MT9M111_SC_HBLANK_CONTEXT_A		0x07
+#define MT9M111_SC_VBLANK_CONTEXT_A		0x08
+#define MT9M111_SC_SHUTTER_WIDTH		0x09
+#define MT9M111_SC_ROW_SPEED			0x0a
+
+#define MT9M111_SC_EXTRA_DELAY			0x0b
+#define MT9M111_SC_SHUTTER_DELAY		0x0c
+#define MT9M111_SC_RESET			0x0d
+#define MT9M111_SC_R_MODE_CONTEXT_B		0x20
+#define MT9M111_SC_R_MODE_CONTEXT_A		0x21
+#define MT9M111_SC_FLASH_CONTROL		0x23
+#define MT9M111_SC_GREEN_1_GAIN			0x2b
+#define MT9M111_SC_BLUE_GAIN			0x2c
+#define MT9M111_SC_RED_GAIN			0x2d
+#define MT9M111_SC_GREEN_2_GAIN			0x2e
+#define MT9M111_SC_GLOBAL_GAIN			0x2f
+
+#define MT9M111_RMB_MIRROR_ROWS			(1 << 0)
+#define MT9M111_RMB_MIRROR_COLS			(1 << 1)
+
+#define MT9M111_CONTEXT_CONTROL			0xc8
+#define MT9M111_PAGE_MAP			0xf0
+#define MT9M111_BYTEWISE_ADDRESS		0xf1
+
+#define MT9M111_CP_OPERATING_MODE_CTL		0x06
+#define MT9M111_CP_LUMA_OFFSET			0x34
+#define MT9M111_CP_LUMA_CLIP			0x35
+#define MT9M111_CP_OUTPUT_FORMAT_CTL2_CONTEXT_A 0x3a
+#define MT9M111_CP_LENS_CORRECTION_1		0x3b
+#define MT9M111_CP_DEFECT_CORR_CONTEXT_A	0x4c
+#define MT9M111_CP_DEFECT_CORR_CONTEXT_B	0x4d
+#define MT9M111_CP_OUTPUT_FORMAT_CTL2_CONTEXT_B 0x9b
+#define MT9M111_CP_GLOBAL_CLK_CONTROL		0xb3
+
+#define MT9M111_CC_AUTO_EXPOSURE_PARAMETER_18   0x65
+#define MT9M111_CC_AWB_PARAMETER_7		0x28
+
+#define MT9M111_SENSOR_CORE			0x00
+#define MT9M111_COLORPIPE			0x01
+#define MT9M111_CAMERA_CONTROL			0x02
+
+#define INITIAL_MAX_GAIN			64
+#define DEFAULT_GAIN 				283
+
+/*****************************************************************************/
+
+/* Kernel module parameters */
+extern int force_sensor;
+extern int dump_sensor;
+extern unsigned int m5602_debug;
+
+int mt9m111_probe(struct sd *sd);
+int mt9m111_init(struct sd *sd);
+int mt9m111_power_down(struct sd *sd);
+
+int mt9m111_read_sensor(struct sd *sd, const u8 address,
+			u8 *i2c_data, const u8 len);
+
+int mt9m111_write_sensor(struct sd *sd, const u8 address,
+			 u8 *i2c_data, const u8 len);
+
+void mt9m111_dump_registers(struct sd *sd);
+
+int mt9m111_set_vflip(struct gspca_dev *gspca_dev, __s32 val);
+int mt9m111_get_vflip(struct gspca_dev *gspca_dev, __s32 *val);
+int mt9m111_get_hflip(struct gspca_dev *gspca_dev, __s32 *val);
+int mt9m111_set_hflip(struct gspca_dev *gspca_dev, __s32 val);
+int mt9m111_get_gain(struct gspca_dev *gspca_dev, __s32 *val);
+int mt9m111_set_gain(struct gspca_dev *gspca_dev, __s32 val);
+
+static struct m5602_sensor mt9m111 = {
+	.name = "MT9M111",
+
+	.i2c_slave_id = 0xba,
+
+	.probe = mt9m111_probe,
+	.init = mt9m111_init,
+	.power_down = mt9m111_power_down,
+
+	.read_sensor = mt9m111_read_sensor,
+	.write_sensor = mt9m111_write_sensor,
+
+	.nctrls = 3,
+	.ctrls = {
+	{
+		{
+			.id		= V4L2_CID_VFLIP,
+			.type           = V4L2_CTRL_TYPE_BOOLEAN,
+			.name           = "vertical flip",
+			.minimum        = 0,
+			.maximum        = 1,
+			.step           = 1,
+			.default_value  = 0
+		},
+		.set = mt9m111_set_vflip,
+		.get = mt9m111_get_vflip
+	}, {
+		{
+			.id             = V4L2_CID_HFLIP,
+			.type           = V4L2_CTRL_TYPE_BOOLEAN,
+			.name           = "horizontal flip",
+			.minimum        = 0,
+			.maximum        = 1,
+			.step           = 1,
+			.default_value  = 0
+		},
+		.set = mt9m111_set_hflip,
+		.get = mt9m111_get_hflip
+	}, {
+		{
+			.id             = V4L2_CID_GAIN,
+			.type           = V4L2_CTRL_TYPE_INTEGER,
+			.name           = "gain",
+			.minimum        = 0,
+			.maximum        = (INITIAL_MAX_GAIN - 1) * 2 * 2 * 2,
+			.step           = 1,
+			.default_value  = DEFAULT_GAIN,
+			.flags          = V4L2_CTRL_FLAG_SLIDER
+		},
+		.set = mt9m111_set_hflip,
+		.get = mt9m111_get_hflip
+	}
+	},
+
+	.nmodes = 1,
+	.modes = {
+	{
+		M5602_DEFAULT_FRAME_WIDTH,
+		M5602_DEFAULT_FRAME_HEIGHT,
+		V4L2_PIX_FMT_SBGGR8,
+		V4L2_FIELD_NONE,
+		.sizeimage =
+			M5602_DEFAULT_FRAME_WIDTH * M5602_DEFAULT_FRAME_HEIGHT,
+		.bytesperline = M5602_DEFAULT_FRAME_WIDTH,
+		.colorspace = V4L2_COLORSPACE_SRGB,
+		.priv = 1
+	}
+	}
+};
+
+static const unsigned char preinit_mt9m111[][4] =
+{
+	{BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02, 0x00},
+	{BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0, 0x00},
+	{BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
+	{BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
+	{BRIDGE, M5602_XB_SENSOR_TYPE, 0x0d, 0x00},
+	{BRIDGE, M5602_XB_SENSOR_CTRL, 0x00, 0x00},
+	{BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
+	{BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00},
+
+	{SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
+	{SENSOR, MT9M111_SC_RESET, 0xff, 0xf7},
+
+	{BRIDGE, M5602_XB_GPIO_DIR, 0x05, 0x00},
+	{BRIDGE, M5602_XB_GPIO_DAT, 0x04, 0x00},
+	{BRIDGE, M5602_XB_GPIO_EN_H, 0x3e, 0x00},
+	{BRIDGE, M5602_XB_GPIO_DIR_H, 0x3e, 0x00},
+	{BRIDGE, M5602_XB_GPIO_DAT_H, 0x02, 0x00},
+	{BRIDGE, M5602_XB_GPIO_EN_L, 0xff, 0x00},
+	{BRIDGE, M5602_XB_GPIO_DIR_L, 0xff, 0x00},
+	{BRIDGE, M5602_XB_GPIO_DAT_L, 0x00, 0x00},
+
+	{BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
+	{BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
+	{BRIDGE, M5602_XB_GPIO_DIR, 0x07, 0x00},
+	{BRIDGE, M5602_XB_GPIO_DAT, 0x0b, 0x00},
+	{BRIDGE, M5602_XB_GPIO_EN_H, 0x06, 0x00},
+	{BRIDGE, M5602_XB_GPIO_EN_L, 0x00, 0x00},
+
+	{BRIDGE, M5602_XB_I2C_CLK_DIV, 0x0a, 0x00}
+};
+
+static const unsigned char init_mt9m111[][4] =
+{
+	{BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02, 0x00},
+	{BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0, 0x00},
+	{BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
+	{BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
+	{BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
+	{BRIDGE, M5602_XB_SENSOR_TYPE, 0x0d, 0x00},
+	{BRIDGE, M5602_XB_SENSOR_CTRL, 0x00, 0x00},
+	{BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
+	{BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00},
+	{BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
+	{BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
+
+	{SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
+	{SENSOR, MT9M111_SC_RESET, 0xff, 0xff},
+	{SENSOR, MT9M111_SC_RESET, 0xff, 0xff},
+	{SENSOR, MT9M111_SC_RESET, 0xff, 0xde},
+	{SENSOR, MT9M111_SC_RESET, 0xff, 0xff},
+	{SENSOR, MT9M111_SC_RESET, 0xff, 0xf7},
+	{SENSOR, MT9M111_PAGE_MAP, 0x00, 0x01},
+
+	{BRIDGE, M5602_XB_I2C_REG_ADDR, 0xb3, 0x00},
+
+	{SENSOR, MT9M111_CP_GLOBAL_CLK_CONTROL, 0xff, 0xff},
+
+	{BRIDGE, M5602_XB_GPIO_DIR, 0x05, 0x00},
+	{BRIDGE, M5602_XB_GPIO_DAT, 0x04, 0x00},
+	{BRIDGE, M5602_XB_GPIO_EN_H, 0x3e, 0x00},
+	{BRIDGE, M5602_XB_GPIO_DIR_H, 0x3e, 0x00},
+	{BRIDGE, M5602_XB_GPIO_DAT_H, 0x02, 0x00},
+	{BRIDGE, M5602_XB_GPIO_EN_L, 0xff, 0x00},
+	{BRIDGE, M5602_XB_GPIO_DIR_L, 0xff, 0x00},
+	{BRIDGE, M5602_XB_GPIO_DAT_L, 0x00, 0x00},
+	{BRIDGE, M5602_XB_SEN_CLK_DIV, 0x04, 0x00},
+	{BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
+	{BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
+	{BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
+	{BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
+	{BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00},
+	{BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
+	{BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
+	{BRIDGE, M5602_XB_GPIO_DIR, 0x07, 0x00},
+	{BRIDGE, M5602_XB_GPIO_DAT, 0x0b, 0x00},
+	{BRIDGE, M5602_XB_GPIO_EN_H, 0x06, 0x00},
+	{BRIDGE, M5602_XB_GPIO_EN_L, 0x00, 0x00},
+	{BRIDGE, M5602_XB_I2C_CLK_DIV, 0x0a, 0x00},
+
+	{SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
+	{SENSOR, MT9M111_SC_RESET, 0x00, 0x05},
+	{SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
+	{SENSOR, MT9M111_SC_RESET, 0x00, 0x29},
+	{SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
+	{SENSOR, MT9M111_SC_RESET, 0x00, 0x08},
+	{SENSOR, MT9M111_PAGE_MAP, 0x00, 0x01},
+	{SENSOR, MT9M111_CP_OPERATING_MODE_CTL, 0x00, 0x10},
+	{SENSOR, MT9M111_CP_LENS_CORRECTION_1, 0x04, 0x2a},
+	{SENSOR, MT9M111_CP_DEFECT_CORR_CONTEXT_A, 0x00, 0x01},
+	{SENSOR, MT9M111_CP_DEFECT_CORR_CONTEXT_B, 0x00, 0x01},
+	{SENSOR, MT9M111_CP_LUMA_OFFSET, 0x00, 0x00},
+	{SENSOR, MT9M111_CP_LUMA_CLIP, 0xff, 0x00},
+	{SENSOR, MT9M111_CP_OUTPUT_FORMAT_CTL2_CONTEXT_A, 0x14, 0x00},
+	{SENSOR, MT9M111_CP_OUTPUT_FORMAT_CTL2_CONTEXT_B, 0x14, 0x00},
+	{BRIDGE, M5602_XB_I2C_REG_ADDR, 0xcd, 0x00},
+
+	{SENSOR, 0xcd, 0x00, 0x0e},
+	{BRIDGE, M5602_XB_I2C_REG_ADDR, 0xd0, 0x00},
+	{SENSOR, 0xd0, 0x00, 0x40},
+	{SENSOR, MT9M111_PAGE_MAP, 0x00, 0x02},
+	{SENSOR, MT9M111_CC_AUTO_EXPOSURE_PARAMETER_18, 0x00, 0x00},
+	{BRIDGE, M5602_XB_I2C_REG_ADDR, 0x28, 0x00},
+	{SENSOR, MT9M111_CC_AWB_PARAMETER_7, 0xef, 0x07},
+	{BRIDGE, M5602_XB_I2C_REG_ADDR, 0x28, 0x00},
+	{SENSOR, MT9M111_CC_AWB_PARAMETER_7, 0xef, 0x03},
+	{SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
+	{BRIDGE, M5602_XB_I2C_REG_ADDR, 0x33, 0x00},
+	{SENSOR, 0x33, 0x03, 0x49},
+	{BRIDGE, M5602_XB_I2C_REG_ADDR, 0x33, 0x00},
+
+	{SENSOR, 0x33, 0x03, 0x49},
+	{SENSOR, 0x34, 0xc0, 0x19},
+	{SENSOR, 0x3f, 0x20, 0x20},
+	{SENSOR, 0x40, 0x20, 0x20},
+	{SENSOR, 0x5a, 0xc0, 0x0a},
+	{SENSOR, 0x70, 0x7b, 0x0a},
+	{SENSOR, 0x71, 0xff, 0x00},
+	{SENSOR, 0x72, 0x19, 0x0e},
+	{SENSOR, 0x73, 0x18, 0x0f},
+	{SENSOR, 0x74, 0x57, 0x32},
+	{SENSOR, 0x75, 0x56, 0x34},
+	{SENSOR, 0x76, 0x73, 0x35},
+	{SENSOR, 0x77, 0x30, 0x12},
+	{SENSOR, 0x78, 0x79, 0x02},
+	{SENSOR, 0x79, 0x75, 0x06},
+	{SENSOR, 0x7a, 0x77, 0x0a},
+	{SENSOR, 0x7b, 0x78, 0x09},
+	{SENSOR, 0x7c, 0x7d, 0x06},
+	{SENSOR, 0x7d, 0x31, 0x10},
+	{SENSOR, 0x7e, 0x00, 0x7e},
+	{SENSOR, 0x80, 0x59, 0x04},
+	{SENSOR, 0x81, 0x59, 0x04},
+	{SENSOR, 0x82, 0x57, 0x0a},
+	{SENSOR, 0x83, 0x58, 0x0b},
+	{SENSOR, 0x84, 0x47, 0x0c},
+	{SENSOR, 0x85, 0x48, 0x0e},
+	{SENSOR, 0x86, 0x5b, 0x02},
+	{SENSOR, 0x87, 0x00, 0x5c},
+	{SENSOR, MT9M111_CONTEXT_CONTROL, 0x00, 0x08},
+	{SENSOR, 0x60, 0x00, 0x80},
+	{SENSOR, 0x61, 0x00, 0x00},
+	{SENSOR, 0x62, 0x00, 0x00},
+	{SENSOR, 0x63, 0x00, 0x00},
+	{SENSOR, 0x64, 0x00, 0x00},
+
+	{SENSOR, MT9M111_SC_ROWSTART, 0x00, 0x0d},
+	{SENSOR, MT9M111_SC_COLSTART, 0x00, 0x18},
+	{SENSOR, MT9M111_SC_WINDOW_HEIGHT, 0x04, 0x04},
+	{SENSOR, MT9M111_SC_WINDOW_WIDTH, 0x05, 0x08},
+	{SENSOR, MT9M111_SC_HBLANK_CONTEXT_B, 0x01, 0x38},
+	{SENSOR, MT9M111_SC_VBLANK_CONTEXT_B, 0x00, 0x11},
+	{SENSOR, MT9M111_SC_HBLANK_CONTEXT_A, 0x01, 0x38},
+	{SENSOR, MT9M111_SC_VBLANK_CONTEXT_A, 0x00, 0x11},
+	{SENSOR, MT9M111_SC_R_MODE_CONTEXT_B, 0x01, 0x03},
+	{SENSOR, MT9M111_SC_R_MODE_CONTEXT_A, 0x01, 0x03},
+	{SENSOR, 0x30, 0x04, 0x00},
+
+	{BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06, 0x00},
+	{BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
+	{BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
+	{BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00},
+	{BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x81, 0x00},
+	{BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82, 0x00},
+	{BRIDGE, M5602_XB_SIG_INI, 0x01, 0x00},
+	{BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+	{BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+	{BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+	{BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+	{BRIDGE, M5602_XB_VSYNC_PARA, 0x04, 0x00},
+	{BRIDGE, M5602_XB_VSYNC_PARA, 0x04, 0x00},
+	{BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+	{BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+	{BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
+	{BRIDGE, M5602_XB_SIG_INI, 0x02, 0x00},
+	{BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00},
+	{BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00},
+	{BRIDGE, M5602_XB_HSYNC_PARA, 0x05, 0x00},
+	{BRIDGE, M5602_XB_HSYNC_PARA, 0x07, 0x00},
+	{BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
+	{BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
+	{BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xa0, 0x00},
+	{SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
+	{SENSOR, MT9M111_SC_SHUTTER_WIDTH, 0x01, 0xf4},
+	{SENSOR, MT9M111_SC_GLOBAL_GAIN, 0x00, 0xea},
+
+	{BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06, 0x00},
+	{BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
+	{BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
+	{BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00},
+	{BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x81, 0x00},
+	{BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82, 0x00},
+	{BRIDGE, M5602_XB_SIG_INI, 0x01, 0x00},
+	{BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+	{BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+	{BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+	{BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+	{BRIDGE, M5602_XB_VSYNC_PARA, 0x04, 0x00},
+	{BRIDGE, M5602_XB_VSYNC_PARA, 0x04, 0x00},
+	{BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+	{BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+	{BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
+	{BRIDGE, M5602_XB_SIG_INI, 0x02, 0x00},
+	{BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00},
+	{BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00},
+	{BRIDGE, M5602_XB_HSYNC_PARA, 0x05, 0x00},
+	{BRIDGE, M5602_XB_HSYNC_PARA, 0x07, 0x00},
+	{BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
+	{BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
+	{BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
+
+	{SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
+	{SENSOR, MT9M111_SC_RESET, 0x00, 0x09},
+	{SENSOR, MT9M111_SC_RESET, 0x00, 0x29},
+	{SENSOR, MT9M111_SC_RESET, 0x00, 0x08},
+	{SENSOR, MT9M111_SC_RESET, 0x00, 0x0c},
+	{SENSOR, MT9M111_SC_RESET, 0x00, 0x04},
+	{SENSOR, MT9M111_PAGE_MAP, 0x00, 0x01},
+	{BRIDGE, M5602_XB_I2C_REG_ADDR, 0xb3, 0x00},
+	{SENSOR, MT9M111_CP_GLOBAL_CLK_CONTROL, 0x00, 0x03},
+	{BRIDGE, M5602_XB_GPIO_DIR, 0x05, 0x00},
+	{BRIDGE, M5602_XB_GPIO_DAT, 0x04, 0x00},
+	{BRIDGE, M5602_XB_GPIO_EN_H, 0x3e, 0x00},
+	{BRIDGE, M5602_XB_GPIO_DIR_H, 0x3e, 0x00},
+	{BRIDGE, M5602_XB_GPIO_DAT_H, 0x02, 0x00},
+	{BRIDGE, M5602_XB_GPIO_EN_L, 0xff, 0x00},
+	{BRIDGE, M5602_XB_GPIO_DIR_L, 0xff, 0x00},
+	{BRIDGE, M5602_XB_GPIO_DAT_L, 0x00, 0x00},
+	{BRIDGE, M5602_XB_SEN_CLK_DIV, 0x04, 0x00},
+	{BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
+	{BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
+	{BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
+	{BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
+	{BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00},
+	{BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
+	{BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
+	{BRIDGE, M5602_XB_GPIO_DIR, 0x07, 0x00},
+	{BRIDGE, M5602_XB_GPIO_DAT, 0x0b, 0x00},
+	{BRIDGE, M5602_XB_GPIO_EN_H, 0x06, 0x00},
+	{BRIDGE, M5602_XB_GPIO_EN_L, 0x00, 0x00},
+	{BRIDGE, M5602_XB_I2C_CLK_DIV, 0x0a, 0x00},
+
+	{SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
+	{SENSOR, MT9M111_SC_RESET, 0x00, 0x05},
+	{SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
+	{SENSOR, MT9M111_SC_RESET, 0x00, 0x29},
+	{SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
+	{SENSOR, MT9M111_SC_RESET, 0x00, 0x08},
+	{SENSOR, MT9M111_PAGE_MAP, 0x00, 0x01},
+	{SENSOR, MT9M111_CP_OPERATING_MODE_CTL, 0x00, 0x10},
+	{SENSOR, MT9M111_CP_LENS_CORRECTION_1, 0x04, 0x2a},
+	{SENSOR, MT9M111_CP_DEFECT_CORR_CONTEXT_A, 0x00, 0x01},
+	{SENSOR, MT9M111_CP_DEFECT_CORR_CONTEXT_B, 0x00, 0x01},
+	{SENSOR, MT9M111_CP_LUMA_OFFSET, 0x00, 0x00},
+	{SENSOR, MT9M111_CP_LUMA_CLIP, 0xff, 0x00},
+	{SENSOR, MT9M111_CP_OUTPUT_FORMAT_CTL2_CONTEXT_A, 0x14, 0x00},
+	{SENSOR, MT9M111_CP_OUTPUT_FORMAT_CTL2_CONTEXT_B, 0x14, 0x00},
+
+	{BRIDGE, M5602_XB_I2C_REG_ADDR, 0xcd, 0x00},
+	{SENSOR, 0xcd, 0x00, 0x0e},
+	{BRIDGE, M5602_XB_I2C_REG_ADDR, 0xd0, 0x00},
+	{SENSOR, 0xd0, 0x00, 0x40},
+	{SENSOR, MT9M111_PAGE_MAP, 0x00, 0x02},
+	{SENSOR, MT9M111_CC_AUTO_EXPOSURE_PARAMETER_18, 0x00, 0x00},
+	{BRIDGE, M5602_XB_I2C_REG_ADDR, 0x28, 0x00},
+	{SENSOR, MT9M111_CC_AWB_PARAMETER_7, 0xef, 0x07},
+	{BRIDGE, M5602_XB_I2C_REG_ADDR, 0x28, 0x00},
+	{SENSOR, MT9M111_CC_AWB_PARAMETER_7, 0xef, 0x03},
+	{SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
+	{BRIDGE, M5602_XB_I2C_REG_ADDR, 0x33, 0x00},
+	{SENSOR, 0x33, 0x03, 0x49},
+	{BRIDGE, M5602_XB_I2C_REG_ADDR, 0x33, 0x00},
+
+	{SENSOR, 0x33, 0x03, 0x49},
+	{SENSOR, 0x34, 0xc0, 0x19},
+	{SENSOR, 0x3f, 0x20, 0x20},
+	{SENSOR, 0x40, 0x20, 0x20},
+	{SENSOR, 0x5a, 0xc0, 0x0a},
+	{SENSOR, 0x70, 0x7b, 0x0a},
+	{SENSOR, 0x71, 0xff, 0x00},
+	{SENSOR, 0x72, 0x19, 0x0e},
+	{SENSOR, 0x73, 0x18, 0x0f},
+	{SENSOR, 0x74, 0x57, 0x32},
+	{SENSOR, 0x75, 0x56, 0x34},
+	{SENSOR, 0x76, 0x73, 0x35},
+	{SENSOR, 0x77, 0x30, 0x12},
+	{SENSOR, 0x78, 0x79, 0x02},
+	{SENSOR, 0x79, 0x75, 0x06},
+	{SENSOR, 0x7a, 0x77, 0x0a},
+	{SENSOR, 0x7b, 0x78, 0x09},
+	{SENSOR, 0x7c, 0x7d, 0x06},
+	{SENSOR, 0x7d, 0x31, 0x10},
+	{SENSOR, 0x7e, 0x00, 0x7e},
+	{SENSOR, 0x80, 0x59, 0x04},
+	{SENSOR, 0x81, 0x59, 0x04},
+	{SENSOR, 0x82, 0x57, 0x0a},
+	{SENSOR, 0x83, 0x58, 0x0b},
+	{SENSOR, 0x84, 0x47, 0x0c},
+	{SENSOR, 0x85, 0x48, 0x0e},
+	{SENSOR, 0x86, 0x5b, 0x02},
+	{SENSOR, 0x87, 0x00, 0x5c},
+	{SENSOR, MT9M111_CONTEXT_CONTROL, 0x00, 0x08},
+	{SENSOR, 0x60, 0x00, 0x80},
+	{SENSOR, 0x61, 0x00, 0x00},
+	{SENSOR, 0x62, 0x00, 0x00},
+	{SENSOR, 0x63, 0x00, 0x00},
+	{SENSOR, 0x64, 0x00, 0x00},
+
+	{SENSOR, MT9M111_SC_ROWSTART, 0x00, 0x0d},
+	{SENSOR, MT9M111_SC_COLSTART, 0x00, 0x18},
+	{SENSOR, MT9M111_SC_WINDOW_HEIGHT, 0x04, 0x04},
+	{SENSOR, MT9M111_SC_WINDOW_WIDTH, 0x05, 0x08},
+	{SENSOR, MT9M111_SC_HBLANK_CONTEXT_B, 0x01, 0x38},
+	{SENSOR, MT9M111_SC_VBLANK_CONTEXT_B, 0x00, 0x11},
+	{SENSOR, MT9M111_SC_HBLANK_CONTEXT_A, 0x01, 0x38},
+	{SENSOR, MT9M111_SC_VBLANK_CONTEXT_A, 0x00, 0x11},
+	{SENSOR, MT9M111_SC_R_MODE_CONTEXT_B, 0x01, 0x03},
+	{SENSOR, MT9M111_SC_R_MODE_CONTEXT_A, 0x01, 0x03},
+	{SENSOR, 0x30, 0x04, 0x00},
+
+	{BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06, 0x00},
+	{BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
+	{BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
+	{BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00},
+	{BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x81, 0x00},
+	{BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82, 0x00},
+	{BRIDGE, M5602_XB_SIG_INI, 0x01, 0x00},
+	{BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+	{BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+	{BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+	{BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+	{BRIDGE, M5602_XB_VSYNC_PARA, 0x04, 0x00},
+	{BRIDGE, M5602_XB_VSYNC_PARA, 0x04, 0x00},
+	{BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+	{BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+	{BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
+	{BRIDGE, M5602_XB_SIG_INI, 0x02, 0x00},
+	{BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00},
+	{BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00},
+	{BRIDGE, M5602_XB_HSYNC_PARA, 0x05, 0x00},
+	{BRIDGE, M5602_XB_HSYNC_PARA, 0x07, 0x00},
+	{BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
+	{BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
+	{BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xa0, 0x00},
+	{SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
+	{SENSOR, MT9M111_SC_SHUTTER_WIDTH, 0x01, 0xf4},
+	{SENSOR, MT9M111_SC_GLOBAL_GAIN, 0x00, 0xea},
+	{BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
+	{BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
+
+	{SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
+	{SENSOR, MT9M111_SC_RESET, 0x00, 0x09},
+	{SENSOR, MT9M111_SC_RESET, 0x00, 0x29},
+	{SENSOR, MT9M111_SC_RESET, 0x00, 0x08},
+	{SENSOR, MT9M111_SC_RESET, 0x00, 0x0c},
+	{SENSOR, MT9M111_SC_RESET, 0x00, 0x04},
+	{SENSOR, MT9M111_PAGE_MAP, 0x00, 0x01},
+
+	{BRIDGE, M5602_XB_I2C_REG_ADDR, 0xb3, 0x00},
+	{SENSOR, MT9M111_CP_GLOBAL_CLK_CONTROL, 0x00, 0x03},
+	{BRIDGE, M5602_XB_GPIO_DIR, 0x05, 0x00},
+	{BRIDGE, M5602_XB_GPIO_DAT, 0x04, 0x00},
+	{BRIDGE, M5602_XB_GPIO_EN_H, 0x3e, 0x00},
+	{BRIDGE, M5602_XB_GPIO_DIR_H, 0x3e, 0x00},
+	{BRIDGE, M5602_XB_GPIO_DAT_H, 0x02, 0x00},
+	{BRIDGE, M5602_XB_GPIO_EN_L, 0xff, 0x00},
+	{BRIDGE, M5602_XB_GPIO_DIR_L, 0xff, 0x00},
+	{BRIDGE, M5602_XB_GPIO_DAT_L, 0x00, 0x00},
+	{BRIDGE, M5602_XB_SEN_CLK_DIV, 0x04, 0x00},
+	{BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
+	{BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
+	{BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
+	{BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
+	{BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00},
+	{BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
+	{BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
+	{BRIDGE, M5602_XB_GPIO_DIR, 0x07, 0x00},
+	{BRIDGE, M5602_XB_GPIO_DAT, 0x0b, 0x00},
+	{BRIDGE, M5602_XB_GPIO_EN_H, 0x06, 0x00},
+	{BRIDGE, M5602_XB_GPIO_EN_L, 0x00, 0x00},
+	{BRIDGE, M5602_XB_I2C_CLK_DIV, 0x0a, 0x00},
+
+	{SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
+	{SENSOR, MT9M111_SC_RESET, 0x00, 0x05},
+	{SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
+	{SENSOR, MT9M111_SC_RESET, 0x00, 0x29},
+	{SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
+	{SENSOR, MT9M111_SC_RESET, 0x00, 0x08},
+	{SENSOR, MT9M111_PAGE_MAP, 0x00, 0x01},
+	{SENSOR, MT9M111_CP_OPERATING_MODE_CTL, 0x00, 0x10},
+	{SENSOR, MT9M111_CP_LENS_CORRECTION_1, 0x04, 0x2a},
+	{SENSOR, MT9M111_CP_DEFECT_CORR_CONTEXT_A, 0x00, 0x01},
+	{SENSOR, MT9M111_CP_DEFECT_CORR_CONTEXT_B, 0x00, 0x01},
+	{SENSOR, MT9M111_CP_LUMA_OFFSET, 0x00, 0x00},
+	{SENSOR, MT9M111_CP_LUMA_CLIP, 0xff, 0x00},
+	{SENSOR, MT9M111_CP_OUTPUT_FORMAT_CTL2_CONTEXT_A, 0x14, 0x00},
+	{SENSOR, MT9M111_CP_OUTPUT_FORMAT_CTL2_CONTEXT_B, 0x14, 0x00},
+
+	{BRIDGE, M5602_XB_I2C_REG_ADDR, 0xcd, 0x00},
+	{SENSOR, 0xcd, 0x00, 0x0e},
+	{BRIDGE, M5602_XB_I2C_REG_ADDR, 0xd0, 0x00},
+	{SENSOR, 0xd0, 0x00, 0x40},
+	{SENSOR, MT9M111_PAGE_MAP, 0x00, 0x02},
+	{SENSOR, MT9M111_CC_AUTO_EXPOSURE_PARAMETER_18, 0x00, 0x00},
+	{BRIDGE, M5602_XB_I2C_REG_ADDR, 0x28, 0x00},
+	{SENSOR, MT9M111_CC_AWB_PARAMETER_7, 0xef, 0x07},
+	{BRIDGE, M5602_XB_I2C_REG_ADDR, 0x28, 0x00},
+	{SENSOR, MT9M111_CC_AWB_PARAMETER_7, 0xef, 0x03},
+	{SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
+	{BRIDGE, M5602_XB_I2C_REG_ADDR, 0x33, 0x00},
+	{SENSOR, 0x33, 0x03, 0x49},
+	{BRIDGE, M5602_XB_I2C_REG_ADDR, 0x33, 0x00},
+
+	{SENSOR, 0x33, 0x03, 0x49},
+	{SENSOR, 0x34, 0xc0, 0x19},
+	{SENSOR, 0x3f, 0x20, 0x20},
+	{SENSOR, 0x40, 0x20, 0x20},
+	{SENSOR, 0x5a, 0xc0, 0x0a},
+	{SENSOR, 0x70, 0x7b, 0x0a},
+	{SENSOR, 0x71, 0xff, 0x00},
+	{SENSOR, 0x72, 0x19, 0x0e},
+	{SENSOR, 0x73, 0x18, 0x0f},
+	{SENSOR, 0x74, 0x57, 0x32},
+	{SENSOR, 0x75, 0x56, 0x34},
+	{SENSOR, 0x76, 0x73, 0x35},
+	{SENSOR, 0x77, 0x30, 0x12},
+	{SENSOR, 0x78, 0x79, 0x02},
+	{SENSOR, 0x79, 0x75, 0x06},
+	{SENSOR, 0x7a, 0x77, 0x0a},
+	{SENSOR, 0x7b, 0x78, 0x09},
+	{SENSOR, 0x7c, 0x7d, 0x06},
+	{SENSOR, 0x7d, 0x31, 0x10},
+	{SENSOR, 0x7e, 0x00, 0x7e},
+	{SENSOR, 0x80, 0x59, 0x04},
+	{SENSOR, 0x81, 0x59, 0x04},
+	{SENSOR, 0x82, 0x57, 0x0a},
+	{SENSOR, 0x83, 0x58, 0x0b},
+	{SENSOR, 0x84, 0x47, 0x0c},
+	{SENSOR, 0x85, 0x48, 0x0e},
+	{SENSOR, 0x86, 0x5b, 0x02},
+	{SENSOR, 0x87, 0x00, 0x5c},
+	{SENSOR, MT9M111_CONTEXT_CONTROL, 0x00, 0x08},
+	{SENSOR, 0x60, 0x00, 0x80},
+	{SENSOR, 0x61, 0x00, 0x00},
+	{SENSOR, 0x62, 0x00, 0x00},
+	{SENSOR, 0x63, 0x00, 0x00},
+	{SENSOR, 0x64, 0x00, 0x00},
+
+	{SENSOR, MT9M111_SC_ROWSTART, 0x00, 0x0d},
+	{SENSOR, MT9M111_SC_COLSTART, 0x00, 0x18},
+	{SENSOR, MT9M111_SC_WINDOW_HEIGHT, 0x04, 0x04},
+	{SENSOR, MT9M111_SC_WINDOW_WIDTH, 0x05, 0x08},
+	{SENSOR, MT9M111_SC_HBLANK_CONTEXT_B, 0x01, 0x38},
+	{SENSOR, MT9M111_SC_VBLANK_CONTEXT_B, 0x00, 0x11},
+	{SENSOR, MT9M111_SC_HBLANK_CONTEXT_A, 0x01, 0x38},
+	{SENSOR, MT9M111_SC_VBLANK_CONTEXT_A, 0x00, 0x11},
+	{SENSOR, MT9M111_SC_R_MODE_CONTEXT_B, 0x01, 0x03},
+	{SENSOR, MT9M111_SC_R_MODE_CONTEXT_A, 0x01, 0x03},
+	{SENSOR, 0x30, 0x04, 0x00},
+
+	{BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06, 0x00},
+	{BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
+	{BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
+	{BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00},
+	{BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x81, 0x00},
+	{BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82, 0x00},
+	{BRIDGE, M5602_XB_SIG_INI, 0x01, 0x00},
+	{BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+	{BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+	{BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+	{BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+	{BRIDGE, M5602_XB_VSYNC_PARA, 0x04, 0x00},
+	{BRIDGE, M5602_XB_VSYNC_PARA, 0x04, 0x00},
+	{BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+	{BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+	{BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00},
+	{BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00},
+	{BRIDGE, M5602_XB_HSYNC_PARA, 0x05, 0x00},
+	{BRIDGE, M5602_XB_HSYNC_PARA, 0x07, 0x00},
+	{BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
+	{BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
+	{BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xa0, 0x00},
+	{SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
+	{SENSOR, MT9M111_SC_SHUTTER_WIDTH, 0x01, 0xf4},
+	{SENSOR, MT9M111_SC_GLOBAL_GAIN, 0x00, 0xea},
+	{BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
+	{BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
+	{SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
+	{BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
+	{BRIDGE, M5602_XB_I2C_REG_ADDR, 0x0d, 0x00},
+	{BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
+	{SENSOR, MT9M111_SC_RESET, 0x00, 0x09},
+	{BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
+	{BRIDGE, M5602_XB_I2C_REG_ADDR, 0x0d, 0x00},
+	{BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
+	{SENSOR, MT9M111_SC_RESET, 0x00, 0x29},
+	{BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
+	{BRIDGE, M5602_XB_I2C_REG_ADDR, 0x0d, 0x00},
+	{BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
+	{SENSOR, MT9M111_SC_RESET, 0x00, 0x08},
+	{BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
+	{BRIDGE, M5602_XB_I2C_REG_ADDR, 0x0d, 0x00},
+	{BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
+	{SENSOR, MT9M111_SC_RESET, 0x00, 0x0c},
+	{BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
+	{BRIDGE, M5602_XB_I2C_REG_ADDR, 0x0d, 0x00},
+	{BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
+	{SENSOR, MT9M111_SC_RESET, 0x00, 0x04},
+	{SENSOR, MT9M111_PAGE_MAP, 0x00, 0x01},
+	{BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
+	{BRIDGE, M5602_XB_I2C_REG_ADDR, 0xb3, 0x00},
+	{BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
+	{SENSOR, MT9M111_CP_GLOBAL_CLK_CONTROL, 0x00, 0x03},
+	{BRIDGE, M5602_XB_GPIO_DIR, 0x05, 0x00},
+	{BRIDGE, M5602_XB_GPIO_DAT, 0x04, 0x00},
+	{BRIDGE, M5602_XB_GPIO_EN_H, 0x3e, 0x00},
+	{BRIDGE, M5602_XB_GPIO_DIR_H, 0x3e, 0x00},
+	{BRIDGE, M5602_XB_GPIO_DAT_H, 0x02, 0x00},
+	{BRIDGE, M5602_XB_GPIO_EN_L, 0xff, 0x00},
+	{BRIDGE, M5602_XB_GPIO_DIR_L, 0xff, 0x00},
+	{BRIDGE, M5602_XB_GPIO_DAT_L, 0x00, 0x00},
+	{BRIDGE, M5602_XB_SEN_CLK_DIV, 0x04, 0x00},
+	{BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
+	{BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
+	{BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
+	{BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
+	{BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00},
+	{BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
+	{BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
+	{BRIDGE, M5602_XB_GPIO_DIR, 0x07, 0x00},
+	{BRIDGE, M5602_XB_GPIO_DAT, 0x0b, 0x00},
+	{BRIDGE, M5602_XB_GPIO_EN_H, 0x06, 0x00},
+	{BRIDGE, M5602_XB_GPIO_EN_L, 0x00, 0x00},
+	{BRIDGE, M5602_XB_I2C_CLK_DIV, 0x0a, 0x00},
+	{SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
+	{BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
+	{BRIDGE, M5602_XB_I2C_REG_ADDR, 0x0d, 0x00},
+	{BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
+	{SENSOR, MT9M111_SC_RESET, 0x00, 0x05},
+	{SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
+	{BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
+	{BRIDGE, M5602_XB_I2C_REG_ADDR, 0x0d, 0x00},
+	{BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
+	{SENSOR, MT9M111_SC_RESET, 0x00, 0x29},
+	{SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
+	{BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
+	{BRIDGE, M5602_XB_I2C_REG_ADDR, 0x0d, 0x00},
+	{BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
+
+	{SENSOR, MT9M111_SC_RESET, 0x00, 0x08},
+	{SENSOR, MT9M111_PAGE_MAP, 0x00, 0x01},
+	{SENSOR, MT9M111_CP_OPERATING_MODE_CTL, 0x00, 0x10},
+	{SENSOR, MT9M111_CP_LENS_CORRECTION_1, 0x04, 0x2a},
+	{SENSOR, MT9M111_CP_DEFECT_CORR_CONTEXT_A, 0x00, 0x01},
+	{SENSOR, MT9M111_CP_DEFECT_CORR_CONTEXT_B, 0x00, 0x01},
+	{SENSOR, MT9M111_CP_LUMA_OFFSET, 0x00, 0x00},
+	{SENSOR, MT9M111_CP_LUMA_CLIP, 0xff, 0x00},
+	{SENSOR, MT9M111_CP_OUTPUT_FORMAT_CTL2_CONTEXT_A, 0x14, 0x00},
+	{SENSOR, MT9M111_CP_OUTPUT_FORMAT_CTL2_CONTEXT_B, 0x14, 0x00},
+
+	{BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
+	{BRIDGE, M5602_XB_I2C_REG_ADDR, 0xcd, 0x00},
+	{BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
+	{SENSOR, 0xcd, 0x00, 0x0e},
+	{BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
+	{BRIDGE, M5602_XB_I2C_REG_ADDR, 0xd0, 0x00},
+	{BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
+	{SENSOR, 0xd0, 0x00, 0x40},
+	{SENSOR, MT9M111_PAGE_MAP, 0x00, 0x02},
+	{SENSOR, MT9M111_CC_AUTO_EXPOSURE_PARAMETER_18, 0x00, 0x00},
+	{BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
+	{BRIDGE, M5602_XB_I2C_REG_ADDR, 0x28, 0x00},
+	{BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
+	{SENSOR, MT9M111_CC_AWB_PARAMETER_7, 0xef, 0x07},
+	{BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
+	{BRIDGE, M5602_XB_I2C_REG_ADDR, 0x28, 0x00},
+	{BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
+	{SENSOR, MT9M111_CC_AWB_PARAMETER_7, 0xef, 0x03},
+	{SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
+	{BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
+	{BRIDGE, M5602_XB_I2C_REG_ADDR, 0x33, 0x00},
+	{BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
+	{SENSOR, 0x33, 0x03, 0x49},
+	{BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
+	{BRIDGE, M5602_XB_I2C_REG_ADDR, 0x33, 0x00},
+	{BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
+
+	{SENSOR, 0x33, 0x03, 0x49},
+	{SENSOR, 0x34, 0xc0, 0x19},
+	{SENSOR, 0x3f, 0x20, 0x20},
+	{SENSOR, 0x40, 0x20, 0x20},
+	{SENSOR, 0x5a, 0xc0, 0x0a},
+	{SENSOR, 0x70, 0x7b, 0x0a},
+	{SENSOR, 0x71, 0xff, 0x00},
+	{SENSOR, 0x72, 0x19, 0x0e},
+	{SENSOR, 0x73, 0x18, 0x0f},
+	{SENSOR, 0x74, 0x57, 0x32},
+	{SENSOR, 0x75, 0x56, 0x34},
+	{SENSOR, 0x76, 0x73, 0x35},
+	{SENSOR, 0x77, 0x30, 0x12},
+	{SENSOR, 0x78, 0x79, 0x02},
+	{SENSOR, 0x79, 0x75, 0x06},
+	{SENSOR, 0x7a, 0x77, 0x0a},
+	{SENSOR, 0x7b, 0x78, 0x09},
+	{SENSOR, 0x7c, 0x7d, 0x06},
+	{SENSOR, 0x7d, 0x31, 0x10},
+	{SENSOR, 0x7e, 0x00, 0x7e},
+	{SENSOR, 0x80, 0x59, 0x04},
+	{SENSOR, 0x81, 0x59, 0x04},
+	{SENSOR, 0x82, 0x57, 0x0a},
+	{SENSOR, 0x83, 0x58, 0x0b},
+	{SENSOR, 0x84, 0x47, 0x0c},
+	{SENSOR, 0x85, 0x48, 0x0e},
+	{SENSOR, 0x86, 0x5b, 0x02},
+	{SENSOR, 0x87, 0x00, 0x5c},
+	{SENSOR, MT9M111_CONTEXT_CONTROL, 0x00, 0x08},
+	{SENSOR, 0x60, 0x00, 0x80},
+	{SENSOR, 0x61, 0x00, 0x00},
+	{SENSOR, 0x62, 0x00, 0x00},
+	{SENSOR, 0x63, 0x00, 0x00},
+	{SENSOR, 0x64, 0x00, 0x00},
+	{SENSOR, MT9M111_SC_ROWSTART, 0x00, 0x0d},
+	{SENSOR, MT9M111_SC_COLSTART, 0x00, 0x12},
+	{SENSOR, MT9M111_SC_WINDOW_HEIGHT, 0x04, 0x00},
+	{SENSOR, MT9M111_SC_WINDOW_WIDTH, 0x05, 0x10},
+	{SENSOR, MT9M111_SC_HBLANK_CONTEXT_B, 0x01, 0x60},
+	{SENSOR, MT9M111_SC_VBLANK_CONTEXT_B, 0x00, 0x11},
+	{SENSOR, MT9M111_SC_HBLANK_CONTEXT_A, 0x01, 0x60},
+	{SENSOR, MT9M111_SC_VBLANK_CONTEXT_A, 0x00, 0x11},
+	{SENSOR, MT9M111_SC_R_MODE_CONTEXT_B, 0x01, 0x0f},
+	{SENSOR, MT9M111_SC_R_MODE_CONTEXT_A, 0x01, 0x0f},
+	{SENSOR, 0x30, 0x04, 0x00},
+
+	{BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06, 0x00},
+	{BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
+	{BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
+	{BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00},
+	{BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x81, 0x00},
+	{BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82, 0x00},
+	{BRIDGE, M5602_XB_SIG_INI, 0x01, 0x00},
+	{BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+	{BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+	{BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+	{BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+	{BRIDGE, M5602_XB_VSYNC_PARA, 0x01, 0x00},
+	{BRIDGE, M5602_XB_VSYNC_PARA, 0xe3, 0x00},
+	{BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+	{BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+	{BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
+	{BRIDGE, M5602_XB_SIG_INI, 0x02, 0x00},
+	{BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00},
+	{BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00},
+	{BRIDGE, M5602_XB_HSYNC_PARA, 0x02, 0x00},
+	{BRIDGE, M5602_XB_HSYNC_PARA, 0x87, 0x00},
+	{BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
+	{BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
+	{BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
+
+	{SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
+	{SENSOR, MT9M111_SC_SHUTTER_WIDTH, 0x01, 0x90},
+	{SENSOR, MT9M111_SC_GLOBAL_GAIN, 0x00, 0xe6},
+	{BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
+	{BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
+	{SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
+	{BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
+	{BRIDGE, M5602_XB_I2C_REG_ADDR, 0x0d, 0x00},
+	{BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
+	{SENSOR, MT9M111_SC_RESET, 0x00, 0x09},
+	{BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
+	{BRIDGE, M5602_XB_I2C_REG_ADDR, 0x0d, 0x00},
+	{BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
+	{SENSOR, MT9M111_SC_RESET, 0x00, 0x29},
+	{BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
+	{BRIDGE, M5602_XB_I2C_REG_ADDR, 0x0d, 0x00},
+	{BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
+	{SENSOR, MT9M111_SC_RESET, 0x00, 0x08},
+	{BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
+	{BRIDGE, M5602_XB_I2C_REG_ADDR, 0x0d, 0x00},
+	{BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
+	{SENSOR, MT9M111_SC_RESET, 0x00, 0x0c},
+	{BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
+	{BRIDGE, M5602_XB_I2C_REG_ADDR, 0x0d, 0x00},
+	{BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
+	{SENSOR, MT9M111_SC_RESET, 0x00, 0x04},
+	{SENSOR, MT9M111_PAGE_MAP, 0x00, 0x01},
+	{BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
+	{BRIDGE, M5602_XB_I2C_REG_ADDR, 0xb3, 0x00},
+	{BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
+	{SENSOR, MT9M111_CP_GLOBAL_CLK_CONTROL, 0x00, 0x03},
+
+	{BRIDGE, M5602_XB_GPIO_DIR, 0x05, 0x00},
+	{BRIDGE, M5602_XB_GPIO_DAT, 0x04, 0x00},
+	{BRIDGE, M5602_XB_GPIO_EN_H, 0x3e, 0x00},
+	{BRIDGE, M5602_XB_GPIO_DIR_H, 0x3e, 0x00},
+	{BRIDGE, M5602_XB_GPIO_DAT_H, 0x02, 0x00},
+	{BRIDGE, M5602_XB_GPIO_EN_L, 0xff, 0x00},
+	{BRIDGE, M5602_XB_GPIO_DIR_L, 0xff, 0x00},
+	{BRIDGE, M5602_XB_GPIO_DAT_L, 0x00, 0x00},
+	{BRIDGE, M5602_XB_SEN_CLK_DIV, 0x04, 0x00},
+	{BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
+	{BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
+	{BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
+	{BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
+	{BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00},
+	{BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
+	{BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
+	{BRIDGE, M5602_XB_GPIO_DIR, 0x07, 0x00},
+	{BRIDGE, M5602_XB_GPIO_DAT, 0x0b, 0x00},
+	{BRIDGE, M5602_XB_GPIO_EN_H, 0x06, 0x00},
+	{BRIDGE, M5602_XB_GPIO_EN_L, 0x00, 0x00},
+	{BRIDGE, M5602_XB_I2C_CLK_DIV, 0x0a, 0x00},
+	{SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
+	{BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
+	{BRIDGE, M5602_XB_I2C_REG_ADDR, 0x0d, 0x00},
+	{BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
+	{SENSOR, MT9M111_SC_RESET, 0x00, 0x05},
+	{SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
+	{BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
+	{BRIDGE, M5602_XB_I2C_REG_ADDR, 0x0d, 0x00},
+	{BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
+	{SENSOR, MT9M111_SC_RESET, 0x00, 0x29},
+	{SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
+	{BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
+	{BRIDGE, M5602_XB_I2C_REG_ADDR, 0x0d, 0x00},
+	{BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
+	{SENSOR, MT9M111_SC_RESET, 0x00, 0x08},
+	{SENSOR, MT9M111_PAGE_MAP, 0x00, 0x01},
+	{SENSOR, MT9M111_CP_OPERATING_MODE_CTL, 0x00, 0x10},
+	{SENSOR, MT9M111_CP_LENS_CORRECTION_1, 0x04, 0x2a},
+	{SENSOR, MT9M111_CP_DEFECT_CORR_CONTEXT_A, 0x00, 0x01},
+	{SENSOR, MT9M111_CP_DEFECT_CORR_CONTEXT_B, 0x00, 0x01},
+	{SENSOR, MT9M111_CP_LUMA_OFFSET, 0x00, 0x00},
+	{SENSOR, MT9M111_CP_LUMA_CLIP, 0xff, 0x00},
+	{SENSOR, MT9M111_CP_OUTPUT_FORMAT_CTL2_CONTEXT_A, 0x14, 0x00},
+	{SENSOR, MT9M111_CP_OUTPUT_FORMAT_CTL2_CONTEXT_B, 0x14, 0x00},
+
+	{BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
+	{BRIDGE, M5602_XB_I2C_REG_ADDR, 0xcd, 0x00},
+	{BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
+	{SENSOR, 0xcd, 0x00, 0x0e},
+	{BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
+	{BRIDGE, M5602_XB_I2C_REG_ADDR, 0xd0, 0x00},
+	{BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
+	{SENSOR, 0xd0, 0x00, 0x40},
+	{SENSOR, MT9M111_PAGE_MAP, 0x00, 0x02},
+	{SENSOR, MT9M111_CC_AUTO_EXPOSURE_PARAMETER_18, 0x00, 0x00},
+	{BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
+	{BRIDGE, M5602_XB_I2C_REG_ADDR, 0x28, 0x00},
+	{BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
+	{SENSOR, MT9M111_CC_AWB_PARAMETER_7, 0xef, 0x07},
+	{BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
+	{BRIDGE, M5602_XB_I2C_REG_ADDR, 0x28, 0x00},
+	{BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
+	{SENSOR, MT9M111_CC_AWB_PARAMETER_7, 0xef, 0x03},
+	{SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
+
+	{BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
+	{BRIDGE, M5602_XB_I2C_REG_ADDR, 0x33, 0x00},
+	{BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
+	{SENSOR, 0x33, 0x03, 0x49},
+	{BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
+	{BRIDGE, M5602_XB_I2C_REG_ADDR, 0x33, 0x00},
+	{BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
+
+	{SENSOR, 0x33, 0x03, 0x49},
+	{SENSOR, 0x34, 0xc0, 0x19},
+	{SENSOR, 0x3f, 0x20, 0x20},
+	{SENSOR, 0x40, 0x20, 0x20},
+	{SENSOR, 0x5a, 0xc0, 0x0a},
+	{SENSOR, 0x70, 0x7b, 0x0a},
+	{SENSOR, 0x71, 0xff, 0x00},
+	{SENSOR, 0x72, 0x19, 0x0e},
+	{SENSOR, 0x73, 0x18, 0x0f},
+	{SENSOR, 0x74, 0x57, 0x32},
+	{SENSOR, 0x75, 0x56, 0x34},
+	{SENSOR, 0x76, 0x73, 0x35},
+	{SENSOR, 0x77, 0x30, 0x12},
+	{SENSOR, 0x78, 0x79, 0x02},
+	{SENSOR, 0x79, 0x75, 0x06},
+	{SENSOR, 0x7a, 0x77, 0x0a},
+	{SENSOR, 0x7b, 0x78, 0x09},
+	{SENSOR, 0x7c, 0x7d, 0x06},
+	{SENSOR, 0x7d, 0x31, 0x10},
+	{SENSOR, 0x7e, 0x00, 0x7e},
+	{SENSOR, 0x80, 0x59, 0x04},
+	{SENSOR, 0x81, 0x59, 0x04},
+	{SENSOR, 0x82, 0x57, 0x0a},
+	{SENSOR, 0x83, 0x58, 0x0b},
+	{SENSOR, 0x84, 0x47, 0x0c},
+	{SENSOR, 0x85, 0x48, 0x0e},
+	{SENSOR, 0x86, 0x5b, 0x02},
+	{SENSOR, 0x87, 0x00, 0x5c},
+	{SENSOR, MT9M111_CONTEXT_CONTROL, 0x00, 0x08},
+	{SENSOR, 0x60, 0x00, 0x80},
+	{SENSOR, 0x61, 0x00, 0x00},
+	{SENSOR, 0x62, 0x00, 0x00},
+	{SENSOR, 0x63, 0x00, 0x00},
+	{SENSOR, 0x64, 0x00, 0x00},
+
+	{SENSOR, MT9M111_SC_ROWSTART, 0x00, 0x0d},
+	{SENSOR, MT9M111_SC_COLSTART, 0x00, 0x12},
+	{SENSOR, MT9M111_SC_WINDOW_HEIGHT, 0x04, 0x00},
+	{SENSOR, MT9M111_SC_WINDOW_WIDTH, 0x05, 0x10},
+	{SENSOR, MT9M111_SC_HBLANK_CONTEXT_B, 0x01, 0x60},
+	{SENSOR, MT9M111_SC_VBLANK_CONTEXT_B, 0x00, 0x11},
+	{SENSOR, MT9M111_SC_HBLANK_CONTEXT_A, 0x01, 0x60},
+	{SENSOR, MT9M111_SC_VBLANK_CONTEXT_A, 0x00, 0x11},
+	{SENSOR, MT9M111_SC_R_MODE_CONTEXT_B, 0x01, 0x0f},
+	{SENSOR, MT9M111_SC_R_MODE_CONTEXT_A, 0x01, 0x0f},
+	{SENSOR, 0x30, 0x04, 0x00},
+
+	{BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06, 0x00},
+	{BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
+	{BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
+	{BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00},
+	{BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x81, 0x00},
+	{BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82, 0x00},
+	{BRIDGE, M5602_XB_SIG_INI, 0x01, 0x00},
+	{BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+	{BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+	{BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+	{BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+	{BRIDGE, M5602_XB_VSYNC_PARA, 0x01, 0x00},
+	{BRIDGE, M5602_XB_VSYNC_PARA, 0xe0, 0x00},
+	{BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+	{BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+	{BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
+	{BRIDGE, M5602_XB_SIG_INI, 0x02, 0x00},
+	{BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00},
+	{BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00},
+	{BRIDGE, M5602_XB_HSYNC_PARA, 0x02, 0x00},
+	{BRIDGE, M5602_XB_HSYNC_PARA, 0x7f, 0x00},
+	{BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
+	{BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
+	{BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
+
+	{SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
+	/* Set number of blank rows chosen to 400 */
+	{SENSOR, MT9M111_SC_SHUTTER_WIDTH, 0x01, 0x90},
+	/* Set the global gain to 283 (of 512) */
+	{SENSOR, MT9M111_SC_GLOBAL_GAIN, 0x03, 0x63}
+};
+
+#endif
diff --git a/drivers/media/video/gspca/m5602/m5602_ov9650.c b/drivers/media/video/gspca/m5602/m5602_ov9650.c
new file mode 100644
index 0000000..31c5896
--- /dev/null
+++ b/drivers/media/video/gspca/m5602/m5602_ov9650.c
@@ -0,0 +1,546 @@
+/*
+ * Driver for the ov9650 sensor
+ *
+ * Copyright (C) 2008 Erik Andren
+ * Copyright (C) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project.
+ * Copyright (C) 2005 m5603x Linux Driver Project <m5602@x3ng.com.br>
+ *
+ * Portions of code to USB interface and ALi driver software,
+ * Copyright (c) 2006 Willem Duinker
+ * v4l2 interface modeled after the V4L2 driver
+ * for SN9C10x PC Camera Controllers
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2.
+ *
+ */
+
+#include "m5602_ov9650.h"
+
+int ov9650_read_sensor(struct sd *sd, const u8 address,
+		      u8 *i2c_data, const u8 len)
+{
+	int err, i;
+
+	/* The ov9650 registers have a max depth of one byte */
+	if (len > 1 || !len)
+		return -EINVAL;
+
+	do {
+		err = m5602_read_bridge(sd, M5602_XB_I2C_STATUS, i2c_data);
+	} while ((*i2c_data & I2C_BUSY) && !err);
+
+	m5602_write_bridge(sd, M5602_XB_I2C_DEV_ADDR,
+			   ov9650.i2c_slave_id);
+	m5602_write_bridge(sd, M5602_XB_I2C_REG_ADDR, address);
+	m5602_write_bridge(sd, M5602_XB_I2C_CTRL, 0x10 + len);
+	m5602_write_bridge(sd, M5602_XB_I2C_CTRL, 0x08);
+
+	for (i = 0; i < len; i++) {
+		err = m5602_read_bridge(sd, M5602_XB_I2C_DATA, &(i2c_data[i]));
+
+		PDEBUG(DBG_TRACE, "Reading sensor register "
+				"0x%x containing 0x%x ", address, *i2c_data);
+	}
+	return (err < 0) ? err : 0;
+}
+
+int ov9650_write_sensor(struct sd *sd, const u8 address,
+			u8 *i2c_data, const u8 len)
+{
+	int err, i;
+	u8 *p;
+	struct usb_device *udev = sd->gspca_dev.dev;
+	__u8 *buf = sd->gspca_dev.usb_buf;
+
+	/* The ov9650 only supports one byte writes */
+	if (len > 1 || !len)
+		return -EINVAL;
+
+	memcpy(buf, sensor_urb_skeleton,
+	       sizeof(sensor_urb_skeleton));
+
+	buf[11] = sd->sensor->i2c_slave_id;
+	buf[15] = address;
+
+	/* Special case larger sensor writes */
+	p = buf + 16;
+
+	/* Copy a four byte write sequence for each byte to be written to */
+	for (i = 0; i < len; i++) {
+		memcpy(p, sensor_urb_skeleton + 16, 4);
+		p[3] = i2c_data[i];
+		p += 4;
+		PDEBUG(DBG_TRACE, "Writing sensor register 0x%x with 0x%x",
+		       address, i2c_data[i]);
+	}
+
+	/* Copy the tailer */
+	memcpy(p, sensor_urb_skeleton + 20, 4);
+
+	/* Set the total length */
+	p[3] = 0x10 + len;
+
+	err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+			      0x04, 0x40, 0x19,
+			      0x0000, buf,
+			      20 + len * 4, M5602_URB_MSG_TIMEOUT);
+
+	return (err < 0) ? err : 0;
+}
+
+int ov9650_probe(struct sd *sd)
+{
+	u8 prod_id = 0, ver_id = 0, i;
+
+	if (force_sensor) {
+		if (force_sensor == OV9650_SENSOR) {
+			info("Forcing an %s sensor", ov9650.name);
+			goto sensor_found;
+		}
+		/* If we want to force another sensor,
+		   don't try to probe this one */
+		return -ENODEV;
+	}
+
+	info("Probing for an ov9650 sensor");
+
+	/* Run the pre-init to actually probe the unit */
+	for (i = 0; i < ARRAY_SIZE(preinit_ov9650); i++) {
+		u8 data = preinit_ov9650[i][2];
+		if (preinit_ov9650[i][0] == SENSOR)
+			ov9650_write_sensor(sd,
+					    preinit_ov9650[i][1], &data, 1);
+		else
+			m5602_write_bridge(sd, preinit_ov9650[i][1], data);
+	}
+
+	if (ov9650_read_sensor(sd, OV9650_PID, &prod_id, 1))
+		return -ENODEV;
+
+	if (ov9650_read_sensor(sd, OV9650_VER, &ver_id, 1))
+		return -ENODEV;
+
+	if ((prod_id == 0x96) && (ver_id == 0x52)) {
+		info("Detected an ov9650 sensor");
+		goto sensor_found;
+	}
+
+	return -ENODEV;
+
+sensor_found:
+	sd->gspca_dev.cam.cam_mode = ov9650.modes;
+	sd->gspca_dev.cam.nmodes = ov9650.nmodes;
+	sd->desc->ctrls = ov9650.ctrls;
+	sd->desc->nctrls = ov9650.nctrls;
+	return 0;
+}
+
+int ov9650_init(struct sd *sd)
+{
+	int i, err = 0;
+	u8 data;
+
+	if (dump_sensor)
+		ov9650_dump_registers(sd);
+
+	for (i = 0; i < ARRAY_SIZE(init_ov9650) && !err; i++) {
+		data = init_ov9650[i][2];
+		if (init_ov9650[i][0] == SENSOR)
+			err = ov9650_write_sensor(sd, init_ov9650[i][1],
+						  &data, 1);
+		else
+			err = m5602_write_bridge(sd, init_ov9650[i][1], data);
+	}
+
+	if (!err && dmi_check_system(ov9650_flip_dmi_table)) {
+		info("vflip quirk active");
+		data = 0x30;
+		err = ov9650_write_sensor(sd, OV9650_MVFP, &data, 1);
+	}
+
+	return (err < 0) ? err : 0;
+}
+
+int ov9650_power_down(struct sd *sd)
+{
+	int i;
+	for (i = 0; i < ARRAY_SIZE(power_down_ov9650); i++) {
+		u8 data = power_down_ov9650[i][2];
+		if (power_down_ov9650[i][0] == SENSOR)
+			ov9650_write_sensor(sd,
+					    power_down_ov9650[i][1], &data, 1);
+		else
+			m5602_write_bridge(sd, power_down_ov9650[i][1], data);
+	}
+
+	return 0;
+}
+
+int ov9650_get_exposure(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	u8 i2c_data;
+	int err;
+
+	err = ov9650_read_sensor(sd, OV9650_COM1, &i2c_data, 1);
+	if (err < 0)
+		goto out;
+	*val = i2c_data & 0x03;
+
+	err = ov9650_read_sensor(sd, OV9650_AECH, &i2c_data, 1);
+	if (err < 0)
+		goto out;
+	*val |= (i2c_data << 2);
+
+	err = ov9650_read_sensor(sd, OV9650_AECHM, &i2c_data, 1);
+	if (err < 0)
+		goto out;
+	*val |= (i2c_data & 0x3f) << 10;
+
+	PDEBUG(DBG_V4L2_CID, "Read exposure %d", *val);
+out:
+	return (err < 0) ? err : 0;
+}
+
+int ov9650_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	u8 i2c_data;
+	int err;
+
+	PDEBUG(DBG_V4L2_CID, "Set exposure to %d",
+	       val & 0xffff);
+
+	/* The 6 MSBs */
+	i2c_data = (val >> 10) & 0x3f;
+	err = ov9650_write_sensor(sd, OV9650_AECHM,
+				  &i2c_data, 1);
+	if (err < 0)
+		goto out;
+
+	/* The 8 middle bits */
+	i2c_data = (val >> 2) & 0xff;
+	err = ov9650_write_sensor(sd, OV9650_AECH,
+				  &i2c_data, 1);
+	if (err < 0)
+		goto out;
+
+	/* The 2 LSBs */
+	i2c_data = val & 0x03;
+	err = ov9650_write_sensor(sd, OV9650_COM1, &i2c_data, 1);
+
+out:
+	return (err < 0) ? err : 0;
+}
+
+int ov9650_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	int err;
+	u8 i2c_data;
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	ov9650_read_sensor(sd, OV9650_VREF, &i2c_data, 1);
+	*val = (i2c_data & 0x03) << 8;
+
+	err = ov9650_read_sensor(sd, OV9650_GAIN, &i2c_data, 1);
+	*val |= i2c_data;
+	PDEBUG(DBG_V4L2_CID, "Read gain %d", *val);
+	return (err < 0) ? err : 0;
+}
+
+int ov9650_set_gain(struct gspca_dev *gspca_dev, __s32 val)
+{
+	int err;
+	u8 i2c_data;
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	/* The 2 MSB */
+	/* Read the OV9650_VREF register first to avoid
+	   corrupting the VREF high and low bits */
+	ov9650_read_sensor(sd, OV9650_VREF, &i2c_data, 1);
+	/* Mask away all uninteresting bits */
+	i2c_data = ((val & 0x0300) >> 2) |
+			(i2c_data & 0x3F);
+	err = ov9650_write_sensor(sd, OV9650_VREF, &i2c_data, 1);
+
+	/* The 8 LSBs */
+	i2c_data = val & 0xff;
+	err = ov9650_write_sensor(sd, OV9650_GAIN, &i2c_data, 1);
+	return (err < 0) ? err : 0;
+}
+
+int ov9650_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	int err;
+	u8 i2c_data;
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	err = ov9650_read_sensor(sd, OV9650_RED, &i2c_data, 1);
+	*val = i2c_data;
+
+	PDEBUG(DBG_V4L2_CID, "Read red gain %d", *val);
+
+	return (err < 0) ? err : 0;
+}
+
+int ov9650_set_red_balance(struct gspca_dev *gspca_dev, __s32 val)
+{
+	int err;
+	u8 i2c_data;
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	PDEBUG(DBG_V4L2_CID, "Set red gain to %d",
+			     val & 0xff);
+
+	i2c_data = val & 0xff;
+	err = ov9650_write_sensor(sd, OV9650_RED, &i2c_data, 1);
+
+	return (err < 0) ? err : 0;
+}
+
+int ov9650_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	int err;
+	u8 i2c_data;
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	err = ov9650_read_sensor(sd, OV9650_BLUE, &i2c_data, 1);
+	*val = i2c_data;
+
+	PDEBUG(DBG_V4L2_CID, "Read blue gain %d", *val);
+
+	return (err < 0) ? err : 0;
+}
+
+int ov9650_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val)
+{
+	int err;
+	u8 i2c_data;
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	PDEBUG(DBG_V4L2_CID, "Set blue gain to %d",
+	       val & 0xff);
+
+	i2c_data = val & 0xff;
+	err = ov9650_write_sensor(sd, OV9650_BLUE, &i2c_data, 1);
+
+	return (err < 0) ? err : 0;
+}
+
+int ov9650_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	int err;
+	u8 i2c_data;
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	err = ov9650_read_sensor(sd, OV9650_MVFP, &i2c_data, 1);
+	if (dmi_check_system(ov9650_flip_dmi_table))
+		*val = ((i2c_data & OV9650_HFLIP) >> 5) ? 0 : 1;
+	else
+		*val = (i2c_data & OV9650_HFLIP) >> 5;
+	PDEBUG(DBG_V4L2_CID, "Read horizontal flip %d", *val);
+
+	return (err < 0) ? err : 0;
+}
+
+int ov9650_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
+{
+	int err;
+	u8 i2c_data;
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	PDEBUG(DBG_V4L2_CID, "Set horizontal flip to %d", val);
+	err = ov9650_read_sensor(sd, OV9650_MVFP, &i2c_data, 1);
+	if (err < 0)
+		goto out;
+
+	if (dmi_check_system(ov9650_flip_dmi_table))
+		i2c_data = ((i2c_data & 0xdf) |
+				(((val ? 0 : 1) & 0x01) << 5));
+	else
+		i2c_data = ((i2c_data & 0xdf) |
+				((val & 0x01) << 5));
+
+	err = ov9650_write_sensor(sd, OV9650_MVFP, &i2c_data, 1);
+out:
+	return (err < 0) ? err : 0;
+}
+
+int ov9650_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	int err;
+	u8 i2c_data;
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	err = ov9650_read_sensor(sd, OV9650_MVFP, &i2c_data, 1);
+	if (dmi_check_system(ov9650_flip_dmi_table))
+		*val = ((i2c_data & 0x10) >> 4) ? 0 : 1;
+	else
+		*val = (i2c_data & 0x10) >> 4;
+	PDEBUG(DBG_V4L2_CID, "Read vertical flip %d", *val);
+
+	return (err < 0) ? err : 0;
+}
+
+int ov9650_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
+{
+	int err;
+	u8 i2c_data;
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	PDEBUG(DBG_V4L2_CID, "Set vertical flip to %d", val);
+	err = ov9650_read_sensor(sd, OV9650_MVFP, &i2c_data, 1);
+	if (err < 0)
+		goto out;
+
+	if (dmi_check_system(ov9650_flip_dmi_table))
+		i2c_data = ((i2c_data & 0xef) |
+				(((val ? 0 : 1) & 0x01) << 4));
+	else
+		i2c_data = ((i2c_data & 0xef) |
+				((val & 0x01) << 4));
+
+	err = ov9650_write_sensor(sd, OV9650_MVFP, &i2c_data, 1);
+out:
+	return (err < 0) ? err : 0;
+}
+
+int ov9650_get_brightness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	int err;
+	u8 i2c_data;
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	err = ov9650_read_sensor(sd, OV9650_VREF, &i2c_data, 1);
+	if (err < 0)
+		goto out;
+	*val = (i2c_data & 0x03) << 8;
+
+	err = ov9650_read_sensor(sd, OV9650_GAIN, &i2c_data, 1);
+	*val |= i2c_data;
+	PDEBUG(DBG_V4L2_CID, "Read gain %d", *val);
+out:
+	return (err < 0) ? err : 0;
+}
+
+int ov9650_set_brightness(struct gspca_dev *gspca_dev, __s32 val)
+{
+	int err;
+	u8 i2c_data;
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	PDEBUG(DBG_V4L2_CID, "Set gain to %d", val & 0x3ff);
+
+	/* Read the OV9650_VREF register first to avoid
+		corrupting the VREF high and low bits */
+	err = ov9650_read_sensor(sd, OV9650_VREF, &i2c_data, 1);
+	if (err < 0)
+		goto out;
+
+	/* Mask away all uninteresting bits */
+	i2c_data = ((val & 0x0300) >> 2) | (i2c_data & 0x3F);
+	err = ov9650_write_sensor(sd, OV9650_VREF, &i2c_data, 1);
+	if (err < 0)
+		goto out;
+
+	/* The 8 LSBs */
+	i2c_data = val & 0xff;
+	err = ov9650_write_sensor(sd, OV9650_GAIN, &i2c_data, 1);
+
+out:
+	return (err < 0) ? err : 0;
+}
+
+int ov9650_get_auto_white_balance(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	int err;
+	u8 i2c_data;
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	err = ov9650_read_sensor(sd, OV9650_COM8, &i2c_data, 1);
+	*val = (i2c_data & OV9650_AWB_EN) >> 1;
+	PDEBUG(DBG_V4L2_CID, "Read auto white balance %d", *val);
+
+	return (err < 0) ? err : 0;
+}
+
+int ov9650_set_auto_white_balance(struct gspca_dev *gspca_dev, __s32 val)
+{
+	int err;
+	u8 i2c_data;
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	PDEBUG(DBG_V4L2_CID, "Set auto white balance to %d", val);
+	err = ov9650_read_sensor(sd, OV9650_COM8, &i2c_data, 1);
+	if (err < 0)
+		goto out;
+
+	i2c_data = ((i2c_data & 0xfd) | ((val & 0x01) << 1));
+	err = ov9650_write_sensor(sd, OV9650_COM8, &i2c_data, 1);
+out:
+	return (err < 0) ? err : 0;
+}
+
+int ov9650_get_auto_gain(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	int err;
+	u8 i2c_data;
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	err = ov9650_read_sensor(sd, OV9650_COM8, &i2c_data, 1);
+	*val = (i2c_data & OV9650_AGC_EN) >> 2;
+	PDEBUG(DBG_V4L2_CID, "Read auto gain control %d", *val);
+
+	return (err < 0) ? err : 0;
+}
+
+int ov9650_set_auto_gain(struct gspca_dev *gspca_dev, __s32 val)
+{
+	int err;
+	u8 i2c_data;
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	PDEBUG(DBG_V4L2_CID, "Set auto gain control to %d", val);
+	err = ov9650_read_sensor(sd, OV9650_COM8, &i2c_data, 1);
+	if (err < 0)
+		goto out;
+
+	i2c_data = ((i2c_data & 0xfb) | ((val & 0x01) << 2));
+	err = ov9650_write_sensor(sd, OV9650_COM8, &i2c_data, 1);
+out:
+	return (err < 0) ? err : 0;
+}
+
+void ov9650_dump_registers(struct sd *sd)
+{
+	int address;
+	info("Dumping the ov9650 register state");
+	for (address = 0; address < 0xa9; address++) {
+		u8 value;
+		ov9650_read_sensor(sd, address, &value, 1);
+		info("register 0x%x contains 0x%x",
+		     address, value);
+	}
+
+	info("ov9650 register state dump complete");
+
+	info("Probing for which registers that are read/write");
+	for (address = 0; address < 0xff; address++) {
+		u8 old_value, ctrl_value;
+		u8 test_value[2] = {0xff, 0xff};
+
+		ov9650_read_sensor(sd, address, &old_value, 1);
+		ov9650_write_sensor(sd, address, test_value, 1);
+		ov9650_read_sensor(sd, address, &ctrl_value, 1);
+
+		if (ctrl_value == test_value[0])
+			info("register 0x%x is writeable", address);
+		else
+			info("register 0x%x is read only", address);
+
+		/* Restore original value */
+		ov9650_write_sensor(sd, address, &old_value, 1);
+	}
+}
diff --git a/drivers/media/video/gspca/m5602/m5602_ov9650.h b/drivers/media/video/gspca/m5602/m5602_ov9650.h
new file mode 100644
index 0000000..2f29cb0
--- /dev/null
+++ b/drivers/media/video/gspca/m5602/m5602_ov9650.h
@@ -0,0 +1,503 @@
+/*
+ * Driver for the ov9650 sensor
+ *
+ * Copyright (C) 2008 Erik Andren
+ * Copyright (C) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project.
+ * Copyright (C) 2005 m5603x Linux Driver Project <m5602@x3ng.com.br>
+ *
+ * Portions of code to USB interface and ALi driver software,
+ * Copyright (c) 2006 Willem Duinker
+ * v4l2 interface modeled after the V4L2 driver
+ * for SN9C10x PC Camera Controllers
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2.
+ *
+ */
+
+#ifndef M5602_OV9650_H_
+#define M5602_OV9650_H_
+
+#include <linux/dmi.h>
+
+#include "m5602_sensor.h"
+
+/*****************************************************************************/
+
+#define OV9650_GAIN			0x00
+#define OV9650_BLUE			0x01
+#define OV9650_RED			0x02
+#define OV9650_VREF			0x03
+#define OV9650_COM1			0x04
+#define OV9650_BAVE			0x05
+#define OV9650_GEAVE			0x06
+#define OV9650_RSVD7			0x07
+#define OV9650_PID			0x0a
+#define OV9650_VER			0x0b
+#define OV9650_COM3			0x0c
+#define OV9650_COM5			0x0e
+#define OV9650_COM6			0x0f
+#define OV9650_AECH			0x10
+#define OV9650_CLKRC			0x11
+#define OV9650_COM7			0x12
+#define OV9650_COM8			0x13
+#define OV9650_COM9			0x14
+#define OV9650_COM10			0x15
+#define OV9650_RSVD16			0x16
+#define OV9650_HSTART			0x17
+#define OV9650_HSTOP			0x18
+#define OV9650_VSTRT			0x19
+#define OV9650_VSTOP			0x1a
+#define OV9650_PSHFT			0x1b
+#define OV9650_MVFP			0x1e
+#define OV9650_AEW			0x24
+#define OV9650_AEB			0x25
+#define OV9650_VPT			0x26
+#define OV9650_BBIAS			0x27
+#define OV9650_GbBIAS			0x28
+#define OV9650_Gr_COM			0x29
+#define OV9650_RBIAS			0x2c
+#define OV9650_HREF			0x32
+#define OV9650_CHLF			0x33
+#define OV9650_ARBLM			0x34
+#define OV9650_RSVD35			0x35
+#define OV9650_RSVD36			0x36
+#define OV9650_ADC			0x37
+#define OV9650_ACOM38			0x38
+#define OV9650_OFON			0x39
+#define OV9650_TSLB			0x3a
+#define OV9650_COM12			0x3c
+#define OV9650_COM13			0x3d
+#define OV9650_COM15			0x40
+#define OV9650_COM16			0x41
+#define OV9650_LCC1			0x62
+#define OV9650_LCC2			0x63
+#define OV9650_LCC3			0x64
+#define OV9650_LCC4			0x65
+#define OV9650_LCC5			0x66
+#define OV9650_HV			0x69
+#define OV9650_DBLV			0x6b
+#define OV9650_COM21			0x8b
+#define OV9650_COM22			0x8c
+#define OV9650_COM24			0x8e
+#define OV9650_DBLC1			0x8f
+#define OV9650_RSVD94			0x94
+#define OV9650_RSVD95			0x95
+#define OV9650_RSVD96			0x96
+#define OV9650_LCCFB			0x9d
+#define OV9650_LCCFR			0x9e
+#define OV9650_AECHM			0xa1
+#define OV9650_COM26			0xa5
+#define OV9650_ACOMA8			0xa8
+#define OV9650_ACOMA9			0xa9
+
+#define OV9650_REGISTER_RESET		(1 << 7)
+#define OV9650_VGA_SELECT		(1 << 6)
+#define OV9650_RGB_SELECT		(1 << 2)
+#define OV9650_RAW_RGB_SELECT		(1 << 0)
+
+#define OV9650_FAST_AGC_AEC		(1 << 7)
+#define OV9650_AEC_UNLIM_STEP_SIZE	(1 << 6)
+#define OV9650_BANDING			(1 << 5)
+#define OV9650_AGC_EN			(1 << 2)
+#define OV9650_AWB_EN			(1 << 1)
+#define OV9650_AEC_EN			(1 << 0)
+
+#define OV9650_VARIOPIXEL		(1 << 2)
+#define OV9650_SYSTEM_CLK_SEL		(1 << 7)
+#define OV9650_SLAM_MODE 		(1 << 4)
+
+#define OV9650_VFLIP			(1 << 4)
+#define OV9650_HFLIP			(1 << 5)
+
+#define GAIN_DEFAULT			0x14
+#define RED_GAIN_DEFAULT		0x70
+#define BLUE_GAIN_DEFAULT		0x20
+#define EXPOSURE_DEFAULT		0x5003
+
+/*****************************************************************************/
+
+/* Kernel module parameters */
+extern int force_sensor;
+extern int dump_sensor;
+extern unsigned int m5602_debug;
+
+int ov9650_probe(struct sd *sd);
+int ov9650_init(struct sd *sd);
+int ov9650_power_down(struct sd *sd);
+
+int ov9650_read_sensor(struct sd *sd, const u8 address,
+		       u8 *i2c_data, const u8 len);
+int ov9650_write_sensor(struct sd *sd, const u8 address,
+		       u8 *i2c_data, const u8 len);
+
+void ov9650_dump_registers(struct sd *sd);
+
+int ov9650_set_exposure(struct gspca_dev *gspca_dev, __s32 val);
+int ov9650_get_exposure(struct gspca_dev *gspca_dev, __s32 *val);
+int ov9650_get_gain(struct gspca_dev *gspca_dev, __s32 *val);
+int ov9650_set_gain(struct gspca_dev *gspca_dev, __s32 val);
+int ov9650_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val);
+int ov9650_set_red_balance(struct gspca_dev *gspca_dev, __s32 val);
+int ov9650_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val);
+int ov9650_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val);
+int ov9650_get_hflip(struct gspca_dev *gspca_dev, __s32 *val);
+int ov9650_set_hflip(struct gspca_dev *gspca_dev, __s32 val);
+int ov9650_get_vflip(struct gspca_dev *gspca_dev, __s32 *val);
+int ov9650_set_vflip(struct gspca_dev *gspca_dev, __s32 val);
+int ov9650_get_brightness(struct gspca_dev *gspca_dev, __s32 *val);
+int ov9650_set_brightness(struct gspca_dev *gspca_dev, __s32 val);
+int ov9650_get_auto_white_balance(struct gspca_dev *gspca_dev, __s32 *val);
+int ov9650_set_auto_white_balance(struct gspca_dev *gspca_dev, __s32 val);
+int ov9650_get_auto_gain(struct gspca_dev *gspca_dev, __s32 *val);
+int ov9650_set_auto_gain(struct gspca_dev *gspca_dev, __s32 val);
+
+static struct m5602_sensor ov9650 = {
+	.name = "OV9650",
+	.i2c_slave_id = 0x60,
+	.probe = ov9650_probe,
+	.init = ov9650_init,
+	.power_down = ov9650_power_down,
+	.read_sensor = ov9650_read_sensor,
+	.write_sensor = ov9650_write_sensor,
+
+	.nctrls = 8,
+	.ctrls = {
+	{
+		{
+			.id		= V4L2_CID_EXPOSURE,
+			.type		= V4L2_CTRL_TYPE_INTEGER,
+			.name		= "exposure",
+			.minimum	= 0x00,
+			.maximum	= 0xffff,
+			.step		= 0x1,
+			.default_value 	= EXPOSURE_DEFAULT,
+			.flags         	= V4L2_CTRL_FLAG_SLIDER
+		},
+		.set = ov9650_set_exposure,
+		.get = ov9650_get_exposure
+	}, {
+		{
+			.id		= V4L2_CID_GAIN,
+			.type		= V4L2_CTRL_TYPE_INTEGER,
+			.name		= "gain",
+			.minimum	= 0x00,
+			.maximum	= 0x3ff,
+			.step		= 0x1,
+			.default_value	= GAIN_DEFAULT,
+			.flags		= V4L2_CTRL_FLAG_SLIDER
+		},
+		.set = ov9650_set_gain,
+		.get = ov9650_get_gain
+	}, {
+		{
+			.type 		= V4L2_CTRL_TYPE_INTEGER,
+			.name 		= "red balance",
+			.minimum 	= 0x00,
+			.maximum 	= 0xff,
+			.step 		= 0x1,
+			.default_value 	= RED_GAIN_DEFAULT,
+			.flags         	= V4L2_CTRL_FLAG_SLIDER
+		},
+		.set = ov9650_set_red_balance,
+		.get = ov9650_get_red_balance
+	}, {
+		{
+			.type 		= V4L2_CTRL_TYPE_INTEGER,
+			.name 		= "blue balance",
+			.minimum 	= 0x00,
+			.maximum 	= 0xff,
+			.step 		= 0x1,
+			.default_value 	= BLUE_GAIN_DEFAULT,
+			.flags         	= V4L2_CTRL_FLAG_SLIDER
+		},
+		.set = ov9650_set_blue_balance,
+		.get = ov9650_get_blue_balance
+	}, {
+		{
+			.id 		= V4L2_CID_HFLIP,
+			.type 		= V4L2_CTRL_TYPE_BOOLEAN,
+			.name 		= "horizontal flip",
+			.minimum 	= 0,
+			.maximum 	= 1,
+			.step 		= 1,
+			.default_value 	= 0
+		},
+		.set = ov9650_set_hflip,
+		.get = ov9650_get_hflip
+	}, {
+		{
+			.id 		= V4L2_CID_VFLIP,
+			.type 		= V4L2_CTRL_TYPE_BOOLEAN,
+			.name 		= "vertical flip",
+			.minimum 	= 0,
+			.maximum 	= 1,
+			.step 		= 1,
+			.default_value 	= 0
+		},
+		.set = ov9650_set_vflip,
+		.get = ov9650_get_vflip
+	}, {
+		{
+			.id 		= V4L2_CID_AUTO_WHITE_BALANCE,
+			.type 		= V4L2_CTRL_TYPE_BOOLEAN,
+			.name 		= "auto white balance",
+			.minimum 	= 0,
+			.maximum 	= 1,
+			.step 		= 1,
+			.default_value 	= 0
+		},
+		.set = ov9650_set_auto_white_balance,
+		.get = ov9650_get_auto_white_balance
+	}, {
+		{
+			.id 		= V4L2_CID_AUTOGAIN,
+			.type 		= V4L2_CTRL_TYPE_BOOLEAN,
+			.name 		= "auto gain control",
+			.minimum 	= 0,
+			.maximum 	= 1,
+			.step 		= 1,
+			.default_value 	= 0
+		},
+		.set = ov9650_set_auto_gain,
+		.get = ov9650_get_auto_gain
+	}
+	},
+
+	.nmodes = 1,
+	.modes = {
+	{
+		M5602_DEFAULT_FRAME_WIDTH,
+		M5602_DEFAULT_FRAME_HEIGHT,
+		V4L2_PIX_FMT_SBGGR8,
+		V4L2_FIELD_NONE,
+		.sizeimage =
+			M5602_DEFAULT_FRAME_WIDTH * M5602_DEFAULT_FRAME_HEIGHT,
+		.bytesperline = M5602_DEFAULT_FRAME_WIDTH,
+		.colorspace = V4L2_COLORSPACE_SRGB,
+		.priv = 1
+	}
+	}
+};
+
+static const unsigned char preinit_ov9650[][3] =
+{
+	/* [INITCAM] */
+	{BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02},
+	{BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0},
+	{BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00},
+	{BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
+	{BRIDGE, M5602_XB_ADC_CTRL, 0xc0},
+	{BRIDGE, M5602_XB_SENSOR_CTRL, 0x00},
+
+	{BRIDGE, M5602_XB_SENSOR_TYPE, 0x08},
+	{BRIDGE, M5602_XB_GPIO_DIR, 0x05},
+	{BRIDGE, M5602_XB_GPIO_DAT, 0x04},
+	{BRIDGE, M5602_XB_GPIO_EN_H, 0x06},
+	{BRIDGE, M5602_XB_GPIO_DIR_H, 0x06},
+	{BRIDGE, M5602_XB_GPIO_DAT_H, 0x00},
+	{BRIDGE, M5602_XB_GPIO_DAT, 0x00},
+	{BRIDGE, M5602_XB_I2C_CLK_DIV, 0x0a},
+	/* Reset chip */
+	{SENSOR, OV9650_COM7, OV9650_REGISTER_RESET},
+	/* Enable double clock */
+	{SENSOR, OV9650_CLKRC, 0x80},
+	/* Do something out of spec with the power */
+	{SENSOR, OV9650_OFON, 0x40}
+};
+
+static const unsigned char init_ov9650[][3] =
+{
+	/* [INITCAM] */
+	{BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02},
+	{BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0},
+	{BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00},
+	{BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
+	{BRIDGE, M5602_XB_ADC_CTRL, 0xc0},
+	{BRIDGE, M5602_XB_SENSOR_CTRL, 0x00},
+
+	{BRIDGE, M5602_XB_SENSOR_TYPE, 0x08},
+	{BRIDGE, M5602_XB_GPIO_DIR, 0x05},
+	{BRIDGE, M5602_XB_GPIO_DAT, 0x04},
+	{BRIDGE, M5602_XB_GPIO_EN_H, 0x06},
+	{BRIDGE, M5602_XB_GPIO_DIR_H, 0x06},
+	{BRIDGE, M5602_XB_GPIO_DAT_H, 0x00},
+	{BRIDGE, M5602_XB_GPIO_DAT, 0x00},
+	{BRIDGE, M5602_XB_I2C_CLK_DIV, 0x0a},
+	/* Reset chip */
+	{SENSOR, OV9650_COM7, OV9650_REGISTER_RESET},
+	/* Enable double clock */
+	{SENSOR, OV9650_CLKRC, 0x80},
+	/* Do something out of spec with the power */
+	{SENSOR, OV9650_OFON, 0x40},
+
+	/* Set QQVGA */
+	{SENSOR, OV9650_COM1, 0x20},
+	/* Set fast AGC/AEC algorithm with unlimited step size */
+	{SENSOR, OV9650_COM8, OV9650_FAST_AGC_AEC |
+			      OV9650_AEC_UNLIM_STEP_SIZE |
+			      OV9650_AWB_EN | OV9650_AGC_EN},
+
+	{SENSOR, OV9650_CHLF, 0x10},
+	{SENSOR, OV9650_ARBLM, 0xbf},
+	{SENSOR, OV9650_ACOM38, 0x81},
+	/* Turn off color matrix coefficient double option */
+	{SENSOR, OV9650_COM16, 0x00},
+		/* Enable color matrix for RGB/YUV, Delay Y channel,
+	set output Y/UV delay to 1 */
+	{SENSOR, OV9650_COM13, 0x19},
+	/* Enable digital BLC, Set output mode to U Y V Y */
+	{SENSOR, OV9650_TSLB, 0x0c},
+	/* Limit the AGC/AEC stable upper region */
+	{SENSOR, OV9650_COM24, 0x00},
+	/* Enable HREF and some out of spec things */
+	{SENSOR, OV9650_COM12, 0x73},
+		/* Set all DBLC offset signs to positive and
+	do some out of spec stuff */
+	{SENSOR, OV9650_DBLC1, 0xdf},
+	{SENSOR, OV9650_COM21, 0x06},
+	{SENSOR, OV9650_RSVD35, 0x91},
+	/* Necessary, no camera stream without it */
+	{SENSOR, OV9650_RSVD16, 0x06},
+	{SENSOR, OV9650_RSVD94, 0x99},
+	{SENSOR, OV9650_RSVD95, 0x99},
+	{SENSOR, OV9650_RSVD96, 0x04},
+	/* Enable full range output */
+	{SENSOR, OV9650_COM15, 0x0},
+		/* Enable HREF at optical black, enable ADBLC bias,
+	enable ADBLC, reset timings at format change */
+	{SENSOR, OV9650_COM6, 0x4b},
+	/* Subtract 32 from the B channel bias */
+	{SENSOR, OV9650_BBIAS, 0xa0},
+	/* Subtract 32 from the Gb channel bias */
+	{SENSOR, OV9650_GbBIAS, 0xa0},
+	/* Do not bypass the analog BLC and to some out of spec stuff */
+	{SENSOR, OV9650_Gr_COM, 0x00},
+	/* Subtract 32 from the R channel bias */
+	{SENSOR, OV9650_RBIAS, 0xa0},
+	/* Subtract 32 from the R channel bias */
+	{SENSOR, OV9650_RBIAS, 0x0},
+	{SENSOR, OV9650_COM26, 0x80},
+	{SENSOR, OV9650_ACOMA9, 0x98},
+	/* Set the AGC/AEC stable region upper limit */
+	{SENSOR, OV9650_AEW, 0x68},
+	/* Set the AGC/AEC stable region lower limit */
+	{SENSOR, OV9650_AEB, 0x5c},
+	/* Set the high and low limit nibbles to 3 */
+	{SENSOR, OV9650_VPT, 0xc3},
+		/* Set the Automatic Gain Ceiling (AGC) to 128x,
+	drop VSYNC at frame drop,
+	limit exposure timing,
+	drop frame when the AEC step is larger than the exposure gap */
+	{SENSOR, OV9650_COM9, 0x6e},
+	/* Set VSYNC negative, Set RESET to SLHS (slave mode horizontal sync)
+	and set PWDN to SLVS (slave mode vertical sync) */
+	{SENSOR, OV9650_COM10, 0x42},
+	/* Set horizontal column start high to default value */
+	{SENSOR, OV9650_HSTART, 0x1a},
+	/* Set horizontal column end */
+	{SENSOR, OV9650_HSTOP, 0xbf},
+	/* Complementing register to the two writes above */
+	{SENSOR, OV9650_HREF, 0xb2},
+	/* Set vertical row start high bits */
+	{SENSOR, OV9650_VSTRT, 0x02},
+	/* Set vertical row end low bits */
+	{SENSOR, OV9650_VSTOP, 0x7e},
+	/* Set complementing vertical frame control */
+	{SENSOR, OV9650_VREF, 0x10},
+	/* Set raw RGB output format with VGA resolution */
+	{SENSOR, OV9650_COM7, OV9650_VGA_SELECT |
+			      OV9650_RGB_SELECT |
+			      OV9650_RAW_RGB_SELECT},
+	{SENSOR, OV9650_ADC, 0x04},
+	{SENSOR, OV9650_HV, 0x40},
+	/* Enable denoise, and white-pixel erase */
+	{SENSOR, OV9650_COM22, 0x23},
+
+	/* Set the high bits of the exposure value */
+	{SENSOR, OV9650_AECH, ((EXPOSURE_DEFAULT & 0xff00) >> 8)},
+
+	/* Set the low bits of the exposure value */
+	{SENSOR, OV9650_COM1, (EXPOSURE_DEFAULT & 0xff)},
+	{SENSOR, OV9650_GAIN, GAIN_DEFAULT},
+	{SENSOR, OV9650_BLUE, BLUE_GAIN_DEFAULT},
+	{SENSOR, OV9650_RED, RED_GAIN_DEFAULT},
+
+	{SENSOR, OV9650_COM3, OV9650_VARIOPIXEL},
+	{SENSOR, OV9650_COM5, OV9650_SYSTEM_CLK_SEL},
+
+	{BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x82},
+	{BRIDGE, M5602_XB_LINE_OF_FRAME_L, 0x00},
+	{BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82},
+	{BRIDGE, M5602_XB_PIX_OF_LINE_L, 0x00},
+	{BRIDGE, M5602_XB_SIG_INI, 0x01},
+	{BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
+	{BRIDGE, M5602_XB_VSYNC_PARA, 0x09},
+	{BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
+	{BRIDGE, M5602_XB_VSYNC_PARA, 0x01},
+	{BRIDGE, M5602_XB_VSYNC_PARA, 0xe0},
+	{BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
+	{BRIDGE, M5602_XB_HSYNC_PARA, 0x00},
+	{BRIDGE, M5602_XB_HSYNC_PARA, 0x5e},
+	{BRIDGE, M5602_XB_HSYNC_PARA, 0x02},
+	{BRIDGE, M5602_XB_HSYNC_PARA, 0xde}
+};
+
+static const unsigned char power_down_ov9650[][3] =
+{
+	{BRIDGE, M5602_XB_SEN_CLK_DIV, 0x04},
+	{BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
+	{SENSOR, OV9650_COM7, 0x80},
+	{SENSOR, OV9650_OFON, 0xf4},
+	{SENSOR, OV9650_MVFP, 0x80},
+	{SENSOR, OV9650_DBLV, 0x3f},
+	{SENSOR, OV9650_RSVD36, 0x49},
+	{SENSOR, OV9650_COM7, 0x05},
+
+	{BRIDGE, M5602_XB_GPIO_DIR, 0x05},
+	{BRIDGE, M5602_XB_GPIO_DAT, 0x04},
+	{BRIDGE, M5602_XB_GPIO_EN_H, 0x06},
+	{BRIDGE, M5602_XB_GPIO_EN_L, 0x06},
+	{BRIDGE, M5602_XB_GPIO_DAT_H, 0x02},
+	{BRIDGE, M5602_XB_SEN_CLK_DIV, 0x04},
+	{BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0}
+};
+
+/* Vertically and horizontally flips the image if matched, needed for machines
+   where the sensor is mounted upside down */
+static
+    const
+	struct dmi_system_id ov9650_flip_dmi_table[] = {
+	{
+		.ident = "ASUS A6VC",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "A6VC")
+		}
+	},
+	{
+		.ident = "ASUS A6VM",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "A6VM")
+		}
+	},
+	{
+		.ident = "ASUS A6JC",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "A6JC")
+		}
+	},
+	{
+		.ident = "ASUS A6Kt",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "A6Kt")
+		}
+	},
+	{ }
+};
+
+#endif
diff --git a/drivers/media/video/gspca/m5602/m5602_po1030.c b/drivers/media/video/gspca/m5602/m5602_po1030.c
new file mode 100644
index 0000000..08c015bd
--- /dev/null
+++ b/drivers/media/video/gspca/m5602/m5602_po1030.c
@@ -0,0 +1,336 @@
+/*
+ * Driver for the po1030 sensor
+ *
+ * Copyright (c) 2008 Erik Andren
+ * Copyright (c) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project.
+ * Copyright (c) 2005 m5603x Linux Driver Project <m5602@x3ng.com.br>
+ *
+ * Portions of code to USB interface and ALi driver software,
+ * Copyright (c) 2006 Willem Duinker
+ * v4l2 interface modeled after the V4L2 driver
+ * for SN9C10x PC Camera Controllers
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2.
+ *
+ */
+
+#include "m5602_po1030.h"
+
+int po1030_probe(struct sd *sd)
+{
+	u8 prod_id = 0, ver_id = 0, i;
+
+	if (force_sensor) {
+		if (force_sensor == PO1030_SENSOR) {
+			info("Forcing a %s sensor", po1030.name);
+			goto sensor_found;
+		}
+		/* If we want to force another sensor, don't try to probe this
+		 * one */
+		return -ENODEV;
+	}
+
+	info("Probing for a po1030 sensor");
+
+	/* Run the pre-init to actually probe the unit */
+	for (i = 0; i < ARRAY_SIZE(preinit_po1030); i++) {
+		u8 data = preinit_po1030[i][2];
+		if (preinit_po1030[i][0] == SENSOR)
+			po1030_write_sensor(sd,
+				preinit_po1030[i][1], &data, 1);
+		else
+			m5602_write_bridge(sd, preinit_po1030[i][1], data);
+	}
+
+	if (po1030_read_sensor(sd, 0x3, &prod_id, 1))
+		return -ENODEV;
+
+	if (po1030_read_sensor(sd, 0x4, &ver_id, 1))
+		return -ENODEV;
+
+	if ((prod_id == 0x02) && (ver_id == 0xef)) {
+		info("Detected a po1030 sensor");
+		goto sensor_found;
+	}
+	return -ENODEV;
+
+sensor_found:
+	sd->gspca_dev.cam.cam_mode = po1030.modes;
+	sd->gspca_dev.cam.nmodes = po1030.nmodes;
+	sd->desc->ctrls = po1030.ctrls;
+	sd->desc->nctrls = po1030.nctrls;
+	return 0;
+}
+
+int po1030_read_sensor(struct sd *sd, const u8 address,
+			u8 *i2c_data, const u8 len)
+{
+	int err, i;
+
+	do {
+		err = m5602_read_bridge(sd, M5602_XB_I2C_STATUS, i2c_data);
+	} while ((*i2c_data & I2C_BUSY) && !err);
+
+	m5602_write_bridge(sd, M5602_XB_I2C_DEV_ADDR,
+			   sd->sensor->i2c_slave_id);
+	m5602_write_bridge(sd, M5602_XB_I2C_REG_ADDR, address);
+	m5602_write_bridge(sd, M5602_XB_I2C_CTRL, 0x10 + len);
+	m5602_write_bridge(sd, M5602_XB_I2C_CTRL, 0x08);
+
+	for (i = 0; i < len; i++) {
+		err = m5602_read_bridge(sd, M5602_XB_I2C_DATA, &(i2c_data[i]));
+
+		PDEBUG(DBG_TRACE, "Reading sensor register "
+				"0x%x containing 0x%x ", address, *i2c_data);
+	}
+	return (err < 0) ? err : 0;
+}
+
+int po1030_write_sensor(struct sd *sd, const u8 address,
+			u8 *i2c_data, const u8 len)
+{
+	int err, i;
+	u8 *p;
+	struct usb_device *udev = sd->gspca_dev.dev;
+	__u8 *buf = sd->gspca_dev.usb_buf;
+
+	/* The po1030 only supports one byte writes */
+	if (len > 1 || !len)
+		return -EINVAL;
+
+	memcpy(buf, sensor_urb_skeleton, sizeof(sensor_urb_skeleton));
+
+	buf[11] = sd->sensor->i2c_slave_id;
+	buf[15] = address;
+
+	p = buf + 16;
+
+	/* Copy a four byte write sequence for each byte to be written to */
+	for (i = 0; i < len; i++) {
+		memcpy(p, sensor_urb_skeleton + 16, 4);
+		p[3] = i2c_data[i];
+		p += 4;
+		PDEBUG(DBG_TRACE, "Writing sensor register 0x%x with 0x%x",
+		       address, i2c_data[i]);
+	}
+
+	/* Copy the footer */
+	memcpy(p, sensor_urb_skeleton + 20, 4);
+
+	/* Set the total length */
+	p[3] = 0x10 + len;
+
+	err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+			      0x04, 0x40, 0x19,
+			      0x0000, buf,
+			      20 + len * 4, M5602_URB_MSG_TIMEOUT);
+
+	return (err < 0) ? err : 0;
+}
+
+int po1030_init(struct sd *sd)
+{
+	int i, err = 0;
+
+	/* Init the sensor */
+	for (i = 0; i < ARRAY_SIZE(init_po1030); i++) {
+		u8 data[2] = {0x00, 0x00};
+
+		switch (init_po1030[i][0]) {
+		case BRIDGE:
+			err = m5602_write_bridge(sd,
+				init_po1030[i][1],
+				init_po1030[i][2]);
+			break;
+
+		case SENSOR:
+			data[0] = init_po1030[i][2];
+			err = po1030_write_sensor(sd,
+				init_po1030[i][1], data, 1);
+			break;
+
+		case SENSOR_LONG:
+			data[0] = init_po1030[i][2];
+			data[1] = init_po1030[i][3];
+			err = po1030_write_sensor(sd,
+				init_po1030[i][1], data, 2);
+			break;
+		default:
+			info("Invalid stream command, exiting init");
+			return -EINVAL;
+		}
+	}
+
+	if (dump_sensor)
+		po1030_dump_registers(sd);
+
+	return (err < 0) ? err : 0;
+}
+
+int po1030_get_exposure(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	u8 i2c_data;
+	int err;
+
+	err = po1030_read_sensor(sd, PO1030_REG_INTEGLINES_H,
+				 &i2c_data, 1);
+	if (err < 0)
+		goto out;
+	*val = (i2c_data << 8);
+
+	err = po1030_read_sensor(sd, PO1030_REG_INTEGLINES_M,
+				 &i2c_data, 1);
+	*val |= i2c_data;
+
+	PDEBUG(DBG_V4L2_CID, "Exposure read as %d", *val);
+out:
+	return (err < 0) ? err : 0;
+}
+
+int po1030_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	u8 i2c_data;
+	int err;
+
+	PDEBUG(DBG_V4L2, "Set exposure to %d", val & 0xffff);
+
+	i2c_data = ((val & 0xff00) >> 8);
+	PDEBUG(DBG_V4L2, "Set exposure to high byte to 0x%x",
+	       i2c_data);
+
+	err = po1030_write_sensor(sd, PO1030_REG_INTEGLINES_H,
+				  &i2c_data, 1);
+	if (err < 0)
+		goto out;
+
+	i2c_data = (val & 0xff);
+	PDEBUG(DBG_V4L2, "Set exposure to low byte to 0x%x",
+	       i2c_data);
+	err = po1030_write_sensor(sd, PO1030_REG_INTEGLINES_M,
+				  &i2c_data, 1);
+
+out:
+	return (err < 0) ? err : 0;
+}
+
+int po1030_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	u8 i2c_data;
+	int err;
+
+	err = po1030_read_sensor(sd, PO1030_REG_GLOBALGAIN,
+				 &i2c_data, 1);
+	*val = i2c_data;
+	PDEBUG(DBG_V4L2_CID, "Read global gain %d", *val);
+
+	return (err < 0) ? err : 0;
+}
+
+int po1030_set_gain(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	u8 i2c_data;
+	int err;
+
+	i2c_data = val & 0xff;
+	PDEBUG(DBG_V4L2, "Set global gain to %d", i2c_data);
+	err = po1030_write_sensor(sd, PO1030_REG_GLOBALGAIN,
+				  &i2c_data, 1);
+	return (err < 0) ? err : 0;
+}
+
+int po1030_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	u8 i2c_data;
+	int err;
+
+	err = po1030_read_sensor(sd, PO1030_REG_RED_GAIN,
+				 &i2c_data, 1);
+	*val = i2c_data;
+	PDEBUG(DBG_V4L2_CID, "Read red gain %d", *val);
+	return (err < 0) ? err : 0;
+}
+
+int po1030_set_red_balance(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	u8 i2c_data;
+	int err;
+
+	i2c_data = val & 0xff;
+	PDEBUG(DBG_V4L2, "Set red gain to %d", i2c_data);
+	err = po1030_write_sensor(sd, PO1030_REG_RED_GAIN,
+				  &i2c_data, 1);
+	return (err < 0) ? err : 0;
+}
+
+int po1030_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	u8 i2c_data;
+	int err;
+
+	err = po1030_read_sensor(sd, PO1030_REG_BLUE_GAIN,
+				 &i2c_data, 1);
+	*val = i2c_data;
+	PDEBUG(DBG_V4L2_CID, "Read blue gain %d", *val);
+
+	return (err < 0) ? err : 0;
+}
+
+int po1030_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	u8 i2c_data;
+	int err;
+	i2c_data = val & 0xff;
+	PDEBUG(DBG_V4L2, "Set blue gain to %d", i2c_data);
+	err = po1030_write_sensor(sd, PO1030_REG_BLUE_GAIN,
+				  &i2c_data, 1);
+
+	return (err < 0) ? err : 0;
+}
+
+int po1030_power_down(struct sd *sd)
+{
+	return 0;
+}
+
+void po1030_dump_registers(struct sd *sd)
+{
+	int address;
+	u8 value = 0;
+
+	info("Dumping the po1030 sensor core registers");
+	for (address = 0; address < 0x7f; address++) {
+		po1030_read_sensor(sd, address, &value, 1);
+		info("register 0x%x contains 0x%x",
+		     address, value);
+	}
+
+	info("po1030 register state dump complete");
+
+	info("Probing for which registers that are read/write");
+	for (address = 0; address < 0xff; address++) {
+		u8 old_value, ctrl_value;
+		u8 test_value[2] = {0xff, 0xff};
+
+		po1030_read_sensor(sd, address, &old_value, 1);
+		po1030_write_sensor(sd, address, test_value, 1);
+		po1030_read_sensor(sd, address, &ctrl_value, 1);
+
+		if (ctrl_value == test_value[0])
+			info("register 0x%x is writeable", address);
+		else
+			info("register 0x%x is read only", address);
+
+		/* Restore original value */
+		po1030_write_sensor(sd, address, &old_value, 1);
+	}
+}
diff --git a/drivers/media/video/gspca/m5602/m5602_po1030.h b/drivers/media/video/gspca/m5602/m5602_po1030.h
new file mode 100644
index 0000000..68f34c9
--- /dev/null
+++ b/drivers/media/video/gspca/m5602/m5602_po1030.h
@@ -0,0 +1,478 @@
+/*
+ * Driver for the po1030 sensor.
+ * This is probably a pixel plus sensor but we haven't identified it yet
+ *
+ * Copyright (c) 2008 Erik Andren
+ * Copyright (c) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project.
+ * Copyright (c) 2005 m5603x Linux Driver Project <m5602@x3ng.com.br>
+ *
+ * Portions of code to USB interface and ALi driver software,
+ * Copyright (c) 2006 Willem Duinker
+ * v4l2 interface modeled after the V4L2 driver
+ * for SN9C10x PC Camera Controllers
+ *
+ * Register defines taken from Pascal Stangs Proxycon Armlib
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2.
+ *
+ */
+
+#ifndef M5602_PO1030_H_
+#define M5602_PO1030_H_
+
+#include "m5602_sensor.h"
+
+/*****************************************************************************/
+
+#define PO1030_REG_DEVID_H		0x00
+#define PO1030_REG_DEVID_L		0x01
+#define PO1030_REG_FRAMEWIDTH_H		0x04
+#define PO1030_REG_FRAMEWIDTH_L		0x05
+#define PO1030_REG_FRAMEHEIGHT_H	0x06
+#define PO1030_REG_FRAMEHEIGHT_L	0x07
+#define PO1030_REG_WINDOWX_H		0x08
+#define PO1030_REG_WINDOWX_L		0x09
+#define PO1030_REG_WINDOWY_H		0x0a
+#define PO1030_REG_WINDOWY_L		0x0b
+#define PO1030_REG_WINDOWWIDTH_H	0x0c
+#define PO1030_REG_WINDOWWIDTH_L	0x0d
+#define PO1030_REG_WINDOWHEIGHT_H	0x0e
+#define PO1030_REG_WINDOWHEIGHT_L	0x0f
+
+#define PO1030_REG_GLOBALIBIAS		0x12
+#define PO1030_REG_PIXELIBIAS		0x13
+
+#define PO1030_REG_GLOBALGAIN		0x15
+#define PO1030_REG_RED_GAIN		0x16
+#define PO1030_REG_GREEN_1_GAIN		0x17
+#define PO1030_REG_BLUE_GAIN		0x18
+#define PO1030_REG_GREEN_2_GAIN		0x19
+
+#define PO1030_REG_INTEGLINES_H		0x1a
+#define PO1030_REG_INTEGLINES_M		0x1b
+#define PO1030_REG_INTEGLINES_L		0x1c
+
+#define PO1030_REG_CONTROL1		0x1d
+#define PO1030_REG_CONTROL2		0x1e
+#define PO1030_REG_CONTROL3		0x1f
+#define PO1030_REG_CONTROL4		0x20
+
+#define PO1030_REG_PERIOD50_H		0x23
+#define PO1030_REG_PERIOD50_L		0x24
+#define PO1030_REG_PERIOD60_H		0x25
+#define PO1030_REG_PERIOD60_L		0x26
+#define PO1030_REG_REGCLK167		0x27
+#define PO1030_REG_DELTA50		0x28
+#define PO1030_REG_DELTA60		0x29
+
+#define PO1030_REG_ADCOFFSET		0x2c
+
+/* Gamma Correction Coeffs */
+#define PO1030_REG_GC0			0x2d
+#define PO1030_REG_GC1			0x2e
+#define PO1030_REG_GC2			0x2f
+#define PO1030_REG_GC3			0x30
+#define PO1030_REG_GC4			0x31
+#define PO1030_REG_GC5			0x32
+#define PO1030_REG_GC6			0x33
+#define PO1030_REG_GC7			0x34
+
+/* Color Transform Matrix */
+#define PO1030_REG_CT0			0x35
+#define PO1030_REG_CT1			0x36
+#define PO1030_REG_CT2			0x37
+#define PO1030_REG_CT3			0x38
+#define PO1030_REG_CT4			0x39
+#define PO1030_REG_CT5			0x3a
+#define PO1030_REG_CT6			0x3b
+#define PO1030_REG_CT7			0x3c
+#define PO1030_REG_CT8			0x3d
+
+#define PO1030_REG_AUTOCTRL1		0x3e
+#define PO1030_REG_AUTOCTRL2		0x3f
+
+#define PO1030_REG_YTARGET		0x40
+#define PO1030_REG_GLOBALGAINMIN	0x41
+#define PO1030_REG_GLOBALGAINMAX	0x42
+
+/* Output format control */
+#define PO1030_REG_OUTFORMCTRL1		0x5a
+#define PO1030_REG_OUTFORMCTRL2		0x5b
+#define PO1030_REG_OUTFORMCTRL3		0x5c
+#define PO1030_REG_OUTFORMCTRL4		0x5d
+#define PO1030_REG_OUTFORMCTRL5		0x5e
+
+/* Imaging coefficients */
+#define PO1030_REG_YBRIGHT		0x73
+#define PO1030_REG_YCONTRAST		0x74
+#define PO1030_REG_YSATURATION		0x75
+
+/*****************************************************************************/
+
+#define PO1030_GLOBAL_GAIN_DEFAULT	0x12
+#define PO1030_EXPOSURE_DEFAULT		0xf0ff
+#define PO1030_BLUE_GAIN_DEFAULT 	0x40
+#define PO1030_RED_GAIN_DEFAULT 	0x40
+
+/*****************************************************************************/
+
+/* Kernel module parameters */
+extern int force_sensor;
+extern int dump_sensor;
+extern unsigned int m5602_debug;
+
+int po1030_probe(struct sd *sd);
+int po1030_init(struct sd *sd);
+int po1030_power_down(struct sd *sd);
+
+void po1030_dump_registers(struct sd *sd);
+
+int po1030_read_sensor(struct sd *sd, const u8 address,
+			      u8 *i2c_data, const u8 len);
+int po1030_write_sensor(struct sd *sd, const u8 address,
+			       u8 *i2c_data, const u8 len);
+
+int po1030_get_exposure(struct gspca_dev *gspca_dev, __s32 *val);
+int po1030_set_exposure(struct gspca_dev *gspca_dev, __s32 val);
+int po1030_get_gain(struct gspca_dev *gspca_dev, __s32 *val);
+int po1030_set_gain(struct gspca_dev *gspca_dev, __s32 val);
+int po1030_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val);
+int po1030_set_red_balance(struct gspca_dev *gspca_dev, __s32 val);
+int po1030_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val);
+int po1030_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val);
+
+static struct m5602_sensor po1030 = {
+	.name = "PO1030",
+
+	.i2c_slave_id = 0xdc,
+
+	.probe = po1030_probe,
+	.init = po1030_init,
+	.power_down = po1030_power_down,
+
+	.nctrls = 4,
+	.ctrls = {
+	{
+		{
+			.id 		= V4L2_CID_GAIN,
+			.type 		= V4L2_CTRL_TYPE_INTEGER,
+			.name 		= "gain",
+			.minimum 	= 0x00,
+			.maximum 	= 0xff,
+			.step 		= 0x1,
+			.default_value 	= PO1030_GLOBAL_GAIN_DEFAULT,
+			.flags         	= V4L2_CTRL_FLAG_SLIDER
+		},
+		.set = po1030_set_gain,
+		.get = po1030_get_gain
+	}, {
+		{
+			.id 		= V4L2_CID_EXPOSURE,
+			.type 		= V4L2_CTRL_TYPE_INTEGER,
+			.name 		= "exposure",
+			.minimum 	= 0x00,
+			.maximum 	= 0xffff,
+			.step 		= 0x1,
+			.default_value 	= PO1030_EXPOSURE_DEFAULT,
+			.flags         	= V4L2_CTRL_FLAG_SLIDER
+		},
+		.set = po1030_set_exposure,
+		.get = po1030_get_exposure
+	}, {
+		{
+			.id 		= V4L2_CID_RED_BALANCE,
+			.type 		= V4L2_CTRL_TYPE_INTEGER,
+			.name 		= "red balance",
+			.minimum 	= 0x00,
+			.maximum 	= 0xff,
+			.step 		= 0x1,
+			.default_value 	= PO1030_RED_GAIN_DEFAULT,
+			.flags         	= V4L2_CTRL_FLAG_SLIDER
+		},
+		.set = po1030_set_red_balance,
+		.get = po1030_get_red_balance
+	}, {
+		{
+			.id 		= V4L2_CID_BLUE_BALANCE,
+			.type 		= V4L2_CTRL_TYPE_INTEGER,
+			.name 		= "blue balance",
+			.minimum 	= 0x00,
+			.maximum 	= 0xff,
+			.step 		= 0x1,
+			.default_value 	= PO1030_BLUE_GAIN_DEFAULT,
+			.flags         	= V4L2_CTRL_FLAG_SLIDER
+		},
+		.set = po1030_set_blue_balance,
+		.get = po1030_get_blue_balance
+	}
+	},
+	.nmodes = 1,
+	.modes = {
+	{
+		M5602_DEFAULT_FRAME_WIDTH,
+		M5602_DEFAULT_FRAME_HEIGHT,
+		V4L2_PIX_FMT_SBGGR8,
+		V4L2_FIELD_NONE,
+		.sizeimage =
+			M5602_DEFAULT_FRAME_WIDTH * M5602_DEFAULT_FRAME_HEIGHT,
+		.bytesperline = M5602_DEFAULT_FRAME_WIDTH,
+		.colorspace = V4L2_COLORSPACE_SRGB,
+		.priv = 1
+	}
+	}
+};
+
+static const unsigned char preinit_po1030[][3] =
+{
+	{BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02},
+	{BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0},
+	{BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00},
+	{BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
+	{BRIDGE, M5602_XB_ADC_CTRL, 0xc0},
+	{BRIDGE, M5602_XB_SENSOR_TYPE, 0x0d},
+	{BRIDGE, M5602_XB_SENSOR_CTRL, 0x00},
+	{BRIDGE, M5602_XB_ADC_CTRL, 0xc0},
+	{BRIDGE, M5602_XB_SENSOR_TYPE, 0x0c},
+
+	{SENSOR, PO1030_REG_AUTOCTRL2, 0x24},
+
+	{BRIDGE, M5602_XB_GPIO_DIR, 0x05},
+	{BRIDGE, M5602_XB_GPIO_DAT, 0x04},
+	{BRIDGE, M5602_XB_GPIO_EN_H, 0x06},
+	{BRIDGE, M5602_XB_GPIO_DIR_H, 0x06},
+	{BRIDGE, M5602_XB_GPIO_DAT_H, 0x02},
+	{BRIDGE, M5602_XB_SEN_CLK_DIV, 0x04},
+	{BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
+	{BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06},
+	{BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
+	{BRIDGE, M5602_XB_ADC_CTRL, 0xc0},
+	{BRIDGE, M5602_XB_SENSOR_TYPE, 0x0c},
+	{BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x81},
+	{BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82},
+	{BRIDGE, M5602_XB_SIG_INI, 0x01},
+	{BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
+	{BRIDGE, M5602_XB_VSYNC_PARA, 0x02},
+	{BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
+	{BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
+	{BRIDGE, M5602_XB_VSYNC_PARA, 0x01},
+	{BRIDGE, M5602_XB_VSYNC_PARA, 0xec},
+	{BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
+	{BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
+	{BRIDGE, M5602_XB_SIG_INI, 0x00},
+	{BRIDGE, M5602_XB_SIG_INI, 0x02},
+	{BRIDGE, M5602_XB_HSYNC_PARA, 0x00},
+	{BRIDGE, M5602_XB_HSYNC_PARA, 0x00},
+	{BRIDGE, M5602_XB_HSYNC_PARA, 0x02},
+	{BRIDGE, M5602_XB_HSYNC_PARA, 0x87},
+	{BRIDGE, M5602_XB_SIG_INI, 0x00},
+
+	{SENSOR, PO1030_REG_AUTOCTRL2, 0x24},
+
+	{BRIDGE, M5602_XB_GPIO_DIR, 0x05},
+	{BRIDGE, M5602_XB_GPIO_DAT, 0x04},
+	{BRIDGE, M5602_XB_GPIO_EN_H, 0x06},
+	{BRIDGE, M5602_XB_GPIO_DIR_H, 0x06},
+	{BRIDGE, M5602_XB_GPIO_DAT_H, 0x02},
+	{BRIDGE, M5602_XB_SEN_CLK_DIV, 0x04},
+	{BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
+	{BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00},
+	{BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
+	{BRIDGE, M5602_XB_ADC_CTRL, 0xc0},
+	{BRIDGE, M5602_XB_SENSOR_TYPE, 0x0c},
+	{BRIDGE, M5602_XB_GPIO_DIR, 0x05},
+	{BRIDGE, M5602_XB_GPIO_DAT, 0x00}
+};
+
+static const unsigned char init_po1030[][4] =
+{
+	{BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02},
+	{BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0},
+	/*sequence 1*/
+	{BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00},
+	{BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
+	{BRIDGE, M5602_XB_ADC_CTRL, 0xc0},
+	{BRIDGE, M5602_XB_SENSOR_TYPE, 0x0d},
+
+	{BRIDGE, M5602_XB_SENSOR_CTRL, 0x00},
+	{BRIDGE, M5602_XB_ADC_CTRL, 0xc0},
+	{BRIDGE, M5602_XB_SENSOR_TYPE, 0x0c},
+	/*end of sequence 1*/
+
+	/*sequence 2 (same as stop sequence)*/
+	{SENSOR, PO1030_REG_AUTOCTRL2, 0x24},
+	{BRIDGE, M5602_XB_GPIO_DIR, 0x05},
+	{BRIDGE, M5602_XB_GPIO_DAT, 0x04},
+	{BRIDGE, M5602_XB_GPIO_EN_H, 0x06},
+	{BRIDGE, M5602_XB_GPIO_DIR_H, 0x06},
+	{BRIDGE, M5602_XB_GPIO_DAT_H, 0x02},
+
+	{BRIDGE, M5602_XB_SEN_CLK_DIV, 0x04},
+	{BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
+	/*end of sequence 2*/
+
+	/*sequence 5*/
+	{BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06},
+	{BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
+	{BRIDGE, M5602_XB_ADC_CTRL, 0xc0},
+	{BRIDGE, M5602_XB_SENSOR_TYPE, 0x0c},
+	{BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x81},
+	{BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82},
+	{BRIDGE, M5602_XB_SIG_INI, 0x01},
+	{BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
+	{BRIDGE, M5602_XB_VSYNC_PARA, 0x02},
+	{BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
+	{BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
+	{BRIDGE, M5602_XB_VSYNC_PARA, 0x01},
+	{BRIDGE, M5602_XB_VSYNC_PARA, 0xec},
+	{BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
+	{BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
+	{BRIDGE, M5602_XB_SIG_INI, 0x00},
+	{BRIDGE, M5602_XB_SIG_INI, 0x02},
+	{BRIDGE, M5602_XB_HSYNC_PARA, 0x00},
+	{BRIDGE, M5602_XB_HSYNC_PARA, 0x00},
+	{BRIDGE, M5602_XB_HSYNC_PARA, 0x02},
+	{BRIDGE, M5602_XB_HSYNC_PARA, 0x87},
+	{BRIDGE, M5602_XB_SIG_INI, 0x00},
+	/*end of sequence 5*/
+
+	/*sequence 2 stop */
+	{SENSOR, PO1030_REG_AUTOCTRL2, 0x24},
+
+	{BRIDGE, M5602_XB_GPIO_DIR, 0x05},
+	{BRIDGE, M5602_XB_GPIO_DAT, 0x04},
+	{BRIDGE, M5602_XB_GPIO_EN_H, 0x06},
+	{BRIDGE, M5602_XB_GPIO_DIR_H, 0x06},
+	{BRIDGE, M5602_XB_GPIO_DAT_H, 0x02},
+	{BRIDGE, M5602_XB_SEN_CLK_DIV, 0x04},
+	{BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
+	/*end of sequence 2 stop */
+
+/* ---------------------------------
+ * end of init - begin of start
+ * --------------------------------- */
+
+	/*sequence 3*/
+	{BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00},
+	{BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
+	{BRIDGE, M5602_XB_ADC_CTRL, 0xc0},
+	{BRIDGE, M5602_XB_SENSOR_TYPE, 0x0c},
+	/*end of sequence 3*/
+	/*sequence 4*/
+	{BRIDGE, M5602_XB_GPIO_DIR, 0x05},
+	{BRIDGE, M5602_XB_GPIO_DAT, 0x00},
+	{BRIDGE, M5602_XB_GPIO_EN_H, 0x06},
+	{BRIDGE, M5602_XB_GPIO_EN_L, 0x00},
+
+	{SENSOR, PO1030_REG_AUTOCTRL2, 0x04},
+
+	/* Set the width to 751 */
+	{SENSOR, PO1030_REG_FRAMEWIDTH_H, 0x02},
+	{SENSOR, PO1030_REG_FRAMEWIDTH_L, 0xef},
+
+	/* Set the height to 540 */
+	{SENSOR, PO1030_REG_FRAMEHEIGHT_H, 0x02},
+	{SENSOR, PO1030_REG_FRAMEHEIGHT_L, 0x1c},
+
+	/* Set the x window to 1 */
+	{SENSOR, PO1030_REG_WINDOWX_H, 0x00},
+	{SENSOR, PO1030_REG_WINDOWX_L, 0x01},
+
+	/* Set the y window to 1 */
+	{SENSOR, PO1030_REG_WINDOWY_H, 0x00},
+	{SENSOR, PO1030_REG_WINDOWX_L, 0x01},
+
+	{SENSOR, PO1030_REG_WINDOWWIDTH_H, 0x02},
+	{SENSOR, PO1030_REG_WINDOWWIDTH_L, 0x87},
+	{SENSOR, PO1030_REG_WINDOWHEIGHT_H, 0x01},
+	{SENSOR, PO1030_REG_WINDOWHEIGHT_L, 0xe3},
+
+	{SENSOR, PO1030_REG_OUTFORMCTRL2, 0x04},
+	{SENSOR, PO1030_REG_OUTFORMCTRL2, 0x04},
+	{SENSOR, PO1030_REG_AUTOCTRL1, 0x08},
+	{SENSOR, PO1030_REG_CONTROL2, 0x03},
+	{SENSOR, 0x21, 0x90},
+	{SENSOR, PO1030_REG_YTARGET, 0x60},
+	{SENSOR, 0x59, 0x13},
+	{SENSOR, PO1030_REG_OUTFORMCTRL1, 0x40},
+	{SENSOR, 0x5f, 0x00},
+	{SENSOR, 0x60, 0x80},
+	{SENSOR, 0x78, 0x14},
+	{SENSOR, 0x6f, 0x01},
+	{SENSOR, PO1030_REG_CONTROL1, 0x18},
+	{SENSOR, PO1030_REG_GLOBALGAINMAX, 0x14},
+	{SENSOR, 0x63, 0x38},
+	{SENSOR, 0x64, 0x38},
+	{SENSOR, PO1030_REG_CONTROL1, 0x58},
+	{SENSOR, PO1030_REG_RED_GAIN, 0x30},
+	{SENSOR, PO1030_REG_GREEN_1_GAIN, 0x30},
+	{SENSOR, PO1030_REG_BLUE_GAIN, 0x30},
+	{SENSOR, PO1030_REG_GREEN_2_GAIN, 0x30},
+	{SENSOR, PO1030_REG_GC0, 0x10},
+	{SENSOR, PO1030_REG_GC1, 0x20},
+	{SENSOR, PO1030_REG_GC2, 0x40},
+	{SENSOR, PO1030_REG_GC3, 0x60},
+	{SENSOR, PO1030_REG_GC4, 0x80},
+	{SENSOR, PO1030_REG_GC5, 0xa0},
+	{SENSOR, PO1030_REG_GC6, 0xc0},
+	{SENSOR, PO1030_REG_GC7, 0xff},
+	/*end of sequence 4*/
+	/*sequence 5*/
+	{BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06},
+	{BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
+	{BRIDGE, M5602_XB_ADC_CTRL, 0xc0},
+	{BRIDGE, M5602_XB_SENSOR_TYPE, 0x0c},
+	{BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x81},
+	{BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82},
+	{BRIDGE, M5602_XB_SIG_INI, 0x01},
+	{BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
+	{BRIDGE, M5602_XB_VSYNC_PARA, 0x02},
+	{BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
+	{BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
+	{BRIDGE, M5602_XB_VSYNC_PARA, 0x01},
+	{BRIDGE, M5602_XB_VSYNC_PARA, 0xec},
+	{BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
+	{BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
+	{BRIDGE, M5602_XB_SIG_INI, 0x00},
+	{BRIDGE, M5602_XB_SIG_INI, 0x00},
+	{BRIDGE, M5602_XB_HSYNC_PARA, 0x00},
+	{BRIDGE, M5602_XB_HSYNC_PARA, 0x00},
+	{BRIDGE, M5602_XB_HSYNC_PARA, 0x02},
+	{BRIDGE, M5602_XB_HSYNC_PARA, 0x7e},
+	{BRIDGE, M5602_XB_SIG_INI, 0x00},
+	/*end of sequence 5*/
+
+	/*sequence 6*/
+	/* Changing 40 in f0 the image becomes green in bayer mode and red in
+	 * rgb mode */
+	{SENSOR, PO1030_REG_RED_GAIN, PO1030_RED_GAIN_DEFAULT},
+	/* in changing 40 in f0 the image becomes green in bayer mode and red in
+	 * rgb mode */
+	{SENSOR, PO1030_REG_BLUE_GAIN, PO1030_BLUE_GAIN_DEFAULT},
+
+	/* with a very low lighted environment increase the exposure but
+	 * decrease the FPS (Frame Per Second) */
+	{BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00},
+	{BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
+
+	/* Controls high exposure more than SENSOR_LOW_EXPOSURE, use only in
+	 * low lighted environment (f0 is more than ff ?)*/
+	{SENSOR, PO1030_REG_INTEGLINES_H, ((PO1030_EXPOSURE_DEFAULT >> 2)
+		& 0xff)},
+
+	/* Controls middle exposure, use only in high lighted environment */
+	{SENSOR, PO1030_REG_INTEGLINES_M, PO1030_EXPOSURE_DEFAULT & 0xff},
+
+	/* Controls clarity (not sure) */
+	{SENSOR, PO1030_REG_INTEGLINES_L, 0x00},
+	/* Controls gain (the image is more lighted) */
+	{SENSOR, PO1030_REG_GLOBALGAIN, PO1030_GLOBAL_GAIN_DEFAULT},
+
+	/* Sets the width */
+	{SENSOR, PO1030_REG_FRAMEWIDTH_H, 0x02},
+	{SENSOR, PO1030_REG_FRAMEWIDTH_L, 0xef}
+	/*end of sequence 6*/
+};
+
+#endif
diff --git a/drivers/media/video/gspca/m5602/m5602_s5k4aa.c b/drivers/media/video/gspca/m5602/m5602_s5k4aa.c
new file mode 100644
index 0000000..6820256
--- /dev/null
+++ b/drivers/media/video/gspca/m5602/m5602_s5k4aa.c
@@ -0,0 +1,463 @@
+/*
+ * Driver for the s5k4aa sensor
+ *
+ * Copyright (C) 2008 Erik Andren
+ * Copyright (C) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project.
+ * Copyright (C) 2005 m5603x Linux Driver Project <m5602@x3ng.com.br>
+ *
+ * Portions of code to USB interface and ALi driver software,
+ * Copyright (c) 2006 Willem Duinker
+ * v4l2 interface modeled after the V4L2 driver
+ * for SN9C10x PC Camera Controllers
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2.
+ *
+ */
+
+#include "m5602_s5k4aa.h"
+
+int s5k4aa_probe(struct sd *sd)
+{
+	u8 prod_id[6] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+	const u8 expected_prod_id[6] = {0x00, 0x10, 0x00, 0x4b, 0x33, 0x75};
+	int i, err = 0;
+
+	if (force_sensor) {
+		if (force_sensor == S5K4AA_SENSOR) {
+			info("Forcing a %s sensor", s5k4aa.name);
+			goto sensor_found;
+		}
+		/* If we want to force another sensor, don't try to probe this
+		 * one */
+		return -ENODEV;
+	}
+
+	info("Probing for a s5k4aa sensor");
+
+	/* Preinit the sensor */
+	for (i = 0; i < ARRAY_SIZE(preinit_s5k4aa) && !err; i++) {
+		u8 data[2] = {0x00, 0x00};
+
+		switch (preinit_s5k4aa[i][0]) {
+		case BRIDGE:
+			err = m5602_write_bridge(sd,
+						 preinit_s5k4aa[i][1],
+						 preinit_s5k4aa[i][2]);
+			break;
+
+		case SENSOR:
+			data[0] = preinit_s5k4aa[i][2];
+			err = s5k4aa_write_sensor(sd,
+						  preinit_s5k4aa[i][1],
+						  data, 1);
+			break;
+
+		case SENSOR_LONG:
+			data[0] = preinit_s5k4aa[i][2];
+			data[1] = preinit_s5k4aa[i][3];
+			err = s5k4aa_write_sensor(sd,
+						  preinit_s5k4aa[i][1],
+						  data, 2);
+			break;
+		default:
+			info("Invalid stream command, exiting init");
+			return -EINVAL;
+		}
+	}
+
+	/* Test some registers, but we don't know their exact meaning yet */
+	if (s5k4aa_read_sensor(sd, 0x00, prod_id, sizeof(prod_id)))
+		return -ENODEV;
+
+	if (memcmp(prod_id, expected_prod_id, sizeof(prod_id)))
+		return -ENODEV;
+	else
+		info("Detected a s5k4aa sensor");
+sensor_found:
+	sd->gspca_dev.cam.cam_mode = s5k4aa.modes;
+	sd->gspca_dev.cam.nmodes = s5k4aa.nmodes;
+	sd->desc->ctrls = s5k4aa.ctrls;
+	sd->desc->nctrls = s5k4aa.nctrls;
+
+	return 0;
+}
+
+int s5k4aa_read_sensor(struct sd *sd, const u8 address,
+		       u8 *i2c_data, const u8 len)
+{
+	int err, i;
+
+	do {
+		err = m5602_read_bridge(sd, M5602_XB_I2C_STATUS, i2c_data);
+	} while ((*i2c_data & I2C_BUSY) && !err);
+	if (err < 0)
+		goto out;
+
+	err = m5602_write_bridge(sd, M5602_XB_I2C_DEV_ADDR,
+				 sd->sensor->i2c_slave_id);
+	if (err < 0)
+		goto out;
+
+	err = m5602_write_bridge(sd, M5602_XB_I2C_REG_ADDR, address);
+	if (err < 0)
+		goto out;
+
+	err = m5602_write_bridge(sd, M5602_XB_I2C_CTRL, 0x18 + len);
+	if (err < 0)
+		goto out;
+
+	do {
+		err = m5602_read_bridge(sd, M5602_XB_I2C_STATUS, i2c_data);
+	} while ((*i2c_data & I2C_BUSY) && !err);
+	if (err < 0)
+		goto out;
+
+	for (i = 0; (i < len) & !err; i++) {
+		err = m5602_read_bridge(sd, M5602_XB_I2C_DATA, &(i2c_data[i]));
+
+		PDEBUG(DBG_TRACE, "Reading sensor register "
+				  "0x%x containing 0x%x ", address, *i2c_data);
+	}
+out:
+	return (err < 0) ? err : 0;
+}
+
+int s5k4aa_write_sensor(struct sd *sd, const u8 address,
+			u8 *i2c_data, const u8 len)
+{
+	int err, i;
+	u8 *p;
+	struct usb_device *udev = sd->gspca_dev.dev;
+	__u8 *buf = sd->gspca_dev.usb_buf;
+
+	/* No sensor with a data width larger than 16 bits has yet been seen */
+	if (len > 2 || !len)
+		return -EINVAL;
+
+	memcpy(buf, sensor_urb_skeleton,
+	       sizeof(sensor_urb_skeleton));
+
+	buf[11] = sd->sensor->i2c_slave_id;
+	buf[15] = address;
+
+	/* Special case larger sensor writes */
+	p = buf + 16;
+
+	/* Copy a four byte write sequence for each byte to be written to */
+	for (i = 0; i < len; i++) {
+		memcpy(p, sensor_urb_skeleton + 16, 4);
+		p[3] = i2c_data[i];
+		p += 4;
+		PDEBUG(DBG_TRACE, "Writing sensor register 0x%x with 0x%x",
+		       address, i2c_data[i]);
+	}
+
+	/* Copy the tailer */
+	memcpy(p, sensor_urb_skeleton + 20, 4);
+
+	/* Set the total length */
+	p[3] = 0x10 + len;
+
+	err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+			      0x04, 0x40, 0x19,
+			      0x0000, buf,
+			      20 + len * 4, M5602_URB_MSG_TIMEOUT);
+
+	return (err < 0) ? err : 0;
+}
+
+int s5k4aa_init(struct sd *sd)
+{
+	int i, err = 0;
+
+	for (i = 0; i < ARRAY_SIZE(init_s5k4aa) && !err; i++) {
+		u8 data[2] = {0x00, 0x00};
+
+		switch (init_s5k4aa[i][0]) {
+		case BRIDGE:
+			err = m5602_write_bridge(sd,
+				init_s5k4aa[i][1],
+				init_s5k4aa[i][2]);
+			break;
+
+		case SENSOR:
+			data[0] = init_s5k4aa[i][2];
+			err = s5k4aa_write_sensor(sd,
+				init_s5k4aa[i][1], data, 1);
+			break;
+
+		case SENSOR_LONG:
+			data[0] = init_s5k4aa[i][2];
+			data[1] = init_s5k4aa[i][3];
+			err = s5k4aa_write_sensor(sd,
+				init_s5k4aa[i][1], data, 2);
+			break;
+		default:
+			info("Invalid stream command, exiting init");
+			return -EINVAL;
+		}
+	}
+
+	if (dump_sensor)
+		s5k4aa_dump_registers(sd);
+
+	if (!err && dmi_check_system(s5k4aa_vflip_dmi_table)) {
+		u8 data = 0x02;
+		info("vertical flip quirk active");
+		s5k4aa_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
+		s5k4aa_read_sensor(sd, S5K4AA_READ_MODE, &data, 1);
+		data |= S5K4AA_RM_V_FLIP;
+		data &= ~S5K4AA_RM_H_FLIP;
+		s5k4aa_write_sensor(sd, S5K4AA_READ_MODE, &data, 1);
+
+		/* Decrement COLSTART to preserve color order (BGGR) */
+		s5k4aa_read_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
+		data--;
+		s5k4aa_write_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
+
+		/* Increment ROWSTART to preserve color order (BGGR) */
+		s5k4aa_read_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
+		data++;
+		s5k4aa_write_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
+	}
+
+	return (err < 0) ? err : 0;
+}
+
+int s5k4aa_power_down(struct sd *sd)
+{
+	return 0;
+}
+
+int s5k4aa_get_exposure(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	u8 data = S5K4AA_PAGE_MAP_2;
+	int err;
+
+	err = s5k4aa_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
+	if (err < 0)
+		goto out;
+
+	err = s5k4aa_read_sensor(sd, S5K4AA_EXPOSURE_HI, &data, 1);
+	if (err < 0)
+		goto out;
+
+	*val = data << 8;
+	err = s5k4aa_read_sensor(sd, S5K4AA_EXPOSURE_LO, &data, 1);
+	*val |= data;
+	PDEBUG(DBG_V4L2_CID, "Read exposure %d", *val);
+out:
+	return (err < 0) ? err : 0;
+}
+
+int s5k4aa_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	u8 data = S5K4AA_PAGE_MAP_2;
+	int err;
+
+	PDEBUG(DBG_V4L2_CID, "Set exposure to %d", val);
+	err = s5k4aa_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
+	if (err < 0)
+		goto out;
+	data = (val >> 8) & 0xff;
+	err = s5k4aa_write_sensor(sd, S5K4AA_EXPOSURE_HI, &data, 1);
+	if (err < 0)
+		goto out;
+	data = val & 0xff;
+	err = s5k4aa_write_sensor(sd, S5K4AA_EXPOSURE_LO, &data, 1);
+out:
+	return (err < 0) ? err : 0;
+}
+
+int s5k4aa_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	u8 data = S5K4AA_PAGE_MAP_2;
+	int err;
+
+	err = s5k4aa_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
+	if (err < 0)
+		goto out;
+
+	err = s5k4aa_read_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
+	*val = (data & S5K4AA_RM_V_FLIP) >> 7;
+	PDEBUG(DBG_V4L2_CID, "Read vertical flip %d", *val);
+
+out:
+	return (err < 0) ? err : 0;
+}
+
+int s5k4aa_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	u8 data = S5K4AA_PAGE_MAP_2;
+	int err;
+
+	PDEBUG(DBG_V4L2_CID, "Set vertical flip to %d", val);
+	err = s5k4aa_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
+	if (err < 0)
+		goto out;
+	err = s5k4aa_write_sensor(sd, S5K4AA_READ_MODE, &data, 1);
+	if (err < 0)
+		goto out;
+	data = ((data & ~S5K4AA_RM_V_FLIP)
+			| ((val & 0x01) << 7));
+	err = s5k4aa_write_sensor(sd, S5K4AA_READ_MODE, &data, 1);
+	if (err < 0)
+		goto out;
+
+	if (val) {
+		err = s5k4aa_read_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
+		if (err < 0)
+			goto out;
+
+		data++;
+		err = s5k4aa_write_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
+	} else {
+		err = s5k4aa_read_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
+		if (err < 0)
+			goto out;
+
+		data--;
+		err = s5k4aa_write_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
+	}
+out:
+	return (err < 0) ? err : 0;
+}
+
+int s5k4aa_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	u8 data = S5K4AA_PAGE_MAP_2;
+	int err;
+
+	err = s5k4aa_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
+	if (err < 0)
+		goto out;
+
+	err = s5k4aa_read_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
+	*val = (data & S5K4AA_RM_H_FLIP) >> 6;
+	PDEBUG(DBG_V4L2_CID, "Read horizontal flip %d", *val);
+out:
+	return (err < 0) ? err : 0;
+}
+
+int s5k4aa_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	u8 data = S5K4AA_PAGE_MAP_2;
+	int err;
+
+	PDEBUG(DBG_V4L2_CID, "Set horizontal flip to %d",
+	       val);
+	err = s5k4aa_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
+	if (err < 0)
+		goto out;
+	err = s5k4aa_write_sensor(sd, S5K4AA_READ_MODE, &data, 1);
+	if (err < 0)
+		goto out;
+
+	data = ((data & ~S5K4AA_RM_H_FLIP) | ((val & 0x01) << 6));
+	err = s5k4aa_write_sensor(sd, S5K4AA_READ_MODE, &data, 1);
+	if (err < 0)
+		goto out;
+
+	if (val) {
+		err = s5k4aa_read_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
+		if (err < 0)
+			goto out;
+		data++;
+		err = s5k4aa_write_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
+		if (err < 0)
+			goto out;
+	} else {
+		err = s5k4aa_read_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
+		if (err < 0)
+			goto out;
+		data--;
+		err = s5k4aa_write_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
+	}
+out:
+	return (err < 0) ? err : 0;
+}
+
+int s5k4aa_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	u8 data = S5K4AA_PAGE_MAP_2;
+	int err;
+
+	err = s5k4aa_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
+	if (err < 0)
+		goto out;
+
+	err = s5k4aa_read_sensor(sd, S5K4AA_GAIN_2, &data, 1);
+	*val = data;
+	PDEBUG(DBG_V4L2_CID, "Read gain %d", *val);
+
+out:
+	return (err < 0) ? err : 0;
+}
+
+int s5k4aa_set_gain(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	u8 data = S5K4AA_PAGE_MAP_2;
+	int err;
+
+	PDEBUG(DBG_V4L2_CID, "Set gain to %d", val);
+	err = s5k4aa_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
+	if (err < 0)
+		goto out;
+
+	data = val & 0xff;
+	err = s5k4aa_write_sensor(sd, S5K4AA_GAIN_2, &data, 1);
+
+out:
+	return (err < 0) ? err : 0;
+}
+
+void s5k4aa_dump_registers(struct sd *sd)
+{
+	int address;
+	u8 page, old_page;
+	s5k4aa_read_sensor(sd, S5K4AA_PAGE_MAP, &old_page, 1);
+	for (page = 0; page < 16; page++) {
+		s5k4aa_write_sensor(sd, S5K4AA_PAGE_MAP, &page, 1);
+		info("Dumping the s5k4aa register state for page 0x%x", page);
+		for (address = 0; address <= 0xff; address++) {
+			u8 value = 0;
+			s5k4aa_read_sensor(sd, address, &value, 1);
+			info("register 0x%x contains 0x%x",
+			     address, value);
+		}
+	}
+	info("s5k4aa register state dump complete");
+
+	for (page = 0; page < 16; page++) {
+		s5k4aa_write_sensor(sd, S5K4AA_PAGE_MAP, &page, 1);
+		info("Probing for which registers that are "
+		     "read/write for page 0x%x", page);
+		for (address = 0; address <= 0xff; address++) {
+			u8 old_value, ctrl_value, test_value = 0xff;
+
+			s5k4aa_read_sensor(sd, address, &old_value, 1);
+			s5k4aa_write_sensor(sd, address, &test_value, 1);
+			s5k4aa_read_sensor(sd, address, &ctrl_value, 1);
+
+			if (ctrl_value == test_value)
+				info("register 0x%x is writeable", address);
+			else
+				info("register 0x%x is read only", address);
+
+			/* Restore original value */
+			s5k4aa_write_sensor(sd, address, &old_value, 1);
+		}
+	}
+	info("Read/write register probing complete");
+	s5k4aa_write_sensor(sd, S5K4AA_PAGE_MAP, &old_page, 1);
+}
diff --git a/drivers/media/video/gspca/m5602/m5602_s5k4aa.h b/drivers/media/video/gspca/m5602/m5602_s5k4aa.h
new file mode 100644
index 0000000..bb7f7e3
--- /dev/null
+++ b/drivers/media/video/gspca/m5602/m5602_s5k4aa.h
@@ -0,0 +1,370 @@
+/*
+ * Driver for the s5k4aa sensor
+ *
+ * Copyright (C) 2008 Erik Andren
+ * Copyright (C) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project.
+ * Copyright (C) 2005 m5603x Linux Driver Project <m5602@x3ng.com.br>
+ *
+ * Portions of code to USB interface and ALi driver software,
+ * Copyright (c) 2006 Willem Duinker
+ * v4l2 interface modeled after the V4L2 driver
+ * for SN9C10x PC Camera Controllers
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2.
+ *
+ */
+
+#ifndef M5602_S5K4AA_H_
+#define M5602_S5K4AA_H_
+
+#include <linux/dmi.h>
+
+#include "m5602_sensor.h"
+
+/*****************************************************************************/
+
+#define S5K4AA_PAGE_MAP			0xec
+
+#define S5K4AA_PAGE_MAP_0		0x00
+#define S5K4AA_PAGE_MAP_1		0x01
+#define S5K4AA_PAGE_MAP_2		0x02
+
+/* Sensor register definitions for page 0x02 */
+#define S5K4AA_READ_MODE		0x03
+#define S5K4AA_ROWSTART_HI		0x04
+#define S5K4AA_ROWSTART_LO		0x05
+#define S5K4AA_COLSTART_HI		0x06
+#define S5K4AA_COLSTART_LO		0x07
+#define S5K4AA_WINDOW_HEIGHT_HI		0x08
+#define S5K4AA_WINDOW_HEIGHT_LO		0x09
+#define S5K4AA_WINDOW_WIDTH_HI		0x0a
+#define S5K4AA_WINDOW_WIDTH_LO		0x0b
+#define S5K4AA_GLOBAL_GAIN__		0x0f /* Only a guess ATM !!! */
+#define S5K4AA_H_BLANK_HI__		0x1d /* Only a guess ATM !!! sync lost
+						if too low, reduces frame rate
+						if too high */
+#define S5K4AA_H_BLANK_LO__		0x1e /* Only a guess ATM !!! */
+#define S5K4AA_EXPOSURE_HI		0x17
+#define S5K4AA_EXPOSURE_LO		0x18
+#define S5K4AA_GAIN_1			0x1f /* (digital?) gain : 5 bits */
+#define S5K4AA_GAIN_2			0x20 /* (analogue?) gain : 7 bits */
+
+#define S5K4AA_RM_ROW_SKIP_4X		0x08
+#define S5K4AA_RM_ROW_SKIP_2X		0x04
+#define S5K4AA_RM_COL_SKIP_4X		0x02
+#define S5K4AA_RM_COL_SKIP_2X		0x01
+#define S5K4AA_RM_H_FLIP		0x40
+#define S5K4AA_RM_V_FLIP		0x80
+
+/*****************************************************************************/
+
+/* Kernel module parameters */
+extern int force_sensor;
+extern int dump_sensor;
+extern unsigned int m5602_debug;
+
+int s5k4aa_probe(struct sd *sd);
+int s5k4aa_init(struct sd *sd);
+int s5k4aa_power_down(struct sd *sd);
+
+void s5k4aa_dump_registers(struct sd *sd);
+
+int s5k4aa_read_sensor(struct sd *sd, const u8 address,
+		       u8 *i2c_data, const u8 len);
+int s5k4aa_write_sensor(struct sd *sd, const u8 address,
+			u8 *i2c_data, const u8 len);
+
+int s5k4aa_get_exposure(struct gspca_dev *gspca_dev, __s32 *val);
+int s5k4aa_set_exposure(struct gspca_dev *gspca_dev, __s32 val);
+int s5k4aa_get_vflip(struct gspca_dev *gspca_dev, __s32 *val);
+int s5k4aa_set_vflip(struct gspca_dev *gspca_dev, __s32 val);
+int s5k4aa_get_hflip(struct gspca_dev *gspca_dev, __s32 *val);
+int s5k4aa_set_hflip(struct gspca_dev *gspca_dev, __s32 val);
+int s5k4aa_get_gain(struct gspca_dev *gspca_dev, __s32 *val);
+int s5k4aa_set_gain(struct gspca_dev *gspca_dev, __s32 val);
+
+static struct m5602_sensor s5k4aa = {
+	.name = "S5K4AA",
+	.probe = s5k4aa_probe,
+	.init = s5k4aa_init,
+	.power_down = s5k4aa_power_down,
+	.read_sensor = s5k4aa_read_sensor,
+	.write_sensor = s5k4aa_write_sensor,
+	.i2c_slave_id = 0x5a,
+	.nctrls = 4,
+	.ctrls = {
+	{
+		{
+			.id 		= V4L2_CID_VFLIP,
+			.type 		= V4L2_CTRL_TYPE_BOOLEAN,
+			.name 		= "vertical flip",
+			.minimum 	= 0,
+			.maximum 	= 1,
+			.step 		= 1,
+			.default_value 	= 0
+		},
+		.set = s5k4aa_set_vflip,
+		.get = s5k4aa_get_vflip
+
+	}, {
+		{
+			.id 		= V4L2_CID_HFLIP,
+			.type 		= V4L2_CTRL_TYPE_BOOLEAN,
+			.name 		= "horizontal flip",
+			.minimum 	= 0,
+			.maximum 	= 1,
+			.step 		= 1,
+			.default_value 	= 0
+		},
+		.set = s5k4aa_set_hflip,
+		.get = s5k4aa_get_hflip
+
+	}, {
+		{
+			.id		= V4L2_CID_GAIN,
+			.type		= V4L2_CTRL_TYPE_INTEGER,
+			.name		= "Gain",
+			.minimum	= 0,
+			.maximum	= 127,
+			.step		= 1,
+			.default_value	= 0xa0,
+			.flags		= V4L2_CTRL_FLAG_SLIDER
+		},
+		.set = s5k4aa_set_gain,
+		.get = s5k4aa_get_gain
+	}, {
+		{
+			.id		= V4L2_CID_EXPOSURE,
+			.type		= V4L2_CTRL_TYPE_INTEGER,
+			.name		= "Exposure",
+			.minimum	= 13,
+			.maximum	= 0xfff,
+			.step		= 1,
+			.default_value	= 0x100,
+			.flags		= V4L2_CTRL_FLAG_SLIDER
+		},
+		.set = s5k4aa_set_exposure,
+		.get = s5k4aa_get_exposure
+	}
+	},
+
+	.nmodes = 1,
+	.modes = {
+	{
+		M5602_DEFAULT_FRAME_WIDTH,
+		M5602_DEFAULT_FRAME_HEIGHT,
+		V4L2_PIX_FMT_SBGGR8,
+		V4L2_FIELD_NONE,
+		.sizeimage =
+			M5602_DEFAULT_FRAME_WIDTH * M5602_DEFAULT_FRAME_HEIGHT,
+		.bytesperline = M5602_DEFAULT_FRAME_WIDTH,
+		.colorspace = V4L2_COLORSPACE_SRGB,
+		.priv = 1
+	}
+	}
+};
+
+static const unsigned char preinit_s5k4aa[][4] =
+{
+	{BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02, 0x00},
+	{BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0, 0x00},
+	{BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
+	{BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
+	{BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
+	{BRIDGE, M5602_XB_SENSOR_TYPE, 0x0d, 0x00},
+	{BRIDGE, M5602_XB_SENSOR_CTRL, 0x00, 0x00},
+
+	{BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00},
+	{BRIDGE, M5602_XB_GPIO_DAT, 0x08, 0x00},
+	{BRIDGE, M5602_XB_SEN_CLK_DIV, 0xb0, 0x00},
+	{BRIDGE, M5602_XB_SEN_CLK_CTRL, 0x80, 0x00},
+	{BRIDGE, M5602_XB_GPIO_EN_H, 0x3f, 0x00},
+	{BRIDGE, M5602_XB_GPIO_DIR_H, 0x3f, 0x00},
+	{BRIDGE, M5602_XB_GPIO_DAT_H, 0x00, 0x00},
+	{BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00},
+	{BRIDGE, M5602_XB_GPIO_DAT, 0x00, 0x00},
+	{BRIDGE, M5602_XB_GPIO_EN_L, 0xff, 0x00},
+	{BRIDGE, M5602_XB_GPIO_DIR_L, 0xff, 0x00},
+	{BRIDGE, M5602_XB_GPIO_DAT_L, 0x00, 0x00},
+	{BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
+	{BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
+	{BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
+	{BRIDGE, M5602_XB_SENSOR_TYPE, 0x08, 0x00},
+
+	{BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02, 0x00},
+	{BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0, 0x00},
+	{BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00},
+	{BRIDGE, M5602_XB_GPIO_DAT, 0x14, 0x00},
+	{BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
+	{BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xf0, 0x00},
+	{BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00},
+	{BRIDGE, M5602_XB_GPIO_DAT, 0x1c, 0x00},
+	{BRIDGE, M5602_XB_GPIO_EN_H, 0x06, 0x00},
+	{BRIDGE, M5602_XB_GPIO_DIR_H, 0x06, 0x00},
+	{BRIDGE, M5602_XB_GPIO_DAT_H, 0x00, 0x00},
+	{BRIDGE, M5602_XB_GPIO_EN_L, 0x00, 0x00},
+	{BRIDGE, M5602_XB_I2C_CLK_DIV, 0x20, 0x00},
+
+	{SENSOR, S5K4AA_PAGE_MAP, 0x00, 0x00}
+};
+
+static const unsigned char init_s5k4aa[][4] =
+{
+	{BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02, 0x00},
+	{BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0, 0x00},
+	{BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
+	{BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
+	{BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
+	{BRIDGE, M5602_XB_SENSOR_TYPE, 0x0d, 0x00},
+	{BRIDGE, M5602_XB_SENSOR_CTRL, 0x00, 0x00},
+
+	{BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00},
+	{BRIDGE, M5602_XB_GPIO_DAT, 0x08, 0x00},
+	{BRIDGE, M5602_XB_SEN_CLK_DIV, 0xb0, 0x00},
+	{BRIDGE, M5602_XB_SEN_CLK_CTRL, 0x80, 0x00},
+	{BRIDGE, M5602_XB_GPIO_EN_H, 0x3f, 0x00},
+	{BRIDGE, M5602_XB_GPIO_DIR_H, 0x3f, 0x00},
+	{BRIDGE, M5602_XB_GPIO_DAT_H, 0x00, 0x00},
+	{BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00},
+	{BRIDGE, M5602_XB_GPIO_DAT, 0x00, 0x00},
+	{BRIDGE, M5602_XB_GPIO_EN_L, 0xff, 0x00},
+	{BRIDGE, M5602_XB_GPIO_DIR_L, 0xff, 0x00},
+	{BRIDGE, M5602_XB_GPIO_DAT_L, 0x00, 0x00},
+	{BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
+	{BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
+	{BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
+	{BRIDGE, M5602_XB_SENSOR_TYPE, 0x08, 0x00},
+
+	{BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02, 0x00},
+	{BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0, 0x00},
+	{BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00},
+	{BRIDGE, M5602_XB_GPIO_DAT, 0x14, 0x00},
+	{BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
+	{BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xf0, 0x00},
+	{BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00},
+	{BRIDGE, M5602_XB_GPIO_DAT, 0x1c, 0x00},
+	{BRIDGE, M5602_XB_GPIO_EN_H, 0x06, 0x00},
+	{BRIDGE, M5602_XB_GPIO_DIR_H, 0x06, 0x00},
+	{BRIDGE, M5602_XB_GPIO_DAT_H, 0x00, 0x00},
+	{BRIDGE, M5602_XB_GPIO_EN_L, 0x00, 0x00},
+	{BRIDGE, M5602_XB_I2C_CLK_DIV, 0x20, 0x00},
+
+	{SENSOR, S5K4AA_PAGE_MAP, 0x07, 0x00},
+	{SENSOR, 0x36, 0x01, 0x00},
+	{SENSOR, S5K4AA_PAGE_MAP, 0x00, 0x00},
+	{SENSOR, 0x7b, 0xff, 0x00},
+	{SENSOR, S5K4AA_PAGE_MAP, 0x02, 0x00},
+	{SENSOR, 0x0c, 0x05, 0x00},
+	{SENSOR, 0x02, 0x0e, 0x00},
+	{SENSOR, S5K4AA_GAIN_1, 0x0f, 0x00},
+	{SENSOR, S5K4AA_GAIN_2, 0x00, 0x00},
+	{SENSOR, S5K4AA_GLOBAL_GAIN__, 0x01, 0x00},
+	{SENSOR, 0x11, 0x00, 0x00},
+	{SENSOR, 0x12, 0x00, 0x00},
+	{SENSOR, S5K4AA_PAGE_MAP, 0x02, 0x00},
+	{SENSOR, S5K4AA_READ_MODE, 0xa0, 0x00},
+	{SENSOR, 0x37, 0x00, 0x00},
+	{SENSOR, S5K4AA_ROWSTART_HI, 0x00, 0x00},
+	{SENSOR, S5K4AA_ROWSTART_LO, 0x2a, 0x00},
+	{SENSOR, S5K4AA_COLSTART_HI, 0x00, 0x00},
+	{SENSOR, S5K4AA_COLSTART_LO, 0x0b, 0x00},
+	{SENSOR, S5K4AA_WINDOW_HEIGHT_HI, 0x03, 0x00},
+	{SENSOR, S5K4AA_WINDOW_HEIGHT_LO, 0xc4, 0x00},
+	{SENSOR, S5K4AA_WINDOW_WIDTH_HI, 0x05, 0x00},
+	{SENSOR, S5K4AA_WINDOW_WIDTH_LO, 0x08, 0x00},
+	{SENSOR, S5K4AA_H_BLANK_HI__, 0x00, 0x00},
+	{SENSOR, S5K4AA_H_BLANK_LO__, 0x48, 0x00},
+	{SENSOR, S5K4AA_EXPOSURE_HI, 0x00, 0x00},
+	{SENSOR, S5K4AA_EXPOSURE_LO, 0x43, 0x00},
+	{SENSOR, 0x11, 0x04, 0x00},
+	{SENSOR, 0x12, 0xc3, 0x00},
+	{SENSOR, S5K4AA_PAGE_MAP, 0x02, 0x00},
+
+	{BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06, 0x00},
+	{BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
+	{BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
+	{BRIDGE, M5602_XB_SENSOR_TYPE, 0x08, 0x00},
+	{BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x81, 0x00},
+	{BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82, 0x00},
+	{BRIDGE, M5602_XB_SIG_INI, 0x01, 0x00},
+	{BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+	{BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+	{BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+	{BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+	/* VSYNC_PARA, VSYNC_PARA : img height 480 = 0x01e0 */
+	{BRIDGE, M5602_XB_VSYNC_PARA, 0x01, 0x00},
+	{BRIDGE, M5602_XB_VSYNC_PARA, 0xe0, 0x00},
+	{BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+	{BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+	{BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
+	{BRIDGE, M5602_XB_SIG_INI, 0x02, 0x00},
+	{BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00},
+	{BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00},
+	/* HSYNC_PARA, HSYNC_PARA : img width 640 = 0x0280 */
+	{BRIDGE, M5602_XB_HSYNC_PARA, 0x02, 0x00},
+	{BRIDGE, M5602_XB_HSYNC_PARA, 0x80, 0x00},
+	{BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
+	{BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
+	{BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xa0, 0x00}, /* 48 MHz */
+
+	{SENSOR, S5K4AA_PAGE_MAP, 0x02, 0x00},
+	{SENSOR, S5K4AA_READ_MODE, S5K4AA_RM_H_FLIP | S5K4AA_RM_ROW_SKIP_2X
+		| S5K4AA_RM_COL_SKIP_2X, 0x00},
+	/* 0x37 : Fix image stability when light is too bright and improves
+	 * image quality in 640x480, but worsens it in 1280x1024 */
+	{SENSOR, 0x37, 0x01, 0x00},
+	/* ROWSTART_HI, ROWSTART_LO : 10 + (1024-960)/2 = 42 = 0x002a */
+	{SENSOR, S5K4AA_ROWSTART_HI, 0x00, 0x00},
+	{SENSOR, S5K4AA_ROWSTART_LO, 0x2a, 0x00},
+	{SENSOR, S5K4AA_COLSTART_HI, 0x00, 0x00},
+	{SENSOR, S5K4AA_COLSTART_LO, 0x0c, 0x00},
+	/* window_height_hi, window_height_lo : 960 = 0x03c0 */
+	{SENSOR, S5K4AA_WINDOW_HEIGHT_HI, 0x03, 0x00},
+	{SENSOR, S5K4AA_WINDOW_HEIGHT_LO, 0xc0, 0x00},
+	/* window_width_hi, window_width_lo : 1280 = 0x0500 */
+	{SENSOR, S5K4AA_WINDOW_WIDTH_HI, 0x05, 0x00},
+	{SENSOR, S5K4AA_WINDOW_WIDTH_LO, 0x00, 0x00},
+	{SENSOR, S5K4AA_H_BLANK_HI__, 0x00, 0x00},
+	{SENSOR, S5K4AA_H_BLANK_LO__, 0xa8, 0x00}, /* helps to sync... */
+	{SENSOR, S5K4AA_EXPOSURE_HI, 0x01, 0x00},
+	{SENSOR, S5K4AA_EXPOSURE_LO, 0x00, 0x00},
+	{SENSOR, 0x11, 0x04, 0x00},
+	{SENSOR, 0x12, 0xc3, 0x00},
+	{SENSOR, S5K4AA_PAGE_MAP, 0x02, 0x00},
+	{SENSOR, 0x02, 0x0e, 0x00},
+	{SENSOR_LONG, S5K4AA_GLOBAL_GAIN__, 0x0f, 0x00},
+	{SENSOR, S5K4AA_GAIN_1, 0x0b, 0x00},
+	{SENSOR, S5K4AA_GAIN_2, 0xa0, 0x00}
+};
+
+static
+    const
+	struct dmi_system_id s5k4aa_vflip_dmi_table[] = {
+	{
+		.ident = "Fujitsu-Siemens Amilo Xa 2528",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Xa 2528")
+		}
+	},
+	{
+		.ident = "Fujitsu-Siemens Amilo Xi 2550",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Xi 2550")
+		}
+	},
+		{
+		.ident = "MSI GX700",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "GX700"),
+			DMI_MATCH(DMI_BIOS_DATE, "07/26/2007")
+		}
+	},
+	{ }
+};
+
+#endif
diff --git a/drivers/media/video/gspca/m5602/m5602_s5k83a.c b/drivers/media/video/gspca/m5602/m5602_s5k83a.c
new file mode 100644
index 0000000..b4b33c2
--- /dev/null
+++ b/drivers/media/video/gspca/m5602/m5602_s5k83a.c
@@ -0,0 +1,423 @@
+/*
+ * Driver for the s5k83a sensor
+ *
+ * Copyright (C) 2008 Erik Andren
+ * Copyright (C) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project.
+ * Copyright (C) 2005 m5603x Linux Driver Project <m5602@x3ng.com.br>
+ *
+ * Portions of code to USB interface and ALi driver software,
+ * Copyright (c) 2006 Willem Duinker
+ * v4l2 interface modeled after the V4L2 driver
+ * for SN9C10x PC Camera Controllers
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2.
+ *
+ */
+
+#include "m5602_s5k83a.h"
+
+int s5k83a_probe(struct sd *sd)
+{
+	u8 prod_id = 0, ver_id = 0;
+	int i, err = 0;
+
+	if (force_sensor) {
+		if (force_sensor == S5K83A_SENSOR) {
+			info("Forcing a %s sensor", s5k83a.name);
+			goto sensor_found;
+		}
+		/* If we want to force another sensor, don't try to probe this
+		 * one */
+		return -ENODEV;
+	}
+
+	info("Probing for a s5k83a sensor");
+
+	/* Preinit the sensor */
+	for (i = 0; i < ARRAY_SIZE(preinit_s5k83a) && !err; i++) {
+		u8 data[2] = {preinit_s5k83a[i][2], preinit_s5k83a[i][3]};
+		if (preinit_s5k83a[i][0] == SENSOR)
+			err = s5k83a_write_sensor(sd, preinit_s5k83a[i][1],
+				data, 2);
+		else
+			err = m5602_write_bridge(sd, preinit_s5k83a[i][1],
+				data[0]);
+	}
+
+	/* We don't know what register (if any) that contain the product id
+	 * Just pick the first addresses that seem to produce the same results
+	 * on multiple machines */
+	if (s5k83a_read_sensor(sd, 0x00, &prod_id, 1))
+		return -ENODEV;
+
+	if (s5k83a_read_sensor(sd, 0x01, &ver_id, 1))
+		return -ENODEV;
+
+	if ((prod_id == 0xff) || (ver_id == 0xff))
+		return -ENODEV;
+	else
+		info("Detected a s5k83a sensor");
+
+sensor_found:
+	sd->gspca_dev.cam.cam_mode = s5k83a.modes;
+	sd->gspca_dev.cam.nmodes = s5k83a.nmodes;
+	sd->desc->ctrls = s5k83a.ctrls;
+	sd->desc->nctrls = s5k83a.nctrls;
+	return 0;
+}
+
+int s5k83a_read_sensor(struct sd *sd, const u8 address,
+			      u8 *i2c_data, const u8 len)
+{
+	int err, i;
+
+	do {
+		err = m5602_read_bridge(sd, M5602_XB_I2C_STATUS, i2c_data);
+	} while ((*i2c_data & I2C_BUSY) && !err);
+	if (err < 0)
+		goto out;
+
+	err = m5602_write_bridge(sd, M5602_XB_I2C_DEV_ADDR,
+				 sd->sensor->i2c_slave_id);
+	if (err < 0)
+		goto out;
+
+	err = m5602_write_bridge(sd, M5602_XB_I2C_REG_ADDR, address);
+	if (err < 0)
+		goto out;
+
+	err = m5602_write_bridge(sd, M5602_XB_I2C_CTRL, 0x18 + len);
+	if (err < 0)
+		goto out;
+
+	do {
+		err = m5602_read_bridge(sd, M5602_XB_I2C_STATUS, i2c_data);
+	} while ((*i2c_data & I2C_BUSY) && !err);
+
+	if (err < 0)
+		goto out;
+	for (i = 0; i < len && !len; i++) {
+		err = m5602_read_bridge(sd, M5602_XB_I2C_DATA, &(i2c_data[i]));
+
+		PDEBUG(DBG_TRACE, "Reading sensor register "
+				  "0x%x containing 0x%x ", address, *i2c_data);
+	}
+
+out:
+	return (err < 0) ? err : 0;
+}
+
+int s5k83a_write_sensor(struct sd *sd, const u8 address,
+			       u8 *i2c_data, const u8 len)
+{
+	int err, i;
+	u8 *p;
+	struct usb_device *udev = sd->gspca_dev.dev;
+	__u8 *buf = sd->gspca_dev.usb_buf;
+
+	/* No sensor with a data width larger than 16 bits has yet been seen */
+	if (len > 2 || !len)
+		return -EINVAL;
+
+	memcpy(buf, sensor_urb_skeleton,
+	       sizeof(sensor_urb_skeleton));
+
+	buf[11] = sd->sensor->i2c_slave_id;
+	buf[15] = address;
+
+	/* Special case larger sensor writes */
+	p = buf + 16;
+
+	/* Copy a four byte write sequence for each byte to be written to */
+	for (i = 0; i < len; i++) {
+		memcpy(p, sensor_urb_skeleton + 16, 4);
+		p[3] = i2c_data[i];
+		p += 4;
+		PDEBUG(DBG_TRACE, "Writing sensor register 0x%x with 0x%x",
+		       address, i2c_data[i]);
+	}
+
+	/* Copy the tailer */
+	memcpy(p, sensor_urb_skeleton + 20, 4);
+
+	/* Set the total length */
+	p[3] = 0x10 + len;
+
+	err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+			      0x04, 0x40, 0x19,
+			      0x0000, buf,
+			      20 + len * 4, M5602_URB_MSG_TIMEOUT);
+
+	return (err < 0) ? err : 0;
+}
+
+int s5k83a_init(struct sd *sd)
+{
+	int i, err = 0;
+
+	for (i = 0; i < ARRAY_SIZE(init_s5k83a) && !err; i++) {
+		u8 data[2] = {0x00, 0x00};
+
+		switch (init_s5k83a[i][0]) {
+		case BRIDGE:
+			err = m5602_write_bridge(sd,
+					init_s5k83a[i][1],
+					init_s5k83a[i][2]);
+			break;
+
+		case SENSOR:
+			data[0] = init_s5k83a[i][2];
+			err = s5k83a_write_sensor(sd,
+				init_s5k83a[i][1], data, 1);
+			break;
+
+		case SENSOR_LONG:
+			data[0] = init_s5k83a[i][2];
+			data[1] = init_s5k83a[i][3];
+			err = s5k83a_write_sensor(sd,
+				init_s5k83a[i][1], data, 2);
+			break;
+		default:
+			info("Invalid stream command, exiting init");
+			return -EINVAL;
+		}
+	}
+
+	if (dump_sensor)
+		s5k83a_dump_registers(sd);
+
+	return (err < 0) ? err : 0;
+}
+
+int s5k83a_power_down(struct sd *sd)
+{
+	return 0;
+}
+
+void s5k83a_dump_registers(struct sd *sd)
+{
+	int address;
+	u8 page, old_page;
+	s5k83a_read_sensor(sd, S5K83A_PAGE_MAP, &old_page, 1);
+
+	for (page = 0; page < 16; page++) {
+		s5k83a_write_sensor(sd, S5K83A_PAGE_MAP, &page, 1);
+		info("Dumping the s5k83a register state for page 0x%x", page);
+		for (address = 0; address <= 0xff; address++) {
+			u8 val = 0;
+			s5k83a_read_sensor(sd, address, &val, 1);
+			info("register 0x%x contains 0x%x",
+			     address, val);
+		}
+	}
+	info("s5k83a register state dump complete");
+
+	for (page = 0; page < 16; page++) {
+		s5k83a_write_sensor(sd, S5K83A_PAGE_MAP, &page, 1);
+		info("Probing for which registers that are read/write "
+		      "for page 0x%x", page);
+		for (address = 0; address <= 0xff; address++) {
+			u8 old_val, ctrl_val, test_val = 0xff;
+
+			s5k83a_read_sensor(sd, address, &old_val, 1);
+			s5k83a_write_sensor(sd, address, &test_val, 1);
+			s5k83a_read_sensor(sd, address, &ctrl_val, 1);
+
+			if (ctrl_val == test_val)
+				info("register 0x%x is writeable", address);
+			else
+				info("register 0x%x is read only", address);
+
+			/* Restore original val */
+			s5k83a_write_sensor(sd, address, &old_val, 1);
+		}
+	}
+	info("Read/write register probing complete");
+	s5k83a_write_sensor(sd, S5K83A_PAGE_MAP, &old_page, 1);
+}
+
+int s5k83a_get_brightness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	int err;
+	u8 data[2];
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	err = s5k83a_read_sensor(sd, S5K83A_BRIGHTNESS, data, 2);
+	data[1] = data[1] << 1;
+	*val = data[1];
+
+	return (err < 0) ? err : 0;
+}
+
+int s5k83a_set_brightness(struct gspca_dev *gspca_dev, __s32 val)
+{
+	int err;
+	u8 data[2];
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	data[0] = 0x00;
+	data[1] = 0x20;
+	err = s5k83a_write_sensor(sd, 0x14, data, 2);
+	if (err < 0)
+		return err;
+
+	data[0] = 0x01;
+	data[1] = 0x00;
+	err = s5k83a_write_sensor(sd, 0x0d, data, 2);
+	if (err < 0)
+		return err;
+
+	/* FIXME: This is not sane, we need to figure out the composition
+		  of these registers */
+	data[0] = val >> 3; /* brightness, high 5 bits */
+	data[1] = val >> 1; /* brightness, high 7 bits */
+	err = s5k83a_write_sensor(sd, S5K83A_BRIGHTNESS, data, 2);
+
+	return (err < 0) ? err : 0;
+}
+
+int s5k83a_get_whiteness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	int err;
+	u8 data;
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	err = s5k83a_read_sensor(sd, S5K83A_WHITENESS, &data, 1);
+
+	*val = data;
+	return (err < 0) ? err : 0;
+}
+
+int s5k83a_set_whiteness(struct gspca_dev *gspca_dev, __s32 val)
+{
+	int err;
+	u8 data[1];
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	data[0] = val;
+	err = s5k83a_write_sensor(sd, S5K83A_WHITENESS, data, 1);
+
+	return (err < 0) ? err : 0;
+}
+
+int s5k83a_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	int err;
+	u8 data[2];
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	err = s5k83a_read_sensor(sd, S5K83A_GAIN, data, 2);
+
+	data[1] = data[1] & 0x3f;
+	if (data[1] > S5K83A_MAXIMUM_GAIN)
+		data[1] = S5K83A_MAXIMUM_GAIN;
+
+	*val = data[1];
+
+	return (err < 0) ? err : 0;
+}
+
+int s5k83a_set_gain(struct gspca_dev *gspca_dev, __s32 val)
+{
+	int err;
+	u8 data[2];
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	data[0] = 0;
+	data[1] = val;
+	err = s5k83a_write_sensor(sd, S5K83A_GAIN, data, 2);
+
+	return (err < 0) ? err : 0;
+}
+
+int s5k83a_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	int err;
+	u8 data[1];
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	data[0] = 0x05;
+	err = s5k83a_write_sensor(sd, S5K83A_PAGE_MAP, data, 1);
+	if (err < 0)
+		return err;
+
+	err = s5k83a_read_sensor(sd, S5K83A_FLIP, data, 1);
+	*val = (data[0] | 0x40) ? 1 : 0;
+
+	return (err < 0) ? err : 0;
+}
+
+int s5k83a_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
+{
+	int err;
+	u8 data[1];
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	data[0] = 0x05;
+	err = s5k83a_write_sensor(sd, S5K83A_PAGE_MAP, data, 1);
+	if (err < 0)
+		return err;
+
+	err = s5k83a_read_sensor(sd, S5K83A_FLIP, data, 1);
+	if (err < 0)
+		return err;
+
+	/* set or zero six bit, seven is hflip */
+	data[0] = (val) ? (data[0] & 0x80) | 0x40 | S5K83A_FLIP_MASK
+			: (data[0] & 0x80) | S5K83A_FLIP_MASK;
+	err = s5k83a_write_sensor(sd, S5K83A_FLIP, data, 1);
+	if (err < 0)
+		return err;
+
+	data[0] = (val) ? 0x0b : 0x0a;
+	err = s5k83a_write_sensor(sd, S5K83A_VFLIP_TUNE, data, 1);
+
+	return (err < 0) ? err : 0;
+}
+
+int s5k83a_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	int err;
+	u8 data[1];
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	data[0] = 0x05;
+	err = s5k83a_write_sensor(sd, S5K83A_PAGE_MAP, data, 1);
+	if (err < 0)
+		return err;
+
+	err = s5k83a_read_sensor(sd, S5K83A_FLIP, data, 1);
+	*val = (data[0] | 0x80) ? 1 : 0;
+
+	return (err < 0) ? err : 0;
+}
+
+int s5k83a_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
+{
+	int err;
+	u8 data[1];
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	data[0] = 0x05;
+	err = s5k83a_write_sensor(sd, S5K83A_PAGE_MAP, data, 1);
+	if (err < 0)
+		return err;
+
+	err = s5k83a_read_sensor(sd, S5K83A_FLIP, data, 1);
+	if (err < 0)
+		return err;
+
+	/* set or zero seven bit, six is vflip */
+	data[0] = (val) ? (data[0] & 0x40) | 0x80 | S5K83A_FLIP_MASK
+			: (data[0] & 0x40) | S5K83A_FLIP_MASK;
+	err = s5k83a_write_sensor(sd, S5K83A_FLIP, data, 1);
+	if (err < 0)
+		return err;
+
+	data[0] = (val) ? 0x0a : 0x0b;
+	err = s5k83a_write_sensor(sd, S5K83A_HFLIP_TUNE, data, 1);
+
+	return (err < 0) ? err : 0;
+}
diff --git a/drivers/media/video/gspca/m5602/m5602_s5k83a.h b/drivers/media/video/gspca/m5602/m5602_s5k83a.h
new file mode 100644
index 0000000..833708e
--- /dev/null
+++ b/drivers/media/video/gspca/m5602/m5602_s5k83a.h
@@ -0,0 +1,484 @@
+/*
+ * Driver for the s5k83a sensor
+ *
+ * Copyright (C) 2008 Erik Andren
+ * Copyright (C) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project.
+ * Copyright (C) 2005 m5603x Linux Driver Project <m5602@x3ng.com.br>
+ *
+ * Portions of code to USB interface and ALi driver software,
+ * Copyright (c) 2006 Willem Duinker
+ * v4l2 interface modeled after the V4L2 driver
+ * for SN9C10x PC Camera Controllers
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2.
+ *
+ */
+
+#ifndef M5602_S5K83A_H_
+#define M5602_S5K83A_H_
+
+#include "m5602_sensor.h"
+
+#define S5K83A_FLIP				0x01
+#define S5K83A_HFLIP_TUNE		0x03
+#define S5K83A_VFLIP_TUNE		0x05
+#define S5K83A_WHITENESS		0x0a
+#define S5K83A_GAIN				0x18
+#define S5K83A_BRIGHTNESS		0x1b
+#define S5K83A_PAGE_MAP			0xec
+
+#define S5K83A_DEFAULT_BRIGHTNESS	0x71
+#define S5K83A_DEFAULT_WHITENESS	0x7e
+#define S5K83A_DEFAULT_GAIN			0x00
+#define S5K83A_MAXIMUM_GAIN			0x3c
+#define S5K83A_FLIP_MASK			0x10
+
+
+/*****************************************************************************/
+
+/* Kernel module parameters */
+extern int force_sensor;
+extern int dump_sensor;
+extern unsigned int m5602_debug;
+
+
+int s5k83a_probe(struct sd *sd);
+int s5k83a_init(struct sd *sd);
+int s5k83a_power_down(struct sd *sd);
+
+void s5k83a_dump_registers(struct sd *sd);
+
+int s5k83a_read_sensor(struct sd *sd, const u8 address,
+		       u8 *i2c_data, const u8 len);
+int s5k83a_write_sensor(struct sd *sd, const u8 address,
+			u8 *i2c_data, const u8 len);
+
+int s5k83a_set_brightness(struct gspca_dev *gspca_dev, __s32 val);
+int s5k83a_get_brightness(struct gspca_dev *gspca_dev, __s32 *val);
+int s5k83a_set_whiteness(struct gspca_dev *gspca_dev, __s32 val);
+int s5k83a_get_whiteness(struct gspca_dev *gspca_dev, __s32 *val);
+int s5k83a_set_gain(struct gspca_dev *gspca_dev, __s32 val);
+int s5k83a_get_gain(struct gspca_dev *gspca_dev, __s32 *val);
+int s5k83a_get_vflip(struct gspca_dev *gspca_dev, __s32 *val);
+int s5k83a_set_vflip(struct gspca_dev *gspca_dev, __s32 val);
+int s5k83a_get_hflip(struct gspca_dev *gspca_dev, __s32 *val);
+int s5k83a_set_hflip(struct gspca_dev *gspca_dev, __s32 val);
+
+
+static struct m5602_sensor s5k83a = {
+	.name = "S5K83A",
+	.probe = s5k83a_probe,
+	.init = s5k83a_init,
+	.power_down = s5k83a_power_down,
+	.read_sensor = s5k83a_read_sensor,
+	.write_sensor = s5k83a_write_sensor,
+	.i2c_slave_id = 0x5a,
+	.nctrls = 5,
+	.ctrls = {
+	{
+		{
+			.id = V4L2_CID_BRIGHTNESS,
+			.type = V4L2_CTRL_TYPE_INTEGER,
+			.name = "brightness",
+			.minimum = 0x00,
+			.maximum = 0xff,
+			.step = 0x01,
+			.default_value = S5K83A_DEFAULT_BRIGHTNESS,
+			.flags = V4L2_CTRL_FLAG_SLIDER
+		},
+			.set = s5k83a_set_brightness,
+			.get = s5k83a_get_brightness
+
+	}, {
+		{
+			.id = V4L2_CID_WHITENESS,
+			.type = V4L2_CTRL_TYPE_INTEGER,
+			.name = "whiteness",
+			.minimum = 0x00,
+			.maximum = 0xff,
+			.step = 0x01,
+			.default_value = S5K83A_DEFAULT_WHITENESS,
+			.flags = V4L2_CTRL_FLAG_SLIDER
+		},
+			.set = s5k83a_set_whiteness,
+			.get = s5k83a_get_whiteness,
+	}, {
+		{
+			.id = V4L2_CID_GAIN,
+			.type = V4L2_CTRL_TYPE_INTEGER,
+			.name = "gain",
+			.minimum = 0x00,
+			.maximum = S5K83A_MAXIMUM_GAIN,
+			.step = 0x01,
+			.default_value = S5K83A_DEFAULT_GAIN,
+			.flags = V4L2_CTRL_FLAG_SLIDER
+		},
+			.set = s5k83a_set_gain,
+			.get = s5k83a_get_gain
+	}, {
+		{
+			.id         = V4L2_CID_HFLIP,
+			.type       = V4L2_CTRL_TYPE_BOOLEAN,
+			.name       = "horizontal flip",
+			.minimum    = 0,
+			.maximum    = 1,
+			.step       = 1,
+			.default_value  = 0
+		},
+			.set = s5k83a_set_hflip,
+			.get = s5k83a_get_hflip
+	}, {
+		{
+		 .id         = V4L2_CID_VFLIP,
+		.type       = V4L2_CTRL_TYPE_BOOLEAN,
+		.name       = "vertical flip",
+		.minimum    = 0,
+		.maximum    = 1,
+		.step       = 1,
+		.default_value  = 0
+		},
+		.set = s5k83a_set_vflip,
+		.get = s5k83a_get_vflip
+		}
+	},
+	.nmodes = 1,
+	.modes = {
+	{
+		M5602_DEFAULT_FRAME_WIDTH,
+		M5602_DEFAULT_FRAME_HEIGHT,
+		V4L2_PIX_FMT_SBGGR8,
+		V4L2_FIELD_NONE,
+		.sizeimage =
+			M5602_DEFAULT_FRAME_WIDTH * M5602_DEFAULT_FRAME_HEIGHT,
+		.bytesperline = M5602_DEFAULT_FRAME_WIDTH,
+		.colorspace = V4L2_COLORSPACE_SRGB,
+		.priv = 1
+	}
+	}
+};
+
+static const unsigned char preinit_s5k83a[][4] =
+{
+	{BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02, 0x00},
+	{BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0, 0x00},
+	{BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
+	{BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
+	{BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
+	{BRIDGE, M5602_XB_SENSOR_TYPE, 0x0d, 0x00},
+	{BRIDGE, M5602_XB_SENSOR_CTRL, 0x00, 0x00},
+
+	{BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
+	{BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00},
+	{BRIDGE, M5602_XB_GPIO_DAT, 0x08, 0x00},
+	{BRIDGE, M5602_XB_GPIO_EN_H, 0x3f, 0x00},
+	{BRIDGE, M5602_XB_GPIO_DIR_H, 0x3f, 0x00},
+	{BRIDGE, M5602_XB_GPIO_DAT_H, 0x00, 0x00},
+	{BRIDGE, M5602_XB_GPIO_EN_L, 0xff, 0x00},
+	{BRIDGE, M5602_XB_GPIO_DIR_L, 0xff, 0x00},
+	{BRIDGE, M5602_XB_GPIO_DAT_L, 0x00, 0x00},
+	{BRIDGE, M5602_XB_SEN_CLK_DIV, 0xb0, 0x00},
+	{BRIDGE, M5602_XB_SEN_CLK_CTRL, 0x80, 0x00},
+	{BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
+	{BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
+	{BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
+	{BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00},
+	{BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02, 0x00},
+	{BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0, 0x00},
+	{BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
+	{BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xf0, 0x00},
+	{BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00},
+	{BRIDGE, M5602_XB_GPIO_DAT, 0x1c, 0x00},
+	{BRIDGE, M5602_XB_GPIO_EN_H, 0x06, 0x00},
+	{BRIDGE, M5602_XB_GPIO_DIR_H, 0x06, 0x00},
+	{BRIDGE, M5602_XB_GPIO_DAT_H, 0x00, 0x00},
+	{BRIDGE, M5602_XB_GPIO_EN_L, 0x00, 0x00},
+	{BRIDGE, M5602_XB_I2C_CLK_DIV, 0x20, 0x00},
+
+	{SENSOR, S5K83A_PAGE_MAP, 0x00, 0x00}
+};
+
+/* This could probably be considerably shortened.
+   I don't have the hardware to experiment with it, patches welcome
+*/
+static const unsigned char init_s5k83a[][4] =
+{
+	{SENSOR, S5K83A_PAGE_MAP, 0x04, 0x00},
+	{SENSOR, 0xaf, 0x01, 0x00},
+	{SENSOR, S5K83A_PAGE_MAP, 0x00, 0x00},
+	{SENSOR, 0x7b, 0xff, 0x00},
+	{SENSOR, S5K83A_PAGE_MAP, 0x05, 0x00},
+	{SENSOR, 0x01, 0x50, 0x00},
+	{SENSOR, 0x12, 0x20, 0x00},
+	{SENSOR, 0x17, 0x40, 0x00},
+	{SENSOR, S5K83A_BRIGHTNESS, 0x0f, 0x00},
+	{SENSOR, 0x1c, 0x00, 0x00},
+	{SENSOR, 0x02, 0x70, 0x00},
+	{SENSOR, 0x03, 0x0b, 0x00},
+	{SENSOR, 0x04, 0xf0, 0x00},
+	{SENSOR, 0x05, 0x0b, 0x00},
+	{SENSOR, S5K83A_PAGE_MAP, 0x05, 0x00},
+
+	{BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06, 0x00},
+	{BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
+	{BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
+	{BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00},
+	{BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x81, 0x00},
+	{BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82, 0x00},
+	{BRIDGE, M5602_XB_SIG_INI, 0x01, 0x00},
+	{BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+	{BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+	{BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+	{BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+	{BRIDGE, M5602_XB_VSYNC_PARA, 0x01, 0x00},
+	{BRIDGE, M5602_XB_VSYNC_PARA, 0xe4, 0x00},
+	{BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+	{BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+	{BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
+	{BRIDGE, M5602_XB_SIG_INI, 0x02, 0x00},
+	{BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00},
+	{BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00},
+	{BRIDGE, M5602_XB_HSYNC_PARA, 0x02, 0x00},
+	{BRIDGE, M5602_XB_HSYNC_PARA, 0x87, 0x00},
+	{BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
+	{BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
+	{BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
+
+	{SENSOR, S5K83A_PAGE_MAP, 0x05, 0x00},
+	{SENSOR, 0x06, 0x71, 0x00},
+	{SENSOR, 0x07, 0xe8, 0x00},
+	{SENSOR, 0x08, 0x02, 0x00},
+	{SENSOR, 0x09, 0x88, 0x00},
+	{SENSOR, 0x14, 0x00, 0x00},
+	{SENSOR, 0x15, 0x20, 0x00},
+	{SENSOR, 0x19, 0x00, 0x00},
+	{SENSOR, 0x1a, 0x98, 0x00},
+	{SENSOR, 0x0f, 0x02, 0x00},
+	{SENSOR, 0x10, 0xe5, 0x00},
+	{SENSOR, S5K83A_PAGE_MAP, 0x05, 0x00},
+	{SENSOR_LONG, 0x14, 0x00, 0x20},
+	{SENSOR_LONG, 0x0d, 0x00, 0x7d},
+	{SENSOR_LONG, 0x1b, 0x0d, 0x05},
+
+	{BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06, 0x00},
+	{BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
+	{BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
+	{BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00},
+	{BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x81, 0x00},
+	{BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82, 0x00},
+	{BRIDGE, M5602_XB_SIG_INI, 0x01, 0x00},
+	{BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+	{BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+	{BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+	{BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+	{BRIDGE, M5602_XB_VSYNC_PARA, 0x01, 0x00},
+	{BRIDGE, M5602_XB_VSYNC_PARA, 0xe4, 0x00},
+	{BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+	{BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+	{BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
+	{BRIDGE, M5602_XB_SIG_INI, 0x02, 0x00},
+	{BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00},
+	{BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00},
+	{BRIDGE, M5602_XB_HSYNC_PARA, 0x02, 0x00},
+	{BRIDGE, M5602_XB_HSYNC_PARA, 0x87, 0x00},
+
+	{BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
+	{BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00},
+	{BRIDGE, M5602_XB_GPIO_DAT, 0x08, 0x00},
+	{BRIDGE, M5602_XB_GPIO_EN_H, 0x3f, 0x00},
+	{BRIDGE, M5602_XB_GPIO_DIR_H, 0x3f, 0x00},
+	{BRIDGE, M5602_XB_GPIO_DAT_H, 0x00, 0x00},
+	{BRIDGE, M5602_XB_GPIO_EN_L, 0xff, 0x00},
+	{BRIDGE, M5602_XB_GPIO_DIR_L, 0xff, 0x00},
+	{BRIDGE, M5602_XB_GPIO_DAT_L, 0x00, 0x00},
+	{BRIDGE, M5602_XB_SEN_CLK_DIV, 0xb0, 0x00},
+	{BRIDGE, M5602_XB_SEN_CLK_CTRL, 0x80, 0x00},
+	{BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
+	{BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
+	{BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
+	{BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00},
+	{BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02, 0x00},
+	{BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0, 0x00},
+	{BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
+	{BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xf0, 0x00},
+	{BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00},
+	{BRIDGE, M5602_XB_GPIO_DAT, 0x1c, 0x00},
+	{BRIDGE, M5602_XB_GPIO_EN_H, 0x06, 0x00},
+	{BRIDGE, M5602_XB_GPIO_DIR_H, 0x06, 0x00},
+	{BRIDGE, M5602_XB_GPIO_DAT_H, 0x00, 0x00},
+	{BRIDGE, M5602_XB_GPIO_EN_L, 0x00, 0x00},
+	{BRIDGE, M5602_XB_I2C_CLK_DIV, 0x20, 0x00},
+
+	{SENSOR, S5K83A_PAGE_MAP, 0x04, 0x00},
+	{SENSOR, 0xaf, 0x01, 0x00},
+	{SENSOR, S5K83A_PAGE_MAP, 0x05, 0x00},
+	/* ff ( init value )is very dark) || 71 and f0 better */
+	{SENSOR, 0x7b, 0xff, 0x00},
+	{SENSOR, S5K83A_PAGE_MAP, 0x05, 0x00},
+	{SENSOR, 0x01, 0x50, 0x00},
+	{SENSOR, 0x12, 0x20, 0x00},
+	{SENSOR, 0x17, 0x40, 0x00},
+	{SENSOR, S5K83A_BRIGHTNESS, 0x0f, 0x00},
+	{SENSOR, 0x1c, 0x00, 0x00},
+	{SENSOR, 0x02, 0x70, 0x00},
+	/* some values like 0x10 give a blue-purple image */
+	{SENSOR, 0x03, 0x0b, 0x00},
+	{SENSOR, 0x04, 0xf0, 0x00},
+	{SENSOR, 0x05, 0x0b, 0x00},
+	{SENSOR, S5K83A_PAGE_MAP, 0x05, 0x00},
+
+	{BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06, 0x00},
+	/* under 80 don't work, highter depend on value */
+	{BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
+
+	{BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
+	{BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00},
+	{BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x81, 0x00},
+	{BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82, 0x00},
+	{BRIDGE, M5602_XB_SIG_INI, 0x01, 0x00},
+	{BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+	{BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+	{BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+	{BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+	{BRIDGE, M5602_XB_VSYNC_PARA, 0x01, 0x00},
+	{BRIDGE, M5602_XB_VSYNC_PARA, 0xe4, 0x00},
+	{BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+	{BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+	{BRIDGE, M5602_XB_SIG_INI, 0x02, 0x00},
+	{BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00},
+	{BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00},
+	{BRIDGE, M5602_XB_HSYNC_PARA, 0x02, 0x00},
+	{BRIDGE, M5602_XB_HSYNC_PARA, 0x7f, 0x00},
+
+	{BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
+	{BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
+	{BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
+
+	{SENSOR, S5K83A_PAGE_MAP, 0x05, 0x00},
+	{SENSOR, 0x06, 0x71, 0x00},
+	{SENSOR, 0x07, 0xe8, 0x00},
+	{SENSOR, 0x08, 0x02, 0x00},
+	{SENSOR, 0x09, 0x88, 0x00},
+	{SENSOR, 0x14, 0x00, 0x00},
+	{SENSOR, 0x15, 0x20, 0x00},
+	{SENSOR, 0x19, 0x00, 0x00},
+	{SENSOR, 0x1a, 0x98, 0x00},
+	{SENSOR, 0x0f, 0x02, 0x00},
+	{SENSOR, 0x10, 0xe5, 0x00},
+	{SENSOR, S5K83A_PAGE_MAP, 0x05, 0x00},
+	{SENSOR_LONG, 0x14, 0x00, 0x20},
+	{SENSOR_LONG, 0x0d, 0x00, 0x7d},
+	{SENSOR_LONG, 0x1b, 0x0d, 0x05},
+
+	/* The following sequence is useless after a clean boot
+	   but is necessary after resume from suspend */
+	{BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00},
+	{BRIDGE, M5602_XB_GPIO_DAT, 0x08, 0x00},
+	{BRIDGE, M5602_XB_GPIO_EN_H, 0x3f, 0x00},
+	{BRIDGE, M5602_XB_GPIO_DIR_H, 0x3f, 0x00},
+	{BRIDGE, M5602_XB_GPIO_DAT_H, 0x00, 0x00},
+	{BRIDGE, M5602_XB_GPIO_EN_L, 0xff, 0x00},
+	{BRIDGE, M5602_XB_GPIO_DIR_L, 0xff, 0x00},
+	{BRIDGE, M5602_XB_GPIO_DAT_L, 0x00, 0x00},
+	{BRIDGE, M5602_XB_SEN_CLK_DIV, 0xb0, 0x00},
+	{BRIDGE, M5602_XB_SEN_CLK_CTRL, 0x80, 0x00},
+	{BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
+	{BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
+	{BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
+	{BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00},
+	{BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02, 0x00},
+	{BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0, 0x00},
+	{BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
+	{BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xf0, 0x00},
+	{BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00},
+	{BRIDGE, M5602_XB_GPIO_DAT, 0x1c, 0x00},
+	{BRIDGE, M5602_XB_GPIO_EN_H, 0x06, 0x00},
+	{BRIDGE, M5602_XB_GPIO_DIR_H, 0x06, 0x00},
+	{BRIDGE, M5602_XB_GPIO_DAT_H, 0x00, 0x00},
+	{BRIDGE, M5602_XB_GPIO_EN_L, 0x00, 0x00},
+	{BRIDGE, M5602_XB_I2C_CLK_DIV, 0x20, 0x00},
+
+	{SENSOR, S5K83A_PAGE_MAP, 0x04, 0x00},
+	{SENSOR, 0xaf, 0x01, 0x00},
+	{SENSOR, S5K83A_PAGE_MAP, 0x00, 0x00},
+	{SENSOR, 0x7b, 0xff, 0x00},
+	{SENSOR, S5K83A_PAGE_MAP, 0x05, 0x00},
+	{SENSOR, 0x01, 0x50, 0x00},
+	{SENSOR, 0x12, 0x20, 0x00},
+	{SENSOR, 0x17, 0x40, 0x00},
+	{SENSOR, S5K83A_BRIGHTNESS, 0x0f, 0x00},
+	{SENSOR, 0x1c, 0x00, 0x00},
+	{SENSOR, 0x02, 0x70, 0x00},
+	{SENSOR, 0x03, 0x0b, 0x00},
+	{SENSOR, 0x04, 0xf0, 0x00},
+	{SENSOR, 0x05, 0x0b, 0x00},
+	{SENSOR, S5K83A_PAGE_MAP, 0x05, 0x00},
+
+	{BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06, 0x00},
+	{BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
+	{BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
+	{BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00},
+	{BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x81, 0x00},
+	{BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82, 0x00},
+	{BRIDGE, M5602_XB_SIG_INI, 0x01, 0x00},
+	{BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+	{BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+	{BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+	{BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+	{BRIDGE, M5602_XB_VSYNC_PARA, 0x01, 0x00},
+	{BRIDGE, M5602_XB_VSYNC_PARA, 0xe4, 0x00},
+	{BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+	{BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+	{BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
+	{BRIDGE, M5602_XB_SIG_INI, 0x02, 0x00},
+	{BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00},
+	{BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00},
+	{BRIDGE, M5602_XB_HSYNC_PARA, 0x02, 0x00},
+	{BRIDGE, M5602_XB_HSYNC_PARA, 0x7f, 0x00},
+	{BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
+	{BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
+	{BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
+
+	{SENSOR, S5K83A_PAGE_MAP, 0x05, 0x00},
+	{SENSOR, 0x06, 0x71, 0x00},
+	{SENSOR, 0x07, 0xe8, 0x00},
+	{SENSOR, 0x08, 0x02, 0x00},
+	{SENSOR, 0x09, 0x88, 0x00},
+	{SENSOR, 0x14, 0x00, 0x00},
+	{SENSOR, 0x15, 0x20, 0x00},
+	{SENSOR, 0x19, 0x00, 0x00},
+	{SENSOR, 0x1a, 0x98, 0x00},
+	{SENSOR, 0x0f, 0x02, 0x00},
+
+	{SENSOR, 0x10, 0xe5, 0x00},
+	{SENSOR, S5K83A_PAGE_MAP, 0x05, 0x00},
+	{SENSOR_LONG, 0x14, 0x00, 0x20},
+	{SENSOR_LONG, 0x0d, 0x00, 0x7d},
+	{SENSOR_LONG, 0x1b, 0x0d, 0x05},
+
+	/* normal colors
+	   (this is value after boot, but after tries can be different) */
+	{SENSOR, 0x00, 0x06, 0x00},
+
+	/* set default brightness */
+	{SENSOR_LONG, 0x14, 0x00, 0x20},
+	{SENSOR_LONG, 0x0d, 0x01, 0x00},
+	{SENSOR_LONG, 0x1b, S5K83A_DEFAULT_BRIGHTNESS >> 3,
+			    S5K83A_DEFAULT_BRIGHTNESS >> 1},
+
+	/* set default whiteness */
+	{SENSOR, S5K83A_WHITENESS, S5K83A_DEFAULT_WHITENESS, 0x00},
+
+	/* set default gain */
+	{SENSOR_LONG, 0x18, 0x00, S5K83A_DEFAULT_GAIN},
+
+	/* set default flip */
+	{SENSOR, S5K83A_PAGE_MAP, 0x05, 0x00},
+	{SENSOR, S5K83A_FLIP, 0x00 | S5K83A_FLIP_MASK, 0x00},
+	{SENSOR, S5K83A_HFLIP_TUNE, 0x0b, 0x00},
+	{SENSOR, S5K83A_VFLIP_TUNE, 0x0a, 0x00}
+
+};
+
+#endif
diff --git a/drivers/media/video/gspca/m5602/m5602_sensor.h b/drivers/media/video/gspca/m5602/m5602_sensor.h
new file mode 100644
index 0000000..930fcaa
--- /dev/null
+++ b/drivers/media/video/gspca/m5602/m5602_sensor.h
@@ -0,0 +1,76 @@
+/*
+ * USB Driver for ALi m5602 based webcams
+ *
+ * Copyright (C) 2008 Erik Andren
+ * Copyright (C) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project.
+ * Copyright (C) 2005 m5603x Linux Driver Project <m5602@x3ng.com.br>
+ *
+ * Portions of code to USB interface and ALi driver software,
+ * Copyright (c) 2006 Willem Duinker
+ * v4l2 interface modeled after the V4L2 driver
+ * for SN9C10x PC Camera Controllers
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2.
+ *
+ */
+
+#ifndef M5602_SENSOR_H_
+#define M5602_SENSOR_H_
+
+#include "m5602_bridge.h"
+
+#define M5602_DEFAULT_FRAME_WIDTH  640
+#define M5602_DEFAULT_FRAME_HEIGHT 480
+
+#define M5602_MAX_CTRLS		(V4L2_CID_LASTP1 - V4L2_CID_BASE + 10)
+
+/* Enumerates all supported sensors */
+enum sensors {
+	OV9650_SENSOR	= 1,
+	S5K83A_SENSOR	= 2,
+	S5K4AA_SENSOR	= 3,
+	MT9M111_SENSOR	= 4,
+	PO1030_SENSOR	= 5
+};
+
+/* Enumerates all possible instruction types */
+enum instruction {
+	BRIDGE,
+	SENSOR,
+	SENSOR_LONG
+};
+
+struct m5602_sensor {
+	/* Defines the name of a sensor */
+	char name[32];
+
+	/* What i2c address the sensor is connected to */
+	u8 i2c_slave_id;
+
+	/* Probes if the sensor is connected */
+	int (*probe)(struct sd *sd);
+
+	/* Performs a initialization sequence */
+	int (*init)(struct sd *sd);
+
+	/* Performs a power down sequence */
+	int (*power_down)(struct sd *sd);
+
+	/* Reads a sensor register */
+	int (*read_sensor)(struct sd *sd, const u8 address,
+	      u8 *i2c_data, const u8 len);
+
+	/* Writes to a sensor register */
+	int (*write_sensor)(struct sd *sd, const u8 address,
+	      u8 *i2c_data, const u8 len);
+
+	int nctrls;
+	struct ctrl ctrls[M5602_MAX_CTRLS];
+
+	char nmodes;
+	struct v4l2_pix_format modes[];
+};
+
+#endif
diff --git a/drivers/media/video/gspca/mars.c b/drivers/media/video/gspca/mars.c
index 4d5db47..277ca34 100644
--- a/drivers/media/video/gspca/mars.c
+++ b/drivers/media/video/gspca/mars.c
@@ -134,7 +134,7 @@
 	return 0;
 }
 
-static void sd_start(struct gspca_dev *gspca_dev)
+static int sd_start(struct gspca_dev *gspca_dev)
 {
 	int err_code;
 	__u8 *data;
@@ -143,9 +143,10 @@
 	int intpipe;
 
 	PDEBUG(D_STREAM, "camera start, iface %d, alt 8", gspca_dev->iface);
-	if (usb_set_interface(gspca_dev->dev, gspca_dev->iface, 8) < 0) {
+	err_code = usb_set_interface(gspca_dev->dev, gspca_dev->iface, 8);
+	if (err_code < 0) {
 		PDEBUG(D_ERR|D_STREAM, "Set packet size: set interface error");
-		return;
+		return err_code;
 	}
 
 	data = gspca_dev->usb_buf;
@@ -154,7 +155,7 @@
 
 	err_code = reg_w(gspca_dev, data[0], 2);
 	if (err_code < 0)
-		return;
+		return err_code;
 
 	/*
 	   Initialize the MR97113 chip register
@@ -180,14 +181,14 @@
 
 	err_code = reg_w(gspca_dev, data[0], 11);
 	if (err_code < 0)
-		return;
+		return err_code;
 
 	data[0] = 0x23;		/* address */
 	data[1] = 0x09;		/* reg 35, append frame header */
 
 	err_code = reg_w(gspca_dev, data[0], 2);
 	if (err_code < 0)
-		return;
+		return err_code;
 
 	data[0] = 0x3c;		/* address */
 /*	if (gspca_dev->width == 1280) */
@@ -198,7 +199,7 @@
 				 *	(unit: 4KB) 200KB */
 	err_code = reg_w(gspca_dev, data[0], 2);
 	if (err_code < 0)
-		return;
+		return err_code;
 
 	if (0) {			/* fixed dark-gain */
 		data[1] = 0;		/* reg 94, Y Gain (1.75) */
@@ -240,13 +241,13 @@
 
 	err_code = reg_w(gspca_dev, data[0], 6);
 	if (err_code < 0)
-		return;
+		return err_code;
 
 	data[0] = 0x67;
 	data[1] = 0x13;		/* reg 103, first pixel B, disable sharpness */
 	err_code = reg_w(gspca_dev, data[0], 2);
 	if (err_code < 0)
-		return;
+		return err_code;
 
 	/*
 	 * initialize the value of MI sensor...
@@ -326,6 +327,7 @@
 	data[0] = 0x00;
 	data[1] = 0x4d;		/* ISOC transfering enable... */
 	reg_w(gspca_dev, data[0], 2);
+	return err_code;
 }
 
 static void sd_stopN(struct gspca_dev *gspca_dev)
diff --git a/drivers/media/video/gspca/ov519.c b/drivers/media/video/gspca/ov519.c
index 4df4eec..ca67119 100644
--- a/drivers/media/video/gspca/ov519.c
+++ b/drivers/media/video/gspca/ov519.c
@@ -1854,7 +1854,7 @@
 }
 
 /* -- start the camera -- */
-static void sd_start(struct gspca_dev *gspca_dev)
+static int sd_start(struct gspca_dev *gspca_dev)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
 	int ret;
@@ -1871,9 +1871,10 @@
 		goto out;
 	PDEBUG(D_STREAM, "camera started alt: 0x%02x", gspca_dev->alt);
 	ov51x_led_control(sd, 1);
-	return;
+	return 0;
 out:
 	PDEBUG(D_ERR, "camera start error:%d", ret);
+	return ret;
 }
 
 static void sd_stopN(struct gspca_dev *gspca_dev)
diff --git a/drivers/media/video/gspca/pac207.c b/drivers/media/video/gspca/pac207.c
index 83b5f74..0b0c573 100644
--- a/drivers/media/video/gspca/pac207.c
+++ b/drivers/media/video/gspca/pac207.c
@@ -281,7 +281,7 @@
 }
 
 /* -- start the camera -- */
-static void sd_start(struct gspca_dev *gspca_dev)
+static int sd_start(struct gspca_dev *gspca_dev)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
 	__u8 mode;
@@ -323,6 +323,7 @@
 	sd->sof_read = 0;
 	sd->autogain_ignore_frames = 0;
 	atomic_set(&sd->avg_lum, -1);
+	return 0;
 }
 
 static void sd_stopN(struct gspca_dev *gspca_dev)
@@ -534,6 +535,7 @@
 	{USB_DEVICE(0x093a, 0x2470)},
 	{USB_DEVICE(0x093a, 0x2471)},
 	{USB_DEVICE(0x093a, 0x2472)},
+	{USB_DEVICE(0x093a, 0x2476)},
 	{USB_DEVICE(0x2001, 0xf115)},
 	{}
 };
diff --git a/drivers/media/video/gspca/pac7311.c b/drivers/media/video/gspca/pac7311.c
index d4be518..e5ff9a6 100644
--- a/drivers/media/video/gspca/pac7311.c
+++ b/drivers/media/video/gspca/pac7311.c
@@ -675,7 +675,7 @@
 	return 0;
 }
 
-static void sd_start(struct gspca_dev *gspca_dev)
+static int sd_start(struct gspca_dev *gspca_dev)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
 
@@ -724,6 +724,7 @@
 		reg_w(gspca_dev, 0x78, 0x01);
 	else
 		reg_w(gspca_dev, 0x78, 0x05);
+	return 0;
 }
 
 static void sd_stopN(struct gspca_dev *gspca_dev)
@@ -1063,6 +1064,7 @@
 	{USB_DEVICE(0x093a, 0x2621), .driver_info = SENSOR_PAC7302},
 	{USB_DEVICE(0x093a, 0x2624), .driver_info = SENSOR_PAC7302},
 	{USB_DEVICE(0x093a, 0x2626), .driver_info = SENSOR_PAC7302},
+	{USB_DEVICE(0x093a, 0x262a), .driver_info = SENSOR_PAC7302},
 	{}
 };
 MODULE_DEVICE_TABLE(usb, device_table);
diff --git a/drivers/media/video/gspca/sonixb.c b/drivers/media/video/gspca/sonixb.c
index 5dd78c6..6c69bc7 100644
--- a/drivers/media/video/gspca/sonixb.c
+++ b/drivers/media/video/gspca/sonixb.c
@@ -232,7 +232,7 @@
 static struct v4l2_pix_format vga_mode[] = {
 	{160, 120, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
 		.bytesperline = 160,
-		.sizeimage = 160 * 120 * 5 / 4,
+		.sizeimage = 160 * 120,
 		.colorspace = V4L2_COLORSPACE_SRGB,
 		.priv = 2 | MODE_RAW},
 	{160, 120, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE,
@@ -264,7 +264,7 @@
 		.priv = 1 | MODE_REDUCED_SIF},
 	{176, 144, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
 		.bytesperline = 176,
-		.sizeimage = 176 * 144 * 5 / 4,
+		.sizeimage = 176 * 144,
 		.colorspace = V4L2_COLORSPACE_SRGB,
 		.priv = 1 | MODE_RAW},
 	{176, 144, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE,
@@ -490,7 +490,7 @@
 	{0x30, 0x11, 0x02, 0x20, 0x70, 0x00, 0x00, 0x10},
 };
 
-struct sensor_data sensor_data[] = {
+static struct sensor_data sensor_data[] = {
 SENS(initHv7131, NULL, hv7131_sensor_init, NULL, NULL, 0, NO_EXPO|NO_FREQ, 0),
 SENS(initOv6650, NULL, ov6650_sensor_init, NULL, NULL, F_GAIN|F_SIF, 0, 0x60),
 SENS(initOv7630, initOv7630_3, ov7630_sensor_init, NULL, ov7630_sensor_init_3,
@@ -892,7 +892,7 @@
 }
 
 /* -- start the camera -- */
-static void sd_start(struct gspca_dev *gspca_dev)
+static int sd_start(struct gspca_dev *gspca_dev)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
 	struct cam *cam = &gspca_dev->cam;
@@ -976,6 +976,7 @@
 	sd->frames_to_drop = 0;
 	sd->autogain_ignore_frames = 0;
 	atomic_set(&sd->avg_lum, -1);
+	return 0;
 }
 
 static void sd_stopN(struct gspca_dev *gspca_dev)
diff --git a/drivers/media/video/gspca/sonixj.c b/drivers/media/video/gspca/sonixj.c
index d75b1d2..53cb82d 100644
--- a/drivers/media/video/gspca/sonixj.c
+++ b/drivers/media/video/gspca/sonixj.c
@@ -39,6 +39,7 @@
 	unsigned char contrast;
 	unsigned char colors;
 	unsigned char autogain;
+	__u8 vflip;			/* ov7630 only */
 
 	signed char ag_cnt;
 #define AG_CNT_START 13
@@ -70,6 +71,8 @@
 static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val);
 static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
 static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val);
 
 static struct ctrl sd_ctrls[] = {
 	{
@@ -131,6 +134,22 @@
 	    .set = sd_setautogain,
 	    .get = sd_getautogain,
 	},
+/* ov7630 only */
+#define VFLIP_IDX 4
+	{
+	    {
+		.id      = V4L2_CID_VFLIP,
+		.type    = V4L2_CTRL_TYPE_BOOLEAN,
+		.name    = "Vflip",
+		.minimum = 0,
+		.maximum = 1,
+		.step    = 1,
+#define VFLIP_DEF 1
+		.default_value = VFLIP_DEF,
+	    },
+	    .set = sd_setvflip,
+	    .get = sd_getvflip,
+	},
 };
 
 static struct v4l2_pix_format vga_mode[] = {
@@ -248,10 +267,12 @@
 	0xa6, 0xb2, 0xbf, 0xca, 0xd5, 0xe0, 0xeb, 0xf5, 0xff
 };
 
+/* color matrix and offsets */
 static const __u8 reg84[] = {
-	0x14, 0x00, 0x27, 0x00, 0x07, 0x00, 0xe5, 0x0f,
-	0xe4, 0x0f, 0x38, 0x00, 0x3e, 0x00, 0xc3, 0x0f,
-	0xf7, 0x0f, 0x00, 0x00, 0x00
+	0x14, 0x00, 0x27, 0x00, 0x07, 0x00,	/* YR YG YB gains */
+	0xe8, 0x0f, 0xda, 0x0f, 0x40, 0x00,	/* UR UG UB */
+	0x3e, 0x00, 0xcd, 0x0f, 0xf7, 0x0f,	/* VR VG VB */
+	0x00, 0x00, 0x00			/* YUV offsets */
 };
 static const __u8 hv7131r_sensor_init[][8] = {
 	{0xC1, 0x11, 0x01, 0x08, 0x01, 0x00, 0x00, 0x10},
@@ -434,7 +455,8 @@
 	{0xa1, 0x21, 0x12, 0x48, 0x00, 0x00, 0x00, 0x10},
 	{0xa1, 0x21, 0x12, 0x48, 0x00, 0x00, 0x00, 0x10},
 /*fixme: + 0x12, 0x04*/
-	{0xa1, 0x21, 0x75, 0x82, 0x00, 0x00, 0x00, 0x10},
+/*	{0xa1, 0x21, 0x75, 0x82, 0x00, 0x00, 0x00, 0x10},  * COMN
+							 * set by setvflip */
 	{0xa1, 0x21, 0x10, 0x32, 0x00, 0x00, 0x00, 0x10},
 	{0xa1, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10},
 	{0xb1, 0x21, 0x01, 0x80, 0x80, 0x00, 0x00, 0x10},
@@ -707,6 +729,7 @@
 			0x08, 0,		/* value, index */
 			gspca_dev->usb_buf, 8,
 			500);
+	msleep(2);
 }
 
 /* read 5 bytes in gspca_dev->usb_buf */
@@ -948,6 +971,8 @@
 		gspca_dev->ctrl_dis = (1 << AUTOGAIN_IDX);
 		break;
 	}
+	if (sd->sensor != SENSOR_OV7630)
+		gspca_dev->ctrl_dis |= (1 << VFLIP_IDX);
 
 	return 0;
 }
@@ -976,13 +1001,13 @@
 	case BRIDGE_SN9C105:
 		if (regF1 != 0x11)
 			return -ENODEV;
-		reg_w(gspca_dev, 0x02, regGpio, 2);
+		reg_w(gspca_dev, 0x01, regGpio, 2);
 		break;
 	case BRIDGE_SN9C120:
 		if (regF1 != 0x12)
 			return -ENODEV;
 		regGpio[1] = 0x70;
-		reg_w(gspca_dev, 0x02, regGpio, 2);
+		reg_w(gspca_dev, 0x01, regGpio, 2);
 		break;
 	default:
 /*	case BRIDGE_SN9C110: */
@@ -1079,20 +1104,17 @@
 static void setbrightcont(struct gspca_dev *gspca_dev)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
-	unsigned val;
+	int val;
 	__u8 reg84_full[0x15];
 
-	memset(reg84_full, 0, sizeof reg84_full);
-	val = sd->contrast * 0x20 / CONTRAST_MAX + 0x10;	/* 10..30 */
-	reg84_full[2] = val;
-	reg84_full[0] = (val + 1) / 2;
-	reg84_full[4] = (val + 1) / 5;
-	if (val > BRIGHTNESS_DEF)
-		val = (sd->brightness - BRIGHTNESS_DEF) * 0x20
+	memcpy(reg84_full, reg84, sizeof reg84_full);
+	val = sd->contrast * 0x30 / CONTRAST_MAX + 0x10;	/* 10..40 */
+	reg84_full[0] = (val + 1) / 2;		/* red */
+	reg84_full[2] = val;			/* green */
+	reg84_full[4] = (val + 1) / 5;		/* blue */
+	val = (sd->brightness - BRIGHTNESS_DEF) * 0x10
 			/ BRIGHTNESS_MAX;
-	else
-		val = 0;
-	reg84_full[0x12] = val;			/* 00..1f */
+	reg84_full[0x12] = val & 0x1f;		/* 5:0 signed value */
 	reg_w(gspca_dev, 0x84, reg84_full, sizeof reg84_full);
 }
 
@@ -1171,8 +1193,16 @@
 		sd->ag_cnt = -1;
 }
 
+static void setvflip(struct sd *sd)
+{
+	if (sd->sensor != SENSOR_OV7630)
+		return;
+	i2c_w1(&sd->gspca_dev, 0x75,			/* COMN */
+		sd->vflip ? 0x82 : 0x02);
+}
+
 /* -- start the camera -- */
-static void sd_start(struct gspca_dev *gspca_dev)
+static int sd_start(struct gspca_dev *gspca_dev)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
 	int i;
@@ -1183,7 +1213,7 @@
 	static const __u8 CA[] = { 0x28, 0xd8, 0x14, 0xec };
 	static const __u8 CE[] = { 0x32, 0xdd, 0x2d, 0xdd };	/* MI0360 */
 	static const __u8 CE_ov76xx[] =
-			{ 0x32, 0xdd, 0x32, 0xdd };	/* OV7630/48 */
+				{ 0x32, 0xdd, 0x32, 0xdd };
 
 	sn9c1xx = sn_tb[(int) sd->sensor];
 	configure_gpio(gspca_dev, sn9c1xx);
@@ -1223,8 +1253,15 @@
 	reg_w(gspca_dev, 0x20, gamma_def, sizeof gamma_def);
 	for (i = 0; i < 8; i++)
 		reg_w(gspca_dev, 0x84, reg84, sizeof reg84);
+	switch (sd->sensor) {
+	case SENSOR_OV7660:
+		reg_w1(gspca_dev, 0x9a, 0x05);
+		break;
+	default:
 		reg_w1(gspca_dev, 0x9a, 0x08);
 		reg_w1(gspca_dev, 0x99, 0x59);
+		break;
+	}
 
 	mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
 	if (mode)
@@ -1255,6 +1292,7 @@
 		break;
 	case SENSOR_OV7630:
 		ov7630_InitSensor(gspca_dev);
+		setvflip(sd);
 		reg17 = 0xe2;
 		reg1 = 0x44;
 		break;
@@ -1275,8 +1313,8 @@
 /*			reg1 = 0x44; */
 /*			reg1 = 0x46;	(done) */
 		} else {
-			reg17 = 0x22;	/* 640 MCKSIZE */
-			reg1 = 0x06;
+			reg17 = 0xa2;	/* 640 */
+			reg1 = 0x44;
 		}
 		break;
 	}
@@ -1285,6 +1323,7 @@
 	switch (sd->sensor) {
 	case SENSOR_OV7630:
 	case SENSOR_OV7648:
+	case SENSOR_OV7660:
 		reg_w(gspca_dev, 0xce, CE_ov76xx, 4);
 		break;
 	default:
@@ -1311,12 +1350,16 @@
 		setbrightness(gspca_dev);
 		setcontrast(gspca_dev);
 		break;
+	case SENSOR_OV7630:
+		setvflip(sd);
+		/* fall thru */
 	default:			/* OV76xx */
 		setbrightcont(gspca_dev);
 		break;
 	}
 	setautogain(gspca_dev);
 	reg_w1(gspca_dev, 0x01, reg1);
+	return 0;
 }
 
 static void sd_stopN(struct gspca_dev *gspca_dev)
@@ -1537,6 +1580,24 @@
 	return 0;
 }
 
+static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->vflip = val;
+	if (gspca_dev->streaming)
+		setvflip(sd);
+	return 0;
+}
+
+static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	*val = sd->vflip;
+	return 0;
+}
+
 /* sub-driver description */
 static const struct sd_desc sd_desc = {
 	.name = MODULE_NAME,
@@ -1558,6 +1619,7 @@
 static const __devinitdata struct usb_device_id device_table[] = {
 #if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE
 	{USB_DEVICE(0x0458, 0x7025), BSI(SN9C120, MI0360, 0x5d)},
+	{USB_DEVICE(0x0458, 0x702e), BSI(SN9C120, OV7660, 0x21)},
 	{USB_DEVICE(0x045e, 0x00f5), BSI(SN9C105, OV7660, 0x21)},
 	{USB_DEVICE(0x045e, 0x00f7), BSI(SN9C105, OV7660, 0x21)},
 	{USB_DEVICE(0x0471, 0x0327), BSI(SN9C105, MI0360, 0x5d)},
@@ -1579,7 +1641,9 @@
 /*	{USB_DEVICE(0x0c45, 0x60fa), BSI(SN9C105, OV7648, 0x??)}, */
 	{USB_DEVICE(0x0c45, 0x60fb), BSI(SN9C105, OV7660, 0x21)},
 	{USB_DEVICE(0x0c45, 0x60fc), BSI(SN9C105, HV7131R, 0x11)},
-/*	{USB_DEVICE(0x0c45, 0x60fe), BSI(SN9C105, OV7630, 0x??)}, */
+#if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE
+	{USB_DEVICE(0x0c45, 0x60fe), BSI(SN9C105, OV7630, 0x21)},
+#endif
 /*	{USB_DEVICE(0x0c45, 0x6108), BSI(SN9C120, OM6801, 0x??)}, */
 /*	{USB_DEVICE(0x0c45, 0x6122), BSI(SN9C110, ICM105C, 0x??)}, */
 /*	{USB_DEVICE(0x0c45, 0x6123), BSI(SN9C110, SanyoCCD, 0x??)}, */
diff --git a/drivers/media/video/gspca/spca500.c b/drivers/media/video/gspca/spca500.c
index 6e73390..bca106c 100644
--- a/drivers/media/video/gspca/spca500.c
+++ b/drivers/media/video/gspca/spca500.c
@@ -660,7 +660,7 @@
 	return 0;
 }
 
-static void sd_start(struct gspca_dev *gspca_dev)
+static int sd_start(struct gspca_dev *gspca_dev)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
 	int err;
@@ -867,6 +867,7 @@
 		write_vector(gspca_dev, Clicksmart510_defaults);
 		break;
 	}
+	return 0;
 }
 
 static void sd_stopN(struct gspca_dev *gspca_dev)
diff --git a/drivers/media/video/gspca/spca501.c b/drivers/media/video/gspca/spca501.c
index e9eb59b..b742f26 100644
--- a/drivers/media/video/gspca/spca501.c
+++ b/drivers/media/video/gspca/spca501.c
@@ -1980,7 +1980,7 @@
 	return 0;
 }
 
-static void sd_start(struct gspca_dev *gspca_dev)
+static int sd_start(struct gspca_dev *gspca_dev)
 {
 	struct usb_device *dev = gspca_dev->dev;
 	int mode;
@@ -2012,6 +2012,7 @@
 	setbrightness(gspca_dev);
 	setcontrast(gspca_dev);
 	setcolors(gspca_dev);
+	return 0;
 }
 
 static void sd_stopN(struct gspca_dev *gspca_dev)
diff --git a/drivers/media/video/gspca/spca505.c b/drivers/media/video/gspca/spca505.c
index f601daf..b345749 100644
--- a/drivers/media/video/gspca/spca505.c
+++ b/drivers/media/video/gspca/spca505.c
@@ -688,7 +688,7 @@
 	return 0;
 }
 
-static void sd_start(struct gspca_dev *gspca_dev)
+static int sd_start(struct gspca_dev *gspca_dev)
 {
 	struct usb_device *dev = gspca_dev->dev;
 	int ret;
@@ -733,6 +733,7 @@
 /*	reg_write(dev, 0x5, 0x0, 0x0); */
 /*	reg_write(dev, 0x5, 0x0, 0x1); */
 /*	reg_write(dev, 0x5, 0x11, 0x2); */
+	return ret;
 }
 
 static void sd_stopN(struct gspca_dev *gspca_dev)
diff --git a/drivers/media/video/gspca/spca506.c b/drivers/media/video/gspca/spca506.c
index 195dce9..645ee9d 100644
--- a/drivers/media/video/gspca/spca506.c
+++ b/drivers/media/video/gspca/spca506.c
@@ -422,7 +422,7 @@
 	return 0;
 }
 
-static void sd_start(struct gspca_dev *gspca_dev)
+static int sd_start(struct gspca_dev *gspca_dev)
 {
 	struct usb_device *dev = gspca_dev->dev;
 	__u16 norme;
@@ -549,6 +549,7 @@
 	PDEBUG(D_STREAM, "webcam started");
 	spca506_GetNormeInput(gspca_dev, &norme, &channel);
 	spca506_SetNormeInput(gspca_dev, norme, channel);
+	return 0;
 }
 
 static void sd_stopN(struct gspca_dev *gspca_dev)
diff --git a/drivers/media/video/gspca/spca508.c b/drivers/media/video/gspca/spca508.c
index 281ce02..63ec902 100644
--- a/drivers/media/video/gspca/spca508.c
+++ b/drivers/media/video/gspca/spca508.c
@@ -1528,7 +1528,7 @@
 	return 0;
 }
 
-static void sd_start(struct gspca_dev *gspca_dev)
+static int sd_start(struct gspca_dev *gspca_dev)
 {
 	int mode;
 
@@ -1546,6 +1546,7 @@
 		break;
 	}
 	reg_write(gspca_dev->dev, 0x8112, 0x10 | 0x20);
+	return 0;
 }
 
 static void sd_stopN(struct gspca_dev *gspca_dev)
diff --git a/drivers/media/video/gspca/spca561.c b/drivers/media/video/gspca/spca561.c
index cfbc9eb..020a03c 100644
--- a/drivers/media/video/gspca/spca561.c
+++ b/drivers/media/video/gspca/spca561.c
@@ -152,7 +152,7 @@
 
 	ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
 			      0,		/* request */
-			      USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+			      USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
 			      value, index, NULL, 0, 500);
 	PDEBUG(D_USBO, "reg write: 0x%02x:0x%02x", index, value);
 	if (ret < 0)
@@ -225,7 +225,7 @@
 	reg_w_val(gspca_dev->dev, 0x8802, (mode | 0x01));
 	do {
 		reg_r(gspca_dev, 0x8803, 1);
-		if (!gspca_dev->usb_buf)
+		if (!gspca_dev->usb_buf[0])
 			break;
 	} while (--retry);
 	if (retry == 0)
@@ -699,7 +699,7 @@
 		sd->ag_cnt = -1;
 }
 
-static void sd_start_12a(struct gspca_dev *gspca_dev)
+static int sd_start_12a(struct gspca_dev *gspca_dev)
 {
 	struct usb_device *dev = gspca_dev->dev;
 	int Clck = 0x8a; /* lower 0x8X values lead to fps > 30 */
@@ -725,8 +725,9 @@
 	setwhite(gspca_dev);
 	setautogain(gspca_dev);
 	setexposure(gspca_dev);
+	return 0;
 }
-static void sd_start_72a(struct gspca_dev *gspca_dev)
+static int sd_start_72a(struct gspca_dev *gspca_dev)
 {
 	struct usb_device *dev = gspca_dev->dev;
 	int Clck;
@@ -750,6 +751,7 @@
 	reg_w_val(dev, 0x8700, Clck);	/* 0x27 clock */
 	reg_w_val(dev, 0x8112, 0x10 | 0x20);
 	setautogain(gspca_dev);
+	return 0;
 }
 
 static void sd_stopN(struct gspca_dev *gspca_dev)
@@ -1064,7 +1066,7 @@
 	    {
 		.id = V4L2_CID_DO_WHITE_BALANCE,
 		.type = V4L2_CTRL_TYPE_INTEGER,
-		.name = "While Balance",
+		.name = "White Balance",
 		.minimum = WHITE_MIN,
 		.maximum = WHITE_MAX,
 		.step = 1,
diff --git a/drivers/media/video/gspca/stk014.c b/drivers/media/video/gspca/stk014.c
index 2f2de42..d9d6491 100644
--- a/drivers/media/video/gspca/stk014.c
+++ b/drivers/media/video/gspca/stk014.c
@@ -324,7 +324,7 @@
 }
 
 /* -- start the camera -- */
-static void sd_start(struct gspca_dev *gspca_dev)
+static int sd_start(struct gspca_dev *gspca_dev)
 {
 	int ret, value;
 
@@ -374,9 +374,10 @@
 	set_par(gspca_dev, 0x01000000);
 	set_par(gspca_dev, 0x01000000);
 	PDEBUG(D_STREAM, "camera started alt: 0x%02x", gspca_dev->alt);
-	return;
+	return 0;
 out:
 	PDEBUG(D_ERR|D_STREAM, "camera start err %d", ret);
+	return ret;
 }
 
 static void sd_stopN(struct gspca_dev *gspca_dev)
diff --git a/drivers/media/video/gspca/sunplus.c b/drivers/media/video/gspca/sunplus.c
index 1cfcc6c..bd92886 100644
--- a/drivers/media/video/gspca/sunplus.c
+++ b/drivers/media/video/gspca/sunplus.c
@@ -961,7 +961,7 @@
 	return 0;
 }
 
-static void sd_start(struct gspca_dev *gspca_dev)
+static int sd_start(struct gspca_dev *gspca_dev)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
 	struct usb_device *dev = gspca_dev->dev;
@@ -1042,6 +1042,7 @@
 		break;
 	}
 	sp5xx_initContBrigHueRegisters(gspca_dev);
+	return 0;
 }
 
 static void sd_stopN(struct gspca_dev *gspca_dev)
diff --git a/drivers/media/video/gspca/t613.c b/drivers/media/video/gspca/t613.c
index f034c74..b561f7c 100644
--- a/drivers/media/video/gspca/t613.c
+++ b/drivers/media/video/gspca/t613.c
@@ -28,8 +28,6 @@
 
 #include "gspca.h"
 
-#define MAX_GAMMA 0x10		/* 0 to 15 */
-
 #define V4L2_CID_EFFECTS (V4L2_CID_PRIVATE_BASE + 0)
 
 MODULE_AUTHOR("Leandro Costantino <le_costantino@pixartargentina.com.ar>");
@@ -49,6 +47,10 @@
 	unsigned char whitebalance;
 	unsigned char mirror;
 	unsigned char effect;
+
+	__u8 sensor;
+#define SENSOR_TAS5130A 0
+#define SENSOR_OTHER 1
 };
 
 /* V4L2 controls supported by the driver */
@@ -83,9 +85,9 @@
 	  .type = V4L2_CTRL_TYPE_INTEGER,
 	  .name = "Brightness",
 	  .minimum = 0,
-	  .maximum = 0x0f,
+	  .maximum = 14,
 	  .step = 1,
-	  .default_value = 0x09,
+	  .default_value = 8,
 	  },
 	 .set = sd_setbrightness,
 	 .get = sd_getbrightness,
@@ -118,16 +120,17 @@
 	 .set = sd_setcolors,
 	 .get = sd_getcolors,
 	 },
-#define SD_GAMMA 3
+#define GAMMA_MAX 16
+#define GAMMA_DEF 10
 	{
 	 {
 	  .id = V4L2_CID_GAMMA,	/* (gamma on win) */
 	  .type = V4L2_CTRL_TYPE_INTEGER,
-	  .name = "Gamma (Untested)",
+	  .name = "Gamma",
 	  .minimum = 0,
-	  .maximum = MAX_GAMMA,
+	  .maximum = GAMMA_MAX - 1,
 	  .step = 1,
-	  .default_value = 0x09,
+	  .default_value = GAMMA_DEF,
 	  },
 	 .set = sd_setgamma,
 	 .get = sd_getgamma,
@@ -197,7 +200,7 @@
 	  .type = V4L2_CTRL_TYPE_INTEGER,
 	  .name = "Sharpness",
 	  .minimum = 0,
-	  .maximum = MAX_GAMMA,	/* 0 to 16 */
+	  .maximum = 15,
 	  .step = 1,
 	  .default_value = 0x06,
 	  },
@@ -258,7 +261,6 @@
 		.priv = 0},
 };
 
-#define T16_OFFSET_DATA 631
 #define MAX_EFFECTS 7
 /* easily done by soft, this table could be removed,
  * i keep it here just in case */
@@ -272,87 +274,87 @@
 	{0xa8, 0xc8, 0xc6, 0xd2, 0xc0, 0x40},	/* Negative */
 };
 
-static const __u8 gamma_table[MAX_GAMMA][34] = {
-	{0x90, 0x00, 0x91, 0x3e, 0x92, 0x69, 0x93, 0x85,
+static const __u8 gamma_table[GAMMA_MAX][34] = {
+	{0x90, 0x00, 0x91, 0x3e, 0x92, 0x69, 0x93, 0x85,	/* 0 */
 	 0x94, 0x95, 0x95, 0xa1, 0x96, 0xae, 0x97, 0xb9,
 	 0x98, 0xc2, 0x99, 0xcb, 0x9a, 0xd4, 0x9b, 0xdb,
 	 0x9c, 0xe3, 0x9d, 0xea, 0x9e, 0xf1, 0x9f, 0xf8,
 	 0xa0, 0xff},
-	{0x90, 0x00, 0x91, 0x33, 0x92, 0x5A, 0x93, 0x75,
-	 0x94, 0x85, 0x95, 0x93, 0x96, 0xA1, 0x97, 0xAD,
-	 0x98, 0xB7, 0x99, 0xC2, 0x9A, 0xCB, 0x9B, 0xD4,
-	 0x9C, 0xDE, 0x9D, 0xE7, 0x9E, 0xF0, 0x9F, 0xF7,
+	{0x90, 0x00, 0x91, 0x33, 0x92, 0x5a, 0x93, 0x75,	/* 1 */
+	 0x94, 0x85, 0x95, 0x93, 0x96, 0xa1, 0x97, 0xad,
+	 0x98, 0xb7, 0x99, 0xc2, 0x9a, 0xcb, 0x9b, 0xd4,
+	 0x9c, 0xde, 0x9D, 0xe7, 0x9e, 0xf0, 0x9f, 0xf7,
 	 0xa0, 0xff},
-	{0x90, 0x00, 0x91, 0x2F, 0x92, 0x51, 0x93, 0x6B,
-	 0x94, 0x7C, 0x95, 0x8A, 0x96, 0x99, 0x97, 0xA6,
-	 0x98, 0xB1, 0x99, 0xBC, 0x9A, 0xC6, 0x9B, 0xD0,
-	 0x9C, 0xDB, 0x9D, 0xE4, 0x9E, 0xED, 0x9F, 0xF6,
+	{0x90, 0x00, 0x91, 0x2f, 0x92, 0x51, 0x93, 0x6b,	/* 2 */
+	 0x94, 0x7c, 0x95, 0x8a, 0x96, 0x99, 0x97, 0xa6,
+	 0x98, 0xb1, 0x99, 0xbc, 0x9a, 0xc6, 0x9b, 0xd0,
+	 0x9c, 0xdb, 0x9d, 0xe4, 0x9e, 0xed, 0x9f, 0xf6,
 	 0xa0, 0xff},
-	{0x90, 0x00, 0x91, 0x29, 0x92, 0x48, 0x93, 0x60,
-	 0x94, 0x72, 0x95, 0x81, 0x96, 0x90, 0x97, 0x9E,
-	 0x98, 0xAA, 0x99, 0xB5, 0x9A, 0xBF, 0x9B, 0xCB,
-	 0x9C, 0xD6, 0x9D, 0xE1, 0x9E, 0xEB, 0x9F, 0xF5,
+	{0x90, 0x00, 0x91, 0x29, 0x92, 0x48, 0x93, 0x60,	/* 3 */
+	 0x94, 0x72, 0x95, 0x81, 0x96, 0x90, 0x97, 0x9e,
+	 0x98, 0xaa, 0x99, 0xb5, 0x9a, 0xbf, 0x9b, 0xcb,
+	 0x9c, 0xd6, 0x9d, 0xe1, 0x9e, 0xeb, 0x9f, 0xf5,
 	 0xa0, 0xff},
-	{0x90, 0x00, 0x91, 0x23, 0x92, 0x3F, 0x93, 0x55,
+	{0x90, 0x00, 0x91, 0x23, 0x92, 0x3f, 0x93, 0x55,	/* 4 */
 	 0x94, 0x68, 0x95, 0x77, 0x96, 0x86, 0x97, 0x95,
-	 0x98, 0xA2, 0x99, 0xAD, 0x9A, 0xB9, 0x9B, 0xC6,
-	 0x9C, 0xD2, 0x9D, 0xDE, 0x9E, 0xE9, 0x9F, 0xF4,
+	 0x98, 0xa2, 0x99, 0xad, 0x9a, 0xb9, 0x9b, 0xc6,
+	 0x9c, 0xd2, 0x9d, 0xde, 0x9e, 0xe9, 0x9f, 0xf4,
 	 0xa0, 0xff},
-	{0x90, 0x00, 0x91, 0x1B, 0x92, 0x33, 0x93, 0x48,
+	{0x90, 0x00, 0x91, 0x1b, 0x92, 0x33, 0x93, 0x48,	/* 5 */
 	 0x94, 0x59, 0x95, 0x69, 0x96, 0x79, 0x97, 0x87,
-	 0x98, 0x96, 0x99, 0xA3, 0x9A, 0xB1, 0x9B, 0xBE,
-	 0x9C, 0xCC, 0x9D, 0xDA, 0x9E, 0xE7, 0x9F, 0xF3,
+	 0x98, 0x96, 0x99, 0xa3, 0x9a, 0xb1, 0x9b, 0xbe,
+	 0x9c, 0xcc, 0x9d, 0xda, 0x9e, 0xe7, 0x9f, 0xf3,
 	 0xa0, 0xff},
-	{0x90, 0x00, 0x91, 0x02, 0x92, 0x10, 0x93, 0x20,
+	{0x90, 0x00, 0x91, 0x02, 0x92, 0x10, 0x93, 0x20,	/* 6 */
 	 0x94, 0x32, 0x95, 0x40, 0x96, 0x57, 0x97, 0x67,
 	 0x98, 0x77, 0x99, 0x88, 0x9a, 0x99, 0x9b, 0xaa,
 	 0x9c, 0xbb, 0x9d, 0xcc, 0x9e, 0xdd, 0x9f, 0xee,
 	 0xa0, 0xff},
-	{0x90, 0x00, 0x91, 0x02, 0x92, 0x14, 0x93, 0x26,
-	 0x94, 0x38, 0x95, 0x4A, 0x96, 0x60, 0x97, 0x70,
-	 0x98, 0x80, 0x99, 0x90, 0x9A, 0xA0, 0x9B, 0xB0,
-	 0x9C, 0xC0, 0x9D, 0xD0, 0x9E, 0xE0, 0x9F, 0xF0,
+	{0x90, 0x00, 0x91, 0x02, 0x92, 0x14, 0x93, 0x26,	/* 7 */
+	 0x94, 0x38, 0x95, 0x4a, 0x96, 0x60, 0x97, 0x70,
+	 0x98, 0x80, 0x99, 0x90, 0x9a, 0xa0, 0x9b, 0xb0,
+	 0x9c, 0xc0, 0x9D, 0xd0, 0x9e, 0xe0, 0x9f, 0xf0,
 	 0xa0, 0xff},
-	{0x90, 0x00, 0x91, 0x10, 0x92, 0x22, 0x93, 0x35,
-	 0x94, 0x47, 0x95, 0x5A, 0x96, 0x69, 0x97, 0x79,
-	 0x98, 0x88, 0x99, 0x97, 0x9A, 0xA7, 0x9B, 0xB6,
-	 0x9C, 0xC4, 0x9D, 0xD3, 0x9E, 0xE0, 0x9F, 0xF0,
+	{0x90, 0x00, 0x91, 0x10, 0x92, 0x22, 0x93, 0x35,	/* 8 */
+	 0x94, 0x47, 0x95, 0x5a, 0x96, 0x69, 0x97, 0x79,
+	 0x98, 0x88, 0x99, 0x97, 0x9a, 0xa7, 0x9b, 0xb6,
+	 0x9c, 0xc4, 0x9d, 0xd3, 0x9e, 0xe0, 0x9f, 0xf0,
 	 0xa0, 0xff},
-	{0x90, 0x00, 0x91, 0x10, 0x92, 0x26, 0x93, 0x40,
+	{0x90, 0x00, 0x91, 0x10, 0x92, 0x26, 0x93, 0x40,	/* 9 */
 	 0x94, 0x54, 0x95, 0x65, 0x96, 0x75, 0x97, 0x84,
 	 0x98, 0x93, 0x99, 0xa1, 0x9a, 0xb0, 0x9b, 0xbd,
 	 0x9c, 0xca, 0x9d, 0xd6, 0x9e, 0xe0, 0x9f, 0xf0,
 	 0xa0, 0xff},
-	{0x90, 0x00, 0x91, 0x18, 0x92, 0x2B, 0x93, 0x44,
-	 0x94, 0x60, 0x95, 0x70, 0x96, 0x80, 0x97, 0x8E,
-	 0x98, 0x9C, 0x99, 0xAA, 0x9A, 0xB7, 0x9B, 0xC4,
-	 0x9C, 0xD0, 0x9D, 0xD8, 0x9E, 0xE2, 0x9F, 0xF0,
+	{0x90, 0x00, 0x91, 0x18, 0x92, 0x2b, 0x93, 0x44,	/* 10 */
+	 0x94, 0x60, 0x95, 0x70, 0x96, 0x80, 0x97, 0x8e,
+	 0x98, 0x9c, 0x99, 0xaa, 0x9a, 0xb7, 0x9b, 0xc4,
+	 0x9c, 0xd0, 0x9d, 0xd8, 0x9e, 0xe2, 0x9f, 0xf0,
 	 0xa0, 0xff},
-	{0x90, 0x00, 0x91, 0x1A, 0x92, 0x34, 0x93, 0x52,
-	 0x94, 0x66, 0x95, 0x7E, 0x96, 0x8D, 0x97, 0x9B,
-	 0x98, 0xA8, 0x99, 0xB4, 0x9A, 0xC0, 0x9B, 0xCB,
-	 0x9C, 0xD6, 0x9D, 0xE1, 0x9E, 0xEB, 0x9F, 0xF5,
+	{0x90, 0x00, 0x91, 0x1a, 0x92, 0x34, 0x93, 0x52,	/* 11 */
+	 0x94, 0x66, 0x95, 0x7e, 0x96, 0x8D, 0x97, 0x9B,
+	 0x98, 0xa8, 0x99, 0xb4, 0x9a, 0xc0, 0x9b, 0xcb,
+	 0x9c, 0xd6, 0x9d, 0xe1, 0x9e, 0xeb, 0x9f, 0xf5,
 	 0xa0, 0xff},
-	{0x90, 0x00, 0x91, 0x3F, 0x92, 0x5A, 0x93, 0x6E,
-	 0x94, 0x7F, 0x95, 0x8E, 0x96, 0x9C, 0x97, 0xA8,
-	 0x98, 0xB4, 0x99, 0xBF, 0x9A, 0xC9, 0x9B, 0xD3,
-	 0x9C, 0xDC, 0x9D, 0xE5, 0x9E, 0xEE, 0x9F, 0xF6,
-	 0xA0, 0xFF},
-	{0x90, 0x00, 0x91, 0x54, 0x92, 0x6F, 0x93, 0x83,
-	 0x94, 0x93, 0x95, 0xA0, 0x96, 0xAD, 0x97, 0xB7,
-	 0x98, 0xC2, 0x99, 0xCB, 0x9A, 0xD4, 0x9B, 0xDC,
-	 0x9C, 0xE4, 0x9D, 0xEB, 0x9E, 0xF2, 0x9F, 0xF9,
+	{0x90, 0x00, 0x91, 0x3f, 0x92, 0x5a, 0x93, 0x6e,	/* 12 */
+	 0x94, 0x7f, 0x95, 0x8e, 0x96, 0x9c, 0x97, 0xa8,
+	 0x98, 0xb4, 0x99, 0xbf, 0x9a, 0xc9, 0x9b, 0xd3,
+	 0x9c, 0xdc, 0x9d, 0xe5, 0x9e, 0xee, 0x9f, 0xf6,
 	 0xa0, 0xff},
-	{0x90, 0x00, 0x91, 0x6E, 0x92, 0x88, 0x93, 0x9A,
-	 0x94, 0xA8, 0x95, 0xB3, 0x96, 0xBD, 0x97, 0xC6,
-	 0x98, 0xCF, 0x99, 0xD6, 0x9A, 0xDD, 0x9B, 0xE3,
-	 0x9C, 0xE9, 0x9D, 0xEF, 0x9E, 0xF4, 0x9F, 0xFA,
+	{0x90, 0x00, 0x91, 0x54, 0x92, 0x6f, 0x93, 0x83,	/* 13 */
+	 0x94, 0x93, 0x95, 0xa0, 0x96, 0xad, 0x97, 0xb7,
+	 0x98, 0xc2, 0x99, 0xcb, 0x9a, 0xd4, 0x9b, 0xdc,
+	 0x9c, 0xe4, 0x9d, 0xeb, 0x9e, 0xf2, 0x9f, 0xf9,
 	 0xa0, 0xff},
-	{0x90, 0x00, 0x91, 0x93, 0x92, 0xA8, 0x93, 0xB7,
-	 0x94, 0xC1, 0x95, 0xCA, 0x96, 0xD2, 0x97, 0xD8,
-	 0x98, 0xDE, 0x99, 0xE3, 0x9A, 0xE8, 0x9B, 0xED,
-	 0x9C, 0xF1, 0x9D, 0xF5, 0x9E, 0xF8, 0x9F, 0xFC,
-	 0xA0, 0xFF}
+	{0x90, 0x00, 0x91, 0x6e, 0x92, 0x88, 0x93, 0x9a,	/* 14 */
+	 0x94, 0xa8, 0x95, 0xb3, 0x96, 0xbd, 0x97, 0xc6,
+	 0x98, 0xcf, 0x99, 0xd6, 0x9a, 0xdd, 0x9b, 0xe3,
+	 0x9c, 0xe9, 0x9d, 0xef, 0x9e, 0xf4, 0x9f, 0xfa,
+	 0xa0, 0xff},
+	{0x90, 0x00, 0x91, 0x93, 0x92, 0xa8, 0x93, 0xb7,	/* 15 */
+	 0x94, 0xc1, 0x95, 0xca, 0x96, 0xd2, 0x97, 0xd8,
+	 0x98, 0xde, 0x99, 0xe3, 0x9a, 0xe8, 0x9b, 0xed,
+	 0x9c, 0xf1, 0x9d, 0xf5, 0x9e, 0xf8, 0x9f, 0xfc,
+	 0xa0, 0xff}
 };
 
 static const __u8 tas5130a_sensor_init[][8] = {
@@ -364,7 +366,7 @@
 };
 
 /* read 1 byte */
-static int reg_r_1(struct gspca_dev *gspca_dev,
+static int reg_r(struct gspca_dev *gspca_dev,
 		   __u16 index)
 {
 	usb_control_msg(gspca_dev->dev,
@@ -378,26 +380,26 @@
 }
 
 static void reg_w(struct gspca_dev *gspca_dev,
-			__u16 value,
-			__u16 index,
-			const __u8 *buffer, __u16 len)
+		  __u16 index)
 {
-	if (buffer == NULL) {
-		usb_control_msg(gspca_dev->dev,
-				usb_sndctrlpipe(gspca_dev->dev, 0),
-				0,
-			   USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
-				value, index,
-				NULL, 0, 500);
-		return;
-	}
+	usb_control_msg(gspca_dev->dev,
+			usb_sndctrlpipe(gspca_dev->dev, 0),
+			0,
+			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
+			0, index,
+			NULL, 0, 500);
+}
+
+static void i2c_w(struct gspca_dev *gspca_dev,
+		  const __u8 *buffer, __u16 len)
+{
 	if (len <= USB_BUF_SZ) {
 		memcpy(gspca_dev->usb_buf, buffer, len);
 		usb_control_msg(gspca_dev->dev,
 				usb_sndctrlpipe(gspca_dev->dev, 0),
 				0,
 			   USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
-				value, index,
+				0x01, 0,
 				gspca_dev->usb_buf, len, 500);
 	} else {
 		__u8 *tmpbuf;
@@ -408,12 +410,56 @@
 				usb_sndctrlpipe(gspca_dev->dev, 0),
 				0,
 			   USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
-				value, index,
+				0x01, 0,
 				tmpbuf, len, 500);
 		kfree(tmpbuf);
 	}
 }
 
+static void other_sensor_init(struct gspca_dev *gspca_dev)
+{
+	int i;
+	const __u8 *p;
+	__u8 byte;
+	__u8 val[6] = {0x62, 0, 0x64, 0, 0x60, 0x05};
+	static const __u8 sensor_init[] = {
+		0xdf, 0x6d,
+		0xdd, 0x18,
+		0x5a, 0xe0,
+		0x5c, 0x07,
+		0x5d, 0xb0,
+		0x5e, 0x1e,
+		0x60, 0x71,
+		0xef, 0x00,
+		0xe9, 0x00,
+		0xea, 0x00,
+		0x90, 0x24,
+		0x91, 0xb2,
+		0x82, 0x32,
+		0xfd, 0x00,
+		0xfd, 0x01,
+		0xfd, 0x41,
+		0x00			/* table end */
+	};
+
+	p = sensor_init;
+	while (*p != 0) {
+		val[1] = *p++;
+		val[3] = *p++;
+		if (*p == 0)
+			reg_w(gspca_dev, 0x3c80);
+		i2c_w(gspca_dev, val, sizeof val);
+		i = 4;
+		while (--i >= 0) {
+			msleep(15);
+			byte = reg_r(gspca_dev, 0x60);
+			if (!(byte & 0x01))
+				break;
+		}
+	}
+			reg_w(gspca_dev, 0x3c80);
+}
+
 /* this function is called at probe time */
 static int sd_config(struct gspca_dev *gspca_dev,
 		     const struct usb_device_id *id)
@@ -430,7 +476,7 @@
 	sd->brightness = sd_ctrls[SD_BRIGHTNESS].qctrl.default_value;
 	sd->contrast = sd_ctrls[SD_CONTRAST].qctrl.default_value;
 	sd->colors = sd_ctrls[SD_COLOR].qctrl.default_value;
-	sd->gamma = sd_ctrls[SD_GAMMA].qctrl.default_value;
+	sd->gamma = GAMMA_DEF;
 	sd->mirror = sd_ctrls[SD_MIRROR].qctrl.default_value;
 	sd->freq = sd_ctrls[SD_LIGHTFREQ].qctrl.default_value;
 	sd->whitebalance = sd_ctrls[SD_WHITE_BALANCE].qctrl.default_value;
@@ -439,27 +485,37 @@
 	return 0;
 }
 
-static int init_default_parameters(struct gspca_dev *gspca_dev)
+static void setgamma(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	PDEBUG(D_CONF, "Gamma: %d", sd->gamma);
+	i2c_w(gspca_dev, gamma_table[sd->gamma], sizeof gamma_table[0]);
+}
+
+/* this function is called at probe and resume time */
+static int sd_init(struct gspca_dev *gspca_dev)
 {
 	/* some of this registers are not really neded, because
 	 * they are overriden by setbrigthness, setcontrast, etc,
 	 * but wont hurt anyway, and can help someone with similar webcam
 	 * to see the initial parameters.*/
-	int i = 0;
-	__u8 test_byte;
+	struct sd *sd = (struct sd *) gspca_dev;
+	int i;
+	__u8 byte, test_byte;
 
 	static const __u8 read_indexs[] =
 		{ 0x06, 0x07, 0x0a, 0x0b, 0x66, 0x80, 0x81, 0x8e, 0x8f, 0xa5,
 		  0xa6, 0xa8, 0xbb, 0xbc, 0xc6, 0x00, 0x00 };
-	static const __u8 n1[6] =
+	static const __u8 n1[] =
 			{0x08, 0x03, 0x09, 0x03, 0x12, 0x04};
-	static const __u8 n2[2] =
+	static const __u8 n2[] =
 			{0x08, 0x00};
-	static const __u8 nset[6] =
-		{ 0x61, 0x68, 0x62, 0xff, 0x60, 0x07 };
-	static const __u8 n3[6] =
+	static const __u8 nset[] =
+			{ 0x61, 0x68, 0x62, 0xff, 0x60, 0x07 };
+	static const __u8 n3[] =
 			{0x61, 0x68, 0x65, 0x0a, 0x60, 0x04};
-	static const __u8 n4[0x46] =
+	static const __u8 n4[] =
 		{0x09, 0x01, 0x12, 0x04, 0x66, 0x8a, 0x80, 0x3c,
 		 0x81, 0x22, 0x84, 0x50, 0x8a, 0x78, 0x8b, 0x68,
 		 0x8c, 0x88, 0x8e, 0x33, 0x8f, 0x24, 0xaa, 0xb1,
@@ -469,33 +525,26 @@
 		 0x65, 0x0a, 0xbb, 0x86, 0xaf, 0x58, 0xb0, 0x68,
 		 0x87, 0x40, 0x89, 0x2b, 0x8d, 0xff, 0x83, 0x40,
 		 0xac, 0x84, 0xad, 0x86, 0xaf, 0x46};
-	static const __u8 nset4[18] = {
+	static const __u8 nset4[] = {
 		0xe0, 0x60, 0xe1, 0xa8, 0xe2, 0xe0, 0xe3, 0x60, 0xe4, 0xa8,
 		0xe5, 0xe0, 0xe6, 0x60, 0xe7, 0xa8,
 		0xe8, 0xe0
 	};
 	/* ojo puede ser 0xe6 en vez de 0xe9 */
-	static const __u8 nset2[20] = {
+	static const __u8 nset2[] = {
 		0xd0, 0xbb, 0xd1, 0x28, 0xd2, 0x10, 0xd3, 0x10, 0xd4, 0xbb,
 		0xd5, 0x28, 0xd6, 0x1e, 0xd7, 0x27,
 		0xd8, 0xc8, 0xd9, 0xfc
 	};
-	static const __u8 missing[8] =
+	static const __u8 missing[] =
 		{ 0x87, 0x20, 0x88, 0x20, 0x89, 0x20, 0x80, 0x38 };
-	static const __u8 nset3[18] = {
+	static const __u8 nset3[] = {
 		0xc7, 0x60, 0xc8, 0xa8, 0xc9, 0xe0, 0xca, 0x60, 0xcb, 0xa8,
 		0xcc, 0xe0, 0xcd, 0x60, 0xce, 0xa8,
 		0xcf, 0xe0
 	};
-	static const __u8 nset5[4] =
-		{ 0x8f, 0x24, 0xc3, 0x00 };	/* bright */
-	static const __u8 nset6[34] = {
-		0x90, 0x00, 0x91, 0x1c, 0x92, 0x30, 0x93, 0x43, 0x94, 0x54,
-		0x95, 0x65, 0x96, 0x75, 0x97, 0x84,
-		0x98, 0x93, 0x99, 0xa1, 0x9a, 0xb0, 0x9b, 0xbd, 0x9c, 0xca,
-		0x9d, 0xd8, 0x9e, 0xe5, 0x9f, 0xf2,
-		0xa0, 0xff
-	};			/* Gamma */
+	static const __u8 nset5[] =
+			{ 0x8f, 0x24, 0xc3, 0x00 };	/* bright */
 	static const __u8 nset7[4] =
 			{ 0x66, 0xca, 0xa8, 0xf8 };	/* 50/60 Hz */
 	static const __u8 nset9[4] =
@@ -505,95 +554,111 @@
 	static const __u8 nset10[6] =
 			{ 0x0c, 0x03, 0xab, 0x10, 0x81, 0x20 };
 
-	reg_w(gspca_dev, 0x01, 0x0000, n1, 0x06);
-	reg_w(gspca_dev, 0x01, 0x0000, nset, 0x06);
-	reg_r_1(gspca_dev, 0x0063);
-	reg_w(gspca_dev, 0x01, 0x0000, n2, 0x02);
+	byte = reg_r(gspca_dev, 0x06);
+	test_byte = reg_r(gspca_dev, 0x07);
+	if (byte == 0x08 && test_byte == 0x07) {
+		PDEBUG(D_CONF, "other sensor");
+		sd->sensor = SENSOR_OTHER;
+	} else {
+		PDEBUG(D_CONF, "sensor %02x %02x", byte, test_byte);
+		sd->sensor = SENSOR_TAS5130A;
+	}
 
+	i2c_w(gspca_dev, n1, sizeof n1);
+	test_byte = 0;
+	i = 5;
+	while (--i >= 0) {
+		i2c_w(gspca_dev, nset, sizeof nset);
+		msleep(5);
+		test_byte = reg_r(gspca_dev, 0x0063);
+		msleep(100);
+		if (test_byte == 0x17)
+			break;		/* OK */
+	}
+	if (i < 0) {
+		err("Bad sensor reset %02x", test_byte);
+/*		return -EIO; */
+/*fixme: test - continue */
+	}
+	i2c_w(gspca_dev, n2, sizeof n2);
+
+	i = 0;
 	while (read_indexs[i] != 0x00) {
-		test_byte = reg_r_1(gspca_dev, read_indexs[i]);
-		PDEBUG(D_CONF, "Reg 0x%02x => 0x%02x", read_indexs[i],
+		test_byte = reg_r(gspca_dev, read_indexs[i]);
+		PDEBUG(D_STREAM, "Reg 0x%02x = 0x%02x", read_indexs[i],
 		       test_byte);
 		i++;
 	}
 
-	reg_w(gspca_dev, 0x01, 0x0000, n3, 0x06);
-	reg_w(gspca_dev, 0x01, 0x0000, n4, 0x46);
-	reg_r_1(gspca_dev, 0x0080);
-	reg_w(gspca_dev, 0x00, 0x2c80, NULL, 0);
-	reg_w(gspca_dev, 0x01, 0x0000, nset2, 0x14);
-	reg_w(gspca_dev, 0x01, 0x0000, nset3, 0x12);
-	reg_w(gspca_dev, 0x01, 0x0000, nset4, 0x12);
-	reg_w(gspca_dev, 0x00, 0x3880, NULL, 0);
-	reg_w(gspca_dev, 0x00, 0x3880, NULL, 0);
-	reg_w(gspca_dev, 0x00, 0x338e, NULL, 0);
-	reg_w(gspca_dev, 0x01, 0x0000, nset5, 0x04);
-	reg_w(gspca_dev, 0x00, 0x00a9, NULL, 0);
-	reg_w(gspca_dev, 0x01, 0x0000, nset6, 0x22);
-	reg_w(gspca_dev, 0x00, 0x86bb, NULL, 0);
-	reg_w(gspca_dev, 0x00, 0x4aa6, NULL, 0);
+	i2c_w(gspca_dev, n3, sizeof n3);
+	i2c_w(gspca_dev, n4, sizeof n4);
+	reg_r(gspca_dev, 0x0080);
+	reg_w(gspca_dev, 0x2c80);
+	i2c_w(gspca_dev, nset2, sizeof nset2);
+	i2c_w(gspca_dev, nset3, sizeof nset3);
+	i2c_w(gspca_dev, nset4, sizeof nset4);
+	reg_w(gspca_dev, 0x3880);
+	reg_w(gspca_dev, 0x3880);
+	reg_w(gspca_dev, 0x338e);
+	i2c_w(gspca_dev, nset5, sizeof nset5);
+	reg_w(gspca_dev, 0x00a9);
+	setgamma(gspca_dev);
+	reg_w(gspca_dev, 0x86bb);
+	reg_w(gspca_dev, 0x4aa6);
 
-	reg_w(gspca_dev, 0x01, 0x0000, missing, 0x08);
+	i2c_w(gspca_dev, missing, sizeof missing);
 
-	reg_w(gspca_dev, 0x00, 0x2087, NULL, 0);
-	reg_w(gspca_dev, 0x00, 0x2088, NULL, 0);
-	reg_w(gspca_dev, 0x00, 0x2089, NULL, 0);
+	reg_w(gspca_dev, 0x2087);
+	reg_w(gspca_dev, 0x2088);
+	reg_w(gspca_dev, 0x2089);
 
-	reg_w(gspca_dev, 0x01, 0x0000, nset7, 0x04);
-	reg_w(gspca_dev, 0x01, 0x0000, nset10, 0x06);
-	reg_w(gspca_dev, 0x01, 0x0000, nset8, 0x06);
-	reg_w(gspca_dev, 0x01, 0x0000, nset9, 0x04);
+	i2c_w(gspca_dev, nset7, sizeof nset7);
+	i2c_w(gspca_dev, nset10, sizeof nset10);
+	i2c_w(gspca_dev, nset8, sizeof nset8);
+	i2c_w(gspca_dev, nset9, sizeof nset9);
 
-	reg_w(gspca_dev, 0x00, 0x2880, NULL, 0);
-	reg_w(gspca_dev, 0x01, 0x0000, nset2, 0x14);
-	reg_w(gspca_dev, 0x01, 0x0000, nset3, 0x12);
-	reg_w(gspca_dev, 0x01, 0x0000, nset4, 0x12);
+	reg_w(gspca_dev, 0x2880);
+	i2c_w(gspca_dev, nset2, sizeof nset2);
+	i2c_w(gspca_dev, nset3, sizeof nset3);
+	i2c_w(gspca_dev, nset4, sizeof nset4);
 
 	return 0;
 }
 
-/* this function is called at probe and resume time */
-static int sd_init(struct gspca_dev *gspca_dev)
-{
-	init_default_parameters(gspca_dev);
-	return 0;
-}
-
 static void setbrightness(struct gspca_dev *gspca_dev)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
 	unsigned int brightness;
-	__u8 set6[4] = { 0x8f, 0x26, 0xc3, 0x80 };
-	brightness = sd->brightness;
+	__u8 set6[4] = { 0x8f, 0x26, 0xc3, 0x00 };
 
+	brightness = sd->brightness;
 	if (brightness < 7) {
-		set6[3] = 0x70 - (brightness * 0xa);
+		set6[3] = 0x70 - brightness * 0x10;
 	} else {
 		set6[1] = 0x24;
-		set6[3] = 0x00 + ((brightness - 7) * 0xa);
+		set6[3] = 0x00 + ((brightness - 7) * 0x10);
 	}
 
-	reg_w(gspca_dev, 0x01, 0x0000, set6, 4);
+	i2c_w(gspca_dev, set6, sizeof set6);
 }
 
 static void setflip(struct gspca_dev *gspca_dev)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
-
 	__u8 flipcmd[8] =
-	    { 0x62, 0x07, 0x63, 0x03, 0x64, 0x00, 0x60, 0x09 };
+		{0x62, 0x07, 0x63, 0x03, 0x64, 0x00, 0x60, 0x09};
 
-	if (sd->mirror == 1)
+	if (sd->mirror)
 		flipcmd[3] = 0x01;
 
-	reg_w(gspca_dev, 0x01, 0x0000, flipcmd, 8);
+	i2c_w(gspca_dev, flipcmd, sizeof flipcmd);
 }
 
 static void seteffect(struct gspca_dev *gspca_dev)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
 
-	reg_w(gspca_dev, 0x01, 0x0000, effects_table[sd->effect], 0x06);
+	i2c_w(gspca_dev, effects_table[sd->effect], sizeof effects_table[0]);
 	if (sd->effect == 1 || sd->effect == 5) {
 		PDEBUG(D_CONF,
 		       "This effect have been disabled for webcam \"safety\"");
@@ -601,9 +666,9 @@
 	}
 
 	if (sd->effect == 1 || sd->effect == 4)
-		reg_w(gspca_dev, 0x00, 0x4aa6, NULL, 0);
+		reg_w(gspca_dev, 0x4aa6);
 	else
-		reg_w(gspca_dev, 0x00, 0xfaa6, NULL, 0);
+		reg_w(gspca_dev, 0xfaa6);
 }
 
 static void setwhitebalance(struct gspca_dev *gspca_dev)
@@ -616,7 +681,7 @@
 	if (sd->whitebalance == 1)
 		white_balance[7] = 0x3c;
 
-	reg_w(gspca_dev, 0x01, 0x0000, white_balance, 8);
+	i2c_w(gspca_dev, white_balance, sizeof white_balance);
 }
 
 static void setlightfreq(struct gspca_dev *gspca_dev)
@@ -627,21 +692,21 @@
 	if (sd->freq == 2)	/* 60hz */
 		freq[1] = 0x00;
 
-	reg_w(gspca_dev, 0x1, 0x0000, freq, 0x4);
+	i2c_w(gspca_dev, freq, sizeof freq);
 }
 
 static void setcontrast(struct gspca_dev *gspca_dev)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
 	unsigned int contrast = sd->contrast;
-	__u16 reg_to_write = 0x00;
+	__u16 reg_to_write;
 
 	if (contrast < 7)
 		reg_to_write = 0x8ea9 - (0x200 * contrast);
 	else
 		reg_to_write = (0x00a9 + ((contrast - 7) * 0x200));
 
-	reg_w(gspca_dev, 0x00, reg_to_write, NULL, 0);
+	reg_w(gspca_dev, reg_to_write);
 }
 
 static void setcolors(struct gspca_dev *gspca_dev)
@@ -650,11 +715,7 @@
 	__u16 reg_to_write;
 
 	reg_to_write = 0xc0bb + sd->colors * 0x100;
-	reg_w(gspca_dev, 0x00, reg_to_write, NULL, 0);
-}
-
-static void setgamma(struct gspca_dev *gspca_dev)
-{
+	reg_w(gspca_dev, reg_to_write);
 }
 
 static void setsharpness(struct gspca_dev *gspca_dev)
@@ -664,7 +725,99 @@
 
 	reg_to_write = 0x0aa6 + 0x1000 * sd->sharpness;
 
-	reg_w(gspca_dev, 0x00, reg_to_write, NULL, 0);
+	reg_w(gspca_dev, reg_to_write);
+}
+
+static int sd_start(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	int i, mode;
+	static const __u8 t1[] = { 0x66, 0x00, 0xa8, 0xe8 };
+	__u8 t2[] = { 0x07, 0x00, 0x0d, 0x60, 0x0e, 0x80 };
+	static const __u8 t3[] =
+		{ 0xb3, 0x07, 0xb4, 0x00, 0xb5, 0x88, 0xb6, 0x02, 0xb7, 0x06,
+		  0xb8, 0x00, 0xb9, 0xe7, 0xba, 0x01 };
+	static const __u8 t4[] = { 0x0b, 0x04, 0x0a, 0x40 };
+
+	mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode]. priv;
+	switch (mode) {
+	case 1:		/* 352x288 */
+		t2[1] = 0x40;
+		break;
+	case 2:		/* 320x240 */
+		t2[1] = 0x10;
+		break;
+	case 3:		/* 176x144 */
+		t2[1] = 0x50;
+		break;
+	case 4:		/* 160x120 */
+		t2[1] = 0x20;
+		break;
+	default:	/* 640x480 (0x00) */
+		break;
+	}
+
+	if (sd->sensor == SENSOR_TAS5130A) {
+		i = 0;
+		while (tas5130a_sensor_init[i][0] != 0) {
+			i2c_w(gspca_dev, tas5130a_sensor_init[i],
+					 sizeof tas5130a_sensor_init[0]);
+			i++;
+		}
+		reg_w(gspca_dev, 0x3c80);
+		/* just in case and to keep sync with logs (for mine) */
+		i2c_w(gspca_dev, tas5130a_sensor_init[3],
+				 sizeof tas5130a_sensor_init[0]);
+		reg_w(gspca_dev, 0x3c80);
+	} else {
+		other_sensor_init(gspca_dev);
+	}
+	/* just in case and to keep sync with logs  (for mine) */
+	i2c_w(gspca_dev, t1, sizeof t1);
+	i2c_w(gspca_dev, t2, sizeof t2);
+	reg_r(gspca_dev, 0x0012);
+	i2c_w(gspca_dev, t3, sizeof t3);
+	reg_w(gspca_dev, 0x0013);
+	i2c_w(gspca_dev, t4, sizeof t4);
+	/* restart on each start, just in case, sometimes regs goes wrong
+	 * when using controls from app */
+	setbrightness(gspca_dev);
+	setcontrast(gspca_dev);
+	setcolors(gspca_dev);
+	return 0;
+}
+
+static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+			struct gspca_frame *frame,	/* target */
+			__u8 *data,			/* isoc packet */
+			int len)			/* iso packet length */
+{
+	static __u8 ffd9[] = { 0xff, 0xd9 };
+
+	if (data[0] == 0x5a) {
+		/* Control Packet, after this came the header again,
+		 * but extra bytes came in the packet before this,
+		 * sometimes an EOF arrives, sometimes not... */
+		return;
+	}
+	data += 2;
+	len -= 2;
+	if (data[0] == 0xff && data[1] == 0xd8) {
+		/* extra bytes....., could be processed too but would be
+		 * a waste of time, right now leave the application and
+		 * libjpeg do it for ourserlves.. */
+		frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
+					ffd9, 2);
+		gspca_frame_add(gspca_dev, FIRST_PACKET, frame, data, len);
+		return;
+	}
+
+	if (data[len - 2] == 0xff && data[len - 1] == 0xd9) {
+		/* Just in case, i have seen packets with the marker,
+		 * other's do not include it... */
+		len -= 2;
+	}
+	gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
 }
 
 static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
@@ -788,6 +941,7 @@
 static int sd_getgamma(struct gspca_dev *gspca_dev, __s32 *val)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
+
 	*val = sd->gamma;
 	return 0;
 }
@@ -835,9 +989,9 @@
 
 	sd->autogain = val;
 	if (val != 0)
-		reg_w(gspca_dev, 0x00, 0xf48e, NULL, 0);
+		reg_w(gspca_dev, 0xf48e);
 	else
-		reg_w(gspca_dev, 0x00, 0xb48e, NULL, 0);
+		reg_w(gspca_dev, 0xb48e);
 	return 0;
 }
 
@@ -849,99 +1003,6 @@
 	return 0;
 }
 
-static void sd_start(struct gspca_dev *gspca_dev)
-{
-	int mode;
-
-	static const __u8 t1[] = { 0x66, 0x00, 0xa8, 0xe8 };
-	__u8 t2[] = { 0x07, 0x00, 0x0d, 0x60, 0x0e, 0x80 };
-	static const __u8 t3[] =
-		{ 0xb3, 0x07, 0xb4, 0x00, 0xb5, 0x88, 0xb6, 0x02, 0xb7, 0x06,
-		  0xb8, 0x00, 0xb9, 0xe7, 0xba, 0x01 };
-	static const __u8 t4[] = { 0x0b, 0x04, 0x0a, 0x40 };
-
-	mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode]. priv;
-	switch (mode) {
-	case 1:		/* 352x288 */
-		t2[1] = 0x40;
-		break;
-	case 2:		/* 320x240 */
-		t2[1] = 0x10;
-		break;
-	case 3:		/* 176x144 */
-		t2[1] = 0x50;
-		break;
-	case 4:		/* 160x120 */
-		t2[1] = 0x20;
-		break;
-	default:	/* 640x480 (0x00) */
-		break;
-	}
-
-	reg_w(gspca_dev, 0x01, 0x0000, tas5130a_sensor_init[0], 0x8);
-	reg_w(gspca_dev, 0x01, 0x0000, tas5130a_sensor_init[1], 0x8);
-	reg_w(gspca_dev, 0x01, 0x0000, tas5130a_sensor_init[2], 0x8);
-	reg_w(gspca_dev, 0x01, 0x0000, tas5130a_sensor_init[3], 0x8);
-	reg_w(gspca_dev, 0x00, 0x3c80, NULL, 0);
-		/* just in case and to keep sync with logs  (for mine) */
-	reg_w(gspca_dev, 0x01, 0x0000, tas5130a_sensor_init[3], 0x8);
-	reg_w(gspca_dev, 0x00, 0x3c80, NULL, 0);
-		/* just in case and to keep sync with logs  (for mine) */
-	reg_w(gspca_dev, 0x01, 0x0000, t1, 4);
-	reg_w(gspca_dev, 0x01, 0x0000, t2, 6);
-	reg_r_1(gspca_dev, 0x0012);
-	reg_w(gspca_dev, 0x01, 0x0000, t3, 0x10);
-	reg_w(gspca_dev, 0x00, 0x0013, NULL, 0);
-	reg_w(gspca_dev, 0x01, 0x0000, t4, 0x4);
-	/* restart on each start, just in case, sometimes regs goes wrong
-	 * when using controls from app */
-	setbrightness(gspca_dev);
-	setcontrast(gspca_dev);
-	setcolors(gspca_dev);
-}
-
-static void sd_pkt_scan(struct gspca_dev *gspca_dev,
-			struct gspca_frame *frame,	/* target */
-			__u8 *data,			/* isoc packet */
-			int len)			/* iso packet length */
-{
-	int sof = 0;
-	static __u8 ffd9[] = { 0xff, 0xd9 };
-
-	if (data[0] == 0x5a) {
-		/* Control Packet, after this came the header again,
-		 * but extra bytes came in the packet before this,
-		 * sometimes an EOF arrives, sometimes not... */
-		return;
-	}
-
-	if (data[len - 1] == 0xff && data[len] == 0xd9) {
-		/* Just in case, i have seen packets with the marker,
-		 * other's do not include it... */
-		data += 2;
-		len -= 4;
-	} else if (data[2] == 0xff && data[3] == 0xd8) {
-		sof = 1;
-		data += 2;
-		len -= 2;
-	} else {
-		data += 2;
-		len -= 2;
-	}
-
-	if (sof) {
-		/* extra bytes....., could be processed too but would be
-		 * a waste of time, right now leave the application and
-		 * libjpeg do it for ourserlves.. */
-		frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
-					ffd9, 2);
-		gspca_frame_add(gspca_dev, FIRST_PACKET, frame, data, len);
-		return;
-	}
-
-	gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
-}
-
 static int sd_querymenu(struct gspca_dev *gspca_dev,
 			struct v4l2_querymenu *menu)
 {
diff --git a/drivers/media/video/gspca/tv8532.c b/drivers/media/video/gspca/tv8532.c
index 084af05..968a591 100644
--- a/drivers/media/video/gspca/tv8532.c
+++ b/drivers/media/video/gspca/tv8532.c
@@ -390,7 +390,7 @@
 }
 
 /* -- start the camera -- */
-static void sd_start(struct gspca_dev *gspca_dev)
+static int sd_start(struct gspca_dev *gspca_dev)
 {
 	reg_w_1(gspca_dev, TV8532_AD_SLOPE, 0x32);
 	reg_w_1(gspca_dev, TV8532_AD_BITCTRL, 0x00);
@@ -443,6 +443,7 @@
 	/************************************************/
 	tv_8532_PollReg(gspca_dev);
 	reg_w_1(gspca_dev, TV8532_UDP_UPDATE, 0x00);	/* 0x31 */
+	return 0;
 }
 
 static void sd_stopN(struct gspca_dev *gspca_dev)
diff --git a/drivers/media/video/gspca/vc032x.c b/drivers/media/video/gspca/vc032x.c
index bd4c226..be46d92 100644
--- a/drivers/media/video/gspca/vc032x.c
+++ b/drivers/media/video/gspca/vc032x.c
@@ -80,7 +80,6 @@
 		.step    = 1,
 #define FREQ_DEF 1
 		.default_value = FREQ_DEF,
-		.default_value = 1,
 	    },
 	    .set = sd_setfreq,
 	    .get = sd_getfreq,
@@ -1502,7 +1501,7 @@
 	usb_exchange(gspca_dev, ov7660_freq_tb[sd->lightfreq]);
 }
 
-static void sd_start(struct gspca_dev *gspca_dev)
+static int sd_start(struct gspca_dev *gspca_dev)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
 	const __u8 *GammaT = NULL;
@@ -1586,7 +1585,7 @@
 		break;
 	default:
 		PDEBUG(D_PROBE, "Damned !! no sensor found Bye");
-		return;
+		return -EMEDIUMTYPE;
 	}
 	if (GammaT && MatrixT) {
 		put_tab_to_reg(gspca_dev, GammaT, 17, 0xb84a);
@@ -1622,6 +1621,7 @@
 		setautogain(gspca_dev);
 		setlightfreq(gspca_dev);
 	}
+	return 0;
 }
 
 static void sd_stopN(struct gspca_dev *gspca_dev)
diff --git a/drivers/media/video/gspca/zc3xx.c b/drivers/media/video/gspca/zc3xx.c
index 8d7c27e..d0a4451 100644
--- a/drivers/media/video/gspca/zc3xx.c
+++ b/drivers/media/video/gspca/zc3xx.c
@@ -6576,8 +6576,8 @@
 		 cs2102_60HZ, cs2102_60HZScale},
 /* SENSOR_CS2102K 1 */
 		{cs2102_NoFliker, cs2102_NoFlikerScale,
-		 cs2102_50HZ, cs2102_50HZScale,
-		 cs2102_60HZ, cs2102_60HZScale},
+		 NULL, NULL, /* currently disabled */
+		 NULL, NULL},
 /* SENSOR_GC0305 2 */
 		{gc0305_NoFliker, gc0305_NoFliker,
 		 gc0305_50HZ, gc0305_50HZ,
@@ -7178,7 +7178,7 @@
 	return 0;
 }
 
-static void sd_start(struct gspca_dev *gspca_dev)
+static int sd_start(struct gspca_dev *gspca_dev)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
 	struct usb_device *dev = gspca_dev->dev;
@@ -7331,6 +7331,7 @@
 		reg_w(dev, 0x02, 0x0008);
 		break;
 	}
+	return 0;
 }
 
 static void sd_stop0(struct gspca_dev *gspca_dev)
diff --git a/drivers/media/video/ir-kbd-i2c.c b/drivers/media/video/ir-kbd-i2c.c
index a30254b..efe8499 100644
--- a/drivers/media/video/ir-kbd-i2c.c
+++ b/drivers/media/video/ir-kbd-i2c.c
@@ -12,6 +12,10 @@
  *      Markus Rechberger <mrechberger@gmail.com>
  * modified for DViCO Fusion HDTV 5 RT GOLD by
  *      Chaogui Zhang <czhang1974@gmail.com>
+ * modified for MSI TV@nywhere Plus by
+ *      Henry Wong <henry@stuffedcow.net>
+ *      Mark Schultz <n9xmj@yahoo.com>
+ *      Brian Rogers <brian_rogers@comcast.net>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -65,7 +69,7 @@
 			       int size, int offset)
 {
 	unsigned char buf[6];
-	int start, range, toggle, dev, code;
+	int start, range, toggle, dev, code, ircode;
 
 	/* poll IR chip */
 	if (size != i2c_master_recv(&ir->c,buf,size))
@@ -85,6 +89,24 @@
 	if (!start)
 		/* no key pressed */
 		return 0;
+	/*
+	 * Hauppauge remotes (black/silver) always use
+	 * specific device ids. If we do not filter the
+	 * device ids then messages destined for devices
+	 * such as TVs (id=0) will get through causing
+	 * mis-fired events.
+	 *
+	 * We also filter out invalid key presses which
+	 * produce annoying debug log entries.
+	 */
+	ircode= (start << 12) | (toggle << 11) | (dev << 6) | code;
+	if ((ircode & 0x1fff)==0x1fff)
+		/* invalid key press */
+		return 0;
+
+	if (dev!=0x1e && dev!=0x1f)
+		/* not a hauppauge remote */
+		return 0;
 
 	if (!range)
 		code += 64;
@@ -94,7 +116,7 @@
 
 	/* return key */
 	*ir_key = code;
-	*ir_raw = (start << 12) | (toggle << 11) | (dev << 6) | code;
+	*ir_raw = ircode;
 	return 1;
 }
 
@@ -224,9 +246,15 @@
 static void ir_work(struct work_struct *work)
 {
 	struct IR_i2c *ir = container_of(work, struct IR_i2c, work);
+	int polling_interval = 100;
+
+	/* MSI TV@nywhere Plus requires more frequent polling
+	   otherwise it will miss some keypresses */
+	if (ir->c.adapter->id == I2C_HW_SAA7134 && ir->c.addr == 0x30)
+		polling_interval = 50;
 
 	ir_key_poll(ir);
-	mod_timer(&ir->timer, jiffies + msecs_to_jiffies(100));
+	mod_timer(&ir->timer, jiffies + msecs_to_jiffies(polling_interval));
 }
 
 /* ----------------------------------------------------------------------- */
@@ -465,9 +493,37 @@
 			(1 == rc) ? "yes" : "no");
 		if (1 == rc) {
 			ir_attach(adap, probe[i], 0, 0);
-			break;
+			return 0;
 		}
 	}
+
+	/* Special case for MSI TV@nywhere Plus remote */
+	if (adap->id == I2C_HW_SAA7134) {
+		u8 temp;
+
+		/* MSI TV@nywhere Plus controller doesn't seem to
+		   respond to probes unless we read something from
+		   an existing device. Weird... */
+
+		msg.addr = 0x50;
+		rc = i2c_transfer(adap, &msg, 1);
+			dprintk(1, "probe 0x%02x @ %s: %s\n",
+			msg.addr, adap->name,
+			(1 == rc) ? "yes" : "no");
+
+		/* Now do the probe. The controller does not respond
+		   to 0-byte reads, so we use a 1-byte read instead. */
+		msg.addr = 0x30;
+		msg.len = 1;
+		msg.buf = &temp;
+		rc = i2c_transfer(adap, &msg, 1);
+		dprintk(1, "probe 0x%02x @ %s: %s\n",
+			msg.addr, adap->name,
+			(1 == rc) ? "yes" : "no");
+		if (1 == rc)
+			ir_attach(adap, msg.addr, 0, 0);
+	}
+
 	return 0;
 }
 
diff --git a/drivers/media/video/ivtv/ivtv-cards.h b/drivers/media/video/ivtv/ivtv-cards.h
index 381af1b..0b8fe85 100644
--- a/drivers/media/video/ivtv/ivtv-cards.h
+++ b/drivers/media/video/ivtv/ivtv-cards.h
@@ -154,7 +154,7 @@
 #define IVTV_CAP_ENCODER (V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_TUNER | \
 			  V4L2_CAP_AUDIO | V4L2_CAP_READWRITE | V4L2_CAP_VBI_CAPTURE | \
 			  V4L2_CAP_SLICED_VBI_CAPTURE)
-#define IVTV_CAP_DECODER (V4L2_CAP_VBI_OUTPUT | V4L2_CAP_VIDEO_OUTPUT | \
+#define IVTV_CAP_DECODER (V4L2_CAP_VIDEO_OUTPUT | \
 			  V4L2_CAP_SLICED_VBI_OUTPUT | V4L2_CAP_VIDEO_OUTPUT_OVERLAY)
 
 struct ivtv_card_video_input {
diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c
index 4afc7ea..aeaa13f 100644
--- a/drivers/media/video/ivtv/ivtv-driver.c
+++ b/drivers/media/video/ivtv/ivtv-driver.c
@@ -61,14 +61,14 @@
 #include "tuner-xc2028.h"
 
 /* var to keep track of the number of array elements in use */
-int ivtv_cards_active = 0;
+int ivtv_cards_active;
 
 /* If you have already X v4l cards, then set this to X. This way
    the device numbers stay matched. Example: you have a WinTV card
    without radio and a PVR-350 with. Normally this would give a
    video1 device together with a radio0 device for the PVR. By
    setting this to 1 you ensure that radio0 is now also radio1. */
-int ivtv_first_minor = 0;
+int ivtv_first_minor;
 
 /* Master variable for all ivtv info */
 struct ivtv *ivtv_cards[IVTV_MAX_CARDS];
@@ -251,7 +251,7 @@
 		 "\t\t\t-1 is autodetect, 0 is off, 1 is on\n"
 		 "\t\t\tDefault is autodetect");
 
-MODULE_PARM_DESC(ivtv_first_minor, "Set minor assigned to first card");
+MODULE_PARM_DESC(ivtv_first_minor, "Set kernel number assigned to first card");
 
 MODULE_AUTHOR("Kevin Thayer, Chris Kennedy, Hans Verkuil");
 MODULE_DESCRIPTION("CX23415/CX23416 driver");
@@ -655,9 +655,9 @@
 
 	if (itv->card == NULL) {
 		itv->card = ivtv_get_card(IVTV_CARD_PVR_150);
-		IVTV_ERR("Unknown card: vendor/device: %04x/%04x\n",
+		IVTV_ERR("Unknown card: vendor/device: [%04x:%04x]\n",
 		     itv->dev->vendor, itv->dev->device);
-		IVTV_ERR("              subsystem vendor/device: %04x/%04x\n",
+		IVTV_ERR("              subsystem vendor/device: [%04x:%04x]\n",
 		     itv->dev->subsystem_vendor, itv->dev->subsystem_device);
 		IVTV_ERR("              %s based\n", chipname);
 		IVTV_ERR("Defaulting to %s card\n", itv->card->name);
@@ -720,7 +720,7 @@
 	itv->speed = 1000;
 
 	/* VBI */
-	itv->vbi.in.type = V4L2_BUF_TYPE_SLICED_VBI_CAPTURE;
+	itv->vbi.in.type = V4L2_BUF_TYPE_VBI_CAPTURE;
 	itv->vbi.sliced_in = &itv->vbi.in.fmt.sliced;
 
 	/* Init the sg table for osd/yuv output */
diff --git a/drivers/media/video/ivtv/ivtv-driver.h b/drivers/media/video/ivtv/ivtv-driver.h
index 2ceb522..bc29436 100644
--- a/drivers/media/video/ivtv/ivtv-driver.h
+++ b/drivers/media/video/ivtv/ivtv-driver.h
@@ -49,7 +49,6 @@
 #include <linux/i2c-algo-bit.h>
 #include <linux/list.h>
 #include <linux/unistd.h>
-#include <linux/byteorder/swab.h>
 #include <linux/pagemap.h>
 #include <linux/scatterlist.h>
 #include <linux/workqueue.h>
@@ -507,6 +506,8 @@
 	struct v4l2_rect main_rect;
 	u32 v4l2_src_w;
 	u32 v4l2_src_h;
+
+	u8 running; /* Have any frames been displayed */
 };
 
 #define IVTV_VBI_FRAMES 32
@@ -751,6 +752,12 @@
 /* First-open initialization: load firmware, init cx25840, etc. */
 int ivtv_init_on_first_open(struct ivtv *itv);
 
+/* Test if the current VBI mode is raw (1) or sliced (0) */
+static inline int ivtv_raw_vbi(const struct ivtv *itv)
+{
+	return itv->vbi.in.type == V4L2_BUF_TYPE_VBI_CAPTURE;
+}
+
 /* This is a PCI post thing, where if the pci register is not read, then
    the write doesn't always take effect right away. By reading back the
    register any pending PCI writes will be performed (in order), and so
diff --git a/drivers/media/video/ivtv/ivtv-fileops.c b/drivers/media/video/ivtv/ivtv-fileops.c
index 7ec5c99..b7457fc 100644
--- a/drivers/media/video/ivtv/ivtv-fileops.c
+++ b/drivers/media/video/ivtv/ivtv-fileops.c
@@ -39,7 +39,7 @@
    associated VBI streams are also automatically claimed.
    Possible error returns: -EBUSY if someone else has claimed
    the stream or 0 on success. */
-int ivtv_claim_stream(struct ivtv_open_id *id, int type)
+static int ivtv_claim_stream(struct ivtv_open_id *id, int type)
 {
 	struct ivtv *itv = id->itv;
 	struct ivtv_stream *s = &itv->streams[type];
@@ -78,7 +78,7 @@
 	if (type == IVTV_DEC_STREAM_TYPE_MPG) {
 		vbi_type = IVTV_DEC_STREAM_TYPE_VBI;
 	} else if (type == IVTV_ENC_STREAM_TYPE_MPG &&
-		   itv->vbi.insert_mpeg && itv->vbi.sliced_in->service_set) {
+		   itv->vbi.insert_mpeg && !ivtv_raw_vbi(itv)) {
 		vbi_type = IVTV_ENC_STREAM_TYPE_VBI;
 	} else {
 		return 0;
@@ -305,7 +305,7 @@
 
 	if (len > ucount) len = ucount;
 	if (itv->vbi.insert_mpeg && s->type == IVTV_ENC_STREAM_TYPE_MPG &&
-	    itv->vbi.sliced_in->service_set && buf != &itv->vbi.sliced_mpeg_buf) {
+	    !ivtv_raw_vbi(itv) && buf != &itv->vbi.sliced_mpeg_buf) {
 		const char *start = buf->buf + buf->readpos;
 		const char *p = start + 1;
 		const u8 *q;
@@ -372,7 +372,7 @@
 	/* Each VBI buffer is one frame, the v4l2 API says that for VBI the frames should
 	   arrive one-by-one, so make sure we never output more than one VBI frame at a time */
 	if (s->type == IVTV_DEC_STREAM_TYPE_VBI ||
-			(s->type == IVTV_ENC_STREAM_TYPE_VBI && itv->vbi.sliced_in->service_set))
+	    (s->type == IVTV_ENC_STREAM_TYPE_VBI && !ivtv_raw_vbi(itv)))
 		single_frame = 1;
 
 	for (;;) {
diff --git a/drivers/media/video/ivtv/ivtv-fileops.h b/drivers/media/video/ivtv/ivtv-fileops.h
index 2c8d518..df81e79 100644
--- a/drivers/media/video/ivtv/ivtv-fileops.h
+++ b/drivers/media/video/ivtv/ivtv-fileops.h
@@ -38,11 +38,6 @@
 
 /* Utilities */
 
-/* Try to claim a stream for the filehandle. Return 0 on success,
-   -EBUSY if stream already claimed. Once a stream is claimed, it
-   remains claimed until the associated filehandle is closed. */
-int ivtv_claim_stream(struct ivtv_open_id *id, int type);
-
 /* Release a previously claimed stream. */
 void ivtv_release_stream(struct ivtv_stream *s);
 
diff --git a/drivers/media/video/ivtv/ivtv-gpio.c b/drivers/media/video/ivtv/ivtv-gpio.c
index bc22905..74a4484 100644
--- a/drivers/media/video/ivtv/ivtv-gpio.c
+++ b/drivers/media/video/ivtv/ivtv-gpio.c
@@ -124,7 +124,7 @@
 }
 
 /* Xceive tuner reset function */
-int ivtv_reset_tuner_gpio(void *dev, int cmd, int value)
+int ivtv_reset_tuner_gpio(void *dev, int component, int cmd, int value)
 {
 	struct i2c_algo_bit_data *algo = dev;
 	struct ivtv *itv = algo->data;
diff --git a/drivers/media/video/ivtv/ivtv-gpio.h b/drivers/media/video/ivtv/ivtv-gpio.h
index 964a265..48b6291 100644
--- a/drivers/media/video/ivtv/ivtv-gpio.h
+++ b/drivers/media/video/ivtv/ivtv-gpio.h
@@ -24,7 +24,7 @@
 /* GPIO stuff */
 void ivtv_gpio_init(struct ivtv *itv);
 void ivtv_reset_ir_gpio(struct ivtv *itv);
-int ivtv_reset_tuner_gpio(void *dev, int cmd, int value);
+int ivtv_reset_tuner_gpio(void *dev, int component, int cmd, int value);
 int ivtv_gpio(struct ivtv *itv, unsigned int command, void *arg);
 
 #endif
diff --git a/drivers/media/video/ivtv/ivtv-i2c.c b/drivers/media/video/ivtv/ivtv-i2c.c
index af15423..24700c2 100644
--- a/drivers/media/video/ivtv/ivtv-i2c.c
+++ b/drivers/media/video/ivtv/ivtv-i2c.c
@@ -64,8 +64,6 @@
 #include "ivtv-gpio.h"
 #include "ivtv-i2c.h"
 
-#include <media/ir-kbd-i2c.h>
-
 /* i2c implementation for cx23415/6 chip, ivtv project.
  * Author: Kevin Thayer (nufan_wfk at yahoo.com)
  */
diff --git a/drivers/media/video/ivtv/ivtv-ioctl.c b/drivers/media/video/ivtv/ivtv-ioctl.c
index 6103030..8696527 100644
--- a/drivers/media/video/ivtv/ivtv-ioctl.c
+++ b/drivers/media/video/ivtv/ivtv-ioctl.c
@@ -101,18 +101,15 @@
 	}
 }
 
-static int check_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal)
+static void check_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal)
 {
 	int f, l;
-	u16 set = 0;
 
 	for (f = 0; f < 2; f++) {
 		for (l = 0; l < 24; l++) {
 			fmt->service_lines[f][l] = select_service_from_set(f, l, fmt->service_lines[f][l], is_pal);
-			set |= fmt->service_lines[f][l];
 		}
 	}
-	return set != 0;
 }
 
 u16 ivtv_get_service_set(struct v4l2_sliced_vbi_format *fmt)
@@ -474,7 +471,7 @@
 	int h = fmt->fmt.pix.height;
 
 	w = min(w, 720);
-	w = max(w, 1);
+	w = max(w, 2);
 	h = min(h, itv->is_50hz ? 576 : 480);
 	h = max(h, 2);
 	ivtv_g_fmt_vid_cap(file, fh, fmt);
@@ -512,27 +509,20 @@
 static int ivtv_try_fmt_vid_out(struct file *file, void *fh, struct v4l2_format *fmt)
 {
 	struct ivtv_open_id *id = fh;
-	s32 w, h;
-	int field;
-	int ret;
+	struct ivtv *itv = id->itv;
+	s32 w = fmt->fmt.pix.width;
+	s32 h = fmt->fmt.pix.height;
+	int field = fmt->fmt.pix.field;
+	int ret = ivtv_g_fmt_vid_out(file, fh, fmt);
 
-	w = fmt->fmt.pix.width;
-	h = fmt->fmt.pix.height;
-	field = fmt->fmt.pix.field;
-	ret = ivtv_g_fmt_vid_out(file, fh, fmt);
+	w = min(w, 720);
+	w = max(w, 2);
+	h = min(h, itv->is_out_50hz ? 576 : 480);
+	h = max(h, 2);
+	if (id->type == IVTV_DEC_STREAM_TYPE_YUV)
+		fmt->fmt.pix.field = field;
 	fmt->fmt.pix.width = w;
 	fmt->fmt.pix.height = h;
-	if (!ret && id->type == IVTV_DEC_STREAM_TYPE_YUV) {
-		fmt->fmt.pix.field = field;
-		if (fmt->fmt.pix.width < 2)
-			fmt->fmt.pix.width = 2;
-		if (fmt->fmt.pix.width > 720)
-			fmt->fmt.pix.width = 720;
-		if (fmt->fmt.pix.height < 2)
-			fmt->fmt.pix.height = 2;
-		if (fmt->fmt.pix.height > 576)
-			fmt->fmt.pix.height = 576;
-	}
 	return ret;
 }
 
@@ -560,9 +550,9 @@
 	struct ivtv_open_id *id = fh;
 	struct ivtv *itv = id->itv;
 	struct cx2341x_mpeg_params *p = &itv->params;
+	int ret = ivtv_try_fmt_vid_cap(file, fh, fmt);
 	int w = fmt->fmt.pix.width;
 	int h = fmt->fmt.pix.height;
-	int ret = ivtv_try_fmt_vid_cap(file, fh, fmt);
 
 	if (ret)
 		return ret;
@@ -585,8 +575,11 @@
 {
 	struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
 
+	if (!ivtv_raw_vbi(itv) && atomic_read(&itv->capturing) > 0)
+		return -EBUSY;
 	itv->vbi.sliced_in->service_set = 0;
-	itv->video_dec_func(itv, VIDIOC_S_FMT, &itv->vbi.in);
+	itv->vbi.in.type = V4L2_BUF_TYPE_VBI_CAPTURE;
+	itv->video_dec_func(itv, VIDIOC_S_FMT, fmt);
 	return ivtv_g_fmt_vbi_cap(file, fh, fmt);
 }
 
@@ -600,10 +593,10 @@
 	if (ret || id->type == IVTV_DEC_STREAM_TYPE_VBI)
 		return ret;
 
-	if (check_service_set(vbifmt, itv->is_50hz) == 0)
-		return -EINVAL;
-	if (atomic_read(&itv->capturing) > 0)
+	check_service_set(vbifmt, itv->is_50hz);
+	if (ivtv_raw_vbi(itv) && atomic_read(&itv->capturing) > 0)
 		return -EBUSY;
+	itv->vbi.in.type = V4L2_BUF_TYPE_SLICED_VBI_CAPTURE;
 	itv->video_dec_func(itv, VIDIOC_S_FMT, fmt);
 	memcpy(itv->vbi.sliced_in, vbifmt, sizeof(*itv->vbi.sliced_in));
 	return 0;
@@ -651,8 +644,6 @@
 		itv->dma_data_req_size =
 			1080 * ((yi->v4l2_src_h + 31) & ~31);
 
-	/* Force update of yuv registers */
-	yi->yuv_forced_update = 1;
 	return 0;
 }
 
@@ -761,7 +752,7 @@
 
 	strlcpy(vcap->driver, IVTV_DRIVER_NAME, sizeof(vcap->driver));
 	strlcpy(vcap->card, itv->card_name, sizeof(vcap->card));
-	strlcpy(vcap->bus_info, pci_name(itv->dev), sizeof(vcap->bus_info));
+	snprintf(vcap->bus_info, sizeof(vcap->bus_info), "PCI:%s", pci_name(itv->dev));
 	vcap->version = IVTV_DRIVER_VERSION; 	    /* version */
 	vcap->capabilities = itv->v4l2_cap; 	    /* capabilities */
 	return 0;
@@ -1370,6 +1361,9 @@
 	if (itv->osd_global_alpha_state)
 		fb->flags |= V4L2_FBUF_FLAG_GLOBAL_ALPHA;
 
+	if (yi->track_osd)
+		fb->flags |= V4L2_FBUF_FLAG_OVERLAY;
+
 	pixfmt &= 7;
 
 	/* no local alpha for RGB565 or unknown formats */
@@ -1389,8 +1383,6 @@
 		else
 			fb->flags |= V4L2_FBUF_FLAG_LOCAL_ALPHA;
 	}
-	if (yi->track_osd)
-		fb->flags |= V4L2_FBUF_FLAG_OVERLAY;
 
 	return 0;
 }
diff --git a/drivers/media/video/ivtv/ivtv-irq.c b/drivers/media/video/ivtv/ivtv-irq.c
index 34f3ab8..f5d00ec 100644
--- a/drivers/media/video/ivtv/ivtv-irq.c
+++ b/drivers/media/video/ivtv/ivtv-irq.c
@@ -753,7 +753,7 @@
 	 */
 	unsigned int frame = read_reg(0x28c0) & 1;
 	struct yuv_playback_info *yi = &itv->yuv_info;
-	int last_dma_frame = atomic_read(&itv->yuv_info.next_dma_frame);
+	int last_dma_frame = atomic_read(&yi->next_dma_frame);
 	struct yuv_frame_info *f = &yi->new_frame_info[last_dma_frame];
 
 	if (0) IVTV_DEBUG_IRQ("DEC VSYNC\n");
@@ -772,6 +772,7 @@
 				next_dma_frame = (next_dma_frame + 1) % IVTV_YUV_BUFFERS;
 				atomic_set(&yi->next_dma_frame, next_dma_frame);
 				yi->fields_lapsed = -1;
+				yi->running = 1;
 			}
 		}
 	}
@@ -804,9 +805,11 @@
 		}
 
 		/* Check if we need to update the yuv registers */
-		if ((yi->yuv_forced_update || f->update) && last_dma_frame != -1) {
+		if (yi->running && (yi->yuv_forced_update || f->update)) {
 			if (!f->update) {
-				last_dma_frame = (u8)(last_dma_frame - 1) % IVTV_YUV_BUFFERS;
+				last_dma_frame =
+					(u8)(atomic_read(&yi->next_dma_frame) -
+						 1) % IVTV_YUV_BUFFERS;
 				f = &yi->new_frame_info[last_dma_frame];
 			}
 
diff --git a/drivers/media/video/ivtv/ivtv-streams.c b/drivers/media/video/ivtv/ivtv-streams.c
index 730e85d..5bbf31e 100644
--- a/drivers/media/video/ivtv/ivtv-streams.c
+++ b/drivers/media/video/ivtv/ivtv-streams.c
@@ -75,7 +75,7 @@
 static struct {
 	const char *name;
 	int vfl_type;
-	int minor_offset;
+	int num_offset;
 	int dma, pio;
 	enum v4l2_buf_type buf_type;
 	const struct file_operations *fops;
@@ -171,8 +171,8 @@
 static int ivtv_prep_dev(struct ivtv *itv, int type)
 {
 	struct ivtv_stream *s = &itv->streams[type];
-	int minor_offset = ivtv_stream_info[type].minor_offset;
-	int minor;
+	int num_offset = ivtv_stream_info[type].num_offset;
+	int num = itv->num + ivtv_first_minor + num_offset;
 
 	/* These four fields are always initialized. If v4l2dev == NULL, then
 	   this stream is not in use. In that case no other fields but these
@@ -188,9 +188,6 @@
 	if (type >= IVTV_DEC_STREAM_TYPE_MPG && !(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
 		return 0;
 
-	/* card number + user defined offset + device offset */
-	minor = itv->num + ivtv_first_minor + minor_offset;
-
 	/* User explicitly selected 0 buffers for these streams, so don't
 	   create them. */
 	if (ivtv_stream_info[type].dma != PCI_DMA_NONE &&
@@ -211,7 +208,7 @@
 	snprintf(s->v4l2dev->name, sizeof(s->v4l2dev->name), "ivtv%d %s",
 			itv->num, s->name);
 
-	s->v4l2dev->minor = minor;
+	s->v4l2dev->num = num;
 	s->v4l2dev->parent = &itv->dev->dev;
 	s->v4l2dev->fops = ivtv_stream_info[type].fops;
 	s->v4l2dev->release = video_device_release;
@@ -250,39 +247,46 @@
 {
 	struct ivtv_stream *s = &itv->streams[type];
 	int vfl_type = ivtv_stream_info[type].vfl_type;
-	int minor;
+	int num;
 
 	if (s->v4l2dev == NULL)
 		return 0;
 
-	minor = s->v4l2dev->minor;
+	num = s->v4l2dev->num;
+	/* card number + user defined offset + device offset */
+	if (type != IVTV_ENC_STREAM_TYPE_MPG) {
+		struct ivtv_stream *s_mpg = &itv->streams[IVTV_ENC_STREAM_TYPE_MPG];
+
+		if (s_mpg->v4l2dev)
+			num = s_mpg->v4l2dev->num + ivtv_stream_info[type].num_offset;
+	}
+
 	/* Register device. First try the desired minor, then any free one. */
-	if (video_register_device(s->v4l2dev, vfl_type, minor) &&
-			video_register_device(s->v4l2dev, vfl_type, -1)) {
-		IVTV_ERR("Couldn't register v4l2 device for %s minor %d\n",
-				s->name, minor);
+	if (video_register_device(s->v4l2dev, vfl_type, num)) {
+		IVTV_ERR("Couldn't register v4l2 device for %s kernel number %d\n",
+				s->name, num);
 		video_device_release(s->v4l2dev);
 		s->v4l2dev = NULL;
 		return -ENOMEM;
 	}
+	num = s->v4l2dev->num;
 
 	switch (vfl_type) {
 	case VFL_TYPE_GRABBER:
 		IVTV_INFO("Registered device video%d for %s (%d kB)\n",
-			s->v4l2dev->minor, s->name, itv->options.kilobytes[type]);
+			num, s->name, itv->options.kilobytes[type]);
 		break;
 	case VFL_TYPE_RADIO:
 		IVTV_INFO("Registered device radio%d for %s\n",
-			s->v4l2dev->minor - MINOR_VFL_TYPE_RADIO_MIN, s->name);
+			num, s->name);
 		break;
 	case VFL_TYPE_VBI:
 		if (itv->options.kilobytes[type])
 			IVTV_INFO("Registered device vbi%d for %s (%d kB)\n",
-				s->v4l2dev->minor - MINOR_VFL_TYPE_VBI_MIN,
-				s->name, itv->options.kilobytes[type]);
+				num, s->name, itv->options.kilobytes[type]);
 		else
 			IVTV_INFO("Registered device vbi%d for %s\n",
-				s->v4l2dev->minor - MINOR_VFL_TYPE_VBI_MIN, s->name);
+				num, s->name);
 		break;
 	}
 	return 0;
@@ -330,7 +334,7 @@
 
 static void ivtv_vbi_setup(struct ivtv *itv)
 {
-	int raw = itv->vbi.sliced_in->service_set == 0;
+	int raw = ivtv_raw_vbi(itv);
 	u32 data[CX2341X_MBOX_MAX_DATA];
 	int lines;
 	int i;
diff --git a/drivers/media/video/ivtv/ivtv-vbi.c b/drivers/media/video/ivtv/ivtv-vbi.c
index 1ce9deb..4a37a7d 100644
--- a/drivers/media/video/ivtv/ivtv-vbi.c
+++ b/drivers/media/video/ivtv/ivtv-vbi.c
@@ -334,7 +334,7 @@
 	int y;
 
 	/* Raw VBI data */
-	if (streamtype == IVTV_ENC_STREAM_TYPE_VBI && itv->vbi.sliced_in->service_set == 0) {
+	if (streamtype == IVTV_ENC_STREAM_TYPE_VBI && ivtv_raw_vbi(itv)) {
 		u8 type;
 
 		ivtv_buf_swap(buf);
diff --git a/drivers/media/video/ivtv/ivtv-yuv.c b/drivers/media/video/ivtv/ivtv-yuv.c
index 3092ff1..ee91107 100644
--- a/drivers/media/video/ivtv/ivtv-yuv.c
+++ b/drivers/media/video/ivtv/ivtv-yuv.c
@@ -1147,6 +1147,7 @@
 	IVTV_DEBUG_YUV("ivtv_yuv_close\n");
 	ivtv_waitq(&itv->vsync_waitq);
 
+	yi->running = 0;
 	atomic_set(&yi->next_dma_frame, -1);
 	atomic_set(&yi->next_fill_frame, 0);
 
diff --git a/drivers/media/video/ivtv/ivtvfb.c b/drivers/media/video/ivtv/ivtvfb.c
index bdfda48..8a4a150 100644
--- a/drivers/media/video/ivtv/ivtvfb.c
+++ b/drivers/media/video/ivtv/ivtvfb.c
@@ -275,7 +275,6 @@
 				  int size_in_bytes)
 {
 	DEFINE_WAIT(wait);
-	int ret = 0;
 	int got_sig = 0;
 
 	mutex_lock(&itv->udma.lock);
@@ -316,7 +315,7 @@
 		return -EINTR;
 	}
 
-	return ret;
+	return 0;
 }
 
 static int ivtvfb_prep_frame(struct ivtv *itv, int cmd, void __user *source,
@@ -368,11 +367,12 @@
 }
 
 static ssize_t ivtvfb_write(struct fb_info *info, const char __user *buf,
-		     size_t count, loff_t *ppos)
+						size_t count, loff_t *ppos)
 {
 	unsigned long p = *ppos;
 	void *dst;
 	int err = 0;
+	int dma_err;
 	unsigned long total_size;
 	struct ivtv *itv = (struct ivtv *) info->par;
 	unsigned long dma_offset =
@@ -399,7 +399,6 @@
 	if (count + p > total_size) {
 		if (!err)
 			err = -ENOSPC;
-
 		count = total_size - p;
 	}
 
@@ -408,39 +407,34 @@
 	if (info->fbops->fb_sync)
 		info->fbops->fb_sync(info);
 
-	if (!access_ok(VERIFY_READ, buf, count)) {
-		IVTVFB_WARN("Invalid userspace pointer 0x%08lx\n",
-			(unsigned long)buf);
-		err = -EFAULT;
-	}
-
-	if (!err) {
-		/* If transfer size > threshold and both src/dst
-		addresses are aligned, use DMA */
-		if (count >= 4096 &&
-		    ((unsigned long)buf & 3) == ((unsigned long)dst & 3)) {
-			/* Odd address = can't DMA. Align */
-			if ((unsigned long)dst & 3) {
-				lead = 4 - ((unsigned long)dst & 3);
-				memcpy(dst, buf, lead);
-				buf += lead;
-				dst += lead;
-			}
-			/* DMA resolution is 32 bits */
-			if ((count - lead) & 3)
-				tail = (count - lead) & 3;
-			/* DMA the data */
-			dma_size = count - lead - tail;
-			err = ivtvfb_prep_dec_dma_to_device(itv,
-			       p + lead + dma_offset, (void *)buf, dma_size);
-			dst += dma_size;
-			buf += dma_size;
-			/* Copy any leftover data */
-			if (tail)
-				memcpy(dst, buf, tail);
-		} else {
-			memcpy(dst, buf, count);
+	/* If transfer size > threshold and both src/dst
+	addresses are aligned, use DMA */
+	if (count >= 4096 &&
+	    ((unsigned long)buf & 3) == ((unsigned long)dst & 3)) {
+		/* Odd address = can't DMA. Align */
+		if ((unsigned long)dst & 3) {
+			lead = 4 - ((unsigned long)dst & 3);
+			if (copy_from_user(dst, buf, lead))
+				return -EFAULT;
+			buf += lead;
+			dst += lead;
 		}
+		/* DMA resolution is 32 bits */
+		if ((count - lead) & 3)
+			tail = (count - lead) & 3;
+		/* DMA the data */
+		dma_size = count - lead - tail;
+		dma_err = ivtvfb_prep_dec_dma_to_device(itv,
+		       p + lead + dma_offset, (void __user *)buf, dma_size);
+		if (dma_err)
+			return dma_err;
+		dst += dma_size;
+		buf += dma_size;
+		/* Copy any leftover data */
+		if (tail && copy_from_user(dst, buf, tail))
+			return -EFAULT;
+	} else if (copy_from_user(dst, buf, count)) {
+		return -EFAULT;
 	}
 
 	if  (!err)
@@ -463,9 +457,12 @@
 			vblank.flags = FB_VBLANK_HAVE_COUNT |FB_VBLANK_HAVE_VCOUNT |
 					FB_VBLANK_HAVE_VSYNC;
 			trace = read_reg(0x028c0) >> 16;
-			if (itv->is_50hz && trace > 312) trace -= 312;
-			else if (itv->is_60hz && trace > 262) trace -= 262;
-			if (trace == 1) vblank.flags |= FB_VBLANK_VSYNCING;
+			if (itv->is_50hz && trace > 312)
+				trace -= 312;
+			else if (itv->is_60hz && trace > 262)
+				trace -= 262;
+			if (trace == 1)
+				vblank.flags |= FB_VBLANK_VSYNCING;
 			vblank.count = itv->last_vsync_field;
 			vblank.vcount = trace;
 			vblank.hcount = 0;
@@ -476,7 +473,8 @@
 
 		case FBIO_WAITFORVSYNC:
 			prepare_to_wait(&itv->vsync_waitq, &wait, TASK_INTERRUPTIBLE);
-			if (!schedule_timeout(msecs_to_jiffies(50))) rc = -ETIMEDOUT;
+			if (!schedule_timeout(msecs_to_jiffies(50)))
+				rc = -ETIMEDOUT;
 			finish_wait(&itv->vsync_waitq, &wait);
 			return rc;
 
diff --git a/drivers/media/video/meye.c b/drivers/media/video/meye.c
index a9ef780..6418f4a 100644
--- a/drivers/media/video/meye.c
+++ b/drivers/media/video/meye.c
@@ -843,17 +843,16 @@
 
 static int meye_open(struct inode *inode, struct file *file)
 {
-	int i, err;
+	int i;
 
-	err = video_exclusive_open(inode, file);
-	if (err < 0)
-		return err;
+	if (test_and_set_bit(0, &meye.in_use))
+		return -EBUSY;
 
 	mchip_hic_stop();
 
 	if (mchip_dma_alloc()) {
 		printk(KERN_ERR "meye: mchip framebuffer allocation failed\n");
-		video_exclusive_release(inode, file);
+		clear_bit(0, &meye.in_use);
 		return -ENOBUFS;
 	}
 
@@ -868,7 +867,7 @@
 {
 	mchip_hic_stop();
 	mchip_dma_free();
-	video_exclusive_release(inode, file);
+	clear_bit(0, &meye.in_use);
 	return 0;
 }
 
@@ -1774,6 +1773,7 @@
 		goto outnotdev;
 	}
 
+	ret = -ENOMEM;
 	meye.mchip_dev = pcidev;
 	meye.video_dev = video_device_alloc();
 	if (!meye.video_dev) {
@@ -1781,7 +1781,6 @@
 		goto outnotdev;
 	}
 
-	ret = -ENOMEM;
 	meye.grab_temp = vmalloc(MCHIP_NB_PAGES_MJPEG * PAGE_SIZE);
 	if (!meye.grab_temp) {
 		printk(KERN_ERR "meye: grab buffer allocation failed\n");
diff --git a/drivers/media/video/meye.h b/drivers/media/video/meye.h
index d535748..5f70a10 100644
--- a/drivers/media/video/meye.h
+++ b/drivers/media/video/meye.h
@@ -311,6 +311,7 @@
 	struct video_device *video_dev;	/* video device parameters */
 	struct video_picture picture;	/* video picture parameters */
 	struct meye_params params;	/* additional parameters */
+	unsigned long in_use;		/* set to 1 if the device is in use */
 #ifdef CONFIG_PM
 	u8 pm_mchip_mode;		/* old mchip mode */
 #endif
diff --git a/drivers/media/video/mt9m001.c b/drivers/media/video/mt9m001.c
index 554d229..0c52437 100644
--- a/drivers/media/video/mt9m001.c
+++ b/drivers/media/video/mt9m001.c
@@ -117,24 +117,51 @@
 
 static int mt9m001_init(struct soc_camera_device *icd)
 {
+	struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd);
+	struct soc_camera_link *icl = mt9m001->client->dev.platform_data;
 	int ret;
 
-	/* Disable chip, synchronous option update */
 	dev_dbg(icd->vdev->parent, "%s\n", __func__);
 
-	ret = reg_write(icd, MT9M001_RESET, 1);
-	if (ret >= 0)
-		ret = reg_write(icd, MT9M001_RESET, 0);
-	if (ret >= 0)
+	if (icl->power) {
+		ret = icl->power(&mt9m001->client->dev, 1);
+		if (ret < 0) {
+			dev_err(icd->vdev->parent,
+				"Platform failed to power-on the camera.\n");
+			return ret;
+		}
+	}
+
+	/* The camera could have been already on, we reset it additionally */
+	if (icl->reset)
+		ret = icl->reset(&mt9m001->client->dev);
+	else
+		ret = -ENODEV;
+
+	if (ret < 0) {
+		/* Either no platform reset, or platform reset failed */
+		ret = reg_write(icd, MT9M001_RESET, 1);
+		if (!ret)
+			ret = reg_write(icd, MT9M001_RESET, 0);
+	}
+	/* Disable chip, synchronous option update */
+	if (!ret)
 		ret = reg_write(icd, MT9M001_OUTPUT_CONTROL, 0);
 
-	return ret >= 0 ? 0 : -EIO;
+	return ret;
 }
 
 static int mt9m001_release(struct soc_camera_device *icd)
 {
+	struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd);
+	struct soc_camera_link *icl = mt9m001->client->dev.platform_data;
+
 	/* Disable the chip */
 	reg_write(icd, MT9M001_OUTPUT_CONTROL, 0);
+
+	if (icl->power)
+		icl->power(&mt9m001->client->dev, 0);
+
 	return 0;
 }
 
@@ -267,24 +294,24 @@
 
 	/* Blanking and start values - default... */
 	ret = reg_write(icd, MT9M001_HORIZONTAL_BLANKING, hblank);
-	if (ret >= 0)
+	if (!ret)
 		ret = reg_write(icd, MT9M001_VERTICAL_BLANKING, vblank);
 
 	/* The caller provides a supported format, as verified per
 	 * call to icd->try_fmt_cap() */
-	if (ret >= 0)
+	if (!ret)
 		ret = reg_write(icd, MT9M001_COLUMN_START, rect->left);
-	if (ret >= 0)
+	if (!ret)
 		ret = reg_write(icd, MT9M001_ROW_START, rect->top);
-	if (ret >= 0)
+	if (!ret)
 		ret = reg_write(icd, MT9M001_WINDOW_WIDTH, rect->width - 1);
-	if (ret >= 0)
+	if (!ret)
 		ret = reg_write(icd, MT9M001_WINDOW_HEIGHT,
 				rect->height + icd->y_skip_top - 1);
-	if (ret >= 0 && mt9m001->autoexposure) {
+	if (!ret && mt9m001->autoexposure) {
 		ret = reg_write(icd, MT9M001_SHUTTER_WIDTH,
 				rect->height + icd->y_skip_top + vblank);
-		if (ret >= 0) {
+		if (!ret) {
 			const struct v4l2_queryctrl *qctrl =
 				soc_camera_find_qctrl(icd->ops,
 						      V4L2_CID_EXPOSURE);
@@ -295,7 +322,7 @@
 		}
 	}
 
-	return ret < 0 ? ret : 0;
+	return ret;
 }
 
 static int mt9m001_try_fmt_cap(struct soc_camera_device *icd,
diff --git a/drivers/media/video/mt9m111.c b/drivers/media/video/mt9m111.c
new file mode 100644
index 0000000..da0b2d5
--- /dev/null
+++ b/drivers/media/video/mt9m111.c
@@ -0,0 +1,973 @@
+/*
+ * Driver for MT9M111 CMOS Image Sensor from Micron
+ *
+ * Copyright (C) 2008, Robert Jarzmik <robert.jarzmik@free.fr>
+ *
+ * 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/videodev2.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/log2.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+
+#include <media/v4l2-common.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/soc_camera.h>
+
+/*
+ * mt9m111 i2c address is 0x5d or 0x48 (depending on SAddr pin)
+ * The platform has to define i2c_board_info and call i2c_register_board_info()
+ */
+
+/* mt9m111: Sensor register addresses */
+#define MT9M111_CHIP_VERSION		0x000
+#define MT9M111_ROW_START		0x001
+#define MT9M111_COLUMN_START		0x002
+#define MT9M111_WINDOW_HEIGHT		0x003
+#define MT9M111_WINDOW_WIDTH		0x004
+#define MT9M111_HORIZONTAL_BLANKING_B	0x005
+#define MT9M111_VERTICAL_BLANKING_B	0x006
+#define MT9M111_HORIZONTAL_BLANKING_A	0x007
+#define MT9M111_VERTICAL_BLANKING_A	0x008
+#define MT9M111_SHUTTER_WIDTH		0x009
+#define MT9M111_ROW_SPEED		0x00a
+#define MT9M111_EXTRA_DELAY		0x00b
+#define MT9M111_SHUTTER_DELAY		0x00c
+#define MT9M111_RESET			0x00d
+#define MT9M111_READ_MODE_B		0x020
+#define MT9M111_READ_MODE_A		0x021
+#define MT9M111_FLASH_CONTROL		0x023
+#define MT9M111_GREEN1_GAIN		0x02b
+#define MT9M111_BLUE_GAIN		0x02c
+#define MT9M111_RED_GAIN		0x02d
+#define MT9M111_GREEN2_GAIN		0x02e
+#define MT9M111_GLOBAL_GAIN		0x02f
+#define MT9M111_CONTEXT_CONTROL		0x0c8
+#define MT9M111_PAGE_MAP		0x0f0
+#define MT9M111_BYTE_WISE_ADDR		0x0f1
+
+#define MT9M111_RESET_SYNC_CHANGES	(1 << 15)
+#define MT9M111_RESET_RESTART_BAD_FRAME	(1 << 9)
+#define MT9M111_RESET_SHOW_BAD_FRAMES	(1 << 8)
+#define MT9M111_RESET_RESET_SOC		(1 << 5)
+#define MT9M111_RESET_OUTPUT_DISABLE	(1 << 4)
+#define MT9M111_RESET_CHIP_ENABLE	(1 << 3)
+#define MT9M111_RESET_ANALOG_STANDBY	(1 << 2)
+#define MT9M111_RESET_RESTART_FRAME	(1 << 1)
+#define MT9M111_RESET_RESET_MODE	(1 << 0)
+
+#define MT9M111_RMB_MIRROR_COLS		(1 << 1)
+#define MT9M111_RMB_MIRROR_ROWS		(1 << 0)
+#define MT9M111_CTXT_CTRL_RESTART	(1 << 15)
+#define MT9M111_CTXT_CTRL_DEFECTCOR_B	(1 << 12)
+#define MT9M111_CTXT_CTRL_RESIZE_B	(1 << 10)
+#define MT9M111_CTXT_CTRL_CTRL2_B	(1 << 9)
+#define MT9M111_CTXT_CTRL_GAMMA_B	(1 << 8)
+#define MT9M111_CTXT_CTRL_XENON_EN	(1 << 7)
+#define MT9M111_CTXT_CTRL_READ_MODE_B	(1 << 3)
+#define MT9M111_CTXT_CTRL_LED_FLASH_EN	(1 << 2)
+#define MT9M111_CTXT_CTRL_VBLANK_SEL_B	(1 << 1)
+#define MT9M111_CTXT_CTRL_HBLANK_SEL_B	(1 << 0)
+/*
+ * mt9m111: Colorpipe register addresses (0x100..0x1ff)
+ */
+#define MT9M111_OPER_MODE_CTRL		0x106
+#define MT9M111_OUTPUT_FORMAT_CTRL	0x108
+#define MT9M111_REDUCER_XZOOM_B		0x1a0
+#define MT9M111_REDUCER_XSIZE_B		0x1a1
+#define MT9M111_REDUCER_YZOOM_B		0x1a3
+#define MT9M111_REDUCER_YSIZE_B		0x1a4
+#define MT9M111_REDUCER_XZOOM_A		0x1a6
+#define MT9M111_REDUCER_XSIZE_A		0x1a7
+#define MT9M111_REDUCER_YZOOM_A		0x1a9
+#define MT9M111_REDUCER_YSIZE_A		0x1aa
+
+#define MT9M111_OUTPUT_FORMAT_CTRL2_A	0x13a
+#define MT9M111_OUTPUT_FORMAT_CTRL2_B	0x19b
+
+#define MT9M111_OPMODE_AUTOEXPO_EN	(1 << 14)
+
+
+#define MT9M111_OUTFMT_PROCESSED_BAYER	(1 << 14)
+#define MT9M111_OUTFMT_BYPASS_IFP	(1 << 10)
+#define MT9M111_OUTFMT_INV_PIX_CLOCK	(1 << 9)
+#define MT9M111_OUTFMT_RGB		(1 << 8)
+#define MT9M111_OUTFMT_RGB565		(0x0 << 6)
+#define MT9M111_OUTFMT_RGB555		(0x1 << 6)
+#define MT9M111_OUTFMT_RGB444x		(0x2 << 6)
+#define MT9M111_OUTFMT_RGBx444		(0x3 << 6)
+#define MT9M111_OUTFMT_TST_RAMP_OFF	(0x0 << 4)
+#define MT9M111_OUTFMT_TST_RAMP_COL	(0x1 << 4)
+#define MT9M111_OUTFMT_TST_RAMP_ROW	(0x2 << 4)
+#define MT9M111_OUTFMT_TST_RAMP_FRAME	(0x3 << 4)
+#define MT9M111_OUTFMT_SHIFT_3_UP	(1 << 3)
+#define MT9M111_OUTFMT_AVG_CHROMA	(1 << 2)
+#define MT9M111_OUTFMT_SWAP_YCbCr_C_Y	(1 << 1)
+#define MT9M111_OUTFMT_SWAP_RGB_EVEN	(1 << 1)
+#define MT9M111_OUTFMT_SWAP_YCbCr_Cb_Cr	(1 << 0)
+/*
+ * mt9m111: Camera control register addresses (0x200..0x2ff not implemented)
+ */
+
+#define reg_read(reg) mt9m111_reg_read(icd, MT9M111_##reg)
+#define reg_write(reg, val) mt9m111_reg_write(icd, MT9M111_##reg, (val))
+#define reg_set(reg, val) mt9m111_reg_set(icd, MT9M111_##reg, (val))
+#define reg_clear(reg, val) mt9m111_reg_clear(icd, MT9M111_##reg, (val))
+
+#define MT9M111_MIN_DARK_ROWS	8
+#define MT9M111_MIN_DARK_COLS	24
+#define MT9M111_MAX_HEIGHT	1024
+#define MT9M111_MAX_WIDTH	1280
+
+#define COL_FMT(_name, _depth, _fourcc, _colorspace) \
+	{ .name = _name, .depth = _depth, .fourcc = _fourcc, \
+	.colorspace = _colorspace }
+#define RGB_FMT(_name, _depth, _fourcc) \
+	COL_FMT(_name, _depth, _fourcc, V4L2_COLORSPACE_SRGB)
+
+static const struct soc_camera_data_format mt9m111_colour_formats[] = {
+	COL_FMT("YCrYCb 8 bit", 8, V4L2_PIX_FMT_YUYV, V4L2_COLORSPACE_JPEG),
+	RGB_FMT("RGB 565", 16, V4L2_PIX_FMT_RGB565),
+	RGB_FMT("RGB 555", 16, V4L2_PIX_FMT_RGB555),
+	RGB_FMT("Bayer (sRGB) 10 bit", 10, V4L2_PIX_FMT_SBGGR16),
+	RGB_FMT("Bayer (sRGB) 8 bit", 8, V4L2_PIX_FMT_SBGGR8),
+};
+
+enum mt9m111_context {
+	HIGHPOWER = 0,
+	LOWPOWER,
+};
+
+struct mt9m111 {
+	struct i2c_client *client;
+	struct soc_camera_device icd;
+	int model;	/* V4L2_IDENT_MT9M111* codes from v4l2-chip-ident.h */
+	enum mt9m111_context context;
+	unsigned int left, top, width, height;
+	u32 pixfmt;
+	unsigned char autoexposure;
+	unsigned char datawidth;
+	unsigned int powered:1;
+	unsigned int hflip:1;
+	unsigned int vflip:1;
+	unsigned int swap_rgb_even_odd:1;
+	unsigned int swap_rgb_red_blue:1;
+	unsigned int swap_yuv_y_chromas:1;
+	unsigned int swap_yuv_cb_cr:1;
+};
+
+static int reg_page_map_set(struct i2c_client *client, const u16 reg)
+{
+	int ret;
+	u16 page;
+	static int lastpage = -1;	/* PageMap cache value */
+
+	page = (reg >> 8);
+	if (page == lastpage)
+		return 0;
+	if (page > 2)
+		return -EINVAL;
+
+	ret = i2c_smbus_write_word_data(client, MT9M111_PAGE_MAP, swab16(page));
+	if (!ret)
+		lastpage = page;
+	return ret;
+}
+
+static int mt9m111_reg_read(struct soc_camera_device *icd, const u16 reg)
+{
+	struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+	struct i2c_client *client = mt9m111->client;
+	int ret;
+
+	ret = reg_page_map_set(client, reg);
+	if (!ret)
+		ret = swab16(i2c_smbus_read_word_data(client, (reg & 0xff)));
+
+	dev_dbg(&icd->dev, "read  reg.%03x -> %04x\n", reg, ret);
+	return ret;
+}
+
+static int mt9m111_reg_write(struct soc_camera_device *icd, const u16 reg,
+			     const u16 data)
+{
+	struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+	struct i2c_client *client = mt9m111->client;
+	int ret;
+
+	ret = reg_page_map_set(client, reg);
+	if (!ret)
+		ret = i2c_smbus_write_word_data(mt9m111->client, (reg & 0xff),
+						swab16(data));
+	dev_dbg(&icd->dev, "write reg.%03x = %04x -> %d\n", reg, data, ret);
+	return ret;
+}
+
+static int mt9m111_reg_set(struct soc_camera_device *icd, const u16 reg,
+			   const u16 data)
+{
+	int ret;
+
+	ret = mt9m111_reg_read(icd, reg);
+	if (ret >= 0)
+		ret = mt9m111_reg_write(icd, reg, ret | data);
+	return ret;
+}
+
+static int mt9m111_reg_clear(struct soc_camera_device *icd, const u16 reg,
+			     const u16 data)
+{
+	int ret;
+
+	ret = mt9m111_reg_read(icd, reg);
+	return mt9m111_reg_write(icd, reg, ret & ~data);
+}
+
+static int mt9m111_set_context(struct soc_camera_device *icd,
+			       enum mt9m111_context ctxt)
+{
+	int valB = MT9M111_CTXT_CTRL_RESTART | MT9M111_CTXT_CTRL_DEFECTCOR_B
+		| MT9M111_CTXT_CTRL_RESIZE_B | MT9M111_CTXT_CTRL_CTRL2_B
+		| MT9M111_CTXT_CTRL_GAMMA_B | MT9M111_CTXT_CTRL_READ_MODE_B
+		| MT9M111_CTXT_CTRL_VBLANK_SEL_B
+		| MT9M111_CTXT_CTRL_HBLANK_SEL_B;
+	int valA = MT9M111_CTXT_CTRL_RESTART;
+
+	if (ctxt == HIGHPOWER)
+		return reg_write(CONTEXT_CONTROL, valB);
+	else
+		return reg_write(CONTEXT_CONTROL, valA);
+}
+
+static int mt9m111_setup_rect(struct soc_camera_device *icd)
+{
+	struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+	int ret, is_raw_format;
+	int width = mt9m111->width;
+	int height = mt9m111->height;
+
+	if ((mt9m111->pixfmt == V4L2_PIX_FMT_SBGGR8)
+	    || (mt9m111->pixfmt == V4L2_PIX_FMT_SBGGR16))
+		is_raw_format = 1;
+	else
+		is_raw_format = 0;
+
+	ret = reg_write(COLUMN_START, mt9m111->left);
+	if (!ret)
+		ret = reg_write(ROW_START, mt9m111->top);
+
+	if (is_raw_format) {
+		if (!ret)
+			ret = reg_write(WINDOW_WIDTH, width);
+		if (!ret)
+			ret = reg_write(WINDOW_HEIGHT, height);
+	} else {
+		if (!ret)
+			ret = reg_write(REDUCER_XZOOM_B, MT9M111_MAX_WIDTH);
+		if (!ret)
+			ret = reg_write(REDUCER_YZOOM_B, MT9M111_MAX_HEIGHT);
+		if (!ret)
+			ret = reg_write(REDUCER_XSIZE_B, width);
+		if (!ret)
+			ret = reg_write(REDUCER_YSIZE_B, height);
+		if (!ret)
+			ret = reg_write(REDUCER_XZOOM_A, MT9M111_MAX_WIDTH);
+		if (!ret)
+			ret = reg_write(REDUCER_YZOOM_A, MT9M111_MAX_HEIGHT);
+		if (!ret)
+			ret = reg_write(REDUCER_XSIZE_A, width);
+		if (!ret)
+			ret = reg_write(REDUCER_YSIZE_A, height);
+	}
+
+	return ret;
+}
+
+static int mt9m111_setup_pixfmt(struct soc_camera_device *icd, u16 outfmt)
+{
+	int ret;
+
+	ret = reg_write(OUTPUT_FORMAT_CTRL2_A, outfmt);
+	if (!ret)
+		ret = reg_write(OUTPUT_FORMAT_CTRL2_B, outfmt);
+	return ret;
+}
+
+static int mt9m111_setfmt_bayer8(struct soc_camera_device *icd)
+{
+	return mt9m111_setup_pixfmt(icd, MT9M111_OUTFMT_PROCESSED_BAYER);
+}
+
+static int mt9m111_setfmt_bayer10(struct soc_camera_device *icd)
+{
+	return mt9m111_setup_pixfmt(icd, MT9M111_OUTFMT_BYPASS_IFP);
+}
+
+static int mt9m111_setfmt_rgb565(struct soc_camera_device *icd)
+{
+	struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+	int val = 0;
+
+	if (mt9m111->swap_rgb_red_blue)
+		val |= MT9M111_OUTFMT_SWAP_YCbCr_Cb_Cr;
+	if (mt9m111->swap_rgb_even_odd)
+		val |= MT9M111_OUTFMT_SWAP_RGB_EVEN;
+	val |= MT9M111_OUTFMT_RGB | MT9M111_OUTFMT_RGB565;
+
+	return mt9m111_setup_pixfmt(icd, val);
+}
+
+static int mt9m111_setfmt_rgb555(struct soc_camera_device *icd)
+{
+	struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+	int val = 0;
+
+	if (mt9m111->swap_rgb_red_blue)
+		val |= MT9M111_OUTFMT_SWAP_YCbCr_Cb_Cr;
+	if (mt9m111->swap_rgb_even_odd)
+		val |= MT9M111_OUTFMT_SWAP_RGB_EVEN;
+	val |= MT9M111_OUTFMT_RGB | MT9M111_OUTFMT_RGB555;
+
+	return mt9m111_setup_pixfmt(icd, val);
+}
+
+static int mt9m111_setfmt_yuv(struct soc_camera_device *icd)
+{
+	struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+	int val = 0;
+
+	if (mt9m111->swap_yuv_cb_cr)
+		val |= MT9M111_OUTFMT_SWAP_YCbCr_Cb_Cr;
+	if (mt9m111->swap_yuv_y_chromas)
+		val |= MT9M111_OUTFMT_SWAP_YCbCr_C_Y;
+
+	return mt9m111_setup_pixfmt(icd, val);
+}
+
+static int mt9m111_enable(struct soc_camera_device *icd)
+{
+	struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+	struct soc_camera_link *icl = mt9m111->client->dev.platform_data;
+	int ret;
+
+	if (icl->power) {
+		ret = icl->power(&mt9m111->client->dev, 1);
+		if (ret < 0) {
+			dev_err(icd->vdev->parent,
+				"Platform failed to power-on the camera.\n");
+			return ret;
+		}
+	}
+
+	ret = reg_set(RESET, MT9M111_RESET_CHIP_ENABLE);
+	if (!ret)
+		mt9m111->powered = 1;
+	return ret;
+}
+
+static int mt9m111_disable(struct soc_camera_device *icd)
+{
+	struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+	struct soc_camera_link *icl = mt9m111->client->dev.platform_data;
+	int ret;
+
+	ret = reg_clear(RESET, MT9M111_RESET_CHIP_ENABLE);
+	if (!ret)
+		mt9m111->powered = 0;
+
+	if (icl->power)
+		icl->power(&mt9m111->client->dev, 0);
+
+	return ret;
+}
+
+static int mt9m111_reset(struct soc_camera_device *icd)
+{
+	int ret;
+
+	ret = reg_set(RESET, MT9M111_RESET_RESET_MODE);
+	if (!ret)
+		ret = reg_set(RESET, MT9M111_RESET_RESET_SOC);
+	if (!ret)
+		ret = reg_clear(RESET, MT9M111_RESET_RESET_MODE
+				| MT9M111_RESET_RESET_SOC);
+	return ret;
+}
+
+static int mt9m111_start_capture(struct soc_camera_device *icd)
+{
+	return 0;
+}
+
+static int mt9m111_stop_capture(struct soc_camera_device *icd)
+{
+	return 0;
+}
+
+static unsigned long mt9m111_query_bus_param(struct soc_camera_device *icd)
+{
+	return SOCAM_MASTER | SOCAM_PCLK_SAMPLE_RISING |
+		SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_HIGH |
+		SOCAM_DATAWIDTH_8;
+}
+
+static int mt9m111_set_bus_param(struct soc_camera_device *icd, unsigned long f)
+{
+	return 0;
+}
+
+static int mt9m111_set_pixfmt(struct soc_camera_device *icd, u32 pixfmt)
+{
+	struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+	int ret;
+
+	switch (pixfmt) {
+	case V4L2_PIX_FMT_SBGGR8:
+		ret = mt9m111_setfmt_bayer8(icd);
+		break;
+	case V4L2_PIX_FMT_SBGGR16:
+		ret = mt9m111_setfmt_bayer10(icd);
+		break;
+	case V4L2_PIX_FMT_RGB555:
+		ret = mt9m111_setfmt_rgb555(icd);
+		break;
+	case V4L2_PIX_FMT_RGB565:
+		ret = mt9m111_setfmt_rgb565(icd);
+		break;
+	case V4L2_PIX_FMT_YUYV:
+		ret = mt9m111_setfmt_yuv(icd);
+		break;
+	default:
+		dev_err(&icd->dev, "Pixel format not handled : %x\n", pixfmt);
+		ret = -EINVAL;
+	}
+
+	if (!ret)
+		mt9m111->pixfmt = pixfmt;
+
+	return ret;
+}
+
+static int mt9m111_set_fmt_cap(struct soc_camera_device *icd,
+			       __u32 pixfmt, struct v4l2_rect *rect)
+{
+	struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+	int ret;
+
+	mt9m111->left = rect->left;
+	mt9m111->top = rect->top;
+	mt9m111->width = rect->width;
+	mt9m111->height = rect->height;
+
+	dev_dbg(&icd->dev, "%s fmt=%x left=%d, top=%d, width=%d, height=%d\n",
+		__func__, pixfmt, mt9m111->left, mt9m111->top, mt9m111->width,
+		mt9m111->height);
+
+	ret = mt9m111_setup_rect(icd);
+	if (!ret)
+		ret = mt9m111_set_pixfmt(icd, pixfmt);
+	return ret;
+}
+
+static int mt9m111_try_fmt_cap(struct soc_camera_device *icd,
+			       struct v4l2_format *f)
+{
+	if (f->fmt.pix.height > MT9M111_MAX_HEIGHT)
+		f->fmt.pix.height = MT9M111_MAX_HEIGHT;
+	if (f->fmt.pix.width > MT9M111_MAX_WIDTH)
+		f->fmt.pix.width = MT9M111_MAX_WIDTH;
+
+	return 0;
+}
+
+static int mt9m111_get_chip_id(struct soc_camera_device *icd,
+			       struct v4l2_chip_ident *id)
+{
+	struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+
+	if (id->match_type != V4L2_CHIP_MATCH_I2C_ADDR)
+		return -EINVAL;
+
+	if (id->match_chip != mt9m111->client->addr)
+		return -ENODEV;
+
+	id->ident	= mt9m111->model;
+	id->revision	= 0;
+
+	return 0;
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int mt9m111_get_register(struct soc_camera_device *icd,
+				struct v4l2_register *reg)
+{
+	int val;
+
+	struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+
+	if (reg->match_type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0x2ff)
+		return -EINVAL;
+	if (reg->match_chip != mt9m111->client->addr)
+		return -ENODEV;
+
+	val = mt9m111_reg_read(icd, reg->reg);
+	reg->val = (u64)val;
+
+	if (reg->val > 0xffff)
+		return -EIO;
+
+	return 0;
+}
+
+static int mt9m111_set_register(struct soc_camera_device *icd,
+				struct v4l2_register *reg)
+{
+	struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+
+	if (reg->match_type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0x2ff)
+		return -EINVAL;
+
+	if (reg->match_chip != mt9m111->client->addr)
+		return -ENODEV;
+
+	if (mt9m111_reg_write(icd, reg->reg, reg->val) < 0)
+		return -EIO;
+
+	return 0;
+}
+#endif
+
+static const struct v4l2_queryctrl mt9m111_controls[] = {
+	{
+		.id		= V4L2_CID_VFLIP,
+		.type		= V4L2_CTRL_TYPE_BOOLEAN,
+		.name		= "Flip Verticaly",
+		.minimum	= 0,
+		.maximum	= 1,
+		.step		= 1,
+		.default_value	= 0,
+	}, {
+		.id		= V4L2_CID_HFLIP,
+		.type		= V4L2_CTRL_TYPE_BOOLEAN,
+		.name		= "Flip Horizontaly",
+		.minimum	= 0,
+		.maximum	= 1,
+		.step		= 1,
+		.default_value	= 0,
+	}, {	/* gain = 1/32*val (=>gain=1 if val==32) */
+		.id		= V4L2_CID_GAIN,
+		.type		= V4L2_CTRL_TYPE_INTEGER,
+		.name		= "Gain",
+		.minimum	= 0,
+		.maximum	= 63 * 2 * 2,
+		.step		= 1,
+		.default_value	= 32,
+		.flags		= V4L2_CTRL_FLAG_SLIDER,
+	}, {
+		.id		= V4L2_CID_EXPOSURE_AUTO,
+		.type		= V4L2_CTRL_TYPE_BOOLEAN,
+		.name		= "Auto Exposure",
+		.minimum	= 0,
+		.maximum	= 1,
+		.step		= 1,
+		.default_value	= 1,
+	}
+};
+
+static int mt9m111_video_probe(struct soc_camera_device *);
+static void mt9m111_video_remove(struct soc_camera_device *);
+static int mt9m111_get_control(struct soc_camera_device *,
+			       struct v4l2_control *);
+static int mt9m111_set_control(struct soc_camera_device *,
+			       struct v4l2_control *);
+static int mt9m111_resume(struct soc_camera_device *icd);
+static int mt9m111_init(struct soc_camera_device *icd);
+static int mt9m111_release(struct soc_camera_device *icd);
+
+static struct soc_camera_ops mt9m111_ops = {
+	.owner			= THIS_MODULE,
+	.probe			= mt9m111_video_probe,
+	.remove			= mt9m111_video_remove,
+	.init			= mt9m111_init,
+	.resume			= mt9m111_resume,
+	.release		= mt9m111_release,
+	.start_capture		= mt9m111_start_capture,
+	.stop_capture		= mt9m111_stop_capture,
+	.set_fmt_cap		= mt9m111_set_fmt_cap,
+	.try_fmt_cap		= mt9m111_try_fmt_cap,
+	.query_bus_param	= mt9m111_query_bus_param,
+	.set_bus_param		= mt9m111_set_bus_param,
+	.controls		= mt9m111_controls,
+	.num_controls		= ARRAY_SIZE(mt9m111_controls),
+	.get_control		= mt9m111_get_control,
+	.set_control		= mt9m111_set_control,
+	.get_chip_id		= mt9m111_get_chip_id,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+	.get_register		= mt9m111_get_register,
+	.set_register		= mt9m111_set_register,
+#endif
+};
+
+static int mt9m111_set_flip(struct soc_camera_device *icd, int flip, int mask)
+{
+	struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+	int ret;
+
+	if (mt9m111->context == HIGHPOWER) {
+		if (flip)
+			ret = reg_set(READ_MODE_B, mask);
+		else
+			ret = reg_clear(READ_MODE_B, mask);
+	} else {
+		if (flip)
+			ret = reg_set(READ_MODE_A, mask);
+		else
+			ret = reg_clear(READ_MODE_A, mask);
+	}
+
+	return ret;
+}
+
+static int mt9m111_get_global_gain(struct soc_camera_device *icd)
+{
+	unsigned int data, gain;
+
+	data = reg_read(GLOBAL_GAIN);
+	if (data >= 0)
+		gain = ((data & (1 << 10)) * 2)
+			| ((data & (1 << 9)) * 2)
+			| (data & 0x2f);
+	else
+		gain = data;
+
+	return gain;
+}
+static int mt9m111_set_global_gain(struct soc_camera_device *icd, int gain)
+{
+	u16 val;
+
+	if (gain > 63 * 2 * 2)
+		return -EINVAL;
+
+	icd->gain = gain;
+	if ((gain >= 64 * 2) && (gain < 63 * 2 * 2))
+		val = (1 << 10) | (1 << 9) | (gain / 4);
+	else if ((gain >= 64) && (gain < 64 * 2))
+		val = (1 << 9) | (gain / 2);
+	else
+		val = gain;
+
+	return reg_write(GLOBAL_GAIN, val);
+}
+
+static int mt9m111_set_autoexposure(struct soc_camera_device *icd, int on)
+{
+	struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+	int ret;
+
+	if (on)
+		ret = reg_set(OPER_MODE_CTRL, MT9M111_OPMODE_AUTOEXPO_EN);
+	else
+		ret = reg_clear(OPER_MODE_CTRL, MT9M111_OPMODE_AUTOEXPO_EN);
+
+	if (!ret)
+		mt9m111->autoexposure = on;
+
+	return ret;
+}
+static int mt9m111_get_control(struct soc_camera_device *icd,
+			       struct v4l2_control *ctrl)
+{
+	struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+	int data;
+
+	switch (ctrl->id) {
+	case V4L2_CID_VFLIP:
+		if (mt9m111->context == HIGHPOWER)
+			data = reg_read(READ_MODE_B);
+		else
+			data = reg_read(READ_MODE_A);
+
+		if (data < 0)
+			return -EIO;
+		ctrl->value = !!(data & MT9M111_RMB_MIRROR_ROWS);
+		break;
+	case V4L2_CID_HFLIP:
+		if (mt9m111->context == HIGHPOWER)
+			data = reg_read(READ_MODE_B);
+		else
+			data = reg_read(READ_MODE_A);
+
+		if (data < 0)
+			return -EIO;
+		ctrl->value = !!(data & MT9M111_RMB_MIRROR_COLS);
+		break;
+	case V4L2_CID_GAIN:
+		data = mt9m111_get_global_gain(icd);
+		if (data < 0)
+			return data;
+		ctrl->value = data;
+		break;
+	case V4L2_CID_EXPOSURE_AUTO:
+		ctrl->value = mt9m111->autoexposure;
+		break;
+	}
+	return 0;
+}
+
+static int mt9m111_set_control(struct soc_camera_device *icd,
+			       struct v4l2_control *ctrl)
+{
+	struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+	const struct v4l2_queryctrl *qctrl;
+	int ret;
+
+	qctrl = soc_camera_find_qctrl(&mt9m111_ops, ctrl->id);
+
+	if (!qctrl)
+		return -EINVAL;
+
+	switch (ctrl->id) {
+	case V4L2_CID_VFLIP:
+		mt9m111->vflip = ctrl->value;
+		ret = mt9m111_set_flip(icd, ctrl->value,
+					MT9M111_RMB_MIRROR_ROWS);
+		break;
+	case V4L2_CID_HFLIP:
+		mt9m111->hflip = ctrl->value;
+		ret = mt9m111_set_flip(icd, ctrl->value,
+					MT9M111_RMB_MIRROR_COLS);
+		break;
+	case V4L2_CID_GAIN:
+		ret = mt9m111_set_global_gain(icd, ctrl->value);
+		break;
+	case V4L2_CID_EXPOSURE_AUTO:
+		ret =  mt9m111_set_autoexposure(icd, ctrl->value);
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+static int mt9m111_restore_state(struct soc_camera_device *icd)
+{
+	struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+
+	mt9m111_set_context(icd, mt9m111->context);
+	mt9m111_set_pixfmt(icd, mt9m111->pixfmt);
+	mt9m111_setup_rect(icd);
+	mt9m111_set_flip(icd, mt9m111->hflip, MT9M111_RMB_MIRROR_COLS);
+	mt9m111_set_flip(icd, mt9m111->vflip, MT9M111_RMB_MIRROR_ROWS);
+	mt9m111_set_global_gain(icd, icd->gain);
+	mt9m111_set_autoexposure(icd, mt9m111->autoexposure);
+	return 0;
+}
+
+static int mt9m111_resume(struct soc_camera_device *icd)
+{
+	struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+	int ret = 0;
+
+	if (mt9m111->powered) {
+		ret = mt9m111_enable(icd);
+		if (!ret)
+			ret = mt9m111_reset(icd);
+		if (!ret)
+			ret = mt9m111_restore_state(icd);
+	}
+	return ret;
+}
+
+static int mt9m111_init(struct soc_camera_device *icd)
+{
+	struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+	int ret;
+
+	mt9m111->context = HIGHPOWER;
+	ret = mt9m111_enable(icd);
+	if (!ret)
+		ret = mt9m111_reset(icd);
+	if (!ret)
+		ret = mt9m111_set_context(icd, mt9m111->context);
+	if (!ret)
+		ret = mt9m111_set_autoexposure(icd, mt9m111->autoexposure);
+	if (ret)
+		dev_err(&icd->dev, "mt9m111 init failed: %d\n", ret);
+	return ret;
+}
+
+static int mt9m111_release(struct soc_camera_device *icd)
+{
+	int ret;
+
+	ret = mt9m111_disable(icd);
+	if (ret < 0)
+		dev_err(&icd->dev, "mt9m111 release failed: %d\n", ret);
+
+	return ret;
+}
+
+/*
+ * Interface active, can use i2c. If it fails, it can indeed mean, that
+ * this wasn't our capture interface, so, we wait for the right one
+ */
+static int mt9m111_video_probe(struct soc_camera_device *icd)
+{
+	struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+	s32 data;
+	int ret;
+
+	/*
+	 * We must have a parent by now. And it cannot be a wrong one.
+	 * So this entire test is completely redundant.
+	 */
+	if (!icd->dev.parent ||
+	    to_soc_camera_host(icd->dev.parent)->nr != icd->iface)
+		return -ENODEV;
+
+	ret = mt9m111_enable(icd);
+	if (ret)
+		goto ei2c;
+	ret = mt9m111_reset(icd);
+	if (ret)
+		goto ei2c;
+
+	data = reg_read(CHIP_VERSION);
+
+	switch (data) {
+	case 0x143a:
+		mt9m111->model = V4L2_IDENT_MT9M111;
+		icd->formats = mt9m111_colour_formats;
+		icd->num_formats = ARRAY_SIZE(mt9m111_colour_formats);
+		break;
+	default:
+		ret = -ENODEV;
+		dev_err(&icd->dev,
+			"No MT9M111 chip detected, register read %x\n", data);
+		goto ei2c;
+	}
+
+	dev_info(&icd->dev, "Detected a MT9M111 chip ID 0x143a\n");
+
+	ret = soc_camera_video_start(icd);
+	if (ret)
+		goto eisis;
+
+	mt9m111->autoexposure = 1;
+
+	mt9m111->swap_rgb_even_odd = 1;
+	mt9m111->swap_rgb_red_blue = 1;
+
+	return 0;
+eisis:
+ei2c:
+	return ret;
+}
+
+static void mt9m111_video_remove(struct soc_camera_device *icd)
+{
+	struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+
+	dev_dbg(&icd->dev, "Video %x removed: %p, %p\n", mt9m111->client->addr,
+		mt9m111->icd.dev.parent, mt9m111->icd.vdev);
+	soc_camera_video_stop(&mt9m111->icd);
+}
+
+static int mt9m111_probe(struct i2c_client *client,
+			 const struct i2c_device_id *did)
+{
+	struct mt9m111 *mt9m111;
+	struct soc_camera_device *icd;
+	struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
+	struct soc_camera_link *icl = client->dev.platform_data;
+	int ret;
+
+	if (!icl) {
+		dev_err(&client->dev, "MT9M111 driver needs platform data\n");
+		return -EINVAL;
+	}
+
+	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) {
+		dev_warn(&adapter->dev,
+			 "I2C-Adapter doesn't support I2C_FUNC_SMBUS_WORD\n");
+		return -EIO;
+	}
+
+	mt9m111 = kzalloc(sizeof(struct mt9m111), GFP_KERNEL);
+	if (!mt9m111)
+		return -ENOMEM;
+
+	mt9m111->client = client;
+	i2c_set_clientdata(client, mt9m111);
+
+	/* Second stage probe - when a capture adapter is there */
+	icd 		= &mt9m111->icd;
+	icd->ops	= &mt9m111_ops;
+	icd->control	= &client->dev;
+	icd->x_min	= MT9M111_MIN_DARK_COLS;
+	icd->y_min	= MT9M111_MIN_DARK_ROWS;
+	icd->x_current	= icd->x_min;
+	icd->y_current	= icd->y_min;
+	icd->width_min	= MT9M111_MIN_DARK_ROWS;
+	icd->width_max	= MT9M111_MAX_WIDTH;
+	icd->height_min	= MT9M111_MIN_DARK_COLS;
+	icd->height_max	= MT9M111_MAX_HEIGHT;
+	icd->y_skip_top	= 0;
+	icd->iface	= icl->bus_id;
+
+	ret = soc_camera_device_register(icd);
+	if (ret)
+		goto eisdr;
+	return 0;
+
+eisdr:
+	kfree(mt9m111);
+	return ret;
+}
+
+static int mt9m111_remove(struct i2c_client *client)
+{
+	struct mt9m111 *mt9m111 = i2c_get_clientdata(client);
+	soc_camera_device_unregister(&mt9m111->icd);
+	kfree(mt9m111);
+
+	return 0;
+}
+
+static const struct i2c_device_id mt9m111_id[] = {
+	{ "mt9m111", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, mt9m111_id);
+
+static struct i2c_driver mt9m111_i2c_driver = {
+	.driver = {
+		.name = "mt9m111",
+	},
+	.probe		= mt9m111_probe,
+	.remove		= mt9m111_remove,
+	.id_table	= mt9m111_id,
+};
+
+static int __init mt9m111_mod_init(void)
+{
+	return i2c_add_driver(&mt9m111_i2c_driver);
+}
+
+static void __exit mt9m111_mod_exit(void)
+{
+	i2c_del_driver(&mt9m111_i2c_driver);
+}
+
+module_init(mt9m111_mod_init);
+module_exit(mt9m111_mod_exit);
+
+MODULE_DESCRIPTION("Micron MT9M111 Camera driver");
+MODULE_AUTHOR("Robert Jarzmik");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/mt9v022.c b/drivers/media/video/mt9v022.c
index 56808cd..2584201 100644
--- a/drivers/media/video/mt9v022.c
+++ b/drivers/media/video/mt9v022.c
@@ -134,34 +134,56 @@
 static int mt9v022_init(struct soc_camera_device *icd)
 {
 	struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd);
+	struct soc_camera_link *icl = mt9v022->client->dev.platform_data;
 	int ret;
 
+	if (icl->power) {
+		ret = icl->power(&mt9v022->client->dev, 1);
+		if (ret < 0) {
+			dev_err(icd->vdev->parent,
+				"Platform failed to power-on the camera.\n");
+			return ret;
+		}
+	}
+
+	/*
+	 * The camera could have been already on, we hard-reset it additionally,
+	 * if available. Soft reset is done in video_probe().
+	 */
+	if (icl->reset)
+		icl->reset(&mt9v022->client->dev);
+
 	/* Almost the default mode: master, parallel, simultaneous, and an
 	 * undocumented bit 0x200, which is present in table 7, but not in 8,
 	 * plus snapshot mode to disable scan for now */
 	mt9v022->chip_control |= 0x10;
 	ret = reg_write(icd, MT9V022_CHIP_CONTROL, mt9v022->chip_control);
-	if (ret >= 0)
-		reg_write(icd, MT9V022_READ_MODE, 0x300);
+	if (!ret)
+		ret = reg_write(icd, MT9V022_READ_MODE, 0x300);
 
 	/* All defaults */
-	if (ret >= 0)
+	if (!ret)
 		/* AEC, AGC on */
 		ret = reg_set(icd, MT9V022_AEC_AGC_ENABLE, 0x3);
-	if (ret >= 0)
+	if (!ret)
 		ret = reg_write(icd, MT9V022_MAX_TOTAL_SHUTTER_WIDTH, 480);
-	if (ret >= 0)
+	if (!ret)
 		/* default - auto */
 		ret = reg_clear(icd, MT9V022_BLACK_LEVEL_CALIB_CTRL, 1);
-	if (ret >= 0)
+	if (!ret)
 		ret = reg_write(icd, MT9V022_DIGITAL_TEST_PATTERN, 0);
 
-	return ret >= 0 ? 0 : -EIO;
+	return ret;
 }
 
 static int mt9v022_release(struct soc_camera_device *icd)
 {
-	/* Nothing? */
+	struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd);
+	struct soc_camera_link *icl = mt9v022->client->dev.platform_data;
+
+	if (icl->power)
+		icl->power(&mt9v022->client->dev, 0);
+
 	return 0;
 }
 
@@ -352,21 +374,21 @@
 					rect->height + icd->y_skip_top + 43);
 	}
 	/* Setup frame format: defaults apart from width and height */
-	if (ret >= 0)
+	if (!ret)
 		ret = reg_write(icd, MT9V022_COLUMN_START, rect->left);
-	if (ret >= 0)
+	if (!ret)
 		ret = reg_write(icd, MT9V022_ROW_START, rect->top);
-	if (ret >= 0)
+	if (!ret)
 		/* Default 94, Phytec driver says:
 		 * "width + horizontal blank >= 660" */
 		ret = reg_write(icd, MT9V022_HORIZONTAL_BLANKING,
 				rect->width > 660 - 43 ? 43 :
 				660 - rect->width);
-	if (ret >= 0)
+	if (!ret)
 		ret = reg_write(icd, MT9V022_VERTICAL_BLANKING, 45);
-	if (ret >= 0)
+	if (!ret)
 		ret = reg_write(icd, MT9V022_WINDOW_WIDTH, rect->width);
-	if (ret >= 0)
+	if (!ret)
 		ret = reg_write(icd, MT9V022_WINDOW_HEIGHT,
 				rect->height + icd->y_skip_top);
 
@@ -717,7 +739,7 @@
 			icd->num_formats = 1;
 	}
 
-	if (ret >= 0)
+	if (!ret)
 		ret = soc_camera_video_start(icd);
 	if (ret < 0)
 		goto eisis;
diff --git a/drivers/media/video/mxb.c b/drivers/media/video/mxb.c
index 8ef578c..7f13028 100644
--- a/drivers/media/video/mxb.c
+++ b/drivers/media/video/mxb.c
@@ -27,6 +27,7 @@
 #include <media/tuner.h>
 #include <linux/video_decoder.h>
 #include <media/v4l2-common.h>
+#include <media/saa7115.h>
 
 #include "mxb.h"
 #include "tea6415c.h"
@@ -122,6 +123,8 @@
 	{ VIDIOC_S_FREQUENCY, 	SAA7146_EXCLUSIVE },
 	{ VIDIOC_G_AUDIO, 	SAA7146_EXCLUSIVE },
 	{ VIDIOC_S_AUDIO, 	SAA7146_EXCLUSIVE },
+	{ VIDIOC_DBG_G_REGISTER, 	SAA7146_EXCLUSIVE },
+	{ VIDIOC_DBG_S_REGISTER, 	SAA7146_EXCLUSIVE },
 	{ MXB_S_AUDIO_CD, 	SAA7146_EXCLUSIVE },	/* custom control */
 	{ MXB_S_AUDIO_LINE, 	SAA7146_EXCLUSIVE },	/* custom control */
 	{ 0,			0 }
@@ -134,12 +137,12 @@
 
 	struct i2c_adapter	i2c_adapter;
 
-	struct i2c_client*	saa7111a;
-	struct i2c_client*	tda9840;
-	struct i2c_client*	tea6415c;
-	struct i2c_client*	tuner;
-	struct i2c_client*	tea6420_1;
-	struct i2c_client*	tea6420_2;
+	struct i2c_client	*saa7111a;
+	struct i2c_client	*tda9840;
+	struct i2c_client	*tea6415c;
+	struct i2c_client	*tuner;
+	struct i2c_client	*tea6420_1;
+	struct i2c_client	*tea6420_2;
 
 	int	cur_mode;	/* current audio mode (mono, stereo, ...) */
 	int	cur_input;	/* current input */
@@ -151,23 +154,23 @@
 
 static int mxb_check_clients(struct device *dev, void *data)
 {
-	struct mxb* mxb = data;
+	struct mxb *mxb = data;
 	struct i2c_client *client = i2c_verify_client(dev);
 
-	if( !client )
+	if (!client)
 		return 0;
 
-	if( I2C_ADDR_TEA6420_1 == client->addr )
+	if (I2C_ADDR_TEA6420_1 == client->addr)
 		mxb->tea6420_1 = client;
-	if( I2C_ADDR_TEA6420_2 == client->addr )
+	if (I2C_ADDR_TEA6420_2 == client->addr)
 		mxb->tea6420_2 = client;
-	if( I2C_TEA6415C_2 == client->addr )
+	if (I2C_TEA6415C_2 == client->addr)
 		mxb->tea6415c = client;
-	if( I2C_ADDR_TDA9840 == client->addr )
+	if (I2C_ADDR_TDA9840 == client->addr)
 		mxb->tda9840 = client;
-	if( I2C_SAA7111 == client->addr )
+	if (I2C_SAA7111 == client->addr)
 		mxb->saa7111a = client;
-	if( 0x60 == client->addr )
+	if (0x60 == client->addr)
 		mxb->tuner = client;
 
 	return 0;
@@ -178,23 +181,28 @@
 	struct mxb* mxb = NULL;
 	int result;
 
-	if ((result = request_module("saa7111")) < 0) {
+	result = request_module("saa7115");
+	if (result < 0) {
 		printk("mxb: saa7111 i2c module not available.\n");
 		return -ENODEV;
 	}
-	if ((result = request_module("tea6420")) < 0) {
+	result = request_module("tea6420");
+	if (result < 0) {
 		printk("mxb: tea6420 i2c module not available.\n");
 		return -ENODEV;
 	}
-	if ((result = request_module("tea6415c")) < 0) {
+	result = request_module("tea6415c");
+	if (result < 0) {
 		printk("mxb: tea6415c i2c module not available.\n");
 		return -ENODEV;
 	}
-	if ((result = request_module("tda9840")) < 0) {
+	result = request_module("tda9840");
+	if (result < 0) {
 		printk("mxb: tda9840 i2c module not available.\n");
 		return -ENODEV;
 	}
-	if ((result = request_module("tuner")) < 0) {
+	result = request_module("tuner");
+	if (result < 0) {
 		printk("mxb: tuner i2c module not available.\n");
 		return -ENODEV;
 	}
@@ -207,9 +215,10 @@
 
 	mxb->i2c_adapter = (struct i2c_adapter) {
 		.class = I2C_CLASS_TV_ANALOG,
-		.name = "mxb",
 	};
 
+	snprintf(mxb->i2c_adapter.name, sizeof(mxb->i2c_adapter.name), "mxb%d", mxb_num);
+
 	saa7146_i2c_adapter_prepare(dev, &mxb->i2c_adapter, SAA7146_I2C_BUS_BIT_RATE_480);
 	if(i2c_add_adapter(&mxb->i2c_adapter) < 0) {
 		DEB_S(("cannot register i2c-device. skipping.\n"));
@@ -290,38 +299,7 @@
 	{ 9, { 0x1d, 0xed, 0xd0, 0x68, 0x29, 0xb4, 0xe1, 0x00, 0xb8 } },
 	{ 9, { 0x3d, 0xed, 0xd0, 0x68, 0x29, 0xb4, 0xe1, 0x00, 0xb8 } },
 	{ 3, { 0x80, 0xb3, 0x0a } },
-	{-1, { 0} }
-};
-
-static const unsigned char mxb_saa7111_init[] = {
-	0x00, 0x00,	  /* 00 - ID byte */
-	0x01, 0x00,	  /* 01 - reserved */
-
-	/*front end */
-	0x02, 0xd8,	  /* 02 - FUSE=x, GUDL=x, MODE=x */
-	0x03, 0x23,	  /* 03 - HLNRS=0, VBSL=1, WPOFF=0, HOLDG=0, GAFIX=0, GAI1=256, GAI2=256 */
-	0x04, 0x00,	  /* 04 - GAI1=256 */
-	0x05, 0x00,	  /* 05 - GAI2=256 */
-
-	/* decoder */
-	0x06, 0xf0,	  /* 06 - HSB at  xx(50Hz) /  xx(60Hz) pixels after end of last line */
-	0x07, 0x30,	  /* 07 - HSS at  xx(50Hz) /  xx(60Hz) pixels after end of last line */
-	0x08, 0xa8,	  /* 08 - AUFD=x, FSEL=x, EXFIL=x, VTRC=x, HPLL=x, VNOI=x */
-	0x09, 0x02,	  /* 09 - BYPS=x, PREF=x, BPSS=x, VBLB=x, UPTCV=x, APER=x */
-	0x0a, 0x80,	  /* 0a - BRIG=128 */
-	0x0b, 0x47,	  /* 0b - CONT=1.109 */
-	0x0c, 0x40,	  /* 0c - SATN=1.0 */
-	0x0d, 0x00,	  /* 0d - HUE=0 */
-	0x0e, 0x01,	  /* 0e - CDTO=0, CSTD=0, DCCF=0, FCTC=0, CHBW=1 */
-	0x0f, 0x00,	  /* 0f - reserved */
-	0x10, 0xd0,	  /* 10 - OFTS=x, HDEL=x, VRLN=x, YDEL=x */
-	0x11, 0x8c,	  /* 11 - GPSW=x, CM99=x, FECO=x, COMPO=x, OEYC=1, OEHV=1, VIPB=0, COLO=0 */
-	0x12, 0x80,	  /* 12 - xx output control 2 */
-	0x13, 0x30,	  /* 13 - xx output control 3 */
-	0x14, 0x00,	  /* 14 - reserved */
-	0x15, 0x15,	  /* 15 - VBI */
-	0x16, 0x04,	  /* 16 - VBI */
-	0x17, 0x00,	  /* 17 - VBI */
+	{-1, { 0 } }
 };
 
 /* bring hardware to a sane state. this has to be done, just in case someone
@@ -331,37 +309,28 @@
 static int mxb_init_done(struct saa7146_dev* dev)
 {
 	struct mxb* mxb = (struct mxb*)dev->ext_priv;
-	struct video_decoder_init init;
 	struct i2c_msg msg;
 	struct tuner_setup tun_setup;
 	v4l2_std_id std = V4L2_STD_PAL_BG;
+	struct v4l2_routing route;
 
 	int i = 0, err = 0;
-	struct	tea6415c_multiplex vm;
+	struct tea6415c_multiplex vm;
 
 	/* select video mode in saa7111a */
-	i = VIDEO_MODE_PAL;
-	/* fixme: currently pointless: gets overwritten by configuration below */
-	mxb->saa7111a->driver->command(mxb->saa7111a,DECODER_SET_NORM, &i);
-
-	/* write configuration to saa7111a */
-	init.data = mxb_saa7111_init;
-	init.len = sizeof(mxb_saa7111_init);
-	mxb->saa7111a->driver->command(mxb->saa7111a,DECODER_INIT, &init);
+	mxb->saa7111a->driver->command(mxb->saa7111a, VIDIOC_S_STD, &std);
 
 	/* select tuner-output on saa7111a */
 	i = 0;
-	mxb->saa7111a->driver->command(mxb->saa7111a,DECODER_SET_INPUT, &i);
-
-	/* enable vbi bypass */
-	i = 1;
-	mxb->saa7111a->driver->command(mxb->saa7111a,DECODER_SET_VBI_BYPASS, &i);
+	route.input = SAA7115_COMPOSITE0;
+	route.output = SAA7111_FMT_CCIR | SAA7111_VBI_BYPASS;
+	mxb->saa7111a->driver->command(mxb->saa7111a, VIDIOC_INT_S_VIDEO_ROUTING, &route);
 
 	/* select a tuner type */
 	tun_setup.mode_mask = T_ANALOG_TV;
 	tun_setup.addr = ADDR_UNSET;
 	tun_setup.type = TUNER_PHILIPS_PAL;
-	mxb->tuner->driver->command(mxb->tuner,TUNER_SET_TYPE_ADDR, &tun_setup);
+	mxb->tuner->driver->command(mxb->tuner, TUNER_SET_TYPE_ADDR, &tun_setup);
 	/* tune in some frequency on tuner */
 	mxb->cur_freq.tuner = 0;
 	mxb->cur_freq.type = V4L2_TUNER_ANALOG_TV;
@@ -373,27 +342,26 @@
 	mxb->tuner->driver->command(mxb->tuner, VIDIOC_S_STD, &std);
 
 	/* mute audio on tea6420s */
-	mxb->tea6420_1->driver->command(mxb->tea6420_1,TEA6420_SWITCH, &TEA6420_line[6][0]);
-	mxb->tea6420_2->driver->command(mxb->tea6420_2,TEA6420_SWITCH, &TEA6420_line[6][1]);
-	mxb->tea6420_1->driver->command(mxb->tea6420_1,TEA6420_SWITCH, &TEA6420_cd[6][0]);
-	mxb->tea6420_2->driver->command(mxb->tea6420_2,TEA6420_SWITCH, &TEA6420_cd[6][1]);
+	mxb->tea6420_1->driver->command(mxb->tea6420_1, TEA6420_SWITCH, &TEA6420_line[6][0]);
+	mxb->tea6420_2->driver->command(mxb->tea6420_2, TEA6420_SWITCH, &TEA6420_line[6][1]);
+	mxb->tea6420_1->driver->command(mxb->tea6420_1, TEA6420_SWITCH, &TEA6420_cd[6][0]);
+	mxb->tea6420_2->driver->command(mxb->tea6420_2, TEA6420_SWITCH, &TEA6420_cd[6][1]);
 
 	/* switch to tuner-channel on tea6415c*/
 	vm.out = 17;
 	vm.in  = 3;
-	mxb->tea6415c->driver->command(mxb->tea6415c,TEA6415C_SWITCH, &vm);
+	mxb->tea6415c->driver->command(mxb->tea6415c, TEA6415C_SWITCH, &vm);
 
 	/* select tuner-output on multicable on tea6415c*/
 	vm.in  = 3;
 	vm.out = 13;
-	mxb->tea6415c->driver->command(mxb->tea6415c,TEA6415C_SWITCH, &vm);
+	mxb->tea6415c->driver->command(mxb->tea6415c, TEA6415C_SWITCH, &vm);
 
 	/* the rest for mxb */
 	mxb->cur_input = 0;
 	mxb->cur_mute = 1;
 
 	mxb->cur_mode = V4L2_TUNER_MODE_STEREO;
-	mxb->tda9840->driver->command(mxb->tda9840, TDA9840_SWITCH, &mxb->cur_mode);
 
 	/* check if the saa7740 (aka 'sound arena module') is present
 	   on the mxb. if so, we must initialize it. due to lack of
@@ -404,21 +372,22 @@
 	msg.len = mxb_saa7740_init[0].length;
 	msg.buf = &mxb_saa7740_init[0].data[0];
 
-	if( 1 == (err = i2c_transfer(&mxb->i2c_adapter, &msg, 1))) {
+	err = i2c_transfer(&mxb->i2c_adapter, &msg, 1);
+	if (err == 1) {
 		/* the sound arena module is a pos, that's probably the reason
 		   philips refuses to hand out a datasheet for the saa7740...
 		   it seems to screw up the i2c bus, so we disable fast irq
 		   based i2c transactions here and rely on the slow and safe
 		   polling method ... */
 		extension.flags &= ~SAA7146_USE_I2C_IRQ;
-		for(i = 1;;i++) {
-			if( -1 == mxb_saa7740_init[i].length ) {
+		for (i = 1; ; i++) {
+			if (-1 == mxb_saa7740_init[i].length)
 				break;
-			}
 
 			msg.len = mxb_saa7740_init[i].length;
 			msg.buf = &mxb_saa7740_init[i].data[0];
-			if( 1 != (err = i2c_transfer(&mxb->i2c_adapter, &msg, 1))) {
+			err = i2c_transfer(&mxb->i2c_adapter, &msg, 1);
+			if (err != 1) {
 				DEB_D(("failed to initialize 'sound arena module'.\n"));
 				goto err;
 			}
@@ -432,7 +401,8 @@
 	/* ext->saa has been filled by the core driver */
 
 	/* some stuff is done via variables */
-	saa7146_set_hps_source_and_sync(dev, input_port_selection[mxb->cur_input].hps_source, input_port_selection[mxb->cur_input].hps_sync);
+	saa7146_set_hps_source_and_sync(dev, input_port_selection[mxb->cur_input].hps_source,
+			input_port_selection[mxb->cur_input].hps_sync);
 
 	/* some stuff is done via direct write to the registers */
 
@@ -457,24 +427,24 @@
 static struct saa7146_ext_vv vv_data;
 
 /* this function only gets called when the probing was successful */
-static int mxb_attach(struct saa7146_dev* dev, struct saa7146_pci_extension_data *info)
+static int mxb_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data *info)
 {
-	struct mxb* mxb = (struct mxb*)dev->ext_priv;
+	struct mxb *mxb = (struct mxb *)dev->ext_priv;
 
-	DEB_EE(("dev:%p\n",dev));
+	DEB_EE(("dev:%p\n", dev));
 
 	/* checking for i2c-devices can be omitted here, because we
 	   already did this in "mxb_vl42_probe" */
 
-	saa7146_vv_init(dev,&vv_data);
-	if( 0 != saa7146_register_device(&mxb->video_dev, dev, "mxb", VFL_TYPE_GRABBER)) {
+	saa7146_vv_init(dev, &vv_data);
+	if (saa7146_register_device(&mxb->video_dev, dev, "mxb", VFL_TYPE_GRABBER)) {
 		ERR(("cannot register capture v4l2 device. skipping.\n"));
 		return -1;
 	}
 
 	/* initialization stuff (vbi) (only for revision > 0 and for extensions which want it)*/
-	if( 0 != MXB_BOARD_CAN_DO_VBI(dev)) {
-		if( 0 != saa7146_register_device(&mxb->vbi_dev, dev, "mxb", VFL_TYPE_VBI)) {
+	if (MXB_BOARD_CAN_DO_VBI(dev)) {
+		if (saa7146_register_device(&mxb->vbi_dev, dev, "mxb", VFL_TYPE_VBI)) {
 			ERR(("cannot register vbi v4l2 device. skipping.\n"));
 		}
 	}
@@ -486,18 +456,18 @@
 	i2c_use_client(mxb->saa7111a);
 	i2c_use_client(mxb->tuner);
 
-	printk("mxb: found 'Multimedia eXtension Board'-%d.\n",mxb_num);
+	printk("mxb: found Multimedia eXtension Board #%d.\n", mxb_num);
 
 	mxb_num++;
 	mxb_init_done(dev);
 	return 0;
 }
 
-static int mxb_detach(struct saa7146_dev* dev)
+static int mxb_detach(struct saa7146_dev *dev)
 {
-	struct mxb* mxb = (struct mxb*)dev->ext_priv;
+	struct mxb *mxb = (struct mxb *)dev->ext_priv;
 
-	DEB_EE(("dev:%p\n",dev));
+	DEB_EE(("dev:%p\n", dev));
 
 	i2c_release_client(mxb->tea6420_1);
 	i2c_release_client(mxb->tea6420_2);
@@ -507,9 +477,8 @@
 	i2c_release_client(mxb->tuner);
 
 	saa7146_unregister_device(&mxb->video_dev,dev);
-	if( 0 != MXB_BOARD_CAN_DO_VBI(dev)) {
-		saa7146_unregister_device(&mxb->vbi_dev,dev);
-	}
+	if (MXB_BOARD_CAN_DO_VBI(dev))
+		saa7146_unregister_device(&mxb->vbi_dev, dev);
 	saa7146_vv_release(dev);
 
 	mxb_num--;
@@ -523,7 +492,7 @@
 static int mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
 {
 	struct saa7146_dev *dev = fh->dev;
-	struct mxb* mxb = (struct mxb*)dev->ext_priv;
+	struct mxb *mxb = (struct mxb *)dev->ext_priv;
 	struct saa7146_vv *vv = dev->vv_data;
 
 	switch(cmd) {
@@ -532,11 +501,9 @@
 		struct v4l2_input *i = arg;
 
 		DEB_EE(("VIDIOC_ENUMINPUT %d.\n",i->index));
-		if( i->index < 0 || i->index >= MXB_INPUTS) {
+		if (i->index < 0 || i->index >= MXB_INPUTS)
 			return -EINVAL;
-		}
 		memcpy(i, &mxb_inputs[i->index], sizeof(struct v4l2_input));
-
 		return 0;
 	}
 	/* the saa7146 provides some controls (brightness, contrast, saturation)
@@ -550,7 +517,7 @@
 		for (i = MAXCONTROLS - 1; i >= 0; i--) {
 			if (mxb_controls[i].id == qc->id) {
 				*qc = mxb_controls[i];
-				DEB_D(("VIDIOC_QUERYCTRL %d.\n",qc->id));
+				DEB_D(("VIDIOC_QUERYCTRL %d.\n", qc->id));
 				return 0;
 			}
 		}
@@ -562,56 +529,51 @@
 		int i;
 
 		for (i = MAXCONTROLS - 1; i >= 0; i--) {
-			if (mxb_controls[i].id == vc->id) {
+			if (mxb_controls[i].id == vc->id)
 				break;
-			}
 		}
 
-		if( i < 0 ) {
+		if (i < 0)
 			return -EAGAIN;
+
+		if (vc->id == V4L2_CID_AUDIO_MUTE) {
+			vc->value = mxb->cur_mute;
+			DEB_D(("VIDIOC_G_CTRL V4L2_CID_AUDIO_MUTE:%d.\n", vc->value));
+			return 0;
 		}
 
-		switch (vc->id ) {
-			case V4L2_CID_AUDIO_MUTE: {
-				vc->value = mxb->cur_mute;
-				DEB_D(("VIDIOC_G_CTRL V4L2_CID_AUDIO_MUTE:%d.\n",vc->value));
-				return 0;
-			}
-		}
-
-		DEB_EE(("VIDIOC_G_CTRL V4L2_CID_AUDIO_MUTE:%d.\n",vc->value));
+		DEB_EE(("VIDIOC_G_CTRL V4L2_CID_AUDIO_MUTE:%d.\n", vc->value));
 		return 0;
 	}
 
 	case VIDIOC_S_CTRL:
 	{
-		struct	v4l2_control	*vc = arg;
+		struct v4l2_control *vc = arg;
 		int i = 0;
 
 		for (i = MAXCONTROLS - 1; i >= 0; i--) {
-			if (mxb_controls[i].id == vc->id) {
+			if (mxb_controls[i].id == vc->id)
 				break;
-			}
 		}
 
-		if( i < 0 ) {
+		if (i < 0)
 			return -EAGAIN;
-		}
 
-		switch (vc->id ) {
-			case V4L2_CID_AUDIO_MUTE: {
-				mxb->cur_mute = vc->value;
-				if( 0 == vc->value ) {
-					/* switch the audio-source */
-					mxb->tea6420_1->driver->command(mxb->tea6420_1,TEA6420_SWITCH, &TEA6420_line[video_audio_connect[mxb->cur_input]][0]);
-					mxb->tea6420_2->driver->command(mxb->tea6420_2,TEA6420_SWITCH, &TEA6420_line[video_audio_connect[mxb->cur_input]][1]);
-				} else {
-					mxb->tea6420_1->driver->command(mxb->tea6420_1,TEA6420_SWITCH, &TEA6420_line[6][0]);
-					mxb->tea6420_2->driver->command(mxb->tea6420_2,TEA6420_SWITCH, &TEA6420_line[6][1]);
-				}
-				DEB_EE(("VIDIOC_S_CTRL, V4L2_CID_AUDIO_MUTE: %d.\n",vc->value));
-				break;
+		if (vc->id == V4L2_CID_AUDIO_MUTE) {
+			mxb->cur_mute = vc->value;
+			if (!vc->value) {
+				/* switch the audio-source */
+				mxb->tea6420_1->driver->command(mxb->tea6420_1, TEA6420_SWITCH,
+						&TEA6420_line[video_audio_connect[mxb->cur_input]][0]);
+				mxb->tea6420_2->driver->command(mxb->tea6420_2, TEA6420_SWITCH,
+						&TEA6420_line[video_audio_connect[mxb->cur_input]][1]);
+			} else {
+				mxb->tea6420_1->driver->command(mxb->tea6420_1, TEA6420_SWITCH,
+						&TEA6420_line[6][0]);
+				mxb->tea6420_2->driver->command(mxb->tea6420_2, TEA6420_SWITCH,
+						&TEA6420_line[6][1]);
 			}
+			DEB_EE(("VIDIOC_S_CTRL, V4L2_CID_AUDIO_MUTE: %d.\n", vc->value));
 		}
 		return 0;
 	}
@@ -620,106 +582,84 @@
 		int *input = (int *)arg;
 		*input = mxb->cur_input;
 
-		DEB_EE(("VIDIOC_G_INPUT %d.\n",*input));
+		DEB_EE(("VIDIOC_G_INPUT %d.\n", *input));
 		return 0;
 	}
 	case VIDIOC_S_INPUT:
 	{
 		int input = *(int *)arg;
-		struct	tea6415c_multiplex vm;
+		struct tea6415c_multiplex vm;
+		struct v4l2_routing route;
 		int i = 0;
 
-		DEB_EE(("VIDIOC_S_INPUT %d.\n",input));
+		DEB_EE(("VIDIOC_S_INPUT %d.\n", input));
 
-		if (input < 0 || input >= MXB_INPUTS) {
+		if (input < 0 || input >= MXB_INPUTS)
 			return -EINVAL;
-		}
-
-		/* fixme: locke das setzen des inputs mit hilfe des mutexes
-		mutex_lock(&dev->lock);
-		video_mux(dev,*i);
-		mutex_unlock(&dev->lock);
-		*/
-
-		/* fixme: check if streaming capture
-		if ( 0 != dev->streaming ) {
-			DEB_D(("VIDIOC_S_INPUT illegal while streaming.\n"));
-			return -EPERM;
-		}
-		*/
 
 		mxb->cur_input = input;
 
-		saa7146_set_hps_source_and_sync(dev, input_port_selection[input].hps_source, input_port_selection[input].hps_sync);
+		saa7146_set_hps_source_and_sync(dev, input_port_selection[input].hps_source,
+				input_port_selection[input].hps_sync);
 
 		/* prepare switching of tea6415c and saa7111a;
 		   have a look at the 'background'-file for further informations  */
-		switch( input ) {
+		switch (input) {
+		case TUNER:
+			i = SAA7115_COMPOSITE0;
+			vm.in  = 3;
+			vm.out = 17;
 
-			case TUNER:
-			{
-				i = 0;
-				vm.in  = 3;
-				vm.out = 17;
-
-			if ( 0 != mxb->tea6415c->driver->command(mxb->tea6415c,TEA6415C_SWITCH, &vm)) {
-					printk("VIDIOC_S_INPUT: could not address tea6415c #1\n");
-					return -EFAULT;
-				}
-				/* connect tuner-output always to multicable */
-				vm.in  = 3;
-				vm.out = 13;
-				break;
+			if (mxb->tea6415c->driver->command(mxb->tea6415c, TEA6415C_SWITCH, &vm)) {
+				printk(KERN_ERR "VIDIOC_S_INPUT: could not address tea6415c #1\n");
+				return -EFAULT;
 			}
-			case AUX3_YC:
-			{
-				/* nothing to be done here. aux3_yc is
-				   directly connected to the saa711a */
-				i = 5;
-				break;
-			}
-			case AUX3:
-			{
-				/* nothing to be done here. aux3 is
-				   directly connected to the saa711a */
-				i = 1;
-				break;
-			}
-			case AUX1:
-			{
-				i = 0;
-				vm.in  = 1;
-				vm.out = 17;
-				break;
-			}
+			/* connect tuner-output always to multicable */
+			vm.in  = 3;
+			vm.out = 13;
+			break;
+		case AUX3_YC:
+			/* nothing to be done here. aux3_yc is
+			   directly connected to the saa711a */
+			i = SAA7115_SVIDEO1;
+			break;
+		case AUX3:
+			/* nothing to be done here. aux3 is
+			   directly connected to the saa711a */
+			i = SAA7115_COMPOSITE1;
+			break;
+		case AUX1:
+			i = SAA7115_COMPOSITE0;
+			vm.in  = 1;
+			vm.out = 17;
+			break;
 		}
 
 		/* switch video in tea6415c only if necessary */
-		switch( input ) {
-			case TUNER:
-			case AUX1:
-			{
-				if ( 0 != mxb->tea6415c->driver->command(mxb->tea6415c,TEA6415C_SWITCH, &vm)) {
-					printk("VIDIOC_S_INPUT: could not address tea6415c #3\n");
-					return -EFAULT;
-				}
-				break;
+		switch (input) {
+		case TUNER:
+		case AUX1:
+			if (mxb->tea6415c->driver->command(mxb->tea6415c, TEA6415C_SWITCH, &vm)) {
+				printk(KERN_ERR "VIDIOC_S_INPUT: could not address tea6415c #3\n");
+				return -EFAULT;
 			}
-			default:
-			{
-				break;
-			}
+			break;
+		default:
+			break;
 		}
 
 		/* switch video in saa7111a */
-		if ( 0 != mxb->saa7111a->driver->command(mxb->saa7111a,DECODER_SET_INPUT, &i)) {
+		route.input = i;
+		route.output = 0;
+		if (mxb->saa7111a->driver->command(mxb->saa7111a, VIDIOC_INT_S_VIDEO_ROUTING, &route))
 			printk("VIDIOC_S_INPUT: could not address saa7111a #1.\n");
-		}
 
 		/* switch the audio-source only if necessary */
 		if( 0 == mxb->cur_mute ) {
-			mxb->tea6420_1->driver->command(mxb->tea6420_1,TEA6420_SWITCH, &TEA6420_line[video_audio_connect[input]][0]);
-			mxb->tea6420_2->driver->command(mxb->tea6420_2,TEA6420_SWITCH, &TEA6420_line[video_audio_connect[input]][1]);
+			mxb->tea6420_1->driver->command(mxb->tea6420_1, TEA6420_SWITCH,
+					&TEA6420_line[video_audio_connect[input]][0]);
+			mxb->tea6420_2->driver->command(mxb->tea6420_2, TEA6420_SWITCH,
+				       &TEA6420_line[video_audio_connect[input]][1]);
 		}
 
 		return 0;
@@ -727,114 +667,44 @@
 	case VIDIOC_G_TUNER:
 	{
 		struct v4l2_tuner *t = arg;
-		int byte = 0;
 
-		if( 0 != t->index ) {
+		if (t->index) {
 			DEB_D(("VIDIOC_G_TUNER: channel %d does not have a tuner attached.\n", t->index));
 			return -EINVAL;
 		}
 
 		DEB_EE(("VIDIOC_G_TUNER: %d\n", t->index));
 
-		memset(t,0,sizeof(*t));
-		strcpy(t->name, "Television");
+		memset(t, 0, sizeof(*t));
+		i2c_clients_command(&mxb->i2c_adapter, cmd, arg);
 
+		strlcpy(t->name, "TV Tuner", sizeof(t->name));
 		t->type = V4L2_TUNER_ANALOG_TV;
-		t->capability = V4L2_TUNER_CAP_NORM | V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2 | V4L2_TUNER_CAP_SAP;
-		t->rangelow = 772;	/* 48.25 MHZ / 62.5 kHz = 772, see fi1216mk2-specs, page 2 */
-		t->rangehigh = 13684;	/* 855.25 MHz / 62.5 kHz = 13684 */
-		/* FIXME: add the real signal strength here */
-		t->signal = 0xffff;
-		t->afc = 0;
-
-		mxb->tda9840->driver->command(mxb->tda9840,TDA9840_DETECT, &byte);
+		t->capability = V4L2_TUNER_CAP_NORM | V4L2_TUNER_CAP_STEREO | \
+			V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2 | V4L2_TUNER_CAP_SAP;
 		t->audmode = mxb->cur_mode;
-
-		if( byte < 0 ) {
-			t->rxsubchans  = V4L2_TUNER_SUB_MONO;
-		} else {
-			switch(byte) {
-				case TDA9840_MONO_DETECT: {
-					t->rxsubchans 	= V4L2_TUNER_SUB_MONO;
-					DEB_D(("VIDIOC_G_TUNER: V4L2_TUNER_MODE_MONO.\n"));
-					break;
-				}
-				case TDA9840_DUAL_DETECT: {
-					t->rxsubchans 	= V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
-					DEB_D(("VIDIOC_G_TUNER: V4L2_TUNER_MODE_LANG1.\n"));
-					break;
-				}
-				case TDA9840_STEREO_DETECT: {
-					t->rxsubchans 	= V4L2_TUNER_SUB_STEREO | V4L2_TUNER_SUB_MONO;
-					DEB_D(("VIDIOC_G_TUNER: V4L2_TUNER_MODE_STEREO.\n"));
-					break;
-				}
-				default: { /* TDA9840_INCORRECT_DETECT */
-					t->rxsubchans 	= V4L2_TUNER_MODE_MONO;
-					DEB_D(("VIDIOC_G_TUNER: TDA9840_INCORRECT_DETECT => V4L2_TUNER_MODE_MONO\n"));
-					break;
-				}
-			}
-		}
-
 		return 0;
 	}
 	case VIDIOC_S_TUNER:
 	{
 		struct v4l2_tuner *t = arg;
-		int result = 0;
-		int byte = 0;
 
-		if( 0 != t->index ) {
+		if (t->index) {
 			DEB_D(("VIDIOC_S_TUNER: channel %d does not have a tuner attached.\n",t->index));
 			return -EINVAL;
 		}
 
-		switch(t->audmode) {
-			case V4L2_TUNER_MODE_STEREO: {
-				mxb->cur_mode = V4L2_TUNER_MODE_STEREO;
-				byte = TDA9840_SET_STEREO;
-				DEB_D(("VIDIOC_S_TUNER: V4L2_TUNER_MODE_STEREO\n"));
-				break;
-			}
-			case V4L2_TUNER_MODE_LANG1_LANG2: {
-				mxb->cur_mode = V4L2_TUNER_MODE_LANG1_LANG2;
-				byte = TDA9840_SET_BOTH;
-				DEB_D(("VIDIOC_S_TUNER: V4L2_TUNER_MODE_LANG1_LANG2\n"));
-				break;
-			}
-			case V4L2_TUNER_MODE_LANG1: {
-				mxb->cur_mode = V4L2_TUNER_MODE_LANG1;
-				byte = TDA9840_SET_LANG1;
-				DEB_D(("VIDIOC_S_TUNER: V4L2_TUNER_MODE_LANG1\n"));
-				break;
-			}
-			case V4L2_TUNER_MODE_LANG2: {
-				mxb->cur_mode = V4L2_TUNER_MODE_LANG2;
-				byte = TDA9840_SET_LANG2;
-				DEB_D(("VIDIOC_S_TUNER: V4L2_TUNER_MODE_LANG2\n"));
-				break;
-			}
-			default: { /* case V4L2_TUNER_MODE_MONO: {*/
-				mxb->cur_mode = V4L2_TUNER_MODE_MONO;
-				byte = TDA9840_SET_MONO;
-				DEB_D(("VIDIOC_S_TUNER: TDA9840_SET_MONO\n"));
-				break;
-			}
-		}
-
-		if( 0 != (result = mxb->tda9840->driver->command(mxb->tda9840, TDA9840_SWITCH, &byte))) {
-			printk("VIDIOC_S_TUNER error. result:%d, byte:%d\n",result,byte);
-		}
-
+		mxb->cur_mode = t->audmode;
+		i2c_clients_command(&mxb->i2c_adapter, cmd, arg);
 		return 0;
 	}
 	case VIDIOC_G_FREQUENCY:
 	{
 		struct v4l2_frequency *f = arg;
 
-		if(0 != mxb->cur_input) {
-			DEB_D(("VIDIOC_G_FREQ: channel %d does not have a tuner!\n",mxb->cur_input));
+		if (mxb->cur_input) {
+			DEB_D(("VIDIOC_G_FREQ: channel %d does not have a tuner!\n",
+						mxb->cur_input));
 			return -EINVAL;
 		}
 
@@ -847,14 +717,14 @@
 	{
 		struct v4l2_frequency *f = arg;
 
-		if (0 != f->tuner)
+		if (f->tuner)
 			return -EINVAL;
 
 		if (V4L2_TUNER_ANALOG_TV != f->type)
 			return -EINVAL;
 
-		if(0 != mxb->cur_input) {
-			DEB_D(("VIDIOC_S_FREQ: channel %d does not have a tuner!\n",mxb->cur_input));
+		if (mxb->cur_input) {
+			DEB_D(("VIDIOC_S_FREQ: channel %d does not have a tuner!\n", mxb->cur_input));
 			return -EINVAL;
 		}
 
@@ -875,7 +745,7 @@
 	{
 		int i = *(int*)arg;
 
-		if( i < 0 || i >= MXB_AUDIOS ) {
+		if (i < 0 || i >= MXB_AUDIOS) {
 			DEB_D(("illegal argument to MXB_S_AUDIO_CD: i:%d.\n",i));
 			return -EINVAL;
 		}
@@ -891,7 +761,7 @@
 	{
 		int i = *(int*)arg;
 
-		if( i < 0 || i >= MXB_AUDIOS ) {
+		if (i < 0 || i >= MXB_AUDIOS) {
 			DEB_D(("illegal argument to MXB_S_AUDIO_LINE: i:%d.\n",i));
 			return -EINVAL;
 		}
@@ -906,12 +776,12 @@
 	{
 		struct v4l2_audio *a = arg;
 
-		if( a->index < 0 || a->index > MXB_INPUTS ) {
-			DEB_D(("VIDIOC_G_AUDIO %d out of range.\n",a->index));
+		if (a->index < 0 || a->index > MXB_INPUTS) {
+			DEB_D(("VIDIOC_G_AUDIO %d out of range.\n", a->index));
 			return -EINVAL;
 		}
 
-		DEB_EE(("VIDIOC_G_AUDIO %d.\n",a->index));
+		DEB_EE(("VIDIOC_G_AUDIO %d.\n", a->index));
 		memcpy(a, &mxb_audios[video_audio_connect[mxb->cur_input]], sizeof(struct v4l2_audio));
 
 		return 0;
@@ -919,9 +789,16 @@
 	case VIDIOC_S_AUDIO:
 	{
 		struct v4l2_audio *a = arg;
-		DEB_D(("VIDIOC_S_AUDIO %d.\n",a->index));
+
+		DEB_D(("VIDIOC_S_AUDIO %d.\n", a->index));
 		return 0;
 	}
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+	case VIDIOC_DBG_S_REGISTER:
+	case VIDIOC_DBG_G_REGISTER:
+		i2c_clients_command(&mxb->i2c_adapter, cmd, arg);
+		return 0;
+#endif
 	default:
 /*
 		DEB2(printk("does not handle this ioctl.\n"));
@@ -944,7 +821,7 @@
 		/* set the 7146 gpio register -- I don't know what this does exactly */
 		saa7146_write(dev, GPIO_CTRL, 0x00404050);
 		/* unset the 7111 gpio register -- I don't know what this does exactly */
-		mxb->saa7111a->driver->command(mxb->saa7111a, DECODER_SET_GPIO, &zero);
+		mxb->saa7111a->driver->command(mxb->saa7111a, VIDIOC_INT_S_GPIO, &zero);
 		mxb->tuner->driver->command(mxb->tuner, VIDIOC_S_STD, &std);
 	} else {
 		v4l2_std_id std = V4L2_STD_PAL_BG;
@@ -953,7 +830,7 @@
 		/* set the 7146 gpio register -- I don't know what this does exactly */
 		saa7146_write(dev, GPIO_CTRL, 0x00404050);
 		/* set the 7111 gpio register -- I don't know what this does exactly */
-		mxb->saa7111a->driver->command(mxb->saa7111a, DECODER_SET_GPIO, &one);
+		mxb->saa7111a->driver->command(mxb->saa7111a, VIDIOC_INT_S_GPIO, &one);
 		mxb->tuner->driver->command(mxb->tuner, VIDIOC_S_STD, &std);
 	}
 	return 0;
@@ -1029,7 +906,7 @@
 
 static int __init mxb_init_module(void)
 {
-	if( 0 != saa7146_register_extension(&extension)) {
+	if (saa7146_register_extension(&extension)) {
 		DEB_S(("failed to register extension.\n"));
 		return -ENODEV;
 	}
diff --git a/drivers/media/video/ov511.c b/drivers/media/video/ov511.c
index 3d3c48d..935d73d 100644
--- a/drivers/media/video/ov511.c
+++ b/drivers/media/video/ov511.c
@@ -974,14 +974,14 @@
 
 	for (i = reg1; i <= regn; i++) {
 		rc = i2c_r(ov, i);
-		info("Sensor[0x%02X] = 0x%02X", i, rc);
+		dev_info(&ov->dev->dev, "Sensor[0x%02X] = 0x%02X\n", i, rc);
 	}
 }
 
 static void
 dump_i2c_regs(struct usb_ov511 *ov)
 {
-	info("I2C REGS");
+	dev_info(&ov->dev->dev, "I2C REGS\n");
 	dump_i2c_range(ov, 0x00, 0x7C);
 }
 
@@ -992,28 +992,28 @@
 
 	for (i = reg1; i <= regn; i++) {
 		rc = reg_r(ov, i);
-		info("OV511[0x%02X] = 0x%02X", i, rc);
+		dev_info(&ov->dev->dev, "OV511[0x%02X] = 0x%02X\n", i, rc);
 	}
 }
 
 static void
 ov511_dump_regs(struct usb_ov511 *ov)
 {
-	info("CAMERA INTERFACE REGS");
+	dev_info(&ov->dev->dev, "CAMERA INTERFACE REGS\n");
 	dump_reg_range(ov, 0x10, 0x1f);
-	info("DRAM INTERFACE REGS");
+	dev_info(&ov->dev->dev, "DRAM INTERFACE REGS\n");
 	dump_reg_range(ov, 0x20, 0x23);
-	info("ISO FIFO REGS");
+	dev_info(&ov->dev->dev, "ISO FIFO REGS\n");
 	dump_reg_range(ov, 0x30, 0x31);
-	info("PIO REGS");
+	dev_info(&ov->dev->dev, "PIO REGS\n");
 	dump_reg_range(ov, 0x38, 0x39);
 	dump_reg_range(ov, 0x3e, 0x3e);
-	info("I2C REGS");
+	dev_info(&ov->dev->dev, "I2C REGS\n");
 	dump_reg_range(ov, 0x40, 0x49);
-	info("SYSTEM CONTROL REGS");
+	dev_info(&ov->dev->dev, "SYSTEM CONTROL REGS\n");
 	dump_reg_range(ov, 0x50, 0x55);
 	dump_reg_range(ov, 0x5e, 0x5f);
-	info("OmniCE REGS");
+	dev_info(&ov->dev->dev, "OmniCE REGS\n");
 	dump_reg_range(ov, 0x70, 0x79);
 	/* NOTE: Quantization tables are not readable. You will get the value
 	 * in reg. 0x79 for every table register */
@@ -1025,25 +1025,25 @@
 static void
 ov518_dump_regs(struct usb_ov511 *ov)
 {
-	info("VIDEO MODE REGS");
+	dev_info(&ov->dev->dev, "VIDEO MODE REGS\n");
 	dump_reg_range(ov, 0x20, 0x2f);
-	info("DATA PUMP AND SNAPSHOT REGS");
+	dev_info(&ov->dev->dev, "DATA PUMP AND SNAPSHOT REGS\n");
 	dump_reg_range(ov, 0x30, 0x3f);
-	info("I2C REGS");
+	dev_info(&ov->dev->dev, "I2C REGS\n");
 	dump_reg_range(ov, 0x40, 0x4f);
-	info("SYSTEM CONTROL AND VENDOR REGS");
+	dev_info(&ov->dev->dev, "SYSTEM CONTROL AND VENDOR REGS\n");
 	dump_reg_range(ov, 0x50, 0x5f);
-	info("60 - 6F");
+	dev_info(&ov->dev->dev, "60 - 6F\n");
 	dump_reg_range(ov, 0x60, 0x6f);
-	info("70 - 7F");
+	dev_info(&ov->dev->dev, "70 - 7F\n");
 	dump_reg_range(ov, 0x70, 0x7f);
-	info("Y QUANTIZATION TABLE");
+	dev_info(&ov->dev->dev, "Y QUANTIZATION TABLE\n");
 	dump_reg_range(ov, 0x80, 0x8f);
-	info("UV QUANTIZATION TABLE");
+	dev_info(&ov->dev->dev, "UV QUANTIZATION TABLE\n");
 	dump_reg_range(ov, 0x90, 0x9f);
-	info("A0 - BF");
+	dev_info(&ov->dev->dev, "A0 - BF\n");
 	dump_reg_range(ov, 0xa0, 0xbf);
-	info("CBR");
+	dev_info(&ov->dev->dev, "CBR\n");
 	dump_reg_range(ov, 0xc0, 0xcf);
 }
 #endif
@@ -3205,9 +3205,10 @@
 	 */
 
 	if (printph) {
-		info("ph(%3d): %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x",
-		     pnum, in[0], in[1], in[2], in[3], in[4], in[5], in[6],
-		     in[7], in[8], in[9], in[10], in[11]);
+		dev_info(&ov->dev->dev,
+			 "ph(%3d): %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x\n",
+			 pnum, in[0], in[1], in[2], in[3], in[4], in[5], in[6],
+			 in[7], in[8], in[9], in[10], in[11]);
 	}
 
 	/* Check for SOF/EOF packet */
@@ -3366,8 +3367,10 @@
 	 * the definitive SOF/EOF format */
 	if ((!(in[0] | in[1] | in[2] | in[3] | in[5])) && in[6]) {
 		if (printph) {
-			info("ph: %2x %2x %2x %2x %2x %2x %2x %2x", in[0],
-			     in[1], in[2], in[3], in[4], in[5], in[6], in[7]);
+			dev_info(&ov->dev->dev,
+				 "ph: %2x %2x %2x %2x %2x %2x %2x %2x\n",
+				 in[0], in[1], in[2], in[3], in[4], in[5],
+				 in[6], in[7]);
 		}
 
 		if (frame->scanstate == STATE_LINES) {
@@ -3591,7 +3594,7 @@
 ov51x_init_isoc(struct usb_ov511 *ov)
 {
 	struct urb *urb;
-	int fx, err, n, size;
+	int fx, err, n, i, size;
 
 	PDEBUG(3, "*** Initializing capture ***");
 
@@ -3646,14 +3649,16 @@
 		if (packetsize == -1) {
 			ov518_set_packet_size(ov, 640);
 		} else {
-			info("Forcing packet size to %d", packetsize);
+			dev_info(&ov->dev->dev, "Forcing packet size to %d\n",
+				 packetsize);
 			ov518_set_packet_size(ov, packetsize);
 		}
 	} else {
 		if (packetsize == -1) {
 			ov511_set_packet_size(ov, size);
 		} else {
-			info("Forcing packet size to %d", packetsize);
+			dev_info(&ov->dev->dev, "Forcing packet size to %d\n",
+				 packetsize);
 			ov511_set_packet_size(ov, packetsize);
 		}
 	}
@@ -3662,6 +3667,8 @@
 		urb = usb_alloc_urb(FRAMES_PER_DESC, GFP_KERNEL);
 		if (!urb) {
 			err("init isoc: usb_alloc_urb ret. NULL");
+			for (i = 0; i < n; i++)
+				usb_free_urb(ov->sbuf[i].urb);
 			return -ENOMEM;
 		}
 		ov->sbuf[n].urb = urb;
@@ -4119,7 +4126,7 @@
 			return -EIO;
 
 		if (force_palette && p->palette != force_palette) {
-			info("Palette rejected (%s)",
+			dev_info(&ov->dev->dev, "Palette rejected (%s)\n",
 			     symbolic(v4l1_plist, p->palette));
 			return -EINVAL;
 		}
@@ -4847,26 +4854,27 @@
 		err("Error detecting sensor type");
 		return -1;
 	} else if ((rc & 3) == 3) {
-		info("Sensor is an OV7610");
+		dev_info(&ov->dev->dev, "Sensor is an OV7610\n");
 		ov->sensor = SEN_OV7610;
 	} else if ((rc & 3) == 1) {
 		/* I don't know what's different about the 76BE yet. */
 		if (i2c_r(ov, 0x15) & 1)
-			info("Sensor is an OV7620AE");
+			dev_info(&ov->dev->dev, "Sensor is an OV7620AE\n");
 		else
-			info("Sensor is an OV76BE");
+			dev_info(&ov->dev->dev, "Sensor is an OV76BE\n");
 
 		/* OV511+ will return all zero isoc data unless we
 		 * configure the sensor as a 7620. Someone needs to
 		 * find the exact reg. setting that causes this. */
 		if (ov->bridge == BRG_OV511PLUS) {
-			info("Enabling 511+/7620AE workaround");
+			dev_info(&ov->dev->dev,
+				 "Enabling 511+/7620AE workaround\n");
 			ov->sensor = SEN_OV7620;
 		} else {
 			ov->sensor = SEN_OV76BE;
 		}
 	} else if ((rc & 3) == 0) {
-		info("Sensor is an OV7620");
+		dev_info(&ov->dev->dev, "Sensor is an OV7620\n");
 		ov->sensor = SEN_OV7620;
 	} else {
 		err("Unknown image sensor version: %d", rc & 3);
@@ -5022,16 +5030,16 @@
 
 	if ((rc & 3) == 0) {
 		ov->sensor = SEN_OV6630;
-		info("Sensor is an OV6630");
+		dev_info(&ov->dev->dev, "Sensor is an OV6630\n");
 	} else if ((rc & 3) == 1) {
 		ov->sensor = SEN_OV6620;
-		info("Sensor is an OV6620");
+		dev_info(&ov->dev->dev, "Sensor is an OV6620\n");
 	} else if ((rc & 3) == 2) {
 		ov->sensor = SEN_OV6630;
-		info("Sensor is an OV6630AE");
+		dev_info(&ov->dev->dev, "Sensor is an OV6630AE\n");
 	} else if ((rc & 3) == 3) {
 		ov->sensor = SEN_OV6630;
-		info("Sensor is an OV6630AF");
+		dev_info(&ov->dev->dev, "Sensor is an OV6630AF\n");
 	}
 
 	/* Set sensor-specific vars */
@@ -5086,10 +5094,10 @@
 			err("Error detecting sensor type");
 			return -1;
 		} else if ((rc & 0x0f) == 0) {
-			info("Sensor is a KS0127");
+			dev_info(&ov->dev->dev, "Sensor is a KS0127\n");
 			ov->sensor = SEN_KS0127;
 		} else if ((rc & 0x0f) == 9) {
-			info("Sensor is a KS0127B Rev. A");
+			dev_info(&ov->dev->dev, "Sensor is a KS0127B Rev. A\n");
 			ov->sensor = SEN_KS0127B;
 		}
 	} else {
@@ -5198,7 +5206,8 @@
 		err("Error detecting sensor version");
 		return -1;
 	} else {
-		info("Sensor is an SAA7111A (version 0x%x)", rc);
+		dev_info(&ov->dev->dev,
+			 "Sensor is an SAA7111A (version 0x%x)\n", rc);
 		ov->sensor = SEN_SAA7111A;
 	}
 
@@ -5260,7 +5269,7 @@
 
 	PDEBUG (1, "CustomID = %d", ov->customid);
 	ov->desc = symbolic(camlist, ov->customid);
-	info("model: %s", ov->desc);
+	dev_info(&ov->dev->dev, "model: %s\n", ov->desc);
 
 	if (0 == strcmp(ov->desc, NOT_DEFINED_STR)) {
 		err("Camera type (%d) not recognized", ov->customid);
@@ -5424,7 +5433,8 @@
 	PDEBUG(4, "");
 
 	/* First 5 bits of custom ID reg are a revision ID on OV518 */
-	info("Device revision %d", 0x1F & reg_r(ov, R511_SYS_CUST_ID));
+	dev_info(&ov->dev->dev, "Device revision %d\n",
+		 0x1F & reg_r(ov, R511_SYS_CUST_ID));
 
 	/* Give it the default description */
 	ov->desc = symbolic(camlist, 0);
@@ -5651,7 +5661,7 @@
 	if (!ov->dev)
 		return -ENODEV;
 	sensor_get_exposure(ov, &exp);
-	return sprintf(buf, "%d\n", exp >> 8);
+	return sprintf(buf, "%d\n", exp);
 }
 static DEVICE_ATTR(exposure, S_IRUGO, show_exposure, NULL);
 
@@ -5771,7 +5781,8 @@
 		goto error;
 	}
 
-	info("USB %s video device found", symbolic(brglist, ov->bridge));
+	dev_info(&intf->dev, "USB %s video device found\n",
+		 symbolic(brglist, ov->bridge));
 
 	init_waitqueue_head(&ov->wq);
 
@@ -5852,8 +5863,8 @@
 		goto error;
 	}
 
-	info("Device at %s registered to minor %d", ov->usb_path,
-	     ov->vdev->minor);
+	dev_info(&intf->dev, "Device at %s registered to minor %d\n",
+		 ov->usb_path, ov->vdev->minor);
 
 	usb_set_intfdata(intf, ov);
 	if (ov_create_sysfs(ov->vdev)) {
@@ -5956,7 +5967,8 @@
 	if (retval)
 		goto out;
 
-	info(DRIVER_VERSION " : " DRIVER_DESC);
+	printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
+	       DRIVER_DESC "\n");
 
 out:
 	return retval;
@@ -5966,8 +5978,7 @@
 usb_ov511_exit(void)
 {
 	usb_deregister(&ov511_driver);
-	info("driver deregistered");
-
+	printk(KERN_INFO KBUILD_MODNAME ": driver deregistered\n");
 }
 
 module_init(usb_ov511_init);
diff --git a/drivers/media/video/ov511.h b/drivers/media/video/ov511.h
index baded12..70d99e5 100644
--- a/drivers/media/video/ov511.h
+++ b/drivers/media/video/ov511.h
@@ -12,7 +12,8 @@
 
 #ifdef OV511_DEBUG
 	#define PDEBUG(level, fmt, args...) \
-		if (debug >= (level)) info("[%s:%d] " fmt, \
+		if (debug >= (level))	\
+			printk(KERN_INFO KBUILD_MODNAME "[%s:%d] \n" fmt, \
 		__func__, __LINE__ , ## args)
 #else
 	#define PDEBUG(level, fmt, args...) do {} while(0)
diff --git a/drivers/media/video/ovcamchip/ovcamchip_core.c b/drivers/media/video/ovcamchip/ovcamchip_core.c
index 065c245..2c4acbf 100644
--- a/drivers/media/video/ovcamchip/ovcamchip_core.c
+++ b/drivers/media/video/ovcamchip/ovcamchip_core.c
@@ -49,12 +49,6 @@
 #define GENERIC_REG_ID_LOW        0x1D	/* manufacturer ID LSB */
 #define GENERIC_REG_COM_I         0x29	/* misc ID bits */
 
-extern struct ovcamchip_ops ov6x20_ops;
-extern struct ovcamchip_ops ov6x30_ops;
-extern struct ovcamchip_ops ov7x10_ops;
-extern struct ovcamchip_ops ov7x20_ops;
-extern struct ovcamchip_ops ov76be_ops;
-
 static char *chip_names[NUM_CC_TYPES] = {
 	[CC_UNKNOWN]	= "Unknown chip",
 	[CC_OV76BE]	= "OV76BE",
diff --git a/drivers/media/video/ovcamchip/ovcamchip_priv.h b/drivers/media/video/ovcamchip/ovcamchip_priv.h
index 9afa4fe..a05650f 100644
--- a/drivers/media/video/ovcamchip/ovcamchip_priv.h
+++ b/drivers/media/video/ovcamchip/ovcamchip_priv.h
@@ -53,6 +53,12 @@
 	int initialized;           /* OVCAMCHIP_CMD_INITIALIZE was successful */
 };
 
+extern struct ovcamchip_ops ov6x20_ops;
+extern struct ovcamchip_ops ov6x30_ops;
+extern struct ovcamchip_ops ov7x10_ops;
+extern struct ovcamchip_ops ov7x20_ops;
+extern struct ovcamchip_ops ov76be_ops;
+
 /* --------------------------------- */
 /*              I2C I/O              */
 /* --------------------------------- */
diff --git a/drivers/media/video/pms.c b/drivers/media/video/pms.c
index 7c84f79..9948078 100644
--- a/drivers/media/video/pms.c
+++ b/drivers/media/video/pms.c
@@ -47,6 +47,7 @@
 	struct video_picture picture;
 	int height;
 	int width;
+	unsigned long in_use;
 	struct mutex lock;
 };
 
@@ -881,10 +882,27 @@
 	return len;
 }
 
+static int pms_exclusive_open(struct inode *inode, struct file *file)
+{
+	struct video_device *v = video_devdata(file);
+	struct pms_device *pd = (struct pms_device *)v;
+
+	return test_and_set_bit(0, &pd->in_use) ? -EBUSY : 0;
+}
+
+static int pms_exclusive_release(struct inode *inode, struct file *file)
+{
+	struct video_device *v = video_devdata(file);
+	struct pms_device *pd = (struct pms_device *)v;
+
+	clear_bit(0, &pd->in_use);
+	return 0;
+}
+
 static const struct file_operations pms_fops = {
 	.owner		= THIS_MODULE,
-	.open           = video_exclusive_open,
-	.release        = video_exclusive_release,
+	.open           = pms_exclusive_open,
+	.release        = pms_exclusive_release,
 	.ioctl          = pms_ioctl,
 #ifdef CONFIG_COMPAT
 	.compat_ioctl	= v4l_compat_ioctl32,
@@ -897,6 +915,7 @@
 {
 	.name		= "Mediavision PMS",
 	.fops           = &pms_fops,
+	.release 	= video_device_release_empty,
 };
 
 static struct pms_device pms_device;
diff --git a/drivers/media/video/pvrusb2/pvrusb2-ctrl.c b/drivers/media/video/pvrusb2/pvrusb2-ctrl.c
index 0764fbf..203f54c 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-ctrl.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-ctrl.c
@@ -134,13 +134,17 @@
 
 
 /* Retrieve control's default value (any type) */
-int pvr2_ctrl_get_def(struct pvr2_ctrl *cptr)
+int pvr2_ctrl_get_def(struct pvr2_ctrl *cptr, int *valptr)
 {
 	int ret = 0;
 	if (!cptr) return 0;
 	LOCK_TAKE(cptr->hdw->big_lock); do {
 		if (cptr->info->type == pvr2_ctl_int) {
-			ret = cptr->info->default_value;
+			if (cptr->info->get_def_value) {
+				ret = cptr->info->get_def_value(cptr, valptr);
+			} else {
+				*valptr = cptr->info->default_value;
+			}
 		}
 	} while(0); LOCK_GIVE(cptr->hdw->big_lock);
 	return ret;
diff --git a/drivers/media/video/pvrusb2/pvrusb2-ctrl.h b/drivers/media/video/pvrusb2/pvrusb2-ctrl.h
index 0371ae6..794ff90 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-ctrl.h
+++ b/drivers/media/video/pvrusb2/pvrusb2-ctrl.h
@@ -49,7 +49,7 @@
 int pvr2_ctrl_get_min(struct pvr2_ctrl *);
 
 /* Retrieve control's default value (any type) */
-int pvr2_ctrl_get_def(struct pvr2_ctrl *);
+int pvr2_ctrl_get_def(struct pvr2_ctrl *, int *valptr);
 
 /* Retrieve control's enumeration count (enum only) */
 int pvr2_ctrl_get_cnt(struct pvr2_ctrl *);
diff --git a/drivers/media/video/pvrusb2/pvrusb2-devattr.c b/drivers/media/video/pvrusb2/pvrusb2-devattr.c
index 88e1751..cbe2a34 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-devattr.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-devattr.c
@@ -489,6 +489,8 @@
 struct usb_device_id pvr2_device_table[] = {
 	{ USB_DEVICE(0x2040, 0x2900),
 	  .driver_info = (kernel_ulong_t)&pvr2_device_29xxx},
+	{ USB_DEVICE(0x2040, 0x2950), /* Logically identical to 2900 */
+	  .driver_info = (kernel_ulong_t)&pvr2_device_29xxx},
 	{ USB_DEVICE(0x2040, 0x2400),
 	  .driver_info = (kernel_ulong_t)&pvr2_device_24xxx},
 	{ USB_DEVICE(0x1164, 0x0622),
diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h b/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h
index 657f861..de7ee72 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h
+++ b/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h
@@ -82,6 +82,7 @@
 
 	/* Control's implementation */
 	pvr2_ctlf_get_value get_value;      /* Get its value */
+	pvr2_ctlf_get_value get_def_value;  /* Get its default value */
 	pvr2_ctlf_get_value get_min_value;  /* Get minimum allowed value */
 	pvr2_ctlf_get_value get_max_value;  /* Get maximum allowed value */
 	pvr2_ctlf_set_value set_value;      /* Set its value */
@@ -307,6 +308,10 @@
 	struct v4l2_tuner tuner_signal_info;
 	int tuner_signal_stale;
 
+	/* Cropping capability info */
+	struct v4l2_cropcap cropcap_info;
+	int cropcap_stale;
+
 	/* Video standard handling */
 	v4l2_std_id std_mask_eeprom; // Hardware supported selections
 	v4l2_std_id std_mask_avail;  // Which standards we may select from
@@ -367,6 +372,10 @@
 	VCREATE_DATA(bass);
 	VCREATE_DATA(treble);
 	VCREATE_DATA(mute);
+	VCREATE_DATA(cropl);
+	VCREATE_DATA(cropt);
+	VCREATE_DATA(cropw);
+	VCREATE_DATA(croph);
 	VCREATE_DATA(input);
 	VCREATE_DATA(audiomode);
 	VCREATE_DATA(res_hor);
diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/drivers/media/video/pvrusb2/pvrusb2-hdw.c
index f051c6a..94265bd 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-hdw.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.c
@@ -298,6 +298,7 @@
 				unsigned int timeout,int probe_fl,
 				void *write_data,unsigned int write_len,
 				void *read_data,unsigned int read_len);
+static int pvr2_hdw_check_cropcap(struct pvr2_hdw *hdw);
 
 
 static void trace_stbit(const char *name,int val)
@@ -402,6 +403,194 @@
 	return 0;
 }
 
+static int ctrl_cropl_min_get(struct pvr2_ctrl *cptr, int *left)
+{
+	struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info;
+	int stat = pvr2_hdw_check_cropcap(cptr->hdw);
+	if (stat != 0) {
+		return stat;
+	}
+	*left = cap->bounds.left;
+	return 0;
+}
+
+static int ctrl_cropl_max_get(struct pvr2_ctrl *cptr, int *left)
+{
+	struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info;
+	int stat = pvr2_hdw_check_cropcap(cptr->hdw);
+	if (stat != 0) {
+		return stat;
+	}
+	*left = cap->bounds.left;
+	if (cap->bounds.width > cptr->hdw->cropw_val) {
+		*left += cap->bounds.width - cptr->hdw->cropw_val;
+	}
+	return 0;
+}
+
+static int ctrl_cropt_min_get(struct pvr2_ctrl *cptr, int *top)
+{
+	struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info;
+	int stat = pvr2_hdw_check_cropcap(cptr->hdw);
+	if (stat != 0) {
+		return stat;
+	}
+	*top = cap->bounds.top;
+	return 0;
+}
+
+static int ctrl_cropt_max_get(struct pvr2_ctrl *cptr, int *top)
+{
+	struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info;
+	int stat = pvr2_hdw_check_cropcap(cptr->hdw);
+	if (stat != 0) {
+		return stat;
+	}
+	*top = cap->bounds.top;
+	if (cap->bounds.height > cptr->hdw->croph_val) {
+		*top += cap->bounds.height - cptr->hdw->croph_val;
+	}
+	return 0;
+}
+
+static int ctrl_cropw_max_get(struct pvr2_ctrl *cptr, int *val)
+{
+	struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info;
+	int stat = pvr2_hdw_check_cropcap(cptr->hdw);
+	if (stat != 0) {
+		return stat;
+	}
+	*val = 0;
+	if (cap->bounds.width > cptr->hdw->cropl_val) {
+		*val = cap->bounds.width - cptr->hdw->cropl_val;
+	}
+	return 0;
+}
+
+static int ctrl_croph_max_get(struct pvr2_ctrl *cptr, int *val)
+{
+	struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info;
+	int stat = pvr2_hdw_check_cropcap(cptr->hdw);
+	if (stat != 0) {
+		return stat;
+	}
+	*val = 0;
+	if (cap->bounds.height > cptr->hdw->cropt_val) {
+		*val = cap->bounds.height - cptr->hdw->cropt_val;
+	}
+	return 0;
+}
+
+static int ctrl_get_cropcapbl(struct pvr2_ctrl *cptr, int *val)
+{
+	struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info;
+	int stat = pvr2_hdw_check_cropcap(cptr->hdw);
+	if (stat != 0) {
+		return stat;
+	}
+	*val = cap->bounds.left;
+	return 0;
+}
+
+static int ctrl_get_cropcapbt(struct pvr2_ctrl *cptr, int *val)
+{
+	struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info;
+	int stat = pvr2_hdw_check_cropcap(cptr->hdw);
+	if (stat != 0) {
+		return stat;
+	}
+	*val = cap->bounds.top;
+	return 0;
+}
+
+static int ctrl_get_cropcapbw(struct pvr2_ctrl *cptr, int *val)
+{
+	struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info;
+	int stat = pvr2_hdw_check_cropcap(cptr->hdw);
+	if (stat != 0) {
+		return stat;
+	}
+	*val = cap->bounds.width;
+	return 0;
+}
+
+static int ctrl_get_cropcapbh(struct pvr2_ctrl *cptr, int *val)
+{
+	struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info;
+	int stat = pvr2_hdw_check_cropcap(cptr->hdw);
+	if (stat != 0) {
+		return stat;
+	}
+	*val = cap->bounds.height;
+	return 0;
+}
+
+static int ctrl_get_cropcapdl(struct pvr2_ctrl *cptr, int *val)
+{
+	struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info;
+	int stat = pvr2_hdw_check_cropcap(cptr->hdw);
+	if (stat != 0) {
+		return stat;
+	}
+	*val = cap->defrect.left;
+	return 0;
+}
+
+static int ctrl_get_cropcapdt(struct pvr2_ctrl *cptr, int *val)
+{
+	struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info;
+	int stat = pvr2_hdw_check_cropcap(cptr->hdw);
+	if (stat != 0) {
+		return stat;
+	}
+	*val = cap->defrect.top;
+	return 0;
+}
+
+static int ctrl_get_cropcapdw(struct pvr2_ctrl *cptr, int *val)
+{
+	struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info;
+	int stat = pvr2_hdw_check_cropcap(cptr->hdw);
+	if (stat != 0) {
+		return stat;
+	}
+	*val = cap->defrect.width;
+	return 0;
+}
+
+static int ctrl_get_cropcapdh(struct pvr2_ctrl *cptr, int *val)
+{
+	struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info;
+	int stat = pvr2_hdw_check_cropcap(cptr->hdw);
+	if (stat != 0) {
+		return stat;
+	}
+	*val = cap->defrect.height;
+	return 0;
+}
+
+static int ctrl_get_cropcappan(struct pvr2_ctrl *cptr, int *val)
+{
+	struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info;
+	int stat = pvr2_hdw_check_cropcap(cptr->hdw);
+	if (stat != 0) {
+		return stat;
+	}
+	*val = cap->pixelaspect.numerator;
+	return 0;
+}
+
+static int ctrl_get_cropcappad(struct pvr2_ctrl *cptr, int *val)
+{
+	struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info;
+	int stat = pvr2_hdw_check_cropcap(cptr->hdw);
+	if (stat != 0) {
+		return stat;
+	}
+	*val = cap->pixelaspect.denominator;
+	return 0;
+}
+
 static int ctrl_vres_max_get(struct pvr2_ctrl *cptr,int *vp)
 {
 	/* Actual maximum depends on the video standard in effect. */
@@ -779,6 +968,10 @@
 VCREATE_FUNCS(bass)
 VCREATE_FUNCS(treble)
 VCREATE_FUNCS(mute)
+VCREATE_FUNCS(cropl)
+VCREATE_FUNCS(cropt)
+VCREATE_FUNCS(cropw)
+VCREATE_FUNCS(croph)
 VCREATE_FUNCS(audiomode)
 VCREATE_FUNCS(res_hor)
 VCREATE_FUNCS(res_ver)
@@ -849,6 +1042,72 @@
 		.default_value = 0,
 		DEFREF(mute),
 		DEFBOOL,
+	}, {
+		.desc = "Capture crop left margin",
+		.name = "crop_left",
+		.internal_id = PVR2_CID_CROPL,
+		.default_value = 0,
+		DEFREF(cropl),
+		DEFINT(-129, 340),
+		.get_min_value = ctrl_cropl_min_get,
+		.get_max_value = ctrl_cropl_max_get,
+		.get_def_value = ctrl_get_cropcapdl,
+	}, {
+		.desc = "Capture crop top margin",
+		.name = "crop_top",
+		.internal_id = PVR2_CID_CROPT,
+		.default_value = 0,
+		DEFREF(cropt),
+		DEFINT(-35, 544),
+		.get_min_value = ctrl_cropt_min_get,
+		.get_max_value = ctrl_cropt_max_get,
+		.get_def_value = ctrl_get_cropcapdt,
+	}, {
+		.desc = "Capture crop width",
+		.name = "crop_width",
+		.internal_id = PVR2_CID_CROPW,
+		.default_value = 720,
+		DEFREF(cropw),
+		.get_max_value = ctrl_cropw_max_get,
+		.get_def_value = ctrl_get_cropcapdw,
+	}, {
+		.desc = "Capture crop height",
+		.name = "crop_height",
+		.internal_id = PVR2_CID_CROPH,
+		.default_value = 480,
+		DEFREF(croph),
+		.get_max_value = ctrl_croph_max_get,
+		.get_def_value = ctrl_get_cropcapdh,
+	}, {
+		.desc = "Capture capability pixel aspect numerator",
+		.name = "cropcap_pixel_numerator",
+		.internal_id = PVR2_CID_CROPCAPPAN,
+		.get_value = ctrl_get_cropcappan,
+	}, {
+		.desc = "Capture capability pixel aspect denominator",
+		.name = "cropcap_pixel_denominator",
+		.internal_id = PVR2_CID_CROPCAPPAD,
+		.get_value = ctrl_get_cropcappad,
+	}, {
+		.desc = "Capture capability bounds top",
+		.name = "cropcap_bounds_top",
+		.internal_id = PVR2_CID_CROPCAPBT,
+		.get_value = ctrl_get_cropcapbt,
+	}, {
+		.desc = "Capture capability bounds left",
+		.name = "cropcap_bounds_left",
+		.internal_id = PVR2_CID_CROPCAPBL,
+		.get_value = ctrl_get_cropcapbl,
+	}, {
+		.desc = "Capture capability bounds width",
+		.name = "cropcap_bounds_width",
+		.internal_id = PVR2_CID_CROPCAPBW,
+		.get_value = ctrl_get_cropcapbw,
+	}, {
+		.desc = "Capture capability bounds height",
+		.name = "cropcap_bounds_height",
+		.internal_id = PVR2_CID_CROPCAPBH,
+		.get_value = ctrl_get_cropcapbh,
 	},{
 		.desc = "Video Source",
 		.name = "input",
@@ -1313,9 +1572,19 @@
 		if (bcnt > FIRMWARE_CHUNK_SIZE) bcnt = FIRMWARE_CHUNK_SIZE;
 		memcpy(fw_ptr, fw_entry->data + fw_done, bcnt);
 		/* Usbsnoop log shows that we must swap bytes... */
+		/* Some background info: The data being swapped here is a
+		   firmware image destined for the mpeg encoder chip that
+		   lives at the other end of a USB endpoint.  The encoder
+		   chip always talks in 32 bit chunks and its storage is
+		   organized into 32 bit words.  However from the file
+		   system to the encoder chip everything is purely a byte
+		   stream.  The firmware file's contents are always 32 bit
+		   swapped from what the encoder expects.  Thus the need
+		   always exists to swap the bytes regardless of the endian
+		   type of the host processor and therefore swab32() makes
+		   the most sense. */
 		for (icnt = 0; icnt < bcnt/4 ; icnt++)
-			((u32 *)fw_ptr)[icnt] =
-				___swab32(((u32 *)fw_ptr)[icnt]);
+			((u32 *)fw_ptr)[icnt] = swab32(((u32 *)fw_ptr)[icnt]);
 
 		ret |= usb_bulk_msg(hdw->usb_dev, pipe, fw_ptr,bcnt,
 				    &actual_length, HZ);
@@ -1905,7 +2174,7 @@
 				 const struct usb_device_id *devid)
 {
 	unsigned int idx,cnt1,cnt2,m;
-	struct pvr2_hdw *hdw;
+	struct pvr2_hdw *hdw = NULL;
 	int valid_std_mask;
 	struct pvr2_ctrl *cptr;
 	const struct pvr2_device_desc *hdw_desc;
@@ -1915,6 +2184,16 @@
 
 	hdw_desc = (const struct pvr2_device_desc *)(devid->driver_info);
 
+	if (hdw_desc == NULL) {
+		pvr2_trace(PVR2_TRACE_INIT, "pvr2_hdw_create:"
+			   " No device description pointer,"
+			   " unable to continue.");
+		pvr2_trace(PVR2_TRACE_INIT, "If you have a new device type,"
+			   " please contact Mike Isely <isely@pobox.com>"
+			   " to get it included in the driver\n");
+		goto fail;
+	}
+
 	hdw = kzalloc(sizeof(*hdw),GFP_KERNEL);
 	pvr2_trace(PVR2_TRACE_INIT,"pvr2_hdw_create: hdw=%p, type \"%s\"",
 		   hdw,hdw_desc->description);
@@ -2072,6 +2351,7 @@
 			valid_std_mask;
 	}
 
+	hdw->cropcap_stale = !0;
 	hdw->eeprom_addr = -1;
 	hdw->unit_number = -1;
 	hdw->v4l_minor_number_video = -1;
@@ -2508,6 +2788,28 @@
 		/* Can't commit anything until pathway is ok. */
 		return 0;
 	}
+	/* The broadcast decoder can only scale down, so if
+	 * res_*_dirty && crop window < output format ==> enlarge crop.
+	 *
+	 * The mpeg encoder receives fields of res_hor_val dots and
+	 * res_ver_val halflines.  Limits: hor<=720, ver<=576.
+	 */
+	if (hdw->res_hor_dirty && hdw->cropw_val < hdw->res_hor_val) {
+		hdw->cropw_val = hdw->res_hor_val;
+		hdw->cropw_dirty = !0;
+	} else if (hdw->cropw_dirty) {
+		hdw->res_hor_dirty = !0;           /* must rescale */
+		hdw->res_hor_val = min(720, hdw->cropw_val);
+	}
+	if (hdw->res_ver_dirty && hdw->croph_val < hdw->res_ver_val) {
+		hdw->croph_val = hdw->res_ver_val;
+		hdw->croph_dirty = !0;
+	} else if (hdw->croph_dirty) {
+		int nvres = hdw->std_mask_cur & V4L2_STD_525_60 ? 480 : 576;
+		hdw->res_ver_dirty = !0;
+		hdw->res_ver_val = min(nvres, hdw->croph_val);
+	}
+
 	/* If any of the below has changed, then we can't do the update
 	   while the pipeline is running.  Pipeline must be paused first
 	   and decoder -> encoder connection be made quiescent before we
@@ -2518,6 +2820,8 @@
 		 hdw->srate_dirty ||
 		 hdw->res_ver_dirty ||
 		 hdw->res_hor_dirty ||
+		 hdw->cropw_dirty ||
+		 hdw->croph_dirty ||
 		 hdw->input_dirty ||
 		 (hdw->active_stream_type != hdw->desired_stream_type));
 	if (disruptive_change && !hdw->state_pipeline_idle) {
@@ -2587,6 +2891,9 @@
 	}
 
 	hdw->state_pipeline_config = !0;
+	/* Hardware state may have changed in a way to cause the cropping
+	   capabilities to have changed.  So mark it stale, which will
+	   cause a later re-fetch. */
 	trace_stbit("state_pipeline_config",hdw->state_pipeline_config);
 	return !0;
 }
@@ -2677,6 +2984,33 @@
 }
 
 
+static int pvr2_hdw_check_cropcap(struct pvr2_hdw *hdw)
+{
+	if (!hdw->cropcap_stale) {
+		return 0;
+	}
+	pvr2_i2c_core_status_poll(hdw);
+	if (hdw->cropcap_stale) {
+		return -EIO;
+	}
+	return 0;
+}
+
+
+/* Return information about cropping capabilities */
+int pvr2_hdw_get_cropcap(struct pvr2_hdw *hdw, struct v4l2_cropcap *pp)
+{
+	int stat = 0;
+	LOCK_TAKE(hdw->big_lock);
+	stat = pvr2_hdw_check_cropcap(hdw);
+	if (!stat) {
+		memcpy(pp, &hdw->cropcap_info, sizeof(hdw->cropcap_info));
+	}
+	LOCK_GIVE(hdw->big_lock);
+	return stat;
+}
+
+
 /* Return information about the tuner */
 int pvr2_hdw_get_tuner_status(struct pvr2_hdw *hdw,struct v4l2_tuner *vtp)
 {
diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.h b/drivers/media/video/pvrusb2/pvrusb2-hdw.h
index c04956d..49482d1 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-hdw.h
+++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.h
@@ -36,6 +36,16 @@
 #define PVR2_CID_FREQUENCY 6
 #define PVR2_CID_HRES 7
 #define PVR2_CID_VRES 8
+#define PVR2_CID_CROPL 9
+#define PVR2_CID_CROPT 10
+#define PVR2_CID_CROPW 11
+#define PVR2_CID_CROPH 12
+#define PVR2_CID_CROPCAPPAN 13
+#define PVR2_CID_CROPCAPPAD 14
+#define PVR2_CID_CROPCAPBL 15
+#define PVR2_CID_CROPCAPBT 16
+#define PVR2_CID_CROPCAPBW 17
+#define PVR2_CID_CROPCAPBH 18
 
 /* Legal values for the INPUT state variable */
 #define PVR2_CVAL_INPUT_TV 0
@@ -170,6 +180,9 @@
 /* Return information about the tuner */
 int pvr2_hdw_get_tuner_status(struct pvr2_hdw *,struct v4l2_tuner *);
 
+/* Return information about cropping capabilities */
+int pvr2_hdw_get_cropcap(struct pvr2_hdw *, struct v4l2_cropcap *);
+
 /* Query device and see if it thinks it is on a high-speed USB link */
 int pvr2_hdw_is_hsm(struct pvr2_hdw *);
 
diff --git a/drivers/media/video/pvrusb2/pvrusb2-i2c-chips-v4l2.c b/drivers/media/video/pvrusb2/pvrusb2-i2c-chips-v4l2.c
index ccdb429..94a4771 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-i2c-chips-v4l2.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-i2c-chips-v4l2.c
@@ -37,8 +37,9 @@
 #define OP_VOLUME 3
 #define OP_FREQ 4
 #define OP_AUDIORATE 5
-#define OP_SIZE 6
-#define OP_LOG 7
+#define OP_CROP 6
+#define OP_SIZE 7
+#define OP_LOG 8
 
 static const struct pvr2_i2c_op * const ops[] = {
 	[OP_STANDARD] = &pvr2_i2c_op_v4l2_standard,
@@ -46,6 +47,7 @@
 	[OP_BCSH] = &pvr2_i2c_op_v4l2_bcsh,
 	[OP_VOLUME] = &pvr2_i2c_op_v4l2_volume,
 	[OP_FREQ] = &pvr2_i2c_op_v4l2_frequency,
+	[OP_CROP] = &pvr2_i2c_op_v4l2_crop,
 	[OP_SIZE] = &pvr2_i2c_op_v4l2_size,
 	[OP_LOG] = &pvr2_i2c_op_v4l2_log,
 };
@@ -59,6 +61,7 @@
 			(1 << OP_BCSH) |
 			(1 << OP_VOLUME) |
 			(1 << OP_FREQ) |
+			(1 << OP_CROP) |
 			(1 << OP_SIZE) |
 			(1 << OP_LOG));
 	cp->status_poll = pvr2_v4l2_cmd_status_poll;
diff --git a/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.c b/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.c
index 55f04a0..16bb119 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.c
@@ -37,6 +37,7 @@
 		pvr2_i2c_core_cmd(hdw,VIDIOC_S_STD,&vs);
 	}
 	hdw->tuner_signal_stale = !0;
+	hdw->cropcap_stale = !0;
 }
 
 
@@ -233,6 +234,37 @@
 };
 
 
+static void set_crop(struct pvr2_hdw *hdw)
+{
+	struct v4l2_crop crop;
+
+	memset(&crop, 0, sizeof crop);
+	crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	crop.c.left = hdw->cropl_val;
+	crop.c.top = hdw->cropt_val;
+	crop.c.height = hdw->croph_val;
+	crop.c.width = hdw->cropw_val;
+
+	pvr2_trace(PVR2_TRACE_CHIPS,
+		   "i2c v4l2 set_crop crop=%d:%d:%d:%d",
+		   crop.c.width, crop.c.height, crop.c.left, crop.c.top);
+
+	pvr2_i2c_core_cmd(hdw, VIDIOC_S_CROP, &crop);
+}
+
+static int check_crop(struct pvr2_hdw *hdw)
+{
+	return (hdw->cropl_dirty || hdw->cropt_dirty ||
+		hdw->cropw_dirty || hdw->croph_dirty);
+}
+
+const struct pvr2_i2c_op pvr2_i2c_op_v4l2_crop = {
+	.check = check_crop,
+	.update = set_crop,
+	.name = "v4l2_crop",
+};
+
+
 static void do_log(struct pvr2_hdw *hdw)
 {
 	pvr2_trace(PVR2_TRACE_CHIPS,"i2c v4l2 do_log()");
@@ -263,7 +295,19 @@
 
 void pvr2_v4l2_cmd_status_poll(struct pvr2_i2c_client *cp)
 {
-	pvr2_i2c_client_cmd(cp,VIDIOC_G_TUNER,&cp->hdw->tuner_signal_info);
+	int stat;
+	struct pvr2_hdw *hdw = cp->hdw;
+	if (hdw->cropcap_stale) {
+		hdw->cropcap_info.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+		stat = pvr2_i2c_client_cmd(cp, VIDIOC_CROPCAP,
+					   &hdw->cropcap_info);
+		if (stat == 0) {
+			/* Check was successful, so the data is no
+			   longer considered stale. */
+			hdw->cropcap_stale = 0;
+		}
+	}
+	pvr2_i2c_client_cmd(cp, VIDIOC_G_TUNER, &hdw->tuner_signal_info);
 }
 
 
diff --git a/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.h b/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.h
index 7fa3868..eb744a2 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.h
+++ b/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.h
@@ -29,6 +29,7 @@
 extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_bcsh;
 extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_volume;
 extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_frequency;
+extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_crop;
 extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_size;
 extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_audiomode;
 extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_log;
diff --git a/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c b/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c
index e600576..d6a3540 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c
@@ -827,7 +827,7 @@
 	if ((detail & PVR2_I2C_DETAIL_CTLMASK) && cp->ctl_mask) {
 		unsigned int idx;
 		unsigned long msk,sm;
-		int spcfl;
+
 		bcnt = scnprintf(buf,maxlen," [");
 		ccnt += bcnt; buf += bcnt; maxlen -= bcnt;
 		sm = 0;
@@ -891,6 +891,7 @@
 	INIT_LIST_HEAD(&cp->list);
 	cp->client = client;
 	mutex_lock(&hdw->i2c_list_lock); do {
+		hdw->cropcap_stale = !0;
 		list_add_tail(&cp->list,&hdw->i2c_clients);
 		hdw->i2c_pend_types |= PVR2_I2C_PEND_DETECT;
 	} while (0); mutex_unlock(&hdw->i2c_list_lock);
@@ -905,6 +906,7 @@
 	unsigned long amask = 0;
 	int foundfl = 0;
 	mutex_lock(&hdw->i2c_list_lock); do {
+		hdw->cropcap_stale = !0;
 		list_for_each_entry_safe(cp, ncp, &hdw->i2c_clients, list) {
 			if (cp->client == client) {
 				trace_i2c("pvr2_i2c_detach"
@@ -946,22 +948,32 @@
 	.client_unregister = pvr2_i2c_detach_inform,
 };
 
-static void do_i2c_scan(struct pvr2_hdw *hdw)
+
+/* Return true if device exists at given address */
+static int do_i2c_probe(struct pvr2_hdw *hdw, int addr)
 {
 	struct i2c_msg msg[1];
-	int i,rc;
+	int rc;
 	msg[0].addr = 0;
 	msg[0].flags = I2C_M_RD;
 	msg[0].len = 0;
 	msg[0].buf = NULL;
-	printk("%s: i2c scan beginning\n",hdw->name);
+	msg[0].addr = addr;
+	rc = i2c_transfer(&hdw->i2c_adap, msg, ARRAY_SIZE(msg));
+	return rc == 1;
+}
+
+static void do_i2c_scan(struct pvr2_hdw *hdw)
+{
+	int i;
+	printk(KERN_INFO "%s: i2c scan beginning\n", hdw->name);
 	for (i = 0; i < 128; i++) {
-		msg[0].addr = i;
-		rc = i2c_transfer(&hdw->i2c_adap,msg, ARRAY_SIZE(msg));
-		if (rc != 1) continue;
-		printk("%s: i2c scan: found device @ 0x%x\n",hdw->name,i);
+		if (do_i2c_probe(hdw, i)) {
+			printk(KERN_INFO "%s: i2c scan: found device @ 0x%x\n",
+			       hdw->name, i);
+		}
 	}
-	printk("%s: i2c scan done.\n",hdw->name);
+	printk(KERN_INFO "%s: i2c scan done.\n", hdw->name);
 }
 
 void pvr2_i2c_core_init(struct pvr2_hdw *hdw)
@@ -980,8 +992,6 @@
 		hdw->i2c_func[0x18] = i2c_black_hole;
 	} else if (ir_mode[hdw->unit_number] == 1) {
 		if (hdw->hdw_desc->ir_scheme == PVR2_IR_SCHEME_24XXX) {
-			/* This comment is present PURELY to get
-			   checkpatch.pl to STFU.  Lovely, eh? */
 			hdw->i2c_func[0x18] = i2c_24xxx_ir;
 		}
 	}
@@ -1006,6 +1016,16 @@
 	mutex_init(&hdw->i2c_list_lock);
 	hdw->i2c_linked = !0;
 	i2c_add_adapter(&hdw->i2c_adap);
+	if (hdw->i2c_func[0x18] == i2c_24xxx_ir) {
+		/* Probe for a different type of IR receiver on this
+		   device.  If present, disable the emulated IR receiver. */
+		if (do_i2c_probe(hdw, 0x71)) {
+			pvr2_trace(PVR2_TRACE_INFO,
+				   "Device has newer IR hardware;"
+				   " disabling unneeded virtual IR device");
+			hdw->i2c_func[0x18] = NULL;
+		}
+	}
 	if (i2c_scan) do_i2c_scan(hdw);
 }
 
diff --git a/drivers/media/video/pvrusb2/pvrusb2-main.c b/drivers/media/video/pvrusb2/pvrusb2-main.c
index ad0d98c..9b3c874 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-main.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-main.c
@@ -137,9 +137,11 @@
 	ret = usb_register(&pvr_driver);
 
 	if (ret == 0)
-		info(DRIVER_DESC " : " DRIVER_VERSION);
-	if (pvrusb2_debug) info("Debug mask is %d (0x%x)",
-				pvrusb2_debug,pvrusb2_debug);
+		printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
+		       DRIVER_DESC "\n");
+	if (pvrusb2_debug)
+		printk(KERN_INFO KBUILD_MODNAME ": Debug mask is %d (0x%x)\n",
+		       pvrusb2_debug,pvrusb2_debug);
 
 	pvr2_trace(PVR2_TRACE_INIT,"pvr_init complete");
 
diff --git a/drivers/media/video/pvrusb2/pvrusb2-sysfs.c b/drivers/media/video/pvrusb2/pvrusb2-sysfs.c
index 46a8c39b..733680f 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-sysfs.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-sysfs.c
@@ -65,6 +65,7 @@
 	struct device_attribute attr_type;
 	struct device_attribute attr_min;
 	struct device_attribute attr_max;
+	struct device_attribute attr_def;
 	struct device_attribute attr_enum;
 	struct device_attribute attr_bits;
 	struct device_attribute attr_val;
@@ -145,6 +146,23 @@
 	return scnprintf(buf, PAGE_SIZE, "%ld\n", val);
 }
 
+static ssize_t show_def(struct device *class_dev,
+			struct device_attribute *attr,
+			char *buf)
+{
+	struct pvr2_sysfs_ctl_item *cip;
+	int val;
+	int ret;
+	cip = container_of(attr, struct pvr2_sysfs_ctl_item, attr_def);
+	ret = pvr2_ctrl_get_def(cip->cptr, &val);
+	pvr2_sysfs_trace("pvr2_sysfs(%p) show_def(cid=%d) is %d, stat=%d",
+			 cip->chptr, cip->ctl_id, val, ret);
+	if (ret < 0) {
+		return ret;
+	}
+	return scnprintf(buf, PAGE_SIZE, "%d\n", val);
+}
+
 static ssize_t show_val_norm(struct device *class_dev,
 			     struct device_attribute *attr,
 			     char *buf)
@@ -320,6 +338,10 @@
 	cip->attr_max.attr.mode = S_IRUGO;
 	cip->attr_max.show = show_max;
 
+	cip->attr_def.attr.name = "def_val";
+	cip->attr_def.attr.mode = S_IRUGO;
+	cip->attr_def.show = show_def;
+
 	cip->attr_val.attr.name = "cur_val";
 	cip->attr_val.attr.mode = S_IRUGO;
 
@@ -343,6 +365,7 @@
 	cip->attr_gen[acnt++] = &cip->attr_name.attr;
 	cip->attr_gen[acnt++] = &cip->attr_type.attr;
 	cip->attr_gen[acnt++] = &cip->attr_val.attr;
+	cip->attr_gen[acnt++] = &cip->attr_def.attr;
 	cip->attr_val.show = show_val_norm;
 	cip->attr_val.store = store_val_norm;
 	if (pvr2_ctrl_has_custom_symbols(cptr)) {
diff --git a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
index 00306fa..f048d80 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
@@ -533,7 +533,7 @@
 
 			lmin = pvr2_ctrl_get_min(hcp);
 			lmax = pvr2_ctrl_get_max(hcp);
-			ldef = pvr2_ctrl_get_def(hcp);
+			pvr2_ctrl_get_def(hcp, &ldef);
 			if (w == -1) {
 				w = ldef;
 			} else if (w < lmin) {
@@ -543,7 +543,7 @@
 			}
 			lmin = pvr2_ctrl_get_min(vcp);
 			lmax = pvr2_ctrl_get_max(vcp);
-			ldef = pvr2_ctrl_get_def(vcp);
+			pvr2_ctrl_get_def(vcp, &ldef);
 			if (h == -1) {
 				h = ldef;
 			} else if (h < lmin) {
@@ -604,6 +604,7 @@
 	case VIDIOC_QUERYCTRL:
 	{
 		struct pvr2_ctrl *cptr;
+		int val;
 		struct v4l2_queryctrl *vc = (struct v4l2_queryctrl *)arg;
 		ret = 0;
 		if (vc->id & V4L2_CTRL_FLAG_NEXT_CTRL) {
@@ -627,7 +628,8 @@
 			   pvr2_ctrl_get_desc(cptr));
 		strlcpy(vc->name,pvr2_ctrl_get_desc(cptr),sizeof(vc->name));
 		vc->flags = pvr2_ctrl_get_v4lflags(cptr);
-		vc->default_value = pvr2_ctrl_get_def(cptr);
+		pvr2_ctrl_get_def(cptr, &val);
+		vc->default_value = val;
 		switch (pvr2_ctrl_get_type(cptr)) {
 		case pvr2_ctl_enum:
 			vc->type = V4L2_CTRL_TYPE_MENU;
@@ -753,6 +755,92 @@
 		break;
 	}
 
+	case VIDIOC_CROPCAP:
+	{
+		struct v4l2_cropcap *cap = (struct v4l2_cropcap *)arg;
+		if (cap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+			ret = -EINVAL;
+			break;
+		}
+		ret = pvr2_hdw_get_cropcap(hdw, cap);
+		cap->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; /* paranoia */
+		break;
+	}
+	case VIDIOC_G_CROP:
+	{
+		struct v4l2_crop *crop = (struct v4l2_crop *)arg;
+		int val = 0;
+		if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+			ret = -EINVAL;
+			break;
+		}
+		ret = pvr2_ctrl_get_value(
+			pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPL), &val);
+		if (ret != 0) {
+			ret = -EINVAL;
+			break;
+		}
+		crop->c.left = val;
+		ret = pvr2_ctrl_get_value(
+			pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPT), &val);
+		if (ret != 0) {
+			ret = -EINVAL;
+			break;
+		}
+		crop->c.top = val;
+		ret = pvr2_ctrl_get_value(
+			pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPW), &val);
+		if (ret != 0) {
+			ret = -EINVAL;
+			break;
+		}
+		crop->c.width = val;
+		ret = pvr2_ctrl_get_value(
+			pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPH), &val);
+		if (ret != 0) {
+			ret = -EINVAL;
+			break;
+		}
+		crop->c.height = val;
+	}
+	case VIDIOC_S_CROP:
+	{
+		struct v4l2_crop *crop = (struct v4l2_crop *)arg;
+		struct v4l2_cropcap cap;
+		if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+			ret = -EINVAL;
+			break;
+		}
+		cap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+		ret = pvr2_ctrl_set_value(
+			pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPL),
+			crop->c.left);
+		if (ret != 0) {
+			ret = -EINVAL;
+			break;
+		}
+		ret = pvr2_ctrl_set_value(
+			pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPT),
+			crop->c.top);
+		if (ret != 0) {
+			ret = -EINVAL;
+			break;
+		}
+		ret = pvr2_ctrl_set_value(
+			pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPW),
+			crop->c.width);
+		if (ret != 0) {
+			ret = -EINVAL;
+			break;
+		}
+		ret = pvr2_ctrl_set_value(
+			pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPH),
+			crop->c.height);
+		if (ret != 0) {
+			ret = -EINVAL;
+			break;
+		}
+	}
 	case VIDIOC_LOG_STATUS:
 	{
 		pvr2_hdw_trigger_module_log(hdw);
diff --git a/drivers/media/video/pwc/pwc-ctrl.c b/drivers/media/video/pwc/pwc-ctrl.c
index dbc5607..c665302 100644
--- a/drivers/media/video/pwc/pwc-ctrl.c
+++ b/drivers/media/video/pwc/pwc-ctrl.c
@@ -41,7 +41,6 @@
 #include <asm/uaccess.h>
 #endif
 #include <asm/errno.h>
-#include <linux/version.h>
 
 #include "pwc.h"
 #include "pwc-uncompress.h"
diff --git a/drivers/media/video/pwc/pwc-if.c b/drivers/media/video/pwc/pwc-if.c
index 9aee7cb..ab28389 100644
--- a/drivers/media/video/pwc/pwc-if.c
+++ b/drivers/media/video/pwc/pwc-if.c
@@ -1112,7 +1112,7 @@
 
 	PWC_DEBUG_OPEN(">> video_open called(vdev = 0x%p).\n", vdev);
 
-	pdev = (struct pwc_device *)vdev->priv;
+	pdev = video_get_drvdata(vdev);
 	BUG_ON(!pdev);
 	if (pdev->vopen) {
 		PWC_DEBUG_OPEN("I'm busy, someone is using the device.\n");
@@ -1233,7 +1233,7 @@
 	PWC_DEBUG_OPEN(">> video_close called(vdev = 0x%p).\n", vdev);
 
 	lock_kernel();
-	pdev = (struct pwc_device *)vdev->priv;
+	pdev = video_get_drvdata(vdev);
 	if (pdev->vopen == 0)
 		PWC_DEBUG_MODULE("video_close() called on closed device?\n");
 
@@ -1304,7 +1304,7 @@
 			vdev, buf, count);
 	if (vdev == NULL)
 		return -EFAULT;
-	pdev = vdev->priv;
+	pdev = video_get_drvdata(vdev);
 	if (pdev == NULL)
 		return -EFAULT;
 
@@ -1386,7 +1386,7 @@
 
 	if (vdev == NULL)
 		return -EFAULT;
-	pdev = vdev->priv;
+	pdev = video_get_drvdata(vdev);
 	if (pdev == NULL)
 		return -EFAULT;
 
@@ -1408,7 +1408,7 @@
 
 	if (!vdev)
 		goto out;
-	pdev = vdev->priv;
+	pdev = video_get_drvdata(vdev);
 
 	mutex_lock(&pdev->modlock);
 	if (!pdev->unplugged)
@@ -1428,7 +1428,7 @@
 	int index;
 
 	PWC_DEBUG_MEMORY(">> %s\n", __func__);
-	pdev = vdev->priv;
+	pdev = video_get_drvdata(vdev);
 	size = vma->vm_end - vma->vm_start;
 	start = vma->vm_start;
 
diff --git a/drivers/media/video/pwc/pwc-v4l.c b/drivers/media/video/pwc/pwc-v4l.c
index 1742889..76a1376 100644
--- a/drivers/media/video/pwc/pwc-v4l.c
+++ b/drivers/media/video/pwc/pwc-v4l.c
@@ -346,7 +346,7 @@
 
 	if (vdev == NULL)
 		return -EFAULT;
-	pdev = vdev->priv;
+	pdev = video_get_drvdata(vdev);
 	if (pdev == NULL)
 		return -EFAULT;
 
diff --git a/drivers/media/video/pxa_camera.c b/drivers/media/video/pxa_camera.c
index 388cf94..eb6be58 100644
--- a/drivers/media/video/pxa_camera.c
+++ b/drivers/media/video/pxa_camera.c
@@ -629,17 +629,6 @@
 		pdata->init(pcdev->dev);
 	}
 
-	if (pdata && pdata->power) {
-		dev_dbg(pcdev->dev, "%s: Power on camera\n", __func__);
-		pdata->power(pcdev->dev, 1);
-	}
-
-	if (pdata && pdata->reset) {
-		dev_dbg(pcdev->dev, "%s: Releasing camera reset\n",
-			__func__);
-		pdata->reset(pcdev->dev, 1);
-	}
-
 	CICR0 = 0x3FF;   /* disable all interrupts */
 
 	if (pcdev->platform_flags & PXA_CAMERA_PCLK_EN)
@@ -660,20 +649,7 @@
 
 static void pxa_camera_deactivate(struct pxa_camera_dev *pcdev)
 {
-	struct pxacamera_platform_data *board = pcdev->pdata;
-
 	clk_disable(pcdev->clk);
-
-	if (board && board->reset) {
-		dev_dbg(pcdev->dev, "%s: Asserting camera reset\n",
-			__func__);
-		board->reset(pcdev->dev, 0);
-	}
-
-	if (board && board->power) {
-		dev_dbg(pcdev->dev, "%s: Power off camera\n", __func__);
-		board->power(pcdev->dev, 0);
-	}
 }
 
 static irqreturn_t pxa_camera_irq(int irq, void *data)
@@ -1025,9 +1001,9 @@
 	struct pxa_camera_dev *pcdev = ici->priv;
 	int i = 0, ret = 0;
 
-	DRCMR68 = pcdev->dma_chans[0] | DRCMR_MAPVLD;
-	DRCMR69 = pcdev->dma_chans[1] | DRCMR_MAPVLD;
-	DRCMR70 = pcdev->dma_chans[2] | DRCMR_MAPVLD;
+	DRCMR(68) = pcdev->dma_chans[0] | DRCMR_MAPVLD;
+	DRCMR(69) = pcdev->dma_chans[1] | DRCMR_MAPVLD;
+	DRCMR(70) = pcdev->dma_chans[2] | DRCMR_MAPVLD;
 
 	CICR0 = pcdev->save_cicr[i++] & ~CICR0_ENB;
 	CICR1 = pcdev->save_cicr[i++];
@@ -1144,36 +1120,36 @@
 	pcdev->dev = &pdev->dev;
 
 	/* request dma */
-	pcdev->dma_chans[0] = pxa_request_dma("CI_Y", DMA_PRIO_HIGH,
-					      pxa_camera_dma_irq_y, pcdev);
-	if (pcdev->dma_chans[0] < 0) {
+	err = pxa_request_dma("CI_Y", DMA_PRIO_HIGH,
+			      pxa_camera_dma_irq_y, pcdev);
+	if (err < 0) {
 		dev_err(pcdev->dev, "Can't request DMA for Y\n");
-		err = -ENOMEM;
 		goto exit_iounmap;
 	}
+	pcdev->dma_chans[0] = err;
 	dev_dbg(pcdev->dev, "got DMA channel %d\n", pcdev->dma_chans[0]);
 
-	pcdev->dma_chans[1] = pxa_request_dma("CI_U", DMA_PRIO_HIGH,
-					      pxa_camera_dma_irq_u, pcdev);
-	if (pcdev->dma_chans[1] < 0) {
+	err = pxa_request_dma("CI_U", DMA_PRIO_HIGH,
+			      pxa_camera_dma_irq_u, pcdev);
+	if (err < 0) {
 		dev_err(pcdev->dev, "Can't request DMA for U\n");
-		err = -ENOMEM;
 		goto exit_free_dma_y;
 	}
+	pcdev->dma_chans[1] = err;
 	dev_dbg(pcdev->dev, "got DMA channel (U) %d\n", pcdev->dma_chans[1]);
 
-	pcdev->dma_chans[2] = pxa_request_dma("CI_V", DMA_PRIO_HIGH,
-					      pxa_camera_dma_irq_v, pcdev);
-	if (pcdev->dma_chans[0] < 0) {
+	err = pxa_request_dma("CI_V", DMA_PRIO_HIGH,
+			      pxa_camera_dma_irq_v, pcdev);
+	if (err < 0) {
 		dev_err(pcdev->dev, "Can't request DMA for V\n");
-		err = -ENOMEM;
 		goto exit_free_dma_u;
 	}
+	pcdev->dma_chans[2] = err;
 	dev_dbg(pcdev->dev, "got DMA channel (V) %d\n", pcdev->dma_chans[2]);
 
-	DRCMR68 = pcdev->dma_chans[0] | DRCMR_MAPVLD;
-	DRCMR69 = pcdev->dma_chans[1] | DRCMR_MAPVLD;
-	DRCMR70 = pcdev->dma_chans[2] | DRCMR_MAPVLD;
+	DRCMR(68) = pcdev->dma_chans[0] | DRCMR_MAPVLD;
+	DRCMR(69) = pcdev->dma_chans[1] | DRCMR_MAPVLD;
+	DRCMR(70) = pcdev->dma_chans[2] | DRCMR_MAPVLD;
 
 	/* request irq */
 	err = request_irq(pcdev->irq, pxa_camera_irq, 0, PXA_CAM_DRV_NAME,
diff --git a/drivers/media/video/s2255drv.c b/drivers/media/video/s2255drv.c
index b1d09d8..5272926 100644
--- a/drivers/media/video/s2255drv.c
+++ b/drivers/media/video/s2255drv.c
@@ -58,6 +58,8 @@
 
 
 
+/* default JPEG quality */
+#define S2255_DEF_JPEG_QUAL     50
 /* vendor request in */
 #define S2255_VR_IN		0
 /* vendor request out */
@@ -67,20 +69,21 @@
 /* USB endpoint number for configuring the device */
 #define S2255_CONFIG_EP         2
 /* maximum time for DSP to start responding after last FW word loaded(ms) */
-#define S2255_DSP_BOOTTIME      400
+#define S2255_DSP_BOOTTIME      800
 /* maximum time to wait for firmware to load (ms) */
 #define S2255_LOAD_TIMEOUT      (5000 + S2255_DSP_BOOTTIME)
 #define S2255_DEF_BUFS          16
+#define S2255_SETMODE_TIMEOUT   500
 #define MAX_CHANNELS		4
-#define FRAME_MARKER		0x2255DA4AL
-#define MAX_PIPE_USBBLOCK	(40 * 1024)
-#define DEFAULT_PIPE_USBBLOCK	(16 * 1024)
+#define S2255_MARKER_FRAME	0x2255DA4AL
+#define S2255_MARKER_RESPONSE	0x2255ACACL
+#define S2255_USB_XFER_SIZE	(16 * 1024)
 #define MAX_CHANNELS		4
 #define MAX_PIPE_BUFFERS	1
 #define SYS_FRAMES		4
 /* maximum size is PAL full size plus room for the marker header(s) */
-#define SYS_FRAMES_MAXSIZE	(720 * 288 * 2 * 2 + 4096)
-#define DEF_USB_BLOCK		(4096)
+#define SYS_FRAMES_MAXSIZE	(720*288*2*2 + 4096)
+#define DEF_USB_BLOCK		S2255_USB_XFER_SIZE
 #define LINE_SZ_4CIFS_NTSC	640
 #define LINE_SZ_2CIFS_NTSC	640
 #define LINE_SZ_1CIFS_NTSC	320
@@ -108,6 +111,9 @@
 #define COLOR_YUVPL	1	/* YUV planar */
 #define COLOR_YUVPK	2	/* YUV packed */
 #define COLOR_Y8	4	/* monochrome */
+#define COLOR_JPG       5       /* JPEG */
+#define MASK_COLOR      0xff
+#define MASK_JPG_QUALITY 0xff00
 
 /* frame decimation. Not implemented by V4L yet(experimental in V4L) */
 #define FDEC_1		1	/* capture every frame. default */
@@ -148,16 +154,14 @@
 	u32 restart;	/* if DSP requires restart */
 };
 
+
+#define S2255_READ_IDLE		0
+#define S2255_READ_FRAME	1
+
 /* frame structure */
-#define FRAME_STATE_UNUSED	0
-#define FRAME_STATE_FILLING	1
-#define FRAME_STATE_FULL	2
-
-
 struct s2255_framei {
 	unsigned long size;
-
-	unsigned long ulState;	/* ulState ==0 unused, 1 being filled, 2 full */
+	unsigned long ulState;	/* ulState:S2255_READ_IDLE, S2255_READ_FRAME*/
 	void *lpvbits;		/* image data */
 	unsigned long cur_size;	/* current data copied to it */
 };
@@ -188,6 +192,10 @@
 #define S2255_FW_FAILED		3
 #define S2255_FW_DISCONNECTING  4
 
+#define S2255_FW_MARKER         0x22552f2f
+/* 2255 read states */
+#define S2255_READ_IDLE         0
+#define S2255_READ_FRAME        1
 struct s2255_fw {
 	int		      fw_loaded;
 	int		      fw_size;
@@ -195,7 +203,6 @@
 	atomic_t	      fw_state;
 	void		      *pfw_data;
 	wait_queue_head_t     wait_fw;
-	struct timer_list     dsp_wait;
 	const struct firmware *fw;
 };
 
@@ -237,15 +244,27 @@
 	struct s2255_pipeinfo	pipes[MAX_PIPE_BUFFERS];
 	struct s2255_bufferi		buffer[MAX_CHANNELS];
 	struct s2255_mode	mode[MAX_CHANNELS];
+	/* jpeg compression */
+	struct v4l2_jpegcompression jc[MAX_CHANNELS];
 	const struct s2255_fmt	*cur_fmt[MAX_CHANNELS];
 	int			cur_frame[MAX_CHANNELS];
 	int			last_frame[MAX_CHANNELS];
 	u32			cc;	/* current channel */
 	int			b_acquire[MAX_CHANNELS];
+	/* allocated image size */
 	unsigned long		req_image_size[MAX_CHANNELS];
+	/* received packet size */
+	unsigned long		pkt_size[MAX_CHANNELS];
 	int			bad_payload[MAX_CHANNELS];
 	unsigned long		frame_count[MAX_CHANNELS];
 	int			frame_ready;
+	/* if JPEG image */
+	int                     jpg_size[MAX_CHANNELS];
+	/* if channel configured to default state */
+	int                     chn_configured[MAX_CHANNELS];
+	wait_queue_head_t       wait_setmode[MAX_CHANNELS];
+	int                     setmode_ready[MAX_CHANNELS];
+	int                     chn_ready;
 	struct kref		kref;
 	spinlock_t              slock;
 };
@@ -306,12 +325,16 @@
 static int s2255_start_acquire(struct s2255_dev *dev, unsigned long chn);
 static int s2255_stop_acquire(struct s2255_dev *dev, unsigned long chn);
 static void s2255_fillbuff(struct s2255_dev *dev, struct s2255_buffer *buf,
-			   int chn);
+			   int chn, int jpgsize);
 static int s2255_set_mode(struct s2255_dev *dev, unsigned long chn,
 			  struct s2255_mode *mode);
 static int s2255_board_shutdown(struct s2255_dev *dev);
 static void s2255_exit_v4l(struct s2255_dev *dev);
-static void s2255_fwload_start(struct s2255_dev *dev);
+static void s2255_fwload_start(struct s2255_dev *dev, int reset);
+static void s2255_destroy(struct kref *kref);
+static long s2255_vendor_req(struct s2255_dev *dev, unsigned char req,
+			     u16 index, u16 value, void *buf,
+			     s32 buf_len, int bOut);
 
 #define dprintk(level, fmt, arg...)					\
 	do {								\
@@ -407,6 +430,10 @@
 		.fourcc = V4L2_PIX_FMT_UYVY,
 		.depth = 16
 	}, {
+		.name = "JPG",
+		.fourcc = V4L2_PIX_FMT_JPEG,
+		.depth = 24
+	}, {
 		.name = "8bpp GREY",
 		.fourcc = V4L2_PIX_FMT_GREY,
 		.depth = 8
@@ -464,6 +491,13 @@
 	return;
 }
 
+static void s2255_reset_dsppower(struct s2255_dev *dev)
+{
+	s2255_vendor_req(dev, 0x40, 0x0b0b, 0x0b0b, NULL, 0, 1);
+	msleep(10);
+	s2255_vendor_req(dev, 0x50, 0x0000, 0x0000, NULL, 0, 1);
+	return;
+}
 
 /* kickstarts the firmware loading. from probe
  */
@@ -480,18 +514,6 @@
 	}
 }
 
-/* called when DSP is up and running.  DSP is guaranteed to
-   be running after S2255_DSP_BOOTTIME */
-static void s2255_dsp_running(unsigned long user_data)
-{
-	struct s2255_fw *data = (struct s2255_fw *)user_data;
-	dprintk(1, "dsp running\n");
-	atomic_set(&data->fw_state, S2255_FW_SUCCESS);
-	wake_up(&data->wait_fw);
-	printk(KERN_INFO "s2255: firmware loaded successfully\n");
-	return;
-}
-
 
 /* this loads the firmware asynchronously.
    Originally this was done synchroously in probe.
@@ -549,19 +571,14 @@
 		}
 		data->fw_loaded += len;
 	} else {
-		init_timer(&data->dsp_wait);
-		data->dsp_wait.function = s2255_dsp_running;
-		data->dsp_wait.data = (unsigned long)data;
 		atomic_set(&data->fw_state, S2255_FW_LOADED_DSPWAIT);
-		mod_timer(&data->dsp_wait, msecs_to_jiffies(S2255_DSP_BOOTTIME)
-			  + jiffies);
 	}
 	dprintk(100, "2255 complete done\n");
 	return;
 
 }
 
-static int s2255_got_frame(struct s2255_dev *dev, int chn)
+static int s2255_got_frame(struct s2255_dev *dev, int chn, int jpgsize)
 {
 	struct s2255_dmaqueue *dma_q = &dev->vidq[chn];
 	struct s2255_buffer *buf;
@@ -586,8 +603,7 @@
 	list_del(&buf->vb.queue);
 	do_gettimeofday(&buf->vb.ts);
 	dprintk(100, "[%p/%d] wakeup\n", buf, buf->vb.i);
-
-	s2255_fillbuff(dev, buf, dma_q->channel);
+	s2255_fillbuff(dev, buf, dma_q->channel, jpgsize);
 	wake_up(&buf->vb.done);
 	dprintk(2, "wakeup [buf/i] [%p/%d]\n", buf, buf->vb.i);
 unlock:
@@ -621,7 +637,7 @@
  *
  */
 static void s2255_fillbuff(struct s2255_dev *dev, struct s2255_buffer *buf,
-			   int chn)
+			   int chn, int jpgsize)
 {
 	int pos = 0;
 	struct timeval ts;
@@ -649,6 +665,10 @@
 		case V4L2_PIX_FMT_GREY:
 			memcpy(vbuf, tmpbuf, buf->vb.width * buf->vb.height);
 			break;
+		case V4L2_PIX_FMT_JPEG:
+			buf->vb.size = jpgsize;
+			memcpy(vbuf, tmpbuf, buf->vb.size);
+			break;
 		case V4L2_PIX_FMT_YUV422P:
 			memcpy(vbuf, tmpbuf,
 			       buf->vb.width * buf->vb.height * 2);
@@ -657,9 +677,6 @@
 			printk(KERN_DEBUG "s2255: unknown format?\n");
 		}
 		dev->last_frame[chn] = -1;
-		/* done with the frame, free it */
-		frm->ulState = 0;
-		dprintk(4, "freeing buffer\n");
 	} else {
 		printk(KERN_ERR "s2255: =======no frame\n");
 		return;
@@ -669,7 +686,7 @@
 		(unsigned long)vbuf, pos);
 	/* tell v4l buffer was filled */
 
-	buf->vb.field_count++;
+	buf->vb.field_count = dev->frame_count[chn] * 2;
 	do_gettimeofday(&ts);
 	buf->vb.ts = ts;
 	buf->vb.state = VIDEOBUF_DONE;
@@ -1021,6 +1038,10 @@
 	case V4L2_PIX_FMT_GREY:
 		fh->mode.color = COLOR_Y8;
 		break;
+	case V4L2_PIX_FMT_JPEG:
+		fh->mode.color = COLOR_JPG |
+			(fh->dev->jc[fh->channel].quality << 8);
+		break;
 	case V4L2_PIX_FMT_YUV422P:
 		fh->mode.color = COLOR_YUVPL;
 		break;
@@ -1139,7 +1160,7 @@
 		}
 	}
 	outImageSize = linesPerFrame * pixelsPerLine;
-	if (mode->color != COLOR_Y8) {
+	if ((mode->color & MASK_COLOR) != COLOR_Y8) {
 		/* 2 bytes/pixel if not monochrome */
 		outImageSize *= 2;
 	}
@@ -1185,12 +1206,17 @@
 	u32 *buffer;
 	unsigned long chn_rev;
 
+	mutex_lock(&dev->lock);
 	chn_rev = G_chnmap[chn];
 	dprintk(3, "mode scale [%ld] %p %d\n", chn, mode, mode->scale);
 	dprintk(3, "mode scale [%ld] %p %d\n", chn, &dev->mode[chn],
 		dev->mode[chn].scale);
 	dprintk(2, "mode contrast %x\n", mode->contrast);
 
+	/* if JPEG, set the quality */
+	if ((mode->color & MASK_COLOR) == COLOR_JPG)
+		mode->color = (dev->jc[chn].quality << 8) | COLOR_JPG;
+
 	/* save the mode */
 	dev->mode[chn] = *mode;
 	dev->req_image_size[chn] = get_transfer_size(mode);
@@ -1199,6 +1225,7 @@
 	buffer = kzalloc(512, GFP_KERNEL);
 	if (buffer == NULL) {
 		dev_err(&dev->udev->dev, "out of mem\n");
+		mutex_unlock(&dev->lock);
 		return -ENOMEM;
 	}
 
@@ -1214,12 +1241,20 @@
 	dprintk(1, "set mode done chn %lu, %d\n", chn, res);
 
 	/* wait at least 3 frames before continuing */
-	if (mode->restart)
-		msleep(125);
+	if (mode->restart) {
+		dev->setmode_ready[chn] = 0;
+		wait_event_timeout(dev->wait_setmode[chn],
+				   (dev->setmode_ready[chn] != 0),
+				   msecs_to_jiffies(S2255_SETMODE_TIMEOUT));
+		if (dev->setmode_ready[chn] != 1) {
+			printk(KERN_DEBUG "s2255: no set mode response\n");
+			res = -EFAULT;
+		}
+	}
 
 	/* clear the restart flag */
 	dev->mode[chn].restart = 0;
-
+	mutex_unlock(&dev->lock);
 	return res;
 }
 
@@ -1268,8 +1303,9 @@
 	dev->last_frame[chn] = -1;
 	dev->bad_payload[chn] = 0;
 	dev->cur_frame[chn] = 0;
+	dev->frame_count[chn] = 0;
 	for (j = 0; j < SYS_FRAMES; j++) {
-		dev->buffer[chn].frame[j].ulState = 0;
+		dev->buffer[chn].frame[j].ulState = S2255_READ_IDLE;
 		dev->buffer[chn].frame[j].cur_size = 0;
 	}
 	res = videobuf_streamon(&fh->vb_vidq);
@@ -1445,6 +1481,27 @@
 	return -EINVAL;
 }
 
+static int vidioc_g_jpegcomp(struct file *file, void *priv,
+			 struct v4l2_jpegcompression *jc)
+{
+	struct s2255_fh *fh = priv;
+	struct s2255_dev *dev = fh->dev;
+	*jc = dev->jc[fh->channel];
+	dprintk(2, "getting jpegcompression, quality %d\n", jc->quality);
+	return 0;
+}
+
+static int vidioc_s_jpegcomp(struct file *file, void *priv,
+			 struct v4l2_jpegcompression *jc)
+{
+	struct s2255_fh *fh = priv;
+	struct s2255_dev *dev = fh->dev;
+	if (jc->quality < 0 || jc->quality > 100)
+		return -EINVAL;
+	dev->jc[fh->channel].quality = jc->quality;
+	dprintk(2, "setting jpeg quality %d\n", jc->quality);
+	return 0;
+}
 static int s2255_open(struct inode *inode, struct file *file)
 {
 	int minor = iminor(inode);
@@ -1454,8 +1511,10 @@
 	enum v4l2_buf_type type = 0;
 	int i = 0;
 	int cur_channel = -1;
+	int state;
 	dprintk(1, "s2255: open called (minor=%d)\n", minor);
 
+	lock_kernel();
 	list_for_each(list, &s2255_devlist) {
 		h = list_entry(list, struct s2255_dev, s2255_devlist);
 		for (i = 0; i < MAX_CHANNELS; i++) {
@@ -1468,45 +1527,78 @@
 	}
 
 	if ((NULL == dev) || (cur_channel == -1)) {
-		dprintk(1, "s2255: openv4l no dev\n");
+		unlock_kernel();
+		printk(KERN_INFO "s2255: openv4l no dev\n");
 		return -ENODEV;
 	}
 
+	if (atomic_read(&dev->fw_data->fw_state) == S2255_FW_DISCONNECTING) {
+		unlock_kernel();
+		printk(KERN_INFO "disconnecting\n");
+		return -ENODEV;
+	}
+	kref_get(&dev->kref);
 	mutex_lock(&dev->open_lock);
 
 	dev->users[cur_channel]++;
 	dprintk(4, "s2255: open_handles %d\n", dev->users[cur_channel]);
 
-	if (atomic_read(&dev->fw_data->fw_state) == S2255_FW_FAILED) {
+	switch (atomic_read(&dev->fw_data->fw_state)) {
+	case S2255_FW_FAILED:
 		err("2255 firmware load failed. retrying.\n");
-		s2255_fwload_start(dev);
+		s2255_fwload_start(dev, 1);
 		wait_event_timeout(dev->fw_data->wait_fw,
-				   (atomic_read(&dev->fw_data->fw_state)
-				    != S2255_FW_NOTLOADED),
+				   ((atomic_read(&dev->fw_data->fw_state)
+				     == S2255_FW_SUCCESS) ||
+				    (atomic_read(&dev->fw_data->fw_state)
+				     == S2255_FW_DISCONNECTING)),
 				   msecs_to_jiffies(S2255_LOAD_TIMEOUT));
-		if (atomic_read(&dev->fw_data->fw_state)
-		    != S2255_FW_SUCCESS) {
-			printk(KERN_INFO "2255 FW load failed.\n");
-			dev->users[cur_channel]--;
-			mutex_unlock(&dev->open_lock);
-			return -EFAULT;
-		}
-	} else if (atomic_read(&dev->fw_data->fw_state) == S2255_FW_NOTLOADED) {
+		break;
+	case S2255_FW_NOTLOADED:
+	case S2255_FW_LOADED_DSPWAIT:
 		/* give S2255_LOAD_TIMEOUT time for firmware to load in case
 		   driver loaded and then device immediately opened */
 		printk(KERN_INFO "%s waiting for firmware load\n", __func__);
 		wait_event_timeout(dev->fw_data->wait_fw,
-				   (atomic_read(&dev->fw_data->fw_state)
-				   != S2255_FW_NOTLOADED),
-				   msecs_to_jiffies(S2255_LOAD_TIMEOUT));
-		if (atomic_read(&dev->fw_data->fw_state)
-		    != S2255_FW_SUCCESS) {
-			printk(KERN_INFO "2255 firmware not loaded"
-			       "try again\n");
-			dev->users[cur_channel]--;
-			mutex_unlock(&dev->open_lock);
-			return -EBUSY;
+				   ((atomic_read(&dev->fw_data->fw_state)
+				     == S2255_FW_SUCCESS) ||
+				    (atomic_read(&dev->fw_data->fw_state)
+				     == S2255_FW_DISCONNECTING)),
+			msecs_to_jiffies(S2255_LOAD_TIMEOUT));
+		break;
+	case S2255_FW_SUCCESS:
+	default:
+		break;
+	}
+	state = atomic_read(&dev->fw_data->fw_state);
+	if (state != S2255_FW_SUCCESS) {
+		int rc;
+		switch (state) {
+		case S2255_FW_FAILED:
+			printk(KERN_INFO "2255 FW load failed. %d\n", state);
+			rc = -ENODEV;
+			break;
+		case S2255_FW_DISCONNECTING:
+			printk(KERN_INFO "%s: disconnecting\n", __func__);
+			rc = -ENODEV;
+			break;
+		case S2255_FW_LOADED_DSPWAIT:
+		case S2255_FW_NOTLOADED:
+			printk(KERN_INFO "%s: firmware not loaded yet"
+			       "please try again later\n",
+			       __func__);
+			rc = -EAGAIN;
+			break;
+		default:
+			printk(KERN_INFO "%s: unknown state\n", __func__);
+			rc = -EFAULT;
+			break;
 		}
+		dev->users[cur_channel]--;
+		mutex_unlock(&dev->open_lock);
+		kref_put(&dev->kref, s2255_destroy);
+		unlock_kernel();
+		return rc;
 	}
 
 	/* allocate + initialize per filehandle data */
@@ -1514,6 +1606,8 @@
 	if (NULL == fh) {
 		dev->users[cur_channel]--;
 		mutex_unlock(&dev->open_lock);
+		kref_put(&dev->kref, s2255_destroy);
+		unlock_kernel();
 		return -ENOMEM;
 	}
 
@@ -1527,6 +1621,13 @@
 	fh->height = NUM_LINES_4CIFS_NTSC * 2;
 	fh->channel = cur_channel;
 
+	/* configure channel to default state */
+	if (!dev->chn_configured[cur_channel]) {
+		s2255_set_mode(dev, cur_channel, &fh->mode);
+		dev->chn_configured[cur_channel] = 1;
+	}
+
+
 	/* Put all controls at a sane state */
 	for (i = 0; i < ARRAY_SIZE(s2255_qctrl); i++)
 		qctl_regs[i] = s2255_qctrl[i].default_value;
@@ -1545,8 +1646,8 @@
 				    V4L2_FIELD_INTERLACED,
 				    sizeof(struct s2255_buffer), fh);
 
-	kref_get(&dev->kref);
 	mutex_unlock(&dev->open_lock);
+	unlock_kernel();
 	return 0;
 }
 
@@ -1568,30 +1669,24 @@
 static void s2255_destroy(struct kref *kref)
 {
 	struct s2255_dev *dev = to_s2255_dev(kref);
+	struct list_head *list;
+	int i;
 	if (!dev) {
 		printk(KERN_ERR "s2255drv: kref problem\n");
 		return;
 	}
-
-	/*
-	 * Wake up any firmware load waiting (only done in .open,
-	 * which holds the open_lock mutex)
-	 */
 	atomic_set(&dev->fw_data->fw_state, S2255_FW_DISCONNECTING);
 	wake_up(&dev->fw_data->wait_fw);
-
-	/* prevent s2255_disconnect from racing s2255_open */
+	for (i = 0; i < MAX_CHANNELS; i++) {
+		dev->setmode_ready[i] = 1;
+		wake_up(&dev->wait_setmode[i]);
+	}
 	mutex_lock(&dev->open_lock);
+	/* reset the DSP so firmware can be reload next time */
+	s2255_reset_dsppower(dev);
 	s2255_exit_v4l(dev);
-	/*
-	 * device unregistered so no longer possible to open. open_mutex
-	 *  can be unlocked and timers deleted afterwards.
-	 */
-	mutex_unlock(&dev->open_lock);
-
 	/* board shutdown stops the read pipe if it is running */
 	s2255_board_shutdown(dev);
-
 	/* make sure firmware still not trying to load */
 	del_timer(&dev->timer);  /* only started in .probe and .open */
 
@@ -1601,23 +1696,19 @@
 		usb_free_urb(dev->fw_data->fw_urb);
 		dev->fw_data->fw_urb = NULL;
 	}
-
-	/*
-	 * delete the dsp_wait timer, which sets the firmware
-	 * state on completion.  This is done before fw_data
-	 * is freed below.
-	 */
-
-	del_timer(&dev->fw_data->dsp_wait); /* only started in .open */
-
 	if (dev->fw_data->fw)
 		release_firmware(dev->fw_data->fw);
 	kfree(dev->fw_data->pfw_data);
 	kfree(dev->fw_data);
-
 	usb_put_dev(dev->udev);
 	dprintk(1, "%s", __func__);
 	kfree(dev);
+
+	while (!list_empty(&s2255_devlist)) {
+		list = s2255_devlist.next;
+		list_del(list);
+	}
+	mutex_unlock(&dev->open_lock);
 }
 
 static int s2255_close(struct inode *inode, struct file *file)
@@ -1701,6 +1792,8 @@
 #ifdef CONFIG_VIDEO_V4L1_COMPAT
 	.vidiocgmbuf = vidioc_cgmbuf,
 #endif
+	.vidioc_s_jpegcomp = vidioc_s_jpegcomp,
+	.vidioc_g_jpegcomp = vidioc_g_jpegcomp,
 };
 
 static struct video_device template = {
@@ -1739,7 +1832,7 @@
 			ret = video_register_device(dev->vdev[i],
 						    VFL_TYPE_GRABBER,
 						    cur_nr + i);
-		dev->vdev[i]->priv = dev;
+		video_set_drvdata(dev->vdev[i], dev);
 
 		if (ret != 0) {
 			dev_err(&dev->udev->dev,
@@ -1753,18 +1846,16 @@
 
 static void s2255_exit_v4l(struct s2255_dev *dev)
 {
-	struct list_head *list;
+
 	int i;
-	/* unregister the video devices */
-	while (!list_empty(&s2255_devlist)) {
-		list = s2255_devlist.next;
-		list_del(list);
-	}
 	for (i = 0; i < MAX_CHANNELS; i++) {
-		if (-1 != dev->vdev[i]->minor)
+		if (-1 != dev->vdev[i]->minor) {
 			video_unregister_device(dev->vdev[i]);
-		else
+			printk(KERN_INFO "s2255 unregistered\n");
+		} else {
 			video_device_release(dev->vdev[i]);
+			printk(KERN_INFO "s2255 released\n");
+		}
 	}
 }
 
@@ -1774,133 +1865,122 @@
  * function again).
  *
  * Received frame structure:
- * bytes 0-3:  marker : 0x2255DA4AL (FRAME_MARKER)
+ * bytes 0-3:  marker : 0x2255DA4AL (S2255_MARKER_FRAME)
  * bytes 4-7:  channel: 0-3
  * bytes 8-11: payload size:  size of the frame
  * bytes 12-payloadsize+12:  frame data
  */
 static int save_frame(struct s2255_dev *dev, struct s2255_pipeinfo *pipe_info)
 {
-	static int dbgsync; /* = 0; */
 	char *pdest;
 	u32 offset = 0;
-	int bsync = 0;
-	int btrunc = 0;
+	int bframe = 0;
 	char *psrc;
 	unsigned long copy_size;
 	unsigned long size;
 	s32 idx = -1;
 	struct s2255_framei *frm;
 	unsigned char *pdata;
-	unsigned long cur_size;
-	int bsearch = 0;
-	struct s2255_bufferi *buf;
+
 	dprintk(100, "buffer to user\n");
 
 	idx = dev->cur_frame[dev->cc];
-	buf = &dev->buffer[dev->cc];
-	frm = &buf->frame[idx];
-
-	if (frm->ulState == 0) {
-		frm->ulState = 1;
-		frm->cur_size = 0;
-		bsearch = 1;
-	} else if (frm->ulState == 2) {
-		/* system frame was not freed */
-		dprintk(2, "sys frame not free.  overrun ringbuf\n");
-		bsearch = 1;
-		frm->ulState = 1;
-		frm->cur_size = 0;
-	}
-
-	if (bsearch) {
-		if (*(s32 *) pipe_info->transfer_buffer != FRAME_MARKER) {
-			u32 jj;
-			if (dbgsync == 0) {
-				dprintk(3, "not synched, discarding all packets"
-					"until marker\n");
-
-				dbgsync++;
-			}
-			pdata = (unsigned char *)pipe_info->transfer_buffer;
-			for (jj = 0; jj < (pipe_info->cur_transfer_size - 12);
-			     jj++) {
-				if (*(s32 *) pdata == FRAME_MARKER) {
-					int cc;
-					dprintk(3,
-						"found frame marker at offset:"
-						" %d [%x %x]\n", jj, pdata[0],
-						pdata[1]);
-					offset = jj;
-					bsync = 1;
-					cc = *(u32 *) (pdata + sizeof(u32));
-					if (cc >= MAX_CHANNELS) {
-						printk(KERN_ERR
-						       "bad channel\n");
-						return -EINVAL;
-					}
-					/* reverse it */
-					dev->cc = G_chnmap[cc];
-					break;
-				}
-				pdata++;
-			}
-			if (bsync == 0)
-				return -EINVAL;
-		} else {
-			u32 *pword;
-			u32 payload;
-			int cc;
-			dbgsync = 0;
-			bsync = 1;
-			pword = (u32 *) pipe_info->transfer_buffer;
-			cc = pword[1];
-
-			if (cc >= MAX_CHANNELS) {
-				printk("invalid channel found. "
-					"throwing out data!\n");
-				return -EINVAL;
-			}
-			dev->cc = G_chnmap[cc];
-			payload = pword[2];
-			if (payload != dev->req_image_size[dev->cc]) {
-				dprintk(1, "[%d][%d]unexpected payload: %d"
-					"required: %lu \n", cc, dev->cc,
-					payload, dev->req_image_size[dev->cc]);
-				dev->bad_payload[dev->cc]++;
-				/* discard the bad frame */
-				return -EINVAL;
-			}
-
-		}
-	}
-	/* search done.  now find out if should be acquiring
-	   on this channel */
-	if (!dev->b_acquire[dev->cc]) {
-		frm->ulState = 0;
-		return -EINVAL;
-	}
-
-	idx = dev->cur_frame[dev->cc];
 	frm = &dev->buffer[dev->cc].frame[idx];
 
-	if (frm->ulState == 0) {
-		frm->ulState = 1;
-		frm->cur_size = 0;
-	} else if (frm->ulState == 2) {
-		/* system frame ring buffer overrun */
-		dprintk(2, "sys frame overrun.  overwriting frame %d %d\n",
-			dev->cc, idx);
-		frm->ulState = 1;
+	if (frm->ulState == S2255_READ_IDLE) {
+		int jj;
+		unsigned int cc;
+		s32 *pdword;
+		int payload;
+		/* search for marker codes */
+		pdata = (unsigned char *)pipe_info->transfer_buffer;
+		for (jj = 0; jj < (pipe_info->cur_transfer_size - 12); jj++) {
+			switch (*(s32 *) pdata) {
+			case S2255_MARKER_FRAME:
+				pdword = (s32 *)pdata;
+				dprintk(4, "found frame marker at offset:"
+					" %d [%x %x]\n", jj, pdata[0],
+					pdata[1]);
+				offset = jj + PREFIX_SIZE;
+				bframe = 1;
+				cc = pdword[1];
+				if (cc >= MAX_CHANNELS) {
+					printk(KERN_ERR
+					       "bad channel\n");
+					return -EINVAL;
+				}
+				/* reverse it */
+				dev->cc = G_chnmap[cc];
+				payload =  pdword[3];
+				if (payload > dev->req_image_size[dev->cc]) {
+					dev->bad_payload[dev->cc]++;
+					/* discard the bad frame */
+					return -EINVAL;
+				}
+				dev->pkt_size[dev->cc] = payload;
+				dev->jpg_size[dev->cc] = pdword[4];
+				break;
+			case S2255_MARKER_RESPONSE:
+				pdword = (s32 *)pdata;
+				pdata += DEF_USB_BLOCK;
+				jj += DEF_USB_BLOCK;
+				if (pdword[1] >= MAX_CHANNELS)
+					break;
+				cc = G_chnmap[pdword[1]];
+				if (!(cc >= 0 && cc < MAX_CHANNELS))
+					break;
+				switch (pdword[2]) {
+				case 0x01:
+					/* check if channel valid */
+					/* set mode ready */
+					dev->setmode_ready[cc] = 1;
+					wake_up(&dev->wait_setmode[cc]);
+					dprintk(5, "setmode ready %d\n", cc);
+					break;
+				case 0x10:
+
+					dev->chn_ready |= (1 << cc);
+					if ((dev->chn_ready & 0x0f) != 0x0f)
+						break;
+					/* all channels ready */
+					printk(KERN_INFO "s2255: fw loaded\n");
+					atomic_set(&dev->fw_data->fw_state,
+						   S2255_FW_SUCCESS);
+					wake_up(&dev->fw_data->wait_fw);
+					break;
+				default:
+					printk(KERN_INFO "s2255 unknwn resp\n");
+				}
+			default:
+				pdata++;
+				break;
+			}
+			if (bframe)
+				break;
+		} /* for */
+		if (!bframe)
+			return -EINVAL;
+	}
+
+
+	idx = dev->cur_frame[dev->cc];
+	frm = &dev->buffer[dev->cc].frame[idx];
+
+	/* search done.  now find out if should be acquiring on this channel */
+	if (!dev->b_acquire[dev->cc]) {
+		/* we found a frame, but this channel is turned off */
+		frm->ulState = S2255_READ_IDLE;
+		return -EINVAL;
+	}
+
+	if (frm->ulState == S2255_READ_IDLE) {
+		frm->ulState = S2255_READ_FRAME;
 		frm->cur_size = 0;
 	}
 
-	if (bsync) {
-		/* skip the marker 512 bytes (and offset if out of sync) */
-		psrc = (u8 *)pipe_info->transfer_buffer + offset + PREFIX_SIZE;
-	} else {
-		psrc = (u8 *)pipe_info->transfer_buffer;
-	}
+	/* skip the marker 512 bytes (and offset if out of sync) */
+	psrc = (u8 *)pipe_info->transfer_buffer + offset;
+
 
 	if (frm->lpvbits == NULL) {
 		dprintk(1, "s2255 frame buffer == NULL.%p %p %d %d",
@@ -1910,33 +1990,20 @@
 
 	pdest = frm->lpvbits + frm->cur_size;
 
-	if (bsync) {
-		copy_size =
-		    (pipe_info->cur_transfer_size - offset) - PREFIX_SIZE;
-		if (copy_size > pipe_info->cur_transfer_size) {
-			printk("invalid copy size, overflow!\n");
-			return -ENOMEM;
-		}
-	} else {
-		copy_size = pipe_info->cur_transfer_size;
-	}
+	copy_size = (pipe_info->cur_transfer_size - offset);
 
-	cur_size = frm->cur_size;
-	size = dev->req_image_size[dev->cc];
+	size = dev->pkt_size[dev->cc] - PREFIX_SIZE;
 
-	if ((copy_size + cur_size) > size) {
-		copy_size = size - cur_size;
-		btrunc = 1;
-	}
+	/* sanity check on pdest */
+	if ((copy_size + frm->cur_size) < dev->req_image_size[dev->cc])
+		memcpy(pdest, psrc, copy_size);
 
-	memcpy(pdest, psrc, copy_size);
-	cur_size += copy_size;
 	frm->cur_size += copy_size;
-	dprintk(50, "cur_size size %lu size %lu \n", cur_size, size);
+	dprintk(4, "cur_size size %lu size %lu \n", frm->cur_size, size);
 
-	if (cur_size >= (size - PREFIX_SIZE)) {
+	if (frm->cur_size >= size) {
+
 		u32 cc = dev->cc;
-		frm->ulState = 2;
 		dprintk(2, "****************[%d]Buffer[%d]full*************\n",
 			cc, idx);
 		dev->last_frame[cc] = dev->cur_frame[cc];
@@ -1945,16 +2012,13 @@
 		if ((dev->cur_frame[cc] == SYS_FRAMES) ||
 		    (dev->cur_frame[cc] == dev->buffer[cc].dwFrames))
 			dev->cur_frame[cc] = 0;
-
-		/* signal the semaphore for this channel */
+		/* frame ready */
 		if (dev->b_acquire[cc])
-			s2255_got_frame(dev, cc);
+			s2255_got_frame(dev, cc, dev->jpg_size[cc]);
 		dev->frame_count[cc]++;
-	}
-	/* frame was truncated */
-	if (btrunc) {
-		/* return more data to process */
-		return EAGAIN;
+		frm->ulState = S2255_READ_IDLE;
+		frm->cur_size = 0;
+
 	}
 	/* done successfully */
 	return 0;
@@ -1973,8 +2037,8 @@
 	}
 	/* otherwise copy to the system buffers */
 	res = save_frame(dev, pipe_info);
-	if (res == EAGAIN)
-		save_frame(dev, pipe_info);
+	if (res != 0)
+		dprintk(4, "s2255: read callback failed\n");
 
 	dprintk(50, "callback read video done\n");
 	return;
@@ -2094,11 +2158,9 @@
 
 		memset(pipe, 0, sizeof(*pipe));
 		pipe->dev = dev;
-		pipe->cur_transfer_size = DEFAULT_PIPE_USBBLOCK;
-		pipe->max_transfer_size = MAX_PIPE_USBBLOCK;
+		pipe->cur_transfer_size = S2255_USB_XFER_SIZE;
+		pipe->max_transfer_size = S2255_USB_XFER_SIZE;
 
-		if (pipe->cur_transfer_size > pipe->max_transfer_size)
-			pipe->cur_transfer_size = pipe->max_transfer_size;
 		pipe->transfer_buffer = kzalloc(pipe->max_transfer_size,
 						GFP_KERNEL);
 		if (pipe->transfer_buffer == NULL) {
@@ -2118,6 +2180,7 @@
 	for (j = 0; j < MAX_CHANNELS; j++) {
 		dev->b_acquire[j] = 0;
 		dev->mode[j] = mode_def;
+		dev->jc[j].quality = S2255_DEF_JPEG_QUAL;
 		dev->cur_fmt[j] = &formats[0];
 		dev->mode[j].restart = 1;
 		dev->req_image_size[j] = get_transfer_size(&mode_def);
@@ -2322,7 +2385,7 @@
 	kfree(buffer);
 	dev->b_acquire[chn] = 0;
 
-	return 0;
+	return res;
 }
 
 static void s2255_stop_readpipe(struct s2255_dev *dev)
@@ -2358,8 +2421,10 @@
 	return;
 }
 
-static void s2255_fwload_start(struct s2255_dev *dev)
+static void s2255_fwload_start(struct s2255_dev *dev, int reset)
 {
+	if (reset)
+		s2255_reset_dsppower(dev);
 	dev->fw_data->fw_size = dev->fw_data->fw->size;
 	atomic_set(&dev->fw_data->fw_state, S2255_FW_NOTLOADED);
 	memcpy(dev->fw_data->pfw_data,
@@ -2382,6 +2447,8 @@
 	struct usb_endpoint_descriptor *endpoint;
 	int i;
 	int retval = -ENOMEM;
+	__le32 *pdata;
+	int fw_size;
 
 	dprintk(2, "s2255: probe\n");
 
@@ -2436,6 +2503,8 @@
 	dev->timer.data = (unsigned long)dev->fw_data;
 
 	init_waitqueue_head(&dev->fw_data->wait_fw);
+	for (i = 0; i < MAX_CHANNELS; i++)
+		init_waitqueue_head(&dev->wait_setmode[i]);
 
 
 	dev->fw_data->fw_urb = usb_alloc_urb(0, GFP_KERNEL);
@@ -2455,16 +2524,30 @@
 		printk(KERN_ERR "sensoray 2255 failed to get firmware\n");
 		goto error;
 	}
+	/* check the firmware is valid */
+	fw_size = dev->fw_data->fw->size;
+	pdata = (__le32 *) &dev->fw_data->fw->data[fw_size - 8];
 
+	if (*pdata != S2255_FW_MARKER) {
+		printk(KERN_INFO "Firmware invalid.\n");
+		retval = -ENODEV;
+		goto error;
+	} else {
+		/* make sure firmware is the latest */
+		__le32 *pRel;
+		pRel = (__le32 *) &dev->fw_data->fw->data[fw_size - 4];
+		printk(KERN_INFO "s2255 dsp fw version %x\n", *pRel);
+	}
 	/* loads v4l specific */
 	s2255_probe_v4l(dev);
+	usb_reset_device(dev->udev);
 	/* load 2255 board specific */
 	s2255_board_init(dev);
 
 	dprintk(4, "before probe done %p\n", dev);
 	spin_lock_init(&dev->slock);
 
-	s2255_fwload_start(dev);
+	s2255_fwload_start(dev, 0);
 	dev_info(&interface->dev, "Sensoray 2255 detected\n");
 	return 0;
 error:
@@ -2475,14 +2558,30 @@
 static void s2255_disconnect(struct usb_interface *interface)
 {
 	struct s2255_dev *dev = NULL;
+	int i;
 	dprintk(1, "s2255: disconnect interface %p\n", interface);
 	dev = usb_get_intfdata(interface);
+
+	/*
+	 * wake up any of the timers to allow open_lock to be
+	 * acquired sooner
+	 */
+	atomic_set(&dev->fw_data->fw_state, S2255_FW_DISCONNECTING);
+	wake_up(&dev->fw_data->wait_fw);
+	for (i = 0; i < MAX_CHANNELS; i++) {
+		dev->setmode_ready[i] = 1;
+		wake_up(&dev->wait_setmode[i]);
+	}
+
+	mutex_lock(&dev->open_lock);
+	usb_set_intfdata(interface, NULL);
+	mutex_unlock(&dev->open_lock);
+
 	if (dev) {
 		kref_put(&dev->kref, s2255_destroy);
 		dprintk(1, "s2255drv: disconnect\n");
 		dev_info(&interface->dev, "s2255usb now disconnected\n");
 	}
-	usb_set_intfdata(interface, NULL);
 }
 
 static struct usb_driver s2255_driver = {
diff --git a/drivers/media/video/saa5246a.c b/drivers/media/video/saa5246a.c
index 6ee63e6..4a21b8a 100644
--- a/drivers/media/video/saa5246a.c
+++ b/drivers/media/video/saa5246a.c
@@ -43,136 +43,364 @@
 #include <linux/mm.h>
 #include <linux/init.h>
 #include <linux/i2c.h>
+#include <linux/smp_lock.h>
+#include <linux/mutex.h>
 #include <linux/videotext.h>
 #include <linux/videodev.h>
 #include <media/v4l2-common.h>
 #include <media/v4l2-ioctl.h>
-#include <linux/mutex.h>
-
-#include "saa5246a.h"
+#include <media/v4l2-i2c-drv-legacy.h>
 
 MODULE_AUTHOR("Michael Geng <linux@MichaelGeng.de>");
 MODULE_DESCRIPTION("Philips SAA5246A, SAA5281 Teletext decoder driver");
 MODULE_LICENSE("GPL");
 
+#define MAJOR_VERSION 1		/* driver major version number */
+#define MINOR_VERSION 8		/* driver minor version number */
+
+/* Number of DAUs = number of pages that can be searched at the same time. */
+#define NUM_DAUS 4
+
+#define NUM_ROWS_PER_PAGE 40
+
+/* first column is 0 (not 1) */
+#define POS_TIME_START 32
+#define POS_TIME_END 39
+
+#define POS_HEADER_START 7
+#define POS_HEADER_END 31
+
+/* Returns 'true' if the part of the videotext page described with req contains
+   (at least parts of) the time field */
+#define REQ_CONTAINS_TIME(p_req) \
+	((p_req)->start <= POS_TIME_END && \
+	 (p_req)->end   >= POS_TIME_START)
+
+/* Returns 'true' if the part of the videotext page described with req contains
+   (at least parts of) the page header */
+#define REQ_CONTAINS_HEADER(p_req) \
+	((p_req)->start <= POS_HEADER_END && \
+	 (p_req)->end   >= POS_HEADER_START)
+
+/*****************************************************************************/
+/* Mode register numbers of the SAA5246A				     */
+/*****************************************************************************/
+#define SAA5246A_REGISTER_R0    0
+#define SAA5246A_REGISTER_R1    1
+#define SAA5246A_REGISTER_R2    2
+#define SAA5246A_REGISTER_R3    3
+#define SAA5246A_REGISTER_R4    4
+#define SAA5246A_REGISTER_R5    5
+#define SAA5246A_REGISTER_R6    6
+#define SAA5246A_REGISTER_R7    7
+#define SAA5246A_REGISTER_R8    8
+#define SAA5246A_REGISTER_R9    9
+#define SAA5246A_REGISTER_R10  10
+#define SAA5246A_REGISTER_R11  11
+#define SAA5246A_REGISTER_R11B 11
+
+/* SAA5246A mode registers often autoincrement to the next register.
+   Therefore we use variable argument lists. The following macro indicates
+   the end of a command list. */
+#define COMMAND_END (-1)
+
+/*****************************************************************************/
+/* Contents of the mode registers of the SAA5246A			     */
+/*****************************************************************************/
+/* Register R0 (Advanced Control) */
+#define R0_SELECT_R11					   0x00
+#define R0_SELECT_R11B					   0x01
+
+#define R0_PLL_TIME_CONSTANT_LONG			   0x00
+#define R0_PLL_TIME_CONSTANT_SHORT			   0x02
+
+#define R0_ENABLE_nODD_EVEN_OUTPUT			   0x00
+#define R0_DISABLE_nODD_EVEN_OUTPUT			   0x04
+
+#define R0_ENABLE_HDR_POLL				   0x00
+#define R0_DISABLE_HDR_POLL				   0x10
+
+#define R0_DO_NOT_FORCE_nODD_EVEN_LOW_IF_PICTURE_DISPLAYED 0x00
+#define R0_FORCE_nODD_EVEN_LOW_IF_PICTURE_DISPLAYED	   0x20
+
+#define R0_NO_FREE_RUN_PLL				   0x00
+#define R0_FREE_RUN_PLL					   0x40
+
+#define R0_NO_AUTOMATIC_FASTEXT_PROMPT			   0x00
+#define R0_AUTOMATIC_FASTEXT_PROMPT			   0x80
+
+/* Register R1 (Mode) */
+#define R1_INTERLACED_312_AND_HALF_312_AND_HALF_LINES	   0x00
+#define R1_NON_INTERLACED_312_313_LINES			   0x01
+#define R1_NON_INTERLACED_312_312_LINES			   0x02
+#define R1_FFB_LEADING_EDGE_IN_FIRST_BROAD_PULSE	   0x03
+#define R1_FFB_LEADING_EDGE_IN_SECOND_BROAD_PULSE	   0x07
+
+#define R1_DEW						   0x00
+#define R1_FULL_FIELD					   0x08
+
+#define R1_EXTENDED_PACKET_DISABLE			   0x00
+#define R1_EXTENDED_PACKET_ENABLE			   0x10
+
+#define R1_DAUS_ALL_ON					   0x00
+#define R1_DAUS_ALL_OFF					   0x20
+
+#define R1_7_BITS_PLUS_PARITY				   0x00
+#define R1_8_BITS_NO_PARITY				   0x40
+
+#define R1_VCS_TO_SCS					   0x00
+#define R1_NO_VCS_TO_SCS				   0x80
+
+/* Register R2 (Page request address) */
+#define R2_IN_R3_SELECT_PAGE_HUNDREDS			   0x00
+#define R2_IN_R3_SELECT_PAGE_TENS			   0x01
+#define R2_IN_R3_SELECT_PAGE_UNITS			   0x02
+#define R2_IN_R3_SELECT_HOURS_TENS			   0x03
+#define R2_IN_R3_SELECT_HOURS_UNITS			   0x04
+#define R2_IN_R3_SELECT_MINUTES_TENS			   0x05
+#define R2_IN_R3_SELECT_MINUTES_UNITS			   0x06
+
+#define R2_DAU_0					   0x00
+#define R2_DAU_1					   0x10
+#define R2_DAU_2					   0x20
+#define R2_DAU_3					   0x30
+
+#define R2_BANK_0					   0x00
+#define R2_BANK 1					   0x40
+
+#define R2_HAMMING_CHECK_ON				   0x80
+#define R2_HAMMING_CHECK_OFF				   0x00
+
+/* Register R3 (Page request data) */
+#define R3_PAGE_HUNDREDS_0				   0x00
+#define R3_PAGE_HUNDREDS_1				   0x01
+#define R3_PAGE_HUNDREDS_2				   0x02
+#define R3_PAGE_HUNDREDS_3				   0x03
+#define R3_PAGE_HUNDREDS_4				   0x04
+#define R3_PAGE_HUNDREDS_5				   0x05
+#define R3_PAGE_HUNDREDS_6				   0x06
+#define R3_PAGE_HUNDREDS_7				   0x07
+
+#define R3_HOLD_PAGE					   0x00
+#define R3_UPDATE_PAGE					   0x08
+
+#define R3_PAGE_HUNDREDS_DO_NOT_CARE			   0x00
+#define R3_PAGE_HUNDREDS_DO_CARE			   0x10
+
+#define R3_PAGE_TENS_DO_NOT_CARE			   0x00
+#define R3_PAGE_TENS_DO_CARE				   0x10
+
+#define R3_PAGE_UNITS_DO_NOT_CARE			   0x00
+#define R3_PAGE_UNITS_DO_CARE				   0x10
+
+#define R3_HOURS_TENS_DO_NOT_CARE			   0x00
+#define R3_HOURS_TENS_DO_CARE				   0x10
+
+#define R3_HOURS_UNITS_DO_NOT_CARE			   0x00
+#define R3_HOURS_UNITS_DO_CARE				   0x10
+
+#define R3_MINUTES_TENS_DO_NOT_CARE			   0x00
+#define R3_MINUTES_TENS_DO_CARE				   0x10
+
+#define R3_MINUTES_UNITS_DO_NOT_CARE			   0x00
+#define R3_MINUTES_UNITS_DO_CARE			   0x10
+
+/* Register R4 (Display chapter) */
+#define R4_DISPLAY_PAGE_0				   0x00
+#define R4_DISPLAY_PAGE_1				   0x01
+#define R4_DISPLAY_PAGE_2				   0x02
+#define R4_DISPLAY_PAGE_3				   0x03
+#define R4_DISPLAY_PAGE_4				   0x04
+#define R4_DISPLAY_PAGE_5				   0x05
+#define R4_DISPLAY_PAGE_6				   0x06
+#define R4_DISPLAY_PAGE_7				   0x07
+
+/* Register R5 (Normal display control) */
+#define R5_PICTURE_INSIDE_BOXING_OFF			   0x00
+#define R5_PICTURE_INSIDE_BOXING_ON			   0x01
+
+#define R5_PICTURE_OUTSIDE_BOXING_OFF			   0x00
+#define R5_PICTURE_OUTSIDE_BOXING_ON			   0x02
+
+#define R5_TEXT_INSIDE_BOXING_OFF			   0x00
+#define R5_TEXT_INSIDE_BOXING_ON			   0x04
+
+#define R5_TEXT_OUTSIDE_BOXING_OFF			   0x00
+#define R5_TEXT_OUTSIDE_BOXING_ON			   0x08
+
+#define R5_CONTRAST_REDUCTION_INSIDE_BOXING_OFF		   0x00
+#define R5_CONTRAST_REDUCTION_INSIDE_BOXING_ON		   0x10
+
+#define R5_CONTRAST_REDUCTION_OUTSIDE_BOXING_OFF	   0x00
+#define R5_CONTRAST_REDUCTION_OUTSIDE_BOXING_ON		   0x20
+
+#define R5_BACKGROUND_COLOR_INSIDE_BOXING_OFF		   0x00
+#define R5_BACKGROUND_COLOR_INSIDE_BOXING_ON		   0x40
+
+#define R5_BACKGROUND_COLOR_OUTSIDE_BOXING_OFF		   0x00
+#define R5_BACKGROUND_COLOR_OUTSIDE_BOXING_ON		   0x80
+
+/* Register R6 (Newsflash display) */
+#define R6_NEWSFLASH_PICTURE_INSIDE_BOXING_OFF		   0x00
+#define R6_NEWSFLASH_PICTURE_INSIDE_BOXING_ON		   0x01
+
+#define R6_NEWSFLASH_PICTURE_OUTSIDE_BOXING_OFF		   0x00
+#define R6_NEWSFLASH_PICTURE_OUTSIDE_BOXING_ON		   0x02
+
+#define R6_NEWSFLASH_TEXT_INSIDE_BOXING_OFF		   0x00
+#define R6_NEWSFLASH_TEXT_INSIDE_BOXING_ON		   0x04
+
+#define R6_NEWSFLASH_TEXT_OUTSIDE_BOXING_OFF		   0x00
+#define R6_NEWSFLASH_TEXT_OUTSIDE_BOXING_ON		   0x08
+
+#define R6_NEWSFLASH_CONTRAST_REDUCTION_INSIDE_BOXING_OFF  0x00
+#define R6_NEWSFLASH_CONTRAST_REDUCTION_INSIDE_BOXING_ON   0x10
+
+#define R6_NEWSFLASH_CONTRAST_REDUCTION_OUTSIDE_BOXING_OFF 0x00
+#define R6_NEWSFLASH_CONTRAST_REDUCTION_OUTSIDE_BOXING_ON  0x20
+
+#define R6_NEWSFLASH_BACKGROUND_COLOR_INSIDE_BOXING_OFF    0x00
+#define R6_NEWSFLASH_BACKGROUND_COLOR_INSIDE_BOXING_ON	   0x40
+
+#define R6_NEWSFLASH_BACKGROUND_COLOR_OUTSIDE_BOXING_OFF   0x00
+#define R6_NEWSFLASH_BACKGROUND_COLOR_OUTSIDE_BOXING_ON    0x80
+
+/* Register R7 (Display mode) */
+#define R7_BOX_OFF_ROW_0				   0x00
+#define R7_BOX_ON_ROW_0					   0x01
+
+#define R7_BOX_OFF_ROW_1_TO_23				   0x00
+#define R7_BOX_ON_ROW_1_TO_23				   0x02
+
+#define R7_BOX_OFF_ROW_24				   0x00
+#define R7_BOX_ON_ROW_24				   0x04
+
+#define R7_SINGLE_HEIGHT				   0x00
+#define R7_DOUBLE_HEIGHT				   0x08
+
+#define R7_TOP_HALF					   0x00
+#define R7_BOTTOM_HALF					   0x10
+
+#define R7_REVEAL_OFF					   0x00
+#define R7_REVEAL_ON					   0x20
+
+#define R7_CURSER_OFF					   0x00
+#define R7_CURSER_ON					   0x40
+
+#define R7_STATUS_BOTTOM				   0x00
+#define R7_STATUS_TOP					   0x80
+
+/* Register R8 (Active chapter) */
+#define R8_ACTIVE_CHAPTER_0				   0x00
+#define R8_ACTIVE_CHAPTER_1				   0x01
+#define R8_ACTIVE_CHAPTER_2				   0x02
+#define R8_ACTIVE_CHAPTER_3				   0x03
+#define R8_ACTIVE_CHAPTER_4				   0x04
+#define R8_ACTIVE_CHAPTER_5				   0x05
+#define R8_ACTIVE_CHAPTER_6				   0x06
+#define R8_ACTIVE_CHAPTER_7				   0x07
+
+#define R8_CLEAR_MEMORY					   0x08
+#define R8_DO_NOT_CLEAR_MEMORY				   0x00
+
+/* Register R9 (Curser row) */
+#define R9_CURSER_ROW_0					   0x00
+#define R9_CURSER_ROW_1					   0x01
+#define R9_CURSER_ROW_2					   0x02
+#define R9_CURSER_ROW_25				   0x19
+
+/* Register R10 (Curser column) */
+#define R10_CURSER_COLUMN_0				   0x00
+#define R10_CURSER_COLUMN_6				   0x06
+#define R10_CURSER_COLUMN_8				   0x08
+
+/*****************************************************************************/
+/* Row 25 control data in column 0 to 9					     */
+/*****************************************************************************/
+#define ROW25_COLUMN0_PAGE_UNITS			   0x0F
+
+#define ROW25_COLUMN1_PAGE_TENS				   0x0F
+
+#define ROW25_COLUMN2_MINUTES_UNITS			   0x0F
+
+#define ROW25_COLUMN3_MINUTES_TENS			   0x07
+#define ROW25_COLUMN3_DELETE_PAGE			   0x08
+
+#define ROW25_COLUMN4_HOUR_UNITS			   0x0F
+
+#define ROW25_COLUMN5_HOUR_TENS				   0x03
+#define ROW25_COLUMN5_INSERT_HEADLINE			   0x04
+#define ROW25_COLUMN5_INSERT_SUBTITLE			   0x08
+
+#define ROW25_COLUMN6_SUPPRESS_HEADER			   0x01
+#define ROW25_COLUMN6_UPDATE_PAGE			   0x02
+#define ROW25_COLUMN6_INTERRUPTED_SEQUENCE		   0x04
+#define ROW25_COLUMN6_SUPPRESS_DISPLAY			   0x08
+
+#define ROW25_COLUMN7_SERIAL_MODE			   0x01
+#define ROW25_COLUMN7_CHARACTER_SET			   0x0E
+
+#define ROW25_COLUMN8_PAGE_HUNDREDS			   0x07
+#define ROW25_COLUMN8_PAGE_NOT_FOUND			   0x10
+
+#define ROW25_COLUMN9_PAGE_BEING_LOOKED_FOR		   0x20
+
+#define ROW25_COLUMN0_TO_7_HAMMING_ERROR		   0x10
+
+/*****************************************************************************/
+/* Helper macros for extracting page, hour and minute digits		     */
+/*****************************************************************************/
+/* BYTE_POS  0 is at row 0, column 0,
+   BYTE_POS  1 is at row 0, column 1,
+   BYTE_POS 40 is at row 1, column 0, (with NUM_ROWS_PER_PAGE = 40)
+   BYTE_POS 41 is at row 1, column 1, (with NUM_ROWS_PER_PAGE = 40),
+   ... */
+#define ROW(BYTE_POS)    (BYTE_POS / NUM_ROWS_PER_PAGE)
+#define COLUMN(BYTE_POS) (BYTE_POS % NUM_ROWS_PER_PAGE)
+
+/*****************************************************************************/
+/* Helper macros for extracting page, hour and minute digits		     */
+/*****************************************************************************/
+/* Macros for extracting hundreds, tens and units of a page number which
+   must be in the range 0 ... 0x799.
+   Note that page is coded in hexadecimal, i.e. 0x123 means page 123.
+   page 0x.. means page 8.. */
+#define HUNDREDS_OF_PAGE(page) (((page) / 0x100) & 0x7)
+#define TENS_OF_PAGE(page)     (((page) / 0x10)  & 0xF)
+#define UNITS_OF_PAGE(page)     ((page) & 0xF)
+
+/* Macros for extracting tens and units of a hour information which
+   must be in the range 0 ... 0x24.
+   Note that hour is coded in hexadecimal, i.e. 0x12 means 12 hours */
+#define TENS_OF_HOUR(hour)  ((hour) / 0x10)
+#define UNITS_OF_HOUR(hour) ((hour) & 0xF)
+
+/* Macros for extracting tens and units of a minute information which
+   must be in the range 0 ... 0x59.
+   Note that minute is coded in hexadecimal, i.e. 0x12 means 12 minutes */
+#define TENS_OF_MINUTE(minute)  ((minute) / 0x10)
+#define UNITS_OF_MINUTE(minute) ((minute) & 0xF)
+
+#define HOUR_MAX   0x23
+#define MINUTE_MAX 0x59
+#define PAGE_MAX   0x8FF
+
+
 struct saa5246a_device
 {
 	u8     pgbuf[NUM_DAUS][VTX_VIRTUALSIZE];
 	int    is_searching[NUM_DAUS];
 	struct i2c_client *client;
+	unsigned long in_use;
 	struct mutex lock;
 };
 
 static struct video_device saa_template;	/* Declared near bottom */
 
-/* Addresses to scan */
-static unsigned short normal_i2c[]	 = { I2C_ADDRESS, I2C_CLIENT_END };
-
-I2C_CLIENT_INSMOD;
-
-static struct i2c_client client_template;
-
-static int saa5246a_attach(struct i2c_adapter *adap, int addr, int kind)
-{
-	int pgbuf;
-	int err;
-	struct i2c_client *client;
-	struct video_device *vd;
-	struct saa5246a_device *t;
-
-	printk(KERN_INFO "saa5246a: teletext chip found.\n");
-	client=kmalloc(sizeof(*client), GFP_KERNEL);
-	if(client==NULL)
-		return -ENOMEM;
-	client_template.adapter = adap;
-	client_template.addr = addr;
-	memcpy(client, &client_template, sizeof(*client));
-	t = kzalloc(sizeof(*t), GFP_KERNEL);
-	if(t==NULL)
-	{
-		kfree(client);
-		return -ENOMEM;
-	}
-	strlcpy(client->name, IF_NAME, I2C_NAME_SIZE);
-	mutex_init(&t->lock);
-
-	/*
-	 *	Now create a video4linux device
-	 */
-
-	vd = video_device_alloc();
-	if(vd==NULL)
-	{
-		kfree(t);
-		kfree(client);
-		return -ENOMEM;
-	}
-	i2c_set_clientdata(client, vd);
-	memcpy(vd, &saa_template, sizeof(*vd));
-
-	for (pgbuf = 0; pgbuf < NUM_DAUS; pgbuf++)
-	{
-		memset(t->pgbuf[pgbuf], ' ', sizeof(t->pgbuf[0]));
-		t->is_searching[pgbuf] = false;
-	}
-	vd->priv=t;
-
-
-	/*
-	 *	Register it
-	 */
-
-	if((err=video_register_device(vd, VFL_TYPE_VTX,-1))<0)
-	{
-		kfree(t);
-		kfree(client);
-		video_device_release(vd);
-		return err;
-	}
-	t->client = client;
-	i2c_attach_client(client);
-	return 0;
-}
-
-/*
- *	We do most of the hard work when we become a device on the i2c.
- */
-static int saa5246a_probe(struct i2c_adapter *adap)
-{
-	if (adap->class & I2C_CLASS_TV_ANALOG)
-		return i2c_probe(adap, &addr_data, saa5246a_attach);
-	return 0;
-}
-
-static int saa5246a_detach(struct i2c_client *client)
-{
-	struct video_device *vd = i2c_get_clientdata(client);
-	i2c_detach_client(client);
-	video_unregister_device(vd);
-	kfree(vd->priv);
-	kfree(client);
-	return 0;
-}
-
 /*
  *	I2C interfaces
  */
 
-static struct i2c_driver i2c_driver_videotext =
-{
-	.driver = {
-		.name 	= IF_NAME,		/* name */
-	},
-	.id 		= I2C_DRIVERID_SAA5249, /* in i2c.h */
-	.attach_adapter = saa5246a_probe,
-	.detach_client  = saa5246a_detach,
-};
-
-static struct i2c_client client_template = {
-	.driver		= &i2c_driver_videotext,
-	.name		= "(unset)",
-};
-
 static int i2c_sendbuf(struct saa5246a_device *t, int reg, int count, u8 *data)
 {
 	char buf[64];
@@ -579,8 +807,8 @@
 static int do_saa5246a_ioctl(struct inode *inode, struct file *file,
 			    unsigned int cmd, void *arg)
 {
-	struct video_device *vd = video_devdata(file);
-	struct saa5246a_device *t=vd->priv;
+	struct saa5246a_device *t = video_drvdata(file);
+
 	switch(cmd)
 	{
 		case VTXIOCGETINFO:
@@ -720,8 +948,7 @@
 static int saa5246a_ioctl(struct inode *inode, struct file *file,
 			 unsigned int cmd, unsigned long arg)
 {
-	struct video_device *vd = video_devdata(file);
-	struct saa5246a_device *t = vd->priv;
+	struct saa5246a_device *t = video_drvdata(file);
 	int err;
 
 	cmd = vtx_fix_command(cmd);
@@ -733,21 +960,15 @@
 
 static int saa5246a_open(struct inode *inode, struct file *file)
 {
-	struct video_device *vd = video_devdata(file);
-	struct saa5246a_device *t = vd->priv;
-	int err;
+	struct saa5246a_device *t = video_drvdata(file);
 
-	err = video_exclusive_open(inode,file);
-	if (err < 0)
-		return err;
+	if (t->client == NULL)
+		return -ENODEV;
 
-	if (t->client==NULL) {
-		err = -ENODEV;
-		goto fail;
-	}
+	if (test_and_set_bit(0, &t->in_use))
+		return -EBUSY;
 
 	if (i2c_senddata(t, SAA5246A_REGISTER_R0,
-
 		R0_SELECT_R11 |
 		R0_PLL_TIME_CONSTANT_LONG |
 		R0_ENABLE_nODD_EVEN_OUTPUT |
@@ -773,21 +994,15 @@
 
 		COMMAND_END))
 	{
-		err = -EIO;
-		goto fail;
+		clear_bit(0, &t->in_use);
+		return -EIO;
 	}
-
 	return 0;
-
-fail:
-	video_exclusive_release(inode,file);
-	return err;
 }
 
 static int saa5246a_release(struct inode *inode, struct file *file)
 {
-	struct video_device *vd = video_devdata(file);
-	struct saa5246a_device *t = vd->priv;
+	struct saa5246a_device *t = video_drvdata(file);
 
 	/* Stop all acquisition circuits. */
 	i2c_senddata(t, SAA5246A_REGISTER_R1,
@@ -800,26 +1015,10 @@
 		R1_VCS_TO_SCS,
 
 		COMMAND_END);
-	video_exclusive_release(inode,file);
+	clear_bit(0, &t->in_use);
 	return 0;
 }
 
-static int __init init_saa_5246a (void)
-{
-	printk(KERN_INFO
-		"SAA5246A (or compatible) Teletext decoder driver version %d.%d\n",
-		MAJOR_VERSION, MINOR_VERSION);
-	return i2c_add_driver(&i2c_driver_videotext);
-}
-
-static void __exit cleanup_saa_5246a (void)
-{
-	i2c_del_driver(&i2c_driver_videotext);
-}
-
-module_init(init_saa_5246a);
-module_exit(cleanup_saa_5246a);
-
 static const struct file_operations saa_fops = {
 	.owner	 = THIS_MODULE,
 	.open	 = saa5246a_open,
@@ -830,8 +1029,79 @@
 
 static struct video_device saa_template =
 {
-	.name	  = IF_NAME,
+	.name	  = "saa5246a",
 	.fops	  = &saa_fops,
 	.release  = video_device_release,
 	.minor    = -1,
 };
+
+/* Addresses to scan */
+static unsigned short normal_i2c[] = { 0x22 >> 1, I2C_CLIENT_END };
+
+I2C_CLIENT_INSMOD;
+
+static int saa5246a_probe(struct i2c_client *client,
+			const struct i2c_device_id *id)
+{
+	int pgbuf;
+	int err;
+	struct video_device *vd;
+	struct saa5246a_device *t;
+
+	v4l_info(client, "chip found @ 0x%x (%s)\n",
+			client->addr << 1, client->adapter->name);
+	v4l_info(client, "VideoText version %d.%d\n",
+			MAJOR_VERSION, MINOR_VERSION);
+	t = kzalloc(sizeof(*t), GFP_KERNEL);
+	if (t == NULL)
+		return -ENOMEM;
+	mutex_init(&t->lock);
+
+	/* Now create a video4linux device */
+	vd = video_device_alloc();
+	if (vd == NULL) {
+		kfree(t);
+		return -ENOMEM;
+	}
+	i2c_set_clientdata(client, vd);
+	memcpy(vd, &saa_template, sizeof(*vd));
+
+	for (pgbuf = 0; pgbuf < NUM_DAUS; pgbuf++) {
+		memset(t->pgbuf[pgbuf], ' ', sizeof(t->pgbuf[0]));
+		t->is_searching[pgbuf] = false;
+	}
+	video_set_drvdata(vd, t);
+
+	/* Register it */
+	err = video_register_device(vd, VFL_TYPE_VTX, -1);
+	if (err < 0) {
+		kfree(t);
+		video_device_release(vd);
+		return err;
+	}
+	t->client = client;
+	return 0;
+}
+
+static int saa5246a_remove(struct i2c_client *client)
+{
+	struct video_device *vd = i2c_get_clientdata(client);
+
+	video_unregister_device(vd);
+	kfree(video_get_drvdata(vd));
+	return 0;
+}
+
+static const struct i2c_device_id saa5246a_id[] = {
+	{ "saa5246a", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, saa5246a_id);
+
+static struct v4l2_i2c_driver_data v4l2_i2c_data = {
+	.name = "saa5246a",
+	.driverid = I2C_DRIVERID_SAA5249,
+	.probe = saa5246a_probe,
+	.remove = saa5246a_remove,
+	.id_table = saa5246a_id,
+};
diff --git a/drivers/media/video/saa5246a.h b/drivers/media/video/saa5246a.h
deleted file mode 100644
index 64394c0..0000000
--- a/drivers/media/video/saa5246a.h
+++ /dev/null
@@ -1,359 +0,0 @@
-/*
-   Driver for the SAA5246A or SAA5281 Teletext (=Videotext) decoder chips from
-   Philips.
-
-   Copyright (C) 2004 Michael Geng (linux@MichaelGeng.de)
-
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
-   (at your option) any later version.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
- */
-#ifndef __SAA5246A_H__
-#define __SAA5246A_H__
-
-#define MAJOR_VERSION 1		/* driver major version number */
-#define MINOR_VERSION 8		/* driver minor version number */
-
-#define IF_NAME "SAA5246A"
-
-#define I2C_ADDRESS 17
-
-/* Number of DAUs = number of pages that can be searched at the same time. */
-#define NUM_DAUS 4
-
-#define NUM_ROWS_PER_PAGE 40
-
-/* first column is 0 (not 1) */
-#define POS_TIME_START 32
-#define POS_TIME_END 39
-
-#define POS_HEADER_START 7
-#define POS_HEADER_END 31
-
-/* Returns 'true' if the part of the videotext page described with req contains
-   (at least parts of) the time field */
-#define REQ_CONTAINS_TIME(p_req) \
-	((p_req)->start <= POS_TIME_END && \
-	 (p_req)->end   >= POS_TIME_START)
-
-/* Returns 'true' if the part of the videotext page described with req contains
-   (at least parts of) the page header */
-#define REQ_CONTAINS_HEADER(p_req) \
-	((p_req)->start <= POS_HEADER_END && \
-	 (p_req)->end   >= POS_HEADER_START)
-
-/*****************************************************************************/
-/* Mode register numbers of the SAA5246A				     */
-/*****************************************************************************/
-#define SAA5246A_REGISTER_R0    0
-#define SAA5246A_REGISTER_R1    1
-#define SAA5246A_REGISTER_R2    2
-#define SAA5246A_REGISTER_R3    3
-#define SAA5246A_REGISTER_R4    4
-#define SAA5246A_REGISTER_R5    5
-#define SAA5246A_REGISTER_R6    6
-#define SAA5246A_REGISTER_R7    7
-#define SAA5246A_REGISTER_R8    8
-#define SAA5246A_REGISTER_R9    9
-#define SAA5246A_REGISTER_R10  10
-#define SAA5246A_REGISTER_R11  11
-#define SAA5246A_REGISTER_R11B 11
-
-/* SAA5246A mode registers often autoincrement to the next register.
-   Therefore we use variable argument lists. The following macro indicates
-   the end of a command list. */
-#define COMMAND_END (- 1)
-
-/*****************************************************************************/
-/* Contents of the mode registers of the SAA5246A			     */
-/*****************************************************************************/
-/* Register R0 (Advanced Control) */
-#define R0_SELECT_R11					   0x00
-#define R0_SELECT_R11B					   0x01
-
-#define R0_PLL_TIME_CONSTANT_LONG			   0x00
-#define R0_PLL_TIME_CONSTANT_SHORT			   0x02
-
-#define R0_ENABLE_nODD_EVEN_OUTPUT			   0x00
-#define R0_DISABLE_nODD_EVEN_OUTPUT			   0x04
-
-#define R0_ENABLE_HDR_POLL				   0x00
-#define R0_DISABLE_HDR_POLL				   0x10
-
-#define R0_DO_NOT_FORCE_nODD_EVEN_LOW_IF_PICTURE_DISPLAYED 0x00
-#define R0_FORCE_nODD_EVEN_LOW_IF_PICTURE_DISPLAYED	   0x20
-
-#define R0_NO_FREE_RUN_PLL				   0x00
-#define R0_FREE_RUN_PLL					   0x40
-
-#define R0_NO_AUTOMATIC_FASTEXT_PROMPT			   0x00
-#define R0_AUTOMATIC_FASTEXT_PROMPT			   0x80
-
-/* Register R1 (Mode) */
-#define R1_INTERLACED_312_AND_HALF_312_AND_HALF_LINES	   0x00
-#define R1_NON_INTERLACED_312_313_LINES			   0x01
-#define R1_NON_INTERLACED_312_312_LINES			   0x02
-#define R1_FFB_LEADING_EDGE_IN_FIRST_BROAD_PULSE	   0x03
-#define R1_FFB_LEADING_EDGE_IN_SECOND_BROAD_PULSE	   0x07
-
-#define R1_DEW						   0x00
-#define R1_FULL_FIELD					   0x08
-
-#define R1_EXTENDED_PACKET_DISABLE			   0x00
-#define R1_EXTENDED_PACKET_ENABLE			   0x10
-
-#define R1_DAUS_ALL_ON					   0x00
-#define R1_DAUS_ALL_OFF					   0x20
-
-#define R1_7_BITS_PLUS_PARITY				   0x00
-#define R1_8_BITS_NO_PARITY				   0x40
-
-#define R1_VCS_TO_SCS					   0x00
-#define R1_NO_VCS_TO_SCS				   0x80
-
-/* Register R2 (Page request address) */
-#define R2_IN_R3_SELECT_PAGE_HUNDREDS			   0x00
-#define R2_IN_R3_SELECT_PAGE_TENS			   0x01
-#define R2_IN_R3_SELECT_PAGE_UNITS			   0x02
-#define R2_IN_R3_SELECT_HOURS_TENS			   0x03
-#define R2_IN_R3_SELECT_HOURS_UNITS			   0x04
-#define R2_IN_R3_SELECT_MINUTES_TENS			   0x05
-#define R2_IN_R3_SELECT_MINUTES_UNITS			   0x06
-
-#define R2_DAU_0					   0x00
-#define R2_DAU_1					   0x10
-#define R2_DAU_2					   0x20
-#define R2_DAU_3					   0x30
-
-#define R2_BANK_0					   0x00
-#define R2_BANK 1					   0x40
-
-#define R2_HAMMING_CHECK_ON				   0x80
-#define R2_HAMMING_CHECK_OFF				   0x00
-
-/* Register R3 (Page request data) */
-#define R3_PAGE_HUNDREDS_0				   0x00
-#define R3_PAGE_HUNDREDS_1				   0x01
-#define R3_PAGE_HUNDREDS_2				   0x02
-#define R3_PAGE_HUNDREDS_3				   0x03
-#define R3_PAGE_HUNDREDS_4				   0x04
-#define R3_PAGE_HUNDREDS_5				   0x05
-#define R3_PAGE_HUNDREDS_6				   0x06
-#define R3_PAGE_HUNDREDS_7				   0x07
-
-#define R3_HOLD_PAGE					   0x00
-#define R3_UPDATE_PAGE					   0x08
-
-#define R3_PAGE_HUNDREDS_DO_NOT_CARE			   0x00
-#define R3_PAGE_HUNDREDS_DO_CARE			   0x10
-
-#define R3_PAGE_TENS_DO_NOT_CARE			   0x00
-#define R3_PAGE_TENS_DO_CARE				   0x10
-
-#define R3_PAGE_UNITS_DO_NOT_CARE			   0x00
-#define R3_PAGE_UNITS_DO_CARE				   0x10
-
-#define R3_HOURS_TENS_DO_NOT_CARE			   0x00
-#define R3_HOURS_TENS_DO_CARE				   0x10
-
-#define R3_HOURS_UNITS_DO_NOT_CARE			   0x00
-#define R3_HOURS_UNITS_DO_CARE				   0x10
-
-#define R3_MINUTES_TENS_DO_NOT_CARE			   0x00
-#define R3_MINUTES_TENS_DO_CARE				   0x10
-
-#define R3_MINUTES_UNITS_DO_NOT_CARE			   0x00
-#define R3_MINUTES_UNITS_DO_CARE			   0x10
-
-/* Register R4 (Display chapter) */
-#define R4_DISPLAY_PAGE_0				   0x00
-#define R4_DISPLAY_PAGE_1				   0x01
-#define R4_DISPLAY_PAGE_2				   0x02
-#define R4_DISPLAY_PAGE_3				   0x03
-#define R4_DISPLAY_PAGE_4				   0x04
-#define R4_DISPLAY_PAGE_5				   0x05
-#define R4_DISPLAY_PAGE_6				   0x06
-#define R4_DISPLAY_PAGE_7				   0x07
-
-/* Register R5 (Normal display control) */
-#define R5_PICTURE_INSIDE_BOXING_OFF			   0x00
-#define R5_PICTURE_INSIDE_BOXING_ON			   0x01
-
-#define R5_PICTURE_OUTSIDE_BOXING_OFF			   0x00
-#define R5_PICTURE_OUTSIDE_BOXING_ON			   0x02
-
-#define R5_TEXT_INSIDE_BOXING_OFF			   0x00
-#define R5_TEXT_INSIDE_BOXING_ON			   0x04
-
-#define R5_TEXT_OUTSIDE_BOXING_OFF			   0x00
-#define R5_TEXT_OUTSIDE_BOXING_ON			   0x08
-
-#define R5_CONTRAST_REDUCTION_INSIDE_BOXING_OFF		   0x00
-#define R5_CONTRAST_REDUCTION_INSIDE_BOXING_ON		   0x10
-
-#define R5_CONTRAST_REDUCTION_OUTSIDE_BOXING_OFF	   0x00
-#define R5_CONTRAST_REDUCTION_OUTSIDE_BOXING_ON		   0x20
-
-#define R5_BACKGROUND_COLOR_INSIDE_BOXING_OFF		   0x00
-#define R5_BACKGROUND_COLOR_INSIDE_BOXING_ON		   0x40
-
-#define R5_BACKGROUND_COLOR_OUTSIDE_BOXING_OFF		   0x00
-#define R5_BACKGROUND_COLOR_OUTSIDE_BOXING_ON		   0x80
-
-/* Register R6 (Newsflash display) */
-#define R6_NEWSFLASH_PICTURE_INSIDE_BOXING_OFF		   0x00
-#define R6_NEWSFLASH_PICTURE_INSIDE_BOXING_ON		   0x01
-
-#define R6_NEWSFLASH_PICTURE_OUTSIDE_BOXING_OFF		   0x00
-#define R6_NEWSFLASH_PICTURE_OUTSIDE_BOXING_ON		   0x02
-
-#define R6_NEWSFLASH_TEXT_INSIDE_BOXING_OFF		   0x00
-#define R6_NEWSFLASH_TEXT_INSIDE_BOXING_ON		   0x04
-
-#define R6_NEWSFLASH_TEXT_OUTSIDE_BOXING_OFF		   0x00
-#define R6_NEWSFLASH_TEXT_OUTSIDE_BOXING_ON		   0x08
-
-#define R6_NEWSFLASH_CONTRAST_REDUCTION_INSIDE_BOXING_OFF  0x00
-#define R6_NEWSFLASH_CONTRAST_REDUCTION_INSIDE_BOXING_ON   0x10
-
-#define R6_NEWSFLASH_CONTRAST_REDUCTION_OUTSIDE_BOXING_OFF 0x00
-#define R6_NEWSFLASH_CONTRAST_REDUCTION_OUTSIDE_BOXING_ON  0x20
-
-#define R6_NEWSFLASH_BACKGROUND_COLOR_INSIDE_BOXING_OFF    0x00
-#define R6_NEWSFLASH_BACKGROUND_COLOR_INSIDE_BOXING_ON	   0x40
-
-#define R6_NEWSFLASH_BACKGROUND_COLOR_OUTSIDE_BOXING_OFF   0x00
-#define R6_NEWSFLASH_BACKGROUND_COLOR_OUTSIDE_BOXING_ON    0x80
-
-/* Register R7 (Display mode) */
-#define R7_BOX_OFF_ROW_0				   0x00
-#define R7_BOX_ON_ROW_0					   0x01
-
-#define R7_BOX_OFF_ROW_1_TO_23				   0x00
-#define R7_BOX_ON_ROW_1_TO_23				   0x02
-
-#define R7_BOX_OFF_ROW_24				   0x00
-#define R7_BOX_ON_ROW_24				   0x04
-
-#define R7_SINGLE_HEIGHT				   0x00
-#define R7_DOUBLE_HEIGHT				   0x08
-
-#define R7_TOP_HALF					   0x00
-#define R7_BOTTOM_HALF					   0x10
-
-#define R7_REVEAL_OFF					   0x00
-#define R7_REVEAL_ON					   0x20
-
-#define R7_CURSER_OFF					   0x00
-#define R7_CURSER_ON					   0x40
-
-#define R7_STATUS_BOTTOM				   0x00
-#define R7_STATUS_TOP					   0x80
-
-/* Register R8 (Active chapter) */
-#define R8_ACTIVE_CHAPTER_0				   0x00
-#define R8_ACTIVE_CHAPTER_1				   0x01
-#define R8_ACTIVE_CHAPTER_2				   0x02
-#define R8_ACTIVE_CHAPTER_3				   0x03
-#define R8_ACTIVE_CHAPTER_4				   0x04
-#define R8_ACTIVE_CHAPTER_5				   0x05
-#define R8_ACTIVE_CHAPTER_6				   0x06
-#define R8_ACTIVE_CHAPTER_7				   0x07
-
-#define R8_CLEAR_MEMORY					   0x08
-#define R8_DO_NOT_CLEAR_MEMORY				   0x00
-
-/* Register R9 (Curser row) */
-#define R9_CURSER_ROW_0					   0x00
-#define R9_CURSER_ROW_1					   0x01
-#define R9_CURSER_ROW_2					   0x02
-#define R9_CURSER_ROW_25				   0x19
-
-/* Register R10 (Curser column) */
-#define R10_CURSER_COLUMN_0				   0x00
-#define R10_CURSER_COLUMN_6				   0x06
-#define R10_CURSER_COLUMN_8				   0x08
-
-/*****************************************************************************/
-/* Row 25 control data in column 0 to 9					     */
-/*****************************************************************************/
-#define ROW25_COLUMN0_PAGE_UNITS			   0x0F
-
-#define ROW25_COLUMN1_PAGE_TENS				   0x0F
-
-#define ROW25_COLUMN2_MINUTES_UNITS			   0x0F
-
-#define ROW25_COLUMN3_MINUTES_TENS			   0x07
-#define ROW25_COLUMN3_DELETE_PAGE			   0x08
-
-#define ROW25_COLUMN4_HOUR_UNITS			   0x0F
-
-#define ROW25_COLUMN5_HOUR_TENS				   0x03
-#define ROW25_COLUMN5_INSERT_HEADLINE			   0x04
-#define ROW25_COLUMN5_INSERT_SUBTITLE			   0x08
-
-#define ROW25_COLUMN6_SUPPRESS_HEADER			   0x01
-#define ROW25_COLUMN6_UPDATE_PAGE			   0x02
-#define ROW25_COLUMN6_INTERRUPTED_SEQUENCE		   0x04
-#define ROW25_COLUMN6_SUPPRESS_DISPLAY			   0x08
-
-#define ROW25_COLUMN7_SERIAL_MODE			   0x01
-#define ROW25_COLUMN7_CHARACTER_SET			   0x0E
-
-#define ROW25_COLUMN8_PAGE_HUNDREDS			   0x07
-#define ROW25_COLUMN8_PAGE_NOT_FOUND			   0x10
-
-#define ROW25_COLUMN9_PAGE_BEING_LOOKED_FOR		   0x20
-
-#define ROW25_COLUMN0_TO_7_HAMMING_ERROR		   0x10
-
-/*****************************************************************************/
-/* Helper macros for extracting page, hour and minute digits		     */
-/*****************************************************************************/
-/* BYTE_POS  0 is at row 0, column 0,
-   BYTE_POS  1 is at row 0, column 1,
-   BYTE_POS 40 is at row 1, column 0, (with NUM_ROWS_PER_PAGE = 40)
-   BYTE_POS 41 is at row 1, column 1, (with NUM_ROWS_PER_PAGE = 40),
-   ... */
-#define ROW(BYTE_POS)    (BYTE_POS / NUM_ROWS_PER_PAGE)
-#define COLUMN(BYTE_POS) (BYTE_POS % NUM_ROWS_PER_PAGE)
-
-/*****************************************************************************/
-/* Helper macros for extracting page, hour and minute digits		     */
-/*****************************************************************************/
-/* Macros for extracting hundreds, tens and units of a page number which
-   must be in the range 0 ... 0x799.
-   Note that page is coded in hexadecimal, i.e. 0x123 means page 123.
-   page 0x.. means page 8.. */
-#define HUNDREDS_OF_PAGE(page) (((page) / 0x100) & 0x7)
-#define TENS_OF_PAGE(page)     (((page) / 0x10)  & 0xF)
-#define UNITS_OF_PAGE(page)     ((page) & 0xF)
-
-/* Macros for extracting tens and units of a hour information which
-   must be in the range 0 ... 0x24.
-   Note that hour is coded in hexadecimal, i.e. 0x12 means 12 hours */
-#define TENS_OF_HOUR(hour)  ((hour) / 0x10)
-#define UNITS_OF_HOUR(hour) ((hour) & 0xF)
-
-/* Macros for extracting tens and units of a minute information which
-   must be in the range 0 ... 0x59.
-   Note that minute is coded in hexadecimal, i.e. 0x12 means 12 minutes */
-#define TENS_OF_MINUTE(minute)  ((minute) / 0x10)
-#define UNITS_OF_MINUTE(minute) ((minute) & 0xF)
-
-#define HOUR_MAX   0x23
-#define MINUTE_MAX 0x59
-#define PAGE_MAX   0x8FF
-
-#endif  /* __SAA5246A_H__ */
diff --git a/drivers/media/video/saa5249.c b/drivers/media/video/saa5249.c
index 0d63973..3bb959c 100644
--- a/drivers/media/video/saa5249.c
+++ b/drivers/media/video/saa5249.c
@@ -15,8 +15,6 @@
  *
  *	Copyright (c) 1998 Richard Guenther <richard.guenther@student.uni-tuebingen.de>
  *
- * $Id: saa5249.c,v 1.1 1998/03/30 22:23:23 alan Exp $
- *
  *	Derived From
  *
  * vtx.c:
@@ -45,33 +43,28 @@
 
 #include <linux/module.h>
 #include <linux/kernel.h>
-#include <linux/sched.h>
 #include <linux/mm.h>
-#include <linux/errno.h>
-#include <linux/delay.h>
-#include <linux/ioport.h>
-#include <linux/slab.h>
 #include <linux/init.h>
-#include <stdarg.h>
 #include <linux/i2c.h>
+#include <linux/smp_lock.h>
+#include <linux/mutex.h>
+#include <linux/delay.h>
 #include <linux/videotext.h>
 #include <linux/videodev.h>
 #include <media/v4l2-common.h>
 #include <media/v4l2-ioctl.h>
-#include <linux/mutex.h>
+#include <media/v4l2-i2c-drv-legacy.h>
 
-
-#include <asm/io.h>
-#include <asm/uaccess.h>
+MODULE_AUTHOR("Michael Geng <linux@MichaelGeng.de>");
+MODULE_DESCRIPTION("Philips SAA5249 Teletext decoder driver");
+MODULE_LICENSE("GPL");
 
 #define VTX_VER_MAJ 1
 #define VTX_VER_MIN 8
 
 
-
 #define NUM_DAUS 4
 #define NUM_BUFS 8
-#define IF_NAME "SAA5249"
 
 static const int disp_modes[8][3] =
 {
@@ -109,6 +102,7 @@
 	int disp_mode;
 	int virtual_mode;
 	struct i2c_client *client;
+	unsigned long in_use;
 	struct mutex lock;
 };
 
@@ -123,125 +117,8 @@
 
 #define VTX_DEV_MINOR 0
 
-/* General defines and debugging support */
-
-#define RESCHED do { cond_resched(); } while(0)
-
 static struct video_device saa_template;	/* Declared near bottom */
 
-/* Addresses to scan */
-static unsigned short normal_i2c[] = {34>>1,I2C_CLIENT_END};
-
-I2C_CLIENT_INSMOD;
-
-static struct i2c_client client_template;
-
-static int saa5249_attach(struct i2c_adapter *adap, int addr, int kind)
-{
-	int pgbuf;
-	int err;
-	struct i2c_client *client;
-	struct video_device *vd;
-	struct saa5249_device *t;
-
-	printk(KERN_INFO "saa5249: teletext chip found.\n");
-	client=kmalloc(sizeof(*client), GFP_KERNEL);
-	if(client==NULL)
-		return -ENOMEM;
-	client_template.adapter = adap;
-	client_template.addr = addr;
-	memcpy(client, &client_template, sizeof(*client));
-	t = kzalloc(sizeof(*t), GFP_KERNEL);
-	if(t==NULL)
-	{
-		kfree(client);
-		return -ENOMEM;
-	}
-	strlcpy(client->name, IF_NAME, I2C_NAME_SIZE);
-	mutex_init(&t->lock);
-
-	/*
-	 *	Now create a video4linux device
-	 */
-
-	vd = kmalloc(sizeof(struct video_device), GFP_KERNEL);
-	if(vd==NULL)
-	{
-		kfree(t);
-		kfree(client);
-		return -ENOMEM;
-	}
-	i2c_set_clientdata(client, vd);
-	memcpy(vd, &saa_template, sizeof(*vd));
-
-	for (pgbuf = 0; pgbuf < NUM_DAUS; pgbuf++)
-	{
-		memset(t->vdau[pgbuf].pgbuf, ' ', sizeof(t->vdau[0].pgbuf));
-		memset(t->vdau[pgbuf].sregs, 0, sizeof(t->vdau[0].sregs));
-		memset(t->vdau[pgbuf].laststat, 0, sizeof(t->vdau[0].laststat));
-		t->vdau[pgbuf].expire = 0;
-		t->vdau[pgbuf].clrfound = true;
-		t->vdau[pgbuf].stopped = true;
-		t->is_searching[pgbuf] = false;
-	}
-	vd->priv=t;
-
-
-	/*
-	 *	Register it
-	 */
-
-	if((err=video_register_device(vd, VFL_TYPE_VTX,-1))<0)
-	{
-		kfree(t);
-		kfree(vd);
-		kfree(client);
-		return err;
-	}
-	t->client = client;
-	i2c_attach_client(client);
-	return 0;
-}
-
-/*
- *	We do most of the hard work when we become a device on the i2c.
- */
-
-static int saa5249_probe(struct i2c_adapter *adap)
-{
-	if (adap->class & I2C_CLASS_TV_ANALOG)
-		return i2c_probe(adap, &addr_data, saa5249_attach);
-	return 0;
-}
-
-static int saa5249_detach(struct i2c_client *client)
-{
-	struct video_device *vd = i2c_get_clientdata(client);
-	i2c_detach_client(client);
-	video_unregister_device(vd);
-	kfree(vd->priv);
-	kfree(vd);
-	kfree(client);
-	return 0;
-}
-
-/* new I2C driver support */
-
-static struct i2c_driver i2c_driver_videotext =
-{
-	.driver = {
-		.name 	= IF_NAME,		/* name */
-	},
-	.id 		= I2C_DRIVERID_SAA5249, /* in i2c.h */
-	.attach_adapter = saa5249_probe,
-	.detach_client  = saa5249_detach,
-};
-
-static struct i2c_client client_template = {
-	.driver		= &i2c_driver_videotext,
-	.name		= "(unset)",
-};
-
 /*
  *	Wait the given number of jiffies (10ms). This calls the scheduler, so the actual
  *	delay may be longer.
@@ -275,7 +152,7 @@
 	buf[0] = reg;
 	memcpy(buf+1, data, count);
 
-	if(i2c_master_send(t->client, buf, count+1)==count+1)
+	if (i2c_master_send(t->client, buf, count + 1) == count + 1)
 		return 0;
 	return -1;
 }
@@ -317,246 +194,236 @@
 			    unsigned int cmd, void *arg)
 {
 	static int virtual_mode = false;
-	struct video_device *vd = video_devdata(file);
-	struct saa5249_device *t=vd->priv;
+	struct saa5249_device *t = video_drvdata(file);
 
-	switch(cmd)
+	switch (cmd) {
+	case VTXIOCGETINFO:
 	{
-		case VTXIOCGETINFO:
-		{
-			vtx_info_t *info = arg;
-			info->version_major = VTX_VER_MAJ;
-			info->version_minor = VTX_VER_MIN;
-			info->numpages = NUM_DAUS;
-			/*info->cct_type = CCT_TYPE;*/
-			return 0;
-		}
+		vtx_info_t *info = arg;
+		info->version_major = VTX_VER_MAJ;
+		info->version_minor = VTX_VER_MIN;
+		info->numpages = NUM_DAUS;
+		/*info->cct_type = CCT_TYPE;*/
+		return 0;
+	}
 
-		case VTXIOCCLRPAGE:
-		{
-			vtx_pagereq_t *req = arg;
+	case VTXIOCCLRPAGE:
+	{
+		vtx_pagereq_t *req = arg;
 
-			if (req->pgbuf < 0 || req->pgbuf >= NUM_DAUS)
-				return -EINVAL;
-			memset(t->vdau[req->pgbuf].pgbuf, ' ', sizeof(t->vdau[0].pgbuf));
-			t->vdau[req->pgbuf].clrfound = true;
-			return 0;
-		}
+		if (req->pgbuf < 0 || req->pgbuf >= NUM_DAUS)
+			return -EINVAL;
+		memset(t->vdau[req->pgbuf].pgbuf, ' ', sizeof(t->vdau[0].pgbuf));
+		t->vdau[req->pgbuf].clrfound = true;
+		return 0;
+	}
 
-		case VTXIOCCLRFOUND:
-		{
-			vtx_pagereq_t *req = arg;
+	case VTXIOCCLRFOUND:
+	{
+		vtx_pagereq_t *req = arg;
 
-			if (req->pgbuf < 0 || req->pgbuf >= NUM_DAUS)
-				return -EINVAL;
-			t->vdau[req->pgbuf].clrfound = true;
-			return 0;
-		}
+		if (req->pgbuf < 0 || req->pgbuf >= NUM_DAUS)
+			return -EINVAL;
+		t->vdau[req->pgbuf].clrfound = true;
+		return 0;
+	}
 
-		case VTXIOCPAGEREQ:
-		{
-			vtx_pagereq_t *req = arg;
-			if (!(req->pagemask & PGMASK_PAGE))
-				req->page = 0;
-			if (!(req->pagemask & PGMASK_HOUR))
-				req->hour = 0;
-			if (!(req->pagemask & PGMASK_MINUTE))
-				req->minute = 0;
-			if (req->page < 0 || req->page > 0x8ff) /* 7FF ?? */
-				return -EINVAL;
-			req->page &= 0x7ff;
-			if (req->hour < 0 || req->hour > 0x3f || req->minute < 0 || req->minute > 0x7f ||
-				req->pagemask < 0 || req->pagemask >= PGMASK_MAX || req->pgbuf < 0 || req->pgbuf >= NUM_DAUS)
-				return -EINVAL;
-			t->vdau[req->pgbuf].sregs[0] = (req->pagemask & PG_HUND ? 0x10 : 0) | (req->page / 0x100);
-			t->vdau[req->pgbuf].sregs[1] = (req->pagemask & PG_TEN ? 0x10 : 0) | ((req->page / 0x10) & 0xf);
-			t->vdau[req->pgbuf].sregs[2] = (req->pagemask & PG_UNIT ? 0x10 : 0) | (req->page & 0xf);
-			t->vdau[req->pgbuf].sregs[3] = (req->pagemask & HR_TEN ? 0x10 : 0) | (req->hour / 0x10);
-			t->vdau[req->pgbuf].sregs[4] = (req->pagemask & HR_UNIT ? 0x10 : 0) | (req->hour & 0xf);
-			t->vdau[req->pgbuf].sregs[5] = (req->pagemask & MIN_TEN ? 0x10 : 0) | (req->minute / 0x10);
-			t->vdau[req->pgbuf].sregs[6] = (req->pagemask & MIN_UNIT ? 0x10 : 0) | (req->minute & 0xf);
-			t->vdau[req->pgbuf].stopped = false;
-			t->vdau[req->pgbuf].clrfound = true;
-			t->is_searching[req->pgbuf] = true;
-			return 0;
-		}
+	case VTXIOCPAGEREQ:
+	{
+		vtx_pagereq_t *req = arg;
+		if (!(req->pagemask & PGMASK_PAGE))
+			req->page = 0;
+		if (!(req->pagemask & PGMASK_HOUR))
+			req->hour = 0;
+		if (!(req->pagemask & PGMASK_MINUTE))
+			req->minute = 0;
+		if (req->page < 0 || req->page > 0x8ff) /* 7FF ?? */
+			return -EINVAL;
+		req->page &= 0x7ff;
+		if (req->hour < 0 || req->hour > 0x3f || req->minute < 0 || req->minute > 0x7f ||
+			req->pagemask < 0 || req->pagemask >= PGMASK_MAX || req->pgbuf < 0 || req->pgbuf >= NUM_DAUS)
+			return -EINVAL;
+		t->vdau[req->pgbuf].sregs[0] = (req->pagemask & PG_HUND ? 0x10 : 0) | (req->page / 0x100);
+		t->vdau[req->pgbuf].sregs[1] = (req->pagemask & PG_TEN ? 0x10 : 0) | ((req->page / 0x10) & 0xf);
+		t->vdau[req->pgbuf].sregs[2] = (req->pagemask & PG_UNIT ? 0x10 : 0) | (req->page & 0xf);
+		t->vdau[req->pgbuf].sregs[3] = (req->pagemask & HR_TEN ? 0x10 : 0) | (req->hour / 0x10);
+		t->vdau[req->pgbuf].sregs[4] = (req->pagemask & HR_UNIT ? 0x10 : 0) | (req->hour & 0xf);
+		t->vdau[req->pgbuf].sregs[5] = (req->pagemask & MIN_TEN ? 0x10 : 0) | (req->minute / 0x10);
+		t->vdau[req->pgbuf].sregs[6] = (req->pagemask & MIN_UNIT ? 0x10 : 0) | (req->minute & 0xf);
+		t->vdau[req->pgbuf].stopped = false;
+		t->vdau[req->pgbuf].clrfound = true;
+		t->is_searching[req->pgbuf] = true;
+		return 0;
+	}
 
-		case VTXIOCGETSTAT:
-		{
-			vtx_pagereq_t *req = arg;
-			u8 infobits[10];
-			vtx_pageinfo_t info;
-			int a;
+	case VTXIOCGETSTAT:
+	{
+		vtx_pagereq_t *req = arg;
+		u8 infobits[10];
+		vtx_pageinfo_t info;
+		int a;
 
-			if (req->pgbuf < 0 || req->pgbuf >= NUM_DAUS)
-				return -EINVAL;
-			if (!t->vdau[req->pgbuf].stopped)
-			{
-				if (i2c_senddata(t, 2, 0, -1) ||
-					i2c_sendbuf(t, 3, sizeof(t->vdau[0].sregs), t->vdau[req->pgbuf].sregs) ||
-					i2c_senddata(t, 8, 0, 25, 0, ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', -1) ||
-					i2c_senddata(t, 2, 0, t->vdau[req->pgbuf].sregs[0] | 8, -1) ||
-					i2c_senddata(t, 8, 0, 25, 0, -1))
+		if (req->pgbuf < 0 || req->pgbuf >= NUM_DAUS)
+			return -EINVAL;
+		if (!t->vdau[req->pgbuf].stopped) {
+			if (i2c_senddata(t, 2, 0, -1) ||
+				i2c_sendbuf(t, 3, sizeof(t->vdau[0].sregs), t->vdau[req->pgbuf].sregs) ||
+				i2c_senddata(t, 8, 0, 25, 0, ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', -1) ||
+				i2c_senddata(t, 2, 0, t->vdau[req->pgbuf].sregs[0] | 8, -1) ||
+				i2c_senddata(t, 8, 0, 25, 0, -1))
+				return -EIO;
+			jdelay(PAGE_WAIT);
+			if (i2c_getdata(t, 10, infobits))
+				return -EIO;
+
+			if (!(infobits[8] & 0x10) && !(infobits[7] & 0xf0) &&	/* check FOUND-bit */
+				(memcmp(infobits, t->vdau[req->pgbuf].laststat, sizeof(infobits)) ||
+				time_after_eq(jiffies, t->vdau[req->pgbuf].expire)))
+			{		/* check if new page arrived */
+				if (i2c_senddata(t, 8, 0, 0, 0, -1) ||
+					i2c_getdata(t, VTX_PAGESIZE, t->vdau[req->pgbuf].pgbuf))
 					return -EIO;
-				jdelay(PAGE_WAIT);
-				if (i2c_getdata(t, 10, infobits))
-					return -EIO;
-
-				if (!(infobits[8] & 0x10) && !(infobits[7] & 0xf0) &&	/* check FOUND-bit */
-					(memcmp(infobits, t->vdau[req->pgbuf].laststat, sizeof(infobits)) ||
-					time_after_eq(jiffies, t->vdau[req->pgbuf].expire)))
-				{		/* check if new page arrived */
-					if (i2c_senddata(t, 8, 0, 0, 0, -1) ||
-						i2c_getdata(t, VTX_PAGESIZE, t->vdau[req->pgbuf].pgbuf))
+				t->vdau[req->pgbuf].expire = jiffies + PGBUF_EXPIRE;
+				memset(t->vdau[req->pgbuf].pgbuf + VTX_PAGESIZE, ' ', VTX_VIRTUALSIZE - VTX_PAGESIZE);
+				if (t->virtual_mode) {
+					/* Packet X/24 */
+					if (i2c_senddata(t, 8, 0, 0x20, 0, -1) ||
+						i2c_getdata(t, 40, t->vdau[req->pgbuf].pgbuf + VTX_PAGESIZE + 20 * 40))
 						return -EIO;
-					t->vdau[req->pgbuf].expire = jiffies + PGBUF_EXPIRE;
-					memset(t->vdau[req->pgbuf].pgbuf + VTX_PAGESIZE, ' ', VTX_VIRTUALSIZE - VTX_PAGESIZE);
-					if (t->virtual_mode)
-					{
-						/* Packet X/24 */
-						if (i2c_senddata(t, 8, 0, 0x20, 0, -1) ||
-							i2c_getdata(t, 40, t->vdau[req->pgbuf].pgbuf + VTX_PAGESIZE + 20 * 40))
-							return -EIO;
-						/* Packet X/27/0 */
-						if (i2c_senddata(t, 8, 0, 0x21, 0, -1) ||
-							i2c_getdata(t, 40, t->vdau[req->pgbuf].pgbuf + VTX_PAGESIZE + 16 * 40))
-							return -EIO;
-						/* Packet 8/30/0...8/30/15
-						 * FIXME: AFAIK, the 5249 does hamming-decoding for some bytes in packet 8/30,
-						 *        so we should undo this here.
-						 */
-						if (i2c_senddata(t, 8, 0, 0x22, 0, -1) ||
-							i2c_getdata(t, 40, t->vdau[req->pgbuf].pgbuf + VTX_PAGESIZE + 23 * 40))
-							return -EIO;
-					}
-					t->vdau[req->pgbuf].clrfound = false;
-					memcpy(t->vdau[req->pgbuf].laststat, infobits, sizeof(infobits));
+					/* Packet X/27/0 */
+					if (i2c_senddata(t, 8, 0, 0x21, 0, -1) ||
+						i2c_getdata(t, 40, t->vdau[req->pgbuf].pgbuf + VTX_PAGESIZE + 16 * 40))
+						return -EIO;
+					/* Packet 8/30/0...8/30/15
+					 * FIXME: AFAIK, the 5249 does hamming-decoding for some bytes in packet 8/30,
+					 *        so we should undo this here.
+					 */
+					if (i2c_senddata(t, 8, 0, 0x22, 0, -1) ||
+						i2c_getdata(t, 40, t->vdau[req->pgbuf].pgbuf + VTX_PAGESIZE + 23 * 40))
+						return -EIO;
 				}
-				else
-				{
-					memcpy(infobits, t->vdau[req->pgbuf].laststat, sizeof(infobits));
-				}
-			}
-			else
-			{
+				t->vdau[req->pgbuf].clrfound = false;
+				memcpy(t->vdau[req->pgbuf].laststat, infobits, sizeof(infobits));
+			} else {
 				memcpy(infobits, t->vdau[req->pgbuf].laststat, sizeof(infobits));
 			}
-
-			info.pagenum = ((infobits[8] << 8) & 0x700) | ((infobits[1] << 4) & 0xf0) | (infobits[0] & 0x0f);
-			if (info.pagenum < 0x100)
-				info.pagenum += 0x800;
-			info.hour = ((infobits[5] << 4) & 0x30) | (infobits[4] & 0x0f);
-			info.minute = ((infobits[3] << 4) & 0x70) | (infobits[2] & 0x0f);
-			info.charset = ((infobits[7] >> 1) & 7);
-			info.delete = !!(infobits[3] & 8);
-			info.headline = !!(infobits[5] & 4);
-			info.subtitle = !!(infobits[5] & 8);
-			info.supp_header = !!(infobits[6] & 1);
-			info.update = !!(infobits[6] & 2);
-			info.inter_seq = !!(infobits[6] & 4);
-			info.dis_disp = !!(infobits[6] & 8);
-			info.serial = !!(infobits[7] & 1);
-			info.notfound = !!(infobits[8] & 0x10);
-			info.pblf = !!(infobits[9] & 0x20);
-			info.hamming = 0;
-			for (a = 0; a <= 7; a++)
-			{
-				if (infobits[a] & 0xf0)
-				{
-					info.hamming = 1;
-					break;
-				}
-			}
-			if (t->vdau[req->pgbuf].clrfound)
-				info.notfound = 1;
-			if(copy_to_user(req->buffer, &info, sizeof(vtx_pageinfo_t)))
-				return -EFAULT;
-			if (!info.hamming && !info.notfound)
-			{
-				t->is_searching[req->pgbuf] = false;
-			}
-			return 0;
+		} else {
+			memcpy(infobits, t->vdau[req->pgbuf].laststat, sizeof(infobits));
 		}
 
-		case VTXIOCGETPAGE:
-		{
-			vtx_pagereq_t *req = arg;
-			int start, end;
-
-			if (req->pgbuf < 0 || req->pgbuf >= NUM_DAUS || req->start < 0 ||
-				req->start > req->end || req->end >= (virtual_mode ? VTX_VIRTUALSIZE : VTX_PAGESIZE))
-				return -EINVAL;
-			if(copy_to_user(req->buffer, &t->vdau[req->pgbuf].pgbuf[req->start], req->end - req->start + 1))
-				return -EFAULT;
-
-			 /*
-			  *	Always read the time directly from SAA5249
-			  */
-
-			if (req->start <= 39 && req->end >= 32)
-			{
-				int len;
-				char buf[16];
-				start = max(req->start, 32);
-				end = min(req->end, 39);
-				len=end-start+1;
-				if (i2c_senddata(t, 8, 0, 0, start, -1) ||
-					i2c_getdata(t, len, buf))
-					return -EIO;
-				if(copy_to_user(req->buffer+start-req->start, buf, len))
-					return -EFAULT;
+		info.pagenum = ((infobits[8] << 8) & 0x700) | ((infobits[1] << 4) & 0xf0) | (infobits[0] & 0x0f);
+		if (info.pagenum < 0x100)
+			info.pagenum += 0x800;
+		info.hour = ((infobits[5] << 4) & 0x30) | (infobits[4] & 0x0f);
+		info.minute = ((infobits[3] << 4) & 0x70) | (infobits[2] & 0x0f);
+		info.charset = ((infobits[7] >> 1) & 7);
+		info.delete = !!(infobits[3] & 8);
+		info.headline = !!(infobits[5] & 4);
+		info.subtitle = !!(infobits[5] & 8);
+		info.supp_header = !!(infobits[6] & 1);
+		info.update = !!(infobits[6] & 2);
+		info.inter_seq = !!(infobits[6] & 4);
+		info.dis_disp = !!(infobits[6] & 8);
+		info.serial = !!(infobits[7] & 1);
+		info.notfound = !!(infobits[8] & 0x10);
+		info.pblf = !!(infobits[9] & 0x20);
+		info.hamming = 0;
+		for (a = 0; a <= 7; a++) {
+			if (infobits[a] & 0xf0) {
+				info.hamming = 1;
+				break;
 			}
-			/* Insert the current header if DAU is still searching for a page */
-			if (req->start <= 31 && req->end >= 7 && t->is_searching[req->pgbuf])
-			{
-				char buf[32];
-				int len;
-				start = max(req->start, 7);
-				end = min(req->end, 31);
-				len=end-start+1;
-				if (i2c_senddata(t, 8, 0, 0, start, -1) ||
-					i2c_getdata(t, len, buf))
-					return -EIO;
-				if(copy_to_user(req->buffer+start-req->start, buf, len))
-					return -EFAULT;
-			}
-			return 0;
 		}
-
-		case VTXIOCSTOPDAU:
-		{
-			vtx_pagereq_t *req = arg;
-
-			if (req->pgbuf < 0 || req->pgbuf >= NUM_DAUS)
-				return -EINVAL;
-			t->vdau[req->pgbuf].stopped = true;
+		if (t->vdau[req->pgbuf].clrfound)
+			info.notfound = 1;
+		if (copy_to_user(req->buffer, &info, sizeof(vtx_pageinfo_t)))
+			return -EFAULT;
+		if (!info.hamming && !info.notfound)
 			t->is_searching[req->pgbuf] = false;
-			return 0;
-		}
+		return 0;
+	}
 
-		case VTXIOCPUTPAGE:
-		case VTXIOCSETDISP:
-		case VTXIOCPUTSTAT:
-			return 0;
+	case VTXIOCGETPAGE:
+	{
+		vtx_pagereq_t *req = arg;
+		int start, end;
 
-		case VTXIOCCLRCACHE:
-		{
-			if (i2c_senddata(t, 0, NUM_DAUS, 0, 8, -1) || i2c_senddata(t, 11,
-				' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',
-				' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ', -1))
+		if (req->pgbuf < 0 || req->pgbuf >= NUM_DAUS || req->start < 0 ||
+			req->start > req->end || req->end >= (virtual_mode ? VTX_VIRTUALSIZE : VTX_PAGESIZE))
+			return -EINVAL;
+		if (copy_to_user(req->buffer, &t->vdau[req->pgbuf].pgbuf[req->start], req->end - req->start + 1))
+			return -EFAULT;
+
+		 /*
+		  *	Always read the time directly from SAA5249
+		  */
+
+		if (req->start <= 39 && req->end >= 32) {
+			int len;
+			char buf[16];
+			start = max(req->start, 32);
+			end = min(req->end, 39);
+			len = end - start + 1;
+			if (i2c_senddata(t, 8, 0, 0, start, -1) ||
+				i2c_getdata(t, len, buf))
 				return -EIO;
-			if (i2c_senddata(t, 3, 0x20, -1))
-				return -EIO;
-			jdelay(10 * CLEAR_DELAY);			/* I have no idea how long we have to wait here */
-			return 0;
+			if (copy_to_user(req->buffer + start - req->start, buf, len))
+				return -EFAULT;
 		}
+		/* Insert the current header if DAU is still searching for a page */
+		if (req->start <= 31 && req->end >= 7 && t->is_searching[req->pgbuf]) {
+			char buf[32];
+			int len;
 
-		case VTXIOCSETVIRT:
-		{
-			/* The SAA5249 has virtual-row reception turned on always */
-			t->virtual_mode = (int)(long)arg;
-			return 0;
+			start = max(req->start, 7);
+			end = min(req->end, 31);
+			len = end - start + 1;
+			if (i2c_senddata(t, 8, 0, 0, start, -1) ||
+				i2c_getdata(t, len, buf))
+				return -EIO;
+			if (copy_to_user(req->buffer + start - req->start, buf, len))
+				return -EFAULT;
 		}
+		return 0;
+	}
+
+	case VTXIOCSTOPDAU:
+	{
+		vtx_pagereq_t *req = arg;
+
+		if (req->pgbuf < 0 || req->pgbuf >= NUM_DAUS)
+			return -EINVAL;
+		t->vdau[req->pgbuf].stopped = true;
+		t->is_searching[req->pgbuf] = false;
+		return 0;
+	}
+
+	case VTXIOCPUTPAGE:
+	case VTXIOCSETDISP:
+	case VTXIOCPUTSTAT:
+		return 0;
+
+	case VTXIOCCLRCACHE:
+	{
+		if (i2c_senddata(t, 0, NUM_DAUS, 0, 8, -1) || i2c_senddata(t, 11,
+			' ', ' ', ' ', ' ', ' ', ' ',
+			' ', ' ', ' ', ' ', ' ', ' ',
+			' ', ' ', ' ', ' ', ' ', ' ',
+			' ', ' ', ' ', ' ', ' ', ' ',
+			-1))
+			return -EIO;
+		if (i2c_senddata(t, 3, 0x20, -1))
+			return -EIO;
+		jdelay(10 * CLEAR_DELAY);			/* I have no idea how long we have to wait here */
+		return 0;
+	}
+
+	case VTXIOCSETVIRT:
+	{
+		/* The SAA5249 has virtual-row reception turned on always */
+		t->virtual_mode = (int)(long)arg;
+		return 0;
+	}
 	}
 	return -EINVAL;
 }
@@ -616,8 +483,7 @@
 static int saa5249_ioctl(struct inode *inode, struct file *file,
 			 unsigned int cmd, unsigned long arg)
 {
-	struct video_device *vd = video_devdata(file);
-	struct saa5249_device *t=vd->priv;
+	struct saa5249_device *t = video_drvdata(file);
 	int err;
 
 	cmd = vtx_fix_command(cmd);
@@ -629,32 +495,27 @@
 
 static int saa5249_open(struct inode *inode, struct file *file)
 {
-	struct video_device *vd = video_devdata(file);
-	struct saa5249_device *t=vd->priv;
-	int err,pgbuf;
+	struct saa5249_device *t = video_drvdata(file);
+	int pgbuf;
 
-	err = video_exclusive_open(inode,file);
-	if (err < 0)
-		return err;
+	if (t->client == NULL)
+		return -ENODEV;
 
-	if (t->client==NULL) {
-		err = -ENODEV;
-		goto fail;
-	}
+	if (test_and_set_bit(0, &t->in_use))
+		return -EBUSY;
 
-	if (i2c_senddata(t, 0, 0, -1) ||		/* Select R11 */
-						/* Turn off parity checks (we do this ourselves) */
+	if (i2c_senddata(t, 0, 0, -1) || /* Select R11 */
+		/* Turn off parity checks (we do this ourselves) */
 		i2c_senddata(t, 1, disp_modes[t->disp_mode][0], 0, -1) ||
-						/* Display TV-picture, no virtual rows */
-		i2c_senddata(t, 4, NUM_DAUS, disp_modes[t->disp_mode][1], disp_modes[t->disp_mode][2], 7, -1)) /* Set display to page 4 */
-
+		/* Display TV-picture, no virtual rows */
+		i2c_senddata(t, 4, NUM_DAUS, disp_modes[t->disp_mode][1], disp_modes[t->disp_mode][2], 7, -1))
+		/* Set display to page 4 */
 	{
-		err = -EIO;
-		goto fail;
+		clear_bit(0, &t->in_use);
+		return -EIO;
 	}
 
-	for (pgbuf = 0; pgbuf < NUM_DAUS; pgbuf++)
-	{
+	for (pgbuf = 0; pgbuf < NUM_DAUS; pgbuf++) {
 		memset(t->vdau[pgbuf].pgbuf, ' ', sizeof(t->vdau[0].pgbuf));
 		memset(t->vdau[pgbuf].sregs, 0, sizeof(t->vdau[0].sregs));
 		memset(t->vdau[pgbuf].laststat, 0, sizeof(t->vdau[0].laststat));
@@ -665,39 +526,20 @@
 	}
 	t->virtual_mode = false;
 	return 0;
-
- fail:
-	video_exclusive_release(inode,file);
-	return err;
 }
 
 
 
 static int saa5249_release(struct inode *inode, struct file *file)
 {
-	struct video_device *vd = video_devdata(file);
-	struct saa5249_device *t=vd->priv;
+	struct saa5249_device *t = video_drvdata(file);
+
 	i2c_senddata(t, 1, 0x20, -1);		/* Turn off CCT */
 	i2c_senddata(t, 5, 3, 3, -1);		/* Turn off TV-display */
-	video_exclusive_release(inode,file);
+	clear_bit(0, &t->in_use);
 	return 0;
 }
 
-static int __init init_saa_5249 (void)
-{
-	printk(KERN_INFO "SAA5249 driver (" IF_NAME " interface) for VideoText version %d.%d\n",
-			VTX_VER_MAJ, VTX_VER_MIN);
-	return i2c_add_driver(&i2c_driver_videotext);
-}
-
-static void __exit cleanup_saa_5249 (void)
-{
-	i2c_del_driver(&i2c_driver_videotext);
-}
-
-module_init(init_saa_5249);
-module_exit(cleanup_saa_5249);
-
 static const struct file_operations saa_fops = {
 	.owner		= THIS_MODULE,
 	.open		= saa5249_open,
@@ -711,8 +553,84 @@
 
 static struct video_device saa_template =
 {
-	.name		= IF_NAME,
+	.name		= "saa5249",
 	.fops           = &saa_fops,
+	.release 	= video_device_release,
 };
 
-MODULE_LICENSE("GPL");
+/* Addresses to scan */
+static unsigned short normal_i2c[] = { 0x22 >> 1, I2C_CLIENT_END };
+
+I2C_CLIENT_INSMOD;
+
+static int saa5249_probe(struct i2c_client *client,
+			const struct i2c_device_id *id)
+{
+	int pgbuf;
+	int err;
+	struct video_device *vd;
+	struct saa5249_device *t;
+
+	v4l_info(client, "chip found @ 0x%x (%s)\n",
+			client->addr << 1, client->adapter->name);
+	v4l_info(client, "VideoText version %d.%d\n",
+			VTX_VER_MAJ, VTX_VER_MIN);
+	t = kzalloc(sizeof(*t), GFP_KERNEL);
+	if (t == NULL)
+		return -ENOMEM;
+	mutex_init(&t->lock);
+
+	/* Now create a video4linux device */
+	vd = kmalloc(sizeof(struct video_device), GFP_KERNEL);
+	if (vd == NULL) {
+		kfree(client);
+		return -ENOMEM;
+	}
+	i2c_set_clientdata(client, vd);
+	memcpy(vd, &saa_template, sizeof(*vd));
+
+	for (pgbuf = 0; pgbuf < NUM_DAUS; pgbuf++) {
+		memset(t->vdau[pgbuf].pgbuf, ' ', sizeof(t->vdau[0].pgbuf));
+		memset(t->vdau[pgbuf].sregs, 0, sizeof(t->vdau[0].sregs));
+		memset(t->vdau[pgbuf].laststat, 0, sizeof(t->vdau[0].laststat));
+		t->vdau[pgbuf].expire = 0;
+		t->vdau[pgbuf].clrfound = true;
+		t->vdau[pgbuf].stopped = true;
+		t->is_searching[pgbuf] = false;
+	}
+	video_set_drvdata(vd, t);
+
+	/* Register it */
+	err = video_register_device(vd, VFL_TYPE_VTX, -1);
+	if (err < 0) {
+		kfree(t);
+		kfree(vd);
+		return err;
+	}
+	t->client = client;
+	return 0;
+}
+
+static int saa5249_remove(struct i2c_client *client)
+{
+	struct video_device *vd = i2c_get_clientdata(client);
+
+	video_unregister_device(vd);
+	kfree(video_get_drvdata(vd));
+	kfree(vd);
+	return 0;
+}
+
+static const struct i2c_device_id saa5249_id[] = {
+	{ "saa5249", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, saa5249_id);
+
+static struct v4l2_i2c_driver_data v4l2_i2c_data = {
+	.name = "saa5249",
+	.driverid = I2C_DRIVERID_SAA5249,
+	.probe = saa5249_probe,
+	.remove = saa5249_remove,
+	.id_table = saa5249_id,
+};
diff --git a/drivers/media/video/saa7115.c b/drivers/media/video/saa7115.c
index ad733ca..c8e9cb3 100644
--- a/drivers/media/video/saa7115.c
+++ b/drivers/media/video/saa7115.c
@@ -1057,7 +1057,7 @@
 	for (i = 0; i <= 23; i++)
 		lcr[i] = 0xff;
 
-	if (fmt->service_set == 0) {
+	if (fmt == NULL) {
 		/* raw VBI */
 		if (is_50hz)
 			for (i = 6; i <= 23; i++)
@@ -1113,7 +1113,7 @@
 	}
 
 	/* enable/disable raw VBI capturing */
-	saa711x_writeregs(client, fmt->service_set == 0 ?
+	saa711x_writeregs(client, fmt == NULL ?
 				saa7115_cfg_vbi_on :
 				saa7115_cfg_vbi_off);
 }
@@ -1153,6 +1153,10 @@
 		saa711x_set_lcr(client, &fmt->fmt.sliced);
 		return 0;
 	}
+	if (fmt->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
+		saa711x_set_lcr(client, NULL);
+		return 0;
+	}
 	if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
 		return -EINVAL;
 
@@ -1309,10 +1313,13 @@
 	case VIDIOC_INT_S_VIDEO_ROUTING:
 	{
 		struct v4l2_routing *route = arg;
+		u32 input = route->input;
+		u8 mask = (state->ident == V4L2_IDENT_SAA7111) ? 0xf8 : 0xf0;
 
 		v4l_dbg(1, debug, client, "decoder set input %d output %d\n", route->input, route->output);
-		/* saa7113 does not have these inputs */
-		if (state->ident == V4L2_IDENT_SAA7113 &&
+		/* saa7111/3 does not have these inputs */
+		if ((state->ident == V4L2_IDENT_SAA7113 ||
+		     state->ident == V4L2_IDENT_SAA7111) &&
 		    (route->input == SAA7115_COMPOSITE4 ||
 		     route->input == SAA7115_COMPOSITE5)) {
 			return -EINVAL;
@@ -1327,10 +1334,23 @@
 			(route->input >= SAA7115_SVIDEO0) ? "S-Video" : "Composite", (route->output == SAA7115_IPORT_ON) ? "iport on" : "iport off");
 		state->input = route->input;
 
+		/* saa7111 has slightly different input numbering */
+		if (state->ident == V4L2_IDENT_SAA7111) {
+			if (input >= SAA7115_COMPOSITE4)
+				input -= 2;
+			/* saa7111 specific */
+			saa711x_write(client, R_10_CHROMA_CNTL_2,
+					(saa711x_read(client, R_10_CHROMA_CNTL_2) & 0x3f) |
+					((route->output & 0xc0) ^ 0x40));
+			saa711x_write(client, R_13_RT_X_PORT_OUT_CNTL,
+					(saa711x_read(client, R_13_RT_X_PORT_OUT_CNTL) & 0xf0) |
+					((route->output & 2) ? 0x0a : 0));
+		}
+
 		/* select mode */
 		saa711x_write(client, R_02_INPUT_CNTL_1,
-			      (saa711x_read(client, R_02_INPUT_CNTL_1) & 0xf0) |
-			       state->input);
+			      (saa711x_read(client, R_02_INPUT_CNTL_1) & mask) |
+			       input);
 
 		/* bypass chrominance trap for S-Video modes */
 		saa711x_write(client, R_09_LUMA_CNTL,
@@ -1384,6 +1404,13 @@
 		saa711x_writeregs(client, saa7115_cfg_reset_scaler);
 		break;
 
+	case VIDIOC_INT_S_GPIO:
+		if (state->ident != V4L2_IDENT_SAA7111)
+			return -EINVAL;
+		saa711x_write(client, 0x11, (saa711x_read(client, 0x11) & 0x7f) |
+			(*(u32 *)arg ? 0x80 : 0));
+		break;
+
 	case VIDIOC_INT_G_VBI_DATA:
 	{
 		struct v4l2_sliced_vbi_data *data = arg;
@@ -1539,7 +1566,8 @@
 		state->crystal_freq = SAA7115_FREQ_32_11_MHZ;
 		saa711x_writeregs(client, saa7115_init_auto_input);
 	}
-	saa711x_writeregs(client, saa7115_init_misc);
+	if (state->ident != V4L2_IDENT_SAA7111)
+		saa711x_writeregs(client, saa7115_init_misc);
 	saa711x_set_v4lstd(client, V4L2_STD_NTSC);
 
 	v4l_dbg(1, debug, client, "status: (1E) 0x%02x, (1F) 0x%02x\n",
diff --git a/drivers/media/video/saa7134/saa6752hs.c b/drivers/media/video/saa7134/saa6752hs.c
index 707be17..1fb6ecc 100644
--- a/drivers/media/video/saa7134/saa6752hs.c
+++ b/drivers/media/video/saa7134/saa6752hs.c
@@ -1,3 +1,27 @@
+ /*
+    saa6752hs - i2c-driver for the saa6752hs by Philips
+
+    Copyright (C) 2004 Andrew de Quincey
+
+    AC-3 support:
+
+    Copyright (C) 2008 Hans Verkuil <hverkuil@xs4all.nl>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License vs 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 Mvss Ave, Cambridge, MA 02139, USA.
+  */
+
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/string.h>
@@ -10,6 +34,8 @@
 #include <linux/types.h>
 #include <linux/videodev2.h>
 #include <media/v4l2-common.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-i2c-drv-legacy.h>
 #include <linux/init.h>
 #include <linux/crc32.h>
 
@@ -27,9 +53,6 @@
 MODULE_AUTHOR("Andrew de Quincey");
 MODULE_LICENSE("GPL");
 
-static struct i2c_driver driver;
-static struct i2c_client client_template;
-
 enum saa6752hs_videoformat {
 	SAA6752HS_VF_D1 = 0,    /* standard D1 video format: 720x576 */
 	SAA6752HS_VF_2_3_D1 = 1,/* 2/3D1 video format: 480x576 */
@@ -46,7 +69,9 @@
 	__u16				ts_pid_pcr;
 
 	/* audio */
-	enum v4l2_mpeg_audio_l2_bitrate au_l2_bitrate;
+	enum v4l2_mpeg_audio_encoding    au_encoding;
+	enum v4l2_mpeg_audio_l2_bitrate  au_l2_bitrate;
+	enum v4l2_mpeg_audio_ac3_bitrate au_ac3_bitrate;
 
 	/* video */
 	enum v4l2_mpeg_video_aspect	vi_aspect;
@@ -70,7 +95,9 @@
 };
 
 struct saa6752hs_state {
-	struct i2c_client             client;
+	int 			      chip;
+	u32 			      revision;
+	int 			      has_ac3;
 	struct saa6752hs_mpeg_params  params;
 	enum saa6752hs_videoformat    video_format;
 	v4l2_std_id                   standard;
@@ -145,6 +172,39 @@
 	0x00, 0x00, 0x00, 0x00 /* CRC32 */
 };
 
+static u8 PMT_AC3[] = {
+	0xc2, /* i2c register */
+	0x01, /* table number for encoder(1) */
+	0x47, /* sync */
+
+	0x40, /* transport_error_indicator(0), payload_unit_start(1), transport_priority(0) */
+	0x10, /* PMT PID (0x0010) */
+	0x10, /* transport_scrambling_control(00), adaptation_field_control(01), continuity_counter(0) */
+
+	0x00, /* PSI pointer to start of table */
+
+	0x02, /* TID (2) */
+	0xb0, 0x1a, /* section_syntax_indicator(1), section_length(26) */
+
+	0x00, 0x01, /* program_number(1) */
+
+	0xc1, /* version_number(0), current_next_indicator(1) */
+
+	0x00, 0x00, /* section_number(0), last_section_number(0) */
+
+	0xe1, 0x04, /* PCR_PID (0x0104) */
+
+	0xf0, 0x00, /* program_info_length(0) */
+
+	0x02, 0xe1, 0x00, 0xf0, 0x00, /* video stream type(2), pid */
+	0x06, 0xe1, 0x03, 0xf0, 0x03, /* audio stream type(6), pid */
+	0x6a, /* AC3 */
+	0x01, /* Descriptor_length(1) */
+	0x00, /* component_type_flag(0), bsid_flag(0), mainid_flag(0), asvc_flag(0), reserved flags(0) */
+
+	0xED, 0xDE, 0x2D, 0xF3 /* CRC32 BE */
+};
+
 static struct saa6752hs_mpeg_params param_defaults =
 {
 	.ts_pid_pmt      = 16,
@@ -157,12 +217,14 @@
 	.vi_bitrate_peak = 6000,
 	.vi_bitrate_mode = V4L2_MPEG_VIDEO_BITRATE_MODE_VBR,
 
+	.au_encoding     = V4L2_MPEG_AUDIO_ENCODING_LAYER_2,
 	.au_l2_bitrate   = V4L2_MPEG_AUDIO_L2_BITRATE_256K,
+	.au_ac3_bitrate  = V4L2_MPEG_AUDIO_AC3_BITRATE_256K,
 };
 
 /* ---------------------------------------------------------------------- */
 
-static int saa6752hs_chip_command(struct i2c_client* client,
+static int saa6752hs_chip_command(struct i2c_client *client,
 				  enum saa6752hs_command command)
 {
 	unsigned char buf[3];
@@ -229,45 +291,61 @@
 }
 
 
-static int saa6752hs_set_bitrate(struct i2c_client* client,
-				 struct saa6752hs_mpeg_params* params)
+static inline void set_reg8(struct i2c_client *client, uint8_t reg, uint8_t val)
+{
+	u8 buf[2];
+
+	buf[0] = reg;
+	buf[1] = val;
+	i2c_master_send(client, buf, 2);
+}
+
+static inline void set_reg16(struct i2c_client *client, uint8_t reg, uint16_t val)
 {
 	u8 buf[3];
+
+	buf[0] = reg;
+	buf[1] = val >> 8;
+	buf[2] = val & 0xff;
+	i2c_master_send(client, buf, 3);
+}
+
+static int saa6752hs_set_bitrate(struct i2c_client *client,
+				 struct saa6752hs_state *h)
+{
+	struct saa6752hs_mpeg_params *params = &h->params;
 	int tot_bitrate;
+	int is_384k;
 
 	/* set the bitrate mode */
-	buf[0] = 0x71;
-	buf[1] = (params->vi_bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) ? 0 : 1;
-	i2c_master_send(client, buf, 2);
+	set_reg8(client, 0x71,
+		params->vi_bitrate_mode != V4L2_MPEG_VIDEO_BITRATE_MODE_VBR);
 
 	/* set the video bitrate */
 	if (params->vi_bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) {
 		/* set the target bitrate */
-		buf[0] = 0x80;
-		buf[1] = params->vi_bitrate >> 8;
-		buf[2] = params->vi_bitrate & 0xff;
-		i2c_master_send(client, buf, 3);
+		set_reg16(client, 0x80, params->vi_bitrate);
 
 		/* set the max bitrate */
-		buf[0] = 0x81;
-		buf[1] = params->vi_bitrate_peak >> 8;
-		buf[2] = params->vi_bitrate_peak & 0xff;
-		i2c_master_send(client, buf, 3);
+		set_reg16(client, 0x81, params->vi_bitrate_peak);
 		tot_bitrate = params->vi_bitrate_peak;
 	} else {
 		/* set the target bitrate (no max bitrate for CBR) */
-		buf[0] = 0x81;
-		buf[1] = params->vi_bitrate >> 8;
-		buf[2] = params->vi_bitrate & 0xff;
-		i2c_master_send(client, buf, 3);
+		set_reg16(client, 0x81, params->vi_bitrate);
 		tot_bitrate = params->vi_bitrate;
 	}
 
+	/* set the audio encoding */
+	set_reg8(client, 0x93,
+			params->au_encoding == V4L2_MPEG_AUDIO_ENCODING_AC3);
+
 	/* set the audio bitrate */
-	buf[0] = 0x94;
-	buf[1] = (V4L2_MPEG_AUDIO_L2_BITRATE_256K == params->au_l2_bitrate) ? 0 : 1;
-	i2c_master_send(client, buf, 2);
-	tot_bitrate += (V4L2_MPEG_AUDIO_L2_BITRATE_256K == params->au_l2_bitrate) ? 256 : 384;
+	if (params->au_encoding == V4L2_MPEG_AUDIO_ENCODING_AC3)
+		is_384k = V4L2_MPEG_AUDIO_AC3_BITRATE_384K == params->au_ac3_bitrate;
+	else
+		is_384k = V4L2_MPEG_AUDIO_L2_BITRATE_384K == params->au_l2_bitrate;
+	set_reg8(client, 0x94, is_384k);
+	tot_bitrate += is_384k ? 384 : 256;
 
 	/* Note: the total max bitrate is determined by adding the video and audio
 	   bitrates together and also adding an extra 768kbit/s to stay on the
@@ -278,16 +356,12 @@
 		tot_bitrate = MPEG_TOTAL_TARGET_BITRATE_MAX;
 
 	/* set the total bitrate */
-	buf[0] = 0xb1;
-	buf[1] = tot_bitrate >> 8;
-	buf[2] = tot_bitrate & 0xff;
-	i2c_master_send(client, buf, 3);
-
+	set_reg16(client, 0xb1, tot_bitrate);
 	return 0;
 }
 
-static void saa6752hs_set_subsampling(struct i2c_client* client,
-				      struct v4l2_format* f)
+static void saa6752hs_set_subsampling(struct i2c_client *client,
+				      struct v4l2_format *f)
 {
 	struct saa6752hs_state *h = i2c_get_clientdata(client);
 	int dist_352, dist_480, dist_720;
@@ -332,7 +406,7 @@
 }
 
 
-static int handle_ctrl(struct saa6752hs_mpeg_params *params,
+static int handle_ctrl(int has_ac3, struct saa6752hs_mpeg_params *params,
 		struct v4l2_ext_control *ctrl, unsigned int cmd)
 {
 	int old = 0, new;
@@ -379,8 +453,9 @@
 			params->ts_pid_pcr = new;
 			break;
 		case V4L2_CID_MPEG_AUDIO_ENCODING:
-			old = V4L2_MPEG_AUDIO_ENCODING_LAYER_2;
-			if (set && new != old)
+			old = params->au_encoding;
+			if (set && new != V4L2_MPEG_AUDIO_ENCODING_LAYER_2 &&
+			    (!has_ac3 || new != V4L2_MPEG_AUDIO_ENCODING_AC3))
 				return -ERANGE;
 			new = old;
 			break;
@@ -395,6 +470,19 @@
 				new = V4L2_MPEG_AUDIO_L2_BITRATE_384K;
 			params->au_l2_bitrate = new;
 			break;
+		case V4L2_CID_MPEG_AUDIO_AC3_BITRATE:
+			if (!has_ac3)
+				return -EINVAL;
+			old = params->au_ac3_bitrate;
+			if (set && new != V4L2_MPEG_AUDIO_AC3_BITRATE_256K &&
+				   new != V4L2_MPEG_AUDIO_AC3_BITRATE_384K)
+				return -ERANGE;
+			if (new <= V4L2_MPEG_AUDIO_AC3_BITRATE_256K)
+				new = V4L2_MPEG_AUDIO_AC3_BITRATE_256K;
+			else
+				new = V4L2_MPEG_AUDIO_AC3_BITRATE_384K;
+			params->au_ac3_bitrate = new;
+			break;
 		case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ:
 			old = V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000;
 			if (set && new != old)
@@ -448,17 +536,19 @@
 	return 0;
 }
 
-static int saa6752hs_qctrl(struct saa6752hs_mpeg_params *params,
+static int saa6752hs_qctrl(struct saa6752hs_state *h,
 		struct v4l2_queryctrl *qctrl)
 {
+	struct saa6752hs_mpeg_params *params = &h->params;
 	int err;
 
 	switch (qctrl->id) {
 	case V4L2_CID_MPEG_AUDIO_ENCODING:
 		return v4l2_ctrl_query_fill(qctrl,
 				V4L2_MPEG_AUDIO_ENCODING_LAYER_2,
-				V4L2_MPEG_AUDIO_ENCODING_LAYER_2, 1,
-				V4L2_MPEG_AUDIO_ENCODING_LAYER_2);
+				h->has_ac3 ? V4L2_MPEG_AUDIO_ENCODING_AC3 :
+					V4L2_MPEG_AUDIO_ENCODING_LAYER_2,
+				1, V4L2_MPEG_AUDIO_ENCODING_LAYER_2);
 
 	case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
 		return v4l2_ctrl_query_fill(qctrl,
@@ -466,6 +556,14 @@
 				V4L2_MPEG_AUDIO_L2_BITRATE_384K, 1,
 				V4L2_MPEG_AUDIO_L2_BITRATE_256K);
 
+	case V4L2_CID_MPEG_AUDIO_AC3_BITRATE:
+		if (!h->has_ac3)
+			return -EINVAL;
+		return v4l2_ctrl_query_fill(qctrl,
+				V4L2_MPEG_AUDIO_AC3_BITRATE_256K,
+				V4L2_MPEG_AUDIO_AC3_BITRATE_384K, 1,
+				V4L2_MPEG_AUDIO_AC3_BITRATE_256K);
+
 	case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ:
 		return v4l2_ctrl_query_fill(qctrl,
 				V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000,
@@ -512,44 +610,57 @@
 	return -EINVAL;
 }
 
-static int saa6752hs_qmenu(struct saa6752hs_mpeg_params *params,
+static int saa6752hs_qmenu(struct saa6752hs_state *h,
 		struct v4l2_querymenu *qmenu)
 {
-	static const char *mpeg_audio_l2_bitrate[] = {
-		"",
-		"",
-		"",
-		"",
-		"",
-		"",
-		"",
-		"",
-		"",
-		"",
-		"",
-		"256 kbps",
-		"",
-		"384 kbps",
-		NULL
+	static const u32 mpeg_audio_encoding[] = {
+		V4L2_MPEG_AUDIO_ENCODING_LAYER_2,
+		V4L2_CTRL_MENU_IDS_END
+	};
+	static const u32 mpeg_audio_ac3_encoding[] = {
+		V4L2_MPEG_AUDIO_ENCODING_LAYER_2,
+		V4L2_MPEG_AUDIO_ENCODING_AC3,
+		V4L2_CTRL_MENU_IDS_END
+	};
+	static u32 mpeg_audio_l2_bitrate[] = {
+		V4L2_MPEG_AUDIO_L2_BITRATE_256K,
+		V4L2_MPEG_AUDIO_L2_BITRATE_384K,
+		V4L2_CTRL_MENU_IDS_END
+	};
+	static u32 mpeg_audio_ac3_bitrate[] = {
+		V4L2_MPEG_AUDIO_AC3_BITRATE_256K,
+		V4L2_MPEG_AUDIO_AC3_BITRATE_384K,
+		V4L2_CTRL_MENU_IDS_END
 	};
 	struct v4l2_queryctrl qctrl;
 	int err;
 
 	qctrl.id = qmenu->id;
-	err = saa6752hs_qctrl(params, &qctrl);
+	err = saa6752hs_qctrl(h, &qctrl);
 	if (err)
 		return err;
-	if (qmenu->id == V4L2_CID_MPEG_AUDIO_L2_BITRATE)
-		return v4l2_ctrl_query_menu(qmenu, &qctrl,
+	switch (qmenu->id) {
+	case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
+		return v4l2_ctrl_query_menu_valid_items(qmenu,
 				mpeg_audio_l2_bitrate);
-	return v4l2_ctrl_query_menu(qmenu, &qctrl,
-			v4l2_ctrl_get_menu(qmenu->id));
+	case V4L2_CID_MPEG_AUDIO_AC3_BITRATE:
+		if (!h->has_ac3)
+			return -EINVAL;
+		return v4l2_ctrl_query_menu_valid_items(qmenu,
+				mpeg_audio_ac3_bitrate);
+	case V4L2_CID_MPEG_AUDIO_ENCODING:
+		return v4l2_ctrl_query_menu_valid_items(qmenu,
+			h->has_ac3 ? mpeg_audio_ac3_encoding :
+				mpeg_audio_encoding);
+	}
+	return v4l2_ctrl_query_menu(qmenu, &qctrl, NULL);
 }
 
-static int saa6752hs_init(struct i2c_client* client)
+static int saa6752hs_init(struct i2c_client *client, u32 leading_null_bytes)
 {
 	unsigned char buf[9], buf2[4];
 	struct saa6752hs_state *h;
+	unsigned size;
 	u32 crc;
 	unsigned char localPAT[256];
 	unsigned char localPMT[256];
@@ -557,45 +668,31 @@
 	h = i2c_get_clientdata(client);
 
 	/* Set video format - must be done first as it resets other settings */
-	buf[0] = 0x41;
-	buf[1] = h->video_format;
-	i2c_master_send(client, buf, 2);
+	set_reg8(client, 0x41, h->video_format);
 
 	/* Set number of lines in input signal */
-	buf[0] = 0x40;
-	buf[1] = 0x00;
-	if (h->standard & V4L2_STD_525_60)
-		buf[1] = 0x01;
-	i2c_master_send(client, buf, 2);
+	set_reg8(client, 0x40, (h->standard & V4L2_STD_525_60) ? 1 : 0);
 
 	/* set bitrate */
-	saa6752hs_set_bitrate(client, &h->params);
+	saa6752hs_set_bitrate(client, h);
 
 	/* Set GOP structure {3, 13} */
-	buf[0] = 0x72;
-	buf[1] = 0x03;
-	buf[2] = 0x0D;
-	i2c_master_send(client,buf,3);
+	set_reg16(client, 0x72, 0x030d);
 
 	/* Set minimum Q-scale {4} */
-	buf[0] = 0x82;
-	buf[1] = 0x04;
-	i2c_master_send(client,buf,2);
+	set_reg8(client, 0x82, 0x04);
 
 	/* Set maximum Q-scale {12} */
-	buf[0] = 0x83;
-	buf[1] = 0x0C;
-	i2c_master_send(client,buf,2);
+	set_reg8(client, 0x83, 0x0c);
 
 	/* Set Output Protocol */
-	buf[0] = 0xD0;
-	buf[1] = 0x81;
-	i2c_master_send(client,buf,2);
+	set_reg8(client, 0xd0, 0x81);
 
 	/* Set video output stream format {TS} */
-	buf[0] = 0xB0;
-	buf[1] = 0x05;
-	i2c_master_send(client,buf,2);
+	set_reg8(client, 0xb0, 0x05);
+
+	/* Set leading null byte for TS */
+	set_reg16(client, 0xf6, leading_null_bytes);
 
 	/* compute PAT */
 	memcpy(localPAT, PAT, sizeof(PAT));
@@ -608,7 +705,13 @@
 	localPAT[sizeof(PAT) - 1] = crc & 0xFF;
 
 	/* compute PMT */
-	memcpy(localPMT, PMT, sizeof(PMT));
+	if (h->params.au_encoding == V4L2_MPEG_AUDIO_ENCODING_AC3) {
+		size = sizeof(PMT_AC3);
+		memcpy(localPMT, PMT_AC3, size);
+	} else {
+		size = sizeof(PMT);
+		memcpy(localPMT, PMT, size);
+	}
 	localPMT[3] = 0x40 | ((h->params.ts_pid_pmt >> 8) & 0x0f);
 	localPMT[4] = h->params.ts_pid_pmt & 0xff;
 	localPMT[15] = 0xE0 | ((h->params.ts_pid_pcr >> 8) & 0x0F);
@@ -617,40 +720,28 @@
 	localPMT[21] = h->params.ts_pid_video & 0xFF;
 	localPMT[25] = 0xE0 | ((h->params.ts_pid_audio >> 8) & 0x0F);
 	localPMT[26] = h->params.ts_pid_audio & 0xFF;
-	crc = crc32_be(~0, &localPMT[7], sizeof(PMT) - 7 - 4);
-	localPMT[sizeof(PMT) - 4] = (crc >> 24) & 0xFF;
-	localPMT[sizeof(PMT) - 3] = (crc >> 16) & 0xFF;
-	localPMT[sizeof(PMT) - 2] = (crc >> 8) & 0xFF;
-	localPMT[sizeof(PMT) - 1] = crc & 0xFF;
+	crc = crc32_be(~0, &localPMT[7], size - 7 - 4);
+	localPMT[size - 4] = (crc >> 24) & 0xFF;
+	localPMT[size - 3] = (crc >> 16) & 0xFF;
+	localPMT[size - 2] = (crc >> 8) & 0xFF;
+	localPMT[size - 1] = crc & 0xFF;
 
 	/* Set Audio PID */
-	buf[0] = 0xC1;
-	buf[1] = (h->params.ts_pid_audio >> 8) & 0xFF;
-	buf[2] = h->params.ts_pid_audio & 0xFF;
-	i2c_master_send(client,buf,3);
+	set_reg16(client, 0xc1, h->params.ts_pid_audio);
 
 	/* Set Video PID */
-	buf[0] = 0xC0;
-	buf[1] = (h->params.ts_pid_video >> 8) & 0xFF;
-	buf[2] = h->params.ts_pid_video & 0xFF;
-	i2c_master_send(client,buf,3);
+	set_reg16(client, 0xc0, h->params.ts_pid_video);
 
 	/* Set PCR PID */
-	buf[0] = 0xC4;
-	buf[1] = (h->params.ts_pid_pcr >> 8) & 0xFF;
-	buf[2] = h->params.ts_pid_pcr & 0xFF;
-	i2c_master_send(client,buf,3);
+	set_reg16(client, 0xc4, h->params.ts_pid_pcr);
 
 	/* Send SI tables */
-	i2c_master_send(client,localPAT,sizeof(PAT));
-	i2c_master_send(client,localPMT,sizeof(PMT));
+	i2c_master_send(client, localPAT, sizeof(PAT));
+	i2c_master_send(client, localPMT, size);
 
 	/* mute then unmute audio. This removes buzzing artefacts */
-	buf[0] = 0xa4;
-	buf[1] = 1;
-	i2c_master_send(client, buf, 2);
-	buf[1] = 0;
-	i2c_master_send(client, buf, 2);
+	set_reg8(client, 0xa4, 1);
+	set_reg8(client, 0xa4, 0);
 
 	/* start it going */
 	saa6752hs_chip_command(client, SAA6752HS_COMMAND_START);
@@ -688,45 +779,6 @@
 	return 0;
 }
 
-static int saa6752hs_attach(struct i2c_adapter *adap, int addr, int kind)
-{
-	struct saa6752hs_state *h;
-
-
-	if (NULL == (h = kzalloc(sizeof(*h), GFP_KERNEL)))
-		return -ENOMEM;
-	h->client = client_template;
-	h->params = param_defaults;
-	h->client.adapter = adap;
-	h->client.addr = addr;
-
-	/* Assume 625 input lines */
-	h->standard = 0;
-
-	i2c_set_clientdata(&h->client, h);
-	i2c_attach_client(&h->client);
-
-	v4l_info(&h->client,"saa6752hs: chip found @ 0x%x\n", addr<<1);
-	return 0;
-}
-
-static int saa6752hs_probe(struct i2c_adapter *adap)
-{
-	if (adap->class & I2C_CLASS_TV_ANALOG)
-		return i2c_probe(adap, &addr_data, saa6752hs_attach);
-	return 0;
-}
-
-static int saa6752hs_detach(struct i2c_client *client)
-{
-	struct saa6752hs_state *h;
-
-	h = i2c_get_clientdata(client);
-	i2c_detach_client(client);
-	kfree(h);
-	return 0;
-}
-
 static int
 saa6752hs_command(struct i2c_client *client, unsigned int cmd, void *arg)
 {
@@ -737,14 +789,13 @@
 	int i;
 
 	switch (cmd) {
+	case VIDIOC_INT_INIT:
+		/* apply settings and start encoder */
+		saa6752hs_init(client, *(u32 *)arg);
+		break;
 	case VIDIOC_S_EXT_CTRLS:
 		if (ctrls->ctrl_class != V4L2_CTRL_CLASS_MPEG)
 			return -EINVAL;
-		if (ctrls->count == 0) {
-			/* apply settings and start encoder */
-			saa6752hs_init(client);
-			break;
-		}
 		/* fall through */
 	case VIDIOC_TRY_EXT_CTRLS:
 	case VIDIOC_G_EXT_CTRLS:
@@ -752,7 +803,8 @@
 			return -EINVAL;
 		params = h->params;
 		for (i = 0; i < ctrls->count; i++) {
-			if ((err = handle_ctrl(&params, ctrls->controls + i, cmd))) {
+			err = handle_ctrl(h->has_ac3, &params, ctrls->controls + i, cmd);
+			if (err) {
 				ctrls->error_idx = i;
 				return err;
 			}
@@ -760,9 +812,9 @@
 		h->params = params;
 		break;
 	case VIDIOC_QUERYCTRL:
-		return saa6752hs_qctrl(&h->params, arg);
+		return saa6752hs_qctrl(h, arg);
 	case VIDIOC_QUERYMENU:
-		return saa6752hs_qmenu(&h->params, arg);
+		return saa6752hs_qmenu(h, arg);
 	case VIDIOC_G_FMT:
 	{
 	   struct v4l2_format *f = arg;
@@ -785,6 +837,11 @@
 	case VIDIOC_S_STD:
 		h->standard = *((v4l2_std_id *) arg);
 		break;
+
+	case VIDIOC_G_CHIP_IDENT:
+		return v4l2_chip_ident_i2c_client(client,
+				arg, h->chip, h->revision);
+
 	default:
 		/* nothing */
 		break;
@@ -793,36 +850,55 @@
 	return err;
 }
 
-/* ----------------------------------------------------------------------- */
-
-static struct i2c_driver driver = {
-	.driver = {
-		.name   = "saa6752hs",
-	},
-	.id             = I2C_DRIVERID_SAA6752HS,
-	.attach_adapter = saa6752hs_probe,
-	.detach_client  = saa6752hs_detach,
-	.command        = saa6752hs_command,
-};
-
-static struct i2c_client client_template =
+static int saa6752hs_probe(struct i2c_client *client,
+			const struct i2c_device_id *id)
 {
-	.name       = "saa6752hs",
-	.driver     = &driver,
-};
+	struct saa6752hs_state *h = kzalloc(sizeof(*h), GFP_KERNEL);
+	u8 addr = 0x13;
+	u8 data[12];
 
-static int __init saa6752hs_init_module(void)
-{
-	return i2c_add_driver(&driver);
+	v4l_info(client, "chip found @ 0x%x (%s)\n",
+			client->addr << 1, client->adapter->name);
+	if (h == NULL)
+		return -ENOMEM;
+
+	i2c_master_send(client, &addr, 1);
+	i2c_master_recv(client, data, sizeof(data));
+	h->chip = V4L2_IDENT_SAA6752HS;
+	h->revision = (data[8] << 8) | data[9];
+	h->has_ac3 = 0;
+	if (h->revision == 0x0206) {
+		h->chip = V4L2_IDENT_SAA6752HS_AC3;
+		h->has_ac3 = 1;
+		v4l_info(client, "support AC-3\n");
+	}
+	h->params = param_defaults;
+	h->standard = 0; /* Assume 625 input lines */
+
+	i2c_set_clientdata(client, h);
+	return 0;
 }
 
-static void __exit saa6752hs_cleanup_module(void)
+static int saa6752hs_remove(struct i2c_client *client)
 {
-	i2c_del_driver(&driver);
+	kfree(i2c_get_clientdata(client));
+	return 0;
 }
 
-module_init(saa6752hs_init_module);
-module_exit(saa6752hs_cleanup_module);
+static const struct i2c_device_id saa6752hs_id[] = {
+	{ "saa6752hs", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, saa6752hs_id);
+
+static struct v4l2_i2c_driver_data v4l2_i2c_data = {
+	.name = "saa6752hs",
+	.driverid = I2C_DRIVERID_SAA6752HS,
+	.command = saa6752hs_command,
+	.probe = saa6752hs_probe,
+	.remove = saa6752hs_remove,
+	.id_table = saa6752hs_id,
+};
 
 /*
  * Overrides for Emacs so that we follow Linus's tabbing style.
diff --git a/drivers/media/video/saa7134/saa7134-alsa.c b/drivers/media/video/saa7134/saa7134-alsa.c
index 9929d20..26194a0 100644
--- a/drivers/media/video/saa7134/saa7134-alsa.c
+++ b/drivers/media/video/saa7134/saa7134-alsa.c
@@ -488,10 +488,12 @@
 	period_size = params_period_bytes(hw_params);
 	periods = params_periods(hw_params);
 
-	snd_assert(period_size >= 0x100 && period_size <= 0x10000,
-		   return -EINVAL);
-	snd_assert(periods >= 4, return -EINVAL);
-	snd_assert(period_size * periods <= 1024 * 1024, return -EINVAL);
+	if (period_size < 0x100 || period_size > 0x10000)
+		return -EINVAL;
+	if (periods < 4)
+		return -EINVAL;
+	if (period_size * periods > 1024 * 1024)
+		return -EINVAL;
 
 	dev = saa7134->dev;
 
@@ -942,7 +944,8 @@
 	unsigned int idx;
 	int err;
 
-	snd_assert(chip != NULL, return -EINVAL);
+	if (snd_BUG_ON(!chip))
+		return -EINVAL;
 	strcpy(card->mixername, "SAA7134 Mixer");
 
 	for (idx = 0; idx < ARRAY_SIZE(snd_saa7134_controls); idx++) {
diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c
index 98364d1..ddc5402 100644
--- a/drivers/media/video/saa7134/saa7134-cards.c
+++ b/drivers/media/video/saa7134/saa7134-cards.c
@@ -3260,6 +3260,7 @@
 	},
 	[SAA7134_BOARD_HAUPPAUGE_HVR1110] = {
 		/* Thomas Genty <tomlohave@gmail.com> */
+		/* David Bentham <db260179@hotmail.com> */
 		.name           = "Hauppauge WinTV-HVR1110 DVB-T/Hybrid",
 		.audio_clock    = 0x00187de7,
 		.tuner_type     = TUNER_PHILIPS_TDA8290,
@@ -3268,23 +3269,26 @@
 		.radio_addr     = ADDR_UNSET,
 		.tuner_config   = 1,
 		.mpeg           = SAA7134_MPEG_DVB,
+		.gpiomask       = 0x0200100,
 		.inputs         = {{
 			.name = name_tv,
 			.vmux = 1,
 			.amux = TV,
 			.tv   = 1,
-		},{
-			.name   = name_comp1,
-			.vmux   = 3,
-			.amux   = LINE2, /* FIXME: audio doesn't work on svideo/composite */
-		},{
-			.name   = name_svideo,
-			.vmux   = 8,
-			.amux   = LINE2, /* FIXME: audio doesn't work on svideo/composite */
-		}},
+			.gpio = 0x0000100,
+		}, {
+			.name = name_comp1,
+			.vmux = 3,
+			.amux = LINE1,
+		}, {
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE1,
+		} },
 		.radio = {
 			.name = name_radio,
-			.amux   = TV,
+			.amux = TV,
+			.gpio = 0x0200100,
 		},
 	},
 	[SAA7134_BOARD_CINERGY_HT_PCMCIA] = {
@@ -3388,6 +3392,42 @@
 			.amux = 0,
 		},
 	},
+	[SAA7134_BOARD_ENCORE_ENLTV_FM53] = {
+		.name           = "Encore ENLTV-FM v5.3",
+		.audio_clock    = 0x00200000,
+		.tuner_type     = TUNER_TNF_5335MF,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.gpiomask	= 0x7000,
+		.inputs         = { {
+			.name = name_tv,
+			.vmux = 1,
+			.amux = 1,
+			.tv   = 1,
+			.gpio = 0x50000,
+		}, {
+			.name = name_comp1,
+			.vmux = 3,
+			.amux = 2,
+			.gpio = 0x2000,
+		}, {
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = 2,
+			.gpio = 0x2000,
+		} },
+		.radio = {
+			.name = name_radio,
+			.vmux = 1,
+			.amux = 1,
+		},
+		.mute = {
+			.name = name_mute,
+			.gpio = 0xf000,
+			.amux = 0,
+		},
+	},
 	[SAA7134_BOARD_CINERGY_HT_PCI] = {
 		.name           = "Terratec Cinergy HT PCI",
 		.audio_clock    = 0x00187de7,
@@ -3631,6 +3671,40 @@
 			.tv     = 1,
 		}},
 	},
+	[SAA7134_BOARD_AVERMEDIA_M135A] = {
+		.name           = "Avermedia PCI pure analog (M135A)",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_TDA8290,
+		.radio_type     = UNSET,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.tuner_config   = 2,
+		.gpiomask       = 0x020200000,
+		.inputs         = {{
+			.name = name_tv,
+			.vmux = 1,
+			.amux = TV,
+			.tv   = 1,
+		}, {
+			.name = name_comp1,
+			.vmux = 3,
+			.amux = LINE1,
+		}, {
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE1,
+		} },
+		.radio = {
+			.name = name_radio,
+			.amux = TV,
+			.gpio = 0x00200000,
+		},
+		.mute = {
+			.name = name_mute,
+			.amux = TV,
+			.gpio = 0x01,
+		},
+	},
 	[SAA7134_BOARD_BEHOLD_401] = {
 		/*       Beholder Intl. Ltd. 2008      */
 		/*Dmitry Belimov <d.belimov@gmail.com> */
@@ -4409,6 +4483,129 @@
 		/* no DVB support for now */
 		/* .mpeg           = SAA7134_MPEG_DVB, */
 	},
+	[SAA7134_BOARD_ASUSTeK_TIGER_3IN1] = {
+		.name           = "Asus Tiger 3in1",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_TDA8290,
+		.radio_type     = UNSET,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.tuner_config   = 2,
+		.gpiomask       = 1 << 21,
+		.mpeg           = SAA7134_MPEG_DVB,
+		.inputs         = {{
+			.name = name_tv,
+			.vmux = 1,
+			.amux = TV,
+			.tv   = 1,
+		}, {
+			.name = name_comp,
+			.vmux = 0,
+			.amux = LINE2,
+		}, {
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE2,
+		} },
+		.radio = {
+			.name = name_radio,
+			.amux = TV,
+			.gpio = 0x0200000,
+		},
+	},
+	[SAA7134_BOARD_REAL_ANGEL_220] = {
+		.name           = "Zogis Real Angel 220",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_TNF_5335MF,
+		.radio_type     = UNSET,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.gpiomask       = 0x801a8087,
+		.inputs = { {
+			.name   = name_tv,
+			.vmux   = 3,
+			.amux   = LINE2,
+			.tv     = 1,
+			.gpio   = 0x624000,
+		}, {
+			.name   = name_comp1,
+			.vmux   = 1,
+			.amux   = LINE1,
+			.gpio   = 0x624000,
+		}, {
+			.name   = name_svideo,
+			.vmux   = 1,
+			.amux   = LINE1,
+			.gpio   = 0x624000,
+		} },
+		.radio = {
+			.name   = name_radio,
+			.amux   = LINE2,
+			.gpio   = 0x624001,
+		},
+		.mute = {
+			.name = name_mute,
+			.amux = TV,
+		},
+	},
+	[SAA7134_BOARD_ADS_INSTANT_HDTV_PCI] = {
+		.name           = "ADS Tech Instant HDTV",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_TUV1236D,
+		.radio_type     = UNSET,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.tda9887_conf   = TDA9887_PRESENT,
+		.mpeg           = SAA7134_MPEG_DVB,
+		.inputs         = { {
+			.name = name_tv,
+			.vmux = 1,
+			.amux = TV,
+			.tv   = 1,
+		}, {
+			.name = name_comp,
+			.vmux = 4,
+			.amux = LINE1,
+		}, {
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE1,
+		} },
+	},
+	[SAA7134_BOARD_ASUSTeK_TIGER] = {
+		.name           = "Asus Tiger Rev:1.00",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_TDA8290,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.tuner_config   = 0,
+		.mpeg           = SAA7134_MPEG_DVB,
+		.gpiomask       = 0x0200000,
+		.inputs = { {
+			.name   = name_tv,
+			.vmux   = 1,
+			.amux   = TV,
+			.tv     = 1,
+		}, {
+			.name   = name_comp1,
+			.vmux   = 3,
+			.amux   = LINE2,
+		}, {
+			.name   = name_comp2,
+			.vmux   = 0,
+			.amux   = LINE2,
+		}, {
+			.name   = name_svideo,
+			.vmux   = 8,
+			.amux   = LINE2,
+		} },
+		.radio = {
+			.name   = name_radio,
+			.amux   = TV,
+			.gpio   = 0x0200000,
+		},
+	},
 };
 
 const unsigned int saa7134_bcount = ARRAY_SIZE(saa7134_boards);
@@ -4777,6 +4974,12 @@
 
 	},{
 		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x1461, /* Avermedia Technologies Inc */
+		.subdevice    = 0xf11d,
+		.driver_data  = SAA7134_BOARD_AVERMEDIA_M135A,
+	}, {
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
 		.device       = PCI_DEVICE_ID_PHILIPS_SAA7130,
 		.subvendor    = PCI_VENDOR_ID_PHILIPS,
 		.subdevice    = 0x2004,
@@ -5157,6 +5360,12 @@
 		.driver_data  = SAA7134_BOARD_ENCORE_ENLTV_FM,
 	},{
 		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7130,
+		.subvendor    = 0x1a7f,
+		.subdevice    = 0x2008,
+		.driver_data  = SAA7134_BOARD_ENCORE_ENLTV_FM53,
+	}, {
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
 		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
 		.subvendor    = 0x153b,
 		.subdevice    = 0x1175,
@@ -5183,8 +5392,8 @@
 		.vendor       = PCI_VENDOR_ID_PHILIPS,
 		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
 		.subvendor    = 0x1043,
-		.subdevice    = 0x4857,
-		.driver_data  = SAA7134_BOARD_ASUSTeK_P7131_DUAL,
+		.subdevice    = 0x4857,		/* REV:1.00 */
+		.driver_data  = SAA7134_BOARD_ASUSTeK_TIGER,
 	},{
 		.vendor       = PCI_VENDOR_ID_PHILIPS,
 		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
@@ -5415,6 +5624,12 @@
 		.driver_data  = SAA7134_BOARD_VIDEOMATE_T750,
 	}, {
 		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133, /* SAA7135HL */
+		.subvendor    = 0x1421,
+		.subdevice    = 0x0380,
+		.driver_data  = SAA7134_BOARD_ADS_INSTANT_HDTV_PCI,
+	}, {
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
 		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
 		.subvendor    = 0x5169,
 		.subdevice    = 0x1502,
@@ -5432,6 +5647,12 @@
 		.subdevice    = 0xf636,
 		.driver_data  = SAA7134_BOARD_AVERMEDIA_M103,
 	}, {
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x1043,
+		.subdevice    = 0x4878, /* REV:1.02G */
+		.driver_data  = SAA7134_BOARD_ASUSTeK_TIGER_3IN1,
+	}, {
 		/* --- boards without eeprom + subsystem ID --- */
 		.vendor       = PCI_VENDOR_ID_PHILIPS,
 		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
@@ -5540,7 +5761,7 @@
 	return 0;
 }
 
-int saa7134_tuner_callback(void *priv, int command, int arg)
+int saa7134_tuner_callback(void *priv, int component, int command, int arg)
 {
 	struct saa7134_dev *dev = priv;
 	if (dev != NULL) {
@@ -5620,6 +5841,7 @@
 	case SAA7134_BOARD_AVERMEDIA_STUDIO_507:
 	case SAA7134_BOARD_AVERMEDIA_GO_007_FM:
 	case SAA7134_BOARD_AVERMEDIA_777:
+	case SAA7134_BOARD_AVERMEDIA_M135A:
 /*      case SAA7134_BOARD_SABRENT_SBTTVFM:  */ /* not finished yet */
 	case SAA7134_BOARD_VIDEOMATE_TV_PVR:
 	case SAA7134_BOARD_VIDEOMATE_GOLD_PLUS:
@@ -5644,6 +5866,7 @@
 	case SAA7134_BOARD_AVERMEDIA_A16AR:
 	case SAA7134_BOARD_ENCORE_ENLTV:
 	case SAA7134_BOARD_ENCORE_ENLTV_FM:
+	case SAA7134_BOARD_ENCORE_ENLTV_FM53:
 	case SAA7134_BOARD_10MOONSTVMASTER3:
 	case SAA7134_BOARD_BEHOLD_401:
 	case SAA7134_BOARD_BEHOLD_403:
@@ -5656,6 +5879,7 @@
 	case SAA7134_BOARD_BEHOLD_505FM:
 	case SAA7134_BOARD_BEHOLD_507_9FM:
 	case SAA7134_BOARD_GENIUS_TVGO_A11MCE:
+	case SAA7134_BOARD_REAL_ANGEL_220:
 		dev->has_remote = SAA7134_REMOTE_GPIO;
 		break;
 	case SAA7134_BOARD_FLYDVBS_LR300:
@@ -5745,6 +5969,7 @@
 	case SAA7134_BOARD_PINNACLE_PCTV_110i:
 	case SAA7134_BOARD_PINNACLE_PCTV_310i:
 	case SAA7134_BOARD_UPMOST_PURPLE_TV:
+	case SAA7134_BOARD_MSI_TVATANYWHERE_PLUS:
 	case SAA7134_BOARD_HAUPPAUGE_HVR1110:
 	case SAA7134_BOARD_BEHOLD_607_9FM:
 	case SAA7134_BOARD_BEHOLD_M6:
@@ -5987,6 +6212,7 @@
 	case SAA7134_BOARD_PINNACLE_PCTV_310i:
 	case SAA7134_BOARD_KWORLD_DVBT_210:
 	case SAA7134_BOARD_TEVION_DVBT_220RF:
+	case SAA7134_BOARD_ASUSTeK_TIGER:
 	case SAA7134_BOARD_ASUSTeK_P7131_DUAL:
 	case SAA7134_BOARD_ASUSTeK_P7131_HYBRID_LNA:
 	case SAA7134_BOARD_MEDION_MD8800_QUADRO:
@@ -6002,6 +6228,14 @@
 		i2c_transfer(&dev->i2c_adap, &msg, 1);
 		break;
 	}
+	case SAA7134_BOARD_ASUSTeK_TIGER_3IN1:
+	{
+		u8 data[] = { 0x3c, 0x33, 0x60};
+		struct i2c_msg msg = {.addr = 0x0b, .flags = 0, .buf = data,
+							.len = sizeof(data)};
+		i2c_transfer(&dev->i2c_adap, &msg, 1);
+		break;
+	}
 	case SAA7134_BOARD_FLYDVB_TRIO:
 	{
 		u8 data[] = { 0x3c, 0x33, 0x62};
@@ -6027,6 +6261,7 @@
 		i2c_transfer(&dev->i2c_adap, &msg, 1);
 		break;
 	}
+	case SAA7134_BOARD_ADS_INSTANT_HDTV_PCI:
 	case SAA7134_BOARD_KWORLD_ATSC110:
 	{
 		/* enable tuner */
diff --git a/drivers/media/video/saa7134/saa7134-core.c b/drivers/media/video/saa7134/saa7134-core.c
index 75d6184..b686bfa 100644
--- a/drivers/media/video/saa7134/saa7134-core.c
+++ b/drivers/media/video/saa7134/saa7134-core.c
@@ -215,7 +215,7 @@
 int saa7134_pgtable_alloc(struct pci_dev *pci, struct saa7134_pgtable *pt)
 {
 	__le32       *cpu;
-	dma_addr_t   dma_addr;
+	dma_addr_t   dma_addr = 0;
 
 	cpu = pci_alloc_consistent(pci, SAA7134_PGTABLE_SIZE, &dma_addr);
 	if (NULL == cpu)
@@ -359,32 +359,6 @@
 	spin_unlock_irqrestore(&dev->slock,flags);
 }
 
-/* resends a current buffer in queue after resume */
-
-static int saa7134_buffer_requeue(struct saa7134_dev *dev,
-				  struct saa7134_dmaqueue *q)
-{
-	struct saa7134_buf *buf, *next;
-
-	assert_spin_locked(&dev->slock);
-
-	buf  = q->curr;
-	next = buf;
-	dprintk("buffer_requeue\n");
-
-	if (!buf)
-		return 0;
-
-	dprintk("buffer_requeue : resending active buffers \n");
-
-	if (!list_empty(&q->queue))
-		next = list_entry(q->queue.next, struct saa7134_buf,
-					  vb.queue);
-	buf->activate(dev, buf, next);
-
-	return 0;
-}
-
 /* ------------------------------------------------------------------ */
 
 int saa7134_set_dmabits(struct saa7134_dev *dev)
@@ -442,9 +416,7 @@
 	/* TS capture -- dma 5 */
 	if (dev->ts_q.curr) {
 		ctrl |= SAA7134_MAIN_CTRL_TE5;
-		irq  |= SAA7134_IRQ1_INTE_RA2_3 |
-			SAA7134_IRQ1_INTE_RA2_2 |
-			SAA7134_IRQ1_INTE_RA2_1 |
+		irq  |= SAA7134_IRQ1_INTE_RA2_1 |
 			SAA7134_IRQ1_INTE_RA2_0;
 	}
 
@@ -727,6 +699,10 @@
 			irq2_mask |= SAA7134_IRQ2_INTE_GPIO18A;
 	}
 
+	if (dev->has_remote == SAA7134_REMOTE_I2C) {
+		request_module("ir-kbd-i2c");
+	}
+
 	saa_writel(SAA7134_IRQ1, 0);
 	saa_writel(SAA7134_IRQ2, irq2_mask);
 
@@ -1139,6 +1115,32 @@
 }
 
 #ifdef CONFIG_PM
+
+/* resends a current buffer in queue after resume */
+static int saa7134_buffer_requeue(struct saa7134_dev *dev,
+				  struct saa7134_dmaqueue *q)
+{
+	struct saa7134_buf *buf, *next;
+
+	assert_spin_locked(&dev->slock);
+
+	buf  = q->curr;
+	next = buf;
+	dprintk("buffer_requeue\n");
+
+	if (!buf)
+		return 0;
+
+	dprintk("buffer_requeue : resending active buffers \n");
+
+	if (!list_empty(&q->queue))
+		next = list_entry(q->queue.next, struct saa7134_buf,
+					  vb.queue);
+	buf->activate(dev, buf, next);
+
+	return 0;
+}
+
 static int saa7134_suspend(struct pci_dev *pci_dev , pm_message_t state)
 {
 
diff --git a/drivers/media/video/saa7134/saa7134-dvb.c b/drivers/media/video/saa7134/saa7134-dvb.c
index be48b9b..87c1098 100644
--- a/drivers/media/video/saa7134/saa7134-dvb.c
+++ b/drivers/media/video/saa7134/saa7134-dvb.c
@@ -553,7 +553,6 @@
 /* ------------------------------------------------------------------ */
 
 static struct tda827x_config tda827x_cfg_0 = {
-	.tuner_callback = saa7134_tuner_callback,
 	.init = philips_tda827x_tuner_init,
 	.sleep = philips_tda827x_tuner_sleep,
 	.config = 0,
@@ -561,7 +560,6 @@
 };
 
 static struct tda827x_config tda827x_cfg_1 = {
-	.tuner_callback = saa7134_tuner_callback,
 	.init = philips_tda827x_tuner_init,
 	.sleep = philips_tda827x_tuner_sleep,
 	.config = 1,
@@ -569,7 +567,6 @@
 };
 
 static struct tda827x_config tda827x_cfg_2 = {
-	.tuner_callback = saa7134_tuner_callback,
 	.init = philips_tda827x_tuner_init,
 	.sleep = philips_tda827x_tuner_sleep,
 	.config = 2,
@@ -577,7 +574,6 @@
 };
 
 static struct tda827x_config tda827x_cfg_2_sw42 = {
-	.tuner_callback = saa7134_tuner_callback,
 	.init = philips_tda827x_tuner_init,
 	.sleep = philips_tda827x_tuner_sleep,
 	.config = 2,
@@ -799,6 +795,20 @@
 	.request_firmware = philips_tda1004x_request_firmware
 };
 
+static struct tda1004x_config asus_tiger_3in1_config = {
+	.demod_address = 0x0b,
+	.invert        = 1,
+	.invert_oclk   = 0,
+	.xtal_freq     = TDA10046_XTAL_16M,
+	.agc_config    = TDA10046_AGC_TDA827X,
+	.gpio_config   = TDA10046_GP11_I,
+	.if_freq       = TDA10046_FREQ_045,
+	.i2c_gate      = 0x4b,
+	.tuner_address = 0x61,
+	.antenna_switch = 1,
+	.request_firmware = philips_tda1004x_request_firmware
+};
+
 /* ------------------------------------------------------------------
  * special case: this card uses saa713x GPIO22 for the mode switch
  */
@@ -822,7 +832,6 @@
 }
 
 static struct tda827x_config ads_duo_cfg = {
-	.tuner_callback = saa7134_tuner_callback,
 	.init = ads_duo_tuner_init,
 	.sleep = ads_duo_tuner_sleep,
 	.config = 0
@@ -1147,6 +1156,7 @@
 			dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
 				   NULL, DVB_PLL_TDHU2);
 		break;
+	case SAA7134_BOARD_ADS_INSTANT_HDTV_PCI:
 	case SAA7134_BOARD_KWORLD_ATSC110:
 		dev->dvb.frontend = dvb_attach(nxt200x_attach, &kworldatsc110,
 					       &dev->i2c_adap);
@@ -1300,6 +1310,36 @@
 						&dev->i2c_adap);
 		attach_xc3028 = 1;
 		break;
+	case SAA7134_BOARD_ASUSTeK_TIGER_3IN1:
+		if (!use_frontend) {     /* terrestrial */
+			if (configure_tda827x_fe(dev, &asus_tiger_3in1_config,
+							&tda827x_cfg_2) < 0)
+				goto dettach_frontend;
+		} else {  		/* satellite */
+			dev->dvb.frontend = dvb_attach(tda10086_attach,
+						&flydvbs, &dev->i2c_adap);
+			if (dev->dvb.frontend) {
+				if (dvb_attach(tda826x_attach,
+						dev->dvb.frontend, 0x60,
+						&dev->i2c_adap, 0) == NULL) {
+					wprintk("%s: Asus Tiger 3in1, no "
+						"tda826x found!\n", __func__);
+					goto dettach_frontend;
+				}
+				if (dvb_attach(lnbp21_attach, dev->dvb.frontend,
+						&dev->i2c_adap, 0, 0) == NULL) {
+					wprintk("%s: Asus Tiger 3in1, no lnbp21"
+						" found!\n", __func__);
+					goto dettach_frontend;
+				}
+			}
+		}
+		break;
+	case SAA7134_BOARD_ASUSTeK_TIGER:
+		if (configure_tda827x_fe(dev, &philips_tiger_config,
+					 &tda827x_cfg_0) < 0)
+			goto dettach_frontend;
+		break;
 	default:
 		wprintk("Huh? unknown DVB card?\n");
 		break;
@@ -1327,6 +1367,8 @@
 		printk(KERN_ERR "%s/dvb: frontend initialization failed\n", dev->name);
 		return -1;
 	}
+	/* define general-purpose callback pointer */
+	dev->dvb.frontend->callback = saa7134_tuner_callback;
 
 	/* register everything else */
 	ret = videobuf_dvb_register(&dev->dvb, THIS_MODULE, dev, &dev->pci->dev,
diff --git a/drivers/media/video/saa7134/saa7134-empress.c b/drivers/media/video/saa7134/saa7134-empress.c
index c0c5d75..9a8766a 100644
--- a/drivers/media/video/saa7134/saa7134-empress.c
+++ b/drivers/media/video/saa7134/saa7134-empress.c
@@ -29,6 +29,7 @@
 
 #include <media/saa6752hs.h>
 #include <media/v4l2-common.h>
+#include <media/v4l2-chip-ident.h>
 
 /* ------------------------------------------------------------------ */
 
@@ -63,10 +64,19 @@
 
 static int ts_init_encoder(struct saa7134_dev* dev)
 {
-	struct v4l2_ext_controls ctrls = { V4L2_CTRL_CLASS_MPEG, 0 };
+	u32 leading_null_bytes = 0;
 
+	/* If more cards start to need this, then this
+	   should probably be added to the card definitions. */
+	switch (dev->board) {
+	case SAA7134_BOARD_BEHOLD_M6:
+	case SAA7134_BOARD_BEHOLD_M63:
+	case SAA7134_BOARD_BEHOLD_M6_EXTRA:
+		leading_null_bytes = 1;
+		break;
+	}
 	ts_reset_encoder(dev);
-	saa7134_i2c_call_clients(dev, VIDIOC_S_EXT_CTRLS, &ctrls);
+	saa7134_i2c_call_clients(dev, VIDIOC_INT_INIT, &leading_null_bytes);
 	dev->empress_started = 1;
 	return 0;
 }
@@ -79,9 +89,11 @@
 	struct saa7134_dev *dev;
 	int err;
 
+	lock_kernel();
 	list_for_each_entry(dev, &saa7134_devlist, devlist)
 		if (dev->empress_dev && dev->empress_dev->minor == minor)
 			goto found;
+	unlock_kernel();
 	return -ENODEV;
  found:
 
@@ -103,6 +115,7 @@
 done_up:
 	mutex_unlock(&dev->empress_tsq.vb_lock);
 done:
+	unlock_kernel();
 	return err;
 }
 
@@ -290,15 +303,6 @@
 	return videobuf_streamoff(&dev->empress_tsq);
 }
 
-static int saa7134_i2c_call_saa6752(struct saa7134_dev *dev,
-					      unsigned int cmd, void *arg)
-{
-	if (dev->mpeg_i2c_client == NULL)
-		return -EINVAL;
-	return dev->mpeg_i2c_client->driver->command(dev->mpeg_i2c_client,
-								cmd, arg);
-}
-
 static int empress_s_ext_ctrls(struct file *file, void *priv,
 			       struct v4l2_ext_controls *ctrls)
 {
@@ -400,6 +404,39 @@
 	return saa7134_i2c_call_saa6752(dev, VIDIOC_QUERYMENU, c);
 }
 
+static int empress_g_chip_ident(struct file *file, void *fh,
+	       struct v4l2_chip_ident *chip)
+{
+	struct saa7134_dev *dev = file->private_data;
+
+	chip->ident = V4L2_IDENT_NONE;
+	chip->revision = 0;
+	if (dev->mpeg_i2c_client == NULL)
+		return -EINVAL;
+	if (chip->match_type == V4L2_CHIP_MATCH_I2C_DRIVER &&
+	    chip->match_chip == I2C_DRIVERID_SAA6752HS)
+		return saa7134_i2c_call_saa6752(dev, VIDIOC_G_CHIP_IDENT, chip);
+	if (chip->match_type == V4L2_CHIP_MATCH_I2C_ADDR &&
+	    chip->match_chip == dev->mpeg_i2c_client->addr)
+		return saa7134_i2c_call_saa6752(dev, VIDIOC_G_CHIP_IDENT, chip);
+	return -EINVAL;
+}
+
+static int empress_s_std(struct file *file, void *priv, v4l2_std_id *id)
+{
+	struct saa7134_dev *dev = file->private_data;
+
+	return saa7134_s_std_internal(dev, NULL, id);
+}
+
+static int empress_g_std(struct file *file, void *priv, v4l2_std_id *id)
+{
+	struct saa7134_dev *dev = file->private_data;
+
+	*id = dev->tvnorm->id;
+	return 0;
+}
+
 static const struct file_operations ts_fops =
 {
 	.owner	  = THIS_MODULE,
@@ -428,11 +465,13 @@
 	.vidioc_enum_input		= empress_enum_input,
 	.vidioc_g_input			= empress_g_input,
 	.vidioc_s_input			= empress_s_input,
-
 	.vidioc_queryctrl		= empress_queryctrl,
 	.vidioc_querymenu		= empress_querymenu,
 	.vidioc_g_ctrl			= empress_g_ctrl,
 	.vidioc_s_ctrl			= empress_s_ctrl,
+	.vidioc_g_chip_ident 		= empress_g_chip_ident,
+	.vidioc_s_std			= empress_s_std,
+	.vidioc_g_std			= empress_g_std,
 };
 
 /* ----------------------------------------------------------- */
diff --git a/drivers/media/video/saa7134/saa7134-i2c.c b/drivers/media/video/saa7134/saa7134-i2c.c
index 5f713e6..20c1b33 100644
--- a/drivers/media/video/saa7134/saa7134-i2c.c
+++ b/drivers/media/video/saa7134/saa7134-i2c.c
@@ -337,6 +337,7 @@
 		case 0x47:
 		case 0x71:
 		case 0x2d:
+		case 0x30:
 		{
 			struct IR_i2c *ir = i2c_get_clientdata(client);
 			d1printk("%s i2c IR detected (%s).\n",
@@ -427,6 +428,16 @@
 	i2c_clients_command(&dev->i2c_adap, cmd, arg);
 }
 
+int saa7134_i2c_call_saa6752(struct saa7134_dev *dev,
+					      unsigned int cmd, void *arg)
+{
+	if (dev->mpeg_i2c_client == NULL)
+		return -EINVAL;
+	return dev->mpeg_i2c_client->driver->command(dev->mpeg_i2c_client,
+								cmd, arg);
+}
+EXPORT_SYMBOL_GPL(saa7134_i2c_call_saa6752);
+
 int saa7134_i2c_register(struct saa7134_dev *dev)
 {
 	dev->i2c_adap = saa7134_adap_template;
diff --git a/drivers/media/video/saa7134/saa7134-input.c b/drivers/media/video/saa7134/saa7134-input.c
index ad08d13..c53fd5f 100644
--- a/drivers/media/video/saa7134/saa7134-input.c
+++ b/drivers/media/video/saa7134/saa7134-input.c
@@ -62,8 +62,11 @@
 #define i2cdprintk(fmt, arg...)    if (ir_debug) \
 	printk(KERN_DEBUG "%s/ir: " fmt, ir->c.name , ## arg)
 
-/** rc5 functions */
+/* Helper functions for RC5 and NEC decoding at GPIO16 or GPIO18 */
 static int saa7134_rc5_irq(struct saa7134_dev *dev);
+static int saa7134_nec_irq(struct saa7134_dev *dev);
+static void nec_task(unsigned long data);
+static void saa7134_nec_timer(unsigned long data);
 
 /* -------------------- GPIO generic keycode builder -------------------- */
 
@@ -115,6 +118,53 @@
 
 /* --------------------- Chip specific I2C key builders ----------------- */
 
+static int get_key_msi_tvanywhere_plus(struct IR_i2c *ir, u32 *ir_key,
+				       u32 *ir_raw)
+{
+	unsigned char b;
+	int gpio;
+
+	/* <dev> is needed to access GPIO. Used by the saa_readl macro. */
+	struct saa7134_dev *dev = ir->c.adapter->algo_data;
+	if (dev == NULL) {
+		dprintk("get_key_msi_tvanywhere_plus: "
+			"gir->c.adapter->algo_data is NULL!\n");
+		return -EIO;
+	}
+
+	/* rising SAA7134_GPIO_GPRESCAN reads the status */
+
+	saa_clearb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
+	saa_setb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
+
+	gpio = saa_readl(SAA7134_GPIO_GPSTATUS0 >> 2);
+
+	/* GPIO&0x40 is pulsed low when a button is pressed. Don't do
+	   I2C receive if gpio&0x40 is not low. */
+
+	if (gpio & 0x40)
+		return 0;       /* No button press */
+
+	/* GPIO says there is a button press. Get it. */
+
+	if (1 != i2c_master_recv(&ir->c, &b, 1)) {
+		i2cdprintk("read error\n");
+		return -EIO;
+	}
+
+	/* No button press */
+
+	if (b == 0xff)
+		return 0;
+
+	/* Button pressed */
+
+	dprintk("get_key_msi_tvanywhere_plus: Key = 0x%02X\n", b);
+	*ir_key = b;
+	*ir_raw = b;
+	return 1;
+}
+
 static int get_key_purpletv(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
 {
 	unsigned char b;
@@ -280,7 +330,9 @@
 {
 	struct card_ir *ir = dev->remote;
 
-	if (!ir->polling && !ir->rc5_gpio) {
+	if (ir->nec_gpio) {
+		saa7134_nec_irq(dev);
+	} else if (!ir->polling && !ir->rc5_gpio) {
 		build_key(dev);
 	} else if (ir->rc5_gpio) {
 		saa7134_rc5_irq(dev);
@@ -316,6 +368,10 @@
 		ir->addr = 0x17;
 		ir->rc5_key_timeout = ir_rc5_key_timeout;
 		ir->rc5_remote_gap = ir_rc5_remote_gap;
+	} else if (ir->nec_gpio) {
+		setup_timer(&ir->timer_keyup, saa7134_nec_timer,
+			    (unsigned long)dev);
+		tasklet_init(&ir->tlet, nec_task, (unsigned long)dev);
 	}
 }
 
@@ -335,6 +391,7 @@
 	u32 mask_keyup   = 0;
 	int polling      = 0;
 	int rc5_gpio	 = 0;
+	int nec_gpio	 = 0;
 	int ir_type      = IR_TYPE_OTHER;
 	int err;
 
@@ -391,6 +448,12 @@
 		saa_setb(SAA7134_GPIO_GPMODE0, 0x4);
 		saa_setb(SAA7134_GPIO_GPSTATUS0, 0x4);
 		break;
+	case SAA7134_BOARD_AVERMEDIA_M135A:
+		ir_codes     = ir_codes_avermedia_m135a;
+		mask_keydown = 0x0040000;
+		mask_keycode = 0x00013f;
+		nec_gpio     = 1;
+		break;
 	case SAA7134_BOARD_AVERMEDIA_777:
 	case SAA7134_BOARD_AVERMEDIA_A16AR:
 		ir_codes     = ir_codes_avermedia;
@@ -499,6 +562,12 @@
 		mask_keyup   = 0x040000;
 		polling      = 50; // ms
 		break;
+	case SAA7134_BOARD_ENCORE_ENLTV_FM53:
+		ir_codes     = ir_codes_encore_enltv_fm53;
+		mask_keydown = 0x0040000;
+		mask_keycode = 0x00007f;
+		nec_gpio = 1;
+		break;
 	case SAA7134_BOARD_10MOONSTVMASTER3:
 		ir_codes     = ir_codes_encore_enltv;
 		mask_keycode = 0x5f80000;
@@ -511,6 +580,12 @@
 		mask_keydown = 0xf00000;
 		polling = 50; /* ms */
 		break;
+	case SAA7134_BOARD_REAL_ANGEL_220:
+		ir_codes     = ir_codes_real_audio_220_32_keys;
+		mask_keycode = 0x3f00;
+		mask_keyup   = 0x4000;
+		polling = 50; /* ms */
+		break;
 	}
 	if (NULL == ir_codes) {
 		printk("%s: Oops: IR config error [card=%d]\n",
@@ -533,6 +608,7 @@
 	ir->mask_keyup   = mask_keyup;
 	ir->polling      = polling;
 	ir->rc5_gpio	 = rc5_gpio;
+	ir->nec_gpio	 = nec_gpio;
 
 	/* init input device */
 	snprintf(ir->name, sizeof(ir->name), "saa7134 IR (%s)",
@@ -612,6 +688,11 @@
 		ir->get_key   = get_key_purpletv;
 		ir->ir_codes  = ir_codes_purpletv;
 		break;
+	case SAA7134_BOARD_MSI_TVATANYWHERE_PLUS:
+		snprintf(ir->c.name, sizeof(ir->c.name), "MSI TV@nywhere Plus");
+		ir->get_key  = get_key_msi_tvanywhere_plus;
+		ir->ir_codes = ir_codes_msi_tvanywhere_plus;
+		break;
 	case SAA7134_BOARD_HAUPPAUGE_HVR1110:
 		snprintf(ir->c.name, sizeof(ir->c.name), "HVR 1110");
 		ir->get_key   = get_key_hvr1110;
@@ -675,8 +756,125 @@
 	return 1;
 }
 
-/* ----------------------------------------------------------------------
- * Local variables:
- * c-basic-offset: 8
- * End:
+
+/* On NEC protocol, One has 2.25 ms, and zero has 1.125 ms
+   The first pulse (start) has 9 + 4.5 ms
  */
+
+static void saa7134_nec_timer(unsigned long data)
+{
+	struct saa7134_dev *dev = (struct saa7134_dev *) data;
+	struct card_ir *ir = dev->remote;
+
+	dprintk("Cancel key repeat\n");
+
+	ir_input_nokey(ir->dev, &ir->ir);
+}
+
+static void nec_task(unsigned long data)
+{
+	struct saa7134_dev *dev = (struct saa7134_dev *) data;
+	struct card_ir *ir;
+	struct timeval tv;
+	int count, pulse, oldpulse, gap;
+	u32 ircode = 0, not_code = 0;
+	int ngap = 0;
+
+	if (!data) {
+		printk(KERN_ERR "saa713x/ir: Can't recover dev struct\n");
+		/* GPIO will be kept disabled */
+		return;
+	}
+
+	ir = dev->remote;
+
+	/* rising SAA7134_GPIO_GPRESCAN reads the status */
+	saa_clearb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
+	saa_setb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
+
+	oldpulse = saa_readl(SAA7134_GPIO_GPSTATUS0 >> 2) & ir->mask_keydown;
+	pulse = oldpulse;
+
+	do_gettimeofday(&tv);
+	ir->base_time = tv;
+
+	/* Decode NEC pulsecode. This code can take up to 76.5 ms to run.
+	   Unfortunately, using IRQ to decode pulse didn't work, since it uses
+	   a pulse train of 38KHz. This means one pulse on each 52 us
+	 */
+	do {
+		/* Wait until the end of pulse/space or 5 ms */
+		for (count = 0; count < 500; count++)  {
+			udelay(10);
+			/* rising SAA7134_GPIO_GPRESCAN reads the status */
+			saa_clearb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
+			saa_setb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
+			pulse = saa_readl(SAA7134_GPIO_GPSTATUS0 >> 2)
+				& ir->mask_keydown;
+			if (pulse != oldpulse)
+				break;
+		}
+
+		do_gettimeofday(&tv);
+		gap = 1000000 * (tv.tv_sec - ir->base_time.tv_sec) +
+				tv.tv_usec - ir->base_time.tv_usec;
+
+		if (!pulse) {
+			/* Bit 0 has 560 us, while bit 1 has 1120 us.
+			   Do something only if bit == 1
+			 */
+			if (ngap && (gap > 560 + 280)) {
+				unsigned int shift = ngap - 1;
+
+				/* Address first, then command */
+				if (shift < 8) {
+					shift += 8;
+					ircode |= 1 << shift;
+				} else if (shift < 16) {
+					not_code |= 1 << shift;
+				} else if (shift < 24) {
+					shift -= 16;
+					ircode |= 1 << shift;
+				} else {
+					shift -= 24;
+					not_code |= 1 << shift;
+				}
+			}
+			ngap++;
+		}
+
+
+		ir->base_time = tv;
+
+		/* TIMEOUT - Long pulse */
+		if (gap >= 5000)
+			break;
+		oldpulse = pulse;
+	} while (ngap < 32);
+
+	if (ngap == 32) {
+		/* FIXME: should check if not_code == ~ircode */
+		ir->code = ir_extract_bits(ircode, ir->mask_keycode);
+
+		dprintk("scancode = 0x%02x (code = 0x%02x, notcode= 0x%02x)\n",
+			 ir->code, ircode, not_code);
+
+		ir_input_keydown(ir->dev, &ir->ir, ir->code, ir->code);
+	} else
+		dprintk("Repeat last key\n");
+
+	/* Keep repeating the last key */
+	mod_timer(&ir->timer_keyup, jiffies + msecs_to_jiffies(150));
+
+	saa_setl(SAA7134_IRQ2, SAA7134_IRQ2_INTE_GPIO18);
+}
+
+static int saa7134_nec_irq(struct saa7134_dev *dev)
+{
+	struct card_ir *ir = dev->remote;
+
+	saa_clearl(SAA7134_IRQ2, SAA7134_IRQ2_INTE_GPIO18);
+	tasklet_schedule(&ir->tlet);
+
+	return 1;
+}
diff --git a/drivers/media/video/saa7134/saa7134-ts.c b/drivers/media/video/saa7134/saa7134-ts.c
index eae72fd..ef55a59 100644
--- a/drivers/media/video/saa7134/saa7134-ts.c
+++ b/drivers/media/video/saa7134/saa7134-ts.c
@@ -66,11 +66,29 @@
 	saa7134_set_dmabits(dev);
 
 	mod_timer(&dev->ts_q.timeout, jiffies+BUFFER_TIMEOUT);
+
+	if (dev->ts_state == SAA7134_TS_BUFF_DONE) {
+		/* Clear TS cache */
+		dev->buff_cnt = 0;
+		saa_writeb(SAA7134_TS_SERIAL1, 0x00);
+		saa_writeb(SAA7134_TS_SERIAL1, 0x03);
+		saa_writeb(SAA7134_TS_SERIAL1, 0x00);
+		saa_writeb(SAA7134_TS_SERIAL1, 0x01);
+
+		/* TS clock non-inverted */
+		saa_writeb(SAA7134_TS_SERIAL1, 0x00);
+
+		/* Start TS stream */
+		saa_writeb(SAA7134_TS_SERIAL0, 0x40);
+		saa_writeb(SAA7134_TS_PARALLEL, 0xEC);
+		dev->ts_state = SAA7134_TS_STARTED;
+	}
+
 	return 0;
 }
 
 static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
-			  enum v4l2_field field)
+		enum v4l2_field field)
 {
 	struct saa7134_dev *dev = q->priv_data;
 	struct saa7134_buf *buf = container_of(vb,struct saa7134_buf,vb);
@@ -110,16 +128,22 @@
 			goto oops;
 	}
 
-	/* dma: setup channel 5 (= TS) */
-	control = SAA7134_RS_CONTROL_BURST_16 |
-		  SAA7134_RS_CONTROL_ME |
-		  (buf->pt->dma >> 12);
+	dev->buff_cnt++;
 
-	saa_writeb(SAA7134_TS_DMA0, ((lines-1)&0xff));
-	saa_writeb(SAA7134_TS_DMA1, (((lines-1)>>8)&0xff));
-	saa_writeb(SAA7134_TS_DMA2, ((((lines-1)>>16)&0x3f) | 0x00)); /* TSNOPIT=0, TSCOLAP=0 */
-	saa_writel(SAA7134_RS_PITCH(5),TS_PACKET_SIZE);
-	saa_writel(SAA7134_RS_CONTROL(5),control);
+	if (dev->buff_cnt == dev->ts.nr_bufs) {
+		dev->ts_state = SAA7134_TS_BUFF_DONE;
+		/* dma: setup channel 5 (= TS) */
+		control = SAA7134_RS_CONTROL_BURST_16 |
+			SAA7134_RS_CONTROL_ME |
+			(buf->pt->dma >> 12);
+
+		saa_writeb(SAA7134_TS_DMA0, (lines - 1) & 0xff);
+		saa_writeb(SAA7134_TS_DMA1, ((lines - 1) >> 8) & 0xff);
+		/* TSNOPIT=0, TSCOLAP=0 */
+		saa_writeb(SAA7134_TS_DMA2, (((lines - 1) >> 16) & 0x3f) | 0x00);
+		saa_writel(SAA7134_RS_PITCH(5), TS_PACKET_SIZE);
+		saa_writel(SAA7134_RS_CONTROL(5), control);
+	}
 
 	buf->vb.state = VIDEOBUF_PREPARED;
 	buf->activate = buffer_activate;
@@ -140,6 +164,8 @@
 	if (0 == *count)
 		*count = dev->ts.nr_bufs;
 	*count = saa7134_buffer_count(*size,*count);
+	dev->buff_cnt = 0;
+	dev->ts_state = SAA7134_TS_STOPPED;
 	return 0;
 }
 
@@ -154,7 +180,13 @@
 static void buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
 {
 	struct saa7134_buf *buf = container_of(vb,struct saa7134_buf,vb);
+	struct saa7134_dev *dev = q->priv_data;
 
+	if (dev->ts_state == SAA7134_TS_STARTED) {
+		/* Stop TS transport */
+		saa_writeb(SAA7134_TS_PARALLEL, 0x6c);
+		dev->ts_state = SAA7134_TS_STOPPED;
+	}
 	saa7134_dma_free(q,buf);
 }
 
@@ -182,7 +214,7 @@
 	/* deactivate TS softreset */
 	saa_writeb(SAA7134_TS_SERIAL1, 0x00);
 	/* TSSOP high active, TSVAL high active, TSLOCK ignored */
-	saa_writeb(SAA7134_TS_PARALLEL, 0xec);
+	saa_writeb(SAA7134_TS_PARALLEL, 0x6c);
 	saa_writeb(SAA7134_TS_PARALLEL_SERIAL, (TS_PACKET_SIZE-1));
 	saa_writeb(SAA7134_TS_DMA0, ((dev->ts.nr_packets-1)&0xff));
 	saa_writeb(SAA7134_TS_DMA1, (((dev->ts.nr_packets-1)>>8)&0xff));
diff --git a/drivers/media/video/saa7134/saa7134-video.c b/drivers/media/video/saa7134/saa7134-video.c
index 68c2689..02bb674 100644
--- a/drivers/media/video/saa7134/saa7134-video.c
+++ b/drivers/media/video/saa7134/saa7134-video.c
@@ -628,6 +628,9 @@
 
 	if (card_in(dev, dev->ctl_input).tv)
 		saa7134_i2c_call_clients(dev, VIDIOC_S_STD, &dev->tvnorm->id);
+	/* Set the correct norm for the saa6752hs. This function
+	   does nothing if there is no saa6752hs. */
+	saa7134_i2c_call_saa6752(dev, VIDIOC_S_STD, &dev->tvnorm->id);
 }
 
 static void set_h_prescale(struct saa7134_dev *dev, int task, int prescale)
@@ -1330,6 +1333,8 @@
 	struct saa7134_fh *fh;
 	enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
 	int radio = 0;
+
+	lock_kernel();
 	list_for_each_entry(dev, &saa7134_devlist, devlist) {
 		if (dev->video_dev && (dev->video_dev->minor == minor))
 			goto found;
@@ -1342,6 +1347,7 @@
 			goto found;
 		}
 	}
+	unlock_kernel();
 	return -ENODEV;
  found:
 
@@ -1350,8 +1356,10 @@
 
 	/* allocate + initialize per filehandle data */
 	fh = kzalloc(sizeof(*fh),GFP_KERNEL);
-	if (NULL == fh)
+	if (NULL == fh) {
+		unlock_kernel();
 		return -ENOMEM;
+	}
 	file->private_data = fh;
 	fh->dev      = dev;
 	fh->radio    = radio;
@@ -1384,6 +1392,7 @@
 		/* switch to video/vbi mode */
 		video_mux(dev,dev->ctl_input);
 	}
+	unlock_kernel();
 	return 0;
 }
 
@@ -1790,18 +1799,25 @@
 		return 0;
 }
 
-static int saa7134_s_std(struct file *file, void *priv, v4l2_std_id *id)
+int saa7134_s_std_internal(struct saa7134_dev *dev, struct saa7134_fh *fh, v4l2_std_id *id)
 {
-	struct saa7134_fh *fh = priv;
-	struct saa7134_dev *dev = fh->dev;
 	unsigned long flags;
 	unsigned int i;
 	v4l2_std_id fixup;
 	int err;
 
-	err = v4l2_prio_check(&dev->prio, &fh->prio);
-	if (0 != err)
-		return err;
+	/* When called from the empress code fh == NULL.
+	   That needs to be fixed somehow, but for now this is
+	   good enough. */
+	if (fh) {
+		err = v4l2_prio_check(&dev->prio, &fh->prio);
+		if (0 != err)
+			return err;
+	} else if (res_locked(dev, RESOURCE_OVERLAY)) {
+		/* Don't change the std from the mpeg device
+		   if overlay is active. */
+		return -EBUSY;
+	}
 
 	for (i = 0; i < TVNORMS; i++)
 		if (*id == tvnorms[i].id)
@@ -1834,7 +1850,7 @@
 	*id = tvnorms[i].id;
 
 	mutex_lock(&dev->lock);
-	if (res_check(fh, RESOURCE_OVERLAY)) {
+	if (fh && res_check(fh, RESOURCE_OVERLAY)) {
 		spin_lock_irqsave(&dev->slock, flags);
 		stop_preview(dev, fh);
 		spin_unlock_irqrestore(&dev->slock, flags);
@@ -1851,6 +1867,23 @@
 	mutex_unlock(&dev->lock);
 	return 0;
 }
+EXPORT_SYMBOL_GPL(saa7134_s_std_internal);
+
+static int saa7134_s_std(struct file *file, void *priv, v4l2_std_id *id)
+{
+	struct saa7134_fh *fh = priv;
+
+	return saa7134_s_std_internal(fh->dev, fh, id);
+}
+
+static int saa7134_g_std(struct file *file, void *priv, v4l2_std_id *id)
+{
+	struct saa7134_fh *fh = priv;
+	struct saa7134_dev *dev = fh->dev;
+
+	*id = dev->tvnorm->id;
+	return 0;
+}
 
 static int saa7134_cropcap(struct file *file, void *priv,
 					struct v4l2_cropcap *cap)
@@ -2077,18 +2110,6 @@
 	return 0;
 }
 
-static int saa7134_enum_fmt_vbi_cap(struct file *file, void  *priv,
-					struct v4l2_fmtdesc *f)
-{
-	if (0 != f->index)
-		return -EINVAL;
-
-	f->pixelformat = V4L2_PIX_FMT_GREY;
-	strcpy(f->description, "vbi data");
-
-	return 0;
-}
-
 static int saa7134_g_fbuf(struct file *file, void *f,
 				struct v4l2_framebuffer *fb)
 {
@@ -2379,7 +2400,6 @@
 	.vidioc_g_fmt_vid_overlay	= saa7134_g_fmt_vid_overlay,
 	.vidioc_try_fmt_vid_overlay	= saa7134_try_fmt_vid_overlay,
 	.vidioc_s_fmt_vid_overlay	= saa7134_s_fmt_vid_overlay,
-	.vidioc_enum_fmt_vbi_cap	= saa7134_enum_fmt_vbi_cap,
 	.vidioc_g_fmt_vbi_cap		= saa7134_try_get_set_fmt_vbi_cap,
 	.vidioc_try_fmt_vbi_cap		= saa7134_try_get_set_fmt_vbi_cap,
 	.vidioc_s_fmt_vbi_cap		= saa7134_try_get_set_fmt_vbi_cap,
@@ -2391,6 +2411,7 @@
 	.vidioc_qbuf			= saa7134_qbuf,
 	.vidioc_dqbuf			= saa7134_dqbuf,
 	.vidioc_s_std			= saa7134_s_std,
+	.vidioc_g_std			= saa7134_g_std,
 	.vidioc_enum_input		= saa7134_enum_input,
 	.vidioc_g_input			= saa7134_g_input,
 	.vidioc_s_input			= saa7134_s_input,
diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h
index a0884f6..491ab1f 100644
--- a/drivers/media/video/saa7134/saa7134.h
+++ b/drivers/media/video/saa7134/saa7134.h
@@ -269,6 +269,12 @@
 #define SAA7134_BOARD_BEHOLD_M6_EXTRA    144
 #define SAA7134_BOARD_AVERMEDIA_M103    145
 #define SAA7134_BOARD_ASUSTeK_P7131_ANALOG 146
+#define SAA7134_BOARD_ASUSTeK_TIGER_3IN1   147
+#define SAA7134_BOARD_ENCORE_ENLTV_FM53 148
+#define SAA7134_BOARD_AVERMEDIA_M135A    149
+#define SAA7134_BOARD_REAL_ANGEL_220     150
+#define SAA7134_BOARD_ADS_INSTANT_HDTV_PCI  151
+#define SAA7134_BOARD_ASUSTeK_TIGER         152
 
 #define SAA7134_MAXBOARDS 8
 #define SAA7134_INPUT_MAX 8
@@ -462,6 +468,12 @@
 	void                       (*signal_change)(struct saa7134_dev *dev);
 };
 
+enum saa7134_ts_status {
+	SAA7134_TS_STOPPED,
+	SAA7134_TS_BUFF_DONE,
+	SAA7134_TS_STARTED,
+};
+
 /* global device status */
 struct saa7134_dev {
 	struct list_head           devlist;
@@ -555,6 +567,8 @@
 	/* SAA7134_MPEG_* */
 	struct saa7134_ts          ts;
 	struct saa7134_dmaqueue    ts_q;
+	enum saa7134_ts_status 	   ts_state;
+	unsigned int 		   buff_cnt;
 	struct saa7134_mpeg_ops    *mops;
 	struct i2c_client 	   *mpeg_i2c_client;
 
@@ -644,7 +658,7 @@
 
 extern int saa7134_board_init1(struct saa7134_dev *dev);
 extern int saa7134_board_init2(struct saa7134_dev *dev);
-int saa7134_tuner_callback(void *priv, int command, int arg);
+int saa7134_tuner_callback(void *priv, int component, int command, int arg);
 
 
 /* ----------------------------------------------------------- */
@@ -654,6 +668,8 @@
 int saa7134_i2c_unregister(struct saa7134_dev *dev);
 void saa7134_i2c_call_clients(struct saa7134_dev *dev,
 			      unsigned int cmd, void *arg);
+int saa7134_i2c_call_saa6752(struct saa7134_dev *dev,
+			      unsigned int cmd, void *arg);
 
 
 /* ----------------------------------------------------------- */
@@ -666,6 +682,7 @@
 int saa7134_s_ctrl_internal(struct saa7134_dev *dev,  struct saa7134_fh *fh, struct v4l2_control *c);
 int saa7134_g_ctrl_internal(struct saa7134_dev *dev,  struct saa7134_fh *fh, struct v4l2_control *c);
 int saa7134_queryctrl(struct file *file, void *priv, struct v4l2_queryctrl *c);
+int saa7134_s_std_internal(struct saa7134_dev *dev,  struct saa7134_fh *fh, v4l2_std_id *id);
 
 int saa7134_videoport_init(struct saa7134_dev *dev);
 void saa7134_set_tvnorm_hw(struct saa7134_dev *dev);
diff --git a/drivers/media/video/se401.c b/drivers/media/video/se401.c
index acceed5..ae39491 100644
--- a/drivers/media/video/se401.c
+++ b/drivers/media/video/se401.c
@@ -288,7 +288,7 @@
 	int status;
 
 	if (!se401->dev) {
-		info("ohoh: device vapourished");
+		dev_info(&urb->dev->dev, "device vapourished\n");
 		return;
 	}
 
@@ -328,7 +328,7 @@
 		return;
 
 	if (!se401->dev) {
-		info ("ohoh: device vapourished");
+		dev_info(&urb->dev->dev, "device vapourished\n");
 		return;
 	}
 
@@ -375,7 +375,7 @@
 	urb->status=0;
 	urb->dev=se401->dev;
 	if(usb_submit_urb(urb, GFP_KERNEL))
-		info("urb burned down");
+		dev_info(&urb->dev->dev, "urb burned down\n");
 	return;
 }
 
@@ -860,7 +860,8 @@
 		);
 		if (se401->nullpackets > SE401_MAX_NULLPACKETS) {
 			se401->nullpackets=0;
-			info("to many null length packets, restarting capture");
+			dev_info(&se401->dev->dev,
+				 "too many null length packets, restarting capture\n");
 			se401_stop_stream(se401);
 			se401_start_stream(se401);
 		} else {
@@ -880,7 +881,8 @@
 				se401->scratch_use=0;
 			if (errors > SE401_MAX_ERRORS) {
 				errors=0;
-				info("to much errors, restarting capture");
+				dev_info(&se401->dev->dev,
+					 "too many errors, restarting capture\n");
 				se401_stop_stream(se401);
 				se401_start_stream(se401);
 			}
@@ -913,7 +915,7 @@
 		usb_kill_urb(se401->inturb);
 		usb_free_urb(se401->inturb);
 	}
-	info("%s disconnected", se401->camera_name);
+	dev_info(&se401->dev->dev, "%s disconnected", se401->camera_name);
 
 	/* Free the memory */
 	kfree(se401->width);
@@ -936,14 +938,18 @@
 	struct usb_se401 *se401 = (struct usb_se401 *)dev;
 	int err = 0;
 
-	if (se401->user)
+	lock_kernel();
+	if (se401->user) {
+		unlock_kernel();
 		return -EBUSY;
+	}
 	se401->fbuf = rvmalloc(se401->maxframesize * SE401_NUMFRAMES);
 	if (se401->fbuf)
 		file->private_data = dev;
 	else
 		err = -ENOMEM;
 	se401->user = !err;
+	unlock_kernel();
 
 	return err;
 }
@@ -956,8 +962,8 @@
 
 	rvfree(se401->fbuf, se401->maxframesize * SE401_NUMFRAMES);
 	if (se401->removed) {
+		dev_info(&se401->dev->dev, "device unregistered\n");
 		usb_se401_remove_disconnected(se401);
-		info("device unregistered");
 	} else {
 		for (i=0; i<SE401_NUMFRAMES; i++)
 			se401->frame[i].grabstate=FRAME_UNUSED;
@@ -1232,6 +1238,7 @@
 static struct video_device se401_template = {
 	.name =         "se401 USB camera",
 	.fops =         &se401_fops,
+	.release = video_device_release_empty,
 };
 
 
@@ -1271,7 +1278,7 @@
 	for (i=0; i<se401->sizes; i++) {
 		sprintf(temp, "%s %dx%d", temp, se401->width[i], se401->height[i]);
 	}
-	info("%s", temp);
+	dev_info(&se401->dev->dev, "%s\n", temp);
 	se401->maxframesize=se401->width[se401->sizes-1]*se401->height[se401->sizes-1]*3;
 
 	rc=se401_sndctrl(0, se401, SE401_REQ_GET_WIDTH, 0, cp, sizeof(cp));
@@ -1305,7 +1312,8 @@
 	if (button) {
 		se401->inturb=usb_alloc_urb(0, GFP_KERNEL);
 		if (!se401->inturb) {
-			info("Allocation of inturb failed");
+			dev_info(&se401->dev->dev,
+				 "Allocation of inturb failed\n");
 			return 1;
 		}
 		usb_fill_int_urb(se401->inturb, se401->dev,
@@ -1316,7 +1324,7 @@
 		    8
 		);
 		if (usb_submit_urb(se401->inturb, GFP_KERNEL)) {
-			info("int urb burned down");
+			dev_info(&se401->dev->dev, "int urb burned down\n");
 			return 1;
 		}
 	} else
@@ -1373,7 +1381,7 @@
 		return -ENODEV;
 
 	/* We found one */
-	info("SE401 camera found: %s", camera_name);
+	dev_info(&intf->dev, "SE401 camera found: %s\n", camera_name);
 
 	if ((se401 = kzalloc(sizeof(*se401), GFP_KERNEL)) == NULL) {
 		err("couldn't kmalloc se401 struct");
@@ -1384,7 +1392,8 @@
 	se401->iface = interface->bInterfaceNumber;
 	se401->camera_name = camera_name;
 
-	info("firmware version: %02x", le16_to_cpu(dev->descriptor.bcdDevice) & 255);
+	dev_info(&intf->dev, "firmware version: %02x\n",
+		 le16_to_cpu(dev->descriptor.bcdDevice) & 255);
 
 	if (se401_init(se401, button)) {
 		kfree(se401);
@@ -1402,7 +1411,8 @@
 		err("video_register_device failed");
 		return -EIO;
 	}
-	info("registered new video device: video%d", se401->vdev.minor);
+	dev_info(&intf->dev, "registered new video device: video%d\n",
+		 se401->vdev.minor);
 
 	usb_set_intfdata (intf, se401);
 	return 0;
@@ -1446,10 +1456,10 @@
 
 static int __init usb_se401_init(void)
 {
-	info("SE401 usb camera driver version %s registering", version);
+	printk(KERN_INFO "SE401 usb camera driver version %s registering\n", version);
 	if (flickerless)
 		if (flickerless!=50 && flickerless!=60) {
-			info("Invallid flickerless value, use 0, 50 or 60.");
+			printk(KERN_ERR "Invallid flickerless value, use 0, 50 or 60.\n");
 			return -1;
 	}
 	return usb_register(&se401_driver);
@@ -1458,7 +1468,7 @@
 static void __exit usb_se401_exit(void)
 {
 	usb_deregister(&se401_driver);
-	info("SE401 driver deregistered");
+	printk(KERN_INFO "SE401 driver deregistered\frame");
 }
 
 module_init(usb_se401_init);
diff --git a/drivers/media/video/sh_mobile_ceu_camera.c b/drivers/media/video/sh_mobile_ceu_camera.c
index 318754e..7683809 100644
--- a/drivers/media/video/sh_mobile_ceu_camera.c
+++ b/drivers/media/video/sh_mobile_ceu_camera.c
@@ -304,9 +304,6 @@
 		 "SuperH Mobile CEU driver attached to camera %d\n",
 		 icd->devnum);
 
-	if (pcdev->pdata->enable_camera)
-		pcdev->pdata->enable_camera();
-
 	ret = icd->ops->init(icd);
 	if (ret)
 		goto err;
@@ -333,8 +330,6 @@
 	ceu_write(pcdev, CEIER, 0);
 	ceu_write(pcdev, CAPSR, 1 << 16); /* reset */
 	icd->ops->release(icd);
-	if (pcdev->pdata->disable_camera)
-		pcdev->pdata->disable_camera();
 
 	dev_info(&icd->dev,
 		 "SuperH Mobile CEU driver detached from camera %d\n",
diff --git a/drivers/media/video/sn9c102/sn9c102_core.c b/drivers/media/video/sn9c102/sn9c102_core.c
index 2da6938..20e30bd 100644
--- a/drivers/media/video/sn9c102/sn9c102_core.c
+++ b/drivers/media/video/sn9c102/sn9c102_core.c
@@ -116,6 +116,26 @@
 		 "\n");
 #endif
 
+/*
+   Add the probe entries to this table. Be sure to add the entry in the right
+   place, since, on failure, the next probing routine is called according to
+   the order of the list below, from top to bottom.
+*/
+static int (*sn9c102_sensor_table[])(struct sn9c102_device *) = {
+	&sn9c102_probe_hv7131d, /* strong detection based on SENSOR ids */
+	&sn9c102_probe_hv7131r, /* strong detection based on SENSOR ids */
+	&sn9c102_probe_mi0343, /* strong detection based on SENSOR ids */
+	&sn9c102_probe_mi0360, /* strong detection based on SENSOR ids */
+	&sn9c102_probe_mt9v111, /* strong detection based on SENSOR ids */
+	&sn9c102_probe_pas106b, /* strong detection based on SENSOR ids */
+	&sn9c102_probe_pas202bcb, /* strong detection based on SENSOR ids */
+	&sn9c102_probe_ov7630, /* strong detection based on SENSOR ids */
+	&sn9c102_probe_ov7660, /* strong detection based on SENSOR ids */
+	&sn9c102_probe_tas5110c1b, /* detection based on USB pid/vid */
+	&sn9c102_probe_tas5110d, /* detection based on USB pid/vid */
+	&sn9c102_probe_tas5130d1b, /* detection based on USB pid/vid */
+};
+
 /*****************************************************************************/
 
 static u32
@@ -1746,7 +1766,7 @@
 	if (!down_read_trylock(&sn9c102_dev_lock))
 		return -ERESTARTSYS;
 
-	cam = video_get_drvdata(video_devdata(filp));
+	cam = video_drvdata(filp);
 
 	if (wait_for_completion_interruptible(&cam->probe)) {
 		up_read(&sn9c102_dev_lock);
@@ -1843,7 +1863,7 @@
 
 	down_write(&sn9c102_dev_lock);
 
-	cam = video_get_drvdata(video_devdata(filp));
+	cam = video_drvdata(filp);
 
 	sn9c102_stop_transfer(cam);
 	sn9c102_release_buffers(cam);
@@ -1863,7 +1883,7 @@
 static ssize_t
 sn9c102_read(struct file* filp, char __user * buf, size_t count, loff_t* f_pos)
 {
-	struct sn9c102_device* cam = video_get_drvdata(video_devdata(filp));
+	struct sn9c102_device *cam = video_drvdata(filp);
 	struct sn9c102_frame_t* f, * i;
 	unsigned long lock_flags;
 	long timeout;
@@ -1987,7 +2007,7 @@
 
 static unsigned int sn9c102_poll(struct file *filp, poll_table *wait)
 {
-	struct sn9c102_device* cam = video_get_drvdata(video_devdata(filp));
+	struct sn9c102_device *cam = video_drvdata(filp);
 	struct sn9c102_frame_t* f;
 	unsigned long lock_flags;
 	unsigned int mask = 0;
@@ -2063,7 +2083,7 @@
 
 static int sn9c102_mmap(struct file* filp, struct vm_area_struct *vma)
 {
-	struct sn9c102_device* cam = video_get_drvdata(video_devdata(filp));
+	struct sn9c102_device *cam = video_drvdata(filp);
 	unsigned long size = vma->vm_end - vma->vm_start,
 		      start = vma->vm_start;
 	void *pos;
@@ -3075,7 +3095,7 @@
 static int sn9c102_ioctl_v4l2(struct inode* inode, struct file* filp,
 			      unsigned int cmd, void __user * arg)
 {
-	struct sn9c102_device* cam = video_get_drvdata(video_devdata(filp));
+	struct sn9c102_device *cam = video_drvdata(filp);
 
 	switch (cmd) {
 
@@ -3179,7 +3199,7 @@
 static int sn9c102_ioctl(struct inode* inode, struct file* filp,
 			 unsigned int cmd, unsigned long arg)
 {
-	struct sn9c102_device* cam = video_get_drvdata(video_devdata(filp));
+	struct sn9c102_device *cam = video_drvdata(filp);
 	int err = 0;
 
 	if (mutex_lock_interruptible(&cam->fileop_mutex))
diff --git a/drivers/media/video/sn9c102/sn9c102_devtable.h b/drivers/media/video/sn9c102/sn9c102_devtable.h
index 90a401d..e23734f 100644
--- a/drivers/media/video/sn9c102/sn9c102_devtable.h
+++ b/drivers/media/video/sn9c102/sn9c102_devtable.h
@@ -140,24 +140,4 @@
 extern int sn9c102_probe_tas5110d(struct sn9c102_device* cam);
 extern int sn9c102_probe_tas5130d1b(struct sn9c102_device* cam);
 
-/*
-   Add the above entries to this table. Be sure to add the entry in the right
-   place, since, on failure, the next probing routine is called according to
-   the order of the list below, from top to bottom.
-*/
-static int (*sn9c102_sensor_table[])(struct sn9c102_device*) = {
-	&sn9c102_probe_hv7131d, /* strong detection based on SENSOR ids */
-	&sn9c102_probe_hv7131r, /* strong detection based on SENSOR ids */
-	&sn9c102_probe_mi0343, /* strong detection based on SENSOR ids */
-	&sn9c102_probe_mi0360, /* strong detection based on SENSOR ids */
-	&sn9c102_probe_mt9v111, /* strong detection based on SENSOR ids */
-	&sn9c102_probe_pas106b, /* strong detection based on SENSOR ids */
-	&sn9c102_probe_pas202bcb, /* strong detection based on SENSOR ids */
-	&sn9c102_probe_ov7630, /* strong detection based on SENSOR ids */
-	&sn9c102_probe_ov7660, /* strong detection based on SENSOR ids */
-	&sn9c102_probe_tas5110c1b, /* detection based on USB pid/vid */
-	&sn9c102_probe_tas5110d, /* detection based on USB pid/vid */
-	&sn9c102_probe_tas5130d1b, /* detection based on USB pid/vid */
-};
-
 #endif /* _SN9C102_DEVTABLE_H_ */
diff --git a/drivers/media/video/sn9c102/sn9c102_hv7131d.c b/drivers/media/video/sn9c102/sn9c102_hv7131d.c
index eaf9ad0..db24349 100644
--- a/drivers/media/video/sn9c102/sn9c102_hv7131d.c
+++ b/drivers/media/video/sn9c102/sn9c102_hv7131d.c
@@ -20,6 +20,7 @@
  ***************************************************************************/
 
 #include "sn9c102_sensor.h"
+#include "sn9c102_devtable.h"
 
 
 static int hv7131d_init(struct sn9c102_device* cam)
diff --git a/drivers/media/video/sn9c102/sn9c102_hv7131r.c b/drivers/media/video/sn9c102/sn9c102_hv7131r.c
index 0fc4012..4295887 100644
--- a/drivers/media/video/sn9c102/sn9c102_hv7131r.c
+++ b/drivers/media/video/sn9c102/sn9c102_hv7131r.c
@@ -20,6 +20,7 @@
  ***************************************************************************/
 
 #include "sn9c102_sensor.h"
+#include "sn9c102_devtable.h"
 
 
 static int hv7131r_init(struct sn9c102_device* cam)
diff --git a/drivers/media/video/sn9c102/sn9c102_mi0343.c b/drivers/media/video/sn9c102/sn9c102_mi0343.c
index 00b134c..1f5b09b 100644
--- a/drivers/media/video/sn9c102/sn9c102_mi0343.c
+++ b/drivers/media/video/sn9c102/sn9c102_mi0343.c
@@ -20,6 +20,7 @@
  ***************************************************************************/
 
 #include "sn9c102_sensor.h"
+#include "sn9c102_devtable.h"
 
 
 static int mi0343_init(struct sn9c102_device* cam)
diff --git a/drivers/media/video/sn9c102/sn9c102_mi0360.c b/drivers/media/video/sn9c102/sn9c102_mi0360.c
index f8d81d8..d973fc1 100644
--- a/drivers/media/video/sn9c102/sn9c102_mi0360.c
+++ b/drivers/media/video/sn9c102/sn9c102_mi0360.c
@@ -20,6 +20,7 @@
  ***************************************************************************/
 
 #include "sn9c102_sensor.h"
+#include "sn9c102_devtable.h"
 
 
 static int mi0360_init(struct sn9c102_device* cam)
diff --git a/drivers/media/video/sn9c102/sn9c102_mt9v111.c b/drivers/media/video/sn9c102/sn9c102_mt9v111.c
index 3b98ac3..95986eb 100644
--- a/drivers/media/video/sn9c102/sn9c102_mt9v111.c
+++ b/drivers/media/video/sn9c102/sn9c102_mt9v111.c
@@ -20,6 +20,7 @@
  ***************************************************************************/
 
 #include "sn9c102_sensor.h"
+#include "sn9c102_devtable.h"
 
 
 static int mt9v111_init(struct sn9c102_device *cam)
diff --git a/drivers/media/video/sn9c102/sn9c102_ov7630.c b/drivers/media/video/sn9c102/sn9c102_ov7630.c
index e4856fd..803712c 100644
--- a/drivers/media/video/sn9c102/sn9c102_ov7630.c
+++ b/drivers/media/video/sn9c102/sn9c102_ov7630.c
@@ -20,6 +20,7 @@
  ***************************************************************************/
 
 #include "sn9c102_sensor.h"
+#include "sn9c102_devtable.h"
 
 
 static int ov7630_init(struct sn9c102_device* cam)
diff --git a/drivers/media/video/sn9c102/sn9c102_ov7660.c b/drivers/media/video/sn9c102/sn9c102_ov7660.c
index 8aae416..7977795 100644
--- a/drivers/media/video/sn9c102/sn9c102_ov7660.c
+++ b/drivers/media/video/sn9c102/sn9c102_ov7660.c
@@ -20,6 +20,7 @@
  ***************************************************************************/
 
 #include "sn9c102_sensor.h"
+#include "sn9c102_devtable.h"
 
 
 static int ov7660_init(struct sn9c102_device* cam)
diff --git a/drivers/media/video/sn9c102/sn9c102_pas106b.c b/drivers/media/video/sn9c102/sn9c102_pas106b.c
index 360f2a8..81cd969 100644
--- a/drivers/media/video/sn9c102/sn9c102_pas106b.c
+++ b/drivers/media/video/sn9c102/sn9c102_pas106b.c
@@ -21,6 +21,7 @@
 
 #include <linux/delay.h>
 #include "sn9c102_sensor.h"
+#include "sn9c102_devtable.h"
 
 
 static int pas106b_init(struct sn9c102_device* cam)
diff --git a/drivers/media/video/sn9c102/sn9c102_pas202bcb.c b/drivers/media/video/sn9c102/sn9c102_pas202bcb.c
index ca4a150..2782f94 100644
--- a/drivers/media/video/sn9c102/sn9c102_pas202bcb.c
+++ b/drivers/media/video/sn9c102/sn9c102_pas202bcb.c
@@ -26,6 +26,7 @@
 
 #include <linux/delay.h>
 #include "sn9c102_sensor.h"
+#include "sn9c102_devtable.h"
 
 
 static int pas202bcb_init(struct sn9c102_device* cam)
diff --git a/drivers/media/video/sn9c102/sn9c102_tas5110c1b.c b/drivers/media/video/sn9c102/sn9c102_tas5110c1b.c
index e7d2de2..04cdfdd 100644
--- a/drivers/media/video/sn9c102/sn9c102_tas5110c1b.c
+++ b/drivers/media/video/sn9c102/sn9c102_tas5110c1b.c
@@ -20,6 +20,7 @@
  ***************************************************************************/
 
 #include "sn9c102_sensor.h"
+#include "sn9c102_devtable.h"
 
 
 static int tas5110c1b_init(struct sn9c102_device* cam)
diff --git a/drivers/media/video/sn9c102/sn9c102_tas5110d.c b/drivers/media/video/sn9c102/sn9c102_tas5110d.c
index d32fdbc..9372e6f9 100644
--- a/drivers/media/video/sn9c102/sn9c102_tas5110d.c
+++ b/drivers/media/video/sn9c102/sn9c102_tas5110d.c
@@ -20,6 +20,7 @@
  ***************************************************************************/
 
 #include "sn9c102_sensor.h"
+#include "sn9c102_devtable.h"
 
 
 static int tas5110d_init(struct sn9c102_device* cam)
diff --git a/drivers/media/video/sn9c102/sn9c102_tas5130d1b.c b/drivers/media/video/sn9c102/sn9c102_tas5130d1b.c
index 56fb1d5..a30bbc4 100644
--- a/drivers/media/video/sn9c102/sn9c102_tas5130d1b.c
+++ b/drivers/media/video/sn9c102/sn9c102_tas5130d1b.c
@@ -20,6 +20,7 @@
  ***************************************************************************/
 
 #include "sn9c102_sensor.h"
+#include "sn9c102_devtable.h"
 
 
 static int tas5130d1b_init(struct sn9c102_device* cam)
diff --git a/drivers/media/video/stk-webcam.c b/drivers/media/video/stk-webcam.c
index ad36af3..db69bc5 100644
--- a/drivers/media/video/stk-webcam.c
+++ b/drivers/media/video/stk-webcam.c
@@ -65,22 +65,6 @@
 };
 MODULE_DEVICE_TABLE(usb, stkwebcam_table);
 
-static void stk_camera_cleanup(struct kref *kref)
-{
-	struct stk_camera *dev = to_stk_camera(kref);
-
-	STK_INFO("Syntek USB2.0 Camera release resources"
-		" video device /dev/video%d\n", dev->vdev.minor);
-	video_unregister_device(&dev->vdev);
-	dev->vdev.priv = NULL;
-
-	if (dev->sio_bufs != NULL || dev->isobufs != NULL)
-		STK_ERROR("We are leaking memory\n");
-	usb_put_intf(dev->interface);
-	kfree(dev);
-}
-
-
 /*
  * Basic stuff
  */
@@ -689,34 +673,24 @@
 	vdev = video_devdata(fp);
 	dev = vdev_to_camera(vdev);
 
-	if (dev == NULL || !is_present(dev))
+	lock_kernel();
+	if (dev == NULL || !is_present(dev)) {
+		unlock_kernel();
 		return -ENXIO;
-	fp->private_data = vdev;
-	kref_get(&dev->kref);
+	}
+	fp->private_data = dev;
 	usb_autopm_get_interface(dev->interface);
+	unlock_kernel();
 
 	return 0;
 }
 
 static int v4l_stk_release(struct inode *inode, struct file *fp)
 {
-	struct stk_camera *dev;
-	struct video_device *vdev;
-
-	vdev = video_devdata(fp);
-	if (vdev == NULL) {
-		STK_ERROR("v4l_release called w/o video devdata\n");
-		return -EFAULT;
-	}
-	dev = vdev_to_camera(vdev);
-	if (dev == NULL) {
-		STK_ERROR("v4l_release called on removed device\n");
-		return -ENODEV;
-	}
+	struct stk_camera *dev = fp->private_data;
 
 	if (dev->owner != fp) {
 		usb_autopm_put_interface(dev->interface);
-		kref_put(&dev->kref, stk_camera_cleanup);
 		return 0;
 	}
 
@@ -727,7 +701,6 @@
 	dev->owner = NULL;
 
 	usb_autopm_put_interface(dev->interface);
-	kref_put(&dev->kref, stk_camera_cleanup);
 
 	return 0;
 }
@@ -738,14 +711,8 @@
 	int i;
 	int ret;
 	unsigned long flags;
-	struct stk_camera *dev;
-	struct video_device *vdev;
 	struct stk_sio_buffer *sbuf;
-
-	vdev = video_devdata(fp);
-	if (vdev == NULL)
-		return -EFAULT;
-	dev = vdev_to_camera(vdev);
+	struct stk_camera *dev = fp->private_data;
 
 	if (dev == NULL)
 		return -EIO;
@@ -804,15 +771,8 @@
 
 static unsigned int v4l_stk_poll(struct file *fp, poll_table *wait)
 {
-	struct stk_camera *dev;
-	struct video_device *vdev;
+	struct stk_camera *dev = fp->private_data;
 
-	vdev = video_devdata(fp);
-
-	if (vdev == NULL)
-		return -EFAULT;
-
-	dev = vdev_to_camera(vdev);
 	if (dev == NULL)
 		return -ENODEV;
 
@@ -850,16 +810,12 @@
 	unsigned int i;
 	int ret;
 	unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
-	struct stk_camera *dev;
-	struct video_device *vdev;
+	struct stk_camera *dev = fp->private_data;
 	struct stk_sio_buffer *sbuf = NULL;
 
 	if (!(vma->vm_flags & VM_WRITE) || !(vma->vm_flags & VM_SHARED))
 		return -EINVAL;
 
-	vdev = video_devdata(fp);
-	dev = vdev_to_camera(vdev);
-
 	for (i = 0; i < dev->n_sbufs; i++) {
 		if (dev->sio_bufs[i].v4lbuf.m.offset == offset) {
 			sbuf = dev->sio_bufs + i;
@@ -1355,6 +1311,12 @@
 
 static void stk_v4l_dev_release(struct video_device *vd)
 {
+	struct stk_camera *dev = vdev_to_camera(vd);
+
+	if (dev->sio_bufs != NULL || dev->isobufs != NULL)
+		STK_ERROR("We are leaking memory\n");
+	usb_put_intf(dev->interface);
+	kfree(dev);
 }
 
 static struct video_device stk_v4l_data = {
@@ -1375,7 +1337,6 @@
 	dev->vdev = stk_v4l_data;
 	dev->vdev.debug = debug;
 	dev->vdev.parent = &dev->interface->dev;
-	dev->vdev.priv = dev;
 	err = video_register_device(&dev->vdev, VFL_TYPE_GRABBER, -1);
 	if (err)
 		STK_ERROR("v4l registration failed\n");
@@ -1392,7 +1353,7 @@
 		const struct usb_device_id *id)
 {
 	int i;
-	int err;
+	int err = 0;
 
 	struct stk_camera *dev = NULL;
 	struct usb_device *udev = interface_to_usbdev(interface);
@@ -1405,7 +1366,6 @@
 		return -ENOMEM;
 	}
 
-	kref_init(&dev->kref);
 	spin_lock_init(&dev->spinlock);
 	init_waitqueue_head(&dev->wait_frame);
 
@@ -1438,8 +1398,8 @@
 	}
 	if (!dev->isoc_ep) {
 		STK_ERROR("Could not find isoc-in endpoint");
-		kref_put(&dev->kref, stk_camera_cleanup);
-		return -ENODEV;
+		err = -ENODEV;
+		goto error;
 	}
 	dev->vsettings.brightness = 0x7fff;
 	dev->vsettings.palette = V4L2_PIX_FMT_RGB565;
@@ -1453,14 +1413,17 @@
 
 	err = stk_register_video_device(dev);
 	if (err) {
-		kref_put(&dev->kref, stk_camera_cleanup);
-		return err;
+		goto error;
 	}
 
 	stk_create_sysfs_files(&dev->vdev);
 	usb_autopm_enable(dev->interface);
 
 	return 0;
+
+error:
+	kfree(dev);
+	return err;
 }
 
 static void stk_camera_disconnect(struct usb_interface *interface)
@@ -1473,7 +1436,10 @@
 	wake_up_interruptible(&dev->wait_frame);
 	stk_remove_sysfs_files(&dev->vdev);
 
-	kref_put(&dev->kref, stk_camera_cleanup);
+	STK_INFO("Syntek USB2.0 Camera release resources"
+		"video device /dev/video%d\n", dev->vdev.minor);
+
+	video_unregister_device(&dev->vdev);
 }
 
 #ifdef CONFIG_PM
diff --git a/drivers/media/video/stk-webcam.h b/drivers/media/video/stk-webcam.h
index df4dfef..084a85b 100644
--- a/drivers/media/video/stk-webcam.h
+++ b/drivers/media/video/stk-webcam.h
@@ -99,7 +99,6 @@
 
 	u8 isoc_ep;
 
-	struct kref kref;
 	/* Not sure if this is right */
 	atomic_t urbs_used;
 
@@ -121,7 +120,6 @@
 	unsigned sequence;
 };
 
-#define to_stk_camera(d) container_of(d, struct stk_camera, kref)
 #define vdev_to_camera(d) container_of(d, struct stk_camera, vdev)
 
 void stk_camera_delete(struct kref *);
diff --git a/drivers/media/video/stradis.c b/drivers/media/video/stradis.c
index 276bded..bbad54f 100644
--- a/drivers/media/video/stradis.c
+++ b/drivers/media/video/stradis.c
@@ -1882,12 +1882,16 @@
 	struct video_device *vdev = video_devdata(file);
 	struct saa7146 *saa = container_of(vdev, struct saa7146, video_dev);
 
+	lock_kernel();
 	file->private_data = saa;
 
 	saa->user++;
-	if (saa->user > 1)
+	if (saa->user > 1) {
+		unlock_kernel();
 		return 0;	/* device open already, don't reset */
+	}
 	saa->writemode = VID_WRITE_MPEG_VID;	/* default to video */
+	unlock_kernel();
 	return 0;
 }
 
@@ -1921,6 +1925,7 @@
 	.name = "SAA7146A",
 	.fops = &saa_fops,
 	.minor = -1,
+	.release = video_device_release_empty,
 };
 
 static int __devinit configure_saa7146(struct pci_dev *pdev, int num)
diff --git a/drivers/media/video/stv680.c b/drivers/media/video/stv680.c
index dce9474..9c549d9 100644
--- a/drivers/media/video/stv680.c
+++ b/drivers/media/video/stv680.c
@@ -84,7 +84,8 @@
 #define PDEBUG(level, fmt, args...) \
 	do { \
 	if (debug >= level)	\
-		info("[%s:%d] " fmt, __func__, __LINE__ , ## args);	\
+		printk(KERN_INFO KBUILD_MODNAME " [%s:%d] \n" fmt,	\
+			__func__, __LINE__ , ## args);	\
 	} while (0)
 
 
@@ -1086,6 +1087,7 @@
 	int err = 0;
 
 	/* we are called with the BKL held */
+	lock_kernel();
 	stv680->user = 1;
 	err = stv_init (stv680);	/* main initialization routine for camera */
 
@@ -1099,6 +1101,7 @@
 	}
 	if (err)
 		stv680->user = 0;
+	unlock_kernel();
 
 	return err;
 }
@@ -1550,7 +1553,8 @@
 	}
 	PDEBUG (0, "STV(i): usb camera driver version %s registering", DRIVER_VERSION);
 
-	info(DRIVER_DESC " " DRIVER_VERSION);
+	printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
+	       DRIVER_DESC "\n");
 	return 0;
 }
 
diff --git a/drivers/media/video/tda9840.c b/drivers/media/video/tda9840.c
index 2437c1a..1c391f0 100644
--- a/drivers/media/video/tda9840.c
+++ b/drivers/media/video/tda9840.c
@@ -2,6 +2,7 @@
     tda9840 - i2c-driver for the tda9840 by SGS Thomson
 
     Copyright (C) 1998-2003 Michael Hunold <michael@mihu.de>
+    Copyright (C) 2008 Hans Verkuil <hverkuil@xs4all.nl>
 
     The tda9840 is a stereo/dual sound processor with digital
     identification. It can be found at address 0x84 on the i2c-bus.
@@ -28,59 +29,118 @@
 #include <linux/module.h>
 #include <linux/ioctl.h>
 #include <linux/i2c.h>
-
+#include <media/v4l2-common.h>
+#include <media/v4l2-i2c-drv-legacy.h>
 #include "tda9840.h"
 
-static int debug;		/* insmod parameter */
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "Turn on/off device debugging (default:off).");
+MODULE_AUTHOR("Michael Hunold <michael@mihu.de>");
+MODULE_DESCRIPTION("tda9840 driver");
+MODULE_LICENSE("GPL");
 
-#define dprintk(args...) \
-	    do { if (debug) { printk("%s: %s()[%d]: ", KBUILD_MODNAME, __func__, __LINE__); printk(args); } } while (0)
+static int debug;
+module_param(debug, int, 0644);
+
+MODULE_PARM_DESC(debug, "Debug level (0-1)");
 
 #define	SWITCH		0x00
 #define	LEVEL_ADJUST	0x02
 #define	STEREO_ADJUST	0x03
 #define	TEST		0x04
 
+#define TDA9840_SET_MUTE                0x00
+#define TDA9840_SET_MONO                0x10
+#define TDA9840_SET_STEREO              0x2a
+#define TDA9840_SET_LANG1               0x12
+#define TDA9840_SET_LANG2               0x1e
+#define TDA9840_SET_BOTH                0x1a
+#define TDA9840_SET_BOTH_R              0x16
+#define TDA9840_SET_EXTERNAL            0x7a
+
 /* addresses to scan, found only at 0x42 (7-Bit) */
 static unsigned short normal_i2c[] = { I2C_ADDR_TDA9840, I2C_CLIENT_END };
 
 /* magic definition of all other variables and things */
 I2C_CLIENT_INSMOD;
 
-static struct i2c_driver driver;
-static struct i2c_client client_template;
-
-static int command(struct i2c_client *client, unsigned int cmd, void *arg)
+static void tda9840_write(struct i2c_client *client, u8 reg, u8 val)
 {
-	int result;
+	if (i2c_smbus_write_byte_data(client, reg, val))
+		v4l_dbg(1, debug, client, "error writing %02x to %02x\n",
+				val, reg);
+}
+
+static int tda9840_command(struct i2c_client *client, unsigned cmd, void *arg)
+{
 	int byte = *(int *)arg;
 
 	switch (cmd) {
-	case TDA9840_SWITCH:
+	case VIDIOC_S_TUNER: {
+		struct v4l2_tuner *t = arg;
+		int byte;
 
-		dprintk("TDA9840_SWITCH: 0x%02x\n", byte);
+		if (t->index)
+			return -EINVAL;
 
-		if (byte != TDA9840_SET_MONO
-		    && byte != TDA9840_SET_MUTE
-		    && byte != TDA9840_SET_STEREO
-		    && byte != TDA9840_SET_LANG1
-		    && byte != TDA9840_SET_LANG2
-		    && byte != TDA9840_SET_BOTH
-		    && byte != TDA9840_SET_BOTH_R
-		    && byte != TDA9840_SET_EXTERNAL) {
+		switch (t->audmode) {
+		case V4L2_TUNER_MODE_STEREO:
+			byte = TDA9840_SET_STEREO;
+			break;
+		case V4L2_TUNER_MODE_LANG1_LANG2:
+			byte = TDA9840_SET_BOTH;
+			break;
+		case V4L2_TUNER_MODE_LANG1:
+			byte = TDA9840_SET_LANG1;
+			break;
+		case V4L2_TUNER_MODE_LANG2:
+			byte = TDA9840_SET_LANG2;
+			break;
+		default:
+			byte = TDA9840_SET_MONO;
+			break;
+		}
+		v4l_dbg(1, debug, client, "TDA9840_SWITCH: 0x%02x\n", byte);
+		tda9840_write(client, SWITCH, byte);
+		break;
+	}
+
+	case VIDIOC_G_TUNER: {
+		struct v4l2_tuner *t = arg;
+		u8 byte;
+
+		t->rxsubchans = V4L2_TUNER_SUB_MONO;
+		if (1 != i2c_master_recv(client, &byte, 1)) {
+			v4l_dbg(1, debug, client,
+				"i2c_master_recv() failed\n");
+			return -EIO;
+		}
+
+		if (byte & 0x80) {
+			v4l_dbg(1, debug, client,
+				"TDA9840_DETECT: register contents invalid\n");
 			return -EINVAL;
 		}
 
-		result = i2c_smbus_write_byte_data(client, SWITCH, byte);
-		if (result)
-			dprintk("i2c_smbus_write_byte() failed, ret:%d\n", result);
+		v4l_dbg(1, debug, client, "TDA9840_DETECT: byte: 0x%02x\n", byte);
+
+		switch (byte & 0x60) {
+		case 0x00:
+			t->rxsubchans = V4L2_TUNER_SUB_MONO;
+			break;
+		case 0x20:
+			t->rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
+			break;
+		case 0x40:
+			t->rxsubchans = V4L2_TUNER_SUB_STEREO | V4L2_TUNER_SUB_MONO;
+			break;
+		default: /* Incorrect detect */
+			t->rxsubchans = V4L2_TUNER_MODE_MONO;
+			break;
+		}
 		break;
+	}
 
 	case TDA9840_LEVEL_ADJUST:
-
-		dprintk("TDA9840_LEVEL_ADJUST: %d\n", byte);
+		v4l_dbg(1, debug, client, "TDA9840_LEVEL_ADJUST: %d\n", byte);
 
 		/* check for correct range */
 		if (byte > 25 || byte < -20)
@@ -92,15 +152,11 @@
 			byte += 0x8;
 		else
 			byte = -byte;
-
-		result = i2c_smbus_write_byte_data(client, LEVEL_ADJUST, byte);
-		if (result)
-			dprintk("i2c_smbus_write_byte() failed, ret:%d\n", result);
+		tda9840_write(client, LEVEL_ADJUST, byte);
 		break;
 
 	case TDA9840_STEREO_ADJUST:
-
-		dprintk("TDA9840_STEREO_ADJUST: %d\n", byte);
+		v4l_dbg(1, debug, client, "TDA9840_STEREO_ADJUST: %d\n", byte);
 
 		/* check for correct range */
 		if (byte > 25 || byte < -24)
@@ -113,143 +169,59 @@
 		else
 			byte = -byte;
 
-		result = i2c_smbus_write_byte_data(client, STEREO_ADJUST, byte);
-		if (result)
-			dprintk("i2c_smbus_write_byte() failed, ret:%d\n", result);
-		break;
-
-	case TDA9840_DETECT: {
-		int *ret = (int *)arg;
-
-		byte = i2c_smbus_read_byte_data(client, STEREO_ADJUST);
-		if (byte == -1) {
-			dprintk("i2c_smbus_read_byte_data() failed\n");
-			return -EIO;
-		}
-
-		if (0 != (byte & 0x80)) {
-			dprintk("TDA9840_DETECT: register contents invalid\n");
-			return -EINVAL;
-		}
-
-		dprintk("TDA9840_DETECT: byte: 0x%02x\n", byte);
-		*ret = ((byte & 0x60) >> 5);
-		result = 0;
-		break;
-	}
-	case TDA9840_TEST:
-		dprintk("TDA9840_TEST: 0x%02x\n", byte);
-
-		/* mask out irrelevant bits */
-		byte &= 0x3;
-
-		result = i2c_smbus_write_byte_data(client, TEST, byte);
-		if (result)
-			dprintk("i2c_smbus_write_byte() failed, ret:%d\n", result);
+		tda9840_write(client, STEREO_ADJUST, byte);
 		break;
 	default:
 		return -ENOIOCTLCMD;
 	}
 
-	if (result)
-		return -EIO;
-
 	return 0;
 }
 
-static int detect(struct i2c_adapter *adapter, int address, int kind)
+static int tda9840_probe(struct i2c_client *client,
+			  const struct i2c_device_id *id)
 {
-	struct i2c_client *client;
-	int result = 0;
-
-	int byte = 0x0;
+	int result;
+	int byte;
 
 	/* let's see whether this adapter can support what we need */
-	if (0 == i2c_check_functionality(adapter,
-				    I2C_FUNC_SMBUS_READ_BYTE_DATA |
-				    I2C_FUNC_SMBUS_WRITE_BYTE_DATA)) {
+	if (!i2c_check_functionality(client->adapter,
+			I2C_FUNC_SMBUS_READ_BYTE_DATA |
+			I2C_FUNC_SMBUS_WRITE_BYTE_DATA))
 		return 0;
-	}
 
-	/* allocate memory for client structure */
-	client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL);
-	if (!client) {
-		printk("not enough kernel memory\n");
-		return -ENOMEM;
-	}
-
-	/* fill client structure */
-	memcpy(client, &client_template, sizeof(struct i2c_client));
-	client->addr = address;
-	client->adapter = adapter;
-
-	/* tell the i2c layer a new client has arrived */
-	if (0 != (result = i2c_attach_client(client))) {
-		kfree(client);
-		return result;
-	}
+	v4l_info(client, "chip found @ 0x%x (%s)\n",
+			client->addr << 1, client->adapter->name);
 
 	/* set initial values for level & stereo - adjustment, mode */
 	byte = 0;
-	result  = command(client, TDA9840_LEVEL_ADJUST, &byte);
-	result += command(client, TDA9840_STEREO_ADJUST, &byte);
-	byte = TDA9840_SET_MONO;
-	result = command(client, TDA9840_SWITCH, &byte);
+	result = tda9840_command(client, TDA9840_LEVEL_ADJUST, &byte);
+	result += tda9840_command(client, TDA9840_STEREO_ADJUST, &byte);
+	tda9840_write(client, SWITCH, TDA9840_SET_STEREO);
 	if (result) {
-		dprintk("could not initialize tda9840\n");
+		v4l_dbg(1, debug, client, "could not initialize tda9840\n");
 		return -ENODEV;
 	}
-
-	printk("tda9840: detected @ 0x%02x on adapter %s\n", address, &client->adapter->name[0]);
 	return 0;
 }
 
-static int attach(struct i2c_adapter *adapter)
+static int tda9840_legacy_probe(struct i2c_adapter *adapter)
 {
-	/* let's see whether this is a know adapter we can attach to */
-	if (adapter->id != I2C_HW_SAA7146) {
-		dprintk("refusing to probe on unknown adapter [name='%s',id=0x%x]\n", adapter->name, adapter->id);
-		return -ENODEV;
-	}
-
-	return i2c_probe(adapter, &addr_data, &detect);
+	/* Let's see whether this is a known adapter we can attach to.
+	   Prevents conflicts with tvaudio.c. */
+	return adapter->id == I2C_HW_SAA7146;
 }
-
-static int detach(struct i2c_client *client)
-{
-	int ret = i2c_detach_client(client);
-	kfree(client);
-	return ret;
-}
-
-static struct i2c_driver driver = {
-	.driver = {
-		.name = "tda9840",
-	},
-	.id	= I2C_DRIVERID_TDA9840,
-	.attach_adapter	= attach,
-	.detach_client	= detach,
-	.command	= command,
+static const struct i2c_device_id tda9840_id[] = {
+	{ "tda9840", 0 },
+	{ }
 };
+MODULE_DEVICE_TABLE(i2c, tda9840_id);
 
-static struct i2c_client client_template = {
+static struct v4l2_i2c_driver_data v4l2_i2c_data = {
 	.name = "tda9840",
-	.driver = &driver,
+	.driverid = I2C_DRIVERID_TDA9840,
+	.command = tda9840_command,
+	.probe = tda9840_probe,
+	.legacy_probe = tda9840_legacy_probe,
+	.id_table = tda9840_id,
 };
-
-static int __init this_module_init(void)
-{
-	return i2c_add_driver(&driver);
-}
-
-static void __exit this_module_exit(void)
-{
-	i2c_del_driver(&driver);
-}
-
-module_init(this_module_init);
-module_exit(this_module_exit);
-
-MODULE_AUTHOR("Michael Hunold <michael@mihu.de>");
-MODULE_DESCRIPTION("tda9840 driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/tda9840.h b/drivers/media/video/tda9840.h
index 7da8432..dc12ae7 100644
--- a/drivers/media/video/tda9840.h
+++ b/drivers/media/video/tda9840.h
@@ -3,24 +3,6 @@
 
 #define	I2C_ADDR_TDA9840		0x42
 
-#define TDA9840_DETECT		_IOR('v',1,int)
-/* return values for TDA9840_DETCT */
-#define TDA9840_MONO_DETECT		0x0
-#define	TDA9840_DUAL_DETECT		0x1
-#define	TDA9840_STEREO_DETECT		0x2
-#define	TDA9840_INCORRECT_DETECT	0x3
-
-#define TDA9840_SWITCH		_IOW('v',2,int)
-/* modes than can be set with TDA9840_SWITCH */
-#define	TDA9840_SET_MUTE		0x00
-#define	TDA9840_SET_MONO		0x10
-#define	TDA9840_SET_STEREO		0x2a
-#define	TDA9840_SET_LANG1		0x12
-#define	TDA9840_SET_LANG2		0x1e
-#define	TDA9840_SET_BOTH		0x1a
-#define	TDA9840_SET_BOTH_R		0x16
-#define	TDA9840_SET_EXTERNAL		0x7a
-
 /* values may range between +2.5 and -2.0;
    the value has to be multiplied with 10 */
 #define TDA9840_LEVEL_ADJUST	_IOW('v',3,int)
@@ -29,7 +11,4 @@
    the value has to be multiplied with 10 */
 #define TDA9840_STEREO_ADJUST	_IOW('v',4,int)
 
-/* currently not implemented */
-#define TDA9840_TEST		_IOW('v',5,int)
-
 #endif
diff --git a/drivers/media/video/tea6415c.c b/drivers/media/video/tea6415c.c
index 421c144..cde092a 100644
--- a/drivers/media/video/tea6415c.c
+++ b/drivers/media/video/tea6415c.c
@@ -2,6 +2,7 @@
     tea6415c - i2c-driver for the tea6415c by SGS Thomson
 
     Copyright (C) 1998-2003 Michael Hunold <michael@mihu.de>
+    Copyright (C) 2008 Hans Verkuil <hverkuil@xs4all.nl>
 
     The tea6415c is a bus controlled video-matrix-switch
     with 8 inputs and 6 outputs.
@@ -30,18 +31,18 @@
 #include <linux/module.h>
 #include <linux/ioctl.h>
 #include <linux/i2c.h>
-
+#include <media/v4l2-common.h>
+#include <media/v4l2-i2c-drv-legacy.h>
 #include "tea6415c.h"
 
-static int debug;		/* insmod parameter */
+MODULE_AUTHOR("Michael Hunold <michael@mihu.de>");
+MODULE_DESCRIPTION("tea6415c driver");
+MODULE_LICENSE("GPL");
+
+static int debug;
 module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "Turn on/off device debugging (default:off).");
 
-#define dprintk(args...) \
-	    do { if (debug) { printk("%s: %s()[%d]: ", KBUILD_MODNAME, __func__, __LINE__); printk(args); } } while (0)
-
-#define TEA6415C_NUM_INPUTS	8
-#define TEA6415C_NUM_OUTPUTS	6
+MODULE_PARM_DESC(debug, "Debug level (0-1)");
 
 /* addresses to scan, found only at 0x03 and/or 0x43 (7-bit) */
 static unsigned short normal_i2c[] = { I2C_TEA6415C_1, I2C_TEA6415C_2, I2C_CLIENT_END };
@@ -49,60 +50,6 @@
 /* magic definition of all other variables and things */
 I2C_CLIENT_INSMOD;
 
-static struct i2c_driver driver;
-static struct i2c_client client_template;
-
-/* this function is called by i2c_probe */
-static int detect(struct i2c_adapter *adapter, int address, int kind)
-{
-	struct i2c_client *client = NULL;
-	int err = 0;
-
-	/* let's see whether this adapter can support what we need */
-	if (0 == i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WRITE_BYTE)) {
-		return 0;
-	}
-
-	/* allocate memory for client structure */
-	client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL);
-	if (!client) {
-		return -ENOMEM;
-	}
-
-	/* fill client structure */
-	memcpy(client, &client_template, sizeof(struct i2c_client));
-	client->addr = address;
-	client->adapter = adapter;
-
-	/* tell the i2c layer a new client has arrived */
-	if (0 != (err = i2c_attach_client(client))) {
-		kfree(client);
-		return err;
-	}
-
-	printk("tea6415c: detected @ 0x%02x on adapter %s\n", address, &client->adapter->name[0]);
-
-	return 0;
-}
-
-static int attach(struct i2c_adapter *adapter)
-{
-	/* let's see whether this is a know adapter we can attach to */
-	if (adapter->id != I2C_HW_SAA7146) {
-		dprintk("refusing to probe on unknown adapter [name='%s',id=0x%x]\n", adapter->name, adapter->id);
-		return -ENODEV;
-	}
-
-	return i2c_probe(adapter, &addr_data, &detect);
-}
-
-static int detach(struct i2c_client *client)
-{
-	int ret = i2c_detach_client(client);
-	kfree(client);
-	return ret;
-}
-
 /* makes a connection between the input-pin 'i' and the output-pin 'o'
    for the tea6415c-client 'client' */
 static int switch_matrix(struct i2c_client *client, int i, int o)
@@ -110,7 +57,7 @@
 	u8 byte = 0;
 	int ret;
 
-	dprintk("adr:0x%02x, i:%d, o:%d\n", client->addr, i, o);
+	v4l_dbg(1, debug, client, "i=%d, o=%d\n", i, o);
 
 	/* check if the pins are valid */
 	if (0 == ((1 == i ||  3 == i ||  5 == i ||  6 == i ||  8 == i || 10 == i || 20 == i || 11 == i)
@@ -168,14 +115,14 @@
 
 	ret = i2c_smbus_write_byte(client, byte);
 	if (ret) {
-		dprintk("i2c_smbus_write_byte() failed, ret:%d\n", ret);
+		v4l_dbg(1, debug, client,
+			"i2c_smbus_write_byte() failed, ret:%d\n", ret);
 		return -EIO;
 	}
-
 	return ret;
 }
 
-static int command(struct i2c_client *client, unsigned int cmd, void *arg)
+static int tea6415c_command(struct i2c_client *client, unsigned cmd, void *arg)
 {
 	struct tea6415c_multiplex *v = (struct tea6415c_multiplex *)arg;
 	int result = 0;
@@ -187,38 +134,40 @@
 	default:
 		return -ENOIOCTLCMD;
 	}
-
 	return result;
 }
 
-static struct i2c_driver driver = {
-	.driver = {
-		.name = "tea6415c",
-	},
-	.id 	= I2C_DRIVERID_TEA6415C,
-	.attach_adapter	= attach,
-	.detach_client	= detach,
-	.command	= command,
-};
+/* this function is called by i2c_probe */
+static int tea6415c_probe(struct i2c_client *client,
+			  const struct i2c_device_id *id)
+{
+	/* let's see whether this adapter can support what we need */
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WRITE_BYTE))
+		return 0;
 
-static struct i2c_client client_template = {
+	v4l_info(client, "chip found @ 0x%x (%s)\n",
+			client->addr << 1, client->adapter->name);
+	return 0;
+}
+
+static int tea6415c_legacy_probe(struct i2c_adapter *adapter)
+{
+	/* Let's see whether this is a known adapter we can attach to.
+	   Prevents conflicts with tvaudio.c. */
+	return adapter->id == I2C_HW_SAA7146;
+}
+
+static const struct i2c_device_id tea6415c_id[] = {
+	{ "tea6415c", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, tea6415c_id);
+
+static struct v4l2_i2c_driver_data v4l2_i2c_data = {
 	.name = "tea6415c",
-	.driver = &driver,
+	.driverid = I2C_DRIVERID_TEA6415C,
+	.command = tea6415c_command,
+	.probe = tea6415c_probe,
+	.legacy_probe = tea6415c_legacy_probe,
+	.id_table = tea6415c_id,
 };
-
-static int __init this_module_init(void)
-{
-	return i2c_add_driver(&driver);
-}
-
-static void __exit this_module_exit(void)
-{
-	i2c_del_driver(&driver);
-}
-
-module_init(this_module_init);
-module_exit(this_module_exit);
-
-MODULE_AUTHOR("Michael Hunold <michael@mihu.de>");
-MODULE_DESCRIPTION("tea6415c driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/tea6420.c b/drivers/media/video/tea6420.c
index b5c8957..e508209 100644
--- a/drivers/media/video/tea6420.c
+++ b/drivers/media/video/tea6420.c
@@ -2,6 +2,7 @@
     tea6420 - i2c-driver for the tea6420 by SGS Thomson
 
     Copyright (C) 1998-2003 Michael Hunold <michael@mihu.de>
+    Copyright (C) 2008 Hans Verkuil <hverkuil@xs4all.nl>
 
     The tea6420 is a bus controlled audio-matrix with 5 stereo inputs,
     4 stereo outputs and gain control for each output.
@@ -30,15 +31,18 @@
 #include <linux/module.h>
 #include <linux/ioctl.h>
 #include <linux/i2c.h>
-
+#include <media/v4l2-common.h>
+#include <media/v4l2-i2c-drv-legacy.h>
 #include "tea6420.h"
 
-static int debug;		/* insmod parameter */
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "Turn on/off device debugging (default:off).");
+MODULE_AUTHOR("Michael Hunold <michael@mihu.de>");
+MODULE_DESCRIPTION("tea6420 driver");
+MODULE_LICENSE("GPL");
 
-#define dprintk(args...) \
-	    do { if (debug) { printk("%s: %s()[%d]: ", KBUILD_MODNAME, __func__, __LINE__); printk(args); } } while (0)
+static int debug;
+module_param(debug, int, 0644);
+
+MODULE_PARM_DESC(debug, "Debug level (0-1)");
 
 /* addresses to scan, found only at 0x4c and/or 0x4d (7-Bit) */
 static unsigned short normal_i2c[] = { I2C_ADDR_TEA6420_1, I2C_ADDR_TEA6420_2, I2C_CLIENT_END };
@@ -46,23 +50,20 @@
 /* magic definition of all other variables and things */
 I2C_CLIENT_INSMOD;
 
-static struct i2c_driver driver;
-static struct i2c_client client_template;
-
 /* make a connection between the input 'i' and the output 'o'
    with gain 'g' for the tea6420-client 'client' (note: i = 6 means 'mute') */
 static int tea6420_switch(struct i2c_client *client, int i, int o, int g)
 {
-	u8 byte = 0;
+	u8 byte;
 	int ret;
 
-	dprintk("adr:0x%02x, i:%d, o:%d, g:%d\n", client->addr, i, o, g);
+	v4l_dbg(1, debug, client, "i=%d, o=%d, g=%d\n", i, o, g);
 
 	/* check if the parameters are valid */
 	if (i < 1 || i > 6 || o < 1 || o > 4 || g < 0 || g > 6 || g % 2 != 0)
 		return -1;
 
-	byte  = ((o - 1) << 5);
+	byte = ((o - 1) << 5);
 	byte |= (i - 1);
 
 	/* to understand this, have a look at the tea6420-specs (p.5) */
@@ -82,76 +83,14 @@
 
 	ret = i2c_smbus_write_byte(client, byte);
 	if (ret) {
-		dprintk("i2c_smbus_write_byte() failed, ret:%d\n", ret);
+		v4l_dbg(1, debug, client,
+			"i2c_smbus_write_byte() failed, ret:%d\n", ret);
 		return -EIO;
 	}
-
 	return 0;
 }
 
-/* this function is called by i2c_probe */
-static int tea6420_detect(struct i2c_adapter *adapter, int address, int kind)
-{
-	struct i2c_client *client;
-	int err = 0, i = 0;
-
-	/* let's see whether this adapter can support what we need */
-	if (0 == i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WRITE_BYTE)) {
-		return 0;
-	}
-
-	/* allocate memory for client structure */
-	client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
-	if (!client) {
-		return -ENOMEM;
-	}
-
-	/* fill client structure */
-	memcpy(client, &client_template, sizeof(struct i2c_client));
-	client->addr = address;
-	client->adapter = adapter;
-
-	/* tell the i2c layer a new client has arrived */
-	if (0 != (err = i2c_attach_client(client))) {
-		kfree(client);
-		return err;
-	}
-
-	/* set initial values: set "mute"-input to all outputs at gain 0 */
-	err = 0;
-	for (i = 1; i < 5; i++) {
-		err += tea6420_switch(client, 6, i, 0);
-	}
-	if (err) {
-		dprintk("could not initialize tea6420\n");
-		kfree(client);
-		return -ENODEV;
-	}
-
-	printk("tea6420: detected @ 0x%02x on adapter %s\n", address, &client->adapter->name[0]);
-
-	return 0;
-}
-
-static int attach(struct i2c_adapter *adapter)
-{
-	/* let's see whether this is a know adapter we can attach to */
-	if (adapter->id != I2C_HW_SAA7146) {
-		dprintk("refusing to probe on unknown adapter [name='%s',id=0x%x]\n", adapter->name, adapter->id);
-		return -ENODEV;
-	}
-
-	return i2c_probe(adapter, &addr_data, &tea6420_detect);
-}
-
-static int detach(struct i2c_client *client)
-{
-	int ret = i2c_detach_client(client);
-	kfree(client);
-	return ret;
-}
-
-static int command(struct i2c_client *client, unsigned int cmd, void *arg)
+static int tea6420_command(struct i2c_client *client, unsigned cmd, void *arg)
 {
 	struct tea6420_multiplex *a = (struct tea6420_multiplex *)arg;
 	int result = 0;
@@ -167,34 +106,50 @@
 	return result;
 }
 
-static struct i2c_driver driver = {
-	.driver = {
-		.name = "tea6420",
-	},
-	.id	= I2C_DRIVERID_TEA6420,
-	.attach_adapter	= attach,
-	.detach_client	= detach,
-	.command	= command,
-};
+/* this function is called by i2c_probe */
+static int tea6420_probe(struct i2c_client *client,
+			  const struct i2c_device_id *id)
+{
+	int err, i;
 
-static struct i2c_client client_template = {
+	/* let's see whether this adapter can support what we need */
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WRITE_BYTE))
+		return -EIO;
+
+	v4l_info(client, "chip found @ 0x%x (%s)\n",
+			client->addr << 1, client->adapter->name);
+
+	/* set initial values: set "mute"-input to all outputs at gain 0 */
+	err = 0;
+	for (i = 1; i < 5; i++) {
+		err += tea6420_switch(client, 6, i, 0);
+	}
+	if (err) {
+		v4l_dbg(1, debug, client, "could not initialize tea6420\n");
+		kfree(client);
+		return -ENODEV;
+	}
+	return 0;
+}
+
+static int tea6420_legacy_probe(struct i2c_adapter *adapter)
+{
+	/* Let's see whether this is a known adapter we can attach to.
+	   Prevents conflicts with tvaudio.c. */
+	return adapter->id == I2C_HW_SAA7146;
+}
+
+static const struct i2c_device_id tea6420_id[] = {
+	{ "tea6420", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, tea6420_id);
+
+static struct v4l2_i2c_driver_data v4l2_i2c_data = {
 	.name = "tea6420",
-	.driver = &driver,
+	.driverid = I2C_DRIVERID_TEA6420,
+	.command = tea6420_command,
+	.probe = tea6420_probe,
+	.legacy_probe = tea6420_legacy_probe,
+	.id_table = tea6420_id,
 };
-
-static int __init this_module_init(void)
-{
-	return i2c_add_driver(&driver);
-}
-
-static void __exit this_module_exit(void)
-{
-	i2c_del_driver(&driver);
-}
-
-module_init(this_module_init);
-module_exit(this_module_exit);
-
-MODULE_AUTHOR("Michael Hunold <michael@mihu.de>");
-MODULE_DESCRIPTION("tea6420 driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/tuner-3036.c b/drivers/media/video/tuner-3036.c
deleted file mode 100644
index bdf506e..0000000
--- a/drivers/media/video/tuner-3036.c
+++ /dev/null
@@ -1,214 +0,0 @@
-/*
- * Driver for Philips SAB3036 "CITAC" tuner control chip.
- *
- * Author: Phil Blundell <philb@gnu.org>
- *
- * The SAB3036 is just about different enough from the chips that
- * tuner.c copes with to make it not worth the effort to crowbar
- * the support into that file.  So instead we have a separate 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.
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/string.h>
-#include <linux/timer.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-
-#include <linux/i2c.h>
-#include <linux/videodev.h>
-#include <media/v4l2-common.h>
-
-#include <media/tuner.h>
-
-static int debug;	/* insmod parameter */
-static int this_adap;
-
-static struct i2c_client client_template;
-
-/* Addresses to scan */
-static unsigned short normal_i2c[] = { 0x60, 0x61, I2C_CLIENT_END };
-static unsigned short ignore = I2C_CLIENT_END;
-
-static struct i2c_client_address_data addr_data = {
-	.normal_i2c	= normal_i2c,
-	.probe		= &ignore,
-	.ignore		= &ignore,
-};
-
-/* ---------------------------------------------------------------------- */
-
-static unsigned char
-tuner_getstatus (struct i2c_client *c)
-{
-	unsigned char byte;
-	if (i2c_master_recv(c, &byte, 1) != 1)
-		printk(KERN_ERR "tuner-3036: I/O error.\n");
-	return byte;
-}
-
-#define TUNER_FL        0x80
-
-static int
-tuner_islocked (struct i2c_client *c)
-{
-	return (tuner_getstatus(c) & TUNER_FL);
-}
-
-/* ---------------------------------------------------------------------- */
-
-static void
-set_tv_freq(struct i2c_client *c, int freq)
-{
-	u16 div = ((freq * 20) / 16);
-	unsigned long give_up = jiffies + HZ;
-	unsigned char buffer[2];
-
-	if (debug)
-		printk(KERN_DEBUG "tuner: setting frequency %dMHz, divisor %x\n", freq / 16, div);
-
-	/* Select high tuning current */
-	buffer[0] = 0x29;
-	buffer[1] = 0x3e;
-
-	if (i2c_master_send(c, buffer, 2) != 2)
-		printk("tuner: i2c i/o error 1\n");
-
-	buffer[0] = 0x80 | ((div>>8) & 0x7f);
-	buffer[1] = div & 0xff;
-
-	if (i2c_master_send(c, buffer, 2) != 2)
-		printk("tuner: i2c i/o error 2\n");
-
-	while (!tuner_islocked(c) && time_before(jiffies, give_up))
-		schedule();
-
-	if (!tuner_islocked(c))
-		printk(KERN_WARNING "tuner: failed to achieve PLL lock\n");
-
-	/* Select low tuning current and engage AFC */
-	buffer[0] = 0x29;
-	buffer[1] = 0xb2;
-
-	if (i2c_master_send(c, buffer, 2) != 2)
-		printk("tuner: i2c i/o error 3\n");
-
-	if (debug)
-		printk(KERN_DEBUG "tuner: status %02x\n", tuner_getstatus(c));
-}
-
-/* ---------------------------------------------------------------------- */
-
-static int
-tuner_attach(struct i2c_adapter *adap, int addr, int kind)
-{
-	static unsigned char buffer[] = { 0x29, 0x32, 0x2a, 0, 0x2b, 0 };
-
-	struct i2c_client *client;
-
-	if (this_adap > 0)
-		return -1;
-	this_adap++;
-
-	client_template.adapter = adap;
-	client_template.addr = addr;
-
-	client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL);
-	if (client == NULL)
-		return -ENOMEM;
-	memcpy(client, &client_template, sizeof(struct i2c_client));
-
-	printk("tuner: SAB3036 found, status %02x\n", tuner_getstatus(client));
-
-	i2c_attach_client(client);
-
-	if (i2c_master_send(client, buffer, 2) != 2)
-		printk("tuner: i2c i/o error 1\n");
-	if (i2c_master_send(client, buffer+2, 2) != 2)
-		printk("tuner: i2c i/o error 2\n");
-	if (i2c_master_send(client, buffer+4, 2) != 2)
-		printk("tuner: i2c i/o error 3\n");
-	return 0;
-}
-
-static int
-tuner_detach(struct i2c_client *c)
-{
-	return 0;
-}
-
-static int
-tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
-{
-	int *iarg = (int*)arg;
-
-	switch (cmd)
-	{
-		case VIDIOCSFREQ:
-			set_tv_freq(client, *iarg);
-			break;
-
-		default:
-			return -EINVAL;
-	}
-	return 0;
-}
-
-static int
-tuner_probe(struct i2c_adapter *adap)
-{
-	this_adap = 0;
-	if (adap->id == I2C_HW_B_LP)
-		return i2c_probe(adap, &addr_data, tuner_attach);
-	return 0;
-}
-
-/* ----------------------------------------------------------------------- */
-
-static struct i2c_driver
-i2c_driver_tuner =
-{
-	.driver = {
-		.name	=	"sab3036",
-	},
-	.id		=	I2C_DRIVERID_SAB3036,
-	.attach_adapter =	tuner_probe,
-	.detach_client  =	tuner_detach,
-	.command	=	tuner_command
-};
-
-static struct i2c_client client_template =
-{
-	.driver		= &i2c_driver_tuner,
-	.name		= "SAB3036",
-};
-
-static int __init
-tuner3036_init(void)
-{
-	return i2c_add_driver(&i2c_driver_tuner);
-}
-
-static void __exit
-tuner3036_exit(void)
-{
-	i2c_del_driver(&i2c_driver_tuner);
-}
-
-MODULE_DESCRIPTION("SAB3036 tuner driver");
-MODULE_AUTHOR("Philip Blundell <philb@gnu.org>");
-MODULE_LICENSE("GPL");
-
-module_param(debug, int, 0);
-MODULE_PARM_DESC(debug,"Enable debugging output");
-
-module_init(tuner3036_init);
-module_exit(tuner3036_exit);
diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c
index d806a35..4a7735c 100644
--- a/drivers/media/video/tuner-core.c
+++ b/drivers/media/video/tuner-core.c
@@ -92,7 +92,6 @@
 
 	unsigned int        type; /* chip type id */
 	unsigned int        config;
-	int (*tuner_callback) (void *dev, int command, int arg);
 	const char          *name;
 };
 
@@ -346,7 +345,7 @@
 
 static void set_type(struct i2c_client *c, unsigned int type,
 		     unsigned int new_mode_mask, unsigned int new_config,
-		     int (*tuner_callback) (void *dev, int command,int arg))
+		     int (*tuner_callback) (void *dev, int component, int cmd, int arg))
 {
 	struct tuner *t = i2c_get_clientdata(c);
 	struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops;
@@ -362,7 +361,7 @@
 	t->config = new_config;
 	if (tuner_callback != NULL) {
 		tuner_dbg("defining GPIO callback\n");
-		t->tuner_callback = tuner_callback;
+		t->fe.callback = tuner_callback;
 	}
 
 	if (t->mode == T_UNINITIALIZED) {
@@ -385,7 +384,6 @@
 	{
 		struct tda829x_config cfg = {
 			.lna_cfg        = t->config,
-			.tuner_callback = t->tuner_callback,
 		};
 		if (!dvb_attach(tda829x_attach, &t->fe, t->i2c->adapter,
 				t->i2c->addr, &cfg))
@@ -433,7 +431,6 @@
 		struct xc2028_config cfg = {
 			.i2c_adap  = t->i2c->adapter,
 			.i2c_addr  = t->i2c->addr,
-			.callback  = t->tuner_callback,
 		};
 		if (!dvb_attach(xc2028_attach, &t->fe, &cfg))
 			goto attach_failed;
@@ -450,10 +447,8 @@
 
 		xc5000_cfg.i2c_address	  = t->i2c->addr;
 		xc5000_cfg.if_khz	  = 5380;
-		xc5000_cfg.tuner_callback = t->tuner_callback;
 		if (!dvb_attach(xc5000_attach,
-				&t->fe, t->i2c->adapter, &xc5000_cfg,
-				c->adapter->algo_data))
+				&t->fe, t->i2c->adapter, &xc5000_cfg))
 			goto attach_failed;
 
 		xc_tuner_ops = &t->fe.ops.tuner_ops;
@@ -1225,7 +1220,7 @@
 	} else {
 		t->mode = V4L2_TUNER_DIGITAL_TV;
 	}
-	set_type(client, t->type, t->mode_mask, t->config, t->tuner_callback);
+	set_type(client, t->type, t->mode_mask, t->config, t->fe.callback);
 	list_add_tail(&t->list, &tuner_list);
 	return 0;
 }
diff --git a/drivers/media/video/tvaudio.c b/drivers/media/video/tvaudio.c
index 463680b..b59e472 100644
--- a/drivers/media/video/tvaudio.c
+++ b/drivers/media/video/tvaudio.c
@@ -1792,7 +1792,7 @@
 		break;
 	case VIDIOC_S_FREQUENCY:
 		chip->mode = 0; /* automatic */
-		if (desc->checkmode) {
+		if (desc->checkmode && desc->setmode) {
 			desc->setmode(chip,V4L2_TUNER_MODE_MONO);
 			if (chip->prevmode != V4L2_TUNER_MODE_MONO)
 				chip->prevmode = -1; /* reset previous mode */
diff --git a/drivers/media/video/usbvideo/ibmcam.c b/drivers/media/video/usbvideo/ibmcam.c
index cc27efe..28421d3 100644
--- a/drivers/media/video/usbvideo/ibmcam.c
+++ b/drivers/media/video/usbvideo/ibmcam.c
@@ -258,7 +258,9 @@
 			    (RING_QUEUE_PEEK(&uvd->dp, 2) == 0x00))
 			{
 #if 0				/* This code helps to detect new frame markers */
-				info("Header sig: 00 FF 00 %02X", RING_QUEUE_PEEK(&uvd->dp, 3));
+				dev_info(&uvd->dev->dev,
+					 "Header sig: 00 FF 00 %02X\n",
+					 RING_QUEUE_PEEK(&uvd->dp, 3));
 #endif
 				frame->header = RING_QUEUE_PEEK(&uvd->dp, 3);
 				if ((frame->header == HDRSIG_MODEL1_128x96) ||
@@ -266,7 +268,8 @@
 				    (frame->header == HDRSIG_MODEL1_352x288))
 				{
 #if 0
-					info("Header found.");
+					dev_info(&uvd->dev->dev,
+						 "Header found.\n");
 #endif
 					RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, marker_len);
 					icam->has_hdr = 1;
@@ -295,7 +298,7 @@
 			    (RING_QUEUE_PEEK(&uvd->dp, 1) == 0xFF))
 			{
 #if 0
-				info("Header found.");
+				dev_info(&uvd->dev->dev, "Header found.\n");
 #endif
 				RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, marker_len);
 				icam->has_hdr = 1;
@@ -338,7 +341,7 @@
 				byte4 = RING_QUEUE_PEEK(&uvd->dp, 3);
 				frame->header = (byte3 << 8) | byte4;
 #if 0
-				info("Header found.");
+				dev_info(&uvd->dev->dev, "Header found.\n");
 #endif
 				RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, marker_len);
 				icam->has_hdr = 1;
@@ -354,7 +357,8 @@
 	}
 	if (!icam->has_hdr) {
 		if (uvd->debug > 2)
-			info("Skipping frame, no header");
+			dev_info(&uvd->dev->dev,
+				 "Skipping frame, no header\n");
 		return scan_EndParse;
 	}
 
@@ -881,7 +885,9 @@
 	 */
 	if ((frame->curline + 1) >= data_h) {
 		if (uvd->debug >= 3)
-			info("Reached line %d. (frame is done)", frame->curline);
+			dev_info(&uvd->dev->dev,
+				 "Reached line %d. (frame is done)\n",
+				 frame->curline);
 		return scan_NextFrame;
 	}
 
@@ -954,8 +960,9 @@
 
 	if (frame->curline >= VIDEOSIZE_Y(frame->request)) {
 		if (uvd->debug >= 3) {
-			info("All requested lines (%ld.) done.",
-			     VIDEOSIZE_Y(frame->request));
+			dev_info(&uvd->dev->dev,
+				 "All requested lines (%ld.) done.\n",
+				 VIDEOSIZE_Y(frame->request));
 		}
 		return scan_NextFrame;
 	} else
@@ -1000,7 +1007,9 @@
 	 */
 	if ((frame->curline + 1) >= data_h) {
 		if (uvd->debug >= 3)
-			info("Reached line %d. (frame is done)", frame->curline);
+			dev_info(&uvd->dev->dev,
+				 "Reached line %d. (frame is done)\n",
+				 frame->curline);
 		return scan_NextFrame;
 	}
 
@@ -1049,8 +1058,9 @@
 
 	if (frame->curline >= VIDEOSIZE_Y(frame->request)) {
 		if (uvd->debug >= 3) {
-			info("All requested lines (%ld.) done.",
-			     VIDEOSIZE_Y(frame->request));
+			dev_info(&uvd->dev->dev,
+				 "All requested lines (%ld.) done.\n",
+				 VIDEOSIZE_Y(frame->request));
 		}
 		return scan_NextFrame;
 	} else
@@ -1171,10 +1181,11 @@
 			sizeof(cp),
 			1000);
 #if 0
-		info("USB => %02x%02x%02x%02x%02x%02x%02x%02x "
-		       "(req=$%02x val=$%04x ind=$%04x)",
-		       cp[0],cp[1],cp[2],cp[3],cp[4],cp[5],cp[6],cp[7],
-		       req, value, index);
+		dev_info(&uvd->dev->dev,
+			 "USB => %02x%02x%02x%02x%02x%02x%02x%02x "
+			 "(req=$%02x val=$%04x ind=$%04x)\n",
+			 cp[0],cp[1],cp[2],cp[3],cp[4],cp[5],cp[6],cp[7],
+			 req, value, index);
 #endif
 	} else {
 		i = usb_control_msg(
@@ -1449,10 +1460,9 @@
  */
 static void ibmcam_change_lighting_conditions(struct uvd *uvd)
 {
-	static const char proc[] = "ibmcam_change_lighting_conditions";
-
 	if (debug > 0)
-		info("%s: Set lighting to %hu.", proc, lighting);
+		dev_info(&uvd->dev->dev,
+			 "%s: Set lighting to %hu.\n", __func__, lighting);
 
 	switch (IBMCAM_T(uvd)->camera_model) {
 	case IBMCAM_MODEL_1:
@@ -1495,8 +1505,6 @@
  */
 static void ibmcam_set_sharpness(struct uvd *uvd)
 {
-	static const char proc[] = "ibmcam_set_sharpness";
-
 	switch (IBMCAM_T(uvd)->camera_model) {
 	case IBMCAM_MODEL_1:
 	{
@@ -1505,7 +1513,8 @@
 
 		RESTRICT_TO_RANGE(sharpness, SHARPNESS_MIN, SHARPNESS_MAX);
 		if (debug > 0)
-			info("%s: Set sharpness to %hu.", proc, sharpness);
+			dev_info(&uvd->dev->dev, "%s: Set sharpness to %hu.\n",
+				 __func__, sharpness);
 
 		sv = sa[sharpness - SHARPNESS_MIN];
 		for (i=0; i < 2; i++) {
@@ -1564,11 +1573,11 @@
  */
 static void ibmcam_set_brightness(struct uvd *uvd)
 {
-	static const char proc[] = "ibmcam_set_brightness";
 	static const unsigned short n = 1;
 
 	if (debug > 0)
-		info("%s: Set brightness to %hu.", proc, uvd->vpic.brightness);
+		dev_info(&uvd->dev->dev, "%s: Set brightness to %hu.\n",
+			 __func__, uvd->vpic.brightness);
 
 	switch (IBMCAM_T(uvd)->camera_model) {
 	case IBMCAM_MODEL_1:
@@ -2115,7 +2124,8 @@
 			break;
 		}
 		if (uvd->debug > 0)
-			info("Framerate (hardware): %hd.", hw_fps);
+			dev_info(&uvd->dev->dev, "Framerate (hardware): %hd.\n",
+				 hw_fps);
 		RESTRICT_TO_RANGE(hw_fps, 0, 31);
 		ibmcam_model2_Packet1(uvd, mod2_set_framerate, hw_fps);
 	}
@@ -3487,7 +3497,7 @@
 	/* 01.01.08 - Added for RCA video in support -LO */
 	if(init_model3_input) {
 		if (debug > 0)
-			info("Setting input to RCA.");
+			dev_info(&uvd->dev->dev, "Setting input to RCA.\n");
 		for (i=0; i < ARRAY_SIZE(initData); i++) {
 			ibmcam_veio(uvd, initData[i].req, initData[i].value, initData[i].index);
 		}
@@ -3685,7 +3695,7 @@
 	unsigned char video_ep = 0;
 
 	if (debug >= 1)
-		info("ibmcam_probe(%p,%u.)", intf, ifnum);
+		dev_info(&uvd->dev->dev, "ibmcam_probe(%p,%u.)\n", intf, ifnum);
 
 	/* We don't handle multi-config cameras */
 	if (dev->descriptor.bNumConfigurations != 1)
@@ -3736,14 +3746,16 @@
 			brand = "IBM PC Camera"; /* a.k.a. Xirlink C-It */
 			break;
 		}
-		info("%s USB camera found (model %d, rev. 0x%04x)",
-		     brand, model, le16_to_cpu(dev->descriptor.bcdDevice));
+		dev_info(&uvd->dev->dev,
+			 "%s USB camera found (model %d, rev. 0x%04x)\n",
+			 brand, model, le16_to_cpu(dev->descriptor.bcdDevice));
 	} while (0);
 
 	/* Validate found interface: must have one ISO endpoint */
 	nas = intf->num_altsetting;
 	if (debug > 0)
-		info("Number of alternate settings=%d.", nas);
+		dev_info(&uvd->dev->dev, "Number of alternate settings=%d.\n",
+			 nas);
 	if (nas < 2) {
 		err("Too few alternate settings for this camera!");
 		return -ENODEV;
@@ -3787,7 +3799,9 @@
 				actInterface = i;
 				maxPS = le16_to_cpu(endpoint->wMaxPacketSize);
 				if (debug > 0)
-					info("Active setting=%d. maxPS=%d.", i, maxPS);
+					dev_info(&uvd->dev->dev,
+						 "Active setting=%d. "
+						 "maxPS=%d.\n", i, maxPS);
 			} else
 				err("More than one active alt. setting! Ignoring #%d.", i);
 		}
@@ -3826,7 +3840,7 @@
 			RESTRICT_TO_RANGE(framerate, 0, 5);
 			break;
 		default:
-			info("IBM camera: using 320x240");
+			dev_info(&uvd->dev->dev, "IBM camera: using 320x240\n");
 			size = SIZE_320x240;
 			/* No break here */
 		case SIZE_320x240:
@@ -3855,7 +3869,7 @@
 			canvasY = 120;
 			break;
 		default:
-			info("IBM NetCamera: using 176x144");
+			dev_info(&uvd->dev->dev, "IBM NetCamera: using 176x144\n");
 			size = SIZE_176x144;
 			/* No break here */
 		case SIZE_176x144:
diff --git a/drivers/media/video/usbvideo/konicawc.c b/drivers/media/video/usbvideo/konicawc.c
index 1c18028..e986c28 100644
--- a/drivers/media/video/usbvideo/konicawc.c
+++ b/drivers/media/video/usbvideo/konicawc.c
@@ -337,7 +337,8 @@
 		}
 
 		if((sts > 0x01) && (sts < 0x80)) {
-			info("unknown status %2.2x", sts);
+			dev_info(&uvd->dev->dev, "unknown status %2.2x\n",
+				 sts);
 			bad++;
 			continue;
 		}
@@ -568,8 +569,12 @@
 					fdrops = (0x80 + curframe - cam->lastframe) & 0x7F;
 					fdrops--;
 					if(fdrops) {
-						info("Dropped %d frames (%d -> %d)", fdrops,
-						     cam->lastframe, curframe);
+						dev_info(&uvd->dev->dev,
+							 "Dropped %d frames "
+							 "(%d -> %d)\n",
+							 fdrops,
+							 cam->lastframe,
+							 curframe);
 					}
 				}
 				cam->lastframe = curframe;
@@ -784,7 +789,8 @@
 	if (dev->descriptor.bNumConfigurations != 1)
 		return -ENODEV;
 
-	info("Konica Webcam (rev. 0x%04x)", le16_to_cpu(dev->descriptor.bcdDevice));
+	dev_info(&intf->dev, "Konica Webcam (rev. 0x%04x)\n",
+		 le16_to_cpu(dev->descriptor.bcdDevice));
 	RESTRICT_TO_RANGE(speed, 0, MAX_SPEED);
 
 	/* Validate found interface: must have one ISO endpoint */
@@ -925,7 +931,8 @@
 static int __init konicawc_init(void)
 {
 	struct usbvideo_cb cbTbl;
-	info(DRIVER_DESC " " DRIVER_VERSION);
+	printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
+	       DRIVER_DESC "\n");
 	memset(&cbTbl, 0, sizeof(cbTbl));
 	cbTbl.probe = konicawc_probe;
 	cbTbl.setupOnOpen = konicawc_setup_on_open;
diff --git a/drivers/media/video/usbvideo/quickcam_messenger.c b/drivers/media/video/usbvideo/quickcam_messenger.c
index 3d26a30..05c61b5 100644
--- a/drivers/media/video/usbvideo/quickcam_messenger.c
+++ b/drivers/media/video/usbvideo/quickcam_messenger.c
@@ -1080,7 +1080,8 @@
 
 static int __init qcm_init(void)
 {
-	info(DRIVER_DESC " " DRIVER_VERSION);
+	printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
+	       DRIVER_DESC "\n");
 
 	return usbvideo_register(
 		&cams,
diff --git a/drivers/media/video/usbvideo/ultracam.c b/drivers/media/video/usbvideo/ultracam.c
index 9544e64..9714baa 100644
--- a/drivers/media/video/usbvideo/ultracam.c
+++ b/drivers/media/video/usbvideo/ultracam.c
@@ -156,10 +156,11 @@
 			sizeof(cp),
 			1000);
 #if 1
-		info("USB => %02x%02x%02x%02x%02x%02x%02x%02x "
-		       "(req=$%02x val=$%04x ind=$%04x)",
-		       cp[0],cp[1],cp[2],cp[3],cp[4],cp[5],cp[6],cp[7],
-		       req, value, index);
+		dev_info(&uvd->dev->dev,
+			 "USB => %02x%02x%02x%02x%02x%02x%02x%02x "
+			 "(req=$%02x val=$%04x ind=$%04x)\n",
+			 cp[0],cp[1],cp[2],cp[3],cp[4],cp[5],cp[6],cp[7],
+			 req, value, index);
 #endif
 	} else {
 		i = usb_control_msg(
@@ -517,19 +518,20 @@
 	unsigned char video_ep = 0;
 
 	if (debug >= 1)
-		info("ultracam_probe(%p)", intf);
+		dev_info(&intf->dev, "ultracam_probe\n");
 
 	/* We don't handle multi-config cameras */
 	if (dev->descriptor.bNumConfigurations != 1)
 		return -ENODEV;
 
-	info("IBM Ultra camera found (rev. 0x%04x)",
-		le16_to_cpu(dev->descriptor.bcdDevice));
+	dev_info(&intf->dev, "IBM Ultra camera found (rev. 0x%04x)\n",
+		 le16_to_cpu(dev->descriptor.bcdDevice));
 
 	/* Validate found interface: must have one ISO endpoint */
 	nas = intf->num_altsetting;
 	if (debug > 0)
-		info("Number of alternate settings=%d.", nas);
+		dev_info(&intf->dev, "Number of alternate settings=%d.\n",
+			 nas);
 	if (nas < 8) {
 		err("Too few alternate settings for this camera!");
 		return -ENODEV;
@@ -576,7 +578,9 @@
 				actInterface = i;
 				maxPS = le16_to_cpu(endpoint->wMaxPacketSize);
 				if (debug > 0)
-					info("Active setting=%d. maxPS=%d.", i, maxPS);
+					dev_info(&intf->dev,
+						 "Active setting=%d. "
+						 "maxPS=%d.\n", i, maxPS);
 			} else {
 				/* Got another active alt. setting */
 				if (maxPS < le16_to_cpu(endpoint->wMaxPacketSize)) {
@@ -584,8 +588,11 @@
 					actInterface = i;
 					maxPS = le16_to_cpu(endpoint->wMaxPacketSize);
 					if (debug > 0) {
-						info("Even better ctive setting=%d. maxPS=%d.",
-						     i, maxPS);
+						dev_info(&intf->dev,
+							 "Even better ctive "
+							 "setting=%d. "
+							 "maxPS=%d.\n",
+							 i, maxPS);
 					}
 				}
 			}
diff --git a/drivers/media/video/usbvideo/usbvideo.c b/drivers/media/video/usbvideo/usbvideo.c
index bf1bc2f..07cd87d 100644
--- a/drivers/media/video/usbvideo/usbvideo.c
+++ b/drivers/media/video/usbvideo/usbvideo.c
@@ -468,8 +468,9 @@
 			percent = (100 * goodPackets) / allPackets;
 		else
 			percent = goodPackets / (allPackets / 100);
-		info("Packet Statistics: Total=%lu. Empty=%lu. Usage=%lu%%",
-		     allPackets, badPackets, percent);
+		dev_info(&uvd->dev->dev,
+			 "Packet Statistics: Total=%lu. Empty=%lu. Usage=%lu%%\n",
+			 allPackets, badPackets, percent);
 		if (uvd->iso_packet_len > 0) {
 			unsigned long allBytes, xferBytes;
 			char multiplier = ' ';
@@ -497,8 +498,9 @@
 					}
 				}
 			}
-			info("Transfer Statistics: Transferred=%lu%cB Usage=%lu%%",
-			     xferBytes, multiplier, percent);
+			dev_info(&uvd->dev->dev,
+				 "Transfer Statistics: Transferred=%lu%cB Usage=%lu%%\n",
+				 xferBytes, multiplier, percent);
 		}
 	}
 }
@@ -545,7 +547,7 @@
 	{	/* For debugging purposes only */
 		char tmp[20];
 		usbvideo_VideosizeToString(tmp, sizeof(tmp), frame->request);
-		info("testpattern: frame=%s", tmp);
+		dev_info(&uvd->dev->dev, "testpattern: frame=%s\n", tmp);
 	}
 #endif
 	/* Form every scan line */
@@ -854,7 +856,7 @@
 
 	usbvideo_ClientIncModCount(uvd);
 	if (uvd->debug > 0)
-		info("%s(%p.)", __func__, intf);
+		dev_info(&intf->dev, "%s(%p.)\n", __func__, intf);
 
 	mutex_lock(&uvd->lock);
 	uvd->remove_pending = 1; /* Now all ISO data will be ignored */
@@ -870,14 +872,15 @@
 
 	video_unregister_device(&uvd->vdev);
 	if (uvd->debug > 0)
-		info("%s: Video unregistered.", __func__);
+		dev_info(&intf->dev, "%s: Video unregistered.\n", __func__);
 
 	if (uvd->user)
-		info("%s: In use, disconnect pending.", __func__);
+		dev_info(&intf->dev, "%s: In use, disconnect pending.\n",
+			 __func__);
 	else
 		usbvideo_CameraRelease(uvd);
 	mutex_unlock(&uvd->lock);
-	info("USB camera disconnected.");
+	dev_info(&intf->dev, "USB camera disconnected.\n");
 
 	usbvideo_ClientDecModCount(uvd);
 }
@@ -1015,14 +1018,17 @@
 		return -EINVAL;
 	}
 	if (uvd->video_endp == 0) {
-		info("%s: No video endpoint specified; data pump disabled.", __func__);
+		dev_info(&uvd->dev->dev,
+			 "%s: No video endpoint specified; data pump disabled.\n",
+			 __func__);
 	}
 	if (uvd->paletteBits == 0) {
 		err("%s: No palettes specified!", __func__);
 		return -EINVAL;
 	}
 	if (uvd->defaultPalette == 0) {
-		info("%s: No default palette!", __func__);
+		dev_info(&uvd->dev->dev, "%s: No default palette!\n",
+			 __func__);
 	}
 
 	uvd->max_frame_size = VIDEOSIZE_X(uvd->canvas) *
@@ -1031,25 +1037,29 @@
 	usbvideo_VideosizeToString(tmp2, sizeof(tmp2), uvd->canvas);
 
 	if (uvd->debug > 0) {
-		info("%s: iface=%d. endpoint=$%02x paletteBits=$%08lx",
-		     __func__, uvd->iface, uvd->video_endp, uvd->paletteBits);
+		dev_info(&uvd->dev->dev,
+			 "%s: iface=%d. endpoint=$%02x paletteBits=$%08lx\n",
+			 __func__, uvd->iface, uvd->video_endp,
+			 uvd->paletteBits);
 	}
 	if (uvd->dev == NULL) {
 		err("%s: uvd->dev == NULL", __func__);
 		return -EINVAL;
 	}
 	uvd->vdev.parent = &uvd->dev->dev;
-	if (video_register_device(&uvd->vdev, VFL_TYPE_GRABBER, video_nr) == -1) {
+	uvd->vdev.release = video_device_release_empty;
+	if (video_register_device(&uvd->vdev, VFL_TYPE_GRABBER, video_nr) < 0) {
 		err("%s: video_register_device failed", __func__);
 		return -EPIPE;
 	}
 	if (uvd->debug > 1) {
-		info("%s: video_register_device() successful", __func__);
+		dev_info(&uvd->dev->dev,
+			 "%s: video_register_device() successful\n", __func__);
 	}
 
-	info("%s on /dev/video%d: canvas=%s videosize=%s",
-	     (uvd->handle != NULL) ? uvd->handle->drvName : "???",
-	     uvd->vdev.minor, tmp2, tmp1);
+	dev_info(&uvd->dev->dev, "%s on /dev/video%d: canvas=%s videosize=%s\n",
+		 (uvd->handle != NULL) ? uvd->handle->drvName : "???",
+		 uvd->vdev.minor, tmp2, tmp1);
 
 	usb_get_dev(uvd->dev);
 	return 0;
@@ -1111,7 +1121,7 @@
 	int i, errCode = 0;
 
 	if (uvd->debug > 1)
-		info("%s($%p)", __func__, dev);
+		dev_info(&uvd->dev->dev, "%s($%p)\n", __func__, dev);
 
 	if (0 < usbvideo_ClientIncModCount(uvd))
 		return -ENODEV;
@@ -1178,19 +1188,25 @@
 		if (errCode == 0) {
 			if (VALID_CALLBACK(uvd, setupOnOpen)) {
 				if (uvd->debug > 1)
-					info("%s: setupOnOpen callback", __func__);
+					dev_info(&uvd->dev->dev,
+						 "%s: setupOnOpen callback\n",
+						 __func__);
 				errCode = GET_CALLBACK(uvd, setupOnOpen)(uvd);
 				if (errCode < 0) {
 					err("%s: setupOnOpen callback failed (%d.).",
 					    __func__, errCode);
 				} else if (uvd->debug > 1) {
-					info("%s: setupOnOpen callback successful", __func__);
+					dev_info(&uvd->dev->dev,
+						 "%s: setupOnOpen callback successful\n",
+						 __func__);
 				}
 			}
 			if (errCode == 0) {
 				uvd->settingsAdjusted = 0;
 				if (uvd->debug > 1)
-					info("%s: Open succeeded.", __func__);
+					dev_info(&uvd->dev->dev,
+						 "%s: Open succeeded.\n",
+						 __func__);
 				uvd->user++;
 				file->private_data = uvd;
 			}
@@ -1200,7 +1216,8 @@
 	if (errCode != 0)
 		usbvideo_ClientDecModCount(uvd);
 	if (uvd->debug > 0)
-		info("%s: Returning %d.", __func__, errCode);
+		dev_info(&uvd->dev->dev, "%s: Returning %d.\n", __func__,
+			 errCode);
 	return errCode;
 }
 
@@ -1223,7 +1240,7 @@
 	int i;
 
 	if (uvd->debug > 1)
-		info("%s($%p)", __func__, dev);
+		dev_info(&uvd->dev->dev, "%s($%p)\n", __func__, dev);
 
 	mutex_lock(&uvd->lock);
 	GET_CALLBACK(uvd, stopDataPump)(uvd);
@@ -1243,14 +1260,15 @@
 	uvd->user--;
 	if (uvd->remove_pending) {
 		if (uvd->debug > 0)
-			info("usbvideo_v4l_close: Final disconnect.");
+			dev_info(&uvd->dev->dev, "%s: Final disconnect.\n",
+				 __func__);
 		usbvideo_CameraRelease(uvd);
 	}
 	mutex_unlock(&uvd->lock);
 	usbvideo_ClientDecModCount(uvd);
 
 	if (uvd->debug > 1)
-		info("%s: Completed.", __func__);
+		dev_info(&uvd->dev->dev, "%s: Completed.\n", __func__);
 	file->private_data = NULL;
 	return 0;
 }
@@ -1364,8 +1382,9 @@
 			struct video_mmap *vm = arg;
 
 			if (uvd->debug >= 1) {
-				info("VIDIOCMCAPTURE: frame=%d. size=%dx%d, format=%d.",
-				     vm->frame, vm->width, vm->height, vm->format);
+				dev_info(&uvd->dev->dev,
+					 "VIDIOCMCAPTURE: frame=%d. size=%dx%d, format=%d.\n",
+					 vm->frame, vm->width, vm->height, vm->format);
 			}
 			/*
 			 * Check if the requested size is supported. If the requestor
@@ -1383,18 +1402,24 @@
 			if ((vm->width > VIDEOSIZE_X(uvd->canvas)) ||
 			    (vm->height > VIDEOSIZE_Y(uvd->canvas))) {
 				if (uvd->debug > 0) {
-					info("VIDIOCMCAPTURE: Size=%dx%d too large; "
-					     "allowed only up to %ldx%ld", vm->width, vm->height,
-					     VIDEOSIZE_X(uvd->canvas), VIDEOSIZE_Y(uvd->canvas));
+					dev_info(&uvd->dev->dev,
+						 "VIDIOCMCAPTURE: Size=%dx%d "
+						 "too large; allowed only up "
+						 "to %ldx%ld\n", vm->width,
+						 vm->height,
+						 VIDEOSIZE_X(uvd->canvas),
+						 VIDEOSIZE_Y(uvd->canvas));
 				}
 				return -EINVAL;
 			}
 			/* Check if the palette is supported */
 			if (((1L << vm->format) & uvd->paletteBits) == 0) {
 				if (uvd->debug > 0) {
-					info("VIDIOCMCAPTURE: format=%d. not supported"
-					     " (paletteBits=$%08lx)",
-					     vm->format, uvd->paletteBits);
+					dev_info(&uvd->dev->dev,
+						 "VIDIOCMCAPTURE: format=%d. "
+						 "not supported "
+						 "(paletteBits=$%08lx)\n",
+						 vm->format, uvd->paletteBits);
 				}
 				return -EINVAL;
 			}
@@ -1422,7 +1447,9 @@
 				return -EINVAL;
 
 			if (uvd->debug >= 1)
-				info("VIDIOCSYNC: syncing to frame %d.", *frameNum);
+				dev_info(&uvd->dev->dev,
+					 "VIDIOCSYNC: syncing to frame %d.\n",
+					 *frameNum);
 			if (uvd->flags & FLAGS_NO_DECODING)
 				ret = usbvideo_GetFrame(uvd, *frameNum);
 			else if (VALID_CALLBACK(uvd, getFrame)) {
@@ -1504,7 +1531,9 @@
 		return -EFAULT;
 
 	if (uvd->debug >= 1)
-		info("%s: %Zd. bytes, noblock=%d.", __func__, count, noblock);
+		dev_info(&uvd->dev->dev,
+			 "%s: %Zd. bytes, noblock=%d.\n",
+			 __func__, count, noblock);
 
 	mutex_lock(&uvd->lock);
 
@@ -1685,18 +1714,21 @@
 		return;
 #if 0
 	if (urb->actual_length > 0) {
-		info("urb=$%p status=%d. errcount=%d. length=%d.",
-		     urb, urb->status, urb->error_count, urb->actual_length);
+		dev_info(&uvd->dev->dev,
+			 "urb=$%p status=%d. errcount=%d. length=%d.\n",
+			 urb, urb->status, urb->error_count,
+			 urb->actual_length);
 	} else {
 		static int c = 0;
 		if (c++ % 100 == 0)
-			info("No Isoc data");
+			dev_info(&uvd->dev->dev, "No Isoc data\n");
 	}
 #endif
 
 	if (!uvd->streaming) {
 		if (uvd->debug >= 1)
-			info("Not streaming, but interrupt!");
+			dev_info(&uvd->dev->dev,
+				 "Not streaming, but interrupt!\n");
 		return;
 	}
 
@@ -1741,7 +1773,7 @@
 	int i, errFlag;
 
 	if (uvd->debug > 1)
-		info("%s($%p)", __func__, uvd);
+		dev_info(&uvd->dev->dev, "%s($%p)\n", __func__, uvd);
 
 	if (!CAMERA_IS_OPERATIONAL(uvd)) {
 		err("%s: Camera is not operational", __func__);
@@ -1789,7 +1821,9 @@
 
 	uvd->streaming = 1;
 	if (uvd->debug > 1)
-		info("%s: streaming=1 video_endp=$%02x", __func__, uvd->video_endp);
+		dev_info(&uvd->dev->dev,
+			 "%s: streaming=1 video_endp=$%02x\n", __func__,
+			 uvd->video_endp);
 	return 0;
 }
 
@@ -1811,14 +1845,14 @@
 		return;
 
 	if (uvd->debug > 1)
-		info("%s($%p)", __func__, uvd);
+		dev_info(&uvd->dev->dev, "%s($%p)\n", __func__, uvd);
 
 	/* Unschedule all of the iso td's */
 	for (i=0; i < USBVIDEO_NUMSBUF; i++) {
 		usb_kill_urb(uvd->sbuf[i].urb);
 	}
 	if (uvd->debug > 1)
-		info("%s: streaming=0", __func__);
+		dev_info(&uvd->dev->dev, "%s: streaming=0\n", __func__);
 	uvd->streaming = 0;
 
 	if (!uvd->remove_pending) {
@@ -1850,7 +1884,8 @@
 	int n;
 
 	if (uvd->debug > 1)
-		info("usbvideo_NewFrame($%p,%d.)", uvd, framenum);
+		dev_info(&uvd->dev->dev, "usbvideo_NewFrame($%p,%d.)\n", uvd,
+			 framenum);
 
 	/* If we're not grabbing a frame right now and the other frame is */
 	/*  ready to be grabbed into, then use it instead */
@@ -1955,12 +1990,14 @@
 	struct usbvideo_frame *frame = &uvd->frame[frameNum];
 
 	if (uvd->debug >= 2)
-		info("%s($%p,%d.)", __func__, uvd, frameNum);
+		dev_info(&uvd->dev->dev, "%s($%p,%d.)\n", __func__, uvd,
+			 frameNum);
 
 	switch (frame->frameState) {
 	case FrameState_Unused:
 		if (uvd->debug >= 2)
-			info("%s: FrameState_Unused", __func__);
+			dev_info(&uvd->dev->dev, "%s: FrameState_Unused\n",
+				 __func__);
 		return -EINVAL;
 	case FrameState_Ready:
 	case FrameState_Grabbing:
@@ -1970,7 +2007,9 @@
 	redo:
 		if (!CAMERA_IS_OPERATIONAL(uvd)) {
 			if (uvd->debug >= 2)
-				info("%s: Camera is not operational (1)", __func__);
+				dev_info(&uvd->dev->dev,
+					 "%s: Camera is not operational (1)\n",
+					 __func__);
 			return -EIO;
 		}
 		ntries = 0;
@@ -1979,24 +2018,33 @@
 			signalPending = signal_pending(current);
 			if (!CAMERA_IS_OPERATIONAL(uvd)) {
 				if (uvd->debug >= 2)
-					info("%s: Camera is not operational (2)", __func__);
+					dev_info(&uvd->dev->dev,
+						 "%s: Camera is not "
+						 "operational (2)\n", __func__);
 				return -EIO;
 			}
 			assert(uvd->fbuf != NULL);
 			if (signalPending) {
 				if (uvd->debug >= 2)
-					info("%s: Signal=$%08x", __func__, signalPending);
+					dev_info(&uvd->dev->dev,
+					"%s: Signal=$%08x\n", __func__,
+					signalPending);
 				if (uvd->flags & FLAGS_RETRY_VIDIOCSYNC) {
 					usbvideo_TestPattern(uvd, 1, 0);
 					uvd->curframe = -1;
 					uvd->stats.frame_num++;
 					if (uvd->debug >= 2)
-						info("%s: Forced test pattern screen", __func__);
+						dev_info(&uvd->dev->dev,
+							 "%s: Forced test "
+							 "pattern screen\n",
+							 __func__);
 					return 0;
 				} else {
 					/* Standard answer: Interrupted! */
 					if (uvd->debug >= 2)
-						info("%s: Interrupted!", __func__);
+						dev_info(&uvd->dev->dev,
+							 "%s: Interrupted!\n",
+							 __func__);
 					return -EINTR;
 				}
 			} else {
@@ -2010,8 +2058,10 @@
 			}
 		} while (frame->frameState == FrameState_Grabbing);
 		if (uvd->debug >= 2) {
-			info("%s: Grabbing done; state=%d. (%lu. bytes)",
-			     __func__, frame->frameState, frame->seqRead_Length);
+			dev_info(&uvd->dev->dev,
+				 "%s: Grabbing done; state=%d. (%lu. bytes)\n",
+				 __func__, frame->frameState,
+				 frame->seqRead_Length);
 		}
 		if (frame->frameState == FrameState_Error) {
 			int ret = usbvideo_NewFrame(uvd, frameNum);
@@ -2048,7 +2098,9 @@
 		}
 		frame->frameState = FrameState_Done_Hold;
 		if (uvd->debug >= 2)
-			info("%s: Entered FrameState_Done_Hold state.", __func__);
+			dev_info(&uvd->dev->dev,
+				 "%s: Entered FrameState_Done_Hold state.\n",
+				 __func__);
 		return 0;
 
 	case FrameState_Done_Hold:
@@ -2059,7 +2111,9 @@
 		 * it will be released back into the wild to roam freely.
 		 */
 		if (uvd->debug >= 2)
-			info("%s: FrameState_Done_Hold state.", __func__);
+			dev_info(&uvd->dev->dev,
+				 "%s: FrameState_Done_Hold state.\n",
+				 __func__);
 		return 0;
 	}
 
diff --git a/drivers/media/video/usbvideo/vicam.c b/drivers/media/video/usbvideo/vicam.c
index 2eb4582..7a127d6 100644
--- a/drivers/media/video/usbvideo/vicam.c
+++ b/drivers/media/video/usbvideo/vicam.c
@@ -472,9 +472,8 @@
 static int
 vicam_open(struct inode *inode, struct file *file)
 {
-	struct video_device *dev = video_devdata(file);
-	struct vicam_camera *cam =
-	    (struct vicam_camera *) dev->priv;
+	struct vicam_camera *cam = video_drvdata(file);
+
 	DBG("open\n");
 
 	if (!cam) {
@@ -488,20 +487,24 @@
 	 * rely on this fact forever.
 	 */
 
+	lock_kernel();
 	if (cam->open_count > 0) {
 		printk(KERN_INFO
 		       "vicam_open called on already opened camera");
+		unlock_kernel();
 		return -EBUSY;
 	}
 
 	cam->raw_image = kmalloc(VICAM_MAX_READ_SIZE, GFP_KERNEL);
 	if (!cam->raw_image) {
+		unlock_kernel();
 		return -ENOMEM;
 	}
 
 	cam->framebuf = rvmalloc(VICAM_MAX_FRAME_SIZE * VICAM_FRAMES);
 	if (!cam->framebuf) {
 		kfree(cam->raw_image);
+		unlock_kernel();
 		return -ENOMEM;
 	}
 
@@ -509,6 +512,7 @@
 	if (!cam->cntrlbuf) {
 		kfree(cam->raw_image);
 		rvfree(cam->framebuf, VICAM_MAX_FRAME_SIZE * VICAM_FRAMES);
+		unlock_kernel();
 		return -ENOMEM;
 	}
 
@@ -526,6 +530,7 @@
 	cam->open_count++;
 
 	file->private_data = cam;
+	unlock_kernel();
 
 	return 0;
 }
@@ -795,6 +800,7 @@
 	.name 		= "ViCam-based USB Camera",
 	.fops 		= &vicam_fops,
 	.minor 		= -1,
+	.release 	= video_device_release_empty,
 };
 
 /* table of devices that work with this driver */
@@ -859,9 +865,8 @@
 
 	mutex_init(&cam->cam_lock);
 
-	memcpy(&cam->vdev, &vicam_template,
-	       sizeof (vicam_template));
-	cam->vdev.priv = cam;	// sort of a reverse mapping for those functions that get vdev only
+	memcpy(&cam->vdev, &vicam_template, sizeof(vicam_template));
+	video_set_drvdata(&cam->vdev, cam);
 
 	cam->udev = dev;
 	cam->bulkEndpoint = bulkEndpoint;
diff --git a/drivers/media/video/usbvision/usbvision-core.c b/drivers/media/video/usbvision/usbvision-core.c
index c317ed7..b26b563 100644
--- a/drivers/media/video/usbvision/usbvision-core.c
+++ b/drivers/media/video/usbvision/usbvision-core.c
@@ -84,7 +84,8 @@
 #ifdef USBVISION_DEBUG
 	#define PDEBUG(level, fmt, args...) { \
 		if (core_debug & (level)) \
-			info("[%s:%d] " fmt, __func__, __LINE__ , ## args); \
+			printk(KERN_INFO KBUILD_MODNAME ":[%s:%d] " fmt, \
+				__func__, __LINE__ , ## args); \
 	}
 #else
 	#define PDEBUG(level, fmt, args...) do {} while(0)
diff --git a/drivers/media/video/usbvision/usbvision-i2c.c b/drivers/media/video/usbvision/usbvision-i2c.c
index a6d0085..92427fd 100644
--- a/drivers/media/video/usbvision/usbvision-i2c.c
+++ b/drivers/media/video/usbvision/usbvision-i2c.c
@@ -47,7 +47,8 @@
 
 #define PDEBUG(level, fmt, args...) { \
 		if (i2c_debug & (level)) \
-			info("[%s:%d] " fmt, __func__, __LINE__ , ## args); \
+			printk(KERN_INFO KBUILD_MODNAME ":[%s:%d] " fmt, \
+				__func__, __LINE__ , ## args); \
 	}
 
 static int usbvision_i2c_write(struct usb_usbvision *usbvision, unsigned char addr, char *buf,
diff --git a/drivers/media/video/usbvision/usbvision-video.c b/drivers/media/video/usbvision/usbvision-video.c
index b977116..e10b256 100644
--- a/drivers/media/video/usbvision/usbvision-video.c
+++ b/drivers/media/video/usbvision/usbvision-video.c
@@ -98,7 +98,8 @@
 #ifdef USBVISION_DEBUG
 	#define PDEBUG(level, fmt, args...) { \
 		if (video_debug & (level)) \
-			info("[%s:%d] " fmt, __func__, __LINE__ , ## args); \
+			printk(KERN_INFO KBUILD_MODNAME ":[%s:%d] " fmt, \
+				__func__, __LINE__ , ## args); \
 	}
 #else
 	#define PDEBUG(level, fmt, args...) do {} while(0)
@@ -360,13 +361,12 @@
  */
 static int usbvision_v4l2_open(struct inode *inode, struct file *file)
 {
-	struct video_device *dev = video_devdata(file);
-	struct usb_usbvision *usbvision =
-		(struct usb_usbvision *) video_get_drvdata(dev);
+	struct usb_usbvision *usbvision = video_drvdata(file);
 	int errCode = 0;
 
 	PDEBUG(DBG_IO, "open");
 
+	lock_kernel();
 	usbvision_reset_powerOffTimer(usbvision);
 
 	if (usbvision->user)
@@ -424,6 +424,7 @@
 	usbvision_empty_framequeues(usbvision);
 
 	PDEBUG(DBG_IO, "success");
+	unlock_kernel();
 	return errCode;
 }
 
@@ -437,9 +438,7 @@
  */
 static int usbvision_v4l2_close(struct inode *inode, struct file *file)
 {
-	struct video_device *dev = video_devdata(file);
-	struct usb_usbvision *usbvision =
-		(struct usb_usbvision *) video_get_drvdata(dev);
+	struct usb_usbvision *usbvision = video_drvdata(file);
 
 	PDEBUG(DBG_IO, "close");
 	mutex_lock(&usbvision->lock);
@@ -484,9 +483,7 @@
 static int vidioc_g_register (struct file *file, void *priv,
 				struct v4l2_register *reg)
 {
-	struct video_device *dev = video_devdata(file);
-	struct usb_usbvision *usbvision =
-		(struct usb_usbvision *) video_get_drvdata(dev);
+	struct usb_usbvision *usbvision = video_drvdata(file);
 	int errCode;
 
 	if (!v4l2_chip_match_host(reg->match_type, reg->match_chip))
@@ -505,9 +502,7 @@
 static int vidioc_s_register (struct file *file, void *priv,
 				struct v4l2_register *reg)
 {
-	struct video_device *dev = video_devdata(file);
-	struct usb_usbvision *usbvision =
-		(struct usb_usbvision *) video_get_drvdata(dev);
+	struct usb_usbvision *usbvision = video_drvdata(file);
 	int errCode;
 
 	if (!v4l2_chip_match_host(reg->match_type, reg->match_chip))
@@ -526,9 +521,7 @@
 static int vidioc_querycap (struct file *file, void  *priv,
 					struct v4l2_capability *vc)
 {
-	struct video_device *dev = video_devdata(file);
-	struct usb_usbvision *usbvision =
-		(struct usb_usbvision *) video_get_drvdata(dev);
+	struct usb_usbvision *usbvision = video_drvdata(file);
 
 	strlcpy(vc->driver, "USBVision", sizeof(vc->driver));
 	strlcpy(vc->card,
@@ -548,9 +541,7 @@
 static int vidioc_enum_input (struct file *file, void *priv,
 				struct v4l2_input *vi)
 {
-	struct video_device *dev = video_devdata(file);
-	struct usb_usbvision *usbvision =
-		(struct usb_usbvision *) video_get_drvdata(dev);
+	struct usb_usbvision *usbvision = video_drvdata(file);
 	int chan;
 
 	if ((vi->index >= usbvision->video_inputs) || (vi->index < 0) )
@@ -603,9 +594,7 @@
 
 static int vidioc_g_input (struct file *file, void *priv, unsigned int *input)
 {
-	struct video_device *dev = video_devdata(file);
-	struct usb_usbvision *usbvision =
-		(struct usb_usbvision *) video_get_drvdata(dev);
+	struct usb_usbvision *usbvision = video_drvdata(file);
 
 	*input = usbvision->ctl_input;
 	return 0;
@@ -613,9 +602,7 @@
 
 static int vidioc_s_input (struct file *file, void *priv, unsigned int input)
 {
-	struct video_device *dev = video_devdata(file);
-	struct usb_usbvision *usbvision =
-		(struct usb_usbvision *) video_get_drvdata(dev);
+	struct usb_usbvision *usbvision = video_drvdata(file);
 
 	if ((input >= usbvision->video_inputs) || (input < 0) )
 		return -EINVAL;
@@ -632,9 +619,8 @@
 
 static int vidioc_s_std (struct file *file, void *priv, v4l2_std_id *id)
 {
-	struct video_device *dev = video_devdata(file);
-	struct usb_usbvision *usbvision =
-		(struct usb_usbvision *) video_get_drvdata(dev);
+	struct usb_usbvision *usbvision = video_drvdata(file);
+
 	usbvision->tvnormId=*id;
 
 	mutex_lock(&usbvision->lock);
@@ -650,9 +636,7 @@
 static int vidioc_g_tuner (struct file *file, void *priv,
 				struct v4l2_tuner *vt)
 {
-	struct video_device *dev = video_devdata(file);
-	struct usb_usbvision *usbvision =
-		(struct usb_usbvision *) video_get_drvdata(dev);
+	struct usb_usbvision *usbvision = video_drvdata(file);
 
 	if (!usbvision->have_tuner || vt->index)	// Only tuner 0
 		return -EINVAL;
@@ -671,9 +655,7 @@
 static int vidioc_s_tuner (struct file *file, void *priv,
 				struct v4l2_tuner *vt)
 {
-	struct video_device *dev = video_devdata(file);
-	struct usb_usbvision *usbvision =
-		(struct usb_usbvision *) video_get_drvdata(dev);
+	struct usb_usbvision *usbvision = video_drvdata(file);
 
 	// Only no or one tuner for now
 	if (!usbvision->have_tuner || vt->index)
@@ -687,9 +669,7 @@
 static int vidioc_g_frequency (struct file *file, void *priv,
 				struct v4l2_frequency *freq)
 {
-	struct video_device *dev = video_devdata(file);
-	struct usb_usbvision *usbvision =
-		(struct usb_usbvision *) video_get_drvdata(dev);
+	struct usb_usbvision *usbvision = video_drvdata(file);
 
 	freq->tuner = 0; // Only one tuner
 	if(usbvision->radio) {
@@ -705,9 +685,7 @@
 static int vidioc_s_frequency (struct file *file, void *priv,
 				struct v4l2_frequency *freq)
 {
-	struct video_device *dev = video_devdata(file);
-	struct usb_usbvision *usbvision =
-		(struct usb_usbvision *) video_get_drvdata(dev);
+	struct usb_usbvision *usbvision = video_drvdata(file);
 
 	// Only no or one tuner for now
 	if (!usbvision->have_tuner || freq->tuner)
@@ -721,9 +699,7 @@
 
 static int vidioc_g_audio (struct file *file, void *priv, struct v4l2_audio *a)
 {
-	struct video_device *dev = video_devdata(file);
-	struct usb_usbvision *usbvision =
-		(struct usb_usbvision *) video_get_drvdata(dev);
+	struct usb_usbvision *usbvision = video_drvdata(file);
 
 	memset(a,0,sizeof(*a));
 	if(usbvision->radio) {
@@ -748,9 +724,7 @@
 static int vidioc_queryctrl (struct file *file, void *priv,
 			    struct v4l2_queryctrl *ctrl)
 {
-	struct video_device *dev = video_devdata(file);
-	struct usb_usbvision *usbvision =
-		(struct usb_usbvision *) video_get_drvdata(dev);
+	struct usb_usbvision *usbvision = video_drvdata(file);
 	int id=ctrl->id;
 
 	memset(ctrl,0,sizeof(*ctrl));
@@ -767,9 +741,7 @@
 static int vidioc_g_ctrl (struct file *file, void *priv,
 				struct v4l2_control *ctrl)
 {
-	struct video_device *dev = video_devdata(file);
-	struct usb_usbvision *usbvision =
-		(struct usb_usbvision *) video_get_drvdata(dev);
+	struct usb_usbvision *usbvision = video_drvdata(file);
 	call_i2c_clients(usbvision, VIDIOC_G_CTRL, ctrl);
 
 	return 0;
@@ -778,9 +750,7 @@
 static int vidioc_s_ctrl (struct file *file, void *priv,
 				struct v4l2_control *ctrl)
 {
-	struct video_device *dev = video_devdata(file);
-	struct usb_usbvision *usbvision =
-		(struct usb_usbvision *) video_get_drvdata(dev);
+	struct usb_usbvision *usbvision = video_drvdata(file);
 	call_i2c_clients(usbvision, VIDIOC_S_CTRL, ctrl);
 
 	return 0;
@@ -789,9 +759,7 @@
 static int vidioc_reqbufs (struct file *file,
 			   void *priv, struct v4l2_requestbuffers *vr)
 {
-	struct video_device *dev = video_devdata(file);
-	struct usb_usbvision *usbvision =
-		(struct usb_usbvision *) video_get_drvdata(dev);
+	struct usb_usbvision *usbvision = video_drvdata(file);
 	int ret;
 
 	RESTRICT_TO_RANGE(vr->count,1,USBVISION_NUMFRAMES);
@@ -819,9 +787,7 @@
 static int vidioc_querybuf (struct file *file,
 			    void *priv, struct v4l2_buffer *vb)
 {
-	struct video_device *dev = video_devdata(file);
-	struct usb_usbvision *usbvision =
-		(struct usb_usbvision *) video_get_drvdata(dev);
+	struct usb_usbvision *usbvision = video_drvdata(file);
 	struct usbvision_frame *frame;
 
 	/* FIXME : must control
@@ -857,9 +823,7 @@
 
 static int vidioc_qbuf (struct file *file, void *priv, struct v4l2_buffer *vb)
 {
-	struct video_device *dev = video_devdata(file);
-	struct usb_usbvision *usbvision =
-		(struct usb_usbvision *) video_get_drvdata(dev);
+	struct usb_usbvision *usbvision = video_drvdata(file);
 	struct usbvision_frame *frame;
 	unsigned long lock_flags;
 
@@ -896,9 +860,7 @@
 
 static int vidioc_dqbuf (struct file *file, void *priv, struct v4l2_buffer *vb)
 {
-	struct video_device *dev = video_devdata(file);
-	struct usb_usbvision *usbvision =
-		(struct usb_usbvision *) video_get_drvdata(dev);
+	struct usb_usbvision *usbvision = video_drvdata(file);
 	int ret;
 	struct usbvision_frame *f;
 	unsigned long lock_flags;
@@ -939,9 +901,7 @@
 
 static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
 {
-	struct video_device *dev = video_devdata(file);
-	struct usb_usbvision *usbvision =
-		(struct usb_usbvision *) video_get_drvdata(dev);
+	struct usb_usbvision *usbvision = video_drvdata(file);
 	int b=V4L2_BUF_TYPE_VIDEO_CAPTURE;
 
 	usbvision->streaming = Stream_On;
@@ -953,9 +913,7 @@
 static int vidioc_streamoff(struct file *file,
 			    void *priv, enum v4l2_buf_type type)
 {
-	struct video_device *dev = video_devdata(file);
-	struct usb_usbvision *usbvision =
-		(struct usb_usbvision *) video_get_drvdata(dev);
+	struct usb_usbvision *usbvision = video_drvdata(file);
 	int b=V4L2_BUF_TYPE_VIDEO_CAPTURE;
 
 	if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
@@ -988,9 +946,7 @@
 static int vidioc_g_fmt_vid_cap (struct file *file, void *priv,
 					struct v4l2_format *vf)
 {
-	struct video_device *dev = video_devdata(file);
-	struct usb_usbvision *usbvision =
-		(struct usb_usbvision *) video_get_drvdata(dev);
+	struct usb_usbvision *usbvision = video_drvdata(file);
 	vf->fmt.pix.width = usbvision->curwidth;
 	vf->fmt.pix.height = usbvision->curheight;
 	vf->fmt.pix.pixelformat = usbvision->palette.format;
@@ -1006,9 +962,7 @@
 static int vidioc_try_fmt_vid_cap (struct file *file, void *priv,
 			       struct v4l2_format *vf)
 {
-	struct video_device *dev = video_devdata(file);
-	struct usb_usbvision *usbvision =
-		(struct usb_usbvision *) video_get_drvdata(dev);
+	struct usb_usbvision *usbvision = video_drvdata(file);
 	int formatIdx;
 
 	/* Find requested format in available ones */
@@ -1036,9 +990,7 @@
 static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
 			       struct v4l2_format *vf)
 {
-	struct video_device *dev = video_devdata(file);
-	struct usb_usbvision *usbvision =
-		(struct usb_usbvision *) video_get_drvdata(dev);
+	struct usb_usbvision *usbvision = video_drvdata(file);
 	int ret;
 
 	if( 0 != (ret=vidioc_try_fmt_vid_cap (file, priv, vf)) ) {
@@ -1066,9 +1018,7 @@
 static ssize_t usbvision_v4l2_read(struct file *file, char __user *buf,
 		      size_t count, loff_t *ppos)
 {
-	struct video_device *dev = video_devdata(file);
-	struct usb_usbvision *usbvision =
-		(struct usb_usbvision *) video_get_drvdata(dev);
+	struct usb_usbvision *usbvision = video_drvdata(file);
 	int noblock = file->f_flags & O_NONBLOCK;
 	unsigned long lock_flags;
 
@@ -1177,10 +1127,7 @@
 		start = vma->vm_start;
 	void *pos;
 	u32 i;
-
-	struct video_device *dev = video_devdata(file);
-	struct usb_usbvision *usbvision =
-		(struct usb_usbvision *) video_get_drvdata(dev);
+	struct usb_usbvision *usbvision = video_drvdata(file);
 
 	PDEBUG(DBG_MMAP, "mmap");
 
@@ -1237,9 +1184,7 @@
  */
 static int usbvision_radio_open(struct inode *inode, struct file *file)
 {
-	struct video_device *dev = video_devdata(file);
-	struct usb_usbvision *usbvision =
-		(struct usb_usbvision *) video_get_drvdata(dev);
+	struct usb_usbvision *usbvision = video_drvdata(file);
 	int errCode = 0;
 
 	PDEBUG(DBG_IO, "%s:", __func__);
@@ -1289,9 +1234,7 @@
 
 static int usbvision_radio_close(struct inode *inode, struct file *file)
 {
-	struct video_device *dev = video_devdata(file);
-	struct usb_usbvision *usbvision =
-		(struct usb_usbvision *) video_get_drvdata(dev);
+	struct usb_usbvision *usbvision = video_drvdata(file);
 	int errCode = 0;
 
 	PDEBUG(DBG_IO, "");
diff --git a/drivers/media/video/uvc/uvc_ctrl.c b/drivers/media/video/uvc/uvc_ctrl.c
index 6ef3e52..f16aafe 100644
--- a/drivers/media/video/uvc/uvc_ctrl.c
+++ b/drivers/media/video/uvc/uvc_ctrl.c
@@ -83,6 +83,22 @@
 	},
 	{
 		.entity		= UVC_GUID_UVC_PROCESSING,
+		.selector	= PU_WHITE_BALANCE_TEMPERATURE_CONTROL,
+		.index		= 6,
+		.size		= 2,
+		.flags		= UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
+				| UVC_CONTROL_RESTORE | UVC_CONTROL_AUTO_UPDATE,
+	},
+	{
+		.entity		= UVC_GUID_UVC_PROCESSING,
+		.selector	= PU_WHITE_BALANCE_COMPONENT_CONTROL,
+		.index		= 7,
+		.size		= 4,
+		.flags		= UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
+				| UVC_CONTROL_RESTORE | UVC_CONTROL_AUTO_UPDATE,
+	},
+	{
+		.entity		= UVC_GUID_UVC_PROCESSING,
 		.selector	= PU_BACKLIGHT_COMPENSATION_CONTROL,
 		.index		= 8,
 		.size		= 2,
@@ -114,6 +130,60 @@
 				| UVC_CONTROL_GET_DEF | UVC_CONTROL_RESTORE,
 	},
 	{
+		.entity		= UVC_GUID_UVC_PROCESSING,
+		.selector	= PU_WHITE_BALANCE_TEMPERATURE_AUTO_CONTROL,
+		.index		= 12,
+		.size		= 1,
+		.flags		= UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR
+				| UVC_CONTROL_GET_DEF | UVC_CONTROL_RESTORE,
+	},
+	{
+		.entity		= UVC_GUID_UVC_PROCESSING,
+		.selector	= PU_WHITE_BALANCE_COMPONENT_AUTO_CONTROL,
+		.index		= 13,
+		.size		= 1,
+		.flags		= UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR
+				| UVC_CONTROL_GET_DEF | UVC_CONTROL_RESTORE,
+	},
+	{
+		.entity		= UVC_GUID_UVC_PROCESSING,
+		.selector	= PU_DIGITAL_MULTIPLIER_CONTROL,
+		.index		= 14,
+		.size		= 2,
+		.flags		= UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
+				| UVC_CONTROL_RESTORE,
+	},
+	{
+		.entity		= UVC_GUID_UVC_PROCESSING,
+		.selector	= PU_DIGITAL_MULTIPLIER_LIMIT_CONTROL,
+		.index		= 15,
+		.size		= 2,
+		.flags		= UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
+				| UVC_CONTROL_RESTORE,
+	},
+	{
+		.entity		= UVC_GUID_UVC_PROCESSING,
+		.selector	= PU_ANALOG_VIDEO_STANDARD_CONTROL,
+		.index		= 16,
+		.size		= 1,
+		.flags		= UVC_CONTROL_GET_CUR,
+	},
+	{
+		.entity		= UVC_GUID_UVC_PROCESSING,
+		.selector	= PU_ANALOG_LOCK_STATUS_CONTROL,
+		.index		= 17,
+		.size		= 1,
+		.flags		= UVC_CONTROL_GET_CUR,
+	},
+	{
+		.entity		= UVC_GUID_UVC_CAMERA,
+		.selector	= CT_SCANNING_MODE_CONTROL,
+		.index		= 0,
+		.size		= 1,
+		.flags		= UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR
+				| UVC_CONTROL_RESTORE,
+	},
+	{
 		.entity		= UVC_GUID_UVC_CAMERA,
 		.selector	= CT_AE_MODE_CONTROL,
 		.index		= 1,
@@ -140,6 +210,14 @@
 	},
 	{
 		.entity		= UVC_GUID_UVC_CAMERA,
+		.selector	= CT_EXPOSURE_TIME_RELATIVE_CONTROL,
+		.index		= 4,
+		.size		= 1,
+		.flags		= UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR
+				| UVC_CONTROL_RESTORE,
+	},
+	{
+		.entity		= UVC_GUID_UVC_CAMERA,
 		.selector	= CT_FOCUS_ABSOLUTE_CONTROL,
 		.index		= 5,
 		.size		= 2,
@@ -148,6 +226,78 @@
 	},
 	{
 		.entity		= UVC_GUID_UVC_CAMERA,
+		.selector	= CT_FOCUS_RELATIVE_CONTROL,
+		.index		= 6,
+		.size		= 2,
+		.flags		= UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
+				| UVC_CONTROL_AUTO_UPDATE,
+	},
+	{
+		.entity		= UVC_GUID_UVC_CAMERA,
+		.selector	= CT_IRIS_ABSOLUTE_CONTROL,
+		.index		= 7,
+		.size		= 2,
+		.flags		= UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
+				| UVC_CONTROL_RESTORE | UVC_CONTROL_AUTO_UPDATE,
+	},
+	{
+		.entity		= UVC_GUID_UVC_CAMERA,
+		.selector	= CT_IRIS_RELATIVE_CONTROL,
+		.index		= 8,
+		.size		= 1,
+		.flags		= UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR
+				| UVC_CONTROL_AUTO_UPDATE,
+	},
+	{
+		.entity		= UVC_GUID_UVC_CAMERA,
+		.selector	= CT_ZOOM_ABSOLUTE_CONTROL,
+		.index		= 9,
+		.size		= 2,
+		.flags		= UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
+				| UVC_CONTROL_RESTORE | UVC_CONTROL_AUTO_UPDATE,
+	},
+	{
+		.entity		= UVC_GUID_UVC_CAMERA,
+		.selector	= CT_ZOOM_RELATIVE_CONTROL,
+		.index		= 10,
+		.size		= 3,
+		.flags		= UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
+				| UVC_CONTROL_AUTO_UPDATE,
+	},
+	{
+		.entity		= UVC_GUID_UVC_CAMERA,
+		.selector	= CT_PANTILT_ABSOLUTE_CONTROL,
+		.index		= 11,
+		.size		= 8,
+		.flags		= UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
+				| UVC_CONTROL_RESTORE | UVC_CONTROL_AUTO_UPDATE,
+	},
+	{
+		.entity		= UVC_GUID_UVC_CAMERA,
+		.selector	= CT_PANTILT_RELATIVE_CONTROL,
+		.index		= 12,
+		.size		= 4,
+		.flags		= UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
+				| UVC_CONTROL_AUTO_UPDATE,
+	},
+	{
+		.entity		= UVC_GUID_UVC_CAMERA,
+		.selector	= CT_ROLL_ABSOLUTE_CONTROL,
+		.index		= 13,
+		.size		= 2,
+		.flags		= UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
+				| UVC_CONTROL_RESTORE | UVC_CONTROL_AUTO_UPDATE,
+	},
+	{
+		.entity		= UVC_GUID_UVC_CAMERA,
+		.selector	= CT_ROLL_RELATIVE_CONTROL,
+		.index		= 14,
+		.size		= 2,
+		.flags		= UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
+				| UVC_CONTROL_AUTO_UPDATE,
+	},
+	{
+		.entity		= UVC_GUID_UVC_CAMERA,
 		.selector	= CT_FOCUS_AUTO_CONTROL,
 		.index		= 17,
 		.size		= 1,
@@ -155,35 +305,11 @@
 				| UVC_CONTROL_GET_DEF | UVC_CONTROL_RESTORE,
 	},
 	{
-		.entity		= UVC_GUID_UVC_PROCESSING,
-		.selector	= PU_WHITE_BALANCE_TEMPERATURE_AUTO_CONTROL,
-		.index		= 12,
+		.entity		= UVC_GUID_UVC_CAMERA,
+		.selector	= CT_PRIVACY_CONTROL,
+		.index		= 18,
 		.size		= 1,
 		.flags		= UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR
-				| UVC_CONTROL_GET_DEF | UVC_CONTROL_RESTORE,
-	},
-	{
-		.entity		= UVC_GUID_UVC_PROCESSING,
-		.selector	= PU_WHITE_BALANCE_TEMPERATURE_CONTROL,
-		.index		= 6,
-		.size		= 2,
-		.flags		= UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
-				| UVC_CONTROL_RESTORE | UVC_CONTROL_AUTO_UPDATE,
-	},
-	{
-		.entity		= UVC_GUID_UVC_PROCESSING,
-		.selector	= PU_WHITE_BALANCE_COMPONENT_AUTO_CONTROL,
-		.index		= 13,
-		.size		= 1,
-		.flags		= UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR
-				| UVC_CONTROL_GET_DEF | UVC_CONTROL_RESTORE,
-	},
-	{
-		.entity		= UVC_GUID_UVC_PROCESSING,
-		.selector	= PU_WHITE_BALANCE_COMPONENT_CONTROL,
-		.index		= 7,
-		.size		= 4,
-		.flags		= UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
 				| UVC_CONTROL_RESTORE | UVC_CONTROL_AUTO_UPDATE,
 	},
 };
@@ -592,7 +718,7 @@
 	if (ctrl == NULL)
 		return -EINVAL;
 
-	data = kmalloc(8, GFP_KERNEL);
+	data = kmalloc(ctrl->info->size, GFP_KERNEL);
 	if (data == NULL)
 		return -ENOMEM;
 
@@ -711,7 +837,17 @@
 
 	for (i = 0; i < entity->ncontrols; ++i) {
 		ctrl = &entity->controls[i];
-		if (ctrl->info == NULL || !ctrl->dirty)
+		if (ctrl->info == NULL)
+			continue;
+
+		/* Reset the loaded flag for auto-update controls that were
+		 * marked as loaded in uvc_ctrl_get/uvc_ctrl_set to prevent
+		 * uvc_ctrl_get from using the cached value.
+		 */
+		if (ctrl->info->flags & UVC_CONTROL_AUTO_UPDATE)
+			ctrl->loaded = 0;
+
+		if (!ctrl->dirty)
 			continue;
 
 		if (!rollback)
@@ -727,9 +863,6 @@
 			       uvc_ctrl_data(ctrl, UVC_CTRL_DATA_BACKUP),
 			       ctrl->info->size);
 
-		if ((ctrl->info->flags & UVC_CONTROL_GET_CUR) == 0)
-			ctrl->loaded = 0;
-
 		ctrl->dirty = 0;
 
 		if (ret < 0)
@@ -787,8 +920,7 @@
 		if (ret < 0)
 			return ret;
 
-		if ((ctrl->info->flags & UVC_CONTROL_AUTO_UPDATE) == 0)
-			ctrl->loaded = 1;
+		ctrl->loaded = 1;
 	}
 
 	xctrl->value = uvc_get_le_value(
@@ -839,8 +971,7 @@
 				return ret;
 		}
 
-		if ((ctrl->info->flags & UVC_CONTROL_AUTO_UPDATE) == 0)
-			ctrl->loaded = 1;
+		ctrl->loaded = 1;
 	}
 
 	if (!ctrl->dirty) {
diff --git a/drivers/media/video/uvc/uvc_driver.c b/drivers/media/video/uvc/uvc_driver.c
index 7e10203..d7ad060 100644
--- a/drivers/media/video/uvc/uvc_driver.c
+++ b/drivers/media/video/uvc/uvc_driver.c
@@ -1663,7 +1663,7 @@
 	return uvc_video_suspend(&dev->video);
 }
 
-static int uvc_resume(struct usb_interface *intf)
+static int __uvc_resume(struct usb_interface *intf, int reset)
 {
 	struct uvc_device *dev = usb_get_intfdata(intf);
 	int ret;
@@ -1672,7 +1672,7 @@
 		intf->cur_altsetting->desc.bInterfaceNumber);
 
 	if (intf->cur_altsetting->desc.bInterfaceSubClass == SC_VIDEOCONTROL) {
-		if ((ret = uvc_ctrl_resume_device(dev)) < 0)
+		if (reset && (ret = uvc_ctrl_resume_device(dev)) < 0)
 			return ret;
 
 		return uvc_status_resume(dev);
@@ -1687,6 +1687,16 @@
 	return uvc_video_resume(&dev->video);
 }
 
+static int uvc_resume(struct usb_interface *intf)
+{
+	return __uvc_resume(intf, 0);
+}
+
+static int uvc_reset_resume(struct usb_interface *intf)
+{
+	return __uvc_resume(intf, 1);
+}
+
 /* ------------------------------------------------------------------------
  * Driver initialization and cleanup
  */
@@ -1902,6 +1912,24 @@
 	  .bInterfaceSubClass	= 1,
 	  .bInterfaceProtocol	= 0,
 	  .driver_info		= UVC_QUIRK_PROBE_MINMAX },
+	/* Compaq Presario B1200 - Bison Electronics */
+	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE
+				| USB_DEVICE_ID_MATCH_INT_INFO,
+	  .idVendor		= 0x5986,
+	  .idProduct		= 0x0104,
+	  .bInterfaceClass	= USB_CLASS_VIDEO,
+	  .bInterfaceSubClass	= 1,
+	  .bInterfaceProtocol	= 0,
+	  .driver_info		= UVC_QUIRK_PROBE_MINMAX },
+	/* Acer Travelmate 7720 - Bison Electronics */
+	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE
+				| USB_DEVICE_ID_MATCH_INT_INFO,
+	  .idVendor		= 0x5986,
+	  .idProduct		= 0x0105,
+	  .bInterfaceClass	= USB_CLASS_VIDEO,
+	  .bInterfaceSubClass	= 1,
+	  .bInterfaceProtocol	= 0,
+	  .driver_info		= UVC_QUIRK_PROBE_MINMAX },
 	/* Medion Akoya Mini E1210 - Bison Electronics */
 	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE
 				| USB_DEVICE_ID_MATCH_INT_INFO,
@@ -1920,6 +1948,24 @@
 	  .bInterfaceSubClass	= 1,
 	  .bInterfaceProtocol	= 0,
 	  .driver_info		= UVC_QUIRK_PROBE_MINMAX },
+	/*  Fujitsu Amilo SI2636 - Bison Electronics */
+	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE
+				| USB_DEVICE_ID_MATCH_INT_INFO,
+	  .idVendor		= 0x5986,
+	  .idProduct		= 0x0202,
+	  .bInterfaceClass	= USB_CLASS_VIDEO,
+	  .bInterfaceSubClass	= 1,
+	  .bInterfaceProtocol	= 0,
+	  .driver_info		= UVC_QUIRK_PROBE_MINMAX },
+	/*  Advent 4211 - Bison Electronics */
+	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE
+				| USB_DEVICE_ID_MATCH_INT_INFO,
+	  .idVendor		= 0x5986,
+	  .idProduct		= 0x0203,
+	  .bInterfaceClass	= USB_CLASS_VIDEO,
+	  .bInterfaceSubClass	= 1,
+	  .bInterfaceProtocol	= 0,
+	  .driver_info		= UVC_QUIRK_PROBE_MINMAX },
 	/* Bison Electronics */
 	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE
 				| USB_DEVICE_ID_MATCH_INT_INFO,
@@ -1952,6 +1998,7 @@
 		.disconnect	= uvc_disconnect,
 		.suspend	= uvc_suspend,
 		.resume		= uvc_resume,
+		.reset_resume	= uvc_reset_resume,
 		.id_table	= uvc_ids,
 		.supports_autosuspend = 1,
 	},
diff --git a/drivers/media/video/uvc/uvc_status.c b/drivers/media/video/uvc/uvc_status.c
index 75e678a..5d60b26 100644
--- a/drivers/media/video/uvc/uvc_status.c
+++ b/drivers/media/video/uvc/uvc_status.c
@@ -177,10 +177,16 @@
 
 	uvc_input_init(dev);
 
-	dev->int_urb = usb_alloc_urb(0, GFP_KERNEL);
-	if (dev->int_urb == NULL)
+	dev->status = kzalloc(UVC_MAX_STATUS_SIZE, GFP_KERNEL);
+	if (dev->status == NULL)
 		return -ENOMEM;
 
+	dev->int_urb = usb_alloc_urb(0, GFP_KERNEL);
+	if (dev->int_urb == NULL) {
+		kfree(dev->status);
+		return -ENOMEM;
+	}
+
 	pipe = usb_rcvintpipe(dev->udev, ep->desc.bEndpointAddress);
 
 	/* For high-speed interrupt endpoints, the bInterval value is used as
@@ -192,7 +198,7 @@
 		interval = fls(interval) - 1;
 
 	usb_fill_int_urb(dev->int_urb, dev->udev, pipe,
-		dev->status, sizeof dev->status, uvc_status_complete,
+		dev->status, UVC_MAX_STATUS_SIZE, uvc_status_complete,
 		dev, interval);
 
 	return usb_submit_urb(dev->int_urb, GFP_KERNEL);
@@ -202,6 +208,7 @@
 {
 	usb_kill_urb(dev->int_urb);
 	usb_free_urb(dev->int_urb);
+	kfree(dev->status);
 	uvc_input_cleanup(dev);
 }
 
diff --git a/drivers/media/video/uvc/uvc_v4l2.c b/drivers/media/video/uvc/uvc_v4l2.c
index d7bd71b..78e4c4e 100644
--- a/drivers/media/video/uvc/uvc_v4l2.c
+++ b/drivers/media/video/uvc/uvc_v4l2.c
@@ -400,15 +400,13 @@
 
 static int uvc_v4l2_open(struct inode *inode, struct file *file)
 {
-	struct video_device *vdev;
 	struct uvc_video_device *video;
 	struct uvc_fh *handle;
 	int ret = 0;
 
 	uvc_trace(UVC_TRACE_CALLS, "uvc_v4l2_open\n");
 	mutex_lock(&uvc_driver.open_mutex);
-	vdev = video_devdata(file);
-	video = video_get_drvdata(vdev);
+	video = video_drvdata(file);
 
 	if (video->dev->state & UVC_DEV_DISCONNECTED) {
 		ret = -ENODEV;
@@ -440,8 +438,7 @@
 
 static int uvc_v4l2_release(struct inode *inode, struct file *file)
 {
-	struct video_device *vdev = video_devdata(file);
-	struct uvc_video_device *video = video_get_drvdata(vdev);
+	struct uvc_video_device *video = video_drvdata(file);
 	struct uvc_fh *handle = (struct uvc_fh *)file->private_data;
 
 	uvc_trace(UVC_TRACE_CALLS, "uvc_v4l2_release\n");
@@ -845,10 +842,6 @@
 		if (ret < 0)
 			return ret;
 
-		if (!(video->streaming->cur_format->flags &
-		    UVC_FMT_FLAG_COMPRESSED))
-			video->queue.flags |= UVC_QUEUE_DROP_INCOMPLETE;
-
 		rb->count = ret;
 		ret = 0;
 		break;
@@ -1031,8 +1024,7 @@
 
 static int uvc_v4l2_mmap(struct file *file, struct vm_area_struct *vma)
 {
-	struct video_device *vdev = video_devdata(file);
-	struct uvc_video_device *video = video_get_drvdata(vdev);
+	struct uvc_video_device *video = video_drvdata(file);
 	struct uvc_buffer *uninitialized_var(buffer);
 	struct page *page;
 	unsigned long addr, start, size;
@@ -1085,8 +1077,7 @@
 
 static unsigned int uvc_v4l2_poll(struct file *file, poll_table *wait)
 {
-	struct video_device *vdev = video_devdata(file);
-	struct uvc_video_device *video = video_get_drvdata(vdev);
+	struct uvc_video_device *video = video_drvdata(file);
 
 	uvc_trace(UVC_TRACE_CALLS, "uvc_v4l2_poll\n");
 
diff --git a/drivers/media/video/uvc/uvc_video.c b/drivers/media/video/uvc/uvc_video.c
index 6854ac7..b7bb238 100644
--- a/drivers/media/video/uvc/uvc_video.c
+++ b/drivers/media/video/uvc/uvc_video.c
@@ -455,7 +455,8 @@
 			urb->iso_frame_desc[i].actual_length - ret);
 
 		/* Process the header again. */
-		uvc_video_decode_end(video, buf, mem, ret);
+		uvc_video_decode_end(video, buf, mem,
+			urb->iso_frame_desc[i].actual_length);
 
 		if (buf->state == UVC_BUF_STATE_DONE ||
 		    buf->state == UVC_BUF_STATE_ERROR)
@@ -512,7 +513,7 @@
 	    video->bulk.payload_size >= video->bulk.max_payload_size) {
 		if (!video->bulk.skip_payload && buf != NULL) {
 			uvc_video_decode_end(video, buf, video->bulk.header,
-				video->bulk.header_size);
+				video->bulk.payload_size);
 			if (buf->state == UVC_BUF_STATE_DONE ||
 			    buf->state == UVC_BUF_STATE_ERROR)
 				buf = uvc_queue_next_buffer(&video->queue, buf);
@@ -655,7 +656,7 @@
 	if (size > UVC_MAX_FRAME_SIZE)
 		return -EINVAL;
 
-	npackets = (size + psize - 1) / psize;
+	npackets = DIV_ROUND_UP(size, psize);
 	if (npackets > UVC_MAX_ISO_PACKETS)
 		npackets = UVC_MAX_ISO_PACKETS;
 
@@ -970,6 +971,11 @@
 		return 0;
 	}
 
+	if (video->streaming->cur_format->flags & UVC_FMT_FLAG_COMPRESSED)
+		video->queue.flags &= ~UVC_QUEUE_DROP_INCOMPLETE;
+	else
+		video->queue.flags |= UVC_QUEUE_DROP_INCOMPLETE;
+
 	if ((ret = uvc_queue_enable(&video->queue, 1)) < 0)
 		return ret;
 
diff --git a/drivers/media/video/uvc/uvcvideo.h b/drivers/media/video/uvc/uvcvideo.h
index bafe340..9a6bc1a 100644
--- a/drivers/media/video/uvc/uvcvideo.h
+++ b/drivers/media/video/uvc/uvcvideo.h
@@ -303,6 +303,8 @@
 #define UVC_MAX_FRAME_SIZE	(16*1024*1024)
 /* Maximum number of video buffers. */
 #define UVC_MAX_VIDEO_BUFFERS	32
+/* Maximum status buffer size in bytes of interrupt URB. */
+#define UVC_MAX_STATUS_SIZE	16
 
 #define UVC_CTRL_CONTROL_TIMEOUT	300
 #define UVC_CTRL_STREAMING_TIMEOUT	1000
@@ -634,7 +636,7 @@
 	/* Status Interrupt Endpoint */
 	struct usb_host_endpoint *int_ep;
 	struct urb *int_urb;
-	__u8 status[16];
+	__u8 *status;
 	struct input_dev *input;
 
 	/* Video Streaming interfaces */
diff --git a/drivers/media/video/v4l2-common.c b/drivers/media/video/v4l2-common.c
index 88ca131..20c3be8 100644
--- a/drivers/media/video/v4l2-common.c
+++ b/drivers/media/video/v4l2-common.c
@@ -187,9 +187,11 @@
 		NULL
 	};
 	static const char *mpeg_audio_encoding[] = {
-		"Layer I",
-		"Layer II",
-		"Layer III",
+		"MPEG-1/2 Layer I",
+		"MPEG-1/2 Layer II",
+		"MPEG-1/2 Layer III",
+		"MPEG-2/4 AAC",
+		"AC-3",
 		NULL
 	};
 	static const char *mpeg_audio_l1_bitrate[] = {
@@ -243,6 +245,28 @@
 		"320 kbps",
 		NULL
 	};
+	static const char *mpeg_audio_ac3_bitrate[] = {
+		"32 kbps",
+		"40 kbps",
+		"48 kbps",
+		"56 kbps",
+		"64 kbps",
+		"80 kbps",
+		"96 kbps",
+		"112 kbps",
+		"128 kbps",
+		"160 kbps",
+		"192 kbps",
+		"224 kbps",
+		"256 kbps",
+		"320 kbps",
+		"384 kbps",
+		"448 kbps",
+		"512 kbps",
+		"576 kbps",
+		"640 kbps",
+		NULL
+	};
 	static const char *mpeg_audio_mode[] = {
 		"Stereo",
 		"Joint Stereo",
@@ -271,6 +295,7 @@
 	static const char *mpeg_video_encoding[] = {
 		"MPEG-1",
 		"MPEG-2",
+		"MPEG-4 AVC",
 		NULL
 	};
 	static const char *mpeg_video_aspect[] = {
@@ -311,6 +336,8 @@
 			return mpeg_audio_l2_bitrate;
 		case V4L2_CID_MPEG_AUDIO_L3_BITRATE:
 			return mpeg_audio_l3_bitrate;
+		case V4L2_CID_MPEG_AUDIO_AC3_BITRATE:
+			return mpeg_audio_ac3_bitrate;
 		case V4L2_CID_MPEG_AUDIO_MODE:
 			return mpeg_audio_mode;
 		case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION:
@@ -335,62 +362,73 @@
 }
 EXPORT_SYMBOL(v4l2_ctrl_get_menu);
 
+/* Return the control name. */
+const char *v4l2_ctrl_get_name(u32 id)
+{
+	switch (id) {
+	/* USER controls */
+	case V4L2_CID_USER_CLASS: 	return "User Controls";
+	case V4L2_CID_AUDIO_VOLUME: 	return "Volume";
+	case V4L2_CID_AUDIO_MUTE: 	return "Mute";
+	case V4L2_CID_AUDIO_BALANCE: 	return "Balance";
+	case V4L2_CID_AUDIO_BASS: 	return "Bass";
+	case V4L2_CID_AUDIO_TREBLE: 	return "Treble";
+	case V4L2_CID_AUDIO_LOUDNESS: 	return "Loudness";
+	case V4L2_CID_BRIGHTNESS: 	return "Brightness";
+	case V4L2_CID_CONTRAST: 	return "Contrast";
+	case V4L2_CID_SATURATION: 	return "Saturation";
+	case V4L2_CID_HUE: 		return "Hue";
+
+	/* MPEG controls */
+	case V4L2_CID_MPEG_CLASS: 		return "MPEG Encoder Controls";
+	case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ: return "Audio Sampling Frequency";
+	case V4L2_CID_MPEG_AUDIO_ENCODING: 	return "Audio Encoding";
+	case V4L2_CID_MPEG_AUDIO_L1_BITRATE: 	return "Audio Layer I Bitrate";
+	case V4L2_CID_MPEG_AUDIO_L2_BITRATE: 	return "Audio Layer II Bitrate";
+	case V4L2_CID_MPEG_AUDIO_L3_BITRATE: 	return "Audio Layer III Bitrate";
+	case V4L2_CID_MPEG_AUDIO_AAC_BITRATE: 	return "Audio AAC Bitrate";
+	case V4L2_CID_MPEG_AUDIO_AC3_BITRATE: 	return "Audio AC-3 Bitrate";
+	case V4L2_CID_MPEG_AUDIO_MODE: 		return "Audio Stereo Mode";
+	case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION: return "Audio Stereo Mode Extension";
+	case V4L2_CID_MPEG_AUDIO_EMPHASIS: 	return "Audio Emphasis";
+	case V4L2_CID_MPEG_AUDIO_CRC: 		return "Audio CRC";
+	case V4L2_CID_MPEG_AUDIO_MUTE: 		return "Audio Mute";
+	case V4L2_CID_MPEG_VIDEO_ENCODING: 	return "Video Encoding";
+	case V4L2_CID_MPEG_VIDEO_ASPECT: 	return "Video Aspect";
+	case V4L2_CID_MPEG_VIDEO_B_FRAMES: 	return "Video B Frames";
+	case V4L2_CID_MPEG_VIDEO_GOP_SIZE: 	return "Video GOP Size";
+	case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE: 	return "Video GOP Closure";
+	case V4L2_CID_MPEG_VIDEO_PULLDOWN: 	return "Video Pulldown";
+	case V4L2_CID_MPEG_VIDEO_BITRATE_MODE: 	return "Video Bitrate Mode";
+	case V4L2_CID_MPEG_VIDEO_BITRATE: 	return "Video Bitrate";
+	case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK: 	return "Video Peak Bitrate";
+	case V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION: return "Video Temporal Decimation";
+	case V4L2_CID_MPEG_VIDEO_MUTE: 		return "Video Mute";
+	case V4L2_CID_MPEG_VIDEO_MUTE_YUV:	return "Video Mute YUV";
+	case V4L2_CID_MPEG_STREAM_TYPE: 	return "Stream Type";
+	case V4L2_CID_MPEG_STREAM_PID_PMT: 	return "Stream PMT Program ID";
+	case V4L2_CID_MPEG_STREAM_PID_AUDIO: 	return "Stream Audio Program ID";
+	case V4L2_CID_MPEG_STREAM_PID_VIDEO: 	return "Stream Video Program ID";
+	case V4L2_CID_MPEG_STREAM_PID_PCR: 	return "Stream PCR Program ID";
+	case V4L2_CID_MPEG_STREAM_PES_ID_AUDIO: return "Stream PES Audio ID";
+	case V4L2_CID_MPEG_STREAM_PES_ID_VIDEO: return "Stream PES Video ID";
+	case V4L2_CID_MPEG_STREAM_VBI_FMT:	return "Stream VBI Format";
+
+	default:
+		return NULL;
+	}
+}
+EXPORT_SYMBOL(v4l2_ctrl_get_name);
+
 /* Fill in a struct v4l2_queryctrl */
 int v4l2_ctrl_query_fill(struct v4l2_queryctrl *qctrl, s32 min, s32 max, s32 step, s32 def)
 {
-	const char *name;
+	const char *name = v4l2_ctrl_get_name(qctrl->id);
 
 	qctrl->flags = 0;
-	switch (qctrl->id) {
-	/* USER controls */
-	case V4L2_CID_USER_CLASS: 	name = "User Controls"; break;
-	case V4L2_CID_AUDIO_VOLUME: 	name = "Volume"; break;
-	case V4L2_CID_AUDIO_MUTE: 	name = "Mute"; break;
-	case V4L2_CID_AUDIO_BALANCE: 	name = "Balance"; break;
-	case V4L2_CID_AUDIO_BASS: 	name = "Bass"; break;
-	case V4L2_CID_AUDIO_TREBLE: 	name = "Treble"; break;
-	case V4L2_CID_AUDIO_LOUDNESS: 	name = "Loudness"; break;
-	case V4L2_CID_BRIGHTNESS: 	name = "Brightness"; break;
-	case V4L2_CID_CONTRAST: 	name = "Contrast"; break;
-	case V4L2_CID_SATURATION: 	name = "Saturation"; break;
-	case V4L2_CID_HUE: 		name = "Hue"; break;
-
-	/* MPEG controls */
-	case V4L2_CID_MPEG_CLASS: 		name = "MPEG Encoder Controls"; break;
-	case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ: name = "Audio Sampling Frequency"; break;
-	case V4L2_CID_MPEG_AUDIO_ENCODING: 	name = "Audio Encoding Layer"; break;
-	case V4L2_CID_MPEG_AUDIO_L1_BITRATE: 	name = "Audio Layer I Bitrate"; break;
-	case V4L2_CID_MPEG_AUDIO_L2_BITRATE: 	name = "Audio Layer II Bitrate"; break;
-	case V4L2_CID_MPEG_AUDIO_L3_BITRATE: 	name = "Audio Layer III Bitrate"; break;
-	case V4L2_CID_MPEG_AUDIO_MODE: 		name = "Audio Stereo Mode"; break;
-	case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION: name = "Audio Stereo Mode Extension"; break;
-	case V4L2_CID_MPEG_AUDIO_EMPHASIS: 	name = "Audio Emphasis"; break;
-	case V4L2_CID_MPEG_AUDIO_CRC: 		name = "Audio CRC"; break;
-	case V4L2_CID_MPEG_AUDIO_MUTE: 		name = "Audio Mute"; break;
-	case V4L2_CID_MPEG_VIDEO_ENCODING: 	name = "Video Encoding"; break;
-	case V4L2_CID_MPEG_VIDEO_ASPECT: 	name = "Video Aspect"; break;
-	case V4L2_CID_MPEG_VIDEO_B_FRAMES: 	name = "Video B Frames"; break;
-	case V4L2_CID_MPEG_VIDEO_GOP_SIZE: 	name = "Video GOP Size"; break;
-	case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE: 	name = "Video GOP Closure"; break;
-	case V4L2_CID_MPEG_VIDEO_PULLDOWN: 	name = "Video Pulldown"; break;
-	case V4L2_CID_MPEG_VIDEO_BITRATE_MODE: 	name = "Video Bitrate Mode"; break;
-	case V4L2_CID_MPEG_VIDEO_BITRATE: 	name = "Video Bitrate"; break;
-	case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK: 	name = "Video Peak Bitrate"; break;
-	case V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION: name = "Video Temporal Decimation"; break;
-	case V4L2_CID_MPEG_VIDEO_MUTE: 		name = "Video Mute"; break;
-	case V4L2_CID_MPEG_VIDEO_MUTE_YUV:	name = "Video Mute YUV"; break;
-	case V4L2_CID_MPEG_STREAM_TYPE: 	name = "Stream Type"; break;
-	case V4L2_CID_MPEG_STREAM_PID_PMT: 	name = "Stream PMT Program ID"; break;
-	case V4L2_CID_MPEG_STREAM_PID_AUDIO: 	name = "Stream Audio Program ID"; break;
-	case V4L2_CID_MPEG_STREAM_PID_VIDEO: 	name = "Stream Video Program ID"; break;
-	case V4L2_CID_MPEG_STREAM_PID_PCR: 	name = "Stream PCR Program ID"; break;
-	case V4L2_CID_MPEG_STREAM_PES_ID_AUDIO: name = "Stream PES Audio ID"; break;
-	case V4L2_CID_MPEG_STREAM_PES_ID_VIDEO: name = "Stream PES Video ID"; break;
-	case V4L2_CID_MPEG_STREAM_VBI_FMT:	name = "Stream VBI Format"; break;
-
-	default:
+	if (name == NULL)
 		return -EINVAL;
-	}
+
 	switch (qctrl->id) {
 	case V4L2_CID_AUDIO_MUTE:
 	case V4L2_CID_AUDIO_LOUDNESS:
@@ -407,6 +445,7 @@
 	case V4L2_CID_MPEG_AUDIO_L1_BITRATE:
 	case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
 	case V4L2_CID_MPEG_AUDIO_L3_BITRATE:
+	case V4L2_CID_MPEG_AUDIO_AC3_BITRATE:
 	case V4L2_CID_MPEG_AUDIO_MODE:
 	case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION:
 	case V4L2_CID_MPEG_AUDIO_EMPHASIS:
@@ -493,7 +532,7 @@
 	case V4L2_CID_MPEG_AUDIO_ENCODING:
 		return v4l2_ctrl_query_fill(qctrl,
 				V4L2_MPEG_AUDIO_ENCODING_LAYER_1,
-				V4L2_MPEG_AUDIO_ENCODING_LAYER_3, 1,
+				V4L2_MPEG_AUDIO_ENCODING_AC3, 1,
 				V4L2_MPEG_AUDIO_ENCODING_LAYER_2);
 	case V4L2_CID_MPEG_AUDIO_L1_BITRATE:
 		return v4l2_ctrl_query_fill(qctrl,
@@ -510,6 +549,13 @@
 				V4L2_MPEG_AUDIO_L3_BITRATE_32K,
 				V4L2_MPEG_AUDIO_L3_BITRATE_320K, 1,
 				V4L2_MPEG_AUDIO_L3_BITRATE_192K);
+	case V4L2_CID_MPEG_AUDIO_AAC_BITRATE:
+		return v4l2_ctrl_query_fill(qctrl, 0, 6400, 1, 3200000);
+	case V4L2_CID_MPEG_AUDIO_AC3_BITRATE:
+		return v4l2_ctrl_query_fill(qctrl,
+				V4L2_MPEG_AUDIO_AC3_BITRATE_32K,
+				V4L2_MPEG_AUDIO_AC3_BITRATE_640K, 1,
+				V4L2_MPEG_AUDIO_AC3_BITRATE_384K);
 	case V4L2_CID_MPEG_AUDIO_MODE:
 		return v4l2_ctrl_query_fill(qctrl,
 				V4L2_MPEG_AUDIO_MODE_STEREO,
@@ -535,7 +581,7 @@
 	case V4L2_CID_MPEG_VIDEO_ENCODING:
 		return v4l2_ctrl_query_fill(qctrl,
 				V4L2_MPEG_VIDEO_ENCODING_MPEG_1,
-				V4L2_MPEG_VIDEO_ENCODING_MPEG_2, 1,
+				V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC, 1,
 				V4L2_MPEG_VIDEO_ENCODING_MPEG_2);
 	case V4L2_CID_MPEG_VIDEO_ASPECT:
 		return v4l2_ctrl_query_fill(qctrl,
@@ -594,12 +640,17 @@
 EXPORT_SYMBOL(v4l2_ctrl_query_fill_std);
 
 /* Fill in a struct v4l2_querymenu based on the struct v4l2_queryctrl and
-   the menu. The qctrl pointer may be NULL, in which case it is ignored. */
+   the menu. The qctrl pointer may be NULL, in which case it is ignored.
+   If menu_items is NULL, then the menu items are retrieved using
+   v4l2_ctrl_get_menu. */
 int v4l2_ctrl_query_menu(struct v4l2_querymenu *qmenu, struct v4l2_queryctrl *qctrl,
 	       const char **menu_items)
 {
 	int i;
 
+	qmenu->reserved = 0;
+	if (menu_items == NULL)
+		menu_items = v4l2_ctrl_get_menu(qmenu->id);
 	if (menu_items == NULL ||
 	    (qctrl && (qmenu->index < qctrl->minimum || qmenu->index > qctrl->maximum)))
 		return -EINVAL;
@@ -607,11 +658,31 @@
 	if (menu_items[i] == NULL || menu_items[i][0] == '\0')
 		return -EINVAL;
 	snprintf(qmenu->name, sizeof(qmenu->name), menu_items[qmenu->index]);
-	qmenu->reserved = 0;
 	return 0;
 }
 EXPORT_SYMBOL(v4l2_ctrl_query_menu);
 
+/* Fill in a struct v4l2_querymenu based on the specified array of valid
+   menu items (terminated by V4L2_CTRL_MENU_IDS_END).
+   Use this if there are 'holes' in the list of valid menu items. */
+int v4l2_ctrl_query_menu_valid_items(struct v4l2_querymenu *qmenu, const u32 *ids)
+{
+	const char **menu_items = v4l2_ctrl_get_menu(qmenu->id);
+
+	qmenu->reserved = 0;
+	if (menu_items == NULL || ids == NULL)
+		return -EINVAL;
+	while (*ids != V4L2_CTRL_MENU_IDS_END) {
+		if (*ids++ == qmenu->index) {
+			snprintf(qmenu->name, sizeof(qmenu->name),
+				       menu_items[qmenu->index]);
+			return 0;
+		}
+	}
+	return -EINVAL;
+}
+EXPORT_SYMBOL(v4l2_ctrl_query_menu_valid_items);
+
 /* ctrl_classes points to an array of u32 pointers, the last element is
    a NULL pointer. Each u32 array is a 0-terminated array of control IDs.
    Each array must be sorted low to high and belong to the same control
diff --git a/drivers/media/video/v4l2-dev.c b/drivers/media/video/v4l2-dev.c
index 155fdec..ccd6566 100644
--- a/drivers/media/video/v4l2-dev.c
+++ b/drivers/media/video/v4l2-dev.c
@@ -42,6 +42,7 @@
 			 struct device_attribute *attr, char *buf)
 {
 	struct video_device *vfd = container_of(cd, struct video_device, dev);
+
 	return sprintf(buf, "%i\n", vfd->index);
 }
 
@@ -49,6 +50,7 @@
 			 struct device_attribute *attr, char *buf)
 {
 	struct video_device *vfd = container_of(cd, struct video_device, dev);
+
 	return sprintf(buf, "%.*s\n", (int)sizeof(vfd->name), vfd->name);
 }
 
@@ -58,12 +60,16 @@
 	__ATTR_NULL
 };
 
+/*
+ *	Active devices
+ */
+static struct video_device *video_device[VIDEO_NUM_DEVICES];
+static DEFINE_MUTEX(videodev_lock);
+static DECLARE_BITMAP(video_nums[VFL_TYPE_MAX], VIDEO_NUM_DEVICES);
+
 struct video_device *video_device_alloc(void)
 {
-	struct video_device *vfd;
-
-	vfd = kzalloc(sizeof(*vfd), GFP_KERNEL);
-	return vfd;
+	return kzalloc(sizeof(struct video_device), GFP_KERNEL);
 }
 EXPORT_SYMBOL(video_device_alloc);
 
@@ -73,16 +79,52 @@
 }
 EXPORT_SYMBOL(video_device_release);
 
+void video_device_release_empty(struct video_device *vfd)
+{
+	/* Do nothing */
+	/* Only valid when the video_device struct is a static. */
+}
+EXPORT_SYMBOL(video_device_release_empty);
+
+/* Called when the last user of the character device is gone. */
+static void v4l2_chardev_release(struct kobject *kobj)
+{
+	struct video_device *vfd = container_of(kobj, struct video_device, cdev.kobj);
+
+	mutex_lock(&videodev_lock);
+	if (video_device[vfd->minor] != vfd) {
+		mutex_unlock(&videodev_lock);
+		BUG();
+		return;
+	}
+
+	/* Free up this device for reuse */
+	video_device[vfd->minor] = NULL;
+	clear_bit(vfd->num, video_nums[vfd->vfl_type]);
+	mutex_unlock(&videodev_lock);
+
+	/* Release the character device */
+	vfd->cdev_release(kobj);
+	/* Release video_device and perform other
+	   cleanups as needed. */
+	if (vfd->release)
+		vfd->release(vfd);
+}
+
+/* The new kobj_type for the character device */
+static struct kobj_type v4l2_ktype_cdev_default = {
+	.release = v4l2_chardev_release,
+};
+
 static void video_release(struct device *cd)
 {
 	struct video_device *vfd = container_of(cd, struct video_device, dev);
 
-#if 1
-	/* needed until all drivers are fixed */
-	if (!vfd->release)
-		return;
-#endif
-	vfd->release(vfd);
+	/* It's now safe to delete the char device.
+	   This will either trigger the v4l2_chardev_release immediately (if
+	   the refcount goes to 0) or later when the last user of the
+	   character device closes it. */
+	cdev_del(&vfd->cdev);
 }
 
 static struct class video_class = {
@@ -91,87 +133,12 @@
 	.dev_release = video_release,
 };
 
-/*
- *	Active devices
- */
-
-static struct video_device *video_device[VIDEO_NUM_DEVICES];
-static DEFINE_MUTEX(videodev_lock);
-
 struct video_device *video_devdata(struct file *file)
 {
 	return video_device[iminor(file->f_path.dentry->d_inode)];
 }
 EXPORT_SYMBOL(video_devdata);
 
-/*
- *	Open a video device - FIXME: Obsoleted
- */
-static int video_open(struct inode *inode, struct file *file)
-{
-	unsigned int minor = iminor(inode);
-	int err = 0;
-	struct video_device *vfl;
-	const struct file_operations *old_fops;
-
-	if (minor >= VIDEO_NUM_DEVICES)
-		return -ENODEV;
-	lock_kernel();
-	mutex_lock(&videodev_lock);
-	vfl = video_device[minor];
-	if (vfl == NULL) {
-		mutex_unlock(&videodev_lock);
-		request_module("char-major-%d-%d", VIDEO_MAJOR, minor);
-		mutex_lock(&videodev_lock);
-		vfl = video_device[minor];
-		if (vfl == NULL) {
-			mutex_unlock(&videodev_lock);
-			unlock_kernel();
-			return -ENODEV;
-		}
-	}
-	old_fops = file->f_op;
-	file->f_op = fops_get(vfl->fops);
-	if (file->f_op->open)
-		err = file->f_op->open(inode, file);
-	if (err) {
-		fops_put(file->f_op);
-		file->f_op = fops_get(old_fops);
-	}
-	fops_put(old_fops);
-	mutex_unlock(&videodev_lock);
-	unlock_kernel();
-	return err;
-}
-
-/*
- * open/release helper functions -- handle exclusive opens
- * Should be removed soon
- */
-int video_exclusive_open(struct inode *inode, struct file *file)
-{
-	struct video_device *vfl = video_devdata(file);
-	int retval = 0;
-
-	mutex_lock(&vfl->lock);
-	if (vfl->users)
-		retval = -EBUSY;
-	else
-		vfl->users++;
-	mutex_unlock(&vfl->lock);
-	return retval;
-}
-EXPORT_SYMBOL(video_exclusive_open);
-
-int video_exclusive_release(struct inode *inode, struct file *file)
-{
-	struct video_device *vfl = video_devdata(file);
-
-	vfl->users--;
-	return 0;
-}
-EXPORT_SYMBOL(video_exclusive_release);
-
 /**
  * get_index - assign stream number based on parent device
  * @vdev: video_device to assign index number to, vdev->dev should be assigned
@@ -252,33 +219,29 @@
 					int index)
 {
 	int i = 0;
-	int base;
-	int end;
 	int ret;
-	char *name_base;
+	int minor_offset = 0;
+	int minor_cnt = VIDEO_NUM_DEVICES;
+	const char *name_base;
+	void *priv = video_get_drvdata(vfd);
+
+	/* the release callback MUST be present */
+	BUG_ON(!vfd->release);
 
 	if (vfd == NULL)
 		return -EINVAL;
 
 	switch (type) {
 	case VFL_TYPE_GRABBER:
-		base = MINOR_VFL_TYPE_GRABBER_MIN;
-		end = MINOR_VFL_TYPE_GRABBER_MAX+1;
 		name_base = "video";
 		break;
 	case VFL_TYPE_VTX:
-		base = MINOR_VFL_TYPE_VTX_MIN;
-		end = MINOR_VFL_TYPE_VTX_MAX+1;
 		name_base = "vtx";
 		break;
 	case VFL_TYPE_VBI:
-		base = MINOR_VFL_TYPE_VBI_MIN;
-		end = MINOR_VFL_TYPE_VBI_MAX+1;
 		name_base = "vbi";
 		break;
 	case VFL_TYPE_RADIO:
-		base = MINOR_VFL_TYPE_RADIO_MIN;
-		end = MINOR_VFL_TYPE_RADIO_MAX+1;
 		name_base = "radio";
 		break;
 	default:
@@ -287,28 +250,70 @@
 		return -EINVAL;
 	}
 
+	vfd->vfl_type = type;
+
+#ifdef CONFIG_VIDEO_FIXED_MINOR_RANGES
+	/* Keep the ranges for the first four types for historical
+	 * reasons.
+	 * Newer devices (not yet in place) should use the range
+	 * of 128-191 and just pick the first free minor there
+	 * (new style). */
+	switch (type) {
+	case VFL_TYPE_GRABBER:
+		minor_offset = 0;
+		minor_cnt = 64;
+		break;
+	case VFL_TYPE_RADIO:
+		minor_offset = 64;
+		minor_cnt = 64;
+		break;
+	case VFL_TYPE_VTX:
+		minor_offset = 192;
+		minor_cnt = 32;
+		break;
+	case VFL_TYPE_VBI:
+		minor_offset = 224;
+		minor_cnt = 32;
+		break;
+	default:
+		minor_offset = 128;
+		minor_cnt = 64;
+		break;
+	}
+#endif
+
+	/* Initialize the character device */
+	cdev_init(&vfd->cdev, vfd->fops);
+	vfd->cdev.owner = vfd->fops->owner;
 	/* pick a minor number */
 	mutex_lock(&videodev_lock);
-	if (nr >= 0  &&  nr < end-base) {
-		/* use the one the driver asked for */
-		i = base + nr;
-		if (NULL != video_device[i]) {
-			mutex_unlock(&videodev_lock);
-			return -ENFILE;
-		}
-	} else {
-		/* use first free */
-		for (i = base; i < end; i++)
-			if (NULL == video_device[i])
-				break;
-		if (i == end) {
-			mutex_unlock(&videodev_lock);
-			return -ENFILE;
-		}
+	nr = find_next_zero_bit(video_nums[type], minor_cnt, nr == -1 ? 0 : nr);
+	if (nr == minor_cnt)
+		nr = find_first_zero_bit(video_nums[type], minor_cnt);
+	if (nr == minor_cnt) {
+		printk(KERN_ERR "could not get a free kernel number\n");
+		mutex_unlock(&videodev_lock);
+		return -ENFILE;
 	}
-	video_device[i] = vfd;
-	vfd->vfl_type = type;
-	vfd->minor = i;
+#ifdef CONFIG_VIDEO_FIXED_MINOR_RANGES
+	/* 1-on-1 mapping of kernel number to minor number */
+	i = nr;
+#else
+	/* The kernel number and minor numbers are independent */
+	for (i = 0; i < VIDEO_NUM_DEVICES; i++)
+		if (video_device[i] == NULL)
+			break;
+	if (i == VIDEO_NUM_DEVICES) {
+		mutex_unlock(&videodev_lock);
+		printk(KERN_ERR "could not get a free minor\n");
+		return -ENFILE;
+	}
+#endif
+	vfd->minor = i + minor_offset;
+	vfd->num = nr;
+	set_bit(nr, video_nums[type]);
+	BUG_ON(video_device[vfd->minor]);
+	video_device[vfd->minor] = vfd;
 
 	ret = get_index(vfd, index);
 	vfd->index = ret;
@@ -320,35 +325,41 @@
 		goto fail_minor;
 	}
 
-	mutex_init(&vfd->lock);
-
+	ret = cdev_add(&vfd->cdev, MKDEV(VIDEO_MAJOR, vfd->minor), 1);
+	if (ret < 0) {
+		printk(KERN_ERR "%s: cdev_add failed\n", __func__);
+		goto fail_minor;
+	}
 	/* sysfs class */
-	memset(&vfd->dev, 0x00, sizeof(vfd->dev));
+	memset(&vfd->dev, 0, sizeof(vfd->dev));
+	/* The memset above cleared the device's drvdata, so
+	   put back the copy we made earlier. */
+	video_set_drvdata(vfd, priv);
 	vfd->dev.class = &video_class;
 	vfd->dev.devt = MKDEV(VIDEO_MAJOR, vfd->minor);
 	if (vfd->parent)
 		vfd->dev.parent = vfd->parent;
-	sprintf(vfd->dev.bus_id, "%s%d", name_base, i - base);
+	sprintf(vfd->dev.bus_id, "%s%d", name_base, nr);
 	ret = device_register(&vfd->dev);
 	if (ret < 0) {
 		printk(KERN_ERR "%s: device_register failed\n", __func__);
-		goto fail_minor;
+		goto del_cdev;
 	}
-
-#if 1
-	/* needed until all drivers are fixed */
-	if (!vfd->release)
-		printk(KERN_WARNING "videodev: \"%s\" has no release callback. "
-		       "Please fix your driver for proper sysfs support, see "
-		       "http://lwn.net/Articles/36850/\n", vfd->name);
-#endif
+	/* Remember the cdev's release function */
+	vfd->cdev_release = vfd->cdev.kobj.ktype->release;
+	/* Install our own */
+	vfd->cdev.kobj.ktype = &v4l2_ktype_cdev_default;
 	return 0;
 
+del_cdev:
+	cdev_del(&vfd->cdev);
+
 fail_minor:
 	mutex_lock(&videodev_lock);
 	video_device[vfd->minor] = NULL;
-	vfd->minor = -1;
+	clear_bit(vfd->num, video_nums[type]);
 	mutex_unlock(&videodev_lock);
+	vfd->minor = -1;
 	return ret;
 }
 EXPORT_SYMBOL(video_register_device_index);
@@ -363,42 +374,29 @@
 
 void video_unregister_device(struct video_device *vfd)
 {
-	mutex_lock(&videodev_lock);
-	if (video_device[vfd->minor] != vfd)
-		panic("videodev: bad unregister");
-
-	video_device[vfd->minor] = NULL;
 	device_unregister(&vfd->dev);
-	mutex_unlock(&videodev_lock);
 }
 EXPORT_SYMBOL(video_unregister_device);
 
 /*
- * Video fs operations
- */
-static const struct file_operations video_fops = {
-	.owner		= THIS_MODULE,
-	.llseek		= no_llseek,
-	.open		= video_open,
-};
-
-/*
  *	Initialise video for linux
  */
-
 static int __init videodev_init(void)
 {
+	dev_t dev = MKDEV(VIDEO_MAJOR, 0);
 	int ret;
 
 	printk(KERN_INFO "Linux video capture interface: v2.00\n");
-	if (register_chrdev(VIDEO_MAJOR, VIDEO_NAME, &video_fops)) {
-		printk(KERN_WARNING "video_dev: unable to get major %d\n", VIDEO_MAJOR);
-		return -EIO;
+	ret = register_chrdev_region(dev, VIDEO_NUM_DEVICES, VIDEO_NAME);
+	if (ret < 0) {
+		printk(KERN_WARNING "videodev: unable to get major %d\n",
+				VIDEO_MAJOR);
+		return ret;
 	}
 
 	ret = class_register(&video_class);
 	if (ret < 0) {
-		unregister_chrdev(VIDEO_MAJOR, VIDEO_NAME);
+		unregister_chrdev_region(dev, VIDEO_NUM_DEVICES);
 		printk(KERN_WARNING "video_dev: class_register failed\n");
 		return -EIO;
 	}
@@ -408,8 +406,10 @@
 
 static void __exit videodev_exit(void)
 {
+	dev_t dev = MKDEV(VIDEO_MAJOR, 0);
+
 	class_unregister(&video_class);
-	unregister_chrdev(VIDEO_MAJOR, VIDEO_NAME);
+	unregister_chrdev_region(dev, VIDEO_NUM_DEVICES);
 }
 
 module_init(videodev_init)
diff --git a/drivers/media/video/v4l2-ioctl.c b/drivers/media/video/v4l2-ioctl.c
index 140ef92..155c9d7 100644
--- a/drivers/media/video/v4l2-ioctl.c
+++ b/drivers/media/video/v4l2-ioctl.c
@@ -746,18 +746,6 @@
 				ret = ops->vidioc_enum_fmt_vid_overlay(file,
 					fh, f);
 			break;
-#if 1
-		/* V4L2_BUF_TYPE_VBI_CAPTURE should not support VIDIOC_ENUM_FMT
-		 * according to the spec. The bttv and saa7134 drivers support
-		 * it though, so just warn that this is deprecated and will be
-		 * removed in the near future. */
-		case V4L2_BUF_TYPE_VBI_CAPTURE:
-			if (ops->vidioc_enum_fmt_vbi_cap) {
-				printk(KERN_WARNING "vidioc_enum_fmt_vbi_cap will be removed in 2.6.28!\n");
-				ret = ops->vidioc_enum_fmt_vbi_cap(file, fh, f);
-			}
-			break;
-#endif
 		case V4L2_BUF_TYPE_VIDEO_OUTPUT:
 			if (ops->vidioc_enum_fmt_vid_out)
 				ret = ops->vidioc_enum_fmt_vid_out(file, fh, f);
diff --git a/drivers/media/video/vino.c b/drivers/media/video/vino.c
index 1edda45..8ec57df 100644
--- a/drivers/media/video/vino.c
+++ b/drivers/media/video/vino.c
@@ -39,7 +39,6 @@
 #include <linux/i2c-algo-sgi.h>
 
 #include <linux/videodev2.h>
-#include <media/v4l2-ioctl.h>
 #include <media/v4l2-common.h>
 #include <media/v4l2-ioctl.h>
 #include <linux/video_decoder.h>
@@ -810,7 +809,7 @@
 	dprintk("vino_free_buffer_with_count(): count = %d\n", count);
 
 	for (i = 0; i < count; i++) {
-		ClearPageReserved(virt_to_page(fb->desc_table.virtual[i]));
+		ClearPageReserved(virt_to_page((void *)fb->desc_table.virtual[i]));
 		dma_unmap_single(NULL,
 				 fb->desc_table.dma_cpu[VINO_PAGE_RATIO * i],
 				 PAGE_SIZE, DMA_FROM_DEVICE);
@@ -888,7 +887,7 @@
 				dma_data_addr + VINO_PAGE_SIZE * j;
 		}
 
-		SetPageReserved(virt_to_page(fb->desc_table.virtual[i]));
+		SetPageReserved(virt_to_page((void *)fb->desc_table.virtual[i]));
 	}
 
 	/* page_count needs to be set anyway, because the descriptor table has
@@ -975,7 +974,7 @@
 				dma_data_addr + VINO_PAGE_SIZE * j;
 		}
 
-		SetPageReserved(virt_to_page(fb->desc_table.virtual[i]));
+		SetPageReserved(virt_to_page((void *)fb->desc_table.virtual[i]));
 	}
 
 	/* page_count needs to be set anyway, because the descriptor table has
@@ -4025,8 +4024,7 @@
 
 static int vino_open(struct inode *inode, struct file *file)
 {
-	struct video_device *dev = video_devdata(file);
-	struct vino_channel_settings *vcs = video_get_drvdata(dev);
+	struct vino_channel_settings *vcs = video_drvdata(file);
 	int ret = 0;
 	dprintk("open(): channel = %c\n",
 	       (vcs->channel == VINO_CHANNEL_A) ? 'A' : 'B');
@@ -4057,8 +4055,7 @@
 
 static int vino_close(struct inode *inode, struct file *file)
 {
-	struct video_device *dev = video_devdata(file);
-	struct vino_channel_settings *vcs = video_get_drvdata(dev);
+	struct vino_channel_settings *vcs = video_drvdata(file);
 	dprintk("close():\n");
 
 	mutex_lock(&vcs->mutex);
@@ -4101,8 +4098,7 @@
 
 static int vino_mmap(struct file *file, struct vm_area_struct *vma)
 {
-	struct video_device *dev = video_devdata(file);
-	struct vino_channel_settings *vcs = video_get_drvdata(dev);
+	struct vino_channel_settings *vcs = video_drvdata(file);
 
 	unsigned long start = vma->vm_start;
 	unsigned long size = vma->vm_end - vma->vm_start;
@@ -4207,8 +4203,7 @@
 
 static unsigned int vino_poll(struct file *file, poll_table *pt)
 {
-	struct video_device *dev = video_devdata(file);
-	struct vino_channel_settings *vcs = video_get_drvdata(dev);
+	struct vino_channel_settings *vcs = video_drvdata(file);
 	unsigned int outgoing;
 	unsigned int ret = 0;
 
@@ -4248,8 +4243,7 @@
 static int vino_do_ioctl(struct inode *inode, struct file *file,
 		      unsigned int cmd, void *arg)
 {
-	struct video_device *dev = video_devdata(file);
-	struct vino_channel_settings *vcs = video_get_drvdata(dev);
+	struct vino_channel_settings *vcs = video_drvdata(file);
 
 #ifdef VINO_DEBUG
 	switch (_IOC_TYPE(cmd)) {
@@ -4356,8 +4350,7 @@
 static int vino_ioctl(struct inode *inode, struct file *file,
 		      unsigned int cmd, unsigned long arg)
 {
-	struct video_device *dev = video_devdata(file);
-	struct vino_channel_settings *vcs = video_get_drvdata(dev);
+	struct vino_channel_settings *vcs = video_drvdata(file);
 	int ret;
 
 	if (mutex_lock_interruptible(&vcs->mutex))
diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c
index 8ba8daa..65c8af1 100644
--- a/drivers/media/video/vivi.c
+++ b/drivers/media/video/vivi.c
@@ -898,9 +898,11 @@
 
 	printk(KERN_DEBUG "vivi: open called (minor=%d)\n", minor);
 
+	lock_kernel();
 	list_for_each_entry(dev, &vivi_devlist, vivi_devlist)
 		if (dev->vfd->minor == minor)
 			goto found;
+	unlock_kernel();
 	return -ENODEV;
 
 found:
@@ -925,8 +927,10 @@
 	}
 unlock:
 	mutex_unlock(&dev->mutex);
-	if (retval)
+	if (retval) {
+		unlock_kernel();
 		return retval;
+	}
 
 	file->private_data = fh;
 	fh->dev      = dev;
@@ -955,6 +959,7 @@
 			sizeof(struct vivi_buffer), fh);
 
 	vivi_start_thread(fh);
+	unlock_kernel();
 
 	return 0;
 }
diff --git a/drivers/media/video/vpx3220.c b/drivers/media/video/vpx3220.c
index 35293029..45be9ec 100644
--- a/drivers/media/video/vpx3220.c
+++ b/drivers/media/video/vpx3220.c
@@ -24,8 +24,6 @@
 #include <linux/types.h>
 #include <linux/slab.h>
 
-#include <linux/byteorder/swab.h>
-
 #include <asm/io.h>
 #include <asm/uaccess.h>
 
diff --git a/drivers/media/video/w9966.c b/drivers/media/video/w9966.c
index 2ff00bc..b2dbe48 100644
--- a/drivers/media/video/w9966.c
+++ b/drivers/media/video/w9966.c
@@ -113,6 +113,7 @@
 	signed char contrast;
 	signed char color;
 	signed char hue;
+	unsigned long in_use;
 };
 
 /*
@@ -184,10 +185,25 @@
 static ssize_t w9966_v4l_read(struct file *file, char __user *buf,
 			      size_t count, loff_t *ppos);
 
+static int w9966_exclusive_open(struct inode *inode, struct file *file)
+{
+	struct w9966_dev *cam = video_drvdata(file);
+
+	return test_and_set_bit(0, &cam->in_use) ? -EBUSY : 0;
+}
+
+static int w9966_exclusive_release(struct inode *inode, struct file *file)
+{
+	struct w9966_dev *cam = video_drvdata(file);
+
+	clear_bit(0, &cam->in_use);
+	return 0;
+}
+
 static const struct file_operations w9966_fops = {
 	.owner		= THIS_MODULE,
-	.open           = video_exclusive_open,
-	.release        = video_exclusive_release,
+	.open           = w9966_exclusive_open,
+	.release        = w9966_exclusive_release,
 	.ioctl          = w9966_v4l_ioctl,
 #ifdef CONFIG_COMPAT
 	.compat_ioctl	= v4l_compat_ioctl32,
@@ -198,6 +214,7 @@
 static struct video_device w9966_template = {
 	.name           = W9966_DRIVERNAME,
 	.fops           = &w9966_fops,
+	.release 	= video_device_release_empty,
 };
 
 /*
@@ -332,7 +349,7 @@
 
 // Fill in the video_device struct and register us to v4l
 	memcpy(&cam->vdev, &w9966_template, sizeof(struct video_device));
-	cam->vdev.priv = cam;
+	video_set_drvdata(&cam->vdev, cam);
 
 	if (video_register_device(&cam->vdev, VFL_TYPE_GRABBER, video_nr) < 0)
 		return -1;
@@ -713,8 +730,7 @@
 static int w9966_v4l_do_ioctl(struct inode *inode, struct file *file,
 			      unsigned int cmd, void *arg)
 {
-	struct video_device *vdev = video_devdata(file);
-	struct w9966_dev *cam = vdev->priv;
+	struct w9966_dev *cam = video_drvdata(file);
 
 	switch(cmd)
 	{
@@ -872,8 +888,7 @@
 static ssize_t w9966_v4l_read(struct file *file, char  __user *buf,
 			      size_t count, loff_t *ppos)
 {
-	struct video_device *vdev = video_devdata(file);
-	struct w9966_dev *cam = vdev->priv;
+	struct w9966_dev *cam = video_drvdata(file);
 	unsigned char addr = 0xa0;	// ECP, read, CCD-transfer, 00000
 	unsigned char __user *dest = (unsigned char __user *)buf;
 	unsigned long dleft = count;
diff --git a/drivers/media/video/w9968cf.c b/drivers/media/video/w9968cf.c
index 168baab..11edf79 100644
--- a/drivers/media/video/w9968cf.c
+++ b/drivers/media/video/w9968cf.c
@@ -911,7 +911,6 @@
 
 	for (i = 0; i < W9968CF_URBS; i++) {
 		urb = usb_alloc_urb(W9968CF_ISO_PACKETS, GFP_KERNEL);
-		cam->urb[i] = urb;
 		if (!urb) {
 			for (j = 0; j < i; j++)
 				usb_free_urb(cam->urb[j]);
@@ -919,6 +918,7 @@
 			return -ENOMEM;
 		}
 
+		cam->urb[i] = urb;
 		urb->dev = udev;
 		urb->context = (void*)cam;
 		urb->pipe = usb_rcvisocpipe(udev, 1);
diff --git a/drivers/media/video/wm8739.c b/drivers/media/video/wm8739.c
index 95c79ad..54ac3fe 100644
--- a/drivers/media/video/wm8739.c
+++ b/drivers/media/video/wm8739.c
@@ -274,10 +274,8 @@
 			client->addr << 1, client->adapter->name);
 
 	state = kmalloc(sizeof(struct wm8739_state), GFP_KERNEL);
-	if (state == NULL) {
-		kfree(client);
+	if (state == NULL)
 		return -ENOMEM;
-	}
 	state->vol_l = 0x17; /* 0dB */
 	state->vol_r = 0x17; /* 0dB */
 	state->muted = 0;
diff --git a/drivers/media/video/zc0301/zc0301_core.c b/drivers/media/video/zc0301/zc0301_core.c
index 0c32877..6a0902b 100644
--- a/drivers/media/video/zc0301/zc0301_core.c
+++ b/drivers/media/video/zc0301/zc0301_core.c
@@ -657,7 +657,7 @@
 	if (!down_read_trylock(&zc0301_dev_lock))
 		return -EAGAIN;
 
-	cam = video_get_drvdata(video_devdata(filp));
+	cam = video_drvdata(filp);
 
 	if (wait_for_completion_interruptible(&cam->probe)) {
 		up_read(&zc0301_dev_lock);
@@ -739,7 +739,7 @@
 
 	down_write(&zc0301_dev_lock);
 
-	cam = video_get_drvdata(video_devdata(filp));
+	cam = video_drvdata(filp);
 
 	zc0301_stop_transfer(cam);
 	zc0301_release_buffers(cam);
@@ -759,7 +759,7 @@
 static ssize_t
 zc0301_read(struct file* filp, char __user * buf, size_t count, loff_t* f_pos)
 {
-	struct zc0301_device* cam = video_get_drvdata(video_devdata(filp));
+	struct zc0301_device *cam = video_drvdata(filp);
 	struct zc0301_frame_t* f, * i;
 	unsigned long lock_flags;
 	long timeout;
@@ -866,7 +866,7 @@
 
 static unsigned int zc0301_poll(struct file *filp, poll_table *wait)
 {
-	struct zc0301_device* cam = video_get_drvdata(video_devdata(filp));
+	struct zc0301_device *cam = video_drvdata(filp);
 	struct zc0301_frame_t* f;
 	unsigned long lock_flags;
 	unsigned int mask = 0;
@@ -941,7 +941,7 @@
 
 static int zc0301_mmap(struct file* filp, struct vm_area_struct *vma)
 {
-	struct zc0301_device* cam = video_get_drvdata(video_devdata(filp));
+	struct zc0301_device *cam = video_drvdata(filp);
 	unsigned long size = vma->vm_end - vma->vm_start,
 		      start = vma->vm_start;
 	void *pos;
@@ -1796,7 +1796,7 @@
 static int zc0301_ioctl_v4l2(struct inode* inode, struct file* filp,
 			     unsigned int cmd, void __user * arg)
 {
-	struct zc0301_device* cam = video_get_drvdata(video_devdata(filp));
+	struct zc0301_device *cam = video_drvdata(filp);
 
 	switch (cmd) {
 
@@ -1891,7 +1891,7 @@
 static int zc0301_ioctl(struct inode* inode, struct file* filp,
 			unsigned int cmd, unsigned long arg)
 {
-	struct zc0301_device* cam = video_get_drvdata(video_devdata(filp));
+	struct zc0301_device *cam = video_drvdata(filp);
 	int err = 0;
 
 	if (mutex_lock_interruptible(&cam->fileop_mutex))
diff --git a/drivers/media/video/zoran/Kconfig b/drivers/media/video/zoran/Kconfig
new file mode 100644
index 0000000..4ea5fa7
--- /dev/null
+++ b/drivers/media/video/zoran/Kconfig
@@ -0,0 +1,73 @@
+config VIDEO_ZORAN
+	tristate "Zoran ZR36057/36067 Video For Linux"
+	depends on PCI && I2C_ALGOBIT && VIDEO_V4L1 && VIRT_TO_BUS
+	help
+	  Say Y for support for MJPEG capture cards based on the Zoran
+	  36057/36067 PCI controller chipset. This includes the Iomega
+	  Buz, Pinnacle DC10+ and the Linux Media Labs LML33. There is
+	  a driver homepage at <http://mjpeg.sf.net/driver-zoran/>. For
+	  more information, check <file:Documentation/video4linux/Zoran>.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called zr36067.
+
+config VIDEO_ZORAN_DC30
+	tristate "Pinnacle/Miro DC30(+) support"
+	depends on VIDEO_ZORAN
+	select VIDEO_ADV7175 if VIDEO_HELPER_CHIPS_AUTO
+	select VIDEO_VPX3220 if VIDEO_HELPER_CHIPS_AUTO
+	help
+	  Support for the Pinnacle/Miro DC30(+) MJPEG capture/playback
+	  card. This also supports really old DC10 cards based on the
+	  zr36050 MJPEG codec and zr36016 VFE.
+
+config VIDEO_ZORAN_ZR36060
+	tristate "Zoran ZR36060"
+	depends on VIDEO_ZORAN
+	help
+	  Say Y to support Zoran boards based on 36060 chips.
+	  This includes Iomega Buz, Pinnacle DC10, Linux media Labs 33
+	  and 33 R10 and AverMedia 6 boards.
+
+config VIDEO_ZORAN_BUZ
+	tristate "Iomega Buz support"
+	depends on VIDEO_ZORAN_ZR36060
+	select VIDEO_SAA7111 if VIDEO_HELPER_CHIPS_AUTO
+	select VIDEO_SAA7185 if VIDEO_HELPER_CHIPS_AUTO
+	help
+	  Support for the Iomega Buz MJPEG capture/playback card.
+
+config VIDEO_ZORAN_DC10
+	tristate "Pinnacle/Miro DC10(+) support"
+	depends on VIDEO_ZORAN_ZR36060
+	select VIDEO_SAA7110 if VIDEO_HELPER_CHIPS_AUTO
+	select VIDEO_ADV7175 if VIDEO_HELPER_CHIPS_AUTO
+	help
+	  Support for the Pinnacle/Miro DC10(+) MJPEG capture/playback
+	  card.
+
+config VIDEO_ZORAN_LML33
+	tristate "Linux Media Labs LML33 support"
+	depends on VIDEO_ZORAN_ZR36060
+	select VIDEO_BT819 if VIDEO_HELPER_CHIPS_AUTO
+	select VIDEO_BT856 if VIDEO_HELPER_CHIPS_AUTO
+	help
+	  Support for the Linux Media Labs LML33 MJPEG capture/playback
+	  card.
+
+config VIDEO_ZORAN_LML33R10
+	tristate "Linux Media Labs LML33R10 support"
+	depends on VIDEO_ZORAN_ZR36060
+	select VIDEO_SAA7114 if VIDEO_HELPER_CHIPS_AUTO
+	select VIDEO_ADV7170 if VIDEO_HELPER_CHIPS_AUTO
+	help
+	  support for the Linux Media Labs LML33R10 MJPEG capture/playback
+	  card.
+
+config VIDEO_ZORAN_AVS6EYES
+	tristate "AverMedia 6 Eyes support (EXPERIMENTAL)"
+	depends on VIDEO_ZORAN_ZR36060 && EXPERIMENTAL && VIDEO_V4L1
+	select VIDEO_BT856 if VIDEO_HELPER_CHIPS_AUTO
+	select VIDEO_KS0127 if VIDEO_HELPER_CHIPS_AUTO
+	help
+	  Support for the AverMedia 6 Eyes video surveillance card.
diff --git a/drivers/media/video/zoran/Makefile b/drivers/media/video/zoran/Makefile
new file mode 100644
index 0000000..44cc133
--- /dev/null
+++ b/drivers/media/video/zoran/Makefile
@@ -0,0 +1,6 @@
+zr36067-objs	:=	zoran_procfs.o zoran_device.o \
+			zoran_driver.o zoran_card.o
+
+obj-$(CONFIG_VIDEO_ZORAN) += zr36067.o videocodec.o
+obj-$(CONFIG_VIDEO_ZORAN_DC30) += zr36050.o zr36016.o
+obj-$(CONFIG_VIDEO_ZORAN_ZR36060) += zr36060.o
diff --git a/drivers/media/video/videocodec.c b/drivers/media/video/zoran/videocodec.c
similarity index 100%
rename from drivers/media/video/videocodec.c
rename to drivers/media/video/zoran/videocodec.c
diff --git a/drivers/media/video/videocodec.h b/drivers/media/video/zoran/videocodec.h
similarity index 100%
rename from drivers/media/video/videocodec.h
rename to drivers/media/video/zoran/videocodec.h
diff --git a/drivers/media/video/zoran.h b/drivers/media/video/zoran/zoran.h
similarity index 100%
rename from drivers/media/video/zoran.h
rename to drivers/media/video/zoran/zoran.h
diff --git a/drivers/media/video/zoran/zoran_card.c b/drivers/media/video/zoran/zoran_card.c
new file mode 100644
index 0000000..3282be7
--- /dev/null
+++ b/drivers/media/video/zoran/zoran_card.c
@@ -0,0 +1,1670 @@
+/*
+ * Zoran zr36057/zr36067 PCI controller driver, for the
+ * Pinnacle/Miro DC10/DC10+/DC30/DC30+, Iomega Buz, Linux
+ * Media Labs LML33/LML33R10.
+ *
+ * This part handles card-specific data and detection
+ *
+ * Copyright (C) 2000 Serguei Miridonov <mirsev@cicese.mx>
+ *
+ * Currently maintained by:
+ *   Ronald Bultje    <rbultje@ronald.bitfreak.net>
+ *   Laurent Pinchart <laurent.pinchart@skynet.be>
+ *   Mailinglist      <mjpeg-users@lists.sf.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU 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/delay.h>
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/vmalloc.h>
+
+#include <linux/proc_fs.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+#include <linux/videodev.h>
+#include <media/v4l2-common.h>
+#include <linux/spinlock.h>
+#include <linux/sem.h>
+#include <linux/kmod.h>
+#include <linux/wait.h>
+
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+#include <linux/video_decoder.h>
+#include <linux/video_encoder.h>
+#include <linux/mutex.h>
+
+#include <asm/io.h>
+
+#include "videocodec.h"
+#include "zoran.h"
+#include "zoran_card.h"
+#include "zoran_device.h"
+#include "zoran_procfs.h"
+
+extern const struct zoran_format zoran_formats[];
+
+static int card[BUZ_MAX] = { -1, -1, -1, -1 };
+module_param_array(card, int, NULL, 0444);
+MODULE_PARM_DESC(card, "The type of card");
+
+static int encoder[BUZ_MAX] = { -1, -1, -1, -1 };
+module_param_array(encoder, int, NULL, 0444);
+MODULE_PARM_DESC(encoder, "i2c TV encoder");
+
+static int decoder[BUZ_MAX] = { -1, -1, -1, -1 };
+module_param_array(decoder, int, NULL, 0444);
+MODULE_PARM_DESC(decoder, "i2c TV decoder");
+
+/*
+   The video mem address of the video card.
+   The driver has a little database for some videocards
+   to determine it from there. If your video card is not in there
+   you have either to give it to the driver as a parameter
+   or set in in a VIDIOCSFBUF ioctl
+ */
+
+static unsigned long vidmem;	/* default = 0 - Video memory base address */
+module_param(vidmem, ulong, 0444);
+MODULE_PARM_DESC(vidmem, "Default video memory base address");
+
+/*
+   Default input and video norm at startup of the driver.
+*/
+
+static unsigned int default_input;	/* default 0 = Composite, 1 = S-Video */
+module_param(default_input, uint, 0444);
+MODULE_PARM_DESC(default_input,
+		 "Default input (0=Composite, 1=S-Video, 2=Internal)");
+
+static int default_mux = 1;	/* 6 Eyes input selection */
+module_param(default_mux, int, 0644);
+MODULE_PARM_DESC(default_mux,
+		 "Default 6 Eyes mux setting (Input selection)");
+
+static int default_norm;	/* default 0 = PAL, 1 = NTSC 2 = SECAM */
+module_param(default_norm, int, 0444);
+MODULE_PARM_DESC(default_norm, "Default norm (0=PAL, 1=NTSC, 2=SECAM)");
+
+/* /dev/videoN, -1 for autodetect */
+static int video_nr[BUZ_MAX] = {-1, -1, -1, -1};
+module_param_array(video_nr, int, NULL, 0444);
+MODULE_PARM_DESC(video_nr, "video device number (-1=Auto)");
+
+/*
+   Number and size of grab buffers for Video 4 Linux
+   The vast majority of applications should not need more than 2,
+   the very popular BTTV driver actually does ONLY have 2.
+   Time sensitive applications might need more, the maximum
+   is VIDEO_MAX_FRAME (defined in <linux/videodev.h>).
+
+   The size is set so that the maximum possible request
+   can be satisfied. Decrease  it, if bigphys_area alloc'd
+   memory is low. If you don't have the bigphys_area patch,
+   set it to 128 KB. Will you allow only to grab small
+   images with V4L, but that's better than nothing.
+
+   v4l_bufsize has to be given in KB !
+
+*/
+
+int v4l_nbufs = 2;
+int v4l_bufsize = 128;		/* Everybody should be able to work with this setting */
+module_param(v4l_nbufs, int, 0644);
+MODULE_PARM_DESC(v4l_nbufs, "Maximum number of V4L buffers to use");
+module_param(v4l_bufsize, int, 0644);
+MODULE_PARM_DESC(v4l_bufsize, "Maximum size per V4L buffer (in kB)");
+
+int jpg_nbufs = 32;
+int jpg_bufsize = 512;		/* max size for 100% quality full-PAL frame */
+module_param(jpg_nbufs, int, 0644);
+MODULE_PARM_DESC(jpg_nbufs, "Maximum number of JPG buffers to use");
+module_param(jpg_bufsize, int, 0644);
+MODULE_PARM_DESC(jpg_bufsize, "Maximum size per JPG buffer (in kB)");
+
+int pass_through = 0;		/* 1=Pass through TV signal when device is not used */
+				/* 0=Show color bar when device is not used (LML33: only if lml33dpath=1) */
+module_param(pass_through, int, 0644);
+MODULE_PARM_DESC(pass_through,
+		 "Pass TV signal through to TV-out when idling");
+
+int zr36067_debug = 1;
+module_param_named(debug, zr36067_debug, int, 0644);
+MODULE_PARM_DESC(debug, "Debug level (0-5)");
+
+MODULE_DESCRIPTION("Zoran-36057/36067 JPEG codec driver");
+MODULE_AUTHOR("Serguei Miridonov");
+MODULE_LICENSE("GPL");
+
+static struct pci_device_id zr36067_pci_tbl[] = {
+	{PCI_VENDOR_ID_ZORAN, PCI_DEVICE_ID_ZORAN_36057,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{0}
+};
+MODULE_DEVICE_TABLE(pci, zr36067_pci_tbl);
+
+int zoran_num;			/* number of Buzs in use */
+struct zoran *zoran[BUZ_MAX];
+
+/* videocodec bus functions ZR36060 */
+static u32
+zr36060_read (struct videocodec *codec,
+	      u16                reg)
+{
+	struct zoran *zr = (struct zoran *) codec->master_data->data;
+	__u32 data;
+
+	if (post_office_wait(zr)
+	    || post_office_write(zr, 0, 1, reg >> 8)
+	    || post_office_write(zr, 0, 2, reg & 0xff)) {
+		return -1;
+	}
+
+	data = post_office_read(zr, 0, 3) & 0xff;
+	return data;
+}
+
+static void
+zr36060_write (struct videocodec *codec,
+	       u16                reg,
+	       u32                val)
+{
+	struct zoran *zr = (struct zoran *) codec->master_data->data;
+
+	if (post_office_wait(zr)
+	    || post_office_write(zr, 0, 1, reg >> 8)
+	    || post_office_write(zr, 0, 2, reg & 0xff)) {
+		return;
+	}
+
+	post_office_write(zr, 0, 3, val & 0xff);
+}
+
+/* videocodec bus functions ZR36050 */
+static u32
+zr36050_read (struct videocodec *codec,
+	      u16                reg)
+{
+	struct zoran *zr = (struct zoran *) codec->master_data->data;
+	__u32 data;
+
+	if (post_office_wait(zr)
+	    || post_office_write(zr, 1, 0, reg >> 2)) {	// reg. HIGHBYTES
+		return -1;
+	}
+
+	data = post_office_read(zr, 0, reg & 0x03) & 0xff;	// reg. LOWBYTES + read
+	return data;
+}
+
+static void
+zr36050_write (struct videocodec *codec,
+	       u16                reg,
+	       u32                val)
+{
+	struct zoran *zr = (struct zoran *) codec->master_data->data;
+
+	if (post_office_wait(zr)
+	    || post_office_write(zr, 1, 0, reg >> 2)) {	// reg. HIGHBYTES
+		return;
+	}
+
+	post_office_write(zr, 0, reg & 0x03, val & 0xff);	// reg. LOWBYTES + wr. data
+}
+
+/* videocodec bus functions ZR36016 */
+static u32
+zr36016_read (struct videocodec *codec,
+	      u16                reg)
+{
+	struct zoran *zr = (struct zoran *) codec->master_data->data;
+	__u32 data;
+
+	if (post_office_wait(zr)) {
+		return -1;
+	}
+
+	data = post_office_read(zr, 2, reg & 0x03) & 0xff;	// read
+	return data;
+}
+
+/* hack for in zoran_device.c */
+void
+zr36016_write (struct videocodec *codec,
+	       u16                reg,
+	       u32                val)
+{
+	struct zoran *zr = (struct zoran *) codec->master_data->data;
+
+	if (post_office_wait(zr)) {
+		return;
+	}
+
+	post_office_write(zr, 2, reg & 0x03, val & 0x0ff);	// wr. data
+}
+
+/*
+ * Board specific information
+ */
+
+static void
+dc10_init (struct zoran *zr)
+{
+	dprintk(3, KERN_DEBUG "%s: dc10_init()\n", ZR_DEVNAME(zr));
+
+	/* Pixel clock selection */
+	GPIO(zr, 4, 0);
+	GPIO(zr, 5, 1);
+	/* Enable the video bus sync signals */
+	GPIO(zr, 7, 0);
+}
+
+static void
+dc10plus_init (struct zoran *zr)
+{
+	dprintk(3, KERN_DEBUG "%s: dc10plus_init()\n", ZR_DEVNAME(zr));
+}
+
+static void
+buz_init (struct zoran *zr)
+{
+	dprintk(3, KERN_DEBUG "%s: buz_init()\n", ZR_DEVNAME(zr));
+
+	/* some stuff from Iomega */
+	pci_write_config_dword(zr->pci_dev, 0xfc, 0x90680f15);
+	pci_write_config_dword(zr->pci_dev, 0x0c, 0x00012020);
+	pci_write_config_dword(zr->pci_dev, 0xe8, 0xc0200000);
+}
+
+static void
+lml33_init (struct zoran *zr)
+{
+	dprintk(3, KERN_DEBUG "%s: lml33_init()\n", ZR_DEVNAME(zr));
+
+	GPIO(zr, 2, 1);		// Set Composite input/output
+}
+
+static void
+avs6eyes_init (struct zoran *zr)
+{
+	// AverMedia 6-Eyes original driver by Christer Weinigel
+
+	// Lifted straight from Christer's old driver and
+	// modified slightly by Martin Samuelsson.
+
+	int mux = default_mux; /* 1 = BT866, 7 = VID1 */
+
+	GPIO(zr, 4, 1); /* Bt866 SLEEP on */
+	udelay(2);
+
+	GPIO(zr, 0, 1); /* ZR36060 /RESET on */
+	GPIO(zr, 1, 0); /* ZR36060 /SLEEP on */
+	GPIO(zr, 2, mux & 1);   /* MUX S0 */
+	GPIO(zr, 3, 0); /* /FRAME on */
+	GPIO(zr, 4, 0); /* Bt866 SLEEP off */
+	GPIO(zr, 5, mux & 2);   /* MUX S1 */
+	GPIO(zr, 6, 0); /* ? */
+	GPIO(zr, 7, mux & 4);   /* MUX S2 */
+
+}
+
+static char *
+i2cid_to_modulename (u16 i2c_id)
+{
+	char *name = NULL;
+
+	switch (i2c_id) {
+	case I2C_DRIVERID_SAA7110:
+		name = "saa7110";
+		break;
+	case I2C_DRIVERID_SAA7111A:
+		name = "saa7111";
+		break;
+	case I2C_DRIVERID_SAA7114:
+		name = "saa7114";
+		break;
+	case I2C_DRIVERID_SAA7185B:
+		name = "saa7185";
+		break;
+	case I2C_DRIVERID_ADV7170:
+		name = "adv7170";
+		break;
+	case I2C_DRIVERID_ADV7175:
+		name = "adv7175";
+		break;
+	case I2C_DRIVERID_BT819:
+		name = "bt819";
+		break;
+	case I2C_DRIVERID_BT856:
+		name = "bt856";
+		break;
+	case I2C_DRIVERID_BT866:
+		name = "bt866";
+		break;
+	case I2C_DRIVERID_VPX3220:
+		name = "vpx3220";
+		break;
+	case I2C_DRIVERID_KS0127:
+		name = "ks0127";
+		break;
+	}
+
+	return name;
+}
+
+static char *
+codecid_to_modulename (u16 codecid)
+{
+	char *name = NULL;
+
+	switch (codecid) {
+	case CODEC_TYPE_ZR36060:
+		name = "zr36060";
+		break;
+	case CODEC_TYPE_ZR36050:
+		name = "zr36050";
+		break;
+	case CODEC_TYPE_ZR36016:
+		name = "zr36016";
+		break;
+	}
+
+	return name;
+}
+
+// struct tvnorm {
+//      u16 Wt, Wa, HStart, HSyncStart, Ht, Ha, VStart;
+// };
+
+static struct tvnorm f50sqpixel = { 944, 768, 83, 880, 625, 576, 16 };
+static struct tvnorm f60sqpixel = { 780, 640, 51, 716, 525, 480, 12 };
+static struct tvnorm f50ccir601 = { 864, 720, 75, 804, 625, 576, 18 };
+static struct tvnorm f60ccir601 = { 858, 720, 57, 788, 525, 480, 16 };
+
+static struct tvnorm f50ccir601_lml33 = { 864, 720, 75+34, 804, 625, 576, 18 };
+static struct tvnorm f60ccir601_lml33 = { 858, 720, 57+34, 788, 525, 480, 16 };
+
+/* The DC10 (57/16/50) uses VActive as HSync, so HStart must be 0 */
+static struct tvnorm f50sqpixel_dc10 = { 944, 768, 0, 880, 625, 576, 0 };
+static struct tvnorm f60sqpixel_dc10 = { 780, 640, 0, 716, 525, 480, 12 };
+
+/* FIXME: I cannot swap U and V in saa7114, so i do one
+ * pixel left shift in zoran (75 -> 74)
+ * (Maxim Yevtyushkin <max@linuxmedialabs.com>) */
+static struct tvnorm f50ccir601_lm33r10 = { 864, 720, 74+54, 804, 625, 576, 18 };
+static struct tvnorm f60ccir601_lm33r10 = { 858, 720, 56+54, 788, 525, 480, 16 };
+
+/* FIXME: The ks0127 seem incapable of swapping U and V, too, which is why I
+ * copy Maxim's left shift hack for the 6 Eyes.
+ *
+ * Christer's driver used the unshifted norms, though...
+ * /Sam  */
+static struct tvnorm f50ccir601_avs6eyes = { 864, 720, 74, 804, 625, 576, 18 };
+static struct tvnorm f60ccir601_avs6eyes = { 858, 720, 56, 788, 525, 480, 16 };
+
+static struct card_info zoran_cards[NUM_CARDS] __devinitdata = {
+	{
+		.type = DC10_old,
+		.name = "DC10(old)",
+		.i2c_decoder = I2C_DRIVERID_VPX3220,
+		.video_codec = CODEC_TYPE_ZR36050,
+		.video_vfe = CODEC_TYPE_ZR36016,
+
+		.inputs = 3,
+		.input = {
+			{ 1, "Composite" },
+			{ 2, "S-Video" },
+			{ 0, "Internal/comp" }
+		},
+		.norms = 3,
+		.tvn = {
+			&f50sqpixel_dc10,
+			&f60sqpixel_dc10,
+			&f50sqpixel_dc10
+		},
+		.jpeg_int = 0,
+		.vsync_int = ZR36057_ISR_GIRQ1,
+		.gpio = { 2, 1, -1, 3, 7, 0, 4, 5 },
+		.gpio_pol = { 0, 0, 0, 1, 0, 0, 0, 0 },
+		.gpcs = { -1, 0 },
+		.vfe_pol = { 0, 0, 0, 0, 0, 0, 0, 0 },
+		.gws_not_connected = 0,
+		.input_mux = 0,
+		.init = &dc10_init,
+	}, {
+		.type = DC10_new,
+		.name = "DC10(new)",
+		.i2c_decoder = I2C_DRIVERID_SAA7110,
+		.i2c_encoder = I2C_DRIVERID_ADV7175,
+		.video_codec = CODEC_TYPE_ZR36060,
+
+		.inputs = 3,
+		.input = {
+				{ 0, "Composite" },
+				{ 7, "S-Video" },
+				{ 5, "Internal/comp" }
+			},
+		.norms = 3,
+		.tvn = {
+				&f50sqpixel,
+				&f60sqpixel,
+				&f50sqpixel},
+		.jpeg_int = ZR36057_ISR_GIRQ0,
+		.vsync_int = ZR36057_ISR_GIRQ1,
+		.gpio = { 3, 0, 6, 1, 2, -1, 4, 5 },
+		.gpio_pol = { 0, 0, 0, 0, 0, 0, 0, 0 },
+		.gpcs = { -1, 1},
+		.vfe_pol = { 1, 1, 1, 1, 0, 0, 0, 0 },
+		.gws_not_connected = 0,
+		.input_mux = 0,
+		.init = &dc10plus_init,
+	}, {
+		.type = DC10plus,
+		.name = "DC10plus",
+		.vendor_id = PCI_VENDOR_ID_MIRO,
+		.device_id = PCI_DEVICE_ID_MIRO_DC10PLUS,
+		.i2c_decoder = I2C_DRIVERID_SAA7110,
+		.i2c_encoder = I2C_DRIVERID_ADV7175,
+		.video_codec = CODEC_TYPE_ZR36060,
+
+		.inputs = 3,
+		.input = {
+			{ 0, "Composite" },
+			{ 7, "S-Video" },
+			{ 5, "Internal/comp" }
+		},
+		.norms = 3,
+		.tvn = {
+			&f50sqpixel,
+			&f60sqpixel,
+			&f50sqpixel
+		},
+		.jpeg_int = ZR36057_ISR_GIRQ0,
+		.vsync_int = ZR36057_ISR_GIRQ1,
+		.gpio = { 3, 0, 6, 1, 2, -1, 4, 5 },
+		.gpio_pol = { 0, 0, 0, 0, 0, 0, 0, 0 },
+		.gpcs = { -1, 1 },
+		.vfe_pol = { 1, 1, 1, 1, 0, 0, 0, 0 },
+		.gws_not_connected = 0,
+		.input_mux = 0,
+		.init = &dc10plus_init,
+	}, {
+		.type = DC30,
+		.name = "DC30",
+		.i2c_decoder = I2C_DRIVERID_VPX3220,
+		.i2c_encoder = I2C_DRIVERID_ADV7175,
+		.video_codec = CODEC_TYPE_ZR36050,
+		.video_vfe = CODEC_TYPE_ZR36016,
+
+		.inputs = 3,
+		.input = {
+			{ 1, "Composite" },
+			{ 2, "S-Video" },
+			{ 0, "Internal/comp" }
+		},
+		.norms = 3,
+		.tvn = {
+			&f50sqpixel_dc10,
+			&f60sqpixel_dc10,
+			&f50sqpixel_dc10
+		},
+		.jpeg_int = 0,
+		.vsync_int = ZR36057_ISR_GIRQ1,
+		.gpio = { 2, 1, -1, 3, 7, 0, 4, 5 },
+		.gpio_pol = { 0, 0, 0, 1, 0, 0, 0, 0 },
+		.gpcs = { -1, 0 },
+		.vfe_pol = { 0, 0, 0, 0, 0, 0, 0, 0 },
+		.gws_not_connected = 0,
+		.input_mux = 0,
+		.init = &dc10_init,
+	}, {
+		.type = DC30plus,
+		.name = "DC30plus",
+		.vendor_id = PCI_VENDOR_ID_MIRO,
+		.device_id = PCI_DEVICE_ID_MIRO_DC30PLUS,
+		.i2c_decoder = I2C_DRIVERID_VPX3220,
+		.i2c_encoder = I2C_DRIVERID_ADV7175,
+		.video_codec = CODEC_TYPE_ZR36050,
+		.video_vfe = CODEC_TYPE_ZR36016,
+
+		.inputs = 3,
+		.input = {
+			{ 1, "Composite" },
+			{ 2, "S-Video" },
+			{ 0, "Internal/comp" }
+		},
+		.norms = 3,
+		.tvn = {
+			&f50sqpixel_dc10,
+			&f60sqpixel_dc10,
+			&f50sqpixel_dc10
+		},
+		.jpeg_int = 0,
+		.vsync_int = ZR36057_ISR_GIRQ1,
+		.gpio = { 2, 1, -1, 3, 7, 0, 4, 5 },
+		.gpio_pol = { 0, 0, 0, 1, 0, 0, 0, 0 },
+		.gpcs = { -1, 0 },
+		.vfe_pol = { 0, 0, 0, 0, 0, 0, 0, 0 },
+		.gws_not_connected = 0,
+		.input_mux = 0,
+		.init = &dc10_init,
+	}, {
+		.type = LML33,
+		.name = "LML33",
+		.i2c_decoder = I2C_DRIVERID_BT819,
+		.i2c_encoder = I2C_DRIVERID_BT856,
+		.video_codec = CODEC_TYPE_ZR36060,
+
+		.inputs = 2,
+		.input = {
+			{ 0, "Composite" },
+			{ 7, "S-Video" }
+		},
+		.norms = 2,
+		.tvn = {
+			&f50ccir601_lml33,
+			&f60ccir601_lml33,
+			NULL
+		},
+		.jpeg_int = ZR36057_ISR_GIRQ1,
+		.vsync_int = ZR36057_ISR_GIRQ0,
+		.gpio = { 1, -1, 3, 5, 7, -1, -1, -1 },
+		.gpio_pol = { 0, 0, 0, 0, 1, 0, 0, 0 },
+		.gpcs = { 3, 1 },
+		.vfe_pol = { 1, 1, 0, 0, 0, 1, 0, 0 },
+		.gws_not_connected = 1,
+		.input_mux = 0,
+		.init = &lml33_init,
+	}, {
+		.type = LML33R10,
+		.name = "LML33R10",
+		.vendor_id = PCI_VENDOR_ID_ELECTRONICDESIGNGMBH,
+		.device_id = PCI_DEVICE_ID_LML_33R10,
+		.i2c_decoder = I2C_DRIVERID_SAA7114,
+		.i2c_encoder = I2C_DRIVERID_ADV7170,
+		.video_codec = CODEC_TYPE_ZR36060,
+
+		.inputs = 2,
+		.input = {
+			{ 0, "Composite" },
+			{ 7, "S-Video" }
+		},
+		.norms = 2,
+		.tvn = {
+			&f50ccir601_lm33r10,
+			&f60ccir601_lm33r10,
+			NULL
+		},
+		.jpeg_int = ZR36057_ISR_GIRQ1,
+		.vsync_int = ZR36057_ISR_GIRQ0,
+		.gpio = { 1, -1, 3, 5, 7, -1, -1, -1 },
+		.gpio_pol = { 0, 0, 0, 0, 1, 0, 0, 0 },
+		.gpcs = { 3, 1 },
+		.vfe_pol = { 1, 1, 0, 0, 0, 1, 0, 0 },
+		.gws_not_connected = 1,
+		.input_mux = 0,
+		.init = &lml33_init,
+	}, {
+		.type = BUZ,
+		.name = "Buz",
+		.vendor_id = PCI_VENDOR_ID_IOMEGA,
+		.device_id = PCI_DEVICE_ID_IOMEGA_BUZ,
+		.i2c_decoder = I2C_DRIVERID_SAA7111A,
+		.i2c_encoder = I2C_DRIVERID_SAA7185B,
+		.video_codec = CODEC_TYPE_ZR36060,
+
+		.inputs = 2,
+		.input = {
+			{ 3, "Composite" },
+			{ 7, "S-Video" }
+		},
+		.norms = 3,
+		.tvn = {
+			&f50ccir601,
+			&f60ccir601,
+			&f50ccir601
+		},
+		.jpeg_int = ZR36057_ISR_GIRQ1,
+		.vsync_int = ZR36057_ISR_GIRQ0,
+		.gpio = { 1, -1, 3, -1, -1, -1, -1, -1 },
+		.gpio_pol = { 0, 0, 0, 0, 0, 0, 0, 0 },
+		.gpcs = { 3, 1 },
+		.vfe_pol = { 1, 1, 0, 0, 0, 1, 0, 0 },
+		.gws_not_connected = 1,
+		.input_mux = 0,
+		.init = &buz_init,
+	}, {
+		.type = AVS6EYES,
+		.name = "6-Eyes",
+		/* AverMedia chose not to brand the 6-Eyes. Thus it
+		   can't be autodetected, and requires card=x. */
+		.vendor_id = -1,
+		.device_id = -1,
+		.i2c_decoder = I2C_DRIVERID_KS0127,
+		.i2c_encoder = I2C_DRIVERID_BT866,
+		.video_codec = CODEC_TYPE_ZR36060,
+
+		.inputs = 10,
+		.input = {
+			{ 0, "Composite 1" },
+			{ 1, "Composite 2" },
+			{ 2, "Composite 3" },
+			{ 4, "Composite 4" },
+			{ 5, "Composite 5" },
+			{ 6, "Composite 6" },
+			{ 8, "S-Video 1" },
+			{ 9, "S-Video 2" },
+			{10, "S-Video 3" },
+			{15, "YCbCr" }
+		},
+		.norms = 2,
+		.tvn = {
+			&f50ccir601_avs6eyes,
+			&f60ccir601_avs6eyes,
+			NULL
+		},
+		.jpeg_int = ZR36057_ISR_GIRQ1,
+		.vsync_int = ZR36057_ISR_GIRQ0,
+		.gpio = { 1, 0, 3, -1, -1, -1, -1, -1 },// Validity unknown /Sam
+		.gpio_pol = { 0, 0, 0, 0, 0, 0, 0, 0 }, // Validity unknown /Sam
+		.gpcs = { 3, 1 },			// Validity unknown /Sam
+		.vfe_pol = { 1, 0, 0, 0, 0, 1, 0, 0 },  // Validity unknown /Sam
+		.gws_not_connected = 1,
+		.input_mux = 1,
+		.init = &avs6eyes_init,
+	}
+
+};
+
+/*
+ * I2C functions
+ */
+/* software I2C functions */
+static int
+zoran_i2c_getsda (void *data)
+{
+	struct zoran *zr = (struct zoran *) data;
+
+	return (btread(ZR36057_I2CBR) >> 1) & 1;
+}
+
+static int
+zoran_i2c_getscl (void *data)
+{
+	struct zoran *zr = (struct zoran *) data;
+
+	return btread(ZR36057_I2CBR) & 1;
+}
+
+static void
+zoran_i2c_setsda (void *data,
+		  int   state)
+{
+	struct zoran *zr = (struct zoran *) data;
+
+	if (state)
+		zr->i2cbr |= 2;
+	else
+		zr->i2cbr &= ~2;
+	btwrite(zr->i2cbr, ZR36057_I2CBR);
+}
+
+static void
+zoran_i2c_setscl (void *data,
+		  int   state)
+{
+	struct zoran *zr = (struct zoran *) data;
+
+	if (state)
+		zr->i2cbr |= 1;
+	else
+		zr->i2cbr &= ~1;
+	btwrite(zr->i2cbr, ZR36057_I2CBR);
+}
+
+static int
+zoran_i2c_client_register (struct i2c_client *client)
+{
+	struct zoran *zr = (struct zoran *) i2c_get_adapdata(client->adapter);
+	int res = 0;
+
+	dprintk(2,
+		KERN_DEBUG "%s: i2c_client_register() - driver id = %d\n",
+		ZR_DEVNAME(zr), client->driver->id);
+
+	mutex_lock(&zr->resource_lock);
+
+	if (zr->user > 0) {
+		/* we're already busy, so we keep a reference to
+		 * them... Could do a lot of stuff here, but this
+		 * is easiest. (Did I ever mention I'm a lazy ass?)
+		 */
+		res = -EBUSY;
+		goto clientreg_unlock_and_return;
+	}
+
+	if (client->driver->id == zr->card.i2c_decoder)
+		zr->decoder = client;
+	else if (client->driver->id == zr->card.i2c_encoder)
+		zr->encoder = client;
+	else {
+		res = -ENODEV;
+		goto clientreg_unlock_and_return;
+	}
+
+clientreg_unlock_and_return:
+	mutex_unlock(&zr->resource_lock);
+
+	return res;
+}
+
+static int
+zoran_i2c_client_unregister (struct i2c_client *client)
+{
+	struct zoran *zr = (struct zoran *) i2c_get_adapdata(client->adapter);
+	int res = 0;
+
+	dprintk(2, KERN_DEBUG "%s: i2c_client_unregister()\n", ZR_DEVNAME(zr));
+
+	mutex_lock(&zr->resource_lock);
+
+	if (zr->user > 0) {
+		res = -EBUSY;
+		goto clientunreg_unlock_and_return;
+	}
+
+	/* try to locate it */
+	if (client == zr->encoder) {
+		zr->encoder = NULL;
+	} else if (client == zr->decoder) {
+		zr->decoder = NULL;
+		snprintf(ZR_DEVNAME(zr), sizeof(ZR_DEVNAME(zr)), "MJPEG[%d]", zr->id);
+	}
+clientunreg_unlock_and_return:
+	mutex_unlock(&zr->resource_lock);
+	return res;
+}
+
+static const struct i2c_algo_bit_data zoran_i2c_bit_data_template = {
+	.setsda = zoran_i2c_setsda,
+	.setscl = zoran_i2c_setscl,
+	.getsda = zoran_i2c_getsda,
+	.getscl = zoran_i2c_getscl,
+	.udelay = 10,
+	.timeout = 100,
+};
+
+static int
+zoran_register_i2c (struct zoran *zr)
+{
+	memcpy(&zr->i2c_algo, &zoran_i2c_bit_data_template,
+	       sizeof(struct i2c_algo_bit_data));
+	zr->i2c_algo.data = zr;
+	zr->i2c_adapter.id = I2C_HW_B_ZR36067;
+	zr->i2c_adapter.client_register = zoran_i2c_client_register;
+	zr->i2c_adapter.client_unregister = zoran_i2c_client_unregister;
+	strlcpy(zr->i2c_adapter.name, ZR_DEVNAME(zr),
+		sizeof(zr->i2c_adapter.name));
+	i2c_set_adapdata(&zr->i2c_adapter, zr);
+	zr->i2c_adapter.algo_data = &zr->i2c_algo;
+	zr->i2c_adapter.dev.parent = &zr->pci_dev->dev;
+	return i2c_bit_add_bus(&zr->i2c_adapter);
+}
+
+static void
+zoran_unregister_i2c (struct zoran *zr)
+{
+	i2c_del_adapter(&zr->i2c_adapter);
+}
+
+/* Check a zoran_params struct for correctness, insert default params */
+
+int
+zoran_check_jpg_settings (struct zoran              *zr,
+			  struct zoran_jpg_settings *settings)
+{
+	int err = 0, err0 = 0;
+
+	dprintk(4,
+		KERN_DEBUG
+		"%s: check_jpg_settings() - dec: %d, Hdcm: %d, Vdcm: %d, Tdcm: %d\n",
+		ZR_DEVNAME(zr), settings->decimation, settings->HorDcm,
+		settings->VerDcm, settings->TmpDcm);
+	dprintk(4,
+		KERN_DEBUG
+		"%s: check_jpg_settings() - x: %d, y: %d, w: %d, y: %d\n",
+		ZR_DEVNAME(zr), settings->img_x, settings->img_y,
+		settings->img_width, settings->img_height);
+	/* Check decimation, set default values for decimation = 1, 2, 4 */
+	switch (settings->decimation) {
+	case 1:
+
+		settings->HorDcm = 1;
+		settings->VerDcm = 1;
+		settings->TmpDcm = 1;
+		settings->field_per_buff = 2;
+		settings->img_x = 0;
+		settings->img_y = 0;
+		settings->img_width = BUZ_MAX_WIDTH;
+		settings->img_height = BUZ_MAX_HEIGHT / 2;
+		break;
+	case 2:
+
+		settings->HorDcm = 2;
+		settings->VerDcm = 1;
+		settings->TmpDcm = 2;
+		settings->field_per_buff = 1;
+		settings->img_x = (BUZ_MAX_WIDTH == 720) ? 8 : 0;
+		settings->img_y = 0;
+		settings->img_width =
+		    (BUZ_MAX_WIDTH == 720) ? 704 : BUZ_MAX_WIDTH;
+		settings->img_height = BUZ_MAX_HEIGHT / 2;
+		break;
+	case 4:
+
+		if (zr->card.type == DC10_new) {
+			dprintk(1,
+				KERN_DEBUG
+				"%s: check_jpg_settings() - HDec by 4 is not supported on the DC10\n",
+				ZR_DEVNAME(zr));
+			err0++;
+			break;
+		}
+
+		settings->HorDcm = 4;
+		settings->VerDcm = 2;
+		settings->TmpDcm = 2;
+		settings->field_per_buff = 1;
+		settings->img_x = (BUZ_MAX_WIDTH == 720) ? 8 : 0;
+		settings->img_y = 0;
+		settings->img_width =
+		    (BUZ_MAX_WIDTH == 720) ? 704 : BUZ_MAX_WIDTH;
+		settings->img_height = BUZ_MAX_HEIGHT / 2;
+		break;
+	case 0:
+
+		/* We have to check the data the user has set */
+
+		if (settings->HorDcm != 1 && settings->HorDcm != 2 &&
+		    (zr->card.type == DC10_new || settings->HorDcm != 4))
+			err0++;
+		if (settings->VerDcm != 1 && settings->VerDcm != 2)
+			err0++;
+		if (settings->TmpDcm != 1 && settings->TmpDcm != 2)
+			err0++;
+		if (settings->field_per_buff != 1 &&
+		    settings->field_per_buff != 2)
+			err0++;
+		if (settings->img_x < 0)
+			err0++;
+		if (settings->img_y < 0)
+			err0++;
+		if (settings->img_width < 0)
+			err0++;
+		if (settings->img_height < 0)
+			err0++;
+		if (settings->img_x + settings->img_width > BUZ_MAX_WIDTH)
+			err0++;
+		if (settings->img_y + settings->img_height >
+		    BUZ_MAX_HEIGHT / 2)
+			err0++;
+		if (settings->HorDcm && settings->VerDcm) {
+			if (settings->img_width %
+			    (16 * settings->HorDcm) != 0)
+				err0++;
+			if (settings->img_height %
+			    (8 * settings->VerDcm) != 0)
+				err0++;
+		}
+
+		if (err0) {
+			dprintk(1,
+				KERN_ERR
+				"%s: check_jpg_settings() - error in params for decimation = 0\n",
+				ZR_DEVNAME(zr));
+			err++;
+		}
+		break;
+	default:
+		dprintk(1,
+			KERN_ERR
+			"%s: check_jpg_settings() - decimation = %d, must be 0, 1, 2 or 4\n",
+			ZR_DEVNAME(zr), settings->decimation);
+		err++;
+		break;
+	}
+
+	if (settings->jpg_comp.quality > 100)
+		settings->jpg_comp.quality = 100;
+	if (settings->jpg_comp.quality < 5)
+		settings->jpg_comp.quality = 5;
+	if (settings->jpg_comp.APPn < 0)
+		settings->jpg_comp.APPn = 0;
+	if (settings->jpg_comp.APPn > 15)
+		settings->jpg_comp.APPn = 15;
+	if (settings->jpg_comp.APP_len < 0)
+		settings->jpg_comp.APP_len = 0;
+	if (settings->jpg_comp.APP_len > 60)
+		settings->jpg_comp.APP_len = 60;
+	if (settings->jpg_comp.COM_len < 0)
+		settings->jpg_comp.COM_len = 0;
+	if (settings->jpg_comp.COM_len > 60)
+		settings->jpg_comp.COM_len = 60;
+	if (err)
+		return -EINVAL;
+	return 0;
+}
+
+void
+zoran_open_init_params (struct zoran *zr)
+{
+	int i;
+
+	/* User must explicitly set a window */
+	zr->overlay_settings.is_set = 0;
+	zr->overlay_mask = NULL;
+	zr->overlay_active = ZORAN_FREE;
+
+	zr->v4l_memgrab_active = 0;
+	zr->v4l_overlay_active = 0;
+	zr->v4l_grab_frame = NO_GRAB_ACTIVE;
+	zr->v4l_grab_seq = 0;
+	zr->v4l_settings.width = 192;
+	zr->v4l_settings.height = 144;
+	zr->v4l_settings.format = &zoran_formats[7];	/* YUY2 - YUV-4:2:2 packed */
+	zr->v4l_settings.bytesperline =
+	    zr->v4l_settings.width *
+	    ((zr->v4l_settings.format->depth + 7) / 8);
+
+	/* DMA ring stuff for V4L */
+	zr->v4l_pend_tail = 0;
+	zr->v4l_pend_head = 0;
+	zr->v4l_sync_tail = 0;
+	zr->v4l_buffers.active = ZORAN_FREE;
+	for (i = 0; i < VIDEO_MAX_FRAME; i++) {
+		zr->v4l_buffers.buffer[i].state = BUZ_STATE_USER;	/* nothing going on */
+	}
+	zr->v4l_buffers.allocated = 0;
+
+	for (i = 0; i < BUZ_MAX_FRAME; i++) {
+		zr->jpg_buffers.buffer[i].state = BUZ_STATE_USER;	/* nothing going on */
+	}
+	zr->jpg_buffers.active = ZORAN_FREE;
+	zr->jpg_buffers.allocated = 0;
+	/* Set necessary params and call zoran_check_jpg_settings to set the defaults */
+	zr->jpg_settings.decimation = 1;
+	zr->jpg_settings.jpg_comp.quality = 50;	/* default compression factor 8 */
+	if (zr->card.type != BUZ)
+		zr->jpg_settings.odd_even = 1;
+	else
+		zr->jpg_settings.odd_even = 0;
+	zr->jpg_settings.jpg_comp.APPn = 0;
+	zr->jpg_settings.jpg_comp.APP_len = 0;	/* No APPn marker */
+	memset(zr->jpg_settings.jpg_comp.APP_data, 0,
+	       sizeof(zr->jpg_settings.jpg_comp.APP_data));
+	zr->jpg_settings.jpg_comp.COM_len = 0;	/* No COM marker */
+	memset(zr->jpg_settings.jpg_comp.COM_data, 0,
+	       sizeof(zr->jpg_settings.jpg_comp.COM_data));
+	zr->jpg_settings.jpg_comp.jpeg_markers =
+	    JPEG_MARKER_DHT | JPEG_MARKER_DQT;
+	i = zoran_check_jpg_settings(zr, &zr->jpg_settings);
+	if (i)
+		dprintk(1,
+			KERN_ERR
+			"%s: zoran_open_init_params() internal error\n",
+			ZR_DEVNAME(zr));
+
+	clear_interrupt_counters(zr);
+	zr->testing = 0;
+}
+
+static void __devinit
+test_interrupts (struct zoran *zr)
+{
+	DEFINE_WAIT(wait);
+	int timeout, icr;
+
+	clear_interrupt_counters(zr);
+
+	zr->testing = 1;
+	icr = btread(ZR36057_ICR);
+	btwrite(0x78000000 | ZR36057_ICR_IntPinEn, ZR36057_ICR);
+	prepare_to_wait(&zr->test_q, &wait, TASK_INTERRUPTIBLE);
+	timeout = schedule_timeout(HZ);
+	finish_wait(&zr->test_q, &wait);
+	btwrite(0, ZR36057_ICR);
+	btwrite(0x78000000, ZR36057_ISR);
+	zr->testing = 0;
+	dprintk(5, KERN_INFO "%s: Testing interrupts...\n", ZR_DEVNAME(zr));
+	if (timeout) {
+		dprintk(1, ": time spent: %d\n", 1 * HZ - timeout);
+	}
+	if (zr36067_debug > 1)
+		print_interrupts(zr);
+	btwrite(icr, ZR36057_ICR);
+}
+
+static int __devinit
+zr36057_init (struct zoran *zr)
+{
+	int j, err;
+	int two = 2;
+	int zero = 0;
+
+	dprintk(1,
+		KERN_INFO
+		"%s: zr36057_init() - initializing card[%d], zr=%p\n",
+		ZR_DEVNAME(zr), zr->id, zr);
+
+	/* default setup of all parameters which will persist between opens */
+	zr->user = 0;
+
+	init_waitqueue_head(&zr->v4l_capq);
+	init_waitqueue_head(&zr->jpg_capq);
+	init_waitqueue_head(&zr->test_q);
+	zr->jpg_buffers.allocated = 0;
+	zr->v4l_buffers.allocated = 0;
+
+	zr->buffer.base = (void *) vidmem;
+	zr->buffer.width = 0;
+	zr->buffer.height = 0;
+	zr->buffer.depth = 0;
+	zr->buffer.bytesperline = 0;
+
+	/* Avoid nonsense settings from user for default input/norm */
+	if (default_norm < VIDEO_MODE_PAL &&
+	    default_norm > VIDEO_MODE_SECAM)
+		default_norm = VIDEO_MODE_PAL;
+	zr->norm = default_norm;
+	if (!(zr->timing = zr->card.tvn[zr->norm])) {
+		dprintk(1,
+			KERN_WARNING
+			"%s: zr36057_init() - default TV standard not supported by hardware. PAL will be used.\n",
+			ZR_DEVNAME(zr));
+		zr->norm = VIDEO_MODE_PAL;
+		zr->timing = zr->card.tvn[zr->norm];
+	}
+
+	if (default_input > zr->card.inputs-1) {
+		dprintk(1,
+			KERN_WARNING
+			"%s: default_input value %d out of range (0-%d)\n",
+			ZR_DEVNAME(zr), default_input, zr->card.inputs-1);
+		default_input = 0;
+	}
+	zr->input = default_input;
+
+	/* Should the following be reset at every open ? */
+	zr->hue = 32768;
+	zr->contrast = 32768;
+	zr->saturation = 32768;
+	zr->brightness = 32768;
+
+	/* default setup (will be repeated at every open) */
+	zoran_open_init_params(zr);
+
+	/* allocate memory *before* doing anything to the hardware
+	 * in case allocation fails */
+	zr->stat_com = kzalloc(BUZ_NUM_STAT_COM * 4, GFP_KERNEL);
+	zr->video_dev = kmalloc(sizeof(struct video_device), GFP_KERNEL);
+	if (!zr->stat_com || !zr->video_dev) {
+		dprintk(1,
+			KERN_ERR
+			"%s: zr36057_init() - kmalloc (STAT_COM) failed\n",
+			ZR_DEVNAME(zr));
+		err = -ENOMEM;
+		goto exit_free;
+	}
+	for (j = 0; j < BUZ_NUM_STAT_COM; j++) {
+		zr->stat_com[j] = cpu_to_le32(1); /* mark as unavailable to zr36057 */
+	}
+
+	/*
+	 *   Now add the template and register the device unit.
+	 */
+	memcpy(zr->video_dev, &zoran_template, sizeof(zoran_template));
+	strcpy(zr->video_dev->name, ZR_DEVNAME(zr));
+	err = video_register_device(zr->video_dev, VFL_TYPE_GRABBER, video_nr[zr->id]);
+	if (err < 0)
+		goto exit_unregister;
+
+	zoran_init_hardware(zr);
+	if (zr36067_debug > 2)
+		detect_guest_activity(zr);
+	test_interrupts(zr);
+	if (!pass_through) {
+		decoder_command(zr, DECODER_ENABLE_OUTPUT, &zero);
+		encoder_command(zr, ENCODER_SET_INPUT, &two);
+	}
+
+	zr->zoran_proc = NULL;
+	zr->initialized = 1;
+	return 0;
+
+exit_unregister:
+	zoran_unregister_i2c(zr);
+exit_free:
+	kfree(zr->stat_com);
+	kfree(zr->video_dev);
+	return err;
+}
+
+static void
+zoran_release (struct zoran *zr)
+{
+	if (!zr->initialized)
+		goto exit_free;
+	/* unregister videocodec bus */
+	if (zr->codec) {
+		struct videocodec_master *master = zr->codec->master_data;
+
+		videocodec_detach(zr->codec);
+		kfree(master);
+	}
+	if (zr->vfe) {
+		struct videocodec_master *master = zr->vfe->master_data;
+
+		videocodec_detach(zr->vfe);
+		kfree(master);
+	}
+
+	/* unregister i2c bus */
+	zoran_unregister_i2c(zr);
+	/* disable PCI bus-mastering */
+	zoran_set_pci_master(zr, 0);
+	/* put chip into reset */
+	btwrite(0, ZR36057_SPGPPCR);
+	free_irq(zr->pci_dev->irq, zr);
+	/* unmap and free memory */
+	kfree(zr->stat_com);
+	zoran_proc_cleanup(zr);
+	iounmap(zr->zr36057_mem);
+	pci_disable_device(zr->pci_dev);
+	video_unregister_device(zr->video_dev);
+exit_free:
+	kfree(zr);
+}
+
+void
+zoran_vdev_release (struct video_device *vdev)
+{
+	kfree(vdev);
+}
+
+static struct videocodec_master * __devinit
+zoran_setup_videocodec (struct zoran *zr,
+			int           type)
+{
+	struct videocodec_master *m = NULL;
+
+	m = kmalloc(sizeof(struct videocodec_master), GFP_KERNEL);
+	if (!m) {
+		dprintk(1,
+			KERN_ERR
+			"%s: zoran_setup_videocodec() - no memory\n",
+			ZR_DEVNAME(zr));
+		return m;
+	}
+
+	/* magic and type are unused for master struct. Makes sense only at
+	   codec structs.
+	   In the past, .type were initialized to the old V4L1 .hardware
+	   value, as VID_HARDWARE_ZR36067
+	 */
+	m->magic = 0L;
+	m->type = 0;
+
+	m->flags = CODEC_FLAG_ENCODER | CODEC_FLAG_DECODER;
+	strncpy(m->name, ZR_DEVNAME(zr), sizeof(m->name));
+	m->data = zr;
+
+	switch (type)
+	{
+	case CODEC_TYPE_ZR36060:
+		m->readreg = zr36060_read;
+		m->writereg = zr36060_write;
+		m->flags |= CODEC_FLAG_JPEG | CODEC_FLAG_VFE;
+		break;
+	case CODEC_TYPE_ZR36050:
+		m->readreg = zr36050_read;
+		m->writereg = zr36050_write;
+		m->flags |= CODEC_FLAG_JPEG;
+		break;
+	case CODEC_TYPE_ZR36016:
+		m->readreg = zr36016_read;
+		m->writereg = zr36016_write;
+		m->flags |= CODEC_FLAG_VFE;
+		break;
+	}
+
+	return m;
+}
+
+/*
+ *   Scan for a Buz card (actually for the PCI controller ZR36057),
+ *   request the irq and map the io memory
+ */
+static int __devinit
+find_zr36057 (void)
+{
+	unsigned char latency, need_latency;
+	struct zoran *zr;
+	struct pci_dev *dev = NULL;
+	int result;
+	struct videocodec_master *master_vfe = NULL;
+	struct videocodec_master *master_codec = NULL;
+	int card_num;
+	char *i2c_enc_name, *i2c_dec_name, *codec_name, *vfe_name;
+
+	zoran_num = 0;
+	while (zoran_num < BUZ_MAX &&
+	       (dev = pci_get_device(PCI_VENDOR_ID_ZORAN, PCI_DEVICE_ID_ZORAN_36057, dev)) != NULL) {
+		card_num = card[zoran_num];
+		zr = kzalloc(sizeof(struct zoran), GFP_KERNEL);
+		if (!zr) {
+			dprintk(1,
+				KERN_ERR
+				"%s: find_zr36057() - kzalloc failed\n",
+				ZORAN_NAME);
+			continue;
+		}
+		zr->pci_dev = dev;
+		//zr->zr36057_mem = NULL;
+		zr->id = zoran_num;
+		snprintf(ZR_DEVNAME(zr), sizeof(ZR_DEVNAME(zr)), "MJPEG[%u]", zr->id);
+		spin_lock_init(&zr->spinlock);
+		mutex_init(&zr->resource_lock);
+		if (pci_enable_device(dev))
+			goto zr_free_mem;
+		zr->zr36057_adr = pci_resource_start(zr->pci_dev, 0);
+		pci_read_config_byte(zr->pci_dev, PCI_CLASS_REVISION,
+				     &zr->revision);
+		if (zr->revision < 2) {
+			dprintk(1,
+				KERN_INFO
+				"%s: Zoran ZR36057 (rev %d) irq: %d, memory: 0x%08x.\n",
+				ZR_DEVNAME(zr), zr->revision, zr->pci_dev->irq,
+				zr->zr36057_adr);
+
+			if (card_num == -1) {
+				dprintk(1,
+					KERN_ERR
+					"%s: find_zr36057() - no card specified, please use the card=X insmod option\n",
+					ZR_DEVNAME(zr));
+				goto zr_free_mem;
+			}
+		} else {
+			int i;
+			unsigned short ss_vendor, ss_device;
+
+			ss_vendor = zr->pci_dev->subsystem_vendor;
+			ss_device = zr->pci_dev->subsystem_device;
+			dprintk(1,
+				KERN_INFO
+				"%s: Zoran ZR36067 (rev %d) irq: %d, memory: 0x%08x\n",
+				ZR_DEVNAME(zr), zr->revision, zr->pci_dev->irq,
+				zr->zr36057_adr);
+			dprintk(1,
+				KERN_INFO
+				"%s: subsystem vendor=0x%04x id=0x%04x\n",
+				ZR_DEVNAME(zr), ss_vendor, ss_device);
+			if (card_num == -1) {
+				dprintk(3,
+					KERN_DEBUG
+					"%s: find_zr36057() - trying to autodetect card type\n",
+					ZR_DEVNAME(zr));
+				for (i=0;i<NUM_CARDS;i++) {
+					if (ss_vendor == zoran_cards[i].vendor_id &&
+					    ss_device == zoran_cards[i].device_id) {
+						dprintk(3,
+							KERN_DEBUG
+							"%s: find_zr36057() - card %s detected\n",
+							ZR_DEVNAME(zr),
+							zoran_cards[i].name);
+						card_num = i;
+						break;
+					}
+				}
+				if (i == NUM_CARDS) {
+					dprintk(1,
+						KERN_ERR
+						"%s: find_zr36057() - unknown card\n",
+						ZR_DEVNAME(zr));
+					goto zr_free_mem;
+				}
+			}
+		}
+
+		if (card_num < 0 || card_num >= NUM_CARDS) {
+			dprintk(2,
+				KERN_ERR
+				"%s: find_zr36057() - invalid cardnum %d\n",
+				ZR_DEVNAME(zr), card_num);
+			goto zr_free_mem;
+		}
+
+		/* even though we make this a non pointer and thus
+		 * theoretically allow for making changes to this struct
+		 * on a per-individual card basis at runtime, this is
+		 * strongly discouraged. This structure is intended to
+		 * keep general card information, no settings or anything */
+		zr->card = zoran_cards[card_num];
+		snprintf(ZR_DEVNAME(zr), sizeof(ZR_DEVNAME(zr)),
+			 "%s[%u]", zr->card.name, zr->id);
+
+		zr->zr36057_mem = ioremap_nocache(zr->zr36057_adr, 0x1000);
+		if (!zr->zr36057_mem) {
+			dprintk(1,
+				KERN_ERR
+				"%s: find_zr36057() - ioremap failed\n",
+				ZR_DEVNAME(zr));
+			goto zr_free_mem;
+		}
+
+		result = request_irq(zr->pci_dev->irq,
+				     zoran_irq,
+				     IRQF_SHARED | IRQF_DISABLED,
+				     ZR_DEVNAME(zr),
+				     (void *) zr);
+		if (result < 0) {
+			if (result == -EINVAL) {
+				dprintk(1,
+					KERN_ERR
+					"%s: find_zr36057() - bad irq number or handler\n",
+					ZR_DEVNAME(zr));
+			} else if (result == -EBUSY) {
+				dprintk(1,
+					KERN_ERR
+					"%s: find_zr36057() - IRQ %d busy, change your PnP config in BIOS\n",
+					ZR_DEVNAME(zr), zr->pci_dev->irq);
+			} else {
+				dprintk(1,
+					KERN_ERR
+					"%s: find_zr36057() - can't assign irq, error code %d\n",
+					ZR_DEVNAME(zr), result);
+			}
+			goto zr_unmap;
+		}
+
+		/* set PCI latency timer */
+		pci_read_config_byte(zr->pci_dev, PCI_LATENCY_TIMER,
+				     &latency);
+		need_latency = zr->revision > 1 ? 32 : 48;
+		if (latency != need_latency) {
+			dprintk(2,
+				KERN_INFO
+				"%s: Changing PCI latency from %d to %d.\n",
+				ZR_DEVNAME(zr), latency, need_latency);
+			pci_write_config_byte(zr->pci_dev,
+					      PCI_LATENCY_TIMER,
+					      need_latency);
+		}
+
+		zr36057_restart(zr);
+		/* i2c */
+		dprintk(2, KERN_INFO "%s: Initializing i2c bus...\n",
+			ZR_DEVNAME(zr));
+
+		/* i2c decoder */
+		if (decoder[zr->id] != -1) {
+			i2c_dec_name = i2cid_to_modulename(decoder[zr->id]);
+			zr->card.i2c_decoder = decoder[zr->id];
+		} else if (zr->card.i2c_decoder != 0) {
+			i2c_dec_name =
+				i2cid_to_modulename(zr->card.i2c_decoder);
+		} else {
+			i2c_dec_name = NULL;
+		}
+
+		if (i2c_dec_name) {
+			if ((result = request_module(i2c_dec_name)) < 0) {
+				dprintk(1,
+					KERN_ERR
+					"%s: failed to load module %s: %d\n",
+					ZR_DEVNAME(zr), i2c_dec_name, result);
+			}
+		}
+
+		/* i2c encoder */
+		if (encoder[zr->id] != -1) {
+			i2c_enc_name = i2cid_to_modulename(encoder[zr->id]);
+			zr->card.i2c_encoder = encoder[zr->id];
+		} else if (zr->card.i2c_encoder != 0) {
+			i2c_enc_name =
+				i2cid_to_modulename(zr->card.i2c_encoder);
+		} else {
+			i2c_enc_name = NULL;
+		}
+
+		if (i2c_enc_name) {
+			if ((result = request_module(i2c_enc_name)) < 0) {
+				dprintk(1,
+					KERN_ERR
+					"%s: failed to load module %s: %d\n",
+					ZR_DEVNAME(zr), i2c_enc_name, result);
+			}
+		}
+
+		if (zoran_register_i2c(zr) < 0) {
+			dprintk(1,
+				KERN_ERR
+				"%s: find_zr36057() - can't initialize i2c bus\n",
+				ZR_DEVNAME(zr));
+			goto zr_free_irq;
+		}
+
+		dprintk(2,
+			KERN_INFO "%s: Initializing videocodec bus...\n",
+			ZR_DEVNAME(zr));
+
+		if (zr->card.video_codec != 0 &&
+		    (codec_name =
+		     codecid_to_modulename(zr->card.video_codec)) != NULL) {
+			if ((result = request_module(codec_name)) < 0) {
+				dprintk(1,
+					KERN_ERR
+					"%s: failed to load modules %s: %d\n",
+					ZR_DEVNAME(zr), codec_name, result);
+			}
+		}
+		if (zr->card.video_vfe != 0 &&
+		    (vfe_name =
+		     codecid_to_modulename(zr->card.video_vfe)) != NULL) {
+			if ((result = request_module(vfe_name)) < 0) {
+				dprintk(1,
+					KERN_ERR
+					"%s: failed to load modules %s: %d\n",
+					ZR_DEVNAME(zr), vfe_name, result);
+			}
+		}
+
+		/* reset JPEG codec */
+		jpeg_codec_sleep(zr, 1);
+		jpeg_codec_reset(zr);
+		/* video bus enabled */
+		/* display codec revision */
+		if (zr->card.video_codec != 0) {
+			master_codec = zoran_setup_videocodec(zr,
+							      zr->card.video_codec);
+			if (!master_codec)
+				goto zr_unreg_i2c;
+			zr->codec = videocodec_attach(master_codec);
+			if (!zr->codec) {
+				dprintk(1,
+					KERN_ERR
+					"%s: find_zr36057() - no codec found\n",
+					ZR_DEVNAME(zr));
+				goto zr_free_codec;
+			}
+			if (zr->codec->type != zr->card.video_codec) {
+				dprintk(1,
+					KERN_ERR
+					"%s: find_zr36057() - wrong codec\n",
+					ZR_DEVNAME(zr));
+				goto zr_detach_codec;
+			}
+		}
+		if (zr->card.video_vfe != 0) {
+			master_vfe = zoran_setup_videocodec(zr,
+							    zr->card.video_vfe);
+			if (!master_vfe)
+				goto zr_detach_codec;
+			zr->vfe = videocodec_attach(master_vfe);
+			if (!zr->vfe) {
+				dprintk(1,
+					KERN_ERR
+					"%s: find_zr36057() - no VFE found\n",
+					ZR_DEVNAME(zr));
+				goto zr_free_vfe;
+			}
+			if (zr->vfe->type != zr->card.video_vfe) {
+				dprintk(1,
+					KERN_ERR
+					"%s: find_zr36057() = wrong VFE\n",
+					ZR_DEVNAME(zr));
+				goto zr_detach_vfe;
+			}
+		}
+		/* Success so keep the pci_dev referenced */
+		pci_dev_get(zr->pci_dev);
+		zoran[zoran_num++] = zr;
+		continue;
+
+		// Init errors
+	      zr_detach_vfe:
+		videocodec_detach(zr->vfe);
+	      zr_free_vfe:
+		kfree(master_vfe);
+	      zr_detach_codec:
+		videocodec_detach(zr->codec);
+	      zr_free_codec:
+		kfree(master_codec);
+	      zr_unreg_i2c:
+		zoran_unregister_i2c(zr);
+	      zr_free_irq:
+		btwrite(0, ZR36057_SPGPPCR);
+		free_irq(zr->pci_dev->irq, zr);
+	      zr_unmap:
+		iounmap(zr->zr36057_mem);
+	      zr_free_mem:
+		kfree(zr);
+		continue;
+	}
+	if (dev)	/* Clean up ref count on early exit */
+		pci_dev_put(dev);
+
+	if (zoran_num == 0) {
+		dprintk(1, KERN_INFO "No known MJPEG cards found.\n");
+	}
+	return zoran_num;
+}
+
+static int __init
+init_dc10_cards (void)
+{
+	int i;
+
+	memset(zoran, 0, sizeof(zoran));
+	printk(KERN_INFO "Zoran MJPEG board driver version %d.%d.%d\n",
+	       MAJOR_VERSION, MINOR_VERSION, RELEASE_VERSION);
+
+	/* Look for cards */
+	if (find_zr36057() < 0) {
+		return -EIO;
+	}
+	if (zoran_num == 0)
+		return -ENODEV;
+	dprintk(1, KERN_INFO "%s: %d card(s) found\n", ZORAN_NAME,
+		zoran_num);
+	/* check the parameters we have been given, adjust if necessary */
+	if (v4l_nbufs < 2)
+		v4l_nbufs = 2;
+	if (v4l_nbufs > VIDEO_MAX_FRAME)
+		v4l_nbufs = VIDEO_MAX_FRAME;
+	/* The user specfies the in KB, we want them in byte
+	 * (and page aligned) */
+	v4l_bufsize = PAGE_ALIGN(v4l_bufsize * 1024);
+	if (v4l_bufsize < 32768)
+		v4l_bufsize = 32768;
+	/* 2 MB is arbitrary but sufficient for the maximum possible images */
+	if (v4l_bufsize > 2048 * 1024)
+		v4l_bufsize = 2048 * 1024;
+	if (jpg_nbufs < 4)
+		jpg_nbufs = 4;
+	if (jpg_nbufs > BUZ_MAX_FRAME)
+		jpg_nbufs = BUZ_MAX_FRAME;
+	jpg_bufsize = PAGE_ALIGN(jpg_bufsize * 1024);
+	if (jpg_bufsize < 8192)
+		jpg_bufsize = 8192;
+	if (jpg_bufsize > (512 * 1024))
+		jpg_bufsize = 512 * 1024;
+	/* Use parameter for vidmem or try to find a video card */
+	if (vidmem) {
+		dprintk(1,
+			KERN_INFO
+			"%s: Using supplied video memory base address @ 0x%lx\n",
+			ZORAN_NAME, vidmem);
+	}
+
+	/* random nonsense */
+	dprintk(6, KERN_DEBUG "Jotti is een held!\n");
+
+	/* some mainboards might not do PCI-PCI data transfer well */
+	if (pci_pci_problems & (PCIPCI_FAIL|PCIAGP_FAIL|PCIPCI_ALIMAGIK)) {
+		dprintk(1,
+			KERN_WARNING
+			"%s: chipset does not support reliable PCI-PCI DMA\n",
+			ZORAN_NAME);
+	}
+
+	/* take care of Natoma chipset and a revision 1 zr36057 */
+	for (i = 0; i < zoran_num; i++) {
+		struct zoran *zr = zoran[i];
+
+		if ((pci_pci_problems & PCIPCI_NATOMA) && zr->revision <= 1) {
+			zr->jpg_buffers.need_contiguous = 1;
+			dprintk(1,
+				KERN_INFO
+				"%s: ZR36057/Natoma bug, max. buffer size is 128K\n",
+				ZR_DEVNAME(zr));
+		}
+
+		if (zr36057_init(zr) < 0) {
+			for (i = 0; i < zoran_num; i++)
+				zoran_release(zoran[i]);
+			return -EIO;
+		}
+		zoran_proc_init(zr);
+	}
+
+	return 0;
+}
+
+static void __exit
+unload_dc10_cards (void)
+{
+	int i;
+
+	for (i = 0; i < zoran_num; i++)
+		zoran_release(zoran[i]);
+}
+
+module_init(init_dc10_cards);
+module_exit(unload_dc10_cards);
diff --git a/drivers/media/video/zoran_card.h b/drivers/media/video/zoran/zoran_card.h
similarity index 100%
rename from drivers/media/video/zoran_card.h
rename to drivers/media/video/zoran/zoran_card.h
diff --git a/drivers/media/video/zoran/zoran_device.c b/drivers/media/video/zoran/zoran_device.c
new file mode 100644
index 0000000..5d948ff
--- /dev/null
+++ b/drivers/media/video/zoran/zoran_device.c
@@ -0,0 +1,1747 @@
+/*
+ * Zoran zr36057/zr36067 PCI controller driver, for the
+ * Pinnacle/Miro DC10/DC10+/DC30/DC30+, Iomega Buz, Linux
+ * Media Labs LML33/LML33R10.
+ *
+ * This part handles device access (PCI/I2C/codec/...)
+ *
+ * Copyright (C) 2000 Serguei Miridonov <mirsev@cicese.mx>
+ *
+ * Currently maintained by:
+ *   Ronald Bultje    <rbultje@ronald.bitfreak.net>
+ *   Laurent Pinchart <laurent.pinchart@skynet.be>
+ *   Mailinglist      <mjpeg-users@lists.sf.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU 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/types.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/vmalloc.h>
+
+#include <linux/interrupt.h>
+#include <linux/proc_fs.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+#include <linux/videodev.h>
+#include <linux/spinlock.h>
+#include <linux/sem.h>
+
+#include <linux/pci.h>
+#include <linux/video_decoder.h>
+#include <linux/video_encoder.h>
+#include <linux/delay.h>
+#include <linux/wait.h>
+
+#include <asm/byteorder.h>
+#include <asm/io.h>
+
+#include "videocodec.h"
+#include "zoran.h"
+#include "zoran_device.h"
+#include "zoran_card.h"
+
+#define IRQ_MASK ( ZR36057_ISR_GIRQ0 | \
+		   ZR36057_ISR_GIRQ1 | \
+		   ZR36057_ISR_JPEGRepIRQ )
+
+static int lml33dpath;		/* default = 0
+				 * 1 will use digital path in capture
+				 * mode instead of analog. It can be
+				 * used for picture adjustments using
+				 * tool like xawtv while watching image
+				 * on TV monitor connected to the output.
+				 * However, due to absence of 75 Ohm
+				 * load on Bt819 input, there will be
+				 * some image imperfections */
+
+module_param(lml33dpath, bool, 0644);
+MODULE_PARM_DESC(lml33dpath,
+		 "Use digital path capture mode (on LML33 cards)");
+
+static void
+zr36057_init_vfe (struct zoran *zr);
+
+/*
+ * General Purpose I/O and Guest bus access
+ */
+
+/*
+ * This is a bit tricky. When a board lacks a GPIO function, the corresponding
+ * GPIO bit number in the card_info structure is set to 0.
+ */
+
+void
+GPIO (struct zoran *zr,
+      int           bit,
+      unsigned int  value)
+{
+	u32 reg;
+	u32 mask;
+
+	/* Make sure the bit number is legal
+	 * A bit number of -1 (lacking) gives a mask of 0,
+	 * making it harmless */
+	mask = (1 << (24 + bit)) & 0xff000000;
+	reg = btread(ZR36057_GPPGCR1) & ~mask;
+	if (value) {
+		reg |= mask;
+	}
+	btwrite(reg, ZR36057_GPPGCR1);
+	udelay(1);
+}
+
+/*
+ * Wait til post office is no longer busy
+ */
+
+int
+post_office_wait (struct zoran *zr)
+{
+	u32 por;
+
+//      while (((por = btread(ZR36057_POR)) & (ZR36057_POR_POPen | ZR36057_POR_POTime)) == ZR36057_POR_POPen) {
+	while ((por = btread(ZR36057_POR)) & ZR36057_POR_POPen) {
+		/* wait for something to happen */
+	}
+	if ((por & ZR36057_POR_POTime) && !zr->card.gws_not_connected) {
+		/* In LML33/BUZ \GWS line is not connected, so it has always timeout set */
+		dprintk(1, KERN_INFO "%s: pop timeout %08x\n", ZR_DEVNAME(zr),
+			por);
+		return -1;
+	}
+
+	return 0;
+}
+
+int
+post_office_write (struct zoran *zr,
+		   unsigned int  guest,
+		   unsigned int  reg,
+		   unsigned int  value)
+{
+	u32 por;
+
+	por =
+	    ZR36057_POR_PODir | ZR36057_POR_POTime | ((guest & 7) << 20) |
+	    ((reg & 7) << 16) | (value & 0xFF);
+	btwrite(por, ZR36057_POR);
+
+	return post_office_wait(zr);
+}
+
+int
+post_office_read (struct zoran *zr,
+		  unsigned int  guest,
+		  unsigned int  reg)
+{
+	u32 por;
+
+	por = ZR36057_POR_POTime | ((guest & 7) << 20) | ((reg & 7) << 16);
+	btwrite(por, ZR36057_POR);
+	if (post_office_wait(zr) < 0) {
+		return -1;
+	}
+
+	return btread(ZR36057_POR) & 0xFF;
+}
+
+/*
+ * detect guests
+ */
+
+static void
+dump_guests (struct zoran *zr)
+{
+	if (zr36067_debug > 2) {
+		int i, guest[8];
+
+		for (i = 1; i < 8; i++) {	// Don't read jpeg codec here
+			guest[i] = post_office_read(zr, i, 0);
+		}
+
+		printk(KERN_INFO "%s: Guests:", ZR_DEVNAME(zr));
+
+		for (i = 1; i < 8; i++) {
+			printk(" 0x%02x", guest[i]);
+		}
+		printk("\n");
+	}
+}
+
+static inline unsigned long
+get_time (void)
+{
+	struct timeval tv;
+
+	do_gettimeofday(&tv);
+	return (1000000 * tv.tv_sec + tv.tv_usec);
+}
+
+void
+detect_guest_activity (struct zoran *zr)
+{
+	int timeout, i, j, res, guest[8], guest0[8], change[8][3];
+	unsigned long t0, t1;
+
+	dump_guests(zr);
+	printk(KERN_INFO "%s: Detecting guests activity, please wait...\n",
+	       ZR_DEVNAME(zr));
+	for (i = 1; i < 8; i++) {	// Don't read jpeg codec here
+		guest0[i] = guest[i] = post_office_read(zr, i, 0);
+	}
+
+	timeout = 0;
+	j = 0;
+	t0 = get_time();
+	while (timeout < 10000) {
+		udelay(10);
+		timeout++;
+		for (i = 1; (i < 8) && (j < 8); i++) {
+			res = post_office_read(zr, i, 0);
+			if (res != guest[i]) {
+				t1 = get_time();
+				change[j][0] = (t1 - t0);
+				t0 = t1;
+				change[j][1] = i;
+				change[j][2] = res;
+				j++;
+				guest[i] = res;
+			}
+		}
+		if (j >= 8)
+			break;
+	}
+	printk(KERN_INFO "%s: Guests:", ZR_DEVNAME(zr));
+
+	for (i = 1; i < 8; i++) {
+		printk(" 0x%02x", guest0[i]);
+	}
+	printk("\n");
+	if (j == 0) {
+		printk(KERN_INFO "%s: No activity detected.\n", ZR_DEVNAME(zr));
+		return;
+	}
+	for (i = 0; i < j; i++) {
+		printk(KERN_INFO "%s: %6d: %d => 0x%02x\n", ZR_DEVNAME(zr),
+		       change[i][0], change[i][1], change[i][2]);
+	}
+}
+
+/*
+ * JPEG Codec access
+ */
+
+void
+jpeg_codec_sleep (struct zoran *zr,
+		  int           sleep)
+{
+	GPIO(zr, zr->card.gpio[ZR_GPIO_JPEG_SLEEP], !sleep);
+	if (!sleep) {
+		dprintk(3,
+			KERN_DEBUG
+			"%s: jpeg_codec_sleep() - wake GPIO=0x%08x\n",
+			ZR_DEVNAME(zr), btread(ZR36057_GPPGCR1));
+		udelay(500);
+	} else {
+		dprintk(3,
+			KERN_DEBUG
+			"%s: jpeg_codec_sleep() - sleep GPIO=0x%08x\n",
+			ZR_DEVNAME(zr), btread(ZR36057_GPPGCR1));
+		udelay(2);
+	}
+}
+
+int
+jpeg_codec_reset (struct zoran *zr)
+{
+	/* Take the codec out of sleep */
+	jpeg_codec_sleep(zr, 0);
+
+	if (zr->card.gpcs[GPCS_JPEG_RESET] != 0xff) {
+		post_office_write(zr, zr->card.gpcs[GPCS_JPEG_RESET], 0,
+				  0);
+		udelay(2);
+	} else {
+		GPIO(zr, zr->card.gpio[ZR_GPIO_JPEG_RESET], 0);
+		udelay(2);
+		GPIO(zr, zr->card.gpio[ZR_GPIO_JPEG_RESET], 1);
+		udelay(2);
+	}
+
+	return 0;
+}
+
+/*
+ *   Set the registers for the size we have specified. Don't bother
+ *   trying to understand this without the ZR36057 manual in front of
+ *   you [AC].
+ *
+ *   PS: The manual is free for download in .pdf format from
+ *   www.zoran.com - nicely done those folks.
+ */
+
+static void
+zr36057_adjust_vfe (struct zoran          *zr,
+		    enum zoran_codec_mode  mode)
+{
+	u32 reg;
+
+	switch (mode) {
+	case BUZ_MODE_MOTION_DECOMPRESS:
+		btand(~ZR36057_VFESPFR_ExtFl, ZR36057_VFESPFR);
+		reg = btread(ZR36057_VFEHCR);
+		if ((reg & (1 << 10)) && zr->card.type != LML33R10) {
+			reg += ((1 << 10) | 1);
+		}
+		btwrite(reg, ZR36057_VFEHCR);
+		break;
+	case BUZ_MODE_MOTION_COMPRESS:
+	case BUZ_MODE_IDLE:
+	default:
+		if (zr->norm == VIDEO_MODE_NTSC ||
+		    (zr->card.type == LML33R10 &&
+		     zr->norm == VIDEO_MODE_PAL))
+			btand(~ZR36057_VFESPFR_ExtFl, ZR36057_VFESPFR);
+		else
+			btor(ZR36057_VFESPFR_ExtFl, ZR36057_VFESPFR);
+		reg = btread(ZR36057_VFEHCR);
+		if (!(reg & (1 << 10)) && zr->card.type != LML33R10) {
+			reg -= ((1 << 10) | 1);
+		}
+		btwrite(reg, ZR36057_VFEHCR);
+		break;
+	}
+}
+
+/*
+ * set geometry
+ */
+
+static void
+zr36057_set_vfe (struct zoran              *zr,
+		 int                        video_width,
+		 int                        video_height,
+		 const struct zoran_format *format)
+{
+	struct tvnorm *tvn;
+	unsigned HStart, HEnd, VStart, VEnd;
+	unsigned DispMode;
+	unsigned VidWinWid, VidWinHt;
+	unsigned hcrop1, hcrop2, vcrop1, vcrop2;
+	unsigned Wa, We, Ha, He;
+	unsigned X, Y, HorDcm, VerDcm;
+	u32 reg;
+	unsigned mask_line_size;
+
+	tvn = zr->timing;
+
+	Wa = tvn->Wa;
+	Ha = tvn->Ha;
+
+	dprintk(2, KERN_INFO "%s: set_vfe() - width = %d, height = %d\n",
+		ZR_DEVNAME(zr), video_width, video_height);
+
+	if (zr->norm != VIDEO_MODE_PAL &&
+	    zr->norm != VIDEO_MODE_NTSC &&
+	    zr->norm != VIDEO_MODE_SECAM) {
+		dprintk(1,
+			KERN_ERR "%s: set_vfe() - norm = %d not valid\n",
+			ZR_DEVNAME(zr), zr->norm);
+		return;
+	}
+	if (video_width < BUZ_MIN_WIDTH ||
+	    video_height < BUZ_MIN_HEIGHT ||
+	    video_width > Wa || video_height > Ha) {
+		dprintk(1, KERN_ERR "%s: set_vfe: w=%d h=%d not valid\n",
+			ZR_DEVNAME(zr), video_width, video_height);
+		return;
+	}
+
+	/**** zr36057 ****/
+
+	/* horizontal */
+	VidWinWid = video_width;
+	X = DIV_ROUND_UP(VidWinWid * 64, tvn->Wa);
+	We = (VidWinWid * 64) / X;
+	HorDcm = 64 - X;
+	hcrop1 = 2 * ((tvn->Wa - We) / 4);
+	hcrop2 = tvn->Wa - We - hcrop1;
+	HStart = tvn->HStart ? tvn->HStart : 1;
+	/* (Ronald) Original comment:
+	 * "| 1 Doesn't have any effect, tested on both a DC10 and a DC10+"
+	 * this is false. It inverses chroma values on the LML33R10 (so Cr
+	 * suddenly is shown as Cb and reverse, really cool effect if you
+	 * want to see blue faces, not useful otherwise). So don't use |1.
+	 * However, the DC10 has '0' as HStart, but does need |1, so we
+	 * use a dirty check...
+	 */
+	HEnd = HStart + tvn->Wa - 1;
+	HStart += hcrop1;
+	HEnd -= hcrop2;
+	reg = ((HStart & ZR36057_VFEHCR_Hmask) << ZR36057_VFEHCR_HStart)
+	    | ((HEnd & ZR36057_VFEHCR_Hmask) << ZR36057_VFEHCR_HEnd);
+	if (zr->card.vfe_pol.hsync_pol)
+		reg |= ZR36057_VFEHCR_HSPol;
+	btwrite(reg, ZR36057_VFEHCR);
+
+	/* Vertical */
+	DispMode = !(video_height > BUZ_MAX_HEIGHT / 2);
+	VidWinHt = DispMode ? video_height : video_height / 2;
+	Y = DIV_ROUND_UP(VidWinHt * 64 * 2, tvn->Ha);
+	He = (VidWinHt * 64) / Y;
+	VerDcm = 64 - Y;
+	vcrop1 = (tvn->Ha / 2 - He) / 2;
+	vcrop2 = tvn->Ha / 2 - He - vcrop1;
+	VStart = tvn->VStart;
+	VEnd = VStart + tvn->Ha / 2;	// - 1; FIXME SnapShot times out with -1 in 768*576 on the DC10 - LP
+	VStart += vcrop1;
+	VEnd -= vcrop2;
+	reg = ((VStart & ZR36057_VFEVCR_Vmask) << ZR36057_VFEVCR_VStart)
+	    | ((VEnd & ZR36057_VFEVCR_Vmask) << ZR36057_VFEVCR_VEnd);
+	if (zr->card.vfe_pol.vsync_pol)
+		reg |= ZR36057_VFEVCR_VSPol;
+	btwrite(reg, ZR36057_VFEVCR);
+
+	/* scaler and pixel format */
+	reg = 0;
+	reg |= (HorDcm << ZR36057_VFESPFR_HorDcm);
+	reg |= (VerDcm << ZR36057_VFESPFR_VerDcm);
+	reg |= (DispMode << ZR36057_VFESPFR_DispMode);
+	/* RJ: I don't know, why the following has to be the opposite
+	 * of the corresponding ZR36060 setting, but only this way
+	 * we get the correct colors when uncompressing to the screen  */
+	//reg |= ZR36057_VFESPFR_VCLKPol; /**/
+	/* RJ: Don't know if that is needed for NTSC also */
+	if (zr->norm != VIDEO_MODE_NTSC)
+		reg |= ZR36057_VFESPFR_ExtFl;	// NEEDED!!!!!!! Wolfgang
+	reg |= ZR36057_VFESPFR_TopField;
+	if (HorDcm >= 48) {
+		reg |= 3 << ZR36057_VFESPFR_HFilter;	/* 5 tap filter */
+	} else if (HorDcm >= 32) {
+		reg |= 2 << ZR36057_VFESPFR_HFilter;	/* 4 tap filter */
+	} else if (HorDcm >= 16) {
+		reg |= 1 << ZR36057_VFESPFR_HFilter;	/* 3 tap filter */
+	}
+	reg |= format->vfespfr;
+	btwrite(reg, ZR36057_VFESPFR);
+
+	/* display configuration */
+	reg = (16 << ZR36057_VDCR_MinPix)
+	    | (VidWinHt << ZR36057_VDCR_VidWinHt)
+	    | (VidWinWid << ZR36057_VDCR_VidWinWid);
+	if (pci_pci_problems & PCIPCI_TRITON)
+		// || zr->revision < 1) // Revision 1 has also Triton support
+		reg &= ~ZR36057_VDCR_Triton;
+	else
+		reg |= ZR36057_VDCR_Triton;
+	btwrite(reg, ZR36057_VDCR);
+
+	/* (Ronald) don't write this if overlay_mask = NULL */
+	if (zr->overlay_mask) {
+		/* Write overlay clipping mask data, but don't enable overlay clipping */
+		/* RJ: since this makes only sense on the screen, we use
+		 * zr->overlay_settings.width instead of video_width */
+
+		mask_line_size = (BUZ_MAX_WIDTH + 31) / 32;
+		reg = virt_to_bus(zr->overlay_mask);
+		btwrite(reg, ZR36057_MMTR);
+		reg = virt_to_bus(zr->overlay_mask + mask_line_size);
+		btwrite(reg, ZR36057_MMBR);
+		reg =
+		    mask_line_size - (zr->overlay_settings.width +
+				      31) / 32;
+		if (DispMode == 0)
+			reg += mask_line_size;
+		reg <<= ZR36057_OCR_MaskStride;
+		btwrite(reg, ZR36057_OCR);
+	}
+
+	zr36057_adjust_vfe(zr, zr->codec_mode);
+}
+
+/*
+ * Switch overlay on or off
+ */
+
+void
+zr36057_overlay (struct zoran *zr,
+		 int           on)
+{
+	u32 reg;
+
+	if (on) {
+		/* do the necessary settings ... */
+		btand(~ZR36057_VDCR_VidEn, ZR36057_VDCR);	/* switch it off first */
+
+		zr36057_set_vfe(zr,
+				zr->overlay_settings.width,
+				zr->overlay_settings.height,
+				zr->overlay_settings.format);
+
+		/* Start and length of each line MUST be 4-byte aligned.
+		 * This should be allready checked before the call to this routine.
+		 * All error messages are internal driver checking only! */
+
+		/* video display top and bottom registers */
+		reg = (long) zr->buffer.base +
+		    zr->overlay_settings.x *
+		    ((zr->overlay_settings.format->depth + 7) / 8) +
+		    zr->overlay_settings.y *
+		    zr->buffer.bytesperline;
+		btwrite(reg, ZR36057_VDTR);
+		if (reg & 3)
+			dprintk(1,
+				KERN_ERR
+				"%s: zr36057_overlay() - video_address not aligned\n",
+				ZR_DEVNAME(zr));
+		if (zr->overlay_settings.height > BUZ_MAX_HEIGHT / 2)
+			reg += zr->buffer.bytesperline;
+		btwrite(reg, ZR36057_VDBR);
+
+		/* video stride, status, and frame grab register */
+		reg = zr->buffer.bytesperline -
+		    zr->overlay_settings.width *
+		    ((zr->overlay_settings.format->depth + 7) / 8);
+		if (zr->overlay_settings.height > BUZ_MAX_HEIGHT / 2)
+			reg += zr->buffer.bytesperline;
+		if (reg & 3)
+			dprintk(1,
+				KERN_ERR
+				"%s: zr36057_overlay() - video_stride not aligned\n",
+				ZR_DEVNAME(zr));
+		reg = (reg << ZR36057_VSSFGR_DispStride);
+		reg |= ZR36057_VSSFGR_VidOvf;	/* clear overflow status */
+		btwrite(reg, ZR36057_VSSFGR);
+
+		/* Set overlay clipping */
+		if (zr->overlay_settings.clipcount > 0)
+			btor(ZR36057_OCR_OvlEnable, ZR36057_OCR);
+
+		/* ... and switch it on */
+		btor(ZR36057_VDCR_VidEn, ZR36057_VDCR);
+	} else {
+		/* Switch it off */
+		btand(~ZR36057_VDCR_VidEn, ZR36057_VDCR);
+	}
+}
+
+/*
+ * The overlay mask has one bit for each pixel on a scan line,
+ *  and the maximum window size is BUZ_MAX_WIDTH * BUZ_MAX_HEIGHT pixels.
+ */
+
+void
+write_overlay_mask (struct file       *file,
+		    struct video_clip *vp,
+		    int                count)
+{
+	struct zoran_fh *fh = file->private_data;
+	struct zoran *zr = fh->zr;
+	unsigned mask_line_size = (BUZ_MAX_WIDTH + 31) / 32;
+	u32 *mask;
+	int x, y, width, height;
+	unsigned i, j, k;
+	u32 reg;
+
+	/* fill mask with one bits */
+	memset(fh->overlay_mask, ~0, mask_line_size * 4 * BUZ_MAX_HEIGHT);
+	reg = 0;
+
+	for (i = 0; i < count; ++i) {
+		/* pick up local copy of clip */
+		x = vp[i].x;
+		y = vp[i].y;
+		width = vp[i].width;
+		height = vp[i].height;
+
+		/* trim clips that extend beyond the window */
+		if (x < 0) {
+			width += x;
+			x = 0;
+		}
+		if (y < 0) {
+			height += y;
+			y = 0;
+		}
+		if (x + width > fh->overlay_settings.width) {
+			width = fh->overlay_settings.width - x;
+		}
+		if (y + height > fh->overlay_settings.height) {
+			height = fh->overlay_settings.height - y;
+		}
+
+		/* ignore degenerate clips */
+		if (height <= 0) {
+			continue;
+		}
+		if (width <= 0) {
+			continue;
+		}
+
+		/* apply clip for each scan line */
+		for (j = 0; j < height; ++j) {
+			/* reset bit for each pixel */
+			/* this can be optimized later if need be */
+			mask = fh->overlay_mask + (y + j) * mask_line_size;
+			for (k = 0; k < width; ++k) {
+				mask[(x + k) / 32] &=
+				    ~((u32) 1 << (x + k) % 32);
+			}
+		}
+	}
+}
+
+/* Enable/Disable uncompressed memory grabbing of the 36057 */
+
+void
+zr36057_set_memgrab (struct zoran *zr,
+		     int           mode)
+{
+	if (mode) {
+		/* We only check SnapShot and not FrameGrab here.  SnapShot==1
+		 * means a capture is already in progress, but FrameGrab==1
+		 * doesn't necessary mean that.  It's more correct to say a 1
+		 * to 0 transition indicates a capture completed.  If a
+		 * capture is pending when capturing is tuned off, FrameGrab
+		 * will be stuck at 1 until capturing is turned back on.
+		 */
+		if (btread(ZR36057_VSSFGR) & ZR36057_VSSFGR_SnapShot)
+			dprintk(1,
+				KERN_WARNING
+				"%s: zr36057_set_memgrab(1) with SnapShot on!?\n",
+				ZR_DEVNAME(zr));
+
+		/* switch on VSync interrupts */
+		btwrite(IRQ_MASK, ZR36057_ISR);	// Clear Interrupts
+		btor(zr->card.vsync_int, ZR36057_ICR);	// SW
+
+		/* enable SnapShot */
+		btor(ZR36057_VSSFGR_SnapShot, ZR36057_VSSFGR);
+
+		/* Set zr36057 video front end  and enable video */
+		zr36057_set_vfe(zr, zr->v4l_settings.width,
+				zr->v4l_settings.height,
+				zr->v4l_settings.format);
+
+		zr->v4l_memgrab_active = 1;
+	} else {
+		/* switch off VSync interrupts */
+		btand(~zr->card.vsync_int, ZR36057_ICR);	// SW
+
+		zr->v4l_memgrab_active = 0;
+		zr->v4l_grab_frame = NO_GRAB_ACTIVE;
+
+		/* reenable grabbing to screen if it was running */
+		if (zr->v4l_overlay_active) {
+			zr36057_overlay(zr, 1);
+		} else {
+			btand(~ZR36057_VDCR_VidEn, ZR36057_VDCR);
+			btand(~ZR36057_VSSFGR_SnapShot, ZR36057_VSSFGR);
+		}
+	}
+}
+
+int
+wait_grab_pending (struct zoran *zr)
+{
+	unsigned long flags;
+
+	/* wait until all pending grabs are finished */
+
+	if (!zr->v4l_memgrab_active)
+		return 0;
+
+	wait_event_interruptible(zr->v4l_capq,
+			(zr->v4l_pend_tail == zr->v4l_pend_head));
+	if (signal_pending(current))
+		return -ERESTARTSYS;
+
+	spin_lock_irqsave(&zr->spinlock, flags);
+	zr36057_set_memgrab(zr, 0);
+	spin_unlock_irqrestore(&zr->spinlock, flags);
+
+	return 0;
+}
+
+/*****************************************************************************
+ *                                                                           *
+ *  Set up the Buz-specific MJPEG part                                       *
+ *                                                                           *
+ *****************************************************************************/
+
+static inline void
+set_frame (struct zoran *zr,
+	   int           val)
+{
+	GPIO(zr, zr->card.gpio[ZR_GPIO_JPEG_FRAME], val);
+}
+
+static void
+set_videobus_dir (struct zoran *zr,
+		  int           val)
+{
+	switch (zr->card.type) {
+	case LML33:
+	case LML33R10:
+		if (lml33dpath == 0)
+			GPIO(zr, 5, val);
+		else
+			GPIO(zr, 5, 1);
+		break;
+	default:
+		GPIO(zr, zr->card.gpio[ZR_GPIO_VID_DIR],
+		     zr->card.gpio_pol[ZR_GPIO_VID_DIR] ? !val : val);
+		break;
+	}
+}
+
+static void
+init_jpeg_queue (struct zoran *zr)
+{
+	int i;
+
+	/* re-initialize DMA ring stuff */
+	zr->jpg_que_head = 0;
+	zr->jpg_dma_head = 0;
+	zr->jpg_dma_tail = 0;
+	zr->jpg_que_tail = 0;
+	zr->jpg_seq_num = 0;
+	zr->JPEG_error = 0;
+	zr->num_errors = 0;
+	zr->jpg_err_seq = 0;
+	zr->jpg_err_shift = 0;
+	zr->jpg_queued_num = 0;
+	for (i = 0; i < zr->jpg_buffers.num_buffers; i++) {
+		zr->jpg_buffers.buffer[i].state = BUZ_STATE_USER;	/* nothing going on */
+	}
+	for (i = 0; i < BUZ_NUM_STAT_COM; i++) {
+		zr->stat_com[i] = cpu_to_le32(1);	/* mark as unavailable to zr36057 */
+	}
+}
+
+static void
+zr36057_set_jpg (struct zoran          *zr,
+		 enum zoran_codec_mode  mode)
+{
+	struct tvnorm *tvn;
+	u32 reg;
+
+	tvn = zr->timing;
+
+	/* assert P_Reset, disable code transfer, deassert Active */
+	btwrite(0, ZR36057_JPC);
+
+	/* MJPEG compression mode */
+	switch (mode) {
+
+	case BUZ_MODE_MOTION_COMPRESS:
+	default:
+		reg = ZR36057_JMC_MJPGCmpMode;
+		break;
+
+	case BUZ_MODE_MOTION_DECOMPRESS:
+		reg = ZR36057_JMC_MJPGExpMode;
+		reg |= ZR36057_JMC_SyncMstr;
+		/* RJ: The following is experimental - improves the output to screen */
+		//if(zr->jpg_settings.VFIFO_FB) reg |= ZR36057_JMC_VFIFO_FB; // No, it doesn't. SM
+		break;
+
+	case BUZ_MODE_STILL_COMPRESS:
+		reg = ZR36057_JMC_JPGCmpMode;
+		break;
+
+	case BUZ_MODE_STILL_DECOMPRESS:
+		reg = ZR36057_JMC_JPGExpMode;
+		break;
+
+	}
+	reg |= ZR36057_JMC_JPG;
+	if (zr->jpg_settings.field_per_buff == 1)
+		reg |= ZR36057_JMC_Fld_per_buff;
+	btwrite(reg, ZR36057_JMC);
+
+	/* vertical */
+	btor(ZR36057_VFEVCR_VSPol, ZR36057_VFEVCR);
+	reg = (6 << ZR36057_VSP_VsyncSize) |
+	      (tvn->Ht << ZR36057_VSP_FrmTot);
+	btwrite(reg, ZR36057_VSP);
+	reg = ((zr->jpg_settings.img_y + tvn->VStart) << ZR36057_FVAP_NAY) |
+	      (zr->jpg_settings.img_height << ZR36057_FVAP_PAY);
+	btwrite(reg, ZR36057_FVAP);
+
+	/* horizontal */
+	if (zr->card.vfe_pol.hsync_pol)
+		btor(ZR36057_VFEHCR_HSPol, ZR36057_VFEHCR);
+	else
+		btand(~ZR36057_VFEHCR_HSPol, ZR36057_VFEHCR);
+	reg = ((tvn->HSyncStart) << ZR36057_HSP_HsyncStart) |
+	      (tvn->Wt << ZR36057_HSP_LineTot);
+	btwrite(reg, ZR36057_HSP);
+	reg = ((zr->jpg_settings.img_x +
+		tvn->HStart + 4) << ZR36057_FHAP_NAX) |
+	      (zr->jpg_settings.img_width << ZR36057_FHAP_PAX);
+	btwrite(reg, ZR36057_FHAP);
+
+	/* field process parameters */
+	if (zr->jpg_settings.odd_even)
+		reg = ZR36057_FPP_Odd_Even;
+	else
+		reg = 0;
+
+	btwrite(reg, ZR36057_FPP);
+
+	/* Set proper VCLK Polarity, else colors will be wrong during playback */
+	//btor(ZR36057_VFESPFR_VCLKPol, ZR36057_VFESPFR);
+
+	/* code base address */
+	reg = virt_to_bus(zr->stat_com);
+	btwrite(reg, ZR36057_JCBA);
+
+	/* FIFO threshold (FIFO is 160. double words) */
+	/* NOTE: decimal values here */
+	switch (mode) {
+
+	case BUZ_MODE_STILL_COMPRESS:
+	case BUZ_MODE_MOTION_COMPRESS:
+		if (zr->card.type != BUZ)
+			reg = 140;
+		else
+			reg = 60;
+		break;
+
+	case BUZ_MODE_STILL_DECOMPRESS:
+	case BUZ_MODE_MOTION_DECOMPRESS:
+		reg = 20;
+		break;
+
+	default:
+		reg = 80;
+		break;
+
+	}
+	btwrite(reg, ZR36057_JCFT);
+	zr36057_adjust_vfe(zr, mode);
+
+}
+
+void
+print_interrupts (struct zoran *zr)
+{
+	int res, noerr = 0;
+
+	printk(KERN_INFO "%s: interrupts received:", ZR_DEVNAME(zr));
+	if ((res = zr->field_counter) < -1 || res > 1) {
+		printk(" FD:%d", res);
+	}
+	if ((res = zr->intr_counter_GIRQ1) != 0) {
+		printk(" GIRQ1:%d", res);
+		noerr++;
+	}
+	if ((res = zr->intr_counter_GIRQ0) != 0) {
+		printk(" GIRQ0:%d", res);
+		noerr++;
+	}
+	if ((res = zr->intr_counter_CodRepIRQ) != 0) {
+		printk(" CodRepIRQ:%d", res);
+		noerr++;
+	}
+	if ((res = zr->intr_counter_JPEGRepIRQ) != 0) {
+		printk(" JPEGRepIRQ:%d", res);
+		noerr++;
+	}
+	if (zr->JPEG_max_missed) {
+		printk(" JPEG delays: max=%d min=%d", zr->JPEG_max_missed,
+		       zr->JPEG_min_missed);
+	}
+	if (zr->END_event_missed) {
+		printk(" ENDs missed: %d", zr->END_event_missed);
+	}
+	//if (zr->jpg_queued_num) {
+	printk(" queue_state=%ld/%ld/%ld/%ld", zr->jpg_que_tail,
+	       zr->jpg_dma_tail, zr->jpg_dma_head, zr->jpg_que_head);
+	//}
+	if (!noerr) {
+		printk(": no interrupts detected.");
+	}
+	printk("\n");
+}
+
+void
+clear_interrupt_counters (struct zoran *zr)
+{
+	zr->intr_counter_GIRQ1 = 0;
+	zr->intr_counter_GIRQ0 = 0;
+	zr->intr_counter_CodRepIRQ = 0;
+	zr->intr_counter_JPEGRepIRQ = 0;
+	zr->field_counter = 0;
+	zr->IRQ1_in = 0;
+	zr->IRQ1_out = 0;
+	zr->JPEG_in = 0;
+	zr->JPEG_out = 0;
+	zr->JPEG_0 = 0;
+	zr->JPEG_1 = 0;
+	zr->END_event_missed = 0;
+	zr->JPEG_missed = 0;
+	zr->JPEG_max_missed = 0;
+	zr->JPEG_min_missed = 0x7fffffff;
+}
+
+static u32
+count_reset_interrupt (struct zoran *zr)
+{
+	u32 isr;
+
+	if ((isr = btread(ZR36057_ISR) & 0x78000000)) {
+		if (isr & ZR36057_ISR_GIRQ1) {
+			btwrite(ZR36057_ISR_GIRQ1, ZR36057_ISR);
+			zr->intr_counter_GIRQ1++;
+		}
+		if (isr & ZR36057_ISR_GIRQ0) {
+			btwrite(ZR36057_ISR_GIRQ0, ZR36057_ISR);
+			zr->intr_counter_GIRQ0++;
+		}
+		if (isr & ZR36057_ISR_CodRepIRQ) {
+			btwrite(ZR36057_ISR_CodRepIRQ, ZR36057_ISR);
+			zr->intr_counter_CodRepIRQ++;
+		}
+		if (isr & ZR36057_ISR_JPEGRepIRQ) {
+			btwrite(ZR36057_ISR_JPEGRepIRQ, ZR36057_ISR);
+			zr->intr_counter_JPEGRepIRQ++;
+		}
+	}
+	return isr;
+}
+
+void
+jpeg_start (struct zoran *zr)
+{
+	int reg;
+
+	zr->frame_num = 0;
+
+	/* deassert P_reset, disable code transfer, deassert Active */
+	btwrite(ZR36057_JPC_P_Reset, ZR36057_JPC);
+	/* stop flushing the internal code buffer */
+	btand(~ZR36057_MCTCR_CFlush, ZR36057_MCTCR);
+	/* enable code transfer */
+	btor(ZR36057_JPC_CodTrnsEn, ZR36057_JPC);
+
+	/* clear IRQs */
+	btwrite(IRQ_MASK, ZR36057_ISR);
+	/* enable the JPEG IRQs */
+	btwrite(zr->card.jpeg_int |
+			ZR36057_ICR_JPEGRepIRQ |
+			ZR36057_ICR_IntPinEn,
+		ZR36057_ICR);
+
+	set_frame(zr, 0);	// \FRAME
+
+	/* set the JPEG codec guest ID */
+	reg = (zr->card.gpcs[1] << ZR36057_JCGI_JPEGuestID) |
+	       (0 << ZR36057_JCGI_JPEGuestReg);
+	btwrite(reg, ZR36057_JCGI);
+
+	if (zr->card.video_vfe == CODEC_TYPE_ZR36016 &&
+	    zr->card.video_codec == CODEC_TYPE_ZR36050) {
+		/* Enable processing on the ZR36016 */
+		if (zr->vfe)
+			zr36016_write(zr->vfe, 0, 1);
+
+		/* load the address of the GO register in the ZR36050 latch */
+		post_office_write(zr, 0, 0, 0);
+	}
+
+	/* assert Active */
+	btor(ZR36057_JPC_Active, ZR36057_JPC);
+
+	/* enable the Go generation */
+	btor(ZR36057_JMC_Go_en, ZR36057_JMC);
+	udelay(30);
+
+	set_frame(zr, 1);	// /FRAME
+
+	dprintk(3, KERN_DEBUG "%s: jpeg_start\n", ZR_DEVNAME(zr));
+}
+
+void
+zr36057_enable_jpg (struct zoran          *zr,
+		    enum zoran_codec_mode  mode)
+{
+	static int zero;
+	static int one = 1;
+	struct vfe_settings cap;
+	int field_size =
+	    zr->jpg_buffers.buffer_size / zr->jpg_settings.field_per_buff;
+
+	zr->codec_mode = mode;
+
+	cap.x = zr->jpg_settings.img_x;
+	cap.y = zr->jpg_settings.img_y;
+	cap.width = zr->jpg_settings.img_width;
+	cap.height = zr->jpg_settings.img_height;
+	cap.decimation =
+	    zr->jpg_settings.HorDcm | (zr->jpg_settings.VerDcm << 8);
+	cap.quality = zr->jpg_settings.jpg_comp.quality;
+
+	switch (mode) {
+
+	case BUZ_MODE_MOTION_COMPRESS: {
+		struct jpeg_app_marker app;
+		struct jpeg_com_marker com;
+
+		/* In motion compress mode, the decoder output must be enabled, and
+		 * the video bus direction set to input.
+		 */
+		set_videobus_dir(zr, 0);
+		decoder_command(zr, DECODER_ENABLE_OUTPUT, &one);
+		encoder_command(zr, ENCODER_SET_INPUT, &zero);
+
+		/* Take the JPEG codec and the VFE out of sleep */
+		jpeg_codec_sleep(zr, 0);
+
+		/* set JPEG app/com marker */
+		app.appn = zr->jpg_settings.jpg_comp.APPn;
+		app.len = zr->jpg_settings.jpg_comp.APP_len;
+		memcpy(app.data, zr->jpg_settings.jpg_comp.APP_data, 60);
+		zr->codec->control(zr->codec, CODEC_S_JPEG_APP_DATA,
+				   sizeof(struct jpeg_app_marker), &app);
+
+		com.len = zr->jpg_settings.jpg_comp.COM_len;
+		memcpy(com.data, zr->jpg_settings.jpg_comp.COM_data, 60);
+		zr->codec->control(zr->codec, CODEC_S_JPEG_COM_DATA,
+				   sizeof(struct jpeg_com_marker), &com);
+
+		/* Setup the JPEG codec */
+		zr->codec->control(zr->codec, CODEC_S_JPEG_TDS_BYTE,
+				   sizeof(int), &field_size);
+		zr->codec->set_video(zr->codec, zr->timing, &cap,
+				     &zr->card.vfe_pol);
+		zr->codec->set_mode(zr->codec, CODEC_DO_COMPRESSION);
+
+		/* Setup the VFE */
+		if (zr->vfe) {
+			zr->vfe->control(zr->vfe, CODEC_S_JPEG_TDS_BYTE,
+					 sizeof(int), &field_size);
+			zr->vfe->set_video(zr->vfe, zr->timing, &cap,
+					   &zr->card.vfe_pol);
+			zr->vfe->set_mode(zr->vfe, CODEC_DO_COMPRESSION);
+		}
+
+		init_jpeg_queue(zr);
+		zr36057_set_jpg(zr, mode);	// \P_Reset, ... Video param, FIFO
+
+		clear_interrupt_counters(zr);
+		dprintk(2, KERN_INFO "%s: enable_jpg(MOTION_COMPRESS)\n",
+			ZR_DEVNAME(zr));
+		break;
+	}
+
+	case BUZ_MODE_MOTION_DECOMPRESS:
+		/* In motion decompression mode, the decoder output must be disabled, and
+		 * the video bus direction set to output.
+		 */
+		decoder_command(zr, DECODER_ENABLE_OUTPUT, &zero);
+		set_videobus_dir(zr, 1);
+		encoder_command(zr, ENCODER_SET_INPUT, &one);
+
+		/* Take the JPEG codec and the VFE out of sleep */
+		jpeg_codec_sleep(zr, 0);
+		/* Setup the VFE */
+		if (zr->vfe) {
+			zr->vfe->set_video(zr->vfe, zr->timing, &cap,
+					   &zr->card.vfe_pol);
+			zr->vfe->set_mode(zr->vfe, CODEC_DO_EXPANSION);
+		}
+		/* Setup the JPEG codec */
+		zr->codec->set_video(zr->codec, zr->timing, &cap,
+				     &zr->card.vfe_pol);
+		zr->codec->set_mode(zr->codec, CODEC_DO_EXPANSION);
+
+		init_jpeg_queue(zr);
+		zr36057_set_jpg(zr, mode);	// \P_Reset, ... Video param, FIFO
+
+		clear_interrupt_counters(zr);
+		dprintk(2, KERN_INFO "%s: enable_jpg(MOTION_DECOMPRESS)\n",
+			ZR_DEVNAME(zr));
+		break;
+
+	case BUZ_MODE_IDLE:
+	default:
+		/* shut down processing */
+		btand(~(zr->card.jpeg_int | ZR36057_ICR_JPEGRepIRQ),
+		      ZR36057_ICR);
+		btwrite(zr->card.jpeg_int | ZR36057_ICR_JPEGRepIRQ,
+			ZR36057_ISR);
+		btand(~ZR36057_JMC_Go_en, ZR36057_JMC);	// \Go_en
+
+		msleep(50);
+
+		set_videobus_dir(zr, 0);
+		set_frame(zr, 1);	// /FRAME
+		btor(ZR36057_MCTCR_CFlush, ZR36057_MCTCR);	// /CFlush
+		btwrite(0, ZR36057_JPC);	// \P_Reset,\CodTrnsEn,\Active
+		btand(~ZR36057_JMC_VFIFO_FB, ZR36057_JMC);
+		btand(~ZR36057_JMC_SyncMstr, ZR36057_JMC);
+		jpeg_codec_reset(zr);
+		jpeg_codec_sleep(zr, 1);
+		zr36057_adjust_vfe(zr, mode);
+
+		decoder_command(zr, DECODER_ENABLE_OUTPUT, &one);
+		encoder_command(zr, ENCODER_SET_INPUT, &zero);
+
+		dprintk(2, KERN_INFO "%s: enable_jpg(IDLE)\n", ZR_DEVNAME(zr));
+		break;
+
+	}
+}
+
+/* when this is called the spinlock must be held */
+void
+zoran_feed_stat_com (struct zoran *zr)
+{
+	/* move frames from pending queue to DMA */
+
+	int frame, i, max_stat_com;
+
+	max_stat_com =
+	    (zr->jpg_settings.TmpDcm ==
+	     1) ? BUZ_NUM_STAT_COM : (BUZ_NUM_STAT_COM >> 1);
+
+	while ((zr->jpg_dma_head - zr->jpg_dma_tail) < max_stat_com &&
+	       zr->jpg_dma_head < zr->jpg_que_head) {
+
+		frame = zr->jpg_pend[zr->jpg_dma_head & BUZ_MASK_FRAME];
+		if (zr->jpg_settings.TmpDcm == 1) {
+			/* fill 1 stat_com entry */
+			i = (zr->jpg_dma_head -
+			     zr->jpg_err_shift) & BUZ_MASK_STAT_COM;
+			if (!(zr->stat_com[i] & cpu_to_le32(1)))
+				break;
+			zr->stat_com[i] =
+			    cpu_to_le32(zr->jpg_buffers.buffer[frame].frag_tab_bus);
+		} else {
+			/* fill 2 stat_com entries */
+			i = ((zr->jpg_dma_head -
+			      zr->jpg_err_shift) & 1) * 2;
+			if (!(zr->stat_com[i] & cpu_to_le32(1)))
+				break;
+			zr->stat_com[i] =
+			    cpu_to_le32(zr->jpg_buffers.buffer[frame].frag_tab_bus);
+			zr->stat_com[i + 1] =
+			    cpu_to_le32(zr->jpg_buffers.buffer[frame].frag_tab_bus);
+		}
+		zr->jpg_buffers.buffer[frame].state = BUZ_STATE_DMA;
+		zr->jpg_dma_head++;
+
+	}
+	if (zr->codec_mode == BUZ_MODE_MOTION_DECOMPRESS)
+		zr->jpg_queued_num++;
+}
+
+/* when this is called the spinlock must be held */
+static void
+zoran_reap_stat_com (struct zoran *zr)
+{
+	/* move frames from DMA queue to done queue */
+
+	int i;
+	u32 stat_com;
+	unsigned int seq;
+	unsigned int dif;
+	struct zoran_jpg_buffer *buffer;
+	int frame;
+
+	/* In motion decompress we don't have a hardware frame counter,
+	 * we just count the interrupts here */
+
+	if (zr->codec_mode == BUZ_MODE_MOTION_DECOMPRESS) {
+		zr->jpg_seq_num++;
+	}
+	while (zr->jpg_dma_tail < zr->jpg_dma_head) {
+		if (zr->jpg_settings.TmpDcm == 1)
+			i = (zr->jpg_dma_tail -
+			     zr->jpg_err_shift) & BUZ_MASK_STAT_COM;
+		else
+			i = ((zr->jpg_dma_tail -
+			      zr->jpg_err_shift) & 1) * 2 + 1;
+
+		stat_com = le32_to_cpu(zr->stat_com[i]);
+
+		if ((stat_com & 1) == 0) {
+			return;
+		}
+		frame = zr->jpg_pend[zr->jpg_dma_tail & BUZ_MASK_FRAME];
+		buffer = &zr->jpg_buffers.buffer[frame];
+		do_gettimeofday(&buffer->bs.timestamp);
+
+		if (zr->codec_mode == BUZ_MODE_MOTION_COMPRESS) {
+			buffer->bs.length = (stat_com & 0x7fffff) >> 1;
+
+			/* update sequence number with the help of the counter in stat_com */
+
+			seq = ((stat_com >> 24) + zr->jpg_err_seq) & 0xff;
+			dif = (seq - zr->jpg_seq_num) & 0xff;
+			zr->jpg_seq_num += dif;
+		} else {
+			buffer->bs.length = 0;
+		}
+		buffer->bs.seq =
+		    zr->jpg_settings.TmpDcm ==
+		    2 ? (zr->jpg_seq_num >> 1) : zr->jpg_seq_num;
+		buffer->state = BUZ_STATE_DONE;
+
+		zr->jpg_dma_tail++;
+	}
+}
+
+static void
+error_handler (struct zoran *zr,
+	       u32           astat,
+	       u32           stat)
+{
+	/* This is JPEG error handling part */
+	if ((zr->codec_mode != BUZ_MODE_MOTION_COMPRESS) &&
+	    (zr->codec_mode != BUZ_MODE_MOTION_DECOMPRESS)) {
+		//dprintk(1, KERN_ERR "%s: Internal error: error handling request in mode %d\n", ZR_DEVNAME(zr), zr->codec_mode);
+		return;
+	}
+
+	if ((stat & 1) == 0 &&
+	    zr->codec_mode == BUZ_MODE_MOTION_COMPRESS &&
+	    zr->jpg_dma_tail - zr->jpg_que_tail >=
+	     zr->jpg_buffers.num_buffers) {
+		/* No free buffers... */
+		zoran_reap_stat_com(zr);
+		zoran_feed_stat_com(zr);
+		wake_up_interruptible(&zr->jpg_capq);
+		zr->JPEG_missed = 0;
+		return;
+	}
+
+	if (zr->JPEG_error != 1) {
+		/*
+		 * First entry: error just happened during normal operation
+		 *
+		 * In BUZ_MODE_MOTION_COMPRESS:
+		 *
+		 * Possible glitch in TV signal. In this case we should
+		 * stop the codec and wait for good quality signal before
+		 * restarting it to avoid further problems
+		 *
+		 * In BUZ_MODE_MOTION_DECOMPRESS:
+		 *
+		 * Bad JPEG frame: we have to mark it as processed (codec crashed
+		 * and was not able to do it itself), and to remove it from queue.
+		 */
+		btand(~ZR36057_JMC_Go_en, ZR36057_JMC);
+		udelay(1);
+		stat = stat | (post_office_read(zr, 7, 0) & 3) << 8;
+		btwrite(0, ZR36057_JPC);
+		btor(ZR36057_MCTCR_CFlush, ZR36057_MCTCR);
+		jpeg_codec_reset(zr);
+		jpeg_codec_sleep(zr, 1);
+		zr->JPEG_error = 1;
+		zr->num_errors++;
+
+		/* Report error */
+		if (zr36067_debug > 1 && zr->num_errors <= 8) {
+			long frame;
+			frame =
+			    zr->jpg_pend[zr->jpg_dma_tail & BUZ_MASK_FRAME];
+			printk(KERN_ERR
+			       "%s: JPEG error stat=0x%08x(0x%08x) queue_state=%ld/%ld/%ld/%ld seq=%ld frame=%ld. Codec stopped. ",
+			       ZR_DEVNAME(zr), stat, zr->last_isr,
+			       zr->jpg_que_tail, zr->jpg_dma_tail,
+			       zr->jpg_dma_head, zr->jpg_que_head,
+			       zr->jpg_seq_num, frame);
+			printk("stat_com frames:");
+			{
+				int i, j;
+				for (j = 0; j < BUZ_NUM_STAT_COM; j++) {
+					for (i = 0;
+					     i < zr->jpg_buffers.num_buffers;
+					     i++) {
+						if (le32_to_cpu(zr->stat_com[j]) ==
+						    zr->jpg_buffers.
+						    buffer[i].
+						    frag_tab_bus) {
+							printk("% d->%d",
+							       j, i);
+						}
+					}
+				}
+				printk("\n");
+			}
+		}
+		/* Find an entry in stat_com and rotate contents */
+		{
+			int i;
+
+			if (zr->jpg_settings.TmpDcm == 1)
+				i = (zr->jpg_dma_tail -
+				     zr->jpg_err_shift) & BUZ_MASK_STAT_COM;
+			else
+				i = ((zr->jpg_dma_tail -
+				      zr->jpg_err_shift) & 1) * 2;
+			if (zr->codec_mode == BUZ_MODE_MOTION_DECOMPRESS) {
+				/* Mimic zr36067 operation */
+				zr->stat_com[i] |= cpu_to_le32(1);
+				if (zr->jpg_settings.TmpDcm != 1)
+					zr->stat_com[i + 1] |= cpu_to_le32(1);
+				/* Refill */
+				zoran_reap_stat_com(zr);
+				zoran_feed_stat_com(zr);
+				wake_up_interruptible(&zr->jpg_capq);
+				/* Find an entry in stat_com again after refill */
+				if (zr->jpg_settings.TmpDcm == 1)
+					i = (zr->jpg_dma_tail -
+					     zr->jpg_err_shift) &
+					    BUZ_MASK_STAT_COM;
+				else
+					i = ((zr->jpg_dma_tail -
+					      zr->jpg_err_shift) & 1) * 2;
+			}
+			if (i) {
+				/* Rotate stat_comm entries to make current entry first */
+				int j;
+				__le32 bus_addr[BUZ_NUM_STAT_COM];
+
+				/* Here we are copying the stat_com array, which
+				 * is already in little endian format, so
+				 * no endian conversions here
+				 */
+				memcpy(bus_addr, zr->stat_com,
+				       sizeof(bus_addr));
+				for (j = 0; j < BUZ_NUM_STAT_COM; j++) {
+					zr->stat_com[j] =
+					    bus_addr[(i + j) &
+						     BUZ_MASK_STAT_COM];
+
+				}
+				zr->jpg_err_shift += i;
+				zr->jpg_err_shift &= BUZ_MASK_STAT_COM;
+			}
+			if (zr->codec_mode == BUZ_MODE_MOTION_COMPRESS)
+				zr->jpg_err_seq = zr->jpg_seq_num;	/* + 1; */
+		}
+	}
+
+	/* Now the stat_comm buffer is ready for restart */
+	do {
+		int status, mode;
+
+		if (zr->codec_mode == BUZ_MODE_MOTION_COMPRESS) {
+			decoder_command(zr, DECODER_GET_STATUS, &status);
+			mode = CODEC_DO_COMPRESSION;
+		} else {
+			status = 0;
+			mode = CODEC_DO_EXPANSION;
+		}
+		if (zr->codec_mode == BUZ_MODE_MOTION_DECOMPRESS ||
+		    (status & DECODER_STATUS_GOOD)) {
+			/********** RESTART code *************/
+			jpeg_codec_reset(zr);
+			zr->codec->set_mode(zr->codec, mode);
+			zr36057_set_jpg(zr, zr->codec_mode);
+			jpeg_start(zr);
+
+			if (zr->num_errors <= 8)
+				dprintk(2, KERN_INFO "%s: Restart\n",
+					ZR_DEVNAME(zr));
+
+			zr->JPEG_missed = 0;
+			zr->JPEG_error = 2;
+			/********** End RESTART code ***********/
+		}
+	} while (0);
+}
+
+irqreturn_t
+zoran_irq (int             irq,
+	   void           *dev_id)
+{
+	u32 stat, astat;
+	int count;
+	struct zoran *zr;
+	unsigned long flags;
+
+	zr = dev_id;
+	count = 0;
+
+	if (zr->testing) {
+		/* Testing interrupts */
+		spin_lock_irqsave(&zr->spinlock, flags);
+		while ((stat = count_reset_interrupt(zr))) {
+			if (count++ > 100) {
+				btand(~ZR36057_ICR_IntPinEn, ZR36057_ICR);
+				dprintk(1,
+					KERN_ERR
+					"%s: IRQ lockup while testing, isr=0x%08x, cleared int mask\n",
+					ZR_DEVNAME(zr), stat);
+				wake_up_interruptible(&zr->test_q);
+			}
+		}
+		zr->last_isr = stat;
+		spin_unlock_irqrestore(&zr->spinlock, flags);
+		return IRQ_HANDLED;
+	}
+
+	spin_lock_irqsave(&zr->spinlock, flags);
+	while (1) {
+		/* get/clear interrupt status bits */
+		stat = count_reset_interrupt(zr);
+		astat = stat & IRQ_MASK;
+		if (!astat) {
+			break;
+		}
+		dprintk(4,
+			KERN_DEBUG
+			"zoran_irq: astat: 0x%08x, mask: 0x%08x\n",
+			astat, btread(ZR36057_ICR));
+		if (astat & zr->card.vsync_int) {	// SW
+
+			if (zr->codec_mode == BUZ_MODE_MOTION_DECOMPRESS ||
+			    zr->codec_mode == BUZ_MODE_MOTION_COMPRESS) {
+				/* count missed interrupts */
+				zr->JPEG_missed++;
+			}
+			//post_office_read(zr,1,0);
+			/* Interrupts may still happen when
+			 * zr->v4l_memgrab_active is switched off.
+			 * We simply ignore them */
+
+			if (zr->v4l_memgrab_active) {
+
+				/* A lot more checks should be here ... */
+				if ((btread(ZR36057_VSSFGR) &
+				     ZR36057_VSSFGR_SnapShot) == 0)
+					dprintk(1,
+						KERN_WARNING
+						"%s: BuzIRQ with SnapShot off ???\n",
+						ZR_DEVNAME(zr));
+
+				if (zr->v4l_grab_frame != NO_GRAB_ACTIVE) {
+					/* There is a grab on a frame going on, check if it has finished */
+
+					if ((btread(ZR36057_VSSFGR) &
+					     ZR36057_VSSFGR_FrameGrab) ==
+					    0) {
+						/* it is finished, notify the user */
+
+						zr->v4l_buffers.buffer[zr->v4l_grab_frame].state = BUZ_STATE_DONE;
+						zr->v4l_buffers.buffer[zr->v4l_grab_frame].bs.seq = zr->v4l_grab_seq;
+						do_gettimeofday(&zr->v4l_buffers.buffer[zr->v4l_grab_frame].bs.timestamp);
+						zr->v4l_grab_frame = NO_GRAB_ACTIVE;
+						zr->v4l_pend_tail++;
+					}
+				}
+
+				if (zr->v4l_grab_frame == NO_GRAB_ACTIVE)
+					wake_up_interruptible(&zr->v4l_capq);
+
+				/* Check if there is another grab queued */
+
+				if (zr->v4l_grab_frame == NO_GRAB_ACTIVE &&
+				    zr->v4l_pend_tail != zr->v4l_pend_head) {
+
+					int frame = zr->v4l_pend[zr->v4l_pend_tail &
+							 V4L_MASK_FRAME];
+					u32 reg;
+
+					zr->v4l_grab_frame = frame;
+
+					/* Set zr36057 video front end and enable video */
+
+					/* Buffer address */
+
+					reg =
+					    zr->v4l_buffers.buffer[frame].
+					    fbuffer_bus;
+					btwrite(reg, ZR36057_VDTR);
+					if (zr->v4l_settings.height >
+					    BUZ_MAX_HEIGHT / 2)
+						reg +=
+						    zr->v4l_settings.
+						    bytesperline;
+					btwrite(reg, ZR36057_VDBR);
+
+					/* video stride, status, and frame grab register */
+					reg = 0;
+					if (zr->v4l_settings.height >
+					    BUZ_MAX_HEIGHT / 2)
+						reg +=
+						    zr->v4l_settings.
+						    bytesperline;
+					reg =
+					    (reg <<
+					     ZR36057_VSSFGR_DispStride);
+					reg |= ZR36057_VSSFGR_VidOvf;
+					reg |= ZR36057_VSSFGR_SnapShot;
+					reg |= ZR36057_VSSFGR_FrameGrab;
+					btwrite(reg, ZR36057_VSSFGR);
+
+					btor(ZR36057_VDCR_VidEn,
+					     ZR36057_VDCR);
+				}
+			}
+
+			/* even if we don't grab, we do want to increment
+			 * the sequence counter to see lost frames */
+			zr->v4l_grab_seq++;
+		}
+#if (IRQ_MASK & ZR36057_ISR_CodRepIRQ)
+		if (astat & ZR36057_ISR_CodRepIRQ) {
+			zr->intr_counter_CodRepIRQ++;
+			IDEBUG(printk
+			       (KERN_DEBUG "%s: ZR36057_ISR_CodRepIRQ\n",
+				ZR_DEVNAME(zr)));
+			btand(~ZR36057_ICR_CodRepIRQ, ZR36057_ICR);
+		}
+#endif				/* (IRQ_MASK & ZR36057_ISR_CodRepIRQ) */
+
+#if (IRQ_MASK & ZR36057_ISR_JPEGRepIRQ)
+		if (astat & ZR36057_ISR_JPEGRepIRQ) {
+
+			if (zr->codec_mode == BUZ_MODE_MOTION_DECOMPRESS ||
+			    zr->codec_mode == BUZ_MODE_MOTION_COMPRESS) {
+				if (zr36067_debug > 1 &&
+				    (!zr->frame_num || zr->JPEG_error)) {
+					printk(KERN_INFO
+					       "%s: first frame ready: state=0x%08x odd_even=%d field_per_buff=%d delay=%d\n",
+					       ZR_DEVNAME(zr), stat,
+					       zr->jpg_settings.odd_even,
+					       zr->jpg_settings.
+					       field_per_buff,
+					       zr->JPEG_missed);
+					{
+						char sc[] = "0000";
+						char sv[5];
+						int i;
+						strcpy(sv, sc);
+						for (i = 0; i < 4; i++) {
+							if (le32_to_cpu(zr->stat_com[i]) & 1)
+								sv[i] = '1';
+						}
+						sv[4] = 0;
+						printk(KERN_INFO
+						       "%s: stat_com=%s queue_state=%ld/%ld/%ld/%ld\n",
+						       ZR_DEVNAME(zr), sv,
+						       zr->jpg_que_tail,
+						       zr->jpg_dma_tail,
+						       zr->jpg_dma_head,
+						       zr->jpg_que_head);
+					}
+				} else {
+					if (zr->JPEG_missed > zr->JPEG_max_missed)	// Get statistics
+						zr->JPEG_max_missed =
+						    zr->JPEG_missed;
+					if (zr->JPEG_missed <
+					    zr->JPEG_min_missed)
+						zr->JPEG_min_missed =
+						    zr->JPEG_missed;
+				}
+
+				if (zr36067_debug > 2 && zr->frame_num < 6) {
+					int i;
+					printk("%s: seq=%ld stat_com:",
+					       ZR_DEVNAME(zr), zr->jpg_seq_num);
+					for (i = 0; i < 4; i++) {
+						printk(" %08x",
+						       le32_to_cpu(zr->stat_com[i]));
+					}
+					printk("\n");
+				}
+				zr->frame_num++;
+				zr->JPEG_missed = 0;
+				zr->JPEG_error = 0;
+				zoran_reap_stat_com(zr);
+				zoran_feed_stat_com(zr);
+				wake_up_interruptible(&zr->jpg_capq);
+			} /*else {
+			      dprintk(1,
+					KERN_ERR
+					"%s: JPEG interrupt while not in motion (de)compress mode!\n",
+					ZR_DEVNAME(zr));
+			}*/
+		}
+#endif				/* (IRQ_MASK & ZR36057_ISR_JPEGRepIRQ) */
+
+		/* DATERR, too many fields missed, error processing */
+		if ((astat & zr->card.jpeg_int) ||
+		    zr->JPEG_missed > 25 ||
+		    zr->JPEG_error == 1	||
+		    ((zr->codec_mode == BUZ_MODE_MOTION_DECOMPRESS) &&
+		     (zr->frame_num & (zr->JPEG_missed >
+				       zr->jpg_settings.field_per_buff)))) {
+			error_handler(zr, astat, stat);
+		}
+
+		count++;
+		if (count > 10) {
+			dprintk(2, KERN_WARNING "%s: irq loop %d\n",
+				ZR_DEVNAME(zr), count);
+			if (count > 20) {
+				btand(~ZR36057_ICR_IntPinEn, ZR36057_ICR);
+				dprintk(2,
+					KERN_ERR
+					"%s: IRQ lockup, cleared int mask\n",
+					ZR_DEVNAME(zr));
+				break;
+			}
+		}
+		zr->last_isr = stat;
+	}
+	spin_unlock_irqrestore(&zr->spinlock, flags);
+
+	return IRQ_HANDLED;
+}
+
+void
+zoran_set_pci_master (struct zoran *zr,
+		      int           set_master)
+{
+	if (set_master) {
+		pci_set_master(zr->pci_dev);
+	} else {
+		u16 command;
+
+		pci_read_config_word(zr->pci_dev, PCI_COMMAND, &command);
+		command &= ~PCI_COMMAND_MASTER;
+		pci_write_config_word(zr->pci_dev, PCI_COMMAND, command);
+	}
+}
+
+void
+zoran_init_hardware (struct zoran *zr)
+{
+	int j, zero = 0;
+
+	/* Enable bus-mastering */
+	zoran_set_pci_master(zr, 1);
+
+	/* Initialize the board */
+	if (zr->card.init) {
+		zr->card.init(zr);
+	}
+
+	j = zr->card.input[zr->input].muxsel;
+
+	decoder_command(zr, 0, NULL);
+	decoder_command(zr, DECODER_SET_NORM, &zr->norm);
+	decoder_command(zr, DECODER_SET_INPUT, &j);
+
+	encoder_command(zr, 0, NULL);
+	encoder_command(zr, ENCODER_SET_NORM, &zr->norm);
+	encoder_command(zr, ENCODER_SET_INPUT, &zero);
+
+	/* toggle JPEG codec sleep to sync PLL */
+	jpeg_codec_sleep(zr, 1);
+	jpeg_codec_sleep(zr, 0);
+
+	/* set individual interrupt enables (without GIRQ1)
+	 * but don't global enable until zoran_open() */
+
+	//btwrite(IRQ_MASK & ~ZR36057_ISR_GIRQ1, ZR36057_ICR);  // SW
+	// It looks like using only JPEGRepIRQEn is not always reliable,
+	// may be when JPEG codec crashes it won't generate IRQ? So,
+	 /*CP*/			//        btwrite(IRQ_MASK, ZR36057_ICR); // Enable Vsync interrupts too. SM    WHY ? LP
+	    zr36057_init_vfe(zr);
+
+	zr36057_enable_jpg(zr, BUZ_MODE_IDLE);
+
+	btwrite(IRQ_MASK, ZR36057_ISR);	// Clears interrupts
+}
+
+void
+zr36057_restart (struct zoran *zr)
+{
+	btwrite(0, ZR36057_SPGPPCR);
+	mdelay(1);
+	btor(ZR36057_SPGPPCR_SoftReset, ZR36057_SPGPPCR);
+	mdelay(1);
+
+	/* assert P_Reset */
+	btwrite(0, ZR36057_JPC);
+	/* set up GPIO direction - all output */
+	btwrite(ZR36057_SPGPPCR_SoftReset | 0, ZR36057_SPGPPCR);
+
+	/* set up GPIO pins and guest bus timing */
+	btwrite((0x81 << 24) | 0x8888, ZR36057_GPPGCR1);
+}
+
+/*
+ * initialize video front end
+ */
+
+static void
+zr36057_init_vfe (struct zoran *zr)
+{
+	u32 reg;
+
+	reg = btread(ZR36057_VFESPFR);
+	reg |= ZR36057_VFESPFR_LittleEndian;
+	reg &= ~ZR36057_VFESPFR_VCLKPol;
+	reg |= ZR36057_VFESPFR_ExtFl;
+	reg |= ZR36057_VFESPFR_TopField;
+	btwrite(reg, ZR36057_VFESPFR);
+	reg = btread(ZR36057_VDCR);
+	if (pci_pci_problems & PCIPCI_TRITON)
+		// || zr->revision < 1) // Revision 1 has also Triton support
+		reg &= ~ZR36057_VDCR_Triton;
+	else
+		reg |= ZR36057_VDCR_Triton;
+	btwrite(reg, ZR36057_VDCR);
+}
+
+/*
+ * Interface to decoder and encoder chips using i2c bus
+ */
+
+int
+decoder_command (struct zoran *zr,
+		 int           cmd,
+		 void         *data)
+{
+	if (zr->decoder == NULL)
+		return -EIO;
+
+	if (zr->card.type == LML33 &&
+	    (cmd == DECODER_SET_NORM || cmd == DECODER_SET_INPUT)) {
+		int res;
+
+		// Bt819 needs to reset its FIFO buffer using #FRST pin and
+		// LML33 card uses GPIO(7) for that.
+		GPIO(zr, 7, 0);
+		res = zr->decoder->driver->command(zr->decoder, cmd, data);
+		// Pull #FRST high.
+		GPIO(zr, 7, 1);
+		return res;
+	} else
+		return zr->decoder->driver->command(zr->decoder, cmd,
+						    data);
+}
+
+int
+encoder_command (struct zoran *zr,
+		 int           cmd,
+		 void         *data)
+{
+	if (zr->encoder == NULL)
+		return -1;
+
+	return zr->encoder->driver->command(zr->encoder, cmd, data);
+}
diff --git a/drivers/media/video/zoran/zoran_device.h b/drivers/media/video/zoran/zoran_device.h
new file mode 100644
index 0000000..74c6c8e
--- /dev/null
+++ b/drivers/media/video/zoran/zoran_device.h
@@ -0,0 +1,97 @@
+/*
+ * Zoran zr36057/zr36067 PCI controller driver, for the
+ * Pinnacle/Miro DC10/DC10+/DC30/DC30+, Iomega Buz, Linux
+ * Media Labs LML33/LML33R10.
+ *
+ * This part handles card-specific data and detection
+ *
+ * Copyright (C) 2000 Serguei Miridonov <mirsev@cicese.mx>
+ *
+ * Currently maintained by:
+ *   Ronald Bultje    <rbultje@ronald.bitfreak.net>
+ *   Laurent Pinchart <laurent.pinchart@skynet.be>
+ *   Mailinglist      <mjpeg-users@lists.sf.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU 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 __ZORAN_DEVICE_H__
+#define __ZORAN_DEVICE_H__
+
+/* general purpose I/O */
+extern void GPIO(struct zoran *zr,
+		 int bit,
+		 unsigned int value);
+
+/* codec (or actually: guest bus) access */
+extern int post_office_wait(struct zoran *zr);
+extern int post_office_write(struct zoran *zr,
+			     unsigned guest,
+			     unsigned reg,
+			     unsigned value);
+extern int post_office_read(struct zoran *zr,
+			    unsigned guest,
+			    unsigned reg);
+
+extern void detect_guest_activity(struct zoran *zr);
+
+extern void jpeg_codec_sleep(struct zoran *zr,
+			     int sleep);
+extern int jpeg_codec_reset(struct zoran *zr);
+
+/* zr360x7 access to raw capture */
+extern void zr36057_overlay(struct zoran *zr,
+			    int on);
+extern void write_overlay_mask(struct file *file,
+			       struct video_clip *vp,
+			       int count);
+extern void zr36057_set_memgrab(struct zoran *zr,
+				int mode);
+extern int wait_grab_pending(struct zoran *zr);
+
+/* interrupts */
+extern void print_interrupts(struct zoran *zr);
+extern void clear_interrupt_counters(struct zoran *zr);
+extern irqreturn_t zoran_irq(int irq, void *dev_id);
+
+/* JPEG codec access */
+extern void jpeg_start(struct zoran *zr);
+extern void zr36057_enable_jpg(struct zoran *zr,
+			       enum zoran_codec_mode mode);
+extern void zoran_feed_stat_com(struct zoran *zr);
+
+/* general */
+extern void zoran_set_pci_master(struct zoran *zr,
+				 int set_master);
+extern void zoran_init_hardware(struct zoran *zr);
+extern void zr36057_restart(struct zoran *zr);
+
+extern const struct zoran_format zoran_formats[];
+
+extern int v4l_nbufs;
+extern int v4l_bufsize;
+extern int jpg_nbufs;
+extern int jpg_bufsize;
+extern int pass_through;
+
+/* i2c */
+extern int decoder_command(struct zoran *zr,
+			   int cmd,
+			   void *data);
+extern int encoder_command(struct zoran *zr,
+			   int cmd,
+			   void *data);
+
+#endif				/* __ZORAN_DEVICE_H__ */
diff --git a/drivers/media/video/zoran/zoran_driver.c b/drivers/media/video/zoran/zoran_driver.c
new file mode 100644
index 0000000..25de763
--- /dev/null
+++ b/drivers/media/video/zoran/zoran_driver.c
@@ -0,0 +1,4649 @@
+/*
+ * Zoran zr36057/zr36067 PCI controller driver, for the
+ * Pinnacle/Miro DC10/DC10+/DC30/DC30+, Iomega Buz, Linux
+ * Media Labs LML33/LML33R10.
+ *
+ * Copyright (C) 2000 Serguei Miridonov <mirsev@cicese.mx>
+ *
+ * Changes for BUZ by Wolfgang Scherr <scherr@net4you.net>
+ *
+ * Changes for DC10/DC30 by Laurent Pinchart <laurent.pinchart@skynet.be>
+ *
+ * Changes for LML33R10 by Maxim Yevtyushkin <max@linuxmedialabs.com>
+ *
+ * Changes for videodev2/v4l2 by Ronald Bultje <rbultje@ronald.bitfreak.net>
+ *
+ * Based on
+ *
+ * Miro DC10 driver
+ * Copyright (C) 1999 Wolfgang Scherr <scherr@net4you.net>
+ *
+ * Iomega Buz driver version 1.0
+ * Copyright (C) 1999 Rainer Johanni <Rainer@Johanni.de>
+ *
+ * buz.0.0.3
+ * Copyright (C) 1998 Dave Perks <dperks@ibm.net>
+ *
+ * bttv - Bt848 frame grabber driver
+ * Copyright (C) 1996,97,98 Ralph  Metzler (rjkm@thp.uni-koeln.de)
+ *                        & Marcus Metzler (mocm@thp.uni-koeln.de)
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/version.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+#include <linux/vmalloc.h>
+#include <linux/wait.h>
+
+#include <linux/interrupt.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+
+#include <linux/spinlock.h>
+#define     MAP_NR(x)       virt_to_page(x)
+#define     ZORAN_VID_TYPE  ( \
+				VID_TYPE_CAPTURE | \
+				VID_TYPE_OVERLAY | \
+				VID_TYPE_CLIPPING | \
+				VID_TYPE_FRAMERAM | \
+				VID_TYPE_SCALES | \
+				VID_TYPE_MJPEG_DECODER | \
+				VID_TYPE_MJPEG_ENCODER \
+			     )
+
+#include <linux/videodev.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-ioctl.h>
+#include "videocodec.h"
+
+#include <asm/byteorder.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <linux/proc_fs.h>
+
+#include <linux/video_decoder.h>
+#include <linux/video_encoder.h>
+#include <linux/mutex.h>
+#include "zoran.h"
+#include "zoran_device.h"
+#include "zoran_card.h"
+
+	/* we declare some card type definitions here, they mean
+	 * the same as the v4l1 ZORAN_VID_TYPE above, except it's v4l2 */
+#define ZORAN_V4L2_VID_FLAGS ( \
+				V4L2_CAP_STREAMING |\
+				V4L2_CAP_VIDEO_CAPTURE |\
+				V4L2_CAP_VIDEO_OUTPUT |\
+				V4L2_CAP_VIDEO_OVERLAY \
+			      )
+
+
+#if defined(CONFIG_VIDEO_V4L1_COMPAT)
+#define ZFMT(pal, fcc, cs) \
+	.palette = (pal), .fourcc = (fcc), .colorspace = (cs)
+#else
+#define ZFMT(pal, fcc, cs) \
+	.fourcc = (fcc), .colorspace = (cs)
+#endif
+
+const struct zoran_format zoran_formats[] = {
+	{
+		.name = "15-bit RGB LE",
+		ZFMT(VIDEO_PALETTE_RGB555,
+		     V4L2_PIX_FMT_RGB555, V4L2_COLORSPACE_SRGB),
+		.depth = 15,
+		.flags = ZORAN_FORMAT_CAPTURE |
+			 ZORAN_FORMAT_OVERLAY,
+		.vfespfr = ZR36057_VFESPFR_RGB555|ZR36057_VFESPFR_ErrDif|
+			   ZR36057_VFESPFR_LittleEndian,
+	}, {
+		.name = "15-bit RGB BE",
+		ZFMT(-1,
+		     V4L2_PIX_FMT_RGB555X, V4L2_COLORSPACE_SRGB),
+		.depth = 15,
+		.flags = ZORAN_FORMAT_CAPTURE |
+			 ZORAN_FORMAT_OVERLAY,
+		.vfespfr = ZR36057_VFESPFR_RGB555|ZR36057_VFESPFR_ErrDif,
+	}, {
+		.name = "16-bit RGB LE",
+		ZFMT(VIDEO_PALETTE_RGB565,
+		     V4L2_PIX_FMT_RGB565, V4L2_COLORSPACE_SRGB),
+		.depth = 16,
+		.flags = ZORAN_FORMAT_CAPTURE |
+			 ZORAN_FORMAT_OVERLAY,
+		.vfespfr = ZR36057_VFESPFR_RGB565|ZR36057_VFESPFR_ErrDif|
+			   ZR36057_VFESPFR_LittleEndian,
+	}, {
+		.name = "16-bit RGB BE",
+		ZFMT(-1,
+		     V4L2_PIX_FMT_RGB565X, V4L2_COLORSPACE_SRGB),
+		.depth = 16,
+		.flags = ZORAN_FORMAT_CAPTURE |
+			 ZORAN_FORMAT_OVERLAY,
+		.vfespfr = ZR36057_VFESPFR_RGB565|ZR36057_VFESPFR_ErrDif,
+	}, {
+		.name = "24-bit RGB",
+		ZFMT(VIDEO_PALETTE_RGB24,
+		     V4L2_PIX_FMT_BGR24, V4L2_COLORSPACE_SRGB),
+		.depth = 24,
+		.flags = ZORAN_FORMAT_CAPTURE |
+			 ZORAN_FORMAT_OVERLAY,
+		.vfespfr = ZR36057_VFESPFR_RGB888|ZR36057_VFESPFR_Pack24,
+	}, {
+		.name = "32-bit RGB LE",
+		ZFMT(VIDEO_PALETTE_RGB32,
+		     V4L2_PIX_FMT_BGR32, V4L2_COLORSPACE_SRGB),
+		.depth = 32,
+		.flags = ZORAN_FORMAT_CAPTURE |
+			 ZORAN_FORMAT_OVERLAY,
+		.vfespfr = ZR36057_VFESPFR_RGB888|ZR36057_VFESPFR_LittleEndian,
+	}, {
+		.name = "32-bit RGB BE",
+		ZFMT(-1,
+		     V4L2_PIX_FMT_RGB32, V4L2_COLORSPACE_SRGB),
+		.depth = 32,
+		.flags = ZORAN_FORMAT_CAPTURE |
+			 ZORAN_FORMAT_OVERLAY,
+		.vfespfr = ZR36057_VFESPFR_RGB888,
+	}, {
+		.name = "4:2:2, packed, YUYV",
+		ZFMT(VIDEO_PALETTE_YUV422,
+		     V4L2_PIX_FMT_YUYV, V4L2_COLORSPACE_SMPTE170M),
+		.depth = 16,
+		.flags = ZORAN_FORMAT_CAPTURE |
+			 ZORAN_FORMAT_OVERLAY,
+		.vfespfr = ZR36057_VFESPFR_YUV422,
+	}, {
+		.name = "4:2:2, packed, UYVY",
+		ZFMT(VIDEO_PALETTE_UYVY,
+		     V4L2_PIX_FMT_UYVY, V4L2_COLORSPACE_SMPTE170M),
+		.depth = 16,
+		.flags = ZORAN_FORMAT_CAPTURE |
+			 ZORAN_FORMAT_OVERLAY,
+		.vfespfr = ZR36057_VFESPFR_YUV422|ZR36057_VFESPFR_LittleEndian,
+	}, {
+		.name = "Hardware-encoded Motion-JPEG",
+		ZFMT(-1,
+		     V4L2_PIX_FMT_MJPEG, V4L2_COLORSPACE_SMPTE170M),
+		.depth = 0,
+		.flags = ZORAN_FORMAT_CAPTURE |
+			 ZORAN_FORMAT_PLAYBACK |
+			 ZORAN_FORMAT_COMPRESSED,
+	}
+};
+#define NUM_FORMATS ARRAY_SIZE(zoran_formats)
+
+// RJ: Test only - want to test BUZ_USE_HIMEM even when CONFIG_BIGPHYS_AREA is defined
+
+
+static int lock_norm;	/* 0 = default 1 = Don't change TV standard (norm) */
+module_param(lock_norm, int, 0644);
+MODULE_PARM_DESC(lock_norm, "Prevent norm changes (1 = ignore, >1 = fail)");
+
+	/* small helper function for calculating buffersizes for v4l2
+	 * we calculate the nearest higher power-of-two, which
+	 * will be the recommended buffersize */
+static __u32
+zoran_v4l2_calc_bufsize (struct zoran_jpg_settings *settings)
+{
+	__u8 div = settings->VerDcm * settings->HorDcm * settings->TmpDcm;
+	__u32 num = (1024 * 512) / (div);
+	__u32 result = 2;
+
+	num--;
+	while (num) {
+		num >>= 1;
+		result <<= 1;
+	}
+
+	if (result > jpg_bufsize)
+		return jpg_bufsize;
+	if (result < 8192)
+		return 8192;
+	return result;
+}
+
+/* forward references */
+static void v4l_fbuffer_free(struct file *file);
+static void jpg_fbuffer_free(struct file *file);
+
+/*
+ *   Allocate the V4L grab buffers
+ *
+ *   These have to be pysically contiguous.
+ *   If v4l_bufsize <= MAX_KMALLOC_MEM we use kmalloc
+ *   else we try to allocate them with bigphysarea_alloc_pages
+ *   if the bigphysarea patch is present in the kernel,
+ *   else we try to use high memory (if the user has bootet
+ *   Linux with the necessary memory left over).
+ */
+
+static unsigned long
+get_high_mem (unsigned long size)
+{
+/*
+ * Check if there is usable memory at the end of Linux memory
+ * of at least size. Return the physical address of this memory,
+ * return 0 on failure.
+ *
+ * The idea is from Alexandro Rubini's book "Linux device drivers".
+ * The driver from him which is downloadable from O'Reilly's
+ * web site misses the "virt_to_phys(high_memory)" part
+ * (and therefore doesn't work at all - at least with 2.2.x kernels).
+ *
+ * It should be unnecessary to mention that THIS IS DANGEROUS,
+ * if more than one driver at a time has the idea to use this memory!!!!
+ */
+
+	volatile unsigned char __iomem *mem;
+	unsigned char c;
+	unsigned long hi_mem_ph;
+	unsigned long i;
+
+	/* Map the high memory to user space */
+
+	hi_mem_ph = virt_to_phys(high_memory);
+
+	mem = ioremap(hi_mem_ph, size);
+	if (!mem) {
+		dprintk(1,
+			KERN_ERR "%s: get_high_mem() - ioremap failed\n",
+			ZORAN_NAME);
+		return 0;
+	}
+
+	for (i = 0; i < size; i++) {
+		/* Check if it is memory */
+		c = i & 0xff;
+		writeb(c, mem + i);
+		if (readb(mem + i) != c)
+			break;
+		c = 255 - c;
+		writeb(c, mem + i);
+		if (readb(mem + i) != c)
+			break;
+		writeb(0, mem + i);	/* zero out memory */
+
+		/* give the kernel air to breath */
+		if ((i & 0x3ffff) == 0x3ffff)
+			schedule();
+	}
+
+	iounmap(mem);
+
+	if (i != size) {
+		dprintk(1,
+			KERN_ERR
+			"%s: get_high_mem() - requested %lu, avail %lu\n",
+			ZORAN_NAME, size, i);
+		return 0;
+	}
+
+	return hi_mem_ph;
+}
+
+static int
+v4l_fbuffer_alloc (struct file *file)
+{
+	struct zoran_fh *fh = file->private_data;
+	struct zoran *zr = fh->zr;
+	int i, off;
+	unsigned char *mem;
+	unsigned long pmem = 0;
+
+	/* we might have old buffers lying around... */
+	if (fh->v4l_buffers.ready_to_be_freed) {
+		v4l_fbuffer_free(file);
+	}
+
+	for (i = 0; i < fh->v4l_buffers.num_buffers; i++) {
+		if (fh->v4l_buffers.buffer[i].fbuffer)
+			dprintk(2,
+				KERN_WARNING
+				"%s: v4l_fbuffer_alloc() - buffer %d allready allocated!?\n",
+				ZR_DEVNAME(zr), i);
+
+		//udelay(20);
+		if (fh->v4l_buffers.buffer_size <= MAX_KMALLOC_MEM) {
+			/* Use kmalloc */
+
+			mem = kmalloc(fh->v4l_buffers.buffer_size, GFP_KERNEL);
+			if (!mem) {
+				dprintk(1,
+					KERN_ERR
+					"%s: v4l_fbuffer_alloc() - kmalloc for V4L buf %d failed\n",
+					ZR_DEVNAME(zr), i);
+				v4l_fbuffer_free(file);
+				return -ENOBUFS;
+			}
+			fh->v4l_buffers.buffer[i].fbuffer = mem;
+			fh->v4l_buffers.buffer[i].fbuffer_phys =
+			    virt_to_phys(mem);
+			fh->v4l_buffers.buffer[i].fbuffer_bus =
+			    virt_to_bus(mem);
+			for (off = 0; off < fh->v4l_buffers.buffer_size;
+			     off += PAGE_SIZE)
+				SetPageReserved(MAP_NR(mem + off));
+			dprintk(4,
+				KERN_INFO
+				"%s: v4l_fbuffer_alloc() - V4L frame %d mem 0x%lx (bus: 0x%lx)\n",
+				ZR_DEVNAME(zr), i, (unsigned long) mem,
+				virt_to_bus(mem));
+		} else {
+
+			/* Use high memory which has been left at boot time */
+
+			/* Ok., Ok. this is an evil hack - we make
+			 * the assumption that physical addresses are
+			 * the same as bus addresses (true at least
+			 * for Intel processors). The whole method of
+			 * obtaining and using this memory is not very
+			 * nice - but I hope it saves some poor users
+			 * from kernel hacking, which might have even
+			 * more evil results */
+
+			if (i == 0) {
+				int size =
+				    fh->v4l_buffers.num_buffers *
+				    fh->v4l_buffers.buffer_size;
+
+				pmem = get_high_mem(size);
+				if (pmem == 0) {
+					dprintk(1,
+						KERN_ERR
+						"%s: v4l_fbuffer_alloc() - get_high_mem (size = %d KB) for V4L bufs failed\n",
+						ZR_DEVNAME(zr), size >> 10);
+					return -ENOBUFS;
+				}
+				fh->v4l_buffers.buffer[0].fbuffer = NULL;
+				fh->v4l_buffers.buffer[0].fbuffer_phys = pmem;
+				fh->v4l_buffers.buffer[0].fbuffer_bus = pmem;
+				dprintk(4,
+					KERN_INFO
+					"%s: v4l_fbuffer_alloc() - using %d KB high memory\n",
+					ZR_DEVNAME(zr), size >> 10);
+			} else {
+				fh->v4l_buffers.buffer[i].fbuffer = NULL;
+				fh->v4l_buffers.buffer[i].fbuffer_phys =
+				    pmem + i * fh->v4l_buffers.buffer_size;
+				fh->v4l_buffers.buffer[i].fbuffer_bus =
+				    pmem + i * fh->v4l_buffers.buffer_size;
+			}
+		}
+	}
+
+	fh->v4l_buffers.allocated = 1;
+
+	return 0;
+}
+
+/* free the V4L grab buffers */
+static void
+v4l_fbuffer_free (struct file *file)
+{
+	struct zoran_fh *fh = file->private_data;
+	struct zoran *zr = fh->zr;
+	int i, off;
+	unsigned char *mem;
+
+	dprintk(4, KERN_INFO "%s: v4l_fbuffer_free()\n", ZR_DEVNAME(zr));
+
+	for (i = 0; i < fh->v4l_buffers.num_buffers; i++) {
+		if (!fh->v4l_buffers.buffer[i].fbuffer)
+			continue;
+
+		if (fh->v4l_buffers.buffer_size <= MAX_KMALLOC_MEM) {
+			mem = fh->v4l_buffers.buffer[i].fbuffer;
+			for (off = 0; off < fh->v4l_buffers.buffer_size;
+			     off += PAGE_SIZE)
+				ClearPageReserved(MAP_NR(mem + off));
+			kfree((void *) fh->v4l_buffers.buffer[i].fbuffer);
+		}
+		fh->v4l_buffers.buffer[i].fbuffer = NULL;
+	}
+
+	fh->v4l_buffers.allocated = 0;
+	fh->v4l_buffers.ready_to_be_freed = 0;
+}
+
+/*
+ *   Allocate the MJPEG grab buffers.
+ *
+ *   If the requested buffer size is smaller than MAX_KMALLOC_MEM,
+ *   kmalloc is used to request a physically contiguous area,
+ *   else we allocate the memory in framgents with get_zeroed_page.
+ *
+ *   If a Natoma chipset is present and this is a revision 1 zr36057,
+ *   each MJPEG buffer needs to be physically contiguous.
+ *   (RJ: This statement is from Dave Perks' original driver,
+ *   I could never check it because I have a zr36067)
+ *   The driver cares about this because it reduces the buffer
+ *   size to MAX_KMALLOC_MEM in that case (which forces contiguous allocation).
+ *
+ *   RJ: The contents grab buffers needs never be accessed in the driver.
+ *       Therefore there is no need to allocate them with vmalloc in order
+ *       to get a contiguous virtual memory space.
+ *       I don't understand why many other drivers first allocate them with
+ *       vmalloc (which uses internally also get_zeroed_page, but delivers you
+ *       virtual addresses) and then again have to make a lot of efforts
+ *       to get the physical address.
+ *
+ *   Ben Capper:
+ *       On big-endian architectures (such as ppc) some extra steps
+ *       are needed. When reading and writing to the stat_com array
+ *       and fragment buffers, the device expects to see little-
+ *       endian values. The use of cpu_to_le32() and le32_to_cpu()
+ *       in this function (and one or two others in zoran_device.c)
+ *       ensure that these values are always stored in little-endian
+ *       form, regardless of architecture. The zr36057 does Very Bad
+ *       Things on big endian architectures if the stat_com array
+ *       and fragment buffers are not little-endian.
+ */
+
+static int
+jpg_fbuffer_alloc (struct file *file)
+{
+	struct zoran_fh *fh = file->private_data;
+	struct zoran *zr = fh->zr;
+	int i, j, off;
+	unsigned long mem;
+
+	/* we might have old buffers lying around */
+	if (fh->jpg_buffers.ready_to_be_freed) {
+		jpg_fbuffer_free(file);
+	}
+
+	for (i = 0; i < fh->jpg_buffers.num_buffers; i++) {
+		if (fh->jpg_buffers.buffer[i].frag_tab)
+			dprintk(2,
+				KERN_WARNING
+				"%s: jpg_fbuffer_alloc() - buffer %d allready allocated!?\n",
+				ZR_DEVNAME(zr), i);
+
+		/* Allocate fragment table for this buffer */
+
+		mem = get_zeroed_page(GFP_KERNEL);
+		if (mem == 0) {
+			dprintk(1,
+				KERN_ERR
+				"%s: jpg_fbuffer_alloc() - get_zeroed_page (frag_tab) failed for buffer %d\n",
+				ZR_DEVNAME(zr), i);
+			jpg_fbuffer_free(file);
+			return -ENOBUFS;
+		}
+		fh->jpg_buffers.buffer[i].frag_tab = (__le32 *) mem;
+		fh->jpg_buffers.buffer[i].frag_tab_bus =
+		    virt_to_bus((void *) mem);
+
+		//if (alloc_contig) {
+		if (fh->jpg_buffers.need_contiguous) {
+			mem =
+			    (unsigned long) kmalloc(fh->jpg_buffers.
+						    buffer_size,
+						    GFP_KERNEL);
+			if (mem == 0) {
+				dprintk(1,
+					KERN_ERR
+					"%s: jpg_fbuffer_alloc() - kmalloc failed for buffer %d\n",
+					ZR_DEVNAME(zr), i);
+				jpg_fbuffer_free(file);
+				return -ENOBUFS;
+			}
+			fh->jpg_buffers.buffer[i].frag_tab[0] =
+			    cpu_to_le32(virt_to_bus((void *) mem));
+			fh->jpg_buffers.buffer[i].frag_tab[1] =
+			    cpu_to_le32(((fh->jpg_buffers.buffer_size / 4) << 1) | 1);
+			for (off = 0; off < fh->jpg_buffers.buffer_size;
+			     off += PAGE_SIZE)
+				SetPageReserved(MAP_NR(mem + off));
+		} else {
+			/* jpg_bufsize is allreay page aligned */
+			for (j = 0;
+			     j < fh->jpg_buffers.buffer_size / PAGE_SIZE;
+			     j++) {
+				mem = get_zeroed_page(GFP_KERNEL);
+				if (mem == 0) {
+					dprintk(1,
+						KERN_ERR
+						"%s: jpg_fbuffer_alloc() - get_zeroed_page failed for buffer %d\n",
+						ZR_DEVNAME(zr), i);
+					jpg_fbuffer_free(file);
+					return -ENOBUFS;
+				}
+
+				fh->jpg_buffers.buffer[i].frag_tab[2 * j] =
+				    cpu_to_le32(virt_to_bus((void *) mem));
+				fh->jpg_buffers.buffer[i].frag_tab[2 * j +
+								   1] =
+				    cpu_to_le32((PAGE_SIZE / 4) << 1);
+				SetPageReserved(MAP_NR(mem));
+			}
+
+			fh->jpg_buffers.buffer[i].frag_tab[2 * j - 1] |= cpu_to_le32(1);
+		}
+	}
+
+	dprintk(4,
+		KERN_DEBUG "%s: jpg_fbuffer_alloc() - %d KB allocated\n",
+		ZR_DEVNAME(zr),
+		(fh->jpg_buffers.num_buffers *
+		 fh->jpg_buffers.buffer_size) >> 10);
+
+	fh->jpg_buffers.allocated = 1;
+
+	return 0;
+}
+
+/* free the MJPEG grab buffers */
+static void
+jpg_fbuffer_free (struct file *file)
+{
+	struct zoran_fh *fh = file->private_data;
+	struct zoran *zr = fh->zr;
+	int i, j, off;
+	unsigned char *mem;
+
+	dprintk(4, KERN_DEBUG "%s: jpg_fbuffer_free()\n", ZR_DEVNAME(zr));
+
+	for (i = 0; i < fh->jpg_buffers.num_buffers; i++) {
+		if (!fh->jpg_buffers.buffer[i].frag_tab)
+			continue;
+
+		//if (alloc_contig) {
+		if (fh->jpg_buffers.need_contiguous) {
+			if (fh->jpg_buffers.buffer[i].frag_tab[0]) {
+				mem = (unsigned char *) bus_to_virt(le32_to_cpu(
+					fh->jpg_buffers.buffer[i].frag_tab[0]));
+				for (off = 0;
+				     off < fh->jpg_buffers.buffer_size;
+				     off += PAGE_SIZE)
+					ClearPageReserved(MAP_NR
+							  (mem + off));
+				kfree(mem);
+				fh->jpg_buffers.buffer[i].frag_tab[0] = 0;
+				fh->jpg_buffers.buffer[i].frag_tab[1] = 0;
+			}
+		} else {
+			for (j = 0;
+			     j < fh->jpg_buffers.buffer_size / PAGE_SIZE;
+			     j++) {
+				if (!fh->jpg_buffers.buffer[i].
+				    frag_tab[2 * j])
+					break;
+				ClearPageReserved(MAP_NR
+						  (bus_to_virt
+						   (le32_to_cpu
+						    (fh->jpg_buffers.
+						     buffer[i].frag_tab[2 *
+								       j]))));
+				free_page((unsigned long)
+					  bus_to_virt
+						  (le32_to_cpu
+						   (fh->jpg_buffers.
+						      buffer[i].
+						      frag_tab[2 * j])));
+				fh->jpg_buffers.buffer[i].frag_tab[2 * j] =
+				    0;
+				fh->jpg_buffers.buffer[i].frag_tab[2 * j +
+								   1] = 0;
+			}
+		}
+
+		free_page((unsigned long) fh->jpg_buffers.buffer[i].
+			  frag_tab);
+		fh->jpg_buffers.buffer[i].frag_tab = NULL;
+	}
+
+	fh->jpg_buffers.allocated = 0;
+	fh->jpg_buffers.ready_to_be_freed = 0;
+}
+
+/*
+ *   V4L Buffer grabbing
+ */
+
+static int
+zoran_v4l_set_format (struct file               *file,
+		      int                        width,
+		      int                        height,
+		      const struct zoran_format *format)
+{
+	struct zoran_fh *fh = file->private_data;
+	struct zoran *zr = fh->zr;
+	int bpp;
+
+	/* Check size and format of the grab wanted */
+
+	if (height < BUZ_MIN_HEIGHT || width < BUZ_MIN_WIDTH ||
+	    height > BUZ_MAX_HEIGHT || width > BUZ_MAX_WIDTH) {
+		dprintk(1,
+			KERN_ERR
+			"%s: v4l_set_format() - wrong frame size (%dx%d)\n",
+			ZR_DEVNAME(zr), width, height);
+		return -EINVAL;
+	}
+
+	bpp = (format->depth + 7) / 8;
+
+	/* Check against available buffer size */
+	if (height * width * bpp > fh->v4l_buffers.buffer_size) {
+		dprintk(1,
+			KERN_ERR
+			"%s: v4l_set_format() - video buffer size (%d kB) is too small\n",
+			ZR_DEVNAME(zr), fh->v4l_buffers.buffer_size >> 10);
+		return -EINVAL;
+	}
+
+	/* The video front end needs 4-byte alinged line sizes */
+
+	if ((bpp == 2 && (width & 1)) || (bpp == 3 && (width & 3))) {
+		dprintk(1,
+			KERN_ERR
+			"%s: v4l_set_format() - wrong frame alingment\n",
+			ZR_DEVNAME(zr));
+		return -EINVAL;
+	}
+
+	fh->v4l_settings.width = width;
+	fh->v4l_settings.height = height;
+	fh->v4l_settings.format = format;
+	fh->v4l_settings.bytesperline = bpp * fh->v4l_settings.width;
+
+	return 0;
+}
+
+static int
+zoran_v4l_queue_frame (struct file *file,
+		       int          num)
+{
+	struct zoran_fh *fh = file->private_data;
+	struct zoran *zr = fh->zr;
+	unsigned long flags;
+	int res = 0;
+
+	if (!fh->v4l_buffers.allocated) {
+		dprintk(1,
+			KERN_ERR
+			"%s: v4l_queue_frame() - buffers not yet allocated\n",
+			ZR_DEVNAME(zr));
+		res = -ENOMEM;
+	}
+
+	/* No grabbing outside the buffer range! */
+	if (num >= fh->v4l_buffers.num_buffers || num < 0) {
+		dprintk(1,
+			KERN_ERR
+			"%s: v4l_queue_frame() - buffer %d is out of range\n",
+			ZR_DEVNAME(zr), num);
+		res = -EINVAL;
+	}
+
+	spin_lock_irqsave(&zr->spinlock, flags);
+
+	if (fh->v4l_buffers.active == ZORAN_FREE) {
+		if (zr->v4l_buffers.active == ZORAN_FREE) {
+			zr->v4l_buffers = fh->v4l_buffers;
+			fh->v4l_buffers.active = ZORAN_ACTIVE;
+		} else {
+			dprintk(1,
+				KERN_ERR
+				"%s: v4l_queue_frame() - another session is already capturing\n",
+				ZR_DEVNAME(zr));
+			res = -EBUSY;
+		}
+	}
+
+	/* make sure a grab isn't going on currently with this buffer */
+	if (!res) {
+		switch (zr->v4l_buffers.buffer[num].state) {
+		default:
+		case BUZ_STATE_PEND:
+			if (zr->v4l_buffers.active == ZORAN_FREE) {
+				fh->v4l_buffers.active = ZORAN_FREE;
+				zr->v4l_buffers.allocated = 0;
+			}
+			res = -EBUSY;	/* what are you doing? */
+			break;
+		case BUZ_STATE_DONE:
+			dprintk(2,
+				KERN_WARNING
+				"%s: v4l_queue_frame() - queueing buffer %d in state DONE!?\n",
+				ZR_DEVNAME(zr), num);
+		case BUZ_STATE_USER:
+			/* since there is at least one unused buffer there's room for at least
+			 * one more pend[] entry */
+			zr->v4l_pend[zr->v4l_pend_head++ &
+					V4L_MASK_FRAME] = num;
+			zr->v4l_buffers.buffer[num].state = BUZ_STATE_PEND;
+			zr->v4l_buffers.buffer[num].bs.length =
+			    fh->v4l_settings.bytesperline *
+			    zr->v4l_settings.height;
+			fh->v4l_buffers.buffer[num] =
+			    zr->v4l_buffers.buffer[num];
+			break;
+		}
+	}
+
+	spin_unlock_irqrestore(&zr->spinlock, flags);
+
+	if (!res && zr->v4l_buffers.active == ZORAN_FREE)
+		zr->v4l_buffers.active = fh->v4l_buffers.active;
+
+	return res;
+}
+
+static int
+v4l_grab (struct file       *file,
+	  struct video_mmap *mp)
+{
+	struct zoran_fh *fh = file->private_data;
+	struct zoran *zr = fh->zr;
+	int res = 0, i;
+
+	for (i = 0; i < NUM_FORMATS; i++) {
+		if (zoran_formats[i].palette == mp->format &&
+		    zoran_formats[i].flags & ZORAN_FORMAT_CAPTURE &&
+		    !(zoran_formats[i].flags & ZORAN_FORMAT_COMPRESSED))
+			break;
+	}
+	if (i == NUM_FORMATS || zoran_formats[i].depth == 0) {
+		dprintk(1,
+			KERN_ERR
+			"%s: v4l_grab() - wrong bytes-per-pixel format\n",
+			ZR_DEVNAME(zr));
+		return -EINVAL;
+	}
+
+	/*
+	 * To minimize the time spent in the IRQ routine, we avoid setting up
+	 * the video front end there.
+	 * If this grab has different parameters from a running streaming capture
+	 * we stop the streaming capture and start it over again.
+	 */
+	if (zr->v4l_memgrab_active &&
+	    (zr->v4l_settings.width != mp->width ||
+	     zr->v4l_settings.height != mp->height ||
+	     zr->v4l_settings.format->palette != mp->format)) {
+		res = wait_grab_pending(zr);
+		if (res)
+			return res;
+	}
+	if ((res = zoran_v4l_set_format(file,
+					mp->width,
+					mp->height,
+					&zoran_formats[i])))
+		return res;
+	zr->v4l_settings = fh->v4l_settings;
+
+	/* queue the frame in the pending queue */
+	if ((res = zoran_v4l_queue_frame(file, mp->frame))) {
+		fh->v4l_buffers.active = ZORAN_FREE;
+		return res;
+	}
+
+	/* put the 36057 into frame grabbing mode */
+	if (!res && !zr->v4l_memgrab_active)
+		zr36057_set_memgrab(zr, 1);
+
+	//dprintk(4, KERN_INFO "%s: Frame grab 3...\n", ZR_DEVNAME(zr));
+
+	return res;
+}
+
+/*
+ * Sync on a V4L buffer
+ */
+
+static int
+v4l_sync (struct file *file,
+	  int          frame)
+{
+	struct zoran_fh *fh = file->private_data;
+	struct zoran *zr = fh->zr;
+	unsigned long flags;
+
+	if (fh->v4l_buffers.active == ZORAN_FREE) {
+		dprintk(1,
+			KERN_ERR
+			"%s: v4l_sync() - no grab active for this session\n",
+			ZR_DEVNAME(zr));
+		return -EINVAL;
+	}
+
+	/* check passed-in frame number */
+	if (frame >= fh->v4l_buffers.num_buffers || frame < 0) {
+		dprintk(1,
+			KERN_ERR "%s: v4l_sync() - frame %d is invalid\n",
+			ZR_DEVNAME(zr), frame);
+		return -EINVAL;
+	}
+
+	/* Check if is buffer was queued at all */
+	if (zr->v4l_buffers.buffer[frame].state == BUZ_STATE_USER) {
+		dprintk(1,
+			KERN_ERR
+			"%s: v4l_sync() - attempt to sync on a buffer which was not queued?\n",
+			ZR_DEVNAME(zr));
+		return -EPROTO;
+	}
+
+	/* wait on this buffer to get ready */
+	if (!wait_event_interruptible_timeout(zr->v4l_capq,
+				(zr->v4l_buffers.buffer[frame].state != BUZ_STATE_PEND),
+				10*HZ))
+		return -ETIME;
+	if (signal_pending(current))
+		return -ERESTARTSYS;
+
+	/* buffer should now be in BUZ_STATE_DONE */
+	if (zr->v4l_buffers.buffer[frame].state != BUZ_STATE_DONE)
+		dprintk(2,
+			KERN_ERR "%s: v4l_sync() - internal state error\n",
+			ZR_DEVNAME(zr));
+
+	zr->v4l_buffers.buffer[frame].state = BUZ_STATE_USER;
+	fh->v4l_buffers.buffer[frame] = zr->v4l_buffers.buffer[frame];
+
+	spin_lock_irqsave(&zr->spinlock, flags);
+
+	/* Check if streaming capture has finished */
+	if (zr->v4l_pend_tail == zr->v4l_pend_head) {
+		zr36057_set_memgrab(zr, 0);
+		if (zr->v4l_buffers.active == ZORAN_ACTIVE) {
+			fh->v4l_buffers.active = zr->v4l_buffers.active =
+			    ZORAN_FREE;
+			zr->v4l_buffers.allocated = 0;
+		}
+	}
+
+	spin_unlock_irqrestore(&zr->spinlock, flags);
+
+	return 0;
+}
+
+/*
+ *   Queue a MJPEG buffer for capture/playback
+ */
+
+static int
+zoran_jpg_queue_frame (struct file          *file,
+		       int                   num,
+		       enum zoran_codec_mode mode)
+{
+	struct zoran_fh *fh = file->private_data;
+	struct zoran *zr = fh->zr;
+	unsigned long flags;
+	int res = 0;
+
+	/* Check if buffers are allocated */
+	if (!fh->jpg_buffers.allocated) {
+		dprintk(1,
+			KERN_ERR
+			"%s: jpg_queue_frame() - buffers not yet allocated\n",
+			ZR_DEVNAME(zr));
+		return -ENOMEM;
+	}
+
+	/* No grabbing outside the buffer range! */
+	if (num >= fh->jpg_buffers.num_buffers || num < 0) {
+		dprintk(1,
+			KERN_ERR
+			"%s: jpg_queue_frame() - buffer %d out of range\n",
+			ZR_DEVNAME(zr), num);
+		return -EINVAL;
+	}
+
+	/* what is the codec mode right now? */
+	if (zr->codec_mode == BUZ_MODE_IDLE) {
+		zr->jpg_settings = fh->jpg_settings;
+	} else if (zr->codec_mode != mode) {
+		/* wrong codec mode active - invalid */
+		dprintk(1,
+			KERN_ERR
+			"%s: jpg_queue_frame() - codec in wrong mode\n",
+			ZR_DEVNAME(zr));
+		return -EINVAL;
+	}
+
+	if (fh->jpg_buffers.active == ZORAN_FREE) {
+		if (zr->jpg_buffers.active == ZORAN_FREE) {
+			zr->jpg_buffers = fh->jpg_buffers;
+			fh->jpg_buffers.active = ZORAN_ACTIVE;
+		} else {
+			dprintk(1,
+				KERN_ERR
+				"%s: jpg_queue_frame() - another session is already capturing\n",
+				ZR_DEVNAME(zr));
+			res = -EBUSY;
+		}
+	}
+
+	if (!res && zr->codec_mode == BUZ_MODE_IDLE) {
+		/* Ok load up the jpeg codec */
+		zr36057_enable_jpg(zr, mode);
+	}
+
+	spin_lock_irqsave(&zr->spinlock, flags);
+
+	if (!res) {
+		switch (zr->jpg_buffers.buffer[num].state) {
+		case BUZ_STATE_DONE:
+			dprintk(2,
+				KERN_WARNING
+				"%s: jpg_queue_frame() - queing frame in BUZ_STATE_DONE state!?\n",
+				ZR_DEVNAME(zr));
+		case BUZ_STATE_USER:
+			/* since there is at least one unused buffer there's room for at
+			 *least one more pend[] entry */
+			zr->jpg_pend[zr->jpg_que_head++ & BUZ_MASK_FRAME] =
+			    num;
+			zr->jpg_buffers.buffer[num].state = BUZ_STATE_PEND;
+			fh->jpg_buffers.buffer[num] =
+			    zr->jpg_buffers.buffer[num];
+			zoran_feed_stat_com(zr);
+			break;
+		default:
+		case BUZ_STATE_DMA:
+		case BUZ_STATE_PEND:
+			if (zr->jpg_buffers.active == ZORAN_FREE) {
+				fh->jpg_buffers.active = ZORAN_FREE;
+				zr->jpg_buffers.allocated = 0;
+			}
+			res = -EBUSY;	/* what are you doing? */
+			break;
+		}
+	}
+
+	spin_unlock_irqrestore(&zr->spinlock, flags);
+
+	if (!res && zr->jpg_buffers.active == ZORAN_FREE) {
+		zr->jpg_buffers.active = fh->jpg_buffers.active;
+	}
+
+	return res;
+}
+
+static int
+jpg_qbuf (struct file          *file,
+	  int                   frame,
+	  enum zoran_codec_mode mode)
+{
+	struct zoran_fh *fh = file->private_data;
+	struct zoran *zr = fh->zr;
+	int res = 0;
+
+	/* Does the user want to stop streaming? */
+	if (frame < 0) {
+		if (zr->codec_mode == mode) {
+			if (fh->jpg_buffers.active == ZORAN_FREE) {
+				dprintk(1,
+					KERN_ERR
+					"%s: jpg_qbuf(-1) - session not active\n",
+					ZR_DEVNAME(zr));
+				return -EINVAL;
+			}
+			fh->jpg_buffers.active = zr->jpg_buffers.active =
+			    ZORAN_FREE;
+			zr->jpg_buffers.allocated = 0;
+			zr36057_enable_jpg(zr, BUZ_MODE_IDLE);
+			return 0;
+		} else {
+			dprintk(1,
+				KERN_ERR
+				"%s: jpg_qbuf() - stop streaming but not in streaming mode\n",
+				ZR_DEVNAME(zr));
+			return -EINVAL;
+		}
+	}
+
+	if ((res = zoran_jpg_queue_frame(file, frame, mode)))
+		return res;
+
+	/* Start the jpeg codec when the first frame is queued  */
+	if (!res && zr->jpg_que_head == 1)
+		jpeg_start(zr);
+
+	return res;
+}
+
+/*
+ *   Sync on a MJPEG buffer
+ */
+
+static int
+jpg_sync (struct file       *file,
+	  struct zoran_sync *bs)
+{
+	struct zoran_fh *fh = file->private_data;
+	struct zoran *zr = fh->zr;
+	unsigned long flags;
+	int frame;
+
+	if (fh->jpg_buffers.active == ZORAN_FREE) {
+		dprintk(1,
+			KERN_ERR
+			"%s: jpg_sync() - capture is not currently active\n",
+			ZR_DEVNAME(zr));
+		return -EINVAL;
+	}
+	if (zr->codec_mode != BUZ_MODE_MOTION_DECOMPRESS &&
+	    zr->codec_mode != BUZ_MODE_MOTION_COMPRESS) {
+		dprintk(1,
+			KERN_ERR
+			"%s: jpg_sync() - codec not in streaming mode\n",
+			ZR_DEVNAME(zr));
+		return -EINVAL;
+	}
+	if (!wait_event_interruptible_timeout(zr->jpg_capq,
+			(zr->jpg_que_tail != zr->jpg_dma_tail ||
+			 zr->jpg_dma_tail == zr->jpg_dma_head),
+			10*HZ)) {
+		int isr;
+
+		btand(~ZR36057_JMC_Go_en, ZR36057_JMC);
+		udelay(1);
+		zr->codec->control(zr->codec, CODEC_G_STATUS,
+					   sizeof(isr), &isr);
+		dprintk(1,
+			KERN_ERR
+			"%s: jpg_sync() - timeout: codec isr=0x%02x\n",
+			ZR_DEVNAME(zr), isr);
+
+		return -ETIME;
+
+	}
+	if (signal_pending(current))
+		return -ERESTARTSYS;
+
+	spin_lock_irqsave(&zr->spinlock, flags);
+
+	if (zr->jpg_dma_tail != zr->jpg_dma_head)
+		frame = zr->jpg_pend[zr->jpg_que_tail++ & BUZ_MASK_FRAME];
+	else
+		frame = zr->jpg_pend[zr->jpg_que_tail & BUZ_MASK_FRAME];
+
+	/* buffer should now be in BUZ_STATE_DONE */
+	if (zr->jpg_buffers.buffer[frame].state != BUZ_STATE_DONE)
+		dprintk(2,
+			KERN_ERR "%s: jpg_sync() - internal state error\n",
+			ZR_DEVNAME(zr));
+
+	*bs = zr->jpg_buffers.buffer[frame].bs;
+	bs->frame = frame;
+	zr->jpg_buffers.buffer[frame].state = BUZ_STATE_USER;
+	fh->jpg_buffers.buffer[frame] = zr->jpg_buffers.buffer[frame];
+
+	spin_unlock_irqrestore(&zr->spinlock, flags);
+
+	return 0;
+}
+
+static void
+zoran_open_init_session (struct file *file)
+{
+	int i;
+	struct zoran_fh *fh = file->private_data;
+	struct zoran *zr = fh->zr;
+
+	/* Per default, map the V4L Buffers */
+	fh->map_mode = ZORAN_MAP_MODE_RAW;
+
+	/* take over the card's current settings */
+	fh->overlay_settings = zr->overlay_settings;
+	fh->overlay_settings.is_set = 0;
+	fh->overlay_settings.format = zr->overlay_settings.format;
+	fh->overlay_active = ZORAN_FREE;
+
+	/* v4l settings */
+	fh->v4l_settings = zr->v4l_settings;
+
+	/* v4l_buffers */
+	memset(&fh->v4l_buffers, 0, sizeof(struct zoran_v4l_struct));
+	for (i = 0; i < VIDEO_MAX_FRAME; i++) {
+		fh->v4l_buffers.buffer[i].state = BUZ_STATE_USER;	/* nothing going on */
+		fh->v4l_buffers.buffer[i].bs.frame = i;
+	}
+	fh->v4l_buffers.allocated = 0;
+	fh->v4l_buffers.ready_to_be_freed = 0;
+	fh->v4l_buffers.active = ZORAN_FREE;
+	fh->v4l_buffers.buffer_size = v4l_bufsize;
+	fh->v4l_buffers.num_buffers = v4l_nbufs;
+
+	/* jpg settings */
+	fh->jpg_settings = zr->jpg_settings;
+
+	/* jpg_buffers */
+	memset(&fh->jpg_buffers, 0, sizeof(struct zoran_jpg_struct));
+	for (i = 0; i < BUZ_MAX_FRAME; i++) {
+		fh->jpg_buffers.buffer[i].state = BUZ_STATE_USER;	/* nothing going on */
+		fh->jpg_buffers.buffer[i].bs.frame = i;
+	}
+	fh->jpg_buffers.need_contiguous = zr->jpg_buffers.need_contiguous;
+	fh->jpg_buffers.allocated = 0;
+	fh->jpg_buffers.ready_to_be_freed = 0;
+	fh->jpg_buffers.active = ZORAN_FREE;
+	fh->jpg_buffers.buffer_size = jpg_bufsize;
+	fh->jpg_buffers.num_buffers = jpg_nbufs;
+}
+
+static void
+zoran_close_end_session (struct file *file)
+{
+	struct zoran_fh *fh = file->private_data;
+	struct zoran *zr = fh->zr;
+
+	/* overlay */
+	if (fh->overlay_active != ZORAN_FREE) {
+		fh->overlay_active = zr->overlay_active = ZORAN_FREE;
+		zr->v4l_overlay_active = 0;
+		if (!zr->v4l_memgrab_active)
+			zr36057_overlay(zr, 0);
+		zr->overlay_mask = NULL;
+	}
+
+	/* v4l capture */
+	if (fh->v4l_buffers.active != ZORAN_FREE) {
+		unsigned long flags;
+
+		spin_lock_irqsave(&zr->spinlock, flags);
+		zr36057_set_memgrab(zr, 0);
+		zr->v4l_buffers.allocated = 0;
+		zr->v4l_buffers.active = fh->v4l_buffers.active =
+		    ZORAN_FREE;
+		spin_unlock_irqrestore(&zr->spinlock, flags);
+	}
+
+	/* v4l buffers */
+	if (fh->v4l_buffers.allocated ||
+	    fh->v4l_buffers.ready_to_be_freed) {
+		v4l_fbuffer_free(file);
+	}
+
+	/* jpg capture */
+	if (fh->jpg_buffers.active != ZORAN_FREE) {
+		zr36057_enable_jpg(zr, BUZ_MODE_IDLE);
+		zr->jpg_buffers.allocated = 0;
+		zr->jpg_buffers.active = fh->jpg_buffers.active =
+		    ZORAN_FREE;
+	}
+
+	/* jpg buffers */
+	if (fh->jpg_buffers.allocated ||
+	    fh->jpg_buffers.ready_to_be_freed) {
+		jpg_fbuffer_free(file);
+	}
+}
+
+/*
+ *   Open a zoran card. Right now the flags stuff is just playing
+ */
+
+static int
+zoran_open (struct inode *inode,
+	    struct file  *file)
+{
+	unsigned int minor = iminor(inode);
+	struct zoran *zr = NULL;
+	struct zoran_fh *fh;
+	int i, res, first_open = 0, have_module_locks = 0;
+
+	lock_kernel();
+	/* find the device */
+	for (i = 0; i < zoran_num; i++) {
+		if (zoran[i]->video_dev->minor == minor) {
+			zr = zoran[i];
+			break;
+		}
+	}
+
+	if (!zr) {
+		dprintk(1, KERN_ERR "%s: device not found!\n", ZORAN_NAME);
+		res = -ENODEV;
+		goto open_unlock_and_return;
+	}
+
+	/* see fs/device.c - the kernel already locks during open(),
+	 * so locking ourselves only causes deadlocks */
+	/*mutex_lock(&zr->resource_lock);*/
+
+	if (!zr->decoder) {
+		dprintk(1,
+			KERN_ERR "%s: no TV decoder loaded for device!\n",
+			ZR_DEVNAME(zr));
+		res = -EIO;
+		goto open_unlock_and_return;
+	}
+
+	/* try to grab a module lock */
+	if (!try_module_get(THIS_MODULE)) {
+		dprintk(1,
+			KERN_ERR
+			"%s: failed to acquire my own lock! PANIC!\n",
+			ZR_DEVNAME(zr));
+		res = -ENODEV;
+		goto open_unlock_and_return;
+	}
+	if (!try_module_get(zr->decoder->driver->driver.owner)) {
+		dprintk(1,
+			KERN_ERR
+			"%s: failed to grab ownership of i2c decoder\n",
+			ZR_DEVNAME(zr));
+		res = -EIO;
+		module_put(THIS_MODULE);
+		goto open_unlock_and_return;
+	}
+	if (zr->encoder &&
+	    !try_module_get(zr->encoder->driver->driver.owner)) {
+		dprintk(1,
+			KERN_ERR
+			"%s: failed to grab ownership of i2c encoder\n",
+			ZR_DEVNAME(zr));
+		res = -EIO;
+		module_put(zr->decoder->driver->driver.owner);
+		module_put(THIS_MODULE);
+		goto open_unlock_and_return;
+	}
+
+	have_module_locks = 1;
+
+	if (zr->user >= 2048) {
+		dprintk(1, KERN_ERR "%s: too many users (%d) on device\n",
+			ZR_DEVNAME(zr), zr->user);
+		res = -EBUSY;
+		goto open_unlock_and_return;
+	}
+
+	dprintk(1, KERN_INFO "%s: zoran_open(%s, pid=[%d]), users(-)=%d\n",
+		ZR_DEVNAME(zr), current->comm, task_pid_nr(current), zr->user);
+
+	/* now, create the open()-specific file_ops struct */
+	fh = kzalloc(sizeof(struct zoran_fh), GFP_KERNEL);
+	if (!fh) {
+		dprintk(1,
+			KERN_ERR
+			"%s: zoran_open() - allocation of zoran_fh failed\n",
+			ZR_DEVNAME(zr));
+		res = -ENOMEM;
+		goto open_unlock_and_return;
+	}
+	/* used to be BUZ_MAX_WIDTH/HEIGHT, but that gives overflows
+	 * on norm-change! */
+	fh->overlay_mask =
+	    kmalloc(((768 + 31) / 32) * 576 * 4, GFP_KERNEL);
+	if (!fh->overlay_mask) {
+		dprintk(1,
+			KERN_ERR
+			"%s: zoran_open() - allocation of overlay_mask failed\n",
+			ZR_DEVNAME(zr));
+		kfree(fh);
+		res = -ENOMEM;
+		goto open_unlock_and_return;
+	}
+
+	if (zr->user++ == 0)
+		first_open = 1;
+
+	/*mutex_unlock(&zr->resource_lock);*/
+
+	/* default setup - TODO: look at flags */
+	if (first_open) {	/* First device open */
+		zr36057_restart(zr);
+		zoran_open_init_params(zr);
+		zoran_init_hardware(zr);
+
+		btor(ZR36057_ICR_IntPinEn, ZR36057_ICR);
+	}
+
+	/* set file_ops stuff */
+	file->private_data = fh;
+	fh->zr = zr;
+	zoran_open_init_session(file);
+	unlock_kernel();
+
+	return 0;
+
+open_unlock_and_return:
+	/* if we grabbed locks, release them accordingly */
+	if (have_module_locks) {
+		module_put(zr->decoder->driver->driver.owner);
+		if (zr->encoder) {
+			module_put(zr->encoder->driver->driver.owner);
+		}
+		module_put(THIS_MODULE);
+	}
+
+	/* if there's no device found, we didn't obtain the lock either */
+	if (zr) {
+		/*mutex_unlock(&zr->resource_lock);*/
+	}
+	unlock_kernel();
+
+	return res;
+}
+
+static int
+zoran_close (struct inode *inode,
+	     struct file  *file)
+{
+	struct zoran_fh *fh = file->private_data;
+	struct zoran *zr = fh->zr;
+
+	dprintk(1, KERN_INFO "%s: zoran_close(%s, pid=[%d]), users(+)=%d\n",
+		ZR_DEVNAME(zr), current->comm, task_pid_nr(current), zr->user);
+
+	/* kernel locks (fs/device.c), so don't do that ourselves
+	 * (prevents deadlocks) */
+	/*mutex_lock(&zr->resource_lock);*/
+
+	zoran_close_end_session(file);
+
+	if (zr->user-- == 1) {	/* Last process */
+		/* Clean up JPEG process */
+		wake_up_interruptible(&zr->jpg_capq);
+		zr36057_enable_jpg(zr, BUZ_MODE_IDLE);
+		zr->jpg_buffers.allocated = 0;
+		zr->jpg_buffers.active = ZORAN_FREE;
+
+		/* disable interrupts */
+		btand(~ZR36057_ICR_IntPinEn, ZR36057_ICR);
+
+		if (zr36067_debug > 1)
+			print_interrupts(zr);
+
+		/* Overlay off */
+		zr->v4l_overlay_active = 0;
+		zr36057_overlay(zr, 0);
+		zr->overlay_mask = NULL;
+
+		/* capture off */
+		wake_up_interruptible(&zr->v4l_capq);
+		zr36057_set_memgrab(zr, 0);
+		zr->v4l_buffers.allocated = 0;
+		zr->v4l_buffers.active = ZORAN_FREE;
+		zoran_set_pci_master(zr, 0);
+
+		if (!pass_through) {	/* Switch to color bar */
+			int zero = 0, two = 2;
+			decoder_command(zr, DECODER_ENABLE_OUTPUT, &zero);
+			encoder_command(zr, ENCODER_SET_INPUT, &two);
+		}
+	}
+
+	file->private_data = NULL;
+	kfree(fh->overlay_mask);
+	kfree(fh);
+
+	/* release locks on the i2c modules */
+	module_put(zr->decoder->driver->driver.owner);
+	if (zr->encoder) {
+		 module_put(zr->encoder->driver->driver.owner);
+	}
+	module_put(THIS_MODULE);
+
+	/*mutex_unlock(&zr->resource_lock);*/
+
+	dprintk(4, KERN_INFO "%s: zoran_close() done\n", ZR_DEVNAME(zr));
+
+	return 0;
+}
+
+
+static ssize_t
+zoran_read (struct file *file,
+	    char        __user *data,
+	    size_t       count,
+	    loff_t      *ppos)
+{
+	/* we simply don't support read() (yet)... */
+
+	return -EINVAL;
+}
+
+static ssize_t
+zoran_write (struct file *file,
+	     const char  __user *data,
+	     size_t       count,
+	     loff_t      *ppos)
+{
+	/* ...and the same goes for write() */
+
+	return -EINVAL;
+}
+
+static int
+setup_fbuffer (struct file               *file,
+	       void                      *base,
+	       const struct zoran_format *fmt,
+	       int                        width,
+	       int                        height,
+	       int                        bytesperline)
+{
+	struct zoran_fh *fh = file->private_data;
+	struct zoran *zr = fh->zr;
+
+	/* (Ronald) v4l/v4l2 guidelines */
+	if (!capable(CAP_SYS_ADMIN) && !capable(CAP_SYS_RAWIO))
+		return -EPERM;
+
+	/* Don't allow frame buffer overlay if PCI or AGP is buggy, or on
+	   ALi Magik (that needs very low latency while the card needs a
+	   higher value always) */
+
+	if (pci_pci_problems & (PCIPCI_FAIL | PCIAGP_FAIL | PCIPCI_ALIMAGIK))
+		return -ENXIO;
+
+	/* we need a bytesperline value, even if not given */
+	if (!bytesperline)
+		bytesperline = width * ((fmt->depth + 7) & ~7) / 8;
+
+#if 0
+	if (zr->overlay_active) {
+		/* dzjee... stupid users... don't even bother to turn off
+		 * overlay before changing the memory location...
+		 * normally, we would return errors here. However, one of
+		 * the tools that does this is... xawtv! and since xawtv
+		 * is used by +/- 99% of the users, we'd rather be user-
+		 * friendly and silently do as if nothing went wrong */
+		dprintk(3,
+			KERN_ERR
+			"%s: setup_fbuffer() - forced overlay turnoff because framebuffer changed\n",
+			ZR_DEVNAME(zr));
+		zr36057_overlay(zr, 0);
+	}
+#endif
+
+	if (!(fmt->flags & ZORAN_FORMAT_OVERLAY)) {
+		dprintk(1,
+			KERN_ERR
+			"%s: setup_fbuffer() - no valid overlay format given\n",
+			ZR_DEVNAME(zr));
+		return -EINVAL;
+	}
+	if (height <= 0 || width <= 0 || bytesperline <= 0) {
+		dprintk(1,
+			KERN_ERR
+			"%s: setup_fbuffer() - invalid height/width/bpl value (%d|%d|%d)\n",
+			ZR_DEVNAME(zr), width, height, bytesperline);
+		return -EINVAL;
+	}
+	if (bytesperline & 3) {
+		dprintk(1,
+			KERN_ERR
+			"%s: setup_fbuffer() - bytesperline (%d) must be 4-byte aligned\n",
+			ZR_DEVNAME(zr), bytesperline);
+		return -EINVAL;
+	}
+
+	zr->buffer.base = (void *) ((unsigned long) base & ~3);
+	zr->buffer.height = height;
+	zr->buffer.width = width;
+	zr->buffer.depth = fmt->depth;
+	zr->overlay_settings.format = fmt;
+	zr->buffer.bytesperline = bytesperline;
+
+	/* The user should set new window parameters */
+	zr->overlay_settings.is_set = 0;
+
+	return 0;
+}
+
+
+static int
+setup_window (struct file       *file,
+	      int                x,
+	      int                y,
+	      int                width,
+	      int                height,
+	      struct video_clip __user *clips,
+	      int                clipcount,
+	      void              __user *bitmap)
+{
+	struct zoran_fh *fh = file->private_data;
+	struct zoran *zr = fh->zr;
+	struct video_clip *vcp = NULL;
+	int on, end;
+
+
+	if (!zr->buffer.base) {
+		dprintk(1,
+			KERN_ERR
+			"%s: setup_window() - frame buffer has to be set first\n",
+			ZR_DEVNAME(zr));
+		return -EINVAL;
+	}
+
+	if (!fh->overlay_settings.format) {
+		dprintk(1,
+			KERN_ERR
+			"%s: setup_window() - no overlay format set\n",
+			ZR_DEVNAME(zr));
+		return -EINVAL;
+	}
+
+	/*
+	 * The video front end needs 4-byte alinged line sizes, we correct that
+	 * silently here if necessary
+	 */
+	if (zr->buffer.depth == 15 || zr->buffer.depth == 16) {
+		end = (x + width) & ~1;	/* round down */
+		x = (x + 1) & ~1;	/* round up */
+		width = end - x;
+	}
+
+	if (zr->buffer.depth == 24) {
+		end = (x + width) & ~3;	/* round down */
+		x = (x + 3) & ~3;	/* round up */
+		width = end - x;
+	}
+
+	if (width > BUZ_MAX_WIDTH)
+		width = BUZ_MAX_WIDTH;
+	if (height > BUZ_MAX_HEIGHT)
+		height = BUZ_MAX_HEIGHT;
+
+	/* Check for vaild parameters */
+	if (width < BUZ_MIN_WIDTH || height < BUZ_MIN_HEIGHT ||
+	    width > BUZ_MAX_WIDTH || height > BUZ_MAX_HEIGHT) {
+		dprintk(1,
+			KERN_ERR
+			"%s: setup_window() - width = %d or height = %d invalid\n",
+			ZR_DEVNAME(zr), width, height);
+		return -EINVAL;
+	}
+
+	fh->overlay_settings.x = x;
+	fh->overlay_settings.y = y;
+	fh->overlay_settings.width = width;
+	fh->overlay_settings.height = height;
+	fh->overlay_settings.clipcount = clipcount;
+
+	/*
+	 * If an overlay is running, we have to switch it off
+	 * and switch it on again in order to get the new settings in effect.
+	 *
+	 * We also want to avoid that the overlay mask is written
+	 * when an overlay is running.
+	 */
+
+	on = zr->v4l_overlay_active && !zr->v4l_memgrab_active &&
+	    zr->overlay_active != ZORAN_FREE &&
+	    fh->overlay_active != ZORAN_FREE;
+	if (on)
+		zr36057_overlay(zr, 0);
+
+	/*
+	 *   Write the overlay mask if clips are wanted.
+	 *   We prefer a bitmap.
+	 */
+	if (bitmap) {
+		/* fake value - it just means we want clips */
+		fh->overlay_settings.clipcount = 1;
+
+		if (copy_from_user(fh->overlay_mask, bitmap,
+				   (width * height + 7) / 8)) {
+			return -EFAULT;
+		}
+	} else if (clipcount > 0) {
+		/* write our own bitmap from the clips */
+		vcp = vmalloc(sizeof(struct video_clip) * (clipcount + 4));
+		if (vcp == NULL) {
+			dprintk(1,
+				KERN_ERR
+				"%s: setup_window() - Alloc of clip mask failed\n",
+				ZR_DEVNAME(zr));
+			return -ENOMEM;
+		}
+		if (copy_from_user
+		    (vcp, clips, sizeof(struct video_clip) * clipcount)) {
+			vfree(vcp);
+			return -EFAULT;
+		}
+		write_overlay_mask(file, vcp, clipcount);
+		vfree(vcp);
+	}
+
+	fh->overlay_settings.is_set = 1;
+	if (fh->overlay_active != ZORAN_FREE &&
+	    zr->overlay_active != ZORAN_FREE)
+		zr->overlay_settings = fh->overlay_settings;
+
+	if (on)
+		zr36057_overlay(zr, 1);
+
+	/* Make sure the changes come into effect */
+	return wait_grab_pending(zr);
+}
+
+static int
+setup_overlay (struct file *file,
+	       int          on)
+{
+	struct zoran_fh *fh = file->private_data;
+	struct zoran *zr = fh->zr;
+
+	/* If there is nothing to do, return immediatly */
+	if ((on && fh->overlay_active != ZORAN_FREE) ||
+	    (!on && fh->overlay_active == ZORAN_FREE))
+		return 0;
+
+	/* check whether we're touching someone else's overlay */
+	if (on && zr->overlay_active != ZORAN_FREE &&
+	    fh->overlay_active == ZORAN_FREE) {
+		dprintk(1,
+			KERN_ERR
+			"%s: setup_overlay() - overlay is already active for another session\n",
+			ZR_DEVNAME(zr));
+		return -EBUSY;
+	}
+	if (!on && zr->overlay_active != ZORAN_FREE &&
+	    fh->overlay_active == ZORAN_FREE) {
+		dprintk(1,
+			KERN_ERR
+			"%s: setup_overlay() - you cannot cancel someone else's session\n",
+			ZR_DEVNAME(zr));
+		return -EPERM;
+	}
+
+	if (on == 0) {
+		zr->overlay_active = fh->overlay_active = ZORAN_FREE;
+		zr->v4l_overlay_active = 0;
+		/* When a grab is running, the video simply
+		 * won't be switched on any more */
+		if (!zr->v4l_memgrab_active)
+			zr36057_overlay(zr, 0);
+		zr->overlay_mask = NULL;
+	} else {
+		if (!zr->buffer.base || !fh->overlay_settings.is_set) {
+			dprintk(1,
+				KERN_ERR
+				"%s: setup_overlay() - buffer or window not set\n",
+				ZR_DEVNAME(zr));
+			return -EINVAL;
+		}
+		if (!fh->overlay_settings.format) {
+			dprintk(1,
+				KERN_ERR
+				"%s: setup_overlay() - no overlay format set\n",
+				ZR_DEVNAME(zr));
+			return -EINVAL;
+		}
+		zr->overlay_active = fh->overlay_active = ZORAN_LOCKED;
+		zr->v4l_overlay_active = 1;
+		zr->overlay_mask = fh->overlay_mask;
+		zr->overlay_settings = fh->overlay_settings;
+		if (!zr->v4l_memgrab_active)
+			zr36057_overlay(zr, 1);
+		/* When a grab is running, the video will be
+		 * switched on when grab is finished */
+	}
+
+	/* Make sure the changes come into effect */
+	return wait_grab_pending(zr);
+}
+
+	/* get the status of a buffer in the clients buffer queue */
+static int
+zoran_v4l2_buffer_status (struct file        *file,
+			  struct v4l2_buffer *buf,
+			  int                 num)
+{
+	struct zoran_fh *fh = file->private_data;
+	struct zoran *zr = fh->zr;
+
+	buf->flags = V4L2_BUF_FLAG_MAPPED;
+
+	switch (fh->map_mode) {
+	case ZORAN_MAP_MODE_RAW:
+
+		/* check range */
+		if (num < 0 || num >= fh->v4l_buffers.num_buffers ||
+		    !fh->v4l_buffers.allocated) {
+			dprintk(1,
+				KERN_ERR
+				"%s: v4l2_buffer_status() - wrong number or buffers not allocated\n",
+				ZR_DEVNAME(zr));
+			return -EINVAL;
+		}
+
+		buf->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+		buf->length = fh->v4l_buffers.buffer_size;
+
+		/* get buffer */
+		buf->bytesused = fh->v4l_buffers.buffer[num].bs.length;
+		if (fh->v4l_buffers.buffer[num].state == BUZ_STATE_DONE ||
+		    fh->v4l_buffers.buffer[num].state == BUZ_STATE_USER) {
+			buf->sequence = fh->v4l_buffers.buffer[num].bs.seq;
+			buf->flags |= V4L2_BUF_FLAG_DONE;
+			buf->timestamp =
+			    fh->v4l_buffers.buffer[num].bs.timestamp;
+		} else {
+			buf->flags |= V4L2_BUF_FLAG_QUEUED;
+		}
+
+		if (fh->v4l_settings.height <= BUZ_MAX_HEIGHT / 2)
+			buf->field = V4L2_FIELD_TOP;
+		else
+			buf->field = V4L2_FIELD_INTERLACED;
+
+		break;
+
+	case ZORAN_MAP_MODE_JPG_REC:
+	case ZORAN_MAP_MODE_JPG_PLAY:
+
+		/* check range */
+		if (num < 0 || num >= fh->jpg_buffers.num_buffers ||
+		    !fh->jpg_buffers.allocated) {
+			dprintk(1,
+				KERN_ERR
+				"%s: v4l2_buffer_status() - wrong number or buffers not allocated\n",
+				ZR_DEVNAME(zr));
+			return -EINVAL;
+		}
+
+		buf->type = (fh->map_mode == ZORAN_MAP_MODE_JPG_REC) ?
+			      V4L2_BUF_TYPE_VIDEO_CAPTURE :
+			      V4L2_BUF_TYPE_VIDEO_OUTPUT;
+		buf->length = fh->jpg_buffers.buffer_size;
+
+		/* these variables are only written after frame has been captured */
+		if (fh->jpg_buffers.buffer[num].state == BUZ_STATE_DONE ||
+		    fh->jpg_buffers.buffer[num].state == BUZ_STATE_USER) {
+			buf->sequence = fh->jpg_buffers.buffer[num].bs.seq;
+			buf->timestamp =
+			    fh->jpg_buffers.buffer[num].bs.timestamp;
+			buf->bytesused =
+			    fh->jpg_buffers.buffer[num].bs.length;
+			buf->flags |= V4L2_BUF_FLAG_DONE;
+		} else {
+			buf->flags |= V4L2_BUF_FLAG_QUEUED;
+		}
+
+		/* which fields are these? */
+		if (fh->jpg_settings.TmpDcm != 1)
+			buf->field =
+			    fh->jpg_settings.
+			    odd_even ? V4L2_FIELD_TOP : V4L2_FIELD_BOTTOM;
+		else
+			buf->field =
+			    fh->jpg_settings.
+			    odd_even ? V4L2_FIELD_SEQ_TB :
+			    V4L2_FIELD_SEQ_BT;
+
+		break;
+
+	default:
+
+		dprintk(5,
+			KERN_ERR
+			"%s: v4l2_buffer_status() - invalid buffer type|map_mode (%d|%d)\n",
+			ZR_DEVNAME(zr), buf->type, fh->map_mode);
+		return -EINVAL;
+	}
+
+	buf->memory = V4L2_MEMORY_MMAP;
+	buf->index = num;
+	buf->m.offset = buf->length * num;
+
+	return 0;
+}
+
+static int
+zoran_set_norm (struct zoran *zr,
+		int           norm) /* VIDEO_MODE_* */
+{
+	int norm_encoder, on;
+
+	if (zr->v4l_buffers.active != ZORAN_FREE ||
+	    zr->jpg_buffers.active != ZORAN_FREE) {
+		dprintk(1,
+			KERN_WARNING
+			"%s: set_norm() called while in playback/capture mode\n",
+			ZR_DEVNAME(zr));
+		return -EBUSY;
+	}
+
+	if (lock_norm && norm != zr->norm) {
+		if (lock_norm > 1) {
+			dprintk(1,
+				KERN_WARNING
+				"%s: set_norm() - TV standard is locked, can not switch norm\n",
+				ZR_DEVNAME(zr));
+			return -EPERM;
+		} else {
+			dprintk(1,
+				KERN_WARNING
+				"%s: set_norm() - TV standard is locked, norm was not changed\n",
+				ZR_DEVNAME(zr));
+			norm = zr->norm;
+		}
+	}
+
+	if (norm != VIDEO_MODE_AUTO &&
+	    (norm < 0 || norm >= zr->card.norms ||
+	     !zr->card.tvn[norm])) {
+		dprintk(1,
+			KERN_ERR "%s: set_norm() - unsupported norm %d\n",
+			ZR_DEVNAME(zr), norm);
+		return -EINVAL;
+	}
+
+	if (norm == VIDEO_MODE_AUTO) {
+		int status;
+
+		/* if we have autodetect, ... */
+		struct video_decoder_capability caps;
+		decoder_command(zr, DECODER_GET_CAPABILITIES, &caps);
+		if (!(caps.flags & VIDEO_DECODER_AUTO)) {
+			dprintk(1, KERN_ERR "%s: norm=auto unsupported\n",
+				ZR_DEVNAME(zr));
+			return -EINVAL;
+		}
+
+		decoder_command(zr, DECODER_SET_NORM, &norm);
+
+		/* let changes come into effect */
+		ssleep(2);
+
+		decoder_command(zr, DECODER_GET_STATUS, &status);
+		if (!(status & DECODER_STATUS_GOOD)) {
+			dprintk(1,
+				KERN_ERR
+				"%s: set_norm() - no norm detected\n",
+				ZR_DEVNAME(zr));
+			/* reset norm */
+			decoder_command(zr, DECODER_SET_NORM, &zr->norm);
+			return -EIO;
+		}
+
+		if (status & DECODER_STATUS_NTSC)
+			norm = VIDEO_MODE_NTSC;
+		else if (status & DECODER_STATUS_SECAM)
+			norm = VIDEO_MODE_SECAM;
+		else
+			norm = VIDEO_MODE_PAL;
+	}
+	zr->timing = zr->card.tvn[norm];
+	norm_encoder = norm;
+
+	/* We switch overlay off and on since a change in the
+	 * norm needs different VFE settings */
+	on = zr->overlay_active && !zr->v4l_memgrab_active;
+	if (on)
+		zr36057_overlay(zr, 0);
+
+	decoder_command(zr, DECODER_SET_NORM, &norm);
+	encoder_command(zr, ENCODER_SET_NORM, &norm_encoder);
+
+	if (on)
+		zr36057_overlay(zr, 1);
+
+	/* Make sure the changes come into effect */
+	zr->norm = norm;
+
+	return 0;
+}
+
+static int
+zoran_set_input (struct zoran *zr,
+		 int           input)
+{
+	int realinput;
+
+	if (input == zr->input) {
+		return 0;
+	}
+
+	if (zr->v4l_buffers.active != ZORAN_FREE ||
+	    zr->jpg_buffers.active != ZORAN_FREE) {
+		dprintk(1,
+			KERN_WARNING
+			"%s: set_input() called while in playback/capture mode\n",
+			ZR_DEVNAME(zr));
+		return -EBUSY;
+	}
+
+	if (input < 0 || input >= zr->card.inputs) {
+		dprintk(1,
+			KERN_ERR
+			"%s: set_input() - unnsupported input %d\n",
+			ZR_DEVNAME(zr), input);
+		return -EINVAL;
+	}
+
+	realinput = zr->card.input[input].muxsel;
+	zr->input = input;
+
+	decoder_command(zr, DECODER_SET_INPUT, &realinput);
+
+	return 0;
+}
+
+/*
+ *   ioctl routine
+ */
+
+static int
+zoran_do_ioctl (struct inode *inode,
+		struct file  *file,
+		unsigned int  cmd,
+		void         *arg)
+{
+	struct zoran_fh *fh = file->private_data;
+	struct zoran *zr = fh->zr;
+	/* CAREFUL: used in multiple places here */
+	struct zoran_jpg_settings settings;
+
+	/* we might have older buffers lying around... We don't want
+	 * to wait, but we do want to try cleaning them up ASAP. So
+	 * we try to obtain the lock and free them. If that fails, we
+	 * don't do anything and wait for the next turn. In the end,
+	 * zoran_close() or a new allocation will still free them...
+	 * This is just a 'the sooner the better' extra 'feature'
+	 *
+	 * We don't free the buffers right on munmap() because that
+	 * causes oopses (kfree() inside munmap() oopses for no
+	 * apparent reason - it's also not reproduceable in any way,
+	 * but moving the free code outside the munmap() handler fixes
+	 * all this... If someone knows why, please explain me (Ronald)
+	 */
+	if (mutex_trylock(&zr->resource_lock)) {
+		/* we obtained it! Let's try to free some things */
+		if (fh->jpg_buffers.ready_to_be_freed)
+			jpg_fbuffer_free(file);
+		if (fh->v4l_buffers.ready_to_be_freed)
+			v4l_fbuffer_free(file);
+
+		mutex_unlock(&zr->resource_lock);
+	}
+
+	switch (cmd) {
+
+	case VIDIOCGCAP:
+	{
+		struct video_capability *vcap = arg;
+
+		dprintk(3, KERN_DEBUG "%s: VIDIOCGCAP\n", ZR_DEVNAME(zr));
+
+		memset(vcap, 0, sizeof(struct video_capability));
+		strncpy(vcap->name, ZR_DEVNAME(zr), sizeof(vcap->name)-1);
+		vcap->type = ZORAN_VID_TYPE;
+
+		vcap->channels = zr->card.inputs;
+		vcap->audios = 0;
+		mutex_lock(&zr->resource_lock);
+		vcap->maxwidth = BUZ_MAX_WIDTH;
+		vcap->maxheight = BUZ_MAX_HEIGHT;
+		vcap->minwidth = BUZ_MIN_WIDTH;
+		vcap->minheight = BUZ_MIN_HEIGHT;
+		mutex_unlock(&zr->resource_lock);
+
+		return 0;
+	}
+		break;
+
+	case VIDIOCGCHAN:
+	{
+		struct video_channel *vchan = arg;
+		int channel = vchan->channel;
+
+		dprintk(3, KERN_DEBUG "%s: VIDIOCGCHAN - channel=%d\n",
+			ZR_DEVNAME(zr), vchan->channel);
+
+		memset(vchan, 0, sizeof(struct video_channel));
+		if (channel > zr->card.inputs || channel < 0) {
+			dprintk(1,
+				KERN_ERR
+				"%s: VIDIOCGCHAN on not existing channel %d\n",
+				ZR_DEVNAME(zr), channel);
+			return -EINVAL;
+		}
+
+		strcpy(vchan->name, zr->card.input[channel].name);
+
+		vchan->tuners = 0;
+		vchan->flags = 0;
+		vchan->type = VIDEO_TYPE_CAMERA;
+		mutex_lock(&zr->resource_lock);
+		vchan->norm = zr->norm;
+		mutex_unlock(&zr->resource_lock);
+		vchan->channel = channel;
+
+		return 0;
+	}
+		break;
+
+		/* RJ: the documentation at http://roadrunner.swansea.linux.org.uk/v4lapi.shtml says:
+		 *
+		 * * "The VIDIOCSCHAN ioctl takes an integer argument and switches the capture to this input."
+		 * *                                 ^^^^^^^
+		 * * The famos BTTV driver has it implemented with a struct video_channel argument
+		 * * and we follow it for compatibility reasons
+		 * *
+		 * * BTW: this is the only way the user can set the norm!
+		 */
+
+	case VIDIOCSCHAN:
+	{
+		struct video_channel *vchan = arg;
+		int res;
+
+		dprintk(3,
+			KERN_DEBUG
+			"%s: VIDIOCSCHAN - channel=%d, norm=%d\n",
+			ZR_DEVNAME(zr), vchan->channel, vchan->norm);
+
+		mutex_lock(&zr->resource_lock);
+		if ((res = zoran_set_input(zr, vchan->channel)))
+			goto schan_unlock_and_return;
+		if ((res = zoran_set_norm(zr, vchan->norm)))
+			goto schan_unlock_and_return;
+
+		/* Make sure the changes come into effect */
+		res = wait_grab_pending(zr);
+	schan_unlock_and_return:
+		mutex_unlock(&zr->resource_lock);
+		return res;
+	}
+		break;
+
+	case VIDIOCGPICT:
+	{
+		struct video_picture *vpict = arg;
+
+		dprintk(3, KERN_DEBUG "%s: VIDIOCGPICT\n", ZR_DEVNAME(zr));
+
+		memset(vpict, 0, sizeof(struct video_picture));
+		mutex_lock(&zr->resource_lock);
+		vpict->hue = zr->hue;
+		vpict->brightness = zr->brightness;
+		vpict->contrast = zr->contrast;
+		vpict->colour = zr->saturation;
+		if (fh->overlay_settings.format) {
+			vpict->depth = fh->overlay_settings.format->depth;
+			vpict->palette = fh->overlay_settings.format->palette;
+		} else {
+			vpict->depth = 0;
+		}
+		mutex_unlock(&zr->resource_lock);
+
+		return 0;
+	}
+		break;
+
+	case VIDIOCSPICT:
+	{
+		struct video_picture *vpict = arg;
+		int i;
+
+		dprintk(3,
+			KERN_DEBUG
+			"%s: VIDIOCSPICT - bri=%d, hue=%d, col=%d, con=%d, dep=%d, pal=%d\n",
+			ZR_DEVNAME(zr), vpict->brightness, vpict->hue,
+			vpict->colour, vpict->contrast, vpict->depth,
+			vpict->palette);
+
+		for (i = 0; i < NUM_FORMATS; i++) {
+			const struct zoran_format *fmt = &zoran_formats[i];
+
+			if (fmt->palette != -1 &&
+			    fmt->flags & ZORAN_FORMAT_OVERLAY &&
+			    fmt->palette == vpict->palette &&
+			    fmt->depth == vpict->depth)
+				break;
+		}
+		if (i == NUM_FORMATS) {
+			dprintk(1,
+				KERN_ERR
+				"%s: VIDIOCSPICT - Invalid palette %d\n",
+				ZR_DEVNAME(zr), vpict->palette);
+			return -EINVAL;
+		}
+
+		mutex_lock(&zr->resource_lock);
+
+		decoder_command(zr, DECODER_SET_PICTURE, vpict);
+
+		zr->hue = vpict->hue;
+		zr->contrast = vpict->contrast;
+		zr->saturation = vpict->colour;
+		zr->brightness = vpict->brightness;
+
+		fh->overlay_settings.format = &zoran_formats[i];
+
+		mutex_unlock(&zr->resource_lock);
+
+		return 0;
+	}
+		break;
+
+	case VIDIOCCAPTURE:
+	{
+		int *on = arg, res;
+
+		dprintk(3, KERN_DEBUG "%s: VIDIOCCAPTURE - on=%d\n",
+			ZR_DEVNAME(zr), *on);
+
+		mutex_lock(&zr->resource_lock);
+		res = setup_overlay(file, *on);
+		mutex_unlock(&zr->resource_lock);
+
+		return res;
+	}
+		break;
+
+	case VIDIOCGWIN:
+	{
+		struct video_window *vwin = arg;
+
+		dprintk(3, KERN_DEBUG "%s: VIDIOCGWIN\n", ZR_DEVNAME(zr));
+
+		memset(vwin, 0, sizeof(struct video_window));
+		mutex_lock(&zr->resource_lock);
+		vwin->x = fh->overlay_settings.x;
+		vwin->y = fh->overlay_settings.y;
+		vwin->width = fh->overlay_settings.width;
+		vwin->height = fh->overlay_settings.height;
+		mutex_unlock(&zr->resource_lock);
+		vwin->clipcount = 0;
+		return 0;
+	}
+		break;
+
+	case VIDIOCSWIN:
+	{
+		struct video_window *vwin = arg;
+		int res;
+
+		dprintk(3,
+			KERN_DEBUG
+			"%s: VIDIOCSWIN - x=%d, y=%d, w=%d, h=%d, clipcount=%d\n",
+			ZR_DEVNAME(zr), vwin->x, vwin->y, vwin->width,
+			vwin->height, vwin->clipcount);
+
+		mutex_lock(&zr->resource_lock);
+		res =
+		    setup_window(file, vwin->x, vwin->y, vwin->width,
+				 vwin->height, vwin->clips,
+				 vwin->clipcount, NULL);
+		mutex_unlock(&zr->resource_lock);
+
+		return res;
+	}
+		break;
+
+	case VIDIOCGFBUF:
+	{
+		struct video_buffer *vbuf = arg;
+
+		dprintk(3, KERN_DEBUG "%s: VIDIOCGFBUF\n", ZR_DEVNAME(zr));
+
+		mutex_lock(&zr->resource_lock);
+		*vbuf = zr->buffer;
+		mutex_unlock(&zr->resource_lock);
+		return 0;
+	}
+		break;
+
+	case VIDIOCSFBUF:
+	{
+		struct video_buffer *vbuf = arg;
+		int i, res = 0;
+
+		dprintk(3,
+			KERN_DEBUG
+			"%s: VIDIOCSFBUF - base=%p, w=%d, h=%d, depth=%d, bpl=%d\n",
+			ZR_DEVNAME(zr), vbuf->base, vbuf->width,
+			vbuf->height, vbuf->depth, vbuf->bytesperline);
+
+		for (i = 0; i < NUM_FORMATS; i++)
+			if (zoran_formats[i].depth == vbuf->depth)
+				break;
+		if (i == NUM_FORMATS) {
+			dprintk(1,
+				KERN_ERR
+				"%s: VIDIOCSFBUF - invalid fbuf depth %d\n",
+				ZR_DEVNAME(zr), vbuf->depth);
+			return -EINVAL;
+		}
+
+		mutex_lock(&zr->resource_lock);
+		res =
+		    setup_fbuffer(file, vbuf->base, &zoran_formats[i],
+				  vbuf->width, vbuf->height,
+				  vbuf->bytesperline);
+		mutex_unlock(&zr->resource_lock);
+
+		return res;
+	}
+		break;
+
+	case VIDIOCSYNC:
+	{
+		int *frame = arg, res;
+
+		dprintk(3, KERN_DEBUG "%s: VIDIOCSYNC - frame=%d\n",
+			ZR_DEVNAME(zr), *frame);
+
+		mutex_lock(&zr->resource_lock);
+		res = v4l_sync(file, *frame);
+		mutex_unlock(&zr->resource_lock);
+		if (!res)
+			zr->v4l_sync_tail++;
+		return res;
+	}
+		break;
+
+	case VIDIOCMCAPTURE:
+	{
+		struct video_mmap *vmap = arg;
+		int res;
+
+		dprintk(3,
+			KERN_DEBUG
+			"%s: VIDIOCMCAPTURE - frame=%d, geom=%dx%d, fmt=%d\n",
+			ZR_DEVNAME(zr), vmap->frame, vmap->width, vmap->height,
+			vmap->format);
+
+		mutex_lock(&zr->resource_lock);
+		res = v4l_grab(file, vmap);
+		mutex_unlock(&zr->resource_lock);
+		return res;
+	}
+		break;
+
+	case VIDIOCGMBUF:
+	{
+		struct video_mbuf *vmbuf = arg;
+		int i, res = 0;
+
+		dprintk(3, KERN_DEBUG "%s: VIDIOCGMBUF\n", ZR_DEVNAME(zr));
+
+		vmbuf->size =
+		    fh->v4l_buffers.num_buffers *
+		    fh->v4l_buffers.buffer_size;
+		vmbuf->frames = fh->v4l_buffers.num_buffers;
+		for (i = 0; i < vmbuf->frames; i++) {
+			vmbuf->offsets[i] =
+			    i * fh->v4l_buffers.buffer_size;
+		}
+
+		mutex_lock(&zr->resource_lock);
+
+		if (fh->jpg_buffers.allocated || fh->v4l_buffers.allocated) {
+			dprintk(1,
+				KERN_ERR
+				"%s: VIDIOCGMBUF - buffers already allocated\n",
+				ZR_DEVNAME(zr));
+			res = -EINVAL;
+			goto v4l1reqbuf_unlock_and_return;
+		}
+
+		if (v4l_fbuffer_alloc(file)) {
+			res = -ENOMEM;
+			goto v4l1reqbuf_unlock_and_return;
+		}
+
+		/* The next mmap will map the V4L buffers */
+		fh->map_mode = ZORAN_MAP_MODE_RAW;
+	v4l1reqbuf_unlock_and_return:
+		mutex_unlock(&zr->resource_lock);
+
+		return res;
+	}
+		break;
+
+	case VIDIOCGUNIT:
+	{
+		struct video_unit *vunit = arg;
+
+		dprintk(3, KERN_DEBUG "%s: VIDIOCGUNIT\n", ZR_DEVNAME(zr));
+
+		vunit->video = zr->video_dev->minor;
+		vunit->vbi = VIDEO_NO_UNIT;
+		vunit->radio = VIDEO_NO_UNIT;
+		vunit->audio = VIDEO_NO_UNIT;
+		vunit->teletext = VIDEO_NO_UNIT;
+
+		return 0;
+	}
+		break;
+
+		/*
+		 * RJ: In principal we could support subcaptures for V4L grabbing.
+		 *     Not even the famous BTTV driver has them, however.
+		 *     If there should be a strong demand, one could consider
+		 *     to implement them.
+		 */
+	case VIDIOCGCAPTURE:
+	{
+		dprintk(3, KERN_ERR "%s: VIDIOCGCAPTURE not supported\n",
+			ZR_DEVNAME(zr));
+		return -EINVAL;
+	}
+		break;
+
+	case VIDIOCSCAPTURE:
+	{
+		dprintk(3, KERN_ERR "%s: VIDIOCSCAPTURE not supported\n",
+			ZR_DEVNAME(zr));
+		return -EINVAL;
+	}
+		break;
+
+	case BUZIOC_G_PARAMS:
+	{
+		struct zoran_params *bparams = arg;
+
+		dprintk(3, KERN_DEBUG "%s: BUZIOC_G_PARAMS\n", ZR_DEVNAME(zr));
+
+		memset(bparams, 0, sizeof(struct zoran_params));
+		bparams->major_version = MAJOR_VERSION;
+		bparams->minor_version = MINOR_VERSION;
+
+		mutex_lock(&zr->resource_lock);
+
+		bparams->norm = zr->norm;
+		bparams->input = zr->input;
+
+		bparams->decimation = fh->jpg_settings.decimation;
+		bparams->HorDcm = fh->jpg_settings.HorDcm;
+		bparams->VerDcm = fh->jpg_settings.VerDcm;
+		bparams->TmpDcm = fh->jpg_settings.TmpDcm;
+		bparams->field_per_buff = fh->jpg_settings.field_per_buff;
+		bparams->img_x = fh->jpg_settings.img_x;
+		bparams->img_y = fh->jpg_settings.img_y;
+		bparams->img_width = fh->jpg_settings.img_width;
+		bparams->img_height = fh->jpg_settings.img_height;
+		bparams->odd_even = fh->jpg_settings.odd_even;
+
+		bparams->quality = fh->jpg_settings.jpg_comp.quality;
+		bparams->APPn = fh->jpg_settings.jpg_comp.APPn;
+		bparams->APP_len = fh->jpg_settings.jpg_comp.APP_len;
+		memcpy(bparams->APP_data,
+		       fh->jpg_settings.jpg_comp.APP_data,
+		       sizeof(bparams->APP_data));
+		bparams->COM_len = zr->jpg_settings.jpg_comp.COM_len;
+		memcpy(bparams->COM_data,
+		       fh->jpg_settings.jpg_comp.COM_data,
+		       sizeof(bparams->COM_data));
+		bparams->jpeg_markers =
+		    fh->jpg_settings.jpg_comp.jpeg_markers;
+
+		mutex_unlock(&zr->resource_lock);
+
+		bparams->VFIFO_FB = 0;
+
+		return 0;
+	}
+		break;
+
+	case BUZIOC_S_PARAMS:
+	{
+		struct zoran_params *bparams = arg;
+		int res = 0;
+
+		dprintk(3, KERN_DEBUG "%s: BUZIOC_S_PARAMS\n", ZR_DEVNAME(zr));
+
+		settings.decimation = bparams->decimation;
+		settings.HorDcm = bparams->HorDcm;
+		settings.VerDcm = bparams->VerDcm;
+		settings.TmpDcm = bparams->TmpDcm;
+		settings.field_per_buff = bparams->field_per_buff;
+		settings.img_x = bparams->img_x;
+		settings.img_y = bparams->img_y;
+		settings.img_width = bparams->img_width;
+		settings.img_height = bparams->img_height;
+		settings.odd_even = bparams->odd_even;
+
+		settings.jpg_comp.quality = bparams->quality;
+		settings.jpg_comp.APPn = bparams->APPn;
+		settings.jpg_comp.APP_len = bparams->APP_len;
+		memcpy(settings.jpg_comp.APP_data, bparams->APP_data,
+		       sizeof(bparams->APP_data));
+		settings.jpg_comp.COM_len = bparams->COM_len;
+		memcpy(settings.jpg_comp.COM_data, bparams->COM_data,
+		       sizeof(bparams->COM_data));
+		settings.jpg_comp.jpeg_markers = bparams->jpeg_markers;
+
+		mutex_lock(&zr->resource_lock);
+
+		if (zr->codec_mode != BUZ_MODE_IDLE) {
+			dprintk(1,
+				KERN_ERR
+				"%s: BUZIOC_S_PARAMS called, but Buz in capture/playback mode\n",
+				ZR_DEVNAME(zr));
+			res = -EINVAL;
+			goto sparams_unlock_and_return;
+		}
+
+		/* Check the params first before overwriting our
+		 * nternal values */
+		if (zoran_check_jpg_settings(zr, &settings)) {
+			res = -EINVAL;
+			goto sparams_unlock_and_return;
+		}
+
+		fh->jpg_settings = settings;
+	sparams_unlock_and_return:
+		mutex_unlock(&zr->resource_lock);
+
+		return res;
+	}
+		break;
+
+	case BUZIOC_REQBUFS:
+	{
+		struct zoran_requestbuffers *breq = arg;
+		int res = 0;
+
+		dprintk(3,
+			KERN_DEBUG
+			"%s: BUZIOC_REQBUFS - count=%lu, size=%lu\n",
+			ZR_DEVNAME(zr), breq->count, breq->size);
+
+		/* Enforce reasonable lower and upper limits */
+		if (breq->count < 4)
+			breq->count = 4;	/* Could be choosen smaller */
+		if (breq->count > jpg_nbufs)
+			breq->count = jpg_nbufs;
+		breq->size = PAGE_ALIGN(breq->size);
+		if (breq->size < 8192)
+			breq->size = 8192;	/* Arbitrary */
+		/* breq->size is limited by 1 page for the stat_com
+		 * tables to a Maximum of 2 MB */
+		if (breq->size > jpg_bufsize)
+			breq->size = jpg_bufsize;
+		if (fh->jpg_buffers.need_contiguous &&
+		    breq->size > MAX_KMALLOC_MEM)
+			breq->size = MAX_KMALLOC_MEM;
+
+		mutex_lock(&zr->resource_lock);
+
+		if (fh->jpg_buffers.allocated || fh->v4l_buffers.allocated) {
+			dprintk(1,
+				KERN_ERR
+				"%s: BUZIOC_REQBUFS - buffers allready allocated\n",
+				ZR_DEVNAME(zr));
+			res = -EBUSY;
+			goto jpgreqbuf_unlock_and_return;
+		}
+
+		fh->jpg_buffers.num_buffers = breq->count;
+		fh->jpg_buffers.buffer_size = breq->size;
+
+		if (jpg_fbuffer_alloc(file)) {
+			res = -ENOMEM;
+			goto jpgreqbuf_unlock_and_return;
+		}
+
+		/* The next mmap will map the MJPEG buffers - could
+		 * also be *_PLAY, but it doesn't matter here */
+		fh->map_mode = ZORAN_MAP_MODE_JPG_REC;
+	jpgreqbuf_unlock_and_return:
+		mutex_unlock(&zr->resource_lock);
+
+		return res;
+	}
+		break;
+
+	case BUZIOC_QBUF_CAPT:
+	{
+		int *frame = arg, res;
+
+		dprintk(3, KERN_DEBUG "%s: BUZIOC_QBUF_CAPT - frame=%d\n",
+			ZR_DEVNAME(zr), *frame);
+
+		mutex_lock(&zr->resource_lock);
+		res = jpg_qbuf(file, *frame, BUZ_MODE_MOTION_COMPRESS);
+		mutex_unlock(&zr->resource_lock);
+
+		return res;
+	}
+		break;
+
+	case BUZIOC_QBUF_PLAY:
+	{
+		int *frame = arg, res;
+
+		dprintk(3, KERN_DEBUG "%s: BUZIOC_QBUF_PLAY - frame=%d\n",
+			ZR_DEVNAME(zr), *frame);
+
+		mutex_lock(&zr->resource_lock);
+		res = jpg_qbuf(file, *frame, BUZ_MODE_MOTION_DECOMPRESS);
+		mutex_unlock(&zr->resource_lock);
+
+		return res;
+	}
+		break;
+
+	case BUZIOC_SYNC:
+	{
+		struct zoran_sync *bsync = arg;
+		int res;
+
+		dprintk(3, KERN_DEBUG "%s: BUZIOC_SYNC\n", ZR_DEVNAME(zr));
+
+		mutex_lock(&zr->resource_lock);
+		res = jpg_sync(file, bsync);
+		mutex_unlock(&zr->resource_lock);
+
+		return res;
+	}
+		break;
+
+	case BUZIOC_G_STATUS:
+	{
+		struct zoran_status *bstat = arg;
+		int norm, input, status, res = 0;
+
+		dprintk(3, KERN_DEBUG "%s: BUZIOC_G_STATUS\n", ZR_DEVNAME(zr));
+
+		if (zr->codec_mode != BUZ_MODE_IDLE) {
+			dprintk(1,
+				KERN_ERR
+				"%s: BUZIOC_G_STATUS called but Buz in capture/playback mode\n",
+				ZR_DEVNAME(zr));
+			return -EINVAL;
+		}
+
+		input = zr->card.input[bstat->input].muxsel;
+		norm = VIDEO_MODE_AUTO;
+
+		mutex_lock(&zr->resource_lock);
+
+		if (zr->codec_mode != BUZ_MODE_IDLE) {
+			dprintk(1,
+				KERN_ERR
+				"%s: BUZIOC_G_STATUS called, but Buz in capture/playback mode\n",
+				ZR_DEVNAME(zr));
+			res = -EINVAL;
+			goto gstat_unlock_and_return;
+		}
+
+		decoder_command(zr, DECODER_SET_INPUT, &input);
+		decoder_command(zr, DECODER_SET_NORM, &norm);
+
+		/* sleep 1 second */
+		ssleep(1);
+
+		/* Get status of video decoder */
+		decoder_command(zr, DECODER_GET_STATUS, &status);
+
+		/* restore previous input and norm */
+		input = zr->card.input[zr->input].muxsel;
+		decoder_command(zr, DECODER_SET_INPUT, &input);
+		decoder_command(zr, DECODER_SET_NORM, &zr->norm);
+	gstat_unlock_and_return:
+		mutex_unlock(&zr->resource_lock);
+
+		if (!res) {
+			bstat->signal =
+			    (status & DECODER_STATUS_GOOD) ? 1 : 0;
+			if (status & DECODER_STATUS_NTSC)
+				bstat->norm = VIDEO_MODE_NTSC;
+			else if (status & DECODER_STATUS_SECAM)
+				bstat->norm = VIDEO_MODE_SECAM;
+			else
+				bstat->norm = VIDEO_MODE_PAL;
+
+			bstat->color =
+			    (status & DECODER_STATUS_COLOR) ? 1 : 0;
+		}
+
+		return res;
+	}
+		break;
+
+		/* The new video4linux2 capture interface - much nicer than video4linux1, since
+		 * it allows for integrating the JPEG capturing calls inside standard v4l2
+		 */
+
+	case VIDIOC_QUERYCAP:
+	{
+		struct v4l2_capability *cap = arg;
+
+		dprintk(3, KERN_DEBUG "%s: VIDIOC_QUERYCAP\n", ZR_DEVNAME(zr));
+
+		memset(cap, 0, sizeof(*cap));
+		strncpy(cap->card, ZR_DEVNAME(zr), sizeof(cap->card)-1);
+		strncpy(cap->driver, "zoran", sizeof(cap->driver)-1);
+		snprintf(cap->bus_info, sizeof(cap->bus_info), "PCI:%s",
+			 pci_name(zr->pci_dev));
+		cap->version =
+		    KERNEL_VERSION(MAJOR_VERSION, MINOR_VERSION,
+				   RELEASE_VERSION);
+		cap->capabilities = ZORAN_V4L2_VID_FLAGS;
+
+		return 0;
+	}
+		break;
+
+	case VIDIOC_ENUM_FMT:
+	{
+		struct v4l2_fmtdesc *fmt = arg;
+		int index = fmt->index, num = -1, i, flag = 0, type =
+		    fmt->type;
+
+		dprintk(3, KERN_DEBUG "%s: VIDIOC_ENUM_FMT - index=%d\n",
+			ZR_DEVNAME(zr), fmt->index);
+
+		switch (fmt->type) {
+		case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+			flag = ZORAN_FORMAT_CAPTURE;
+			break;
+		case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+			flag = ZORAN_FORMAT_PLAYBACK;
+			break;
+		case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+			flag = ZORAN_FORMAT_OVERLAY;
+			break;
+		default:
+			dprintk(1,
+				KERN_ERR
+				"%s: VIDIOC_ENUM_FMT - unknown type %d\n",
+				ZR_DEVNAME(zr), fmt->type);
+			return -EINVAL;
+		}
+
+		for (i = 0; i < NUM_FORMATS; i++) {
+			if (zoran_formats[i].flags & flag)
+				num++;
+			if (num == fmt->index)
+				break;
+		}
+		if (fmt->index < 0 /* late, but not too late */  ||
+		    i == NUM_FORMATS)
+			return -EINVAL;
+
+		memset(fmt, 0, sizeof(*fmt));
+		fmt->index = index;
+		fmt->type = type;
+		strncpy(fmt->description, zoran_formats[i].name, sizeof(fmt->description)-1);
+		fmt->pixelformat = zoran_formats[i].fourcc;
+		if (zoran_formats[i].flags & ZORAN_FORMAT_COMPRESSED)
+			fmt->flags |= V4L2_FMT_FLAG_COMPRESSED;
+
+		return 0;
+	}
+		break;
+
+	case VIDIOC_G_FMT:
+	{
+		struct v4l2_format *fmt = arg;
+		int type = fmt->type;
+
+		dprintk(5, KERN_DEBUG "%s: VIDIOC_G_FMT\n", ZR_DEVNAME(zr));
+
+		memset(fmt, 0, sizeof(*fmt));
+		fmt->type = type;
+
+		switch (fmt->type) {
+		case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+
+			mutex_lock(&zr->resource_lock);
+
+			fmt->fmt.win.w.left = fh->overlay_settings.x;
+			fmt->fmt.win.w.top = fh->overlay_settings.y;
+			fmt->fmt.win.w.width = fh->overlay_settings.width;
+			fmt->fmt.win.w.height =
+			    fh->overlay_settings.height;
+			if (fh->overlay_settings.width * 2 >
+			    BUZ_MAX_HEIGHT)
+				fmt->fmt.win.field = V4L2_FIELD_INTERLACED;
+			else
+				fmt->fmt.win.field = V4L2_FIELD_TOP;
+
+			mutex_unlock(&zr->resource_lock);
+
+			break;
+
+		case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+		case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+
+			mutex_lock(&zr->resource_lock);
+
+			if (fmt->type == V4L2_BUF_TYPE_VIDEO_CAPTURE &&
+			    fh->map_mode == ZORAN_MAP_MODE_RAW) {
+
+				fmt->fmt.pix.width =
+				    fh->v4l_settings.width;
+				fmt->fmt.pix.height =
+				    fh->v4l_settings.height;
+				fmt->fmt.pix.sizeimage =
+				    fh->v4l_settings.bytesperline *
+				    fh->v4l_settings.height;
+				fmt->fmt.pix.pixelformat =
+				    fh->v4l_settings.format->fourcc;
+				fmt->fmt.pix.colorspace =
+				    fh->v4l_settings.format->colorspace;
+				fmt->fmt.pix.bytesperline =
+				    fh->v4l_settings.bytesperline;
+				if (BUZ_MAX_HEIGHT <
+				    (fh->v4l_settings.height * 2))
+					fmt->fmt.pix.field =
+					    V4L2_FIELD_INTERLACED;
+				else
+					fmt->fmt.pix.field =
+					    V4L2_FIELD_TOP;
+
+			} else {
+
+				fmt->fmt.pix.width =
+				    fh->jpg_settings.img_width /
+				    fh->jpg_settings.HorDcm;
+				fmt->fmt.pix.height =
+				    fh->jpg_settings.img_height /
+				    (fh->jpg_settings.VerDcm *
+				     fh->jpg_settings.TmpDcm);
+				fmt->fmt.pix.sizeimage =
+				    zoran_v4l2_calc_bufsize(&fh->
+							    jpg_settings);
+				fmt->fmt.pix.pixelformat =
+				    V4L2_PIX_FMT_MJPEG;
+				if (fh->jpg_settings.TmpDcm == 1)
+					fmt->fmt.pix.field =
+					    (fh->jpg_settings.
+					     odd_even ? V4L2_FIELD_SEQ_BT :
+					     V4L2_FIELD_SEQ_BT);
+				else
+					fmt->fmt.pix.field =
+					    (fh->jpg_settings.
+					     odd_even ? V4L2_FIELD_TOP :
+					     V4L2_FIELD_BOTTOM);
+
+				fmt->fmt.pix.bytesperline = 0;
+				fmt->fmt.pix.colorspace =
+				    V4L2_COLORSPACE_SMPTE170M;
+			}
+
+			mutex_unlock(&zr->resource_lock);
+
+			break;
+
+		default:
+			dprintk(1,
+				KERN_ERR
+				"%s: VIDIOC_G_FMT - unsupported type %d\n",
+				ZR_DEVNAME(zr), fmt->type);
+			return -EINVAL;
+		}
+		return 0;
+	}
+		break;
+
+	case VIDIOC_S_FMT:
+	{
+		struct v4l2_format *fmt = arg;
+		int i, res = 0;
+		__le32 printformat;
+
+		dprintk(3, KERN_DEBUG "%s: VIDIOC_S_FMT - type=%d, ",
+			ZR_DEVNAME(zr), fmt->type);
+
+		switch (fmt->type) {
+		case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+
+			dprintk(3, "x=%d, y=%d, w=%d, h=%d, cnt=%d, map=0x%p\n",
+				fmt->fmt.win.w.left, fmt->fmt.win.w.top,
+				fmt->fmt.win.w.width,
+				fmt->fmt.win.w.height,
+				fmt->fmt.win.clipcount,
+				fmt->fmt.win.bitmap);
+			mutex_lock(&zr->resource_lock);
+			res =
+			    setup_window(file, fmt->fmt.win.w.left,
+					 fmt->fmt.win.w.top,
+					 fmt->fmt.win.w.width,
+					 fmt->fmt.win.w.height,
+					 (struct video_clip __user *)
+					   fmt->fmt.win.clips,
+					 fmt->fmt.win.clipcount,
+					 fmt->fmt.win.bitmap);
+			mutex_unlock(&zr->resource_lock);
+			return res;
+			break;
+
+		case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+		case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+
+			printformat =
+			    __cpu_to_le32(fmt->fmt.pix.pixelformat);
+			dprintk(3, "size=%dx%d, fmt=0x%x (%4.4s)\n",
+				fmt->fmt.pix.width, fmt->fmt.pix.height,
+				fmt->fmt.pix.pixelformat,
+				(char *) &printformat);
+
+			/* we can be requested to do JPEG/raw playback/capture */
+			if (!
+			    (fmt->type == V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+			     (fmt->type == V4L2_BUF_TYPE_VIDEO_OUTPUT &&
+			      fmt->fmt.pix.pixelformat ==
+			      V4L2_PIX_FMT_MJPEG))) {
+				dprintk(1,
+					KERN_ERR
+					"%s: VIDIOC_S_FMT - unknown type %d/0x%x(%4.4s) combination\n",
+					ZR_DEVNAME(zr), fmt->type,
+					fmt->fmt.pix.pixelformat,
+					(char *) &printformat);
+				return -EINVAL;
+			}
+
+			if (fmt->fmt.pix.pixelformat == V4L2_PIX_FMT_MJPEG) {
+				mutex_lock(&zr->resource_lock);
+
+				settings = fh->jpg_settings;
+
+				if (fh->v4l_buffers.allocated ||
+				    fh->jpg_buffers.allocated) {
+					dprintk(1,
+						KERN_ERR
+						"%s: VIDIOC_S_FMT - cannot change capture mode\n",
+						ZR_DEVNAME(zr));
+					res = -EBUSY;
+					goto sfmtjpg_unlock_and_return;
+				}
+
+				/* we actually need to set 'real' parameters now */
+				if ((fmt->fmt.pix.height * 2) >
+				    BUZ_MAX_HEIGHT)
+					settings.TmpDcm = 1;
+				else
+					settings.TmpDcm = 2;
+				settings.decimation = 0;
+				if (fmt->fmt.pix.height <=
+				    fh->jpg_settings.img_height / 2)
+					settings.VerDcm = 2;
+				else
+					settings.VerDcm = 1;
+				if (fmt->fmt.pix.width <=
+				    fh->jpg_settings.img_width / 4)
+					settings.HorDcm = 4;
+				else if (fmt->fmt.pix.width <=
+					 fh->jpg_settings.img_width / 2)
+					settings.HorDcm = 2;
+				else
+					settings.HorDcm = 1;
+				if (settings.TmpDcm == 1)
+					settings.field_per_buff = 2;
+				else
+					settings.field_per_buff = 1;
+
+				/* check */
+				if ((res =
+				     zoran_check_jpg_settings(zr,
+							      &settings)))
+					goto sfmtjpg_unlock_and_return;
+
+				/* it's ok, so set them */
+				fh->jpg_settings = settings;
+
+				/* tell the user what we actually did */
+				fmt->fmt.pix.width =
+				    settings.img_width / settings.HorDcm;
+				fmt->fmt.pix.height =
+				    settings.img_height * 2 /
+				    (settings.TmpDcm * settings.VerDcm);
+				if (settings.TmpDcm == 1)
+					fmt->fmt.pix.field =
+					    (fh->jpg_settings.
+					     odd_even ? V4L2_FIELD_SEQ_TB :
+					     V4L2_FIELD_SEQ_BT);
+				else
+					fmt->fmt.pix.field =
+					    (fh->jpg_settings.
+					     odd_even ? V4L2_FIELD_TOP :
+					     V4L2_FIELD_BOTTOM);
+				fh->jpg_buffers.buffer_size =
+				    zoran_v4l2_calc_bufsize(&fh->
+							    jpg_settings);
+				fmt->fmt.pix.bytesperline = 0;
+				fmt->fmt.pix.sizeimage =
+				    fh->jpg_buffers.buffer_size;
+				fmt->fmt.pix.colorspace =
+				    V4L2_COLORSPACE_SMPTE170M;
+
+				/* we hereby abuse this variable to show that
+				 * we're gonna do mjpeg capture */
+				fh->map_mode =
+				    (fmt->type ==
+				     V4L2_BUF_TYPE_VIDEO_CAPTURE) ?
+				    ZORAN_MAP_MODE_JPG_REC :
+				    ZORAN_MAP_MODE_JPG_PLAY;
+			sfmtjpg_unlock_and_return:
+				mutex_unlock(&zr->resource_lock);
+			} else {
+				for (i = 0; i < NUM_FORMATS; i++)
+					if (fmt->fmt.pix.pixelformat ==
+					    zoran_formats[i].fourcc)
+						break;
+				if (i == NUM_FORMATS) {
+					dprintk(1,
+						KERN_ERR
+						"%s: VIDIOC_S_FMT - unknown/unsupported format 0x%x (%4.4s)\n",
+						ZR_DEVNAME(zr),
+						fmt->fmt.pix.pixelformat,
+						(char *) &printformat);
+					return -EINVAL;
+				}
+				mutex_lock(&zr->resource_lock);
+				if (fh->jpg_buffers.allocated ||
+				    (fh->v4l_buffers.allocated &&
+				     fh->v4l_buffers.active !=
+				     ZORAN_FREE)) {
+					dprintk(1,
+						KERN_ERR
+						"%s: VIDIOC_S_FMT - cannot change capture mode\n",
+						ZR_DEVNAME(zr));
+					res = -EBUSY;
+					goto sfmtv4l_unlock_and_return;
+				}
+				if (fmt->fmt.pix.height > BUZ_MAX_HEIGHT)
+					fmt->fmt.pix.height =
+					    BUZ_MAX_HEIGHT;
+				if (fmt->fmt.pix.width > BUZ_MAX_WIDTH)
+					fmt->fmt.pix.width = BUZ_MAX_WIDTH;
+
+				if ((res =
+				     zoran_v4l_set_format(file,
+							  fmt->fmt.pix.
+							  width,
+							  fmt->fmt.pix.
+							  height,
+							  &zoran_formats
+							  [i])))
+					goto sfmtv4l_unlock_and_return;
+
+				/* tell the user the
+				 * results/missing stuff */
+				fmt->fmt.pix.bytesperline =
+					fh->v4l_settings.bytesperline;
+				fmt->fmt.pix.sizeimage =
+					fh->v4l_settings.height *
+					fh->v4l_settings.bytesperline;
+				fmt->fmt.pix.colorspace =
+					fh->v4l_settings.format->colorspace;
+				if (BUZ_MAX_HEIGHT <
+				    (fh->v4l_settings.height * 2))
+					fmt->fmt.pix.field =
+					    V4L2_FIELD_INTERLACED;
+				else
+					fmt->fmt.pix.field =
+					    V4L2_FIELD_TOP;
+
+				fh->map_mode = ZORAN_MAP_MODE_RAW;
+			sfmtv4l_unlock_and_return:
+				mutex_unlock(&zr->resource_lock);
+			}
+
+			break;
+
+		default:
+			dprintk(3, "unsupported\n");
+			dprintk(1,
+				KERN_ERR
+				"%s: VIDIOC_S_FMT - unsupported type %d\n",
+				ZR_DEVNAME(zr), fmt->type);
+			return -EINVAL;
+		}
+
+		return res;
+	}
+		break;
+
+	case VIDIOC_G_FBUF:
+	{
+		struct v4l2_framebuffer *fb = arg;
+
+		dprintk(3, KERN_DEBUG "%s: VIDIOC_G_FBUF\n", ZR_DEVNAME(zr));
+
+		memset(fb, 0, sizeof(*fb));
+		mutex_lock(&zr->resource_lock);
+		fb->base = zr->buffer.base;
+		fb->fmt.width = zr->buffer.width;
+		fb->fmt.height = zr->buffer.height;
+		if (zr->overlay_settings.format) {
+			fb->fmt.pixelformat =
+				fh->overlay_settings.format->fourcc;
+		}
+		fb->fmt.bytesperline = zr->buffer.bytesperline;
+		mutex_unlock(&zr->resource_lock);
+		fb->fmt.colorspace = V4L2_COLORSPACE_SRGB;
+		fb->fmt.field = V4L2_FIELD_INTERLACED;
+		fb->flags = V4L2_FBUF_FLAG_OVERLAY;
+		fb->capability = V4L2_FBUF_CAP_LIST_CLIPPING;
+
+		return 0;
+	}
+		break;
+
+	case VIDIOC_S_FBUF:
+	{
+		int i, res = 0;
+		struct v4l2_framebuffer *fb = arg;
+		__le32 printformat = __cpu_to_le32(fb->fmt.pixelformat);
+
+		dprintk(3,
+			KERN_DEBUG
+			"%s: VIDIOC_S_FBUF - base=0x%p, size=%dx%d, bpl=%d, fmt=0x%x (%4.4s)\n",
+			ZR_DEVNAME(zr), fb->base, fb->fmt.width, fb->fmt.height,
+			fb->fmt.bytesperline, fb->fmt.pixelformat,
+			(char *) &printformat);
+
+		for (i = 0; i < NUM_FORMATS; i++)
+			if (zoran_formats[i].fourcc == fb->fmt.pixelformat)
+				break;
+		if (i == NUM_FORMATS) {
+			dprintk(1,
+				KERN_ERR
+				"%s: VIDIOC_S_FBUF - format=0x%x (%4.4s) not allowed\n",
+				ZR_DEVNAME(zr), fb->fmt.pixelformat,
+				(char *) &printformat);
+			return -EINVAL;
+		}
+
+		mutex_lock(&zr->resource_lock);
+		res =
+		    setup_fbuffer(file, fb->base, &zoran_formats[i],
+				  fb->fmt.width, fb->fmt.height,
+				  fb->fmt.bytesperline);
+		mutex_unlock(&zr->resource_lock);
+
+		return res;
+	}
+		break;
+
+	case VIDIOC_OVERLAY:
+	{
+		int *on = arg, res;
+
+		dprintk(3, KERN_DEBUG "%s: VIDIOC_PREVIEW - on=%d\n",
+			ZR_DEVNAME(zr), *on);
+
+		mutex_lock(&zr->resource_lock);
+		res = setup_overlay(file, *on);
+		mutex_unlock(&zr->resource_lock);
+
+		return res;
+	}
+		break;
+
+	case VIDIOC_REQBUFS:
+	{
+		struct v4l2_requestbuffers *req = arg;
+		int res = 0;
+
+		dprintk(3, KERN_DEBUG "%s: VIDIOC_REQBUFS - type=%d\n",
+			ZR_DEVNAME(zr), req->type);
+
+		if (req->memory != V4L2_MEMORY_MMAP) {
+			dprintk(1,
+				KERN_ERR
+				"%s: only MEMORY_MMAP capture is supported, not %d\n",
+				ZR_DEVNAME(zr), req->memory);
+			return -EINVAL;
+		}
+
+		mutex_lock(&zr->resource_lock);
+
+		if (fh->v4l_buffers.allocated || fh->jpg_buffers.allocated) {
+			dprintk(1,
+				KERN_ERR
+				"%s: VIDIOC_REQBUFS - buffers allready allocated\n",
+				ZR_DEVNAME(zr));
+			res = -EBUSY;
+			goto v4l2reqbuf_unlock_and_return;
+		}
+
+		if (fh->map_mode == ZORAN_MAP_MODE_RAW &&
+		    req->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+
+			/* control user input */
+			if (req->count < 2)
+				req->count = 2;
+			if (req->count > v4l_nbufs)
+				req->count = v4l_nbufs;
+			fh->v4l_buffers.num_buffers = req->count;
+
+			if (v4l_fbuffer_alloc(file)) {
+				res = -ENOMEM;
+				goto v4l2reqbuf_unlock_and_return;
+			}
+
+			/* The next mmap will map the V4L buffers */
+			fh->map_mode = ZORAN_MAP_MODE_RAW;
+
+		} else if (fh->map_mode == ZORAN_MAP_MODE_JPG_REC ||
+			   fh->map_mode == ZORAN_MAP_MODE_JPG_PLAY) {
+
+			/* we need to calculate size ourselves now */
+			if (req->count < 4)
+				req->count = 4;
+			if (req->count > jpg_nbufs)
+				req->count = jpg_nbufs;
+			fh->jpg_buffers.num_buffers = req->count;
+			fh->jpg_buffers.buffer_size =
+			    zoran_v4l2_calc_bufsize(&fh->jpg_settings);
+
+			if (jpg_fbuffer_alloc(file)) {
+				res = -ENOMEM;
+				goto v4l2reqbuf_unlock_and_return;
+			}
+
+			/* The next mmap will map the MJPEG buffers */
+			if (req->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+				fh->map_mode = ZORAN_MAP_MODE_JPG_REC;
+			else
+				fh->map_mode = ZORAN_MAP_MODE_JPG_PLAY;
+
+		} else {
+			dprintk(1,
+				KERN_ERR
+				"%s: VIDIOC_REQBUFS - unknown type %d\n",
+				ZR_DEVNAME(zr), req->type);
+			res = -EINVAL;
+			goto v4l2reqbuf_unlock_and_return;
+		}
+	v4l2reqbuf_unlock_and_return:
+		mutex_unlock(&zr->resource_lock);
+
+		return 0;
+	}
+		break;
+
+	case VIDIOC_QUERYBUF:
+	{
+		struct v4l2_buffer *buf = arg;
+		__u32 type = buf->type;
+		int index = buf->index, res;
+
+		dprintk(3,
+			KERN_DEBUG
+			"%s: VIDIOC_QUERYBUF - index=%d, type=%d\n",
+			ZR_DEVNAME(zr), buf->index, buf->type);
+
+		memset(buf, 0, sizeof(*buf));
+		buf->type = type;
+		buf->index = index;
+
+		mutex_lock(&zr->resource_lock);
+		res = zoran_v4l2_buffer_status(file, buf, buf->index);
+		mutex_unlock(&zr->resource_lock);
+
+		return res;
+	}
+		break;
+
+	case VIDIOC_QBUF:
+	{
+		struct v4l2_buffer *buf = arg;
+		int res = 0, codec_mode, buf_type;
+
+		dprintk(3,
+			KERN_DEBUG "%s: VIDIOC_QBUF - type=%d, index=%d\n",
+			ZR_DEVNAME(zr), buf->type, buf->index);
+
+		mutex_lock(&zr->resource_lock);
+
+		switch (fh->map_mode) {
+		case ZORAN_MAP_MODE_RAW:
+			if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+				dprintk(1,
+					KERN_ERR
+					"%s: VIDIOC_QBUF - invalid buf->type=%d for map_mode=%d\n",
+					ZR_DEVNAME(zr), buf->type, fh->map_mode);
+				res = -EINVAL;
+				goto qbuf_unlock_and_return;
+			}
+
+			res = zoran_v4l_queue_frame(file, buf->index);
+			if (res)
+				goto qbuf_unlock_and_return;
+			if (!zr->v4l_memgrab_active &&
+			    fh->v4l_buffers.active == ZORAN_LOCKED)
+				zr36057_set_memgrab(zr, 1);
+			break;
+
+		case ZORAN_MAP_MODE_JPG_REC:
+		case ZORAN_MAP_MODE_JPG_PLAY:
+			if (fh->map_mode == ZORAN_MAP_MODE_JPG_PLAY) {
+				buf_type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+				codec_mode = BUZ_MODE_MOTION_DECOMPRESS;
+			} else {
+				buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+				codec_mode = BUZ_MODE_MOTION_COMPRESS;
+			}
+
+			if (buf->type != buf_type) {
+				dprintk(1,
+					KERN_ERR
+					"%s: VIDIOC_QBUF - invalid buf->type=%d for map_mode=%d\n",
+					ZR_DEVNAME(zr), buf->type, fh->map_mode);
+				res = -EINVAL;
+				goto qbuf_unlock_and_return;
+			}
+
+			res =
+			    zoran_jpg_queue_frame(file, buf->index,
+						  codec_mode);
+			if (res != 0)
+				goto qbuf_unlock_and_return;
+			if (zr->codec_mode == BUZ_MODE_IDLE &&
+			    fh->jpg_buffers.active == ZORAN_LOCKED) {
+				zr36057_enable_jpg(zr, codec_mode);
+			}
+			break;
+
+		default:
+			dprintk(1,
+				KERN_ERR
+				"%s: VIDIOC_QBUF - unsupported type %d\n",
+				ZR_DEVNAME(zr), buf->type);
+			res = -EINVAL;
+			goto qbuf_unlock_and_return;
+		}
+	qbuf_unlock_and_return:
+		mutex_unlock(&zr->resource_lock);
+
+		return res;
+	}
+		break;
+
+	case VIDIOC_DQBUF:
+	{
+		struct v4l2_buffer *buf = arg;
+		int res = 0, buf_type, num = -1;	/* compiler borks here (?) */
+
+		dprintk(3, KERN_DEBUG "%s: VIDIOC_DQBUF - type=%d\n",
+			ZR_DEVNAME(zr), buf->type);
+
+		mutex_lock(&zr->resource_lock);
+
+		switch (fh->map_mode) {
+		case ZORAN_MAP_MODE_RAW:
+			if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+				dprintk(1,
+					KERN_ERR
+					"%s: VIDIOC_QBUF - invalid buf->type=%d for map_mode=%d\n",
+					ZR_DEVNAME(zr), buf->type, fh->map_mode);
+				res = -EINVAL;
+				goto dqbuf_unlock_and_return;
+			}
+
+			num = zr->v4l_pend[zr->v4l_sync_tail & V4L_MASK_FRAME];
+			if (file->f_flags & O_NONBLOCK &&
+			    zr->v4l_buffers.buffer[num].state !=
+			    BUZ_STATE_DONE) {
+				res = -EAGAIN;
+				goto dqbuf_unlock_and_return;
+			}
+			res = v4l_sync(file, num);
+			if (res)
+				goto dqbuf_unlock_and_return;
+			else
+				zr->v4l_sync_tail++;
+			res = zoran_v4l2_buffer_status(file, buf, num);
+			break;
+
+		case ZORAN_MAP_MODE_JPG_REC:
+		case ZORAN_MAP_MODE_JPG_PLAY:
+		{
+			struct zoran_sync bs;
+
+			if (fh->map_mode == ZORAN_MAP_MODE_JPG_PLAY)
+				buf_type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+			else
+				buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+			if (buf->type != buf_type) {
+				dprintk(1,
+					KERN_ERR
+					"%s: VIDIOC_QBUF - invalid buf->type=%d for map_mode=%d\n",
+					ZR_DEVNAME(zr), buf->type, fh->map_mode);
+				res = -EINVAL;
+				goto dqbuf_unlock_and_return;
+			}
+
+			num =
+			    zr->jpg_pend[zr->
+					 jpg_que_tail & BUZ_MASK_FRAME];
+
+			if (file->f_flags & O_NONBLOCK &&
+			    zr->jpg_buffers.buffer[num].state !=
+			    BUZ_STATE_DONE) {
+				res = -EAGAIN;
+				goto dqbuf_unlock_and_return;
+			}
+			res = jpg_sync(file, &bs);
+			if (res)
+				goto dqbuf_unlock_and_return;
+			res =
+			    zoran_v4l2_buffer_status(file, buf, bs.frame);
+			break;
+		}
+
+		default:
+			dprintk(1,
+				KERN_ERR
+				"%s: VIDIOC_DQBUF - unsupported type %d\n",
+				ZR_DEVNAME(zr), buf->type);
+			res = -EINVAL;
+			goto dqbuf_unlock_and_return;
+		}
+	dqbuf_unlock_and_return:
+		mutex_unlock(&zr->resource_lock);
+
+		return res;
+	}
+		break;
+
+	case VIDIOC_STREAMON:
+	{
+		int res = 0;
+
+		dprintk(3, KERN_DEBUG "%s: VIDIOC_STREAMON\n", ZR_DEVNAME(zr));
+
+		mutex_lock(&zr->resource_lock);
+
+		switch (fh->map_mode) {
+		case ZORAN_MAP_MODE_RAW:	/* raw capture */
+			if (zr->v4l_buffers.active != ZORAN_ACTIVE ||
+			    fh->v4l_buffers.active != ZORAN_ACTIVE) {
+				res = -EBUSY;
+				goto strmon_unlock_and_return;
+			}
+
+			zr->v4l_buffers.active = fh->v4l_buffers.active =
+			    ZORAN_LOCKED;
+			zr->v4l_settings = fh->v4l_settings;
+
+			zr->v4l_sync_tail = zr->v4l_pend_tail;
+			if (!zr->v4l_memgrab_active &&
+			    zr->v4l_pend_head != zr->v4l_pend_tail) {
+				zr36057_set_memgrab(zr, 1);
+			}
+			break;
+
+		case ZORAN_MAP_MODE_JPG_REC:
+		case ZORAN_MAP_MODE_JPG_PLAY:
+			/* what is the codec mode right now? */
+			if (zr->jpg_buffers.active != ZORAN_ACTIVE ||
+			    fh->jpg_buffers.active != ZORAN_ACTIVE) {
+				res = -EBUSY;
+				goto strmon_unlock_and_return;
+			}
+
+			zr->jpg_buffers.active = fh->jpg_buffers.active =
+			    ZORAN_LOCKED;
+
+			if (zr->jpg_que_head != zr->jpg_que_tail) {
+				/* Start the jpeg codec when the first frame is queued  */
+				jpeg_start(zr);
+			}
+
+			break;
+		default:
+			dprintk(1,
+				KERN_ERR
+				"%s: VIDIOC_STREAMON - invalid map mode %d\n",
+				ZR_DEVNAME(zr), fh->map_mode);
+			res = -EINVAL;
+			goto strmon_unlock_and_return;
+		}
+	strmon_unlock_and_return:
+		mutex_unlock(&zr->resource_lock);
+
+		return res;
+	}
+		break;
+
+	case VIDIOC_STREAMOFF:
+	{
+		int i, res = 0;
+
+		dprintk(3, KERN_DEBUG "%s: VIDIOC_STREAMOFF\n", ZR_DEVNAME(zr));
+
+		mutex_lock(&zr->resource_lock);
+
+		switch (fh->map_mode) {
+		case ZORAN_MAP_MODE_RAW:	/* raw capture */
+			if (fh->v4l_buffers.active == ZORAN_FREE &&
+			    zr->v4l_buffers.active != ZORAN_FREE) {
+				res = -EPERM;	/* stay off other's settings! */
+				goto strmoff_unlock_and_return;
+			}
+			if (zr->v4l_buffers.active == ZORAN_FREE)
+				goto strmoff_unlock_and_return;
+
+			/* unload capture */
+			if (zr->v4l_memgrab_active) {
+				unsigned long flags;
+
+				spin_lock_irqsave(&zr->spinlock, flags);
+				zr36057_set_memgrab(zr, 0);
+				spin_unlock_irqrestore(&zr->spinlock, flags);
+			}
+
+			for (i = 0; i < fh->v4l_buffers.num_buffers; i++)
+				zr->v4l_buffers.buffer[i].state =
+				    BUZ_STATE_USER;
+			fh->v4l_buffers = zr->v4l_buffers;
+
+			zr->v4l_buffers.active = fh->v4l_buffers.active =
+			    ZORAN_FREE;
+
+			zr->v4l_grab_seq = 0;
+			zr->v4l_pend_head = zr->v4l_pend_tail = 0;
+			zr->v4l_sync_tail = 0;
+
+			break;
+
+		case ZORAN_MAP_MODE_JPG_REC:
+		case ZORAN_MAP_MODE_JPG_PLAY:
+			if (fh->jpg_buffers.active == ZORAN_FREE &&
+			    zr->jpg_buffers.active != ZORAN_FREE) {
+				res = -EPERM;	/* stay off other's settings! */
+				goto strmoff_unlock_and_return;
+			}
+			if (zr->jpg_buffers.active == ZORAN_FREE)
+				goto strmoff_unlock_and_return;
+
+			res =
+			    jpg_qbuf(file, -1,
+				     (fh->map_mode ==
+				      ZORAN_MAP_MODE_JPG_REC) ?
+				     BUZ_MODE_MOTION_COMPRESS :
+				     BUZ_MODE_MOTION_DECOMPRESS);
+			if (res)
+				goto strmoff_unlock_and_return;
+			break;
+		default:
+			dprintk(1,
+				KERN_ERR
+				"%s: VIDIOC_STREAMOFF - invalid map mode %d\n",
+				ZR_DEVNAME(zr), fh->map_mode);
+			res = -EINVAL;
+			goto strmoff_unlock_and_return;
+		}
+	strmoff_unlock_and_return:
+		mutex_unlock(&zr->resource_lock);
+
+		return res;
+	}
+		break;
+
+	case VIDIOC_QUERYCTRL:
+	{
+		struct v4l2_queryctrl *ctrl = arg;
+
+		dprintk(3, KERN_DEBUG "%s: VIDIOC_QUERYCTRL - id=%d\n",
+			ZR_DEVNAME(zr), ctrl->id);
+
+		/* we only support hue/saturation/contrast/brightness */
+		if (ctrl->id < V4L2_CID_BRIGHTNESS ||
+		    ctrl->id > V4L2_CID_HUE)
+			return -EINVAL;
+		else {
+			int id = ctrl->id;
+			memset(ctrl, 0, sizeof(*ctrl));
+			ctrl->id = id;
+		}
+
+		switch (ctrl->id) {
+		case V4L2_CID_BRIGHTNESS:
+			strncpy(ctrl->name, "Brightness", sizeof(ctrl->name)-1);
+			break;
+		case V4L2_CID_CONTRAST:
+			strncpy(ctrl->name, "Contrast", sizeof(ctrl->name)-1);
+			break;
+		case V4L2_CID_SATURATION:
+			strncpy(ctrl->name, "Saturation", sizeof(ctrl->name)-1);
+			break;
+		case V4L2_CID_HUE:
+			strncpy(ctrl->name, "Hue", sizeof(ctrl->name)-1);
+			break;
+		}
+
+		ctrl->minimum = 0;
+		ctrl->maximum = 65535;
+		ctrl->step = 1;
+		ctrl->default_value = 32768;
+		ctrl->type = V4L2_CTRL_TYPE_INTEGER;
+
+		return 0;
+	}
+		break;
+
+	case VIDIOC_G_CTRL:
+	{
+		struct v4l2_control *ctrl = arg;
+
+		dprintk(3, KERN_DEBUG "%s: VIDIOC_G_CTRL - id=%d\n",
+			ZR_DEVNAME(zr), ctrl->id);
+
+		/* we only support hue/saturation/contrast/brightness */
+		if (ctrl->id < V4L2_CID_BRIGHTNESS ||
+		    ctrl->id > V4L2_CID_HUE)
+			return -EINVAL;
+
+		mutex_lock(&zr->resource_lock);
+		switch (ctrl->id) {
+		case V4L2_CID_BRIGHTNESS:
+			ctrl->value = zr->brightness;
+			break;
+		case V4L2_CID_CONTRAST:
+			ctrl->value = zr->contrast;
+			break;
+		case V4L2_CID_SATURATION:
+			ctrl->value = zr->saturation;
+			break;
+		case V4L2_CID_HUE:
+			ctrl->value = zr->hue;
+			break;
+		}
+		mutex_unlock(&zr->resource_lock);
+
+		return 0;
+	}
+		break;
+
+	case VIDIOC_S_CTRL:
+	{
+		struct v4l2_control *ctrl = arg;
+		struct video_picture pict;
+
+		dprintk(3, KERN_DEBUG "%s: VIDIOC_S_CTRL - id=%d\n",
+			ZR_DEVNAME(zr), ctrl->id);
+
+		/* we only support hue/saturation/contrast/brightness */
+		if (ctrl->id < V4L2_CID_BRIGHTNESS ||
+		    ctrl->id > V4L2_CID_HUE)
+			return -EINVAL;
+
+		if (ctrl->value < 0 || ctrl->value > 65535) {
+			dprintk(1,
+				KERN_ERR
+				"%s: VIDIOC_S_CTRL - invalid value %d for id=%d\n",
+				ZR_DEVNAME(zr), ctrl->value, ctrl->id);
+			return -EINVAL;
+		}
+
+		mutex_lock(&zr->resource_lock);
+		switch (ctrl->id) {
+		case V4L2_CID_BRIGHTNESS:
+			zr->brightness = ctrl->value;
+			break;
+		case V4L2_CID_CONTRAST:
+			zr->contrast = ctrl->value;
+			break;
+		case V4L2_CID_SATURATION:
+			zr->saturation = ctrl->value;
+			break;
+		case V4L2_CID_HUE:
+			zr->hue = ctrl->value;
+			break;
+		}
+		pict.brightness = zr->brightness;
+		pict.contrast = zr->contrast;
+		pict.colour = zr->saturation;
+		pict.hue = zr->hue;
+
+		decoder_command(zr, DECODER_SET_PICTURE, &pict);
+
+		mutex_unlock(&zr->resource_lock);
+
+		return 0;
+	}
+		break;
+
+	case VIDIOC_ENUMSTD:
+	{
+		struct v4l2_standard *std = arg;
+
+		dprintk(3, KERN_DEBUG "%s: VIDIOC_ENUMSTD - index=%d\n",
+			ZR_DEVNAME(zr), std->index);
+
+		if (std->index < 0 || std->index >= (zr->card.norms + 1))
+			return -EINVAL;
+		else {
+			int id = std->index;
+			memset(std, 0, sizeof(*std));
+			std->index = id;
+		}
+
+		if (std->index == zr->card.norms) {
+			/* if we have autodetect, ... */
+			struct video_decoder_capability caps;
+			decoder_command(zr, DECODER_GET_CAPABILITIES,
+					&caps);
+			if (caps.flags & VIDEO_DECODER_AUTO) {
+				std->id = V4L2_STD_ALL;
+				strncpy(std->name, "Autodetect", sizeof(std->name)-1);
+				return 0;
+			} else
+				return -EINVAL;
+		}
+		switch (std->index) {
+		case 0:
+			std->id = V4L2_STD_PAL;
+			strncpy(std->name, "PAL", sizeof(std->name)-1);
+			std->frameperiod.numerator = 1;
+			std->frameperiod.denominator = 25;
+			std->framelines = zr->card.tvn[0]->Ht;
+			break;
+		case 1:
+			std->id = V4L2_STD_NTSC;
+			strncpy(std->name, "NTSC", sizeof(std->name)-1);
+			std->frameperiod.numerator = 1001;
+			std->frameperiod.denominator = 30000;
+			std->framelines = zr->card.tvn[1]->Ht;
+			break;
+		case 2:
+			std->id = V4L2_STD_SECAM;
+			strncpy(std->name, "SECAM", sizeof(std->name)-1);
+			std->frameperiod.numerator = 1;
+			std->frameperiod.denominator = 25;
+			std->framelines = zr->card.tvn[2]->Ht;
+			break;
+		}
+
+		return 0;
+	}
+		break;
+
+	case VIDIOC_G_STD:
+	{
+		v4l2_std_id *std = arg;
+		int norm;
+
+		dprintk(3, KERN_DEBUG "%s: VIDIOC_G_STD\n", ZR_DEVNAME(zr));
+
+		mutex_lock(&zr->resource_lock);
+		norm = zr->norm;
+		mutex_unlock(&zr->resource_lock);
+
+		switch (norm) {
+		case VIDEO_MODE_PAL:
+			*std = V4L2_STD_PAL;
+			break;
+		case VIDEO_MODE_NTSC:
+			*std = V4L2_STD_NTSC;
+			break;
+		case VIDEO_MODE_SECAM:
+			*std = V4L2_STD_SECAM;
+			break;
+		}
+
+		return 0;
+	}
+		break;
+
+	case VIDIOC_S_STD:
+	{
+		int norm = -1, res = 0;
+		v4l2_std_id *std = arg;
+
+		dprintk(3, KERN_DEBUG "%s: VIDIOC_S_STD - norm=0x%llx\n",
+			ZR_DEVNAME(zr), (unsigned long long)*std);
+
+		if ((*std & V4L2_STD_PAL) && !(*std & ~V4L2_STD_PAL))
+			norm = VIDEO_MODE_PAL;
+		else if ((*std & V4L2_STD_NTSC) && !(*std & ~V4L2_STD_NTSC))
+			norm = VIDEO_MODE_NTSC;
+		else if ((*std & V4L2_STD_SECAM) && !(*std & ~V4L2_STD_SECAM))
+			norm = VIDEO_MODE_SECAM;
+		else if (*std == V4L2_STD_ALL)
+			norm = VIDEO_MODE_AUTO;
+		else {
+			dprintk(1,
+				KERN_ERR
+				"%s: VIDIOC_S_STD - invalid norm 0x%llx\n",
+				ZR_DEVNAME(zr), (unsigned long long)*std);
+			return -EINVAL;
+		}
+
+		mutex_lock(&zr->resource_lock);
+		if ((res = zoran_set_norm(zr, norm)))
+			goto sstd_unlock_and_return;
+
+		res = wait_grab_pending(zr);
+	sstd_unlock_and_return:
+		mutex_unlock(&zr->resource_lock);
+		return res;
+	}
+		break;
+
+	case VIDIOC_ENUMINPUT:
+	{
+		struct v4l2_input *inp = arg;
+		int status;
+
+		dprintk(3, KERN_DEBUG "%s: VIDIOC_ENUMINPUT - index=%d\n",
+			ZR_DEVNAME(zr), inp->index);
+
+		if (inp->index < 0 || inp->index >= zr->card.inputs)
+			return -EINVAL;
+		else {
+			int id = inp->index;
+			memset(inp, 0, sizeof(*inp));
+			inp->index = id;
+		}
+
+		strncpy(inp->name, zr->card.input[inp->index].name,
+			sizeof(inp->name) - 1);
+		inp->type = V4L2_INPUT_TYPE_CAMERA;
+		inp->std = V4L2_STD_ALL;
+
+		/* Get status of video decoder */
+		mutex_lock(&zr->resource_lock);
+		decoder_command(zr, DECODER_GET_STATUS, &status);
+		mutex_unlock(&zr->resource_lock);
+
+		if (!(status & DECODER_STATUS_GOOD)) {
+			inp->status |= V4L2_IN_ST_NO_POWER;
+			inp->status |= V4L2_IN_ST_NO_SIGNAL;
+		}
+		if (!(status & DECODER_STATUS_COLOR))
+			inp->status |= V4L2_IN_ST_NO_COLOR;
+
+		return 0;
+	}
+		break;
+
+	case VIDIOC_G_INPUT:
+	{
+		int *input = arg;
+
+		dprintk(3, KERN_DEBUG "%s: VIDIOC_G_INPUT\n", ZR_DEVNAME(zr));
+
+		mutex_lock(&zr->resource_lock);
+		*input = zr->input;
+		mutex_unlock(&zr->resource_lock);
+
+		return 0;
+	}
+		break;
+
+	case VIDIOC_S_INPUT:
+	{
+		int *input = arg, res = 0;
+
+		dprintk(3, KERN_DEBUG "%s: VIDIOC_S_INPUT - input=%d\n",
+			ZR_DEVNAME(zr), *input);
+
+		mutex_lock(&zr->resource_lock);
+		if ((res = zoran_set_input(zr, *input)))
+			goto sinput_unlock_and_return;
+
+		/* Make sure the changes come into effect */
+		res = wait_grab_pending(zr);
+	sinput_unlock_and_return:
+		mutex_unlock(&zr->resource_lock);
+		return res;
+	}
+		break;
+
+	case VIDIOC_ENUMOUTPUT:
+	{
+		struct v4l2_output *outp = arg;
+
+		dprintk(3, KERN_DEBUG "%s: VIDIOC_ENUMOUTPUT - index=%d\n",
+			ZR_DEVNAME(zr), outp->index);
+
+		if (outp->index != 0)
+			return -EINVAL;
+
+		memset(outp, 0, sizeof(*outp));
+		outp->index = 0;
+		outp->type = V4L2_OUTPUT_TYPE_ANALOGVGAOVERLAY;
+		strncpy(outp->name, "Autodetect", sizeof(outp->name)-1);
+
+		return 0;
+	}
+		break;
+
+	case VIDIOC_G_OUTPUT:
+	{
+		int *output = arg;
+
+		dprintk(3, KERN_DEBUG "%s: VIDIOC_G_OUTPUT\n", ZR_DEVNAME(zr));
+
+		*output = 0;
+
+		return 0;
+	}
+		break;
+
+	case VIDIOC_S_OUTPUT:
+	{
+		int *output = arg;
+
+		dprintk(3, KERN_DEBUG "%s: VIDIOC_S_OUTPUT - output=%d\n",
+			ZR_DEVNAME(zr), *output);
+
+		if (*output != 0)
+			return -EINVAL;
+
+		return 0;
+	}
+		break;
+
+		/* cropping (sub-frame capture) */
+	case VIDIOC_CROPCAP:
+	{
+		struct v4l2_cropcap *cropcap = arg;
+		int type = cropcap->type, res = 0;
+
+		dprintk(3, KERN_ERR "%s: VIDIOC_CROPCAP - type=%d\n",
+			ZR_DEVNAME(zr), cropcap->type);
+
+		memset(cropcap, 0, sizeof(*cropcap));
+		cropcap->type = type;
+
+		mutex_lock(&zr->resource_lock);
+
+		if (cropcap->type != V4L2_BUF_TYPE_VIDEO_OUTPUT &&
+		    (cropcap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+		     fh->map_mode == ZORAN_MAP_MODE_RAW)) {
+			dprintk(1,
+				KERN_ERR
+				"%s: VIDIOC_CROPCAP - subcapture only supported for compressed capture\n",
+				ZR_DEVNAME(zr));
+			res = -EINVAL;
+			goto cropcap_unlock_and_return;
+		}
+
+		cropcap->bounds.top = cropcap->bounds.left = 0;
+		cropcap->bounds.width = BUZ_MAX_WIDTH;
+		cropcap->bounds.height = BUZ_MAX_HEIGHT;
+		cropcap->defrect.top = cropcap->defrect.left = 0;
+		cropcap->defrect.width = BUZ_MIN_WIDTH;
+		cropcap->defrect.height = BUZ_MIN_HEIGHT;
+	cropcap_unlock_and_return:
+		mutex_unlock(&zr->resource_lock);
+		return res;
+	}
+		break;
+
+	case VIDIOC_G_CROP:
+	{
+		struct v4l2_crop *crop = arg;
+		int type = crop->type, res = 0;
+
+		dprintk(3, KERN_ERR "%s: VIDIOC_G_CROP - type=%d\n",
+			ZR_DEVNAME(zr), crop->type);
+
+		memset(crop, 0, sizeof(*crop));
+		crop->type = type;
+
+		mutex_lock(&zr->resource_lock);
+
+		if (crop->type != V4L2_BUF_TYPE_VIDEO_OUTPUT &&
+		    (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+		     fh->map_mode == ZORAN_MAP_MODE_RAW)) {
+			dprintk(1,
+				KERN_ERR
+				"%s: VIDIOC_G_CROP - subcapture only supported for compressed capture\n",
+				ZR_DEVNAME(zr));
+			res = -EINVAL;
+			goto gcrop_unlock_and_return;
+		}
+
+		crop->c.top = fh->jpg_settings.img_y;
+		crop->c.left = fh->jpg_settings.img_x;
+		crop->c.width = fh->jpg_settings.img_width;
+		crop->c.height = fh->jpg_settings.img_height;
+
+	gcrop_unlock_and_return:
+		mutex_unlock(&zr->resource_lock);
+
+		return res;
+	}
+		break;
+
+	case VIDIOC_S_CROP:
+	{
+		struct v4l2_crop *crop = arg;
+		int res = 0;
+
+		settings = fh->jpg_settings;
+
+		dprintk(3,
+			KERN_ERR
+			"%s: VIDIOC_S_CROP - type=%d, x=%d,y=%d,w=%d,h=%d\n",
+			ZR_DEVNAME(zr), crop->type, crop->c.left, crop->c.top,
+			crop->c.width, crop->c.height);
+
+		mutex_lock(&zr->resource_lock);
+
+		if (fh->jpg_buffers.allocated || fh->v4l_buffers.allocated) {
+			dprintk(1,
+				KERN_ERR
+				"%s: VIDIOC_S_CROP - cannot change settings while active\n",
+				ZR_DEVNAME(zr));
+			res = -EBUSY;
+			goto scrop_unlock_and_return;
+		}
+
+		if (crop->type != V4L2_BUF_TYPE_VIDEO_OUTPUT &&
+		    (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+		     fh->map_mode == ZORAN_MAP_MODE_RAW)) {
+			dprintk(1,
+				KERN_ERR
+				"%s: VIDIOC_G_CROP - subcapture only supported for compressed capture\n",
+				ZR_DEVNAME(zr));
+			res = -EINVAL;
+			goto scrop_unlock_and_return;
+		}
+
+		/* move into a form that we understand */
+		settings.img_x = crop->c.left;
+		settings.img_y = crop->c.top;
+		settings.img_width = crop->c.width;
+		settings.img_height = crop->c.height;
+
+		/* check validity */
+		if ((res = zoran_check_jpg_settings(zr, &settings)))
+			goto scrop_unlock_and_return;
+
+		/* accept */
+		fh->jpg_settings = settings;
+
+	scrop_unlock_and_return:
+		mutex_unlock(&zr->resource_lock);
+		return res;
+	}
+		break;
+
+	case VIDIOC_G_JPEGCOMP:
+	{
+		struct v4l2_jpegcompression *params = arg;
+
+		dprintk(3, KERN_DEBUG "%s: VIDIOC_G_JPEGCOMP\n",
+			ZR_DEVNAME(zr));
+
+		memset(params, 0, sizeof(*params));
+
+		mutex_lock(&zr->resource_lock);
+
+		params->quality = fh->jpg_settings.jpg_comp.quality;
+		params->APPn = fh->jpg_settings.jpg_comp.APPn;
+		memcpy(params->APP_data,
+		       fh->jpg_settings.jpg_comp.APP_data,
+		       fh->jpg_settings.jpg_comp.APP_len);
+		params->APP_len = fh->jpg_settings.jpg_comp.APP_len;
+		memcpy(params->COM_data,
+		       fh->jpg_settings.jpg_comp.COM_data,
+		       fh->jpg_settings.jpg_comp.COM_len);
+		params->COM_len = fh->jpg_settings.jpg_comp.COM_len;
+		params->jpeg_markers =
+		    fh->jpg_settings.jpg_comp.jpeg_markers;
+
+		mutex_unlock(&zr->resource_lock);
+
+		return 0;
+	}
+		break;
+
+	case VIDIOC_S_JPEGCOMP:
+	{
+		struct v4l2_jpegcompression *params = arg;
+		int res = 0;
+
+		settings = fh->jpg_settings;
+
+		dprintk(3,
+			KERN_DEBUG
+			"%s: VIDIOC_S_JPEGCOMP - quality=%d, APPN=%d, APP_len=%d, COM_len=%d\n",
+			ZR_DEVNAME(zr), params->quality, params->APPn,
+			params->APP_len, params->COM_len);
+
+		settings.jpg_comp = *params;
+
+		mutex_lock(&zr->resource_lock);
+
+		if (fh->v4l_buffers.active != ZORAN_FREE ||
+		    fh->jpg_buffers.active != ZORAN_FREE) {
+			dprintk(1,
+				KERN_WARNING
+				"%s: VIDIOC_S_JPEGCOMP called while in playback/capture mode\n",
+				ZR_DEVNAME(zr));
+			res = -EBUSY;
+			goto sjpegc_unlock_and_return;
+		}
+
+		if ((res = zoran_check_jpg_settings(zr, &settings)))
+			goto sjpegc_unlock_and_return;
+		if (!fh->jpg_buffers.allocated)
+			fh->jpg_buffers.buffer_size =
+			    zoran_v4l2_calc_bufsize(&fh->jpg_settings);
+		fh->jpg_settings.jpg_comp = *params = settings.jpg_comp;
+	sjpegc_unlock_and_return:
+		mutex_unlock(&zr->resource_lock);
+
+		return 0;
+	}
+		break;
+
+	case VIDIOC_QUERYSTD:	/* why is this useful? */
+	{
+		v4l2_std_id *std = arg;
+
+		dprintk(3,
+			KERN_DEBUG "%s: VIDIOC_QUERY_STD - std=0x%llx\n",
+			ZR_DEVNAME(zr), (unsigned long long)*std);
+
+		if (*std == V4L2_STD_ALL || *std == V4L2_STD_NTSC ||
+		    *std == V4L2_STD_PAL || (*std == V4L2_STD_SECAM &&
+					     zr->card.norms == 3)) {
+			return 0;
+		}
+
+		return -EINVAL;
+	}
+		break;
+
+	case VIDIOC_TRY_FMT:
+	{
+		struct v4l2_format *fmt = arg;
+		int res = 0;
+
+		dprintk(3, KERN_DEBUG "%s: VIDIOC_TRY_FMT - type=%d\n",
+			ZR_DEVNAME(zr), fmt->type);
+
+		switch (fmt->type) {
+		case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+			mutex_lock(&zr->resource_lock);
+
+			if (fmt->fmt.win.w.width > BUZ_MAX_WIDTH)
+				fmt->fmt.win.w.width = BUZ_MAX_WIDTH;
+			if (fmt->fmt.win.w.width < BUZ_MIN_WIDTH)
+				fmt->fmt.win.w.width = BUZ_MIN_WIDTH;
+			if (fmt->fmt.win.w.height > BUZ_MAX_HEIGHT)
+				fmt->fmt.win.w.height = BUZ_MAX_HEIGHT;
+			if (fmt->fmt.win.w.height < BUZ_MIN_HEIGHT)
+				fmt->fmt.win.w.height = BUZ_MIN_HEIGHT;
+
+			mutex_unlock(&zr->resource_lock);
+			break;
+
+		case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+		case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+			if (fmt->fmt.pix.bytesperline > 0)
+				return -EINVAL;
+
+			mutex_lock(&zr->resource_lock);
+
+			if (fmt->fmt.pix.pixelformat == V4L2_PIX_FMT_MJPEG) {
+				settings = fh->jpg_settings;
+
+				/* we actually need to set 'real' parameters now */
+				if ((fmt->fmt.pix.height * 2) >
+				    BUZ_MAX_HEIGHT)
+					settings.TmpDcm = 1;
+				else
+					settings.TmpDcm = 2;
+				settings.decimation = 0;
+				if (fmt->fmt.pix.height <=
+				    fh->jpg_settings.img_height / 2)
+					settings.VerDcm = 2;
+				else
+					settings.VerDcm = 1;
+				if (fmt->fmt.pix.width <=
+				    fh->jpg_settings.img_width / 4)
+					settings.HorDcm = 4;
+				else if (fmt->fmt.pix.width <=
+					 fh->jpg_settings.img_width / 2)
+					settings.HorDcm = 2;
+				else
+					settings.HorDcm = 1;
+				if (settings.TmpDcm == 1)
+					settings.field_per_buff = 2;
+				else
+					settings.field_per_buff = 1;
+
+				/* check */
+				if ((res =
+				     zoran_check_jpg_settings(zr,
+							      &settings)))
+					goto tryfmt_unlock_and_return;
+
+				/* tell the user what we actually did */
+				fmt->fmt.pix.width =
+				    settings.img_width / settings.HorDcm;
+				fmt->fmt.pix.height =
+				    settings.img_height * 2 /
+				    (settings.TmpDcm * settings.VerDcm);
+				if (settings.TmpDcm == 1)
+					fmt->fmt.pix.field =
+					    (fh->jpg_settings.
+					     odd_even ? V4L2_FIELD_SEQ_TB :
+					     V4L2_FIELD_SEQ_BT);
+				else
+					fmt->fmt.pix.field =
+					    (fh->jpg_settings.
+					     odd_even ? V4L2_FIELD_TOP :
+					     V4L2_FIELD_BOTTOM);
+
+				fmt->fmt.pix.sizeimage =
+				    zoran_v4l2_calc_bufsize(&settings);
+			} else if (fmt->type ==
+				   V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+				int i;
+
+				for (i = 0; i < NUM_FORMATS; i++)
+					if (zoran_formats[i].fourcc ==
+					    fmt->fmt.pix.pixelformat)
+						break;
+				if (i == NUM_FORMATS) {
+					res = -EINVAL;
+					goto tryfmt_unlock_and_return;
+				}
+
+				if (fmt->fmt.pix.width > BUZ_MAX_WIDTH)
+					fmt->fmt.pix.width = BUZ_MAX_WIDTH;
+				if (fmt->fmt.pix.width < BUZ_MIN_WIDTH)
+					fmt->fmt.pix.width = BUZ_MIN_WIDTH;
+				if (fmt->fmt.pix.height > BUZ_MAX_HEIGHT)
+					fmt->fmt.pix.height =
+					    BUZ_MAX_HEIGHT;
+				if (fmt->fmt.pix.height < BUZ_MIN_HEIGHT)
+					fmt->fmt.pix.height =
+					    BUZ_MIN_HEIGHT;
+			} else {
+				res = -EINVAL;
+				goto tryfmt_unlock_and_return;
+			}
+		tryfmt_unlock_and_return:
+			mutex_unlock(&zr->resource_lock);
+
+			return res;
+			break;
+
+		default:
+			return -EINVAL;
+		}
+
+		return 0;
+	}
+		break;
+
+	default:
+		dprintk(1, KERN_DEBUG "%s: UNKNOWN ioctl cmd: 0x%x\n",
+			ZR_DEVNAME(zr), cmd);
+		return -ENOIOCTLCMD;
+		break;
+
+	}
+	return 0;
+}
+
+
+static int
+zoran_ioctl (struct inode *inode,
+	     struct file  *file,
+	     unsigned int  cmd,
+	     unsigned long arg)
+{
+	return video_usercopy(inode, file, cmd, arg, zoran_do_ioctl);
+}
+
+static unsigned int
+zoran_poll (struct file *file,
+	    poll_table  *wait)
+{
+	struct zoran_fh *fh = file->private_data;
+	struct zoran *zr = fh->zr;
+	int res = 0, frame;
+	unsigned long flags;
+
+	/* we should check whether buffers are ready to be synced on
+	 * (w/o waits - O_NONBLOCK) here
+	 * if ready for read (sync), return POLLIN|POLLRDNORM,
+	 * if ready for write (sync), return POLLOUT|POLLWRNORM,
+	 * if error, return POLLERR,
+	 * if no buffers queued or so, return POLLNVAL
+	 */
+
+	mutex_lock(&zr->resource_lock);
+
+	switch (fh->map_mode) {
+	case ZORAN_MAP_MODE_RAW:
+		poll_wait(file, &zr->v4l_capq, wait);
+		frame = zr->v4l_pend[zr->v4l_sync_tail & V4L_MASK_FRAME];
+
+		spin_lock_irqsave(&zr->spinlock, flags);
+		dprintk(3,
+			KERN_DEBUG
+			"%s: %s() raw - active=%c, sync_tail=%lu/%c, pend_tail=%lu, pend_head=%lu\n",
+			ZR_DEVNAME(zr), __func__,
+			"FAL"[fh->v4l_buffers.active], zr->v4l_sync_tail,
+			"UPMD"[zr->v4l_buffers.buffer[frame].state],
+			zr->v4l_pend_tail, zr->v4l_pend_head);
+		/* Process is the one capturing? */
+		if (fh->v4l_buffers.active != ZORAN_FREE &&
+		    /* Buffer ready to DQBUF? */
+		    zr->v4l_buffers.buffer[frame].state == BUZ_STATE_DONE)
+			res = POLLIN | POLLRDNORM;
+		spin_unlock_irqrestore(&zr->spinlock, flags);
+
+		break;
+
+	case ZORAN_MAP_MODE_JPG_REC:
+	case ZORAN_MAP_MODE_JPG_PLAY:
+		poll_wait(file, &zr->jpg_capq, wait);
+		frame = zr->jpg_pend[zr->jpg_que_tail & BUZ_MASK_FRAME];
+
+		spin_lock_irqsave(&zr->spinlock, flags);
+		dprintk(3,
+			KERN_DEBUG
+			"%s: %s() jpg - active=%c, que_tail=%lu/%c, que_head=%lu, dma=%lu/%lu\n",
+			ZR_DEVNAME(zr), __func__,
+			"FAL"[fh->jpg_buffers.active], zr->jpg_que_tail,
+			"UPMD"[zr->jpg_buffers.buffer[frame].state],
+			zr->jpg_que_head, zr->jpg_dma_tail, zr->jpg_dma_head);
+		if (fh->jpg_buffers.active != ZORAN_FREE &&
+		    zr->jpg_buffers.buffer[frame].state == BUZ_STATE_DONE) {
+			if (fh->map_mode == ZORAN_MAP_MODE_JPG_REC)
+				res = POLLIN | POLLRDNORM;
+			else
+				res = POLLOUT | POLLWRNORM;
+		}
+		spin_unlock_irqrestore(&zr->spinlock, flags);
+
+		break;
+
+	default:
+		dprintk(1,
+			KERN_ERR
+			"%s: zoran_poll() - internal error, unknown map_mode=%d\n",
+			ZR_DEVNAME(zr), fh->map_mode);
+		res = POLLNVAL;
+	}
+
+	mutex_unlock(&zr->resource_lock);
+
+	return res;
+}
+
+
+/*
+ * This maps the buffers to user space.
+ *
+ * Depending on the state of fh->map_mode
+ * the V4L or the MJPEG buffers are mapped
+ * per buffer or all together
+ *
+ * Note that we need to connect to some
+ * unmap signal event to unmap the de-allocate
+ * the buffer accordingly (zoran_vm_close())
+ */
+
+static void
+zoran_vm_open (struct vm_area_struct *vma)
+{
+	struct zoran_mapping *map = vma->vm_private_data;
+
+	map->count++;
+}
+
+static void
+zoran_vm_close (struct vm_area_struct *vma)
+{
+	struct zoran_mapping *map = vma->vm_private_data;
+	struct file *file = map->file;
+	struct zoran_fh *fh = file->private_data;
+	struct zoran *zr = fh->zr;
+	int i;
+
+	map->count--;
+	if (map->count == 0) {
+		switch (fh->map_mode) {
+		case ZORAN_MAP_MODE_JPG_REC:
+		case ZORAN_MAP_MODE_JPG_PLAY:
+
+			dprintk(3, KERN_INFO "%s: munmap(MJPEG)\n",
+				ZR_DEVNAME(zr));
+
+			for (i = 0; i < fh->jpg_buffers.num_buffers; i++) {
+				if (fh->jpg_buffers.buffer[i].map == map) {
+					fh->jpg_buffers.buffer[i].map =
+					    NULL;
+				}
+			}
+			kfree(map);
+
+			for (i = 0; i < fh->jpg_buffers.num_buffers; i++)
+				if (fh->jpg_buffers.buffer[i].map)
+					break;
+			if (i == fh->jpg_buffers.num_buffers) {
+				mutex_lock(&zr->resource_lock);
+
+				if (fh->jpg_buffers.active != ZORAN_FREE) {
+					jpg_qbuf(file, -1, zr->codec_mode);
+					zr->jpg_buffers.allocated = 0;
+					zr->jpg_buffers.active =
+					    fh->jpg_buffers.active =
+					    ZORAN_FREE;
+				}
+				//jpg_fbuffer_free(file);
+				fh->jpg_buffers.allocated = 0;
+				fh->jpg_buffers.ready_to_be_freed = 1;
+
+				mutex_unlock(&zr->resource_lock);
+			}
+
+			break;
+
+		case ZORAN_MAP_MODE_RAW:
+
+			dprintk(3, KERN_INFO "%s: munmap(V4L)\n",
+				ZR_DEVNAME(zr));
+
+			for (i = 0; i < fh->v4l_buffers.num_buffers; i++) {
+				if (fh->v4l_buffers.buffer[i].map == map) {
+					/* unqueue/unmap */
+					fh->v4l_buffers.buffer[i].map =
+					    NULL;
+				}
+			}
+			kfree(map);
+
+			for (i = 0; i < fh->v4l_buffers.num_buffers; i++)
+				if (fh->v4l_buffers.buffer[i].map)
+					break;
+			if (i == fh->v4l_buffers.num_buffers) {
+				mutex_lock(&zr->resource_lock);
+
+				if (fh->v4l_buffers.active != ZORAN_FREE) {
+					unsigned long flags;
+
+					spin_lock_irqsave(&zr->spinlock, flags);
+					zr36057_set_memgrab(zr, 0);
+					zr->v4l_buffers.allocated = 0;
+					zr->v4l_buffers.active =
+					    fh->v4l_buffers.active =
+					    ZORAN_FREE;
+					spin_unlock_irqrestore(&zr->spinlock, flags);
+				}
+				//v4l_fbuffer_free(file);
+				fh->v4l_buffers.allocated = 0;
+				fh->v4l_buffers.ready_to_be_freed = 1;
+
+				mutex_unlock(&zr->resource_lock);
+			}
+
+			break;
+
+		default:
+			printk(KERN_ERR
+			       "%s: munmap() - internal error - unknown map mode %d\n",
+			       ZR_DEVNAME(zr), fh->map_mode);
+			break;
+
+		}
+	}
+}
+
+static struct vm_operations_struct zoran_vm_ops = {
+	.open = zoran_vm_open,
+	.close = zoran_vm_close,
+};
+
+static int
+zoran_mmap (struct file           *file,
+	    struct vm_area_struct *vma)
+{
+	struct zoran_fh *fh = file->private_data;
+	struct zoran *zr = fh->zr;
+	unsigned long size = (vma->vm_end - vma->vm_start);
+	unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
+	int i, j;
+	unsigned long page, start = vma->vm_start, todo, pos, fraglen;
+	int first, last;
+	struct zoran_mapping *map;
+	int res = 0;
+
+	dprintk(3,
+		KERN_INFO "%s: mmap(%s) of 0x%08lx-0x%08lx (size=%lu)\n",
+		ZR_DEVNAME(zr),
+		fh->map_mode == ZORAN_MAP_MODE_RAW ? "V4L" : "MJPEG",
+		vma->vm_start, vma->vm_end, size);
+
+	if (!(vma->vm_flags & VM_SHARED) || !(vma->vm_flags & VM_READ) ||
+	    !(vma->vm_flags & VM_WRITE)) {
+		dprintk(1,
+			KERN_ERR
+			"%s: mmap() - no MAP_SHARED/PROT_{READ,WRITE} given\n",
+			ZR_DEVNAME(zr));
+		return -EINVAL;
+	}
+
+	switch (fh->map_mode) {
+
+	case ZORAN_MAP_MODE_JPG_REC:
+	case ZORAN_MAP_MODE_JPG_PLAY:
+
+		/* lock */
+		mutex_lock(&zr->resource_lock);
+
+		/* Map the MJPEG buffers */
+		if (!fh->jpg_buffers.allocated) {
+			dprintk(1,
+				KERN_ERR
+				"%s: zoran_mmap(MJPEG) - buffers not yet allocated\n",
+				ZR_DEVNAME(zr));
+			res = -ENOMEM;
+			goto jpg_mmap_unlock_and_return;
+		}
+
+		first = offset / fh->jpg_buffers.buffer_size;
+		last = first - 1 + size / fh->jpg_buffers.buffer_size;
+		if (offset % fh->jpg_buffers.buffer_size != 0 ||
+		    size % fh->jpg_buffers.buffer_size != 0 || first < 0 ||
+		    last < 0 || first >= fh->jpg_buffers.num_buffers ||
+		    last >= fh->jpg_buffers.num_buffers) {
+			dprintk(1,
+				KERN_ERR
+				"%s: mmap(MJPEG) - offset=%lu or size=%lu invalid for bufsize=%d and numbufs=%d\n",
+				ZR_DEVNAME(zr), offset, size,
+				fh->jpg_buffers.buffer_size,
+				fh->jpg_buffers.num_buffers);
+			res = -EINVAL;
+			goto jpg_mmap_unlock_and_return;
+		}
+		for (i = first; i <= last; i++) {
+			if (fh->jpg_buffers.buffer[i].map) {
+				dprintk(1,
+					KERN_ERR
+					"%s: mmap(MJPEG) - buffer %d already mapped\n",
+					ZR_DEVNAME(zr), i);
+				res = -EBUSY;
+				goto jpg_mmap_unlock_and_return;
+			}
+		}
+
+		/* map these buffers (v4l_buffers[i]) */
+		map = kmalloc(sizeof(struct zoran_mapping), GFP_KERNEL);
+		if (!map) {
+			res = -ENOMEM;
+			goto jpg_mmap_unlock_and_return;
+		}
+		map->file = file;
+		map->count = 1;
+
+		vma->vm_ops = &zoran_vm_ops;
+		vma->vm_flags |= VM_DONTEXPAND;
+		vma->vm_private_data = map;
+
+		for (i = first; i <= last; i++) {
+			for (j = 0;
+			     j < fh->jpg_buffers.buffer_size / PAGE_SIZE;
+			     j++) {
+				fraglen =
+				    (le32_to_cpu(fh->jpg_buffers.buffer[i].
+				     frag_tab[2 * j + 1]) & ~1) << 1;
+				todo = size;
+				if (todo > fraglen)
+					todo = fraglen;
+				pos =
+				    le32_to_cpu(fh->jpg_buffers.
+				    buffer[i].frag_tab[2 * j]);
+				/* should just be pos on i386 */
+				page = virt_to_phys(bus_to_virt(pos))
+								>> PAGE_SHIFT;
+				if (remap_pfn_range(vma, start, page,
+							todo, PAGE_SHARED)) {
+					dprintk(1,
+						KERN_ERR
+						"%s: zoran_mmap(V4L) - remap_pfn_range failed\n",
+						ZR_DEVNAME(zr));
+					res = -EAGAIN;
+					goto jpg_mmap_unlock_and_return;
+				}
+				size -= todo;
+				start += todo;
+				if (size == 0)
+					break;
+				if (le32_to_cpu(fh->jpg_buffers.buffer[i].
+				    frag_tab[2 * j + 1]) & 1)
+					break;	/* was last fragment */
+			}
+			fh->jpg_buffers.buffer[i].map = map;
+			if (size == 0)
+				break;
+
+		}
+	jpg_mmap_unlock_and_return:
+		mutex_unlock(&zr->resource_lock);
+
+		break;
+
+	case ZORAN_MAP_MODE_RAW:
+
+		mutex_lock(&zr->resource_lock);
+
+		/* Map the V4L buffers */
+		if (!fh->v4l_buffers.allocated) {
+			dprintk(1,
+				KERN_ERR
+				"%s: zoran_mmap(V4L) - buffers not yet allocated\n",
+				ZR_DEVNAME(zr));
+			res = -ENOMEM;
+			goto v4l_mmap_unlock_and_return;
+		}
+
+		first = offset / fh->v4l_buffers.buffer_size;
+		last = first - 1 + size / fh->v4l_buffers.buffer_size;
+		if (offset % fh->v4l_buffers.buffer_size != 0 ||
+		    size % fh->v4l_buffers.buffer_size != 0 || first < 0 ||
+		    last < 0 || first >= fh->v4l_buffers.num_buffers ||
+		    last >= fh->v4l_buffers.buffer_size) {
+			dprintk(1,
+				KERN_ERR
+				"%s: mmap(V4L) - offset=%lu or size=%lu invalid for bufsize=%d and numbufs=%d\n",
+				ZR_DEVNAME(zr), offset, size,
+				fh->v4l_buffers.buffer_size,
+				fh->v4l_buffers.num_buffers);
+			res = -EINVAL;
+			goto v4l_mmap_unlock_and_return;
+		}
+		for (i = first; i <= last; i++) {
+			if (fh->v4l_buffers.buffer[i].map) {
+				dprintk(1,
+					KERN_ERR
+					"%s: mmap(V4L) - buffer %d already mapped\n",
+					ZR_DEVNAME(zr), i);
+				res = -EBUSY;
+				goto v4l_mmap_unlock_and_return;
+			}
+		}
+
+		/* map these buffers (v4l_buffers[i]) */
+		map = kmalloc(sizeof(struct zoran_mapping), GFP_KERNEL);
+		if (!map) {
+			res = -ENOMEM;
+			goto v4l_mmap_unlock_and_return;
+		}
+		map->file = file;
+		map->count = 1;
+
+		vma->vm_ops = &zoran_vm_ops;
+		vma->vm_flags |= VM_DONTEXPAND;
+		vma->vm_private_data = map;
+
+		for (i = first; i <= last; i++) {
+			todo = size;
+			if (todo > fh->v4l_buffers.buffer_size)
+				todo = fh->v4l_buffers.buffer_size;
+			page = fh->v4l_buffers.buffer[i].fbuffer_phys;
+			if (remap_pfn_range(vma, start, page >> PAGE_SHIFT,
+							todo, PAGE_SHARED)) {
+				dprintk(1,
+					KERN_ERR
+					"%s: zoran_mmap(V4L)i - remap_pfn_range failed\n",
+					ZR_DEVNAME(zr));
+				res = -EAGAIN;
+				goto v4l_mmap_unlock_and_return;
+			}
+			size -= todo;
+			start += todo;
+			fh->v4l_buffers.buffer[i].map = map;
+			if (size == 0)
+				break;
+		}
+	v4l_mmap_unlock_and_return:
+		mutex_unlock(&zr->resource_lock);
+
+		break;
+
+	default:
+		dprintk(1,
+			KERN_ERR
+			"%s: zoran_mmap() - internal error - unknown map mode %d\n",
+			ZR_DEVNAME(zr), fh->map_mode);
+		break;
+	}
+
+	return 0;
+}
+
+static const struct file_operations zoran_fops = {
+	.owner = THIS_MODULE,
+	.open = zoran_open,
+	.release = zoran_close,
+	.ioctl = zoran_ioctl,
+#ifdef CONFIG_COMPAT
+	.compat_ioctl	= v4l_compat_ioctl32,
+#endif
+	.llseek = no_llseek,
+	.read = zoran_read,
+	.write = zoran_write,
+	.mmap = zoran_mmap,
+	.poll = zoran_poll,
+};
+
+struct video_device zoran_template __devinitdata = {
+	.name = ZORAN_NAME,
+	.fops = &zoran_fops,
+	.release = &zoran_vdev_release,
+	.minor = -1
+};
+
diff --git a/drivers/media/video/zoran_procfs.c b/drivers/media/video/zoran/zoran_procfs.c
similarity index 100%
rename from drivers/media/video/zoran_procfs.c
rename to drivers/media/video/zoran/zoran_procfs.c
diff --git a/drivers/media/video/zoran_procfs.h b/drivers/media/video/zoran/zoran_procfs.h
similarity index 100%
rename from drivers/media/video/zoran_procfs.h
rename to drivers/media/video/zoran/zoran_procfs.h
diff --git a/drivers/media/video/zr36016.c b/drivers/media/video/zoran/zr36016.c
similarity index 100%
rename from drivers/media/video/zr36016.c
rename to drivers/media/video/zoran/zr36016.c
diff --git a/drivers/media/video/zr36016.h b/drivers/media/video/zoran/zr36016.h
similarity index 100%
rename from drivers/media/video/zr36016.h
rename to drivers/media/video/zoran/zr36016.h
diff --git a/drivers/media/video/zr36050.c b/drivers/media/video/zoran/zr36050.c
similarity index 100%
rename from drivers/media/video/zr36050.c
rename to drivers/media/video/zoran/zr36050.c
diff --git a/drivers/media/video/zr36050.h b/drivers/media/video/zoran/zr36050.h
similarity index 100%
rename from drivers/media/video/zr36050.h
rename to drivers/media/video/zoran/zr36050.h
diff --git a/drivers/media/video/zr36057.h b/drivers/media/video/zoran/zr36057.h
similarity index 100%
rename from drivers/media/video/zr36057.h
rename to drivers/media/video/zoran/zr36057.h
diff --git a/drivers/media/video/zr36060.c b/drivers/media/video/zoran/zr36060.c
similarity index 100%
rename from drivers/media/video/zr36060.c
rename to drivers/media/video/zoran/zr36060.c
diff --git a/drivers/media/video/zr36060.h b/drivers/media/video/zoran/zr36060.h
similarity index 100%
rename from drivers/media/video/zr36060.h
rename to drivers/media/video/zoran/zr36060.h
diff --git a/drivers/media/video/zoran_card.c b/drivers/media/video/zoran_card.c
deleted file mode 100644
index d842a7c..0000000
--- a/drivers/media/video/zoran_card.c
+++ /dev/null
@@ -1,1670 +0,0 @@
-/*
- * Zoran zr36057/zr36067 PCI controller driver, for the
- * Pinnacle/Miro DC10/DC10+/DC30/DC30+, Iomega Buz, Linux
- * Media Labs LML33/LML33R10.
- *
- * This part handles card-specific data and detection
- *
- * Copyright (C) 2000 Serguei Miridonov <mirsev@cicese.mx>
- *
- * Currently maintained by:
- *   Ronald Bultje    <rbultje@ronald.bitfreak.net>
- *   Laurent Pinchart <laurent.pinchart@skynet.be>
- *   Mailinglist      <mjpeg-users@lists.sf.net>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU 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/delay.h>
-
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/vmalloc.h>
-
-#include <linux/proc_fs.h>
-#include <linux/i2c.h>
-#include <linux/i2c-algo-bit.h>
-#include <linux/videodev.h>
-#include <media/v4l2-common.h>
-#include <linux/spinlock.h>
-#include <linux/sem.h>
-#include <linux/kmod.h>
-#include <linux/wait.h>
-
-#include <linux/pci.h>
-#include <linux/interrupt.h>
-#include <linux/video_decoder.h>
-#include <linux/video_encoder.h>
-#include <linux/mutex.h>
-
-#include <asm/io.h>
-
-#include "videocodec.h"
-#include "zoran.h"
-#include "zoran_card.h"
-#include "zoran_device.h"
-#include "zoran_procfs.h"
-
-extern const struct zoran_format zoran_formats[];
-
-static int card[BUZ_MAX] = { -1, -1, -1, -1 };
-module_param_array(card, int, NULL, 0444);
-MODULE_PARM_DESC(card, "The type of card");
-
-static int encoder[BUZ_MAX] = { -1, -1, -1, -1 };
-module_param_array(encoder, int, NULL, 0444);
-MODULE_PARM_DESC(encoder, "i2c TV encoder");
-
-static int decoder[BUZ_MAX] = { -1, -1, -1, -1 };
-module_param_array(decoder, int, NULL, 0444);
-MODULE_PARM_DESC(decoder, "i2c TV decoder");
-
-/*
-   The video mem address of the video card.
-   The driver has a little database for some videocards
-   to determine it from there. If your video card is not in there
-   you have either to give it to the driver as a parameter
-   or set in in a VIDIOCSFBUF ioctl
- */
-
-static unsigned long vidmem;	/* default = 0 - Video memory base address */
-module_param(vidmem, ulong, 0444);
-MODULE_PARM_DESC(vidmem, "Default video memory base address");
-
-/*
-   Default input and video norm at startup of the driver.
-*/
-
-static unsigned int default_input;	/* default 0 = Composite, 1 = S-Video */
-module_param(default_input, uint, 0444);
-MODULE_PARM_DESC(default_input,
-		 "Default input (0=Composite, 1=S-Video, 2=Internal)");
-
-static int default_mux = 1;	/* 6 Eyes input selection */
-module_param(default_mux, int, 0644);
-MODULE_PARM_DESC(default_mux,
-		 "Default 6 Eyes mux setting (Input selection)");
-
-static int default_norm;	/* default 0 = PAL, 1 = NTSC 2 = SECAM */
-module_param(default_norm, int, 0444);
-MODULE_PARM_DESC(default_norm, "Default norm (0=PAL, 1=NTSC, 2=SECAM)");
-
-/* /dev/videoN, -1 for autodetect */
-static int video_nr[BUZ_MAX] = {-1, -1, -1, -1};
-module_param_array(video_nr, int, NULL, 0444);
-MODULE_PARM_DESC(video_nr, "video device number (-1=Auto)");
-
-/*
-   Number and size of grab buffers for Video 4 Linux
-   The vast majority of applications should not need more than 2,
-   the very popular BTTV driver actually does ONLY have 2.
-   Time sensitive applications might need more, the maximum
-   is VIDEO_MAX_FRAME (defined in <linux/videodev.h>).
-
-   The size is set so that the maximum possible request
-   can be satisfied. Decrease  it, if bigphys_area alloc'd
-   memory is low. If you don't have the bigphys_area patch,
-   set it to 128 KB. Will you allow only to grab small
-   images with V4L, but that's better than nothing.
-
-   v4l_bufsize has to be given in KB !
-
-*/
-
-int v4l_nbufs = 2;
-int v4l_bufsize = 128;		/* Everybody should be able to work with this setting */
-module_param(v4l_nbufs, int, 0644);
-MODULE_PARM_DESC(v4l_nbufs, "Maximum number of V4L buffers to use");
-module_param(v4l_bufsize, int, 0644);
-MODULE_PARM_DESC(v4l_bufsize, "Maximum size per V4L buffer (in kB)");
-
-int jpg_nbufs = 32;
-int jpg_bufsize = 512;		/* max size for 100% quality full-PAL frame */
-module_param(jpg_nbufs, int, 0644);
-MODULE_PARM_DESC(jpg_nbufs, "Maximum number of JPG buffers to use");
-module_param(jpg_bufsize, int, 0644);
-MODULE_PARM_DESC(jpg_bufsize, "Maximum size per JPG buffer (in kB)");
-
-int pass_through = 0;		/* 1=Pass through TV signal when device is not used */
-				/* 0=Show color bar when device is not used (LML33: only if lml33dpath=1) */
-module_param(pass_through, int, 0644);
-MODULE_PARM_DESC(pass_through,
-		 "Pass TV signal through to TV-out when idling");
-
-int zr36067_debug = 1;
-module_param_named(debug, zr36067_debug, int, 0644);
-MODULE_PARM_DESC(debug, "Debug level (0-5)");
-
-MODULE_DESCRIPTION("Zoran-36057/36067 JPEG codec driver");
-MODULE_AUTHOR("Serguei Miridonov");
-MODULE_LICENSE("GPL");
-
-static struct pci_device_id zr36067_pci_tbl[] = {
-	{PCI_VENDOR_ID_ZORAN, PCI_DEVICE_ID_ZORAN_36057,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{0}
-};
-MODULE_DEVICE_TABLE(pci, zr36067_pci_tbl);
-
-int zoran_num;			/* number of Buzs in use */
-struct zoran *zoran[BUZ_MAX];
-
-/* videocodec bus functions ZR36060 */
-static u32
-zr36060_read (struct videocodec *codec,
-	      u16                reg)
-{
-	struct zoran *zr = (struct zoran *) codec->master_data->data;
-	__u32 data;
-
-	if (post_office_wait(zr)
-	    || post_office_write(zr, 0, 1, reg >> 8)
-	    || post_office_write(zr, 0, 2, reg & 0xff)) {
-		return -1;
-	}
-
-	data = post_office_read(zr, 0, 3) & 0xff;
-	return data;
-}
-
-static void
-zr36060_write (struct videocodec *codec,
-	       u16                reg,
-	       u32                val)
-{
-	struct zoran *zr = (struct zoran *) codec->master_data->data;
-
-	if (post_office_wait(zr)
-	    || post_office_write(zr, 0, 1, reg >> 8)
-	    || post_office_write(zr, 0, 2, reg & 0xff)) {
-		return;
-	}
-
-	post_office_write(zr, 0, 3, val & 0xff);
-}
-
-/* videocodec bus functions ZR36050 */
-static u32
-zr36050_read (struct videocodec *codec,
-	      u16                reg)
-{
-	struct zoran *zr = (struct zoran *) codec->master_data->data;
-	__u32 data;
-
-	if (post_office_wait(zr)
-	    || post_office_write(zr, 1, 0, reg >> 2)) {	// reg. HIGHBYTES
-		return -1;
-	}
-
-	data = post_office_read(zr, 0, reg & 0x03) & 0xff;	// reg. LOWBYTES + read
-	return data;
-}
-
-static void
-zr36050_write (struct videocodec *codec,
-	       u16                reg,
-	       u32                val)
-{
-	struct zoran *zr = (struct zoran *) codec->master_data->data;
-
-	if (post_office_wait(zr)
-	    || post_office_write(zr, 1, 0, reg >> 2)) {	// reg. HIGHBYTES
-		return;
-	}
-
-	post_office_write(zr, 0, reg & 0x03, val & 0xff);	// reg. LOWBYTES + wr. data
-}
-
-/* videocodec bus functions ZR36016 */
-static u32
-zr36016_read (struct videocodec *codec,
-	      u16                reg)
-{
-	struct zoran *zr = (struct zoran *) codec->master_data->data;
-	__u32 data;
-
-	if (post_office_wait(zr)) {
-		return -1;
-	}
-
-	data = post_office_read(zr, 2, reg & 0x03) & 0xff;	// read
-	return data;
-}
-
-/* hack for in zoran_device.c */
-void
-zr36016_write (struct videocodec *codec,
-	       u16                reg,
-	       u32                val)
-{
-	struct zoran *zr = (struct zoran *) codec->master_data->data;
-
-	if (post_office_wait(zr)) {
-		return;
-	}
-
-	post_office_write(zr, 2, reg & 0x03, val & 0x0ff);	// wr. data
-}
-
-/*
- * Board specific information
- */
-
-static void
-dc10_init (struct zoran *zr)
-{
-	dprintk(3, KERN_DEBUG "%s: dc10_init()\n", ZR_DEVNAME(zr));
-
-	/* Pixel clock selection */
-	GPIO(zr, 4, 0);
-	GPIO(zr, 5, 1);
-	/* Enable the video bus sync signals */
-	GPIO(zr, 7, 0);
-}
-
-static void
-dc10plus_init (struct zoran *zr)
-{
-	dprintk(3, KERN_DEBUG "%s: dc10plus_init()\n", ZR_DEVNAME(zr));
-}
-
-static void
-buz_init (struct zoran *zr)
-{
-	dprintk(3, KERN_DEBUG "%s: buz_init()\n", ZR_DEVNAME(zr));
-
-	/* some stuff from Iomega */
-	pci_write_config_dword(zr->pci_dev, 0xfc, 0x90680f15);
-	pci_write_config_dword(zr->pci_dev, 0x0c, 0x00012020);
-	pci_write_config_dword(zr->pci_dev, 0xe8, 0xc0200000);
-}
-
-static void
-lml33_init (struct zoran *zr)
-{
-	dprintk(3, KERN_DEBUG "%s: lml33_init()\n", ZR_DEVNAME(zr));
-
-	GPIO(zr, 2, 1);		// Set Composite input/output
-}
-
-static void
-avs6eyes_init (struct zoran *zr)
-{
-	// AverMedia 6-Eyes original driver by Christer Weinigel
-
-	// Lifted straight from Christer's old driver and
-	// modified slightly by Martin Samuelsson.
-
-	int mux = default_mux; /* 1 = BT866, 7 = VID1 */
-
-	GPIO(zr, 4, 1); /* Bt866 SLEEP on */
-	udelay(2);
-
-	GPIO(zr, 0, 1); /* ZR36060 /RESET on */
-	GPIO(zr, 1, 0); /* ZR36060 /SLEEP on */
-	GPIO(zr, 2, mux & 1);   /* MUX S0 */
-	GPIO(zr, 3, 0); /* /FRAME on */
-	GPIO(zr, 4, 0); /* Bt866 SLEEP off */
-	GPIO(zr, 5, mux & 2);   /* MUX S1 */
-	GPIO(zr, 6, 0); /* ? */
-	GPIO(zr, 7, mux & 4);   /* MUX S2 */
-
-}
-
-static char *
-i2cid_to_modulename (u16 i2c_id)
-{
-	char *name = NULL;
-
-	switch (i2c_id) {
-	case I2C_DRIVERID_SAA7110:
-		name = "saa7110";
-		break;
-	case I2C_DRIVERID_SAA7111A:
-		name = "saa7111";
-		break;
-	case I2C_DRIVERID_SAA7114:
-		name = "saa7114";
-		break;
-	case I2C_DRIVERID_SAA7185B:
-		name = "saa7185";
-		break;
-	case I2C_DRIVERID_ADV7170:
-		name = "adv7170";
-		break;
-	case I2C_DRIVERID_ADV7175:
-		name = "adv7175";
-		break;
-	case I2C_DRIVERID_BT819:
-		name = "bt819";
-		break;
-	case I2C_DRIVERID_BT856:
-		name = "bt856";
-		break;
-	case I2C_DRIVERID_BT866:
-		name = "bt866";
-		break;
-	case I2C_DRIVERID_VPX3220:
-		name = "vpx3220";
-		break;
-	case I2C_DRIVERID_KS0127:
-		name = "ks0127";
-		break;
-	}
-
-	return name;
-}
-
-static char *
-codecid_to_modulename (u16 codecid)
-{
-	char *name = NULL;
-
-	switch (codecid) {
-	case CODEC_TYPE_ZR36060:
-		name = "zr36060";
-		break;
-	case CODEC_TYPE_ZR36050:
-		name = "zr36050";
-		break;
-	case CODEC_TYPE_ZR36016:
-		name = "zr36016";
-		break;
-	}
-
-	return name;
-}
-
-// struct tvnorm {
-//      u16 Wt, Wa, HStart, HSyncStart, Ht, Ha, VStart;
-// };
-
-static struct tvnorm f50sqpixel = { 944, 768, 83, 880, 625, 576, 16 };
-static struct tvnorm f60sqpixel = { 780, 640, 51, 716, 525, 480, 12 };
-static struct tvnorm f50ccir601 = { 864, 720, 75, 804, 625, 576, 18 };
-static struct tvnorm f60ccir601 = { 858, 720, 57, 788, 525, 480, 16 };
-
-static struct tvnorm f50ccir601_lml33 = { 864, 720, 75+34, 804, 625, 576, 18 };
-static struct tvnorm f60ccir601_lml33 = { 858, 720, 57+34, 788, 525, 480, 16 };
-
-/* The DC10 (57/16/50) uses VActive as HSync, so HStart must be 0 */
-static struct tvnorm f50sqpixel_dc10 = { 944, 768, 0, 880, 625, 576, 0 };
-static struct tvnorm f60sqpixel_dc10 = { 780, 640, 0, 716, 525, 480, 12 };
-
-/* FIXME: I cannot swap U and V in saa7114, so i do one
- * pixel left shift in zoran (75 -> 74)
- * (Maxim Yevtyushkin <max@linuxmedialabs.com>) */
-static struct tvnorm f50ccir601_lm33r10 = { 864, 720, 74+54, 804, 625, 576, 18 };
-static struct tvnorm f60ccir601_lm33r10 = { 858, 720, 56+54, 788, 525, 480, 16 };
-
-/* FIXME: The ks0127 seem incapable of swapping U and V, too, which is why I
- * copy Maxim's left shift hack for the 6 Eyes.
- *
- * Christer's driver used the unshifted norms, though...
- * /Sam  */
-static struct tvnorm f50ccir601_avs6eyes = { 864, 720, 74, 804, 625, 576, 18 };
-static struct tvnorm f60ccir601_avs6eyes = { 858, 720, 56, 788, 525, 480, 16 };
-
-static struct card_info zoran_cards[NUM_CARDS] __devinitdata = {
-	{
-		.type = DC10_old,
-		.name = "DC10(old)",
-		.i2c_decoder = I2C_DRIVERID_VPX3220,
-		.video_codec = CODEC_TYPE_ZR36050,
-		.video_vfe = CODEC_TYPE_ZR36016,
-
-		.inputs = 3,
-		.input = {
-			{ 1, "Composite" },
-			{ 2, "S-Video" },
-			{ 0, "Internal/comp" }
-		},
-		.norms = 3,
-		.tvn = {
-			&f50sqpixel_dc10,
-			&f60sqpixel_dc10,
-			&f50sqpixel_dc10
-		},
-		.jpeg_int = 0,
-		.vsync_int = ZR36057_ISR_GIRQ1,
-		.gpio = { 2, 1, -1, 3, 7, 0, 4, 5 },
-		.gpio_pol = { 0, 0, 0, 1, 0, 0, 0, 0 },
-		.gpcs = { -1, 0 },
-		.vfe_pol = { 0, 0, 0, 0, 0, 0, 0, 0 },
-		.gws_not_connected = 0,
-		.input_mux = 0,
-		.init = &dc10_init,
-	}, {
-		.type = DC10_new,
-		.name = "DC10(new)",
-		.i2c_decoder = I2C_DRIVERID_SAA7110,
-		.i2c_encoder = I2C_DRIVERID_ADV7175,
-		.video_codec = CODEC_TYPE_ZR36060,
-
-		.inputs = 3,
-		.input = {
-				{ 0, "Composite" },
-				{ 7, "S-Video" },
-				{ 5, "Internal/comp" }
-			},
-		.norms = 3,
-		.tvn = {
-				&f50sqpixel,
-				&f60sqpixel,
-				&f50sqpixel},
-		.jpeg_int = ZR36057_ISR_GIRQ0,
-		.vsync_int = ZR36057_ISR_GIRQ1,
-		.gpio = { 3, 0, 6, 1, 2, -1, 4, 5 },
-		.gpio_pol = { 0, 0, 0, 0, 0, 0, 0, 0 },
-		.gpcs = { -1, 1},
-		.vfe_pol = { 1, 1, 1, 1, 0, 0, 0, 0 },
-		.gws_not_connected = 0,
-		.input_mux = 0,
-		.init = &dc10plus_init,
-	}, {
-		.type = DC10plus,
-		.name = "DC10plus",
-		.vendor_id = PCI_VENDOR_ID_MIRO,
-		.device_id = PCI_DEVICE_ID_MIRO_DC10PLUS,
-		.i2c_decoder = I2C_DRIVERID_SAA7110,
-		.i2c_encoder = I2C_DRIVERID_ADV7175,
-		.video_codec = CODEC_TYPE_ZR36060,
-
-		.inputs = 3,
-		.input = {
-			{ 0, "Composite" },
-			{ 7, "S-Video" },
-			{ 5, "Internal/comp" }
-		},
-		.norms = 3,
-		.tvn = {
-			&f50sqpixel,
-			&f60sqpixel,
-			&f50sqpixel
-		},
-		.jpeg_int = ZR36057_ISR_GIRQ0,
-		.vsync_int = ZR36057_ISR_GIRQ1,
-		.gpio = { 3, 0, 6, 1, 2, -1, 4, 5 },
-		.gpio_pol = { 0, 0, 0, 0, 0, 0, 0, 0 },
-		.gpcs = { -1, 1 },
-		.vfe_pol = { 1, 1, 1, 1, 0, 0, 0, 0 },
-		.gws_not_connected = 0,
-		.input_mux = 0,
-		.init = &dc10plus_init,
-	}, {
-		.type = DC30,
-		.name = "DC30",
-		.i2c_decoder = I2C_DRIVERID_VPX3220,
-		.i2c_encoder = I2C_DRIVERID_ADV7175,
-		.video_codec = CODEC_TYPE_ZR36050,
-		.video_vfe = CODEC_TYPE_ZR36016,
-
-		.inputs = 3,
-		.input = {
-			{ 1, "Composite" },
-			{ 2, "S-Video" },
-			{ 0, "Internal/comp" }
-		},
-		.norms = 3,
-		.tvn = {
-			&f50sqpixel_dc10,
-			&f60sqpixel_dc10,
-			&f50sqpixel_dc10
-		},
-		.jpeg_int = 0,
-		.vsync_int = ZR36057_ISR_GIRQ1,
-		.gpio = { 2, 1, -1, 3, 7, 0, 4, 5 },
-		.gpio_pol = { 0, 0, 0, 1, 0, 0, 0, 0 },
-		.gpcs = { -1, 0 },
-		.vfe_pol = { 0, 0, 0, 0, 0, 0, 0, 0 },
-		.gws_not_connected = 0,
-		.input_mux = 0,
-		.init = &dc10_init,
-	}, {
-		.type = DC30plus,
-		.name = "DC30plus",
-		.vendor_id = PCI_VENDOR_ID_MIRO,
-		.device_id = PCI_DEVICE_ID_MIRO_DC30PLUS,
-		.i2c_decoder = I2C_DRIVERID_VPX3220,
-		.i2c_encoder = I2C_DRIVERID_ADV7175,
-		.video_codec = CODEC_TYPE_ZR36050,
-		.video_vfe = CODEC_TYPE_ZR36016,
-
-		.inputs = 3,
-		.input = {
-			{ 1, "Composite" },
-			{ 2, "S-Video" },
-			{ 0, "Internal/comp" }
-		},
-		.norms = 3,
-		.tvn = {
-			&f50sqpixel_dc10,
-			&f60sqpixel_dc10,
-			&f50sqpixel_dc10
-		},
-		.jpeg_int = 0,
-		.vsync_int = ZR36057_ISR_GIRQ1,
-		.gpio = { 2, 1, -1, 3, 7, 0, 4, 5 },
-		.gpio_pol = { 0, 0, 0, 1, 0, 0, 0, 0 },
-		.gpcs = { -1, 0 },
-		.vfe_pol = { 0, 0, 0, 0, 0, 0, 0, 0 },
-		.gws_not_connected = 0,
-		.input_mux = 0,
-		.init = &dc10_init,
-	}, {
-		.type = LML33,
-		.name = "LML33",
-		.i2c_decoder = I2C_DRIVERID_BT819,
-		.i2c_encoder = I2C_DRIVERID_BT856,
-		.video_codec = CODEC_TYPE_ZR36060,
-
-		.inputs = 2,
-		.input = {
-			{ 0, "Composite" },
-			{ 7, "S-Video" }
-		},
-		.norms = 2,
-		.tvn = {
-			&f50ccir601_lml33,
-			&f60ccir601_lml33,
-			NULL
-		},
-		.jpeg_int = ZR36057_ISR_GIRQ1,
-		.vsync_int = ZR36057_ISR_GIRQ0,
-		.gpio = { 1, -1, 3, 5, 7, -1, -1, -1 },
-		.gpio_pol = { 0, 0, 0, 0, 1, 0, 0, 0 },
-		.gpcs = { 3, 1 },
-		.vfe_pol = { 1, 1, 0, 0, 0, 1, 0, 0 },
-		.gws_not_connected = 1,
-		.input_mux = 0,
-		.init = &lml33_init,
-	}, {
-		.type = LML33R10,
-		.name = "LML33R10",
-		.vendor_id = PCI_VENDOR_ID_ELECTRONICDESIGNGMBH,
-		.device_id = PCI_DEVICE_ID_LML_33R10,
-		.i2c_decoder = I2C_DRIVERID_SAA7114,
-		.i2c_encoder = I2C_DRIVERID_ADV7170,
-		.video_codec = CODEC_TYPE_ZR36060,
-
-		.inputs = 2,
-		.input = {
-			{ 0, "Composite" },
-			{ 7, "S-Video" }
-		},
-		.norms = 2,
-		.tvn = {
-			&f50ccir601_lm33r10,
-			&f60ccir601_lm33r10,
-			NULL
-		},
-		.jpeg_int = ZR36057_ISR_GIRQ1,
-		.vsync_int = ZR36057_ISR_GIRQ0,
-		.gpio = { 1, -1, 3, 5, 7, -1, -1, -1 },
-		.gpio_pol = { 0, 0, 0, 0, 1, 0, 0, 0 },
-		.gpcs = { 3, 1 },
-		.vfe_pol = { 1, 1, 0, 0, 0, 1, 0, 0 },
-		.gws_not_connected = 1,
-		.input_mux = 0,
-		.init = &lml33_init,
-	}, {
-		.type = BUZ,
-		.name = "Buz",
-		.vendor_id = PCI_VENDOR_ID_IOMEGA,
-		.device_id = PCI_DEVICE_ID_IOMEGA_BUZ,
-		.i2c_decoder = I2C_DRIVERID_SAA7111A,
-		.i2c_encoder = I2C_DRIVERID_SAA7185B,
-		.video_codec = CODEC_TYPE_ZR36060,
-
-		.inputs = 2,
-		.input = {
-			{ 3, "Composite" },
-			{ 7, "S-Video" }
-		},
-		.norms = 3,
-		.tvn = {
-			&f50ccir601,
-			&f60ccir601,
-			&f50ccir601
-		},
-		.jpeg_int = ZR36057_ISR_GIRQ1,
-		.vsync_int = ZR36057_ISR_GIRQ0,
-		.gpio = { 1, -1, 3, -1, -1, -1, -1, -1 },
-		.gpio_pol = { 0, 0, 0, 0, 0, 0, 0, 0 },
-		.gpcs = { 3, 1 },
-		.vfe_pol = { 1, 1, 0, 0, 0, 1, 0, 0 },
-		.gws_not_connected = 1,
-		.input_mux = 0,
-		.init = &buz_init,
-	}, {
-		.type = AVS6EYES,
-		.name = "6-Eyes",
-		/* AverMedia chose not to brand the 6-Eyes. Thus it
-		   can't be autodetected, and requires card=x. */
-		.vendor_id = -1,
-		.device_id = -1,
-		.i2c_decoder = I2C_DRIVERID_KS0127,
-		.i2c_encoder = I2C_DRIVERID_BT866,
-		.video_codec = CODEC_TYPE_ZR36060,
-
-		.inputs = 10,
-		.input = {
-			{ 0, "Composite 1" },
-			{ 1, "Composite 2" },
-			{ 2, "Composite 3" },
-			{ 4, "Composite 4" },
-			{ 5, "Composite 5" },
-			{ 6, "Composite 6" },
-			{ 8, "S-Video 1" },
-			{ 9, "S-Video 2" },
-			{10, "S-Video 3" },
-			{15, "YCbCr" }
-		},
-		.norms = 2,
-		.tvn = {
-			&f50ccir601_avs6eyes,
-			&f60ccir601_avs6eyes,
-			NULL
-		},
-		.jpeg_int = ZR36057_ISR_GIRQ1,
-		.vsync_int = ZR36057_ISR_GIRQ0,
-		.gpio = { 1, 0, 3, -1, -1, -1, -1, -1 },// Validity unknown /Sam
-		.gpio_pol = { 0, 0, 0, 0, 0, 0, 0, 0 }, // Validity unknown /Sam
-		.gpcs = { 3, 1 },			// Validity unknown /Sam
-		.vfe_pol = { 1, 0, 0, 0, 0, 1, 0, 0 },  // Validity unknown /Sam
-		.gws_not_connected = 1,
-		.input_mux = 1,
-		.init = &avs6eyes_init,
-	}
-
-};
-
-/*
- * I2C functions
- */
-/* software I2C functions */
-static int
-zoran_i2c_getsda (void *data)
-{
-	struct zoran *zr = (struct zoran *) data;
-
-	return (btread(ZR36057_I2CBR) >> 1) & 1;
-}
-
-static int
-zoran_i2c_getscl (void *data)
-{
-	struct zoran *zr = (struct zoran *) data;
-
-	return btread(ZR36057_I2CBR) & 1;
-}
-
-static void
-zoran_i2c_setsda (void *data,
-		  int   state)
-{
-	struct zoran *zr = (struct zoran *) data;
-
-	if (state)
-		zr->i2cbr |= 2;
-	else
-		zr->i2cbr &= ~2;
-	btwrite(zr->i2cbr, ZR36057_I2CBR);
-}
-
-static void
-zoran_i2c_setscl (void *data,
-		  int   state)
-{
-	struct zoran *zr = (struct zoran *) data;
-
-	if (state)
-		zr->i2cbr |= 1;
-	else
-		zr->i2cbr &= ~1;
-	btwrite(zr->i2cbr, ZR36057_I2CBR);
-}
-
-static int
-zoran_i2c_client_register (struct i2c_client *client)
-{
-	struct zoran *zr = (struct zoran *) i2c_get_adapdata(client->adapter);
-	int res = 0;
-
-	dprintk(2,
-		KERN_DEBUG "%s: i2c_client_register() - driver id = %d\n",
-		ZR_DEVNAME(zr), client->driver->id);
-
-	mutex_lock(&zr->resource_lock);
-
-	if (zr->user > 0) {
-		/* we're already busy, so we keep a reference to
-		 * them... Could do a lot of stuff here, but this
-		 * is easiest. (Did I ever mention I'm a lazy ass?)
-		 */
-		res = -EBUSY;
-		goto clientreg_unlock_and_return;
-	}
-
-	if (client->driver->id == zr->card.i2c_decoder)
-		zr->decoder = client;
-	else if (client->driver->id == zr->card.i2c_encoder)
-		zr->encoder = client;
-	else {
-		res = -ENODEV;
-		goto clientreg_unlock_and_return;
-	}
-
-clientreg_unlock_and_return:
-	mutex_unlock(&zr->resource_lock);
-
-	return res;
-}
-
-static int
-zoran_i2c_client_unregister (struct i2c_client *client)
-{
-	struct zoran *zr = (struct zoran *) i2c_get_adapdata(client->adapter);
-	int res = 0;
-
-	dprintk(2, KERN_DEBUG "%s: i2c_client_unregister()\n", ZR_DEVNAME(zr));
-
-	mutex_lock(&zr->resource_lock);
-
-	if (zr->user > 0) {
-		res = -EBUSY;
-		goto clientunreg_unlock_and_return;
-	}
-
-	/* try to locate it */
-	if (client == zr->encoder) {
-		zr->encoder = NULL;
-	} else if (client == zr->decoder) {
-		zr->decoder = NULL;
-		snprintf(ZR_DEVNAME(zr), sizeof(ZR_DEVNAME(zr)), "MJPEG[%d]", zr->id);
-	}
-clientunreg_unlock_and_return:
-	mutex_unlock(&zr->resource_lock);
-	return res;
-}
-
-static const struct i2c_algo_bit_data zoran_i2c_bit_data_template = {
-	.setsda = zoran_i2c_setsda,
-	.setscl = zoran_i2c_setscl,
-	.getsda = zoran_i2c_getsda,
-	.getscl = zoran_i2c_getscl,
-	.udelay = 10,
-	.timeout = 100,
-};
-
-static int
-zoran_register_i2c (struct zoran *zr)
-{
-	memcpy(&zr->i2c_algo, &zoran_i2c_bit_data_template,
-	       sizeof(struct i2c_algo_bit_data));
-	zr->i2c_algo.data = zr;
-	zr->i2c_adapter.id = I2C_HW_B_ZR36067;
-	zr->i2c_adapter.client_register = zoran_i2c_client_register;
-	zr->i2c_adapter.client_unregister = zoran_i2c_client_unregister;
-	strlcpy(zr->i2c_adapter.name, ZR_DEVNAME(zr),
-		sizeof(zr->i2c_adapter.name));
-	i2c_set_adapdata(&zr->i2c_adapter, zr);
-	zr->i2c_adapter.algo_data = &zr->i2c_algo;
-	zr->i2c_adapter.dev.parent = &zr->pci_dev->dev;
-	return i2c_bit_add_bus(&zr->i2c_adapter);
-}
-
-static void
-zoran_unregister_i2c (struct zoran *zr)
-{
-	i2c_del_adapter(&zr->i2c_adapter);
-}
-
-/* Check a zoran_params struct for correctness, insert default params */
-
-int
-zoran_check_jpg_settings (struct zoran              *zr,
-			  struct zoran_jpg_settings *settings)
-{
-	int err = 0, err0 = 0;
-
-	dprintk(4,
-		KERN_DEBUG
-		"%s: check_jpg_settings() - dec: %d, Hdcm: %d, Vdcm: %d, Tdcm: %d\n",
-		ZR_DEVNAME(zr), settings->decimation, settings->HorDcm,
-		settings->VerDcm, settings->TmpDcm);
-	dprintk(4,
-		KERN_DEBUG
-		"%s: check_jpg_settings() - x: %d, y: %d, w: %d, y: %d\n",
-		ZR_DEVNAME(zr), settings->img_x, settings->img_y,
-		settings->img_width, settings->img_height);
-	/* Check decimation, set default values for decimation = 1, 2, 4 */
-	switch (settings->decimation) {
-	case 1:
-
-		settings->HorDcm = 1;
-		settings->VerDcm = 1;
-		settings->TmpDcm = 1;
-		settings->field_per_buff = 2;
-		settings->img_x = 0;
-		settings->img_y = 0;
-		settings->img_width = BUZ_MAX_WIDTH;
-		settings->img_height = BUZ_MAX_HEIGHT / 2;
-		break;
-	case 2:
-
-		settings->HorDcm = 2;
-		settings->VerDcm = 1;
-		settings->TmpDcm = 2;
-		settings->field_per_buff = 1;
-		settings->img_x = (BUZ_MAX_WIDTH == 720) ? 8 : 0;
-		settings->img_y = 0;
-		settings->img_width =
-		    (BUZ_MAX_WIDTH == 720) ? 704 : BUZ_MAX_WIDTH;
-		settings->img_height = BUZ_MAX_HEIGHT / 2;
-		break;
-	case 4:
-
-		if (zr->card.type == DC10_new) {
-			dprintk(1,
-				KERN_DEBUG
-				"%s: check_jpg_settings() - HDec by 4 is not supported on the DC10\n",
-				ZR_DEVNAME(zr));
-			err0++;
-			break;
-		}
-
-		settings->HorDcm = 4;
-		settings->VerDcm = 2;
-		settings->TmpDcm = 2;
-		settings->field_per_buff = 1;
-		settings->img_x = (BUZ_MAX_WIDTH == 720) ? 8 : 0;
-		settings->img_y = 0;
-		settings->img_width =
-		    (BUZ_MAX_WIDTH == 720) ? 704 : BUZ_MAX_WIDTH;
-		settings->img_height = BUZ_MAX_HEIGHT / 2;
-		break;
-	case 0:
-
-		/* We have to check the data the user has set */
-
-		if (settings->HorDcm != 1 && settings->HorDcm != 2 &&
-		    (zr->card.type == DC10_new || settings->HorDcm != 4))
-			err0++;
-		if (settings->VerDcm != 1 && settings->VerDcm != 2)
-			err0++;
-		if (settings->TmpDcm != 1 && settings->TmpDcm != 2)
-			err0++;
-		if (settings->field_per_buff != 1 &&
-		    settings->field_per_buff != 2)
-			err0++;
-		if (settings->img_x < 0)
-			err0++;
-		if (settings->img_y < 0)
-			err0++;
-		if (settings->img_width < 0)
-			err0++;
-		if (settings->img_height < 0)
-			err0++;
-		if (settings->img_x + settings->img_width > BUZ_MAX_WIDTH)
-			err0++;
-		if (settings->img_y + settings->img_height >
-		    BUZ_MAX_HEIGHT / 2)
-			err0++;
-		if (settings->HorDcm && settings->VerDcm) {
-			if (settings->img_width %
-			    (16 * settings->HorDcm) != 0)
-				err0++;
-			if (settings->img_height %
-			    (8 * settings->VerDcm) != 0)
-				err0++;
-		}
-
-		if (err0) {
-			dprintk(1,
-				KERN_ERR
-				"%s: check_jpg_settings() - error in params for decimation = 0\n",
-				ZR_DEVNAME(zr));
-			err++;
-		}
-		break;
-	default:
-		dprintk(1,
-			KERN_ERR
-			"%s: check_jpg_settings() - decimation = %d, must be 0, 1, 2 or 4\n",
-			ZR_DEVNAME(zr), settings->decimation);
-		err++;
-		break;
-	}
-
-	if (settings->jpg_comp.quality > 100)
-		settings->jpg_comp.quality = 100;
-	if (settings->jpg_comp.quality < 5)
-		settings->jpg_comp.quality = 5;
-	if (settings->jpg_comp.APPn < 0)
-		settings->jpg_comp.APPn = 0;
-	if (settings->jpg_comp.APPn > 15)
-		settings->jpg_comp.APPn = 15;
-	if (settings->jpg_comp.APP_len < 0)
-		settings->jpg_comp.APP_len = 0;
-	if (settings->jpg_comp.APP_len > 60)
-		settings->jpg_comp.APP_len = 60;
-	if (settings->jpg_comp.COM_len < 0)
-		settings->jpg_comp.COM_len = 0;
-	if (settings->jpg_comp.COM_len > 60)
-		settings->jpg_comp.COM_len = 60;
-	if (err)
-		return -EINVAL;
-	return 0;
-}
-
-void
-zoran_open_init_params (struct zoran *zr)
-{
-	int i;
-
-	/* User must explicitly set a window */
-	zr->overlay_settings.is_set = 0;
-	zr->overlay_mask = NULL;
-	zr->overlay_active = ZORAN_FREE;
-
-	zr->v4l_memgrab_active = 0;
-	zr->v4l_overlay_active = 0;
-	zr->v4l_grab_frame = NO_GRAB_ACTIVE;
-	zr->v4l_grab_seq = 0;
-	zr->v4l_settings.width = 192;
-	zr->v4l_settings.height = 144;
-	zr->v4l_settings.format = &zoran_formats[4];	/* YUY2 - YUV-4:2:2 packed */
-	zr->v4l_settings.bytesperline =
-	    zr->v4l_settings.width *
-	    ((zr->v4l_settings.format->depth + 7) / 8);
-
-	/* DMA ring stuff for V4L */
-	zr->v4l_pend_tail = 0;
-	zr->v4l_pend_head = 0;
-	zr->v4l_sync_tail = 0;
-	zr->v4l_buffers.active = ZORAN_FREE;
-	for (i = 0; i < VIDEO_MAX_FRAME; i++) {
-		zr->v4l_buffers.buffer[i].state = BUZ_STATE_USER;	/* nothing going on */
-	}
-	zr->v4l_buffers.allocated = 0;
-
-	for (i = 0; i < BUZ_MAX_FRAME; i++) {
-		zr->jpg_buffers.buffer[i].state = BUZ_STATE_USER;	/* nothing going on */
-	}
-	zr->jpg_buffers.active = ZORAN_FREE;
-	zr->jpg_buffers.allocated = 0;
-	/* Set necessary params and call zoran_check_jpg_settings to set the defaults */
-	zr->jpg_settings.decimation = 1;
-	zr->jpg_settings.jpg_comp.quality = 50;	/* default compression factor 8 */
-	if (zr->card.type != BUZ)
-		zr->jpg_settings.odd_even = 1;
-	else
-		zr->jpg_settings.odd_even = 0;
-	zr->jpg_settings.jpg_comp.APPn = 0;
-	zr->jpg_settings.jpg_comp.APP_len = 0;	/* No APPn marker */
-	memset(zr->jpg_settings.jpg_comp.APP_data, 0,
-	       sizeof(zr->jpg_settings.jpg_comp.APP_data));
-	zr->jpg_settings.jpg_comp.COM_len = 0;	/* No COM marker */
-	memset(zr->jpg_settings.jpg_comp.COM_data, 0,
-	       sizeof(zr->jpg_settings.jpg_comp.COM_data));
-	zr->jpg_settings.jpg_comp.jpeg_markers =
-	    JPEG_MARKER_DHT | JPEG_MARKER_DQT;
-	i = zoran_check_jpg_settings(zr, &zr->jpg_settings);
-	if (i)
-		dprintk(1,
-			KERN_ERR
-			"%s: zoran_open_init_params() internal error\n",
-			ZR_DEVNAME(zr));
-
-	clear_interrupt_counters(zr);
-	zr->testing = 0;
-}
-
-static void __devinit
-test_interrupts (struct zoran *zr)
-{
-	DEFINE_WAIT(wait);
-	int timeout, icr;
-
-	clear_interrupt_counters(zr);
-
-	zr->testing = 1;
-	icr = btread(ZR36057_ICR);
-	btwrite(0x78000000 | ZR36057_ICR_IntPinEn, ZR36057_ICR);
-	prepare_to_wait(&zr->test_q, &wait, TASK_INTERRUPTIBLE);
-	timeout = schedule_timeout(HZ);
-	finish_wait(&zr->test_q, &wait);
-	btwrite(0, ZR36057_ICR);
-	btwrite(0x78000000, ZR36057_ISR);
-	zr->testing = 0;
-	dprintk(5, KERN_INFO "%s: Testing interrupts...\n", ZR_DEVNAME(zr));
-	if (timeout) {
-		dprintk(1, ": time spent: %d\n", 1 * HZ - timeout);
-	}
-	if (zr36067_debug > 1)
-		print_interrupts(zr);
-	btwrite(icr, ZR36057_ICR);
-}
-
-static int __devinit
-zr36057_init (struct zoran *zr)
-{
-	int j, err;
-	int two = 2;
-	int zero = 0;
-
-	dprintk(1,
-		KERN_INFO
-		"%s: zr36057_init() - initializing card[%d], zr=%p\n",
-		ZR_DEVNAME(zr), zr->id, zr);
-
-	/* default setup of all parameters which will persist between opens */
-	zr->user = 0;
-
-	init_waitqueue_head(&zr->v4l_capq);
-	init_waitqueue_head(&zr->jpg_capq);
-	init_waitqueue_head(&zr->test_q);
-	zr->jpg_buffers.allocated = 0;
-	zr->v4l_buffers.allocated = 0;
-
-	zr->buffer.base = (void *) vidmem;
-	zr->buffer.width = 0;
-	zr->buffer.height = 0;
-	zr->buffer.depth = 0;
-	zr->buffer.bytesperline = 0;
-
-	/* Avoid nonsense settings from user for default input/norm */
-	if (default_norm < VIDEO_MODE_PAL &&
-	    default_norm > VIDEO_MODE_SECAM)
-		default_norm = VIDEO_MODE_PAL;
-	zr->norm = default_norm;
-	if (!(zr->timing = zr->card.tvn[zr->norm])) {
-		dprintk(1,
-			KERN_WARNING
-			"%s: zr36057_init() - default TV standard not supported by hardware. PAL will be used.\n",
-			ZR_DEVNAME(zr));
-		zr->norm = VIDEO_MODE_PAL;
-		zr->timing = zr->card.tvn[zr->norm];
-	}
-
-	if (default_input > zr->card.inputs-1) {
-		dprintk(1,
-			KERN_WARNING
-			"%s: default_input value %d out of range (0-%d)\n",
-			ZR_DEVNAME(zr), default_input, zr->card.inputs-1);
-		default_input = 0;
-	}
-	zr->input = default_input;
-
-	/* Should the following be reset at every open ? */
-	zr->hue = 32768;
-	zr->contrast = 32768;
-	zr->saturation = 32768;
-	zr->brightness = 32768;
-
-	/* default setup (will be repeated at every open) */
-	zoran_open_init_params(zr);
-
-	/* allocate memory *before* doing anything to the hardware
-	 * in case allocation fails */
-	zr->stat_com = kzalloc(BUZ_NUM_STAT_COM * 4, GFP_KERNEL);
-	zr->video_dev = kmalloc(sizeof(struct video_device), GFP_KERNEL);
-	if (!zr->stat_com || !zr->video_dev) {
-		dprintk(1,
-			KERN_ERR
-			"%s: zr36057_init() - kmalloc (STAT_COM) failed\n",
-			ZR_DEVNAME(zr));
-		err = -ENOMEM;
-		goto exit_free;
-	}
-	for (j = 0; j < BUZ_NUM_STAT_COM; j++) {
-		zr->stat_com[j] = cpu_to_le32(1); /* mark as unavailable to zr36057 */
-	}
-
-	/*
-	 *   Now add the template and register the device unit.
-	 */
-	memcpy(zr->video_dev, &zoran_template, sizeof(zoran_template));
-	strcpy(zr->video_dev->name, ZR_DEVNAME(zr));
-	err = video_register_device(zr->video_dev, VFL_TYPE_GRABBER, video_nr[zr->id]);
-	if (err < 0)
-		goto exit_unregister;
-
-	zoran_init_hardware(zr);
-	if (zr36067_debug > 2)
-		detect_guest_activity(zr);
-	test_interrupts(zr);
-	if (!pass_through) {
-		decoder_command(zr, DECODER_ENABLE_OUTPUT, &zero);
-		encoder_command(zr, ENCODER_SET_INPUT, &two);
-	}
-
-	zr->zoran_proc = NULL;
-	zr->initialized = 1;
-	return 0;
-
-exit_unregister:
-	zoran_unregister_i2c(zr);
-exit_free:
-	kfree(zr->stat_com);
-	kfree(zr->video_dev);
-	return err;
-}
-
-static void
-zoran_release (struct zoran *zr)
-{
-	if (!zr->initialized)
-		goto exit_free;
-	/* unregister videocodec bus */
-	if (zr->codec) {
-		struct videocodec_master *master = zr->codec->master_data;
-
-		videocodec_detach(zr->codec);
-		kfree(master);
-	}
-	if (zr->vfe) {
-		struct videocodec_master *master = zr->vfe->master_data;
-
-		videocodec_detach(zr->vfe);
-		kfree(master);
-	}
-
-	/* unregister i2c bus */
-	zoran_unregister_i2c(zr);
-	/* disable PCI bus-mastering */
-	zoran_set_pci_master(zr, 0);
-	/* put chip into reset */
-	btwrite(0, ZR36057_SPGPPCR);
-	free_irq(zr->pci_dev->irq, zr);
-	/* unmap and free memory */
-	kfree(zr->stat_com);
-	zoran_proc_cleanup(zr);
-	iounmap(zr->zr36057_mem);
-	pci_disable_device(zr->pci_dev);
-	video_unregister_device(zr->video_dev);
-exit_free:
-	kfree(zr);
-}
-
-void
-zoran_vdev_release (struct video_device *vdev)
-{
-	kfree(vdev);
-}
-
-static struct videocodec_master * __devinit
-zoran_setup_videocodec (struct zoran *zr,
-			int           type)
-{
-	struct videocodec_master *m = NULL;
-
-	m = kmalloc(sizeof(struct videocodec_master), GFP_KERNEL);
-	if (!m) {
-		dprintk(1,
-			KERN_ERR
-			"%s: zoran_setup_videocodec() - no memory\n",
-			ZR_DEVNAME(zr));
-		return m;
-	}
-
-	/* magic and type are unused for master struct. Makes sense only at
-	   codec structs.
-	   In the past, .type were initialized to the old V4L1 .hardware
-	   value, as VID_HARDWARE_ZR36067
-	 */
-	m->magic = 0L;
-	m->type = 0;
-
-	m->flags = CODEC_FLAG_ENCODER | CODEC_FLAG_DECODER;
-	strncpy(m->name, ZR_DEVNAME(zr), sizeof(m->name));
-	m->data = zr;
-
-	switch (type)
-	{
-	case CODEC_TYPE_ZR36060:
-		m->readreg = zr36060_read;
-		m->writereg = zr36060_write;
-		m->flags |= CODEC_FLAG_JPEG | CODEC_FLAG_VFE;
-		break;
-	case CODEC_TYPE_ZR36050:
-		m->readreg = zr36050_read;
-		m->writereg = zr36050_write;
-		m->flags |= CODEC_FLAG_JPEG;
-		break;
-	case CODEC_TYPE_ZR36016:
-		m->readreg = zr36016_read;
-		m->writereg = zr36016_write;
-		m->flags |= CODEC_FLAG_VFE;
-		break;
-	}
-
-	return m;
-}
-
-/*
- *   Scan for a Buz card (actually for the PCI controller ZR36057),
- *   request the irq and map the io memory
- */
-static int __devinit
-find_zr36057 (void)
-{
-	unsigned char latency, need_latency;
-	struct zoran *zr;
-	struct pci_dev *dev = NULL;
-	int result;
-	struct videocodec_master *master_vfe = NULL;
-	struct videocodec_master *master_codec = NULL;
-	int card_num;
-	char *i2c_enc_name, *i2c_dec_name, *codec_name, *vfe_name;
-
-	zoran_num = 0;
-	while (zoran_num < BUZ_MAX &&
-	       (dev = pci_get_device(PCI_VENDOR_ID_ZORAN, PCI_DEVICE_ID_ZORAN_36057, dev)) != NULL) {
-		card_num = card[zoran_num];
-		zr = kzalloc(sizeof(struct zoran), GFP_KERNEL);
-		if (!zr) {
-			dprintk(1,
-				KERN_ERR
-				"%s: find_zr36057() - kzalloc failed\n",
-				ZORAN_NAME);
-			continue;
-		}
-		zr->pci_dev = dev;
-		//zr->zr36057_mem = NULL;
-		zr->id = zoran_num;
-		snprintf(ZR_DEVNAME(zr), sizeof(ZR_DEVNAME(zr)), "MJPEG[%u]", zr->id);
-		spin_lock_init(&zr->spinlock);
-		mutex_init(&zr->resource_lock);
-		if (pci_enable_device(dev))
-			goto zr_free_mem;
-		zr->zr36057_adr = pci_resource_start(zr->pci_dev, 0);
-		pci_read_config_byte(zr->pci_dev, PCI_CLASS_REVISION,
-				     &zr->revision);
-		if (zr->revision < 2) {
-			dprintk(1,
-				KERN_INFO
-				"%s: Zoran ZR36057 (rev %d) irq: %d, memory: 0x%08x.\n",
-				ZR_DEVNAME(zr), zr->revision, zr->pci_dev->irq,
-				zr->zr36057_adr);
-
-			if (card_num == -1) {
-				dprintk(1,
-					KERN_ERR
-					"%s: find_zr36057() - no card specified, please use the card=X insmod option\n",
-					ZR_DEVNAME(zr));
-				goto zr_free_mem;
-			}
-		} else {
-			int i;
-			unsigned short ss_vendor, ss_device;
-
-			ss_vendor = zr->pci_dev->subsystem_vendor;
-			ss_device = zr->pci_dev->subsystem_device;
-			dprintk(1,
-				KERN_INFO
-				"%s: Zoran ZR36067 (rev %d) irq: %d, memory: 0x%08x\n",
-				ZR_DEVNAME(zr), zr->revision, zr->pci_dev->irq,
-				zr->zr36057_adr);
-			dprintk(1,
-				KERN_INFO
-				"%s: subsystem vendor=0x%04x id=0x%04x\n",
-				ZR_DEVNAME(zr), ss_vendor, ss_device);
-			if (card_num == -1) {
-				dprintk(3,
-					KERN_DEBUG
-					"%s: find_zr36057() - trying to autodetect card type\n",
-					ZR_DEVNAME(zr));
-				for (i=0;i<NUM_CARDS;i++) {
-					if (ss_vendor == zoran_cards[i].vendor_id &&
-					    ss_device == zoran_cards[i].device_id) {
-						dprintk(3,
-							KERN_DEBUG
-							"%s: find_zr36057() - card %s detected\n",
-							ZR_DEVNAME(zr),
-							zoran_cards[i].name);
-						card_num = i;
-						break;
-					}
-				}
-				if (i == NUM_CARDS) {
-					dprintk(1,
-						KERN_ERR
-						"%s: find_zr36057() - unknown card\n",
-						ZR_DEVNAME(zr));
-					goto zr_free_mem;
-				}
-			}
-		}
-
-		if (card_num < 0 || card_num >= NUM_CARDS) {
-			dprintk(2,
-				KERN_ERR
-				"%s: find_zr36057() - invalid cardnum %d\n",
-				ZR_DEVNAME(zr), card_num);
-			goto zr_free_mem;
-		}
-
-		/* even though we make this a non pointer and thus
-		 * theoretically allow for making changes to this struct
-		 * on a per-individual card basis at runtime, this is
-		 * strongly discouraged. This structure is intended to
-		 * keep general card information, no settings or anything */
-		zr->card = zoran_cards[card_num];
-		snprintf(ZR_DEVNAME(zr), sizeof(ZR_DEVNAME(zr)),
-			 "%s[%u]", zr->card.name, zr->id);
-
-		zr->zr36057_mem = ioremap_nocache(zr->zr36057_adr, 0x1000);
-		if (!zr->zr36057_mem) {
-			dprintk(1,
-				KERN_ERR
-				"%s: find_zr36057() - ioremap failed\n",
-				ZR_DEVNAME(zr));
-			goto zr_free_mem;
-		}
-
-		result = request_irq(zr->pci_dev->irq,
-				     zoran_irq,
-				     IRQF_SHARED | IRQF_DISABLED,
-				     ZR_DEVNAME(zr),
-				     (void *) zr);
-		if (result < 0) {
-			if (result == -EINVAL) {
-				dprintk(1,
-					KERN_ERR
-					"%s: find_zr36057() - bad irq number or handler\n",
-					ZR_DEVNAME(zr));
-			} else if (result == -EBUSY) {
-				dprintk(1,
-					KERN_ERR
-					"%s: find_zr36057() - IRQ %d busy, change your PnP config in BIOS\n",
-					ZR_DEVNAME(zr), zr->pci_dev->irq);
-			} else {
-				dprintk(1,
-					KERN_ERR
-					"%s: find_zr36057() - can't assign irq, error code %d\n",
-					ZR_DEVNAME(zr), result);
-			}
-			goto zr_unmap;
-		}
-
-		/* set PCI latency timer */
-		pci_read_config_byte(zr->pci_dev, PCI_LATENCY_TIMER,
-				     &latency);
-		need_latency = zr->revision > 1 ? 32 : 48;
-		if (latency != need_latency) {
-			dprintk(2,
-				KERN_INFO
-				"%s: Changing PCI latency from %d to %d.\n",
-				ZR_DEVNAME(zr), latency, need_latency);
-			pci_write_config_byte(zr->pci_dev,
-					      PCI_LATENCY_TIMER,
-					      need_latency);
-		}
-
-		zr36057_restart(zr);
-		/* i2c */
-		dprintk(2, KERN_INFO "%s: Initializing i2c bus...\n",
-			ZR_DEVNAME(zr));
-
-		/* i2c decoder */
-		if (decoder[zr->id] != -1) {
-			i2c_dec_name = i2cid_to_modulename(decoder[zr->id]);
-			zr->card.i2c_decoder = decoder[zr->id];
-		} else if (zr->card.i2c_decoder != 0) {
-			i2c_dec_name =
-				i2cid_to_modulename(zr->card.i2c_decoder);
-		} else {
-			i2c_dec_name = NULL;
-		}
-
-		if (i2c_dec_name) {
-			if ((result = request_module(i2c_dec_name)) < 0) {
-				dprintk(1,
-					KERN_ERR
-					"%s: failed to load module %s: %d\n",
-					ZR_DEVNAME(zr), i2c_dec_name, result);
-			}
-		}
-
-		/* i2c encoder */
-		if (encoder[zr->id] != -1) {
-			i2c_enc_name = i2cid_to_modulename(encoder[zr->id]);
-			zr->card.i2c_encoder = encoder[zr->id];
-		} else if (zr->card.i2c_encoder != 0) {
-			i2c_enc_name =
-				i2cid_to_modulename(zr->card.i2c_encoder);
-		} else {
-			i2c_enc_name = NULL;
-		}
-
-		if (i2c_enc_name) {
-			if ((result = request_module(i2c_enc_name)) < 0) {
-				dprintk(1,
-					KERN_ERR
-					"%s: failed to load module %s: %d\n",
-					ZR_DEVNAME(zr), i2c_enc_name, result);
-			}
-		}
-
-		if (zoran_register_i2c(zr) < 0) {
-			dprintk(1,
-				KERN_ERR
-				"%s: find_zr36057() - can't initialize i2c bus\n",
-				ZR_DEVNAME(zr));
-			goto zr_free_irq;
-		}
-
-		dprintk(2,
-			KERN_INFO "%s: Initializing videocodec bus...\n",
-			ZR_DEVNAME(zr));
-
-		if (zr->card.video_codec != 0 &&
-		    (codec_name =
-		     codecid_to_modulename(zr->card.video_codec)) != NULL) {
-			if ((result = request_module(codec_name)) < 0) {
-				dprintk(1,
-					KERN_ERR
-					"%s: failed to load modules %s: %d\n",
-					ZR_DEVNAME(zr), codec_name, result);
-			}
-		}
-		if (zr->card.video_vfe != 0 &&
-		    (vfe_name =
-		     codecid_to_modulename(zr->card.video_vfe)) != NULL) {
-			if ((result = request_module(vfe_name)) < 0) {
-				dprintk(1,
-					KERN_ERR
-					"%s: failed to load modules %s: %d\n",
-					ZR_DEVNAME(zr), vfe_name, result);
-			}
-		}
-
-		/* reset JPEG codec */
-		jpeg_codec_sleep(zr, 1);
-		jpeg_codec_reset(zr);
-		/* video bus enabled */
-		/* display codec revision */
-		if (zr->card.video_codec != 0) {
-			master_codec = zoran_setup_videocodec(zr,
-							      zr->card.video_codec);
-			if (!master_codec)
-				goto zr_unreg_i2c;
-			zr->codec = videocodec_attach(master_codec);
-			if (!zr->codec) {
-				dprintk(1,
-					KERN_ERR
-					"%s: find_zr36057() - no codec found\n",
-					ZR_DEVNAME(zr));
-				goto zr_free_codec;
-			}
-			if (zr->codec->type != zr->card.video_codec) {
-				dprintk(1,
-					KERN_ERR
-					"%s: find_zr36057() - wrong codec\n",
-					ZR_DEVNAME(zr));
-				goto zr_detach_codec;
-			}
-		}
-		if (zr->card.video_vfe != 0) {
-			master_vfe = zoran_setup_videocodec(zr,
-							    zr->card.video_vfe);
-			if (!master_vfe)
-				goto zr_detach_codec;
-			zr->vfe = videocodec_attach(master_vfe);
-			if (!zr->vfe) {
-				dprintk(1,
-					KERN_ERR
-					"%s: find_zr36057() - no VFE found\n",
-					ZR_DEVNAME(zr));
-				goto zr_free_vfe;
-			}
-			if (zr->vfe->type != zr->card.video_vfe) {
-				dprintk(1,
-					KERN_ERR
-					"%s: find_zr36057() = wrong VFE\n",
-					ZR_DEVNAME(zr));
-				goto zr_detach_vfe;
-			}
-		}
-		/* Success so keep the pci_dev referenced */
-		pci_dev_get(zr->pci_dev);
-		zoran[zoran_num++] = zr;
-		continue;
-
-		// Init errors
-	      zr_detach_vfe:
-		videocodec_detach(zr->vfe);
-	      zr_free_vfe:
-		kfree(master_vfe);
-	      zr_detach_codec:
-		videocodec_detach(zr->codec);
-	      zr_free_codec:
-		kfree(master_codec);
-	      zr_unreg_i2c:
-		zoran_unregister_i2c(zr);
-	      zr_free_irq:
-		btwrite(0, ZR36057_SPGPPCR);
-		free_irq(zr->pci_dev->irq, zr);
-	      zr_unmap:
-		iounmap(zr->zr36057_mem);
-	      zr_free_mem:
-		kfree(zr);
-		continue;
-	}
-	if (dev)	/* Clean up ref count on early exit */
-		pci_dev_put(dev);
-
-	if (zoran_num == 0) {
-		dprintk(1, KERN_INFO "No known MJPEG cards found.\n");
-	}
-	return zoran_num;
-}
-
-static int __init
-init_dc10_cards (void)
-{
-	int i;
-
-	memset(zoran, 0, sizeof(zoran));
-	printk(KERN_INFO "Zoran MJPEG board driver version %d.%d.%d\n",
-	       MAJOR_VERSION, MINOR_VERSION, RELEASE_VERSION);
-
-	/* Look for cards */
-	if (find_zr36057() < 0) {
-		return -EIO;
-	}
-	if (zoran_num == 0)
-		return -ENODEV;
-	dprintk(1, KERN_INFO "%s: %d card(s) found\n", ZORAN_NAME,
-		zoran_num);
-	/* check the parameters we have been given, adjust if necessary */
-	if (v4l_nbufs < 2)
-		v4l_nbufs = 2;
-	if (v4l_nbufs > VIDEO_MAX_FRAME)
-		v4l_nbufs = VIDEO_MAX_FRAME;
-	/* The user specfies the in KB, we want them in byte
-	 * (and page aligned) */
-	v4l_bufsize = PAGE_ALIGN(v4l_bufsize * 1024);
-	if (v4l_bufsize < 32768)
-		v4l_bufsize = 32768;
-	/* 2 MB is arbitrary but sufficient for the maximum possible images */
-	if (v4l_bufsize > 2048 * 1024)
-		v4l_bufsize = 2048 * 1024;
-	if (jpg_nbufs < 4)
-		jpg_nbufs = 4;
-	if (jpg_nbufs > BUZ_MAX_FRAME)
-		jpg_nbufs = BUZ_MAX_FRAME;
-	jpg_bufsize = PAGE_ALIGN(jpg_bufsize * 1024);
-	if (jpg_bufsize < 8192)
-		jpg_bufsize = 8192;
-	if (jpg_bufsize > (512 * 1024))
-		jpg_bufsize = 512 * 1024;
-	/* Use parameter for vidmem or try to find a video card */
-	if (vidmem) {
-		dprintk(1,
-			KERN_INFO
-			"%s: Using supplied video memory base address @ 0x%lx\n",
-			ZORAN_NAME, vidmem);
-	}
-
-	/* random nonsense */
-	dprintk(6, KERN_DEBUG "Jotti is een held!\n");
-
-	/* some mainboards might not do PCI-PCI data transfer well */
-	if (pci_pci_problems & (PCIPCI_FAIL|PCIAGP_FAIL|PCIPCI_ALIMAGIK)) {
-		dprintk(1,
-			KERN_WARNING
-			"%s: chipset does not support reliable PCI-PCI DMA\n",
-			ZORAN_NAME);
-	}
-
-	/* take care of Natoma chipset and a revision 1 zr36057 */
-	for (i = 0; i < zoran_num; i++) {
-		struct zoran *zr = zoran[i];
-
-		if ((pci_pci_problems & PCIPCI_NATOMA) && zr->revision <= 1) {
-			zr->jpg_buffers.need_contiguous = 1;
-			dprintk(1,
-				KERN_INFO
-				"%s: ZR36057/Natoma bug, max. buffer size is 128K\n",
-				ZR_DEVNAME(zr));
-		}
-
-		if (zr36057_init(zr) < 0) {
-			for (i = 0; i < zoran_num; i++)
-				zoran_release(zoran[i]);
-			return -EIO;
-		}
-		zoran_proc_init(zr);
-	}
-
-	return 0;
-}
-
-static void __exit
-unload_dc10_cards (void)
-{
-	int i;
-
-	for (i = 0; i < zoran_num; i++)
-		zoran_release(zoran[i]);
-}
-
-module_init(init_dc10_cards);
-module_exit(unload_dc10_cards);
diff --git a/drivers/media/video/zoran_device.c b/drivers/media/video/zoran_device.c
deleted file mode 100644
index 88d3697..0000000
--- a/drivers/media/video/zoran_device.c
+++ /dev/null
@@ -1,1749 +0,0 @@
-/*
- * Zoran zr36057/zr36067 PCI controller driver, for the
- * Pinnacle/Miro DC10/DC10+/DC30/DC30+, Iomega Buz, Linux
- * Media Labs LML33/LML33R10.
- *
- * This part handles device access (PCI/I2C/codec/...)
- *
- * Copyright (C) 2000 Serguei Miridonov <mirsev@cicese.mx>
- *
- * Currently maintained by:
- *   Ronald Bultje    <rbultje@ronald.bitfreak.net>
- *   Laurent Pinchart <laurent.pinchart@skynet.be>
- *   Mailinglist      <mjpeg-users@lists.sf.net>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU 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/types.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/vmalloc.h>
-
-#include <linux/interrupt.h>
-#include <linux/proc_fs.h>
-#include <linux/i2c.h>
-#include <linux/i2c-algo-bit.h>
-#include <linux/videodev.h>
-#include <linux/spinlock.h>
-#include <linux/sem.h>
-
-#include <linux/pci.h>
-#include <linux/video_decoder.h>
-#include <linux/video_encoder.h>
-#include <linux/delay.h>
-#include <linux/wait.h>
-
-#include <asm/byteorder.h>
-#include <asm/io.h>
-
-#include "videocodec.h"
-#include "zoran.h"
-#include "zoran_device.h"
-#include "zoran_card.h"
-
-#define IRQ_MASK ( ZR36057_ISR_GIRQ0 | \
-		   ZR36057_ISR_GIRQ1 | \
-		   ZR36057_ISR_JPEGRepIRQ )
-
-extern const struct zoran_format zoran_formats[];
-
-static int lml33dpath;		/* default = 0
-				 * 1 will use digital path in capture
-				 * mode instead of analog. It can be
-				 * used for picture adjustments using
-				 * tool like xawtv while watching image
-				 * on TV monitor connected to the output.
-				 * However, due to absence of 75 Ohm
-				 * load on Bt819 input, there will be
-				 * some image imperfections */
-
-module_param(lml33dpath, bool, 0644);
-MODULE_PARM_DESC(lml33dpath,
-		 "Use digital path capture mode (on LML33 cards)");
-
-static void
-zr36057_init_vfe (struct zoran *zr);
-
-/*
- * General Purpose I/O and Guest bus access
- */
-
-/*
- * This is a bit tricky. When a board lacks a GPIO function, the corresponding
- * GPIO bit number in the card_info structure is set to 0.
- */
-
-void
-GPIO (struct zoran *zr,
-      int           bit,
-      unsigned int  value)
-{
-	u32 reg;
-	u32 mask;
-
-	/* Make sure the bit number is legal
-	 * A bit number of -1 (lacking) gives a mask of 0,
-	 * making it harmless */
-	mask = (1 << (24 + bit)) & 0xff000000;
-	reg = btread(ZR36057_GPPGCR1) & ~mask;
-	if (value) {
-		reg |= mask;
-	}
-	btwrite(reg, ZR36057_GPPGCR1);
-	udelay(1);
-}
-
-/*
- * Wait til post office is no longer busy
- */
-
-int
-post_office_wait (struct zoran *zr)
-{
-	u32 por;
-
-//      while (((por = btread(ZR36057_POR)) & (ZR36057_POR_POPen | ZR36057_POR_POTime)) == ZR36057_POR_POPen) {
-	while ((por = btread(ZR36057_POR)) & ZR36057_POR_POPen) {
-		/* wait for something to happen */
-	}
-	if ((por & ZR36057_POR_POTime) && !zr->card.gws_not_connected) {
-		/* In LML33/BUZ \GWS line is not connected, so it has always timeout set */
-		dprintk(1, KERN_INFO "%s: pop timeout %08x\n", ZR_DEVNAME(zr),
-			por);
-		return -1;
-	}
-
-	return 0;
-}
-
-int
-post_office_write (struct zoran *zr,
-		   unsigned int  guest,
-		   unsigned int  reg,
-		   unsigned int  value)
-{
-	u32 por;
-
-	por =
-	    ZR36057_POR_PODir | ZR36057_POR_POTime | ((guest & 7) << 20) |
-	    ((reg & 7) << 16) | (value & 0xFF);
-	btwrite(por, ZR36057_POR);
-
-	return post_office_wait(zr);
-}
-
-int
-post_office_read (struct zoran *zr,
-		  unsigned int  guest,
-		  unsigned int  reg)
-{
-	u32 por;
-
-	por = ZR36057_POR_POTime | ((guest & 7) << 20) | ((reg & 7) << 16);
-	btwrite(por, ZR36057_POR);
-	if (post_office_wait(zr) < 0) {
-		return -1;
-	}
-
-	return btread(ZR36057_POR) & 0xFF;
-}
-
-/*
- * detect guests
- */
-
-static void
-dump_guests (struct zoran *zr)
-{
-	if (zr36067_debug > 2) {
-		int i, guest[8];
-
-		for (i = 1; i < 8; i++) {	// Don't read jpeg codec here
-			guest[i] = post_office_read(zr, i, 0);
-		}
-
-		printk(KERN_INFO "%s: Guests:", ZR_DEVNAME(zr));
-
-		for (i = 1; i < 8; i++) {
-			printk(" 0x%02x", guest[i]);
-		}
-		printk("\n");
-	}
-}
-
-static inline unsigned long
-get_time (void)
-{
-	struct timeval tv;
-
-	do_gettimeofday(&tv);
-	return (1000000 * tv.tv_sec + tv.tv_usec);
-}
-
-void
-detect_guest_activity (struct zoran *zr)
-{
-	int timeout, i, j, res, guest[8], guest0[8], change[8][3];
-	unsigned long t0, t1;
-
-	dump_guests(zr);
-	printk(KERN_INFO "%s: Detecting guests activity, please wait...\n",
-	       ZR_DEVNAME(zr));
-	for (i = 1; i < 8; i++) {	// Don't read jpeg codec here
-		guest0[i] = guest[i] = post_office_read(zr, i, 0);
-	}
-
-	timeout = 0;
-	j = 0;
-	t0 = get_time();
-	while (timeout < 10000) {
-		udelay(10);
-		timeout++;
-		for (i = 1; (i < 8) && (j < 8); i++) {
-			res = post_office_read(zr, i, 0);
-			if (res != guest[i]) {
-				t1 = get_time();
-				change[j][0] = (t1 - t0);
-				t0 = t1;
-				change[j][1] = i;
-				change[j][2] = res;
-				j++;
-				guest[i] = res;
-			}
-		}
-		if (j >= 8)
-			break;
-	}
-	printk(KERN_INFO "%s: Guests:", ZR_DEVNAME(zr));
-
-	for (i = 1; i < 8; i++) {
-		printk(" 0x%02x", guest0[i]);
-	}
-	printk("\n");
-	if (j == 0) {
-		printk(KERN_INFO "%s: No activity detected.\n", ZR_DEVNAME(zr));
-		return;
-	}
-	for (i = 0; i < j; i++) {
-		printk(KERN_INFO "%s: %6d: %d => 0x%02x\n", ZR_DEVNAME(zr),
-		       change[i][0], change[i][1], change[i][2]);
-	}
-}
-
-/*
- * JPEG Codec access
- */
-
-void
-jpeg_codec_sleep (struct zoran *zr,
-		  int           sleep)
-{
-	GPIO(zr, zr->card.gpio[ZR_GPIO_JPEG_SLEEP], !sleep);
-	if (!sleep) {
-		dprintk(3,
-			KERN_DEBUG
-			"%s: jpeg_codec_sleep() - wake GPIO=0x%08x\n",
-			ZR_DEVNAME(zr), btread(ZR36057_GPPGCR1));
-		udelay(500);
-	} else {
-		dprintk(3,
-			KERN_DEBUG
-			"%s: jpeg_codec_sleep() - sleep GPIO=0x%08x\n",
-			ZR_DEVNAME(zr), btread(ZR36057_GPPGCR1));
-		udelay(2);
-	}
-}
-
-int
-jpeg_codec_reset (struct zoran *zr)
-{
-	/* Take the codec out of sleep */
-	jpeg_codec_sleep(zr, 0);
-
-	if (zr->card.gpcs[GPCS_JPEG_RESET] != 0xff) {
-		post_office_write(zr, zr->card.gpcs[GPCS_JPEG_RESET], 0,
-				  0);
-		udelay(2);
-	} else {
-		GPIO(zr, zr->card.gpio[ZR_GPIO_JPEG_RESET], 0);
-		udelay(2);
-		GPIO(zr, zr->card.gpio[ZR_GPIO_JPEG_RESET], 1);
-		udelay(2);
-	}
-
-	return 0;
-}
-
-/*
- *   Set the registers for the size we have specified. Don't bother
- *   trying to understand this without the ZR36057 manual in front of
- *   you [AC].
- *
- *   PS: The manual is free for download in .pdf format from
- *   www.zoran.com - nicely done those folks.
- */
-
-static void
-zr36057_adjust_vfe (struct zoran          *zr,
-		    enum zoran_codec_mode  mode)
-{
-	u32 reg;
-
-	switch (mode) {
-	case BUZ_MODE_MOTION_DECOMPRESS:
-		btand(~ZR36057_VFESPFR_ExtFl, ZR36057_VFESPFR);
-		reg = btread(ZR36057_VFEHCR);
-		if ((reg & (1 << 10)) && zr->card.type != LML33R10) {
-			reg += ((1 << 10) | 1);
-		}
-		btwrite(reg, ZR36057_VFEHCR);
-		break;
-	case BUZ_MODE_MOTION_COMPRESS:
-	case BUZ_MODE_IDLE:
-	default:
-		if (zr->norm == VIDEO_MODE_NTSC ||
-		    (zr->card.type == LML33R10 &&
-		     zr->norm == VIDEO_MODE_PAL))
-			btand(~ZR36057_VFESPFR_ExtFl, ZR36057_VFESPFR);
-		else
-			btor(ZR36057_VFESPFR_ExtFl, ZR36057_VFESPFR);
-		reg = btread(ZR36057_VFEHCR);
-		if (!(reg & (1 << 10)) && zr->card.type != LML33R10) {
-			reg -= ((1 << 10) | 1);
-		}
-		btwrite(reg, ZR36057_VFEHCR);
-		break;
-	}
-}
-
-/*
- * set geometry
- */
-
-static void
-zr36057_set_vfe (struct zoran              *zr,
-		 int                        video_width,
-		 int                        video_height,
-		 const struct zoran_format *format)
-{
-	struct tvnorm *tvn;
-	unsigned HStart, HEnd, VStart, VEnd;
-	unsigned DispMode;
-	unsigned VidWinWid, VidWinHt;
-	unsigned hcrop1, hcrop2, vcrop1, vcrop2;
-	unsigned Wa, We, Ha, He;
-	unsigned X, Y, HorDcm, VerDcm;
-	u32 reg;
-	unsigned mask_line_size;
-
-	tvn = zr->timing;
-
-	Wa = tvn->Wa;
-	Ha = tvn->Ha;
-
-	dprintk(2, KERN_INFO "%s: set_vfe() - width = %d, height = %d\n",
-		ZR_DEVNAME(zr), video_width, video_height);
-
-	if (zr->norm != VIDEO_MODE_PAL &&
-	    zr->norm != VIDEO_MODE_NTSC &&
-	    zr->norm != VIDEO_MODE_SECAM) {
-		dprintk(1,
-			KERN_ERR "%s: set_vfe() - norm = %d not valid\n",
-			ZR_DEVNAME(zr), zr->norm);
-		return;
-	}
-	if (video_width < BUZ_MIN_WIDTH ||
-	    video_height < BUZ_MIN_HEIGHT ||
-	    video_width > Wa || video_height > Ha) {
-		dprintk(1, KERN_ERR "%s: set_vfe: w=%d h=%d not valid\n",
-			ZR_DEVNAME(zr), video_width, video_height);
-		return;
-	}
-
-	/**** zr36057 ****/
-
-	/* horizontal */
-	VidWinWid = video_width;
-	X = (VidWinWid * 64 + tvn->Wa - 1) / tvn->Wa;
-	We = (VidWinWid * 64) / X;
-	HorDcm = 64 - X;
-	hcrop1 = 2 * ((tvn->Wa - We) / 4);
-	hcrop2 = tvn->Wa - We - hcrop1;
-	HStart = tvn->HStart ? tvn->HStart : 1;
-	/* (Ronald) Original comment:
-	 * "| 1 Doesn't have any effect, tested on both a DC10 and a DC10+"
-	 * this is false. It inverses chroma values on the LML33R10 (so Cr
-	 * suddenly is shown as Cb and reverse, really cool effect if you
-	 * want to see blue faces, not useful otherwise). So don't use |1.
-	 * However, the DC10 has '0' as HStart, but does need |1, so we
-	 * use a dirty check...
-	 */
-	HEnd = HStart + tvn->Wa - 1;
-	HStart += hcrop1;
-	HEnd -= hcrop2;
-	reg = ((HStart & ZR36057_VFEHCR_Hmask) << ZR36057_VFEHCR_HStart)
-	    | ((HEnd & ZR36057_VFEHCR_Hmask) << ZR36057_VFEHCR_HEnd);
-	if (zr->card.vfe_pol.hsync_pol)
-		reg |= ZR36057_VFEHCR_HSPol;
-	btwrite(reg, ZR36057_VFEHCR);
-
-	/* Vertical */
-	DispMode = !(video_height > BUZ_MAX_HEIGHT / 2);
-	VidWinHt = DispMode ? video_height : video_height / 2;
-	Y = (VidWinHt * 64 * 2 + tvn->Ha - 1) / tvn->Ha;
-	He = (VidWinHt * 64) / Y;
-	VerDcm = 64 - Y;
-	vcrop1 = (tvn->Ha / 2 - He) / 2;
-	vcrop2 = tvn->Ha / 2 - He - vcrop1;
-	VStart = tvn->VStart;
-	VEnd = VStart + tvn->Ha / 2;	// - 1; FIXME SnapShot times out with -1 in 768*576 on the DC10 - LP
-	VStart += vcrop1;
-	VEnd -= vcrop2;
-	reg = ((VStart & ZR36057_VFEVCR_Vmask) << ZR36057_VFEVCR_VStart)
-	    | ((VEnd & ZR36057_VFEVCR_Vmask) << ZR36057_VFEVCR_VEnd);
-	if (zr->card.vfe_pol.vsync_pol)
-		reg |= ZR36057_VFEVCR_VSPol;
-	btwrite(reg, ZR36057_VFEVCR);
-
-	/* scaler and pixel format */
-	reg = 0;
-	reg |= (HorDcm << ZR36057_VFESPFR_HorDcm);
-	reg |= (VerDcm << ZR36057_VFESPFR_VerDcm);
-	reg |= (DispMode << ZR36057_VFESPFR_DispMode);
-	/* RJ: I don't know, why the following has to be the opposite
-	 * of the corresponding ZR36060 setting, but only this way
-	 * we get the correct colors when uncompressing to the screen  */
-	//reg |= ZR36057_VFESPFR_VCLKPol; /**/
-	/* RJ: Don't know if that is needed for NTSC also */
-	if (zr->norm != VIDEO_MODE_NTSC)
-		reg |= ZR36057_VFESPFR_ExtFl;	// NEEDED!!!!!!! Wolfgang
-	reg |= ZR36057_VFESPFR_TopField;
-	if (HorDcm >= 48) {
-		reg |= 3 << ZR36057_VFESPFR_HFilter;	/* 5 tap filter */
-	} else if (HorDcm >= 32) {
-		reg |= 2 << ZR36057_VFESPFR_HFilter;	/* 4 tap filter */
-	} else if (HorDcm >= 16) {
-		reg |= 1 << ZR36057_VFESPFR_HFilter;	/* 3 tap filter */
-	}
-	reg |= format->vfespfr;
-	btwrite(reg, ZR36057_VFESPFR);
-
-	/* display configuration */
-	reg = (16 << ZR36057_VDCR_MinPix)
-	    | (VidWinHt << ZR36057_VDCR_VidWinHt)
-	    | (VidWinWid << ZR36057_VDCR_VidWinWid);
-	if (pci_pci_problems & PCIPCI_TRITON)
-		// || zr->revision < 1) // Revision 1 has also Triton support
-		reg &= ~ZR36057_VDCR_Triton;
-	else
-		reg |= ZR36057_VDCR_Triton;
-	btwrite(reg, ZR36057_VDCR);
-
-	/* (Ronald) don't write this if overlay_mask = NULL */
-	if (zr->overlay_mask) {
-		/* Write overlay clipping mask data, but don't enable overlay clipping */
-		/* RJ: since this makes only sense on the screen, we use
-		 * zr->overlay_settings.width instead of video_width */
-
-		mask_line_size = (BUZ_MAX_WIDTH + 31) / 32;
-		reg = virt_to_bus(zr->overlay_mask);
-		btwrite(reg, ZR36057_MMTR);
-		reg = virt_to_bus(zr->overlay_mask + mask_line_size);
-		btwrite(reg, ZR36057_MMBR);
-		reg =
-		    mask_line_size - (zr->overlay_settings.width +
-				      31) / 32;
-		if (DispMode == 0)
-			reg += mask_line_size;
-		reg <<= ZR36057_OCR_MaskStride;
-		btwrite(reg, ZR36057_OCR);
-	}
-
-	zr36057_adjust_vfe(zr, zr->codec_mode);
-}
-
-/*
- * Switch overlay on or off
- */
-
-void
-zr36057_overlay (struct zoran *zr,
-		 int           on)
-{
-	u32 reg;
-
-	if (on) {
-		/* do the necessary settings ... */
-		btand(~ZR36057_VDCR_VidEn, ZR36057_VDCR);	/* switch it off first */
-
-		zr36057_set_vfe(zr,
-				zr->overlay_settings.width,
-				zr->overlay_settings.height,
-				zr->overlay_settings.format);
-
-		/* Start and length of each line MUST be 4-byte aligned.
-		 * This should be allready checked before the call to this routine.
-		 * All error messages are internal driver checking only! */
-
-		/* video display top and bottom registers */
-		reg = (long) zr->buffer.base +
-		    zr->overlay_settings.x *
-		    ((zr->overlay_settings.format->depth + 7) / 8) +
-		    zr->overlay_settings.y *
-		    zr->buffer.bytesperline;
-		btwrite(reg, ZR36057_VDTR);
-		if (reg & 3)
-			dprintk(1,
-				KERN_ERR
-				"%s: zr36057_overlay() - video_address not aligned\n",
-				ZR_DEVNAME(zr));
-		if (zr->overlay_settings.height > BUZ_MAX_HEIGHT / 2)
-			reg += zr->buffer.bytesperline;
-		btwrite(reg, ZR36057_VDBR);
-
-		/* video stride, status, and frame grab register */
-		reg = zr->buffer.bytesperline -
-		    zr->overlay_settings.width *
-		    ((zr->overlay_settings.format->depth + 7) / 8);
-		if (zr->overlay_settings.height > BUZ_MAX_HEIGHT / 2)
-			reg += zr->buffer.bytesperline;
-		if (reg & 3)
-			dprintk(1,
-				KERN_ERR
-				"%s: zr36057_overlay() - video_stride not aligned\n",
-				ZR_DEVNAME(zr));
-		reg = (reg << ZR36057_VSSFGR_DispStride);
-		reg |= ZR36057_VSSFGR_VidOvf;	/* clear overflow status */
-		btwrite(reg, ZR36057_VSSFGR);
-
-		/* Set overlay clipping */
-		if (zr->overlay_settings.clipcount > 0)
-			btor(ZR36057_OCR_OvlEnable, ZR36057_OCR);
-
-		/* ... and switch it on */
-		btor(ZR36057_VDCR_VidEn, ZR36057_VDCR);
-	} else {
-		/* Switch it off */
-		btand(~ZR36057_VDCR_VidEn, ZR36057_VDCR);
-	}
-}
-
-/*
- * The overlay mask has one bit for each pixel on a scan line,
- *  and the maximum window size is BUZ_MAX_WIDTH * BUZ_MAX_HEIGHT pixels.
- */
-
-void
-write_overlay_mask (struct file       *file,
-		    struct video_clip *vp,
-		    int                count)
-{
-	struct zoran_fh *fh = file->private_data;
-	struct zoran *zr = fh->zr;
-	unsigned mask_line_size = (BUZ_MAX_WIDTH + 31) / 32;
-	u32 *mask;
-	int x, y, width, height;
-	unsigned i, j, k;
-	u32 reg;
-
-	/* fill mask with one bits */
-	memset(fh->overlay_mask, ~0, mask_line_size * 4 * BUZ_MAX_HEIGHT);
-	reg = 0;
-
-	for (i = 0; i < count; ++i) {
-		/* pick up local copy of clip */
-		x = vp[i].x;
-		y = vp[i].y;
-		width = vp[i].width;
-		height = vp[i].height;
-
-		/* trim clips that extend beyond the window */
-		if (x < 0) {
-			width += x;
-			x = 0;
-		}
-		if (y < 0) {
-			height += y;
-			y = 0;
-		}
-		if (x + width > fh->overlay_settings.width) {
-			width = fh->overlay_settings.width - x;
-		}
-		if (y + height > fh->overlay_settings.height) {
-			height = fh->overlay_settings.height - y;
-		}
-
-		/* ignore degenerate clips */
-		if (height <= 0) {
-			continue;
-		}
-		if (width <= 0) {
-			continue;
-		}
-
-		/* apply clip for each scan line */
-		for (j = 0; j < height; ++j) {
-			/* reset bit for each pixel */
-			/* this can be optimized later if need be */
-			mask = fh->overlay_mask + (y + j) * mask_line_size;
-			for (k = 0; k < width; ++k) {
-				mask[(x + k) / 32] &=
-				    ~((u32) 1 << (x + k) % 32);
-			}
-		}
-	}
-}
-
-/* Enable/Disable uncompressed memory grabbing of the 36057 */
-
-void
-zr36057_set_memgrab (struct zoran *zr,
-		     int           mode)
-{
-	if (mode) {
-		/* We only check SnapShot and not FrameGrab here.  SnapShot==1
-		 * means a capture is already in progress, but FrameGrab==1
-		 * doesn't necessary mean that.  It's more correct to say a 1
-		 * to 0 transition indicates a capture completed.  If a
-		 * capture is pending when capturing is tuned off, FrameGrab
-		 * will be stuck at 1 until capturing is turned back on.
-		 */
-		if (btread(ZR36057_VSSFGR) & ZR36057_VSSFGR_SnapShot)
-			dprintk(1,
-				KERN_WARNING
-				"%s: zr36057_set_memgrab(1) with SnapShot on!?\n",
-				ZR_DEVNAME(zr));
-
-		/* switch on VSync interrupts */
-		btwrite(IRQ_MASK, ZR36057_ISR);	// Clear Interrupts
-		btor(zr->card.vsync_int, ZR36057_ICR);	// SW
-
-		/* enable SnapShot */
-		btor(ZR36057_VSSFGR_SnapShot, ZR36057_VSSFGR);
-
-		/* Set zr36057 video front end  and enable video */
-		zr36057_set_vfe(zr, zr->v4l_settings.width,
-				zr->v4l_settings.height,
-				zr->v4l_settings.format);
-
-		zr->v4l_memgrab_active = 1;
-	} else {
-		/* switch off VSync interrupts */
-		btand(~zr->card.vsync_int, ZR36057_ICR);	// SW
-
-		zr->v4l_memgrab_active = 0;
-		zr->v4l_grab_frame = NO_GRAB_ACTIVE;
-
-		/* reenable grabbing to screen if it was running */
-		if (zr->v4l_overlay_active) {
-			zr36057_overlay(zr, 1);
-		} else {
-			btand(~ZR36057_VDCR_VidEn, ZR36057_VDCR);
-			btand(~ZR36057_VSSFGR_SnapShot, ZR36057_VSSFGR);
-		}
-	}
-}
-
-int
-wait_grab_pending (struct zoran *zr)
-{
-	unsigned long flags;
-
-	/* wait until all pending grabs are finished */
-
-	if (!zr->v4l_memgrab_active)
-		return 0;
-
-	wait_event_interruptible(zr->v4l_capq,
-			(zr->v4l_pend_tail == zr->v4l_pend_head));
-	if (signal_pending(current))
-		return -ERESTARTSYS;
-
-	spin_lock_irqsave(&zr->spinlock, flags);
-	zr36057_set_memgrab(zr, 0);
-	spin_unlock_irqrestore(&zr->spinlock, flags);
-
-	return 0;
-}
-
-/*****************************************************************************
- *                                                                           *
- *  Set up the Buz-specific MJPEG part                                       *
- *                                                                           *
- *****************************************************************************/
-
-static inline void
-set_frame (struct zoran *zr,
-	   int           val)
-{
-	GPIO(zr, zr->card.gpio[ZR_GPIO_JPEG_FRAME], val);
-}
-
-static void
-set_videobus_dir (struct zoran *zr,
-		  int           val)
-{
-	switch (zr->card.type) {
-	case LML33:
-	case LML33R10:
-		if (lml33dpath == 0)
-			GPIO(zr, 5, val);
-		else
-			GPIO(zr, 5, 1);
-		break;
-	default:
-		GPIO(zr, zr->card.gpio[ZR_GPIO_VID_DIR],
-		     zr->card.gpio_pol[ZR_GPIO_VID_DIR] ? !val : val);
-		break;
-	}
-}
-
-static void
-init_jpeg_queue (struct zoran *zr)
-{
-	int i;
-
-	/* re-initialize DMA ring stuff */
-	zr->jpg_que_head = 0;
-	zr->jpg_dma_head = 0;
-	zr->jpg_dma_tail = 0;
-	zr->jpg_que_tail = 0;
-	zr->jpg_seq_num = 0;
-	zr->JPEG_error = 0;
-	zr->num_errors = 0;
-	zr->jpg_err_seq = 0;
-	zr->jpg_err_shift = 0;
-	zr->jpg_queued_num = 0;
-	for (i = 0; i < zr->jpg_buffers.num_buffers; i++) {
-		zr->jpg_buffers.buffer[i].state = BUZ_STATE_USER;	/* nothing going on */
-	}
-	for (i = 0; i < BUZ_NUM_STAT_COM; i++) {
-		zr->stat_com[i] = cpu_to_le32(1);	/* mark as unavailable to zr36057 */
-	}
-}
-
-static void
-zr36057_set_jpg (struct zoran          *zr,
-		 enum zoran_codec_mode  mode)
-{
-	struct tvnorm *tvn;
-	u32 reg;
-
-	tvn = zr->timing;
-
-	/* assert P_Reset, disable code transfer, deassert Active */
-	btwrite(0, ZR36057_JPC);
-
-	/* MJPEG compression mode */
-	switch (mode) {
-
-	case BUZ_MODE_MOTION_COMPRESS:
-	default:
-		reg = ZR36057_JMC_MJPGCmpMode;
-		break;
-
-	case BUZ_MODE_MOTION_DECOMPRESS:
-		reg = ZR36057_JMC_MJPGExpMode;
-		reg |= ZR36057_JMC_SyncMstr;
-		/* RJ: The following is experimental - improves the output to screen */
-		//if(zr->jpg_settings.VFIFO_FB) reg |= ZR36057_JMC_VFIFO_FB; // No, it doesn't. SM
-		break;
-
-	case BUZ_MODE_STILL_COMPRESS:
-		reg = ZR36057_JMC_JPGCmpMode;
-		break;
-
-	case BUZ_MODE_STILL_DECOMPRESS:
-		reg = ZR36057_JMC_JPGExpMode;
-		break;
-
-	}
-	reg |= ZR36057_JMC_JPG;
-	if (zr->jpg_settings.field_per_buff == 1)
-		reg |= ZR36057_JMC_Fld_per_buff;
-	btwrite(reg, ZR36057_JMC);
-
-	/* vertical */
-	btor(ZR36057_VFEVCR_VSPol, ZR36057_VFEVCR);
-	reg = (6 << ZR36057_VSP_VsyncSize) |
-	      (tvn->Ht << ZR36057_VSP_FrmTot);
-	btwrite(reg, ZR36057_VSP);
-	reg = ((zr->jpg_settings.img_y + tvn->VStart) << ZR36057_FVAP_NAY) |
-	      (zr->jpg_settings.img_height << ZR36057_FVAP_PAY);
-	btwrite(reg, ZR36057_FVAP);
-
-	/* horizontal */
-	if (zr->card.vfe_pol.hsync_pol)
-		btor(ZR36057_VFEHCR_HSPol, ZR36057_VFEHCR);
-	else
-		btand(~ZR36057_VFEHCR_HSPol, ZR36057_VFEHCR);
-	reg = ((tvn->HSyncStart) << ZR36057_HSP_HsyncStart) |
-	      (tvn->Wt << ZR36057_HSP_LineTot);
-	btwrite(reg, ZR36057_HSP);
-	reg = ((zr->jpg_settings.img_x +
-		tvn->HStart + 4) << ZR36057_FHAP_NAX) |
-	      (zr->jpg_settings.img_width << ZR36057_FHAP_PAX);
-	btwrite(reg, ZR36057_FHAP);
-
-	/* field process parameters */
-	if (zr->jpg_settings.odd_even)
-		reg = ZR36057_FPP_Odd_Even;
-	else
-		reg = 0;
-
-	btwrite(reg, ZR36057_FPP);
-
-	/* Set proper VCLK Polarity, else colors will be wrong during playback */
-	//btor(ZR36057_VFESPFR_VCLKPol, ZR36057_VFESPFR);
-
-	/* code base address */
-	reg = virt_to_bus(zr->stat_com);
-	btwrite(reg, ZR36057_JCBA);
-
-	/* FIFO threshold (FIFO is 160. double words) */
-	/* NOTE: decimal values here */
-	switch (mode) {
-
-	case BUZ_MODE_STILL_COMPRESS:
-	case BUZ_MODE_MOTION_COMPRESS:
-		if (zr->card.type != BUZ)
-			reg = 140;
-		else
-			reg = 60;
-		break;
-
-	case BUZ_MODE_STILL_DECOMPRESS:
-	case BUZ_MODE_MOTION_DECOMPRESS:
-		reg = 20;
-		break;
-
-	default:
-		reg = 80;
-		break;
-
-	}
-	btwrite(reg, ZR36057_JCFT);
-	zr36057_adjust_vfe(zr, mode);
-
-}
-
-void
-print_interrupts (struct zoran *zr)
-{
-	int res, noerr = 0;
-
-	printk(KERN_INFO "%s: interrupts received:", ZR_DEVNAME(zr));
-	if ((res = zr->field_counter) < -1 || res > 1) {
-		printk(" FD:%d", res);
-	}
-	if ((res = zr->intr_counter_GIRQ1) != 0) {
-		printk(" GIRQ1:%d", res);
-		noerr++;
-	}
-	if ((res = zr->intr_counter_GIRQ0) != 0) {
-		printk(" GIRQ0:%d", res);
-		noerr++;
-	}
-	if ((res = zr->intr_counter_CodRepIRQ) != 0) {
-		printk(" CodRepIRQ:%d", res);
-		noerr++;
-	}
-	if ((res = zr->intr_counter_JPEGRepIRQ) != 0) {
-		printk(" JPEGRepIRQ:%d", res);
-		noerr++;
-	}
-	if (zr->JPEG_max_missed) {
-		printk(" JPEG delays: max=%d min=%d", zr->JPEG_max_missed,
-		       zr->JPEG_min_missed);
-	}
-	if (zr->END_event_missed) {
-		printk(" ENDs missed: %d", zr->END_event_missed);
-	}
-	//if (zr->jpg_queued_num) {
-	printk(" queue_state=%ld/%ld/%ld/%ld", zr->jpg_que_tail,
-	       zr->jpg_dma_tail, zr->jpg_dma_head, zr->jpg_que_head);
-	//}
-	if (!noerr) {
-		printk(": no interrupts detected.");
-	}
-	printk("\n");
-}
-
-void
-clear_interrupt_counters (struct zoran *zr)
-{
-	zr->intr_counter_GIRQ1 = 0;
-	zr->intr_counter_GIRQ0 = 0;
-	zr->intr_counter_CodRepIRQ = 0;
-	zr->intr_counter_JPEGRepIRQ = 0;
-	zr->field_counter = 0;
-	zr->IRQ1_in = 0;
-	zr->IRQ1_out = 0;
-	zr->JPEG_in = 0;
-	zr->JPEG_out = 0;
-	zr->JPEG_0 = 0;
-	zr->JPEG_1 = 0;
-	zr->END_event_missed = 0;
-	zr->JPEG_missed = 0;
-	zr->JPEG_max_missed = 0;
-	zr->JPEG_min_missed = 0x7fffffff;
-}
-
-static u32
-count_reset_interrupt (struct zoran *zr)
-{
-	u32 isr;
-
-	if ((isr = btread(ZR36057_ISR) & 0x78000000)) {
-		if (isr & ZR36057_ISR_GIRQ1) {
-			btwrite(ZR36057_ISR_GIRQ1, ZR36057_ISR);
-			zr->intr_counter_GIRQ1++;
-		}
-		if (isr & ZR36057_ISR_GIRQ0) {
-			btwrite(ZR36057_ISR_GIRQ0, ZR36057_ISR);
-			zr->intr_counter_GIRQ0++;
-		}
-		if (isr & ZR36057_ISR_CodRepIRQ) {
-			btwrite(ZR36057_ISR_CodRepIRQ, ZR36057_ISR);
-			zr->intr_counter_CodRepIRQ++;
-		}
-		if (isr & ZR36057_ISR_JPEGRepIRQ) {
-			btwrite(ZR36057_ISR_JPEGRepIRQ, ZR36057_ISR);
-			zr->intr_counter_JPEGRepIRQ++;
-		}
-	}
-	return isr;
-}
-
-void
-jpeg_start (struct zoran *zr)
-{
-	int reg;
-
-	zr->frame_num = 0;
-
-	/* deassert P_reset, disable code transfer, deassert Active */
-	btwrite(ZR36057_JPC_P_Reset, ZR36057_JPC);
-	/* stop flushing the internal code buffer */
-	btand(~ZR36057_MCTCR_CFlush, ZR36057_MCTCR);
-	/* enable code transfer */
-	btor(ZR36057_JPC_CodTrnsEn, ZR36057_JPC);
-
-	/* clear IRQs */
-	btwrite(IRQ_MASK, ZR36057_ISR);
-	/* enable the JPEG IRQs */
-	btwrite(zr->card.jpeg_int |
-			ZR36057_ICR_JPEGRepIRQ |
-			ZR36057_ICR_IntPinEn,
-		ZR36057_ICR);
-
-	set_frame(zr, 0);	// \FRAME
-
-	/* set the JPEG codec guest ID */
-	reg = (zr->card.gpcs[1] << ZR36057_JCGI_JPEGuestID) |
-	       (0 << ZR36057_JCGI_JPEGuestReg);
-	btwrite(reg, ZR36057_JCGI);
-
-	if (zr->card.video_vfe == CODEC_TYPE_ZR36016 &&
-	    zr->card.video_codec == CODEC_TYPE_ZR36050) {
-		/* Enable processing on the ZR36016 */
-		if (zr->vfe)
-			zr36016_write(zr->vfe, 0, 1);
-
-		/* load the address of the GO register in the ZR36050 latch */
-		post_office_write(zr, 0, 0, 0);
-	}
-
-	/* assert Active */
-	btor(ZR36057_JPC_Active, ZR36057_JPC);
-
-	/* enable the Go generation */
-	btor(ZR36057_JMC_Go_en, ZR36057_JMC);
-	udelay(30);
-
-	set_frame(zr, 1);	// /FRAME
-
-	dprintk(3, KERN_DEBUG "%s: jpeg_start\n", ZR_DEVNAME(zr));
-}
-
-void
-zr36057_enable_jpg (struct zoran          *zr,
-		    enum zoran_codec_mode  mode)
-{
-	static int zero;
-	static int one = 1;
-	struct vfe_settings cap;
-	int field_size =
-	    zr->jpg_buffers.buffer_size / zr->jpg_settings.field_per_buff;
-
-	zr->codec_mode = mode;
-
-	cap.x = zr->jpg_settings.img_x;
-	cap.y = zr->jpg_settings.img_y;
-	cap.width = zr->jpg_settings.img_width;
-	cap.height = zr->jpg_settings.img_height;
-	cap.decimation =
-	    zr->jpg_settings.HorDcm | (zr->jpg_settings.VerDcm << 8);
-	cap.quality = zr->jpg_settings.jpg_comp.quality;
-
-	switch (mode) {
-
-	case BUZ_MODE_MOTION_COMPRESS: {
-		struct jpeg_app_marker app;
-		struct jpeg_com_marker com;
-
-		/* In motion compress mode, the decoder output must be enabled, and
-		 * the video bus direction set to input.
-		 */
-		set_videobus_dir(zr, 0);
-		decoder_command(zr, DECODER_ENABLE_OUTPUT, &one);
-		encoder_command(zr, ENCODER_SET_INPUT, &zero);
-
-		/* Take the JPEG codec and the VFE out of sleep */
-		jpeg_codec_sleep(zr, 0);
-
-		/* set JPEG app/com marker */
-		app.appn = zr->jpg_settings.jpg_comp.APPn;
-		app.len = zr->jpg_settings.jpg_comp.APP_len;
-		memcpy(app.data, zr->jpg_settings.jpg_comp.APP_data, 60);
-		zr->codec->control(zr->codec, CODEC_S_JPEG_APP_DATA,
-				   sizeof(struct jpeg_app_marker), &app);
-
-		com.len = zr->jpg_settings.jpg_comp.COM_len;
-		memcpy(com.data, zr->jpg_settings.jpg_comp.COM_data, 60);
-		zr->codec->control(zr->codec, CODEC_S_JPEG_COM_DATA,
-				   sizeof(struct jpeg_com_marker), &com);
-
-		/* Setup the JPEG codec */
-		zr->codec->control(zr->codec, CODEC_S_JPEG_TDS_BYTE,
-				   sizeof(int), &field_size);
-		zr->codec->set_video(zr->codec, zr->timing, &cap,
-				     &zr->card.vfe_pol);
-		zr->codec->set_mode(zr->codec, CODEC_DO_COMPRESSION);
-
-		/* Setup the VFE */
-		if (zr->vfe) {
-			zr->vfe->control(zr->vfe, CODEC_S_JPEG_TDS_BYTE,
-					 sizeof(int), &field_size);
-			zr->vfe->set_video(zr->vfe, zr->timing, &cap,
-					   &zr->card.vfe_pol);
-			zr->vfe->set_mode(zr->vfe, CODEC_DO_COMPRESSION);
-		}
-
-		init_jpeg_queue(zr);
-		zr36057_set_jpg(zr, mode);	// \P_Reset, ... Video param, FIFO
-
-		clear_interrupt_counters(zr);
-		dprintk(2, KERN_INFO "%s: enable_jpg(MOTION_COMPRESS)\n",
-			ZR_DEVNAME(zr));
-		break;
-	}
-
-	case BUZ_MODE_MOTION_DECOMPRESS:
-		/* In motion decompression mode, the decoder output must be disabled, and
-		 * the video bus direction set to output.
-		 */
-		decoder_command(zr, DECODER_ENABLE_OUTPUT, &zero);
-		set_videobus_dir(zr, 1);
-		encoder_command(zr, ENCODER_SET_INPUT, &one);
-
-		/* Take the JPEG codec and the VFE out of sleep */
-		jpeg_codec_sleep(zr, 0);
-		/* Setup the VFE */
-		if (zr->vfe) {
-			zr->vfe->set_video(zr->vfe, zr->timing, &cap,
-					   &zr->card.vfe_pol);
-			zr->vfe->set_mode(zr->vfe, CODEC_DO_EXPANSION);
-		}
-		/* Setup the JPEG codec */
-		zr->codec->set_video(zr->codec, zr->timing, &cap,
-				     &zr->card.vfe_pol);
-		zr->codec->set_mode(zr->codec, CODEC_DO_EXPANSION);
-
-		init_jpeg_queue(zr);
-		zr36057_set_jpg(zr, mode);	// \P_Reset, ... Video param, FIFO
-
-		clear_interrupt_counters(zr);
-		dprintk(2, KERN_INFO "%s: enable_jpg(MOTION_DECOMPRESS)\n",
-			ZR_DEVNAME(zr));
-		break;
-
-	case BUZ_MODE_IDLE:
-	default:
-		/* shut down processing */
-		btand(~(zr->card.jpeg_int | ZR36057_ICR_JPEGRepIRQ),
-		      ZR36057_ICR);
-		btwrite(zr->card.jpeg_int | ZR36057_ICR_JPEGRepIRQ,
-			ZR36057_ISR);
-		btand(~ZR36057_JMC_Go_en, ZR36057_JMC);	// \Go_en
-
-		msleep(50);
-
-		set_videobus_dir(zr, 0);
-		set_frame(zr, 1);	// /FRAME
-		btor(ZR36057_MCTCR_CFlush, ZR36057_MCTCR);	// /CFlush
-		btwrite(0, ZR36057_JPC);	// \P_Reset,\CodTrnsEn,\Active
-		btand(~ZR36057_JMC_VFIFO_FB, ZR36057_JMC);
-		btand(~ZR36057_JMC_SyncMstr, ZR36057_JMC);
-		jpeg_codec_reset(zr);
-		jpeg_codec_sleep(zr, 1);
-		zr36057_adjust_vfe(zr, mode);
-
-		decoder_command(zr, DECODER_ENABLE_OUTPUT, &one);
-		encoder_command(zr, ENCODER_SET_INPUT, &zero);
-
-		dprintk(2, KERN_INFO "%s: enable_jpg(IDLE)\n", ZR_DEVNAME(zr));
-		break;
-
-	}
-}
-
-/* when this is called the spinlock must be held */
-void
-zoran_feed_stat_com (struct zoran *zr)
-{
-	/* move frames from pending queue to DMA */
-
-	int frame, i, max_stat_com;
-
-	max_stat_com =
-	    (zr->jpg_settings.TmpDcm ==
-	     1) ? BUZ_NUM_STAT_COM : (BUZ_NUM_STAT_COM >> 1);
-
-	while ((zr->jpg_dma_head - zr->jpg_dma_tail) < max_stat_com &&
-	       zr->jpg_dma_head < zr->jpg_que_head) {
-
-		frame = zr->jpg_pend[zr->jpg_dma_head & BUZ_MASK_FRAME];
-		if (zr->jpg_settings.TmpDcm == 1) {
-			/* fill 1 stat_com entry */
-			i = (zr->jpg_dma_head -
-			     zr->jpg_err_shift) & BUZ_MASK_STAT_COM;
-			if (!(zr->stat_com[i] & cpu_to_le32(1)))
-				break;
-			zr->stat_com[i] =
-			    cpu_to_le32(zr->jpg_buffers.buffer[frame].frag_tab_bus);
-		} else {
-			/* fill 2 stat_com entries */
-			i = ((zr->jpg_dma_head -
-			      zr->jpg_err_shift) & 1) * 2;
-			if (!(zr->stat_com[i] & cpu_to_le32(1)))
-				break;
-			zr->stat_com[i] =
-			    cpu_to_le32(zr->jpg_buffers.buffer[frame].frag_tab_bus);
-			zr->stat_com[i + 1] =
-			    cpu_to_le32(zr->jpg_buffers.buffer[frame].frag_tab_bus);
-		}
-		zr->jpg_buffers.buffer[frame].state = BUZ_STATE_DMA;
-		zr->jpg_dma_head++;
-
-	}
-	if (zr->codec_mode == BUZ_MODE_MOTION_DECOMPRESS)
-		zr->jpg_queued_num++;
-}
-
-/* when this is called the spinlock must be held */
-static void
-zoran_reap_stat_com (struct zoran *zr)
-{
-	/* move frames from DMA queue to done queue */
-
-	int i;
-	u32 stat_com;
-	unsigned int seq;
-	unsigned int dif;
-	struct zoran_jpg_buffer *buffer;
-	int frame;
-
-	/* In motion decompress we don't have a hardware frame counter,
-	 * we just count the interrupts here */
-
-	if (zr->codec_mode == BUZ_MODE_MOTION_DECOMPRESS) {
-		zr->jpg_seq_num++;
-	}
-	while (zr->jpg_dma_tail < zr->jpg_dma_head) {
-		if (zr->jpg_settings.TmpDcm == 1)
-			i = (zr->jpg_dma_tail -
-			     zr->jpg_err_shift) & BUZ_MASK_STAT_COM;
-		else
-			i = ((zr->jpg_dma_tail -
-			      zr->jpg_err_shift) & 1) * 2 + 1;
-
-		stat_com = le32_to_cpu(zr->stat_com[i]);
-
-		if ((stat_com & 1) == 0) {
-			return;
-		}
-		frame = zr->jpg_pend[zr->jpg_dma_tail & BUZ_MASK_FRAME];
-		buffer = &zr->jpg_buffers.buffer[frame];
-		do_gettimeofday(&buffer->bs.timestamp);
-
-		if (zr->codec_mode == BUZ_MODE_MOTION_COMPRESS) {
-			buffer->bs.length = (stat_com & 0x7fffff) >> 1;
-
-			/* update sequence number with the help of the counter in stat_com */
-
-			seq = ((stat_com >> 24) + zr->jpg_err_seq) & 0xff;
-			dif = (seq - zr->jpg_seq_num) & 0xff;
-			zr->jpg_seq_num += dif;
-		} else {
-			buffer->bs.length = 0;
-		}
-		buffer->bs.seq =
-		    zr->jpg_settings.TmpDcm ==
-		    2 ? (zr->jpg_seq_num >> 1) : zr->jpg_seq_num;
-		buffer->state = BUZ_STATE_DONE;
-
-		zr->jpg_dma_tail++;
-	}
-}
-
-static void
-error_handler (struct zoran *zr,
-	       u32           astat,
-	       u32           stat)
-{
-	/* This is JPEG error handling part */
-	if ((zr->codec_mode != BUZ_MODE_MOTION_COMPRESS) &&
-	    (zr->codec_mode != BUZ_MODE_MOTION_DECOMPRESS)) {
-		//dprintk(1, KERN_ERR "%s: Internal error: error handling request in mode %d\n", ZR_DEVNAME(zr), zr->codec_mode);
-		return;
-	}
-
-	if ((stat & 1) == 0 &&
-	    zr->codec_mode == BUZ_MODE_MOTION_COMPRESS &&
-	    zr->jpg_dma_tail - zr->jpg_que_tail >=
-	     zr->jpg_buffers.num_buffers) {
-		/* No free buffers... */
-		zoran_reap_stat_com(zr);
-		zoran_feed_stat_com(zr);
-		wake_up_interruptible(&zr->jpg_capq);
-		zr->JPEG_missed = 0;
-		return;
-	}
-
-	if (zr->JPEG_error != 1) {
-		/*
-		 * First entry: error just happened during normal operation
-		 *
-		 * In BUZ_MODE_MOTION_COMPRESS:
-		 *
-		 * Possible glitch in TV signal. In this case we should
-		 * stop the codec and wait for good quality signal before
-		 * restarting it to avoid further problems
-		 *
-		 * In BUZ_MODE_MOTION_DECOMPRESS:
-		 *
-		 * Bad JPEG frame: we have to mark it as processed (codec crashed
-		 * and was not able to do it itself), and to remove it from queue.
-		 */
-		btand(~ZR36057_JMC_Go_en, ZR36057_JMC);
-		udelay(1);
-		stat = stat | (post_office_read(zr, 7, 0) & 3) << 8;
-		btwrite(0, ZR36057_JPC);
-		btor(ZR36057_MCTCR_CFlush, ZR36057_MCTCR);
-		jpeg_codec_reset(zr);
-		jpeg_codec_sleep(zr, 1);
-		zr->JPEG_error = 1;
-		zr->num_errors++;
-
-		/* Report error */
-		if (zr36067_debug > 1 && zr->num_errors <= 8) {
-			long frame;
-			frame =
-			    zr->jpg_pend[zr->jpg_dma_tail & BUZ_MASK_FRAME];
-			printk(KERN_ERR
-			       "%s: JPEG error stat=0x%08x(0x%08x) queue_state=%ld/%ld/%ld/%ld seq=%ld frame=%ld. Codec stopped. ",
-			       ZR_DEVNAME(zr), stat, zr->last_isr,
-			       zr->jpg_que_tail, zr->jpg_dma_tail,
-			       zr->jpg_dma_head, zr->jpg_que_head,
-			       zr->jpg_seq_num, frame);
-			printk("stat_com frames:");
-			{
-				int i, j;
-				for (j = 0; j < BUZ_NUM_STAT_COM; j++) {
-					for (i = 0;
-					     i < zr->jpg_buffers.num_buffers;
-					     i++) {
-						if (le32_to_cpu(zr->stat_com[j]) ==
-						    zr->jpg_buffers.
-						    buffer[i].
-						    frag_tab_bus) {
-							printk("% d->%d",
-							       j, i);
-						}
-					}
-				}
-				printk("\n");
-			}
-		}
-		/* Find an entry in stat_com and rotate contents */
-		{
-			int i;
-
-			if (zr->jpg_settings.TmpDcm == 1)
-				i = (zr->jpg_dma_tail -
-				     zr->jpg_err_shift) & BUZ_MASK_STAT_COM;
-			else
-				i = ((zr->jpg_dma_tail -
-				      zr->jpg_err_shift) & 1) * 2;
-			if (zr->codec_mode == BUZ_MODE_MOTION_DECOMPRESS) {
-				/* Mimic zr36067 operation */
-				zr->stat_com[i] |= cpu_to_le32(1);
-				if (zr->jpg_settings.TmpDcm != 1)
-					zr->stat_com[i + 1] |= cpu_to_le32(1);
-				/* Refill */
-				zoran_reap_stat_com(zr);
-				zoran_feed_stat_com(zr);
-				wake_up_interruptible(&zr->jpg_capq);
-				/* Find an entry in stat_com again after refill */
-				if (zr->jpg_settings.TmpDcm == 1)
-					i = (zr->jpg_dma_tail -
-					     zr->jpg_err_shift) &
-					    BUZ_MASK_STAT_COM;
-				else
-					i = ((zr->jpg_dma_tail -
-					      zr->jpg_err_shift) & 1) * 2;
-			}
-			if (i) {
-				/* Rotate stat_comm entries to make current entry first */
-				int j;
-				__le32 bus_addr[BUZ_NUM_STAT_COM];
-
-				/* Here we are copying the stat_com array, which
-				 * is already in little endian format, so
-				 * no endian conversions here
-				 */
-				memcpy(bus_addr, zr->stat_com,
-				       sizeof(bus_addr));
-				for (j = 0; j < BUZ_NUM_STAT_COM; j++) {
-					zr->stat_com[j] =
-					    bus_addr[(i + j) &
-						     BUZ_MASK_STAT_COM];
-
-				}
-				zr->jpg_err_shift += i;
-				zr->jpg_err_shift &= BUZ_MASK_STAT_COM;
-			}
-			if (zr->codec_mode == BUZ_MODE_MOTION_COMPRESS)
-				zr->jpg_err_seq = zr->jpg_seq_num;	/* + 1; */
-		}
-	}
-
-	/* Now the stat_comm buffer is ready for restart */
-	do {
-		int status, mode;
-
-		if (zr->codec_mode == BUZ_MODE_MOTION_COMPRESS) {
-			decoder_command(zr, DECODER_GET_STATUS, &status);
-			mode = CODEC_DO_COMPRESSION;
-		} else {
-			status = 0;
-			mode = CODEC_DO_EXPANSION;
-		}
-		if (zr->codec_mode == BUZ_MODE_MOTION_DECOMPRESS ||
-		    (status & DECODER_STATUS_GOOD)) {
-			/********** RESTART code *************/
-			jpeg_codec_reset(zr);
-			zr->codec->set_mode(zr->codec, mode);
-			zr36057_set_jpg(zr, zr->codec_mode);
-			jpeg_start(zr);
-
-			if (zr->num_errors <= 8)
-				dprintk(2, KERN_INFO "%s: Restart\n",
-					ZR_DEVNAME(zr));
-
-			zr->JPEG_missed = 0;
-			zr->JPEG_error = 2;
-			/********** End RESTART code ***********/
-		}
-	} while (0);
-}
-
-irqreturn_t
-zoran_irq (int             irq,
-	   void           *dev_id)
-{
-	u32 stat, astat;
-	int count;
-	struct zoran *zr;
-	unsigned long flags;
-
-	zr = dev_id;
-	count = 0;
-
-	if (zr->testing) {
-		/* Testing interrupts */
-		spin_lock_irqsave(&zr->spinlock, flags);
-		while ((stat = count_reset_interrupt(zr))) {
-			if (count++ > 100) {
-				btand(~ZR36057_ICR_IntPinEn, ZR36057_ICR);
-				dprintk(1,
-					KERN_ERR
-					"%s: IRQ lockup while testing, isr=0x%08x, cleared int mask\n",
-					ZR_DEVNAME(zr), stat);
-				wake_up_interruptible(&zr->test_q);
-			}
-		}
-		zr->last_isr = stat;
-		spin_unlock_irqrestore(&zr->spinlock, flags);
-		return IRQ_HANDLED;
-	}
-
-	spin_lock_irqsave(&zr->spinlock, flags);
-	while (1) {
-		/* get/clear interrupt status bits */
-		stat = count_reset_interrupt(zr);
-		astat = stat & IRQ_MASK;
-		if (!astat) {
-			break;
-		}
-		dprintk(4,
-			KERN_DEBUG
-			"zoran_irq: astat: 0x%08x, mask: 0x%08x\n",
-			astat, btread(ZR36057_ICR));
-		if (astat & zr->card.vsync_int) {	// SW
-
-			if (zr->codec_mode == BUZ_MODE_MOTION_DECOMPRESS ||
-			    zr->codec_mode == BUZ_MODE_MOTION_COMPRESS) {
-				/* count missed interrupts */
-				zr->JPEG_missed++;
-			}
-			//post_office_read(zr,1,0);
-			/* Interrupts may still happen when
-			 * zr->v4l_memgrab_active is switched off.
-			 * We simply ignore them */
-
-			if (zr->v4l_memgrab_active) {
-
-				/* A lot more checks should be here ... */
-				if ((btread(ZR36057_VSSFGR) &
-				     ZR36057_VSSFGR_SnapShot) == 0)
-					dprintk(1,
-						KERN_WARNING
-						"%s: BuzIRQ with SnapShot off ???\n",
-						ZR_DEVNAME(zr));
-
-				if (zr->v4l_grab_frame != NO_GRAB_ACTIVE) {
-					/* There is a grab on a frame going on, check if it has finished */
-
-					if ((btread(ZR36057_VSSFGR) &
-					     ZR36057_VSSFGR_FrameGrab) ==
-					    0) {
-						/* it is finished, notify the user */
-
-						zr->v4l_buffers.buffer[zr->v4l_grab_frame].state = BUZ_STATE_DONE;
-						zr->v4l_buffers.buffer[zr->v4l_grab_frame].bs.seq = zr->v4l_grab_seq;
-						do_gettimeofday(&zr->v4l_buffers.buffer[zr->v4l_grab_frame].bs.timestamp);
-						zr->v4l_grab_frame = NO_GRAB_ACTIVE;
-						zr->v4l_pend_tail++;
-					}
-				}
-
-				if (zr->v4l_grab_frame == NO_GRAB_ACTIVE)
-					wake_up_interruptible(&zr->v4l_capq);
-
-				/* Check if there is another grab queued */
-
-				if (zr->v4l_grab_frame == NO_GRAB_ACTIVE &&
-				    zr->v4l_pend_tail != zr->v4l_pend_head) {
-
-					int frame = zr->v4l_pend[zr->v4l_pend_tail &
-							 V4L_MASK_FRAME];
-					u32 reg;
-
-					zr->v4l_grab_frame = frame;
-
-					/* Set zr36057 video front end and enable video */
-
-					/* Buffer address */
-
-					reg =
-					    zr->v4l_buffers.buffer[frame].
-					    fbuffer_bus;
-					btwrite(reg, ZR36057_VDTR);
-					if (zr->v4l_settings.height >
-					    BUZ_MAX_HEIGHT / 2)
-						reg +=
-						    zr->v4l_settings.
-						    bytesperline;
-					btwrite(reg, ZR36057_VDBR);
-
-					/* video stride, status, and frame grab register */
-					reg = 0;
-					if (zr->v4l_settings.height >
-					    BUZ_MAX_HEIGHT / 2)
-						reg +=
-						    zr->v4l_settings.
-						    bytesperline;
-					reg =
-					    (reg <<
-					     ZR36057_VSSFGR_DispStride);
-					reg |= ZR36057_VSSFGR_VidOvf;
-					reg |= ZR36057_VSSFGR_SnapShot;
-					reg |= ZR36057_VSSFGR_FrameGrab;
-					btwrite(reg, ZR36057_VSSFGR);
-
-					btor(ZR36057_VDCR_VidEn,
-					     ZR36057_VDCR);
-				}
-			}
-
-			/* even if we don't grab, we do want to increment
-			 * the sequence counter to see lost frames */
-			zr->v4l_grab_seq++;
-		}
-#if (IRQ_MASK & ZR36057_ISR_CodRepIRQ)
-		if (astat & ZR36057_ISR_CodRepIRQ) {
-			zr->intr_counter_CodRepIRQ++;
-			IDEBUG(printk
-			       (KERN_DEBUG "%s: ZR36057_ISR_CodRepIRQ\n",
-				ZR_DEVNAME(zr)));
-			btand(~ZR36057_ICR_CodRepIRQ, ZR36057_ICR);
-		}
-#endif				/* (IRQ_MASK & ZR36057_ISR_CodRepIRQ) */
-
-#if (IRQ_MASK & ZR36057_ISR_JPEGRepIRQ)
-		if (astat & ZR36057_ISR_JPEGRepIRQ) {
-
-			if (zr->codec_mode == BUZ_MODE_MOTION_DECOMPRESS ||
-			    zr->codec_mode == BUZ_MODE_MOTION_COMPRESS) {
-				if (zr36067_debug > 1 &&
-				    (!zr->frame_num || zr->JPEG_error)) {
-					printk(KERN_INFO
-					       "%s: first frame ready: state=0x%08x odd_even=%d field_per_buff=%d delay=%d\n",
-					       ZR_DEVNAME(zr), stat,
-					       zr->jpg_settings.odd_even,
-					       zr->jpg_settings.
-					       field_per_buff,
-					       zr->JPEG_missed);
-					{
-						char sc[] = "0000";
-						char sv[5];
-						int i;
-						strcpy(sv, sc);
-						for (i = 0; i < 4; i++) {
-							if (le32_to_cpu(zr->stat_com[i]) & 1)
-								sv[i] = '1';
-						}
-						sv[4] = 0;
-						printk(KERN_INFO
-						       "%s: stat_com=%s queue_state=%ld/%ld/%ld/%ld\n",
-						       ZR_DEVNAME(zr), sv,
-						       zr->jpg_que_tail,
-						       zr->jpg_dma_tail,
-						       zr->jpg_dma_head,
-						       zr->jpg_que_head);
-					}
-				} else {
-					if (zr->JPEG_missed > zr->JPEG_max_missed)	// Get statistics
-						zr->JPEG_max_missed =
-						    zr->JPEG_missed;
-					if (zr->JPEG_missed <
-					    zr->JPEG_min_missed)
-						zr->JPEG_min_missed =
-						    zr->JPEG_missed;
-				}
-
-				if (zr36067_debug > 2 && zr->frame_num < 6) {
-					int i;
-					printk("%s: seq=%ld stat_com:",
-					       ZR_DEVNAME(zr), zr->jpg_seq_num);
-					for (i = 0; i < 4; i++) {
-						printk(" %08x",
-						       le32_to_cpu(zr->stat_com[i]));
-					}
-					printk("\n");
-				}
-				zr->frame_num++;
-				zr->JPEG_missed = 0;
-				zr->JPEG_error = 0;
-				zoran_reap_stat_com(zr);
-				zoran_feed_stat_com(zr);
-				wake_up_interruptible(&zr->jpg_capq);
-			} /*else {
-			      dprintk(1,
-					KERN_ERR
-					"%s: JPEG interrupt while not in motion (de)compress mode!\n",
-					ZR_DEVNAME(zr));
-			}*/
-		}
-#endif				/* (IRQ_MASK & ZR36057_ISR_JPEGRepIRQ) */
-
-		/* DATERR, too many fields missed, error processing */
-		if ((astat & zr->card.jpeg_int) ||
-		    zr->JPEG_missed > 25 ||
-		    zr->JPEG_error == 1	||
-		    ((zr->codec_mode == BUZ_MODE_MOTION_DECOMPRESS) &&
-		     (zr->frame_num & (zr->JPEG_missed >
-				       zr->jpg_settings.field_per_buff)))) {
-			error_handler(zr, astat, stat);
-		}
-
-		count++;
-		if (count > 10) {
-			dprintk(2, KERN_WARNING "%s: irq loop %d\n",
-				ZR_DEVNAME(zr), count);
-			if (count > 20) {
-				btand(~ZR36057_ICR_IntPinEn, ZR36057_ICR);
-				dprintk(2,
-					KERN_ERR
-					"%s: IRQ lockup, cleared int mask\n",
-					ZR_DEVNAME(zr));
-				break;
-			}
-		}
-		zr->last_isr = stat;
-	}
-	spin_unlock_irqrestore(&zr->spinlock, flags);
-
-	return IRQ_HANDLED;
-}
-
-void
-zoran_set_pci_master (struct zoran *zr,
-		      int           set_master)
-{
-	if (set_master) {
-		pci_set_master(zr->pci_dev);
-	} else {
-		u16 command;
-
-		pci_read_config_word(zr->pci_dev, PCI_COMMAND, &command);
-		command &= ~PCI_COMMAND_MASTER;
-		pci_write_config_word(zr->pci_dev, PCI_COMMAND, command);
-	}
-}
-
-void
-zoran_init_hardware (struct zoran *zr)
-{
-	int j, zero = 0;
-
-	/* Enable bus-mastering */
-	zoran_set_pci_master(zr, 1);
-
-	/* Initialize the board */
-	if (zr->card.init) {
-		zr->card.init(zr);
-	}
-
-	j = zr->card.input[zr->input].muxsel;
-
-	decoder_command(zr, 0, NULL);
-	decoder_command(zr, DECODER_SET_NORM, &zr->norm);
-	decoder_command(zr, DECODER_SET_INPUT, &j);
-
-	encoder_command(zr, 0, NULL);
-	encoder_command(zr, ENCODER_SET_NORM, &zr->norm);
-	encoder_command(zr, ENCODER_SET_INPUT, &zero);
-
-	/* toggle JPEG codec sleep to sync PLL */
-	jpeg_codec_sleep(zr, 1);
-	jpeg_codec_sleep(zr, 0);
-
-	/* set individual interrupt enables (without GIRQ1)
-	 * but don't global enable until zoran_open() */
-
-	//btwrite(IRQ_MASK & ~ZR36057_ISR_GIRQ1, ZR36057_ICR);  // SW
-	// It looks like using only JPEGRepIRQEn is not always reliable,
-	// may be when JPEG codec crashes it won't generate IRQ? So,
-	 /*CP*/			//        btwrite(IRQ_MASK, ZR36057_ICR); // Enable Vsync interrupts too. SM    WHY ? LP
-	    zr36057_init_vfe(zr);
-
-	zr36057_enable_jpg(zr, BUZ_MODE_IDLE);
-
-	btwrite(IRQ_MASK, ZR36057_ISR);	// Clears interrupts
-}
-
-void
-zr36057_restart (struct zoran *zr)
-{
-	btwrite(0, ZR36057_SPGPPCR);
-	mdelay(1);
-	btor(ZR36057_SPGPPCR_SoftReset, ZR36057_SPGPPCR);
-	mdelay(1);
-
-	/* assert P_Reset */
-	btwrite(0, ZR36057_JPC);
-	/* set up GPIO direction - all output */
-	btwrite(ZR36057_SPGPPCR_SoftReset | 0, ZR36057_SPGPPCR);
-
-	/* set up GPIO pins and guest bus timing */
-	btwrite((0x81 << 24) | 0x8888, ZR36057_GPPGCR1);
-}
-
-/*
- * initialize video front end
- */
-
-static void
-zr36057_init_vfe (struct zoran *zr)
-{
-	u32 reg;
-
-	reg = btread(ZR36057_VFESPFR);
-	reg |= ZR36057_VFESPFR_LittleEndian;
-	reg &= ~ZR36057_VFESPFR_VCLKPol;
-	reg |= ZR36057_VFESPFR_ExtFl;
-	reg |= ZR36057_VFESPFR_TopField;
-	btwrite(reg, ZR36057_VFESPFR);
-	reg = btread(ZR36057_VDCR);
-	if (pci_pci_problems & PCIPCI_TRITON)
-		// || zr->revision < 1) // Revision 1 has also Triton support
-		reg &= ~ZR36057_VDCR_Triton;
-	else
-		reg |= ZR36057_VDCR_Triton;
-	btwrite(reg, ZR36057_VDCR);
-}
-
-/*
- * Interface to decoder and encoder chips using i2c bus
- */
-
-int
-decoder_command (struct zoran *zr,
-		 int           cmd,
-		 void         *data)
-{
-	if (zr->decoder == NULL)
-		return -EIO;
-
-	if (zr->card.type == LML33 &&
-	    (cmd == DECODER_SET_NORM || cmd == DECODER_SET_INPUT)) {
-		int res;
-
-		// Bt819 needs to reset its FIFO buffer using #FRST pin and
-		// LML33 card uses GPIO(7) for that.
-		GPIO(zr, 7, 0);
-		res = zr->decoder->driver->command(zr->decoder, cmd, data);
-		// Pull #FRST high.
-		GPIO(zr, 7, 1);
-		return res;
-	} else
-		return zr->decoder->driver->command(zr->decoder, cmd,
-						    data);
-}
-
-int
-encoder_command (struct zoran *zr,
-		 int           cmd,
-		 void         *data)
-{
-	if (zr->encoder == NULL)
-		return -1;
-
-	return zr->encoder->driver->command(zr->encoder, cmd, data);
-}
diff --git a/drivers/media/video/zoran_device.h b/drivers/media/video/zoran_device.h
deleted file mode 100644
index 37fa86a..0000000
--- a/drivers/media/video/zoran_device.h
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Zoran zr36057/zr36067 PCI controller driver, for the
- * Pinnacle/Miro DC10/DC10+/DC30/DC30+, Iomega Buz, Linux
- * Media Labs LML33/LML33R10.
- *
- * This part handles card-specific data and detection
- *
- * Copyright (C) 2000 Serguei Miridonov <mirsev@cicese.mx>
- *
- * Currently maintained by:
- *   Ronald Bultje    <rbultje@ronald.bitfreak.net>
- *   Laurent Pinchart <laurent.pinchart@skynet.be>
- *   Mailinglist      <mjpeg-users@lists.sf.net>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU 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 __ZORAN_DEVICE_H__
-#define __ZORAN_DEVICE_H__
-
-/* general purpose I/O */
-extern void GPIO(struct zoran *zr,
-		 int bit,
-		 unsigned int value);
-
-/* codec (or actually: guest bus) access */
-extern int post_office_wait(struct zoran *zr);
-extern int post_office_write(struct zoran *zr,
-			     unsigned guest,
-			     unsigned reg,
-			     unsigned value);
-extern int post_office_read(struct zoran *zr,
-			    unsigned guest,
-			    unsigned reg);
-
-extern void detect_guest_activity(struct zoran *zr);
-
-extern void jpeg_codec_sleep(struct zoran *zr,
-			     int sleep);
-extern int jpeg_codec_reset(struct zoran *zr);
-
-/* zr360x7 access to raw capture */
-extern void zr36057_overlay(struct zoran *zr,
-			    int on);
-extern void write_overlay_mask(struct file *file,
-			       struct video_clip *vp,
-			       int count);
-extern void zr36057_set_memgrab(struct zoran *zr,
-				int mode);
-extern int wait_grab_pending(struct zoran *zr);
-
-/* interrupts */
-extern void print_interrupts(struct zoran *zr);
-extern void clear_interrupt_counters(struct zoran *zr);
-extern irqreturn_t zoran_irq(int irq, void *dev_id);
-
-/* JPEG codec access */
-extern void jpeg_start(struct zoran *zr);
-extern void zr36057_enable_jpg(struct zoran *zr,
-			       enum zoran_codec_mode mode);
-extern void zoran_feed_stat_com(struct zoran *zr);
-
-/* general */
-extern void zoran_set_pci_master(struct zoran *zr,
-				 int set_master);
-extern void zoran_init_hardware(struct zoran *zr);
-extern void zr36057_restart(struct zoran *zr);
-
-/* i2c */
-extern int decoder_command(struct zoran *zr,
-			   int cmd,
-			   void *data);
-extern int encoder_command(struct zoran *zr,
-			   int cmd,
-			   void *data);
-
-#endif				/* __ZORAN_DEVICE_H__ */
diff --git a/drivers/media/video/zoran_driver.c b/drivers/media/video/zoran_driver.c
deleted file mode 100644
index ec6f596..0000000
--- a/drivers/media/video/zoran_driver.c
+++ /dev/null
@@ -1,4651 +0,0 @@
-/*
- * Zoran zr36057/zr36067 PCI controller driver, for the
- * Pinnacle/Miro DC10/DC10+/DC30/DC30+, Iomega Buz, Linux
- * Media Labs LML33/LML33R10.
- *
- * Copyright (C) 2000 Serguei Miridonov <mirsev@cicese.mx>
- *
- * Changes for BUZ by Wolfgang Scherr <scherr@net4you.net>
- *
- * Changes for DC10/DC30 by Laurent Pinchart <laurent.pinchart@skynet.be>
- *
- * Changes for LML33R10 by Maxim Yevtyushkin <max@linuxmedialabs.com>
- *
- * Changes for videodev2/v4l2 by Ronald Bultje <rbultje@ronald.bitfreak.net>
- *
- * Based on
- *
- * Miro DC10 driver
- * Copyright (C) 1999 Wolfgang Scherr <scherr@net4you.net>
- *
- * Iomega Buz driver version 1.0
- * Copyright (C) 1999 Rainer Johanni <Rainer@Johanni.de>
- *
- * buz.0.0.3
- * Copyright (C) 1998 Dave Perks <dperks@ibm.net>
- *
- * bttv - Bt848 frame grabber driver
- * Copyright (C) 1996,97,98 Ralph  Metzler (rjkm@thp.uni-koeln.de)
- *                        & Marcus Metzler (mocm@thp.uni-koeln.de)
- *
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include <linux/version.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/delay.h>
-#include <linux/slab.h>
-#include <linux/pci.h>
-#include <linux/vmalloc.h>
-#include <linux/wait.h>
-
-#include <linux/interrupt.h>
-#include <linux/i2c.h>
-#include <linux/i2c-algo-bit.h>
-
-#include <linux/spinlock.h>
-#define     MAP_NR(x)       virt_to_page(x)
-#define     ZORAN_VID_TYPE  ( \
-				VID_TYPE_CAPTURE | \
-				VID_TYPE_OVERLAY | \
-				VID_TYPE_CLIPPING | \
-				VID_TYPE_FRAMERAM | \
-				VID_TYPE_SCALES | \
-				VID_TYPE_MJPEG_DECODER | \
-				VID_TYPE_MJPEG_ENCODER \
-			     )
-
-#include <linux/videodev.h>
-#include <media/v4l2-common.h>
-#include <media/v4l2-ioctl.h>
-#include "videocodec.h"
-
-#include <asm/byteorder.h>
-#include <asm/io.h>
-#include <asm/uaccess.h>
-#include <linux/proc_fs.h>
-
-#include <linux/video_decoder.h>
-#include <linux/video_encoder.h>
-#include <linux/mutex.h>
-#include "zoran.h"
-#include "zoran_device.h"
-#include "zoran_card.h"
-
-	/* we declare some card type definitions here, they mean
-	 * the same as the v4l1 ZORAN_VID_TYPE above, except it's v4l2 */
-#define ZORAN_V4L2_VID_FLAGS ( \
-				V4L2_CAP_STREAMING |\
-				V4L2_CAP_VIDEO_CAPTURE |\
-				V4L2_CAP_VIDEO_OUTPUT |\
-				V4L2_CAP_VIDEO_OVERLAY \
-			      )
-
-
-#if defined(CONFIG_VIDEO_V4L1_COMPAT)
-#define ZFMT(pal, fcc, cs) \
-	.palette = (pal), .fourcc = (fcc), .colorspace = (cs)
-#else
-#define ZFMT(pal, fcc, cs) \
-	.fourcc = (fcc), .colorspace = (cs)
-#endif
-
-const struct zoran_format zoran_formats[] = {
-	{
-		.name = "15-bit RGB LE",
-		ZFMT(VIDEO_PALETTE_RGB555,
-		     V4L2_PIX_FMT_RGB555, V4L2_COLORSPACE_SRGB),
-		.depth = 15,
-		.flags = ZORAN_FORMAT_CAPTURE |
-			 ZORAN_FORMAT_OVERLAY,
-		.vfespfr = ZR36057_VFESPFR_RGB555|ZR36057_VFESPFR_ErrDif|
-			   ZR36057_VFESPFR_LittleEndian,
-	}, {
-		.name = "15-bit RGB BE",
-		ZFMT(-1,
-		     V4L2_PIX_FMT_RGB555X, V4L2_COLORSPACE_SRGB),
-		.depth = 15,
-		.flags = ZORAN_FORMAT_CAPTURE |
-			 ZORAN_FORMAT_OVERLAY,
-		.vfespfr = ZR36057_VFESPFR_RGB555|ZR36057_VFESPFR_ErrDif,
-	}, {
-		.name = "16-bit RGB LE",
-		ZFMT(VIDEO_PALETTE_RGB565,
-		     V4L2_PIX_FMT_RGB565, V4L2_COLORSPACE_SRGB),
-		.depth = 16,
-		.flags = ZORAN_FORMAT_CAPTURE |
-			 ZORAN_FORMAT_OVERLAY,
-		.vfespfr = ZR36057_VFESPFR_RGB565|ZR36057_VFESPFR_ErrDif|
-			   ZR36057_VFESPFR_LittleEndian,
-	}, {
-		.name = "16-bit RGB BE",
-		ZFMT(-1,
-		     V4L2_PIX_FMT_RGB565, V4L2_COLORSPACE_SRGB),
-		.depth = 16,
-		.flags = ZORAN_FORMAT_CAPTURE |
-			 ZORAN_FORMAT_OVERLAY,
-		.vfespfr = ZR36057_VFESPFR_RGB565|ZR36057_VFESPFR_ErrDif,
-	}, {
-		.name = "24-bit RGB",
-		ZFMT(VIDEO_PALETTE_RGB24,
-		     V4L2_PIX_FMT_BGR24, V4L2_COLORSPACE_SRGB),
-		.depth = 24,
-		.flags = ZORAN_FORMAT_CAPTURE |
-			 ZORAN_FORMAT_OVERLAY,
-		.vfespfr = ZR36057_VFESPFR_RGB888|ZR36057_VFESPFR_Pack24,
-	}, {
-		.name = "32-bit RGB LE",
-		ZFMT(VIDEO_PALETTE_RGB32,
-		     V4L2_PIX_FMT_BGR32, V4L2_COLORSPACE_SRGB),
-		.depth = 32,
-		.flags = ZORAN_FORMAT_CAPTURE |
-			 ZORAN_FORMAT_OVERLAY,
-		.vfespfr = ZR36057_VFESPFR_RGB888|ZR36057_VFESPFR_LittleEndian,
-	}, {
-		.name = "32-bit RGB BE",
-		ZFMT(-1,
-		     V4L2_PIX_FMT_RGB32, V4L2_COLORSPACE_SRGB),
-		.depth = 32,
-		.flags = ZORAN_FORMAT_CAPTURE |
-			 ZORAN_FORMAT_OVERLAY,
-		.vfespfr = ZR36057_VFESPFR_RGB888,
-	}, {
-		.name = "4:2:2, packed, YUYV",
-		ZFMT(VIDEO_PALETTE_YUV422,
-		     V4L2_PIX_FMT_YUYV, V4L2_COLORSPACE_SMPTE170M),
-		.depth = 16,
-		.flags = ZORAN_FORMAT_CAPTURE |
-			 ZORAN_FORMAT_OVERLAY,
-		.vfespfr = ZR36057_VFESPFR_YUV422,
-	}, {
-		.name = "4:2:2, packed, UYVY",
-		ZFMT(VIDEO_PALETTE_UYVY,
-		     V4L2_PIX_FMT_UYVY, V4L2_COLORSPACE_SMPTE170M),
-		.depth = 16,
-		.flags = ZORAN_FORMAT_CAPTURE |
-			 ZORAN_FORMAT_OVERLAY,
-		.vfespfr = ZR36057_VFESPFR_YUV422|ZR36057_VFESPFR_LittleEndian,
-	}, {
-		.name = "Hardware-encoded Motion-JPEG",
-		ZFMT(-1,
-		     V4L2_PIX_FMT_MJPEG, V4L2_COLORSPACE_SMPTE170M),
-		.depth = 0,
-		.flags = ZORAN_FORMAT_CAPTURE |
-			 ZORAN_FORMAT_PLAYBACK |
-			 ZORAN_FORMAT_COMPRESSED,
-	}
-};
-#define NUM_FORMATS ARRAY_SIZE(zoran_formats)
-
-// RJ: Test only - want to test BUZ_USE_HIMEM even when CONFIG_BIGPHYS_AREA is defined
-
-
-extern int v4l_nbufs;
-extern int v4l_bufsize;
-extern int jpg_nbufs;
-extern int jpg_bufsize;
-extern int pass_through;
-
-static int lock_norm;	/* 0 = default 1 = Don't change TV standard (norm) */
-module_param(lock_norm, int, 0644);
-MODULE_PARM_DESC(lock_norm, "Prevent norm changes (1 = ignore, >1 = fail)");
-
-	/* small helper function for calculating buffersizes for v4l2
-	 * we calculate the nearest higher power-of-two, which
-	 * will be the recommended buffersize */
-static __u32
-zoran_v4l2_calc_bufsize (struct zoran_jpg_settings *settings)
-{
-	__u8 div = settings->VerDcm * settings->HorDcm * settings->TmpDcm;
-	__u32 num = (1024 * 512) / (div);
-	__u32 result = 2;
-
-	num--;
-	while (num) {
-		num >>= 1;
-		result <<= 1;
-	}
-
-	if (result > jpg_bufsize)
-		return jpg_bufsize;
-	if (result < 8192)
-		return 8192;
-	return result;
-}
-
-/* forward references */
-static void v4l_fbuffer_free(struct file *file);
-static void jpg_fbuffer_free(struct file *file);
-
-/*
- *   Allocate the V4L grab buffers
- *
- *   These have to be pysically contiguous.
- *   If v4l_bufsize <= MAX_KMALLOC_MEM we use kmalloc
- *   else we try to allocate them with bigphysarea_alloc_pages
- *   if the bigphysarea patch is present in the kernel,
- *   else we try to use high memory (if the user has bootet
- *   Linux with the necessary memory left over).
- */
-
-static unsigned long
-get_high_mem (unsigned long size)
-{
-/*
- * Check if there is usable memory at the end of Linux memory
- * of at least size. Return the physical address of this memory,
- * return 0 on failure.
- *
- * The idea is from Alexandro Rubini's book "Linux device drivers".
- * The driver from him which is downloadable from O'Reilly's
- * web site misses the "virt_to_phys(high_memory)" part
- * (and therefore doesn't work at all - at least with 2.2.x kernels).
- *
- * It should be unnecessary to mention that THIS IS DANGEROUS,
- * if more than one driver at a time has the idea to use this memory!!!!
- */
-
-	volatile unsigned char __iomem *mem;
-	unsigned char c;
-	unsigned long hi_mem_ph;
-	unsigned long i;
-
-	/* Map the high memory to user space */
-
-	hi_mem_ph = virt_to_phys(high_memory);
-
-	mem = ioremap(hi_mem_ph, size);
-	if (!mem) {
-		dprintk(1,
-			KERN_ERR "%s: get_high_mem() - ioremap failed\n",
-			ZORAN_NAME);
-		return 0;
-	}
-
-	for (i = 0; i < size; i++) {
-		/* Check if it is memory */
-		c = i & 0xff;
-		writeb(c, mem + i);
-		if (readb(mem + i) != c)
-			break;
-		c = 255 - c;
-		writeb(c, mem + i);
-		if (readb(mem + i) != c)
-			break;
-		writeb(0, mem + i);	/* zero out memory */
-
-		/* give the kernel air to breath */
-		if ((i & 0x3ffff) == 0x3ffff)
-			schedule();
-	}
-
-	iounmap(mem);
-
-	if (i != size) {
-		dprintk(1,
-			KERN_ERR
-			"%s: get_high_mem() - requested %lu, avail %lu\n",
-			ZORAN_NAME, size, i);
-		return 0;
-	}
-
-	return hi_mem_ph;
-}
-
-static int
-v4l_fbuffer_alloc (struct file *file)
-{
-	struct zoran_fh *fh = file->private_data;
-	struct zoran *zr = fh->zr;
-	int i, off;
-	unsigned char *mem;
-	unsigned long pmem = 0;
-
-	/* we might have old buffers lying around... */
-	if (fh->v4l_buffers.ready_to_be_freed) {
-		v4l_fbuffer_free(file);
-	}
-
-	for (i = 0; i < fh->v4l_buffers.num_buffers; i++) {
-		if (fh->v4l_buffers.buffer[i].fbuffer)
-			dprintk(2,
-				KERN_WARNING
-				"%s: v4l_fbuffer_alloc() - buffer %d allready allocated!?\n",
-				ZR_DEVNAME(zr), i);
-
-		//udelay(20);
-		if (fh->v4l_buffers.buffer_size <= MAX_KMALLOC_MEM) {
-			/* Use kmalloc */
-
-			mem = kmalloc(fh->v4l_buffers.buffer_size, GFP_KERNEL);
-			if (!mem) {
-				dprintk(1,
-					KERN_ERR
-					"%s: v4l_fbuffer_alloc() - kmalloc for V4L buf %d failed\n",
-					ZR_DEVNAME(zr), i);
-				v4l_fbuffer_free(file);
-				return -ENOBUFS;
-			}
-			fh->v4l_buffers.buffer[i].fbuffer = mem;
-			fh->v4l_buffers.buffer[i].fbuffer_phys =
-			    virt_to_phys(mem);
-			fh->v4l_buffers.buffer[i].fbuffer_bus =
-			    virt_to_bus(mem);
-			for (off = 0; off < fh->v4l_buffers.buffer_size;
-			     off += PAGE_SIZE)
-				SetPageReserved(MAP_NR(mem + off));
-			dprintk(4,
-				KERN_INFO
-				"%s: v4l_fbuffer_alloc() - V4L frame %d mem 0x%lx (bus: 0x%lx)\n",
-				ZR_DEVNAME(zr), i, (unsigned long) mem,
-				virt_to_bus(mem));
-		} else {
-
-			/* Use high memory which has been left at boot time */
-
-			/* Ok., Ok. this is an evil hack - we make
-			 * the assumption that physical addresses are
-			 * the same as bus addresses (true at least
-			 * for Intel processors). The whole method of
-			 * obtaining and using this memory is not very
-			 * nice - but I hope it saves some poor users
-			 * from kernel hacking, which might have even
-			 * more evil results */
-
-			if (i == 0) {
-				int size =
-				    fh->v4l_buffers.num_buffers *
-				    fh->v4l_buffers.buffer_size;
-
-				pmem = get_high_mem(size);
-				if (pmem == 0) {
-					dprintk(1,
-						KERN_ERR
-						"%s: v4l_fbuffer_alloc() - get_high_mem (size = %d KB) for V4L bufs failed\n",
-						ZR_DEVNAME(zr), size >> 10);
-					return -ENOBUFS;
-				}
-				fh->v4l_buffers.buffer[0].fbuffer = NULL;
-				fh->v4l_buffers.buffer[0].fbuffer_phys = pmem;
-				fh->v4l_buffers.buffer[0].fbuffer_bus = pmem;
-				dprintk(4,
-					KERN_INFO
-					"%s: v4l_fbuffer_alloc() - using %d KB high memory\n",
-					ZR_DEVNAME(zr), size >> 10);
-			} else {
-				fh->v4l_buffers.buffer[i].fbuffer = NULL;
-				fh->v4l_buffers.buffer[i].fbuffer_phys =
-				    pmem + i * fh->v4l_buffers.buffer_size;
-				fh->v4l_buffers.buffer[i].fbuffer_bus =
-				    pmem + i * fh->v4l_buffers.buffer_size;
-			}
-		}
-	}
-
-	fh->v4l_buffers.allocated = 1;
-
-	return 0;
-}
-
-/* free the V4L grab buffers */
-static void
-v4l_fbuffer_free (struct file *file)
-{
-	struct zoran_fh *fh = file->private_data;
-	struct zoran *zr = fh->zr;
-	int i, off;
-	unsigned char *mem;
-
-	dprintk(4, KERN_INFO "%s: v4l_fbuffer_free()\n", ZR_DEVNAME(zr));
-
-	for (i = 0; i < fh->v4l_buffers.num_buffers; i++) {
-		if (!fh->v4l_buffers.buffer[i].fbuffer)
-			continue;
-
-		if (fh->v4l_buffers.buffer_size <= MAX_KMALLOC_MEM) {
-			mem = fh->v4l_buffers.buffer[i].fbuffer;
-			for (off = 0; off < fh->v4l_buffers.buffer_size;
-			     off += PAGE_SIZE)
-				ClearPageReserved(MAP_NR(mem + off));
-			kfree((void *) fh->v4l_buffers.buffer[i].fbuffer);
-		}
-		fh->v4l_buffers.buffer[i].fbuffer = NULL;
-	}
-
-	fh->v4l_buffers.allocated = 0;
-	fh->v4l_buffers.ready_to_be_freed = 0;
-}
-
-/*
- *   Allocate the MJPEG grab buffers.
- *
- *   If the requested buffer size is smaller than MAX_KMALLOC_MEM,
- *   kmalloc is used to request a physically contiguous area,
- *   else we allocate the memory in framgents with get_zeroed_page.
- *
- *   If a Natoma chipset is present and this is a revision 1 zr36057,
- *   each MJPEG buffer needs to be physically contiguous.
- *   (RJ: This statement is from Dave Perks' original driver,
- *   I could never check it because I have a zr36067)
- *   The driver cares about this because it reduces the buffer
- *   size to MAX_KMALLOC_MEM in that case (which forces contiguous allocation).
- *
- *   RJ: The contents grab buffers needs never be accessed in the driver.
- *       Therefore there is no need to allocate them with vmalloc in order
- *       to get a contiguous virtual memory space.
- *       I don't understand why many other drivers first allocate them with
- *       vmalloc (which uses internally also get_zeroed_page, but delivers you
- *       virtual addresses) and then again have to make a lot of efforts
- *       to get the physical address.
- *
- *   Ben Capper:
- *       On big-endian architectures (such as ppc) some extra steps
- *       are needed. When reading and writing to the stat_com array
- *       and fragment buffers, the device expects to see little-
- *       endian values. The use of cpu_to_le32() and le32_to_cpu()
- *       in this function (and one or two others in zoran_device.c)
- *       ensure that these values are always stored in little-endian
- *       form, regardless of architecture. The zr36057 does Very Bad
- *       Things on big endian architectures if the stat_com array
- *       and fragment buffers are not little-endian.
- */
-
-static int
-jpg_fbuffer_alloc (struct file *file)
-{
-	struct zoran_fh *fh = file->private_data;
-	struct zoran *zr = fh->zr;
-	int i, j, off;
-	unsigned long mem;
-
-	/* we might have old buffers lying around */
-	if (fh->jpg_buffers.ready_to_be_freed) {
-		jpg_fbuffer_free(file);
-	}
-
-	for (i = 0; i < fh->jpg_buffers.num_buffers; i++) {
-		if (fh->jpg_buffers.buffer[i].frag_tab)
-			dprintk(2,
-				KERN_WARNING
-				"%s: jpg_fbuffer_alloc() - buffer %d allready allocated!?\n",
-				ZR_DEVNAME(zr), i);
-
-		/* Allocate fragment table for this buffer */
-
-		mem = get_zeroed_page(GFP_KERNEL);
-		if (mem == 0) {
-			dprintk(1,
-				KERN_ERR
-				"%s: jpg_fbuffer_alloc() - get_zeroed_page (frag_tab) failed for buffer %d\n",
-				ZR_DEVNAME(zr), i);
-			jpg_fbuffer_free(file);
-			return -ENOBUFS;
-		}
-		fh->jpg_buffers.buffer[i].frag_tab = (__le32 *) mem;
-		fh->jpg_buffers.buffer[i].frag_tab_bus =
-		    virt_to_bus((void *) mem);
-
-		//if (alloc_contig) {
-		if (fh->jpg_buffers.need_contiguous) {
-			mem =
-			    (unsigned long) kmalloc(fh->jpg_buffers.
-						    buffer_size,
-						    GFP_KERNEL);
-			if (mem == 0) {
-				dprintk(1,
-					KERN_ERR
-					"%s: jpg_fbuffer_alloc() - kmalloc failed for buffer %d\n",
-					ZR_DEVNAME(zr), i);
-				jpg_fbuffer_free(file);
-				return -ENOBUFS;
-			}
-			fh->jpg_buffers.buffer[i].frag_tab[0] =
-			    cpu_to_le32(virt_to_bus((void *) mem));
-			fh->jpg_buffers.buffer[i].frag_tab[1] =
-			    cpu_to_le32(((fh->jpg_buffers.buffer_size / 4) << 1) | 1);
-			for (off = 0; off < fh->jpg_buffers.buffer_size;
-			     off += PAGE_SIZE)
-				SetPageReserved(MAP_NR(mem + off));
-		} else {
-			/* jpg_bufsize is allreay page aligned */
-			for (j = 0;
-			     j < fh->jpg_buffers.buffer_size / PAGE_SIZE;
-			     j++) {
-				mem = get_zeroed_page(GFP_KERNEL);
-				if (mem == 0) {
-					dprintk(1,
-						KERN_ERR
-						"%s: jpg_fbuffer_alloc() - get_zeroed_page failed for buffer %d\n",
-						ZR_DEVNAME(zr), i);
-					jpg_fbuffer_free(file);
-					return -ENOBUFS;
-				}
-
-				fh->jpg_buffers.buffer[i].frag_tab[2 * j] =
-				    cpu_to_le32(virt_to_bus((void *) mem));
-				fh->jpg_buffers.buffer[i].frag_tab[2 * j +
-								   1] =
-				    cpu_to_le32((PAGE_SIZE / 4) << 1);
-				SetPageReserved(MAP_NR(mem));
-			}
-
-			fh->jpg_buffers.buffer[i].frag_tab[2 * j - 1] |= cpu_to_le32(1);
-		}
-	}
-
-	dprintk(4,
-		KERN_DEBUG "%s: jpg_fbuffer_alloc() - %d KB allocated\n",
-		ZR_DEVNAME(zr),
-		(fh->jpg_buffers.num_buffers *
-		 fh->jpg_buffers.buffer_size) >> 10);
-
-	fh->jpg_buffers.allocated = 1;
-
-	return 0;
-}
-
-/* free the MJPEG grab buffers */
-static void
-jpg_fbuffer_free (struct file *file)
-{
-	struct zoran_fh *fh = file->private_data;
-	struct zoran *zr = fh->zr;
-	int i, j, off;
-	unsigned char *mem;
-
-	dprintk(4, KERN_DEBUG "%s: jpg_fbuffer_free()\n", ZR_DEVNAME(zr));
-
-	for (i = 0; i < fh->jpg_buffers.num_buffers; i++) {
-		if (!fh->jpg_buffers.buffer[i].frag_tab)
-			continue;
-
-		//if (alloc_contig) {
-		if (fh->jpg_buffers.need_contiguous) {
-			if (fh->jpg_buffers.buffer[i].frag_tab[0]) {
-				mem = (unsigned char *) bus_to_virt(le32_to_cpu(
-					fh->jpg_buffers.buffer[i].frag_tab[0]));
-				for (off = 0;
-				     off < fh->jpg_buffers.buffer_size;
-				     off += PAGE_SIZE)
-					ClearPageReserved(MAP_NR
-							  (mem + off));
-				kfree(mem);
-				fh->jpg_buffers.buffer[i].frag_tab[0] = 0;
-				fh->jpg_buffers.buffer[i].frag_tab[1] = 0;
-			}
-		} else {
-			for (j = 0;
-			     j < fh->jpg_buffers.buffer_size / PAGE_SIZE;
-			     j++) {
-				if (!fh->jpg_buffers.buffer[i].
-				    frag_tab[2 * j])
-					break;
-				ClearPageReserved(MAP_NR
-						  (bus_to_virt
-						   (le32_to_cpu
-						    (fh->jpg_buffers.
-						     buffer[i].frag_tab[2 *
-								       j]))));
-				free_page((unsigned long)
-					  bus_to_virt
-						  (le32_to_cpu
-						   (fh->jpg_buffers.
-						      buffer[i].
-						      frag_tab[2 * j])));
-				fh->jpg_buffers.buffer[i].frag_tab[2 * j] =
-				    0;
-				fh->jpg_buffers.buffer[i].frag_tab[2 * j +
-								   1] = 0;
-			}
-		}
-
-		free_page((unsigned long) fh->jpg_buffers.buffer[i].
-			  frag_tab);
-		fh->jpg_buffers.buffer[i].frag_tab = NULL;
-	}
-
-	fh->jpg_buffers.allocated = 0;
-	fh->jpg_buffers.ready_to_be_freed = 0;
-}
-
-/*
- *   V4L Buffer grabbing
- */
-
-static int
-zoran_v4l_set_format (struct file               *file,
-		      int                        width,
-		      int                        height,
-		      const struct zoran_format *format)
-{
-	struct zoran_fh *fh = file->private_data;
-	struct zoran *zr = fh->zr;
-	int bpp;
-
-	/* Check size and format of the grab wanted */
-
-	if (height < BUZ_MIN_HEIGHT || width < BUZ_MIN_WIDTH ||
-	    height > BUZ_MAX_HEIGHT || width > BUZ_MAX_WIDTH) {
-		dprintk(1,
-			KERN_ERR
-			"%s: v4l_set_format() - wrong frame size (%dx%d)\n",
-			ZR_DEVNAME(zr), width, height);
-		return -EINVAL;
-	}
-
-	bpp = (format->depth + 7) / 8;
-
-	/* Check against available buffer size */
-	if (height * width * bpp > fh->v4l_buffers.buffer_size) {
-		dprintk(1,
-			KERN_ERR
-			"%s: v4l_set_format() - video buffer size (%d kB) is too small\n",
-			ZR_DEVNAME(zr), fh->v4l_buffers.buffer_size >> 10);
-		return -EINVAL;
-	}
-
-	/* The video front end needs 4-byte alinged line sizes */
-
-	if ((bpp == 2 && (width & 1)) || (bpp == 3 && (width & 3))) {
-		dprintk(1,
-			KERN_ERR
-			"%s: v4l_set_format() - wrong frame alingment\n",
-			ZR_DEVNAME(zr));
-		return -EINVAL;
-	}
-
-	fh->v4l_settings.width = width;
-	fh->v4l_settings.height = height;
-	fh->v4l_settings.format = format;
-	fh->v4l_settings.bytesperline = bpp * fh->v4l_settings.width;
-
-	return 0;
-}
-
-static int
-zoran_v4l_queue_frame (struct file *file,
-		       int          num)
-{
-	struct zoran_fh *fh = file->private_data;
-	struct zoran *zr = fh->zr;
-	unsigned long flags;
-	int res = 0;
-
-	if (!fh->v4l_buffers.allocated) {
-		dprintk(1,
-			KERN_ERR
-			"%s: v4l_queue_frame() - buffers not yet allocated\n",
-			ZR_DEVNAME(zr));
-		res = -ENOMEM;
-	}
-
-	/* No grabbing outside the buffer range! */
-	if (num >= fh->v4l_buffers.num_buffers || num < 0) {
-		dprintk(1,
-			KERN_ERR
-			"%s: v4l_queue_frame() - buffer %d is out of range\n",
-			ZR_DEVNAME(zr), num);
-		res = -EINVAL;
-	}
-
-	spin_lock_irqsave(&zr->spinlock, flags);
-
-	if (fh->v4l_buffers.active == ZORAN_FREE) {
-		if (zr->v4l_buffers.active == ZORAN_FREE) {
-			zr->v4l_buffers = fh->v4l_buffers;
-			fh->v4l_buffers.active = ZORAN_ACTIVE;
-		} else {
-			dprintk(1,
-				KERN_ERR
-				"%s: v4l_queue_frame() - another session is already capturing\n",
-				ZR_DEVNAME(zr));
-			res = -EBUSY;
-		}
-	}
-
-	/* make sure a grab isn't going on currently with this buffer */
-	if (!res) {
-		switch (zr->v4l_buffers.buffer[num].state) {
-		default:
-		case BUZ_STATE_PEND:
-			if (zr->v4l_buffers.active == ZORAN_FREE) {
-				fh->v4l_buffers.active = ZORAN_FREE;
-				zr->v4l_buffers.allocated = 0;
-			}
-			res = -EBUSY;	/* what are you doing? */
-			break;
-		case BUZ_STATE_DONE:
-			dprintk(2,
-				KERN_WARNING
-				"%s: v4l_queue_frame() - queueing buffer %d in state DONE!?\n",
-				ZR_DEVNAME(zr), num);
-		case BUZ_STATE_USER:
-			/* since there is at least one unused buffer there's room for at least
-			 * one more pend[] entry */
-			zr->v4l_pend[zr->v4l_pend_head++ &
-					V4L_MASK_FRAME] = num;
-			zr->v4l_buffers.buffer[num].state = BUZ_STATE_PEND;
-			zr->v4l_buffers.buffer[num].bs.length =
-			    fh->v4l_settings.bytesperline *
-			    zr->v4l_settings.height;
-			fh->v4l_buffers.buffer[num] =
-			    zr->v4l_buffers.buffer[num];
-			break;
-		}
-	}
-
-	spin_unlock_irqrestore(&zr->spinlock, flags);
-
-	if (!res && zr->v4l_buffers.active == ZORAN_FREE)
-		zr->v4l_buffers.active = fh->v4l_buffers.active;
-
-	return res;
-}
-
-static int
-v4l_grab (struct file       *file,
-	  struct video_mmap *mp)
-{
-	struct zoran_fh *fh = file->private_data;
-	struct zoran *zr = fh->zr;
-	int res = 0, i;
-
-	for (i = 0; i < NUM_FORMATS; i++) {
-		if (zoran_formats[i].palette == mp->format &&
-		    zoran_formats[i].flags & ZORAN_FORMAT_CAPTURE &&
-		    !(zoran_formats[i].flags & ZORAN_FORMAT_COMPRESSED))
-			break;
-	}
-	if (i == NUM_FORMATS || zoran_formats[i].depth == 0) {
-		dprintk(1,
-			KERN_ERR
-			"%s: v4l_grab() - wrong bytes-per-pixel format\n",
-			ZR_DEVNAME(zr));
-		return -EINVAL;
-	}
-
-	/*
-	 * To minimize the time spent in the IRQ routine, we avoid setting up
-	 * the video front end there.
-	 * If this grab has different parameters from a running streaming capture
-	 * we stop the streaming capture and start it over again.
-	 */
-	if (zr->v4l_memgrab_active &&
-	    (zr->v4l_settings.width != mp->width ||
-	     zr->v4l_settings.height != mp->height ||
-	     zr->v4l_settings.format->palette != mp->format)) {
-		res = wait_grab_pending(zr);
-		if (res)
-			return res;
-	}
-	if ((res = zoran_v4l_set_format(file,
-					mp->width,
-					mp->height,
-					&zoran_formats[i])))
-		return res;
-	zr->v4l_settings = fh->v4l_settings;
-
-	/* queue the frame in the pending queue */
-	if ((res = zoran_v4l_queue_frame(file, mp->frame))) {
-		fh->v4l_buffers.active = ZORAN_FREE;
-		return res;
-	}
-
-	/* put the 36057 into frame grabbing mode */
-	if (!res && !zr->v4l_memgrab_active)
-		zr36057_set_memgrab(zr, 1);
-
-	//dprintk(4, KERN_INFO "%s: Frame grab 3...\n", ZR_DEVNAME(zr));
-
-	return res;
-}
-
-/*
- * Sync on a V4L buffer
- */
-
-static int
-v4l_sync (struct file *file,
-	  int          frame)
-{
-	struct zoran_fh *fh = file->private_data;
-	struct zoran *zr = fh->zr;
-	unsigned long flags;
-
-	if (fh->v4l_buffers.active == ZORAN_FREE) {
-		dprintk(1,
-			KERN_ERR
-			"%s: v4l_sync() - no grab active for this session\n",
-			ZR_DEVNAME(zr));
-		return -EINVAL;
-	}
-
-	/* check passed-in frame number */
-	if (frame >= fh->v4l_buffers.num_buffers || frame < 0) {
-		dprintk(1,
-			KERN_ERR "%s: v4l_sync() - frame %d is invalid\n",
-			ZR_DEVNAME(zr), frame);
-		return -EINVAL;
-	}
-
-	/* Check if is buffer was queued at all */
-	if (zr->v4l_buffers.buffer[frame].state == BUZ_STATE_USER) {
-		dprintk(1,
-			KERN_ERR
-			"%s: v4l_sync() - attempt to sync on a buffer which was not queued?\n",
-			ZR_DEVNAME(zr));
-		return -EPROTO;
-	}
-
-	/* wait on this buffer to get ready */
-	if (!wait_event_interruptible_timeout(zr->v4l_capq,
-				(zr->v4l_buffers.buffer[frame].state != BUZ_STATE_PEND),
-				10*HZ))
-		return -ETIME;
-	if (signal_pending(current))
-		return -ERESTARTSYS;
-
-	/* buffer should now be in BUZ_STATE_DONE */
-	if (zr->v4l_buffers.buffer[frame].state != BUZ_STATE_DONE)
-		dprintk(2,
-			KERN_ERR "%s: v4l_sync() - internal state error\n",
-			ZR_DEVNAME(zr));
-
-	zr->v4l_buffers.buffer[frame].state = BUZ_STATE_USER;
-	fh->v4l_buffers.buffer[frame] = zr->v4l_buffers.buffer[frame];
-
-	spin_lock_irqsave(&zr->spinlock, flags);
-
-	/* Check if streaming capture has finished */
-	if (zr->v4l_pend_tail == zr->v4l_pend_head) {
-		zr36057_set_memgrab(zr, 0);
-		if (zr->v4l_buffers.active == ZORAN_ACTIVE) {
-			fh->v4l_buffers.active = zr->v4l_buffers.active =
-			    ZORAN_FREE;
-			zr->v4l_buffers.allocated = 0;
-		}
-	}
-
-	spin_unlock_irqrestore(&zr->spinlock, flags);
-
-	return 0;
-}
-
-/*
- *   Queue a MJPEG buffer for capture/playback
- */
-
-static int
-zoran_jpg_queue_frame (struct file          *file,
-		       int                   num,
-		       enum zoran_codec_mode mode)
-{
-	struct zoran_fh *fh = file->private_data;
-	struct zoran *zr = fh->zr;
-	unsigned long flags;
-	int res = 0;
-
-	/* Check if buffers are allocated */
-	if (!fh->jpg_buffers.allocated) {
-		dprintk(1,
-			KERN_ERR
-			"%s: jpg_queue_frame() - buffers not yet allocated\n",
-			ZR_DEVNAME(zr));
-		return -ENOMEM;
-	}
-
-	/* No grabbing outside the buffer range! */
-	if (num >= fh->jpg_buffers.num_buffers || num < 0) {
-		dprintk(1,
-			KERN_ERR
-			"%s: jpg_queue_frame() - buffer %d out of range\n",
-			ZR_DEVNAME(zr), num);
-		return -EINVAL;
-	}
-
-	/* what is the codec mode right now? */
-	if (zr->codec_mode == BUZ_MODE_IDLE) {
-		zr->jpg_settings = fh->jpg_settings;
-	} else if (zr->codec_mode != mode) {
-		/* wrong codec mode active - invalid */
-		dprintk(1,
-			KERN_ERR
-			"%s: jpg_queue_frame() - codec in wrong mode\n",
-			ZR_DEVNAME(zr));
-		return -EINVAL;
-	}
-
-	if (fh->jpg_buffers.active == ZORAN_FREE) {
-		if (zr->jpg_buffers.active == ZORAN_FREE) {
-			zr->jpg_buffers = fh->jpg_buffers;
-			fh->jpg_buffers.active = ZORAN_ACTIVE;
-		} else {
-			dprintk(1,
-				KERN_ERR
-				"%s: jpg_queue_frame() - another session is already capturing\n",
-				ZR_DEVNAME(zr));
-			res = -EBUSY;
-		}
-	}
-
-	if (!res && zr->codec_mode == BUZ_MODE_IDLE) {
-		/* Ok load up the jpeg codec */
-		zr36057_enable_jpg(zr, mode);
-	}
-
-	spin_lock_irqsave(&zr->spinlock, flags);
-
-	if (!res) {
-		switch (zr->jpg_buffers.buffer[num].state) {
-		case BUZ_STATE_DONE:
-			dprintk(2,
-				KERN_WARNING
-				"%s: jpg_queue_frame() - queing frame in BUZ_STATE_DONE state!?\n",
-				ZR_DEVNAME(zr));
-		case BUZ_STATE_USER:
-			/* since there is at least one unused buffer there's room for at
-			 *least one more pend[] entry */
-			zr->jpg_pend[zr->jpg_que_head++ & BUZ_MASK_FRAME] =
-			    num;
-			zr->jpg_buffers.buffer[num].state = BUZ_STATE_PEND;
-			fh->jpg_buffers.buffer[num] =
-			    zr->jpg_buffers.buffer[num];
-			zoran_feed_stat_com(zr);
-			break;
-		default:
-		case BUZ_STATE_DMA:
-		case BUZ_STATE_PEND:
-			if (zr->jpg_buffers.active == ZORAN_FREE) {
-				fh->jpg_buffers.active = ZORAN_FREE;
-				zr->jpg_buffers.allocated = 0;
-			}
-			res = -EBUSY;	/* what are you doing? */
-			break;
-		}
-	}
-
-	spin_unlock_irqrestore(&zr->spinlock, flags);
-
-	if (!res && zr->jpg_buffers.active == ZORAN_FREE) {
-		zr->jpg_buffers.active = fh->jpg_buffers.active;
-	}
-
-	return res;
-}
-
-static int
-jpg_qbuf (struct file          *file,
-	  int                   frame,
-	  enum zoran_codec_mode mode)
-{
-	struct zoran_fh *fh = file->private_data;
-	struct zoran *zr = fh->zr;
-	int res = 0;
-
-	/* Does the user want to stop streaming? */
-	if (frame < 0) {
-		if (zr->codec_mode == mode) {
-			if (fh->jpg_buffers.active == ZORAN_FREE) {
-				dprintk(1,
-					KERN_ERR
-					"%s: jpg_qbuf(-1) - session not active\n",
-					ZR_DEVNAME(zr));
-				return -EINVAL;
-			}
-			fh->jpg_buffers.active = zr->jpg_buffers.active =
-			    ZORAN_FREE;
-			zr->jpg_buffers.allocated = 0;
-			zr36057_enable_jpg(zr, BUZ_MODE_IDLE);
-			return 0;
-		} else {
-			dprintk(1,
-				KERN_ERR
-				"%s: jpg_qbuf() - stop streaming but not in streaming mode\n",
-				ZR_DEVNAME(zr));
-			return -EINVAL;
-		}
-	}
-
-	if ((res = zoran_jpg_queue_frame(file, frame, mode)))
-		return res;
-
-	/* Start the jpeg codec when the first frame is queued  */
-	if (!res && zr->jpg_que_head == 1)
-		jpeg_start(zr);
-
-	return res;
-}
-
-/*
- *   Sync on a MJPEG buffer
- */
-
-static int
-jpg_sync (struct file       *file,
-	  struct zoran_sync *bs)
-{
-	struct zoran_fh *fh = file->private_data;
-	struct zoran *zr = fh->zr;
-	unsigned long flags;
-	int frame;
-
-	if (fh->jpg_buffers.active == ZORAN_FREE) {
-		dprintk(1,
-			KERN_ERR
-			"%s: jpg_sync() - capture is not currently active\n",
-			ZR_DEVNAME(zr));
-		return -EINVAL;
-	}
-	if (zr->codec_mode != BUZ_MODE_MOTION_DECOMPRESS &&
-	    zr->codec_mode != BUZ_MODE_MOTION_COMPRESS) {
-		dprintk(1,
-			KERN_ERR
-			"%s: jpg_sync() - codec not in streaming mode\n",
-			ZR_DEVNAME(zr));
-		return -EINVAL;
-	}
-	if (!wait_event_interruptible_timeout(zr->jpg_capq,
-			(zr->jpg_que_tail != zr->jpg_dma_tail ||
-			 zr->jpg_dma_tail == zr->jpg_dma_head),
-			10*HZ)) {
-		int isr;
-
-		btand(~ZR36057_JMC_Go_en, ZR36057_JMC);
-		udelay(1);
-		zr->codec->control(zr->codec, CODEC_G_STATUS,
-					   sizeof(isr), &isr);
-		dprintk(1,
-			KERN_ERR
-			"%s: jpg_sync() - timeout: codec isr=0x%02x\n",
-			ZR_DEVNAME(zr), isr);
-
-		return -ETIME;
-
-	}
-	if (signal_pending(current))
-		return -ERESTARTSYS;
-
-	spin_lock_irqsave(&zr->spinlock, flags);
-
-	if (zr->jpg_dma_tail != zr->jpg_dma_head)
-		frame = zr->jpg_pend[zr->jpg_que_tail++ & BUZ_MASK_FRAME];
-	else
-		frame = zr->jpg_pend[zr->jpg_que_tail & BUZ_MASK_FRAME];
-
-	/* buffer should now be in BUZ_STATE_DONE */
-	if (zr->jpg_buffers.buffer[frame].state != BUZ_STATE_DONE)
-		dprintk(2,
-			KERN_ERR "%s: jpg_sync() - internal state error\n",
-			ZR_DEVNAME(zr));
-
-	*bs = zr->jpg_buffers.buffer[frame].bs;
-	bs->frame = frame;
-	zr->jpg_buffers.buffer[frame].state = BUZ_STATE_USER;
-	fh->jpg_buffers.buffer[frame] = zr->jpg_buffers.buffer[frame];
-
-	spin_unlock_irqrestore(&zr->spinlock, flags);
-
-	return 0;
-}
-
-static void
-zoran_open_init_session (struct file *file)
-{
-	int i;
-	struct zoran_fh *fh = file->private_data;
-	struct zoran *zr = fh->zr;
-
-	/* Per default, map the V4L Buffers */
-	fh->map_mode = ZORAN_MAP_MODE_RAW;
-
-	/* take over the card's current settings */
-	fh->overlay_settings = zr->overlay_settings;
-	fh->overlay_settings.is_set = 0;
-	fh->overlay_settings.format = zr->overlay_settings.format;
-	fh->overlay_active = ZORAN_FREE;
-
-	/* v4l settings */
-	fh->v4l_settings = zr->v4l_settings;
-
-	/* v4l_buffers */
-	memset(&fh->v4l_buffers, 0, sizeof(struct zoran_v4l_struct));
-	for (i = 0; i < VIDEO_MAX_FRAME; i++) {
-		fh->v4l_buffers.buffer[i].state = BUZ_STATE_USER;	/* nothing going on */
-		fh->v4l_buffers.buffer[i].bs.frame = i;
-	}
-	fh->v4l_buffers.allocated = 0;
-	fh->v4l_buffers.ready_to_be_freed = 0;
-	fh->v4l_buffers.active = ZORAN_FREE;
-	fh->v4l_buffers.buffer_size = v4l_bufsize;
-	fh->v4l_buffers.num_buffers = v4l_nbufs;
-
-	/* jpg settings */
-	fh->jpg_settings = zr->jpg_settings;
-
-	/* jpg_buffers */
-	memset(&fh->jpg_buffers, 0, sizeof(struct zoran_jpg_struct));
-	for (i = 0; i < BUZ_MAX_FRAME; i++) {
-		fh->jpg_buffers.buffer[i].state = BUZ_STATE_USER;	/* nothing going on */
-		fh->jpg_buffers.buffer[i].bs.frame = i;
-	}
-	fh->jpg_buffers.need_contiguous = zr->jpg_buffers.need_contiguous;
-	fh->jpg_buffers.allocated = 0;
-	fh->jpg_buffers.ready_to_be_freed = 0;
-	fh->jpg_buffers.active = ZORAN_FREE;
-	fh->jpg_buffers.buffer_size = jpg_bufsize;
-	fh->jpg_buffers.num_buffers = jpg_nbufs;
-}
-
-static void
-zoran_close_end_session (struct file *file)
-{
-	struct zoran_fh *fh = file->private_data;
-	struct zoran *zr = fh->zr;
-
-	/* overlay */
-	if (fh->overlay_active != ZORAN_FREE) {
-		fh->overlay_active = zr->overlay_active = ZORAN_FREE;
-		zr->v4l_overlay_active = 0;
-		if (!zr->v4l_memgrab_active)
-			zr36057_overlay(zr, 0);
-		zr->overlay_mask = NULL;
-	}
-
-	/* v4l capture */
-	if (fh->v4l_buffers.active != ZORAN_FREE) {
-		unsigned long flags;
-
-		spin_lock_irqsave(&zr->spinlock, flags);
-		zr36057_set_memgrab(zr, 0);
-		zr->v4l_buffers.allocated = 0;
-		zr->v4l_buffers.active = fh->v4l_buffers.active =
-		    ZORAN_FREE;
-		spin_unlock_irqrestore(&zr->spinlock, flags);
-	}
-
-	/* v4l buffers */
-	if (fh->v4l_buffers.allocated ||
-	    fh->v4l_buffers.ready_to_be_freed) {
-		v4l_fbuffer_free(file);
-	}
-
-	/* jpg capture */
-	if (fh->jpg_buffers.active != ZORAN_FREE) {
-		zr36057_enable_jpg(zr, BUZ_MODE_IDLE);
-		zr->jpg_buffers.allocated = 0;
-		zr->jpg_buffers.active = fh->jpg_buffers.active =
-		    ZORAN_FREE;
-	}
-
-	/* jpg buffers */
-	if (fh->jpg_buffers.allocated ||
-	    fh->jpg_buffers.ready_to_be_freed) {
-		jpg_fbuffer_free(file);
-	}
-}
-
-/*
- *   Open a zoran card. Right now the flags stuff is just playing
- */
-
-static int
-zoran_open (struct inode *inode,
-	    struct file  *file)
-{
-	unsigned int minor = iminor(inode);
-	struct zoran *zr = NULL;
-	struct zoran_fh *fh;
-	int i, res, first_open = 0, have_module_locks = 0;
-
-	/* find the device */
-	for (i = 0; i < zoran_num; i++) {
-		if (zoran[i]->video_dev->minor == minor) {
-			zr = zoran[i];
-			break;
-		}
-	}
-
-	if (!zr) {
-		dprintk(1, KERN_ERR "%s: device not found!\n", ZORAN_NAME);
-		res = -ENODEV;
-		goto open_unlock_and_return;
-	}
-
-	/* see fs/device.c - the kernel already locks during open(),
-	 * so locking ourselves only causes deadlocks */
-	/*mutex_lock(&zr->resource_lock);*/
-
-	if (!zr->decoder) {
-		dprintk(1,
-			KERN_ERR "%s: no TV decoder loaded for device!\n",
-			ZR_DEVNAME(zr));
-		res = -EIO;
-		goto open_unlock_and_return;
-	}
-
-	/* try to grab a module lock */
-	if (!try_module_get(THIS_MODULE)) {
-		dprintk(1,
-			KERN_ERR
-			"%s: failed to acquire my own lock! PANIC!\n",
-			ZR_DEVNAME(zr));
-		res = -ENODEV;
-		goto open_unlock_and_return;
-	}
-	if (!try_module_get(zr->decoder->driver->driver.owner)) {
-		dprintk(1,
-			KERN_ERR
-			"%s: failed to grab ownership of i2c decoder\n",
-			ZR_DEVNAME(zr));
-		res = -EIO;
-		module_put(THIS_MODULE);
-		goto open_unlock_and_return;
-	}
-	if (zr->encoder &&
-	    !try_module_get(zr->encoder->driver->driver.owner)) {
-		dprintk(1,
-			KERN_ERR
-			"%s: failed to grab ownership of i2c encoder\n",
-			ZR_DEVNAME(zr));
-		res = -EIO;
-		module_put(zr->decoder->driver->driver.owner);
-		module_put(THIS_MODULE);
-		goto open_unlock_and_return;
-	}
-
-	have_module_locks = 1;
-
-	if (zr->user >= 2048) {
-		dprintk(1, KERN_ERR "%s: too many users (%d) on device\n",
-			ZR_DEVNAME(zr), zr->user);
-		res = -EBUSY;
-		goto open_unlock_and_return;
-	}
-
-	dprintk(1, KERN_INFO "%s: zoran_open(%s, pid=[%d]), users(-)=%d\n",
-		ZR_DEVNAME(zr), current->comm, task_pid_nr(current), zr->user);
-
-	/* now, create the open()-specific file_ops struct */
-	fh = kzalloc(sizeof(struct zoran_fh), GFP_KERNEL);
-	if (!fh) {
-		dprintk(1,
-			KERN_ERR
-			"%s: zoran_open() - allocation of zoran_fh failed\n",
-			ZR_DEVNAME(zr));
-		res = -ENOMEM;
-		goto open_unlock_and_return;
-	}
-	/* used to be BUZ_MAX_WIDTH/HEIGHT, but that gives overflows
-	 * on norm-change! */
-	fh->overlay_mask =
-	    kmalloc(((768 + 31) / 32) * 576 * 4, GFP_KERNEL);
-	if (!fh->overlay_mask) {
-		dprintk(1,
-			KERN_ERR
-			"%s: zoran_open() - allocation of overlay_mask failed\n",
-			ZR_DEVNAME(zr));
-		kfree(fh);
-		res = -ENOMEM;
-		goto open_unlock_and_return;
-	}
-
-	if (zr->user++ == 0)
-		first_open = 1;
-
-	/*mutex_unlock(&zr->resource_lock);*/
-
-	/* default setup - TODO: look at flags */
-	if (first_open) {	/* First device open */
-		zr36057_restart(zr);
-		zoran_open_init_params(zr);
-		zoran_init_hardware(zr);
-
-		btor(ZR36057_ICR_IntPinEn, ZR36057_ICR);
-	}
-
-	/* set file_ops stuff */
-	file->private_data = fh;
-	fh->zr = zr;
-	zoran_open_init_session(file);
-
-	return 0;
-
-open_unlock_and_return:
-	/* if we grabbed locks, release them accordingly */
-	if (have_module_locks) {
-		module_put(zr->decoder->driver->driver.owner);
-		if (zr->encoder) {
-			module_put(zr->encoder->driver->driver.owner);
-		}
-		module_put(THIS_MODULE);
-	}
-
-	/* if there's no device found, we didn't obtain the lock either */
-	if (zr) {
-		/*mutex_unlock(&zr->resource_lock);*/
-	}
-
-	return res;
-}
-
-static int
-zoran_close (struct inode *inode,
-	     struct file  *file)
-{
-	struct zoran_fh *fh = file->private_data;
-	struct zoran *zr = fh->zr;
-
-	dprintk(1, KERN_INFO "%s: zoran_close(%s, pid=[%d]), users(+)=%d\n",
-		ZR_DEVNAME(zr), current->comm, task_pid_nr(current), zr->user);
-
-	/* kernel locks (fs/device.c), so don't do that ourselves
-	 * (prevents deadlocks) */
-	/*mutex_lock(&zr->resource_lock);*/
-
-	zoran_close_end_session(file);
-
-	if (zr->user-- == 1) {	/* Last process */
-		/* Clean up JPEG process */
-		wake_up_interruptible(&zr->jpg_capq);
-		zr36057_enable_jpg(zr, BUZ_MODE_IDLE);
-		zr->jpg_buffers.allocated = 0;
-		zr->jpg_buffers.active = ZORAN_FREE;
-
-		/* disable interrupts */
-		btand(~ZR36057_ICR_IntPinEn, ZR36057_ICR);
-
-		if (zr36067_debug > 1)
-			print_interrupts(zr);
-
-		/* Overlay off */
-		zr->v4l_overlay_active = 0;
-		zr36057_overlay(zr, 0);
-		zr->overlay_mask = NULL;
-
-		/* capture off */
-		wake_up_interruptible(&zr->v4l_capq);
-		zr36057_set_memgrab(zr, 0);
-		zr->v4l_buffers.allocated = 0;
-		zr->v4l_buffers.active = ZORAN_FREE;
-		zoran_set_pci_master(zr, 0);
-
-		if (!pass_through) {	/* Switch to color bar */
-			int zero = 0, two = 2;
-			decoder_command(zr, DECODER_ENABLE_OUTPUT, &zero);
-			encoder_command(zr, ENCODER_SET_INPUT, &two);
-		}
-	}
-
-	file->private_data = NULL;
-	kfree(fh->overlay_mask);
-	kfree(fh);
-
-	/* release locks on the i2c modules */
-	module_put(zr->decoder->driver->driver.owner);
-	if (zr->encoder) {
-		 module_put(zr->encoder->driver->driver.owner);
-	}
-	module_put(THIS_MODULE);
-
-	/*mutex_unlock(&zr->resource_lock);*/
-
-	dprintk(4, KERN_INFO "%s: zoran_close() done\n", ZR_DEVNAME(zr));
-
-	return 0;
-}
-
-
-static ssize_t
-zoran_read (struct file *file,
-	    char        __user *data,
-	    size_t       count,
-	    loff_t      *ppos)
-{
-	/* we simply don't support read() (yet)... */
-
-	return -EINVAL;
-}
-
-static ssize_t
-zoran_write (struct file *file,
-	     const char  __user *data,
-	     size_t       count,
-	     loff_t      *ppos)
-{
-	/* ...and the same goes for write() */
-
-	return -EINVAL;
-}
-
-static int
-setup_fbuffer (struct file               *file,
-	       void                      *base,
-	       const struct zoran_format *fmt,
-	       int                        width,
-	       int                        height,
-	       int                        bytesperline)
-{
-	struct zoran_fh *fh = file->private_data;
-	struct zoran *zr = fh->zr;
-
-	/* (Ronald) v4l/v4l2 guidelines */
-	if (!capable(CAP_SYS_ADMIN) && !capable(CAP_SYS_RAWIO))
-		return -EPERM;
-
-	/* Don't allow frame buffer overlay if PCI or AGP is buggy, or on
-	   ALi Magik (that needs very low latency while the card needs a
-	   higher value always) */
-
-	if (pci_pci_problems & (PCIPCI_FAIL | PCIAGP_FAIL | PCIPCI_ALIMAGIK))
-		return -ENXIO;
-
-	/* we need a bytesperline value, even if not given */
-	if (!bytesperline)
-		bytesperline = width * ((fmt->depth + 7) & ~7) / 8;
-
-#if 0
-	if (zr->overlay_active) {
-		/* dzjee... stupid users... don't even bother to turn off
-		 * overlay before changing the memory location...
-		 * normally, we would return errors here. However, one of
-		 * the tools that does this is... xawtv! and since xawtv
-		 * is used by +/- 99% of the users, we'd rather be user-
-		 * friendly and silently do as if nothing went wrong */
-		dprintk(3,
-			KERN_ERR
-			"%s: setup_fbuffer() - forced overlay turnoff because framebuffer changed\n",
-			ZR_DEVNAME(zr));
-		zr36057_overlay(zr, 0);
-	}
-#endif
-
-	if (!(fmt->flags & ZORAN_FORMAT_OVERLAY)) {
-		dprintk(1,
-			KERN_ERR
-			"%s: setup_fbuffer() - no valid overlay format given\n",
-			ZR_DEVNAME(zr));
-		return -EINVAL;
-	}
-	if (height <= 0 || width <= 0 || bytesperline <= 0) {
-		dprintk(1,
-			KERN_ERR
-			"%s: setup_fbuffer() - invalid height/width/bpl value (%d|%d|%d)\n",
-			ZR_DEVNAME(zr), width, height, bytesperline);
-		return -EINVAL;
-	}
-	if (bytesperline & 3) {
-		dprintk(1,
-			KERN_ERR
-			"%s: setup_fbuffer() - bytesperline (%d) must be 4-byte aligned\n",
-			ZR_DEVNAME(zr), bytesperline);
-		return -EINVAL;
-	}
-
-	zr->buffer.base = (void *) ((unsigned long) base & ~3);
-	zr->buffer.height = height;
-	zr->buffer.width = width;
-	zr->buffer.depth = fmt->depth;
-	zr->overlay_settings.format = fmt;
-	zr->buffer.bytesperline = bytesperline;
-
-	/* The user should set new window parameters */
-	zr->overlay_settings.is_set = 0;
-
-	return 0;
-}
-
-
-static int
-setup_window (struct file       *file,
-	      int                x,
-	      int                y,
-	      int                width,
-	      int                height,
-	      struct video_clip __user *clips,
-	      int                clipcount,
-	      void              __user *bitmap)
-{
-	struct zoran_fh *fh = file->private_data;
-	struct zoran *zr = fh->zr;
-	struct video_clip *vcp = NULL;
-	int on, end;
-
-
-	if (!zr->buffer.base) {
-		dprintk(1,
-			KERN_ERR
-			"%s: setup_window() - frame buffer has to be set first\n",
-			ZR_DEVNAME(zr));
-		return -EINVAL;
-	}
-
-	if (!fh->overlay_settings.format) {
-		dprintk(1,
-			KERN_ERR
-			"%s: setup_window() - no overlay format set\n",
-			ZR_DEVNAME(zr));
-		return -EINVAL;
-	}
-
-	/*
-	 * The video front end needs 4-byte alinged line sizes, we correct that
-	 * silently here if necessary
-	 */
-	if (zr->buffer.depth == 15 || zr->buffer.depth == 16) {
-		end = (x + width) & ~1;	/* round down */
-		x = (x + 1) & ~1;	/* round up */
-		width = end - x;
-	}
-
-	if (zr->buffer.depth == 24) {
-		end = (x + width) & ~3;	/* round down */
-		x = (x + 3) & ~3;	/* round up */
-		width = end - x;
-	}
-
-	if (width > BUZ_MAX_WIDTH)
-		width = BUZ_MAX_WIDTH;
-	if (height > BUZ_MAX_HEIGHT)
-		height = BUZ_MAX_HEIGHT;
-
-	/* Check for vaild parameters */
-	if (width < BUZ_MIN_WIDTH || height < BUZ_MIN_HEIGHT ||
-	    width > BUZ_MAX_WIDTH || height > BUZ_MAX_HEIGHT) {
-		dprintk(1,
-			KERN_ERR
-			"%s: setup_window() - width = %d or height = %d invalid\n",
-			ZR_DEVNAME(zr), width, height);
-		return -EINVAL;
-	}
-
-	fh->overlay_settings.x = x;
-	fh->overlay_settings.y = y;
-	fh->overlay_settings.width = width;
-	fh->overlay_settings.height = height;
-	fh->overlay_settings.clipcount = clipcount;
-
-	/*
-	 * If an overlay is running, we have to switch it off
-	 * and switch it on again in order to get the new settings in effect.
-	 *
-	 * We also want to avoid that the overlay mask is written
-	 * when an overlay is running.
-	 */
-
-	on = zr->v4l_overlay_active && !zr->v4l_memgrab_active &&
-	    zr->overlay_active != ZORAN_FREE &&
-	    fh->overlay_active != ZORAN_FREE;
-	if (on)
-		zr36057_overlay(zr, 0);
-
-	/*
-	 *   Write the overlay mask if clips are wanted.
-	 *   We prefer a bitmap.
-	 */
-	if (bitmap) {
-		/* fake value - it just means we want clips */
-		fh->overlay_settings.clipcount = 1;
-
-		if (copy_from_user(fh->overlay_mask, bitmap,
-				   (width * height + 7) / 8)) {
-			return -EFAULT;
-		}
-	} else if (clipcount > 0) {
-		/* write our own bitmap from the clips */
-		vcp = vmalloc(sizeof(struct video_clip) * (clipcount + 4));
-		if (vcp == NULL) {
-			dprintk(1,
-				KERN_ERR
-				"%s: setup_window() - Alloc of clip mask failed\n",
-				ZR_DEVNAME(zr));
-			return -ENOMEM;
-		}
-		if (copy_from_user
-		    (vcp, clips, sizeof(struct video_clip) * clipcount)) {
-			vfree(vcp);
-			return -EFAULT;
-		}
-		write_overlay_mask(file, vcp, clipcount);
-		vfree(vcp);
-	}
-
-	fh->overlay_settings.is_set = 1;
-	if (fh->overlay_active != ZORAN_FREE &&
-	    zr->overlay_active != ZORAN_FREE)
-		zr->overlay_settings = fh->overlay_settings;
-
-	if (on)
-		zr36057_overlay(zr, 1);
-
-	/* Make sure the changes come into effect */
-	return wait_grab_pending(zr);
-}
-
-static int
-setup_overlay (struct file *file,
-	       int          on)
-{
-	struct zoran_fh *fh = file->private_data;
-	struct zoran *zr = fh->zr;
-
-	/* If there is nothing to do, return immediatly */
-	if ((on && fh->overlay_active != ZORAN_FREE) ||
-	    (!on && fh->overlay_active == ZORAN_FREE))
-		return 0;
-
-	/* check whether we're touching someone else's overlay */
-	if (on && zr->overlay_active != ZORAN_FREE &&
-	    fh->overlay_active == ZORAN_FREE) {
-		dprintk(1,
-			KERN_ERR
-			"%s: setup_overlay() - overlay is already active for another session\n",
-			ZR_DEVNAME(zr));
-		return -EBUSY;
-	}
-	if (!on && zr->overlay_active != ZORAN_FREE &&
-	    fh->overlay_active == ZORAN_FREE) {
-		dprintk(1,
-			KERN_ERR
-			"%s: setup_overlay() - you cannot cancel someone else's session\n",
-			ZR_DEVNAME(zr));
-		return -EPERM;
-	}
-
-	if (on == 0) {
-		zr->overlay_active = fh->overlay_active = ZORAN_FREE;
-		zr->v4l_overlay_active = 0;
-		/* When a grab is running, the video simply
-		 * won't be switched on any more */
-		if (!zr->v4l_memgrab_active)
-			zr36057_overlay(zr, 0);
-		zr->overlay_mask = NULL;
-	} else {
-		if (!zr->buffer.base || !fh->overlay_settings.is_set) {
-			dprintk(1,
-				KERN_ERR
-				"%s: setup_overlay() - buffer or window not set\n",
-				ZR_DEVNAME(zr));
-			return -EINVAL;
-		}
-		if (!fh->overlay_settings.format) {
-			dprintk(1,
-				KERN_ERR
-				"%s: setup_overlay() - no overlay format set\n",
-				ZR_DEVNAME(zr));
-			return -EINVAL;
-		}
-		zr->overlay_active = fh->overlay_active = ZORAN_LOCKED;
-		zr->v4l_overlay_active = 1;
-		zr->overlay_mask = fh->overlay_mask;
-		zr->overlay_settings = fh->overlay_settings;
-		if (!zr->v4l_memgrab_active)
-			zr36057_overlay(zr, 1);
-		/* When a grab is running, the video will be
-		 * switched on when grab is finished */
-	}
-
-	/* Make sure the changes come into effect */
-	return wait_grab_pending(zr);
-}
-
-	/* get the status of a buffer in the clients buffer queue */
-static int
-zoran_v4l2_buffer_status (struct file        *file,
-			  struct v4l2_buffer *buf,
-			  int                 num)
-{
-	struct zoran_fh *fh = file->private_data;
-	struct zoran *zr = fh->zr;
-
-	buf->flags = V4L2_BUF_FLAG_MAPPED;
-
-	switch (fh->map_mode) {
-	case ZORAN_MAP_MODE_RAW:
-
-		/* check range */
-		if (num < 0 || num >= fh->v4l_buffers.num_buffers ||
-		    !fh->v4l_buffers.allocated) {
-			dprintk(1,
-				KERN_ERR
-				"%s: v4l2_buffer_status() - wrong number or buffers not allocated\n",
-				ZR_DEVNAME(zr));
-			return -EINVAL;
-		}
-
-		buf->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-		buf->length = fh->v4l_buffers.buffer_size;
-
-		/* get buffer */
-		buf->bytesused = fh->v4l_buffers.buffer[num].bs.length;
-		if (fh->v4l_buffers.buffer[num].state == BUZ_STATE_DONE ||
-		    fh->v4l_buffers.buffer[num].state == BUZ_STATE_USER) {
-			buf->sequence = fh->v4l_buffers.buffer[num].bs.seq;
-			buf->flags |= V4L2_BUF_FLAG_DONE;
-			buf->timestamp =
-			    fh->v4l_buffers.buffer[num].bs.timestamp;
-		} else {
-			buf->flags |= V4L2_BUF_FLAG_QUEUED;
-		}
-
-		if (fh->v4l_settings.height <= BUZ_MAX_HEIGHT / 2)
-			buf->field = V4L2_FIELD_TOP;
-		else
-			buf->field = V4L2_FIELD_INTERLACED;
-
-		break;
-
-	case ZORAN_MAP_MODE_JPG_REC:
-	case ZORAN_MAP_MODE_JPG_PLAY:
-
-		/* check range */
-		if (num < 0 || num >= fh->jpg_buffers.num_buffers ||
-		    !fh->jpg_buffers.allocated) {
-			dprintk(1,
-				KERN_ERR
-				"%s: v4l2_buffer_status() - wrong number or buffers not allocated\n",
-				ZR_DEVNAME(zr));
-			return -EINVAL;
-		}
-
-		buf->type = (fh->map_mode == ZORAN_MAP_MODE_JPG_REC) ?
-			      V4L2_BUF_TYPE_VIDEO_CAPTURE :
-			      V4L2_BUF_TYPE_VIDEO_OUTPUT;
-		buf->length = fh->jpg_buffers.buffer_size;
-
-		/* these variables are only written after frame has been captured */
-		if (fh->jpg_buffers.buffer[num].state == BUZ_STATE_DONE ||
-		    fh->jpg_buffers.buffer[num].state == BUZ_STATE_USER) {
-			buf->sequence = fh->jpg_buffers.buffer[num].bs.seq;
-			buf->timestamp =
-			    fh->jpg_buffers.buffer[num].bs.timestamp;
-			buf->bytesused =
-			    fh->jpg_buffers.buffer[num].bs.length;
-			buf->flags |= V4L2_BUF_FLAG_DONE;
-		} else {
-			buf->flags |= V4L2_BUF_FLAG_QUEUED;
-		}
-
-		/* which fields are these? */
-		if (fh->jpg_settings.TmpDcm != 1)
-			buf->field =
-			    fh->jpg_settings.
-			    odd_even ? V4L2_FIELD_TOP : V4L2_FIELD_BOTTOM;
-		else
-			buf->field =
-			    fh->jpg_settings.
-			    odd_even ? V4L2_FIELD_SEQ_TB :
-			    V4L2_FIELD_SEQ_BT;
-
-		break;
-
-	default:
-
-		dprintk(5,
-			KERN_ERR
-			"%s: v4l2_buffer_status() - invalid buffer type|map_mode (%d|%d)\n",
-			ZR_DEVNAME(zr), buf->type, fh->map_mode);
-		return -EINVAL;
-	}
-
-	buf->memory = V4L2_MEMORY_MMAP;
-	buf->index = num;
-	buf->m.offset = buf->length * num;
-
-	return 0;
-}
-
-static int
-zoran_set_norm (struct zoran *zr,
-		int           norm) /* VIDEO_MODE_* */
-{
-	int norm_encoder, on;
-
-	if (zr->v4l_buffers.active != ZORAN_FREE ||
-	    zr->jpg_buffers.active != ZORAN_FREE) {
-		dprintk(1,
-			KERN_WARNING
-			"%s: set_norm() called while in playback/capture mode\n",
-			ZR_DEVNAME(zr));
-		return -EBUSY;
-	}
-
-	if (lock_norm && norm != zr->norm) {
-		if (lock_norm > 1) {
-			dprintk(1,
-				KERN_WARNING
-				"%s: set_norm() - TV standard is locked, can not switch norm\n",
-				ZR_DEVNAME(zr));
-			return -EPERM;
-		} else {
-			dprintk(1,
-				KERN_WARNING
-				"%s: set_norm() - TV standard is locked, norm was not changed\n",
-				ZR_DEVNAME(zr));
-			norm = zr->norm;
-		}
-	}
-
-	if (norm != VIDEO_MODE_AUTO &&
-	    (norm < 0 || norm >= zr->card.norms ||
-	     !zr->card.tvn[norm])) {
-		dprintk(1,
-			KERN_ERR "%s: set_norm() - unsupported norm %d\n",
-			ZR_DEVNAME(zr), norm);
-		return -EINVAL;
-	}
-
-	if (norm == VIDEO_MODE_AUTO) {
-		int status;
-
-		/* if we have autodetect, ... */
-		struct video_decoder_capability caps;
-		decoder_command(zr, DECODER_GET_CAPABILITIES, &caps);
-		if (!(caps.flags & VIDEO_DECODER_AUTO)) {
-			dprintk(1, KERN_ERR "%s: norm=auto unsupported\n",
-				ZR_DEVNAME(zr));
-			return -EINVAL;
-		}
-
-		decoder_command(zr, DECODER_SET_NORM, &norm);
-
-		/* let changes come into effect */
-		ssleep(2);
-
-		decoder_command(zr, DECODER_GET_STATUS, &status);
-		if (!(status & DECODER_STATUS_GOOD)) {
-			dprintk(1,
-				KERN_ERR
-				"%s: set_norm() - no norm detected\n",
-				ZR_DEVNAME(zr));
-			/* reset norm */
-			decoder_command(zr, DECODER_SET_NORM, &zr->norm);
-			return -EIO;
-		}
-
-		if (status & DECODER_STATUS_NTSC)
-			norm = VIDEO_MODE_NTSC;
-		else if (status & DECODER_STATUS_SECAM)
-			norm = VIDEO_MODE_SECAM;
-		else
-			norm = VIDEO_MODE_PAL;
-	}
-	zr->timing = zr->card.tvn[norm];
-	norm_encoder = norm;
-
-	/* We switch overlay off and on since a change in the
-	 * norm needs different VFE settings */
-	on = zr->overlay_active && !zr->v4l_memgrab_active;
-	if (on)
-		zr36057_overlay(zr, 0);
-
-	decoder_command(zr, DECODER_SET_NORM, &norm);
-	encoder_command(zr, ENCODER_SET_NORM, &norm_encoder);
-
-	if (on)
-		zr36057_overlay(zr, 1);
-
-	/* Make sure the changes come into effect */
-	zr->norm = norm;
-
-	return 0;
-}
-
-static int
-zoran_set_input (struct zoran *zr,
-		 int           input)
-{
-	int realinput;
-
-	if (input == zr->input) {
-		return 0;
-	}
-
-	if (zr->v4l_buffers.active != ZORAN_FREE ||
-	    zr->jpg_buffers.active != ZORAN_FREE) {
-		dprintk(1,
-			KERN_WARNING
-			"%s: set_input() called while in playback/capture mode\n",
-			ZR_DEVNAME(zr));
-		return -EBUSY;
-	}
-
-	if (input < 0 || input >= zr->card.inputs) {
-		dprintk(1,
-			KERN_ERR
-			"%s: set_input() - unnsupported input %d\n",
-			ZR_DEVNAME(zr), input);
-		return -EINVAL;
-	}
-
-	realinput = zr->card.input[input].muxsel;
-	zr->input = input;
-
-	decoder_command(zr, DECODER_SET_INPUT, &realinput);
-
-	return 0;
-}
-
-/*
- *   ioctl routine
- */
-
-static int
-zoran_do_ioctl (struct inode *inode,
-		struct file  *file,
-		unsigned int  cmd,
-		void         *arg)
-{
-	struct zoran_fh *fh = file->private_data;
-	struct zoran *zr = fh->zr;
-	/* CAREFUL: used in multiple places here */
-	struct zoran_jpg_settings settings;
-
-	/* we might have older buffers lying around... We don't want
-	 * to wait, but we do want to try cleaning them up ASAP. So
-	 * we try to obtain the lock and free them. If that fails, we
-	 * don't do anything and wait for the next turn. In the end,
-	 * zoran_close() or a new allocation will still free them...
-	 * This is just a 'the sooner the better' extra 'feature'
-	 *
-	 * We don't free the buffers right on munmap() because that
-	 * causes oopses (kfree() inside munmap() oopses for no
-	 * apparent reason - it's also not reproduceable in any way,
-	 * but moving the free code outside the munmap() handler fixes
-	 * all this... If someone knows why, please explain me (Ronald)
-	 */
-	if (mutex_trylock(&zr->resource_lock)) {
-		/* we obtained it! Let's try to free some things */
-		if (fh->jpg_buffers.ready_to_be_freed)
-			jpg_fbuffer_free(file);
-		if (fh->v4l_buffers.ready_to_be_freed)
-			v4l_fbuffer_free(file);
-
-		mutex_unlock(&zr->resource_lock);
-	}
-
-	switch (cmd) {
-
-	case VIDIOCGCAP:
-	{
-		struct video_capability *vcap = arg;
-
-		dprintk(3, KERN_DEBUG "%s: VIDIOCGCAP\n", ZR_DEVNAME(zr));
-
-		memset(vcap, 0, sizeof(struct video_capability));
-		strncpy(vcap->name, ZR_DEVNAME(zr), sizeof(vcap->name)-1);
-		vcap->type = ZORAN_VID_TYPE;
-
-		vcap->channels = zr->card.inputs;
-		vcap->audios = 0;
-		mutex_lock(&zr->resource_lock);
-		vcap->maxwidth = BUZ_MAX_WIDTH;
-		vcap->maxheight = BUZ_MAX_HEIGHT;
-		vcap->minwidth = BUZ_MIN_WIDTH;
-		vcap->minheight = BUZ_MIN_HEIGHT;
-		mutex_unlock(&zr->resource_lock);
-
-		return 0;
-	}
-		break;
-
-	case VIDIOCGCHAN:
-	{
-		struct video_channel *vchan = arg;
-		int channel = vchan->channel;
-
-		dprintk(3, KERN_DEBUG "%s: VIDIOCGCHAN - channel=%d\n",
-			ZR_DEVNAME(zr), vchan->channel);
-
-		memset(vchan, 0, sizeof(struct video_channel));
-		if (channel > zr->card.inputs || channel < 0) {
-			dprintk(1,
-				KERN_ERR
-				"%s: VIDIOCGCHAN on not existing channel %d\n",
-				ZR_DEVNAME(zr), channel);
-			return -EINVAL;
-		}
-
-		strcpy(vchan->name, zr->card.input[channel].name);
-
-		vchan->tuners = 0;
-		vchan->flags = 0;
-		vchan->type = VIDEO_TYPE_CAMERA;
-		mutex_lock(&zr->resource_lock);
-		vchan->norm = zr->norm;
-		mutex_unlock(&zr->resource_lock);
-		vchan->channel = channel;
-
-		return 0;
-	}
-		break;
-
-		/* RJ: the documentation at http://roadrunner.swansea.linux.org.uk/v4lapi.shtml says:
-		 *
-		 * * "The VIDIOCSCHAN ioctl takes an integer argument and switches the capture to this input."
-		 * *                                 ^^^^^^^
-		 * * The famos BTTV driver has it implemented with a struct video_channel argument
-		 * * and we follow it for compatibility reasons
-		 * *
-		 * * BTW: this is the only way the user can set the norm!
-		 */
-
-	case VIDIOCSCHAN:
-	{
-		struct video_channel *vchan = arg;
-		int res;
-
-		dprintk(3,
-			KERN_DEBUG
-			"%s: VIDIOCSCHAN - channel=%d, norm=%d\n",
-			ZR_DEVNAME(zr), vchan->channel, vchan->norm);
-
-		mutex_lock(&zr->resource_lock);
-		if ((res = zoran_set_input(zr, vchan->channel)))
-			goto schan_unlock_and_return;
-		if ((res = zoran_set_norm(zr, vchan->norm)))
-			goto schan_unlock_and_return;
-
-		/* Make sure the changes come into effect */
-		res = wait_grab_pending(zr);
-	schan_unlock_and_return:
-		mutex_unlock(&zr->resource_lock);
-		return res;
-	}
-		break;
-
-	case VIDIOCGPICT:
-	{
-		struct video_picture *vpict = arg;
-
-		dprintk(3, KERN_DEBUG "%s: VIDIOCGPICT\n", ZR_DEVNAME(zr));
-
-		memset(vpict, 0, sizeof(struct video_picture));
-		mutex_lock(&zr->resource_lock);
-		vpict->hue = zr->hue;
-		vpict->brightness = zr->brightness;
-		vpict->contrast = zr->contrast;
-		vpict->colour = zr->saturation;
-		if (fh->overlay_settings.format) {
-			vpict->depth = fh->overlay_settings.format->depth;
-			vpict->palette = fh->overlay_settings.format->palette;
-		} else {
-			vpict->depth = 0;
-		}
-		mutex_unlock(&zr->resource_lock);
-
-		return 0;
-	}
-		break;
-
-	case VIDIOCSPICT:
-	{
-		struct video_picture *vpict = arg;
-		int i;
-
-		dprintk(3,
-			KERN_DEBUG
-			"%s: VIDIOCSPICT - bri=%d, hue=%d, col=%d, con=%d, dep=%d, pal=%d\n",
-			ZR_DEVNAME(zr), vpict->brightness, vpict->hue,
-			vpict->colour, vpict->contrast, vpict->depth,
-			vpict->palette);
-
-		for (i = 0; i < NUM_FORMATS; i++) {
-			const struct zoran_format *fmt = &zoran_formats[i];
-
-			if (fmt->palette != -1 &&
-			    fmt->flags & ZORAN_FORMAT_OVERLAY &&
-			    fmt->palette == vpict->palette &&
-			    fmt->depth == vpict->depth)
-				break;
-		}
-		if (i == NUM_FORMATS) {
-			dprintk(1,
-				KERN_ERR
-				"%s: VIDIOCSPICT - Invalid palette %d\n",
-				ZR_DEVNAME(zr), vpict->palette);
-			return -EINVAL;
-		}
-
-		mutex_lock(&zr->resource_lock);
-
-		decoder_command(zr, DECODER_SET_PICTURE, vpict);
-
-		zr->hue = vpict->hue;
-		zr->contrast = vpict->contrast;
-		zr->saturation = vpict->colour;
-		zr->brightness = vpict->brightness;
-
-		fh->overlay_settings.format = &zoran_formats[i];
-
-		mutex_unlock(&zr->resource_lock);
-
-		return 0;
-	}
-		break;
-
-	case VIDIOCCAPTURE:
-	{
-		int *on = arg, res;
-
-		dprintk(3, KERN_DEBUG "%s: VIDIOCCAPTURE - on=%d\n",
-			ZR_DEVNAME(zr), *on);
-
-		mutex_lock(&zr->resource_lock);
-		res = setup_overlay(file, *on);
-		mutex_unlock(&zr->resource_lock);
-
-		return res;
-	}
-		break;
-
-	case VIDIOCGWIN:
-	{
-		struct video_window *vwin = arg;
-
-		dprintk(3, KERN_DEBUG "%s: VIDIOCGWIN\n", ZR_DEVNAME(zr));
-
-		memset(vwin, 0, sizeof(struct video_window));
-		mutex_lock(&zr->resource_lock);
-		vwin->x = fh->overlay_settings.x;
-		vwin->y = fh->overlay_settings.y;
-		vwin->width = fh->overlay_settings.width;
-		vwin->height = fh->overlay_settings.height;
-		mutex_unlock(&zr->resource_lock);
-		vwin->clipcount = 0;
-		return 0;
-	}
-		break;
-
-	case VIDIOCSWIN:
-	{
-		struct video_window *vwin = arg;
-		int res;
-
-		dprintk(3,
-			KERN_DEBUG
-			"%s: VIDIOCSWIN - x=%d, y=%d, w=%d, h=%d, clipcount=%d\n",
-			ZR_DEVNAME(zr), vwin->x, vwin->y, vwin->width,
-			vwin->height, vwin->clipcount);
-
-		mutex_lock(&zr->resource_lock);
-		res =
-		    setup_window(file, vwin->x, vwin->y, vwin->width,
-				 vwin->height, vwin->clips,
-				 vwin->clipcount, NULL);
-		mutex_unlock(&zr->resource_lock);
-
-		return res;
-	}
-		break;
-
-	case VIDIOCGFBUF:
-	{
-		struct video_buffer *vbuf = arg;
-
-		dprintk(3, KERN_DEBUG "%s: VIDIOCGFBUF\n", ZR_DEVNAME(zr));
-
-		mutex_lock(&zr->resource_lock);
-		*vbuf = zr->buffer;
-		mutex_unlock(&zr->resource_lock);
-		return 0;
-	}
-		break;
-
-	case VIDIOCSFBUF:
-	{
-		struct video_buffer *vbuf = arg;
-		int i, res = 0;
-
-		dprintk(3,
-			KERN_DEBUG
-			"%s: VIDIOCSFBUF - base=%p, w=%d, h=%d, depth=%d, bpl=%d\n",
-			ZR_DEVNAME(zr), vbuf->base, vbuf->width,
-			vbuf->height, vbuf->depth, vbuf->bytesperline);
-
-		for (i = 0; i < NUM_FORMATS; i++)
-			if (zoran_formats[i].depth == vbuf->depth)
-				break;
-		if (i == NUM_FORMATS) {
-			dprintk(1,
-				KERN_ERR
-				"%s: VIDIOCSFBUF - invalid fbuf depth %d\n",
-				ZR_DEVNAME(zr), vbuf->depth);
-			return -EINVAL;
-		}
-
-		mutex_lock(&zr->resource_lock);
-		res =
-		    setup_fbuffer(file, vbuf->base, &zoran_formats[i],
-				  vbuf->width, vbuf->height,
-				  vbuf->bytesperline);
-		mutex_unlock(&zr->resource_lock);
-
-		return res;
-	}
-		break;
-
-	case VIDIOCSYNC:
-	{
-		int *frame = arg, res;
-
-		dprintk(3, KERN_DEBUG "%s: VIDIOCSYNC - frame=%d\n",
-			ZR_DEVNAME(zr), *frame);
-
-		mutex_lock(&zr->resource_lock);
-		res = v4l_sync(file, *frame);
-		mutex_unlock(&zr->resource_lock);
-		if (!res)
-			zr->v4l_sync_tail++;
-		return res;
-	}
-		break;
-
-	case VIDIOCMCAPTURE:
-	{
-		struct video_mmap *vmap = arg;
-		int res;
-
-		dprintk(3,
-			KERN_DEBUG
-			"%s: VIDIOCMCAPTURE - frame=%d, geom=%dx%d, fmt=%d\n",
-			ZR_DEVNAME(zr), vmap->frame, vmap->width, vmap->height,
-			vmap->format);
-
-		mutex_lock(&zr->resource_lock);
-		res = v4l_grab(file, vmap);
-		mutex_unlock(&zr->resource_lock);
-		return res;
-	}
-		break;
-
-	case VIDIOCGMBUF:
-	{
-		struct video_mbuf *vmbuf = arg;
-		int i, res = 0;
-
-		dprintk(3, KERN_DEBUG "%s: VIDIOCGMBUF\n", ZR_DEVNAME(zr));
-
-		vmbuf->size =
-		    fh->v4l_buffers.num_buffers *
-		    fh->v4l_buffers.buffer_size;
-		vmbuf->frames = fh->v4l_buffers.num_buffers;
-		for (i = 0; i < vmbuf->frames; i++) {
-			vmbuf->offsets[i] =
-			    i * fh->v4l_buffers.buffer_size;
-		}
-
-		mutex_lock(&zr->resource_lock);
-
-		if (fh->jpg_buffers.allocated || fh->v4l_buffers.allocated) {
-			dprintk(1,
-				KERN_ERR
-				"%s: VIDIOCGMBUF - buffers already allocated\n",
-				ZR_DEVNAME(zr));
-			res = -EINVAL;
-			goto v4l1reqbuf_unlock_and_return;
-		}
-
-		if (v4l_fbuffer_alloc(file)) {
-			res = -ENOMEM;
-			goto v4l1reqbuf_unlock_and_return;
-		}
-
-		/* The next mmap will map the V4L buffers */
-		fh->map_mode = ZORAN_MAP_MODE_RAW;
-	v4l1reqbuf_unlock_and_return:
-		mutex_unlock(&zr->resource_lock);
-
-		return res;
-	}
-		break;
-
-	case VIDIOCGUNIT:
-	{
-		struct video_unit *vunit = arg;
-
-		dprintk(3, KERN_DEBUG "%s: VIDIOCGUNIT\n", ZR_DEVNAME(zr));
-
-		vunit->video = zr->video_dev->minor;
-		vunit->vbi = VIDEO_NO_UNIT;
-		vunit->radio = VIDEO_NO_UNIT;
-		vunit->audio = VIDEO_NO_UNIT;
-		vunit->teletext = VIDEO_NO_UNIT;
-
-		return 0;
-	}
-		break;
-
-		/*
-		 * RJ: In principal we could support subcaptures for V4L grabbing.
-		 *     Not even the famous BTTV driver has them, however.
-		 *     If there should be a strong demand, one could consider
-		 *     to implement them.
-		 */
-	case VIDIOCGCAPTURE:
-	{
-		dprintk(3, KERN_ERR "%s: VIDIOCGCAPTURE not supported\n",
-			ZR_DEVNAME(zr));
-		return -EINVAL;
-	}
-		break;
-
-	case VIDIOCSCAPTURE:
-	{
-		dprintk(3, KERN_ERR "%s: VIDIOCSCAPTURE not supported\n",
-			ZR_DEVNAME(zr));
-		return -EINVAL;
-	}
-		break;
-
-	case BUZIOC_G_PARAMS:
-	{
-		struct zoran_params *bparams = arg;
-
-		dprintk(3, KERN_DEBUG "%s: BUZIOC_G_PARAMS\n", ZR_DEVNAME(zr));
-
-		memset(bparams, 0, sizeof(struct zoran_params));
-		bparams->major_version = MAJOR_VERSION;
-		bparams->minor_version = MINOR_VERSION;
-
-		mutex_lock(&zr->resource_lock);
-
-		bparams->norm = zr->norm;
-		bparams->input = zr->input;
-
-		bparams->decimation = fh->jpg_settings.decimation;
-		bparams->HorDcm = fh->jpg_settings.HorDcm;
-		bparams->VerDcm = fh->jpg_settings.VerDcm;
-		bparams->TmpDcm = fh->jpg_settings.TmpDcm;
-		bparams->field_per_buff = fh->jpg_settings.field_per_buff;
-		bparams->img_x = fh->jpg_settings.img_x;
-		bparams->img_y = fh->jpg_settings.img_y;
-		bparams->img_width = fh->jpg_settings.img_width;
-		bparams->img_height = fh->jpg_settings.img_height;
-		bparams->odd_even = fh->jpg_settings.odd_even;
-
-		bparams->quality = fh->jpg_settings.jpg_comp.quality;
-		bparams->APPn = fh->jpg_settings.jpg_comp.APPn;
-		bparams->APP_len = fh->jpg_settings.jpg_comp.APP_len;
-		memcpy(bparams->APP_data,
-		       fh->jpg_settings.jpg_comp.APP_data,
-		       sizeof(bparams->APP_data));
-		bparams->COM_len = zr->jpg_settings.jpg_comp.COM_len;
-		memcpy(bparams->COM_data,
-		       fh->jpg_settings.jpg_comp.COM_data,
-		       sizeof(bparams->COM_data));
-		bparams->jpeg_markers =
-		    fh->jpg_settings.jpg_comp.jpeg_markers;
-
-		mutex_unlock(&zr->resource_lock);
-
-		bparams->VFIFO_FB = 0;
-
-		return 0;
-	}
-		break;
-
-	case BUZIOC_S_PARAMS:
-	{
-		struct zoran_params *bparams = arg;
-		int res = 0;
-
-		dprintk(3, KERN_DEBUG "%s: BUZIOC_S_PARAMS\n", ZR_DEVNAME(zr));
-
-		settings.decimation = bparams->decimation;
-		settings.HorDcm = bparams->HorDcm;
-		settings.VerDcm = bparams->VerDcm;
-		settings.TmpDcm = bparams->TmpDcm;
-		settings.field_per_buff = bparams->field_per_buff;
-		settings.img_x = bparams->img_x;
-		settings.img_y = bparams->img_y;
-		settings.img_width = bparams->img_width;
-		settings.img_height = bparams->img_height;
-		settings.odd_even = bparams->odd_even;
-
-		settings.jpg_comp.quality = bparams->quality;
-		settings.jpg_comp.APPn = bparams->APPn;
-		settings.jpg_comp.APP_len = bparams->APP_len;
-		memcpy(settings.jpg_comp.APP_data, bparams->APP_data,
-		       sizeof(bparams->APP_data));
-		settings.jpg_comp.COM_len = bparams->COM_len;
-		memcpy(settings.jpg_comp.COM_data, bparams->COM_data,
-		       sizeof(bparams->COM_data));
-		settings.jpg_comp.jpeg_markers = bparams->jpeg_markers;
-
-		mutex_lock(&zr->resource_lock);
-
-		if (zr->codec_mode != BUZ_MODE_IDLE) {
-			dprintk(1,
-				KERN_ERR
-				"%s: BUZIOC_S_PARAMS called, but Buz in capture/playback mode\n",
-				ZR_DEVNAME(zr));
-			res = -EINVAL;
-			goto sparams_unlock_and_return;
-		}
-
-		/* Check the params first before overwriting our
-		 * nternal values */
-		if (zoran_check_jpg_settings(zr, &settings)) {
-			res = -EINVAL;
-			goto sparams_unlock_and_return;
-		}
-
-		fh->jpg_settings = settings;
-	sparams_unlock_and_return:
-		mutex_unlock(&zr->resource_lock);
-
-		return res;
-	}
-		break;
-
-	case BUZIOC_REQBUFS:
-	{
-		struct zoran_requestbuffers *breq = arg;
-		int res = 0;
-
-		dprintk(3,
-			KERN_DEBUG
-			"%s: BUZIOC_REQBUFS - count=%lu, size=%lu\n",
-			ZR_DEVNAME(zr), breq->count, breq->size);
-
-		/* Enforce reasonable lower and upper limits */
-		if (breq->count < 4)
-			breq->count = 4;	/* Could be choosen smaller */
-		if (breq->count > jpg_nbufs)
-			breq->count = jpg_nbufs;
-		breq->size = PAGE_ALIGN(breq->size);
-		if (breq->size < 8192)
-			breq->size = 8192;	/* Arbitrary */
-		/* breq->size is limited by 1 page for the stat_com
-		 * tables to a Maximum of 2 MB */
-		if (breq->size > jpg_bufsize)
-			breq->size = jpg_bufsize;
-		if (fh->jpg_buffers.need_contiguous &&
-		    breq->size > MAX_KMALLOC_MEM)
-			breq->size = MAX_KMALLOC_MEM;
-
-		mutex_lock(&zr->resource_lock);
-
-		if (fh->jpg_buffers.allocated || fh->v4l_buffers.allocated) {
-			dprintk(1,
-				KERN_ERR
-				"%s: BUZIOC_REQBUFS - buffers allready allocated\n",
-				ZR_DEVNAME(zr));
-			res = -EBUSY;
-			goto jpgreqbuf_unlock_and_return;
-		}
-
-		fh->jpg_buffers.num_buffers = breq->count;
-		fh->jpg_buffers.buffer_size = breq->size;
-
-		if (jpg_fbuffer_alloc(file)) {
-			res = -ENOMEM;
-			goto jpgreqbuf_unlock_and_return;
-		}
-
-		/* The next mmap will map the MJPEG buffers - could
-		 * also be *_PLAY, but it doesn't matter here */
-		fh->map_mode = ZORAN_MAP_MODE_JPG_REC;
-	jpgreqbuf_unlock_and_return:
-		mutex_unlock(&zr->resource_lock);
-
-		return res;
-	}
-		break;
-
-	case BUZIOC_QBUF_CAPT:
-	{
-		int *frame = arg, res;
-
-		dprintk(3, KERN_DEBUG "%s: BUZIOC_QBUF_CAPT - frame=%d\n",
-			ZR_DEVNAME(zr), *frame);
-
-		mutex_lock(&zr->resource_lock);
-		res = jpg_qbuf(file, *frame, BUZ_MODE_MOTION_COMPRESS);
-		mutex_unlock(&zr->resource_lock);
-
-		return res;
-	}
-		break;
-
-	case BUZIOC_QBUF_PLAY:
-	{
-		int *frame = arg, res;
-
-		dprintk(3, KERN_DEBUG "%s: BUZIOC_QBUF_PLAY - frame=%d\n",
-			ZR_DEVNAME(zr), *frame);
-
-		mutex_lock(&zr->resource_lock);
-		res = jpg_qbuf(file, *frame, BUZ_MODE_MOTION_DECOMPRESS);
-		mutex_unlock(&zr->resource_lock);
-
-		return res;
-	}
-		break;
-
-	case BUZIOC_SYNC:
-	{
-		struct zoran_sync *bsync = arg;
-		int res;
-
-		dprintk(3, KERN_DEBUG "%s: BUZIOC_SYNC\n", ZR_DEVNAME(zr));
-
-		mutex_lock(&zr->resource_lock);
-		res = jpg_sync(file, bsync);
-		mutex_unlock(&zr->resource_lock);
-
-		return res;
-	}
-		break;
-
-	case BUZIOC_G_STATUS:
-	{
-		struct zoran_status *bstat = arg;
-		int norm, input, status, res = 0;
-
-		dprintk(3, KERN_DEBUG "%s: BUZIOC_G_STATUS\n", ZR_DEVNAME(zr));
-
-		if (zr->codec_mode != BUZ_MODE_IDLE) {
-			dprintk(1,
-				KERN_ERR
-				"%s: BUZIOC_G_STATUS called but Buz in capture/playback mode\n",
-				ZR_DEVNAME(zr));
-			return -EINVAL;
-		}
-
-		input = zr->card.input[bstat->input].muxsel;
-		norm = VIDEO_MODE_AUTO;
-
-		mutex_lock(&zr->resource_lock);
-
-		if (zr->codec_mode != BUZ_MODE_IDLE) {
-			dprintk(1,
-				KERN_ERR
-				"%s: BUZIOC_G_STATUS called, but Buz in capture/playback mode\n",
-				ZR_DEVNAME(zr));
-			res = -EINVAL;
-			goto gstat_unlock_and_return;
-		}
-
-		decoder_command(zr, DECODER_SET_INPUT, &input);
-		decoder_command(zr, DECODER_SET_NORM, &norm);
-
-		/* sleep 1 second */
-		ssleep(1);
-
-		/* Get status of video decoder */
-		decoder_command(zr, DECODER_GET_STATUS, &status);
-
-		/* restore previous input and norm */
-		input = zr->card.input[zr->input].muxsel;
-		decoder_command(zr, DECODER_SET_INPUT, &input);
-		decoder_command(zr, DECODER_SET_NORM, &zr->norm);
-	gstat_unlock_and_return:
-		mutex_unlock(&zr->resource_lock);
-
-		if (!res) {
-			bstat->signal =
-			    (status & DECODER_STATUS_GOOD) ? 1 : 0;
-			if (status & DECODER_STATUS_NTSC)
-				bstat->norm = VIDEO_MODE_NTSC;
-			else if (status & DECODER_STATUS_SECAM)
-				bstat->norm = VIDEO_MODE_SECAM;
-			else
-				bstat->norm = VIDEO_MODE_PAL;
-
-			bstat->color =
-			    (status & DECODER_STATUS_COLOR) ? 1 : 0;
-		}
-
-		return res;
-	}
-		break;
-
-		/* The new video4linux2 capture interface - much nicer than video4linux1, since
-		 * it allows for integrating the JPEG capturing calls inside standard v4l2
-		 */
-
-	case VIDIOC_QUERYCAP:
-	{
-		struct v4l2_capability *cap = arg;
-
-		dprintk(3, KERN_DEBUG "%s: VIDIOC_QUERYCAP\n", ZR_DEVNAME(zr));
-
-		memset(cap, 0, sizeof(*cap));
-		strncpy(cap->card, ZR_DEVNAME(zr), sizeof(cap->card)-1);
-		strncpy(cap->driver, "zoran", sizeof(cap->driver)-1);
-		snprintf(cap->bus_info, sizeof(cap->bus_info), "PCI:%s",
-			 pci_name(zr->pci_dev));
-		cap->version =
-		    KERNEL_VERSION(MAJOR_VERSION, MINOR_VERSION,
-				   RELEASE_VERSION);
-		cap->capabilities = ZORAN_V4L2_VID_FLAGS;
-
-		return 0;
-	}
-		break;
-
-	case VIDIOC_ENUM_FMT:
-	{
-		struct v4l2_fmtdesc *fmt = arg;
-		int index = fmt->index, num = -1, i, flag = 0, type =
-		    fmt->type;
-
-		dprintk(3, KERN_DEBUG "%s: VIDIOC_ENUM_FMT - index=%d\n",
-			ZR_DEVNAME(zr), fmt->index);
-
-		switch (fmt->type) {
-		case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-			flag = ZORAN_FORMAT_CAPTURE;
-			break;
-		case V4L2_BUF_TYPE_VIDEO_OUTPUT:
-			flag = ZORAN_FORMAT_PLAYBACK;
-			break;
-		case V4L2_BUF_TYPE_VIDEO_OVERLAY:
-			flag = ZORAN_FORMAT_OVERLAY;
-			break;
-		default:
-			dprintk(1,
-				KERN_ERR
-				"%s: VIDIOC_ENUM_FMT - unknown type %d\n",
-				ZR_DEVNAME(zr), fmt->type);
-			return -EINVAL;
-		}
-
-		for (i = 0; i < NUM_FORMATS; i++) {
-			if (zoran_formats[i].flags & flag)
-				num++;
-			if (num == fmt->index)
-				break;
-		}
-		if (fmt->index < 0 /* late, but not too late */  ||
-		    i == NUM_FORMATS)
-			return -EINVAL;
-
-		memset(fmt, 0, sizeof(*fmt));
-		fmt->index = index;
-		fmt->type = type;
-		strncpy(fmt->description, zoran_formats[i].name, sizeof(fmt->description)-1);
-		fmt->pixelformat = zoran_formats[i].fourcc;
-		if (zoran_formats[i].flags & ZORAN_FORMAT_COMPRESSED)
-			fmt->flags |= V4L2_FMT_FLAG_COMPRESSED;
-
-		return 0;
-	}
-		break;
-
-	case VIDIOC_G_FMT:
-	{
-		struct v4l2_format *fmt = arg;
-		int type = fmt->type;
-
-		dprintk(5, KERN_DEBUG "%s: VIDIOC_G_FMT\n", ZR_DEVNAME(zr));
-
-		memset(fmt, 0, sizeof(*fmt));
-		fmt->type = type;
-
-		switch (fmt->type) {
-		case V4L2_BUF_TYPE_VIDEO_OVERLAY:
-
-			mutex_lock(&zr->resource_lock);
-
-			fmt->fmt.win.w.left = fh->overlay_settings.x;
-			fmt->fmt.win.w.top = fh->overlay_settings.y;
-			fmt->fmt.win.w.width = fh->overlay_settings.width;
-			fmt->fmt.win.w.height =
-			    fh->overlay_settings.height;
-			if (fh->overlay_settings.width * 2 >
-			    BUZ_MAX_HEIGHT)
-				fmt->fmt.win.field = V4L2_FIELD_INTERLACED;
-			else
-				fmt->fmt.win.field = V4L2_FIELD_TOP;
-
-			mutex_unlock(&zr->resource_lock);
-
-			break;
-
-		case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-		case V4L2_BUF_TYPE_VIDEO_OUTPUT:
-
-			mutex_lock(&zr->resource_lock);
-
-			if (fmt->type == V4L2_BUF_TYPE_VIDEO_CAPTURE &&
-			    fh->map_mode == ZORAN_MAP_MODE_RAW) {
-
-				fmt->fmt.pix.width =
-				    fh->v4l_settings.width;
-				fmt->fmt.pix.height =
-				    fh->v4l_settings.height;
-				fmt->fmt.pix.sizeimage =
-				    fh->v4l_settings.bytesperline *
-				    fh->v4l_settings.height;
-				fmt->fmt.pix.pixelformat =
-				    fh->v4l_settings.format->fourcc;
-				fmt->fmt.pix.colorspace =
-				    fh->v4l_settings.format->colorspace;
-				fmt->fmt.pix.bytesperline = 0;
-				if (BUZ_MAX_HEIGHT <
-				    (fh->v4l_settings.height * 2))
-					fmt->fmt.pix.field =
-					    V4L2_FIELD_INTERLACED;
-				else
-					fmt->fmt.pix.field =
-					    V4L2_FIELD_TOP;
-
-			} else {
-
-				fmt->fmt.pix.width =
-				    fh->jpg_settings.img_width /
-				    fh->jpg_settings.HorDcm;
-				fmt->fmt.pix.height =
-				    fh->jpg_settings.img_height /
-				    (fh->jpg_settings.VerDcm *
-				     fh->jpg_settings.TmpDcm);
-				fmt->fmt.pix.sizeimage =
-				    zoran_v4l2_calc_bufsize(&fh->
-							    jpg_settings);
-				fmt->fmt.pix.pixelformat =
-				    V4L2_PIX_FMT_MJPEG;
-				if (fh->jpg_settings.TmpDcm == 1)
-					fmt->fmt.pix.field =
-					    (fh->jpg_settings.
-					     odd_even ? V4L2_FIELD_SEQ_BT :
-					     V4L2_FIELD_SEQ_BT);
-				else
-					fmt->fmt.pix.field =
-					    (fh->jpg_settings.
-					     odd_even ? V4L2_FIELD_TOP :
-					     V4L2_FIELD_BOTTOM);
-
-				fmt->fmt.pix.bytesperline = 0;
-				fmt->fmt.pix.colorspace =
-				    V4L2_COLORSPACE_SMPTE170M;
-			}
-
-			mutex_unlock(&zr->resource_lock);
-
-			break;
-
-		default:
-			dprintk(1,
-				KERN_ERR
-				"%s: VIDIOC_G_FMT - unsupported type %d\n",
-				ZR_DEVNAME(zr), fmt->type);
-			return -EINVAL;
-		}
-		return 0;
-	}
-		break;
-
-	case VIDIOC_S_FMT:
-	{
-		struct v4l2_format *fmt = arg;
-		int i, res = 0;
-		__le32 printformat;
-
-		dprintk(3, KERN_DEBUG "%s: VIDIOC_S_FMT - type=%d, ",
-			ZR_DEVNAME(zr), fmt->type);
-
-		switch (fmt->type) {
-		case V4L2_BUF_TYPE_VIDEO_OVERLAY:
-
-			dprintk(3, "x=%d, y=%d, w=%d, h=%d, cnt=%d, map=0x%p\n",
-				fmt->fmt.win.w.left, fmt->fmt.win.w.top,
-				fmt->fmt.win.w.width,
-				fmt->fmt.win.w.height,
-				fmt->fmt.win.clipcount,
-				fmt->fmt.win.bitmap);
-			mutex_lock(&zr->resource_lock);
-			res =
-			    setup_window(file, fmt->fmt.win.w.left,
-					 fmt->fmt.win.w.top,
-					 fmt->fmt.win.w.width,
-					 fmt->fmt.win.w.height,
-					 (struct video_clip __user *)
-					   fmt->fmt.win.clips,
-					 fmt->fmt.win.clipcount,
-					 fmt->fmt.win.bitmap);
-			mutex_unlock(&zr->resource_lock);
-			return res;
-			break;
-
-		case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-		case V4L2_BUF_TYPE_VIDEO_OUTPUT:
-
-			printformat =
-			    __cpu_to_le32(fmt->fmt.pix.pixelformat);
-			dprintk(3, "size=%dx%d, fmt=0x%x (%4.4s)\n",
-				fmt->fmt.pix.width, fmt->fmt.pix.height,
-				fmt->fmt.pix.pixelformat,
-				(char *) &printformat);
-
-			if (fmt->fmt.pix.bytesperline > 0) {
-				dprintk(5,
-					KERN_ERR "%s: bpl not supported\n",
-					ZR_DEVNAME(zr));
-				return -EINVAL;
-			}
-
-			/* we can be requested to do JPEG/raw playback/capture */
-			if (!
-			    (fmt->type == V4L2_BUF_TYPE_VIDEO_CAPTURE ||
-			     (fmt->type == V4L2_BUF_TYPE_VIDEO_OUTPUT &&
-			      fmt->fmt.pix.pixelformat ==
-			      V4L2_PIX_FMT_MJPEG))) {
-				dprintk(1,
-					KERN_ERR
-					"%s: VIDIOC_S_FMT - unknown type %d/0x%x(%4.4s) combination\n",
-					ZR_DEVNAME(zr), fmt->type,
-					fmt->fmt.pix.pixelformat,
-					(char *) &printformat);
-				return -EINVAL;
-			}
-
-			if (fmt->fmt.pix.pixelformat == V4L2_PIX_FMT_MJPEG) {
-				mutex_lock(&zr->resource_lock);
-
-				settings = fh->jpg_settings;
-
-				if (fh->v4l_buffers.allocated ||
-				    fh->jpg_buffers.allocated) {
-					dprintk(1,
-						KERN_ERR
-						"%s: VIDIOC_S_FMT - cannot change capture mode\n",
-						ZR_DEVNAME(zr));
-					res = -EBUSY;
-					goto sfmtjpg_unlock_and_return;
-				}
-
-				/* we actually need to set 'real' parameters now */
-				if ((fmt->fmt.pix.height * 2) >
-				    BUZ_MAX_HEIGHT)
-					settings.TmpDcm = 1;
-				else
-					settings.TmpDcm = 2;
-				settings.decimation = 0;
-				if (fmt->fmt.pix.height <=
-				    fh->jpg_settings.img_height / 2)
-					settings.VerDcm = 2;
-				else
-					settings.VerDcm = 1;
-				if (fmt->fmt.pix.width <=
-				    fh->jpg_settings.img_width / 4)
-					settings.HorDcm = 4;
-				else if (fmt->fmt.pix.width <=
-					 fh->jpg_settings.img_width / 2)
-					settings.HorDcm = 2;
-				else
-					settings.HorDcm = 1;
-				if (settings.TmpDcm == 1)
-					settings.field_per_buff = 2;
-				else
-					settings.field_per_buff = 1;
-
-				/* check */
-				if ((res =
-				     zoran_check_jpg_settings(zr,
-							      &settings)))
-					goto sfmtjpg_unlock_and_return;
-
-				/* it's ok, so set them */
-				fh->jpg_settings = settings;
-
-				/* tell the user what we actually did */
-				fmt->fmt.pix.width =
-				    settings.img_width / settings.HorDcm;
-				fmt->fmt.pix.height =
-				    settings.img_height * 2 /
-				    (settings.TmpDcm * settings.VerDcm);
-				if (settings.TmpDcm == 1)
-					fmt->fmt.pix.field =
-					    (fh->jpg_settings.
-					     odd_even ? V4L2_FIELD_SEQ_TB :
-					     V4L2_FIELD_SEQ_BT);
-				else
-					fmt->fmt.pix.field =
-					    (fh->jpg_settings.
-					     odd_even ? V4L2_FIELD_TOP :
-					     V4L2_FIELD_BOTTOM);
-				fh->jpg_buffers.buffer_size =
-				    zoran_v4l2_calc_bufsize(&fh->
-							    jpg_settings);
-				fmt->fmt.pix.sizeimage =
-				    fh->jpg_buffers.buffer_size;
-
-				/* we hereby abuse this variable to show that
-				 * we're gonna do mjpeg capture */
-				fh->map_mode =
-				    (fmt->type ==
-				     V4L2_BUF_TYPE_VIDEO_CAPTURE) ?
-				    ZORAN_MAP_MODE_JPG_REC :
-				    ZORAN_MAP_MODE_JPG_PLAY;
-			sfmtjpg_unlock_and_return:
-				mutex_unlock(&zr->resource_lock);
-			} else {
-				for (i = 0; i < NUM_FORMATS; i++)
-					if (fmt->fmt.pix.pixelformat ==
-					    zoran_formats[i].fourcc)
-						break;
-				if (i == NUM_FORMATS) {
-					dprintk(1,
-						KERN_ERR
-						"%s: VIDIOC_S_FMT - unknown/unsupported format 0x%x (%4.4s)\n",
-						ZR_DEVNAME(zr),
-						fmt->fmt.pix.pixelformat,
-						(char *) &printformat);
-					return -EINVAL;
-				}
-				mutex_lock(&zr->resource_lock);
-				if (fh->jpg_buffers.allocated ||
-				    (fh->v4l_buffers.allocated &&
-				     fh->v4l_buffers.active !=
-				     ZORAN_FREE)) {
-					dprintk(1,
-						KERN_ERR
-						"%s: VIDIOC_S_FMT - cannot change capture mode\n",
-						ZR_DEVNAME(zr));
-					res = -EBUSY;
-					goto sfmtv4l_unlock_and_return;
-				}
-				if (fmt->fmt.pix.height > BUZ_MAX_HEIGHT)
-					fmt->fmt.pix.height =
-					    BUZ_MAX_HEIGHT;
-				if (fmt->fmt.pix.width > BUZ_MAX_WIDTH)
-					fmt->fmt.pix.width = BUZ_MAX_WIDTH;
-
-				if ((res =
-				     zoran_v4l_set_format(file,
-							  fmt->fmt.pix.
-							  width,
-							  fmt->fmt.pix.
-							  height,
-							  &zoran_formats
-							  [i])))
-					goto sfmtv4l_unlock_and_return;
-
-				/* tell the user the
-				 * results/missing stuff */
-				fmt->fmt.pix.sizeimage =
-					fh->v4l_settings.height *
-					fh->v4l_settings.bytesperline;
-				if (BUZ_MAX_HEIGHT <
-				    (fh->v4l_settings.height * 2))
-					fmt->fmt.pix.field =
-					    V4L2_FIELD_INTERLACED;
-				else
-					fmt->fmt.pix.field =
-					    V4L2_FIELD_TOP;
-
-				fh->map_mode = ZORAN_MAP_MODE_RAW;
-			sfmtv4l_unlock_and_return:
-				mutex_unlock(&zr->resource_lock);
-			}
-
-			break;
-
-		default:
-			dprintk(3, "unsupported\n");
-			dprintk(1,
-				KERN_ERR
-				"%s: VIDIOC_S_FMT - unsupported type %d\n",
-				ZR_DEVNAME(zr), fmt->type);
-			return -EINVAL;
-		}
-
-		return res;
-	}
-		break;
-
-	case VIDIOC_G_FBUF:
-	{
-		struct v4l2_framebuffer *fb = arg;
-
-		dprintk(3, KERN_DEBUG "%s: VIDIOC_G_FBUF\n", ZR_DEVNAME(zr));
-
-		memset(fb, 0, sizeof(*fb));
-		mutex_lock(&zr->resource_lock);
-		fb->base = zr->buffer.base;
-		fb->fmt.width = zr->buffer.width;
-		fb->fmt.height = zr->buffer.height;
-		if (zr->overlay_settings.format) {
-			fb->fmt.pixelformat =
-				fh->overlay_settings.format->fourcc;
-		}
-		fb->fmt.bytesperline = zr->buffer.bytesperline;
-		mutex_unlock(&zr->resource_lock);
-		fb->fmt.colorspace = V4L2_COLORSPACE_SRGB;
-		fb->fmt.field = V4L2_FIELD_INTERLACED;
-		fb->flags = V4L2_FBUF_FLAG_OVERLAY;
-		fb->capability = V4L2_FBUF_CAP_LIST_CLIPPING;
-
-		return 0;
-	}
-		break;
-
-	case VIDIOC_S_FBUF:
-	{
-		int i, res = 0;
-		struct v4l2_framebuffer *fb = arg;
-		__le32 printformat = __cpu_to_le32(fb->fmt.pixelformat);
-
-		dprintk(3,
-			KERN_DEBUG
-			"%s: VIDIOC_S_FBUF - base=0x%p, size=%dx%d, bpl=%d, fmt=0x%x (%4.4s)\n",
-			ZR_DEVNAME(zr), fb->base, fb->fmt.width, fb->fmt.height,
-			fb->fmt.bytesperline, fb->fmt.pixelformat,
-			(char *) &printformat);
-
-		for (i = 0; i < NUM_FORMATS; i++)
-			if (zoran_formats[i].fourcc == fb->fmt.pixelformat)
-				break;
-		if (i == NUM_FORMATS) {
-			dprintk(1,
-				KERN_ERR
-				"%s: VIDIOC_S_FBUF - format=0x%x (%4.4s) not allowed\n",
-				ZR_DEVNAME(zr), fb->fmt.pixelformat,
-				(char *) &printformat);
-			return -EINVAL;
-		}
-
-		mutex_lock(&zr->resource_lock);
-		res =
-		    setup_fbuffer(file, fb->base, &zoran_formats[i],
-				  fb->fmt.width, fb->fmt.height,
-				  fb->fmt.bytesperline);
-		mutex_unlock(&zr->resource_lock);
-
-		return res;
-	}
-		break;
-
-	case VIDIOC_OVERLAY:
-	{
-		int *on = arg, res;
-
-		dprintk(3, KERN_DEBUG "%s: VIDIOC_PREVIEW - on=%d\n",
-			ZR_DEVNAME(zr), *on);
-
-		mutex_lock(&zr->resource_lock);
-		res = setup_overlay(file, *on);
-		mutex_unlock(&zr->resource_lock);
-
-		return res;
-	}
-		break;
-
-	case VIDIOC_REQBUFS:
-	{
-		struct v4l2_requestbuffers *req = arg;
-		int res = 0;
-
-		dprintk(3, KERN_DEBUG "%s: VIDIOC_REQBUFS - type=%d\n",
-			ZR_DEVNAME(zr), req->type);
-
-		if (req->memory != V4L2_MEMORY_MMAP) {
-			dprintk(1,
-				KERN_ERR
-				"%s: only MEMORY_MMAP capture is supported, not %d\n",
-				ZR_DEVNAME(zr), req->memory);
-			return -EINVAL;
-		}
-
-		mutex_lock(&zr->resource_lock);
-
-		if (fh->v4l_buffers.allocated || fh->jpg_buffers.allocated) {
-			dprintk(1,
-				KERN_ERR
-				"%s: VIDIOC_REQBUFS - buffers allready allocated\n",
-				ZR_DEVNAME(zr));
-			res = -EBUSY;
-			goto v4l2reqbuf_unlock_and_return;
-		}
-
-		if (fh->map_mode == ZORAN_MAP_MODE_RAW &&
-		    req->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
-
-			/* control user input */
-			if (req->count < 2)
-				req->count = 2;
-			if (req->count > v4l_nbufs)
-				req->count = v4l_nbufs;
-			fh->v4l_buffers.num_buffers = req->count;
-
-			if (v4l_fbuffer_alloc(file)) {
-				res = -ENOMEM;
-				goto v4l2reqbuf_unlock_and_return;
-			}
-
-			/* The next mmap will map the V4L buffers */
-			fh->map_mode = ZORAN_MAP_MODE_RAW;
-
-		} else if (fh->map_mode == ZORAN_MAP_MODE_JPG_REC ||
-			   fh->map_mode == ZORAN_MAP_MODE_JPG_PLAY) {
-
-			/* we need to calculate size ourselves now */
-			if (req->count < 4)
-				req->count = 4;
-			if (req->count > jpg_nbufs)
-				req->count = jpg_nbufs;
-			fh->jpg_buffers.num_buffers = req->count;
-			fh->jpg_buffers.buffer_size =
-			    zoran_v4l2_calc_bufsize(&fh->jpg_settings);
-
-			if (jpg_fbuffer_alloc(file)) {
-				res = -ENOMEM;
-				goto v4l2reqbuf_unlock_and_return;
-			}
-
-			/* The next mmap will map the MJPEG buffers */
-			if (req->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
-				fh->map_mode = ZORAN_MAP_MODE_JPG_REC;
-			else
-				fh->map_mode = ZORAN_MAP_MODE_JPG_PLAY;
-
-		} else {
-			dprintk(1,
-				KERN_ERR
-				"%s: VIDIOC_REQBUFS - unknown type %d\n",
-				ZR_DEVNAME(zr), req->type);
-			res = -EINVAL;
-			goto v4l2reqbuf_unlock_and_return;
-		}
-	v4l2reqbuf_unlock_and_return:
-		mutex_unlock(&zr->resource_lock);
-
-		return 0;
-	}
-		break;
-
-	case VIDIOC_QUERYBUF:
-	{
-		struct v4l2_buffer *buf = arg;
-		__u32 type = buf->type;
-		int index = buf->index, res;
-
-		dprintk(3,
-			KERN_DEBUG
-			"%s: VIDIOC_QUERYBUF - index=%d, type=%d\n",
-			ZR_DEVNAME(zr), buf->index, buf->type);
-
-		memset(buf, 0, sizeof(*buf));
-		buf->type = type;
-		buf->index = index;
-
-		mutex_lock(&zr->resource_lock);
-		res = zoran_v4l2_buffer_status(file, buf, buf->index);
-		mutex_unlock(&zr->resource_lock);
-
-		return res;
-	}
-		break;
-
-	case VIDIOC_QBUF:
-	{
-		struct v4l2_buffer *buf = arg;
-		int res = 0, codec_mode, buf_type;
-
-		dprintk(3,
-			KERN_DEBUG "%s: VIDIOC_QBUF - type=%d, index=%d\n",
-			ZR_DEVNAME(zr), buf->type, buf->index);
-
-		mutex_lock(&zr->resource_lock);
-
-		switch (fh->map_mode) {
-		case ZORAN_MAP_MODE_RAW:
-			if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
-				dprintk(1,
-					KERN_ERR
-					"%s: VIDIOC_QBUF - invalid buf->type=%d for map_mode=%d\n",
-					ZR_DEVNAME(zr), buf->type, fh->map_mode);
-				res = -EINVAL;
-				goto qbuf_unlock_and_return;
-			}
-
-			res = zoran_v4l_queue_frame(file, buf->index);
-			if (res)
-				goto qbuf_unlock_and_return;
-			if (!zr->v4l_memgrab_active &&
-			    fh->v4l_buffers.active == ZORAN_LOCKED)
-				zr36057_set_memgrab(zr, 1);
-			break;
-
-		case ZORAN_MAP_MODE_JPG_REC:
-		case ZORAN_MAP_MODE_JPG_PLAY:
-			if (fh->map_mode == ZORAN_MAP_MODE_JPG_PLAY) {
-				buf_type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
-				codec_mode = BUZ_MODE_MOTION_DECOMPRESS;
-			} else {
-				buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-				codec_mode = BUZ_MODE_MOTION_COMPRESS;
-			}
-
-			if (buf->type != buf_type) {
-				dprintk(1,
-					KERN_ERR
-					"%s: VIDIOC_QBUF - invalid buf->type=%d for map_mode=%d\n",
-					ZR_DEVNAME(zr), buf->type, fh->map_mode);
-				res = -EINVAL;
-				goto qbuf_unlock_and_return;
-			}
-
-			res =
-			    zoran_jpg_queue_frame(file, buf->index,
-						  codec_mode);
-			if (res != 0)
-				goto qbuf_unlock_and_return;
-			if (zr->codec_mode == BUZ_MODE_IDLE &&
-			    fh->jpg_buffers.active == ZORAN_LOCKED) {
-				zr36057_enable_jpg(zr, codec_mode);
-			}
-			break;
-
-		default:
-			dprintk(1,
-				KERN_ERR
-				"%s: VIDIOC_QBUF - unsupported type %d\n",
-				ZR_DEVNAME(zr), buf->type);
-			res = -EINVAL;
-			goto qbuf_unlock_and_return;
-		}
-	qbuf_unlock_and_return:
-		mutex_unlock(&zr->resource_lock);
-
-		return res;
-	}
-		break;
-
-	case VIDIOC_DQBUF:
-	{
-		struct v4l2_buffer *buf = arg;
-		int res = 0, buf_type, num = -1;	/* compiler borks here (?) */
-
-		dprintk(3, KERN_DEBUG "%s: VIDIOC_DQBUF - type=%d\n",
-			ZR_DEVNAME(zr), buf->type);
-
-		mutex_lock(&zr->resource_lock);
-
-		switch (fh->map_mode) {
-		case ZORAN_MAP_MODE_RAW:
-			if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
-				dprintk(1,
-					KERN_ERR
-					"%s: VIDIOC_QBUF - invalid buf->type=%d for map_mode=%d\n",
-					ZR_DEVNAME(zr), buf->type, fh->map_mode);
-				res = -EINVAL;
-				goto dqbuf_unlock_and_return;
-			}
-
-			num = zr->v4l_pend[zr->v4l_sync_tail & V4L_MASK_FRAME];
-			if (file->f_flags & O_NONBLOCK &&
-			    zr->v4l_buffers.buffer[num].state !=
-			    BUZ_STATE_DONE) {
-				res = -EAGAIN;
-				goto dqbuf_unlock_and_return;
-			}
-			res = v4l_sync(file, num);
-			if (res)
-				goto dqbuf_unlock_and_return;
-			else
-				zr->v4l_sync_tail++;
-			res = zoran_v4l2_buffer_status(file, buf, num);
-			break;
-
-		case ZORAN_MAP_MODE_JPG_REC:
-		case ZORAN_MAP_MODE_JPG_PLAY:
-		{
-			struct zoran_sync bs;
-
-			if (fh->map_mode == ZORAN_MAP_MODE_JPG_PLAY)
-				buf_type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
-			else
-				buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-
-			if (buf->type != buf_type) {
-				dprintk(1,
-					KERN_ERR
-					"%s: VIDIOC_QBUF - invalid buf->type=%d for map_mode=%d\n",
-					ZR_DEVNAME(zr), buf->type, fh->map_mode);
-				res = -EINVAL;
-				goto dqbuf_unlock_and_return;
-			}
-
-			num =
-			    zr->jpg_pend[zr->
-					 jpg_que_tail & BUZ_MASK_FRAME];
-
-			if (file->f_flags & O_NONBLOCK &&
-			    zr->jpg_buffers.buffer[num].state !=
-			    BUZ_STATE_DONE) {
-				res = -EAGAIN;
-				goto dqbuf_unlock_and_return;
-			}
-			res = jpg_sync(file, &bs);
-			if (res)
-				goto dqbuf_unlock_and_return;
-			res =
-			    zoran_v4l2_buffer_status(file, buf, bs.frame);
-			break;
-		}
-
-		default:
-			dprintk(1,
-				KERN_ERR
-				"%s: VIDIOC_DQBUF - unsupported type %d\n",
-				ZR_DEVNAME(zr), buf->type);
-			res = -EINVAL;
-			goto dqbuf_unlock_and_return;
-		}
-	dqbuf_unlock_and_return:
-		mutex_unlock(&zr->resource_lock);
-
-		return res;
-	}
-		break;
-
-	case VIDIOC_STREAMON:
-	{
-		int res = 0;
-
-		dprintk(3, KERN_DEBUG "%s: VIDIOC_STREAMON\n", ZR_DEVNAME(zr));
-
-		mutex_lock(&zr->resource_lock);
-
-		switch (fh->map_mode) {
-		case ZORAN_MAP_MODE_RAW:	/* raw capture */
-			if (zr->v4l_buffers.active != ZORAN_ACTIVE ||
-			    fh->v4l_buffers.active != ZORAN_ACTIVE) {
-				res = -EBUSY;
-				goto strmon_unlock_and_return;
-			}
-
-			zr->v4l_buffers.active = fh->v4l_buffers.active =
-			    ZORAN_LOCKED;
-			zr->v4l_settings = fh->v4l_settings;
-
-			zr->v4l_sync_tail = zr->v4l_pend_tail;
-			if (!zr->v4l_memgrab_active &&
-			    zr->v4l_pend_head != zr->v4l_pend_tail) {
-				zr36057_set_memgrab(zr, 1);
-			}
-			break;
-
-		case ZORAN_MAP_MODE_JPG_REC:
-		case ZORAN_MAP_MODE_JPG_PLAY:
-			/* what is the codec mode right now? */
-			if (zr->jpg_buffers.active != ZORAN_ACTIVE ||
-			    fh->jpg_buffers.active != ZORAN_ACTIVE) {
-				res = -EBUSY;
-				goto strmon_unlock_and_return;
-			}
-
-			zr->jpg_buffers.active = fh->jpg_buffers.active =
-			    ZORAN_LOCKED;
-
-			if (zr->jpg_que_head != zr->jpg_que_tail) {
-				/* Start the jpeg codec when the first frame is queued  */
-				jpeg_start(zr);
-			}
-
-			break;
-		default:
-			dprintk(1,
-				KERN_ERR
-				"%s: VIDIOC_STREAMON - invalid map mode %d\n",
-				ZR_DEVNAME(zr), fh->map_mode);
-			res = -EINVAL;
-			goto strmon_unlock_and_return;
-		}
-	strmon_unlock_and_return:
-		mutex_unlock(&zr->resource_lock);
-
-		return res;
-	}
-		break;
-
-	case VIDIOC_STREAMOFF:
-	{
-		int i, res = 0;
-
-		dprintk(3, KERN_DEBUG "%s: VIDIOC_STREAMOFF\n", ZR_DEVNAME(zr));
-
-		mutex_lock(&zr->resource_lock);
-
-		switch (fh->map_mode) {
-		case ZORAN_MAP_MODE_RAW:	/* raw capture */
-			if (fh->v4l_buffers.active == ZORAN_FREE &&
-			    zr->v4l_buffers.active != ZORAN_FREE) {
-				res = -EPERM;	/* stay off other's settings! */
-				goto strmoff_unlock_and_return;
-			}
-			if (zr->v4l_buffers.active == ZORAN_FREE)
-				goto strmoff_unlock_and_return;
-
-			/* unload capture */
-			if (zr->v4l_memgrab_active) {
-				unsigned long flags;
-
-				spin_lock_irqsave(&zr->spinlock, flags);
-				zr36057_set_memgrab(zr, 0);
-				spin_unlock_irqrestore(&zr->spinlock, flags);
-			}
-
-			for (i = 0; i < fh->v4l_buffers.num_buffers; i++)
-				zr->v4l_buffers.buffer[i].state =
-				    BUZ_STATE_USER;
-			fh->v4l_buffers = zr->v4l_buffers;
-
-			zr->v4l_buffers.active = fh->v4l_buffers.active =
-			    ZORAN_FREE;
-
-			zr->v4l_grab_seq = 0;
-			zr->v4l_pend_head = zr->v4l_pend_tail = 0;
-			zr->v4l_sync_tail = 0;
-
-			break;
-
-		case ZORAN_MAP_MODE_JPG_REC:
-		case ZORAN_MAP_MODE_JPG_PLAY:
-			if (fh->jpg_buffers.active == ZORAN_FREE &&
-			    zr->jpg_buffers.active != ZORAN_FREE) {
-				res = -EPERM;	/* stay off other's settings! */
-				goto strmoff_unlock_and_return;
-			}
-			if (zr->jpg_buffers.active == ZORAN_FREE)
-				goto strmoff_unlock_and_return;
-
-			res =
-			    jpg_qbuf(file, -1,
-				     (fh->map_mode ==
-				      ZORAN_MAP_MODE_JPG_REC) ?
-				     BUZ_MODE_MOTION_COMPRESS :
-				     BUZ_MODE_MOTION_DECOMPRESS);
-			if (res)
-				goto strmoff_unlock_and_return;
-			break;
-		default:
-			dprintk(1,
-				KERN_ERR
-				"%s: VIDIOC_STREAMOFF - invalid map mode %d\n",
-				ZR_DEVNAME(zr), fh->map_mode);
-			res = -EINVAL;
-			goto strmoff_unlock_and_return;
-		}
-	strmoff_unlock_and_return:
-		mutex_unlock(&zr->resource_lock);
-
-		return res;
-	}
-		break;
-
-	case VIDIOC_QUERYCTRL:
-	{
-		struct v4l2_queryctrl *ctrl = arg;
-
-		dprintk(3, KERN_DEBUG "%s: VIDIOC_QUERYCTRL - id=%d\n",
-			ZR_DEVNAME(zr), ctrl->id);
-
-		/* we only support hue/saturation/contrast/brightness */
-		if (ctrl->id < V4L2_CID_BRIGHTNESS ||
-		    ctrl->id > V4L2_CID_HUE)
-			return -EINVAL;
-		else {
-			int id = ctrl->id;
-			memset(ctrl, 0, sizeof(*ctrl));
-			ctrl->id = id;
-		}
-
-		switch (ctrl->id) {
-		case V4L2_CID_BRIGHTNESS:
-			strncpy(ctrl->name, "Brightness", sizeof(ctrl->name)-1);
-			break;
-		case V4L2_CID_CONTRAST:
-			strncpy(ctrl->name, "Contrast", sizeof(ctrl->name)-1);
-			break;
-		case V4L2_CID_SATURATION:
-			strncpy(ctrl->name, "Saturation", sizeof(ctrl->name)-1);
-			break;
-		case V4L2_CID_HUE:
-			strncpy(ctrl->name, "Hue", sizeof(ctrl->name)-1);
-			break;
-		}
-
-		ctrl->minimum = 0;
-		ctrl->maximum = 65535;
-		ctrl->step = 1;
-		ctrl->default_value = 32768;
-		ctrl->type = V4L2_CTRL_TYPE_INTEGER;
-
-		return 0;
-	}
-		break;
-
-	case VIDIOC_G_CTRL:
-	{
-		struct v4l2_control *ctrl = arg;
-
-		dprintk(3, KERN_DEBUG "%s: VIDIOC_G_CTRL - id=%d\n",
-			ZR_DEVNAME(zr), ctrl->id);
-
-		/* we only support hue/saturation/contrast/brightness */
-		if (ctrl->id < V4L2_CID_BRIGHTNESS ||
-		    ctrl->id > V4L2_CID_HUE)
-			return -EINVAL;
-
-		mutex_lock(&zr->resource_lock);
-		switch (ctrl->id) {
-		case V4L2_CID_BRIGHTNESS:
-			ctrl->value = zr->brightness;
-			break;
-		case V4L2_CID_CONTRAST:
-			ctrl->value = zr->contrast;
-			break;
-		case V4L2_CID_SATURATION:
-			ctrl->value = zr->saturation;
-			break;
-		case V4L2_CID_HUE:
-			ctrl->value = zr->hue;
-			break;
-		}
-		mutex_unlock(&zr->resource_lock);
-
-		return 0;
-	}
-		break;
-
-	case VIDIOC_S_CTRL:
-	{
-		struct v4l2_control *ctrl = arg;
-		struct video_picture pict;
-
-		dprintk(3, KERN_DEBUG "%s: VIDIOC_S_CTRL - id=%d\n",
-			ZR_DEVNAME(zr), ctrl->id);
-
-		/* we only support hue/saturation/contrast/brightness */
-		if (ctrl->id < V4L2_CID_BRIGHTNESS ||
-		    ctrl->id > V4L2_CID_HUE)
-			return -EINVAL;
-
-		if (ctrl->value < 0 || ctrl->value > 65535) {
-			dprintk(1,
-				KERN_ERR
-				"%s: VIDIOC_S_CTRL - invalid value %d for id=%d\n",
-				ZR_DEVNAME(zr), ctrl->value, ctrl->id);
-			return -EINVAL;
-		}
-
-		mutex_lock(&zr->resource_lock);
-		switch (ctrl->id) {
-		case V4L2_CID_BRIGHTNESS:
-			zr->brightness = ctrl->value;
-			break;
-		case V4L2_CID_CONTRAST:
-			zr->contrast = ctrl->value;
-			break;
-		case V4L2_CID_SATURATION:
-			zr->saturation = ctrl->value;
-			break;
-		case V4L2_CID_HUE:
-			zr->hue = ctrl->value;
-			break;
-		}
-		pict.brightness = zr->brightness;
-		pict.contrast = zr->contrast;
-		pict.colour = zr->saturation;
-		pict.hue = zr->hue;
-
-		decoder_command(zr, DECODER_SET_PICTURE, &pict);
-
-		mutex_unlock(&zr->resource_lock);
-
-		return 0;
-	}
-		break;
-
-	case VIDIOC_ENUMSTD:
-	{
-		struct v4l2_standard *std = arg;
-
-		dprintk(3, KERN_DEBUG "%s: VIDIOC_ENUMSTD - index=%d\n",
-			ZR_DEVNAME(zr), std->index);
-
-		if (std->index < 0 || std->index >= (zr->card.norms + 1))
-			return -EINVAL;
-		else {
-			int id = std->index;
-			memset(std, 0, sizeof(*std));
-			std->index = id;
-		}
-
-		if (std->index == zr->card.norms) {
-			/* if we have autodetect, ... */
-			struct video_decoder_capability caps;
-			decoder_command(zr, DECODER_GET_CAPABILITIES,
-					&caps);
-			if (caps.flags & VIDEO_DECODER_AUTO) {
-				std->id = V4L2_STD_ALL;
-				strncpy(std->name, "Autodetect", sizeof(std->name)-1);
-				return 0;
-			} else
-				return -EINVAL;
-		}
-		switch (std->index) {
-		case 0:
-			std->id = V4L2_STD_PAL;
-			strncpy(std->name, "PAL", sizeof(std->name)-1);
-			std->frameperiod.numerator = 1;
-			std->frameperiod.denominator = 25;
-			std->framelines = zr->card.tvn[0]->Ht;
-			break;
-		case 1:
-			std->id = V4L2_STD_NTSC;
-			strncpy(std->name, "NTSC", sizeof(std->name)-1);
-			std->frameperiod.numerator = 1001;
-			std->frameperiod.denominator = 30000;
-			std->framelines = zr->card.tvn[1]->Ht;
-			break;
-		case 2:
-			std->id = V4L2_STD_SECAM;
-			strncpy(std->name, "SECAM", sizeof(std->name)-1);
-			std->frameperiod.numerator = 1;
-			std->frameperiod.denominator = 25;
-			std->framelines = zr->card.tvn[2]->Ht;
-			break;
-		}
-
-		return 0;
-	}
-		break;
-
-	case VIDIOC_G_STD:
-	{
-		v4l2_std_id *std = arg;
-		int norm;
-
-		dprintk(3, KERN_DEBUG "%s: VIDIOC_G_STD\n", ZR_DEVNAME(zr));
-
-		mutex_lock(&zr->resource_lock);
-		norm = zr->norm;
-		mutex_unlock(&zr->resource_lock);
-
-		switch (norm) {
-		case VIDEO_MODE_PAL:
-			*std = V4L2_STD_PAL;
-			break;
-		case VIDEO_MODE_NTSC:
-			*std = V4L2_STD_NTSC;
-			break;
-		case VIDEO_MODE_SECAM:
-			*std = V4L2_STD_SECAM;
-			break;
-		}
-
-		return 0;
-	}
-		break;
-
-	case VIDIOC_S_STD:
-	{
-		int norm = -1, res = 0;
-		v4l2_std_id *std = arg;
-
-		dprintk(3, KERN_DEBUG "%s: VIDIOC_S_STD - norm=0x%llx\n",
-			ZR_DEVNAME(zr), (unsigned long long)*std);
-
-		if ((*std & V4L2_STD_PAL) && !(*std & ~V4L2_STD_PAL))
-			norm = VIDEO_MODE_PAL;
-		else if ((*std & V4L2_STD_NTSC) && !(*std & ~V4L2_STD_NTSC))
-			norm = VIDEO_MODE_NTSC;
-		else if ((*std & V4L2_STD_SECAM) && !(*std & ~V4L2_STD_SECAM))
-			norm = VIDEO_MODE_SECAM;
-		else if (*std == V4L2_STD_ALL)
-			norm = VIDEO_MODE_AUTO;
-		else {
-			dprintk(1,
-				KERN_ERR
-				"%s: VIDIOC_S_STD - invalid norm 0x%llx\n",
-				ZR_DEVNAME(zr), (unsigned long long)*std);
-			return -EINVAL;
-		}
-
-		mutex_lock(&zr->resource_lock);
-		if ((res = zoran_set_norm(zr, norm)))
-			goto sstd_unlock_and_return;
-
-		res = wait_grab_pending(zr);
-	sstd_unlock_and_return:
-		mutex_unlock(&zr->resource_lock);
-		return res;
-	}
-		break;
-
-	case VIDIOC_ENUMINPUT:
-	{
-		struct v4l2_input *inp = arg;
-		int status;
-
-		dprintk(3, KERN_DEBUG "%s: VIDIOC_ENUMINPUT - index=%d\n",
-			ZR_DEVNAME(zr), inp->index);
-
-		if (inp->index < 0 || inp->index >= zr->card.inputs)
-			return -EINVAL;
-		else {
-			int id = inp->index;
-			memset(inp, 0, sizeof(*inp));
-			inp->index = id;
-		}
-
-		strncpy(inp->name, zr->card.input[inp->index].name,
-			sizeof(inp->name) - 1);
-		inp->type = V4L2_INPUT_TYPE_CAMERA;
-		inp->std = V4L2_STD_ALL;
-
-		/* Get status of video decoder */
-		mutex_lock(&zr->resource_lock);
-		decoder_command(zr, DECODER_GET_STATUS, &status);
-		mutex_unlock(&zr->resource_lock);
-
-		if (!(status & DECODER_STATUS_GOOD)) {
-			inp->status |= V4L2_IN_ST_NO_POWER;
-			inp->status |= V4L2_IN_ST_NO_SIGNAL;
-		}
-		if (!(status & DECODER_STATUS_COLOR))
-			inp->status |= V4L2_IN_ST_NO_COLOR;
-
-		return 0;
-	}
-		break;
-
-	case VIDIOC_G_INPUT:
-	{
-		int *input = arg;
-
-		dprintk(3, KERN_DEBUG "%s: VIDIOC_G_INPUT\n", ZR_DEVNAME(zr));
-
-		mutex_lock(&zr->resource_lock);
-		*input = zr->input;
-		mutex_unlock(&zr->resource_lock);
-
-		return 0;
-	}
-		break;
-
-	case VIDIOC_S_INPUT:
-	{
-		int *input = arg, res = 0;
-
-		dprintk(3, KERN_DEBUG "%s: VIDIOC_S_INPUT - input=%d\n",
-			ZR_DEVNAME(zr), *input);
-
-		mutex_lock(&zr->resource_lock);
-		if ((res = zoran_set_input(zr, *input)))
-			goto sinput_unlock_and_return;
-
-		/* Make sure the changes come into effect */
-		res = wait_grab_pending(zr);
-	sinput_unlock_and_return:
-		mutex_unlock(&zr->resource_lock);
-		return res;
-	}
-		break;
-
-	case VIDIOC_ENUMOUTPUT:
-	{
-		struct v4l2_output *outp = arg;
-
-		dprintk(3, KERN_DEBUG "%s: VIDIOC_ENUMOUTPUT - index=%d\n",
-			ZR_DEVNAME(zr), outp->index);
-
-		if (outp->index != 0)
-			return -EINVAL;
-
-		memset(outp, 0, sizeof(*outp));
-		outp->index = 0;
-		outp->type = V4L2_OUTPUT_TYPE_ANALOGVGAOVERLAY;
-		strncpy(outp->name, "Autodetect", sizeof(outp->name)-1);
-
-		return 0;
-	}
-		break;
-
-	case VIDIOC_G_OUTPUT:
-	{
-		int *output = arg;
-
-		dprintk(3, KERN_DEBUG "%s: VIDIOC_G_OUTPUT\n", ZR_DEVNAME(zr));
-
-		*output = 0;
-
-		return 0;
-	}
-		break;
-
-	case VIDIOC_S_OUTPUT:
-	{
-		int *output = arg;
-
-		dprintk(3, KERN_DEBUG "%s: VIDIOC_S_OUTPUT - output=%d\n",
-			ZR_DEVNAME(zr), *output);
-
-		if (*output != 0)
-			return -EINVAL;
-
-		return 0;
-	}
-		break;
-
-		/* cropping (sub-frame capture) */
-	case VIDIOC_CROPCAP:
-	{
-		struct v4l2_cropcap *cropcap = arg;
-		int type = cropcap->type, res = 0;
-
-		dprintk(3, KERN_ERR "%s: VIDIOC_CROPCAP - type=%d\n",
-			ZR_DEVNAME(zr), cropcap->type);
-
-		memset(cropcap, 0, sizeof(*cropcap));
-		cropcap->type = type;
-
-		mutex_lock(&zr->resource_lock);
-
-		if (cropcap->type != V4L2_BUF_TYPE_VIDEO_OUTPUT &&
-		    (cropcap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
-		     fh->map_mode == ZORAN_MAP_MODE_RAW)) {
-			dprintk(1,
-				KERN_ERR
-				"%s: VIDIOC_CROPCAP - subcapture only supported for compressed capture\n",
-				ZR_DEVNAME(zr));
-			res = -EINVAL;
-			goto cropcap_unlock_and_return;
-		}
-
-		cropcap->bounds.top = cropcap->bounds.left = 0;
-		cropcap->bounds.width = BUZ_MAX_WIDTH;
-		cropcap->bounds.height = BUZ_MAX_HEIGHT;
-		cropcap->defrect.top = cropcap->defrect.left = 0;
-		cropcap->defrect.width = BUZ_MIN_WIDTH;
-		cropcap->defrect.height = BUZ_MIN_HEIGHT;
-	cropcap_unlock_and_return:
-		mutex_unlock(&zr->resource_lock);
-		return res;
-	}
-		break;
-
-	case VIDIOC_G_CROP:
-	{
-		struct v4l2_crop *crop = arg;
-		int type = crop->type, res = 0;
-
-		dprintk(3, KERN_ERR "%s: VIDIOC_G_CROP - type=%d\n",
-			ZR_DEVNAME(zr), crop->type);
-
-		memset(crop, 0, sizeof(*crop));
-		crop->type = type;
-
-		mutex_lock(&zr->resource_lock);
-
-		if (crop->type != V4L2_BUF_TYPE_VIDEO_OUTPUT &&
-		    (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
-		     fh->map_mode == ZORAN_MAP_MODE_RAW)) {
-			dprintk(1,
-				KERN_ERR
-				"%s: VIDIOC_G_CROP - subcapture only supported for compressed capture\n",
-				ZR_DEVNAME(zr));
-			res = -EINVAL;
-			goto gcrop_unlock_and_return;
-		}
-
-		crop->c.top = fh->jpg_settings.img_y;
-		crop->c.left = fh->jpg_settings.img_x;
-		crop->c.width = fh->jpg_settings.img_width;
-		crop->c.height = fh->jpg_settings.img_height;
-
-	gcrop_unlock_and_return:
-		mutex_unlock(&zr->resource_lock);
-
-		return res;
-	}
-		break;
-
-	case VIDIOC_S_CROP:
-	{
-		struct v4l2_crop *crop = arg;
-		int res = 0;
-
-		settings = fh->jpg_settings;
-
-		dprintk(3,
-			KERN_ERR
-			"%s: VIDIOC_S_CROP - type=%d, x=%d,y=%d,w=%d,h=%d\n",
-			ZR_DEVNAME(zr), crop->type, crop->c.left, crop->c.top,
-			crop->c.width, crop->c.height);
-
-		mutex_lock(&zr->resource_lock);
-
-		if (fh->jpg_buffers.allocated || fh->v4l_buffers.allocated) {
-			dprintk(1,
-				KERN_ERR
-				"%s: VIDIOC_S_CROP - cannot change settings while active\n",
-				ZR_DEVNAME(zr));
-			res = -EBUSY;
-			goto scrop_unlock_and_return;
-		}
-
-		if (crop->type != V4L2_BUF_TYPE_VIDEO_OUTPUT &&
-		    (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
-		     fh->map_mode == ZORAN_MAP_MODE_RAW)) {
-			dprintk(1,
-				KERN_ERR
-				"%s: VIDIOC_G_CROP - subcapture only supported for compressed capture\n",
-				ZR_DEVNAME(zr));
-			res = -EINVAL;
-			goto scrop_unlock_and_return;
-		}
-
-		/* move into a form that we understand */
-		settings.img_x = crop->c.left;
-		settings.img_y = crop->c.top;
-		settings.img_width = crop->c.width;
-		settings.img_height = crop->c.height;
-
-		/* check validity */
-		if ((res = zoran_check_jpg_settings(zr, &settings)))
-			goto scrop_unlock_and_return;
-
-		/* accept */
-		fh->jpg_settings = settings;
-
-	scrop_unlock_and_return:
-		mutex_unlock(&zr->resource_lock);
-		return res;
-	}
-		break;
-
-	case VIDIOC_G_JPEGCOMP:
-	{
-		struct v4l2_jpegcompression *params = arg;
-
-		dprintk(3, KERN_DEBUG "%s: VIDIOC_G_JPEGCOMP\n",
-			ZR_DEVNAME(zr));
-
-		memset(params, 0, sizeof(*params));
-
-		mutex_lock(&zr->resource_lock);
-
-		params->quality = fh->jpg_settings.jpg_comp.quality;
-		params->APPn = fh->jpg_settings.jpg_comp.APPn;
-		memcpy(params->APP_data,
-		       fh->jpg_settings.jpg_comp.APP_data,
-		       fh->jpg_settings.jpg_comp.APP_len);
-		params->APP_len = fh->jpg_settings.jpg_comp.APP_len;
-		memcpy(params->COM_data,
-		       fh->jpg_settings.jpg_comp.COM_data,
-		       fh->jpg_settings.jpg_comp.COM_len);
-		params->COM_len = fh->jpg_settings.jpg_comp.COM_len;
-		params->jpeg_markers =
-		    fh->jpg_settings.jpg_comp.jpeg_markers;
-
-		mutex_unlock(&zr->resource_lock);
-
-		return 0;
-	}
-		break;
-
-	case VIDIOC_S_JPEGCOMP:
-	{
-		struct v4l2_jpegcompression *params = arg;
-		int res = 0;
-
-		settings = fh->jpg_settings;
-
-		dprintk(3,
-			KERN_DEBUG
-			"%s: VIDIOC_S_JPEGCOMP - quality=%d, APPN=%d, APP_len=%d, COM_len=%d\n",
-			ZR_DEVNAME(zr), params->quality, params->APPn,
-			params->APP_len, params->COM_len);
-
-		settings.jpg_comp = *params;
-
-		mutex_lock(&zr->resource_lock);
-
-		if (fh->v4l_buffers.active != ZORAN_FREE ||
-		    fh->jpg_buffers.active != ZORAN_FREE) {
-			dprintk(1,
-				KERN_WARNING
-				"%s: VIDIOC_S_JPEGCOMP called while in playback/capture mode\n",
-				ZR_DEVNAME(zr));
-			res = -EBUSY;
-			goto sjpegc_unlock_and_return;
-		}
-
-		if ((res = zoran_check_jpg_settings(zr, &settings)))
-			goto sjpegc_unlock_and_return;
-		if (!fh->jpg_buffers.allocated)
-			fh->jpg_buffers.buffer_size =
-			    zoran_v4l2_calc_bufsize(&fh->jpg_settings);
-		fh->jpg_settings.jpg_comp = *params = settings.jpg_comp;
-	sjpegc_unlock_and_return:
-		mutex_unlock(&zr->resource_lock);
-
-		return 0;
-	}
-		break;
-
-	case VIDIOC_QUERYSTD:	/* why is this useful? */
-	{
-		v4l2_std_id *std = arg;
-
-		dprintk(3,
-			KERN_DEBUG "%s: VIDIOC_QUERY_STD - std=0x%llx\n",
-			ZR_DEVNAME(zr), (unsigned long long)*std);
-
-		if (*std == V4L2_STD_ALL || *std == V4L2_STD_NTSC ||
-		    *std == V4L2_STD_PAL || (*std == V4L2_STD_SECAM &&
-					     zr->card.norms == 3)) {
-			return 0;
-		}
-
-		return -EINVAL;
-	}
-		break;
-
-	case VIDIOC_TRY_FMT:
-	{
-		struct v4l2_format *fmt = arg;
-		int res = 0;
-
-		dprintk(3, KERN_DEBUG "%s: VIDIOC_TRY_FMT - type=%d\n",
-			ZR_DEVNAME(zr), fmt->type);
-
-		switch (fmt->type) {
-		case V4L2_BUF_TYPE_VIDEO_OVERLAY:
-			mutex_lock(&zr->resource_lock);
-
-			if (fmt->fmt.win.w.width > BUZ_MAX_WIDTH)
-				fmt->fmt.win.w.width = BUZ_MAX_WIDTH;
-			if (fmt->fmt.win.w.width < BUZ_MIN_WIDTH)
-				fmt->fmt.win.w.width = BUZ_MIN_WIDTH;
-			if (fmt->fmt.win.w.height > BUZ_MAX_HEIGHT)
-				fmt->fmt.win.w.height = BUZ_MAX_HEIGHT;
-			if (fmt->fmt.win.w.height < BUZ_MIN_HEIGHT)
-				fmt->fmt.win.w.height = BUZ_MIN_HEIGHT;
-
-			mutex_unlock(&zr->resource_lock);
-			break;
-
-		case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-		case V4L2_BUF_TYPE_VIDEO_OUTPUT:
-			if (fmt->fmt.pix.bytesperline > 0)
-				return -EINVAL;
-
-			mutex_lock(&zr->resource_lock);
-
-			if (fmt->fmt.pix.pixelformat == V4L2_PIX_FMT_MJPEG) {
-				settings = fh->jpg_settings;
-
-				/* we actually need to set 'real' parameters now */
-				if ((fmt->fmt.pix.height * 2) >
-				    BUZ_MAX_HEIGHT)
-					settings.TmpDcm = 1;
-				else
-					settings.TmpDcm = 2;
-				settings.decimation = 0;
-				if (fmt->fmt.pix.height <=
-				    fh->jpg_settings.img_height / 2)
-					settings.VerDcm = 2;
-				else
-					settings.VerDcm = 1;
-				if (fmt->fmt.pix.width <=
-				    fh->jpg_settings.img_width / 4)
-					settings.HorDcm = 4;
-				else if (fmt->fmt.pix.width <=
-					 fh->jpg_settings.img_width / 2)
-					settings.HorDcm = 2;
-				else
-					settings.HorDcm = 1;
-				if (settings.TmpDcm == 1)
-					settings.field_per_buff = 2;
-				else
-					settings.field_per_buff = 1;
-
-				/* check */
-				if ((res =
-				     zoran_check_jpg_settings(zr,
-							      &settings)))
-					goto tryfmt_unlock_and_return;
-
-				/* tell the user what we actually did */
-				fmt->fmt.pix.width =
-				    settings.img_width / settings.HorDcm;
-				fmt->fmt.pix.height =
-				    settings.img_height * 2 /
-				    (settings.TmpDcm * settings.VerDcm);
-				if (settings.TmpDcm == 1)
-					fmt->fmt.pix.field =
-					    (fh->jpg_settings.
-					     odd_even ? V4L2_FIELD_SEQ_TB :
-					     V4L2_FIELD_SEQ_BT);
-				else
-					fmt->fmt.pix.field =
-					    (fh->jpg_settings.
-					     odd_even ? V4L2_FIELD_TOP :
-					     V4L2_FIELD_BOTTOM);
-
-				fmt->fmt.pix.sizeimage =
-				    zoran_v4l2_calc_bufsize(&settings);
-			} else if (fmt->type ==
-				   V4L2_BUF_TYPE_VIDEO_CAPTURE) {
-				int i;
-
-				for (i = 0; i < NUM_FORMATS; i++)
-					if (zoran_formats[i].fourcc ==
-					    fmt->fmt.pix.pixelformat)
-						break;
-				if (i == NUM_FORMATS) {
-					res = -EINVAL;
-					goto tryfmt_unlock_and_return;
-				}
-
-				if (fmt->fmt.pix.width > BUZ_MAX_WIDTH)
-					fmt->fmt.pix.width = BUZ_MAX_WIDTH;
-				if (fmt->fmt.pix.width < BUZ_MIN_WIDTH)
-					fmt->fmt.pix.width = BUZ_MIN_WIDTH;
-				if (fmt->fmt.pix.height > BUZ_MAX_HEIGHT)
-					fmt->fmt.pix.height =
-					    BUZ_MAX_HEIGHT;
-				if (fmt->fmt.pix.height < BUZ_MIN_HEIGHT)
-					fmt->fmt.pix.height =
-					    BUZ_MIN_HEIGHT;
-			} else {
-				res = -EINVAL;
-				goto tryfmt_unlock_and_return;
-			}
-		tryfmt_unlock_and_return:
-			mutex_unlock(&zr->resource_lock);
-
-			return res;
-			break;
-
-		default:
-			return -EINVAL;
-		}
-
-		return 0;
-	}
-		break;
-
-	default:
-		dprintk(1, KERN_DEBUG "%s: UNKNOWN ioctl cmd: 0x%x\n",
-			ZR_DEVNAME(zr), cmd);
-		return -ENOIOCTLCMD;
-		break;
-
-	}
-	return 0;
-}
-
-
-static int
-zoran_ioctl (struct inode *inode,
-	     struct file  *file,
-	     unsigned int  cmd,
-	     unsigned long arg)
-{
-	return video_usercopy(inode, file, cmd, arg, zoran_do_ioctl);
-}
-
-static unsigned int
-zoran_poll (struct file *file,
-	    poll_table  *wait)
-{
-	struct zoran_fh *fh = file->private_data;
-	struct zoran *zr = fh->zr;
-	int res = 0, frame;
-	unsigned long flags;
-
-	/* we should check whether buffers are ready to be synced on
-	 * (w/o waits - O_NONBLOCK) here
-	 * if ready for read (sync), return POLLIN|POLLRDNORM,
-	 * if ready for write (sync), return POLLOUT|POLLWRNORM,
-	 * if error, return POLLERR,
-	 * if no buffers queued or so, return POLLNVAL
-	 */
-
-	mutex_lock(&zr->resource_lock);
-
-	switch (fh->map_mode) {
-	case ZORAN_MAP_MODE_RAW:
-		poll_wait(file, &zr->v4l_capq, wait);
-		frame = zr->v4l_pend[zr->v4l_sync_tail & V4L_MASK_FRAME];
-
-		spin_lock_irqsave(&zr->spinlock, flags);
-		dprintk(3,
-			KERN_DEBUG
-			"%s: %s() raw - active=%c, sync_tail=%lu/%c, pend_tail=%lu, pend_head=%lu\n",
-			ZR_DEVNAME(zr), __func__,
-			"FAL"[fh->v4l_buffers.active], zr->v4l_sync_tail,
-			"UPMD"[zr->v4l_buffers.buffer[frame].state],
-			zr->v4l_pend_tail, zr->v4l_pend_head);
-		/* Process is the one capturing? */
-		if (fh->v4l_buffers.active != ZORAN_FREE &&
-		    /* Buffer ready to DQBUF? */
-		    zr->v4l_buffers.buffer[frame].state == BUZ_STATE_DONE)
-			res = POLLIN | POLLRDNORM;
-		spin_unlock_irqrestore(&zr->spinlock, flags);
-
-		break;
-
-	case ZORAN_MAP_MODE_JPG_REC:
-	case ZORAN_MAP_MODE_JPG_PLAY:
-		poll_wait(file, &zr->jpg_capq, wait);
-		frame = zr->jpg_pend[zr->jpg_que_tail & BUZ_MASK_FRAME];
-
-		spin_lock_irqsave(&zr->spinlock, flags);
-		dprintk(3,
-			KERN_DEBUG
-			"%s: %s() jpg - active=%c, que_tail=%lu/%c, que_head=%lu, dma=%lu/%lu\n",
-			ZR_DEVNAME(zr), __func__,
-			"FAL"[fh->jpg_buffers.active], zr->jpg_que_tail,
-			"UPMD"[zr->jpg_buffers.buffer[frame].state],
-			zr->jpg_que_head, zr->jpg_dma_tail, zr->jpg_dma_head);
-		if (fh->jpg_buffers.active != ZORAN_FREE &&
-		    zr->jpg_buffers.buffer[frame].state == BUZ_STATE_DONE) {
-			if (fh->map_mode == ZORAN_MAP_MODE_JPG_REC)
-				res = POLLIN | POLLRDNORM;
-			else
-				res = POLLOUT | POLLWRNORM;
-		}
-		spin_unlock_irqrestore(&zr->spinlock, flags);
-
-		break;
-
-	default:
-		dprintk(1,
-			KERN_ERR
-			"%s: zoran_poll() - internal error, unknown map_mode=%d\n",
-			ZR_DEVNAME(zr), fh->map_mode);
-		res = POLLNVAL;
-	}
-
-	mutex_unlock(&zr->resource_lock);
-
-	return res;
-}
-
-
-/*
- * This maps the buffers to user space.
- *
- * Depending on the state of fh->map_mode
- * the V4L or the MJPEG buffers are mapped
- * per buffer or all together
- *
- * Note that we need to connect to some
- * unmap signal event to unmap the de-allocate
- * the buffer accordingly (zoran_vm_close())
- */
-
-static void
-zoran_vm_open (struct vm_area_struct *vma)
-{
-	struct zoran_mapping *map = vma->vm_private_data;
-
-	map->count++;
-}
-
-static void
-zoran_vm_close (struct vm_area_struct *vma)
-{
-	struct zoran_mapping *map = vma->vm_private_data;
-	struct file *file = map->file;
-	struct zoran_fh *fh = file->private_data;
-	struct zoran *zr = fh->zr;
-	int i;
-
-	map->count--;
-	if (map->count == 0) {
-		switch (fh->map_mode) {
-		case ZORAN_MAP_MODE_JPG_REC:
-		case ZORAN_MAP_MODE_JPG_PLAY:
-
-			dprintk(3, KERN_INFO "%s: munmap(MJPEG)\n",
-				ZR_DEVNAME(zr));
-
-			for (i = 0; i < fh->jpg_buffers.num_buffers; i++) {
-				if (fh->jpg_buffers.buffer[i].map == map) {
-					fh->jpg_buffers.buffer[i].map =
-					    NULL;
-				}
-			}
-			kfree(map);
-
-			for (i = 0; i < fh->jpg_buffers.num_buffers; i++)
-				if (fh->jpg_buffers.buffer[i].map)
-					break;
-			if (i == fh->jpg_buffers.num_buffers) {
-				mutex_lock(&zr->resource_lock);
-
-				if (fh->jpg_buffers.active != ZORAN_FREE) {
-					jpg_qbuf(file, -1, zr->codec_mode);
-					zr->jpg_buffers.allocated = 0;
-					zr->jpg_buffers.active =
-					    fh->jpg_buffers.active =
-					    ZORAN_FREE;
-				}
-				//jpg_fbuffer_free(file);
-				fh->jpg_buffers.allocated = 0;
-				fh->jpg_buffers.ready_to_be_freed = 1;
-
-				mutex_unlock(&zr->resource_lock);
-			}
-
-			break;
-
-		case ZORAN_MAP_MODE_RAW:
-
-			dprintk(3, KERN_INFO "%s: munmap(V4L)\n",
-				ZR_DEVNAME(zr));
-
-			for (i = 0; i < fh->v4l_buffers.num_buffers; i++) {
-				if (fh->v4l_buffers.buffer[i].map == map) {
-					/* unqueue/unmap */
-					fh->v4l_buffers.buffer[i].map =
-					    NULL;
-				}
-			}
-			kfree(map);
-
-			for (i = 0; i < fh->v4l_buffers.num_buffers; i++)
-				if (fh->v4l_buffers.buffer[i].map)
-					break;
-			if (i == fh->v4l_buffers.num_buffers) {
-				mutex_lock(&zr->resource_lock);
-
-				if (fh->v4l_buffers.active != ZORAN_FREE) {
-					unsigned long flags;
-
-					spin_lock_irqsave(&zr->spinlock, flags);
-					zr36057_set_memgrab(zr, 0);
-					zr->v4l_buffers.allocated = 0;
-					zr->v4l_buffers.active =
-					    fh->v4l_buffers.active =
-					    ZORAN_FREE;
-					spin_unlock_irqrestore(&zr->spinlock, flags);
-				}
-				//v4l_fbuffer_free(file);
-				fh->v4l_buffers.allocated = 0;
-				fh->v4l_buffers.ready_to_be_freed = 1;
-
-				mutex_unlock(&zr->resource_lock);
-			}
-
-			break;
-
-		default:
-			printk(KERN_ERR
-			       "%s: munmap() - internal error - unknown map mode %d\n",
-			       ZR_DEVNAME(zr), fh->map_mode);
-			break;
-
-		}
-	}
-}
-
-static struct vm_operations_struct zoran_vm_ops = {
-	.open = zoran_vm_open,
-	.close = zoran_vm_close,
-};
-
-static int
-zoran_mmap (struct file           *file,
-	    struct vm_area_struct *vma)
-{
-	struct zoran_fh *fh = file->private_data;
-	struct zoran *zr = fh->zr;
-	unsigned long size = (vma->vm_end - vma->vm_start);
-	unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
-	int i, j;
-	unsigned long page, start = vma->vm_start, todo, pos, fraglen;
-	int first, last;
-	struct zoran_mapping *map;
-	int res = 0;
-
-	dprintk(3,
-		KERN_INFO "%s: mmap(%s) of 0x%08lx-0x%08lx (size=%lu)\n",
-		ZR_DEVNAME(zr),
-		fh->map_mode == ZORAN_MAP_MODE_RAW ? "V4L" : "MJPEG",
-		vma->vm_start, vma->vm_end, size);
-
-	if (!(vma->vm_flags & VM_SHARED) || !(vma->vm_flags & VM_READ) ||
-	    !(vma->vm_flags & VM_WRITE)) {
-		dprintk(1,
-			KERN_ERR
-			"%s: mmap() - no MAP_SHARED/PROT_{READ,WRITE} given\n",
-			ZR_DEVNAME(zr));
-		return -EINVAL;
-	}
-
-	switch (fh->map_mode) {
-
-	case ZORAN_MAP_MODE_JPG_REC:
-	case ZORAN_MAP_MODE_JPG_PLAY:
-
-		/* lock */
-		mutex_lock(&zr->resource_lock);
-
-		/* Map the MJPEG buffers */
-		if (!fh->jpg_buffers.allocated) {
-			dprintk(1,
-				KERN_ERR
-				"%s: zoran_mmap(MJPEG) - buffers not yet allocated\n",
-				ZR_DEVNAME(zr));
-			res = -ENOMEM;
-			goto jpg_mmap_unlock_and_return;
-		}
-
-		first = offset / fh->jpg_buffers.buffer_size;
-		last = first - 1 + size / fh->jpg_buffers.buffer_size;
-		if (offset % fh->jpg_buffers.buffer_size != 0 ||
-		    size % fh->jpg_buffers.buffer_size != 0 || first < 0 ||
-		    last < 0 || first >= fh->jpg_buffers.num_buffers ||
-		    last >= fh->jpg_buffers.num_buffers) {
-			dprintk(1,
-				KERN_ERR
-				"%s: mmap(MJPEG) - offset=%lu or size=%lu invalid for bufsize=%d and numbufs=%d\n",
-				ZR_DEVNAME(zr), offset, size,
-				fh->jpg_buffers.buffer_size,
-				fh->jpg_buffers.num_buffers);
-			res = -EINVAL;
-			goto jpg_mmap_unlock_and_return;
-		}
-		for (i = first; i <= last; i++) {
-			if (fh->jpg_buffers.buffer[i].map) {
-				dprintk(1,
-					KERN_ERR
-					"%s: mmap(MJPEG) - buffer %d already mapped\n",
-					ZR_DEVNAME(zr), i);
-				res = -EBUSY;
-				goto jpg_mmap_unlock_and_return;
-			}
-		}
-
-		/* map these buffers (v4l_buffers[i]) */
-		map = kmalloc(sizeof(struct zoran_mapping), GFP_KERNEL);
-		if (!map) {
-			res = -ENOMEM;
-			goto jpg_mmap_unlock_and_return;
-		}
-		map->file = file;
-		map->count = 1;
-
-		vma->vm_ops = &zoran_vm_ops;
-		vma->vm_flags |= VM_DONTEXPAND;
-		vma->vm_private_data = map;
-
-		for (i = first; i <= last; i++) {
-			for (j = 0;
-			     j < fh->jpg_buffers.buffer_size / PAGE_SIZE;
-			     j++) {
-				fraglen =
-				    (le32_to_cpu(fh->jpg_buffers.buffer[i].
-				     frag_tab[2 * j + 1]) & ~1) << 1;
-				todo = size;
-				if (todo > fraglen)
-					todo = fraglen;
-				pos =
-				    le32_to_cpu(fh->jpg_buffers.
-				    buffer[i].frag_tab[2 * j]);
-				/* should just be pos on i386 */
-				page = virt_to_phys(bus_to_virt(pos))
-								>> PAGE_SHIFT;
-				if (remap_pfn_range(vma, start, page,
-							todo, PAGE_SHARED)) {
-					dprintk(1,
-						KERN_ERR
-						"%s: zoran_mmap(V4L) - remap_pfn_range failed\n",
-						ZR_DEVNAME(zr));
-					res = -EAGAIN;
-					goto jpg_mmap_unlock_and_return;
-				}
-				size -= todo;
-				start += todo;
-				if (size == 0)
-					break;
-				if (le32_to_cpu(fh->jpg_buffers.buffer[i].
-				    frag_tab[2 * j + 1]) & 1)
-					break;	/* was last fragment */
-			}
-			fh->jpg_buffers.buffer[i].map = map;
-			if (size == 0)
-				break;
-
-		}
-	jpg_mmap_unlock_and_return:
-		mutex_unlock(&zr->resource_lock);
-
-		break;
-
-	case ZORAN_MAP_MODE_RAW:
-
-		mutex_lock(&zr->resource_lock);
-
-		/* Map the V4L buffers */
-		if (!fh->v4l_buffers.allocated) {
-			dprintk(1,
-				KERN_ERR
-				"%s: zoran_mmap(V4L) - buffers not yet allocated\n",
-				ZR_DEVNAME(zr));
-			res = -ENOMEM;
-			goto v4l_mmap_unlock_and_return;
-		}
-
-		first = offset / fh->v4l_buffers.buffer_size;
-		last = first - 1 + size / fh->v4l_buffers.buffer_size;
-		if (offset % fh->v4l_buffers.buffer_size != 0 ||
-		    size % fh->v4l_buffers.buffer_size != 0 || first < 0 ||
-		    last < 0 || first >= fh->v4l_buffers.num_buffers ||
-		    last >= fh->v4l_buffers.buffer_size) {
-			dprintk(1,
-				KERN_ERR
-				"%s: mmap(V4L) - offset=%lu or size=%lu invalid for bufsize=%d and numbufs=%d\n",
-				ZR_DEVNAME(zr), offset, size,
-				fh->v4l_buffers.buffer_size,
-				fh->v4l_buffers.num_buffers);
-			res = -EINVAL;
-			goto v4l_mmap_unlock_and_return;
-		}
-		for (i = first; i <= last; i++) {
-			if (fh->v4l_buffers.buffer[i].map) {
-				dprintk(1,
-					KERN_ERR
-					"%s: mmap(V4L) - buffer %d already mapped\n",
-					ZR_DEVNAME(zr), i);
-				res = -EBUSY;
-				goto v4l_mmap_unlock_and_return;
-			}
-		}
-
-		/* map these buffers (v4l_buffers[i]) */
-		map = kmalloc(sizeof(struct zoran_mapping), GFP_KERNEL);
-		if (!map) {
-			res = -ENOMEM;
-			goto v4l_mmap_unlock_and_return;
-		}
-		map->file = file;
-		map->count = 1;
-
-		vma->vm_ops = &zoran_vm_ops;
-		vma->vm_flags |= VM_DONTEXPAND;
-		vma->vm_private_data = map;
-
-		for (i = first; i <= last; i++) {
-			todo = size;
-			if (todo > fh->v4l_buffers.buffer_size)
-				todo = fh->v4l_buffers.buffer_size;
-			page = fh->v4l_buffers.buffer[i].fbuffer_phys;
-			if (remap_pfn_range(vma, start, page >> PAGE_SHIFT,
-							todo, PAGE_SHARED)) {
-				dprintk(1,
-					KERN_ERR
-					"%s: zoran_mmap(V4L)i - remap_pfn_range failed\n",
-					ZR_DEVNAME(zr));
-				res = -EAGAIN;
-				goto v4l_mmap_unlock_and_return;
-			}
-			size -= todo;
-			start += todo;
-			fh->v4l_buffers.buffer[i].map = map;
-			if (size == 0)
-				break;
-		}
-	v4l_mmap_unlock_and_return:
-		mutex_unlock(&zr->resource_lock);
-
-		break;
-
-	default:
-		dprintk(1,
-			KERN_ERR
-			"%s: zoran_mmap() - internal error - unknown map mode %d\n",
-			ZR_DEVNAME(zr), fh->map_mode);
-		break;
-	}
-
-	return 0;
-}
-
-static const struct file_operations zoran_fops = {
-	.owner = THIS_MODULE,
-	.open = zoran_open,
-	.release = zoran_close,
-	.ioctl = zoran_ioctl,
-#ifdef CONFIG_COMPAT
-	.compat_ioctl	= v4l_compat_ioctl32,
-#endif
-	.llseek = no_llseek,
-	.read = zoran_read,
-	.write = zoran_write,
-	.mmap = zoran_mmap,
-	.poll = zoran_poll,
-};
-
-struct video_device zoran_template __devinitdata = {
-	.name = ZORAN_NAME,
-	.fops = &zoran_fops,
-	.release = &zoran_vdev_release,
-	.minor = -1
-};
-
diff --git a/drivers/media/video/zr364xx.c b/drivers/media/video/zr364xx.c
index 18d1c4b..7cdac99 100644
--- a/drivers/media/video/zr364xx.c
+++ b/drivers/media/video/zr364xx.c
@@ -52,7 +52,7 @@
 
 
 /* Debug macro */
-#define DBG(x...) if (debug) info(x)
+#define DBG(x...) if (debug) printk(KERN_INFO KBUILD_MODNAME x)
 
 
 /* Init methods, need to find nicer names for these
@@ -116,6 +116,7 @@
 	int height;
 	int method;
 	struct mutex lock;
+	int users;
 };
 
 
@@ -127,7 +128,7 @@
 
 	unsigned char *transfer_buffer = kmalloc(size, GFP_KERNEL);
 	if (!transfer_buffer) {
-		info("kmalloc(%d) failed", size);
+		dev_err(&udev->dev, "kmalloc(%d) failed\n", size);
 		return -ENOMEM;
 	}
 
@@ -143,7 +144,8 @@
 	kfree(transfer_buffer);
 
 	if (status < 0)
-		info("Failed sending control message, error %d.", status);
+		dev_err(&udev->dev,
+			"Failed sending control message, error %d.\n", status);
 
 	return status;
 }
@@ -303,11 +305,11 @@
 		DBG("buffer : %d %d", cam->buffer[0], cam->buffer[1]);
 		DBG("bulk : n=%d size=%d", n, actual_length);
 		if (n < 0) {
-			info("error reading bulk msg");
+			dev_err(&cam->udev->dev, "error reading bulk msg\n");
 			return 0;
 		}
 		if (actual_length < 0 || actual_length > BUFFER_SIZE) {
-			info("wrong number of bytes");
+			dev_err(&cam->udev->dev, "wrong number of bytes\n");
 			return 0;
 		}
 
@@ -641,42 +643,47 @@
 
 	DBG("zr364xx_open");
 
-	cam->skip = 2;
+	mutex_lock(&cam->lock);
 
-	err = video_exclusive_open(inode, file);
-	if (err < 0)
-		return err;
+	if (cam->users) {
+		err = -EBUSY;
+		goto out;
+	}
 
 	if (!cam->framebuf) {
 		cam->framebuf = vmalloc_32(MAX_FRAME_SIZE * FRAMES);
 		if (!cam->framebuf) {
-			info("vmalloc_32 failed!");
-			return -ENOMEM;
+			dev_err(&cam->udev->dev, "vmalloc_32 failed!\n");
+			err = -ENOMEM;
+			goto out;
 		}
 	}
 
-	mutex_lock(&cam->lock);
 	for (i = 0; init[cam->method][i].size != -1; i++) {
 		err =
 		    send_control_msg(udev, 1, init[cam->method][i].value,
 				     0, init[cam->method][i].bytes,
 				     init[cam->method][i].size);
 		if (err < 0) {
-			info("error during open sequence: %d", i);
-			mutex_unlock(&cam->lock);
-			return err;
+			dev_err(&cam->udev->dev,
+				"error during open sequence: %d\n", i);
+			goto out;
 		}
 	}
 
+	cam->skip = 2;
+	cam->users++;
 	file->private_data = vdev;
 
 	/* Added some delay here, since opening/closing the camera quickly,
 	 * like Ekiga does during its startup, can crash the webcam
 	 */
 	mdelay(100);
+	err = 0;
 
+out:
 	mutex_unlock(&cam->lock);
-	return 0;
+	return err;
 }
 
 
@@ -697,28 +704,30 @@
 	udev = cam->udev;
 
 	mutex_lock(&cam->lock);
+
+	cam->users--;
+	file->private_data = NULL;
+
 	for (i = 0; i < 2; i++) {
 		err =
 		    send_control_msg(udev, 1, init[cam->method][i].value,
 				     0, init[i][cam->method].bytes,
 				     init[cam->method][i].size);
 		if (err < 0) {
-			info("error during release sequence");
-			mutex_unlock(&cam->lock);
-			return err;
+			dev_err(&udev->dev, "error during release sequence\n");
+			goto out;
 		}
 	}
 
-	file->private_data = NULL;
-	video_exclusive_release(inode, file);
-
 	/* Added some delay here, since opening/closing the camera quickly,
 	 * like Ekiga does during its startup, can crash the webcam
 	 */
 	mdelay(100);
+	err = 0;
 
+out:
 	mutex_unlock(&cam->lock);
-	return 0;
+	return err;
 }
 
 
@@ -801,13 +810,14 @@
 
 	DBG("probing...");
 
-	info(DRIVER_DESC " compatible webcam plugged");
-	info("model %04x:%04x detected", udev->descriptor.idVendor,
-	     udev->descriptor.idProduct);
+	dev_info(&intf->dev, DRIVER_DESC " compatible webcam plugged\n");
+	dev_info(&intf->dev, "model %04x:%04x detected\n",
+		 le16_to_cpu(udev->descriptor.idVendor),
+		 le16_to_cpu(udev->descriptor.idProduct));
 
 	cam = kzalloc(sizeof(struct zr364xx_camera), GFP_KERNEL);
 	if (cam == NULL) {
-		info("cam: out of memory !");
+		dev_err(&udev->dev, "cam: out of memory !\n");
 		return -ENOMEM;
 	}
 	/* save the init method used by this camera */
@@ -815,7 +825,7 @@
 
 	cam->vdev = video_device_alloc();
 	if (cam->vdev == NULL) {
-		info("cam->vdev: out of memory !");
+		dev_err(&udev->dev, "cam->vdev: out of memory !\n");
 		kfree(cam);
 		return -ENOMEM;
 	}
@@ -827,7 +837,7 @@
 	cam->udev = udev;
 
 	if ((cam->buffer = kmalloc(BUFFER_SIZE, GFP_KERNEL)) == NULL) {
-		info("cam->buffer: out of memory !");
+		dev_info(&udev->dev, "cam->buffer: out of memory !\n");
 		video_device_release(cam->vdev);
 		kfree(cam);
 		return -ENODEV;
@@ -835,17 +845,17 @@
 
 	switch (mode) {
 	case 1:
-		info("160x120 mode selected");
+		dev_info(&udev->dev, "160x120 mode selected\n");
 		cam->width = 160;
 		cam->height = 120;
 		break;
 	case 2:
-		info("640x480 mode selected");
+		dev_info(&udev->dev, "640x480 mode selected\n");
 		cam->width = 640;
 		cam->height = 480;
 		break;
 	default:
-		info("320x240 mode selected");
+		dev_info(&udev->dev, "320x240 mode selected\n");
 		cam->width = 320;
 		cam->height = 240;
 		break;
@@ -865,7 +875,7 @@
 
 	err = video_register_device(cam->vdev, VFL_TYPE_GRABBER, -1);
 	if (err) {
-		info("video_register_device failed");
+		dev_err(&udev->dev, "video_register_device failed\n");
 		video_device_release(cam->vdev);
 		kfree(cam->buffer);
 		kfree(cam);
@@ -874,7 +884,8 @@
 
 	usb_set_intfdata(intf, cam);
 
-	info(DRIVER_DESC " controlling video device %d", cam->vdev->minor);
+	dev_info(&udev->dev, DRIVER_DESC " controlling video device %d\n",
+		 cam->vdev->minor);
 	return 0;
 }
 
@@ -884,7 +895,7 @@
 	struct zr364xx_camera *cam = usb_get_intfdata(intf);
 	usb_set_intfdata(intf, NULL);
 	dev_set_drvdata(&intf->dev, NULL);
-	info(DRIVER_DESC " webcam unplugged");
+	dev_info(&intf->dev, DRIVER_DESC " webcam unplugged\n");
 	if (cam->vdev)
 		video_unregister_device(cam->vdev);
 	cam->vdev = NULL;
@@ -913,16 +924,16 @@
 	int retval;
 	retval = usb_register(&zr364xx_driver);
 	if (retval)
-		info("usb_register failed!");
+		printk(KERN_ERR KBUILD_MODNAME ": usb_register failed!\n");
 	else
-		info(DRIVER_DESC " module loaded");
+		printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_DESC "\n");
 	return retval;
 }
 
 
 static void __exit zr364xx_exit(void)
 {
-	info(DRIVER_DESC " module unloaded");
+	printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_DESC " module unloaded\n");
 	usb_deregister(&zr364xx_driver);
 }
 
diff --git a/drivers/memstick/core/mspro_block.c b/drivers/memstick/core/mspro_block.c
index d2d2318..6e291bf 100644
--- a/drivers/memstick/core/mspro_block.c
+++ b/drivers/memstick/core/mspro_block.c
@@ -197,7 +197,7 @@
 static int mspro_block_disk_release(struct gendisk *disk)
 {
 	struct mspro_block_data *msb = disk->private_data;
-	int disk_id = disk->first_minor >> MSPRO_BLOCK_PART_SHIFT;
+	int disk_id = MINOR(disk_devt(disk)) >> MSPRO_BLOCK_PART_SHIFT;
 
 	mutex_lock(&mspro_block_disk_lock);
 
@@ -828,7 +828,7 @@
 
 	if (msb->eject) {
 		while ((req = elv_next_request(q)) != NULL)
-			end_queued_request(req, -ENODEV);
+			__blk_end_request(req, -ENODEV, blk_rq_bytes(req));
 
 		return;
 	}
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 10c44d3..5eff8ad 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -21,7 +21,7 @@
 
 config MFD_SM501_GPIO
 	bool "Export GPIO via GPIO layer"
-	depends on MFD_SM501 && HAVE_GPIO_LIB
+	depends on MFD_SM501 && GPIOLIB
 	 ---help---
 	 This option uses the gpio library layer to export the 64 GPIO
 	 lines on the SM501. The platform data is used to supply the
@@ -29,7 +29,7 @@
 
 config MFD_ASIC3
 	bool "Support for Compaq ASIC3"
-	depends on GENERIC_HARDIRQS && HAVE_GPIO_LIB && ARM
+	depends on GENERIC_HARDIRQS && GPIOLIB && ARM
 	 ---help---
 	  This driver supports the ASIC3 multifunction chip found on many
 	  PDAs (mainly iPAQ and HTC based ones)
@@ -50,6 +50,15 @@
 	  HTC Magician devices, respectively. Actual functionality is
 	  handled by the leds-pasic3 and ds1wm drivers.
 
+config UCB1400_CORE
+	tristate "Philips UCB1400 Core driver"
+	help
+	  This enables support for the Philips UCB1400 core functions.
+	  The UCB1400 is an AC97 audio codec.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called ucb1400_core.
+
 config MFD_TMIO
 	bool
 	default n
@@ -78,6 +87,44 @@
 	help
 	  Support for Toshiba Mobile IO Controller TC6393XB
 
+config MFD_WM8400
+	tristate "Support Wolfson Microelectronics WM8400"
+	help
+	  Support for the Wolfson Microelecronics WM8400 PMIC and audio
+	  CODEC.  This driver adds provides common support for accessing
+	  the device, additional drivers must be enabled in order to use
+	  the functionality of the device.
+
+config MFD_WM8350
+	tristate
+
+config MFD_WM8350_CONFIG_MODE_0
+	bool
+	depends on MFD_WM8350
+
+config MFD_WM8350_CONFIG_MODE_1
+	bool
+	depends on MFD_WM8350
+
+config MFD_WM8350_CONFIG_MODE_2
+	bool
+	depends on MFD_WM8350
+
+config MFD_WM8350_CONFIG_MODE_3
+	bool
+	depends on MFD_WM8350
+
+config MFD_WM8350_I2C
+	tristate "Support Wolfson Microelectronics WM8350 with I2C"
+	select MFD_WM8350
+	depends on I2C
+	help
+	  The WM8350 is an integrated audio and power management
+	  subsystem with watchdog and RTC functionality for embedded
+	  systems.  This option enables core support for the WM8350 with
+	  I2C as the control interface.  Additional options must be
+	  selected to enable support for the functionality of the chip.
+
 endmenu
 
 menu "Multimedia Capabilities Port drivers"
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index 03ad239..759b1fe 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -12,6 +12,11 @@
 obj-$(CONFIG_MFD_TC6387XB)	+= tc6387xb.o
 obj-$(CONFIG_MFD_TC6393XB)	+= tc6393xb.o
 
+obj-$(CONFIG_MFD_WM8400)	+= wm8400-core.o
+wm8350-objs			:= wm8350-core.o wm8350-regmap.o wm8350-gpio.o
+obj-$(CONFIG_MFD_WM8350)	+= wm8350.o
+obj-$(CONFIG_MFD_WM8350_I2C)	+= wm8350-i2c.o
+
 obj-$(CONFIG_MFD_CORE)		+= mfd-core.o
 
 obj-$(CONFIG_MCP)		+= mcp-core.o
@@ -22,3 +27,4 @@
 ifeq ($(CONFIG_SA1100_ASSABET),y)
 obj-$(CONFIG_MCP_UCB1200)	+= ucb1x00-assabet.o
 endif
+obj-$(CONFIG_UCB1400_CORE)	+= ucb1400_core.o
diff --git a/drivers/mfd/asic3.c b/drivers/mfd/asic3.c
index bc2a807..ba5aa20 100644
--- a/drivers/mfd/asic3.c
+++ b/drivers/mfd/asic3.c
@@ -312,7 +312,6 @@
 	struct asic3 *asic = platform_get_drvdata(pdev);
 	unsigned long clksel = 0;
 	unsigned int irq, irq_base;
-	int map_size;
 	int ret;
 
 	ret = platform_get_irq(pdev, 0);
@@ -534,6 +533,7 @@
 	struct asic3 *asic;
 	struct resource *mem;
 	unsigned long clksel;
+	int map_size;
 	int ret = 0;
 
 	asic = kzalloc(sizeof(struct asic3), GFP_KERNEL);
diff --git a/drivers/mfd/ucb1400_core.c b/drivers/mfd/ucb1400_core.c
new file mode 100644
index 0000000..178159e
--- /dev/null
+++ b/drivers/mfd/ucb1400_core.c
@@ -0,0 +1,106 @@
+/*
+ * Core functions for:
+ *  Philips UCB1400 multifunction chip
+ *
+ * Based on ucb1400_ts.c:
+ *  Author:	Nicolas Pitre
+ *  Created:	September 25, 2006
+ *  Copyright:	MontaVista Software, Inc.
+ *
+ * Spliting done by: Marek Vasut <marek.vasut@gmail.com>
+ * If something doesnt work and it worked before spliting, e-mail me,
+ * dont bother Nicolas please ;-)
+ *
+ * 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 code is heavily based on ucb1x00-*.c copyrighted by Russell King
+ * covering the UCB1100, UCB1200 and UCB1300..  Support for the UCB1400 has
+ * been made separate from ucb1x00-core/ucb1x00-ts on Russell's request.
+ */
+
+#include <linux/module.h>
+#include <linux/ucb1400.h>
+
+static int ucb1400_core_probe(struct device *dev)
+{
+	int err;
+	struct ucb1400 *ucb;
+	struct ucb1400_ts ucb_ts;
+	struct snd_ac97 *ac97;
+
+	memset(&ucb_ts, 0, sizeof(ucb_ts));
+
+	ucb = kzalloc(sizeof(struct ucb1400), GFP_KERNEL);
+	if (!ucb) {
+		err = -ENOMEM;
+		goto err;
+	}
+
+	dev_set_drvdata(dev, ucb);
+
+	ac97 = to_ac97_t(dev);
+
+	ucb_ts.id = ucb1400_reg_read(ac97, UCB_ID);
+	if (ucb_ts.id != UCB_ID_1400) {
+		err = -ENODEV;
+		goto err0;
+	}
+
+	/* TOUCHSCREEN */
+	ucb_ts.ac97 = ac97;
+	ucb->ucb1400_ts = platform_device_alloc("ucb1400_ts", -1);
+	if (!ucb->ucb1400_ts) {
+		err = -ENOMEM;
+		goto err0;
+	}
+	err = platform_device_add_data(ucb->ucb1400_ts, &ucb_ts,
+					sizeof(ucb_ts));
+	if (err)
+		goto err1;
+	err = platform_device_add(ucb->ucb1400_ts);
+	if (err)
+		goto err1;
+
+	return 0;
+
+err1:
+	platform_device_put(ucb->ucb1400_ts);
+err0:
+	kfree(ucb);
+err:
+	return err;
+}
+
+static int ucb1400_core_remove(struct device *dev)
+{
+	struct ucb1400 *ucb = dev_get_drvdata(dev);
+
+	platform_device_unregister(ucb->ucb1400_ts);
+	kfree(ucb);
+	return 0;
+}
+
+static struct device_driver ucb1400_core_driver = {
+	.name	= "ucb1400_core",
+	.bus	= &ac97_bus_type,
+	.probe	= ucb1400_core_probe,
+	.remove	= ucb1400_core_remove,
+};
+
+static int __init ucb1400_core_init(void)
+{
+	return driver_register(&ucb1400_core_driver);
+}
+
+static void __exit ucb1400_core_exit(void)
+{
+	driver_unregister(&ucb1400_core_driver);
+}
+
+module_init(ucb1400_core_init);
+module_exit(ucb1400_core_exit);
+
+MODULE_DESCRIPTION("Philips UCB1400 driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/wm8350-core.c b/drivers/mfd/wm8350-core.c
new file mode 100644
index 0000000..25a7a5d
--- /dev/null
+++ b/drivers/mfd/wm8350-core.c
@@ -0,0 +1,1273 @@
+/*
+ * wm8350-core.c  --  Device access for Wolfson WM8350
+ *
+ * Copyright 2007, 2008 Wolfson Microelectronics PLC.
+ *
+ * Author: Liam Girdwood, Mark Brown
+ *
+ *  This program is free software; you can redistribute  it and/or 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/module.h>
+#include <linux/init.h>
+#include <linux/bug.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/workqueue.h>
+
+#include <linux/mfd/wm8350/core.h>
+#include <linux/mfd/wm8350/audio.h>
+#include <linux/mfd/wm8350/comparator.h>
+#include <linux/mfd/wm8350/gpio.h>
+#include <linux/mfd/wm8350/pmic.h>
+#include <linux/mfd/wm8350/rtc.h>
+#include <linux/mfd/wm8350/supply.h>
+#include <linux/mfd/wm8350/wdt.h>
+
+#define WM8350_UNLOCK_KEY		0x0013
+#define WM8350_LOCK_KEY			0x0000
+
+#define WM8350_CLOCK_CONTROL_1		0x28
+#define WM8350_AIF_TEST			0x74
+
+/* debug */
+#define WM8350_BUS_DEBUG 0
+#if WM8350_BUS_DEBUG
+#define dump(regs, src) do { \
+	int i_; \
+	u16 *src_ = src; \
+	printk(KERN_DEBUG); \
+	for (i_ = 0; i_ < regs; i_++) \
+		printk(" 0x%4.4x", *src_++); \
+	printk("\n"); \
+} while (0);
+#else
+#define dump(bytes, src)
+#endif
+
+#define WM8350_LOCK_DEBUG 0
+#if WM8350_LOCK_DEBUG
+#define ldbg(format, arg...) printk(format, ## arg)
+#else
+#define ldbg(format, arg...)
+#endif
+
+/*
+ * WM8350 Device IO
+ */
+static DEFINE_MUTEX(io_mutex);
+static DEFINE_MUTEX(reg_lock_mutex);
+static DEFINE_MUTEX(auxadc_mutex);
+
+/* Perform a physical read from the device.
+ */
+static int wm8350_phys_read(struct wm8350 *wm8350, u8 reg, int num_regs,
+			    u16 *dest)
+{
+	int i, ret;
+	int bytes = num_regs * 2;
+
+	dev_dbg(wm8350->dev, "volatile read\n");
+	ret = wm8350->read_dev(wm8350, reg, bytes, (char *)dest);
+
+	for (i = reg; i < reg + num_regs; i++) {
+		/* Cache is CPU endian */
+		dest[i - reg] = be16_to_cpu(dest[i - reg]);
+
+		/* Satisfy non-volatile bits from cache */
+		dest[i - reg] &= wm8350_reg_io_map[i].vol;
+		dest[i - reg] |= wm8350->reg_cache[i];
+
+		/* Mask out non-readable bits */
+		dest[i - reg] &= wm8350_reg_io_map[i].readable;
+	}
+
+	dump(num_regs, dest);
+
+	return ret;
+}
+
+static int wm8350_read(struct wm8350 *wm8350, u8 reg, int num_regs, u16 *dest)
+{
+	int i;
+	int end = reg + num_regs;
+	int ret = 0;
+	int bytes = num_regs * 2;
+
+	if (wm8350->read_dev == NULL)
+		return -ENODEV;
+
+	if ((reg + num_regs - 1) > WM8350_MAX_REGISTER) {
+		dev_err(wm8350->dev, "invalid reg %x\n",
+			reg + num_regs - 1);
+		return -EINVAL;
+	}
+
+	dev_dbg(wm8350->dev,
+		"%s R%d(0x%2.2x) %d regs\n", __func__, reg, reg, num_regs);
+
+#if WM8350_BUS_DEBUG
+	/* we can _safely_ read any register, but warn if read not supported */
+	for (i = reg; i < end; i++) {
+		if (!wm8350_reg_io_map[i].readable)
+			dev_warn(wm8350->dev,
+				"reg R%d is not readable\n", i);
+	}
+#endif
+
+	/* if any volatile registers are required, then read back all */
+	for (i = reg; i < end; i++)
+		if (wm8350_reg_io_map[i].vol)
+			return wm8350_phys_read(wm8350, reg, num_regs, dest);
+
+	/* no volatiles, then cache is good */
+	dev_dbg(wm8350->dev, "cache read\n");
+	memcpy(dest, &wm8350->reg_cache[reg], bytes);
+	dump(num_regs, dest);
+	return ret;
+}
+
+static inline int is_reg_locked(struct wm8350 *wm8350, u8 reg)
+{
+	if (reg == WM8350_SECURITY ||
+	    wm8350->reg_cache[WM8350_SECURITY] == WM8350_UNLOCK_KEY)
+		return 0;
+
+	if ((reg == WM8350_GPIO_CONFIGURATION_I_O) ||
+	    (reg >= WM8350_GPIO_FUNCTION_SELECT_1 &&
+	     reg <= WM8350_GPIO_FUNCTION_SELECT_4) ||
+	    (reg >= WM8350_BATTERY_CHARGER_CONTROL_1 &&
+	     reg <= WM8350_BATTERY_CHARGER_CONTROL_3))
+		return 1;
+	return 0;
+}
+
+static int wm8350_write(struct wm8350 *wm8350, u8 reg, int num_regs, u16 *src)
+{
+	int i;
+	int end = reg + num_regs;
+	int bytes = num_regs * 2;
+
+	if (wm8350->write_dev == NULL)
+		return -ENODEV;
+
+	if ((reg + num_regs - 1) > WM8350_MAX_REGISTER) {
+		dev_err(wm8350->dev, "invalid reg %x\n",
+			reg + num_regs - 1);
+		return -EINVAL;
+	}
+
+	/* it's generally not a good idea to write to RO or locked registers */
+	for (i = reg; i < end; i++) {
+		if (!wm8350_reg_io_map[i].writable) {
+			dev_err(wm8350->dev,
+				"attempted write to read only reg R%d\n", i);
+			return -EINVAL;
+		}
+
+		if (is_reg_locked(wm8350, i)) {
+			dev_err(wm8350->dev,
+			       "attempted write to locked reg R%d\n", i);
+			return -EINVAL;
+		}
+
+		src[i - reg] &= wm8350_reg_io_map[i].writable;
+
+		wm8350->reg_cache[i] =
+			(wm8350->reg_cache[i] & ~wm8350_reg_io_map[i].writable)
+			| src[i - reg];
+
+		src[i - reg] = cpu_to_be16(src[i - reg]);
+	}
+
+	/* Actually write it out */
+	return wm8350->write_dev(wm8350, reg, bytes, (char *)src);
+}
+
+/*
+ * Safe read, modify, write methods
+ */
+int wm8350_clear_bits(struct wm8350 *wm8350, u16 reg, u16 mask)
+{
+	u16 data;
+	int err;
+
+	mutex_lock(&io_mutex);
+	err = wm8350_read(wm8350, reg, 1, &data);
+	if (err) {
+		dev_err(wm8350->dev, "read from reg R%d failed\n", reg);
+		goto out;
+	}
+
+	data &= ~mask;
+	err = wm8350_write(wm8350, reg, 1, &data);
+	if (err)
+		dev_err(wm8350->dev, "write to reg R%d failed\n", reg);
+out:
+	mutex_unlock(&io_mutex);
+	return err;
+}
+EXPORT_SYMBOL_GPL(wm8350_clear_bits);
+
+int wm8350_set_bits(struct wm8350 *wm8350, u16 reg, u16 mask)
+{
+	u16 data;
+	int err;
+
+	mutex_lock(&io_mutex);
+	err = wm8350_read(wm8350, reg, 1, &data);
+	if (err) {
+		dev_err(wm8350->dev, "read from reg R%d failed\n", reg);
+		goto out;
+	}
+
+	data |= mask;
+	err = wm8350_write(wm8350, reg, 1, &data);
+	if (err)
+		dev_err(wm8350->dev, "write to reg R%d failed\n", reg);
+out:
+	mutex_unlock(&io_mutex);
+	return err;
+}
+EXPORT_SYMBOL_GPL(wm8350_set_bits);
+
+u16 wm8350_reg_read(struct wm8350 *wm8350, int reg)
+{
+	u16 data;
+	int err;
+
+	mutex_lock(&io_mutex);
+	err = wm8350_read(wm8350, reg, 1, &data);
+	if (err)
+		dev_err(wm8350->dev, "read from reg R%d failed\n", reg);
+
+	mutex_unlock(&io_mutex);
+	return data;
+}
+EXPORT_SYMBOL_GPL(wm8350_reg_read);
+
+int wm8350_reg_write(struct wm8350 *wm8350, int reg, u16 val)
+{
+	int ret;
+	u16 data = val;
+
+	mutex_lock(&io_mutex);
+	ret = wm8350_write(wm8350, reg, 1, &data);
+	if (ret)
+		dev_err(wm8350->dev, "write to reg R%d failed\n", reg);
+	mutex_unlock(&io_mutex);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(wm8350_reg_write);
+
+int wm8350_block_read(struct wm8350 *wm8350, int start_reg, int regs,
+		      u16 *dest)
+{
+	int err = 0;
+
+	mutex_lock(&io_mutex);
+	err = wm8350_read(wm8350, start_reg, regs, dest);
+	if (err)
+		dev_err(wm8350->dev, "block read starting from R%d failed\n",
+			start_reg);
+	mutex_unlock(&io_mutex);
+	return err;
+}
+EXPORT_SYMBOL_GPL(wm8350_block_read);
+
+int wm8350_block_write(struct wm8350 *wm8350, int start_reg, int regs,
+		       u16 *src)
+{
+	int ret = 0;
+
+	mutex_lock(&io_mutex);
+	ret = wm8350_write(wm8350, start_reg, regs, src);
+	if (ret)
+		dev_err(wm8350->dev, "block write starting at R%d failed\n",
+			start_reg);
+	mutex_unlock(&io_mutex);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(wm8350_block_write);
+
+int wm8350_reg_lock(struct wm8350 *wm8350)
+{
+	u16 key = WM8350_LOCK_KEY;
+	int ret;
+
+	ldbg(__func__);
+	mutex_lock(&io_mutex);
+	ret = wm8350_write(wm8350, WM8350_SECURITY, 1, &key);
+	if (ret)
+		dev_err(wm8350->dev, "lock failed\n");
+	mutex_unlock(&io_mutex);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(wm8350_reg_lock);
+
+int wm8350_reg_unlock(struct wm8350 *wm8350)
+{
+	u16 key = WM8350_UNLOCK_KEY;
+	int ret;
+
+	ldbg(__func__);
+	mutex_lock(&io_mutex);
+	ret = wm8350_write(wm8350, WM8350_SECURITY, 1, &key);
+	if (ret)
+		dev_err(wm8350->dev, "unlock failed\n");
+	mutex_unlock(&io_mutex);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(wm8350_reg_unlock);
+
+static void wm8350_irq_call_handler(struct wm8350 *wm8350, int irq)
+{
+	mutex_lock(&wm8350->irq_mutex);
+
+	if (wm8350->irq[irq].handler)
+		wm8350->irq[irq].handler(wm8350, irq, wm8350->irq[irq].data);
+	else {
+		dev_err(wm8350->dev, "irq %d nobody cared. now masked.\n",
+			irq);
+		wm8350_mask_irq(wm8350, irq);
+	}
+
+	mutex_unlock(&wm8350->irq_mutex);
+}
+
+/*
+ * wm8350_irq_worker actually handles the interrupts.  Since all
+ * interrupts are clear on read the IRQ line will be reasserted and
+ * the physical IRQ will be handled again if another interrupt is
+ * asserted while we run - in the normal course of events this is a
+ * rare occurrence so we save I2C/SPI reads.
+ */
+static void wm8350_irq_worker(struct work_struct *work)
+{
+	struct wm8350 *wm8350 = container_of(work, struct wm8350, irq_work);
+	u16 level_one, status1, status2, comp;
+
+	/* TODO: Use block reads to improve performance? */
+	level_one = wm8350_reg_read(wm8350, WM8350_SYSTEM_INTERRUPTS)
+		& ~wm8350_reg_read(wm8350, WM8350_SYSTEM_INTERRUPTS_MASK);
+	status1 = wm8350_reg_read(wm8350, WM8350_INT_STATUS_1)
+		& ~wm8350_reg_read(wm8350, WM8350_INT_STATUS_1_MASK);
+	status2 = wm8350_reg_read(wm8350, WM8350_INT_STATUS_2)
+		& ~wm8350_reg_read(wm8350, WM8350_INT_STATUS_2_MASK);
+	comp = wm8350_reg_read(wm8350, WM8350_COMPARATOR_INT_STATUS)
+		& ~wm8350_reg_read(wm8350, WM8350_COMPARATOR_INT_STATUS_MASK);
+
+	/* over current */
+	if (level_one & WM8350_OC_INT) {
+		u16 oc;
+
+		oc = wm8350_reg_read(wm8350, WM8350_OVER_CURRENT_INT_STATUS);
+		oc &= ~wm8350_reg_read(wm8350,
+				       WM8350_OVER_CURRENT_INT_STATUS_MASK);
+
+		if (oc & WM8350_OC_LS_EINT)	/* limit switch */
+			wm8350_irq_call_handler(wm8350, WM8350_IRQ_OC_LS);
+	}
+
+	/* under voltage */
+	if (level_one & WM8350_UV_INT) {
+		u16 uv;
+
+		uv = wm8350_reg_read(wm8350, WM8350_UNDER_VOLTAGE_INT_STATUS);
+		uv &= ~wm8350_reg_read(wm8350,
+				       WM8350_UNDER_VOLTAGE_INT_STATUS_MASK);
+
+		if (uv & WM8350_UV_DC1_EINT)
+			wm8350_irq_call_handler(wm8350, WM8350_IRQ_UV_DC1);
+		if (uv & WM8350_UV_DC2_EINT)
+			wm8350_irq_call_handler(wm8350, WM8350_IRQ_UV_DC2);
+		if (uv & WM8350_UV_DC3_EINT)
+			wm8350_irq_call_handler(wm8350, WM8350_IRQ_UV_DC3);
+		if (uv & WM8350_UV_DC4_EINT)
+			wm8350_irq_call_handler(wm8350, WM8350_IRQ_UV_DC4);
+		if (uv & WM8350_UV_DC5_EINT)
+			wm8350_irq_call_handler(wm8350, WM8350_IRQ_UV_DC5);
+		if (uv & WM8350_UV_DC6_EINT)
+			wm8350_irq_call_handler(wm8350, WM8350_IRQ_UV_DC6);
+		if (uv & WM8350_UV_LDO1_EINT)
+			wm8350_irq_call_handler(wm8350, WM8350_IRQ_UV_LDO1);
+		if (uv & WM8350_UV_LDO2_EINT)
+			wm8350_irq_call_handler(wm8350, WM8350_IRQ_UV_LDO2);
+		if (uv & WM8350_UV_LDO3_EINT)
+			wm8350_irq_call_handler(wm8350, WM8350_IRQ_UV_LDO3);
+		if (uv & WM8350_UV_LDO4_EINT)
+			wm8350_irq_call_handler(wm8350, WM8350_IRQ_UV_LDO4);
+	}
+
+	/* charger, RTC */
+	if (status1) {
+		if (status1 & WM8350_CHG_BAT_HOT_EINT)
+			wm8350_irq_call_handler(wm8350,
+						WM8350_IRQ_CHG_BAT_HOT);
+		if (status1 & WM8350_CHG_BAT_COLD_EINT)
+			wm8350_irq_call_handler(wm8350,
+						WM8350_IRQ_CHG_BAT_COLD);
+		if (status1 & WM8350_CHG_BAT_FAIL_EINT)
+			wm8350_irq_call_handler(wm8350,
+						WM8350_IRQ_CHG_BAT_FAIL);
+		if (status1 & WM8350_CHG_TO_EINT)
+			wm8350_irq_call_handler(wm8350, WM8350_IRQ_CHG_TO);
+		if (status1 & WM8350_CHG_END_EINT)
+			wm8350_irq_call_handler(wm8350, WM8350_IRQ_CHG_END);
+		if (status1 & WM8350_CHG_START_EINT)
+			wm8350_irq_call_handler(wm8350, WM8350_IRQ_CHG_START);
+		if (status1 & WM8350_CHG_FAST_RDY_EINT)
+			wm8350_irq_call_handler(wm8350,
+						WM8350_IRQ_CHG_FAST_RDY);
+		if (status1 & WM8350_CHG_VBATT_LT_3P9_EINT)
+			wm8350_irq_call_handler(wm8350,
+						WM8350_IRQ_CHG_VBATT_LT_3P9);
+		if (status1 & WM8350_CHG_VBATT_LT_3P1_EINT)
+			wm8350_irq_call_handler(wm8350,
+						WM8350_IRQ_CHG_VBATT_LT_3P1);
+		if (status1 & WM8350_CHG_VBATT_LT_2P85_EINT)
+			wm8350_irq_call_handler(wm8350,
+						WM8350_IRQ_CHG_VBATT_LT_2P85);
+		if (status1 & WM8350_RTC_ALM_EINT)
+			wm8350_irq_call_handler(wm8350, WM8350_IRQ_RTC_ALM);
+		if (status1 & WM8350_RTC_SEC_EINT)
+			wm8350_irq_call_handler(wm8350, WM8350_IRQ_RTC_SEC);
+		if (status1 & WM8350_RTC_PER_EINT)
+			wm8350_irq_call_handler(wm8350, WM8350_IRQ_RTC_PER);
+	}
+
+	/* current sink, system, aux adc */
+	if (status2) {
+		if (status2 & WM8350_CS1_EINT)
+			wm8350_irq_call_handler(wm8350, WM8350_IRQ_CS1);
+		if (status2 & WM8350_CS2_EINT)
+			wm8350_irq_call_handler(wm8350, WM8350_IRQ_CS2);
+
+		if (status2 & WM8350_SYS_HYST_COMP_FAIL_EINT)
+			wm8350_irq_call_handler(wm8350,
+						WM8350_IRQ_SYS_HYST_COMP_FAIL);
+		if (status2 & WM8350_SYS_CHIP_GT115_EINT)
+			wm8350_irq_call_handler(wm8350,
+						WM8350_IRQ_SYS_CHIP_GT115);
+		if (status2 & WM8350_SYS_CHIP_GT140_EINT)
+			wm8350_irq_call_handler(wm8350,
+						WM8350_IRQ_SYS_CHIP_GT140);
+		if (status2 & WM8350_SYS_WDOG_TO_EINT)
+			wm8350_irq_call_handler(wm8350,
+						WM8350_IRQ_SYS_WDOG_TO);
+
+		if (status2 & WM8350_AUXADC_DATARDY_EINT)
+			wm8350_irq_call_handler(wm8350,
+						WM8350_IRQ_AUXADC_DATARDY);
+		if (status2 & WM8350_AUXADC_DCOMP4_EINT)
+			wm8350_irq_call_handler(wm8350,
+						WM8350_IRQ_AUXADC_DCOMP4);
+		if (status2 & WM8350_AUXADC_DCOMP3_EINT)
+			wm8350_irq_call_handler(wm8350,
+						WM8350_IRQ_AUXADC_DCOMP3);
+		if (status2 & WM8350_AUXADC_DCOMP2_EINT)
+			wm8350_irq_call_handler(wm8350,
+						WM8350_IRQ_AUXADC_DCOMP2);
+		if (status2 & WM8350_AUXADC_DCOMP1_EINT)
+			wm8350_irq_call_handler(wm8350,
+						WM8350_IRQ_AUXADC_DCOMP1);
+
+		if (status2 & WM8350_USB_LIMIT_EINT)
+			wm8350_irq_call_handler(wm8350, WM8350_IRQ_USB_LIMIT);
+	}
+
+	/* wake, codec, ext */
+	if (comp) {
+		if (comp & WM8350_WKUP_OFF_STATE_EINT)
+			wm8350_irq_call_handler(wm8350,
+						WM8350_IRQ_WKUP_OFF_STATE);
+		if (comp & WM8350_WKUP_HIB_STATE_EINT)
+			wm8350_irq_call_handler(wm8350,
+						WM8350_IRQ_WKUP_HIB_STATE);
+		if (comp & WM8350_WKUP_CONV_FAULT_EINT)
+			wm8350_irq_call_handler(wm8350,
+						WM8350_IRQ_WKUP_CONV_FAULT);
+		if (comp & WM8350_WKUP_WDOG_RST_EINT)
+			wm8350_irq_call_handler(wm8350,
+						WM8350_IRQ_WKUP_WDOG_RST);
+		if (comp & WM8350_WKUP_GP_PWR_ON_EINT)
+			wm8350_irq_call_handler(wm8350,
+						WM8350_IRQ_WKUP_GP_PWR_ON);
+		if (comp & WM8350_WKUP_ONKEY_EINT)
+			wm8350_irq_call_handler(wm8350, WM8350_IRQ_WKUP_ONKEY);
+		if (comp & WM8350_WKUP_GP_WAKEUP_EINT)
+			wm8350_irq_call_handler(wm8350,
+						WM8350_IRQ_WKUP_GP_WAKEUP);
+
+		if (comp & WM8350_CODEC_JCK_DET_L_EINT)
+			wm8350_irq_call_handler(wm8350,
+						WM8350_IRQ_CODEC_JCK_DET_L);
+		if (comp & WM8350_CODEC_JCK_DET_R_EINT)
+			wm8350_irq_call_handler(wm8350,
+						WM8350_IRQ_CODEC_JCK_DET_R);
+		if (comp & WM8350_CODEC_MICSCD_EINT)
+			wm8350_irq_call_handler(wm8350,
+						WM8350_IRQ_CODEC_MICSCD);
+		if (comp & WM8350_CODEC_MICD_EINT)
+			wm8350_irq_call_handler(wm8350, WM8350_IRQ_CODEC_MICD);
+
+		if (comp & WM8350_EXT_USB_FB_EINT)
+			wm8350_irq_call_handler(wm8350, WM8350_IRQ_EXT_USB_FB);
+		if (comp & WM8350_EXT_WALL_FB_EINT)
+			wm8350_irq_call_handler(wm8350,
+						WM8350_IRQ_EXT_WALL_FB);
+		if (comp & WM8350_EXT_BAT_FB_EINT)
+			wm8350_irq_call_handler(wm8350, WM8350_IRQ_EXT_BAT_FB);
+	}
+
+	if (level_one & WM8350_GP_INT) {
+		int i;
+		u16 gpio;
+
+		gpio = wm8350_reg_read(wm8350, WM8350_GPIO_INT_STATUS);
+		gpio &= ~wm8350_reg_read(wm8350,
+					 WM8350_GPIO_INT_STATUS_MASK);
+
+		for (i = 0; i < 12; i++) {
+			if (gpio & (1 << i))
+				wm8350_irq_call_handler(wm8350,
+							WM8350_IRQ_GPIO(i));
+		}
+	}
+
+	enable_irq(wm8350->chip_irq);
+}
+
+static irqreturn_t wm8350_irq(int irq, void *data)
+{
+	struct wm8350 *wm8350 = data;
+
+	disable_irq_nosync(irq);
+	schedule_work(&wm8350->irq_work);
+
+	return IRQ_HANDLED;
+}
+
+int wm8350_register_irq(struct wm8350 *wm8350, int irq,
+			void (*handler) (struct wm8350 *, int, void *),
+			void *data)
+{
+	if (irq < 0 || irq > WM8350_NUM_IRQ || !handler)
+		return -EINVAL;
+
+	if (wm8350->irq[irq].handler)
+		return -EBUSY;
+
+	mutex_lock(&wm8350->irq_mutex);
+	wm8350->irq[irq].handler = handler;
+	wm8350->irq[irq].data = data;
+	mutex_unlock(&wm8350->irq_mutex);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(wm8350_register_irq);
+
+int wm8350_free_irq(struct wm8350 *wm8350, int irq)
+{
+	if (irq < 0 || irq > WM8350_NUM_IRQ)
+		return -EINVAL;
+
+	mutex_lock(&wm8350->irq_mutex);
+	wm8350->irq[irq].handler = NULL;
+	mutex_unlock(&wm8350->irq_mutex);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(wm8350_free_irq);
+
+int wm8350_mask_irq(struct wm8350 *wm8350, int irq)
+{
+	switch (irq) {
+	case WM8350_IRQ_CHG_BAT_HOT:
+		return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK,
+				       WM8350_IM_CHG_BAT_HOT_EINT);
+	case WM8350_IRQ_CHG_BAT_COLD:
+		return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK,
+				       WM8350_IM_CHG_BAT_COLD_EINT);
+	case WM8350_IRQ_CHG_BAT_FAIL:
+		return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK,
+				       WM8350_IM_CHG_BAT_FAIL_EINT);
+	case WM8350_IRQ_CHG_TO:
+		return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK,
+				       WM8350_IM_CHG_TO_EINT);
+	case WM8350_IRQ_CHG_END:
+		return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK,
+				       WM8350_IM_CHG_END_EINT);
+	case WM8350_IRQ_CHG_START:
+		return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK,
+				       WM8350_IM_CHG_START_EINT);
+	case WM8350_IRQ_CHG_FAST_RDY:
+		return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK,
+				       WM8350_IM_CHG_FAST_RDY_EINT);
+	case WM8350_IRQ_RTC_PER:
+		return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK,
+				       WM8350_IM_RTC_PER_EINT);
+	case WM8350_IRQ_RTC_SEC:
+		return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK,
+				       WM8350_IM_RTC_SEC_EINT);
+	case WM8350_IRQ_RTC_ALM:
+		return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK,
+				       WM8350_IM_RTC_ALM_EINT);
+	case WM8350_IRQ_CHG_VBATT_LT_3P9:
+		return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK,
+				       WM8350_IM_CHG_VBATT_LT_3P9_EINT);
+	case WM8350_IRQ_CHG_VBATT_LT_3P1:
+		return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK,
+				       WM8350_IM_CHG_VBATT_LT_3P1_EINT);
+	case WM8350_IRQ_CHG_VBATT_LT_2P85:
+		return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK,
+				       WM8350_IM_CHG_VBATT_LT_2P85_EINT);
+	case WM8350_IRQ_CS1:
+		return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK,
+				       WM8350_IM_CS1_EINT);
+	case WM8350_IRQ_CS2:
+		return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK,
+				       WM8350_IM_CS2_EINT);
+	case WM8350_IRQ_USB_LIMIT:
+		return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK,
+				       WM8350_IM_USB_LIMIT_EINT);
+	case WM8350_IRQ_AUXADC_DATARDY:
+		return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK,
+				       WM8350_IM_AUXADC_DATARDY_EINT);
+	case WM8350_IRQ_AUXADC_DCOMP4:
+		return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK,
+				       WM8350_IM_AUXADC_DCOMP4_EINT);
+	case WM8350_IRQ_AUXADC_DCOMP3:
+		return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK,
+				       WM8350_IM_AUXADC_DCOMP3_EINT);
+	case WM8350_IRQ_AUXADC_DCOMP2:
+		return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK,
+				       WM8350_IM_AUXADC_DCOMP2_EINT);
+	case WM8350_IRQ_AUXADC_DCOMP1:
+		return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK,
+				       WM8350_IM_AUXADC_DCOMP1_EINT);
+	case WM8350_IRQ_SYS_HYST_COMP_FAIL:
+		return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK,
+				       WM8350_IM_SYS_HYST_COMP_FAIL_EINT);
+	case WM8350_IRQ_SYS_CHIP_GT115:
+		return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK,
+				       WM8350_IM_SYS_CHIP_GT115_EINT);
+	case WM8350_IRQ_SYS_CHIP_GT140:
+		return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK,
+				       WM8350_IM_SYS_CHIP_GT140_EINT);
+	case WM8350_IRQ_SYS_WDOG_TO:
+		return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK,
+				       WM8350_IM_SYS_WDOG_TO_EINT);
+	case WM8350_IRQ_UV_LDO4:
+		return wm8350_set_bits(wm8350,
+				       WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
+				       WM8350_IM_UV_LDO4_EINT);
+	case WM8350_IRQ_UV_LDO3:
+		return wm8350_set_bits(wm8350,
+				       WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
+				       WM8350_IM_UV_LDO3_EINT);
+	case WM8350_IRQ_UV_LDO2:
+		return wm8350_set_bits(wm8350,
+				       WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
+				       WM8350_IM_UV_LDO2_EINT);
+	case WM8350_IRQ_UV_LDO1:
+		return wm8350_set_bits(wm8350,
+				       WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
+				       WM8350_IM_UV_LDO1_EINT);
+	case WM8350_IRQ_UV_DC6:
+		return wm8350_set_bits(wm8350,
+				       WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
+				       WM8350_IM_UV_DC6_EINT);
+	case WM8350_IRQ_UV_DC5:
+		return wm8350_set_bits(wm8350,
+				       WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
+				       WM8350_IM_UV_DC5_EINT);
+	case WM8350_IRQ_UV_DC4:
+		return wm8350_set_bits(wm8350,
+				       WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
+				       WM8350_IM_UV_DC4_EINT);
+	case WM8350_IRQ_UV_DC3:
+		return wm8350_set_bits(wm8350,
+				       WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
+				       WM8350_IM_UV_DC3_EINT);
+	case WM8350_IRQ_UV_DC2:
+		return wm8350_set_bits(wm8350,
+				       WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
+				       WM8350_IM_UV_DC2_EINT);
+	case WM8350_IRQ_UV_DC1:
+		return wm8350_set_bits(wm8350,
+				       WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
+				       WM8350_IM_UV_DC1_EINT);
+	case WM8350_IRQ_OC_LS:
+		return wm8350_set_bits(wm8350,
+				       WM8350_OVER_CURRENT_INT_STATUS_MASK,
+				       WM8350_IM_OC_LS_EINT);
+	case WM8350_IRQ_EXT_USB_FB:
+		return wm8350_set_bits(wm8350,
+				       WM8350_COMPARATOR_INT_STATUS_MASK,
+				       WM8350_IM_EXT_USB_FB_EINT);
+	case WM8350_IRQ_EXT_WALL_FB:
+		return wm8350_set_bits(wm8350,
+				       WM8350_COMPARATOR_INT_STATUS_MASK,
+				       WM8350_IM_EXT_WALL_FB_EINT);
+	case WM8350_IRQ_EXT_BAT_FB:
+		return wm8350_set_bits(wm8350,
+				       WM8350_COMPARATOR_INT_STATUS_MASK,
+				       WM8350_IM_EXT_BAT_FB_EINT);
+	case WM8350_IRQ_CODEC_JCK_DET_L:
+		return wm8350_set_bits(wm8350,
+				       WM8350_COMPARATOR_INT_STATUS_MASK,
+				       WM8350_IM_CODEC_JCK_DET_L_EINT);
+	case WM8350_IRQ_CODEC_JCK_DET_R:
+		return wm8350_set_bits(wm8350,
+				       WM8350_COMPARATOR_INT_STATUS_MASK,
+				       WM8350_IM_CODEC_JCK_DET_R_EINT);
+	case WM8350_IRQ_CODEC_MICSCD:
+		return wm8350_set_bits(wm8350,
+				       WM8350_COMPARATOR_INT_STATUS_MASK,
+				       WM8350_IM_CODEC_MICSCD_EINT);
+	case WM8350_IRQ_CODEC_MICD:
+		return wm8350_set_bits(wm8350,
+				       WM8350_COMPARATOR_INT_STATUS_MASK,
+				       WM8350_IM_CODEC_MICD_EINT);
+	case WM8350_IRQ_WKUP_OFF_STATE:
+		return wm8350_set_bits(wm8350,
+				       WM8350_COMPARATOR_INT_STATUS_MASK,
+				       WM8350_IM_WKUP_OFF_STATE_EINT);
+	case WM8350_IRQ_WKUP_HIB_STATE:
+		return wm8350_set_bits(wm8350,
+				       WM8350_COMPARATOR_INT_STATUS_MASK,
+				       WM8350_IM_WKUP_HIB_STATE_EINT);
+	case WM8350_IRQ_WKUP_CONV_FAULT:
+		return wm8350_set_bits(wm8350,
+				       WM8350_COMPARATOR_INT_STATUS_MASK,
+				       WM8350_IM_WKUP_CONV_FAULT_EINT);
+	case WM8350_IRQ_WKUP_WDOG_RST:
+		return wm8350_set_bits(wm8350,
+				       WM8350_COMPARATOR_INT_STATUS_MASK,
+				       WM8350_IM_WKUP_OFF_STATE_EINT);
+	case WM8350_IRQ_WKUP_GP_PWR_ON:
+		return wm8350_set_bits(wm8350,
+				       WM8350_COMPARATOR_INT_STATUS_MASK,
+				       WM8350_IM_WKUP_GP_PWR_ON_EINT);
+	case WM8350_IRQ_WKUP_ONKEY:
+		return wm8350_set_bits(wm8350,
+				       WM8350_COMPARATOR_INT_STATUS_MASK,
+				       WM8350_IM_WKUP_ONKEY_EINT);
+	case WM8350_IRQ_WKUP_GP_WAKEUP:
+		return wm8350_set_bits(wm8350,
+				       WM8350_COMPARATOR_INT_STATUS_MASK,
+				       WM8350_IM_WKUP_GP_WAKEUP_EINT);
+	case WM8350_IRQ_GPIO(0):
+		return wm8350_set_bits(wm8350,
+				       WM8350_GPIO_INT_STATUS_MASK,
+				       WM8350_IM_GP0_EINT);
+	case WM8350_IRQ_GPIO(1):
+		return wm8350_set_bits(wm8350,
+				       WM8350_GPIO_INT_STATUS_MASK,
+				       WM8350_IM_GP1_EINT);
+	case WM8350_IRQ_GPIO(2):
+		return wm8350_set_bits(wm8350,
+				       WM8350_GPIO_INT_STATUS_MASK,
+				       WM8350_IM_GP2_EINT);
+	case WM8350_IRQ_GPIO(3):
+		return wm8350_set_bits(wm8350,
+				       WM8350_GPIO_INT_STATUS_MASK,
+				       WM8350_IM_GP3_EINT);
+	case WM8350_IRQ_GPIO(4):
+		return wm8350_set_bits(wm8350,
+				       WM8350_GPIO_INT_STATUS_MASK,
+				       WM8350_IM_GP4_EINT);
+	case WM8350_IRQ_GPIO(5):
+		return wm8350_set_bits(wm8350,
+				       WM8350_GPIO_INT_STATUS_MASK,
+				       WM8350_IM_GP5_EINT);
+	case WM8350_IRQ_GPIO(6):
+		return wm8350_set_bits(wm8350,
+				       WM8350_GPIO_INT_STATUS_MASK,
+				       WM8350_IM_GP6_EINT);
+	case WM8350_IRQ_GPIO(7):
+		return wm8350_set_bits(wm8350,
+				       WM8350_GPIO_INT_STATUS_MASK,
+				       WM8350_IM_GP7_EINT);
+	case WM8350_IRQ_GPIO(8):
+		return wm8350_set_bits(wm8350,
+				       WM8350_GPIO_INT_STATUS_MASK,
+				       WM8350_IM_GP8_EINT);
+	case WM8350_IRQ_GPIO(9):
+		return wm8350_set_bits(wm8350,
+				       WM8350_GPIO_INT_STATUS_MASK,
+				       WM8350_IM_GP9_EINT);
+	case WM8350_IRQ_GPIO(10):
+		return wm8350_set_bits(wm8350,
+				       WM8350_GPIO_INT_STATUS_MASK,
+				       WM8350_IM_GP10_EINT);
+	case WM8350_IRQ_GPIO(11):
+		return wm8350_set_bits(wm8350,
+				       WM8350_GPIO_INT_STATUS_MASK,
+				       WM8350_IM_GP11_EINT);
+	case WM8350_IRQ_GPIO(12):
+		return wm8350_set_bits(wm8350,
+				       WM8350_GPIO_INT_STATUS_MASK,
+				       WM8350_IM_GP12_EINT);
+	default:
+		dev_warn(wm8350->dev, "Attempting to mask unknown IRQ %d\n",
+			 irq);
+		return -EINVAL;
+	}
+	return 0;
+}
+EXPORT_SYMBOL_GPL(wm8350_mask_irq);
+
+int wm8350_unmask_irq(struct wm8350 *wm8350, int irq)
+{
+	switch (irq) {
+	case WM8350_IRQ_CHG_BAT_HOT:
+		return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK,
+					 WM8350_IM_CHG_BAT_HOT_EINT);
+	case WM8350_IRQ_CHG_BAT_COLD:
+		return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK,
+					 WM8350_IM_CHG_BAT_COLD_EINT);
+	case WM8350_IRQ_CHG_BAT_FAIL:
+		return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK,
+					 WM8350_IM_CHG_BAT_FAIL_EINT);
+	case WM8350_IRQ_CHG_TO:
+		return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK,
+					 WM8350_IM_CHG_TO_EINT);
+	case WM8350_IRQ_CHG_END:
+		return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK,
+					 WM8350_IM_CHG_END_EINT);
+	case WM8350_IRQ_CHG_START:
+		return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK,
+					 WM8350_IM_CHG_START_EINT);
+	case WM8350_IRQ_CHG_FAST_RDY:
+		return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK,
+					 WM8350_IM_CHG_FAST_RDY_EINT);
+	case WM8350_IRQ_RTC_PER:
+		return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK,
+					 WM8350_IM_RTC_PER_EINT);
+	case WM8350_IRQ_RTC_SEC:
+		return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK,
+					 WM8350_IM_RTC_SEC_EINT);
+	case WM8350_IRQ_RTC_ALM:
+		return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK,
+					 WM8350_IM_RTC_ALM_EINT);
+	case WM8350_IRQ_CHG_VBATT_LT_3P9:
+		return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK,
+					 WM8350_IM_CHG_VBATT_LT_3P9_EINT);
+	case WM8350_IRQ_CHG_VBATT_LT_3P1:
+		return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK,
+					 WM8350_IM_CHG_VBATT_LT_3P1_EINT);
+	case WM8350_IRQ_CHG_VBATT_LT_2P85:
+		return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK,
+					 WM8350_IM_CHG_VBATT_LT_2P85_EINT);
+	case WM8350_IRQ_CS1:
+		return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK,
+					 WM8350_IM_CS1_EINT);
+	case WM8350_IRQ_CS2:
+		return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK,
+					 WM8350_IM_CS2_EINT);
+	case WM8350_IRQ_USB_LIMIT:
+		return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK,
+					 WM8350_IM_USB_LIMIT_EINT);
+	case WM8350_IRQ_AUXADC_DATARDY:
+		return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK,
+					 WM8350_IM_AUXADC_DATARDY_EINT);
+	case WM8350_IRQ_AUXADC_DCOMP4:
+		return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK,
+					 WM8350_IM_AUXADC_DCOMP4_EINT);
+	case WM8350_IRQ_AUXADC_DCOMP3:
+		return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK,
+					 WM8350_IM_AUXADC_DCOMP3_EINT);
+	case WM8350_IRQ_AUXADC_DCOMP2:
+		return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK,
+					 WM8350_IM_AUXADC_DCOMP2_EINT);
+	case WM8350_IRQ_AUXADC_DCOMP1:
+		return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK,
+					 WM8350_IM_AUXADC_DCOMP1_EINT);
+	case WM8350_IRQ_SYS_HYST_COMP_FAIL:
+		return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK,
+					 WM8350_IM_SYS_HYST_COMP_FAIL_EINT);
+	case WM8350_IRQ_SYS_CHIP_GT115:
+		return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK,
+					 WM8350_IM_SYS_CHIP_GT115_EINT);
+	case WM8350_IRQ_SYS_CHIP_GT140:
+		return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK,
+					 WM8350_IM_SYS_CHIP_GT140_EINT);
+	case WM8350_IRQ_SYS_WDOG_TO:
+		return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK,
+					 WM8350_IM_SYS_WDOG_TO_EINT);
+	case WM8350_IRQ_UV_LDO4:
+		return wm8350_clear_bits(wm8350,
+					 WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
+					 WM8350_IM_UV_LDO4_EINT);
+	case WM8350_IRQ_UV_LDO3:
+		return wm8350_clear_bits(wm8350,
+					 WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
+					 WM8350_IM_UV_LDO3_EINT);
+	case WM8350_IRQ_UV_LDO2:
+		return wm8350_clear_bits(wm8350,
+					 WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
+					 WM8350_IM_UV_LDO2_EINT);
+	case WM8350_IRQ_UV_LDO1:
+		return wm8350_clear_bits(wm8350,
+					 WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
+					 WM8350_IM_UV_LDO1_EINT);
+	case WM8350_IRQ_UV_DC6:
+		return wm8350_clear_bits(wm8350,
+					 WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
+					 WM8350_IM_UV_DC6_EINT);
+	case WM8350_IRQ_UV_DC5:
+		return wm8350_clear_bits(wm8350,
+					 WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
+					 WM8350_IM_UV_DC5_EINT);
+	case WM8350_IRQ_UV_DC4:
+		return wm8350_clear_bits(wm8350,
+					 WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
+					 WM8350_IM_UV_DC4_EINT);
+	case WM8350_IRQ_UV_DC3:
+		return wm8350_clear_bits(wm8350,
+					 WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
+					 WM8350_IM_UV_DC3_EINT);
+	case WM8350_IRQ_UV_DC2:
+		return wm8350_clear_bits(wm8350,
+					 WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
+					 WM8350_IM_UV_DC2_EINT);
+	case WM8350_IRQ_UV_DC1:
+		return wm8350_clear_bits(wm8350,
+					 WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
+					 WM8350_IM_UV_DC1_EINT);
+	case WM8350_IRQ_OC_LS:
+		return wm8350_clear_bits(wm8350,
+					 WM8350_OVER_CURRENT_INT_STATUS_MASK,
+					 WM8350_IM_OC_LS_EINT);
+	case WM8350_IRQ_EXT_USB_FB:
+		return wm8350_clear_bits(wm8350,
+					 WM8350_COMPARATOR_INT_STATUS_MASK,
+					 WM8350_IM_EXT_USB_FB_EINT);
+	case WM8350_IRQ_EXT_WALL_FB:
+		return wm8350_clear_bits(wm8350,
+					 WM8350_COMPARATOR_INT_STATUS_MASK,
+					 WM8350_IM_EXT_WALL_FB_EINT);
+	case WM8350_IRQ_EXT_BAT_FB:
+		return wm8350_clear_bits(wm8350,
+					 WM8350_COMPARATOR_INT_STATUS_MASK,
+					 WM8350_IM_EXT_BAT_FB_EINT);
+	case WM8350_IRQ_CODEC_JCK_DET_L:
+		return wm8350_clear_bits(wm8350,
+					 WM8350_COMPARATOR_INT_STATUS_MASK,
+					 WM8350_IM_CODEC_JCK_DET_L_EINT);
+	case WM8350_IRQ_CODEC_JCK_DET_R:
+		return wm8350_clear_bits(wm8350,
+					 WM8350_COMPARATOR_INT_STATUS_MASK,
+					 WM8350_IM_CODEC_JCK_DET_R_EINT);
+	case WM8350_IRQ_CODEC_MICSCD:
+		return wm8350_clear_bits(wm8350,
+					 WM8350_COMPARATOR_INT_STATUS_MASK,
+					 WM8350_IM_CODEC_MICSCD_EINT);
+	case WM8350_IRQ_CODEC_MICD:
+		return wm8350_clear_bits(wm8350,
+					 WM8350_COMPARATOR_INT_STATUS_MASK,
+					 WM8350_IM_CODEC_MICD_EINT);
+	case WM8350_IRQ_WKUP_OFF_STATE:
+		return wm8350_clear_bits(wm8350,
+					 WM8350_COMPARATOR_INT_STATUS_MASK,
+					 WM8350_IM_WKUP_OFF_STATE_EINT);
+	case WM8350_IRQ_WKUP_HIB_STATE:
+		return wm8350_clear_bits(wm8350,
+					 WM8350_COMPARATOR_INT_STATUS_MASK,
+					 WM8350_IM_WKUP_HIB_STATE_EINT);
+	case WM8350_IRQ_WKUP_CONV_FAULT:
+		return wm8350_clear_bits(wm8350,
+					 WM8350_COMPARATOR_INT_STATUS_MASK,
+					 WM8350_IM_WKUP_CONV_FAULT_EINT);
+	case WM8350_IRQ_WKUP_WDOG_RST:
+		return wm8350_clear_bits(wm8350,
+					 WM8350_COMPARATOR_INT_STATUS_MASK,
+					 WM8350_IM_WKUP_OFF_STATE_EINT);
+	case WM8350_IRQ_WKUP_GP_PWR_ON:
+		return wm8350_clear_bits(wm8350,
+					 WM8350_COMPARATOR_INT_STATUS_MASK,
+					 WM8350_IM_WKUP_GP_PWR_ON_EINT);
+	case WM8350_IRQ_WKUP_ONKEY:
+		return wm8350_clear_bits(wm8350,
+					 WM8350_COMPARATOR_INT_STATUS_MASK,
+					 WM8350_IM_WKUP_ONKEY_EINT);
+	case WM8350_IRQ_WKUP_GP_WAKEUP:
+		return wm8350_clear_bits(wm8350,
+					 WM8350_COMPARATOR_INT_STATUS_MASK,
+					 WM8350_IM_WKUP_GP_WAKEUP_EINT);
+	case WM8350_IRQ_GPIO(0):
+		return wm8350_clear_bits(wm8350,
+					 WM8350_GPIO_INT_STATUS_MASK,
+					 WM8350_IM_GP0_EINT);
+	case WM8350_IRQ_GPIO(1):
+		return wm8350_clear_bits(wm8350,
+					 WM8350_GPIO_INT_STATUS_MASK,
+					 WM8350_IM_GP1_EINT);
+	case WM8350_IRQ_GPIO(2):
+		return wm8350_clear_bits(wm8350,
+					 WM8350_GPIO_INT_STATUS_MASK,
+					 WM8350_IM_GP2_EINT);
+	case WM8350_IRQ_GPIO(3):
+		return wm8350_clear_bits(wm8350,
+					 WM8350_GPIO_INT_STATUS_MASK,
+					 WM8350_IM_GP3_EINT);
+	case WM8350_IRQ_GPIO(4):
+		return wm8350_clear_bits(wm8350,
+					 WM8350_GPIO_INT_STATUS_MASK,
+					 WM8350_IM_GP4_EINT);
+	case WM8350_IRQ_GPIO(5):
+		return wm8350_clear_bits(wm8350,
+					 WM8350_GPIO_INT_STATUS_MASK,
+					 WM8350_IM_GP5_EINT);
+	case WM8350_IRQ_GPIO(6):
+		return wm8350_clear_bits(wm8350,
+					 WM8350_GPIO_INT_STATUS_MASK,
+					 WM8350_IM_GP6_EINT);
+	case WM8350_IRQ_GPIO(7):
+		return wm8350_clear_bits(wm8350,
+					 WM8350_GPIO_INT_STATUS_MASK,
+					 WM8350_IM_GP7_EINT);
+	case WM8350_IRQ_GPIO(8):
+		return wm8350_clear_bits(wm8350,
+					 WM8350_GPIO_INT_STATUS_MASK,
+					 WM8350_IM_GP8_EINT);
+	case WM8350_IRQ_GPIO(9):
+		return wm8350_clear_bits(wm8350,
+					 WM8350_GPIO_INT_STATUS_MASK,
+					 WM8350_IM_GP9_EINT);
+	case WM8350_IRQ_GPIO(10):
+		return wm8350_clear_bits(wm8350,
+					 WM8350_GPIO_INT_STATUS_MASK,
+					 WM8350_IM_GP10_EINT);
+	case WM8350_IRQ_GPIO(11):
+		return wm8350_clear_bits(wm8350,
+					 WM8350_GPIO_INT_STATUS_MASK,
+					 WM8350_IM_GP11_EINT);
+	case WM8350_IRQ_GPIO(12):
+		return wm8350_clear_bits(wm8350,
+					 WM8350_GPIO_INT_STATUS_MASK,
+					 WM8350_IM_GP12_EINT);
+	default:
+		dev_warn(wm8350->dev, "Attempting to unmask unknown IRQ %d\n",
+			 irq);
+		return -EINVAL;
+	}
+	return 0;
+}
+EXPORT_SYMBOL_GPL(wm8350_unmask_irq);
+
+/*
+ * Cache is always host endian.
+ */
+static int wm8350_create_cache(struct wm8350 *wm8350, int mode)
+{
+	int i, ret = 0;
+	u16 value;
+	const u16 *reg_map;
+
+	switch (mode) {
+#ifdef CONFIG_MFD_WM8350_CONFIG_MODE_0
+	case 0:
+		reg_map = wm8350_mode0_defaults;
+		break;
+#endif
+#ifdef CONFIG_MFD_WM8350_CONFIG_MODE_1
+	case 1:
+		reg_map = wm8350_mode1_defaults;
+		break;
+#endif
+#ifdef CONFIG_MFD_WM8350_CONFIG_MODE_2
+	case 2:
+		reg_map = wm8350_mode2_defaults;
+		break;
+#endif
+#ifdef CONFIG_MFD_WM8350_CONFIG_MODE_3
+	case 3:
+		reg_map = wm8350_mode3_defaults;
+		break;
+#endif
+	default:
+		dev_err(wm8350->dev, "Configuration mode %d not supported\n",
+			mode);
+		return -EINVAL;
+	}
+
+	wm8350->reg_cache =
+	    kzalloc(sizeof(u16) * (WM8350_MAX_REGISTER + 1), GFP_KERNEL);
+	if (wm8350->reg_cache == NULL)
+		return -ENOMEM;
+
+	/* Read the initial cache state back from the device - this is
+	 * a PMIC so the device many not be in a virgin state and we
+	 * can't rely on the silicon values.
+	 */
+	for (i = 0; i < WM8350_MAX_REGISTER; i++) {
+		/* audio register range */
+		if (wm8350_reg_io_map[i].readable &&
+		    (i < WM8350_CLOCK_CONTROL_1 || i > WM8350_AIF_TEST)) {
+			ret = wm8350->read_dev(wm8350, i, 2, (char *)&value);
+			if (ret < 0) {
+				dev_err(wm8350->dev,
+				       "failed to read initial cache value\n");
+				goto out;
+			}
+			value = be16_to_cpu(value);
+			value &= wm8350_reg_io_map[i].readable;
+			wm8350->reg_cache[i] = value;
+		} else
+			wm8350->reg_cache[i] = reg_map[i];
+	}
+
+out:
+	return ret;
+}
+EXPORT_SYMBOL_GPL(wm8350_create_cache);
+
+/*
+ * Register a client device.  This is non-fatal since there is no need to
+ * fail the entire device init due to a single platform device failing.
+ */
+static void wm8350_client_dev_register(struct wm8350 *wm8350,
+				       const char *name,
+				       struct platform_device **pdev)
+{
+	int ret;
+
+	*pdev = platform_device_alloc(name, -1);
+	if (pdev == NULL) {
+		dev_err(wm8350->dev, "Failed to allocate %s\n", name);
+		return;
+	}
+
+	(*pdev)->dev.parent = wm8350->dev;
+	platform_set_drvdata(*pdev, wm8350);
+	ret = platform_device_add(*pdev);
+	if (ret != 0) {
+		dev_err(wm8350->dev, "Failed to register %s: %d\n", name, ret);
+		platform_device_put(*pdev);
+		*pdev = NULL;
+	}
+}
+
+int wm8350_device_init(struct wm8350 *wm8350, int irq,
+		       struct wm8350_platform_data *pdata)
+{
+	int ret = -EINVAL;
+	u16 id1, id2, mask, mode;
+
+	/* get WM8350 revision and config mode */
+	wm8350->read_dev(wm8350, WM8350_RESET_ID, sizeof(id1), &id1);
+	wm8350->read_dev(wm8350, WM8350_ID, sizeof(id2), &id2);
+
+	id1 = be16_to_cpu(id1);
+	id2 = be16_to_cpu(id2);
+
+	if (id1 == 0x6143) {
+		switch ((id2 & WM8350_CHIP_REV_MASK) >> 12) {
+		case WM8350_REV_E:
+			dev_info(wm8350->dev, "Found Rev E device\n");
+			wm8350->rev = WM8350_REV_E;
+			break;
+		case WM8350_REV_F:
+			dev_info(wm8350->dev, "Found Rev F device\n");
+			wm8350->rev = WM8350_REV_F;
+			break;
+		case WM8350_REV_G:
+			dev_info(wm8350->dev, "Found Rev G device\n");
+			wm8350->rev = WM8350_REV_G;
+			break;
+		default:
+			/* For safety we refuse to run on unknown hardware */
+			dev_info(wm8350->dev, "Found unknown rev\n");
+			ret = -ENODEV;
+			goto err;
+		}
+	} else {
+		dev_info(wm8350->dev, "Device with ID %x is not a WM8350\n",
+			 id1);
+		ret = -ENODEV;
+		goto err;
+	}
+
+	mode = id2 & WM8350_CONF_STS_MASK >> 10;
+	mask = id2 & WM8350_CUST_ID_MASK;
+	dev_info(wm8350->dev, "Config mode %d, ROM mask %d\n", mode, mask);
+
+	ret = wm8350_create_cache(wm8350, mode);
+	if (ret < 0) {
+		printk(KERN_ERR "wm8350: failed to create register cache\n");
+		return ret;
+	}
+
+	if (pdata->init) {
+		ret = pdata->init(wm8350);
+		if (ret != 0) {
+			dev_err(wm8350->dev, "Platform init() failed: %d\n",
+				ret);
+			goto err;
+		}
+	}
+
+	mutex_init(&wm8350->irq_mutex);
+	INIT_WORK(&wm8350->irq_work, wm8350_irq_worker);
+	if (irq != NO_IRQ) {
+		ret = request_irq(irq, wm8350_irq, 0,
+				  "wm8350", wm8350);
+		if (ret != 0) {
+			dev_err(wm8350->dev, "Failed to request IRQ: %d\n",
+				ret);
+			goto err;
+		}
+	} else {
+		dev_err(wm8350->dev, "No IRQ configured\n");
+		goto err;
+	}
+	wm8350->chip_irq = irq;
+
+	wm8350_reg_write(wm8350, WM8350_SYSTEM_INTERRUPTS_MASK, 0x0);
+
+	wm8350_client_dev_register(wm8350, "wm8350-codec",
+				   &(wm8350->codec.pdev));
+	wm8350_client_dev_register(wm8350, "wm8350-gpio",
+				   &(wm8350->gpio.pdev));
+	wm8350_client_dev_register(wm8350, "wm8350-power",
+				   &(wm8350->power.pdev));
+	wm8350_client_dev_register(wm8350, "wm8350-rtc", &(wm8350->rtc.pdev));
+	wm8350_client_dev_register(wm8350, "wm8350-wdt", &(wm8350->wdt.pdev));
+
+	return 0;
+
+err:
+	kfree(wm8350->reg_cache);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(wm8350_device_init);
+
+void wm8350_device_exit(struct wm8350 *wm8350)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(wm8350->pmic.pdev); i++)
+		platform_device_unregister(wm8350->pmic.pdev[i]);
+
+	platform_device_unregister(wm8350->wdt.pdev);
+	platform_device_unregister(wm8350->rtc.pdev);
+	platform_device_unregister(wm8350->power.pdev);
+	platform_device_unregister(wm8350->gpio.pdev);
+	platform_device_unregister(wm8350->codec.pdev);
+
+	free_irq(wm8350->chip_irq, wm8350);
+	flush_work(&wm8350->irq_work);
+	kfree(wm8350->reg_cache);
+}
+EXPORT_SYMBOL_GPL(wm8350_device_exit);
+
+MODULE_DESCRIPTION("WM8350 AudioPlus PMIC core driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/wm8350-gpio.c b/drivers/mfd/wm8350-gpio.c
new file mode 100644
index 0000000..ebf99be
--- /dev/null
+++ b/drivers/mfd/wm8350-gpio.c
@@ -0,0 +1,222 @@
+/*
+ * wm8350-core.c  --  Device access for Wolfson WM8350
+ *
+ * Copyright 2007, 2008 Wolfson Microelectronics PLC.
+ *
+ * Author: Liam Girdwood
+ *
+ *  This program is free software; you can redistribute  it and/or 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/module.h>
+#include <linux/errno.h>
+
+#include <linux/mfd/wm8350/core.h>
+#include <linux/mfd/wm8350/gpio.h>
+#include <linux/mfd/wm8350/pmic.h>
+
+static int gpio_set_dir(struct wm8350 *wm8350, int gpio, int dir)
+{
+	int ret;
+
+	wm8350_reg_unlock(wm8350);
+	if (dir == WM8350_GPIO_DIR_OUT)
+		ret = wm8350_clear_bits(wm8350,
+					WM8350_GPIO_CONFIGURATION_I_O,
+					1 << gpio);
+	else
+		ret = wm8350_set_bits(wm8350,
+				      WM8350_GPIO_CONFIGURATION_I_O,
+				      1 << gpio);
+	wm8350_reg_lock(wm8350);
+	return ret;
+}
+
+static int gpio_set_debounce(struct wm8350 *wm8350, int gpio, int db)
+{
+	if (db == WM8350_GPIO_DEBOUNCE_ON)
+		return wm8350_set_bits(wm8350, WM8350_GPIO_DEBOUNCE,
+				       1 << gpio);
+	else
+		return wm8350_clear_bits(wm8350,
+					 WM8350_GPIO_DEBOUNCE, 1 << gpio);
+}
+
+static int gpio_set_func(struct wm8350 *wm8350, int gpio, int func)
+{
+	u16 reg;
+
+	wm8350_reg_unlock(wm8350);
+	switch (gpio) {
+	case 0:
+		reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_1)
+		    & ~WM8350_GP0_FN_MASK;
+		wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_1,
+				 reg | ((func & 0xf) << 0));
+		break;
+	case 1:
+		reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_1)
+		    & ~WM8350_GP1_FN_MASK;
+		wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_1,
+				 reg | ((func & 0xf) << 4));
+		break;
+	case 2:
+		reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_1)
+		    & ~WM8350_GP2_FN_MASK;
+		wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_1,
+				 reg | ((func & 0xf) << 8));
+		break;
+	case 3:
+		reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_1)
+		    & ~WM8350_GP3_FN_MASK;
+		wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_1,
+				 reg | ((func & 0xf) << 12));
+		break;
+	case 4:
+		reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_2)
+		    & ~WM8350_GP4_FN_MASK;
+		wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_2,
+				 reg | ((func & 0xf) << 0));
+		break;
+	case 5:
+		reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_2)
+		    & ~WM8350_GP5_FN_MASK;
+		wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_2,
+				 reg | ((func & 0xf) << 4));
+		break;
+	case 6:
+		reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_2)
+		    & ~WM8350_GP6_FN_MASK;
+		wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_2,
+				 reg | ((func & 0xf) << 8));
+		break;
+	case 7:
+		reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_2)
+		    & ~WM8350_GP7_FN_MASK;
+		wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_2,
+				 reg | ((func & 0xf) << 12));
+		break;
+	case 8:
+		reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_3)
+		    & ~WM8350_GP8_FN_MASK;
+		wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_3,
+				 reg | ((func & 0xf) << 0));
+		break;
+	case 9:
+		reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_3)
+		    & ~WM8350_GP9_FN_MASK;
+		wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_3,
+				 reg | ((func & 0xf) << 4));
+		break;
+	case 10:
+		reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_3)
+		    & ~WM8350_GP10_FN_MASK;
+		wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_3,
+				 reg | ((func & 0xf) << 8));
+		break;
+	case 11:
+		reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_3)
+		    & ~WM8350_GP11_FN_MASK;
+		wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_3,
+				 reg | ((func & 0xf) << 12));
+		break;
+	case 12:
+		reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_4)
+		    & ~WM8350_GP12_FN_MASK;
+		wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_4,
+				 reg | ((func & 0xf) << 0));
+		break;
+	default:
+		wm8350_reg_lock(wm8350);
+		return -EINVAL;
+	}
+
+	wm8350_reg_lock(wm8350);
+	return 0;
+}
+
+static int gpio_set_pull_up(struct wm8350 *wm8350, int gpio, int up)
+{
+	if (up)
+		return wm8350_set_bits(wm8350,
+				       WM8350_GPIO_PIN_PULL_UP_CONTROL,
+				       1 << gpio);
+	else
+		return wm8350_clear_bits(wm8350,
+					 WM8350_GPIO_PIN_PULL_UP_CONTROL,
+					 1 << gpio);
+}
+
+static int gpio_set_pull_down(struct wm8350 *wm8350, int gpio, int down)
+{
+	if (down)
+		return wm8350_set_bits(wm8350,
+				       WM8350_GPIO_PULL_DOWN_CONTROL,
+				       1 << gpio);
+	else
+		return wm8350_clear_bits(wm8350,
+					 WM8350_GPIO_PULL_DOWN_CONTROL,
+					 1 << gpio);
+}
+
+static int gpio_set_polarity(struct wm8350 *wm8350, int gpio, int pol)
+{
+	if (pol == WM8350_GPIO_ACTIVE_HIGH)
+		return wm8350_set_bits(wm8350,
+				       WM8350_GPIO_PIN_POLARITY_TYPE,
+				       1 << gpio);
+	else
+		return wm8350_clear_bits(wm8350,
+					 WM8350_GPIO_PIN_POLARITY_TYPE,
+					 1 << gpio);
+}
+
+static int gpio_set_invert(struct wm8350 *wm8350, int gpio, int invert)
+{
+	if (invert == WM8350_GPIO_INVERT_ON)
+		return wm8350_set_bits(wm8350, WM8350_GPIO_INT_MODE, 1 << gpio);
+	else
+		return wm8350_clear_bits(wm8350,
+					 WM8350_GPIO_INT_MODE, 1 << gpio);
+}
+
+int wm8350_gpio_config(struct wm8350 *wm8350, int gpio, int dir, int func,
+		       int pol, int pull, int invert, int debounce)
+{
+	/* make sure we never pull up and down at the same time */
+	if (pull == WM8350_GPIO_PULL_NONE) {
+		if (gpio_set_pull_up(wm8350, gpio, 0))
+			goto err;
+		if (gpio_set_pull_down(wm8350, gpio, 0))
+			goto err;
+	} else if (pull == WM8350_GPIO_PULL_UP) {
+		if (gpio_set_pull_down(wm8350, gpio, 0))
+			goto err;
+		if (gpio_set_pull_up(wm8350, gpio, 1))
+			goto err;
+	} else if (pull == WM8350_GPIO_PULL_DOWN) {
+		if (gpio_set_pull_up(wm8350, gpio, 0))
+			goto err;
+		if (gpio_set_pull_down(wm8350, gpio, 1))
+			goto err;
+	}
+
+	if (gpio_set_invert(wm8350, gpio, invert))
+		goto err;
+	if (gpio_set_polarity(wm8350, gpio, pol))
+		goto err;
+	if (gpio_set_debounce(wm8350, gpio, debounce))
+		goto err;
+	if (gpio_set_dir(wm8350, gpio, dir))
+		goto err;
+	return gpio_set_func(wm8350, gpio, func);
+
+err:
+	return -EIO;
+}
+EXPORT_SYMBOL_GPL(wm8350_gpio_config);
diff --git a/drivers/mfd/wm8350-i2c.c b/drivers/mfd/wm8350-i2c.c
new file mode 100644
index 0000000..8dfe21b
--- /dev/null
+++ b/drivers/mfd/wm8350-i2c.c
@@ -0,0 +1,120 @@
+/*
+ * wm8350-i2c.c  --  Generic I2C driver for Wolfson WM8350 PMIC
+ *
+ * This driver defines and configures the WM8350 for the Freescale i.MX32ADS.
+ *
+ * Copyright 2007, 2008 Wolfson Microelectronics PLC.
+ *
+ * Author: Liam Girdwood
+ *         linux@wolfsonmicro.com
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/mfd/wm8350/core.h>
+
+static int wm8350_i2c_read_device(struct wm8350 *wm8350, char reg,
+				  int bytes, void *dest)
+{
+	int ret;
+
+	ret = i2c_master_send(wm8350->i2c_client, &reg, 1);
+	if (ret < 0)
+		return ret;
+	return i2c_master_recv(wm8350->i2c_client, dest, bytes);
+}
+
+static int wm8350_i2c_write_device(struct wm8350 *wm8350, char reg,
+				   int bytes, void *src)
+{
+	/* we add 1 byte for device register */
+	u8 msg[(WM8350_MAX_REGISTER << 1) + 1];
+
+	if (bytes > ((WM8350_MAX_REGISTER << 1) + 1))
+		return -EINVAL;
+
+	msg[0] = reg;
+	memcpy(&msg[1], src, bytes);
+	return i2c_master_send(wm8350->i2c_client, msg, bytes + 1);
+}
+
+static int wm8350_i2c_probe(struct i2c_client *i2c,
+			    const struct i2c_device_id *id)
+{
+	struct wm8350 *wm8350;
+	int ret = 0;
+
+	wm8350 = kzalloc(sizeof(struct wm8350), GFP_KERNEL);
+	if (wm8350 == NULL) {
+		kfree(i2c);
+		return -ENOMEM;
+	}
+
+	i2c_set_clientdata(i2c, wm8350);
+	wm8350->dev = &i2c->dev;
+	wm8350->i2c_client = i2c;
+	wm8350->read_dev = wm8350_i2c_read_device;
+	wm8350->write_dev = wm8350_i2c_write_device;
+
+	ret = wm8350_device_init(wm8350, i2c->irq, i2c->dev.platform_data);
+	if (ret < 0)
+		goto err;
+
+	return ret;
+
+err:
+	kfree(wm8350);
+	return ret;
+}
+
+static int wm8350_i2c_remove(struct i2c_client *i2c)
+{
+	struct wm8350 *wm8350 = i2c_get_clientdata(i2c);
+
+	wm8350_device_exit(wm8350);
+	kfree(wm8350);
+
+	return 0;
+}
+
+static const struct i2c_device_id wm8350_i2c_id[] = {
+       { "wm8350", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, wm8350_i2c_id);
+
+
+static struct i2c_driver wm8350_i2c_driver = {
+	.driver = {
+		   .name = "wm8350",
+		   .owner = THIS_MODULE,
+	},
+	.probe = wm8350_i2c_probe,
+	.remove = wm8350_i2c_remove,
+	.id_table = wm8350_i2c_id,
+};
+
+static int __init wm8350_i2c_init(void)
+{
+	return i2c_add_driver(&wm8350_i2c_driver);
+}
+/* init early so consumer devices can complete system boot */
+subsys_initcall(wm8350_i2c_init);
+
+static void __exit wm8350_i2c_exit(void)
+{
+	i2c_del_driver(&wm8350_i2c_driver);
+}
+module_exit(wm8350_i2c_exit);
+
+MODULE_DESCRIPTION("I2C support for the WM8350 AudioPlus PMIC");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/wm8350-regmap.c b/drivers/mfd/wm8350-regmap.c
new file mode 100644
index 0000000..974678d
--- /dev/null
+++ b/drivers/mfd/wm8350-regmap.c
@@ -0,0 +1,1347 @@
+/*
+ * wm8350-regmap.c  --  Wolfson Microelectronics WM8350 register map
+ *
+ * This file splits out the tables describing the defaults and access
+ * status of the WM8350 registers since they are rather large.
+ *
+ * Copyright 2007, 2008 Wolfson Microelectronics PLC.
+ *
+ *  This program is free software; you can redistribute  it and/or 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/mfd/wm8350/core.h>
+
+#ifdef CONFIG_MFD_WM8350_CONFIG_MODE_0
+
+#undef WM8350_HAVE_CONFIG_MODE
+#define WM8350_HAVE_CONFIG_MODE
+
+const u16 wm8350_mode0_defaults[] = {
+	0x17FF,     /* R0   - Reset/ID */
+	0x1000,     /* R1   - ID */
+	0x0000,     /* R2 */
+	0x1002,     /* R3   - System Control 1 */
+	0x0004,     /* R4   - System Control 2 */
+	0x0000,     /* R5   - System Hibernate */
+	0x8A00,     /* R6   - Interface Control */
+	0x0000,     /* R7 */
+	0x8000,     /* R8   - Power mgmt (1) */
+	0x0000,     /* R9   - Power mgmt (2) */
+	0x0000,     /* R10  - Power mgmt (3) */
+	0x2000,     /* R11  - Power mgmt (4) */
+	0x0E00,     /* R12  - Power mgmt (5) */
+	0x0000,     /* R13  - Power mgmt (6) */
+	0x0000,     /* R14  - Power mgmt (7) */
+	0x0000,     /* R15 */
+	0x0000,     /* R16  - RTC Seconds/Minutes */
+	0x0100,     /* R17  - RTC Hours/Day */
+	0x0101,     /* R18  - RTC Date/Month */
+	0x1400,     /* R19  - RTC Year */
+	0x0000,     /* R20  - Alarm Seconds/Minutes */
+	0x0000,     /* R21  - Alarm Hours/Day */
+	0x0000,     /* R22  - Alarm Date/Month */
+	0x0320,     /* R23  - RTC Time Control */
+	0x0000,     /* R24  - System Interrupts */
+	0x0000,     /* R25  - Interrupt Status 1 */
+	0x0000,     /* R26  - Interrupt Status 2 */
+	0x0000,     /* R27  - Power Up Interrupt Status */
+	0x0000,     /* R28  - Under Voltage Interrupt status */
+	0x0000,     /* R29  - Over Current Interrupt status */
+	0x0000,     /* R30  - GPIO Interrupt Status */
+	0x0000,     /* R31  - Comparator Interrupt Status */
+	0x3FFF,     /* R32  - System Interrupts Mask */
+	0x0000,     /* R33  - Interrupt Status 1 Mask */
+	0x0000,     /* R34  - Interrupt Status 2 Mask */
+	0x0000,     /* R35  - Power Up Interrupt Status Mask */
+	0x0000,     /* R36  - Under Voltage Interrupt status Mask */
+	0x0000,     /* R37  - Over Current Interrupt status Mask */
+	0x0000,     /* R38  - GPIO Interrupt Status Mask */
+	0x0000,     /* R39  - Comparator Interrupt Status Mask */
+	0x0040,     /* R40  - Clock Control 1 */
+	0x0000,     /* R41  - Clock Control 2 */
+	0x3B00,     /* R42  - FLL Control 1 */
+	0x7086,     /* R43  - FLL Control 2 */
+	0xC226,     /* R44  - FLL Control 3 */
+	0x0000,     /* R45  - FLL Control 4 */
+	0x0000,     /* R46 */
+	0x0000,     /* R47 */
+	0x0000,     /* R48  - DAC Control */
+	0x0000,     /* R49 */
+	0x00C0,     /* R50  - DAC Digital Volume L */
+	0x00C0,     /* R51  - DAC Digital Volume R */
+	0x0000,     /* R52 */
+	0x0040,     /* R53  - DAC LR Rate */
+	0x0000,     /* R54  - DAC Clock Control */
+	0x0000,     /* R55 */
+	0x0000,     /* R56 */
+	0x0000,     /* R57 */
+	0x4000,     /* R58  - DAC Mute */
+	0x0000,     /* R59  - DAC Mute Volume */
+	0x0000,     /* R60  - DAC Side */
+	0x0000,     /* R61 */
+	0x0000,     /* R62 */
+	0x0000,     /* R63 */
+	0x8000,     /* R64  - ADC Control */
+	0x0000,     /* R65 */
+	0x00C0,     /* R66  - ADC Digital Volume L */
+	0x00C0,     /* R67  - ADC Digital Volume R */
+	0x0000,     /* R68  - ADC Divider */
+	0x0000,     /* R69 */
+	0x0040,     /* R70  - ADC LR Rate */
+	0x0000,     /* R71 */
+	0x0303,     /* R72  - Input Control */
+	0x0000,     /* R73  - IN3 Input Control */
+	0x0000,     /* R74  - Mic Bias Control */
+	0x0000,     /* R75 */
+	0x0000,     /* R76  - Output Control */
+	0x0000,     /* R77  - Jack Detect */
+	0x0000,     /* R78  - Anti Pop Control */
+	0x0000,     /* R79 */
+	0x0040,     /* R80  - Left Input Volume */
+	0x0040,     /* R81  - Right Input Volume */
+	0x0000,     /* R82 */
+	0x0000,     /* R83 */
+	0x0000,     /* R84 */
+	0x0000,     /* R85 */
+	0x0000,     /* R86 */
+	0x0000,     /* R87 */
+	0x0800,     /* R88  - Left Mixer Control */
+	0x1000,     /* R89  - Right Mixer Control */
+	0x0000,     /* R90 */
+	0x0000,     /* R91 */
+	0x0000,     /* R92  - OUT3 Mixer Control */
+	0x0000,     /* R93  - OUT4 Mixer Control */
+	0x0000,     /* R94 */
+	0x0000,     /* R95 */
+	0x0000,     /* R96  - Output Left Mixer Volume */
+	0x0000,     /* R97  - Output Right Mixer Volume */
+	0x0000,     /* R98  - Input Mixer Volume L */
+	0x0000,     /* R99  - Input Mixer Volume R */
+	0x0000,     /* R100 - Input Mixer Volume */
+	0x0000,     /* R101 */
+	0x0000,     /* R102 */
+	0x0000,     /* R103 */
+	0x00E4,     /* R104 - LOUT1 Volume */
+	0x00E4,     /* R105 - ROUT1 Volume */
+	0x00E4,     /* R106 - LOUT2 Volume */
+	0x02E4,     /* R107 - ROUT2 Volume */
+	0x0000,     /* R108 */
+	0x0000,     /* R109 */
+	0x0000,     /* R110 */
+	0x0000,     /* R111 - BEEP Volume */
+	0x0A00,     /* R112 - AI Formating */
+	0x0000,     /* R113 - ADC DAC COMP */
+	0x0020,     /* R114 - AI ADC Control */
+	0x0020,     /* R115 - AI DAC Control */
+	0x0000,     /* R116 - AIF Test */
+	0x0000,     /* R117 */
+	0x0000,     /* R118 */
+	0x0000,     /* R119 */
+	0x0000,     /* R120 */
+	0x0000,     /* R121 */
+	0x0000,     /* R122 */
+	0x0000,     /* R123 */
+	0x0000,     /* R124 */
+	0x0000,     /* R125 */
+	0x0000,     /* R126 */
+	0x0000,     /* R127 */
+	0x1FFF,     /* R128 - GPIO Debounce */
+	0x0000,     /* R129 - GPIO Pin pull up Control */
+	0x03FC,     /* R130 - GPIO Pull down Control */
+	0x0000,     /* R131 - GPIO Interrupt Mode */
+	0x0000,     /* R132 */
+	0x0000,     /* R133 - GPIO Control */
+	0x0FFC,     /* R134 - GPIO Configuration (i/o) */
+	0x0FFC,     /* R135 - GPIO Pin Polarity / Type */
+	0x0000,     /* R136 */
+	0x0000,     /* R137 */
+	0x0000,     /* R138 */
+	0x0000,     /* R139 */
+	0x0013,     /* R140 - GPIO Function Select 1 */
+	0x0000,     /* R141 - GPIO Function Select 2 */
+	0x0000,     /* R142 - GPIO Function Select 3 */
+	0x0003,     /* R143 - GPIO Function Select 4 */
+	0x0000,     /* R144 - Digitiser Control (1) */
+	0x0002,     /* R145 - Digitiser Control (2) */
+	0x0000,     /* R146 */
+	0x0000,     /* R147 */
+	0x0000,     /* R148 */
+	0x0000,     /* R149 */
+	0x0000,     /* R150 */
+	0x0000,     /* R151 */
+	0x7000,     /* R152 - AUX1 Readback */
+	0x7000,     /* R153 - AUX2 Readback */
+	0x7000,     /* R154 - AUX3 Readback */
+	0x7000,     /* R155 - AUX4 Readback */
+	0x0000,     /* R156 - USB Voltage Readback */
+	0x0000,     /* R157 - LINE Voltage Readback */
+	0x0000,     /* R158 - BATT Voltage Readback */
+	0x0000,     /* R159 - Chip Temp Readback */
+	0x0000,     /* R160 */
+	0x0000,     /* R161 */
+	0x0000,     /* R162 */
+	0x0000,     /* R163 - Generic Comparator Control */
+	0x0000,     /* R164 - Generic comparator 1 */
+	0x0000,     /* R165 - Generic comparator 2 */
+	0x0000,     /* R166 - Generic comparator 3 */
+	0x0000,     /* R167 - Generic comparator 4 */
+	0xA00F,     /* R168 - Battery Charger Control 1 */
+	0x0B06,     /* R169 - Battery Charger Control 2 */
+	0x0000,     /* R170 - Battery Charger Control 3 */
+	0x0000,     /* R171 */
+	0x0000,     /* R172 - Current Sink Driver A */
+	0x0000,     /* R173 - CSA Flash control */
+	0x0000,     /* R174 - Current Sink Driver B */
+	0x0000,     /* R175 - CSB Flash control */
+	0x0000,     /* R176 - DCDC/LDO requested */
+	0x002D,     /* R177 - DCDC Active options */
+	0x0000,     /* R178 - DCDC Sleep options */
+	0x0025,     /* R179 - Power-check comparator */
+	0x000E,     /* R180 - DCDC1 Control */
+	0x0000,     /* R181 - DCDC1 Timeouts */
+	0x1006,     /* R182 - DCDC1 Low Power */
+	0x0018,     /* R183 - DCDC2 Control */
+	0x0000,     /* R184 - DCDC2 Timeouts */
+	0x0000,     /* R185 */
+	0x0000,     /* R186 - DCDC3 Control */
+	0x0000,     /* R187 - DCDC3 Timeouts */
+	0x0006,     /* R188 - DCDC3 Low Power */
+	0x0000,     /* R189 - DCDC4 Control */
+	0x0000,     /* R190 - DCDC4 Timeouts */
+	0x0006,     /* R191 - DCDC4 Low Power */
+	0x0008,     /* R192 - DCDC5 Control */
+	0x0000,     /* R193 - DCDC5 Timeouts */
+	0x0000,     /* R194 */
+	0x0000,     /* R195 - DCDC6 Control */
+	0x0000,     /* R196 - DCDC6 Timeouts */
+	0x0006,     /* R197 - DCDC6 Low Power */
+	0x0000,     /* R198 */
+	0x0003,     /* R199 - Limit Switch Control */
+	0x001C,     /* R200 - LDO1 Control */
+	0x0000,     /* R201 - LDO1 Timeouts */
+	0x001C,     /* R202 - LDO1 Low Power */
+	0x001B,     /* R203 - LDO2 Control */
+	0x0000,     /* R204 - LDO2 Timeouts */
+	0x001C,     /* R205 - LDO2 Low Power */
+	0x001B,     /* R206 - LDO3 Control */
+	0x0000,     /* R207 - LDO3 Timeouts */
+	0x001C,     /* R208 - LDO3 Low Power */
+	0x001B,     /* R209 - LDO4 Control */
+	0x0000,     /* R210 - LDO4 Timeouts */
+	0x001C,     /* R211 - LDO4 Low Power */
+	0x0000,     /* R212 */
+	0x0000,     /* R213 */
+	0x0000,     /* R214 */
+	0x0000,     /* R215 - VCC_FAULT Masks */
+	0x001F,     /* R216 - Main Bandgap Control */
+	0x0000,     /* R217 - OSC Control */
+	0x9000,     /* R218 - RTC Tick Control */
+	0x0000,     /* R219 */
+	0x4000,     /* R220 - RAM BIST 1 */
+	0x0000,     /* R221 */
+	0x0000,     /* R222 */
+	0x0000,     /* R223 */
+	0x0000,     /* R224 */
+	0x0000,     /* R225 - DCDC/LDO status */
+	0x0000,     /* R226 */
+	0x0000,     /* R227 */
+	0x0000,     /* R228 */
+	0x0000,     /* R229 */
+	0xE000,     /* R230 - GPIO Pin Status */
+	0x0000,     /* R231 */
+	0x0000,     /* R232 */
+	0x0000,     /* R233 */
+	0x0000,     /* R234 */
+	0x0000,     /* R235 */
+	0x0000,     /* R236 */
+	0x0000,     /* R237 */
+	0x0000,     /* R238 */
+	0x0000,     /* R239 */
+	0x0000,     /* R240 */
+	0x0000,     /* R241 */
+	0x0000,     /* R242 */
+	0x0000,     /* R243 */
+	0x0000,     /* R244 */
+	0x0000,     /* R245 */
+	0x0000,     /* R246 */
+	0x0000,     /* R247 */
+	0x0000,     /* R248 */
+	0x0000,     /* R249 */
+	0x0000,     /* R250 */
+	0x0000,     /* R251 */
+	0x0000,     /* R252 */
+	0x0000,     /* R253 */
+	0x0000,     /* R254 */
+	0x0000,     /* R255 */
+};
+#endif
+
+#ifdef CONFIG_MFD_WM8350_CONFIG_MODE_1
+
+#undef WM8350_HAVE_CONFIG_MODE
+#define WM8350_HAVE_CONFIG_MODE
+
+const u16 wm8350_mode1_defaults[] = {
+	0x17FF,     /* R0   - Reset/ID */
+	0x1000,     /* R1   - ID */
+	0x0000,     /* R2 */
+	0x1002,     /* R3   - System Control 1 */
+	0x0014,     /* R4   - System Control 2 */
+	0x0000,     /* R5   - System Hibernate */
+	0x8A00,     /* R6   - Interface Control */
+	0x0000,     /* R7 */
+	0x8000,     /* R8   - Power mgmt (1) */
+	0x0000,     /* R9   - Power mgmt (2) */
+	0x0000,     /* R10  - Power mgmt (3) */
+	0x2000,     /* R11  - Power mgmt (4) */
+	0x0E00,     /* R12  - Power mgmt (5) */
+	0x0000,     /* R13  - Power mgmt (6) */
+	0x0000,     /* R14  - Power mgmt (7) */
+	0x0000,     /* R15 */
+	0x0000,     /* R16  - RTC Seconds/Minutes */
+	0x0100,     /* R17  - RTC Hours/Day */
+	0x0101,     /* R18  - RTC Date/Month */
+	0x1400,     /* R19  - RTC Year */
+	0x0000,     /* R20  - Alarm Seconds/Minutes */
+	0x0000,     /* R21  - Alarm Hours/Day */
+	0x0000,     /* R22  - Alarm Date/Month */
+	0x0320,     /* R23  - RTC Time Control */
+	0x0000,     /* R24  - System Interrupts */
+	0x0000,     /* R25  - Interrupt Status 1 */
+	0x0000,     /* R26  - Interrupt Status 2 */
+	0x0000,     /* R27  - Power Up Interrupt Status */
+	0x0000,     /* R28  - Under Voltage Interrupt status */
+	0x0000,     /* R29  - Over Current Interrupt status */
+	0x0000,     /* R30  - GPIO Interrupt Status */
+	0x0000,     /* R31  - Comparator Interrupt Status */
+	0x3FFF,     /* R32  - System Interrupts Mask */
+	0x0000,     /* R33  - Interrupt Status 1 Mask */
+	0x0000,     /* R34  - Interrupt Status 2 Mask */
+	0x0000,     /* R35  - Power Up Interrupt Status Mask */
+	0x0000,     /* R36  - Under Voltage Interrupt status Mask */
+	0x0000,     /* R37  - Over Current Interrupt status Mask */
+	0x0000,     /* R38  - GPIO Interrupt Status Mask */
+	0x0000,     /* R39  - Comparator Interrupt Status Mask */
+	0x0040,     /* R40  - Clock Control 1 */
+	0x0000,     /* R41  - Clock Control 2 */
+	0x3B00,     /* R42  - FLL Control 1 */
+	0x7086,     /* R43  - FLL Control 2 */
+	0xC226,     /* R44  - FLL Control 3 */
+	0x0000,     /* R45  - FLL Control 4 */
+	0x0000,     /* R46 */
+	0x0000,     /* R47 */
+	0x0000,     /* R48  - DAC Control */
+	0x0000,     /* R49 */
+	0x00C0,     /* R50  - DAC Digital Volume L */
+	0x00C0,     /* R51  - DAC Digital Volume R */
+	0x0000,     /* R52 */
+	0x0040,     /* R53  - DAC LR Rate */
+	0x0000,     /* R54  - DAC Clock Control */
+	0x0000,     /* R55 */
+	0x0000,     /* R56 */
+	0x0000,     /* R57 */
+	0x4000,     /* R58  - DAC Mute */
+	0x0000,     /* R59  - DAC Mute Volume */
+	0x0000,     /* R60  - DAC Side */
+	0x0000,     /* R61 */
+	0x0000,     /* R62 */
+	0x0000,     /* R63 */
+	0x8000,     /* R64  - ADC Control */
+	0x0000,     /* R65 */
+	0x00C0,     /* R66  - ADC Digital Volume L */
+	0x00C0,     /* R67  - ADC Digital Volume R */
+	0x0000,     /* R68  - ADC Divider */
+	0x0000,     /* R69 */
+	0x0040,     /* R70  - ADC LR Rate */
+	0x0000,     /* R71 */
+	0x0303,     /* R72  - Input Control */
+	0x0000,     /* R73  - IN3 Input Control */
+	0x0000,     /* R74  - Mic Bias Control */
+	0x0000,     /* R75 */
+	0x0000,     /* R76  - Output Control */
+	0x0000,     /* R77  - Jack Detect */
+	0x0000,     /* R78  - Anti Pop Control */
+	0x0000,     /* R79 */
+	0x0040,     /* R80  - Left Input Volume */
+	0x0040,     /* R81  - Right Input Volume */
+	0x0000,     /* R82 */
+	0x0000,     /* R83 */
+	0x0000,     /* R84 */
+	0x0000,     /* R85 */
+	0x0000,     /* R86 */
+	0x0000,     /* R87 */
+	0x0800,     /* R88  - Left Mixer Control */
+	0x1000,     /* R89  - Right Mixer Control */
+	0x0000,     /* R90 */
+	0x0000,     /* R91 */
+	0x0000,     /* R92  - OUT3 Mixer Control */
+	0x0000,     /* R93  - OUT4 Mixer Control */
+	0x0000,     /* R94 */
+	0x0000,     /* R95 */
+	0x0000,     /* R96  - Output Left Mixer Volume */
+	0x0000,     /* R97  - Output Right Mixer Volume */
+	0x0000,     /* R98  - Input Mixer Volume L */
+	0x0000,     /* R99  - Input Mixer Volume R */
+	0x0000,     /* R100 - Input Mixer Volume */
+	0x0000,     /* R101 */
+	0x0000,     /* R102 */
+	0x0000,     /* R103 */
+	0x00E4,     /* R104 - LOUT1 Volume */
+	0x00E4,     /* R105 - ROUT1 Volume */
+	0x00E4,     /* R106 - LOUT2 Volume */
+	0x02E4,     /* R107 - ROUT2 Volume */
+	0x0000,     /* R108 */
+	0x0000,     /* R109 */
+	0x0000,     /* R110 */
+	0x0000,     /* R111 - BEEP Volume */
+	0x0A00,     /* R112 - AI Formating */
+	0x0000,     /* R113 - ADC DAC COMP */
+	0x0020,     /* R114 - AI ADC Control */
+	0x0020,     /* R115 - AI DAC Control */
+	0x0000,     /* R116 - AIF Test */
+	0x0000,     /* R117 */
+	0x0000,     /* R118 */
+	0x0000,     /* R119 */
+	0x0000,     /* R120 */
+	0x0000,     /* R121 */
+	0x0000,     /* R122 */
+	0x0000,     /* R123 */
+	0x0000,     /* R124 */
+	0x0000,     /* R125 */
+	0x0000,     /* R126 */
+	0x0000,     /* R127 */
+	0x1FFF,     /* R128 - GPIO Debounce */
+	0x0000,     /* R129 - GPIO Pin pull up Control */
+	0x03FC,     /* R130 - GPIO Pull down Control */
+	0x0000,     /* R131 - GPIO Interrupt Mode */
+	0x0000,     /* R132 */
+	0x0000,     /* R133 - GPIO Control */
+	0x00FB,     /* R134 - GPIO Configuration (i/o) */
+	0x04FE,     /* R135 - GPIO Pin Polarity / Type */
+	0x0000,     /* R136 */
+	0x0000,     /* R137 */
+	0x0000,     /* R138 */
+	0x0000,     /* R139 */
+	0x0312,     /* R140 - GPIO Function Select 1 */
+	0x1003,     /* R141 - GPIO Function Select 2 */
+	0x1331,     /* R142 - GPIO Function Select 3 */
+	0x0003,     /* R143 - GPIO Function Select 4 */
+	0x0000,     /* R144 - Digitiser Control (1) */
+	0x0002,     /* R145 - Digitiser Control (2) */
+	0x0000,     /* R146 */
+	0x0000,     /* R147 */
+	0x0000,     /* R148 */
+	0x0000,     /* R149 */
+	0x0000,     /* R150 */
+	0x0000,     /* R151 */
+	0x7000,     /* R152 - AUX1 Readback */
+	0x7000,     /* R153 - AUX2 Readback */
+	0x7000,     /* R154 - AUX3 Readback */
+	0x7000,     /* R155 - AUX4 Readback */
+	0x0000,     /* R156 - USB Voltage Readback */
+	0x0000,     /* R157 - LINE Voltage Readback */
+	0x0000,     /* R158 - BATT Voltage Readback */
+	0x0000,     /* R159 - Chip Temp Readback */
+	0x0000,     /* R160 */
+	0x0000,     /* R161 */
+	0x0000,     /* R162 */
+	0x0000,     /* R163 - Generic Comparator Control */
+	0x0000,     /* R164 - Generic comparator 1 */
+	0x0000,     /* R165 - Generic comparator 2 */
+	0x0000,     /* R166 - Generic comparator 3 */
+	0x0000,     /* R167 - Generic comparator 4 */
+	0xA00F,     /* R168 - Battery Charger Control 1 */
+	0x0B06,     /* R169 - Battery Charger Control 2 */
+	0x0000,     /* R170 - Battery Charger Control 3 */
+	0x0000,     /* R171 */
+	0x0000,     /* R172 - Current Sink Driver A */
+	0x0000,     /* R173 - CSA Flash control */
+	0x0000,     /* R174 - Current Sink Driver B */
+	0x0000,     /* R175 - CSB Flash control */
+	0x0000,     /* R176 - DCDC/LDO requested */
+	0x002D,     /* R177 - DCDC Active options */
+	0x0000,     /* R178 - DCDC Sleep options */
+	0x0025,     /* R179 - Power-check comparator */
+	0x0062,     /* R180 - DCDC1 Control */
+	0x0400,     /* R181 - DCDC1 Timeouts */
+	0x1006,     /* R182 - DCDC1 Low Power */
+	0x0018,     /* R183 - DCDC2 Control */
+	0x0000,     /* R184 - DCDC2 Timeouts */
+	0x0000,     /* R185 */
+	0x0026,     /* R186 - DCDC3 Control */
+	0x0400,     /* R187 - DCDC3 Timeouts */
+	0x0006,     /* R188 - DCDC3 Low Power */
+	0x0062,     /* R189 - DCDC4 Control */
+	0x0400,     /* R190 - DCDC4 Timeouts */
+	0x0006,     /* R191 - DCDC4 Low Power */
+	0x0008,     /* R192 - DCDC5 Control */
+	0x0000,     /* R193 - DCDC5 Timeouts */
+	0x0000,     /* R194 */
+	0x0026,     /* R195 - DCDC6 Control */
+	0x0800,     /* R196 - DCDC6 Timeouts */
+	0x0006,     /* R197 - DCDC6 Low Power */
+	0x0000,     /* R198 */
+	0x0003,     /* R199 - Limit Switch Control */
+	0x0006,     /* R200 - LDO1 Control */
+	0x0400,     /* R201 - LDO1 Timeouts */
+	0x001C,     /* R202 - LDO1 Low Power */
+	0x0006,     /* R203 - LDO2 Control */
+	0x0400,     /* R204 - LDO2 Timeouts */
+	0x001C,     /* R205 - LDO2 Low Power */
+	0x001B,     /* R206 - LDO3 Control */
+	0x0000,     /* R207 - LDO3 Timeouts */
+	0x001C,     /* R208 - LDO3 Low Power */
+	0x001B,     /* R209 - LDO4 Control */
+	0x0000,     /* R210 - LDO4 Timeouts */
+	0x001C,     /* R211 - LDO4 Low Power */
+	0x0000,     /* R212 */
+	0x0000,     /* R213 */
+	0x0000,     /* R214 */
+	0x0000,     /* R215 - VCC_FAULT Masks */
+	0x001F,     /* R216 - Main Bandgap Control */
+	0x0000,     /* R217 - OSC Control */
+	0x9000,     /* R218 - RTC Tick Control */
+	0x0000,     /* R219 */
+	0x4000,     /* R220 - RAM BIST 1 */
+	0x0000,     /* R221 */
+	0x0000,     /* R222 */
+	0x0000,     /* R223 */
+	0x0000,     /* R224 */
+	0x0000,     /* R225 - DCDC/LDO status */
+	0x0000,     /* R226 */
+	0x0000,     /* R227 */
+	0x0000,     /* R228 */
+	0x0000,     /* R229 */
+	0xE000,     /* R230 - GPIO Pin Status */
+	0x0000,     /* R231 */
+	0x0000,     /* R232 */
+	0x0000,     /* R233 */
+	0x0000,     /* R234 */
+	0x0000,     /* R235 */
+	0x0000,     /* R236 */
+	0x0000,     /* R237 */
+	0x0000,     /* R238 */
+	0x0000,     /* R239 */
+	0x0000,     /* R240 */
+	0x0000,     /* R241 */
+	0x0000,     /* R242 */
+	0x0000,     /* R243 */
+	0x0000,     /* R244 */
+	0x0000,     /* R245 */
+	0x0000,     /* R246 */
+	0x0000,     /* R247 */
+	0x0000,     /* R248 */
+	0x0000,     /* R249 */
+	0x0000,     /* R250 */
+	0x0000,     /* R251 */
+	0x0000,     /* R252 */
+	0x0000,     /* R253 */
+	0x0000,     /* R254 */
+	0x0000,     /* R255 */
+};
+#endif
+
+#ifdef CONFIG_MFD_WM8350_CONFIG_MODE_2
+
+#undef WM8350_HAVE_CONFIG_MODE
+#define WM8350_HAVE_CONFIG_MODE
+
+const u16 wm8350_mode2_defaults[] = {
+	0x17FF,     /* R0   - Reset/ID */
+	0x1000,     /* R1   - ID */
+	0x0000,     /* R2 */
+	0x1002,     /* R3   - System Control 1 */
+	0x0014,     /* R4   - System Control 2 */
+	0x0000,     /* R5   - System Hibernate */
+	0x8A00,     /* R6   - Interface Control */
+	0x0000,     /* R7 */
+	0x8000,     /* R8   - Power mgmt (1) */
+	0x0000,     /* R9   - Power mgmt (2) */
+	0x0000,     /* R10  - Power mgmt (3) */
+	0x2000,     /* R11  - Power mgmt (4) */
+	0x0E00,     /* R12  - Power mgmt (5) */
+	0x0000,     /* R13  - Power mgmt (6) */
+	0x0000,     /* R14  - Power mgmt (7) */
+	0x0000,     /* R15 */
+	0x0000,     /* R16  - RTC Seconds/Minutes */
+	0x0100,     /* R17  - RTC Hours/Day */
+	0x0101,     /* R18  - RTC Date/Month */
+	0x1400,     /* R19  - RTC Year */
+	0x0000,     /* R20  - Alarm Seconds/Minutes */
+	0x0000,     /* R21  - Alarm Hours/Day */
+	0x0000,     /* R22  - Alarm Date/Month */
+	0x0320,     /* R23  - RTC Time Control */
+	0x0000,     /* R24  - System Interrupts */
+	0x0000,     /* R25  - Interrupt Status 1 */
+	0x0000,     /* R26  - Interrupt Status 2 */
+	0x0000,     /* R27  - Power Up Interrupt Status */
+	0x0000,     /* R28  - Under Voltage Interrupt status */
+	0x0000,     /* R29  - Over Current Interrupt status */
+	0x0000,     /* R30  - GPIO Interrupt Status */
+	0x0000,     /* R31  - Comparator Interrupt Status */
+	0x3FFF,     /* R32  - System Interrupts Mask */
+	0x0000,     /* R33  - Interrupt Status 1 Mask */
+	0x0000,     /* R34  - Interrupt Status 2 Mask */
+	0x0000,     /* R35  - Power Up Interrupt Status Mask */
+	0x0000,     /* R36  - Under Voltage Interrupt status Mask */
+	0x0000,     /* R37  - Over Current Interrupt status Mask */
+	0x0000,     /* R38  - GPIO Interrupt Status Mask */
+	0x0000,     /* R39  - Comparator Interrupt Status Mask */
+	0x0040,     /* R40  - Clock Control 1 */
+	0x0000,     /* R41  - Clock Control 2 */
+	0x3B00,     /* R42  - FLL Control 1 */
+	0x7086,     /* R43  - FLL Control 2 */
+	0xC226,     /* R44  - FLL Control 3 */
+	0x0000,     /* R45  - FLL Control 4 */
+	0x0000,     /* R46 */
+	0x0000,     /* R47 */
+	0x0000,     /* R48  - DAC Control */
+	0x0000,     /* R49 */
+	0x00C0,     /* R50  - DAC Digital Volume L */
+	0x00C0,     /* R51  - DAC Digital Volume R */
+	0x0000,     /* R52 */
+	0x0040,     /* R53  - DAC LR Rate */
+	0x0000,     /* R54  - DAC Clock Control */
+	0x0000,     /* R55 */
+	0x0000,     /* R56 */
+	0x0000,     /* R57 */
+	0x4000,     /* R58  - DAC Mute */
+	0x0000,     /* R59  - DAC Mute Volume */
+	0x0000,     /* R60  - DAC Side */
+	0x0000,     /* R61 */
+	0x0000,     /* R62 */
+	0x0000,     /* R63 */
+	0x8000,     /* R64  - ADC Control */
+	0x0000,     /* R65 */
+	0x00C0,     /* R66  - ADC Digital Volume L */
+	0x00C0,     /* R67  - ADC Digital Volume R */
+	0x0000,     /* R68  - ADC Divider */
+	0x0000,     /* R69 */
+	0x0040,     /* R70  - ADC LR Rate */
+	0x0000,     /* R71 */
+	0x0303,     /* R72  - Input Control */
+	0x0000,     /* R73  - IN3 Input Control */
+	0x0000,     /* R74  - Mic Bias Control */
+	0x0000,     /* R75 */
+	0x0000,     /* R76  - Output Control */
+	0x0000,     /* R77  - Jack Detect */
+	0x0000,     /* R78  - Anti Pop Control */
+	0x0000,     /* R79 */
+	0x0040,     /* R80  - Left Input Volume */
+	0x0040,     /* R81  - Right Input Volume */
+	0x0000,     /* R82 */
+	0x0000,     /* R83 */
+	0x0000,     /* R84 */
+	0x0000,     /* R85 */
+	0x0000,     /* R86 */
+	0x0000,     /* R87 */
+	0x0800,     /* R88  - Left Mixer Control */
+	0x1000,     /* R89  - Right Mixer Control */
+	0x0000,     /* R90 */
+	0x0000,     /* R91 */
+	0x0000,     /* R92  - OUT3 Mixer Control */
+	0x0000,     /* R93  - OUT4 Mixer Control */
+	0x0000,     /* R94 */
+	0x0000,     /* R95 */
+	0x0000,     /* R96  - Output Left Mixer Volume */
+	0x0000,     /* R97  - Output Right Mixer Volume */
+	0x0000,     /* R98  - Input Mixer Volume L */
+	0x0000,     /* R99  - Input Mixer Volume R */
+	0x0000,     /* R100 - Input Mixer Volume */
+	0x0000,     /* R101 */
+	0x0000,     /* R102 */
+	0x0000,     /* R103 */
+	0x00E4,     /* R104 - LOUT1 Volume */
+	0x00E4,     /* R105 - ROUT1 Volume */
+	0x00E4,     /* R106 - LOUT2 Volume */
+	0x02E4,     /* R107 - ROUT2 Volume */
+	0x0000,     /* R108 */
+	0x0000,     /* R109 */
+	0x0000,     /* R110 */
+	0x0000,     /* R111 - BEEP Volume */
+	0x0A00,     /* R112 - AI Formating */
+	0x0000,     /* R113 - ADC DAC COMP */
+	0x0020,     /* R114 - AI ADC Control */
+	0x0020,     /* R115 - AI DAC Control */
+	0x0000,     /* R116 - AIF Test */
+	0x0000,     /* R117 */
+	0x0000,     /* R118 */
+	0x0000,     /* R119 */
+	0x0000,     /* R120 */
+	0x0000,     /* R121 */
+	0x0000,     /* R122 */
+	0x0000,     /* R123 */
+	0x0000,     /* R124 */
+	0x0000,     /* R125 */
+	0x0000,     /* R126 */
+	0x0000,     /* R127 */
+	0x1FFF,     /* R128 - GPIO Debounce */
+	0x0000,     /* R129 - GPIO Pin pull up Control */
+	0x03FC,     /* R130 - GPIO Pull down Control */
+	0x0000,     /* R131 - GPIO Interrupt Mode */
+	0x0000,     /* R132 */
+	0x0000,     /* R133 - GPIO Control */
+	0x08FB,     /* R134 - GPIO Configuration (i/o) */
+	0x0CFE,     /* R135 - GPIO Pin Polarity / Type */
+	0x0000,     /* R136 */
+	0x0000,     /* R137 */
+	0x0000,     /* R138 */
+	0x0000,     /* R139 */
+	0x0312,     /* R140 - GPIO Function Select 1 */
+	0x0003,     /* R141 - GPIO Function Select 2 */
+	0x2331,     /* R142 - GPIO Function Select 3 */
+	0x0003,     /* R143 - GPIO Function Select 4 */
+	0x0000,     /* R144 - Digitiser Control (1) */
+	0x0002,     /* R145 - Digitiser Control (2) */
+	0x0000,     /* R146 */
+	0x0000,     /* R147 */
+	0x0000,     /* R148 */
+	0x0000,     /* R149 */
+	0x0000,     /* R150 */
+	0x0000,     /* R151 */
+	0x7000,     /* R152 - AUX1 Readback */
+	0x7000,     /* R153 - AUX2 Readback */
+	0x7000,     /* R154 - AUX3 Readback */
+	0x7000,     /* R155 - AUX4 Readback */
+	0x0000,     /* R156 - USB Voltage Readback */
+	0x0000,     /* R157 - LINE Voltage Readback */
+	0x0000,     /* R158 - BATT Voltage Readback */
+	0x0000,     /* R159 - Chip Temp Readback */
+	0x0000,     /* R160 */
+	0x0000,     /* R161 */
+	0x0000,     /* R162 */
+	0x0000,     /* R163 - Generic Comparator Control */
+	0x0000,     /* R164 - Generic comparator 1 */
+	0x0000,     /* R165 - Generic comparator 2 */
+	0x0000,     /* R166 - Generic comparator 3 */
+	0x0000,     /* R167 - Generic comparator 4 */
+	0xA00F,     /* R168 - Battery Charger Control 1 */
+	0x0B06,     /* R169 - Battery Charger Control 2 */
+	0x0000,     /* R170 - Battery Charger Control 3 */
+	0x0000,     /* R171 */
+	0x0000,     /* R172 - Current Sink Driver A */
+	0x0000,     /* R173 - CSA Flash control */
+	0x0000,     /* R174 - Current Sink Driver B */
+	0x0000,     /* R175 - CSB Flash control */
+	0x0000,     /* R176 - DCDC/LDO requested */
+	0x002D,     /* R177 - DCDC Active options */
+	0x0000,     /* R178 - DCDC Sleep options */
+	0x0025,     /* R179 - Power-check comparator */
+	0x000E,     /* R180 - DCDC1 Control */
+	0x0400,     /* R181 - DCDC1 Timeouts */
+	0x1006,     /* R182 - DCDC1 Low Power */
+	0x0018,     /* R183 - DCDC2 Control */
+	0x0000,     /* R184 - DCDC2 Timeouts */
+	0x0000,     /* R185 */
+	0x002E,     /* R186 - DCDC3 Control */
+	0x0800,     /* R187 - DCDC3 Timeouts */
+	0x0006,     /* R188 - DCDC3 Low Power */
+	0x000E,     /* R189 - DCDC4 Control */
+	0x0800,     /* R190 - DCDC4 Timeouts */
+	0x0006,     /* R191 - DCDC4 Low Power */
+	0x0008,     /* R192 - DCDC5 Control */
+	0x0000,     /* R193 - DCDC5 Timeouts */
+	0x0000,     /* R194 */
+	0x0026,     /* R195 - DCDC6 Control */
+	0x0C00,     /* R196 - DCDC6 Timeouts */
+	0x0006,     /* R197 - DCDC6 Low Power */
+	0x0000,     /* R198 */
+	0x0003,     /* R199 - Limit Switch Control */
+	0x001A,     /* R200 - LDO1 Control */
+	0x0800,     /* R201 - LDO1 Timeouts */
+	0x001C,     /* R202 - LDO1 Low Power */
+	0x0010,     /* R203 - LDO2 Control */
+	0x0800,     /* R204 - LDO2 Timeouts */
+	0x001C,     /* R205 - LDO2 Low Power */
+	0x000A,     /* R206 - LDO3 Control */
+	0x0C00,     /* R207 - LDO3 Timeouts */
+	0x001C,     /* R208 - LDO3 Low Power */
+	0x001A,     /* R209 - LDO4 Control */
+	0x0800,     /* R210 - LDO4 Timeouts */
+	0x001C,     /* R211 - LDO4 Low Power */
+	0x0000,     /* R212 */
+	0x0000,     /* R213 */
+	0x0000,     /* R214 */
+	0x0000,     /* R215 - VCC_FAULT Masks */
+	0x001F,     /* R216 - Main Bandgap Control */
+	0x0000,     /* R217 - OSC Control */
+	0x9000,     /* R218 - RTC Tick Control */
+	0x0000,     /* R219 */
+	0x4000,     /* R220 - RAM BIST 1 */
+	0x0000,     /* R221 */
+	0x0000,     /* R222 */
+	0x0000,     /* R223 */
+	0x0000,     /* R224 */
+	0x0000,     /* R225 - DCDC/LDO status */
+	0x0000,     /* R226 */
+	0x0000,     /* R227 */
+	0x0000,     /* R228 */
+	0x0000,     /* R229 */
+	0xE000,     /* R230 - GPIO Pin Status */
+	0x0000,     /* R231 */
+	0x0000,     /* R232 */
+	0x0000,     /* R233 */
+	0x0000,     /* R234 */
+	0x0000,     /* R235 */
+	0x0000,     /* R236 */
+	0x0000,     /* R237 */
+	0x0000,     /* R238 */
+	0x0000,     /* R239 */
+	0x0000,     /* R240 */
+	0x0000,     /* R241 */
+	0x0000,     /* R242 */
+	0x0000,     /* R243 */
+	0x0000,     /* R244 */
+	0x0000,     /* R245 */
+	0x0000,     /* R246 */
+	0x0000,     /* R247 */
+	0x0000,     /* R248 */
+	0x0000,     /* R249 */
+	0x0000,     /* R250 */
+	0x0000,     /* R251 */
+	0x0000,     /* R252 */
+	0x0000,     /* R253 */
+	0x0000,     /* R254 */
+	0x0000,     /* R255 */
+};
+#endif
+
+#ifdef CONFIG_MFD_WM8350_CONFIG_MODE_3
+
+#undef WM8350_HAVE_CONFIG_MODE
+#define WM8350_HAVE_CONFIG_MODE
+
+const u16 wm8350_mode3_defaults[] = {
+	0x17FF,     /* R0   - Reset/ID */
+	0x1000,     /* R1   - ID */
+	0x0000,     /* R2 */
+	0x1000,     /* R3   - System Control 1 */
+	0x0004,     /* R4   - System Control 2 */
+	0x0000,     /* R5   - System Hibernate */
+	0x8A00,     /* R6   - Interface Control */
+	0x0000,     /* R7 */
+	0x8000,     /* R8   - Power mgmt (1) */
+	0x0000,     /* R9   - Power mgmt (2) */
+	0x0000,     /* R10  - Power mgmt (3) */
+	0x2000,     /* R11  - Power mgmt (4) */
+	0x0E00,     /* R12  - Power mgmt (5) */
+	0x0000,     /* R13  - Power mgmt (6) */
+	0x0000,     /* R14  - Power mgmt (7) */
+	0x0000,     /* R15 */
+	0x0000,     /* R16  - RTC Seconds/Minutes */
+	0x0100,     /* R17  - RTC Hours/Day */
+	0x0101,     /* R18  - RTC Date/Month */
+	0x1400,     /* R19  - RTC Year */
+	0x0000,     /* R20  - Alarm Seconds/Minutes */
+	0x0000,     /* R21  - Alarm Hours/Day */
+	0x0000,     /* R22  - Alarm Date/Month */
+	0x0320,     /* R23  - RTC Time Control */
+	0x0000,     /* R24  - System Interrupts */
+	0x0000,     /* R25  - Interrupt Status 1 */
+	0x0000,     /* R26  - Interrupt Status 2 */
+	0x0000,     /* R27  - Power Up Interrupt Status */
+	0x0000,     /* R28  - Under Voltage Interrupt status */
+	0x0000,     /* R29  - Over Current Interrupt status */
+	0x0000,     /* R30  - GPIO Interrupt Status */
+	0x0000,     /* R31  - Comparator Interrupt Status */
+	0x3FFF,     /* R32  - System Interrupts Mask */
+	0x0000,     /* R33  - Interrupt Status 1 Mask */
+	0x0000,     /* R34  - Interrupt Status 2 Mask */
+	0x0000,     /* R35  - Power Up Interrupt Status Mask */
+	0x0000,     /* R36  - Under Voltage Interrupt status Mask */
+	0x0000,     /* R37  - Over Current Interrupt status Mask */
+	0x0000,     /* R38  - GPIO Interrupt Status Mask */
+	0x0000,     /* R39  - Comparator Interrupt Status Mask */
+	0x0040,     /* R40  - Clock Control 1 */
+	0x0000,     /* R41  - Clock Control 2 */
+	0x3B00,     /* R42  - FLL Control 1 */
+	0x7086,     /* R43  - FLL Control 2 */
+	0xC226,     /* R44  - FLL Control 3 */
+	0x0000,     /* R45  - FLL Control 4 */
+	0x0000,     /* R46 */
+	0x0000,     /* R47 */
+	0x0000,     /* R48  - DAC Control */
+	0x0000,     /* R49 */
+	0x00C0,     /* R50  - DAC Digital Volume L */
+	0x00C0,     /* R51  - DAC Digital Volume R */
+	0x0000,     /* R52 */
+	0x0040,     /* R53  - DAC LR Rate */
+	0x0000,     /* R54  - DAC Clock Control */
+	0x0000,     /* R55 */
+	0x0000,     /* R56 */
+	0x0000,     /* R57 */
+	0x4000,     /* R58  - DAC Mute */
+	0x0000,     /* R59  - DAC Mute Volume */
+	0x0000,     /* R60  - DAC Side */
+	0x0000,     /* R61 */
+	0x0000,     /* R62 */
+	0x0000,     /* R63 */
+	0x8000,     /* R64  - ADC Control */
+	0x0000,     /* R65 */
+	0x00C0,     /* R66  - ADC Digital Volume L */
+	0x00C0,     /* R67  - ADC Digital Volume R */
+	0x0000,     /* R68  - ADC Divider */
+	0x0000,     /* R69 */
+	0x0040,     /* R70  - ADC LR Rate */
+	0x0000,     /* R71 */
+	0x0303,     /* R72  - Input Control */
+	0x0000,     /* R73  - IN3 Input Control */
+	0x0000,     /* R74  - Mic Bias Control */
+	0x0000,     /* R75 */
+	0x0000,     /* R76  - Output Control */
+	0x0000,     /* R77  - Jack Detect */
+	0x0000,     /* R78  - Anti Pop Control */
+	0x0000,     /* R79 */
+	0x0040,     /* R80  - Left Input Volume */
+	0x0040,     /* R81  - Right Input Volume */
+	0x0000,     /* R82 */
+	0x0000,     /* R83 */
+	0x0000,     /* R84 */
+	0x0000,     /* R85 */
+	0x0000,     /* R86 */
+	0x0000,     /* R87 */
+	0x0800,     /* R88  - Left Mixer Control */
+	0x1000,     /* R89  - Right Mixer Control */
+	0x0000,     /* R90 */
+	0x0000,     /* R91 */
+	0x0000,     /* R92  - OUT3 Mixer Control */
+	0x0000,     /* R93  - OUT4 Mixer Control */
+	0x0000,     /* R94 */
+	0x0000,     /* R95 */
+	0x0000,     /* R96  - Output Left Mixer Volume */
+	0x0000,     /* R97  - Output Right Mixer Volume */
+	0x0000,     /* R98  - Input Mixer Volume L */
+	0x0000,     /* R99  - Input Mixer Volume R */
+	0x0000,     /* R100 - Input Mixer Volume */
+	0x0000,     /* R101 */
+	0x0000,     /* R102 */
+	0x0000,     /* R103 */
+	0x00E4,     /* R104 - LOUT1 Volume */
+	0x00E4,     /* R105 - ROUT1 Volume */
+	0x00E4,     /* R106 - LOUT2 Volume */
+	0x02E4,     /* R107 - ROUT2 Volume */
+	0x0000,     /* R108 */
+	0x0000,     /* R109 */
+	0x0000,     /* R110 */
+	0x0000,     /* R111 - BEEP Volume */
+	0x0A00,     /* R112 - AI Formating */
+	0x0000,     /* R113 - ADC DAC COMP */
+	0x0020,     /* R114 - AI ADC Control */
+	0x0020,     /* R115 - AI DAC Control */
+	0x0000,     /* R116 - AIF Test */
+	0x0000,     /* R117 */
+	0x0000,     /* R118 */
+	0x0000,     /* R119 */
+	0x0000,     /* R120 */
+	0x0000,     /* R121 */
+	0x0000,     /* R122 */
+	0x0000,     /* R123 */
+	0x0000,     /* R124 */
+	0x0000,     /* R125 */
+	0x0000,     /* R126 */
+	0x0000,     /* R127 */
+	0x1FFF,     /* R128 - GPIO Debounce */
+	0x0000,     /* R129 - GPIO Pin pull up Control */
+	0x03FC,     /* R130 - GPIO Pull down Control */
+	0x0000,     /* R131 - GPIO Interrupt Mode */
+	0x0000,     /* R132 */
+	0x0000,     /* R133 - GPIO Control */
+	0x0A7B,     /* R134 - GPIO Configuration (i/o) */
+	0x06FE,     /* R135 - GPIO Pin Polarity / Type */
+	0x0000,     /* R136 */
+	0x0000,     /* R137 */
+	0x0000,     /* R138 */
+	0x0000,     /* R139 */
+	0x1312,     /* R140 - GPIO Function Select 1 */
+	0x1030,     /* R141 - GPIO Function Select 2 */
+	0x2231,     /* R142 - GPIO Function Select 3 */
+	0x0003,     /* R143 - GPIO Function Select 4 */
+	0x0000,     /* R144 - Digitiser Control (1) */
+	0x0002,     /* R145 - Digitiser Control (2) */
+	0x0000,     /* R146 */
+	0x0000,     /* R147 */
+	0x0000,     /* R148 */
+	0x0000,     /* R149 */
+	0x0000,     /* R150 */
+	0x0000,     /* R151 */
+	0x7000,     /* R152 - AUX1 Readback */
+	0x7000,     /* R153 - AUX2 Readback */
+	0x7000,     /* R154 - AUX3 Readback */
+	0x7000,     /* R155 - AUX4 Readback */
+	0x0000,     /* R156 - USB Voltage Readback */
+	0x0000,     /* R157 - LINE Voltage Readback */
+	0x0000,     /* R158 - BATT Voltage Readback */
+	0x0000,     /* R159 - Chip Temp Readback */
+	0x0000,     /* R160 */
+	0x0000,     /* R161 */
+	0x0000,     /* R162 */
+	0x0000,     /* R163 - Generic Comparator Control */
+	0x0000,     /* R164 - Generic comparator 1 */
+	0x0000,     /* R165 - Generic comparator 2 */
+	0x0000,     /* R166 - Generic comparator 3 */
+	0x0000,     /* R167 - Generic comparator 4 */
+	0xA00F,     /* R168 - Battery Charger Control 1 */
+	0x0B06,     /* R169 - Battery Charger Control 2 */
+	0x0000,     /* R170 - Battery Charger Control 3 */
+	0x0000,     /* R171 */
+	0x0000,     /* R172 - Current Sink Driver A */
+	0x0000,     /* R173 - CSA Flash control */
+	0x0000,     /* R174 - Current Sink Driver B */
+	0x0000,     /* R175 - CSB Flash control */
+	0x0000,     /* R176 - DCDC/LDO requested */
+	0x002D,     /* R177 - DCDC Active options */
+	0x0000,     /* R178 - DCDC Sleep options */
+	0x0025,     /* R179 - Power-check comparator */
+	0x000E,     /* R180 - DCDC1 Control */
+	0x0400,     /* R181 - DCDC1 Timeouts */
+	0x1006,     /* R182 - DCDC1 Low Power */
+	0x0018,     /* R183 - DCDC2 Control */
+	0x0000,     /* R184 - DCDC2 Timeouts */
+	0x0000,     /* R185 */
+	0x000E,     /* R186 - DCDC3 Control */
+	0x0400,     /* R187 - DCDC3 Timeouts */
+	0x0006,     /* R188 - DCDC3 Low Power */
+	0x0026,     /* R189 - DCDC4 Control */
+	0x0400,     /* R190 - DCDC4 Timeouts */
+	0x0006,     /* R191 - DCDC4 Low Power */
+	0x0008,     /* R192 - DCDC5 Control */
+	0x0000,     /* R193 - DCDC5 Timeouts */
+	0x0000,     /* R194 */
+	0x0026,     /* R195 - DCDC6 Control */
+	0x0400,     /* R196 - DCDC6 Timeouts */
+	0x0006,     /* R197 - DCDC6 Low Power */
+	0x0000,     /* R198 */
+	0x0003,     /* R199 - Limit Switch Control */
+	0x001C,     /* R200 - LDO1 Control */
+	0x0000,     /* R201 - LDO1 Timeouts */
+	0x001C,     /* R202 - LDO1 Low Power */
+	0x001C,     /* R203 - LDO2 Control */
+	0x0400,     /* R204 - LDO2 Timeouts */
+	0x001C,     /* R205 - LDO2 Low Power */
+	0x001C,     /* R206 - LDO3 Control */
+	0x0400,     /* R207 - LDO3 Timeouts */
+	0x001C,     /* R208 - LDO3 Low Power */
+	0x001F,     /* R209 - LDO4 Control */
+	0x0400,     /* R210 - LDO4 Timeouts */
+	0x001C,     /* R211 - LDO4 Low Power */
+	0x0000,     /* R212 */
+	0x0000,     /* R213 */
+	0x0000,     /* R214 */
+	0x0000,     /* R215 - VCC_FAULT Masks */
+	0x001F,     /* R216 - Main Bandgap Control */
+	0x0000,     /* R217 - OSC Control */
+	0x9000,     /* R218 - RTC Tick Control */
+	0x0000,     /* R219 */
+	0x4000,     /* R220 - RAM BIST 1 */
+	0x0000,     /* R221 */
+	0x0000,     /* R222 */
+	0x0000,     /* R223 */
+	0x0000,     /* R224 */
+	0x0000,     /* R225 - DCDC/LDO status */
+	0x0000,     /* R226 */
+	0x0000,     /* R227 */
+	0x0000,     /* R228 */
+	0x0000,     /* R229 */
+	0xE000,     /* R230 - GPIO Pin Status */
+	0x0000,     /* R231 */
+	0x0000,     /* R232 */
+	0x0000,     /* R233 */
+	0x0000,     /* R234 */
+	0x0000,     /* R235 */
+	0x0000,     /* R236 */
+	0x0000,     /* R237 */
+	0x0000,     /* R238 */
+	0x0000,     /* R239 */
+	0x0000,     /* R240 */
+	0x0000,     /* R241 */
+	0x0000,     /* R242 */
+	0x0000,     /* R243 */
+	0x0000,     /* R244 */
+	0x0000,     /* R245 */
+	0x0000,     /* R246 */
+	0x0000,     /* R247 */
+	0x0000,     /* R248 */
+	0x0000,     /* R249 */
+	0x0000,     /* R250 */
+	0x0000,     /* R251 */
+	0x0000,     /* R252 */
+	0x0000,     /* R253 */
+	0x0000,     /* R254 */
+	0x0000,     /* R255 */
+};
+#endif
+
+/* The register defaults for the config mode used must be compiled in but
+ * due to the impact on kernel size it is possible to disable
+ */
+#ifndef WM8350_HAVE_CONFIG_MODE
+#warning No WM8350 config modes supported - select at least one of the
+#warning MFD_WM8350_CONFIG_MODE_n options from the board driver.
+#endif
+
+/*
+ * Access masks.
+ */
+
+const struct wm8350_reg_access wm8350_reg_io_map[] = {
+	/*  read    write volatile */
+	{ 0xFFFF, 0xFFFF, 0xFFFF }, /* R0   - Reset/ID */
+	{ 0x7CFF, 0x0C00, 0x7FFF }, /* R1   - ID */
+	{ 0x0000, 0x0000, 0x0000 }, /* R2 */
+	{ 0xBE3B, 0xBE3B, 0x8000 }, /* R3   - System Control 1 */
+	{ 0xFCF7, 0xFCF7, 0xF800 }, /* R4   - System Control 2 */
+	{ 0x80FF, 0x80FF, 0x8000 }, /* R5   - System Hibernate */
+	{ 0xFB0E, 0xFB0E, 0x0000 }, /* R6   - Interface Control */
+	{ 0x0000, 0x0000, 0x0000 }, /* R7 */
+	{ 0xE537, 0xE537, 0xFFFF }, /* R8   - Power mgmt (1) */
+	{ 0x0FF3, 0x0FF3, 0xFFFF }, /* R9   - Power mgmt (2) */
+	{ 0x008F, 0x008F, 0xFFFF }, /* R10  - Power mgmt (3) */
+	{ 0x6D3C, 0x6D3C, 0xFFFF }, /* R11  - Power mgmt (4) */
+	{ 0x1F8F, 0x1F8F, 0xFFFF }, /* R12  - Power mgmt (5) */
+	{ 0x8F3F, 0x8F3F, 0xFFFF }, /* R13  - Power mgmt (6) */
+	{ 0x0003, 0x0003, 0xFFFF }, /* R14  - Power mgmt (7) */
+	{ 0x0000, 0x0000, 0x0000 }, /* R15 */
+	{ 0x7F7F, 0x7F7F, 0xFFFF }, /* R16  - RTC Seconds/Minutes */
+	{ 0x073F, 0x073F, 0xFFFF }, /* R17  - RTC Hours/Day */
+	{ 0x1F3F, 0x1F3F, 0xFFFF }, /* R18  - RTC Date/Month */
+	{ 0x3FFF, 0x00FF, 0xFFFF }, /* R19  - RTC Year */
+	{ 0x7F7F, 0x7F7F, 0x0000 }, /* R20  - Alarm Seconds/Minutes */
+	{ 0x0F3F, 0x0F3F, 0x0000 }, /* R21  - Alarm Hours/Day */
+	{ 0x1F3F, 0x1F3F, 0x0000 }, /* R22  - Alarm Date/Month */
+	{ 0xEF7F, 0xEA7F, 0xFFFF }, /* R23  - RTC Time Control */
+	{ 0x3BFF, 0x0000, 0xFFFF }, /* R24  - System Interrupts */
+	{ 0xFEE7, 0x0000, 0xFFFF }, /* R25  - Interrupt Status 1 */
+	{ 0x35FF, 0x0000, 0xFFFF }, /* R26  - Interrupt Status 2 */
+	{ 0x0F3F, 0x0000, 0xFFFF }, /* R27  - Power Up Interrupt Status */
+	{ 0x0F3F, 0x0000, 0xFFFF }, /* R28  - Under Voltage Interrupt status */
+	{ 0x8000, 0x0000, 0xFFFF }, /* R29  - Over Current Interrupt status */
+	{ 0x1FFF, 0x0000, 0xFFFF }, /* R30  - GPIO Interrupt Status */
+	{ 0xEF7F, 0x0000, 0xFFFF }, /* R31  - Comparator Interrupt Status */
+	{ 0x3FFF, 0x3FFF, 0x0000 }, /* R32  - System Interrupts Mask */
+	{ 0xFEE7, 0xFEE7, 0x0000 }, /* R33  - Interrupt Status 1 Mask */
+	{ 0xF5FF, 0xF5FF, 0x0000 }, /* R34  - Interrupt Status 2 Mask */
+	{ 0x0F3F, 0x0F3F, 0x0000 }, /* R35  - Power Up Interrupt Status Mask */
+	{ 0x0F3F, 0x0F3F, 0x0000 }, /* R36  - Under Voltage Int status Mask */
+	{ 0x8000, 0x8000, 0x0000 }, /* R37  - Over Current Int status Mask */
+	{ 0x1FFF, 0x1FFF, 0x0000 }, /* R38  - GPIO Interrupt Status Mask */
+	{ 0xEF7F, 0xEF7F, 0x0000 }, /* R39  - Comparator IntStatus Mask */
+	{ 0xC9F7, 0xC9F7, 0xFFFF }, /* R40  - Clock Control 1 */
+	{ 0x8001, 0x8001, 0x0000 }, /* R41  - Clock Control 2 */
+	{ 0xFFF7, 0xFFF7, 0xFFFF }, /* R42  - FLL Control 1 */
+	{ 0xFBFF, 0xFBFF, 0x0000 }, /* R43  - FLL Control 2 */
+	{ 0xFFFF, 0xFFFF, 0x0000 }, /* R44  - FLL Control 3 */
+	{ 0x0033, 0x0033, 0x0000 }, /* R45  - FLL Control 4 */
+	{ 0x0000, 0x0000, 0x0000 }, /* R46 */
+	{ 0x0000, 0x0000, 0x0000 }, /* R47 */
+	{ 0x3033, 0x3033, 0x0000 }, /* R48  - DAC Control */
+	{ 0x0000, 0x0000, 0x0000 }, /* R49 */
+	{ 0x81FF, 0x81FF, 0xFFFF }, /* R50  - DAC Digital Volume L */
+	{ 0x81FF, 0x81FF, 0xFFFF }, /* R51  - DAC Digital Volume R */
+	{ 0x0000, 0x0000, 0x0000 }, /* R52 */
+	{ 0x0FFF, 0x0FFF, 0xFFFF }, /* R53  - DAC LR Rate */
+	{ 0x0017, 0x0017, 0x0000 }, /* R54  - DAC Clock Control */
+	{ 0x0000, 0x0000, 0x0000 }, /* R55 */
+	{ 0x0000, 0x0000, 0x0000 }, /* R56 */
+	{ 0x0000, 0x0000, 0x0000 }, /* R57 */
+	{ 0x4000, 0x4000, 0x0000 }, /* R58  - DAC Mute */
+	{ 0x7000, 0x7000, 0x0000 }, /* R59  - DAC Mute Volume */
+	{ 0x3C00, 0x3C00, 0x0000 }, /* R60  - DAC Side */
+	{ 0x0000, 0x0000, 0x0000 }, /* R61 */
+	{ 0x0000, 0x0000, 0x0000 }, /* R62 */
+	{ 0x0000, 0x0000, 0x0000 }, /* R63 */
+	{ 0x8303, 0x8303, 0xFFFF }, /* R64  - ADC Control */
+	{ 0x0000, 0x0000, 0x0000 }, /* R65 */
+	{ 0x81FF, 0x81FF, 0xFFFF }, /* R66  - ADC Digital Volume L */
+	{ 0x81FF, 0x81FF, 0xFFFF }, /* R67  - ADC Digital Volume R */
+	{ 0x0FFF, 0x0FFF, 0x0000 }, /* R68  - ADC Divider */
+	{ 0x0000, 0x0000, 0x0000 }, /* R69 */
+	{ 0x0FFF, 0x0FFF, 0xFFFF }, /* R70  - ADC LR Rate */
+	{ 0x0000, 0x0000, 0x0000 }, /* R71 */
+	{ 0x0707, 0x0707, 0xFFFF }, /* R72  - Input Control */
+	{ 0xC0C0, 0xC0C0, 0xFFFF }, /* R73  - IN3 Input Control */
+	{ 0xC09F, 0xC09F, 0xFFFF }, /* R74  - Mic Bias Control */
+	{ 0x0000, 0x0000, 0x0000 }, /* R75 */
+	{ 0x0F15, 0x0F15, 0xFFFF }, /* R76  - Output Control */
+	{ 0xC000, 0xC000, 0xFFFF }, /* R77  - Jack Detect */
+	{ 0x03FF, 0x03FF, 0x0000 }, /* R78  - Anti Pop Control */
+	{ 0x0000, 0x0000, 0x0000 }, /* R79 */
+	{ 0xE1FC, 0xE1FC, 0x8000 }, /* R80  - Left Input Volume */
+	{ 0xE1FC, 0xE1FC, 0x8000 }, /* R81  - Right Input Volume */
+	{ 0x0000, 0x0000, 0x0000 }, /* R82 */
+	{ 0x0000, 0x0000, 0x0000 }, /* R83 */
+	{ 0x0000, 0x0000, 0x0000 }, /* R84 */
+	{ 0x0000, 0x0000, 0x0000 }, /* R85 */
+	{ 0x0000, 0x0000, 0x0000 }, /* R86 */
+	{ 0x0000, 0x0000, 0x0000 }, /* R87 */
+	{ 0x9807, 0x9807, 0xFFFF }, /* R88  - Left Mixer Control */
+	{ 0x980B, 0x980B, 0xFFFF }, /* R89  - Right Mixer Control */
+	{ 0x0000, 0x0000, 0x0000 }, /* R90 */
+	{ 0x0000, 0x0000, 0x0000 }, /* R91 */
+	{ 0x8909, 0x8909, 0xFFFF }, /* R92  - OUT3 Mixer Control */
+	{ 0x9E07, 0x9E07, 0xFFFF }, /* R93  - OUT4 Mixer Control */
+	{ 0x0000, 0x0000, 0x0000 }, /* R94 */
+	{ 0x0000, 0x0000, 0x0000 }, /* R95 */
+	{ 0x0EEE, 0x0EEE, 0x0000 }, /* R96  - Output Left Mixer Volume */
+	{ 0xE0EE, 0xE0EE, 0x0000 }, /* R97  - Output Right Mixer Volume */
+	{ 0x0E0F, 0x0E0F, 0x0000 }, /* R98  - Input Mixer Volume L */
+	{ 0xE0E1, 0xE0E1, 0x0000 }, /* R99  - Input Mixer Volume R */
+	{ 0x800E, 0x800E, 0x0000 }, /* R100 - Input Mixer Volume */
+	{ 0x0000, 0x0000, 0x0000 }, /* R101 */
+	{ 0x0000, 0x0000, 0x0000 }, /* R102 */
+	{ 0x0000, 0x0000, 0x0000 }, /* R103 */
+	{ 0xE1FC, 0xE1FC, 0xFFFF }, /* R104 - LOUT1 Volume */
+	{ 0xE1FC, 0xE1FC, 0xFFFF }, /* R105 - ROUT1 Volume */
+	{ 0xE1FC, 0xE1FC, 0xFFFF }, /* R106 - LOUT2 Volume */
+	{ 0xE7FC, 0xE7FC, 0xFFFF }, /* R107 - ROUT2 Volume */
+	{ 0x0000, 0x0000, 0x0000 }, /* R108 */
+	{ 0x0000, 0x0000, 0x0000 }, /* R109 */
+	{ 0x0000, 0x0000, 0x0000 }, /* R110 */
+	{ 0x80E0, 0x80E0, 0xFFFF }, /* R111 - BEEP Volume */
+	{ 0xBF00, 0xBF00, 0x0000 }, /* R112 - AI Formating */
+	{ 0x00F1, 0x00F1, 0x0000 }, /* R113 - ADC DAC COMP */
+	{ 0x00F8, 0x00F8, 0x0000 }, /* R114 - AI ADC Control */
+	{ 0x40FB, 0x40FB, 0x0000 }, /* R115 - AI DAC Control */
+	{ 0x7C30, 0x7C30, 0x0000 }, /* R116 - AIF Test */
+	{ 0x0000, 0x0000, 0x0000 }, /* R117 */
+	{ 0x0000, 0x0000, 0x0000 }, /* R118 */
+	{ 0x0000, 0x0000, 0x0000 }, /* R119 */
+	{ 0x0000, 0x0000, 0x0000 }, /* R120 */
+	{ 0x0000, 0x0000, 0x0000 }, /* R121 */
+	{ 0x0000, 0x0000, 0x0000 }, /* R122 */
+	{ 0x0000, 0x0000, 0x0000 }, /* R123 */
+	{ 0x0000, 0x0000, 0x0000 }, /* R124 */
+	{ 0x0000, 0x0000, 0x0000 }, /* R125 */
+	{ 0x0000, 0x0000, 0x0000 }, /* R126 */
+	{ 0x0000, 0x0000, 0x0000 }, /* R127 */
+	{ 0x1FFF, 0x1FFF, 0x0000 }, /* R128 - GPIO Debounce */
+	{ 0x1FFF, 0x1FFF, 0x0000 }, /* R129 - GPIO Pin pull up Control */
+	{ 0x1FFF, 0x1FFF, 0x0000 }, /* R130 - GPIO Pull down Control */
+	{ 0x1FFF, 0x1FFF, 0x0000 }, /* R131 - GPIO Interrupt Mode */
+	{ 0x0000, 0x0000, 0x0000 }, /* R132 */
+	{ 0x00C0, 0x00C0, 0x0000 }, /* R133 - GPIO Control */
+	{ 0x1FFF, 0x1FFF, 0x0000 }, /* R134 - GPIO Configuration (i/o) */
+	{ 0x1FFF, 0x1FFF, 0x0000 }, /* R135 - GPIO Pin Polarity / Type */
+	{ 0x0000, 0x0000, 0x0000 }, /* R136 */
+	{ 0x0000, 0x0000, 0x0000 }, /* R137 */
+	{ 0x0000, 0x0000, 0x0000 }, /* R138 */
+	{ 0x0000, 0x0000, 0x0000 }, /* R139 */
+	{ 0xFFFF, 0xFFFF, 0x0000 }, /* R140 - GPIO Function Select 1 */
+	{ 0xFFFF, 0xFFFF, 0x0000 }, /* R141 - GPIO Function Select 2 */
+	{ 0xFFFF, 0xFFFF, 0x0000 }, /* R142 - GPIO Function Select 3 */
+	{ 0x000F, 0x000F, 0x0000 }, /* R143 - GPIO Function Select 4 */
+	{ 0xF0FF, 0xF0FF, 0xA000 }, /* R144 - Digitiser Control (1) */
+	{ 0x3707, 0x3707, 0x0000 }, /* R145 - Digitiser Control (2) */
+	{ 0x0000, 0x0000, 0x0000 }, /* R146 */
+	{ 0x0000, 0x0000, 0x0000 }, /* R147 */
+	{ 0x0000, 0x0000, 0x0000 }, /* R148 */
+	{ 0x0000, 0x0000, 0x0000 }, /* R149 */
+	{ 0x0000, 0x0000, 0x0000 }, /* R150 */
+	{ 0x0000, 0x0000, 0x0000 }, /* R151 */
+	{ 0x7FFF, 0x7000, 0xFFFF }, /* R152 - AUX1 Readback */
+	{ 0x7FFF, 0x7000, 0xFFFF }, /* R153 - AUX2 Readback */
+	{ 0x7FFF, 0x7000, 0xFFFF }, /* R154 - AUX3 Readback */
+	{ 0x7FFF, 0x7000, 0xFFFF }, /* R155 - AUX4 Readback */
+	{ 0x0FFF, 0x0000, 0xFFFF }, /* R156 - USB Voltage Readback */
+	{ 0x0FFF, 0x0000, 0xFFFF }, /* R157 - LINE Voltage Readback */
+	{ 0x0FFF, 0x0000, 0xFFFF }, /* R158 - BATT Voltage Readback */
+	{ 0x0FFF, 0x0000, 0xFFFF }, /* R159 - Chip Temp Readback */
+	{ 0x0000, 0x0000, 0x0000 }, /* R160 */
+	{ 0x0000, 0x0000, 0x0000 }, /* R161 */
+	{ 0x0000, 0x0000, 0x0000 }, /* R162 */
+	{ 0x000F, 0x000F, 0x0000 }, /* R163 - Generic Comparator Control */
+	{ 0xFFFF, 0xFFFF, 0x0000 }, /* R164 - Generic comparator 1 */
+	{ 0xFFFF, 0xFFFF, 0x0000 }, /* R165 - Generic comparator 2 */
+	{ 0xFFFF, 0xFFFF, 0x0000 }, /* R166 - Generic comparator 3 */
+	{ 0xFFFF, 0xFFFF, 0x0000 }, /* R167 - Generic comparator 4 */
+	{ 0xBFFF, 0xBFFF, 0x8000 }, /* R168 - Battery Charger Control 1 */
+	{ 0xFFFF, 0x4FFF, 0xB000 }, /* R169 - Battery Charger Control 2 */
+	{ 0x007F, 0x007F, 0x0000 }, /* R170 - Battery Charger Control 3 */
+	{ 0x0000, 0x0000, 0x0000 }, /* R171 */
+	{ 0x903F, 0x903F, 0xFFFF }, /* R172 - Current Sink Driver A */
+	{ 0xE333, 0xE333, 0xFFFF }, /* R173 - CSA Flash control */
+	{ 0x903F, 0x903F, 0xFFFF }, /* R174 - Current Sink Driver B */
+	{ 0xE333, 0xE333, 0xFFFF }, /* R175 - CSB Flash control */
+	{ 0x8F3F, 0x8F3F, 0xFFFF }, /* R176 - DCDC/LDO requested */
+	{ 0x332D, 0x332D, 0x0000 }, /* R177 - DCDC Active options */
+	{ 0x002D, 0x002D, 0x0000 }, /* R178 - DCDC Sleep options */
+	{ 0x5177, 0x5177, 0x8000 }, /* R179 - Power-check comparator */
+	{ 0x047F, 0x047F, 0x0000 }, /* R180 - DCDC1 Control */
+	{ 0xFFC0, 0xFFC0, 0x0000 }, /* R181 - DCDC1 Timeouts */
+	{ 0x737F, 0x737F, 0x0000 }, /* R182 - DCDC1 Low Power */
+	{ 0x535B, 0x535B, 0x0000 }, /* R183 - DCDC2 Control */
+	{ 0xFFC0, 0xFFC0, 0x0000 }, /* R184 - DCDC2 Timeouts */
+	{ 0x0000, 0x0000, 0x0000 }, /* R185 */
+	{ 0x047F, 0x047F, 0x0000 }, /* R186 - DCDC3 Control */
+	{ 0xFFC0, 0xFFC0, 0x0000 }, /* R187 - DCDC3 Timeouts */
+	{ 0x737F, 0x737F, 0x0000 }, /* R188 - DCDC3 Low Power */
+	{ 0x047F, 0x047F, 0x0000 }, /* R189 - DCDC4 Control */
+	{ 0xFFC0, 0xFFC0, 0x0000 }, /* R190 - DCDC4 Timeouts */
+	{ 0x737F, 0x737F, 0x0000 }, /* R191 - DCDC4 Low Power */
+	{ 0x535B, 0x535B, 0x0000 }, /* R192 - DCDC5 Control */
+	{ 0xFFC0, 0xFFC0, 0x0000 }, /* R193 - DCDC5 Timeouts */
+	{ 0x0000, 0x0000, 0x0000 }, /* R194 */
+	{ 0x047F, 0x047F, 0x0000 }, /* R195 - DCDC6 Control */
+	{ 0xFFC0, 0xFFC0, 0x0000 }, /* R196 - DCDC6 Timeouts */
+	{ 0x737F, 0x737F, 0x0000 }, /* R197 - DCDC6 Low Power */
+	{ 0x0000, 0x0000, 0x0000 }, /* R198 */
+	{ 0xFFD3, 0xFFD3, 0x0000 }, /* R199 - Limit Switch Control */
+	{ 0x441F, 0x441F, 0x0000 }, /* R200 - LDO1 Control */
+	{ 0xFFC0, 0xFFC0, 0x0000 }, /* R201 - LDO1 Timeouts */
+	{ 0x331F, 0x331F, 0x0000 }, /* R202 - LDO1 Low Power */
+	{ 0x441F, 0x441F, 0x0000 }, /* R203 - LDO2 Control */
+	{ 0xFFC0, 0xFFC0, 0x0000 }, /* R204 - LDO2 Timeouts */
+	{ 0x331F, 0x331F, 0x0000 }, /* R205 - LDO2 Low Power */
+	{ 0x441F, 0x441F, 0x0000 }, /* R206 - LDO3 Control */
+	{ 0xFFC0, 0xFFC0, 0x0000 }, /* R207 - LDO3 Timeouts */
+	{ 0x331F, 0x331F, 0x0000 }, /* R208 - LDO3 Low Power */
+	{ 0x441F, 0x441F, 0x0000 }, /* R209 - LDO4 Control */
+	{ 0xFFC0, 0xFFC0, 0x0000 }, /* R210 - LDO4 Timeouts */
+	{ 0x331F, 0x331F, 0x0000 }, /* R211 - LDO4 Low Power */
+	{ 0x0000, 0x0000, 0x0000 }, /* R212 */
+	{ 0x0000, 0x0000, 0x0000 }, /* R213 */
+	{ 0x0000, 0x0000, 0x0000 }, /* R214 */
+	{ 0x8F3F, 0x8F3F, 0x0000 }, /* R215 - VCC_FAULT Masks */
+	{ 0xFF3F, 0xE03F, 0x0000 }, /* R216 - Main Bandgap Control */
+	{ 0xEF2F, 0xE02F, 0x0000 }, /* R217 - OSC Control */
+	{ 0xF3FF, 0xB3FF, 0xc000 }, /* R218 - RTC Tick Control */
+	{ 0xFFFF, 0xFFFF, 0xFFFF }, /* R219 */
+	{ 0x09FF, 0x01FF, 0x0000 }, /* R220 - RAM BIST 1 */
+	{ 0x0000, 0x0000, 0x0000 }, /* R221 */
+	{ 0xFFFF, 0xFFFF, 0xFFFF }, /* R222 */
+	{ 0xFFFF, 0xFFFF, 0xFFFF }, /* R223 */
+	{ 0x0000, 0x0000, 0x0000 }, /* R224 */
+	{ 0x8F3F, 0x0000, 0xFFFF }, /* R225 - DCDC/LDO status */
+	{ 0x0000, 0x0000, 0x0000 }, /* R226 */
+	{ 0x0000, 0x0000, 0xFFFF }, /* R227 */
+	{ 0x0000, 0x0000, 0x0000 }, /* R228 */
+	{ 0x0000, 0x0000, 0x0000 }, /* R229 */
+	{ 0xFFFF, 0x1FFF, 0xFFFF }, /* R230 - GPIO Pin Status */
+	{ 0xFFFF, 0x1FFF, 0xFFFF }, /* R231 */
+	{ 0xFFFF, 0x1FFF, 0xFFFF }, /* R232 */
+	{ 0xFFFF, 0x1FFF, 0xFFFF }, /* R233 */
+	{ 0x0000, 0x0000, 0x0000 }, /* R234 */
+	{ 0x0000, 0x0000, 0x0000 }, /* R235 */
+	{ 0x0000, 0x0000, 0x0000 }, /* R236 */
+	{ 0x0000, 0x0000, 0x0000 }, /* R237 */
+	{ 0x0000, 0x0000, 0x0000 }, /* R238 */
+	{ 0x0000, 0x0000, 0x0000 }, /* R239 */
+	{ 0x0000, 0x0000, 0x0000 }, /* R240 */
+	{ 0x0000, 0x0000, 0x0000 }, /* R241 */
+	{ 0x0000, 0x0000, 0x0000 }, /* R242 */
+	{ 0x0000, 0x0000, 0x0000 }, /* R243 */
+	{ 0x0000, 0x0000, 0x0000 }, /* R244 */
+	{ 0x0000, 0x0000, 0x0000 }, /* R245 */
+	{ 0x0000, 0x0000, 0x0000 }, /* R246 */
+	{ 0x0000, 0x0000, 0x0000 }, /* R247 */
+	{ 0xFFFF, 0x0010, 0xFFFF }, /* R248 */
+	{ 0x0000, 0x0000, 0x0000 }, /* R249 */
+	{ 0xFFFF, 0x0010, 0xFFFF }, /* R250 */
+	{ 0xFFFF, 0x0010, 0xFFFF }, /* R251 */
+	{ 0x0000, 0x0000, 0x0000 }, /* R252 */
+	{ 0xFFFF, 0x0010, 0xFFFF }, /* R253 */
+	{ 0x0000, 0x0000, 0x0000 }, /* R254 */
+	{ 0x0000, 0x0000, 0x0000 }, /* R255 */
+};
diff --git a/drivers/mfd/wm8400-core.c b/drivers/mfd/wm8400-core.c
new file mode 100644
index 0000000..6a0cedb
--- /dev/null
+++ b/drivers/mfd/wm8400-core.c
@@ -0,0 +1,455 @@
+/*
+ * Core driver for WM8400.
+ *
+ * Copyright 2008 Wolfson Microelectronics PLC.
+ *
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.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/bug.h>
+#include <linux/i2c.h>
+#include <linux/kernel.h>
+#include <linux/mfd/wm8400-private.h>
+#include <linux/mfd/wm8400-audio.h>
+
+static struct {
+	u16  readable;    /* Mask of readable bits */
+	u16  writable;    /* Mask of writable bits */
+	u16  vol;         /* Mask of volatile bits */
+	int  is_codec;    /* Register controlled by codec reset */
+	u16  default_val; /* Value on reset */
+} reg_data[] = {
+	{ 0xFFFF, 0xFFFF, 0x0000, 0, 0x6172 }, /* R0 */
+	{ 0x7000, 0x0000, 0x8000, 0, 0x0000 }, /* R1 */
+	{ 0xFF17, 0xFF17, 0x0000, 0, 0x0000 }, /* R2 */
+	{ 0xEBF3, 0xEBF3, 0x0000, 1, 0x6000 }, /* R3 */
+	{ 0x3CF3, 0x3CF3, 0x0000, 1, 0x0000 }, /* R4  */
+	{ 0xF1F8, 0xF1F8, 0x0000, 1, 0x4050 }, /* R5  */
+	{ 0xFC1F, 0xFC1F, 0x0000, 1, 0x4000 }, /* R6  */
+	{ 0xDFDE, 0xDFDE, 0x0000, 1, 0x01C8 }, /* R7  */
+	{ 0xFCFC, 0xFCFC, 0x0000, 1, 0x0000 }, /* R8  */
+	{ 0xEFFF, 0xEFFF, 0x0000, 1, 0x0040 }, /* R9  */
+	{ 0xEFFF, 0xEFFF, 0x0000, 1, 0x0040 }, /* R10 */
+	{ 0x27F7, 0x27F7, 0x0000, 1, 0x0004 }, /* R11 */
+	{ 0x01FF, 0x01FF, 0x0000, 1, 0x00C0 }, /* R12 */
+	{ 0x01FF, 0x01FF, 0x0000, 1, 0x00C0 }, /* R13 */
+	{ 0x1FEF, 0x1FEF, 0x0000, 1, 0x0000 }, /* R14 */
+	{ 0x0163, 0x0163, 0x0000, 1, 0x0100 }, /* R15 */
+	{ 0x01FF, 0x01FF, 0x0000, 1, 0x00C0 }, /* R16 */
+	{ 0x01FF, 0x01FF, 0x0000, 1, 0x00C0 }, /* R17 */
+	{ 0x1FFF, 0x0FFF, 0x0000, 1, 0x0000 }, /* R18 */
+	{ 0xFFFF, 0xFFFF, 0x0000, 1, 0x1000 }, /* R19 */
+	{ 0xFFFF, 0xFFFF, 0x0000, 1, 0x1010 }, /* R20 */
+	{ 0xFFFF, 0xFFFF, 0x0000, 1, 0x1010 }, /* R21 */
+	{ 0x0FDD, 0x0FDD, 0x0000, 1, 0x8000 }, /* R22 */
+	{ 0x1FFF, 0x1FFF, 0x0000, 1, 0x0800 }, /* R23 */
+	{ 0x0000, 0x01DF, 0x0000, 1, 0x008B }, /* R24 */
+	{ 0x0000, 0x01DF, 0x0000, 1, 0x008B }, /* R25 */
+	{ 0x0000, 0x01DF, 0x0000, 1, 0x008B }, /* R26 */
+	{ 0x0000, 0x01DF, 0x0000, 1, 0x008B }, /* R27 */
+	{ 0x0000, 0x01FF, 0x0000, 1, 0x0000 }, /* R28 */
+	{ 0x0000, 0x01FF, 0x0000, 1, 0x0000 }, /* R29 */
+	{ 0x0000, 0x0077, 0x0000, 1, 0x0066 }, /* R30 */
+	{ 0x0000, 0x0033, 0x0000, 1, 0x0022 }, /* R31 */
+	{ 0x0000, 0x01FF, 0x0000, 1, 0x0079 }, /* R32 */
+	{ 0x0000, 0x01FF, 0x0000, 1, 0x0079 }, /* R33 */
+	{ 0x0000, 0x0003, 0x0000, 1, 0x0003 }, /* R34 */
+	{ 0x0000, 0x01FF, 0x0000, 1, 0x0003 }, /* R35 */
+	{ 0x0000, 0x0000, 0x0000, 0, 0x0000 }, /* R36 */
+	{ 0x0000, 0x003F, 0x0000, 1, 0x0100 }, /* R37 */
+	{ 0x0000, 0x0000, 0x0000, 0, 0x0000 }, /* R38 */
+	{ 0x0000, 0x000F, 0x0000, 0, 0x0000 }, /* R39 */
+	{ 0x0000, 0x00FF, 0x0000, 1, 0x0000 }, /* R40 */
+	{ 0x0000, 0x01B7, 0x0000, 1, 0x0000 }, /* R41 */
+	{ 0x0000, 0x01B7, 0x0000, 1, 0x0000 }, /* R42 */
+	{ 0x0000, 0x01FF, 0x0000, 1, 0x0000 }, /* R43 */
+	{ 0x0000, 0x01FF, 0x0000, 1, 0x0000 }, /* R44 */
+	{ 0x0000, 0x00FD, 0x0000, 1, 0x0000 }, /* R45 */
+	{ 0x0000, 0x00FD, 0x0000, 1, 0x0000 }, /* R46 */
+	{ 0x0000, 0x01FF, 0x0000, 1, 0x0000 }, /* R47 */
+	{ 0x0000, 0x01FF, 0x0000, 1, 0x0000 }, /* R48 */
+	{ 0x0000, 0x01FF, 0x0000, 1, 0x0000 }, /* R49 */
+	{ 0x0000, 0x01FF, 0x0000, 1, 0x0000 }, /* R50 */
+	{ 0x0000, 0x01B3, 0x0000, 1, 0x0180 }, /* R51 */
+	{ 0x0000, 0x0077, 0x0000, 1, 0x0000 }, /* R52 */
+	{ 0x0000, 0x0077, 0x0000, 1, 0x0000 }, /* R53 */
+	{ 0x0000, 0x00FF, 0x0000, 1, 0x0000 }, /* R54 */
+	{ 0x0000, 0x0001, 0x0000, 1, 0x0000 }, /* R55 */
+	{ 0x0000, 0x003F, 0x0000, 1, 0x0000 }, /* R56 */
+	{ 0x0000, 0x004F, 0x0000, 1, 0x0000 }, /* R57 */
+	{ 0x0000, 0x00FD, 0x0000, 1, 0x0000 }, /* R58 */
+	{ 0x0000, 0x0000, 0x0000, 0, 0x0000 }, /* R59 */
+	{ 0x1FFF, 0x1FFF, 0x0000, 1, 0x0000 }, /* R60 */
+	{ 0xFFFF, 0xFFFF, 0x0000, 1, 0x0000 }, /* R61 */
+	{ 0x03FF, 0x03FF, 0x0000, 1, 0x0000 }, /* R62 */
+	{ 0x007F, 0x007F, 0x0000, 1, 0x0000 }, /* R63 */
+	{ 0x0000, 0x0000, 0x0000, 0, 0x0000 }, /* R64 */
+	{ 0xDFFF, 0xDFFF, 0x0000, 0, 0x0000 }, /* R65 */
+	{ 0xDFFF, 0xDFFF, 0x0000, 0, 0x0000 }, /* R66 */
+	{ 0xDFFF, 0xDFFF, 0x0000, 0, 0x0000 }, /* R67 */
+	{ 0xDFFF, 0xDFFF, 0x0000, 0, 0x0000 }, /* R68 */
+	{ 0x0000, 0x0000, 0x0000, 0, 0x0000 }, /* R69 */
+	{ 0xFFFF, 0xFFFF, 0x0000, 0, 0x4400 }, /* R70 */
+	{ 0x23FF, 0x23FF, 0x0000, 0, 0x0000 }, /* R71 */
+	{ 0xFFFF, 0xFFFF, 0x0000, 0, 0x4400 }, /* R72 */
+	{ 0x23FF, 0x23FF, 0x0000, 0, 0x0000 }, /* R73 */
+	{ 0x0000, 0x0000, 0x0000, 0, 0x0000 }, /* R74 */
+	{ 0x000E, 0x000E, 0x0000, 0, 0x0008 }, /* R75 */
+	{ 0xE00F, 0xE00F, 0x0000, 0, 0x0000 }, /* R76 */
+	{ 0x0000, 0x0000, 0x0000, 0, 0x0000 }, /* R77 */
+	{ 0x03C0, 0x03C0, 0x0000, 0, 0x02C0 }, /* R78 */
+	{ 0xFFFF, 0x0000, 0xffff, 0, 0x0000 }, /* R79 */
+	{ 0xFFFF, 0xFFFF, 0x0000, 0, 0x0000 }, /* R80 */
+	{ 0xFFFF, 0x0000, 0xffff, 0, 0x0000 }, /* R81 */
+	{ 0x2BFF, 0x0000, 0xffff, 0, 0x0000 }, /* R82 */
+	{ 0x0000, 0x0000, 0x0000, 0, 0x0000 }, /* R83 */
+	{ 0x80FF, 0x80FF, 0x0000, 0, 0x00ff }, /* R84 */
+};
+
+static int wm8400_read(struct wm8400 *wm8400, u8 reg, int num_regs, u16 *dest)
+{
+	int i, ret = 0;
+
+	BUG_ON(reg + num_regs - 1 > ARRAY_SIZE(wm8400->reg_cache));
+
+	/* If there are any volatile reads then read back the entire block */
+	for (i = reg; i < reg + num_regs; i++)
+		if (reg_data[i].vol) {
+			ret = wm8400->read_dev(wm8400->io_data, reg,
+					       num_regs, dest);
+			if (ret != 0)
+				return ret;
+			for (i = 0; i < num_regs; i++)
+				dest[i] = be16_to_cpu(dest[i]);
+
+			return 0;
+		}
+
+	/* Otherwise use the cache */
+	memcpy(dest, &wm8400->reg_cache[reg], num_regs * sizeof(u16));
+
+	return 0;
+}
+
+static int wm8400_write(struct wm8400 *wm8400, u8 reg, int num_regs,
+			u16 *src)
+{
+	int ret, i;
+
+	BUG_ON(reg + num_regs - 1 > ARRAY_SIZE(wm8400->reg_cache));
+
+	for (i = 0; i < num_regs; i++) {
+		BUG_ON(!reg_data[reg + i].writable);
+		wm8400->reg_cache[reg + i] = src[i];
+		src[i] = cpu_to_be16(src[i]);
+	}
+
+	/* Do the actual I/O */
+	ret = wm8400->write_dev(wm8400->io_data, reg, num_regs, src);
+	if (ret != 0)
+		return -EIO;
+
+	return 0;
+}
+
+/**
+ * wm8400_reg_read - Single register read
+ *
+ * @wm8400: Pointer to wm8400 control structure
+ * @reg:    Register to read
+ *
+ * @return  Read value
+ */
+u16 wm8400_reg_read(struct wm8400 *wm8400, u8 reg)
+{
+	u16 val;
+
+	mutex_lock(&wm8400->io_lock);
+
+	wm8400_read(wm8400, reg, 1, &val);
+
+	mutex_unlock(&wm8400->io_lock);
+
+	return val;
+}
+EXPORT_SYMBOL_GPL(wm8400_reg_read);
+
+int wm8400_block_read(struct wm8400 *wm8400, u8 reg, int count, u16 *data)
+{
+	int ret;
+
+	mutex_lock(&wm8400->io_lock);
+
+	ret = wm8400_read(wm8400, reg, count, data);
+
+	mutex_unlock(&wm8400->io_lock);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(wm8400_block_read);
+
+/**
+ * wm8400_set_bits - Bitmask write
+ *
+ * @wm8400: Pointer to wm8400 control structure
+ * @reg:    Register to access
+ * @mask:   Mask of bits to change
+ * @val:    Value to set for masked bits
+ */
+int wm8400_set_bits(struct wm8400 *wm8400, u8 reg, u16 mask, u16 val)
+{
+	u16 tmp;
+	int ret;
+
+	mutex_lock(&wm8400->io_lock);
+
+	ret = wm8400_read(wm8400, reg, 1, &tmp);
+	tmp = (tmp & ~mask) | val;
+	if (ret == 0)
+		ret = wm8400_write(wm8400, reg, 1, &tmp);
+
+	mutex_unlock(&wm8400->io_lock);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(wm8400_set_bits);
+
+/**
+ * wm8400_reset_codec_reg_cache - Reset cached codec registers to
+ * their default values.
+ */
+void wm8400_reset_codec_reg_cache(struct wm8400 *wm8400)
+{
+	int i;
+
+	mutex_lock(&wm8400->io_lock);
+
+	/* Reset all codec registers to their initial value */
+	for (i = 0; i < ARRAY_SIZE(wm8400->reg_cache); i++)
+		if (reg_data[i].is_codec)
+			wm8400->reg_cache[i] = reg_data[i].default_val;
+
+	mutex_unlock(&wm8400->io_lock);
+}
+EXPORT_SYMBOL_GPL(wm8400_reset_codec_reg_cache);
+
+/*
+ * wm8400_init - Generic initialisation
+ *
+ * The WM8400 can be configured as either an I2C or SPI device.  Probe
+ * functions for each bus set up the accessors then call into this to
+ * set up the device itself.
+ */
+static int wm8400_init(struct wm8400 *wm8400,
+		       struct wm8400_platform_data *pdata)
+{
+	u16 reg;
+	int ret, i;
+
+	mutex_init(&wm8400->io_lock);
+
+	wm8400->dev->driver_data = wm8400;
+
+	/* Check that this is actually a WM8400 */
+	ret = wm8400->read_dev(wm8400->io_data, WM8400_RESET_ID, 1, &reg);
+	if (ret != 0) {
+		dev_err(wm8400->dev, "Chip ID register read failed\n");
+		return -EIO;
+	}
+	if (be16_to_cpu(reg) != reg_data[WM8400_RESET_ID].default_val) {
+		dev_err(wm8400->dev, "Device is not a WM8400, ID is %x\n",
+			be16_to_cpu(reg));
+		return -ENODEV;
+	}
+
+	/* We don't know what state the hardware is in and since this
+	 * is a PMIC we can't reset it safely so initialise the register
+	 * cache from the hardware.
+	 */
+	ret = wm8400->read_dev(wm8400->io_data, 0,
+			       ARRAY_SIZE(wm8400->reg_cache),
+			       wm8400->reg_cache);
+	if (ret != 0) {
+		dev_err(wm8400->dev, "Register cache read failed\n");
+		return -EIO;
+	}
+	for (i = 0; i < ARRAY_SIZE(wm8400->reg_cache); i++)
+		wm8400->reg_cache[i] = be16_to_cpu(wm8400->reg_cache[i]);
+
+	/* If the codec is in reset use hard coded values */
+	if (!(wm8400->reg_cache[WM8400_POWER_MANAGEMENT_1] & WM8400_CODEC_ENA))
+		for (i = 0; i < ARRAY_SIZE(wm8400->reg_cache); i++)
+			if (reg_data[i].is_codec)
+				wm8400->reg_cache[i] = reg_data[i].default_val;
+
+	ret = wm8400_read(wm8400, WM8400_ID, 1, &reg);
+	if (ret != 0) {
+		dev_err(wm8400->dev, "ID register read failed: %d\n", ret);
+		return ret;
+	}
+	reg = (reg & WM8400_CHIP_REV_MASK) >> WM8400_CHIP_REV_SHIFT;
+	dev_info(wm8400->dev, "WM8400 revision %x\n", reg);
+
+	if (pdata && pdata->platform_init) {
+		ret = pdata->platform_init(wm8400->dev);
+		if (ret != 0)
+			dev_err(wm8400->dev, "Platform init failed: %d\n",
+				ret);
+	} else
+		dev_warn(wm8400->dev, "No platform initialisation supplied\n");
+
+	return ret;
+}
+
+static void wm8400_release(struct wm8400 *wm8400)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(wm8400->regulators); i++)
+		if (wm8400->regulators[i].name)
+			platform_device_unregister(&wm8400->regulators[i]);
+}
+
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+static int wm8400_i2c_read(void *io_data, char reg, int count, u16 *dest)
+{
+	struct i2c_client *i2c = io_data;
+	struct i2c_msg xfer[2];
+	int ret;
+
+	/* Write register */
+	xfer[0].addr = i2c->addr;
+	xfer[0].flags = 0;
+	xfer[0].len = 1;
+	xfer[0].buf = &reg;
+
+	/* Read data */
+	xfer[1].addr = i2c->addr;
+	xfer[1].flags = I2C_M_RD;
+	xfer[1].len = count * sizeof(u16);
+	xfer[1].buf = (u8 *)dest;
+
+	ret = i2c_transfer(i2c->adapter, xfer, 2);
+	if (ret == 2)
+		ret = 0;
+	else if (ret >= 0)
+		ret = -EIO;
+
+	return ret;
+}
+
+static int wm8400_i2c_write(void *io_data, char reg, int count, const u16 *src)
+{
+	struct i2c_client *i2c = io_data;
+	u8 *msg;
+	int ret;
+
+	/* We add 1 byte for device register - ideally I2C would gather. */
+	msg = kmalloc((count * sizeof(u16)) + 1, GFP_KERNEL);
+	if (msg == NULL)
+		return -ENOMEM;
+
+	msg[0] = reg;
+	memcpy(&msg[1], src, count * sizeof(u16));
+
+	ret = i2c_master_send(i2c, msg, (count * sizeof(u16)) + 1);
+
+	if (ret == (count * 2) + 1)
+		ret = 0;
+	else if (ret >= 0)
+		ret = -EIO;
+
+	kfree(msg);
+
+	return ret;
+}
+
+static int wm8400_i2c_probe(struct i2c_client *i2c,
+			    const struct i2c_device_id *id)
+{
+	struct wm8400 *wm8400;
+	int ret;
+
+	wm8400 = kzalloc(sizeof(struct wm8400), GFP_KERNEL);
+	if (wm8400 == NULL) {
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	wm8400->io_data = i2c;
+	wm8400->read_dev = wm8400_i2c_read;
+	wm8400->write_dev = wm8400_i2c_write;
+	wm8400->dev = &i2c->dev;
+	i2c_set_clientdata(i2c, wm8400);
+
+	ret = wm8400_init(wm8400, i2c->dev.platform_data);
+	if (ret != 0)
+		goto struct_err;
+
+	return 0;
+
+struct_err:
+	i2c_set_clientdata(i2c, NULL);
+	kfree(wm8400);
+err:
+	return ret;
+}
+
+static int wm8400_i2c_remove(struct i2c_client *i2c)
+{
+	struct wm8400 *wm8400 = i2c_get_clientdata(i2c);
+
+	wm8400_release(wm8400);
+	i2c_set_clientdata(i2c, NULL);
+	kfree(wm8400);
+
+	return 0;
+}
+
+static const struct i2c_device_id wm8400_i2c_id[] = {
+       { "wm8400", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, wm8400_i2c_id);
+
+static struct i2c_driver wm8400_i2c_driver = {
+	.driver = {
+		.name = "WM8400",
+		.owner = THIS_MODULE,
+	},
+	.probe    = wm8400_i2c_probe,
+	.remove   = wm8400_i2c_remove,
+	.id_table = wm8400_i2c_id,
+};
+#endif
+
+static int __init wm8400_module_init(void)
+{
+	int ret = -ENODEV;
+
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+	ret = i2c_add_driver(&wm8400_i2c_driver);
+	if (ret != 0)
+		pr_err("Failed to register I2C driver: %d\n", ret);
+#endif
+
+	return ret;
+}
+module_init(wm8400_module_init);
+
+static void __exit wm8400_module_exit(void)
+{
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+	i2c_del_driver(&wm8400_i2c_driver);
+#endif
+}
+module_exit(wm8400_module_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
diff --git a/drivers/misc/eeepc-laptop.c b/drivers/misc/eeepc-laptop.c
index facdb98..1ee8501 100644
--- a/drivers/misc/eeepc-laptop.c
+++ b/drivers/misc/eeepc-laptop.c
@@ -450,12 +450,14 @@
 	int value = 0;
 
 	read_acpi_int(NULL, EEEPC_EC_FAN_PWM, &value);
+	value = value * 255 / 100;
 	return (value);
 }
 
 static void eeepc_set_fan_pwm(int value)
 {
-	value = SENSORS_LIMIT(value, 0, 100);
+	value = SENSORS_LIMIT(value, 0, 255);
+	value = value * 100 / 255;
 	ec_write(EEEPC_EC_SC02, value);
 }
 
@@ -520,15 +522,23 @@
 	static SENSOR_DEVICE_ATTR(_name, _mode, show_##_name, store_##_name, 0);
 
 EEEPC_CREATE_SENSOR_ATTR(fan1_input, S_IRUGO, eeepc_get_fan_rpm, NULL);
-EEEPC_CREATE_SENSOR_ATTR(fan1_pwm, S_IRUGO | S_IWUSR,
+EEEPC_CREATE_SENSOR_ATTR(pwm1, S_IRUGO | S_IWUSR,
 			 eeepc_get_fan_pwm, eeepc_set_fan_pwm);
 EEEPC_CREATE_SENSOR_ATTR(pwm1_enable, S_IRUGO | S_IWUSR,
 			 eeepc_get_fan_ctrl, eeepc_set_fan_ctrl);
 
+static ssize_t
+show_name(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	return sprintf(buf, "eeepc\n");
+}
+static SENSOR_DEVICE_ATTR(name, S_IRUGO, show_name, NULL, 0);
+
 static struct attribute *hwmon_attributes[] = {
-	&sensor_dev_attr_fan1_pwm.dev_attr.attr,
+	&sensor_dev_attr_pwm1.dev_attr.attr,
 	&sensor_dev_attr_fan1_input.dev_attr.attr,
 	&sensor_dev_attr_pwm1_enable.dev_attr.attr,
+	&sensor_dev_attr_name.dev_attr.attr,
 	NULL
 };
 
diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig
index c0b41e8..f2eeb38 100644
--- a/drivers/mmc/Kconfig
+++ b/drivers/mmc/Kconfig
@@ -3,13 +3,14 @@
 #
 
 menuconfig MMC
-	tristate "MMC/SD card support"
+	tristate "MMC/SD/SDIO card support"
 	depends on HAS_IOMEM
 	help
-	  MMC is the "multi-media card" bus protocol.
+	  This selects MultiMediaCard, Secure Digital and Secure
+	  Digital I/O support.
 
-	  If you want MMC support, you should say Y here and also
-	  to the specific driver for your MMC interface.
+	  If you want MMC/SD/SDIO support, you should say Y here and
+	  also to your specific host controller driver.
 
 config MMC_DEBUG
 	bool "MMC debugging"
diff --git a/drivers/mmc/card/Kconfig b/drivers/mmc/card/Kconfig
index dd0f398..3f2a912 100644
--- a/drivers/mmc/card/Kconfig
+++ b/drivers/mmc/card/Kconfig
@@ -2,7 +2,7 @@
 # MMC/SD card drivers
 #
 
-comment "MMC/SD Card Drivers"
+comment "MMC/SD/SDIO Card Drivers"
 
 config MMC_BLOCK
 	tristate "MMC block device driver"
@@ -34,7 +34,6 @@
 
 config SDIO_UART
 	tristate "SDIO UART/GPS class support"
-	depends on MMC
 	help
 	  SDIO function driver for SDIO cards that implements the UART
 	  class, as well as the GPS class which appears like a UART.
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index 6986f39..24c97d3 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -29,6 +29,7 @@
 #include <linux/blkdev.h>
 #include <linux/mutex.h>
 #include <linux/scatterlist.h>
+#include <linux/string_helpers.h>
 
 #include <linux/mmc/card.h>
 #include <linux/mmc/host.h>
@@ -57,7 +58,6 @@
 	struct mmc_queue queue;
 
 	unsigned int	usage;
-	unsigned int	block_bits;
 	unsigned int	read_only;
 };
 
@@ -83,7 +83,7 @@
 	mutex_lock(&open_lock);
 	md->usage--;
 	if (md->usage == 0) {
-		int devidx = md->disk->first_minor >> MMC_SHIFT;
+		int devidx = MINOR(disk_devt(md->disk)) >> MMC_SHIFT;
 		__clear_bit(devidx, dev_use);
 
 		put_disk(md->disk);
@@ -215,8 +215,7 @@
 	struct mmc_blk_data *md = mq->data;
 	struct mmc_card *card = md->queue.card;
 	struct mmc_blk_request brq;
-	int ret = 1, data_size, i;
-	struct scatterlist *sg;
+	int ret = 1;
 
 	mmc_claim_host(card->host);
 
@@ -232,13 +231,11 @@
 		if (!mmc_card_blockaddr(card))
 			brq.cmd.arg <<= 9;
 		brq.cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
-		brq.data.blksz = 1 << md->block_bits;
+		brq.data.blksz = 512;
 		brq.stop.opcode = MMC_STOP_TRANSMISSION;
 		brq.stop.arg = 0;
 		brq.stop.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
-		brq.data.blocks = req->nr_sectors >> (md->block_bits - 9);
-		if (brq.data.blocks > card->host->max_blk_count)
-			brq.data.blocks = card->host->max_blk_count;
+		brq.data.blocks = req->nr_sectors;
 
 		if (brq.data.blocks > 1) {
 			/* SPI multiblock writes terminate using a special
@@ -270,24 +267,6 @@
 
 		mmc_queue_bounce_pre(mq);
 
-		/*
-		 * Adjust the sg list so it is the same size as the
-		 * request.
-		 */
-		if (brq.data.blocks !=
-		    (req->nr_sectors >> (md->block_bits - 9))) {
-			data_size = brq.data.blocks * brq.data.blksz;
-			for_each_sg(brq.data.sg, sg, brq.data.sg_len, i) {
-				data_size -= sg->length;
-				if (data_size <= 0) {
-					sg->length += data_size;
-					i++;
-					break;
-				}
-			}
-			brq.data.sg_len = i;
-		}
-
 		mmc_wait_for_req(card->host, &brq.mrq);
 
 		mmc_queue_bounce_post(mq);
@@ -372,16 +351,11 @@
 	if (rq_data_dir(req) != READ) {
 		if (mmc_card_sd(card)) {
 			u32 blocks;
-			unsigned int bytes;
 
 			blocks = mmc_sd_num_wr_blocks(card);
 			if (blocks != (u32)-1) {
-				if (card->csd.write_partial)
-					bytes = blocks << md->block_bits;
-				else
-					bytes = blocks << 9;
 				spin_lock_irq(&md->lock);
-				ret = __blk_end_request(req, 0, bytes);
+				ret = __blk_end_request(req, 0, blocks << 9);
 				spin_unlock_irq(&md->lock);
 			}
 		} else {
@@ -431,13 +405,6 @@
 	 */
 	md->read_only = mmc_blk_readonly(card);
 
-	/*
-	 * Both SD and MMC specifications state (although a bit
-	 * unclearly in the MMC case) that a block size of 512
-	 * bytes must always be supported by the card.
-	 */
-	md->block_bits = 9;
-
 	md->disk = alloc_disk(1 << MMC_SHIFT);
 	if (md->disk == NULL) {
 		ret = -ENOMEM;
@@ -475,7 +442,7 @@
 
 	sprintf(md->disk->disk_name, "mmcblk%d", devidx);
 
-	blk_queue_hardsect_size(md->queue.queue, 1 << md->block_bits);
+	blk_queue_hardsect_size(md->queue.queue, 512);
 
 	if (!mmc_card_sd(card) && mmc_card_blockaddr(card)) {
 		/*
@@ -513,7 +480,7 @@
 
 	mmc_claim_host(card->host);
 	cmd.opcode = MMC_SET_BLOCKLEN;
-	cmd.arg = 1 << md->block_bits;
+	cmd.arg = 512;
 	cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC;
 	err = mmc_wait_for_cmd(card->host, &cmd, 5);
 	mmc_release_host(card->host);
@@ -532,6 +499,8 @@
 	struct mmc_blk_data *md;
 	int err;
 
+	char cap_str[10];
+
 	/*
 	 * Check that the card supports the command class(es) we need.
 	 */
@@ -546,10 +515,11 @@
 	if (err)
 		goto out;
 
-	printk(KERN_INFO "%s: %s %s %lluKiB %s\n",
+	string_get_size(get_capacity(md->disk) << 9, STRING_UNITS_2,
+			cap_str, sizeof(cap_str));
+	printk(KERN_INFO "%s: %s %s %s %s\n",
 		md->disk->disk_name, mmc_card_id(card), mmc_card_name(card),
-		(unsigned long long)(get_capacity(md->disk) >> 1),
-		md->read_only ? "(ro)" : "");
+		cap_str, md->read_only ? "(ro)" : "");
 
 	mmc_set_drvdata(card, md);
 	add_disk(md->disk);
@@ -615,14 +585,19 @@
 
 static int __init mmc_blk_init(void)
 {
-	int res = -ENOMEM;
+	int res;
 
 	res = register_blkdev(MMC_BLOCK_MAJOR, "mmc");
 	if (res)
 		goto out;
 
-	return mmc_register_driver(&mmc_driver);
+	res = mmc_register_driver(&mmc_driver);
+	if (res)
+		goto out2;
 
+	return 0;
+ out2:
+	unregister_blkdev(MMC_BLOCK_MAJOR, "mmc");
  out:
 	return res;
 }
diff --git a/drivers/mmc/card/mmc_test.c b/drivers/mmc/card/mmc_test.c
index f26b01d..b92b172 100644
--- a/drivers/mmc/card/mmc_test.c
+++ b/drivers/mmc/card/mmc_test.c
@@ -1040,7 +1040,7 @@
 
 };
 
-static struct mutex mmc_test_lock;
+static DEFINE_MUTEX(mmc_test_lock);
 
 static void mmc_test_run(struct mmc_test_card *test, int testcase)
 {
@@ -1171,8 +1171,6 @@
 	if ((card->type != MMC_TYPE_MMC) && (card->type != MMC_TYPE_SD))
 		return -ENODEV;
 
-	mutex_init(&mmc_test_lock);
-
 	ret = device_create_file(&card->dev, &dev_attr_test);
 	if (ret)
 		return ret;
diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c
index 3dee97e..406989e 100644
--- a/drivers/mmc/card/queue.c
+++ b/drivers/mmc/card/queue.c
@@ -31,7 +31,7 @@
 	/*
 	 * We only like normal block requests.
 	 */
-	if (!blk_fs_request(req) && !blk_pc_request(req)) {
+	if (!blk_fs_request(req)) {
 		blk_dump_rq_flags(req, "MMC bad request");
 		return BLKPREP_KILL;
 	}
@@ -131,6 +131,7 @@
 	mq->req = NULL;
 
 	blk_queue_prep_rq(mq->queue, mmc_prep_request);
+	blk_queue_ordered(mq->queue, QUEUE_ORDERED_DRAIN, NULL);
 
 #ifdef CONFIG_MMC_BLOCK_BOUNCE
 	if (host->max_hw_segs == 1) {
@@ -142,12 +143,19 @@
 			bouncesz = host->max_req_size;
 		if (bouncesz > host->max_seg_size)
 			bouncesz = host->max_seg_size;
+		if (bouncesz > (host->max_blk_count * 512))
+			bouncesz = host->max_blk_count * 512;
 
-		mq->bounce_buf = kmalloc(bouncesz, GFP_KERNEL);
-		if (!mq->bounce_buf) {
-			printk(KERN_WARNING "%s: unable to allocate "
-				"bounce buffer\n", mmc_card_name(card));
-		} else {
+		if (bouncesz > 512) {
+			mq->bounce_buf = kmalloc(bouncesz, GFP_KERNEL);
+			if (!mq->bounce_buf) {
+				printk(KERN_WARNING "%s: unable to "
+					"allocate bounce buffer\n",
+					mmc_card_name(card));
+			}
+		}
+
+		if (mq->bounce_buf) {
 			blk_queue_bounce_limit(mq->queue, BLK_BOUNCE_ANY);
 			blk_queue_max_sectors(mq->queue, bouncesz / 512);
 			blk_queue_max_phys_segments(mq->queue, bouncesz / 512);
@@ -175,7 +183,8 @@
 
 	if (!mq->bounce_buf) {
 		blk_queue_bounce_limit(mq->queue, limit);
-		blk_queue_max_sectors(mq->queue, host->max_req_size / 512);
+		blk_queue_max_sectors(mq->queue,
+			min(host->max_blk_count, host->max_req_size / 512));
 		blk_queue_max_phys_segments(mq->queue, host->max_phys_segs);
 		blk_queue_max_hw_segments(mq->queue, host->max_hw_segs);
 		blk_queue_max_segment_size(mq->queue, host->max_seg_size);
diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c
index 64b05c6..9c50e6f 100644
--- a/drivers/mmc/core/mmc_ops.c
+++ b/drivers/mmc/core/mmc_ops.c
@@ -248,8 +248,12 @@
 
 	sg_init_one(&sg, data_buf, len);
 
-	if (card)
-		mmc_set_data_timeout(&data, card);
+	/*
+	 * The spec states that CSR and CID accesses have a timeout
+	 * of 64 clock cycles.
+	 */
+	data.timeout_ns = 0;
+	data.timeout_clks = 64;
 
 	mmc_wait_for_req(host, &mrq);
 
diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c
index 4eab79e..fb99ccf 100644
--- a/drivers/mmc/core/sdio.c
+++ b/drivers/mmc/core/sdio.c
@@ -165,6 +165,36 @@
 }
 
 /*
+ * Test if the card supports high-speed mode and, if so, switch to it.
+ */
+static int sdio_enable_hs(struct mmc_card *card)
+{
+	int ret;
+	u8 speed;
+
+	if (!(card->host->caps & MMC_CAP_SD_HIGHSPEED))
+		return 0;
+
+	if (!card->cccr.high_speed)
+		return 0;
+
+	ret = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_SPEED, 0, &speed);
+	if (ret)
+		return ret;
+
+	speed |= SDIO_SPEED_EHS;
+
+	ret = mmc_io_rw_direct(card, 1, 0, SDIO_CCCR_SPEED, speed, NULL);
+	if (ret)
+		return ret;
+
+	mmc_card_set_highspeed(card);
+	mmc_set_timing(card->host, MMC_TIMING_SD_HS);
+
+	return 0;
+}
+
+/*
  * Host is being removed. Free up the current card.
  */
 static void mmc_sdio_remove(struct mmc_host *host)
@@ -333,10 +363,26 @@
 		goto remove;
 
 	/*
-	 * No support for high-speed yet, so just set
-	 * the card's maximum speed.
+	 * Switch to high-speed (if supported).
 	 */
-	mmc_set_clock(host, card->cis.max_dtr);
+	err = sdio_enable_hs(card);
+	if (err)
+		goto remove;
+
+	/*
+	 * Change to the card's maximum speed.
+	 */
+	if (mmc_card_highspeed(card)) {
+		/*
+		 * The SDIO specification doesn't mention how
+		 * the CIS transfer speed register relates to
+		 * high-speed, but it seems that 50 MHz is
+		 * mandatory.
+		 */
+		mmc_set_clock(host, 50000000);
+	} else {
+		mmc_set_clock(host, card->cis.max_dtr);
+	}
 
 	/*
 	 * Switch to wider bus (if supported).
diff --git a/drivers/mmc/core/sdio_irq.c b/drivers/mmc/core/sdio_irq.c
index c292e12..bb192f9 100644
--- a/drivers/mmc/core/sdio_irq.c
+++ b/drivers/mmc/core/sdio_irq.c
@@ -5,6 +5,8 @@
  * Created:     June 18, 2007
  * Copyright:   MontaVista Software Inc.
  *
+ * Copyright 2008 Pierre Ossman
+ *
  * This program is free software; you can redistribute it and/or 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
@@ -107,11 +109,14 @@
 
 		/*
 		 * Give other threads a chance to run in the presence of
-		 * errors.  FIXME: determine if due to card removal and
-		 * possibly exit this thread if so.
+		 * errors.
 		 */
-		if (ret < 0)
-			ssleep(1);
+		if (ret < 0) {
+			set_current_state(TASK_INTERRUPTIBLE);
+			if (!kthread_should_stop())
+				schedule_timeout(HZ);
+			set_current_state(TASK_RUNNING);
+		}
 
 		/*
 		 * Adaptive polling frequency based on the assumption
@@ -154,7 +159,8 @@
 	if (!host->sdio_irqs++) {
 		atomic_set(&host->sdio_irq_thread_abort, 0);
 		host->sdio_irq_thread =
-			kthread_run(sdio_irq_thread, host, "ksdiorqd");
+			kthread_run(sdio_irq_thread, host, "ksdioirqd/%s",
+				mmc_hostname(host));
 		if (IS_ERR(host->sdio_irq_thread)) {
 			int err = PTR_ERR(host->sdio_irq_thread);
 			host->sdio_irqs--;
diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index ea8d7a3..dfa585f 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -2,7 +2,7 @@
 # MMC/SD host controller drivers
 #
 
-comment "MMC/SD Host Controller Drivers"
+comment "MMC/SD/SDIO Host Controller Drivers"
 
 config MMC_ARMMMCI
 	tristate "ARM AMBA Multimedia Card Interface support"
@@ -114,6 +114,17 @@
 
 	  If unsure, say N.
 
+config MMC_ATMELMCI_DMA
+	bool "Atmel MCI DMA support (EXPERIMENTAL)"
+	depends on MMC_ATMELMCI && DMA_ENGINE && EXPERIMENTAL
+	help
+	  Say Y here to have the Atmel MCI driver use a DMA engine to
+	  do data transfers and thus increase the throughput and
+	  reduce the CPU utilization. Note that this is highly
+	  experimental and may cause the driver to lock up.
+
+	  If unsure, say N.
+
 config MMC_IMX
 	tristate "Motorola i.MX Multimedia Card Interface support"
 	depends on ARCH_IMX
@@ -141,21 +152,22 @@
 	  module will be called tifm_sd.
 
 config MMC_SPI
-	tristate "MMC/SD over SPI"
-	depends on MMC && SPI_MASTER && !HIGHMEM && HAS_DMA
+	tristate "MMC/SD/SDIO over SPI"
+	depends on SPI_MASTER && !HIGHMEM && HAS_DMA
 	select CRC7
 	select CRC_ITU_T
 	help
-	  Some systems accss MMC/SD cards using a SPI controller instead of
-	  using a "native" MMC/SD controller.  This has a disadvantage of
-	  being relatively high overhead, but a compensating advantage of
-	  working on many systems without dedicated MMC/SD controllers.
+	  Some systems accss MMC/SD/SDIO cards using a SPI controller
+	  instead of using a "native" MMC/SD/SDIO controller.  This has a
+	  disadvantage of being relatively high overhead, but a compensating
+	  advantage of working on many systems without dedicated MMC/SD/SDIO
+	  controllers.
 
 	  If unsure, or if your system has no SPI master driver, say N.
 
 config MMC_S3C
 	tristate "Samsung S3C SD/MMC Card Interface support"
-	depends on ARCH_S3C2410 && MMC
+	depends on ARCH_S3C2410
 	help
 	  This selects a driver for the MCI interface found in
           Samsung's S3C2410, S3C2412, S3C2440, S3C2442 CPUs.
@@ -166,7 +178,7 @@
 
 config MMC_SDRICOH_CS
 	tristate "MMC/SD driver for Ricoh Bay1Controllers (EXPERIMENTAL)"
-	depends on EXPERIMENTAL && MMC && PCI && PCMCIA
+	depends on EXPERIMENTAL && PCI && PCMCIA
 	help
 	  Say Y here if your Notebook reports a Ricoh Bay1Controller PCMCIA
 	  card whenever you insert a MMC or SD card into the card slot.
diff --git a/drivers/mmc/host/atmel-mci-regs.h b/drivers/mmc/host/atmel-mci-regs.h
index 26bd80e..b58364e 100644
--- a/drivers/mmc/host/atmel-mci-regs.h
+++ b/drivers/mmc/host/atmel-mci-regs.h
@@ -25,8 +25,10 @@
 #define MCI_SDCR		0x000c	/* SD Card / SDIO */
 # define MCI_SDCSEL_SLOT_A	(  0 <<  0)	/* Select SD slot A */
 # define MCI_SDCSEL_SLOT_B	(  1 <<  0)	/* Select SD slot A */
-# define MCI_SDCBUS_1BIT	(  0 <<  7)	/* 1-bit data bus */
-# define MCI_SDCBUS_4BIT	(  1 <<  7)	/* 4-bit data bus */
+# define MCI_SDCSEL_MASK	(  3 <<  0)
+# define MCI_SDCBUS_1BIT	(  0 <<  6)	/* 1-bit data bus */
+# define MCI_SDCBUS_4BIT	(  2 <<  6)	/* 4-bit data bus */
+# define MCI_SDCBUS_MASK	(  3 <<  6)
 #define MCI_ARGR		0x0010	/* Command Argument */
 #define MCI_CMDR		0x0014	/* Command */
 # define MCI_CMDR_CMDNB(x)	((x) <<  0)	/* Command Opcode */
diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c
index 0bd06f5..7a3f243 100644
--- a/drivers/mmc/host/atmel-mci.c
+++ b/drivers/mmc/host/atmel-mci.c
@@ -11,6 +11,8 @@
 #include <linux/clk.h>
 #include <linux/debugfs.h>
 #include <linux/device.h>
+#include <linux/dmaengine.h>
+#include <linux/dma-mapping.h>
 #include <linux/err.h>
 #include <linux/gpio.h>
 #include <linux/init.h>
@@ -33,64 +35,178 @@
 #include "atmel-mci-regs.h"
 
 #define ATMCI_DATA_ERROR_FLAGS	(MCI_DCRCE | MCI_DTOE | MCI_OVRE | MCI_UNRE)
+#define ATMCI_DMA_THRESHOLD	16
 
 enum {
 	EVENT_CMD_COMPLETE = 0,
-	EVENT_DATA_ERROR,
-	EVENT_DATA_COMPLETE,
-	EVENT_STOP_SENT,
-	EVENT_STOP_COMPLETE,
 	EVENT_XFER_COMPLETE,
+	EVENT_DATA_COMPLETE,
+	EVENT_DATA_ERROR,
 };
 
+enum atmel_mci_state {
+	STATE_IDLE = 0,
+	STATE_SENDING_CMD,
+	STATE_SENDING_DATA,
+	STATE_DATA_BUSY,
+	STATE_SENDING_STOP,
+	STATE_DATA_ERROR,
+};
+
+struct atmel_mci_dma {
+#ifdef CONFIG_MMC_ATMELMCI_DMA
+	struct dma_client		client;
+	struct dma_chan			*chan;
+	struct dma_async_tx_descriptor	*data_desc;
+#endif
+};
+
+/**
+ * struct atmel_mci - MMC controller state shared between all slots
+ * @lock: Spinlock protecting the queue and associated data.
+ * @regs: Pointer to MMIO registers.
+ * @sg: Scatterlist entry currently being processed by PIO code, if any.
+ * @pio_offset: Offset into the current scatterlist entry.
+ * @cur_slot: The slot which is currently using the controller.
+ * @mrq: The request currently being processed on @cur_slot,
+ *	or NULL if the controller is idle.
+ * @cmd: The command currently being sent to the card, or NULL.
+ * @data: The data currently being transferred, or NULL if no data
+ *	transfer is in progress.
+ * @dma: DMA client state.
+ * @data_chan: DMA channel being used for the current data transfer.
+ * @cmd_status: Snapshot of SR taken upon completion of the current
+ *	command. Only valid when EVENT_CMD_COMPLETE is pending.
+ * @data_status: Snapshot of SR taken upon completion of the current
+ *	data transfer. Only valid when EVENT_DATA_COMPLETE or
+ *	EVENT_DATA_ERROR is pending.
+ * @stop_cmdr: Value to be loaded into CMDR when the stop command is
+ *	to be sent.
+ * @tasklet: Tasklet running the request state machine.
+ * @pending_events: Bitmask of events flagged by the interrupt handler
+ *	to be processed by the tasklet.
+ * @completed_events: Bitmask of events which the state machine has
+ *	processed.
+ * @state: Tasklet state.
+ * @queue: List of slots waiting for access to the controller.
+ * @need_clock_update: Update the clock rate before the next request.
+ * @need_reset: Reset controller before next request.
+ * @mode_reg: Value of the MR register.
+ * @bus_hz: The rate of @mck in Hz. This forms the basis for MMC bus
+ *	rate and timeout calculations.
+ * @mapbase: Physical address of the MMIO registers.
+ * @mck: The peripheral bus clock hooked up to the MMC controller.
+ * @pdev: Platform device associated with the MMC controller.
+ * @slot: Slots sharing this MMC controller.
+ *
+ * Locking
+ * =======
+ *
+ * @lock is a softirq-safe spinlock protecting @queue as well as
+ * @cur_slot, @mrq and @state. These must always be updated
+ * at the same time while holding @lock.
+ *
+ * @lock also protects mode_reg and need_clock_update since these are
+ * used to synchronize mode register updates with the queue
+ * processing.
+ *
+ * The @mrq field of struct atmel_mci_slot is also protected by @lock,
+ * and must always be written at the same time as the slot is added to
+ * @queue.
+ *
+ * @pending_events and @completed_events are accessed using atomic bit
+ * operations, so they don't need any locking.
+ *
+ * None of the fields touched by the interrupt handler need any
+ * locking. However, ordering is important: Before EVENT_DATA_ERROR or
+ * EVENT_DATA_COMPLETE is set in @pending_events, all data-related
+ * interrupts must be disabled and @data_status updated with a
+ * snapshot of SR. Similarly, before EVENT_CMD_COMPLETE is set, the
+ * CMDRDY interupt must be disabled and @cmd_status updated with a
+ * snapshot of SR, and before EVENT_XFER_COMPLETE can be set, the
+ * bytes_xfered field of @data must be written. This is ensured by
+ * using barriers.
+ */
 struct atmel_mci {
-	struct mmc_host		*mmc;
+	spinlock_t		lock;
 	void __iomem		*regs;
 
 	struct scatterlist	*sg;
 	unsigned int		pio_offset;
 
+	struct atmel_mci_slot	*cur_slot;
 	struct mmc_request	*mrq;
 	struct mmc_command	*cmd;
 	struct mmc_data		*data;
 
+	struct atmel_mci_dma	dma;
+	struct dma_chan		*data_chan;
+
 	u32			cmd_status;
 	u32			data_status;
-	u32			stop_status;
 	u32			stop_cmdr;
 
-	u32			mode_reg;
-	u32			sdc_reg;
-
 	struct tasklet_struct	tasklet;
 	unsigned long		pending_events;
 	unsigned long		completed_events;
+	enum atmel_mci_state	state;
+	struct list_head	queue;
 
-	int			present;
-	int			detect_pin;
-	int			wp_pin;
-
-	/* For detect pin debouncing */
-	struct timer_list	detect_timer;
-
+	bool			need_clock_update;
+	bool			need_reset;
+	u32			mode_reg;
 	unsigned long		bus_hz;
 	unsigned long		mapbase;
 	struct clk		*mck;
 	struct platform_device	*pdev;
+
+	struct atmel_mci_slot	*slot[ATMEL_MCI_MAX_NR_SLOTS];
 };
 
-#define atmci_is_completed(host, event)				\
-	test_bit(event, &host->completed_events)
+/**
+ * struct atmel_mci_slot - MMC slot state
+ * @mmc: The mmc_host representing this slot.
+ * @host: The MMC controller this slot is using.
+ * @sdc_reg: Value of SDCR to be written before using this slot.
+ * @mrq: mmc_request currently being processed or waiting to be
+ *	processed, or NULL when the slot is idle.
+ * @queue_node: List node for placing this node in the @queue list of
+ *	&struct atmel_mci.
+ * @clock: Clock rate configured by set_ios(). Protected by host->lock.
+ * @flags: Random state bits associated with the slot.
+ * @detect_pin: GPIO pin used for card detection, or negative if not
+ *	available.
+ * @wp_pin: GPIO pin used for card write protect sending, or negative
+ *	if not available.
+ * @detect_timer: Timer used for debouncing @detect_pin interrupts.
+ */
+struct atmel_mci_slot {
+	struct mmc_host		*mmc;
+	struct atmel_mci	*host;
+
+	u32			sdc_reg;
+
+	struct mmc_request	*mrq;
+	struct list_head	queue_node;
+
+	unsigned int		clock;
+	unsigned long		flags;
+#define ATMCI_CARD_PRESENT	0
+#define ATMCI_CARD_NEED_INIT	1
+#define ATMCI_SHUTDOWN		2
+
+	int			detect_pin;
+	int			wp_pin;
+
+	struct timer_list	detect_timer;
+};
+
 #define atmci_test_and_clear_pending(host, event)		\
 	test_and_clear_bit(event, &host->pending_events)
-#define atmci_test_and_set_completed(host, event)		\
-	test_and_set_bit(event, &host->completed_events)
 #define atmci_set_completed(host, event)			\
 	set_bit(event, &host->completed_events)
 #define atmci_set_pending(host, event)				\
 	set_bit(event, &host->pending_events)
-#define atmci_clear_pending(host, event)			\
-	clear_bit(event, &host->pending_events)
 
 /*
  * The debugfs stuff below is mostly optimized away when
@@ -98,14 +214,15 @@
  */
 static int atmci_req_show(struct seq_file *s, void *v)
 {
-	struct atmel_mci	*host = s->private;
-	struct mmc_request	*mrq = host->mrq;
+	struct atmel_mci_slot	*slot = s->private;
+	struct mmc_request	*mrq;
 	struct mmc_command	*cmd;
 	struct mmc_command	*stop;
 	struct mmc_data		*data;
 
 	/* Make sure we get a consistent snapshot */
-	spin_lock_irq(&host->mmc->lock);
+	spin_lock_bh(&slot->host->lock);
+	mrq = slot->mrq;
 
 	if (mrq) {
 		cmd = mrq->cmd;
@@ -130,7 +247,7 @@
 				stop->resp[2], stop->error);
 	}
 
-	spin_unlock_irq(&host->mmc->lock);
+	spin_unlock_bh(&slot->host->lock);
 
 	return 0;
 }
@@ -193,10 +310,16 @@
 	if (!buf)
 		return -ENOMEM;
 
-	/* Grab a more or less consistent snapshot */
-	spin_lock_irq(&host->mmc->lock);
+	/*
+	 * Grab a more or less consistent snapshot. Note that we're
+	 * not disabling interrupts, so IMR and SR may not be
+	 * consistent.
+	 */
+	spin_lock_bh(&host->lock);
+	clk_enable(host->mck);
 	memcpy_fromio(buf, host->regs, MCI_REGS_SIZE);
-	spin_unlock_irq(&host->mmc->lock);
+	clk_disable(host->mck);
+	spin_unlock_bh(&host->lock);
 
 	seq_printf(s, "MR:\t0x%08x%s%s CLKDIV=%u\n",
 			buf[MCI_MR / 4],
@@ -216,6 +339,8 @@
 	atmci_show_status_reg(s, "SR", buf[MCI_SR / 4]);
 	atmci_show_status_reg(s, "IMR", buf[MCI_IMR / 4]);
 
+	kfree(buf);
+
 	return 0;
 }
 
@@ -232,14 +357,13 @@
 	.release	= single_release,
 };
 
-static void atmci_init_debugfs(struct atmel_mci *host)
+static void atmci_init_debugfs(struct atmel_mci_slot *slot)
 {
-	struct mmc_host	*mmc;
-	struct dentry	*root;
-	struct dentry	*node;
-	struct resource	*res;
+	struct mmc_host		*mmc = slot->mmc;
+	struct atmel_mci	*host = slot->host;
+	struct dentry		*root;
+	struct dentry		*node;
 
-	mmc = host->mmc;
 	root = mmc->debugfs_root;
 	if (!root)
 		return;
@@ -251,10 +375,11 @@
 	if (!node)
 		goto err;
 
-	res = platform_get_resource(host->pdev, IORESOURCE_MEM, 0);
-	node->d_inode->i_size = res->end - res->start + 1;
+	node = debugfs_create_file("req", S_IRUSR, root, slot, &atmci_req_fops);
+	if (!node)
+		goto err;
 
-	node = debugfs_create_file("req", S_IRUSR, root, host, &atmci_req_fops);
+	node = debugfs_create_u32("state", S_IRUSR, root, (u32 *)&host->state);
 	if (!node)
 		goto err;
 
@@ -271,25 +396,7 @@
 	return;
 
 err:
-	dev_err(&host->pdev->dev,
-		"failed to initialize debugfs for controller\n");
-}
-
-static void atmci_enable(struct atmel_mci *host)
-{
-	clk_enable(host->mck);
-	mci_writel(host, CR, MCI_CR_MCIEN);
-	mci_writel(host, MR, host->mode_reg);
-	mci_writel(host, SDCR, host->sdc_reg);
-}
-
-static void atmci_disable(struct atmel_mci *host)
-{
-	mci_writel(host, CR, MCI_CR_SWRST);
-
-	/* Stall until write is complete, then disable the bus clock */
-	mci_readl(host, SR);
-	clk_disable(host->mck);
+	dev_err(&mmc->class_dev, "failed to initialize debugfs for slot\n");
 }
 
 static inline unsigned int ns_to_clocks(struct atmel_mci *host,
@@ -299,7 +406,7 @@
 }
 
 static void atmci_set_timeout(struct atmel_mci *host,
-			      struct mmc_data *data)
+		struct atmel_mci_slot *slot, struct mmc_data *data)
 {
 	static unsigned	dtomul_to_shift[] = {
 		0, 4, 7, 8, 10, 12, 16, 20
@@ -322,7 +429,7 @@
 		dtocyc = 15;
 	}
 
-	dev_vdbg(&host->mmc->class_dev, "setting timeout to %u cycles\n",
+	dev_vdbg(&slot->mmc->class_dev, "setting timeout to %u cycles\n",
 			dtocyc << dtomul_to_shift[dtomul]);
 	mci_writel(host, DTOR, (MCI_DTOMUL(dtomul) | MCI_DTOCYC(dtocyc)));
 }
@@ -375,15 +482,12 @@
 }
 
 static void atmci_start_command(struct atmel_mci *host,
-				struct mmc_command *cmd,
-				u32 cmd_flags)
+		struct mmc_command *cmd, u32 cmd_flags)
 {
-	/* Must read host->cmd after testing event flags */
-	smp_rmb();
 	WARN_ON(host->cmd);
 	host->cmd = cmd;
 
-	dev_vdbg(&host->mmc->class_dev,
+	dev_vdbg(&host->pdev->dev,
 			"start command: ARGR=0x%08x CMDR=0x%08x\n",
 			cmd->arg, cmd_flags);
 
@@ -391,34 +495,157 @@
 	mci_writel(host, CMDR, cmd_flags);
 }
 
-static void send_stop_cmd(struct mmc_host *mmc, struct mmc_data *data)
+static void send_stop_cmd(struct atmel_mci *host, struct mmc_data *data)
 {
-	struct atmel_mci *host = mmc_priv(mmc);
-
 	atmci_start_command(host, data->stop, host->stop_cmdr);
 	mci_writel(host, IER, MCI_CMDRDY);
 }
 
-static void atmci_request_end(struct mmc_host *mmc, struct mmc_request *mrq)
+#ifdef CONFIG_MMC_ATMELMCI_DMA
+static void atmci_dma_cleanup(struct atmel_mci *host)
 {
-	struct atmel_mci *host = mmc_priv(mmc);
+	struct mmc_data			*data = host->data;
 
-	WARN_ON(host->cmd || host->data);
-	host->mrq = NULL;
-
-	atmci_disable(host);
-
-	mmc_request_done(mmc, mrq);
+	dma_unmap_sg(&host->pdev->dev, data->sg, data->sg_len,
+		     ((data->flags & MMC_DATA_WRITE)
+		      ? DMA_TO_DEVICE : DMA_FROM_DEVICE));
 }
 
+static void atmci_stop_dma(struct atmel_mci *host)
+{
+	struct dma_chan *chan = host->data_chan;
+
+	if (chan) {
+		chan->device->device_terminate_all(chan);
+		atmci_dma_cleanup(host);
+	} else {
+		/* Data transfer was stopped by the interrupt handler */
+		atmci_set_pending(host, EVENT_XFER_COMPLETE);
+		mci_writel(host, IER, MCI_NOTBUSY);
+	}
+}
+
+/* This function is called by the DMA driver from tasklet context. */
+static void atmci_dma_complete(void *arg)
+{
+	struct atmel_mci	*host = arg;
+	struct mmc_data		*data = host->data;
+
+	dev_vdbg(&host->pdev->dev, "DMA complete\n");
+
+	atmci_dma_cleanup(host);
+
+	/*
+	 * If the card was removed, data will be NULL. No point trying
+	 * to send the stop command or waiting for NBUSY in this case.
+	 */
+	if (data) {
+		atmci_set_pending(host, EVENT_XFER_COMPLETE);
+		tasklet_schedule(&host->tasklet);
+
+		/*
+		 * Regardless of what the documentation says, we have
+		 * to wait for NOTBUSY even after block read
+		 * operations.
+		 *
+		 * When the DMA transfer is complete, the controller
+		 * may still be reading the CRC from the card, i.e.
+		 * the data transfer is still in progress and we
+		 * haven't seen all the potential error bits yet.
+		 *
+		 * The interrupt handler will schedule a different
+		 * tasklet to finish things up when the data transfer
+		 * is completely done.
+		 *
+		 * We may not complete the mmc request here anyway
+		 * because the mmc layer may call back and cause us to
+		 * violate the "don't submit new operations from the
+		 * completion callback" rule of the dma engine
+		 * framework.
+		 */
+		mci_writel(host, IER, MCI_NOTBUSY);
+	}
+}
+
+static int
+atmci_submit_data_dma(struct atmel_mci *host, struct mmc_data *data)
+{
+	struct dma_chan			*chan;
+	struct dma_async_tx_descriptor	*desc;
+	struct scatterlist		*sg;
+	unsigned int			i;
+	enum dma_data_direction		direction;
+
+	/*
+	 * We don't do DMA on "complex" transfers, i.e. with
+	 * non-word-aligned buffers or lengths. Also, we don't bother
+	 * with all the DMA setup overhead for short transfers.
+	 */
+	if (data->blocks * data->blksz < ATMCI_DMA_THRESHOLD)
+		return -EINVAL;
+	if (data->blksz & 3)
+		return -EINVAL;
+
+	for_each_sg(data->sg, sg, data->sg_len, i) {
+		if (sg->offset & 3 || sg->length & 3)
+			return -EINVAL;
+	}
+
+	/* If we don't have a channel, we can't do DMA */
+	chan = host->dma.chan;
+	if (chan) {
+		dma_chan_get(chan);
+		host->data_chan = chan;
+	}
+
+	if (!chan)
+		return -ENODEV;
+
+	if (data->flags & MMC_DATA_READ)
+		direction = DMA_FROM_DEVICE;
+	else
+		direction = DMA_TO_DEVICE;
+
+	desc = chan->device->device_prep_slave_sg(chan,
+			data->sg, data->sg_len, direction,
+			DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+	if (!desc)
+		return -ENOMEM;
+
+	host->dma.data_desc = desc;
+	desc->callback = atmci_dma_complete;
+	desc->callback_param = host;
+	desc->tx_submit(desc);
+
+	/* Go! */
+	chan->device->device_issue_pending(chan);
+
+	return 0;
+}
+
+#else /* CONFIG_MMC_ATMELMCI_DMA */
+
+static int atmci_submit_data_dma(struct atmel_mci *host, struct mmc_data *data)
+{
+	return -ENOSYS;
+}
+
+static void atmci_stop_dma(struct atmel_mci *host)
+{
+	/* Data transfer was stopped by the interrupt handler */
+	atmci_set_pending(host, EVENT_XFER_COMPLETE);
+	mci_writel(host, IER, MCI_NOTBUSY);
+}
+
+#endif /* CONFIG_MMC_ATMELMCI_DMA */
+
 /*
  * Returns a mask of interrupt flags to be enabled after the whole
  * request has been prepared.
  */
-static u32 atmci_submit_data(struct mmc_host *mmc, struct mmc_data *data)
+static u32 atmci_submit_data(struct atmel_mci *host, struct mmc_data *data)
 {
-	struct atmel_mci	*host = mmc_priv(mmc);
-	u32			iflags;
+	u32 iflags;
 
 	data->error = -EINPROGRESS;
 
@@ -426,75 +653,89 @@
 	host->sg = NULL;
 	host->data = data;
 
-	mci_writel(host, BLKR, MCI_BCNT(data->blocks)
-			| MCI_BLKLEN(data->blksz));
-	dev_vdbg(&mmc->class_dev, "BLKR=0x%08x\n",
-			MCI_BCNT(data->blocks) | MCI_BLKLEN(data->blksz));
-
 	iflags = ATMCI_DATA_ERROR_FLAGS;
-	host->sg = data->sg;
-	host->pio_offset = 0;
-	if (data->flags & MMC_DATA_READ)
-		iflags |= MCI_RXRDY;
-	else
-		iflags |= MCI_TXRDY;
+	if (atmci_submit_data_dma(host, data)) {
+		host->data_chan = NULL;
+
+		/*
+		 * Errata: MMC data write operation with less than 12
+		 * bytes is impossible.
+		 *
+		 * Errata: MCI Transmit Data Register (TDR) FIFO
+		 * corruption when length is not multiple of 4.
+		 */
+		if (data->blocks * data->blksz < 12
+				|| (data->blocks * data->blksz) & 3)
+			host->need_reset = true;
+
+		host->sg = data->sg;
+		host->pio_offset = 0;
+		if (data->flags & MMC_DATA_READ)
+			iflags |= MCI_RXRDY;
+		else
+			iflags |= MCI_TXRDY;
+	}
 
 	return iflags;
 }
 
-static void atmci_request(struct mmc_host *mmc, struct mmc_request *mrq)
+static void atmci_start_request(struct atmel_mci *host,
+		struct atmel_mci_slot *slot)
 {
-	struct atmel_mci	*host = mmc_priv(mmc);
-	struct mmc_data		*data;
+	struct mmc_request	*mrq;
 	struct mmc_command	*cmd;
+	struct mmc_data		*data;
 	u32			iflags;
-	u32			cmdflags = 0;
+	u32			cmdflags;
+
+	mrq = slot->mrq;
+	host->cur_slot = slot;
+	host->mrq = mrq;
+
+	host->pending_events = 0;
+	host->completed_events = 0;
+	host->data_status = 0;
+
+	if (host->need_reset) {
+		mci_writel(host, CR, MCI_CR_SWRST);
+		mci_writel(host, CR, MCI_CR_MCIEN);
+		mci_writel(host, MR, host->mode_reg);
+		host->need_reset = false;
+	}
+	mci_writel(host, SDCR, slot->sdc_reg);
 
 	iflags = mci_readl(host, IMR);
 	if (iflags)
-		dev_warn(&mmc->class_dev, "WARNING: IMR=0x%08x\n",
-				mci_readl(host, IMR));
+		dev_warn(&slot->mmc->class_dev, "WARNING: IMR=0x%08x\n",
+				iflags);
 
-	WARN_ON(host->mrq != NULL);
-
-	/*
-	 * We may "know" the card is gone even though there's still an
-	 * electrical connection. If so, we really need to communicate
-	 * this to the MMC core since there won't be any more
-	 * interrupts as the card is completely removed. Otherwise,
-	 * the MMC core might believe the card is still there even
-	 * though the card was just removed very slowly.
-	 */
-	if (!host->present) {
-		mrq->cmd->error = -ENOMEDIUM;
-		mmc_request_done(mmc, mrq);
-		return;
+	if (unlikely(test_and_clear_bit(ATMCI_CARD_NEED_INIT, &slot->flags))) {
+		/* Send init sequence (74 clock cycles) */
+		mci_writel(host, CMDR, MCI_CMDR_SPCMD_INIT);
+		while (!(mci_readl(host, SR) & MCI_CMDRDY))
+			cpu_relax();
 	}
-
-	host->mrq = mrq;
-	host->pending_events = 0;
-	host->completed_events = 0;
-
-	atmci_enable(host);
-
-	/* We don't support multiple blocks of weird lengths. */
 	data = mrq->data;
 	if (data) {
-		if (data->blocks > 1 && data->blksz & 3)
-			goto fail;
-		atmci_set_timeout(host, data);
+		atmci_set_timeout(host, slot, data);
+
+		/* Must set block count/size before sending command */
+		mci_writel(host, BLKR, MCI_BCNT(data->blocks)
+				| MCI_BLKLEN(data->blksz));
+		dev_vdbg(&slot->mmc->class_dev, "BLKR=0x%08x\n",
+			MCI_BCNT(data->blocks) | MCI_BLKLEN(data->blksz));
 	}
 
 	iflags = MCI_CMDRDY;
 	cmd = mrq->cmd;
-	cmdflags = atmci_prepare_command(mmc, cmd);
+	cmdflags = atmci_prepare_command(slot->mmc, cmd);
 	atmci_start_command(host, cmd, cmdflags);
 
 	if (data)
-		iflags |= atmci_submit_data(mmc, data);
+		iflags |= atmci_submit_data(host, data);
 
 	if (mrq->stop) {
-		host->stop_cmdr = atmci_prepare_command(mmc, mrq->stop);
+		host->stop_cmdr = atmci_prepare_command(slot->mmc, mrq->stop);
 		host->stop_cmdr |= MCI_CMDR_STOP_XFER;
 		if (!(data->flags & MMC_DATA_WRITE))
 			host->stop_cmdr |= MCI_CMDR_TRDIR_READ;
@@ -511,59 +752,156 @@
 	 * prepared yet.)
 	 */
 	mci_writel(host, IER, iflags);
+}
 
-	return;
+static void atmci_queue_request(struct atmel_mci *host,
+		struct atmel_mci_slot *slot, struct mmc_request *mrq)
+{
+	dev_vdbg(&slot->mmc->class_dev, "queue request: state=%d\n",
+			host->state);
 
-fail:
-	atmci_disable(host);
-	host->mrq = NULL;
-	mrq->cmd->error = -EINVAL;
-	mmc_request_done(mmc, mrq);
+	spin_lock_bh(&host->lock);
+	slot->mrq = mrq;
+	if (host->state == STATE_IDLE) {
+		host->state = STATE_SENDING_CMD;
+		atmci_start_request(host, slot);
+	} else {
+		list_add_tail(&slot->queue_node, &host->queue);
+	}
+	spin_unlock_bh(&host->lock);
+}
+
+static void atmci_request(struct mmc_host *mmc, struct mmc_request *mrq)
+{
+	struct atmel_mci_slot	*slot = mmc_priv(mmc);
+	struct atmel_mci	*host = slot->host;
+	struct mmc_data		*data;
+
+	WARN_ON(slot->mrq);
+
+	/*
+	 * We may "know" the card is gone even though there's still an
+	 * electrical connection. If so, we really need to communicate
+	 * this to the MMC core since there won't be any more
+	 * interrupts as the card is completely removed. Otherwise,
+	 * the MMC core might believe the card is still there even
+	 * though the card was just removed very slowly.
+	 */
+	if (!test_bit(ATMCI_CARD_PRESENT, &slot->flags)) {
+		mrq->cmd->error = -ENOMEDIUM;
+		mmc_request_done(mmc, mrq);
+		return;
+	}
+
+	/* We don't support multiple blocks of weird lengths. */
+	data = mrq->data;
+	if (data && data->blocks > 1 && data->blksz & 3) {
+		mrq->cmd->error = -EINVAL;
+		mmc_request_done(mmc, mrq);
+	}
+
+	atmci_queue_request(host, slot, mrq);
 }
 
 static void atmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
 {
-	struct atmel_mci	*host = mmc_priv(mmc);
+	struct atmel_mci_slot	*slot = mmc_priv(mmc);
+	struct atmel_mci	*host = slot->host;
+	unsigned int		i;
+
+	slot->sdc_reg &= ~MCI_SDCBUS_MASK;
+	switch (ios->bus_width) {
+	case MMC_BUS_WIDTH_1:
+		slot->sdc_reg |= MCI_SDCBUS_1BIT;
+		break;
+	case MMC_BUS_WIDTH_4:
+		slot->sdc_reg = MCI_SDCBUS_4BIT;
+		break;
+	}
 
 	if (ios->clock) {
+		unsigned int clock_min = ~0U;
 		u32 clkdiv;
 
-		/* Set clock rate */
-		clkdiv = DIV_ROUND_UP(host->bus_hz, 2 * ios->clock) - 1;
+		spin_lock_bh(&host->lock);
+		if (!host->mode_reg) {
+			clk_enable(host->mck);
+			mci_writel(host, CR, MCI_CR_SWRST);
+			mci_writel(host, CR, MCI_CR_MCIEN);
+		}
+
+		/*
+		 * Use mirror of ios->clock to prevent race with mmc
+		 * core ios update when finding the minimum.
+		 */
+		slot->clock = ios->clock;
+		for (i = 0; i < ATMEL_MCI_MAX_NR_SLOTS; i++) {
+			if (host->slot[i] && host->slot[i]->clock
+					&& host->slot[i]->clock < clock_min)
+				clock_min = host->slot[i]->clock;
+		}
+
+		/* Calculate clock divider */
+		clkdiv = DIV_ROUND_UP(host->bus_hz, 2 * clock_min) - 1;
 		if (clkdiv > 255) {
 			dev_warn(&mmc->class_dev,
 				"clock %u too slow; using %lu\n",
-				ios->clock, host->bus_hz / (2 * 256));
+				clock_min, host->bus_hz / (2 * 256));
 			clkdiv = 255;
 		}
 
+		/*
+		 * WRPROOF and RDPROOF prevent overruns/underruns by
+		 * stopping the clock when the FIFO is full/empty.
+		 * This state is not expected to last for long.
+		 */
 		host->mode_reg = MCI_MR_CLKDIV(clkdiv) | MCI_MR_WRPROOF
 					| MCI_MR_RDPROOF;
-	}
 
-	switch (ios->bus_width) {
-	case MMC_BUS_WIDTH_1:
-		host->sdc_reg = 0;
-		break;
-	case MMC_BUS_WIDTH_4:
-		host->sdc_reg = MCI_SDCBUS_4BIT;
-		break;
+		if (list_empty(&host->queue))
+			mci_writel(host, MR, host->mode_reg);
+		else
+			host->need_clock_update = true;
+
+		spin_unlock_bh(&host->lock);
+	} else {
+		bool any_slot_active = false;
+
+		spin_lock_bh(&host->lock);
+		slot->clock = 0;
+		for (i = 0; i < ATMEL_MCI_MAX_NR_SLOTS; i++) {
+			if (host->slot[i] && host->slot[i]->clock) {
+				any_slot_active = true;
+				break;
+			}
+		}
+		if (!any_slot_active) {
+			mci_writel(host, CR, MCI_CR_MCIDIS);
+			if (host->mode_reg) {
+				mci_readl(host, MR);
+				clk_disable(host->mck);
+			}
+			host->mode_reg = 0;
+		}
+		spin_unlock_bh(&host->lock);
 	}
 
 	switch (ios->power_mode) {
-	case MMC_POWER_ON:
-		/* Send init sequence (74 clock cycles) */
-		atmci_enable(host);
-		mci_writel(host, CMDR, MCI_CMDR_SPCMD_INIT);
-		while (!(mci_readl(host, SR) & MCI_CMDRDY))
-			cpu_relax();
-		atmci_disable(host);
+	case MMC_POWER_UP:
+		set_bit(ATMCI_CARD_NEED_INIT, &slot->flags);
 		break;
 	default:
 		/*
 		 * TODO: None of the currently available AVR32-based
 		 * boards allow MMC power to be turned off. Implement
 		 * power control when this can be tested properly.
+		 *
+		 * We also need to hook this into the clock management
+		 * somehow so that newly inserted cards aren't
+		 * subjected to a fast clock before we have a chance
+		 * to figure out what the maximum rate is. Currently,
+		 * there's no way to avoid this, and there never will
+		 * be for boards that don't support power control.
 		 */
 		break;
 	}
@@ -571,31 +909,82 @@
 
 static int atmci_get_ro(struct mmc_host *mmc)
 {
-	int			read_only = 0;
-	struct atmel_mci	*host = mmc_priv(mmc);
+	int			read_only = -ENOSYS;
+	struct atmel_mci_slot	*slot = mmc_priv(mmc);
 
-	if (gpio_is_valid(host->wp_pin)) {
-		read_only = gpio_get_value(host->wp_pin);
+	if (gpio_is_valid(slot->wp_pin)) {
+		read_only = gpio_get_value(slot->wp_pin);
 		dev_dbg(&mmc->class_dev, "card is %s\n",
 				read_only ? "read-only" : "read-write");
-	} else {
-		dev_dbg(&mmc->class_dev,
-			"no pin for checking read-only switch."
-			" Assuming write-enable.\n");
 	}
 
 	return read_only;
 }
 
-static struct mmc_host_ops atmci_ops = {
+static int atmci_get_cd(struct mmc_host *mmc)
+{
+	int			present = -ENOSYS;
+	struct atmel_mci_slot	*slot = mmc_priv(mmc);
+
+	if (gpio_is_valid(slot->detect_pin)) {
+		present = !gpio_get_value(slot->detect_pin);
+		dev_dbg(&mmc->class_dev, "card is %spresent\n",
+				present ? "" : "not ");
+	}
+
+	return present;
+}
+
+static const struct mmc_host_ops atmci_ops = {
 	.request	= atmci_request,
 	.set_ios	= atmci_set_ios,
 	.get_ro		= atmci_get_ro,
+	.get_cd		= atmci_get_cd,
 };
 
-static void atmci_command_complete(struct atmel_mci *host,
-			struct mmc_command *cmd, u32 status)
+/* Called with host->lock held */
+static void atmci_request_end(struct atmel_mci *host, struct mmc_request *mrq)
+	__releases(&host->lock)
+	__acquires(&host->lock)
 {
+	struct atmel_mci_slot	*slot = NULL;
+	struct mmc_host		*prev_mmc = host->cur_slot->mmc;
+
+	WARN_ON(host->cmd || host->data);
+
+	/*
+	 * Update the MMC clock rate if necessary. This may be
+	 * necessary if set_ios() is called when a different slot is
+	 * busy transfering data.
+	 */
+	if (host->need_clock_update)
+		mci_writel(host, MR, host->mode_reg);
+
+	host->cur_slot->mrq = NULL;
+	host->mrq = NULL;
+	if (!list_empty(&host->queue)) {
+		slot = list_entry(host->queue.next,
+				struct atmel_mci_slot, queue_node);
+		list_del(&slot->queue_node);
+		dev_vdbg(&host->pdev->dev, "list not empty: %s is next\n",
+				mmc_hostname(slot->mmc));
+		host->state = STATE_SENDING_CMD;
+		atmci_start_request(host, slot);
+	} else {
+		dev_vdbg(&host->pdev->dev, "list empty\n");
+		host->state = STATE_IDLE;
+	}
+
+	spin_unlock(&host->lock);
+	mmc_request_done(prev_mmc, mrq);
+	spin_lock(&host->lock);
+}
+
+static void atmci_command_complete(struct atmel_mci *host,
+			struct mmc_command *cmd)
+{
+	u32		status = host->cmd_status;
+
 	/* Read the response from the card (up to 16 bytes) */
 	cmd->resp[0] = mci_readl(host, RSPR);
 	cmd->resp[1] = mci_readl(host, RSPR);
@@ -612,11 +1001,12 @@
 		cmd->error = 0;
 
 	if (cmd->error) {
-		dev_dbg(&host->mmc->class_dev,
+		dev_dbg(&host->pdev->dev,
 			"command error: status=0x%08x\n", status);
 
 		if (cmd->data) {
 			host->data = NULL;
+			atmci_stop_dma(host);
 			mci_writel(host, IDR, MCI_NOTBUSY
 					| MCI_TXRDY | MCI_RXRDY
 					| ATMCI_DATA_ERROR_FLAGS);
@@ -626,146 +1016,222 @@
 
 static void atmci_detect_change(unsigned long data)
 {
-	struct atmel_mci *host = (struct atmel_mci *)data;
-	struct mmc_request *mrq = host->mrq;
-	int present;
+	struct atmel_mci_slot	*slot = (struct atmel_mci_slot *)data;
+	bool			present;
+	bool			present_old;
 
 	/*
-	 * atmci_remove() sets detect_pin to -1 before freeing the
-	 * interrupt. We must not re-enable the interrupt if it has
-	 * been freed.
+	 * atmci_cleanup_slot() sets the ATMCI_SHUTDOWN flag before
+	 * freeing the interrupt. We must not re-enable the interrupt
+	 * if it has been freed, and if we're shutting down, it
+	 * doesn't really matter whether the card is present or not.
 	 */
 	smp_rmb();
-	if (!gpio_is_valid(host->detect_pin))
+	if (test_bit(ATMCI_SHUTDOWN, &slot->flags))
 		return;
 
-	enable_irq(gpio_to_irq(host->detect_pin));
-	present = !gpio_get_value(host->detect_pin);
+	enable_irq(gpio_to_irq(slot->detect_pin));
+	present = !gpio_get_value(slot->detect_pin);
+	present_old = test_bit(ATMCI_CARD_PRESENT, &slot->flags);
 
-	dev_vdbg(&host->pdev->dev, "detect change: %d (was %d)\n",
-			present, host->present);
+	dev_vdbg(&slot->mmc->class_dev, "detect change: %d (was %d)\n",
+			present, present_old);
 
-	if (present != host->present) {
-		dev_dbg(&host->mmc->class_dev, "card %s\n",
+	if (present != present_old) {
+		struct atmel_mci	*host = slot->host;
+		struct mmc_request	*mrq;
+
+		dev_dbg(&slot->mmc->class_dev, "card %s\n",
 			present ? "inserted" : "removed");
-		host->present = present;
 
-		/* Reset controller if card is gone */
-		if (!present) {
-			mci_writel(host, CR, MCI_CR_SWRST);
-			mci_writel(host, IDR, ~0UL);
-			mci_writel(host, CR, MCI_CR_MCIEN);
-		}
+		spin_lock(&host->lock);
+
+		if (!present)
+			clear_bit(ATMCI_CARD_PRESENT, &slot->flags);
+		else
+			set_bit(ATMCI_CARD_PRESENT, &slot->flags);
 
 		/* Clean up queue if present */
+		mrq = slot->mrq;
 		if (mrq) {
-			/*
-			 * Reset controller to terminate any ongoing
-			 * commands or data transfers.
-			 */
-			mci_writel(host, CR, MCI_CR_SWRST);
+			if (mrq == host->mrq) {
+				/*
+				 * Reset controller to terminate any ongoing
+				 * commands or data transfers.
+				 */
+				mci_writel(host, CR, MCI_CR_SWRST);
+				mci_writel(host, CR, MCI_CR_MCIEN);
+				mci_writel(host, MR, host->mode_reg);
 
-			if (!atmci_is_completed(host, EVENT_CMD_COMPLETE))
-				mrq->cmd->error = -ENOMEDIUM;
-
-			if (mrq->data && !atmci_is_completed(host,
-						EVENT_DATA_COMPLETE)) {
 				host->data = NULL;
-				mrq->data->error = -ENOMEDIUM;
+				host->cmd = NULL;
+
+				switch (host->state) {
+				case STATE_IDLE:
+					break;
+				case STATE_SENDING_CMD:
+					mrq->cmd->error = -ENOMEDIUM;
+					if (!mrq->data)
+						break;
+					/* fall through */
+				case STATE_SENDING_DATA:
+					mrq->data->error = -ENOMEDIUM;
+					atmci_stop_dma(host);
+					break;
+				case STATE_DATA_BUSY:
+				case STATE_DATA_ERROR:
+					if (mrq->data->error == -EINPROGRESS)
+						mrq->data->error = -ENOMEDIUM;
+					if (!mrq->stop)
+						break;
+					/* fall through */
+				case STATE_SENDING_STOP:
+					mrq->stop->error = -ENOMEDIUM;
+					break;
+				}
+
+				atmci_request_end(host, mrq);
+			} else {
+				list_del(&slot->queue_node);
+				mrq->cmd->error = -ENOMEDIUM;
+				if (mrq->data)
+					mrq->data->error = -ENOMEDIUM;
+				if (mrq->stop)
+					mrq->stop->error = -ENOMEDIUM;
+
+				spin_unlock(&host->lock);
+				mmc_request_done(slot->mmc, mrq);
+				spin_lock(&host->lock);
 			}
-			if (mrq->stop && !atmci_is_completed(host,
-						EVENT_STOP_COMPLETE))
-				mrq->stop->error = -ENOMEDIUM;
-
-			host->cmd = NULL;
-			atmci_request_end(host->mmc, mrq);
 		}
+		spin_unlock(&host->lock);
 
-		mmc_detect_change(host->mmc, 0);
+		mmc_detect_change(slot->mmc, 0);
 	}
 }
 
 static void atmci_tasklet_func(unsigned long priv)
 {
-	struct mmc_host		*mmc = (struct mmc_host *)priv;
-	struct atmel_mci	*host = mmc_priv(mmc);
+	struct atmel_mci	*host = (struct atmel_mci *)priv;
 	struct mmc_request	*mrq = host->mrq;
 	struct mmc_data		*data = host->data;
+	struct mmc_command	*cmd = host->cmd;
+	enum atmel_mci_state	state = host->state;
+	enum atmel_mci_state	prev_state;
+	u32			status;
 
-	dev_vdbg(&mmc->class_dev,
-		"tasklet: pending/completed/mask %lx/%lx/%x\n",
-		host->pending_events, host->completed_events,
+	spin_lock(&host->lock);
+
+	state = host->state;
+
+	dev_vdbg(&host->pdev->dev,
+		"tasklet: state %u pending/completed/mask %lx/%lx/%x\n",
+		state, host->pending_events, host->completed_events,
 		mci_readl(host, IMR));
 
-	if (atmci_test_and_clear_pending(host, EVENT_CMD_COMPLETE)) {
-		/*
-		 * host->cmd must be set to NULL before the interrupt
-		 * handler sees EVENT_CMD_COMPLETE
-		 */
-		host->cmd = NULL;
-		smp_wmb();
-		atmci_set_completed(host, EVENT_CMD_COMPLETE);
-		atmci_command_complete(host, mrq->cmd, host->cmd_status);
+	do {
+		prev_state = state;
 
-		if (!mrq->cmd->error && mrq->stop
-				&& atmci_is_completed(host, EVENT_XFER_COMPLETE)
-				&& !atmci_test_and_set_completed(host,
-					EVENT_STOP_SENT))
-			send_stop_cmd(host->mmc, mrq->data);
-	}
-	if (atmci_test_and_clear_pending(host, EVENT_STOP_COMPLETE)) {
-		/*
-		 * host->cmd must be set to NULL before the interrupt
-		 * handler sees EVENT_STOP_COMPLETE
-		 */
-		host->cmd = NULL;
-		smp_wmb();
-		atmci_set_completed(host, EVENT_STOP_COMPLETE);
-		atmci_command_complete(host, mrq->stop, host->stop_status);
-	}
-	if (atmci_test_and_clear_pending(host, EVENT_DATA_ERROR)) {
-		u32 status = host->data_status;
+		switch (state) {
+		case STATE_IDLE:
+			break;
 
-		dev_vdbg(&mmc->class_dev, "data error: status=%08x\n", status);
+		case STATE_SENDING_CMD:
+			if (!atmci_test_and_clear_pending(host,
+						EVENT_CMD_COMPLETE))
+				break;
 
-		atmci_set_completed(host, EVENT_DATA_ERROR);
-		atmci_set_completed(host, EVENT_DATA_COMPLETE);
+			host->cmd = NULL;
+			atmci_set_completed(host, EVENT_CMD_COMPLETE);
+			atmci_command_complete(host, mrq->cmd);
+			if (!mrq->data || cmd->error) {
+				atmci_request_end(host, host->mrq);
+				goto unlock;
+			}
 
-		if (status & MCI_DTOE) {
-			dev_dbg(&mmc->class_dev,
-					"data timeout error\n");
-			data->error = -ETIMEDOUT;
-		} else if (status & MCI_DCRCE) {
-			dev_dbg(&mmc->class_dev, "data CRC error\n");
-			data->error = -EILSEQ;
-		} else {
-			dev_dbg(&mmc->class_dev,
-					"data FIFO error (status=%08x)\n",
-					status);
-			data->error = -EIO;
+			prev_state = state = STATE_SENDING_DATA;
+			/* fall through */
+
+		case STATE_SENDING_DATA:
+			if (atmci_test_and_clear_pending(host,
+						EVENT_DATA_ERROR)) {
+				atmci_stop_dma(host);
+				if (data->stop)
+					send_stop_cmd(host, data);
+				state = STATE_DATA_ERROR;
+				break;
+			}
+
+			if (!atmci_test_and_clear_pending(host,
+						EVENT_XFER_COMPLETE))
+				break;
+
+			atmci_set_completed(host, EVENT_XFER_COMPLETE);
+			prev_state = state = STATE_DATA_BUSY;
+			/* fall through */
+
+		case STATE_DATA_BUSY:
+			if (!atmci_test_and_clear_pending(host,
+						EVENT_DATA_COMPLETE))
+				break;
+
+			host->data = NULL;
+			atmci_set_completed(host, EVENT_DATA_COMPLETE);
+			status = host->data_status;
+			if (unlikely(status & ATMCI_DATA_ERROR_FLAGS)) {
+				if (status & MCI_DTOE) {
+					dev_dbg(&host->pdev->dev,
+							"data timeout error\n");
+					data->error = -ETIMEDOUT;
+				} else if (status & MCI_DCRCE) {
+					dev_dbg(&host->pdev->dev,
+							"data CRC error\n");
+					data->error = -EILSEQ;
+				} else {
+					dev_dbg(&host->pdev->dev,
+						"data FIFO error (status=%08x)\n",
+						status);
+					data->error = -EIO;
+				}
+			} else {
+				data->bytes_xfered = data->blocks * data->blksz;
+				data->error = 0;
+			}
+
+			if (!data->stop) {
+				atmci_request_end(host, host->mrq);
+				goto unlock;
+			}
+
+			prev_state = state = STATE_SENDING_STOP;
+			if (!data->error)
+				send_stop_cmd(host, data);
+			/* fall through */
+
+		case STATE_SENDING_STOP:
+			if (!atmci_test_and_clear_pending(host,
+						EVENT_CMD_COMPLETE))
+				break;
+
+			host->cmd = NULL;
+			atmci_command_complete(host, mrq->stop);
+			atmci_request_end(host, host->mrq);
+			goto unlock;
+
+		case STATE_DATA_ERROR:
+			if (!atmci_test_and_clear_pending(host,
+						EVENT_XFER_COMPLETE))
+				break;
+
+			state = STATE_DATA_BUSY;
+			break;
 		}
+	} while (state != prev_state);
 
-		if (host->present && data->stop
-				&& atmci_is_completed(host, EVENT_CMD_COMPLETE)
-				&& !atmci_test_and_set_completed(
-					host, EVENT_STOP_SENT))
-			send_stop_cmd(host->mmc, data);
+	host->state = state;
 
-		host->data = NULL;
-	}
-	if (atmci_test_and_clear_pending(host, EVENT_DATA_COMPLETE)) {
-		atmci_set_completed(host, EVENT_DATA_COMPLETE);
-
-		if (!atmci_is_completed(host, EVENT_DATA_ERROR)) {
-			data->bytes_xfered = data->blocks * data->blksz;
-			data->error = 0;
-		}
-
-		host->data = NULL;
-	}
-
-	if (host->mrq && !host->cmd && !host->data)
-		atmci_request_end(mmc, host->mrq);
+unlock:
+	spin_unlock(&host->lock);
 }
 
 static void atmci_read_data_pio(struct atmel_mci *host)
@@ -787,6 +1253,7 @@
 			nbytes += 4;
 
 			if (offset == sg->length) {
+				flush_dcache_page(sg_page(sg));
 				host->sg = sg = sg_next(sg);
 				if (!sg)
 					goto done;
@@ -815,9 +1282,11 @@
 			mci_writel(host, IDR, (MCI_NOTBUSY | MCI_RXRDY
 						| ATMCI_DATA_ERROR_FLAGS));
 			host->data_status = status;
+			data->bytes_xfered += nbytes;
+			smp_wmb();
 			atmci_set_pending(host, EVENT_DATA_ERROR);
 			tasklet_schedule(&host->tasklet);
-			break;
+			return;
 		}
 	} while (status & MCI_RXRDY);
 
@@ -830,10 +1299,8 @@
 	mci_writel(host, IDR, MCI_RXRDY);
 	mci_writel(host, IER, MCI_NOTBUSY);
 	data->bytes_xfered += nbytes;
-	atmci_set_completed(host, EVENT_XFER_COMPLETE);
-	if (data->stop && atmci_is_completed(host, EVENT_CMD_COMPLETE)
-			&& !atmci_test_and_set_completed(host, EVENT_STOP_SENT))
-		send_stop_cmd(host->mmc, data);
+	smp_wmb();
+	atmci_set_pending(host, EVENT_XFER_COMPLETE);
 }
 
 static void atmci_write_data_pio(struct atmel_mci *host)
@@ -886,9 +1353,11 @@
 			mci_writel(host, IDR, (MCI_NOTBUSY | MCI_TXRDY
 						| ATMCI_DATA_ERROR_FLAGS));
 			host->data_status = status;
+			data->bytes_xfered += nbytes;
+			smp_wmb();
 			atmci_set_pending(host, EVENT_DATA_ERROR);
 			tasklet_schedule(&host->tasklet);
-			break;
+			return;
 		}
 	} while (status & MCI_TXRDY);
 
@@ -901,38 +1370,26 @@
 	mci_writel(host, IDR, MCI_TXRDY);
 	mci_writel(host, IER, MCI_NOTBUSY);
 	data->bytes_xfered += nbytes;
-	atmci_set_completed(host, EVENT_XFER_COMPLETE);
-	if (data->stop && atmci_is_completed(host, EVENT_CMD_COMPLETE)
-			&& !atmci_test_and_set_completed(host, EVENT_STOP_SENT))
-		send_stop_cmd(host->mmc, data);
+	smp_wmb();
+	atmci_set_pending(host, EVENT_XFER_COMPLETE);
 }
 
-static void atmci_cmd_interrupt(struct mmc_host *mmc, u32 status)
+static void atmci_cmd_interrupt(struct atmel_mci *host, u32 status)
 {
-	struct atmel_mci	*host = mmc_priv(mmc);
-
 	mci_writel(host, IDR, MCI_CMDRDY);
 
-	if (atmci_is_completed(host, EVENT_STOP_SENT)) {
-		host->stop_status = status;
-		atmci_set_pending(host, EVENT_STOP_COMPLETE);
-	} else {
-		host->cmd_status = status;
-		atmci_set_pending(host, EVENT_CMD_COMPLETE);
-	}
-
+	host->cmd_status = status;
+	smp_wmb();
+	atmci_set_pending(host, EVENT_CMD_COMPLETE);
 	tasklet_schedule(&host->tasklet);
 }
 
 static irqreturn_t atmci_interrupt(int irq, void *dev_id)
 {
-	struct mmc_host		*mmc = dev_id;
-	struct atmel_mci	*host = mmc_priv(mmc);
+	struct atmel_mci	*host = dev_id;
 	u32			status, mask, pending;
 	unsigned int		pass_count = 0;
 
-	spin_lock(&mmc->lock);
-
 	do {
 		status = mci_readl(host, SR);
 		mask = mci_readl(host, IMR);
@@ -944,13 +1401,18 @@
 			mci_writel(host, IDR, ATMCI_DATA_ERROR_FLAGS
 					| MCI_RXRDY | MCI_TXRDY);
 			pending &= mci_readl(host, IMR);
+
 			host->data_status = status;
+			smp_wmb();
 			atmci_set_pending(host, EVENT_DATA_ERROR);
 			tasklet_schedule(&host->tasklet);
 		}
 		if (pending & MCI_NOTBUSY) {
-			mci_writel(host, IDR, (MCI_NOTBUSY
-					       | ATMCI_DATA_ERROR_FLAGS));
+			mci_writel(host, IDR,
+					ATMCI_DATA_ERROR_FLAGS | MCI_NOTBUSY);
+			if (!host->data_status)
+				host->data_status = status;
+			smp_wmb();
 			atmci_set_pending(host, EVENT_DATA_COMPLETE);
 			tasklet_schedule(&host->tasklet);
 		}
@@ -960,18 +1422,15 @@
 			atmci_write_data_pio(host);
 
 		if (pending & MCI_CMDRDY)
-			atmci_cmd_interrupt(mmc, status);
+			atmci_cmd_interrupt(host, status);
 	} while (pass_count++ < 5);
 
-	spin_unlock(&mmc->lock);
-
 	return pass_count ? IRQ_HANDLED : IRQ_NONE;
 }
 
 static irqreturn_t atmci_detect_interrupt(int irq, void *dev_id)
 {
-	struct mmc_host		*mmc = dev_id;
-	struct atmel_mci	*host = mmc_priv(mmc);
+	struct atmel_mci_slot	*slot = dev_id;
 
 	/*
 	 * Disable interrupts until the pin has stabilized and check
@@ -979,19 +1438,176 @@
 	 * middle of the timer routine when this interrupt triggers.
 	 */
 	disable_irq_nosync(irq);
-	mod_timer(&host->detect_timer, jiffies + msecs_to_jiffies(20));
+	mod_timer(&slot->detect_timer, jiffies + msecs_to_jiffies(20));
 
 	return IRQ_HANDLED;
 }
 
+#ifdef CONFIG_MMC_ATMELMCI_DMA
+
+static inline struct atmel_mci *
+dma_client_to_atmel_mci(struct dma_client *client)
+{
+	return container_of(client, struct atmel_mci, dma.client);
+}
+
+static enum dma_state_client atmci_dma_event(struct dma_client *client,
+		struct dma_chan *chan, enum dma_state state)
+{
+	struct atmel_mci	*host;
+	enum dma_state_client	ret = DMA_NAK;
+
+	host = dma_client_to_atmel_mci(client);
+
+	switch (state) {
+	case DMA_RESOURCE_AVAILABLE:
+		spin_lock_bh(&host->lock);
+		if (!host->dma.chan) {
+			host->dma.chan = chan;
+			ret = DMA_ACK;
+		}
+		spin_unlock_bh(&host->lock);
+
+		if (ret == DMA_ACK)
+			dev_info(&host->pdev->dev,
+					"Using %s for DMA transfers\n",
+					chan->dev.bus_id);
+		break;
+
+	case DMA_RESOURCE_REMOVED:
+		spin_lock_bh(&host->lock);
+		if (host->dma.chan == chan) {
+			host->dma.chan = NULL;
+			ret = DMA_ACK;
+		}
+		spin_unlock_bh(&host->lock);
+
+		if (ret == DMA_ACK)
+			dev_info(&host->pdev->dev,
+					"Lost %s, falling back to PIO\n",
+					chan->dev.bus_id);
+		break;
+
+	default:
+		break;
+	}
+
+
+	return ret;
+}
+#endif /* CONFIG_MMC_ATMELMCI_DMA */
+
+static int __init atmci_init_slot(struct atmel_mci *host,
+		struct mci_slot_pdata *slot_data, unsigned int id,
+		u32 sdc_reg)
+{
+	struct mmc_host			*mmc;
+	struct atmel_mci_slot		*slot;
+
+	mmc = mmc_alloc_host(sizeof(struct atmel_mci_slot), &host->pdev->dev);
+	if (!mmc)
+		return -ENOMEM;
+
+	slot = mmc_priv(mmc);
+	slot->mmc = mmc;
+	slot->host = host;
+	slot->detect_pin = slot_data->detect_pin;
+	slot->wp_pin = slot_data->wp_pin;
+	slot->sdc_reg = sdc_reg;
+
+	mmc->ops = &atmci_ops;
+	mmc->f_min = DIV_ROUND_UP(host->bus_hz, 512);
+	mmc->f_max = host->bus_hz / 2;
+	mmc->ocr_avail	= MMC_VDD_32_33 | MMC_VDD_33_34;
+	if (slot_data->bus_width >= 4)
+		mmc->caps |= MMC_CAP_4_BIT_DATA;
+
+	mmc->max_hw_segs = 64;
+	mmc->max_phys_segs = 64;
+	mmc->max_req_size = 32768 * 512;
+	mmc->max_blk_size = 32768;
+	mmc->max_blk_count = 512;
+
+	/* Assume card is present initially */
+	set_bit(ATMCI_CARD_PRESENT, &slot->flags);
+	if (gpio_is_valid(slot->detect_pin)) {
+		if (gpio_request(slot->detect_pin, "mmc_detect")) {
+			dev_dbg(&mmc->class_dev, "no detect pin available\n");
+			slot->detect_pin = -EBUSY;
+		} else if (gpio_get_value(slot->detect_pin)) {
+			clear_bit(ATMCI_CARD_PRESENT, &slot->flags);
+		}
+	}
+
+	if (!gpio_is_valid(slot->detect_pin))
+		mmc->caps |= MMC_CAP_NEEDS_POLL;
+
+	if (gpio_is_valid(slot->wp_pin)) {
+		if (gpio_request(slot->wp_pin, "mmc_wp")) {
+			dev_dbg(&mmc->class_dev, "no WP pin available\n");
+			slot->wp_pin = -EBUSY;
+		}
+	}
+
+	host->slot[id] = slot;
+	mmc_add_host(mmc);
+
+	if (gpio_is_valid(slot->detect_pin)) {
+		int ret;
+
+		setup_timer(&slot->detect_timer, atmci_detect_change,
+				(unsigned long)slot);
+
+		ret = request_irq(gpio_to_irq(slot->detect_pin),
+				atmci_detect_interrupt,
+				IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
+				"mmc-detect", slot);
+		if (ret) {
+			dev_dbg(&mmc->class_dev,
+				"could not request IRQ %d for detect pin\n",
+				gpio_to_irq(slot->detect_pin));
+			gpio_free(slot->detect_pin);
+			slot->detect_pin = -EBUSY;
+		}
+	}
+
+	atmci_init_debugfs(slot);
+
+	return 0;
+}
+
+static void __exit atmci_cleanup_slot(struct atmel_mci_slot *slot,
+		unsigned int id)
+{
+	/* Debugfs stuff is cleaned up by mmc core */
+
+	set_bit(ATMCI_SHUTDOWN, &slot->flags);
+	smp_wmb();
+
+	mmc_remove_host(slot->mmc);
+
+	if (gpio_is_valid(slot->detect_pin)) {
+		int pin = slot->detect_pin;
+
+		free_irq(gpio_to_irq(pin), slot);
+		del_timer_sync(&slot->detect_timer);
+		gpio_free(pin);
+	}
+	if (gpio_is_valid(slot->wp_pin))
+		gpio_free(slot->wp_pin);
+
+	slot->host->slot[id] = NULL;
+	mmc_free_host(slot->mmc);
+}
+
 static int __init atmci_probe(struct platform_device *pdev)
 {
 	struct mci_platform_data	*pdata;
-	struct atmel_mci *host;
-	struct mmc_host *mmc;
-	struct resource *regs;
-	int irq;
-	int ret;
+	struct atmel_mci		*host;
+	struct resource			*regs;
+	unsigned int			nr_slots;
+	int				irq;
+	int				ret;
 
 	regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	if (!regs)
@@ -1003,15 +1619,13 @@
 	if (irq < 0)
 		return irq;
 
-	mmc = mmc_alloc_host(sizeof(struct atmel_mci), &pdev->dev);
-	if (!mmc)
+	host = kzalloc(sizeof(struct atmel_mci), GFP_KERNEL);
+	if (!host)
 		return -ENOMEM;
 
-	host = mmc_priv(mmc);
 	host->pdev = pdev;
-	host->mmc = mmc;
-	host->detect_pin = pdata->detect_pin;
-	host->wp_pin = pdata->wp_pin;
+	spin_lock_init(&host->lock);
+	INIT_LIST_HEAD(&host->queue);
 
 	host->mck = clk_get(&pdev->dev, "mci_clk");
 	if (IS_ERR(host->mck)) {
@@ -1031,118 +1645,102 @@
 
 	host->mapbase = regs->start;
 
-	mmc->ops = &atmci_ops;
-	mmc->f_min = (host->bus_hz + 511) / 512;
-	mmc->f_max = host->bus_hz / 2;
-	mmc->ocr_avail	= MMC_VDD_32_33 | MMC_VDD_33_34;
-	mmc->caps |= MMC_CAP_4_BIT_DATA;
+	tasklet_init(&host->tasklet, atmci_tasklet_func, (unsigned long)host);
 
-	mmc->max_hw_segs = 64;
-	mmc->max_phys_segs = 64;
-	mmc->max_req_size = 32768 * 512;
-	mmc->max_blk_size = 32768;
-	mmc->max_blk_count = 512;
-
-	tasklet_init(&host->tasklet, atmci_tasklet_func, (unsigned long)mmc);
-
-	ret = request_irq(irq, atmci_interrupt, 0, pdev->dev.bus_id, mmc);
+	ret = request_irq(irq, atmci_interrupt, 0, pdev->dev.bus_id, host);
 	if (ret)
 		goto err_request_irq;
 
-	/* Assume card is present if we don't have a detect pin */
-	host->present = 1;
-	if (gpio_is_valid(host->detect_pin)) {
-		if (gpio_request(host->detect_pin, "mmc_detect")) {
-			dev_dbg(&mmc->class_dev, "no detect pin available\n");
-			host->detect_pin = -1;
-		} else {
-			host->present = !gpio_get_value(host->detect_pin);
-		}
+#ifdef CONFIG_MMC_ATMELMCI_DMA
+	if (pdata->dma_slave) {
+		struct dma_slave *slave = pdata->dma_slave;
+
+		slave->tx_reg = regs->start + MCI_TDR;
+		slave->rx_reg = regs->start + MCI_RDR;
+
+		/* Try to grab a DMA channel */
+		host->dma.client.event_callback = atmci_dma_event;
+		dma_cap_set(DMA_SLAVE, host->dma.client.cap_mask);
+		host->dma.client.slave = slave;
+
+		dma_async_client_register(&host->dma.client);
+		dma_async_client_chan_request(&host->dma.client);
+	} else {
+		dev_notice(&pdev->dev, "DMA not available, using PIO\n");
 	}
-	if (gpio_is_valid(host->wp_pin)) {
-		if (gpio_request(host->wp_pin, "mmc_wp")) {
-			dev_dbg(&mmc->class_dev, "no WP pin available\n");
-			host->wp_pin = -1;
-		}
-	}
+#endif /* CONFIG_MMC_ATMELMCI_DMA */
 
 	platform_set_drvdata(pdev, host);
 
-	mmc_add_host(mmc);
-
-	if (gpio_is_valid(host->detect_pin)) {
-		setup_timer(&host->detect_timer, atmci_detect_change,
-				(unsigned long)host);
-
-		ret = request_irq(gpio_to_irq(host->detect_pin),
-				atmci_detect_interrupt,
-				IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
-				"mmc-detect", mmc);
-		if (ret) {
-			dev_dbg(&mmc->class_dev,
-				"could not request IRQ %d for detect pin\n",
-				gpio_to_irq(host->detect_pin));
-			gpio_free(host->detect_pin);
-			host->detect_pin = -1;
-		}
+	/* We need at least one slot to succeed */
+	nr_slots = 0;
+	ret = -ENODEV;
+	if (pdata->slot[0].bus_width) {
+		ret = atmci_init_slot(host, &pdata->slot[0],
+				MCI_SDCSEL_SLOT_A, 0);
+		if (!ret)
+			nr_slots++;
+	}
+	if (pdata->slot[1].bus_width) {
+		ret = atmci_init_slot(host, &pdata->slot[1],
+				MCI_SDCSEL_SLOT_B, 1);
+		if (!ret)
+			nr_slots++;
 	}
 
-	dev_info(&mmc->class_dev,
-			"Atmel MCI controller at 0x%08lx irq %d\n",
-			host->mapbase, irq);
+	if (!nr_slots)
+		goto err_init_slot;
 
-	atmci_init_debugfs(host);
+	dev_info(&pdev->dev,
+			"Atmel MCI controller at 0x%08lx irq %d, %u slots\n",
+			host->mapbase, irq, nr_slots);
 
 	return 0;
 
+err_init_slot:
+#ifdef CONFIG_MMC_ATMELMCI_DMA
+	if (pdata->dma_slave)
+		dma_async_client_unregister(&host->dma.client);
+#endif
+	free_irq(irq, host);
 err_request_irq:
 	iounmap(host->regs);
 err_ioremap:
 	clk_put(host->mck);
 err_clk_get:
-	mmc_free_host(mmc);
+	kfree(host);
 	return ret;
 }
 
 static int __exit atmci_remove(struct platform_device *pdev)
 {
-	struct atmel_mci *host = platform_get_drvdata(pdev);
+	struct atmel_mci	*host = platform_get_drvdata(pdev);
+	unsigned int		i;
 
 	platform_set_drvdata(pdev, NULL);
 
-	if (host) {
-		/* Debugfs stuff is cleaned up by mmc core */
-
-		if (gpio_is_valid(host->detect_pin)) {
-			int pin = host->detect_pin;
-
-			/* Make sure the timer doesn't enable the interrupt */
-			host->detect_pin = -1;
-			smp_wmb();
-
-			free_irq(gpio_to_irq(pin), host->mmc);
-			del_timer_sync(&host->detect_timer);
-			gpio_free(pin);
-		}
-
-		mmc_remove_host(host->mmc);
-
-		clk_enable(host->mck);
-		mci_writel(host, IDR, ~0UL);
-		mci_writel(host, CR, MCI_CR_MCIDIS);
-		mci_readl(host, SR);
-		clk_disable(host->mck);
-
-		if (gpio_is_valid(host->wp_pin))
-			gpio_free(host->wp_pin);
-
-		free_irq(platform_get_irq(pdev, 0), host->mmc);
-		iounmap(host->regs);
-
-		clk_put(host->mck);
-
-		mmc_free_host(host->mmc);
+	for (i = 0; i < ATMEL_MCI_MAX_NR_SLOTS; i++) {
+		if (host->slot[i])
+			atmci_cleanup_slot(host->slot[i], i);
 	}
+
+	clk_enable(host->mck);
+	mci_writel(host, IDR, ~0UL);
+	mci_writel(host, CR, MCI_CR_MCIDIS);
+	mci_readl(host, SR);
+	clk_disable(host->mck);
+
+#ifdef CONFIG_MMC_ATMELMCI_DMA
+	if (host->dma.client.slave)
+		dma_async_client_unregister(&host->dma.client);
+#endif
+
+	free_irq(platform_get_irq(pdev, 0), host);
+	iounmap(host->regs);
+
+	clk_put(host->mck);
+	kfree(host);
+
 	return 0;
 }
 
diff --git a/drivers/mmc/host/mmc_spi.c b/drivers/mmc/host/mmc_spi.c
index 7503b81..07faf54 100644
--- a/drivers/mmc/host/mmc_spi.c
+++ b/drivers/mmc/host/mmc_spi.c
@@ -95,8 +95,6 @@
  * reads which takes nowhere near that long.  Older cards may be able to use
  * shorter timeouts ... but why bother?
  */
-#define readblock_timeout	ktime_set(0, 100 * 1000 * 1000)
-#define writeblock_timeout	ktime_set(0, 250 * 1000 * 1000)
 #define r1b_timeout		ktime_set(3, 0)
 
 
@@ -220,9 +218,9 @@
 	return mmc_spi_skip(host, timeout, sizeof(host->data->status), 0);
 }
 
-static int mmc_spi_readtoken(struct mmc_spi_host *host)
+static int mmc_spi_readtoken(struct mmc_spi_host *host, ktime_t timeout)
 {
-	return mmc_spi_skip(host, readblock_timeout, 1, 0xff);
+	return mmc_spi_skip(host, timeout, 1, 0xff);
 }
 
 
@@ -605,7 +603,8 @@
  * Return negative errno, else success.
  */
 static int
-mmc_spi_writeblock(struct mmc_spi_host *host, struct spi_transfer *t)
+mmc_spi_writeblock(struct mmc_spi_host *host, struct spi_transfer *t,
+	ktime_t timeout)
 {
 	struct spi_device	*spi = host->spi;
 	int			status, i;
@@ -673,7 +672,7 @@
 		if (scratch->status[i] != 0)
 			return 0;
 	}
-	return mmc_spi_wait_unbusy(host, writeblock_timeout);
+	return mmc_spi_wait_unbusy(host, timeout);
 }
 
 /*
@@ -693,7 +692,8 @@
  * STOP_TRANSMISSION command.
  */
 static int
-mmc_spi_readblock(struct mmc_spi_host *host, struct spi_transfer *t)
+mmc_spi_readblock(struct mmc_spi_host *host, struct spi_transfer *t,
+	ktime_t timeout)
 {
 	struct spi_device	*spi = host->spi;
 	int			status;
@@ -707,7 +707,7 @@
 		return status;
 	status = scratch->status[0];
 	if (status == 0xff || status == 0)
-		status = mmc_spi_readtoken(host);
+		status = mmc_spi_readtoken(host, timeout);
 
 	if (status == SPI_TOKEN_SINGLE) {
 		if (host->dma_dev) {
@@ -778,6 +778,8 @@
 	struct scatterlist	*sg;
 	unsigned		n_sg;
 	int			multiple = (data->blocks > 1);
+	u32			clock_rate;
+	ktime_t			timeout;
 
 	if (data->flags & MMC_DATA_READ)
 		direction = DMA_FROM_DEVICE;
@@ -786,6 +788,14 @@
 	mmc_spi_setup_data_message(host, multiple, direction);
 	t = &host->t;
 
+	if (t->speed_hz)
+		clock_rate = t->speed_hz;
+	else
+		clock_rate = spi->max_speed_hz;
+
+	timeout = ktime_add_ns(ktime_set(0, 0), data->timeout_ns +
+			data->timeout_clks * 1000000 / clock_rate);
+
 	/* Handle scatterlist segments one at a time, with synch for
 	 * each 512-byte block
 	 */
@@ -832,9 +842,9 @@
 				t->len);
 
 			if (direction == DMA_TO_DEVICE)
-				status = mmc_spi_writeblock(host, t);
+				status = mmc_spi_writeblock(host, t, timeout);
 			else
-				status = mmc_spi_readblock(host, t);
+				status = mmc_spi_readblock(host, t, timeout);
 			if (status < 0)
 				break;
 
@@ -917,7 +927,7 @@
 			if (scratch->status[tmp] != 0)
 				return;
 		}
-		tmp = mmc_spi_wait_unbusy(host, writeblock_timeout);
+		tmp = mmc_spi_wait_unbusy(host, timeout);
 		if (tmp < 0 && !data->error)
 			data->error = tmp;
 	}
diff --git a/drivers/mmc/host/pxamci.c b/drivers/mmc/host/pxamci.c
index 55093ad..ebfaa99 100644
--- a/drivers/mmc/host/pxamci.c
+++ b/drivers/mmc/host/pxamci.c
@@ -520,7 +520,7 @@
 	/*
 	 * Block length register is only 10 bits before PXA27x.
 	 */
-	mmc->max_blk_size = (cpu_is_pxa21x() || cpu_is_pxa25x()) ? 1023 : 2048;
+	mmc->max_blk_size = cpu_is_pxa25x() ? 1023 : 2048;
 
 	/*
 	 * Block count register is 16 bits.
@@ -554,7 +554,7 @@
 			 MMC_VDD_32_33|MMC_VDD_33_34;
 	mmc->caps = 0;
 	host->cmdat = 0;
-	if (!cpu_is_pxa21x() && !cpu_is_pxa25x()) {
+	if (!cpu_is_pxa25x()) {
 		mmc->caps |= MMC_CAP_4_BIT_DATA | MMC_CAP_SDIO_IRQ;
 		host->cmdat |= CMDAT_SDIO_INT_EN;
 		if (cpu_is_pxa300() || cpu_is_pxa310())
diff --git a/drivers/mmc/host/sdhci-pci.c b/drivers/mmc/host/sdhci-pci.c
index fcb14c2..9bd7026 100644
--- a/drivers/mmc/host/sdhci-pci.c
+++ b/drivers/mmc/host/sdhci-pci.c
@@ -144,7 +144,8 @@
 			  SDHCI_QUIRK_32BIT_DMA_SIZE |
 			  SDHCI_QUIRK_32BIT_ADMA_SIZE |
 			  SDHCI_QUIRK_RESET_AFTER_REQUEST |
-			  SDHCI_QUIRK_BROKEN_SMALL_PIO;
+			  SDHCI_QUIRK_BROKEN_SMALL_PIO |
+			  SDHCI_QUIRK_FORCE_HIGHSPEED;
 	}
 
 	/*
@@ -326,7 +327,7 @@
 
 	{
 		.vendor         = PCI_VENDOR_ID_MARVELL,
-		.device         = PCI_DEVICE_ID_MARVELL_CAFE_SD,
+		.device         = PCI_DEVICE_ID_MARVELL_88ALP01_SD,
 		.subvendor      = PCI_ANY_ID,
 		.subdevice      = PCI_ANY_ID,
 		.driver_data    = (kernel_ulong_t)&sdhci_cafe,
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index e3a8133..30f64b1 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -177,7 +177,7 @@
 {
 	unsigned long flags;
 	size_t blksize, len, chunk;
-	u32 scratch;
+	u32 uninitialized_var(scratch);
 	u8 *buf;
 
 	DBG("PIO reading\n");
@@ -1154,7 +1154,7 @@
 
 	spin_unlock_irqrestore(&host->lock, flags);
 
-	mmc_detect_change(host->mmc, msecs_to_jiffies(500));
+	mmc_detect_change(host->mmc, msecs_to_jiffies(200));
 }
 
 static void sdhci_tasklet_finish(unsigned long param)
@@ -1266,9 +1266,31 @@
 			SDHCI_INT_INDEX))
 		host->cmd->error = -EILSEQ;
 
-	if (host->cmd->error)
+	if (host->cmd->error) {
 		tasklet_schedule(&host->finish_tasklet);
-	else if (intmask & SDHCI_INT_RESPONSE)
+		return;
+	}
+
+	/*
+	 * The host can send and interrupt when the busy state has
+	 * ended, allowing us to wait without wasting CPU cycles.
+	 * Unfortunately this is overloaded on the "data complete"
+	 * interrupt, so we need to take some care when handling
+	 * it.
+	 *
+	 * Note: The 1.0 specification is a bit ambiguous about this
+	 *       feature so there might be some problems with older
+	 *       controllers.
+	 */
+	if (host->cmd->flags & MMC_RSP_BUSY) {
+		if (host->cmd->data)
+			DBG("Cannot wait for busy signal when also "
+				"doing a data transfer");
+		else
+			return;
+	}
+
+	if (intmask & SDHCI_INT_RESPONSE)
 		sdhci_finish_command(host);
 }
 
@@ -1278,11 +1300,16 @@
 
 	if (!host->data) {
 		/*
-		 * A data end interrupt is sent together with the response
-		 * for the stop command.
+		 * The "data complete" interrupt is also used to
+		 * indicate that a busy state has ended. See comment
+		 * above in sdhci_cmd_irq().
 		 */
-		if (intmask & SDHCI_INT_DATA_END)
-			return;
+		if (host->cmd && (host->cmd->flags & MMC_RSP_BUSY)) {
+			if (intmask & SDHCI_INT_DATA_END) {
+				sdhci_finish_command(host);
+				return;
+			}
+		}
 
 		printk(KERN_ERR "%s: Got data interrupt 0x%08x even "
 			"though no data operation was in progress.\n",
@@ -1604,7 +1631,8 @@
 	mmc->f_max = host->max_clk;
 	mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_SDIO_IRQ;
 
-	if (caps & SDHCI_CAN_DO_HISPD)
+	if ((caps & SDHCI_CAN_DO_HISPD) ||
+		(host->quirks & SDHCI_QUIRK_FORCE_HIGHSPEED))
 		mmc->caps |= MMC_CAP_SD_HIGHSPEED;
 
 	mmc->ocr_avail = 0;
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index 197d4a0..31f4b15 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -208,6 +208,8 @@
 #define SDHCI_QUIRK_BROKEN_TIMEOUT_VAL			(1<<12)
 /* Controller has an issue with buffer bits for small transfers */
 #define SDHCI_QUIRK_BROKEN_SMALL_PIO			(1<<13)
+/* Controller supports high speed but doesn't have the caps bit set */
+#define SDHCI_QUIRK_FORCE_HIGHSPEED			(1<<14)
 
 	int			irq;		/* Device IRQ */
 	void __iomem *		ioaddr;		/* Mapped address */
diff --git a/drivers/mmc/host/tmio_mmc.h b/drivers/mmc/host/tmio_mmc.h
index 9e647a0..ba2b424 100644
--- a/drivers/mmc/host/tmio_mmc.h
+++ b/drivers/mmc/host/tmio_mmc.h
@@ -159,10 +159,10 @@
 #define STATUS_TO_TEXT(a) \
 	do { \
 		if (status & TMIO_STAT_##a) \
-			printf(#a); \
+			printk(#a); \
 	} while (0)
 
-void debug_status(u32 status)
+void pr_debug_status(u32 status)
 {
 	printk(KERN_DEBUG "status: %08x = ", status);
 	STATUS_TO_TEXT(CARD_REMOVE);
diff --git a/drivers/mtd/ftl.c b/drivers/mtd/ftl.c
index f34f20c..9bf581c 100644
--- a/drivers/mtd/ftl.c
+++ b/drivers/mtd/ftl.c
@@ -1005,6 +1005,29 @@
 	return ftl_write((void *)dev, buf, block, 1);
 }
 
+static int ftl_discardsect(struct mtd_blktrans_dev *dev,
+			   unsigned long sector, unsigned nr_sects)
+{
+	partition_t *part = (void *)dev;
+	uint32_t bsize = 1 << part->header.EraseUnitSize;
+
+	DEBUG(1, "FTL erase sector %ld for %d sectors\n",
+	      sector, nr_sects);
+
+	while (nr_sects) {
+		uint32_t old_addr = part->VirtualBlockMap[sector];
+		if (old_addr != 0xffffffff) {
+			part->VirtualBlockMap[sector] = 0xffffffff;
+			part->EUNInfo[old_addr/bsize].Deleted++;
+			if (set_bam_entry(part, old_addr, 0))
+				return -EIO;
+		}
+		nr_sects--;
+		sector++;
+	}
+
+	return 0;
+}
 /*====================================================================*/
 
 static void ftl_freepart(partition_t *part)
@@ -1069,6 +1092,7 @@
 	.blksize 	= SECTOR_SIZE,
 	.readsect	= ftl_readsect,
 	.writesect	= ftl_writesect,
+	.discard	= ftl_discardsect,
 	.getgeo		= ftl_getgeo,
 	.add_mtd	= ftl_add_mtd,
 	.remove_dev	= ftl_remove_dev,
diff --git a/drivers/mtd/maps/pcmciamtd.c b/drivers/mtd/maps/pcmciamtd.c
index 90924fb..d600c2d 100644
--- a/drivers/mtd/maps/pcmciamtd.c
+++ b/drivers/mtd/maps/pcmciamtd.c
@@ -118,7 +118,8 @@
 		DEBUG(2, "Remapping window from 0x%8.8x to 0x%8.8x",
 		      dev->offset, mrq.CardOffset);
 		mrq.Page = 0;
-		if( (ret = pcmcia_map_mem_page(win, &mrq)) != CS_SUCCESS) {
+		ret = pcmcia_map_mem_page(win, &mrq);
+		if (ret != 0) {
 			cs_error(dev->p_dev, MapMemPage, ret);
 			return NULL;
 		}
@@ -326,9 +327,8 @@
 
 	DEBUG(2, "dev = %p on = %d vpp = %d\n", dev, on, dev->vpp);
 	ret = pcmcia_modify_configuration(link, &mod);
-	if(ret != CS_SUCCESS) {
+	if (ret != 0)
 		cs_error(link, ModifyConfiguration, ret);
-	}
 }
 
 
@@ -368,14 +368,14 @@
 	tuple.DesiredTuple = RETURN_FIRST_TUPLE;
 
 	rc = pcmcia_get_first_tuple(link, &tuple);
-	while(rc == CS_SUCCESS) {
+	while (rc == 0) {
 		rc = pcmcia_get_tuple_data(link, &tuple);
-		if(rc != CS_SUCCESS) {
+		if (rc != 0) {
 			cs_error(link, GetTupleData, rc);
 			break;
 		}
-		rc = pcmcia_parse_tuple(link, &tuple, &parse);
-		if(rc != CS_SUCCESS) {
+		rc = pcmcia_parse_tuple(&tuple, &parse);
+		if (rc != 0) {
 			cs_error(link, ParseTuple, rc);
 			break;
 		}
@@ -493,18 +493,11 @@
 	int last_ret = 0, last_fn = 0;
 	int ret;
 	int i;
-	config_info_t t;
 	static char *probes[] = { "jedec_probe", "cfi_probe" };
 	int new_name = 0;
 
 	DEBUG(3, "link=0x%p", link);
 
-	DEBUG(2, "Validating CIS");
-	ret = pcmcia_validate_cis(link, NULL);
-	if(ret != CS_SUCCESS) {
-		cs_error(link, GetTupleData, ret);
-	}
-
 	card_settings(dev, link, &new_name);
 
 	dev->pcmcia_map.phys = NO_XIP;
@@ -571,10 +564,7 @@
 	dev->pcmcia_map.map_priv_1 = (unsigned long)dev;
 	dev->pcmcia_map.map_priv_2 = (unsigned long)link->win;
 
-	DEBUG(2, "Getting configuration");
-	CS_CHECK(GetConfigurationInfo, pcmcia_get_configuration_info(link, &t));
-	DEBUG(2, "Vcc = %d Vpp1 = %d Vpp2 = %d", t.Vcc, t.Vpp1, t.Vpp2);
-	dev->vpp = (vpp) ? vpp : t.Vpp1;
+	dev->vpp = (vpp) ? vpp : link->socket.socket.Vpp;
 	link->conf.Attributes = 0;
 	if(setvpp == 2) {
 		link->conf.Vpp = dev->vpp;
@@ -583,16 +573,10 @@
 	}
 
 	link->conf.IntType = INT_MEMORY;
-	link->conf.ConfigBase = t.ConfigBase;
-	link->conf.Status = t.Status;
-	link->conf.Pin = t.Pin;
-	link->conf.Copy = t.Copy;
-	link->conf.ExtStatus = t.ExtStatus;
 	link->conf.ConfigIndex = 0;
-	link->conf.Present = t.Present;
 	DEBUG(2, "Setting Configuration");
 	ret = pcmcia_request_configuration(link, &link->conf);
-	if(ret != CS_SUCCESS) {
+	if (ret != 0) {
 		cs_error(link, RequestConfiguration, ret);
 		if (dev->win_base) {
 			iounmap(dev->win_base);
diff --git a/drivers/mtd/maps/sun_uflash.c b/drivers/mtd/maps/sun_uflash.c
index 0d7c883..fd7a101 100644
--- a/drivers/mtd/maps/sun_uflash.c
+++ b/drivers/mtd/maps/sun_uflash.c
@@ -1,13 +1,10 @@
-/*
- *
- * sun_uflash - Driver implementation for user-programmable flash
- * present on many Sun Microsystems SME boardsets.
+/* sun_uflash.c - Driver for user-programmable flash on
+ *                Sun Microsystems SME boardsets.
  *
  * This driver does NOT provide access to the OBP-flash for
  * safety reasons-- use <linux>/drivers/sbus/char/flash.c instead.
  *
  * Copyright (c) 2001 Eric Brower (ebrower@usa.net)
- *
  */
 
 #include <linux/kernel.h>
@@ -16,8 +13,8 @@
 #include <linux/errno.h>
 #include <linux/init.h>
 #include <linux/ioport.h>
-#include <asm/ebus.h>
-#include <asm/oplib.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 #include <asm/prom.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>
@@ -26,67 +23,65 @@
 #include <linux/mtd/map.h>
 
 #define UFLASH_OBPNAME	"flashprom"
-#define UFLASH_DEVNAME 	"userflash"
+#define DRIVER_NAME	"sun_uflash"
+#define PFX		DRIVER_NAME ": "
 
 #define UFLASH_WINDOW_SIZE	0x200000
 #define UFLASH_BUSWIDTH		1			/* EBus is 8-bit */
 
 MODULE_AUTHOR("Eric Brower <ebrower@usa.net>");
 MODULE_DESCRIPTION("User-programmable flash device on Sun Microsystems boardsets");
-MODULE_SUPPORTED_DEVICE("userflash");
+MODULE_SUPPORTED_DEVICE(DRIVER_NAME);
 MODULE_LICENSE("GPL");
-MODULE_VERSION("2.0");
+MODULE_VERSION("2.1");
 
-static LIST_HEAD(device_list);
 struct uflash_dev {
 	const char		*name;	/* device name */
 	struct map_info 	map;	/* mtd map info */
 	struct mtd_info		*mtd;	/* mtd info */
 };
 
-
 struct map_info uflash_map_templ = {
 	.name =		"SUNW,???-????",
 	.size =		UFLASH_WINDOW_SIZE,
 	.bankwidth =	UFLASH_BUSWIDTH,
 };
 
-int uflash_devinit(struct linux_ebus_device *edev, struct device_node *dp)
+int uflash_devinit(struct of_device *op, struct device_node *dp)
 {
 	struct uflash_dev *up;
-	struct resource *res;
 
-	res = &edev->resource[0];
-
-	if (edev->num_addrs != 1) {
+	if (op->resource[1].flags) {
 		/* Non-CFI userflash device-- once I find one we
 		 * can work on supporting it.
 		 */
-		printk("%s: unsupported device at 0x%llx (%d regs): " \
-			"email ebrower@usa.net\n",
-		       dp->full_name, (unsigned long long)res->start,
-		       edev->num_addrs);
+		printk(KERN_ERR PFX "Unsupported device at %s, 0x%llx\n",
+		       dp->full_name, (unsigned long long)op->resource[0].start);
 
 		return -ENODEV;
 	}
 
 	up = kzalloc(sizeof(struct uflash_dev), GFP_KERNEL);
-	if (!up)
+	if (!up) {
+		printk(KERN_ERR PFX "Cannot allocate struct uflash_dev\n");
 		return -ENOMEM;
+	}
 
 	/* copy defaults and tweak parameters */
 	memcpy(&up->map, &uflash_map_templ, sizeof(uflash_map_templ));
-	up->map.size = (res->end - res->start) + 1UL;
+
+	up->map.size = resource_size(&op->resource[0]);
 
 	up->name = of_get_property(dp, "model", NULL);
 	if (up->name && 0 < strlen(up->name))
 		up->map.name = (char *)up->name;
 
-	up->map.phys = res->start;
+	up->map.phys = op->resource[0].start;
 
-	up->map.virt = ioremap_nocache(res->start, up->map.size);
+	up->map.virt = of_ioremap(&op->resource[0], 0, up->map.size,
+				  DRIVER_NAME);
 	if (!up->map.virt) {
-		printk("%s: Failed to map device.\n", dp->full_name);
+		printk(KERN_ERR PFX "Failed to map device.\n");
 		kfree(up);
 
 		return -EINVAL;
@@ -97,7 +92,7 @@
 	/* MTD registration */
 	up->mtd = do_map_probe("cfi_probe", &up->map);
 	if (!up->mtd) {
-		iounmap(up->map.virt);
+		of_iounmap(&op->resource[0], up->map.virt, up->map.size);
 		kfree(up);
 
 		return -ENXIO;
@@ -107,32 +102,34 @@
 
 	add_mtd_device(up->mtd);
 
-	dev_set_drvdata(&edev->ofdev.dev, up);
+	dev_set_drvdata(&op->dev, up);
 
 	return 0;
 }
 
-static int __devinit uflash_probe(struct of_device *dev, const struct of_device_id *match)
+static int __devinit uflash_probe(struct of_device *op, const struct of_device_id *match)
 {
-	struct linux_ebus_device *edev = to_ebus_device(&dev->dev);
-	struct device_node *dp = dev->node;
+	struct device_node *dp = op->node;
 
-	if (of_find_property(dp, "user", NULL))
+	/* Flashprom must have the "user" property in order to
+	 * be used by this driver.
+	 */
+	if (!of_find_property(dp, "user", NULL))
 		return -ENODEV;
 
-	return uflash_devinit(edev, dp);
+	return uflash_devinit(op, dp);
 }
 
-static int __devexit uflash_remove(struct of_device *dev)
+static int __devexit uflash_remove(struct of_device *op)
 {
-	struct uflash_dev *up = dev_get_drvdata(&dev->dev);
+	struct uflash_dev *up = dev_get_drvdata(&op->dev);
 
 	if (up->mtd) {
 		del_mtd_device(up->mtd);
 		map_destroy(up->mtd);
 	}
 	if (up->map.virt) {
-		iounmap(up->map.virt);
+		of_iounmap(&op->resource[0], up->map.virt, up->map.size);
 		up->map.virt = NULL;
 	}
 
@@ -141,7 +138,7 @@
 	return 0;
 }
 
-static struct of_device_id uflash_match[] = {
+static const struct of_device_id uflash_match[] = {
 	{
 		.name = UFLASH_OBPNAME,
 	},
@@ -151,7 +148,7 @@
 MODULE_DEVICE_TABLE(of, uflash_match);
 
 static struct of_platform_driver uflash_driver = {
-	.name		= UFLASH_DEVNAME,
+	.name		= DRIVER_NAME,
 	.match_table	= uflash_match,
 	.probe		= uflash_probe,
 	.remove		= __devexit_p(uflash_remove),
@@ -159,7 +156,7 @@
 
 static int __init uflash_init(void)
 {
-	return of_register_driver(&uflash_driver, &ebus_bus_type);
+	return of_register_driver(&uflash_driver, &of_bus_type);
 }
 
 static void __exit uflash_exit(void)
diff --git a/drivers/mtd/mtd_blkdevs.c b/drivers/mtd/mtd_blkdevs.c
index 9ff007c..681d5ac 100644
--- a/drivers/mtd/mtd_blkdevs.c
+++ b/drivers/mtd/mtd_blkdevs.c
@@ -32,6 +32,14 @@
 	spinlock_t queue_lock;
 };
 
+static int blktrans_discard_request(struct request_queue *q,
+				    struct request *req)
+{
+	req->cmd_type = REQ_TYPE_LINUX_BLOCK;
+	req->cmd[0] = REQ_LB_OP_DISCARD;
+	return 0;
+}
+
 static int do_blktrans_request(struct mtd_blktrans_ops *tr,
 			       struct mtd_blktrans_dev *dev,
 			       struct request *req)
@@ -44,6 +52,10 @@
 
 	buf = req->buffer;
 
+	if (req->cmd_type == REQ_TYPE_LINUX_BLOCK &&
+	    req->cmd[0] == REQ_LB_OP_DISCARD)
+		return !tr->discard(dev, block, nsect);
+
 	if (!blk_fs_request(req))
 		return 0;
 
@@ -367,6 +379,10 @@
 
 	tr->blkcore_priv->rq->queuedata = tr;
 	blk_queue_hardsect_size(tr->blkcore_priv->rq, tr->blksize);
+	if (tr->discard)
+		blk_queue_set_discard(tr->blkcore_priv->rq,
+				      blktrans_discard_request);
+
 	tr->blkshift = ffs(tr->blksize) - 1;
 
 	tr->blkcore_priv->thread = kthread_run(mtd_blktrans_thread, tr,
diff --git a/drivers/mtd/nand/atmel_nand_ecc.h b/drivers/mtd/nand/atmel_nand_ecc.h
index 1ee7f99..578c776 100644
--- a/drivers/mtd/nand/atmel_nand_ecc.h
+++ b/drivers/mtd/nand/atmel_nand_ecc.h
@@ -2,6 +2,9 @@
  * Error Corrected Code Controller (ECC) - System peripherals regsters.
  * Based on AT91SAM9260 datasheet revision B.
  *
+ * Copyright (C) 2007 Andrew Victor
+ * Copyright (C) 2007 Atmel Corporation.
+ *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the
  * Free Software Foundation; either version 2 of the License, or (at your
diff --git a/drivers/mtd/nand/cafe_nand.c b/drivers/mtd/nand/cafe_nand.c
index 95345d0..b8064bf 100644
--- a/drivers/mtd/nand/cafe_nand.c
+++ b/drivers/mtd/nand/cafe_nand.c
@@ -1,6 +1,9 @@
 /*
  * Driver for One Laptop Per Child ‘CAFÉ’ controller, aka Marvell 88ALP01
  *
+ * The data sheet for this device can be found at:
+ *    http://www.marvell.com/products/pcconn/88ALP01.jsp
+ *
  * Copyright © 2006 Red Hat, Inc.
  * Copyright © 2006 David Woodhouse <dwmw2@infradead.org>
  */
@@ -842,7 +845,8 @@
 }
 
 static struct pci_device_id cafe_nand_tbl[] = {
-	{ 0x11ab, 0x4100, PCI_ANY_ID, PCI_ANY_ID },
+	{ PCI_VENDOR_ID_MARVELL, PCI_DEVICE_ID_MARVELL_88ALP01_NAND,
+	  PCI_ANY_ID, PCI_ANY_ID },
 	{ }
 };
 
diff --git a/drivers/mtd/nand/cmx270_nand.c b/drivers/mtd/nand/cmx270_nand.c
index 9eba3f0..fa129c0 100644
--- a/drivers/mtd/nand/cmx270_nand.c
+++ b/drivers/mtd/nand/cmx270_nand.c
@@ -156,7 +156,7 @@
 	int mtd_parts_nb = 0;
 	int ret;
 
-	if (!machine_is_armcore())
+	if (!(machine_is_armcore() && cpu_is_pxa27x()))
 		return -ENODEV;
 
 	ret = gpio_request(GPIO_NAND_CS, "NAND CS");
diff --git a/drivers/net/3c501.c b/drivers/net/3c501.c
index 5ba4bab..7d15e7c 100644
--- a/drivers/net/3c501.c
+++ b/drivers/net/3c501.c
@@ -17,7 +17,7 @@
 	Annapolis MD 21403
 
     Fixed (again!) the missing interrupt locking on TX/RX shifting.
-	Alan Cox <Alan.Cox@linux.org>
+	Alan Cox <alan@lxorguk.ukuu.org.uk>
 
     Removed calls to init_etherdev since they are no longer needed, and
     cleaned up modularization just a bit. The driver still allows only
@@ -29,16 +29,16 @@
     the board. Now getting 150K/second FTP with a 3c501 card. Still playing
     with a TX-TX optimisation to see if we can touch 180-200K/second as seems
     theoretically maximum.
-		19950402 Alan Cox <Alan.Cox@linux.org>
+		19950402 Alan Cox <alan@lxorguk.ukuu.org.uk>
 
     Cleaned up for 2.3.x because we broke SMP now.
-		20000208 Alan Cox <alan@redhat.com>
+		20000208 Alan Cox <alan@lxorguk.ukuu.org.uk>
 
     Check up pass for 2.5. Nothing significant changed
-		20021009 Alan Cox <alan@redhat.com>
+		20021009 Alan Cox <alan@lxorguk.ukuu.org.uk>
 
     Fixed zero fill corner case
-		20030104 Alan Cox <alan@redhat.com>
+		20030104 Alan Cox <alan@lxorguk.ukuu.org.uk>
 
 
    For the avoidance of doubt the "preferred form" of this code is one which
@@ -104,7 +104,7 @@
 
 
 static const char version[] =
-	DRV_NAME ".c: " DRV_VERSION " Alan Cox (alan@redhat.com).\n";
+	DRV_NAME ".c: " DRV_VERSION " Alan Cox (alan@lxorguk.ukuu.org.uk).\n";
 
 /*
  *	Braindamage remaining:
diff --git a/drivers/net/3c505.c b/drivers/net/3c505.c
index fdfb2b2..a424869 100644
--- a/drivers/net/3c505.c
+++ b/drivers/net/3c505.c
@@ -130,12 +130,12 @@
 
 static const char timeout_msg[] = "*** timeout at %s:%s (line %d) ***\n";
 #define TIMEOUT_MSG(lineno) \
-	printk(timeout_msg, filename,__FUNCTION__,(lineno))
+	printk(timeout_msg, filename,__func__,(lineno))
 
 static const char invalid_pcb_msg[] =
 "*** invalid pcb length %d at %s:%s (line %d) ***\n";
 #define INVALID_PCB_MSG(len) \
-	printk(invalid_pcb_msg, (len),filename,__FUNCTION__,__LINE__)
+	printk(invalid_pcb_msg, (len),filename,__func__,__LINE__)
 
 static char search_msg[] __initdata = KERN_INFO "%s: Looking for 3c505 adapter at address %#x...";
 
diff --git a/drivers/net/3c515.c b/drivers/net/3c515.c
index e4e3241..a0f8b6e 100644
--- a/drivers/net/3c515.c
+++ b/drivers/net/3c515.c
@@ -18,7 +18,7 @@
 
 	2001/11/17 - Added ethtool support (jgarzik)
 
-	2002/10/28 - Locking updates for 2.5 (alan@redhat.com)
+	2002/10/28 - Locking updates for 2.5 (alan@lxorguk.ukuu.org.uk)
 
 */
 
diff --git a/drivers/net/8139cp.c b/drivers/net/8139cp.c
index 6011d6f..85fa40a 100644
--- a/drivers/net/8139cp.c
+++ b/drivers/net/8139cp.c
@@ -127,7 +127,6 @@
 	  (CP)->tx_tail - (CP)->tx_head - 1)
 
 #define PKT_BUF_SZ		1536	/* Size of each temporary Rx buffer.*/
-#define RX_OFFSET		2
 #define CP_INTERNAL_PHY		32
 
 /* The following settings are log_2(bytes)-4:  0 == 16 bytes .. 6==1024, 7==end of packet. */
@@ -552,14 +551,14 @@
 			printk(KERN_DEBUG "%s: rx slot %d status 0x%x len %d\n",
 			       dev->name, rx_tail, status, len);
 
-		buflen = cp->rx_buf_sz + RX_OFFSET;
-		new_skb = dev_alloc_skb (buflen);
+		buflen = cp->rx_buf_sz + NET_IP_ALIGN;
+		new_skb = netdev_alloc_skb(dev, buflen);
 		if (!new_skb) {
 			dev->stats.rx_dropped++;
 			goto rx_next;
 		}
 
-		skb_reserve(new_skb, RX_OFFSET);
+		skb_reserve(new_skb, NET_IP_ALIGN);
 
 		dma_unmap_single(&cp->pdev->dev, mapping,
 				 buflen, PCI_DMA_FROMDEVICE);
@@ -1051,19 +1050,20 @@
 	cpw8_f(Cfg9346, Cfg9346_Lock);
 }
 
-static int cp_refill_rx (struct cp_private *cp)
+static int cp_refill_rx(struct cp_private *cp)
 {
+	struct net_device *dev = cp->dev;
 	unsigned i;
 
 	for (i = 0; i < CP_RX_RING_SIZE; i++) {
 		struct sk_buff *skb;
 		dma_addr_t mapping;
 
-		skb = dev_alloc_skb(cp->rx_buf_sz + RX_OFFSET);
+		skb = netdev_alloc_skb(dev, cp->rx_buf_sz + NET_IP_ALIGN);
 		if (!skb)
 			goto err_out;
 
-		skb_reserve(skb, RX_OFFSET);
+		skb_reserve(skb, NET_IP_ALIGN);
 
 		mapping = dma_map_single(&cp->pdev->dev, skb->data,
 					 cp->rx_buf_sz, PCI_DMA_FROMDEVICE);
diff --git a/drivers/net/8139too.c b/drivers/net/8139too.c
index 8a5b0d2..0daf8c1 100644
--- a/drivers/net/8139too.c
+++ b/drivers/net/8139too.c
@@ -309,7 +309,7 @@
 	Cfg9346		= 0x50,
 	Config0		= 0x51,
 	Config1		= 0x52,
-	FlashReg	= 0x54,
+	TimerInt	= 0x54,
 	MediaStatus	= 0x58,
 	Config3		= 0x59,
 	Config4		= 0x5A,	 /* absent on RTL-8139A */
@@ -325,6 +325,7 @@
 	FIFOTMS		= 0x70,	 /* FIFO Control and test. */
 	CSCR		= 0x74,	 /* Chip Status and Configuration Register. */
 	PARA78		= 0x78,
+	FlashReg	= 0xD4,	/* Communication with Flash ROM, four bytes. */
 	PARA7c		= 0x7c,	 /* Magic transceiver parameter register. */
 	Config5		= 0xD8,	 /* absent on RTL-8139A */
 };
@@ -1722,13 +1723,18 @@
 	}
 
 	spin_lock_irqsave(&tp->lock, flags);
+	/*
+	 * Writing to TxStatus triggers a DMA transfer of the data
+	 * copied to tp->tx_buf[entry] above. Use a memory barrier
+	 * to make sure that the device sees the updated data.
+	 */
+	wmb();
 	RTL_W32_F (TxStatus0 + (entry * sizeof (u32)),
 		   tp->tx_flag | max(len, (unsigned int)ETH_ZLEN));
 
 	dev->trans_start = jiffies;
 
 	tp->cur_tx++;
-	wmb();
 
 	if ((tp->cur_tx - NUM_TX_DESC) == tp->dirty_tx)
 		netif_stop_queue (dev);
@@ -2009,9 +2015,9 @@
 		/* Malloc up new buffer, compatible with net-2e. */
 		/* Omit the four octet CRC from the length. */
 
-		skb = dev_alloc_skb (pkt_size + 2);
+		skb = netdev_alloc_skb(dev, pkt_size + NET_IP_ALIGN);
 		if (likely(skb)) {
-			skb_reserve (skb, 2);	/* 16 byte align the IP fields. */
+			skb_reserve (skb, NET_IP_ALIGN);	/* 16 byte align the IP fields. */
 #if RX_BUF_IDX == 3
 			wrap_copy(skb, rx_ring, ring_offset+4, pkt_size);
 #else
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 4a11296..1d8af33 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -1386,7 +1386,8 @@
 
 config CS89x0
 	tristate "CS89x0 support"
-	depends on NET_PCI && (ISA || MACH_IXDP2351 || ARCH_IXDP2X01 || ARCH_PNX010X)
+	depends on NET_ETHERNET && (ISA || EISA || MACH_IXDP2351 \
+		|| ARCH_IXDP2X01 || ARCH_PNX010X || MACH_MX31ADS)
 	---help---
 	  Support for CS89x0 chipset based Ethernet cards. If you have a
 	  network (Ethernet) card of this type, say Y and read the
@@ -1397,6 +1398,11 @@
 	  To compile this driver as a module, choose M here. The module
 	  will be called cs89x0.
 
+config CS89x0_NONISA_IRQ
+	def_bool y
+	depends on CS89x0 != n
+	depends on MACH_IXDP2351 || ARCH_IXDP2X01 || ARCH_PNX010X || MACH_MX31ADS
+
 config TC35815
 	tristate "TOSHIBA TC35815 Ethernet support"
 	depends on NET_PCI && PCI && MIPS
@@ -1813,7 +1819,7 @@
 
 config FEC_MPC52xx
 	tristate "MPC52xx FEC driver"
-	depends on PPC_MERGE && PPC_MPC52xx && PPC_BESTCOMM_FEC
+	depends on PPC_MPC52xx && PPC_BESTCOMM_FEC
 	select CRC32
 	select PHYLIB
 	---help---
@@ -1840,6 +1846,17 @@
 	  Say Y here if you want to use the NE2000 compatible
 	  controller on the Renesas H8/300 processor.
 
+config ATL2
+	tristate "Atheros L2 Fast Ethernet support"
+	depends on PCI
+	select CRC32
+	select MII
+	help
+	  This driver supports the Atheros L2 fast ethernet adapter.
+
+	  To compile this driver as a module, choose M here.  The module
+	  will be called atl2.
+
 source "drivers/net/fs_enet/Kconfig"
 
 endif # NET_ETHERNET
@@ -1927,15 +1944,6 @@
 	  To compile this driver as a module, choose M here. The module
 	  will be called e1000.
 
-config E1000_DISABLE_PACKET_SPLIT
-	bool "Disable Packet Split for PCI express adapters"
-	depends on E1000
-	help
-	  Say Y here if you want to use the legacy receive path for PCI express
-	  hardware.
-
-	  If in doubt, say N.
-
 config E1000E
 	tristate "Intel(R) PRO/1000 PCI-Express Gigabit Ethernet support"
 	depends on PCI && (!SPARC32 || BROKEN)
@@ -2046,6 +2054,7 @@
 	tristate "Realtek 8169 gigabit ethernet support"
 	depends on PCI
 	select CRC32
+	select MII
 	---help---
 	  Say Y here if you have a Realtek 8169 PCI Gigabit Ethernet adapter.
 
@@ -2262,7 +2271,7 @@
 config MV643XX_ETH
 	tristate "Marvell Discovery (643XX) and Orion ethernet support"
 	depends on MV64360 || MV64X60 || (PPC_MULTIPLATFORM && PPC32) || PLAT_ORION
-	select MII
+	select PHYLIB
 	help
 	  This driver supports the gigabit ethernet MACs in the
 	  Marvell Discovery PPC/MIPS chipset family (MV643XX) and
@@ -2281,12 +2290,13 @@
 	  will be called qla3xxx.
 
 config ATL1
-	tristate "Attansic L1 Gigabit Ethernet support (EXPERIMENTAL)"
-	depends on PCI && EXPERIMENTAL
+	tristate "Atheros/Attansic L1 Gigabit Ethernet support"
+	depends on PCI
 	select CRC32
 	select MII
 	help
-	  This driver supports the Attansic L1 gigabit ethernet adapter.
+	  This driver supports the Atheros/Attansic L1 gigabit ethernet
+	  adapter.
 
 	  To compile this driver as a module, choose M here.  The module
 	  will be called atl1.
@@ -2302,6 +2312,18 @@
 	  To compile this driver as a module, choose M here.  The module
 	  will be called atl1e.
 
+config JME
+	tristate "JMicron(R) PCI-Express Gigabit Ethernet support"
+	depends on PCI
+	select CRC32
+	select MII
+	---help---
+	  This driver supports the PCI-Express gigabit ethernet adapters
+	  based on JMicron JMC250 chipset.
+
+	  To compile this driver as a module, choose M here. The module
+	  will be called jme.
+
 endif # NETDEV_1000
 
 #
@@ -2377,10 +2399,18 @@
 	  To compile the driver as a module, choose M here. The module
 	  will be called ehea.
 
+config ENIC
+	tristate "Cisco 10G Ethernet NIC support"
+	depends on PCI && INET
+	select INET_LRO
+	help
+	  This enables the support for the Cisco 10G Ethernet card.
+
 config IXGBE
 	tristate "Intel(R) 10GbE PCI Express adapters support"
 	depends on PCI && INET
 	select INET_LRO
+	select INTEL_IOATDMA
 	---help---
 	  This driver supports Intel(R) 10GbE PCI Express family of
 	  adapters.  For more information on how to identify your adapter, go
@@ -2432,6 +2462,7 @@
 	select FW_LOADER
 	select CRC32
 	select INET_LRO
+	select INTEL_IOATDMA
 	---help---
 	  This driver supports Myricom Myri-10G Dual Protocol interface in
 	  Ethernet mode. If the eeprom on your board is not recent enough,
@@ -2496,6 +2527,15 @@
 	  To compile this driver as a module, choose M here: the module
 	  will be called bnx2x.  This is recommended.
 
+config QLGE
+	tristate "QLogic QLGE 10Gb Ethernet Driver Support"
+	depends on PCI
+	help
+	  This driver supports QLogic ISP8XXX 10Gb Ethernet cards.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called qlge.
+
 source "drivers/net/sfc/Kconfig"
 
 endif # NETDEV_10000
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 7629c90..fa2510b 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -15,9 +15,12 @@
 obj-$(CONFIG_CAN) += can/
 obj-$(CONFIG_BONDING) += bonding/
 obj-$(CONFIG_ATL1) += atlx/
+obj-$(CONFIG_ATL2) += atlx/
 obj-$(CONFIG_ATL1E) += atl1e/
 obj-$(CONFIG_GIANFAR) += gianfar_driver.o
 obj-$(CONFIG_TEHUTI) += tehuti.o
+obj-$(CONFIG_ENIC) += enic/
+obj-$(CONFIG_JME) += jme.o
 
 gianfar_driver-objs := gianfar.o \
 		gianfar_ethtool.o \
@@ -111,7 +114,7 @@
 obj-$(CONFIG_NE2000) += ne.o 8390p.o
 obj-$(CONFIG_NE2_MCA) += ne2.o 8390p.o
 obj-$(CONFIG_HPLAN) += hp.o 8390p.o
-obj-$(CONFIG_HPLAN_PLUS) += hp-plus.o 8390p.o
+obj-$(CONFIG_HPLAN_PLUS) += hp-plus.o 8390.o
 obj-$(CONFIG_ULTRA) += smc-ultra.o 8390.o
 obj-$(CONFIG_ULTRAMCA) += smc-mca.o 8390.o
 obj-$(CONFIG_ULTRA32) += smc-ultra32.o 8390.o
@@ -128,6 +131,7 @@
 obj-$(CONFIG_TSI108_ETH) += tsi108_eth.o
 obj-$(CONFIG_MV643XX_ETH) += mv643xx_eth.o
 obj-$(CONFIG_QLA3XXX) += qla3xxx.o
+obj-$(CONFIG_QLGE) += qlge/
 
 obj-$(CONFIG_PPP) += ppp_generic.o
 obj-$(CONFIG_PPP_ASYNC) += ppp_async.o
diff --git a/drivers/net/appletalk/cops.c b/drivers/net/appletalk/cops.c
index a0b4c85..735fc94 100644
--- a/drivers/net/appletalk/cops.c
+++ b/drivers/net/appletalk/cops.c
@@ -4,7 +4,7 @@
  *      - Jay Schulist <jschlst@samba.org>
  *
  *	With more than a little help from;
- *	- Alan Cox <Alan.Cox@linux.org> 
+ *	- Alan Cox <alan@lxorguk.ukuu.org.uk>
  *
  *      Derived from:
  *      - skeleton.c: A network driver outline for linux.
diff --git a/drivers/net/arcnet/arcnet.c b/drivers/net/arcnet/arcnet.c
index bdc4c0b..a5b0769 100644
--- a/drivers/net/arcnet/arcnet.c
+++ b/drivers/net/arcnet/arcnet.c
@@ -442,24 +442,24 @@
 		BUGMSG(D_NORMAL, "WARNING!  Station address FF may confuse "
 		       "DOS networking programs!\n");
 
-	BUGMSG(D_DEBUG, "%s: %d: %s\n",__FILE__,__LINE__,__FUNCTION__);
+	BUGMSG(D_DEBUG, "%s: %d: %s\n",__FILE__,__LINE__,__func__);
 	if (ASTATUS() & RESETflag) {
-	  	BUGMSG(D_DEBUG, "%s: %d: %s\n",__FILE__,__LINE__,__FUNCTION__);
+	  	BUGMSG(D_DEBUG, "%s: %d: %s\n",__FILE__,__LINE__,__func__);
 		ACOMMAND(CFLAGScmd | RESETclear);
 	}
 
 
-	BUGMSG(D_DEBUG, "%s: %d: %s\n",__FILE__,__LINE__,__FUNCTION__);
+	BUGMSG(D_DEBUG, "%s: %d: %s\n",__FILE__,__LINE__,__func__);
 	/* make sure we're ready to receive IRQ's. */
 	AINTMASK(0);
 	udelay(1);		/* give it time to set the mask before
 				 * we reset it again. (may not even be
 				 * necessary)
 				 */
-	BUGMSG(D_DEBUG, "%s: %d: %s\n",__FILE__,__LINE__,__FUNCTION__);
+	BUGMSG(D_DEBUG, "%s: %d: %s\n",__FILE__,__LINE__,__func__);
 	lp->intmask = NORXflag | RECONflag;
 	AINTMASK(lp->intmask);
-	BUGMSG(D_DEBUG, "%s: %d: %s\n",__FILE__,__LINE__,__FUNCTION__);
+	BUGMSG(D_DEBUG, "%s: %d: %s\n",__FILE__,__LINE__,__func__);
 
 	netif_start_queue(dev);
 
@@ -670,14 +670,14 @@
 		freeskb = 0;
 	}
 
-	BUGMSG(D_DEBUG, "%s: %d: %s, status: %x\n",__FILE__,__LINE__,__FUNCTION__,ASTATUS());
+	BUGMSG(D_DEBUG, "%s: %d: %s, status: %x\n",__FILE__,__LINE__,__func__,ASTATUS());
 	/* make sure we didn't ignore a TX IRQ while we were in here */
 	AINTMASK(0);
 
-	BUGMSG(D_DEBUG, "%s: %d: %s\n",__FILE__,__LINE__,__FUNCTION__);
+	BUGMSG(D_DEBUG, "%s: %d: %s\n",__FILE__,__LINE__,__func__);
 	lp->intmask |= TXFREEflag|EXCNAKflag;
 	AINTMASK(lp->intmask);
-	BUGMSG(D_DEBUG, "%s: %d: %s, status: %x\n",__FILE__,__LINE__,__FUNCTION__,ASTATUS());
+	BUGMSG(D_DEBUG, "%s: %d: %s, status: %x\n",__FILE__,__LINE__,__func__,ASTATUS());
 
 	spin_unlock_irqrestore(&lp->lock, flags);
 	if (freeskb) {
@@ -798,7 +798,7 @@
                 diagstatus = (status >> 8) & 0xFF;
 
 		BUGMSG(D_DEBUG, "%s: %d: %s: status=%x\n",
-			__FILE__,__LINE__,__FUNCTION__,status);
+			__FILE__,__LINE__,__func__,status);
 		didsomething = 0;
 
 		/*
diff --git a/drivers/net/arcnet/com20020.c b/drivers/net/arcnet/com20020.c
index 8b51313..70124a9 100644
--- a/drivers/net/arcnet/com20020.c
+++ b/drivers/net/arcnet/com20020.c
@@ -238,15 +238,15 @@
 	u_char inbyte;
 
 	BUGMSG(D_DEBUG, "%s: %d: %s: dev: %p, lp: %p, dev->name: %s\n",
-		__FILE__,__LINE__,__FUNCTION__,dev,lp,dev->name);
+		__FILE__,__LINE__,__func__,dev,lp,dev->name);
 	BUGMSG(D_INIT, "Resetting %s (status=%02Xh)\n",
 	       dev->name, ASTATUS());
 
-	BUGMSG(D_DEBUG, "%s: %d: %s\n",__FILE__,__LINE__,__FUNCTION__);
+	BUGMSG(D_DEBUG, "%s: %d: %s\n",__FILE__,__LINE__,__func__);
 	lp->config = TXENcfg | (lp->timeout << 3) | (lp->backplane << 2);
 	/* power-up defaults */
 	SETCONF;
-	BUGMSG(D_DEBUG, "%s: %d: %s\n",__FILE__,__LINE__,__FUNCTION__);
+	BUGMSG(D_DEBUG, "%s: %d: %s\n",__FILE__,__LINE__,__func__);
 
 	if (really_reset) {
 		/* reset the card */
@@ -254,22 +254,22 @@
 		mdelay(RESETtime * 2);	/* COM20020 seems to be slower sometimes */
 	}
 	/* clear flags & end reset */
-	BUGMSG(D_DEBUG, "%s: %d: %s\n",__FILE__,__LINE__,__FUNCTION__);
+	BUGMSG(D_DEBUG, "%s: %d: %s\n",__FILE__,__LINE__,__func__);
 	ACOMMAND(CFLAGScmd | RESETclear | CONFIGclear);
 
 	/* verify that the ARCnet signature byte is present */
-	BUGMSG(D_DEBUG, "%s: %d: %s\n",__FILE__,__LINE__,__FUNCTION__);
+	BUGMSG(D_DEBUG, "%s: %d: %s\n",__FILE__,__LINE__,__func__);
 
 	com20020_copy_from_card(dev, 0, 0, &inbyte, 1);
-	BUGMSG(D_DEBUG, "%s: %d: %s\n",__FILE__,__LINE__,__FUNCTION__);
+	BUGMSG(D_DEBUG, "%s: %d: %s\n",__FILE__,__LINE__,__func__);
 	if (inbyte != TESTvalue) {
-		BUGMSG(D_DEBUG, "%s: %d: %s\n",__FILE__,__LINE__,__FUNCTION__);
+		BUGMSG(D_DEBUG, "%s: %d: %s\n",__FILE__,__LINE__,__func__);
 		BUGMSG(D_NORMAL, "reset failed: TESTvalue not present.\n");
 		return 1;
 	}
 	/* enable extended (512-byte) packets */
 	ACOMMAND(CONFIGcmd | EXTconf);
-	BUGMSG(D_DEBUG, "%s: %d: %s\n",__FILE__,__LINE__,__FUNCTION__);
+	BUGMSG(D_DEBUG, "%s: %d: %s\n",__FILE__,__LINE__,__func__);
 
 	/* done!  return success. */
 	return 0;
diff --git a/drivers/net/atl1e/atl1e_hw.c b/drivers/net/atl1e/atl1e_hw.c
index 949e753..8cbc1b5 100644
--- a/drivers/net/atl1e/atl1e_hw.c
+++ b/drivers/net/atl1e/atl1e_hw.c
@@ -397,7 +397,7 @@
  */
 int atl1e_phy_commit(struct atl1e_hw *hw)
 {
-	struct atl1e_adapter *adapter = (struct atl1e_adapter *)hw->adapter;
+	struct atl1e_adapter *adapter = hw->adapter;
 	struct pci_dev *pdev = adapter->pdev;
 	int ret_val;
 	u16 phy_data;
@@ -431,7 +431,7 @@
 
 int atl1e_phy_init(struct atl1e_hw *hw)
 {
-	struct atl1e_adapter *adapter = (struct atl1e_adapter *)hw->adapter;
+	struct atl1e_adapter *adapter = hw->adapter;
 	struct pci_dev *pdev = adapter->pdev;
 	s32 ret_val;
 	u16 phy_val;
@@ -525,7 +525,7 @@
  */
 int atl1e_reset_hw(struct atl1e_hw *hw)
 {
-	struct atl1e_adapter *adapter = (struct atl1e_adapter *)hw->adapter;
+	struct atl1e_adapter *adapter = hw->adapter;
 	struct pci_dev *pdev = adapter->pdev;
 
 	u32 idle_status_data = 0;
diff --git a/drivers/net/atl1e/atl1e_main.c b/drivers/net/atl1e/atl1e_main.c
index 7685b99..9b60352 100644
--- a/drivers/net/atl1e/atl1e_main.c
+++ b/drivers/net/atl1e/atl1e_main.c
@@ -2390,9 +2390,7 @@
 	}
 
 	/* Init GPHY as early as possible due to power saving issue  */
-	spin_lock(&adapter->mdio_lock);
 	atl1e_phy_init(&adapter->hw);
-	spin_unlock(&adapter->mdio_lock);
 	/* reset the controller to
 	 * put the device in a known good starting state */
 	err = atl1e_reset_hw(&adapter->hw);
diff --git a/drivers/net/atlx/Makefile b/drivers/net/atlx/Makefile
index ca45553..e4f6022 100644
--- a/drivers/net/atlx/Makefile
+++ b/drivers/net/atlx/Makefile
@@ -1 +1,3 @@
 obj-$(CONFIG_ATL1)	+= atl1.o
+obj-$(CONFIG_ATL2)	+= atl2.o
+
diff --git a/drivers/net/atlx/atl1.c b/drivers/net/atlx/atl1.c
index e23ce77..3cf59a7 100644
--- a/drivers/net/atlx/atl1.c
+++ b/drivers/net/atlx/atl1.c
@@ -24,16 +24,12 @@
  * file called COPYING.
  *
  * Contact Information:
- * Xiong Huang <xiong_huang@attansic.com>
- * Attansic Technology Corp. 3F 147, Xianzheng 9th Road, Zhubei,
- * Xinzhu  302, TAIWAN, REPUBLIC OF CHINA
- *
+ * Xiong Huang <xiong.huang@atheros.com>
+ * Jie Yang <jie.yang@atheros.com>
  * Chris Snook <csnook@redhat.com>
  * Jay Cliburn <jcliburn@gmail.com>
  *
- * This version is adapted from the Attansic reference driver for
- * inclusion in the Linux kernel.  It is currently under heavy development.
- * A very incomplete list of things that need to be dealt with:
+ * This version is adapted from the Attansic reference driver.
  *
  * TODO:
  * Add more ethtool functions.
@@ -2109,7 +2105,6 @@
 static int atl1_tso(struct atl1_adapter *adapter, struct sk_buff *skb,
 	struct tx_packet_desc *ptpd)
 {
-	/* spinlock held */
 	u8 hdr_len, ip_off;
 	u32 real_len;
 	int err;
@@ -2196,7 +2191,6 @@
 static void atl1_tx_map(struct atl1_adapter *adapter, struct sk_buff *skb,
 	struct tx_packet_desc *ptpd)
 {
-	/* spinlock held */
 	struct atl1_tpd_ring *tpd_ring = &adapter->tpd_ring;
 	struct atl1_buffer *buffer_info;
 	u16 buf_len = skb->len;
@@ -2303,7 +2297,6 @@
 static void atl1_tx_queue(struct atl1_adapter *adapter, u16 count,
        struct tx_packet_desc *ptpd)
 {
-	/* spinlock held */
 	struct atl1_tpd_ring *tpd_ring = &adapter->tpd_ring;
 	struct atl1_buffer *buffer_info;
 	struct tx_packet_desc *tpd;
@@ -2361,7 +2354,6 @@
 	struct tx_packet_desc *ptpd;
 	u16 frag_size;
 	u16 vlan_tag;
-	unsigned long flags;
 	unsigned int nr_frags = 0;
 	unsigned int mss = 0;
 	unsigned int f;
@@ -2399,18 +2391,9 @@
 		}
 	}
 
-	if (!spin_trylock_irqsave(&adapter->lock, flags)) {
-		/* Can't get lock - tell upper layer to requeue */
-		if (netif_msg_tx_queued(adapter))
-			dev_printk(KERN_DEBUG, &adapter->pdev->dev,
-				"tx locked\n");
-		return NETDEV_TX_LOCKED;
-	}
-
 	if (atl1_tpd_avail(&adapter->tpd_ring) < count) {
 		/* not enough descriptors */
 		netif_stop_queue(netdev);
-		spin_unlock_irqrestore(&adapter->lock, flags);
 		if (netif_msg_tx_queued(adapter))
 			dev_printk(KERN_DEBUG, &adapter->pdev->dev,
 				"tx busy\n");
@@ -2432,7 +2415,6 @@
 
 	tso = atl1_tso(adapter, skb, ptpd);
 	if (tso < 0) {
-		spin_unlock_irqrestore(&adapter->lock, flags);
 		dev_kfree_skb_any(skb);
 		return NETDEV_TX_OK;
 	}
@@ -2440,7 +2422,6 @@
 	if (!tso) {
 		ret_val = atl1_tx_csum(adapter, skb, ptpd);
 		if (ret_val < 0) {
-			spin_unlock_irqrestore(&adapter->lock, flags);
 			dev_kfree_skb_any(skb);
 			return NETDEV_TX_OK;
 		}
@@ -2449,7 +2430,7 @@
 	atl1_tx_map(adapter, skb, ptpd);
 	atl1_tx_queue(adapter, count, ptpd);
 	atl1_update_mailbox(adapter);
-	spin_unlock_irqrestore(&adapter->lock, flags);
+	mmiowb();
 	netdev->trans_start = jiffies;
 	return NETDEV_TX_OK;
 }
@@ -2642,6 +2623,7 @@
 {
 	struct net_device *netdev = adapter->netdev;
 
+	netif_stop_queue(netdev);
 	del_timer_sync(&adapter->watchdog_timer);
 	del_timer_sync(&adapter->phy_config_timer);
 	adapter->phy_timer_pending = false;
@@ -2655,7 +2637,6 @@
 	adapter->link_speed = SPEED_0;
 	adapter->link_duplex = -1;
 	netif_carrier_off(netdev);
-	netif_stop_queue(netdev);
 
 	atl1_clean_tx_ring(adapter);
 	atl1_clean_rx_ring(adapter);
@@ -2724,6 +2705,8 @@
 	struct atl1_adapter *adapter = netdev_priv(netdev);
 	int err;
 
+	netif_carrier_off(netdev);
+
 	/* allocate transmit descriptors */
 	err = atl1_setup_ring_resources(adapter);
 	if (err)
@@ -3022,7 +3005,6 @@
 	netdev->features = NETIF_F_HW_CSUM;
 	netdev->features |= NETIF_F_SG;
 	netdev->features |= (NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX);
-	netdev->features |= NETIF_F_LLTX;
 
 	/*
 	 * patch for some L1 of old version,
diff --git a/drivers/net/atlx/atl2.c b/drivers/net/atlx/atl2.c
new file mode 100644
index 0000000..f5bdc92
--- /dev/null
+++ b/drivers/net/atlx/atl2.c
@@ -0,0 +1,3119 @@
+/*
+ * Copyright(c) 2006 - 2007 Atheros Corporation. All rights reserved.
+ * Copyright(c) 2007 - 2008 Chris Snook <csnook@redhat.com>
+ *
+ * Derived from Intel e1000 driver
+ * Copyright(c) 1999 - 2005 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#include <asm/atomic.h>
+#include <linux/crc32.h>
+#include <linux/dma-mapping.h>
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+#include <linux/hardirq.h>
+#include <linux/if_vlan.h>
+#include <linux/in.h>
+#include <linux/interrupt.h>
+#include <linux/ip.h>
+#include <linux/irqflags.h>
+#include <linux/irqreturn.h>
+#include <linux/mii.h>
+#include <linux/net.h>
+#include <linux/netdevice.h>
+#include <linux/pci.h>
+#include <linux/pci_ids.h>
+#include <linux/pm.h>
+#include <linux/skbuff.h>
+#include <linux/spinlock.h>
+#include <linux/string.h>
+#include <linux/tcp.h>
+#include <linux/timer.h>
+#include <linux/types.h>
+#include <linux/workqueue.h>
+
+#include "atl2.h"
+
+#define ATL2_DRV_VERSION "2.2.3"
+
+static char atl2_driver_name[] = "atl2";
+static const char atl2_driver_string[] = "Atheros(R) L2 Ethernet Driver";
+static char atl2_copyright[] = "Copyright (c) 2007 Atheros Corporation.";
+static char atl2_driver_version[] = ATL2_DRV_VERSION;
+
+MODULE_AUTHOR("Atheros Corporation <xiong.huang@atheros.com>, Chris Snook <csnook@redhat.com>");
+MODULE_DESCRIPTION("Atheros Fast Ethernet Network Driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(ATL2_DRV_VERSION);
+
+/*
+ * atl2_pci_tbl - PCI Device ID Table
+ */
+static struct pci_device_id atl2_pci_tbl[] = {
+	{PCI_DEVICE(PCI_VENDOR_ID_ATTANSIC, PCI_DEVICE_ID_ATTANSIC_L2)},
+	/* required last entry */
+	{0,}
+};
+MODULE_DEVICE_TABLE(pci, atl2_pci_tbl);
+
+static void atl2_set_ethtool_ops(struct net_device *netdev);
+
+static void atl2_check_options(struct atl2_adapter *adapter);
+
+/*
+ * atl2_sw_init - Initialize general software structures (struct atl2_adapter)
+ * @adapter: board private structure to initialize
+ *
+ * atl2_sw_init initializes the Adapter private data structure.
+ * Fields are initialized based on PCI device information and
+ * OS network device settings (MTU size).
+ */
+static int __devinit atl2_sw_init(struct atl2_adapter *adapter)
+{
+	struct atl2_hw *hw = &adapter->hw;
+	struct pci_dev *pdev = adapter->pdev;
+
+	/* PCI config space info */
+	hw->vendor_id = pdev->vendor;
+	hw->device_id = pdev->device;
+	hw->subsystem_vendor_id = pdev->subsystem_vendor;
+	hw->subsystem_id = pdev->subsystem_device;
+
+	pci_read_config_byte(pdev, PCI_REVISION_ID, &hw->revision_id);
+	pci_read_config_word(pdev, PCI_COMMAND, &hw->pci_cmd_word);
+
+	adapter->wol = 0;
+	adapter->ict = 50000;  /* ~100ms */
+	adapter->link_speed = SPEED_0;   /* hardware init */
+	adapter->link_duplex = FULL_DUPLEX;
+
+	hw->phy_configured = false;
+	hw->preamble_len = 7;
+	hw->ipgt = 0x60;
+	hw->min_ifg = 0x50;
+	hw->ipgr1 = 0x40;
+	hw->ipgr2 = 0x60;
+	hw->retry_buf = 2;
+	hw->max_retry = 0xf;
+	hw->lcol = 0x37;
+	hw->jam_ipg = 7;
+	hw->fc_rxd_hi = 0;
+	hw->fc_rxd_lo = 0;
+	hw->max_frame_size = adapter->netdev->mtu;
+
+	spin_lock_init(&adapter->stats_lock);
+
+	set_bit(__ATL2_DOWN, &adapter->flags);
+
+	return 0;
+}
+
+/*
+ * atl2_set_multi - Multicast and Promiscuous mode set
+ * @netdev: network interface device structure
+ *
+ * The set_multi entry point is called whenever the multicast address
+ * list or the network interface flags are updated.  This routine is
+ * responsible for configuring the hardware for proper multicast,
+ * promiscuous mode, and all-multi behavior.
+ */
+static void atl2_set_multi(struct net_device *netdev)
+{
+	struct atl2_adapter *adapter = netdev_priv(netdev);
+	struct atl2_hw *hw = &adapter->hw;
+	struct dev_mc_list *mc_ptr;
+	u32 rctl;
+	u32 hash_value;
+
+	/* Check for Promiscuous and All Multicast modes */
+	rctl = ATL2_READ_REG(hw, REG_MAC_CTRL);
+
+	if (netdev->flags & IFF_PROMISC) {
+		rctl |= MAC_CTRL_PROMIS_EN;
+	} else if (netdev->flags & IFF_ALLMULTI) {
+		rctl |= MAC_CTRL_MC_ALL_EN;
+		rctl &= ~MAC_CTRL_PROMIS_EN;
+	} else
+		rctl &= ~(MAC_CTRL_PROMIS_EN | MAC_CTRL_MC_ALL_EN);
+
+	ATL2_WRITE_REG(hw, REG_MAC_CTRL, rctl);
+
+	/* clear the old settings from the multicast hash table */
+	ATL2_WRITE_REG(hw, REG_RX_HASH_TABLE, 0);
+	ATL2_WRITE_REG_ARRAY(hw, REG_RX_HASH_TABLE, 1, 0);
+
+	/* comoute mc addresses' hash value ,and put it into hash table */
+	for (mc_ptr = netdev->mc_list; mc_ptr; mc_ptr = mc_ptr->next) {
+		hash_value = atl2_hash_mc_addr(hw, mc_ptr->dmi_addr);
+		atl2_hash_set(hw, hash_value);
+	}
+}
+
+static void init_ring_ptrs(struct atl2_adapter *adapter)
+{
+	/* Read / Write Ptr Initialize: */
+	adapter->txd_write_ptr = 0;
+	atomic_set(&adapter->txd_read_ptr, 0);
+
+	adapter->rxd_read_ptr = 0;
+	adapter->rxd_write_ptr = 0;
+
+	atomic_set(&adapter->txs_write_ptr, 0);
+	adapter->txs_next_clear = 0;
+}
+
+/*
+ * atl2_configure - Configure Transmit&Receive Unit after Reset
+ * @adapter: board private structure
+ *
+ * Configure the Tx /Rx unit of the MAC after a reset.
+ */
+static int atl2_configure(struct atl2_adapter *adapter)
+{
+	struct atl2_hw *hw = &adapter->hw;
+	u32 value;
+
+	/* clear interrupt status */
+	ATL2_WRITE_REG(&adapter->hw, REG_ISR, 0xffffffff);
+
+	/* set MAC Address */
+	value = (((u32)hw->mac_addr[2]) << 24) |
+		(((u32)hw->mac_addr[3]) << 16) |
+		(((u32)hw->mac_addr[4]) << 8) |
+		(((u32)hw->mac_addr[5]));
+	ATL2_WRITE_REG(hw, REG_MAC_STA_ADDR, value);
+	value = (((u32)hw->mac_addr[0]) << 8) |
+		(((u32)hw->mac_addr[1]));
+	ATL2_WRITE_REG(hw, (REG_MAC_STA_ADDR+4), value);
+
+	/* HI base address */
+	ATL2_WRITE_REG(hw, REG_DESC_BASE_ADDR_HI,
+		(u32)((adapter->ring_dma & 0xffffffff00000000ULL) >> 32));
+
+	/* LO base address */
+	ATL2_WRITE_REG(hw, REG_TXD_BASE_ADDR_LO,
+		(u32)(adapter->txd_dma & 0x00000000ffffffffULL));
+	ATL2_WRITE_REG(hw, REG_TXS_BASE_ADDR_LO,
+		(u32)(adapter->txs_dma & 0x00000000ffffffffULL));
+	ATL2_WRITE_REG(hw, REG_RXD_BASE_ADDR_LO,
+		(u32)(adapter->rxd_dma & 0x00000000ffffffffULL));
+
+	/* element count */
+	ATL2_WRITE_REGW(hw, REG_TXD_MEM_SIZE, (u16)(adapter->txd_ring_size/4));
+	ATL2_WRITE_REGW(hw, REG_TXS_MEM_SIZE, (u16)adapter->txs_ring_size);
+	ATL2_WRITE_REGW(hw, REG_RXD_BUF_NUM,  (u16)adapter->rxd_ring_size);
+
+	/* config Internal SRAM */
+/*
+    ATL2_WRITE_REGW(hw, REG_SRAM_TXRAM_END, sram_tx_end);
+    ATL2_WRITE_REGW(hw, REG_SRAM_TXRAM_END, sram_rx_end);
+*/
+
+	/* config IPG/IFG */
+	value = (((u32)hw->ipgt & MAC_IPG_IFG_IPGT_MASK) <<
+		MAC_IPG_IFG_IPGT_SHIFT) |
+		(((u32)hw->min_ifg & MAC_IPG_IFG_MIFG_MASK) <<
+		MAC_IPG_IFG_MIFG_SHIFT) |
+		(((u32)hw->ipgr1 & MAC_IPG_IFG_IPGR1_MASK) <<
+		MAC_IPG_IFG_IPGR1_SHIFT)|
+		(((u32)hw->ipgr2 & MAC_IPG_IFG_IPGR2_MASK) <<
+		MAC_IPG_IFG_IPGR2_SHIFT);
+	ATL2_WRITE_REG(hw, REG_MAC_IPG_IFG, value);
+
+	/* config  Half-Duplex Control */
+	value = ((u32)hw->lcol & MAC_HALF_DUPLX_CTRL_LCOL_MASK) |
+		(((u32)hw->max_retry & MAC_HALF_DUPLX_CTRL_RETRY_MASK) <<
+		MAC_HALF_DUPLX_CTRL_RETRY_SHIFT) |
+		MAC_HALF_DUPLX_CTRL_EXC_DEF_EN |
+		(0xa << MAC_HALF_DUPLX_CTRL_ABEBT_SHIFT) |
+		(((u32)hw->jam_ipg & MAC_HALF_DUPLX_CTRL_JAMIPG_MASK) <<
+		MAC_HALF_DUPLX_CTRL_JAMIPG_SHIFT);
+	ATL2_WRITE_REG(hw, REG_MAC_HALF_DUPLX_CTRL, value);
+
+	/* set Interrupt Moderator Timer */
+	ATL2_WRITE_REGW(hw, REG_IRQ_MODU_TIMER_INIT, adapter->imt);
+	ATL2_WRITE_REG(hw, REG_MASTER_CTRL, MASTER_CTRL_ITIMER_EN);
+
+	/* set Interrupt Clear Timer */
+	ATL2_WRITE_REGW(hw, REG_CMBDISDMA_TIMER, adapter->ict);
+
+	/* set MTU */
+	ATL2_WRITE_REG(hw, REG_MTU, adapter->netdev->mtu +
+		ENET_HEADER_SIZE + VLAN_SIZE + ETHERNET_FCS_SIZE);
+
+	/* 1590 */
+	ATL2_WRITE_REG(hw, REG_TX_CUT_THRESH, 0x177);
+
+	/* flow control */
+	ATL2_WRITE_REGW(hw, REG_PAUSE_ON_TH, hw->fc_rxd_hi);
+	ATL2_WRITE_REGW(hw, REG_PAUSE_OFF_TH, hw->fc_rxd_lo);
+
+	/* Init mailbox */
+	ATL2_WRITE_REGW(hw, REG_MB_TXD_WR_IDX, (u16)adapter->txd_write_ptr);
+	ATL2_WRITE_REGW(hw, REG_MB_RXD_RD_IDX, (u16)adapter->rxd_read_ptr);
+
+	/* enable DMA read/write */
+	ATL2_WRITE_REGB(hw, REG_DMAR, DMAR_EN);
+	ATL2_WRITE_REGB(hw, REG_DMAW, DMAW_EN);
+
+	value = ATL2_READ_REG(&adapter->hw, REG_ISR);
+	if ((value & ISR_PHY_LINKDOWN) != 0)
+		value = 1; /* config failed */
+	else
+		value = 0;
+
+	/* clear all interrupt status */
+	ATL2_WRITE_REG(&adapter->hw, REG_ISR, 0x3fffffff);
+	ATL2_WRITE_REG(&adapter->hw, REG_ISR, 0);
+	return value;
+}
+
+/*
+ * atl2_setup_ring_resources - allocate Tx / RX descriptor resources
+ * @adapter: board private structure
+ *
+ * Return 0 on success, negative on failure
+ */
+static s32 atl2_setup_ring_resources(struct atl2_adapter *adapter)
+{
+	struct pci_dev *pdev = adapter->pdev;
+	int size;
+	u8 offset = 0;
+
+	/* real ring DMA buffer */
+	adapter->ring_size = size =
+		adapter->txd_ring_size * 1 + 7 +	/* dword align */
+		adapter->txs_ring_size * 4 + 7 +	/* dword align */
+		adapter->rxd_ring_size * 1536 + 127;	/* 128bytes align */
+
+	adapter->ring_vir_addr = pci_alloc_consistent(pdev, size,
+		&adapter->ring_dma);
+	if (!adapter->ring_vir_addr)
+		return -ENOMEM;
+	memset(adapter->ring_vir_addr, 0, adapter->ring_size);
+
+	/* Init TXD Ring */
+	adapter->txd_dma = adapter->ring_dma ;
+	offset = (adapter->txd_dma & 0x7) ? (8 - (adapter->txd_dma & 0x7)) : 0;
+	adapter->txd_dma += offset;
+	adapter->txd_ring = (struct tx_pkt_header *) (adapter->ring_vir_addr +
+		offset);
+
+	/* Init TXS Ring */
+	adapter->txs_dma = adapter->txd_dma + adapter->txd_ring_size;
+	offset = (adapter->txs_dma & 0x7) ? (8 - (adapter->txs_dma & 0x7)) : 0;
+	adapter->txs_dma += offset;
+	adapter->txs_ring = (struct tx_pkt_status *)
+		(((u8 *)adapter->txd_ring) + (adapter->txd_ring_size + offset));
+
+	/* Init RXD Ring */
+	adapter->rxd_dma = adapter->txs_dma + adapter->txs_ring_size * 4;
+	offset = (adapter->rxd_dma & 127) ?
+		(128 - (adapter->rxd_dma & 127)) : 0;
+	if (offset > 7)
+		offset -= 8;
+	else
+		offset += (128 - 8);
+
+	adapter->rxd_dma += offset;
+	adapter->rxd_ring = (struct rx_desc *) (((u8 *)adapter->txs_ring) +
+		(adapter->txs_ring_size * 4 + offset));
+
+/*
+ * Read / Write Ptr Initialize:
+ *      init_ring_ptrs(adapter);
+ */
+	return 0;
+}
+
+/*
+ * atl2_irq_enable - Enable default interrupt generation settings
+ * @adapter: board private structure
+ */
+static inline void atl2_irq_enable(struct atl2_adapter *adapter)
+{
+	ATL2_WRITE_REG(&adapter->hw, REG_IMR, IMR_NORMAL_MASK);
+	ATL2_WRITE_FLUSH(&adapter->hw);
+}
+
+/*
+ * atl2_irq_disable - Mask off interrupt generation on the NIC
+ * @adapter: board private structure
+ */
+static inline void atl2_irq_disable(struct atl2_adapter *adapter)
+{
+    ATL2_WRITE_REG(&adapter->hw, REG_IMR, 0);
+    ATL2_WRITE_FLUSH(&adapter->hw);
+    synchronize_irq(adapter->pdev->irq);
+}
+
+#ifdef NETIF_F_HW_VLAN_TX
+static void atl2_vlan_rx_register(struct net_device *netdev,
+	struct vlan_group *grp)
+{
+	struct atl2_adapter *adapter = netdev_priv(netdev);
+	u32 ctrl;
+
+	atl2_irq_disable(adapter);
+	adapter->vlgrp = grp;
+
+	if (grp) {
+		/* enable VLAN tag insert/strip */
+		ctrl = ATL2_READ_REG(&adapter->hw, REG_MAC_CTRL);
+		ctrl |= MAC_CTRL_RMV_VLAN;
+		ATL2_WRITE_REG(&adapter->hw, REG_MAC_CTRL, ctrl);
+	} else {
+		/* disable VLAN tag insert/strip */
+		ctrl = ATL2_READ_REG(&adapter->hw, REG_MAC_CTRL);
+		ctrl &= ~MAC_CTRL_RMV_VLAN;
+		ATL2_WRITE_REG(&adapter->hw, REG_MAC_CTRL, ctrl);
+	}
+
+	atl2_irq_enable(adapter);
+}
+
+static void atl2_restore_vlan(struct atl2_adapter *adapter)
+{
+	atl2_vlan_rx_register(adapter->netdev, adapter->vlgrp);
+}
+#endif
+
+static void atl2_intr_rx(struct atl2_adapter *adapter)
+{
+	struct net_device *netdev = adapter->netdev;
+	struct rx_desc *rxd;
+	struct sk_buff *skb;
+
+	do {
+		rxd = adapter->rxd_ring+adapter->rxd_write_ptr;
+		if (!rxd->status.update)
+			break; /* end of tx */
+
+		/* clear this flag at once */
+		rxd->status.update = 0;
+
+		if (rxd->status.ok && rxd->status.pkt_size >= 60) {
+			int rx_size = (int)(rxd->status.pkt_size - 4);
+			/* alloc new buffer */
+			skb = netdev_alloc_skb(netdev, rx_size + NET_IP_ALIGN);
+			if (NULL == skb) {
+				printk(KERN_WARNING
+					"%s: Mem squeeze, deferring packet.\n",
+					netdev->name);
+				/*
+				 * Check that some rx space is free. If not,
+				 * free one and mark stats->rx_dropped++.
+				 */
+				adapter->net_stats.rx_dropped++;
+				break;
+			}
+			skb_reserve(skb, NET_IP_ALIGN);
+			skb->dev = netdev;
+			memcpy(skb->data, rxd->packet, rx_size);
+			skb_put(skb, rx_size);
+			skb->protocol = eth_type_trans(skb, netdev);
+#ifdef NETIF_F_HW_VLAN_TX
+			if (adapter->vlgrp && (rxd->status.vlan)) {
+				u16 vlan_tag = (rxd->status.vtag>>4) |
+					((rxd->status.vtag&7) << 13) |
+					((rxd->status.vtag&8) << 9);
+				vlan_hwaccel_rx(skb, adapter->vlgrp, vlan_tag);
+			} else
+#endif
+			netif_rx(skb);
+			adapter->net_stats.rx_bytes += rx_size;
+			adapter->net_stats.rx_packets++;
+			netdev->last_rx = jiffies;
+		} else {
+			adapter->net_stats.rx_errors++;
+
+			if (rxd->status.ok && rxd->status.pkt_size <= 60)
+				adapter->net_stats.rx_length_errors++;
+			if (rxd->status.mcast)
+				adapter->net_stats.multicast++;
+			if (rxd->status.crc)
+				adapter->net_stats.rx_crc_errors++;
+			if (rxd->status.align)
+				adapter->net_stats.rx_frame_errors++;
+		}
+
+		/* advance write ptr */
+		if (++adapter->rxd_write_ptr == adapter->rxd_ring_size)
+			adapter->rxd_write_ptr = 0;
+	} while (1);
+
+	/* update mailbox? */
+	adapter->rxd_read_ptr = adapter->rxd_write_ptr;
+	ATL2_WRITE_REGW(&adapter->hw, REG_MB_RXD_RD_IDX, adapter->rxd_read_ptr);
+}
+
+static void atl2_intr_tx(struct atl2_adapter *adapter)
+{
+	u32 txd_read_ptr;
+	u32 txs_write_ptr;
+	struct tx_pkt_status *txs;
+	struct tx_pkt_header *txph;
+	int free_hole = 0;
+
+	do {
+		txs_write_ptr = (u32) atomic_read(&adapter->txs_write_ptr);
+		txs = adapter->txs_ring + txs_write_ptr;
+		if (!txs->update)
+			break; /* tx stop here */
+
+		free_hole = 1;
+		txs->update = 0;
+
+		if (++txs_write_ptr == adapter->txs_ring_size)
+			txs_write_ptr = 0;
+		atomic_set(&adapter->txs_write_ptr, (int)txs_write_ptr);
+
+		txd_read_ptr = (u32) atomic_read(&adapter->txd_read_ptr);
+		txph = (struct tx_pkt_header *)
+			(((u8 *)adapter->txd_ring) + txd_read_ptr);
+
+		if (txph->pkt_size != txs->pkt_size) {
+			struct tx_pkt_status *old_txs = txs;
+			printk(KERN_WARNING
+				"%s: txs packet size not consistent with txd"
+				" txd_:0x%08x, txs_:0x%08x!\n",
+				adapter->netdev->name,
+				*(u32 *)txph, *(u32 *)txs);
+			printk(KERN_WARNING
+				"txd read ptr: 0x%x\n",
+				txd_read_ptr);
+			txs = adapter->txs_ring + txs_write_ptr;
+			printk(KERN_WARNING
+				"txs-behind:0x%08x\n",
+				*(u32 *)txs);
+			if (txs_write_ptr < 2) {
+				txs = adapter->txs_ring +
+					(adapter->txs_ring_size +
+					txs_write_ptr - 2);
+			} else {
+				txs = adapter->txs_ring + (txs_write_ptr - 2);
+			}
+			printk(KERN_WARNING
+				"txs-before:0x%08x\n",
+				*(u32 *)txs);
+			txs = old_txs;
+		}
+
+		 /* 4for TPH */
+		txd_read_ptr += (((u32)(txph->pkt_size) + 7) & ~3);
+		if (txd_read_ptr >= adapter->txd_ring_size)
+			txd_read_ptr -= adapter->txd_ring_size;
+
+		atomic_set(&adapter->txd_read_ptr, (int)txd_read_ptr);
+
+		/* tx statistics: */
+		if (txs->ok) {
+			adapter->net_stats.tx_bytes += txs->pkt_size;
+			adapter->net_stats.tx_packets++;
+		}
+		else
+			adapter->net_stats.tx_errors++;
+
+		if (txs->defer)
+			adapter->net_stats.collisions++;
+		if (txs->abort_col)
+			adapter->net_stats.tx_aborted_errors++;
+		if (txs->late_col)
+			adapter->net_stats.tx_window_errors++;
+		if (txs->underun)
+			adapter->net_stats.tx_fifo_errors++;
+	} while (1);
+
+	if (free_hole) {
+		if (netif_queue_stopped(adapter->netdev) &&
+			netif_carrier_ok(adapter->netdev))
+			netif_wake_queue(adapter->netdev);
+	}
+}
+
+static void atl2_check_for_link(struct atl2_adapter *adapter)
+{
+	struct net_device *netdev = adapter->netdev;
+	u16 phy_data = 0;
+
+	spin_lock(&adapter->stats_lock);
+	atl2_read_phy_reg(&adapter->hw, MII_BMSR, &phy_data);
+	atl2_read_phy_reg(&adapter->hw, MII_BMSR, &phy_data);
+	spin_unlock(&adapter->stats_lock);
+
+	/* notify upper layer link down ASAP */
+	if (!(phy_data & BMSR_LSTATUS)) { /* Link Down */
+		if (netif_carrier_ok(netdev)) { /* old link state: Up */
+		printk(KERN_INFO "%s: %s NIC Link is Down\n",
+			atl2_driver_name, netdev->name);
+		adapter->link_speed = SPEED_0;
+		netif_carrier_off(netdev);
+		netif_stop_queue(netdev);
+		}
+	}
+	schedule_work(&adapter->link_chg_task);
+}
+
+static inline void atl2_clear_phy_int(struct atl2_adapter *adapter)
+{
+	u16 phy_data;
+	spin_lock(&adapter->stats_lock);
+	atl2_read_phy_reg(&adapter->hw, 19, &phy_data);
+	spin_unlock(&adapter->stats_lock);
+}
+
+/*
+ * atl2_intr - Interrupt Handler
+ * @irq: interrupt number
+ * @data: pointer to a network interface device structure
+ * @pt_regs: CPU registers structure
+ */
+static irqreturn_t atl2_intr(int irq, void *data)
+{
+	struct atl2_adapter *adapter = netdev_priv(data);
+	struct atl2_hw *hw = &adapter->hw;
+	u32 status;
+
+	status = ATL2_READ_REG(hw, REG_ISR);
+	if (0 == status)
+		return IRQ_NONE;
+
+	/* link event */
+	if (status & ISR_PHY)
+		atl2_clear_phy_int(adapter);
+
+	/* clear ISR status, and Enable CMB DMA/Disable Interrupt */
+	ATL2_WRITE_REG(hw, REG_ISR, status | ISR_DIS_INT);
+
+	/* check if PCIE PHY Link down */
+	if (status & ISR_PHY_LINKDOWN) {
+		if (netif_running(adapter->netdev)) { /* reset MAC */
+			ATL2_WRITE_REG(hw, REG_ISR, 0);
+			ATL2_WRITE_REG(hw, REG_IMR, 0);
+			ATL2_WRITE_FLUSH(hw);
+			schedule_work(&adapter->reset_task);
+			return IRQ_HANDLED;
+		}
+	}
+
+	/* check if DMA read/write error? */
+	if (status & (ISR_DMAR_TO_RST | ISR_DMAW_TO_RST)) {
+		ATL2_WRITE_REG(hw, REG_ISR, 0);
+		ATL2_WRITE_REG(hw, REG_IMR, 0);
+		ATL2_WRITE_FLUSH(hw);
+		schedule_work(&adapter->reset_task);
+		return IRQ_HANDLED;
+	}
+
+	/* link event */
+	if (status & (ISR_PHY | ISR_MANUAL)) {
+		adapter->net_stats.tx_carrier_errors++;
+		atl2_check_for_link(adapter);
+	}
+
+	/* transmit event */
+	if (status & ISR_TX_EVENT)
+		atl2_intr_tx(adapter);
+
+	/* rx exception */
+	if (status & ISR_RX_EVENT)
+		atl2_intr_rx(adapter);
+
+	/* re-enable Interrupt */
+	ATL2_WRITE_REG(&adapter->hw, REG_ISR, 0);
+	return IRQ_HANDLED;
+}
+
+static int atl2_request_irq(struct atl2_adapter *adapter)
+{
+	struct net_device *netdev = adapter->netdev;
+	int flags, err = 0;
+
+	flags = IRQF_SHARED;
+#ifdef CONFIG_PCI_MSI
+	adapter->have_msi = true;
+	err = pci_enable_msi(adapter->pdev);
+	if (err)
+		adapter->have_msi = false;
+
+	if (adapter->have_msi)
+		flags &= ~IRQF_SHARED;
+#endif
+
+	return request_irq(adapter->pdev->irq, &atl2_intr, flags, netdev->name,
+		netdev);
+}
+
+/*
+ * atl2_free_ring_resources - Free Tx / RX descriptor Resources
+ * @adapter: board private structure
+ *
+ * Free all transmit software resources
+ */
+static void atl2_free_ring_resources(struct atl2_adapter *adapter)
+{
+	struct pci_dev *pdev = adapter->pdev;
+	pci_free_consistent(pdev, adapter->ring_size, adapter->ring_vir_addr,
+		adapter->ring_dma);
+}
+
+/*
+ * atl2_open - Called when a network interface is made active
+ * @netdev: network interface device structure
+ *
+ * Returns 0 on success, negative value on failure
+ *
+ * The open entry point is called when a network interface is made
+ * active by the system (IFF_UP).  At this point all resources needed
+ * for transmit and receive operations are allocated, the interrupt
+ * handler is registered with the OS, the watchdog timer is started,
+ * and the stack is notified that the interface is ready.
+ */
+static int atl2_open(struct net_device *netdev)
+{
+	struct atl2_adapter *adapter = netdev_priv(netdev);
+	int err;
+	u32 val;
+
+	/* disallow open during test */
+	if (test_bit(__ATL2_TESTING, &adapter->flags))
+		return -EBUSY;
+
+	/* allocate transmit descriptors */
+	err = atl2_setup_ring_resources(adapter);
+	if (err)
+		return err;
+
+	err = atl2_init_hw(&adapter->hw);
+	if (err) {
+		err = -EIO;
+		goto err_init_hw;
+	}
+
+	/* hardware has been reset, we need to reload some things */
+	atl2_set_multi(netdev);
+	init_ring_ptrs(adapter);
+
+#ifdef NETIF_F_HW_VLAN_TX
+	atl2_restore_vlan(adapter);
+#endif
+
+	if (atl2_configure(adapter)) {
+		err = -EIO;
+		goto err_config;
+	}
+
+	err = atl2_request_irq(adapter);
+	if (err)
+		goto err_req_irq;
+
+	clear_bit(__ATL2_DOWN, &adapter->flags);
+
+	mod_timer(&adapter->watchdog_timer, jiffies + 4*HZ);
+
+	val = ATL2_READ_REG(&adapter->hw, REG_MASTER_CTRL);
+	ATL2_WRITE_REG(&adapter->hw, REG_MASTER_CTRL,
+		val | MASTER_CTRL_MANUAL_INT);
+
+	atl2_irq_enable(adapter);
+
+	return 0;
+
+err_init_hw:
+err_req_irq:
+err_config:
+	atl2_free_ring_resources(adapter);
+	atl2_reset_hw(&adapter->hw);
+
+	return err;
+}
+
+static void atl2_down(struct atl2_adapter *adapter)
+{
+	struct net_device *netdev = adapter->netdev;
+
+	/* signal that we're down so the interrupt handler does not
+	 * reschedule our watchdog timer */
+	set_bit(__ATL2_DOWN, &adapter->flags);
+
+	netif_tx_disable(netdev);
+
+	/* reset MAC to disable all RX/TX */
+	atl2_reset_hw(&adapter->hw);
+	msleep(1);
+
+	atl2_irq_disable(adapter);
+
+	del_timer_sync(&adapter->watchdog_timer);
+	del_timer_sync(&adapter->phy_config_timer);
+	clear_bit(0, &adapter->cfg_phy);
+
+	netif_carrier_off(netdev);
+	adapter->link_speed = SPEED_0;
+	adapter->link_duplex = -1;
+}
+
+static void atl2_free_irq(struct atl2_adapter *adapter)
+{
+	struct net_device *netdev = adapter->netdev;
+
+	free_irq(adapter->pdev->irq, netdev);
+
+#ifdef CONFIG_PCI_MSI
+	if (adapter->have_msi)
+		pci_disable_msi(adapter->pdev);
+#endif
+}
+
+/*
+ * atl2_close - Disables a network interface
+ * @netdev: network interface device structure
+ *
+ * Returns 0, this is not allowed to fail
+ *
+ * The close entry point is called when an interface is de-activated
+ * by the OS.  The hardware is still under the drivers control, but
+ * needs to be disabled.  A global MAC reset is issued to stop the
+ * hardware, and all transmit and receive resources are freed.
+ */
+static int atl2_close(struct net_device *netdev)
+{
+	struct atl2_adapter *adapter = netdev_priv(netdev);
+
+	WARN_ON(test_bit(__ATL2_RESETTING, &adapter->flags));
+
+	atl2_down(adapter);
+	atl2_free_irq(adapter);
+	atl2_free_ring_resources(adapter);
+
+	return 0;
+}
+
+static inline int TxsFreeUnit(struct atl2_adapter *adapter)
+{
+	u32 txs_write_ptr = (u32) atomic_read(&adapter->txs_write_ptr);
+
+	return (adapter->txs_next_clear >= txs_write_ptr) ?
+		(int) (adapter->txs_ring_size - adapter->txs_next_clear +
+		txs_write_ptr - 1) :
+		(int) (txs_write_ptr - adapter->txs_next_clear - 1);
+}
+
+static inline int TxdFreeBytes(struct atl2_adapter *adapter)
+{
+	u32 txd_read_ptr = (u32)atomic_read(&adapter->txd_read_ptr);
+
+	return (adapter->txd_write_ptr >= txd_read_ptr) ?
+		(int) (adapter->txd_ring_size - adapter->txd_write_ptr +
+		txd_read_ptr - 1) :
+		(int) (txd_read_ptr - adapter->txd_write_ptr - 1);
+}
+
+static int atl2_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
+{
+	struct atl2_adapter *adapter = netdev_priv(netdev);
+	struct tx_pkt_header *txph;
+	u32 offset, copy_len;
+	int txs_unused;
+	int txbuf_unused;
+
+	if (test_bit(__ATL2_DOWN, &adapter->flags)) {
+		dev_kfree_skb_any(skb);
+		return NETDEV_TX_OK;
+	}
+
+	if (unlikely(skb->len <= 0)) {
+		dev_kfree_skb_any(skb);
+		return NETDEV_TX_OK;
+	}
+
+	txs_unused = TxsFreeUnit(adapter);
+	txbuf_unused = TxdFreeBytes(adapter);
+
+	if (skb->len + sizeof(struct tx_pkt_header) + 4  > txbuf_unused ||
+		txs_unused < 1) {
+		/* not enough resources */
+		netif_stop_queue(netdev);
+		return NETDEV_TX_BUSY;
+	}
+
+	offset = adapter->txd_write_ptr;
+
+	txph = (struct tx_pkt_header *) (((u8 *)adapter->txd_ring) + offset);
+
+	*(u32 *)txph = 0;
+	txph->pkt_size = skb->len;
+
+	offset += 4;
+	if (offset >= adapter->txd_ring_size)
+		offset -= adapter->txd_ring_size;
+	copy_len = adapter->txd_ring_size - offset;
+	if (copy_len >= skb->len) {
+		memcpy(((u8 *)adapter->txd_ring) + offset, skb->data, skb->len);
+		offset += ((u32)(skb->len + 3) & ~3);
+	} else {
+		memcpy(((u8 *)adapter->txd_ring)+offset, skb->data, copy_len);
+		memcpy((u8 *)adapter->txd_ring, skb->data+copy_len,
+			skb->len-copy_len);
+		offset = ((u32)(skb->len-copy_len + 3) & ~3);
+	}
+#ifdef NETIF_F_HW_VLAN_TX
+	if (adapter->vlgrp && vlan_tx_tag_present(skb)) {
+		u16 vlan_tag = vlan_tx_tag_get(skb);
+		vlan_tag = (vlan_tag << 4) |
+			(vlan_tag >> 13) |
+			((vlan_tag >> 9) & 0x8);
+		txph->ins_vlan = 1;
+		txph->vlan = vlan_tag;
+	}
+#endif
+	if (offset >= adapter->txd_ring_size)
+		offset -= adapter->txd_ring_size;
+	adapter->txd_write_ptr = offset;
+
+	/* clear txs before send */
+	adapter->txs_ring[adapter->txs_next_clear].update = 0;
+	if (++adapter->txs_next_clear == adapter->txs_ring_size)
+		adapter->txs_next_clear = 0;
+
+	ATL2_WRITE_REGW(&adapter->hw, REG_MB_TXD_WR_IDX,
+		(adapter->txd_write_ptr >> 2));
+
+	mmiowb();
+	netdev->trans_start = jiffies;
+	dev_kfree_skb_any(skb);
+	return NETDEV_TX_OK;
+}
+
+/*
+ * atl2_get_stats - Get System Network Statistics
+ * @netdev: network interface device structure
+ *
+ * Returns the address of the device statistics structure.
+ * The statistics are actually updated from the timer callback.
+ */
+static struct net_device_stats *atl2_get_stats(struct net_device *netdev)
+{
+	struct atl2_adapter *adapter = netdev_priv(netdev);
+	return &adapter->net_stats;
+}
+
+/*
+ * atl2_change_mtu - Change the Maximum Transfer Unit
+ * @netdev: network interface device structure
+ * @new_mtu: new value for maximum frame size
+ *
+ * Returns 0 on success, negative on failure
+ */
+static int atl2_change_mtu(struct net_device *netdev, int new_mtu)
+{
+	struct atl2_adapter *adapter = netdev_priv(netdev);
+	struct atl2_hw *hw = &adapter->hw;
+
+	if ((new_mtu < 40) || (new_mtu > (ETH_DATA_LEN + VLAN_SIZE)))
+		return -EINVAL;
+
+	/* set MTU */
+	if (hw->max_frame_size != new_mtu) {
+		netdev->mtu = new_mtu;
+		ATL2_WRITE_REG(hw, REG_MTU, new_mtu + ENET_HEADER_SIZE +
+			VLAN_SIZE + ETHERNET_FCS_SIZE);
+	}
+
+	return 0;
+}
+
+/*
+ * atl2_set_mac - Change the Ethernet Address of the NIC
+ * @netdev: network interface device structure
+ * @p: pointer to an address structure
+ *
+ * Returns 0 on success, negative on failure
+ */
+static int atl2_set_mac(struct net_device *netdev, void *p)
+{
+	struct atl2_adapter *adapter = netdev_priv(netdev);
+	struct sockaddr *addr = p;
+
+	if (!is_valid_ether_addr(addr->sa_data))
+		return -EADDRNOTAVAIL;
+
+	if (netif_running(netdev))
+		return -EBUSY;
+
+	memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len);
+	memcpy(adapter->hw.mac_addr, addr->sa_data, netdev->addr_len);
+
+	atl2_set_mac_addr(&adapter->hw);
+
+	return 0;
+}
+
+/*
+ * atl2_mii_ioctl -
+ * @netdev:
+ * @ifreq:
+ * @cmd:
+ */
+static int atl2_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
+{
+	struct atl2_adapter *adapter = netdev_priv(netdev);
+	struct mii_ioctl_data *data = if_mii(ifr);
+	unsigned long flags;
+
+	switch (cmd) {
+	case SIOCGMIIPHY:
+		data->phy_id = 0;
+		break;
+	case SIOCGMIIREG:
+		if (!capable(CAP_NET_ADMIN))
+			return -EPERM;
+		spin_lock_irqsave(&adapter->stats_lock, flags);
+		if (atl2_read_phy_reg(&adapter->hw,
+			data->reg_num & 0x1F, &data->val_out)) {
+			spin_unlock_irqrestore(&adapter->stats_lock, flags);
+			return -EIO;
+		}
+		spin_unlock_irqrestore(&adapter->stats_lock, flags);
+		break;
+	case SIOCSMIIREG:
+		if (!capable(CAP_NET_ADMIN))
+			return -EPERM;
+		if (data->reg_num & ~(0x1F))
+			return -EFAULT;
+		spin_lock_irqsave(&adapter->stats_lock, flags);
+		if (atl2_write_phy_reg(&adapter->hw, data->reg_num,
+			data->val_in)) {
+			spin_unlock_irqrestore(&adapter->stats_lock, flags);
+			return -EIO;
+		}
+		spin_unlock_irqrestore(&adapter->stats_lock, flags);
+		break;
+	default:
+		return -EOPNOTSUPP;
+	}
+	return 0;
+}
+
+/*
+ * atl2_ioctl -
+ * @netdev:
+ * @ifreq:
+ * @cmd:
+ */
+static int atl2_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
+{
+	switch (cmd) {
+	case SIOCGMIIPHY:
+	case SIOCGMIIREG:
+	case SIOCSMIIREG:
+		return atl2_mii_ioctl(netdev, ifr, cmd);
+#ifdef ETHTOOL_OPS_COMPAT
+	case SIOCETHTOOL:
+		return ethtool_ioctl(ifr);
+#endif
+	default:
+		return -EOPNOTSUPP;
+	}
+}
+
+/*
+ * atl2_tx_timeout - Respond to a Tx Hang
+ * @netdev: network interface device structure
+ */
+static void atl2_tx_timeout(struct net_device *netdev)
+{
+	struct atl2_adapter *adapter = netdev_priv(netdev);
+
+	/* Do the reset outside of interrupt context */
+	schedule_work(&adapter->reset_task);
+}
+
+/*
+ * atl2_watchdog - Timer Call-back
+ * @data: pointer to netdev cast into an unsigned long
+ */
+static void atl2_watchdog(unsigned long data)
+{
+	struct atl2_adapter *adapter = (struct atl2_adapter *) data;
+	u32 drop_rxd, drop_rxs;
+	unsigned long flags;
+
+	if (!test_bit(__ATL2_DOWN, &adapter->flags)) {
+		spin_lock_irqsave(&adapter->stats_lock, flags);
+		drop_rxd = ATL2_READ_REG(&adapter->hw, REG_STS_RXD_OV);
+		drop_rxs = ATL2_READ_REG(&adapter->hw, REG_STS_RXS_OV);
+		adapter->net_stats.rx_over_errors += (drop_rxd+drop_rxs);
+		spin_unlock_irqrestore(&adapter->stats_lock, flags);
+
+		/* Reset the timer */
+		mod_timer(&adapter->watchdog_timer, jiffies + 4 * HZ);
+	}
+}
+
+/*
+ * atl2_phy_config - Timer Call-back
+ * @data: pointer to netdev cast into an unsigned long
+ */
+static void atl2_phy_config(unsigned long data)
+{
+	struct atl2_adapter *adapter = (struct atl2_adapter *) data;
+	struct atl2_hw *hw = &adapter->hw;
+	unsigned long flags;
+
+	spin_lock_irqsave(&adapter->stats_lock, flags);
+	atl2_write_phy_reg(hw, MII_ADVERTISE, hw->mii_autoneg_adv_reg);
+	atl2_write_phy_reg(hw, MII_BMCR, MII_CR_RESET | MII_CR_AUTO_NEG_EN |
+		MII_CR_RESTART_AUTO_NEG);
+	spin_unlock_irqrestore(&adapter->stats_lock, flags);
+	clear_bit(0, &adapter->cfg_phy);
+}
+
+static int atl2_up(struct atl2_adapter *adapter)
+{
+	struct net_device *netdev = adapter->netdev;
+	int err = 0;
+	u32 val;
+
+	/* hardware has been reset, we need to reload some things */
+
+	err = atl2_init_hw(&adapter->hw);
+	if (err) {
+		err = -EIO;
+		return err;
+	}
+
+	atl2_set_multi(netdev);
+	init_ring_ptrs(adapter);
+
+#ifdef NETIF_F_HW_VLAN_TX
+	atl2_restore_vlan(adapter);
+#endif
+
+	if (atl2_configure(adapter)) {
+		err = -EIO;
+		goto err_up;
+	}
+
+	clear_bit(__ATL2_DOWN, &adapter->flags);
+
+	val = ATL2_READ_REG(&adapter->hw, REG_MASTER_CTRL);
+	ATL2_WRITE_REG(&adapter->hw, REG_MASTER_CTRL, val |
+		MASTER_CTRL_MANUAL_INT);
+
+	atl2_irq_enable(adapter);
+
+err_up:
+	return err;
+}
+
+static void atl2_reinit_locked(struct atl2_adapter *adapter)
+{
+	WARN_ON(in_interrupt());
+	while (test_and_set_bit(__ATL2_RESETTING, &adapter->flags))
+		msleep(1);
+	atl2_down(adapter);
+	atl2_up(adapter);
+	clear_bit(__ATL2_RESETTING, &adapter->flags);
+}
+
+static void atl2_reset_task(struct work_struct *work)
+{
+	struct atl2_adapter *adapter;
+	adapter = container_of(work, struct atl2_adapter, reset_task);
+
+	atl2_reinit_locked(adapter);
+}
+
+static void atl2_setup_mac_ctrl(struct atl2_adapter *adapter)
+{
+	u32 value;
+	struct atl2_hw *hw = &adapter->hw;
+	struct net_device *netdev = adapter->netdev;
+
+	/* Config MAC CTRL Register */
+	value = MAC_CTRL_TX_EN | MAC_CTRL_RX_EN | MAC_CTRL_MACLP_CLK_PHY;
+
+	/* duplex */
+	if (FULL_DUPLEX == adapter->link_duplex)
+		value |= MAC_CTRL_DUPLX;
+
+	/* flow control */
+	value |= (MAC_CTRL_TX_FLOW | MAC_CTRL_RX_FLOW);
+
+	/* PAD & CRC */
+	value |= (MAC_CTRL_ADD_CRC | MAC_CTRL_PAD);
+
+	/* preamble length */
+	value |= (((u32)adapter->hw.preamble_len & MAC_CTRL_PRMLEN_MASK) <<
+		MAC_CTRL_PRMLEN_SHIFT);
+
+	/* vlan */
+	if (adapter->vlgrp)
+		value |= MAC_CTRL_RMV_VLAN;
+
+	/* filter mode */
+	value |= MAC_CTRL_BC_EN;
+	if (netdev->flags & IFF_PROMISC)
+		value |= MAC_CTRL_PROMIS_EN;
+	else if (netdev->flags & IFF_ALLMULTI)
+		value |= MAC_CTRL_MC_ALL_EN;
+
+	/* half retry buffer */
+	value |= (((u32)(adapter->hw.retry_buf &
+		MAC_CTRL_HALF_LEFT_BUF_MASK)) << MAC_CTRL_HALF_LEFT_BUF_SHIFT);
+
+	ATL2_WRITE_REG(hw, REG_MAC_CTRL, value);
+}
+
+static int atl2_check_link(struct atl2_adapter *adapter)
+{
+	struct atl2_hw *hw = &adapter->hw;
+	struct net_device *netdev = adapter->netdev;
+	int ret_val;
+	u16 speed, duplex, phy_data;
+	int reconfig = 0;
+
+	/* MII_BMSR must read twise */
+	atl2_read_phy_reg(hw, MII_BMSR, &phy_data);
+	atl2_read_phy_reg(hw, MII_BMSR, &phy_data);
+	if (!(phy_data&BMSR_LSTATUS)) { /* link down */
+		if (netif_carrier_ok(netdev)) { /* old link state: Up */
+			u32 value;
+			/* disable rx */
+			value = ATL2_READ_REG(hw, REG_MAC_CTRL);
+			value &= ~MAC_CTRL_RX_EN;
+			ATL2_WRITE_REG(hw, REG_MAC_CTRL, value);
+			adapter->link_speed = SPEED_0;
+			netif_carrier_off(netdev);
+			netif_stop_queue(netdev);
+		}
+		return 0;
+	}
+
+	/* Link Up */
+	ret_val = atl2_get_speed_and_duplex(hw, &speed, &duplex);
+	if (ret_val)
+		return ret_val;
+	switch (hw->MediaType) {
+	case MEDIA_TYPE_100M_FULL:
+		if (speed  != SPEED_100 || duplex != FULL_DUPLEX)
+			reconfig = 1;
+		break;
+	case MEDIA_TYPE_100M_HALF:
+		if (speed  != SPEED_100 || duplex != HALF_DUPLEX)
+			reconfig = 1;
+		break;
+	case MEDIA_TYPE_10M_FULL:
+		if (speed != SPEED_10 || duplex != FULL_DUPLEX)
+			reconfig = 1;
+		break;
+	case MEDIA_TYPE_10M_HALF:
+		if (speed  != SPEED_10 || duplex != HALF_DUPLEX)
+			reconfig = 1;
+		break;
+	}
+	/* link result is our setting */
+	if (reconfig == 0) {
+		if (adapter->link_speed != speed ||
+			adapter->link_duplex != duplex) {
+			adapter->link_speed = speed;
+			adapter->link_duplex = duplex;
+			atl2_setup_mac_ctrl(adapter);
+			printk(KERN_INFO "%s: %s NIC Link is Up<%d Mbps %s>\n",
+				atl2_driver_name, netdev->name,
+				adapter->link_speed,
+				adapter->link_duplex == FULL_DUPLEX ?
+					"Full Duplex" : "Half Duplex");
+		}
+
+		if (!netif_carrier_ok(netdev)) { /* Link down -> Up */
+			netif_carrier_on(netdev);
+			netif_wake_queue(netdev);
+		}
+		return 0;
+	}
+
+	/* change original link status */
+	if (netif_carrier_ok(netdev)) {
+		u32 value;
+		/* disable rx */
+		value = ATL2_READ_REG(hw, REG_MAC_CTRL);
+		value &= ~MAC_CTRL_RX_EN;
+		ATL2_WRITE_REG(hw, REG_MAC_CTRL, value);
+
+		adapter->link_speed = SPEED_0;
+		netif_carrier_off(netdev);
+		netif_stop_queue(netdev);
+	}
+
+	/* auto-neg, insert timer to re-config phy
+	 * (if interval smaller than 5 seconds, something strange) */
+	if (!test_bit(__ATL2_DOWN, &adapter->flags)) {
+		if (!test_and_set_bit(0, &adapter->cfg_phy))
+			mod_timer(&adapter->phy_config_timer, jiffies + 5 * HZ);
+	}
+
+	return 0;
+}
+
+/*
+ * atl2_link_chg_task - deal with link change event Out of interrupt context
+ * @netdev: network interface device structure
+ */
+static void atl2_link_chg_task(struct work_struct *work)
+{
+	struct atl2_adapter *adapter;
+	unsigned long flags;
+
+	adapter = container_of(work, struct atl2_adapter, link_chg_task);
+
+	spin_lock_irqsave(&adapter->stats_lock, flags);
+	atl2_check_link(adapter);
+	spin_unlock_irqrestore(&adapter->stats_lock, flags);
+}
+
+static void atl2_setup_pcicmd(struct pci_dev *pdev)
+{
+	u16 cmd;
+
+	pci_read_config_word(pdev, PCI_COMMAND, &cmd);
+
+	if (cmd & PCI_COMMAND_INTX_DISABLE)
+		cmd &= ~PCI_COMMAND_INTX_DISABLE;
+	if (cmd & PCI_COMMAND_IO)
+		cmd &= ~PCI_COMMAND_IO;
+	if (0 == (cmd & PCI_COMMAND_MEMORY))
+		cmd |= PCI_COMMAND_MEMORY;
+	if (0 == (cmd & PCI_COMMAND_MASTER))
+		cmd |= PCI_COMMAND_MASTER;
+	pci_write_config_word(pdev, PCI_COMMAND, cmd);
+
+	/*
+	 * some motherboards BIOS(PXE/EFI) driver may set PME
+	 * while they transfer control to OS (Windows/Linux)
+	 * so we should clear this bit before NIC work normally
+	 */
+	pci_write_config_dword(pdev, REG_PM_CTRLSTAT, 0);
+}
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void atl2_poll_controller(struct net_device *netdev)
+{
+	disable_irq(netdev->irq);
+	atl2_intr(netdev->irq, netdev);
+	enable_irq(netdev->irq);
+}
+#endif
+
+/*
+ * atl2_probe - Device Initialization Routine
+ * @pdev: PCI device information struct
+ * @ent: entry in atl2_pci_tbl
+ *
+ * Returns 0 on success, negative on failure
+ *
+ * atl2_probe initializes an adapter identified by a pci_dev structure.
+ * The OS initialization, configuring of the adapter private structure,
+ * and a hardware reset occur.
+ */
+static int __devinit atl2_probe(struct pci_dev *pdev,
+	const struct pci_device_id *ent)
+{
+	struct net_device *netdev;
+	struct atl2_adapter *adapter;
+	static int cards_found;
+	unsigned long mmio_start;
+	int mmio_len;
+	int err;
+
+	cards_found = 0;
+
+	err = pci_enable_device(pdev);
+	if (err)
+		return err;
+
+	/*
+	 * atl2 is a shared-high-32-bit device, so we're stuck with 32-bit DMA
+	 * until the kernel has the proper infrastructure to support 64-bit DMA
+	 * on these devices.
+	 */
+	if (pci_set_dma_mask(pdev, DMA_32BIT_MASK) &&
+		pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK)) {
+		printk(KERN_ERR "atl2: No usable DMA configuration, aborting\n");
+		goto err_dma;
+	}
+
+	/* Mark all PCI regions associated with PCI device
+	 * pdev as being reserved by owner atl2_driver_name */
+	err = pci_request_regions(pdev, atl2_driver_name);
+	if (err)
+		goto err_pci_reg;
+
+	/* Enables bus-mastering on the device and calls
+	 * pcibios_set_master to do the needed arch specific settings */
+	pci_set_master(pdev);
+
+	err = -ENOMEM;
+	netdev = alloc_etherdev(sizeof(struct atl2_adapter));
+	if (!netdev)
+		goto err_alloc_etherdev;
+
+	SET_NETDEV_DEV(netdev, &pdev->dev);
+
+	pci_set_drvdata(pdev, netdev);
+	adapter = netdev_priv(netdev);
+	adapter->netdev = netdev;
+	adapter->pdev = pdev;
+	adapter->hw.back = adapter;
+
+	mmio_start = pci_resource_start(pdev, 0x0);
+	mmio_len = pci_resource_len(pdev, 0x0);
+
+	adapter->hw.mem_rang = (u32)mmio_len;
+	adapter->hw.hw_addr = ioremap(mmio_start, mmio_len);
+	if (!adapter->hw.hw_addr) {
+		err = -EIO;
+		goto err_ioremap;
+	}
+
+	atl2_setup_pcicmd(pdev);
+
+	netdev->open = &atl2_open;
+	netdev->stop = &atl2_close;
+	netdev->hard_start_xmit = &atl2_xmit_frame;
+	netdev->get_stats = &atl2_get_stats;
+	netdev->set_multicast_list = &atl2_set_multi;
+	netdev->set_mac_address = &atl2_set_mac;
+	netdev->change_mtu = &atl2_change_mtu;
+	netdev->do_ioctl = &atl2_ioctl;
+	atl2_set_ethtool_ops(netdev);
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	netdev->poll_controller = atl2_poll_controller;
+#endif
+#ifdef HAVE_TX_TIMEOUT
+	netdev->tx_timeout = &atl2_tx_timeout;
+	netdev->watchdog_timeo = 5 * HZ;
+#endif
+#ifdef NETIF_F_HW_VLAN_TX
+	netdev->vlan_rx_register = atl2_vlan_rx_register;
+#endif
+	strncpy(netdev->name, pci_name(pdev), sizeof(netdev->name) - 1);
+
+	netdev->mem_start = mmio_start;
+	netdev->mem_end = mmio_start + mmio_len;
+	adapter->bd_number = cards_found;
+	adapter->pci_using_64 = false;
+
+	/* setup the private structure */
+	err = atl2_sw_init(adapter);
+	if (err)
+		goto err_sw_init;
+
+	err = -EIO;
+
+#ifdef NETIF_F_HW_VLAN_TX
+	netdev->features |= (NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX);
+#endif
+
+	/* Init PHY as early as possible due to power saving issue  */
+	atl2_phy_init(&adapter->hw);
+
+	/* reset the controller to
+	 * put the device in a known good starting state */
+
+	if (atl2_reset_hw(&adapter->hw)) {
+		err = -EIO;
+		goto err_reset;
+	}
+
+	/* copy the MAC address out of the EEPROM */
+	atl2_read_mac_addr(&adapter->hw);
+	memcpy(netdev->dev_addr, adapter->hw.mac_addr, netdev->addr_len);
+/* FIXME: do we still need this? */
+#ifdef ETHTOOL_GPERMADDR
+	memcpy(netdev->perm_addr, adapter->hw.mac_addr, netdev->addr_len);
+
+	if (!is_valid_ether_addr(netdev->perm_addr)) {
+#else
+	if (!is_valid_ether_addr(netdev->dev_addr)) {
+#endif
+		err = -EIO;
+		goto err_eeprom;
+	}
+
+	atl2_check_options(adapter);
+
+	init_timer(&adapter->watchdog_timer);
+	adapter->watchdog_timer.function = &atl2_watchdog;
+	adapter->watchdog_timer.data = (unsigned long) adapter;
+
+	init_timer(&adapter->phy_config_timer);
+	adapter->phy_config_timer.function = &atl2_phy_config;
+	adapter->phy_config_timer.data = (unsigned long) adapter;
+
+	INIT_WORK(&adapter->reset_task, atl2_reset_task);
+	INIT_WORK(&adapter->link_chg_task, atl2_link_chg_task);
+
+	strcpy(netdev->name, "eth%d"); /* ?? */
+	err = register_netdev(netdev);
+	if (err)
+		goto err_register;
+
+	/* assume we have no link for now */
+	netif_carrier_off(netdev);
+	netif_stop_queue(netdev);
+
+	cards_found++;
+
+	return 0;
+
+err_reset:
+err_register:
+err_sw_init:
+err_eeprom:
+	iounmap(adapter->hw.hw_addr);
+err_ioremap:
+	free_netdev(netdev);
+err_alloc_etherdev:
+	pci_release_regions(pdev);
+err_pci_reg:
+err_dma:
+	pci_disable_device(pdev);
+	return err;
+}
+
+/*
+ * atl2_remove - Device Removal Routine
+ * @pdev: PCI device information struct
+ *
+ * atl2_remove is called by the PCI subsystem to alert the driver
+ * that it should release a PCI device.  The could be caused by a
+ * Hot-Plug event, or because the driver is going to be removed from
+ * memory.
+ */
+/* FIXME: write the original MAC address back in case it was changed from a
+ * BIOS-set value, as in atl1 -- CHS */
+static void __devexit atl2_remove(struct pci_dev *pdev)
+{
+	struct net_device *netdev = pci_get_drvdata(pdev);
+	struct atl2_adapter *adapter = netdev_priv(netdev);
+
+	/* flush_scheduled work may reschedule our watchdog task, so
+	 * explicitly disable watchdog tasks from being rescheduled  */
+	set_bit(__ATL2_DOWN, &adapter->flags);
+
+	del_timer_sync(&adapter->watchdog_timer);
+	del_timer_sync(&adapter->phy_config_timer);
+
+	flush_scheduled_work();
+
+	unregister_netdev(netdev);
+
+	atl2_force_ps(&adapter->hw);
+
+	iounmap(adapter->hw.hw_addr);
+	pci_release_regions(pdev);
+
+	free_netdev(netdev);
+
+	pci_disable_device(pdev);
+}
+
+static int atl2_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+	struct net_device *netdev = pci_get_drvdata(pdev);
+	struct atl2_adapter *adapter = netdev_priv(netdev);
+	struct atl2_hw *hw = &adapter->hw;
+	u16 speed, duplex;
+	u32 ctrl = 0;
+	u32 wufc = adapter->wol;
+
+#ifdef CONFIG_PM
+	int retval = 0;
+#endif
+
+	netif_device_detach(netdev);
+
+	if (netif_running(netdev)) {
+		WARN_ON(test_bit(__ATL2_RESETTING, &adapter->flags));
+		atl2_down(adapter);
+	}
+
+#ifdef CONFIG_PM
+	retval = pci_save_state(pdev);
+	if (retval)
+		return retval;
+#endif
+
+	atl2_read_phy_reg(hw, MII_BMSR, (u16 *)&ctrl);
+	atl2_read_phy_reg(hw, MII_BMSR, (u16 *)&ctrl);
+	if (ctrl & BMSR_LSTATUS)
+		wufc &= ~ATLX_WUFC_LNKC;
+
+	if (0 != (ctrl & BMSR_LSTATUS) && 0 != wufc) {
+		u32 ret_val;
+		/* get current link speed & duplex */
+		ret_val = atl2_get_speed_and_duplex(hw, &speed, &duplex);
+		if (ret_val) {
+			printk(KERN_DEBUG
+				"%s: get speed&duplex error while suspend\n",
+				atl2_driver_name);
+			goto wol_dis;
+		}
+
+		ctrl = 0;
+
+		/* turn on magic packet wol */
+		if (wufc & ATLX_WUFC_MAG)
+			ctrl |= (WOL_MAGIC_EN | WOL_MAGIC_PME_EN);
+
+		/* ignore Link Chg event when Link is up */
+		ATL2_WRITE_REG(hw, REG_WOL_CTRL, ctrl);
+
+		/* Config MAC CTRL Register */
+		ctrl = MAC_CTRL_RX_EN | MAC_CTRL_MACLP_CLK_PHY;
+		if (FULL_DUPLEX == adapter->link_duplex)
+			ctrl |= MAC_CTRL_DUPLX;
+		ctrl |= (MAC_CTRL_ADD_CRC | MAC_CTRL_PAD);
+		ctrl |= (((u32)adapter->hw.preamble_len &
+			MAC_CTRL_PRMLEN_MASK) << MAC_CTRL_PRMLEN_SHIFT);
+		ctrl |= (((u32)(adapter->hw.retry_buf &
+			MAC_CTRL_HALF_LEFT_BUF_MASK)) <<
+			MAC_CTRL_HALF_LEFT_BUF_SHIFT);
+		if (wufc & ATLX_WUFC_MAG) {
+			/* magic packet maybe Broadcast&multicast&Unicast */
+			ctrl |= MAC_CTRL_BC_EN;
+		}
+
+		ATL2_WRITE_REG(hw, REG_MAC_CTRL, ctrl);
+
+		/* pcie patch */
+		ctrl = ATL2_READ_REG(hw, REG_PCIE_PHYMISC);
+		ctrl |= PCIE_PHYMISC_FORCE_RCV_DET;
+		ATL2_WRITE_REG(hw, REG_PCIE_PHYMISC, ctrl);
+		ctrl = ATL2_READ_REG(hw, REG_PCIE_DLL_TX_CTRL1);
+		ctrl |= PCIE_DLL_TX_CTRL1_SEL_NOR_CLK;
+		ATL2_WRITE_REG(hw, REG_PCIE_DLL_TX_CTRL1, ctrl);
+
+		pci_enable_wake(pdev, pci_choose_state(pdev, state), 1);
+		goto suspend_exit;
+	}
+
+	if (0 == (ctrl&BMSR_LSTATUS) && 0 != (wufc&ATLX_WUFC_LNKC)) {
+		/* link is down, so only LINK CHG WOL event enable */
+		ctrl |= (WOL_LINK_CHG_EN | WOL_LINK_CHG_PME_EN);
+		ATL2_WRITE_REG(hw, REG_WOL_CTRL, ctrl);
+		ATL2_WRITE_REG(hw, REG_MAC_CTRL, 0);
+
+		/* pcie patch */
+		ctrl = ATL2_READ_REG(hw, REG_PCIE_PHYMISC);
+		ctrl |= PCIE_PHYMISC_FORCE_RCV_DET;
+		ATL2_WRITE_REG(hw, REG_PCIE_PHYMISC, ctrl);
+		ctrl = ATL2_READ_REG(hw, REG_PCIE_DLL_TX_CTRL1);
+		ctrl |= PCIE_DLL_TX_CTRL1_SEL_NOR_CLK;
+		ATL2_WRITE_REG(hw, REG_PCIE_DLL_TX_CTRL1, ctrl);
+
+		hw->phy_configured = false; /* re-init PHY when resume */
+
+		pci_enable_wake(pdev, pci_choose_state(pdev, state), 1);
+
+		goto suspend_exit;
+	}
+
+wol_dis:
+	/* WOL disabled */
+	ATL2_WRITE_REG(hw, REG_WOL_CTRL, 0);
+
+	/* pcie patch */
+	ctrl = ATL2_READ_REG(hw, REG_PCIE_PHYMISC);
+	ctrl |= PCIE_PHYMISC_FORCE_RCV_DET;
+	ATL2_WRITE_REG(hw, REG_PCIE_PHYMISC, ctrl);
+	ctrl = ATL2_READ_REG(hw, REG_PCIE_DLL_TX_CTRL1);
+	ctrl |= PCIE_DLL_TX_CTRL1_SEL_NOR_CLK;
+	ATL2_WRITE_REG(hw, REG_PCIE_DLL_TX_CTRL1, ctrl);
+
+	atl2_force_ps(hw);
+	hw->phy_configured = false; /* re-init PHY when resume */
+
+	pci_enable_wake(pdev, pci_choose_state(pdev, state), 0);
+
+suspend_exit:
+	if (netif_running(netdev))
+		atl2_free_irq(adapter);
+
+	pci_disable_device(pdev);
+
+	pci_set_power_state(pdev, pci_choose_state(pdev, state));
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int atl2_resume(struct pci_dev *pdev)
+{
+	struct net_device *netdev = pci_get_drvdata(pdev);
+	struct atl2_adapter *adapter = netdev_priv(netdev);
+	u32 err;
+
+	pci_set_power_state(pdev, PCI_D0);
+	pci_restore_state(pdev);
+
+	err = pci_enable_device(pdev);
+	if (err) {
+		printk(KERN_ERR
+			"atl2: Cannot enable PCI device from suspend\n");
+		return err;
+	}
+
+	pci_set_master(pdev);
+
+	ATL2_READ_REG(&adapter->hw, REG_WOL_CTRL); /* clear WOL status */
+
+	pci_enable_wake(pdev, PCI_D3hot, 0);
+	pci_enable_wake(pdev, PCI_D3cold, 0);
+
+	ATL2_WRITE_REG(&adapter->hw, REG_WOL_CTRL, 0);
+
+	err = atl2_request_irq(adapter);
+	if (netif_running(netdev) && err)
+		return err;
+
+	atl2_reset_hw(&adapter->hw);
+
+	if (netif_running(netdev))
+		atl2_up(adapter);
+
+	netif_device_attach(netdev);
+
+	return 0;
+}
+#endif
+
+static void atl2_shutdown(struct pci_dev *pdev)
+{
+	atl2_suspend(pdev, PMSG_SUSPEND);
+}
+
+static struct pci_driver atl2_driver = {
+	.name     = atl2_driver_name,
+	.id_table = atl2_pci_tbl,
+	.probe    = atl2_probe,
+	.remove   = __devexit_p(atl2_remove),
+	/* Power Managment Hooks */
+	.suspend  = atl2_suspend,
+#ifdef CONFIG_PM
+	.resume   = atl2_resume,
+#endif
+	.shutdown = atl2_shutdown,
+};
+
+/*
+ * atl2_init_module - Driver Registration Routine
+ *
+ * atl2_init_module is the first routine called when the driver is
+ * loaded. All it does is register with the PCI subsystem.
+ */
+static int __init atl2_init_module(void)
+{
+	printk(KERN_INFO "%s - version %s\n", atl2_driver_string,
+		atl2_driver_version);
+	printk(KERN_INFO "%s\n", atl2_copyright);
+	return pci_register_driver(&atl2_driver);
+}
+module_init(atl2_init_module);
+
+/*
+ * atl2_exit_module - Driver Exit Cleanup Routine
+ *
+ * atl2_exit_module is called just before the driver is removed
+ * from memory.
+ */
+static void __exit atl2_exit_module(void)
+{
+	pci_unregister_driver(&atl2_driver);
+}
+module_exit(atl2_exit_module);
+
+static void atl2_read_pci_cfg(struct atl2_hw *hw, u32 reg, u16 *value)
+{
+	struct atl2_adapter *adapter = hw->back;
+	pci_read_config_word(adapter->pdev, reg, value);
+}
+
+static void atl2_write_pci_cfg(struct atl2_hw *hw, u32 reg, u16 *value)
+{
+	struct atl2_adapter *adapter = hw->back;
+	pci_write_config_word(adapter->pdev, reg, *value);
+}
+
+static int atl2_get_settings(struct net_device *netdev,
+	struct ethtool_cmd *ecmd)
+{
+	struct atl2_adapter *adapter = netdev_priv(netdev);
+	struct atl2_hw *hw = &adapter->hw;
+
+	ecmd->supported = (SUPPORTED_10baseT_Half |
+		SUPPORTED_10baseT_Full |
+		SUPPORTED_100baseT_Half |
+		SUPPORTED_100baseT_Full |
+		SUPPORTED_Autoneg |
+		SUPPORTED_TP);
+	ecmd->advertising = ADVERTISED_TP;
+
+	ecmd->advertising |= ADVERTISED_Autoneg;
+	ecmd->advertising |= hw->autoneg_advertised;
+
+	ecmd->port = PORT_TP;
+	ecmd->phy_address = 0;
+	ecmd->transceiver = XCVR_INTERNAL;
+
+	if (adapter->link_speed != SPEED_0) {
+		ecmd->speed = adapter->link_speed;
+		if (adapter->link_duplex == FULL_DUPLEX)
+			ecmd->duplex = DUPLEX_FULL;
+		else
+			ecmd->duplex = DUPLEX_HALF;
+	} else {
+		ecmd->speed = -1;
+		ecmd->duplex = -1;
+	}
+
+	ecmd->autoneg = AUTONEG_ENABLE;
+	return 0;
+}
+
+static int atl2_set_settings(struct net_device *netdev,
+	struct ethtool_cmd *ecmd)
+{
+	struct atl2_adapter *adapter = netdev_priv(netdev);
+	struct atl2_hw *hw = &adapter->hw;
+
+	while (test_and_set_bit(__ATL2_RESETTING, &adapter->flags))
+		msleep(1);
+
+	if (ecmd->autoneg == AUTONEG_ENABLE) {
+#define MY_ADV_MASK	(ADVERTISE_10_HALF | \
+			 ADVERTISE_10_FULL | \
+			 ADVERTISE_100_HALF| \
+			 ADVERTISE_100_FULL)
+
+		if ((ecmd->advertising & MY_ADV_MASK) == MY_ADV_MASK) {
+			hw->MediaType = MEDIA_TYPE_AUTO_SENSOR;
+			hw->autoneg_advertised =  MY_ADV_MASK;
+		} else if ((ecmd->advertising & MY_ADV_MASK) ==
+				ADVERTISE_100_FULL) {
+			hw->MediaType = MEDIA_TYPE_100M_FULL;
+			hw->autoneg_advertised = ADVERTISE_100_FULL;
+		} else if ((ecmd->advertising & MY_ADV_MASK) ==
+				ADVERTISE_100_HALF) {
+			hw->MediaType = MEDIA_TYPE_100M_HALF;
+			hw->autoneg_advertised = ADVERTISE_100_HALF;
+		} else if ((ecmd->advertising & MY_ADV_MASK) ==
+				ADVERTISE_10_FULL) {
+			hw->MediaType = MEDIA_TYPE_10M_FULL;
+			hw->autoneg_advertised = ADVERTISE_10_FULL;
+		}  else if ((ecmd->advertising & MY_ADV_MASK) ==
+				ADVERTISE_10_HALF) {
+			hw->MediaType = MEDIA_TYPE_10M_HALF;
+			hw->autoneg_advertised = ADVERTISE_10_HALF;
+		} else {
+			clear_bit(__ATL2_RESETTING, &adapter->flags);
+			return -EINVAL;
+		}
+		ecmd->advertising = hw->autoneg_advertised |
+			ADVERTISED_TP | ADVERTISED_Autoneg;
+	} else {
+		clear_bit(__ATL2_RESETTING, &adapter->flags);
+		return -EINVAL;
+	}
+
+	/* reset the link */
+	if (netif_running(adapter->netdev)) {
+		atl2_down(adapter);
+		atl2_up(adapter);
+	} else
+		atl2_reset_hw(&adapter->hw);
+
+	clear_bit(__ATL2_RESETTING, &adapter->flags);
+	return 0;
+}
+
+static u32 atl2_get_tx_csum(struct net_device *netdev)
+{
+	return (netdev->features & NETIF_F_HW_CSUM) != 0;
+}
+
+static u32 atl2_get_msglevel(struct net_device *netdev)
+{
+	return 0;
+}
+
+/*
+ * It's sane for this to be empty, but we might want to take advantage of this.
+ */
+static void atl2_set_msglevel(struct net_device *netdev, u32 data)
+{
+}
+
+static int atl2_get_regs_len(struct net_device *netdev)
+{
+#define ATL2_REGS_LEN 42
+	return sizeof(u32) * ATL2_REGS_LEN;
+}
+
+static void atl2_get_regs(struct net_device *netdev,
+	struct ethtool_regs *regs, void *p)
+{
+	struct atl2_adapter *adapter = netdev_priv(netdev);
+	struct atl2_hw *hw = &adapter->hw;
+	u32 *regs_buff = p;
+	u16 phy_data;
+
+	memset(p, 0, sizeof(u32) * ATL2_REGS_LEN);
+
+	regs->version = (1 << 24) | (hw->revision_id << 16) | hw->device_id;
+
+	regs_buff[0]  = ATL2_READ_REG(hw, REG_VPD_CAP);
+	regs_buff[1]  = ATL2_READ_REG(hw, REG_SPI_FLASH_CTRL);
+	regs_buff[2]  = ATL2_READ_REG(hw, REG_SPI_FLASH_CONFIG);
+	regs_buff[3]  = ATL2_READ_REG(hw, REG_TWSI_CTRL);
+	regs_buff[4]  = ATL2_READ_REG(hw, REG_PCIE_DEV_MISC_CTRL);
+	regs_buff[5]  = ATL2_READ_REG(hw, REG_MASTER_CTRL);
+	regs_buff[6]  = ATL2_READ_REG(hw, REG_MANUAL_TIMER_INIT);
+	regs_buff[7]  = ATL2_READ_REG(hw, REG_IRQ_MODU_TIMER_INIT);
+	regs_buff[8]  = ATL2_READ_REG(hw, REG_PHY_ENABLE);
+	regs_buff[9]  = ATL2_READ_REG(hw, REG_CMBDISDMA_TIMER);
+	regs_buff[10] = ATL2_READ_REG(hw, REG_IDLE_STATUS);
+	regs_buff[11] = ATL2_READ_REG(hw, REG_MDIO_CTRL);
+	regs_buff[12] = ATL2_READ_REG(hw, REG_SERDES_LOCK);
+	regs_buff[13] = ATL2_READ_REG(hw, REG_MAC_CTRL);
+	regs_buff[14] = ATL2_READ_REG(hw, REG_MAC_IPG_IFG);
+	regs_buff[15] = ATL2_READ_REG(hw, REG_MAC_STA_ADDR);
+	regs_buff[16] = ATL2_READ_REG(hw, REG_MAC_STA_ADDR+4);
+	regs_buff[17] = ATL2_READ_REG(hw, REG_RX_HASH_TABLE);
+	regs_buff[18] = ATL2_READ_REG(hw, REG_RX_HASH_TABLE+4);
+	regs_buff[19] = ATL2_READ_REG(hw, REG_MAC_HALF_DUPLX_CTRL);
+	regs_buff[20] = ATL2_READ_REG(hw, REG_MTU);
+	regs_buff[21] = ATL2_READ_REG(hw, REG_WOL_CTRL);
+	regs_buff[22] = ATL2_READ_REG(hw, REG_SRAM_TXRAM_END);
+	regs_buff[23] = ATL2_READ_REG(hw, REG_DESC_BASE_ADDR_HI);
+	regs_buff[24] = ATL2_READ_REG(hw, REG_TXD_BASE_ADDR_LO);
+	regs_buff[25] = ATL2_READ_REG(hw, REG_TXD_MEM_SIZE);
+	regs_buff[26] = ATL2_READ_REG(hw, REG_TXS_BASE_ADDR_LO);
+	regs_buff[27] = ATL2_READ_REG(hw, REG_TXS_MEM_SIZE);
+	regs_buff[28] = ATL2_READ_REG(hw, REG_RXD_BASE_ADDR_LO);
+	regs_buff[29] = ATL2_READ_REG(hw, REG_RXD_BUF_NUM);
+	regs_buff[30] = ATL2_READ_REG(hw, REG_DMAR);
+	regs_buff[31] = ATL2_READ_REG(hw, REG_TX_CUT_THRESH);
+	regs_buff[32] = ATL2_READ_REG(hw, REG_DMAW);
+	regs_buff[33] = ATL2_READ_REG(hw, REG_PAUSE_ON_TH);
+	regs_buff[34] = ATL2_READ_REG(hw, REG_PAUSE_OFF_TH);
+	regs_buff[35] = ATL2_READ_REG(hw, REG_MB_TXD_WR_IDX);
+	regs_buff[36] = ATL2_READ_REG(hw, REG_MB_RXD_RD_IDX);
+	regs_buff[38] = ATL2_READ_REG(hw, REG_ISR);
+	regs_buff[39] = ATL2_READ_REG(hw, REG_IMR);
+
+	atl2_read_phy_reg(hw, MII_BMCR, &phy_data);
+	regs_buff[40] = (u32)phy_data;
+	atl2_read_phy_reg(hw, MII_BMSR, &phy_data);
+	regs_buff[41] = (u32)phy_data;
+}
+
+static int atl2_get_eeprom_len(struct net_device *netdev)
+{
+	struct atl2_adapter *adapter = netdev_priv(netdev);
+
+	if (!atl2_check_eeprom_exist(&adapter->hw))
+		return 512;
+	else
+		return 0;
+}
+
+static int atl2_get_eeprom(struct net_device *netdev,
+	struct ethtool_eeprom *eeprom, u8 *bytes)
+{
+	struct atl2_adapter *adapter = netdev_priv(netdev);
+	struct atl2_hw *hw = &adapter->hw;
+	u32 *eeprom_buff;
+	int first_dword, last_dword;
+	int ret_val = 0;
+	int i;
+
+	if (eeprom->len == 0)
+		return -EINVAL;
+
+	if (atl2_check_eeprom_exist(hw))
+		return -EINVAL;
+
+	eeprom->magic = hw->vendor_id | (hw->device_id << 16);
+
+	first_dword = eeprom->offset >> 2;
+	last_dword = (eeprom->offset + eeprom->len - 1) >> 2;
+
+	eeprom_buff = kmalloc(sizeof(u32) * (last_dword - first_dword + 1),
+		GFP_KERNEL);
+	if (!eeprom_buff)
+		return -ENOMEM;
+
+	for (i = first_dword; i < last_dword; i++) {
+		if (!atl2_read_eeprom(hw, i*4, &(eeprom_buff[i-first_dword])))
+			return -EIO;
+	}
+
+	memcpy(bytes, (u8 *)eeprom_buff + (eeprom->offset & 3),
+		eeprom->len);
+	kfree(eeprom_buff);
+
+	return ret_val;
+}
+
+static int atl2_set_eeprom(struct net_device *netdev,
+	struct ethtool_eeprom *eeprom, u8 *bytes)
+{
+	struct atl2_adapter *adapter = netdev_priv(netdev);
+	struct atl2_hw *hw = &adapter->hw;
+	u32 *eeprom_buff;
+	u32 *ptr;
+	int max_len, first_dword, last_dword, ret_val = 0;
+	int i;
+
+	if (eeprom->len == 0)
+		return -EOPNOTSUPP;
+
+	if (eeprom->magic != (hw->vendor_id | (hw->device_id << 16)))
+		return -EFAULT;
+
+	max_len = 512;
+
+	first_dword = eeprom->offset >> 2;
+	last_dword = (eeprom->offset + eeprom->len - 1) >> 2;
+	eeprom_buff = kmalloc(max_len, GFP_KERNEL);
+	if (!eeprom_buff)
+		return -ENOMEM;
+
+	ptr = (u32 *)eeprom_buff;
+
+	if (eeprom->offset & 3) {
+		/* need read/modify/write of first changed EEPROM word */
+		/* only the second byte of the word is being modified */
+		if (!atl2_read_eeprom(hw, first_dword*4, &(eeprom_buff[0])))
+			return -EIO;
+		ptr++;
+	}
+	if (((eeprom->offset + eeprom->len) & 3)) {
+		/*
+		 * need read/modify/write of last changed EEPROM word
+		 * only the first byte of the word is being modified
+		 */
+		if (!atl2_read_eeprom(hw, last_dword * 4,
+			&(eeprom_buff[last_dword - first_dword])))
+			return -EIO;
+	}
+
+	/* Device's eeprom is always little-endian, word addressable */
+	memcpy(ptr, bytes, eeprom->len);
+
+	for (i = 0; i < last_dword - first_dword + 1; i++) {
+		if (!atl2_write_eeprom(hw, ((first_dword+i)*4), eeprom_buff[i]))
+			return -EIO;
+	}
+
+	kfree(eeprom_buff);
+	return ret_val;
+}
+
+static void atl2_get_drvinfo(struct net_device *netdev,
+	struct ethtool_drvinfo *drvinfo)
+{
+	struct atl2_adapter *adapter = netdev_priv(netdev);
+
+	strncpy(drvinfo->driver,  atl2_driver_name, 32);
+	strncpy(drvinfo->version, atl2_driver_version, 32);
+	strncpy(drvinfo->fw_version, "L2", 32);
+	strncpy(drvinfo->bus_info, pci_name(adapter->pdev), 32);
+	drvinfo->n_stats = 0;
+	drvinfo->testinfo_len = 0;
+	drvinfo->regdump_len = atl2_get_regs_len(netdev);
+	drvinfo->eedump_len = atl2_get_eeprom_len(netdev);
+}
+
+static void atl2_get_wol(struct net_device *netdev,
+	struct ethtool_wolinfo *wol)
+{
+	struct atl2_adapter *adapter = netdev_priv(netdev);
+
+	wol->supported = WAKE_MAGIC;
+	wol->wolopts = 0;
+
+	if (adapter->wol & ATLX_WUFC_EX)
+		wol->wolopts |= WAKE_UCAST;
+	if (adapter->wol & ATLX_WUFC_MC)
+		wol->wolopts |= WAKE_MCAST;
+	if (adapter->wol & ATLX_WUFC_BC)
+		wol->wolopts |= WAKE_BCAST;
+	if (adapter->wol & ATLX_WUFC_MAG)
+		wol->wolopts |= WAKE_MAGIC;
+	if (adapter->wol & ATLX_WUFC_LNKC)
+		wol->wolopts |= WAKE_PHY;
+}
+
+static int atl2_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
+{
+	struct atl2_adapter *adapter = netdev_priv(netdev);
+
+	if (wol->wolopts & (WAKE_ARP | WAKE_MAGICSECURE))
+		return -EOPNOTSUPP;
+
+	if (wol->wolopts & (WAKE_MCAST|WAKE_BCAST|WAKE_MCAST))
+		return -EOPNOTSUPP;
+
+	/* these settings will always override what we currently have */
+	adapter->wol = 0;
+
+	if (wol->wolopts & WAKE_MAGIC)
+		adapter->wol |= ATLX_WUFC_MAG;
+	if (wol->wolopts & WAKE_PHY)
+		adapter->wol |= ATLX_WUFC_LNKC;
+
+	return 0;
+}
+
+static int atl2_nway_reset(struct net_device *netdev)
+{
+	struct atl2_adapter *adapter = netdev_priv(netdev);
+	if (netif_running(netdev))
+		atl2_reinit_locked(adapter);
+	return 0;
+}
+
+static struct ethtool_ops atl2_ethtool_ops = {
+	.get_settings		= atl2_get_settings,
+	.set_settings		= atl2_set_settings,
+	.get_drvinfo		= atl2_get_drvinfo,
+	.get_regs_len		= atl2_get_regs_len,
+	.get_regs		= atl2_get_regs,
+	.get_wol		= atl2_get_wol,
+	.set_wol		= atl2_set_wol,
+	.get_msglevel		= atl2_get_msglevel,
+	.set_msglevel		= atl2_set_msglevel,
+	.nway_reset		= atl2_nway_reset,
+	.get_link		= ethtool_op_get_link,
+	.get_eeprom_len		= atl2_get_eeprom_len,
+	.get_eeprom		= atl2_get_eeprom,
+	.set_eeprom		= atl2_set_eeprom,
+	.get_tx_csum		= atl2_get_tx_csum,
+	.get_sg			= ethtool_op_get_sg,
+	.set_sg			= ethtool_op_set_sg,
+#ifdef NETIF_F_TSO
+	.get_tso		= ethtool_op_get_tso,
+#endif
+};
+
+static void atl2_set_ethtool_ops(struct net_device *netdev)
+{
+	SET_ETHTOOL_OPS(netdev, &atl2_ethtool_ops);
+}
+
+#define LBYTESWAP(a)  ((((a) & 0x00ff00ff) << 8) | \
+	(((a) & 0xff00ff00) >> 8))
+#define LONGSWAP(a)   ((LBYTESWAP(a) << 16) | (LBYTESWAP(a) >> 16))
+#define SHORTSWAP(a)  (((a) << 8) | ((a) >> 8))
+
+/*
+ * Reset the transmit and receive units; mask and clear all interrupts.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * return : 0  or  idle status (if error)
+ */
+static s32 atl2_reset_hw(struct atl2_hw *hw)
+{
+	u32 icr;
+	u16 pci_cfg_cmd_word;
+	int i;
+
+	/* Workaround for PCI problem when BIOS sets MMRBC incorrectly. */
+	atl2_read_pci_cfg(hw, PCI_REG_COMMAND, &pci_cfg_cmd_word);
+	if ((pci_cfg_cmd_word &
+		(CMD_IO_SPACE|CMD_MEMORY_SPACE|CMD_BUS_MASTER)) !=
+		(CMD_IO_SPACE|CMD_MEMORY_SPACE|CMD_BUS_MASTER)) {
+		pci_cfg_cmd_word |=
+			(CMD_IO_SPACE|CMD_MEMORY_SPACE|CMD_BUS_MASTER);
+		atl2_write_pci_cfg(hw, PCI_REG_COMMAND, &pci_cfg_cmd_word);
+	}
+
+	/* Clear Interrupt mask to stop board from generating
+	 * interrupts & Clear any pending interrupt events
+	 */
+	/* FIXME */
+	/* ATL2_WRITE_REG(hw, REG_IMR, 0); */
+	/* ATL2_WRITE_REG(hw, REG_ISR, 0xffffffff); */
+
+	/* Issue Soft Reset to the MAC.  This will reset the chip's
+	 * transmit, receive, DMA.  It will not effect
+	 * the current PCI configuration.  The global reset bit is self-
+	 * clearing, and should clear within a microsecond.
+	 */
+	ATL2_WRITE_REG(hw, REG_MASTER_CTRL, MASTER_CTRL_SOFT_RST);
+	wmb();
+	msleep(1); /* delay about 1ms */
+
+	/* Wait at least 10ms for All module to be Idle */
+	for (i = 0; i < 10; i++) {
+		icr = ATL2_READ_REG(hw, REG_IDLE_STATUS);
+		if (!icr)
+			break;
+		msleep(1); /* delay 1 ms */
+		cpu_relax();
+	}
+
+	if (icr)
+		return icr;
+
+	return 0;
+}
+
+#define CUSTOM_SPI_CS_SETUP        2
+#define CUSTOM_SPI_CLK_HI          2
+#define CUSTOM_SPI_CLK_LO          2
+#define CUSTOM_SPI_CS_HOLD         2
+#define CUSTOM_SPI_CS_HI           3
+
+static struct atl2_spi_flash_dev flash_table[] =
+{
+/* MFR    WRSR  READ  PROGRAM WREN  WRDI  RDSR  RDID  SECTOR_ERASE CHIP_ERASE */
+{"Atmel", 0x0,  0x03, 0x02,   0x06, 0x04, 0x05, 0x15, 0x52,        0x62 },
+{"SST",   0x01, 0x03, 0x02,   0x06, 0x04, 0x05, 0x90, 0x20,        0x60 },
+{"ST",    0x01, 0x03, 0x02,   0x06, 0x04, 0x05, 0xAB, 0xD8,        0xC7 },
+};
+
+static bool atl2_spi_read(struct atl2_hw *hw, u32 addr, u32 *buf)
+{
+	int i;
+	u32 value;
+
+	ATL2_WRITE_REG(hw, REG_SPI_DATA, 0);
+	ATL2_WRITE_REG(hw, REG_SPI_ADDR, addr);
+
+	value = SPI_FLASH_CTRL_WAIT_READY |
+		(CUSTOM_SPI_CS_SETUP & SPI_FLASH_CTRL_CS_SETUP_MASK) <<
+			SPI_FLASH_CTRL_CS_SETUP_SHIFT |
+		(CUSTOM_SPI_CLK_HI & SPI_FLASH_CTRL_CLK_HI_MASK) <<
+			SPI_FLASH_CTRL_CLK_HI_SHIFT |
+		(CUSTOM_SPI_CLK_LO & SPI_FLASH_CTRL_CLK_LO_MASK) <<
+			SPI_FLASH_CTRL_CLK_LO_SHIFT |
+		(CUSTOM_SPI_CS_HOLD & SPI_FLASH_CTRL_CS_HOLD_MASK) <<
+			SPI_FLASH_CTRL_CS_HOLD_SHIFT |
+		(CUSTOM_SPI_CS_HI & SPI_FLASH_CTRL_CS_HI_MASK) <<
+			SPI_FLASH_CTRL_CS_HI_SHIFT |
+		(0x1 & SPI_FLASH_CTRL_INS_MASK) << SPI_FLASH_CTRL_INS_SHIFT;
+
+	ATL2_WRITE_REG(hw, REG_SPI_FLASH_CTRL, value);
+
+	value |= SPI_FLASH_CTRL_START;
+
+	ATL2_WRITE_REG(hw, REG_SPI_FLASH_CTRL, value);
+
+	for (i = 0; i < 10; i++) {
+		msleep(1);
+		value = ATL2_READ_REG(hw, REG_SPI_FLASH_CTRL);
+		if (!(value & SPI_FLASH_CTRL_START))
+			break;
+	}
+
+	if (value & SPI_FLASH_CTRL_START)
+		return false;
+
+	*buf = ATL2_READ_REG(hw, REG_SPI_DATA);
+
+	return true;
+}
+
+/*
+ * get_permanent_address
+ * return 0 if get valid mac address,
+ */
+static int get_permanent_address(struct atl2_hw *hw)
+{
+	u32 Addr[2];
+	u32 i, Control;
+	u16 Register;
+	u8  EthAddr[NODE_ADDRESS_SIZE];
+	bool KeyValid;
+
+	if (is_valid_ether_addr(hw->perm_mac_addr))
+		return 0;
+
+	Addr[0] = 0;
+	Addr[1] = 0;
+
+	if (!atl2_check_eeprom_exist(hw)) { /* eeprom exists */
+		Register = 0;
+		KeyValid = false;
+
+		/* Read out all EEPROM content */
+		i = 0;
+		while (1) {
+			if (atl2_read_eeprom(hw, i + 0x100, &Control)) {
+				if (KeyValid) {
+					if (Register == REG_MAC_STA_ADDR)
+						Addr[0] = Control;
+					else if (Register ==
+						(REG_MAC_STA_ADDR + 4))
+						Addr[1] = Control;
+					KeyValid = false;
+				} else if ((Control & 0xff) == 0x5A) {
+					KeyValid = true;
+					Register = (u16) (Control >> 16);
+				} else {
+			/* assume data end while encount an invalid KEYWORD */
+					break;
+				}
+			} else {
+				break; /* read error */
+			}
+			i += 4;
+		}
+
+		*(u32 *) &EthAddr[2] = LONGSWAP(Addr[0]);
+		*(u16 *) &EthAddr[0] = SHORTSWAP(*(u16 *) &Addr[1]);
+
+		if (is_valid_ether_addr(EthAddr)) {
+			memcpy(hw->perm_mac_addr, EthAddr, NODE_ADDRESS_SIZE);
+			return 0;
+		}
+		return 1;
+	}
+
+	/* see if SPI flash exists? */
+	Addr[0] = 0;
+	Addr[1] = 0;
+	Register = 0;
+	KeyValid = false;
+	i = 0;
+	while (1) {
+		if (atl2_spi_read(hw, i + 0x1f000, &Control)) {
+			if (KeyValid) {
+				if (Register == REG_MAC_STA_ADDR)
+					Addr[0] = Control;
+				else if (Register == (REG_MAC_STA_ADDR + 4))
+					Addr[1] = Control;
+				KeyValid = false;
+			} else if ((Control & 0xff) == 0x5A) {
+				KeyValid = true;
+				Register = (u16) (Control >> 16);
+			} else {
+				break; /* data end */
+			}
+		} else {
+			break; /* read error */
+		}
+		i += 4;
+	}
+
+	*(u32 *) &EthAddr[2] = LONGSWAP(Addr[0]);
+	*(u16 *) &EthAddr[0] = SHORTSWAP(*(u16 *)&Addr[1]);
+	if (is_valid_ether_addr(EthAddr)) {
+		memcpy(hw->perm_mac_addr, EthAddr, NODE_ADDRESS_SIZE);
+		return 0;
+	}
+	/* maybe MAC-address is from BIOS */
+	Addr[0] = ATL2_READ_REG(hw, REG_MAC_STA_ADDR);
+	Addr[1] = ATL2_READ_REG(hw, REG_MAC_STA_ADDR + 4);
+	*(u32 *) &EthAddr[2] = LONGSWAP(Addr[0]);
+	*(u16 *) &EthAddr[0] = SHORTSWAP(*(u16 *) &Addr[1]);
+
+	if (is_valid_ether_addr(EthAddr)) {
+		memcpy(hw->perm_mac_addr, EthAddr, NODE_ADDRESS_SIZE);
+		return 0;
+	}
+
+	return 1;
+}
+
+/*
+ * Reads the adapter's MAC address from the EEPROM
+ *
+ * hw - Struct containing variables accessed by shared code
+ */
+static s32 atl2_read_mac_addr(struct atl2_hw *hw)
+{
+	u16 i;
+
+	if (get_permanent_address(hw)) {
+		/* for test */
+		/* FIXME: shouldn't we use random_ether_addr() here? */
+		hw->perm_mac_addr[0] = 0x00;
+		hw->perm_mac_addr[1] = 0x13;
+		hw->perm_mac_addr[2] = 0x74;
+		hw->perm_mac_addr[3] = 0x00;
+		hw->perm_mac_addr[4] = 0x5c;
+		hw->perm_mac_addr[5] = 0x38;
+	}
+
+	for (i = 0; i < NODE_ADDRESS_SIZE; i++)
+		hw->mac_addr[i] = hw->perm_mac_addr[i];
+
+	return 0;
+}
+
+/*
+ * Hashes an address to determine its location in the multicast table
+ *
+ * hw - Struct containing variables accessed by shared code
+ * mc_addr - the multicast address to hash
+ *
+ * atl2_hash_mc_addr
+ *  purpose
+ *      set hash value for a multicast address
+ *      hash calcu processing :
+ *          1. calcu 32bit CRC for multicast address
+ *          2. reverse crc with MSB to LSB
+ */
+static u32 atl2_hash_mc_addr(struct atl2_hw *hw, u8 *mc_addr)
+{
+	u32 crc32, value;
+	int i;
+
+	value = 0;
+	crc32 = ether_crc_le(6, mc_addr);
+
+	for (i = 0; i < 32; i++)
+		value |= (((crc32 >> i) & 1) << (31 - i));
+
+	return value;
+}
+
+/*
+ * Sets the bit in the multicast table corresponding to the hash value.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * hash_value - Multicast address hash value
+ */
+static void atl2_hash_set(struct atl2_hw *hw, u32 hash_value)
+{
+	u32 hash_bit, hash_reg;
+	u32 mta;
+
+	/* The HASH Table  is a register array of 2 32-bit registers.
+	 * It is treated like an array of 64 bits.  We want to set
+	 * bit BitArray[hash_value]. So we figure out what register
+	 * the bit is in, read it, OR in the new bit, then write
+	 * back the new value.  The register is determined by the
+	 * upper 7 bits of the hash value and the bit within that
+	 * register are determined by the lower 5 bits of the value.
+	 */
+	hash_reg = (hash_value >> 31) & 0x1;
+	hash_bit = (hash_value >> 26) & 0x1F;
+
+	mta = ATL2_READ_REG_ARRAY(hw, REG_RX_HASH_TABLE, hash_reg);
+
+	mta |= (1 << hash_bit);
+
+	ATL2_WRITE_REG_ARRAY(hw, REG_RX_HASH_TABLE, hash_reg, mta);
+}
+
+/*
+ * atl2_init_pcie - init PCIE module
+ */
+static void atl2_init_pcie(struct atl2_hw *hw)
+{
+    u32 value;
+    value = LTSSM_TEST_MODE_DEF;
+    ATL2_WRITE_REG(hw, REG_LTSSM_TEST_MODE, value);
+
+    value = PCIE_DLL_TX_CTRL1_DEF;
+    ATL2_WRITE_REG(hw, REG_PCIE_DLL_TX_CTRL1, value);
+}
+
+static void atl2_init_flash_opcode(struct atl2_hw *hw)
+{
+	if (hw->flash_vendor >= ARRAY_SIZE(flash_table))
+		hw->flash_vendor = 0; /* ATMEL */
+
+	/* Init OP table */
+	ATL2_WRITE_REGB(hw, REG_SPI_FLASH_OP_PROGRAM,
+		flash_table[hw->flash_vendor].cmdPROGRAM);
+	ATL2_WRITE_REGB(hw, REG_SPI_FLASH_OP_SC_ERASE,
+		flash_table[hw->flash_vendor].cmdSECTOR_ERASE);
+	ATL2_WRITE_REGB(hw, REG_SPI_FLASH_OP_CHIP_ERASE,
+		flash_table[hw->flash_vendor].cmdCHIP_ERASE);
+	ATL2_WRITE_REGB(hw, REG_SPI_FLASH_OP_RDID,
+		flash_table[hw->flash_vendor].cmdRDID);
+	ATL2_WRITE_REGB(hw, REG_SPI_FLASH_OP_WREN,
+		flash_table[hw->flash_vendor].cmdWREN);
+	ATL2_WRITE_REGB(hw, REG_SPI_FLASH_OP_RDSR,
+		flash_table[hw->flash_vendor].cmdRDSR);
+	ATL2_WRITE_REGB(hw, REG_SPI_FLASH_OP_WRSR,
+		flash_table[hw->flash_vendor].cmdWRSR);
+	ATL2_WRITE_REGB(hw, REG_SPI_FLASH_OP_READ,
+		flash_table[hw->flash_vendor].cmdREAD);
+}
+
+/********************************************************************
+* Performs basic configuration of the adapter.
+*
+* hw - Struct containing variables accessed by shared code
+* Assumes that the controller has previously been reset and is in a
+* post-reset uninitialized state. Initializes multicast table,
+* and  Calls routines to setup link
+* Leaves the transmit and receive units disabled and uninitialized.
+********************************************************************/
+static s32 atl2_init_hw(struct atl2_hw *hw)
+{
+	u32 ret_val = 0;
+
+	atl2_init_pcie(hw);
+
+	/* Zero out the Multicast HASH table */
+	/* clear the old settings from the multicast hash table */
+	ATL2_WRITE_REG(hw, REG_RX_HASH_TABLE, 0);
+	ATL2_WRITE_REG_ARRAY(hw, REG_RX_HASH_TABLE, 1, 0);
+
+	atl2_init_flash_opcode(hw);
+
+	ret_val = atl2_phy_init(hw);
+
+	return ret_val;
+}
+
+/*
+ * Detects the current speed and duplex settings of the hardware.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * speed - Speed of the connection
+ * duplex - Duplex setting of the connection
+ */
+static s32 atl2_get_speed_and_duplex(struct atl2_hw *hw, u16 *speed,
+	u16 *duplex)
+{
+	s32 ret_val;
+	u16 phy_data;
+
+	/* Read PHY Specific Status Register (17) */
+	ret_val = atl2_read_phy_reg(hw, MII_ATLX_PSSR, &phy_data);
+	if (ret_val)
+		return ret_val;
+
+	if (!(phy_data & MII_ATLX_PSSR_SPD_DPLX_RESOLVED))
+		return ATLX_ERR_PHY_RES;
+
+	switch (phy_data & MII_ATLX_PSSR_SPEED) {
+	case MII_ATLX_PSSR_100MBS:
+		*speed = SPEED_100;
+		break;
+	case MII_ATLX_PSSR_10MBS:
+		*speed = SPEED_10;
+		break;
+	default:
+		return ATLX_ERR_PHY_SPEED;
+		break;
+	}
+
+	if (phy_data & MII_ATLX_PSSR_DPLX)
+		*duplex = FULL_DUPLEX;
+	else
+		*duplex = HALF_DUPLEX;
+
+	return 0;
+}
+
+/*
+ * Reads the value from a PHY register
+ * hw - Struct containing variables accessed by shared code
+ * reg_addr - address of the PHY register to read
+ */
+static s32 atl2_read_phy_reg(struct atl2_hw *hw, u16 reg_addr, u16 *phy_data)
+{
+	u32 val;
+	int i;
+
+	val = ((u32)(reg_addr & MDIO_REG_ADDR_MASK)) << MDIO_REG_ADDR_SHIFT |
+		MDIO_START |
+		MDIO_SUP_PREAMBLE |
+		MDIO_RW |
+		MDIO_CLK_25_4 << MDIO_CLK_SEL_SHIFT;
+	ATL2_WRITE_REG(hw, REG_MDIO_CTRL, val);
+
+	wmb();
+
+	for (i = 0; i < MDIO_WAIT_TIMES; i++) {
+		udelay(2);
+		val = ATL2_READ_REG(hw, REG_MDIO_CTRL);
+		if (!(val & (MDIO_START | MDIO_BUSY)))
+			break;
+		wmb();
+	}
+	if (!(val & (MDIO_START | MDIO_BUSY))) {
+		*phy_data = (u16)val;
+		return 0;
+	}
+
+	return ATLX_ERR_PHY;
+}
+
+/*
+ * Writes a value to a PHY register
+ * hw - Struct containing variables accessed by shared code
+ * reg_addr - address of the PHY register to write
+ * data - data to write to the PHY
+ */
+static s32 atl2_write_phy_reg(struct atl2_hw *hw, u32 reg_addr, u16 phy_data)
+{
+	int i;
+	u32 val;
+
+	val = ((u32)(phy_data & MDIO_DATA_MASK)) << MDIO_DATA_SHIFT |
+		(reg_addr & MDIO_REG_ADDR_MASK) << MDIO_REG_ADDR_SHIFT |
+		MDIO_SUP_PREAMBLE |
+		MDIO_START |
+		MDIO_CLK_25_4 << MDIO_CLK_SEL_SHIFT;
+	ATL2_WRITE_REG(hw, REG_MDIO_CTRL, val);
+
+	wmb();
+
+	for (i = 0; i < MDIO_WAIT_TIMES; i++) {
+		udelay(2);
+		val = ATL2_READ_REG(hw, REG_MDIO_CTRL);
+		if (!(val & (MDIO_START | MDIO_BUSY)))
+			break;
+
+		wmb();
+	}
+
+	if (!(val & (MDIO_START | MDIO_BUSY)))
+		return 0;
+
+	return ATLX_ERR_PHY;
+}
+
+/*
+ * Configures PHY autoneg and flow control advertisement settings
+ *
+ * hw - Struct containing variables accessed by shared code
+ */
+static s32 atl2_phy_setup_autoneg_adv(struct atl2_hw *hw)
+{
+	s32 ret_val;
+	s16 mii_autoneg_adv_reg;
+
+	/* Read the MII Auto-Neg Advertisement Register (Address 4). */
+	mii_autoneg_adv_reg = MII_AR_DEFAULT_CAP_MASK;
+
+	/* Need to parse autoneg_advertised  and set up
+	 * the appropriate PHY registers.  First we will parse for
+	 * autoneg_advertised software override.  Since we can advertise
+	 * a plethora of combinations, we need to check each bit
+	 * individually.
+	 */
+
+	/* First we clear all the 10/100 mb speed bits in the Auto-Neg
+	 * Advertisement Register (Address 4) and the 1000 mb speed bits in
+	 * the  1000Base-T Control Register (Address 9). */
+	mii_autoneg_adv_reg &= ~MII_AR_SPEED_MASK;
+
+	/* Need to parse MediaType and setup the
+	 * appropriate PHY registers. */
+	switch (hw->MediaType) {
+	case MEDIA_TYPE_AUTO_SENSOR:
+		mii_autoneg_adv_reg |=
+			(MII_AR_10T_HD_CAPS |
+			MII_AR_10T_FD_CAPS  |
+			MII_AR_100TX_HD_CAPS|
+			MII_AR_100TX_FD_CAPS);
+		hw->autoneg_advertised =
+			ADVERTISE_10_HALF |
+			ADVERTISE_10_FULL |
+			ADVERTISE_100_HALF|
+			ADVERTISE_100_FULL;
+		break;
+	case MEDIA_TYPE_100M_FULL:
+		mii_autoneg_adv_reg |= MII_AR_100TX_FD_CAPS;
+		hw->autoneg_advertised = ADVERTISE_100_FULL;
+		break;
+	case MEDIA_TYPE_100M_HALF:
+		mii_autoneg_adv_reg |= MII_AR_100TX_HD_CAPS;
+		hw->autoneg_advertised = ADVERTISE_100_HALF;
+		break;
+	case MEDIA_TYPE_10M_FULL:
+		mii_autoneg_adv_reg |= MII_AR_10T_FD_CAPS;
+		hw->autoneg_advertised = ADVERTISE_10_FULL;
+		break;
+	default:
+		mii_autoneg_adv_reg |= MII_AR_10T_HD_CAPS;
+		hw->autoneg_advertised = ADVERTISE_10_HALF;
+		break;
+	}
+
+	/* flow control fixed to enable all */
+	mii_autoneg_adv_reg |= (MII_AR_ASM_DIR | MII_AR_PAUSE);
+
+	hw->mii_autoneg_adv_reg = mii_autoneg_adv_reg;
+
+	ret_val = atl2_write_phy_reg(hw, MII_ADVERTISE, mii_autoneg_adv_reg);
+
+	if (ret_val)
+		return ret_val;
+
+	return 0;
+}
+
+/*
+ * Resets the PHY and make all config validate
+ *
+ * hw - Struct containing variables accessed by shared code
+ *
+ * Sets bit 15 and 12 of the MII Control regiser (for F001 bug)
+ */
+static s32 atl2_phy_commit(struct atl2_hw *hw)
+{
+	s32 ret_val;
+	u16 phy_data;
+
+	phy_data = MII_CR_RESET | MII_CR_AUTO_NEG_EN | MII_CR_RESTART_AUTO_NEG;
+	ret_val = atl2_write_phy_reg(hw, MII_BMCR, phy_data);
+	if (ret_val) {
+		u32 val;
+		int i;
+		/* pcie serdes link may be down ! */
+		for (i = 0; i < 25; i++) {
+			msleep(1);
+			val = ATL2_READ_REG(hw, REG_MDIO_CTRL);
+			if (!(val & (MDIO_START | MDIO_BUSY)))
+				break;
+		}
+
+		if (0 != (val & (MDIO_START | MDIO_BUSY))) {
+			printk(KERN_ERR "atl2: PCIe link down for at least 25ms !\n");
+			return ret_val;
+		}
+	}
+	return 0;
+}
+
+static s32 atl2_phy_init(struct atl2_hw *hw)
+{
+	s32 ret_val;
+	u16 phy_val;
+
+	if (hw->phy_configured)
+		return 0;
+
+	/* Enable PHY */
+	ATL2_WRITE_REGW(hw, REG_PHY_ENABLE, 1);
+	ATL2_WRITE_FLUSH(hw);
+	msleep(1);
+
+	/* check if the PHY is in powersaving mode */
+	atl2_write_phy_reg(hw, MII_DBG_ADDR, 0);
+	atl2_read_phy_reg(hw, MII_DBG_DATA, &phy_val);
+
+	/* 024E / 124E 0r 0274 / 1274 ? */
+	if (phy_val & 0x1000) {
+		phy_val &= ~0x1000;
+		atl2_write_phy_reg(hw, MII_DBG_DATA, phy_val);
+	}
+
+	msleep(1);
+
+	/*Enable PHY LinkChange Interrupt */
+	ret_val = atl2_write_phy_reg(hw, 18, 0xC00);
+	if (ret_val)
+		return ret_val;
+
+	/* setup AutoNeg parameters */
+	ret_val = atl2_phy_setup_autoneg_adv(hw);
+	if (ret_val)
+		return ret_val;
+
+	/* SW.Reset & En-Auto-Neg to restart Auto-Neg */
+	ret_val = atl2_phy_commit(hw);
+	if (ret_val)
+		return ret_val;
+
+	hw->phy_configured = true;
+
+	return ret_val;
+}
+
+static void atl2_set_mac_addr(struct atl2_hw *hw)
+{
+	u32 value;
+	/* 00-0B-6A-F6-00-DC
+	 * 0:  6AF600DC   1: 000B
+	 * low dword */
+	value = (((u32)hw->mac_addr[2]) << 24) |
+		(((u32)hw->mac_addr[3]) << 16) |
+		(((u32)hw->mac_addr[4]) << 8)  |
+		(((u32)hw->mac_addr[5]));
+	ATL2_WRITE_REG_ARRAY(hw, REG_MAC_STA_ADDR, 0, value);
+	/* hight dword */
+	value = (((u32)hw->mac_addr[0]) << 8) |
+		(((u32)hw->mac_addr[1]));
+	ATL2_WRITE_REG_ARRAY(hw, REG_MAC_STA_ADDR, 1, value);
+}
+
+/*
+ * check_eeprom_exist
+ * return 0 if eeprom exist
+ */
+static int atl2_check_eeprom_exist(struct atl2_hw *hw)
+{
+	u32 value;
+
+	value = ATL2_READ_REG(hw, REG_SPI_FLASH_CTRL);
+	if (value & SPI_FLASH_CTRL_EN_VPD) {
+		value &= ~SPI_FLASH_CTRL_EN_VPD;
+		ATL2_WRITE_REG(hw, REG_SPI_FLASH_CTRL, value);
+	}
+	value = ATL2_READ_REGW(hw, REG_PCIE_CAP_LIST);
+	return ((value & 0xFF00) == 0x6C00) ? 0 : 1;
+}
+
+/* FIXME: This doesn't look right. -- CHS */
+static bool atl2_write_eeprom(struct atl2_hw *hw, u32 offset, u32 value)
+{
+	return true;
+}
+
+static bool atl2_read_eeprom(struct atl2_hw *hw, u32 Offset, u32 *pValue)
+{
+	int i;
+	u32    Control;
+
+	if (Offset & 0x3)
+		return false; /* address do not align */
+
+	ATL2_WRITE_REG(hw, REG_VPD_DATA, 0);
+	Control = (Offset & VPD_CAP_VPD_ADDR_MASK) << VPD_CAP_VPD_ADDR_SHIFT;
+	ATL2_WRITE_REG(hw, REG_VPD_CAP, Control);
+
+	for (i = 0; i < 10; i++) {
+		msleep(2);
+		Control = ATL2_READ_REG(hw, REG_VPD_CAP);
+		if (Control & VPD_CAP_VPD_FLAG)
+			break;
+	}
+
+	if (Control & VPD_CAP_VPD_FLAG) {
+		*pValue = ATL2_READ_REG(hw, REG_VPD_DATA);
+		return true;
+	}
+	return false; /* timeout */
+}
+
+static void atl2_force_ps(struct atl2_hw *hw)
+{
+	u16 phy_val;
+
+	atl2_write_phy_reg(hw, MII_DBG_ADDR, 0);
+	atl2_read_phy_reg(hw, MII_DBG_DATA, &phy_val);
+	atl2_write_phy_reg(hw, MII_DBG_DATA, phy_val | 0x1000);
+
+	atl2_write_phy_reg(hw, MII_DBG_ADDR, 2);
+	atl2_write_phy_reg(hw, MII_DBG_DATA, 0x3000);
+	atl2_write_phy_reg(hw, MII_DBG_ADDR, 3);
+	atl2_write_phy_reg(hw, MII_DBG_DATA, 0);
+}
+
+/* This is the only thing that needs to be changed to adjust the
+ * maximum number of ports that the driver can manage.
+ */
+#define ATL2_MAX_NIC 4
+
+#define OPTION_UNSET    -1
+#define OPTION_DISABLED 0
+#define OPTION_ENABLED  1
+
+/* All parameters are treated the same, as an integer array of values.
+ * This macro just reduces the need to repeat the same declaration code
+ * over and over (plus this helps to avoid typo bugs).
+ */
+#define ATL2_PARAM_INIT {[0 ... ATL2_MAX_NIC] = OPTION_UNSET}
+#ifndef module_param_array
+/* Module Parameters are always initialized to -1, so that the driver
+ * can tell the difference between no user specified value or the
+ * user asking for the default value.
+ * The true default values are loaded in when atl2_check_options is called.
+ *
+ * This is a GCC extension to ANSI C.
+ * See the item "Labeled Elements in Initializers" in the section
+ * "Extensions to the C Language Family" of the GCC documentation.
+ */
+
+#define ATL2_PARAM(X, desc) \
+    static const int __devinitdata X[ATL2_MAX_NIC + 1] = ATL2_PARAM_INIT; \
+    MODULE_PARM(X, "1-" __MODULE_STRING(ATL2_MAX_NIC) "i"); \
+    MODULE_PARM_DESC(X, desc);
+#else
+#define ATL2_PARAM(X, desc) \
+    static int __devinitdata X[ATL2_MAX_NIC+1] = ATL2_PARAM_INIT; \
+    static int num_##X = 0; \
+    module_param_array_named(X, X, int, &num_##X, 0); \
+    MODULE_PARM_DESC(X, desc);
+#endif
+
+/*
+ * Transmit Memory Size
+ * Valid Range: 64-2048
+ * Default Value: 128
+ */
+#define ATL2_MIN_TX_MEMSIZE		4	/* 4KB */
+#define ATL2_MAX_TX_MEMSIZE		64	/* 64KB */
+#define ATL2_DEFAULT_TX_MEMSIZE		8	/* 8KB */
+ATL2_PARAM(TxMemSize, "Bytes of Transmit Memory");
+
+/*
+ * Receive Memory Block Count
+ * Valid Range: 16-512
+ * Default Value: 128
+ */
+#define ATL2_MIN_RXD_COUNT		16
+#define ATL2_MAX_RXD_COUNT		512
+#define ATL2_DEFAULT_RXD_COUNT		64
+ATL2_PARAM(RxMemBlock, "Number of receive memory block");
+
+/*
+ * User Specified MediaType Override
+ *
+ * Valid Range: 0-5
+ *  - 0    - auto-negotiate at all supported speeds
+ *  - 1    - only link at 1000Mbps Full Duplex
+ *  - 2    - only link at 100Mbps Full Duplex
+ *  - 3    - only link at 100Mbps Half Duplex
+ *  - 4    - only link at 10Mbps Full Duplex
+ *  - 5    - only link at 10Mbps Half Duplex
+ * Default Value: 0
+ */
+ATL2_PARAM(MediaType, "MediaType Select");
+
+/*
+ * Interrupt Moderate Timer in units of 2048 ns (~2 us)
+ * Valid Range: 10-65535
+ * Default Value: 45000(90ms)
+ */
+#define INT_MOD_DEFAULT_CNT	100 /* 200us */
+#define INT_MOD_MAX_CNT		65000
+#define INT_MOD_MIN_CNT		50
+ATL2_PARAM(IntModTimer, "Interrupt Moderator Timer");
+
+/*
+ * FlashVendor
+ * Valid Range: 0-2
+ * 0 - Atmel
+ * 1 - SST
+ * 2 - ST
+ */
+ATL2_PARAM(FlashVendor, "SPI Flash Vendor");
+
+#define AUTONEG_ADV_DEFAULT	0x2F
+#define AUTONEG_ADV_MASK	0x2F
+#define FLOW_CONTROL_DEFAULT	FLOW_CONTROL_FULL
+
+#define FLASH_VENDOR_DEFAULT	0
+#define FLASH_VENDOR_MIN	0
+#define FLASH_VENDOR_MAX	2
+
+struct atl2_option {
+	enum { enable_option, range_option, list_option } type;
+	char *name;
+	char *err;
+	int  def;
+	union {
+		struct { /* range_option info */
+			int min;
+			int max;
+		} r;
+		struct { /* list_option info */
+			int nr;
+			struct atl2_opt_list { int i; char *str; } *p;
+		} l;
+	} arg;
+};
+
+static int __devinit atl2_validate_option(int *value, struct atl2_option *opt)
+{
+	int i;
+	struct atl2_opt_list *ent;
+
+	if (*value == OPTION_UNSET) {
+		*value = opt->def;
+		return 0;
+	}
+
+	switch (opt->type) {
+	case enable_option:
+		switch (*value) {
+		case OPTION_ENABLED:
+			printk(KERN_INFO "%s Enabled\n", opt->name);
+			return 0;
+			break;
+		case OPTION_DISABLED:
+			printk(KERN_INFO "%s Disabled\n", opt->name);
+			return 0;
+			break;
+		}
+		break;
+	case range_option:
+		if (*value >= opt->arg.r.min && *value <= opt->arg.r.max) {
+			printk(KERN_INFO "%s set to %i\n", opt->name, *value);
+			return 0;
+		}
+		break;
+	case list_option:
+		for (i = 0; i < opt->arg.l.nr; i++) {
+			ent = &opt->arg.l.p[i];
+			if (*value == ent->i) {
+				if (ent->str[0] != '\0')
+					printk(KERN_INFO "%s\n", ent->str);
+			return 0;
+			}
+		}
+		break;
+	default:
+		BUG();
+	}
+
+	printk(KERN_INFO "Invalid %s specified (%i) %s\n",
+		opt->name, *value, opt->err);
+	*value = opt->def;
+	return -1;
+}
+
+/*
+ * atl2_check_options - Range Checking for Command Line Parameters
+ * @adapter: board private structure
+ *
+ * This routine checks all command line parameters for valid user
+ * input.  If an invalid value is given, or if no user specified
+ * value exists, a default value is used.  The final value is stored
+ * in a variable in the adapter structure.
+ */
+static void __devinit atl2_check_options(struct atl2_adapter *adapter)
+{
+	int val;
+	struct atl2_option opt;
+	int bd = adapter->bd_number;
+	if (bd >= ATL2_MAX_NIC) {
+		printk(KERN_NOTICE "Warning: no configuration for board #%i\n",
+			bd);
+		printk(KERN_NOTICE "Using defaults for all values\n");
+#ifndef module_param_array
+		bd = ATL2_MAX_NIC;
+#endif
+	}
+
+	/* Bytes of Transmit Memory */
+	opt.type = range_option;
+	opt.name = "Bytes of Transmit Memory";
+	opt.err = "using default of " __MODULE_STRING(ATL2_DEFAULT_TX_MEMSIZE);
+	opt.def = ATL2_DEFAULT_TX_MEMSIZE;
+	opt.arg.r.min = ATL2_MIN_TX_MEMSIZE;
+	opt.arg.r.max = ATL2_MAX_TX_MEMSIZE;
+#ifdef module_param_array
+	if (num_TxMemSize > bd) {
+#endif
+		val = TxMemSize[bd];
+		atl2_validate_option(&val, &opt);
+		adapter->txd_ring_size = ((u32) val) * 1024;
+#ifdef module_param_array
+	} else
+		adapter->txd_ring_size = ((u32)opt.def) * 1024;
+#endif
+	/* txs ring size: */
+	adapter->txs_ring_size = adapter->txd_ring_size / 128;
+	if (adapter->txs_ring_size > 160)
+		adapter->txs_ring_size = 160;
+
+	/* Receive Memory Block Count */
+	opt.type = range_option;
+	opt.name = "Number of receive memory block";
+	opt.err = "using default of " __MODULE_STRING(ATL2_DEFAULT_RXD_COUNT);
+	opt.def = ATL2_DEFAULT_RXD_COUNT;
+	opt.arg.r.min = ATL2_MIN_RXD_COUNT;
+	opt.arg.r.max = ATL2_MAX_RXD_COUNT;
+#ifdef module_param_array
+	if (num_RxMemBlock > bd) {
+#endif
+		val = RxMemBlock[bd];
+		atl2_validate_option(&val, &opt);
+		adapter->rxd_ring_size = (u32)val;
+		/* FIXME */
+		/* ((u16)val)&~1; */	/* even number */
+#ifdef module_param_array
+	} else
+		adapter->rxd_ring_size = (u32)opt.def;
+#endif
+	/* init RXD Flow control value */
+	adapter->hw.fc_rxd_hi = (adapter->rxd_ring_size / 8) * 7;
+	adapter->hw.fc_rxd_lo = (ATL2_MIN_RXD_COUNT / 8) >
+		(adapter->rxd_ring_size / 12) ? (ATL2_MIN_RXD_COUNT / 8) :
+		(adapter->rxd_ring_size / 12);
+
+	/* Interrupt Moderate Timer */
+	opt.type = range_option;
+	opt.name = "Interrupt Moderate Timer";
+	opt.err = "using default of " __MODULE_STRING(INT_MOD_DEFAULT_CNT);
+	opt.def = INT_MOD_DEFAULT_CNT;
+	opt.arg.r.min = INT_MOD_MIN_CNT;
+	opt.arg.r.max = INT_MOD_MAX_CNT;
+#ifdef module_param_array
+	if (num_IntModTimer > bd) {
+#endif
+		val = IntModTimer[bd];
+		atl2_validate_option(&val, &opt);
+		adapter->imt = (u16) val;
+#ifdef module_param_array
+	} else
+		adapter->imt = (u16)(opt.def);
+#endif
+	/* Flash Vendor */
+	opt.type = range_option;
+	opt.name = "SPI Flash Vendor";
+	opt.err = "using default of " __MODULE_STRING(FLASH_VENDOR_DEFAULT);
+	opt.def = FLASH_VENDOR_DEFAULT;
+	opt.arg.r.min = FLASH_VENDOR_MIN;
+	opt.arg.r.max = FLASH_VENDOR_MAX;
+#ifdef module_param_array
+	if (num_FlashVendor > bd) {
+#endif
+		val = FlashVendor[bd];
+		atl2_validate_option(&val, &opt);
+		adapter->hw.flash_vendor = (u8) val;
+#ifdef module_param_array
+	} else
+		adapter->hw.flash_vendor = (u8)(opt.def);
+#endif
+	/* MediaType */
+	opt.type = range_option;
+	opt.name = "Speed/Duplex Selection";
+	opt.err = "using default of " __MODULE_STRING(MEDIA_TYPE_AUTO_SENSOR);
+	opt.def = MEDIA_TYPE_AUTO_SENSOR;
+	opt.arg.r.min = MEDIA_TYPE_AUTO_SENSOR;
+	opt.arg.r.max = MEDIA_TYPE_10M_HALF;
+#ifdef module_param_array
+	if (num_MediaType > bd) {
+#endif
+		val = MediaType[bd];
+		atl2_validate_option(&val, &opt);
+		adapter->hw.MediaType = (u16) val;
+#ifdef module_param_array
+	} else
+		adapter->hw.MediaType = (u16)(opt.def);
+#endif
+}
diff --git a/drivers/net/atlx/atl2.h b/drivers/net/atlx/atl2.h
new file mode 100644
index 0000000..09974df
--- /dev/null
+++ b/drivers/net/atlx/atl2.h
@@ -0,0 +1,529 @@
+/* atl2.h -- atl2 driver definitions
+ *
+ * Copyright(c) 2007 Atheros Corporation. All rights reserved.
+ * Copyright(c) 2006 xiong huang <xiong.huang@atheros.com>
+ * Copyright(c) 2007 Chris Snook <csnook@redhat.com>
+ *
+ * Derived from Intel e1000 driver
+ * Copyright(c) 1999 - 2005 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#ifndef _ATL2_H_
+#define _ATL2_H_
+
+#include <asm/atomic.h>
+#include <linux/netdevice.h>
+
+#ifndef _ATL2_HW_H_
+#define _ATL2_HW_H_
+
+#ifndef _ATL2_OSDEP_H_
+#define _ATL2_OSDEP_H_
+
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/if_ether.h>
+
+#include "atlx.h"
+
+#ifdef ETHTOOL_OPS_COMPAT
+extern int ethtool_ioctl(struct ifreq *ifr);
+#endif
+
+#define PCI_COMMAND_REGISTER	PCI_COMMAND
+#define CMD_MEM_WRT_INVALIDATE	PCI_COMMAND_INVALIDATE
+#define ETH_ADDR_LEN		ETH_ALEN
+
+#define ATL2_WRITE_REG(a, reg, value) (iowrite32((value), \
+	((a)->hw_addr + (reg))))
+
+#define ATL2_WRITE_FLUSH(a) (ioread32((a)->hw_addr))
+
+#define ATL2_READ_REG(a, reg) (ioread32((a)->hw_addr + (reg)))
+
+#define ATL2_WRITE_REGB(a, reg, value) (iowrite8((value), \
+	((a)->hw_addr + (reg))))
+
+#define ATL2_READ_REGB(a, reg) (ioread8((a)->hw_addr + (reg)))
+
+#define ATL2_WRITE_REGW(a, reg, value) (iowrite16((value), \
+	((a)->hw_addr + (reg))))
+
+#define ATL2_READ_REGW(a, reg) (ioread16((a)->hw_addr + (reg)))
+
+#define ATL2_WRITE_REG_ARRAY(a, reg, offset, value) \
+	(iowrite32((value), (((a)->hw_addr + (reg)) + ((offset) << 2))))
+
+#define ATL2_READ_REG_ARRAY(a, reg, offset) \
+	(ioread32(((a)->hw_addr + (reg)) + ((offset) << 2)))
+
+#endif /* _ATL2_OSDEP_H_ */
+
+struct atl2_adapter;
+struct atl2_hw;
+
+/* function prototype */
+static s32 atl2_reset_hw(struct atl2_hw *hw);
+static s32 atl2_read_mac_addr(struct atl2_hw *hw);
+static s32 atl2_init_hw(struct atl2_hw *hw);
+static s32 atl2_get_speed_and_duplex(struct atl2_hw *hw, u16 *speed,
+	u16 *duplex);
+static u32 atl2_hash_mc_addr(struct atl2_hw *hw, u8 *mc_addr);
+static void atl2_hash_set(struct atl2_hw *hw, u32 hash_value);
+static s32 atl2_read_phy_reg(struct atl2_hw *hw, u16 reg_addr, u16 *phy_data);
+static s32 atl2_write_phy_reg(struct atl2_hw *hw, u32 reg_addr, u16 phy_data);
+static void atl2_read_pci_cfg(struct atl2_hw *hw, u32 reg, u16 *value);
+static void atl2_write_pci_cfg(struct atl2_hw *hw, u32 reg, u16 *value);
+static void atl2_set_mac_addr(struct atl2_hw *hw);
+static bool atl2_read_eeprom(struct atl2_hw *hw, u32 Offset, u32 *pValue);
+static bool atl2_write_eeprom(struct atl2_hw *hw, u32 offset, u32 value);
+static s32 atl2_phy_init(struct atl2_hw *hw);
+static int atl2_check_eeprom_exist(struct atl2_hw *hw);
+static void atl2_force_ps(struct atl2_hw *hw);
+
+/* register definition */
+
+/* Block IDLE Status Register */
+#define IDLE_STATUS_RXMAC	1	/* 1: RXMAC is non-IDLE */
+#define IDLE_STATUS_TXMAC	2	/* 1: TXMAC is non-IDLE */
+#define IDLE_STATUS_DMAR	8	/* 1: DMAR is non-IDLE */
+#define IDLE_STATUS_DMAW	4	/* 1: DMAW is non-IDLE */
+
+/* MDIO Control Register */
+#define MDIO_WAIT_TIMES		10
+
+/* MAC Control Register */
+#define MAC_CTRL_DBG_TX_BKPRESURE	0x100000	/* 1: TX max backoff */
+#define MAC_CTRL_MACLP_CLK_PHY		0x8000000	/* 1: 25MHz from phy */
+#define MAC_CTRL_HALF_LEFT_BUF_SHIFT	28
+#define MAC_CTRL_HALF_LEFT_BUF_MASK	0xF		/* MAC retry buf x32B */
+
+/* Internal SRAM Partition Register */
+#define REG_SRAM_TXRAM_END	0x1500	/* Internal tail address of TXRAM
+					 * default: 2byte*1024 */
+#define REG_SRAM_RXRAM_END	0x1502	/* Internal tail address of RXRAM
+					 * default: 2byte*1024 */
+
+/* Descriptor Control register */
+#define REG_TXD_BASE_ADDR_LO	0x1544	/* The base address of the Transmit
+					 * Data Mem low 32-bit(dword align) */
+#define REG_TXD_MEM_SIZE	0x1548	/* Transmit Data Memory size(by
+					 * double word , max 256KB) */
+#define REG_TXS_BASE_ADDR_LO	0x154C	/* The base address of the Transmit
+					 * Status Memory low 32-bit(dword word
+					 * align) */
+#define REG_TXS_MEM_SIZE	0x1550	/* double word unit, max 4*2047
+					 * bytes. */
+#define REG_RXD_BASE_ADDR_LO	0x1554	/* The base address of the Transmit
+					 * Status Memory low 32-bit(unit 8
+					 * bytes) */
+#define REG_RXD_BUF_NUM		0x1558	/* Receive Data & Status Memory buffer
+					 * number (unit 1536bytes, max
+					 * 1536*2047) */
+
+/* DMAR Control Register */
+#define REG_DMAR	0x1580
+#define     DMAR_EN	0x1	/* 1: Enable DMAR */
+
+/* TX Cur-Through (early tx threshold) Control Register */
+#define REG_TX_CUT_THRESH	0x1590	/* TxMac begin transmit packet
+					 * threshold(unit word) */
+
+/* DMAW Control Register */
+#define REG_DMAW	0x15A0
+#define     DMAW_EN	0x1
+
+/* Flow control register */
+#define REG_PAUSE_ON_TH		0x15A8	/* RXD high watermark of overflow
+					 * threshold configuration register */
+#define REG_PAUSE_OFF_TH	0x15AA	/* RXD lower watermark of overflow
+					 * threshold configuration register */
+
+/* Mailbox Register */
+#define REG_MB_TXD_WR_IDX	0x15f0	/* double word align */
+#define REG_MB_RXD_RD_IDX	0x15F4	/* RXD Read index (unit: 1536byets) */
+
+/* Interrupt Status Register */
+#define ISR_TIMER	1	/* Interrupt when Timer counts down to zero */
+#define ISR_MANUAL	2	/* Software manual interrupt, for debug. Set
+				 * when SW_MAN_INT_EN is set in Table 51
+				 * Selene Master Control Register
+				 * (Offset 0x1400). */
+#define ISR_RXF_OV	4	/* RXF overflow interrupt */
+#define ISR_TXF_UR	8	/* TXF underrun interrupt */
+#define ISR_TXS_OV	0x10	/* Internal transmit status buffer full
+				 * interrupt */
+#define ISR_RXS_OV	0x20	/* Internal receive status buffer full
+				 * interrupt */
+#define ISR_LINK_CHG	0x40	/* Link Status Change Interrupt */
+#define ISR_HOST_TXD_UR	0x80
+#define ISR_HOST_RXD_OV	0x100	/* Host rx data memory full , one pulse */
+#define ISR_DMAR_TO_RST	0x200	/* DMAR op timeout interrupt. SW should
+				 * do Reset */
+#define ISR_DMAW_TO_RST	0x400
+#define ISR_PHY		0x800	/* phy interrupt */
+#define ISR_TS_UPDATE	0x10000	/* interrupt after new tx pkt status written
+				 * to host */
+#define ISR_RS_UPDATE	0x20000	/* interrupt ater new rx pkt status written
+				 * to host. */
+#define ISR_TX_EARLY	0x40000	/* interrupt when txmac begin transmit one
+				 * packet */
+
+#define ISR_TX_EVENT (ISR_TXF_UR | ISR_TXS_OV | ISR_HOST_TXD_UR |\
+	ISR_TS_UPDATE | ISR_TX_EARLY)
+#define ISR_RX_EVENT (ISR_RXF_OV | ISR_RXS_OV | ISR_HOST_RXD_OV |\
+	 ISR_RS_UPDATE)
+
+#define IMR_NORMAL_MASK		(\
+	/*ISR_LINK_CHG		|*/\
+	ISR_MANUAL		|\
+	ISR_DMAR_TO_RST		|\
+	ISR_DMAW_TO_RST		|\
+	ISR_PHY			|\
+	ISR_PHY_LINKDOWN	|\
+	ISR_TS_UPDATE		|\
+	ISR_RS_UPDATE)
+
+/* Receive MAC Statistics Registers */
+#define REG_STS_RX_PAUSE	0x1700	/* Num pause packets received */
+#define REG_STS_RXD_OV		0x1704	/* Num frames dropped due to RX
+					 * FIFO overflow */
+#define REG_STS_RXS_OV		0x1708	/* Num frames dropped due to RX
+					 * Status Buffer Overflow */
+#define REG_STS_RX_FILTER	0x170C	/* Num packets dropped due to
+					 * address filtering */
+
+/* MII definitions */
+
+/* PHY Common Register */
+#define MII_SMARTSPEED	0x14
+#define MII_DBG_ADDR	0x1D
+#define MII_DBG_DATA	0x1E
+
+/* PCI Command Register Bit Definitions */
+#define PCI_REG_COMMAND		0x04
+#define CMD_IO_SPACE		0x0001
+#define CMD_MEMORY_SPACE	0x0002
+#define CMD_BUS_MASTER		0x0004
+
+#define MEDIA_TYPE_100M_FULL	1
+#define MEDIA_TYPE_100M_HALF	2
+#define MEDIA_TYPE_10M_FULL	3
+#define MEDIA_TYPE_10M_HALF	4
+
+#define AUTONEG_ADVERTISE_SPEED_DEFAULT	0x000F	/* Everything */
+
+/* The size (in bytes) of a ethernet packet */
+#define ENET_HEADER_SIZE		14
+#define MAXIMUM_ETHERNET_FRAME_SIZE	1518	/* with FCS */
+#define MINIMUM_ETHERNET_FRAME_SIZE	64	/* with FCS */
+#define ETHERNET_FCS_SIZE		4
+#define MAX_JUMBO_FRAME_SIZE		0x2000
+#define VLAN_SIZE                                               4
+
+struct tx_pkt_header {
+	unsigned pkt_size:11;
+	unsigned:4;			/* reserved */
+	unsigned ins_vlan:1;		/* txmac should insert vlan */
+	unsigned short vlan;		/* vlan tag */
+};
+/* FIXME: replace above bitfields with MASK/SHIFT defines below */
+#define TX_PKT_HEADER_SIZE_MASK		0x7FF
+#define TX_PKT_HEADER_SIZE_SHIFT	0
+#define TX_PKT_HEADER_INS_VLAN_MASK	0x1
+#define TX_PKT_HEADER_INS_VLAN_SHIFT	15
+#define TX_PKT_HEADER_VLAN_TAG_MASK	0xFFFF
+#define TX_PKT_HEADER_VLAN_TAG_SHIFT	16
+
+struct tx_pkt_status {
+	unsigned pkt_size:11;
+	unsigned:5;		/* reserved */
+	unsigned ok:1;		/* current packet transmitted without error */
+	unsigned bcast:1;	/* broadcast packet */
+	unsigned mcast:1;	/* multicast packet */
+	unsigned pause:1;	/* transmiited a pause frame */
+	unsigned ctrl:1;
+	unsigned defer:1;    	/* current packet is xmitted with defer */
+	unsigned exc_defer:1;
+	unsigned single_col:1;
+	unsigned multi_col:1;
+	unsigned late_col:1;
+	unsigned abort_col:1;
+	unsigned underun:1;	/* current packet is aborted
+				 * due to txram underrun */
+	unsigned:3;		/* reserved */
+	unsigned update:1;	/* always 1'b1 in tx_status_buf */
+};
+/* FIXME: replace above bitfields with MASK/SHIFT defines below */
+#define TX_PKT_STATUS_SIZE_MASK		0x7FF
+#define TX_PKT_STATUS_SIZE_SHIFT	0
+#define TX_PKT_STATUS_OK_MASK		0x1
+#define TX_PKT_STATUS_OK_SHIFT		16
+#define TX_PKT_STATUS_BCAST_MASK	0x1
+#define TX_PKT_STATUS_BCAST_SHIFT	17
+#define TX_PKT_STATUS_MCAST_MASK	0x1
+#define TX_PKT_STATUS_MCAST_SHIFT	18
+#define TX_PKT_STATUS_PAUSE_MASK	0x1
+#define TX_PKT_STATUS_PAUSE_SHIFT	19
+#define TX_PKT_STATUS_CTRL_MASK		0x1
+#define TX_PKT_STATUS_CTRL_SHIFT	20
+#define TX_PKT_STATUS_DEFER_MASK	0x1
+#define TX_PKT_STATUS_DEFER_SHIFT	21
+#define TX_PKT_STATUS_EXC_DEFER_MASK	0x1
+#define TX_PKT_STATUS_EXC_DEFER_SHIFT	22
+#define TX_PKT_STATUS_SINGLE_COL_MASK	0x1
+#define TX_PKT_STATUS_SINGLE_COL_SHIFT	23
+#define TX_PKT_STATUS_MULTI_COL_MASK	0x1
+#define TX_PKT_STATUS_MULTI_COL_SHIFT	24
+#define TX_PKT_STATUS_LATE_COL_MASK	0x1
+#define TX_PKT_STATUS_LATE_COL_SHIFT	25
+#define TX_PKT_STATUS_ABORT_COL_MASK	0x1
+#define TX_PKT_STATUS_ABORT_COL_SHIFT	26
+#define TX_PKT_STATUS_UNDERRUN_MASK	0x1
+#define TX_PKT_STATUS_UNDERRUN_SHIFT	27
+#define TX_PKT_STATUS_UPDATE_MASK	0x1
+#define TX_PKT_STATUS_UPDATE_SHIFT	31
+
+struct rx_pkt_status {
+	unsigned pkt_size:11;	/* packet size, max 2047 bytes */
+	unsigned:5;		/* reserved */
+	unsigned ok:1;		/* current packet received ok without error */
+	unsigned bcast:1;	/* current packet is broadcast */
+	unsigned mcast:1;	/* current packet is multicast */
+	unsigned pause:1;
+	unsigned ctrl:1;
+	unsigned crc:1;		/* received a packet with crc error */
+	unsigned code:1;	/* received a packet with code error */
+	unsigned runt:1;	/* received a packet less than 64 bytes
+				 * with good crc */
+	unsigned frag:1;	/* received a packet less than 64 bytes
+				 * with bad crc */
+	unsigned trunc:1;	/* current frame truncated due to rxram full */
+	unsigned align:1;	/* this packet is alignment error */
+	unsigned vlan:1;	/* this packet has vlan */
+	unsigned:3;		/* reserved */
+	unsigned update:1;
+	unsigned short vtag;	/* vlan tag */
+	unsigned:16;
+};
+/* FIXME: replace above bitfields with MASK/SHIFT defines below */
+#define RX_PKT_STATUS_SIZE_MASK		0x7FF
+#define RX_PKT_STATUS_SIZE_SHIFT	0
+#define RX_PKT_STATUS_OK_MASK		0x1
+#define RX_PKT_STATUS_OK_SHIFT		16
+#define RX_PKT_STATUS_BCAST_MASK	0x1
+#define RX_PKT_STATUS_BCAST_SHIFT	17
+#define RX_PKT_STATUS_MCAST_MASK	0x1
+#define RX_PKT_STATUS_MCAST_SHIFT	18
+#define RX_PKT_STATUS_PAUSE_MASK	0x1
+#define RX_PKT_STATUS_PAUSE_SHIFT	19
+#define RX_PKT_STATUS_CTRL_MASK		0x1
+#define RX_PKT_STATUS_CTRL_SHIFT	20
+#define RX_PKT_STATUS_CRC_MASK		0x1
+#define RX_PKT_STATUS_CRC_SHIFT		21
+#define RX_PKT_STATUS_CODE_MASK		0x1
+#define RX_PKT_STATUS_CODE_SHIFT	22
+#define RX_PKT_STATUS_RUNT_MASK		0x1
+#define RX_PKT_STATUS_RUNT_SHIFT	23
+#define RX_PKT_STATUS_FRAG_MASK		0x1
+#define RX_PKT_STATUS_FRAG_SHIFT	24
+#define RX_PKT_STATUS_TRUNK_MASK	0x1
+#define RX_PKT_STATUS_TRUNK_SHIFT	25
+#define RX_PKT_STATUS_ALIGN_MASK	0x1
+#define RX_PKT_STATUS_ALIGN_SHIFT	26
+#define RX_PKT_STATUS_VLAN_MASK		0x1
+#define RX_PKT_STATUS_VLAN_SHIFT	27
+#define RX_PKT_STATUS_UPDATE_MASK	0x1
+#define RX_PKT_STATUS_UPDATE_SHIFT	31
+#define RX_PKT_STATUS_VLAN_TAG_MASK	0xFFFF
+#define RX_PKT_STATUS_VLAN_TAG_SHIFT	32
+
+struct rx_desc {
+	struct rx_pkt_status	status;
+	unsigned char     	packet[1536-sizeof(struct rx_pkt_status)];
+};
+
+enum atl2_speed_duplex {
+	atl2_10_half = 0,
+	atl2_10_full = 1,
+	atl2_100_half = 2,
+	atl2_100_full = 3
+};
+
+struct atl2_spi_flash_dev {
+	const char *manu_name;	/* manufacturer id */
+	/* op-code */
+	u8 cmdWRSR;
+	u8 cmdREAD;
+	u8 cmdPROGRAM;
+	u8 cmdWREN;
+	u8 cmdWRDI;
+	u8 cmdRDSR;
+	u8 cmdRDID;
+	u8 cmdSECTOR_ERASE;
+	u8 cmdCHIP_ERASE;
+};
+
+/* Structure containing variables used by the shared code (atl2_hw.c) */
+struct atl2_hw {
+	u8 __iomem *hw_addr;
+	void *back;
+
+	u8 preamble_len;
+	u8 max_retry;          /* Retransmission maximum, afterwards the
+				* packet will be discarded. */
+	u8 jam_ipg;            /* IPG to start JAM for collision based flow
+				* control in half-duplex mode. In unit of
+				* 8-bit time. */
+	u8 ipgt;               /* Desired back to back inter-packet gap. The
+				* default is 96-bit time. */
+	u8 min_ifg;            /* Minimum number of IFG to enforce in between
+				* RX frames. Frame gap below such IFP is
+				* dropped. */
+	u8 ipgr1;              /* 64bit Carrier-Sense window */
+	u8 ipgr2;              /* 96-bit IPG window */
+	u8 retry_buf;          /* When half-duplex mode, should hold some
+				* bytes for mac retry . (8*4bytes unit) */
+
+	u16 fc_rxd_hi;
+	u16 fc_rxd_lo;
+	u16 lcol;              /* Collision Window */
+	u16 max_frame_size;
+
+	u16 MediaType;
+	u16 autoneg_advertised;
+	u16 pci_cmd_word;
+
+	u16 mii_autoneg_adv_reg;
+
+	u32 mem_rang;
+	u32 txcw;
+	u32 mc_filter_type;
+	u32 num_mc_addrs;
+	u32 collision_delta;
+	u32 tx_packet_delta;
+	u16 phy_spd_default;
+
+	u16 device_id;
+	u16 vendor_id;
+	u16 subsystem_id;
+	u16 subsystem_vendor_id;
+	u8 revision_id;
+
+	/* spi flash */
+	u8 flash_vendor;
+
+	u8 dma_fairness;
+	u8 mac_addr[NODE_ADDRESS_SIZE];
+	u8 perm_mac_addr[NODE_ADDRESS_SIZE];
+
+	/* FIXME */
+	/* bool phy_preamble_sup; */
+	bool phy_configured;
+};
+
+#endif /* _ATL2_HW_H_ */
+
+struct atl2_ring_header {
+    /* pointer to the descriptor ring memory */
+    void *desc;
+    /* physical adress of the descriptor ring */
+    dma_addr_t dma;
+    /* length of descriptor ring in bytes */
+    unsigned int size;
+};
+
+/* board specific private data structure */
+struct atl2_adapter {
+	/* OS defined structs */
+	struct net_device *netdev;
+	struct pci_dev *pdev;
+	struct net_device_stats net_stats;
+#ifdef NETIF_F_HW_VLAN_TX
+	struct vlan_group *vlgrp;
+#endif
+	u32 wol;
+	u16 link_speed;
+	u16 link_duplex;
+
+	spinlock_t stats_lock;
+
+	struct work_struct reset_task;
+	struct work_struct link_chg_task;
+	struct timer_list watchdog_timer;
+	struct timer_list phy_config_timer;
+
+	unsigned long cfg_phy;
+	bool mac_disabled;
+
+	/* All Descriptor memory */
+	dma_addr_t	ring_dma;
+	void		*ring_vir_addr;
+	int		ring_size;
+
+	struct tx_pkt_header	*txd_ring;
+	dma_addr_t	txd_dma;
+
+	struct tx_pkt_status	*txs_ring;
+	dma_addr_t	txs_dma;
+
+	struct rx_desc	*rxd_ring;
+	dma_addr_t	rxd_dma;
+
+	u32 txd_ring_size;         /* bytes per unit */
+	u32 txs_ring_size;         /* dwords per unit */
+	u32 rxd_ring_size;         /* 1536 bytes per unit */
+
+	/* read /write ptr: */
+	/* host */
+	u32 txd_write_ptr;
+	u32 txs_next_clear;
+	u32 rxd_read_ptr;
+
+	/* nic */
+	atomic_t txd_read_ptr;
+	atomic_t txs_write_ptr;
+	u32 rxd_write_ptr;
+
+	/* Interrupt Moderator timer ( 2us resolution) */
+	u16 imt;
+	/* Interrupt Clear timer (2us resolution) */
+	u16 ict;
+
+	unsigned long flags;
+	/* structs defined in atl2_hw.h */
+	u32 bd_number;     /* board number */
+	bool pci_using_64;
+	bool have_msi;
+	struct atl2_hw hw;
+
+	u32 usr_cmd;
+	/* FIXME */
+	/* u32 regs_buff[ATL2_REGS_LEN]; */
+	u32 pci_state[16];
+
+	u32 *config_space;
+};
+
+enum atl2_state_t {
+	__ATL2_TESTING,
+	__ATL2_RESETTING,
+	__ATL2_DOWN
+};
+
+#endif /* _ATL2_H_ */
diff --git a/drivers/net/atlx/atlx.c b/drivers/net/atlx/atlx.c
index b3e7fcf..3cc9d10 100644
--- a/drivers/net/atlx/atlx.c
+++ b/drivers/net/atlx/atlx.c
@@ -105,7 +105,6 @@
 				netdev->name);
 			adapter->link_speed = SPEED_0;
 			netif_carrier_off(netdev);
-			netif_stop_queue(netdev);
 		}
 	}
 	schedule_work(&adapter->link_chg_task);
diff --git a/drivers/net/au1000_eth.c b/drivers/net/au1000_eth.c
index 5ee1b05..019b13c 100644
--- a/drivers/net/au1000_eth.c
+++ b/drivers/net/au1000_eth.c
@@ -94,8 +94,8 @@
 static void au1000_tx_timeout(struct net_device *);
 static void set_rx_mode(struct net_device *);
 static int au1000_ioctl(struct net_device *, struct ifreq *, int);
-static int mdio_read(struct net_device *, int, int);
-static void mdio_write(struct net_device *, int, int, u16);
+static int au1000_mdio_read(struct net_device *, int, int);
+static void au1000_mdio_write(struct net_device *, int, int, u16);
 static void au1000_adjust_link(struct net_device *);
 static void enable_mac(struct net_device *, int);
 
@@ -191,7 +191,7 @@
 /*
  * MII operations
  */
-static int mdio_read(struct net_device *dev, int phy_addr, int reg)
+static int au1000_mdio_read(struct net_device *dev, int phy_addr, int reg)
 {
 	struct au1000_private *aup = (struct au1000_private *) dev->priv;
 	volatile u32 *const mii_control_reg = &aup->mac->mii_control;
@@ -225,7 +225,8 @@
 	return (int)*mii_data_reg;
 }
 
-static void mdio_write(struct net_device *dev, int phy_addr, int reg, u16 value)
+static void au1000_mdio_write(struct net_device *dev, int phy_addr,
+			      int reg, u16 value)
 {
 	struct au1000_private *aup = (struct au1000_private *) dev->priv;
 	volatile u32 *const mii_control_reg = &aup->mac->mii_control;
@@ -249,7 +250,7 @@
 	*mii_control_reg = mii_control;
 }
 
-static int mdiobus_read(struct mii_bus *bus, int phy_addr, int regnum)
+static int au1000_mdiobus_read(struct mii_bus *bus, int phy_addr, int regnum)
 {
 	/* WARNING: bus->phy_map[phy_addr].attached_dev == dev does
 	 * _NOT_ hold (e.g. when PHY is accessed through other MAC's MII bus) */
@@ -257,21 +258,21 @@
 
 	enable_mac(dev, 0); /* make sure the MAC associated with this
 			     * mii_bus is enabled */
-	return mdio_read(dev, phy_addr, regnum);
+	return au1000_mdio_read(dev, phy_addr, regnum);
 }
 
-static int mdiobus_write(struct mii_bus *bus, int phy_addr, int regnum,
-			 u16 value)
+static int au1000_mdiobus_write(struct mii_bus *bus, int phy_addr, int regnum,
+				u16 value)
 {
 	struct net_device *const dev = bus->priv;
 
 	enable_mac(dev, 0); /* make sure the MAC associated with this
 			     * mii_bus is enabled */
-	mdio_write(dev, phy_addr, regnum, value);
+	au1000_mdio_write(dev, phy_addr, regnum, value);
 	return 0;
 }
 
-static int mdiobus_reset(struct mii_bus *bus)
+static int au1000_mdiobus_reset(struct mii_bus *bus)
 {
 	struct net_device *const dev = bus->priv;
 
@@ -290,7 +291,7 @@
 
 	if(aup->mac_id == 0) { /* get PHY0 */
 # if defined(AU1XXX_PHY0_ADDR)
-		phydev = au_macs[AU1XXX_PHY0_BUSID]->mii_bus.phy_map[AU1XXX_PHY0_ADDR];
+		phydev = au_macs[AU1XXX_PHY0_BUSID]->mii_bus->phy_map[AU1XXX_PHY0_ADDR];
 # else
 		printk (KERN_INFO DRV_NAME ":%s: using PHY-less setup\n",
 			dev->name);
@@ -298,7 +299,7 @@
 # endif /* defined(AU1XXX_PHY0_ADDR) */
 	} else if (aup->mac_id == 1) { /* get PHY1 */
 # if defined(AU1XXX_PHY1_ADDR)
-		phydev = au_macs[AU1XXX_PHY1_BUSID]->mii_bus.phy_map[AU1XXX_PHY1_ADDR];
+		phydev = au_macs[AU1XXX_PHY1_BUSID]->mii_bus->phy_map[AU1XXX_PHY1_ADDR];
 # else
 		printk (KERN_INFO DRV_NAME ":%s: using PHY-less setup\n",
 			dev->name);
@@ -311,8 +312,8 @@
 
 	/* find the first (lowest address) PHY on the current MAC's MII bus */
 	for (phy_addr = 0; phy_addr < PHY_MAX_ADDR; phy_addr++)
-		if (aup->mii_bus.phy_map[phy_addr]) {
-			phydev = aup->mii_bus.phy_map[phy_addr];
+		if (aup->mii_bus->phy_map[phy_addr]) {
+			phydev = aup->mii_bus->phy_map[phy_addr];
 # if !defined(AU1XXX_PHY_SEARCH_HIGHEST_ADDR)
 			break; /* break out with first one found */
 # endif
@@ -331,7 +332,7 @@
 		 * the MAC0 MII bus */
 		for (phy_addr = 0; phy_addr < PHY_MAX_ADDR; phy_addr++) {
 			struct phy_device *const tmp_phydev =
-				au_macs[0]->mii_bus.phy_map[phy_addr];
+				au_macs[0]->mii_bus->phy_map[phy_addr];
 
 			if (!tmp_phydev)
 				continue; /* no PHY here... */
@@ -653,6 +654,8 @@
 
 	aup = dev->priv;
 
+	spin_lock_init(&aup->lock);
+
 	/* Allocate the data buffers */
 	/* Snooping works fine with eth on all au1xxx */
 	aup->vaddr = (u32)dma_alloc_noncoherent(NULL, MAX_BUF_SIZE *
@@ -696,28 +699,32 @@
 	*aup->enable = 0;
 	aup->mac_enabled = 0;
 
-	aup->mii_bus.priv = dev;
-	aup->mii_bus.read = mdiobus_read;
-	aup->mii_bus.write = mdiobus_write;
-	aup->mii_bus.reset = mdiobus_reset;
-	aup->mii_bus.name = "au1000_eth_mii";
-	snprintf(aup->mii_bus.id, MII_BUS_ID_SIZE, "%x", aup->mac_id);
-	aup->mii_bus.irq = kmalloc(sizeof(int)*PHY_MAX_ADDR, GFP_KERNEL);
+	aup->mii_bus = mdiobus_alloc();
+	if (aup->mii_bus == NULL)
+		goto err_out;
+
+	aup->mii_bus->priv = dev;
+	aup->mii_bus->read = au1000_mdiobus_read;
+	aup->mii_bus->write = au1000_mdiobus_write;
+	aup->mii_bus->reset = au1000_mdiobus_reset;
+	aup->mii_bus->name = "au1000_eth_mii";
+	snprintf(aup->mii_bus->id, MII_BUS_ID_SIZE, "%x", aup->mac_id);
+	aup->mii_bus->irq = kmalloc(sizeof(int)*PHY_MAX_ADDR, GFP_KERNEL);
 	for(i = 0; i < PHY_MAX_ADDR; ++i)
-		aup->mii_bus.irq[i] = PHY_POLL;
+		aup->mii_bus->irq[i] = PHY_POLL;
 
 	/* if known, set corresponding PHY IRQs */
 #if defined(AU1XXX_PHY_STATIC_CONFIG)
 # if defined(AU1XXX_PHY0_IRQ)
 	if (AU1XXX_PHY0_BUSID == aup->mac_id)
-		aup->mii_bus.irq[AU1XXX_PHY0_ADDR] = AU1XXX_PHY0_IRQ;
+		aup->mii_bus->irq[AU1XXX_PHY0_ADDR] = AU1XXX_PHY0_IRQ;
 # endif
 # if defined(AU1XXX_PHY1_IRQ)
 	if (AU1XXX_PHY1_BUSID == aup->mac_id)
-		aup->mii_bus.irq[AU1XXX_PHY1_ADDR] = AU1XXX_PHY1_IRQ;
+		aup->mii_bus->irq[AU1XXX_PHY1_ADDR] = AU1XXX_PHY1_IRQ;
 # endif
 #endif
-	mdiobus_register(&aup->mii_bus);
+	mdiobus_register(aup->mii_bus);
 
 	if (mii_probe(dev) != 0) {
 		goto err_out;
@@ -753,7 +760,6 @@
 		aup->tx_db_inuse[i] = pDB;
 	}
 
-	spin_lock_init(&aup->lock);
 	dev->base_addr = base;
 	dev->irq = irq;
 	dev->open = au1000_open;
@@ -774,6 +780,11 @@
 	return dev;
 
 err_out:
+	if (aup->mii_bus != NULL) {
+		mdiobus_unregister(aup->mii_bus);
+		mdiobus_free(aup->mii_bus);
+	}
+
 	/* here we should have a valid dev plus aup-> register addresses
 	 * so we can reset the mac properly.*/
 	reset_mac(dev);
@@ -1004,6 +1015,8 @@
 		if (dev) {
 			aup = (struct au1000_private *) dev->priv;
 			unregister_netdev(dev);
+			mdiobus_unregister(aup->mii_bus);
+			mdiobus_free(aup->mii_bus);
 			for (j = 0; j < NUM_RX_DMA; j++)
 				if (aup->rx_db_inuse[j])
 					ReleaseDB(aup, aup->rx_db_inuse[j]);
diff --git a/drivers/net/au1000_eth.h b/drivers/net/au1000_eth.h
index f3baeaa..824ecd5 100644
--- a/drivers/net/au1000_eth.h
+++ b/drivers/net/au1000_eth.h
@@ -106,7 +106,7 @@
 	int old_duplex;
 
 	struct phy_device *phy_dev;
-	struct mii_bus mii_bus;
+	struct mii_bus *mii_bus;
 
 	/* These variables are just for quick access to certain regs addresses. */
 	volatile mac_reg_t *mac;  /* mac registers                      */
diff --git a/drivers/net/ax88796.c b/drivers/net/ax88796.c
index a886a4b..4207d6e 100644
--- a/drivers/net/ax88796.c
+++ b/drivers/net/ax88796.c
@@ -153,7 +153,7 @@
 	while ((ei_inb(addr + EN0_ISR) & ENISR_RESET) == 0) {
 		if (jiffies - reset_start_time > 2*HZ/100) {
 			dev_warn(&ax->dev->dev, "%s: %s did not complete.\n",
-			       __FUNCTION__, dev->name);
+			       __func__, dev->name);
 			break;
 		}
 	}
@@ -173,7 +173,7 @@
 	if (ei_status.dmaing) {
 		dev_err(&ax->dev->dev, "%s: DMAing conflict in %s "
 			"[DMAstat:%d][irqlock:%d].\n",
-			dev->name, __FUNCTION__,
+			dev->name, __func__,
 			ei_status.dmaing, ei_status.irqlock);
 		return;
 	}
@@ -215,7 +215,7 @@
 		dev_err(&ax->dev->dev,
 			"%s: DMAing conflict in %s "
 			"[DMAstat:%d][irqlock:%d].\n",
-			dev->name, __FUNCTION__,
+			dev->name, __func__,
 			ei_status.dmaing, ei_status.irqlock);
 		return;
 	}
@@ -260,7 +260,7 @@
 	if (ei_status.dmaing) {
 		dev_err(&ax->dev->dev, "%s: DMAing conflict in %s."
 			"[DMAstat:%d][irqlock:%d]\n",
-			dev->name, __FUNCTION__,
+			dev->name, __func__,
 		       ei_status.dmaing, ei_status.irqlock);
 		return;
 	}
@@ -396,7 +396,7 @@
 {
 	if (phy_debug)
 		pr_debug("%s: dev %p, %04x, %04x, %d\n",
-			__FUNCTION__, dev, phy_addr, reg, opc);
+			__func__, dev, phy_addr, reg, opc);
 
 	ax_mii_ei_outbits(dev, 0x3f, 6);	/* pre-amble */
 	ax_mii_ei_outbits(dev, 1, 2);		/* frame-start */
@@ -422,7 +422,7 @@
       	spin_unlock_irqrestore(&ei_local->page_lock, flags);
 
 	if (phy_debug)
-		pr_debug("%s: %04x.%04x => read %04x\n", __FUNCTION__,
+		pr_debug("%s: %04x.%04x => read %04x\n", __func__,
 			 phy_addr, reg, result);
 
 	return result;
@@ -436,7 +436,7 @@
 	unsigned long flags;
 
 	dev_dbg(&ax->dev->dev, "%s: %p, %04x, %04x %04x\n",
-		__FUNCTION__, dev, phy_addr, reg, value);
+		__func__, dev, phy_addr, reg, value);
 
       	spin_lock_irqsave(&ei->page_lock, flags);
 
diff --git a/drivers/net/bfin_mac.c b/drivers/net/bfin_mac.c
index 3db7db1..b458d60 100644
--- a/drivers/net/bfin_mac.c
+++ b/drivers/net/bfin_mac.c
@@ -253,7 +253,7 @@
  * MII operations
  */
 /* Wait until the previous MDC/MDIO transaction has completed */
-static void mdio_poll(void)
+static void bfin_mdio_poll(void)
 {
 	int timeout_cnt = MAX_TIMEOUT_CNT;
 
@@ -269,25 +269,25 @@
 }
 
 /* Read an off-chip register in a PHY through the MDC/MDIO port */
-static int mdiobus_read(struct mii_bus *bus, int phy_addr, int regnum)
+static int bfin_mdiobus_read(struct mii_bus *bus, int phy_addr, int regnum)
 {
-	mdio_poll();
+	bfin_mdio_poll();
 
 	/* read mode */
 	bfin_write_EMAC_STAADD(SET_PHYAD((u16) phy_addr) |
 				SET_REGAD((u16) regnum) |
 				STABUSY);
 
-	mdio_poll();
+	bfin_mdio_poll();
 
 	return (int) bfin_read_EMAC_STADAT();
 }
 
 /* Write an off-chip register in a PHY through the MDC/MDIO port */
-static int mdiobus_write(struct mii_bus *bus, int phy_addr, int regnum,
-			 u16 value)
+static int bfin_mdiobus_write(struct mii_bus *bus, int phy_addr, int regnum,
+			      u16 value)
 {
-	mdio_poll();
+	bfin_mdio_poll();
 
 	bfin_write_EMAC_STADAT((u32) value);
 
@@ -297,12 +297,12 @@
 				STAOP |
 				STABUSY);
 
-	mdio_poll();
+	bfin_mdio_poll();
 
 	return 0;
 }
 
-static int mdiobus_reset(struct mii_bus *bus)
+static int bfin_mdiobus_reset(struct mii_bus *bus)
 {
 	return 0;
 }
@@ -398,7 +398,7 @@
 
 	/* search for connect PHY device */
 	for (i = 0; i < PHY_MAX_ADDR; i++) {
-		struct phy_device *const tmp_phydev = lp->mii_bus.phy_map[i];
+		struct phy_device *const tmp_phydev = lp->mii_bus->phy_map[i];
 
 		if (!tmp_phydev)
 			continue; /* no PHY here... */
@@ -811,14 +811,14 @@
 {
 	u32 opmode;
 
-	pr_debug("%s: %s\n", DRV_NAME, __FUNCTION__);
+	pr_debug("%s: %s\n", DRV_NAME, __func__);
 
 	/* Set RX DMA */
 	bfin_write_DMA1_NEXT_DESC_PTR(&(rx_list_head->desc_a));
 	bfin_write_DMA1_CONFIG(rx_list_head->desc_a.config);
 
 	/* Wait MII done */
-	mdio_poll();
+	bfin_mdio_poll();
 
 	/* We enable only RX here */
 	/* ASTP   : Enable Automatic Pad Stripping
@@ -847,7 +847,7 @@
 /* Our watchdog timed out. Called by the networking layer */
 static void bfin_mac_timeout(struct net_device *dev)
 {
-	pr_debug("%s: %s\n", dev->name, __FUNCTION__);
+	pr_debug("%s: %s\n", dev->name, __func__);
 
 	bfin_mac_disable();
 
@@ -949,7 +949,7 @@
 {
 	struct bfin_mac_local *lp = netdev_priv(dev);
 	int retval;
-	pr_debug("%s: %s\n", dev->name, __FUNCTION__);
+	pr_debug("%s: %s\n", dev->name, __func__);
 
 	/*
 	 * Check that the address is valid.  If its not, refuse
@@ -989,7 +989,7 @@
 static int bfin_mac_close(struct net_device *dev)
 {
 	struct bfin_mac_local *lp = netdev_priv(dev);
-	pr_debug("%s: %s\n", dev->name, __FUNCTION__);
+	pr_debug("%s: %s\n", dev->name, __func__);
 
 	netif_stop_queue(dev);
 	netif_carrier_off(dev);
@@ -1058,17 +1058,21 @@
 	setup_mac_addr(ndev->dev_addr);
 
 	/* MDIO bus initial */
-	lp->mii_bus.priv = ndev;
-	lp->mii_bus.read = mdiobus_read;
-	lp->mii_bus.write = mdiobus_write;
-	lp->mii_bus.reset = mdiobus_reset;
-	lp->mii_bus.name = "bfin_mac_mdio";
-	snprintf(lp->mii_bus.id, MII_BUS_ID_SIZE, "0");
-	lp->mii_bus.irq = kmalloc(sizeof(int)*PHY_MAX_ADDR, GFP_KERNEL);
-	for (i = 0; i < PHY_MAX_ADDR; ++i)
-		lp->mii_bus.irq[i] = PHY_POLL;
+	lp->mii_bus = mdiobus_alloc();
+	if (lp->mii_bus == NULL)
+		goto out_err_mdiobus_alloc;
 
-	rc = mdiobus_register(&lp->mii_bus);
+	lp->mii_bus->priv = ndev;
+	lp->mii_bus->read = bfin_mdiobus_read;
+	lp->mii_bus->write = bfin_mdiobus_write;
+	lp->mii_bus->reset = bfin_mdiobus_reset;
+	lp->mii_bus->name = "bfin_mac_mdio";
+	snprintf(lp->mii_bus->id, MII_BUS_ID_SIZE, "0");
+	lp->mii_bus->irq = kmalloc(sizeof(int)*PHY_MAX_ADDR, GFP_KERNEL);
+	for (i = 0; i < PHY_MAX_ADDR; ++i)
+		lp->mii_bus->irq[i] = PHY_POLL;
+
+	rc = mdiobus_register(lp->mii_bus);
 	if (rc) {
 		dev_err(&pdev->dev, "Cannot register MDIO bus!\n");
 		goto out_err_mdiobus_register;
@@ -1121,8 +1125,10 @@
 	free_irq(IRQ_MAC_RX, ndev);
 out_err_request_irq:
 out_err_mii_probe:
-	mdiobus_unregister(&lp->mii_bus);
+	mdiobus_unregister(lp->mii_bus);
 out_err_mdiobus_register:
+	mdiobus_free(lp->mii_bus);
+out_err_mdiobus_alloc:
 	peripheral_free_list(pin_req);
 out_err_setup_pin_mux:
 out_err_probe_mac:
@@ -1139,7 +1145,8 @@
 
 	platform_set_drvdata(pdev, NULL);
 
-	mdiobus_unregister(&lp->mii_bus);
+	mdiobus_unregister(lp->mii_bus);
+	mdiobus_free(lp->mii_bus);
 
 	unregister_netdev(ndev);
 
diff --git a/drivers/net/bfin_mac.h b/drivers/net/bfin_mac.h
index beff510..052b5dc 100644
--- a/drivers/net/bfin_mac.h
+++ b/drivers/net/bfin_mac.h
@@ -66,7 +66,7 @@
 	int old_duplex;
 
 	struct phy_device *phydev;
-	struct mii_bus mii_bus;
+	struct mii_bus *mii_bus;
 };
 
 extern void bfin_get_ether_addr(char *addr);
diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c
index 2486a65..430d430 100644
--- a/drivers/net/bnx2.c
+++ b/drivers/net/bnx2.c
@@ -57,8 +57,8 @@
 
 #define DRV_MODULE_NAME		"bnx2"
 #define PFX DRV_MODULE_NAME	": "
-#define DRV_MODULE_VERSION	"1.8.0"
-#define DRV_MODULE_RELDATE	"Aug 14, 2008"
+#define DRV_MODULE_VERSION	"1.8.1"
+#define DRV_MODULE_RELDATE	"Oct 7, 2008"
 
 #define RUN_AT(x) (jiffies + (x))
 
@@ -69,7 +69,7 @@
 	"Broadcom NetXtreme II Gigabit Ethernet Driver " DRV_MODULE_NAME " v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n";
 
 MODULE_AUTHOR("Michael Chan <mchan@broadcom.com>");
-MODULE_DESCRIPTION("Broadcom NetXtreme II BCM5706/5708/5709 Driver");
+MODULE_DESCRIPTION("Broadcom NetXtreme II BCM5706/5708/5709/5716 Driver");
 MODULE_LICENSE("GPL");
 MODULE_VERSION(DRV_MODULE_VERSION);
 
@@ -1127,7 +1127,7 @@
 	}
 }
 
-static int
+static void
 bnx2_set_mac_link(struct bnx2 *bp)
 {
 	u32 val;
@@ -1193,8 +1193,6 @@
 
 	if (CHIP_NUM(bp) == CHIP_NUM_5709)
 		bnx2_init_all_rx_contexts(bp);
-
-	return 0;
 }
 
 static void
@@ -2478,6 +2476,11 @@
 		return -ENOMEM;
 	mapping = pci_map_page(bp->pdev, page, 0, PAGE_SIZE,
 			       PCI_DMA_FROMDEVICE);
+	if (pci_dma_mapping_error(bp->pdev, mapping)) {
+		__free_page(page);
+		return -EIO;
+	}
+
 	rx_pg->page = page;
 	pci_unmap_addr_set(rx_pg, mapping, mapping);
 	rxbd->rx_bd_haddr_hi = (u64) mapping >> 32;
@@ -2520,6 +2523,10 @@
 
 	mapping = pci_map_single(bp->pdev, skb->data, bp->rx_buf_use_size,
 		PCI_DMA_FROMDEVICE);
+	if (pci_dma_mapping_error(bp->pdev, mapping)) {
+		dev_kfree_skb(skb);
+		return -EIO;
+	}
 
 	rx_buf->skb = skb;
 	pci_unmap_addr_set(rx_buf, mapping, mapping);
@@ -2594,7 +2601,7 @@
 	sw_cons = txr->tx_cons;
 
 	while (sw_cons != hw_cons) {
-		struct sw_bd *tx_buf;
+		struct sw_tx_bd *tx_buf;
 		struct sk_buff *skb;
 		int i, last;
 
@@ -2619,21 +2626,13 @@
 			}
 		}
 
-		pci_unmap_single(bp->pdev, pci_unmap_addr(tx_buf, mapping),
-			skb_headlen(skb), PCI_DMA_TODEVICE);
+		skb_dma_unmap(&bp->pdev->dev, skb, DMA_TO_DEVICE);
 
 		tx_buf->skb = NULL;
 		last = skb_shinfo(skb)->nr_frags;
 
 		for (i = 0; i < last; i++) {
 			sw_cons = NEXT_TX_BD(sw_cons);
-
-			pci_unmap_page(bp->pdev,
-				pci_unmap_addr(
-					&txr->tx_buf_ring[TX_RING_IDX(sw_cons)],
-				       	mapping),
-				skb_shinfo(skb)->frags[i].size,
-				PCI_DMA_TODEVICE);
 		}
 
 		sw_cons = NEXT_TX_BD(sw_cons);
@@ -2674,11 +2673,31 @@
 {
 	struct sw_pg *cons_rx_pg, *prod_rx_pg;
 	struct rx_bd *cons_bd, *prod_bd;
-	dma_addr_t mapping;
 	int i;
-	u16 hw_prod = rxr->rx_pg_prod, prod;
+	u16 hw_prod, prod;
 	u16 cons = rxr->rx_pg_cons;
 
+	cons_rx_pg = &rxr->rx_pg_ring[cons];
+
+	/* The caller was unable to allocate a new page to replace the
+	 * last one in the frags array, so we need to recycle that page
+	 * and then free the skb.
+	 */
+	if (skb) {
+		struct page *page;
+		struct skb_shared_info *shinfo;
+
+		shinfo = skb_shinfo(skb);
+		shinfo->nr_frags--;
+		page = shinfo->frags[shinfo->nr_frags].page;
+		shinfo->frags[shinfo->nr_frags].page = NULL;
+
+		cons_rx_pg->page = page;
+		dev_kfree_skb(skb);
+	}
+
+	hw_prod = rxr->rx_pg_prod;
+
 	for (i = 0; i < count; i++) {
 		prod = RX_PG_RING_IDX(hw_prod);
 
@@ -2687,20 +2706,6 @@
 		cons_bd = &rxr->rx_pg_desc_ring[RX_RING(cons)][RX_IDX(cons)];
 		prod_bd = &rxr->rx_pg_desc_ring[RX_RING(prod)][RX_IDX(prod)];
 
-		if (i == 0 && skb) {
-			struct page *page;
-			struct skb_shared_info *shinfo;
-
-			shinfo = skb_shinfo(skb);
-			shinfo->nr_frags--;
-			page = shinfo->frags[shinfo->nr_frags].page;
-			shinfo->frags[shinfo->nr_frags].page = NULL;
-			mapping = pci_map_page(bp->pdev, page, 0, PAGE_SIZE,
-					       PCI_DMA_FROMDEVICE);
-			cons_rx_pg->page = page;
-			pci_unmap_addr_set(cons_rx_pg, mapping, mapping);
-			dev_kfree_skb(skb);
-		}
 		if (prod != cons) {
 			prod_rx_pg->page = cons_rx_pg->page;
 			cons_rx_pg->page = NULL;
@@ -2786,6 +2791,8 @@
 		skb_put(skb, hdr_len);
 
 		for (i = 0; i < pages; i++) {
+			dma_addr_t mapping_old;
+
 			frag_len = min(frag_size, (unsigned int) PAGE_SIZE);
 			if (unlikely(frag_len <= 4)) {
 				unsigned int tail = 4 - frag_len;
@@ -2808,9 +2815,10 @@
 			}
 			rx_pg = &rxr->rx_pg_ring[pg_cons];
 
-			pci_unmap_page(bp->pdev, pci_unmap_addr(rx_pg, mapping),
-				       PAGE_SIZE, PCI_DMA_FROMDEVICE);
-
+			/* Don't unmap yet.  If we're unable to allocate a new
+			 * page, we need to recycle the page and the DMA addr.
+			 */
+			mapping_old = pci_unmap_addr(rx_pg, mapping);
 			if (i == pages - 1)
 				frag_len -= 4;
 
@@ -2827,6 +2835,9 @@
 				return err;
 			}
 
+			pci_unmap_page(bp->pdev, mapping_old,
+				       PAGE_SIZE, PCI_DMA_FROMDEVICE);
+
 			frag_size -= frag_len;
 			skb->data_len += frag_len;
 			skb->truesize += frag_len;
@@ -3250,6 +3261,9 @@
 	struct dev_addr_list *uc_ptr;
 	int i;
 
+	if (!netif_running(dev))
+		return;
+
 	spin_lock_bh(&bp->phy_lock);
 
 	rx_mode = bp->rx_mode & ~(BNX2_EMAC_RX_MODE_PROMISCUOUS |
@@ -4970,31 +4984,20 @@
 			continue;
 
 		for (j = 0; j < TX_DESC_CNT; ) {
-			struct sw_bd *tx_buf = &txr->tx_buf_ring[j];
+			struct sw_tx_bd *tx_buf = &txr->tx_buf_ring[j];
 			struct sk_buff *skb = tx_buf->skb;
-			int k, last;
 
 			if (skb == NULL) {
 				j++;
 				continue;
 			}
 
-			pci_unmap_single(bp->pdev,
-					 pci_unmap_addr(tx_buf, mapping),
-			skb_headlen(skb), PCI_DMA_TODEVICE);
+			skb_dma_unmap(&bp->pdev->dev, skb, DMA_TO_DEVICE);
 
 			tx_buf->skb = NULL;
 
-			last = skb_shinfo(skb)->nr_frags;
-			for (k = 0; k < last; k++) {
-				tx_buf = &txr->tx_buf_ring[j + k + 1];
-				pci_unmap_page(bp->pdev,
-					pci_unmap_addr(tx_buf, mapping),
-					skb_shinfo(skb)->frags[j].size,
-					PCI_DMA_TODEVICE);
-			}
+			j += skb_shinfo(skb)->nr_frags + 1;
 			dev_kfree_skb(skb);
-			j += k + 1;
 		}
 	}
 }
@@ -5075,6 +5078,21 @@
 }
 
 static int
+bnx2_shutdown_chip(struct bnx2 *bp)
+{
+	u32 reset_code;
+
+	if (bp->flags & BNX2_FLAG_NO_WOL)
+		reset_code = BNX2_DRV_MSG_CODE_UNLOAD_LNK_DN;
+	else if (bp->wol)
+		reset_code = BNX2_DRV_MSG_CODE_SUSPEND_WOL;
+	else
+		reset_code = BNX2_DRV_MSG_CODE_SUSPEND_NO_WOL;
+
+	return bnx2_reset_chip(bp, reset_code);
+}
+
+static int
 bnx2_test_registers(struct bnx2 *bp)
 {
 	int ret;
@@ -5357,8 +5375,11 @@
 	for (i = 14; i < pkt_size; i++)
 		packet[i] = (unsigned char) (i & 0xff);
 
-	map = pci_map_single(bp->pdev, skb->data, pkt_size,
-		PCI_DMA_TODEVICE);
+	if (skb_dma_map(&bp->pdev->dev, skb, DMA_TO_DEVICE)) {
+		dev_kfree_skb(skb);
+		return -EIO;
+	}
+	map = skb_shinfo(skb)->dma_maps[0];
 
 	REG_WR(bp, BNX2_HC_COMMAND,
 	       bp->hc_cmd | BNX2_HC_COMMAND_COAL_NOW_WO_INT);
@@ -5393,7 +5414,7 @@
 
 	udelay(5);
 
-	pci_unmap_single(bp->pdev, map, pkt_size, PCI_DMA_TODEVICE);
+	skb_dma_unmap(&bp->pdev->dev, skb, DMA_TO_DEVICE);
 	dev_kfree_skb(skb);
 
 	if (bnx2_get_hw_tx_cons(tx_napi) != txr->tx_prod)
@@ -5508,6 +5529,9 @@
 {
 	u32 bmsr;
 
+	if (!netif_running(bp->dev))
+		return -ENODEV;
+
 	if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP) {
 		if (bp->link_up)
 			return 0;
@@ -5600,7 +5624,7 @@
 	} else if ((bp->link_up == 0) && (bp->autoneg & AUTONEG_SPEED)) {
 		u32 bmcr;
 
-		bp->current_interval = bp->timer_interval;
+		bp->current_interval = BNX2_TIMER_INTERVAL;
 
 		bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
 
@@ -5629,7 +5653,7 @@
 			bp->phy_flags &= ~BNX2_PHY_FLAG_PARALLEL_DETECT;
 		}
 	} else
-		bp->current_interval = bp->timer_interval;
+		bp->current_interval = BNX2_TIMER_INTERVAL;
 
 	if (check_link) {
 		u32 val;
@@ -5674,11 +5698,11 @@
 		} else {
 			bnx2_disable_forced_2g5(bp);
 			bp->serdes_an_pending = 2;
-			bp->current_interval = bp->timer_interval;
+			bp->current_interval = BNX2_TIMER_INTERVAL;
 		}
 
 	} else
-		bp->current_interval = bp->timer_interval;
+		bp->current_interval = BNX2_TIMER_INTERVAL;
 
 	spin_unlock(&bp->phy_lock);
 }
@@ -5951,13 +5975,14 @@
 	struct bnx2 *bp = netdev_priv(dev);
 	dma_addr_t mapping;
 	struct tx_bd *txbd;
-	struct sw_bd *tx_buf;
+	struct sw_tx_bd *tx_buf;
 	u32 len, vlan_tag_flags, last_frag, mss;
 	u16 prod, ring_prod;
 	int i;
 	struct bnx2_napi *bnapi;
 	struct bnx2_tx_ring_info *txr;
 	struct netdev_queue *txq;
+	struct skb_shared_info *sp;
 
 	/*  Determine which tx ring we will be placed on */
 	i = skb_get_queue_mapping(skb);
@@ -5989,7 +6014,7 @@
 	}
 #endif
 	if ((mss = skb_shinfo(skb)->gso_size)) {
-		u32 tcp_opt_len, ip_tcp_len;
+		u32 tcp_opt_len;
 		struct iphdr *iph;
 
 		vlan_tag_flags |= TX_BD_FLAGS_SW_LSO;
@@ -6013,21 +6038,7 @@
 				mss |= (tcp_off & 0xc) << TX_BD_TCP6_OFF2_SHL;
 			}
 		} else {
-			if (skb_header_cloned(skb) &&
-			    pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) {
-				dev_kfree_skb(skb);
-				return NETDEV_TX_OK;
-			}
-
-			ip_tcp_len = ip_hdrlen(skb) + sizeof(struct tcphdr);
-
 			iph = ip_hdr(skb);
-			iph->check = 0;
-			iph->tot_len = htons(mss + ip_tcp_len + tcp_opt_len);
-			tcp_hdr(skb)->check = ~csum_tcpudp_magic(iph->saddr,
-								 iph->daddr, 0,
-								 IPPROTO_TCP,
-								 0);
 			if (tcp_opt_len || (iph->ihl > 5)) {
 				vlan_tag_flags |= ((iph->ihl - 5) +
 						   (tcp_opt_len >> 2)) << 8;
@@ -6036,11 +6047,16 @@
 	} else
 		mss = 0;
 
-	mapping = pci_map_single(bp->pdev, skb->data, len, PCI_DMA_TODEVICE);
+	if (skb_dma_map(&bp->pdev->dev, skb, DMA_TO_DEVICE)) {
+		dev_kfree_skb(skb);
+		return NETDEV_TX_OK;
+	}
+
+	sp = skb_shinfo(skb);
+	mapping = sp->dma_maps[0];
 
 	tx_buf = &txr->tx_buf_ring[ring_prod];
 	tx_buf->skb = skb;
-	pci_unmap_addr_set(tx_buf, mapping, mapping);
 
 	txbd = &txr->tx_desc_ring[ring_prod];
 
@@ -6059,10 +6075,7 @@
 		txbd = &txr->tx_desc_ring[ring_prod];
 
 		len = frag->size;
-		mapping = pci_map_page(bp->pdev, frag->page, frag->page_offset,
-			len, PCI_DMA_TODEVICE);
-		pci_unmap_addr_set(&txr->tx_buf_ring[ring_prod],
-				mapping, mapping);
+		mapping = sp->dma_maps[i + 1];
 
 		txbd->tx_bd_haddr_hi = (u64) mapping >> 32;
 		txbd->tx_bd_haddr_lo = (u64) mapping & 0xffffffff;
@@ -6097,20 +6110,13 @@
 bnx2_close(struct net_device *dev)
 {
 	struct bnx2 *bp = netdev_priv(dev);
-	u32 reset_code;
 
 	cancel_work_sync(&bp->reset_task);
 
 	bnx2_disable_int_sync(bp);
 	bnx2_napi_disable(bp);
 	del_timer_sync(&bp->timer);
-	if (bp->flags & BNX2_FLAG_NO_WOL)
-		reset_code = BNX2_DRV_MSG_CODE_UNLOAD_LNK_DN;
-	else if (bp->wol)
-		reset_code = BNX2_DRV_MSG_CODE_SUSPEND_WOL;
-	else
-		reset_code = BNX2_DRV_MSG_CODE_SUSPEND_NO_WOL;
-	bnx2_reset_chip(bp, reset_code);
+	bnx2_shutdown_chip(bp);
 	bnx2_free_irq(bp);
 	bnx2_free_skbs(bp);
 	bnx2_free_mem(bp);
@@ -6479,6 +6485,9 @@
 	struct bnx2 *bp = netdev_priv(dev);
 	u32 bmcr;
 
+	if (!netif_running(dev))
+		return -EAGAIN;
+
 	if (!(bp->autoneg & AUTONEG_SPEED)) {
 		return -EINVAL;
 	}
@@ -6534,6 +6543,9 @@
 	struct bnx2 *bp = netdev_priv(dev);
 	int rc;
 
+	if (!netif_running(dev))
+		return -EAGAIN;
+
 	/* parameters already validated in ethtool_get_eeprom */
 
 	rc = bnx2_nvram_read(bp, eeprom->offset, eebuf, eeprom->len);
@@ -6548,6 +6560,9 @@
 	struct bnx2 *bp = netdev_priv(dev);
 	int rc;
 
+	if (!netif_running(dev))
+		return -EAGAIN;
+
 	/* parameters already validated in ethtool_set_eeprom */
 
 	rc = bnx2_nvram_write(bp, eeprom->offset, eebuf, eeprom->len);
@@ -6712,11 +6727,11 @@
 		bp->autoneg &= ~AUTONEG_FLOW_CTRL;
 	}
 
-	spin_lock_bh(&bp->phy_lock);
-
-	bnx2_setup_phy(bp, bp->phy_port);
-
-	spin_unlock_bh(&bp->phy_lock);
+	if (netif_running(dev)) {
+		spin_lock_bh(&bp->phy_lock);
+		bnx2_setup_phy(bp, bp->phy_port);
+		spin_unlock_bh(&bp->phy_lock);
+	}
 
 	return 0;
 }
@@ -6907,6 +6922,8 @@
 {
 	struct bnx2 *bp = netdev_priv(dev);
 
+	bnx2_set_power_state(bp, PCI_D0);
+
 	memset(buf, 0, sizeof(u64) * BNX2_NUM_TESTS);
 	if (etest->flags & ETH_TEST_FL_OFFLINE) {
 		int i;
@@ -6926,9 +6943,8 @@
 		if ((buf[2] = bnx2_test_loopback(bp)) != 0)
 			etest->flags |= ETH_TEST_FL_FAILED;
 
-		if (!netif_running(bp->dev)) {
-			bnx2_reset_chip(bp, BNX2_DRV_MSG_CODE_RESET);
-		}
+		if (!netif_running(bp->dev))
+			bnx2_shutdown_chip(bp);
 		else {
 			bnx2_init_nic(bp, 1);
 			bnx2_netif_start(bp);
@@ -6956,6 +6972,8 @@
 		etest->flags |= ETH_TEST_FL_FAILED;
 
 	}
+	if (!netif_running(bp->dev))
+		bnx2_set_power_state(bp, PCI_D3hot);
 }
 
 static void
@@ -7021,6 +7039,8 @@
 	int i;
 	u32 save;
 
+	bnx2_set_power_state(bp, PCI_D0);
+
 	if (data == 0)
 		data = 2;
 
@@ -7045,6 +7065,10 @@
 	}
 	REG_WR(bp, BNX2_EMAC_LED, 0);
 	REG_WR(bp, BNX2_MISC_CFG, save);
+
+	if (!netif_running(dev))
+		bnx2_set_power_state(bp, PCI_D3hot);
+
 	return 0;
 }
 
@@ -7516,8 +7540,7 @@
 
 	bp->stats_ticks = USEC_PER_SEC & BNX2_HC_STATS_TICKS_HC_STAT_TICKS;
 
-	bp->timer_interval =  HZ;
-	bp->current_interval =  HZ;
+	bp->current_interval = BNX2_TIMER_INTERVAL;
 
 	bp->phy_addr = 1;
 
@@ -7607,7 +7630,7 @@
 	bp->req_flow_ctrl = FLOW_CTRL_RX | FLOW_CTRL_TX;
 
 	init_timer(&bp->timer);
-	bp->timer.expires = RUN_AT(bp->timer_interval);
+	bp->timer.expires = RUN_AT(BNX2_TIMER_INTERVAL);
 	bp->timer.data = (unsigned long) bp;
 	bp->timer.function = bnx2_timer;
 
@@ -7720,7 +7743,6 @@
 
 	memcpy(dev->dev_addr, bp->mac_addr, 6);
 	memcpy(dev->perm_addr, bp->mac_addr, 6);
-	bp->name = board_info[ent->driver_data].name;
 
 	dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG;
 	if (CHIP_NUM(bp) == CHIP_NUM_5709)
@@ -7747,7 +7769,7 @@
 	printk(KERN_INFO "%s: %s (%c%d) %s found at mem %lx, "
 		"IRQ %d, node addr %s\n",
 		dev->name,
-		bp->name,
+		board_info[ent->driver_data].name,
 		((CHIP_ID(bp) & 0xf000) >> 12) + 'A',
 		((CHIP_ID(bp) & 0x0ff0) >> 4),
 		bnx2_bus_string(bp, str),
@@ -7781,7 +7803,6 @@
 {
 	struct net_device *dev = pci_get_drvdata(pdev);
 	struct bnx2 *bp = netdev_priv(dev);
-	u32 reset_code;
 
 	/* PCI register 4 needs to be saved whether netif_running() or not.
 	 * MSI address and data need to be saved if using MSI and
@@ -7795,13 +7816,7 @@
 	bnx2_netif_stop(bp);
 	netif_device_detach(dev);
 	del_timer_sync(&bp->timer);
-	if (bp->flags & BNX2_FLAG_NO_WOL)
-		reset_code = BNX2_DRV_MSG_CODE_UNLOAD_LNK_DN;
-	else if (bp->wol)
-		reset_code = BNX2_DRV_MSG_CODE_SUSPEND_WOL;
-	else
-		reset_code = BNX2_DRV_MSG_CODE_SUSPEND_NO_WOL;
-	bnx2_reset_chip(bp, reset_code);
+	bnx2_shutdown_chip(bp);
 	bnx2_free_skbs(bp);
 	bnx2_set_power_state(bp, pci_choose_state(pdev, state));
 	return 0;
diff --git a/drivers/net/bnx2.h b/drivers/net/bnx2.h
index c3c579f..617d953 100644
--- a/drivers/net/bnx2.h
+++ b/drivers/net/bnx2.h
@@ -6526,10 +6526,14 @@
 	DECLARE_PCI_UNMAP_ADDR(mapping)
 };
 
+struct sw_tx_bd {
+	struct sk_buff		*skb;
+};
+
 #define SW_RXBD_RING_SIZE (sizeof(struct sw_bd) * RX_DESC_CNT)
 #define SW_RXPG_RING_SIZE (sizeof(struct sw_pg) * RX_DESC_CNT)
 #define RXBD_RING_SIZE (sizeof(struct rx_bd) * RX_DESC_CNT)
-#define SW_TXBD_RING_SIZE (sizeof(struct sw_bd) * TX_DESC_CNT)
+#define SW_TXBD_RING_SIZE (sizeof(struct sw_tx_bd) * TX_DESC_CNT)
 #define TXBD_RING_SIZE (sizeof(struct tx_bd) * TX_DESC_CNT)
 
 /* Buffered flash (Atmel: AT45DB011B) specific information */
@@ -6597,7 +6601,7 @@
 
 struct bnx2_irq {
 	irq_handler_t	handler;
-	u16		vector;
+	unsigned int	vector;
 	u8		requested;
 	char		name[16];
 };
@@ -6609,7 +6613,7 @@
 	u32			tx_bseq_addr;
 
 	struct tx_bd		*tx_desc_ring;
-	struct sw_bd		*tx_buf_ring;
+	struct sw_tx_bd		*tx_buf_ring;
 
 	u16			tx_cons;
 	u16			hw_tx_cons;
@@ -6654,6 +6658,8 @@
 	struct bnx2_tx_ring_info	tx_ring;
 };
 
+#define BNX2_TIMER_INTERVAL			HZ
+
 struct bnx2 {
 	/* Fields used in the tx and intr/napi performance paths are grouped */
 	/* together in the beginning of the structure. */
@@ -6701,9 +6707,6 @@
 
 	/* End of fields used in the performance code paths. */
 
-	char			*name;
-
-	int			timer_interval;
 	int			current_interval;
 	struct			timer_list timer;
 	struct work_struct	reset_task;
diff --git a/drivers/net/bnx2_fw.h b/drivers/net/bnx2_fw.h
index e4b1de4..24c3cc4 100644
--- a/drivers/net/bnx2_fw.h
+++ b/drivers/net/bnx2_fw.h
@@ -15,854 +15,854 @@
  */
 
 static u8 bnx2_COM_b06FwText[] = {
-	0xcd, 0x7c, 0x0d, 0x70, 0x5c, 0xd5, 0x95, 0xe6, 0xe9, 0xd7, 0xdd, 0x52,
-	0x4b, 0x96, 0xe5, 0x27, 0xb9, 0x51, 0x1a, 0xa2, 0x24, 0xef, 0xa9, 0x9f,
-	0xa4, 0x06, 0x29, 0xe4, 0xd9, 0x08, 0x10, 0x49, 0x0f, 0x34, 0xdd, 0x92,
-	0x11, 0x89, 0x77, 0x24, 0x40, 0x61, 0xbc, 0x3b, 0xae, 0xac, 0xa6, 0x2d,
-	0x13, 0x42, 0x31, 0x35, 0xae, 0x0a, 0x3b, 0x71, 0xb2, 0x04, 0x37, 0x2d,
-	0x99, 0x38, 0x8c, 0xec, 0x56, 0x64, 0x59, 0x66, 0x67, 0xd8, 0xd9, 0x4e,
-	0x4b, 0xb2, 0x19, 0xa6, 0xed, 0xc6, 0x90, 0x1f, 0xa6, 0x92, 0x0c, 0x5a,
-	0xe3, 0x00, 0x93, 0xcd, 0x56, 0x41, 0x2a, 0xb5, 0xcb, 0x6c, 0x51, 0xbb,
-	0x5e, 0x27, 0x4c, 0xb2, 0xa9, 0xda, 0x0a, 0x3b, 0x93, 0xda, 0x65, 0xf2,
-	0x33, 0x6f, 0xbf, 0xef, 0xbe, 0xfb, 0xa4, 0x96, 0xac, 0x38, 0x4c, 0xa6,
-	0x52, 0x35, 0xaa, 0xea, 0xba, 0xef, 0xde, 0x77, 0x7f, 0xce, 0x3d, 0xf7,
-	0xdc, 0x73, 0xbe, 0x73, 0xee, 0x7d, 0xba, 0x55, 0xa4, 0x59, 0xf4, 0xdf,
-	0x56, 0xfc, 0x06, 0x7e, 0xff, 0x0f, 0xf6, 0xdd, 0x78, 0xbd, 0x7b, 0x3d,
-	0xf3, 0x46, 0x54, 0x22, 0x4c, 0xc3, 0xf8, 0xc5, 0xf1, 0xdb, 0xa9, 0x9f,
-	0x37, 0xfb, 0x33, 0xf1, 0xbb, 0x29, 0x24, 0x32, 0xf1, 0x23, 0x91, 0xd0,
-	0x86, 0x77, 0xb1, 0x4d, 0xea, 0x7b, 0xde, 0x2f, 0xe9, 0x48, 0xff, 0x19,
-	0xf8, 0x59, 0x57, 0xae, 0xb2, 0x3a, 0xee, 0xaf, 0xfb, 0x17, 0xd6, 0xcd,
-	0xb7, 0xea, 0x9f, 0xc4, 0x8c, 0xf4, 0xc5, 0xdf, 0xce, 0x3a, 0x12, 0x0b,
-	0xa7, 0xbf, 0x3b, 0xba, 0xcf, 0x11, 0xc9, 0x54, 0xfb, 0xac, 0x9c, 0xfc,
-	0xc2, 0x2b, 0xc4, 0x23, 0xc2, 0xf2, 0xf7, 0xa4, 0x7f, 0x7e, 0xe8, 0x1b,
-	0x37, 0xdb, 0x6f, 0x95, 0xc3, 0x12, 0x33, 0xd3, 0x6f, 0x8b, 0xd9, 0x23,
-	0xb1, 0x4e, 0xb4, 0x79, 0xb2, 0xf7, 0x29, 0x43, 0x5a, 0x83, 0xbe, 0xcc,
-	0x89, 0x70, 0x5a, 0xc6, 0x26, 0x67, 0x0e, 0x79, 0x86, 0x23, 0x85, 0x6b,
-	0xd2, 0x8e, 0x55, 0x94, 0x96, 0xc1, 0xe9, 0x81, 0x9b, 0x05, 0xf9, 0xb1,
-	0xc9, 0x6a, 0x4c, 0xb2, 0xb5, 0x42, 0x8b, 0xe1, 0x38, 0x48, 0x63, 0x85,
-	0x77, 0xa7, 0x25, 0xd6, 0x90, 0x9e, 0x6f, 0x7c, 0xc9, 0xe1, 0xf8, 0x89,
-	0xd1, 0xac, 0xf3, 0x6e, 0x89, 0x38, 0x9e, 0x37, 0x8d, 0xf1, 0x77, 0x55,
-	0x7f, 0xe1, 0x3d, 0x1a, 0xf1, 0xc7, 0x36, 0xd2, 0x07, 0xc3, 0x4c, 0x43,
-	0x69, 0x6b, 0xb4, 0xab, 0xaa, 0xf2, 0x0d, 0x7e, 0xde, 0xd1, 0xf9, 0x58,
-	0xb3, 0x4f, 0xbb, 0x34, 0x81, 0xf6, 0x58, 0x24, 0x9d, 0x6e, 0x42, 0x1f,
-	0xb1, 0x68, 0xfa, 0x99, 0xdf, 0x5a, 0x56, 0xf5, 0xee, 0xd7, 0xf5, 0xee,
-	0x8f, 0xfa, 0xed, 0x26, 0x47, 0x7b, 0xaa, 0x4c, 0x1f, 0x1a, 0xed, 0x56,
-	0xe9, 0xc3, 0xa3, 0x49, 0x95, 0x16, 0x54, 0xbd, 0x50, 0x7a, 0x7a, 0xd4,
-	0x51, 0x69, 0xa7, 0x2e, 0x4f, 0x8d, 0x5a, 0x2a, 0xed, 0xd7, 0xa9, 0xab,
-	0xd3, 0x01, 0x9d, 0x0e, 0xea, 0x34, 0xad, 0xd3, 0x8c, 0x4e, 0x87, 0x74,
-	0x3f, 0x23, 0x3a, 0xbf, 0x5b, 0xa7, 0x63, 0x3a, 0x1d, 0xd7, 0xe9, 0x1e,
-	0x9d, 0xee, 0xd5, 0x74, 0x4d, 0xe8, 0xf4, 0x41, 0x5d, 0x7e, 0x40, 0xd3,
-	0x79, 0x10, 0xf4, 0x7c, 0xa6, 0x51, 0xcb, 0x2d, 0xe6, 0x6b, 0xc9, 0xbe,
-	0x99, 0x98, 0x14, 0x4b, 0x61, 0xc9, 0xa9, 0xf5, 0xfc, 0x7c, 0x54, 0x9a,
-	0x63, 0x32, 0x55, 0x8b, 0xc9, 0x45, 0x25, 0xae, 0x3f, 0xf4, 0xbe, 0xd1,
-	0x6b, 0xca, 0x33, 0xb5, 0xb8, 0xbc, 0x50, 0x93, 0xd0, 0x58, 0x6f, 0x93,
-	0x18, 0x73, 0xd7, 0x48, 0xc6, 0x0c, 0x49, 0x58, 0xf1, 0xd5, 0x92, 0xec,
-	0x4c, 0x07, 0xf2, 0x76, 0x42, 0xe4, 0xe5, 0xa8, 0xbf, 0x8e, 0x31, 0x09,
-	0x2f, 0x70, 0x5d, 0x16, 0x46, 0x5f, 0x9a, 0x4f, 0x48, 0xe4, 0x98, 0x85,
-	0xfe, 0x5b, 0x24, 0xba, 0x20, 0x9d, 0x61, 0xe9, 0x4e, 0xdc, 0x87, 0x1a,
-	0x43, 0xd5, 0x88, 0x0c, 0x57, 0x43, 0x58, 0xab, 0x18, 0xe4, 0xa4, 0x05,
-	0x3f, 0x13, 0xbf, 0x38, 0x7e, 0x09, 0xfc, 0x3c, 0xf4, 0xd3, 0x29, 0xb9,
-	0x2a, 0xfb, 0xc4, 0xb8, 0x25, 0x8c, 0x5f, 0xb2, 0xcd, 0x09, 0x21, 0x4d,
-	0x09, 0xf9, 0x46, 0xaf, 0x4f, 0xd3, 0x0b, 0xb5, 0x58, 0x28, 0x7b, 0x52,
-	0x0e, 0xe4, 0x5c, 0xb1, 0x0c, 0xa7, 0x59, 0xf2, 0x66, 0xc8, 0x9a, 0x4c,
-	0xb5, 0x4b, 0x61, 0x1c, 0xef, 0x4a, 0x92, 0x31, 0xd0, 0x77, 0xde, 0x94,
-	0x09, 0xff, 0x1d, 0xcb, 0xfe, 0x1e, 0xfb, 0xd5, 0x36, 0x29, 0xb8, 0x2f,
-	0x94, 0xfe, 0x02, 0xcf, 0xec, 0xeb, 0xcd, 0x88, 0x4f, 0xf3, 0xdb, 0xc8,
-	0xb3, 0xfc, 0x67, 0xdb, 0xfc, 0x3c, 0x9f, 0x59, 0x37, 0x18, 0x33, 0x98,
-	0x2b, 0xc7, 0xee, 0xc5, 0x7c, 0x39, 0xfe, 0xea, 0x7c, 0x41, 0x47, 0x4b,
-	0x28, 0x77, 0xd2, 0x92, 0xc3, 0xa5, 0x5b, 0x25, 0xeb, 0x7a, 0xde, 0x3e,
-	0x57, 0xe2, 0x86, 0x74, 0x9b, 0x39, 0xbc, 0xad, 0x54, 0x25, 0x94, 0x2d,
-	0x05, 0xfc, 0x60, 0xbf, 0x11, 0x94, 0x75, 0xa0, 0x7e, 0x6b, 0x68, 0xe8,
-	0x24, 0x68, 0x4f, 0x93, 0x2f, 0x90, 0x59, 0xb7, 0x3b, 0x31, 0x89, 0xf1,
-	0x16, 0xab, 0xdd, 0xee, 0x79, 0x31, 0xd1, 0x67, 0x3b, 0xea, 0x90, 0x47,
-	0xec, 0x8b, 0x7d, 0xb2, 0xbf, 0x16, 0xb4, 0x8d, 0xe3, 0x1d, 0x69, 0xf2,
-	0xbc, 0xac, 0x6b, 0x32, 0x2f, 0x65, 0xf0, 0xad, 0x4c, 0xbe, 0x35, 0x77,
-	0xca, 0xa9, 0x2a, 0xc7, 0xd8, 0x8c, 0xee, 0xeb, 0xfe, 0x99, 0xd1, 0x9d,
-	0x40, 0xff, 0x71, 0xa4, 0x5b, 0x42, 0xd9, 0xe3, 0x1e, 0xc6, 0x4f, 0xe0,
-	0x79, 0xb3, 0x39, 0x5c, 0xd4, 0x32, 0x98, 0x00, 0xed, 0x71, 0x39, 0xa7,
-	0xe4, 0x70, 0x8b, 0x84, 0x21, 0x87, 0x5c, 0xe3, 0xb6, 0x85, 0x1b, 0x25,
-	0x1f, 0xb7, 0x2d, 0xea, 0xce, 0xae, 0x9d, 0x4d, 0x98, 0xa3, 0xd6, 0x82,
-	0xc7, 0xe2, 0x90, 0xc3, 0xf3, 0x6d, 0x06, 0x4a, 0x0c, 0xb1, 0xcd, 0x7f,
-	0x25, 0x05, 0xc9, 0x2d, 0x7d, 0x2a, 0x24, 0xcd, 0x06, 0xea, 0x5d, 0x1b,
-	0xf2, 0x79, 0x40, 0xfe, 0x64, 0xc0, 0x9f, 0x90, 0xf8, 0xfb, 0x3a, 0x23,
-	0x5d, 0x55, 0xbe, 0xef, 0xb3, 0x0c, 0xf5, 0x6e, 0x08, 0xef, 0x22, 0x92,
-	0xdc, 0x19, 0xbc, 0x1f, 0xc2, 0xfb, 0x6b, 0x64, 0xc2, 0x04, 0x2d, 0xa5,
-	0xe7, 0x8d, 0x2c, 0x68, 0xbc, 0x3d, 0xa2, 0xe6, 0x8a, 0xba, 0x13, 0x75,
-	0xfd, 0x4c, 0xa0, 0xde, 0x1f, 0x63, 0x2c, 0xd0, 0x5b, 0xb2, 0x40, 0x4b,
-	0x07, 0x68, 0x21, 0x8d, 0x05, 0x23, 0x5b, 0x8b, 0x20, 0x3f, 0x6d, 0xe4,
-	0x4e, 0x1f, 0xc1, 0xb3, 0x98, 0x46, 0xfa, 0x79, 0xa6, 0x68, 0xbf, 0xb7,
-	0xae, 0xfd, 0x5e, 0xb4, 0xe7, 0x18, 0x6c, 0xef, 0xcb, 0x7f, 0x41, 0xc9,
-	0xa2, 0x75, 0x05, 0x7e, 0x84, 0x7f, 0x0d, 0x7e, 0x7c, 0x4d, 0xf3, 0xe3,
-	0x67, 0xf2, 0x9b, 0xe7, 0xc7, 0x7f, 0xff, 0x0d, 0xf1, 0x43, 0x24, 0x7f,
-	0x9c, 0xcf, 0x11, 0x29, 0x28, 0xbd, 0xc5, 0x7d, 0x4b, 0x79, 0xa7, 0xce,
-	0x22, 0x9f, 0x28, 0xc7, 0xd8, 0x03, 0xb5, 0x08, 0xd2, 0xa7, 0x90, 0x6e,
-	0x09, 0x8d, 0x1d, 0xbf, 0x84, 0xf5, 0xf7, 0xc4, 0xdc, 0x19, 0xd8, 0x8d,
-	0x42, 0xc2, 0x94, 0x4e, 0x31, 0xaf, 0x87, 0xd1, 0xee, 0xb0, 0xcd, 0xbc,
-	0xbc, 0x89, 0xf7, 0xbf, 0x08, 0x05, 0xf6, 0x3d, 0x3b, 0xd3, 0xf4, 0x76,
-	0x46, 0x3d, 0x45, 0xc9, 0xcf, 0x8c, 0x91, 0x8e, 0x84, 0x72, 0x25, 0x6b,
-	0xc2, 0x48, 0xc7, 0xa1, 0xa7, 0x98, 0x1f, 0x0c, 0xf9, 0x34, 0x0f, 0xa0,
-	0x6e, 0xa0, 0xb3, 0x02, 0xda, 0x07, 0x40, 0xfb, 0x46, 0xdd, 0x95, 0x01,
-	0x2d, 0xa4, 0x81, 0x74, 0x55, 0xc2, 0x9a, 0xf7, 0xe8, 0xe7, 0xa0, 0xea,
-	0x27, 0x9c, 0x1e, 0x14, 0xda, 0xd0, 0xfc, 0x0c, 0xf7, 0x01, 0xdb, 0xb1,
-	0x2f, 0x5f, 0x27, 0xe7, 0xab, 0x41, 0x1f, 0x85, 0xba, 0x3e, 0x0a, 0xa0,
-	0x47, 0xb6, 0x19, 0x4e, 0x14, 0x6b, 0xcf, 0xae, 0x8e, 0xe0, 0xdd, 0x93,
-	0x92, 0x3d, 0x7d, 0xb3, 0x81, 0x39, 0xa0, 0x5f, 0xf2, 0x68, 0x0c, 0x3a,
-	0x9b, 0xfb, 0x2c, 0x26, 0xb9, 0x38, 0xcb, 0x3e, 0xa6, 0xc7, 0x8d, 0x48,
-	0x46, 0xe5, 0x5f, 0x69, 0x5d, 0xa3, 0xe3, 0x79, 0x3d, 0x9f, 0x34, 0xe6,
-	0x43, 0x1a, 0x82, 0xb9, 0xa4, 0xeb, 0xe6, 0x12, 0xf0, 0x9a, 0xbc, 0x30,
-	0xa1, 0xe3, 0x63, 0xda, 0x86, 0xb0, 0xdd, 0x74, 0xdd, 0xda, 0x4d, 0xa3,
-	0x0d, 0x79, 0x8f, 0x3a, 0x1b, 0xec, 0x0a, 0x6d, 0xca, 0x10, 0xfa, 0x29,
-	0xce, 0x1b, 0x92, 0x73, 0x61, 0xab, 0xdd, 0x77, 0x6b, 0x79, 0x5d, 0x93,
-	0xa5, 0xe8, 0xa6, 0xb2, 0x74, 0xc8, 0xf0, 0xf5, 0x35, 0x6c, 0x0b, 0xec,
-	0xcf, 0xd4, 0xbc, 0x9d, 0x0a, 0x64, 0xa9, 0x38, 0xf3, 0x4e, 0x64, 0x29,
-	0x68, 0x1f, 0x83, 0xec, 0x06, 0x63, 0x6c, 0xa4, 0x39, 0xa8, 0x03, 0x1a,
-	0x4b, 0x59, 0x8d, 0x51, 0x38, 0x8e, 0x6f, 0x1b, 0xca, 0xeb, 0x6c, 0xc3,
-	0x11, 0xb4, 0x95, 0x50, 0xae, 0xb7, 0x45, 0xf6, 0xcf, 0x07, 0x7d, 0x1c,
-	0x51, 0x32, 0x3b, 0x39, 0x63, 0x9b, 0xc3, 0x61, 0xc9, 0x0c, 0xcf, 0x0e,
-	0xca, 0x50, 0xad, 0x13, 0x6b, 0xfa, 0xb6, 0x07, 0xdb, 0x79, 0x7d, 0x54,
-	0x1c, 0xe8, 0x45, 0xcc, 0x79, 0x00, 0x3c, 0xae, 0x45, 0xc5, 0x48, 0xbb,
-	0x48, 0xeb, 0x31, 0x56, 0x24, 0x32, 0xbc, 0x2e, 0xdf, 0x80, 0x3a, 0xe8,
-	0x7b, 0x60, 0x63, 0x3d, 0xc8, 0x27, 0x78, 0x9b, 0x75, 0x7f, 0xe1, 0xc1,
-	0x0e, 0x6b, 0x9b, 0xc5, 0x52, 0xea, 0x89, 0x40, 0x47, 0x7c, 0x14, 0xfb,
-	0x5b, 0xed, 0x85, 0x82, 0x91, 0x3e, 0x80, 0x3e, 0x44, 0xc9, 0x69, 0xb1,
-	0xf6, 0x4c, 0xb0, 0xef, 0x55, 0xf9, 0xae, 0x01, 0xca, 0x5e, 0x19, 0x98,
-	0x80, 0x73, 0x5a, 0x52, 0x7b, 0x3d, 0x67, 0xc6, 0x65, 0xba, 0xc4, 0xf9,
-	0x2c, 0x49, 0xb2, 0xfa, 0xa7, 0x92, 0x3b, 0x2d, 0xf2, 0xad, 0x19, 0xd6,
-	0xfb, 0xba, 0xae, 0xf7, 0x3c, 0xea, 0x25, 0xad, 0xa1, 0x90, 0x0d, 0x3b,
-	0x60, 0x63, 0x9b, 0xf4, 0x59, 0x48, 0xcd, 0x11, 0xfc, 0x86, 0x68, 0x64,
-	0x50, 0xcf, 0xc7, 0x40, 0xcf, 0x83, 0x1f, 0x22, 0x77, 0x95, 0x1a, 0xa1,
-	0x4f, 0xfe, 0x27, 0x68, 0x8d, 0xcb, 0xe3, 0x98, 0xc7, 0x4b, 0x33, 0xc4,
-	0x59, 0x5f, 0x97, 0xe5, 0x19, 0xe2, 0xae, 0xe7, 0x65, 0x7a, 0x26, 0xe9,
-	0x7e, 0x0b, 0x7c, 0x3e, 0x25, 0x9c, 0x4b, 0x9f, 0x8b, 0x14, 0x18, 0xd0,
-	0xb6, 0x1e, 0x83, 0x3e, 0xeb, 0xdd, 0xe9, 0xf7, 0xd7, 0xad, 0xfb, 0x73,
-	0xaa, 0xb6, 0x5c, 0x34, 0xa9, 0x9f, 0x2e, 0xdf, 0xe3, 0x59, 0xbd, 0xc7,
-	0xc7, 0xdc, 0x4e, 0x31, 0xb0, 0xaf, 0x33, 0xe3, 0x05, 0x58, 0x3f, 0xee,
-	0xeb, 0xff, 0x6b, 0xac, 0xe1, 0x9f, 0x04, 0xb0, 0xaa, 0xad, 0xec, 0xdd,
-	0x3f, 0x6e, 0x8f, 0xd7, 0xef, 0x6d, 0x8e, 0xdf, 0x8a, 0x36, 0x11, 0xa4,
-	0x57, 0xde, 0xd7, 0xe8, 0xa3, 0xae, 0xed, 0x20, 0xf7, 0x05, 0xda, 0xfc,
-	0x09, 0x78, 0x41, 0xfe, 0xbf, 0x93, 0xfd, 0xdc, 0x17, 0x7e, 0x47, 0xfb,
-	0x79, 0xfc, 0x4a, 0xfb, 0xb9, 0x7e, 0x2f, 0x9f, 0x25, 0x2f, 0x30, 0xb6,
-	0xcc, 0xfa, 0xb2, 0xd5, 0x0d, 0x5e, 0x5b, 0x90, 0x53, 0xd0, 0x50, 0xfa,
-	0x07, 0x2f, 0x13, 0xf1, 0xf1, 0x9c, 0x2f, 0x4f, 0xac, 0x17, 0xd4, 0xf1,
-	0x75, 0xef, 0x50, 0xed, 0xa2, 0xd2, 0xb3, 0xe7, 0x94, 0x9e, 0xb5, 0x8f,
-	0x14, 0x84, 0xf2, 0x76, 0x43, 0x98, 0x7c, 0x7f, 0xc6, 0xfd, 0x2c, 0x68,
-	0xb4, 0x2d, 0xcb, 0xe8, 0x2e, 0x18, 0xc6, 0x67, 0xe5, 0xc0, 0xe2, 0x43,
-	0x72, 0xa0, 0xc4, 0x3e, 0xd2, 0x78, 0xef, 0xa0, 0xac, 0x09, 0xba, 0x96,
-	0x3a, 0xfd, 0xed, 0x90, 0x3f, 0x96, 0x01, 0xfb, 0xb5, 0x12, 0xba, 0xab,
-	0x76, 0x21, 0x94, 0x5d, 0xe4, 0xde, 0x45, 0x79, 0xad, 0x5e, 0xe7, 0x07,
-	0xfa, 0xbe, 0x5e, 0xb7, 0x17, 0x42, 0x63, 0xa5, 0x69, 0xe2, 0x40, 0x23,
-	0xeb, 0x46, 0xb5, 0xee, 0xf8, 0x9a, 0x29, 0xad, 0xb0, 0x2d, 0xc6, 0x3c,
-	0x78, 0x45, 0x9c, 0x4a, 0xde, 0xa5, 0x24, 0x13, 0x21, 0x9e, 0xe4, 0xb3,
-	0x78, 0xe1, 0x34, 0xf7, 0x9e, 0x44, 0xc2, 0xe9, 0x2e, 0xf0, 0x8e, 0x75,
-	0x6e, 0x05, 0xad, 0xb0, 0x7b, 0xee, 0xfb, 0x84, 0x72, 0xf9, 0x42, 0xe9,
-	0x36, 0xe4, 0x23, 0x9a, 0xbf, 0x51, 0xd4, 0x61, 0x7f, 0x3f, 0x6d, 0x90,
-	0xd6, 0xe3, 0xd0, 0x15, 0x41, 0xbf, 0xac, 0x93, 0xd0, 0x75, 0x5a, 0x74,
-	0x9d, 0x5b, 0xf0, 0x7e, 0x0e, 0xf5, 0x6c, 0x57, 0x84, 0x7c, 0x60, 0x59,
-	0x3b, 0xe6, 0x85, 0xba, 0x8b, 0xe9, 0xf0, 0x7a, 0xba, 0x6e, 0xaa, 0xab,
-	0xcb, 0xfc, 0x66, 0x58, 0x97, 0xf2, 0x24, 0x5a, 0x97, 0xb1, 0x6c, 0x10,
-	0xcf, 0x5d, 0x32, 0xb1, 0x98, 0x81, 0x4e, 0xba, 0x5d, 0xf5, 0x13, 0x75,
-	0xd6, 0xd9, 0x3a, 0xd0, 0x64, 0x69, 0x9a, 0xb6, 0x04, 0xfa, 0x18, 0x65,
-	0xae, 0x2e, 0x6b, 0xa8, 0x2b, 0x0b, 0xe4, 0xe7, 0x5f, 0x83, 0x76, 0x8e,
-	0x3d, 0xa2, 0x71, 0x98, 0xe7, 0xe5, 0x28, 0x77, 0xfd, 0xff, 0x52, 0xf3,
-	0xa2, 0x60, 0x86, 0xd5, 0x5e, 0xa9, 0xfe, 0xf6, 0xda, 0x5e, 0x01, 0x6e,
-	0x57, 0xbd, 0x70, 0x8e, 0xa4, 0xa5, 0x05, 0x6b, 0x3b, 0x04, 0x5a, 0xb1,
-	0x86, 0x1d, 0x21, 0xcc, 0xb7, 0x45, 0xf2, 0xb5, 0xb4, 0x7e, 0xc7, 0xf2,
-	0x88, 0x8c, 0xc5, 0x83, 0xf9, 0x7d, 0xc0, 0xf4, 0xb1, 0x37, 0xea, 0x94,
-	0xb6, 0x44, 0xfc, 0xbd, 0x68, 0x4a, 0xfe, 0xe4, 0x10, 0x64, 0x9e, 0xd8,
-	0xb0, 0x01, 0x32, 0x1f, 0x57, 0x36, 0xc7, 0x70, 0x58, 0x1f, 0xef, 0x4e,
-	0xff, 0xbb, 0xb0, 0xdf, 0x86, 0xf5, 0x82, 0x36, 0xc1, 0xd8, 0xed, 0xab,
-	0x6d, 0xc7, 0x5c, 0x43, 0xc2, 0x6a, 0x7c, 0x94, 0x9d, 0x5e, 0x3f, 0xbe,
-	0xd1, 0x11, 0x8c, 0xff, 0xa7, 0xba, 0xaf, 0xf6, 0xba, 0xbe, 0xe2, 0x57,
-	0x18, 0x1f, 0xef, 0x4e, 0xff, 0xee, 0x76, 0xbf, 0x4d, 0xbc, 0xae, 0x4d,
-	0xc7, 0x86, 0x36, 0xac, 0x1f, 0x8c, 0x81, 0x77, 0xa7, 0xef, 0x6b, 0xf1,
-	0xdb, 0xb0, 0x5e, 0x03, 0x6c, 0x2c, 0xdf, 0x71, 0x0f, 0x1e, 0xa8, 0xdb,
-	0x83, 0x07, 0xb0, 0x07, 0x03, 0xd9, 0xde, 0x88, 0xd7, 0x03, 0xbf, 0x8b,
-	0xfe, 0x16, 0x31, 0xde, 0x9a, 0x7f, 0x15, 0x59, 0x68, 0x01, 0x7e, 0x6a,
-	0xa5, 0x4f, 0xa5, 0xf1, 0x39, 0x7d, 0x2c, 0xe2, 0x71, 0x71, 0x22, 0xd2,
-	0x0d, 0x5d, 0xd9, 0x9d, 0xd8, 0xcf, 0x8d, 0x5f, 0x8d, 0x2b, 0xdc, 0x9e,
-	0xd1, 0x63, 0xd0, 0xbf, 0x22, 0xdf, 0x99, 0xcf, 0xad, 0xfa, 0x5b, 0x9d,
-	0xf0, 0xc7, 0x88, 0xbb, 0x89, 0xdb, 0x02, 0xfa, 0x03, 0x7a, 0x0e, 0x1a,
-	0x6b, 0x7b, 0x33, 0x63, 0x0c, 0xd5, 0x86, 0x0c, 0x7f, 0x6f, 0xf2, 0xfd,
-	0x41, 0x6d, 0x5b, 0x37, 0xd2, 0xfb, 0x9e, 0x0d, 0xf4, 0x12, 0xdf, 0x59,
-	0x32, 0x05, 0x19, 0x89, 0x2c, 0x50, 0xd7, 0x2f, 0x8c, 0x2e, 0xcf, 0x13,
-	0xc7, 0xf4, 0x83, 0x2f, 0xa4, 0x97, 0xfc, 0xa3, 0x4e, 0x69, 0x85, 0x9e,
-	0xea, 0x4e, 0x55, 0x50, 0x9f, 0x7e, 0xfe, 0x84, 0xf2, 0x0f, 0x5b, 0x90,
-	0xc2, 0x89, 0x03, 0xad, 0x13, 0xa0, 0x75, 0x42, 0xfb, 0x86, 0xfb, 0x61,
-	0x47, 0x22, 0xc7, 0x02, 0x5a, 0x6f, 0x89, 0x04, 0x6b, 0xb3, 0x9e, 0xf6,
-	0x7a, 0xfb, 0xe7, 0xe3, 0xc0, 0xbb, 0x7a, 0xd5, 0x9e, 0x2c, 0x10, 0x3b,
-	0x4e, 0x9c, 0x0e, 0xf6, 0xa3, 0xf8, 0x7b, 0xa9, 0x35, 0xc0, 0x01, 0x9c,
-	0x0f, 0x71, 0x08, 0x75, 0x4f, 0x30, 0x87, 0x16, 0xe9, 0x5a, 0xe0, 0x1c,
-	0x56, 0xe9, 0x8f, 0x33, 0xca, 0x72, 0x00, 0xfa, 0x3b, 0xaf, 0x68, 0xdd,
-	0x2d, 0x93, 0xa5, 0xf7, 0x69, 0xfa, 0x5b, 0x40, 0xff, 0x18, 0x64, 0x7b,
-	0x4d, 0x77, 0xe5, 0xab, 0xe3, 0xc8, 0xfb, 0x98, 0x90, 0x3c, 0xce, 0x57,
-	0xa9, 0xc7, 0xf4, 0x7c, 0x9a, 0x39, 0x9f, 0x8d, 0x3a, 0x6e, 0x33, 0xbe,
-	0xbe, 0x77, 0x03, 0x5f, 0x45, 0xf3, 0x35, 0x26, 0x0d, 0x0b, 0xca, 0xbf,
-	0x46, 0xbf, 0xe4, 0x35, 0xed, 0xe8, 0xc2, 0xe8, 0xf4, 0xbc, 0xf4, 0x33,
-	0x08, 0x95, 0x07, 0xdf, 0x50, 0x36, 0xd0, 0x20, 0xdd, 0xee, 0x05, 0xcc,
-	0x3b, 0x8f, 0xf5, 0x36, 0x8e, 0xf9, 0xf2, 0x4d, 0xfe, 0xe6, 0xab, 0xcd,
-	0xf0, 0xe9, 0x39, 0x36, 0x79, 0x46, 0xfa, 0x4d, 0x45, 0xcf, 0x2a, 0xbf,
-	0x41, 0xdf, 0x7d, 0xd5, 0x8d, 0xbc, 0xad, 0xd7, 0x33, 0x41, 0xec, 0xe0,
-	0x35, 0xd3, 0xdf, 0x17, 0x9b, 0xc5, 0x0e, 0x5a, 0xa0, 0xa3, 0x23, 0x8c,
-	0x13, 0x80, 0xf7, 0x8c, 0xf3, 0x5c, 0x8a, 0xd0, 0x17, 0x78, 0xa1, 0x04,
-	0x3d, 0x73, 0x9c, 0xd8, 0xa5, 0x55, 0xef, 0x8f, 0x1b, 0xb4, 0x0d, 0x8b,
-	0x2a, 0xdb, 0x21, 0x86, 0x49, 0x7c, 0x84, 0x32, 0xe4, 0x17, 0x99, 0x0f,
-	0xe8, 0xb8, 0x7b, 0x4f, 0xd4, 0x79, 0x21, 0x12, 0xe8, 0x84, 0x35, 0xba,
-	0xea, 0x63, 0x03, 0x1e, 0x30, 0xe5, 0xfb, 0x20, 0xb7, 0xb7, 0xc3, 0xff,
-	0xb7, 0x24, 0x9f, 0xe2, 0x3e, 0x1a, 0x54, 0x3e, 0x92, 0xe1, 0xec, 0x47,
-	0x59, 0x13, 0xca, 0x60, 0x4c, 0x4d, 0xcc, 0xdf, 0xf9, 0x3d, 0x99, 0x80,
-	0x8c, 0xe7, 0x53, 0x7d, 0xa0, 0x83, 0xf8, 0x0e, 0x58, 0xcb, 0x49, 0x31,
-	0x7e, 0x80, 0xbf, 0x7b, 0xa3, 0xfe, 0xbc, 0xf6, 0x20, 0xdf, 0x8c, 0x3a,
-	0x5d, 0xba, 0xce, 0x16, 0x61, 0x1c, 0x2a, 0x6f, 0xb6, 0x22, 0xed, 0xd9,
-	0x50, 0xf7, 0x43, 0xc8, 0xdf, 0xa2, 0xfb, 0x2f, 0xe0, 0xfd, 0x4d, 0xf8,
-	0x0d, 0xa1, 0xec, 0x66, 0x94, 0xb9, 0x28, 0xbb, 0x11, 0xf9, 0x0f, 0xe9,
-	0xb8, 0x44, 0xd0, 0xa6, 0x15, 0xf9, 0x47, 0xf1, 0x1e, 0xba, 0xc2, 0x7c,
-	0x05, 0xef, 0x6f, 0xc1, 0xef, 0xfa, 0x0d, 0x75, 0xda, 0x37, 0xe4, 0x4f,
-	0xae, 0xf2, 0xe0, 0x85, 0xd2, 0x55, 0xfa, 0x99, 0xf2, 0xcc, 0xfc, 0x2b,
-	0x3a, 0x7f, 0xfb, 0x86, 0xf2, 0xfb, 0x83, 0x7c, 0xdd, 0x1a, 0xc2, 0x0e,
-	0x9a, 0x01, 0xd6, 0xbd, 0xda, 0xf4, 0xd7, 0xe0, 0x3d, 0x7e, 0xbc, 0xa0,
-	0x14, 0xb4, 0x23, 0xf6, 0xbd, 0x3d, 0xbc, 0xbe, 0xaf, 0xff, 0xd6, 0xb0,
-	0x96, 0x6f, 0x09, 0x0d, 0x9f, 0x64, 0xd9, 0x4f, 0x1b, 0xd6, 0xd7, 0x79,
-	0x5f, 0xe3, 0x5a, 0x7e, 0x6b, 0x68, 0xf8, 0x38, 0xcb, 0xee, 0x6b, 0x5c,
-	0x5f, 0x67, 0xb8, 0x71, 0x6d, 0x1e, 0x6b, 0xba, 0x30, 0x92, 0xae, 0x50,
-	0x8e, 0xb1, 0x17, 0xaa, 0xa3, 0xd9, 0x19, 0xcf, 0x9b, 0x72, 0x57, 0x12,
-	0x61, 0xa1, 0x0d, 0x22, 0x66, 0x66, 0xf9, 0x53, 0x28, 0x07, 0xa6, 0xaa,
-	0x8d, 0x09, 0x75, 0xd2, 0xe6, 0xd8, 0xd8, 0xd2, 0xd8, 0x58, 0x65, 0x23,
-	0x59, 0x85, 0x65, 0x9f, 0x18, 0x05, 0xf6, 0xd2, 0xcf, 0x4f, 0xe2, 0xd9,
-	0xaa, 0xc7, 0xdf, 0xe8, 0xb7, 0x3c, 0x9a, 0x9d, 0xa7, 0xcd, 0x5b, 0x1a,
-	0xdd, 0x37, 0xcf, 0x3d, 0x7f, 0x0a, 0x7b, 0x3e, 0x24, 0xd3, 0xca, 0xfe,
-	0x91, 0x0e, 0xb6, 0x2b, 0x8f, 0x76, 0x2d, 0x31, 0xad, 0x8c, 0x3a, 0x4b,
-	0x61, 0xd9, 0x1f, 0xf7, 0xdb, 0x32, 0x6f, 0x2d, 0x05, 0x7b, 0xa0, 0x59,
-	0xa2, 0x69, 0xca, 0xa4, 0x9d, 0x82, 0x0f, 0x80, 0xf9, 0x1c, 0x19, 0x9d,
-	0x76, 0x28, 0x9f, 0x9f, 0x82, 0xdd, 0x6f, 0x96, 0x06, 0xa5, 0x6f, 0x1e,
-	0xd7, 0x63, 0x9d, 0xc2, 0x58, 0xdb, 0xd4, 0x7e, 0xca, 0x3a, 0x91, 0x04,
-	0xc6, 0x39, 0x64, 0x38, 0x7d, 0x18, 0x8f, 0x1e, 0x7b, 0xa7, 0x4c, 0xd5,
-	0xb8, 0x6f, 0xf6, 0x44, 0xd7, 0xfc, 0xf4, 0x39, 0xb4, 0x0b, 0xfc, 0x43,
-	0x8e, 0x57, 0x01, 0x3e, 0x84, 0x2c, 0xa7, 0x6d, 0x33, 0x1b, 0x86, 0x9d,
-	0x9f, 0x0f, 0xea, 0x90, 0xa6, 0x63, 0xa3, 0xc9, 0xa5, 0x24, 0xfa, 0xea,
-	0xa4, 0x0e, 0x83, 0xee, 0x0a, 0xe3, 0xc7, 0xbe, 0xd9, 0x0e, 0xb6, 0x68,
-	0x90, 0x76, 0x64, 0x0e, 0x76, 0xa4, 0x53, 0x0e, 0x97, 0x54, 0x1f, 0x16,
-	0xfb, 0x28, 0xea, 0xb6, 0x5d, 0x4b, 0x0d, 0xf0, 0xb1, 0x92, 0xe6, 0x8b,
-	0xb2, 0xd6, 0x76, 0x58, 0xfc, 0x76, 0x7e, 0xdf, 0x3f, 0xf1, 0x32, 0xf1,
-	0xfa, 0xbd, 0xdf, 0x2c, 0x61, 0xd0, 0x91, 0x43, 0x1f, 0x1c, 0x7f, 0xad,
-	0xef, 0xa0, 0xbf, 0xa4, 0x79, 0xfe, 0xb2, 0xbe, 0xb6, 0x69, 0xfc, 0x66,
-	0x5b, 0xb9, 0x5f, 0x6b, 0x6c, 0xce, 0xf7, 0x09, 0xc8, 0x83, 0x44, 0x72,
-	0xbd, 0xd0, 0x8b, 0xb5, 0x41, 0x2d, 0x23, 0x4f, 0xa2, 0xac, 0xde, 0xc7,
-	0xf2, 0xe5, 0xab, 0x00, 0x6c, 0x59, 0xc4, 0x3e, 0x0f, 0xa7, 0x33, 0x6d,
-	0x7e, 0xcc, 0xeb, 0x4a, 0x7e, 0x15, 0xe4, 0x06, 0x7d, 0x16, 0x57, 0xdb,
-	0x72, 0x4e, 0x4f, 0x8e, 0xbe, 0x34, 0x93, 0xc0, 0x9c, 0x7c, 0xbb, 0xe0,
-	0xf3, 0x9a, 0x36, 0x27, 0x24, 0xcb, 0x8e, 0x05, 0xff, 0x9d, 0x36, 0xde,
-	0x92, 0x97, 0x9d, 0xc0, 0xfe, 0xd0, 0x16, 0xa1, 0x7e, 0x8d, 0xb4, 0x91,
-	0xf6, 0x39, 0xcc, 0xcd, 0x93, 0x59, 0xd7, 0x97, 0xc1, 0x5e, 0xd8, 0x91,
-	0xff, 0x18, 0xb1, 0x8f, 0xd0, 0xcf, 0xbb, 0x18, 0xa9, 0x9f, 0x4f, 0x80,
-	0x15, 0x9e, 0xd0, 0x31, 0xe8, 0x39, 0x2d, 0x2f, 0x65, 0xc8, 0x4b, 0x9f,
-	0x65, 0x4a, 0x0f, 0x68, 0x47, 0x9d, 0xfe, 0x6e, 0xf8, 0x5b, 0xf4, 0xe5,
-	0x13, 0xa0, 0xc7, 0x84, 0xee, 0xd8, 0xa6, 0x7d, 0x87, 0xb7, 0xa2, 0xb4,
-	0x6d, 0x6d, 0x2a, 0xbe, 0x3d, 0xa7, 0xe4, 0xd9, 0x97, 0xef, 0xb0, 0x7e,
-	0x1f, 0xc8, 0x54, 0x98, 0x90, 0x46, 0xd6, 0xe2, 0xb8, 0xac, 0xbf, 0xa0,
-	0xeb, 0xcf, 0xa3, 0x7e, 0x08, 0x73, 0xf2, 0xbc, 0x49, 0x45, 0xef, 0x02,
-	0xf8, 0x1e, 0x96, 0xe2, 0xaa, 0xcc, 0x2f, 0x40, 0xe6, 0x29, 0xdf, 0x73,
-	0xd8, 0xaf, 0x20, 0xfe, 0x6e, 0xca, 0x7d, 0x45, 0x86, 0x4e, 0xef, 0x6f,
-	0x60, 0xcc, 0xd5, 0x32, 0xe8, 0x03, 0x53, 0x26, 0x3b, 0xe5, 0xb1, 0x52,
-	0xd2, 0x9c, 0xaa, 0x5b, 0xcb, 0x5d, 0xeb, 0xd6, 0x92, 0x32, 0xa0, 0xea,
-	0xa7, 0x58, 0xbf, 0x52, 0x27, 0x03, 0x8b, 0xf3, 0x57, 0x6a, 0x47, 0x19,
-	0x60, 0xbb, 0xcd, 0xfc, 0x05, 0xc6, 0x28, 0x3d, 0x6f, 0xd9, 0x25, 0xfe,
-	0x6f, 0x94, 0x82, 0x92, 0xb1, 0x90, 0x14, 0x5d, 0xee, 0xab, 0xac, 0x15,
-	0x11, 0x1b, 0x58, 0xe9, 0xf7, 0x41, 0x67, 0x26, 0x15, 0x15, 0x3f, 0xa6,
-	0x31, 0x81, 0x35, 0x58, 0x31, 0x3d, 0xef, 0x25, 0x47, 0xa4, 0x02, 0x1f,
-	0x78, 0x19, 0x69, 0xb1, 0x8a, 0x3d, 0xdb, 0x1c, 0x81, 0x0e, 0x08, 0x64,
-	0x3c, 0x26, 0x65, 0xd4, 0x59, 0xc4, 0xbb, 0xc7, 0xaa, 0x81, 0xc4, 0x78,
-	0x9e, 0x01, 0x1e, 0xed, 0x73, 0x7e, 0xea, 0xe5, 0xe3, 0xf5, 0x75, 0x03,
-	0x4c, 0x4c, 0x2c, 0x4b, 0x6c, 0x4a, 0x4c, 0xc9, 0x77, 0xc4, 0x89, 0x87,
-	0x40, 0x0b, 0xf7, 0x6c, 0xab, 0xc4, 0xd2, 0x76, 0x62, 0x44, 0x02, 0xdb,
-	0xff, 0x3a, 0x64, 0xa9, 0xe0, 0x35, 0x3a, 0x9d, 0xf2, 0x1c, 0xe4, 0xe6,
-	0xd9, 0x55, 0x1c, 0x63, 0x41, 0x8e, 0x68, 0x47, 0x3d, 0x39, 0xe7, 0x3a,
-	0xd6, 0xe7, 0x90, 0x7e, 0xc7, 0xfd, 0x00, 0xf9, 0xf6, 0x84, 0x48, 0x3f,
-	0x7c, 0x32, 0xe8, 0xf5, 0xd9, 0x00, 0xdb, 0xb7, 0xd2, 0x37, 0xd4, 0xb2,
-	0x74, 0x11, 0x7d, 0xda, 0xa6, 0x01, 0x50, 0x7b, 0x07, 0xea, 0xf9, 0x7b,
-	0x23, 0x28, 0x3b, 0x84, 0xba, 0xa4, 0x81, 0x7e, 0xfb, 0x77, 0xb1, 0x67,
-	0x3d, 0xef, 0x1e, 0xf7, 0xe5, 0x3a, 0x5d, 0xb3, 0x80, 0xf5, 0x57, 0x72,
-	0x3e, 0xd0, 0x26, 0x8c, 0xf3, 0x4a, 0x7f, 0xbb, 0xf2, 0x2b, 0xf9, 0x0c,
-	0x79, 0x1f, 0x20, 0x16, 0xb2, 0x14, 0xd6, 0x24, 0x6e, 0x78, 0x16, 0xbc,
-	0xff, 0xa4, 0xc2, 0x34, 0xc4, 0x6f, 0xa0, 0xbf, 0x44, 0x4c, 0xe1, 0x63,
-	0x69, 0x1f, 0xd7, 0x11, 0x5b, 0xa4, 0xb8, 0x36, 0x1a, 0x5f, 0xb0, 0x2d,
-	0xeb, 0xb1, 0x6d, 0xfd, 0xfa, 0xb1, 0xce, 0xb6, 0x50, 0xee, 0x38, 0xe5,
-	0x99, 0xf6, 0xb1, 0x4d, 0xf6, 0xa7, 0x1a, 0xc1, 0xf7, 0x76, 0x6d, 0xc7,
-	0x3f, 0x08, 0xcc, 0x06, 0xec, 0x6d, 0xd2, 0x87, 0x0a, 0x78, 0x7d, 0x23,
-	0xca, 0x7e, 0x0e, 0xfe, 0xb3, 0x0c, 0xfe, 0x95, 0xb2, 0x93, 0x0f, 0x61,
-	0x2f, 0x97, 0xb7, 0xf9, 0x31, 0x34, 0xae, 0x43, 0x80, 0x13, 0x02, 0xdc,
-	0x67, 0x6a, 0xbc, 0xcf, 0xb5, 0xf1, 0xe3, 0x6d, 0x86, 0xaa, 0x4b, 0x5f,
-	0xab, 0xde, 0xc7, 0xe5, 0x1e, 0xf6, 0xbc, 0x73, 0x6e, 0x80, 0x23, 0xeb,
-	0xfd, 0xc4, 0xc0, 0x07, 0x8c, 0x89, 0xd5, 0x4e, 0x4c, 0xf1, 0x47, 0x0d,
-	0x6b, 0x58, 0xe6, 0x1f, 0xbc, 0xb0, 0x43, 0x9f, 0x93, 0x38, 0x26, 0xf0,
-	0x07, 0x59, 0x97, 0xd8, 0xe6, 0x51, 0x8c, 0x11, 0x16, 0xab, 0x83, 0xf9,
-	0x1f, 0xeb, 0x36, 0x7c, 0xf6, 0xa4, 0x67, 0x67, 0xbd, 0x3c, 0x0f, 0xfa,
-	0xfe, 0x62, 0x73, 0x10, 0x03, 0xee, 0x54, 0xfa, 0x64, 0x4d, 0x2e, 0x02,
-	0x9a, 0x82, 0x71, 0x7d, 0xff, 0xb4, 0x1d, 0xb4, 0xdd, 0x05, 0x9b, 0xb2,
-	0xb3, 0xdd, 0xae, 0xf3, 0x45, 0xeb, 0x69, 0xaa, 0xc7, 0x57, 0x16, 0xc6,
-	0x68, 0x94, 0x9d, 0x1d, 0xe4, 0x5d, 0xa7, 0xb2, 0x2d, 0x6b, 0xeb, 0x41,
-	0xdb, 0xcf, 0xb1, 0x37, 0x96, 0xdf, 0x52, 0x47, 0xd7, 0x46, 0xcc, 0x47,
-	0x1f, 0xd7, 0xc7, 0x7c, 0x99, 0xb8, 0x27, 0xbb, 0xdc, 0x00, 0xdf, 0xd5,
-	0xd3, 0x41, 0x8c, 0x47, 0x9a, 0xa3, 0x75, 0x3e, 0xf2, 0xef, 0xea, 0x33,
-	0xaa, 0x39, 0x3d, 0x97, 0xc0, 0x97, 0x4e, 0xa2, 0xfe, 0x7f, 0x00, 0xdd,
-	0x7c, 0x26, 0xed, 0x01, 0x1e, 0x4c, 0xfa, 0x6d, 0x9b, 0x37, 0xc3, 0xfd,
-	0xdc, 0x27, 0x01, 0x6f, 0xda, 0xf5, 0xba, 0xd4, 0xfb, 0xe3, 0xea, 0xe7,
-	0xae, 0xd7, 0x1d, 0x37, 0xd6, 0xcd, 0xa9, 0x5f, 0x0a, 0x8b, 0x94, 0x85,
-	0xf7, 0x23, 0x0d, 0xfc, 0xa1, 0x01, 0xd8, 0x8e, 0x0c, 0xfc, 0x1f, 0xfa,
-	0x45, 0x97, 0xf9, 0x44, 0x3c, 0xc3, 0x1c, 0xcf, 0xc3, 0x47, 0x56, 0xb6,
-	0xc3, 0xb7, 0x8b, 0xc8, 0x43, 0x87, 0xd4, 0xee, 0xa6, 0x5c, 0x8d, 0x4f,
-	0x54, 0xdd, 0xf1, 0xc9, 0xea, 0xc0, 0x38, 0x7d, 0x07, 0x5f, 0xce, 0x50,
-	0xbf, 0x2a, 0x13, 0x06, 0xda, 0x65, 0x55, 0x3b, 0x15, 0xcb, 0xd8, 0xa4,
-	0x1f, 0xe1, 0x1e, 0x9c, 0xf0, 0xc7, 0x8a, 0x8d, 0xe7, 0xa0, 0x77, 0x16,
-	0x67, 0x61, 0xd7, 0x1c, 0x3b, 0x43, 0x59, 0xdc, 0xe7, 0xda, 0x23, 0x4a,
-	0xde, 0xe2, 0xf6, 0x18, 0xd7, 0xaf, 0x32, 0xfb, 0x5e, 0xe8, 0x4d, 0x4f,
-	0xee, 0x84, 0xfe, 0x7b, 0x00, 0xf2, 0x29, 0x67, 0xa0, 0xfc, 0xce, 0x40,
-	0x61, 0x9d, 0x89, 0x8b, 0x71, 0xa2, 0x53, 0xa2, 0x47, 0x13, 0x12, 0x39,
-	0x4a, 0xff, 0x2b, 0x69, 0xde, 0x29, 0x02, 0x3b, 0xf8, 0xe2, 0xcd, 0x86,
-	0xd8, 0x83, 0x19, 0x49, 0xc2, 0x87, 0xec, 0x33, 0x2b, 0x48, 0x8b, 0x92,
-	0x4c, 0x9d, 0x46, 0x5f, 0xd1, 0x33, 0xa8, 0x8b, 0x76, 0x4d, 0xcb, 0x16,
-	0x7e, 0x1d, 0xd2, 0xbc, 0xec, 0xef, 0x8f, 0xe6, 0xe5, 0xf5, 0xf1, 0x9b,
-	0xa1, 0xd5, 0xf8, 0x0d, 0xdf, 0xbf, 0xad, 0xe3, 0x4e, 0x5f, 0xd2, 0xbe,
-	0x0c, 0xe5, 0x82, 0xf6, 0x4c, 0xf9, 0x63, 0xd0, 0xdd, 0x5f, 0x82, 0xff,
-	0xeb, 0x48, 0xae, 0x04, 0x9c, 0x9e, 0xf6, 0xe4, 0x69, 0xb7, 0xe0, 0x65,
-	0x07, 0x3c, 0x79, 0xdd, 0x75, 0x0a, 0x79, 0xb1, 0xdf, 0xa6, 0x8e, 0xfb,
-	0xb1, 0xfb, 0x21, 0xd9, 0xd3, 0x66, 0xef, 0xc9, 0x84, 0x0a, 0x5e, 0x8b,
-	0xd3, 0x2c, 0x57, 0xa7, 0x0f, 0xc9, 0xbe, 0x1d, 0x2b, 0x66, 0x58, 0x32,
-	0x57, 0x03, 0x0b, 0x26, 0xf2, 0x4a, 0x3f, 0xbd, 0xa1, 0x7c, 0xea, 0xfb,
-	0xbb, 0x0f, 0xc9, 0xd6, 0x1d, 0xb6, 0x79, 0x29, 0x4c, 0x9c, 0x76, 0x08,
-	0xf8, 0xdf, 0x4e, 0xe4, 0xc2, 0x8e, 0xb9, 0x5b, 0xec, 0x91, 0x4f, 0x0b,
-	0xcf, 0x8c, 0x1d, 0xe9, 0x3a, 0xea, 0x24, 0x1e, 0x0c, 0xf5, 0x1c, 0x78,
-	0x90, 0x3e, 0xdd, 0x19, 0xe6, 0x3d, 0x89, 0xed, 0x30, 0xf1, 0x1c, 0x97,
-	0xae, 0x13, 0x96, 0x24, 0xc1, 0x97, 0x5e, 0xc5, 0x13, 0x9e, 0x5d, 0x25,
-	0xa4, 0xe7, 0x28, 0x71, 0x93, 0xe2, 0x4d, 0x2f, 0x78, 0x93, 0x02, 0x6f,
-	0xe0, 0x47, 0xf5, 0x99, 0x97, 0x90, 0x9e, 0x97, 0xe4, 0xe0, 0x9b, 0xe0,
-	0x4d, 0x2f, 0x78, 0xd3, 0x73, 0xc6, 0x42, 0x7b, 0xf4, 0xb1, 0xdc, 0x85,
-	0xb4, 0x59, 0x3e, 0x72, 0x55, 0x07, 0x9e, 0x1d, 0x49, 0x1e, 0x8d, 0x61,
-	0x8c, 0x90, 0xec, 0xea, 0x2e, 0xc8, 0xf0, 0x0e, 0xf8, 0x63, 0xf1, 0x43,
-	0x72, 0x01, 0xb6, 0xa7, 0x04, 0xbf, 0xe0, 0xe9, 0x41, 0x7b, 0x6c, 0x05,
-	0xfa, 0xb3, 0x76, 0x97, 0x27, 0xaf, 0xec, 0xf8, 0x2b, 0x2f, 0x71, 0x95,
-	0xbd, 0x47, 0x42, 0x03, 0x32, 0x5d, 0x52, 0x36, 0x21, 0x91, 0x0d, 0x2b,
-	0x2c, 0x86, 0x39, 0x16, 0x60, 0x57, 0x78, 0x16, 0xee, 0x40, 0xbf, 0x7f,
-	0x5a, 0x1e, 0x28, 0x4f, 0xe1, 0x07, 0x1f, 0x73, 0x86, 0x75, 0x0f, 0xc0,
-	0x87, 0x7b, 0x48, 0xf6, 0xcf, 0x00, 0x2f, 0xa6, 0x41, 0xf7, 0x80, 0x03,
-	0x1f, 0xee, 0x7c, 0xa3, 0xb4, 0xa2, 0x0c, 0xbc, 0x1d, 0xab, 0x6d, 0xf4,
-	0xdd, 0x56, 0xb0, 0x0e, 0x83, 0xf2, 0x97, 0xb5, 0x01, 0xf9, 0x6a, 0xad,
-	0x5f, 0xbe, 0x0c, 0x7b, 0xf2, 0x6c, 0xad, 0x13, 0x7b, 0x25, 0x81, 0x35,
-	0x49, 0x63, 0x7d, 0x5c, 0xf9, 0x4a, 0x2d, 0x25, 0x5f, 0x02, 0xaf, 0x9e,
-	0xc3, 0x6f, 0xb8, 0x94, 0x92, 0x5d, 0xa5, 0x7e, 0xbd, 0x46, 0x5c, 0x1f,
-	0x07, 0xf4, 0x38, 0x98, 0xbb, 0xfd, 0x54, 0x01, 0xfb, 0x6f, 0xb1, 0xe6,
-	0xbc, 0x55, 0x91, 0xc7, 0x1a, 0x19, 0x5f, 0x3e, 0xb5, 0x6a, 0x53, 0x0a,
-	0x9e, 0xe9, 0xd8, 0x47, 0x26, 0xb0, 0x0e, 0x15, 0xec, 0xd3, 0x31, 0xc5,
-	0xfb, 0x35, 0x7b, 0x53, 0xf1, 0xed, 0x4d, 0x30, 0xbf, 0xd9, 0xbc, 0x7c,
-	0x47, 0xb2, 0x73, 0xd3, 0xb2, 0xef, 0xb8, 0x27, 0xbf, 0xe3, 0x7a, 0x90,
-	0x63, 0xea, 0xdf, 0x01, 0xea, 0x75, 0x6b, 0x22, 0x6c, 0x28, 0xff, 0xc9,
-	0xc7, 0x2a, 0xbd, 0xdb, 0xb1, 0x67, 0x53, 0x19, 0x63, 0x4a, 0x92, 0x73,
-	0x53, 0xd2, 0x35, 0x07, 0x59, 0x70, 0xd9, 0xd7, 0x8a, 0x69, 0x5c, 0x26,
-	0x0f, 0x1c, 0xc7, 0x1e, 0xcc, 0x89, 0x63, 0xbe, 0x25, 0x29, 0x8c, 0x7f,
-	0x50, 0xba, 0xd1, 0xc6, 0x41, 0x9b, 0x4b, 0x6a, 0xec, 0x16, 0x8c, 0xdd,
-	0x28, 0x87, 0xe3, 0x36, 0x64, 0x8d, 0x76, 0xfb, 0xff, 0x48, 0xb6, 0xc2,
-	0xf4, 0x6f, 0x25, 0x7b, 0xea, 0x91, 0x98, 0x34, 0xf3, 0x19, 0xaa, 0x61,
-	0x81, 0xe5, 0x5d, 0x48, 0x59, 0xee, 0xc0, 0x77, 0xfe, 0x89, 0x64, 0xcf,
-	0x72, 0xec, 0xb7, 0x50, 0xfe, 0x8a, 0x64, 0x8f, 0xfd, 0x1c, 0xf9, 0x0b,
-	0x48, 0xdf, 0x46, 0x3a, 0x26, 0x5d, 0xc7, 0x24, 0x94, 0x3d, 0xfb, 0x6d,
-	0xe4, 0x23, 0x48, 0x0f, 0xa3, 0xde, 0x6d, 0xa0, 0xef, 0xaf, 0xd1, 0x5f,
-	0x06, 0x7a, 0xee, 0xc3, 0x9a, 0x7e, 0x96, 0xb3, 0x8c, 0xef, 0x0e, 0x43,
-	0xa7, 0xfd, 0x0f, 0x8f, 0xf1, 0x44, 0xf5, 0xbc, 0xc8, 0x3c, 0x75, 0x1b,
-	0x9f, 0xa7, 0xc0, 0x93, 0x83, 0xc8, 0x7b, 0xf2, 0x90, 0x4b, 0x1b, 0x73,
-	0x93, 0x8c, 0x9b, 0x05, 0xaf, 0x19, 0x58, 0xa2, 0x05, 0xfb, 0x60, 0x6a,
-	0xe7, 0xe6, 0xfb, 0xe0, 0x48, 0xcf, 0x21, 0x69, 0xda, 0x11, 0xcc, 0x3f,
-	0x98, 0xaf, 0x63, 0xfe, 0x48, 0xf1, 0xc1, 0x2e, 0x3c, 0x28, 0x9c, 0x87,
-	0x93, 0x78, 0xdc, 0xe8, 0xd9, 0xf3, 0x00, 0xf6, 0x81, 0x71, 0x96, 0x79,
-	0x7f, 0x1f, 0x18, 0x67, 0xa1, 0x1b, 0x16, 0xe0, 0x17, 0x2e, 0x74, 0x4a,
-	0xe3, 0xb1, 0xb5, 0x7d, 0xd0, 0x70, 0xec, 0x57, 0xef, 0x83, 0xc6, 0xb3,
-	0xa8, 0x77, 0x96, 0x3c, 0x43, 0x1f, 0xa7, 0xc8, 0xb3, 0x0e, 0xa4, 0x9f,
-	0xc6, 0x5c, 0x49, 0x7b, 0x23, 0x68, 0xf7, 0xb1, 0xd0, 0xcd, 0x90, 0xf7,
-	0xfb, 0x77, 0x1c, 0xd4, 0xe5, 0xff, 0xd9, 0x1b, 0x89, 0xdb, 0x65, 0x09,
-	0x91, 0xa7, 0xa8, 0x5b, 0x21, 0x0f, 0x6f, 0x69, 0x92, 0xe6, 0x03, 0xd2,
-	0x45, 0xfe, 0x55, 0x76, 0x23, 0x5f, 0xf0, 0xa2, 0x4e, 0x8b, 0xe6, 0x27,
-	0xb0, 0xd1, 0x00, 0xcb, 0x5f, 0x83, 0xcc, 0x10, 0xa3, 0xbe, 0x21, 0xfb,
-	0x66, 0x3c, 0x19, 0x77, 0x39, 0xff, 0xef, 0x63, 0xfe, 0x99, 0x1d, 0x71,
-	0x59, 0xb1, 0xe2, 0xe0, 0xc9, 0x22, 0x74, 0xfb, 0x05, 0xf1, 0xf9, 0xc0,
-	0x33, 0x89, 0x5d, 0xe2, 0x24, 0x86, 0xc5, 0x49, 0xbd, 0x09, 0x3e, 0x0c,
-	0x43, 0xf6, 0x73, 0x35, 0xca, 0xce, 0xab, 0x32, 0x04, 0x99, 0xf8, 0x9e,
-	0x6b, 0xa7, 0x80, 0x7f, 0xa0, 0x2f, 0x28, 0x17, 0x94, 0x89, 0x56, 0xa5,
-	0x93, 0x16, 0x5c, 0xfb, 0x89, 0x8a, 0x5c, 0x27, 0x0b, 0xed, 0xa4, 0x1d,
-	0xef, 0x8e, 0x29, 0x7b, 0x91, 0x9a, 0x30, 0xba, 0xa1, 0xa3, 0x53, 0x62,
-	0xf6, 0x7c, 0xb1, 0x31, 0xb8, 0xbf, 0x92, 0x9f, 0x0b, 0xc9, 0x54, 0x0f,
-	0xd7, 0x8a, 0xfd, 0x22, 0x5f, 0x29, 0x78, 0x11, 0xe7, 0x2d, 0xef, 0x64,
-	0x87, 0x25, 0x9f, 0xec, 0x59, 0x95, 0xcb, 0xb2, 0x88, 0xbf, 0x2f, 0x86,
-	0xd4, 0x7a, 0x04, 0x74, 0x07, 0x73, 0x09, 0xde, 0xf5, 0xd7, 0xbd, 0xe3,
-	0x5c, 0x28, 0xeb, 0xab, 0x7b, 0xc7, 0xba, 0x9c, 0xd6, 0x9f, 0x41, 0x9e,
-	0xec, 0x27, 0x8a, 0xf2, 0x3a, 0x64, 0x0f, 0x3c, 0x3c, 0xcb, 0x94, 0x3c,
-	0x9c, 0x82, 0xdc, 0xbf, 0x26, 0xbb, 0xe6, 0xb8, 0x67, 0x5e, 0xc3, 0x5c,
-	0x95, 0x2e, 0x81, 0x8e, 0x60, 0x7f, 0x9e, 0x4c, 0xbb, 0xdd, 0xa9, 0x53,
-	0x72, 0x5d, 0x62, 0x12, 0x7e, 0xe6, 0x84, 0xe9, 0xc9, 0xb2, 0x5b, 0x90,
-	0xe5, 0x41, 0xb4, 0xa9, 0x7c, 0x1a, 0xbf, 0x79, 0x3d, 0xb7, 0x47, 0xc0,
-	0x77, 0xdb, 0x2a, 0x1b, 0x9f, 0x01, 0xdf, 0x1f, 0x92, 0xe4, 0xb1, 0x55,
-	0x5d, 0x03, 0xb9, 0xf3, 0x75, 0x4d, 0xf2, 0xac, 0x29, 0x95, 0x92, 0x23,
-	0x1f, 0xa3, 0x0e, 0x29, 0x71, 0x5e, 0xd0, 0x31, 0x3c, 0xdf, 0x2f, 0x41,
-	0xcf, 0x94, 0xa0, 0x53, 0xa0, 0x43, 0xbe, 0x8c, 0xf2, 0x2f, 0xa1, 0xce,
-	0x73, 0xf0, 0x99, 0x9e, 0x05, 0xde, 0x3b, 0x07, 0x1c, 0xf1, 0x4c, 0x29,
-	0xa3, 0xfd, 0x57, 0x35, 0x5f, 0xd8, 0x2c, 0xe5, 0xef, 0x48, 0xa5, 0x4c,
-	0x7e, 0xfc, 0x44, 0xad, 0x6d, 0xd6, 0xdd, 0x46, 0x6c, 0x05, 0xca, 0x44,
-	0xca, 0xe5, 0x80, 0x27, 0xd4, 0x7d, 0x3c, 0x1b, 0x0a, 0x74, 0x65, 0xcb,
-	0x06, 0x5d, 0x29, 0xf2, 0x62, 0xd5, 0xc7, 0x90, 0xc4, 0xc4, 0xc5, 0x19,
-	0x6b, 0xf5, 0x0c, 0xb5, 0x08, 0xbb, 0x79, 0x1e, 0xbe, 0x45, 0x2c, 0xfd,
-	0x2d, 0x89, 0x9d, 0xf0, 0xbc, 0x1f, 0xc0, 0x6e, 0x16, 0xb0, 0x26, 0x46,
-	0x08, 0xe5, 0x4b, 0x7c, 0x47, 0xb9, 0xa7, 0x6c, 0x87, 0x78, 0x96, 0x22,
-	0x2f, 0xa3, 0xac, 0xa2, 0x7c, 0xae, 0x6f, 0x83, 0x1e, 0x4d, 0x9f, 0x2a,
-	0x63, 0xbd, 0x46, 0xc9, 0x8d, 0xa7, 0xe0, 0xd7, 0xf4, 0x99, 0x8d, 0x68,
-	0x5f, 0x5e, 0x62, 0x1b, 0x7b, 0x90, 0x57, 0xb9, 0x5e, 0x5e, 0x62, 0x79,
-	0xa7, 0x5c, 0x80, 0xff, 0x49, 0x1a, 0x2a, 0xf3, 0x69, 0xf1, 0xe3, 0xc5,
-	0xd4, 0x57, 0xa4, 0x15, 0x79, 0xf0, 0x2b, 0x5b, 0xa2, 0x9d, 0x8d, 0x48,
-	0x21, 0x41, 0x5e, 0x27, 0xe4, 0xfc, 0xcc, 0x1f, 0x37, 0x31, 0x1e, 0x9b,
-	0x75, 0xf8, 0x1c, 0xc4, 0x37, 0xcc, 0x77, 0x10, 0xdf, 0x60, 0x4c, 0x23,
-	0x02, 0x5b, 0xa6, 0xe2, 0x1c, 0x48, 0xad, 0x3a, 0x9f, 0x97, 0xef, 0x7d,
-	0x6c, 0xb4, 0x86, 0x19, 0x89, 0x21, 0x39, 0x5f, 0xbb, 0xb0, 0x02, 0xfd,
-	0xd1, 0x9e, 0x7e, 0x49, 0xee, 0x5e, 0xf0, 0xe7, 0x67, 0x9c, 0x12, 0xde,
-	0xe3, 0x91, 0x4b, 0xf3, 0xb6, 0x7b, 0x51, 0x78, 0x06, 0xe2, 0x62, 0xbd,
-	0xfe, 0xa0, 0x09, 0xfa, 0x6b, 0x30, 0x63, 0x7c, 0xbb, 0xc9, 0xc7, 0x67,
-	0x11, 0x99, 0x9a, 0xe1, 0x99, 0x2b, 0x74, 0x1b, 0x70, 0xe3, 0xef, 0x45,
-	0xf0, 0x5c, 0x65, 0x1e, 0x7e, 0xa8, 0xef, 0xc3, 0xe2, 0xd9, 0xef, 0x8f,
-	0x3c, 0x37, 0x16, 0x38, 0xf7, 0x90, 0xdc, 0x0d, 0x74, 0x22, 0xe8, 0xbf,
-	0x4b, 0x8f, 0xd5, 0x75, 0x2a, 0xc5, 0xf8, 0xb5, 0x24, 0xa1, 0x2f, 0xb2,
-	0xf0, 0x1f, 0x73, 0xf1, 0x4e, 0x8d, 0xc7, 0xf9, 0x6e, 0x23, 0xde, 0x0c,
-	0xfc, 0xba, 0x94, 0x7c, 0xbe, 0x14, 0x60, 0xbd, 0x14, 0x6c, 0xac, 0x44,
-	0x46, 0x7a, 0x3d, 0xf9, 0x81, 0x4b, 0x7e, 0xf5, 0x23, 0xef, 0xca, 0x91,
-	0xda, 0x2f, 0x3b, 0x5b, 0xad, 0xff, 0x6b, 0x01, 0x8d, 0xfc, 0x81, 0x3e,
-	0xe0, 0x23, 0xd2, 0x6e, 0xc0, 0x9e, 0x17, 0x81, 0xbb, 0x8c, 0x33, 0x9d,
-	0xea, 0x9d, 0x01, 0x6c, 0x50, 0x99, 0x81, 0x6e, 0x3c, 0xc3, 0xf3, 0x66,
-	0xe8, 0xb6, 0x33, 0x51, 0x29, 0xce, 0x52, 0x2e, 0xa5, 0xdd, 0xc0, 0x7a,
-	0xb1, 0x7e, 0x65, 0xa6, 0x13, 0x69, 0x0b, 0x52, 0x4b, 0xf5, 0x53, 0x99,
-	0x71, 0x54, 0xfb, 0xca, 0x4c, 0x4a, 0xb5, 0xab, 0xcc, 0xf4, 0x23, 0x75,
-	0xa5, 0xe1, 0x0c, 0x9c, 0xa5, 0x33, 0x3d, 0x32, 0x75, 0x12, 0xf6, 0x65,
-	0xc0, 0x50, 0x77, 0x35, 0x26, 0x60, 0x7f, 0x22, 0xf0, 0xac, 0x2e, 0x9a,
-	0x83, 0xc0, 0x58, 0x37, 0x01, 0x83, 0xdc, 0x24, 0xce, 0x09, 0xce, 0x9f,
-	0xba, 0xf7, 0x3c, 0x63, 0x5e, 0x89, 0x4f, 0x48, 0x46, 0xf6, 0xcf, 0x36,
-	0x62, 0xbf, 0x46, 0xcc, 0xa2, 0x74, 0x9b, 0xc3, 0xc8, 0xe7, 0xcb, 0xe4,
-	0xdb, 0xbd, 0xca, 0x5f, 0xcb, 0xba, 0x37, 0x34, 0x4b, 0x73, 0x1a, 0x63,
-	0xbc, 0x93, 0xf6, 0xbd, 0x90, 0x3f, 0x47, 0xf7, 0x91, 0x06, 0x3d, 0xf5,
-	0xfc, 0xe0, 0x39, 0x73, 0xe6, 0x57, 0x9c, 0x33, 0x53, 0xae, 0xc9, 0xdf,
-	0x7b, 0xe5, 0xbc, 0x93, 0x96, 0x97, 0x9d, 0x94, 0x5c, 0x70, 0x76, 0xca,
-	0x37, 0x61, 0xa7, 0x5f, 0x72, 0xce, 0x34, 0x11, 0x0b, 0x54, 0xd4, 0xd9,
-	0x5d, 0xb0, 0x56, 0x8e, 0x8e, 0x9d, 0xff, 0x50, 0x96, 0x67, 0x88, 0x9d,
-	0xbd, 0xdb, 0xf6, 0xb9, 0x05, 0xda, 0x2d, 0xd0, 0x40, 0xac, 0x56, 0x80,
-	0xfd, 0x3b, 0x24, 0xc3, 0x2e, 0xed, 0x9e, 0xb2, 0x51, 0x89, 0x61, 0x7f,
-	0x3f, 0xbb, 0x79, 0xe8, 0xd5, 0xf3, 0xb3, 0xd8, 0x4f, 0x42, 0xf9, 0xc7,
-	0x73, 0x99, 0xeb, 0xee, 0xc8, 0xe3, 0x25, 0xce, 0xb3, 0xb8, 0xbd, 0x59,
-	0xc2, 0x32, 0xa2, 0xf0, 0x42, 0xab, 0xbc, 0xb8, 0xb4, 0x45, 0x0c, 0x58,
-	0x28, 0xe3, 0xda, 0xa8, 0xba, 0xe5, 0x42, 0x9f, 0x5b, 0xda, 0x78, 0xb6,
-	0xf6, 0x87, 0xe0, 0x0d, 0xfd, 0x7f, 0xcc, 0xad, 0x8d, 0x33, 0x09, 0xf2,
-	0xfd, 0xd8, 0x5f, 0x7c, 0x0e, 0x49, 0xce, 0x89, 0xe3, 0x99, 0x29, 0xf7,
-	0x1c, 0x63, 0x63, 0x61, 0xf1, 0x31, 0xf7, 0x21, 0xf5, 0xbe, 0xd1, 0xb9,
-	0x15, 0xb8, 0x8e, 0xf2, 0x8a, 0x74, 0xd9, 0x1f, 0x37, 0x07, 0x1c, 0x97,
-	0xef, 0xe7, 0x1d, 0x1b, 0x3b, 0x55, 0xc0, 0x5e, 0x98, 0x50, 0xf5, 0x07,
-	0xe4, 0xa5, 0x99, 0x52, 0xb3, 0xbf, 0x3f, 0x06, 0xf5, 0x33, 0xdf, 0xd3,
-	0xa7, 0x62, 0x8c, 0xe4, 0x99, 0xd1, 0x69, 0xe7, 0xa2, 0xde, 0x3f, 0x12,
-	0xba, 0xb3, 0x17, 0x38, 0xf4, 0x68, 0x03, 0xe6, 0x62, 0x5b, 0x56, 0xc8,
-	0xe8, 0x30, 0x80, 0xe3, 0x87, 0x95, 0xcd, 0xed, 0x55, 0x31, 0xe8, 0x53,
-	0xa9, 0x56, 0xa9, 0x98, 0x8e, 0xba, 0x93, 0xb7, 0x62, 0xee, 0x20, 0xd6,
-	0xc7, 0xaf, 0x09, 0x65, 0xdd, 0x48, 0x1b, 0x91, 0xbe, 0x5f, 0x8a, 0xc7,
-	0xcf, 0xe8, 0xf1, 0xa2, 0x1b, 0xf2, 0x1f, 0xd1, 0xe9, 0x67, 0xb5, 0x3f,
-	0xc5, 0x71, 0xa2, 0xe2, 0x7c, 0xa1, 0x45, 0xba, 0x8f, 0x9a, 0xc0, 0xb6,
-	0x09, 0x60, 0xdd, 0x4e, 0x49, 0x1d, 0xb5, 0xe4, 0xda, 0xa3, 0x41, 0x9c,
-	0xe9, 0x2b, 0xa3, 0x49, 0x15, 0xd7, 0xfc, 0xf2, 0xa8, 0x53, 0x56, 0xe7,
-	0xed, 0xfa, 0xee, 0xe0, 0x8a, 0xbe, 0x53, 0xf8, 0xca, 0x68, 0xaf, 0x4a,
-	0xbf, 0x3d, 0x9a, 0x52, 0xe9, 0xab, 0xa3, 0xd7, 0x56, 0x7d, 0xff, 0xa8,
-	0xb8, 0x98, 0x92, 0xcf, 0x95, 0x88, 0x2f, 0x07, 0x80, 0x1d, 0x5d, 0xe8,
-	0x99, 0x7e, 0xe8, 0x99, 0x14, 0xf4, 0xcc, 0x20, 0xf5, 0x0c, 0xf4, 0xf6,
-	0xab, 0xd0, 0xdb, 0xae, 0x7c, 0x0f, 0xf2, 0xfa, 0x8c, 0xdb, 0x08, 0x5c,
-	0xe8, 0x79, 0xfe, 0x5c, 0xed, 0x27, 0x56, 0xb0, 0xbe, 0x95, 0xd3, 0x12,
-	0x6b, 0x83, 0x0e, 0xda, 0xb1, 0xd0, 0x20, 0x8b, 0x71, 0xcf, 0x9b, 0x73,
-	0x1d, 0xb9, 0x84, 0xfa, 0x59, 0x87, 0xfb, 0xf8, 0x6f, 0x9a, 0xe9, 0x8f,
-	0x5d, 0x9a, 0xd9, 0x09, 0x9d, 0x44, 0x79, 0x8f, 0x49, 0x65, 0x3c, 0x21,
-	0x4b, 0xf0, 0xcf, 0xd6, 0xea, 0xa4, 0xf0, 0xcc, 0xfd, 0xff, 0x13, 0xd4,
-	0x4d, 0xc1, 0x3e, 0x98, 0xb2, 0xdc, 0x6b, 0xc9, 0xa9, 0x5e, 0x7b, 0xd0,
-	0x32, 0xa8, 0xbb, 0x2c, 0x29, 0xc3, 0xbf, 0xaf, 0x94, 0x58, 0x9f, 0xf5,
-	0xb0, 0x3f, 0x4b, 0x7e, 0xbb, 0xe9, 0x52, 0xa0, 0x27, 0x06, 0x18, 0x7b,
-	0x8c, 0xe4, 0x7a, 0x7d, 0x1b, 0x60, 0x18, 0x8d, 0x90, 0x03, 0x17, 0xfc,
-	0x1f, 0x47, 0xf9, 0x00, 0xef, 0x9a, 0xa0, 0x8c, 0x58, 0x28, 0xb6, 0x85,
-	0x18, 0x31, 0xe7, 0x8e, 0xa3, 0x8c, 0x6d, 0xec, 0x44, 0x12, 0xe5, 0x63,
-	0x92, 0x4c, 0xe4, 0xd5, 0xbd, 0xb7, 0x0e, 0x94, 0xb1, 0x8f, 0xb0, 0x8e,
-	0xc1, 0x74, 0x6c, 0xf1, 0xcf, 0x7d, 0x83, 0xf2, 0x3e, 0x15, 0x0f, 0xc8,
-	0x98, 0x2e, 0xf6, 0x03, 0xcb, 0x92, 0x26, 0xdb, 0xe5, 0x5c, 0x57, 0xe9,
-	0xc2, 0x7b, 0xaa, 0x3c, 0xb7, 0x8b, 0xc9, 0xdd, 0xd5, 0x16, 0xc9, 0x55,
-	0x1b, 0xae, 0xa0, 0xff, 0x83, 0x3d, 0x79, 0x3e, 0x61, 0x0a, 0xef, 0x60,
-	0xf8, 0xfb, 0x3c, 0xb2, 0x93, 0x7b, 0x02, 0x7c, 0x87, 0xfd, 0x7d, 0x0e,
-	0xf3, 0x7d, 0x16, 0xf6, 0xf7, 0x1c, 0xec, 0xef, 0x33, 0xa5, 0x35, 0xfd,
-	0xe1, 0xdb, 0x5d, 0xea, 0x80, 0xa7, 0xb0, 0x66, 0x63, 0xc0, 0xfd, 0xbb,
-	0xe1, 0x0f, 0x8c, 0x00, 0xfb, 0x0f, 0x61, 0xfd, 0xd2, 0x58, 0xbb, 0x71,
-	0xde, 0x55, 0xc2, 0x3a, 0x0e, 0xaa, 0xb3, 0xe5, 0x59, 0x75, 0xdf, 0xe3,
-	0x87, 0xca, 0xf6, 0x3e, 0x56, 0x32, 0x60, 0x1f, 0x0a, 0xde, 0x76, 0xc7,
-	0x06, 0xfe, 0x5b, 0xdd, 0xcf, 0x83, 0x2f, 0x42, 0xaf, 0xfc, 0x1d, 0xe8,
-	0x7a, 0x76, 0x96, 0xf6, 0x1c, 0x75, 0x7c, 0xbc, 0xed, 0x32, 0xbe, 0x85,
-	0xfd, 0x7c, 0xe4, 0xbc, 0xac, 0x00, 0x77, 0x64, 0x28, 0xc7, 0xf0, 0x1f,
-	0xec, 0x67, 0xca, 0xd2, 0x43, 0x1d, 0x58, 0xe6, 0x5e, 0x19, 0x38, 0x96,
-	0x00, 0xd6, 0x03, 0x92, 0x57, 0x67, 0xa9, 0x78, 0x3e, 0xbb, 0x55, 0x0c,
-	0xe2, 0x3d, 0xf7, 0x2a, 0x94, 0x51, 0x6f, 0x04, 0x18, 0x69, 0x65, 0xb0,
-	0x5d, 0x32, 0x3b, 0xda, 0x95, 0xee, 0xb0, 0xdd, 0x97, 0x31, 0xee, 0x2e,
-	0x69, 0x04, 0x86, 0x2b, 0x60, 0x8c, 0x83, 0xf2, 0x37, 0x2e, 0xe3, 0x52,
-	0xbe, 0xef, 0x07, 0x5a, 0x62, 0xe0, 0x59, 0xd3, 0x3e, 0xc7, 0x8c, 0xed,
-	0xaa, 0xb1, 0xff, 0x98, 0xc2, 0x58, 0x39, 0x61, 0xff, 0xb0, 0x13, 0x18,
-	0x33, 0x79, 0x8c, 0xb2, 0xdf, 0x87, 0x75, 0xfb, 0x2d, 0x60, 0x20, 0x72,
-	0xf5, 0x5b, 0x5b, 0xfc, 0xfd, 0x42, 0xfa, 0x57, 0x88, 0x27, 0x18, 0xf7,
-	0xf7, 0xfd, 0xf2, 0x55, 0xda, 0x06, 0x40, 0xef, 0x73, 0x5b, 0x82, 0xf3,
-	0xe3, 0xae, 0x63, 0xbe, 0xbd, 0xee, 0x3a, 0x8b, 0x56, 0x73, 0xd2, 0xc1,
-	0x93, 0x68, 0x43, 0xae, 0x95, 0xdb, 0x23, 0x7e, 0x3f, 0xc6, 0x82, 0x09,
-	0x59, 0xa5, 0x1e, 0xe8, 0x80, 0x9c, 0x33, 0x4f, 0x9d, 0x42, 0x9d, 0x40,
-	0x59, 0x70, 0xa4, 0x58, 0x83, 0x4e, 0x68, 0xed, 0x94, 0x32, 0x79, 0xb6,
-	0x40, 0x3d, 0xf1, 0x43, 0x99, 0xde, 0xa0, 0x2b, 0x87, 0x24, 0xf0, 0x6b,
-	0x5b, 0x24, 0x9a, 0x76, 0xcc, 0x7b, 0xd4, 0x1c, 0x7d, 0x7d, 0xb9, 0x9f,
-	0xf8, 0x73, 0x36, 0x63, 0xb7, 0x8b, 0xc6, 0x9e, 0x0a, 0x3f, 0x7d, 0x1f,
-	0x73, 0x65, 0x1f, 0x8a, 0x4f, 0x83, 0x43, 0xbe, 0x2f, 0xa0, 0xe2, 0x7c,
-	0xc0, 0xc1, 0x89, 0xbf, 0x83, 0xae, 0xcd, 0x11, 0x97, 0x80, 0xcf, 0x5d,
-	0x73, 0x94, 0xa3, 0xed, 0xd4, 0x65, 0xc0, 0x79, 0x29, 0xea, 0x6b, 0x59,
-	0x3a, 0x06, 0xcc, 0x65, 0xdc, 0x2a, 0x79, 0xca, 0x2b, 0xef, 0x48, 0x2c,
-	0x19, 0x32, 0x3d, 0xdf, 0x2a, 0xdd, 0x0b, 0x8c, 0xa9, 0x7e, 0xb3, 0x59,
-	0x5a, 0x19, 0x57, 0xa5, 0x0d, 0x1a, 0x90, 0x1c, 0xca, 0xbb, 0x16, 0xc2,
-	0x2a, 0x06, 0x56, 0x36, 0xc8, 0xa3, 0x7e, 0xe8, 0x03, 0x3b, 0xb5, 0x62,
-	0x7c, 0xb4, 0xc9, 0xc7, 0x90, 0x90, 0xa5, 0x12, 0x64, 0xac, 0x04, 0x19,
-	0x2b, 0x41, 0xc6, 0x4a, 0x90, 0x31, 0x60, 0xbf, 0x67, 0xb1, 0xff, 0xce,
-	0x95, 0x06, 0xb5, 0x5d, 0xdf, 0xa3, 0xec, 0xfa, 0xe1, 0xd2, 0xab, 0x1e,
-	0xd3, 0x2f, 0x29, 0xdf, 0xb4, 0x1f, 0x32, 0x48, 0x5f, 0x34, 0xf0, 0x51,
-	0x5f, 0x95, 0xa7, 0x66, 0x5f, 0x93, 0x53, 0xb3, 0x6b, 0x38, 0x70, 0xaa,
-	0xe4, 0xc9, 0xcb, 0x2e, 0xfc, 0xcf, 0x45, 0x62, 0xaa, 0x4c, 0x5b, 0xa3,
-	0xc2, 0x56, 0x87, 0x24, 0xaf, 0x70, 0xb2, 0xb2, 0x23, 0xc0, 0x57, 0x0a,
-	0x17, 0x72, 0x6f, 0x4a, 0xfb, 0x8e, 0xd7, 0xe5, 0x1c, 0xec, 0xf8, 0x52,
-	0xed, 0x0d, 0x79, 0x4e, 0xe1, 0x71, 0xf2, 0xe1, 0x7d, 0xf2, 0xb7, 0xa6,
-	0x7f, 0x86, 0x7f, 0x0a, 0x58, 0x63, 0xa9, 0x97, 0xba, 0x23, 0x02, 0x5b,
-	0x60, 0x17, 0xba, 0xb0, 0xaf, 0x0f, 0x18, 0xef, 0x02, 0xa6, 0xe1, 0xfb,
-	0xad, 0xf2, 0xe2, 0x6c, 0xa1, 0x4e, 0x26, 0xa8, 0x1f, 0xec, 0x23, 0x62,
-	0xd0, 0x4e, 0xd1, 0x6e, 0x72, 0xbe, 0xb4, 0x53, 0x6d, 0x2d, 0xbc, 0x3f,
-	0x56, 0x39, 0x7e, 0xc3, 0x16, 0xc6, 0x18, 0xe3, 0x0e, 0x79, 0xfa, 0xba,
-	0x1c, 0xa8, 0xb2, 0xec, 0x35, 0xac, 0x0f, 0xd3, 0x37, 0xbd, 0xbb, 0xe3,
-	0x1c, 0x8f, 0xfd, 0x02, 0x37, 0x75, 0x60, 0xae, 0xa5, 0xcf, 0x6a, 0xcc,
-	0xdd, 0xaf, 0x70, 0xf4, 0xe5, 0x78, 0x99, 0x7c, 0x72, 0xc1, 0xa7, 0xd7,
-	0x55, 0x0c, 0x70, 0x93, 0xd8, 0xf0, 0x13, 0xd8, 0x57, 0x85, 0x8b, 0xc2,
-	0x38, 0x25, 0x63, 0xb8, 0x8c, 0x0f, 0xd7, 0x6b, 0x0c, 0x75, 0x57, 0x40,
-	0xee, 0x82, 0x7e, 0xb9, 0x1b, 0xfa, 0xe5, 0x9e, 0xcb, 0xee, 0x5f, 0x07,
-	0x71, 0xff, 0xee, 0x42, 0xd8, 0xe8, 0x94, 0xb1, 0x6a, 0x7d, 0x5b, 0xc6,
-	0x6e, 0x37, 0x8b, 0xd5, 0x32, 0x8e, 0x9b, 0xda, 0x10, 0xff, 0xa3, 0x6c,
-	0x78, 0xf2, 0x92, 0xcb, 0xb8, 0x5b, 0x70, 0x67, 0x7f, 0x33, 0xfc, 0x65,
-	0xb5, 0x04, 0x71, 0xe6, 0x48, 0xfa, 0xa2, 0xf0, 0xee, 0x7e, 0x71, 0x86,
-	0x78, 0x20, 0xae, 0xee, 0xd9, 0x19, 0x2a, 0xce, 0xe7, 0xb7, 0x2d, 0xce,
-	0xa8, 0x73, 0xa5, 0x02, 0xe3, 0xd5, 0xe6, 0x4e, 0xdb, 0x1c, 0x0b, 0xfb,
-	0xf7, 0x65, 0xb8, 0x97, 0x7d, 0x5d, 0x06, 0x59, 0xac, 0xad, 0xdd, 0xb1,
-	0x1c, 0x52, 0xfa, 0xe2, 0x22, 0xf6, 0x00, 0xd7, 0x0b, 0xfe, 0x02, 0xf6,
-	0xc9, 0x14, 0xf4, 0x53, 0x5e, 0xf5, 0x17, 0xa3, 0x5c, 0x64, 0xb2, 0x61,
-	0x43, 0xa2, 0x27, 0xe8, 0x0b, 0xf9, 0xb1, 0x96, 0x5c, 0xd8, 0x56, 0xfa,
-	0x1b, 0xb4, 0x03, 0x9f, 0x71, 0x7f, 0x5a, 0x13, 0x8d, 0xe9, 0x06, 0xd8,
-	0x55, 0xac, 0x5f, 0x8d, 0x31, 0x01, 0xec, 0xdd, 0xe5, 0xef, 0xca, 0xfe,
-	0xf9, 0xe1, 0x16, 0x5f, 0xfe, 0x19, 0x3b, 0xe6, 0xfc, 0x02, 0x1a, 0xd6,
-	0xf7, 0x6d, 0x9c, 0x90, 0x58, 0x33, 0x6c, 0xda, 0x87, 0xe1, 0x67, 0xec,
-	0x82, 0xac, 0xac, 0xc4, 0xd9, 0xaf, 0xbf, 0x67, 0xa6, 0x4b, 0xec, 0xfb,
-	0xbb, 0x32, 0x3c, 0x7f, 0xb6, 0x85, 0xb6, 0x64, 0x19, 0x7a, 0xe0, 0xbc,
-	0x49, 0x1b, 0x3a, 0x0e, 0x1b, 0xd7, 0x21, 0xdf, 0x9f, 0xa7, 0x7d, 0x4c,
-	0x9a, 0xa7, 0xa4, 0x2f, 0x71, 0x0a, 0x34, 0x7d, 0xde, 0x8d, 0xd0, 0x47,
-	0xf3, 0x86, 0x50, 0xf6, 0x4d, 0x49, 0x9a, 0x5d, 0x21, 0x3e, 0xf7, 0x99,
-	0x8f, 0x03, 0xc3, 0x66, 0xcc, 0xa4, 0x79, 0x5d, 0x88, 0x72, 0x04, 0x9f,
-	0x7b, 0x79, 0x8d, 0xce, 0x37, 0xe7, 0x95, 0x9f, 0xa4, 0xf4, 0xcc, 0xb2,
-	0xcb, 0xf1, 0x40, 0xb7, 0xd2, 0x59, 0xd7, 0x41, 0x9f, 0xc4, 0xf4, 0x99,
-	0x1b, 0xda, 0x10, 0xdb, 0xb8, 0x11, 0x9d, 0x7f, 0x44, 0xb2, 0x27, 0xe3,
-	0xd0, 0x67, 0xec, 0x2b, 0xf0, 0x1d, 0x68, 0x23, 0x03, 0xbc, 0x4d, 0x7b,
-	0x77, 0x2b, 0xec, 0xde, 0x35, 0x8a, 0x9e, 0x11, 0xb7, 0x5f, 0xa6, 0x8e,
-	0x73, 0xec, 0x5e, 0xe8, 0xf2, 0x84, 0x92, 0xdb, 0x62, 0xe9, 0x7c, 0x22,
-	0x06, 0x9d, 0x1c, 0xdb, 0x41, 0x7e, 0x7e, 0x50, 0xee, 0x70, 0xc6, 0xe5,
-	0x4e, 0xc8, 0xce, 0x90, 0xe3, 0xca, 0x30, 0xd6, 0x62, 0x97, 0x03, 0xbb,
-	0xa3, 0x30, 0x74, 0x23, 0xfc, 0x2e, 0x8e, 0xdd, 0xa1, 0xef, 0x5c, 0xf8,
-	0xf8, 0xf1, 0xcf, 0x6a, 0x3e, 0x8f, 0xb2, 0xf3, 0x2f, 0x2b, 0xde, 0x8c,
-	0xb8, 0x37, 0x69, 0x3b, 0xdb, 0x2a, 0x39, 0x55, 0xef, 0x26, 0x65, 0x8f,
-	0x8b, 0x4b, 0xf7, 0x22, 0x85, 0x6d, 0x5e, 0x82, 0xbe, 0x01, 0xe6, 0x2e,
-	0x56, 0x77, 0x22, 0x0f, 0x1b, 0xba, 0x94, 0x46, 0xfa, 0x41, 0xa4, 0xac,
-	0xfb, 0xb9, 0x16, 0x3f, 0x96, 0x5b, 0x7f, 0x87, 0xcc, 0xbf, 0x7f, 0xfa,
-	0x61, 0x85, 0x4b, 0x2f, 0xaa, 0xfb, 0x87, 0x06, 0xb0, 0x4e, 0x16, 0x7a,
-	0xa5, 0x05, 0x18, 0x68, 0xe6, 0x84, 0x9d, 0x1a, 0x0e, 0xdd, 0x26, 0x1f,
-	0x81, 0x2f, 0x5f, 0x71, 0xb9, 0x96, 0x3b, 0xe5, 0x13, 0xb7, 0x50, 0x46,
-	0x6e, 0x93, 0x7d, 0xb7, 0x84, 0x64, 0x5f, 0xbf, 0x9d, 0x21, 0xdd, 0xd7,
-	0xbe, 0x3f, 0xf0, 0xa7, 0xbb, 0x47, 0x92, 0xa1, 0x01, 0x79, 0x1c, 0x32,
-	0x56, 0x80, 0x7c, 0x0d, 0xd7, 0xc8, 0x73, 0xea, 0x7b, 0xea, 0xf9, 0x14,
-	0xb0, 0x72, 0x80, 0xfd, 0x1c, 0x99, 0xa9, 0x35, 0x88, 0x75, 0x15, 0xe3,
-	0xc9, 0x96, 0x7f, 0xae, 0x71, 0x15, 0x65, 0x02, 0x3e, 0xc8, 0x55, 0xfe,
-	0xfe, 0x54, 0xf7, 0xfe, 0xae, 0xf2, 0xed, 0x0a, 0xfc, 0x5f, 0x8f, 0x38,
-	0xcf, 0xbf, 0x5f, 0x70, 0x51, 0xeb, 0xd2, 0xe4, 0xd6, 0x55, 0x7c, 0xd7,
-	0x4a, 0xff, 0xe1, 0xeb, 0x2d, 0x6b, 0xdf, 0x2d, 0x6c, 0x94, 0xc5, 0x20,
-	0xee, 0x56, 0xc6, 0x9c, 0x69, 0xd3, 0x6d, 0x93, 0xba, 0xb0, 0xcd, 0xd9,
-	0x23, 0x7f, 0x09, 0xfb, 0xfe, 0xd5, 0x55, 0xfb, 0xbe, 0x17, 0xfc, 0xd8,
-	0x88, 0x01, 0x1c, 0xf3, 0x2e, 0xcc, 0x65, 0x04, 0xeb, 0x79, 0x27, 0x7e,
-	0x77, 0x94, 0xd6, 0xc5, 0xf1, 0x66, 0x0b, 0xc0, 0x93, 0x0d, 0x0e, 0xfb,
-	0x5b, 0x17, 0xcf, 0x2b, 0xe4, 0x65, 0x35, 0x56, 0x38, 0x78, 0x49, 0x68,
-	0xf7, 0xde, 0x92, 0x68, 0x8f, 0xf3, 0x56, 0x57, 0xc8, 0x79, 0xde, 0x08,
-	0xf1, 0xec, 0xdb, 0x95, 0xd3, 0x35, 0xe2, 0xb0, 0x0b, 0x62, 0x9c, 0x25,
-	0x06, 0x7b, 0x45, 0xc5, 0xa0, 0x2a, 0xa5, 0x6f, 0x23, 0x45, 0x7d, 0xe8,
-	0xc7, 0xb0, 0x1f, 0xa7, 0x50, 0x58, 0x85, 0x7a, 0xf6, 0x4e, 0xac, 0xc3,
-	0x14, 0x7e, 0x5d, 0x3b, 0xae, 0xc3, 0xfe, 0xa5, 0x9c, 0x32, 0xf6, 0xd5,
-	0x63, 0xee, 0x08, 0xf1, 0xdd, 0x66, 0x71, 0xb0, 0xef, 0x48, 0x64, 0x0e,
-	0xb6, 0xce, 0xa0, 0x7e, 0xe0, 0x3c, 0x68, 0x27, 0x4d, 0x59, 0x3c, 0xce,
-	0xbd, 0xbe, 0x59, 0xfd, 0xa0, 0x6e, 0x30, 0x17, 0x65, 0x37, 0x32, 0x79,
-	0xc6, 0x38, 0x4b, 0x5c, 0x03, 0x17, 0x6b, 0xe0, 0xc9, 0x09, 0xb7, 0x0d,
-	0x7a, 0x3b, 0x2e, 0xe1, 0x13, 0x9e, 0x0c, 0x29, 0xec, 0xda, 0x07, 0xcc,
-	0xb5, 0x55, 0xe3, 0x86, 0xb8, 0x44, 0x4e, 0x74, 0x4a, 0x23, 0x70, 0x75,
-	0xc3, 0x51, 0xda, 0xc8, 0xa4, 0x35, 0x04, 0x21, 0x88, 0xa8, 0xbb, 0xac,
-	0xf6, 0xe0, 0xf7, 0xa5, 0xcf, 0xfa, 0xbe, 0x10, 0x2f, 0xfd, 0x7b, 0xac,
-	0x9f, 0xed, 0x5e, 0xd8, 0xa4, 0x7e, 0x71, 0xad, 0x3e, 0xe4, 0x88, 0xb1,
-	0x35, 0xb6, 0x61, 0xac, 0x2d, 0x39, 0xf8, 0x3d, 0xc6, 0xd8, 0xe0, 0x6b,
-	0x36, 0x9c, 0xf1, 0x69, 0x30, 0x96, 0xdb, 0xa5, 0x72, 0x92, 0x7b, 0x94,
-	0x71, 0x16, 0xd3, 0xf7, 0x53, 0x4b, 0xf4, 0x57, 0xf9, 0xde, 0xd2, 0xef,
-	0xbb, 0xf4, 0x7b, 0xfa, 0xa3, 0x05, 0xaf, 0x01, 0x3c, 0xdd, 0x05, 0xfd,
-	0x79, 0xef, 0x4e, 0x47, 0xe1, 0x86, 0x7b, 0x57, 0xd7, 0x6c, 0xb7, 0xba,
-	0x4f, 0x54, 0x29, 0x1d, 0x12, 0x67, 0xc7, 0x4a, 0x2a, 0x22, 0x63, 0x58,
-	0x0b, 0xe6, 0x33, 0xa4, 0x27, 0x75, 0x58, 0x0e, 0xa8, 0xb5, 0xa9, 0x1c,
-	0xb7, 0x8f, 0x58, 0xa1, 0x29, 0x31, 0x2a, 0x7c, 0xfe, 0x34, 0xd2, 0xc3,
-	0xc0, 0x3b, 0x7e, 0xec, 0xd2, 0xa8, 0xac, 0xe7, 0x25, 0x30, 0x86, 0xb9,
-	0x6b, 0x5d, 0x1c, 0x6b, 0x2d, 0xc6, 0xc5, 0xf7, 0x43, 0xea, 0x7d, 0x6a,
-	0x5d, 0x9c, 0x2b, 0x67, 0x10, 0xcb, 0x04, 0xef, 0xb9, 0x16, 0x5c, 0x2f,
-	0xd8, 0xe2, 0xe3, 0x41, 0xcc, 0xab, 0x55, 0xaf, 0x0b, 0xd7, 0x67, 0x46,
-	0xce, 0x99, 0xf6, 0x08, 0xe5, 0xef, 0x86, 0x9d, 0x57, 0xcb, 0x44, 0x07,
-	0xe3, 0x6d, 0xf5, 0x34, 0x6c, 0x8c, 0xa3, 0xd5, 0x8f, 0xbf, 0x31, 0xfe,
-	0xc6, 0xb1, 0xfd, 0x18, 0x5b, 0x76, 0x5d, 0x8c, 0xad, 0x7e, 0x3c, 0x8e,
-	0xb5, 0x15, 0xfe, 0x53, 0xc1, 0x8b, 0x3b, 0x5c, 0xa3, 0x6e, 0x6b, 0x9e,
-	0xf9, 0x2f, 0x1a, 0x58, 0xc7, 0x38, 0xec, 0x08, 0xd7, 0x32, 0x38, 0x6f,
-	0xe6, 0x9a, 0x26, 0xad, 0xc3, 0xfe, 0x7a, 0x0e, 0xfa, 0xeb, 0xee, 0xaf,
-	0xff, 0x85, 0xd5, 0x75, 0xa4, 0x7d, 0xe0, 0x3a, 0x76, 0x88, 0x40, 0xcf,
-	0x1a, 0x47, 0xb9, 0x86, 0x4c, 0xb9, 0x86, 0x7c, 0xc7, 0x35, 0xec, 0xd2,
-	0xef, 0xb8, 0x7e, 0xc0, 0x69, 0x5f, 0xe0, 0x3d, 0xd5, 0xac, 0xfa, 0x06,
-	0xab, 0xab, 0x27, 0xd8, 0x8b, 0x29, 0x79, 0x6e, 0xb1, 0x59, 0xcc, 0xb4,
-	0x3f, 0xaf, 0xf1, 0x75, 0xf1, 0x76, 0x9e, 0x5f, 0xf5, 0x13, 0x7b, 0x06,
-	0xf3, 0x4a, 0x70, 0x5e, 0x07, 0xe4, 0x75, 0xc9, 0xcf, 0x44, 0xe0, 0x03,
-	0xa6, 0x80, 0x73, 0xfa, 0xa1, 0x6f, 0x19, 0x1f, 0x45, 0x59, 0x95, 0x78,
-	0x85, 0xb6, 0x2e, 0x85, 0xbd, 0x42, 0x1d, 0x4c, 0x3c, 0xf2, 0x9a, 0xe4,
-	0xca, 0x81, 0x8e, 0x41, 0xff, 0x46, 0xd0, 0x3f, 0xf9, 0x9c, 0xb9, 0x76,
-	0xbb, 0xac, 0x58, 0xdb, 0xc5, 0xb6, 0x96, 0x64, 0x6d, 0x5d, 0xc7, 0x37,
-	0xe7, 0xbb, 0x7b, 0x6f, 0x78, 0x4d, 0x36, 0xc6, 0x37, 0x59, 0xfb, 0x49,
-	0x09, 0xde, 0x07, 0x6b, 0xbf, 0xe9, 0x3a, 0x14, 0x5e, 0x15, 0xae, 0x05,
-	0x79, 0x40, 0x3c, 0x1c, 0x95, 0x7f, 0x13, 0xe7, 0x7e, 0x2c, 0xa8, 0x33,
-	0xcd, 0xa4, 0xd1, 0xa3, 0x74, 0xc6, 0x90, 0xeb, 0xcb, 0x6b, 0x01, 0xe3,
-	0xc4, 0xba, 0xff, 0xd0, 0x1b, 0x8a, 0xc3, 0xcf, 0xed, 0xa6, 0x7e, 0x09,
-	0xf6, 0x74, 0xb3, 0xda, 0xd3, 0x9f, 0x77, 0x43, 0x52, 0x74, 0x42, 0x32,
-	0xe5, 0x1c, 0x52, 0x18, 0xff, 0xa3, 0xe8, 0xeb, 0x13, 0xba, 0xaf, 0x29,
-	0xe9, 0xd1, 0xfa, 0xe7, 0x20, 0xe4, 0xdc, 0x93, 0x7b, 0xdc, 0x9d, 0x72,
-	0x43, 0x1b, 0xf7, 0x40, 0x30, 0xff, 0x43, 0xd2, 0xbd, 0x73, 0xc5, 0x82,
-	0x67, 0x70, 0x6d, 0x74, 0x95, 0x07, 0xdc, 0x67, 0x81, 0x7c, 0xfb, 0x7c,
-	0xf0, 0xe7, 0xbf, 0x6e, 0xae, 0x7a, 0x9e, 0x9c, 0x33, 0xeb, 0x71, 0xae,
-	0x3e, 0x96, 0x5f, 0x9b, 0x6b, 0x50, 0xbf, 0x05, 0xb2, 0x64, 0x5b, 0x12,
-	0xaa, 0xe7, 0xcd, 0xaa, 0x8e, 0x1a, 0x61, 0x8c, 0x64, 0xc5, 0xb4, 0x53,
-	0x56, 0x28, 0x88, 0x45, 0xfb, 0x58, 0xb7, 0x0b, 0x38, 0xdc, 0xe9, 0xe9,
-	0x49, 0xe5, 0x55, 0x8c, 0xd4, 0x50, 0xf3, 0x9a, 0x02, 0x26, 0x5b, 0x74,
-	0x5f, 0xf5, 0x3e, 0x09, 0xcc, 0x3a, 0x21, 0x0f, 0x49, 0x78, 0x5d, 0x2c,
-	0x17, 0xf9, 0xb3, 0x8c, 0xe7, 0xda, 0x56, 0x06, 0x6b, 0xfc, 0x3b, 0xf0,
-	0xe1, 0x2b, 0xd0, 0xfb, 0x1f, 0xa3, 0x6d, 0x28, 0xc1, 0x5e, 0x00, 0x97,
-	0x7c, 0xf5, 0x8a, 0x18, 0x7e, 0xa2, 0x2e, 0x96, 0xeb, 0xe3, 0xd3, 0x73,
-	0x0a, 0x93, 0x12, 0xb7, 0x1f, 0x09, 0xdd, 0xd5, 0x1b, 0x86, 0x9f, 0x51,
-	0xf0, 0x62, 0x0e, 0x71, 0xdc, 0x21, 0xb9, 0x03, 0xeb, 0x73, 0x7a, 0xb1,
-	0x10, 0xda, 0x55, 0x0a, 0x64, 0x15, 0x7e, 0x65, 0xcd, 0x4e, 0x9d, 0x07,
-	0x3f, 0x9e, 0xd2, 0x98, 0x8f, 0xe7, 0x35, 0x15, 0xed, 0xb3, 0x30, 0x36,
-	0x54, 0xac, 0x1d, 0x92, 0x69, 0x97, 0xb1, 0x9d, 0x6e, 0x29, 0xc6, 0x33,
-	0x57, 0x37, 0xae, 0xf2, 0xc8, 0x36, 0xe1, 0xf3, 0xa5, 0xa8, 0xbf, 0x2b,
-	0xfa, 0xbc, 0xe3, 0x29, 0x25, 0x5f, 0x41, 0x5c, 0x98, 0xfe, 0x11, 0xcf,
-	0xab, 0xba, 0xcd, 0x11, 0x3e, 0x97, 0x29, 0x03, 0xca, 0x67, 0x02, 0x2f,
-	0xef, 0x90, 0xcc, 0x98, 0xa5, 0x70, 0xcb, 0x63, 0x25, 0xee, 0x17, 0xe2,
-	0xff, 0xd7, 0x81, 0xfd, 0x23, 0x58, 0x33, 0xfa, 0x01, 0x1c, 0x9b, 0xfb,
-	0x02, 0x65, 0x55, 0xf3, 0x97, 0xec, 0x8b, 0x0f, 0x6d, 0x23, 0xc6, 0x78,
-	0xa1, 0xf4, 0x98, 0xe2, 0xdf, 0x8a, 0x04, 0xb1, 0x73, 0x85, 0x05, 0x0b,
-	0xd9, 0x70, 0x48, 0x92, 0x73, 0xff, 0x16, 0x32, 0xd4, 0x0f, 0x1f, 0x89,
-	0xf5, 0x44, 0x9d, 0x5f, 0x0d, 0x01, 0x73, 0x19, 0xce, 0xbb, 0xa4, 0x68,
-	0x46, 0xa5, 0xa8, 0xee, 0xfe, 0xf1, 0x3c, 0x37, 0xac, 0x62, 0x3b, 0x45,
-	0x93, 0x98, 0x3f, 0xbd, 0x2d, 0xb8, 0xfb, 0x57, 0x34, 0xd9, 0x8e, 0x79,
-	0x96, 0x4f, 0x49, 0x74, 0xee, 0xa0, 0x34, 0xcc, 0x3d, 0x24, 0x8d, 0xc7,
-	0x88, 0xf1, 0x18, 0xbb, 0x37, 0x6e, 0x6d, 0x14, 0x62, 0xee, 0x6f, 0x61,
-	0xec, 0x43, 0xf2, 0x03, 0x37, 0xa0, 0xe9, 0xba, 0xad, 0xd2, 0xca, 0x3a,
-	0x41, 0x9e, 0xcf, 0xc4, 0x09, 0x3c, 0x17, 0x77, 0xfc, 0x18, 0xa9, 0x3a,
-	0x57, 0x41, 0x5a, 0xe1, 0xb9, 0x38, 0xdf, 0xbf, 0x66, 0xfa, 0xa9, 0x8f,
-	0xf7, 0x7d, 0xdf, 0x83, 0x6d, 0x52, 0x75, 0xd8, 0x62, 0xfd, 0xf7, 0xa1,
-	0x39, 0x94, 0xe7, 0xe7, 0x83, 0x3b, 0x3a, 0x06, 0x7c, 0x5f, 0xbb, 0x40,
-	0x9f, 0xc1, 0xe4, 0xb7, 0x98, 0xf3, 0x05, 0xf0, 0xf9, 0x1a, 0x75, 0xbf,
-	0x87, 0x77, 0x24, 0x50, 0xcf, 0xf2, 0x31, 0x1f, 0xf3, 0x09, 0xf0, 0xf9,
-	0xfd, 0x9d, 0x46, 0xfa, 0x7f, 0x5f, 0x9d, 0x1d, 0x20, 0xa6, 0xd8, 0xc6,
-	0xb3, 0x3f, 0x60, 0x55, 0xae, 0xed, 0x77, 0xb1, 0xb6, 0x8d, 0xea, 0xac,
-	0xa5, 0x58, 0xa2, 0x0f, 0x95, 0xc7, 0x9a, 0xf1, 0x9e, 0x1c, 0x7d, 0xad,
-	0xbc, 0x8e, 0x81, 0x92, 0x4e, 0xe2, 0xe8, 0x00, 0x93, 0xb3, 0xcf, 0xcd,
-	0xee, 0x03, 0x07, 0x7e, 0x12, 0xd7, 0x38, 0xa1, 0x68, 0x1e, 0xde, 0xe0,
-	0x23, 0x1c, 0xc6, 0xfe, 0x5b, 0x84, 0x0c, 0x4d, 0x42, 0xef, 0x0c, 0x85,
-	0xb9, 0x27, 0x9a, 0xb5, 0xff, 0xe8, 0xd0, 0x57, 0x0e, 0x8d, 0xa1, 0x0f,
-	0xe3, 0xd8, 0x1b, 0x32, 0x05, 0x9d, 0x3b, 0x5d, 0x4b, 0xaa, 0x6f, 0x78,
-	0x32, 0x09, 0xde, 0xdb, 0x62, 0xf9, 0x7f, 0x81, 0x8c, 0xbc, 0x01, 0x0c,
-	0xba, 0x05, 0xfc, 0x34, 0xf4, 0xbd, 0x90, 0x0f, 0xe8, 0xf8, 0x4f, 0x8c,
-	0xf1, 0x6f, 0xe8, 0xaa, 0xa2, 0x8f, 0xef, 0xe2, 0xd3, 0x48, 0xbf, 0xd0,
-	0xec, 0xcb, 0xc8, 0xcb, 0x7a, 0x8d, 0x9b, 0x50, 0xfe, 0xa8, 0x8a, 0xfb,
-	0xf9, 0x73, 0xb2, 0xb5, 0x7f, 0x10, 0xc5, 0x3a, 0x73, 0x5e, 0x5f, 0x41,
-	0x3d, 0xae, 0x6f, 0xaf, 0x3e, 0x0f, 0x6d, 0x56, 0x3a, 0x29, 0xe7, 0x5a,
-	0xf0, 0x75, 0x89, 0x89, 0x80, 0xa9, 0x5d, 0xb6, 0x7b, 0x76, 0x1b, 0xcf,
-	0x1b, 0x1b, 0x1c, 0x85, 0xe7, 0x3b, 0xc2, 0x12, 0x94, 0xdd, 0x8e, 0x32,
-	0xc6, 0x25, 0xde, 0x85, 0xb5, 0x61, 0x59, 0x16, 0x79, 0x8e, 0x75, 0xb5,
-	0x1e, 0x87, 0x63, 0x0c, 0xb7, 0xac, 0xa7, 0x89, 0x73, 0xe9, 0xd8, 0xf0,
-	0xfd, 0x00, 0xcb, 0xde, 0xa5, 0xcb, 0x22, 0x7a, 0x7e, 0xb7, 0xeb, 0x6f,
-	0x67, 0xed, 0x23, 0x99, 0x55, 0x3c, 0x4a, 0xfa, 0x62, 0xaa, 0x5d, 0xc6,
-	0xf4, 0x65, 0xe7, 0x30, 0xd6, 0x23, 0x92, 0xf6, 0xda, 0xb9, 0x47, 0x86,
-	0xc2, 0x81, 0x5f, 0x98, 0x50, 0xbe, 0x9e, 0x65, 0xf8, 0x77, 0x84, 0xce,
-	0x5d, 0x76, 0x0f, 0xda, 0xbf, 0x53, 0x3e, 0xdc, 0xdb, 0x24, 0x8b, 0xb3,
-	0x31, 0x7d, 0x3f, 0x31, 0xa1, 0xf6, 0x49, 0x7e, 0x9c, 0xf9, 0x1f, 0x6d,
-	0xe3, 0x77, 0xcb, 0x86, 0xc3, 0xf2, 0x0e, 0xcd, 0xdf, 0x77, 0xa9, 0xfb,
-	0x3c, 0xbc, 0x67, 0x52, 0x2c, 0xff, 0x44, 0xbd, 0x3f, 0x3d, 0xdf, 0xa0,
-	0xea, 0x9f, 0x9e, 0xdf, 0x78, 0x27, 0x87, 0x65, 0xef, 0x66, 0x4c, 0x41,
-	0x96, 0x66, 0x1a, 0x64, 0x79, 0xde, 0xa2, 0x8f, 0x94, 0x6e, 0x5c, 0xfb,
-	0xf6, 0x45, 0x7f, 0xa7, 0xe6, 0xc9, 0x30, 0xd6, 0x6f, 0x71, 0x70, 0x5a,
-	0x2a, 0x83, 0xf4, 0x01, 0xd4, 0xbd, 0x3b, 0xc8, 0x48, 0x03, 0xf0, 0x5f,
-	0xc1, 0xab, 0x38, 0x8c, 0xbd, 0xb6, 0x6a, 0x1f, 0xea, 0xc7, 0xda, 0xcf,
-	0x22, 0x8f, 0x0c, 0xc9, 0xf5, 0x4f, 0x29, 0xba, 0x2a, 0x8a, 0x57, 0xc1,
-	0xb7, 0x45, 0xec, 0x9f, 0xdf, 0x17, 0x85, 0x35, 0x7e, 0x7c, 0x50, 0xf3,
-	0xfc, 0xaf, 0x75, 0xfa, 0x88, 0xec, 0x3b, 0xfe, 0x19, 0xd0, 0xda, 0xe4,
-	0xdf, 0x2d, 0x92, 0xfa, 0xef, 0x36, 0x22, 0xea, 0xdb, 0x95, 0x88, 0xf3,
-	0x08, 0xca, 0x18, 0x7b, 0x7a, 0x44, 0xcd, 0x83, 0xf7, 0xd7, 0x0a, 0xf2,
-	0xab, 0xee, 0x64, 0x04, 0xfe, 0x0f, 0xef, 0x08, 0x35, 0xeb, 0xfe, 0x76,
-	0xe9, 0x75, 0x1c, 0x97, 0x7d, 0xd0, 0xef, 0x79, 0xe0, 0x40, 0xde, 0xab,
-	0x9a, 0x08, 0xd7, 0x8f, 0x19, 0xc8, 0xb2, 0xef, 0x5b, 0x07, 0x67, 0xfd,
-	0x61, 0xe5, 0x03, 0xac, 0xfa, 0xe9, 0xba, 0x7c, 0x5c, 0xf6, 0x97, 0x94,
-	0xbf, 0xae, 0xce, 0xe8, 0xa6, 0xb1, 0x27, 0x87, 0x94, 0x0e, 0x8f, 0x85,
-	0x86, 0xab, 0x69, 0xc9, 0x9f, 0xdc, 0x8d, 0x71, 0x18, 0xfb, 0xca, 0xe8,
-	0xb3, 0xb0, 0xbd, 0xb2, 0xaf, 0xe6, 0x8f, 0x3d, 0x59, 0xe2, 0xfb, 0x24,
-	0xec, 0x22, 0xdf, 0xe7, 0x12, 0x61, 0x15, 0xcd, 0xbf, 0x0e, 0x6d, 0x1b,
-	0x34, 0x6f, 0x79, 0x9f, 0x9e, 0xed, 0xb9, 0xff, 0x3e, 0x6e, 0x4a, 0x73,
-	0x0e, 0xef, 0xd9, 0x26, 0xe8, 0x6f, 0x12, 0x7a, 0x9a, 0xfe, 0xe8, 0xc3,
-	0xb2, 0x52, 0x9e, 0x96, 0xf3, 0xe5, 0x40, 0xce, 0x78, 0xb7, 0x99, 0xb4,
-	0xdf, 0xa9, 0xef, 0x36, 0x67, 0xb0, 0x0e, 0xeb, 0x79, 0x95, 0x5b, 0xf7,
-	0xfd, 0xd1, 0x5f, 0x98, 0xfe, 0x37, 0x80, 0xb7, 0xa9, 0x7b, 0x4a, 0xeb,
-	0xe5, 0x9d, 0xfd, 0x2c, 0x9b, 0x8c, 0xed, 0xfb, 0x77, 0xad, 0x3a, 0xea,
-	0xde, 0xc7, 0xf5, 0xfd, 0xa6, 0xe7, 0xf4, 0x9d, 0x78, 0xf2, 0x73, 0x4c,
-	0xd3, 0x7b, 0x1d, 0xf6, 0x1e, 0xfb, 0x7c, 0x54, 0xaf, 0x1b, 0xd2, 0x45,
-	0x3e, 0x53, 0x0f, 0xad, 0xe8, 0xf3, 0x4e, 0x53, 0x8f, 0x51, 0x7f, 0xbf,
-	0xac, 0xa1, 0x6e, 0x5c, 0xb6, 0xe7, 0xb7, 0x48, 0xc1, 0x5d, 0x6b, 0x96,
-	0x1d, 0xd7, 0xf7, 0xd8, 0x82, 0xbb, 0xd5, 0x2c, 0x0b, 0xee, 0x5b, 0x91,
-	0x5f, 0x8c, 0xe1, 0x21, 0xad, 0x8d, 0xe9, 0xe7, 0xb1, 0xba, 0x6f, 0x74,
-	0x82, 0x3e, 0x23, 0xe8, 0xe3, 0xf6, 0xf0, 0xe5, 0x77, 0xb1, 0xf9, 0xdd,
-	0x14, 0x65, 0xd1, 0xe0, 0x37, 0xdd, 0xf4, 0x7b, 0x80, 0x55, 0xb6, 0xca,
-	0xa4, 0xa2, 0xa7, 0xa0, 0xee, 0x27, 0x64, 0xdd, 0x26, 0x19, 0x32, 0xfd,
-	0xfc, 0xe4, 0xe2, 0x46, 0x39, 0x65, 0xf9, 0xf5, 0x31, 0x69, 0x2e, 0x60,
-	0x1c, 0xbe, 0xdf, 0xec, 0x1b, 0x81, 0xa8, 0xfe, 0x4e, 0xc9, 0x45, 0x9b,
-	0xcf, 0x53, 0xde, 0x0b, 0x85, 0xd5, 0xbb, 0x90, 0x05, 0x15, 0x97, 0x14,
-	0x23, 0xb8, 0x93, 0xc8, 0x6f, 0xd6, 0x45, 0x9e, 0xa9, 0xf2, 0xbb, 0xad,
-	0xdb, 0xd4, 0xbd, 0x11, 0xff, 0x2c, 0x8e, 0x74, 0x75, 0x2b, 0x9d, 0x5c,
-	0xa9, 0x16, 0xc9, 0x53, 0x1d, 0x87, 0x8d, 0xea, 0x38, 0x2c, 0x79, 0x3c,
-	0x02, 0x1e, 0xff, 0x3f, 0xbd, 0x2e, 0xc1, 0x77, 0x5f, 0x3c, 0xeb, 0xe1,
-	0x79, 0xd0, 0xa3, 0x6a, 0x2e, 0xd4, 0xd1, 0x68, 0xfb, 0xde, 0xb0, 0xda,
-	0xbb, 0xea, 0x9b, 0x78, 0xc8, 0x27, 0xbf, 0x71, 0x87, 0x7e, 0x2d, 0xf1,
-	0x5b, 0xf6, 0x11, 0xf5, 0x3d, 0x47, 0xa5, 0xca, 0x75, 0xe5, 0x37, 0xec,
-	0x63, 0x75, 0xf2, 0x18, 0xd6, 0x63, 0x6d, 0x69, 0x93, 0x66, 0x7f, 0xdd,
-	0xf9, 0x2d, 0x48, 0xa5, 0x1a, 0xdc, 0xa3, 0xdc, 0xb2, 0xc2, 0x3d, 0x21,
-	0xbe, 0x5f, 0xab, 0xbe, 0x67, 0xa9, 0xa8, 0xef, 0x43, 0x2c, 0x7e, 0x67,
-	0x09, 0xdb, 0xb1, 0x07, 0xcf, 0x3c, 0x47, 0xdd, 0x8b, 0x14, 0x3a, 0xa7,
-	0x3a, 0x81, 0xf4, 0x21, 0xc9, 0xa9, 0x38, 0x57, 0x0b, 0xf2, 0x93, 0x6a,
-	0xec, 0x62, 0xf5, 0x7e, 0xd9, 0x77, 0xf2, 0x01, 0x7e, 0x43, 0xa3, 0xbe,
-	0xc3, 0xcf, 0xba, 0xa4, 0x31, 0x2e, 0x53, 0x6a, 0xde, 0x85, 0xb5, 0x6f,
-	0x33, 0x7c, 0x39, 0x6a, 0xe3, 0x9a, 0x16, 0xaa, 0x2d, 0xa0, 0x31, 0xa4,
-	0xef, 0x52, 0x12, 0xff, 0x06, 0xf3, 0x6f, 0xe6, 0xfd, 0x3c, 0x8f, 0xe7,
-	0x65, 0xfb, 0x4a, 0xbc, 0x2b, 0x99, 0xd4, 0x7e, 0x31, 0x63, 0x65, 0x8c,
-	0xc7, 0x53, 0xc6, 0xed, 0xd4, 0x04, 0xb4, 0x7f, 0x54, 0x12, 0x3c, 0xcb,
-	0xd5, 0x73, 0x69, 0xa9, 0x9b, 0x0b, 0xef, 0x87, 0xfa, 0xf3, 0xe1, 0x37,
-	0x27, 0xf9, 0x52, 0xfd, 0xf7, 0x32, 0xea, 0x9b, 0x70, 0xf5, 0x7d, 0xca,
-	0x44, 0xf5, 0x41, 0xb9, 0xaf, 0xb4, 0x55, 0x7f, 0x2b, 0x13, 0x93, 0xfb,
-	0xaa, 0x6f, 0x28, 0x9e, 0xe6, 0xd5, 0x77, 0x3e, 0x51, 0xbd, 0x66, 0x71,
-	0xd5, 0xc7, 0xda, 0xf7, 0x3e, 0x76, 0xdd, 0xb7, 0x1f, 0x51, 0x99, 0x58,
-	0xfc, 0x65, 0xdf, 0xfc, 0x3c, 0x2c, 0xfc, 0xee, 0xe3, 0x25, 0x77, 0x5a,
-	0x1e, 0x2b, 0x7b, 0xde, 0x1d, 0x2e, 0xb1, 0xd4, 0x16, 0x39, 0x1f, 0xcf,
-	0x0c, 0x7e, 0xcf, 0x69, 0x0f, 0x55, 0x66, 0x1b, 0xa1, 0xaf, 0x1b, 0x95,
-	0x2d, 0x61, 0x7e, 0x71, 0x96, 0x7b, 0x3e, 0x82, 0x39, 0xda, 0xe6, 0x25,
-	0xf9, 0x54, 0x1b, 0xe3, 0x4c, 0x77, 0xc0, 0x77, 0xfb, 0xb8, 0xeb, 0xeb,
-	0xe5, 0xcf, 0x2d, 0xed, 0x96, 0xcf, 0x55, 0x63, 0xa1, 0xca, 0x0c, 0xef,
-	0xd7, 0xd9, 0x23, 0x65, 0x49, 0xa2, 0x1e, 0xfb, 0x87, 0xbc, 0x24, 0xb6,
-	0xcb, 0xd3, 0xc7, 0x7f, 0xee, 0x5d, 0x72, 0xf0, 0x1e, 0xba, 0xe6, 0xbc,
-	0x1b, 0xc4, 0xd2, 0xe0, 0x37, 0x1f, 0x65, 0xbd, 0xed, 0x90, 0x03, 0xd8,
-	0x6d, 0xec, 0x39, 0xfa, 0x75, 0x97, 0xb4, 0xde, 0x32, 0x8e, 0x5e, 0x23,
-	0x97, 0x56, 0xef, 0xe4, 0xbe, 0x0e, 0xd9, 0xb6, 0x7c, 0xfe, 0xab, 0xd8,
-	0xf3, 0x41, 0x09, 0x7f, 0x01, 0x76, 0xe2, 0x0b, 0x0d, 0x4a, 0xb7, 0xd3,
-	0x9e, 0x01, 0xf3, 0x03, 0xd7, 0x47, 0xd0, 0xcf, 0xfe, 0x36, 0x5f, 0x66,
-	0xa7, 0x45, 0xbe, 0xd8, 0x24, 0x99, 0x36, 0xfa, 0x8d, 0xf2, 0x2b, 0xf4,
-	0x57, 0xfd, 0x3e, 0x4b, 0xc9, 0x9f, 0x71, 0x8f, 0xd7, 0x38, 0x97, 0x64,
-	0xe2, 0x7f, 0xc9, 0x27, 0x65, 0x22, 0xc1, 0xb9, 0x3c, 0x2c, 0x85, 0xf2,
-	0xa3, 0xf8, 0x71, 0x9e, 0xa4, 0xfb, 0x5f, 0xe8, 0xb3, 0xfb, 0x31, 0x29,
-	0xce, 0xa4, 0x65, 0x6a, 0x7e, 0x92, 0xdf, 0xe4, 0x8e, 0xdc, 0xa1, 0xce,
-	0xb4, 0xec, 0x44, 0x32, 0xd4, 0x67, 0x4d, 0xf1, 0xae, 0x82, 0x9a, 0xcf,
-	0x24, 0xe6, 0xf3, 0x4a, 0x1b, 0xef, 0x78, 0x5f, 0x82, 0xfe, 0x35, 0x4e,
-	0x50, 0x0e, 0x6d, 0xb3, 0x2b, 0xc4, 0xfc, 0x5e, 0xf8, 0xab, 0x2c, 0xdb,
-	0x2b, 0xe1, 0xa3, 0xab, 0x7a, 0x1e, 0xe5, 0xfa, 0x6c, 0x55, 0xb5, 0xff,
-	0xaf, 0x68, 0x8b, 0x7a, 0x47, 0x83, 0xb6, 0x41, 0x1d, 0xb6, 0xe5, 0x3c,
-	0x77, 0xc3, 0x4f, 0x0e, 0xe8, 0x82, 0x1c, 0x26, 0xea, 0xf9, 0xdd, 0xbc,
-	0x81, 0xdf, 0x11, 0xe2, 0x4d, 0xf0, 0x8b, 0x3c, 0x0e, 0x6b, 0x1e, 0xff,
-	0x3d, 0xfa, 0x0f, 0xd6, 0xe0, 0x0e, 0x94, 0x99, 0xfa, 0x1b, 0xbc, 0x77,
-	0xc2, 0x77, 0xf2, 0x9c, 0xf5, 0xf7, 0xb7, 0xf9, 0xb2, 0x46, 0x7a, 0x36,
-	0xe3, 0xf9, 0x7b, 0xdb, 0xfd, 0x75, 0xd9, 0x0b, 0x7e, 0xf1, 0x1e, 0x65,
-	0x9f, 0xba, 0x8f, 0x9f, 0x19, 0xdf, 0x0b, 0xd9, 0x09, 0xe6, 0xd5, 0x07,
-	0x19, 0xe3, 0x39, 0x01, 0xeb, 0xd7, 0xf3, 0xc4, 0xb7, 0x7b, 0x61, 0xfa,
-	0xfa, 0x0e, 0xe7, 0x0a, 0x4c, 0xf8, 0x45, 0xf5, 0xfd, 0x0d, 0xf4, 0xe4,
-	0xbb, 0x57, 0xbf, 0xbf, 0xb9, 0xf2, 0x1a, 0x0f, 0xb4, 0xfb, 0x36, 0xca,
-	0x04, 0x4f, 0x5a, 0x75, 0x9b, 0xbd, 0xc0, 0xa7, 0x8c, 0x7f, 0x26, 0x13,
-	0x9f, 0x90, 0x60, 0x1c, 0xef, 0x36, 0xfa, 0x79, 0x43, 0x03, 0x7d, 0xf0,
-	0x69, 0xd5, 0x1d, 0x95, 0x04, 0xef, 0xbc, 0x24, 0x43, 0x7b, 0xd5, 0x7d,
-	0x85, 0x17, 0xd6, 0x7d, 0x43, 0x95, 0x92, 0xa7, 0xd7, 0x64, 0x65, 0xe4,
-	0x47, 0x62, 0x8b, 0x75, 0x35, 0x65, 0x85, 0xfd, 0x4e, 0x72, 0x9e, 0x89,
-	0x07, 0xd4, 0x3c, 0x4d, 0xf8, 0x4d, 0xbc, 0x5b, 0x60, 0x86, 0x2a, 0xf3,
-	0x5c, 0x77, 0xa4, 0x4b, 0x7c, 0x0e, 0xce, 0x37, 0x95, 0x5e, 0xc1, 0xb8,
-	0x2c, 0xa3, 0x6e, 0xe4, 0xfb, 0xb4, 0x3e, 0xff, 0xbc, 0xa7, 0x9d, 0x67,
-	0xf0, 0x79, 0x94, 0x95, 0x97, 0x36, 0xa7, 0xed, 0xe3, 0x4a, 0x0e, 0x1e,
-	0x06, 0xdf, 0xff, 0x04, 0x75, 0x1f, 0x45, 0xca, 0x39, 0xa6, 0x57, 0xd7,
-	0x9d, 0xfc, 0xfe, 0xb0, 0x0c, 0x42, 0x2e, 0x98, 0x7f, 0x58, 0x8a, 0xea,
-	0xee, 0x10, 0xd2, 0x32, 0x9f, 0xa9, 0xeb, 0x1d, 0x6d, 0x4f, 0x49, 0xcb,
-	0x5e, 0xfd, 0xdd, 0x56, 0x20, 0x4f, 0x7b, 0x74, 0xbb, 0xf1, 0x55, 0x5e,
-	0x3d, 0x70, 0x19, 0xde, 0x88, 0xae, 0xe2, 0x0d, 0x7f, 0xac, 0x62, 0x7b,
-	0x80, 0x35, 0xfc, 0x39, 0xf8, 0x58, 0xc3, 0x97, 0xf3, 0x49, 0x89, 0x40,
-	0x8e, 0xc3, 0x6b, 0x72, 0x0c, 0xdc, 0xe3, 0xef, 0x99, 0x29, 0x9e, 0xdb,
-	0x29, 0x3e, 0x53, 0x0e, 0x29, 0xbf, 0x5c, 0xc7, 0xfa, 0xb5, 0xbe, 0xf1,
-	0x97, 0xac, 0xf5, 0x85, 0xf6, 0x00, 0x3f, 0xfc, 0xd3, 0xf6, 0xc1, 0xd7,
-	0xda, 0xd7, 0xf6, 0xc1, 0x35, 0xbf, 0xa1, 0x7d, 0xb0, 0x51, 0x2e, 0xeb,
-	0x65, 0xca, 0x84, 0x3c, 0x71, 0xbd, 0x28, 0x4f, 0x94, 0x23, 0xf2, 0x92,
-	0xfa, 0xb4, 0x91, 0xbe, 0x53, 0xe2, 0xa2, 0xfa, 0x3e, 0x62, 0x1a, 0x3a,
-	0xa8, 0x3d, 0x54, 0x86, 0x5f, 0x5e, 0x5c, 0xba, 0x49, 0xc9, 0xf4, 0xd3,
-	0x35, 0xea, 0xa5, 0x2b, 0xcd, 0x7d, 0xbd, 0xce, 0xcd, 0x6f, 0xd0, 0xb9,
-	0xf9, 0x55, 0x9d, 0xdb, 0xa6, 0xfd, 0xa5, 0x7f, 0x8a, 0xce, 0x8d, 0xd7,
-	0x9d, 0x85, 0x04, 0xe7, 0x20, 0x12, 0xca, 0xf6, 0x36, 0xcb, 0xae, 0xd9,
-	0xb8, 0x8c, 0xcc, 0xec, 0x96, 0x3f, 0x9a, 0x99, 0x56, 0xf7, 0x82, 0xfe,
-	0xca, 0x4d, 0x26, 0xee, 0x0f, 0x79, 0xf2, 0x61, 0xf8, 0xbb, 0x13, 0x9d,
-	0x0d, 0xb2, 0xeb, 0xfd, 0xea, 0x7c, 0xcf, 0xcc, 0x86, 0x3a, 0x84, 0x91,
-	0xe7, 0x9c, 0x6b, 0xbb, 0x56, 0x88, 0x77, 0xc4, 0x1a, 0x65, 0x22, 0xde,
-	0x22, 0xbb, 0x81, 0x9d, 0x0a, 0x57, 0xb9, 0xea, 0x9b, 0xed, 0x8c, 0x3a,
-	0x3f, 0xe9, 0xde, 0xee, 0x8f, 0x0b, 0x3e, 0xb4, 0x9a, 0xf2, 0xe7, 0xb5,
-	0x6e, 0xf5, 0xfd, 0xf1, 0x0b, 0xa5, 0x3f, 0x6f, 0x5b, 0x9f, 0xe7, 0xf3,
-	0x7f, 0x42, 0x9d, 0x38, 0x78, 0x55, 0x7f, 0xdf, 0x26, 0xac, 0xf8, 0x59,
-	0x2c, 0x8f, 0xab, 0x7b, 0x4c, 0x17, 0xc3, 0xe4, 0x97, 0xf2, 0x9b, 0x12,
-	0xd9, 0x30, 0x30, 0xce, 0x2c, 0x90, 0xb4, 0x43, 0x9f, 0x4f, 0xe3, 0x4f,
-	0xe8, 0xff, 0x7d, 0xea, 0x3c, 0x75, 0x05, 0xbc, 0xf1, 0x54, 0xbc, 0x35,
-	0x1f, 0x27, 0xae, 0x5f, 0xbb, 0xb3, 0x7b, 0x39, 0xbe, 0xf7, 0xbf, 0xf1,
-	0xd2, 0xb1, 0x7f, 0x1d, 0x9f, 0xd1, 0x3e, 0xb8, 0x3a, 0xcb, 0xda, 0xec,
-	0xff, 0x50, 0xf8, 0xdf, 0xec, 0x67, 0x4b, 0xc4, 0x76, 0xf6, 0x91, 0xb2,
-	0xf4, 0x6f, 0x57, 0xb1, 0x26, 0xf2, 0xb7, 0x82, 0x75, 0x3a, 0x96, 0x08,
-	0xec, 0x79, 0xa8, 0xeb, 0x6c, 0xbd, 0x1f, 0xc8, 0x3e, 0x62, 0xea, 0x0e,
-	0xc4, 0xda, 0xff, 0xbd, 0x61, 0x4c, 0x25, 0x13, 0xba, 0xab, 0x34, 0x2d,
-	0xe1, 0xb9, 0x31, 0x89, 0x1c, 0x63, 0xfc, 0x3a, 0x23, 0xc5, 0xb8, 0x27,
-	0xf7, 0xb9, 0xeb, 0x7d, 0x93, 0x2e, 0x63, 0x23, 0xed, 0x0f, 0xcb, 0xd0,
-	0xc9, 0x47, 0x25, 0x3a, 0xc7, 0x77, 0xeb, 0xce, 0x2e, 0xa0, 0x8f, 0xb6,
-	0x48, 0x39, 0xce, 0x18, 0x6e, 0x54, 0x9d, 0x05, 0x9f, 0x1f, 0x5f, 0x90,
-	0x22, 0xb0, 0x42, 0x5e, 0xe9, 0x16, 0xa4, 0xab, 0xbe, 0xc4, 0xf4, 0x76,
-	0xee, 0x29, 0xf8, 0x98, 0xa1, 0x89, 0x72, 0x54, 0xdd, 0xc9, 0x39, 0x1f,
-	0x67, 0x5d, 0xf8, 0xef, 0x73, 0xc4, 0x19, 0xd0, 0x1d, 0x63, 0x12, 0x62,
-	0x3e, 0x3c, 0xb7, 0x86, 0x33, 0xa8, 0x13, 0x86, 0xdc, 0xb8, 0x44, 0x4e,
-	0xf9, 0x73, 0xe7, 0x3f, 0x52, 0x32, 0x16, 0x76, 0x4b, 0xf8, 0x18, 0x9f,
-	0xeb, 0xfd, 0x21, 0x62, 0x77, 0xd8, 0x86, 0xb3, 0x9f, 0x45, 0x7f, 0x7c,
-	0x97, 0xd1, 0xdf, 0xc2, 0x22, 0x5f, 0xf9, 0xc7, 0xfe, 0xcf, 0x04, 0xca,
-	0xfe, 0xff, 0x07, 0x3b, 0x97, 0x22, 0x9a, 0xb0, 0x4e, 0x00, 0x00, 0x00 };
+	0xcd, 0x7c, 0x0d, 0x70, 0x5b, 0xd7, 0x95, 0xde, 0xc1, 0x03, 0x40, 0x82,
+	0x10, 0x45, 0x3d, 0x52, 0x30, 0x0d, 0x3b, 0x4c, 0x82, 0x47, 0x3c, 0x92,
+	0xb0, 0xc9, 0x64, 0x9f, 0x64, 0x46, 0x66, 0x12, 0xac, 0x05, 0x03, 0xa4,
+	0x4c, 0x27, 0xea, 0x92, 0xb6, 0x19, 0x47, 0x6d, 0x35, 0x09, 0x17, 0x92,
+	0x12, 0xdb, 0x4d, 0xa7, 0x9a, 0xc6, 0xe9, 0x2a, 0x1b, 0xc7, 0x82, 0x41,
+	0xca, 0x51, 0x52, 0x8a, 0x60, 0x24, 0x4a, 0xf2, 0x74, 0xb3, 0xbb, 0x0c,
+	0x48, 0x4a, 0x8e, 0x03, 0x09, 0x96, 0xec, 0x75, 0xdc, 0xad, 0xb3, 0x62,
+	0x68, 0xad, 0xec, 0x4d, 0xb3, 0xad, 0x9d, 0x49, 0x3a, 0x9a, 0xa9, 0xb7,
+	0x55, 0x95, 0xa4, 0xf9, 0x99, 0xfe, 0xb8, 0x49, 0xa6, 0x75, 0xbb, 0xf1,
+	0xbe, 0x7e, 0xdf, 0x7d, 0xf7, 0x11, 0x20, 0xc5, 0x28, 0xde, 0xec, 0x64,
+	0x66, 0x39, 0x83, 0xb9, 0xef, 0xde, 0x77, 0x7f, 0xce, 0x3d, 0xf7, 0xfc,
+	0x7c, 0xe7, 0xde, 0xfb, 0x78, 0x87, 0x48, 0x54, 0xf4, 0xdf, 0x46, 0xfc,
+	0xfa, 0xff, 0xe9, 0x3f, 0xdb, 0xb3, 0xf5, 0xdd, 0xfd, 0xef, 0x66, 0xde,
+	0x30, 0x42, 0x21, 0xa6, 0x41, 0xfc, 0x62, 0xf8, 0x6d, 0xd5, 0xcf, 0xeb,
+	0xfd, 0x99, 0xf8, 0x6d, 0x0b, 0x88, 0x8c, 0xff, 0x44, 0x24, 0xb0, 0xe6,
+	0x5d, 0x64, 0x9d, 0xfa, 0xae, 0xfb, 0x4b, 0x3a, 0xd2, 0x7f, 0x06, 0x7e,
+	0x89, 0xeb, 0x57, 0x59, 0x19, 0xf7, 0xd7, 0xfd, 0x0b, 0xea, 0xe6, 0x1b,
+	0xf5, 0x4f, 0x22, 0x46, 0x5a, 0x46, 0xb2, 0xb6, 0x44, 0x82, 0xe9, 0x9f,
+	0x8f, 0xec, 0xb1, 0x45, 0x32, 0x95, 0xde, 0x44, 0x4e, 0xde, 0x74, 0x0b,
+	0xb1, 0x90, 0xb0, 0xfc, 0xed, 0xe9, 0x5f, 0x1c, 0xfc, 0xfa, 0xed, 0xd6,
+	0xeb, 0x73, 0x41, 0x89, 0x98, 0xe9, 0x37, 0xc4, 0xec, 0x96, 0x48, 0x07,
+	0xda, 0x7c, 0xa9, 0xe7, 0x49, 0x43, 0x5a, 0xfc, 0xbe, 0xcc, 0xf1, 0x60,
+	0x5a, 0x46, 0xf7, 0x4e, 0x1d, 0x74, 0x0d, 0x5b, 0x0a, 0x37, 0xa7, 0xed,
+	0x44, 0x51, 0x9a, 0x07, 0x26, 0xfb, 0x6f, 0x17, 0xe4, 0x47, 0xf7, 0x56,
+	0x22, 0x92, 0xad, 0x16, 0x9a, 0x0d, 0xdb, 0x46, 0x1a, 0x29, 0xbc, 0x2d,
+	0x2d, 0x91, 0x86, 0xf4, 0x6c, 0xe3, 0x25, 0x9b, 0xe3, 0x0f, 0x60, 0xfc,
+	0xb7, 0x49, 0xc8, 0x76, 0xdd, 0x49, 0x8c, 0xbf, 0xa3, 0xf2, 0xa6, 0xfb,
+	0x58, 0xc8, 0x1b, 0xdb, 0x48, 0x1f, 0x08, 0x32, 0x0d, 0xa4, 0x33, 0x23,
+	0x9d, 0x15, 0x95, 0x6f, 0xf0, 0xf2, 0x83, 0x3a, 0x1f, 0x89, 0x7a, 0xb4,
+	0x4b, 0x13, 0x68, 0x8f, 0x84, 0xd2, 0xe9, 0x26, 0xf4, 0x11, 0x09, 0xa7,
+	0x97, 0x7e, 0x7b, 0x51, 0xd5, 0x3b, 0xac, 0xeb, 0x3d, 0x10, 0xf6, 0xda,
+	0x4d, 0x8e, 0x74, 0x57, 0x98, 0xce, 0x8e, 0x74, 0xa9, 0xf4, 0x4b, 0x23,
+	0x49, 0x95, 0xce, 0xa9, 0x7a, 0x81, 0xf4, 0xc2, 0x88, 0xad, 0xd2, 0xb4,
+	0x2e, 0x1f, 0x1e, 0x49, 0xa8, 0x74, 0xa7, 0x4e, 0x47, 0x75, 0x3a, 0xa6,
+	0xd3, 0x5d, 0x3a, 0xdd, 0xad, 0xd3, 0x71, 0x9d, 0xee, 0xd5, 0xfd, 0x3c,
+	0xa0, 0xf3, 0x9f, 0xd0, 0xe9, 0x7e, 0x9d, 0x3e, 0xac, 0xd3, 0x03, 0x3a,
+	0x7d, 0x44, 0xd3, 0x55, 0xd0, 0xe9, 0x94, 0x2e, 0x9f, 0xd1, 0x74, 0x3e,
+	0x01, 0x7a, 0xfe, 0x71, 0xa3, 0x96, 0x5b, 0xcc, 0x37, 0x21, 0x7b, 0xa6,
+	0x22, 0x52, 0x2c, 0x05, 0x25, 0xa7, 0xd6, 0xf3, 0xe3, 0x61, 0x89, 0x46,
+	0x64, 0xa2, 0x1a, 0x91, 0x2b, 0x4a, 0x5c, 0x7f, 0xe4, 0x7e, 0xbd, 0xc7,
+	0x94, 0xa7, 0xab, 0x31, 0xb9, 0x50, 0x95, 0xc0, 0x68, 0x4f, 0x93, 0x18,
+	0x47, 0x6f, 0x96, 0x8c, 0x19, 0x90, 0xa0, 0xe2, 0x6b, 0x42, 0xb2, 0x53,
+	0xed, 0xc8, 0x5b, 0x71, 0x91, 0xc5, 0xb0, 0xb7, 0x8e, 0x11, 0x09, 0x9e,
+	0xe0, 0xba, 0x3c, 0x37, 0x72, 0x69, 0x36, 0x2e, 0xa1, 0xe9, 0x04, 0xfa,
+	0x6f, 0x96, 0xf0, 0x09, 0xe9, 0x08, 0x4a, 0x57, 0xfc, 0x63, 0xa8, 0x31,
+	0x58, 0x09, 0xc9, 0x50, 0x25, 0x80, 0xb5, 0x8a, 0x40, 0x4e, 0x9a, 0xf1,
+	0x33, 0xf1, 0x8b, 0xe1, 0x17, 0xc7, 0xef, 0xaf, 0xd0, 0x4f, 0x87, 0xe4,
+	0x2a, 0xec, 0x13, 0xe3, 0x96, 0x30, 0x7e, 0xc9, 0x32, 0xc7, 0x85, 0x34,
+	0xc5, 0xe5, 0xeb, 0x3d, 0x1e, 0x4d, 0x17, 0xaa, 0x91, 0x40, 0xf6, 0xa4,
+	0xec, 0xcf, 0x39, 0x92, 0x30, 0xec, 0xa8, 0xe4, 0xcd, 0x40, 0x62, 0x6f,
+	0xaa, 0x4d, 0x0a, 0x63, 0x78, 0x57, 0x92, 0x8c, 0x81, 0xbe, 0xf3, 0xa6,
+	0x8c, 0x7b, 0xef, 0x58, 0xf6, 0x7f, 0xa1, 0xaf, 0x96, 0x49, 0xc1, 0xbd,
+	0x50, 0xfa, 0xd7, 0x78, 0x66, 0x5f, 0x2f, 0x86, 0x3c, 0x9a, 0xdf, 0x40,
+	0x9e, 0xe5, 0xee, 0x26, 0x2f, 0xcf, 0x67, 0xd6, 0xf5, 0xc7, 0xf4, 0xe7,
+	0xca, 0xb1, 0x7b, 0x30, 0x5f, 0x8e, 0xbf, 0x32, 0x5f, 0xd0, 0xd1, 0x1c,
+	0xc8, 0x9d, 0x4c, 0xc8, 0xa1, 0xd2, 0x1d, 0x92, 0x75, 0x5c, 0x77, 0x8f,
+	0x23, 0x31, 0x43, 0xba, 0xcc, 0x1c, 0xde, 0x96, 0x2b, 0x12, 0xc8, 0x96,
+	0x7c, 0x7e, 0xb0, 0xdf, 0x10, 0xca, 0xda, 0x51, 0xbf, 0x25, 0x30, 0x78,
+	0x12, 0xb4, 0xa7, 0xc9, 0x17, 0xc8, 0xac, 0xd3, 0x15, 0xdf, 0x8b, 0xf1,
+	0xe6, 0x2b, 0x5d, 0xce, 0xb2, 0x98, 0xe8, 0xb3, 0x0d, 0x75, 0xc8, 0x23,
+	0xf6, 0xc5, 0x3e, 0xd9, 0x5f, 0x33, 0xda, 0xc6, 0xf0, 0x8e, 0x34, 0xb9,
+	0x6e, 0xd6, 0x31, 0x99, 0x97, 0x39, 0xf0, 0x6d, 0x8e, 0x7c, 0x8b, 0x76,
+	0xc8, 0xa9, 0x0a, 0xc7, 0x58, 0x8f, 0xee, 0x5b, 0xff, 0x9e, 0xd1, 0x1d,
+	0x47, 0xff, 0x31, 0xa4, 0x1b, 0x02, 0xd9, 0x63, 0x2e, 0xc6, 0x8f, 0xe3,
+	0x79, 0xbd, 0x39, 0x5c, 0xd1, 0x32, 0x18, 0x07, 0xed, 0x31, 0x39, 0xa7,
+	0xe4, 0x70, 0x83, 0x04, 0x21, 0x87, 0x5c, 0xe3, 0xd6, 0x13, 0xef, 0x91,
+	0x7c, 0xcc, 0x4a, 0xd0, 0x76, 0x76, 0x6e, 0x6d, 0xc2, 0x1c, 0xb5, 0x15,
+	0x9c, 0x8e, 0x41, 0x0e, 0x97, 0x5b, 0x0d, 0x94, 0x18, 0x62, 0x99, 0xff,
+	0x48, 0x0a, 0x92, 0x5b, 0xf8, 0xbd, 0x80, 0x44, 0x0d, 0xd4, 0xbb, 0x25,
+	0xe0, 0xf1, 0x80, 0xfc, 0xc9, 0x80, 0x3f, 0x01, 0xd1, 0xf6, 0x41, 0x3a,
+	0x2b, 0x7c, 0xdf, 0x9b, 0x30, 0xd4, 0xbb, 0x41, 0xbc, 0x0b, 0x49, 0x72,
+	0xab, 0xff, 0x7e, 0x10, 0xef, 0x6f, 0x96, 0x71, 0x13, 0xb4, 0x94, 0x9e,
+	0x37, 0xb2, 0xa0, 0xf1, 0xce, 0x90, 0x9a, 0x2b, 0xea, 0x8e, 0xd7, 0xf5,
+	0x33, 0x8e, 0x7a, 0xff, 0x0a, 0x63, 0x81, 0xde, 0x52, 0x02, 0xb4, 0xb4,
+	0x83, 0x16, 0xd2, 0x58, 0x30, 0xb2, 0xd5, 0x10, 0xf2, 0x93, 0x46, 0xee,
+	0xf4, 0x61, 0x3c, 0x8b, 0x69, 0xa4, 0x9f, 0x67, 0x8a, 0xf6, 0xbb, 0xeb,
+	0xda, 0xef, 0x46, 0x7b, 0x8e, 0xc1, 0xf6, 0x9e, 0xfc, 0x17, 0x94, 0x2c,
+	0x26, 0xae, 0xc3, 0x8f, 0xe0, 0xaf, 0xc1, 0x8f, 0x7f, 0xa3, 0xf9, 0xf1,
+	0xd7, 0xf2, 0x9b, 0xe7, 0xc7, 0x7f, 0xfa, 0x0d, 0xf1, 0x43, 0x24, 0x7f,
+	0x8c, 0xcf, 0x21, 0x29, 0x28, 0xbb, 0x45, 0xbd, 0xa5, 0xbc, 0xd3, 0x66,
+	0x91, 0x4f, 0x94, 0x63, 0xe8, 0x40, 0x35, 0x84, 0xf4, 0x49, 0xa4, 0x1b,
+	0x02, 0xa3, 0xc7, 0xae, 0x62, 0xfd, 0x5d, 0x31, 0xb7, 0xfa, 0x7e, 0xa3,
+	0x10, 0x37, 0xa5, 0x43, 0xcc, 0x77, 0xc3, 0x69, 0xb7, 0x5b, 0x66, 0x5e,
+	0x7e, 0x80, 0xf7, 0x6f, 0x06, 0x7c, 0xff, 0x9e, 0x9d, 0x6a, 0x7a, 0x23,
+	0xa3, 0x9e, 0xc2, 0xe4, 0x67, 0xc6, 0x48, 0x87, 0x02, 0xb9, 0x52, 0x62,
+	0xdc, 0x48, 0xc7, 0x60, 0xa7, 0x98, 0x1f, 0x08, 0x78, 0x34, 0xf7, 0xa3,
+	0xae, 0x6f, 0xb3, 0x7c, 0xda, 0xfb, 0x41, 0xfb, 0x5a, 0xdb, 0x95, 0x01,
+	0x2d, 0xa4, 0x81, 0x74, 0x15, 0x82, 0x9a, 0xf7, 0xe8, 0xe7, 0x80, 0xea,
+	0x27, 0x98, 0x1e, 0x10, 0xfa, 0xd0, 0xfc, 0x14, 0xf5, 0x80, 0xed, 0xd8,
+	0x97, 0x67, 0x93, 0xf3, 0x15, 0xbf, 0x8f, 0x42, 0x7d, 0x1f, 0xa0, 0x47,
+	0x36, 0x19, 0x76, 0x18, 0x6b, 0xcf, 0xae, 0x0e, 0xe3, 0xdd, 0x97, 0x24,
+	0x7b, 0xfa, 0x76, 0x03, 0x73, 0x40, 0xbf, 0xe4, 0xd1, 0x28, 0x6c, 0x36,
+	0xf5, 0x2c, 0x22, 0xb9, 0x18, 0xcb, 0x3e, 0xa2, 0xc7, 0x0d, 0x49, 0x46,
+	0xe5, 0xbf, 0xd2, 0x52, 0xa3, 0xe3, 0x79, 0x3d, 0x9f, 0x34, 0xe6, 0x43,
+	0x1a, 0xfc, 0xb9, 0xa4, 0xeb, 0xe6, 0xe2, 0xf3, 0x9a, 0xbc, 0x30, 0x61,
+	0xe3, 0x23, 0xda, 0x87, 0xb0, 0xdd, 0x64, 0xdd, 0xda, 0x4d, 0xa2, 0x0d,
+	0x79, 0x8f, 0x3a, 0x6b, 0xfc, 0x0a, 0x7d, 0xca, 0x20, 0xfa, 0x29, 0xce,
+	0x1a, 0x92, 0x73, 0xe0, 0xab, 0x9d, 0xb7, 0x69, 0x79, 0xad, 0xc9, 0x52,
+	0x78, 0x5d, 0x59, 0x3a, 0x68, 0x78, 0xf6, 0x1a, 0xbe, 0x05, 0xfe, 0x67,
+	0x62, 0xd6, 0x4a, 0xf9, 0xb2, 0x54, 0x9c, 0x7a, 0x2b, 0xb2, 0xe4, 0xb7,
+	0x8f, 0x40, 0x76, 0xfd, 0x31, 0xd6, 0xd2, 0xec, 0xd7, 0x01, 0x8d, 0xa5,
+	0xac, 0xc6, 0x28, 0x1c, 0xc7, 0xf3, 0x0d, 0x73, 0xab, 0x7c, 0xc3, 0x61,
+	0xb4, 0x95, 0x40, 0xae, 0xa7, 0x59, 0xf6, 0xcd, 0xfa, 0x7d, 0x1c, 0x56,
+	0x32, 0xbb, 0x77, 0xca, 0x32, 0x87, 0x82, 0x92, 0x19, 0x9a, 0x19, 0x90,
+	0xc1, 0x6a, 0x07, 0xd6, 0xf4, 0x0d, 0x17, 0xbe, 0xf3, 0xdd, 0x61, 0xb1,
+	0x61, 0x17, 0x31, 0xe7, 0x7e, 0xf0, 0xb8, 0x1a, 0x16, 0x23, 0xed, 0x20,
+	0xad, 0xc7, 0x58, 0xa1, 0xd0, 0xd0, 0xaa, 0x7c, 0x03, 0xea, 0xa0, 0xef,
+	0xfe, 0xb5, 0xf5, 0x20, 0x9f, 0xe0, 0x6d, 0xd6, 0x79, 0xd3, 0x85, 0x1f,
+	0xd6, 0x3e, 0x8b, 0xa5, 0xb4, 0x13, 0xbe, 0x8d, 0xf8, 0x10, 0xf4, 0x5b,
+	0xe9, 0x42, 0xc1, 0x48, 0xef, 0x47, 0x1f, 0xa2, 0xe4, 0xb4, 0x58, 0x7d,
+	0xda, 0xd7, 0x7b, 0x55, 0xbe, 0xa3, 0x9f, 0xb2, 0x37, 0x07, 0x4c, 0xc0,
+	0x39, 0x2d, 0x28, 0x5d, 0xcf, 0x99, 0x31, 0x99, 0x2c, 0x29, 0x4c, 0x23,
+	0xc9, 0xca, 0x1f, 0x49, 0xee, 0xb4, 0xc8, 0x37, 0xa7, 0x58, 0xef, 0x05,
+	0x5d, 0xef, 0x79, 0xd4, 0x4b, 0x26, 0x06, 0x03, 0x16, 0xfc, 0x80, 0x05,
+	0x35, 0xe9, 0x4d, 0x20, 0x35, 0x87, 0xf1, 0x1b, 0xa4, 0x93, 0x41, 0x3d,
+	0x0f, 0x03, 0x3d, 0x0f, 0x7e, 0x88, 0xdc, 0x53, 0x6a, 0x84, 0x3d, 0xf9,
+	0x2f, 0xa0, 0x35, 0x26, 0x5f, 0xc0, 0x3c, 0x2e, 0x4d, 0x11, 0x67, 0xbd,
+	0x20, 0x8b, 0x53, 0xc4, 0x5d, 0xcf, 0xcb, 0xe4, 0x54, 0xd2, 0xf9, 0x26,
+	0xf8, 0x7c, 0x4a, 0x38, 0x97, 0x5e, 0x07, 0x29, 0x30, 0xa0, 0x95, 0x78,
+	0x1c, 0xf6, 0xac, 0x67, 0xab, 0xd7, 0x5f, 0x97, 0xee, 0xcf, 0xae, 0x58,
+	0x72, 0xc5, 0xa4, 0x7d, 0xba, 0x56, 0xc7, 0xb3, 0x5a, 0xc7, 0x47, 0x9d,
+	0x0e, 0x31, 0xa0, 0xd7, 0x99, 0xb1, 0x02, 0xbc, 0x1f, 0xf5, 0xfa, 0x7f,
+	0x1b, 0x35, 0xfc, 0x33, 0x00, 0xac, 0x6a, 0x29, 0x7f, 0xf7, 0xb7, 0xd3,
+	0xf1, 0x7a, 0xdd, 0xe6, 0xf8, 0x2d, 0x68, 0x13, 0x42, 0x7a, 0x7d, 0xbd,
+	0x46, 0x1f, 0x75, 0x6d, 0x07, 0xa8, 0x17, 0x68, 0xf3, 0x07, 0xe0, 0x05,
+	0xf9, 0xff, 0x56, 0xf4, 0xb9, 0x37, 0xf8, 0x96, 0xf4, 0x79, 0xec, 0x7a,
+	0xfa, 0x5c, 0xaf, 0xcb, 0x67, 0xc9, 0x0b, 0x8c, 0x2d, 0x33, 0x9e, 0x6c,
+	0x75, 0x81, 0xd7, 0x09, 0xc8, 0x29, 0x68, 0x28, 0xfd, 0x8d, 0x9b, 0x09,
+	0x79, 0x78, 0xce, 0x93, 0x27, 0xd6, 0xf3, 0xeb, 0x78, 0xb6, 0x77, 0xb0,
+	0x7a, 0x45, 0xd9, 0xd9, 0x73, 0xca, 0xce, 0x5a, 0x87, 0x0b, 0x42, 0x79,
+	0xbb, 0x2d, 0x48, 0xbe, 0x3f, 0xed, 0x7c, 0x16, 0x34, 0x5a, 0x89, 0x84,
+	0xd1, 0x55, 0x30, 0x8c, 0xcf, 0xca, 0xfe, 0xf9, 0x87, 0x65, 0x7f, 0x89,
+	0x7d, 0xa4, 0xf1, 0xde, 0x46, 0x59, 0x13, 0x6c, 0x2d, 0x6d, 0xfa, 0x1b,
+	0x01, 0x6f, 0x2c, 0x03, 0xfe, 0x6b, 0x29, 0x70, 0x4f, 0xf5, 0x62, 0x20,
+	0x3b, 0x4f, 0xdd, 0x45, 0x79, 0xb5, 0xde, 0xe6, 0xfb, 0xf6, 0xbe, 0x66,
+	0xff, 0x06, 0x4b, 0x93, 0xc4, 0x80, 0x46, 0xd6, 0xe1, 0x9a, 0x51, 0x37,
+	0x2f, 0x98, 0xde, 0x9c, 0x3f, 0x09, 0x3e, 0x51, 0xaf, 0xc9, 0x37, 0xf8,
+	0xc0, 0x10, 0x75, 0x96, 0xcf, 0xe2, 0x06, 0xd3, 0xd4, 0x3b, 0x09, 0x05,
+	0x41, 0x46, 0x2e, 0xc6, 0x3a, 0x77, 0x80, 0xce, 0xb5, 0x3a, 0xcd, 0x75,
+	0x14, 0x6d, 0x43, 0x58, 0x36, 0x80, 0xe7, 0x4e, 0x19, 0x9f, 0xcf, 0x60,
+	0xcc, 0x3b, 0x75, 0xdf, 0xab, 0x7c, 0x0c, 0xfa, 0x48, 0xe8, 0xf5, 0xd8,
+	0xe0, 0xdb, 0x41, 0x94, 0x39, 0xba, 0xac, 0xa1, 0xae, 0xcc, 0x5f, 0xb7,
+	0x8f, 0x62, 0x7c, 0xfa, 0x8a, 0x61, 0x8d, 0x7f, 0x5c, 0x37, 0xc7, 0xf5,
+	0xee, 0xfb, 0x87, 0x42, 0xdd, 0xb8, 0x50, 0x2a, 0x98, 0x41, 0x25, 0xa3,
+	0x2f, 0xfc, 0x4e, 0x4d, 0x46, 0x81, 0x97, 0x55, 0x2f, 0xe4, 0x31, 0x69,
+	0x69, 0x06, 0x4f, 0x07, 0x41, 0x2b, 0x78, 0xd7, 0x1e, 0x00, 0xff, 0x9a,
+	0x25, 0x5f, 0x4d, 0xeb, 0x77, 0x2c, 0x0f, 0xc9, 0x68, 0xcc, 0xf7, 0x47,
+	0xb7, 0x99, 0x1e, 0xe6, 0x45, 0x9d, 0xd2, 0x8f, 0x83, 0x9e, 0x0e, 0x98,
+	0x92, 0x3f, 0x39, 0x08, 0x59, 0x23, 0x26, 0x6b, 0x80, 0xac, 0xc5, 0x94,
+	0xad, 0x37, 0x6c, 0xd6, 0xc7, 0xbb, 0xd3, 0xbf, 0x17, 0xf4, 0xda, 0xb0,
+	0x9e, 0xdf, 0xc6, 0x1f, 0xbb, 0x6d, 0xa5, 0xed, 0xa8, 0x63, 0x48, 0x50,
+	0x8d, 0x8f, 0xb2, 0xd3, 0xab, 0xc7, 0x37, 0xda, 0xfd, 0xf1, 0x1f, 0xd1,
+	0x7d, 0xb5, 0xd5, 0xf5, 0x15, 0xbb, 0xce, 0xf8, 0x78, 0x77, 0xfa, 0xa3,
+	0x9b, 0xbd, 0x36, 0xb1, 0xba, 0x36, 0xed, 0x6b, 0xda, 0xb0, 0xbe, 0x3f,
+	0x06, 0xde, 0x9d, 0xbe, 0xab, 0xd9, 0x6b, 0xc3, 0x7a, 0x0d, 0xf0, 0x6d,
+	0x7c, 0x47, 0xd9, 0xdf, 0x5f, 0x27, 0xfb, 0xfb, 0x21, 0xfb, 0xbe, 0x4c,
+	0xad, 0xc5, 0xc9, 0x7e, 0xbc, 0xc3, 0x38, 0x87, 0xd8, 0xaa, 0x16, 0xd7,
+	0x84, 0x4e, 0x34, 0x03, 0xb7, 0xb4, 0x30, 0x96, 0xd1, 0xb8, 0x98, 0xb1,
+	0x0d, 0x71, 0xb0, 0xd8, 0x21, 0xe9, 0x82, 0x8d, 0xea, 0x8a, 0xef, 0xa3,
+	0xc2, 0x55, 0x62, 0x0a, 0x2f, 0x67, 0xf4, 0x18, 0x8c, 0x6b, 0xc8, 0x77,
+	0xe6, 0x73, 0x2b, 0x71, 0x4e, 0x07, 0xe2, 0x20, 0xe2, 0x5d, 0xe2, 0x25,
+	0x9f, 0x7e, 0x9f, 0x9e, 0x03, 0x46, 0x4d, 0x27, 0x32, 0xc6, 0x60, 0x75,
+	0xd0, 0xf0, 0x74, 0x82, 0xef, 0x0f, 0x68, 0x9f, 0xb6, 0x96, 0xde, 0xb7,
+	0xaf, 0xa1, 0x97, 0xb8, 0x2a, 0x21, 0x13, 0x90, 0x91, 0xd0, 0x09, 0xda,
+	0xd8, 0xe7, 0x46, 0x16, 0x67, 0x89, 0x1f, 0xfa, 0xc0, 0x17, 0xd2, 0x4b,
+	0xfe, 0x51, 0x97, 0x5b, 0x60, 0x1f, 0xba, 0x52, 0x65, 0xd4, 0x67, 0x7c,
+	0x3d, 0xae, 0xe2, 0xb2, 0x66, 0xa4, 0x08, 0x9e, 0x40, 0xeb, 0x38, 0x68,
+	0x1d, 0xd7, 0x31, 0xd9, 0x3e, 0xd8, 0xef, 0xd0, 0xb4, 0x4f, 0xeb, 0x8d,
+	0x21, 0x7f, 0x6d, 0x56, 0xd3, 0x5e, 0xef, 0x77, 0x3c, 0xfc, 0x75, 0x4f,
+	0x0f, 0x65, 0xc6, 0x2a, 0x10, 0xb3, 0x8d, 0x2b, 0xf9, 0x00, 0xf6, 0x33,
+	0xc4, 0xd3, 0xa5, 0x16, 0xdf, 0xff, 0x72, 0x3e, 0xf4, 0xff, 0xd4, 0x79,
+	0x7f, 0x0e, 0xcd, 0xd2, 0x79, 0x82, 0x73, 0x58, 0xa1, 0x3f, 0xc6, 0xdd,
+	0x8d, 0xfd, 0xb0, 0x9b, 0x79, 0x45, 0xeb, 0x4e, 0xd9, 0x5b, 0x7a, 0xa7,
+	0xa6, 0xbf, 0x19, 0xf4, 0x8f, 0x42, 0xb6, 0x6b, 0x36, 0x23, 0x5f, 0x19,
+	0x43, 0xde, 0xc3, 0x62, 0xe4, 0x71, 0xbe, 0x42, 0xfb, 0xa1, 0xe7, 0x13,
+	0xe5, 0x7c, 0xd6, 0xda, 0x96, 0xf5, 0xf8, 0xfa, 0x8e, 0x35, 0x7c, 0x15,
+	0xcd, 0xd7, 0x88, 0x34, 0x9c, 0x50, 0x71, 0x2d, 0xfa, 0x25, 0xaf, 0xe9,
+	0xbf, 0x9e, 0x1b, 0x99, 0x9c, 0x95, 0xbe, 0xb0, 0x90, 0xbe, 0x38, 0xcb,
+	0xfa, 0x1b, 0xa4, 0xcb, 0xb9, 0x88, 0x79, 0xe7, 0xb1, 0xde, 0xc6, 0xb4,
+	0x27, 0xdf, 0xe4, 0x6f, 0xbe, 0x12, 0x45, 0x2c, 0xcd, 0xb1, 0xc9, 0x33,
+	0xd2, 0x6f, 0x2a, 0x7a, 0x56, 0xf8, 0x0d, 0xfa, 0x3e, 0x56, 0x59, 0xcb,
+	0xdb, 0x7a, 0x3b, 0xe3, 0xc7, 0xec, 0xdf, 0x35, 0x3d, 0xbd, 0x58, 0x2f,
+	0x66, 0x6f, 0x86, 0x7d, 0x0c, 0xd1, 0x36, 0x82, 0xf7, 0xdc, 0x5f, 0x59,
+	0x0a, 0x11, 0x83, 0x5f, 0x28, 0x85, 0x95, 0xcd, 0xcb, 0x3a, 0x2d, 0x5a,
+	0x3f, 0x6e, 0xd3, 0xbe, 0x23, 0xac, 0x6c, 0xb6, 0x18, 0x26, 0x71, 0x09,
+	0xca, 0x90, 0x9f, 0x67, 0xde, 0xa7, 0xe3, 0xde, 0x5d, 0x61, 0xfb, 0x0f,
+	0x43, 0xbe, 0x4d, 0xa8, 0xd1, 0x55, 0x1f, 0x93, 0xbb, 0xc0, 0x72, 0xef,
+	0x84, 0xdc, 0xde, 0x89, 0xb8, 0x3b, 0x21, 0xf9, 0x14, 0xf5, 0x68, 0x40,
+	0xc5, 0x26, 0x86, 0xbd, 0x0f, 0x65, 0x4d, 0x28, 0x83, 0x13, 0x33, 0x31,
+	0x7f, 0xfb, 0x77, 0x65, 0x1c, 0x32, 0x9e, 0x4f, 0xf5, 0x82, 0x0e, 0xda,
+	0x60, 0x60, 0x1c, 0x3b, 0xc5, 0xb8, 0x1d, 0x7f, 0xfd, 0x61, 0x6f, 0x5e,
+	0xbb, 0x90, 0x47, 0x0c, 0x9f, 0xea, 0xd4, 0x75, 0x36, 0x08, 0xf7, 0x7f,
+	0xf2, 0x66, 0x0b, 0xd2, 0xee, 0x35, 0x75, 0xdf, 0x8f, 0xfc, 0x7b, 0x75,
+	0xff, 0x05, 0xbc, 0xdf, 0x86, 0xdf, 0x20, 0xca, 0x6e, 0x47, 0x99, 0x83,
+	0xb2, 0xf7, 0x20, 0xff, 0x7e, 0xbd, 0x1f, 0xe0, 0xb7, 0x69, 0x41, 0xfe,
+	0x31, 0xbc, 0x87, 0xad, 0x30, 0x5f, 0xc6, 0xfb, 0xf7, 0xe2, 0xf7, 0xee,
+	0x35, 0x75, 0xda, 0xd6, 0xe4, 0x3f, 0xb5, 0xc2, 0x83, 0x0b, 0xa5, 0x9f,
+	0x69, 0xbb, 0x46, 0x79, 0x66, 0xfe, 0x94, 0x7e, 0xf7, 0xce, 0xd0, 0xea,
+	0xf2, 0x1d, 0x7e, 0xbe, 0x6e, 0x0d, 0x3b, 0xb1, 0x86, 0x3e, 0xc6, 0x7c,
+	0xbb, 0xf6, 0x5d, 0x6f, 0xf7, 0xe2, 0xf4, 0x92, 0xdf, 0x8e, 0x7e, 0xed,
+	0xce, 0x35, 0x63, 0x3c, 0xdf, 0x50, 0xcb, 0x37, 0x07, 0x86, 0x4e, 0xb2,
+	0xec, 0x72, 0xc3, 0xea, 0x3a, 0x6f, 0xd6, 0xe5, 0x37, 0x06, 0x86, 0x94,
+	0x8f, 0xbb, 0xab, 0x71, 0x75, 0x9d, 0x64, 0x63, 0x6d, 0x1e, 0x35, 0x5b,
+	0x18, 0x4a, 0x2f, 0x53, 0x8e, 0xa1, 0x0b, 0xdf, 0x1a, 0xc9, 0x4e, 0xb9,
+	0xee, 0x84, 0xb3, 0x14, 0x0f, 0x0a, 0x7d, 0x10, 0xb1, 0x2a, 0xcb, 0x5f,
+	0x46, 0x39, 0xb0, 0x4c, 0x75, 0x54, 0x68, 0x93, 0xd6, 0xc7, 0xa4, 0x09,
+	0x8d, 0x49, 0x55, 0x36, 0x94, 0x55, 0x18, 0xf2, 0xf9, 0x11, 0x60, 0x1e,
+	0xfd, 0xfc, 0x02, 0x9e, 0x13, 0xf5, 0xb8, 0x17, 0xfd, 0x2e, 0x8d, 0x64,
+	0x67, 0xe9, 0xf3, 0x2e, 0x8e, 0xec, 0x99, 0xa5, 0xce, 0x5f, 0x82, 0xce,
+	0x07, 0x64, 0x52, 0xf9, 0x3f, 0xd2, 0xc1, 0x76, 0x4b, 0x23, 0x9d, 0x0b,
+	0x4c, 0x97, 0x47, 0xec, 0x85, 0xa0, 0xec, 0x8b, 0x79, 0x6d, 0x99, 0x4f,
+	0x2c, 0xf8, 0x3a, 0x10, 0x95, 0x70, 0x9a, 0x32, 0x69, 0xa5, 0x80, 0xbd,
+	0x31, 0x9f, 0x27, 0x47, 0x26, 0x6d, 0xca, 0xe7, 0x87, 0x1a, 0xa4, 0x25,
+	0x2a, 0x0d, 0xca, 0xde, 0x3c, 0xa5, 0xc7, 0xba, 0x84, 0xb1, 0x36, 0x29,
+	0x7d, 0xca, 0xda, 0xa1, 0x38, 0xc6, 0x39, 0x68, 0xd8, 0xbd, 0x18, 0x8f,
+	0x91, 0x72, 0x87, 0x4c, 0x54, 0xa9, 0x37, 0xdb, 0xc2, 0xb5, 0xf8, 0xf8,
+	0x3c, 0xda, 0xf9, 0x71, 0x19, 0xc7, 0x2b, 0x03, 0x97, 0x41, 0x96, 0xd3,
+	0x96, 0x99, 0x0d, 0xc2, 0xcf, 0xcf, 0xfa, 0x75, 0x48, 0xd3, 0xd9, 0x91,
+	0xe4, 0x42, 0x12, 0x7d, 0x75, 0xd0, 0x86, 0xc1, 0x76, 0x05, 0xf1, 0x63,
+	0xdf, 0x6c, 0x07, 0x5f, 0x34, 0x40, 0x3f, 0x72, 0x1e, 0x7e, 0xa4, 0x43,
+	0x0e, 0x95, 0x54, 0x1f, 0x09, 0xf6, 0x51, 0xd4, 0x6d, 0x3b, 0x17, 0x1a,
+	0x10, 0xdb, 0x24, 0xcd, 0x17, 0xa5, 0xd6, 0x76, 0x48, 0xbc, 0x76, 0x5e,
+	0xdf, 0x3f, 0x77, 0x33, 0xb1, 0x7a, 0xdd, 0x8f, 0x4a, 0x10, 0x74, 0xe4,
+	0xd0, 0x07, 0xc7, 0xaf, 0xf5, 0xed, 0xf7, 0x97, 0x34, 0x97, 0xaf, 0xe9,
+	0x6b, 0x93, 0x8e, 0xb9, 0xac, 0x44, 0xee, 0xd7, 0x1a, 0x5b, 0xc5, 0x00,
+	0x90, 0x07, 0x09, 0xe5, 0x7a, 0x60, 0x17, 0xab, 0x03, 0x5a, 0x46, 0x5e,
+	0x40, 0x59, 0x7d, 0x6c, 0xe3, 0xc9, 0x57, 0x01, 0x98, 0xae, 0x08, 0x3d,
+	0x0f, 0xa6, 0x33, 0xad, 0xde, 0x5e, 0xd3, 0xf5, 0xe2, 0x19, 0xc8, 0x0d,
+	0xfa, 0x2c, 0xae, 0xb4, 0xe5, 0x9c, 0x5e, 0x18, 0xb9, 0x34, 0x15, 0xc7,
+	0x9c, 0x3c, 0xbf, 0xe0, 0xf1, 0x9a, 0x3e, 0x27, 0x20, 0x8b, 0x76, 0x02,
+	0x71, 0x33, 0x7d, 0x7c, 0x42, 0x5e, 0xb2, 0x7d, 0xff, 0x43, 0x5f, 0x84,
+	0xfa, 0x55, 0xd2, 0x46, 0xda, 0xcf, 0x63, 0x6e, 0xae, 0xcc, 0x38, 0x9e,
+	0x0c, 0xf6, 0xc0, 0x8f, 0x7c, 0x23, 0x64, 0x1d, 0x66, 0x7c, 0x75, 0x25,
+	0x54, 0x3f, 0x1f, 0x1f, 0x2b, 0x3c, 0xaf, 0xf7, 0x7e, 0xcf, 0x6b, 0x79,
+	0x59, 0x82, 0xbc, 0xf4, 0x26, 0x4c, 0xe9, 0x06, 0xed, 0xa8, 0xd3, 0xd7,
+	0x85, 0x38, 0x87, 0x31, 0x74, 0x1c, 0xf4, 0x98, 0xb0, 0x1d, 0x9b, 0x34,
+	0x66, 0xff, 0x77, 0x61, 0xfa, 0xb6, 0x56, 0xb5, 0xaf, 0x7c, 0x5e, 0xc9,
+	0xb3, 0x27, 0xdf, 0x41, 0xfd, 0xde, 0x97, 0xa9, 0x20, 0x21, 0x8d, 0xd4,
+	0xf6, 0x4f, 0x59, 0xff, 0x39, 0x5d, 0xff, 0x59, 0xd4, 0x0f, 0x60, 0x4e,
+	0xae, 0xbb, 0x57, 0xd1, 0xfb, 0x1c, 0xf8, 0x1e, 0x94, 0xe2, 0x8a, 0xcc,
+	0x3f, 0x07, 0x99, 0xa7, 0x7c, 0x9f, 0x87, 0xbe, 0x82, 0xf8, 0x7b, 0x29,
+	0xf7, 0x65, 0x19, 0x3c, 0x9d, 0x6b, 0xe0, 0x5e, 0x67, 0xc2, 0x60, 0xec,
+	0x49, 0x99, 0xec, 0x90, 0xc7, 0x4b, 0x49, 0x73, 0xa2, 0x6e, 0x2d, 0x77,
+	0xac, 0x5a, 0x4b, 0xca, 0x80, 0xaa, 0x9f, 0x62, 0xfd, 0x72, 0x9d, 0x0c,
+	0xcc, 0xcf, 0x5e, 0xaf, 0x1d, 0x65, 0x80, 0xed, 0xd6, 0xc3, 0xe9, 0xdc,
+	0x1b, 0x74, 0xdd, 0x45, 0x87, 0xfb, 0xb8, 0x8d, 0x52, 0x50, 0x32, 0x16,
+	0x90, 0xa2, 0x43, 0xbd, 0xca, 0x26, 0x42, 0x62, 0x01, 0x2b, 0x7d, 0x10,
+	0x74, 0x66, 0x52, 0x61, 0xf1, 0xf6, 0x12, 0xc6, 0xb1, 0x06, 0x4b, 0xa6,
+	0xeb, 0x5e, 0xb2, 0x45, 0xca, 0x88, 0x3d, 0x17, 0x91, 0x16, 0x2b, 0xd0,
+	0xd9, 0x68, 0x08, 0x36, 0xc0, 0x97, 0xf1, 0x88, 0xcc, 0xa1, 0xce, 0x3c,
+	0xde, 0x3d, 0x5e, 0xf1, 0x25, 0xc6, 0x75, 0x0d, 0xf0, 0x68, 0x8f, 0xfd,
+	0xff, 0xdc, 0x7c, 0xac, 0xbe, 0xae, 0x8f, 0x89, 0x89, 0x65, 0x89, 0x4d,
+	0x89, 0x29, 0xf9, 0x8e, 0x38, 0xf1, 0x20, 0x68, 0xa1, 0xce, 0xb6, 0x48,
+	0x24, 0x6d, 0xc5, 0x87, 0xc5, 0xf7, 0xfd, 0x97, 0x21, 0x4b, 0x05, 0xb7,
+	0xd1, 0xee, 0x90, 0x67, 0x20, 0x37, 0xe7, 0x57, 0x70, 0x4c, 0x02, 0x72,
+	0x44, 0x3f, 0xea, 0xca, 0x39, 0xc7, 0x4e, 0x7c, 0x0e, 0xe9, 0xb7, 0x9d,
+	0xdf, 0x22, 0xdf, 0x9e, 0x10, 0xe9, 0x43, 0x2c, 0x04, 0xbb, 0x3e, 0xe3,
+	0x63, 0xfb, 0x16, 0xc6, 0x64, 0x5a, 0x96, 0xae, 0xa0, 0x4f, 0xcb, 0x34,
+	0x00, 0x6a, 0xef, 0x42, 0x3d, 0x4f, 0x37, 0xfc, 0xb2, 0x83, 0xa8, 0x4b,
+	0x1a, 0x18, 0x2f, 0x7f, 0x07, 0x3a, 0xeb, 0xba, 0xf7, 0x39, 0x8b, 0x75,
+	0xb6, 0xe6, 0x39, 0xac, 0xbf, 0x92, 0xf3, 0xfe, 0x56, 0xe1, 0xfe, 0xaa,
+	0xf4, 0xb5, 0xa9, 0x78, 0x8e, 0xcf, 0x90, 0xf7, 0x7e, 0x62, 0xa1, 0x84,
+	0xc2, 0x9a, 0xc4, 0x0d, 0xe7, 0xc1, 0xfb, 0x4f, 0x2a, 0x4c, 0x43, 0xfc,
+	0x06, 0xfa, 0x4b, 0xc4, 0x14, 0x1e, 0x96, 0xf6, 0x70, 0x1d, 0xb1, 0x45,
+	0x0a, 0x6b, 0xe3, 0xe3, 0x0b, 0xb6, 0x65, 0x3d, 0xb6, 0xad, 0x5f, 0x3f,
+	0xd6, 0xd9, 0x14, 0xc8, 0x1d, 0xa3, 0x3c, 0xd3, 0x3f, 0xb6, 0xca, 0xbe,
+	0x54, 0x23, 0xf8, 0xde, 0xa6, 0xfd, 0xf8, 0xfb, 0x80, 0xd9, 0x80, 0xbd,
+	0x4d, 0xcb, 0xa9, 0xd9, 0x9e, 0xf7, 0xa0, 0xec, 0x17, 0xe0, 0x3f, 0xcb,
+	0xf6, 0x37, 0x78, 0x7e, 0xf2, 0x61, 0xe8, 0xf2, 0xdc, 0x26, 0x6f, 0xef,
+	0x8a, 0xeb, 0xe0, 0xe3, 0x04, 0x1f, 0xf7, 0x99, 0x1a, 0xef, 0x73, 0x6d,
+	0xbc, 0x7d, 0x2e, 0x43, 0xd5, 0x65, 0xac, 0x55, 0x1f, 0x5b, 0x52, 0x87,
+	0x5d, 0xf7, 0x9c, 0xe3, 0xe3, 0xc8, 0xed, 0xf0, 0xa1, 0x21, 0xcd, 0xeb,
+	0x66, 0xf0, 0x9a, 0x18, 0x25, 0x22, 0x89, 0x36, 0x62, 0x8a, 0x07, 0x1b,
+	0x6a, 0x58, 0xe6, 0x6f, 0xdc, 0xa0, 0xcd, 0x78, 0x8f, 0x38, 0x86, 0xb4,
+	0x6f, 0xd7, 0x78, 0x86, 0xd8, 0xe6, 0x31, 0x8c, 0x11, 0x94, 0x44, 0x3b,
+	0xf3, 0x7f, 0xa9, 0xdb, 0xf0, 0xd9, 0x95, 0xee, 0xad, 0xf5, 0xf2, 0x3c,
+	0x00, 0x3a, 0x39, 0x1f, 0x7f, 0xef, 0xb5, 0x43, 0xd9, 0x93, 0x9a, 0x5c,
+	0xf8, 0x34, 0xf9, 0xe3, 0x92, 0xb6, 0xb8, 0xb4, 0x81, 0xb6, 0x7b, 0xe0,
+	0x53, 0xb6, 0xb6, 0xb1, 0x4f, 0x7f, 0xec, 0x7a, 0x9a, 0xea, 0xf1, 0x55,
+	0x02, 0x63, 0x34, 0xca, 0xd6, 0x76, 0xf2, 0xae, 0x43, 0xf9, 0x96, 0xda,
+	0x7a, 0xd0, 0xf7, 0x73, 0xec, 0xb5, 0xe5, 0xef, 0xad, 0xa3, 0x6b, 0x2d,
+	0xe6, 0xdb, 0x86, 0x77, 0xa4, 0xc9, 0x84, 0x5d, 0x72, 0x65, 0x87, 0xe3,
+	0xe3, 0xbb, 0x7a, 0x3a, 0x88, 0xf1, 0x48, 0x33, 0x69, 0xf0, 0x31, 0x39,
+	0x7f, 0x5c, 0x1b, 0xd2, 0x93, 0xd6, 0xe7, 0x44, 0xfb, 0xf5, 0xbc, 0x6e,
+	0xd3, 0x75, 0x92, 0x68, 0xfb, 0xc7, 0x98, 0x03, 0x9f, 0x39, 0x0f, 0x1f,
+	0x1b, 0x26, 0xbd, 0x7e, 0xa2, 0xeb, 0xc5, 0x00, 0xd4, 0x19, 0x9f, 0x4f,
+	0x6d, 0x7a, 0x8d, 0xb6, 0xaf, 0x19, 0xd7, 0x72, 0x56, 0xdb, 0x91, 0xf7,
+	0xd4, 0xcd, 0xaf, 0x4f, 0x0a, 0xf3, 0x94, 0x8b, 0x77, 0x21, 0xf5, 0x63,
+	0xa3, 0x7e, 0xf8, 0x91, 0x0c, 0x62, 0x21, 0xc6, 0x48, 0xd7, 0xc4, 0x47,
+	0x3c, 0x47, 0x1c, 0xcb, 0x23, 0x5e, 0x56, 0x7e, 0xc4, 0xf3, 0x91, 0xc8,
+	0xc3, 0x9e, 0x54, 0xef, 0xa5, 0x8c, 0x8d, 0x8d, 0x57, 0x9c, 0xb1, 0xbd,
+	0x95, 0xfe, 0x31, 0xc6, 0x11, 0x9e, 0xcc, 0xa1, 0x7e, 0x45, 0xc6, 0x0d,
+	0xb4, 0xcb, 0xaa, 0x76, 0x6a, 0x1f, 0x68, 0x9d, 0x7e, 0x84, 0xfa, 0x38,
+	0xee, 0x8d, 0x15, 0x19, 0xcb, 0xc1, 0x06, 0xcd, 0xcf, 0xc0, 0xc7, 0xd9,
+	0x56, 0x86, 0x72, 0xb9, 0xc7, 0xb1, 0x86, 0x95, 0xec, 0xc5, 0xac, 0x51,
+	0xae, 0x65, 0x79, 0xe6, 0x1d, 0xb0, 0xa1, 0xae, 0xdc, 0x0d, 0x5b, 0xf8,
+	0x10, 0x64, 0x55, 0xce, 0xc0, 0x10, 0x9e, 0x81, 0xf1, 0x3a, 0x13, 0x13,
+	0xe3, 0x78, 0x87, 0x84, 0x8f, 0xc4, 0x25, 0x74, 0x84, 0xb1, 0x58, 0xd2,
+	0xbc, 0x5b, 0x04, 0x3e, 0xf1, 0xc5, 0xdb, 0x0d, 0xb1, 0x06, 0x32, 0x92,
+	0x44, 0x3c, 0xd9, 0x6b, 0x96, 0x91, 0x16, 0x25, 0x99, 0x3a, 0x8d, 0xbe,
+	0xc2, 0x67, 0x50, 0x17, 0xed, 0x9a, 0x16, 0x13, 0xf8, 0xb5, 0x4b, 0x74,
+	0xd1, 0xd3, 0x95, 0xe8, 0xe2, 0xea, 0x3d, 0x94, 0xc1, 0x95, 0x3d, 0x14,
+	0xbe, 0x7f, 0x43, 0xef, 0xfd, 0x3c, 0xab, 0xe3, 0x1a, 0xca, 0x08, 0x7d,
+	0x9b, 0x8a, 0xcd, 0x60, 0xc7, 0x9f, 0x45, 0x2c, 0x6c, 0x4b, 0xae, 0x04,
+	0xcc, 0x9e, 0x76, 0xe5, 0x29, 0xa7, 0xe0, 0x66, 0xfb, 0x5d, 0xb9, 0xec,
+	0xd8, 0x85, 0xbc, 0x58, 0x6f, 0xd0, 0xde, 0xfd, 0x4f, 0xe7, 0xfd, 0xb2,
+	0xab, 0xd5, 0xda, 0x95, 0x09, 0x14, 0xdc, 0x66, 0x3b, 0x2a, 0x37, 0xa5,
+	0x0f, 0xca, 0x9e, 0x2d, 0x4b, 0x66, 0x50, 0x32, 0x37, 0x01, 0x17, 0xc6,
+	0xf3, 0xca, 0x56, 0xbd, 0xa6, 0xe2, 0xeb, 0x07, 0xba, 0x0e, 0xca, 0xc6,
+	0x2d, 0x96, 0x79, 0x35, 0x48, 0xcc, 0x76, 0x10, 0xb1, 0x80, 0x15, 0xcf,
+	0x05, 0x6d, 0x73, 0xa7, 0x58, 0xc3, 0x9f, 0x16, 0x9e, 0xdb, 0xda, 0xd2,
+	0x79, 0xc4, 0x8e, 0x7f, 0x22, 0xd0, 0xbd, 0xff, 0x13, 0x8c, 0xef, 0xce,
+	0x30, 0xef, 0x4a, 0x64, 0x8b, 0x89, 0xe7, 0x98, 0x74, 0x1e, 0x4f, 0x48,
+	0x12, 0x7c, 0xe9, 0x51, 0x3c, 0xe1, 0xf9, 0x51, 0x5c, 0xba, 0x8f, 0x10,
+	0x43, 0x29, 0xde, 0xf4, 0x80, 0x37, 0x29, 0xf0, 0x06, 0x31, 0x55, 0xaf,
+	0x79, 0x15, 0xe9, 0xb2, 0x24, 0x07, 0x7e, 0x00, 0xde, 0xf4, 0x80, 0x37,
+	0xdd, 0x67, 0x12, 0x68, 0x8f, 0x3e, 0x16, 0x3b, 0x91, 0x46, 0xe5, 0x83,
+	0x37, 0xb4, 0xe3, 0xd9, 0x96, 0xe4, 0x91, 0x08, 0xc6, 0x08, 0xc8, 0x8e,
+	0xae, 0x82, 0x0c, 0x6d, 0x41, 0x6c, 0x16, 0x3b, 0x28, 0x17, 0xe1, 0x87,
+	0x4a, 0x88, 0x11, 0x9e, 0x1a, 0xb0, 0x46, 0x97, 0x60, 0x4b, 0xab, 0xf7,
+	0xb8, 0xf2, 0xf2, 0x96, 0xbf, 0x70, 0xe3, 0x37, 0x58, 0xbb, 0x24, 0xd0,
+	0x2f, 0x93, 0x25, 0xe5, 0x1f, 0xe2, 0xd9, 0xa0, 0xc2, 0x65, 0x98, 0x63,
+	0x01, 0x3e, 0x86, 0xe7, 0xd1, 0x36, 0x6c, 0xfd, 0xa7, 0xe5, 0xa1, 0xb9,
+	0x09, 0xfc, 0x10, 0x6f, 0x4e, 0xb1, 0xee, 0x7e, 0xc4, 0x73, 0x0f, 0xcb,
+	0xbe, 0x29, 0x60, 0xc7, 0x34, 0xe8, 0xee, 0xb7, 0x11, 0xcf, 0xcd, 0x37,
+	0x4a, 0x0b, 0xca, 0xc0, 0xdb, 0xd1, 0xea, 0xda, 0x38, 0x6e, 0x09, 0xeb,
+	0x30, 0x20, 0x7f, 0x56, 0xed, 0x97, 0xaf, 0x55, 0xfb, 0xe4, 0x4f, 0xe0,
+	0x5b, 0xce, 0x57, 0x3b, 0xa0, 0x2b, 0x71, 0xac, 0x49, 0x1a, 0xeb, 0xe3,
+	0xc8, 0x73, 0xd5, 0x94, 0x3c, 0x0b, 0x5e, 0x3d, 0x83, 0xdf, 0x50, 0x29,
+	0x25, 0x3b, 0x4a, 0x7d, 0x7a, 0x8d, 0xb8, 0x3e, 0x36, 0xe8, 0xb1, 0x31,
+	0x77, 0xeb, 0xc9, 0x02, 0xf4, 0x6f, 0xbe, 0x6a, 0xbf, 0x5e, 0x96, 0x8f,
+	0x37, 0x72, 0x8f, 0xf7, 0xd4, 0x8a, 0x7f, 0x29, 0xb8, 0xa6, 0x6d, 0x1d,
+	0x1e, 0xc7, 0x3a, 0x94, 0xa1, 0xa7, 0xa3, 0x8a, 0xf7, 0x35, 0xdf, 0x53,
+	0xf6, 0x7c, 0x8f, 0x3f, 0xbf, 0x99, 0xbc, 0x7c, 0x5b, 0xb2, 0x47, 0x27,
+	0x65, 0xcf, 0x31, 0x57, 0x3e, 0xec, 0xb8, 0x90, 0x63, 0xda, 0xe2, 0x7e,
+	0xda, 0xf8, 0xc4, 0x78, 0xd0, 0x50, 0xb1, 0x94, 0x87, 0x5b, 0x7a, 0x37,
+	0x43, 0x67, 0x53, 0x19, 0x63, 0x42, 0x92, 0x47, 0x27, 0xa4, 0xf3, 0x28,
+	0x64, 0xc1, 0x61, 0x5f, 0x4b, 0xa6, 0x71, 0x8d, 0x3c, 0x70, 0x1c, 0x6b,
+	0x20, 0x27, 0xb6, 0xf9, 0xba, 0xa4, 0x30, 0xfe, 0x01, 0xe9, 0x42, 0x1b,
+	0x1b, 0x6d, 0xae, 0xaa, 0xb1, 0x9b, 0x31, 0x76, 0xa3, 0x1c, 0x8a, 0x59,
+	0x90, 0x35, 0xfa, 0xf0, 0xff, 0x25, 0xd9, 0x32, 0xd3, 0x9f, 0x4a, 0xf6,
+	0xd4, 0x47, 0x23, 0x12, 0xe5, 0x33, 0x4c, 0xc3, 0x09, 0x96, 0x77, 0x22,
+	0x65, 0xb9, 0x8d, 0x38, 0xfa, 0xe7, 0x92, 0x3d, 0xcb, 0xb1, 0x5f, 0x47,
+	0xf9, 0xcb, 0x92, 0x9d, 0xfe, 0x05, 0xf2, 0x17, 0x91, 0xbe, 0x81, 0x74,
+	0x54, 0x3a, 0xa7, 0x25, 0x90, 0x3d, 0xfb, 0x2d, 0xe4, 0x43, 0x48, 0x0f,
+	0xa1, 0xde, 0x76, 0xd0, 0xf7, 0xa7, 0xe8, 0x2f, 0x03, 0x9b, 0xf7, 0x3b,
+	0x9a, 0x7e, 0x96, 0xb3, 0x8c, 0xef, 0x0e, 0xc1, 0xa6, 0xfd, 0x67, 0xd8,
+	0x34, 0xfd, 0x3c, 0xcf, 0x3c, 0x6d, 0x1b, 0x9f, 0x27, 0xc0, 0x93, 0x03,
+	0xc8, 0xbb, 0xf2, 0xb0, 0x43, 0x7f, 0xb3, 0x4d, 0xc6, 0xcc, 0x82, 0x1b,
+	0x05, 0xae, 0x68, 0x86, 0x1e, 0x4c, 0x6c, 0x5d, 0x5f, 0x0f, 0x0e, 0x77,
+	0x1f, 0x94, 0xa6, 0x2d, 0xfe, 0xfc, 0xfd, 0xf9, 0xda, 0xe6, 0x4f, 0x14,
+	0x1f, 0xac, 0xc2, 0x27, 0x84, 0xf3, 0xb0, 0xe3, 0x5f, 0x30, 0xba, 0x77,
+	0x3d, 0x04, 0x3d, 0x30, 0xce, 0x32, 0xef, 0xe9, 0x81, 0x71, 0x16, 0xb6,
+	0xe1, 0x04, 0x62, 0xc4, 0x13, 0x1d, 0xd2, 0x38, 0x5d, 0xd3, 0x83, 0x86,
+	0xe9, 0x5f, 0xad, 0x07, 0x8d, 0x67, 0x51, 0xef, 0x2c, 0x79, 0x86, 0x3e,
+	0x4e, 0x91, 0x67, 0xed, 0x48, 0x3f, 0x8d, 0xb9, 0x92, 0xf6, 0x46, 0xd0,
+	0xee, 0xe1, 0xa2, 0xdb, 0x21, 0xef, 0x0f, 0x6c, 0x39, 0xa0, 0xcb, 0xff,
+	0xd2, 0x1d, 0x8e, 0x59, 0x73, 0x12, 0x20, 0x4f, 0x51, 0xb7, 0x4c, 0x1e,
+	0xde, 0xdc, 0x24, 0xd1, 0xfd, 0xd2, 0x49, 0xfe, 0x95, 0x77, 0x22, 0x5f,
+	0x70, 0xc3, 0x76, 0xb3, 0xe6, 0x27, 0x70, 0x52, 0x3f, 0xcb, 0x5f, 0x85,
+	0xcc, 0x10, 0xaf, 0xbe, 0x26, 0x7b, 0xa6, 0x5c, 0x19, 0x73, 0x38, 0xff,
+	0xef, 0x63, 0xfe, 0x99, 0x2d, 0x31, 0x59, 0x4a, 0xc4, 0xc0, 0x93, 0x79,
+	0xd8, 0xf6, 0x8b, 0xe2, 0xf1, 0x81, 0xe7, 0x02, 0x3b, 0xc4, 0x8e, 0x0f,
+	0x89, 0x9d, 0xfa, 0x01, 0xf8, 0x30, 0x04, 0xd9, 0xcf, 0x55, 0x29, 0x3b,
+	0xaf, 0xc8, 0x20, 0x64, 0xe2, 0x7b, 0x8e, 0x95, 0x02, 0x16, 0x82, 0xbd,
+	0xa0, 0x5c, 0x50, 0x26, 0x5a, 0x94, 0x4d, 0x3a, 0xe1, 0x58, 0x4f, 0x94,
+	0xe5, 0x56, 0x39, 0xd1, 0x46, 0xda, 0xf1, 0x6e, 0x5a, 0xf9, 0x8b, 0xd4,
+	0xb8, 0xd1, 0x05, 0x1b, 0x9d, 0x12, 0xb3, 0xbb, 0xd8, 0xe8, 0xdf, 0x21,
+	0xc9, 0x1f, 0x0d, 0xc8, 0x44, 0x37, 0xd7, 0x8a, 0xfd, 0x22, 0x5f, 0x2e,
+	0xb8, 0x21, 0xfb, 0x75, 0xf7, 0x64, 0x7b, 0x42, 0x3e, 0xd9, 0xbd, 0x22,
+	0x97, 0x73, 0x22, 0x9e, 0x5e, 0x0c, 0xaa, 0xf5, 0xf0, 0xe9, 0xf6, 0xe7,
+	0xe2, 0xbf, 0xeb, 0xab, 0x7b, 0xc7, 0xb9, 0x50, 0xd6, 0x57, 0x74, 0x27,
+	0x71, 0x2d, 0xad, 0xaf, 0x41, 0x9e, 0xac, 0x27, 0x8a, 0x72, 0x19, 0xb2,
+	0x07, 0x1e, 0x9e, 0x65, 0x4a, 0x1e, 0x4e, 0x40, 0xee, 0x5f, 0x95, 0x1d,
+	0x47, 0xa9, 0x33, 0xaf, 0x62, 0xae, 0xca, 0x96, 0xc0, 0x46, 0xb0, 0x3f,
+	0x57, 0x26, 0x9d, 0xae, 0xd4, 0x29, 0xb9, 0x35, 0xbe, 0x17, 0x31, 0xe7,
+	0xb8, 0xe9, 0xca, 0xa2, 0x53, 0x90, 0xc5, 0x01, 0xb4, 0x29, 0x7f, 0x1a,
+	0xbf, 0x4f, 0xe9, 0xb9, 0x3d, 0x0a, 0xbe, 0x5b, 0x89, 0x39, 0xe3, 0xf7,
+	0xc1, 0xf7, 0x87, 0x25, 0x39, 0xbd, 0x62, 0x6b, 0x20, 0x77, 0x9e, 0xad,
+	0x49, 0x9e, 0x35, 0xa5, 0x5c, 0xb2, 0xe5, 0x23, 0xb4, 0x21, 0x25, 0xce,
+	0x0b, 0x36, 0x86, 0x67, 0xec, 0x25, 0xd8, 0x99, 0x12, 0x6c, 0x0a, 0x6c,
+	0xc8, 0x9f, 0xa0, 0xfc, 0x59, 0xd4, 0x79, 0x06, 0xf1, 0xd3, 0x79, 0x60,
+	0xbf, 0x73, 0xc0, 0x14, 0x4f, 0x97, 0x32, 0x3a, 0x96, 0x55, 0xf3, 0x85,
+	0xcf, 0x52, 0xb1, 0x8f, 0x94, 0xe7, 0xd4, 0x7d, 0x1e, 0xb5, 0xb6, 0x59,
+	0x67, 0x13, 0x71, 0x16, 0x28, 0x13, 0x99, 0x9b, 0xf3, 0x79, 0x42, 0xdb,
+	0xc7, 0xf3, 0x19, 0xdf, 0x56, 0x36, 0xaf, 0xb1, 0x95, 0x22, 0x2f, 0x56,
+	0x3c, 0x3c, 0x49, 0x7c, 0x5c, 0x9c, 0x4a, 0xac, 0x9c, 0x63, 0x16, 0xe1,
+	0x37, 0x97, 0x11, 0x67, 0x44, 0xd2, 0xdf, 0x94, 0xc8, 0x71, 0xd7, 0xfd,
+	0x21, 0xfc, 0x66, 0x01, 0x6b, 0x62, 0x04, 0x50, 0xbe, 0xc0, 0x77, 0x94,
+	0x7b, 0xca, 0x76, 0x80, 0xe7, 0x19, 0xf2, 0x12, 0xca, 0xca, 0x2a, 0xfe,
+	0xfa, 0x16, 0xe8, 0xd1, 0xf4, 0xa9, 0x32, 0xd6, 0x6b, 0x94, 0xdc, 0x58,
+	0x0a, 0x31, 0x4e, 0xaf, 0xd9, 0x88, 0xf6, 0x73, 0x0b, 0x6c, 0x63, 0x0d,
+	0xf0, 0x3a, 0xd5, 0x4b, 0x0b, 0x2c, 0xef, 0x90, 0x8b, 0x88, 0x45, 0x49,
+	0x43, 0x79, 0x36, 0x2d, 0xde, 0xde, 0x31, 0xed, 0x15, 0x69, 0x45, 0x1e,
+	0xfc, 0xca, 0x96, 0xe8, 0x67, 0x43, 0x52, 0x88, 0x93, 0xd7, 0x71, 0x59,
+	0x9e, 0xfa, 0x4c, 0x13, 0xf7, 0x66, 0xb3, 0x36, 0x9f, 0xfd, 0xbd, 0x0e,
+	0xf3, 0x2d, 0xec, 0x75, 0x70, 0x7f, 0x23, 0x04, 0x5f, 0xa6, 0xf6, 0x3c,
+	0x90, 0x26, 0xea, 0xe2, 0x5f, 0xbe, 0xf7, 0xb0, 0x51, 0x0d, 0x3f, 0x12,
+	0x4f, 0x72, 0xbe, 0x56, 0x61, 0x09, 0xf6, 0xa3, 0x2d, 0x7d, 0x49, 0xee,
+	0x3d, 0xe1, 0xcd, 0xcf, 0x38, 0x25, 0xbc, 0x4b, 0x23, 0x57, 0x67, 0x2d,
+	0xe7, 0x0a, 0x30, 0x45, 0x2e, 0xe6, 0x60, 0xbd, 0x46, 0x9b, 0x60, 0xbf,
+	0x06, 0x32, 0xc6, 0x99, 0x26, 0x0f, 0x9f, 0x85, 0x64, 0x62, 0x8a, 0xe7,
+	0x9e, 0xb0, 0x6d, 0xc0, 0x90, 0xbf, 0x1b, 0xc2, 0x73, 0x85, 0x79, 0xc4,
+	0xa4, 0x5e, 0x3c, 0x8b, 0x67, 0xaf, 0x3f, 0xf2, 0xdc, 0x38, 0xc1, 0xb9,
+	0x07, 0xe4, 0x5e, 0xa0, 0x13, 0x41, 0xff, 0x9d, 0x7a, 0xac, 0xce, 0x53,
+	0x29, 0xee, 0x65, 0x4b, 0x12, 0xf6, 0x22, 0x8b, 0x58, 0x32, 0x17, 0xeb,
+	0xd0, 0xd8, 0x9c, 0xef, 0xd6, 0x62, 0x4f, 0x3f, 0xc6, 0x4b, 0xc9, 0xe7,
+	0x4b, 0x3e, 0xd6, 0x4b, 0xc1, 0xc7, 0x4a, 0x68, 0xb8, 0xc7, 0x95, 0x1f,
+	0x3a, 0xe4, 0x57, 0x1f, 0xf2, 0x8e, 0x1c, 0xae, 0xfe, 0xb2, 0xf3, 0xcd,
+	0xfa, 0xbf, 0x66, 0xd0, 0xc8, 0x1f, 0xe8, 0x03, 0x3e, 0x22, 0xed, 0x06,
+	0xfc, 0x79, 0x11, 0xb8, 0xcb, 0x38, 0xd3, 0xa1, 0xde, 0x19, 0xc0, 0x06,
+	0xe5, 0x29, 0xd8, 0xc6, 0x33, 0x3c, 0xf3, 0x85, 0x6d, 0x3b, 0x13, 0x96,
+	0xe2, 0x0c, 0xe5, 0x52, 0xda, 0x0c, 0xac, 0x17, 0xeb, 0x97, 0xa7, 0x3a,
+	0x90, 0x36, 0x23, 0x4d, 0xa8, 0x7e, 0xca, 0x53, 0xb6, 0x6a, 0x5f, 0x9e,
+	0x4a, 0xa9, 0x76, 0xe5, 0xa9, 0x3e, 0xa4, 0x8e, 0x34, 0x9c, 0x41, 0xe0,
+	0x74, 0xa6, 0x5b, 0x26, 0x4e, 0xc2, 0xbf, 0xf4, 0x1b, 0xea, 0xbe, 0xc4,
+	0x38, 0xfc, 0x4f, 0x08, 0x51, 0xd6, 0x15, 0x73, 0x00, 0x18, 0x6b, 0x1b,
+	0x30, 0xc8, 0x36, 0xb1, 0x8f, 0x73, 0xfe, 0xb4, 0xbd, 0xcb, 0xdc, 0xff,
+	0x8a, 0x3f, 0x28, 0x19, 0xd9, 0x37, 0xd3, 0x08, 0x7d, 0x0d, 0x99, 0x45,
+	0xe9, 0x32, 0x87, 0x90, 0xcf, 0xcf, 0x91, 0x6f, 0xf7, 0xab, 0xd8, 0x2d,
+	0xeb, 0xc4, 0xa2, 0x12, 0x4d, 0x63, 0x8c, 0xb7, 0xd2, 0xbe, 0x07, 0xf2,
+	0x67, 0xeb, 0x3e, 0xd2, 0xa0, 0xa7, 0x9e, 0x1f, 0x3c, 0xeb, 0xcd, 0xfc,
+	0x8a, 0xb3, 0x5e, 0xca, 0x35, 0xf9, 0x7b, 0xbf, 0x2c, 0xdb, 0x69, 0x79,
+	0xc9, 0x4e, 0xc9, 0x45, 0x7b, 0xab, 0xfc, 0x39, 0xfc, 0xf4, 0x25, 0x7b,
+	0xba, 0x89, 0x58, 0xa0, 0xac, 0xce, 0xcf, 0xfc, 0xb5, 0xb2, 0xf5, 0x3e,
+	0xfa, 0x8f, 0x64, 0x71, 0x8a, 0xd8, 0xd9, 0xdd, 0xbe, 0xc7, 0x29, 0xd0,
+	0x6f, 0x81, 0x06, 0x62, 0xb5, 0x02, 0xfc, 0xdf, 0x41, 0x19, 0x72, 0xe8,
+	0xf7, 0x94, 0x8f, 0x8a, 0x0f, 0x79, 0xfa, 0xec, 0xe4, 0x61, 0x57, 0x97,
+	0x67, 0xa0, 0x4f, 0x42, 0xf9, 0xc7, 0xf3, 0x1c, 0xd7, 0xdd, 0x96, 0x2f,
+	0x94, 0x38, 0xcf, 0xe2, 0xe6, 0xa8, 0x04, 0x65, 0x58, 0xe1, 0x85, 0x16,
+	0x79, 0x71, 0x61, 0x83, 0x18, 0xf0, 0x50, 0xc6, 0x2d, 0x61, 0x75, 0xd3,
+	0x84, 0xf1, 0xb7, 0xb4, 0xf2, 0xbe, 0xd8, 0x87, 0xc1, 0x1b, 0xee, 0x05,
+	0x60, 0x6e, 0xad, 0x9c, 0x89, 0x9f, 0xef, 0x83, 0x7e, 0xf1, 0x39, 0x20,
+	0x39, 0x3b, 0x86, 0x67, 0xa6, 0xd4, 0x39, 0xee, 0x93, 0x05, 0xc5, 0xc3,
+	0xdc, 0xe3, 0xea, 0x7d, 0xa3, 0x7d, 0x07, 0x70, 0x1d, 0xe5, 0x15, 0xe9,
+	0xa2, 0x37, 0x6e, 0x0e, 0x38, 0x2e, 0xdf, 0xd7, 0xa4, 0xce, 0xff, 0x0a,
+	0xd0, 0x85, 0x71, 0x55, 0xbf, 0x5f, 0x2e, 0x4d, 0xed, 0x8f, 0x7a, 0xfa,
+	0x31, 0xa0, 0x9f, 0xf9, 0x9e, 0xf1, 0x15, 0xf7, 0x4b, 0x5e, 0x19, 0x99,
+	0xb4, 0xbf, 0xa1, 0xf5, 0x47, 0x02, 0x77, 0xf7, 0x00, 0x87, 0x1e, 0x69,
+	0xc0, 0x5c, 0xac, 0x44, 0x22, 0x60, 0xb4, 0x1b, 0xc0, 0xf1, 0x43, 0xca,
+	0xe7, 0xf6, 0xa8, 0xfd, 0xe8, 0x53, 0xa9, 0x16, 0x29, 0x9b, 0xb6, 0xba,
+	0x17, 0xb7, 0x64, 0x6e, 0x21, 0xd6, 0xc7, 0xaf, 0x09, 0x65, 0x5d, 0x48,
+	0x1b, 0x91, 0xbe, 0x4b, 0x8a, 0xc7, 0xa6, 0xf5, 0x78, 0xe1, 0x35, 0xf9,
+	0x3e, 0x9d, 0x7e, 0x44, 0xc7, 0x53, 0x1c, 0x27, 0x2c, 0xf6, 0x17, 0x9b,
+	0xa5, 0xeb, 0x88, 0x09, 0x6c, 0x1b, 0x07, 0xd6, 0xed, 0x90, 0xd4, 0x91,
+	0x84, 0xdc, 0x72, 0xc4, 0xdf, 0x73, 0xfa, 0x0f, 0x23, 0x49, 0xb5, 0xc7,
+	0xf9, 0xdd, 0x11, 0x7b, 0x8e, 0xe9, 0x6b, 0xfa, 0xfe, 0xde, 0x15, 0x7d,
+	0xaf, 0xef, 0x47, 0x23, 0x3d, 0x2a, 0xfd, 0x6f, 0x23, 0x29, 0x95, 0xbe,
+	0x3e, 0x72, 0x4b, 0xc5, 0x8b, 0x8f, 0x8a, 0xf3, 0x29, 0xf9, 0x5c, 0x89,
+	0xf8, 0xb2, 0x1f, 0xd8, 0xd1, 0x81, 0x9d, 0xe9, 0x83, 0x9d, 0x49, 0xc1,
+	0xce, 0x0c, 0xd0, 0xce, 0xc0, 0x6e, 0xbf, 0x02, 0xbb, 0xed, 0xc8, 0xf7,
+	0x20, 0xaf, 0x4f, 0x3b, 0x8d, 0xc0, 0x85, 0xae, 0xeb, 0xcd, 0xd5, 0x7a,
+	0x62, 0x09, 0xeb, 0x5b, 0x3e, 0x2d, 0x91, 0x56, 0xd8, 0xa0, 0x2d, 0x27,
+	0x1a, 0x64, 0x3e, 0xe6, 0xba, 0x47, 0x1d, 0x5b, 0xae, 0xa2, 0x7e, 0xd6,
+	0xa6, 0x1e, 0xbf, 0x14, 0x65, 0x3c, 0x76, 0x75, 0x6a, 0x2b, 0x6c, 0x12,
+	0xe5, 0x3d, 0x22, 0xe5, 0xb1, 0xb8, 0x2c, 0x20, 0x3e, 0xab, 0xd5, 0x49,
+	0xe1, 0x99, 0xfa, 0xff, 0x5d, 0xd4, 0x4d, 0xc1, 0x3f, 0x98, 0xb2, 0xd8,
+	0x93, 0x90, 0x53, 0x3d, 0xd6, 0x40, 0xc2, 0xa0, 0xed, 0x4a, 0xc8, 0x1c,
+	0x62, 0xfd, 0x72, 0x89, 0xf5, 0x59, 0x0f, 0xfa, 0x59, 0xf2, 0xda, 0x4d,
+	0x96, 0x7c, 0x3b, 0xd1, 0xcf, 0x7d, 0xc8, 0x50, 0xae, 0xc7, 0xf3, 0x01,
+	0x86, 0xd1, 0x08, 0x39, 0x70, 0xc0, 0xff, 0x31, 0x94, 0xf7, 0xf3, 0xbe,
+	0x07, 0xca, 0x88, 0x85, 0x7e, 0x1c, 0x25, 0x46, 0xcc, 0x39, 0x63, 0x28,
+	0x63, 0x1b, 0x2b, 0x9e, 0x44, 0xf9, 0xa8, 0x24, 0xe3, 0x79, 0x75, 0xf7,
+	0xac, 0x1d, 0x65, 0xec, 0x23, 0xa8, 0xf7, 0x63, 0xfe, 0x8f, 0x92, 0xa3,
+	0xa0, 0xed, 0x97, 0xf7, 0xaa, 0xbd, 0x81, 0x8c, 0xe9, 0x40, 0x1f, 0x58,
+	0x96, 0x34, 0xd9, 0x2e, 0xe7, 0x38, 0xca, 0x16, 0xde, 0x57, 0xe1, 0x19,
+	0x5e, 0x44, 0xee, 0xad, 0x34, 0x4b, 0xae, 0xd2, 0x70, 0x1d, 0xfb, 0xef,
+	0xeb, 0xe4, 0x72, 0xdc, 0x14, 0xde, 0x83, 0xf0, 0xf4, 0x3c, 0xb4, 0x95,
+	0x3a, 0x31, 0xc0, 0x73, 0x03, 0xf8, 0x5b, 0xac, 0x05, 0xfc, 0xef, 0x39,
+	0xf8, 0xdf, 0xa7, 0x4b, 0x35, 0xfb, 0xe1, 0xf9, 0x5d, 0xda, 0x80, 0x27,
+	0xb1, 0x66, 0xa3, 0xc0, 0xfd, 0x3b, 0x11, 0x0f, 0x0c, 0x03, 0xfb, 0x0f,
+	0x62, 0xfd, 0xd2, 0x58, 0xbb, 0x31, 0xde, 0x17, 0xc2, 0x3a, 0x0e, 0xa8,
+	0x73, 0xe6, 0x19, 0x75, 0xe7, 0xe2, 0x47, 0xca, 0xf7, 0x3e, 0x5e, 0x32,
+	0xe0, 0x1f, 0x0a, 0xee, 0x66, 0xdb, 0x02, 0xfe, 0x5b, 0xd1, 0xe7, 0x81,
+	0x17, 0x61, 0x57, 0x7e, 0x06, 0xba, 0xce, 0xcf, 0xd0, 0x9f, 0xa3, 0x8e,
+	0x87, 0xb7, 0x1d, 0xee, 0x75, 0x41, 0x9f, 0x0f, 0x2f, 0xcb, 0x12, 0x70,
+	0x47, 0x86, 0x72, 0x8c, 0xf8, 0xc1, 0x7a, 0x7a, 0x4e, 0xba, 0x69, 0x03,
+	0xe7, 0xa8, 0x2b, 0xfd, 0xd3, 0x71, 0x60, 0x3d, 0x20, 0x79, 0x75, 0xae,
+	0x8a, 0xe7, 0xb3, 0x1b, 0xc5, 0x20, 0xde, 0x73, 0x6e, 0x40, 0x19, 0xed,
+	0x86, 0x8f, 0x91, 0x96, 0x06, 0xda, 0x24, 0xb3, 0xa5, 0x4d, 0xd9, 0x0e,
+	0xcb, 0x79, 0x09, 0xe3, 0xee, 0x90, 0x46, 0x60, 0xb8, 0x02, 0xc6, 0x38,
+	0x20, 0xff, 0xd5, 0xe1, 0x1e, 0x95, 0x17, 0xfb, 0x81, 0x96, 0x08, 0x78,
+	0xd6, 0xb4, 0xc7, 0x36, 0x23, 0x3b, 0xaa, 0xec, 0x3f, 0xa2, 0x30, 0x56,
+	0x4e, 0xd8, 0x3f, 0xfc, 0x04, 0xc6, 0x4c, 0x4e, 0x53, 0xf6, 0x7b, 0xb1,
+	0x6e, 0xbf, 0x0d, 0x0c, 0x44, 0xae, 0x7e, 0x75, 0x83, 0xa7, 0x2f, 0xa4,
+	0x7f, 0x89, 0x78, 0x82, 0x67, 0x00, 0x5e, 0x5c, 0xbe, 0x42, 0x5b, 0x3f,
+	0xe8, 0x9d, 0xdd, 0xe0, 0x9f, 0x25, 0x77, 0x4e, 0x7b, 0xfe, 0xba, 0xf3,
+	0x2c, 0x5a, 0x1d, 0x95, 0x76, 0x9e, 0x4a, 0x1b, 0x72, 0x8b, 0xdc, 0x19,
+	0xf2, 0xfa, 0x31, 0x4e, 0x98, 0x90, 0x55, 0xda, 0x81, 0x76, 0xc8, 0x39,
+	0xf3, 0xb4, 0x29, 0xb4, 0x09, 0x94, 0x05, 0x5b, 0x8a, 0x55, 0xd8, 0x84,
+	0x96, 0x0e, 0x99, 0x23, 0xcf, 0x4e, 0xd0, 0x4e, 0xfc, 0x48, 0x26, 0xd7,
+	0xd8, 0xca, 0x41, 0xf1, 0xe3, 0xda, 0x66, 0x09, 0xa7, 0x6d, 0xf3, 0x3e,
+	0x35, 0x47, 0xcf, 0x5e, 0xee, 0x23, 0xfe, 0x9c, 0xc9, 0x58, 0x6d, 0xa2,
+	0xb1, 0xa7, 0xc2, 0x4f, 0xdf, 0xc7, 0x5c, 0xd9, 0x87, 0xe2, 0xd3, 0xc0,
+	0xa0, 0x17, 0x0b, 0xa8, 0x3d, 0x3f, 0xe0, 0xe0, 0xf8, 0xcf, 0x60, 0x6b,
+	0x73, 0xc4, 0x25, 0xe0, 0x73, 0xe7, 0x51, 0xca, 0xd1, 0x66, 0xda, 0x32,
+	0xe0, 0xbc, 0x14, 0xed, 0xb5, 0x2c, 0x4c, 0x03, 0x73, 0x19, 0x77, 0x48,
+	0x9e, 0xf2, 0xca, 0xbb, 0x0a, 0x0b, 0x86, 0x4c, 0xce, 0xb6, 0x48, 0xd7,
+	0x09, 0xee, 0xaf, 0x9e, 0x8a, 0x4a, 0x0b, 0xf7, 0x58, 0xe9, 0x83, 0xfa,
+	0x25, 0x87, 0xf2, 0xce, 0x13, 0x41, 0xb5, 0x1f, 0x36, 0x67, 0x90, 0x47,
+	0x7d, 0xb0, 0x07, 0x56, 0x6a, 0xc9, 0xd8, 0xd6, 0xe4, 0x61, 0x48, 0xc8,
+	0x52, 0x09, 0x32, 0x56, 0x82, 0x8c, 0x95, 0x20, 0x63, 0x25, 0xc8, 0x18,
+	0xb0, 0xdf, 0x79, 0xe8, 0xdf, 0xb9, 0xd2, 0x80, 0xf6, 0xeb, 0xbb, 0x94,
+	0x5f, 0x3f, 0x54, 0x7a, 0xc5, 0x65, 0xfa, 0xac, 0x8a, 0x4d, 0xfb, 0x20,
+	0x83, 0x8c, 0x45, 0xfd, 0x18, 0xf5, 0x15, 0x79, 0x72, 0xe6, 0x55, 0x39,
+	0x35, 0x53, 0xc3, 0x81, 0x13, 0x25, 0x57, 0x5e, 0x72, 0x10, 0x7f, 0xce,
+	0x13, 0x53, 0x65, 0x5a, 0x1b, 0x15, 0xb6, 0x3a, 0x28, 0x79, 0x85, 0x93,
+	0x95, 0x1f, 0x01, 0xbe, 0x52, 0xb8, 0x90, 0xba, 0x29, 0x6d, 0x5b, 0x2e,
+	0xcb, 0x39, 0xf8, 0xf1, 0x85, 0xea, 0x6b, 0xf2, 0x8c, 0xc2, 0xe3, 0xe4,
+	0xc3, 0x3b, 0xe5, 0xa7, 0xa6, 0x77, 0x9e, 0x7f, 0x0a, 0x58, 0x63, 0xa1,
+	0x87, 0xb6, 0x23, 0x04, 0x5f, 0x60, 0x15, 0x3a, 0xa1, 0xd7, 0xfb, 0x8d,
+	0x1b, 0x81, 0x69, 0xf8, 0x7e, 0xa3, 0xbc, 0x38, 0x53, 0xa8, 0x93, 0x09,
+	0xda, 0x07, 0xeb, 0xb0, 0x18, 0xf4, 0x53, 0xf4, 0x9b, 0x9c, 0x2f, 0xfd,
+	0xd4, 0x4f, 0x37, 0xf0, 0x0e, 0x57, 0xf9, 0x58, 0x6c, 0x03, 0xf7, 0x1b,
+	0x63, 0x36, 0x79, 0x7a, 0x59, 0xf6, 0x57, 0x58, 0xf6, 0x2a, 0xd6, 0x87,
+	0xe9, 0x0f, 0xdc, 0x7b, 0x63, 0x1c, 0x8f, 0xfd, 0x02, 0x37, 0xb5, 0x63,
+	0xae, 0xa5, 0x8f, 0x68, 0xcc, 0xdd, 0xa7, 0x70, 0xf4, 0xb5, 0x78, 0x99,
+	0x7c, 0x72, 0xc0, 0xa7, 0xcb, 0x6a, 0x3f, 0x70, 0x9d, 0x7d, 0xe2, 0x27,
+	0xa0, 0x57, 0x85, 0x2b, 0xc2, 0x3d, 0x4b, 0xee, 0xe7, 0x72, 0xaf, 0xb8,
+	0xde, 0x62, 0xa8, 0x7b, 0x03, 0x72, 0x0f, 0xec, 0xcb, 0xbd, 0xb0, 0x2f,
+	0xf7, 0x5d, 0x73, 0x07, 0xda, 0x3f, 0x03, 0xe8, 0x2a, 0x04, 0x8d, 0x0e,
+	0x19, 0xad, 0xd4, 0xb7, 0xe5, 0x3e, 0xee, 0x7a, 0xfb, 0xb6, 0xdc, 0xd3,
+	0x4d, 0xad, 0xd9, 0x0b, 0xa4, 0x6c, 0xb8, 0x72, 0xc9, 0xe1, 0xbe, 0x9b,
+	0x7f, 0x6f, 0x7e, 0x3d, 0xfc, 0x15, 0x68, 0xf6, 0xf7, 0x9c, 0x43, 0xe9,
+	0x2b, 0xc2, 0xfb, 0xf3, 0xc5, 0x29, 0xe2, 0x81, 0x98, 0xba, 0x17, 0x63,
+	0xa8, 0x7d, 0x3e, 0xaf, 0x6d, 0x71, 0x4a, 0x9d, 0x31, 0x15, 0xb8, 0x77,
+	0x6d, 0x6e, 0xb5, 0xcc, 0xd1, 0xa0, 0x77, 0x1f, 0x93, 0xba, 0xec, 0xd9,
+	0x32, 0xc8, 0x62, 0xb5, 0x76, 0xcf, 0x71, 0x50, 0xd9, 0x8b, 0x2b, 0xd0,
+	0x01, 0xae, 0x17, 0xe2, 0x05, 0xe8, 0xc9, 0x04, 0xec, 0x53, 0x5e, 0xf5,
+	0x17, 0xa1, 0x5c, 0x64, 0xb2, 0x41, 0x43, 0xc2, 0xc7, 0x19, 0x0b, 0x79,
+	0x7b, 0x2d, 0xb9, 0xa0, 0xa5, 0xec, 0x37, 0x68, 0x07, 0x3e, 0xa3, 0x7e,
+	0x26, 0xc6, 0x1b, 0xd3, 0x0d, 0xf0, 0xab, 0x58, 0xbf, 0x2a, 0xf7, 0x04,
+	0xa0, 0xbb, 0x8b, 0xdf, 0x91, 0x7d, 0xb3, 0xdd, 0xcd, 0x9e, 0xfc, 0x73,
+	0x1f, 0x99, 0xf3, 0xf3, 0x69, 0x58, 0xdd, 0xb7, 0x71, 0x5c, 0x22, 0x51,
+	0xf8, 0xb4, 0x0f, 0x20, 0xce, 0xd8, 0x01, 0x59, 0x59, 0x8a, 0xb1, 0x5f,
+	0x4f, 0x67, 0x26, 0x4b, 0xec, 0xfb, 0x3b, 0x32, 0x34, 0x5b, 0x6a, 0xa6,
+	0x2f, 0x59, 0x84, 0x1d, 0x58, 0x36, 0xe9, 0x43, 0xc7, 0xe0, 0xe3, 0xda,
+	0xe5, 0xfb, 0xb3, 0xf4, 0x8f, 0x49, 0xf3, 0x94, 0xf4, 0xc6, 0x4f, 0x81,
+	0xa6, 0xcf, 0x3b, 0x21, 0xc6, 0x68, 0xee, 0x20, 0xca, 0xfe, 0x5c, 0x92,
+	0x66, 0x67, 0x80, 0xcf, 0xbd, 0xe6, 0x17, 0x80, 0x61, 0x33, 0x66, 0xd2,
+	0xbc, 0x35, 0x40, 0x39, 0x42, 0xcc, 0xbd, 0x58, 0xa3, 0xf3, 0x07, 0xb3,
+	0x2a, 0x4e, 0x52, 0x76, 0x66, 0xd1, 0xe1, 0x78, 0xa0, 0x5b, 0xd9, 0xac,
+	0x5b, 0x61, 0x4f, 0x22, 0xfa, 0xfc, 0x0d, 0x6d, 0x88, 0x6d, 0x9c, 0x90,
+	0xce, 0x3f, 0x2a, 0xd9, 0x93, 0x31, 0xd8, 0x33, 0xf6, 0xe5, 0xc7, 0x0e,
+	0xf4, 0x91, 0x3e, 0xde, 0xa6, 0xbf, 0xbb, 0x03, 0x7e, 0xef, 0x66, 0x45,
+	0xcf, 0xb0, 0xd3, 0x27, 0x13, 0xc7, 0x38, 0x76, 0x0f, 0x6c, 0x79, 0x5c,
+	0xc9, 0x6d, 0xb1, 0xb4, 0x1c, 0x8f, 0xc0, 0x26, 0x47, 0xb6, 0x90, 0x9f,
+	0xef, 0x93, 0xbb, 0xec, 0x31, 0xb9, 0x1b, 0xb2, 0x33, 0x68, 0x3b, 0x32,
+	0x84, 0xb5, 0xd8, 0x61, 0xc3, 0xef, 0x28, 0x0c, 0xdd, 0x88, 0xb8, 0x8b,
+	0x63, 0xb7, 0xeb, 0xfb, 0x17, 0x1e, 0x7e, 0xfc, 0x4a, 0xd5, 0xe3, 0x51,
+	0x76, 0xf6, 0x49, 0xc5, 0x9b, 0x61, 0x67, 0x9b, 0xf6, 0xb3, 0x2d, 0x92,
+	0x53, 0xf5, 0xb6, 0x29, 0x7f, 0x5c, 0x5c, 0xb8, 0x1f, 0x29, 0x7c, 0xf3,
+	0x02, 0xec, 0x0d, 0x30, 0x77, 0xb1, 0xb2, 0x15, 0x79, 0xf8, 0xd0, 0x85,
+	0x34, 0xd2, 0xf7, 0x21, 0x65, 0xdd, 0x07, 0x9a, 0xbd, 0xbd, 0xdc, 0xb5,
+	0xf7, 0xb8, 0x24, 0xf0, 0x01, 0x85, 0x4b, 0xaf, 0xa8, 0x3b, 0x80, 0x88,
+	0xa1, 0x47, 0xb2, 0xb0, 0x2b, 0xcd, 0xc0, 0x40, 0x53, 0xc7, 0xad, 0xd4,
+	0x50, 0x60, 0xbb, 0x7c, 0x10, 0xb1, 0x7c, 0xd9, 0xe1, 0x5a, 0x6e, 0x95,
+	0x07, 0xdf, 0x4b, 0x19, 0xd9, 0x2e, 0x7b, 0xde, 0x1b, 0x90, 0x3d, 0x7d,
+	0x56, 0x86, 0x74, 0xdf, 0xf2, 0x2e, 0x3f, 0x9e, 0xee, 0x1a, 0x4e, 0x06,
+	0xfa, 0xe5, 0x0b, 0x90, 0xb1, 0x02, 0xe4, 0x6b, 0xa8, 0x4a, 0x9e, 0xd3,
+	0xde, 0xd3, 0xce, 0xa7, 0x80, 0x95, 0x7d, 0xec, 0x67, 0xcb, 0x54, 0xb5,
+	0x41, 0x12, 0x37, 0x70, 0x3f, 0x39, 0xe1, 0x9d, 0x71, 0xdc, 0x40, 0x99,
+	0x40, 0x0c, 0x72, 0x83, 0xa7, 0x9f, 0xea, 0xee, 0xdd, 0x0d, 0x9e, 0x5f,
+	0x41, 0xfc, 0xeb, 0x12, 0xe7, 0x79, 0x77, 0x0d, 0xbe, 0xa1, 0x6d, 0x69,
+	0x68, 0xe3, 0x0a, 0xbe, 0x6b, 0x61, 0xfc, 0xf0, 0x87, 0xcd, 0xb5, 0x6f,
+	0x07, 0xd6, 0xca, 0xa2, 0xbf, 0xef, 0x36, 0x87, 0x39, 0xd3, 0xa7, 0x5b,
+	0x26, 0x6d, 0x61, 0xab, 0xbd, 0x4b, 0xfe, 0x0c, 0xfe, 0xfd, 0x6b, 0x2b,
+	0xfe, 0x7d, 0x37, 0xf8, 0xb1, 0x16, 0x03, 0xd8, 0xe6, 0x3d, 0x98, 0xcb,
+	0x30, 0xd6, 0xf3, 0x6e, 0xfc, 0xee, 0x2a, 0xad, 0xda, 0xc7, 0x9b, 0x29,
+	0x00, 0x4f, 0x36, 0xd8, 0xec, 0x6f, 0xd5, 0x7e, 0x5e, 0x21, 0x2f, 0x2b,
+	0x7b, 0x85, 0x03, 0x57, 0x85, 0x7e, 0xef, 0x75, 0x09, 0x77, 0xdb, 0xaf,
+	0x77, 0x06, 0xec, 0xe7, 0x8d, 0x00, 0xcf, 0xc1, 0x1d, 0x39, 0x5d, 0x25,
+	0x0e, 0xbb, 0x28, 0xc6, 0x59, 0x62, 0xb0, 0x97, 0xd5, 0x1e, 0x54, 0xb9,
+	0xf4, 0x2d, 0xa4, 0xa8, 0x0f, 0xfb, 0x18, 0xf4, 0xf6, 0x29, 0x14, 0x56,
+	0xa1, 0x9d, 0xbd, 0x1b, 0xeb, 0x30, 0x81, 0x5f, 0xe7, 0x96, 0x5b, 0xa1,
+	0xbf, 0x94, 0x53, 0xee, 0x7d, 0x75, 0x9b, 0x5b, 0x02, 0x7c, 0xb7, 0xde,
+	0x3e, 0xd8, 0xb7, 0x25, 0x74, 0x14, 0xbe, 0xce, 0xa0, 0x7d, 0xe0, 0x3c,
+	0xe8, 0x27, 0x4d, 0x99, 0x3f, 0x46, 0x5d, 0x5f, 0xaf, 0xbe, 0x5f, 0xd7,
+	0x9f, 0x8b, 0xf2, 0x1b, 0x99, 0x3c, 0xf7, 0x38, 0x4b, 0x5c, 0x03, 0x07,
+	0x6b, 0xe0, 0xca, 0x71, 0xa7, 0x95, 0x36, 0x5d, 0x82, 0xc7, 0x5d, 0x19,
+	0x54, 0xd8, 0xb5, 0x17, 0x98, 0x6b, 0xa3, 0xc6, 0x0d, 0x31, 0x09, 0x1d,
+	0xef, 0x90, 0x46, 0xe0, 0xea, 0x86, 0x23, 0xf4, 0x91, 0xc9, 0xc4, 0x20,
+	0x84, 0x20, 0xa4, 0xee, 0x93, 0x5a, 0x03, 0xdf, 0x97, 0xde, 0xc4, 0xf7,
+	0x85, 0x78, 0xe9, 0x51, 0xac, 0x9f, 0xe5, 0x5c, 0x5c, 0xa7, 0x7e, 0xb1,
+	0x56, 0x1f, 0x72, 0xc4, 0xbd, 0x35, 0xb6, 0xe1, 0x5e, 0x5b, 0x72, 0xe0,
+	0x7b, 0xdc, 0x63, 0x43, 0xac, 0xd9, 0x70, 0xc6, 0xa3, 0xc1, 0x58, 0x6c,
+	0x93, 0xf2, 0x49, 0xea, 0x28, 0xf7, 0x59, 0x4c, 0x2f, 0x4e, 0x2d, 0x31,
+	0x5e, 0xe5, 0xfb, 0x84, 0x7e, 0xdf, 0xa9, 0xdf, 0x33, 0x1e, 0x2d, 0xb8,
+	0x0d, 0xe0, 0xe9, 0x0e, 0xd8, 0xcf, 0xfb, 0xb7, 0xda, 0x0a, 0x37, 0xdc,
+	0xbf, 0xb2, 0x66, 0x3b, 0xd5, 0xdd, 0xa2, 0x72, 0xe9, 0xa0, 0xd8, 0x5b,
+	0x96, 0x52, 0x21, 0x19, 0xc5, 0x5a, 0x30, 0x9f, 0x21, 0x3d, 0xa9, 0x43,
+	0xb2, 0x5f, 0xad, 0x4d, 0xf9, 0x98, 0x75, 0x38, 0x11, 0x98, 0x10, 0xa3,
+	0xcc, 0xe7, 0x4f, 0x23, 0x3d, 0x04, 0xbc, 0xe3, 0xed, 0x5d, 0x1a, 0xe5,
+	0xd5, 0xbc, 0x04, 0xc6, 0x30, 0x77, 0xac, 0xda, 0xc7, 0xaa, 0xed, 0x71,
+	0xf1, 0xfd, 0xa0, 0x7a, 0x9f, 0x5a, 0xb5, 0xcf, 0x95, 0x33, 0x88, 0x65,
+	0xfc, 0xf7, 0x5c, 0x0b, 0xae, 0x17, 0x7c, 0xf1, 0x31, 0x7f, 0xcf, 0xab,
+	0x45, 0xaf, 0x0b, 0xd7, 0x67, 0x4a, 0xce, 0x99, 0xd6, 0x30, 0xe5, 0xef,
+	0xb6, 0xad, 0x37, 0xc9, 0x78, 0x3b, 0xf7, 0xdb, 0xea, 0x69, 0x58, 0xbb,
+	0x8f, 0x56, 0x3f, 0xfe, 0xda, 0xfd, 0x37, 0x8e, 0xed, 0xed, 0xb1, 0x65,
+	0x57, 0xed, 0xb1, 0xd5, 0x8f, 0xc7, 0xb1, 0x36, 0x22, 0x7e, 0x2a, 0xb8,
+	0x31, 0x9b, 0x6b, 0xd4, 0x95, 0x98, 0x65, 0xfe, 0xcb, 0x06, 0xd6, 0x31,
+	0x06, 0x3f, 0xc2, 0xb5, 0xf4, 0xcf, 0x9e, 0xb9, 0xa6, 0xc9, 0xc4, 0x21,
+	0x6f, 0x3d, 0x07, 0xbc, 0x75, 0xf7, 0xd6, 0xff, 0xe2, 0xca, 0x3a, 0xd2,
+	0x3f, 0x70, 0x1d, 0xdb, 0x45, 0x60, 0x67, 0x8d, 0x23, 0x5c, 0x43, 0xa6,
+	0x5c, 0x43, 0xbe, 0xe3, 0x1a, 0x76, 0xea, 0x77, 0x5c, 0x3f, 0xe0, 0xb4,
+	0x2f, 0x02, 0x63, 0x38, 0x59, 0xf5, 0x1d, 0x54, 0x67, 0xb7, 0xaf, 0x8b,
+	0x29, 0x79, 0x66, 0x3e, 0x2a, 0x66, 0xda, 0x9b, 0xd7, 0xd8, 0xaa, 0xfd,
+	0x76, 0x9e, 0x5f, 0xf5, 0x11, 0x7b, 0xfa, 0xf3, 0x8a, 0x73, 0x5e, 0xfb,
+	0xe5, 0xb2, 0xe4, 0xa7, 0x42, 0x88, 0x01, 0x53, 0xc0, 0x39, 0x7d, 0xb0,
+	0xb7, 0xdc, 0x1f, 0x45, 0x59, 0x85, 0x78, 0x85, 0xbe, 0x2e, 0x05, 0x5d,
+	0xa1, 0x0d, 0x26, 0x1e, 0x79, 0x55, 0x72, 0x73, 0xbe, 0x8d, 0x41, 0xff,
+	0x86, 0xdf, 0x3f, 0xf9, 0x9c, 0xb9, 0x65, 0xb3, 0x2c, 0x25, 0x36, 0x8b,
+	0x95, 0x58, 0x90, 0xda, 0xba, 0x8e, 0xad, 0xcf, 0x77, 0xe7, 0xfe, 0x60,
+	0x4d, 0x36, 0xc6, 0xd6, 0x59, 0xfb, 0xbd, 0xe2, 0xbf, 0xf7, 0xd7, 0x7e,
+	0xdd, 0x75, 0x28, 0xbc, 0x22, 0x5c, 0x0b, 0xf2, 0x80, 0x78, 0x38, 0x2c,
+	0x9f, 0x8a, 0x51, 0x1f, 0x0b, 0xea, 0x7c, 0x33, 0x69, 0x74, 0x2b, 0x9b,
+	0x31, 0xe8, 0x78, 0xf2, 0x5a, 0xc0, 0x38, 0x91, 0xae, 0x7f, 0xe1, 0x0e,
+	0xc6, 0x10, 0xe7, 0x76, 0xd1, 0xbe, 0xf8, 0x3a, 0x1d, 0x55, 0x3a, 0xfd,
+	0x79, 0x27, 0x20, 0x45, 0x3b, 0x20, 0x13, 0xf6, 0x41, 0x85, 0xf1, 0x3f,
+	0x84, 0xbe, 0x1e, 0xd4, 0x7d, 0x4d, 0x48, 0xb7, 0xb6, 0x3f, 0x07, 0x20,
+	0xe7, 0xae, 0xdc, 0xe7, 0x6c, 0x95, 0xdb, 0x5a, 0xa9, 0x03, 0xfe, 0xfc,
+	0x0f, 0x4a, 0xd7, 0xd6, 0xa5, 0x04, 0x22, 0x83, 0x5b, 0xc2, 0x2b, 0x3c,
+	0xa0, 0x9e, 0xf9, 0xf2, 0xed, 0xf1, 0xc1, 0x9b, 0xff, 0xaa, 0xb9, 0xea,
+	0x79, 0x72, 0xce, 0xac, 0xc7, 0xb9, 0x7a, 0x58, 0xbe, 0x36, 0x57, 0xbf,
+	0x7e, 0x33, 0x64, 0xc9, 0x4a, 0x48, 0xa0, 0x9e, 0x37, 0x2b, 0x36, 0x6a,
+	0x98, 0x7b, 0x24, 0x4b, 0xa6, 0x95, 0x4a, 0x04, 0xfc, 0xbd, 0x68, 0x0f,
+	0xeb, 0x76, 0x02, 0x87, 0xdb, 0xdd, 0xdd, 0xa9, 0xbc, 0xda, 0x23, 0x35,
+	0xd4, 0xbc, 0x26, 0x80, 0xc9, 0xe6, 0x9d, 0x57, 0xdc, 0x4f, 0x02, 0xb3,
+	0x8e, 0xcb, 0xc3, 0x12, 0x5c, 0xb5, 0x97, 0x8b, 0xfc, 0x59, 0xee, 0xe7,
+	0x5a, 0x89, 0x0c, 0xd6, 0xf8, 0xc3, 0x88, 0xe1, 0xcb, 0xb0, 0xfb, 0x1f,
+	0xa1, 0x6f, 0x28, 0xc1, 0x5f, 0x00, 0x97, 0x7c, 0xed, 0xba, 0x18, 0x7e,
+	0xbc, 0x6e, 0x2f, 0xd7, 0xc3, 0xa7, 0xe7, 0x14, 0x26, 0x25, 0x6e, 0x3f,
+	0x1c, 0xb8, 0xa7, 0x27, 0x88, 0x38, 0xa3, 0xe0, 0x46, 0x6c, 0xe2, 0xb8,
+	0x83, 0x72, 0x17, 0xd6, 0xe7, 0xf4, 0x7c, 0x21, 0xb0, 0xa3, 0xe4, 0xcb,
+	0x2a, 0xe2, 0xca, 0xaa, 0x95, 0x5a, 0x06, 0x3f, 0x9e, 0xd4, 0x98, 0x8f,
+	0xe7, 0x35, 0x65, 0x1d, 0xb3, 0x70, 0x6f, 0xa8, 0x58, 0x3d, 0x28, 0x93,
+	0x0e, 0xf7, 0x76, 0xba, 0xa4, 0x18, 0xcb, 0xdc, 0xd4, 0xb8, 0xc2, 0x23,
+	0xcb, 0x44, 0xcc, 0x97, 0xa2, 0xfd, 0x2e, 0xeb, 0xf3, 0x8e, 0x27, 0x95,
+	0x7c, 0xf9, 0xfb, 0xc2, 0x8c, 0x8f, 0x78, 0x5e, 0xd5, 0x65, 0x0e, 0xf3,
+	0x79, 0x8e, 0x32, 0xa0, 0x62, 0x26, 0xf0, 0xf2, 0x21, 0xc9, 0x8c, 0x26,
+	0x14, 0x6e, 0x79, 0xbc, 0x44, 0x7d, 0x21, 0xfe, 0xbf, 0x0c, 0xec, 0x1f,
+	0xc2, 0x9a, 0x31, 0x0e, 0xe0, 0xd8, 0xd4, 0x0b, 0x94, 0x55, 0xcc, 0x5f,
+	0xa2, 0x17, 0xdb, 0x37, 0x11, 0x63, 0x5c, 0x28, 0x7d, 0x5c, 0xf1, 0x6f,
+	0x49, 0xfc, 0xbd, 0x73, 0x85, 0x05, 0x0b, 0xd9, 0x60, 0x40, 0x92, 0x47,
+	0x3f, 0x03, 0x19, 0x1a, 0x41, 0x8c, 0xc4, 0x7a, 0xa2, 0xce, 0xaf, 0x06,
+	0x81, 0xb9, 0x0c, 0xfb, 0x46, 0x29, 0x9a, 0x61, 0x29, 0xaa, 0x7b, 0x80,
+	0x3c, 0xcf, 0x0d, 0xaa, 0xbd, 0x9d, 0xa2, 0x49, 0xcc, 0x9f, 0xd9, 0xe4,
+	0xdf, 0x03, 0x2c, 0x9a, 0x6c, 0xc7, 0x3c, 0xcb, 0x27, 0x24, 0x7c, 0xf4,
+	0x80, 0x34, 0x1c, 0x7d, 0x58, 0x1a, 0xa7, 0x89, 0xf1, 0xb8, 0x77, 0x6f,
+	0xdc, 0xd1, 0x28, 0xc4, 0xdc, 0x5f, 0xc5, 0xd8, 0x07, 0xe5, 0x87, 0x8e,
+	0x4f, 0xd3, 0x86, 0x8d, 0xd2, 0xc2, 0x3a, 0x7e, 0xde, 0xc7, 0xe3, 0x77,
+	0x80, 0x1e, 0xce, 0x3f, 0xa1, 0x71, 0xdf, 0x1d, 0x75, 0xb1, 0x6b, 0x83,
+	0x8e, 0x5d, 0xd9, 0xee, 0x32, 0x7c, 0xf6, 0x31, 0x09, 0xdb, 0x7e, 0xfb,
+	0xed, 0xa8, 0x17, 0xaf, 0xbb, 0x03, 0xc1, 0x3a, 0xfa, 0x4e, 0x40, 0x0b,
+	0x71, 0x0f, 0xcf, 0xdb, 0x59, 0xe6, 0x9d, 0xf9, 0x1b, 0xe5, 0x74, 0x70,
+	0xf5, 0xf8, 0xdb, 0xea, 0xea, 0xfa, 0x65, 0x7e, 0x9b, 0xb0, 0x17, 0xf3,
+	0xf7, 0x87, 0xeb, 0xda, 0x7d, 0xd7, 0xf4, 0x52, 0x2f, 0xf6, 0xf0, 0xe2,
+	0x20, 0xce, 0x21, 0x55, 0x87, 0x73, 0x56, 0x7f, 0x2f, 0x9a, 0x43, 0x79,
+	0x7e, 0xd6, 0xbf, 0x3b, 0x64, 0x60, 0x2e, 0x56, 0x81, 0xf1, 0x8b, 0xc9,
+	0x6f, 0x33, 0x67, 0x0b, 0xa0, 0xfb, 0x66, 0x75, 0xef, 0x88, 0x77, 0x37,
+	0x50, 0x2f, 0xe1, 0xe1, 0x4f, 0xe6, 0xe3, 0x58, 0xf3, 0x77, 0x75, 0x18,
+	0xe9, 0xff, 0x7e, 0x53, 0xb6, 0x9f, 0xf8, 0x66, 0x13, 0xcf, 0x21, 0x81,
+	0x9b, 0x29, 0x67, 0xdf, 0x81, 0x9c, 0x35, 0xaa, 0x73, 0x9f, 0x62, 0x89,
+	0xf1, 0x5c, 0x1e, 0xf2, 0xc3, 0xfb, 0x7b, 0x8c, 0xfb, 0xf2, 0x7a, 0x3f,
+	0x96, 0x74, 0x12, 0xd3, 0xfb, 0xf1, 0x01, 0xfb, 0x5c, 0xef, 0x9e, 0xb2,
+	0x1f, 0xb3, 0x51, 0xde, 0xe2, 0x8a, 0xe6, 0xa1, 0x35, 0xf1, 0xca, 0x21,
+	0xd8, 0x82, 0x79, 0xc8, 0xf3, 0x5e, 0xd8, 0xc0, 0xc1, 0x20, 0xf5, 0x33,
+	0xaa, 0x63, 0x59, 0x9b, 0x71, 0x7b, 0x60, 0x14, 0x7d, 0x18, 0xd3, 0xaf,
+	0xc9, 0x04, 0xec, 0xff, 0x64, 0x35, 0xa9, 0xbe, 0xe9, 0xc9, 0xc4, 0x79,
+	0x9f, 0x8c, 0xe5, 0x5f, 0x83, 0xbc, 0xbe, 0x06, 0x3c, 0xbc, 0x01, 0xfc,
+	0x34, 0xf4, 0x5a, 0xfd, 0x96, 0xde, 0x8b, 0x8a, 0x70, 0x2f, 0x1e, 0x76,
+	0xb3, 0xe8, 0x61, 0xcd, 0xd8, 0x24, 0xd2, 0x7f, 0x1e, 0xf5, 0xe4, 0xf5,
+	0xdf, 0x6a, 0x79, 0x6b, 0x42, 0xf9, 0x63, 0x6a, 0x0f, 0xd2, 0x9b, 0x93,
+	0xa5, 0x63, 0x95, 0x30, 0x64, 0x8e, 0xf3, 0xfa, 0x53, 0xd4, 0xa3, 0xac,
+	0xf5, 0xe8, 0xb3, 0xd9, 0xa8, 0xb2, 0x8f, 0x39, 0xc8, 0x52, 0x5e, 0xc5,
+	0x11, 0xc0, 0xf7, 0x0e, 0xdb, 0x3d, 0xb7, 0x89, 0x67, 0x9f, 0x0d, 0xb6,
+	0x8a, 0x2d, 0xda, 0x83, 0xe2, 0x97, 0xdd, 0x89, 0x32, 0xca, 0xd9, 0x8d,
+	0x58, 0x1b, 0x96, 0x65, 0x91, 0xe7, 0x58, 0x37, 0xe9, 0x71, 0x38, 0x46,
+	0x77, 0xf3, 0x6a, 0x9a, 0x38, 0x97, 0xf6, 0x35, 0xdf, 0x35, 0xb0, 0xec,
+	0x46, 0x5d, 0x16, 0xd2, 0xf3, 0x1b, 0xd2, 0xdf, 0xd2, 0x5a, 0x87, 0x33,
+	0x2b, 0xd8, 0x98, 0xf4, 0x45, 0x54, 0xbb, 0x8c, 0xe9, 0xc9, 0xce, 0x21,
+	0xac, 0x47, 0x28, 0x1d, 0xe4, 0x99, 0x2c, 0xf8, 0xeb, 0xeb, 0x44, 0x5c,
+	0xc5, 0x9d, 0x09, 0xc3, 0xbb, 0xbb, 0x74, 0xee, 0x9a, 0xfb, 0xd9, 0xde,
+	0x5d, 0xf7, 0xa1, 0x9e, 0x26, 0x99, 0x9f, 0x89, 0xe8, 0x7b, 0x93, 0x71,
+	0xa5, 0xb3, 0xf9, 0x31, 0xe6, 0xff, 0xc7, 0x26, 0x7e, 0xc7, 0x6c, 0xd8,
+	0x2c, 0x6f, 0xd7, 0xfc, 0xbd, 0x51, 0xdd, 0x33, 0xa2, 0x2e, 0x14, 0xe7,
+	0xde, 0x50, 0xef, 0x4f, 0xcf, 0x36, 0xa8, 0xfa, 0xa7, 0x67, 0xd7, 0xde,
+	0x15, 0x62, 0xd9, 0xdb, 0xb8, 0xbf, 0x21, 0x0b, 0x53, 0x0d, 0xb2, 0x38,
+	0x1b, 0x60, 0xbc, 0x96, 0x6e, 0xac, 0x7d, 0x0b, 0xa3, 0xbf, 0x5b, 0x73,
+	0x65, 0x08, 0xeb, 0x37, 0x3f, 0x30, 0x29, 0xe5, 0x01, 0xc6, 0x23, 0xea,
+	0x3e, 0x20, 0x64, 0xa4, 0x01, 0x58, 0xb4, 0xe0, 0x96, 0x6d, 0xee, 0x03,
+	0xb7, 0x68, 0xbd, 0x7e, 0x45, 0xc7, 0x7c, 0xe4, 0x91, 0x21, 0xb9, 0xbe,
+	0x09, 0x45, 0x57, 0x59, 0xf1, 0xca, 0xff, 0xd6, 0x88, 0xfd, 0xf3, 0x7b,
+	0xa3, 0xa0, 0xc6, 0xb2, 0xfb, 0x35, 0xcf, 0xff, 0x4a, 0xa7, 0x8f, 0xca,
+	0x9e, 0x63, 0xbf, 0x0f, 0x5a, 0x9b, 0xbc, 0x3b, 0x4f, 0x52, 0xff, 0x3d,
+	0x49, 0x48, 0x7d, 0xcf, 0x12, 0xb2, 0x1f, 0x45, 0x19, 0xf7, 0xc1, 0x1e,
+	0x55, 0xf3, 0xe0, 0xbd, 0xba, 0x82, 0xfc, 0xaa, 0xfb, 0x21, 0x7e, 0x2c,
+	0xc6, 0xbb, 0x4b, 0x51, 0xdd, 0xdf, 0x0e, 0xbd, 0x8e, 0x63, 0xb2, 0x07,
+	0xbe, 0x26, 0x0f, 0x4c, 0xca, 0xfb, 0x5e, 0xe3, 0xc1, 0xfa, 0x31, 0x7d,
+	0x59, 0xf6, 0xe2, 0x7c, 0xff, 0xde, 0x41, 0x50, 0xc5, 0x23, 0x2b, 0x7b,
+	0x06, 0xba, 0x7c, 0x4c, 0xf6, 0x95, 0xd4, 0xde, 0x81, 0x3a, 0x2f, 0x9c,
+	0x84, 0x4e, 0x0e, 0x2a, 0x7f, 0x12, 0x09, 0x0c, 0x55, 0xd2, 0x92, 0x3f,
+	0xb9, 0x13, 0xe3, 0x70, 0x1f, 0x2e, 0xa3, 0xcf, 0xe5, 0x76, 0xcb, 0x9e,
+	0xaa, 0x37, 0xf6, 0xde, 0x12, 0xdf, 0x27, 0xe1, 0xa3, 0xf9, 0x3e, 0x17,
+	0x0f, 0xaa, 0x93, 0x85, 0x5b, 0xd1, 0xb6, 0x41, 0xf3, 0x96, 0xf7, 0xfc,
+	0xd9, 0x9e, 0xfa, 0xf7, 0x4f, 0x4c, 0x89, 0xe6, 0xf0, 0x9e, 0x6d, 0xfc,
+	0xfe, 0xf6, 0xc2, 0x67, 0x30, 0x36, 0x7e, 0x44, 0x96, 0xe6, 0x26, 0x65,
+	0x79, 0xce, 0x97, 0x33, 0xde, 0xb9, 0x26, 0xed, 0x77, 0xeb, 0x3b, 0xd7,
+	0x19, 0xac, 0xc3, 0x6a, 0x5e, 0xe5, 0x56, 0x7d, 0x8f, 0xf4, 0x75, 0xd3,
+	0xfb, 0x26, 0x70, 0xbb, 0xba, 0x3f, 0xb5, 0x5a, 0xde, 0xd9, 0xcf, 0x57,
+	0x4c, 0x9e, 0x33, 0x78, 0x77, 0xc0, 0xda, 0xeb, 0xde, 0xc7, 0xf4, 0xbd,
+	0xab, 0xaf, 0xe9, 0xbb, 0xfa, 0xe4, 0xe7, 0xa8, 0xa6, 0xf7, 0x56, 0xe8,
+	0x1e, 0xfb, 0x7c, 0x4c, 0xaf, 0x1b, 0xd2, 0x79, 0x3e, 0xab, 0xbb, 0xa6,
+	0xfa, 0xec, 0xd5, 0xd4, 0x63, 0xd4, 0xdf, 0x7b, 0x6b, 0xa8, 0x1b, 0x97,
+	0xed, 0xe9, 0x1b, 0xfc, 0x3b, 0xe0, 0x2c, 0x3b, 0xa6, 0xef, 0xd7, 0xf9,
+	0x77, 0xbe, 0x59, 0xe6, 0xdf, 0x03, 0x23, 0xbf, 0xb8, 0x9f, 0x88, 0xb4,
+	0x3a, 0xaa, 0x9f, 0x47, 0xeb, 0xbe, 0x1d, 0xf2, 0xfb, 0x0c, 0xa1, 0x8f,
+	0x3b, 0x83, 0xd7, 0xde, 0x11, 0xe7, 0xb7, 0x54, 0x94, 0x45, 0x83, 0xdf,
+	0x78, 0x33, 0x06, 0x03, 0x6e, 0xda, 0x28, 0x7b, 0x15, 0x3d, 0x05, 0x75,
+	0x57, 0x22, 0xeb, 0x34, 0xc9, 0xa0, 0xe9, 0xe5, 0xf7, 0xce, 0xaf, 0x95,
+	0x53, 0x96, 0x6f, 0x8a, 0x48, 0x94, 0xdf, 0x70, 0xf1, 0xfd, 0x7a, 0xdf,
+	0x2e, 0x84, 0xf5, 0xf7, 0x53, 0x0e, 0xda, 0x7c, 0x9e, 0xf2, 0x5e, 0x28,
+	0xac, 0xdc, 0xd1, 0x2c, 0xa8, 0x3d, 0x52, 0x00, 0x73, 0x7d, 0x57, 0x92,
+	0xdf, 0xb0, 0x8b, 0x3c, 0x5d, 0xe1, 0xb7, 0x5c, 0xdb, 0xd5, 0x1d, 0x16,
+	0xef, 0x5c, 0x90, 0x74, 0x75, 0x29, 0x9b, 0x5c, 0xae, 0x14, 0xc9, 0x53,
+	0xed, 0x57, 0xc3, 0xda, 0xaf, 0x92, 0xc7, 0xc3, 0xe0, 0xf1, 0x5f, 0xeb,
+	0x75, 0x61, 0xfb, 0x8c, 0xba, 0x0b, 0x9e, 0x89, 0xf1, 0x6c, 0xea, 0x31,
+	0x35, 0x17, 0xda, 0x68, 0xb4, 0x7d, 0x47, 0x50, 0xe9, 0xae, 0xfa, 0x46,
+	0x1e, 0xf2, 0xc9, 0x6f, 0xde, 0x61, 0x5f, 0x4b, 0xfc, 0xb6, 0x7d, 0x58,
+	0x7d, 0x67, 0x52, 0xae, 0x70, 0x5d, 0xf9, 0x4d, 0xfb, 0x68, 0x9d, 0x3c,
+	0x06, 0xf5, 0x58, 0x9b, 0x5a, 0x25, 0xea, 0xad, 0x3b, 0xbf, 0x51, 0x29,
+	0x57, 0xfc, 0xfb, 0x9d, 0x1b, 0x96, 0xa8, 0x13, 0xa2, 0x62, 0x6c, 0xef,
+	0x3b, 0x9b, 0xb2, 0xfa, 0x6e, 0x25, 0xc1, 0xef, 0x2e, 0xe1, 0x3b, 0x76,
+	0xe1, 0x99, 0x67, 0xba, 0xbb, 0x91, 0xc2, 0xe6, 0x54, 0xc6, 0x91, 0x3e,
+	0x2c, 0x39, 0xb5, 0xe7, 0xd6, 0x8c, 0xfc, 0x5e, 0x35, 0x76, 0xb1, 0xf2,
+	0x80, 0xec, 0x39, 0xf9, 0x10, 0xbf, 0xed, 0x51, 0xdf, 0xe5, 0x67, 0x1d,
+	0xd2, 0x18, 0x93, 0x09, 0x35, 0xef, 0x42, 0xed, 0x9b, 0x11, 0xc5, 0xfb,
+	0x5c, 0x2b, 0xd7, 0xb4, 0x50, 0x69, 0x06, 0x8d, 0x01, 0x7d, 0xc7, 0x93,
+	0x58, 0xdc, 0x9f, 0x7f, 0x94, 0xf7, 0x06, 0x5d, 0x9e, 0xdd, 0xed, 0x29,
+	0xf1, 0x0e, 0x67, 0x52, 0xc7, 0xe8, 0xdc, 0xb7, 0xe3, 0xd9, 0x00, 0x65,
+	0xdc, 0x4a, 0x8d, 0xc3, 0xfa, 0x87, 0x25, 0xce, 0x73, 0x65, 0x3d, 0x97,
+	0xe6, 0xba, 0xb9, 0xf0, 0xde, 0xaa, 0x37, 0x1f, 0x7e, 0x0b, 0x93, 0x2f,
+	0xd5, 0x7f, 0xc7, 0xa3, 0xbe, 0x11, 0x57, 0xdf, 0xcd, 0x8c, 0x57, 0x3e,
+	0x21, 0x1f, 0x2b, 0x6d, 0xd4, 0xdf, 0xf0, 0x44, 0xe4, 0x63, 0x95, 0xd7,
+	0x14, 0x4f, 0xf3, 0xea, 0xfb, 0xa3, 0xb0, 0x5e, 0xb3, 0x98, 0xea, 0xa3,
+	0xf6, 0x1d, 0x92, 0x55, 0xf7, 0x4d, 0x4a, 0x58, 0xc6, 0xe7, 0x7f, 0xd9,
+	0xb7, 0x48, 0x8f, 0x08, 0xbf, 0x47, 0xb9, 0xe4, 0x4c, 0xca, 0xe3, 0x73,
+	0xae, 0x7b, 0x97, 0x43, 0x5c, 0xb7, 0x41, 0x96, 0x63, 0xa3, 0x3b, 0xbe,
+	0x67, 0xb7, 0x05, 0xca, 0x33, 0x8d, 0xb0, 0xd7, 0xc4, 0x12, 0x12, 0x65,
+	0x7e, 0x7e, 0x86, 0x7a, 0x1a, 0xc2, 0x1c, 0x2d, 0xf3, 0xaa, 0x7c, 0xa6,
+	0x95, 0x7b, 0x5e, 0x77, 0x21, 0x8e, 0xfc, 0xb8, 0xe3, 0xd9, 0xe5, 0xcf,
+	0x2d, 0xec, 0x94, 0xcf, 0x55, 0x22, 0x81, 0xf2, 0x14, 0xef, 0xfa, 0x59,
+	0xc3, 0x73, 0x92, 0x44, 0x3d, 0xf6, 0x0f, 0x79, 0x89, 0x6f, 0x96, 0xa7,
+	0x8e, 0xfd, 0xc2, 0xbd, 0x6a, 0xe3, 0x3d, 0x6c, 0xcd, 0xb2, 0xe3, 0xef,
+	0xeb, 0x21, 0x86, 0x3f, 0xc2, 0x7a, 0x9b, 0x21, 0x07, 0xf0, 0xdb, 0xd0,
+	0x39, 0xc6, 0x98, 0x57, 0xb5, 0xdd, 0x32, 0x8e, 0xdc, 0x2c, 0x57, 0x57,
+	0xee, 0x0a, 0x5f, 0x86, 0x6c, 0x27, 0x3c, 0xfe, 0xab, 0x7d, 0xf0, 0x03,
+	0x12, 0xfc, 0x22, 0xfc, 0xc4, 0x17, 0x1b, 0x94, 0x6d, 0xa7, 0x3f, 0x43,
+	0xfc, 0x81, 0x18, 0x23, 0x84, 0x7e, 0x1e, 0x6c, 0xf5, 0x64, 0x76, 0x52,
+	0xe4, 0xcb, 0x4d, 0x92, 0x69, 0x65, 0x0c, 0x2b, 0xbf, 0xc2, 0x7e, 0xd5,
+	0xeb, 0x59, 0x4a, 0xbe, 0x42, 0x1d, 0xaf, 0x72, 0x2e, 0xc9, 0xf8, 0x8f,
+	0xe5, 0x93, 0x32, 0x1e, 0xe7, 0x5c, 0x1e, 0x91, 0xc2, 0xdc, 0x63, 0xf8,
+	0x71, 0x9e, 0xa4, 0xfb, 0x1f, 0xe8, 0x7b, 0x04, 0xa3, 0x52, 0x9c, 0x4a,
+	0xcb, 0xc4, 0xec, 0x5e, 0x7e, 0xa3, 0x3b, 0x7c, 0x97, 0x3a, 0x5f, 0xb3,
+	0xe2, 0xc9, 0x40, 0x6f, 0x62, 0x82, 0xf7, 0x26, 0xd4, 0x7c, 0xf6, 0x62,
+	0x3e, 0xdf, 0x6a, 0xe5, 0xdd, 0xf3, 0xab, 0xb0, 0xbf, 0xc6, 0x71, 0xca,
+	0xa1, 0x65, 0x76, 0x06, 0x98, 0xdf, 0x8d, 0xd8, 0x99, 0x65, 0xbb, 0x25,
+	0x78, 0x64, 0xc5, 0xce, 0xa3, 0x5c, 0x9f, 0xf3, 0xaa, 0xf6, 0xff, 0x11,
+	0x6d, 0x51, 0xef, 0x88, 0xdf, 0xd6, 0xaf, 0xc3, 0xb6, 0x9c, 0xe7, 0x4e,
+	0xc4, 0xec, 0x3e, 0x5d, 0x90, 0xc3, 0x78, 0x3d, 0xbf, 0xa3, 0x6b, 0xf8,
+	0x1d, 0x22, 0xde, 0x04, 0xbf, 0xc8, 0xe3, 0xa0, 0xe6, 0xf1, 0x9b, 0xe8,
+	0xdf, 0x5f, 0x83, 0xbb, 0x50, 0x66, 0xea, 0x6f, 0x03, 0xdf, 0x0a, 0xdf,
+	0xc9, 0x73, 0xd6, 0x7f, 0xb0, 0xd5, 0x93, 0x35, 0xd2, 0xb3, 0x1e, 0xcf,
+	0x3b, 0xdb, 0xbc, 0x75, 0xd9, 0x0d, 0x7e, 0xf1, 0x4e, 0x67, 0xaf, 0xfa,
+	0x4e, 0x20, 0x33, 0xb6, 0x1b, 0xb2, 0xe3, 0xcf, 0xab, 0x17, 0x32, 0xc6,
+	0x33, 0x0b, 0xd6, 0xaf, 0xe7, 0x89, 0xe7, 0xf7, 0x82, 0xdc, 0x77, 0xb0,
+	0x39, 0x57, 0x60, 0xc2, 0x2f, 0xab, 0xef, 0x82, 0x60, 0x27, 0xdf, 0xb6,
+	0xf2, 0x5d, 0xd0, 0xf5, 0xd7, 0x78, 0xa0, 0xcd, 0xf3, 0x51, 0x26, 0x78,
+	0xd2, 0xa2, 0xdb, 0xec, 0x06, 0x3e, 0xe5, 0x5e, 0x6c, 0x32, 0xfe, 0xa0,
+	0xf8, 0xe3, 0xb8, 0xdb, 0x19, 0x73, 0x0e, 0xf6, 0xf7, 0x22, 0xbe, 0x56,
+	0xf7, 0x65, 0xe2, 0xbc, 0x7f, 0x93, 0x0c, 0xec, 0x56, 0x77, 0x27, 0x2e,
+	0xac, 0xfa, 0xb6, 0x2b, 0x25, 0x4f, 0xd5, 0x64, 0x65, 0xf8, 0x27, 0x62,
+	0x49, 0xe2, 0x26, 0xca, 0x0a, 0xfb, 0xdd, 0xcb, 0x79, 0xc6, 0x1f, 0x52,
+	0xf3, 0x34, 0x11, 0xc3, 0xf1, 0x9e, 0x83, 0x19, 0x28, 0xcf, 0x72, 0xdd,
+	0x91, 0x2e, 0xf0, 0xd9, 0x3f, 0x6b, 0x55, 0x76, 0x05, 0xe3, 0xb2, 0x8c,
+	0xb6, 0x91, 0xef, 0xd3, 0xfa, 0x2c, 0xf6, 0xc3, 0x6d, 0xbc, 0x0f, 0x90,
+	0x47, 0xd9, 0xdc, 0xc2, 0xfa, 0xb4, 0x7d, 0x5c, 0xc9, 0xc1, 0x23, 0xe0,
+	0xfb, 0x1f, 0xa3, 0xee, 0x63, 0x48, 0x39, 0xc7, 0xf4, 0xca, 0xba, 0x93,
+	0xdf, 0x1f, 0x90, 0x01, 0xc8, 0x05, 0xf3, 0x8f, 0x48, 0x51, 0xdd, 0x63,
+	0x42, 0x3a, 0xc7, 0x67, 0xda, 0x7a, 0x5b, 0xfb, 0x53, 0xd2, 0xb2, 0x5b,
+	0x7f, 0x4f, 0xe6, 0xcb, 0xd3, 0x2e, 0xdd, 0x6e, 0x6c, 0x85, 0x57, 0x0f,
+	0x5d, 0x83, 0x37, 0xc2, 0x2b, 0x78, 0xc3, 0x1b, 0xeb, 0xf1, 0x36, 0x1f,
+	0x6b, 0x78, 0x73, 0xf0, 0xb0, 0x86, 0x27, 0xe7, 0x7b, 0x25, 0x04, 0x39,
+	0x0e, 0xd6, 0xe4, 0x18, 0xb8, 0xc7, 0xd3, 0x99, 0x09, 0x9e, 0x21, 0x2a,
+	0x3e, 0x53, 0x0e, 0x29, 0xbf, 0x5c, 0xc7, 0xfa, 0xb5, 0x7e, 0xcf, 0x2f,
+	0x59, 0xeb, 0x97, 0xdb, 0x7c, 0xfc, 0xf0, 0x77, 0xd3, 0x83, 0x0b, 0x6d,
+	0x35, 0x3d, 0xb8, 0xf9, 0x37, 0xa4, 0x07, 0x6b, 0xe5, 0xb2, 0x5e, 0xa6,
+	0x4c, 0xc8, 0x13, 0xd7, 0x8b, 0xf2, 0x44, 0x39, 0x22, 0x2f, 0x69, 0x4f,
+	0x1b, 0x19, 0x3b, 0xc5, 0xaf, 0xa8, 0xef, 0x36, 0x26, 0x61, 0x83, 0xda,
+	0x02, 0x73, 0x73, 0x31, 0x29, 0x2e, 0xbc, 0x4f, 0xc9, 0xf4, 0x53, 0x55,
+	0xda, 0xa5, 0xeb, 0xcd, 0x7d, 0xb5, 0xcd, 0xcd, 0xaf, 0xb1, 0xb9, 0xf9,
+	0x15, 0x9b, 0xdb, 0xaa, 0xe3, 0xa5, 0xbf, 0x8b, 0xcd, 0x8d, 0xd5, 0x9d,
+	0xcb, 0xf8, 0x67, 0x32, 0x12, 0xc8, 0xf6, 0x44, 0x65, 0x07, 0xfc, 0xc8,
+	0xf0, 0xd4, 0x4e, 0xf9, 0x97, 0x53, 0x93, 0xea, 0x8e, 0xd2, 0x5f, 0x38,
+	0xc9, 0xf8, 0x03, 0x01, 0x57, 0x3e, 0x80, 0x78, 0x77, 0xbc, 0xa3, 0x41,
+	0x76, 0xbc, 0x4b, 0x9d, 0x35, 0x9a, 0xd9, 0x40, 0xbb, 0x70, 0x17, 0x3c,
+	0xe7, 0x58, 0x4e, 0x22, 0xc0, 0xfb, 0x6a, 0x8d, 0x32, 0x1e, 0x6b, 0x96,
+	0x9d, 0xc0, 0x4e, 0x85, 0x1b, 0x1c, 0xf5, 0x2d, 0x79, 0x46, 0x9d, 0xe5,
+	0xdc, 0xb2, 0xd9, 0x1b, 0x17, 0x7c, 0x68, 0x31, 0xe5, 0xab, 0xd5, 0x5b,
+	0xd4, 0x77, 0xd1, 0x17, 0x4a, 0xd5, 0xd6, 0xd5, 0x79, 0x3e, 0xff, 0x7b,
+	0xd4, 0x89, 0x81, 0x57, 0xf5, 0x77, 0x7f, 0x82, 0x8a, 0x9f, 0xc5, 0xb9,
+	0x31, 0x75, 0xa7, 0xea, 0x4a, 0x90, 0xfc, 0x52, 0x71, 0x53, 0x3c, 0x1b,
+	0x04, 0xc6, 0x99, 0x01, 0x92, 0xb6, 0x19, 0xf3, 0x69, 0xfc, 0x09, 0xfb,
+	0xbf, 0x47, 0x9d, 0xed, 0x2e, 0x81, 0x37, 0xae, 0xda, 0xfb, 0xcd, 0xc7,
+	0x88, 0xeb, 0x6b, 0xf7, 0x87, 0xaf, 0xc5, 0xf7, 0xde, 0xb7, 0x67, 0xfa,
+	0x1c, 0x42, 0xef, 0x15, 0xe9, 0x18, 0x5c, 0x9d, 0xab, 0xad, 0xf7, 0x7f,
+	0x29, 0x88, 0xf5, 0xf8, 0x7f, 0x0f, 0x88, 0xed, 0xac, 0xc3, 0x73, 0xe2,
+	0xa8, 0x38, 0x30, 0x43, 0xfe, 0x96, 0xb1, 0x4e, 0xd3, 0x71, 0xdf, 0x9f,
+	0x07, 0x3a, 0xcf, 0xd6, 0xc7, 0x81, 0xec, 0x23, 0xa2, 0xee, 0x63, 0xd4,
+	0xfe, 0x0f, 0x0e, 0xf7, 0x77, 0x32, 0x81, 0x7b, 0x4a, 0x93, 0x12, 0x3c,
+	0x3a, 0x2a, 0xa1, 0x69, 0xee, 0xa5, 0x67, 0xa4, 0x18, 0x73, 0xe5, 0x63,
+	0xce, 0xea, 0xd8, 0xa4, 0xd3, 0x58, 0x4b, 0xfb, 0x23, 0x32, 0x78, 0xf2,
+	0x31, 0x09, 0x1f, 0xe5, 0xbb, 0x55, 0xe7, 0x28, 0xb0, 0x47, 0x1b, 0x64,
+	0x2e, 0xc6, 0xfd, 0xe4, 0xb0, 0x3a, 0x97, 0x5e, 0x1e, 0x7b, 0x2d, 0x5c,
+	0x04, 0x56, 0xc8, 0x2b, 0xdb, 0x82, 0x74, 0x25, 0x96, 0x38, 0xbc, 0x99,
+	0x3a, 0x85, 0x18, 0x33, 0x30, 0x3e, 0x17, 0x56, 0xf7, 0x83, 0x96, 0x63,
+	0xac, 0x8b, 0xf8, 0xfd, 0x28, 0x71, 0x06, 0x6c, 0xc7, 0xa8, 0x44, 0x99,
+	0x0f, 0x1e, 0xad, 0xe1, 0x0c, 0xda, 0x84, 0x41, 0x27, 0x26, 0xa1, 0x53,
+	0xde, 0xdc, 0xf9, 0x8f, 0x95, 0x8c, 0x13, 0x3b, 0x25, 0x38, 0xcd, 0xe7,
+	0xfa, 0x78, 0x88, 0xd8, 0x1d, 0xbe, 0xe1, 0xec, 0x67, 0xd1, 0x1f, 0xdf,
+	0x65, 0xf4, 0x37, 0xba, 0xc8, 0x97, 0xff, 0xb6, 0xff, 0x43, 0x81, 0xb2,
+	0xff, 0xff, 0x01, 0xe6, 0x8e, 0x9a, 0x21, 0xc0, 0x4e, 0x00, 0x00, 0x00 };
 
 static const u32 bnx2_COM_b06FwData[(0x0/4) + 1] = { 0x0 };
 static const u32 bnx2_COM_b06FwRodata[(0x14/4) + 1] = {
-	0x08000f04, 0x08000f4c, 0x08000f80, 0x08000fcc, 0x08001000, 0x00000000
+	0x08000e7c, 0x08000ec4, 0x08000ef8, 0x08000f44, 0x08000f78, 0x00000000
 };
 
 static struct fw_info bnx2_com_fw_06 = {
-	/* Firmware version: 4.0.5 */
+	/* Firmware version: 4.4.2 */
 	.ver_major			= 0x4,
-	.ver_minor			= 0x0,
-	.ver_fix			= 0x5,
+	.ver_minor			= 0x4,
+	.ver_fix			= 0x2,
 
 	.start_addr			= 0x080000f8,
 
 	.text_addr			= 0x08000000,
-	.text_len			= 0x4eac,
+	.text_len			= 0x4ebc,
 	.text_index			= 0x0,
 	.gz_text			= bnx2_COM_b06FwText,
 	.gz_text_len			= sizeof(bnx2_COM_b06FwText),
@@ -872,15 +872,15 @@
 	.data_index			= 0x0,
 	.data				= bnx2_COM_b06FwData,
 
-	.sbss_addr			= 0x08004ee0,
+	.sbss_addr			= 0x08004f00,
 	.sbss_len			= 0x38,
 	.sbss_index			= 0x0,
 
-	.bss_addr			= 0x08004f18,
+	.bss_addr			= 0x08004f38,
 	.bss_len			= 0xbc,
 	.bss_index			= 0x0,
 
-	.rodata_addr			= 0x08004eac,
+	.rodata_addr			= 0x08004ebc,
 	.rodata_len			= 0x14,
 	.rodata_index			= 0x0,
 	.rodata				= bnx2_COM_b06FwRodata,
@@ -902,1231 +902,1232 @@
 	.mips_view_base = 0x8000000,
 };
 
-
 static u8 bnx2_CP_b06FwText[] = {
-	0x9d, 0xbc, 0x0d, 0x78, 0x13, 0xe7, 0x99, 0x2e, 0x7c, 0xcf, 0x48, 0xb2,
-	0x65, 0x5b, 0xb6, 0xc7, 0xb6, 0x0c, 0x22, 0x65, 0x41, 0x83, 0x47, 0x20,
-	0x62, 0x27, 0x1d, 0x81, 0x49, 0x94, 0xac, 0x36, 0xa8, 0xc6, 0x01, 0x93,
-	0x90, 0xc6, 0x34, 0xb4, 0x75, 0x7a, 0xd2, 0x8d, 0x62, 0x0c, 0x21, 0x84,
-	0x10, 0x67, 0x9b, 0x9e, 0xe3, 0x7c, 0x5f, 0xce, 0x5a, 0x35, 0x06, 0x0c,
-	0xc8, 0x96, 0x31, 0x0e, 0x90, 0xfd, 0x7a, 0x9d, 0x18, 0x6c, 0x30, 0x49,
-	0x65, 0x8b, 0x34, 0x74, 0x97, 0xf4, 0xa3, 0x45, 0x07, 0xf2, 0xe3, 0xfc,
-	0x35, 0xa4, 0xed, 0x76, 0xdb, 0x3d, 0x39, 0x89, 0x0f, 0x25, 0x84, 0xb4,
-	0xdd, 0xfc, 0xb4, 0xdd, 0x2d, 0x69, 0x9b, 0xcc, 0x77, 0x3f, 0x23, 0x09,
-	0x0c, 0x4d, 0x7f, 0xf6, 0xf3, 0x75, 0xcd, 0x65, 0xcd, 0xcc, 0xfb, 0xf3,
-	0xbc, 0xcf, 0xfb, 0x3c, 0xf7, 0x73, 0x3f, 0xef, 0xbc, 0x33, 0xb3, 0x80,
-	0x62, 0xe4, 0xfe, 0x4a, 0x79, 0x5c, 0x5d, 0xdf, 0xbe, 0x1a, 0x8b, 0xae,
-	0x36, 0xe5, 0xdc, 0xe9, 0x82, 0x13, 0x7f, 0xe1, 0x9f, 0xff, 0x2f, 0x2d,
-	0x38, 0xe5, 0xcf, 0x01, 0x68, 0xf9, 0x7e, 0xe5, 0x80, 0x5b, 0x8d, 0x3c,
-	0xf3, 0x5f, 0x1a, 0x0c, 0xb8, 0x1d, 0x91, 0x9e, 0xd6, 0xd5, 0x06, 0x10,
-	0x4d, 0xd5, 0xfa, 0x97, 0xe0, 0x23, 0x2b, 0xee, 0x75, 0x42, 0xae, 0xff,
-	0x55, 0xe4, 0xf7, 0x9d, 0xdf, 0xb9, 0x56, 0x7f, 0x7f, 0xc8, 0x01, 0xb7,
-	0x16, 0xe9, 0x80, 0x36, 0x17, 0xee, 0x99, 0xac, 0xf3, 0xf5, 0x79, 0xdb,
-	0x15, 0x94, 0xe5, 0xdb, 0x3a, 0x67, 0x7d, 0x67, 0x9e, 0x2f, 0x56, 0x14,
-	0xd1, 0x70, 0x3c, 0x8d, 0xe6, 0xba, 0xde, 0x4e, 0xab, 0xd4, 0x08, 0xc1,
-	0x6d, 0x18, 0x2d, 0xbd, 0x8a, 0x27, 0xbc, 0x7e, 0x11, 0x3c, 0x85, 0x06,
-	0xe2, 0x57, 0x44, 0xd0, 0x7c, 0xe5, 0x58, 0x71, 0xdc, 0x19, 0x71, 0xa3,
-	0x29, 0xed, 0x8e, 0x7f, 0x2a, 0x62, 0x60, 0x59, 0xfa, 0xfa, 0x62, 0x94,
-	0xb9, 0xd1, 0x9d, 0xfe, 0xa8, 0x28, 0xdb, 0x5e, 0x73, 0xee, 0xff, 0xec,
-	0xaa, 0xec, 0xff, 0x69, 0x31, 0x67, 0x04, 0xd8, 0x9c, 0xb0, 0xac, 0x82,
-	0xc8, 0x6d, 0xb7, 0xa9, 0x11, 0xc3, 0x77, 0x10, 0x8b, 0xd1, 0xaa, 0xe1,
-	0xe1, 0x2d, 0xf5, 0xbf, 0x54, 0x4e, 0x0c, 0xb2, 0xe1, 0x51, 0x07, 0xa2,
-	0xda, 0x33, 0xfc, 0x3f, 0x6b, 0x56, 0x4b, 0xd8, 0xc0, 0xde, 0xd1, 0xf3,
-	0xbc, 0xee, 0xb4, 0xaf, 0x6d, 0xda, 0x33, 0x6b, 0xd6, 0xed, 0xe1, 0x67,
-	0xf0, 0xe8, 0xa8, 0xfc, 0xbe, 0x1b, 0x9d, 0x75, 0x0a, 0x26, 0x6f, 0x5b,
-	0x0b, 0x87, 0x61, 0xa0, 0x7b, 0x8f, 0xe2, 0xec, 0xaa, 0x53, 0x11, 0xf5,
-	0xea, 0xc1, 0x18, 0x95, 0xef, 0x34, 0x10, 0x2b, 0x8c, 0x84, 0x9d, 0xef,
-	0x24, 0x22, 0x9a, 0xc3, 0xb0, 0xac, 0x60, 0x68, 0x3a, 0x1c, 0x15, 0x96,
-	0xf5, 0xb4, 0xe9, 0x81, 0xff, 0x8b, 0xcf, 0x21, 0x3e, 0xdc, 0x0c, 0xd5,
-	0x78, 0x0e, 0x5d, 0xc3, 0xcf, 0xe1, 0xb1, 0x5d, 0xc5, 0x98, 0xac, 0xe2,
-	0x78, 0x93, 0x3e, 0x7c, 0x67, 0x9e, 0xf4, 0x2d, 0x72, 0xd4, 0xf1, 0x70,
-	0x63, 0xd2, 0xf1, 0x06, 0xff, 0x4b, 0x99, 0xf3, 0xd6, 0xe4, 0xf4, 0x8b,
-	0x65, 0x36, 0xb3, 0x4c, 0xf7, 0x65, 0x65, 0xe2, 0xc3, 0x11, 0xbc, 0x94,
-	0x50, 0xb0, 0x3e, 0x54, 0x86, 0x68, 0x85, 0x8c, 0xd7, 0xb2, 0x46, 0xcd,
-	0xb3, 0xd6, 0xa4, 0x26, 0x7d, 0x4d, 0xe0, 0x65, 0xde, 0xdb, 0x12, 0x3a,
-	0x63, 0x65, 0xbc, 0xd2, 0x5e, 0x3b, 0x6d, 0x67, 0x25, 0xaf, 0x3b, 0x91,
-	0x4c, 0x20, 0x56, 0x16, 0xb9, 0x8d, 0xe7, 0xba, 0xf9, 0xae, 0xe2, 0x76,
-	0xbf, 0x97, 0x70, 0x7f, 0xb1, 0xd4, 0x50, 0x1f, 0x2c, 0xa7, 0x01, 0xbd,
-	0x42, 0x99, 0x8f, 0x9a, 0x6b, 0xe1, 0x32, 0x1e, 0x10, 0x5b, 0xe3, 0xb8,
-	0x7e, 0x68, 0x61, 0x7a, 0xbe, 0xbe, 0xb4, 0xeb, 0xc6, 0x96, 0xa4, 0x65,
-	0x6d, 0x33, 0xa3, 0xd7, 0x15, 0xd1, 0x20, 0x4e, 0x26, 0x9a, 0xe1, 0x8e,
-	0x04, 0xfc, 0xe7, 0x10, 0xc6, 0x92, 0xb4, 0x17, 0xcf, 0x26, 0xe0, 0x6c,
-	0x98, 0xe7, 0x45, 0x57, 0x3a, 0x82, 0x1b, 0xd3, 0x26, 0x1a, 0xd3, 0x7f,
-	0xde, 0xb2, 0x6e, 0x4e, 0xfa, 0x39, 0x86, 0x8f, 0xac, 0xec, 0x18, 0x64,
-	0x7c, 0xd9, 0xff, 0xdd, 0xc9, 0x2b, 0xb0, 0x9d, 0x73, 0xb4, 0x95, 0xf3,
-	0xb7, 0x3c, 0x94, 0x89, 0x16, 0x41, 0x37, 0xcf, 0x21, 0x82, 0xa5, 0x69,
-	0x83, 0x73, 0x1a, 0xc1, 0x92, 0x64, 0x8d, 0x36, 0x8c, 0xf9, 0x88, 0xfa,
-	0xb2, 0x36, 0xbd, 0x83, 0xe3, 0x6d, 0x0d, 0x34, 0xa3, 0x94, 0x36, 0x92,
-	0x5a, 0x14, 0x46, 0x03, 0xfb, 0x5f, 0xf1, 0x17, 0xf4, 0x7f, 0x2b, 0xfb,
-	0x7f, 0x97, 0xfd, 0x67, 0xec, 0xfe, 0xe1, 0xbc, 0x89, 0xe7, 0x6e, 0xda,
-	0xe3, 0xf6, 0x94, 0xd3, 0xb9, 0x3c, 0xe9, 0xc5, 0xb6, 0x94, 0x49, 0x9b,
-	0x93, 0x5b, 0x3e, 0x6c, 0x19, 0x9c, 0x89, 0xad, 0x83, 0xba, 0xef, 0x79,
-	0xfe, 0xde, 0x34, 0x72, 0x05, 0x36, 0x0f, 0x2a, 0xd8, 0x6f, 0x5c, 0x81,
-	0x2e, 0xfe, 0xde, 0x3b, 0x38, 0x0b, 0x8f, 0x0e, 0x3a, 0x10, 0xae, 0xba,
-	0x74, 0x1c, 0x93, 0x8e, 0x2b, 0x10, 0x1f, 0xf1, 0xa3, 0x2b, 0xf1, 0xa2,
-	0xad, 0xc3, 0xd2, 0xc8, 0xff, 0x9b, 0xf7, 0x63, 0xfa, 0x8e, 0x1f, 0xab,
-	0x13, 0x1a, 0xba, 0x92, 0x0e, 0xb1, 0x4b, 0xfe, 0xfd, 0x92, 0xf7, 0x34,
-	0x6c, 0x4a, 0xe7, 0xeb, 0x8b, 0x9f, 0xf9, 0xd1, 0x90, 0x98, 0xa0, 0x9f,
-	0xd4, 0xd3, 0x47, 0x4c, 0x7c, 0x37, 0x5d, 0x87, 0x7f, 0x4a, 0x07, 0xf1,
-	0x8f, 0xd4, 0xc3, 0xb7, 0xd2, 0x7e, 0x1c, 0x49, 0xcf, 0xc4, 0x53, 0x69,
-	0x1f, 0xbe, 0x49, 0xfd, 0x3f, 0x99, 0x6e, 0xa6, 0xed, 0x6a, 0x38, 0x9c,
-	0x16, 0xfd, 0x15, 0x50, 0xde, 0x62, 0x6c, 0x1a, 0xac, 0x09, 0x9e, 0xa4,
-	0x6d, 0xfc, 0xa3, 0x79, 0x13, 0x32, 0x95, 0xf5, 0xb6, 0x4d, 0x6d, 0xe3,
-	0xf5, 0xed, 0x83, 0x35, 0xd1, 0x2b, 0x15, 0xcb, 0x52, 0x43, 0xb5, 0xe1,
-	0x13, 0xaa, 0x8a, 0x49, 0xaf, 0xee, 0xcf, 0xa8, 0xba, 0x3f, 0x0a, 0x17,
-	0x12, 0xb4, 0xed, 0x78, 0xb5, 0x3e, 0x14, 0xa7, 0x4d, 0x78, 0x8d, 0x7d,
-	0x40, 0x99, 0xee, 0x8f, 0xab, 0x6e, 0x6c, 0x4d, 0xea, 0x7b, 0xe3, 0xaa,
-	0x07, 0xf1, 0x74, 0x31, 0xfe, 0x6d, 0x50, 0xef, 0x89, 0xab, 0x9f, 0x45,
-	0xbc, 0xd2, 0xb2, 0xbe, 0x19, 0x42, 0xfb, 0xf4, 0x08, 0xa2, 0xd5, 0x11,
-	0xc4, 0x66, 0x45, 0xbc, 0x48, 0x26, 0x81, 0x77, 0x7b, 0x0d, 0xdf, 0xbf,
-	0x28, 0xcd, 0xf8, 0x6a, 0xb3, 0xee, 0xf7, 0xab, 0xb5, 0xf1, 0x61, 0x75,
-	0x11, 0x5d, 0x12, 0x7e, 0x5f, 0x64, 0x19, 0x3a, 0xec, 0x6b, 0x0a, 0x34,
-	0xc3, 0x83, 0x4d, 0xc9, 0xeb, 0x10, 0xf3, 0xd6, 0xb4, 0xec, 0x54, 0x6b,
-	0xce, 0x9b, 0xaa, 0x3e, 0xd1, 0xac, 0x5a, 0xd6, 0x07, 0x0b, 0xdf, 0xb5,
-	0xfc, 0xd3, 0x2c, 0x6b, 0xc1, 0x42, 0xe9, 0xd3, 0x8f, 0x8a, 0x88, 0x89,
-	0x95, 0xf6, 0x1c, 0x14, 0xe3, 0xec, 0x60, 0x25, 0xfb, 0xd0, 0xf0, 0xcf,
-	0xd7, 0xea, 0xc1, 0xb5, 0x6a, 0x31, 0xde, 0x1a, 0x29, 0xc6, 0x69, 0x8e,
-	0xe7, 0x97, 0x83, 0x3e, 0xfc, 0x7a, 0xd0, 0xb2, 0xbe, 0x68, 0xfe, 0x35,
-	0x06, 0x2a, 0xfb, 0xf1, 0x4f, 0xe3, 0x5e, 0xfc, 0x1b, 0x75, 0x7b, 0x26,
-	0x11, 0x7d, 0xa0, 0x0a, 0x7a, 0x74, 0x5c, 0x39, 0x79, 0x67, 0x19, 0x6a,
-	0x9b, 0xcb, 0x14, 0xbd, 0x69, 0x07, 0x74, 0xdf, 0x95, 0x8a, 0x17, 0xe7,
-	0x52, 0x1a, 0x7e, 0x9a, 0xaa, 0x09, 0xff, 0x80, 0x7d, 0xfe, 0x87, 0xf9,
-	0xb4, 0x95, 0x99, 0x26, 0x7a, 0x13, 0x1d, 0x51, 0xcf, 0x49, 0xea, 0x39,
-	0x49, 0x3d, 0x27, 0xa9, 0x67, 0xca, 0x70, 0x24, 0x49, 0x3d, 0x53, 0x77,
-	0xdf, 0xa4, 0x4d, 0x3c, 0x99, 0xa4, 0x8e, 0x93, 0x32, 0x47, 0x61, 0xfa,
-	0xe7, 0xa7, 0xf0, 0xf7, 0xf6, 0xdc, 0xbd, 0x6c, 0xfd, 0x37, 0xaf, 0x8c,
-	0xe9, 0xfe, 0x69, 0x59, 0xfc, 0x91, 0xb1, 0xbd, 0x64, 0xc5, 0x34, 0x19,
-	0x97, 0x8c, 0xcf, 0xd6, 0x9f, 0xbf, 0x5d, 0xf9, 0xaa, 0x82, 0x62, 0xcb,
-	0xda, 0x65, 0xe6, 0xee, 0x7b, 0xf3, 0xe3, 0xfb, 0x8c, 0x92, 0xb5, 0x8b,
-	0x7f, 0x72, 0x53, 0xdf, 0xc1, 0xa8, 0xba, 0x88, 0xe7, 0x7a, 0x3c, 0x8a,
-	0x9b, 0x0a, 0x2f, 0x3d, 0xbf, 0xb6, 0x5a, 0xe6, 0xc3, 0x7f, 0xe1, 0x9c,
-	0xf6, 0x64, 0xf7, 0xf7, 0x45, 0x9e, 0xcb, 0x58, 0x04, 0x53, 0xc5, 0x06,
-	0xbc, 0xb4, 0x97, 0x45, 0xb9, 0x7b, 0x88, 0xab, 0x91, 0x76, 0x34, 0xd7,
-	0xef, 0xb5, 0xfb, 0x28, 0xe8, 0x13, 0xbb, 0x57, 0xf0, 0xee, 0x75, 0x0a,
-	0x4e, 0x84, 0x0c, 0xda, 0xcc, 0x10, 0xfd, 0x1a, 0x28, 0xec, 0x83, 0xdb,
-	0x13, 0x89, 0x20, 0xd1, 0x0b, 0x77, 0x51, 0x24, 0x8c, 0xf9, 0xbd, 0x35,
-	0xeb, 0xce, 0x42, 0x0f, 0xf6, 0x2a, 0x7a, 0x33, 0x50, 0x6b, 0x8e, 0x51,
-	0x8f, 0x57, 0x2a, 0xba, 0xbf, 0x40, 0x81, 0x5b, 0x61, 0xb9, 0x40, 0x6a,
-	0x08, 0x5b, 0xd3, 0xf2, 0x3b, 0x0c, 0x23, 0xf5, 0xeb, 0x7c, 0x5f, 0xb4,
-	0xeb, 0x76, 0xda, 0xf5, 0x59, 0x8e, 0x5d, 0xf7, 0x13, 0x1f, 0xdd, 0xae,
-	0xc8, 0x3a, 0x1c, 0x48, 0xc0, 0x5d, 0x10, 0xd9, 0x80, 0xe7, 0x12, 0x1f,
-	0x57, 0xe7, 0xcb, 0x29, 0x2c, 0xe7, 0x4f, 0x4d, 0x95, 0xe5, 0x0d, 0x2b,
-	0xea, 0xcd, 0xca, 0x52, 0xdc, 0x37, 0x84, 0x1d, 0x49, 0xa9, 0x1b, 0xb1,
-	0xeb, 0x3a, 0xd9, 0x47, 0x77, 0xa2, 0xa6, 0xe9, 0x66, 0x45, 0x0f, 0x3f,
-	0x8e, 0xda, 0xe8, 0x3b, 0x9c, 0xc3, 0x2e, 0xe8, 0xe7, 0xd7, 0x21, 0x2b,
-	0xcb, 0xbc, 0x54, 0x56, 0x8e, 0xc5, 0x29, 0x28, 0xb7, 0x27, 0xe1, 0xf1,
-	0x19, 0x55, 0x39, 0x5f, 0x84, 0x72, 0x0b, 0xe7, 0x4f, 0x35, 0xfc, 0xb8,
-	0x85, 0x36, 0xb4, 0x61, 0x97, 0x85, 0x4d, 0xa1, 0x4a, 0xfa, 0x5b, 0x33,
-	0xca, 0x88, 0x87, 0x1b, 0x35, 0x44, 0xcb, 0x23, 0x61, 0xe5, 0xd6, 0xf4,
-	0xce, 0x9c, 0xfe, 0x9f, 0xae, 0xa4, 0x7c, 0x4a, 0x63, 0xf2, 0xf2, 0xeb,
-	0x1f, 0xe5, 0xc7, 0x77, 0xd9, 0xf5, 0xb9, 0x05, 0x9f, 0x5c, 0xbe, 0x56,
-	0x1b, 0x81, 0xc2, 0x78, 0x51, 0x44, 0xfd, 0xea, 0x8c, 0xd2, 0xd1, 0xa0,
-	0xcb, 0xbe, 0xe6, 0xc0, 0x90, 0x33, 0xea, 0x73, 0xe0, 0xf7, 0x56, 0x74,
-	0x95, 0x5c, 0x2b, 0x46, 0xac, 0xb9, 0xd6, 0xe7, 0x44, 0x6d, 0x78, 0x33,
-	0xfd, 0x6d, 0x72, 0x55, 0x03, 0xef, 0x05, 0xcc, 0x93, 0xa8, 0xf1, 0x6f,
-	0x86, 0xfc, 0xfe, 0x90, 0x36, 0xd2, 0x20, 0x75, 0x59, 0x46, 0x6c, 0x4e,
-	0xd7, 0x4e, 0xc2, 0x8b, 0xcd, 0xb4, 0xbf, 0xc2, 0x88, 0x6e, 0x2e, 0x73,
-	0x38, 0x71, 0x88, 0x38, 0xec, 0x30, 0x7a, 0x50, 0xc8, 0x31, 0x32, 0x3e,
-	0xe2, 0xf1, 0x04, 0xf0, 0x62, 0xbf, 0x85, 0x86, 0x90, 0x07, 0x4b, 0x6c,
-	0xdb, 0x3c, 0xaa, 0xdc, 0x98, 0xfc, 0xd8, 0x1a, 0x72, 0x16, 0x45, 0xd5,
-	0x48, 0xc0, 0x77, 0x9a, 0xd1, 0xbc, 0x20, 0x52, 0xab, 0x39, 0x11, 0x57,
-	0x9a, 0xd2, 0xdd, 0xca, 0xf2, 0x74, 0x8f, 0xb2, 0xc4, 0xc6, 0x9c, 0xa3,
-	0xca, 0xd2, 0xb4, 0x07, 0xa9, 0x7e, 0x05, 0x3b, 0x42, 0x94, 0xab, 0x3a,
-	0x6b, 0xc7, 0xe9, 0x7e, 0x95, 0x18, 0xf9, 0x2e, 0x31, 0x52, 0x0f, 0x83,
-	0x7d, 0x3f, 0x9d, 0xa8, 0xc4, 0x51, 0x62, 0xe1, 0x4f, 0x52, 0xe5, 0x2a,
-	0x8a, 0xaf, 0xc0, 0x8f, 0x47, 0xca, 0x30, 0x36, 0x38, 0x8b, 0xbf, 0xeb,
-	0xf0, 0xca, 0x88, 0x65, 0x75, 0x9b, 0x96, 0x75, 0xc0, 0x3c, 0xaa, 0x34,
-	0xb0, 0xcf, 0xa8, 0x33, 0x1e, 0x2d, 0x8c, 0x04, 0xcc, 0xad, 0xec, 0xd3,
-	0x11, 0x89, 0x2b, 0x51, 0xf6, 0x77, 0x23, 0xfb, 0x5b, 0x9a, 0xeb, 0x2f,
-	0xdb, 0xaf, 0xc8, 0x22, 0xf5, 0xf2, 0x75, 0xc2, 0xac, 0x03, 0x1c, 0x4c,
-	0x04, 0x82, 0xf9, 0x7a, 0x4b, 0x59, 0xe7, 0xc6, 0x0b, 0x75, 0x80, 0xe1,
-	0x44, 0x90, 0x73, 0x2a, 0xb6, 0xee, 0x67, 0xec, 0xf9, 0x1a, 0x9c, 0x46,
-	0x3d, 0x5a, 0x87, 0x85, 0x47, 0x84, 0xd5, 0xec, 0x3c, 0x49, 0xfc, 0x74,
-	0xdb, 0x31, 0x6b, 0xd2, 0x21, 0x71, 0x34, 0x88, 0x5e, 0xfa, 0x75, 0x57,
-	0x52, 0x6c, 0xbc, 0xfe, 0xcb, 0x89, 0x80, 0x82, 0x6f, 0x04, 0x32, 0xcd,
-	0xa5, 0x28, 0xc7, 0xba, 0x90, 0xd8, 0xa6, 0xf9, 0xe5, 0xe7, 0x0c, 0x3d,
-	0xbc, 0x42, 0xe1, 0x9c, 0x05, 0xf4, 0xa6, 0xa5, 0x0a, 0x10, 0x18, 0x03,
-	0xce, 0xa4, 0xca, 0xb1, 0xda, 0x74, 0x40, 0xad, 0x08, 0xa2, 0x27, 0x3d,
-	0x15, 0xd7, 0x4d, 0xe2, 0xb4, 0xb4, 0x17, 0xa4, 0x5f, 0x97, 0x60, 0x99,
-	0x96, 0xb5, 0x69, 0x37, 0xdb, 0x76, 0x07, 0x32, 0x41, 0x95, 0xf1, 0xea,
-	0x10, 0x2f, 0x9c, 0x64, 0x5c, 0x6a, 0x30, 0x5c, 0x68, 0xd3, 0xca, 0xd1,
-	0x60, 0xfe, 0xd6, 0x5a, 0xb6, 0x4a, 0xee, 0x5d, 0xc4, 0xf7, 0x42, 0xf6,
-	0xfb, 0xb6, 0xa1, 0xfb, 0x47, 0x79, 0x92, 0x49, 0x65, 0xaf, 0xc7, 0x19,
-	0x73, 0x36, 0xb1, 0xdd, 0x2d, 0x6c, 0x77, 0xad, 0xa6, 0x47, 0xe3, 0x17,
-	0xca, 0x65, 0x82, 0x0e, 0xe8, 0x9a, 0x94, 0x6d, 0x64, 0xbb, 0xab, 0xd9,
-	0x6e, 0x8f, 0x26, 0xf2, 0xfd, 0xd6, 0x5a, 0xbb, 0x4a, 0xee, 0x65, 0xed,
-	0x23, 0xdb, 0x6e, 0xbd, 0xb4, 0x6b, 0x8e, 0xe6, 0xfa, 0x3a, 0x91, 0x40,
-	0xbf, 0x23, 0xc2, 0x18, 0x59, 0x1f, 0xf0, 0x77, 0x31, 0x5e, 0x36, 0x32,
-	0x76, 0x64, 0x6d, 0x62, 0x6a, 0xbc, 0x42, 0xfc, 0x62, 0x19, 0xb9, 0x26,
-	0xe5, 0xc4, 0xd6, 0x26, 0xa9, 0x67, 0x89, 0x2f, 0x3e, 0xea, 0x57, 0xb0,
-	0xc5, 0x89, 0xc3, 0x09, 0xe2, 0x3f, 0xbe, 0x46, 0xbb, 0xf3, 0xa3, 0x39,
-	0x5d, 0x83, 0xb6, 0x5d, 0x8c, 0x63, 0x66, 0x05, 0x6d, 0x3d, 0x6b, 0x6f,
-	0xcb, 0xd8, 0xf6, 0xa4, 0xdd, 0x76, 0x5c, 0x69, 0x4e, 0xd7, 0x6a, 0x15,
-	0x8c, 0x99, 0xc7, 0x2f, 0x60, 0xe7, 0xec, 0x68, 0x71, 0x24, 0xd0, 0xb4,
-	0x9e, 0x93, 0xe4, 0x66, 0x7c, 0xfb, 0xce, 0xbc, 0x6e, 0xda, 0x45, 0x0f,
-	0xed, 0x30, 0x3b, 0xbf, 0x4d, 0x62, 0x70, 0xc4, 0x38, 0xa8, 0x35, 0x58,
-	0xbb, 0x4b, 0xfe, 0x93, 0x6b, 0xd4, 0x3f, 0xca, 0x6b, 0x35, 0x58, 0x3d,
-	0xfc, 0x0d, 0xda, 0x99, 0xee, 0x13, 0x3b, 0xec, 0xba, 0x20, 0x97, 0xc8,
-	0x24, 0xb2, 0x89, 0x4c, 0xff, 0x37, 0xcb, 0xcd, 0xa4, 0x7e, 0x04, 0x1b,
-	0x2b, 0x29, 0xcf, 0x36, 0xf2, 0x99, 0xa3, 0xca, 0x67, 0x29, 0x4f, 0xc6,
-	0xe5, 0xc5, 0x63, 0x49, 0x91, 0x47, 0x89, 0xce, 0x88, 0xcc, 0xc4, 0xf9,
-	0x64, 0x20, 0xfe, 0x34, 0x44, 0xb6, 0x6e, 0xa5, 0x45, 0xea, 0x27, 0x7b,
-	0x78, 0x2f, 0x2f, 0x23, 0xb4, 0x72, 0x5b, 0xb6, 0xac, 0x4c, 0xb7, 0x72,
-	0xae, 0x5d, 0xc6, 0xfd, 0xa5, 0x28, 0x73, 0xd2, 0xd6, 0xa4, 0xed, 0x9f,
-	0x59, 0x51, 0x6d, 0x13, 0xaf, 0x79, 0x39, 0x4f, 0x6e, 0xc6, 0x75, 0x3d,
-	0x78, 0x8b, 0x43, 0x69, 0xf6, 0x48, 0xbc, 0xa6, 0x7d, 0xa6, 0x52, 0x4e,
-	0x3c, 0x93, 0x58, 0xba, 0xb4, 0xc4, 0xb8, 0x1a, 0xdf, 0x18, 0xf1, 0x61,
-	0x84, 0x73, 0xfb, 0x62, 0x42, 0xe2, 0xeb, 0x4c, 0x3c, 0x91, 0xf2, 0xe0,
-	0x85, 0x84, 0x1f, 0x8f, 0x33, 0xfe, 0x4c, 0x24, 0x0c, 0x1c, 0x4a, 0x79,
-	0xf1, 0x3c, 0xed, 0x79, 0x34, 0xe5, 0xa3, 0xbd, 0xd4, 0x61, 0x38, 0xd5,
-	0x6c, 0x8f, 0xe1, 0xd9, 0xc4, 0xab, 0x32, 0xd6, 0xa0, 0x8c, 0x75, 0x8b,
-	0x3d, 0xd6, 0x7c, 0x9c, 0x9f, 0x79, 0x61, 0x1e, 0x4e, 0x25, 0x6c, 0x1c,
-	0xe8, 0x59, 0xe6, 0x90, 0x79, 0xa0, 0xcd, 0x0e, 0x08, 0x16, 0xe8, 0xfd,
-	0x71, 0x58, 0xd8, 0x6f, 0xce, 0xa0, 0xff, 0xf7, 0x50, 0x5e, 0xea, 0x94,
-	0xe3, 0x87, 0xab, 0x2c, 0x5a, 0x1a, 0x09, 0xc4, 0x7a, 0xa9, 0x77, 0x67,
-	0x44, 0xf4, 0x90, 0xd5, 0xfb, 0x8a, 0xf4, 0x51, 0x45, 0xb8, 0xda, 0x95,
-	0x03, 0x71, 0xab, 0xc4, 0x10, 0x7d, 0x07, 0x88, 0xb3, 0xc0, 0xfc, 0xfd,
-	0x4e, 0x8e, 0x6f, 0x25, 0xc7, 0x6c, 0xa2, 0xc0, 0xa8, 0xd5, 0x2a, 0x29,
-	0xfb, 0xf1, 0x3f, 0x88, 0x81, 0xa2, 0xa3, 0x35, 0xb9, 0xf9, 0x2a, 0x77,
-	0x50, 0x5e, 0x3f, 0x90, 0x9f, 0x17, 0xcb, 0xda, 0x69, 0xe6, 0xe7, 0xa6,
-	0x1a, 0xfe, 0x4a, 0x3d, 0x3e, 0x44, 0x8b, 0x18, 0x49, 0x54, 0x21, 0xae,
-	0xa9, 0xb9, 0xb6, 0xa3, 0x4a, 0x01, 0xf3, 0x07, 0x8c, 0x8b, 0xef, 0x97,
-	0x22, 0xea, 0x94, 0xfa, 0x88, 0x16, 0x44, 0x02, 0xc1, 0xb9, 0xea, 0x54,
-	0x9b, 0x11, 0x1c, 0x90, 0xbe, 0xe2, 0x94, 0xf5, 0x52, 0x2c, 0x18, 0x49,
-	0xe4, 0x71, 0xe3, 0x3f, 0x53, 0xcf, 0x4b, 0x1f, 0x9b, 0xaa, 0x53, 0x91,
-	0x53, 0xf4, 0xaa, 0xa2, 0x75, 0x50, 0xf4, 0xe7, 0xc4, 0x4a, 0x73, 0x51,
-	0x4e, 0xe6, 0x99, 0x68, 0x4b, 0xa8, 0xd8, 0x30, 0xc8, 0xbe, 0x52, 0x0a,
-	0x36, 0x87, 0x96, 0x60, 0xc8, 0x6b, 0xd3, 0x45, 0xb4, 0x26, 0x1a, 0x69,
-	0x63, 0xc4, 0x99, 0x71, 0x3b, 0x7e, 0xda, 0xfe, 0x33, 0x9b, 0x3e, 0xb1,
-	0x2c, 0xfd, 0x20, 0xd6, 0x26, 0x03, 0xfe, 0x93, 0x78, 0x10, 0x6d, 0x69,
-	0x17, 0x62, 0xc3, 0x1e, 0x74, 0xb2, 0x6f, 0xb5, 0x4f, 0xfc, 0x49, 0x43,
-	0xe7, 0xe8, 0x89, 0x17, 0x54, 0xda, 0x67, 0xe7, 0xa8, 0x97, 0xc7, 0x34,
-	0x1e, 0x6e, 0x3c, 0xc4, 0xe3, 0x28, 0xe7, 0xbf, 0x83, 0x18, 0x9c, 0x4e,
-	0x98, 0xb8, 0x9f, 0x32, 0x8d, 0x27, 0xea, 0xb1, 0x91, 0xf2, 0x8d, 0x25,
-	0x1c, 0xf0, 0x4f, 0x0b, 0xe3, 0x3e, 0xea, 0xf2, 0xc9, 0x44, 0x58, 0x79,
-	0x80, 0xff, 0x0f, 0x51, 0x26, 0xc9, 0x47, 0xd6, 0xd1, 0x0e, 0xa2, 0xd3,
-	0x68, 0x27, 0x6a, 0xad, 0xc3, 0x9e, 0x07, 0x88, 0x7f, 0x5c, 0x3e, 0x57,
-	0xba, 0x16, 0x43, 0x7e, 0xbe, 0x80, 0xa1, 0x14, 0x62, 0xee, 0x48, 0x5d,
-	0x63, 0x41, 0x6f, 0xeb, 0x86, 0xc2, 0x48, 0xfb, 0x43, 0x3f, 0xad, 0x9f,
-	0x85, 0x93, 0x9c, 0x13, 0xa7, 0x6d, 0xe3, 0x51, 0xc5, 0x65, 0x18, 0xb6,
-	0x2f, 0xab, 0xe3, 0xed, 0xb9, 0xbc, 0x4a, 0x97, 0x38, 0xc6, 0x3e, 0x44,
-	0x6f, 0xa2, 0x0b, 0xd1, 0xc3, 0x71, 0x6b, 0xc8, 0xf6, 0x77, 0xf1, 0x39,
-	0x27, 0x75, 0xf4, 0x5d, 0xc6, 0x6f, 0xd1, 0x85, 0x94, 0xdb, 0xca, 0xb6,
-	0x44, 0x1e, 0x3b, 0x16, 0xfa, 0xfe, 0xd0, 0x76, 0xa6, 0xca, 0x53, 0x87,
-	0xed, 0x7b, 0x0c, 0xec, 0xd8, 0x53, 0x4b, 0xbb, 0xfb, 0xa5, 0xe5, 0xaf,
-	0x18, 0x60, 0xdd, 0xa9, 0xb2, 0x08, 0x2f, 0x40, 0xae, 0x5d, 0x69, 0x73,
-	0x13, 0xef, 0x1d, 0xa6, 0xad, 0x49, 0xbb, 0x96, 0xb5, 0xe5, 0x42, 0xdc,
-	0x28, 0x88, 0x16, 0x31, 0x6e, 0x1c, 0x4a, 0x04, 0xc2, 0x2f, 0xd8, 0xb1,
-	0xcd, 0x49, 0xdb, 0x90, 0xf9, 0xef, 0xb6, 0xe7, 0x7e, 0xd9, 0x85, 0xb9,
-	0x9f, 0xbc, 0xc0, 0x91, 0xfa, 0x93, 0x53, 0x7d, 0x2a, 0x3b, 0xef, 0xce,
-	0x3e, 0xbd, 0xc7, 0xb6, 0xd3, 0x94, 0xe0, 0x9f, 0x03, 0x8e, 0x01, 0xce,
-	0xb3, 0x79, 0x15, 0xc7, 0x5f, 0xc9, 0x78, 0x52, 0xc0, 0x83, 0x79, 0xe4,
-	0xf0, 0xa7, 0x50, 0x3c, 0x90, 0xb1, 0x8a, 0xf8, 0xbb, 0x29, 0x14, 0x08,
-	0x17, 0x29, 0x37, 0xe0, 0xee, 0x61, 0x07, 0x0a, 0x06, 0x14, 0x3c, 0x6b,
-	0xd6, 0xe5, 0xec, 0x43, 0xe6, 0xfb, 0x2a, 0xdb, 0x3e, 0xe6, 0x8c, 0xcb,
-	0x7c, 0xcb, 0x1c, 0x7b, 0xe0, 0xeb, 0x53, 0xe0, 0x21, 0x6e, 0x94, 0x18,
-	0x32, 0xd7, 0x1a, 0xca, 0xfb, 0x64, 0xae, 0x49, 0x1b, 0x77, 0x87, 0xb1,
-	0x91, 0xf6, 0x50, 0xba, 0xfb, 0x7a, 0xdc, 0xc7, 0x72, 0x1b, 0x78, 0x6f,
-	0xc3, 0x68, 0x25, 0x0f, 0x2f, 0x8f, 0x69, 0x3c, 0xea, 0x71, 0xef, 0x70,
-	0x0d, 0xa2, 0x95, 0x7a, 0xd0, 0xaf, 0x3a, 0x50, 0x39, 0x20, 0x3a, 0x55,
-	0xb1, 0x72, 0x81, 0x02, 0xf3, 0xea, 0x42, 0xa8, 0x73, 0x3f, 0xc9, 0x37,
-	0xff, 0x9c, 0xac, 0x3f, 0x9a, 0x32, 0x87, 0x6e, 0x8e, 0xfd, 0x9f, 0xed,
-	0x39, 0x9c, 0x33, 0x2e, 0x7d, 0x48, 0x2c, 0xb5, 0xe7, 0xf1, 0x4f, 0xf8,
-	0xfe, 0x73, 0x9c, 0x8f, 0x2e, 0x96, 0xf9, 0xc3, 0xf9, 0xc5, 0x85, 0xf9,
-	0x9d, 0xca, 0x49, 0x25, 0xae, 0xeb, 0xe1, 0x21, 0x9b, 0xc3, 0xf8, 0x99,
-	0xcf, 0xe9, 0x71, 0xd1, 0x39, 0x39, 0x8b, 0x5b, 0x35, 0xe0, 0x2f, 0x30,
-	0xee, 0xc0, 0x3d, 0x9c, 0xa7, 0x03, 0x09, 0x75, 0xa9, 0x0b, 0xea, 0x4c,
-	0x17, 0x13, 0xdb, 0x11, 0x53, 0xc7, 0xba, 0x61, 0xe6, 0x4a, 0xc3, 0xa5,
-	0xe8, 0xd2, 0x14, 0xf7, 0xf6, 0xba, 0x45, 0x92, 0xf3, 0xfa, 0xcb, 0x0d,
-	0xa8, 0x25, 0x8c, 0xef, 0x3b, 0x34, 0x38, 0x0b, 0x0c, 0x45, 0x4d, 0xd4,
-	0x35, 0x22, 0x5e, 0x01, 0x67, 0x99, 0x01, 0x85, 0x39, 0x2d, 0x7a, 0x35,
-	0x08, 0xb6, 0x44, 0x0b, 0x8c, 0x07, 0x71, 0x4f, 0x12, 0x56, 0x71, 0x84,
-	0xf9, 0x4e, 0xc4, 0x20, 0x87, 0x0d, 0xf8, 0x0a, 0x94, 0x07, 0xb1, 0x9a,
-	0xbc, 0x61, 0xcd, 0xb0, 0xc8, 0xe1, 0x21, 0x9f, 0x30, 0xfc, 0xad, 0x60,
-	0x8e, 0xdd, 0xac, 0x07, 0x27, 0x99, 0x67, 0xae, 0xa6, 0xee, 0x47, 0x12,
-	0x0f, 0xa2, 0x21, 0x79, 0xdc, 0xf2, 0x90, 0x27, 0x16, 0x18, 0x35, 0xe7,
-	0xbb, 0x10, 0xa3, 0x0f, 0x0b, 0xff, 0x69, 0xc3, 0x43, 0xf4, 0xbf, 0x74,
-	0x42, 0x7d, 0x86, 0xec, 0x01, 0x1d, 0xa3, 0xeb, 0x71, 0xff, 0xe8, 0x4c,
-	0xfa, 0xea, 0x06, 0xfa, 0x2a, 0xb9, 0x50, 0xff, 0x0d, 0xb8, 0x6f, 0xf8,
-	0x06, 0xdc, 0xbb, 0xcb, 0x08, 0x6e, 0xa0, 0xae, 0xd7, 0x0c, 0x33, 0x10,
-	0x4e, 0x93, 0x76, 0xf3, 0xba, 0x12, 0x3e, 0x48, 0x5d, 0xe4, 0xf4, 0x94,
-	0x41, 0x9e, 0xa3, 0xfc, 0xb3, 0xc5, 0x4b, 0xf1, 0x82, 0x7a, 0xc5, 0xbf,
-	0xb7, 0xee, 0xfb, 0xcc, 0xbd, 0x45, 0x76, 0x44, 0x67, 0x18, 0xaf, 0x5a,
-	0x8f, 0x6a, 0x0a, 0x0a, 0x22, 0x88, 0xcf, 0xae, 0x7f, 0xd9, 0x7a, 0x6c,
-	0x95, 0x5c, 0xbf, 0xd5, 0x89, 0x62, 0x95, 0xd7, 0xa4, 0xcd, 0x1d, 0x32,
-	0x47, 0x44, 0xda, 0x4f, 0x6a, 0x33, 0x63, 0xf5, 0x5d, 0x28, 0x4f, 0xde,
-	0x47, 0xac, 0x7d, 0x3a, 0xe1, 0x45, 0x4f, 0x32, 0xcb, 0x9d, 0x6e, 0x4f,
-	0x0b, 0x67, 0x72, 0xa3, 0xb8, 0x57, 0xe2, 0x46, 0x14, 0xeb, 0xf9, 0xbb,
-	0xa8, 0x57, 0x6f, 0x8e, 0x83, 0xc9, 0xbc, 0xd1, 0xc8, 0xb9, 0xa0, 0xbd,
-	0xf6, 0x3a, 0x50, 0x64, 0x34, 0x65, 0x6d, 0xb5, 0x77, 0x85, 0x8d, 0x4b,
-	0x65, 0xbd, 0xdd, 0x36, 0x2e, 0x95, 0xb2, 0x9e, 0x60, 0x92, 0xa7, 0x77,
-	0x15, 0xed, 0x75, 0x26, 0x4a, 0x7a, 0x5b, 0x70, 0x2f, 0xe7, 0x78, 0x2d,
-	0x79, 0xf6, 0x09, 0xb3, 0x3c, 0xc7, 0x3f, 0x9b, 0x70, 0x77, 0x32, 0x8a,
-	0xd6, 0x64, 0x4d, 0xf4, 0xb4, 0xac, 0x25, 0xb9, 0xb2, 0xd8, 0x19, 0xad,
-	0x16, 0x5d, 0x3c, 0x97, 0xc3, 0x08, 0xbd, 0x29, 0xcb, 0xd9, 0x74, 0xcd,
-	0xaf, 0xe4, 0x65, 0xef, 0x46, 0x8c, 0xf9, 0xc5, 0xec, 0x48, 0x33, 0xac,
-	0xa4, 0xc8, 0x1d, 0xb7, 0x7c, 0xcc, 0x19, 0x3d, 0x11, 0xbd, 0x7d, 0xb1,
-	0xc3, 0xe8, 0xf8, 0xb1, 0x12, 0xc4, 0xad, 0x94, 0xa1, 0xa4, 0xb7, 0x13,
-	0xaf, 0x84, 0x74, 0xdf, 0xb7, 0x15, 0xfd, 0xfc, 0x06, 0xfc, 0x18, 0x3f,
-	0xe7, 0xb5, 0x82, 0xde, 0x09, 0x3c, 0x96, 0x7e, 0x1d, 0x67, 0x29, 0xab,
-	0xda, 0xfb, 0xb1, 0xb5, 0xcc, 0x20, 0x18, 0x14, 0xbb, 0x95, 0xb7, 0xd3,
-	0x53, 0x6d, 0xf1, 0x06, 0xac, 0xde, 0x25, 0xf6, 0xa7, 0x07, 0xe3, 0xa0,
-	0x7c, 0x66, 0x99, 0x60, 0x9c, 0xc4, 0x1f, 0xca, 0xdf, 0x4c, 0xd9, 0x2c,
-	0xfa, 0x07, 0xed, 0xc0, 0x1e, 0xc3, 0x43, 0x36, 0x0e, 0x3a, 0xfb, 0xe4,
-	0xc8, 0xeb, 0x39, 0xa2, 0xb4, 0x8e, 0x5e, 0x53, 0x8c, 0x62, 0x5f, 0xce,
-	0x0f, 0xb2, 0x6b, 0x0a, 0x17, 0xeb, 0xfe, 0xd2, 0x1a, 0xf1, 0x5e, 0x5a,
-	0xb7, 0x8c, 0x39, 0x56, 0x39, 0xc7, 0xf3, 0x5e, 0x6f, 0xdc, 0x2a, 0xce,
-	0x8e, 0xa5, 0xe9, 0x55, 0x45, 0x6c, 0x32, 0x48, 0xee, 0xde, 0x89, 0xab,
-	0x42, 0x7a, 0xcb, 0xb7, 0x15, 0x29, 0xab, 0x87, 0x37, 0x28, 0xf9, 0x7e,
-	0x7e, 0x84, 0xd3, 0x23, 0xd2, 0x87, 0xf4, 0x35, 0xc1, 0x9c, 0xeb, 0x52,
-	0x7f, 0x4a, 0xd9, 0xf3, 0xa9, 0x9b, 0x43, 0xe4, 0x75, 0x2b, 0x38, 0xcc,
-	0x92, 0x5e, 0x19, 0x93, 0xa9, 0xdc, 0x3b, 0x2a, 0xf3, 0xba, 0x40, 0x59,
-	0x4f, 0x2c, 0x29, 0xea, 0xad, 0x57, 0xee, 0x21, 0x96, 0x14, 0xee, 0xac,
-	0x51, 0xee, 0xb6, 0x6d, 0xbe, 0x0a, 0x23, 0xfd, 0xd7, 0x28, 0x6d, 0xc3,
-	0xa2, 0x03, 0x37, 0xc7, 0x3e, 0x8d, 0x63, 0xf7, 0xa2, 0x8f, 0xfe, 0xfb,
-	0x4a, 0x6f, 0x9d, 0x72, 0x1f, 0x7d, 0xa3, 0x73, 0x97, 0x8a, 0xc9, 0x2a,
-	0x85, 0x78, 0x47, 0xfe, 0x6b, 0xf8, 0x94, 0xd6, 0xe1, 0xef, 0x3b, 0x25,
-	0xbe, 0x64, 0x70, 0x03, 0x5a, 0x79, 0x6f, 0xa9, 0xe9, 0x42, 0x46, 0xab,
-	0xd5, 0x34, 0xac, 0xc0, 0xea, 0xe4, 0x2a, 0xb4, 0x25, 0x8b, 0xc9, 0x73,
-	0x65, 0xbc, 0x79, 0xb9, 0xf3, 0xf3, 0xf8, 0x20, 0x5a, 0x92, 0x88, 0xcf,
-	0x88, 0x04, 0x3a, 0x66, 0x38, 0xe8, 0xd2, 0xc5, 0x75, 0xca, 0xfd, 0xe9,
-	0x1a, 0x65, 0xcd, 0xae, 0x72, 0x64, 0xb1, 0xe7, 0x61, 0x34, 0xed, 0xa9,
-	0x57, 0xee, 0xde, 0x53, 0x85, 0x49, 0xcd, 0xb2, 0x9c, 0xa1, 0x7a, 0xa5,
-	0x75, 0x8f, 0x65, 0xdd, 0x64, 0x46, 0x9b, 0x8a, 0xc9, 0x77, 0xb7, 0xb1,
-	0xbd, 0xd6, 0x51, 0xe9, 0xe7, 0xf2, 0x76, 0x4d, 0x65, 0xe3, 0x9e, 0x87,
-	0xb1, 0x82, 0x65, 0x5f, 0x09, 0x45, 0x5b, 0x4a, 0x59, 0x56, 0x74, 0xd6,
-	0x3a, 0xfa, 0x19, 0xf6, 0x21, 0xe5, 0x17, 0x4c, 0x69, 0x67, 0x31, 0xaf,
-	0x49, 0x5b, 0x59, 0xdd, 0x89, 0xde, 0x1e, 0xcf, 0xea, 0x2d, 0x2c, 0x7a,
-	0x5b, 0x4e, 0x5d, 0xba, 0x7a, 0x7d, 0x3c, 0x5c, 0xf4, 0x75, 0x1f, 0xd6,
-	0xa4, 0x65, 0x4c, 0x33, 0x89, 0x03, 0xcd, 0xb4, 0xdb, 0x76, 0xb4, 0x52,
-	0xaf, 0x71, 0x2d, 0x6b, 0x9f, 0x17, 0x7d, 0x4b, 0xf7, 0x4f, 0x72, 0xec,
-	0xad, 0x49, 0xd1, 0x4b, 0x33, 0xcb, 0xdb, 0xf7, 0xe9, 0xdb, 0x53, 0xcb,
-	0x5c, 0x3a, 0x57, 0xfb, 0x13, 0xc2, 0x27, 0x0a, 0xc8, 0x7d, 0x0a, 0xd8,
-	0x5e, 0x96, 0x2b, 0x8a, 0xbd, 0x38, 0x68, 0x2f, 0xcf, 0x98, 0xc5, 0xd8,
-	0xe4, 0x95, 0x31, 0x66, 0xf5, 0x0c, 0x15, 0x58, 0xc7, 0x7b, 0x2e, 0xde,
-	0x2b, 0x0c, 0x15, 0xe2, 0x2d, 0x5b, 0x57, 0x59, 0x3e, 0x98, 0xf7, 0xf3,
-	0xa1, 0x0b, 0xfd, 0x1c, 0xab, 0xce, 0xda, 0xd8, 0x26, 0x57, 0x96, 0x33,
-	0xe6, 0xb9, 0x8d, 0x65, 0x0d, 0x98, 0x79, 0x6e, 0x23, 0x71, 0xee, 0x53,
-	0xc2, 0x15, 0x6c, 0x1e, 0xd6, 0x96, 0xeb, 0xb7, 0xcb, 0x0c, 0xd0, 0x4f,
-	0x85, 0xfb, 0x45, 0x94, 0xb6, 0x3d, 0xa7, 0x68, 0xab, 0x92, 0x8b, 0x01,
-	0x1b, 0x79, 0xbf, 0x94, 0xf7, 0x5f, 0x0b, 0xb9, 0x70, 0xd5, 0x34, 0xe9,
-	0xfb, 0x06, 0x74, 0xec, 0x8a, 0xa2, 0x7c, 0x61, 0x00, 0x93, 0xf6, 0x7a,
-	0x59, 0x9e, 0xa7, 0xbb, 0x70, 0xdf, 0xae, 0x8f, 0xad, 0x32, 0x9b, 0x3b,
-	0x1a, 0xb1, 0x71, 0x45, 0xc5, 0x8e, 0x45, 0xc2, 0xd7, 0x5d, 0x8c, 0x57,
-	0xe4, 0xce, 0x92, 0x0b, 0xb8, 0x4a, 0xc8, 0xb9, 0x85, 0x73, 0x06, 0x32,
-	0xb7, 0xab, 0xd0, 0xb4, 0x88, 0x70, 0xcf, 0x99, 0x36, 0xe7, 0x16, 0xee,
-	0xfd, 0xcd, 0xe4, 0xd1, 0x29, 0xdc, 0xfb, 0x02, 0x4f, 0x61, 0xae, 0xd6,
-	0x8c, 0x44, 0xaf, 0x07, 0xee, 0x88, 0xde, 0xbc, 0x59, 0xe9, 0xc4, 0xf2,
-	0x90, 0x61, 0xca, 0x1a, 0xc0, 0xf5, 0x8a, 0x1e, 0x3c, 0x87, 0x20, 0xe3,
-	0xc7, 0x8f, 0x30, 0x32, 0xf8, 0x0f, 0x2e, 0xf1, 0x8b, 0xcd, 0xe9, 0x8b,
-	0xf2, 0xdc, 0x4d, 0x79, 0xdc, 0x59, 0x79, 0xcc, 0x73, 0x54, 0xe4, 0xb3,
-	0xf5, 0x2e, 0xe2, 0xf0, 0x7f, 0xb7, 0xed, 0x76, 0x89, 0x9d, 0x4b, 0xfc,
-	0x77, 0xc6, 0x93, 0x70, 0x71, 0x5e, 0xcf, 0x9d, 0xc4, 0xab, 0x0f, 0x17,
-	0x16, 0x21, 0x44, 0x7b, 0xaf, 0x30, 0x3a, 0x98, 0xcf, 0x7f, 0x6c, 0xc5,
-	0x9d, 0xa4, 0xdf, 0x06, 0xb4, 0xa2, 0x48, 0x94, 0xb2, 0x35, 0x2a, 0x37,
-	0x0d, 0x8f, 0xb3, 0x9f, 0x0e, 0xe6, 0x29, 0x1e, 0x3c, 0x40, 0x5c, 0x79,
-	0x80, 0xfe, 0xf4, 0x00, 0x63, 0xf3, 0x03, 0xa3, 0xff, 0x8b, 0xd7, 0xa7,
-	0xd9, 0xbf, 0x37, 0x27, 0xf3, 0xf6, 0xe5, 0x64, 0x9c, 0x13, 0xfd, 0x6e,
-	0x21, 0x16, 0x48, 0x9c, 0x03, 0x65, 0xb2, 0x70, 0xda, 0x2c, 0xa4, 0xae,
-	0xf5, 0x60, 0x06, 0x09, 0xd7, 0xc5, 0x3c, 0x35, 0x1f, 0x2b, 0x65, 0x1e,
-	0x5d, 0xb8, 0x87, 0x32, 0x06, 0x43, 0xbf, 0xb1, 0x50, 0x21, 0x58, 0x74,
-	0xf9, 0xfd, 0xec, 0xbc, 0x1e, 0xbf, 0xc0, 0x59, 0x15, 0xc9, 0x91, 0xe8,
-	0xef, 0xfd, 0x36, 0x07, 0x7b, 0x8d, 0x3e, 0xd9, 0xb6, 0xeb, 0xc4, 0x7c,
-	0x31, 0x95, 0x35, 0xa3, 0x51, 0x6c, 0xe2, 0xb8, 0x57, 0x0f, 0x3f, 0x9a,
-	0xd3, 0x4b, 0x7e, 0xbc, 0xe2, 0xd3, 0x1e, 0xda, 0x74, 0x36, 0xb7, 0x6a,
-	0x1d, 0x15, 0x2e, 0x5e, 0xc9, 0xff, 0xc2, 0xc5, 0xc5, 0x7f, 0x84, 0x97,
-	0x4f, 0xe3, 0x7f, 0x27, 0x39, 0xa7, 0x70, 0xe9, 0x3a, 0xf4, 0xd0, 0x8f,
-	0x0a, 0x03, 0x75, 0xd8, 0x3a, 0x7a, 0xf9, 0x1c, 0x5d, 0x2e, 0x8f, 0x3d,
-	0x07, 0xcc, 0xc3, 0x5c, 0x82, 0xad, 0x7e, 0xbf, 0x2a, 0x7d, 0x5b, 0x68,
-	0x37, 0x6f, 0xc8, 0x72, 0xa7, 0x4a, 0xb9, 0x36, 0x95, 0x9f, 0xe7, 0xdb,
-	0x99, 0x7a, 0x4d, 0x2d, 0x40, 0x71, 0x9e, 0x37, 0x78, 0x73, 0xb9, 0x0e,
-	0xf3, 0x9b, 0xa4, 0xe8, 0x4b, 0xc6, 0x90, 0xcd, 0x5f, 0xc5, 0x5e, 0x2e,
-	0xc5, 0x83, 0xf8, 0xb4, 0x22, 0x43, 0x6c, 0x25, 0x48, 0x7f, 0xd6, 0xc3,
-	0x4d, 0x0c, 0x35, 0x67, 0x13, 0x88, 0x39, 0x22, 0x4d, 0x8d, 0x6b, 0x12,
-	0x73, 0xb5, 0x67, 0x72, 0xf9, 0xf1, 0x7e, 0xc6, 0x1e, 0xd5, 0x90, 0xb5,
-	0x19, 0xda, 0xc3, 0xb0, 0xe8, 0xa7, 0x43, 0xb9, 0x98, 0x0b, 0x47, 0xc9,
-	0x15, 0x19, 0x57, 0x0d, 0xc9, 0x91, 0x1a, 0x95, 0xa5, 0xc3, 0x52, 0x87,
-	0xf6, 0x70, 0x19, 0x67, 0xcc, 0x8e, 0xb7, 0x0c, 0x9e, 0x01, 0xe1, 0x8a,
-	0x3a, 0x36, 0x90, 0x9b, 0x94, 0x0c, 0xf8, 0x69, 0xef, 0x95, 0x28, 0xde,
-	0x1d, 0xc1, 0xfa, 0x51, 0x0d, 0x45, 0xbb, 0x2d, 0x6b, 0x6e, 0xa8, 0x1b,
-	0x6b, 0xd3, 0xcb, 0x0b, 0x24, 0x9f, 0x73, 0xf6, 0x11, 0x2b, 0x88, 0x2b,
-	0xeb, 0x92, 0x0a, 0x6e, 0x24, 0x07, 0x88, 0xa2, 0x99, 0xdc, 0x5d, 0xf0,
-	0xc5, 0xea, 0x9c, 0x1d, 0x71, 0xd1, 0x4e, 0x56, 0xf1, 0x7e, 0x0b, 0xb1,
-	0xa7, 0x85, 0x58, 0x62, 0x59, 0x1f, 0x5e, 0x8b, 0xce, 0x92, 0xc8, 0x1d,
-	0xc4, 0xa0, 0x1a, 0xe6, 0x0f, 0xc2, 0x39, 0xae, 0x45, 0x1b, 0xb1, 0xbb,
-	0xb0, 0xcf, 0xce, 0xf1, 0xa8, 0x47, 0xc6, 0xd5, 0x34, 0xe3, 0x32, 0x65,
-	0x7f, 0x9e, 0x7c, 0xbd, 0x83, 0x7e, 0x54, 0xde, 0xb7, 0x81, 0xf1, 0xd9,
-	0x83, 0xb2, 0x81, 0x6b, 0xb0, 0x91, 0xd8, 0x7e, 0xdf, 0x2e, 0x3f, 0x52,
-	0x8b, 0x6e, 0xa0, 0x7c, 0x0f, 0x62, 0x7d, 0xd2, 0x90, 0xbc, 0x2e, 0x1a,
-	0x5c, 0xf4, 0x20, 0xfb, 0xa5, 0x7d, 0xec, 0x92, 0x1c, 0xb1, 0x04, 0x4b,
-	0x9a, 0x81, 0x60, 0x9f, 0x60, 0x8e, 0x8c, 0xff, 0x36, 0x59, 0xcf, 0x82,
-	0xd1, 0x37, 0x75, 0x3e, 0xa6, 0x72, 0x39, 0x59, 0x1b, 0x6c, 0xc6, 0x7c,
-	0xc6, 0x2f, 0xb1, 0x21, 0x8d, 0x79, 0x6f, 0x91, 0x62, 0xf8, 0xf6, 0xd3,
-	0x17, 0x25, 0x17, 0xbb, 0xae, 0x2f, 0x1f, 0xaf, 0xf5, 0xcc, 0x62, 0x47,
-	0x27, 0xb1, 0x42, 0x6f, 0xff, 0xad, 0xa2, 0xaf, 0x3b, 0xa5, 0xfc, 0x18,
-	0x07, 0xc7, 0x5e, 0xc7, 0xd0, 0x98, 0x5b, 0x19, 0x1d, 0x93, 0xbe, 0x26,
-	0xd0, 0x9b, 0xfe, 0x73, 0x7d, 0x4d, 0x5d, 0x13, 0x5a, 0x74, 0xc9, 0x3a,
-	0xd2, 0x8d, 0xb9, 0xdc, 0x75, 0xe9, 0x25, 0x9c, 0x5e, 0xe6, 0x44, 0x6c,
-	0xcf, 0x8b, 0xee, 0xe4, 0xc5, 0xb5, 0x8a, 0xfe, 0xc4, 0x76, 0xdb, 0x07,
-	0x9b, 0xd3, 0x62, 0x93, 0xcc, 0xef, 0xcc, 0x39, 0xf6, 0xb3, 0x1b, 0x59,
-	0x5f, 0x58, 0xb3, 0xab, 0xd7, 0xbe, 0x77, 0xd0, 0xfc, 0x2b, 0x64, 0xec,
-	0x6b, 0x8b, 0xe9, 0x7f, 0x8c, 0x93, 0xc4, 0xbd, 0x60, 0xc8, 0x87, 0xc2,
-	0x0a, 0x59, 0x5b, 0xba, 0xb8, 0x1e, 0xb1, 0x61, 0x17, 0x69, 0x84, 0x8d,
-	0x2b, 0x0d, 0xc4, 0xb8, 0x1a, 0xce, 0x77, 0x16, 0x4b, 0xd6, 0xd3, 0x86,
-	0x6e, 0x11, 0x1b, 0x72, 0x65, 0x6d, 0xe8, 0x0f, 0xd7, 0x3c, 0x54, 0x90,
-	0xaf, 0x6a, 0x65, 0x76, 0x2e, 0xda, 0xa8, 0xdc, 0x9a, 0xb3, 0xab, 0xcf,
-	0xa6, 0xbf, 0x53, 0x90, 0xcb, 0x91, 0x2e, 0x2b, 0xff, 0x49, 0x3a, 0xb8,
-	0xe6, 0x2f, 0xd0, 0x81, 0x60, 0xbe, 0xe4, 0x31, 0xa2, 0x83, 0x99, 0x53,
-	0xfc, 0xf2, 0x93, 0xf4, 0x50, 0x9b, 0xd3, 0xc3, 0x62, 0x62, 0x48, 0x25,
-	0x71, 0x4f, 0x38, 0x4b, 0x00, 0x4f, 0x6a, 0x79, 0x3d, 0x38, 0x73, 0x7a,
-	0xd0, 0xff, 0x40, 0x0f, 0xf7, 0x13, 0x5f, 0x4b, 0xd9, 0x56, 0x31, 0x8f,
-	0x77, 0xa9, 0x87, 0x8d, 0xc3, 0x8b, 0xf1, 0x00, 0x7d, 0x69, 0x83, 0xbd,
-	0x5e, 0x23, 0xcf, 0xef, 0x5c, 0x97, 0xe8, 0x66, 0x25, 0xe5, 0xf7, 0x17,
-	0xa8, 0x98, 0x41, 0x1d, 0xf8, 0x6c, 0x3c, 0x95, 0x3e, 0x1a, 0x95, 0xdb,
-	0x87, 0x05, 0xe3, 0x3e, 0xa6, 0x0e, 0x3a, 0x18, 0x07, 0xfe, 0x54, 0x9e,
-	0x21, 0xfd, 0x7f, 0x7c, 0x41, 0x57, 0x7f, 0xbc, 0xdc, 0x8f, 0xa9, 0x03,
-	0x79, 0x26, 0x22, 0x6b, 0xec, 0xf2, 0x7c, 0x44, 0xf4, 0x61, 0x4c, 0xd1,
-	0x83, 0x65, 0x1d, 0x31, 0xe7, 0x21, 0x56, 0xa9, 0xf7, 0x4b, 0x1c, 0xed,
-	0x27, 0xa6, 0x38, 0x98, 0xb7, 0x17, 0x44, 0xa2, 0x14, 0x5b, 0xbd, 0x81,
-	0x4c, 0xa7, 0xce, 0x81, 0x4e, 0x9c, 0x31, 0x8d, 0x9e, 0xb5, 0xf8, 0x2b,
-	0x74, 0x79, 0x2d, 0x1c, 0x60, 0x3b, 0x9b, 0x92, 0x45, 0x58, 0x57, 0x47,
-	0xd3, 0x5c, 0xe9, 0xc1, 0xce, 0x64, 0xbc, 0x85, 0xd0, 0xc2, 0xd8, 0x74,
-	0xe6, 0xf6, 0x44, 0x40, 0x6f, 0xde, 0x40, 0xbe, 0xb6, 0xbc, 0xd7, 0x0d,
-	0xbf, 0x92, 0x8d, 0xcf, 0x03, 0xaa, 0xac, 0x7f, 0x5e, 0xc9, 0xb1, 0x77,
-	0xdb, 0x79, 0xac, 0x7f, 0x9a, 0xf4, 0xe3, 0x47, 0x3c, 0x2d, 0x75, 0xa9,
-	0xb3, 0xb9, 0x0a, 0x96, 0xcf, 0xd5, 0xe3, 0x51, 0xc5, 0xb2, 0x16, 0x84,
-	0x9c, 0xf6, 0xfd, 0xed, 0xe9, 0xda, 0x96, 0xdb, 0xd4, 0xd7, 0xad, 0xec,
-	0x9a, 0xab, 0xae, 0x45, 0x99, 0x0c, 0x1d, 0xff, 0xa3, 0xcf, 0x1d, 0x82,
-	0x90, 0xe7, 0x41, 0x6e, 0x63, 0x25, 0x0e, 0xe5, 0xd6, 0x1d, 0x5d, 0x91,
-	0xc3, 0x5f, 0x3e, 0x60, 0x48, 0xbe, 0x26, 0x7a, 0x92, 0xfe, 0xc4, 0x9e,
-	0x1e, 0x28, 0x14, 0x1c, 0xed, 0x4a, 0x2f, 0xe4, 0x3c, 0xfe, 0x87, 0x35,
-	0xea, 0x9d, 0x5a, 0x76, 0x89, 0x9a, 0x7d, 0x8e, 0x20, 0x65, 0xf3, 0xe5,
-	0xe6, 0x10, 0x57, 0x1a, 0x30, 0x7c, 0x49, 0x9b, 0x92, 0x6f, 0xe7, 0xdb,
-	0xec, 0x2d, 0x14, 0x5e, 0x55, 0x81, 0x42, 0xe2, 0xe3, 0x6f, 0xac, 0x83,
-	0x97, 0xb4, 0xb7, 0xd1, 0x95, 0x6d, 0x6f, 0x0f, 0xcb, 0x48, 0xd9, 0x02,
-	0xd6, 0x79, 0x37, 0xc7, 0x7f, 0xf3, 0x65, 0x3e, 0x77, 0x59, 0x19, 0x66,
-	0x78, 0xc6, 0x5b, 0xd6, 0xfe, 0x4b, 0xca, 0x7c, 0xda, 0x79, 0x69, 0x19,
-	0x27, 0x66, 0x1b, 0xaf, 0x5b, 0xc7, 0x2f, 0x29, 0x33, 0x70, 0x59, 0x99,
-	0x6b, 0x31, 0x56, 0xf7, 0xb8, 0x35, 0x94, 0x9d, 0x9b, 0x0c, 0x5d, 0xd0,
-	0x3d, 0x23, 0xe2, 0xfe, 0xd2, 0x75, 0xf3, 0x74, 0xf2, 0x4d, 0x79, 0x16,
-	0xe5, 0x46, 0x26, 0x3b, 0x37, 0x71, 0x99, 0x1b, 0xd7, 0x82, 0xfc, 0xdc,
-	0x3c, 0x90, 0xab, 0x9f, 0x6f, 0x37, 0x56, 0x70, 0x69, 0xbb, 0xf9, 0xeb,
-	0x8e, 0xcb, 0xe4, 0x9e, 0xb8, 0xac, 0x5c, 0x51, 0xe1, 0x27, 0xd7, 0xfb,
-	0x81, 0xe3, 0xd2, 0xeb, 0xff, 0x43, 0xbd, 0xf4, 0xfc, 0x9a, 0xdc, 0x79,
-	0x5e, 0xff, 0xd6, 0x65, 0xf7, 0x1d, 0x97, 0x9d, 0x3f, 0xa3, 0x7e, 0x72,
-	0x3f, 0xab, 0x2e, 0xeb, 0xc7, 0x5e, 0x83, 0xc7, 0x73, 0x17, 0x70, 0x03,
-	0x8d, 0x05, 0x08, 0x98, 0x4e, 0x05, 0x7e, 0xe2, 0x87, 0xff, 0xf9, 0xcb,
-	0xd6, 0xe2, 0x1b, 0x2f, 0xe0, 0xc7, 0x25, 0x5c, 0x35, 0x56, 0x18, 0x91,
-	0x38, 0x28, 0x3c, 0x55, 0xf8, 0xe2, 0x27, 0xf1, 0xef, 0xb2, 0x58, 0x51,
-	0xa4, 0x1e, 0xfe, 0xb1, 0x99, 0xfe, 0xb7, 0x12, 0xb2, 0x1e, 0xfb, 0x7b,
-	0x72, 0x2e, 0xc3, 0x77, 0x08, 0x33, 0xfd, 0x3f, 0x4d, 0x95, 0xb8, 0x51,
-	0xe6, 0xc1, 0x8d, 0x89, 0x4f, 0xae, 0xa7, 0x46, 0xa0, 0x2c, 0xab, 0xf7,
-	0x31, 0xaf, 0x84, 0xf3, 0xa6, 0x79, 0x98, 0xf2, 0xd7, 0x2c, 0x79, 0xae,
-	0x7a, 0xb2, 0x3e, 0xcc, 0x18, 0x9f, 0x7d, 0x8e, 0xbc, 0x24, 0xad, 0xfb,
-	0xa2, 0x4a, 0xf6, 0x59, 0xf1, 0xba, 0xd0, 0x47, 0xe4, 0x45, 0x9d, 0x94,
-	0xcb, 0x62, 0x5f, 0xc0, 0x86, 0x84, 0x65, 0x3d, 0xc7, 0xfc, 0x5c, 0xf6,
-	0x20, 0xfc, 0x22, 0xf5, 0x3b, 0x6b, 0xc2, 0xeb, 0xc4, 0xdb, 0xc6, 0xd4,
-	0xf6, 0xfc, 0x28, 0x8f, 0x98, 0xcc, 0x13, 0xed, 0x13, 0x75, 0xcc, 0xa8,
-	0x6d, 0x3f, 0x40, 0xbf, 0x9b, 0x1f, 0xd0, 0xfd, 0x7d, 0xf8, 0x3f, 0x96,
-	0xbf, 0x5a, 0x0f, 0x0e, 0x29, 0xf9, 0xf5, 0xef, 0xcb, 0xd7, 0xb9, 0xcb,
-	0x62, 0x2e, 0x8e, 0x6f, 0xbf, 0xbd, 0xd6, 0x5d, 0x40, 0xac, 0x44, 0xcc,
-	0x19, 0x99, 0xe9, 0xdf, 0x9a, 0xb0, 0xc7, 0x49, 0x5e, 0xa9, 0xe0, 0x64,
-	0xfd, 0x4c, 0xff, 0xa6, 0x94, 0x17, 0x3b, 0x18, 0xd3, 0x8b, 0x8c, 0x7a,
-	0x3c, 0x9e, 0x52, 0x71, 0xcf, 0x23, 0x5e, 0xac, 0x21, 0x67, 0x6d, 0xef,
-	0xfd, 0x1a, 0x8c, 0xab, 0x9c, 0xb8, 0x9b, 0xf6, 0xb7, 0x96, 0xae, 0x23,
-	0xf9, 0xc3, 0xfa, 0x5e, 0x27, 0xea, 0xae, 0x2a, 0x43, 0xbc, 0xba, 0x10,
-	0xdf, 0x33, 0x1d, 0xcc, 0xf7, 0x4a, 0x30, 0x64, 0x73, 0x69, 0xc9, 0xe1,
-	0x05, 0x13, 0x45, 0x6f, 0x0e, 0x7b, 0xbd, 0xf5, 0x93, 0xe3, 0xc1, 0x7f,
-	0x58, 0x99, 0xea, 0x1d, 0x36, 0x8e, 0x3b, 0x22, 0xa6, 0x1d, 0x73, 0x81,
-	0x2c, 0x9f, 0xeb, 0xba, 0xe4, 0x79, 0x77, 0xb3, 0x32, 0x3b, 0x12, 0x98,
-	0x58, 0xac, 0x38, 0x10, 0x0e, 0x94, 0xc5, 0xca, 0x23, 0x61, 0x2c, 0x4b,
-	0x77, 0xf9, 0x7c, 0xf6, 0x33, 0xf4, 0x08, 0xce, 0x2d, 0x32, 0x99, 0xfb,
-	0xc3, 0xb9, 0x8c, 0xba, 0x6f, 0xa4, 0x5e, 0xb7, 0x98, 0x1f, 0x59, 0x19,
-	0xdb, 0xef, 0xdd, 0x88, 0x31, 0x07, 0x5b, 0x4b, 0xfd, 0x3a, 0xa8, 0xc7,
-	0x9f, 0xe7, 0xf4, 0x2b, 0x3a, 0x2d, 0x19, 0xfb, 0x9d, 0x75, 0x92, 0xfa,
-	0x75, 0xb3, 0x3d, 0x37, 0xdb, 0x2b, 0x1a, 0xbb, 0x54, 0xcf, 0x85, 0x94,
-	0x67, 0x99, 0x2d, 0xc3, 0x42, 0x79, 0x86, 0xe9, 0x8f, 0x2a, 0x32, 0x1e,
-	0xc1, 0xf7, 0x3f, 0x37, 0xa6, 0x1f, 0x4f, 0xc9, 0x55, 0x44, 0xff, 0x7e,
-	0xea, 0x5f, 0x30, 0x5c, 0xe6, 0xa0, 0x4e, 0xd6, 0xbb, 0x7a, 0x80, 0x97,
-	0x98, 0xcc, 0x2a, 0xa8, 0x32, 0x22, 0x78, 0xaa, 0xd9, 0x83, 0xb7, 0x12,
-	0xa5, 0xf6, 0xb8, 0xaf, 0x9a, 0x6b, 0x59, 0x4f, 0x86, 0xfc, 0xf8, 0x85,
-	0x51, 0x1b, 0x5e, 0xa0, 0xea, 0xcc, 0x1f, 0xbd, 0x48, 0x10, 0x67, 0xbb,
-	0x92, 0xb3, 0x38, 0x5f, 0x5e, 0x6c, 0x4d, 0xa2, 0x9d, 0xf6, 0xe4, 0x77,
-	0x44, 0x80, 0x33, 0x09, 0x23, 0xb8, 0x85, 0xfd, 0x0f, 0x7b, 0xeb, 0xc9,
-	0xd3, 0xd5, 0x46, 0xd2, 0xbd, 0x78, 0x51, 0xc4, 0x88, 0x6f, 0xc3, 0xcf,
-	0xac, 0x21, 0xe2, 0x7c, 0x41, 0x48, 0xd6, 0x1c, 0x67, 0xe3, 0x19, 0xcd,
-	0x81, 0x17, 0x83, 0xcc, 0x87, 0x2b, 0x1c, 0x28, 0x31, 0xde, 0xb6, 0x7e,
-	0xe0, 0x95, 0x7e, 0x64, 0x2c, 0x33, 0x38, 0x0e, 0xc5, 0xc6, 0xc2, 0xad,
-	0xc9, 0x7a, 0xea, 0xfb, 0xf2, 0xfe, 0xff, 0x8f, 0x35, 0xe9, 0x95, 0xfe,
-	0x75, 0xcd, 0xaf, 0x72, 0x0c, 0x7f, 0x14, 0xbb, 0xbf, 0x6f, 0xbd, 0x64,
-	0xb7, 0x79, 0xbb, 0x3b, 0x1b, 0x4f, 0xa5, 0xbd, 0xb7, 0x38, 0x3e, 0x69,
-	0x33, 0xdf, 0x8f, 0xe8, 0xed, 0x8c, 0x5b, 0xfc, 0x79, 0x6b, 0x52, 0xf4,
-	0x27, 0x78, 0x75, 0xd2, 0xc2, 0x34, 0x39, 0x7f, 0xd6, 0x2e, 0x1b, 0xa7,
-	0xbe, 0xba, 0x68, 0x43, 0x8c, 0xe1, 0x3e, 0xd8, 0xbb, 0x3b, 0x34, 0x3b,
-	0x9f, 0xdb, 0xcc, 0x1c, 0x60, 0xc8, 0x5b, 0x8e, 0xad, 0x26, 0xed, 0xce,
-	0x50, 0xe7, 0x38, 0x61, 0xe1, 0xa4, 0x29, 0xe7, 0x2e, 0x4c, 0x7a, 0x1d,
-	0xd8, 0x66, 0x3a, 0xb1, 0xce, 0x50, 0x75, 0xb9, 0xee, 0x08, 0xc9, 0xb9,
-	0x0b, 0xfe, 0x6a, 0x05, 0x3b, 0x18, 0x3e, 0xd6, 0x1b, 0x5d, 0x7e, 0xb9,
-	0xbe, 0x24, 0x24, 0xe7, 0x0a, 0xda, 0xa8, 0x93, 0xb8, 0xa6, 0x60, 0x83,
-	0x21, 0xcf, 0x4d, 0xb3, 0xfc, 0x39, 0x06, 0xcb, 0xda, 0x61, 0x36, 0x5c,
-	0x57, 0xc2, 0x72, 0x67, 0x4d, 0xe1, 0x83, 0x87, 0xef, 0x98, 0x1f, 0x88,
-	0x47, 0x0b, 0xa0, 0xc7, 0x8a, 0xe8, 0xa7, 0x5b, 0x7b, 0x67, 0xb3, 0x9e,
-	0x42, 0x6e, 0xe0, 0xf4, 0x6d, 0x87, 0xc4, 0xcf, 0x80, 0xff, 0xa7, 0x4c,
-	0xb2, 0x86, 0xbc, 0xf3, 0xa8, 0x59, 0xc3, 0x7f, 0x9a, 0xf3, 0x56, 0x6e,
-	0x38, 0xdb, 0x5f, 0x85, 0xbe, 0xae, 0x48, 0x99, 0x17, 0x2c, 0x63, 0xae,
-	0x10, 0x27, 0xbe, 0x8f, 0x8c, 0x39, 0xb1, 0x25, 0x69, 0x68, 0x07, 0x6d,
-	0xfe, 0xe7, 0xa4, 0x2e, 0x9c, 0xcc, 0xcf, 0x03, 0xda, 0x84, 0x92, 0x3f,
-	0x9f, 0x2d, 0xd8, 0x40, 0x3e, 0x2f, 0xf8, 0x16, 0xb7, 0x9e, 0xad, 0x17,
-	0xaa, 0xe1, 0xf6, 0xc7, 0x52, 0x1e, 0x1e, 0x1a, 0x0f, 0xaf, 0x7f, 0x4d,
-	0xca, 0xe7, 0x6f, 0x4b, 0xc1, 0xdf, 0x9a, 0xca, 0xdb, 0x65, 0xde, 0xb7,
-	0x05, 0xdb, 0x2c, 0x72, 0xd6, 0x6c, 0x6e, 0xd6, 0x25, 0xb9, 0x0f, 0xe4,
-	0xb9, 0xdf, 0xe1, 0x3b, 0x9e, 0xa3, 0xad, 0xbb, 0x98, 0x0f, 0x6c, 0x33,
-	0xe2, 0x51, 0x79, 0x0e, 0x69, 0x84, 0x74, 0x5f, 0x81, 0xe2, 0xc7, 0xd6,
-	0xba, 0xdf, 0x72, 0x3e, 0xc9, 0x93, 0x53, 0x9f, 0x29, 0xca, 0xce, 0x87,
-	0xf8, 0x99, 0x60, 0x80, 0x9f, 0xf9, 0x92, 0xcf, 0xdf, 0xc5, 0x7e, 0x36,
-	0xa7, 0xa6, 0xfa, 0x80, 0x82, 0x9b, 0xd8, 0x56, 0x43, 0x08, 0xce, 0xa5,
-	0x75, 0xbf, 0xb1, 0x32, 0xde, 0xec, 0x33, 0xc8, 0x2c, 0xe6, 0x81, 0x36,
-	0x67, 0xf7, 0xe9, 0xdc, 0x5f, 0x27, 0xfb, 0x8e, 0x14, 0x0c, 0xd3, 0xa7,
-	0x36, 0xa5, 0xc5, 0x9e, 0xb2, 0x7a, 0x8d, 0xff, 0x01, 0xfe, 0x98, 0xb8,
-	0x37, 0x89, 0x58, 0x41, 0x44, 0xf0, 0xc7, 0xed, 0x7f, 0x29, 0x55, 0x47,
-	0x0e, 0x2f, 0xcf, 0xf2, 0xdd, 0x9c, 0x67, 0x8f, 0xff, 0xc5, 0xd4, 0xf5,
-	0xb8, 0x67, 0x4f, 0x18, 0xeb, 0xf6, 0xa0, 0xae, 0x88, 0x72, 0x17, 0x86,
-	0x02, 0xfe, 0x51, 0x68, 0xfe, 0x67, 0xa8, 0x87, 0x13, 0x94, 0xed, 0xe4,
-	0x25, 0xb2, 0x89, 0xde, 0xe0, 0xbf, 0x2f, 0xe1, 0x46, 0x2a, 0xf4, 0xa1,
-	0x15, 0xb7, 0x79, 0x86, 0xd7, 0xbf, 0x31, 0xe1, 0x47, 0xc6, 0xe6, 0xac,
-	0xae, 0x22, 0xc9, 0x1f, 0xbb, 0x93, 0xf1, 0x28, 0xd3, 0xe1, 0xdc, 0x9c,
-	0xea, 0x61, 0x99, 0xcf, 0x33, 0x09, 0xb9, 0x17, 0xfd, 0x9a, 0x0a, 0xdd,
-	0xaf, 0x32, 0x7e, 0xf6, 0x9b, 0x62, 0xb3, 0x35, 0xa2, 0x93, 0x20, 0x2b,
-	0xc6, 0x3d, 0x91, 0x40, 0x4b, 0x1d, 0xaf, 0x6b, 0x0b, 0x10, 0xab, 0x88,
-	0x08, 0x27, 0xf4, 0xfa, 0x6b, 0xc7, 0x7d, 0x7e, 0x73, 0x1c, 0xfe, 0x2b,
-	0xc7, 0xa7, 0x8a, 0x40, 0x6e, 0xff, 0x89, 0xb9, 0x9f, 0xd7, 0xbf, 0x36,
-	0x31, 0x1b, 0x6a, 0x24, 0x6e, 0x2d, 0xa9, 0x3f, 0x67, 0xcd, 0x8e, 0x18,
-	0x99, 0x93, 0x94, 0xe1, 0xc3, 0x6b, 0xf5, 0xf8, 0x0c, 0xc7, 0x89, 0x87,
-	0xb4, 0x29, 0x7d, 0xbc, 0x1f, 0xfa, 0xff, 0xdb, 0x47, 0x3e, 0xb6, 0x89,
-	0xfc, 0x12, 0xdf, 0x72, 0x73, 0xaa, 0xe6, 0xc7, 0xa2, 0x70, 0x4e, 0x39,
-	0x1f, 0xc9, 0x7c, 0xac, 0xb2, 0xac, 0x56, 0xc3, 0x97, 0x7b, 0xfe, 0x07,
-	0xda, 0xcb, 0x89, 0xeb, 0x9c, 0x58, 0x4c, 0x7b, 0x6f, 0xf8, 0x6b, 0x27,
-	0xa2, 0xbe, 0x42, 0xc6, 0x50, 0xd9, 0x53, 0xf0, 0x4c, 0xdd, 0xa4, 0x35,
-	0x61, 0xd4, 0xa1, 0x21, 0x2d, 0xcf, 0x63, 0x1d, 0xb4, 0x63, 0x0b, 0x8f,
-	0x9b, 0x72, 0x5f, 0xf0, 0x24, 0x1e, 0x73, 0xd0, 0x26, 0xdc, 0x86, 0xde,
-	0xf2, 0x0f, 0x4a, 0x19, 0x8a, 0x23, 0xce, 0xe0, 0x04, 0xf4, 0xf0, 0x7a,
-	0x72, 0x63, 0x7f, 0xc5, 0x3c, 0x53, 0xd4, 0xfe, 0x4e, 0x22, 0x60, 0x06,
-	0x72, 0xf1, 0xe7, 0x2c, 0xe7, 0xeb, 0xdd, 0x84, 0xb1, 0xee, 0xb9, 0xdc,
-	0xf9, 0xbf, 0xa5, 0xa6, 0xe6, 0xbf, 0x62, 0x77, 0x6e, 0xf7, 0xe6, 0x04,
-	0xde, 0x77, 0xd4, 0xe3, 0xfd, 0xfd, 0x66, 0x01, 0xf3, 0x36, 0xb1, 0x47,
-	0xb7, 0x7b, 0x6b, 0x02, 0x93, 0x4e, 0x5e, 0x3b, 0x6b, 0xce, 0x22, 0x76,
-	0xa9, 0xbc, 0x16, 0x96, 0x58, 0x10, 0xd3, 0x18, 0x47, 0x8b, 0x23, 0x5e,
-	0x77, 0xf1, 0x38, 0xb4, 0x22, 0xa3, 0x8c, 0x79, 0x31, 0x1a, 0x1d, 0x7d,
-	0xba, 0xbf, 0xc9, 0x51, 0xc7, 0xfc, 0xd8, 0xaf, 0xb8, 0x8c, 0x6f, 0x31,
-	0xcf, 0x97, 0xf5, 0xaa, 0x30, 0xc7, 0xed, 0x64, 0x85, 0x9d, 0xd3, 0xd4,
-	0x88, 0x42, 0xcc, 0x2b, 0xc3, 0xbd, 0xda, 0x86, 0xc5, 0x6a, 0xa4, 0x1f,
-	0xb7, 0xd6, 0xbb, 0x1b, 0xcb, 0xc7, 0xf3, 0x3a, 0x41, 0xcc, 0x13, 0x61,
-	0x0e, 0x63, 0x40, 0x2d, 0x8d, 0x88, 0x6e, 0xfc, 0x8d, 0x7d, 0x63, 0x22,
-	0xab, 0xe6, 0xee, 0x1d, 0xf3, 0x14, 0xa3, 0x38, 0x4c, 0x4c, 0xfa, 0x57,
-	0xdf, 0x7f, 0xae, 0xde, 0x64, 0x91, 0xe0, 0xba, 0xcb, 0x90, 0xff, 0xb6,
-	0x3d, 0xb9, 0xdd, 0x91, 0x63, 0x31, 0x77, 0xc0, 0xb2, 0x18, 0x0f, 0x7d,
-	0x50, 0x66, 0x71, 0x3c, 0xf4, 0x29, 0xce, 0x4d, 0x5b, 0xea, 0x23, 0xeb,
-	0x33, 0x4e, 0x3b, 0xd6, 0xbb, 0x0b, 0x23, 0xe1, 0xbb, 0xde, 0x36, 0x7e,
-	0x6f, 0xbd, 0x95, 0x60, 0x5e, 0x4d, 0xdf, 0x2d, 0x20, 0x6e, 0x6f, 0x37,
-	0x9d, 0x4d, 0x4b, 0x15, 0x05, 0xdd, 0xc6, 0x3c, 0xad, 0x88, 0xf1, 0x68,
-	0x13, 0xfd, 0x37, 0xe6, 0x35, 0x82, 0xfb, 0xc1, 0x72, 0xa9, 0xb5, 0x6b,
-	0x5d, 0x91, 0x8d, 0x77, 0x8d, 0xd4, 0x8b, 0xcf, 0x9f, 0xbf, 0xeb, 0x39,
-	0xa3, 0x19, 0xdd, 0xe9, 0x41, 0xf4, 0xa4, 0xb3, 0xfd, 0x64, 0x30, 0xfb,
-	0x13, 0xfa, 0x59, 0xbb, 0xb6, 0x30, 0x22, 0x1c, 0xeb, 0xe8, 0x5d, 0x07,
-	0x8c, 0x28, 0xb6, 0xa4, 0x37, 0xde, 0x75, 0xb6, 0xbe, 0x9f, 0xff, 0xb3,
-	0x75, 0x86, 0x50, 0xfe, 0x89, 0x75, 0x4a, 0x22, 0xd2, 0x47, 0x98, 0x7d,
-	0x6c, 0xbc, 0x6b, 0xdd, 0xa2, 0xaf, 0x63, 0x73, 0x7a, 0xdd, 0x9f, 0xed,
-	0xa7, 0x94, 0x75, 0x8a, 0x23, 0x1d, 0xad, 0x37, 0x05, 0x36, 0xde, 0x95,
-	0x5a, 0xd4, 0xc3, 0x3e, 0x56, 0x31, 0x8e, 0x64, 0xeb, 0x44, 0x15, 0xc7,
-	0x27, 0xea, 0xa0, 0x28, 0xd2, 0xd3, 0x3a, 0x3f, 0xf0, 0x7b, 0x6b, 0x5e,
-	0x6f, 0x81, 0xad, 0x03, 0x17, 0x75, 0xf0, 0xa8, 0xe9, 0xcc, 0x04, 0x1c,
-	0xb6, 0x0e, 0x3a, 0x7c, 0xd4, 0x41, 0x1f, 0x75, 0x90, 0xa9, 0x36, 0xc2,
-	0xef, 0x51, 0x07, 0xf3, 0xc6, 0xd6, 0xae, 0x2d, 0x8a, 0xc0, 0xe9, 0x30,
-	0x5e, 0x77, 0x38, 0x39, 0x17, 0x2e, 0x63, 0x2d, 0xf5, 0xb6, 0xf1, 0xae,
-	0x39, 0x8b, 0x6c, 0x9d, 0x7f, 0xd9, 0x1d, 0xd8, 0x60, 0xef, 0xdd, 0xdb,
-	0x94, 0x6e, 0xe3, 0xd1, 0xc4, 0xe3, 0x61, 0x1e, 0xdd, 0xcc, 0x4d, 0xee,
-	0xa0, 0xae, 0x1a, 0x39, 0x8e, 0x15, 0x94, 0xab, 0x9d, 0xbf, 0x5b, 0xf8,
-	0xbb, 0x83, 0xbf, 0x65, 0x7e, 0xd4, 0x0b, 0xb2, 0xc5, 0x2e, 0xc8, 0xe6,
-	0xa0, 0x3c, 0x1e, 0x62, 0x94, 0x8c, 0x69, 0xe2, 0xcb, 0x37, 0x05, 0x62,
-	0x6c, 0xe3, 0xa9, 0x62, 0xd9, 0xf7, 0xe4, 0x32, 0xe2, 0x3e, 0x27, 0x44,
-	0x3e, 0xbd, 0x65, 0x1d, 0x32, 0xc4, 0xd8, 0xdf, 0x65, 0x31, 0x96, 0xb2,
-	0x95, 0x71, 0x7e, 0x5e, 0x59, 0x34, 0x34, 0xdd, 0x63, 0xc0, 0xe7, 0x36,
-	0xe2, 0xe8, 0x4d, 0x27, 0xa8, 0x03, 0xb1, 0x93, 0x07, 0xa9, 0xbf, 0x4e,
-	0x74, 0x19, 0x27, 0xf4, 0xec, 0xde, 0x89, 0xbd, 0x94, 0x21, 0x48, 0x7e,
-	0xe8, 0x81, 0x33, 0xa2, 0xfb, 0x1b, 0x1d, 0x5d, 0x41, 0x17, 0x68, 0xcb,
-	0xc5, 0x62, 0xcb, 0x71, 0xc6, 0x35, 0xc1, 0x3a, 0xb7, 0xd6, 0x66, 0xe3,
-	0x5f, 0x7c, 0xbe, 0x0b, 0x1e, 0x6d, 0x4d, 0x2a, 0x1f, 0x0b, 0x3c, 0x5a,
-	0x6b, 0x42, 0xfc, 0x4a, 0xd6, 0xfc, 0xc3, 0x76, 0x2c, 0x3f, 0x9e, 0x7e,
-	0xb1, 0x18, 0x65, 0xb6, 0x8f, 0x95, 0x39, 0x8d, 0x6c, 0xbb, 0x1a, 0xdb,
-	0x6d, 0x76, 0x68, 0xb8, 0xe8, 0x23, 0xba, 0xd6, 0xec, 0x90, 0x7d, 0xae,
-	0xf4, 0xfe, 0x54, 0xae, 0x5e, 0x16, 0x27, 0x16, 0xbb, 0x6c, 0x9c, 0x60,
-	0x1b, 0xc5, 0xc0, 0x92, 0xc4, 0xe5, 0xfd, 0x4b, 0x7f, 0xd2, 0x6f, 0x57,
-	0x85, 0x8a, 0x09, 0xfb, 0x99, 0xcb, 0x91, 0x74, 0x0c, 0x83, 0xc9, 0xa9,
-	0x7b, 0xf9, 0xf4, 0xa3, 0x6c, 0xff, 0x70, 0x9c, 0xfa, 0x98, 0x65, 0xc8,
-	0x3e, 0x3f, 0xd9, 0xdb, 0x37, 0x75, 0x5f, 0x9f, 0xc8, 0x56, 0x58, 0x42,
-	0x00, 0xc1, 0x01, 0xe2, 0x4c, 0xb4, 0x59, 0xea, 0x5b, 0xd6, 0x1b, 0xf3,
-	0x82, 0xc8, 0x54, 0x39, 0x31, 0x38, 0x17, 0x18, 0xe8, 0x93, 0x7d, 0x57,
-	0x47, 0x63, 0xab, 0x99, 0x97, 0x45, 0x2b, 0x6b, 0xb5, 0x4d, 0xaa, 0xec,
-	0x99, 0x3a, 0xf6, 0xe5, 0x6e, 0xa3, 0x46, 0xeb, 0x56, 0x33, 0x87, 0x88,
-	0xdd, 0x7b, 0x81, 0x69, 0x25, 0xe2, 0x6b, 0x15, 0x46, 0xb4, 0xa7, 0x02,
-	0x73, 0xe1, 0xaf, 0xb4, 0xf1, 0x32, 0xfe, 0x94, 0x6a, 0x04, 0x57, 0xda,
-	0x38, 0xf8, 0xa1, 0x35, 0xc4, 0xb8, 0xf4, 0x95, 0xb9, 0x3f, 0x28, 0xce,
-	0xe6, 0xd9, 0xd1, 0x75, 0xd3, 0x38, 0x57, 0xbf, 0x58, 0xa0, 0xfb, 0x53,
-	0x8a, 0xe8, 0x48, 0xb8, 0x49, 0x02, 0xdb, 0xc8, 0x75, 0x7f, 0x33, 0x37,
-	0x82, 0x83, 0xfc, 0xff, 0xf3, 0xeb, 0x65, 0x0f, 0xaa, 0x65, 0x05, 0x03,
-	0xf3, 0xc2, 0x15, 0x1c, 0xc3, 0x8b, 0xbc, 0xdf, 0x93, 0x7e, 0xdb, 0x3a,
-	0x3b, 0xcd, 0xe8, 0x5f, 0xc6, 0x40, 0x32, 0x30, 0xae, 0x6b, 0x93, 0xea,
-	0x7f, 0x76, 0x4f, 0x1d, 0xdc, 0x65, 0x1c, 0xcb, 0xf7, 0x02, 0xb5, 0x5a,
-	0x9f, 0xaa, 0x96, 0x88, 0x5e, 0x07, 0xc6, 0x7f, 0x3c, 0x65, 0xaf, 0x47,
-	0x9e, 0x1f, 0xda, 0x6b, 0x1d, 0x3d, 0x43, 0xf4, 0xa9, 0x21, 0x2d, 0x1a,
-	0xa7, 0xde, 0xdd, 0x55, 0x1c, 0xf3, 0x57, 0xe6, 0xde, 0x6a, 0x8f, 0xb3,
-	0xd2, 0x98, 0xc1, 0x31, 0x2a, 0xd0, 0xe6, 0xfe, 0x2c, 0xb7, 0xee, 0xd9,
-	0x40, 0x36, 0x33, 0x64, 0x35, 0xd2, 0x06, 0x0b, 0x58, 0xe7, 0x46, 0x73,
-	0xdf, 0xf4, 0xae, 0x3a, 0xdd, 0xf7, 0x15, 0xc6, 0xce, 0xd0, 0xdc, 0x5f,
-	0x5b, 0x51, 0xcd, 0x69, 0x7e, 0x93, 0xa3, 0xbe, 0x27, 0x21, 0x65, 0x65,
-	0x5e, 0x8d, 0xe8, 0x5c, 0xe5, 0x5d, 0x0b, 0xd5, 0x81, 0xf0, 0x5c, 0x7b,
-	0xfc, 0xc0, 0xdd, 0xa9, 0x04, 0xb6, 0x27, 0xa5, 0x4d, 0x05, 0xcb, 0x02,
-	0xef, 0x58, 0xfe, 0x69, 0x09, 0x6c, 0x4d, 0xff, 0x29, 0xae, 0x37, 0x28,
-	0x71, 0xbf, 0x25, 0x0e, 0x3d, 0x9a, 0x7d, 0xc6, 0x35, 0x5b, 0xd6, 0x94,
-	0x65, 0x0f, 0xd2, 0x5d, 0x89, 0x00, 0xdc, 0xa5, 0xc4, 0xba, 0xb1, 0x80,
-	0x3c, 0x13, 0xf5, 0x22, 0xd3, 0x2c, 0x65, 0x6a, 0xb4, 0x31, 0x64, 0xc8,
-	0xc4, 0x64, 0x7d, 0xb2, 0xa7, 0x24, 0xbb, 0x9f, 0x82, 0x86, 0x57, 0xad,
-	0x6b, 0x67, 0xc8, 0x9d, 0x9a, 0x0c, 0x69, 0x43, 0xc1, 0xfc, 0x40, 0x15,
-	0x6a, 0x57, 0xbe, 0xfe, 0x66, 0x41, 0xa0, 0x80, 0xb8, 0x2d, 0xfe, 0x64,
-	0xb4, 0x9f, 0xc4, 0xbf, 0xd3, 0xd7, 0x65, 0x6f, 0xd9, 0x16, 0xa9, 0xc7,
-	0xb6, 0xe6, 0x22, 0xa5, 0x39, 0xc9, 0x33, 0x64, 0x9f, 0xb2, 0x65, 0xdd,
-	0x14, 0x78, 0xcb, 0x8a, 0x56, 0x53, 0x1e, 0xf2, 0x9f, 0x6c, 0x5d, 0x29,
-	0x93, 0xdb, 0x33, 0xa4, 0x34, 0xdc, 0x25, 0x3a, 0x79, 0xd6, 0x8c, 0x93,
-	0x5d, 0x0b, 0xbe, 0x1e, 0x8b, 0xbd, 0x6d, 0x28, 0xf6, 0xb3, 0xca, 0x65,
-	0x4a, 0x39, 0xe3, 0x95, 0xd3, 0x3f, 0x62, 0xe7, 0xdf, 0x61, 0x62, 0xa1,
-	0xf0, 0x35, 0xc9, 0xa1, 0x9c, 0x78, 0xce, 0xa8, 0xc0, 0xb3, 0x5a, 0x96,
-	0xfb, 0x10, 0x53, 0xf0, 0x6a, 0x62, 0x5e, 0x86, 0x1e, 0x42, 0x0e, 0x69,
-	0xac, 0x3b, 0xaf, 0xfc, 0x3b, 0xf3, 0x2b, 0xe0, 0x95, 0x54, 0x3b, 0x1e,
-	0x95, 0x75, 0x3d, 0xa5, 0xa6, 0xa9, 0xd6, 0x21, 0xfd, 0xb5, 0x63, 0x5b,
-	0x5a, 0xda, 0x3a, 0x16, 0x3b, 0x60, 0xf4, 0xe7, 0x64, 0x15, 0xcc, 0x3c,
-	0x16, 0x7b, 0xce, 0x78, 0xdc, 0x9e, 0x3b, 0x79, 0x7e, 0xd6, 0x63, 0x0a,
-	0xb6, 0x14, 0x43, 0x25, 0x0f, 0x77, 0x18, 0x77, 0xc0, 0x51, 0xf1, 0x75,
-	0xda, 0x9e, 0xec, 0xbf, 0xb9, 0x13, 0xce, 0x0a, 0x17, 0x7d, 0xf3, 0x6e,
-	0xb8, 0x2a, 0x84, 0xfb, 0xe6, 0x79, 0x69, 0x94, 0xf7, 0x45, 0xb7, 0xe7,
-	0x6d, 0xdd, 0x3a, 0x89, 0xa7, 0xdd, 0x92, 0x27, 0x19, 0xe5, 0xd4, 0x91,
-	0xde, 0x42, 0x8e, 0x8c, 0x52, 0x62, 0x13, 0xe3, 0x90, 0xbb, 0x9c, 0x65,
-	0xde, 0xa3, 0xde, 0xe7, 0xf5, 0x96, 0x90, 0x13, 0x5b, 0xd6, 0x87, 0xe4,
-	0xc4, 0xf3, 0x03, 0xb5, 0x19, 0x83, 0xf1, 0x03, 0xb7, 0xe9, 0x4d, 0x71,
-	0xe6, 0x88, 0xab, 0x8d, 0xf3, 0x56, 0x6c, 0x95, 0x94, 0xd1, 0x7d, 0x31,
-	0x25, 0xdf, 0xc7, 0x02, 0xf8, 0xab, 0x2c, 0xb8, 0x22, 0xb2, 0x96, 0x2f,
-	0x6b, 0xb8, 0x0d, 0xf2, 0xcc, 0xb0, 0x59, 0xc6, 0xef, 0x92, 0x75, 0x41,
-	0x44, 0x27, 0x5c, 0x30, 0x32, 0x07, 0x65, 0xce, 0xa6, 0x5b, 0x08, 0x2c,
-	0xfc, 0x1d, 0x73, 0x0b, 0x99, 0x9f, 0x9a, 0x4c, 0x9d, 0x92, 0x09, 0xfa,
-	0xc8, 0x91, 0x9f, 0x80, 0xde, 0x9c, 0xa0, 0xae, 0x1b, 0x43, 0xb2, 0x0f,
-	0xc0, 0xe9, 0x4b, 0xc0, 0xe6, 0xc5, 0xe6, 0x69, 0x7c, 0x06, 0xa5, 0xcc,
-	0x05, 0xe7, 0x8e, 0xad, 0x40, 0x59, 0x45, 0xd4, 0x57, 0x8c, 0x6b, 0x78,
-	0xde, 0x46, 0xbe, 0xff, 0x05, 0x94, 0xad, 0x6c, 0x41, 0x82, 0x63, 0x2f,
-	0x35, 0xbe, 0xc4, 0x6b, 0x0f, 0xa3, 0x2f, 0xe9, 0xe2, 0x38, 0xfe, 0xd5,
-	0x2a, 0xab, 0x16, 0xd9, 0x4c, 0x6f, 0x09, 0xf3, 0xf4, 0xa8, 0xad, 0x0b,
-	0x62, 0x63, 0x52, 0xb8, 0x48, 0x6d, 0x74, 0x3d, 0x98, 0x2b, 0x57, 0xeb,
-	0x2d, 0x6d, 0x4a, 0x07, 0x6d, 0xb6, 0x9b, 0x3a, 0x97, 0xb2, 0x96, 0xb5,
-	0x3c, 0x30, 0x49, 0x1d, 0x77, 0xf0, 0xdc, 0xf0, 0xbf, 0x05, 0xf5, 0x9a,
-	0x42, 0x9c, 0xb2, 0xe2, 0x9a, 0x8f, 0x76, 0xa9, 0xae, 0x12, 0xde, 0xb2,
-	0x34, 0x74, 0xae, 0x44, 0xf6, 0x21, 0x67, 0xed, 0xf4, 0x68, 0x4e, 0x97,
-	0xe7, 0xef, 0xea, 0x36, 0x5e, 0xb5, 0xaf, 0x3b, 0xec, 0xeb, 0xe1, 0xdc,
-	0xf5, 0xa3, 0xbc, 0xfe, 0x3d, 0x5e, 0xef, 0xa1, 0xee, 0xd5, 0x2b, 0xa4,
-	0xfe, 0x5a, 0x53, 0xea, 0x33, 0x45, 0x31, 0xba, 0x73, 0xf3, 0xd1, 0xd1,
-	0x9a, 0x2d, 0xdb, 0xd3, 0x9a, 0x6d, 0xc3, 0xc9, 0x36, 0xe2, 0xd1, 0x62,
-	0x98, 0x28, 0x61, 0x9c, 0x3f, 0x6b, 0x88, 0x5c, 0x9c, 0xbb, 0xb4, 0xc8,
-	0xd5, 0xc6, 0xb8, 0xd2, 0xf5, 0x42, 0x31, 0xe2, 0x1d, 0x33, 0x6c, 0x3b,
-	0x3c, 0x7a, 0x97, 0xec, 0x8f, 0x7b, 0x5b, 0x69, 0xf0, 0xc9, 0xb6, 0xca,
-	0x24, 0x79, 0xe2, 0x43, 0xa6, 0x33, 0x5c, 0xe7, 0x98, 0x97, 0x29, 0x84,
-	0x11, 0x3b, 0xaf, 0x7c, 0x64, 0xe3, 0x43, 0x22, 0xd5, 0xc0, 0x4c, 0x26,
-	0x1e, 0x64, 0x0e, 0x12, 0x4c, 0x53, 0xb7, 0xad, 0x44, 0xec, 0xa3, 0xf6,
-	0x1e, 0x39, 0xe7, 0xc4, 0x0a, 0x34, 0xe8, 0x0e, 0xcc, 0x0b, 0xcf, 0x60,
-	0x26, 0x43, 0xbb, 0x34, 0x0b, 0x1d, 0xba, 0xff, 0x56, 0x7c, 0xc6, 0x23,
-	0xf5, 0x0e, 0xa6, 0x32, 0xeb, 0x8a, 0x39, 0xa7, 0xdf, 0xa0, 0x1c, 0xdb,
-	0x03, 0x22, 0xc7, 0xd7, 0x73, 0x72, 0xb4, 0x30, 0x66, 0x99, 0xda, 0xcd,
-	0x81, 0x9e, 0x0b, 0x7a, 0x7b, 0xc1, 0xd6, 0xdb, 0xc3, 0x3c, 0x2f, 0x64,
-	0xbe, 0x5c, 0x80, 0x13, 0x75, 0xde, 0xdc, 0x7e, 0x37, 0xc9, 0x7d, 0x04,
-	0x7f, 0xcf, 0x7c, 0x69, 0xb5, 0xa1, 0x87, 0x1d, 0x36, 0x67, 0x76, 0x23,
-	0x6e, 0xf3, 0x51, 0x79, 0x76, 0x5e, 0x86, 0xc7, 0xed, 0x72, 0x2e, 0xea,
-	0xa4, 0x04, 0x4f, 0xe4, 0xfc, 0x45, 0xf6, 0x2e, 0x7c, 0xc3, 0xfe, 0xbd,
-	0x97, 0x73, 0xeb, 0xa2, 0xaf, 0xe6, 0x63, 0x94, 0xac, 0x81, 0x6f, 0xb4,
-	0x7d, 0x7f, 0x08, 0xc7, 0xec, 0xff, 0x99, 0x6c, 0xfe, 0x82, 0x6e, 0x53,
-	0xf6, 0xfc, 0x94, 0x60, 0x93, 0x3c, 0x8b, 0x4c, 0x4b, 0x4e, 0x7d, 0x3d,
-	0xb6, 0x70, 0x54, 0x6e, 0x83, 0x1c, 0x43, 0x13, 0x9b, 0xe8, 0x44, 0x9f,
-	0x66, 0x7a, 0xd3, 0x75, 0x53, 0x73, 0x0f, 0x13, 0xfb, 0xeb, 0x7e, 0x6f,
-	0x45, 0xed, 0x7c, 0xe4, 0x94, 0x75, 0xc0, 0x38, 0x11, 0xa2, 0x07, 0xaf,
-	0x2b, 0xb0, 0xf5, 0x7b, 0xfe, 0x2e, 0x7b, 0x9f, 0x20, 0x65, 0x7e, 0x21,
-	0x21, 0x71, 0x74, 0x36, 0x52, 0xa6, 0xc8, 0xe6, 0x6c, 0xde, 0xc1, 0x39,
-	0xe9, 0x4e, 0x06, 0xa2, 0x57, 0xf2, 0xde, 0x04, 0x63, 0xd9, 0x26, 0xea,
-	0x33, 0xd6, 0x2c, 0x3c, 0xa8, 0x0d, 0x7b, 0x69, 0x63, 0xe3, 0xa6, 0x65,
-	0x1d, 0x24, 0x46, 0x94, 0xcf, 0x53, 0x91, 0xa9, 0x6e, 0x43, 0x92, 0xb1,
-	0xe9, 0xa0, 0xd1, 0xf0, 0x99, 0x02, 0xc4, 0xfd, 0x6e, 0xe8, 0xbe, 0xad,
-	0x1c, 0xcd, 0x43, 0x9c, 0xaf, 0x13, 0xa6, 0xf0, 0x33, 0xe7, 0xf9, 0xa5,
-	0x30, 0xc2, 0x8b, 0x1d, 0xff, 0x6a, 0x4d, 0xda, 0xcf, 0x51, 0xbb, 0xfe,
-	0x27, 0x65, 0x68, 0x17, 0xe7, 0x2d, 0xe7, 0x1c, 0xbf, 0x17, 0x90, 0xe7,
-	0xe0, 0x40, 0x6d, 0x6f, 0xc3, 0x3a, 0x91, 0xe1, 0x40, 0xc8, 0x19, 0x3b,
-	0x88, 0x40, 0xf3, 0x06, 0xe5, 0x22, 0x07, 0xbf, 0x72, 0xcc, 0xc4, 0x68,
-	0xdd, 0x8b, 0xe4, 0x0b, 0x52, 0xbf, 0x10, 0x4f, 0x9b, 0xcf, 0x5b, 0x35,
-	0xd3, 0xbf, 0x67, 0x1d, 0x32, 0xd4, 0xf5, 0xd4, 0x76, 0xac, 0x94, 0x6d,
-	0x95, 0xb0, 0xad, 0x7b, 0x03, 0xba, 0xb9, 0x83, 0x6d, 0x3d, 0x93, 0x38,
-	0x11, 0x74, 0xb3, 0xad, 0x27, 0x4c, 0xe1, 0xe0, 0xce, 0xa6, 0x26, 0xce,
-	0x6d, 0x57, 0x32, 0xe0, 0xdb, 0x46, 0xb9, 0x24, 0x37, 0xba, 0x33, 0x21,
-	0xef, 0x74, 0x7c, 0x9d, 0xe3, 0x89, 0xb6, 0xbb, 0xd0, 0xf0, 0x50, 0x19,
-	0xed, 0xa7, 0x1c, 0x79, 0x5b, 0xd7, 0x7d, 0xc4, 0x3b, 0xdc, 0xcb, 0x32,
-	0x6f, 0x06, 0x66, 0xe3, 0x95, 0x50, 0xc3, 0xca, 0xd9, 0x70, 0xc6, 0x0e,
-	0x29, 0x81, 0xa6, 0x0d, 0x4a, 0x5c, 0x13, 0x5b, 0xbc, 0x27, 0xa5, 0x07,
-	0x1b, 0x21, 0xd8, 0xdd, 0x42, 0x7d, 0xcc, 0xc6, 0x87, 0x0b, 0x45, 0x2e,
-	0x67, 0x38, 0xe8, 0x08, 0x74, 0x3c, 0xcf, 0xf9, 0x2d, 0x9b, 0x97, 0xcd,
-	0xfb, 0xd2, 0xf6, 0xbe, 0xce, 0x16, 0xf4, 0xa5, 0x4f, 0xbd, 0x77, 0xc0,
-	0x80, 0xf3, 0x68, 0xdd, 0xa3, 0x16, 0xec, 0x77, 0x40, 0x1a, 0x64, 0x1e,
-	0x5a, 0x64, 0x1e, 0x8a, 0xe9, 0x4f, 0x37, 0x51, 0xee, 0xf5, 0xb6, 0xdc,
-	0xb3, 0x31, 0x6c, 0xca, 0x7a, 0x92, 0x53, 0xbb, 0x07, 0x3d, 0xc4, 0xce,
-	0xc0, 0xf9, 0x2e, 0xf6, 0xf3, 0x26, 0x65, 0x9e, 0x47, 0xbd, 0x4f, 0x36,
-	0x0b, 0x3f, 0x7c, 0x18, 0xbd, 0xc9, 0xfc, 0x3b, 0x22, 0x0a, 0x52, 0x01,
-	0xe9, 0xe3, 0x61, 0xf2, 0xa5, 0x2e, 0x6b, 0xb2, 0x5a, 0xae, 0xef, 0x65,
-	0x2e, 0x1d, 0xd5, 0xe8, 0x0f, 0xd4, 0x3b, 0xf4, 0xd9, 0xd0, 0x27, 0xce,
-	0x38, 0xa2, 0xf4, 0x01, 0xd3, 0x7b, 0x9e, 0xd8, 0x70, 0x14, 0x1d, 0x16,
-	0x2a, 0x6c, 0x7b, 0xf8, 0xf9, 0x88, 0xf1, 0x0b, 0x45, 0x62, 0x7b, 0x86,
-	0x3a, 0x60, 0xb6, 0xdf, 0x2e, 0x3a, 0x28, 0xa5, 0xcf, 0x8e, 0x05, 0x74,
-	0xff, 0x2b, 0x94, 0x67, 0x07, 0xe5, 0x59, 0x91, 0x9d, 0x43, 0xdf, 0x16,
-	0x45, 0x7c, 0x3a, 0xd0, 0xbc, 0x9a, 0xd7, 0xb7, 0x53, 0x9e, 0x40, 0xaf,
-	0x82, 0xa1, 0xe6, 0x6e, 0xf2, 0xb1, 0x0e, 0xea, 0xe0, 0xa2, 0x3c, 0x6e,
-	0x7b, 0xce, 0x3a, 0xc8, 0x05, 0x0a, 0x99, 0xff, 0x0b, 0x7e, 0x6b, 0x18,
-	0xa6, 0x9d, 0xee, 0xe7, 0x8c, 0x44, 0xbd, 0x2a, 0x0a, 0x0d, 0xc1, 0x80,
-	0x6a, 0x5e, 0x73, 0x71, 0x6e, 0xca, 0x71, 0x48, 0xdb, 0x6b, 0xef, 0x69,
-	0xce, 0xe6, 0xea, 0x1f, 0x59, 0xa3, 0x5e, 0xe1, 0x67, 0xb2, 0xde, 0x24,
-	0x6b, 0x32, 0x71, 0x4f, 0x76, 0x4f, 0xb5, 0x8b, 0x3a, 0xc9, 0x5e, 0x7f,
-	0x41, 0x73, 0xe4, 0xf2, 0x66, 0xb9, 0xfe, 0x81, 0xf5, 0xac, 0x5d, 0x5e,
-	0xca, 0xb9, 0x6c, 0x2e, 0x5c, 0x6c, 0x97, 0xfb, 0xc0, 0x7a, 0x51, 0x73,
-	0x4e, 0x29, 0x97, 0x7f, 0x86, 0x77, 0xe2, 0x6b, 0x4e, 0x62, 0x5e, 0xe1,
-	0xdc, 0xc5, 0x38, 0x69, 0x9c, 0xaa, 0x39, 0x5d, 0xd7, 0xc9, 0x38, 0x36,
-	0x75, 0x1f, 0x98, 0x85, 0x27, 0xed, 0x1c, 0xb7, 0x6b, 0xbe, 0x03, 0x27,
-	0x76, 0x16, 0xd0, 0x27, 0xa3, 0x9a, 0xac, 0x87, 0x45, 0x4b, 0x72, 0x7b,
-	0x55, 0x24, 0x6f, 0x0c, 0xfa, 0xd5, 0xab, 0x6d, 0x6e, 0x18, 0x55, 0xff,
-	0xdc, 0x7e, 0x3b, 0xe1, 0x2e, 0x9d, 0xd8, 0x6f, 0xe4, 0x39, 0xcb, 0x89,
-	0x47, 0x55, 0xe2, 0xe4, 0x80, 0xb9, 0x58, 0x62, 0xb3, 0x9f, 0xf5, 0x83,
-	0x31, 0x75, 0x2a, 0xb7, 0x59, 0xed, 0x41, 0x59, 0xd7, 0x36, 0x07, 0x64,
-	0x9f, 0xa9, 0xec, 0x19, 0x95, 0xbe, 0x8a, 0x72, 0xeb, 0x3c, 0x9f, 0xc4,
-	0x35, 0xf2, 0x7d, 0x09, 0xdf, 0xf8, 0x20, 0xc7, 0xdd, 0xf4, 0x60, 0xd4,
-	0x96, 0xf3, 0x57, 0xd6, 0x4a, 0x2d, 0x33, 0x43, 0xc3, 0xa5, 0xb2, 0x47,
-	0x73, 0xb2, 0xc7, 0x3e, 0x71, 0x9d, 0x4a, 0xfa, 0x99, 0xda, 0x66, 0x7e,
-	0x4f, 0xb7, 0xac, 0x61, 0xca, 0x3d, 0x05, 0x5d, 0xc4, 0xa1, 0xa8, 0xd6,
-	0xc0, 0x38, 0xaf, 0xfb, 0xd6, 0x70, 0x3e, 0xe2, 0x5e, 0xd9, 0xcb, 0x9e,
-	0x8f, 0x91, 0x85, 0xc8, 0xae, 0x25, 0xca, 0x7e, 0x87, 0xec, 0xfa, 0x21,
-	0xed, 0x1e, 0x5d, 0xa9, 0xdf, 0x59, 0x19, 0xaf, 0x93, 0xb1, 0xf0, 0xe2,
-	0x3e, 0xea, 0x21, 0xea, 0x55, 0xd6, 0x41, 0xb6, 0x5c, 0x58, 0xab, 0x90,
-	0x35, 0x1a, 0x89, 0xbd, 0xbf, 0xb5, 0x5a, 0x2f, 0x29, 0x3b, 0x75, 0x4f,
-	0x79, 0x75, 0x4c, 0x9e, 0x83, 0x8d, 0xe6, 0xd6, 0xb1, 0x1b, 0xff, 0xe0,
-	0x39, 0xd8, 0x04, 0x6d, 0x09, 0xd1, 0x2d, 0xe4, 0x76, 0x71, 0x74, 0x63,
-	0x34, 0x51, 0xab, 0x6d, 0x85, 0x26, 0xeb, 0xb7, 0xfc, 0xeb, 0xc6, 0xa1,
-	0x04, 0xa2, 0x05, 0x57, 0x95, 0x93, 0x6f, 0x21, 0xea, 0x60, 0x8c, 0x7a,
-	0x22, 0x51, 0xdb, 0xb4, 0x9d, 0x63, 0xf2, 0xaf, 0xec, 0xc6, 0x70, 0xa2,
-	0xe1, 0x4b, 0x8c, 0x23, 0xfe, 0x12, 0x9b, 0xeb, 0x44, 0xff, 0xcb, 0x01,
-	0xe2, 0xc0, 0xe6, 0xdc, 0x1a, 0x52, 0x6b, 0xe2, 0xd7, 0x94, 0xdf, 0x16,
-	0x92, 0xf5, 0xfe, 0x54, 0xb9, 0x09, 0xe6, 0xd3, 0xa7, 0xb0, 0xb6, 0x5f,
-	0xc1, 0xb3, 0xc6, 0x29, 0xac, 0x19, 0x12, 0x79, 0x4e, 0xa1, 0xad, 0xff,
-	0xfb, 0xd8, 0xdf, 0x3f, 0x1d, 0x8d, 0xb6, 0x6e, 0x3a, 0xb0, 0x61, 0xd7,
-	0x11, 0xec, 0x48, 0x5a, 0xd8, 0x1e, 0xf2, 0x60, 0xfd, 0x3e, 0x05, 0xcb,
-	0x03, 0xc7, 0xb0, 0x75, 0x97, 0x85, 0x39, 0xa1, 0x4e, 0x34, 0x99, 0x25,
-	0x28, 0xac, 0x98, 0xb7, 0x4e, 0x65, 0xb9, 0xd6, 0xe1, 0x8e, 0xdc, 0xfe,
-	0xe5, 0x43, 0xc4, 0x02, 0x15, 0x3e, 0x43, 0xf6, 0x26, 0x47, 0x95, 0xdb,
-	0xd3, 0x8d, 0x4a, 0x4b, 0xee, 0x39, 0xe2, 0xad, 0xe9, 0x8f, 0x99, 0xff,
-	0xc4, 0xb1, 0x3f, 0x74, 0x0a, 0x43, 0x43, 0xbf, 0x2e, 0xcd, 0xfa, 0xcb,
-	0x04, 0xb9, 0x83, 0xe4, 0x1c, 0x26, 0x6d, 0xea, 0x4f, 0xbd, 0x37, 0x24,
-	0x76, 0x37, 0x89, 0x9f, 0x0e, 0x9e, 0xc6, 0xe9, 0xc1, 0x7f, 0xc1, 0x12,
-	0x4d, 0xf2, 0x34, 0xab, 0xd3, 0x19, 0xb1, 0xac, 0x3d, 0xf5, 0x71, 0xab,
-	0xda, 0x78, 0xab, 0x0c, 0xc5, 0x65, 0x98, 0x16, 0x79, 0x0d, 0xdb, 0x35,
-	0xb6, 0x95, 0x3c, 0x84, 0x9d, 0x8c, 0xeb, 0xbe, 0xc8, 0x1d, 0xf0, 0x25,
-	0x33, 0x66, 0x25, 0xa2, 0x3b, 0x2b, 0xa1, 0xb7, 0x57, 0x38, 0x8c, 0x8e,
-	0x7f, 0x56, 0xea, 0x70, 0x6b, 0xfa, 0x34, 0x7e, 0x31, 0x68, 0xef, 0xc9,
-	0x6a, 0xf9, 0xb6, 0x62, 0x75, 0x6e, 0x0f, 0xe9, 0x4d, 0xff, 0x55, 0x89,
-	0xc6, 0x65, 0x2f, 0x4f, 0x11, 0x73, 0x82, 0xdb, 0x06, 0x25, 0xdf, 0x6c,
-	0x81, 0xbb, 0x57, 0xcf, 0x2c, 0x25, 0xcf, 0xfe, 0xca, 0x82, 0xf8, 0x8c,
-	0x2a, 0xda, 0xa5, 0x43, 0xd1, 0x83, 0x86, 0xda, 0x89, 0xe3, 0xa6, 0x3e,
-	0xf1, 0x5b, 0x87, 0x31, 0xf4, 0x2d, 0xd4, 0x61, 0x55, 0x5a, 0x1f, 0xba,
-	0x86, 0x79, 0xd8, 0xd6, 0x3e, 0x13, 0xc9, 0x3e, 0xbd, 0xa5, 0xc3, 0xd1,
-	0x83, 0xfb, 0x02, 0x35, 0xed, 0xef, 0x91, 0xcb, 0x79, 0x88, 0x29, 0x7d,
-	0xe3, 0x23, 0xcc, 0x13, 0x7b, 0xb0, 0x61, 0x5f, 0x04, 0xeb, 0xf7, 0x98,
-	0xe8, 0xee, 0x1b, 0xa1, 0x6c, 0x2f, 0x95, 0xca, 0x1e, 0x96, 0xe6, 0x50,
-	0xfc, 0x66, 0x15, 0x81, 0x28, 0xfb, 0x6c, 0x50, 0x23, 0x01, 0xbf, 0xaa,
-	0x30, 0xfa, 0x8f, 0x3b, 0xb1, 0x89, 0x65, 0x7a, 0x93, 0xb4, 0xb9, 0x3e,
-	0x37, 0xe3, 0xe5, 0x4c, 0x0c, 0x8f, 0xf9, 0x70, 0x70, 0xcc, 0x83, 0xa1,
-	0x31, 0x8d, 0x47, 0x31, 0x1e, 0x1b, 0x90, 0xbd, 0x20, 0x5e, 0x3c, 0x7d,
-	0xc0, 0x8d, 0xcd, 0xbb, 0x3d, 0x98, 0x1d, 0x99, 0x86, 0x03, 0x07, 0x8a,
-	0xb1, 0x97, 0xd7, 0x2b, 0x16, 0xfa, 0xf1, 0x24, 0xaf, 0xf7, 0xef, 0x76,
-	0x71, 0x1e, 0xe6, 0xe0, 0x30, 0x0d, 0x7b, 0x68, 0xac, 0x04, 0xc9, 0x01,
-	0x9a, 0x3c, 0x39, 0xeb, 0xdb, 0xcc, 0x30, 0x46, 0x0f, 0x30, 0x36, 0xee,
-	0x33, 0x91, 0x60, 0x3f, 0x3b, 0xa8, 0xab, 0x6e, 0xe2, 0xda, 0x86, 0x31,
-	0xc1, 0xf8, 0x55, 0xb8, 0xa9, 0x57, 0x6f, 0x6a, 0x54, 0x8c, 0xe8, 0x22,
-	0x7b, 0xbf, 0x97, 0xbc, 0xdf, 0xb5, 0x0a, 0x0d, 0x09, 0xdd, 0x6c, 0x44,
-	0x27, 0x4e, 0x72, 0xdc, 0xff, 0x17, 0xfd, 0x76, 0xb1, 0x43, 0xef, 0xb9,
-	0x51, 0x3d, 0x82, 0x9d, 0xe9, 0xa3, 0xe4, 0xea, 0x40, 0x78, 0xff, 0x11,
-	0xf2, 0xb7, 0xe3, 0xc4, 0x9f, 0x37, 0x2d, 0x9f, 0xa1, 0xe2, 0xd6, 0x47,
-	0x8c, 0xf0, 0xfb, 0x4a, 0xa0, 0xfd, 0x57, 0xd4, 0xc1, 0x67, 0x0f, 0xa8,
-	0xb8, 0x65, 0xe7, 0x62, 0xa4, 0x42, 0x51, 0xec, 0x58, 0xa4, 0xe2, 0xe6,
-	0x7d, 0x47, 0x88, 0xfb, 0x13, 0x36, 0x4f, 0xce, 0xa4, 0x1e, 0x46, 0xb0,
-	0x57, 0xd6, 0xb8, 0xdd, 0x8c, 0xdf, 0xa5, 0x78, 0xa6, 0x9f, 0x39, 0xb4,
-	0x59, 0x8a, 0x13, 0x43, 0x47, 0x68, 0x8f, 0xa5, 0x38, 0xde, 0x6f, 0x4c,
-	0xfc, 0xd4, 0x51, 0x8a, 0xa7, 0x79, 0xbe, 0x93, 0xe7, 0x0b, 0x07, 0x8c,
-	0xfe, 0x0e, 0xb5, 0x14, 0x0b, 0xf6, 0xd7, 0xa3, 0xbf, 0x4f, 0x6c, 0x53,
-	0x43, 0xfb, 0x58, 0x5d, 0x4e, 0xf7, 0xa2, 0x73, 0x2f, 0x36, 0x52, 0x57,
-	0xf7, 0xed, 0xec, 0x64, 0x7f, 0x3e, 0xea, 0xfc, 0x08, 0x1e, 0x63, 0x5e,
-	0xb7, 0xbd, 0xcf, 0x87, 0x73, 0x49, 0xc3, 0xff, 0x45, 0xc5, 0x30, 0x8b,
-	0x94, 0x80, 0xf6, 0x0c, 0x7c, 0x38, 0x9d, 0x2e, 0xc6, 0xa6, 0x81, 0x99,
-	0xf8, 0x29, 0xed, 0xf3, 0xd1, 0xdd, 0xd2, 0xdf, 0x04, 0xe3, 0xc3, 0x2c,
-	0x3c, 0x3d, 0x62, 0xb2, 0x6d, 0x99, 0x27, 0x89, 0x39, 0xdd, 0x70, 0x25,
-	0xc5, 0x37, 0xa2, 0x3b, 0x69, 0x16, 0xc4, 0xc4, 0x63, 0x48, 0xf7, 0xeb,
-	0x3d, 0xb7, 0xa9, 0xc2, 0xab, 0x55, 0xea, 0xd2, 0x81, 0x49, 0x4d, 0x8f,
-	0x57, 0xa8, 0xf1, 0x7e, 0xe6, 0xaf, 0xf1, 0x4a, 0xf5, 0x18, 0x9e, 0xee,
-	0x77, 0x62, 0xde, 0x42, 0x95, 0xd7, 0xe3, 0xe7, 0x19, 0xdb, 0xe2, 0xb3,
-	0x55, 0x13, 0x7b, 0x6d, 0x59, 0x11, 0x2f, 0x20, 0xb7, 0x2f, 0x5f, 0x58,
-	0xc3, 0xf8, 0xe5, 0x10, 0xdb, 0x8b, 0x95, 0xaa, 0x4e, 0xea, 0xfd, 0x34,
-	0x46, 0x68, 0xd7, 0x4f, 0xf0, 0x38, 0x3c, 0x68, 0x75, 0x2e, 0x27, 0xe7,
-	0x9e, 0x13, 0xb0, 0x3a, 0x6f, 0x33, 0x0d, 0x5f, 0x81, 0x1a, 0x88, 0x7e,
-	0x05, 0xa7, 0x71, 0x68, 0x44, 0xca, 0xc0, 0xed, 0x8d, 0x30, 0xaf, 0xee,
-	0xb3, 0x3a, 0x77, 0x9a, 0x73, 0x50, 0x6f, 0xe7, 0xc6, 0x3f, 0x2f, 0xcd,
-	0x62, 0xa6, 0xf8, 0x91, 0xbd, 0xa7, 0x0a, 0xbf, 0x62, 0x3b, 0xef, 0x0f,
-	0x96, 0xa3, 0xaa, 0x52, 0xfc, 0xe0, 0x14, 0xde, 0xe9, 0x7f, 0x0d, 0xe7,
-	0xfa, 0x2d, 0x2c, 0x08, 0x59, 0x70, 0x86, 0x6a, 0xcd, 0x46, 0xf5, 0x1a,
-	0x62, 0x84, 0x82, 0x9b, 0xe6, 0x7e, 0x1f, 0xef, 0xd2, 0xff, 0x6f, 0x9e,
-	0x6b, 0xd9, 0xb2, 0xf4, 0x62, 0xa1, 0xb5, 0xa3, 0x5a, 0xfc, 0xc6, 0xb4,
-	0xf7, 0xd3, 0xfc, 0xe9, 0x3c, 0x38, 0xbf, 0xaf, 0x4b, 0x72, 0xe1, 0xd3,
-	0x18, 0x1e, 0x34, 0xa2, 0x6b, 0xf3, 0x72, 0xf6, 0x9f, 0xa6, 0x0e, 0x2c,
-	0xec, 0x34, 0x4f, 0xec, 0xab, 0xc0, 0xbc, 0xf3, 0xcc, 0x1a, 0xaf, 0x9b,
-	0x4d, 0xdb, 0x59, 0xb0, 0x30, 0x60, 0x2e, 0x53, 0xff, 0x37, 0xfd, 0xf4,
-	0x34, 0x0e, 0x0e, 0xe5, 0xf1, 0xda, 0x87, 0x46, 0xfa, 0x79, 0x76, 0xcf,
-	0xbb, 0x17, 0x0d, 0xc9, 0xa3, 0xf6, 0xfa, 0xc3, 0x61, 0xe2, 0x63, 0xf6,
-	0x19, 0xa1, 0x86, 0x91, 0x74, 0x23, 0xb1, 0x21, 0x8a, 0xef, 0xa6, 0x23,
-	0xc4, 0x87, 0x30, 0xf1, 0xa1, 0x9e, 0xf8, 0x60, 0x12, 0x1f, 0xea, 0x88,
-	0x0f, 0x41, 0xfb, 0xd9, 0xb9, 0xac, 0x47, 0x0f, 0x8d, 0xbe, 0x86, 0x82,
-	0x81, 0x53, 0x70, 0x0d, 0xc8, 0x3e, 0x35, 0x8b, 0xfc, 0xa4, 0x56, 0x6b,
-	0xc3, 0x1c, 0x45, 0xf6, 0x0c, 0x0e, 0xa5, 0x4f, 0xa1, 0x68, 0x40, 0xe3,
-	0x58, 0x64, 0xaf, 0x40, 0x4d, 0xb8, 0x87, 0x58, 0xfd, 0x6b, 0xa3, 0xb6,
-	0xc7, 0x8b, 0xda, 0xbd, 0xd5, 0x30, 0xfa, 0x17, 0xaa, 0x73, 0x95, 0xe8,
-	0xe7, 0xbc, 0x1c, 0x67, 0x25, 0x66, 0xed, 0xd6, 0x30, 0x9b, 0xc7, 0x3f,
-	0x25, 0x6b, 0x26, 0xde, 0x74, 0xc0, 0x3b, 0x9d, 0x74, 0x67, 0x06, 0x99,
-	0x00, 0x59, 0xad, 0xd7, 0x87, 0x2b, 0x0f, 0x9f, 0x56, 0x15, 0x64, 0x3e,
-	0x27, 0x31, 0xaf, 0x36, 0xd8, 0xad, 0x32, 0x5b, 0xd7, 0x04, 0xc3, 0x79,
-	0xa8, 0x88, 0x90, 0x45, 0xcc, 0x64, 0x7e, 0x61, 0xb5, 0x99, 0x45, 0xd8,
-	0x52, 0xa7, 0xca, 0x7e, 0x8d, 0xa3, 0x12, 0xa3, 0xa6, 0x33, 0x46, 0x14,
-	0xf7, 0xc5, 0xef, 0x99, 0x0e, 0x0f, 0x8a, 0xfa, 0x2c, 0xeb, 0x1b, 0x21,
-	0x0d, 0x9e, 0x48, 0x20, 0xba, 0x81, 0x69, 0xe4, 0xe7, 0xe6, 0x85, 0x71,
-	0x53, 0xfa, 0x30, 0x06, 0x38, 0xbe, 0xe5, 0xe9, 0xfc, 0xbb, 0x9c, 0x7f,
-	0xfa, 0xef, 0xe2, 0x3b, 0xa1, 0x57, 0xee, 0x9d, 0x0e, 0x43, 0x7b, 0x40,
-	0xed, 0x28, 0x27, 0x07, 0x3f, 0xcc, 0xb8, 0xa7, 0x4c, 0x7e, 0x5e, 0x41,
-	0xcb, 0x40, 0x1c, 0x55, 0xa1, 0x53, 0x4a, 0x4c, 0xf6, 0x32, 0x29, 0x95,
-	0xf8, 0xfc, 0x6e, 0xea, 0x7a, 0x41, 0x86, 0xb6, 0xe2, 0xc3, 0xb7, 0x46,
-	0x45, 0xb7, 0x35, 0x43, 0x3b, 0x39, 0x8e, 0x37, 0xe6, 0x1e, 0x16, 0x9c,
-	0x3c, 0x32, 0x0b, 0x8e, 0x23, 0xd3, 0x98, 0x9b, 0xd6, 0xcc, 0xbd, 0xf2,
-	0xfc, 0xbf, 0xa8, 0xa2, 0x17, 0x85, 0xd8, 0xa1, 0xf7, 0xc7, 0xd8, 0xf6,
-	0x07, 0x8e, 0xc3, 0xd8, 0x44, 0x0c, 0x3e, 0x9a, 0xfe, 0x0e, 0x75, 0x79,
-	0x28, 0x97, 0x2f, 0xad, 0x42, 0xa2, 0x57, 0xf6, 0xe3, 0x9d, 0xc2, 0xac,
-	0x01, 0xbd, 0x79, 0x9b, 0x62, 0x04, 0x6f, 0x56, 0x4e, 0x61, 0xc6, 0x40,
-	0x90, 0x73, 0xa9, 0x61, 0x59, 0x5f, 0x1e, 0x3f, 0x05, 0x83, 0x57, 0x11,
-	0x83, 0xad, 0xc5, 0x3f, 0x35, 0xe3, 0xcc, 0x71, 0x74, 0xd3, 0xa9, 0xe8,
-	0x2d, 0x73, 0x15, 0xd9, 0x9b, 0x63, 0x9c, 0x6f, 0x65, 0x1d, 0xcf, 0x40,
-	0x1d, 0xee, 0xe4, 0x98, 0x9b, 0x38, 0x6f, 0xaf, 0x2d, 0xb4, 0xb0, 0x68,
-	0xa1, 0xbe, 0xb7, 0xc8, 0x11, 0x7d, 0xa0, 0x02, 0x99, 0x8e, 0x6a, 0xda,
-	0xcd, 0x7d, 0x0b, 0xf4, 0xf0, 0xab, 0xc4, 0x5d, 0xe2, 0x34, 0x36, 0x31,
-	0xee, 0xb4, 0x31, 0x16, 0x15, 0x47, 0xf4, 0x1e, 0xe6, 0xa8, 0xef, 0xdf,
-	0xed, 0x88, 0x86, 0xe4, 0x7d, 0xa3, 0x7f, 0xc0, 0x62, 0xb8, 0x43, 0x65,
-	0xc4, 0x41, 0x3d, 0xf3, 0x1a, 0xf4, 0xbd, 0x77, 0x92, 0x93, 0xfe, 0x84,
-	0xfc, 0xae, 0xfa, 0xaa, 0xa3, 0xc4, 0xa8, 0x11, 0x3c, 0x9a, 0x3e, 0x82,
-	0xbd, 0xe9, 0x14, 0x76, 0xa5, 0x77, 0x28, 0x43, 0xf6, 0xb3, 0x3a, 0x45,
-	0xde, 0xad, 0x8b, 0x96, 0x29, 0x5f, 0x46, 0x69, 0xe8, 0x9b, 0xd6, 0x50,
-	0x85, 0x8a, 0xf2, 0x50, 0x10, 0x37, 0xf5, 0xc5, 0xe1, 0x88, 0xbc, 0x67,
-	0xc9, 0x7b, 0xd9, 0xeb, 0xc7, 0x0d, 0xdc, 0xd8, 0x57, 0x8c, 0xd8, 0x7e,
-	0xcb, 0xea, 0xa9, 0x77, 0x62, 0xcd, 0x78, 0x1d, 0x96, 0x0d, 0x3c, 0x66,
-	0xcd, 0x66, 0xcc, 0xf9, 0xf8, 0x5a, 0x0f, 0xee, 0xde, 0xef, 0x41, 0x6b,
-	0x5f, 0x14, 0xbe, 0x48, 0x09, 0x7f, 0x07, 0xcc, 0x25, 0x30, 0x26, 0x26,
-	0x60, 0xf4, 0xdc, 0xe0, 0x08, 0x1c, 0x0a, 0xab, 0x1e, 0x7c, 0x95, 0x38,
-	0xbe, 0x9c, 0xb8, 0x13, 0x1b, 0xb7, 0x50, 0x1e, 0xf1, 0xe2, 0x1e, 0xd6,
-	0xbf, 0x85, 0x73, 0xff, 0xee, 0xa2, 0x43, 0xc4, 0x02, 0xd9, 0x83, 0xa8,
-	0x61, 0xc3, 0xb8, 0x9b, 0xba, 0x72, 0x23, 0x76, 0xb0, 0x12, 0x37, 0xee,
-	0xf6, 0xe3, 0xee, 0x71, 0x0f, 0x1a, 0xfa, 0xac, 0xc5, 0x87, 0xcd, 0xf8,
-	0x4a, 0x0d, 0x06, 0x5a, 0xc7, 0xbd, 0xf8, 0xdb, 0x3e, 0xdd, 0x77, 0x33,
-	0x73, 0xfe, 0x11, 0x33, 0x88, 0xbf, 0x1f, 0xf7, 0xe1, 0xf6, 0xbe, 0x13,
-	0x92, 0x47, 0x2e, 0x71, 0x32, 0xf6, 0x3c, 0x34, 0x3e, 0x13, 0x2b, 0xfb,
-	0xf4, 0xf3, 0x13, 0xe4, 0x76, 0x9d, 0x07, 0x4d, 0x3c, 0x30, 0xae, 0xa2,
-	0x85, 0xed, 0x7c, 0xbe, 0x6f, 0x16, 0x3a, 0x0e, 0xd6, 0x53, 0x86, 0x85,
-	0x58, 0x3e, 0xe0, 0x84, 0x49, 0x16, 0x8f, 0x2f, 0x00, 0xcd, 0x03, 0x13,
-	0xcc, 0xe3, 0x1e, 0xc6, 0x8e, 0x5e, 0x13, 0xf7, 0x8e, 0xcb, 0xf9, 0x11,
-	0xfb, 0x5d, 0xd8, 0xf7, 0xf7, 0x2d, 0xc4, 0x67, 0x07, 0x54, 0xe2, 0x40,
-	0x21, 0x86, 0x56, 0x2a, 0xf8, 0x5b, 0x5e, 0xdf, 0x96, 0x94, 0xbd, 0xcc,
-	0x40, 0x68, 0x67, 0xe0, 0x50, 0x05, 0x39, 0xc3, 0xa2, 0x7d, 0xd9, 0xeb,
-	0x8f, 0x12, 0xe7, 0x8b, 0x88, 0xf3, 0x25, 0xe4, 0xb0, 0x37, 0x0c, 0x1f,
-	0xc1, 0x23, 0xc4, 0xe5, 0xa3, 0x03, 0x9d, 0x8c, 0x3b, 0xa5, 0x78, 0x92,
-	0x71, 0xa0, 0x8f, 0xe7, 0xa7, 0x76, 0x1a, 0x1d, 0x45, 0xc4, 0xe9, 0x57,
-	0x89, 0xbf, 0x3d, 0xc4, 0x8c, 0xfb, 0xfa, 0x18, 0xee, 0x77, 0x32, 0x07,
-	0xb8, 0x2a, 0x3a, 0xdf, 0xc3, 0x1c, 0xeb, 0x66, 0x25, 0xe0, 0x7b, 0x0b,
-	0xa5, 0x70, 0xec, 0xab, 0x44, 0xc3, 0x6e, 0x29, 0x23, 0xf8, 0xa5, 0x42,
-	0x3d, 0xe0, 0xa4, 0xce, 0x8f, 0xc1, 0xea, 0x77, 0x70, 0xbc, 0x35, 0x26,
-	0x19, 0x38, 0xde, 0x30, 0x75, 0xed, 0xbb, 0xc4, 0xda, 0x0f, 0x89, 0xa9,
-	0xfe, 0xe9, 0xf5, 0x68, 0x34, 0x4c, 0x1e, 0xc7, 0x70, 0xba, 0xdf, 0x30,
-	0x65, 0x9f, 0xdc, 0x9b, 0xe4, 0x79, 0x93, 0xd3, 0x19, 0x33, 0x0d, 0xf1,
-	0xc3, 0x11, 0x8e, 0x47, 0x95, 0xbc, 0x04, 0x8e, 0x31, 0xe0, 0x9d, 0x7d,
-	0x8b, 0x39, 0x2e, 0x89, 0xa5, 0x12, 0xef, 0x46, 0x28, 0xeb, 0x62, 0xac,
-	0xa0, 0x3e, 0x1a, 0xfb, 0x54, 0xa4, 0x0e, 0x46, 0x70, 0xef, 0x9e, 0x6c,
-	0x1c, 0x6e, 0x0f, 0xc5, 0x6f, 0x63, 0x1c, 0x0e, 0x17, 0x33, 0x0e, 0xbb,
-	0x22, 0x22, 0x9b, 0x13, 0xc3, 0x8c, 0xdb, 0x5b, 0x92, 0x61, 0x34, 0x71,
-	0x0e, 0x27, 0x52, 0xec, 0xb7, 0x6f, 0x26, 0x9e, 0x49, 0x79, 0x18, 0xb3,
-	0x34, 0x1e, 0x44, 0xb5, 0x91, 0x69, 0x3c, 0xfc, 0x3c, 0xe6, 0xf0, 0x30,
-	0xec, 0x6b, 0x6d, 0x7d, 0x0a, 0xe2, 0xcd, 0xd9, 0xe7, 0x65, 0xcf, 0xa4,
-	0x04, 0x9b, 0x65, 0x2d, 0xf3, 0xde, 0x72, 0xd9, 0xfb, 0xd9, 0x9f, 0xfc,
-	0x3e, 0xca, 0x89, 0x4f, 0x65, 0x39, 0x1c, 0xfa, 0x79, 0x48, 0x70, 0xb7,
-	0x86, 0xb8, 0x2b, 0xfb, 0x73, 0x2c, 0x6b, 0x55, 0x60, 0x2a, 0x1e, 0xfd,
-	0xef, 0x8f, 0xa3, 0xf6, 0x7e, 0x56, 0xc1, 0x24, 0xe2, 0x5f, 0x92, 0xf8,
-	0xc7, 0x31, 0x74, 0x5d, 0x4f, 0x0c, 0xa4, 0x4c, 0xff, 0x98, 0x24, 0x06,
-	0x12, 0xa7, 0x8f, 0x10, 0xa7, 0x9f, 0x22, 0x4e, 0x7f, 0x93, 0x38, 0xfd,
-	0x24, 0x31, 0x21, 0xbb, 0xa6, 0xd7, 0x24, 0xcf, 0x2f, 0x38, 0x1f, 0xef,
-	0xd9, 0x6b, 0x8b, 0xd5, 0xd4, 0xd5, 0xac, 0x01, 0x79, 0xe7, 0x47, 0x3f,
-	0x24, 0x76, 0xff, 0x13, 0xce, 0x93, 0xbf, 0x2a, 0xbb, 0xef, 0xaa, 0xb1,
-	0xaf, 0x1b, 0xee, 0xbe, 0x5a, 0xad, 0x07, 0xf6, 0xb7, 0x02, 0x4c, 0xe1,
-	0xa2, 0x05, 0x7d, 0x6d, 0x70, 0xf4, 0xd5, 0x1e, 0x3a, 0x29, 0xcf, 0x43,
-	0xa7, 0x49, 0x5e, 0xdf, 0x26, 0x7b, 0xbd, 0x0f, 0xc9, 0x7e, 0xad, 0x65,
-	0xbc, 0xe7, 0xea, 0xab, 0x35, 0xdf, 0x82, 0x8d, 0x6d, 0xfe, 0x49, 0xfb,
-	0x5e, 0xcd, 0xfb, 0x8f, 0x50, 0x5f, 0x19, 0xb6, 0x99, 0x4a, 0xca, 0x7e,
-	0xd4, 0x99, 0x78, 0x22, 0x2d, 0xbf, 0x6b, 0x5b, 0x12, 0xea, 0xe3, 0x88,
-	0x55, 0x0b, 0x1f, 0x0f, 0xe3, 0xd6, 0x3e, 0x0f, 0xed, 0x20, 0x8e, 0x32,
-	0xfa, 0xd6, 0xfd, 0xe3, 0xf5, 0xf4, 0xb5, 0xc7, 0x2c, 0x2d, 0x12, 0x68,
-	0x19, 0x27, 0xe7, 0x59, 0x3f, 0xbe, 0x18, 0x4b, 0x07, 0x2c, 0xcb, 0x73,
-	0x8d, 0x11, 0xde, 0xa0, 0xf8, 0xe1, 0xa2, 0x0f, 0x3a, 0xe8, 0x57, 0x6b,
-	0xf7, 0x07, 0xb4, 0xb7, 0x88, 0xa7, 0xeb, 0xea, 0x0f, 0xd3, 0x3e, 0x8c,
-	0xf3, 0x4d, 0xc4, 0x52, 0x67, 0x24, 0xc0, 0x3c, 0xd1, 0x43, 0xdb, 0xf7,
-	0xe2, 0x7c, 0x42, 0xfc, 0x4b, 0xef, 0xf8, 0x2e, 0x73, 0x93, 0x0e, 0xfa,
-	0xc6, 0x07, 0x89, 0xeb, 0xe9, 0x4b, 0x61, 0x1e, 0x33, 0xe9, 0x0b, 0x6e,
-	0xbc, 0x93, 0x30, 0xe8, 0x77, 0x1e, 0xbc, 0x9b, 0xa8, 0x63, 0x9f, 0x41,
-	0x96, 0xf5, 0x63, 0xa3, 0xfd, 0xde, 0x75, 0x4d, 0xfc, 0x5b, 0x4a, 0x4d,
-	0xff, 0x2c, 0xb5, 0x02, 0xd1, 0x4a, 0x0d, 0x7f, 0x37, 0xfe, 0x37, 0xf8,
-	0x19, 0xe3, 0xf6, 0x9a, 0x3e, 0x70, 0x0e, 0x11, 0x22, 0x0f, 0x9c, 0x38,
-	0x28, 0xcf, 0xe9, 0x50, 0x1b, 0x9d, 0xeb, 0xd0, 0x99, 0xdb, 0xea, 0x99,
-	0x73, 0x0e, 0x27, 0xfb, 0x24, 0x2b, 0x66, 0xd9, 0x0f, 0xfa, 0x8b, 0xf1,
-	0xc0, 0xfe, 0xc3, 0xf4, 0x91, 0x02, 0x2c, 0x78, 0xc4, 0x8d, 0xbf, 0x3b,
-	0x38, 0x22, 0x6b, 0x4b, 0x82, 0x99, 0xfe, 0x21, 0x12, 0x85, 0x30, 0xb9,
-	0xde, 0xfd, 0x7b, 0x46, 0x30, 0x90, 0xe3, 0x79, 0x1f, 0x84, 0xe2, 0x5f,
-	0x51, 0x71, 0x98, 0x3c, 0x22, 0x10, 0xbf, 0x9a, 0x36, 0x26, 0xef, 0xb8,
-	0x49, 0xec, 0x5f, 0x41, 0x1b, 0xeb, 0xe6, 0x7c, 0x7e, 0x83, 0xe3, 0xd8,
-	0x41, 0x1b, 0x1b, 0x4d, 0xcc, 0xc4, 0x56, 0xda, 0x58, 0x9c, 0x36, 0x16,
-	0xa7, 0x3d, 0xc5, 0x69, 0x63, 0xf2, 0x6e, 0x7e, 0x9c, 0x36, 0x16, 0xa7,
-	0x8d, 0xc5, 0x53, 0x8b, 0xf1, 0x14, 0x99, 0xc6, 0xae, 0x91, 0x45, 0xc4,
-	0x31, 0x79, 0xb6, 0xc6, 0x79, 0xb8, 0xed, 0x6f, 0xc8, 0xd9, 0x6f, 0xe0,
-	0xa1, 0xe0, 0x4e, 0xfa, 0xe4, 0x63, 0x43, 0xc4, 0x3b, 0xda, 0xc1, 0xa2,
-	0xb4, 0x70, 0xfc, 0x7a, 0xe6, 0xb1, 0xc7, 0xc8, 0xf3, 0x55, 0x3c, 0x6b,
-	0x4a, 0x1e, 0x6c, 0xf2, 0x9c, 0xb1, 0x26, 0x29, 0x1c, 0xec, 0x18, 0x36,
-	0xf4, 0x03, 0x37, 0x91, 0x17, 0x56, 0x92, 0x97, 0x8c, 0x2c, 0x00, 0x5e,
-	0x1c, 0x12, 0x19, 0xc5, 0xc7, 0xb3, 0xfb, 0x4f, 0x8f, 0xf7, 0xd7, 0x44,
-	0x1b, 0x65, 0x7d, 0x88, 0x9c, 0x64, 0xf1, 0xb0, 0x70, 0xbc, 0xc3, 0xe4,
-	0x48, 0x7a, 0xf8, 0xdf, 0x21, 0x1c, 0xaf, 0x12, 0x65, 0x7b, 0xf4, 0xf0,
-	0x3b, 0x30, 0xd6, 0xfd, 0x52, 0xb1, 0x16, 0xbf, 0x16, 0x0a, 0xc4, 0x9f,
-	0x54, 0x54, 0x34, 0x93, 0xef, 0xdd, 0xbc, 0xd3, 0x89, 0x9e, 0xd0, 0x62,
-	0x7c, 0x85, 0x9c, 0x6f, 0xf5, 0x35, 0x2a, 0x96, 0xec, 0xa3, 0x2d, 0x55,
-	0x0a, 0xc7, 0xd2, 0xc3, 0xe7, 0x30, 0x61, 0xaf, 0x13, 0x8e, 0xa6, 0x8e,
-	0x5b, 0x55, 0x86, 0x60, 0x11, 0xb1, 0xed, 0xea, 0x37, 0x2d, 0xb7, 0xac,
-	0x35, 0x91, 0x03, 0x0e, 0xf7, 0x47, 0x5f, 0x70, 0x12, 0xf7, 0xd7, 0x93,
-	0x07, 0x3e, 0x91, 0xe3, 0x81, 0x07, 0xfb, 0x0d, 0xed, 0x07, 0xc4, 0x8b,
-	0xfd, 0x3c, 0xdf, 0xca, 0x73, 0xab, 0xdf, 0xe0, 0x7c, 0x04, 0x9a, 0x66,
-	0x90, 0x1b, 0xbe, 0x43, 0x99, 0x7b, 0x29, 0x73, 0x82, 0xf6, 0x9f, 0xee,
-	0xd5, 0x90, 0x1c, 0x33, 0x30, 0xde, 0xeb, 0x45, 0xdf, 0x58, 0x10, 0x4f,
-	0xf6, 0xfa, 0xb0, 0x93, 0xfc, 0xf0, 0x70, 0xaf, 0xf8, 0xe2, 0x4c, 0xf4,
-	0x8f, 0xcd, 0xc4, 0x37, 0x92, 0xb2, 0x3e, 0xf5, 0x2e, 0x56, 0x57, 0x88,
-	0x7e, 0xc4, 0x2f, 0xc9, 0xaf, 0x93, 0x7a, 0x4f, 0x8c, 0x63, 0x8a, 0x79,
-	0xf5, 0x43, 0x31, 0xe8, 0x43, 0x9c, 0xc1, 0x8f, 0x87, 0xbe, 0x20, 0x31,
-	0x52, 0x7c, 0x52, 0xc3, 0x13, 0xe4, 0x3c, 0xa5, 0xc4, 0xd5, 0x92, 0x48,
-	0x4d, 0xf4, 0x0b, 0x8a, 0x1e, 0x7b, 0x45, 0xb5, 0xac, 0x4a, 0x89, 0xe1,
-	0x07, 0x35, 0xf2, 0x0f, 0x13, 0x37, 0xdb, 0x31, 0x5b, 0xc3, 0xf4, 0xdd,
-	0x95, 0xa8, 0xda, 0xdd, 0x87, 0xff, 0x56, 0x19, 0xff, 0x60, 0x1a, 0x63,
-	0xfd, 0x34, 0x62, 0xfb, 0xec, 0xbe, 0x93, 0xd3, 0x67, 0x91, 0x33, 0xbf,
-	0xa1, 0xd6, 0x66, 0xbe, 0x0b, 0xfd, 0xd0, 0x69, 0x87, 0x3e, 0x71, 0x94,
-	0xf1, 0xc1, 0x45, 0xfb, 0x9c, 0x31, 0xae, 0xd1, 0x7f, 0x6b, 0x8f, 0x56,
-	0xc1, 0x88, 0x5f, 0xab, 0x3a, 0x2d, 0x54, 0x8a, 0x3c, 0xa1, 0xf2, 0x6c,
-	0x6e, 0x14, 0x26, 0xf6, 0x4b, 0x6c, 0x70, 0x40, 0x23, 0x0e, 0xff, 0x3d,
-	0x7d, 0xe6, 0x4e, 0x3b, 0x1e, 0x1d, 0xb6, 0x9f, 0x85, 0x76, 0x8e, 0xc7,
-	0xe9, 0x27, 0x8b, 0xd1, 0xd1, 0xef, 0x41, 0xbb, 0x1d, 0x8b, 0x1e, 0xb3,
-	0x2a, 0xe8, 0x33, 0x1d, 0xfb, 0x03, 0x4d, 0x37, 0xd2, 0x67, 0xae, 0xbb,
-	0x46, 0xe2, 0xd8, 0x61, 0xf2, 0x5f, 0xc3, 0xbc, 0x8e, 0xf8, 0xb2, 0xb5,
-	0xde, 0xe8, 0x78, 0x9e, 0x32, 0xdd, 0x4f, 0xfb, 0x7f, 0x97, 0x3c, 0xe7,
-	0xdc, 0x9e, 0x43, 0xd4, 0x99, 0x66, 0xfb, 0xc3, 0xcf, 0x92, 0x3e, 0xdb,
-	0x37, 0x62, 0xfc, 0x2d, 0x71, 0x2f, 0x46, 0x5f, 0xfa, 0x37, 0xc6, 0xec,
-	0xe2, 0x50, 0xfc, 0xf6, 0x62, 0x04, 0x71, 0x1f, 0x65, 0xfd, 0x38, 0xa9,
-	0xf7, 0x6f, 0x90, 0x77, 0x8f, 0x43, 0x26, 0x65, 0xf1, 0xe0, 0x83, 0xa4,
-	0xd8, 0xd9, 0x89, 0xff, 0x59, 0x89, 0xf8, 0x26, 0xc6, 0xe0, 0xa0, 0xe6,
-	0x90, 0xb5, 0xf0, 0x99, 0x58, 0x73, 0xf0, 0x1a, 0xca, 0x5c, 0x47, 0xff,
-	0x03, 0xe6, 0x0c, 0x47, 0x70, 0xcf, 0x1e, 0xc9, 0x31, 0xd0, 0x20, 0xb9,
-	0xda, 0xbc, 0x50, 0xc0, 0x3c, 0x43, 0xac, 0x58, 0x3b, 0x76, 0x98, 0x71,
-	0x42, 0xd6, 0x96, 0x91, 0xf1, 0x19, 0x61, 0xbc, 0xda, 0x5b, 0x6f, 0xbf,
-	0xd3, 0x70, 0xff, 0x58, 0x3d, 0x5e, 0xe9, 0x9d, 0x89, 0xfb, 0x98, 0xeb,
-	0xc4, 0x98, 0xeb, 0xc4, 0xc6, 0xbc, 0x88, 0x1d, 0x98, 0xc6, 0x83, 0xb2,
-	0x1d, 0x98, 0xc3, 0x83, 0xb2, 0x8d, 0xa9, 0xf8, 0x2a, 0xf3, 0x97, 0x0d,
-	0xc4, 0xf3, 0x1e, 0xda, 0xe3, 0xff, 0xe0, 0xdc, 0x0f, 0xd0, 0xde, 0xab,
-	0x89, 0xf7, 0x6f, 0xee, 0x02, 0xee, 0xb4, 0xf5, 0x73, 0x84, 0x7a, 0x54,
-	0xf0, 0x15, 0xfa, 0x44, 0x15, 0x63, 0x52, 0x37, 0xe7, 0x7c, 0xe7, 0xa0,
-	0x11, 0x0c, 0xab, 0x01, 0xed, 0x09, 0xce, 0x73, 0xd7, 0x88, 0x8a, 0x47,
-	0xfb, 0x17, 0x63, 0x3e, 0x63, 0xca, 0xb6, 0xa1, 0x09, 0xbb, 0x7c, 0x37,
-	0xfd, 0xe1, 0x6e, 0xfa, 0xc9, 0x7b, 0xf4, 0x93, 0xc9, 0x95, 0xf2, 0x3e,
-	0xa9, 0x93, 0x39, 0xff, 0xc3, 0x58, 0x93, 0x90, 0x78, 0xa7, 0xf7, 0x0c,
-	0xa9, 0xcc, 0xb5, 0x68, 0x9f, 0x5d, 0xcc, 0x51, 0x6e, 0xa7, 0x6d, 0x3e,
-	0x3a, 0x24, 0x3e, 0x24, 0x39, 0x8b, 0x11, 0xde, 0x46, 0xdb, 0x7c, 0x7e,
-	0x48, 0xfc, 0xa3, 0x14, 0xb7, 0xee, 0x94, 0xfd, 0xa6, 0xa5, 0xf8, 0xec,
-	0xbe, 0xc3, 0x94, 0xef, 0x08, 0x76, 0xd1, 0x2e, 0x4b, 0x69, 0x97, 0xf7,
-	0x51, 0xaf, 0x1e, 0xda, 0xe5, 0x06, 0xe2, 0x50, 0x09, 0xed, 0xf2, 0x5e,
-	0xf2, 0x81, 0xca, 0x9c, 0x5d, 0xfe, 0xdd, 0xf8, 0xc2, 0x8a, 0x6c, 0x8c,
-	0xf0, 0x42, 0xdd, 0x2d, 0xef, 0xf7, 0x59, 0xd6, 0xed, 0x66, 0xa6, 0x69,
-	0x06, 0x74, 0xb6, 0x1d, 0xc1, 0xb2, 0xb4, 0x13, 0xe5, 0x7d, 0x11, 0x2c,
-	0x4d, 0xd6, 0xb4, 0x9f, 0x55, 0x22, 0xc8, 0xcc, 0xc8, 0xf2, 0x40, 0x57,
-	0x9f, 0x7c, 0xdf, 0x43, 0x23, 0x07, 0xe1, 0xf8, 0xaf, 0xcd, 0x7e, 0x53,
-	0xe4, 0xf3, 0x7f, 0x01, 0x7f, 0x5c, 0x42, 0x99, 0x3a, 0xcd, 0x8f, 0xac,
-	0xc9, 0xec, 0xf7, 0x07, 0x9c, 0xb7, 0xf1, 0x7c, 0x16, 0xdb, 0xa8, 0x1a,
-	0x77, 0x3a, 0xbf, 0x98, 0xf4, 0x60, 0xfa, 0xb8, 0x89, 0xbf, 0xcd, 0xb6,
-	0xe3, 0x2e, 0x88, 0x34, 0xe2, 0xb9, 0x84, 0x82, 0x69, 0xc6, 0xd3, 0xf8,
-	0x91, 0xbd, 0x2e, 0x50, 0x89, 0xf2, 0xdd, 0xf6, 0x9a, 0x02, 0x0e, 0x24,
-	0xf4, 0xf6, 0x34, 0xcf, 0xcb, 0x0e, 0x7a, 0x51, 0xbc, 0x5b, 0xc1, 0x2d,
-	0x01, 0x2f, 0x4a, 0xf9, 0xdb, 0x43, 0xbe, 0xd9, 0x1d, 0x5a, 0x6e, 0x6d,
-	0x59, 0x25, 0xf6, 0xed, 0x05, 0x0e, 0x96, 0x94, 0x0b, 0x0e, 0x1e, 0x30,
-	0x65, 0xed, 0xd2, 0x40, 0x77, 0xa2, 0x12, 0x85, 0xbb, 0x6b, 0x9a, 0x1a,
-	0x51, 0x63, 0xbe, 0xc3, 0xfa, 0x05, 0x07, 0x3f, 0x5b, 0x21, 0xeb, 0xf6,
-	0x4f, 0x49, 0x8c, 0x1b, 0x92, 0x79, 0xcd, 0xc6, 0x50, 0xe7, 0xd8, 0x5b,
-	0x9a, 0xe8, 0x65, 0x13, 0x39, 0x8a, 0xda, 0xf7, 0xa6, 0x5d, 0xc6, 0x17,
-	0x39, 0x4a, 0x0c, 0x90, 0xf8, 0x72, 0x0a, 0xed, 0xfd, 0xa7, 0x68, 0xff,
-	0xb2, 0x8e, 0xc1, 0xbc, 0x77, 0x81, 0x85, 0xe2, 0x85, 0x99, 0x60, 0x31,
-	0xa2, 0x15, 0x15, 0xc4, 0x6f, 0xfa, 0x00, 0x5e, 0x30, 0xf5, 0x96, 0x87,
-	0x1c, 0xd1, 0x87, 0x8a, 0xa0, 0xaf, 0x7b, 0x5b, 0xe9, 0xc1, 0xc6, 0xc0,
-	0x08, 0xfa, 0xc8, 0x05, 0xf3, 0xf9, 0xf8, 0xba, 0x3d, 0x8c, 0x6f, 0x8e,
-	0x8b, 0xf9, 0xb8, 0x16, 0x8a, 0xff, 0x8e, 0x3c, 0xc0, 0x3f, 0x9b, 0x18,
-	0xed, 0xb0, 0x7d, 0x27, 0x90, 0xd9, 0x44, 0x7b, 0x0d, 0x8f, 0x87, 0xe9,
-	0x23, 0x23, 0x82, 0x7d, 0xf2, 0x35, 0xa3, 0x17, 0x0a, 0x98, 0x3f, 0x16,
-	0x33, 0x0f, 0x39, 0x9d, 0xb4, 0x3a, 0xdd, 0xb4, 0x6b, 0xe7, 0xa2, 0x99,
-	0x50, 0xd3, 0x37, 0xe0, 0x9d, 0x5d, 0x33, 0x51, 0x48, 0x5f, 0xaa, 0x48,
-	0xca, 0x0b, 0x55, 0xea, 0xa7, 0xd9, 0x6f, 0xec, 0x3d, 0x04, 0xda, 0x03,
-	0x8e, 0xda, 0x75, 0x49, 0x45, 0x27, 0xf6, 0xeb, 0x2d, 0xa5, 0xea, 0x4c,
-	0x78, 0x98, 0xaf, 0x94, 0xa4, 0x3d, 0x00, 0xb9, 0x32, 0x58, 0xef, 0xa7,
-	0xbb, 0x5c, 0x28, 0x37, 0x8c, 0xe8, 0x33, 0xcc, 0x81, 0x1c, 0xa3, 0x4e,
-	0xfc, 0xcc, 0x96, 0x6b, 0x1a, 0x8a, 0x47, 0x6f, 0xc0, 0xe9, 0x5d, 0x7e,
-	0xa8, 0xbc, 0x76, 0x76, 0xcf, 0x1c, 0x14, 0x8c, 0x12, 0x08, 0xd2, 0x8b,
-	0xf1, 0xd6, 0x2e, 0x15, 0xae, 0xd1, 0xbf, 0xc1, 0x87, 0xbb, 0x14, 0xcc,
-	0x9f, 0xa7, 0xa0, 0x68, 0x78, 0x84, 0x3a, 0x11, 0xee, 0x45, 0x3f, 0x4d,
-	0xc1, 0xe6, 0x5d, 0x5b, 0x92, 0xc2, 0xed, 0xc9, 0xe9, 0x06, 0x2b, 0x61,
-	0xee, 0x7e, 0xd3, 0xaa, 0x30, 0x8c, 0xd8, 0x2d, 0xaa, 0xb5, 0xb8, 0x72,
-	0x41, 0xa0, 0x65, 0x80, 0x38, 0xfd, 0x12, 0x7d, 0xe0, 0x64, 0x7f, 0xdc,
-	0xf2, 0x18, 0x8b, 0x89, 0xb5, 0x51, 0x34, 0x30, 0x37, 0x97, 0xbc, 0x7b,
-	0x9b, 0x9d, 0xef, 0xca, 0x7e, 0x63, 0x27, 0xfc, 0x63, 0x0f, 0xe3, 0x78,
-	0xc2, 0x8d, 0xc5, 0x63, 0xa5, 0xb8, 0x8e, 0x39, 0x75, 0x98, 0xdc, 0x21,
-	0xbc, 0x2f, 0xcb, 0xf1, 0x9e, 0x27, 0xc7, 0xfb, 0x15, 0xb2, 0x1c, 0x6f,
-	0x80, 0xb9, 0x5a, 0x95, 0x51, 0x8a, 0x5b, 0x06, 0x0c, 0xc6, 0x80, 0x52,
-	0x34, 0xdb, 0xeb, 0x01, 0x1a, 0x6e, 0xa3, 0xff, 0x7e, 0x9e, 0xf9, 0xf8,
-	0xcd, 0x3b, 0x03, 0xbe, 0x1d, 0x8a, 0x8f, 0x71, 0x40, 0xda, 0x3f, 0x4c,
-	0xdc, 0xf0, 0x61, 0x4e, 0xaf, 0x11, 0x5c, 0x8a, 0xc0, 0xf9, 0x43, 0xd4,
-	0xe5, 0xe2, 0xb1, 0x1b, 0x10, 0xa6, 0xee, 0xc2, 0xfb, 0x0e, 0xe7, 0xc6,
-	0x31, 0x41, 0xd9, 0x9d, 0x78, 0x6f, 0x70, 0x16, 0x5e, 0x3d, 0x90, 0xcd,
-	0xc3, 0x03, 0x7d, 0x13, 0xb2, 0x5e, 0xfc, 0x35, 0x86, 0xd7, 0x7b, 0x24,
-	0x0f, 0xff, 0x41, 0xbf, 0xde, 0x5f, 0x2a, 0xeb, 0x84, 0xf4, 0xe7, 0xaf,
-	0x2e, 0x70, 0x30, 0xbe, 0xe8, 0xfe, 0xef, 0x3b, 0xe2, 0xf2, 0x1c, 0xd9,
-	0xff, 0x08, 0xef, 0x7f, 0x9f, 0xf1, 0xfc, 0x36, 0x5e, 0x8f, 0x55, 0x32,
-	0xd7, 0x5e, 0x18, 0x3f, 0xef, 0xe2, 0xf5, 0xc7, 0x38, 0x97, 0x65, 0x46,
-	0x4d, 0xec, 0x15, 0xe5, 0x08, 0x71, 0xc3, 0x81, 0x1d, 0x21, 0x3d, 0xba,
-	0xc3, 0xce, 0xa1, 0x9d, 0x98, 0x48, 0x5f, 0x9d, 0xf3, 0xc1, 0x4a, 0x94,
-	0xec, 0x96, 0xfc, 0xc5, 0x90, 0xf5, 0x9f, 0xfe, 0x12, 0xe6, 0x4f, 0x95,
-	0x17, 0xec, 0x33, 0xbf, 0xff, 0x09, 0xee, 0x8a, 0x48, 0x33, 0x42, 0x7d,
-	0xf9, 0x7d, 0x50, 0x87, 0xd0, 0x9d, 0x7e, 0x10, 0xed, 0xbb, 0xf4, 0x76,
-	0x59, 0x1f, 0x7a, 0x25, 0x14, 0xb7, 0xca, 0x8d, 0x4e, 0xb8, 0x16, 0x18,
-	0xcd, 0xcc, 0x5d, 0x62, 0xdf, 0x56, 0x8a, 0x19, 0x3b, 0x8e, 0x61, 0xf3,
-	0xb0, 0x1e, 0xdc, 0xa1, 0x18, 0xcc, 0xf7, 0x34, 0x1c, 0x1a, 0x2c, 0xc0,
-	0xdd, 0x7b, 0x5a, 0x19, 0xdb, 0x4c, 0xe2, 0x66, 0x8d, 0xff, 0x1c, 0xde,
-	0xc7, 0x49, 0x53, 0xde, 0x11, 0x2a, 0x42, 0xab, 0x26, 0x7b, 0x80, 0x98,
-	0x79, 0x4e, 0xbb, 0xe4, 0x3d, 0x71, 0x4f, 0x91, 0x91, 0x7f, 0xdf, 0xdf,
-	0x60, 0xae, 0x38, 0x89, 0xfd, 0x83, 0xb2, 0x2e, 0x50, 0xa5, 0x1c, 0xef,
-	0x9f, 0xeb, 0xeb, 0x22, 0xe6, 0x3f, 0x64, 0x66, 0x70, 0x7e, 0x61, 0x25,
-	0x30, 0x5d, 0x41, 0xe8, 0xd3, 0x01, 0xf9, 0x9e, 0x0d, 0xff, 0xde, 0xb3,
-	0xfc, 0x5f, 0x90, 0x76, 0x4a, 0xcb, 0xb2, 0x6b, 0x05, 0x3f, 0xaa, 0x94,
-	0xf7, 0x01, 0x8f, 0x27, 0x2b, 0xca, 0xb3, 0xcf, 0x9c, 0xff, 0x54, 0x1f,
-	0x6f, 0x58, 0x7e, 0xbb, 0x8d, 0x7c, 0xdd, 0xd7, 0xad, 0xa8, 0x57, 0xca,
-	0x17, 0xb0, 0x6d, 0xf1, 0xcb, 0x2a, 0x65, 0x1d, 0x71, 0x54, 0x0d, 0x55,
-	0x29, 0xad, 0x43, 0x97, 0xb7, 0xfb, 0x9a, 0x15, 0x6d, 0x96, 0xf3, 0x7c,
-	0x39, 0x8b, 0xf7, 0xa5, 0x6c, 0xfe, 0xfe, 0x0b, 0xb9, 0xb6, 0x0a, 0xc9,
-	0x53, 0xb3, 0x65, 0xee, 0xee, 0x97, 0xfd, 0x4b, 0x51, 0x9c, 0xa8, 0x9f,
-	0xda, 0x5e, 0xbe, 0xef, 0xef, 0x5c, 0xd2, 0x5e, 0xb6, 0x6c, 0x55, 0x15,
-	0x8a, 0xa5, 0x7c, 0x06, 0xff, 0x8f, 0xbd, 0x86, 0x70, 0xc6, 0xde, 0x73,
-	0xb8, 0xcd, 0x6c, 0x88, 0x16, 0xe1, 0x33, 0x50, 0xaf, 0x8a, 0xcf, 0x2f,
-	0xb2, 0xb9, 0x6d, 0xb4, 0xb9, 0x88, 0xf9, 0xad, 0xdb, 0x88, 0x3e, 0xe4,
-	0x46, 0x26, 0xe3, 0x86, 0xde, 0x72, 0x5e, 0x39, 0xa4, 0xdc, 0x1d, 0xd0,
-	0xdb, 0xdf, 0x23, 0xd7, 0x78, 0x39, 0x10, 0xb7, 0x4a, 0x0d, 0xc3, 0xd7,
-	0xab, 0xe8, 0xe6, 0x1a, 0xc6, 0xb2, 0x17, 0x99, 0x3f, 0xb6, 0x05, 0x7a,
-	0xec, 0xe7, 0x8b, 0x4a, 0x64, 0x05, 0xae, 0xb4, 0xbf, 0xdd, 0xd2, 0x0c,
-	0x23, 0xf5, 0xb2, 0xac, 0x77, 0xf1, 0x77, 0x0c, 0xf3, 0xed, 0x6b, 0x6d,
-	0x08, 0xda, 0xff, 0x57, 0xe5, 0xbe, 0xef, 0xd2, 0x82, 0x1a, 0xfb, 0xff,
-	0x1d, 0x98, 0x9b, 0xba, 0xb0, 0x2e, 0x8c, 0x4d, 0xa6, 0x65, 0x3d, 0x67,
-	0x5a, 0x38, 0x73, 0x71, 0xbf, 0xf3, 0x0a, 0x07, 0xf3, 0x0d, 0x52, 0xac,
-	0x58, 0xf6, 0xfb, 0x54, 0x17, 0xdf, 0x97, 0x58, 0x7a, 0xc9, 0x7e, 0x67,
-	0xf9, 0xae, 0x42, 0xa5, 0xfd, 0xfd, 0xb1, 0x79, 0x8b, 0x9c, 0x78, 0x29,
-	0x51, 0x16, 0xf3, 0xf0, 0xf7, 0xe6, 0x45, 0x05, 0x58, 0x4f, 0x4e, 0xd6,
-	0x74, 0xd5, 0x33, 0x38, 0x67, 0x7f, 0xc7, 0x21, 0x1e, 0x92, 0xef, 0x37,
-	0x9c, 0x48, 0xd0, 0xa7, 0x07, 0xbb, 0x43, 0xfb, 0xed, 0xbe, 0x5f, 0xc7,
-	0xa6, 0x51, 0x79, 0xe6, 0xd7, 0x8c, 0xd5, 0x89, 0x49, 0xc6, 0x37, 0x69,
-	0x4b, 0xf2, 0x6e, 0x3d, 0xd3, 0xc6, 0x5c, 0x55, 0x75, 0x04, 0x71, 0x3b,
-	0xe3, 0xca, 0x2b, 0x09, 0xda, 0xe9, 0x42, 0xbd, 0xe3, 0xdb, 0xe4, 0x06,
-	0x65, 0x11, 0x3d, 0xf8, 0xae, 0xd2, 0x82, 0x31, 0xd6, 0x9f, 0x48, 0x88,
-	0x2d, 0x56, 0xc6, 0x0a, 0x39, 0x96, 0x43, 0xe4, 0xa3, 0x2f, 0x27, 0x34,
-	0x9c, 0xab, 0xf7, 0x20, 0x45, 0x7e, 0xfa, 0x52, 0x42, 0xb8, 0x9a, 0x17,
-	0x4f, 0x0c, 0xca, 0xfa, 0x60, 0x23, 0x1a, 0x12, 0xb2, 0x36, 0xec, 0xc5,
-	0xe3, 0x23, 0x5e, 0xda, 0xa3, 0x65, 0x6d, 0xa2, 0xed, 0xb6, 0x6a, 0x13,
-	0xec, 0x53, 0xd6, 0x14, 0xa3, 0xb8, 0xa9, 0xb7, 0x12, 0x4f, 0x8c, 0xf8,
-	0xf0, 0x3d, 0xf2, 0xf1, 0x3e, 0xd6, 0x7b, 0x25, 0xe1, 0x47, 0x6f, 0xca,
-	0x87, 0xe7, 0xc9, 0xcb, 0xb7, 0xf2, 0x5c, 0xbe, 0x05, 0x56, 0x60, 0x04,
-	0x91, 0x48, 0x1d, 0x63, 0x6c, 0xbc, 0x02, 0x6b, 0x57, 0x1e, 0x81, 0xda,
-	0x7b, 0x94, 0xc7, 0xf5, 0x8c, 0xd5, 0xd7, 0x23, 0x39, 0x18, 0x41, 0x72,
-	0xe4, 0x87, 0xe8, 0x19, 0x94, 0x71, 0xc9, 0x37, 0xa1, 0x64, 0x6f, 0x91,
-	0x81, 0xf9, 0x8c, 0xa7, 0x43, 0x23, 0xd2, 0x4f, 0x25, 0xfb, 0xfe, 0x4b,
-	0xdb, 0xff, 0x99, 0xb5, 0xf6, 0xf3, 0xd2, 0xf6, 0x91, 0x3f, 0xd1, 0xbe,
-	0xe8, 0x2a, 0xff, 0x6e, 0x9f, 0xac, 0x73, 0xb8, 0xd9, 0xa6, 0x07, 0x8e,
-	0x48, 0x66, 0x65, 0x29, 0xf4, 0xe8, 0x76, 0xc5, 0x68, 0x2a, 0x51, 0x26,
-	0xb1, 0x3d, 0x2d, 0xef, 0x71, 0x15, 0xe2, 0x79, 0x72, 0x02, 0x57, 0x48,
-	0xd7, 0xbe, 0x4d, 0xdb, 0x59, 0x42, 0x8c, 0x39, 0x63, 0x7e, 0x1a, 0x71,
-	0x4d, 0xf4, 0x57, 0x88, 0x57, 0xfb, 0xdd, 0x78, 0x37, 0xc4, 0x98, 0x6d,
-	0xef, 0xa1, 0xf6, 0xe0, 0x27, 0x09, 0x2f, 0xe7, 0xab, 0x36, 0x63, 0x38,
-	0xe6, 0x02, 0x55, 0xd9, 0x6b, 0x27, 0x12, 0x6d, 0xd8, 0x4f, 0x79, 0x5f,
-	0x49, 0x9c, 0xe7, 0xfc, 0xac, 0xa3, 0xfe, 0x45, 0xdf, 0xf1, 0x9c, 0xae,
-	0xbb, 0xa9, 0xeb, 0x99, 0x78, 0x31, 0xf1, 0x30, 0x9e, 0xa0, 0xfc, 0x8f,
-	0xf7, 0x1b, 0xd1, 0x39, 0xca, 0x31, 0x1c, 0x1a, 0x2a, 0x24, 0x7e, 0xbb,
-	0x71, 0x37, 0xb3, 0xe4, 0x49, 0xe9, 0x2b, 0x29, 0x6b, 0x93, 0x0a, 0xb9,
-	0xc7, 0x31, 0x8c, 0xf3, 0xde, 0x4f, 0xf8, 0x3b, 0xbc, 0xb0, 0x9c, 0x7d,
-	0x88, 0x7e, 0xfc, 0x76, 0x1e, 0xd0, 0x45, 0x7e, 0xb3, 0xbc, 0xfe, 0x98,
-	0xcd, 0x79, 0xba, 0x93, 0xad, 0xe8, 0xe9, 0x7f, 0x9f, 0x7c, 0x8e, 0x38,
-	0xe4, 0xad, 0xa7, 0xad, 0x67, 0xb0, 0x3d, 0xf5, 0xef, 0x55, 0x59, 0xee,
-	0xf9, 0x6a, 0x95, 0xec, 0xeb, 0x3d, 0x91, 0x28, 0xc4, 0x4b, 0xac, 0xb3,
-	0x36, 0xe4, 0xca, 0x3d, 0x2f, 0x39, 0x86, 0x5e, 0xe2, 0x6a, 0x8a, 0x7d,
-	0x24, 0xec, 0x36, 0xaa, 0x94, 0xbd, 0xf4, 0xc3, 0xf2, 0x85, 0x55, 0x4a,
-	0x92, 0xe7, 0x7d, 0xc9, 0x1f, 0xe2, 0xd9, 0x47, 0xb2, 0x3a, 0xdc, 0x6f,
-	0xb6, 0x61, 0x28, 0x75, 0x2a, 0xd7, 0xde, 0x8f, 0xa7, 0xbc, 0x9b, 0x26,
-	0xef, 0xba, 0xe4, 0xdf, 0x7b, 0xc9, 0x3e, 0xcf, 0x7a, 0x2a, 0x5d, 0x46,
-	0xde, 0x5c, 0x4c, 0x5b, 0x2b, 0x88, 0x79, 0x19, 0x4f, 0xdb, 0x16, 0x68,
-	0xd8, 0x75, 0xcd, 0x9c, 0x2a, 0x94, 0x69, 0xee, 0x5f, 0xd7, 0xbf, 0xcc,
-	0x7e, 0xca, 0x62, 0x15, 0x91, 0x8c, 0xbd, 0x07, 0x2a, 0x74, 0x4d, 0x35,
-	0x73, 0x68, 0x79, 0x2e, 0x1c, 0xc3, 0xdb, 0x89, 0xca, 0x58, 0x65, 0xa4,
-	0x9c, 0x78, 0x7b, 0x0e, 0xbd, 0xc3, 0xc4, 0x76, 0xf2, 0xe5, 0xd2, 0xbe,
-	0x4a, 0xb8, 0xed, 0x35, 0xbc, 0x2b, 0x30, 0x63, 0xf7, 0x2c, 0xf8, 0x76,
-	0xcf, 0x24, 0x5f, 0x61, 0x6e, 0x19, 0xb2, 0xac, 0x9f, 0x2f, 0xb4, 0xac,
-	0x2b, 0x79, 0x14, 0xf1, 0x38, 0x1b, 0x12, 0x3f, 0x8d, 0xa2, 0xd6, 0xf6,
-	0x57, 0x03, 0x75, 0xf6, 0xff, 0x46, 0xfa, 0x7a, 0x47, 0x68, 0xfe, 0xf8,
-	0xc3, 0xa1, 0xb9, 0xe3, 0xd5, 0x50, 0x07, 0xa6, 0xc1, 0xc1, 0xb6, 0x3e,
-	0x77, 0x8d, 0x85, 0x46, 0xfa, 0xf0, 0x1a, 0x53, 0xf8, 0x50, 0x1b, 0xf9,
-	0x50, 0x4f, 0xc8, 0x18, 0x3f, 0x82, 0x1b, 0xc9, 0x97, 0xdd, 0x03, 0x3e,
-	0xf6, 0x23, 0xf9, 0xb5, 0x33, 0x33, 0x9b, 0x3c, 0xfb, 0xd3, 0x0b, 0x85,
-	0x1b, 0xb5, 0x90, 0x1b, 0x1d, 0x45, 0xcb, 0xf8, 0x31, 0xdc, 0xca, 0x32,
-	0x1e, 0xe6, 0xfd, 0x7d, 0xe9, 0x1f, 0x92, 0x77, 0x58, 0x8c, 0x39, 0x19,
-	0xdc, 0xcc, 0xb6, 0x8b, 0x07, 0x9a, 0x70, 0xf7, 0xf8, 0x0a, 0xac, 0x1d,
-	0xb7, 0xb0, 0x3c, 0x34, 0x81, 0xe5, 0xe3, 0xe4, 0x9a, 0xe3, 0x79, 0x7f,
-	0x15, 0x9e, 0xb4, 0x82, 0x3c, 0x49, 0xe2, 0xd0, 0x2a, 0x7b, 0x1d, 0x4d,
-	0xa5, 0x1f, 0x36, 0x24, 0xe4, 0x9d, 0x9b, 0x38, 0x56, 0x8f, 0x0b, 0x56,
-	0x3f, 0x88, 0x4d, 0xe3, 0xb2, 0x2e, 0xfb, 0xf5, 0xd0, 0x9c, 0xf1, 0xd7,
-	0xd1, 0x30, 0x3e, 0x14, 0x9a, 0x37, 0x3e, 0x42, 0xb9, 0x13, 0x94, 0xad,
-	0x3f, 0x54, 0x33, 0x3e, 0x18, 0x0a, 0x8e, 0xef, 0x0d, 0x05, 0xc6, 0x9b,
-	0xb1, 0x75, 0x7c, 0x15, 0xb6, 0x8c, 0xb7, 0x63, 0xf3, 0xb8, 0xe0, 0xfc,
-	0x24, 0x96, 0x8d, 0x9f, 0xc1, 0xd2, 0xf1, 0x97, 0xd1, 0x38, 0x7e, 0x0a,
-	0x4b, 0xc6, 0x7f, 0x88, 0xa6, 0xf1, 0x1f, 0x73, 0x2c, 0xb2, 0xce, 0x2b,
-	0x6b, 0xbc, 0xf9, 0x67, 0x6a, 0xf9, 0xf7, 0x44, 0xf3, 0xdf, 0xd7, 0x70,
-	0x21, 0xaa, 0xbd, 0x81, 0xee, 0x3d, 0xf2, 0xbd, 0xc1, 0x5a, 0x6d, 0x93,
-	0xfd, 0xbe, 0xc1, 0xcb, 0xb2, 0x4f, 0x1d, 0x45, 0xc6, 0xe5, 0xef, 0xc5,
-	0xcb, 0x77, 0x31, 0xe4, 0x39, 0xe7, 0x24, 0xba, 0xd2, 0xe7, 0xad, 0xa8,
-	0x26, 0x65, 0xde, 0xc0, 0xe6, 0x3d, 0xf2, 0x3e, 0x71, 0x06, 0x5d, 0x49,
-	0x79, 0x0e, 0x2f, 0xef, 0xa0, 0xbf, 0x81, 0x2d, 0xa3, 0xb6, 0xaf, 0xa1,
-	0x71, 0x48, 0xde, 0x89, 0x69, 0xc3, 0x75, 0xc9, 0x8c, 0xbd, 0x56, 0x5e,
-	0x66, 0xe0, 0xef, 0x67, 0xe0, 0x41, 0xe6, 0x04, 0x05, 0xe4, 0xfd, 0xc5,
-	0xe8, 0x7c, 0x24, 0x6e, 0x15, 0x1a, 0x1e, 0xcc, 0x88, 0x18, 0x99, 0x77,
-	0x1d, 0xc5, 0xe8, 0xe0, 0xb5, 0xfb, 0x76, 0xc2, 0xef, 0x33, 0x44, 0xf7,
-	0x81, 0xd8, 0x28, 0x63, 0xec, 0x86, 0x7d, 0x19, 0xf2, 0x8b, 0x0e, 0xf8,
-	0xf9, 0x7f, 0x7b, 0x52, 0xf6, 0x21, 0x6d, 0x42, 0x74, 0x9f, 0xe8, 0xb0,
-	0x99, 0x3a, 0x9c, 0x64, 0xdc, 0x90, 0x67, 0x38, 0x46, 0x70, 0x2b, 0x64,
-	0x9d, 0x52, 0xc5, 0xf7, 0x06, 0xe5, 0x79, 0x83, 0xde, 0xf1, 0x25, 0xfa,
-	0xf4, 0x87, 0xca, 0x0f, 0x51, 0x76, 0x40, 0xf8, 0xd2, 0x04, 0x7a, 0x84,
-	0x6f, 0x47, 0x14, 0x23, 0x15, 0x38, 0x0b, 0xcf, 0x01, 0xc1, 0x5d, 0x27,
-	0x4a, 0xc6, 0xe4, 0xfb, 0x38, 0x40, 0x31, 0xf3, 0x12, 0x1c, 0x20, 0xa7,
-	0x3d, 0x70, 0x0a, 0xd8, 0x27, 0xeb, 0x56, 0xaf, 0x61, 0x72, 0x48, 0xe6,
-	0xad, 0x8d, 0xf3, 0x26, 0x7e, 0xf8, 0x7d, 0x0c, 0x0f, 0x79, 0xe8, 0xe3,
-	0x13, 0x1c, 0xc7, 0xeb, 0x78, 0x74, 0x8f, 0x3c, 0x17, 0x99, 0x89, 0x36,
-	0xd6, 0x3b, 0xc1, 0x3c, 0xbf, 0x75, 0xcc, 0xe4, 0x78, 0x56, 0xa1, 0xf3,
-	0xc0, 0x17, 0x78, 0x4c, 0xc3, 0x43, 0x07, 0xd6, 0x71, 0x8c, 0x71, 0x74,
-	0x8c, 0x75, 0xf3, 0x68, 0xc5, 0xc6, 0x9d, 0x26, 0xb9, 0xa0, 0xd8, 0xb4,
-	0x46, 0x3f, 0x6b, 0xe5, 0x98, 0xa4, 0x8f, 0xd5, 0xf8, 0x19, 0x31, 0xa6,
-	0x29, 0xb4, 0x1a, 0xe7, 0x6c, 0xbf, 0x5b, 0x8d, 0x2d, 0xfd, 0x46, 0xf0,
-	0x24, 0x56, 0x63, 0x33, 0xcf, 0x1f, 0xa5, 0xef, 0xcf, 0x21, 0x17, 0xbc,
-	0x93, 0xbe, 0xbd, 0x78, 0x78, 0x42, 0xbe, 0x9d, 0x80, 0xbe, 0x5d, 0x32,
-	0x1f, 0x6d, 0xf0, 0x8d, 0x65, 0x50, 0x3e, 0xc6, 0xec, 0x79, 0x27, 0xee,
-	0x2a, 0x43, 0x39, 0xbe, 0x11, 0x92, 0x3d, 0x0b, 0x3f, 0x40, 0xf1, 0x3e,
-	0x91, 0xf5, 0x87, 0x6c, 0xfb, 0x1c, 0x73, 0xf1, 0x53, 0x9c, 0x83, 0xfc,
-	0xb3, 0xf1, 0x5f, 0xe0, 0x60, 0x6a, 0x92, 0xb8, 0x7a, 0x9a, 0xc7, 0xe5,
-	0xcf, 0xa5, 0xbd, 0x76, 0x8e, 0x92, 0xdd, 0xff, 0xed, 0xc4, 0x8c, 0x3e,
-	0x59, 0xdf, 0x6d, 0x86, 0x2f, 0x29, 0x7c, 0x27, 0xb3, 0x8d, 0xf9, 0x4a,
-	0x7b, 0xd8, 0xe6, 0x3f, 0x46, 0x8c, 0xbc, 0xa7, 0xf9, 0xdb, 0x8a, 0x87,
-	0xbc, 0x27, 0x88, 0x15, 0x69, 0x3d, 0x7a, 0x33, 0xf5, 0x5b, 0xf4, 0xc8,
-	0x8f, 0xe0, 0x7c, 0xc4, 0x89, 0x42, 0xe6, 0x37, 0xa1, 0x90, 0xe8, 0x59,
-	0xde, 0x95, 0xcd, 0xe8, 0x85, 0xc4, 0xcc, 0x82, 0xbe, 0x0c, 0xe7, 0x27,
-	0x33, 0xbf, 0x00, 0x7e, 0xce, 0xcd, 0x0d, 0x68, 0xeb, 0x8f, 0x72, 0x6e,
-	0x3e, 0x45, 0x1b, 0x9b, 0xa0, 0xbd, 0x48, 0x4e, 0xf4, 0x32, 0x65, 0x74,
-	0xe5, 0xbe, 0xc9, 0x93, 0xd1, 0x9d, 0xd0, 0x4d, 0xbf, 0x5a, 0x95, 0x7d,
-	0x27, 0x05, 0xf6, 0xb3, 0xe7, 0x30, 0xf0, 0x06, 0x6d, 0x33, 0xcf, 0x67,
-	0x2c, 0xab, 0x9d, 0xf6, 0xd5, 0x3f, 0x2a, 0xbe, 0xb2, 0xb4, 0x2a, 0xfb,
-	0xbe, 0xee, 0x54, 0xae, 0x93, 0xaf, 0xeb, 0x20, 0x36, 0xe6, 0xef, 0xff,
-	0x08, 0x77, 0x32, 0x7e, 0x9d, 0x59, 0x78, 0x2a, 0x67, 0xf3, 0xd3, 0xab,
-	0xb3, 0xf8, 0xf5, 0x49, 0xdf, 0x0b, 0xfa, 0x2b, 0xfb, 0xdb, 0x3b, 0xd9,
-	0x6f, 0x1f, 0x01, 0xcf, 0x26, 0x0a, 0xe4, 0x29, 0xc1, 0x62, 0x17, 0x54,
-	0xaf, 0x0b, 0x85, 0x8c, 0x01, 0xd5, 0xd8, 0xe4, 0xb5, 0x70, 0xa3, 0x59,
-	0x80, 0x43, 0x75, 0xb7, 0x00, 0x15, 0xf1, 0x16, 0x97, 0xfd, 0x4e, 0xde,
-	0xef, 0xbf, 0xf4, 0x87, 0xef, 0xe4, 0x9d, 0xb1, 0xf3, 0xe1, 0x52, 0xe3,
-	0x76, 0xbc, 0x62, 0xc7, 0x09, 0x05, 0x25, 0x73, 0x65, 0x5d, 0xd2, 0x8f,
-	0x17, 0x8d, 0x5a, 0x7f, 0x85, 0x3c, 0x6f, 0x52, 0xce, 0x5a, 0x71, 0xaf,
-	0xbc, 0x87, 0xf7, 0xc7, 0xf6, 0x8f, 0x3f, 0x87, 0xad, 0xbb, 0xc2, 0x90,
-	0xf7, 0x3b, 0x9c, 0x46, 0xa1, 0x37, 0x2b, 0xbf, 0xc8, 0x26, 0xeb, 0x44,
-	0xb7, 0x71, 0x1c, 0x67, 0xe8, 0x8b, 0x67, 0xec, 0x75, 0x2a, 0xb7, 0xf1,
-	0xd7, 0x08, 0x56, 0xe4, 0xc7, 0x2f, 0x39, 0x8d, 0x92, 0xd5, 0x41, 0xf6,
-	0xfd, 0xda, 0x6a, 0xc1, 0xfe, 0x2d, 0xc9, 0x33, 0xf6, 0x9a, 0xac, 0xcb,
-	0xf8, 0x0f, 0xeb, 0x2d, 0x6f, 0x25, 0xcb, 0x3e, 0x95, 0xbb, 0x3f, 0x29,
-	0xeb, 0x38, 0xa6, 0x7c, 0xbb, 0xca, 0x69, 0xd7, 0x11, 0xbd, 0x5f, 0xac,
-	0xb3, 0x89, 0xbc, 0x7a, 0xb6, 0x71, 0xca, 0xea, 0xf4, 0xca, 0x18, 0xd6,
-	0x5c, 0x56, 0x47, 0xd6, 0x08, 0x34, 0xe9, 0x37, 0x2c, 0x63, 0xee, 0x4a,
-	0xff, 0x61, 0x9f, 0xb2, 0x7e, 0x5b, 0x60, 0x94, 0xe0, 0x6c, 0x45, 0x76,
-	0x4d, 0xe5, 0xa2, 0x8c, 0xed, 0xd5, 0xb2, 0xef, 0xae, 0xd0, 0x3e, 0xb7,
-	0xfb, 0x35, 0x2f, 0xd6, 0x7b, 0x30, 0x37, 0xde, 0x4a, 0xfb, 0x9d, 0x9a,
-	0x47, 0x6d, 0xae, 0xe3, 0x98, 0x32, 0xee, 0xdf, 0x78, 0x2f, 0xed, 0xe7,
-	0xf3, 0xb9, 0x7e, 0x45, 0x1e, 0xef, 0x94, 0x3e, 0x44, 0xae, 0xde, 0x5c,
-	0x1d, 0x3d, 0x1c, 0xb5, 0xfb, 0x57, 0x11, 0xde, 0x93, 0xef, 0xd3, 0xb2,
-	0x0a, 0x16, 0xe6, 0xdb, 0xc8, 0xd0, 0x0f, 0xad, 0xce, 0x42, 0xc6, 0xab,
-	0xb3, 0xf5, 0x0f, 0x62, 0x73, 0x42, 0xf4, 0x2c, 0xdf, 0x70, 0x25, 0x2e,
-	0xdb, 0xfc, 0xcb, 0xc5, 0x5c, 0xf6, 0x1a, 0x0c, 0x69, 0x71, 0xec, 0xaf,
-	0x93, 0x77, 0xc8, 0x5c, 0xf4, 0x85, 0x38, 0x71, 0xb0, 0x90, 0x38, 0x1a,
-	0xb7, 0xf7, 0x94, 0x1c, 0x34, 0xf5, 0xe8, 0xb3, 0xf2, 0x8d, 0xb2, 0xab,
-	0xec, 0xb5, 0xa7, 0xa6, 0x21, 0xc8, 0xf5, 0xfc, 0x7a, 0x52, 0xfe, 0xaf,
-	0x88, 0xb6, 0x23, 0x72, 0x89, 0x0d, 0x50, 0xba, 0x84, 0xbc, 0xeb, 0x54,
-	0x1b, 0x23, 0x67, 0xc4, 0x2b, 0x29, 0xd9, 0x7f, 0xf0, 0x5b, 0x2b, 0x5e,
-	0x2d, 0xfb, 0x1c, 0xa7, 0xd6, 0x29, 0x20, 0x97, 0x0b, 0x84, 0xcb, 0x94,
-	0xfc, 0xfb, 0x4e, 0x17, 0xff, 0x6e, 0xa5, 0xcd, 0x9c, 0xb3, 0xdf, 0x51,
-	0x93, 0xb3, 0x08, 0x1a, 0x92, 0xf2, 0xad, 0x52, 0x7d, 0x62, 0x39, 0x6a,
-	0x33, 0x35, 0x0e, 0x67, 0x8e, 0x93, 0x84, 0xb1, 0x82, 0x76, 0xb3, 0x25,
-	0x10, 0xb6, 0xdf, 0xc5, 0x5a, 0x96, 0xac, 0x09, 0x3e, 0xce, 0x1c, 0xfa,
-	0x1d, 0x96, 0xbf, 0x25, 0xfd, 0x3d, 0x6b, 0xc8, 0x2b, 0x63, 0xca, 0x63,
-	0xc3, 0x29, 0xfa, 0x06, 0xf5, 0x18, 0x11, 0xff, 0xf0, 0xa0, 0x22, 0x12,
-	0xa6, 0xff, 0x4a, 0x4c, 0x97, 0xf7, 0xb8, 0xf4, 0xbd, 0x71, 0x98, 0xc4,
-	0xfc, 0x1e, 0xda, 0x91, 0xec, 0x5b, 0xd6, 0xfd, 0x2b, 0x19, 0x5b, 0x8e,
-	0x5f, 0x78, 0xc6, 0x2f, 0x1c, 0xe0, 0xd9, 0xea, 0xdc, 0xde, 0x66, 0xf7,
-	0x6c, 0xc6, 0x3c, 0xcb, 0x7e, 0x6e, 0xdf, 0x66, 0x63, 0x8a, 0x66, 0xe8,
-	0x87, 0x7e, 0xe5, 0xe8, 0xc4, 0xd3, 0x0b, 0x8c, 0x8e, 0xc3, 0x6a, 0x66,
-	0xc8, 0x47, 0x7c, 0xb9, 0xde, 0x11, 0xdd, 0xc9, 0xff, 0xfe, 0xd7, 0xec,
-	0x6f, 0xab, 0x48, 0x5d, 0x3d, 0xb8, 0x4a, 0x95, 0xfd, 0x40, 0xcd, 0x18,
-	0xeb, 0x95, 0x77, 0x06, 0xf4, 0x96, 0xa7, 0x94, 0x4e, 0x6c, 0x08, 0x19,
-	0xcd, 0xed, 0x8a, 0xde, 0xf4, 0x0f, 0x8a, 0xee, 0x0f, 0x29, 0x52, 0x2e,
-	0xc8, 0xbc, 0xeb, 0x62, 0x3c, 0x75, 0xb1, 0x8f, 0x03, 0x09, 0x3d, 0x5c,
-	0xc5, 0xb2, 0x67, 0x4d, 0xc3, 0xf7, 0x3e, 0xdb, 0xfc, 0x57, 0x1e, 0x3b,
-	0xed, 0xf7, 0xc4, 0xa5, 0x7c, 0x74, 0xbe, 0xcb, 0xfe, 0xbe, 0x69, 0x0b,
-	0xe3, 0xae, 0x7c, 0x23, 0x38, 0x06, 0xad, 0x6f, 0x26, 0x4d, 0x4c, 0xef,
-	0xb9, 0x0d, 0xb2, 0xe7, 0xa0, 0x89, 0x09, 0xba, 0x07, 0xde, 0x48, 0x27,
+	0x9d, 0xbc, 0x0d, 0x78, 0x1b, 0xe5, 0x95, 0x36, 0x7c, 0xcf, 0x48, 0xb2,
+	0x65, 0x5b, 0xb6, 0xc7, 0x8e, 0x9c, 0x28, 0x6c, 0x9a, 0x68, 0xf0, 0x28,
+	0x51, 0xb0, 0x69, 0x47, 0x89, 0x03, 0x82, 0x55, 0x89, 0xea, 0x98, 0xc4,
+	0x81, 0x50, 0x9c, 0x12, 0x5a, 0xb3, 0x4b, 0x5b, 0xe1, 0xfc, 0x60, 0x42,
+	0xa0, 0xa1, 0xb0, 0xef, 0x9a, 0xef, 0x65, 0x5f, 0xab, 0xb6, 0x93, 0x38,
+	0x89, 0x2c, 0x39, 0x8e, 0x21, 0x61, 0xbf, 0x5e, 0x8b, 0x89, 0x9d, 0x38,
+	0x80, 0x6c, 0x85, 0x36, 0xdd, 0x0d, 0x7d, 0xd3, 0x8d, 0x36, 0x09, 0x60,
+	0xfe, 0xda, 0x40, 0xbb, 0x2c, 0xed, 0xcb, 0x07, 0xde, 0x14, 0x42, 0xd8,
+	0xb6, 0x40, 0xb7, 0x3f, 0x1b, 0x5a, 0xca, 0xbc, 0xf7, 0x19, 0x49, 0x89,
+	0x13, 0x28, 0xed, 0x7e, 0xbe, 0xae, 0xb9, 0xac, 0x99, 0x79, 0x7e, 0xce,
+	0x73, 0x9e, 0x73, 0xee, 0x73, 0x9f, 0x67, 0x9e, 0x19, 0x3f, 0x50, 0x8a,
+	0xfc, 0x5f, 0x39, 0x8f, 0x4f, 0x37, 0x6c, 0x5c, 0xbd, 0x60, 0xc1, 0xa7,
+	0x1b, 0xe4, 0xdc, 0x39, 0xdd, 0xe9, 0xc4, 0x9f, 0xf9, 0xe7, 0xff, 0x73,
+	0x0b, 0x7e, 0xcc, 0x9f, 0x03, 0xd0, 0x0a, 0xfd, 0xcb, 0x01, 0xb7, 0x1a,
+	0x71, 0xde, 0xdc, 0x68, 0xc0, 0xed, 0x88, 0x4c, 0xb4, 0xad, 0x36, 0x80,
+	0x68, 0xba, 0xce, 0xbf, 0x04, 0x7f, 0xb0, 0xe2, 0x5e, 0x27, 0xe4, 0xfa,
+	0xa7, 0x22, 0x1f, 0x74, 0x7e, 0xef, 0x72, 0xfd, 0xbd, 0x21, 0x07, 0xdc,
+	0x5a, 0x24, 0x0e, 0x6d, 0x2e, 0xdc, 0xb3, 0x58, 0xe7, 0x9b, 0xf3, 0xbe,
+	0xa9, 0xa0, 0xa2, 0xd0, 0xd6, 0x69, 0xeb, 0x7b, 0xf3, 0x7c, 0xb1, 0x92,
+	0x88, 0x86, 0x23, 0x19, 0xb4, 0xd4, 0xf7, 0x75, 0x5a, 0xe5, 0x46, 0x08,
+	0x6e, 0xc3, 0x68, 0xed, 0x53, 0x3c, 0xe1, 0xf5, 0x8b, 0xe0, 0x29, 0x36,
+	0x10, 0xbf, 0x28, 0x82, 0x96, 0x4b, 0xc6, 0x4a, 0xe3, 0xce, 0x88, 0x1b,
+	0xcd, 0x19, 0x77, 0xfc, 0x2f, 0x22, 0x06, 0x96, 0x65, 0x66, 0x95, 0xa2,
+	0xc2, 0x8d, 0x9e, 0xcc, 0xeb, 0x25, 0xb9, 0xf6, 0xea, 0xf3, 0xff, 0x83,
+	0xd3, 0x72, 0xff, 0xa7, 0xc7, 0x9c, 0x11, 0x60, 0x53, 0xc2, 0xb2, 0x8a,
+	0x22, 0x37, 0xdc, 0xa0, 0x46, 0x0c, 0xdf, 0x3e, 0x2c, 0x46, 0x9b, 0x86,
+	0xfb, 0x36, 0x37, 0xfc, 0xa7, 0x72, 0x74, 0x90, 0x0d, 0x8f, 0x3a, 0x10,
+	0xd5, 0x8e, 0xf3, 0xff, 0xec, 0xd9, 0xad, 0x61, 0x03, 0xbb, 0x47, 0xcf,
+	0xf0, 0xba, 0xd3, 0xbe, 0xd6, 0xbd, 0x6b, 0xf6, 0xec, 0x9b, 0xc2, 0xc7,
+	0xf1, 0xe0, 0xa8, 0xfc, 0xbe, 0x15, 0x9d, 0xf5, 0x0a, 0x26, 0x6f, 0x58,
+	0x07, 0x87, 0x61, 0xa0, 0x67, 0x97, 0xe2, 0xec, 0xaa, 0x57, 0x11, 0xf5,
+	0xea, 0xc1, 0x18, 0x27, 0xc1, 0x69, 0x20, 0x56, 0x1c, 0x09, 0x3b, 0xdf,
+	0x4e, 0x44, 0x34, 0x87, 0x61, 0x59, 0xc1, 0xd0, 0x0c, 0x38, 0xaa, 0x2c,
+	0xeb, 0x09, 0xd3, 0x03, 0xff, 0x97, 0x9e, 0x42, 0x7c, 0xb8, 0x05, 0xaa,
+	0xf1, 0x14, 0xba, 0x86, 0x9f, 0xc2, 0x43, 0x3b, 0x4b, 0x31, 0x39, 0x8d,
+	0xe3, 0x4d, 0xf9, 0xf0, 0xbd, 0x79, 0xd2, 0xb7, 0xc8, 0x51, 0xcf, 0xc3,
+	0x8d, 0x49, 0xc7, 0x6b, 0xfc, 0x2f, 0x65, 0xce, 0x58, 0x93, 0x33, 0xce,
+	0x95, 0xd9, 0xc4, 0x32, 0x3d, 0x17, 0x94, 0x89, 0x0f, 0x47, 0xf0, 0x5c,
+	0x42, 0xc1, 0xfa, 0x50, 0x05, 0xa2, 0x55, 0x32, 0x5e, 0xcb, 0x1a, 0x35,
+	0x4f, 0x59, 0x93, 0x9a, 0xf4, 0x35, 0x81, 0xe7, 0x79, 0x6f, 0x73, 0xe8,
+	0x0d, 0x2b, 0xeb, 0x95, 0xf6, 0xbe, 0x4e, 0x1b, 0x5a, 0xc9, 0xeb, 0x4e,
+	0xa4, 0x12, 0x88, 0x55, 0x44, 0x6e, 0xe4, 0xb9, 0x6e, 0xbe, 0xa3, 0xb8,
+	0xdd, 0xef, 0x26, 0xdc, 0x5f, 0x2a, 0x37, 0xd4, 0x7b, 0x2a, 0xe1, 0xc4,
+	0x0b, 0x94, 0xf9, 0x90, 0xb9, 0x0e, 0x2e, 0xe3, 0x6e, 0xb1, 0x39, 0x8e,
+	0xeb, 0x47, 0x16, 0x66, 0x14, 0xea, 0x4b, 0xbb, 0x6e, 0x6c, 0x4e, 0x59,
+	0xd6, 0x56, 0x33, 0x7a, 0x45, 0x09, 0x0d, 0xe2, 0x58, 0xa2, 0x05, 0xee,
+	0x48, 0xc0, 0x7f, 0x1a, 0x61, 0x2c, 0xc9, 0x78, 0xf1, 0x64, 0x02, 0xce,
+	0xc6, 0x79, 0x5e, 0x74, 0x65, 0x22, 0xb8, 0x3a, 0x63, 0xa2, 0x29, 0xf3,
+	0xa7, 0x2d, 0xeb, 0xda, 0x94, 0x9f, 0x63, 0xf8, 0x83, 0x95, 0x1b, 0x83,
+	0x8c, 0x2f, 0xf7, 0xbf, 0x27, 0x75, 0x11, 0xb6, 0x71, 0x8e, 0xb6, 0x70,
+	0xfe, 0x96, 0x87, 0xb2, 0xd1, 0x12, 0xe8, 0xe6, 0x69, 0x44, 0xb0, 0x34,
+	0x63, 0x70, 0x4e, 0x23, 0x58, 0x92, 0xaa, 0xd5, 0x86, 0x31, 0x1f, 0x51,
+	0x5f, 0xce, 0xb6, 0xb7, 0x73, 0xbc, 0x6d, 0x81, 0x16, 0x94, 0xd3, 0x46,
+	0xd2, 0x8b, 0xc2, 0x68, 0x64, 0xff, 0x2b, 0xfe, 0x8c, 0xfe, 0xaf, 0x67,
+	0xff, 0xef, 0xb0, 0xff, 0xac, 0xdd, 0x3f, 0x9c, 0xd7, 0xf0, 0xdc, 0x4d,
+	0x7b, 0xdc, 0x96, 0x76, 0x3a, 0x97, 0xa7, 0xbc, 0xd8, 0x9a, 0x36, 0x69,
+	0x73, 0x72, 0xcb, 0x87, 0xcd, 0x83, 0xb3, 0xb0, 0x65, 0x50, 0xf7, 0x3d,
+	0xcd, 0xdf, 0xdd, 0x23, 0x17, 0x61, 0xd3, 0xa0, 0x82, 0x3d, 0xc6, 0x45,
+	0xe8, 0xe2, 0xef, 0xdd, 0x83, 0xb3, 0xf1, 0xe0, 0xa0, 0x03, 0xe1, 0x69,
+	0xe7, 0x8f, 0x63, 0xd2, 0x71, 0x11, 0xe2, 0x23, 0x7e, 0x74, 0x25, 0x9e,
+	0xb7, 0x75, 0x58, 0x1e, 0xf9, 0x5e, 0xc1, 0x9f, 0xe9, 0x3b, 0x7e, 0xac,
+	0x4e, 0x68, 0xe8, 0x4a, 0x89, 0x1f, 0xb8, 0x69, 0x9b, 0xe2, 0x07, 0xbf,
+	0x06, 0x2a, 0x34, 0x74, 0x67, 0x0a, 0xf7, 0x15, 0x38, 0x39, 0x6f, 0x6b,
+	0x34, 0x37, 0xb6, 0xa6, 0xc4, 0x26, 0xa4, 0x4d, 0xb1, 0x0b, 0xf9, 0x5d,
+	0x4d, 0xbb, 0x2b, 0x85, 0x7f, 0x6f, 0x29, 0x82, 0xf7, 0x6b, 0x78, 0xb3,
+	0x41, 0xae, 0xd3, 0xde, 0x43, 0x52, 0xa6, 0x1f, 0xfb, 0xd2, 0xe2, 0xa7,
+	0x7e, 0x34, 0x26, 0x26, 0xd8, 0x7e, 0x03, 0xdb, 0x36, 0xf1, 0xcf, 0x99,
+	0x7a, 0xfc, 0x53, 0x26, 0x88, 0x7f, 0xa4, 0x1e, 0xbf, 0x93, 0xf1, 0xe3,
+	0x60, 0x66, 0x16, 0xbe, 0x9d, 0xf1, 0xe1, 0x5b, 0x9c, 0xbf, 0xc7, 0x33,
+	0x2d, 0xb4, 0x7d, 0x0d, 0x07, 0x32, 0xa2, 0xff, 0x22, 0x8e, 0xb7, 0x14,
+	0xdd, 0x83, 0xb5, 0xc1, 0x63, 0xb4, 0xad, 0x7f, 0x34, 0xaf, 0x41, 0xb6,
+	0xba, 0xc1, 0xb6, 0xc9, 0xad, 0xbc, 0xbe, 0x6d, 0xb0, 0x36, 0x7a, 0x89,
+	0x62, 0x59, 0x6a, 0xa8, 0x2e, 0x7c, 0x54, 0x55, 0x31, 0xe9, 0xd5, 0xfd,
+	0x59, 0x55, 0xf7, 0x47, 0xe1, 0x42, 0x82, 0xbe, 0x11, 0xaf, 0xd1, 0x87,
+	0xe2, 0xb4, 0x29, 0xaf, 0x31, 0xcc, 0xf1, 0xe8, 0xfe, 0xb8, 0xea, 0xc6,
+	0x96, 0x94, 0xbe, 0x3b, 0xae, 0x7a, 0x10, 0xcf, 0x94, 0xe2, 0x17, 0x83,
+	0x7a, 0x6f, 0x5c, 0xfd, 0x3c, 0xe2, 0xd5, 0x96, 0xf5, 0xad, 0x10, 0x36,
+	0xce, 0x88, 0x20, 0x5a, 0x13, 0x41, 0x6c, 0x76, 0xc4, 0x8b, 0x54, 0x0a,
+	0x78, 0xa7, 0xcf, 0xf0, 0xfd, 0x9b, 0xd2, 0x82, 0xbf, 0x69, 0xd1, 0xfd,
+	0x7e, 0xb5, 0x2e, 0x3e, 0xac, 0x2e, 0xa2, 0x4b, 0xc3, 0xef, 0x8b, 0x2c,
+	0x43, 0x87, 0x7d, 0x4d, 0x81, 0x66, 0x78, 0xd0, 0x9d, 0xba, 0x02, 0x31,
+	0x6f, 0x6d, 0xeb, 0x0e, 0xb5, 0xf6, 0x8c, 0xa9, 0xea, 0x13, 0x2d, 0xaa,
+	0x65, 0xfd, 0x72, 0xe1, 0x3b, 0x96, 0x7f, 0xba, 0x65, 0x2d, 0x58, 0x28,
+	0x7d, 0xfa, 0x51, 0x15, 0x31, 0xb1, 0xd2, 0x9e, 0xc3, 0x52, 0x9c, 0x1a,
+	0xac, 0x66, 0x1f, 0x1a, 0xfe, 0xf5, 0x72, 0x3d, 0xb8, 0x4e, 0x2d, 0xc5,
+	0x9b, 0x23, 0xa5, 0x38, 0xc9, 0xf1, 0xfc, 0xe7, 0xa0, 0x0f, 0xbf, 0x1e,
+	0xb4, 0xac, 0x2f, 0x99, 0x7f, 0x89, 0x81, 0xea, 0x7e, 0xfc, 0xd3, 0xb8,
+	0x17, 0xbf, 0xe0, 0xdc, 0xbc, 0x91, 0x88, 0xde, 0x35, 0x0d, 0x7a, 0x74,
+	0x5c, 0x39, 0xf6, 0xd5, 0x0a, 0xd4, 0xb5, 0x54, 0x28, 0x7a, 0xf3, 0x76,
+	0xe8, 0xbe, 0x4b, 0x14, 0x2f, 0x4e, 0xa7, 0x35, 0xfc, 0x34, 0x5d, 0x1b,
+	0xfe, 0x21, 0xfb, 0xfc, 0xad, 0xf9, 0x84, 0x95, 0x9d, 0x2e, 0x7a, 0x13,
+	0x1d, 0x51, 0xcf, 0x29, 0xea, 0x39, 0x45, 0x3d, 0xa7, 0xa8, 0x67, 0xca,
+	0x70, 0x30, 0x45, 0x3d, 0x53, 0x77, 0xdf, 0xa2, 0x4d, 0x3d, 0xce, 0x79,
+	0x3c, 0x60, 0xcf, 0x63, 0x98, 0xf3, 0xf5, 0x17, 0xf8, 0x5f, 0x36, 0xb6,
+	0x3e, 0x6f, 0xfd, 0xad, 0x57, 0xc6, 0xd4, 0x3d, 0x3d, 0x87, 0x5f, 0x32,
+	0xb6, 0xe7, 0xac, 0x98, 0x26, 0xe3, 0x92, 0xf1, 0xd9, 0xfa, 0xf3, 0x6f,
+	0x54, 0xb6, 0x28, 0x28, 0xb5, 0xac, 0x9d, 0x66, 0xfe, 0xbe, 0xb7, 0x30,
+	0xbe, 0x1b, 0x94, 0x9c, 0x5d, 0xed, 0x74, 0x53, 0xdf, 0xc1, 0xa8, 0xba,
+	0x8c, 0xe7, 0x7a, 0x3c, 0x8a, 0xb9, 0xc5, 0xe7, 0x9f, 0x5f, 0x5b, 0x23,
+	0xf3, 0xe1, 0x3f, 0x7b, 0x4e, 0x7b, 0xb4, 0xfb, 0xbb, 0x8d, 0xe7, 0x32,
+	0x16, 0xb1, 0x45, 0xb1, 0x01, 0x2f, 0xed, 0xe5, 0xf2, 0xfc, 0x3d, 0xc4,
+	0xd5, 0xc8, 0x46, 0xb4, 0x34, 0x3c, 0x6a, 0xf7, 0x51, 0x94, 0x14, 0xbf,
+	0x51, 0xf0, 0xce, 0x15, 0x0a, 0x8e, 0x86, 0x0c, 0xda, 0xcc, 0x10, 0x71,
+	0x01, 0x28, 0x4e, 0xc2, 0xed, 0x89, 0x44, 0x90, 0xe8, 0x83, 0xbb, 0x24,
+	0x12, 0xc6, 0xfc, 0xbe, 0xda, 0xf6, 0x53, 0xd0, 0x83, 0x7d, 0x8a, 0xde,
+	0x02, 0xd4, 0x99, 0x63, 0xd4, 0xe3, 0x25, 0x8a, 0xee, 0x2f, 0x52, 0xe0,
+	0x56, 0x58, 0x2e, 0x90, 0x1e, 0xc2, 0x96, 0x8c, 0xfc, 0x0e, 0xc3, 0x48,
+	0xff, 0xb6, 0xd0, 0x17, 0xed, 0x7e, 0x23, 0xed, 0xfe, 0x14, 0xc7, 0xae,
+	0xfb, 0x89, 0xaf, 0x6e, 0x57, 0xa4, 0x1d, 0x7b, 0x13, 0x70, 0x17, 0x45,
+	0x36, 0xe0, 0xa9, 0x44, 0xf5, 0xf4, 0x42, 0x39, 0x85, 0xe5, 0xfc, 0xe9,
+	0xa9, 0xb2, 0xbc, 0x66, 0x45, 0xbd, 0x39, 0x59, 0x4a, 0x93, 0x43, 0xd8,
+	0x9e, 0x92, 0xba, 0x11, 0xbb, 0xae, 0x93, 0x7d, 0xf4, 0x24, 0x6a, 0x9b,
+	0xaf, 0x55, 0xf4, 0xf0, 0x23, 0xa8, 0x8b, 0xbe, 0xcd, 0x39, 0xec, 0x82,
+	0x7e, 0xa6, 0x1d, 0x39, 0x59, 0xe6, 0xa5, 0x73, 0x72, 0x2c, 0x4e, 0x43,
+	0xb9, 0x29, 0x05, 0x8f, 0xcf, 0x98, 0x96, 0xf7, 0x65, 0x28, 0xd7, 0x71,
+	0xfe, 0x54, 0xc3, 0x8f, 0xeb, 0x68, 0x43, 0x1b, 0x76, 0x5a, 0xe8, 0x0e,
+	0x55, 0xd3, 0x57, 0x5b, 0x50, 0x41, 0xbf, 0xbc, 0x53, 0x43, 0xb4, 0x32,
+	0x12, 0x56, 0xae, 0xcf, 0x0c, 0xe7, 0xf5, 0x7f, 0xb4, 0x9a, 0xf2, 0x29,
+	0x4d, 0xa9, 0x0b, 0xaf, 0x57, 0xe6, 0xe3, 0xde, 0x85, 0xd7, 0x3d, 0x45,
+	0x1f, 0x5f, 0xbe, 0x4e, 0x1b, 0x81, 0xc2, 0x78, 0x53, 0x42, 0xfd, 0xea,
+	0x26, 0xab, 0x05, 0x5d, 0xf6, 0x35, 0x07, 0x86, 0x9c, 0x51, 0x9f, 0x03,
+	0x1f, 0x58, 0xd1, 0x55, 0x72, 0xad, 0x14, 0xb1, 0x96, 0x3a, 0x9f, 0x13,
+	0x75, 0xe1, 0x4d, 0xf4, 0xb7, 0xc9, 0x55, 0x8d, 0xbc, 0x17, 0x30, 0x8f,
+	0xa1, 0xd6, 0xbf, 0x09, 0xf2, 0xfb, 0x7d, 0xda, 0x48, 0xa3, 0xd4, 0x65,
+	0x19, 0xb1, 0x39, 0x5d, 0x3b, 0x06, 0x2f, 0x36, 0xd1, 0xfe, 0x8a, 0x23,
+	0xba, 0xb9, 0xcc, 0xe1, 0xc4, 0x7e, 0xe2, 0xb8, 0xc3, 0xe8, 0x45, 0x31,
+	0xc7, 0xc8, 0xf8, 0x8a, 0x47, 0x12, 0xc0, 0xb3, 0xfd, 0x16, 0x1a, 0x43,
+	0x1e, 0x2c, 0xb1, 0x6d, 0xf3, 0x90, 0x72, 0x75, 0xea, 0x43, 0x6b, 0xc8,
+	0x59, 0x12, 0x55, 0x23, 0x01, 0xdf, 0x49, 0xb2, 0x81, 0xa2, 0x48, 0x9d,
+	0xe6, 0x44, 0x5c, 0x69, 0xce, 0xf4, 0x28, 0xcb, 0x33, 0xbd, 0xca, 0x92,
+	0x8c, 0xb4, 0x7d, 0x48, 0x59, 0x9a, 0xf1, 0x20, 0xdd, 0xaf, 0x60, 0x7b,
+	0x88, 0x72, 0xd5, 0xe4, 0xec, 0x38, 0xd3, 0xaf, 0x12, 0x63, 0xdf, 0x21,
+	0xc6, 0xea, 0x61, 0xb0, 0xef, 0x27, 0x12, 0xd5, 0x38, 0x44, 0x2c, 0xfd,
+	0x71, 0x5a, 0x57, 0x51, 0x7a, 0x11, 0x5e, 0x19, 0xa9, 0xc0, 0xd8, 0xa0,
+	0xc9, 0xdf, 0xf5, 0x78, 0x61, 0xc4, 0xb2, 0x7a, 0x4c, 0xcb, 0xda, 0x6b,
+	0x1e, 0x52, 0x1a, 0xd9, 0x67, 0xd4, 0x19, 0x8f, 0x16, 0x47, 0x02, 0xe6,
+	0x16, 0xf6, 0xe9, 0x88, 0xc4, 0x95, 0x28, 0xfb, 0xbb, 0x9a, 0xfd, 0x2d,
+	0xcd, 0xf7, 0x97, 0xeb, 0x57, 0x64, 0x91, 0x7a, 0x85, 0x3a, 0x61, 0xd6,
+	0x01, 0xf6, 0x25, 0x02, 0xc1, 0x42, 0xbd, 0xa5, 0xac, 0x73, 0xf5, 0xd9,
+	0x3a, 0xc0, 0x70, 0x22, 0xc8, 0x39, 0x15, 0x5b, 0xf7, 0x33, 0x76, 0x7d,
+	0x83, 0x18, 0xdb, 0x80, 0xb6, 0x61, 0xc1, 0xdf, 0x6b, 0xd4, 0xdc, 0x3c,
+	0xe5, 0xb0, 0x56, 0x62, 0x5e, 0x0e, 0x6f, 0x83, 0xe8, 0xa3, 0x5f, 0x77,
+	0xa5, 0xc4, 0xc6, 0xef, 0xf9, 0x72, 0x22, 0xa0, 0xe0, 0xb1, 0x40, 0xb6,
+	0xa5, 0x1c, 0x95, 0x68, 0x0f, 0x89, 0x6d, 0x6e, 0xfc, 0xf2, 0x53, 0x86,
+	0x1e, 0x5e, 0xa1, 0x70, 0xce, 0x02, 0x7a, 0xf3, 0x52, 0x05, 0x08, 0x8c,
+	0x01, 0x6f, 0xa4, 0x2b, 0xb1, 0xda, 0x74, 0x40, 0xad, 0x0a, 0xa2, 0x37,
+	0x33, 0x35, 0x2e, 0x98, 0xc4, 0x78, 0x69, 0x2f, 0x48, 0xbf, 0x2e, 0xc3,
+	0x32, 0x2d, 0x67, 0xd3, 0x6e, 0xb6, 0xed, 0x0e, 0x64, 0x83, 0x2a, 0xe3,
+	0xdd, 0x7e, 0x5e, 0x38, 0x46, 0xfc, 0x6f, 0x34, 0x5c, 0xc4, 0xff, 0x4a,
+	0x34, 0x9a, 0xbf, 0xb3, 0x96, 0xad, 0x92, 0x7b, 0x85, 0x76, 0xe0, 0x2e,
+	0x66, 0xbf, 0x6f, 0x19, 0xba, 0x7f, 0x94, 0x27, 0xd9, 0x74, 0xee, 0x7a,
+	0x9c, 0x31, 0xab, 0x9b, 0xed, 0x6e, 0x66, 0xbb, 0xeb, 0x34, 0x3d, 0x1a,
+	0x3f, 0x5b, 0x2e, 0x1b, 0x74, 0x40, 0xd7, 0xa4, 0x6c, 0x13, 0xdb, 0x5d,
+	0xcd, 0x76, 0x7b, 0x35, 0x91, 0xef, 0x77, 0xd6, 0xba, 0x55, 0x72, 0x2f,
+	0x67, 0x1f, 0xb9, 0x76, 0xef, 0x91, 0x76, 0xcd, 0xd1, 0x7c, 0x5f, 0x47,
+	0x13, 0xe8, 0x77, 0x44, 0x18, 0x63, 0x1b, 0x02, 0xfe, 0x2e, 0xc6, 0xdb,
+	0x26, 0xc6, 0x8e, 0x9c, 0x4d, 0x4c, 0x8d, 0x77, 0x88, 0x9f, 0x2b, 0x23,
+	0xd7, 0xa4, 0x9c, 0xd8, 0xda, 0x24, 0xf5, 0x2c, 0xf1, 0xc5, 0x47, 0xfd,
+	0x0a, 0xb6, 0x38, 0x71, 0x20, 0x41, 0xfc, 0xc7, 0x37, 0x68, 0x77, 0x7e,
+	0xb4, 0x64, 0x6a, 0xb1, 0x66, 0x27, 0xe3, 0xa0, 0x59, 0x45, 0x5b, 0xcf,
+	0xd9, 0xdb, 0x32, 0xb6, 0x3d, 0x69, 0xb7, 0x1d, 0x57, 0x5a, 0x32, 0x75,
+	0x5a, 0x15, 0x63, 0xee, 0x91, 0xb3, 0xd8, 0x39, 0x27, 0x5a, 0x1a, 0x09,
+	0x34, 0xaf, 0xe7, 0x24, 0xb9, 0x19, 0xdf, 0xbe, 0x37, 0xaf, 0x87, 0x76,
+	0xd1, 0x4b, 0x3b, 0xcc, 0xcd, 0x6f, 0x73, 0x66, 0x8f, 0x2a, 0x18, 0x07,
+	0xb5, 0x16, 0xeb, 0x76, 0xca, 0x7f, 0x72, 0x95, 0x86, 0xc7, 0x78, 0xad,
+	0x16, 0xab, 0x87, 0xbf, 0x47, 0x3b, 0xd3, 0x7d, 0x62, 0x87, 0x5d, 0x67,
+	0xe5, 0x12, 0x99, 0x44, 0x36, 0x91, 0xa9, 0x8f, 0xe5, 0x66, 0x51, 0x3f,
+	0x82, 0x8d, 0xd5, 0x94, 0x67, 0x2b, 0xf9, 0xd0, 0x21, 0xe5, 0xf3, 0x94,
+	0x27, 0xeb, 0xf2, 0xe2, 0xa1, 0x94, 0xc8, 0xa3, 0x44, 0x67, 0x46, 0x66,
+	0xe1, 0x4c, 0x2a, 0x10, 0x7f, 0x02, 0x22, 0x5b, 0x8f, 0xd2, 0x2a, 0xf5,
+	0x53, 0xbd, 0xbc, 0x57, 0x90, 0x11, 0x5a, 0xa5, 0x2d, 0x5b, 0x4e, 0xa6,
+	0xeb, 0x39, 0xd7, 0x2e, 0xe3, 0x6f, 0xcb, 0x51, 0xe1, 0xa4, 0xad, 0x49,
+	0xdb, 0xff, 0x61, 0x45, 0xb5, 0x6e, 0x5e, 0xf3, 0x72, 0x9e, 0xdc, 0xe4,
+	0x05, 0x7a, 0xf0, 0x3a, 0x87, 0xd2, 0xe2, 0x91, 0x78, 0x4d, 0xfb, 0x4c,
+	0xa7, 0x9d, 0x38, 0x9e, 0x58, 0xba, 0xb4, 0xcc, 0xf8, 0x34, 0x1e, 0x1b,
+	0xf1, 0x61, 0x84, 0x73, 0xfb, 0x6c, 0x42, 0xe2, 0xeb, 0x2c, 0x3c, 0x9a,
+	0xf6, 0xe0, 0x99, 0x84, 0x1f, 0x8f, 0x30, 0xfe, 0x4c, 0x24, 0x0c, 0xec,
+	0x4f, 0x7b, 0xf1, 0x34, 0xed, 0x79, 0x34, 0xed, 0xa3, 0xbd, 0xd4, 0x63,
+	0x38, 0xdd, 0x66, 0x8f, 0xe1, 0xc9, 0xc4, 0xbf, 0xcb, 0x58, 0x83, 0x32,
+	0xd6, 0xcd, 0xf6, 0x58, 0x0b, 0x71, 0x7e, 0xd6, 0xd9, 0x79, 0x38, 0x91,
+	0xb0, 0x71, 0xa0, 0x77, 0x99, 0x43, 0xe6, 0x81, 0x36, 0x3b, 0x20, 0x58,
+	0xa0, 0xf7, 0xc7, 0x61, 0x61, 0x8f, 0x39, 0x93, 0xfe, 0xdf, 0x4b, 0x79,
+	0xa9, 0x53, 0x8e, 0x1f, 0xae, 0x8a, 0x68, 0x79, 0x24, 0x10, 0xeb, 0xa3,
+	0xde, 0x9d, 0x11, 0xd1, 0x43, 0x4e, 0xef, 0x2b, 0x32, 0x87, 0x14, 0xe1,
+	0x7a, 0x97, 0x0c, 0xc4, 0xad, 0x32, 0x43, 0xf4, 0x1d, 0x20, 0xce, 0x02,
+	0xf3, 0xf7, 0x38, 0x39, 0xbe, 0x9b, 0x38, 0x66, 0x13, 0x45, 0x46, 0x9d,
+	0x56, 0x4d, 0xd9, 0x8f, 0x7c, 0x24, 0x06, 0x8a, 0x8e, 0xfe, 0x36, 0x3f,
+	0x5f, 0xba, 0x83, 0xf2, 0xfa, 0x81, 0xc2, 0xbc, 0x58, 0xd6, 0x0e, 0xb3,
+	0x30, 0x37, 0x35, 0xf0, 0x57, 0xeb, 0xf1, 0x21, 0x5a, 0xc4, 0x48, 0x62,
+	0x1a, 0xe2, 0x9a, 0x9a, 0x6f, 0x3b, 0xaa, 0x14, 0x31, 0xff, 0xc0, 0xb8,
+	0xf8, 0x7e, 0x39, 0xa2, 0x4e, 0xa9, 0x8f, 0x68, 0x51, 0x24, 0x10, 0x9c,
+	0xab, 0x4e, 0xb5, 0x19, 0xc1, 0x01, 0xe9, 0x2b, 0x4e, 0x59, 0xcf, 0xc7,
+	0x82, 0x91, 0x44, 0x01, 0x37, 0xfe, 0x3b, 0xf5, 0x2e, 0xd4, 0xa9, 0xc8,
+	0x29, 0x7a, 0x55, 0x71, 0x74, 0x50, 0xf4, 0xe7, 0xc4, 0x4a, 0x73, 0x7a,
+	0x5e, 0xe6, 0x59, 0x9c, 0x17, 0x62, 0x0e, 0xe7, 0xeb, 0x85, 0x7e, 0x2f,
+	0xe5, 0xb6, 0x90, 0x0e, 0x5d, 0x8c, 0x4d, 0x36, 0xe7, 0x5c, 0x95, 0xcf,
+	0x5b, 0x38, 0x4f, 0xea, 0x76, 0xea, 0xfa, 0xb3, 0x8e, 0xdc, 0x79, 0x9d,
+	0xef, 0xa3, 0xfa, 0xd2, 0xb5, 0x18, 0x0a, 0x3a, 0x03, 0x86, 0xd2, 0x88,
+	0xb9, 0x23, 0xf5, 0x4d, 0xce, 0xbe, 0xb6, 0x0d, 0xf4, 0xef, 0x7b, 0x4f,
+	0x35, 0x7c, 0x16, 0x9b, 0xa9, 0x17, 0xa7, 0x6d, 0x67, 0x51, 0xc5, 0x65,
+	0x2c, 0xb1, 0xfd, 0x49, 0x1d, 0x5f, 0x91, 0xef, 0x23, 0x6a, 0xe7, 0x2c,
+	0x50, 0x5b, 0xf2, 0xe7, 0x77, 0x53, 0xdf, 0x32, 0x0e, 0x15, 0x3f, 0x20,
+	0x97, 0x7d, 0x27, 0xf4, 0x59, 0x64, 0x6d, 0xcc, 0x76, 0xd2, 0xdf, 0xaf,
+	0x62, 0x5d, 0xe2, 0xdf, 0xb8, 0xc4, 0x52, 0xc4, 0x4b, 0xe8, 0xd7, 0x45,
+	0xf4, 0xd5, 0x6b, 0x32, 0xf7, 0xa0, 0x3d, 0x15, 0x08, 0x97, 0x28, 0xf7,
+	0xe0, 0xd6, 0x8c, 0x0b, 0xb1, 0x61, 0x0f, 0xd6, 0x51, 0x27, 0xce, 0xa4,
+	0xf8, 0xb9, 0x86, 0x75, 0xa3, 0x47, 0x67, 0x3a, 0xe9, 0x37, 0xeb, 0x46,
+	0xbd, 0x3c, 0xa6, 0xf3, 0x70, 0x63, 0x35, 0x8f, 0x3d, 0xb4, 0xcb, 0x36,
+	0xc6, 0x86, 0x23, 0x09, 0x13, 0x9d, 0xd4, 0xd5, 0x13, 0x89, 0x06, 0xdc,
+	0x4b, 0xbd, 0x1d, 0x4a, 0x7c, 0x8a, 0x3a, 0x0a, 0xa3, 0x83, 0x73, 0xfc,
+	0x58, 0x42, 0xb5, 0xf3, 0xab, 0xdb, 0x33, 0xff, 0x62, 0x45, 0xa7, 0x8b,
+	0x9c, 0xa2, 0x0b, 0x99, 0xcf, 0x8f, 0xe8, 0x81, 0xfe, 0x3b, 0x55, 0x17,
+	0xf5, 0xd8, 0xb6, 0xcb, 0xc0, 0xf6, 0x5d, 0x75, 0xb4, 0xbb, 0x8c, 0xe5,
+	0xaf, 0x1a, 0xa0, 0x0e, 0xa6, 0xea, 0xe1, 0x08, 0x79, 0x81, 0xe8, 0x41,
+	0xda, 0xbc, 0x8f, 0x63, 0xee, 0xe6, 0x3d, 0x1f, 0x1e, 0x4f, 0x7c, 0x97,
+	0xbf, 0xc3, 0xca, 0x5d, 0x19, 0xf1, 0x79, 0xf1, 0xb7, 0x7f, 0x70, 0xe4,
+	0x62, 0x6f, 0xa1, 0xdc, 0x16, 0x96, 0xb3, 0xac, 0xcd, 0x67, 0xe3, 0x4a,
+	0x51, 0xb4, 0x84, 0x71, 0x65, 0x7f, 0x22, 0x10, 0x7e, 0xc6, 0x8e, 0x7d,
+	0x4e, 0xda, 0x8e, 0xd8, 0x47, 0x8f, 0x6d, 0x1b, 0xcb, 0xce, 0xda, 0xc6,
+	0xe4, 0x59, 0x0e, 0xd5, 0x9f, 0x9a, 0xea, 0x73, 0x39, 0xbb, 0x70, 0x26,
+	0xf5, 0x5e, 0xdb, 0x8e, 0xd3, 0x82, 0x8f, 0x0e, 0x38, 0x06, 0x9c, 0x68,
+	0x33, 0x2f, 0xa5, 0xbe, 0xab, 0x19, 0x6f, 0x8a, 0x78, 0x30, 0x4f, 0x1d,
+	0xfe, 0x0b, 0x94, 0x0e, 0x64, 0xad, 0x12, 0xfe, 0x6e, 0x0e, 0x89, 0xbe,
+	0xaf, 0xc2, 0xad, 0xc3, 0x0e, 0x14, 0x0d, 0x28, 0x78, 0xd2, 0xac, 0xc7,
+	0x90, 0x37, 0x87, 0xbb, 0x6a, 0xf2, 0x52, 0x7b, 0x9e, 0x2e, 0x1e, 0x3f,
+	0xfa, 0x8c, 0xc4, 0x85, 0x7b, 0x47, 0x3d, 0xf0, 0x25, 0x15, 0x78, 0x88,
+	0x2b, 0x65, 0x46, 0x3d, 0xf5, 0xaa, 0xa1, 0x32, 0x69, 0xe2, 0x6b, 0x19,
+	0xd2, 0xa6, 0x07, 0xc2, 0xb8, 0x93, 0xf3, 0x52, 0xfe, 0xc0, 0x95, 0xb8,
+	0x83, 0xe5, 0x36, 0xf0, 0xde, 0x86, 0xd1, 0x6a, 0x1e, 0x5e, 0x1e, 0xd3,
+	0x79, 0x34, 0xe0, 0xf6, 0xe1, 0x5a, 0x44, 0xab, 0xf5, 0xa0, 0x5f, 0x75,
+	0xa0, 0x7a, 0x40, 0xf4, 0xae, 0x62, 0xe5, 0x02, 0x05, 0xe6, 0xa7, 0x8b,
+	0xa1, 0xce, 0xfd, 0x38, 0xdf, 0xfd, 0x53, 0xb2, 0xbe, 0x6c, 0x0d, 0xd9,
+	0x98, 0x2e, 0x3a, 0x16, 0x3b, 0xf9, 0x57, 0xce, 0x85, 0xc8, 0x2b, 0x7d,
+	0x48, 0xac, 0x15, 0x1d, 0x7f, 0x12, 0x36, 0x30, 0xb2, 0x54, 0x74, 0xb1,
+	0xcc, 0x47, 0x7d, 0x01, 0x67, 0xe7, 0x7f, 0x2a, 0x67, 0x95, 0xb8, 0xaf,
+	0x87, 0x87, 0x6c, 0x8e, 0xe3, 0x67, 0xbe, 0xa8, 0xc7, 0x45, 0xe7, 0xe4,
+	0x34, 0x6e, 0xd5, 0x80, 0xbf, 0xc8, 0xb8, 0x19, 0xb7, 0x71, 0x9e, 0xf6,
+	0x26, 0xd4, 0xa5, 0x2e, 0xa8, 0xb3, 0x5c, 0x4c, 0x9c, 0x47, 0x4c, 0x1d,
+	0xed, 0xc3, 0xcc, 0xb5, 0x86, 0xcb, 0xd1, 0xa5, 0x29, 0xee, 0x6d, 0xf5,
+	0x8b, 0x24, 0xa7, 0xf6, 0x57, 0x1a, 0x50, 0xcb, 0x18, 0xff, 0xb7, 0x6b,
+	0x70, 0x16, 0x19, 0x8a, 0x9a, 0xa8, 0x6f, 0x42, 0xbc, 0x0a, 0xce, 0x0a,
+	0x03, 0x0a, 0x73, 0x66, 0xf4, 0x69, 0x10, 0xec, 0x89, 0x16, 0x19, 0xf7,
+	0xe0, 0xb6, 0x14, 0xac, 0xd2, 0x08, 0xf3, 0xa1, 0x88, 0x41, 0x8e, 0x1b,
+	0xf0, 0x15, 0xd1, 0x3f, 0x56, 0x93, 0x57, 0xac, 0x1d, 0x16, 0x39, 0x3c,
+	0xe4, 0x1b, 0x86, 0xbf, 0x0d, 0xcc, 0xe1, 0x5b, 0xf4, 0xe0, 0x24, 0xf3,
+	0xd8, 0xd5, 0xd4, 0xfd, 0x48, 0xe2, 0x1e, 0x34, 0xa6, 0x8e, 0x58, 0x1e,
+	0xf2, 0xc8, 0x22, 0xa3, 0xf6, 0x4c, 0x17, 0x62, 0xf4, 0x0d, 0xe1, 0x47,
+	0x6b, 0xe8, 0x1b, 0x3e, 0x64, 0x12, 0xea, 0x71, 0xb2, 0x0b, 0x74, 0x8c,
+	0xae, 0xc7, 0xd7, 0x46, 0x67, 0x61, 0x3c, 0xb1, 0x01, 0x77, 0x66, 0xc8,
+	0x95, 0xfa, 0xaf, 0xc2, 0x1d, 0xc3, 0x57, 0xe1, 0xf6, 0x9d, 0x46, 0x70,
+	0x03, 0x75, 0xbd, 0x76, 0x98, 0x81, 0x72, 0xba, 0xb4, 0x5b, 0xd0, 0x95,
+	0xf0, 0x45, 0xea, 0x22, 0xaf, 0xa7, 0x2c, 0x0a, 0x1c, 0xe6, 0x5f, 0x2d,
+	0x5e, 0x8a, 0x17, 0x35, 0x28, 0xfe, 0xdd, 0xf5, 0x2f, 0x31, 0xb7, 0x17,
+	0xd9, 0x11, 0x9d, 0x69, 0xfc, 0xc0, 0x7a, 0x50, 0xa3, 0x7f, 0x47, 0x10,
+	0x9f, 0xd3, 0xf0, 0xbc, 0xf5, 0xd0, 0x2a, 0xb9, 0x7e, 0x9b, 0x13, 0xa5,
+	0x2a, 0xaf, 0x49, 0x9b, 0x82, 0x4b, 0x75, 0x44, 0xe2, 0x8f, 0x6b, 0x33,
+	0x6b, 0x25, 0xcf, 0x96, 0x27, 0x2f, 0x24, 0x16, 0x3f, 0x91, 0xf0, 0xa2,
+	0x37, 0x95, 0xe3, 0x56, 0x37, 0x65, 0x84, 0x53, 0xb9, 0x51, 0xda, 0x27,
+	0x71, 0x25, 0x8a, 0xf5, 0xfc, 0x5d, 0xd2, 0xa7, 0xb7, 0xc4, 0x91, 0x60,
+	0x9b, 0x4d, 0x9c, 0x0b, 0xda, 0x6b, 0x9f, 0x03, 0x25, 0x46, 0x73, 0xce,
+	0x56, 0xfb, 0x56, 0xd0, 0x56, 0x35, 0x54, 0xf4, 0xf5, 0x70, 0xac, 0xb4,
+	0x55, 0xd6, 0xbb, 0x83, 0xba, 0xf0, 0xf4, 0xad, 0xa2, 0xbd, 0xce, 0x42,
+	0x59, 0x5f, 0x2b, 0xf1, 0x01, 0x8c, 0xeb, 0x16, 0x8e, 0x9a, 0x95, 0x79,
+	0x7e, 0xda, 0x8c, 0x5b, 0x53, 0x51, 0xb4, 0xa5, 0x6a, 0xa3, 0x27, 0x65,
+	0xad, 0xca, 0x95, 0xc3, 0xb0, 0x68, 0x8d, 0xe8, 0x62, 0x32, 0x8f, 0xa7,
+	0x7a, 0x73, 0x8e, 0xd3, 0xe9, 0x9a, 0x5f, 0x29, 0xc8, 0xde, 0x83, 0x18,
+	0xf3, 0x8f, 0x39, 0x91, 0x16, 0x58, 0x29, 0x91, 0x3b, 0x6e, 0xf9, 0x98,
+	0x53, 0x7a, 0x22, 0xfa, 0xc6, 0xc5, 0x0e, 0xa3, 0xe3, 0x15, 0x25, 0x88,
+	0xeb, 0x29, 0x43, 0x59, 0x5f, 0x27, 0x5e, 0x08, 0xe9, 0xbe, 0xef, 0x2a,
+	0xfa, 0x99, 0x0d, 0x78, 0x05, 0x3f, 0xe3, 0xb5, 0xa2, 0xbe, 0x09, 0x3c,
+	0x94, 0x79, 0x15, 0xa7, 0x28, 0xab, 0xda, 0xf7, 0xa1, 0xb5, 0xcc, 0x78,
+	0x86, 0xe3, 0x77, 0x2b, 0x6f, 0x65, 0xa6, 0xda, 0xe2, 0x55, 0x58, 0xbd,
+	0x53, 0xec, 0x4f, 0x0f, 0xc6, 0x89, 0xbd, 0x6d, 0x66, 0x85, 0x70, 0x79,
+	0x89, 0x4f, 0x94, 0xbf, 0x45, 0xb0, 0x85, 0xfe, 0x41, 0x3b, 0xb0, 0xc7,
+	0xd0, 0x6a, 0x63, 0xb2, 0x33, 0x09, 0x1b, 0x4b, 0x73, 0x7a, 0x8e, 0x28,
+	0x6d, 0xa3, 0xbe, 0x52, 0x94, 0xfa, 0xf2, 0x7e, 0x90, 0x5b, 0xb3, 0x38,
+	0x57, 0xf7, 0x3f, 0xad, 0x11, 0xef, 0xf9, 0x75, 0x2b, 0x98, 0x83, 0x55,
+	0x72, 0x3c, 0xef, 0xf6, 0xc5, 0xad, 0xd2, 0xdc, 0x58, 0x9a, 0x7f, 0xa0,
+	0x88, 0x4d, 0x06, 0xc9, 0xed, 0x3b, 0x71, 0x69, 0x48, 0x6f, 0xfd, 0xae,
+	0x22, 0x65, 0xf5, 0xf0, 0x06, 0xa5, 0xd0, 0xcf, 0xcb, 0x38, 0x39, 0x22,
+	0x7d, 0x48, 0x5f, 0x13, 0xcc, 0xc9, 0x72, 0x63, 0x10, 0x5f, 0x7a, 0xc4,
+	0x9e, 0x4b, 0xf1, 0x27, 0x3f, 0x96, 0x73, 0x4c, 0xae, 0x3e, 0x1f, 0x0f,
+	0x17, 0xed, 0xd5, 0x87, 0xb5, 0x99, 0x15, 0x58, 0xcd, 0xbc, 0x76, 0x75,
+	0xa6, 0x85, 0xba, 0xdf, 0x48, 0x7c, 0x67, 0x46, 0xa0, 0xe5, 0x74, 0x7c,
+	0xce, 0x3e, 0x74, 0xff, 0x24, 0x56, 0xf0, 0xfe, 0xcf, 0x9d, 0xa8, 0x68,
+	0x61, 0x79, 0xfb, 0xbe, 0x29, 0xf8, 0x7d, 0xae, 0xcc, 0x47, 0x78, 0x98,
+	0x1d, 0xe7, 0xf7, 0xda, 0x1c, 0xb1, 0xc5, 0xce, 0xbd, 0xae, 0xb6, 0xe7,
+	0x5c, 0x38, 0x82, 0x85, 0x63, 0x66, 0x31, 0xf3, 0xaf, 0xba, 0xe0, 0xf9,
+	0x9c, 0x50, 0x67, 0x16, 0x5a, 0xc0, 0x03, 0xe9, 0x4b, 0xf4, 0x72, 0xa2,
+	0x26, 0xa7, 0x97, 0x4f, 0x2a, 0x7b, 0x3e, 0x76, 0xec, 0x49, 0x48, 0xdf,
+	0x45, 0x36, 0x2f, 0x6d, 0xcc, 0x94, 0x22, 0xee, 0x15, 0x1d, 0x49, 0x7b,
+	0xba, 0x5f, 0x64, 0x5a, 0xbb, 0x53, 0xec, 0xd8, 0xc2, 0x08, 0x65, 0xe8,
+	0xb6, 0xe7, 0x2d, 0xc7, 0x25, 0x8f, 0x9c, 0x17, 0x9f, 0x65, 0x4c, 0x85,
+	0xbe, 0x6f, 0x73, 0xe5, 0xf8, 0x66, 0x81, 0x2b, 0x58, 0xd6, 0x80, 0x59,
+	0xe0, 0x0a, 0x32, 0xe6, 0xbf, 0x00, 0x63, 0x9d, 0x3d, 0xde, 0x35, 0xf9,
+	0xb6, 0xbb, 0xcc, 0x00, 0xed, 0x5a, 0xb8, 0x54, 0x44, 0x59, 0xb3, 0x2b,
+	0xc3, 0xb9, 0x95, 0xdc, 0x06, 0xb8, 0x93, 0xf7, 0xcb, 0x79, 0xff, 0xc5,
+	0x90, 0x0b, 0x97, 0x4e, 0x97, 0xbe, 0xaf, 0x42, 0xc7, 0xce, 0x28, 0x2a,
+	0x17, 0x06, 0x30, 0x69, 0x73, 0x89, 0x02, 0xef, 0x75, 0xe1, 0x8e, 0x9d,
+	0x1f, 0x5a, 0x15, 0x36, 0x17, 0x33, 0x62, 0xe3, 0x8a, 0x8a, 0xed, 0x8b,
+	0x84, 0xff, 0xba, 0x88, 0xef, 0xe4, 0xa2, 0xc2, 0xad, 0x5d, 0x65, 0xe4,
+	0xb0, 0xc2, 0xe1, 0x02, 0xd9, 0x9b, 0x54, 0x68, 0x5a, 0x44, 0xb8, 0xdc,
+	0x2c, 0x9b, 0xc3, 0x0a, 0x97, 0xfd, 0x56, 0xea, 0xd0, 0x14, 0x2e, 0x7b,
+	0x96, 0x73, 0x30, 0xf7, 0x69, 0x61, 0x7e, 0xef, 0x81, 0x3b, 0xa2, 0xb7,
+	0x6c, 0x52, 0x3a, 0xb1, 0x3c, 0x64, 0x98, 0x92, 0x53, 0x5f, 0xa9, 0xe8,
+	0xc1, 0xd3, 0x08, 0x12, 0x6f, 0x5f, 0xc6, 0xc8, 0x60, 0xdc, 0x25, 0x76,
+	0xb4, 0x29, 0x73, 0x4e, 0x9e, 0x5b, 0x29, 0x8f, 0x3b, 0x27, 0x8f, 0x79,
+	0x1a, 0x2a, 0x9e, 0x6c, 0x70, 0x11, 0xb7, 0xfe, 0x0e, 0x6d, 0x3b, 0x55,
+	0x2c, 0xb1, 0xb9, 0xf9, 0xdf, 0x11, 0x7f, 0x2f, 0x2a, 0xcd, 0x95, 0x07,
+	0x3a, 0xe9, 0xdf, 0xef, 0x2f, 0x2c, 0x41, 0x68, 0x9a, 0x82, 0x2a, 0xa3,
+	0x83, 0xf9, 0xf1, 0x87, 0x56, 0xdc, 0x49, 0x3a, 0x6b, 0x40, 0x2b, 0x89,
+	0x44, 0x29, 0x5b, 0x93, 0x72, 0xcd, 0xf0, 0x20, 0xfb, 0xe9, 0x20, 0xef,
+	0xf7, 0xe0, 0x2e, 0xda, 0xce, 0x5d, 0x8c, 0x65, 0x77, 0x31, 0x96, 0xdd,
+	0x35, 0xfa, 0x2f, 0xbc, 0x3e, 0xdd, 0xfe, 0xbd, 0x29, 0x55, 0xb0, 0x65,
+	0x27, 0xe3, 0x82, 0xe8, 0x77, 0x33, 0x7d, 0x47, 0xe2, 0x02, 0x28, 0x93,
+	0x85, 0x93, 0x9c, 0xc7, 0x25, 0x9a, 0x1e, 0xcc, 0xe2, 0xeb, 0xae, 0x73,
+	0x79, 0x5f, 0x21, 0xb6, 0xc8, 0x3c, 0xba, 0x70, 0x1b, 0x65, 0x0c, 0x86,
+	0xfe, 0xcb, 0x42, 0x95, 0xf8, 0xee, 0x85, 0xf7, 0x73, 0xf3, 0x7a, 0xe4,
+	0x2c, 0x07, 0x54, 0xc4, 0x4e, 0xe9, 0xf3, 0x7b, 0x6c, 0x4e, 0xf1, 0xa2,
+	0xc9, 0xdc, 0x6d, 0xe7, 0xd1, 0xf9, 0x62, 0x2a, 0x6b, 0x47, 0xa3, 0xe8,
+	0xe6, 0xb8, 0x57, 0x0f, 0x3f, 0x96, 0xd7, 0x4b, 0x61, 0xbc, 0x0a, 0xd5,
+	0xe2, 0xa1, 0xff, 0xe4, 0x72, 0x95, 0xb6, 0x51, 0xe1, 0xb6, 0xd5, 0xfc,
+	0x2f, 0xdc, 0xd6, 0xcb, 0xff, 0xc2, 0x73, 0xa7, 0xf3, 0xbf, 0x13, 0xfe,
+	0xe9, 0x62, 0xc7, 0xf5, 0xe8, 0xdd, 0x65, 0x59, 0xc5, 0x81, 0x7a, 0x6c,
+	0x19, 0xfd, 0x48, 0xbc, 0xbc, 0x40, 0x1e, 0x7b, 0x0e, 0xe8, 0x47, 0x2e,
+	0xc1, 0x22, 0xbf, 0x5f, 0x95, 0xbe, 0x2d, 0x6c, 0x34, 0xaf, 0x62, 0x9f,
+	0x8c, 0x80, 0xd5, 0x53, 0xfd, 0xa2, 0xd0, 0x46, 0x41, 0xdf, 0xc5, 0xf4,
+	0x73, 0x68, 0x2e, 0xea, 0x7b, 0x65, 0x46, 0xea, 0x36, 0x29, 0x4b, 0x87,
+	0xa7, 0x96, 0xef, 0x20, 0x1f, 0x3e, 0x4d, 0x5d, 0x17, 0xfc, 0xc8, 0x9b,
+	0xcf, 0x2b, 0x98, 0x4b, 0xa4, 0x44, 0x97, 0x32, 0xbe, 0x5c, 0xae, 0x28,
+	0xb6, 0x74, 0xe4, 0x6c, 0x1f, 0xa2, 0xb7, 0xf8, 0xf4, 0x12, 0x43, 0xec,
+	0x28, 0x48, 0x5c, 0xd1, 0xc3, 0xcd, 0x84, 0xed, 0x53, 0x09, 0xc4, 0x1c,
+	0x91, 0xe6, 0xa6, 0xb5, 0x89, 0xb9, 0xda, 0xf1, 0x7c, 0x2e, 0xba, 0x87,
+	0x38, 0xae, 0x1a, 0xb2, 0x0e, 0x42, 0x5b, 0x19, 0x16, 0xdd, 0x75, 0x28,
+	0xe7, 0xf2, 0xce, 0x28, 0x79, 0x97, 0x6a, 0xcb, 0xe8, 0x8c, 0x88, 0x6c,
+	0x52, 0x87, 0xb2, 0x5f, 0xc0, 0xbf, 0x72, 0xba, 0xa8, 0x80, 0x67, 0x40,
+	0x78, 0x97, 0x8e, 0x0d, 0x8c, 0xf3, 0x65, 0x03, 0x7e, 0xfa, 0x42, 0x35,
+	0x4a, 0x1f, 0x88, 0x60, 0xfd, 0xa8, 0x86, 0x92, 0x07, 0x2c, 0x6b, 0x6e,
+	0xa8, 0x87, 0x5c, 0xf6, 0xb2, 0x22, 0xc9, 0x9d, 0x9c, 0x49, 0x62, 0x16,
+	0xf1, 0xad, 0x3d, 0xa5, 0xe0, 0x6a, 0xc6, 0xd3, 0x28, 0x71, 0xa8, 0xdd,
+	0xc6, 0x39, 0xab, 0x73, 0x4e, 0xc4, 0x45, 0x1b, 0x5a, 0xc5, 0xfb, 0xad,
+	0xc4, 0xc0, 0x56, 0x62, 0x9a, 0x65, 0xbd, 0x7f, 0x39, 0x3a, 0xcb, 0x22,
+	0x37, 0x13, 0x0b, 0x6b, 0xc9, 0x89, 0x25, 0x7e, 0x5f, 0x8e, 0x35, 0x8c,
+	0xfd, 0xc5, 0x49, 0x3b, 0x9f, 0xa2, 0xee, 0x18, 0xa3, 0x32, 0x8c, 0x71,
+	0x94, 0xfd, 0x69, 0x72, 0x5c, 0xe1, 0xbb, 0x95, 0xc9, 0x0d, 0x8c, 0x75,
+	0x1e, 0x54, 0x0c, 0x5c, 0x86, 0x3b, 0x19, 0xcf, 0xef, 0xd8, 0xe9, 0x47,
+	0x7a, 0xd1, 0x55, 0x94, 0xef, 0x1e, 0xac, 0x4f, 0x19, 0x92, 0x43, 0x45,
+	0x83, 0x8b, 0xc8, 0xb7, 0x33, 0x82, 0x3b, 0x92, 0x8f, 0x95, 0x61, 0x49,
+	0x0b, 0x10, 0x4c, 0x16, 0xf0, 0x2d, 0x2a, 0x6b, 0x47, 0x30, 0x92, 0xe7,
+	0x63, 0xdb, 0x39, 0x5e, 0x24, 0xeb, 0x70, 0x2d, 0x98, 0xcf, 0x58, 0x20,
+	0xf6, 0xa5, 0x31, 0xc7, 0x2c, 0x51, 0x0c, 0xdf, 0x1e, 0xfa, 0xa9, 0xe4,
+	0x3d, 0x57, 0x24, 0x0b, 0xb1, 0x4f, 0xcf, 0x2e, 0x76, 0x74, 0x12, 0x47,
+	0xf4, 0x8d, 0xbf, 0x53, 0xf4, 0xf6, 0x13, 0xca, 0x2b, 0xd8, 0x37, 0xf6,
+	0x2a, 0x86, 0xc6, 0xdc, 0xca, 0xe8, 0x98, 0xf4, 0x35, 0x81, 0xbe, 0xcc,
+	0x9f, 0xea, 0x6b, 0xea, 0xfa, 0xcb, 0xa2, 0xf3, 0xd6, 0x6c, 0xae, 0xce,
+	0xe7, 0x89, 0x4b, 0xcf, 0xe3, 0xc7, 0x32, 0x27, 0x62, 0x97, 0x5e, 0xf4,
+	0xa4, 0xce, 0xad, 0x0b, 0xf4, 0x27, 0xb6, 0xd9, 0xfe, 0xd9, 0x92, 0x11,
+	0x7b, 0x55, 0x19, 0x33, 0x2f, 0xce, 0xe7, 0x2c, 0xb5, 0xd4, 0x41, 0x9f,
+	0x7d, 0x6f, 0x9f, 0xf9, 0x29, 0x64, 0xed, 0x6b, 0x8b, 0xe9, 0x9b, 0xd5,
+	0x28, 0x26, 0x26, 0x06, 0x43, 0x3e, 0x14, 0x57, 0xc9, 0x3a, 0xce, 0xb9,
+	0xdc, 0x7f, 0xc3, 0x4e, 0x86, 0x64, 0x1b, 0x73, 0x1a, 0x89, 0x7f, 0xb5,
+	0x9c, 0xef, 0x1c, 0xce, 0xac, 0xa7, 0x0d, 0x5d, 0x27, 0x36, 0xe4, 0xca,
+	0xd9, 0xd0, 0x47, 0xd7, 0x17, 0x54, 0x90, 0xfb, 0x69, 0x15, 0x76, 0xde,
+	0xd7, 0xa4, 0x5c, 0x9f, 0xb7, 0xab, 0xcf, 0x67, 0x1e, 0x2d, 0xca, 0xe7,
+	0x66, 0x17, 0x94, 0xff, 0x38, 0x1d, 0x5c, 0xf6, 0x67, 0xe8, 0x40, 0xe2,
+	0x81, 0xe4, 0x04, 0xa2, 0x83, 0xf3, 0xf3, 0xf2, 0xfe, 0x44, 0x35, 0x71,
+	0xef, 0x42, 0x5d, 0xcc, 0xcc, 0xeb, 0x62, 0x31, 0xb1, 0x4b, 0xfe, 0x5b,
+	0x38, 0x65, 0x7a, 0xf1, 0xa2, 0x26, 0xe3, 0x5e, 0x8c, 0xf5, 0x1c, 0xaf,
+	0x9b, 0xba, 0x58, 0x1e, 0xaa, 0x44, 0xf0, 0xbc, 0x78, 0x50, 0xcb, 0xd8,
+	0xf1, 0x21, 0x79, 0xa6, 0xfc, 0xf6, 0xe3, 0x05, 0xea, 0xe2, 0x8e, 0xe1,
+	0xc5, 0xb8, 0x8b, 0xfe, 0x94, 0xe3, 0x90, 0xb9, 0xd8, 0xb0, 0x76, 0x58,
+	0xda, 0x14, 0x8c, 0xfb, 0xd9, 0xd9, 0x71, 0xfe, 0x71, 0x5e, 0xfe, 0x0a,
+	0xe5, 0x97, 0x67, 0x07, 0xb2, 0x16, 0x2d, 0xcf, 0x11, 0x64, 0x2c, 0xc6,
+	0x14, 0xdc, 0xb1, 0xac, 0x83, 0xe6, 0x3c, 0xc4, 0xaa, 0xf5, 0x7e, 0x89,
+	0x8f, 0xfd, 0xc4, 0x03, 0x07, 0xf3, 0xc8, 0xa2, 0x48, 0x94, 0xfe, 0xac,
+	0x5e, 0xe5, 0x80, 0x5a, 0xef, 0x40, 0x27, 0xde, 0x30, 0x8d, 0xde, 0x75,
+	0xf8, 0x14, 0xba, 0xbc, 0x16, 0xf6, 0xb2, 0x9d, 0xee, 0x54, 0x09, 0xda,
+	0xeb, 0x69, 0x56, 0x2b, 0x3d, 0xd8, 0x91, 0x8a, 0xb7, 0x12, 0x16, 0x18,
+	0x73, 0x1a, 0xfe, 0x2a, 0x11, 0xd0, 0x5b, 0x36, 0x90, 0xb7, 0x2c, 0xef,
+	0x73, 0xc3, 0xaf, 0xe4, 0x72, 0xb4, 0x01, 0x55, 0xd6, 0x09, 0x23, 0x94,
+	0xbd, 0xc7, 0xce, 0xf7, 0xfc, 0xd3, 0xa5, 0x1f, 0x3f, 0xe2, 0x19, 0xa9,
+	0xeb, 0x47, 0xe9, 0x5c, 0x05, 0xcb, 0xe7, 0xea, 0xf1, 0xa8, 0x62, 0x59,
+	0x0b, 0x42, 0x4e, 0xfb, 0xfe, 0xb6, 0x4c, 0x5d, 0xeb, 0x0d, 0xea, 0xab,
+	0x56, 0x6e, 0x6d, 0x52, 0xd7, 0xa2, 0x4c, 0x0a, 0x8e, 0xfc, 0xd1, 0xf5,
+	0xf9, 0x20, 0xe4, 0xb9, 0x89, 0xdb, 0x58, 0x89, 0xfd, 0xf9, 0xf5, 0x39,
+	0x57, 0xe4, 0xbd, 0x2f, 0xef, 0x35, 0x24, 0x6f, 0x11, 0x9d, 0x4b, 0x7f,
+	0x62, 0x0b, 0xd7, 0x15, 0x0b, 0x06, 0x76, 0x65, 0x16, 0xd2, 0x16, 0x7f,
+	0x6b, 0x8d, 0x7a, 0xa7, 0x96, 0xbd, 0x51, 0xcd, 0xad, 0xb7, 0x4b, 0xd9,
+	0x42, 0xb9, 0x8b, 0x89, 0x09, 0x8d, 0x18, 0x3e, 0xaf, 0x4d, 0xc9, 0x75,
+	0x0b, 0x6d, 0xde, 0xc6, 0x72, 0xd2, 0xae, 0xe0, 0xef, 0x7f, 0x59, 0xfb,
+	0xce, 0x6b, 0xaf, 0xd5, 0x95, 0x6b, 0xef, 0xee, 0x62, 0xc9, 0xdd, 0xfb,
+	0x53, 0x45, 0xac, 0xf3, 0x4e, 0x9e, 0x07, 0x16, 0xca, 0x7c, 0xea, 0x82,
+	0x32, 0xc4, 0x79, 0xe3, 0x4d, 0x6b, 0xcf, 0x79, 0x65, 0x96, 0x3b, 0xcf,
+	0x2f, 0xe3, 0xc4, 0x1c, 0xe3, 0x55, 0xeb, 0xc8, 0x79, 0x65, 0xd2, 0x17,
+	0x94, 0xb9, 0x1c, 0x63, 0xf5, 0x8f, 0x58, 0x43, 0xb9, 0xb9, 0xc9, 0xd2,
+	0x7d, 0xdc, 0x33, 0x23, 0xad, 0x7f, 0x75, 0xc5, 0x3c, 0xbd, 0x63, 0xa6,
+	0x43, 0x9e, 0xd9, 0xb8, 0x91, 0xcd, 0xcd, 0x4d, 0x5c, 0xe6, 0xc6, 0xb5,
+	0xa0, 0x30, 0x37, 0xd7, 0xe5, 0xeb, 0x17, 0xda, 0xbd, 0xae, 0xe8, 0xfc,
+	0x76, 0x0b, 0xd7, 0xaf, 0xb8, 0x40, 0xee, 0xef, 0x5c, 0x50, 0xee, 0xb7,
+	0x7f, 0xa4, 0xde, 0x2f, 0x1c, 0xe7, 0x5f, 0x3f, 0xa0, 0x9e, 0x7f, 0xde,
+	0x9c, 0x3f, 0x2f, 0xe8, 0xbf, 0xea, 0x82, 0xf2, 0x35, 0x17, 0x94, 0x7f,
+	0x59, 0xfd, 0xf8, 0x7e, 0xd6, 0x5d, 0x50, 0xcf, 0x5e, 0xab, 0xc6, 0x53,
+	0x67, 0x7d, 0x1e, 0x4d, 0x45, 0x08, 0x98, 0x4e, 0x05, 0x7e, 0xfa, 0xbe,
+	0xff, 0xe9, 0x0b, 0xd6, 0xac, 0x9b, 0xce, 0xfa, 0xfe, 0x79, 0x9c, 0x33,
+	0x56, 0x1c, 0x91, 0x18, 0x56, 0x44, 0xee, 0x2c, 0x3c, 0xb0, 0x4e, 0x3b,
+	0x97, 0x67, 0x15, 0x62, 0x65, 0x45, 0xac, 0x24, 0xd2, 0x00, 0xff, 0xd8,
+	0x2c, 0xff, 0x9b, 0x09, 0x59, 0xb7, 0xfc, 0x80, 0x5c, 0xca, 0xf0, 0xed,
+	0xc7, 0x2c, 0xff, 0x4f, 0xd3, 0x6f, 0x15, 0xa3, 0xc2, 0x83, 0xab, 0x13,
+	0x1f, 0x5f, 0x4f, 0x8d, 0x40, 0x59, 0xd6, 0xe0, 0x63, 0x7e, 0x05, 0xe7,
+	0x35, 0xf3, 0x30, 0xe5, 0xaf, 0x45, 0xf2, 0x3d, 0xf5, 0x58, 0x43, 0x98,
+	0xf1, 0x39, 0xf7, 0xbc, 0x76, 0x49, 0x46, 0xf7, 0x45, 0x95, 0xdc, 0x33,
+	0xd9, 0xf6, 0xd0, 0x1f, 0xc8, 0x77, 0x3a, 0x29, 0x97, 0xc5, 0xbe, 0x80,
+	0x0d, 0x09, 0xcb, 0x7a, 0x8a, 0x79, 0xaa, 0x3c, 0xeb, 0xff, 0x79, 0xfa,
+	0xf7, 0xd6, 0x84, 0xd7, 0x89, 0xb7, 0x8c, 0xa9, 0xed, 0xf9, 0x51, 0x19,
+	0x31, 0x99, 0x2f, 0xd9, 0x27, 0xea, 0x98, 0x51, 0xb7, 0x71, 0x2f, 0xfd,
+	0x6e, 0x7e, 0x40, 0xf7, 0x27, 0xf1, 0xef, 0x96, 0xbf, 0x46, 0x0f, 0x0e,
+	0x29, 0x85, 0x75, 0xe2, 0x0b, 0xd7, 0x83, 0x2b, 0x62, 0x2e, 0x8e, 0x6f,
+	0x8f, 0xcd, 0xf7, 0x8b, 0x88, 0x71, 0x88, 0x39, 0x23, 0xb3, 0xfc, 0x5b,
+	0x12, 0xf6, 0x38, 0xc9, 0x17, 0x15, 0x1c, 0x6b, 0x98, 0xe5, 0xef, 0x4e,
+	0x7b, 0xb1, 0x9d, 0xf1, 0xb8, 0xc4, 0x68, 0xc0, 0x23, 0x69, 0x15, 0xb7,
+	0xdd, 0xef, 0xc5, 0x5a, 0x72, 0xd1, 0x8d, 0x7d, 0xdf, 0x80, 0x71, 0xa9,
+	0x13, 0xb7, 0xd2, 0xfe, 0xd6, 0xf5, 0x15, 0xdb, 0x39, 0xc8, 0xfa, 0x3e,
+	0x27, 0xea, 0x2f, 0xad, 0x40, 0xbc, 0xa6, 0x18, 0xdf, 0x37, 0x1d, 0xcc,
+	0x7b, 0xca, 0x30, 0x64, 0x63, 0xa2, 0xe4, 0xb2, 0x82, 0x73, 0xa2, 0x37,
+	0x87, 0xbd, 0x2e, 0xf9, 0xf1, 0x58, 0xfe, 0x5b, 0x2b, 0x5b, 0xb3, 0xdd,
+	0xc6, 0x5f, 0x47, 0xc4, 0xb4, 0xe3, 0x25, 0x90, 0xe3, 0x69, 0x5d, 0xe7,
+	0x3d, 0x57, 0x6e, 0x51, 0xe6, 0x44, 0x02, 0x13, 0x8b, 0x15, 0x07, 0xc2,
+	0x81, 0x8a, 0x58, 0x65, 0x24, 0x8c, 0x65, 0x99, 0x2e, 0x9f, 0xcf, 0x7e,
+	0x56, 0x1d, 0xc1, 0xe9, 0x45, 0x26, 0x73, 0x60, 0x38, 0x97, 0x51, 0xf7,
+	0x4d, 0xd4, 0xeb, 0x66, 0xf3, 0x0f, 0x56, 0xd6, 0xf6, 0x7b, 0x37, 0x62,
+	0x9a, 0x65, 0xad, 0xa3, 0x7e, 0x1d, 0xd4, 0xe3, 0xcf, 0xf2, 0xfa, 0x15,
+	0x9d, 0x96, 0x8d, 0xfd, 0xde, 0x3a, 0x46, 0xfd, 0xba, 0xd9, 0x9e, 0x9b,
+	0xed, 0x95, 0x8c, 0x9d, 0xaf, 0xe7, 0x62, 0xca, 0xb3, 0xcc, 0x96, 0xa1,
+	0x52, 0x9e, 0xf5, 0xf9, 0xa3, 0x4a, 0x01, 0xb7, 0xff, 0xd4, 0x98, 0x5e,
+	0x99, 0x92, 0x83, 0x88, 0xfe, 0xfd, 0xd4, 0xbf, 0x60, 0xb8, 0xcc, 0x41,
+	0xbd, 0xac, 0xfb, 0xf4, 0x02, 0xa3, 0x4c, 0xd6, 0x15, 0x4c, 0x33, 0x22,
+	0xf8, 0x76, 0x8b, 0x07, 0x6f, 0x26, 0xca, 0xed, 0x71, 0x5f, 0x3a, 0xd7,
+	0xb2, 0x1e, 0x0f, 0xf9, 0xf1, 0x73, 0xa3, 0x2e, 0xbc, 0x40, 0xd5, 0x31,
+	0xa9, 0x79, 0x91, 0x20, 0xce, 0x76, 0xa5, 0x66, 0x73, 0xbe, 0xbc, 0xd8,
+	0x92, 0xc2, 0x46, 0xda, 0x93, 0xdf, 0x11, 0x01, 0xde, 0x48, 0x18, 0xc1,
+	0xcd, 0xec, 0x7f, 0xd8, 0xdb, 0x40, 0xfe, 0xad, 0x36, 0x91, 0xaa, 0xc5,
+	0x4b, 0x22, 0x46, 0x7c, 0x2b, 0xfe, 0xc3, 0x1a, 0x22, 0xce, 0x17, 0x85,
+	0x64, 0x6d, 0x6e, 0x0e, 0x8e, 0x6b, 0x0e, 0x3c, 0x1b, 0x9c, 0x8e, 0x28,
+	0xdd, 0xb1, 0xcc, 0x78, 0xcb, 0xfa, 0xa1, 0x57, 0xfa, 0x91, 0xb1, 0xfc,
+	0x86, 0xe3, 0x50, 0x6c, 0x2c, 0xdc, 0x92, 0x6a, 0xa0, 0xbe, 0x2f, 0xec,
+	0xff, 0xdf, 0xad, 0x49, 0xaf, 0xf4, 0xcf, 0x5c, 0x9e, 0xf1, 0xec, 0xc8,
+	0x1f, 0xc5, 0xee, 0x97, 0xac, 0xe7, 0xec, 0x36, 0x17, 0xb9, 0x73, 0x71,
+	0x50, 0xda, 0xfb, 0x17, 0x8e, 0x4f, 0xda, 0x2c, 0xf4, 0x23, 0x7a, 0xcb,
+	0xba, 0xc5, 0x9f, 0xb7, 0xa4, 0x44, 0x7f, 0x82, 0x57, 0xc7, 0x2c, 0x4c,
+	0x97, 0xf3, 0x87, 0xed, 0xb2, 0x71, 0xea, 0xab, 0x8b, 0x36, 0xc4, 0xd8,
+	0xcb, 0x3c, 0x4e, 0x76, 0x51, 0x68, 0x76, 0x9e, 0xb6, 0x89, 0xdc, 0x7e,
+	0xc8, 0x5b, 0x89, 0x2d, 0x26, 0xed, 0xce, 0x50, 0x2f, 0x76, 0x42, 0x72,
+	0x53, 0x39, 0x77, 0x61, 0xd2, 0xeb, 0xc0, 0x56, 0xd3, 0x89, 0x76, 0x43,
+	0xd5, 0xe5, 0xba, 0x23, 0x24, 0xe7, 0x2e, 0xf8, 0x6b, 0x14, 0x6c, 0x0f,
+	0xab, 0x58, 0x6f, 0x74, 0xf9, 0xe5, 0xfa, 0x92, 0x90, 0x9c, 0x2b, 0x58,
+	0x43, 0x9d, 0xc4, 0x35, 0x05, 0x1b, 0x0c, 0x79, 0xbe, 0x98, 0xe3, 0xbe,
+	0x31, 0x58, 0xd6, 0x76, 0xb3, 0xf1, 0x8a, 0x32, 0x48, 0x9c, 0x17, 0x2e,
+	0xf7, 0xde, 0xcd, 0xf3, 0x03, 0x71, 0x12, 0x31, 0x3d, 0x56, 0x42, 0x3f,
+	0xdd, 0xd2, 0x37, 0x87, 0xf5, 0x14, 0x72, 0x1c, 0xa7, 0x6f, 0x1b, 0x24,
+	0x7e, 0x06, 0xfc, 0x3f, 0x65, 0xf2, 0x34, 0xe4, 0x9d, 0x47, 0xcd, 0x1a,
+	0xfe, 0x93, 0x9c, 0xb7, 0x4a, 0xc3, 0xb9, 0xf1, 0x07, 0xd0, 0xdb, 0x4b,
+	0x94, 0x79, 0xc1, 0x0a, 0xe6, 0x00, 0x71, 0xe2, 0xfb, 0xc8, 0x98, 0x13,
+	0x9b, 0x53, 0x86, 0xb6, 0xcf, 0xe6, 0x6e, 0x4e, 0xea, 0xc2, 0xc9, 0x1c,
+	0x3f, 0xa0, 0x4d, 0x28, 0x85, 0xf3, 0x39, 0x82, 0x0d, 0xe4, 0xe2, 0x82,
+	0x6f, 0x71, 0xeb, 0xc9, 0x06, 0x49, 0xdb, 0xdc, 0xfe, 0x58, 0xda, 0xc3,
+	0x43, 0xe3, 0xe1, 0xf5, 0xaf, 0x4d, 0xfb, 0xfc, 0x6b, 0xd2, 0xf0, 0xb7,
+	0xa5, 0x0b, 0x76, 0x59, 0xf0, 0x6d, 0xc1, 0x36, 0x8b, 0x7c, 0x33, 0x97,
+	0x73, 0x75, 0x49, 0x4e, 0x03, 0x79, 0x3e, 0xf6, 0xde, 0xcd, 0x4f, 0xd1,
+	0xd6, 0x5d, 0xe4, 0xf2, 0x5b, 0x8d, 0x78, 0x54, 0x9e, 0xd7, 0x19, 0x21,
+	0xdd, 0x57, 0xa4, 0xf8, 0xb1, 0xa5, 0xfe, 0x77, 0x9c, 0x4f, 0x72, 0xdc,
+	0xf4, 0xa7, 0x4a, 0x72, 0xf3, 0x21, 0x7e, 0x26, 0x18, 0xe0, 0x67, 0x1e,
+	0xe4, 0xf3, 0x77, 0xb1, 0x9f, 0x4d, 0xe9, 0xa9, 0x3e, 0xa0, 0xe0, 0x1a,
+	0xb6, 0xd5, 0x18, 0x82, 0x73, 0x69, 0xfd, 0x7f, 0x59, 0x59, 0xef, 0xd4,
+	0x7d, 0x11, 0x20, 0x87, 0x80, 0xb3, 0xad, 0x5e, 0xce, 0x15, 0x34, 0x86,
+	0xe5, 0x5c, 0x41, 0x9b, 0x91, 0x93, 0x4f, 0x7c, 0xb7, 0x9b, 0xb8, 0x7d,
+	0xee, 0xfc, 0x42, 0x2c, 0x32, 0x71, 0x7b, 0x0a, 0xb1, 0xa2, 0x88, 0x60,
+	0x91, 0xdb, 0xff, 0x5c, 0xba, 0x9e, 0x5c, 0x5c, 0x9e, 0x7f, 0xbb, 0x39,
+	0xe7, 0x1e, 0xff, 0xb3, 0xe9, 0x2b, 0x71, 0xdb, 0xae, 0x30, 0xda, 0x77,
+	0xc9, 0x86, 0x23, 0xe6, 0x60, 0xa1, 0x80, 0x7f, 0x14, 0x9a, 0xff, 0x38,
+	0x75, 0x72, 0x94, 0x72, 0x1e, 0x3b, 0x4f, 0x4e, 0xd1, 0x21, 0xfc, 0x77,
+	0x24, 0xdc, 0x48, 0x87, 0xde, 0xb7, 0xe2, 0x36, 0xe7, 0xf0, 0xfa, 0xef,
+	0x4c, 0xf8, 0x91, 0xb5, 0xb9, 0xe7, 0xbf, 0xbb, 0x25, 0x47, 0xec, 0x49,
+	0xc5, 0xa3, 0x4c, 0x79, 0xf3, 0xf3, 0xab, 0x87, 0x65, 0x6e, 0xdf, 0x48,
+	0xc8, 0xbd, 0xe8, 0x37, 0x54, 0xe8, 0x7e, 0x95, 0xb1, 0xb4, 0xdf, 0x14,
+	0xfb, 0xb5, 0xec, 0x67, 0xfb, 0xac, 0x18, 0xf7, 0x44, 0x02, 0xad, 0xf5,
+	0xbc, 0xae, 0x2d, 0x40, 0xac, 0x8a, 0x7a, 0x2a, 0x35, 0xbc, 0xfe, 0xba,
+	0x71, 0x9f, 0xdf, 0x1c, 0x87, 0xff, 0x92, 0xf1, 0xa9, 0x22, 0x90, 0xa3,
+	0xab, 0x1f, 0x87, 0x05, 0x5e, 0xff, 0xba, 0xc4, 0x1c, 0xa8, 0x91, 0xb8,
+	0xb5, 0xa4, 0xe1, 0xb4, 0x35, 0x27, 0x62, 0x64, 0x8f, 0x51, 0x86, 0xf7,
+	0x2f, 0xd7, 0xe3, 0x33, 0x1d, 0x47, 0xef, 0xd5, 0xa6, 0xf4, 0xf1, 0x5e,
+	0xe8, 0xff, 0x6f, 0x1f, 0x85, 0x38, 0x47, 0x7b, 0x68, 0x90, 0x31, 0x48,
+	0xbc, 0x2b, 0x62, 0xce, 0x29, 0x63, 0xf9, 0x54, 0xe1, 0xb9, 0x47, 0x7e,
+	0x5c, 0x0a, 0xe7, 0x1a, 0x36, 0x0f, 0xce, 0xc5, 0x30, 0xcb, 0xea, 0x36,
+	0x7c, 0xf9, 0xe7, 0x67, 0x9c, 0xb3, 0xcc, 0xd1, 0x2b, 0x9c, 0x58, 0x4c,
+	0x3f, 0x68, 0xfc, 0x4b, 0x27, 0xa2, 0xbe, 0x62, 0xc6, 0x56, 0x59, 0x17,
+	0x3a, 0x5e, 0x3f, 0x69, 0x4d, 0x18, 0xf5, 0x68, 0xcc, 0xc8, 0xf3, 0x4c,
+	0x07, 0xed, 0xdb, 0xc2, 0x23, 0xa6, 0xdc, 0x17, 0x9c, 0x89, 0xc7, 0x1c,
+	0xb4, 0x15, 0xb7, 0xa1, 0xb7, 0xfe, 0xbd, 0x52, 0x81, 0xd2, 0x88, 0x33,
+	0x38, 0x01, 0x3d, 0xbc, 0x5e, 0xa1, 0x1f, 0x56, 0xcd, 0x33, 0x65, 0x0a,
+	0xde, 0x4e, 0x04, 0xcc, 0x40, 0x3e, 0x2e, 0x9d, 0xe2, 0xdc, 0xbd, 0x93,
+	0x30, 0xda, 0x9f, 0xca, 0x9f, 0xff, 0x22, 0x3d, 0x35, 0xa7, 0x15, 0x7b,
+	0x74, 0xbb, 0x37, 0x25, 0xf0, 0x9e, 0xa3, 0x01, 0xef, 0xed, 0x31, 0x8b,
+	0x98, 0x8b, 0x89, 0x9d, 0xba, 0xdd, 0x5b, 0x12, 0x98, 0x74, 0xf2, 0xda,
+	0x29, 0x73, 0x36, 0x31, 0x4d, 0xe5, 0xb5, 0xb0, 0xd8, 0x59, 0x4c, 0x63,
+	0x7c, 0x2d, 0x8d, 0x78, 0xdd, 0xa5, 0xe3, 0xd0, 0x4a, 0x8c, 0x0a, 0xe6,
+	0xba, 0x68, 0x72, 0x24, 0x75, 0x7f, 0xb3, 0xa3, 0x9e, 0x39, 0xaf, 0x5f,
+	0x71, 0x19, 0xdf, 0x63, 0x5e, 0x2f, 0x6b, 0x61, 0x61, 0xda, 0xa4, 0x93,
+	0x15, 0x76, 0x4c, 0x57, 0x23, 0x0a, 0xb1, 0xb0, 0x02, 0xb7, 0x6b, 0x1b,
+	0x3e, 0xab, 0x46, 0xfa, 0x71, 0x7d, 0x83, 0xbb, 0xa9, 0x72, 0xbc, 0xa0,
+	0x13, 0xc4, 0x3c, 0x11, 0xe6, 0x25, 0x06, 0xd4, 0xf2, 0x88, 0xe8, 0xc6,
+	0xdf, 0x94, 0x1c, 0x13, 0x59, 0x35, 0x77, 0xdf, 0xd8, 0x3b, 0x25, 0x28,
+	0x0d, 0x13, 0xab, 0x7e, 0xe2, 0xfb, 0xef, 0xd5, 0x3b, 0x5a, 0x22, 0x78,
+	0xef, 0x32, 0xe4, 0xbf, 0x6d, 0x5b, 0x6e, 0x77, 0xe4, 0x83, 0x98, 0x3b,
+	0x60, 0x59, 0x8c, 0x93, 0x3e, 0x28, 0xb3, 0x39, 0x1e, 0xfa, 0x1a, 0xe7,
+	0x66, 0x4d, 0xfa, 0x0f, 0xd6, 0xe7, 0x9c, 0x36, 0x07, 0x70, 0x17, 0x47,
+	0x3a, 0x6e, 0x79, 0xcb, 0xf8, 0xc0, 0x7a, 0x33, 0xc1, 0x5c, 0xd9, 0x90,
+	0x67, 0x43, 0x73, 0xb0, 0xcd, 0x74, 0x36, 0x2f, 0x55, 0x14, 0xf4, 0x18,
+	0xf3, 0xb4, 0x12, 0xc6, 0xa9, 0x6e, 0xfa, 0x75, 0xcc, 0x6b, 0x04, 0xf7,
+	0x80, 0xe5, 0xd2, 0xeb, 0xd6, 0xb9, 0x22, 0x77, 0xde, 0x32, 0xd2, 0x20,
+	0x58, 0x10, 0x6e, 0x7b, 0xca, 0x68, 0x41, 0x4f, 0x66, 0x10, 0xbd, 0x99,
+	0x5c, 0x3f, 0x59, 0xcc, 0xf9, 0x98, 0x7e, 0xd6, 0xad, 0x2b, 0x8e, 0x08,
+	0xf7, 0x3a, 0x73, 0xcb, 0x5e, 0x23, 0x8a, 0xcd, 0x99, 0x3b, 0x6f, 0x39,
+	0xd5, 0xd0, 0xcf, 0xff, 0xb9, 0x3a, 0x43, 0xa8, 0xfc, 0xd8, 0x3a, 0x65,
+	0x11, 0xe9, 0xa3, 0xe3, 0x96, 0xa7, 0x8c, 0x3b, 0x6f, 0x69, 0x5f, 0xf4,
+	0x4d, 0x6c, 0xca, 0xb4, 0xff, 0xc9, 0x7e, 0xca, 0x59, 0xa7, 0x34, 0x72,
+	0xa8, 0xed, 0x9a, 0xc0, 0x9d, 0xb7, 0xa4, 0x17, 0xf5, 0xb2, 0x8f, 0x55,
+	0x8c, 0x2f, 0xb9, 0x3a, 0x51, 0xc6, 0xf6, 0x8f, 0xd3, 0x41, 0x49, 0x64,
+	0xa2, 0x6d, 0x7e, 0xe0, 0x03, 0x6b, 0x5e, 0x5f, 0x91, 0xad, 0x03, 0x17,
+	0x75, 0xf0, 0xa0, 0xe9, 0xcc, 0x06, 0x1c, 0xb6, 0x0e, 0x3a, 0x7c, 0xd4,
+	0x41, 0x92, 0x3a, 0xc8, 0xd6, 0x18, 0xe1, 0x77, 0xa9, 0x83, 0x79, 0x63,
+	0xeb, 0xd6, 0x95, 0x44, 0xe0, 0x74, 0x18, 0xaf, 0x3a, 0x9c, 0x9c, 0x0b,
+	0x97, 0xb1, 0x8e, 0x7a, 0xbb, 0xf3, 0x96, 0x8b, 0x17, 0xd9, 0x3a, 0xff,
+	0xb2, 0x3b, 0xb0, 0xc1, 0xde, 0x3b, 0xd7, 0x9d, 0x59, 0xc3, 0xa3, 0x99,
+	0xc7, 0x7d, 0x3c, 0x7a, 0x98, 0xb3, 0xdc, 0x4c, 0x5d, 0x35, 0x71, 0x1c,
+	0x2b, 0x28, 0xd7, 0x46, 0xfe, 0x6e, 0xe5, 0xef, 0x0e, 0xfe, 0x96, 0xf9,
+	0x51, 0xcf, 0xca, 0x16, 0x3b, 0x2b, 0x9b, 0x83, 0xf2, 0x78, 0x88, 0x57,
+	0x32, 0x26, 0xf7, 0x57, 0xae, 0x09, 0xc4, 0xd8, 0xc6, 0xfd, 0xa5, 0xb2,
+	0x6f, 0xc8, 0x65, 0xc4, 0x7d, 0x4e, 0x88, 0x7c, 0x7a, 0x6b, 0x3b, 0xb2,
+	0xc4, 0xde, 0xdf, 0xe7, 0xb0, 0x97, 0xb2, 0x55, 0x70, 0x7e, 0x5e, 0x58,
+	0x34, 0x34, 0xc3, 0x63, 0xc0, 0xe7, 0x36, 0xe2, 0xcc, 0xf9, 0x13, 0xd4,
+	0x81, 0xd8, 0xc9, 0x3d, 0xd4, 0x5f, 0x27, 0xeb, 0x1c, 0x65, 0x2c, 0xdb,
+	0xcd, 0xfe, 0xed, 0xf5, 0xdb, 0xb0, 0xfd, 0x9c, 0x0c, 0xba, 0x79, 0x9c,
+	0xed, 0xed, 0x35, 0x7e, 0x53, 0x76, 0xb4, 0x5e, 0xf6, 0x53, 0x3a, 0x31,
+	0x6c, 0xcf, 0xbb, 0x42, 0x2e, 0x73, 0x11, 0x79, 0x82, 0x65, 0xfd, 0xd4,
+	0x68, 0x9c, 0xef, 0xb0, 0xed, 0xea, 0x50, 0x9b, 0x3b, 0xe0, 0xc6, 0x90,
+	0xbd, 0x06, 0x6e, 0x59, 0x45, 0xb6, 0x7d, 0x89, 0x2c, 0x75, 0xcd, 0x9b,
+	0x68, 0x78, 0xeb, 0xd2, 0x1f, 0x90, 0x27, 0x8a, 0xfc, 0x73, 0x70, 0x92,
+	0x31, 0x35, 0xaa, 0xc5, 0xdb, 0x45, 0xd6, 0x32, 0xc3, 0x19, 0xbe, 0x16,
+	0xf1, 0x16, 0x27, 0xfb, 0x6b, 0x26, 0xa7, 0x3c, 0x95, 0xc7, 0xee, 0x7d,
+	0x69, 0x3d, 0xb6, 0x5f, 0xc9, 0xf1, 0xd3, 0xde, 0xb1, 0x42, 0xfc, 0x09,
+	0x92, 0xcf, 0x7a, 0xe0, 0x8c, 0xe8, 0xfe, 0x26, 0x47, 0x57, 0xd0, 0x05,
+	0xfa, 0x58, 0xa9, 0xc8, 0x1b, 0xa7, 0xec, 0x82, 0xc7, 0x6e, 0x6d, 0x8d,
+	0x8d, 0xd1, 0xf1, 0xf9, 0x2e, 0x78, 0xb4, 0xb5, 0xe9, 0x42, 0xec, 0xf2,
+	0x68, 0x6d, 0x09, 0xf1, 0x77, 0x59, 0xab, 0x0f, 0xdb, 0xdc, 0xe3, 0x48,
+	0xe6, 0xa5, 0x52, 0xd9, 0x8b, 0x47, 0xdf, 0xaf, 0x70, 0x1a, 0xb9, 0x76,
+	0x35, 0xb6, 0xdb, 0xe2, 0xd0, 0x70, 0xce, 0x77, 0x75, 0xad, 0xc5, 0x21,
+	0xfb, 0x5f, 0x89, 0x4a, 0xe9, 0x7c, 0xbd, 0x1c, 0x7e, 0x2d, 0x76, 0xd9,
+	0xf8, 0xc5, 0x36, 0x4a, 0x81, 0x25, 0x89, 0x0b, 0xfb, 0x97, 0xfe, 0xa4,
+	0xdf, 0xae, 0x2a, 0x15, 0x13, 0xf6, 0xb3, 0x92, 0x83, 0x99, 0x18, 0x06,
+	0x53, 0x53, 0xf7, 0xe8, 0xe9, 0x87, 0xd8, 0xfe, 0x81, 0x38, 0xe7, 0x69,
+	0xb6, 0x21, 0xfb, 0xf7, 0x64, 0xcf, 0xde, 0xd4, 0xfd, 0x7a, 0x22, 0x5b,
+	0x65, 0x19, 0x81, 0x0d, 0x7b, 0x89, 0x7f, 0xd1, 0x16, 0xa9, 0x6f, 0x59,
+	0xaf, 0xcd, 0x0b, 0x22, 0x3b, 0xcd, 0x89, 0xc1, 0xb9, 0xc0, 0x40, 0x52,
+	0xf6, 0x53, 0x9d, 0x89, 0xad, 0x66, 0x1e, 0x19, 0xad, 0xae, 0xd3, 0xba,
+	0x55, 0xd9, 0x0b, 0xf5, 0xc1, 0x97, 0x7b, 0x8c, 0x5a, 0xad, 0x47, 0xcd,
+	0xee, 0x67, 0x7c, 0xd9, 0x0d, 0xcc, 0x2e, 0x13, 0x0c, 0xa8, 0x32, 0xa2,
+	0xbd, 0x55, 0x98, 0x0b, 0x7f, 0xb5, 0x8d, 0xcb, 0xf1, 0x6f, 0xab, 0x46,
+	0x70, 0xa5, 0xf0, 0x4a, 0xf5, 0x7d, 0x6b, 0x88, 0xdc, 0xe4, 0xee, 0xb9,
+	0xff, 0xa7, 0x34, 0xbf, 0xee, 0xd4, 0x3e, 0x9d, 0xf3, 0xf2, 0xf3, 0x05,
+	0xba, 0x3f, 0xad, 0x88, 0x8e, 0x84, 0x4b, 0x25, 0xb0, 0x95, 0x71, 0xf6,
+	0xbf, 0xe6, 0x46, 0xb0, 0x8f, 0xff, 0x7f, 0x76, 0xa5, 0xec, 0x4d, 0xb5,
+	0xac, 0x60, 0x60, 0x5e, 0xb8, 0x8a, 0x63, 0x78, 0x96, 0xf7, 0x7b, 0x33,
+	0x6f, 0x59, 0xa7, 0xa6, 0x1b, 0xfd, 0xcb, 0x18, 0xec, 0x06, 0xc6, 0x75,
+	0x6d, 0x52, 0xfd, 0xef, 0xee, 0x95, 0x83, 0xbb, 0x82, 0x63, 0xf9, 0x7e,
+	0xa0, 0x4e, 0x4b, 0xaa, 0xa5, 0x65, 0xa2, 0xd7, 0x81, 0xf1, 0x57, 0xa6,
+	0x3c, 0x3b, 0x28, 0xf0, 0x59, 0x7b, 0x5d, 0xa5, 0x77, 0x88, 0xbe, 0x3e,
+	0xa4, 0x45, 0xe3, 0xd4, 0xbb, 0x7b, 0x1a, 0xc7, 0x7c, 0xf7, 0xdc, 0x2f,
+	0xd9, 0xe3, 0xac, 0x36, 0x66, 0x72, 0x8c, 0x0a, 0xb4, 0xb9, 0xff, 0x99,
+	0x5f, 0x7f, 0x6d, 0x24, 0xfb, 0x1a, 0xb2, 0x9a, 0xe8, 0x1b, 0x45, 0xac,
+	0x73, 0xb5, 0xf9, 0xf0, 0x8c, 0xae, 0x7a, 0xdd, 0x77, 0x37, 0x6d, 0x34,
+	0x34, 0xf7, 0xd7, 0x16, 0x6d, 0xda, 0xfc, 0x16, 0x47, 0x7d, 0x5b, 0xc2,
+	0x8e, 0x55, 0x9c, 0x57, 0x23, 0x3a, 0x57, 0x79, 0xc7, 0x42, 0x4d, 0x20,
+	0x3c, 0xd7, 0x1e, 0x3f, 0x70, 0x6b, 0x3a, 0x81, 0x6d, 0x29, 0x69, 0x53,
+	0xc1, 0xb2, 0xc0, 0xdb, 0x96, 0x7f, 0x7a, 0x02, 0x5b, 0x32, 0x9f, 0xc4,
+	0x4d, 0x07, 0xc9, 0x8d, 0xf5, 0xd6, 0x38, 0xf4, 0x68, 0xee, 0xd9, 0xd4,
+	0x1c, 0x59, 0xdb, 0x96, 0xbd, 0x45, 0xb7, 0x24, 0x02, 0x70, 0x97, 0x13,
+	0x83, 0xc7, 0x02, 0xf2, 0x2c, 0xd3, 0x8b, 0x6c, 0x8b, 0x94, 0xa9, 0xd5,
+	0xc6, 0x90, 0x25, 0x73, 0x94, 0xb5, 0xd0, 0xfe, 0xb2, 0xdc, 0x3e, 0x09,
+	0x1a, 0x5e, 0x8d, 0xae, 0xbd, 0x41, 0xae, 0xd7, 0x6c, 0x48, 0x1b, 0x0a,
+	0xe6, 0x07, 0xa6, 0xa1, 0x6e, 0xe5, 0xab, 0xaf, 0x17, 0x05, 0x8a, 0x18,
+	0x4f, 0xc4, 0xb7, 0x8c, 0x8d, 0xc7, 0xf0, 0x1b, 0x62, 0x90, 0xec, 0x19,
+	0x4b, 0x4a, 0x3d, 0xb6, 0x35, 0x17, 0x69, 0xf1, 0x53, 0x43, 0xf6, 0x2f,
+	0x5b, 0xd6, 0x35, 0x81, 0x37, 0xad, 0x68, 0x0d, 0xe5, 0x21, 0x5f, 0xcb,
+	0xd5, 0x95, 0x32, 0xf9, 0xbd, 0x40, 0x4a, 0xe3, 0x2d, 0xa2, 0x93, 0x27,
+	0xcd, 0x38, 0xb3, 0x01, 0xc1, 0xfd, 0x0f, 0x62, 0x6f, 0x19, 0x8a, 0xfd,
+	0x8c, 0x71, 0x99, 0x52, 0xc9, 0x38, 0xea, 0xf4, 0x8f, 0xd8, 0xeb, 0x05,
+	0x1d, 0xc4, 0x68, 0xe1, 0x97, 0x92, 0xf3, 0x39, 0xf1, 0x94, 0x51, 0x85,
+	0x27, 0xb5, 0x1c, 0x57, 0x23, 0xd6, 0xe1, 0x07, 0x89, 0x79, 0x59, 0x7a,
+	0x08, 0x39, 0xaf, 0xd1, 0x7e, 0x46, 0xf9, 0x0d, 0xfd, 0x1c, 0x78, 0x21,
+	0xbd, 0x11, 0x0f, 0xca, 0x1a, 0xa2, 0x52, 0xdb, 0x5c, 0xe7, 0x90, 0xfe,
+	0x36, 0x62, 0x6b, 0x46, 0xda, 0xfa, 0x20, 0xb6, 0xd7, 0xd8, 0x9d, 0x97,
+	0x55, 0xb0, 0xfc, 0x83, 0xd8, 0x53, 0xc6, 0xe3, 0xf6, 0xdc, 0xc9, 0x73,
+	0xaf, 0x5e, 0x53, 0x30, 0xaf, 0x14, 0x2a, 0xf3, 0x06, 0x87, 0x71, 0x33,
+	0x1c, 0x55, 0xdf, 0xa4, 0xed, 0xc9, 0xbe, 0x9a, 0xaf, 0xc2, 0x59, 0xe5,
+	0xa2, 0x6f, 0xde, 0x0a, 0x57, 0x95, 0x70, 0xf5, 0x02, 0x8f, 0x8e, 0xf2,
+	0xbe, 0xe8, 0x36, 0xdc, 0x26, 0xba, 0x75, 0x12, 0x87, 0x7a, 0x24, 0xaf,
+	0x33, 0x2a, 0xa9, 0x23, 0xbd, 0x95, 0x9c, 0x1e, 0xe5, 0xc4, 0x4c, 0xc6,
+	0x47, 0x37, 0xf3, 0xb7, 0xb6, 0x77, 0xa9, 0xf7, 0x79, 0x7d, 0x65, 0xe4,
+	0xf0, 0x96, 0xf5, 0x3e, 0x39, 0xfc, 0xfc, 0x40, 0x5d, 0xd6, 0x20, 0x4e,
+	0xe1, 0x06, 0xbd, 0x39, 0x4e, 0xbc, 0x59, 0x6d, 0x9c, 0xb1, 0x62, 0xab,
+	0xa4, 0x8c, 0xee, 0x8b, 0x29, 0x85, 0x3e, 0x16, 0xc0, 0x3f, 0xcd, 0x82,
+	0x2b, 0x22, 0xcf, 0x14, 0x64, 0xbd, 0xb8, 0x51, 0x9e, 0xf5, 0xb5, 0xc8,
+	0xf8, 0x5d, 0xb2, 0xee, 0x86, 0xe8, 0x84, 0x0b, 0x46, 0x76, 0x9f, 0xcc,
+	0xd9, 0x0c, 0x0b, 0x81, 0x85, 0xbf, 0x67, 0x2e, 0x24, 0xf3, 0x53, 0x9b,
+	0xad, 0x57, 0xb2, 0x41, 0x1f, 0x39, 0xfd, 0xa3, 0xd0, 0x5b, 0x12, 0xd4,
+	0x75, 0x53, 0x48, 0x9e, 0xdf, 0x3b, 0x7d, 0x09, 0xd8, 0x3c, 0xde, 0x3c,
+	0x89, 0xcf, 0xa1, 0x9c, 0xb9, 0xeb, 0xdc, 0xb1, 0x15, 0xa8, 0xa8, 0x8a,
+	0xfa, 0x4a, 0x71, 0x19, 0xcf, 0xd7, 0x30, 0x3f, 0xf9, 0x22, 0x2a, 0x56,
+	0xb6, 0x22, 0xc1, 0xb1, 0x97, 0x1b, 0x7f, 0xc5, 0x6b, 0xf7, 0x21, 0x99,
+	0x72, 0x71, 0x1c, 0x3f, 0xb1, 0x2a, 0x6a, 0x44, 0x36, 0xd3, 0x5b, 0x66,
+	0x30, 0x9f, 0xb6, 0x75, 0x41, 0xdc, 0x4e, 0x09, 0x47, 0xaa, 0x8b, 0xae,
+	0x07, 0x73, 0xfb, 0x1a, 0xbd, 0x75, 0x8d, 0xd2, 0x41, 0x9b, 0xed, 0xa1,
+	0xce, 0xa5, 0xac, 0x65, 0x2d, 0x0f, 0x9c, 0xa6, 0x8e, 0x3b, 0x78, 0x6e,
+	0xf8, 0xdf, 0x84, 0x7a, 0x59, 0x31, 0x4e, 0x58, 0x71, 0xcd, 0x47, 0xbb,
+	0x54, 0x57, 0x09, 0x9f, 0x5a, 0x1a, 0x7a, 0x8f, 0xf7, 0xb5, 0xbc, 0x9d,
+	0x9e, 0xb9, 0x25, 0xa7, 0xcb, 0x30, 0x75, 0xf9, 0x6f, 0xf6, 0x75, 0x87,
+	0x7d, 0xbd, 0x23, 0x7f, 0xfd, 0xcc, 0x2d, 0x3d, 0xc6, 0xcb, 0xbc, 0xde,
+	0x4b, 0xdd, 0xab, 0x17, 0x49, 0xfd, 0x75, 0xa6, 0xd4, 0x67, 0x4a, 0x65,
+	0xf4, 0xe4, 0xe7, 0xe3, 0x50, 0x7e, 0x3e, 0x26, 0xf2, 0x6d, 0x38, 0xd9,
+	0x46, 0x3c, 0x5a, 0x0a, 0x13, 0x65, 0x01, 0xc1, 0x79, 0x91, 0x8b, 0x73,
+	0x97, 0x11, 0xb9, 0xd6, 0x30, 0xde, 0x75, 0x3d, 0x53, 0x8a, 0x78, 0xc7,
+	0x4c, 0xdb, 0x0e, 0xcf, 0xdc, 0x22, 0xfb, 0xde, 0xde, 0x52, 0x1a, 0x7d,
+	0xb2, 0x65, 0x23, 0x45, 0x2e, 0x7b, 0xaf, 0xe9, 0x0c, 0xd7, 0x3b, 0xe6,
+	0x65, 0x8b, 0x61, 0xc4, 0xce, 0x28, 0x2e, 0x8f, 0xe0, 0x43, 0x22, 0xdd,
+	0xc8, 0xcc, 0x2b, 0x1e, 0x64, 0xce, 0x14, 0xcc, 0x50, 0xb7, 0x6d, 0x44,
+	0xec, 0x43, 0xf6, 0xde, 0x37, 0xe7, 0xc4, 0x0a, 0x34, 0xea, 0x0e, 0xcc,
+	0x0b, 0xcf, 0x64, 0xe6, 0x45, 0xbb, 0x34, 0x8b, 0x1d, 0xba, 0xff, 0x7a,
+	0x2c, 0xb7, 0xeb, 0xed, 0x4b, 0x67, 0xdb, 0x4b, 0x39, 0xa7, 0x8f, 0x51,
+	0x8e, 0x6d, 0x01, 0x91, 0xe3, 0x9b, 0x79, 0x39, 0x5a, 0x19, 0x4b, 0x4d,
+	0xed, 0xda, 0x40, 0xef, 0x59, 0xbd, 0x3d, 0x63, 0xeb, 0xed, 0x3e, 0x9e,
+	0x17, 0x33, 0xbf, 0x2f, 0xc2, 0xd1, 0x7a, 0x6f, 0x7e, 0x1f, 0x9b, 0xe4,
+	0x6a, 0x82, 0xbf, 0x0d, 0x7f, 0xbd, 0xda, 0xd0, 0xc3, 0x0e, 0x9b, 0xd7,
+	0xbb, 0x11, 0xb7, 0x39, 0xb3, 0x3c, 0xf3, 0xae, 0xc0, 0x23, 0x76, 0x39,
+	0x17, 0x75, 0x52, 0x86, 0x47, 0xf3, 0xfe, 0x22, 0x7b, 0x0e, 0x1e, 0xb3,
+	0x7f, 0xef, 0xe6, 0xdc, 0xba, 0xe8, 0xab, 0x85, 0x18, 0x25, 0xeb, 0xed,
+	0xff, 0xc3, 0xf6, 0xfd, 0x21, 0x1c, 0xb7, 0xff, 0x67, 0x73, 0xf9, 0x16,
+	0x7a, 0x4c, 0xd9, 0x3b, 0x53, 0x86, 0x6e, 0x7b, 0x0f, 0xb9, 0xac, 0x01,
+	0x5c, 0x89, 0xcd, 0x9a, 0xac, 0x07, 0x93, 0xfb, 0x68, 0x62, 0x13, 0x9d,
+	0x48, 0x6a, 0xa6, 0x37, 0x53, 0x3f, 0x35, 0x57, 0x32, 0xb1, 0xa7, 0xfe,
+	0x03, 0x2b, 0x6a, 0xe7, 0x4f, 0x27, 0xac, 0xbd, 0xc6, 0xd1, 0x10, 0x3d,
+	0xb8, 0xbd, 0xc8, 0xd6, 0x6f, 0xb8, 0xcd, 0xde, 0xff, 0x47, 0x99, 0x9f,
+	0x49, 0x48, 0x1c, 0x9d, 0x83, 0xb4, 0x69, 0xc7, 0xe2, 0x96, 0xed, 0x9c,
+	0x93, 0x9e, 0x54, 0x20, 0x7a, 0x09, 0xef, 0x4d, 0x30, 0x96, 0x75, 0x53,
+	0x9f, 0xb1, 0x16, 0xe1, 0x67, 0x6b, 0xb0, 0x9b, 0x36, 0x36, 0x6e, 0x5a,
+	0xd6, 0x3e, 0x62, 0x44, 0xe5, 0x3c, 0x15, 0xd9, 0x9a, 0x35, 0x48, 0x31,
+	0x36, 0xed, 0x33, 0x1a, 0x3f, 0x57, 0x84, 0xb8, 0xdf, 0x0d, 0xdd, 0xb7,
+	0x85, 0xa3, 0xb9, 0x97, 0xf3, 0x75, 0xd4, 0x14, 0xde, 0xe8, 0x3c, 0xb3,
+	0x14, 0x46, 0x78, 0xb1, 0xe3, 0x27, 0xd6, 0xa4, 0xfd, 0xec, 0xb8, 0xeb,
+	0x5f, 0x28, 0xc3, 0x46, 0x71, 0xde, 0x4a, 0xce, 0xf1, 0xbb, 0x01, 0x79,
+	0x7e, 0x0d, 0xd4, 0xf5, 0x35, 0xb6, 0x8b, 0x0c, 0x7b, 0x43, 0xce, 0xd8,
+	0x3e, 0x04, 0x5a, 0x36, 0x28, 0xe7, 0x72, 0x83, 0x4b, 0xc6, 0x4c, 0x8c,
+	0xd6, 0x3f, 0x4b, 0x1e, 0x23, 0xf5, 0x8b, 0xf1, 0x84, 0xf9, 0xb4, 0x55,
+	0x3b, 0xe3, 0xfb, 0xd6, 0x7e, 0x43, 0x5d, 0x4f, 0x6d, 0xc7, 0xca, 0xd9,
+	0x56, 0x19, 0xdb, 0xba, 0x3d, 0xa0, 0x9b, 0xdb, 0xd9, 0xd6, 0xf1, 0xc4,
+	0xd1, 0xa0, 0x9b, 0x6d, 0x3d, 0x6a, 0x4a, 0x6e, 0xe0, 0x6c, 0x6e, 0xe6,
+	0xdc, 0x76, 0xa5, 0x02, 0xbe, 0xad, 0x94, 0x4b, 0xf2, 0xb7, 0xaf, 0x26,
+	0xe4, 0x5d, 0x8f, 0x6f, 0x72, 0x3c, 0xd1, 0x8d, 0x2e, 0x34, 0xde, 0x5b,
+	0x41, 0xfb, 0xa9, 0x44, 0xc1, 0xd6, 0x75, 0x1f, 0xf1, 0x0e, 0xb7, 0xb3,
+	0xcc, 0xeb, 0x81, 0x39, 0x78, 0x21, 0xd4, 0xb8, 0x72, 0x0e, 0x9c, 0xe4,
+	0x21, 0x81, 0xe6, 0x0d, 0x4a, 0x5c, 0x13, 0x5b, 0xbc, 0x2d, 0xad, 0x07,
+	0x9b, 0x20, 0xd8, 0xdd, 0x4a, 0x7d, 0xcc, 0xc1, 0xfb, 0x0b, 0x45, 0x2e,
+	0x67, 0x38, 0xe8, 0x08, 0x74, 0x3c, 0xcd, 0xf9, 0xad, 0x98, 0x97, 0xcb,
+	0x53, 0x33, 0xf6, 0x7e, 0xcd, 0x56, 0x24, 0x33, 0x27, 0xde, 0xdd, 0x6b,
+	0xc0, 0x79, 0xa8, 0xfe, 0x41, 0x0b, 0xf6, 0xbb, 0x21, 0x8d, 0x32, 0x0f,
+	0xad, 0x32, 0x0f, 0xa5, 0xf4, 0xa7, 0x6b, 0x28, 0xf7, 0x7a, 0x5b, 0xee,
+	0x39, 0x18, 0x36, 0x65, 0xfd, 0xcb, 0xa9, 0xdd, 0x86, 0x5e, 0x62, 0x67,
+	0xe0, 0x4c, 0x17, 0xfb, 0x79, 0x9d, 0x32, 0xcf, 0xa3, 0xde, 0x27, 0x5b,
+	0x84, 0xb7, 0xde, 0x87, 0xbe, 0x54, 0xe1, 0xdd, 0x11, 0x05, 0xe9, 0x80,
+	0xf4, 0x71, 0x1f, 0x79, 0x5c, 0x97, 0x35, 0x59, 0x23, 0xd7, 0x77, 0x33,
+	0xf7, 0x8f, 0x6a, 0xf4, 0x07, 0xea, 0x1d, 0xfa, 0x1c, 0xe8, 0x13, 0x6f,
+	0x38, 0xa2, 0xf4, 0x01, 0xd3, 0x7b, 0x86, 0xd8, 0x70, 0x08, 0x1d, 0x16,
+	0xaa, 0x6c, 0x7b, 0xf8, 0xd9, 0x88, 0xf1, 0xa1, 0x22, 0xb1, 0x3d, 0x4b,
+	0x1d, 0xa8, 0x9c, 0x13, 0xd1, 0x41, 0x39, 0x7d, 0x76, 0x2c, 0xa0, 0xfb,
+	0x5f, 0xa0, 0x3c, 0xdb, 0x29, 0xcf, 0x8a, 0xdc, 0x1c, 0xfa, 0x36, 0x2b,
+	0xe2, 0xd3, 0x81, 0x96, 0xd5, 0xbc, 0xbe, 0x8d, 0xf2, 0x04, 0xfa, 0x14,
+	0x0c, 0xb5, 0xf4, 0x90, 0x2b, 0x76, 0x50, 0x07, 0xe7, 0xe4, 0x71, 0xdb,
+	0x73, 0xd6, 0x41, 0x2e, 0x50, 0x8c, 0xbd, 0xa6, 0xe0, 0xb7, 0x86, 0x61,
+	0xda, 0xe9, 0x1e, 0xce, 0x48, 0xd4, 0xab, 0xa2, 0xd8, 0x10, 0x0c, 0xa8,
+	0xe1, 0x35, 0x17, 0xe7, 0xa6, 0x12, 0xfb, 0xb5, 0xdd, 0xf6, 0x5e, 0xe5,
+	0x1c, 0xb7, 0xfb, 0x83, 0x35, 0xea, 0x15, 0x7e, 0x26, 0xeb, 0x63, 0xb2,
+	0x86, 0xd4, 0xeb, 0xc9, 0xed, 0xd7, 0x72, 0x51, 0x27, 0xb9, 0xeb, 0xcf,
+	0x68, 0xc2, 0x7d, 0x0b, 0xe5, 0x7f, 0x69, 0x3d, 0x69, 0x97, 0x97, 0x72,
+	0x2e, 0x9b, 0xa3, 0x97, 0xda, 0xe5, 0x7e, 0x69, 0x3d, 0xab, 0x39, 0xa7,
+	0x94, 0x2b, 0x3c, 0x2f, 0x3c, 0xfa, 0x0d, 0x27, 0x31, 0xaf, 0x78, 0xee,
+	0x62, 0x1c, 0x33, 0x4e, 0xd4, 0x9e, 0xac, 0xef, 0x64, 0x1c, 0x9b, 0xba,
+	0x7f, 0xcb, 0xc2, 0xe3, 0x76, 0x1e, 0xde, 0x45, 0x3e, 0x7b, 0x74, 0x47,
+	0x11, 0x84, 0xa3, 0xca, 0xfa, 0x5d, 0x73, 0xd9, 0xb9, 0x5c, 0x56, 0xf6,
+	0x35, 0x5d, 0x66, 0x73, 0xc3, 0xa8, 0x2a, 0xb8, 0xfb, 0x49, 0x7b, 0xf8,
+	0x84, 0xbb, 0x74, 0x62, 0x8f, 0x51, 0xe0, 0x2c, 0x47, 0x1f, 0x54, 0x89,
+	0x93, 0x03, 0xe6, 0x62, 0x89, 0xcd, 0x7e, 0xd6, 0x0f, 0xc6, 0xd4, 0xa9,
+	0xdc, 0xe6, 0x76, 0x0f, 0x2a, 0xba, 0xb6, 0x3a, 0x20, 0xfb, 0x47, 0x65,
+	0x2f, 0xa8, 0xf4, 0x55, 0x92, 0x5f, 0x97, 0xfa, 0x38, 0xae, 0x51, 0xe8,
+	0x4b, 0xf8, 0xc6, 0xfb, 0xa5, 0x85, 0x7d, 0x86, 0x51, 0x5b, 0xce, 0x5f,
+	0x59, 0x2b, 0xb5, 0xec, 0x4c, 0x0d, 0xe7, 0xcb, 0x1e, 0xcd, 0xcb, 0x1e,
+	0xfb, 0xd8, 0x75, 0xb5, 0xa9, 0xfb, 0xee, 0x82, 0xf9, 0xe7, 0x5d, 0xf2,
+	0x0c, 0x46, 0xd6, 0x5c, 0xe5, 0x9e, 0x82, 0x2e, 0xe2, 0x50, 0x54, 0x6b,
+	0x64, 0x9c, 0xd7, 0x7d, 0x6b, 0x39, 0x1f, 0x71, 0xaf, 0xec, 0x51, 0x2f,
+	0xc4, 0xc8, 0x62, 0xe4, 0xd6, 0x3e, 0x65, 0x9f, 0x45, 0x6e, 0xbd, 0x93,
+	0x76, 0x8f, 0xae, 0xf4, 0xef, 0xad, 0xac, 0xd7, 0xc9, 0x58, 0x78, 0x6e,
+	0x7f, 0xf4, 0x10, 0xf5, 0x3a, 0xcc, 0x7b, 0x9b, 0xcf, 0xae, 0xa7, 0xc8,
+	0x9a, 0x92, 0xc4, 0xde, 0xdf, 0x59, 0x6d, 0xe7, 0x95, 0x9d, 0xba, 0x57,
+	0xbc, 0x26, 0x26, 0xcf, 0xdc, 0x46, 0xf3, 0xeb, 0xee, 0x4d, 0x1f, 0x79,
+	0xe6, 0x36, 0x41, 0x5b, 0x42, 0x74, 0x33, 0xb9, 0x5d, 0x1c, 0x3d, 0x18,
+	0x4d, 0xd4, 0x69, 0x5b, 0xa0, 0xc9, 0x7a, 0x33, 0xff, 0x7a, 0xb0, 0x3f,
+	0x81, 0x68, 0xd1, 0xa5, 0x95, 0xe4, 0x5b, 0x88, 0x3a, 0x18, 0xa3, 0x1e,
+	0x4d, 0xd4, 0x35, 0x6f, 0xe3, 0x98, 0xfc, 0x2b, 0x7b, 0x30, 0x9c, 0x68,
+	0xfc, 0x2b, 0xc6, 0x11, 0x7f, 0x99, 0xcd, 0x75, 0xe2, 0x7f, 0xbd, 0x97,
+	0x38, 0xb0, 0x29, 0xbf, 0xe6, 0xd5, 0x96, 0xf8, 0x35, 0xe5, 0xb7, 0x85,
+	0x64, 0xbd, 0x4f, 0x2a, 0x37, 0xc1, 0x3c, 0xff, 0x04, 0xd6, 0xf5, 0x2b,
+	0x78, 0xd2, 0x38, 0x81, 0xb5, 0x43, 0x22, 0xcf, 0x09, 0xac, 0xe9, 0x7f,
+	0x09, 0x7b, 0xfa, 0x67, 0xa0, 0xc9, 0xd6, 0x4d, 0x07, 0x36, 0xec, 0x3c,
+	0x88, 0xed, 0x29, 0x0b, 0xdb, 0x42, 0x1e, 0xac, 0x7f, 0x58, 0xc1, 0xf2,
+	0xc0, 0x61, 0x6c, 0xd9, 0x69, 0xe1, 0xe2, 0x50, 0x27, 0x9a, 0xcd, 0x32,
+	0x14, 0x57, 0xcd, 0x6b, 0x57, 0x59, 0xae, 0x6d, 0xb8, 0x23, 0xbf, 0x2f,
+	0x79, 0x3f, 0xb1, 0x40, 0x85, 0xcf, 0x90, 0x3d, 0xc7, 0x51, 0xe5, 0xa6,
+	0x4c, 0x93, 0xd2, 0x9a, 0x7f, 0x66, 0x79, 0x7d, 0xa6, 0xa8, 0x02, 0xa5,
+	0x71, 0xec, 0x09, 0x9d, 0xc0, 0xd0, 0xd0, 0x07, 0xe5, 0x39, 0x7f, 0x99,
+	0x20, 0x77, 0x90, 0x9c, 0xc3, 0xa4, 0x4d, 0x7d, 0xd2, 0xfb, 0x40, 0x62,
+	0x77, 0x93, 0xf8, 0xe9, 0xe0, 0x49, 0x9c, 0x1c, 0xfc, 0x37, 0x2c, 0xd1,
+	0x24, 0x7f, 0xb4, 0x3a, 0x9d, 0x11, 0xcb, 0xda, 0xd5, 0x10, 0xb7, 0x6a,
+	0x8c, 0x5f, 0xb0, 0xed, 0x0a, 0x4c, 0x8f, 0xbc, 0x88, 0x6d, 0x1a, 0xdb,
+	0x4a, 0xed, 0xc7, 0x0e, 0xc6, 0x75, 0x5f, 0xe4, 0x66, 0xf8, 0x52, 0x59,
+	0xb3, 0x1a, 0xd1, 0x1d, 0xd5, 0xd0, 0x37, 0x56, 0x39, 0x8c, 0x8e, 0x7f,
+	0x55, 0xea, 0x71, 0x7d, 0xe6, 0x24, 0x7e, 0x3e, 0x68, 0xef, 0xa5, 0x6a,
+	0xfd, 0xae, 0x62, 0x75, 0x6e, 0x0b, 0xe9, 0xcd, 0xff, 0x43, 0x89, 0xc6,
+	0x4b, 0x69, 0x53, 0x25, 0xcc, 0x09, 0x6e, 0x18, 0x94, 0x1c, 0xb1, 0x15,
+	0xee, 0x3e, 0x3d, 0xbb, 0x94, 0x3c, 0xfb, 0xee, 0x05, 0xf1, 0x99, 0xd3,
+	0x68, 0x97, 0x0e, 0x45, 0x0f, 0x1a, 0x6a, 0x27, 0x8e, 0x98, 0xfa, 0xc4,
+	0xef, 0x1c, 0xc6, 0xd0, 0x77, 0x50, 0x8f, 0x55, 0x19, 0x7d, 0xe8, 0x32,
+	0xe6, 0x61, 0x5b, 0x92, 0x26, 0x52, 0x49, 0xbd, 0xb5, 0xc3, 0xd1, 0x8b,
+	0x3b, 0x02, 0xb5, 0x1b, 0xdf, 0x25, 0x97, 0xf3, 0x10, 0x53, 0x92, 0xe3,
+	0x23, 0xcc, 0x5f, 0x7b, 0xb1, 0xe1, 0xe1, 0x08, 0xd6, 0xef, 0x32, 0xd1,
+	0x93, 0x1c, 0xa1, 0x6c, 0x3f, 0x2c, 0x97, 0xbd, 0x34, 0x2d, 0xa1, 0xf8,
+	0xb5, 0x2a, 0x02, 0x51, 0xf6, 0xd9, 0xa8, 0x46, 0x02, 0x7e, 0x55, 0x61,
+	0xf4, 0x1f, 0x77, 0xa2, 0x9b, 0x65, 0xfa, 0x52, 0xb4, 0xb9, 0xa4, 0x9b,
+	0xf1, 0x72, 0x16, 0x86, 0xc7, 0x7c, 0xd8, 0x37, 0xe6, 0xc1, 0xd0, 0x98,
+	0xc6, 0xa3, 0x14, 0x0f, 0x0d, 0xc8, 0x9e, 0x14, 0x2f, 0x9e, 0xd8, 0xeb,
+	0xc6, 0xa6, 0x07, 0x3c, 0x98, 0x13, 0x99, 0x8e, 0xbd, 0x7b, 0x4b, 0xb1,
+	0x9b, 0xd7, 0xab, 0x16, 0xfa, 0xf1, 0x38, 0xaf, 0xf7, 0x3f, 0xe0, 0xe2,
+	0x3c, 0x5c, 0x8c, 0x03, 0x34, 0xec, 0xa1, 0xb1, 0x32, 0xa4, 0x06, 0x68,
+	0xf2, 0xe4, 0xac, 0x6f, 0x31, 0xc3, 0x18, 0xdd, 0xcb, 0xd8, 0xf8, 0xb0,
+	0x89, 0x04, 0xfb, 0xd9, 0x4e, 0x5d, 0xf5, 0x10, 0xd7, 0x36, 0x8c, 0x09,
+	0xc6, 0xaf, 0xc2, 0x35, 0x7d, 0x7a, 0x73, 0x93, 0x62, 0x44, 0x17, 0xd9,
+	0xfb, 0xb4, 0xe4, 0xbd, 0xad, 0x55, 0x68, 0x4c, 0xe8, 0x66, 0x13, 0x3a,
+	0x71, 0x8c, 0xe3, 0xfe, 0x7f, 0xe8, 0xb7, 0x8b, 0x1d, 0x7a, 0xef, 0xd5,
+	0xea, 0x41, 0xec, 0xc8, 0x1c, 0x22, 0x57, 0x07, 0xc2, 0x7b, 0x0e, 0x92,
+	0xbf, 0x1d, 0x21, 0xfe, 0xbc, 0x6e, 0xf9, 0x0c, 0x15, 0xd7, 0xdf, 0x6f,
+	0x84, 0xdf, 0x53, 0x02, 0x1b, 0x7f, 0x45, 0x1d, 0x7c, 0x7e, 0xaf, 0x8a,
+	0xeb, 0x76, 0x2c, 0x46, 0x3a, 0x14, 0xc5, 0xf6, 0x45, 0x2a, 0xae, 0x7d,
+	0xf8, 0x20, 0x71, 0x7f, 0xc2, 0xe6, 0xc9, 0xd9, 0xf4, 0x7d, 0x08, 0xf6,
+	0xc9, 0x9a, 0xbc, 0x9b, 0xf1, 0xbb, 0x1c, 0xc7, 0xfb, 0x3b, 0xe9, 0xb7,
+	0xe5, 0x38, 0x3a, 0x74, 0x90, 0xf6, 0x58, 0x8e, 0x23, 0xfd, 0xc6, 0xc4,
+	0x4f, 0x1d, 0xe5, 0x78, 0x82, 0xe7, 0x3b, 0x78, 0xbe, 0x70, 0xc0, 0xe8,
+	0xef, 0x50, 0xcb, 0xb1, 0x60, 0x4f, 0x03, 0xfa, 0x93, 0x62, 0x9b, 0x1a,
+	0x36, 0x8e, 0xd5, 0xe7, 0x75, 0x2f, 0x3a, 0xf7, 0xe2, 0x4e, 0xea, 0xea,
+	0x8e, 0x1d, 0x9d, 0xec, 0xcf, 0x47, 0x9d, 0x1f, 0xc4, 0x43, 0xcc, 0xeb,
+	0xb6, 0x25, 0x7d, 0x38, 0x9d, 0x32, 0xfc, 0x5f, 0x52, 0x0c, 0xb3, 0x44,
+	0x09, 0x68, 0xc7, 0xe1, 0xc3, 0xc9, 0x4c, 0x29, 0xba, 0x07, 0x66, 0xe1,
+	0xa7, 0xb4, 0xcf, 0x07, 0x1f, 0x90, 0xfe, 0x26, 0x18, 0x1f, 0x66, 0xe3,
+	0x89, 0x11, 0x93, 0x6d, 0xcb, 0x3c, 0x49, 0xcc, 0xe9, 0x81, 0x2b, 0x25,
+	0xbe, 0x11, 0xdd, 0x41, 0xb3, 0x20, 0x26, 0x1e, 0x46, 0xa6, 0x5f, 0xef,
+	0xbd, 0x41, 0x15, 0x5e, 0xad, 0x52, 0x97, 0x0e, 0x4c, 0x6a, 0x7a, 0xbc,
+	0x4a, 0x8d, 0xf7, 0x33, 0x7f, 0x8d, 0x57, 0xab, 0x87, 0xf1, 0x44, 0xbf,
+	0x13, 0xf3, 0x16, 0xaa, 0xbc, 0x1e, 0x3f, 0xc3, 0xd8, 0x16, 0x9f, 0xa3,
+	0x9a, 0xd8, 0x6d, 0xcb, 0x8a, 0x78, 0x11, 0xb9, 0x7d, 0xe5, 0xc2, 0x5a,
+	0xc6, 0x2f, 0x87, 0xd8, 0x5e, 0xac, 0x5c, 0x75, 0x52, 0xef, 0x27, 0x31,
+	0x42, 0xbb, 0x7e, 0x94, 0xc7, 0x81, 0x41, 0xab, 0x73, 0x39, 0x39, 0xf7,
+	0xc5, 0x01, 0xab, 0xf3, 0x06, 0xd3, 0xf0, 0x15, 0xa9, 0x81, 0xe8, 0xdd,
+	0x38, 0x89, 0xfd, 0x23, 0x52, 0x06, 0x6e, 0x6f, 0x84, 0x79, 0x75, 0xd2,
+	0xea, 0xdc, 0x61, 0x5e, 0x8c, 0x06, 0x3b, 0x37, 0xfe, 0x55, 0x79, 0x0e,
+	0x33, 0xc5, 0x8f, 0x64, 0x0d, 0x64, 0x12, 0xbf, 0x62, 0x3b, 0xef, 0x0d,
+	0x56, 0x62, 0x5a, 0xb5, 0xf8, 0xc1, 0x09, 0xbc, 0xdd, 0xff, 0x22, 0x4e,
+	0xf7, 0x5b, 0x58, 0x10, 0xb2, 0xe0, 0x0c, 0xd5, 0x99, 0x4d, 0xea, 0x65,
+	0xc4, 0x08, 0x05, 0xd7, 0xcc, 0x7d, 0x09, 0xef, 0xd0, 0xff, 0xaf, 0x9d,
+	0x6b, 0xd9, 0xb2, 0xf4, 0x61, 0xa1, 0xb5, 0xbd, 0x46, 0xfc, 0xc6, 0xb4,
+	0xf7, 0xf5, 0x7c, 0x72, 0x1e, 0x5c, 0xd8, 0xb7, 0x26, 0xb9, 0xf0, 0x49,
+	0x0c, 0x0f, 0x1a, 0xd1, 0x75, 0x05, 0x39, 0xfb, 0x4f, 0x52, 0x07, 0x16,
+	0x76, 0x98, 0x47, 0x1f, 0xae, 0xc2, 0xbc, 0x33, 0xcc, 0x1a, 0xaf, 0x98,
+	0x43, 0xdb, 0x59, 0xb0, 0x30, 0x60, 0x2e, 0x53, 0xdf, 0xa4, 0x9f, 0x9e,
+	0xc4, 0xbe, 0xa1, 0x02, 0x5e, 0xfb, 0xd0, 0x44, 0x3f, 0xcf, 0xed, 0x65,
+	0xf7, 0xa2, 0x31, 0x75, 0xc8, 0x5e, 0x7f, 0x38, 0x40, 0x7c, 0xcc, 0x3d,
+	0xd3, 0xd4, 0x30, 0x92, 0x69, 0x22, 0x36, 0x44, 0xf1, 0xcf, 0x99, 0x08,
+	0xf1, 0x21, 0x4c, 0x7c, 0x68, 0x20, 0x3e, 0x98, 0xc4, 0x87, 0x7a, 0xe2,
+	0x43, 0xd0, 0x7e, 0xd6, 0x2f, 0x6b, 0xe6, 0x43, 0xa3, 0x2f, 0xa2, 0x68,
+	0xe0, 0x04, 0x5c, 0xf4, 0x81, 0xe3, 0xa6, 0x45, 0x7e, 0x52, 0xa7, 0xad,
+	0xc1, 0xc5, 0x4a, 0x54, 0xf3, 0x62, 0x28, 0x73, 0x02, 0x25, 0x03, 0x1a,
+	0xc7, 0x22, 0xfb, 0x33, 0x6a, 0xc3, 0xbd, 0xc4, 0xea, 0x5f, 0x1b, 0x75,
+	0xbd, 0x5e, 0xd4, 0xed, 0xae, 0x81, 0xd1, 0xbf, 0x50, 0x9d, 0xab, 0x44,
+	0xbf, 0xe0, 0xe5, 0x38, 0xab, 0x31, 0xfb, 0x01, 0x0d, 0x73, 0x78, 0xfc,
+	0x53, 0xaa, 0x76, 0xe2, 0x75, 0x07, 0xbc, 0x33, 0x48, 0x77, 0x66, 0x92,
+	0x09, 0x90, 0xd5, 0x7a, 0x7d, 0xb8, 0xe4, 0xc0, 0x49, 0x55, 0x41, 0xf6,
+	0x0b, 0x12, 0xf3, 0xea, 0x82, 0x3d, 0xaa, 0x2a, 0x6b, 0x48, 0xc4, 0x70,
+	0x1e, 0x2a, 0x22, 0x64, 0x11, 0xb3, 0x98, 0x5f, 0x58, 0x6b, 0xcc, 0x12,
+	0x6c, 0xae, 0x57, 0x65, 0x6f, 0xc8, 0x21, 0x89, 0x51, 0x33, 0x18, 0x23,
+	0x4a, 0x93, 0xf1, 0xdb, 0x66, 0xc0, 0x83, 0x92, 0xa4, 0x65, 0x3d, 0x16,
+	0xd2, 0xe0, 0x89, 0x04, 0xa2, 0x1b, 0x98, 0x46, 0x7e, 0x61, 0x5e, 0x18,
+	0xd7, 0x64, 0x0e, 0x60, 0x80, 0xe3, 0x5b, 0x9e, 0x29, 0xbc, 0xe3, 0xf9,
+	0xc9, 0x7f, 0xe7, 0xde, 0x15, 0xbd, 0x64, 0xf7, 0x0c, 0x18, 0xda, 0x5d,
+	0x6a, 0xbc, 0x92, 0x1c, 0xfc, 0x00, 0xe3, 0x9e, 0x32, 0x79, 0xa3, 0x82,
+	0xd6, 0x81, 0x38, 0xa6, 0x85, 0x7e, 0xa0, 0xc4, 0xaa, 0x75, 0xbf, 0x5f,
+	0xa9, 0xc6, 0x8d, 0x0f, 0x50, 0xd7, 0x0b, 0x26, 0x68, 0x2b, 0x3e, 0x7c,
+	0x67, 0x54, 0x74, 0x5b, 0x3b, 0xb4, 0x83, 0xe3, 0x98, 0x98, 0x7b, 0x40,
+	0x70, 0xf2, 0xa0, 0x1b, 0x8e, 0x83, 0xd3, 0x99, 0x9b, 0xd6, 0xcf, 0xbd,
+	0xa4, 0xe3, 0xdf, 0x54, 0xd1, 0x8b, 0xf0, 0x6b, 0xbd, 0x3f, 0xae, 0x18,
+	0xda, 0x2f, 0x95, 0x03, 0xe4, 0x6c, 0x5e, 0x3c, 0x96, 0x39, 0x4c, 0x5d,
+	0xee, 0xcf, 0xe7, 0x4b, 0xab, 0x90, 0xe8, 0x93, 0x7d, 0x81, 0x27, 0x30,
+	0x7b, 0x40, 0x6f, 0xd9, 0xaa, 0x18, 0xc1, 0x6b, 0x95, 0x13, 0x98, 0x39,
+	0x10, 0xe4, 0x5c, 0x6a, 0x58, 0x96, 0x2c, 0xe0, 0xa7, 0x60, 0xf0, 0x2a,
+	0x62, 0xb0, 0xb5, 0xf8, 0xa7, 0x66, 0x9c, 0x39, 0x8e, 0x6e, 0x3a, 0x15,
+	0xbd, 0x75, 0xae, 0x22, 0xfb, 0x80, 0x8c, 0x33, 0x6d, 0xac, 0xe3, 0x19,
+	0xa8, 0xc7, 0x57, 0x39, 0xe6, 0x66, 0xce, 0xdb, 0x8b, 0x0b, 0x2d, 0x2c,
+	0x5a, 0xa8, 0xef, 0x2e, 0x71, 0x44, 0xef, 0xaa, 0x42, 0xb6, 0xa3, 0x86,
+	0x76, 0x73, 0xc7, 0x02, 0x3d, 0xfc, 0x03, 0xe2, 0x2e, 0x71, 0x1a, 0xdd,
+	0x8c, 0x3b, 0x6b, 0x18, 0x8b, 0x4a, 0x23, 0x7a, 0x2f, 0x73, 0xd4, 0xf7,
+	0x6e, 0x75, 0x44, 0x43, 0xf2, 0x1e, 0xd1, 0xdf, 0x63, 0x31, 0xdc, 0xa1,
+	0x0a, 0xe2, 0xa0, 0x9e, 0x7d, 0x11, 0xfa, 0xee, 0xaf, 0x92, 0x93, 0xfe,
+	0x98, 0xfc, 0xae, 0xe6, 0xd2, 0x43, 0xc4, 0xa8, 0x11, 0x3c, 0x98, 0x39,
+	0x88, 0xdd, 0x99, 0x34, 0x76, 0x66, 0xb6, 0x29, 0x43, 0xf6, 0xb3, 0x45,
+	0x45, 0xde, 0x99, 0x8b, 0x56, 0x28, 0x5f, 0x46, 0x79, 0xe8, 0x5b, 0xd6,
+	0x50, 0x95, 0x8a, 0xca, 0x50, 0x10, 0xd7, 0x24, 0xe3, 0x70, 0x44, 0xde,
+	0xb5, 0xe4, 0x7d, 0xed, 0xf5, 0xe3, 0x06, 0xae, 0x4e, 0x96, 0x22, 0xb6,
+	0xc7, 0xb2, 0x7a, 0x1b, 0x9c, 0x58, 0x3b, 0x5e, 0x8f, 0x65, 0x03, 0x0f,
+	0x59, 0x73, 0x18, 0x73, 0x3e, 0xbc, 0xdc, 0x83, 0x5b, 0xf7, 0x78, 0xd0,
+	0x96, 0x8c, 0xc2, 0x17, 0x29, 0xe3, 0xef, 0x80, 0xb9, 0x04, 0xc6, 0xc4,
+	0x04, 0x8c, 0xde, 0xab, 0x1c, 0x81, 0xfd, 0x61, 0xd5, 0x83, 0xbf, 0x21,
+	0x8e, 0x2f, 0x27, 0xee, 0xc4, 0xc6, 0x2d, 0x54, 0x46, 0xbc, 0xb8, 0x8d,
+	0xf5, 0xaf, 0xe3, 0xdc, 0xbf, 0xb3, 0x68, 0x3f, 0xb1, 0x40, 0xf6, 0x42,
+	0x6a, 0xd8, 0x30, 0xee, 0xa6, 0xae, 0xdc, 0x88, 0xed, 0xab, 0xc6, 0xd5,
+	0x0f, 0xf8, 0x71, 0xeb, 0xb8, 0x07, 0x8d, 0x49, 0x6b, 0xf1, 0x01, 0x33,
+	0xbe, 0x52, 0x83, 0x81, 0xb6, 0x71, 0x2f, 0xbe, 0x92, 0xd4, 0x7d, 0xd7,
+	0x32, 0xe7, 0x1f, 0x31, 0x83, 0xf8, 0x5f, 0xe3, 0x3e, 0xdc, 0x94, 0x3c,
+	0x2a, 0x79, 0xe4, 0x12, 0x27, 0x63, 0xcf, 0xbd, 0xe3, 0xb3, 0xb0, 0x32,
+	0xa9, 0x9f, 0x99, 0x20, 0xb7, 0xeb, 0xdc, 0x67, 0xe2, 0xae, 0x71, 0x15,
+	0xad, 0x6c, 0xe7, 0xc6, 0xe4, 0x6c, 0x74, 0xec, 0x6b, 0xa0, 0x0c, 0x0b,
+	0xb1, 0x7c, 0xc0, 0x09, 0x93, 0x2c, 0x1e, 0x5f, 0x04, 0x5a, 0x06, 0x26,
+	0x98, 0xc7, 0xdd, 0x87, 0xed, 0x7d, 0x26, 0x6e, 0x1f, 0x97, 0xf3, 0x83,
+	0xf6, 0x3b, 0xae, 0xef, 0x3d, 0xbc, 0x10, 0x9f, 0x1f, 0x50, 0x89, 0x03,
+	0xc5, 0x18, 0x5a, 0xa9, 0xe0, 0x2b, 0xbc, 0xbe, 0x35, 0x25, 0x7b, 0x90,
+	0x81, 0xd0, 0x8e, 0xc0, 0xfe, 0x2a, 0x72, 0x86, 0x45, 0x0f, 0xe7, 0xae,
+	0x3f, 0x48, 0x9c, 0x2f, 0x21, 0xce, 0x97, 0x91, 0xc3, 0x5e, 0x35, 0x7c,
+	0x10, 0xf7, 0x13, 0x97, 0x0f, 0x0d, 0x74, 0x32, 0xee, 0x94, 0xe3, 0x71,
+	0xc6, 0x81, 0x24, 0xcf, 0x4f, 0xec, 0x30, 0x3a, 0x4a, 0x88, 0xd3, 0x3f,
+	0x20, 0xfe, 0xf6, 0x12, 0x33, 0xee, 0x48, 0x32, 0xdc, 0xef, 0x60, 0x0e,
+	0x70, 0x69, 0x74, 0xbe, 0x87, 0x39, 0xd6, 0xb5, 0x4a, 0xc0, 0xf7, 0x26,
+	0xca, 0xe1, 0x78, 0xb8, 0x1a, 0x8d, 0x0f, 0x48, 0x19, 0xc1, 0x2f, 0x15,
+	0xea, 0x5e, 0x27, 0x75, 0x7e, 0x18, 0x56, 0xbf, 0x83, 0xe3, 0xad, 0x35,
+	0xc9, 0xc0, 0xf1, 0x9a, 0xa9, 0x6b, 0xff, 0x4c, 0xac, 0x7d, 0x9f, 0x98,
+	0xea, 0x9f, 0xd1, 0x80, 0x26, 0xc3, 0xe4, 0x71, 0x18, 0x27, 0xfb, 0x0d,
+	0x53, 0xf6, 0xe4, 0xbd, 0x4e, 0x9e, 0x37, 0x39, 0x83, 0x31, 0xd3, 0x10,
+	0x3f, 0x1c, 0xe1, 0x78, 0x54, 0xc9, 0x4b, 0xe0, 0x18, 0x03, 0xde, 0x7e,
+	0x78, 0x31, 0xc7, 0x25, 0xb1, 0x54, 0xe2, 0xdd, 0x08, 0x65, 0x5d, 0x8c,
+	0x15, 0xd4, 0x47, 0x53, 0x52, 0x45, 0x7a, 0x5f, 0x04, 0xb7, 0xef, 0xca,
+	0xc5, 0xe1, 0x8d, 0xa1, 0xf8, 0x0d, 0x8c, 0xc3, 0xe1, 0x52, 0xc6, 0x61,
+	0x57, 0x44, 0x64, 0x73, 0x62, 0x98, 0x71, 0x7b, 0x73, 0x2a, 0x8c, 0x66,
+	0xce, 0xe1, 0x44, 0x9a, 0xfd, 0x26, 0x67, 0xe1, 0x78, 0xda, 0xc3, 0x98,
+	0xa5, 0xf1, 0x20, 0xaa, 0x8d, 0x4c, 0xe7, 0xe1, 0xe7, 0x71, 0x31, 0x0f,
+	0xc3, 0xbe, 0xb6, 0x26, 0xa9, 0x20, 0xde, 0xa2, 0xd8, 0x7c, 0xfe, 0x78,
+	0x5a, 0xb0, 0x59, 0xd6, 0x32, 0xef, 0xae, 0x94, 0x3d, 0xa8, 0xfd, 0xa9,
+	0x97, 0x50, 0x49, 0x7c, 0xaa, 0xc8, 0xe3, 0xd0, 0xcf, 0x42, 0x82, 0xbb,
+	0xb5, 0xc4, 0x5d, 0xd9, 0x4f, 0x64, 0x59, 0xab, 0x02, 0x53, 0xf1, 0xe8,
+	0xff, 0xfb, 0x30, 0x6a, 0xef, 0xab, 0x15, 0x4c, 0x22, 0xfe, 0xa5, 0x88,
+	0x7f, 0x1c, 0x43, 0xd7, 0x95, 0xc4, 0x40, 0xca, 0xf4, 0x8f, 0x29, 0x62,
+	0x20, 0x71, 0xfa, 0x20, 0x71, 0xfa, 0xdb, 0xc4, 0xe9, 0x6f, 0x11, 0xa7,
+	0x1f, 0x27, 0x26, 0xe4, 0xd6, 0xf4, 0x9a, 0xe5, 0xb9, 0x0a, 0xe7, 0xe3,
+	0x1d, 0x7b, 0x6d, 0xb1, 0x86, 0xba, 0x9a, 0x3d, 0xa0, 0x60, 0x8e, 0xa1,
+	0xef, 0x17, 0xbb, 0xff, 0x31, 0xe7, 0xc9, 0x3f, 0x2d, 0xb7, 0xe7, 0xb7,
+	0x29, 0xd9, 0x03, 0x77, 0xb2, 0x4e, 0xeb, 0x85, 0xfd, 0x0d, 0x01, 0x53,
+	0xb8, 0x68, 0x51, 0x72, 0x0d, 0x1c, 0xc9, 0xba, 0xfd, 0xc7, 0xe4, 0xf9,
+	0xed, 0x74, 0xc9, 0xeb, 0xd7, 0xc8, 0x1e, 0xed, 0xfd, 0xb2, 0x37, 0x6c,
+	0x19, 0xef, 0xb9, 0x92, 0x75, 0xe6, 0x9b, 0xb0, 0xb1, 0xcd, 0x3f, 0x69,
+	0xdf, 0xab, 0x7d, 0xef, 0x7e, 0xea, 0x2b, 0xcb, 0x36, 0xd3, 0x29, 0xd9,
+	0x17, 0x3b, 0x0b, 0x8f, 0x66, 0xe4, 0x77, 0x5d, 0x6b, 0x42, 0xdd, 0x8f,
+	0x58, 0x8d, 0xf0, 0xf1, 0x30, 0xae, 0x4f, 0x7a, 0x68, 0x07, 0x71, 0x54,
+	0xd0, 0xb7, 0xbe, 0x36, 0xde, 0x40, 0x5f, 0x7b, 0xc8, 0xd2, 0x22, 0x81,
+	0xd6, 0x71, 0x72, 0x9e, 0xf5, 0xe3, 0x8b, 0xb1, 0x74, 0xc0, 0xb2, 0x3c,
+	0x97, 0x19, 0xe1, 0x0d, 0x8a, 0x1f, 0x2e, 0xfa, 0xa0, 0x83, 0x7e, 0xb5,
+	0x6e, 0x4f, 0x40, 0x7b, 0x93, 0x78, 0xda, 0xde, 0x70, 0x80, 0xf6, 0x61,
+	0x9c, 0x69, 0x26, 0x96, 0x3a, 0x23, 0x01, 0xe6, 0x89, 0x1e, 0xda, 0xbe,
+	0x17, 0x67, 0x12, 0xe2, 0x5f, 0x7a, 0xc7, 0x3f, 0x33, 0x37, 0xe9, 0xa0,
+	0x6f, 0xfc, 0x32, 0x31, 0x8b, 0x3e, 0xe0, 0xc6, 0xdb, 0x09, 0x83, 0xfe,
+	0xe6, 0xc1, 0x3b, 0x89, 0x7a, 0xf6, 0x15, 0x64, 0x19, 0x3f, 0xee, 0x1c,
+	0x0f, 0xd3, 0xcf, 0xae, 0xe4, 0x21, 0xef, 0x53, 0xd7, 0xc6, 0xbf, 0xa3,
+	0xd4, 0xf6, 0xcf, 0x56, 0xab, 0x10, 0xad, 0xd6, 0xf0, 0xf5, 0xf1, 0xcf,
+	0xe2, 0x3f, 0x18, 0xb7, 0xd7, 0x26, 0xc1, 0x39, 0x44, 0x88, 0x3c, 0x70,
+	0x62, 0x9f, 0x3c, 0x4b, 0x44, 0x5d, 0x74, 0xae, 0x43, 0x67, 0x6e, 0xab,
+	0x67, 0x4f, 0x3b, 0x9c, 0xec, 0x93, 0xac, 0x98, 0x65, 0x7f, 0xd9, 0x5f,
+	0x8a, 0xbb, 0xf6, 0x1c, 0xa0, 0x8f, 0x14, 0x61, 0xc1, 0xfd, 0x6e, 0x7c,
+	0x7d, 0xdf, 0x08, 0xb9, 0x83, 0x8a, 0x99, 0xcc, 0x95, 0x86, 0x48, 0x14,
+	0x66, 0x0e, 0x47, 0x70, 0xdb, 0xae, 0x11, 0x0c, 0xe4, 0x79, 0x5e, 0x28,
+	0x14, 0xff, 0x9f, 0x2a, 0x0e, 0x90, 0x47, 0x04, 0xda, 0x3f, 0x43, 0x1b,
+	0xab, 0x88, 0x04, 0xe2, 0x32, 0xee, 0x16, 0xda, 0x58, 0x0f, 0xe7, 0x33,
+	0xcd, 0x71, 0x24, 0x68, 0x63, 0x8f, 0x51, 0xfe, 0xed, 0xb4, 0xb1, 0x38,
+	0x6d, 0x2c, 0x4e, 0x7b, 0x8a, 0xd3, 0xc6, 0xe4, 0x9d, 0xfd, 0x38, 0x6d,
+	0x2c, 0x4e, 0x1b, 0x8b, 0xa7, 0x17, 0x63, 0x94, 0x4c, 0x63, 0xcb, 0x48,
+	0x03, 0x71, 0x4c, 0xb1, 0xa3, 0x52, 0xf6, 0x86, 0xcf, 0x92, 0xb3, 0x5f,
+	0xc5, 0x43, 0x41, 0x33, 0x7d, 0xb2, 0x77, 0x68, 0x84, 0x9c, 0xc7, 0x8d,
+	0xdf, 0x64, 0x84, 0xe3, 0x37, 0x30, 0x8f, 0x3d, 0x4c, 0x9e, 0xaf, 0xe2,
+	0x49, 0x53, 0xf2, 0x60, 0x93, 0xe7, 0x8c, 0x35, 0x29, 0xe1, 0x6b, 0x87,
+	0x71, 0x47, 0x3f, 0x70, 0x2d, 0x79, 0x61, 0x35, 0x79, 0xc9, 0xde, 0x05,
+	0xfc, 0xfd, 0xf0, 0x01, 0xda, 0xbc, 0xf8, 0x63, 0x6e, 0xaf, 0xeb, 0xf1,
+	0xfe, 0x5a, 0xdf, 0xd5, 0xf4, 0xc1, 0x7b, 0x59, 0xd7, 0xf9, 0xb0, 0xd4,
+	0x39, 0xc0, 0xb6, 0xf5, 0xf0, 0x6f, 0x38, 0xff, 0xad, 0xf7, 0x57, 0xe3,
+	0xed, 0x5d, 0x7a, 0xf8, 0x7d, 0x62, 0x5e, 0xb5, 0xc3, 0x5a, 0xfc, 0x99,
+	0x50, 0x60, 0xe3, 0x67, 0xd4, 0x1c, 0xdf, 0x6b, 0xd9, 0xe1, 0xc4, 0xfe,
+	0xd0, 0x62, 0x78, 0x16, 0x14, 0x38, 0x1f, 0x6d, 0xa9, 0x5a, 0x38, 0x96,
+	0x1e, 0x3e, 0x4d, 0xae, 0x92, 0x64, 0xfb, 0xa3, 0xe9, 0x23, 0xc4, 0x90,
+	0xfb, 0xf0, 0x02, 0xf3, 0xf3, 0x91, 0x4f, 0xbf, 0x4e, 0xee, 0xe8, 0xc6,
+	0x18, 0x39, 0xe0, 0x81, 0xfe, 0xe8, 0xe7, 0x9c, 0xc4, 0x7d, 0xcf, 0x82,
+	0x72, 0xa4, 0x87, 0x84, 0x2b, 0x96, 0xe3, 0xd9, 0x7e, 0x43, 0xbb, 0x56,
+	0xc9, 0xf1, 0xc2, 0x2d, 0x3c, 0x7f, 0xb3, 0xdf, 0x38, 0x33, 0x8c, 0xc0,
+	0xc4, 0x69, 0x72, 0xc3, 0xf7, 0x87, 0x24, 0x86, 0x1d, 0xa4, 0x8f, 0xfb,
+	0x11, 0x4e, 0x6a, 0x38, 0x34, 0x66, 0x60, 0x7e, 0xd2, 0x8b, 0x47, 0xc6,
+	0x82, 0xf8, 0x0c, 0x7d, 0x37, 0x43, 0x7e, 0xf8, 0xe9, 0xa4, 0xf8, 0xe2,
+	0x2c, 0x8c, 0x8f, 0xcd, 0xb2, 0xf7, 0x54, 0x7a, 0x8c, 0x5f, 0xc0, 0x53,
+	0x2d, 0x3e, 0x49, 0x6e, 0x9d, 0xd2, 0x7b, 0x63, 0x1c, 0x4f, 0xcc, 0xab,
+	0xef, 0x8f, 0x41, 0x1f, 0x02, 0xae, 0xf8, 0x70, 0xe8, 0x8b, 0x12, 0x1f,
+	0xc5, 0x1f, 0x35, 0x8c, 0x93, 0xef, 0x14, 0x13, 0x53, 0x4b, 0x23, 0xb5,
+	0xef, 0xbd, 0xac, 0xe8, 0xd9, 0xa7, 0x55, 0xcb, 0x7a, 0x69, 0xa1, 0x06,
+	0xdf, 0x3e, 0x8d, 0xdc, 0xc3, 0x64, 0xec, 0x16, 0x3f, 0xd5, 0x30, 0xe3,
+	0x81, 0x6a, 0x4c, 0x7b, 0x20, 0x89, 0xbf, 0xad, 0x8e, 0x7f, 0x6e, 0x3a,
+	0xe3, 0xfc, 0x74, 0xe2, 0x7a, 0x65, 0xf2, 0xd8, 0x0c, 0x37, 0xf9, 0xf2,
+	0x84, 0x5a, 0xd7, 0xba, 0x1f, 0xfa, 0xfe, 0x93, 0x8a, 0xee, 0x7b, 0x8c,
+	0xb1, 0xc1, 0x45, 0x1b, 0x75, 0x8c, 0x6b, 0xf4, 0xdd, 0xba, 0x43, 0xd3,
+	0x60, 0xc4, 0x2f, 0x57, 0x5d, 0x16, 0x6c, 0x79, 0xae, 0xa8, 0xcc, 0xe5,
+	0x45, 0x82, 0x3b, 0x12, 0x17, 0x1c, 0xb2, 0xff, 0x13, 0xed, 0xf4, 0x97,
+	0x15, 0x76, 0x2c, 0x3a, 0x60, 0xef, 0x8f, 0xdb, 0x30, 0x1e, 0xa7, 0x8f,
+	0x2c, 0x46, 0xd9, 0x80, 0x07, 0x5f, 0xb3, 0xe3, 0xd0, 0x43, 0x56, 0x15,
+	0xfd, 0xe5, 0xf6, 0x3d, 0x81, 0xf6, 0xab, 0xe9, 0x2f, 0xb5, 0x97, 0x49,
+	0x0c, 0x63, 0xdc, 0x4e, 0x19, 0xe6, 0x30, 0xb1, 0xe5, 0xa1, 0x06, 0x63,
+	0xe2, 0x75, 0xe4, 0x7c, 0x66, 0x6b, 0x5f, 0x35, 0xfe, 0xe1, 0xfe, 0xfd,
+	0xf6, 0x5a, 0xc8, 0x6d, 0x3c, 0x4f, 0xf6, 0xf9, 0x6c, 0xff, 0x88, 0xf1,
+	0xf7, 0x9d, 0x8c, 0x79, 0x31, 0xfa, 0xd1, 0x96, 0x3e, 0x6b, 0xf1, 0xf7,
+	0x17, 0xc6, 0x57, 0x56, 0x20, 0xc8, 0x98, 0xe4, 0x46, 0x6f, 0x9f, 0xde,
+	0xdf, 0xca, 0x18, 0x74, 0x62, 0xa1, 0x49, 0x59, 0x3c, 0xd8, 0xd1, 0x27,
+	0x98, 0x7a, 0xf4, 0xa6, 0x6a, 0xc4, 0xff, 0xa7, 0xc6, 0xf1, 0x7d, 0xcd,
+	0x7e, 0xf6, 0x37, 0x0b, 0x6b, 0xf7, 0x5d, 0x46, 0x99, 0xeb, 0xe9, 0x83,
+	0xcc, 0xab, 0x99, 0xef, 0xac, 0xde, 0x25, 0x7e, 0x81, 0x46, 0xc9, 0xd3,
+	0x3a, 0xcd, 0x80, 0xf9, 0x06, 0x7d, 0xa8, 0x88, 0x5c, 0xe7, 0x41, 0x62,
+	0x59, 0x31, 0x21, 0xb3, 0xcc, 0x08, 0x63, 0x21, 0x6d, 0x54, 0xde, 0xe1,
+	0x98, 0x46, 0x5e, 0x37, 0x9f, 0xf3, 0x51, 0x92, 0xf1, 0x00, 0xe4, 0x10,
+	0x20, 0x3e, 0x61, 0x94, 0x20, 0x38, 0xea, 0xe7, 0x71, 0x31, 0x0f, 0x2a,
+	0x22, 0xa3, 0xa2, 0x66, 0x94, 0x75, 0x87, 0x47, 0x6c, 0x5b, 0xfc, 0x07,
+	0xce, 0x7b, 0x82, 0xb6, 0x7e, 0x23, 0xb1, 0x7e, 0x62, 0x27, 0xd0, 0xfb,
+	0x70, 0xce, 0xb6, 0x53, 0x6c, 0xbf, 0x85, 0x98, 0xf7, 0x1e, 0x6d, 0xb6,
+	0x87, 0xf3, 0xbd, 0x63, 0xd0, 0x08, 0xd6, 0xa9, 0x01, 0x6d, 0x9c, 0xf3,
+	0xdc, 0x35, 0xa2, 0xa2, 0xaf, 0x7f, 0x31, 0x86, 0x99, 0x07, 0x75, 0x0f,
+	0x89, 0x8f, 0x48, 0x99, 0xc3, 0xe8, 0xa4, 0x8f, 0xfc, 0x6a, 0xa1, 0x82,
+	0xd8, 0x17, 0xe4, 0x1d, 0x51, 0x27, 0xf3, 0xfd, 0xfb, 0xb0, 0x36, 0x71,
+	0xc4, 0x2a, 0x37, 0xf4, 0xde, 0x21, 0x95, 0x79, 0x16, 0x6d, 0xb3, 0x8b,
+	0xf9, 0xc9, 0x12, 0xe6, 0x27, 0xdd, 0x79, 0xbb, 0x3c, 0x4e, 0x3b, 0xec,
+	0x63, 0x1c, 0x7b, 0x7d, 0x28, 0x17, 0xf7, 0x7e, 0xbc, 0xc3, 0x8f, 0xf9,
+	0x97, 0x97, 0xe3, 0x99, 0x87, 0x73, 0xb2, 0xed, 0xa4, 0x4d, 0x3e, 0x4d,
+	0x3d, 0xdf, 0x4a, 0xbd, 0xbe, 0x92, 0x12, 0x8c, 0x0a, 0xe2, 0x59, 0xf2,
+	0xe8, 0xf5, 0xe4, 0x02, 0x2f, 0xa5, 0x72, 0x36, 0xf9, 0xf5, 0xf1, 0x2b,
+	0xab, 0x72, 0xf1, 0xc1, 0x0b, 0xf5, 0x01, 0x79, 0x27, 0xcf, 0xb2, 0x96,
+	0x98, 0xd9, 0x76, 0xf2, 0x1a, 0xb6, 0x1d, 0x21, 0x37, 0x72, 0x62, 0x66,
+	0x32, 0x82, 0xa5, 0xa9, 0xda, 0xe6, 0xb9, 0xb2, 0x89, 0x63, 0x66, 0x8e,
+	0x03, 0xba, 0x92, 0xf2, 0xcd, 0x0f, 0x0d, 0x65, 0xcc, 0x9d, 0xfe, 0x26,
+	0xff, 0x9d, 0x91, 0x1b, 0xff, 0x0c, 0xee, 0xb8, 0x82, 0x32, 0xa5, 0xc8,
+	0x1d, 0x27, 0xf3, 0xdf, 0x19, 0xb9, 0xc1, 0xfe, 0xce, 0x88, 0x1b, 0xd3,
+	0xc6, 0x9d, 0xce, 0x2f, 0xa5, 0x3c, 0x98, 0x31, 0x7e, 0x96, 0x83, 0xba,
+	0x8b, 0x22, 0x4d, 0x78, 0x2a, 0xa1, 0x60, 0xba, 0xf1, 0xbf, 0xf1, 0xb2,
+	0xbd, 0x26, 0x50, 0x8d, 0x99, 0x0f, 0xc8, 0x7a, 0x42, 0x54, 0xde, 0x89,
+	0x69, 0x7e, 0x82, 0xe7, 0x25, 0xc4, 0xd3, 0x8a, 0x07, 0x14, 0x3c, 0x1d,
+	0xf0, 0xa2, 0x98, 0xbf, 0x7d, 0xe4, 0x9a, 0xce, 0x85, 0xcb, 0xad, 0xcd,
+	0xab, 0xc4, 0xbe, 0x39, 0x87, 0xfb, 0xa6, 0x55, 0x0a, 0x06, 0xee, 0x35,
+	0x65, 0xdd, 0xd2, 0x40, 0x4f, 0xa2, 0x9a, 0xfc, 0xba, 0xb6, 0xbd, 0x09,
+	0xb5, 0xe6, 0x2f, 0x1c, 0xd5, 0x28, 0xda, 0x77, 0x63, 0x95, 0xac, 0xd9,
+	0x7f, 0x9b, 0x73, 0xd6, 0x4d, 0xec, 0xea, 0x4a, 0xe5, 0xe2, 0x67, 0x53,
+	0xfa, 0x17, 0x9a, 0xe8, 0xa5, 0x9b, 0xfc, 0x44, 0x4d, 0x9e, 0xb2, 0xcb,
+	0x94, 0x45, 0x0e, 0x11, 0x7f, 0x66, 0xe1, 0x10, 0xf3, 0x1a, 0x89, 0xa5,
+	0x65, 0x3c, 0xca, 0xc9, 0x1b, 0x7f, 0xc9, 0x58, 0x7a, 0x67, 0x28, 0x1b,
+	0x94, 0x2f, 0xd0, 0x54, 0x91, 0x8b, 0xd3, 0x07, 0xb0, 0x2f, 0xa4, 0xb7,
+	0xac, 0x76, 0x44, 0x9f, 0x61, 0x0e, 0x16, 0x5e, 0xcc, 0x9c, 0x7c, 0x79,
+	0x60, 0x04, 0x5b, 0xc9, 0x03, 0xb7, 0x30, 0x17, 0x6f, 0xa5, 0x6d, 0xb6,
+	0xef, 0x62, 0x6c, 0x73, 0x9c, 0xcb, 0xc5, 0xb5, 0x50, 0x7c, 0x35, 0x39,
+	0x40, 0x87, 0x47, 0x15, 0x7b, 0x15, 0xdf, 0x09, 0xb4, 0xbe, 0x41, 0x8c,
+	0xae, 0x63, 0xdc, 0x10, 0x7b, 0xdf, 0x9e, 0xd2, 0xdb, 0xa9, 0x80, 0xaa,
+	0x72, 0xe6, 0x8e, 0x77, 0x8d, 0x35, 0xd0, 0x6f, 0xac, 0x4e, 0x37, 0xed,
+	0xda, 0xb9, 0x68, 0x16, 0x73, 0xce, 0xab, 0xd0, 0xbd, 0x83, 0xf6, 0x4f,
+	0x5f, 0xba, 0xb7, 0x0f, 0xe4, 0x67, 0xea, 0x16, 0xce, 0x5f, 0x76, 0x1f,
+	0x02, 0x67, 0x5a, 0x50, 0xd7, 0x5c, 0xe4, 0x10, 0x19, 0xf4, 0x96, 0xb7,
+	0xc9, 0xd3, 0x3a, 0x98, 0x9f, 0xae, 0x67, 0x2e, 0x1f, 0x63, 0x2e, 0x1f,
+	0x63, 0xbd, 0xd4, 0x0e, 0x79, 0x4e, 0x64, 0xb4, 0x1c, 0x67, 0xfe, 0xf3,
+	0x35, 0xf2, 0x9f, 0x1d, 0xf7, 0x8b, 0x5c, 0xd3, 0x71, 0xd7, 0xde, 0xab,
+	0x90, 0xa4, 0x3d, 0xdd, 0xc9, 0x6b, 0x7d, 0xf7, 0x5f, 0x8c, 0x3b, 0x98,
+	0xc7, 0xc7, 0xc6, 0x16, 0xa3, 0x9f, 0x99, 0xe8, 0xc6, 0xbd, 0x9f, 0x45,
+	0x17, 0xf9, 0xd4, 0x12, 0x62, 0xf4, 0xea, 0x87, 0x47, 0x6c, 0xcc, 0x16,
+	0xcc, 0x7f, 0x2d, 0x0d, 0xbc, 0x49, 0x4e, 0xd6, 0x9f, 0x3a, 0x60, 0xf3,
+	0x34, 0x17, 0xe3, 0x43, 0x31, 0x71, 0x29, 0xbc, 0xcb, 0xe8, 0x58, 0xa6,
+	0x5a, 0x8b, 0x4b, 0x16, 0x06, 0x7a, 0xdf, 0xa6, 0xaf, 0x56, 0xed, 0x53,
+	0x51, 0x3d, 0x20, 0xb9, 0x3a, 0xf9, 0x11, 0x31, 0xfa, 0x05, 0x62, 0x74,
+	0xf9, 0x9e, 0x5c, 0x5e, 0x9e, 0x60, 0xde, 0x55, 0x6d, 0xe4, 0x72, 0xf3,
+	0xed, 0x7d, 0xb2, 0xf7, 0xc6, 0x8d, 0xe7, 0x68, 0xfb, 0x47, 0xf3, 0xb6,
+	0x7f, 0x2c, 0x8f, 0xc1, 0x16, 0x73, 0xf3, 0x37, 0x6d, 0xfc, 0xcd, 0xe5,
+	0xe6, 0xf3, 0x07, 0x8c, 0x8e, 0x30, 0x31, 0xfa, 0x33, 0x7b, 0xa4, 0x7f,
+	0x0d, 0xd5, 0xc4, 0x93, 0x1a, 0x62, 0x49, 0xc5, 0x80, 0xac, 0xcf, 0x04,
+	0xda, 0xc7, 0x55, 0x9f, 0xdd, 0xc7, 0x26, 0xca, 0xd6, 0x9d, 0x92, 0x77,
+	0x6c, 0x0d, 0x6d, 0x83, 0x12, 0x30, 0xaf, 0xa1, 0x3e, 0xf7, 0xa5, 0xaf,
+	0x42, 0x7b, 0xff, 0x2c, 0xec, 0x1f, 0x92, 0xf8, 0x22, 0xed, 0x4b, 0x2e,
+	0xee, 0xc4, 0xfb, 0xbb, 0x66, 0xe3, 0xfd, 0x91, 0x73, 0x79, 0xf8, 0xe6,
+	0x54, 0xf4, 0x5e, 0x86, 0xd7, 0xe5, 0x92, 0x87, 0xbf, 0xc4, 0x3c, 0xfc,
+	0x6d, 0x45, 0xd6, 0x10, 0x55, 0xdc, 0xb8, 0xc0, 0xc1, 0xf8, 0xa2, 0xfb,
+	0x5f, 0x74, 0xc4, 0xe5, 0x39, 0xb2, 0xff, 0x7e, 0xde, 0x7f, 0x9e, 0xf1,
+	0x7c, 0x80, 0x33, 0x11, 0xad, 0x76, 0xe0, 0x99, 0x85, 0xf1, 0xa8, 0x8b,
+	0xd7, 0x7b, 0xc9, 0x53, 0x66, 0x1a, 0x07, 0xe9, 0x9b, 0xb5, 0xe1, 0xf9,
+	0x0e, 0x07, 0xce, 0x98, 0x7a, 0xcb, 0x6e, 0x5e, 0x7b, 0x36, 0x23, 0xbe,
+	0x18, 0x26, 0x7e, 0x2d, 0xca, 0xfb, 0xa2, 0xbc, 0x8f, 0x01, 0xf7, 0x6c,
+	0xda, 0xeb, 0x6b, 0x29, 0xbd, 0xff, 0x59, 0xda, 0x69, 0xf5, 0x59, 0x3b,
+	0x2d, 0xec, 0xd3, 0x82, 0xbb, 0x2a, 0xd2, 0x82, 0x50, 0xb2, 0xb0, 0x5f,
+	0x6b, 0x3f, 0x7a, 0x32, 0xf7, 0x60, 0xe3, 0x4e, 0x7d, 0xa3, 0xac, 0x11,
+	0xbd, 0x10, 0x8a, 0x5b, 0x95, 0x46, 0x27, 0x5c, 0x0b, 0x8c, 0x16, 0xe6,
+	0x2f, 0xb1, 0xef, 0x2a, 0xa5, 0xb4, 0xdf, 0xc3, 0xd8, 0x34, 0xac, 0x07,
+	0xb7, 0x2b, 0x06, 0xe3, 0x86, 0x86, 0xfd, 0x83, 0x45, 0xb8, 0x75, 0x57,
+	0x1b, 0xf6, 0xf5, 0x9b, 0xc4, 0xcf, 0x5a, 0xff, 0x69, 0xbc, 0x87, 0x63,
+	0xa6, 0xbc, 0xaf, 0x54, 0x82, 0x36, 0x4d, 0xf6, 0x29, 0x31, 0xfb, 0x9c,
+	0x7e, 0xde, 0x3b, 0xe0, 0x9e, 0x12, 0xa3, 0xf0, 0x2e, 0xbf, 0xc1, 0x7c,
+	0x71, 0x12, 0x7b, 0x06, 0x65, 0x6d, 0x60, 0x9a, 0x72, 0xa4, 0x7f, 0xae,
+	0xaf, 0x8b, 0xd8, 0x7f, 0xaf, 0x99, 0xc5, 0x99, 0x85, 0xd5, 0xc0, 0x0c,
+	0x05, 0xa1, 0xcf, 0x04, 0xe4, 0x5b, 0x35, 0xfc, 0x7b, 0xd7, 0xf2, 0x7f,
+	0x51, 0xda, 0xa9, 0xa9, 0xc8, 0xad, 0x17, 0xbc, 0x5e, 0x2d, 0xef, 0xf2,
+	0x1d, 0x49, 0xcd, 0xac, 0xcc, 0x3d, 0x77, 0xfe, 0xa4, 0x3e, 0x5e, 0xb3,
+	0xfc, 0x76, 0x1b, 0x85, 0xba, 0xaf, 0x5a, 0x51, 0xaf, 0x94, 0x2f, 0x62,
+	0xdb, 0xe2, 0x9f, 0xd3, 0x94, 0x76, 0xe2, 0xa9, 0x1a, 0x9a, 0xa6, 0xb4,
+	0x0d, 0x5d, 0xd8, 0xee, 0x8b, 0x56, 0xb4, 0x45, 0xce, 0x0b, 0xe5, 0xdc,
+	0xd3, 0x50, 0x2a, 0x65, 0x0b, 0xf7, 0x9f, 0xc9, 0xb7, 0x55, 0x4c, 0xae,
+	0x9a, 0x2b, 0x73, 0x6b, 0xbf, 0xec, 0xad, 0x8a, 0xe2, 0x68, 0xc3, 0xd4,
+	0xf6, 0x0a, 0x7d, 0x7f, 0xef, 0xbc, 0xf6, 0x72, 0x65, 0x67, 0xb1, 0x4d,
+	0x29, 0x9f, 0xc5, 0xff, 0x6b, 0xaf, 0x23, 0xbc, 0x61, 0xef, 0x93, 0xdc,
+	0x6a, 0x36, 0x46, 0x4b, 0xf0, 0x39, 0xa8, 0x97, 0xc6, 0xe7, 0x97, 0xd8,
+	0xfc, 0x36, 0xda, 0x52, 0xc2, 0x1c, 0xd7, 0x6d, 0x44, 0xef, 0x75, 0x23,
+	0x9b, 0x65, 0x5c, 0x6e, 0x3d, 0xa3, 0xec, 0x57, 0x6e, 0x0d, 0xe8, 0x1b,
+	0xdf, 0x25, 0xdf, 0x78, 0x3e, 0x10, 0x27, 0xd6, 0x1b, 0xbe, 0x3e, 0x45,
+	0x37, 0xd7, 0x32, 0xa6, 0x3d, 0xcb, 0x1c, 0x72, 0x4d, 0xa0, 0xd7, 0x7e,
+	0xc6, 0xa8, 0x44, 0x56, 0xe0, 0x12, 0xfb, 0xbb, 0x2c, 0x2d, 0x30, 0xd2,
+	0xcf, 0xcb, 0x9a, 0x17, 0x7f, 0xc7, 0x30, 0xdf, 0xbe, 0xb6, 0x06, 0x41,
+	0xfb, 0xff, 0xaa, 0xfc, 0xb7, 0x5b, 0x5a, 0x51, 0x6b, 0xff, 0xbf, 0x19,
+	0x73, 0xd3, 0x67, 0xd7, 0x86, 0xd1, 0x6d, 0x5a, 0xd6, 0x53, 0xa6, 0x85,
+	0x37, 0xce, 0xed, 0xd1, 0x5e, 0xe1, 0x60, 0xce, 0x41, 0x17, 0x8e, 0xe5,
+	0xbe, 0x5d, 0x75, 0xee, 0xfd, 0x8c, 0xa5, 0xe7, 0xed, 0xd1, 0x96, 0xf7,
+	0xe2, 0xab, 0xed, 0x6f, 0x93, 0xcd, 0x5b, 0xe4, 0xc4, 0x73, 0x89, 0x8a,
+	0x98, 0x87, 0xbf, 0x37, 0x2d, 0x2a, 0xc2, 0xfa, 0x10, 0x39, 0xdf, 0xa5,
+	0xc7, 0x71, 0xda, 0xfe, 0x46, 0x43, 0x3c, 0x24, 0xdf, 0x66, 0x38, 0x9a,
+	0x50, 0x71, 0x6c, 0xb0, 0x27, 0xb4, 0xc7, 0xee, 0xfb, 0x55, 0x74, 0x8f,
+	0xca, 0x73, 0xbf, 0x16, 0xac, 0x4e, 0x4c, 0xda, 0x7b, 0xda, 0x36, 0xa7,
+	0x24, 0xf7, 0xd6, 0xb3, 0x6b, 0x98, 0xaf, 0xaa, 0x8e, 0x20, 0x6e, 0x62,
+	0x7c, 0x79, 0x21, 0x41, 0x3b, 0x5d, 0xa8, 0x77, 0x7c, 0x97, 0x1c, 0xa1,
+	0x22, 0xa2, 0x07, 0xdf, 0x51, 0x5a, 0xc9, 0xc5, 0xdc, 0x98, 0x48, 0x88,
+	0x2d, 0xca, 0xb7, 0x9d, 0x6e, 0xc6, 0x7e, 0x72, 0xd2, 0xe7, 0x13, 0x1a,
+	0x4e, 0x37, 0x78, 0x90, 0x26, 0x47, 0x7d, 0x2e, 0xe1, 0xc6, 0x63, 0xe4,
+	0xa8, 0x8f, 0x0e, 0xca, 0x1a, 0x61, 0x13, 0x1a, 0x13, 0xb2, 0x3e, 0x4c,
+	0xde, 0x35, 0xe2, 0xa5, 0x3d, 0x5a, 0x56, 0x37, 0x6d, 0xb7, 0x4d, 0x9b,
+	0x60, 0x9f, 0xb2, 0xae, 0x18, 0xc5, 0x35, 0xe4, 0x1d, 0x8f, 0x8e, 0xf8,
+	0xf0, 0x7d, 0x72, 0xf3, 0x24, 0xeb, 0xbd, 0x90, 0xf0, 0xa3, 0x2f, 0xed,
+	0xc3, 0xd3, 0xe4, 0xe8, 0x5b, 0x78, 0x2e, 0xdf, 0x09, 0x2b, 0x32, 0x82,
+	0xe4, 0xc1, 0x87, 0x51, 0xd6, 0x77, 0x11, 0xd6, 0xad, 0x3c, 0x08, 0xb5,
+	0xef, 0x10, 0x8f, 0x2b, 0x19, 0xb3, 0xaf, 0x44, 0x6a, 0x30, 0x82, 0xd4,
+	0xc8, 0x8f, 0xd0, 0x3b, 0x28, 0xe3, 0x92, 0xef, 0x3d, 0xc9, 0xbe, 0x27,
+	0x72, 0xbd, 0x3e, 0x2f, 0x86, 0x46, 0xa4, 0x9f, 0x6a, 0xf6, 0xfd, 0xe7,
+	0xb6, 0xff, 0x1f, 0xd6, 0xba, 0x1b, 0xa5, 0xed, 0x83, 0x9f, 0xd0, 0xbe,
+	0xe8, 0xaa, 0xf0, 0x9e, 0xa1, 0xac, 0x75, 0xb8, 0xd9, 0xa6, 0x07, 0x8e,
+	0x48, 0x76, 0x65, 0x39, 0xf4, 0xe8, 0x36, 0xc5, 0x68, 0x2e, 0x53, 0x26,
+	0xb1, 0x2d, 0x23, 0xef, 0x8d, 0x15, 0xe3, 0x69, 0xe2, 0xa3, 0x2b, 0xa4,
+	0x6b, 0xdf, 0xa5, 0xed, 0x2c, 0x21, 0xa6, 0xbc, 0x61, 0x7e, 0x06, 0x71,
+	0x4d, 0xf4, 0x57, 0x8c, 0x1f, 0xf4, 0xbb, 0xf1, 0x4e, 0x28, 0x82, 0xdc,
+	0xb7, 0xbd, 0x3c, 0xf8, 0x71, 0xc2, 0xcb, 0xf9, 0xaa, 0xcb, 0x1a, 0x8e,
+	0xb9, 0xc0, 0xb4, 0xdc, 0xb5, 0xa3, 0x89, 0x35, 0xd8, 0x43, 0x79, 0x5f,
+	0x48, 0x9c, 0xe1, 0xfc, 0xb4, 0x53, 0xff, 0xa2, 0xef, 0x78, 0x5e, 0xd7,
+	0x3d, 0xd4, 0xf5, 0x2c, 0x3c, 0x9b, 0xb8, 0x0f, 0x8f, 0x52, 0xfe, 0x47,
+	0xfa, 0x8d, 0xe8, 0xc5, 0xca, 0x61, 0xe2, 0x65, 0x31, 0x8e, 0xb1, 0xed,
+	0x5b, 0x99, 0x29, 0x4f, 0x4a, 0x5f, 0x29, 0x59, 0x9f, 0x54, 0xf0, 0xce,
+	0xa2, 0xc3, 0x18, 0xe7, 0xbd, 0x1f, 0xf3, 0x77, 0x78, 0x61, 0x25, 0xfb,
+	0x10, 0xfd, 0xf8, 0xed, 0x5c, 0xa0, 0x8b, 0x3c, 0x67, 0x79, 0xc3, 0x61,
+	0x6c, 0x1d, 0x92, 0x6b, 0x6d, 0xe8, 0xed, 0x7f, 0x0f, 0x8e, 0x10, 0x71,
+	0xc8, 0xdb, 0x40, 0x5b, 0xcf, 0x62, 0x5b, 0xfa, 0xc3, 0x69, 0x39, 0x0e,
+	0xfa, 0xca, 0x34, 0xd9, 0x8b, 0x7c, 0x34, 0x51, 0x8c, 0xe7, 0x58, 0x67,
+	0x5d, 0xc8, 0x95, 0x7f, 0x66, 0x72, 0x98, 0xfc, 0xc9, 0x89, 0x34, 0xfb,
+	0x48, 0xd8, 0x6d, 0x4c, 0x53, 0x76, 0xd3, 0x0f, 0x2b, 0x17, 0x4e, 0x53,
+	0x52, 0x43, 0xc2, 0xed, 0x7f, 0x84, 0x27, 0xef, 0xcf, 0xe9, 0x70, 0x8f,
+	0xb9, 0x06, 0x43, 0xe9, 0x1f, 0x17, 0xda, 0x9b, 0xf2, 0x2e, 0x9c, 0xbc,
+	0x9f, 0x53, 0x78, 0x57, 0x27, 0xf7, 0x4c, 0xeb, 0xdb, 0x99, 0x0a, 0xf2,
+	0xe7, 0x52, 0xda, 0x5a, 0x51, 0xcc, 0xcb, 0xb8, 0xba, 0x66, 0x81, 0x86,
+	0x9d, 0x97, 0xd5, 0x4d, 0x43, 0x85, 0xe6, 0xfc, 0x75, 0xc3, 0xf3, 0xec,
+	0xa7, 0x22, 0x56, 0x15, 0xd9, 0x63, 0xef, 0x83, 0x0a, 0x5d, 0x56, 0xc3,
+	0xb8, 0x22, 0xcf, 0x86, 0x63, 0x78, 0x2b, 0x51, 0x1d, 0xab, 0x8e, 0x54,
+	0x12, 0x6f, 0x4f, 0xa3, 0x6f, 0xd8, 0x89, 0x0a, 0xf2, 0xe6, 0xf2, 0x64,
+	0x35, 0xdc, 0xf6, 0x3a, 0xde, 0x45, 0xe4, 0x2b, 0xb3, 0xc9, 0x49, 0x66,
+	0xa1, 0x92, 0xbc, 0xc4, 0x13, 0xb2, 0xac, 0x9f, 0x2d, 0xb4, 0xac, 0x4b,
+	0x78, 0x94, 0xf0, 0x38, 0x15, 0x12, 0x3f, 0x8d, 0xa2, 0xce, 0xf6, 0x57,
+	0x03, 0xf5, 0xf6, 0xff, 0x26, 0xfa, 0x7a, 0x47, 0x68, 0xfe, 0xf8, 0x7d,
+	0xa1, 0xb9, 0xe3, 0x35, 0x50, 0x07, 0xa6, 0xc3, 0xc1, 0xb6, 0xbe, 0x70,
+	0x99, 0x85, 0x26, 0xfa, 0xf0, 0x5a, 0x53, 0x78, 0xd1, 0x1a, 0xf2, 0xa2,
+	0xde, 0x90, 0x31, 0x7e, 0x10, 0x57, 0x33, 0xce, 0xb9, 0x07, 0x7c, 0xec,
+	0x47, 0x72, 0x6c, 0x67, 0x76, 0x0e, 0xf9, 0xf6, 0x67, 0x16, 0x0a, 0x47,
+	0x6a, 0x25, 0x47, 0x3a, 0x84, 0xd6, 0xf1, 0xc3, 0xb8, 0x9e, 0x65, 0x3c,
+	0xe4, 0x2a, 0xc9, 0xcc, 0x8f, 0xd0, 0x97, 0xb1, 0xb0, 0x3d, 0x94, 0xc5,
+	0xb5, 0x6c, 0xbb, 0x74, 0xa0, 0x99, 0xdc, 0x70, 0x05, 0xd6, 0x8d, 0xcb,
+	0xbb, 0x52, 0x13, 0x58, 0x3e, 0x4e, 0xce, 0x39, 0x5e, 0xf0, 0x57, 0xe1,
+	0x4b, 0x2b, 0xc8, 0x97, 0x64, 0x2d, 0x6d, 0x95, 0xbd, 0x96, 0xa6, 0xd2,
+	0x0f, 0x1b, 0x13, 0xf2, 0x9e, 0x50, 0x1c, 0xab, 0xc7, 0x05, 0xab, 0xef,
+	0x41, 0xf7, 0xb8, 0xac, 0xcd, 0x7e, 0x33, 0x74, 0xf1, 0xf8, 0xab, 0x68,
+	0x1c, 0x1f, 0x0a, 0xcd, 0x1b, 0x1f, 0xa1, 0xdc, 0x09, 0xca, 0xd6, 0x1f,
+	0xaa, 0x1d, 0x1f, 0x0c, 0x05, 0xc7, 0x77, 0x87, 0x02, 0xe3, 0x2d, 0xd8,
+	0x32, 0xbe, 0x0a, 0x9b, 0xc7, 0x37, 0x62, 0xd3, 0xb8, 0xe0, 0xfc, 0x24,
+	0x96, 0x8d, 0xbf, 0x81, 0xa5, 0xe3, 0xcf, 0xa3, 0x69, 0xfc, 0x04, 0x96,
+	0x8c, 0xff, 0x08, 0xcd, 0xe3, 0xaf, 0x70, 0x2c, 0xb2, 0xd6, 0x2b, 0xeb,
+	0xbc, 0x85, 0xe7, 0x6a, 0x53, 0xf7, 0x24, 0xcb, 0x5a, 0x86, 0x7c, 0xbf,
+	0x43, 0xe6, 0xd0, 0x85, 0x95, 0xda, 0x6b, 0xe8, 0xd9, 0x25, 0xdf, 0x24,
+	0xac, 0xd3, 0xba, 0xe5, 0xf9, 0xa3, 0xf7, 0x79, 0xd9, 0x63, 0x4f, 0x1b,
+	0x3b, 0xff, 0xbd, 0xbc, 0xc9, 0xb3, 0xcf, 0x18, 0xe5, 0x1b, 0x18, 0xf2,
+	0xec, 0x73, 0x12, 0x5d, 0x99, 0xdf, 0x5a, 0x51, 0x4d, 0xca, 0xca, 0xf7,
+	0x3f, 0xc4, 0x1e, 0x5e, 0xc3, 0x43, 0xbb, 0x26, 0xc9, 0x59, 0xb2, 0xf6,
+	0x5a, 0xcd, 0xbb, 0xf3, 0xe4, 0x9b, 0x56, 0xf2, 0xce, 0xfe, 0x6b, 0x48,
+	0x8d, 0x02, 0xe3, 0x0f, 0x8b, 0x1f, 0xae, 0xa1, 0x1f, 0x66, 0xc5, 0x27,
+	0xe3, 0xc4, 0xe4, 0xaf, 0x78, 0x70, 0x0f, 0x79, 0x49, 0x11, 0xb2, 0x23,
+	0xa5, 0x78, 0x66, 0x30, 0x6e, 0xcd, 0x31, 0x3c, 0x28, 0x8f, 0x18, 0xd9,
+	0x4b, 0x18, 0x67, 0x5f, 0xe1, 0xb5, 0x89, 0x7e, 0xf8, 0x7d, 0x46, 0xc0,
+	0x37, 0x87, 0xe7, 0xc7, 0x86, 0xb2, 0xe4, 0x14, 0x1d, 0x98, 0xe4, 0x7f,
+	0xc9, 0x41, 0x81, 0x6e, 0x0c, 0x0d, 0x89, 0x3e, 0x5b, 0xa8, 0x4f, 0xc1,
+	0x45, 0xbd, 0xa3, 0x89, 0x78, 0x68, 0x29, 0x82, 0x87, 0x2a, 0xca, 0x1e,
+	0xe8, 0xa4, 0xbf, 0xea, 0xb1, 0x9f, 0x30, 0x16, 0xf4, 0x29, 0x3f, 0xc2,
+	0x73, 0xcc, 0x19, 0x4a, 0x1f, 0x20, 0xff, 0x20, 0x56, 0x56, 0x44, 0x14,
+	0x63, 0x79, 0xe0, 0x14, 0x9e, 0x19, 0x71, 0xc2, 0x9d, 0x74, 0x62, 0x82,
+	0x38, 0xe9, 0x48, 0xca, 0xf3, 0x7a, 0x8d, 0xb2, 0xc8, 0xba, 0xd0, 0x09,
+	0x64, 0xed, 0xe7, 0x69, 0xf2, 0x3c, 0xe4, 0x45, 0xbb, 0x1f, 0x27, 0x65,
+	0xef, 0x21, 0x96, 0x76, 0xa5, 0x5e, 0x42, 0xd3, 0x90, 0x07, 0x73, 0x92,
+	0x13, 0xcc, 0x5f, 0x5e, 0x45, 0x6a, 0xd7, 0x2c, 0x7c, 0x95, 0x3c, 0x70,
+	0x66, 0xd2, 0x84, 0x46, 0xbd, 0xdd, 0x34, 0x66, 0x22, 0xba, 0x77, 0x15,
+	0x56, 0xee, 0xfd, 0x22, 0x8f, 0xe9, 0xb8, 0x7e, 0x6f, 0x3b, 0x3e, 0x3f,
+	0x16, 0x47, 0xeb, 0x58, 0x0f, 0x8f, 0x36, 0x5c, 0xb7, 0xa3, 0x12, 0xe9,
+	0x90, 0xc6, 0x9c, 0xba, 0x8d, 0x39, 0xb5, 0xf0, 0xa1, 0xd5, 0x78, 0x86,
+	0xb8, 0x13, 0x0c, 0xad, 0xc6, 0x84, 0xed, 0x8b, 0xb2, 0x97, 0x71, 0x35,
+	0x36, 0x31, 0x5f, 0x1e, 0xc6, 0x6a, 0x74, 0xf1, 0xda, 0x0e, 0x7b, 0x0e,
+	0x0e, 0x63, 0x31, 0xf3, 0xa1, 0xf7, 0x2f, 0x3f, 0x8c, 0x2b, 0xf6, 0x48,
+	0xdf, 0xa7, 0x91, 0xda, 0xb9, 0x86, 0x6d, 0x66, 0xd1, 0x32, 0xf6, 0x43,
+	0x7c, 0x7e, 0x07, 0x6e, 0xab, 0x44, 0x25, 0x9e, 0x0f, 0x05, 0x5a, 0xfb,
+	0x94, 0x1f, 0xda, 0x6d, 0x6f, 0xa2, 0x1f, 0x6f, 0x65, 0xb9, 0x47, 0xd2,
+	0x27, 0xd0, 0x9b, 0x9a, 0x3a, 0xa7, 0xf6, 0x7b, 0xed, 0x8c, 0x07, 0x2f,
+	0x63, 0xdf, 0xc8, 0x24, 0xb1, 0xf7, 0x24, 0x8f, 0x0b, 0x9f, 0x5f, 0x7b,
+	0xed, 0x7c, 0x26, 0x67, 0x37, 0x92, 0xbf, 0xc8, 0x3a, 0x70, 0x0b, 0x7c,
+	0x29, 0xe1, 0x44, 0xd9, 0xad, 0x33, 0xa1, 0x6f, 0x0c, 0xdb, 0x1c, 0xc9,
+	0x88, 0x91, 0x1b, 0xb5, 0x7c, 0x57, 0xf1, 0x90, 0x1b, 0x05, 0xb1, 0x22,
+	0xa3, 0x47, 0xaf, 0xa5, 0xbe, 0x4b, 0xee, 0x7f, 0x19, 0xce, 0xfb, 0x9d,
+	0x28, 0x4e, 0xca, 0xda, 0xc9, 0x04, 0x7a, 0x33, 0xf2, 0xfe, 0x6e, 0x56,
+	0x2f, 0x26, 0xae, 0x16, 0x25, 0xb3, 0x8c, 0xfd, 0xd9, 0xf9, 0x45, 0x90,
+	0x77, 0xf1, 0xaf, 0xc2, 0x9a, 0xfe, 0x28, 0xba, 0x4c, 0x79, 0x57, 0x27,
+	0x37, 0xfe, 0x39, 0x0d, 0x2f, 0xa3, 0x9b, 0xf1, 0xa7, 0x8d, 0x98, 0xf8,
+	0x55, 0xfb, 0x59, 0xe8, 0xcb, 0xe8, 0x19, 0x2c, 0xbc, 0xbb, 0x2e, 0x6d,
+	0x3e, 0x4f, 0xbd, 0xb9, 0xf2, 0xdf, 0xec, 0x91, 0x36, 0x75, 0xd3, 0xaf,
+	0x4e, 0xcb, 0xbd, 0x8b, 0x03, 0xfb, 0x19, 0x36, 0xed, 0xe3, 0x35, 0xf4,
+	0xee, 0x2a, 0x8c, 0x99, 0xb9, 0x41, 0xe0, 0x35, 0xf4, 0x8f, 0xca, 0xd8,
+	0xaf, 0x9f, 0x96, 0x7b, 0xc7, 0x78, 0xaa, 0x3e, 0x0a, 0x75, 0x1d, 0xb4,
+	0xe7, 0xc2, 0xfd, 0x8f, 0xfb, 0x6e, 0xd0, 0xa7, 0xec, 0x6f, 0xf0, 0xe4,
+	0xbe, 0x81, 0x04, 0x3c, 0x99, 0x90, 0x77, 0xfb, 0xd5, 0xc5, 0x2e, 0xa8,
+	0x5e, 0x17, 0x8a, 0x19, 0x2f, 0x6a, 0xd0, 0xed, 0xb5, 0x70, 0x35, 0xc7,
+	0xb2, 0xbf, 0xfe, 0x3a, 0x66, 0x1a, 0xf1, 0x56, 0x97, 0xfd, 0xce, 0xe1,
+	0x8a, 0xbf, 0xfe, 0xe8, 0x3b, 0x87, 0x6f, 0x10, 0x67, 0x15, 0x94, 0x1b,
+	0x37, 0xe1, 0x05, 0x3b, 0xa6, 0x28, 0x28, 0x9b, 0x2b, 0xeb, 0x98, 0x7e,
+	0x3c, 0x6b, 0xd4, 0xf9, 0xab, 0xe4, 0xf9, 0x94, 0x72, 0xca, 0x92, 0x6f,
+	0x06, 0x6c, 0xcb, 0xfc, 0xb1, 0x3d, 0xf1, 0x4f, 0x61, 0xcb, 0xce, 0x30,
+	0xe4, 0xfd, 0x15, 0xa7, 0xa1, 0x79, 0x73, 0xfc, 0x4a, 0x64, 0x93, 0xbd,
+	0xe4, 0xb7, 0x12, 0x9c, 0xde, 0xa0, 0x9f, 0xbe, 0x21, 0x7b, 0xa6, 0xc8,
+	0x99, 0xfe, 0x12, 0xc1, 0xaa, 0xc2, 0x38, 0x65, 0xaf, 0xa9, 0x92, 0x1b,
+	0xab, 0x5d, 0x47, 0xca, 0x4a, 0xbd, 0x37, 0xec, 0x35, 0x5c, 0x97, 0xf1,
+	0x5b, 0xeb, 0x4d, 0x6f, 0x35, 0xcb, 0x1e, 0xce, 0xdf, 0x9f, 0x14, 0x9f,
+	0x33, 0xe5, 0x1b, 0x56, 0x4e, 0xbb, 0x8e, 0xe8, 0xf7, 0x5c, 0x9d, 0xee,
+	0x94, 0x83, 0xb8, 0x79, 0xc2, 0xea, 0xf4, 0xca, 0x18, 0xee, 0xbc, 0xa0,
+	0x8e, 0xac, 0x2b, 0x68, 0xd2, 0x6f, 0x58, 0xc6, 0xdc, 0x95, 0xf9, 0x68,
+	0x9f, 0xb2, 0xde, 0x5b, 0x64, 0x94, 0xe1, 0x54, 0x55, 0x6e, 0x1d, 0xe6,
+	0x9c, 0x8c, 0x3d, 0x35, 0xb2, 0x4f, 0xaf, 0xd8, 0x3e, 0xb7, 0xfb, 0x35,
+	0xcf, 0xd5, 0xfb, 0xbb, 0xfc, 0x78, 0xab, 0xed, 0x77, 0x86, 0x1e, 0xb4,
+	0x79, 0x91, 0x63, 0xca, 0xb8, 0x4b, 0x6a, 0xce, 0xef, 0xe7, 0x2b, 0xf9,
+	0x7e, 0x45, 0x1e, 0xef, 0x94, 0x3e, 0x44, 0xae, 0x87, 0xf3, 0x75, 0xf4,
+	0x70, 0xd4, 0xee, 0x5f, 0x65, 0xbe, 0x55, 0xe8, 0x93, 0xfe, 0xb8, 0xb0,
+	0xd0, 0x46, 0x56, 0xec, 0xb3, 0xb3, 0x98, 0xb1, 0xed, 0x54, 0xc3, 0x3d,
+	0xd8, 0x94, 0x10, 0x3d, 0xcb, 0xb7, 0x60, 0x89, 0xe1, 0x36, 0x57, 0x73,
+	0xd1, 0x5f, 0x2f, 0xc3, 0x90, 0x16, 0xc7, 0x9e, 0x7a, 0x79, 0x47, 0xce,
+	0x45, 0x9f, 0x88, 0xa3, 0xc4, 0x28, 0x96, 0xfd, 0xc7, 0xf6, 0x1e, 0x94,
+	0x7d, 0xa6, 0x1e, 0x7d, 0x52, 0xbe, 0x55, 0x76, 0xa9, 0xbd, 0x5e, 0xd5,
+	0x3c, 0x04, 0xb9, 0x6e, 0xe2, 0xda, 0xf3, 0xf2, 0xfe, 0x12, 0xda, 0x8e,
+	0xbd, 0x27, 0xda, 0x94, 0x77, 0xe8, 0xfa, 0x12, 0xf2, 0x2e, 0x57, 0x5d,
+	0x8c, 0xfc, 0x12, 0x2f, 0xa4, 0x65, 0xbf, 0xc2, 0xef, 0xac, 0x78, 0x8d,
+	0xec, 0x8b, 0x9c, 0x5a, 0xa7, 0x88, 0xb8, 0x16, 0x08, 0x57, 0x28, 0x85,
+	0xf7, 0xb9, 0xce, 0xfd, 0x5d, 0x4f, 0x9b, 0x39, 0x6d, 0xbf, 0x83, 0x27,
+	0x67, 0x11, 0x34, 0xa6, 0xe4, 0x9b, 0xa7, 0xfa, 0xc4, 0x72, 0xd4, 0x65,
+	0x6b, 0x1d, 0xce, 0x3c, 0x7f, 0x09, 0x63, 0x05, 0xed, 0x66, 0x73, 0x20,
+	0x6c, 0xbf, 0x6b, 0xb6, 0x2c, 0x55, 0x1b, 0x7c, 0x04, 0x7a, 0xfb, 0xdb,
+	0x2c, 0x7f, 0x5d, 0xe6, 0xfb, 0xd6, 0x90, 0x57, 0xc6, 0x54, 0xc0, 0x88,
+	0x13, 0xf4, 0x0d, 0xea, 0x31, 0x22, 0xfe, 0xe1, 0x41, 0x55, 0x24, 0x4c,
+	0x3f, 0x96, 0xf8, 0x2f, 0xef, 0xa9, 0xe9, 0xbb, 0xe3, 0x30, 0xd1, 0xc8,
+	0x1c, 0xdd, 0x65, 0xef, 0x73, 0xd6, 0xfd, 0x2b, 0x19, 0x87, 0x8e, 0x9c,
+	0xdd, 0x13, 0x20, 0x7c, 0xe1, 0xc7, 0x35, 0xf9, 0xbd, 0xd0, 0xee, 0x39,
+	0x8c, 0x8f, 0x96, 0xfd, 0x9c, 0x7f, 0x8d, 0x8d, 0x2d, 0x9a, 0xa1, 0xef,
+	0xff, 0x95, 0xa3, 0x13, 0x4f, 0x2c, 0x30, 0x3a, 0x0e, 0xa8, 0xd9, 0x21,
+	0x1f, 0x71, 0xe6, 0x4a, 0x47, 0x74, 0x07, 0xff, 0xfb, 0x5f, 0xb4, 0xbf,
+	0xa1, 0x22, 0x75, 0xf5, 0xe0, 0x2a, 0x55, 0xf6, 0x0f, 0xb5, 0x60, 0xac,
+	0x4f, 0xde, 0x7d, 0xd0, 0x5b, 0xbf, 0xad, 0x74, 0x62, 0x43, 0xc8, 0x68,
+	0xd9, 0xa8, 0xe8, 0xcd, 0x7f, 0xaf, 0xe8, 0xfe, 0x90, 0x22, 0xe5, 0x82,
+	0xb2, 0xb6, 0x77, 0x36, 0xf6, 0xba, 0xd8, 0xc7, 0xde, 0x84, 0x1e, 0x9e,
+	0xc6, 0xb2, 0xa7, 0x4c, 0xc3, 0xf7, 0x1e, 0xdb, 0xfc, 0x09, 0x8f, 0x1d,
+	0xf6, 0x3b, 0xec, 0x52, 0x3e, 0x3a, 0xdf, 0x65, 0x7f, 0x8f, 0xb8, 0x95,
+	0x31, 0x45, 0xbe, 0x35, 0x1c, 0x83, 0x96, 0x9c, 0x45, 0x13, 0xd3, 0x7b,
+	0x6f, 0x80, 0xe4, 0xc0, 0x37, 0x4f, 0x47, 0xa9, 0x07, 0xde, 0x48, 0x27,
 	0xe6, 0x2e, 0x30, 0x7c, 0x8b, 0x54, 0xbb, 0x7e, 0x30, 0xaa, 0x4a, 0x7d,
-	0xdd, 0x3f, 0x08, 0x69, 0x23, 0x63, 0x69, 0x73, 0xcb, 0xed, 0x3a, 0x0b,
-	0xd4, 0xcf, 0xc0, 0x75, 0xf5, 0xaf, 0xe5, 0x5b, 0x46, 0x5a, 0xa5, 0x21,
-	0x75, 0xe2, 0x3b, 0x35, 0xfc, 0xb1, 0x7a, 0x82, 0x2b, 0xbf, 0xb2, 0x30,
-	0x4d, 0xea, 0xc9, 0x9e, 0xb1, 0x3b, 0x70, 0xaf, 0xfd, 0x3d, 0x16, 0xf1,
-	0x47, 0x3d, 0xfa, 0x15, 0xf2, 0xcf, 0x62, 0x45, 0xb8, 0xa7, 0xf0, 0x84,
-	0x56, 0x74, 0x33, 0x8e, 0x69, 0x21, 0xbd, 0xe7, 0x0a, 0xd5, 0x83, 0xc2,
-	0xc8, 0x63, 0xb2, 0x6f, 0x66, 0xef, 0x3c, 0x35, 0xbb, 0xbf, 0x26, 0xc6,
-	0x76, 0x8f, 0xff, 0xd1, 0xe7, 0xb8, 0xec, 0xab, 0xd8, 0x94, 0xf7, 0x5b,
-	0xec, 0x35, 0xc5, 0xd6, 0x84, 0x23, 0xb7, 0x5f, 0x30, 0x3f, 0xb7, 0x1a,
-	0xda, 0xc8, 0xf5, 0xd7, 0xc8, 0x37, 0x31, 0x39, 0xd6, 0xb5, 0x09, 0x59,
-	0x4d, 0xfa, 0xff, 0x00, 0x85, 0x57, 0x0f, 0xe7, 0xe8, 0x59, 0x00, 0x00,
+	0xdd, 0x3f, 0x08, 0x69, 0x23, 0x6b, 0x69, 0x73, 0x2b, 0xed, 0x3a, 0x0b,
+	0xd4, 0xcf, 0xc1, 0xf5, 0xe9, 0x5f, 0xcb, 0x37, 0x8b, 0xb4, 0x6a, 0x43,
+	0xea, 0xc4, 0x77, 0x68, 0xf8, 0x63, 0xf5, 0x04, 0x57, 0x7e, 0x65, 0x61,
+	0xba, 0xd4, 0x93, 0x3d, 0x66, 0x37, 0xe3, 0x76, 0xfb, 0xbb, 0x2b, 0xe2,
+	0x8f, 0x7a, 0xf4, 0x6e, 0x72, 0xd5, 0x52, 0x45, 0x78, 0xaa, 0xc4, 0xa2,
+	0x36, 0xe2, 0x61, 0x27, 0xb4, 0x90, 0xde, 0x7b, 0x91, 0xea, 0x41, 0x71,
+	0x64, 0x54, 0xf6, 0xd9, 0xec, 0x9e, 0xa7, 0xe6, 0xf6, 0xe3, 0xc4, 0xd8,
+	0xee, 0x91, 0x3f, 0xfa, 0xdc, 0x97, 0x7d, 0x95, 0x9a, 0xf2, 0xce, 0x8e,
+	0xfd, 0x9e, 0x48, 0x5b, 0xc2, 0x91, 0xdf, 0x5f, 0x58, 0x98, 0x5b, 0x0d,
+	0x6b, 0x98, 0x17, 0xac, 0x95, 0x6f, 0x63, 0x72, 0xac, 0xeb, 0x12, 0xb2,
+	0x0a, 0xf5, 0x7f, 0x01, 0x28, 0xfc, 0xfc, 0x40, 0x38, 0x5a, 0x00, 0x00,
 	0x00 };
 
 static const u32 bnx2_CP_b06FwData[(0x84/4) + 1] = {
@@ -2137,48 +2138,48 @@
 	0x00000002, 0x00000002, 0x00000002, 0x00000002, 0x00000002, 0x00000002,
 	0x00000001, 0x00000001, 0x00000001, 0x00000000 };
 static const u32 bnx2_CP_b06FwRodata[(0x130/4) + 1] = {
-	0x08001f1c, 0x08001da8, 0x08001ef8, 0x08001ed4, 0x08001eb0, 0x08001e8c,
-	0x08001e64, 0x08001e3c, 0x08001e10, 0x08002014, 0x08002004, 0x08001dc4,
-	0x08001dc4, 0x08001dc4, 0x08001f44, 0x08001f44, 0x08001dc4, 0x08001dc4,
-	0x08001ff4, 0x08001dc4, 0x08001dc4, 0x08001dc4, 0x08001dc4, 0x08001fe4,
-	0x08001dc4, 0x08001dc4, 0x08001dc4, 0x08001dc4, 0x08001dc4, 0x08001dc4,
-	0x08001dc4, 0x08001dc4, 0x08001dc4, 0x08001dc4, 0x08001dc4, 0x08001dc4,
-	0x08001dc4, 0x08001dc4, 0x08001fd4, 0x08001dc4, 0x08001dc4, 0x08001fc4,
-	0x08001dc4, 0x08001dc4, 0x08001dc4, 0x08001dc4, 0x08001dc4, 0x08001dc4,
-	0x08001dc4, 0x08001dc4, 0x08001dc4, 0x08001dc4, 0x08001dc4, 0x08001dc4,
-	0x08001dc4, 0x08001dc4, 0x08001dc4, 0x08001dc4, 0x08001dc4, 0x08001fac,
-	0x08001dc4, 0x08001dc4, 0x08001f9c, 0x08001f8c, 0x080031e8, 0x080031f0,
-	0x080031b8, 0x080031c4, 0x080031d0, 0x080031dc, 0x08005644, 0x08005604,
-	0x080055d0, 0x080055a4, 0x08005580, 0x0800553c, 0x00000000 };
+	0x08001e8c, 0x08001d18, 0x08001e68, 0x08001e44, 0x08001e20, 0x08001dfc,
+	0x08001dd4, 0x08001dac, 0x08001d80, 0x08001f84, 0x08001f74, 0x08001d34,
+	0x08001d34, 0x08001d34, 0x08001eb4, 0x08001eb4, 0x08001d34, 0x08001d34,
+	0x08001f64, 0x08001d34, 0x08001d34, 0x08001d34, 0x08001d34, 0x08001f54,
+	0x08001d34, 0x08001d34, 0x08001d34, 0x08001d34, 0x08001d34, 0x08001d34,
+	0x08001d34, 0x08001d34, 0x08001d34, 0x08001d34, 0x08001d34, 0x08001d34,
+	0x08001d34, 0x08001d34, 0x08001f44, 0x08001d34, 0x08001d34, 0x08001f34,
+	0x08001d34, 0x08001d34, 0x08001d34, 0x08001d34, 0x08001d34, 0x08001d34,
+	0x08001d34, 0x08001d34, 0x08001d34, 0x08001d34, 0x08001d34, 0x08001d34,
+	0x08001d34, 0x08001d34, 0x08001d34, 0x08001d34, 0x08001d34, 0x08001f1c,
+	0x08001d34, 0x08001d34, 0x08001f0c, 0x08001efc, 0x08003208, 0x08003210,
+	0x080031d8, 0x080031e4, 0x080031f0, 0x080031fc, 0x08005694, 0x08005654,
+	0x08005620, 0x080055f4, 0x080055d0, 0x0800558c, 0x00000000 };
 
 static struct fw_info bnx2_cp_fw_06 = {
-	/* Firmware version: 4.0.5 */
+	/* Firmware version: 4.4.22 */
 	.ver_major			= 0x4,
-	.ver_minor			= 0x0,
-	.ver_fix			= 0x5,
+	.ver_minor			= 0x4,
+	.ver_fix			= 0x16,
 
-	.start_addr			= 0x08000078,
+	.start_addr			= 0x08000080,
 
 	.text_addr			= 0x08000000,
-	.text_len			= 0x59e4,
+	.text_len			= 0x5a34,
 	.text_index			= 0x0,
 	.gz_text			= bnx2_CP_b06FwText,
 	.gz_text_len			= sizeof(bnx2_CP_b06FwText),
 
-	.data_addr			= 0x08005b40,
+	.data_addr			= 0x08005b80,
 	.data_len			= 0x84,
 	.data_index			= 0x0,
 	.data				= bnx2_CP_b06FwData,
 
-	.sbss_addr			= 0x08005bc4,
+	.sbss_addr			= 0x08005c04,
 	.sbss_len			= 0xe9,
 	.sbss_index			= 0x0,
 
-	.bss_addr			= 0x08005cb0,
+	.bss_addr			= 0x08005cf0,
 	.bss_len			= 0x5d8,
 	.bss_index			= 0x0,
 
-	.rodata_addr			= 0x080059e4,
+	.rodata_addr			= 0x08005a34,
 	.rodata_len			= 0x130,
 	.rodata_index			= 0x0,
 	.rodata				= bnx2_CP_b06FwRodata,
@@ -2201,761 +2202,761 @@
 };
 
 static u8 bnx2_RXP_b06FwText[] = {
-	0xec, 0x5b, 0x5d, 0x70, 0x5c, 0xd7, 0x5d, 0xff, 0xdf, 0xb3, 0x2b, 0x69,
-	0x2d, 0x4b, 0xf2, 0x95, 0xbc, 0x71, 0x56, 0xa9, 0x92, 0xec, 0x5a, 0x57,
-	0xd2, 0xa6, 0x12, 0xe1, 0xca, 0x6c, 0x12, 0x75, 0xd8, 0x69, 0xb6, 0xbb,
-	0xb2, 0xa3, 0xb4, 0x66, 0x46, 0x49, 0x0d, 0xcd, 0xb4, 0x65, 0x10, 0xbb,
-	0x0e, 0xa4, 0x0f, 0x0c, 0xc6, 0x40, 0x26, 0x80, 0xc1, 0xcb, 0x4a, 0x71,
-	0x94, 0x74, 0xad, 0xdd, 0xda, 0x0a, 0x86, 0x69, 0x61, 0x94, 0xd5, 0x87,
-	0x53, 0x66, 0xad, 0x4d, 0xcb, 0x4b, 0x99, 0xd6, 0xb1, 0xea, 0xb8, 0x26,
-	0x0f, 0x3c, 0xa4, 0x94, 0xce, 0x64, 0x20, 0x33, 0x35, 0xb2, 0x63, 0xfb,
-	0x81, 0x8f, 0xc0, 0x4c, 0x49, 0x20, 0x6e, 0x2e, 0xbf, 0xdf, 0xb9, 0xf7,
-	0xca, 0x2b, 0x45, 0xd0, 0x3c, 0xf0, 0x78, 0xcf, 0x8c, 0xe6, 0xde, 0x7b,
-	0xce, 0xff, 0xfc, 0xcf, 0xff, 0xfb, 0xe3, 0xac, 0xfd, 0x3b, 0x1d, 0xd2,
-	0x2e, 0xde, 0xe8, 0xc4, 0x5f, 0xea, 0xc8, 0x33, 0x47, 0x47, 0xef, 0x1f,
-	0xbd, 0x9f, 0xdf, 0x21, 0xc3, 0x08, 0xf3, 0x69, 0x48, 0x30, 0x82, 0x11,
-	0x8c, 0x60, 0x04, 0x23, 0x18, 0xc1, 0x08, 0x46, 0x30, 0x82, 0x11, 0x8c,
-	0x60, 0x04, 0x23, 0x18, 0xc1, 0x08, 0x46, 0x30, 0x82, 0x11, 0x8c, 0x60,
-	0x04, 0x23, 0x18, 0xc1, 0x08, 0x46, 0x30, 0x82, 0x11, 0x8c, 0x60, 0x04,
-	0x23, 0x18, 0xc1, 0x08, 0x46, 0x30, 0x82, 0x11, 0x8c, 0x60, 0x04, 0x23,
-	0x18, 0xc1, 0x08, 0x46, 0x30, 0x82, 0x11, 0x8c, 0x60, 0x04, 0x23, 0x18,
-	0xc1, 0x08, 0x46, 0x30, 0xfe, 0x3f, 0x47, 0x48, 0xc4, 0xe4, 0xb3, 0xd3,
-	0xfb, 0x93, 0x88, 0x4a, 0xc7, 0x8f, 0x66, 0x2d, 0x89, 0x84, 0xd2, 0x97,
-	0x9e, 0x2e, 0x58, 0x22, 0x99, 0xfa, 0x70, 0x3c, 0x27, 0x3f, 0x71, 0x8a,
-	0xd1, 0xb0, 0x70, 0xfe, 0xee, 0xf4, 0xad, 0xe3, 0xe7, 0x1f, 0x4a, 0xbc,
-	0xb3, 0x10, 0x92, 0x88, 0x99, 0x7e, 0x63, 0xd4, 0x1c, 0x94, 0x48, 0x1f,
-	0xf6, 0x7c, 0x6d, 0x68, 0x6d, 0x97, 0x74, 0xf9, 0xb8, 0x44, 0x6a, 0xe5,
-	0x84, 0x7d, 0x40, 0x86, 0xcd, 0x8b, 0x12, 0x96, 0x0c, 0xce, 0x58, 0xa9,
-	0x8b, 0x94, 0xca, 0x06, 0x71, 0x48, 0xa9, 0x1e, 0x91, 0x2b, 0x21, 0x42,
-	0x7d, 0xcb, 0xc8, 0x56, 0x3e, 0x70, 0x32, 0x61, 0x9c, 0x6b, 0xe1, 0xbd,
-	0xe1, 0xcf, 0x47, 0x44, 0xa5, 0x13, 0xc9, 0x6c, 0x68, 0x42, 0x6a, 0xf3,
-	0x8e, 0x33, 0x63, 0x7f, 0x0c, 0x38, 0x7a, 0x64, 0xc6, 0x72, 0xbf, 0xb3,
-	0xf6, 0xc7, 0xcd, 0x71, 0xb9, 0x13, 0x73, 0x21, 0x51, 0xd6, 0x5d, 0xf8,
-	0x8b, 0x1b, 0xb9, 0xd3, 0x5f, 0x36, 0xb2, 0x8b, 0x1d, 0x52, 0xaa, 0x38,
-	0x52, 0xb0, 0x25, 0x93, 0xb5, 0x77, 0x60, 0xfd, 0x03, 0xa7, 0xb0, 0xb1,
-	0x67, 0xd8, 0xcc, 0x49, 0x8b, 0x64, 0xa2, 0x31, 0xc0, 0xcc, 0x1b, 0xb9,
-	0xb3, 0x7f, 0xdd, 0x21, 0xed, 0xa0, 0x27, 0xc5, 0xef, 0x0f, 0x9c, 0x90,
-	0x65, 0x61, 0x9d, 0xe7, 0xe3, 0xbb, 0x41, 0xbc, 0x7c, 0x27, 0xce, 0x2b,
-	0xce, 0xf9, 0xa1, 0x98, 0x7c, 0xb3, 0x11, 0x95, 0x6f, 0x34, 0x4c, 0x79,
-	0xa5, 0xd1, 0x27, 0x17, 0x1a, 0x8e, 0xf3, 0x0d, 0xdb, 0x71, 0xde, 0xc0,
-	0xdf, 0x7f, 0xd8, 0x1b, 0x3c, 0x60, 0x14, 0x8d, 0xf1, 0xc6, 0x57, 0x3b,
-	0xa4, 0x2b, 0x11, 0x17, 0xd5, 0x21, 0xd3, 0x95, 0x98, 0xcc, 0x54, 0xca,
-	0xc6, 0x63, 0x67, 0xe7, 0x8c, 0xc9, 0xb3, 0x55, 0x9c, 0x19, 0xc6, 0x9c,
-	0x14, 0x4b, 0xf6, 0xcb, 0x46, 0xae, 0x31, 0x6b, 0x3c, 0x7e, 0xb6, 0x0b,
-	0x34, 0xf2, 0xfc, 0x3d, 0x46, 0xf6, 0xf4, 0x2d, 0xc9, 0xda, 0x94, 0x71,
-	0xc2, 0xfc, 0x3c, 0xc4, 0x9e, 0x2d, 0x93, 0xe6, 0x56, 0x8f, 0x5e, 0xc7,
-	0x51, 0x69, 0xe7, 0x78, 0x36, 0x65, 0x99, 0x25, 0x21, 0x7d, 0x7a, 0xee,
-	0x82, 0x4b, 0xf3, 0x8a, 0x91, 0x3d, 0xdb, 0x61, 0xe4, 0xce, 0x84, 0x41,
-	0x87, 0xf4, 0x85, 0x84, 0xfb, 0x06, 0x62, 0x79, 0xa9, 0xe3, 0x0c, 0x31,
-	0x55, 0x9a, 0x72, 0x05, 0xcd, 0xa0, 0xe5, 0x9b, 0x15, 0xf0, 0x50, 0x01,
-	0x0f, 0x15, 0xf2, 0x16, 0x97, 0xf3, 0x43, 0x3e, 0x6f, 0x8e, 0xf3, 0x77,
-	0x36, 0x69, 0x4f, 0xc4, 0x33, 0xca, 0xe7, 0xd3, 0x71, 0xfe, 0xdd, 0x26,
-	0xaf, 0xe4, 0xc7, 0x71, 0x5e, 0xb1, 0x63, 0xa0, 0xdd, 0xb9, 0xa0, 0xac,
-	0x32, 0x78, 0xb1, 0x80, 0x9f, 0xb2, 0x9e, 0x03, 0x0f, 0xb3, 0xe0, 0x6f,
-	0x05, 0xbc, 0x55, 0x41, 0xc7, 0x4f, 0x3b, 0xaf, 0x68, 0xe4, 0x86, 0x36,
-	0xe4, 0x15, 0xa7, 0x8c, 0xf3, 0x4b, 0x0a, 0xb2, 0xde, 0x29, 0xf9, 0x05,
-	0x53, 0xa6, 0x96, 0xfc, 0xfd, 0xbe, 0x1d, 0x1c, 0x91, 0x83, 0x95, 0x1e,
-	0xc8, 0x86, 0xb2, 0x4c, 0xd8, 0x22, 0x0e, 0x64, 0x54, 0x4a, 0x2a, 0x11,
-	0x23, 0x6f, 0x1f, 0xd7, 0xfa, 0x5f, 0xb2, 0x24, 0x93, 0xb7, 0x29, 0x47,
-	0x89, 0xe7, 0xed, 0x62, 0x2c, 0x0c, 0x7b, 0x5b, 0xb2, 0x8a, 0x66, 0x58,
-	0x28, 0xc7, 0x44, 0xec, 0xf7, 0x21, 0xcb, 0x27, 0xcb, 0x92, 0xf9, 0x74,
-	0xd9, 0x97, 0xb1, 0x2b, 0xdf, 0xcf, 0x94, 0x3f, 0xd5, 0x29, 0xed, 0xea,
-	0x9e, 0x16, 0xf9, 0x0d, 0xec, 0x25, 0xee, 0x4d, 0x7b, 0xb1, 0xcf, 0x85,
-	0x73, 0xf7, 0x26, 0x9e, 0x10, 0x21, 0x6c, 0xa9, 0xbf, 0x45, 0xfb, 0x88,
-	0x18, 0x59, 0xab, 0x18, 0x0b, 0x01, 0x2e, 0x2f, 0xa5, 0x51, 0x6f, 0xae,
-	0x25, 0x6b, 0xdd, 0x0a, 0xcd, 0xd8, 0x89, 0x78, 0x49, 0x6e, 0x85, 0x2e,
-	0xdb, 0x7a, 0x6e, 0x47, 0xd6, 0x72, 0x64, 0x19, 0xd8, 0x9f, 0x83, 0x3f,
-	0x5c, 0x04, 0x47, 0x5f, 0x2a, 0xeb, 0xf9, 0x4e, 0xec, 0x4f, 0xb6, 0x00,
-	0x67, 0xbb, 0x24, 0x92, 0x35, 0xcc, 0x5f, 0x76, 0xe7, 0xbb, 0x5d, 0xbc,
-	0xa5, 0xfe, 0x76, 0x8d, 0x5b, 0xe4, 0x65, 0x77, 0xfe, 0x0e, 0x17, 0x77,
-	0xe9, 0x3e, 0xcc, 0x03, 0xff, 0xe0, 0xc4, 0x90, 0xa1, 0xe7, 0x7b, 0xe9,
-	0x4f, 0xbf, 0x5e, 0xbe, 0x15, 0x5a, 0xb6, 0x1d, 0xc9, 0x8d, 0x0e, 0x4e,
-	0x0c, 0x1a, 0x2e, 0xbe, 0x13, 0xee, 0xbe, 0xbb, 0x5d, 0x7c, 0x83, 0x13,
-	0x49, 0xc3, 0xc5, 0xb7, 0x54, 0xd6, 0x7b, 0x25, 0x5f, 0x26, 0xec, 0xe0,
-	0x84, 0x65, 0xdc, 0x2d, 0x53, 0xdd, 0x83, 0x13, 0x7b, 0x0d, 0x75, 0xcf,
-	0x4e, 0x97, 0x8f, 0x84, 0x4f, 0xc3, 0x4e, 0x4d, 0x03, 0xcf, 0xd5, 0xf3,
-	0x03, 0x59, 0xab, 0x74, 0xdf, 0x4e, 0x7d, 0x3e, 0xcf, 0xd4, 0x73, 0xf7,
-	0x91, 0x2e, 0x9e, 0x5d, 0x18, 0xdd, 0x74, 0xee, 0xcf, 0xdc, 0x96, 0xcf,
-	0x76, 0x67, 0xf2, 0x3c, 0x89, 0x84, 0xd3, 0xe1, 0xd1, 0x99, 0xf2, 0x11,
-	0xc9, 0x56, 0xe2, 0x32, 0x3d, 0xb2, 0x43, 0xa6, 0xcc, 0xfe, 0xa9, 0x83,
-	0xc2, 0xd8, 0x13, 0x19, 0x2d, 0x78, 0x3a, 0xcc, 0x89, 0x21, 0xd3, 0xe0,
-	0xf1, 0x60, 0x5d, 0x22, 0x06, 0xe0, 0xfb, 0xeb, 0x61, 0x79, 0xbe, 0x61,
-	0x48, 0xab, 0xf6, 0xcf, 0x84, 0xb9, 0x06, 0x3b, 0x7c, 0xb6, 0x42, 0x3b,
-	0xa6, 0xcd, 0x4a, 0xa6, 0x06, 0x3b, 0xbd, 0xa0, 0x7d, 0xb5, 0x9d, 0x7a,
-	0x2d, 0x16, 0x05, 0xae, 0x98, 0xb6, 0xcc, 0x9a, 0xb4, 0x49, 0x66, 0x52,
-	0x8a, 0x5c, 0xf7, 0x7c, 0x27, 0xb6, 0x28, 0xdf, 0x85, 0x0d, 0x88, 0x99,
-	0x4d, 0x71, 0x9e, 0xf0, 0x4d, 0xb0, 0xa6, 0xeb, 0x77, 0x21, 0xf8, 0x5d,
-	0x21, 0x45, 0x58, 0x29, 0xea, 0x58, 0xd1, 0x80, 0x2d, 0x36, 0xee, 0xee,
-	0x74, 0x63, 0x5d, 0x04, 0xfe, 0xd9, 0x01, 0x1f, 0xbf, 0x07, 0xfe, 0xd7,
-	0x67, 0x64, 0xcf, 0x38, 0x0e, 0x62, 0x4f, 0x54, 0x09, 0xfd, 0x0f, 0xbe,
-	0xde, 0xe0, 0x5a, 0x07, 0xe6, 0xc5, 0x9c, 0xb6, 0xbb, 0xc1, 0x9f, 0xe3,
-	0x4c, 0xd8, 0x71, 0x29, 0xd9, 0xbb, 0xb0, 0xaf, 0x45, 0xba, 0x2d, 0xda,
-	0x3b, 0x7d, 0x7a, 0x27, 0xce, 0x33, 0xf8, 0xdd, 0x85, 0xf3, 0x3a, 0x31,
-	0x17, 0x9b, 0xa6, 0x1f, 0xa7, 0x18, 0xb3, 0xdc, 0xf8, 0x29, 0x72, 0x15,
-	0xb4, 0x72, 0x8f, 0x86, 0x8b, 0xb4, 0xa5, 0x53, 0x72, 0xa3, 0xdc, 0x2b,
-	0x57, 0xa2, 0xe4, 0x1f, 0x38, 0x2b, 0x88, 0x87, 0x51, 0x03, 0xf4, 0x93,
-	0x6e, 0xc6, 0xbf, 0xdd, 0xde, 0xb7, 0x71, 0xaf, 0x7b, 0x86, 0x98, 0xa1,
-	0x74, 0x97, 0xe4, 0xf4, 0x9c, 0x28, 0x35, 0xba, 0xd3, 0x5b, 0xef, 0x32,
-	0x0e, 0x9c, 0x51, 0x32, 0xf4, 0x20, 0x62, 0x16, 0xce, 0xba, 0x6c, 0x39,
-	0xce, 0x65, 0xfb, 0xc7, 0xf0, 0x79, 0x25, 0x2d, 0xd6, 0x7a, 0x97, 0xb4,
-	0x43, 0x9e, 0x15, 0xa3, 0x49, 0x86, 0x31, 0x39, 0x51, 0xe1, 0x9e, 0xa2,
-	0x84, 0x2d, 0xc2, 0x10, 0xfe, 0x47, 0x80, 0x0b, 0x49, 0x1b, 0x7c, 0xf1,
-	0xa2, 0x1d, 0x25, 0xbd, 0xbb, 0x5c, 0xf8, 0x6e, 0x9c, 0x41, 0xda, 0xe9,
-	0x7b, 0x8e, 0xf6, 0xbd, 0x6c, 0x48, 0x65, 0xc6, 0xe7, 0xe1, 0x49, 0x23,
-	0x94, 0x77, 0xb6, 0x1b, 0xa1, 0x5f, 0xa6, 0x87, 0x8a, 0xa6, 0xd2, 0xba,
-	0x16, 0xc9, 0x95, 0xef, 0x95, 0x19, 0x1b, 0xe7, 0x59, 0x61, 0xd0, 0xcc,
-	0x38, 0x33, 0x50, 0x0c, 0x29, 0x78, 0x58, 0x0f, 0x65, 0xe5, 0xd3, 0xfa,
-	0x16, 0xce, 0x2b, 0x1a, 0x61, 0x8b, 0x67, 0xfc, 0xb2, 0x27, 0x1f, 0xda,
-	0x9d, 0x2d, 0xd9, 0x72, 0x07, 0xbf, 0x41, 0x47, 0xbb, 0xa6, 0x23, 0x94,
-	0xd6, 0xba, 0x33, 0x54, 0xda, 0x8f, 0xff, 0x04, 0xdd, 0x84, 0x07, 0x7c,
-	0x70, 0xaf, 0x85, 0xbd, 0x11, 0xd0, 0xd8, 0xd9, 0x44, 0x7f, 0x3b, 0xe1,
-	0x21, 0xab, 0x88, 0x77, 0x86, 0xe6, 0xdb, 0x70, 0xf9, 0xf6, 0x65, 0xf5,
-	0x2a, 0x64, 0xf5, 0xbe, 0x33, 0xb4, 0x8f, 0x38, 0x52, 0xc0, 0x01, 0xb9,
-	0x9b, 0x8c, 0x57, 0x8c, 0x51, 0xe6, 0x06, 0x2e, 0xf8, 0x81, 0x0a, 0xa5,
-	0x3b, 0x24, 0x67, 0xea, 0x1c, 0x00, 0xd8, 0x31, 0xd1, 0x31, 0xde, 0x22,
-	0x8f, 0xde, 0xb7, 0x95, 0xd0, 0x76, 0x93, 0xaf, 0x32, 0x0f, 0xfc, 0x31,
-	0x68, 0x5b, 0x4b, 0x28, 0xcd, 0x5a, 0x07, 0x64, 0x2e, 0x91, 0x96, 0xf4,
-	0x1b, 0xb2, 0x5c, 0x56, 0x7b, 0x5a, 0x65, 0x97, 0x4c, 0x42, 0x46, 0xb5,
-	0x31, 0xe4, 0xaf, 0x91, 0x0e, 0x09, 0xdd, 0xcf, 0x3c, 0x10, 0x03, 0xad,
-	0x6b, 0x09, 0x53, 0x6e, 0x39, 0x6a, 0x10, 0xfb, 0x47, 0xa0, 0x87, 0x43,
-	0xd4, 0xa9, 0xf2, 0xe0, 0x08, 0x13, 0xa2, 0xcc, 0x7b, 0x5a, 0x85, 0xb8,
-	0xb9, 0x36, 0x1c, 0x33, 0x85, 0xf3, 0xc8, 0x95, 0x93, 0xdc, 0x4b, 0xfe,
-	0xdc, 0x3d, 0x1f, 0xe6, 0xcf, 0x5f, 0xa7, 0xcc, 0x28, 0x3b, 0xd8, 0x18,
-	0x78, 0xcc, 0xda, 0xbf, 0xe0, 0xc9, 0xe6, 0x4e, 0xb9, 0x62, 0x8a, 0x51,
-	0xb3, 0xef, 0x68, 0x92, 0x1f, 0x79, 0xee, 0xde, 0xc2, 0x33, 0x71, 0x6c,
-	0xcf, 0xf7, 0xe1, 0x2a, 0xcf, 0x74, 0xcf, 0x9e, 0xb1, 0xd6, 0x12, 0x61,
-	0xd9, 0x2c, 0x5f, 0xe8, 0x52, 0x0a, 0x65, 0xda, 0x46, 0xab, 0xe4, 0x51,
-	0x8f, 0xd8, 0xfb, 0x10, 0x54, 0x1e, 0x57, 0x32, 0xfa, 0x20, 0x71, 0xfe,
-	0x23, 0x79, 0x1a, 0x8b, 0x2b, 0x43, 0xf2, 0x3a, 0xf7, 0xfb, 0xfa, 0xe2,
-	0x5c, 0xb3, 0x6d, 0xbf, 0xea, 0xd9, 0xf6, 0xfb, 0xce, 0xe8, 0x3e, 0x5f,
-	0xef, 0x90, 0xd7, 0x87, 0xf6, 0x08, 0xf4, 0xfc, 0x7f, 0xed, 0xa1, 0xad,
-	0x44, 0xb6, 0xec, 0x29, 0x6e, 0xb3, 0x67, 0xb7, 0xc8, 0x2f, 0xd1, 0x87,
-	0xba, 0xbd, 0x98, 0xe1, 0xfb, 0x94, 0x8f, 0x07, 0xba, 0xd1, 0xb6, 0xca,
-	0xb9, 0xed, 0x7c, 0x91, 0x38, 0x88, 0x8b, 0x7b, 0x09, 0xe3, 0xe7, 0x54,
-	0xa8, 0x43, 0xb6, 0xcd, 0xab, 0x18, 0x13, 0x78, 0x57, 0x88, 0x43, 0xcd,
-	0xf9, 0x95, 0x73, 0x26, 0xbe, 0xc7, 0xf1, 0xb4, 0x24, 0x5f, 0xa7, 0x3f,
-	0x71, 0x3f, 0xf3, 0xed, 0x4d, 0x2f, 0x7e, 0x76, 0x4c, 0x85, 0xd3, 0x51,
-	0xc4, 0x4f, 0x99, 0x2c, 0x95, 0x8f, 0xa3, 0x26, 0x92, 0xe2, 0x5d, 0x69,
-	0xda, 0x47, 0xc7, 0x18, 0x62, 0xe4, 0x64, 0xa9, 0xce, 0xba, 0x08, 0x61,
-	0x0c, 0xfb, 0x90, 0xa3, 0x23, 0x6a, 0x2e, 0x52, 0xfc, 0x58, 0x9a, 0x71,
-	0x39, 0x2e, 0xf1, 0xfa, 0x3b, 0xa8, 0x3b, 0x4c, 0xc9, 0x6a, 0x5b, 0xfb,
-	0xb3, 0x5e, 0xd2, 0x5b, 0x42, 0x0d, 0x11, 0x4e, 0x4b, 0x58, 0xa5, 0x5b,
-	0x23, 0xd3, 0xa9, 0x0e, 0xd4, 0x5a, 0x13, 0xbd, 0x6a, 0xf5, 0x60, 0x6f,
-	0x68, 0x75, 0xcf, 0x54, 0x4b, 0xba, 0xd8, 0xab, 0xe6, 0x44, 0x16, 0xcb,
-	0xa2, 0x50, 0xd7, 0xc4, 0x0e, 0x0b, 0xbe, 0x57, 0x3f, 0xfb, 0x59, 0x95,
-	0x0e, 0x41, 0xb7, 0x72, 0x6c, 0x29, 0x15, 0x66, 0x0d, 0x19, 0x9f, 0x94,
-	0x63, 0xa8, 0x1b, 0x9f, 0x91, 0xe9, 0x32, 0xe8, 0xd2, 0x7c, 0xc7, 0xc0,
-	0x6f, 0x1f, 0x70, 0x93, 0xf6, 0x28, 0x62, 0xac, 0x4b, 0x3b, 0x68, 0xce,
-	0xe4, 0x58, 0x27, 0xa5, 0x98, 0x57, 0xde, 0x81, 0xfd, 0xd0, 0x5f, 0xfe,
-	0x59, 0x96, 0xad, 0x1d, 0x92, 0x77, 0xe3, 0x03, 0xed, 0x15, 0x6b, 0x37,
-	0xbd, 0xb5, 0x6b, 0x58, 0xa3, 0xfd, 0xee, 0x6c, 0xd2, 0xe1, 0x97, 0x75,
-	0xad, 0x73, 0xd9, 0xe6, 0x3b, 0x61, 0xff, 0x76, 0xd4, 0x85, 0x7d, 0x7d,
-	0x74, 0xd9, 0xfa, 0xdc, 0x2e, 0x69, 0x37, 0xa9, 0x37, 0x9c, 0x13, 0x65,
-	0x8c, 0xc5, 0xfa, 0x15, 0x0f, 0xd7, 0x5b, 0xc0, 0xd5, 0x41, 0xba, 0x31,
-	0xc2, 0x58, 0x07, 0x7d, 0xa8, 0x79, 0xf2, 0x1b, 0xb1, 0x86, 0xb0, 0xdf,
-	0xf1, 0x70, 0x7d, 0xab, 0x09, 0x17, 0xd7, 0xf8, 0xe4, 0x99, 0x38, 0xbb,
-	0x9d, 0xbc, 0x91, 0x1f, 0xea, 0x80, 0xfa, 0x48, 0x1a, 0x93, 0x88, 0xed,
-	0x93, 0x0d, 0x5d, 0xdb, 0x19, 0xb9, 0x0a, 0x6a, 0xae, 0xc6, 0x8b, 0xa0,
-	0x11, 0xb5, 0x58, 0x63, 0xd0, 0xab, 0xb7, 0x69, 0x47, 0x6b, 0xda, 0x1e,
-	0x19, 0x77, 0x4a, 0xda, 0xae, 0x2e, 0xb9, 0x76, 0x65, 0x51, 0x37, 0x97,
-	0x64, 0x6f, 0xbd, 0xba, 0xcb, 0xfd, 0xbf, 0xdb, 0xa6, 0x84, 0xb4, 0x3e,
-	0x99, 0xdf, 0x68, 0x63, 0x77, 0x22, 0xae, 0x3b, 0xef, 0x32, 0xcf, 0x4c,
-	0x32, 0x07, 0x4d, 0x32, 0x77, 0x18, 0x5e, 0x3c, 0x8c, 0x37, 0xe1, 0x88,
-	0x03, 0xc7, 0x8a, 0x67, 0xbf, 0x73, 0x1e, 0x2e, 0xbf, 0xfe, 0xf4, 0x63,
-	0xea, 0x9f, 0xdf, 0xb5, 0x79, 0x5d, 0x99, 0xee, 0x77, 0xab, 0x8e, 0xc7,
-	0xb0, 0x75, 0xd0, 0x1f, 0x9f, 0x52, 0xb0, 0xaf, 0x5c, 0xdd, 0xd5, 0x07,
-	0x7c, 0x1f, 0xb6, 0xc7, 0x57, 0x5f, 0xb7, 0x6e, 0xfd, 0xed, 0xca, 0x80,
-	0x3a, 0xcd, 0x90, 0xef, 0x4c, 0x98, 0xb4, 0x34, 0x26, 0xb0, 0x5f, 0x8e,
-	0x30, 0x37, 0xe6, 0xc1, 0xc7, 0x61, 0x73, 0xd8, 0x9c, 0x26, 0xee, 0xa8,
-	0x00, 0x27, 0x6a, 0xc9, 0x74, 0x9b, 0xa7, 0xe7, 0x6f, 0xf3, 0x7c, 0xe0,
-	0xde, 0xc9, 0x6f, 0x3c, 0xbf, 0xed, 0xd1, 0x73, 0xa3, 0xcb, 0xa5, 0xc7,
-	0x5f, 0x1f, 0x34, 0x37, 0x7f, 0xaf, 0xf4, 0x7a, 0xf2, 0xc4, 0xfb, 0x33,
-	0x1e, 0x5d, 0xd4, 0x4d, 0x33, 0x4d, 0xd4, 0xcb, 0xbb, 0xc0, 0xa3, 0x6b,
-	0x8d, 0xa2, 0x4a, 0xa3, 0x76, 0x49, 0x31, 0x67, 0x25, 0xc6, 0x32, 0x62,
-	0x41, 0x27, 0x09, 0x7b, 0x0a, 0xbb, 0x6e, 0x96, 0xa9, 0xe7, 0x5b, 0x88,
-	0xd5, 0xd4, 0xfb, 0x7b, 0x32, 0x53, 0xee, 0xb7, 0x5b, 0x0d, 0xfa, 0x6b,
-	0x22, 0xb9, 0x22, 0xc3, 0xf6, 0x8a, 0xae, 0xa1, 0x12, 0xf1, 0x13, 0x42,
-	0xd9, 0xde, 0x92, 0x01, 0x5d, 0xdb, 0xbc, 0x27, 0x16, 0xe4, 0x32, 0x59,
-	0x81, 0x8f, 0xed, 0xfb, 0x57, 0x47, 0xd7, 0xa4, 0x08, 0x6f, 0xd7, 0xb7,
-	0xc1, 0xf5, 0xba, 0xc6, 0x43, 0x7c, 0xcd, 0xb8, 0x0c, 0x69, 0xdb, 0xe7,
-	0xe3, 0xb3, 0x64, 0xb6, 0xe1, 0xe3, 0x0c, 0x23, 0x2e, 0x23, 0x06, 0xec,
-	0xfb, 0xbc, 0x67, 0x2f, 0x7c, 0xff, 0xbe, 0xc3, 0x5a, 0x48, 0xa5, 0xbf,
-	0xea, 0xcd, 0x7d, 0x8f, 0x32, 0xc0, 0xb7, 0x2f, 0xf7, 0x17, 0xbd, 0x78,
-	0x53, 0x34, 0x32, 0x0d, 0xca, 0x80, 0xb6, 0x02, 0xfd, 0x6b, 0xfb, 0x84,
-	0xcf, 0x54, 0x3e, 0x89, 0x98, 0xd5, 0xed, 0xd6, 0x0f, 0xe8, 0xaf, 0x32,
-	0x0d, 0xce, 0xad, 0xb5, 0x65, 0xed, 0x16, 0xcf, 0x97, 0x0e, 0x62, 0x6e,
-	0x12, 0x7f, 0x94, 0x1d, 0x61, 0x0e, 0xe1, 0x3d, 0xe3, 0xc1, 0xc9, 0x58,
-	0x16, 0xb9, 0x2b, 0x73, 0x68, 0x1c, 0xdf, 0x86, 0xd7, 0x67, 0x69, 0xb9,
-	0x57, 0x51, 0xab, 0x40, 0x9e, 0x03, 0xe0, 0x27, 0x2e, 0xe3, 0x0d, 0xe8,
-	0x7c, 0x23, 0x9e, 0x6d, 0xc0, 0x14, 0x6f, 0xc3, 0xb8, 0xb1, 0x6f, 0xbc,
-	0xf1, 0xa6, 0xc3, 0x78, 0xf0, 0x57, 0xda, 0x5f, 0xe2, 0xa0, 0xdd, 0xef,
-	0xd5, 0x32, 0xc6, 0x63, 0x95, 0x09, 0xe3, 0xf1, 0x0a, 0xf7, 0xa8, 0xaf,
-	0xf5, 0x88, 0x15, 0xcf, 0x2a, 0xd4, 0xa9, 0xfb, 0xba, 0x70, 0xe6, 0x09,
-	0xd8, 0x46, 0xd1, 0x98, 0x1c, 0xda, 0x25, 0xf9, 0x64, 0x0f, 0x68, 0x7e,
-	0x08, 0xcf, 0x56, 0xcc, 0xff, 0x3c, 0xe6, 0x61, 0x47, 0x49, 0xfa, 0xc7,
-	0x0e, 0xdd, 0x5b, 0x4e, 0x99, 0xa4, 0x71, 0xc0, 0xb3, 0xad, 0x37, 0x4d,
-	0xd7, 0x96, 0x9e, 0xc6, 0xf7, 0x4e, 0xcc, 0x7f, 0x01, 0x4f, 0xe4, 0xb2,
-	0x7d, 0xfe, 0x3c, 0x7d, 0x70, 0x0c, 0xf3, 0x0f, 0x00, 0xc7, 0x1f, 0xe0,
-	0xfd, 0x5e, 0xbc, 0xff, 0xde, 0x96, 0xbd, 0xbf, 0xcb, 0xb3, 0x31, 0x9f,
-	0xdd, 0x32, 0xef, 0xc7, 0x6f, 0x9e, 0x27, 0xd2, 0xbd, 0x0a, 0xc6, 0x57,
-	0x23, 0xb2, 0x7b, 0xa5, 0x5d, 0x54, 0xcd, 0x8d, 0xe1, 0xaa, 0x66, 0x4a,
-	0xcf, 0x0a, 0xe3, 0xf7, 0x0f, 0xb0, 0xc7, 0x12, 0xb5, 0x0a, 0xa5, 0x51,
-	0xb7, 0xda, 0x47, 0x9f, 0x39, 0xba, 0x77, 0x81, 0xcf, 0xe2, 0xd1, 0xd1,
-	0x3a, 0x61, 0xf8, 0x7e, 0xec, 0xe8, 0xde, 0xfa, 0x3f, 0x00, 0x16, 0x72,
-	0xa9, 0xf8, 0xf8, 0x09, 0x7f, 0x7e, 0xcb, 0x99, 0x5a, 0xb6, 0x38, 0x93,
-	0x7e, 0xff, 0xcc, 0xd1, 0x6c, 0x95, 0x75, 0x42, 0x22, 0x26, 0xba, 0x16,
-	0x2f, 0x1e, 0x2d, 0x20, 0x3f, 0x86, 0x34, 0x2d, 0xfe, 0x3a, 0xd7, 0xa8,
-	0x87, 0xed, 0x68, 0x23, 0x5d, 0xcd, 0x78, 0x98, 0x67, 0x88, 0xe7, 0x18,
-	0xf0, 0x24, 0x81, 0x87, 0xf9, 0xc6, 0xa5, 0x37, 0xbe, 0xb0, 0x1d, 0x6d,
-	0xc4, 0xc5, 0xb3, 0x7c, 0x7c, 0x3d, 0xa2, 0x56, 0x7e, 0x48, 0x7a, 0x4d,
-	0xd6, 0xb6, 0x6e, 0xac, 0x69, 0x91, 0xfc, 0x69, 0xe6, 0xec, 0x7d, 0xde,
-	0x37, 0xca, 0x18, 0xf4, 0xdc, 0x71, 0xc5, 0x79, 0x3e, 0xb1, 0x96, 0x62,
-	0xb9, 0x82, 0xef, 0x45, 0x1f, 0x56, 0x79, 0xb0, 0x9d, 0x4d, 0x7c, 0xb7,
-	0x78, 0xb2, 0xe6, 0x99, 0x7e, 0xef, 0xd9, 0x4c, 0x0b, 0x40, 0xa1, 0x87,
-	0xee, 0x0d, 0x3d, 0xf8, 0x7c, 0x62, 0x61, 0x95, 0xb4, 0x25, 0xc1, 0xab,
-	0x4f, 0xdb, 0x47, 0xd5, 0x1f, 0xf7, 0x26, 0xf1, 0xe7, 0x9f, 0xe7, 0xcb,
-	0x80, 0x74, 0xf1, 0x09, 0x5b, 0xfe, 0x50, 0xef, 0x9c, 0x84, 0xdf, 0xf1,
-	0x1e, 0xc4, 0x71, 0x96, 0x6d, 0xca, 0xbe, 0x0d, 0x7a, 0x27, 0x2f, 0x06,
-	0x7a, 0x09, 0xc5, 0x9a, 0x2e, 0xce, 0x9e, 0xf5, 0x49, 0xb9, 0x0a, 0x5c,
-	0x19, 0xf4, 0x95, 0x6e, 0x6f, 0x34, 0x85, 0xf8, 0xb8, 0x06, 0xfb, 0xbc,
-	0x6c, 0xf1, 0x3e, 0x26, 0xcc, 0x7c, 0x27, 0xa5, 0xfa, 0xbf, 0x00, 0x86,
-	0xf5, 0xd5, 0xed, 0xbb, 0x96, 0x05, 0xc0, 0x2c, 0x62, 0xed, 0x84, 0x1b,
-	0x97, 0x19, 0xdb, 0x1d, 0x85, 0xda, 0xa3, 0x60, 0xfd, 0xb7, 0xc3, 0x3a,
-	0xeb, 0x36, 0xec, 0x76, 0x77, 0x21, 0xc8, 0x39, 0xf3, 0x89, 0xd9, 0x05,
-	0xc4, 0xf0, 0xaa, 0xa5, 0x76, 0x2b, 0x6d, 0x91, 0x89, 0x2a, 0x62, 0x12,
-	0xba, 0xde, 0x44, 0x7c, 0x41, 0xfe, 0x53, 0xeb, 0xa1, 0xc5, 0x1a, 0x36,
-	0x7b, 0xd4, 0xe7, 0x68, 0x57, 0x9a, 0xf2, 0xd0, 0x29, 0xe4, 0xe5, 0x91,
-	0xc7, 0x90, 0x73, 0x20, 0xaf, 0x53, 0x45, 0x74, 0xf2, 0xb4, 0x91, 0x37,
-	0x7e, 0xab, 0x60, 0xb9, 0x7d, 0x80, 0xce, 0x67, 0xe2, 0xf2, 0x18, 0x3a,
-	0xd5, 0xa1, 0xe3, 0x4c, 0x5e, 0xc7, 0x9b, 0x7e, 0x73, 0x52, 0xb5, 0xa3,
-	0xc6, 0x40, 0x01, 0x8a, 0x0a, 0xc7, 0x1c, 0x14, 0xd9, 0x3b, 0x87, 0xb8,
-	0x82, 0x38, 0xbc, 0x77, 0x15, 0xd1, 0xed, 0x14, 0xe1, 0x95, 0x84, 0x4f,
-	0x85, 0xa4, 0xe5, 0x14, 0xef, 0x43, 0x64, 0x0f, 0xfa, 0x31, 0xe2, 0xdc,
-	0x1b, 0xc6, 0x73, 0x1c, 0x7f, 0xfb, 0x51, 0x5b, 0x99, 0xa8, 0x91, 0xb7,
-	0x81, 0x07, 0x2c, 0xf7, 0x6c, 0x07, 0x6f, 0x76, 0x4b, 0x7b, 0x04, 0x7b,
-	0x08, 0x1f, 0x06, 0x1d, 0x7b, 0x40, 0x8f, 0x7b, 0x3e, 0x71, 0x84, 0x4f,
-	0x89, 0xf4, 0xcf, 0x49, 0x8f, 0xd2, 0x7b, 0xc2, 0x52, 0x48, 0x71, 0xad,
-	0x03, 0xf0, 0xdc, 0x87, 0x35, 0xbd, 0xcf, 0xbd, 0x57, 0xca, 0xdf, 0xa6,
-	0x1b, 0x73, 0x06, 0xde, 0x51, 0x4f, 0xa5, 0x4c, 0xe9, 0xaf, 0xb9, 0xb0,
-	0x7b, 0x57, 0xbf, 0xd4, 0xcd, 0xbb, 0x29, 0x65, 0xb9, 0xb4, 0x29, 0xd4,
-	0xc4, 0x79, 0x48, 0x35, 0x3c, 0xc8, 0xfb, 0x19, 0xc2, 0xb0, 0xaf, 0x35,
-	0x35, 0x8c, 0x39, 0x48, 0xf9, 0xb9, 0x73, 0x4a, 0xfd, 0x6f, 0xf7, 0x2e,
-	0xcd, 0x35, 0x85, 0xf6, 0x15, 0xec, 0xff, 0x43, 0xed, 0x2b, 0xa2, 0xe2,
-	0x9e, 0xaf, 0xe0, 0x7b, 0x91, 0xdf, 0x7e, 0x2e, 0xfe, 0xed, 0xbb, 0xdc,
-	0x78, 0xef, 0xc8, 0xb4, 0xcd, 0x3b, 0x0c, 0x47, 0x2e, 0xdb, 0x45, 0xe3,
-	0x91, 0x4d, 0x75, 0x66, 0x52, 0xe7, 0xe7, 0x02, 0x64, 0xbf, 0x5e, 0xd7,
-	0x3d, 0x9b, 0x5c, 0xa9, 0x47, 0xe4, 0xea, 0x52, 0xbb, 0xac, 0x2f, 0xb8,
-	0x36, 0xbf, 0xbe, 0x40, 0x3b, 0x37, 0xe5, 0xed, 0x25, 0x0b, 0x6b, 0x49,
-	0xfc, 0xf5, 0xc8, 0xf5, 0xa5, 0xcd, 0x75, 0xe7, 0x85, 0xc6, 0xc3, 0xa0,
-	0xa5, 0x47, 0x42, 0x96, 0xa3, 0xfb, 0xaf, 0x1c, 0x72, 0x5f, 0x51, 0xc6,
-	0x25, 0x5f, 0xe9, 0x47, 0x0f, 0x88, 0xe4, 0x1c, 0x66, 0x0e, 0x82, 0xfe,
-	0x2b, 0x9f, 0x40, 0x6d, 0x92, 0x80, 0xf3, 0xf4, 0xeb, 0x7b, 0xc5, 0x4f,
-	0x85, 0x7b, 0xa4, 0xd5, 0xfa, 0xa3, 0x6e, 0x37, 0x57, 0x99, 0x6e, 0x9f,
-	0x6a, 0xf9, 0xf9, 0xfa, 0x75, 0xe0, 0x1e, 0x81, 0x9d, 0xd2, 0x36, 0x6d,
-	0xd8, 0xac, 0x29, 0xcb, 0x43, 0x89, 0x6a, 0x51, 0x18, 0x1f, 0x52, 0x38,
-	0xd3, 0xc0, 0xbe, 0x24, 0xe4, 0xb1, 0x43, 0xd7, 0x42, 0x19, 0x05, 0xdd,
-	0xce, 0xcd, 0x48, 0xbe, 0xf1, 0x9b, 0x98, 0xcf, 0xc8, 0x54, 0x63, 0x0c,
-	0x67, 0x9d, 0xa4, 0xdd, 0xf6, 0x48, 0x3b, 0xcf, 0x49, 0x81, 0xc6, 0x87,
-	0xa4, 0x70, 0x7a, 0x46, 0x0e, 0x57, 0x48, 0x27, 0xef, 0x19, 0x13, 0xc9,
-	0x9c, 0x0c, 0xc7, 0x97, 0x50, 0x3b, 0xb9, 0xfe, 0x98, 0x96, 0xc2, 0x19,
-	0xe0, 0xa8, 0xf0, 0x1e, 0xa0, 0x1f, 0x76, 0x33, 0xac, 0xfb, 0x9a, 0x29,
-	0x1d, 0x77, 0x38, 0xff, 0x43, 0xe8, 0xa9, 0xbf, 0xb8, 0x1f, 0x70, 0x79,
-	0xf4, 0x40, 0x93, 0xa8, 0x97, 0x17, 0x2b, 0xe8, 0xf7, 0xec, 0x10, 0x6b,
-	0x2f, 0xa5, 0xee, 0xef, 0x93, 0x5a, 0x65, 0xd8, 0x54, 0x8a, 0x35, 0x15,
-	0x75, 0xc1, 0x35, 0xfa, 0x77, 0x4c, 0x85, 0xad, 0x3e, 0x59, 0xaa, 0x14,
-	0xd1, 0x37, 0x2b, 0xef, 0x5e, 0x03, 0x16, 0x60, 0xb9, 0x71, 0x2f, 0xa3,
-	0xc8, 0x37, 0xea, 0xcf, 0xc6, 0x27, 0x41, 0x63, 0x26, 0x6e, 0xca, 0x71,
-	0xd0, 0x87, 0xf7, 0x45, 0xd8, 0xf8, 0x1c, 0x6b, 0xb8, 0x0c, 0xd6, 0xd2,
-	0x72, 0xe4, 0xec, 0x24, 0x68, 0xe8, 0x92, 0xfe, 0x3f, 0xa1, 0x8f, 0x3d,
-	0x81, 0x39, 0x7e, 0x27, 0x60, 0xaf, 0x5f, 0xc4, 0x3b, 0x61, 0x63, 0x78,
-	0x52, 0x0e, 0x7d, 0x78, 0x9a, 0xa0, 0x25, 0xe2, 0xf6, 0x26, 0x87, 0xe2,
-	0x52, 0x3b, 0xfd, 0xa0, 0x4c, 0x2d, 0x3e, 0x08, 0xfc, 0x3f, 0x42, 0x5f,
-	0x80, 0xfc, 0xb6, 0xc8, 0xb3, 0x58, 0xff, 0xf1, 0x9c, 0x9d, 0x3d, 0xda,
-	0x37, 0xe6, 0x38, 0xcf, 0xe7, 0x41, 0xec, 0x47, 0x8f, 0x51, 0xc9, 0x48,
-	0xa1, 0xc2, 0xb3, 0xa0, 0x3b, 0xd4, 0x53, 0xf9, 0xd3, 0x93, 0x9e, 0x8e,
-	0x7b, 0x24, 0x17, 0x2d, 0xb2, 0xbf, 0x40, 0x9e, 0x58, 0x18, 0xcd, 0x96,
-	0x13, 0x66, 0x56, 0x11, 0x57, 0x52, 0x98, 0x1b, 0xdc, 0xb9, 0x88, 0x58,
-	0x73, 0xe8, 0x6d, 0xd3, 0x5c, 0x3b, 0xee, 0xdd, 0x1d, 0x10, 0xd7, 0x9b,
-	0x32, 0x0e, 0x1b, 0xeb, 0x9f, 0x1b, 0x41, 0x2d, 0xfc, 0x16, 0x6a, 0xc9,
-	0x84, 0x27, 0x83, 0x31, 0xcf, 0x36, 0xda, 0x9b, 0x6c, 0x02, 0x7a, 0xae,
-	0x40, 0xf7, 0x15, 0xd8, 0x01, 0x62, 0xf5, 0x2b, 0x1b, 0xf6, 0x31, 0xd6,
-	0x54, 0x63, 0x76, 0xca, 0xdf, 0x54, 0x13, 0xc9, 0x35, 0xd8, 0xcf, 0x75,
-	0xf4, 0x02, 0x6b, 0xe8, 0x55, 0xd7, 0xd1, 0xd7, 0x2d, 0x96, 0x0f, 0x81,
-	0x7e, 0xd6, 0x94, 0xfc, 0x8e, 0xe9, 0x5a, 0xa7, 0xcd, 0x7a, 0xe1, 0x2e,
-	0x7d, 0xb7, 0x2b, 0x4f, 0xf4, 0xb0, 0xd7, 0x64, 0x5f, 0xce, 0x7b, 0xe9,
-	0xab, 0xd0, 0xe3, 0x9a, 0xc9, 0x75, 0x7f, 0x1f, 0x7b, 0x01, 0xdf, 0x7e,
-	0x48, 0x0b, 0xed, 0x87, 0x7b, 0x08, 0xd3, 0xa3, 0xfd, 0x24, 0xaf, 0xf1,
-	0xd1, 0x66, 0xeb, 0xdd, 0xae, 0x9f, 0xe9, 0x3a, 0xcb, 0xbc, 0x22, 0xbe,
-	0xfd, 0xbe, 0xe7, 0xb0, 0xaf, 0xcb, 0x0e, 0x21, 0x76, 0x37, 0x1c, 0x79,
-	0xc1, 0xde, 0xec, 0x77, 0x07, 0x2a, 0xbe, 0x9c, 0x28, 0xc7, 0x43, 0x72,
-	0xa2, 0x91, 0x80, 0x4f, 0x50, 0x86, 0x56, 0x93, 0x0c, 0x45, 0xbe, 0x5e,
-	0x11, 0x79, 0xb9, 0xc2, 0x35, 0x2d, 0xc3, 0x58, 0x36, 0xd4, 0xce, 0xbb,
-	0x75, 0xd8, 0xe5, 0xdf, 0xcb, 0xe1, 0x79, 0x91, 0xb3, 0x58, 0x5f, 0xae,
-	0xd0, 0x57, 0x47, 0x50, 0xbf, 0xee, 0x94, 0xda, 0x02, 0x7a, 0xb2, 0x8a,
-	0x4c, 0x65, 0x1f, 0x60, 0xbe, 0x89, 0xc8, 0xba, 0xbe, 0x93, 0x15, 0x19,
-	0x3c, 0x17, 0x96, 0xf0, 0x39, 0x34, 0x7f, 0x90, 0xfd, 0xf9, 0x21, 0xff,
-	0x8e, 0xd6, 0xf5, 0xf9, 0x52, 0x19, 0x7b, 0x2b, 0xfd, 0x3a, 0x4e, 0x96,
-	0xea, 0x05, 0xc9, 0x57, 0x79, 0x16, 0x9e, 0x0b, 0x71, 0xac, 0xa5, 0x64,
-	0xfa, 0xf4, 0x88, 0x3c, 0x8b, 0x33, 0xd0, 0xff, 0xe1, 0x8c, 0x71, 0x29,
-	0x9e, 0xc5, 0x7c, 0xfd, 0x9a, 0x2c, 0x2c, 0x15, 0xa4, 0x56, 0xbd, 0xd0,
-	0x74, 0xf7, 0x8e, 0xef, 0x85, 0xe6, 0x5e, 0xf6, 0x10, 0xfb, 0x19, 0xf4,
-	0xaa, 0x16, 0xbe, 0x21, 0xb3, 0xfa, 0xf4, 0xd4, 0xe6, 0x3b, 0xe3, 0xe6,
-	0x1e, 0x76, 0x42, 0x66, 0x2b, 0x29, 0x29, 0x9d, 0x1e, 0xd1, 0x77, 0x0d,
-	0x6d, 0xe9, 0xea, 0xd3, 0x37, 0x90, 0x2b, 0x26, 0xf4, 0x9d, 0xf1, 0x2d,
-	0x79, 0xd4, 0x9e, 0x95, 0x27, 0xad, 0x83, 0x72, 0x02, 0xf5, 0xf5, 0xa7,
-	0xd1, 0xeb, 0xc7, 0xbb, 0xa9, 0x47, 0xd0, 0x6b, 0xb1, 0x07, 0x75, 0x64,
-	0xdc, 0xfe, 0xb8, 0xf9, 0x3c, 0x24, 0x7b, 0xb5, 0xce, 0x3c, 0xf9, 0x5f,
-	0x4e, 0x06, 0x79, 0xef, 0x06, 0x7a, 0xc7, 0x8c, 0x86, 0x33, 0x5c, 0xb8,
-	0x2a, 0xe1, 0x86, 0xcd, 0x17, 0x08, 0xb7, 0x60, 0x78, 0x70, 0x06, 0xe0,
-	0x42, 0x72, 0xd1, 0x0e, 0xc3, 0x46, 0x26, 0xc0, 0x27, 0x62, 0xfc, 0x68,
-	0xa7, 0x57, 0x07, 0xef, 0x40, 0x6e, 0xbd, 0xbd, 0xff, 0x35, 0x6f, 0xff,
-	0xb3, 0xde, 0xfe, 0xcb, 0x1b, 0xfb, 0xfd, 0xfc, 0xfa, 0x13, 0x47, 0x9a,
-	0xe8, 0x7a, 0xad, 0xec, 0xc2, 0xcf, 0x7a, 0x74, 0x5d, 0xde, 0xa0, 0xcb,
-	0x87, 0x87, 0x3c, 0x35, 0xcf, 0x8c, 0xcd, 0x8c, 0xd1, 0xfd, 0x90, 0xa3,
-	0x23, 0x39, 0x1b, 0xbe, 0x51, 0x49, 0x8c, 0x15, 0xf5, 0x9d, 0x9a, 0x92,
-	0xb5, 0xe8, 0xac, 0x4c, 0x58, 0x89, 0xb1, 0x69, 0x09, 0xc1, 0x96, 0x19,
-	0x5b, 0x42, 0x52, 0x63, 0xcc, 0xc1, 0x33, 0x6f, 0x6f, 0x4f, 0xeb, 0xd5,
-	0x26, 0x5a, 0x43, 0x2f, 0x91, 0x46, 0x97, 0xd6, 0xc8, 0xc0, 0x6d, 0x5a,
-	0x5d, 0x78, 0x97, 0xd6, 0xab, 0xe5, 0x26, 0xf8, 0x73, 0x61, 0x0f, 0x3e,
-	0xdc, 0x04, 0x4f, 0x7b, 0x66, 0x5d, 0x41, 0x7b, 0x26, 0x6d, 0x3f, 0x0b,
-	0xdf, 0x90, 0xc8, 0x8e, 0x74, 0xf5, 0xe8, 0x7d, 0x03, 0x8e, 0x44, 0x50,
-	0x6f, 0xb4, 0x62, 0x6d, 0xbd, 0xca, 0x5a, 0x44, 0xed, 0x6d, 0x95, 0x41,
-	0xd8, 0x2c, 0x75, 0xe7, 0xde, 0x0d, 0x3e, 0xaa, 0x6b, 0x02, 0x47, 0x9e,
-	0xb4, 0x49, 0xcb, 0x8f, 0x9d, 0x97, 0xa3, 0x83, 0x76, 0x49, 0x86, 0xcc,
-	0x56, 0x9c, 0x5f, 0x6b, 0x68, 0x9c, 0x49, 0xd2, 0xb2, 0x32, 0xd4, 0x6f,
-	0x7e, 0x0f, 0x7c, 0x8e, 0x57, 0x0d, 0xa9, 0x59, 0x89, 0xd8, 0x79, 0xe0,
-	0xd8, 0x0f, 0xdd, 0xd4, 0x46, 0x48, 0x8f, 0xc8, 0x61, 0xd8, 0x77, 0x4d,
-	0xe7, 0x45, 0xda, 0x71, 0x62, 0xa2, 0x88, 0x5a, 0xe7, 0x2f, 0x75, 0x6e,
-	0x73, 0x9c, 0x1b, 0xc8, 0x6f, 0x13, 0x5b, 0x6c, 0x4f, 0x9d, 0x73, 0x6d,
-	0x4f, 0x9d, 0x43, 0x0f, 0x7c, 0x32, 0x22, 0x6d, 0xcb, 0xf0, 0x9f, 0x97,
-	0xf6, 0xb8, 0xf5, 0xdc, 0x4b, 0xfc, 0xdd, 0x09, 0xf1, 0xee, 0x64, 0x58,
-	0xac, 0x93, 0x3a, 0x1f, 0x40, 0xde, 0xe3, 0x32, 0x7d, 0x86, 0x31, 0xd5,
-	0x92, 0x81, 0x93, 0xd4, 0x07, 0xeb, 0x9a, 0x85, 0xd1, 0x02, 0x7c, 0x64,
-	0x06, 0x71, 0x41, 0x2d, 0xdf, 0x94, 0x82, 0x45, 0x39, 0x74, 0x49, 0xfb,
-	0x32, 0xfa, 0xf1, 0x65, 0xc4, 0x86, 0xe5, 0x98, 0xb4, 0xc0, 0xb7, 0xd4,
-	0xb9, 0xa8, 0x51, 0x9a, 0x7f, 0x17, 0xfe, 0xc0, 0xdf, 0x70, 0x50, 0x5b,
-	0x9e, 0x8b, 0x19, 0xf4, 0x2d, 0x75, 0x8e, 0x76, 0x8e, 0x72, 0xea, 0x1c,
-	0xed, 0x9c, 0x74, 0xf8, 0xfe, 0x82, 0xf7, 0x73, 0x23, 0xfa, 0x9e, 0xfa,
-	0x86, 0x4d, 0x5e, 0x7e, 0x20, 0xd9, 0x2a, 0x6b, 0x44, 0xf2, 0x23, 0xdd,
-	0xa8, 0x65, 0x76, 0x65, 0xed, 0x81, 0xb1, 0x75, 0xf9, 0xa8, 0x7c, 0xdd,
-	0xf9, 0x11, 0xf8, 0x22, 0x1f, 0xcd, 0x7c, 0x91, 0xa7, 0x2e, 0x69, 0xd1,
-	0x7c, 0xf9, 0xfc, 0x40, 0xd0, 0xe0, 0x67, 0xef, 0xc9, 0x18, 0xf0, 0x7f,
-	0x11, 0x31, 0xa0, 0x0f, 0xcf, 0x27, 0xf0, 0x44, 0x4a, 0x3b, 0x47, 0xde,
-	0xc9, 0xeb, 0x75, 0xd4, 0x8d, 0x3e, 0x9f, 0x53, 0x78, 0x7f, 0x55, 0xa6,
-	0xe7, 0x9d, 0xe3, 0xc8, 0xab, 0xbc, 0x43, 0xef, 0x71, 0xef, 0x83, 0xb7,
-	0xf2, 0xfe, 0xaa, 0xb8, 0xf2, 0x49, 0x98, 0x35, 0xc1, 0xfb, 0xd2, 0x56,
-	0x59, 0x34, 0xc7, 0x8e, 0x98, 0xae, 0xc3, 0x0f, 0xd7, 0x19, 0x27, 0x28,
-	0xa3, 0xeb, 0x92, 0x9d, 0xe7, 0xfd, 0x97, 0x8b, 0x6f, 0xaa, 0xee, 0xc7,
-	0x8d, 0xe6, 0x3d, 0x36, 0xe0, 0xfa, 0x00, 0x47, 0xba, 0xd6, 0x28, 0x3f,
-	0xc4, 0x9c, 0xde, 0xa6, 0x58, 0xd3, 0xbc, 0x6f, 0x4c, 0x9e, 0x43, 0x1d,
-	0xf0, 0x9a, 0xbd, 0x49, 0xae, 0x53, 0xac, 0x85, 0x6a, 0xf5, 0x49, 0xf8,
-	0x64, 0x0b, 0x62, 0x99, 0x29, 0xeb, 0xe5, 0x56, 0xa9, 0xa1, 0xde, 0x59,
-	0x5c, 0x62, 0x2c, 0x24, 0xed, 0xed, 0x98, 0x77, 0xe3, 0x17, 0x63, 0xed,
-	0x7a, 0x19, 0x79, 0x16, 0xbe, 0xbd, 0x5e, 0x8e, 0xe2, 0xd9, 0x87, 0xa7,
-	0x85, 0x67, 0x1c, 0xcf, 0x24, 0x9e, 0x23, 0x78, 0x8e, 0xe0, 0x69, 0x61,
-	0x6f, 0x0c, 0x4f, 0xbf, 0x67, 0x20, 0xae, 0xdb, 0x7c, 0x97, 0xf4, 0x79,
-	0xa8, 0x15, 0x2d, 0xe6, 0xb4, 0xb0, 0x9d, 0x43, 0x1f, 0x91, 0x1d, 0x61,
-	0xad, 0xc7, 0x9a, 0xef, 0x03, 0xc7, 0xb4, 0xd8, 0x97, 0x17, 0x8d, 0xfd,
-	0x43, 0xcc, 0x0b, 0x55, 0xe4, 0x85, 0xf7, 0x76, 0xa3, 0x7f, 0x34, 0x0f,
-	0xe8, 0xbb, 0xa3, 0x79, 0x7c, 0xf3, 0x1d, 0x3d, 0x6f, 0x74, 0x06, 0x79,
-	0x8a, 0xf1, 0xd3, 0xc1, 0x9e, 0x3c, 0xe2, 0xf8, 0x2e, 0xf8, 0x5f, 0x06,
-	0x71, 0x1b, 0xef, 0x0b, 0x97, 0x76, 0xbb, 0x39, 0x15, 0xf9, 0x56, 0x6d,
-	0xbd, 0xaf, 0xb1, 0xb1, 0x67, 0xbb, 0xde, 0xa0, 0x13, 0x38, 0x12, 0xd5,
-	0x05, 0xf8, 0xe0, 0xf7, 0xed, 0xe3, 0xba, 0xb6, 0xa3, 0x2e, 0x9e, 0x45,
-	0x8d, 0x9a, 0x9b, 0x63, 0x0d, 0x73, 0x0c, 0x7d, 0x09, 0xfa, 0xb3, 0x28,
-	0x7b, 0x72, 0xe6, 0x02, 0x5d, 0x8b, 0x46, 0xa5, 0x9d, 0x79, 0xe0, 0x06,
-	0xce, 0x03, 0x5f, 0x8b, 0x0e, 0x64, 0xf6, 0x08, 0x6a, 0x42, 0xc7, 0x09,
-	0x5b, 0xfb, 0x25, 0xfe, 0x38, 0x63, 0x8e, 0x60, 0xbf, 0x29, 0xee, 0xbd,
-	0x3a, 0xe2, 0xee, 0xa4, 0xfe, 0xbd, 0x18, 0xc6, 0x65, 0x63, 0xef, 0x1d,
-	0xc0, 0xc5, 0x79, 0xde, 0x69, 0x8b, 0xec, 0x9f, 0x73, 0x6b, 0x5a, 0x65,
-	0x35, 0xe3, 0xfb, 0x39, 0x0f, 0x1f, 0xd7, 0x95, 0xf7, 0xdb, 0xc6, 0x1e,
-	0xc8, 0x08, 0xfe, 0x00, 0x1d, 0x9f, 0x40, 0xfd, 0x7c, 0x11, 0x7a, 0x79,
-	0x0d, 0x3a, 0xb9, 0x54, 0xa6, 0xad, 0x0f, 0xc3, 0xee, 0x21, 0xc3, 0x49,
-	0xe2, 0x1a, 0xd1, 0x67, 0x5f, 0x2c, 0x23, 0x76, 0x32, 0xfe, 0xa9, 0x5f,
-	0x8d, 0xb2, 0x3e, 0x64, 0x1e, 0x74, 0xf1, 0xf4, 0xb9, 0x70, 0xe2, 0xaf,
-	0xed, 0xd6, 0xf4, 0xd4, 0xf4, 0x3d, 0x18, 0xe5, 0x04, 0x1b, 0xe4, 0x6f,
-	0x04, 0x1a, 0xe6, 0x0b, 0x51, 0x7d, 0x0f, 0xaf, 0x38, 0x47, 0x3e, 0x46,
-	0x24, 0x3b, 0xe7, 0xef, 0xeb, 0xc6, 0xbe, 0x1d, 0x4d, 0xb8, 0xee, 0xdc,
-	0xc2, 0x83, 0xf2, 0x78, 0xe0, 0xfa, 0xd6, 0xba, 0x3f, 0x61, 0x16, 0x37,
-	0xee, 0x86, 0x99, 0x7f, 0xa9, 0x9b, 0x14, 0xf6, 0xfb, 0xfa, 0xe9, 0xf3,
-	0x7a, 0x81, 0xc4, 0x6c, 0x51, 0x58, 0xab, 0x50, 0x47, 0x63, 0xf0, 0x6b,
-	0x13, 0xf8, 0x6d, 0xa9, 0x96, 0xdb, 0x44, 0xf5, 0xb0, 0x37, 0x66, 0xad,
-	0xdc, 0x7c, 0xe6, 0xaf, 0x78, 0x67, 0xa2, 0x9f, 0x3e, 0xc5, 0xba, 0x59,
-	0xe7, 0x19, 0xc0, 0x74, 0x6c, 0xa1, 0xed, 0x17, 0x3d, 0x38, 0xae, 0x27,
-	0xa5, 0x88, 0x3a, 0x34, 0x37, 0x87, 0x8a, 0x1e, 0xf1, 0x5b, 0xa5, 0xf9,
-	0xbb, 0x16, 0xef, 0xf0, 0x86, 0xe3, 0xd3, 0xa0, 0xb1, 0x68, 0x66, 0x78,
-	0x6f, 0x06, 0x1c, 0xbd, 0x5b, 0x70, 0x8c, 0x7b, 0x38, 0xc6, 0xa5, 0x74,
-	0x66, 0x02, 0xbe, 0x96, 0x41, 0x7e, 0xef, 0x37, 0x1f, 0x91, 0x4f, 0xa0,
-	0xb9, 0xc6, 0xdc, 0xd9, 0x11, 0xe8, 0xc9, 0x71, 0xf6, 0xdb, 0x87, 0x40,
-	0xf7, 0x77, 0x90, 0x5b, 0xfd, 0x9a, 0xa7, 0x14, 0x0b, 0x21, 0x87, 0x1d,
-	0xd1, 0xbf, 0xc3, 0x16, 0x4d, 0x13, 0xf6, 0xaa, 0x8c, 0xe1, 0x24, 0xda,
-	0x7b, 0xe4, 0xb7, 0x59, 0xe4, 0x2a, 0xf2, 0xd9, 0x29, 0x25, 0xd3, 0x78,
-	0x38, 0x84, 0xba, 0x26, 0x3b, 0x47, 0x3f, 0x92, 0x81, 0x50, 0xba, 0x15,
-	0x35, 0xa9, 0x23, 0x6f, 0xdb, 0xfc, 0x77, 0x0a, 0xb3, 0x72, 0xb1, 0x6e,
-	0xe2, 0xf9, 0x5d, 0xe8, 0xe1, 0x4f, 0xf1, 0xfe, 0x76, 0x0f, 0xea, 0x3e,
-	0xac, 0x64, 0x60, 0xbb, 0x49, 0x5d, 0xcf, 0xb0, 0x8e, 0xa8, 0x21, 0xdf,
-	0x2a, 0xe4, 0x1a, 0xd4, 0x55, 0x63, 0xac, 0x5d, 0x9f, 0x5b, 0xbc, 0x26,
-	0x97, 0xe6, 0xf9, 0x3b, 0x28, 0xf3, 0xf2, 0x41, 0xc6, 0x03, 0x73, 0x26,
-	0x85, 0xb9, 0x25, 0xc6, 0x32, 0x7c, 0x37, 0xe0, 0x40, 0x3d, 0xa8, 0x11,
-	0x50, 0x6b, 0xaf, 0x5b, 0x49, 0xf0, 0x79, 0x4d, 0x2e, 0xce, 0x87, 0x65,
-	0xd1, 0x62, 0x5d, 0x24, 0xf1, 0x2c, 0x60, 0x2f, 0x2e, 0xfd, 0x93, 0x6b,
-	0x13, 0x84, 0x47, 0xcf, 0x53, 0x44, 0x5d, 0xf7, 0x88, 0xde, 0xfb, 0xd3,
-	0xf4, 0x4c, 0x9a, 0x9a, 0xfb, 0xbc, 0x82, 0x5c, 0xa4, 0x3f, 0xe9, 0xdf,
-	0x28, 0x58, 0x1b, 0x1c, 0x83, 0xcd, 0xb2, 0x76, 0x67, 0x3f, 0x80, 0xf7,
-	0x3a, 0xd7, 0xc9, 0x3b, 0x9e, 0x0b, 0xfd, 0x90, 0x0d, 0xfd, 0x9e, 0x77,
-	0x62, 0xc8, 0xa3, 0x8a, 0xbe, 0x5e, 0xd2, 0xb1, 0xa0, 0x54, 0x29, 0x20,
-	0xa7, 0x20, 0x06, 0xd8, 0xbd, 0xb0, 0xc5, 0x49, 0xe8, 0x72, 0x0c, 0x70,
-	0x5b, 0x72, 0xc9, 0x6a, 0x49, 0xd7, 0x65, 0x6a, 0xe5, 0xf6, 0xfd, 0x4d,
-	0x1e, 0xfe, 0xa3, 0x56, 0x61, 0x5b, 0xf0, 0x21, 0xb5, 0x1a, 0xc5, 0x13,
-	0xf1, 0x78, 0x15, 0xfd, 0x45, 0x99, 0xf7, 0x43, 0xe8, 0x0d, 0xca, 0xbc,
-	0x3b, 0x49, 0xe2, 0x39, 0xc2, 0xfb, 0x22, 0x2f, 0xae, 0x11, 0x3f, 0xe9,
-	0xf0, 0xe3, 0x0b, 0x6b, 0x49, 0xc6, 0x17, 0xbf, 0x9e, 0x74, 0x6d, 0xe1,
-	0x44, 0x85, 0x31, 0x84, 0x76, 0xdd, 0x8f, 0xb8, 0x45, 0x5b, 0x70, 0x6b,
-	0xc9, 0xa5, 0xaa, 0x2b, 0xb3, 0xe9, 0xc6, 0x05, 0x9d, 0x23, 0x0e, 0x88,
-	0x05, 0x1b, 0xa3, 0xec, 0xb0, 0xa6, 0x73, 0xc0, 0x79, 0xc9, 0xe8, 0x27,
-	0x65, 0xf6, 0xaa, 0x64, 0x96, 0x46, 0xe4, 0x05, 0x1d, 0xb7, 0xfc, 0x98,
-	0xc5, 0x1a, 0x92, 0xbf, 0x1f, 0x27, 0xe5, 0xf9, 0xd3, 0xd7, 0x24, 0xfb,
-	0x22, 0xe3, 0xd6, 0x70, 0x6c, 0x87, 0xc1, 0x58, 0xe5, 0x48, 0x1d, 0xb9,
-	0xe9, 0x11, 0x9b, 0xff, 0x16, 0x20, 0x84, 0x9e, 0xce, 0x91, 0xd6, 0xd1,
-	0x84, 0x1d, 0x37, 0xfa, 0x9f, 0xd8, 0x61, 0x30, 0x37, 0x0e, 0x9b, 0x4f,
-	0x89, 0x7f, 0x1f, 0xd5, 0x26, 0x4f, 0xe9, 0xbb, 0x0a, 0xb8, 0xed, 0xdc,
-	0xfb, 0xfa, 0x77, 0x94, 0x1b, 0x29, 0xca, 0x1a, 0xdf, 0xab, 0x9c, 0x2f,
-	0x46, 0x6e, 0xa4, 0x5a, 0xa4, 0x74, 0x87, 0xe3, 0x3c, 0x39, 0xfa, 0xc0,
-	0x6e, 0xf7, 0xdf, 0x8b, 0x3c, 0x7d, 0x87, 0x1b, 0x0b, 0x7e, 0xcd, 0xfb,
-	0xfe, 0x3a, 0x9e, 0xb4, 0x6d, 0xe6, 0x5b, 0xe6, 0x47, 0xea, 0x0d, 0xcf,
-	0x25, 0xbe, 0x33, 0xf7, 0xce, 0x22, 0xf7, 0x32, 0x5f, 0xee, 0x92, 0x1c,
-	0x7f, 0xe7, 0x53, 0x7a, 0xbe, 0xe8, 0xd6, 0xd2, 0x1e, 0x5c, 0x75, 0x4a,
-	0xa6, 0xab, 0xac, 0xa1, 0x2e, 0x22, 0x97, 0x0d, 0xc1, 0x56, 0x99, 0xd3,
-	0x8e, 0x23, 0x9f, 0xf3, 0xf7, 0x69, 0xac, 0x2d, 0x70, 0x5f, 0x22, 0x19,
-	0x57, 0xcd, 0xbf, 0x2b, 0xdd, 0x8c, 0xf2, 0x3e, 0xea, 0xfc, 0x10, 0xf4,
-	0xfe, 0x15, 0xf6, 0x16, 0x03, 0xda, 0x46, 0xb2, 0x2f, 0x51, 0xf6, 0xee,
-	0xef, 0xd7, 0xd2, 0xed, 0xfa, 0x00, 0xeb, 0x80, 0xcf, 0x40, 0x2e, 0x07,
-	0xec, 0x6b, 0xcc, 0xdd, 0xff, 0xa6, 0xac, 0xe1, 0xe4, 0x53, 0x06, 0x7d,
-	0x1b, 0xdf, 0x4b, 0x21, 0x59, 0x88, 0x92, 0x7f, 0xc8, 0xcb, 0xa0, 0xef,
-	0x6c, 0x27, 0x87, 0xad, 0x32, 0xf8, 0x0b, 0xc8, 0x80, 0xb2, 0xf4, 0x65,
-	0xc0, 0xf7, 0x09, 0xe8, 0x8b, 0x3d, 0x43, 0xbf, 0xee, 0x23, 0x4b, 0x0d,
-	0xf7, 0xec, 0x52, 0xa5, 0x99, 0x66, 0xd2, 0x4b, 0x9d, 0x9e, 0x97, 0x9c,
-	0xd6, 0xef, 0xac, 0xe4, 0xaa, 0xe7, 0x65, 0x7f, 0x75, 0x56, 0x1e, 0xb5,
-	0x1e, 0x06, 0xbf, 0x57, 0x9c, 0x82, 0xa5, 0x7b, 0x95, 0xb1, 0x3c, 0xce,
-	0x2e, 0x8c, 0xf4, 0xca, 0x4d, 0xd4, 0x1d, 0xcf, 0x2e, 0x9a, 0xf2, 0x3f,
-	0x9d, 0x5b, 0x5f, 0x6c, 0x5b, 0xd5, 0x19, 0xff, 0x7c, 0x6d, 0x27, 0x69,
-	0x68, 0xc2, 0xad, 0xeb, 0x24, 0x6e, 0x9a, 0x51, 0x3b, 0xbe, 0x6d, 0x23,
-	0x92, 0xa2, 0xdb, 0x10, 0x68, 0xd4, 0x65, 0x8a, 0x71, 0x42, 0x17, 0xb6,
-	0x22, 0xd2, 0xae, 0xab, 0x2a, 0x8d, 0x81, 0xe5, 0xa6, 0x7f, 0xd8, 0xc3,
-	0x0a, 0x85, 0x75, 0x08, 0x21, 0xd5, 0xb8, 0xe9, 0xd6, 0x69, 0x21, 0x4e,
-	0xff, 0x2d, 0x8c, 0x87, 0xcd, 0x4a, 0xd2, 0x96, 0x4d, 0x11, 0x2e, 0x88,
-	0xb2, 0x3d, 0x6c, 0xa3, 0x4a, 0x01, 0xed, 0x79, 0x7b, 0x99, 0x34, 0x36,
-	0x65, 0x05, 0x36, 0x5e, 0x36, 0xf5, 0x81, 0x07, 0xa6, 0xd1, 0x79, 0xbf,
-	0xdf, 0x77, 0xee, 0x75, 0x6c, 0x13, 0x84, 0xb4, 0x48, 0x91, 0xef, 0x39,
-	0xf7, 0xdc, 0x73, 0xce, 0x3d, 0xdf, 0xff, 0xef, 0xfb, 0xdd, 0x8c, 0x3d,
-	0x28, 0x3f, 0xd2, 0x5c, 0x3e, 0xe3, 0x93, 0x00, 0x7c, 0x52, 0x83, 0x2d,
-	0x90, 0x36, 0x27, 0x76, 0x53, 0xe8, 0x53, 0x86, 0x41, 0xeb, 0xb8, 0xf1,
-	0x9b, 0x6d, 0x73, 0x7f, 0xcb, 0x59, 0xf8, 0xee, 0xee, 0x7d, 0x6d, 0x7e,
-	0xce, 0xd7, 0xf8, 0xb7, 0x7f, 0xf2, 0x6a, 0x68, 0x83, 0x32, 0x83, 0xfd,
-	0xbc, 0xa1, 0x7a, 0xd6, 0x01, 0x2f, 0x31, 0x37, 0x1d, 0xd3, 0xfc, 0x43,
-	0x78, 0x9a, 0x3a, 0xea, 0x2a, 0x74, 0xd4, 0x10, 0x75, 0xd7, 0xf0, 0xbc,
-	0xcb, 0xfc, 0x40, 0x54, 0xfe, 0x38, 0x45, 0x3d, 0x1c, 0x97, 0x3f, 0x4c,
-	0x3d, 0x8b, 0xfd, 0x24, 0x8a, 0xcc, 0x51, 0xde, 0x98, 0xc9, 0xd1, 0x4f,
-	0x52, 0x7f, 0x3e, 0xed, 0x3e, 0xad, 0x76, 0x20, 0x6e, 0xe5, 0xd7, 0x87,
-	0x55, 0xdf, 0x1c, 0xd3, 0xda, 0x6e, 0xdc, 0xea, 0x92, 0x1b, 0x17, 0x8c,
-	0x8e, 0x0d, 0x4f, 0x47, 0x03, 0x23, 0x0b, 0xb4, 0x4b, 0xc9, 0x58, 0xd6,
-	0x6a, 0x94, 0x43, 0x51, 0xe6, 0x9e, 0x53, 0xd4, 0xcf, 0xb0, 0x85, 0xbd,
-	0x76, 0xd6, 0x6a, 0xf2, 0xec, 0x4f, 0xac, 0x4e, 0xcf, 0x1e, 0xf3, 0xf4,
-	0x2c, 0xef, 0xa5, 0x68, 0x03, 0x20, 0x93, 0x89, 0x99, 0x51, 0x2b, 0x09,
-	0x9b, 0x87, 0xeb, 0x45, 0xce, 0x1f, 0x97, 0xe3, 0x8b, 0x47, 0xe1, 0x7f,
-	0xf7, 0xda, 0x7b, 0x69, 0x57, 0xed, 0x21, 0xe2, 0x71, 0xb0, 0xfe, 0x97,
-	0xea, 0xe6, 0x7a, 0xd4, 0x9b, 0x8b, 0xf7, 0x21, 0xe7, 0xd3, 0xac, 0xd7,
-	0x36, 0x32, 0x9f, 0xa3, 0x7b, 0xad, 0x1d, 0xbb, 0xa7, 0xb2, 0xee, 0x64,
-	0xc1, 0xf1, 0xb0, 0x61, 0xf8, 0x85, 0x2f, 0xf4, 0x8d, 0x08, 0xd7, 0xe4,
-	0x7a, 0xad, 0x92, 0xde, 0x0f, 0xfd, 0x32, 0xcd, 0xff, 0x9c, 0x57, 0xbb,
-	0x42, 0xbc, 0x12, 0xed, 0x5c, 0xc5, 0x36, 0x7d, 0xc5, 0x9b, 0xaf, 0xbf,
-	0x5d, 0x9a, 0xa3, 0x55, 0xe3, 0x99, 0x5b, 0x61, 0x3b, 0x2e, 0xb9, 0x45,
-	0xfe, 0x96, 0xcb, 0x11, 0xa7, 0x41, 0xf6, 0xda, 0x1b, 0xeb, 0xe6, 0xd8,
-	0x86, 0x3e, 0xe3, 0x13, 0x04, 0xa7, 0x03, 0x9e, 0x6f, 0xb1, 0x89, 0x7e,
-	0x93, 0x77, 0xdd, 0xa4, 0x39, 0x99, 0xb8, 0xd5, 0x59, 0xf7, 0x1e, 0x9b,
-	0x2a, 0x76, 0x38, 0x6e, 0x51, 0x77, 0x36, 0x46, 0xa5, 0x95, 0x3c, 0x54,
-	0x56, 0x3f, 0x3e, 0xe4, 0x18, 0xcc, 0x45, 0xd4, 0x39, 0xd2, 0xce, 0x9c,
-	0xfd, 0x5b, 0x7a, 0x6e, 0x2d, 0xf4, 0x09, 0x70, 0x0d, 0x3e, 0xf9, 0x4c,
-	0xbe, 0x97, 0xb9, 0x5e, 0xcc, 0xdf, 0xcc, 0xf9, 0x5d, 0xef, 0x9c, 0x13,
-	0x6e, 0xce, 0xba, 0x5f, 0xb2, 0x17, 0x0c, 0xff, 0xa5, 0x1d, 0xf0, 0x5e,
-	0x2b, 0xda, 0x0b, 0xb4, 0x09, 0x9f, 0x37, 0x8f, 0x6f, 0x1b, 0x7a, 0xd4,
-	0x36, 0x9c, 0x2a, 0x90, 0x3f, 0xc9, 0x97, 0x3e, 0x3f, 0xfa, 0x3a, 0x8f,
-	0x3c, 0x4a, 0x3d, 0x3b, 0x28, 0x67, 0x0b, 0x3c, 0x9b, 0x94, 0xd6, 0xb4,
-	0x36, 0x9f, 0x3b, 0xa8, 0x98, 0xac, 0xee, 0xe9, 0xc4, 0x4b, 0x39, 0x19,
-	0x96, 0xab, 0x2e, 0xcf, 0x2c, 0x51, 0xcc, 0x04, 0x5b, 0xaa, 0xde, 0x7f,
-	0xbf, 0x9e, 0x59, 0x58, 0x7d, 0xc6, 0x18, 0xc6, 0x3e, 0xef, 0xd1, 0xbb,
-	0x55, 0xcf, 0x36, 0x53, 0x43, 0x9f, 0xaf, 0xeb, 0x39, 0x85, 0xa1, 0x13,
-	0x59, 0xdf, 0x0f, 0x47, 0xf8, 0x0c, 0xd7, 0xa5, 0xcf, 0xc7, 0xb5, 0xc8,
-	0x7b, 0xdd, 0xb0, 0xd8, 0xfd, 0x12, 0xdc, 0x09, 0xd1, 0xdf, 0xc9, 0x3a,
-	0x72, 0x00, 0xb2, 0xba, 0xd9, 0x60, 0x60, 0xc6, 0x8d, 0xaf, 0x91, 0xb1,
-	0xae, 0xe1, 0x1c, 0x11, 0xab, 0xc0, 0x8f, 0x3e, 0xf5, 0x93, 0xdb, 0x98,
-	0x2f, 0xe3, 0xf9, 0xeb, 0x03, 0x98, 0xdf, 0xf1, 0xea, 0xea, 0x53, 0xdb,
-	0xc9, 0xab, 0xa3, 0x5a, 0x1f, 0xe4, 0x33, 0x94, 0x63, 0x9e, 0x19, 0xe9,
-	0xf2, 0x1e, 0x9e, 0x67, 0x7b, 0x5b, 0x1d, 0x1d, 0x93, 0xde, 0xfe, 0xfc,
-	0xfb, 0x61, 0x09, 0xb7, 0x53, 0xc7, 0x45, 0x25, 0x39, 0xcd, 0x98, 0x05,
-	0xb6, 0x6b, 0x9c, 0x73, 0x7d, 0xb1, 0x2e, 0xce, 0xfc, 0x9f, 0xba, 0x38,
-	0x63, 0x7d, 0xa4, 0xbc, 0x13, 0xd6, 0x3c, 0xd6, 0xe7, 0xd3, 0xb5, 0x58,
-	0x43, 0x57, 0xbf, 0x76, 0x1f, 0xad, 0xd0, 0xf1, 0x87, 0x05, 0xda, 0xab,
-	0x94, 0xe6, 0x94, 0xff, 0x3e, 0xc5, 0xb3, 0xe5, 0x1e, 0xaf, 0x72, 0x8f,
-	0xc3, 0x4b, 0x8a, 0x83, 0x7c, 0x58, 0x65, 0xf8, 0x74, 0x81, 0x3a, 0xa6,
-	0x45, 0xe6, 0x67, 0x7c, 0x3d, 0x33, 0xe6, 0xf9, 0xb8, 0xf9, 0xf5, 0x0d,
-	0xaa, 0x67, 0xe0, 0xdd, 0x38, 0x23, 0x9e, 0x7d, 0xe9, 0x92, 0xb9, 0x0b,
-	0xb4, 0xbb, 0x49, 0xf4, 0x45, 0x03, 0x73, 0x0b, 0xac, 0x4d, 0x12, 0x8b,
-	0x32, 0x2c, 0xac, 0xfb, 0x8f, 0xd8, 0xa7, 0x20, 0x6f, 0x31, 0x79, 0x7f,
-	0x8a, 0x3e, 0x7d, 0x03, 0x7c, 0xe3, 0xd6, 0xba, 0xf3, 0xdd, 0x51, 0xf1,
-	0x09, 0x6b, 0xe9, 0x1e, 0xef, 0x90, 0x66, 0xf2, 0xb9, 0x63, 0xdf, 0x10,
-	0xfa, 0x60, 0xbc, 0xce, 0x22, 0x16, 0x60, 0xec, 0x11, 0xd7, 0xd8, 0x63,
-	0xae, 0xc8, 0xbe, 0x16, 0x2f, 0xaf, 0xd4, 0xa2, 0xbc, 0x42, 0x7e, 0xcb,
-	0xa8, 0xff, 0x3d, 0xa4, 0x3a, 0x2b, 0x3f, 0xd5, 0x6b, 0x70, 0x2c, 0x76,
-	0x4c, 0x79, 0x4f, 0x6a, 0x78, 0x2f, 0xe6, 0xad, 0x3d, 0xd6, 0x61, 0x7c,
-	0x2b, 0x5b, 0xf5, 0x4d, 0x58, 0xc7, 0xd1, 0xae, 0x70, 0x7e, 0xf2, 0x06,
-	0x79, 0x84, 0x3a, 0xcf, 0x1f, 0xe7, 0xd3, 0xc3, 0x6f, 0x73, 0x3c, 0xf9,
-	0xbf, 0x1a, 0x8b, 0xe0, 0xcb, 0xaa, 0xdf, 0xe7, 0xcb, 0x1d, 0xef, 0x55,
-	0xdb, 0x04, 0xca, 0x5d, 0x75, 0x7d, 0xd2, 0x96, 0xc8, 0xf4, 0x0a, 0x5d,
-	0xd2, 0xfd, 0xdc, 0xff, 0xf3, 0xcc, 0xed, 0x42, 0xde, 0x56, 0xa3, 0xcd,
-	0x09, 0xa5, 0x4d, 0x06, 0xb4, 0x89, 0x28, 0x6d, 0x18, 0xef, 0x3d, 0xe5,
-	0xf1, 0x5b, 0x0b, 0xce, 0x8b, 0xb9, 0x5a, 0xe8, 0xba, 0x7d, 0xd4, 0xf9,
-	0xcf, 0x76, 0x68, 0x7d, 0xd0, 0xa1, 0xee, 0x5b, 0x0b, 0x7d, 0xc6, 0xf6,
-	0x56, 0xf5, 0x47, 0x4c, 0xbc, 0x15, 0xd7, 0x3c, 0x68, 0x10, 0xfa, 0x79,
-	0x6e, 0x0a, 0xbe, 0x1a, 0x71, 0x6f, 0x35, 0xb4, 0xfa, 0x8e, 0x77, 0x5e,
-	0xf3, 0x4a, 0x1b, 0xca, 0x00, 0xf5, 0xe6, 0x3a, 0xcc, 0xb7, 0x27, 0xda,
-	0x07, 0xfe, 0xfa, 0x19, 0xfa, 0x37, 0x6b, 0x3c, 0x11, 0x84, 0xcc, 0xdf,
-	0x9c, 0x6a, 0xf7, 0x62, 0x38, 0x07, 0x6d, 0xc4, 0xad, 0x53, 0x11, 0xc6,
-	0x14, 0x68, 0xf7, 0x48, 0xc3, 0x34, 0xe2, 0x57, 0xe8, 0xf1, 0x25, 0xb5,
-	0x47, 0x7d, 0xb8, 0x7f, 0x07, 0x71, 0x7e, 0xb8, 0x3e, 0x8a, 0xe7, 0x7a,
-	0x0d, 0x16, 0x21, 0xba, 0x45, 0xcf, 0x74, 0x6e, 0x2a, 0x11, 0x3b, 0x2c,
-	0x5e, 0xdf, 0xb8, 0xab, 0xfa, 0x60, 0x65, 0x5f, 0x0f, 0xca, 0x9e, 0x8a,
-	0xbd, 0x60, 0x1c, 0x0d, 0x1f, 0x7e, 0xc6, 0xd8, 0x83, 0x7c, 0xb1, 0x4f,
-	0xf1, 0x51, 0xc1, 0xa1, 0x45, 0x9c, 0x25, 0x7d, 0xd2, 0x65, 0xf8, 0xe1,
-	0x2e, 0xce, 0x90, 0x7e, 0x77, 0xf9, 0xe4, 0xa4, 0x9b, 0x62, 0x7d, 0x0c,
-	0xfa, 0xe0, 0xa4, 0x8c, 0x20, 0x2e, 0x18, 0x09, 0xb6, 0x32, 0xaf, 0x0c,
-	0xdf, 0x30, 0xe7, 0xe5, 0x1e, 0xfb, 0x98, 0x33, 0x95, 0x73, 0x0b, 0xdc,
-	0x3b, 0x65, 0xdb, 0xc4, 0xde, 0x73, 0x53, 0xdc, 0xaf, 0xc9, 0x43, 0xb0,
-	0x6d, 0x4d, 0xbb, 0xf8, 0xe5, 0x59, 0x0c, 0xe0, 0x77, 0x10, 0xf2, 0xc0,
-	0xb1, 0xf8, 0x5d, 0x58, 0x96, 0x77, 0x2f, 0xf8, 0xb6, 0x3d, 0x20, 0x6f,
-	0x3b, 0xe5, 0x93, 0xa7, 0xdc, 0xf5, 0x3c, 0x03, 0x37, 0xc7, 0x9a, 0xb5,
-	0xe3, 0xb8, 0x79, 0x29, 0x97, 0x97, 0xdc, 0xa5, 0xf5, 0x96, 0xd2, 0x92,
-	0xf2, 0xbf, 0x8c, 0x33, 0xbc, 0x7e, 0xaf, 0x25, 0x86, 0x7e, 0xa4, 0xcd,
-	0x67, 0x6b, 0x7f, 0xd5, 0xb6, 0xc0, 0xd7, 0x7f, 0xe4, 0x47, 0xf2, 0xe5,
-	0xb2, 0xec, 0x52, 0xfd, 0xbf, 0xda, 0x73, 0xd5, 0xba, 0xdf, 0xf7, 0x6f,
-	0xa9, 0xdf, 0xb5, 0xfe, 0xa3, 0xf1, 0xc1, 0x96, 0xe9, 0x7a, 0x9d, 0xf0,
-	0x98, 0x57, 0x57, 0x58, 0x8d, 0xf7, 0x0e, 0x78, 0x7a, 0x21, 0xa5, 0xbe,
-	0x73, 0xca, 0xa6, 0x7e, 0xe0, 0x7e, 0x9a, 0xe5, 0xe0, 0xec, 0x6d, 0xd0,
-	0xc4, 0xd7, 0xc1, 0x8c, 0xfb, 0x7c, 0xdd, 0xd1, 0xea, 0xf9, 0xc2, 0x96,
-	0x74, 0x9f, 0xa3, 0xef, 0xe4, 0x40, 0x8f, 0xb6, 0x49, 0x66, 0x3c, 0x28,
-	0xc9, 0x73, 0x1b, 0x62, 0xc6, 0xd7, 0x25, 0xff, 0x41, 0xde, 0xb4, 0x4f,
-	0x7d, 0x51, 0xf4, 0xdf, 0x29, 0x5c, 0xdb, 0xf0, 0x33, 0xe4, 0x79, 0x9f,
-	0x7f, 0xcf, 0xae, 0xe3, 0xd1, 0x9d, 0x1e, 0x8f, 0xf2, 0xbe, 0x65, 0xea,
-	0x1f, 0x18, 0xdb, 0x7d, 0x8e, 0x7b, 0x34, 0xcf, 0x75, 0x9f, 0x33, 0xf1,
-	0x7a, 0xed, 0x73, 0x7d, 0x95, 0xe7, 0x70, 0xbf, 0x47, 0xb1, 0x61, 0x98,
-	0x7b, 0xd7, 0x20, 0x7c, 0xba, 0x3e, 0xda, 0x1c, 0xda, 0xef, 0xcd, 0xee,
-	0x2e, 0x21, 0xbf, 0x27, 0x3c, 0x9e, 0xa3, 0xbe, 0x89, 0x78, 0xfa, 0x66,
-	0xc5, 0xbe, 0x8c, 0x18, 0xfc, 0x09, 0x73, 0x22, 0x55, 0xf6, 0xe5, 0x71,
-	0xf3, 0x6e, 0x35, 0xf6, 0xe5, 0x4e, 0x6f, 0x1e, 0xff, 0x9e, 0xaf, 0x57,
-	0xfc, 0xb6, 0xaf, 0x57, 0xea, 0x7d, 0x5a, 0x9f, 0xf6, 0xb5, 0xb8, 0xaf,
-	0xea, 0x98, 0x2f, 0xbf, 0x6a, 0xde, 0x25, 0x8b, 0x98, 0x8d, 0x3e, 0x65,
-	0x22, 0x67, 0x30, 0xd3, 0xd6, 0x59, 0x8b, 0xb8, 0x0f, 0xe7, 0xc7, 0x92,
-	0x8e, 0xdc, 0xd6, 0xd8, 0xfa, 0xf4, 0xec, 0x98, 0xe6, 0x79, 0xe6, 0x5c,
-	0x4f, 0xef, 0x44, 0x77, 0x43, 0xae, 0x5e, 0x89, 0xac, 0x60, 0x8a, 0x66,
-	0x4e, 0xa4, 0x61, 0x87, 0x52, 0x5a, 0x2f, 0xfb, 0x2e, 0xf6, 0x3b, 0xa8,
-	0x78, 0xae, 0x35, 0xce, 0x73, 0xf2, 0x90, 0x5d, 0xd6, 0xda, 0x4d, 0xd3,
-	0x50, 0xf1, 0x44, 0xd3, 0x8b, 0x3e, 0xdf, 0x93, 0x9f, 0x66, 0x4e, 0x1c,
-	0x9c, 0x29, 0x0f, 0x87, 0xb6, 0xf7, 0xda, 0x79, 0x21, 0x66, 0x7f, 0x58,
-	0x8e, 0x28, 0x76, 0xf8, 0x15, 0xdc, 0xdf, 0xc7, 0xf8, 0x32, 0x11, 0x52,
-	0x4c, 0x70, 0x22, 0x36, 0x01, 0x59, 0xcc, 0xba, 0xc4, 0xf8, 0xaf, 0x55,
-	0xac, 0xff, 0x9c, 0xd0, 0xcf, 0x22, 0xa6, 0xe0, 0x59, 0x39, 0xec, 0x6e,
-	0x76, 0x97, 0xc4, 0xf8, 0xbf, 0x59, 0xad, 0x09, 0x35, 0xca, 0x84, 0x1b,
-	0x6a, 0x4a, 0x97, 0x8c, 0x0c, 0x8c, 0x06, 0x53, 0x6b, 0x26, 0x9d, 0x68,
-	0xd3, 0xae, 0x12, 0x64, 0xbc, 0x04, 0xfd, 0x5f, 0x8a, 0x05, 0x46, 0x14,
-	0x9b, 0xf6, 0x65, 0x49, 0xb7, 0xd3, 0xcf, 0xa7, 0x3e, 0xf9, 0x8a, 0xdc,
-	0xb4, 0xb7, 0xca, 0xcd, 0x1e, 0xe2, 0x31, 0xfb, 0xd1, 0xa6, 0x2e, 0x19,
-	0x44, 0x5f, 0x12, 0x7d, 0x4d, 0xca, 0x8f, 0x1a, 0x9f, 0x41, 0x67, 0xdd,
-	0xb4, 0xa9, 0xab, 0xee, 0xe2, 0x2f, 0xde, 0xf5, 0x6f, 0xa0, 0x09, 0xb1,
-	0x1d, 0xdb, 0xd0, 0xa6, 0x8e, 0xb3, 0xeb, 0xfa, 0x3b, 0xd1, 0xbe, 0x17,
-	0x73, 0x34, 0xe8, 0xfb, 0x59, 0xce, 0x76, 0x53, 0xe7, 0xac, 0x19, 0xb3,
-	0xae, 0xae, 0xfd, 0xfb, 0x36, 0x83, 0x4f, 0xf8, 0x94, 0xf4, 0xce, 0xa5,
-	0xe4, 0xe1, 0x8e, 0xda, 0xf6, 0xbf, 0xea, 0xda, 0xad, 0xb2, 0xa6, 0x8d,
-	0x64, 0x38, 0xd6, 0x5e, 0xdb, 0xef, 0xf3, 0x93, 0xdf, 0xee, 0xc0, 0xfb,
-	0x42, 0x66, 0xac, 0xa4, 0xc6, 0x52, 0x37, 0xa3, 0x5c, 0xeb, 0xc3, 0xba,
-	0x67, 0x78, 0xcd, 0x67, 0xf8, 0x2c, 0xf3, 0x7a, 0xb7, 0xd9, 0x8f, 0x67,
-	0x98, 0x13, 0x60, 0x5e, 0x83, 0x3c, 0xbb, 0x5a, 0x9c, 0xc5, 0x31, 0x9f,
-	0xcd, 0x37, 0x64, 0x2a, 0xbc, 0xe7, 0xeb, 0x95, 0x58, 0x05, 0xab, 0xb6,
-	0xab, 0xe0, 0xe7, 0x84, 0x49, 0x3b, 0xad, 0x49, 0xc5, 0x6e, 0x80, 0xce,
-	0x87, 0x40, 0xe7, 0x07, 0x83, 0x8c, 0x0b, 0x9b, 0x3d, 0x5a, 0x3b, 0x32,
-	0x52, 0xfa, 0x0d, 0x64, 0x9c, 0x3c, 0x0a, 0x9f, 0xa2, 0x64, 0x79, 0xf8,
-	0x8c, 0x01, 0xd8, 0x34, 0x57, 0x82, 0x9a, 0x77, 0x40, 0x7c, 0x3f, 0x7f,
-	0x5d, 0x46, 0xa6, 0x98, 0x13, 0x20, 0x3f, 0x33, 0xae, 0x4f, 0xe1, 0xde,
-	0x2d, 0x8c, 0x75, 0x21, 0xc3, 0x63, 0xe0, 0xd7, 0x90, 0x38, 0xd3, 0xdb,
-	0x24, 0x37, 0x3e, 0xa6, 0x3e, 0x40, 0x37, 0x6c, 0xd4, 0x29, 0x77, 0x54,
-	0x26, 0xaf, 0x6c, 0x82, 0xac, 0x32, 0xee, 0xd7, 0x9c, 0x46, 0x39, 0xac,
-	0xbe, 0x39, 0x7d, 0x0e, 0xe6, 0xe1, 0x4c, 0x8d, 0xd9, 0xc8, 0xed, 0xa1,
-	0x98, 0xb4, 0x8e, 0xca, 0xcc, 0xac, 0xad, 0x78, 0x97, 0x94, 0xdc, 0x2e,
-	0x93, 0x76, 0xd9, 0x7d, 0x71, 0xe8, 0x2a, 0xfa, 0xf2, 0x3f, 0x88, 0x98,
-	0xb3, 0xdc, 0xbd, 0x81, 0x31, 0x71, 0x72, 0xba, 0x7a, 0x0e, 0xc5, 0xc8,
-	0xe0, 0xde, 0x2f, 0xdb, 0x8c, 0xcc, 0x30, 0x3e, 0xfe, 0xa0, 0x9c, 0x8a,
-	0x72, 0x4d, 0x8e, 0x65, 0xed, 0x96, 0x3c, 0xc2, 0xbd, 0xfd, 0xc7, 0xe3,
-	0xe5, 0x97, 0x31, 0x5f, 0x5c, 0xba, 0x5f, 0x1d, 0xd3, 0xb8, 0xfe, 0x54,
-	0x4d, 0x0c, 0x6b, 0xf2, 0x05, 0x26, 0x8e, 0xbd, 0x2e, 0x13, 0x8b, 0xa4,
-	0x0f, 0x6d, 0x7c, 0x40, 0x7e, 0xe1, 0xf4, 0xda, 0x4f, 0x68, 0xad, 0x31,
-	0x91, 0x62, 0x7d, 0xa6, 0xd9, 0x49, 0xda, 0xf3, 0x12, 0x1a, 0xfc, 0x1a,
-	0xae, 0x19, 0xd7, 0xe6, 0xdd, 0x5e, 0xf7, 0x09, 0xf1, 0x71, 0x20, 0x9b,
-	0x53, 0x8d, 0x81, 0x4f, 0xca, 0xd7, 0xf7, 0x71, 0x8c, 0xc1, 0x81, 0x48,
-	0x80, 0xb4, 0x7a, 0xef, 0x2e, 0xe2, 0x67, 0x6a, 0xf3, 0x7f, 0x0f, 0x1c,
-	0xdb, 0x3b, 0x90, 0x38, 0xc3, 0x18, 0x36, 0xec, 0x3c, 0xba, 0xc1, 0xbc,
-	0x6b, 0x2e, 0xb7, 0x4e, 0xb4, 0x7e, 0x76, 0xfc, 0x1f, 0x0e, 0xf1, 0x10,
-	0x89, 0x58, 0xa3, 0xc5, 0x3c, 0x38, 0x75, 0x1c, 0x6b, 0x2a, 0xcc, 0xb9,
-	0x11, 0xcb, 0xdf, 0x24, 0x97, 0xfb, 0x2c, 0x79, 0x20, 0x94, 0x8a, 0x5b,
-	0xb2, 0x25, 0x7e, 0x4e, 0xb0, 0x26, 0xeb, 0x2b, 0x8b, 0x89, 0x1c, 0xc7,
-	0x87, 0xa6, 0x39, 0x5f, 0x5c, 0xe3, 0x95, 0xe4, 0x96, 0x72, 0xf9, 0x29,
-	0x57, 0x02, 0xc9, 0x7b, 0x3e, 0x2c, 0xb3, 0x16, 0x6e, 0xbd, 0xfa, 0x79,
-	0x38, 0x05, 0xea, 0x0a, 0x7b, 0xc2, 0x60, 0x0e, 0x27, 0x8f, 0x77, 0x2f,
-	0xb2, 0xfd, 0xe4, 0x43, 0xa6, 0x7d, 0x06, 0xed, 0x06, 0x0f, 0xeb, 0x34,
-	0x75, 0xbc, 0xbb, 0x78, 0x6c, 0x83, 0x89, 0xbf, 0x97, 0x15, 0xff, 0xf5,
-	0x56, 0x4d, 0x4c, 0x93, 0x0a, 0x8c, 0x17, 0xc6, 0x02, 0x63, 0x05, 0xab,
-	0xaf, 0x09, 0xb4, 0x5a, 0x70, 0x99, 0xab, 0xf1, 0x73, 0x56, 0xcc, 0xf7,
-	0x8b, 0x3c, 0xa9, 0x18, 0x29, 0xd6, 0x14, 0x2d, 0xf5, 0x85, 0x0e, 0x2d,
-	0x30, 0xc7, 0x1f, 0x51, 0x7d, 0x70, 0x78, 0xb1, 0x55, 0xf2, 0xf6, 0x7a,
-	0xc9, 0xab, 0x8c, 0x47, 0x55, 0x07, 0x58, 0xce, 0x3d, 0xe8, 0xe3, 0xbe,
-	0x1f, 0x57, 0x5c, 0xc4, 0xeb, 0x85, 0x4e, 0xb4, 0x99, 0x6b, 0xde, 0x51,
-	0xd7, 0x5f, 0x5d, 0x97, 0x4d, 0xd8, 0x96, 0x55, 0x5f, 0x93, 0x65, 0x5f,
-	0x7d, 0x2d, 0xf6, 0xb4, 0x5c, 0x27, 0xdf, 0x94, 0xfc, 0x9c, 0xbb, 0xeb,
-	0xe5, 0xdc, 0x1f, 0xc3, 0x9c, 0x9c, 0x5b, 0x32, 0xa1, 0xa1, 0xa6, 0xbe,
-	0x53, 0x53, 0xc1, 0x5b, 0x2b, 0xf9, 0x53, 0xb4, 0x17, 0x2b, 0xb5, 0x72,
-	0xdc, 0x7b, 0x06, 0xbe, 0x48, 0x1e, 0x7e, 0x45, 0xce, 0xfb, 0xfe, 0x80,
-	0xf7, 0x2b, 0xcf, 0x7f, 0xc1, 0x9e, 0x9a, 0xb5, 0xce, 0x6e, 0xd5, 0xd4,
-	0xd9, 0xbf, 0x8d, 0x67, 0x59, 0x63, 0xcf, 0x95, 0x1b, 0xc0, 0xbb, 0x0d,
-	0xc4, 0x89, 0x54, 0xc6, 0x53, 0xc7, 0xab, 0x2e, 0xd7, 0xb9, 0x76, 0x79,
-	0x73, 0x05, 0xa1, 0xe7, 0x0f, 0x4e, 0xf9, 0x63, 0x4e, 0x4a, 0x63, 0x7f,
-	0x22, 0x16, 0xb4, 0x38, 0xc6, 0xe8, 0xfb, 0xb4, 0x7b, 0x12, 0x7a, 0x9c,
-	0x3a, 0x9f, 0xef, 0xed, 0xc0, 0xd7, 0xa3, 0x2e, 0xa0, 0x3e, 0x57, 0x1b,
-	0x10, 0xcf, 0x43, 0xd7, 0x8f, 0x94, 0x34, 0x97, 0x1f, 0xfb, 0x6a, 0x30,
-	0x31, 0x93, 0x55, 0xdd, 0x00, 0x7f, 0xaf, 0xf4, 0x26, 0xf3, 0x41, 0x67,
-	0x24, 0x50, 0x5d, 0xa7, 0x61, 0x6c, 0xc6, 0x9a, 0x46, 0x0b, 0x74, 0x83,
-	0xc8, 0x55, 0xf0, 0xc6, 0x6b, 0x0b, 0xe4, 0xd7, 0x60, 0xbb, 0x89, 0xaf,
-	0x96, 0x76, 0x58, 0xd2, 0xae, 0xb5, 0xcf, 0xbc, 0x13, 0xa1, 0x7f, 0x32,
-	0x9c, 0xec, 0x87, 0x9f, 0xad, 0xd8, 0x03, 0xe6, 0x2b, 0x0f, 0x22, 0x1e,
-	0xab, 0xce, 0xb1, 0x40, 0xbe, 0xc6, 0xd9, 0x9f, 0x85, 0x5f, 0xb9, 0x52,
-	0xf7, 0xc8, 0x17, 0x27, 0x35, 0xb7, 0x39, 0xb7, 0xd0, 0xa2, 0x3a, 0x76,
-	0xae, 0x38, 0x86, 0x73, 0x91, 0xad, 0xd6, 0x50, 0xde, 0xeb, 0x0f, 0x4b,
-	0xb1, 0xc8, 0xb6, 0x74, 0x35, 0xe8, 0xb9, 0xfb, 0xb5, 0x1d, 0x5b, 0xe6,
-	0xe1, 0x2b, 0x16, 0x17, 0x1d, 0xfc, 0xf7, 0xe0, 0xbf, 0x0f, 0xff, 0xbb,
-	0x25, 0x3d, 0x4d, 0xff, 0x95, 0xb5, 0x9c, 0x96, 0xba, 0xf5, 0xe9, 0x23,
-	0x75, 0x29, 0x0e, 0x2c, 0xef, 0xc5, 0x39, 0xf9, 0x62, 0xbd, 0x9c, 0x30,
-	0x4f, 0xea, 0xeb, 0x08, 0xe6, 0x4b, 0xfd, 0x5a, 0x5f, 0x75, 0x0d, 0xcb,
-	0xf2, 0xea, 0x5e, 0xe4, 0xe9, 0x66, 0x39, 0x5c, 0xf4, 0x6b, 0x57, 0x31,
-	0x39, 0x52, 0xa9, 0x5d, 0x49, 0x26, 0x38, 0xf4, 0xc9, 0x23, 0xd9, 0x29,
-	0xc5, 0x13, 0x58, 0xd6, 0xd0, 0xf5, 0x47, 0x26, 0x16, 0xdf, 0x7e, 0x64,
-	0x05, 0x13, 0x8e, 0x7b, 0x8b, 0xab, 0x61, 0x86, 0x88, 0xa5, 0xe3, 0xb7,
-	0x72, 0xea, 0xbb, 0x61, 0xdf, 0x7e, 0xcc, 0x43, 0x9c, 0x1d, 0xf4, 0x4c,
-	0xf3, 0x0a, 0x76, 0xd7, 0xc4, 0xa3, 0xc4, 0x91, 0xf2, 0xb9, 0x6a, 0xec,
-	0x47, 0x08, 0xe7, 0x2f, 0x01, 0xcb, 0xc9, 0x61, 0x1f, 0x3f, 0xed, 0x34,
-	0x7e, 0x20, 0x71, 0xa6, 0x89, 0x2a, 0xec, 0x91, 0x8f, 0x35, 0x7d, 0x09,
-	0x73, 0x65, 0xe4, 0x77, 0xa5, 0x47, 0xe5, 0x57, 0xa5, 0x31, 0xc8, 0xf7,
-	0x04, 0xe6, 0x3c, 0x20, 0x6f, 0x96, 0xf6, 0xc9, 0xb5, 0xd2, 0xb8, 0xbc,
-	0x51, 0xda, 0x8d, 0x98, 0x6a, 0x94, 0x58, 0x4f, 0x0f, 0x2b, 0x3d, 0x2c,
-	0x07, 0xcf, 0x2b, 0x06, 0xf0, 0x16, 0xfd, 0x9e, 0xe3, 0xea, 0x67, 0x13,
-	0x5f, 0x9f, 0xf8, 0x35, 0xe3, 0x79, 0x62, 0x33, 0x8b, 0x25, 0x1f, 0xc3,
-	0x71, 0xb4, 0x0b, 0x6b, 0xdb, 0xfc, 0x36, 0x65, 0xe4, 0x7c, 0x24, 0x30,
-	0x7a, 0x3e, 0x14, 0x78, 0x50, 0xbf, 0x73, 0x61, 0xbd, 0xb3, 0x2c, 0x93,
-	0xae, 0x43, 0xde, 0x1c, 0x1c, 0x81, 0x2c, 0x8c, 0x42, 0xd5, 0x3f, 0xe4,
-	0xac, 0x17, 0x90, 0x34, 0xf5, 0x11, 0xfc, 0xcc, 0xe4, 0x8b, 0xae, 0x64,
-	0x0b, 0xf3, 0x01, 0x83, 0x47, 0xb3, 0xd1, 0xee, 0x43, 0xfb, 0xe7, 0x5e,
-	0x7b, 0xa7, 0x64, 0x67, 0x25, 0xf5, 0xbe, 0xfa, 0xc3, 0x2f, 0x7b, 0x7d,
-	0x83, 0xe8, 0x03, 0x67, 0x5e, 0x64, 0xdf, 0x45, 0xaf, 0x8f, 0x67, 0xc2,
-	0x5a, 0x7d, 0x5c, 0xf9, 0x2a, 0x6b, 0x8f, 0x8b, 0x7e, 0xd7, 0xa0, 0xb5,
-	0xf8, 0x0f, 0x3a, 0x8d, 0x6e, 0x23, 0x26, 0xf0, 0x9f, 0x9d, 0x8c, 0xc1,
-	0x8a, 0x90, 0xaf, 0xbb, 0xa0, 0x13, 0xff, 0xba, 0x75, 0xa5, 0x6d, 0x0d,
-	0x7d, 0x5c, 0x85, 0xd1, 0xfe, 0x58, 0xba, 0x17, 0xff, 0xed, 0xe1, 0x79,
-	0x9f, 0xc0, 0xbb, 0xe1, 0xac, 0x0a, 0xc4, 0x8d, 0xc7, 0x21, 0xdb, 0x2d,
-	0xb2, 0xfe, 0x2c, 0xe9, 0xd5, 0x0b, 0x5d, 0x9d, 0x82, 0xdc, 0xba, 0xb2,
-	0x50, 0x0a, 0x05, 0x46, 0x0a, 0x29, 0x31, 0x78, 0x6a, 0x4b, 0x32, 0xd1,
-	0x94, 0x9c, 0x1e, 0x48, 0xf4, 0x30, 0x0f, 0x99, 0xed, 0x77, 0xe5, 0x52,
-	0x89, 0xf6, 0x38, 0x27, 0x97, 0x07, 0x12, 0x6e, 0x51, 0x88, 0x8b, 0x71,
-	0xe5, 0x32, 0x64, 0xf3, 0x9d, 0xf3, 0xbb, 0xe5, 0x48, 0x41, 0xfd, 0xe0,
-	0xde, 0xb0, 0xbc, 0x20, 0x97, 0x06, 0x5e, 0xb8, 0x75, 0xc9, 0x3d, 0x84,
-	0x33, 0x25, 0x1f, 0x1e, 0xee, 0x32, 0xfb, 0x56, 0x1c, 0x92, 0x30, 0x1f,
-	0xa2, 0x35, 0x35, 0xa7, 0x51, 0xd2, 0xfb, 0x23, 0x5e, 0x5c, 0x0e, 0x9f,
-	0x3b, 0x30, 0x60, 0xea, 0x29, 0x01, 0x7f, 0x9f, 0x61, 0xf8, 0x31, 0x7c,
-	0xce, 0xa7, 0x8d, 0x3f, 0x4f, 0x67, 0x20, 0x3d, 0xdb, 0x2a, 0xa1, 0x8b,
-	0xf7, 0x81, 0xae, 0x21, 0x39, 0xd4, 0x5f, 0x2e, 0x7f, 0xd3, 0x0d, 0xc5,
-	0x27, 0x10, 0xa3, 0x60, 0xff, 0xb2, 0xee, 0xc5, 0x36, 0xd0, 0xa4, 0x49,
-	0xa2, 0x2f, 0xfa, 0xeb, 0x35, 0x7a, 0x58, 0x86, 0x8b, 0xeb, 0x8c, 0x2d,
-	0xf3, 0xb1, 0x0d, 0xfe, 0x7c, 0x06, 0x53, 0xd6, 0x6d, 0xf5, 0x07, 0xbc,
-	0xef, 0x24, 0xbc, 0xf6, 0x3d, 0x81, 0x07, 0x42, 0xed, 0x12, 0x72, 0x9e,
-	0xdf, 0x48, 0x6c, 0xe4, 0x52, 0xc1, 0xef, 0x87, 0x9f, 0x18, 0xf2, 0xfd,
-	0x61, 0xd9, 0xbe, 0x72, 0xd6, 0xb2, 0xbd, 0x7b, 0xf1, 0x5b, 0xde, 0x9c,
-	0x29, 0x6f, 0x2c, 0x62, 0x8e, 0xd8, 0x5a, 0xb5, 0x4f, 0x66, 0xec, 0xa7,
-	0xf2, 0x74, 0x7f, 0xe2, 0x15, 0xc5, 0xc9, 0x56, 0x9e, 0xe1, 0x7d, 0xc4,
-	0x90, 0x25, 0x7d, 0x26, 0xb6, 0x07, 0xf4, 0xcd, 0xc4, 0xee, 0xb6, 0xe7,
-	0xad, 0x60, 0xc0, 0xf8, 0x23, 0x0d, 0xf2, 0xbd, 0x28, 0xec, 0x36, 0xbf,
-	0x61, 0x61, 0xfe, 0xcb, 0xbd, 0xed, 0xf9, 0x29, 0xec, 0x4b, 0x9c, 0x49,
-	0x5a, 0x13, 0xd8, 0x1f, 0xcf, 0x80, 0x18, 0x50, 0x0b, 0x74, 0xea, 0xc4,
-	0xfb, 0x21, 0x7e, 0xea, 0xf7, 0xdf, 0x7f, 0x1d, 0x74, 0x18, 0xf7, 0x6f,
-	0x70, 0x61, 0x62, 0x31, 0x17, 0x32, 0xec, 0x61, 0x60, 0xab, 0xe5, 0xd6,
-	0xc7, 0xc6, 0xfa, 0x78, 0x3a, 0x62, 0x94, 0x62, 0xf0, 0x03, 0x29, 0x13,
-	0xe4, 0xcd, 0x0e, 0xf4, 0xaf, 0xf9, 0x24, 0xa5, 0xaf, 0xee, 0xf7, 0x7d,
-	0x58, 0xc1, 0x76, 0x4f, 0x14, 0xf6, 0x19, 0x6c, 0x9e, 0xb5, 0x2c, 0xa9,
-	0xae, 0xa4, 0x3d, 0x89, 0xfd, 0xa6, 0x43, 0x89, 0x62, 0x4e, 0x62, 0x32,
-	0x0f, 0x7d, 0xf1, 0x1a, 0x64, 0xff, 0x5a, 0x29, 0x1e, 0x48, 0x63, 0x4f,
-	0x87, 0x0b, 0x43, 0x32, 0x31, 0xab, 0xdf, 0x7e, 0x41, 0xef, 0x0f, 0xc9,
-	0x5c, 0x21, 0xd1, 0x33, 0x0f, 0xfe, 0x9b, 0x2f, 0x10, 0x5f, 0xd4, 0x1b,
-	0x1f, 0xc5, 0x8c, 0x4b, 0x85, 0xcd, 0xb0, 0x0f, 0x92, 0xba, 0x04, 0xff,
-	0xe7, 0x52, 0xa9, 0x07, 0x7c, 0x86, 0xfb, 0x25, 0x07, 0xbf, 0xd0, 0x99,
-	0xa5, 0x01, 0xc8, 0x39, 0xf7, 0x62, 0xcb, 0xc2, 0x56, 0x9c, 0x1d, 0x71,
-	0x44, 0x8a, 0x1f, 0xff, 0x2f, 0xce, 0xd7, 0x7f, 0xef, 0x1d, 0x6a, 0xa7,
-	0xe7, 0x75, 0x5f, 0xb0, 0xcb, 0x88, 0x01, 0xb2, 0xfd, 0xc6, 0x6e, 0xa7,
-	0x23, 0x6d, 0x92, 0xbe, 0x9b, 0x76, 0xbc, 0x5d, 0x63, 0x44, 0xe5, 0xc5,
-	0x08, 0xef, 0xbf, 0xb3, 0xd1, 0xd0, 0x2f, 0x5c, 0xd7, 0xbe, 0x8e, 0xdf,
-	0x56, 0xe9, 0x70, 0xf8, 0x6b, 0xe3, 0xf7, 0xed, 0x8d, 0xac, 0xef, 0x76,
-	0x38, 0x49, 0xac, 0xf5, 0x5b, 0x2f, 0x5f, 0x80, 0xeb, 0x79, 0x3e, 0xb3,
-	0xc1, 0x5b, 0x97, 0xf3, 0xb6, 0x62, 0x9e, 0x16, 0x6f, 0xad, 0x56, 0xcd,
-	0x4f, 0x9a, 0xb5, 0x10, 0xe3, 0x16, 0xfe, 0xb2, 0x51, 0xbf, 0x35, 0x86,
-	0xbd, 0xa8, 0x6d, 0xff, 0x79, 0x23, 0x71, 0x73, 0x1d, 0x4e, 0xab, 0x62,
-	0x3c, 0x6f, 0xb6, 0xb7, 0xe3, 0x9a, 0x6b, 0x72, 0x8c, 0xc9, 0x87, 0xcf,
-	0x95, 0x38, 0x3f, 0xdb, 0x29, 0x39, 0xa1, 0xf9, 0x0c, 0x83, 0xe5, 0x9b,
-	0x2b, 0xdc, 0x2f, 0x13, 0xe7, 0x15, 0x5f, 0x37, 0x93, 0xb7, 0xf8, 0xdd,
-	0x0b, 0xbf, 0x97, 0xa3, 0x2f, 0x31, 0x26, 0x07, 0x71, 0x7e, 0x97, 0xe1,
-	0x53, 0x2d, 0x99, 0xef, 0x62, 0xf1, 0x77, 0x00, 0xe7, 0x12, 0x82, 0x8c,
-	0x51, 0x46, 0x29, 0x53, 0x38, 0xbf, 0x71, 0x5b, 0xde, 0x1d, 0xa0, 0x3c,
-	0x0f, 0xc8, 0x95, 0x8a, 0x3c, 0xe7, 0x20, 0xcf, 0x94, 0xe5, 0x1c, 0x64,
-	0xda, 0xf0, 0xf5, 0x7e, 0x7e, 0x67, 0x1d, 0x83, 0xbd, 0x52, 0x1f, 0xe2,
-	0x25, 0xf0, 0xb5, 0xed, 0x7d, 0x2b, 0x15, 0xd0, 0x1c, 0x4e, 0x76, 0xb6,
-	0xc1, 0xfb, 0x0e, 0x00, 0xd7, 0x57, 0x9e, 0x93, 0xf4, 0x6c, 0x33, 0xbf,
-	0xe7, 0xea, 0xe2, 0x99, 0x65, 0xaf, 0xf0, 0xdf, 0xe7, 0x45, 0xe2, 0x4d,
-	0xe9, 0xcf, 0xf2, 0x9a, 0x71, 0xde, 0x26, 0x8c, 0x19, 0x04, 0x9d, 0x9b,
-	0x31, 0x3f, 0xf7, 0xb8, 0xda, 0x38, 0xde, 0x0f, 0x55, 0xe1, 0x53, 0x7d,
-	0x7a, 0xaf, 0xd5, 0x35, 0xb3, 0xfd, 0xcd, 0xde, 0xfb, 0xf1, 0x1c, 0x94,
-	0xef, 0xc1, 0xb7, 0xf4, 0x89, 0xc9, 0x2f, 0x29, 0x3d, 0x87, 0xb9, 0x02,
-	0xf9, 0x37, 0xa4, 0x39, 0x8c, 0x2c, 0x6c, 0xcb, 0x5e, 0x1d, 0x1f, 0x5b,
-	0x91, 0xef, 0xae, 0x80, 0xc6, 0xdd, 0xd9, 0xc2, 0x1a, 0xe9, 0x56, 0x1d,
-	0xd4, 0xe5, 0xf1, 0x36, 0xec, 0x85, 0x62, 0xb9, 0x0f, 0xc8, 0xf1, 0xd2,
-	0x20, 0xe8, 0x10, 0x93, 0xa7, 0xe0, 0x37, 0x3f, 0x53, 0xba, 0x43, 0x96,
-	0x23, 0xd8, 0x57, 0x45, 0xc6, 0x86, 0xe5, 0xfb, 0xf3, 0x09, 0xef, 0x3a,
-	0xe1, 0x2e, 0x5b, 0x3b, 0xb0, 0x07, 0xca, 0x13, 0xe5, 0x8a, 0xe3, 0x82,
-	0x88, 0x45, 0x38, 0xef, 0xd3, 0x46, 0xb7, 0x61, 0xde, 0x62, 0x84, 0xf2,
-	0xcb, 0xbd, 0x85, 0x3c, 0x99, 0x65, 0x5c, 0xc5, 0x77, 0x36, 0x36, 0x29,
-	0x53, 0x73, 0x16, 0x09, 0xc5, 0x81, 0xae, 0x9c, 0x81, 0x3f, 0x8f, 0x2f,
-	0x97, 0xfe, 0x77, 0x14, 0xd4, 0xa3, 0xb0, 0x95, 0x05, 0xd8, 0xca, 0x02,
-	0x6c, 0x24, 0x64, 0xe1, 0x5a, 0x01, 0x36, 0xb2, 0x00, 0x1b, 0x09, 0x7d,
-	0xf6, 0x3a, 0x62, 0xbb, 0xd7, 0xc0, 0x43, 0xc6, 0xd7, 0x3e, 0x4a, 0x5f,
-	0x1b, 0x7f, 0xff, 0x03, 0x4c, 0x03, 0x3a, 0xe1, 0xd4, 0x71, 0x00, 0x00,
-	0x00 };
+	0xec, 0x5b, 0x5f, 0x6c, 0x5b, 0xd7, 0x79, 0xff, 0xee, 0x21, 0x25, 0x51,
+	0xb2, 0xfe, 0x5c, 0xc9, 0x8c, 0x43, 0x27, 0x4a, 0x43, 0x4a, 0x57, 0x12,
+	0x13, 0x69, 0xe9, 0x95, 0xc6, 0x26, 0x2a, 0x46, 0x34, 0x2c, 0x29, 0xdb,
+	0x4a, 0xe3, 0x07, 0xc5, 0xf5, 0xda, 0xac, 0xeb, 0x30, 0x81, 0xb2, 0xb1,
+	0xec, 0x61, 0x83, 0x67, 0xac, 0x41, 0xb6, 0xb9, 0x30, 0x41, 0x29, 0x8e,
+	0x92, 0xd2, 0x22, 0x67, 0x2b, 0x73, 0xb1, 0x65, 0x80, 0x42, 0x49, 0x76,
+	0xb6, 0xd1, 0x62, 0xda, 0xbd, 0x74, 0x45, 0x1c, 0x0b, 0x8a, 0xe7, 0xe5,
+	0xa1, 0x0f, 0x69, 0x17, 0x60, 0xed, 0xd0, 0x61, 0x86, 0xe2, 0xda, 0x79,
+	0x28, 0xb6, 0x6c, 0x40, 0x96, 0x6c, 0x71, 0x73, 0xf7, 0xfb, 0x9d, 0x7b,
+	0xaf, 0x4c, 0x2b, 0x1a, 0x9a, 0x87, 0x3d, 0xde, 0x03, 0x08, 0xe7, 0x9e,
+	0x73, 0xbe, 0xf3, 0x9d, 0xef, 0xfb, 0xce, 0xf7, 0xf7, 0xd0, 0xfe, 0xc3,
+	0x76, 0x69, 0x13, 0xaf, 0x75, 0xe0, 0x2f, 0x75, 0xec, 0x99, 0xe3, 0x63,
+	0x0f, 0xa5, 0x1e, 0xe2, 0x38, 0xa4, 0xc2, 0x61, 0xf6, 0x86, 0x04, 0x2d,
+	0x68, 0x41, 0x0b, 0x5a, 0xd0, 0x82, 0x16, 0xb4, 0xa0, 0x05, 0x2d, 0x68,
+	0x41, 0x0b, 0x5a, 0xd0, 0x82, 0x16, 0xb4, 0xa0, 0x05, 0x2d, 0x68, 0x41,
+	0x0b, 0x5a, 0xd0, 0x82, 0x16, 0xb4, 0xa0, 0x05, 0x2d, 0x68, 0x41, 0x0b,
+	0x5a, 0xd0, 0x82, 0x16, 0xb4, 0xa0, 0x05, 0x2d, 0x68, 0x41, 0x0b, 0x5a,
+	0xd0, 0x82, 0x16, 0xb4, 0xa0, 0x05, 0x2d, 0x68, 0x41, 0x0b, 0x5a, 0xd0,
+	0x82, 0x16, 0xb4, 0xa0, 0x05, 0xed, 0xff, 0xb3, 0x85, 0x44, 0x4c, 0xf6,
+	0x1d, 0xde, 0x9f, 0x44, 0x54, 0x3a, 0x7e, 0x3c, 0x6b, 0x49, 0x24, 0x94,
+	0xbe, 0xf2, 0xf4, 0x8c, 0x25, 0x92, 0xa9, 0x0d, 0xc7, 0x73, 0xf2, 0x0b,
+	0xa7, 0x10, 0x0d, 0x0b, 0xe7, 0xef, 0x4b, 0xdf, 0x3a, 0x79, 0xe9, 0x91,
+	0xc4, 0x7b, 0x4b, 0x21, 0x89, 0x98, 0xe9, 0xb7, 0x46, 0xcd, 0x41, 0x89,
+	0xf4, 0x62, 0xcf, 0x4b, 0x43, 0x97, 0xbb, 0xa4, 0xd3, 0xc7, 0x25, 0x52,
+	0x2d, 0x25, 0xec, 0xfd, 0x32, 0x6c, 0x6e, 0x48, 0x58, 0x32, 0x38, 0xe3,
+	0x7c, 0x4d, 0xa4, 0x58, 0x32, 0x88, 0x43, 0x8a, 0xb5, 0x88, 0x5c, 0x0b,
+	0x11, 0xea, 0x7b, 0x46, 0xb6, 0xfc, 0xb1, 0x93, 0x09, 0xe3, 0x5c, 0x0b,
+	0xdf, 0x75, 0x7f, 0x3e, 0x22, 0x2a, 0x9d, 0x48, 0x66, 0x43, 0x93, 0x52,
+	0x5d, 0x74, 0x9c, 0x39, 0xfb, 0x5e, 0xe0, 0xe8, 0x91, 0x39, 0xcb, 0x1d,
+	0x67, 0xed, 0x07, 0xcd, 0x09, 0xb9, 0x1b, 0x73, 0x21, 0x51, 0xd6, 0x3d,
+	0xf8, 0x8b, 0x1b, 0xb9, 0xb3, 0xdf, 0x32, 0xb2, 0xcb, 0xed, 0x52, 0x2c,
+	0x3b, 0x32, 0x63, 0x4b, 0x26, 0x6b, 0xb7, 0x62, 0xfd, 0x63, 0x67, 0x66,
+	0x6b, 0xcf, 0xb0, 0x99, 0x93, 0x26, 0xc9, 0x44, 0x63, 0x80, 0x59, 0x34,
+	0x72, 0x17, 0xfe, 0xae, 0x5d, 0xda, 0x40, 0x4f, 0x8a, 0xe3, 0x8f, 0x9d,
+	0x90, 0x65, 0x61, 0x9d, 0xe7, 0x63, 0x5c, 0x27, 0x5e, 0x7e, 0x13, 0xe7,
+	0x35, 0xe7, 0xd2, 0x50, 0x4c, 0xbe, 0x5b, 0x8f, 0xca, 0x77, 0xea, 0xa6,
+	0xbc, 0x5a, 0xef, 0x95, 0xcb, 0x75, 0xc7, 0xf9, 0x8e, 0xed, 0x38, 0x6f,
+	0xe1, 0xef, 0x3f, 0xed, 0x2d, 0x1e, 0xd0, 0x0a, 0xc6, 0x44, 0xfd, 0x2f,
+	0xda, 0xa5, 0x33, 0x11, 0x17, 0xd5, 0x2e, 0xb3, 0xe5, 0x98, 0xcc, 0x95,
+	0x4b, 0xc6, 0x13, 0x17, 0x16, 0x8c, 0xa9, 0x0b, 0x15, 0x9c, 0x19, 0xc6,
+	0x9c, 0x14, 0x8a, 0xf6, 0x2b, 0x46, 0xae, 0x3e, 0x6f, 0x1c, 0xba, 0xd0,
+	0x09, 0x1a, 0x79, 0xfe, 0x1e, 0x23, 0x7b, 0xf6, 0x96, 0x64, 0x6d, 0xca,
+	0x38, 0x61, 0x7e, 0x0d, 0x62, 0xcf, 0x96, 0x48, 0x73, 0xb3, 0x47, 0xaf,
+	0xe3, 0xa8, 0xb4, 0x73, 0x32, 0x9b, 0xb2, 0xcc, 0xa2, 0x90, 0x3e, 0x3d,
+	0x77, 0xd9, 0xa5, 0xf9, 0xbc, 0x91, 0xbd, 0xd0, 0x6e, 0xe4, 0xce, 0x85,
+	0x41, 0x87, 0xf4, 0x86, 0x84, 0xfb, 0x06, 0x62, 0x79, 0xa9, 0xe1, 0x0c,
+	0x31, 0x55, 0x9a, 0x72, 0x05, 0xcd, 0xa0, 0xe5, 0xbb, 0x65, 0xf0, 0x50,
+	0x06, 0x0f, 0x65, 0xf2, 0x16, 0x97, 0x4b, 0x43, 0x3e, 0x6f, 0x8e, 0xf3,
+	0x23, 0x9b, 0xb4, 0x27, 0xe2, 0x19, 0xe5, 0xf3, 0xe9, 0x38, 0xff, 0x61,
+	0x93, 0x57, 0xf2, 0xe3, 0x38, 0xaf, 0xda, 0x31, 0xd0, 0xee, 0x5c, 0x56,
+	0x56, 0x09, 0xbc, 0x58, 0xc0, 0x4f, 0x59, 0x2f, 0x80, 0x87, 0x79, 0xf0,
+	0x77, 0x1e, 0xbc, 0x55, 0x40, 0xc7, 0x2f, 0x3b, 0xaf, 0x60, 0xe4, 0x86,
+	0xb6, 0xe4, 0x15, 0xa7, 0x8c, 0xf3, 0x2b, 0x0a, 0xb2, 0xde, 0x25, 0xf9,
+	0x25, 0x53, 0xa6, 0x57, 0xfc, 0xfd, 0xbe, 0x1e, 0x1c, 0x93, 0x83, 0xe5,
+	0x1e, 0xc8, 0x86, 0xb2, 0x4c, 0xd8, 0x22, 0x0e, 0x64, 0x54, 0x4c, 0x2a,
+	0x11, 0x23, 0x6f, 0x9f, 0xd4, 0xf7, 0xbf, 0x62, 0x49, 0x26, 0x6f, 0x53,
+	0x8e, 0x12, 0xcf, 0xdb, 0x85, 0x58, 0x18, 0xfa, 0xb6, 0x62, 0x15, 0xcc,
+	0xb0, 0x50, 0x8e, 0x89, 0xd8, 0x1f, 0x43, 0x96, 0x47, 0x4b, 0x92, 0xf9,
+	0x52, 0xc9, 0x97, 0xb1, 0x2b, 0xdf, 0xc7, 0x4b, 0x5f, 0xec, 0x90, 0x36,
+	0xf5, 0x99, 0x26, 0xf9, 0x3d, 0xec, 0x25, 0xee, 0x3b, 0xf6, 0x62, 0x9f,
+	0x0b, 0xe7, 0xee, 0x4d, 0x3c, 0x29, 0x42, 0xd8, 0x62, 0x7f, 0x93, 0xb6,
+	0x11, 0x31, 0xb2, 0x56, 0x21, 0x16, 0x02, 0x5c, 0x5e, 0x8a, 0xa3, 0xde,
+	0x5c, 0x53, 0xd6, 0xba, 0x15, 0x9a, 0xb3, 0x13, 0xf1, 0xa2, 0xdc, 0x0a,
+	0x5d, 0xb5, 0xf5, 0x5c, 0x6b, 0xd6, 0x72, 0x64, 0x15, 0xd8, 0x9f, 0x83,
+	0x3d, 0x6c, 0x80, 0xa3, 0xdf, 0x2d, 0xe9, 0xf9, 0x0e, 0xec, 0x4f, 0x36,
+	0x01, 0x67, 0x9b, 0x24, 0x92, 0x55, 0xcc, 0x5f, 0x75, 0xe7, 0xbb, 0x5d,
+	0xbc, 0xc5, 0xfe, 0x36, 0x8d, 0x5b, 0xe4, 0x15, 0x77, 0xfe, 0x2e, 0x17,
+	0x77, 0xf1, 0x01, 0xcc, 0x03, 0xff, 0xe0, 0xe4, 0x90, 0xa1, 0xe7, 0xf7,
+	0xd2, 0x9e, 0x7e, 0xa7, 0x74, 0x2b, 0xb4, 0x6a, 0x3b, 0x92, 0x1b, 0x1d,
+	0x9c, 0x1c, 0x34, 0x5c, 0x7c, 0xa7, 0xdc, 0x7d, 0xf7, 0xb9, 0xf8, 0x06,
+	0x27, 0x93, 0x86, 0x8b, 0x6f, 0xa5, 0xa4, 0xf7, 0x4a, 0xbe, 0x44, 0xd8,
+	0xc1, 0x49, 0xcb, 0xb8, 0x4f, 0xa6, 0xbb, 0x07, 0x27, 0xfb, 0x0c, 0xf5,
+	0x99, 0x5d, 0x2e, 0x1f, 0x09, 0x9f, 0x86, 0x5d, 0x9a, 0x06, 0x9e, 0xab,
+	0xe7, 0x07, 0xb2, 0x56, 0xf1, 0x81, 0x5d, 0xfa, 0x7c, 0x9e, 0xa9, 0xe7,
+	0x1e, 0x20, 0x5d, 0x3c, 0x7b, 0x66, 0xf4, 0x8e, 0x73, 0x7f, 0xe5, 0xb6,
+	0x7c, 0x76, 0x3a, 0x93, 0xe7, 0x49, 0x24, 0x9c, 0x0e, 0x8f, 0xce, 0x95,
+	0x8e, 0x49, 0xb6, 0x1c, 0x97, 0xd9, 0x91, 0x56, 0x99, 0x36, 0xfb, 0xa7,
+	0x0f, 0x0a, 0x7d, 0x4f, 0x64, 0x74, 0xc6, 0xbb, 0xc3, 0x9c, 0x18, 0x32,
+	0x0b, 0x1e, 0x0f, 0xd6, 0x24, 0x62, 0x00, 0xbe, 0xbf, 0x16, 0x96, 0xe7,
+	0xeb, 0x86, 0x34, 0x6b, 0xfb, 0x4c, 0x98, 0xeb, 0xd0, 0xc3, 0x67, 0xcb,
+	0xd4, 0x63, 0xea, 0xac, 0x64, 0xaa, 0x5a, 0x67, 0x7d, 0x7b, 0x6d, 0xe3,
+	0xdd, 0x16, 0x0a, 0x02, 0x73, 0x4c, 0x5b, 0x66, 0x55, 0x5a, 0x24, 0x33,
+	0x25, 0x85, 0xaa, 0xbd, 0x65, 0x3f, 0xb1, 0x65, 0xd9, 0x80, 0x1e, 0x88,
+	0x99, 0x4d, 0x71, 0x9e, 0xf0, 0x0d, 0xb0, 0xa6, 0x6b, 0x7b, 0x21, 0xd8,
+	0xde, 0x4c, 0x8a, 0xb0, 0x52, 0xd0, 0xfe, 0xa2, 0x0e, 0x7d, 0xac, 0xdf,
+	0xd7, 0xe1, 0xfa, 0xbb, 0x08, 0x6c, 0xb4, 0x1d, 0x76, 0xfe, 0x19, 0xd8,
+	0x60, 0xaf, 0x91, 0x3d, 0xe7, 0x38, 0xf0, 0x3f, 0x51, 0x25, 0xb4, 0x41,
+	0xd8, 0x7b, 0x9d, 0x6b, 0xed, 0x98, 0x17, 0x73, 0xd6, 0xee, 0x06, 0x8f,
+	0x8e, 0x33, 0x69, 0xc7, 0xa5, 0x68, 0x77, 0x61, 0x5f, 0x93, 0xf4, 0x58,
+	0xd4, 0x79, 0xda, 0xf5, 0x2e, 0x9c, 0x67, 0x70, 0xdc, 0x89, 0xf3, 0x3a,
+	0x30, 0x17, 0x9b, 0xa5, 0x2d, 0xa7, 0xe8, 0xb7, 0x5c, 0x1f, 0x2a, 0x72,
+	0x1d, 0xb4, 0x72, 0x8f, 0x86, 0x8b, 0xb4, 0xa4, 0x53, 0x72, 0xb3, 0xb4,
+	0x57, 0xae, 0x45, 0x29, 0x03, 0xe0, 0x2c, 0xc3, 0x27, 0x46, 0x0d, 0xd0,
+	0x4f, 0xba, 0xe9, 0x03, 0x77, 0x7b, 0x63, 0xe3, 0x7e, 0xf7, 0x0c, 0x31,
+	0x43, 0xe9, 0x4e, 0xc9, 0xe9, 0x39, 0x51, 0x6a, 0x74, 0x97, 0xb7, 0xde,
+	0x69, 0xec, 0x3f, 0xa7, 0xe4, 0xc0, 0xc3, 0xf0, 0x5b, 0x38, 0xeb, 0xaa,
+	0xe5, 0x38, 0x57, 0xed, 0xf7, 0x61, 0xf7, 0x4a, 0x9a, 0xac, 0x6b, 0x9d,
+	0xd2, 0x46, 0x7b, 0x36, 0x1a, 0x64, 0x18, 0x93, 0x53, 0x65, 0xee, 0x29,
+	0x48, 0xd8, 0x22, 0x0c, 0xe1, 0xff, 0x05, 0x70, 0x21, 0x69, 0x81, 0x3d,
+	0x6e, 0xd8, 0x51, 0xd2, 0xdb, 0xe5, 0xc2, 0x77, 0xe3, 0x0c, 0xd2, 0x4e,
+	0xfb, 0x73, 0xb4, 0xfd, 0x65, 0x43, 0x2a, 0x33, 0xb1, 0x08, 0x6b, 0x1a,
+	0xa1, 0xbc, 0xb3, 0xdd, 0x70, 0xff, 0x32, 0x3b, 0x54, 0x30, 0x95, 0xbe,
+	0x6f, 0x91, 0x5c, 0xe9, 0x7e, 0x99, 0xb3, 0x71, 0x9e, 0x15, 0x06, 0xcd,
+	0xf4, 0x35, 0x03, 0x85, 0x90, 0x82, 0x95, 0xf5, 0x50, 0x56, 0x3e, 0xad,
+	0xff, 0x8c, 0xf3, 0x0a, 0x46, 0xd8, 0xe2, 0x19, 0xbf, 0xe5, 0xc9, 0x87,
+	0xba, 0x67, 0x4b, 0xb6, 0xd4, 0xce, 0x31, 0xe8, 0x68, 0xd3, 0x74, 0x84,
+	0xd2, 0xfa, 0xee, 0x0c, 0x95, 0xf6, 0x63, 0x00, 0x41, 0xef, 0xc0, 0x03,
+	0x3e, 0xb8, 0xd7, 0xc2, 0xde, 0x08, 0x68, 0xec, 0x68, 0xa0, 0xbf, 0x8d,
+	0xf0, 0x90, 0x55, 0xc4, 0x3b, 0x43, 0xf3, 0x6d, 0xb8, 0x7c, 0xfb, 0xb2,
+	0x7a, 0x1d, 0xb2, 0xfa, 0xc8, 0x39, 0x30, 0x46, 0x1c, 0x29, 0xe0, 0x80,
+	0xdc, 0x4d, 0xfa, 0x2c, 0xfa, 0x29, 0x73, 0x0b, 0x17, 0x6c, 0x41, 0x85,
+	0xd2, 0xed, 0x92, 0x33, 0x75, 0x1c, 0x00, 0xec, 0xb8, 0x68, 0x3f, 0x6f,
+	0x91, 0x47, 0x6f, 0x6c, 0x25, 0xb4, 0xde, 0xe4, 0x2b, 0x8c, 0x05, 0x45,
+	0xd0, 0xb6, 0x9e, 0x50, 0x9a, 0xb5, 0x76, 0xc8, 0x5c, 0x22, 0x4d, 0xe9,
+	0xb7, 0x64, 0xb5, 0xa4, 0xf6, 0x34, 0x4b, 0x97, 0x4c, 0x41, 0x46, 0xd5,
+	0x71, 0xc4, 0xb0, 0x91, 0x76, 0x09, 0x3d, 0xc4, 0x58, 0x10, 0x03, 0xad,
+	0xeb, 0x09, 0x53, 0x6e, 0x39, 0x6a, 0x10, 0xfb, 0x47, 0x70, 0x0f, 0x87,
+	0x79, 0xa7, 0xca, 0x83, 0x23, 0x4c, 0x88, 0x32, 0xef, 0x69, 0x16, 0xe2,
+	0xe6, 0xda, 0x70, 0xcc, 0x14, 0xce, 0x23, 0x5e, 0x4e, 0x71, 0x2f, 0xf9,
+	0x73, 0xf7, 0x7c, 0x92, 0x3f, 0x7f, 0x9d, 0x32, 0xa3, 0xec, 0xa0, 0x63,
+	0xa0, 0xa9, 0x1b, 0x72, 0x1b, 0x5d, 0x80, 0x4f, 0xb4, 0x1f, 0xd7, 0x3a,
+	0xdc, 0x37, 0x76, 0xaf, 0x5c, 0x83, 0xdd, 0xc5, 0x95, 0x18, 0x55, 0x7b,
+	0xaf, 0x9e, 0x53, 0x96, 0x2f, 0x4f, 0xca, 0x60, 0xf7, 0x36, 0x19, 0x10,
+	0xe7, 0xce, 0x72, 0x38, 0x52, 0x21, 0x0d, 0x2e, 0x2d, 0x73, 0xd6, 0x7a,
+	0x22, 0x2c, 0x8d, 0xf4, 0x7c, 0xec, 0x28, 0xcb, 0x2a, 0xf4, 0x29, 0xe2,
+	0x6f, 0x16, 0xb5, 0x27, 0x2c, 0x4f, 0x8c, 0x19, 0x12, 0x3f, 0xa4, 0xe4,
+	0xd0, 0xc3, 0xc4, 0xf9, 0x13, 0xf2, 0x38, 0x9e, 0xe1, 0xfa, 0x18, 0x75,
+	0x21, 0x8c, 0x5e, 0xf3, 0x87, 0xb9, 0x46, 0x5d, 0x7f, 0xdd, 0xd3, 0xf5,
+	0x8f, 0x9c, 0x43, 0x63, 0x61, 0x0f, 0x36, 0xd2, 0x00, 0x2b, 0xb8, 0xef,
+	0x9d, 0x60, 0x09, 0xd3, 0xa8, 0x17, 0x84, 0x2d, 0xec, 0x00, 0x8b, 0xe0,
+	0xf4, 0x15, 0xda, 0x50, 0xb7, 0xe7, 0x33, 0x7c, 0x9b, 0xe2, 0x39, 0xec,
+	0x77, 0xb2, 0x3f, 0xee, 0xe3, 0x7e, 0xc2, 0x6f, 0x8f, 0xa7, 0xb8, 0x06,
+	0xd9, 0x31, 0xa6, 0xa2, 0x4d, 0xe2, 0x5b, 0xc1, 0xff, 0x34, 0xc6, 0x56,
+	0xce, 0x99, 0x18, 0x4f, 0xa0, 0xb7, 0x24, 0x5f, 0xa3, 0x1d, 0x71, 0x3f,
+	0x63, 0xed, 0xbb, 0x9e, 0xef, 0x6c, 0x9f, 0x0e, 0xa7, 0xa3, 0xf0, 0x9d,
+	0x32, 0x55, 0x2c, 0x9d, 0x44, 0x3e, 0x24, 0x85, 0x7b, 0xd2, 0xd4, 0x8b,
+	0xf6, 0x71, 0xf8, 0xc6, 0xa9, 0x62, 0x8d, 0x39, 0x11, 0xdc, 0x17, 0xf6,
+	0x21, 0x3e, 0x47, 0xd4, 0x42, 0xa4, 0x70, 0x6f, 0x9a, 0x3e, 0x39, 0x2e,
+	0xf1, 0xda, 0x7b, 0xc8, 0x39, 0x4c, 0xc9, 0x6a, 0x1d, 0xfb, 0xf6, 0x5e,
+	0xd2, 0x5c, 0x44, 0xfe, 0x10, 0x4e, 0x4b, 0x58, 0xa5, 0x9b, 0x23, 0xb3,
+	0xa9, 0x76, 0xe4, 0x59, 0x93, 0x7b, 0xd5, 0xda, 0xc1, 0xbd, 0xa1, 0xb5,
+	0x3d, 0xd3, 0x4d, 0xe9, 0xc2, 0x5e, 0xb5, 0x20, 0xb2, 0x5c, 0x12, 0x85,
+	0x9c, 0x26, 0x76, 0x44, 0x30, 0x5e, 0xfb, 0xf2, 0x97, 0x55, 0x3a, 0x24,
+	0xf9, 0xa8, 0x9c, 0x58, 0x49, 0x85, 0x99, 0x3f, 0xc6, 0xa7, 0xe4, 0x04,
+	0x72, 0xc6, 0x67, 0x64, 0xb6, 0x04, 0xba, 0x34, 0xdf, 0x31, 0xf0, 0xdb,
+	0x0b, 0xdc, 0xa4, 0x3d, 0x0a, 0xdf, 0xea, 0xd2, 0x0e, 0x9a, 0x33, 0x39,
+	0xe6, 0x48, 0x29, 0xc6, 0x94, 0xf7, 0xa0, 0x27, 0xb4, 0x93, 0x9f, 0xcb,
+	0xaa, 0xd5, 0x2a, 0x79, 0xd7, 0x2f, 0x68, 0x3d, 0x0d, 0xa7, 0xdf, 0xf5,
+	0xd6, 0xae, 0x63, 0x8d, 0xfa, 0xba, 0xab, 0xe1, 0xee, 0xbe, 0xa5, 0xf3,
+	0x9c, 0xab, 0x36, 0xbf, 0x09, 0xfb, 0x83, 0x51, 0x17, 0xf6, 0xcd, 0xd1,
+	0x55, 0xeb, 0x2b, 0x5d, 0xd2, 0x86, 0x73, 0xca, 0x3c, 0x27, 0x4a, 0xdf,
+	0x8a, 0xf5, 0x6b, 0x1e, 0xae, 0x9f, 0x02, 0x57, 0x3b, 0xe9, 0x46, 0x0b,
+	0x63, 0x1d, 0xf4, 0x21, 0xdf, 0xc9, 0x6f, 0xf9, 0x18, 0xc2, 0xbe, 0xe6,
+	0xe1, 0xfa, 0x5e, 0x03, 0x2e, 0xae, 0xb1, 0xe7, 0x99, 0x38, 0xbb, 0x8d,
+	0xbc, 0x91, 0x1f, 0xde, 0x01, 0xef, 0x23, 0x69, 0x4c, 0xc1, 0xa7, 0x4f,
+	0xd5, 0x75, 0x5e, 0x67, 0xe4, 0xca, 0xc8, 0xb7, 0xea, 0x2f, 0x82, 0x46,
+	0xe4, 0x61, 0xf5, 0x01, 0x2f, 0xd7, 0xa6, 0xad, 0xac, 0x6b, 0x9f, 0x45,
+	0x7f, 0x53, 0xd4, 0xf6, 0x74, 0x05, 0x63, 0x9d, 0x67, 0xe3, 0x6e, 0xae,
+	0x48, 0x5f, 0xad, 0xdc, 0xe5, 0xfe, 0xbf, 0x6d, 0x53, 0x42, 0xfa, 0x3e,
+	0x19, 0xd7, 0xa8, 0x67, 0x77, 0xc3, 0x9f, 0x3b, 0x1f, 0x30, 0xbe, 0x4c,
+	0x31, 0xf6, 0x4c, 0x31, 0x66, 0x18, 0x9e, 0x1f, 0x8c, 0x37, 0xe0, 0x88,
+	0x03, 0xc7, 0x79, 0x4f, 0x6f, 0x4f, 0x7b, 0xb8, 0xfc, 0xdc, 0xd3, 0xf7,
+	0xa5, 0x2f, 0xdd, 0x73, 0xe7, 0xba, 0x61, 0xba, 0xe3, 0x66, 0xed, 0x87,
+	0x61, 0xf7, 0xa0, 0x3f, 0x3e, 0xad, 0xa0, 0x5f, 0xb9, 0x9a, 0x7b, 0x1f,
+	0xb0, 0x71, 0xe8, 0x1e, 0x3f, 0xfd, 0xbb, 0x75, 0x73, 0x6f, 0x57, 0x06,
+	0xbc, 0xd3, 0x0c, 0xf9, 0xce, 0x84, 0x49, 0x4b, 0x7d, 0x12, 0xfb, 0xe5,
+	0x18, 0x63, 0x62, 0x1e, 0x7c, 0x1c, 0x31, 0x87, 0xcd, 0x59, 0xe2, 0x8e,
+	0x0a, 0x70, 0x22, 0x8f, 0x4c, 0xb7, 0x78, 0xf7, 0xfc, 0x7d, 0x9e, 0x0f,
+	0xdc, 0xbb, 0x38, 0x46, 0xff, 0x7d, 0x8f, 0x9e, 0x1b, 0x9d, 0x2e, 0x3d,
+	0xfe, 0xfa, 0x80, 0x79, 0xe7, 0x78, 0x75, 0xaf, 0x27, 0x4f, 0x7c, 0x3f,
+	0xe3, 0xd1, 0xc5, 0xbb, 0x69, 0xa4, 0x89, 0xf7, 0xf2, 0x5f, 0xc0, 0xa3,
+	0xf3, 0x8c, 0x82, 0x4a, 0x23, 0x6f, 0x49, 0x31, 0x56, 0xc1, 0xe6, 0xc5,
+	0xc2, 0x9d, 0x24, 0xec, 0x69, 0xec, 0x7a, 0xb7, 0xc4, 0x7b, 0xbe, 0x05,
+	0x1f, 0xcd, 0x7b, 0xff, 0x50, 0xe6, 0x4a, 0xfd, 0x76, 0xb3, 0x41, 0x7b,
+	0x4d, 0x24, 0xcf, 0xcb, 0xb0, 0x7d, 0x5e, 0xe7, 0x4f, 0x89, 0xf8, 0x29,
+	0xa1, 0x6c, 0x6f, 0xc9, 0x80, 0xce, 0x6b, 0x3e, 0x14, 0x0b, 0x72, 0x99,
+	0x2a, 0xc3, 0xc6, 0xc6, 0xfe, 0xcd, 0xd1, 0xf9, 0x28, 0xf2, 0xa5, 0x1b,
+	0x3b, 0xe0, 0x7a, 0x53, 0xe3, 0x21, 0xbe, 0x46, 0x5c, 0x86, 0xb4, 0x8c,
+	0xf9, 0xf8, 0x2c, 0x99, 0xaf, 0xfb, 0x38, 0xc3, 0xf0, 0xc3, 0xf0, 0x01,
+	0x63, 0xbf, 0xe1, 0xe9, 0x0b, 0xbf, 0x7f, 0xe8, 0x30, 0x07, 0x52, 0xe9,
+	0x3f, 0xf7, 0xe6, 0xae, 0x50, 0x06, 0x18, 0xfb, 0x72, 0x7f, 0xd1, 0xf3,
+	0x39, 0x05, 0x23, 0x53, 0xa7, 0x0c, 0xa8, 0x2b, 0xb8, 0x7f, 0xad, 0x9f,
+	0xb0, 0x99, 0xf2, 0x17, 0x10, 0x1f, 0xbb, 0xdd, 0xbc, 0x01, 0xb5, 0x55,
+	0xa6, 0xce, 0xb9, 0xf5, 0x96, 0xac, 0xdd, 0xe4, 0xd9, 0xd2, 0x41, 0xcc,
+	0x4d, 0xe1, 0x8f, 0xb2, 0x23, 0xcc, 0x61, 0x7c, 0x67, 0x3c, 0x38, 0x19,
+	0xcf, 0x22, 0x66, 0x65, 0x0e, 0x4f, 0x60, 0x6c, 0x78, 0x35, 0x96, 0x96,
+	0x7b, 0x05, 0x39, 0x0a, 0xe4, 0x39, 0x00, 0x7e, 0xe2, 0x32, 0x51, 0xc7,
+	0x9d, 0x6f, 0xf9, 0xb3, 0x2d, 0x98, 0xc2, 0x6d, 0x18, 0xd7, 0xf7, 0x4d,
+	0xd4, 0x7f, 0xec, 0xd0, 0x1f, 0xfc, 0xad, 0xb6, 0x97, 0x78, 0x43, 0xde,
+	0x97, 0x31, 0x9e, 0x28, 0x4f, 0x1a, 0x87, 0xca, 0xdc, 0xa3, 0x5e, 0xea,
+	0x11, 0x2b, 0x9e, 0x55, 0xc8, 0x51, 0xc7, 0x3a, 0x71, 0xe6, 0x29, 0xe8,
+	0x46, 0xc1, 0x98, 0x1a, 0xea, 0x92, 0x7c, 0xb2, 0x07, 0x34, 0x3f, 0x82,
+	0x1e, 0xb1, 0xc3, 0xfa, 0x35, 0xcc, 0x43, 0x8f, 0x92, 0xb4, 0x8f, 0x56,
+	0x5d, 0x57, 0x4e, 0xeb, 0xb8, 0x35, 0xe0, 0xe9, 0xd6, 0x3f, 0x99, 0xae,
+	0x2e, 0x3d, 0x8d, 0xf1, 0x2e, 0xcc, 0xff, 0x26, 0x7a, 0xc4, 0xac, 0x31,
+	0x7f, 0x9e, 0x36, 0x38, 0x8e, 0xf9, 0xcf, 0x01, 0xc7, 0x9f, 0xe0, 0xfb,
+	0x7e, 0x7c, 0xff, 0xd1, 0xb6, 0xbd, 0xdf, 0xe0, 0xd9, 0x98, 0xcf, 0x6e,
+	0x9b, 0xf7, 0xfd, 0xb7, 0x8e, 0x93, 0xd2, 0xbd, 0x06, 0xc6, 0xd7, 0x22,
+	0xb2, 0xfb, 0x7c, 0x9b, 0xa8, 0xaa, 0xeb, 0xc3, 0x55, 0xd5, 0x94, 0x9e,
+	0xf3, 0xf4, 0xdf, 0x3f, 0xc2, 0x1e, 0x4b, 0xd4, 0x1a, 0x2e, 0x8d, 0x77,
+	0xab, 0x6d, 0xf4, 0x99, 0xe3, 0x7d, 0x4b, 0xec, 0x0b, 0xc7, 0x47, 0x6b,
+	0x84, 0xe1, 0xf7, 0x89, 0xe3, 0x7d, 0xb5, 0x9f, 0x00, 0x16, 0x72, 0x29,
+	0xfb, 0xf8, 0x09, 0xff, 0xda, 0xb6, 0x33, 0xb5, 0x6c, 0x71, 0x26, 0xed,
+	0xfe, 0x99, 0xe3, 0xd9, 0x0a, 0xf3, 0x83, 0x44, 0x4c, 0x74, 0x1e, 0x5e,
+	0x38, 0x3e, 0x53, 0x0a, 0x4b, 0x48, 0xd3, 0xe2, 0xaf, 0x73, 0x8d, 0xf7,
+	0xb0, 0x13, 0x6d, 0xa4, 0xab, 0x11, 0x0f, 0xe3, 0x0c, 0xf1, 0x9c, 0x00,
+	0x9e, 0x24, 0xf0, 0x30, 0xde, 0xb8, 0xf4, 0xc6, 0x97, 0x76, 0xa2, 0x8d,
+	0xb8, 0x78, 0x96, 0x8f, 0xaf, 0x47, 0xd4, 0xf9, 0xb7, 0x49, 0xaf, 0xc9,
+	0x9c, 0xd6, 0xf5, 0x35, 0x4d, 0x92, 0x3f, 0x8b, 0xdc, 0xc6, 0x1e, 0xf3,
+	0xc6, 0x77, 0x9b, 0xac, 0xb7, 0xe3, 0x8a, 0xf3, 0xec, 0xb1, 0x96, 0x8a,
+	0x63, 0x0e, 0xe3, 0x65, 0x1f, 0x56, 0x79, 0xb0, 0x1d, 0x0d, 0x7c, 0x37,
+	0x79, 0xb2, 0xe6, 0x99, 0x7e, 0xdd, 0xd9, 0x48, 0x0b, 0x40, 0x71, 0x0f,
+	0xdd, 0x5b, 0xf7, 0xe0, 0xf3, 0x89, 0x85, 0x35, 0xd2, 0x96, 0x04, 0xaf,
+	0x3e, 0x6d, 0x9f, 0xf6, 0xfe, 0xb8, 0x37, 0x89, 0x3f, 0xff, 0x3c, 0x5f,
+	0x06, 0xa4, 0x8b, 0x3d, 0x74, 0xf9, 0x13, 0x75, 0x73, 0x12, 0x76, 0xc7,
+	0x37, 0x10, 0xc7, 0x59, 0xb5, 0x29, 0xfb, 0x16, 0xdc, 0xbb, 0xf6, 0xb1,
+	0xa8, 0x21, 0x14, 0x73, 0xb9, 0x38, 0xeb, 0xd5, 0xa3, 0xb2, 0x09, 0x5c,
+	0x19, 0xd4, 0x94, 0x6e, 0x5d, 0x34, 0x0d, 0xff, 0xb8, 0x0e, 0xfd, 0xbc,
+	0x6a, 0xf1, 0x2d, 0x26, 0xcc, 0x78, 0x27, 0xc5, 0xda, 0xcf, 0x01, 0xc3,
+	0x3c, 0xea, 0xf6, 0x3b, 0xcb, 0x12, 0x60, 0x96, 0xb1, 0x76, 0xca, 0xf5,
+	0xcb, 0xf4, 0xed, 0xc8, 0xa9, 0x50, 0xc3, 0x58, 0xff, 0xe3, 0xe4, 0xa3,
+	0x8d, 0xb0, 0x3b, 0xbd, 0x83, 0x20, 0xe6, 0x2c, 0x26, 0xe6, 0x97, 0xe0,
+	0xc3, 0x2b, 0x96, 0xda, 0xad, 0xb4, 0x46, 0x26, 0x2a, 0xf0, 0x49, 0xa8,
+	0x78, 0x13, 0xf1, 0x25, 0x79, 0x5f, 0xdf, 0x43, 0x93, 0x35, 0x6c, 0xf6,
+	0xa8, 0xaf, 0x52, 0xaf, 0x34, 0xe5, 0xa1, 0x33, 0x88, 0xcb, 0x23, 0x4f,
+	0x20, 0xe6, 0x40, 0x5e, 0x67, 0x0a, 0xa8, 0xe2, 0xa9, 0x23, 0x3f, 0xf8,
+	0x83, 0x19, 0xcb, 0xcd, 0xff, 0x75, 0x3c, 0x13, 0x97, 0xc7, 0xd0, 0x99,
+	0x76, 0xed, 0x67, 0xf2, 0xda, 0xdf, 0xf4, 0x9b, 0x53, 0xaa, 0x0d, 0x39,
+	0x06, 0x12, 0x4f, 0x64, 0x38, 0xe6, 0xa0, 0x48, 0x1f, 0xf3, 0x4e, 0xf8,
+	0xe1, 0xbe, 0x35, 0x78, 0xb7, 0x33, 0x84, 0x57, 0x12, 0x3e, 0x13, 0x92,
+	0xa6, 0x33, 0x7c, 0x0b, 0x91, 0x3d, 0xa8, 0xc3, 0x88, 0xb3, 0x2f, 0x8c,
+	0x7e, 0x02, 0x7f, 0xfb, 0x90, 0x5f, 0x99, 0xc8, 0x8d, 0x77, 0x80, 0x07,
+	0x2c, 0xf7, 0xec, 0x04, 0xdf, 0xd5, 0x2d, 0x6d, 0x11, 0xec, 0x21, 0x3c,
+	0xf2, 0x43, 0x6b, 0x0f, 0xe8, 0x71, 0xcf, 0x27, 0x8e, 0xf0, 0x19, 0x91,
+	0xfe, 0x05, 0xe9, 0x51, 0x7a, 0x4f, 0x58, 0x66, 0x52, 0x5c, 0x6b, 0x07,
+	0x3c, 0xf7, 0x61, 0x4d, 0xef, 0x73, 0xdf, 0x94, 0xf2, 0xb7, 0xe9, 0xc6,
+	0x9c, 0x81, 0x6f, 0xe4, 0x53, 0x29, 0x53, 0xfa, 0xab, 0x2e, 0x6c, 0xdf,
+	0xda, 0x53, 0xdd, 0x7c, 0x97, 0x52, 0x96, 0x4b, 0x9b, 0x42, 0xee, 0x9b,
+	0x87, 0x54, 0xc3, 0x83, 0x7c, 0x9b, 0x21, 0x0c, 0xeb, 0xd9, 0x2e, 0x0d,
+	0x63, 0x0e, 0x52, 0x7e, 0xee, 0x9c, 0x52, 0xff, 0xd7, 0x9b, 0x4b, 0x63,
+	0x4e, 0xa1, 0x6d, 0x05, 0xfb, 0xbf, 0xa9, 0x6d, 0x45, 0x54, 0xdc, 0xb3,
+	0x15, 0x8c, 0x97, 0x39, 0xf6, 0x63, 0xf1, 0xf1, 0x7b, 0x5c, 0x7f, 0xef,
+	0xc8, 0xac, 0xcd, 0xf7, 0x0b, 0x47, 0xae, 0xda, 0x05, 0xe3, 0xc0, 0x1d,
+	0x79, 0x66, 0x52, 0xc7, 0xe7, 0x19, 0xc8, 0x7e, 0xb3, 0xa6, 0x6b, 0x35,
+	0xb9, 0x56, 0x8b, 0xc8, 0x3b, 0x2b, 0x6d, 0xb2, 0xb9, 0xe4, 0xea, 0xfc,
+	0xe6, 0x12, 0xf5, 0xdc, 0x94, 0x9f, 0xad, 0x58, 0x58, 0x4b, 0xe2, 0xaf,
+	0x47, 0x6e, 0xac, 0xdc, 0x99, 0x77, 0x5e, 0xae, 0x3f, 0x0a, 0x5a, 0x7a,
+	0x24, 0x64, 0x39, 0xba, 0xee, 0xca, 0x21, 0xf6, 0x15, 0x64, 0x42, 0xf2,
+	0xe5, 0x7e, 0xd4, 0x7e, 0x08, 0xce, 0x61, 0xc6, 0x20, 0xdc, 0x7f, 0xf9,
+	0xf3, 0xc8, 0x4d, 0x12, 0x30, 0x9e, 0x7e, 0xfd, 0xa6, 0xf8, 0xc5, 0x70,
+	0x8f, 0x34, 0x5b, 0xdf, 0xec, 0x76, 0x63, 0x95, 0xe9, 0xd6, 0xa7, 0x96,
+	0x1f, 0xaf, 0xdf, 0x04, 0xee, 0x11, 0xe8, 0x29, 0x75, 0xd3, 0x86, 0xce,
+	0x9a, 0xb2, 0x3a, 0x94, 0xa8, 0x14, 0x84, 0xfe, 0x21, 0xc5, 0x7c, 0x11,
+	0xfb, 0x92, 0x90, 0x47, 0xab, 0xce, 0x85, 0x32, 0x0a, 0x77, 0xbb, 0x30,
+	0x27, 0xf9, 0xfa, 0xef, 0x63, 0x3e, 0x23, 0xd3, 0xf5, 0x71, 0x9c, 0x75,
+	0x1a, 0x7a, 0xfb, 0x60, 0x8f, 0xb4, 0xf1, 0x9c, 0x14, 0x68, 0x7c, 0x44,
+	0x66, 0xce, 0xce, 0xc9, 0x91, 0x32, 0xe9, 0xe4, 0x1b, 0x63, 0x22, 0x99,
+	0x93, 0xe1, 0xf8, 0x0a, 0x72, 0x27, 0xd7, 0x1e, 0xd3, 0x32, 0x73, 0x0e,
+	0x38, 0xca, 0xac, 0xff, 0xfb, 0xa1, 0x37, 0xc3, 0xba, 0x7e, 0x99, 0xd6,
+	0x7e, 0x87, 0xf3, 0x6f, 0xe3, 0x9e, 0xfa, 0x0b, 0xfb, 0x00, 0x97, 0x47,
+	0xad, 0x33, 0x85, 0x7c, 0x79, 0xb9, 0x8c, 0x3a, 0xcf, 0x0e, 0x31, 0xf7,
+	0x52, 0xea, 0xa1, 0x5e, 0xa9, 0x96, 0x87, 0x4d, 0xa5, 0x98, 0x53, 0xf1,
+	0x2e, 0xb8, 0x46, 0xfb, 0x8e, 0xa9, 0xb0, 0xd5, 0x2b, 0x2b, 0xe5, 0x02,
+	0xea, 0x65, 0xe5, 0xbd, 0x67, 0x14, 0xc4, 0xb4, 0x5c, 0xbf, 0xa7, 0x6b,
+	0x1b, 0xe6, 0x9f, 0xf5, 0x2f, 0x80, 0xc6, 0x0c, 0x2e, 0xf3, 0x24, 0xe8,
+	0xc3, 0xf7, 0x32, 0x74, 0x7c, 0x81, 0x39, 0x5c, 0x06, 0x6b, 0x69, 0x39,
+	0x76, 0x61, 0x0a, 0x34, 0x74, 0x4a, 0xff, 0x9f, 0xd1, 0xc6, 0x9e, 0xc4,
+	0x1c, 0xc7, 0x09, 0xe8, 0xeb, 0xd7, 0xf1, 0x4d, 0xd8, 0x18, 0x7a, 0xca,
+	0xa1, 0x17, 0xbd, 0x09, 0x5a, 0x58, 0x07, 0x43, 0xfe, 0x87, 0xe3, 0x52,
+	0x3d, 0xfb, 0xb0, 0x4c, 0x2f, 0x3f, 0x0c, 0xfc, 0xff, 0x8a, 0xba, 0x00,
+	0xf1, 0x6d, 0x99, 0x67, 0x31, 0xff, 0xe3, 0x39, 0x10, 0x10, 0x6d, 0x63,
+	0x81, 0xf3, 0xec, 0x0f, 0x62, 0x3f, 0x6a, 0x8c, 0x72, 0x46, 0x66, 0xca,
+	0x3c, 0x0b, 0x77, 0x87, 0x7c, 0x2a, 0x7f, 0x76, 0xca, 0xbb, 0xe3, 0x1e,
+	0xc9, 0x45, 0x0b, 0xac, 0x2f, 0x10, 0x27, 0x96, 0x46, 0xb3, 0xa5, 0x84,
+	0x99, 0x55, 0xc4, 0x95, 0x14, 0xc6, 0x06, 0x77, 0x2e, 0x22, 0xd6, 0x02,
+	0x6a, 0xda, 0x34, 0xd7, 0x4e, 0x7a, 0x6f, 0x06, 0xc4, 0xf5, 0x63, 0x99,
+	0x80, 0x8e, 0xf5, 0x2f, 0x8c, 0x20, 0x17, 0xfe, 0x29, 0x72, 0xc9, 0xb8,
+	0x27, 0x83, 0x71, 0x4f, 0x37, 0xda, 0x1a, 0x74, 0x02, 0xf7, 0x5c, 0xc6,
+	0xdd, 0x97, 0xa1, 0x07, 0xf0, 0xd5, 0xaf, 0x6e, 0xe9, 0xc7, 0x78, 0x43,
+	0x8e, 0xd9, 0x21, 0xff, 0x50, 0x49, 0x24, 0xd7, 0xa1, 0x3f, 0x37, 0x50,
+	0x0b, 0xac, 0xa3, 0x3e, 0xdc, 0xb4, 0x23, 0xa8, 0x4b, 0x0e, 0x83, 0x7e,
+	0xe6, 0x94, 0x1c, 0xc7, 0x74, 0xae, 0xd3, 0x62, 0x3d, 0x7f, 0x8f, 0x7e,
+	0xd7, 0x95, 0xaf, 0xf6, 0xb0, 0xa6, 0x64, 0x3d, 0xce, 0x37, 0xe9, 0x77,
+	0x70, 0x8f, 0xeb, 0x26, 0xd7, 0xfd, 0x7d, 0xac, 0x05, 0x7c, 0xfd, 0x21,
+	0x2d, 0xd4, 0x1f, 0xee, 0x21, 0x4c, 0x8f, 0xb6, 0x93, 0xbc, 0xc6, 0x47,
+	0x9d, 0xfd, 0x9b, 0x6e, 0xd7, 0xce, 0x74, 0x9e, 0x65, 0x5e, 0x13, 0x5f,
+	0x7f, 0x3f, 0x74, 0x58, 0xd7, 0x65, 0x87, 0xe0, 0xbb, 0xeb, 0x8e, 0xbc,
+	0x60, 0xdf, 0x69, 0x77, 0xfb, 0xcb, 0xbe, 0x9c, 0x28, 0xc7, 0xc3, 0x72,
+	0xaa, 0x9e, 0x80, 0x4d, 0x50, 0x86, 0x56, 0x83, 0x0c, 0x45, 0xfe, 0xaa,
+	0x2c, 0xf2, 0x4a, 0x99, 0x6b, 0x5a, 0x86, 0xb1, 0x6c, 0xa8, 0x8d, 0xef,
+	0xea, 0xd0, 0xcb, 0xb7, 0xe5, 0xc8, 0xa2, 0xc8, 0x05, 0xac, 0xaf, 0x96,
+	0x69, 0xab, 0x23, 0xc8, 0x5f, 0x77, 0x49, 0x75, 0x09, 0x35, 0x59, 0x59,
+	0xa6, 0xb3, 0x9f, 0x63, 0xbc, 0x89, 0xc8, 0xa6, 0x7e, 0x8f, 0x15, 0x19,
+	0xbc, 0x18, 0x96, 0xf0, 0x45, 0x14, 0x7f, 0x90, 0xfd, 0xa5, 0x21, 0xff,
+	0x7d, 0xd6, 0xb5, 0xf9, 0x62, 0x09, 0x7b, 0xcb, 0xfd, 0xda, 0x4f, 0x16,
+	0x6b, 0x33, 0x92, 0xaf, 0xf0, 0x2c, 0xf4, 0x4b, 0x71, 0xac, 0xa5, 0x64,
+	0xf6, 0xec, 0x88, 0x3c, 0x8b, 0x33, 0x50, 0xff, 0xe1, 0x8c, 0x09, 0x29,
+	0x5c, 0xc0, 0x7c, 0xed, 0xba, 0x2c, 0xad, 0xcc, 0x48, 0xb5, 0x72, 0xb9,
+	0xe1, 0xdd, 0x1d, 0xe3, 0xa5, 0xc6, 0x5a, 0xf6, 0x30, 0xeb, 0x19, 0xd4,
+	0xaa, 0x16, 0xc6, 0x90, 0x59, 0x6d, 0x76, 0xfa, 0xce, 0xf7, 0xe2, 0xc6,
+	0x1a, 0x76, 0x52, 0xe6, 0xcb, 0x29, 0x29, 0x9e, 0x1d, 0xd1, 0x6f, 0x0a,
+	0x2d, 0xe9, 0xca, 0xd3, 0x37, 0x11, 0x2b, 0x26, 0xf5, 0x7b, 0xf1, 0x2d,
+	0x79, 0xcc, 0x9e, 0x97, 0xa3, 0xd6, 0x41, 0x39, 0x85, 0xfc, 0xfa, 0x4b,
+	0x76, 0xab, 0xc4, 0xbb, 0x79, 0x8f, 0xa0, 0xd7, 0x62, 0x0d, 0xea, 0xc8,
+	0x84, 0xfd, 0xa0, 0xf9, 0x3c, 0x24, 0xfb, 0x4e, 0x8d, 0x71, 0xf2, 0xbf,
+	0x9d, 0x0c, 0xe2, 0xde, 0x4d, 0xd4, 0x8e, 0x19, 0x0d, 0x67, 0xb8, 0x70,
+	0x15, 0xc2, 0x0d, 0x9b, 0x2f, 0x10, 0x6e, 0xc9, 0xf0, 0xe0, 0x0c, 0xc0,
+	0x85, 0x64, 0xc3, 0x0e, 0x43, 0x47, 0x26, 0xc1, 0x27, 0x7c, 0xfc, 0x68,
+	0x87, 0x97, 0x07, 0xb7, 0x22, 0xb6, 0xde, 0xde, 0xff, 0x86, 0xb7, 0xff,
+	0x59, 0x6f, 0xff, 0xd5, 0xad, 0xfd, 0x7e, 0x7c, 0xfd, 0x85, 0x23, 0x0d,
+	0x74, 0xbd, 0x51, 0x72, 0xe1, 0xe7, 0x3d, 0xba, 0xae, 0x6e, 0xd1, 0xe5,
+	0xc3, 0x43, 0x9e, 0x9a, 0x67, 0xfa, 0x66, 0xfa, 0xe8, 0x7e, 0xc8, 0xd1,
+	0x91, 0x9c, 0x0d, 0xdb, 0x28, 0x27, 0xc6, 0x0b, 0xfa, 0x2d, 0x4d, 0xc9,
+	0x7a, 0x74, 0x5e, 0x26, 0xad, 0xc4, 0xf8, 0xac, 0x84, 0xa0, 0xcb, 0xf4,
+	0x2d, 0x21, 0xa9, 0xd2, 0xe7, 0xa0, 0xcf, 0xdb, 0x3b, 0xd3, 0xfa, 0x4e,
+	0x03, 0xad, 0xa1, 0x97, 0x49, 0xa3, 0x4b, 0x6b, 0x64, 0xe0, 0x36, 0xad,
+	0x2e, 0xbc, 0x4b, 0xeb, 0x3b, 0xa5, 0x06, 0xf8, 0x8b, 0x61, 0x0f, 0x3e,
+	0xdc, 0x00, 0x4f, 0x7d, 0x66, 0x5e, 0x41, 0x7d, 0x26, 0x6d, 0x9f, 0x85,
+	0x6d, 0x48, 0xa4, 0x35, 0x5d, 0x39, 0xfe, 0xc0, 0x80, 0x23, 0x11, 0xe4,
+	0x1b, 0xcd, 0x58, 0xdb, 0xac, 0x30, 0x17, 0x51, 0x7d, 0xcd, 0x32, 0x08,
+	0x9d, 0xe5, 0xdd, 0xb9, 0x6f, 0x82, 0x8f, 0xe9, 0x9c, 0xc0, 0x91, 0xa3,
+	0x36, 0x69, 0x79, 0xdf, 0x79, 0x25, 0x3a, 0x68, 0x17, 0x65, 0xc8, 0x6c,
+	0xc6, 0xf9, 0xd5, 0xba, 0xc6, 0x99, 0x24, 0x2d, 0xe7, 0x87, 0xfa, 0xcd,
+	0xbf, 0x07, 0x9f, 0x13, 0x15, 0x43, 0xaa, 0x56, 0x22, 0x76, 0x09, 0x38,
+	0xf6, 0xe1, 0x6e, 0xaa, 0x23, 0xa4, 0x47, 0xe4, 0x08, 0xf4, 0xbb, 0xaa,
+	0xe3, 0x22, 0xf5, 0x38, 0x31, 0x59, 0x40, 0xae, 0xf3, 0xd7, 0x3a, 0xb6,
+	0x39, 0xce, 0x4d, 0xc4, 0xb7, 0xc9, 0x6d, 0xba, 0xa7, 0x2e, 0xba, 0xba,
+	0xa7, 0x2e, 0xa2, 0x06, 0x3e, 0x1d, 0x91, 0x96, 0x55, 0xd8, 0xcf, 0xcb,
+	0x7b, 0xdc, 0x7c, 0xee, 0x65, 0xfe, 0xe6, 0x04, 0x7f, 0x77, 0x3a, 0x2c,
+	0xd6, 0x69, 0x1d, 0x0f, 0x20, 0xef, 0x09, 0x99, 0x3d, 0x47, 0x9f, 0x6a,
+	0xc9, 0xc0, 0x69, 0xde, 0x07, 0xf3, 0x9a, 0xa5, 0xd1, 0x19, 0xd8, 0xc8,
+	0x1c, 0xfc, 0x82, 0x5a, 0x7d, 0x57, 0x66, 0x2c, 0xca, 0xa1, 0x53, 0xda,
+	0x56, 0x51, 0x8f, 0xaf, 0xc2, 0x37, 0xac, 0xc6, 0xa4, 0x09, 0xb6, 0xa5,
+	0x2e, 0x46, 0x8d, 0xe2, 0xe2, 0x07, 0xb0, 0x07, 0xfe, 0x7e, 0x83, 0xdc,
+	0xf2, 0x62, 0xcc, 0xa0, 0x6d, 0xa9, 0x8b, 0xd4, 0x73, 0xa4, 0x53, 0x17,
+	0xa9, 0xe7, 0xa4, 0xc3, 0xb7, 0x17, 0x7c, 0x5f, 0x1c, 0xd1, 0xef, 0xd3,
+	0x37, 0x6d, 0xf2, 0xf2, 0x8f, 0x92, 0xad, 0x30, 0x47, 0x24, 0x3f, 0xd2,
+	0x8d, 0x5c, 0xa6, 0x2b, 0x6b, 0x0f, 0x8c, 0x6f, 0xca, 0xa7, 0xe5, 0xeb,
+	0xee, 0x4f, 0xc1, 0x17, 0xf9, 0x68, 0xe4, 0x8b, 0x3c, 0x75, 0x4a, 0x93,
+	0xe6, 0xcb, 0xe7, 0x07, 0x82, 0x06, 0x3f, 0x7d, 0xa7, 0x63, 0xc0, 0xff,
+	0x75, 0xf8, 0x80, 0x5e, 0xf4, 0x4f, 0xa2, 0x47, 0x48, 0xbb, 0x48, 0xde,
+	0xc9, 0xeb, 0x0d, 0xe4, 0x8d, 0x3e, 0x9f, 0xd3, 0xf8, 0x7e, 0x5d, 0x66,
+	0x17, 0x9d, 0x93, 0x88, 0xab, 0x7c, 0x3b, 0xef, 0x71, 0xdf, 0x81, 0xb7,
+	0xf3, 0xfe, 0xba, 0xb8, 0xf2, 0x49, 0x98, 0x55, 0xc1, 0xf7, 0xca, 0x76,
+	0x59, 0x34, 0xfa, 0x8e, 0x98, 0xce, 0xc3, 0x8f, 0xd4, 0xe8, 0x27, 0x28,
+	0xa3, 0x1b, 0x92, 0x5d, 0xe4, 0xfb, 0x97, 0x8b, 0x6f, 0xba, 0xe6, 0xfb,
+	0x8d, 0xc6, 0x3d, 0x36, 0xe0, 0x7a, 0x01, 0x47, 0xba, 0xd6, 0x29, 0x3f,
+	0xf8, 0x9c, 0xbd, 0x0d, 0xbe, 0xa6, 0x71, 0xdf, 0xb8, 0x3c, 0x87, 0x3c,
+	0xe0, 0x0d, 0xfb, 0x0e, 0xb9, 0x4e, 0x33, 0x17, 0xaa, 0xd6, 0xa6, 0x60,
+	0x93, 0x4d, 0xf0, 0x65, 0xa6, 0x6c, 0x96, 0x9a, 0xa5, 0x8a, 0x7c, 0x67,
+	0x79, 0x85, 0xbe, 0x90, 0xb4, 0xb7, 0x61, 0xde, 0xf5, 0x5f, 0xf4, 0xb5,
+	0x9b, 0x25, 0xc4, 0x59, 0xd8, 0xf6, 0x66, 0x29, 0x8a, 0xbe, 0x17, 0xbd,
+	0x85, 0x3e, 0x8e, 0x3e, 0x89, 0x7e, 0x04, 0xfd, 0x08, 0x7a, 0x0b, 0x7b,
+	0x63, 0xe8, 0xfd, 0x9a, 0x81, 0xb8, 0x6e, 0xf3, 0x5d, 0xd4, 0xe7, 0x21,
+	0x57, 0xb4, 0x18, 0xd3, 0xc2, 0x76, 0x0e, 0x75, 0x44, 0x76, 0x84, 0xb9,
+	0x1e, 0x73, 0xbe, 0x8f, 0x1d, 0xd3, 0x62, 0x5d, 0x5e, 0x30, 0xf6, 0x0d,
+	0x31, 0x2e, 0x54, 0x10, 0x17, 0x3e, 0xd8, 0x8d, 0xfa, 0xd1, 0xdc, 0xaf,
+	0xdf, 0x8e, 0x16, 0x31, 0xe6, 0x37, 0x6a, 0xde, 0xe8, 0x1c, 0xe2, 0x14,
+	0xfd, 0xa7, 0x83, 0x3d, 0x79, 0xf8, 0xf1, 0x2e, 0xd8, 0x5f, 0x06, 0x7e,
+	0x1b, 0xdf, 0x4b, 0x6f, 0xec, 0x76, 0x63, 0x2a, 0xf2, 0x77, 0xb5, 0xfd,
+	0xbd, 0xc6, 0xc6, 0x9e, 0x9d, 0x6a, 0x83, 0x0e, 0xe0, 0x48, 0x54, 0x96,
+	0x60, 0x83, 0x3f, 0xb4, 0x4f, 0xea, 0xdc, 0x8e, 0x77, 0xf1, 0x2c, 0x72,
+	0xd4, 0xdc, 0x02, 0x73, 0x98, 0x13, 0xa8, 0x4b, 0x50, 0x9f, 0x45, 0x59,
+	0x93, 0x33, 0x16, 0xe8, 0x5c, 0x34, 0x2a, 0x6d, 0x8c, 0x03, 0x37, 0x70,
+	0x1e, 0xf8, 0x5a, 0x76, 0x20, 0xb3, 0x03, 0xc8, 0x09, 0x1d, 0x27, 0x6c,
+	0xed, 0x93, 0xf8, 0x21, 0xfa, 0x1c, 0xc1, 0x7e, 0x53, 0xdc, 0xf7, 0x74,
+	0xf8, 0xdd, 0x29, 0xfd, 0x5b, 0x31, 0x94, 0xeb, 0xb3, 0xd8, 0x7b, 0x17,
+	0x70, 0x71, 0x9e, 0x6f, 0xd9, 0x22, 0xfb, 0x16, 0xdc, 0x9c, 0x56, 0x59,
+	0x8d, 0xf8, 0x7e, 0xd5, 0xc3, 0xc7, 0x75, 0xe5, 0xfd, 0xa6, 0xb1, 0xc7,
+	0x7d, 0x1b, 0xc6, 0x1d, 0x9f, 0x42, 0xfe, 0xbc, 0x81, 0x7b, 0x79, 0x03,
+	0x77, 0x72, 0xa5, 0x44, 0x5d, 0x1f, 0x86, 0xde, 0x43, 0x86, 0x53, 0xc4,
+	0x35, 0xa2, 0xcf, 0xde, 0x28, 0xc1, 0x77, 0xd2, 0xff, 0x29, 0x64, 0x77,
+	0x6d, 0x6e, 0x4c, 0x77, 0xf1, 0xf4, 0xba, 0x70, 0xe2, 0xaf, 0xed, 0xd6,
+	0xf4, 0x54, 0xf5, 0x3b, 0x18, 0xe5, 0x04, 0x1d, 0xe4, 0x6f, 0x03, 0x1a,
+	0xe6, 0x6b, 0x51, 0xfd, 0xfe, 0xae, 0x38, 0x47, 0x3e, 0x46, 0x24, 0xbb,
+	0xe0, 0xef, 0xeb, 0xc6, 0xbe, 0xd6, 0x06, 0x5c, 0x77, 0x6f, 0xe3, 0x41,
+	0x79, 0x3c, 0x70, 0xfd, 0x93, 0x6f, 0xc3, 0x85, 0xad, 0xb7, 0x61, 0xc6,
+	0x5f, 0xde, 0x4d, 0x0a, 0xfb, 0xfd, 0xfb, 0xe9, 0xf5, 0x6a, 0x81, 0xc4,
+	0x7c, 0x41, 0x98, 0xab, 0xf0, 0x8e, 0xc6, 0x61, 0xd7, 0x5d, 0xc0, 0x6f,
+	0x4b, 0xa5, 0xd4, 0x22, 0xaa, 0x87, 0xb5, 0x31, 0x73, 0xe5, 0xc6, 0x33,
+	0x7f, 0xdb, 0x3b, 0x13, 0xf5, 0xf4, 0x19, 0xe6, 0xcd, 0x3a, 0xce, 0x00,
+	0xa6, 0x7d, 0x1b, 0x6d, 0xbf, 0xee, 0xc1, 0x71, 0x3d, 0x29, 0x05, 0xe4,
+	0xa1, 0xb9, 0x05, 0x64, 0xf4, 0xf0, 0xdf, 0x2a, 0xcd, 0xdf, 0xb3, 0xf8,
+	0x86, 0x37, 0x1c, 0x9f, 0x05, 0x8d, 0x05, 0x33, 0xc3, 0x77, 0x33, 0xe0,
+	0xd8, 0xbb, 0x0d, 0xc7, 0x84, 0x87, 0x63, 0x42, 0x8a, 0xe7, 0x26, 0x61,
+	0x6b, 0x19, 0xc4, 0xf7, 0x7e, 0xf3, 0x80, 0x7c, 0x1e, 0xc5, 0x35, 0xe6,
+	0x2e, 0x8c, 0xe0, 0x9e, 0x1c, 0x67, 0x9f, 0x7d, 0x18, 0x74, 0xbf, 0x86,
+	0xd8, 0xea, 0xe7, 0x3c, 0xc5, 0x58, 0x08, 0x31, 0xec, 0x98, 0xfe, 0x0d,
+	0xb6, 0x60, 0x9a, 0xd0, 0x57, 0x65, 0x0c, 0x27, 0x51, 0xde, 0x23, 0xbe,
+	0xcd, 0x23, 0x56, 0x91, 0xcf, 0x0e, 0x29, 0x9a, 0xc6, 0xa3, 0x21, 0xe4,
+	0x35, 0xd9, 0x05, 0xda, 0x91, 0x0c, 0x84, 0xd2, 0xcd, 0xc8, 0x49, 0x1d,
+	0xf9, 0x99, 0xcd, 0x7f, 0xa3, 0x30, 0x2f, 0x1b, 0x35, 0x13, 0xfd, 0x3a,
+	0xee, 0xe1, 0xdb, 0xf8, 0xbe, 0xde, 0x83, 0xbc, 0x0f, 0x2b, 0x19, 0xe8,
+	0x6e, 0x52, 0xe7, 0x33, 0xcc, 0x23, 0xaa, 0x88, 0xb7, 0x0a, 0xb1, 0x06,
+	0x79, 0xd5, 0x38, 0x73, 0xd7, 0xe7, 0x96, 0xaf, 0xcb, 0x95, 0x45, 0xfe,
+	0x06, 0xca, 0xb8, 0x7c, 0x90, 0xfe, 0xc0, 0x9c, 0x4b, 0x61, 0x6e, 0x85,
+	0xbe, 0x0c, 0xe3, 0x3a, 0x0c, 0xa8, 0x07, 0x39, 0x02, 0x72, 0xed, 0x4d,
+	0x2b, 0x09, 0x3e, 0xaf, 0xcb, 0xc6, 0x62, 0x58, 0x96, 0x2d, 0xe6, 0x45,
+	0x12, 0xcf, 0x02, 0x76, 0x63, 0xe5, 0x9a, 0xab, 0x13, 0x84, 0x47, 0xcd,
+	0x53, 0x40, 0x5e, 0x77, 0x40, 0xef, 0xfd, 0x65, 0xf7, 0x4c, 0x9a, 0x1a,
+	0xeb, 0xbc, 0x19, 0xd9, 0xa0, 0x3d, 0xd9, 0x7c, 0x93, 0x62, 0x6e, 0x70,
+	0x02, 0x3a, 0xcb, 0xdc, 0x9d, 0xf5, 0x00, 0xbe, 0x6b, 0x5c, 0x27, 0xef,
+	0xe8, 0x97, 0xfa, 0x21, 0x1b, 0xda, 0x3d, 0xdf, 0xc4, 0x10, 0x47, 0x15,
+	0x6d, 0xbd, 0xa8, 0x7d, 0x41, 0xb1, 0x3c, 0x83, 0x98, 0x02, 0x1f, 0xc0,
+	0xdf, 0x70, 0xa6, 0xa6, 0x70, 0x97, 0xe3, 0x80, 0xdb, 0x16, 0x4b, 0xd6,
+	0x8a, 0x3a, 0x2f, 0x53, 0xe7, 0x6f, 0xbf, 0xdf, 0xe4, 0x61, 0x3f, 0x6a,
+	0x0d, 0xba, 0x05, 0x1b, 0x52, 0x6b, 0x51, 0xf4, 0xf0, 0xc7, 0x6b, 0xa8,
+	0x2f, 0x4a, 0x7c, 0x1f, 0x42, 0x6d, 0x50, 0xe2, 0xdb, 0x49, 0x12, 0xfd,
+	0x08, 0xdf, 0x8b, 0x3c, 0xbf, 0x46, 0xfc, 0xa4, 0xc3, 0xf7, 0x2f, 0xcc,
+	0x25, 0xe9, 0x5f, 0xfc, 0x7c, 0xd2, 0xd5, 0x85, 0x53, 0x65, 0xfa, 0x10,
+	0xea, 0x75, 0x3f, 0xfc, 0x16, 0x75, 0xc1, 0xcd, 0x25, 0x57, 0x2a, 0xae,
+	0xcc, 0x66, 0xeb, 0x97, 0x75, 0x8c, 0xd8, 0x2f, 0x16, 0x74, 0x8c, 0xb2,
+	0xc3, 0x9a, 0x8e, 0x01, 0x97, 0x24, 0xa3, 0x7b, 0xca, 0xec, 0x75, 0xc9,
+	0xac, 0x8c, 0xc8, 0x0b, 0xda, 0x6f, 0xf9, 0x3e, 0x8b, 0x39, 0x64, 0x0c,
+	0xf2, 0x4b, 0xca, 0xf3, 0x67, 0xaf, 0x4b, 0xf6, 0x45, 0xfa, 0xad, 0xe1,
+	0x58, 0xab, 0x41, 0x5f, 0xe5, 0x48, 0x0d, 0xb1, 0xe9, 0x80, 0xcd, 0x7f,
+	0x07, 0x10, 0x42, 0x4d, 0xe7, 0x48, 0xf3, 0x68, 0xc2, 0x8e, 0x1b, 0xfd,
+	0x4f, 0xb6, 0x1a, 0x8c, 0x8d, 0xc3, 0xe6, 0x53, 0xe2, 0xbf, 0x47, 0xb5,
+	0xc8, 0x53, 0xfa, 0xad, 0x02, 0x66, 0xbb, 0xf0, 0x91, 0xfe, 0x1d, 0xe5,
+	0x66, 0x8a, 0xb2, 0xc6, 0x78, 0x8d, 0xf3, 0x85, 0xc8, 0xcd, 0x54, 0x93,
+	0x14, 0xef, 0x72, 0x9c, 0xa3, 0xa3, 0xa9, 0xdd, 0xee, 0xbf, 0x15, 0xf9,
+	0xc6, 0x5d, 0xae, 0x2f, 0x38, 0xea, 0x8d, 0x5f, 0x41, 0x4f, 0xdd, 0x66,
+	0xbc, 0x65, 0x7c, 0xe4, 0xbd, 0xa1, 0x5f, 0xe1, 0x37, 0x63, 0xef, 0x3c,
+	0x62, 0x2f, 0xe3, 0x65, 0x97, 0xe4, 0x0e, 0x6b, 0x9f, 0xc1, 0xf9, 0x82,
+	0x9b, 0x4b, 0x7b, 0x70, 0x95, 0x69, 0x99, 0xad, 0x30, 0x87, 0xda, 0x40,
+	0x2c, 0x1b, 0x82, 0xae, 0x32, 0xa6, 0x9d, 0x44, 0x3c, 0xe7, 0xef, 0xd2,
+	0x58, 0x5b, 0xe2, 0xbe, 0x44, 0x32, 0xae, 0xc0, 0xf3, 0x96, 0x4e, 0xdd,
+	0x8c, 0xf2, 0x3d, 0xea, 0xd2, 0x10, 0xee, 0xfd, 0x4f, 0x59, 0x5b, 0x0c,
+	0x68, 0x1d, 0xc9, 0xbe, 0x4c, 0xd9, 0xbb, 0xbf, 0x5b, 0x4b, 0xb7, 0x6b,
+	0x03, 0xcc, 0x03, 0x1e, 0x87, 0x5c, 0xf6, 0xdb, 0xd7, 0x19, 0xbb, 0xff,
+	0x5d, 0x59, 0xc3, 0xc9, 0xa7, 0x0c, 0xda, 0x36, 0xc6, 0x2b, 0x21, 0x59,
+	0x8a, 0x92, 0x7f, 0xc8, 0xcb, 0xa0, 0xed, 0xec, 0x24, 0x87, 0xed, 0x32,
+	0xf8, 0x4b, 0xc8, 0x80, 0xb2, 0xf4, 0x65, 0xc0, 0xef, 0x49, 0xdc, 0x17,
+	0x6b, 0x86, 0x7e, 0x5d, 0x47, 0x16, 0xeb, 0xee, 0xd9, 0xc5, 0x72, 0x23,
+	0xcd, 0xa4, 0x97, 0x77, 0x7a, 0x49, 0x72, 0xfa, 0x7e, 0xe7, 0x25, 0x57,
+	0xb9, 0x24, 0xfb, 0x2a, 0xf3, 0xf2, 0x98, 0xf5, 0x28, 0xf8, 0xbd, 0xe6,
+	0xcc, 0x58, 0xba, 0x56, 0x19, 0xcf, 0xff, 0x6f, 0xe7, 0x56, 0x1b, 0xdb,
+	0x56, 0x75, 0x86, 0x5f, 0x5f, 0xdb, 0x69, 0x1a, 0x9a, 0x70, 0xeb, 0x3a,
+	0x89, 0x9b, 0x66, 0xad, 0x1d, 0xdf, 0x7e, 0x88, 0xa4, 0xe8, 0x36, 0x64,
+	0x34, 0xea, 0x82, 0x62, 0x9c, 0x50, 0xc2, 0xe8, 0x44, 0xda, 0x75, 0x55,
+	0xb5, 0x31, 0x64, 0x39, 0xe9, 0x07, 0xd3, 0x06, 0xa3, 0xb0, 0x82, 0x18,
+	0x52, 0x8d, 0xdb, 0x6a, 0x9d, 0x96, 0xc6, 0xe9, 0x07, 0x6b, 0x37, 0x69,
+	0x9a, 0xe5, 0xa4, 0x2d, 0x48, 0x11, 0x2e, 0x88, 0x6e, 0xfb, 0xb1, 0x8d,
+	0x2a, 0x65, 0xec, 0xff, 0xf6, 0x67, 0xda, 0xd0, 0x16, 0x15, 0x18, 0xfc,
+	0xd8, 0xa4, 0xfe, 0xe0, 0x47, 0x25, 0xe8, 0xbc, 0xe7, 0x79, 0xcf, 0xbd,
+	0x8e, 0x6d, 0x82, 0x26, 0x2d, 0x52, 0xe4, 0x7b, 0xce, 0x3d, 0xf7, 0x9c,
+	0x73, 0xcf, 0xfb, 0xfd, 0xbe, 0xcf, 0xc5, 0xda, 0x13, 0x7d, 0x6b, 0xe5,
+	0x63, 0xf8, 0x1d, 0x27, 0x67, 0x6d, 0xc9, 0xd8, 0x83, 0xf2, 0x63, 0xcd,
+	0xe5, 0x33, 0x3e, 0x09, 0xc0, 0x27, 0x35, 0xb8, 0x02, 0x69, 0x77, 0x62,
+	0x37, 0x85, 0x3e, 0x65, 0x18, 0xb4, 0x8e, 0x1b, 0xbf, 0xd9, 0x36, 0xf7,
+	0x37, 0x9d, 0x81, 0xef, 0xee, 0x0e, 0xb4, 0xfb, 0x39, 0x5f, 0xe3, 0xdf,
+	0xfe, 0xc5, 0xab, 0xa1, 0x0d, 0xca, 0x0c, 0xf6, 0xf3, 0x96, 0xea, 0x59,
+	0x07, 0xbc, 0xc4, 0xdc, 0x74, 0x4c, 0xf3, 0x0f, 0xe1, 0x69, 0xea, 0xa8,
+	0xab, 0xd0, 0x51, 0x43, 0xd4, 0x5d, 0xc3, 0xb3, 0x2e, 0xf3, 0x03, 0x51,
+	0xf9, 0xf3, 0x14, 0xf5, 0x70, 0x5c, 0xfe, 0x34, 0xf5, 0x02, 0xf6, 0x93,
+	0x28, 0x32, 0x47, 0x79, 0x63, 0x26, 0x47, 0x3f, 0x49, 0xfd, 0xf9, 0xb4,
+	0xfb, 0xac, 0xda, 0x81, 0xb8, 0x95, 0x5f, 0x13, 0x56, 0x7d, 0xf3, 0xb4,
+	0xd6, 0x74, 0xe3, 0x56, 0xb7, 0xdc, 0x38, 0x6f, 0x74, 0x6c, 0x78, 0x3a,
+	0x1a, 0x18, 0x99, 0xa3, 0x5d, 0x4a, 0xc6, 0xb2, 0xd6, 0x0a, 0x39, 0x10,
+	0x65, 0xee, 0x39, 0x45, 0xfd, 0x0c, 0x5b, 0xd8, 0x6b, 0x67, 0xad, 0x66,
+	0xcf, 0xfe, 0xc4, 0x1a, 0xf4, 0xec, 0xd3, 0x9e, 0x9e, 0xe5, 0xbd, 0x14,
+	0x68, 0x4a, 0x5b, 0x94, 0x98, 0x19, 0xb5, 0x92, 0xb0, 0x79, 0xb8, 0x9e,
+	0xe7, 0xfc, 0x71, 0x39, 0x32, 0x7f, 0x18, 0xfe, 0x77, 0xaf, 0xbd, 0x87,
+	0x76, 0xd5, 0x1e, 0x22, 0x16, 0x07, 0xeb, 0x7f, 0xa9, 0x61, 0xae, 0xc7,
+	0xbd, 0xb9, 0x78, 0x1f, 0x72, 0x3e, 0xed, 0xc8, 0x04, 0x6c, 0xc9, 0x88,
+	0x6d, 0xf6, 0x5a, 0x3f, 0x76, 0x77, 0x75, 0xdd, 0x13, 0x05, 0xc7, 0xc3,
+	0x85, 0xe1, 0x17, 0xbe, 0xd0, 0xd7, 0x23, 0x5c, 0x93, 0xeb, 0xb5, 0x49,
+	0x7a, 0x1f, 0xf4, 0xcb, 0x34, 0xff, 0x73, 0x5e, 0xed, 0x0a, 0xf1, 0x4a,
+	0xb4, 0x6b, 0x19, 0xdb, 0xf4, 0x80, 0x37, 0xdf, 0xb6, 0x0e, 0x69, 0x89,
+	0xd6, 0x8c, 0x67, 0x6e, 0x85, 0xed, 0xb8, 0xe4, 0xe6, 0xf9, 0x5b, 0xa9,
+	0x44, 0x9c, 0x26, 0xd9, 0x63, 0xaf, 0x6b, 0x98, 0x63, 0x2b, 0xfa, 0x8c,
+	0x4f, 0x10, 0x9c, 0x0e, 0x78, 0xbe, 0xc5, 0x06, 0xfa, 0x4d, 0xde, 0x75,
+	0xb3, 0xe6, 0x64, 0xe2, 0x56, 0x57, 0xc3, 0x7b, 0x6c, 0xa8, 0xda, 0xe1,
+	0xb8, 0x45, 0xdd, 0xd9, 0x14, 0x95, 0x36, 0xf2, 0x50, 0x45, 0xfd, 0xf8,
+	0x90, 0x63, 0xb0, 0x16, 0x51, 0xe7, 0x60, 0x07, 0x73, 0xf6, 0x6f, 0xeb,
+	0xb9, 0xb5, 0xd2, 0x27, 0xc0, 0x35, 0xf8, 0xe4, 0x73, 0xf9, 0x5e, 0xe6,
+	0x7a, 0x31, 0x7f, 0x0b, 0xe7, 0x77, 0xbd, 0x73, 0x4e, 0xb8, 0x39, 0xeb,
+	0x7e, 0xc9, 0x9e, 0x37, 0xfc, 0x97, 0x76, 0xc0, 0x7b, 0x6d, 0x68, 0xcf,
+	0xd1, 0x26, 0x7c, 0xd1, 0x3c, 0xbe, 0x6d, 0xd8, 0xa2, 0xb6, 0xe1, 0x78,
+	0x81, 0xfc, 0x49, 0xbe, 0xf4, 0xf9, 0xd1, 0xd7, 0x79, 0xe4, 0x51, 0xea,
+	0xd9, 0x41, 0x39, 0x53, 0xe0, 0xd9, 0xa4, 0xb4, 0xa6, 0xb5, 0xf1, 0xec,
+	0x84, 0xe2, 0xb1, 0x7a, 0xa6, 0x13, 0x17, 0x73, 0x32, 0x2c, 0x57, 0x5d,
+	0x9e, 0x59, 0xa2, 0x98, 0x09, 0xb6, 0xd6, 0xbc, 0xff, 0x3e, 0x3d, 0xb3,
+	0xb0, 0xfa, 0x8c, 0x31, 0x8c, 0x7d, 0xc9, 0xa3, 0x77, 0x9b, 0x9e, 0x6d,
+	0xa6, 0x8e, 0x3e, 0x8f, 0xea, 0x39, 0x85, 0xa1, 0x13, 0x59, 0xc7, 0x0f,
+	0x47, 0xf8, 0x0c, 0xd7, 0xa5, 0xcf, 0xc7, 0xb5, 0xc8, 0x7b, 0x3d, 0xb0,
+	0xd8, 0xfd, 0x12, 0xdc, 0x01, 0xd1, 0xdf, 0xc1, 0x3a, 0x72, 0x00, 0xb2,
+	0xba, 0xd1, 0x60, 0x5f, 0xc6, 0x8d, 0xaf, 0x91, 0xb1, 0xde, 0xc2, 0x39,
+	0x22, 0x56, 0x81, 0x1f, 0x7d, 0xfc, 0xa7, 0x77, 0x30, 0x5f, 0xc6, 0xf3,
+	0xd7, 0x07, 0x30, 0x3f, 0xcf, 0x82, 0x32, 0x36, 0xb5, 0x8d, 0xbc, 0x3a,
+	0xaa, 0xf5, 0x41, 0x3e, 0x43, 0x39, 0xe6, 0x99, 0x91, 0x2e, 0x7f, 0xc3,
+	0xf3, 0x6c, 0x6f, 0x6d, 0xa0, 0x63, 0xd2, 0xdb, 0x9f, 0x7f, 0x3f, 0x2c,
+	0xe1, 0x0e, 0xea, 0xb8, 0xa8, 0x24, 0xa7, 0x19, 0xb3, 0xc0, 0x76, 0x8d,
+	0x73, 0xae, 0xff, 0xad, 0x8b, 0x33, 0xff, 0xa7, 0x2e, 0xce, 0x58, 0x1f,
+	0x29, 0xef, 0x84, 0x35, 0x8f, 0xf5, 0xc5, 0x74, 0x2d, 0xd6, 0xd1, 0xd5,
+	0xaf, 0xdd, 0x47, 0xab, 0x74, 0xfc, 0x51, 0x81, 0xf6, 0x2a, 0xa5, 0x39,
+	0xe5, 0x7f, 0x4e, 0xf1, 0x6c, 0xb9, 0xc7, 0xab, 0xdc, 0xe3, 0xf0, 0x82,
+	0x62, 0x20, 0xbf, 0xa6, 0x32, 0x7c, 0xb2, 0x40, 0x1d, 0xd3, 0x2a, 0xb3,
+	0x33, 0xbe, 0x9e, 0x19, 0xf3, 0x7c, 0xdc, 0xfc, 0x9a, 0x26, 0xd5, 0x33,
+	0xf0, 0x6e, 0x9c, 0x11, 0xcf, 0xbe, 0x74, 0x4b, 0xe9, 0x3c, 0xed, 0x6e,
+	0x12, 0x7d, 0xd1, 0x40, 0x69, 0x8e, 0xb5, 0x49, 0x62, 0x50, 0x86, 0x85,
+	0x75, 0xff, 0x11, 0xfb, 0x38, 0xe4, 0x2d, 0x26, 0xef, 0x4f, 0xd1, 0xa7,
+	0x6f, 0x82, 0x6f, 0xdc, 0xd6, 0x70, 0xbe, 0xdb, 0xab, 0x3e, 0x61, 0x3d,
+	0xdd, 0x37, 0x74, 0x4a, 0x0b, 0xf9, 0xdc, 0xb1, 0x6f, 0x08, 0x7d, 0x30,
+	0x5e, 0x67, 0x11, 0x0b, 0x30, 0xf6, 0x88, 0x6b, 0xec, 0x51, 0x2a, 0xb2,
+	0xaf, 0xd5, 0xcb, 0x2b, 0xb5, 0x2a, 0xaf, 0x90, 0xdf, 0x32, 0xea, 0x7f,
+	0x0f, 0xa9, 0xce, 0xca, 0x4f, 0xf5, 0x1a, 0xfc, 0x8a, 0x1d, 0x53, 0xde,
+	0x93, 0x3a, 0xde, 0x8b, 0x79, 0x6b, 0x3f, 0xdc, 0x69, 0x7c, 0x2b, 0x5b,
+	0xf5, 0x4d, 0x58, 0xc7, 0xd1, 0xae, 0x70, 0x7e, 0xf2, 0x06, 0x79, 0x84,
+	0x3a, 0xcf, 0x1f, 0xe7, 0xd3, 0xc3, 0x6f, 0x73, 0x3c, 0xf9, 0xbf, 0x16,
+	0x8b, 0xe0, 0xcb, 0xaa, 0xdf, 0xe7, 0xcb, 0x1d, 0xef, 0xd5, 0xda, 0x04,
+	0xca, 0x5d, 0x6d, 0x7d, 0xd2, 0x96, 0xc8, 0xf4, 0x12, 0x5d, 0xd2, 0xfd,
+	0xdc, 0xff, 0x4b, 0xcc, 0xed, 0x42, 0xde, 0x96, 0xa3, 0xcd, 0x51, 0xa5,
+	0x4d, 0x06, 0xb4, 0x89, 0x28, 0x6d, 0x18, 0xef, 0x3d, 0xe3, 0xf1, 0x5b,
+	0x2b, 0xce, 0x8b, 0xb9, 0x5a, 0xe8, 0xba, 0xbd, 0xd4, 0xf9, 0xcf, 0x77,
+	0x6a, 0x7d, 0xd0, 0xa1, 0xee, 0x5b, 0x05, 0x7d, 0xc6, 0xf6, 0x66, 0xf5,
+	0x47, 0x4c, 0xbc, 0x15, 0xd7, 0x3c, 0x68, 0x10, 0xfa, 0xb9, 0x34, 0x05,
+	0x5f, 0x8d, 0x78, 0xb7, 0x3a, 0x5a, 0x7d, 0xc7, 0x3b, 0xaf, 0x92, 0xd2,
+	0x86, 0x32, 0x40, 0xbd, 0xb9, 0x1a, 0xf3, 0xed, 0x8e, 0xf6, 0x81, 0xbf,
+	0x7e, 0x81, 0xfe, 0x8d, 0x1a, 0x4f, 0x04, 0x21, 0xf3, 0x37, 0xa7, 0x3a,
+	0xbc, 0x18, 0xce, 0x41, 0x1b, 0x71, 0xeb, 0x54, 0x84, 0x31, 0x05, 0xda,
+	0x5b, 0xa4, 0x69, 0x1a, 0xf1, 0x2b, 0xf4, 0xf8, 0x82, 0xda, 0xa3, 0x3e,
+	0xdc, 0xbf, 0x8b, 0x18, 0x3f, 0x5c, 0x1f, 0xc6, 0x73, 0xbd, 0x06, 0x8b,
+	0x10, 0xdd, 0xa4, 0x67, 0x5a, 0x9a, 0x4a, 0xc4, 0x0e, 0x8a, 0xd7, 0x37,
+	0xee, 0xaa, 0x3e, 0x58, 0xda, 0xd7, 0x43, 0xb2, 0xbb, 0x6a, 0x2f, 0x18,
+	0x47, 0xc3, 0x87, 0x9f, 0x31, 0xf6, 0x20, 0x5f, 0xec, 0x53, 0x5c, 0x54,
+	0x70, 0x68, 0x1e, 0x67, 0x49, 0x9f, 0x74, 0x11, 0x7e, 0xb8, 0x8b, 0x33,
+	0xa4, 0xdf, 0x5d, 0x39, 0x76, 0xc2, 0x4d, 0xb1, 0x3e, 0x06, 0x7d, 0x70,
+	0x4c, 0x46, 0x10, 0x17, 0x8c, 0x04, 0xdb, 0x98, 0x57, 0x86, 0x6f, 0x98,
+	0xf3, 0x72, 0x8f, 0x7d, 0xcc, 0x99, 0xca, 0xd9, 0x39, 0xee, 0x9d, 0xb2,
+	0x6d, 0x62, 0xef, 0xd2, 0x14, 0xf7, 0x6b, 0xf2, 0x10, 0x6c, 0x5b, 0xd3,
+	0x2e, 0x7e, 0x79, 0x16, 0x03, 0xf8, 0x1d, 0x84, 0x3c, 0x70, 0x2c, 0x7e,
+	0xe7, 0x16, 0xe5, 0xdd, 0xf3, 0xbe, 0x6d, 0x0f, 0xc8, 0x3b, 0x4e, 0xe5,
+	0xd8, 0x71, 0x77, 0x0d, 0xcf, 0xc0, 0xcd, 0xb1, 0x66, 0xed, 0x38, 0x6e,
+	0x5e, 0x2a, 0x95, 0x05, 0x77, 0x61, 0x8d, 0xa5, 0xb4, 0xa4, 0xfc, 0xff,
+	0x03, 0x67, 0x78, 0xfd, 0x3e, 0x4b, 0x0c, 0xfd, 0x48, 0x9b, 0xcf, 0xd7,
+	0xfe, 0x6a, 0x6d, 0x81, 0xaf, 0xff, 0xc8, 0x8f, 0xe4, 0xcb, 0x45, 0xd9,
+	0xa9, 0xfa, 0x7f, 0xb9, 0xe7, 0x6a, 0x75, 0xbf, 0xef, 0xdf, 0x52, 0xbf,
+	0x93, 0x17, 0x63, 0x1a, 0x1f, 0x6c, 0x9a, 0x6e, 0xd4, 0x09, 0x4f, 0x78,
+	0x75, 0x85, 0xe5, 0x78, 0x6f, 0xbf, 0xa7, 0x17, 0x52, 0xea, 0x3b, 0xa7,
+	0x6c, 0xea, 0x07, 0xee, 0xa7, 0x45, 0x26, 0x2e, 0xdc, 0x01, 0x4d, 0x7c,
+	0x1d, 0xcc, 0xb8, 0xcf, 0xd7, 0x1d, 0x6d, 0x9e, 0x2f, 0x6c, 0x49, 0xcf,
+	0x59, 0xfa, 0x4e, 0x0e, 0xf4, 0x68, 0xbb, 0x64, 0xc6, 0x83, 0x92, 0x3c,
+	0x1b, 0x8b, 0x19, 0x5f, 0x97, 0xfc, 0x07, 0x79, 0xd3, 0x3e, 0xad, 0x45,
+	0xa1, 0xff, 0x6e, 0xe1, 0xda, 0x86, 0x9f, 0x21, 0xcf, 0x7b, 0xfd, 0x7b,
+	0x76, 0x03, 0x8f, 0xee, 0xf0, 0x78, 0x94, 0xf7, 0x2d, 0x53, 0xff, 0xc0,
+	0xd8, 0x9e, 0xb3, 0xdc, 0xa3, 0x79, 0xae, 0xe7, 0xac, 0x89, 0xd7, 0xeb,
+	0x9f, 0xeb, 0xab, 0x3e, 0x87, 0xfb, 0xf0, 0x7d, 0xcd, 0xdc, 0x3b, 0x07,
+	0xe1, 0xd3, 0xf5, 0xd1, 0xe6, 0xd0, 0x7e, 0x6f, 0x74, 0x77, 0x0a, 0xf9,
+	0x3d, 0xe1, 0xf1, 0x1c, 0xf5, 0x4d, 0xc4, 0xd3, 0x37, 0x4b, 0xf6, 0x65,
+	0xc4, 0xe0, 0x4f, 0x98, 0x13, 0xa9, 0xb1, 0x2f, 0x4f, 0x98, 0x77, 0xab,
+	0xb3, 0x2f, 0x77, 0x7b, 0xf3, 0xf8, 0xf7, 0x7c, 0xbd, 0xe2, 0xb7, 0x7d,
+	0xbd, 0xd2, 0xe8, 0xd3, 0xfa, 0xb4, 0xaf, 0xed, 0xaf, 0x8f, 0xf9, 0xf2,
+	0xcb, 0xe6, 0x5d, 0xb2, 0x88, 0xd9, 0xe8, 0x53, 0x26, 0x72, 0x06, 0x2f,
+	0x6d, 0x9d, 0xb1, 0x88, 0xfb, 0x70, 0x7e, 0x22, 0xe9, 0xc8, 0x1d, 0x8d,
+	0xad, 0x4f, 0x5e, 0x18, 0xd3, 0x3c, 0x4f, 0xc9, 0xf5, 0xf4, 0x4e, 0x74,
+	0x17, 0xe4, 0xea, 0x4a, 0x64, 0x09, 0x53, 0x34, 0x73, 0x34, 0x0d, 0x3b,
+	0x94, 0xd2, 0x7a, 0xd9, 0xf7, 0xb0, 0xdf, 0x41, 0xc5, 0x73, 0xad, 0x74,
+	0x5e, 0x94, 0x47, 0xec, 0x8a, 0xd6, 0x6e, 0x9a, 0x87, 0x8a, 0x47, 0x9b,
+	0x4f, 0xfb, 0x7c, 0x4f, 0x7e, 0x9a, 0x39, 0x3a, 0x31, 0x53, 0x19, 0x0e,
+	0x6d, 0xeb, 0xb5, 0xf3, 0x42, 0xbc, 0xfe, 0xb0, 0x1c, 0x52, 0xdc, 0xf0,
+	0xab, 0xb8, 0xbf, 0x97, 0xf1, 0x65, 0x22, 0xa4, 0x78, 0xe0, 0x44, 0x6c,
+	0x12, 0xb2, 0x98, 0x75, 0x89, 0xef, 0x5f, 0xa5, 0x38, 0xff, 0x92, 0xd0,
+	0xcf, 0x22, 0xa6, 0xe0, 0x05, 0x39, 0xe8, 0x6e, 0x74, 0x17, 0xc4, 0xf8,
+	0xbf, 0x59, 0xad, 0x09, 0xad, 0x90, 0x49, 0x37, 0xd4, 0x9c, 0x2e, 0x1b,
+	0x19, 0x18, 0x0d, 0xa6, 0x56, 0x9e, 0x70, 0xa2, 0xcd, 0x3b, 0xcb, 0x90,
+	0xf1, 0x32, 0xf4, 0x7f, 0x39, 0x16, 0x18, 0x51, 0x6c, 0xda, 0x57, 0x24,
+	0xdd, 0x41, 0x3f, 0x9f, 0xfa, 0xe4, 0x01, 0xb9, 0x69, 0x6f, 0x96, 0x9b,
+	0x5b, 0x88, 0xc3, 0xec, 0x47, 0x9b, 0xba, 0x64, 0x10, 0x7d, 0x49, 0xf4,
+	0x35, 0x2b, 0x3f, 0x6a, 0x7c, 0x06, 0x9d, 0x75, 0xd3, 0xa6, 0xae, 0x5a,
+	0xcf, 0x5f, 0xbc, 0xeb, 0x22, 0x68, 0x42, 0x6c, 0xc7, 0x56, 0xb4, 0xa9,
+	0xe3, 0xec, 0x86, 0xfe, 0x2e, 0xb4, 0xef, 0xc3, 0x1c, 0x4d, 0xfa, 0x7e,
+	0x96, 0xb3, 0xcd, 0xd4, 0x39, 0xeb, 0xc6, 0xac, 0x6e, 0x68, 0xff, 0xb1,
+	0xdd, 0xe0, 0x13, 0x3e, 0x25, 0xbd, 0x73, 0x29, 0xd9, 0xd5, 0x59, 0xdf,
+	0xfe, 0x77, 0x43, 0xbb, 0x4d, 0x56, 0xb6, 0x93, 0x0c, 0x4f, 0x75, 0xd4,
+	0xf7, 0xfb, 0xfc, 0xe4, 0xb7, 0x3b, 0xf1, 0xbe, 0x09, 0x18, 0xbc, 0xa4,
+	0xc6, 0x52, 0x37, 0xa3, 0x5c, 0xeb, 0x83, 0x86, 0x67, 0x78, 0xcd, 0x67,
+	0xf8, 0x2c, 0xf3, 0x7a, 0x9f, 0xb1, 0x1f, 0xcf, 0x30, 0x27, 0xc0, 0xbc,
+	0x06, 0x79, 0x76, 0xb9, 0x38, 0x8b, 0x63, 0x3e, 0x9f, 0x6f, 0xc8, 0x54,
+	0x79, 0xcf, 0xd7, 0x2b, 0xb1, 0x2a, 0x56, 0x6d, 0x67, 0xc1, 0xcf, 0x09,
+	0x93, 0x76, 0x5a, 0x93, 0x8a, 0xdd, 0x00, 0x9d, 0x0f, 0x80, 0xce, 0x0f,
+	0x05, 0x19, 0x17, 0xb6, 0x78, 0xb4, 0x76, 0x64, 0xa4, 0xfc, 0x5b, 0xc8,
+	0x38, 0x79, 0x14, 0x3e, 0x45, 0xd9, 0xf2, 0xf0, 0x19, 0x03, 0xb0, 0x69,
+	0xae, 0x04, 0x35, 0xef, 0x80, 0xf8, 0x7e, 0xf6, 0xba, 0x8c, 0x4c, 0x31,
+	0x27, 0x40, 0x7e, 0x66, 0x5c, 0x9f, 0xc2, 0xbd, 0x5b, 0x18, 0xeb, 0x42,
+	0x86, 0xc7, 0xc0, 0xaf, 0x21, 0x71, 0xa6, 0xb7, 0x4a, 0x6e, 0x7c, 0x4c,
+	0x7d, 0x80, 0x1e, 0xd8, 0xa8, 0xe3, 0xee, 0xa8, 0x9c, 0xb8, 0xb2, 0x01,
+	0xb2, 0xca, 0xb8, 0x5f, 0x73, 0x1a, 0x95, 0xb0, 0xfa, 0xe6, 0xf4, 0x39,
+	0x98, 0x87, 0x33, 0x35, 0x66, 0x23, 0xb7, 0x93, 0x31, 0x69, 0x1b, 0x95,
+	0x99, 0x0b, 0xb6, 0xe2, 0x5d, 0x52, 0x72, 0xa7, 0x42, 0xda, 0x65, 0xf7,
+	0xc6, 0xa1, 0xab, 0xe8, 0xcb, 0x9f, 0x8c, 0x98, 0xb3, 0x7c, 0x74, 0x2d,
+	0x63, 0xe2, 0xe4, 0x74, 0xed, 0x1c, 0x8a, 0x91, 0xc1, 0xbd, 0xd7, 0xda,
+	0x8d, 0xcc, 0x30, 0x3e, 0xfe, 0xa0, 0x92, 0x8a, 0x72, 0x4d, 0x8e, 0x65,
+	0xed, 0x96, 0x3c, 0xc2, 0xbd, 0x7d, 0xea, 0xf1, 0xf2, 0xcf, 0x30, 0x5f,
+	0x5c, 0x7a, 0x5e, 0x1f, 0xd3, 0xb8, 0xfe, 0x78, 0x5d, 0x0c, 0x6b, 0xf2,
+	0x05, 0x26, 0x8e, 0xbd, 0x2e, 0x93, 0xf3, 0xa4, 0x0f, 0x6d, 0x7c, 0x40,
+	0x5e, 0x73, 0x7a, 0xed, 0x27, 0xb5, 0xd6, 0x98, 0x48, 0xb1, 0x3e, 0xd3,
+	0xe2, 0x24, 0xed, 0x59, 0x09, 0x0d, 0x7e, 0x15, 0xd7, 0x8c, 0x6b, 0xf3,
+	0x6e, 0xaf, 0xfb, 0xa4, 0xf8, 0x38, 0x90, 0x8d, 0xa9, 0x15, 0x81, 0xdb,
+	0x95, 0xeb, 0x7b, 0x39, 0xc6, 0xe0, 0x40, 0x24, 0x40, 0x5a, 0xbd, 0xb7,
+	0x9e, 0xf8, 0x99, 0xfa, 0xfc, 0xdf, 0x83, 0x4f, 0xef, 0x19, 0x48, 0x9c,
+	0x62, 0x0c, 0x1b, 0x76, 0xbe, 0xb5, 0xd6, 0xbc, 0x6b, 0x2e, 0xb7, 0x5a,
+	0xb4, 0x7e, 0x76, 0xe4, 0x23, 0x87, 0x78, 0x88, 0x44, 0x6c, 0x85, 0xc5,
+	0x3c, 0x38, 0x75, 0x1c, 0x6b, 0x2a, 0xcc, 0xb9, 0x11, 0xc7, 0xdf, 0x2c,
+	0x97, 0xfb, 0x2c, 0x79, 0x30, 0x94, 0x8a, 0x5b, 0xb2, 0x29, 0x7e, 0x56,
+	0xb0, 0x26, 0xeb, 0x2b, 0xf3, 0x89, 0x1c, 0xc7, 0x87, 0xa6, 0x39, 0x5f,
+	0x5c, 0xe3, 0x95, 0xe4, 0xa6, 0x4a, 0xe5, 0x19, 0x57, 0x02, 0xc9, 0x7b,
+	0x3f, 0xac, 0xb0, 0x16, 0x6e, 0xbd, 0xfe, 0x45, 0x38, 0x05, 0xea, 0x8a,
+	0x55, 0x93, 0x06, 0x73, 0x78, 0xe2, 0x48, 0xcf, 0x3c, 0xdb, 0xdf, 0x7d,
+	0xc4, 0xb4, 0x4f, 0xa1, 0xdd, 0xe4, 0x61, 0x9d, 0xa6, 0x8e, 0xf4, 0x14,
+	0x9f, 0x5a, 0x6b, 0xe2, 0xef, 0x45, 0xc5, 0x7f, 0xbd, 0x5d, 0x17, 0xd3,
+	0xa4, 0x02, 0xe3, 0x85, 0xb1, 0xc0, 0x58, 0xc1, 0xea, 0x6b, 0x06, 0xad,
+	0xe6, 0x5c, 0xe6, 0x6a, 0xfc, 0x9c, 0x15, 0xf3, 0xfd, 0x22, 0xdf, 0x57,
+	0x8c, 0x14, 0x6b, 0x8a, 0x96, 0xfa, 0x42, 0x07, 0xe6, 0x98, 0xe3, 0x8f,
+	0xa8, 0x3e, 0x38, 0x38, 0xdf, 0x26, 0x79, 0x7b, 0x8d, 0xe4, 0x55, 0xc6,
+	0xa3, 0xaa, 0x03, 0x2c, 0xe7, 0x5e, 0xf4, 0x71, 0xdf, 0x4f, 0x28, 0x2e,
+	0xe2, 0xcd, 0x42, 0x17, 0xda, 0xcc, 0x35, 0x6f, 0x6f, 0xe8, 0xaf, 0xad,
+	0xcb, 0x26, 0x6c, 0xcb, 0x6a, 0xac, 0xc9, 0xb2, 0xaf, 0xb1, 0x16, 0x7b,
+	0x52, 0xae, 0x93, 0x6f, 0xca, 0x7e, 0xce, 0xdd, 0xf5, 0x72, 0xee, 0xdf,
+	0xee, 0x32, 0x18, 0x61, 0xc9, 0x84, 0x86, 0x9a, 0xfb, 0x8e, 0x4f, 0x05,
+	0x6f, 0x2d, 0xe5, 0x4f, 0xd1, 0x9e, 0xaf, 0xd6, 0xca, 0x71, 0xef, 0x39,
+	0x62, 0xc5, 0xe1, 0x57, 0xe4, 0xbc, 0xef, 0x0e, 0x78, 0xbf, 0xfa, 0xfc,
+	0xff, 0xd8, 0x53, 0x8b, 0xd6, 0xd9, 0xad, 0xba, 0x3a, 0xfb, 0xe3, 0x78,
+	0x96, 0x35, 0xf6, 0x5c, 0xa5, 0x09, 0xbc, 0xdb, 0x44, 0x9c, 0x48, 0x75,
+	0x3c, 0x75, 0xbc, 0xea, 0x72, 0x9d, 0x6b, 0xa7, 0x37, 0x57, 0x10, 0x7a,
+	0x7e, 0x62, 0xca, 0x1f, 0x73, 0x4c, 0x56, 0xf4, 0x27, 0x62, 0x41, 0x8b,
+	0x63, 0x8c, 0xbe, 0x4f, 0xbb, 0xc7, 0xa0, 0xc7, 0xa9, 0xf3, 0xf9, 0xde,
+	0x0e, 0x7c, 0x3d, 0xea, 0x02, 0xea, 0x73, 0xb5, 0x01, 0xf1, 0x3c, 0x74,
+	0xfd, 0x48, 0x59, 0x73, 0xf9, 0xb1, 0x87, 0x83, 0x89, 0x99, 0xac, 0xea,
+	0x06, 0xf8, 0x7b, 0xe5, 0x6b, 0xcc, 0x07, 0x9d, 0x92, 0x40, 0x6d, 0x9d,
+	0x86, 0xb1, 0x19, 0x6b, 0x1a, 0xad, 0xd0, 0x0d, 0x22, 0x57, 0xc1, 0x1b,
+	0x6f, 0xcc, 0x91, 0x5f, 0x83, 0x1d, 0x26, 0xbe, 0x5a, 0xd8, 0x6e, 0x49,
+	0x87, 0xd6, 0x3e, 0xf3, 0x4e, 0x84, 0xfe, 0xc9, 0x70, 0xb2, 0x1f, 0x7e,
+	0xb6, 0x62, 0x0f, 0x98, 0xaf, 0x9c, 0x40, 0x3c, 0x56, 0x9b, 0x63, 0x81,
+	0x7c, 0x8d, 0xb3, 0x3f, 0x0b, 0xbf, 0x72, 0xa9, 0xee, 0x91, 0x2f, 0x9e,
+	0xd0, 0xdc, 0x66, 0x69, 0xae, 0x55, 0x75, 0x6c, 0xa9, 0xf8, 0x30, 0xce,
+	0x45, 0x36, 0x5b, 0x43, 0x79, 0xaf, 0x3f, 0x2c, 0xc5, 0x22, 0xdb, 0xd2,
+	0xdd, 0xa4, 0xe7, 0xee, 0xd7, 0x76, 0x6c, 0x99, 0x85, 0xaf, 0x58, 0x9c,
+	0x77, 0xf0, 0xbf, 0x05, 0xff, 0x7d, 0xf8, 0xdf, 0x25, 0xe9, 0x69, 0xfa,
+	0xaf, 0xac, 0xe5, 0xb4, 0x36, 0xac, 0x1f, 0xf6, 0x70, 0xe0, 0xf4, 0x6b,
+	0x4d, 0x9c, 0x93, 0x2f, 0x36, 0xca, 0x09, 0xf3, 0xa4, 0xbe, 0x8e, 0x60,
+	0xbe, 0xd4, 0xaf, 0xf5, 0xd5, 0xd6, 0xb0, 0x2c, 0xaf, 0xee, 0x45, 0x9e,
+	0x6e, 0x91, 0x83, 0x45, 0xbf, 0x76, 0x15, 0x93, 0x43, 0xd5, 0xda, 0x95,
+	0x64, 0x82, 0x43, 0xb7, 0x1f, 0xcb, 0x4e, 0x29, 0x9e, 0xc0, 0xb2, 0x86,
+	0xae, 0x3f, 0x36, 0x39, 0xff, 0xce, 0x63, 0x4b, 0x98, 0x70, 0xdc, 0x9b,
+	0x5f, 0x0e, 0x33, 0x44, 0x2c, 0x1d, 0xbf, 0x93, 0x53, 0xdf, 0x0d, 0xfb,
+	0xf6, 0x63, 0x1e, 0xe2, 0xec, 0xe2, 0xf6, 0x12, 0x7e, 0xd9, 0x8f, 0x47,
+	0x89, 0x23, 0xe5, 0x73, 0xb5, 0xd8, 0x8f, 0x10, 0xce, 0x5f, 0x02, 0x96,
+	0x93, 0xc3, 0x3e, 0x2e, 0x76, 0x19, 0x3f, 0x90, 0x38, 0xd3, 0x44, 0x0d,
+	0xf6, 0xc8, 0xc7, 0x9a, 0x5e, 0xc4, 0x5c, 0x19, 0xf9, 0x7d, 0xf9, 0x71,
+	0xf9, 0x75, 0x79, 0x0c, 0xf2, 0x3d, 0x89, 0x39, 0xf7, 0xcb, 0xaf, 0xca,
+	0x7b, 0xe5, 0x5a, 0x79, 0x5c, 0xde, 0x2a, 0xef, 0x42, 0x4c, 0x35, 0x4a,
+	0xac, 0xa7, 0x87, 0x95, 0x1e, 0x96, 0x89, 0x73, 0x8a, 0x01, 0xbc, 0x45,
+	0xbf, 0xe7, 0x88, 0xfa, 0xd9, 0x01, 0xf2, 0xf4, 0x6f, 0x18, 0xcf, 0x13,
+	0x9b, 0x59, 0x2c, 0xfb, 0x18, 0x8e, 0x43, 0xdd, 0x58, 0xdb, 0xe6, 0x37,
+	0x29, 0x23, 0xe7, 0x22, 0x81, 0xd1, 0x73, 0xa1, 0xc0, 0x43, 0xfa, 0x7d,
+	0x0b, 0xeb, 0x9d, 0x15, 0x39, 0xe1, 0x3a, 0xe4, 0xcd, 0xc1, 0x11, 0xc8,
+	0xc2, 0x28, 0x54, 0xfd, 0x23, 0xce, 0x1a, 0x01, 0x49, 0x53, 0x1f, 0xc3,
+	0xcf, 0x4c, 0x9e, 0x76, 0x25, 0x5b, 0x98, 0x0d, 0x18, 0x3c, 0x9a, 0x8d,
+	0x76, 0x1f, 0xda, 0xbf, 0xf4, 0xda, 0x3b, 0x24, 0x7b, 0x41, 0x52, 0xef,
+	0xab, 0x3f, 0xfc, 0x73, 0xaf, 0x6f, 0x10, 0x7d, 0xe0, 0xcc, 0x57, 0xd8,
+	0xf7, 0x8a, 0xd7, 0xc7, 0x33, 0x61, 0xad, 0x3e, 0xae, 0x7c, 0x95, 0xb5,
+	0xc7, 0x85, 0xdf, 0x2f, 0x18, 0x4c, 0xe8, 0xfb, 0x5d, 0x46, 0xb7, 0x11,
+	0x13, 0xf8, 0xaf, 0x2e, 0xc6, 0x60, 0x45, 0xc8, 0xd7, 0x7a, 0xe8, 0xc4,
+	0xbf, 0x6f, 0x5e, 0x6a, 0x5b, 0x43, 0x9f, 0xd4, 0x60, 0xb4, 0x3f, 0x91,
+	0x9e, 0xf9, 0xdb, 0x1e, 0x9e, 0xf7, 0x30, 0xde, 0x0d, 0x67, 0x55, 0x20,
+	0x6e, 0x3c, 0x0e, 0xd9, 0x6e, 0x95, 0x35, 0x67, 0x48, 0xaf, 0x5e, 0xe8,
+	0xea, 0x14, 0xe4, 0xd6, 0x95, 0xb9, 0x72, 0x28, 0x30, 0x52, 0x48, 0x89,
+	0xc1, 0x53, 0x5b, 0x92, 0x89, 0xa6, 0xe4, 0xe4, 0x40, 0x62, 0x0b, 0xf3,
+	0x90, 0xd9, 0x7e, 0x57, 0x2e, 0x95, 0x69, 0x8f, 0x73, 0x72, 0x79, 0x20,
+	0xe1, 0x16, 0x85, 0xb8, 0x18, 0x57, 0x2e, 0x43, 0x36, 0xff, 0x70, 0x6e,
+	0x97, 0x1c, 0x2a, 0xa8, 0x1f, 0xdc, 0x1b, 0x96, 0x97, 0xe5, 0xd2, 0xc0,
+	0xcb, 0xb7, 0x2e, 0xb9, 0x93, 0x38, 0x53, 0xf2, 0xe1, 0x81, 0x6e, 0xb3,
+	0x6f, 0xc5, 0x21, 0x09, 0xf3, 0x21, 0x5a, 0x53, 0x73, 0x56, 0x48, 0x7a,
+	0x5f, 0xc4, 0x8b, 0xcb, 0xe1, 0x73, 0x07, 0xee, 0x33, 0xf5, 0x94, 0x80,
+	0xbf, 0xcf, 0x30, 0xfc, 0x18, 0x3e, 0xe7, 0xd3, 0xc6, 0x9f, 0xa7, 0x2b,
+	0x90, 0xbe, 0xd0, 0x26, 0xa1, 0x57, 0xbe, 0x0c, 0xba, 0x86, 0xe4, 0x40,
+	0x7f, 0xa5, 0xf2, 0x0d, 0x37, 0x14, 0x9f, 0x44, 0x8c, 0x82, 0xfd, 0xcb,
+	0xea, 0xd3, 0xed, 0xa0, 0x49, 0xb3, 0x44, 0x4f, 0xfb, 0xeb, 0xad, 0xf0,
+	0xb0, 0x0c, 0xe7, 0x57, 0x1b, 0x5b, 0xe6, 0x63, 0x1b, 0xfc, 0xf9, 0x0c,
+	0xa6, 0xac, 0xc7, 0xea, 0x0f, 0x78, 0xdf, 0x49, 0x78, 0xed, 0x7b, 0x03,
+	0x0f, 0x86, 0x3a, 0x24, 0xe4, 0xfc, 0x70, 0x1d, 0xb1, 0x91, 0x0b, 0x05,
+	0xbf, 0x1f, 0x7e, 0x62, 0xc8, 0xf7, 0x87, 0x65, 0xdb, 0xd2, 0x59, 0xcb,
+	0xb6, 0x9e, 0xf9, 0x6f, 0x7a, 0x73, 0xa6, 0xbc, 0xb1, 0x88, 0x39, 0x62,
+	0xab, 0xd4, 0x3e, 0x99, 0xb1, 0x9f, 0xc9, 0xb3, 0xfd, 0x89, 0x57, 0x15,
+	0x27, 0x5b, 0x7d, 0x86, 0xf7, 0x11, 0x43, 0x96, 0xf5, 0x99, 0xd8, 0x6e,
+	0xd0, 0x37, 0x13, 0xbb, 0xc7, 0x9e, 0xb5, 0x82, 0x01, 0xe3, 0x8f, 0x34,
+	0xc9, 0x0f, 0xa2, 0xb0, 0xdb, 0x88, 0xf1, 0xb2, 0xcc, 0x7f, 0xb9, 0x77,
+	0x3c, 0x3f, 0x85, 0x7d, 0x89, 0x53, 0x49, 0x6b, 0x02, 0xfb, 0xe3, 0x19,
+	0x10, 0x03, 0x6a, 0x81, 0x4e, 0x5d, 0x78, 0x3f, 0xc4, 0x4f, 0xfd, 0xfe,
+	0xfb, 0xaf, 0x86, 0x0e, 0xe3, 0xfe, 0x0d, 0x2e, 0x4c, 0x2c, 0xe6, 0x42,
+	0x86, 0x3d, 0x0c, 0x6c, 0xad, 0xdc, 0xfa, 0xd8, 0x58, 0x1f, 0x4f, 0x47,
+	0x8c, 0x52, 0x0c, 0x7e, 0x20, 0x65, 0x82, 0xbc, 0xd9, 0x89, 0xfe, 0x95,
+	0xb7, 0x53, 0xfa, 0xea, 0x7e, 0xdf, 0x87, 0x55, 0x6c, 0xf7, 0x64, 0x61,
+	0xaf, 0xc1, 0xe6, 0x59, 0x8b, 0x92, 0xea, 0x4e, 0xda, 0x27, 0xb0, 0xdf,
+	0x74, 0x28, 0x51, 0xcc, 0x49, 0x4c, 0x66, 0xa1, 0x2f, 0xde, 0x80, 0xec,
+	0x5f, 0x2b, 0xc7, 0x03, 0x69, 0xec, 0xe9, 0x60, 0x61, 0x48, 0x26, 0x2f,
+	0xe8, 0x37, 0x5f, 0xd0, 0xfb, 0x43, 0x52, 0x2a, 0x24, 0xb6, 0xcc, 0x82,
+	0xff, 0x66, 0x0b, 0xc4, 0x17, 0xf5, 0xc6, 0x47, 0x31, 0xe3, 0x42, 0x61,
+	0x23, 0xec, 0x83, 0xa4, 0x2e, 0xc1, 0xff, 0xb9, 0x54, 0xde, 0x02, 0x3e,
+	0xc3, 0xfd, 0xb2, 0x83, 0x5f, 0xe8, 0xcc, 0xf2, 0x00, 0xe4, 0x9c, 0x7b,
+	0xb1, 0x65, 0x6e, 0x33, 0xce, 0x8e, 0x38, 0x22, 0xc5, 0x8f, 0xff, 0x07,
+	0xe7, 0xeb, 0xbf, 0xf7, 0x76, 0xb5, 0xd3, 0xb3, 0xba, 0x2f, 0xd8, 0x65,
+	0xc4, 0x00, 0xd9, 0x7e, 0x63, 0xb7, 0xd3, 0x91, 0x76, 0x49, 0xdf, 0x43,
+	0x3b, 0xde, 0xa1, 0x31, 0xa2, 0xf2, 0x62, 0x84, 0xf7, 0xdf, 0x59, 0x67,
+	0xe8, 0x17, 0x6e, 0x68, 0xbf, 0x8d, 0xdf, 0x36, 0xe9, 0x74, 0xf8, 0x6b,
+	0xe3, 0xf7, 0xc6, 0x3a, 0xd6, 0x77, 0x3b, 0x9d, 0x24, 0xd6, 0xfa, 0x9d,
+	0x97, 0x2f, 0xc0, 0xf5, 0x2c, 0x9f, 0x59, 0xeb, 0xad, 0xcb, 0x79, 0xdb,
+	0x30, 0x4f, 0xab, 0xb7, 0x56, 0x9b, 0xe6, 0x27, 0xcd, 0x5a, 0x88, 0x71,
+	0x0b, 0xef, 0xad, 0xd3, 0xef, 0x8c, 0x61, 0x2f, 0xea, 0xdb, 0x7f, 0x5d,
+	0x47, 0xdc, 0x5c, 0xa7, 0xd3, 0xa6, 0x18, 0xcf, 0x9b, 0x1d, 0x1d, 0xb8,
+	0xe6, 0x9a, 0x1c, 0x63, 0xf2, 0xe1, 0xa5, 0x32, 0xe7, 0x67, 0x3b, 0x25,
+	0x47, 0x35, 0x9f, 0x61, 0xb0, 0x7c, 0xa5, 0xc2, 0xfd, 0x32, 0x79, 0x4e,
+	0xf1, 0x75, 0x33, 0x79, 0x8b, 0xdf, 0xbd, 0xf0, 0x3b, 0x39, 0xfa, 0x12,
+	0x63, 0x32, 0x81, 0xf3, 0xbb, 0x0c, 0x9f, 0x6a, 0xc1, 0x7c, 0x13, 0x8b,
+	0xbf, 0xfd, 0x38, 0x97, 0x10, 0x64, 0x8c, 0x32, 0x4a, 0x99, 0xc2, 0xf9,
+	0x8d, 0xdb, 0xf2, 0xee, 0x00, 0xe5, 0x79, 0x40, 0xae, 0x54, 0xe5, 0x39,
+	0x07, 0x79, 0xa6, 0x2c, 0xe7, 0x20, 0xd3, 0x86, 0xaf, 0xf7, 0xf1, 0x1b,
+	0x6b, 0x84, 0xeb, 0x25, 0xf5, 0x21, 0x2e, 0x82, 0xaf, 0x6d, 0x13, 0x97,
+	0x2b, 0x2e, 0xfe, 0x30, 0xf4, 0x5a, 0x93, 0xf7, 0x1d, 0x00, 0xae, 0xaf,
+	0xbc, 0x28, 0xe9, 0x0b, 0x2d, 0xd8, 0x77, 0xbc, 0x9b, 0x67, 0x96, 0xbd,
+	0xc2, 0x7f, 0x9f, 0x17, 0x89, 0x37, 0xa5, 0x3f, 0xcb, 0x6b, 0xc6, 0x79,
+	0xeb, 0x31, 0x66, 0x10, 0x74, 0x6e, 0xc1, 0xfc, 0xdc, 0xe3, 0x72, 0xe3,
+	0x78, 0x3f, 0x54, 0x83, 0x4f, 0xf5, 0xe9, 0xbd, 0x4a, 0xd7, 0xcc, 0xea,
+	0x37, 0x5a, 0x46, 0x06, 0x27, 0x0a, 0xe4, 0xfb, 0x18, 0xf8, 0x96, 0x3e,
+	0x31, 0xf9, 0x25, 0xa5, 0xe7, 0x50, 0x2a, 0x90, 0x7f, 0x43, 0x9a, 0xc3,
+	0xc8, 0xc2, 0xb6, 0xec, 0xd1, 0xf1, 0xb1, 0x25, 0xf9, 0xee, 0x0e, 0x68,
+	0xdc, 0x9d, 0x2d, 0xac, 0x94, 0x1e, 0xd5, 0x41, 0xdd, 0x1e, 0x6f, 0xc3,
+	0x5e, 0x28, 0x96, 0x7b, 0xbf, 0x1c, 0x29, 0x0f, 0x82, 0x0e, 0x31, 0x79,
+	0x06, 0x7e, 0xf3, 0x73, 0xe5, 0xbb, 0x64, 0x31, 0x82, 0x7d, 0x55, 0x65,
+	0x6c, 0x58, 0x9e, 0x9f, 0x8d, 0x7b, 0xd7, 0x09, 0x77, 0xd1, 0xda, 0x8e,
+	0x3d, 0x50, 0x9e, 0x28, 0x57, 0x1c, 0x17, 0x44, 0x2c, 0xc2, 0x79, 0x8f,
+	0x18, 0xdd, 0x86, 0x79, 0x8b, 0x11, 0xca, 0x2f, 0xf7, 0x16, 0xf2, 0x64,
+	0x96, 0x71, 0x15, 0xdf, 0xd9, 0xd8, 0xa4, 0x4c, 0xdd, 0x59, 0x24, 0x14,
+	0x07, 0xba, 0x74, 0x06, 0xfe, 0x3c, 0xbe, 0x5c, 0xfa, 0xdf, 0x51, 0x50,
+	0x8f, 0xc2, 0x56, 0x16, 0x60, 0x2b, 0x0b, 0xb0, 0x91, 0x90, 0x85, 0x6b,
+	0x05, 0xd8, 0xc8, 0x02, 0x6c, 0x24, 0xf4, 0xd9, 0x9b, 0x88, 0xed, 0xde,
+	0x00, 0x0f, 0x19, 0x5f, 0xfb, 0x30, 0x7d, 0x6d, 0xfc, 0xfd, 0x17, 0xea,
+	0x52, 0x61, 0x78, 0xd0, 0x71, 0x00, 0x00, 0x00 };
 
 static const u32 bnx2_RXP_b06FwData[(0x0/4) + 1] = { 0x0 };
 static const u32 bnx2_RXP_b06FwRodata[(0x24/4) + 1] = {
-	0x08004590, 0x08004590, 0x08004508, 0x08004540, 0x08004574, 0x08004598,
-	0x08004598, 0x08004598, 0x08004478, 0x00000000 };
+	0x0800458c, 0x0800458c, 0x08004504, 0x0800453c, 0x08004570, 0x08004594,
+	0x08004594, 0x08004594, 0x08004474, 0x00000000 };
 
 static struct fw_info bnx2_rxp_fw_06 = {
-	/* Firmware version: 4.1.1 */
+	/* Firmware version: 4.4.2 */
 	.ver_major			= 0x4,
-	.ver_minor			= 0x1,
-	.ver_fix			= 0x1,
+	.ver_minor			= 0x4,
+	.ver_fix			= 0x2,
 
 	.start_addr			= 0x080031d0,
 
 	.text_addr			= 0x08000000,
-	.text_len			= 0x71d0,
+	.text_len			= 0x71cc,
 	.text_index			= 0x0,
 	.gz_text			= bnx2_RXP_b06FwText,
 	.gz_text_len			= sizeof(bnx2_RXP_b06FwText),
@@ -2973,7 +2974,7 @@
 	.bss_len			= 0x44c,
 	.bss_index			= 0x0,
 
-	.rodata_addr			= 0x080071d0,
+	.rodata_addr			= 0x080071cc,
 	.rodata_len			= 0x24,
 	.rodata_index			= 0x0,
 	.rodata				= bnx2_RXP_b06FwRodata,
@@ -2996,687 +2997,639 @@
 };
 
 static u8 bnx2_rv2p_proc1[] = {
-	/* Date:        12/07/2007 15:02 */
-	0xd5, 0x56, 0x41, 0x6b, 0x13, 0x51, 0x10, 0x9e, 0xdd, 0x6c, 0xbb, 0xdb,
-	0x64, 0xb3, 0x59, 0xaa, 0xd6, 0x50, 0x53, 0x93, 0x06, 0x2f, 0xad, 0x29,
-	0x6d, 0xaa, 0x82, 0x42, 0xa1, 0x92, 0x4b, 0xc1, 0xf6, 0x20, 0xf5, 0x22,
-	0x22, 0xd8, 0x46, 0xd1, 0x5f, 0x21, 0x06, 0xdb, 0xd4, 0x73, 0x05, 0x0b,
-	0xf5, 0xa0, 0x3d, 0x59, 0x11, 0xc1, 0x04, 0x14, 0x44, 0x04, 0x41, 0x45,
-	0x04, 0x3d, 0x78, 0xa8, 0x60, 0x2f, 0xad, 0x22, 0x56, 0x3c, 0x78, 0xd4,
-	0x93, 0x26, 0xbe, 0x37, 0x33, 0xaf, 0xdd, 0xdd, 0x66, 0x9b, 0x2a, 0x82,
-	0x18, 0x68, 0x3f, 0xde, 0xec, 0xbc, 0x37, 0x33, 0xdf, 0xcc, 0x9b, 0x79,
-	0x2e, 0x00, 0xe8, 0x50, 0xaa, 0xa6, 0x05, 0x82, 0xa5, 0x69, 0x96, 0x00,
-	0x0d, 0xe0, 0xae, 0x8d, 0x58, 0xea, 0x77, 0x05, 0xda, 0xda, 0x70, 0x46,
-	0x62, 0x04, 0x86, 0xbb, 0x25, 0xee, 0x87, 0x27, 0x99, 0xa4, 0xc0, 0x9f,
-	0x75, 0x28, 0xc9, 0xf5, 0xee, 0xca, 0xc3, 0x6a, 0x0c, 0xcf, 0x59, 0xed,
-	0x07, 0xfc, 0xbd, 0x8b, 0x10, 0x1e, 0xce, 0x59, 0x88, 0x25, 0x46, 0xe8,
-	0x73, 0x11, 0x96, 0x66, 0x2d, 0x34, 0x57, 0xea, 0xb3, 0x70, 0x1f, 0xe8,
-	0x24, 0x5f, 0x99, 0x4d, 0x88, 0xff, 0x29, 0x78, 0x5f, 0x90, 0x6b, 0x2b,
-	0x3a, 0x8d, 0x7a, 0x15, 0xde, 0x2f, 0xfe, 0x50, 0xff, 0xb8, 0xd8, 0x07,
-	0xfc, 0x53, 0xfb, 0x5c, 0x3c, 0xa7, 0x98, 0x93, 0x7e, 0xb5, 0x0b, 0x83,
-	0xca, 0x1f, 0x9b, 0xe2, 0x4b, 0x93, 0xb6, 0x89, 0xdf, 0xd7, 0x84, 0xdf,
-	0xca, 0x6e, 0x33, 0x7b, 0x41, 0x7f, 0x83, 0x76, 0xe5, 0x79, 0x86, 0xb0,
-	0xe7, 0xb7, 0x03, 0x20, 0xe5, 0xcb, 0xf5, 0x75, 0x79, 0x8f, 0xff, 0xfb,
-	0x6a, 0xaf, 0x3c, 0xaf, 0x05, 0xa0, 0x57, 0xea, 0x2d, 0xb1, 0x3f, 0x83,
-	0xb0, 0x4f, 0x4f, 0xe2, 0x77, 0x03, 0xf7, 0xef, 0x11, 0xe7, 0x4a, 0xec,
-	0x62, 0xec, 0x66, 0x1c, 0x67, 0xbc, 0xca, 0xb8, 0x8b, 0x71, 0x27, 0xe3,
-	0x0e, 0xc6, 0x76, 0xc6, 0x97, 0x8c, 0x2e, 0x63, 0x82, 0xd1, 0x61, 0x7c,
-	0xce, 0x68, 0x33, 0xc6, 0x18, 0x5f, 0x30, 0xbe, 0x62, 0xb4, 0x18, 0x6f,
-	0x30, 0x7e, 0x61, 0xfc, 0xaa, 0xfc, 0xd0, 0x08, 0x1f, 0xf1, 0xfa, 0x10,
-	0xaf, 0x8f, 0x30, 0x02, 0xf3, 0xa4, 0x05, 0x78, 0xba, 0xcf, 0x75, 0x24,
-	0x79, 0xe6, 0xef, 0x3d, 0x4a, 0x8f, 0xf3, 0x84, 0x3c, 0xdd, 0x63, 0xbd,
-	0xf6, 0xca, 0x42, 0xa0, 0xde, 0x32, 0x5b, 0xd6, 0x59, 0xaa, 0x41, 0xde,
-	0x12, 0x18, 0xcf, 0xc4, 0x48, 0x02, 0xed, 0x38, 0xad, 0x24, 0x57, 0x6e,
-	0x9d, 0x4c, 0x10, 0x9e, 0x8b, 0x12, 0x7e, 0x62, 0x3c, 0x1f, 0x23, 0x9c,
-	0x8c, 0x2b, 0x9e, 0xd5, 0x39, 0xca, 0x9f, 0x66, 0x7e, 0x84, 0xd9, 0x53,
-	0x7e, 0x35, 0xb3, 0x4b, 0x58, 0xd4, 0xfd, 0xf1, 0x5f, 0x1f, 0x20, 0x34,
-	0xf2, 0x44, 0xea, 0x9c, 0xdd, 0x26, 0xa0, 0x5e, 0x9f, 0xb7, 0x0d, 0xb9,
-	0x3e, 0x38, 0xff, 0x1a, 0xef, 0xc7, 0xe0, 0x5c, 0x95, 0xfd, 0x4b, 0x28,
-	0x9e, 0xe9, 0xde, 0x64, 0x81, 0xd6, 0xe3, 0xc8, 0xbb, 0xa8, 0xb0, 0x1e,
-	0xee, 0x03, 0x59, 0x7f, 0xbe, 0xa8, 0x6e, 0x23, 0x9c, 0x8f, 0x8b, 0x9c,
-	0x8f, 0xae, 0x90, 0x7c, 0x84, 0xdd, 0xa3, 0xcd, 0xf7, 0xf7, 0x4c, 0x26,
-	0xc8, 0x5b, 0xd8, 0x7d, 0x53, 0x7c, 0x93, 0xf4, 0x77, 0x79, 0xbc, 0xc0,
-	0x3c, 0x16, 0x89, 0xc7, 0xe4, 0xe7, 0x86, 0x3c, 0x65, 0x3c, 0x3c, 0xc9,
-	0x38, 0xf7, 0x86, 0xe4, 0x39, 0x2c, 0xbe, 0xdc, 0x1f, 0xe7, 0x39, 0xe0,
-	0x1f, 0x9c, 0xc5, 0xfe, 0xe4, 0x42, 0x71, 0x44, 0xf9, 0xeb, 0xe7, 0xb9,
-	0x93, 0xf2, 0x0d, 0xd3, 0x79, 0x29, 0xaf, 0x03, 0x3c, 0xd5, 0x71, 0x6d,
-	0x14, 0x34, 0x09, 0x56, 0x31, 0x4f, 0xfb, 0x1d, 0x5d, 0xe7, 0xf5, 0x76,
-	0xeb, 0x42, 0xe5, 0x5d, 0x62, 0x2b, 0x14, 0x26, 0x39, 0xce, 0x2c, 0xd9,
-	0xa3, 0x3a, 0x30, 0xb8, 0x0e, 0x86, 0xb8, 0x7f, 0x05, 0xf9, 0xb0, 0x2a,
-	0x0b, 0xb3, 0xde, 0x7b, 0x9d, 0x84, 0x62, 0x9e, 0xea, 0x6a, 0x73, 0x5e,
-	0xd5, 0xdc, 0x51, 0x7d, 0x09, 0xc5, 0x95, 0x52, 0xc4, 0x17, 0xef, 0x51,
-	0xc8, 0x79, 0x79, 0xd6, 0x1a, 0xd4, 0x47, 0x33, 0x3b, 0xbe, 0xf3, 0x1c,
-	0xc8, 0x35, 0xea, 0x37, 0x26, 0xc7, 0xd5, 0xcd, 0xf5, 0xdd, 0xb1, 0xa9,
-	0xbe, 0xd5, 0x7c, 0xfb, 0x7b, 0x75, 0xce, 0xf1, 0x9b, 0xa8, 0x97, 0x5a,
-	0x79, 0xe0, 0x9d, 0x67, 0x51, 0xcf, 0x3c, 0xa3, 0x6d, 0xa6, 0xf2, 0x3b,
-	0xed, 0x9d, 0x43, 0xb1, 0x90, 0x3c, 0x78, 0xe7, 0x57, 0x30, 0x5e, 0x7f,
-	0x3d, 0x52, 0x5e, 0xa3, 0x1c, 0xbf, 0xd6, 0xa4, 0x2f, 0xb7, 0xb1, 0xde,
-	0x8f, 0x5a, 0xb8, 0x1e, 0x9d, 0x5b, 0xe8, 0xf1, 0xf6, 0xf1, 0xef, 0x35,
-	0x9a, 0x07, 0xdf, 0x6a, 0x8a, 0xdf, 0xc7, 0x21, 0xfc, 0x0e, 0xfd, 0x53,
-	0x7e, 0x21, 0xc0, 0xef, 0x6a, 0x6d, 0x7b, 0xfc, 0x02, 0xc7, 0x0f, 0x21,
-	0xfc, 0xb6, 0x32, 0x0f, 0x6f, 0xb7, 0xe0, 0x4d, 0xea, 0xc5, 0x58, 0xef,
-	0x8d, 0x47, 0x0f, 0xfd, 0x1e, 0xa2, 0x7b, 0x65, 0x16, 0xd7, 0x02, 0xbc,
-	0xe5, 0x73, 0xf2, 0x7e, 0x5f, 0x82, 0x2a, 0xc7, 0xbf, 0xec, 0xe3, 0x21,
-	0x2e, 0xfc, 0x73, 0xd1, 0xfe, 0xed, 0xaa, 0xe2, 0x8b, 0x3e, 0x67, 0x72,
-	0x84, 0x8b, 0xa8, 0xef, 0x7a, 0x78, 0xf3, 0xbe, 0xaf, 0x5c, 0xb8, 0x55,
-	0x55, 0xfd, 0x4c, 0xf6, 0x15, 0x13, 0x06, 0x78, 0x4e, 0x4e, 0x70, 0xff,
-	0xfa, 0x10, 0xa5, 0x3e, 0x59, 0x1c, 0xc5, 0x3e, 0x03, 0x1d, 0xeb, 0xfd,
-	0x8c, 0xd6, 0x9d, 0x71, 0x7a, 0x47, 0x0e, 0x98, 0x36, 0xea, 0x75, 0xc6,
-	0x09, 0x3b, 0x62, 0x72, 0x5f, 0x12, 0x3e, 0x8e, 0xa1, 0x7a, 0x6e, 0xa3,
-	0x3f, 0x05, 0xfb, 0x12, 0xc7, 0x79, 0x40, 0xca, 0x3b, 0x02, 0xfd, 0x48,
-	0xe8, 0xf4, 0x92, 0x7f, 0x37, 0x81, 0xe3, 0x52, 0xfb, 0xd2, 0x92, 0xc7,
-	0xc5, 0x9a, 0xea, 0xe3, 0xd9, 0x11, 0xe9, 0x4f, 0x02, 0x1c, 0x93, 0xf2,
-	0x48, 0x28, 0xf4, 0x74, 0x53, 0x6e, 0x4b, 0x95, 0x75, 0x5a, 0x97, 0x2f,
-	0xe3, 0x31, 0x63, 0x65, 0x25, 0x2f, 0x60, 0x61, 0x8e, 0xdf, 0x79, 0x86,
-	0x72, 0xa7, 0x1a, 0x21, 0xb9, 0x39, 0xaa, 0xf8, 0x48, 0x60, 0x7c, 0x73,
-	0xc4, 0xc7, 0xe9, 0x6b, 0x84, 0xa7, 0xe0, 0x18, 0x62, 0x74, 0x63, 0x2e,
-	0x5b, 0x88, 0x10, 0xf7, 0xf6, 0xdf, 0x16, 0xe1, 0x1e, 0xf6, 0x4d, 0x4f,
-	0x7e, 0x82, 0x73, 0xb5, 0x59, 0x9e, 0xbc, 0x73, 0x5d, 0xe6, 0xa9, 0xd1,
-	0xfc, 0x8e, 0x73, 0x5d, 0x95, 0x9b, 0xd4, 0x9f, 0xea, 0x83, 0x25, 0xae,
-	0xfb, 0x46, 0xef, 0x1a, 0x89, 0x4e, 0xc8, 0xfc, 0x4f, 0xad, 0xfb, 0x95,
-	0x0e, 0x7d, 0x77, 0x91, 0xfe, 0xf6, 0xde, 0x5b, 0x6e, 0xc8, 0x1c, 0xfe,
-	0x1f, 0xde, 0x55, 0x5b, 0xbd, 0xa7, 0x1c, 0xe6, 0xf9, 0x04, 0xf3, 0x6c,
-	0x40, 0x4b, 0x04, 0x89, 0xb1, 0x8d, 0x29, 0x3c, 0x57, 0x2f, 0xd3, 0x58,
-	0xb7, 0x5b, 0x66, 0x70, 0xae, 0x3b, 0xf6, 0x0c, 0xe9, 0x19, 0x24, 0x4f,
-	0x2a, 0xbc, 0x32, 0x45, 0xef, 0x6c, 0x1d, 0x7e, 0x01, 0x50, 0xb6, 0x82,
-	0xa7, 0xd8, 0x0d, 0x00, 0x00, 0x00 };
+	/* Date:        05/13/2008 13:50 */
+	0xa5, 0x56, 0x4f, 0x48, 0x14, 0x61, 0x14, 0x7f, 0x3b, 0xfb, 0x67, 0xd6,
+	0xdd, 0xd9, 0x9d, 0x25, 0xff, 0x6d, 0x66, 0xb8, 0x49, 0x97, 0xd5, 0x15,
+	0xb5, 0x22, 0x3a, 0x18, 0x86, 0x17, 0x21, 0x3b, 0x84, 0x20, 0x45, 0x04,
+	0xd9, 0x12, 0xde, 0x82, 0x0e, 0xd1, 0x29, 0x68, 0xd1, 0x34, 0x8a, 0x0a,
+	0x16, 0x52, 0x30, 0xa2, 0xa4, 0x43, 0x85, 0x04, 0xed, 0x74, 0x0a, 0x12,
+	0x82, 0x8a, 0x88, 0xea, 0x12, 0x78, 0xa8, 0x4b, 0x16, 0x61, 0xd0, 0xa1,
+	0x83, 0x9d, 0xba, 0xe4, 0xf4, 0xbd, 0xef, 0xbd, 0xcf, 0x9d, 0xf9, 0x9c,
+	0x55, 0x21, 0x41, 0x7f, 0xbc, 0x6f, 0xde, 0x7b, 0xdf, 0x9b, 0xdf, 0x7b,
+	0xef, 0x37, 0x66, 0x00, 0xc0, 0x80, 0x92, 0xd3, 0x26, 0x10, 0x52, 0x46,
+	0x28, 0x2e, 0x20, 0x04, 0xf0, 0x18, 0xe8, 0x27, 0x6a, 0x49, 0xbb, 0xd4,
+	0xcd, 0x76, 0x27, 0x41, 0xa9, 0x33, 0x23, 0xfe, 0x9e, 0x85, 0xfe, 0x1c,
+	0x62, 0x18, 0xfa, 0x77, 0x21, 0x1e, 0x84, 0x17, 0xb9, 0xac, 0xc0, 0xbf,
+	0x2e, 0x94, 0xd0, 0x6e, 0xa8, 0x3c, 0x73, 0x92, 0x32, 0xff, 0x12, 0xc7,
+	0x7f, 0x0a, 0x13, 0x1e, 0x28, 0xc4, 0x29, 0x0f, 0x23, 0x74, 0x65, 0x24,
+	0x2c, 0x96, 0xd1, 0x1e, 0x19, 0x81, 0x18, 0xe6, 0x99, 0x12, 0x0e, 0x68,
+	0xb7, 0x86, 0x4a, 0x5d, 0x5c, 0x97, 0x41, 0x7e, 0x5f, 0xca, 0x36, 0x9e,
+	0xc3, 0xd7, 0x01, 0xb4, 0xb7, 0x27, 0x2e, 0x97, 0x11, 0xb3, 0x30, 0x16,
+	0xb7, 0xe8, 0x7d, 0xda, 0x28, 0xed, 0x52, 0x07, 0xc6, 0x09, 0xdf, 0x0e,
+	0xce, 0x1b, 0xc5, 0xbc, 0x3f, 0x5d, 0xca, 0x8b, 0xf9, 0xbc, 0x79, 0x5a,
+	0x45, 0x1e, 0x3c, 0x8f, 0x71, 0x5d, 0x31, 0xad, 0xae, 0x98, 0xa8, 0x83,
+	0x79, 0x00, 0x55, 0x07, 0x62, 0xa3, 0xb8, 0x17, 0xf3, 0xae, 0xf0, 0x7b,
+	0x03, 0x9c, 0xca, 0x71, 0x7e, 0x07, 0xb1, 0xc2, 0xf9, 0xc4, 0x2f, 0xbf,
+	0xc7, 0xfa, 0x3c, 0x8a, 0x27, 0x7f, 0xfd, 0x66, 0x41, 0x3d, 0x57, 0xfd,
+	0xc0, 0x7b, 0x3e, 0x8a, 0x7b, 0xbc, 0xfe, 0xb0, 0x89, 0xff, 0x7b, 0xe1,
+	0xef, 0xcf, 0x4b, 0xe7, 0x6f, 0xab, 0xe7, 0xf9, 0x20, 0xde, 0xa2, 0x1a,
+	0x6f, 0x2f, 0x99, 0xb7, 0x41, 0xd8, 0x6d, 0x64, 0xa5, 0x5f, 0x04, 0x10,
+	0x77, 0x88, 0x02, 0x10, 0x77, 0x32, 0x1e, 0x63, 0xbc, 0xc9, 0x78, 0x83,
+	0xb1, 0x91, 0xb1, 0x81, 0xb1, 0x9e, 0x71, 0x1b, 0xe3, 0x3b, 0xc6, 0x0c,
+	0xa3, 0xcd, 0x98, 0x66, 0x7c, 0xc3, 0x68, 0x31, 0x26, 0xb5, 0x7c, 0x2d,
+	0x8c, 0x71, 0xc6, 0xbb, 0x8c, 0xfb, 0xb5, 0xf8, 0xdf, 0x8c, 0x0b, 0x8c,
+	0xcd, 0x21, 0xc2, 0x43, 0x6c, 0x23, 0xa1, 0x3c, 0xf7, 0x3e, 0xbe, 0xee,
+	0xaf, 0xf5, 0x77, 0xb1, 0xcc, 0xcf, 0xf3, 0xca, 0x2f, 0x2e, 0xf9, 0x83,
+	0x0e, 0xaf, 0xff, 0x9d, 0x0d, 0xfc, 0xc9, 0x6d, 0x20, 0x1f, 0x14, 0x37,
+	0xed, 0x52, 0x1d, 0xb7, 0x38, 0xbe, 0xbe, 0xb2, 0x50, 0x63, 0x8f, 0xfa,
+	0x0a, 0xfa, 0x7c, 0x05, 0xed, 0xd1, 0x4e, 0xde, 0xa3, 0xa3, 0xeb, 0xe6,
+	0x97, 0xe6, 0xd4, 0xbb, 0x87, 0x32, 0x4f, 0x8d, 0x39, 0x7f, 0x1a, 0x2a,
+	0x16, 0xb2, 0x34, 0x17, 0xa5, 0x8d, 0xee, 0xc5, 0x78, 0x9e, 0xcb, 0xbc,
+	0x9a, 0x4f, 0xff, 0x5c, 0xd2, 0x7c, 0xc5, 0xb4, 0xf9, 0xba, 0xb0, 0x09,
+	0xbf, 0x49, 0x8d, 0xa7, 0x73, 0xae, 0xea, 0x97, 0xc1, 0xc7, 0xe3, 0xb1,
+	0x8c, 0xcc, 0x7b, 0xcd, 0x91, 0x66, 0x83, 0x35, 0x85, 0x76, 0x04, 0xae,
+	0x3b, 0x2a, 0x8e, 0xf7, 0xb2, 0x43, 0xdd, 0x43, 0xf1, 0x29, 0x20, 0x9e,
+	0xe7, 0x34, 0x9e, 0x73, 0x5b, 0xd2, 0xa9, 0x15, 0xb7, 0xaa, 0x53, 0xf4,
+	0xbc, 0x0d, 0xbc, 0x3a, 0x15, 0x87, 0xd1, 0x41, 0x5b, 0xde, 0x9b, 0x8e,
+	0x51, 0x9a, 0xe3, 0x36, 0xe1, 0x99, 0x04, 0xe1, 0x72, 0xa2, 0x4e, 0xfc,
+	0x75, 0xdd, 0xb1, 0x24, 0xd9, 0xa7, 0x53, 0x6a, 0x3f, 0x54, 0xbc, 0xaa,
+	0x6b, 0xa3, 0x7a, 0xf0, 0x7e, 0x75, 0x8f, 0xaa, 0x43, 0xdd, 0xe7, 0xe7,
+	0xbf, 0xf6, 0xbd, 0x84, 0x45, 0xc3, 0xcf, 0xc3, 0xed, 0x1e, 0xc2, 0x48,
+	0xaf, 0x84, 0xec, 0x8c, 0x45, 0x71, 0xb3, 0x56, 0x04, 0xed, 0x7d, 0xb3,
+	0x1f, 0x30, 0xbf, 0xb1, 0x67, 0xc6, 0xe1, 0xfa, 0x6c, 0xd5, 0x3f, 0x79,
+	0x0e, 0xed, 0x40, 0xf6, 0x30, 0xcf, 0xc3, 0xb0, 0x9c, 0x7b, 0xb1, 0xd7,
+	0x06, 0x62, 0x0b, 0x94, 0xa4, 0xae, 0x1b, 0x89, 0xd7, 0x32, 0x3e, 0xcc,
+	0xe7, 0xa2, 0x4f, 0xed, 0xfe, 0x7d, 0x59, 0xa2, 0xfe, 0xc7, 0xfd, 0x73,
+	0xd3, 0xed, 0x06, 0xcf, 0x63, 0xa2, 0x32, 0x57, 0x0e, 0xea, 0xd7, 0x73,
+	0xd6, 0xbd, 0x2c, 0x14, 0x7b, 0x6b, 0xe9, 0xb1, 0xfa, 0x0e, 0x2a, 0x3d,
+	0x92, 0xc7, 0x95, 0x52, 0xd8, 0xc7, 0xcb, 0x21, 0x28, 0x04, 0xe5, 0x7f,
+	0xa2, 0xbe, 0x2f, 0x01, 0x7b, 0xb4, 0xd9, 0xbd, 0xbe, 0xfc, 0x69, 0x28,
+	0x04, 0xed, 0x81, 0xa9, 0xed, 0x8d, 0xcd, 0x7b, 0xd3, 0xbc, 0x6e, 0x7e,
+	0x95, 0x4e, 0xe4, 0x36, 0xd4, 0x89, 0xff, 0xd5, 0x05, 0x03, 0x48, 0x17,
+	0x50, 0x8f, 0xfd, 0xf7, 0x9b, 0xaa, 0x7e, 0x6d, 0xff, 0xa9, 0xee, 0x3f,
+	0xab, 0x5b, 0xd3, 0x11, 0xef, 0xfb, 0x07, 0xe9, 0x48, 0x42, 0xd3, 0x85,
+	0x5f, 0xab, 0x55, 0x1d, 0xc1, 0xe7, 0xf3, 0xf3, 0xd4, 0x97, 0x8b, 0xee,
+	0x9a, 0xae, 0xfb, 0xf8, 0xac, 0x63, 0x3e, 0x85, 0x9f, 0x8c, 0x5f, 0xd6,
+	0xe2, 0x55, 0x5f, 0xcf, 0x33, 0xcf, 0x46, 0x1f, 0xcd, 0x95, 0x59, 0xfc,
+	0xa1, 0xf1, 0xdd, 0x5b, 0xc0, 0xbd, 0xb8, 0x04, 0x0e, 0xf3, 0xf6, 0xd9,
+	0xc7, 0x5f, 0x8a, 0xf5, 0xc1, 0x84, 0x47, 0x8e, 0xe2, 0x59, 0xf5, 0x87,
+	0xf0, 0xa1, 0xf4, 0xcf, 0x6c, 0xc2, 0x77, 0x06, 0x1e, 0x38, 0x6a, 0xbf,
+	0x6d, 0x99, 0xaf, 0x87, 0xf5, 0x64, 0x94, 0xf7, 0xfa, 0x5b, 0x82, 0x74,
+	0xa3, 0x38, 0x24, 0xf7, 0x14, 0x9a, 0x78, 0xbf, 0x8b, 0x29, 0xb2, 0x5b,
+	0x52, 0xf4, 0x7f, 0x5b, 0x8f, 0x69, 0x49, 0xbf, 0x96, 0x14, 0x61, 0x53,
+	0x12, 0xe3, 0xb2, 0xf0, 0xfd, 0x88, 0x74, 0x2f, 0x54, 0xf7, 0x5b, 0xdf,
+	0x6b, 0x7e, 0xdf, 0xbd, 0x78, 0xde, 0x24, 0xf6, 0xd4, 0xdb, 0x0f, 0x6b,
+	0x4d, 0x5f, 0xef, 0x71, 0xf5, 0x39, 0xdb, 0xcb, 0xb7, 0x9a, 0xdb, 0x67,
+	0x35, 0xfa, 0x34, 0xe8, 0x2a, 0xdd, 0x6b, 0x1f, 0xc4, 0x7a, 0x6d, 0x48,
+	0x9b, 0x34, 0x1f, 0x84, 0x22, 0x8f, 0x61, 0x62, 0x58, 0xeb, 0x24, 0xeb,
+	0xc4, 0xe4, 0xb8, 0x4c, 0x73, 0x64, 0x52, 0x9d, 0x0f, 0xc8, 0xc1, 0x1f,
+	0x9e, 0x7f, 0x25, 0xcf, 0xd3, 0x4e, 0x98, 0xce, 0xcd, 0x21, 0xc5, 0x97,
+	0x2d, 0xdf, 0x7f, 0x86, 0xf8, 0x3a, 0x39, 0x4d, 0x78, 0x02, 0x0e, 0x4b,
+	0x4c, 0x54, 0xf5, 0x2d, 0x2e, 0x11, 0x52, 0x5e, 0x7d, 0x8b, 0x8a, 0xf2,
+	0xd0, 0xae, 0xf3, 0xf4, 0x51, 0xff, 0x6e, 0x6c, 0xb5, 0x9f, 0x5e, 0x9d,
+	0xc4, 0x7e, 0xea, 0x7a, 0x27, 0xe7, 0x46, 0x9b, 0xcf, 0x72, 0x8d, 0xf9,
+	0xcc, 0xd5, 0x98, 0x6f, 0x5d, 0x2f, 0xae, 0xf2, 0xde, 0x45, 0x20, 0x1a,
+	0x96, 0x1f, 0x24, 0x2b, 0x32, 0x21, 0xfb, 0x6b, 0x4c, 0xd2, 0x87, 0xd4,
+	0x8a, 0x4e, 0x85, 0x24, 0x6f, 0xd6, 0x14, 0xf9, 0x45, 0xe8, 0x3c, 0xab,
+	0xf0, 0xca, 0x84, 0xfa, 0xee, 0xfe, 0x03, 0x65, 0x6c, 0x9a, 0x59, 0x40,
+	0x0c, 0x00, 0x00, 0x00 };
 
 static u8 bnx2_rv2p_proc2[] = {
-	/* Date:        12/07/2007 15:02 */
-	0xed, 0x59, 0x5d, 0x6c, 0x54, 0xc7, 0x15, 0x9e, 0xbd, 0xbb, 0x7b, 0xf7,
-	0x7a, 0x7d, 0xf7, 0xae, 0x71, 0xa8, 0xff, 0xf9, 0xb3, 0x09, 0xd8, 0xa9,
-	0x21, 0xce, 0x9a, 0x98, 0x02, 0x55, 0x63, 0x39, 0x95, 0x81, 0xa6, 0x55,
-	0x0c, 0x49, 0x9b, 0xbe, 0x35, 0x76, 0x02, 0xb6, 0xa9, 0x4d, 0x2d, 0x43,
-	0x83, 0x4a, 0x1b, 0x65, 0x85, 0xd7, 0xf6, 0xcb, 0x26, 0xea, 0x22, 0xc0,
-	0x24, 0xaa, 0xa8, 0x1b, 0xa4, 0x28, 0xea, 0xdb, 0x56, 0x6a, 0x6d, 0xda,
-	0x97, 0xfe, 0x10, 0xb7, 0x4a, 0xa4, 0x42, 0xa5, 0xf6, 0xa1, 0x52, 0x85,
-	0x44, 0xda, 0x62, 0x99, 0xc4, 0x20, 0x63, 0xba, 0x79, 0x21, 0x75, 0x67,
-	0xce, 0x77, 0xe6, 0xee, 0xbd, 0xeb, 0xb5, 0x21, 0x2d, 0x8f, 0xdd, 0x07,
-	0x1f, 0x66, 0xee, 0x99, 0x33, 0xe7, 0xe7, 0x9b, 0x33, 0x67, 0x0e, 0x65,
-	0x42, 0x08, 0x43, 0x24, 0xb3, 0x1b, 0x24, 0x15, 0x56, 0x20, 0x20, 0xf0,
-	0x7b, 0xac, 0x8c, 0xc8, 0x9f, 0xb3, 0x96, 0xfc, 0x1b, 0x16, 0xcf, 0x1b,
-	0x55, 0x34, 0x0e, 0x09, 0x45, 0x1d, 0x21, 0x92, 0x5e, 0x5a, 0xce, 0xf4,
-	0x67, 0x4c, 0x77, 0x1b, 0xa0, 0x3d, 0x4c, 0xeb, 0x98, 0x9e, 0x64, 0xba,
-	0x91, 0xe9, 0x56, 0xa6, 0x27, 0x98, 0x7e, 0x8f, 0xe9, 0x07, 0x4c, 0x77,
-	0xb2, 0x3c, 0xf9, 0x4b, 0xda, 0xf2, 0x4f, 0x40, 0x24, 0x9b, 0xb4, 0x7e,
-	0x36, 0xa6, 0x9b, 0xa0, 0xe7, 0x73, 0x1b, 0x15, 0xdf, 0xcd, 0xa5, 0x3c,
-	0x1f, 0xe6, 0xaf, 0x65, 0x40, 0x37, 0x60, 0xd5, 0x4f, 0x93, 0x8f, 0xeb,
-	0xf5, 0x20, 0xdd, 0x31, 0xd0, 0x9e, 0x20, 0x68, 0x7b, 0x33, 0x91, 0xf4,
-	0x4b, 0x06, 0xc6, 0x9d, 0x5b, 0x2c, 0xb2, 0x2f, 0x64, 0x28, 0x39, 0xeb,
-	0x2d, 0xf3, 0x12, 0xe6, 0xbf, 0x19, 0x07, 0x7d, 0x39, 0x0a, 0xfa, 0x4f,
-	0xa6, 0x87, 0x4b, 0x59, 0xbe, 0xcd, 0x6a, 0x97, 0x62, 0xfd, 0x8c, 0xad,
-	0x68, 0x50, 0x24, 0x79, 0x9d, 0x10, 0xd0, 0xeb, 0xc7, 0x02, 0xdf, 0xd7,
-	0x6c, 0xc5, 0xec, 0x0f, 0x0f, 0x63, 0x5c, 0x7b, 0xb1, 0x8c, 0xf8, 0xcf,
-	0x67, 0xb5, 0xfe, 0x16, 0x79, 0x3f, 0x19, 0x87, 0x1c, 0x51, 0x6f, 0xd1,
-	0x26, 0xc9, 0x66, 0x50, 0xb1, 0x4d, 0xcb, 0xc3, 0xef, 0xdc, 0xa3, 0xda,
-	0x3f, 0x18, 0xaf, 0x4d, 0x80, 0x9e, 0x65, 0x5a, 0xd1, 0x4a, 0x64, 0xfb,
-	0xdf, 0x9f, 0xb0, 0x48, 0x97, 0xe4, 0x36, 0xaf, 0x1f, 0x7f, 0x23, 0xfd,
-	0xc8, 0x82, 0x1a, 0x40, 0x6e, 0x3c, 0xaa, 0xf8, 0xa4, 0x71, 0xf5, 0x90,
-	0x7b, 0xb0, 0xbf, 0x98, 0xff, 0x7f, 0xf9, 0x19, 0xfc, 0xaf, 0xe4, 0xb5,
-	0xb3, 0xfe, 0x1b, 0xa5, 0xfe, 0x8a, 0xd6, 0x05, 0x92, 0xdb, 0xfc, 0xfe,
-	0xb9, 0x96, 0x89, 0xd3, 0xbf, 0x6f, 0x76, 0x94, 0x91, 0xfd, 0xcf, 0x62,
-	0xfe, 0x74, 0xe7, 0x14, 0xfc, 0xb4, 0x9f, 0xe2, 0x22, 0xa2, 0xa9, 0x9f,
-	0x63, 0x55, 0x77, 0x4c, 0x8d, 0x5f, 0xd8, 0x71, 0x23, 0x8b, 0xef, 0xe1,
-	0x11, 0x35, 0x36, 0xe4, 0x3a, 0xfc, 0xf6, 0x07, 0x09, 0xe0, 0x69, 0x73,
-	0x84, 0x86, 0xf6, 0x0c, 0x7d, 0xb7, 0xc5, 0x78, 0x16, 0xdf, 0x8f, 0x96,
-	0xaa, 0xf1, 0xb3, 0xcd, 0x73, 0x18, 0x37, 0xf7, 0x8f, 0xf1, 0x42, 0xa3,
-	0x44, 0xfe, 0x59, 0x5a, 0xba, 0x69, 0x40, 0x1e, 0x87, 0x37, 0x1a, 0x32,
-	0xe2, 0x64, 0xaf, 0xdd, 0x09, 0x3a, 0x4a, 0xdf, 0xef, 0x05, 0xd2, 0x64,
-	0x77, 0xa7, 0x13, 0x9a, 0x02, 0x23, 0xe3, 0xca, 0xc5, 0x8d, 0xc6, 0xdd,
-	0x83, 0xe2, 0x67, 0xcc, 0xc5, 0x0f, 0xfb, 0xbf, 0x69, 0x25, 0xfc, 0x80,
-	0x76, 0x6e, 0x01, 0x35, 0x1b, 0x14, 0x5f, 0xb8, 0x08, 0x8e, 0xfc, 0x7e,
-	0xe6, 0xf8, 0x14, 0xe2, 0x44, 0xe2, 0x03, 0x63, 0xc6, 0x8b, 0xc4, 0x95,
-	0xe2, 0xaf, 0x96, 0xfe, 0xd2, 0xf1, 0x57, 0x82, 0x22, 0xe2, 0xdb, 0x2c,
-	0xaf, 0x9f, 0xed, 0x1a, 0x60, 0x7b, 0xe6, 0xa3, 0xda, 0xaf, 0xda, 0x1e,
-	0xd0, 0x71, 0x9f, 0x3d, 0x01, 0x89, 0x27, 0x8d, 0x23, 0x9f, 0x3e, 0xe9,
-	0xf7, 0xea, 0xf1, 0x8f, 0x5a, 0xc6, 0xa1, 0x6b, 0xe7, 0x16, 0xc5, 0x67,
-	0x26, 0x26, 0xb2, 0x7e, 0x1c, 0x6e, 0x10, 0x5a, 0x8e, 0x96, 0xaf, 0x70,
-	0x99, 0x93, 0xb8, 0x44, 0xdc, 0xce, 0x67, 0xbd, 0xe7, 0xa8, 0xa6, 0xc8,
-	0x39, 0xf2, 0x9f, 0x07, 0xed, 0x97, 0xa3, 0x31, 0x4a, 0x10, 0x3b, 0xae,
-	0xcc, 0xfa, 0xf7, 0x03, 0xbe, 0x23, 0x2e, 0x7e, 0xd6, 0xb6, 0xb1, 0xff,
-	0x98, 0x56, 0xec, 0x54, 0xf2, 0xba, 0x58, 0x7e, 0x0b, 0xcb, 0xb7, 0x0b,
-	0xce, 0xdb, 0x73, 0xee, 0x79, 0xd3, 0x71, 0xcb, 0x9f, 0x3b, 0xed, 0x3f,
-	0xda, 0xbf, 0xf9, 0xca, 0xac, 0x5a, 0x5f, 0x7b, 0x9f, 0x73, 0xb8, 0xbf,
-	0xc8, 0x39, 0x84, 0x9c, 0xbf, 0x3c, 0xee, 0xb7, 0x6b, 0x88, 0xf3, 0x5c,
-	0x0f, 0xe2, 0x66, 0xbd, 0xf4, 0x2b, 0xfe, 0xf0, 0x18, 0xe1, 0x5d, 0xbc,
-	0x18, 0x41, 0x7c, 0x1d, 0xd2, 0x5f, 0xb0, 0x1d, 0x2f, 0x7b, 0xce, 0x6b,
-	0x09, 0xf9, 0xb5, 0xc3, 0xc4, 0x7e, 0x1d, 0xdd, 0x58, 0xde, 0xce, 0x78,
-	0xc8, 0xf1, 0x79, 0x99, 0xb5, 0x49, 0xff, 0xe8, 0x9d, 0x53, 0x98, 0x1f,
-	0xdd, 0x43, 0x24, 0x7d, 0xd5, 0xd0, 0xf6, 0x86, 0xd4, 0xdf, 0xc9, 0x41,
-	0x7c, 0x9f, 0x0c, 0xf1, 0xf9, 0x7c, 0xaf, 0x9e, 0xd6, 0x5b, 0xf3, 0x19,
-	0xac, 0xcf, 0xb1, 0x7e, 0x27, 0x82, 0xc4, 0x1f, 0x1d, 0x63, 0xbe, 0xf1,
-	0x11, 0xbf, 0x9d, 0x3f, 0x40, 0x3e, 0xb7, 0xbf, 0x3f, 0x42, 0xe7, 0xdd,
-	0x31, 0x5d, 0x3e, 0xa2, 0xce, 0xe8, 0x29, 0xc5, 0x5f, 0x29, 0xc6, 0xb2,
-	0x4a, 0xd1, 0x2a, 0xd1, 0xbd, 0x17, 0xeb, 0xde, 0x30, 0x91, 0x6f, 0x7a,
-	0xf7, 0x82, 0x7e, 0x88, 0xf9, 0xf5, 0xce, 0xb8, 0xe2, 0x5f, 0x53, 0xe3,
-	0x4c, 0x29, 0x1a, 0x97, 0xf6, 0x28, 0xfb, 0xa5, 0xed, 0x8c, 0xcf, 0xc1,
-	0x46, 0xf0, 0xf7, 0x1d, 0xa2, 0x8d, 0xcf, 0x0c, 0xe4, 0x28, 0x5f, 0x4d,
-	0x0e, 0x5f, 0x52, 0x7e, 0xa9, 0x16, 0xb3, 0xc7, 0x14, 0x0d, 0x89, 0x8e,
-	0x4d, 0xec, 0x97, 0x3d, 0xfe, 0xfc, 0x3c, 0xbf, 0x53, 0x8d, 0x6b, 0x24,
-	0x9f, 0x17, 0xbf, 0x16, 0xc7, 0x39, 0xe4, 0xfa, 0xf5, 0x13, 0x03, 0x76,
-	0xa7, 0x48, 0xff, 0x3d, 0xd1, 0x14, 0x9d, 0xeb, 0x98, 0xe8, 0x25, 0x3c,
-	0x85, 0xac, 0xc1, 0x4b, 0xf8, 0x3e, 0xff, 0x0b, 0x2d, 0x57, 0xe1, 0x61,
-	0x17, 0xdf, 0x9f, 0xc2, 0x95, 0x13, 0xda, 0xc9, 0x71, 0xd0, 0xfb, 0xb6,
-	0xe2, 0xbe, 0xe9, 0x08, 0xa8, 0xf1, 0x3a, 0x39, 0xb6, 0x29, 0x6e, 0x1d,
-	0xdd, 0x6a, 0xbd, 0x4c, 0x02, 0x74, 0x7e, 0x1c, 0x29, 0x5f, 0xcd, 0x47,
-	0xa4, 0x1d, 0xfe, 0x7d, 0x06, 0x11, 0x0f, 0xfb, 0x28, 0xf9, 0xe7, 0xf3,
-	0xf6, 0xad, 0x8c, 0xb6, 0x07, 0xf3, 0xb7, 0x5d, 0x7d, 0x6c, 0xb2, 0xab,
-	0x63, 0x13, 0xf6, 0x9b, 0x75, 0x78, 0x9f, 0x4d, 0xbc, 0xef, 0x31, 0xb5,
-	0x5f, 0x83, 0x47, 0x5f, 0xc5, 0x67, 0x45, 0x6f, 0x91, 0xdc, 0x75, 0xd6,
-	0x77, 0x2e, 0x91, 0x7f, 0xad, 0xa3, 0x53, 0xd8, 0xff, 0xf6, 0xd4, 0x6a,
-	0x7a, 0xd7, 0xb0, 0x9c, 0x75, 0xec, 0xd7, 0xd8, 0x43, 0x8c, 0xdb, 0xea,
-	0x71, 0xca, 0xfb, 0x57, 0xfb, 0x87, 0xe4, 0xdb, 0x0b, 0xd3, 0xab, 0xe9,
-	0x2b, 0x6d, 0x4a, 0x82, 0x3f, 0x65, 0xd0, 0xc1, 0xa8, 0x82, 0x5f, 0xf2,
-	0x71, 0xd3, 0xfa, 0xce, 0x1f, 0xc2, 0x7d, 0x34, 0xe8, 0xe6, 0x0b, 0x25,
-	0xb7, 0x9d, 0xf1, 0x20, 0xe5, 0x05, 0xe0, 0x9f, 0x85, 0x69, 0x9c, 0x9b,
-	0x13, 0x74, 0x3e, 0xbe, 0x68, 0x87, 0x68, 0xff, 0xa8, 0x75, 0x83, 0xef,
-	0xa5, 0xfc, 0xfd, 0x03, 0x79, 0x7d, 0x36, 0x68, 0x2f, 0xe7, 0xe9, 0x1b,
-	0x4c, 0x53, 0xb6, 0x5a, 0x57, 0x2a, 0xf3, 0xad, 0x45, 0xf2, 0x91, 0x57,
-	0x4b, 0x5c, 0x7d, 0x8f, 0xb0, 0x9c, 0x8f, 0x98, 0x0a, 0x96, 0x33, 0xc0,
-	0xeb, 0xe7, 0x7c, 0x72, 0x0c, 0x8f, 0x1c, 0x7f, 0x3e, 0x1a, 0xe3, 0x7b,
-	0xef, 0xbc, 0xb9, 0x52, 0xbd, 0xa4, 0x68, 0xb9, 0x5c, 0x8f, 0x59, 0x7d,
-	0x2f, 0xa4, 0x1a, 0x89, 0xb4, 0x85, 0x0c, 0xb2, 0x77, 0x32, 0x35, 0x02,
-	0x3f, 0x8d, 0xb3, 0x9f, 0x22, 0xf0, 0x53, 0x4d, 0xfe, 0x9e, 0xe4, 0x8d,
-	0xf8, 0xfc, 0xcd, 0x6c, 0xf6, 0x9f, 0xc7, 0xf3, 0xa6, 0x8e, 0x2f, 0x91,
-	0x34, 0xf2, 0x90, 0xbe, 0x3f, 0xf5, 0xbd, 0x72, 0x4b, 0xe7, 0x6d, 0xb9,
-	0x6f, 0x81, 0x3e, 0x41, 0x8a, 0x73, 0x74, 0x9c, 0xf3, 0xd1, 0xd5, 0xa0,
-	0x8e, 0x27, 0xf4, 0x1b, 0xff, 0x8c, 0xfa, 0xe5, 0xef, 0xe5, 0xb0, 0x22,
-	0xcd, 0xb3, 0xc7, 0x88, 0xb6, 0xf4, 0x1d, 0xc7, 0x7c, 0x65, 0xab, 0xd2,
-	0xe7, 0x27, 0x01, 0x9c, 0xd3, 0xb0, 0x98, 0xc9, 0xe0, 0x9e, 0x13, 0x11,
-	0xd2, 0xa3, 0xee, 0x32, 0xe1, 0xc2, 0x8c, 0xa6, 0x32, 0x3e, 0x7f, 0x79,
-	0xec, 0x2e, 0x66, 0xef, 0x84, 0xc4, 0x93, 0xfa, 0x6e, 0xf2, 0x79, 0x95,
-	0x78, 0xb5, 0xf9, 0xbc, 0x3c, 0x4d, 0x7c, 0xf6, 0x22, 0xd9, 0xf9, 0x0d,
-	0x6b, 0x9c, 0xeb, 0xb4, 0x8f, 0x3b, 0xd5, 0xf8, 0x79, 0xfb, 0x75, 0x9c,
-	0x77, 0xfb, 0x75, 0xe4, 0x5b, 0x2b, 0x7c, 0x11, 0x79, 0xb8, 0xf3, 0xa2,
-	0x6f, 0xff, 0x74, 0xc8, 0xd0, 0xe7, 0xe7, 0x7f, 0xf2, 0x9b, 0xfd, 0x5d,
-	0xf6, 0xdb, 0xdd, 0xd5, 0xe3, 0x9a, 0x36, 0xf9, 0x1c, 0xf6, 0xdd, 0x2d,
-	0xb4, 0x57, 0xf9, 0xef, 0x43, 0xf7, 0x1e, 0x0e, 0xed, 0x62, 0x7d, 0x76,
-	0x71, 0x1e, 0xe0, 0xfa, 0x67, 0x7d, 0x50, 0xdf, 0x8b, 0x1a, 0x0f, 0x7c,
-	0x3f, 0x02, 0xa7, 0xd6, 0x28, 0xec, 0x15, 0xaf, 0xf2, 0x39, 0xf8, 0x37,
-	0xd3, 0xd7, 0x18, 0xff, 0x27, 0xb9, 0x3e, 0xd2, 0xf5, 0xdd, 0x3d, 0xcc,
-	0x3b, 0x13, 0x6e, 0x3d, 0xa4, 0xef, 0x1f, 0x35, 0x0e, 0x08, 0x27, 0x52,
-	0x4a, 0xfb, 0x25, 0x7f, 0x07, 0x80, 0x8d, 0x3f, 0x0d, 0x3f, 0xce, 0xb6,
-	0x82, 0xef, 0x0d, 0xf8, 0xc7, 0xd1, 0xfa, 0x2d, 0x36, 0xfa, 0xde, 0x01,
-	0x6d, 0xf0, 0xaf, 0xe9, 0xfa, 0x57, 0xe3, 0x73, 0x89, 0x69, 0xed, 0x66,
-	0xb6, 0xf3, 0xbf, 0xf3, 0xbb, 0xa7, 0x1e, 0x5b, 0xc9, 0xef, 0xb4, 0xbe,
-	0xad, 0xef, 0x2e, 0xe6, 0xcb, 0x76, 0x83, 0x66, 0x76, 0xd3, 0xfc, 0x66,
-	0xe4, 0xdb, 0x70, 0xdb, 0xe9, 0xfb, 0xd4, 0xa7, 0xfa, 0x5d, 0x53, 0xf9,
-	0x25, 0xd0, 0x33, 0x4c, 0x3f, 0xf7, 0x14, 0xe8, 0xb9, 0xa7, 0xfc, 0x79,
-	0xc4, 0x8c, 0xfb, 0xe2, 0xdb, 0x86, 0xf8, 0xbe, 0xe3, 0xc6, 0x77, 0x3d,
-	0xea, 0x03, 0x19, 0xaf, 0x55, 0xe3, 0xe9, 0xc6, 0xe9, 0x7e, 0xf1, 0x7c,
-	0xd8, 0x71, 0x4c, 0xed, 0xc2, 0x3d, 0x37, 0xcc, 0xef, 0xcd, 0x45, 0xf7,
-	0x9e, 0x2a, 0x16, 0xdf, 0xc8, 0xff, 0xe3, 0x4b, 0xf1, 0x3d, 0xb2, 0xa4,
-	0xf3, 0x1f, 0xee, 0x79, 0x5d, 0xd7, 0x0f, 0x79, 0xea, 0x7a, 0xff, 0xbe,
-	0xdf, 0xa2, 0x7a, 0x79, 0x34, 0xe0, 0xe2, 0x82, 0xf8, 0xa7, 0x79, 0x5d,
-	0x19, 0xaf, 0xdb, 0xb7, 0x6c, 0xdd, 0xb5, 0x8c, 0x5a, 0xf7, 0xb7, 0x4f,
-	0x97, 0xf7, 0x25, 0x7c, 0x7a, 0x26, 0x45, 0x1c, 0xf1, 0xc1, 0x7d, 0x61,
-	0x16, 0xe9, 0x63, 0xf8, 0x71, 0xb7, 0x37, 0x8e, 0x7c, 0xa8, 0xdf, 0x79,
-	0xfe, 0xba, 0xfe, 0x8f, 0x9f, 0xae, 0x5c, 0xd7, 0x6b, 0x79, 0x88, 0x5f,
-	0xb7, 0x11, 0x23, 0xbe, 0xeb, 0x43, 0x6a, 0x5d, 0xbf, 0x6b, 0x5f, 0x3b,
-	0xd9, 0x75, 0x99, 0xed, 0xab, 0x63, 0xfb, 0xe4, 0xe7, 0x6d, 0x74, 0x9f,
-	0x58, 0xd7, 0x87, 0xbc, 0xf6, 0xfd, 0x7a, 0x95, 0xfd, 0x1e, 0xf4, 0x1d,
-	0xc1, 0xfb, 0xc6, 0xf5, 0xfe, 0x4a, 0x5e, 0x2d, 0xd7, 0x63, 0x8e, 0xe0,
-	0xe7, 0x54, 0x91, 0xba, 0x46, 0xed, 0xff, 0x7b, 0xe9, 0x00, 0xbe, 0xc7,
-	0xe8, 0x1d, 0x11, 0xb4, 0x2e, 0x67, 0x8a, 0xf9, 0xe5, 0x6b, 0x01, 0xf0,
-	0x15, 0x8b, 0x9b, 0xfa, 0x1e, 0x66, 0x39, 0xc5, 0xec, 0x66, 0x3d, 0x5d,
-	0x3c, 0xf0, 0x3a, 0xe2, 0xeb, 0x63, 0xbe, 0x50, 0x91, 0xbe, 0x04, 0x46,
-	0xb9, 0xad, 0x54, 0x2f, 0x5e, 0x38, 0x39, 0xad, 0xf8, 0x62, 0xee, 0xbb,
-	0xcc, 0xaf, 0xdf, 0xc4, 0x43, 0xf0, 0x23, 0xbd, 0x3f, 0x44, 0xaf, 0xb3,
-	0x92, 0xbf, 0xf0, 0x7e, 0x5a, 0x98, 0xd6, 0xfe, 0xb6, 0xc9, 0x4e, 0xd4,
-	0xd3, 0x17, 0x0a, 0xfc, 0x68, 0x78, 0xfc, 0x08, 0xfe, 0x95, 0x71, 0xef,
-	0x7f, 0x97, 0x03, 0x17, 0xaf, 0x16, 0xc1, 0x3d, 0xf5, 0xf7, 0x1e, 0xd8,
-	0xce, 0x03, 0xad, 0x5e, 0xbb, 0x1a, 0xc4, 0x4c, 0x16, 0xf8, 0xef, 0x62,
-	0x9c, 0xbc, 0xc8, 0x79, 0xf6, 0x7a, 0x54, 0x4d, 0x58, 0xa2, 0xe7, 0x19,
-	0xe4, 0xe9, 0x8a, 0x52, 0xd8, 0xdd, 0xf3, 0x55, 0xed, 0x27, 0xcc, 0xd7,
-	0xc4, 0x50, 0x57, 0x77, 0x45, 0xf0, 0xbe, 0xa8, 0x89, 0x81, 0x56, 0x70,
-	0x9e, 0x9e, 0x71, 0xfb, 0x29, 0xa0, 0xf9, 0xfa, 0x12, 0x7d, 0xa5, 0xdf,
-	0x9a, 0xa8, 0xc3, 0x45, 0x13, 0xd7, 0xcf, 0x94, 0xef, 0x82, 0xe2, 0x60,
-	0x13, 0x70, 0x22, 0xea, 0xfd, 0x79, 0x8a, 0xf3, 0xec, 0xb2, 0x7a, 0x0d,
-	0x7d, 0x99, 0x12, 0x4f, 0x5f, 0x42, 0xef, 0xa7, 0xfd, 0xa8, 0xe5, 0xd2,
-	0x70, 0x85, 0xba, 0x72, 0x91, 0xf3, 0xd8, 0x23, 0xe2, 0x0f, 0x59, 0xd8,
-	0x35, 0x93, 0x2d, 0xc4, 0x95, 0xde, 0x4f, 0xcb, 0x83, 0xde, 0xda, 0x8e,
-	0xbc, 0x7c, 0xec, 0x7f, 0x88, 0xf5, 0xfc, 0x07, 0xf5, 0x33, 0x2b, 0xd8,
-	0x1e, 0x25, 0x17, 0xf3, 0xfb, 0xb8, 0x4f, 0x94, 0x74, 0xc7, 0xfe, 0xfe,
-	0x4e, 0x17, 0xe9, 0xb5, 0x86, 0x71, 0x54, 0xe1, 0xc1, 0x39, 0xf8, 0xd7,
-	0xb6, 0x80, 0x9e, 0x6d, 0xd1, 0x71, 0xd0, 0xf1, 0xd2, 0xf1, 0x41, 0x1c,
-	0x2b, 0xd0, 0x4f, 0xda, 0xd1, 0xf3, 0x04, 0xdd, 0x0f, 0x2d, 0x3d, 0x0b,
-	0xfa, 0xdc, 0x61, 0xfd, 0x81, 0x66, 0xc5, 0xff, 0x9a, 0xf8, 0x13, 0xf7,
-	0x1b, 0xfe, 0xca, 0xb4, 0xb0, 0x6f, 0x82, 0xbe, 0x8b, 0x8c, 0x5b, 0x98,
-	0x03, 0xd2, 0xaa, 0xf3, 0xac, 0xf7, 0x9d, 0xa0, 0xcf, 0xdf, 0xd6, 0x65,
-	0x78, 0xcd, 0xe7, 0x4b, 0x6d, 0x9f, 0xe2, 0x6f, 0x66, 0x1c, 0xca, 0xf7,
-	0xe9, 0x5e, 0xa5, 0x47, 0x5c, 0xde, 0xdb, 0xc8, 0xc7, 0x4e, 0xc4, 0x1b,
-	0x27, 0x89, 0x87, 0x92, 0x88, 0x1a, 0xd6, 0x95, 0x97, 0x90, 0x1d, 0xa7,
-	0xdf, 0xff, 0x80, 0x3e, 0xbf, 0x3d, 0x51, 0x8a, 0xf9, 0xca, 0x67, 0xe2,
-	0xe4, 0x87, 0x73, 0xc0, 0xf1, 0x8f, 0xce, 0x82, 0xbe, 0x25, 0xbe, 0x82,
-	0xf5, 0xe5, 0xa7, 0xe8, 0xfe, 0xb7, 0x2a, 0x19, 0x97, 0x55, 0x38, 0xf7,
-	0x69, 0xd4, 0x0f, 0x4b, 0x4b, 0x22, 0x86, 0xba, 0x4d, 0xdf, 0x03, 0xc0,
-	0x65, 0xc8, 0x13, 0xdf, 0xfb, 0xe1, 0x54, 0x51, 0xbb, 0xf0, 0x9d, 0x64,
-	0x15, 0xe2, 0x55, 0xfb, 0xa3, 0xca, 0x28, 0x8a, 0xcf, 0x36, 0x3f, 0x3e,
-	0x4d, 0xc6, 0xe7, 0x5d, 0xb7, 0x8e, 0x5a, 0x2e, 0x97, 0xde, 0x89, 0x12,
-	0xb7, 0x0f, 0x0b, 0xaf, 0xa0, 0xfb, 0x1a, 0xd4, 0xfe, 0x95, 0xcb, 0xf2,
-	0xeb, 0x06, 0x5f, 0x9c, 0x6f, 0xde, 0xd3, 0x7a, 0x9d, 0x32, 0xbd, 0xdf,
-	0x5b, 0xdc, 0x7b, 0x66, 0x98, 0xfb, 0xfc, 0x39, 0xf4, 0xa3, 0x12, 0xf3,
-	0x69, 0x1a, 0xda, 0xd5, 0xef, 0x52, 0xdf, 0x22, 0x31, 0xcc, 0xf9, 0xf3,
-	0xfd, 0xa0, 0xae, 0xb7, 0x30, 0xbe, 0xc2, 0x79, 0xe3, 0x0e, 0xeb, 0x75,
-	0x80, 0x61, 0x39, 0xdf, 0x48, 0x79, 0x37, 0xa1, 0xeb, 0xb4, 0x61, 0x7e,
-	0x5f, 0xe8, 0x3e, 0xd5, 0x97, 0x83, 0x9c, 0x4f, 0xc9, 0x8f, 0xa1, 0xc4,
-	0xed, 0x29, 0xdd, 0x4f, 0xd0, 0xfd, 0x05, 0xd6, 0x07, 0xfd, 0x30, 0x71,
-	0x30, 0x02, 0x2a, 0x9a, 0xfc, 0xf1, 0x11, 0xae, 0x9d, 0x18, 0x99, 0x05,
-	0xfd, 0x86, 0x08, 0xf7, 0x09, 0x27, 0x58, 0xbf, 0x33, 0xfc, 0xbe, 0x73,
-	0xc8, 0x4f, 0x65, 0xd2, 0x7e, 0xea, 0x5b, 0x25, 0x8e, 0x4d, 0xc3, 0xae,
-	0x01, 0xf7, 0xfd, 0x06, 0x3e, 0xa6, 0xce, 0x9b, 0xdc, 0x2f, 0xe3, 0xbe,
-	0x9a, 0x63, 0x8e, 0xc0, 0x9e, 0x81, 0x1c, 0xc6, 0x8b, 0x78, 0x17, 0x39,
-	0xff, 0xe2, 0x3a, 0xef, 0xf8, 0x49, 0xfd, 0x1e, 0x2c, 0xbe, 0x4e, 0xd7,
-	0x85, 0x83, 0xf4, 0x2e, 0x79, 0x61, 0x92, 0xfb, 0xea, 0xa2, 0x9f, 0xea,
-	0xd1, 0xaf, 0xdb, 0x39, 0x1e, 0xe7, 0xfb, 0x07, 0xfe, 0xbe, 0x81, 0xae,
-	0xbf, 0xe7, 0xd0, 0xff, 0x9c, 0xcc, 0xa5, 0x81, 0x97, 0x64, 0x89, 0x17,
-	0xe7, 0x25, 0x89, 0x4a, 0x8e, 0xdb, 0xda, 0x27, 0x41, 0xcf, 0x3e, 0x89,
-	0x77, 0xf2, 0xc0, 0x2b, 0xec, 0x97, 0x1d, 0x14, 0xa7, 0xed, 0xe8, 0xbf,
-	0x78, 0xeb, 0x50, 0x85, 0x9b, 0x4f, 0x5c, 0x3c, 0xcf, 0x91, 0x5e, 0xb5,
-	0x93, 0x39, 0xe2, 0xab, 0x11, 0x8f, 0xd0, 0xbd, 0x57, 0xed, 0x2c, 0x40,
-	0xcf, 0xc4, 0x04, 0xdb, 0x37, 0xf4, 0x05, 0xd0, 0x57, 0x38, 0xce, 0x3a,
-	0x7e, 0x57, 0xdd, 0x3e, 0x1e, 0xf4, 0xd5, 0xf7, 0xf1, 0xf2, 0xf7, 0x3b,
-	0xc6, 0xd5, 0xad, 0x48, 0x60, 0x7d, 0xc7, 0x8b, 0xf7, 0xa7, 0xfc, 0x78,
-	0x50, 0x78, 0xd1, 0xb8, 0xf4, 0xe2, 0xa8, 0xf0, 0x9c, 0xe5, 0x71, 0xe1,
-	0x34, 0x55, 0x91, 0xbf, 0x70, 0x9f, 0x98, 0x89, 0x89, 0xcc, 0xea, 0x7e,
-	0x7a, 0x13, 0x7e, 0x4a, 0xb0, 0xde, 0x76, 0xff, 0x08, 0xee, 0xa1, 0x31,
-	0x8e, 0xd3, 0x5c, 0x23, 0xd7, 0x11, 0xac, 0xdf, 0xc7, 0xfc, 0xce, 0x40,
-	0x3c, 0x23, 0xf6, 0xe1, 0x69, 0x8e, 0x1f, 0xe3, 0xea, 0x08, 0xdb, 0xfd,
-	0x11, 0xec, 0xb6, 0xb5, 0xdd, 0xfd, 0xae, 0xdd, 0xba, 0x4e, 0xf1, 0xca,
-	0x29, 0x97, 0xb8, 0xa0, 0x7a, 0xc7, 0xbe, 0x4a, 0x79, 0x24, 0xcc, 0x76,
-	0x4a, 0xbe, 0x56, 0xfd, 0xff, 0x8e, 0xf0, 0x57, 0xef, 0x76, 0xef, 0xba,
-	0x52, 0x5e, 0x17, 0x95, 0xeb, 0x30, 0x8f, 0xf3, 0x67, 0xaf, 0xe0, 0x4f,
-	0xe5, 0x37, 0x2d, 0xb7, 0xf0, 0x7c, 0x79, 0xfd, 0x47, 0x95, 0x1d, 0xfd,
-	0x90, 0x57, 0x64, 0x9c, 0xe8, 0x1e, 0xb2, 0xdd, 0xbc, 0x72, 0x87, 0xea,
-	0xc0, 0xe8, 0x85, 0x41, 0xe4, 0x81, 0x0b, 0x83, 0xef, 0x72, 0x1d, 0xce,
-	0x7e, 0xe9, 0xa2, 0xff, 0xaf, 0x92, 0xb1, 0xab, 0xf7, 0xe7, 0x15, 0xbf,
-	0x1e, 0xb5, 0x1e, 0x3d, 0xf4, 0xbe, 0xff, 0x01, 0xfe, 0xf0, 0x11, 0xdc,
-	0xa0, 0x1d, 0x00, 0x00, 0x00 };
+	/* Date:        05/13/2008 13:50 */
+	0xad, 0x58, 0x4d, 0x6c, 0x54, 0x55, 0x14, 0xbe, 0x7d, 0xf3, 0xdb, 0x99,
+	0x37, 0x3f, 0xb4, 0xb5, 0xbf, 0x68, 0xa1, 0x95, 0xd2, 0x92, 0x29, 0x94,
+	0x69, 0x01, 0x95, 0x44, 0x49, 0x31, 0x05, 0x94, 0x84, 0x52, 0x5d, 0x10,
+	0x37, 0xd0, 0x22, 0xa5, 0x83, 0x2d, 0x69, 0x28, 0x61, 0xc1, 0xc6, 0x09,
+	0xc5, 0xe2, 0x62, 0x12, 0x2d, 0xb1, 0x14, 0x8c, 0xc1, 0x46, 0x37, 0xc4,
+	0xb8, 0x19, 0x83, 0x52, 0xd4, 0xc4, 0x84, 0x60, 0x43, 0x70, 0x01, 0x26,
+	0x9a, 0xe0, 0x42, 0x13, 0xa2, 0x50, 0x0b, 0x36, 0x58, 0x7e, 0x46, 0x17,
+	0xca, 0x78, 0xef, 0xf9, 0xce, 0x7d, 0x7d, 0x6f, 0x3a, 0xb5, 0x2c, 0xe8,
+	0xe6, 0xeb, 0xbd, 0xef, 0xdc, 0x73, 0xcf, 0xcf, 0x77, 0xcf, 0x39, 0x6d,
+	0x54, 0x08, 0xe1, 0x16, 0xc9, 0x74, 0xb5, 0x44, 0x11, 0x32, 0x0a, 0xfc,
+	0x12, 0xb2, 0x42, 0x78, 0xca, 0xd5, 0x5a, 0x18, 0x82, 0x7f, 0x56, 0x44,
+	0x09, 0x7e, 0x48, 0xab, 0xef, 0x3e, 0xf1, 0xaa, 0x81, 0xef, 0x6e, 0xa1,
+	0x30, 0x22, 0x44, 0x52, 0x61, 0x94, 0x71, 0x3d, 0x63, 0x86, 0x31, 0x58,
+	0x00, 0x6c, 0x66, 0x7c, 0xc0, 0xfb, 0x77, 0x78, 0x7d, 0x93, 0xf1, 0x6f,
+	0xde, 0x37, 0x19, 0x6f, 0xf3, 0xfe, 0xf3, 0x06, 0x30, 0xc1, 0xfb, 0x3f,
+	0x4b, 0xd4, 0x76, 0xa9, 0xf5, 0x74, 0x56, 0x24, 0xe5, 0x19, 0x21, 0xc5,
+	0x1b, 0xf4, 0xbe, 0x49, 0x90, 0x6c, 0x80, 0xdd, 0xaf, 0x2c, 0x51, 0x72,
+	0xbf, 0xe7, 0x91, 0x53, 0xfb, 0x37, 0xb2, 0xd0, 0x3b, 0xeb, 0xaf, 0xe1,
+	0x51, 0xe7, 0x96, 0xb6, 0x9c, 0x18, 0xc6, 0xf9, 0x9d, 0x4b, 0xb0, 0xff,
+	0x54, 0x4c, 0xf9, 0xef, 0x15, 0x49, 0x46, 0xd1, 0xa8, 0xd0, 0x28, 0x48,
+	0x36, 0xea, 0x40, 0x41, 0xfe, 0x97, 0x61, 0xac, 0x3a, 0x43, 0xd0, 0x1b,
+	0x70, 0xe8, 0x2d, 0x9d, 0xa3, 0xf7, 0x5a, 0xa1, 0x5d, 0xff, 0x67, 0xac,
+	0x3f, 0xb0, 0xa0, 0xfe, 0xae, 0x10, 0xb0, 0x38, 0x96, 0xef, 0x9e, 0xc2,
+	0x05, 0xec, 0xdf, 0xb7, 0xa0, 0xfe, 0xc3, 0x96, 0xfd, 0x3a, 0x6e, 0xfa,
+	0x3b, 0xb0, 0x1a, 0x62, 0x9f, 0x24, 0x57, 0xe9, 0x78, 0x6a, 0xbf, 0xd9,
+	0x3e, 0x17, 0x70, 0x43, 0x8c, 0x20, 0xb5, 0x9b, 0x03, 0xdc, 0x56, 0xa7,
+	0xee, 0x2d, 0x12, 0x6e, 0x43, 0xe9, 0x59, 0xee, 0xf7, 0x9e, 0xc7, 0xfe,
+	0x8e, 0x08, 0xf0, 0x75, 0x76, 0xe4, 0x46, 0x40, 0x05, 0x26, 0x9b, 0xed,
+	0x0e, 0xb2, 0x7e, 0xa4, 0x55, 0x24, 0x83, 0x38, 0x3f, 0x61, 0x2a, 0xfb,
+	0x2e, 0xcb, 0xfc, 0xa9, 0xb5, 0x4b, 0x24, 0x23, 0x4e, 0x3f, 0x3e, 0x14,
+	0x90, 0x5b, 0xb4, 0x1c, 0xbb, 0xef, 0x76, 0x63, 0x5d, 0xf5, 0x71, 0x94,
+	0xe4, 0x4f, 0xa6, 0xb5, 0x1f, 0x6a, 0x5f, 0xbe, 0x83, 0x08, 0xf4, 0x88,
+	0x1a, 0x3f, 0x5d, 0x86, 0x38, 0xc9, 0x4b, 0x1b, 0xb5, 0x3e, 0xfc, 0x9c,
+	0x58, 0xa6, 0xf9, 0x85, 0x75, 0xb7, 0x97, 0xa0, 0xbc, 0x73, 0x48, 0xd9,
+	0x1b, 0x11, 0xbb, 0x0c, 0x65, 0x88, 0xc1, 0xfe, 0xb9, 0xfc, 0xe6, 0x17,
+	0x90, 0xff, 0xa6, 0xda, 0x24, 0xdb, 0xba, 0x9b, 0x71, 0xae, 0x24, 0x0e,
+	0x1c, 0x89, 0x7b, 0x14, 0xc4, 0xba, 0x07, 0x68, 0xb9, 0xf2, 0xd7, 0xd5,
+	0x7e, 0x92, 0x4b, 0x36, 0x6a, 0xfe, 0xea, 0xb8, 0x2b, 0x7f, 0xdf, 0xc9,
+	0x5a, 0xfc, 0xaf, 0x45, 0x7c, 0x6e, 0x2e, 0x53, 0xf2, 0x32, 0x48, 0x35,
+	0xb8, 0xa7, 0x23, 0x91, 0x8f, 0xff, 0x6f, 0xdb, 0xf8, 0xff, 0x68, 0x79,
+	0xdc, 0x40, 0xfe, 0x6f, 0xe0, 0x38, 0x2c, 0x61, 0xbe, 0x2c, 0xce, 0xc3,
+	0x97, 0x08, 0xfd, 0x7e, 0xab, 0x35, 0x4a, 0x71, 0xdc, 0x86, 0xfd, 0xe3,
+	0x6d, 0xe7, 0x10, 0xef, 0x2d, 0x14, 0x07, 0x11, 0x38, 0xfa, 0x39, 0x4e,
+	0x75, 0x86, 0xd4, 0xfa, 0xb5, 0x96, 0xee, 0x2f, 0xb1, 0xee, 0x72, 0xa9,
+	0xf5, 0x0e, 0x73, 0xf7, 0x38, 0xe4, 0x3d, 0x83, 0x51, 0x8a, 0xdf, 0x36,
+	0xbe, 0x65, 0x8b, 0xab, 0x40, 0x41, 0xca, 0x3b, 0x48, 0x4b, 0x73, 0x82,
+	0xbe, 0x47, 0xc5, 0xb1, 0x34, 0xbe, 0xef, 0x0f, 0x52, 0x7d, 0x90, 0xfe,
+	0x91, 0x5c, 0x49, 0xc2, 0x8b, 0xf3, 0xa9, 0x61, 0x3f, 0xf9, 0x3b, 0x75,
+	0x56, 0xad, 0xb7, 0xc6, 0xa6, 0x20, 0x1f, 0x4b, 0x0c, 0xb1, 0x62, 0x03,
+	0xf1, 0xbb, 0x65, 0x40, 0x9e, 0xe9, 0x15, 0x70, 0x53, 0xfe, 0x0a, 0x84,
+	0xd9, 0x06, 0x7c, 0x8b, 0xbe, 0xff, 0x53, 0x90, 0xa2, 0x78, 0x6d, 0x0c,
+	0xbb, 0xcf, 0xe9, 0xf8, 0x30, 0x46, 0xb4, 0x5f, 0xc0, 0x47, 0xe5, 0xef,
+	0x90, 0xa9, 0x79, 0xcb, 0x79, 0x6b, 0x98, 0x8f, 0xb7, 0xc0, 0xb6, 0x3a,
+	0xa0, 0xb7, 0x56, 0xc9, 0x79, 0xf2, 0xf0, 0xd7, 0x99, 0x17, 0xce, 0xab,
+	0x8d, 0x67, 0x04, 0x92, 0x5f, 0x0e, 0xbe, 0x49, 0x3e, 0x53, 0x5d, 0x92,
+	0xf1, 0xd4, 0xbc, 0x51, 0x8a, 0x7c, 0xe2, 0x0d, 0xd6, 0x97, 0x60, 0xbf,
+	0x7a, 0xd9, 0xaf, 0xe9, 0x80, 0x8e, 0xbb, 0xf6, 0x07, 0x78, 0xcc, 0x04,
+	0xbf, 0x3a, 0x12, 0xda, 0x2f, 0x27, 0x7f, 0xd9, 0x9e, 0xd4, 0xb7, 0x35,
+	0xf8, 0xa5, 0xaa, 0x16, 0x68, 0xf9, 0x59, 0x47, 0xef, 0x25, 0x5c, 0x36,
+	0xae, 0xed, 0x50, 0x79, 0xfd, 0x4b, 0xe6, 0x15, 0xf9, 0x39, 0x99, 0xb6,
+	0xbf, 0xd3, 0xca, 0x3c, 0xef, 0xd4, 0xf9, 0x6e, 0xb4, 0xff, 0xfb, 0x43,
+	0x54, 0x88, 0x5a, 0xae, 0x4c, 0x3a, 0xdf, 0x05, 0xf8, 0xef, 0xb3, 0x78,
+	0x54, 0xb2, 0x96, 0xe3, 0xc4, 0x58, 0xba, 0x4e, 0xe9, 0x6b, 0x67, 0xfd,
+	0x4d, 0xac, 0xdf, 0xb4, 0xbd, 0x4b, 0x65, 0xdf, 0x93, 0xd6, 0x7b, 0xd4,
+	0xf9, 0x99, 0x7d, 0x97, 0x3a, 0x4e, 0x74, 0x7f, 0xec, 0xca, 0xa4, 0x3a,
+	0x5f, 0xb5, 0xc0, 0x3b, 0x2d, 0xb6, 0xf4, 0xfd, 0x68, 0xbd, 0x47, 0xf5,
+	0x3d, 0x28, 0x5e, 0xe0, 0xa5, 0xb3, 0xde, 0xfc, 0x29, 0xeb, 0x0d, 0xf9,
+	0xe1, 0x37, 0xcf, 0x71, 0x7d, 0x19, 0x50, 0xf7, 0x94, 0xb3, 0xdd, 0xe5,
+	0xba, 0xce, 0x4b, 0xbb, 0xb9, 0x0e, 0xed, 0xb4, 0xd7, 0x13, 0x8f, 0xad,
+	0x2e, 0xa8, 0xb5, 0x2b, 0x4f, 0x9f, 0x74, 0xc4, 0x33, 0x29, 0x22, 0x98,
+	0x03, 0x92, 0x11, 0x25, 0x7f, 0x4f, 0xcc, 0xad, 0x2b, 0xb9, 0xf6, 0x23,
+	0x1e, 0x9d, 0x46, 0x88, 0xe4, 0xae, 0xf7, 0xab, 0x73, 0xd7, 0xac, 0x3e,
+	0x8e, 0x3a, 0x73, 0x91, 0xed, 0x5d, 0xcc, 0xf6, 0x4a, 0x7d, 0x8d, 0xc4,
+	0x53, 0xff, 0xf5, 0x7e, 0xbb, 0xbd, 0x77, 0x1e, 0xce, 0x7f, 0x9f, 0x33,
+	0xef, 0xfd, 0xdc, 0x6f, 0xb8, 0x4f, 0xfa, 0x77, 0x7f, 0xa5, 0xed, 0xe1,
+	0x7b, 0x23, 0xfa, 0x7e, 0x93, 0xf2, 0x32, 0x39, 0xa0, 0xce, 0x87, 0x05,
+	0xd3, 0x44, 0xf4, 0xd5, 0xa3, 0xae, 0x4d, 0xef, 0x81, 0xfd, 0x7d, 0x75,
+	0xea, 0xfe, 0x16, 0x81, 0x7e, 0xe3, 0x96, 0x21, 0x45, 0x7d, 0xbf, 0x38,
+	0x9c, 0x2f, 0x8f, 0x5f, 0xb3, 0xdc, 0x38, 0xfb, 0x15, 0x65, 0xbf, 0x36,
+	0x4b, 0xbf, 0x28, 0xee, 0xfc, 0x3d, 0x9f, 0xdf, 0x6c, 0xa7, 0xd0, 0xfd,
+	0x9b, 0xcf, 0x91, 0x5c, 0x0f, 0xcb, 0xb9, 0xe7, 0xed, 0xdb, 0x99, 0xe5,
+	0x54, 0x87, 0x4f, 0x1f, 0xa6, 0x7a, 0x1a, 0xb2, 0xf8, 0xe6, 0xb4, 0x6f,
+	0xe2, 0x31, 0xc4, 0x51, 0xc9, 0x2d, 0x12, 0x7b, 0xc3, 0xf3, 0xc5, 0xcb,
+	0xad, 0xb6, 0xc7, 0x66, 0xc6, 0x75, 0xbc, 0x4d, 0xf2, 0x73, 0x72, 0x80,
+	0xe6, 0xc2, 0x9c, 0x38, 0x1a, 0xb6, 0x38, 0x42, 0x1e, 0xf3, 0x4a, 0xbe,
+	0xf8, 0xe5, 0xeb, 0x8b, 0x9f, 0x3e, 0xd4, 0x7c, 0x3a, 0xe2, 0xd5, 0xf6,
+	0x2b, 0x5c, 0x65, 0xe5, 0xf3, 0x00, 0xcf, 0x23, 0x19, 0x93, 0x7e, 0x89,
+	0x4f, 0xa7, 0x68, 0x69, 0x56, 0x9c, 0x51, 0x72, 0x2b, 0xe2, 0x07, 0xd8,
+	0xce, 0xcb, 0x2e, 0xf8, 0xd1, 0xb3, 0x07, 0xeb, 0x2b, 0x5c, 0xdf, 0xee,
+	0x72, 0x9d, 0xda, 0xee, 0x07, 0x4e, 0xd7, 0x93, 0x7f, 0xf1, 0x03, 0xe7,
+	0xb5, 0x7e, 0xd2, 0x6b, 0x66, 0x38, 0x3e, 0x2f, 0xba, 0xd8, 0xee, 0x1a,
+	0xca, 0x47, 0xfc, 0x0e, 0xbd, 0x4f, 0xb7, 0x68, 0x5d, 0xaa, 0xb0, 0x42,
+	0xc6, 0x81, 0xed, 0x59, 0x0f, 0xec, 0xf0, 0x71, 0x5c, 0x1b, 0x72, 0xf3,
+	0x85, 0x6d, 0x6f, 0x0d, 0x9f, 0xef, 0xc4, 0xda, 0xc7, 0xf5, 0x65, 0x94,
+	0xed, 0x7a, 0xaf, 0x1e, 0x18, 0x6e, 0x40, 0x7f, 0x9c, 0x34, 0x15, 0x46,
+	0xe2, 0x03, 0xe3, 0xf0, 0xa7, 0x77, 0x23, 0xfc, 0xbd, 0xc7, 0x71, 0x60,
+	0x0c, 0x9f, 0x1a, 0xa4, 0xbe, 0x19, 0x1e, 0x42, 0x7f, 0x0d, 0x7b, 0x07,
+	0xe1, 0x47, 0x6f, 0x06, 0xeb, 0x7b, 0xcf, 0x02, 0x1f, 0x3c, 0x87, 0x73,
+	0x07, 0x0f, 0x73, 0x7c, 0x36, 0xe6, 0x3f, 0xd7, 0x73, 0x1f, 0x72, 0x7d,
+	0xf5, 0xd4, 0xe7, 0xc7, 0xb8, 0xef, 0x8a, 0x04, 0xf7, 0xf9, 0x0c, 0xaf,
+	0xf7, 0x71, 0x1f, 0xb9, 0xcd, 0x7d, 0xb2, 0x37, 0xa7, 0x4f, 0x4e, 0xa1,
+	0x6e, 0x8e, 0x65, 0x52, 0x6a, 0x43, 0xd6, 0xaf, 0x42, 0xdd, 0x1f, 0x15,
+	0x06, 0xe2, 0x65, 0x9c, 0xaf, 0x92, 0x35, 0xc0, 0x91, 0x35, 0xe8, 0x6b,
+	0xbd, 0x87, 0x38, 0x2e, 0x2d, 0x94, 0x9f, 0x95, 0x33, 0xe3, 0x9a, 0x0f,
+	0x34, 0x3f, 0x3d, 0xd4, 0xbc, 0x43, 0xfd, 0xca, 0x58, 0xf5, 0x76, 0x8a,
+	0xec, 0xab, 0x1a, 0xcb, 0x90, 0x7c, 0xa5, 0x28, 0x26, 0x7e, 0x55, 0x84,
+	0x67, 0x60, 0x6f, 0x7c, 0x94, 0xfd, 0xec, 0x7f, 0x06, 0x78, 0x88, 0xf3,
+	0xac, 0xf3, 0x77, 0x75, 0x9d, 0x49, 0xe7, 0x26, 0x07, 0x60, 0xb7, 0xe6,
+	0x7d, 0xee, 0x9c, 0xa7, 0xf3, 0x5e, 0xd1, 0x4c, 0x6b, 0xd1, 0x73, 0x50,
+	0xdd, 0x13, 0x92, 0xf9, 0x52, 0x76, 0xc9, 0x58, 0x70, 0x7f, 0x74, 0xf2,
+	0x41, 0xf1, 0x45, 0xf3, 0xd2, 0xce, 0x23, 0x3b, 0x4f, 0x9c, 0xfc, 0x08,
+	0x53, 0x3d, 0x97, 0x8f, 0x97, 0xfa, 0xa7, 0x37, 0x3e, 0x3a, 0xfc, 0xff,
+	0xf1, 0x3a, 0x85, 0x78, 0xc5, 0xd9, 0x6e, 0x33, 0x41, 0x73, 0xd6, 0x13,
+	0x62, 0x88, 0xf3, 0x35, 0x55, 0xcf, 0xef, 0xb5, 0x06, 0xf9, 0xea, 0x7f,
+	0x1a, 0xf6, 0xf4, 0xf3, 0x3b, 0xf9, 0x83, 0xfb, 0x39, 0xf2, 0xec, 0x33,
+	0xbb, 0xc7, 0x39, 0xaf, 0xcc, 0xb7, 0x7d, 0x1c, 0x87, 0xdb, 0x88, 0x83,
+	0xa9, 0xe3, 0x90, 0xb0, 0xe2, 0xa0, 0xeb, 0x83, 0x5d, 0x4f, 0x91, 0xe4,
+	0x0b, 0xd5, 0x19, 0xf3, 0x2a, 0xcd, 0x27, 0x1e, 0xf6, 0x5b, 0xca, 0x35,
+	0x2b, 0xff, 0xc2, 0xec, 0x5f, 0x48, 0xec, 0x5d, 0x69, 0x3f, 0x17, 0xe4,
+	0x73, 0x01, 0x79, 0x0e, 0xfb, 0x78, 0x8f, 0xe6, 0x3c, 0xf1, 0x55, 0x71,
+	0xd4, 0x7a, 0x73, 0xdf, 0x9d, 0x3d, 0x9e, 0x54, 0x51, 0xe9, 0x07, 0x75,
+	0x46, 0xe6, 0x8d, 0xea, 0x91, 0x69, 0xd5, 0x99, 0xbb, 0x54, 0x7f, 0x03,
+	0xa7, 0xfb, 0x50, 0x17, 0x4e, 0xf7, 0x9d, 0xe1, 0xfe, 0xc7, 0x71, 0x69,
+	0xa7, 0xb9, 0x58, 0xc6, 0xae, 0xc6, 0x59, 0x67, 0x9c, 0x76, 0x54, 0xd9,
+	0xec, 0xd0, 0xf7, 0xce, 0xd7, 0x97, 0x31, 0xaf, 0x6d, 0xa2, 0xbe, 0xec,
+	0xb7, 0xe6, 0x49, 0x67, 0xbd, 0xf7, 0x3f, 0x72, 0xbd, 0xdf, 0xde, 0x6c,
+	0xd7, 0x5f, 0x2b, 0x26, 0xd2, 0xd0, 0xdf, 0xce, 0xfd, 0x72, 0x17, 0xbf,
+	0xdb, 0xeb, 0x81, 0x08, 0xdd, 0xd7, 0xf5, 0x32, 0xf9, 0x27, 0x4a, 0x83,
+	0xf0, 0xa7, 0x6b, 0x2b, 0xbe, 0x77, 0x85, 0xb0, 0x5f, 0x19, 0xc2, 0xdf,
+	0x5b, 0xed, 0x3e, 0x93, 0xe4, 0x2b, 0x43, 0xc0, 0x52, 0x7e, 0xef, 0x13,
+	0xd6, 0x5c, 0x0c, 0x3c, 0xe9, 0xb5, 0xcf, 0x8f, 0x6e, 0x71, 0xc1, 0x8b,
+	0xf7, 0x2f, 0x1a, 0x30, 0x07, 0xb6, 0xd6, 0x99, 0xf4, 0xbd, 0xa3, 0x01,
+	0xfd, 0x12, 0xf5, 0x75, 0xf6, 0xef, 0x33, 0x9e, 0x2b, 0x2b, 0x67, 0xe7,
+	0x67, 0xfb, 0x7c, 0x5d, 0x18, 0x1f, 0xb5, 0xe6, 0x5c, 0x7d, 0x9f, 0xfd,
+	0xfd, 0x28, 0xbd, 0xb4, 0x94, 0x73, 0xaa, 0x7d, 0xbe, 0x76, 0xe9, 0x79,
+	0x87, 0xe7, 0xd1, 0x62, 0x71, 0x29, 0x0d, 0xbf, 0x26, 0xd2, 0xf9, 0xde,
+	0xa1, 0xba, 0x4f, 0xeb, 0x83, 0xdd, 0xda, 0x8f, 0x59, 0xfd, 0xb8, 0x7f,
+	0x0f, 0xdb, 0xf9, 0x1b, 0xfd, 0x5d, 0x5c, 0xca, 0xfe, 0x28, 0xbd, 0xd8,
+	0xdf, 0xcc, 0xf3, 0x7e, 0xd2, 0x5a, 0x3b, 0xe7, 0xf4, 0x76, 0xb2, 0xab,
+	0x88, 0xfb, 0x69, 0xa9, 0xad, 0xdf, 0x43, 0xbe, 0xa4, 0x09, 0x38, 0xd2,
+	0xa4, 0xf3, 0xa0, 0xf3, 0xa5, 0xf3, 0x83, 0x3c, 0x96, 0xae, 0x26, 0xb1,
+	0x96, 0xae, 0xd5, 0xf4, 0x60, 0x9b, 0xba, 0x66, 0x9c, 0xff, 0x3f, 0xd8,
+	0x1e, 0x53, 0xf2, 0x6f, 0x8a, 0xef, 0x63, 0x68, 0x80, 0x3f, 0x31, 0xce,
+	0xce, 0xc5, 0x9c, 0x00, 0x6b, 0x1e, 0xc1, 0x7d, 0x17, 0x3c, 0xbc, 0xdd,
+	0xac, 0xe7, 0x46, 0x67, 0xff, 0xfe, 0x90, 0xea, 0xf2, 0xd9, 0x7f, 0x73,
+	0xe7, 0xce, 0xd9, 0xf9, 0x51, 0xfb, 0xa9, 0xe4, 0x1b, 0x99, 0x8f, 0x7e,
+	0xd1, 0xba, 0x09, 0x7f, 0x6f, 0x87, 0x7d, 0xe0, 0x7d, 0xd8, 0x67, 0xcf,
+	0x97, 0xe4, 0x45, 0x21, 0x3d, 0xf0, 0xc5, 0x45, 0x85, 0xe4, 0xcf, 0xf1,
+	0xcb, 0xdf, 0xd1, 0xe7, 0x8f, 0x46, 0x83, 0xd8, 0x2f, 0x6b, 0x85, 0x7a,
+	0x37, 0xf1, 0xd6, 0x25, 0x8e, 0x82, 0xd7, 0x1f, 0x8c, 0x00, 0xdf, 0x17,
+	0x2f, 0x41, 0x4f, 0xd1, 0x11, 0xea, 0x73, 0xfe, 0x32, 0x84, 0x35, 0x35,
+	0xca, 0x7c, 0x2d, 0x37, 0xe8, 0xff, 0x65, 0x59, 0x11, 0xe2, 0xff, 0xab,
+	0xf0, 0xbb, 0x03, 0x4f, 0xdd, 0xb6, 0x7c, 0x2f, 0xc4, 0x5b, 0xaa, 0x1f,
+	0x92, 0x97, 0x38, 0xce, 0xfc, 0xf5, 0xe7, 0xf2, 0x57, 0xc7, 0xa5, 0xdc,
+	0xc8, 0xcb, 0xd7, 0xb5, 0x4e, 0xbe, 0x7a, 0x99, 0xaf, 0xf7, 0xad, 0xfe,
+	0x36, 0x57, 0x2f, 0xfe, 0xae, 0xb8, 0xf4, 0xd8, 0xf8, 0x0b, 0xdc, 0x5c,
+	0xab, 0xee, 0x2f, 0x9b, 0x33, 0x77, 0x56, 0x0b, 0x7b, 0x3d, 0x3a, 0x24,
+	0xf3, 0xfd, 0x1f, 0xfe, 0xac, 0x5e, 0x92, 0x80, 0x14, 0x00, 0x00, 0x00 };
 
 static u8 bnx2_TPAT_b06FwText[] = {
-	0xbd, 0x59, 0x6f, 0x70, 0x5c, 0xd5, 0x7d, 0x3d, 0x6f, 0xf7, 0xed, 0xee,
-	0x93, 0xb4, 0x92, 0x9e, 0x90, 0x0c, 0xab, 0x56, 0x8d, 0xf6, 0x59, 0x6f,
-	0xa5, 0xc5, 0xab, 0xd8, 0x6f, 0x2d, 0xb9, 0xac, 0x87, 0x37, 0xcd, 0xb3,
-	0x2c, 0x29, 0x8b, 0xec, 0xd8, 0xeb, 0x42, 0x66, 0xe4, 0x09, 0x1d, 0x0b,
-	0x59, 0xd8, 0xc2, 0x18, 0xa2, 0x12, 0x3e, 0xa8, 0x13, 0x4f, 0xbd, 0xe8,
-	0x9f, 0x85, 0xbd, 0xd2, 0x23, 0x02, 0x2c, 0x3b, 0x93, 0x0e, 0x1e, 0xf9,
-	0x8f, 0x18, 0x58, 0x6b, 0xa1, 0xfd, 0x92, 0x69, 0xc3, 0x44, 0x13, 0x1b,
-	0xec, 0x90, 0x38, 0x4e, 0xa7, 0x5f, 0xcc, 0xb4, 0x9d, 0xaa, 0x80, 0x29,
-	0x50, 0x70, 0xdc, 0xce, 0xa4, 0x63, 0x0a, 0xf5, 0xed, 0xb9, 0x6f, 0x57,
-	0x46, 0x38, 0x4e, 0x3f, 0xd6, 0x33, 0x8b, 0x76, 0xef, 0x7b, 0xf7, 0xde,
-	0xdf, 0xbd, 0xbf, 0x73, 0xce, 0xef, 0xdc, 0xcb, 0x6a, 0x1f, 0xca, 0x51,
-	0xfa, 0x57, 0xc9, 0x4f, 0xfb, 0x23, 0x43, 0x4f, 0x6f, 0x58, 0x6b, 0xad,
-	0x95, 0xbf, 0x95, 0x00, 0x54, 0xfc, 0x3f, 0xfe, 0xf3, 0x03, 0xfa, 0x72,
-	0x1c, 0xf2, 0x03, 0xcd, 0x67, 0x2f, 0xae, 0xee, 0x30, 0xa1, 0xf9, 0xed,
-	0x87, 0x5a, 0x76, 0x9b, 0x80, 0x93, 0x4f, 0x44, 0x37, 0xe3, 0x7f, 0x44,
-	0xb6, 0x4e, 0x85, 0x6c, 0xff, 0x23, 0xfb, 0x8b, 0x75, 0x6f, 0xdc, 0x67,
-	0x5c, 0x3f, 0xe1, 0x87, 0xa6, 0xdb, 0x93, 0x9a, 0xde, 0x0c, 0xad, 0x81,
-	0x7d, 0x7e, 0xd4, 0xb2, 0x2b, 0x88, 0xaa, 0xe5, 0xb1, 0x80, 0x93, 0x39,
-	0xc3, 0xda, 0x83, 0x84, 0x7e, 0x8e, 0x0b, 0x72, 0x38, 0xc7, 0x99, 0x3c,
-	0x70, 0x28, 0xa7, 0xe0, 0x2a, 0xc7, 0x1c, 0xcf, 0x6b, 0x58, 0xf2, 0x7b,
-	0xd3, 0xf5, 0x95, 0xd9, 0xc8, 0x98, 0x53, 0x07, 0x45, 0xc8, 0x44, 0xf6,
-	0x0f, 0x6c, 0x33, 0x7e, 0x08, 0xe1, 0xd4, 0x5c, 0x3b, 0x32, 0xab, 0xcf,
-	0x6a, 0xd8, 0xe9, 0x36, 0xf4, 0x69, 0x36, 0xf8, 0x8e, 0x82, 0xd4, 0x7d,
-	0x1a, 0x7a, 0x0b, 0x71, 0x64, 0x0b, 0x59, 0x38, 0x85, 0x31, 0x7e, 0x34,
-	0x84, 0xa6, 0x34, 0x6d, 0xdd, 0xd4, 0xdd, 0xf2, 0x1d, 0x84, 0xa7, 0xae,
-	0x8b, 0x6b, 0x49, 0x1d, 0x6f, 0x6f, 0x14, 0xa2, 0xd2, 0x46, 0xb6, 0xa2,
-	0x3d, 0x0b, 0xbf, 0x6d, 0x58, 0x5b, 0xfc, 0x0a, 0x3a, 0xbf, 0x6e, 0xc6,
-	0xa7, 0x94, 0x07, 0x1f, 0xf4, 0xd9, 0xd0, 0x14, 0x3b, 0xaa, 0x35, 0xe5,
-	0x1b, 0x30, 0x51, 0xd0, 0x71, 0xa8, 0x50, 0x87, 0xb1, 0x02, 0x0e, 0xf8,
-	0x37, 0x04, 0x31, 0xa7, 0xc3, 0xf9, 0x4e, 0xcb, 0x01, 0xec, 0xcb, 0x0d,
-	0x63, 0x77, 0x2e, 0x85, 0xc3, 0x05, 0x19, 0x63, 0x14, 0xa3, 0x05, 0x15,
-	0xc1, 0x29, 0x23, 0xf2, 0x73, 0xdc, 0xe9, 0x99, 0x10, 0x63, 0x56, 0x08,
-	0x23, 0x56, 0x1c, 0xe3, 0xae, 0x8f, 0xeb, 0x0c, 0x61, 0xd4, 0xbc, 0x21,
-	0x06, 0x2c, 0xc3, 0x1a, 0x87, 0x68, 0x3c, 0x6f, 0x19, 0x91, 0x4e, 0x3f,
-	0x9c, 0xef, 0x9b, 0x11, 0x8c, 0x33, 0xf6, 0x31, 0xaf, 0xdf, 0x18, 0x3a,
-	0x6f, 0xf5, 0x73, 0xd8, 0x4f, 0xc7, 0xc4, 0x57, 0xfb, 0x46, 0xc7, 0x91,
-	0x88, 0x4c, 0xc0, 0x87, 0xbe, 0xba, 0x56, 0xf6, 0x6b, 0x8a, 0x4e, 0xc0,
-	0x88, 0x73, 0x9c, 0x6c, 0xb0, 0xdd, 0xe1, 0x18, 0x59, 0xf6, 0x37, 0xa2,
-	0x67, 0x20, 0xc7, 0x6a, 0xe0, 0xef, 0x76, 0xf6, 0x57, 0xe0, 0xb3, 0x63,
-	0xd1, 0x11, 0xf6, 0x39, 0x67, 0xa9, 0x78, 0x93, 0x9f, 0x3e, 0xdd, 0x90,
-	0x99, 0x55, 0x42, 0x6c, 0x3f, 0x04, 0x3e, 0x37, 0x2b, 0x70, 0x22, 0x63,
-	0x61, 0x84, 0xeb, 0xd6, 0xd8, 0x36, 0xc9, 0xb6, 0x80, 0x69, 0x71, 0x7c,
-	0xe8, 0x9d, 0x85, 0x95, 0x98, 0x58, 0xce, 0xcd, 0xef, 0x6b, 0xe7, 0x18,
-	0x6e, 0x31, 0xa7, 0xf2, 0x9d, 0xcd, 0xee, 0x4d, 0xf1, 0x88, 0xba, 0xf2,
-	0xf9, 0xb0, 0xd2, 0xc1, 0x36, 0x47, 0x6d, 0xc0, 0x21, 0x17, 0x5a, 0xd0,
-	0xd4, 0x38, 0x8f, 0x86, 0xf7, 0x72, 0xc3, 0x4a, 0x77, 0xc1, 0x51, 0xba,
-	0xe6, 0x3b, 0x14, 0x67, 0x5e, 0x55, 0x3a, 0x67, 0x65, 0xdc, 0x42, 0x3c,
-	0x6b, 0x29, 0x8c, 0xf9, 0x07, 0x32, 0x5e, 0x27, 0xaa, 0xdc, 0x14, 0x6b,
-	0x62, 0x3e, 0x54, 0x98, 0xdd, 0xca, 0x96, 0x79, 0x21, 0xd2, 0xc9, 0xb4,
-	0xd2, 0x33, 0x0f, 0x2d, 0x6c, 0xdb, 0x5a, 0x6e, 0xea, 0x30, 0xb2, 0xab,
-	0x4c, 0x1c, 0x77, 0xa3, 0xb8, 0x64, 0xf9, 0x70, 0x62, 0x55, 0x19, 0x54,
-	0x53, 0xe1, 0x07, 0xe1, 0xcb, 0x16, 0xd4, 0x2a, 0x7e, 0xbf, 0xb6, 0x43,
-	0xc5, 0x58, 0x7b, 0x8f, 0xd2, 0xc9, 0x3e, 0x01, 0xe6, 0xf9, 0x74, 0x2e,
-	0x8d, 0x30, 0xb1, 0x53, 0x61, 0xc7, 0x22, 0x79, 0xee, 0xcd, 0xdb, 0x56,
-	0x2c, 0xfe, 0xb8, 0xc4, 0x63, 0x8d, 0x11, 0x91, 0x7b, 0x53, 0x69, 0xc7,
-	0xe2, 0x67, 0xb9, 0x0f, 0x7e, 0x53, 0xc5, 0xaf, 0xac, 0x00, 0x16, 0x77,
-	0x58, 0xcc, 0xa9, 0x8e, 0x20, 0xdb, 0xcf, 0x78, 0xed, 0xf2, 0x37, 0xf4,
-	0xae, 0xaf, 0xec, 0x43, 0x71, 0x0f, 0x46, 0xdd, 0x26, 0xc6, 0x5c, 0xdc,
-	0x83, 0xed, 0x5c, 0xef, 0xbf, 0x06, 0xe4, 0xd7, 0xaf, 0xdd, 0x6a, 0xdb,
-	0xc9, 0x38, 0x7d, 0xb6, 0xb9, 0xb8, 0xda, 0x5f, 0x0f, 0xd4, 0xb6, 0xe3,
-	0x30, 0x73, 0xdc, 0x99, 0xbc, 0x1b, 0x59, 0xef, 0x79, 0x9d, 0xbe, 0x65,
-	0xb6, 0x16, 0x7d, 0xab, 0xbc, 0x7d, 0xd3, 0xb7, 0xcd, 0x0a, 0xf1, 0x66,
-	0x32, 0x88, 0xb3, 0xe6, 0x48, 0xa4, 0x12, 0x59, 0xcb, 0xcf, 0x7c, 0x5f,
-	0xe0, 0xfc, 0xf9, 0xa4, 0x1f, 0x27, 0x93, 0x27, 0x90, 0xad, 0x01, 0xe6,
-	0x72, 0x92, 0x57, 0xc6, 0xe2, 0x05, 0xfe, 0xd7, 0x57, 0x90, 0xeb, 0xb3,
-	0xb8, 0x3e, 0x05, 0x67, 0x4c, 0x89, 0x69, 0x4b, 0x6b, 0x26, 0xbf, 0xf6,
-	0x71, 0x3f, 0xeb, 0xdb, 0xc3, 0xc4, 0x27, 0xf0, 0x6e, 0x6e, 0x00, 0x3b,
-	0x8b, 0xb1, 0xe0, 0x46, 0x8e, 0xc2, 0xd2, 0x96, 0xc6, 0x89, 0xe2, 0x6f,
-	0x72, 0x3c, 0xad, 0x75, 0xe4, 0x8c, 0x4c, 0x1a, 0x89, 0x8b, 0x1d, 0x8a,
-	0xec, 0x9f, 0xd6, 0xd6, 0xe4, 0x83, 0x88, 0xd6, 0x16, 0x9f, 0x57, 0xd8,
-	0x5b, 0xb5, 0xc7, 0xa7, 0x14, 0xec, 0x8d, 0xc9, 0x67, 0x5b, 0xb5, 0x96,
-	0x3c, 0xb4, 0x4a, 0x7b, 0x48, 0x3b, 0x3b, 0x65, 0xf4, 0xbd, 0xac, 0x24,
-	0xa2, 0x53, 0x5e, 0x9f, 0x21, 0xad, 0x35, 0x1f, 0xe2, 0x7a, 0xe2, 0xcc,
-	0x09, 0xb4, 0x2a, 0xfb, 0x69, 0xed, 0x57, 0x7c, 0x70, 0xd1, 0xeb, 0xf3,
-	0xb4, 0x16, 0xcf, 0xcb, 0x76, 0xc3, 0x8a, 0x2a, 0x21, 0xdc, 0x9b, 0xd4,
-	0xb0, 0xa6, 0x45, 0x34, 0x76, 0x25, 0x8d, 0xc5, 0x2e, 0x7f, 0x04, 0xc7,
-	0xc9, 0x05, 0xe2, 0xce, 0xf9, 0xc3, 0x96, 0x31, 0x74, 0x15, 0xfc, 0x88,
-	0xd6, 0x38, 0x38, 0xe2, 0x86, 0xf0, 0x33, 0xe2, 0xbf, 0xdb, 0xd2, 0x31,
-	0xe6, 0x1a, 0xf1, 0x5f, 0x20, 0x91, 0x3a, 0xc5, 0x9c, 0x2d, 0x91, 0x03,
-	0x47, 0x0a, 0x4d, 0xf1, 0x53, 0x30, 0x06, 0xbb, 0xc8, 0x01, 0xad, 0x5d,
-	0xc6, 0x00, 0x5d, 0xb5, 0xc9, 0x9d, 0x42, 0x03, 0x72, 0xe4, 0x43, 0x97,
-	0xc7, 0xab, 0x61, 0xa5, 0xb3, 0xf0, 0x4b, 0x6a, 0x6b, 0x37, 0xf1, 0x85,
-	0xea, 0x88, 0x19, 0x44, 0xaa, 0x36, 0x8a, 0xf3, 0xc4, 0x4a, 0xb6, 0xae,
-	0x8c, 0xb9, 0x94, 0xf9, 0x7c, 0x87, 0xcf, 0x7b, 0x94, 0xcd, 0xf3, 0x51,
-	0xfc, 0xcc, 0xfa, 0x42, 0x38, 0x75, 0x95, 0x6c, 0x0b, 0xac, 0x68, 0xd7,
-	0x70, 0xf5, 0x85, 0x72, 0x7c, 0xfc, 0x42, 0x18, 0x9f, 0xbd, 0x40, 0x7e,
-	0xbb, 0x68, 0x2f, 0x87, 0x10, 0xa9, 0x36, 0x21, 0x0a, 0x56, 0x2b, 0xde,
-	0xab, 0x89, 0x45, 0xaf, 0x40, 0x6a, 0xa3, 0xa3, 0xed, 0xce, 0x19, 0x43,
-	0x83, 0x48, 0x38, 0xe7, 0xbc, 0xbd, 0x70, 0xb4, 0xb5, 0xf9, 0xf3, 0x02,
-	0x3b, 0x8a, 0x7b, 0x11, 0xb4, 0x3b, 0xb5, 0xb7, 0x98, 0x9b, 0xcb, 0x5e,
-	0x6e, 0x3a, 0xb5, 0x75, 0xf9, 0xfb, 0xfd, 0x28, 0x2f, 0x3e, 0x53, 0xed,
-	0x8c, 0x36, 0x96, 0x33, 0x7a, 0x27, 0xb9, 0xbe, 0x01, 0xaf, 0x6f, 0x46,
-	0x4b, 0x70, 0xef, 0x97, 0x4a, 0xb9, 0xa9, 0xb4, 0x1f, 0xe2, 0x3e, 0x33,
-	0xf7, 0xde, 0x3e, 0x3e, 0xc4, 0x3d, 0x96, 0xf3, 0x0d, 0xdf, 0x36, 0xdf,
-	0x30, 0xe7, 0x7b, 0x79, 0xc5, 0x7c, 0x07, 0x56, 0xcc, 0x77, 0x60, 0xc5,
-	0x7c, 0x29, 0x72, 0xf5, 0x1f, 0xc4, 0x48, 0x5d, 0x71, 0x6c, 0xd5, 0x1e,
-	0xbc, 0x6d, 0xee, 0x41, 0xce, 0x7d, 0x54, 0x2c, 0x65, 0x8a, 0xe3, 0x54,
-	0xda, 0xfb, 0x57, 0xcc, 0xbd, 0x9f, 0x73, 0x2f, 0x8f, 0xa3, 0x53, 0x8b,
-	0x84, 0xd8, 0x66, 0x09, 0xa1, 0xda, 0xa6, 0xde, 0x89, 0xe6, 0x4c, 0x27,
-	0xb1, 0x53, 0x8e, 0xc4, 0xa2, 0x0f, 0xe6, 0x70, 0xbd, 0x3f, 0x80, 0xa5,
-	0x9a, 0x65, 0x6e, 0x54, 0x96, 0xfe, 0xbe, 0xa4, 0x80, 0x5a, 0xff, 0x6a,
-	0xae, 0x9a, 0x63, 0xc4, 0xf4, 0x01, 0x45, 0x88, 0x73, 0x1b, 0x13, 0x83,
-	0x7e, 0x24, 0xfa, 0xaa, 0x60, 0x12, 0x43, 0x81, 0x12, 0x17, 0x56, 0xf6,
-	0x79, 0xd9, 0xeb, 0x53, 0xf0, 0xfa, 0x08, 0xf1, 0xee, 0x86, 0x0f, 0xc5,
-	0x1b, 0x2d, 0x75, 0xf8, 0x29, 0x39, 0xf9, 0x5a, 0x61, 0x59, 0x57, 0xa4,
-	0x6e, 0xc0, 0x77, 0xce, 0x0a, 0x32, 0xa6, 0x91, 0x7d, 0xc1, 0xaf, 0xf4,
-	0x27, 0x60, 0x4c, 0xd9, 0xe6, 0xc7, 0x2b, 0x49, 0x3c, 0x52, 0x0e, 0xa3,
-	0xf7, 0xb0, 0x92, 0x4d, 0x57, 0xc0, 0x70, 0xd6, 0x28, 0xd9, 0x94, 0x06,
-	0xc9, 0x1b, 0xb5, 0xe9, 0xb4, 0x69, 0x64, 0xaf, 0xf2, 0x65, 0x75, 0xfa,
-	0x4e, 0x31, 0xa8, 0x1c, 0x23, 0x8c, 0x27, 0xdd, 0x0b, 0x58, 0x0c, 0x34,
-	0x50, 0x9f, 0xa5, 0x76, 0x72, 0xe0, 0x05, 0x8d, 0x35, 0x2d, 0x44, 0x22,
-	0xaa, 0x38, 0xe8, 0xfa, 0xce, 0x37, 0x42, 0x20, 0xd8, 0x16, 0xc0, 0x3b,
-	0xe6, 0xa8, 0x55, 0x8f, 0x4d, 0xb8, 0xdc, 0xca, 0x3d, 0x58, 0xa5, 0x22,
-	0x32, 0xb7, 0x72, 0xac, 0x08, 0xc7, 0xfa, 0xb3, 0x10, 0xaa, 0xea, 0xa0,
-	0x36, 0xab, 0xd8, 0xeb, 0x6a, 0x4a, 0x97, 0x2b, 0xb1, 0x6b, 0x46, 0x4e,
-	0xe1, 0x14, 0xb5, 0x82, 0x35, 0xec, 0x8c, 0xaa, 0x6c, 0x99, 0x0d, 0xa1,
-	0x7c, 0xe6, 0x13, 0xf1, 0x18, 0xb5, 0x2f, 0xbd, 0x41, 0x08, 0x33, 0x19,
-	0x82, 0xc6, 0x79, 0x86, 0xc9, 0xe7, 0xea, 0xb6, 0x5a, 0x5c, 0xfb, 0x3a,
-	0xb5, 0xe9, 0xdb, 0x21, 0xf8, 0x67, 0x42, 0x08, 0xce, 0x28, 0x78, 0xa7,
-	0x3d, 0x84, 0xfa, 0x39, 0xf9, 0x5b, 0x41, 0xa3, 0x79, 0x14, 0x07, 0x75,
-	0x3f, 0x63, 0xfc, 0x2b, 0xf4, 0xeb, 0x0d, 0x98, 0xa4, 0x36, 0x3f, 0xea,
-	0x6a, 0xa8, 0x3a, 0x4a, 0x2d, 0xb0, 0x85, 0x38, 0x49, 0xfc, 0x1f, 0x64,
-	0x8c, 0x32, 0xde, 0x0b, 0x56, 0x36, 0x1a, 0x42, 0x00, 0xc1, 0x39, 0x23,
-	0x3d, 0xc9, 0xe8, 0x52, 0x53, 0xaa, 0xb2, 0x7d, 0x96, 0xb5, 0xd7, 0x36,
-	0x7b, 0xeb, 0xfd, 0x42, 0x7c, 0x9a, 0x6c, 0xea, 0x5b, 0xa0, 0x06, 0x8f,
-	0xc4, 0x62, 0x99, 0x7e, 0x05, 0x58, 0x73, 0x96, 0x76, 0x64, 0xe6, 0xbf,
-	0x44, 0x98, 0xe3, 0x1c, 0xd9, 0x20, 0x30, 0x6e, 0x65, 0x23, 0x01, 0x18,
-	0x37, 0x86, 0x50, 0x87, 0x0f, 0x9e, 0x17, 0x42, 0xb4, 0x57, 0xe3, 0x1d,
-	0xcb, 0x18, 0x34, 0xfd, 0x02, 0x3f, 0x4e, 0x66, 0x87, 0x22, 0x30, 0x86,
-	0x7f, 0xad, 0x44, 0xf1, 0xf1, 0x94, 0x91, 0xbe, 0xa8, 0x04, 0x51, 0x39,
-	0x67, 0xea, 0x5b, 0x94, 0x30, 0xca, 0x17, 0xc2, 0x58, 0x7d, 0x36, 0x88,
-	0xc0, 0x4c, 0x18, 0xc1, 0x69, 0xf3, 0xe2, 0x2e, 0x78, 0xe3, 0x2c, 0x0e,
-	0xa1, 0x19, 0xd5, 0xb3, 0x66, 0xf4, 0x5f, 0x20, 0xb1, 0x1d, 0x86, 0xba,
-	0x10, 0x45, 0x7d, 0xc1, 0x44, 0x35, 0xf3, 0x7d, 0xf9, 0xac, 0xcc, 0xb3,
-	0x8e, 0xb0, 0xe9, 0xe3, 0xda, 0x1c, 0x65, 0xab, 0x57, 0x37, 0x3a, 0xf9,
-	0xe9, 0x56, 0x3a, 0xe6, 0xe5, 0x9e, 0x29, 0x28, 0xe3, 0xb3, 0x8b, 0xd6,
-	0x4d, 0xb1, 0x2f, 0x26, 0xeb, 0x44, 0x19, 0x02, 0x76, 0x8f, 0xf2, 0xc0,
-	0x3c, 0x8b, 0x90, 0xa7, 0xef, 0x65, 0x4a, 0xc0, 0x2e, 0x6a, 0xfb, 0x25,
-	0x6a, 0xfb, 0x89, 0x92, 0xb6, 0x57, 0x51, 0xdb, 0x17, 0xfe, 0x4f, 0x6d,
-	0x67, 0xbd, 0x9f, 0xf1, 0xe1, 0xbc, 0x19, 0xc2, 0x71, 0xab, 0x69, 0xb1,
-	0x1e, 0x21, 0x54, 0xb7, 0xe9, 0xa8, 0x5e, 0xb0, 0xf0, 0x1c, 0xf7, 0x16,
-	0x77, 0x15, 0xf5, 0xfd, 0x9b, 0x52, 0xf3, 0x4b, 0x5e, 0xed, 0x71, 0x77,
-	0x59, 0x13, 0xc2, 0xd4, 0x2a, 0x55, 0xe9, 0xa1, 0x9e, 0x3f, 0x90, 0xbc,
-	0x29, 0xe2, 0x31, 0x23, 0x4e, 0xce, 0xde, 0x38, 0x89, 0xa2, 0x46, 0xc4,
-	0xa8, 0x97, 0x4b, 0xb5, 0x71, 0x1c, 0x73, 0x65, 0x4d, 0xeb, 0x64, 0x4d,
-	0x53, 0x30, 0x12, 0x2b, 0x6a, 0xc4, 0xea, 0xbc, 0x6c, 0xd7, 0x51, 0x4f,
-	0x9d, 0x5c, 0xd7, 0x16, 0xc1, 0x31, 0x6a, 0xa4, 0x4b, 0x9f, 0xb3, 0x9d,
-	0xe3, 0x6d, 0x9b, 0x35, 0xb2, 0xdb, 0x99, 0x9f, 0xf3, 0xc4, 0xc5, 0x14,
-	0xab, 0xc3, 0x89, 0x1a, 0x6a, 0x67, 0x73, 0x08, 0x13, 0xd4, 0xcb, 0xf3,
-	0xf4, 0x10, 0x2f, 0xb1, 0xdf, 0xb8, 0x6b, 0x44, 0x5f, 0x22, 0xaf, 0xc7,
-	0x4b, 0x9a, 0xf9, 0x12, 0x7d, 0xc3, 0x38, 0xf3, 0xf4, 0x53, 0x3e, 0x7b,
-	0xcd, 0x35, 0x1c, 0xe9, 0x1f, 0xfc, 0x9e, 0x7f, 0x30, 0xe2, 0x7e, 0x45,
-	0x7a, 0x88, 0x08, 0xde, 0x68, 0x91, 0x58, 0x24, 0xc6, 0x6f, 0xe9, 0xa7,
-	0xaa, 0x7c, 0x6b, 0xf6, 0xba, 0xc8, 0xc7, 0xca, 0x55, 0xc9, 0xbf, 0xb1,
-	0xa4, 0xc4, 0x93, 0x10, 0x65, 0x76, 0x98, 0x5e, 0xcb, 0x8c, 0x7f, 0x84,
-	0x18, 0x71, 0x1b, 0xe1, 0xb3, 0x30, 0xfc, 0x67, 0xb7, 0xa8, 0x9e, 0x8f,
-	0x5d, 0x90, 0x7e, 0x8b, 0x79, 0x9a, 0x32, 0x7b, 0xa7, 0x94, 0x58, 0x66,
-	0x40, 0x91, 0xcf, 0x75, 0x94, 0x9f, 0x5d, 0x22, 0x77, 0x23, 0xe4, 0x6e,
-	0x1d, 0x5e, 0xbf, 0x8d, 0xbf, 0xd4, 0x55, 0xdf, 0x00, 0xf9, 0x9b, 0xad,
-	0x1b, 0xe9, 0xf7, 0x7f, 0x85, 0x7b, 0x87, 0x24, 0x7f, 0xd9, 0xe6, 0xc7,
-	0xb3, 0x49, 0xec, 0x2c, 0x83, 0x91, 0x79, 0x4c, 0xc9, 0x3a, 0xe4, 0x71,
-	0xaa, 0x4c, 0xc9, 0xd2, 0x31, 0x7d, 0xc9, 0xdf, 0x37, 0xf9, 0xb6, 0x9f,
-	0xfc, 0xed, 0xab, 0xbb, 0x9d, 0xbf, 0x47, 0x38, 0x86, 0x8a, 0x27, 0xdc,
-	0xe3, 0x98, 0x0b, 0x04, 0x11, 0x99, 0x09, 0x20, 0x34, 0xa3, 0xa2, 0x92,
-	0x5c, 0x09, 0xdb, 0xd9, 0x78, 0x08, 0x46, 0xfa, 0x35, 0x44, 0x90, 0x98,
-	0xd2, 0xf0, 0xe7, 0x2d, 0x01, 0x9c, 0x89, 0x19, 0x99, 0xfd, 0x4a, 0x84,
-	0x58, 0x1f, 0x61, 0x44, 0x46, 0x34, 0xea, 0x2b, 0xf2, 0x35, 0xd0, 0x1c,
-	0x84, 0x36, 0x23, 0xb9, 0x2e, 0x0e, 0xfa, 0xec, 0x6c, 0x54, 0x23, 0x46,
-	0x7f, 0x40, 0x6c, 0x5c, 0x99, 0x12, 0x62, 0x73, 0xbb, 0x79, 0xf1, 0x3d,
-	0xbf, 0x41, 0xdd, 0x53, 0x89, 0xd3, 0xe2, 0xf8, 0x15, 0x33, 0x1a, 0x82,
-	0x47, 0xbd, 0xf1, 0x6f, 0xbc, 0xce, 0x28, 0x3e, 0x75, 0x55, 0x65, 0x2b,
-	0x71, 0x40, 0x6e, 0x45, 0xe6, 0xa9, 0x7d, 0x87, 0x93, 0x46, 0x7a, 0x8b,
-	0xd2, 0xe4, 0x34, 0xf3, 0xbb, 0x2f, 0x19, 0x8b, 0xf6, 0xf3, 0x9d, 0xf7,
-	0x0b, 0x45, 0x0e, 0xd7, 0x9b, 0xbb, 0xf1, 0x17, 0xe4, 0x70, 0x95, 0xf9,
-	0x14, 0x9e, 0xf4, 0xf4, 0x88, 0x38, 0x98, 0x2e, 0x27, 0xb7, 0x1d, 0x65,
-	0x17, 0x71, 0xbf, 0x73, 0x9e, 0xba, 0x32, 0xd3, 0xee, 0x69, 0x51, 0xc8,
-	0xec, 0x54, 0x7a, 0xe7, 0xbb, 0x3d, 0x0f, 0xb5, 0x7d, 0xd6, 0x87, 0xd7,
-	0xad, 0x4d, 0xf4, 0x2b, 0x69, 0x65, 0xfb, 0xbc, 0xc4, 0x7c, 0x8f, 0xf2,
-	0x4d, 0xe2, 0x3f, 0x7a, 0x97, 0x8a, 0x39, 0x6b, 0x93, 0x12, 0xf4, 0xf0,
-	0x1f, 0x80, 0x93, 0x29, 0x62, 0xdf, 0x6f, 0xc7, 0xac, 0x73, 0x2b, 0xb0,
-	0xdf, 0x7d, 0x07, 0x5f, 0x23, 0xf5, 0x03, 0x45, 0x2d, 0xd7, 0x3b, 0x99,
-	0xaf, 0x67, 0x4a, 0x18, 0x7f, 0x92, 0xed, 0x81, 0x19, 0x68, 0xe5, 0xc4,
-	0x71, 0xcf, 0x54, 0x18, 0xd3, 0x1e, 0x56, 0x04, 0x5e, 0x65, 0x4d, 0xc8,
-	0x27, 0x0d, 0x6b, 0xbf, 0x62, 0xa4, 0xbb, 0x95, 0x44, 0x76, 0x4d, 0xa9,
-	0x1e, 0xde, 0xcb, 0x9a, 0x86, 0xbb, 0xa8, 0x0b, 0x16, 0xb4, 0x10, 0xf1,
-	0xfd, 0x6f, 0xac, 0x4f, 0xff, 0x51, 0xaa, 0x87, 0xc9, 0x7c, 0x39, 0xaa,
-	0x5b, 0xa8, 0xef, 0xc4, 0x73, 0x97, 0xc4, 0x33, 0x3d, 0xc4, 0x18, 0xeb,
-	0xff, 0x4e, 0xe2, 0x79, 0x75, 0x9b, 0x91, 0xed, 0xa4, 0x77, 0xf6, 0xad,
-	0x8f, 0x10, 0xab, 0x71, 0xfa, 0xd5, 0x31, 0x74, 0x70, 0xae, 0xf4, 0xac,
-	0x11, 0xe9, 0x20, 0x07, 0x54, 0xf6, 0x79, 0x89, 0x7d, 0x96, 0x6a, 0xa5,
-	0xaf, 0x0e, 0xe1, 0x59, 0xf6, 0x31, 0x93, 0x8e, 0xa7, 0x15, 0x92, 0x03,
-	0x13, 0x48, 0x64, 0x24, 0x07, 0x9c, 0x55, 0xad, 0xf4, 0xf8, 0x92, 0x03,
-	0xc4, 0xa0, 0x4b, 0x0c, 0x16, 0x79, 0x30, 0x28, 0x79, 0x50, 0x45, 0x0f,
-	0xb1, 0x40, 0x0f, 0x51, 0x61, 0x47, 0xc9, 0x01, 0xc9, 0x89, 0xa2, 0x8f,
-	0xe8, 0x2c, 0xf1, 0x60, 0x8b, 0x37, 0x9f, 0x4a, 0xed, 0x0b, 0xa3, 0x69,
-	0xda, 0xd0, 0x55, 0xe5, 0x3f, 0xc5, 0x2e, 0xd3, 0x5c, 0xdc, 0x4b, 0x2f,
-	0xf0, 0x59, 0x5b, 0x8c, 0x79, 0x0f, 0x63, 0xdd, 0x42, 0x79, 0x40, 0xe2,
-	0xbc, 0x7e, 0x3a, 0x8c, 0xea, 0x69, 0xc9, 0x83, 0xec, 0x24, 0xf5, 0x6f,
-	0xc8, 0xf2, 0xfd, 0x13, 0xf1, 0x1f, 0x25, 0x2e, 0x54, 0xa5, 0x8b, 0x63,
-	0x54, 0xcd, 0xe8, 0x68, 0x9d, 0x36, 0x06, 0x17, 0x70, 0x4d, 0xbc, 0x1a,
-	0x33, 0x33, 0x87, 0x98, 0xff, 0x3d, 0xc9, 0x18, 0xf7, 0x4a, 0xc7, 0xbd,
-	0xb7, 0xc6, 0xf0, 0x38, 0xe1, 0xf4, 0x5b, 0xe1, 0x92, 0xaf, 0xd6, 0xd0,
-	0xef, 0x02, 0x7b, 0x5c, 0x1a, 0x5b, 0xd3, 0xb7, 0x36, 0x88, 0xeb, 0x38,
-	0x49, 0xf4, 0x0f, 0xe8, 0x0e, 0xf3, 0x1f, 0xc2, 0xde, 0xd2, 0x3b, 0x45,
-	0xbf, 0xfd, 0xe3, 0xd2, 0x79, 0xf2, 0x17, 0xfe, 0xe2, 0xdf, 0xbf, 0x55,
-	0x97, 0xcf, 0x97, 0xfd, 0xc4, 0xe0, 0x66, 0x62, 0xb0, 0x9b, 0x39, 0xda,
-	0x6b, 0x91, 0xdf, 0xcc, 0x67, 0x56, 0x0d, 0x51, 0x0f, 0x9b, 0xfa, 0x2a,
-	0xa9, 0x6b, 0x87, 0xa9, 0x51, 0x3f, 0x37, 0xcb, 0xe9, 0xb7, 0x1d, 0xfa,
-	0xed, 0x0e, 0x6a, 0x68, 0x27, 0xf5, 0x53, 0x62, 0x2b, 0x4d, 0x1c, 0x69,
-	0x4a, 0x9a, 0x1e, 0x36, 0x90, 0xa4, 0xd7, 0xae, 0x5b, 0xf6, 0xda, 0x32,
-	0x4e, 0xe9, 0xaf, 0x8d, 0xb8, 0x2c, 0xb5, 0x4f, 0x32, 0x0f, 0x8b, 0x35,
-	0x9b, 0xa0, 0xda, 0x9b, 0x14, 0xd5, 0x96, 0xe7, 0x09, 0x15, 0xdf, 0xa5,
-	0xd6, 0x2e, 0xed, 0x90, 0xe7, 0x0a, 0xae, 0x8b, 0x6d, 0x11, 0x33, 0x16,
-	0x3d, 0x4e, 0x5c, 0x1d, 0xfb, 0x9d, 0x73, 0x46, 0x11, 0x6f, 0xa3, 0xae,
-	0x7a, 0xcb, 0x33, 0x4b, 0x7d, 0xd8, 0x74, 0x0b, 0x6f, 0x1a, 0x9e, 0x68,
-	0x89, 0x12, 0x8f, 0x12, 0x6b, 0x1a, 0xf2, 0x2f, 0x96, 0xe3, 0xd5, 0x17,
-	0xc3, 0x78, 0xe5, 0x45, 0x21, 0xc6, 0x93, 0xe0, 0x69, 0x46, 0x6a, 0xec,
-	0x46, 0xbc, 0xac, 0xc7, 0xa2, 0xcf, 0x7a, 0x9e, 0xd5, 0xa1, 0x67, 0x35,
-	0x06, 0x2f, 0xe0, 0x26, 0xf5, 0x4b, 0x72, 0x3a, 0x41, 0xbe, 0x15, 0xb1,
-	0xe8, 0x79, 0xdb, 0x1a, 0x0d, 0x57, 0x88, 0xbf, 0x6a, 0xe2, 0xef, 0x37,
-	0xd4, 0xdd, 0x6b, 0x25, 0xdd, 0x5d, 0x9b, 0x27, 0x1f, 0xdb, 0x42, 0xe8,
-	0x96, 0x6b, 0x21, 0x0e, 0x47, 0x6f, 0xe1, 0x50, 0x88, 0x0f, 0xb8, 0xe7,
-	0x17, 0x2c, 0x23, 0xbe, 0x99, 0x78, 0x9c, 0xb3, 0x0c, 0xa7, 0x83, 0xde,
-	0x75, 0xd4, 0xc3, 0x24, 0xf5, 0x37, 0x26, 0x71, 0x49, 0x1c, 0x32, 0x27,
-	0x87, 0xd9, 0xe7, 0x3c, 0xfb, 0x4c, 0x94, 0xbc, 0xeb, 0xdb, 0x48, 0xa4,
-	0xa5, 0x77, 0x8d, 0x12, 0x83, 0x87, 0x3d, 0xef, 0x2a, 0xbd, 0xaa, 0xf4,
-	0xa9, 0x32, 0xce, 0x76, 0x2f, 0xce, 0xae, 0x5b, 0x38, 0xa4, 0x86, 0xd5,
-	0x48, 0xfc, 0x7d, 0x03, 0x13, 0xcf, 0x57, 0xa1, 0xda, 0xbc, 0x07, 0x97,
-	0x33, 0xdf, 0x50, 0x23, 0x26, 0xf4, 0x7a, 0xbb, 0x88, 0xc7, 0x9d, 0x85,
-	0x14, 0x5c, 0xf7, 0x2d, 0xe1, 0xd6, 0x19, 0xce, 0x05, 0xcf, 0x7f, 0x0e,
-	0xb2, 0xd6, 0xdc, 0x14, 0xbe, 0x98, 0x71, 0xb1, 0x9f, 0x1e, 0xac, 0xc9,
-	0x5f, 0xf4, 0x72, 0x1b, 0xf3, 0xbf, 0x14, 0xa8, 0x2d, 0xae, 0x53, 0xa5,
-	0x7f, 0x1b, 0x23, 0xe7, 0xc6, 0xcd, 0xa2, 0x97, 0x8b, 0xe5, 0xaf, 0x06,
-	0xa4, 0xa6, 0xfb, 0xda, 0xe4, 0xb8, 0x69, 0x6a, 0xc8, 0xf2, 0xd8, 0x5f,
-	0xea, 0xf2, 0x18, 0x31, 0x38, 0x2a, 0x7d, 0x15, 0x7d, 0x09, 0xcf, 0xe5,
-	0x2b, 0x34, 0x75, 0xd8, 0x0f, 0x53, 0xb6, 0x39, 0xca, 0x03, 0x5c, 0x83,
-	0x66, 0x0e, 0x2b, 0x69, 0x9e, 0x3b, 0x0f, 0x11, 0x5f, 0xdd, 0xac, 0xc3,
-	0x57, 0xad, 0x66, 0x72, 0x98, 0xf5, 0x89, 0xb5, 0xf8, 0xb0, 0xb9, 0x7c,
-	0x7e, 0x93, 0x35, 0x99, 0x35, 0xcc, 0xad, 0x64, 0xfd, 0xee, 0x61, 0xcd,
-	0xe6, 0x28, 0xcc, 0xe9, 0x67, 0x31, 0xd1, 0xb8, 0xb6, 0xcd, 0x18, 0xdc,
-	0xe6, 0x0f, 0x21, 0x47, 0xbc, 0x1f, 0x63, 0x1d, 0x72, 0xb9, 0xa7, 0xd3,
-	0x05, 0x23, 0x95, 0xc5, 0x18, 0xb6, 0x71, 0x4f, 0x79, 0xde, 0x71, 0xfe,
-	0x2e, 0x56, 0x3c, 0x0f, 0xef, 0x65, 0x7d, 0x9b, 0x2c, 0x71, 0xfb, 0x43,
-	0x24, 0x2c, 0xc9, 0xed, 0x45, 0xd6, 0xb7, 0x49, 0x8f, 0xdb, 0x46, 0x4a,
-	0xf2, 0xb9, 0xac, 0x54, 0xd7, 0x3e, 0x82, 0xe4, 0xf0, 0xed, 0x35, 0x4d,
-	0xe2, 0xd9, 0x0e, 0x4a, 0x1f, 0xeb, 0xba, 0xb2, 0x26, 0xc9, 0x5a, 0xb4,
-	0x5c, 0x97, 0x34, 0x79, 0x77, 0x90, 0x69, 0x9c, 0x3a, 0x28, 0x7c, 0xc5,
-	0xfb, 0x87, 0x8b, 0xef, 0xfa, 0xc3, 0xa9, 0xd4, 0x7d, 0xc8, 0x44, 0xce,
-	0x6a, 0xd8, 0xe1, 0x36, 0xf4, 0x85, 0x6c, 0xf0, 0x1d, 0x05, 0xd6, 0x1f,
-	0x6b, 0xc8, 0xdc, 0x76, 0xff, 0xf0, 0x41, 0x4e, 0xd3, 0xaa, 0xa7, 0xee,
-	0x96, 0xef, 0xe0, 0x93, 0xdc, 0x1d, 0xef, 0x1f, 0xd2, 0xbf, 0xef, 0xfe,
-	0xe1, 0x59, 0xf2, 0x63, 0xa2, 0x78, 0xff, 0xe0, 0x7c, 0xa7, 0xc5, 0x8f,
-	0xb9, 0x3a, 0x1c, 0x78, 0xaf, 0x5d, 0xc5, 0xd5, 0x9c, 0x11, 0x79, 0x19,
-	0x07, 0x30, 0xe0, 0xdd, 0x35, 0xf0, 0xcc, 0x6f, 0x0f, 0xe1, 0xd7, 0xed,
-	0xf2, 0xae, 0x21, 0x25, 0xd7, 0x38, 0xc9, 0xe5, 0x43, 0xa3, 0xde, 0x6c,
-	0x61, 0x2d, 0xd8, 0xb7, 0x51, 0xc1, 0x03, 0xc9, 0x7b, 0x3c, 0x6c, 0x4f,
-	0x16, 0x8c, 0x74, 0x94, 0xcf, 0xd6, 0x4d, 0xc9, 0x1a, 0xf9, 0x30, 0xcf,
-	0x86, 0xd0, 0x1a, 0xed, 0x5e, 0x4d, 0xb8, 0x4d, 0x91, 0x0f, 0x15, 0xc3,
-	0x39, 0x09, 0x79, 0x1f, 0x90, 0xb8, 0xe8, 0x57, 0x8c, 0xc5, 0x77, 0xfd,
-	0x46, 0xaa, 0xde, 0xc3, 0xcc, 0xc3, 0x3c, 0xa7, 0xc9, 0xbf, 0xbd, 0xf2,
-	0x8c, 0x87, 0x6d, 0x1c, 0xf3, 0xd2, 0x46, 0x79, 0xee, 0xfc, 0x54, 0x64,
-	0x57, 0x19, 0xce, 0x92, 0xa2, 0x31, 0x37, 0xa0, 0x3e, 0x49, 0x0d, 0x7f,
-	0x98, 0x1a, 0x2e, 0xcf, 0x08, 0xbd, 0x3c, 0x23, 0x34, 0x2d, 0xc6, 0xfd,
-	0x46, 0xe6, 0x06, 0xf5, 0x8e, 0x63, 0xf6, 0xf5, 0x2a, 0x46, 0xef, 0x02,
-	0xf5, 0x7f, 0xbf, 0x52, 0x1c, 0x73, 0x4d, 0x69, 0xcc, 0x7b, 0xf3, 0x9a,
-	0xb2, 0xd9, 0x05, 0x75, 0x07, 0xd1, 0x3d, 0x16, 0xb5, 0xa3, 0x50, 0x4e,
-	0x8e, 0x99, 0x72, 0xcd, 0x8c, 0xad, 0x95, 0xb1, 0x29, 0xf8, 0xb0, 0x45,
-	0xbe, 0xdb, 0x2a, 0xe3, 0x70, 0x2a, 0xec, 0x14, 0xb5, 0xf7, 0xb9, 0x60,
-	0x49, 0xbf, 0x7c, 0xfd, 0xd6, 0x2a, 0x38, 0x75, 0xa8, 0x0e, 0x98, 0xb5,
-	0x18, 0xd7, 0x51, 0x19, 0x36, 0x9b, 0x91, 0xd3, 0x83, 0xe8, 0xb7, 0x7e,
-	0x2b, 0xa8, 0x93, 0x7c, 0x1f, 0x78, 0xec, 0x79, 0x9e, 0xd7, 0xcd, 0xeb,
-	0x88, 0x25, 0x9f, 0xc6, 0x19, 0x7d, 0x08, 0xe5, 0xac, 0xa5, 0xaf, 0x78,
-	0x7a, 0x62, 0x13, 0xcf, 0x0a, 0x31, 0x64, 0xcb, 0x5a, 0x77, 0xdb, 0xd8,
-	0xf2, 0xfe, 0xe1, 0x7d, 0x91, 0x2d, 0x8e, 0xe1, 0xec, 0xb1, 0x32, 0x8c,
-	0xeb, 0x4b, 0xdd, 0xdd, 0x47, 0xdd, 0xa5, 0xb7, 0xfc, 0x5a, 0x39, 0x75,
-	0x77, 0xb7, 0xf5, 0x6d, 0x3c, 0x46, 0x8e, 0x57, 0x98, 0x9f, 0x88, 0xc7,
-	0xeb, 0xe4, 0x98, 0xd4, 0xd7, 0xaa, 0x95, 0xe3, 0xff, 0x33, 0xc7, 0x94,
-	0x73, 0xc8, 0x7a, 0x78, 0x59, 0x48, 0x6f, 0x56, 0x61, 0x0f, 0x2b, 0xdb,
-	0xc8, 0xa9, 0x45, 0x96, 0xde, 0xef, 0x92, 0x4f, 0x4b, 0xcc, 0x4f, 0xe3,
-	0x1d, 0xf8, 0xd4, 0x48, 0x3e, 0xed, 0x5a, 0xc1, 0xa7, 0xe3, 0xe4, 0x53,
-	0x2f, 0xf9, 0xd4, 0xd2, 0xf6, 0x27, 0xd4, 0x15, 0x21, 0x82, 0x6d, 0x37,
-	0xc5, 0x9b, 0x9e, 0xff, 0x95, 0x9e, 0x37, 0xad, 0x74, 0xcd, 0x4b, 0x7d,
-	0xaa, 0xa4, 0x27, 0xee, 0xa1, 0x1f, 0x06, 0x06, 0xc8, 0xa7, 0xc7, 0x4d,
-	0xd1, 0xb8, 0x2f, 0x69, 0xa4, 0x16, 0xe9, 0x6b, 0x7a, 0xc8, 0xa9, 0xb7,
-	0xc8, 0xa9, 0xb1, 0x42, 0x51, 0xa7, 0x0e, 0x73, 0xdd, 0xf7, 0x53, 0xa7,
-	0x7a, 0x0a, 0x52, 0xdb, 0x1c, 0xe2, 0x3f, 0x84, 0x4f, 0xc9, 0xa9, 0xf9,
-	0xa4, 0xa7, 0x53, 0xd6, 0x6f, 0x90, 0x18, 0x3a, 0x2f, 0xf9, 0x44, 0x9d,
-	0x72, 0x0b, 0x4d, 0xd6, 0x79, 0xae, 0x69, 0xd2, 0x35, 0x6e, 0x74, 0x93,
-	0x53, 0x81, 0x76, 0xe3, 0xe2, 0x55, 0x62, 0x37, 0x14, 0x83, 0x1e, 0xb1,
-	0xe5, 0x9a, 0x58, 0x63, 0x59, 0x27, 0x8f, 0x13, 0xff, 0xdd, 0xd4, 0x8c,
-	0xde, 0x82, 0x8d, 0x43, 0x85, 0x95, 0x7b, 0xca, 0x3a, 0x74, 0xc7, 0x7d,
-	0x19, 0x0d, 0xdd, 0xb9, 0x9d, 0xf5, 0xea, 0x8e, 0xed, 0x92, 0xaf, 0x7a,
-	0x48, 0xf2, 0x75, 0xd4, 0xfd, 0x61, 0xe0, 0xce, 0xef, 0xc8, 0xfb, 0x33,
-	0x21, 0x4e, 0x5b, 0xf2, 0xfe, 0x41, 0xfa, 0x1e, 0xfa, 0x68, 0x4b, 0xde,
-	0xa1, 0x75, 0x44, 0x55, 0x18, 0x91, 0x47, 0xf1, 0xb9, 0xc8, 0xd6, 0x39,
-	0xf1, 0x80, 0x57, 0x23, 0x0d, 0xbd, 0x8f, 0xb5, 0x6e, 0xb1, 0x74, 0xce,
-	0x9b, 0xcb, 0x09, 0xf1, 0x16, 0xeb, 0xd4, 0x69, 0x9e, 0xe9, 0x46, 0xf2,
-	0x9f, 0x8b, 0xc5, 0x3a, 0x15, 0x63, 0xe6, 0xad, 0xfb, 0x48, 0x4f, 0xc7,
-	0x4e, 0xf2, 0xd9, 0x44, 0x7e, 0xb9, 0x46, 0x51, 0x33, 0x4d, 0x21, 0x76,
-	0x9b, 0xff, 0x2d, 0xfa, 0xbf, 0xf2, 0xae, 0x10, 0xd3, 0x8c, 0xe1, 0x8a,
-	0x85, 0x03, 0x01, 0xc4, 0xfa, 0x6e, 0xb0, 0xae, 0x5f, 0xda, 0x68, 0x64,
-	0xf2, 0x4a, 0xa2, 0x77, 0xab, 0x22, 0xbd, 0x9e, 0xaf, 0xb3, 0x8c, 0xef,
-	0xb4, 0xd0, 0x1b, 0x7d, 0xc8, 0x0c, 0x06, 0xf9, 0xfd, 0x4d, 0xcb, 0xa0,
-	0x7f, 0x16, 0xa2, 0x3f, 0x25, 0xc7, 0x10, 0xa2, 0xc3, 0x92, 0xe7, 0x80,
-	0x31, 0x9e, 0x03, 0xb2, 0xa2, 0xc2, 0xbc, 0x42, 0x6d, 0x32, 0x32, 0x63,
-	0x8a, 0xc9, 0xbe, 0x51, 0x78, 0x3a, 0xcb, 0x67, 0xda, 0x54, 0x04, 0x7f,
-	0xed, 0xf9, 0xe7, 0x28, 0x35, 0xab, 0x01, 0x7f, 0xe3, 0xe9, 0x96, 0x8a,
-	0x3d, 0xcf, 0x1b, 0x29, 0x55, 0x39, 0x88, 0xf7, 0x2d, 0x43, 0xff, 0x21,
-	0xe3, 0xa6, 0xd6, 0x3c, 0xb7, 0x19, 0x51, 0x70, 0x8e, 0x6c, 0x9f, 0xbf,
-	0x46, 0xd1, 0x58, 0x3b, 0xbe, 0xdf, 0x22, 0x6b, 0xf7, 0x10, 0xba, 0x9b,
-	0xf7, 0xf3, 0xa3, 0xa2, 0x76, 0x46, 0x55, 0x76, 0xd0, 0x93, 0x54, 0xcf,
-	0x54, 0x63, 0xef, 0x7a, 0x21, 0xd6, 0xae, 0x77, 0xc0, 0x33, 0x5f, 0xfc,
-	0x02, 0x6b, 0xd0, 0x89, 0x1a, 0x23, 0x0d, 0xfc, 0x04, 0x3b, 0xe9, 0x65,
-	0x53, 0x6d, 0x39, 0xe0, 0x1e, 0xb9, 0xc6, 0x9f, 0x60, 0xb3, 0xf4, 0xc0,
-	0x56, 0xb5, 0xf4, 0x5b, 0x1e, 0x7e, 0x8b, 0x77, 0x48, 0x4c, 0xf5, 0xd1,
-	0xac, 0x28, 0x37, 0x8d, 0xbe, 0x79, 0xd6, 0xdb, 0x4b, 0xb1, 0xbb, 0xf5,
-	0x6f, 0xcd, 0x4b, 0x0f, 0x6c, 0x46, 0xb7, 0x28, 0x82, 0xb9, 0x78, 0x86,
-	0xb9, 0x88, 0x39, 0x61, 0x5a, 0x86, 0x6a, 0x3b, 0xe6, 0x54, 0x2b, 0xc3,
-	0xca, 0x83, 0xe4, 0x43, 0x5f, 0xb0, 0x9c, 0x1e, 0xc2, 0xa1, 0x7f, 0xf0,
-	0xa1, 0xf2, 0xa8, 0xf4, 0x14, 0x21, 0x6a, 0x4d, 0x53, 0x2f, 0x4f, 0x17,
-	0xd8, 0x97, 0x94, 0xfe, 0x83, 0x58, 0x3f, 0x7a, 0x53, 0x6c, 0xa6, 0xc7,
-	0xdd, 0x5c, 0xf2, 0xb8, 0xbb, 0x66, 0xd3, 0xf4, 0xc0, 0x9a, 0x22, 0xef,
-	0xd3, 0x52, 0x6d, 0x3c, 0x94, 0x3e, 0x28, 0x7d, 0x88, 0x5c, 0x83, 0x8e,
-	0x6b, 0x49, 0x89, 0x5d, 0x1d, 0xa3, 0xed, 0x46, 0x24, 0x0b, 0x79, 0x7f,
-	0x73, 0xbb, 0xbf, 0x80, 0x9e, 0xfe, 0x1d, 0xcf, 0x01, 0x7d, 0x07, 0x63,
-	0x31, 0x82, 0x42, 0xd4, 0x26, 0xfd, 0xe8, 0xf3, 0xce, 0x73, 0x11, 0x3d,
-	0x4d, 0xde, 0x5f, 0xa4, 0x4f, 0xf0, 0xf3, 0xdc, 0x7c, 0x90, 0x58, 0xfa,
-	0xac, 0x65, 0xe4, 0x58, 0x3d, 0xb2, 0x93, 0xb5, 0x30, 0xac, 0xfb, 0xa9,
-	0xab, 0x57, 0x72, 0x0f, 0xb2, 0x9e, 0xfb, 0xda, 0x23, 0x3c, 0x03, 0x34,
-	0xce, 0x64, 0x45, 0x3d, 0xfd, 0xe0, 0x37, 0x78, 0xee, 0xad, 0x69, 0x8b,
-	0xd3, 0x6f, 0x2f, 0xef, 0x95, 0x0f, 0x4f, 0x59, 0x26, 0x1c, 0xef, 0x77,
-	0x58, 0xef, 0x9a, 0xbd, 0x29, 0xe6, 0xcc, 0xbb, 0xf5, 0x8e, 0x62, 0x5c,
-	0x6a, 0x99, 0x6d, 0xa1, 0x65, 0x03, 0xcf, 0x8e, 0x77, 0x88, 0xa9, 0x47,
-	0x7a, 0x9f, 0x40, 0xb1, 0xdf, 0x9f, 0xce, 0x36, 0xe8, 0xdb, 0x59, 0xef,
-	0x16, 0x89, 0x95, 0x5d, 0xeb, 0x2d, 0x19, 0xcb, 0xa2, 0x8c, 0x85, 0xfe,
-	0xd2, 0xb9, 0xdf, 0x47, 0x5f, 0x92, 0x04, 0xaa, 0xcf, 0x3e, 0x45, 0x5e,
-	0xf9, 0x5a, 0xab, 0x91, 0x1d, 0x62, 0x8c, 0xc7, 0xfe, 0x91, 0x5b, 0x33,
-	0x30, 0x8d, 0x01, 0x1f, 0xfb, 0x4c, 0x59, 0xc0, 0x13, 0x0b, 0x3c, 0x97,
-	0x4e, 0xc7, 0xe8, 0xcb, 0xe9, 0x23, 0x17, 0x34, 0x3c, 0x3a, 0x5b, 0x8e,
-	0xef, 0xcd, 0x86, 0xb1, 0x6f, 0xd6, 0xbb, 0xd7, 0xda, 0x5a, 0xcb, 0xf7,
-	0x3a, 0x92, 0x42, 0xcc, 0x5b, 0xeb, 0xf1, 0x1e, 0x3d, 0xd4, 0x6a, 0xc5,
-	0x87, 0xc8, 0x51, 0xe8, 0x3a, 0x71, 0x53, 0xd3, 0xf2, 0x3d, 0x26, 0x58,
-	0x08, 0x73, 0xbd, 0xd4, 0xc9, 0x67, 0xbc, 0xef, 0x63, 0xf4, 0x8f, 0x19,
-	0x89, 0x41, 0x97, 0x18, 0x74, 0x89, 0xc9, 0x5b, 0x9e, 0x5a, 0x62, 0x39,
-	0x4e, 0x1f, 0xfd, 0xb4, 0x28, 0x62, 0xe3, 0x0b, 0x71, 0xda, 0x7c, 0x95,
-	0xfc, 0x55, 0xa9, 0xa1, 0xc0, 0xdf, 0xe7, 0x22, 0xfa, 0x8e, 0x82, 0xcc,
-	0xff, 0x5f, 0x96, 0xf2, 0xbf, 0x18, 0x2a, 0xea, 0x85, 0xe1, 0xcc, 0xa3,
-	0x01, 0xd3, 0x6e, 0x83, 0xbe, 0xd5, 0x1d, 0x19, 0xd6, 0x90, 0x8d, 0x56,
-	0xc3, 0x18, 0x9c, 0x86, 0xaf, 0x35, 0x0c, 0xb9, 0x76, 0x20, 0xef, 0xad,
-	0x51, 0x88, 0x09, 0xea, 0x9b, 0xcc, 0xc1, 0xbf, 0xe7, 0xd0, 0xea, 0x63,
-	0x3e, 0x1c, 0xc6, 0xbe, 0x8f, 0x7b, 0xf0, 0x71, 0x5e, 0xde, 0x73, 0xc6,
-	0xd2, 0x5d, 0xb8, 0xee, 0x8d, 0xf9, 0x51, 0x3e, 0x85, 0x23, 0xee, 0x25,
-	0x71, 0xa4, 0xae, 0xa8, 0xf1, 0x69, 0x9e, 0x8f, 0xaa, 0x8f, 0x96, 0xbc,
-	0x10, 0x39, 0x5c, 0xc9, 0xf5, 0x5e, 0x4b, 0x7a, 0xde, 0x9f, 0x35, 0x72,
-	0x50, 0x3b, 0x6d, 0x6e, 0xe4, 0xda, 0x6e, 0x8a, 0x89, 0x58, 0xb3, 0x56,
-	0x8c, 0x29, 0xa1, 0x9f, 0x42, 0x19, 0xb1, 0x2b, 0xcf, 0x48, 0x52, 0x3f,
-	0xe4, 0x6f, 0x9e, 0x4f, 0x54, 0x27, 0xe2, 0xe7, 0xba, 0x9c, 0x87, 0x64,
-	0x5b, 0xa8, 0xe4, 0x57, 0x97, 0xbd, 0x48, 0x07, 0x9f, 0x49, 0x2f, 0xf2,
-	0xb9, 0xe8, 0xab, 0xeb, 0xb8, 0xa5, 0x39, 0x59, 0xbe, 0x31, 0xee, 0xca,
-	0xfb, 0xab, 0x16, 0x3a, 0x62, 0x05, 0xe7, 0x18, 0xf9, 0xa9, 0xd6, 0x98,
-	0x3e, 0xca, 0xf1, 0x1c, 0x5d, 0x27, 0x97, 0x0f, 0xd2, 0x2f, 0xf3, 0x9d,
-	0x42, 0x0b, 0xfb, 0x48, 0x2d, 0xdb, 0xc1, 0xb5, 0xfe, 0xb6, 0x59, 0x62,
-	0x7b, 0xd4, 0x7d, 0xc3, 0xa7, 0x9a, 0x72, 0x9d, 0x89, 0xd4, 0x28, 0xe3,
-	0x59, 0xd2, 0xa5, 0xb7, 0x76, 0xa8, 0x6d, 0x09, 0xaf, 0x7f, 0x56, 0x95,
-	0x71, 0x78, 0xf1, 0xb0, 0x4d, 0x6a, 0x96, 0x91, 0x39, 0x87, 0x84, 0x33,
-	0x20, 0xcd, 0xc1, 0x2a, 0x19, 0x43, 0x53, 0x64, 0x80, 0xf1, 0x9c, 0xa8,
-	0xf3, 0xf4, 0x90, 0xcf, 0x38, 0x9f, 0xeb, 0xdb, 0x5a, 0x0e, 0x81, 0xd5,
-	0x49, 0xef, 0xdc, 0x5f, 0xfa, 0x7f, 0x18, 0x2a, 0x7d, 0x88, 0xc4, 0xe2,
-	0xff, 0x02, 0xc7, 0x2a, 0x26, 0xcf, 0x94, 0x1a, 0x00, 0x00, 0x00 };
+	0xbd, 0x59, 0x6d, 0x70, 0x5b, 0x55, 0x7a, 0x7e, 0xae, 0x74, 0x25, 0x5d,
+	0xdb, 0xb2, 0x75, 0x8d, 0x95, 0x20, 0xb7, 0x2e, 0xd6, 0x8d, 0xaf, 0x6c,
+	0x11, 0xb9, 0xe1, 0x2a, 0x36, 0x45, 0x19, 0xee, 0x94, 0x1b, 0x7f, 0x21,
+	0x92, 0x10, 0x94, 0x42, 0x5b, 0x67, 0x96, 0x19, 0x4c, 0xe2, 0x4d, 0x4c,
+	0x08, 0x6c, 0xba, 0xcb, 0x4c, 0xdd, 0xd9, 0x4c, 0x23, 0xfc, 0x15, 0x93,
+	0xc8, 0x16, 0x6b, 0x20, 0x26, 0x3b, 0x3b, 0x43, 0xc6, 0xf9, 0x70, 0x0a,
+	0x72, 0x14, 0xda, 0x3f, 0x3b, 0xd3, 0x65, 0xf0, 0x6c, 0x12, 0x12, 0x58,
+	0xd8, 0xb4, 0xd3, 0x3f, 0xc9, 0xf4, 0xc7, 0x7a, 0x21, 0xa1, 0x81, 0x42,
+	0x36, 0xed, 0x0c, 0x9d, 0x50, 0x68, 0x4e, 0x9f, 0x73, 0x25, 0x07, 0x13,
+	0xb2, 0xfd, 0xd9, 0xcc, 0x08, 0x4b, 0xe7, 0xde, 0x73, 0xce, 0x7b, 0xce,
+	0xfb, 0x3c, 0xcf, 0xfb, 0x9c, 0xc3, 0x0a, 0x05, 0x95, 0x28, 0xff, 0xab,
+	0xe6, 0xa7, 0xfd, 0xc9, 0x5d, 0xcf, 0xad, 0x5e, 0xd5, 0xbe, 0x8a, 0x5f,
+	0x57, 0x2b, 0xcb, 0x55, 0x15, 0xff, 0x8f, 0xff, 0xbc, 0x80, 0xbe, 0x18,
+	0x87, 0xfc, 0x40, 0xf3, 0xd8, 0xf3, 0x77, 0x75, 0x98, 0xd0, 0xbc, 0xf6,
+	0x63, 0x4d, 0x5b, 0x4d, 0xc0, 0x29, 0x24, 0xa2, 0x9d, 0xf8, 0x1f, 0x91,
+	0x0d, 0xab, 0x90, 0xed, 0x7f, 0x64, 0x7f, 0x7d, 0xcf, 0x5b, 0xf7, 0x19,
+	0xd7, 0x0e, 0x79, 0xa1, 0xe9, 0xf6, 0xb8, 0xaa, 0x37, 0x43, 0x6b, 0x60,
+	0x9f, 0x9f, 0xb5, 0xf4, 0xfb, 0x50, 0xb3, 0x38, 0x16, 0x70, 0x38, 0x67,
+	0x58, 0xdb, 0x90, 0xd0, 0x4f, 0x41, 0x85, 0xc3, 0x39, 0x8e, 0x15, 0x80,
+	0xbd, 0x39, 0x05, 0x97, 0x39, 0xe6, 0x68, 0x41, 0xc3, 0x82, 0xd7, 0x9d,
+	0xae, 0xaf, 0xc2, 0x46, 0xc6, 0x9c, 0xd8, 0x23, 0x02, 0x26, 0xb2, 0x7f,
+	0x60, 0x9b, 0xf1, 0xbd, 0x08, 0xa6, 0x66, 0xda, 0x91, 0x59, 0x31, 0xa7,
+	0x61, 0x73, 0xbe, 0xa1, 0x4f, 0xb3, 0xc1, 0x77, 0x14, 0xa4, 0xee, 0xd3,
+	0xd0, 0x5b, 0x8c, 0x23, 0x5b, 0xcc, 0xc2, 0x29, 0x8e, 0xf0, 0xa3, 0x21,
+	0x30, 0xa1, 0x69, 0xf7, 0x4c, 0x2c, 0x97, 0xef, 0x20, 0x38, 0x71, 0x4d,
+	0x5c, 0x4d, 0xea, 0x78, 0x6f, 0x8d, 0x10, 0xd5, 0x36, 0xb2, 0x55, 0xed,
+	0x59, 0x78, 0x6d, 0xc3, 0x5a, 0xef, 0x55, 0xd0, 0xf5, 0xc7, 0x66, 0x7c,
+	0x42, 0x79, 0xf4, 0x51, 0x8f, 0x0d, 0x4d, 0xb1, 0xa3, 0x6a, 0x53, 0xa1,
+	0x01, 0x63, 0x45, 0x1d, 0x7b, 0x8b, 0x61, 0x8c, 0x14, 0xb1, 0xdb, 0x7b,
+	0xaf, 0x1f, 0x33, 0x3a, 0x9c, 0xef, 0xb5, 0xec, 0xc6, 0x8e, 0xdc, 0x20,
+	0xb6, 0xe6, 0x52, 0xd8, 0x57, 0x94, 0x31, 0x46, 0x31, 0x5c, 0x54, 0xe1,
+	0x9f, 0x30, 0x22, 0xef, 0xe2, 0x76, 0xcf, 0x84, 0x18, 0xb1, 0x02, 0x18,
+	0xb2, 0xe2, 0x18, 0xcd, 0x7b, 0xb8, 0xce, 0x00, 0x86, 0xcd, 0xeb, 0xa2,
+	0xdf, 0x32, 0xac, 0x51, 0x88, 0xc6, 0xd3, 0x96, 0x11, 0xe9, 0xf2, 0xc2,
+	0xf9, 0xb1, 0x19, 0xc1, 0x28, 0x63, 0x1f, 0x71, 0xfb, 0x8d, 0xa0, 0xeb,
+	0x66, 0x3f, 0x87, 0xfd, 0x74, 0x8c, 0x7d, 0xbb, 0x6f, 0x74, 0x14, 0x89,
+	0xc8, 0x18, 0x3c, 0xe8, 0x0b, 0xb7, 0xb2, 0x5f, 0x53, 0x74, 0x0c, 0x46,
+	0x9c, 0xe3, 0x64, 0xfd, 0xed, 0x0e, 0xc7, 0xc8, 0xb2, 0xbf, 0x11, 0x3d,
+	0x06, 0x39, 0x56, 0x03, 0x7f, 0xb7, 0xb3, 0xbf, 0x02, 0x8f, 0x1d, 0x8b,
+	0x0e, 0xb1, 0xcf, 0x29, 0x4b, 0xc5, 0x19, 0x7e, 0xfa, 0x74, 0x43, 0x66,
+	0x56, 0x09, 0xb0, 0x7d, 0x2f, 0xf8, 0xdc, 0xac, 0xc2, 0xa1, 0x8c, 0x85,
+	0x21, 0xae, 0x5b, 0x63, 0xdb, 0x38, 0xdb, 0x7c, 0xa6, 0xc5, 0xf1, 0xa1,
+	0x77, 0x15, 0x97, 0x62, 0x62, 0x31, 0x37, 0xbf, 0xaf, 0x9d, 0x63, 0xe4,
+	0x4b, 0x39, 0x95, 0xef, 0x74, 0xe6, 0x6f, 0x88, 0x27, 0xd5, 0xa5, 0xcf,
+	0x07, 0x95, 0x0e, 0xb6, 0x39, 0x6a, 0x03, 0xf6, 0xe6, 0xa1, 0xf9, 0x4d,
+	0x8d, 0xf3, 0x68, 0xf8, 0x28, 0x37, 0xa8, 0xf4, 0x14, 0x1d, 0xa5, 0x7b,
+	0xb6, 0x43, 0x71, 0x66, 0x55, 0xa5, 0x6b, 0x5a, 0xc6, 0x2d, 0xc4, 0x0b,
+	0x96, 0xc2, 0x98, 0x7f, 0x22, 0xe3, 0x75, 0xa2, 0xca, 0x0d, 0xb1, 0x32,
+	0xe6, 0x41, 0x95, 0xd9, 0xa3, 0xac, 0x9f, 0x15, 0x22, 0x9d, 0x4c, 0x2b,
+	0xeb, 0x66, 0xa1, 0x05, 0x6d, 0x5b, 0xcd, 0x4d, 0xec, 0x43, 0x76, 0x99,
+	0x89, 0x83, 0xf9, 0x28, 0x3e, 0xb0, 0x3c, 0x38, 0xb4, 0xac, 0x02, 0xaa,
+	0xa9, 0xf0, 0x83, 0xe0, 0x79, 0x0b, 0x6a, 0x0d, 0xbf, 0x5f, 0xdd, 0xa4,
+	0x62, 0xa4, 0x7d, 0x9d, 0xd2, 0xc5, 0x3e, 0x3e, 0xe6, 0xf9, 0x68, 0x2e,
+	0x8d, 0x20, 0xb1, 0x53, 0x65, 0xc7, 0x22, 0x05, 0xee, 0xcd, 0x7b, 0x56,
+	0x2c, 0xfe, 0xb4, 0xc4, 0x63, 0xad, 0x11, 0x91, 0x7b, 0x53, 0x6d, 0xc7,
+	0xe2, 0x73, 0xdc, 0x07, 0xaf, 0xa9, 0xe2, 0xd7, 0x96, 0x0f, 0xf3, 0x9b,
+	0x2c, 0xe6, 0x54, 0x87, 0x9f, 0xed, 0xc7, 0xdc, 0x76, 0xf9, 0x1b, 0x7a,
+	0xf7, 0xb7, 0xf6, 0xa1, 0xb4, 0x07, 0xc3, 0xf9, 0x26, 0xc6, 0x5c, 0xda,
+	0x83, 0x47, 0xb8, 0xde, 0xdf, 0xfa, 0xe4, 0xd7, 0xbb, 0x6e, 0xb6, 0x6d,
+	0x66, 0x9c, 0x1e, 0xdb, 0x9c, 0x5f, 0xe1, 0xad, 0x07, 0xea, 0xda, 0xb1,
+	0x8f, 0x39, 0xee, 0x4a, 0x2e, 0x47, 0xd6, 0x7d, 0x1e, 0xd6, 0xd7, 0x4f,
+	0xd7, 0xa1, 0x6f, 0x99, 0xbb, 0x6f, 0xfa, 0xc6, 0x69, 0x21, 0xce, 0x24,
+	0xfd, 0x98, 0x33, 0x87, 0x22, 0xd5, 0xc8, 0x5a, 0x5e, 0xe6, 0xfb, 0x2c,
+	0xe7, 0x2f, 0x24, 0xbd, 0x38, 0x9c, 0x3c, 0x84, 0x6c, 0x2d, 0x30, 0x93,
+	0x93, 0xbc, 0x32, 0xe6, 0xcf, 0xf2, 0xbf, 0x9e, 0xa2, 0x5c, 0x9f, 0xc5,
+	0xf5, 0x29, 0x38, 0x66, 0x4a, 0x4c, 0x5b, 0x6a, 0x33, 0xf9, 0xb5, 0x83,
+	0xfb, 0x59, 0xdf, 0x1e, 0x24, 0x3e, 0x81, 0x0f, 0x73, 0xfd, 0xd8, 0x5c,
+	0x8a, 0x05, 0xd7, 0x73, 0x50, 0x7c, 0x6d, 0x69, 0x1c, 0x2a, 0xfd, 0x26,
+	0xc7, 0xd3, 0x6a, 0x47, 0xce, 0xc8, 0xa4, 0x91, 0x38, 0xd7, 0xa1, 0xc8,
+	0xfe, 0x69, 0x75, 0x65, 0xc1, 0x8f, 0x68, 0x5d, 0xe9, 0x79, 0x95, 0xbd,
+	0x41, 0x7d, 0x7a, 0x42, 0xc1, 0xf6, 0x98, 0x7c, 0xb6, 0x41, 0x6d, 0x29,
+	0x40, 0xab, 0xb6, 0x77, 0xa9, 0x73, 0x13, 0x46, 0xdf, 0x71, 0x25, 0x11,
+	0x9d, 0x70, 0xfb, 0xec, 0x52, 0x5b, 0x0b, 0x01, 0xae, 0x27, 0xce, 0x9c,
+	0x40, 0xab, 0xb1, 0x9f, 0x53, 0x7f, 0xcd, 0x07, 0xe7, 0xdc, 0x3e, 0xcf,
+	0xa9, 0xf1, 0x82, 0x6c, 0x37, 0xac, 0xa8, 0x12, 0xc0, 0xdd, 0x49, 0x0d,
+	0x2b, 0x5b, 0x44, 0x63, 0x77, 0xd2, 0x98, 0xef, 0xf6, 0x46, 0x70, 0x90,
+	0x5c, 0x20, 0xee, 0x9c, 0x3f, 0x6c, 0x19, 0x41, 0x77, 0xd1, 0x8b, 0x68,
+	0xad, 0x83, 0xfd, 0xf9, 0x00, 0x7e, 0x49, 0xfc, 0xf7, 0x58, 0x3a, 0x46,
+	0xf2, 0x46, 0xfc, 0x57, 0x48, 0xa4, 0x8e, 0x30, 0x67, 0x0b, 0xe4, 0xc0,
+	0xfe, 0x62, 0x53, 0xfc, 0x08, 0x8c, 0x81, 0x6e, 0x72, 0x40, 0x6b, 0x97,
+	0x31, 0x40, 0x57, 0x6d, 0x72, 0xa7, 0xd8, 0x80, 0x1c, 0xf9, 0xd0, 0xed,
+	0xf2, 0x6a, 0x50, 0xe9, 0x2a, 0xbe, 0x4f, 0x6d, 0xed, 0x21, 0xbe, 0x10,
+	0x8a, 0x98, 0x7e, 0xa4, 0xea, 0xa2, 0x38, 0x4d, 0xac, 0x64, 0xc3, 0x15,
+	0xcc, 0xa5, 0xcc, 0xe7, 0x45, 0x3e, 0x5f, 0xa7, 0x74, 0xce, 0x46, 0xf1,
+	0x4b, 0xeb, 0x6b, 0xe1, 0x84, 0xab, 0xd9, 0xe6, 0x5b, 0xd2, 0xae, 0xe1,
+	0xf2, 0xcb, 0x95, 0xf8, 0xf4, 0xe5, 0x20, 0xbe, 0x7c, 0x99, 0xfc, 0xce,
+	0xa3, 0xbd, 0x12, 0x42, 0xa4, 0xda, 0x84, 0x28, 0x5a, 0xad, 0xf8, 0xa8,
+	0x36, 0x16, 0xbd, 0x00, 0xa9, 0x8d, 0x8e, 0xba, 0x35, 0x67, 0xec, 0x1a,
+	0x40, 0xc2, 0x39, 0xe5, 0xee, 0x85, 0xa3, 0xae, 0x2a, 0x9c, 0x16, 0xd8,
+	0x54, 0xda, 0x0b, 0xbf, 0xdd, 0xa5, 0xbe, 0xc3, 0xdc, 0x9c, 0x77, 0x73,
+	0xd3, 0xa5, 0xde, 0x53, 0xb8, 0xdf, 0x83, 0xca, 0xd2, 0x33, 0xd5, 0xce,
+	0xa8, 0x23, 0x39, 0xa3, 0x77, 0x9c, 0xeb, 0xeb, 0x77, 0xfb, 0x66, 0xd4,
+	0x04, 0xf7, 0x7e, 0xa1, 0x9c, 0x9b, 0x6a, 0xfb, 0x31, 0xee, 0x33, 0x73,
+	0xef, 0xee, 0xe3, 0x63, 0xdc, 0x63, 0x39, 0xdf, 0xe0, 0x2d, 0xf3, 0x0d,
+	0x72, 0xbe, 0xe3, 0x4b, 0xe6, 0xdb, 0xbd, 0x64, 0xbe, 0xdd, 0x4b, 0xe6,
+	0x4b, 0x91, 0xab, 0xff, 0x22, 0x86, 0xc2, 0xa5, 0xb1, 0x55, 0x7b, 0xe0,
+	0x96, 0xb9, 0x07, 0x38, 0xf7, 0x01, 0xb1, 0x90, 0x29, 0x8d, 0x53, 0x6d,
+	0xef, 0x5c, 0x32, 0xf7, 0x4e, 0xce, 0xbd, 0x38, 0x8e, 0x4e, 0x2d, 0x12,
+	0x62, 0xa3, 0x25, 0x84, 0x6a, 0x9b, 0x7a, 0x17, 0x9a, 0x33, 0x5d, 0xc4,
+	0x4e, 0x25, 0x12, 0xf3, 0x1e, 0x98, 0x83, 0xf5, 0x5e, 0x1f, 0x16, 0x6a,
+	0x17, 0xb9, 0x51, 0x5d, 0xfe, 0xfb, 0x9a, 0x02, 0x6a, 0xfd, 0x1b, 0xb9,
+	0x10, 0xc7, 0x88, 0xe9, 0xfd, 0x8a, 0x10, 0xa7, 0xd6, 0x24, 0x06, 0xbc,
+	0x48, 0xf4, 0xd5, 0xc0, 0x24, 0x86, 0x7c, 0x65, 0x2e, 0x2c, 0xed, 0x73,
+	0xdc, 0xed, 0x53, 0x74, 0xfb, 0x08, 0xf1, 0xe1, 0xbd, 0x57, 0xc4, 0x5b,
+	0x2d, 0x61, 0xbc, 0x4d, 0x4e, 0x9e, 0x2c, 0x2e, 0xea, 0x8a, 0xd4, 0x0d,
+	0x78, 0x4e, 0x59, 0x7e, 0xc6, 0x34, 0xb4, 0xc3, 0xff, 0xad, 0xfe, 0x04,
+	0x8c, 0x29, 0xdb, 0xbc, 0x78, 0x3d, 0x89, 0x27, 0x2b, 0x61, 0xf4, 0xee,
+	0x53, 0xb2, 0xe9, 0x2a, 0x18, 0xce, 0x4a, 0x25, 0x9b, 0xd2, 0x20, 0x79,
+	0xa3, 0x36, 0x1e, 0x35, 0x8d, 0xec, 0x65, 0xbe, 0xac, 0x4e, 0xde, 0x2e,
+	0x06, 0x95, 0x63, 0x04, 0xf1, 0x6c, 0xfe, 0x7d, 0xcc, 0xfb, 0xa4, 0x86,
+	0x49, 0xed, 0xe4, 0xc0, 0x27, 0xa4, 0x86, 0x05, 0x48, 0x44, 0x15, 0x7b,
+	0xf2, 0x9e, 0xd3, 0x8d, 0x10, 0xf0, 0xb7, 0xf9, 0x70, 0xd1, 0x1c, 0xb6,
+	0xea, 0xb1, 0x16, 0xe7, 0x5b, 0xb9, 0x07, 0xcb, 0x54, 0x44, 0x66, 0x96,
+	0x8e, 0x15, 0xe1, 0x58, 0x11, 0x7c, 0x92, 0x13, 0xa2, 0xd2, 0x36, 0xe2,
+	0x0b, 0x30, 0x19, 0x47, 0x04, 0x57, 0x0a, 0x5b, 0xfc, 0xa8, 0x09, 0x43,
+	0x6d, 0x56, 0xb1, 0x3d, 0xaf, 0x29, 0xdd, 0x79, 0xe8, 0x5e, 0xdb, 0x8c,
+	0x1e, 0xc6, 0x51, 0xc6, 0xc3, 0xba, 0x76, 0x4c, 0x55, 0x36, 0x4e, 0x07,
+	0x50, 0x3d, 0xf5, 0x99, 0x78, 0x9f, 0x7a, 0xf8, 0xc6, 0xbd, 0xac, 0x17,
+	0xc9, 0x00, 0xaa, 0xdc, 0xb9, 0x85, 0xf8, 0xb8, 0xad, 0x0e, 0x17, 0x39,
+	0x5f, 0xf4, 0x2f, 0x03, 0xf0, 0x4e, 0x05, 0xe0, 0x9b, 0x52, 0x30, 0xd3,
+	0x1e, 0x80, 0x67, 0x46, 0xfe, 0x56, 0x10, 0x30, 0xa7, 0xb1, 0x5d, 0x6f,
+	0xc0, 0x78, 0x9e, 0x45, 0xda, 0xfc, 0x19, 0x06, 0xdc, 0xef, 0x2a, 0x9e,
+	0xca, 0x6b, 0x08, 0x1d, 0x10, 0xa2, 0xd1, 0x16, 0x22, 0x96, 0xf4, 0x60,
+	0xd6, 0x1c, 0x8e, 0x06, 0xb8, 0x8e, 0x61, 0x4b, 0x6a, 0x8e, 0x0f, 0xea,
+	0x8c, 0x91, 0x39, 0xc7, 0xa8, 0x37, 0x4f, 0xa8, 0x4a, 0xef, 0xf4, 0x1e,
+	0xc1, 0x98, 0xfa, 0x1e, 0xf0, 0x0a, 0x51, 0xd3, 0xd6, 0x34, 0x70, 0x9e,
+	0xda, 0x3c, 0x13, 0x8b, 0xf5, 0x0e, 0x29, 0xc0, 0xfa, 0x39, 0x1f, 0xfc,
+	0x53, 0xff, 0xc5, 0x3a, 0x2b, 0x44, 0xe1, 0x5e, 0x81, 0x77, 0xad, 0x6c,
+	0xbc, 0x02, 0x46, 0xea, 0x24, 0xc2, 0xb8, 0xf4, 0xa2, 0x10, 0xdb, 0xdb,
+	0x43, 0x78, 0xcd, 0x32, 0x76, 0x7d, 0xec, 0x15, 0xb8, 0x98, 0xcc, 0x0e,
+	0xd6, 0x53, 0xb7, 0xae, 0x29, 0x51, 0x54, 0xe5, 0x8d, 0xcc, 0x15, 0x85,
+	0x4b, 0x9f, 0x31, 0xf5, 0x9d, 0x4a, 0x10, 0x55, 0x27, 0x82, 0xe8, 0x98,
+	0xf3, 0xa3, 0x62, 0x2a, 0x08, 0xef, 0xa4, 0x79, 0xfd, 0x41, 0xb8, 0xe3,
+	0x58, 0x27, 0xd1, 0x8c, 0x8b, 0x2f, 0x1b, 0xf3, 0xc7, 0x89, 0x93, 0xed,
+	0x88, 0xe2, 0x37, 0x05, 0x13, 0x17, 0x0b, 0x41, 0xa8, 0x27, 0x74, 0xd4,
+	0xbb, 0xf5, 0x4e, 0x47, 0xb5, 0xe9, 0x61, 0x5e, 0x1c, 0xe5, 0x61, 0xb7,
+	0x9e, 0x74, 0xf1, 0xd3, 0xa3, 0x74, 0xb0, 0xae, 0x6c, 0x98, 0x26, 0x95,
+	0xf9, 0xec, 0x9c, 0x75, 0x43, 0xec, 0x8f, 0xa5, 0x59, 0x47, 0x2a, 0xe0,
+	0xb3, 0xd7, 0xb1, 0x8e, 0xb0, 0x38, 0xb9, 0xba, 0x5f, 0xa1, 0xf8, 0xec,
+	0xef, 0x6a, 0x7e, 0x88, 0x9a, 0x5f, 0xfc, 0x3f, 0x35, 0x5f, 0x85, 0x3a,
+	0xe5, 0xc1, 0x98, 0x19, 0xc0, 0x6f, 0xac, 0xa6, 0x73, 0x8d, 0x08, 0x20,
+	0xd5, 0xa6, 0x23, 0x72, 0xc2, 0xc2, 0x8b, 0xdc, 0x5b, 0xdc, 0x71, 0x6b,
+	0x3d, 0x04, 0x76, 0x92, 0x53, 0x15, 0xd4, 0x86, 0xbb, 0x27, 0x82, 0xd4,
+	0x29, 0x55, 0x59, 0x4f, 0x9d, 0xdf, 0x91, 0xbc, 0x21, 0xd2, 0x31, 0x23,
+	0x1e, 0x57, 0x12, 0xa9, 0xbf, 0x43, 0x49, 0x3b, 0x62, 0xd4, 0xd1, 0x05,
+	0x7d, 0x91, 0x83, 0x5d, 0x2e, 0x07, 0x67, 0x62, 0x25, 0xed, 0x58, 0x51,
+	0x28, 0xf1, 0xef, 0x01, 0xea, 0xe7, 0xf5, 0xb6, 0x92, 0x76, 0xbe, 0x4a,
+	0xff, 0xd3, 0xcb, 0xf1, 0x1e, 0x99, 0x36, 0xb2, 0xbd, 0xcc, 0xcf, 0x25,
+	0x62, 0x63, 0x92, 0x19, 0x9c, 0xaf, 0xa5, 0xa6, 0x36, 0x07, 0x18, 0xe3,
+	0x75, 0x71, 0x9a, 0xde, 0x62, 0x98, 0xfd, 0x46, 0xf3, 0x46, 0x74, 0x98,
+	0x7c, 0x1f, 0x2d, 0x6b, 0xe9, 0x30, 0xfd, 0xc4, 0x28, 0xf3, 0xf4, 0x36,
+	0x9f, 0x9d, 0xcc, 0x1b, 0xe9, 0x2e, 0x57, 0x53, 0xa5, 0xaf, 0x90, 0x31,
+	0x49, 0x6f, 0x11, 0xc1, 0x5b, 0x2d, 0x52, 0x5f, 0x1b, 0xa8, 0xaf, 0x8b,
+	0xba, 0x2a, 0xf1, 0x70, 0x4d, 0x84, 0x5a, 0x42, 0x5e, 0xc9, 0xcb, 0x4b,
+	0x49, 0x21, 0xaa, 0xec, 0x20, 0x2a, 0x27, 0xcc, 0xf4, 0x7a, 0x25, 0x16,
+	0x31, 0x95, 0xbb, 0xd8, 0xce, 0x1c, 0xce, 0x6d, 0xf2, 0xba, 0xde, 0xf6,
+	0x84, 0x10, 0x21, 0x5b, 0x47, 0xcd, 0x84, 0x49, 0xdc, 0xc4, 0xfa, 0x8e,
+	0xb8, 0xcf, 0x75, 0x04, 0xe7, 0x16, 0xc8, 0xe7, 0x08, 0xf9, 0x1c, 0xc6,
+	0x9b, 0xb7, 0x70, 0x9a, 0x5a, 0xeb, 0xe9, 0x27, 0xa7, 0xb3, 0xe1, 0xa1,
+	0x2d, 0xde, 0x6f, 0xf1, 0x71, 0xbf, 0xe4, 0x34, 0xdb, 0xbc, 0x78, 0x21,
+	0x89, 0xcd, 0xc4, 0x47, 0xe6, 0x29, 0x25, 0xeb, 0x90, 0xdb, 0xa9, 0x0a,
+	0x25, 0x4b, 0x17, 0xf5, 0x0d, 0xa7, 0xcf, 0xf0, 0x6d, 0x2f, 0x39, 0xdd,
+	0x17, 0xbe, 0x95, 0xd3, 0x2c, 0xbe, 0xcc, 0xf7, 0x33, 0xf9, 0x83, 0x98,
+	0xf1, 0xf9, 0x11, 0x99, 0xf2, 0x21, 0x30, 0xa5, 0x92, 0x5f, 0x0a, 0xfd,
+	0x41, 0x36, 0x1e, 0x80, 0x91, 0x3e, 0x89, 0x08, 0x12, 0x13, 0x1a, 0xfe,
+	0xaa, 0xc5, 0x87, 0x63, 0x31, 0x23, 0xb3, 0x93, 0x3c, 0x5d, 0x39, 0x37,
+	0xc4, 0x88, 0x8c, 0x68, 0xd4, 0x53, 0xe2, 0xab, 0xaf, 0xd9, 0x0f, 0x6d,
+	0xca, 0xe5, 0xe0, 0x1e, 0x8f, 0x9d, 0x8d, 0x6a, 0x30, 0x76, 0xfd, 0x84,
+	0xb8, 0xb8, 0x30, 0x21, 0x44, 0x67, 0xbb, 0x79, 0xee, 0x23, 0xaf, 0x41,
+	0x2d, 0x54, 0x71, 0x7e, 0xae, 0x34, 0x7e, 0xd5, 0x94, 0x06, 0xff, 0x01,
+	0x77, 0xfc, 0xeb, 0x6f, 0x32, 0x8a, 0xcf, 0xf3, 0x12, 0x9f, 0x42, 0x04,
+	0x6c, 0x33, 0x32, 0x4b, 0x3d, 0xdc, 0x97, 0x34, 0xb8, 0x7f, 0x4d, 0x4e,
+	0x33, 0xbf, 0x7b, 0x92, 0xb1, 0xe8, 0x16, 0xbe, 0x73, 0xa9, 0x58, 0xe2,
+	0x70, 0xbd, 0xb9, 0x15, 0x7f, 0xa3, 0x7b, 0x51, 0x63, 0xfe, 0x10, 0xcf,
+	0xba, 0x1a, 0x45, 0xec, 0x4f, 0x56, 0xa2, 0x91, 0x98, 0x7f, 0x82, 0x98,
+	0xdf, 0x3c, 0x4b, 0xad, 0x99, 0x6a, 0x67, 0x7e, 0x25, 0xdf, 0xbb, 0x94,
+	0xde, 0xd9, 0x1e, 0xd7, 0x57, 0x3d, 0x32, 0xed, 0xc1, 0x9b, 0xd6, 0x5a,
+	0x7a, 0x98, 0xb4, 0xf2, 0xc8, 0xac, 0xc4, 0xfb, 0x3a, 0xe5, 0x41, 0x62,
+	0x3f, 0x7a, 0x87, 0x8a, 0x19, 0x6b, 0xad, 0xe2, 0x77, 0xb1, 0xef, 0x83,
+	0x93, 0x29, 0xe1, 0xde, 0x6b, 0xc7, 0xac, 0x53, 0x4b, 0x70, 0xdf, 0x73,
+	0x1b, 0xaf, 0x23, 0xb5, 0x03, 0x25, 0x7d, 0xd7, 0xbb, 0x98, 0xaf, 0xe7,
+	0xcb, 0xf8, 0x7e, 0x96, 0xed, 0xbe, 0x29, 0x68, 0x95, 0xc4, 0xf0, 0x3a,
+	0x62, 0x7c, 0x92, 0x38, 0x79, 0x78, 0x5a, 0xe0, 0x0d, 0xd6, 0x89, 0x42,
+	0xd2, 0xb0, 0x76, 0x2a, 0x46, 0xba, 0x47, 0x49, 0x64, 0x57, 0x96, 0x6b,
+	0xe4, 0xdd, 0xac, 0x73, 0xb8, 0x43, 0xe0, 0xe7, 0x16, 0xb4, 0x00, 0xb1,
+	0xfd, 0x6f, 0xac, 0x59, 0xff, 0x51, 0xae, 0x91, 0xc9, 0x42, 0x25, 0x42,
+	0x2d, 0xd4, 0x7c, 0x62, 0xb9, 0x9b, 0x58, 0x3e, 0x44, 0x3e, 0x8c, 0xd0,
+	0x13, 0x6c, 0x26, 0x96, 0x57, 0xb4, 0x19, 0xd9, 0x2e, 0xfa, 0x69, 0xcf,
+	0xea, 0x08, 0x71, 0x1a, 0xa7, 0x87, 0x1d, 0x41, 0x07, 0xe7, 0x4a, 0x4f,
+	0x1b, 0x91, 0x0e, 0xe2, 0x5f, 0x65, 0x9f, 0xd7, 0xd8, 0x67, 0xa1, 0x4e,
+	0x7a, 0xed, 0x00, 0x5e, 0x60, 0x1f, 0x33, 0xe9, 0xb8, 0x3a, 0x21, 0xf1,
+	0x3f, 0x86, 0x44, 0x46, 0xe2, 0xdf, 0x59, 0xd6, 0x4a, 0xdf, 0x2f, 0xf1,
+	0x4f, 0x0c, 0xe6, 0x89, 0xc1, 0x12, 0x07, 0x06, 0x24, 0x07, 0x6a, 0xe8,
+	0x2b, 0x4e, 0xd0, 0x57, 0x54, 0xd9, 0x51, 0xe2, 0x5f, 0xf2, 0xa1, 0xe4,
+	0x2d, 0xba, 0xca, 0x1c, 0x58, 0xef, 0xce, 0x27, 0x35, 0x20, 0x88, 0xa6,
+	0x49, 0x43, 0x57, 0x95, 0xff, 0x14, 0x4f, 0x98, 0xe6, 0xfc, 0x76, 0xfa,
+	0x83, 0x2f, 0xdb, 0x62, 0xcc, 0x7b, 0x10, 0xf7, 0x9c, 0x08, 0xa9, 0x12,
+	0xe7, 0xf5, 0x93, 0x41, 0x84, 0x26, 0x25, 0x0f, 0xb2, 0xe3, 0x11, 0x62,
+	0xc4, 0xf2, 0xfc, 0x96, 0xf8, 0x8f, 0x12, 0x17, 0xaa, 0xd2, 0xcd, 0x31,
+	0x6a, 0xa6, 0x74, 0xb4, 0x4e, 0x1a, 0x03, 0x27, 0x70, 0x55, 0xbc, 0x11,
+	0x33, 0x33, 0x7b, 0x99, 0xff, 0x6d, 0xc9, 0x18, 0xf7, 0x4a, 0xc7, 0xdd,
+	0x37, 0xc7, 0x70, 0x39, 0xe1, 0x6c, 0xb1, 0x82, 0x65, 0xaf, 0xad, 0x61,
+	0x4b, 0x1e, 0xd8, 0x96, 0xa7, 0xd9, 0x35, 0x3d, 0xab, 0xfc, 0xb8, 0x86,
+	0xc3, 0x44, 0x7f, 0xbf, 0xee, 0x30, 0xff, 0x01, 0xea, 0x7d, 0xe9, 0x9d,
+	0x92, 0x07, 0xff, 0x79, 0xf9, 0x8c, 0xf9, 0x2b, 0x4f, 0xe9, 0xef, 0xdb,
+	0xde, 0xc5, 0x33, 0xe7, 0x16, 0x62, 0xb0, 0x93, 0x18, 0xec, 0x61, 0x8e,
+	0xb6, 0x5b, 0xe4, 0x36, 0xf3, 0x99, 0x55, 0x03, 0xf4, 0xd4, 0x4d, 0x7d,
+	0xd5, 0xd4, 0xb4, 0x7d, 0xd4, 0xa7, 0x77, 0xcd, 0x4a, 0x7a, 0x70, 0x87,
+	0xda, 0xd9, 0x41, 0xdd, 0xec, 0x52, 0x1e, 0x72, 0xb1, 0x95, 0x26, 0x8e,
+	0x34, 0x25, 0x4d, 0x5f, 0xeb, 0x63, 0xed, 0x38, 0x14, 0x5e, 0xf4, 0xdf,
+	0x32, 0x4e, 0xe9, 0xb9, 0x8d, 0xb8, 0x2c, 0xbf, 0xcf, 0xba, 0x3a, 0xb4,
+	0x16, 0xaa, 0xbd, 0x56, 0x51, 0x6d, 0x79, 0xc6, 0x50, 0xf1, 0x03, 0xea,
+	0xec, 0xc2, 0x26, 0x79, 0xd6, 0xe0, 0xba, 0xd8, 0x16, 0x31, 0x63, 0xd1,
+	0x83, 0xc4, 0xd5, 0xab, 0xdf, 0x39, 0x7b, 0x94, 0xf0, 0x36, 0x9c, 0x57,
+	0x6f, 0xfa, 0x68, 0xa9, 0x0f, 0x6b, 0x6f, 0xe2, 0x4d, 0xc3, 0x33, 0x2d,
+	0x51, 0xe2, 0x51, 0x62, 0x4d, 0x43, 0xe1, 0x95, 0x4a, 0xbc, 0xf1, 0x4a,
+	0x10, 0xaf, 0xbf, 0x22, 0xc4, 0x68, 0x12, 0x3c, 0xe1, 0x08, 0xf1, 0x50,
+	0x72, 0x0d, 0x8e, 0xeb, 0xb1, 0xe8, 0x0b, 0xae, 0x8f, 0x75, 0xe8, 0x63,
+	0x8d, 0x81, 0xb3, 0xb8, 0x21, 0x0a, 0x2e, 0xa7, 0x13, 0xe4, 0x5b, 0x09,
+	0x8b, 0xae, 0xdf, 0xad, 0xd5, 0x70, 0x81, 0xf8, 0x0b, 0x11, 0x7f, 0xbf,
+	0xa3, 0xe6, 0x5e, 0x2d, 0x6b, 0xee, 0xaa, 0x02, 0xf9, 0xd8, 0x16, 0x40,
+	0x8f, 0x5c, 0x0b, 0x71, 0x38, 0x7c, 0x13, 0x87, 0xac, 0xbd, 0xdc, 0xf3,
+	0xb3, 0x96, 0x11, 0xef, 0x24, 0x1e, 0x67, 0x2c, 0xc3, 0xe9, 0xa0, 0x9f,
+	0x1d, 0x76, 0x31, 0x49, 0xed, 0x8d, 0x49, 0x5c, 0x12, 0x87, 0xcc, 0xc9,
+	0x3e, 0xf6, 0x39, 0xcd, 0x3e, 0x63, 0x65, 0x3f, 0xfb, 0x1e, 0x12, 0x69,
+	0xe9, 0x67, 0xa3, 0xc4, 0xe0, 0x3e, 0xd7, 0xcf, 0x4a, 0xff, 0x2a, 0xbd,
+	0xab, 0x8c, 0xb3, 0xdd, 0x8d, 0xb3, 0xfb, 0x26, 0x0e, 0xa9, 0x61, 0xb5,
+	0x12, 0x7f, 0x0f, 0x60, 0xec, 0xa5, 0x1a, 0x84, 0xcc, 0x3b, 0x71, 0x3e,
+	0xf3, 0x80, 0x1a, 0x31, 0xa1, 0xd7, 0xdb, 0x25, 0x3c, 0x6e, 0x2e, 0xa6,
+	0x90, 0xcf, 0xbf, 0x23, 0xf2, 0x61, 0xc3, 0x39, 0xeb, 0x7a, 0xd2, 0x01,
+	0x7a, 0xc4, 0x1b, 0xc2, 0x13, 0x33, 0xce, 0x6d, 0xa1, 0x2f, 0x6b, 0xf2,
+	0x96, 0xfc, 0xdd, 0x9a, 0xc2, 0xfb, 0x02, 0x75, 0xa5, 0x75, 0xaa, 0xf4,
+	0x74, 0x23, 0xe4, 0xdc, 0xa8, 0x59, 0xf2, 0x77, 0xb1, 0xc2, 0xa7, 0xaa,
+	0xd4, 0x73, 0x4f, 0x9b, 0x1c, 0x37, 0x4d, 0x0d, 0x59, 0x1c, 0xfb, 0x1b,
+	0x5d, 0x1e, 0x21, 0x06, 0x87, 0xa5, 0xd7, 0xa2, 0x2f, 0xe1, 0x59, 0x7d,
+	0x89, 0xa6, 0xee, 0xf6, 0xc2, 0x94, 0x6d, 0x8e, 0xf2, 0x10, 0xd7, 0xa0,
+	0x99, 0x83, 0x4a, 0x9a, 0xb5, 0x79, 0x2f, 0xf1, 0xd5, 0xc3, 0x1a, 0x7c,
+	0xd9, 0x6a, 0x26, 0x87, 0x05, 0xeb, 0xd0, 0x0d, 0xb1, 0xcf, 0x5c, 0x3c,
+	0xd3, 0xc9, 0xf3, 0x5c, 0x9c, 0x71, 0x57, 0xb3, 0x76, 0xaf, 0x63, 0xbd,
+	0xe6, 0x69, 0x91, 0x39, 0xfd, 0x32, 0x26, 0x1a, 0x57, 0xb5, 0x19, 0x03,
+	0x1b, 0xbd, 0x01, 0xe4, 0x88, 0xf7, 0x57, 0x59, 0x83, 0xf2, 0xdc, 0xd3,
+	0xc9, 0xa2, 0x91, 0xca, 0x62, 0x04, 0x1b, 0xb9, 0xa7, 0x3c, 0x03, 0x39,
+	0xff, 0x18, 0x2b, 0x9d, 0x91, 0xb7, 0xb3, 0xb6, 0x8d, 0x97, 0xb9, 0x7d,
+	0x05, 0x09, 0x4b, 0x72, 0x7b, 0x9e, 0xb5, 0x6d, 0xdc, 0xe5, 0xb6, 0x91,
+	0x92, 0x7c, 0xae, 0x28, 0xd7, 0xb4, 0x4f, 0x20, 0x39, 0x7c, 0x6b, 0x3d,
+	0x93, 0x78, 0x5e, 0xeb, 0x93, 0xde, 0x36, 0x9f, 0x97, 0x35, 0x49, 0xd6,
+	0xa2, 0xc5, 0xba, 0xa4, 0xc9, 0xfb, 0x84, 0x4c, 0xe3, 0xc4, 0x1e, 0xe1,
+	0x29, 0xdd, 0x49, 0x9c, 0xfb, 0xd0, 0x1b, 0x4c, 0xa5, 0xee, 0x43, 0x26,
+	0x32, 0xa7, 0x61, 0x53, 0xbe, 0xa1, 0x2f, 0x60, 0x83, 0xef, 0x28, 0xb0,
+	0xfe, 0x44, 0x43, 0xe6, 0x96, 0x3b, 0x89, 0x8f, 0x73, 0x9a, 0x16, 0x9a,
+	0x58, 0x2e, 0xdf, 0xc1, 0x67, 0xb9, 0xdb, 0xde, 0x49, 0xa4, 0x7f, 0xdf,
+	0x9d, 0xc4, 0x0b, 0xe4, 0xc7, 0x58, 0xe9, 0x4e, 0xc2, 0xf9, 0x5e, 0x8b,
+	0x17, 0x33, 0x61, 0xec, 0xfe, 0xa8, 0x5d, 0xc5, 0xe5, 0x9c, 0x11, 0x39,
+	0x8e, 0xdd, 0xe8, 0x77, 0xef, 0x1f, 0x90, 0xf5, 0xdb, 0xbb, 0xf0, 0x4f,
+	0xed, 0xf2, 0xfe, 0x21, 0x25, 0xd7, 0x38, 0xce, 0xe5, 0x43, 0xa3, 0xde,
+	0xac, 0x67, 0x2d, 0xd8, 0xb1, 0x46, 0xc1, 0x43, 0xc9, 0x3b, 0x5d, 0x6c,
+	0x8f, 0x17, 0x8d, 0x74, 0x94, 0xcf, 0xee, 0x99, 0x90, 0x35, 0xf2, 0x71,
+	0x9e, 0x17, 0xa1, 0x35, 0xda, 0xbd, 0xaa, 0xc8, 0x37, 0x45, 0xae, 0x28,
+	0x86, 0x73, 0x18, 0xf2, 0x8e, 0x20, 0x71, 0xce, 0xab, 0x18, 0xf3, 0x1f,
+	0x7a, 0x8d, 0x54, 0xbd, 0x8b, 0x99, 0xc7, 0x79, 0x76, 0x93, 0x7f, 0x7b,
+	0xe5, 0xb9, 0x0f, 0x1b, 0x39, 0xe6, 0x07, 0x6b, 0xe4, 0x59, 0xf4, 0x73,
+	0x91, 0x5d, 0x66, 0x38, 0x0b, 0x8a, 0xc6, 0xdc, 0x80, 0xfa, 0x24, 0x35,
+	0xfc, 0x71, 0x6a, 0xb8, 0xf4, 0x2c, 0xbd, 0xf4, 0x2c, 0x4d, 0xf3, 0x71,
+	0xaf, 0x91, 0xb9, 0x4e, 0xbd, 0xe3, 0x98, 0x7d, 0xbd, 0x8a, 0xd1, 0x7b,
+	0x82, 0xfa, 0xbf, 0x53, 0x29, 0x8d, 0xb9, 0xb2, 0x3c, 0xe6, 0xdd, 0x05,
+	0x4d, 0xe9, 0xcc, 0x83, 0xba, 0x83, 0xe8, 0x36, 0x8b, 0xda, 0x51, 0xac,
+	0x24, 0xc7, 0x4c, 0xb9, 0x66, 0xc6, 0xd6, 0xca, 0xd8, 0x14, 0x5c, 0x69,
+	0x91, 0xef, 0xb6, 0xca, 0x38, 0x9c, 0x2a, 0x3b, 0x45, 0xed, 0x7d, 0xc5,
+	0x57, 0xd6, 0x2f, 0xcf, 0x16, 0x6b, 0x19, 0x9c, 0x30, 0x42, 0x3e, 0xb3,
+	0x0e, 0xa3, 0xb4, 0x81, 0x41, 0xb3, 0x19, 0x39, 0xdd, 0x8f, 0x2d, 0xd6,
+	0x17, 0x82, 0x3a, 0xc9, 0xf7, 0x81, 0xa7, 0x5e, 0xe2, 0x19, 0xde, 0xbc,
+	0x86, 0x58, 0xf2, 0x39, 0x1c, 0xd3, 0x77, 0xd1, 0x0f, 0x6e, 0xc5, 0xeb,
+	0xae, 0x9e, 0xd8, 0xc4, 0xb3, 0x42, 0x0c, 0xd9, 0xb2, 0xd6, 0xdd, 0x32,
+	0xb6, 0xbc, 0x93, 0xb8, 0x24, 0xb2, 0xa5, 0x31, 0x9c, 0x6d, 0x56, 0x86,
+	0x71, 0x7d, 0xa3, 0xbb, 0x3b, 0xa8, 0xbb, 0x15, 0xa6, 0xe7, 0xae, 0x4a,
+	0xea, 0xee, 0x56, 0xeb, 0xcf, 0xf1, 0x14, 0x39, 0x5e, 0x65, 0x7e, 0x26,
+	0x9e, 0x0e, 0xcb, 0x31, 0xa9, 0xaf, 0x35, 0x4b, 0xc7, 0xff, 0x90, 0x63,
+	0xca, 0x39, 0x64, 0x3d, 0x3c, 0x2f, 0x0e, 0xd5, 0xca, 0x31, 0x07, 0x95,
+	0x8d, 0xe4, 0xd4, 0x3c, 0x4b, 0xef, 0x0f, 0xc8, 0xa7, 0x05, 0xe6, 0xa7,
+	0xf1, 0x36, 0x7c, 0x6a, 0x24, 0x9f, 0x9e, 0x58, 0xc2, 0xa7, 0x83, 0x79,
+	0xe9, 0xbd, 0x14, 0xb4, 0xb4, 0xfd, 0x29, 0x75, 0x45, 0x08, 0x7f, 0xdb,
+	0x0d, 0x71, 0xc6, 0xf5, 0xbe, 0xd2, 0xef, 0xa6, 0x95, 0xee, 0x59, 0xa9,
+	0x4f, 0xd5, 0x08, 0x92, 0x4f, 0x1b, 0xc8, 0xa7, 0x7e, 0xf2, 0xe9, 0x69,
+	0x53, 0x34, 0xee, 0x48, 0x1a, 0xa9, 0x79, 0xfa, 0x9a, 0x75, 0xe4, 0xd4,
+	0x3b, 0xe4, 0xd4, 0x48, 0xb1, 0xa4, 0x53, 0xfb, 0xb8, 0xee, 0xfb, 0xa9,
+	0x53, 0xeb, 0x8a, 0x52, 0xdb, 0x1c, 0xe2, 0x3f, 0x80, 0xcf, 0xc9, 0xa9,
+	0xd9, 0xa4, 0xab, 0x53, 0xd6, 0xef, 0x90, 0xd8, 0x75, 0x5a, 0xf2, 0x89,
+	0x3a, 0x95, 0x2f, 0x36, 0x59, 0xa7, 0xb9, 0xa6, 0xf1, 0xbc, 0x71, 0xbd,
+	0x87, 0x9c, 0xf2, 0xb5, 0x1b, 0xe7, 0x2e, 0x13, 0xbb, 0x81, 0x18, 0xf4,
+	0x88, 0x2d, 0xd7, 0xc4, 0x1a, 0xcb, 0x3a, 0x79, 0x90, 0xf8, 0xef, 0xa1,
+	0x66, 0xf4, 0x16, 0x6d, 0xec, 0x2d, 0x2e, 0xdd, 0x53, 0xd6, 0xa1, 0xdb,
+	0xee, 0xcb, 0xb8, 0xff, 0xf6, 0xed, 0xac, 0x57, 0xb7, 0x6d, 0x97, 0x7c,
+	0x5d, 0xe6, 0x97, 0x7c, 0x1d, 0xce, 0xbf, 0xa6, 0xde, 0xfe, 0x1d, 0x79,
+	0xa7, 0x26, 0xc4, 0x51, 0x4b, 0xde, 0x49, 0x48, 0xdf, 0xa3, 0x60, 0xc8,
+	0x92, 0xf7, 0x6a, 0x1d, 0x51, 0x15, 0x46, 0xe4, 0xfb, 0xf8, 0x4a, 0x64,
+	0xc3, 0x4e, 0xdc, 0xe7, 0xd6, 0x48, 0x43, 0xef, 0x63, 0xad, 0x9b, 0x2f,
+	0x9f, 0xfd, 0x66, 0x78, 0x3e, 0x7b, 0x87, 0x75, 0xea, 0x28, 0xcf, 0x79,
+	0x43, 0x85, 0xaf, 0xc4, 0x7c, 0x58, 0xc5, 0x88, 0x79, 0xf3, 0x8e, 0xd2,
+	0xd5, 0xb1, 0xc3, 0x7c, 0x36, 0x56, 0x58, 0xac, 0x51, 0xd4, 0x4c, 0x53,
+	0x88, 0xad, 0xe6, 0x7f, 0x8b, 0x2d, 0xdf, 0x7a, 0x57, 0x88, 0x49, 0xc6,
+	0x70, 0xc1, 0xc2, 0x6e, 0x1f, 0x62, 0x7d, 0xd7, 0x59, 0xd7, 0x3f, 0x58,
+	0x63, 0x64, 0x0a, 0x4a, 0xa2, 0x77, 0x83, 0x22, 0xbd, 0x9e, 0xa7, 0xab,
+	0x82, 0xef, 0xb4, 0xd0, 0x1b, 0x5d, 0x61, 0x06, 0xfd, 0xfc, 0x7e, 0xc6,
+	0x32, 0x22, 0x47, 0xf8, 0x77, 0x4b, 0x4a, 0x8e, 0x21, 0x44, 0x87, 0x25,
+	0xef, 0xbb, 0x46, 0xd4, 0xdc, 0x44, 0x56, 0x54, 0x99, 0x17, 0xa8, 0x4d,
+	0x46, 0x66, 0x44, 0x91, 0x3e, 0x3b, 0x0a, 0x57, 0x67, 0xf9, 0x4c, 0x9b,
+	0x88, 0xe0, 0xef, 0x5d, 0xff, 0x1c, 0xa5, 0x66, 0x35, 0xe0, 0x1f, 0x5c,
+	0xdd, 0x52, 0xb1, 0xed, 0x25, 0x23, 0xa5, 0x2a, 0x7b, 0x70, 0xc9, 0x32,
+	0xf4, 0x9f, 0x32, 0x6e, 0x6a, 0xcd, 0x8b, 0x9d, 0x3c, 0x3f, 0x71, 0x8e,
+	0x6c, 0x9f, 0xb7, 0x56, 0xd1, 0x58, 0x3b, 0x7e, 0xdc, 0x22, 0x6b, 0xf7,
+	0x2e, 0xf4, 0x34, 0xef, 0xe4, 0x47, 0x45, 0xdd, 0x94, 0xaa, 0x6c, 0xa2,
+	0x27, 0x09, 0x4d, 0x85, 0xb0, 0x7d, 0xb5, 0x10, 0xab, 0x56, 0x3b, 0xf8,
+	0x3c, 0xd9, 0x14, 0x3f, 0xcb, 0x1a, 0x74, 0xa8, 0xd6, 0x48, 0x03, 0xbf,
+	0xc0, 0x66, 0x7a, 0xd9, 0x54, 0x5b, 0x0e, 0xb8, 0x53, 0xae, 0xf1, 0x17,
+	0xe8, 0x94, 0x1e, 0xd8, 0x0a, 0x49, 0xbf, 0xe5, 0xe2, 0xb7, 0x74, 0xaf,
+	0xc4, 0xd4, 0x1d, 0xc8, 0x8a, 0x4a, 0xd3, 0xe8, 0x9b, 0x65, 0xbd, 0xfd,
+	0x20, 0xb6, 0x5c, 0x7f, 0x78, 0x56, 0x7a, 0x60, 0x33, 0xba, 0x5e, 0x11,
+	0xcc, 0xc5, 0xf3, 0xcc, 0x45, 0xcc, 0x09, 0xd2, 0x32, 0xf0, 0xac, 0xe5,
+	0x84, 0x94, 0x41, 0xe5, 0x51, 0xf2, 0xa1, 0xcf, 0x5f, 0x49, 0x0f, 0xe1,
+	0xd0, 0x3f, 0x78, 0x50, 0x7d, 0x40, 0x7a, 0x8a, 0x00, 0xb5, 0xa6, 0xa9,
+	0x37, 0xc8, 0xfc, 0xec, 0x48, 0x4a, 0xff, 0x41, 0xac, 0x1f, 0xb8, 0x21,
+	0x3a, 0xe9, 0x71, 0x3b, 0xcb, 0x1e, 0xf7, 0x89, 0xe9, 0x34, 0x3d, 0xb0,
+	0xa6, 0xc8, 0x3b, 0xb6, 0x54, 0x1b, 0x0f, 0xa4, 0x8f, 0x4a, 0x1f, 0x22,
+	0xd7, 0xa0, 0xe3, 0x6a, 0x52, 0x62, 0x57, 0xc7, 0x70, 0xbb, 0x11, 0xc9,
+	0x42, 0xde, 0xe9, 0xdc, 0xea, 0x2f, 0xa0, 0xa7, 0xbf, 0xe3, 0x39, 0xa0,
+	0x6f, 0x62, 0x2c, 0x86, 0x5f, 0x88, 0xba, 0xa4, 0x17, 0x7d, 0xee, 0x59,
+	0x2e, 0xa2, 0xa7, 0xc9, 0xfb, 0x73, 0xf4, 0x09, 0x5e, 0x9e, 0x99, 0xf7,
+	0x10, 0x4b, 0x5f, 0xb6, 0x0c, 0xbd, 0x5a, 0x8f, 0xec, 0x78, 0x1d, 0xcf,
+	0xa8, 0xf7, 0x53, 0x57, 0x2f, 0xe4, 0x1e, 0x65, 0x3d, 0xf7, 0xb4, 0x47,
+	0x78, 0x06, 0x68, 0x9c, 0xca, 0x8a, 0x7a, 0xfa, 0x41, 0x9e, 0x97, 0x51,
+	0xdb, 0x16, 0xa7, 0xdf, 0x5e, 0xdc, 0x2b, 0x0f, 0x7e, 0x68, 0x99, 0x70,
+	0xdc, 0xdf, 0x41, 0xbd, 0x7b, 0x9a, 0xe7, 0x68, 0x73, 0xb9, 0xde, 0x51,
+	0x8a, 0x4b, 0xad, 0xb0, 0x2d, 0xb4, 0xdc, 0x0b, 0xfd, 0xc1, 0xdb, 0xc4,
+	0xb4, 0x4e, 0x7a, 0x1f, 0x5f, 0xa9, 0xdf, 0x9f, 0x4d, 0x37, 0xe8, 0x8f,
+	0xb0, 0xde, 0xcd, 0x13, 0x2b, 0x4f, 0xac, 0xb6, 0x64, 0x2c, 0xf3, 0x32,
+	0x16, 0xfa, 0x4b, 0xe7, 0x7e, 0x0f, 0x7d, 0x49, 0x12, 0x08, 0xcd, 0xfd,
+	0x35, 0x79, 0xe5, 0x69, 0x0d, 0x21, 0xbb, 0x8b, 0x31, 0xbe, 0xfa, 0xaf,
+	0xdc, 0x9a, 0xfe, 0x49, 0xf4, 0x7b, 0xd8, 0x67, 0xc2, 0x02, 0x9e, 0x39,
+	0x01, 0x3c, 0x3d, 0x19, 0xa3, 0x2f, 0xa7, 0x8f, 0x3c, 0xa1, 0xe1, 0xfb,
+	0xd3, 0x95, 0xf8, 0xd1, 0x74, 0x10, 0x3b, 0xa6, 0xdd, 0xbb, 0xae, 0x0d,
+	0x75, 0x7c, 0xaf, 0x83, 0x67, 0xbb, 0x59, 0x6b, 0x35, 0x3e, 0xa2, 0x87,
+	0x5a, 0xa1, 0x78, 0x10, 0x39, 0x00, 0x5d, 0x27, 0x6e, 0x6a, 0x5b, 0x7e,
+	0x44, 0x2e, 0x0b, 0x61, 0xae, 0x96, 0x3a, 0xf9, 0xbc, 0xfb, 0x7d, 0x84,
+	0xfe, 0x31, 0x23, 0x31, 0x98, 0x27, 0x06, 0xf3, 0xc4, 0xe4, 0x4d, 0x4f,
+	0x2d, 0xb1, 0x1c, 0xa7, 0x8f, 0x7e, 0x4e, 0x94, 0xb0, 0xf1, 0xb5, 0x38,
+	0x6a, 0x9e, 0x24, 0x7f, 0x55, 0x6a, 0x28, 0xf0, 0xcf, 0xb9, 0x88, 0xbe,
+	0xa9, 0x28, 0xf3, 0xff, 0xb7, 0xe5, 0xfc, 0x9f, 0xf1, 0x97, 0xf4, 0xc2,
+	0x70, 0x66, 0xd1, 0x80, 0xc9, 0x7c, 0x83, 0xbe, 0x21, 0x3f, 0x34, 0xa8,
+	0x21, 0x1b, 0x0d, 0xc1, 0x18, 0x98, 0x84, 0xa7, 0x35, 0x08, 0xb9, 0x76,
+	0xa0, 0xe0, 0xae, 0x51, 0x88, 0x31, 0xea, 0x9b, 0xcc, 0xc1, 0xbf, 0xe7,
+	0xd0, 0xea, 0x61, 0x3e, 0x1c, 0xc8, 0xb3, 0x35, 0xf0, 0x69, 0x41, 0xde,
+	0x7d, 0xc6, 0xd2, 0xdd, 0xf8, 0xc2, 0x1d, 0xf3, 0x93, 0x42, 0x0a, 0xfb,
+	0xf3, 0x1f, 0x88, 0xfd, 0xe1, 0x92, 0xc6, 0xa7, 0x79, 0x3e, 0x0a, 0x1d,
+	0x28, 0x7b, 0x21, 0x72, 0xb8, 0x9a, 0xeb, 0xbd, 0x9a, 0x74, 0xbd, 0x3f,
+	0x6b, 0xe4, 0x80, 0x7a, 0xd4, 0x64, 0xb1, 0xab, 0xb9, 0x21, 0xc6, 0x62,
+	0x89, 0x40, 0x29, 0xa6, 0x84, 0x7e, 0x04, 0x15, 0xc4, 0xae, 0x3c, 0x23,
+	0x49, 0xfd, 0x90, 0xbf, 0x79, 0x3e, 0x51, 0x9d, 0x88, 0x97, 0xeb, 0x72,
+	0x1e, 0x93, 0x6d, 0x81, 0xb2, 0x5f, 0x5d, 0xf4, 0x22, 0x1d, 0x7c, 0x26,
+	0xbd, 0xc8, 0x57, 0xa2, 0x2f, 0xdc, 0x71, 0x53, 0x73, 0xb2, 0x7c, 0x63,
+	0x34, 0x2f, 0xef, 0xb4, 0x5a, 0xe8, 0x88, 0x15, 0x9c, 0x62, 0xe4, 0x47,
+	0x5a, 0x63, 0xfa, 0x30, 0xc7, 0x73, 0x74, 0x9d, 0x5c, 0xde, 0x43, 0xbf,
+	0xcc, 0x77, 0x8a, 0x2d, 0xec, 0x23, 0xb5, 0xec, 0x2f, 0xb8, 0xd6, 0x2f,
+	0x9a, 0x25, 0xb6, 0x87, 0xf3, 0x6f, 0x79, 0x54, 0x53, 0xae, 0x33, 0x91,
+	0x1a, 0x66, 0x3c, 0x0b, 0xba, 0xf4, 0xd6, 0x0e, 0xb5, 0x2d, 0xe1, 0xf6,
+	0xcf, 0xaa, 0x32, 0x0e, 0x37, 0x1e, 0xb6, 0x49, 0xcd, 0x32, 0x32, 0xa7,
+	0x90, 0x70, 0xfa, 0xa5, 0x39, 0x58, 0x26, 0x63, 0x68, 0x8a, 0xf4, 0x33,
+	0x9e, 0x43, 0x61, 0x57, 0x0f, 0xf9, 0x8c, 0xf3, 0xe5, 0x3d, 0x1b, 0x2a,
+	0x21, 0xb0, 0x22, 0xe9, 0x9e, 0xf9, 0xcb, 0xff, 0x5f, 0x43, 0xa5, 0x0f,
+	0x91, 0x58, 0xfc, 0x5f, 0x69, 0xd7, 0x8a, 0xc0, 0xa8, 0x1a, 0x00, 0x00,
+	0x00 };
 
 static const u32 bnx2_TPAT_b06FwData[(0x0/4) + 1] = { 0x0 };
 static const u32 bnx2_TPAT_b06FwRodata[(0x0/4) + 1] = { 0x0 };
 
 static struct fw_info bnx2_tpat_fw_06 = {
-	/* Firmware version: 4.0.5 */
+	/* Firmware version: 4.4.22 */
 	.ver_major			= 0x4,
-	.ver_minor			= 0x0,
-	.ver_fix			= 0x5,
+	.ver_minor			= 0x4,
+	.ver_fix			= 0x16,
 
-	.start_addr			= 0x08000888,
+	.start_addr			= 0x08000488,
 
-	.text_addr			= 0x08000800,
-	.text_len			= 0x1a90,
+	.text_addr			= 0x08000400,
+	.text_len			= 0x1aa4,
 	.text_index			= 0x0,
 	.gz_text			= bnx2_TPAT_b06FwText,
 	.gz_text_len			= sizeof(bnx2_TPAT_b06FwText),
@@ -3686,11 +3639,11 @@
 	.data_index			= 0x0,
 	.data				= bnx2_TPAT_b06FwData,
 
-	.sbss_addr			= 0x080022c0,
+	.sbss_addr			= 0x08001ec0,
 	.sbss_len			= 0x44,
 	.sbss_index			= 0x0,
 
-	.bss_addr			= 0x08002304,
+	.bss_addr			= 0x08001f04,
 	.bss_len			= 0x450,
 	.bss_index			= 0x0,
 
@@ -3717,862 +3670,862 @@
 };
 
 static u8 bnx2_TXP_b06FwText[] = {
-	0xad, 0x7b, 0x7f, 0x70, 0x9b, 0x75, 0x7a, 0xe7, 0xe7, 0xd5, 0x0f, 0x5b,
-	0xb2, 0x65, 0x59, 0x0e, 0x4a, 0x90, 0x77, 0xbd, 0x8d, 0x5e, 0xf4, 0xca,
-	0x16, 0xd8, 0x49, 0x5e, 0x25, 0xce, 0xc6, 0x59, 0xab, 0x44, 0x75, 0x1c,
-	0xdb, 0x71, 0x1c, 0x30, 0xc1, 0xdd, 0x3a, 0x3d, 0xae, 0xf1, 0x25, 0x26,
-	0x31, 0x10, 0xc0, 0xe9, 0xa6, 0x7b, 0x62, 0x8f, 0xd6, 0xc2, 0x76, 0x82,
-	0x43, 0x64, 0xbf, 0xce, 0x2a, 0x59, 0x87, 0x4e, 0x67, 0xd6, 0x60, 0x07,
-	0x07, 0x56, 0x8e, 0x60, 0xdb, 0x6b, 0xbb, 0x73, 0xbb, 0x83, 0x8e, 0x40,
-	0xf0, 0x72, 0x01, 0xb6, 0xfd, 0xa3, 0x47, 0x6f, 0xee, 0xda, 0xcc, 0x02,
-	0x59, 0xa0, 0x4b, 0xa0, 0x3b, 0x7b, 0x53, 0x67, 0x0b, 0xbc, 0xf7, 0x79,
-	0xde, 0x57, 0x4a, 0xb2, 0x94, 0x4e, 0x67, 0x3a, 0xe7, 0x19, 0x8f, 0xac,
-	0xf7, 0xc7, 0xf3, 0x7d, 0x7e, 0x3f, 0x9f, 0xe7, 0xf9, 0x7e, 0x5d, 0x0f,
-	0x54, 0xa0, 0xf8, 0x53, 0xc5, 0xdf, 0xe6, 0xe1, 0xd4, 0xe1, 0x8d, 0x6b,
-	0xf5, 0xb5, 0xd6, 0x05, 0x37, 0x5c, 0x72, 0xf3, 0xab, 0x0a, 0x30, 0xf0,
-	0x01, 0xfe, 0x5d, 0x3f, 0x5f, 0xf9, 0xf7, 0xbd, 0x66, 0xfd, 0x38, 0x81,
-	0x40, 0x89, 0x2f, 0xf9, 0x85, 0xc7, 0x91, 0x40, 0x6b, 0x9b, 0x06, 0x8f,
-	0x33, 0xf1, 0x67, 0x89, 0x7d, 0x1a, 0x90, 0xcc, 0x35, 0x86, 0xb7, 0xe2,
-	0x53, 0x33, 0x1d, 0x74, 0x41, 0xae, 0x7f, 0x25, 0xf1, 0xc9, 0xc8, 0x8f,
-	0x36, 0xa9, 0x1f, 0xcf, 0x3a, 0xe1, 0x09, 0x24, 0x4e, 0x23, 0x50, 0x0f,
-	0x4f, 0x1d, 0xdf, 0xf9, 0x93, 0x86, 0x6a, 0x27, 0xfc, 0x25, 0x5a, 0x2d,
-	0x18, 0x33, 0x90, 0xf6, 0x24, 0x86, 0x51, 0xbe, 0x11, 0x78, 0x37, 0x13,
-	0xd5, 0xc7, 0x80, 0x69, 0x47, 0x22, 0x1a, 0x7e, 0x09, 0x3a, 0x8e, 0xe4,
-	0xc3, 0x68, 0xe7, 0xef, 0x76, 0xe3, 0x33, 0x33, 0xec, 0x46, 0xda, 0xc9,
-	0xe7, 0xf6, 0x36, 0x03, 0xdb, 0x32, 0x3a, 0x8e, 0x1a, 0xf0, 0xd4, 0x26,
-	0x1e, 0xc5, 0x66, 0x7e, 0xfa, 0x13, 0x29, 0xbc, 0x31, 0x19, 0x09, 0x3f,
-	0x03, 0xb5, 0x5f, 0x73, 0xaa, 0x29, 0xa0, 0x71, 0x68, 0x50, 0x51, 0x07,
-	0xde, 0x54, 0xd4, 0xde, 0x49, 0x05, 0x1e, 0x85, 0xcf, 0x35, 0xe6, 0xe4,
-	0x33, 0x85, 0xdb, 0x72, 0x1e, 0x5c, 0x72, 0xca, 0xfa, 0xbf, 0x49, 0x7d,
-	0x2b, 0x70, 0x69, 0x2d, 0x18, 0x27, 0x0f, 0xee, 0x84, 0x82, 0xa7, 0x9b,
-	0xa3, 0xa1, 0x51, 0xc8, 0xfd, 0x30, 0xb6, 0xe6, 0xe5, 0x53, 0xa5, 0xd4,
-	0xa6, 0x39, 0xae, 0x9b, 0xe6, 0x19, 0xbd, 0x1c, 0xe9, 0x80, 0x1a, 0x02,
-	0x14, 0x8c, 0xea, 0x0e, 0x24, 0x03, 0x6d, 0x61, 0x17, 0xd4, 0xd0, 0xbd,
-	0xf8, 0x67, 0xca, 0x9c, 0x8c, 0xb9, 0x61, 0x3f, 0x3f, 0x80, 0x72, 0x14,
-	0x02, 0xb6, 0xd6, 0x9e, 0xce, 0x98, 0xe6, 0x05, 0xcd, 0x85, 0x33, 0xd4,
-	0xcf, 0x68, 0xee, 0x9f, 0xcd, 0x02, 0x75, 0x33, 0xae, 0x95, 0xd6, 0xf7,
-	0x60, 0x36, 0x60, 0x9a, 0x73, 0xbc, 0x77, 0x34, 0x57, 0xd2, 0xb3, 0x69,
-	0x3a, 0x34, 0xd3, 0xdc, 0xa7, 0xfd, 0xca, 0xdc, 0xfb, 0x6b, 0xcf, 0x9a,
-	0xe6, 0x13, 0xfa, 0x4d, 0x38, 0x9b, 0x6d, 0x57, 0xba, 0x17, 0x56, 0xf9,
-	0xb7, 0xcf, 0x98, 0xb8, 0xa0, 0x23, 0xe0, 0x48, 0x74, 0x28, 0xdb, 0x17,
-	0xba, 0x94, 0x6d, 0xf9, 0x5d, 0x4a, 0xc7, 0xdc, 0xef, 0x2a, 0x5d, 0x0b,
-	0x03, 0x4a, 0x67, 0x3e, 0x84, 0x79, 0x23, 0x88, 0x39, 0xa3, 0x5f, 0x69,
-	0x5f, 0xe8, 0x53, 0x6c, 0x39, 0x52, 0x4a, 0x5b, 0xbe, 0x44, 0xeb, 0xba,
-	0x1e, 0xb7, 0x67, 0x12, 0x98, 0x30, 0xca, 0xb9, 0xce, 0xb2, 0xf9, 0xa3,
-	0x86, 0x65, 0xca, 0xa9, 0xe3, 0x58, 0xfe, 0x09, 0xec, 0x9c, 0x31, 0xcd,
-	0x5c, 0x1c, 0xc8, 0xe5, 0x81, 0xef, 0x19, 0x91, 0xde, 0x21, 0xc5, 0x34,
-	0x3b, 0xa3, 0xe6, 0xea, 0xcb, 0x7a, 0x63, 0xec, 0x65, 0xfc, 0x93, 0x39,
-	0x1b, 0x44, 0xda, 0x47, 0x1a, 0xc7, 0x69, 0xb3, 0xfb, 0x27, 0xe1, 0x29,
-	0x4f, 0x8c, 0xe3, 0x67, 0x19, 0x78, 0xca, 0x12, 0x69, 0x5c, 0xc8, 0x8c,
-	0x06, 0x3c, 0x88, 0x84, 0xb6, 0x2b, 0xe9, 0x94, 0x03, 0xea, 0xf0, 0xdb,
-	0x50, 0xc3, 0xb4, 0xc7, 0xd2, 0x79, 0x45, 0x2d, 0xbc, 0x0c, 0x35, 0xf9,
-	0x2b, 0x45, 0xed, 0xaa, 0x75, 0x22, 0xe9, 0x88, 0x7a, 0xf0, 0xa3, 0x06,
-	0xb1, 0xc9, 0x38, 0xd6, 0x5a, 0xb6, 0x49, 0xe3, 0xd6, 0x6b, 0xb6, 0x49,
-	0x60, 0x94, 0x7c, 0x1d, 0x25, 0x5f, 0xaf, 0xe8, 0x6a, 0xe8, 0x69, 0x98,
-	0xab, 0x07, 0x75, 0xb9, 0x97, 0xc0, 0x78, 0xde, 0x0c, 0xfb, 0x13, 0x97,
-	0xc8, 0x2f, 0xd2, 0x5f, 0x4a, 0x78, 0xd2, 0xd5, 0x89, 0x4f, 0xcd, 0xd7,
-	0x37, 0x86, 0xf0, 0x62, 0x3e, 0x88, 0x17, 0xf2, 0x01, 0x3c, 0x9f, 0x6f,
-	0x87, 0x91, 0x87, 0x7f, 0x67, 0xfe, 0x8b, 0xfc, 0xd8, 0x84, 0x8f, 0xcf,
-	0x93, 0x6f, 0xff, 0x8e, 0xbc, 0x6b, 0xa0, 0x2c, 0x81, 0xde, 0x1f, 0x67,
-	0x46, 0xcc, 0x0a, 0x0d, 0x03, 0x35, 0x09, 0x2d, 0x79, 0x9b, 0xe2, 0x6b,
-	0xa1, 0x1f, 0xf6, 0xbe, 0x9a, 0x6b, 0x71, 0x69, 0x53, 0x5e, 0xb8, 0xa9,
-	0xff, 0x6d, 0x79, 0xd3, 0x1c, 0xd3, 0x0f, 0xad, 0xdb, 0xdb, 0xf2, 0xa7,
-	0x85, 0x5e, 0xad, 0x07, 0xe9, 0xfc, 0x20, 0xe0, 0x4f, 0xf0, 0x93, 0xa1,
-	0xb8, 0xab, 0xa9, 0x3d, 0x7c, 0xee, 0x41, 0x97, 0xed, 0xcf, 0xe4, 0x81,
-	0x7a, 0x7f, 0xc1, 0x20, 0x0f, 0xc6, 0xb4, 0x1f, 0x15, 0x61, 0xca, 0xf7,
-	0x13, 0xf2, 0x19, 0xc3, 0xf7, 0xf3, 0x1a, 0x79, 0x6b, 0x22, 0x8f, 0x61,
-	0xf2, 0xe7, 0xc1, 0xde, 0xac, 0x3a, 0x9d, 0x86, 0x3a, 0x31, 0x8b, 0x35,
-	0x48, 0x06, 0x03, 0xf4, 0xc1, 0x3f, 0x86, 0x4d, 0xa3, 0x07, 0x53, 0x06,
-	0xd6, 0x07, 0x12, 0xb4, 0x6f, 0x1c, 0x8f, 0x96, 0x21, 0x3a, 0xf0, 0xb1,
-	0xa2, 0xe0, 0xf5, 0x68, 0x0f, 0x26, 0x29, 0x4f, 0x4f, 0xce, 0x8b, 0x07,
-	0xb2, 0x15, 0xb8, 0x2f, 0x6b, 0xe2, 0xfe, 0x38, 0x12, 0x15, 0x94, 0x27,
-	0x16, 0x8f, 0x86, 0xdf, 0x83, 0x0b, 0xed, 0xb9, 0x1e, 0xc6, 0xd2, 0x56,
-	0x24, 0xcb, 0x3c, 0xd8, 0x9a, 0xf3, 0x31, 0x1e, 0x93, 0x38, 0x3d, 0xe3,
-	0x81, 0x7b, 0x83, 0x03, 0xb3, 0xc1, 0x32, 0xc4, 0xea, 0x1d, 0xfc, 0x0d,
-	0xfa, 0xdb, 0x66, 0xea, 0xfc, 0xdb, 0x0c, 0x17, 0x0e, 0x18, 0x0e, 0x8c,
-	0x64, 0x4d, 0xb3, 0x5d, 0x37, 0x71, 0x75, 0x43, 0x00, 0x3f, 0xa0, 0xfe,
-	0x0e, 0x19, 0x21, 0x9c, 0xcd, 0x3f, 0x4e, 0x5e, 0x82, 0x36, 0xbf, 0x06,
-	0x79, 0x37, 0xc8, 0xbb, 0x41, 0xbe, 0x0d, 0xe1, 0xf3, 0x3c, 0x63, 0x46,
-	0xa7, 0x5c, 0x5e, 0xf2, 0x50, 0x89, 0x21, 0xf2, 0x11, 0x89, 0x9b, 0x70,
-	0xc4, 0xd5, 0xf4, 0x5e, 0x26, 0xaf, 0xd5, 0xf5, 0xa6, 0xf9, 0xf1, 0x06,
-	0x91, 0x85, 0x36, 0x77, 0xf4, 0x48, 0x8c, 0xfe, 0x56, 0x15, 0xe3, 0xea,
-	0x6f, 0xa9, 0xb7, 0x27, 0xf3, 0x5e, 0xa4, 0xb2, 0x96, 0xdf, 0x1e, 0x2e,
-	0x23, 0xdf, 0xc2, 0x57, 0x5e, 0x8b, 0x32, 0x46, 0xa3, 0xfd, 0x8c, 0x51,
-	0xec, 0x20, 0xcf, 0xf7, 0x1b, 0xd1, 0x96, 0x5d, 0x8a, 0x0b, 0x9d, 0xb9,
-	0xa0, 0xbf, 0xfd, 0x06, 0x3e, 0x29, 0xaf, 0xc4, 0x20, 0x65, 0x0d, 0x90,
-	0xbf, 0x20, 0xf6, 0x91, 0xcf, 0x17, 0x8a, 0x7c, 0xce, 0xe5, 0x65, 0xad,
-	0xcf, 0xf3, 0x5a, 0xe2, 0x13, 0xe9, 0x15, 0x89, 0xa0, 0x82, 0x0a, 0x1f,
-	0x76, 0xe5, 0xde, 0xa2, 0x2d, 0xea, 0xf0, 0xa7, 0xb4, 0xc1, 0x8b, 0x8c,
-	0x91, 0xef, 0x5f, 0xf3, 0x17, 0xb1, 0xc7, 0x63, 0xb4, 0x83, 0x7a, 0x3a,
-	0x0d, 0x1f, 0x06, 0xf2, 0x49, 0x1c, 0x99, 0x41, 0x72, 0x5e, 0x3f, 0xce,
-	0x78, 0x5f, 0x05, 0xa7, 0x56, 0x9e, 0x0c, 0x68, 0x15, 0xd8, 0x37, 0x17,
-	0xc4, 0x70, 0xbe, 0x0d, 0x46, 0x36, 0x88, 0x83, 0xf4, 0xcd, 0x2b, 0xf1,
-	0xe4, 0xfd, 0x7e, 0x08, 0xef, 0x41, 0x3c, 0xc0, 0x77, 0x9e, 0x98, 0x09,
-	0x62, 0x88, 0x3a, 0xda, 0x1e, 0x8f, 0xb6, 0x78, 0x79, 0xed, 0x00, 0xaf,
-	0x1d, 0xa5, 0xfe, 0xcf, 0xeb, 0x93, 0x18, 0xe8, 0x55, 0x63, 0x40, 0x10,
-	0xfb, 0x0d, 0x04, 0xe8, 0xc2, 0x8f, 0x31, 0xbf, 0xc5, 0xce, 0xf3, 0xfb,
-	0xbd, 0xf9, 0x0a, 0xca, 0xe9, 0x47, 0x48, 0xfb, 0xc4, 0x74, 0x37, 0x9b,
-	0xe6, 0x77, 0xf5, 0xe8, 0xd2, 0x4f, 0x9d, 0x2e, 0x3c, 0x92, 0x77, 0x20,
-	0x35, 0x57, 0x81, 0xdf, 0xcf, 0xba, 0x70, 0x57, 0x7d, 0x05, 0x0e, 0xcd,
-	0x25, 0x31, 0x36, 0x53, 0x81, 0xc1, 0x2c, 0x56, 0xef, 0xd7, 0xc7, 0x6a,
-	0xca, 0xa0, 0x2e, 0xb7, 0x23, 0x86, 0xab, 0xb4, 0xc3, 0x23, 0x73, 0x3e,
-	0x7f, 0xff, 0x4c, 0x00, 0xa9, 0x05, 0x2f, 0x9f, 0x77, 0xf0, 0xf9, 0x72,
-	0xe8, 0xeb, 0x23, 0xa9, 0x00, 0x84, 0xc7, 0x4a, 0x3c, 0x34, 0xe7, 0xc5,
-	0x83, 0xd9, 0x00, 0x0e, 0xce, 0x34, 0x63, 0xda, 0x48, 0xe2, 0x18, 0x73,
-	0xc7, 0xf7, 0xe2, 0x6a, 0xef, 0x41, 0x45, 0x4d, 0x6e, 0x53, 0x92, 0x68,
-	0x88, 0xbb, 0x71, 0x89, 0x79, 0xc8, 0x1d, 0x6f, 0x6c, 0x79, 0x9e, 0xb9,
-	0xa1, 0x2c, 0x11, 0xe4, 0x77, 0x75, 0x82, 0x31, 0x9b, 0x74, 0x3b, 0x36,
-	0x00, 0x2b, 0x25, 0x7e, 0x83, 0xfe, 0x6e, 0x23, 0xe0, 0xef, 0xce, 0xd7,
-	0xf9, 0xb7, 0x1b, 0x21, 0xff, 0x76, 0xc6, 0xd7, 0x36, 0xf1, 0x47, 0xc3,
-	0x83, 0xe3, 0xf1, 0x4f, 0xcd, 0x81, 0x1a, 0x2b, 0x9f, 0xf9, 0x77, 0xce,
-	0xa8, 0xe9, 0x59, 0xa8, 0x3a, 0xab, 0x01, 0x26, 0x17, 0x5c, 0xb4, 0x9f,
-	0x82, 0x1a, 0xad, 0x99, 0x79, 0x3c, 0x80, 0x87, 0x98, 0x53, 0xfe, 0x9a,
-	0x39, 0x65, 0x70, 0x2a, 0x12, 0x98, 0x86, 0x97, 0xfa, 0x06, 0xf6, 0x9e,
-	0x0b, 0xd2, 0xe6, 0x5d, 0x78, 0x9c, 0x7c, 0x6d, 0xdf, 0x18, 0xc4, 0x7d,
-	0xf9, 0x80, 0xbf, 0x8b, 0xf6, 0x7b, 0x2f, 0x17, 0xf2, 0x6f, 0xa5, 0x2d,
-	0xdf, 0xce, 0xa9, 0xe1, 0x02, 0xfe, 0xaf, 0xf8, 0x53, 0x0c, 0x0e, 0x60,
-	0xff, 0x94, 0x1b, 0x85, 0xa0, 0xac, 0x45, 0x9d, 0x1b, 0x2f, 0x9a, 0x3e,
-	0x4d, 0x3b, 0x7d, 0x90, 0xba, 0xfe, 0x46, 0xde, 0x87, 0x07, 0x0d, 0x35,
-	0xf6, 0x7d, 0xc5, 0x47, 0x9d, 0x7a, 0xa8, 0x07, 0x26, 0x98, 0x55, 0xf2,
-	0x5c, 0x1c, 0xe1, 0x55, 0x76, 0xae, 0x3d, 0x34, 0x27, 0x7e, 0x42, 0xdb,
-	0x1b, 0xf4, 0x01, 0xfa, 0xcf, 0xf7, 0xaf, 0xc5, 0xaa, 0x1a, 0x48, 0x5b,
-	0xb9, 0x3b, 0x46, 0x7f, 0xb1, 0x75, 0x74, 0x62, 0x46, 0xf4, 0xa0, 0x4e,
-	0xc3, 0x91, 0xc4, 0xba, 0xf5, 0x7f, 0x6d, 0x5e, 0x5a, 0x29, 0xfa, 0x08,
-	0x60, 0x84, 0x3a, 0x3c, 0x6d, 0x98, 0xe6, 0xd5, 0x0d, 0x1f, 0x9a, 0x2d,
-	0x37, 0x8b, 0x5e, 0x44, 0xd6, 0x1f, 0x28, 0x52, 0x47, 0x6a, 0x34, 0xff,
-	0xff, 0x07, 0x5f, 0xf9, 0xa6, 0x39, 0x60, 0xc9, 0x27, 0xfe, 0xe2, 0xa2,
-	0x2f, 0x3e, 0x4e, 0xda, 0x0e, 0x0c, 0x90, 0xde, 0xc3, 0x86, 0xf9, 0x51,
-	0x6d, 0xe2, 0x33, 0xb3, 0x65, 0x93, 0x36, 0xbc, 0xac, 0xfc, 0x4f, 0x5e,
-	0x0f, 0xe2, 0xa1, 0x7c, 0x0b, 0x75, 0xd7, 0x8e, 0x27, 0xa8, 0xc3, 0xa3,
-	0x86, 0xe4, 0xc4, 0x10, 0xfd, 0xb9, 0x8e, 0xfe, 0xed, 0x52, 0xb6, 0x19,
-	0x39, 0x6c, 0x9f, 0x4c, 0xa3, 0x93, 0xfe, 0xbe, 0x94, 0x89, 0xb4, 0x3c,
-	0x0b, 0x35, 0x4d, 0x19, 0xfc, 0x5d, 0xd4, 0x71, 0xbb, 0xa1, 0x76, 0x89,
-	0x4d, 0xdb, 0x99, 0x97, 0x5e, 0xca, 0x84, 0xfc, 0x6d, 0x79, 0xd1, 0x77,
-	0x9d, 0x7f, 0x6b, 0xfe, 0xab, 0xb4, 0xbd, 0x82, 0xcd, 0x6b, 0x3c, 0xcc,
-	0x33, 0x77, 0xc1, 0xb6, 0xab, 0x6d, 0xbb, 0xd7, 0xe3, 0x8d, 0x03, 0x1f,
-	0x32, 0x3f, 0xa5, 0x57, 0xda, 0xd7, 0x52, 0xbc, 0x56, 0xbd, 0x01, 0xfe,
-	0x3b, 0xe9, 0x07, 0x7b, 0xe8, 0x07, 0x57, 0x37, 0x7c, 0x6a, 0x86, 0x6f,
-	0xb2, 0xfd, 0xa0, 0x6d, 0xc6, 0xe5, 0xef, 0xa0, 0x9e, 0xb6, 0xe9, 0x0a,
-	0xe6, 0xf4, 0x0c, 0x06, 0xae, 0x61, 0x87, 0xe4, 0xec, 0x59, 0x3d, 0xc9,
-	0x3c, 0xf2, 0x9b, 0x70, 0xd5, 0x60, 0xf6, 0x59, 0xfd, 0x71, 0x84, 0x6d,
-	0xdf, 0xc1, 0xc1, 0xac, 0x17, 0xe9, 0xbb, 0x02, 0x98, 0x6f, 0x08, 0xe0,
-	0x61, 0xd2, 0xbe, 0x12, 0x6f, 0x1c, 0x7a, 0x83, 0x3a, 0x98, 0xad, 0x91,
-	0x6b, 0x49, 0xfc, 0xa5, 0xfe, 0x28, 0x70, 0x93, 0xbd, 0xf6, 0x82, 0xc4,
-	0xe8, 0x42, 0x33, 0x8e, 0xe6, 0xfb, 0x15, 0x3b, 0x6f, 0xaa, 0x5d, 0x49,
-	0xfc, 0xc4, 0x94, 0x5c, 0xba, 0x60, 0x30, 0xc7, 0x51, 0x1f, 0xe3, 0xf4,
-	0xa3, 0xd1, 0x5c, 0x9d, 0xbf, 0x93, 0x7e, 0xf4, 0x78, 0x4e, 0x64, 0x8a,
-	0xea, 0xba, 0xb3, 0x96, 0xb5, 0x99, 0xfa, 0x31, 0xac, 0x9a, 0x5f, 0x1d,
-	0xd0, 0x8e, 0x61, 0xda, 0xe2, 0x2d, 0xa5, 0xf4, 0x13, 0x63, 0x30, 0x64,
-	0xaa, 0xcb, 0xb5, 0x43, 0x78, 0xdc, 0xba, 0x16, 0xf4, 0xef, 0x9e, 0x49,
-	0x3a, 0x1c, 0x1a, 0x02, 0x95, 0x89, 0x76, 0x65, 0x37, 0xeb, 0x6e, 0xc7,
-	0x4c, 0x87, 0xd2, 0xb1, 0x20, 0x31, 0xd0, 0xa5, 0x6c, 0x67, 0xcd, 0x4d,
-	0xb2, 0xe6, 0x26, 0x59, 0x73, 0x93, 0xe4, 0x23, 0xc9, 0x5a, 0xdb, 0x96,
-	0x4f, 0x29, 0x3b, 0x44, 0xff, 0xf4, 0xaf, 0xe7, 0x0d, 0x1b, 0x47, 0x30,
-	0x07, 0xf9, 0x3b, 0xf3, 0x6b, 0x1d, 0x36, 0xb6, 0x4b, 0x29, 0x45, 0x2c,
-	0xe3, 0xa9, 0xd0, 0x58, 0xcb, 0x8c, 0x94, 0xd2, 0xcd, 0x7a, 0xdb, 0x6f,
-	0xe9, 0x32, 0x32, 0xfc, 0x0e, 0xeb, 0xec, 0xeb, 0xac, 0xb3, 0xb9, 0x38,
-	0xe3, 0x6a, 0xcd, 0x55, 0x73, 0x60, 0xa5, 0x5d, 0x13, 0xc6, 0xc8, 0xef,
-	0x77, 0x69, 0xb3, 0x02, 0x6b, 0x69, 0xbb, 0x53, 0xc1, 0x7e, 0x0d, 0xd5,
-	0xb5, 0xcc, 0xa9, 0x47, 0xf3, 0xac, 0x03, 0x7a, 0xa4, 0xe5, 0x7d, 0x2a,
-	0xf6, 0xa8, 0xe6, 0xc6, 0xd5, 0x9b, 0x08, 0x76, 0xb4, 0x36, 0x1c, 0xcf,
-	0x96, 0x63, 0x28, 0x9e, 0x5c, 0xe1, 0x21, 0x56, 0xe9, 0x6a, 0xc6, 0xa3,
-	0x5c, 0x5a, 0x09, 0x25, 0xa2, 0xf4, 0x1b, 0x24, 0xa7, 0x58, 0x27, 0x26,
-	0x8d, 0xaf, 0x22, 0xc7, 0x7a, 0x3a, 0xaf, 0xbb, 0xf0, 0x7a, 0x6e, 0x2d,
-	0xf3, 0x5c, 0x54, 0xf7, 0x29, 0x15, 0x8c, 0xdf, 0x04, 0x32, 0x86, 0xe4,
-	0x27, 0xd3, 0x9c, 0x17, 0x1e, 0xa2, 0xd1, 0xe4, 0x28, 0x24, 0x67, 0x99,
-	0xab, 0xef, 0x8d, 0x97, 0x61, 0x73, 0xd4, 0x8f, 0xd5, 0xda, 0x80, 0xd2,
-	0x95, 0x8f, 0xea, 0xe7, 0xf1, 0xbb, 0xca, 0x9e, 0x85, 0x04, 0x63, 0xbb,
-	0x9f, 0xba, 0xa9, 0xc0, 0xa5, 0xa0, 0xf0, 0x88, 0x6a, 0xb7, 0xe6, 0xc0,
-	0xbb, 0x77, 0x2b, 0x08, 0x68, 0x49, 0x5c, 0x68, 0x0e, 0xd0, 0xaf, 0xba,
-	0x88, 0x31, 0xc2, 0x70, 0x2e, 0x86, 0xfc, 0x3b, 0x68, 0x8b, 0xca, 0xc5,
-	0x3a, 0xda, 0x87, 0xbe, 0x47, 0x1d, 0xb6, 0x51, 0x87, 0xdd, 0x73, 0x08,
-	0x54, 0x24, 0xfa, 0x94, 0x8e, 0x7c, 0xbb, 0xd2, 0x9e, 0x57, 0xa9, 0x27,
-	0xd1, 0xc9, 0x37, 0x89, 0x95, 0xc4, 0x57, 0x4a, 0xb6, 0x14, 0x7f, 0xbd,
-	0xd1, 0x9e, 0xfd, 0x0e, 0x89, 0xb9, 0xcd, 0x6b, 0x12, 0x8c, 0x47, 0x07,
-	0xf9, 0x12, 0x1e, 0x3c, 0xa8, 0x6e, 0x30, 0x57, 0x5f, 0x89, 0x33, 0x79,
-	0x56, 0x24, 0x30, 0x95, 0xef, 0xa1, 0x5d, 0x36, 0x14, 0xfd, 0x2b, 0xe0,
-	0xdf, 0x36, 0xd3, 0xae, 0x6c, 0x5b, 0x58, 0xe1, 0xef, 0xa5, 0x0d, 0x7b,
-	0x17, 0x42, 0x42, 0x97, 0xeb, 0x8b, 0x6d, 0x93, 0x70, 0x68, 0xff, 0x9a,
-	0x2d, 0xbf, 0x41, 0x5a, 0x62, 0x4f, 0x6f, 0xc9, 0x4f, 0xfd, 0x7b, 0x66,
-	0x92, 0x78, 0x77, 0x83, 0x9b, 0x35, 0xb5, 0x84, 0x29, 0xaa, 0x8a, 0x9f,
-	0xa7, 0x1d, 0xd0, 0x52, 0x4a, 0x97, 0xf8, 0x91, 0xdb, 0x5e, 0xf3, 0xce,
-	0x19, 0xb8, 0x09, 0x15, 0xc2, 0x4e, 0x62, 0xba, 0x0f, 0xe3, 0xd1, 0x81,
-	0x73, 0x4a, 0x8f, 0xd2, 0x93, 0x97, 0x1a, 0x6c, 0xfb, 0x54, 0x1b, 0x7d,
-	0xaa, 0x9d, 0xfc, 0xb4, 0xd3, 0xa7, 0xba, 0xc9, 0x4f, 0xb7, 0xe5, 0x53,
-	0xe2, 0x9b, 0xbf, 0xce, 0xcb, 0xd6, 0xfc, 0x1e, 0x4b, 0x2f, 0x3b, 0xf8,
-	0x6e, 0x17, 0xe5, 0xe8, 0xe2, 0x7b, 0x7b, 0xf8, 0xde, 0x9e, 0x85, 0xff,
-	0x2d, 0xfc, 0x51, 0x16, 0x3b, 0xf6, 0xaf, 0xd7, 0x34, 0xc9, 0x01, 0xaf,
-	0x15, 0x31, 0x05, 0xd2, 0x8e, 0x84, 0xe4, 0x88, 0x61, 0xf4, 0x36, 0xc3,
-	0xb3, 0x22, 0xf1, 0x93, 0xd6, 0x5d, 0xf5, 0xcc, 0x67, 0xcc, 0xa7, 0x9e,
-	0x29, 0x62, 0x69, 0xe6, 0xe8, 0xf9, 0x16, 0x05, 0x63, 0xfa, 0xcd, 0x8c,
-	0x53, 0x1d, 0x13, 0x79, 0xb5, 0x2b, 0xcc, 0x7b, 0x4d, 0x93, 0x82, 0xf1,
-	0x0f, 0xa2, 0x8d, 0xb8, 0x2e, 0x94, 0x18, 0x42, 0xc8, 0x88, 0x84, 0x26,
-	0x14, 0x75, 0x68, 0x2b, 0xd4, 0x25, 0xd6, 0x86, 0xd4, 0x9c, 0xa2, 0x0e,
-	0xd7, 0x3a, 0xd5, 0xe4, 0x9b, 0x16, 0xbe, 0x3e, 0x88, 0x35, 0x16, 0x86,
-	0x1b, 0x42, 0x8c, 0x58, 0x76, 0x07, 0x69, 0x1e, 0xd8, 0xac, 0xe0, 0xb2,
-	0xfe, 0x21, 0xed, 0xa8, 0x26, 0xd3, 0x8a, 0x8e, 0x0c, 0xf3, 0x44, 0x68,
-	0x4a, 0xb0, 0xfa, 0x41, 0x62, 0x75, 0x78, 0x7c, 0x7c, 0x36, 0x33, 0x19,
-	0x49, 0x79, 0x9c, 0x6a, 0x8c, 0x38, 0x3d, 0x49, 0x9a, 0x7a, 0x9e, 0xf8,
-	0x9d, 0x6b, 0x84, 0xf7, 0x17, 0x69, 0x46, 0x8b, 0x34, 0xb5, 0x1c, 0x18,
-	0x37, 0x13, 0xe8, 0x8c, 0xb2, 0x56, 0x30, 0xe7, 0x1d, 0x93, 0x9e, 0x80,
-	0xf4, 0xca, 0xa7, 0x74, 0x7e, 0x4f, 0x29, 0xbb, 0x25, 0xa6, 0xca, 0x6d,
-	0x2b, 0x54, 0x73, 0x8d, 0xaa, 0xc4, 0x61, 0x2c, 0x5a, 0x6b, 0x0c, 0xcb,
-	0x1a, 0xc3, 0x3f, 0x53, 0xd4, 0xd8, 0x39, 0x45, 0x72, 0x75, 0x63, 0xff,
-	0x39, 0xc6, 0xd0, 0x51, 0x45, 0x6d, 0x39, 0x4e, 0xf1, 0xbd, 0x9a, 0xd0,
-	0x3f, 0x5c, 0x5c, 0x67, 0x18, 0x0d, 0x39, 0xc6, 0x67, 0xde, 0xa3, 0x6c,
-	0xcd, 0xb6, 0x61, 0x6c, 0xae, 0x0d, 0xa3, 0x59, 0x05, 0x7b, 0xf4, 0x95,
-	0xb8, 0x74, 0xb3, 0xd5, 0xa7, 0x54, 0xad, 0xd6, 0x6a, 0x31, 0x12, 0x40,
-	0xb5, 0x43, 0xfb, 0x0a, 0xf6, 0x16, 0x31, 0x7e, 0xe7, 0x89, 0x5e, 0xe6,
-	0x7d, 0x13, 0xef, 0x33, 0x96, 0x22, 0x35, 0x48, 0xba, 0x13, 0x2d, 0xc4,
-	0xe3, 0x75, 0x4e, 0x3b, 0xde, 0xff, 0xc9, 0x63, 0xdb, 0x40, 0xf4, 0xff,
-	0xf9, 0x7b, 0x6d, 0x78, 0x32, 0x5b, 0x86, 0x96, 0x0d, 0xb8, 0x2b, 0x84,
-	0x2a, 0x07, 0x6b, 0xdc, 0x5b, 0xbb, 0x94, 0x14, 0xef, 0x59, 0xcf, 0x7a,
-	0xbe, 0x9c, 0xe8, 0x4d, 0xfc, 0x97, 0x06, 0xb9, 0x6e, 0xe5, 0x8d, 0x1b,
-	0xae, 0x0f, 0x7f, 0xc1, 0x75, 0x05, 0xcf, 0x31, 0x91, 0x7d, 0x8f, 0x35,
-	0x25, 0x97, 0x31, 0xe1, 0x4c, 0xb8, 0x30, 0x34, 0x19, 0xc6, 0xc1, 0xc5,
-	0x20, 0x16, 0x33, 0xea, 0xc0, 0x25, 0xf6, 0x0f, 0x7b, 0x9b, 0x35, 0x3c,
-	0xb8, 0x18, 0xc2, 0x42, 0x06, 0xa6, 0x37, 0xa1, 0x15, 0xbc, 0x4a, 0x0c,
-	0x07, 0x16, 0xeb, 0x70, 0x2e, 0xa3, 0x2d, 0x8d, 0x2a, 0xd1, 0x54, 0x2d,
-	0x71, 0xc7, 0xc3, 0x8b, 0x4d, 0x78, 0x68, 0xd1, 0xc3, 0x77, 0x4c, 0x74,
-	0xc7, 0xeb, 0xf8, 0xbc, 0x03, 0xcf, 0x9e, 0x34, 0x4d, 0xc1, 0x5d, 0x43,
-	0x8b, 0xc0, 0xc2, 0x34, 0x6b, 0xd1, 0x19, 0xd6, 0xa5, 0xa7, 0x80, 0x03,
-	0x4f, 0x39, 0x30, 0x37, 0x6d, 0x62, 0xaf, 0x3e, 0x5a, 0xeb, 0xa0, 0xc3,
-	0x0f, 0xb0, 0x6e, 0xb8, 0x59, 0x03, 0xef, 0x0d, 0xd8, 0xf9, 0xfc, 0x12,
-	0xf3, 0xd4, 0xfd, 0x4f, 0xc5, 0xf0, 0x56, 0x26, 0x8d, 0x6e, 0xe2, 0xf3,
-	0x14, 0x79, 0x79, 0x33, 0xc3, 0x3a, 0xb6, 0xa8, 0xe3, 0x8d, 0x8c, 0x87,
-	0xeb, 0x34, 0xe1, 0xe5, 0x8c, 0x3c, 0x23, 0xcf, 0xfa, 0x30, 0x48, 0x5e,
-	0x5e, 0xcf, 0x84, 0xb8, 0x66, 0x10, 0x3f, 0xe6, 0x73, 0xf7, 0x2d, 0x6a,
-	0xac, 0x5b, 0x1e, 0xae, 0x1b, 0xc6, 0xab, 0x19, 0x1f, 0x79, 0x0d, 0xb2,
-	0x56, 0x0d, 0x62, 0x2c, 0xd3, 0xb8, 0xb4, 0x95, 0x89, 0xda, 0xae, 0x35,
-	0x72, 0xed, 0x1d, 0xb3, 0xc7, 0x8a, 0x45, 0x59, 0xa7, 0xb4, 0xee, 0x20,
-	0x46, 0x33, 0x6f, 0x38, 0x4b, 0xfd, 0xf4, 0x73, 0xd3, 0xcb, 0x16, 0xf6,
-	0x7b, 0xd6, 0xe0, 0xdf, 0x73, 0xc0, 0x39, 0x23, 0x6d, 0x56, 0x27, 0x88,
-	0x75, 0x59, 0xa3, 0x7e, 0xba, 0xb1, 0x89, 0xeb, 0x6a, 0x03, 0x2f, 0x29,
-	0xd2, 0xef, 0xb8, 0x10, 0x7e, 0x4a, 0xf4, 0x45, 0xcc, 0xbc, 0x00, 0xfc,
-	0x25, 0xf1, 0x67, 0xc3, 0xa4, 0x2a, 0x7e, 0xdf, 0x4f, 0x5c, 0xd3, 0x5b,
-	0x40, 0x7d, 0xec, 0x41, 0x8c, 0x98, 0x65, 0xc4, 0xe7, 0xd5, 0xc4, 0xb5,
-	0x8b, 0x4d, 0xac, 0x53, 0x1b, 0x4d, 0xf3, 0x6f, 0x9b, 0x61, 0x3a, 0x12,
-	0x9a, 0x5e, 0xeb, 0x2c, 0x7c, 0xa5, 0x0a, 0xda, 0x92, 0x5f, 0xd1, 0x0a,
-	0x3f, 0x45, 0x74, 0xf8, 0x3c, 0x44, 0xaf, 0xc0, 0xda, 0x45, 0x17, 0xd6,
-	0x51, 0x9e, 0x6d, 0x93, 0x5c, 0x9b, 0xf8, 0x24, 0x4a, 0x99, 0x76, 0x4e,
-	0x12, 0x73, 0x69, 0x3e, 0xac, 0xa1, 0x8e, 0x87, 0x4e, 0x99, 0x66, 0x39,
-	0x75, 0xdc, 0x40, 0xfb, 0xec, 0x3f, 0x61, 0xe2, 0x25, 0xfd, 0x25, 0xea,
-	0x54, 0x21, 0x6e, 0x6c, 0xe6, 0x3b, 0x41, 0x3e, 0xef, 0xc1, 0x81, 0x49,
-	0xe9, 0x97, 0xea, 0xf8, 0xcc, 0x45, 0x1c, 0xcf, 0xc4, 0xd0, 0x44, 0xfd,
-	0x85, 0x49, 0xb3, 0x91, 0xef, 0x84, 0x49, 0x2f, 0xbc, 0xf8, 0x35, 0x6c,
-	0x3f, 0xa5, 0x40, 0x8b, 0x8a, 0x0e, 0xbe, 0x86, 0xf6, 0x33, 0x5f, 0x94,
-	0x13, 0x98, 0xa5, 0xa6, 0xd5, 0x89, 0x02, 0xf1, 0x77, 0x55, 0x62, 0x04,
-	0xac, 0xdf, 0x78, 0x73, 0x56, 0xc1, 0xd4, 0x34, 0xfb, 0xbd, 0x8d, 0x30,
-	0x2b, 0x28, 0xd3, 0x1b, 0xb3, 0xbf, 0x81, 0x67, 0x4e, 0x52, 0x0f, 0x4f,
-	0x07, 0xf1, 0xbd, 0x8c, 0x0b, 0xb7, 0x4e, 0x09, 0xa6, 0xd3, 0x62, 0x07,
-	0x15, 0xe9, 0x8f, 0xa4, 0x6f, 0x89, 0x86, 0xdd, 0x8a, 0x03, 0xf5, 0xcf,
-	0xb8, 0xa0, 0x9d, 0x0b, 0xc3, 0x5d, 0xef, 0x81, 0x56, 0xff, 0xfb, 0xcc,
-	0x35, 0x0e, 0x94, 0xb1, 0x97, 0xed, 0xfc, 0x76, 0x8c, 0xd7, 0x82, 0xbc,
-	0x86, 0xdf, 0x28, 0x87, 0x73, 0x95, 0x93, 0x35, 0xbc, 0x4c, 0x23, 0x1e,
-	0x73, 0x99, 0xa6, 0x93, 0xb5, 0x61, 0xf7, 0x77, 0x4c, 0x33, 0xb2, 0x41,
-	0x9e, 0x0f, 0x20, 0x72, 0x4e, 0xe3, 0x73, 0x76, 0xbd, 0xbc, 0x8e, 0xc7,
-	0x9c, 0xf4, 0x23, 0x89, 0x55, 0xd6, 0x7b, 0xab, 0x87, 0xb2, 0x71, 0xfb,
-	0x0b, 0x79, 0xc1, 0x36, 0x61, 0x4b, 0x86, 0xb3, 0xd3, 0x0a, 0x73, 0x76,
-	0x82, 0xcf, 0x6e, 0x81, 0x33, 0xae, 0x4e, 0xa4, 0xe9, 0x07, 0x7b, 0x03,
-	0x2d, 0x78, 0xce, 0x70, 0xa3, 0x52, 0x5b, 0x85, 0x07, 0x7a, 0x03, 0x78,
-	0x8e, 0x7d, 0x01, 0x6d, 0x16, 0x2b, 0x80, 0x8d, 0xb4, 0x9f, 0xf4, 0x1c,
-	0x3f, 0x84, 0xf6, 0x6d, 0x07, 0xf3, 0x9c, 0xd3, 0xca, 0x73, 0x65, 0xf5,
-	0x40, 0x21, 0xe7, 0xc2, 0x05, 0xcd, 0xc6, 0x84, 0x2f, 0x58, 0x35, 0x5b,
-	0x0d, 0x14, 0xae, 0x61, 0x41, 0xb5, 0x25, 0xa9, 0x90, 0x19, 0xbf, 0xe8,
-	0xae, 0xdf, 0x65, 0xfb, 0xd2, 0xdf, 0x38, 0xa5, 0xe7, 0xb8, 0xfe, 0xbd,
-	0x02, 0x8e, 0x84, 0x1a, 0x6a, 0x73, 0xc2, 0xe3, 0x4a, 0x0c, 0xb5, 0x8e,
-	0x6b, 0x5f, 0xba, 0x81, 0xf7, 0x26, 0x8c, 0xe5, 0xaf, 0xf7, 0xda, 0x5d,
-	0x19, 0xcb, 0x87, 0xba, 0x44, 0xf7, 0x4f, 0xe8, 0x92, 0x67, 0x53, 0x4a,
-	0x3b, 0xf3, 0x56, 0xda, 0x85, 0x74, 0x15, 0x9f, 0xa1, 0xfe, 0x71, 0x74,
-	0x52, 0xe8, 0x1c, 0xc6, 0x78, 0x46, 0x66, 0x1b, 0xc3, 0xd8, 0x6c, 0x44,
-	0x62, 0x4b, 0xec, 0xa1, 0x8f, 0x40, 0xe6, 0x10, 0x8d, 0x85, 0x57, 0x14,
-	0x35, 0x75, 0x8b, 0x53, 0x1d, 0x5a, 0x56, 0xec, 0xbc, 0xb5, 0xb6, 0x98,
-	0xb7, 0xd6, 0xe4, 0x56, 0xf9, 0x7b, 0x58, 0x0f, 0x7a, 0x16, 0x4a, 0xf5,
-	0xa1, 0x47, 0xe9, 0xb4, 0x6a, 0x6b, 0xbf, 0xb2, 0x63, 0xc1, 0xa3, 0x74,
-	0x64, 0x3d, 0x78, 0x85, 0x58, 0x6c, 0xb6, 0x0f, 0x81, 0x5b, 0x37, 0xc2,
-	0xbb, 0x23, 0xdb, 0x8b, 0x72, 0x4d, 0x7a, 0xc8, 0x72, 0x74, 0x5a, 0x75,
-	0xad, 0xce, 0xdf, 0xc3, 0xfa, 0xd3, 0x93, 0xef, 0x63, 0xfe, 0x43, 0xc0,
-	0x9b, 0xb0, 0x67, 0x06, 0x92, 0x0b, 0xef, 0xe0, 0xbb, 0x4b, 0xf1, 0x15,
-	0x80, 0x5d, 0xff, 0x94, 0x7e, 0xf6, 0x12, 0xd5, 0x1b, 0x14, 0x5c, 0xba,
-	0xcb, 0x03, 0xd2, 0x62, 0xcf, 0x7f, 0xb1, 0xf5, 0xc2, 0x74, 0xaf, 0xd2,
-	0x31, 0x37, 0xef, 0xdd, 0x66, 0xc8, 0x2c, 0x62, 0xd6, 0xdb, 0x4e, 0x1e,
-	0xda, 0x17, 0x9e, 0xf6, 0x6e, 0x25, 0x4f, 0x5b, 0x17, 0x3e, 0x4f, 0x53,
-	0xea, 0xca, 0x44, 0x6b, 0x1b, 0x63, 0x7b, 0xb7, 0xfe, 0x91, 0x19, 0xfe,
-	0x1d, 0xa1, 0xb3, 0x58, 0xd4, 0x67, 0x92, 0x7c, 0x05, 0x3d, 0x9d, 0xf9,
-	0x80, 0x27, 0x99, 0x6f, 0xf7, 0xb6, 0x19, 0xbd, 0xde, 0xad, 0x46, 0x9f,
-	0xb7, 0xdd, 0xb8, 0x87, 0xb4, 0x7b, 0xbc, 0x1d, 0x06, 0xe3, 0x3a, 0xdf,
-	0x47, 0xbd, 0xf6, 0x62, 0x3c, 0x7f, 0x0f, 0xb1, 0x87, 0xd0, 0x1c, 0x20,
-	0x0e, 0xf2, 0x52, 0xc6, 0x11, 0xca, 0x58, 0x08, 0xb9, 0x91, 0x54, 0xdd,
-	0xd4, 0xd7, 0x98, 0x65, 0xc7, 0x09, 0x6b, 0x16, 0x55, 0x91, 0x98, 0x6c,
-	0xed, 0x3e, 0xc1, 0x7c, 0x9f, 0x38, 0xda, 0x7a, 0xeb, 0x29, 0xd4, 0xb8,
-	0x13, 0xd2, 0x3b, 0xb3, 0x1f, 0x8e, 0x46, 0xf5, 0xf7, 0x10, 0x0d, 0xbd,
-	0xc2, 0x67, 0x47, 0xe9, 0xbb, 0x63, 0xd6, 0xfc, 0x81, 0x06, 0xc9, 0x35,
-	0xa1, 0xdb, 0xf0, 0x78, 0x77, 0xb2, 0x37, 0xf3, 0x27, 0xd4, 0x96, 0x3b,
-	0x9c, 0x32, 0x0f, 0x29, 0xfc, 0x96, 0x0f, 0x4d, 0xe8, 0xca, 0x7b, 0x28,
-	0xd7, 0x97, 0xf0, 0x0f, 0x27, 0x59, 0xd7, 0x20, 0x7e, 0x68, 0x9a, 0xf7,
-	0xb1, 0xaf, 0x39, 0x96, 0xab, 0xc3, 0x65, 0xcb, 0xc6, 0x2e, 0x1c, 0xcd,
-	0x85, 0xf1, 0x0e, 0xe5, 0x73, 0x2d, 0xd6, 0xe2, 0xed, 0x69, 0x27, 0xf6,
-	0xe9, 0xb7, 0x17, 0xeb, 0x85, 0x03, 0xf7, 0xc6, 0x0e, 0x11, 0x3b, 0x38,
-	0x50, 0x4d, 0xfc, 0xf6, 0xb0, 0x75, 0xcd, 0xc9, 0xfe, 0xef, 0xb7, 0x91,
-	0xb2, 0xeb, 0x09, 0x79, 0x7c, 0x94, 0x3c, 0x36, 0x7b, 0xb7, 0x66, 0x55,
-	0xef, 0x9d, 0x59, 0x78, 0xdc, 0x89, 0xd1, 0xd6, 0x33, 0x27, 0x4d, 0x0c,
-	0xea, 0xb7, 0xe1, 0xca, 0xc9, 0xd1, 0x21, 0x17, 0xfd, 0xe7, 0xe7, 0xf1,
-	0x7e, 0x18, 0x33, 0xb8, 0x40, 0xe4, 0x71, 0xd1, 0xc7, 0xdc, 0xde, 0x10,
-	0x8f, 0x06, 0x58, 0x8b, 0xf5, 0x05, 0xc6, 0x66, 0x07, 0xd4, 0x21, 0xd6,
-	0xe4, 0xa4, 0x33, 0x11, 0x1d, 0x18, 0x23, 0x78, 0xac, 0x22, 0x3f, 0x5e,
-	0xe6, 0x6e, 0xdf, 0x62, 0xd8, 0xbb, 0x9b, 0xf5, 0x26, 0xc4, 0xfe, 0xce,
-	0x1b, 0xc5, 0xed, 0xb5, 0x88, 0xc6, 0x96, 0x29, 0xb7, 0x7b, 0xb1, 0xc9,
-	0x7b, 0x07, 0xeb, 0xc7, 0xe5, 0xa8, 0x39, 0xf2, 0x92, 0xee, 0x83, 0x7f,
-	0x51, 0xa7, 0xbe, 0xfb, 0x31, 0xba, 0xc0, 0x96, 0x2b, 0xca, 0x9e, 0x7f,
-	0xb1, 0xc5, 0xbb, 0x93, 0xb1, 0x59, 0x45, 0x13, 0x35, 0x2e, 0x26, 0xbd,
-	0xd2, 0xf3, 0x35, 0x2d, 0x6e, 0x22, 0x7f, 0xe2, 0xa3, 0x99, 0xd6, 0xcd,
-	0xf4, 0x87, 0xf0, 0x22, 0x3a, 0x99, 0xe6, 0x5e, 0x26, 0xcd, 0xfe, 0x10,
-	0x31, 0xec, 0x81, 0x8d, 0x3e, 0xe6, 0x29, 0xd1, 0x25, 0xf5, 0x98, 0x2f,
-	0xc9, 0x24, 0x75, 0xf9, 0x68, 0xeb, 0xe2, 0x29, 0xa9, 0xcb, 0xa9, 0xd6,
-	0xcc, 0x29, 0x0d, 0xef, 0xb0, 0xb6, 0xac, 0x8d, 0xab, 0xfa, 0x39, 0x25,
-	0x12, 0xba, 0x48, 0x59, 0x5c, 0xf8, 0x85, 0xb9, 0x57, 0x8b, 0x16, 0x6e,
-	0x61, 0x3c, 0x55, 0x33, 0x37, 0x86, 0x98, 0xf3, 0xab, 0x17, 0xa9, 0x98,
-	0x45, 0xa7, 0x1b, 0x15, 0x21, 0x78, 0xa2, 0x1a, 0xde, 0x3d, 0x19, 0xa3,
-	0x1e, 0xae, 0xd1, 0x3c, 0x48, 0xa8, 0x35, 0xc8, 0x52, 0xf8, 0xd8, 0x33,
-	0xf4, 0xc5, 0x71, 0xae, 0x5b, 0xb6, 0x28, 0x3c, 0xcb, 0xf3, 0x41, 0x3e,
-	0x7f, 0x7d, 0xed, 0x6a, 0xae, 0xfd, 0xd1, 0x29, 0xf1, 0xd7, 0x54, 0xeb,
-	0x85, 0x93, 0xf6, 0xda, 0xd1, 0x78, 0x0c, 0x1f, 0x9e, 0x54, 0x87, 0xdf,
-	0x55, 0x22, 0x03, 0x17, 0x14, 0x59, 0x1f, 0x75, 0x55, 0xb8, 0x62, 0x8e,
-	0x46, 0xa3, 0xa9, 0xbd, 0xa4, 0xd9, 0xb2, 0x89, 0xfa, 0xb7, 0xf8, 0xa0,
-	0xcf, 0x33, 0xcf, 0xba, 0xc9, 0x8f, 0xcd, 0x4b, 0x1d, 0x69, 0x9f, 0x2c,
-	0xf6, 0x6a, 0xec, 0x53, 0xaf, 0xf3, 0x13, 0xa4, 0x1e, 0x3c, 0xbb, 0x9b,
-	0x7d, 0xa8, 0xb5, 0x9e, 0x0b, 0xf0, 0x39, 0xd1, 0xc3, 0x2f, 0x15, 0x87,
-	0xf6, 0x1e, 0xf3, 0x98, 0xe4, 0x92, 0x20, 0x73, 0xd8, 0x3d, 0xd2, 0xd3,
-	0xa6, 0xd3, 0xf4, 0x77, 0x37, 0xfd, 0x7d, 0x9b, 0xf8, 0xb4, 0x41, 0x9f,
-	0x36, 0xe8, 0xd3, 0x86, 0x1a, 0x1a, 0x46, 0x24, 0x30, 0x48, 0xbb, 0x25,
-	0x43, 0xe2, 0xeb, 0x7d, 0xd8, 0xc7, 0xdf, 0xfd, 0xbc, 0x7f, 0x94, 0x7d,
-	0x2e, 0x56, 0xc8, 0x9a, 0x87, 0xd1, 0x6e, 0x3c, 0x86, 0xa1, 0x2c, 0x7e,
-	0xe5, 0x6d, 0x2e, 0x47, 0xf9, 0x1a, 0xe9, 0xe1, 0xd5, 0xc0, 0x31, 0x3c,
-	0xc6, 0x3e, 0xea, 0x97, 0x4a, 0xa5, 0xe6, 0xea, 0x3d, 0xae, 0xa8, 0x81,
-	0x76, 0xf6, 0xc3, 0x7b, 0xf3, 0xf7, 0xd0, 0xbe, 0x91, 0xa1, 0x57, 0x14,
-	0xf6, 0x52, 0xb5, 0x5c, 0x9b, 0xb1, 0x74, 0x27, 0xd7, 0x31, 0x84, 0x0f,
-	0x2b, 0xdf, 0xfe, 0x1e, 0x44, 0xb7, 0x3f, 0x6a, 0x18, 0xe4, 0xfa, 0x36,
-	0x1f, 0xa3, 0xec, 0x29, 0x07, 0x19, 0x63, 0xfb, 0xac, 0xf8, 0xea, 0x23,
-	0x8d, 0xeb, 0x79, 0x6c, 0x6b, 0x46, 0x6a, 0xa9, 0x89, 0xc7, 0x75, 0x13,
-	0xcf, 0xf2, 0x77, 0x89, 0xb9, 0x6c, 0xec, 0x86, 0x5c, 0xe6, 0xe0, 0x73,
-	0xbb, 0xf9, 0x5c, 0x0b, 0x53, 0xe7, 0xc2, 0x9c, 0xcc, 0x06, 0x0f, 0xcb,
-	0x6c, 0x10, 0x39, 0x43, 0x74, 0x3f, 0x8c, 0x0b, 0x99, 0x48, 0xca, 0xe9,
-	0x34, 0x47, 0x18, 0x57, 0x4b, 0x1f, 0xd1, 0x77, 0x5f, 0xdf, 0xa8, 0xf6,
-	0x52, 0x87, 0xb1, 0x49, 0x45, 0x0d, 0xbd, 0x86, 0x42, 0xa7, 0x07, 0x8d,
-	0xe1, 0x75, 0xce, 0x68, 0xe0, 0x2c, 0xd4, 0xc2, 0x20, 0x25, 0x7d, 0x3a,
-	0x6f, 0xe7, 0xba, 0xcd, 0xc5, 0x5c, 0xd7, 0x92, 0xab, 0x50, 0xee, 0xcc,
-	0xb2, 0x3e, 0xcf, 0x99, 0x69, 0x3f, 0xeb, 0x55, 0x7e, 0x4e, 0x68, 0x8f,
-	0xa0, 0x31, 0x2e, 0xb4, 0xb4, 0xae, 0x49, 0x05, 0x5f, 0xaf, 0x44, 0x94,
-	0xb5, 0x0a, 0x7a, 0xb9, 0x96, 0x36, 0x59, 0x93, 0x02, 0xee, 0x84, 0xd4,
-	0xce, 0x1e, 0xf6, 0x2d, 0x7d, 0xcc, 0x8b, 0x82, 0xa9, 0x65, 0x5e, 0x6a,
-	0xe7, 0xa3, 0x6d, 0x79, 0xb1, 0x8b, 0xd8, 0x44, 0x6c, 0x73, 0x18, 0x07,
-	0xac, 0x79, 0xb4, 0x89, 0x69, 0x5d, 0x72, 0x83, 0xd8, 0xe9, 0x30, 0xf6,
-	0xe7, 0xdd, 0xb8, 0x97, 0x79, 0x70, 0xbe, 0x99, 0xba, 0xf2, 0xbb, 0x31,
-	0x38, 0x77, 0x3b, 0xf6, 0x65, 0x65, 0x9e, 0xe0, 0xa6, 0xfd, 0x92, 0xc4,
-	0x40, 0xcc, 0x3a, 0xc4, 0x3f, 0x65, 0x5a, 0x49, 0xa7, 0x42, 0x5b, 0x74,
-	0x5a, 0xfa, 0xbe, 0xe0, 0xb6, 0x75, 0x6c, 0xcf, 0x2d, 0x9d, 0x09, 0x59,
-	0xab, 0x34, 0xb3, 0xb4, 0xf5, 0xda, 0x99, 0x91, 0x35, 0x4d, 0x9c, 0xd5,
-	0x6d, 0x4c, 0x5b, 0xd2, 0x67, 0x88, 0x32, 0xd7, 0x6c, 0x02, 0xd6, 0xdd,
-	0x80, 0x6b, 0x2b, 0x78, 0xad, 0xfb, 0x3a, 0xae, 0xed, 0x17, 0xec, 0x4c,
-	0x5c, 0xdb, 0xb5, 0x83, 0xb8, 0xb6, 0x5e, 0x29, 0x61, 0x5a, 0x99, 0x59,
-	0x94, 0x70, 0x6d, 0x75, 0x31, 0x7f, 0x1f, 0xc6, 0x5e, 0x62, 0x9e, 0xda,
-	0xfa, 0x11, 0x78, 0xd6, 0x3b, 0x3e, 0x73, 0x60, 0x84, 0xbd, 0x4c, 0x19,
-	0xb0, 0xd2, 0xc4, 0x2d, 0x1b, 0xd2, 0x66, 0xb9, 0x56, 0x1f, 0x2e, 0x77,
-	0xc8, 0x4c, 0x3a, 0x9a, 0x1e, 0x63, 0x9e, 0x71, 0xac, 0x57, 0xd3, 0x49,
-	0x78, 0x02, 0x35, 0xda, 0x3d, 0xc5, 0x5e, 0x22, 0xe4, 0xd9, 0x4e, 0x4c,
-	0x14, 0x8d, 0x7f, 0x6a, 0xce, 0x06, 0x85, 0x46, 0xa1, 0xe0, 0x41, 0xf2,
-	0x11, 0x0f, 0x6b, 0xd4, 0xb2, 0x32, 0x81, 0xd7, 0xa3, 0x21, 0xcf, 0xce,
-	0x7c, 0xda, 0xdb, 0xdd, 0x70, 0x0b, 0x7a, 0x4e, 0x49, 0x3d, 0x0a, 0x63,
-	0xc7, 0xa9, 0x76, 0xd6, 0x20, 0x0d, 0x1d, 0x93, 0x5d, 0xec, 0xf1, 0x7a,
-	0x95, 0xde, 0x39, 0xd1, 0xa1, 0xd8, 0x40, 0x0d, 0x84, 0x1d, 0x37, 0xce,
-	0x4c, 0x4b, 0xfd, 0xf2, 0x7b, 0x96, 0x7f, 0x8d, 0xeb, 0x01, 0xea, 0xe7,
-	0xaa, 0x1b, 0x7e, 0x13, 0x67, 0x74, 0xf1, 0x4b, 0x7e, 0x37, 0x92, 0xd8,
-	0xd6, 0x3c, 0x6d, 0xba, 0x34, 0x99, 0x7d, 0x87, 0x2c, 0x9b, 0x6e, 0x65,
-	0x9d, 0x6b, 0x9f, 0xeb, 0xa3, 0x1d, 0x4b, 0x73, 0xee, 0x1b, 0xed, 0xb9,
-	0xc5, 0xbb, 0x8d, 0x39, 0x8f, 0x3d, 0xbc, 0xc7, 0xc3, 0x3c, 0xea, 0x39,
-	0x65, 0x62, 0x4e, 0x7f, 0xcb, 0x7c, 0x5c, 0x73, 0xd1, 0x6e, 0x5f, 0x65,
-	0x4e, 0x16, 0xcc, 0x92, 0xf0, 0xde, 0x31, 0xe3, 0x72, 0x54, 0x25, 0xd0,
-	0x5c, 0x46, 0x7f, 0xbc, 0x18, 0xb7, 0xe7, 0x91, 0xc7, 0x73, 0xb7, 0x7b,
-	0xbb, 0xb3, 0xec, 0x33, 0xd8, 0x07, 0xdb, 0xbd, 0xdf, 0x57, 0xbd, 0x7b,
-	0xb2, 0x4e, 0xa5, 0x36, 0x01, 0x67, 0xcb, 0x26, 0x13, 0x1f, 0x6f, 0x88,
-	0xa6, 0x42, 0x0e, 0xe6, 0x4f, 0xd2, 0x32, 0x72, 0xcd, 0xde, 0x7e, 0xe6,
-	0xeb, 0x9d, 0x59, 0xba, 0x01, 0x7d, 0xc7, 0xbf, 0x61, 0x74, 0xc0, 0x0f,
-	0x99, 0xb3, 0xe1, 0xeb, 0x8c, 0xd8, 0x20, 0xfd, 0x31, 0xd4, 0xa6, 0x44,
-	0x97, 0x87, 0x10, 0x5d, 0xfa, 0xd8, 0xf9, 0x96, 0xf9, 0x64, 0x6e, 0x13,
-	0x9f, 0xef, 0x62, 0x2e, 0x4d, 0x32, 0xb7, 0x8e, 0xa6, 0xdc, 0x90, 0x77,
-	0xd4, 0xfe, 0x37, 0x95, 0x08, 0xe3, 0x00, 0xbf, 0xc3, 0xe7, 0x03, 0x1d,
-	0xcc, 0xa3, 0x73, 0x7a, 0x34, 0xb9, 0x15, 0xe9, 0xae, 0x6a, 0xa8, 0x7a,
-	0x83, 0x22, 0x73, 0x31, 0xb1, 0x43, 0x0c, 0x3f, 0xe1, 0x9a, 0x2e, 0x4d,
-	0xf4, 0xb8, 0x85, 0xbe, 0x48, 0x6c, 0xe0, 0xf8, 0xbc, 0xdf, 0xfd, 0x5e,
-	0x19, 0x2a, 0x56, 0x50, 0xb6, 0x9f, 0x58, 0x39, 0xc7, 0xab, 0x69, 0xf8,
-	0xaf, 0xc4, 0x4e, 0x7f, 0x96, 0x97, 0xf9, 0x67, 0x09, 0x0f, 0x8a, 0x6f,
-	0x64, 0x5a, 0x6f, 0x9d, 0x8d, 0x15, 0xe7, 0xa1, 0x1e, 0x6f, 0xd7, 0x8c,
-	0x89, 0xac, 0xee, 0x87, 0xf4, 0xff, 0xe5, 0xf1, 0x02, 0xd1, 0x41, 0x13,
-	0x3a, 0x78, 0xbd, 0x7d, 0xa6, 0x52, 0x69, 0xcf, 0x9a, 0xf8, 0x33, 0x5d,
-	0x4d, 0xb7, 0x39, 0x19, 0xef, 0xba, 0x7a, 0x16, 0xf8, 0x19, 0x71, 0x94,
-	0xf8, 0x98, 0x0b, 0x3e, 0xcd, 0xa6, 0xd5, 0x34, 0x7b, 0x3b, 0xb1, 0x85,
-	0xc4, 0x9f, 0x73, 0x6d, 0x05, 0x9a, 0x95, 0x59, 0x97, 0xe8, 0xad, 0x0b,
-	0xc9, 0x7c, 0xa5, 0xb2, 0x8b, 0xba, 0xbc, 0x73, 0xbd, 0x17, 0x97, 0x2c,
-	0x5d, 0xde, 0x4e, 0x5d, 0xe2, 0x8d, 0xd5, 0x70, 0x5e, 0xa8, 0x05, 0xc1,
-	0x44, 0xb9, 0x1a, 0x1e, 0x70, 0x88, 0x4d, 0x18, 0x27, 0x82, 0xd5, 0x50,
-	0xc9, 0x7a, 0x9e, 0x24, 0x0e, 0x26, 0x6e, 0x0c, 0xf4, 0xe1, 0xdb, 0xcc,
-	0x4b, 0x8f, 0xd3, 0x6f, 0x7f, 0xa1, 0x35, 0xa1, 0xe2, 0x3b, 0xcd, 0xb4,
-	0xe9, 0x26, 0xef, 0xf6, 0x6c, 0x3f, 0x9e, 0x58, 0x30, 0xf1, 0x0c, 0x63,
-	0xa6, 0x21, 0x9e, 0x0e, 0x94, 0xb3, 0xaf, 0x63, 0xed, 0x5b, 0x3e, 0x61,
-	0xf9, 0xfc, 0x68, 0xeb, 0x96, 0xf9, 0x10, 0x9c, 0xdf, 0xb6, 0xf6, 0x7e,
-	0x5a, 0xc3, 0xf3, 0xd6, 0xde, 0x0f, 0x3f, 0x4d, 0x0c, 0xeb, 0x6a, 0xf2,
-	0x63, 0x67, 0x05, 0x2a, 0xa3, 0xa6, 0x39, 0x1c, 0xb7, 0xf6, 0x1f, 0x5a,
-	0x63, 0xd6, 0xfd, 0xa3, 0xfc, 0x2c, 0xcd, 0xae, 0xff, 0x46, 0x30, 0x63,
-	0x38, 0x49, 0xf9, 0x77, 0x10, 0x07, 0xf4, 0x13, 0x07, 0xd4, 0x26, 0xd4,
-	0xe4, 0x6e, 0xa7, 0xcc, 0x69, 0x0a, 0x87, 0xaa, 0x79, 0xfd, 0x8e, 0x22,
-	0x0e, 0xa8, 0x3a, 0x25, 0xb3, 0x3f, 0x62, 0x45, 0xd8, 0x7b, 0x26, 0x3d,
-	0xc4, 0x01, 0x15, 0x93, 0x2e, 0x74, 0x13, 0x03, 0xb8, 0x89, 0xd9, 0xb7,
-	0xe5, 0x6a, 0xe1, 0x3d, 0xe1, 0x44, 0x24, 0xfe, 0x23, 0x1c, 0xa2, 0xbf,
-	0x1d, 0x8a, 0x79, 0x94, 0xf0, 0x2a, 0x07, 0x75, 0xf6, 0x2b, 0x1c, 0x0c,
-	0x38, 0x51, 0xa5, 0xbd, 0x86, 0x07, 0xbf, 0xa0, 0xf6, 0xf7, 0x67, 0x25,
-	0xce, 0x47, 0x5b, 0xbb, 0x4f, 0xd9, 0xb5, 0xdf, 0x77, 0x6a, 0x74, 0x59,
-	0x6a, 0x7f, 0xed, 0x86, 0x7e, 0x9c, 0x9e, 0xc1, 0x37, 0x57, 0x13, 0x64,
-	0xd6, 0x72, 0xcd, 0xfa, 0x78, 0x94, 0x3d, 0xb8, 0x3a, 0xd4, 0xa1, 0x44,
-	0x27, 0xaa, 0x98, 0x0f, 0x4e, 0xb3, 0xf6, 0x7b, 0x12, 0xd1, 0x40, 0xcc,
-	0x81, 0x1e, 0x37, 0x6d, 0xf3, 0x3e, 0xfb, 0xf1, 0x9f, 0xe6, 0xc2, 0xa4,
-	0x59, 0x06, 0x17, 0x6b, 0xff, 0xfb, 0x1a, 0x3e, 0x73, 0xd2, 0x0f, 0xdf,
-	0x71, 0x7a, 0x70, 0x35, 0x67, 0xd7, 0xfe, 0xea, 0x06, 0x73, 0xe4, 0x72,
-	0xdc, 0x87, 0x2b, 0x39, 0x9d, 0xfe, 0xd8, 0x8f, 0xa3, 0xac, 0xfd, 0x97,
-	0xb5, 0x00, 0x3e, 0xcc, 0xb5, 0xd0, 0x47, 0x83, 0xf8, 0x39, 0x71, 0xf2,
-	0x7a, 0xd6, 0xfe, 0xbb, 0xe8, 0x5f, 0x71, 0xd6, 0xfe, 0x36, 0x0b, 0x97,
-	0x64, 0x5a, 0xcf, 0x4c, 0x5b, 0xb5, 0xbf, 0xc1, 0xc1, 0xba, 0xe9, 0x46,
-	0x74, 0x99, 0x39, 0xc3, 0xfc, 0xc5, 0x26, 0x1f, 0x9f, 0xa5, 0xde, 0xf2,
-	0x1b, 0x30, 0x6b, 0xd5, 0xaa, 0x2d, 0xde, 0x5d, 0x5c, 0x7b, 0xa5, 0x15,
-	0x73, 0x26, 0x76, 0xac, 0xff, 0x6b, 0xfc, 0x41, 0x8d, 0x83, 0x3e, 0x99,
-	0xf0, 0xde, 0xc9, 0xb8, 0xf3, 0x27, 0x4a, 0xb3, 0x91, 0x18, 0xd7, 0xb9,
-	0xdd, 0x7b, 0x17, 0xfd, 0xe4, 0x96, 0xf5, 0xcc, 0x2a, 0x01, 0x3b, 0xe6,
-	0xda, 0x19, 0x73, 0x21, 0xc6, 0xdc, 0x6a, 0xc6, 0xdc, 0x93, 0x7a, 0x34,
-	0xb6, 0x85, 0xf8, 0xec, 0x95, 0x9c, 0xc4, 0x5d, 0x33, 0xe9, 0xaa, 0x94,
-	0x6b, 0x74, 0x40, 0xe2, 0x67, 0xc7, 0xfa, 0xd1, 0xb3, 0x95, 0x10, 0x5d,
-	0xe1, 0xb3, 0x95, 0xc4, 0x22, 0xcc, 0x52, 0x4b, 0xcb, 0xce, 0x68, 0xea,
-	0x36, 0x67, 0x74, 0xf8, 0x3d, 0xe5, 0x2d, 0xf3, 0x0d, 0xc6, 0xdc, 0x4e,
-	0xc6, 0xdc, 0x2e, 0xc6, 0x5c, 0x9b, 0x61, 0xe2, 0x85, 0xb8, 0xda, 0xdf,
-	0xe4, 0x88, 0xe8, 0x6d, 0x0e, 0xac, 0xae, 0x64, 0x09, 0xf1, 0x22, 0xda,
-	0xf5, 0x07, 0xe4, 0x7f, 0x49, 0x8f, 0xf6, 0xc6, 0x14, 0x89, 0xb3, 0x30,
-	0x3e, 0xa0, 0xdc, 0xe5, 0xc5, 0x38, 0x3b, 0x30, 0x77, 0xbe, 0xe8, 0x1b,
-	0x25, 0xd9, 0x9d, 0x78, 0x5e, 0x67, 0x5e, 0x5d, 0x21, 0xbe, 0xdb, 0x87,
-	0x09, 0xea, 0xd1, 0x1b, 0xed, 0xc3, 0x31, 0xd6, 0xcd, 0xfb, 0x58, 0xaf,
-	0xef, 0x37, 0x22, 0x2d, 0xdb, 0xd9, 0x27, 0x5d, 0x0a, 0xa9, 0xe1, 0xb0,
-	0xd2, 0x87, 0x41, 0xfa, 0xf0, 0x20, 0xeb, 0x4b, 0x9b, 0xf1, 0x4b, 0xa5,
-	0x83, 0x98, 0x62, 0x7f, 0x5e, 0xde, 0x53, 0x63, 0x69, 0xc7, 0x10, 0x06,
-	0x16, 0x24, 0xcf, 0x21, 0x70, 0x53, 0xa2, 0x0f, 0x53, 0x46, 0x19, 0xfa,
-	0x9a, 0x7b, 0x94, 0x3b, 0xf2, 0x32, 0xa7, 0x63, 0x6c, 0x1a, 0x8c, 0x5d,
-	0x8b, 0x5f, 0x05, 0xb9, 0x68, 0x0f, 0x32, 0x12, 0xab, 0xc6, 0x2e, 0xe5,
-	0xae, 0x39, 0x89, 0xf7, 0x3e, 0xa5, 0x4f, 0xe2, 0xd9, 0x48, 0x29, 0x77,
-	0x4b, 0x7c, 0x5b, 0xb3, 0x6d, 0xc9, 0x01, 0xb2, 0xf7, 0x71, 0x3b, 0xf1,
-	0x1e, 0x18, 0x5f, 0xce, 0xef, 0x84, 0x18, 0x83, 0x6d, 0x65, 0x0e, 0xfa,
-	0x69, 0x84, 0xb6, 0x73, 0xa0, 0x5d, 0xff, 0xb2, 0x99, 0x0e, 0x0c, 0x30,
-	0xa6, 0xfa, 0x70, 0xd4, 0x08, 0x99, 0x97, 0x2d, 0x1c, 0x53, 0xca, 0xf1,
-	0x5b, 0x58, 0xeb, 0x56, 0xc1, 0xa3, 0x49, 0x7d, 0xf7, 0x21, 0x56, 0xe3,
-	0x41, 0x85, 0x26, 0xb5, 0x27, 0xd3, 0xba, 0x78, 0x42, 0x91, 0x3e, 0xa5,
-	0x18, 0xeb, 0x5b, 0xf0, 0x00, 0x73, 0xc2, 0xbe, 0xf8, 0xbd, 0xb8, 0x3f,
-	0x50, 0x01, 0x3f, 0xf5, 0xf4, 0x50, 0xc0, 0xc7, 0x5c, 0xfb, 0x7b, 0x45,
-	0x3a, 0x7f, 0x51, 0x56, 0xec, 0xbf, 0xaf, 0x61, 0xb0, 0x5a, 0xc6, 0xd8,
-	0xe6, 0x19, 0x99, 0x27, 0xa5, 0x5a, 0x43, 0x33, 0x1a, 0xfc, 0xec, 0x7b,
-	0xb7, 0xc4, 0xd5, 0xd4, 0x16, 0x67, 0x44, 0x7a, 0x9a, 0x8c, 0x9f, 0xf8,
-	0x2f, 0x17, 0x8d, 0xf6, 0x36, 0x89, 0x8e, 0xb5, 0x10, 0x3a, 0xa9, 0xa7,
-	0xee, 0x5c, 0x90, 0x31, 0xe4, 0x28, 0x17, 0x2c, 0x95, 0xcc, 0x5d, 0xa7,
-	0x15, 0x22, 0xad, 0xd0, 0x8c, 0xe0, 0xba, 0x14, 0x71, 0x9d, 0xc6, 0x38,
-	0x34, 0xcd, 0xcd, 0xc4, 0x73, 0xbe, 0x53, 0x32, 0x97, 0x8a, 0x4c, 0x10,
-	0x03, 0x37, 0x11, 0x1f, 0xf7, 0xd1, 0xab, 0xcd, 0x5b, 0xea, 0xa3, 0x7a,
-	0x9b, 0x82, 0xc7, 0xe6, 0x9b, 0xe1, 0x71, 0x92, 0xe6, 0x3b, 0xb9, 0x00,
-	0x2e, 0xe7, 0x42, 0x78, 0x9b, 0xb4, 0x2f, 0x59, 0xb4, 0xeb, 0xf0, 0xb3,
-	0x62, 0x0e, 0x8b, 0x33, 0x87, 0x6d, 0xcd, 0x2a, 0xf4, 0xd7, 0x30, 0x46,
-	0xf4, 0xbf, 0xfa, 0xec, 0xd2, 0xcd, 0x1e, 0xea, 0x4d, 0x64, 0x71, 0xf1,
-	0x73, 0x1c, 0x0f, 0x59, 0x39, 0xfb, 0xb5, 0xcf, 0x66, 0x6b, 0x68, 0x2b,
-	0xea, 0xbe, 0xba, 0xf8, 0xde, 0xba, 0xd9, 0x3f, 0x2f, 0xca, 0xdb, 0x53,
-	0xb4, 0x35, 0x71, 0x9b, 0x71, 0x9e, 0xd7, 0x04, 0x47, 0x69, 0x70, 0x9c,
-	0x8a, 0xa1, 0xec, 0xd4, 0x35, 0xfe, 0x35, 0x89, 0x19, 0x56, 0xde, 0xc7,
-	0xbe, 0x4b, 0x9e, 0x1e, 0x21, 0x5e, 0x34, 0xc9, 0xd3, 0x55, 0x8b, 0x97,
-	0x20, 0x79, 0xf9, 0xe4, 0xb3, 0x12, 0xb6, 0x0c, 0x5d, 0x7b, 0x27, 0x40,
-	0x7d, 0xe0, 0xd1, 0x10, 0xf5, 0x79, 0x65, 0xa3, 0x3c, 0xe7, 0xc3, 0x1d,
-	0xb9, 0x44, 0xb9, 0xe4, 0x79, 0xaf, 0xb6, 0x05, 0x7b, 0xe7, 0x3e, 0xaf,
-	0xf7, 0x20, 0x6d, 0x11, 0xa0, 0xf1, 0xe4, 0xde, 0x17, 0xd5, 0xd4, 0x3f,
-	0x42, 0x8a, 0x3d, 0xd3, 0x23, 0xd9, 0x34, 0x1e, 0xca, 0x7e, 0xcb, 0xda,
-	0xcb, 0x5b, 0xb7, 0x01, 0xfb, 0x49, 0xff, 0x60, 0x35, 0xe3, 0xe8, 0x7f,
-	0xc4, 0xa3, 0x82, 0xa5, 0x76, 0x55, 0x42, 0xea, 0x6e, 0xb4, 0xe5, 0x36,
-	0xc5, 0x44, 0x59, 0x1c, 0xc3, 0xed, 0xcd, 0xd1, 0xd8, 0x65, 0x3c, 0x66,
-	0xca, 0x5c, 0xdc, 0x59, 0xac, 0xc1, 0xc4, 0xaf, 0x4a, 0x3b, 0xeb, 0x70,
-	0x5b, 0x11, 0x53, 0x6d, 0xcd, 0xbf, 0xf5, 0xb9, 0xd9, 0x83, 0xf4, 0xed,
-	0x52, 0x7b, 0xbc, 0x4a, 0x1b, 0xd7, 0x39, 0xca, 0x9c, 0xfd, 0xbc, 0xfe,
-	0x52, 0x88, 0x95, 0x19, 0xae, 0xf5, 0x0a, 0x0e, 0x11, 0x3f, 0xa5, 0x83,
-	0x26, 0x76, 0xf1, 0xf3, 0x00, 0x71, 0xd6, 0xbb, 0x7a, 0x15, 0x66, 0x03,
-	0x01, 0x62, 0x4b, 0xe6, 0x60, 0xc7, 0xdf, 0x49, 0x4d, 0x88, 0x85, 0x1d,
-	0xb2, 0x57, 0xff, 0x6f, 0xed, 0xdf, 0xac, 0x27, 0x96, 0x11, 0xd9, 0xbd,
-	0x0a, 0x73, 0x68, 0x0c, 0xc4, 0x37, 0x7b, 0xf5, 0x42, 0xd8, 0x81, 0xe4,
-	0x55, 0x07, 0xd4, 0xd3, 0xef, 0xb0, 0x1f, 0x7c, 0xa4, 0x5e, 0x3d, 0xdd,
-	0xea, 0xd4, 0x90, 0x9a, 0xf2, 0xe0, 0xe1, 0xa9, 0x0e, 0x54, 0x5b, 0x73,
-	0xa4, 0x71, 0xda, 0xcc, 0xc1, 0x3e, 0x6c, 0xf4, 0x53, 0x17, 0xfb, 0xb1,
-	0xab, 0x1b, 0x1e, 0x45, 0x8b, 0x75, 0x7d, 0x0c, 0xfb, 0xb3, 0x5e, 0xa5,
-	0x3b, 0xeb, 0x42, 0xc7, 0x5d, 0x8f, 0xc2, 0xbd, 0x7e, 0x80, 0x7c, 0xc9,
-	0x75, 0xf9, 0xfb, 0x6e, 0xf6, 0x71, 0xc2, 0x5f, 0x19, 0xc2, 0xab, 0xc8,
-	0xdb, 0x7a, 0x0d, 0x23, 0x53, 0x2e, 0x65, 0xb7, 0xf1, 0x37, 0xe6, 0x55,
-	0x6b, 0x6f, 0x48, 0xae, 0x55, 0xc8, 0x99, 0x01, 0x3e, 0x23, 0x39, 0x67,
-	0x10, 0x59, 0xc6, 0xf6, 0xdd, 0xd6, 0xfb, 0xa7, 0xca, 0x6c, 0x99, 0x92,
-	0xec, 0x6f, 0xdb, 0xe9, 0x1f, 0xf2, 0x4c, 0x5b, 0xf1, 0xda, 0x76, 0x8f,
-	0x7d, 0x2e, 0x41, 0xec, 0x3e, 0x88, 0x5b, 0x69, 0x84, 0xfa, 0xa8, 0xf8,
-	0xd8, 0x20, 0xea, 0x73, 0x4c, 0xa8, 0xab, 0x6c, 0x7e, 0x1f, 0x34, 0x0a,
-	0xec, 0x4d, 0x35, 0xe6, 0x4d, 0xea, 0x6e, 0xa5, 0xbc, 0x4f, 0x47, 0xfd,
-	0xb5, 0xf7, 0x4b, 0xf5, 0x54, 0x70, 0xe9, 0x17, 0xdd, 0xff, 0x4d, 0xc8,
-	0x3d, 0x97, 0xf6, 0x87, 0x8c, 0xe3, 0x68, 0x6f, 0xa5, 0x43, 0xfc, 0xe7,
-	0x0f, 0x71, 0xff, 0x1c, 0x1b, 0xd7, 0x0a, 0xa1, 0x4f, 0xdc, 0x6b, 0xb8,
-	0x94, 0x2e, 0xe6, 0x9f, 0x03, 0x53, 0x8e, 0x3b, 0xca, 0xf0, 0xe7, 0x66,
-	0xf9, 0xca, 0x11, 0xd4, 0xc7, 0xc7, 0xf8, 0xbc, 0x82, 0x76, 0x62, 0xc8,
-	0x27, 0xf4, 0xad, 0xe8, 0xa8, 0x91, 0x1c, 0xf0, 0xbc, 0x39, 0xd8, 0x27,
-	0x3a, 0x54, 0xb0, 0x8d, 0xd7, 0x5f, 0xa0, 0x7d, 0x9f, 0xd6, 0x5d, 0xa8,
-	0x5f, 0x21, 0x33, 0x41, 0x75, 0x3a, 0x89, 0x3d, 0x1e, 0x7b, 0x8f, 0x2c,
-	0x6d, 0x56, 0x6b, 0xda, 0xf0, 0x9d, 0x8e, 0xfa, 0xe9, 0x37, 0xe9, 0x4f,
-	0x6d, 0xeb, 0x6f, 0xbc, 0x57, 0xd2, 0x89, 0x8e, 0xd0, 0xfa, 0xe7, 0x4c,
-	0xdc, 0x34, 0x8a, 0xc0, 0xfa, 0x1b, 0xed, 0x5f, 0xe2, 0xfb, 0x30, 0x63,
-	0x10, 0xe9, 0xea, 0x84, 0xcc, 0x89, 0xa2, 0xa4, 0x73, 0x18, 0xbf, 0x9f,
-	0x1f, 0xc3, 0xa1, 0xac, 0xc8, 0xb9, 0x60, 0xf9, 0xb6, 0xb6, 0xfe, 0xba,
-	0x6c, 0x0f, 0x66, 0xa3, 0x03, 0x55, 0x45, 0xd9, 0x0e, 0xb2, 0x1f, 0xa9,
-	0x64, 0x8e, 0x7d, 0x80, 0x3a, 0x1d, 0xb6, 0x74, 0xda, 0x07, 0x3d, 0x77,
-	0x9d, 0xee, 0x10, 0xe9, 0x7a, 0x13, 0xa2, 0x37, 0xd9, 0x97, 0x63, 0x2f,
-	0x40, 0xba, 0xfb, 0x6e, 0xa0, 0x3b, 0xa8, 0x5f, 0xa7, 0xbb, 0x37, 0x1b,
-	0x3d, 0xed, 0x28, 0xd2, 0xfd, 0xc6, 0x5c, 0x89, 0x46, 0x1a, 0x3b, 0xd7,
-	0xa7, 0x91, 0xdb, 0x7c, 0xd0, 0x3c, 0x68, 0xe9, 0xe3, 0xfb, 0xd6, 0xf5,
-	0x6d, 0xf5, 0x12, 0x0f, 0xfc, 0x33, 0xa1, 0x59, 0x67, 0x00, 0x6c, 0x1c,
-	0x76, 0x63, 0x7c, 0xa8, 0x6f, 0x75, 0x3b, 0x93, 0x8c, 0xe3, 0xa0, 0x67,
-	0xfb, 0xe7, 0x66, 0x1f, 0x1d, 0xec, 0xd7, 0x3a, 0x8d, 0x1e, 0x6f, 0x97,
-	0xe1, 0x21, 0x06, 0xab, 0x54, 0xb6, 0x65, 0x65, 0x06, 0x22, 0xb1, 0x5c,
-	0xc4, 0xc5, 0x79, 0xe9, 0x0b, 0xef, 0x61, 0xcf, 0xb0, 0x81, 0xf6, 0x1d,
-	0xc0, 0x44, 0x7e, 0x40, 0x49, 0x06, 0xb9, 0x8e, 0x21, 0x75, 0x05, 0xac,
-	0x79, 0xbd, 0xa8, 0xa4, 0x2f, 0x05, 0x13, 0xd3, 0x89, 0x93, 0xf5, 0x26,
-	0x88, 0x51, 0x3c, 0x2b, 0x12, 0xb3, 0x89, 0x5d, 0xf5, 0x4e, 0x1c, 0xb7,
-	0xb0, 0x98, 0x3a, 0xcb, 0xdf, 0x69, 0x89, 0x99, 0x3b, 0xb3, 0x52, 0xc7,
-	0x08, 0x27, 0xb5, 0x11, 0xfc, 0x63, 0xbc, 0x30, 0x5c, 0x83, 0xe4, 0x7d,
-	0x35, 0x90, 0x1e, 0x63, 0x02, 0x7f, 0xa9, 0x85, 0x3c, 0xfd, 0x79, 0x97,
-	0xd2, 0x6d, 0xcc, 0x7b, 0x77, 0x18, 0x7e, 0xf8, 0xd8, 0xbf, 0xf5, 0x38,
-	0x23, 0xec, 0x39, 0xac, 0x19, 0x7d, 0xeb, 0xad, 0xb9, 0x7e, 0x6f, 0xbb,
-	0x61, 0xe7, 0xc2, 0x5b, 0x66, 0x3d, 0xde, 0x8e, 0x99, 0x48, 0x68, 0xc2,
-	0xc2, 0x62, 0x07, 0x5b, 0x23, 0x39, 0xd3, 0x7c, 0x55, 0x2f, 0x5c, 0x2d,
-	0xb7, 0xbe, 0x4f, 0xb7, 0xc6, 0x72, 0x4d, 0xd8, 0x43, 0xfc, 0xd4, 0x36,
-	0xd3, 0x04, 0x7d, 0x06, 0x38, 0x31, 0x15, 0xc2, 0xba, 0xac, 0x7a, 0x3a,
-	0xe5, 0xec, 0xc7, 0xf4, 0x42, 0x17, 0xb2, 0x79, 0xef, 0x72, 0xd8, 0x41,
-	0x8c, 0x1d, 0x77, 0xe0, 0x0e, 0x7d, 0x83, 0x52, 0xb0, 0x62, 0x5a, 0xc1,
-	0xdd, 0xfa, 0x2e, 0x65, 0xc0, 0xc2, 0x14, 0xf3, 0xc4, 0x22, 0x0a, 0x6e,
-	0xb2, 0x72, 0xef, 0xc9, 0xd6, 0x38, 0xf1, 0xf7, 0x1d, 0x59, 0xa9, 0xef,
-	0x26, 0x2e, 0xc6, 0xa9, 0x97, 0x78, 0xba, 0xdf, 0xcd, 0x7e, 0xe8, 0xa0,
-	0xa2, 0xf6, 0xea, 0x8a, 0x8d, 0xf1, 0x6e, 0x9b, 0xb7, 0x71, 0xe1, 0xad,
-	0xf3, 0xcd, 0x5e, 0xc9, 0x41, 0xed, 0xba, 0x1a, 0x72, 0x39, 0x02, 0x18,
-	0xb6, 0x68, 0xa4, 0x5b, 0xf5, 0xf9, 0x32, 0xac, 0xd6, 0xfa, 0x70, 0xda,
-	0x92, 0x61, 0xa2, 0x75, 0x0b, 0xb1, 0xf6, 0x93, 0x46, 0x3f, 0x7b, 0x65,
-	0xd9, 0x37, 0x8d, 0xc4, 0x5a, 0x9c, 0x6d, 0xc4, 0xb3, 0x91, 0xf0, 0xb2,
-	0x92, 0x54, 0xd2, 0xae, 0xc6, 0xe4, 0x3c, 0x58, 0x51, 0x6a, 0xec, 0xfa,
-	0x26, 0x32, 0x46, 0x89, 0xb3, 0xda, 0xa6, 0xbc, 0xcb, 0x49, 0xd8, 0x73,
-	0x9e, 0x4e, 0xfd, 0xff, 0xe0, 0x52, 0x50, 0x9d, 0x48, 0x92, 0xef, 0x0e,
-	0xe6, 0xdd, 0x42, 0x9f, 0x8b, 0xf7, 0x65, 0xbe, 0x37, 0xdc, 0x3a, 0x9e,
-	0x41, 0xc1, 0x99, 0x90, 0x1e, 0x0b, 0xfe, 0xde, 0x3c, 0x64, 0xd6, 0xc4,
-	0x3e, 0xe3, 0x53, 0xb3, 0xb4, 0xc7, 0xd4, 0x33, 0x63, 0xef, 0x9f, 0x65,
-	0x16, 0x5c, 0xfe, 0x1d, 0x46, 0x33, 0x8e, 0xe7, 0x5d, 0x37, 0xd0, 0x8e,
-	0x4e, 0xdc, 0xe2, 0x70, 0x20, 0xba, 0xfe, 0x6e, 0xa5, 0xb8, 0x07, 0xc5,
-	0x3c, 0x91, 0xb2, 0x6a, 0x62, 0x19, 0xe5, 0xbc, 0x70, 0x52, 0xd6, 0xf8,
-	0x56, 0xeb, 0xf8, 0x49, 0xa9, 0x91, 0xc3, 0xad, 0x21, 0x43, 0xed, 0x95,
-	0x9e, 0xb0, 0x9a, 0x7a, 0xfa, 0x68, 0x52, 0x6a, 0xf0, 0x14, 0x6b, 0xb0,
-	0xba, 0xdc, 0xae, 0x48, 0x1d, 0x53, 0x63, 0x5e, 0xa7, 0x03, 0x57, 0x1a,
-	0xd4, 0xfe, 0x1f, 0x40, 0x1d, 0xb0, 0xe7, 0x8a, 0x8f, 0xb6, 0x36, 0x16,
-	0xf1, 0xf0, 0x6d, 0xf3, 0x83, 0x72, 0xee, 0xc4, 0xd2, 0x71, 0x53, 0x4e,
-	0xb0, 0xb1, 0x69, 0xbe, 0x1c, 0xef, 0x21, 0x6e, 0x10, 0x6c, 0x2c, 0xd7,
-	0x27, 0x5b, 0x1b, 0x66, 0x3d, 0xe4, 0x4d, 0xc1, 0x7b, 0x5a, 0x0f, 0x7d,
-	0xaf, 0xc4, 0xa3, 0x8d, 0x9b, 0xb7, 0x13, 0x37, 0x3b, 0x13, 0x6a, 0xcb,
-	0x56, 0xe2, 0x66, 0x8d, 0xfd, 0x84, 0x0b, 0x7d, 0x78, 0xc2, 0xb0, 0x7b,
-	0x0a, 0xc1, 0xce, 0xe6, 0x49, 0x35, 0x29, 0xb8, 0xf9, 0xea, 0x06, 0x60,
-	0x37, 0x71, 0xf3, 0x72, 0xc6, 0x85, 0x7e, 0xe2, 0xe6, 0x8f, 0x98, 0x82,
-	0xee, 0x24, 0x6e, 0xbe, 0x42, 0x8c, 0x75, 0x3e, 0xfe, 0x73, 0x7c, 0xa3,
-	0x38, 0x3b, 0xdb, 0x4b, 0xec, 0x9c, 0x0c, 0xde, 0x88, 0x9d, 0xff, 0xe2,
-	0x5f, 0x60, 0xe7, 0x3d, 0xc4, 0x84, 0x3d, 0x59, 0xd9, 0x67, 0x1a, 0x6d,
-	0x7d, 0xe3, 0x94, 0x9c, 0x6d, 0xb9, 0x0d, 0xef, 0x9e, 0x1c, 0x1d, 0x22,
-	0x56, 0xc6, 0x58, 0xbc, 0x1f, 0x99, 0x19, 0xac, 0x22, 0x2e, 0x78, 0xd9,
-	0xc9, 0x75, 0xd7, 0xc5, 0x55, 0xfd, 0x4d, 0x25, 0xda, 0xd5, 0x8f, 0x28,
-	0xfb, 0x66, 0x75, 0x99, 0x26, 0x4c, 0xba, 0x12, 0xc4, 0xc6, 0xac, 0x81,
-	0xab, 0x89, 0x9d, 0xab, 0x16, 0x81, 0xda, 0x45, 0x1b, 0x3b, 0xcb, 0xdc,
-	0xac, 0x2a, 0x8a, 0x3f, 0x22, 0x76, 0x66, 0xaf, 0xcb, 0x50, 0x5b, 0x6c,
-	0x62, 0x8c, 0x2a, 0x38, 0x1a, 0xf5, 0xa1, 0x67, 0x8a, 0xb8, 0xc7, 0x9a,
-	0x9b, 0x99, 0x23, 0x3f, 0xd6, 0xfb, 0x71, 0x6c, 0xc1, 0x9e, 0x9b, 0x75,
-	0x12, 0xbf, 0xb9, 0xa2, 0x41, 0x94, 0x2f, 0xba, 0xf0, 0x1c, 0xf1, 0xf3,
-	0x36, 0xda, 0xf9, 0x0c, 0xf1, 0xf3, 0x9e, 0x1b, 0x66, 0x67, 0xb3, 0x8b,
-	0x78, 0x95, 0x58, 0xbe, 0xae, 0x16, 0x51, 0x99, 0x8b, 0x98, 0x57, 0x36,
-	0xfa, 0x70, 0xce, 0xc2, 0xcf, 0xde, 0xe5, 0xb4, 0x62, 0xcb, 0x56, 0x46,
-	0x5b, 0x88, 0x5d, 0x1d, 0xb4, 0x6b, 0xdb, 0x49, 0xb5, 0xeb, 0x25, 0xea,
-	0xa2, 0x31, 0x7a, 0xde, 0xb2, 0xc7, 0x60, 0x5c, 0x66, 0x2c, 0x43, 0xad,
-	0x72, 0xfe, 0xaa, 0x82, 0xf6, 0xee, 0x9e, 0x8c, 0x24, 0x3f, 0x80, 0x1d,
-	0x93, 0xb1, 0x5c, 0x59, 0xb1, 0x1e, 0xca, 0xbd, 0x09, 0xde, 0x4b, 0xa2,
-	0x6b, 0xa3, 0xed, 0xdf, 0xb1, 0xdc, 0x71, 0x62, 0x57, 0xd9, 0x5b, 0x0d,
-	0xf8, 0x3b, 0x8d, 0x2e, 0x4c, 0x1b, 0x61, 0x94, 0x9f, 0x2b, 0xee, 0xd1,
-	0x9e, 0x93, 0x33, 0x7b, 0x8f, 0xb6, 0x06, 0xbe, 0x53, 0xc2, 0x84, 0x49,
-	0xe2, 0xbb, 0xa0, 0xe7, 0x8e, 0xbc, 0xe0, 0xc5, 0x5e, 0x1c, 0x33, 0xd4,
-	0xd0, 0x4f, 0x18, 0x13, 0xf7, 0xc9, 0xfe, 0xfc, 0x0d, 0x33, 0xaa, 0x87,
-	0x79, 0xcf, 0xf8, 0xdc, 0x8c, 0x2a, 0x95, 0xc5, 0xaf, 0x9c, 0xcd, 0xe5,
-	0x70, 0xac, 0x93, 0x19, 0x89, 0x1a, 0x1a, 0xc3, 0x63, 0xc4, 0x1c, 0xbf,
-	0x54, 0x7c, 0x9a, 0x6b, 0xa8, 0xc9, 0xa9, 0x86, 0xe6, 0x15, 0x1f, 0xdf,
-	0xbd, 0x87, 0xf9, 0xed, 0x1e, 0xfa, 0x46, 0x64, 0xb9, 0x42, 0x71, 0xe2,
-	0xd2, 0x97, 0x2d, 0x3c, 0xea, 0xed, 0xe5, 0xb5, 0xe9, 0x7c, 0x09, 0xd7,
-	0xf4, 0x09, 0xaf, 0xe8, 0x9c, 0xb2, 0x73, 0x88, 0x96, 0xf3, 0x2e, 0x5f,
-	0x82, 0x2d, 0x5b, 0x25, 0x65, 0x7d, 0x60, 0x32, 0x60, 0x0e, 0xac, 0x94,
-	0x18, 0xd6, 0xb0, 0xd3, 0x10, 0xff, 0x1a, 0x24, 0x9f, 0x7d, 0x38, 0x62,
-	0xac, 0x66, 0xef, 0x26, 0xf3, 0xd2, 0x26, 0x62, 0xeb, 0x5e, 0xd6, 0x60,
-	0xd3, 0x4c, 0xe9, 0x69, 0xb3, 0x69, 0x93, 0xa6, 0xe7, 0x94, 0x42, 0x4d,
-	0x88, 0xf8, 0x66, 0x3d, 0x6b, 0x77, 0x5b, 0xbe, 0x09, 0x6f, 0x9e, 0xd1,
-	0xe8, 0x9b, 0xed, 0xc4, 0xef, 0xbd, 0xb8, 0x97, 0xf2, 0x7c, 0x23, 0xff,
-	0x4d, 0x24, 0xbf, 0xee, 0xc2, 0xc4, 0x54, 0x12, 0x5b, 0xd6, 0x8f, 0xe0,
-	0xd2, 0xef, 0x78, 0x98, 0xab, 0x7c, 0x78, 0x72, 0x4a, 0xf2, 0x6b, 0x09,
-	0x6f, 0xdf, 0x88, 0x45, 0x3c, 0x08, 0x5b, 0x38, 0xe4, 0x8b, 0xef, 0xd9,
-	0x18, 0xc5, 0xcb, 0x5e, 0xb8, 0xf4, 0x3e, 0xf3, 0xd0, 0xfa, 0x7f, 0x81,
-	0x67, 0x88, 0x5b, 0x88, 0x05, 0x2a, 0x62, 0xd6, 0xf9, 0xb8, 0x12, 0xde,
-	0x75, 0xd1, 0x07, 0x24, 0xa6, 0x57, 0x33, 0xd6, 0x4d, 0x62, 0xe7, 0xe5,
-	0xe2, 0xfc, 0xf2, 0xed, 0x93, 0xea, 0xd2, 0x11, 0x44, 0x88, 0xa1, 0x31,
-	0x28, 0xd8, 0xcd, 0x49, 0xbc, 0x7b, 0x25, 0x1a, 0xd5, 0xcf, 0x11, 0xef,
-	0x8e, 0xd2, 0xd6, 0x2e, 0x4d, 0x7c, 0x33, 0x80, 0xb2, 0xc5, 0x10, 0x7d,
-	0x52, 0xe6, 0x97, 0x7f, 0xe5, 0xb5, 0xe7, 0x97, 0x32, 0x33, 0x97, 0xf3,
-	0x23, 0xe8, 0x28, 0x63, 0xef, 0x56, 0xae, 0xa4, 0x99, 0x93, 0x67, 0xbd,
-	0xbb, 0x99, 0xdf, 0xfb, 0x8d, 0xa0, 0x7f, 0x77, 0x3e, 0xc0, 0xdf, 0x3a,
-	0x7f, 0x7f, 0x7e, 0x07, 0x9f, 0x0f, 0xf1, 0x33, 0x8c, 0x6c, 0x2e, 0x52,
-	0x21, 0xcd, 0x40, 0x36, 0x67, 0xe7, 0xbc, 0x70, 0xee, 0x90, 0x57, 0xb0,
-	0x66, 0xdb, 0x94, 0xfd, 0x5d, 0xbb, 0xe1, 0xfb, 0xe7, 0x31, 0xbf, 0x9b,
-	0x7c, 0x9f, 0x39, 0xa9, 0xe1, 0xa3, 0x93, 0x16, 0xe6, 0x2f, 0x10, 0xf3,
-	0x0f, 0xbb, 0x9d, 0x82, 0x35, 0x7f, 0x61, 0x9e, 0x8f, 0x46, 0x07, 0xe6,
-	0xe8, 0x07, 0x3d, 0xa4, 0xeb, 0xd0, 0x82, 0x16, 0xbf, 0x36, 0x9f, 0xf6,
-	0xcc, 0xf7, 0xf2, 0xc9, 0x18, 0xde, 0xb9, 0x3e, 0x63, 0xfd, 0xa4, 0xcc,
-	0x9a, 0x15, 0xe3, 0xb1, 0x77, 0x37, 0xc1, 0xd3, 0xc2, 0x7e, 0xd3, 0xcd,
-	0xe7, 0x43, 0xd6, 0xf3, 0x32, 0xf3, 0xbd, 0x8e, 0x9d, 0x3f, 0xba, 0xfe,
-	0xce, 0x61, 0x76, 0x6a, 0x9e, 0xf3, 0x8c, 0x2d, 0xa7, 0xf5, 0x9c, 0xcc,
-	0x65, 0xbd, 0xcb, 0xb0, 0xe2, 0x6b, 0x88, 0x32, 0x89, 0x7d, 0x0f, 0x99,
-	0xb6, 0xdf, 0x06, 0xfd, 0x3b, 0x19, 0x0f, 0xdf, 0xa6, 0x7d, 0x76, 0x9e,
-	0xab, 0xf3, 0xdf, 0x6d, 0xec, 0xb2, 0x64, 0xbe, 0xfb, 0x9c, 0xd4, 0x24,
-	0xb9, 0xff, 0x40, 0x85, 0x60, 0xef, 0x27, 0x59, 0xb3, 0x46, 0x0d, 0xd9,
-	0x03, 0x80, 0xe2, 0x4a, 0x1c, 0x41, 0xe7, 0x74, 0x18, 0x6f, 0xeb, 0xde,
-	0xe2, 0x59, 0x17, 0x89, 0xc9, 0x69, 0xc6, 0x64, 0x10, 0x63, 0x46, 0x24,
-	0xfc, 0x36, 0xf1, 0x69, 0x9a, 0x0c, 0x1f, 0xcb, 0x3a, 0xf1, 0x36, 0x31,
-	0x23, 0x14, 0xfb, 0xac, 0xa8, 0xfd, 0x6e, 0xe9, 0xef, 0x4a, 0x84, 0x6b,
-	0x22, 0x2d, 0x07, 0x50, 0x87, 0x0c, 0x73, 0xbe, 0x57, 0xfb, 0x21, 0x8e,
-	0x9f, 0x70, 0xe0, 0x7e, 0xf6, 0x7d, 0xc9, 0xbb, 0x74, 0x7e, 0x6f, 0x1c,
-	0x7a, 0x1f, 0xff, 0x68, 0xce, 0xca, 0x79, 0x2c, 0x45, 0xce, 0x7c, 0x7c,
-	0x62, 0xd6, 0x6a, 0x5a, 0xe1, 0x07, 0xd0, 0x52, 0x57, 0xd1, 0x38, 0xbc,
-	0x8c, 0x0f, 0xcc, 0x02, 0xef, 0xbd, 0xc7, 0xf8, 0x79, 0x49, 0x8f, 0x84,
-	0x1c, 0x14, 0xa6, 0x10, 0x74, 0xe2, 0x3e, 0x5d, 0xe6, 0x29, 0xea, 0xf0,
-	0xb3, 0x50, 0x87, 0x2e, 0x28, 0x72, 0x86, 0xe7, 0x92, 0x99, 0xae, 0x91,
-	0x75, 0x15, 0xac, 0x5b, 0xd3, 0xd8, 0x55, 0x06, 0xb5, 0xc5, 0xad, 0x68,
-	0xfa, 0xfb, 0xca, 0xff, 0x32, 0x0b, 0xc1, 0x4f, 0xcc, 0x77, 0xb4, 0x12,
-	0x5d, 0x35, 0xec, 0x71, 0x96, 0x78, 0xab, 0xc3, 0x71, 0x43, 0xf6, 0xf1,
-	0x7e, 0x88, 0xfb, 0x4f, 0xb8, 0xd0, 0x1e, 0xff, 0xb9, 0x99, 0x0e, 0x0a,
-	0xcd, 0x50, 0x25, 0x2a, 0x84, 0xbe, 0x3d, 0xdb, 0x7e, 0x31, 0x0f, 0xa5,
-	0xc3, 0x10, 0xbc, 0x2c, 0x7e, 0x3a, 0x0d, 0xd3, 0x90, 0x99, 0xa2, 0x89,
-	0x3b, 0xe3, 0x23, 0x78, 0x2f, 0x9e, 0xfc, 0x4f, 0x1e, 0xa8, 0x4b, 0x97,
-	0x9d, 0x6a, 0xa1, 0xc9, 0x19, 0x56, 0xbc, 0x0d, 0xda, 0x70, 0x83, 0x55,
-	0x6f, 0x2e, 0xb2, 0x77, 0xf2, 0x31, 0xb7, 0x48, 0x8f, 0x39, 0x8d, 0xc5,
-	0xc9, 0x34, 0x5c, 0xc4, 0x76, 0xa3, 0xcd, 0x6a, 0xff, 0x33, 0x8a, 0x1a,
-	0x3a, 0xa8, 0x84, 0x95, 0x7b, 0xb5, 0x14, 0x9e, 0xd3, 0xa3, 0xc9, 0x36,
-	0xa5, 0xce, 0xd3, 0x95, 0x2f, 0xd1, 0x6e, 0x27, 0x56, 0x51, 0x0b, 0x97,
-	0x9d, 0xe5, 0xa8, 0xdd, 0xa0, 0x75, 0x95, 0x3b, 0xd5, 0xd4, 0xd7, 0x18,
-	0x5f, 0xdb, 0xf3, 0x05, 0xef, 0xfb, 0x51, 0x07, 0xd6, 0x5a, 0xfb, 0x0d,
-	0x99, 0xe2, 0xbc, 0x74, 0x1a, 0xdd, 0x93, 0xe6, 0x96, 0x8b, 0x71, 0x35,
-	0xf4, 0x8c, 0x92, 0xde, 0xed, 0x23, 0xa6, 0x79, 0x00, 0x5a, 0x78, 0x81,
-	0x75, 0xaa, 0x3d, 0xef, 0xc0, 0x2d, 0xa7, 0x84, 0x66, 0x86, 0x34, 0x8f,
-	0xa0, 0xfc, 0x84, 0xb9, 0x65, 0xb7, 0xae, 0xa6, 0x2e, 0x3b, 0xd3, 0xff,
-	0xbd, 0x96, 0x7a, 0xeb, 0x50, 0x64, 0xbf, 0x6d, 0x84, 0xb8, 0x62, 0x44,
-	0xce, 0xcd, 0xc5, 0xfe, 0x98, 0x98, 0xe2, 0x5b, 0xf4, 0x55, 0x67, 0xc2,
-	0x4f, 0x3e, 0xd5, 0xd8, 0x1c, 0x64, 0xce, 0x1e, 0xc6, 0x65, 0x3d, 0xed,
-	0xed, 0x6c, 0x88, 0x11, 0x9b, 0x85, 0x58, 0x07, 0xc3, 0x38, 0x46, 0x8c,
-	0x77, 0x24, 0x5f, 0x86, 0x42, 0x40, 0x23, 0x36, 0xeb, 0x85, 0x63, 0xd2,
-	0xa7, 0xcc, 0x67, 0x22, 0x7a, 0x3b, 0xfe, 0x33, 0x0a, 0x21, 0x71, 0x91,
-	0x23, 0xf0, 0x9d, 0xf8, 0x7b, 0xb3, 0x4a, 0xd3, 0x5a, 0x26, 0x15, 0xae,
-	0xfb, 0x54, 0x88, 0x3a, 0xe6, 0x7b, 0x72, 0xbe, 0xc5, 0xe8, 0xc1, 0xbd,
-	0x93, 0x41, 0xbe, 0x5f, 0x85, 0x75, 0x27, 0xc2, 0xb8, 0x12, 0xbf, 0x19,
-	0x85, 0x1a, 0x1b, 0x03, 0x79, 0x35, 0xfa, 0x11, 0xfb, 0xac, 0x34, 0x7b,
-	0x4a, 0xd9, 0x63, 0x3a, 0x62, 0x48, 0x7f, 0xee, 0xe2, 0x77, 0x1f, 0x7f,
-	0x45, 0x9f, 0xdf, 0x2a, 0x62, 0x9d, 0xa9, 0xd6, 0xf0, 0xfc, 0xcf, 0x2b,
-	0xec, 0x79, 0x5a, 0x98, 0xcf, 0x05, 0xac, 0x19, 0xe1, 0x28, 0x69, 0x9e,
-	0x9d, 0x96, 0xbe, 0xad, 0x6d, 0xb3, 0xa7, 0xb8, 0x4f, 0xff, 0x53, 0xdd,
-	0x81, 0x2d, 0xec, 0xed, 0x43, 0x9a, 0xd4, 0xcb, 0x51, 0xb5, 0x16, 0x9b,
-	0x71, 0x3a, 0xc0, 0x26, 0x5c, 0xfb, 0x0f, 0x98, 0x08, 0xc4, 0x98, 0xf3,
-	0x35, 0xbc, 0x9b, 0xf9, 0x32, 0xfb, 0x9d, 0x3a, 0x39, 0xe3, 0x83, 0x5b,
-	0x4e, 0xb8, 0xb9, 0xe6, 0x16, 0xe2, 0x9a, 0x4e, 0xbc, 0x16, 0xb0, 0x7b,
-	0x8d, 0xa3, 0xbc, 0x3e, 0x3e, 0xe7, 0x23, 0x16, 0xf5, 0xf0, 0xf7, 0x46,
-	0xde, 0xbe, 0x88, 0x27, 0x91, 0xe5, 0xdf, 0xe2, 0xc9, 0x43, 0x3c, 0xa0,
-	0xe1, 0x6a, 0xe6, 0x65, 0x5c, 0x21, 0xed, 0xf4, 0x9c, 0x4d, 0x73, 0x2a,
-	0x2f, 0x74, 0x65, 0xbd, 0x48, 0xaa, 0xd6, 0x29, 0xf4, 0x7d, 0x72, 0xde,
-	0xf7, 0xdf, 0xb9, 0x06, 0x91, 0xdd, 0x09, 0xf6, 0xc7, 0x7a, 0x03, 0xda,
-	0x03, 0xb4, 0x97, 0x21, 0x6b, 0xa8, 0xec, 0x45, 0xe5, 0xdd, 0x10, 0xd6,
-	0x4e, 0x9a, 0x23, 0xa1, 0x84, 0x5c, 0x37, 0xcd, 0xea, 0x4d, 0x5a, 0xe8,
-	0x4d, 0xc5, 0xc5, 0x5a, 0xe7, 0xa2, 0x0e, 0xc6, 0x71, 0x36, 0xd3, 0xb8,
-	0xf4, 0x1e, 0xb1, 0x53, 0x98, 0xbd, 0xde, 0x25, 0xe7, 0x38, 0xe6, 0x33,
-	0x0b, 0x95, 0x32, 0x23, 0x18, 0xcf, 0xfb, 0x94, 0xb9, 0xcc, 0x91, 0x4a,
-	0xc9, 0x45, 0x63, 0xf4, 0x85, 0xa6, 0x49, 0xe1, 0xd5, 0x1c, 0xa9, 0x22,
-	0x9d, 0x63, 0xa4, 0x33, 0xb7, 0x51, 0xeb, 0x1f, 0x53, 0x44, 0x67, 0x3e,
-	0xe2, 0xba, 0x8b, 0x32, 0x3f, 0xa3, 0xde, 0xfe, 0x94, 0xcf, 0x8b, 0xde,
-	0x82, 0x78, 0xad, 0x48, 0xe7, 0x89, 0xfc, 0x12, 0xe6, 0x32, 0x1f, 0x58,
-	0x7f, 0x8f, 0xe5, 0x63, 0xac, 0x7d, 0x83, 0xc8, 0x31, 0x9f, 0x4c, 0x66,
-	0x1a, 0xfb, 0x27, 0xc9, 0x87, 0x7d, 0x36, 0x6f, 0x10, 0x4f, 0x17, 0x9f,
-	0x19, 0xe5, 0xbb, 0xa3, 0xd7, 0xfe, 0x16, 0x1d, 0xd9, 0xfb, 0xff, 0xf6,
-	0x1e, 0x43, 0x39, 0x6d, 0x67, 0xf7, 0xe1, 0x47, 0x0d, 0xb7, 0xcc, 0xc3,
-	0xf1, 0xf2, 0xf4, 0x16, 0x8c, 0xe9, 0x7f, 0x8e, 0xbd, 0x94, 0x7b, 0x9c,
-	0xfa, 0x3c, 0x61, 0x58, 0xfb, 0xfc, 0x72, 0xfe, 0x8b, 0xb9, 0xfa, 0x60,
-	0xeb, 0x19, 0x62, 0xb1, 0xe3, 0x8c, 0x99, 0xfd, 0xf1, 0xc6, 0xde, 0x57,
-	0xe8, 0x77, 0xc9, 0xdf, 0x96, 0xbd, 0x74, 0x60, 0x32, 0xfb, 0x0d, 0xcc,
-	0xd6, 0x34, 0x2e, 0x3f, 0xcf, 0x9c, 0x70, 0x9a, 0x79, 0xca, 0xc5, 0x9c,
-	0x50, 0x9d, 0x25, 0x86, 0x64, 0x9e, 0x2a, 0x30, 0x4f, 0xb9, 0xb4, 0xc6,
-	0xa5, 0x79, 0xfc, 0x15, 0xf5, 0x22, 0xfc, 0x45, 0x62, 0xf3, 0x90, 0x67,
-	0xed, 0xf9, 0xab, 0x36, 0x3f, 0x84, 0x4b, 0x37, 0xdb, 0x33, 0x34, 0x27,
-	0x6b, 0xf6, 0xbe, 0x4c, 0x63, 0x60, 0x4c, 0x68, 0xf7, 0xa9, 0xa1, 0x34,
-	0x6d, 0x35, 0x61, 0x61, 0xef, 0x61, 0xf6, 0x0b, 0x72, 0xde, 0xab, 0x0a,
-	0x2e, 0xfa, 0xfe, 0x98, 0x2e, 0xe7, 0x20, 0x42, 0xfe, 0xed, 0xb4, 0xe1,
-	0x98, 0xd1, 0xd8, 0x12, 0x51, 0x76, 0xe3, 0x52, 0x31, 0xc7, 0xda, 0x58,
-	0x5a, 0xed, 0x3f, 0x86, 0xc6, 0xde, 0x07, 0xf0, 0x75, 0x24, 0x6b, 0x1a,
-	0x07, 0xa6, 0x11, 0xd1, 0xef, 0x83, 0x9c, 0x1b, 0xb5, 0x69, 0xd5, 0xe7,
-	0x9c, 0xc4, 0x23, 0x9f, 0x98, 0xab, 0xb5, 0x27, 0x30, 0x4d, 0xcc, 0xd8,
-	0xb0, 0x5e, 0x5b, 0xfa, 0x6e, 0xf1, 0x9e, 0xbd, 0xa7, 0x24, 0xfe, 0xe2,
-	0xa1, 0x0e, 0xca, 0xe1, 0x5a, 0x51, 0xc7, 0x35, 0xa8, 0x0b, 0xeb, 0x4c,
-	0xf1, 0x45, 0x1c, 0xa2, 0xbf, 0x4d, 0xe7, 0x15, 0xe8, 0xf5, 0x17, 0x31,
-	0x2c, 0xb5, 0x89, 0xef, 0xb4, 0x65, 0x7c, 0xc4, 0x29, 0x21, 0x94, 0x6b,
-	0x91, 0xf0, 0x28, 0xe5, 0x6b, 0x63, 0x2e, 0x1f, 0x67, 0x0e, 0x49, 0x07,
-	0x7c, 0xd6, 0x39, 0xd7, 0x72, 0x2d, 0x64, 0xfd, 0x6f, 0x82, 0xf4, 0x41,
-	0x0d, 0xb3, 0xb2, 0x9f, 0x7d, 0x04, 0x17, 0xa7, 0x0b, 0x38, 0x1e, 0x4f,
-	0xe2, 0x40, 0x4d, 0x00, 0x93, 0xc6, 0x4a, 0x6b, 0x6e, 0x20, 0xfd, 0x56,
-	0x77, 0xf6, 0xb0, 0x35, 0x8b, 0xdc, 0x16, 0x77, 0xd4, 0xcb, 0x79, 0x8f,
-	0x39, 0xf6, 0x5d, 0xd3, 0xfa, 0x08, 0x0e, 0xe9, 0xdf, 0x82, 0xbe, 0x42,
-	0x72, 0xe7, 0x18, 0xce, 0xcf, 0x4a, 0x0d, 0x9b, 0x68, 0xbd, 0x75, 0x52,
-	0xf4, 0xe3, 0x20, 0xe6, 0xf5, 0xa0, 0xc9, 0xc2, 0x70, 0xaf, 0xb7, 0xae,
-	0x99, 0xb5, 0xb1, 0x5c, 0x53, 0x4e, 0xce, 0x66, 0x57, 0xc1, 0x4f, 0x7d,
-	0x5d, 0x88, 0xbb, 0x99, 0x73, 0x44, 0x9f, 0x72, 0x16, 0xd0, 0x96, 0x33,
-	0x96, 0x53, 0x30, 0xd6, 0x7c, 0xe3, 0x5e, 0x8b, 0xfc, 0x9f, 0xc2, 0xb5,
-	0xf3, 0x89, 0xc5, 0xd9, 0xf8, 0x1f, 0x9b, 0x97, 0x6e, 0x12, 0xb9, 0x5b,
-	0x7d, 0xcc, 0xe9, 0xe1, 0xd9, 0x6b, 0xfa, 0x15, 0x9d, 0x9e, 0x93, 0x9a,
-	0x61, 0xe9, 0xdc, 0x9e, 0xb7, 0xa9, 0xc3, 0xef, 0x28, 0x8d, 0xac, 0x27,
-	0xf4, 0xab, 0x1a, 0xfa, 0x5b, 0x13, 0x06, 0x56, 0x27, 0x5c, 0x7d, 0x57,
-	0x8d, 0x2d, 0x68, 0xd9, 0xf0, 0xae, 0x89, 0x9b, 0xdb, 0xe0, 0xd4, 0xe4,
-	0xfa, 0xac, 0x99, 0x0c, 0xc8, 0xdf, 0x4f, 0xfa, 0xa4, 0x96, 0xbf, 0x68,
-	0x14, 0xcc, 0x35, 0x2b, 0x6d, 0x6c, 0xf8, 0xf7, 0x19, 0xd9, 0x07, 0x4b,
-	0x9b, 0xec, 0xb5, 0x97, 0xde, 0x76, 0x1e, 0xc6, 0xdf, 0xe6, 0x8e, 0xe0,
-	0xad, 0x69, 0x17, 0x71, 0xa6, 0xc8, 0xb2, 0x05, 0xd5, 0x1b, 0xa2, 0xc9,
-	0x77, 0x99, 0x17, 0x97, 0x66, 0x4b, 0x7e, 0xf1, 0x7a, 0xeb, 0xda, 0x59,
-	0x85, 0xb4, 0xaa, 0x50, 0x46, 0x39, 0x7f, 0xac, 0x3b, 0x11, 0x2e, 0x62,
-	0x5b, 0x27, 0xf9, 0xdc, 0x97, 0xb1, 0x31, 0x6f, 0x24, 0x37, 0xed, 0xb3,
-	0xe7, 0x5f, 0x3e, 0xe6, 0xd1, 0x71, 0x4c, 0x64, 0x1a, 0x63, 0xef, 0xc9,
-	0x79, 0x1e, 0xf6, 0x62, 0x97, 0x30, 0x8e, 0x13, 0x99, 0x52, 0x0e, 0x0d,
-	0xc9, 0x39, 0xd8, 0x58, 0xd8, 0x61, 0xe7, 0xc8, 0xb0, 0x43, 0x4d, 0xf3,
-	0xd7, 0x27, 0xd8, 0x60, 0x34, 0x1f, 0x09, 0x95, 0xc3, 0x89, 0xfd, 0xba,
-	0xed, 0x1f, 0xf5, 0xf3, 0x6e, 0x84, 0x57, 0x48, 0x5d, 0x96, 0x9a, 0xec,
-	0x62, 0x4d, 0x5e, 0x89, 0xe4, 0x4a, 0x17, 0x5e, 0xd7, 0x44, 0x1f, 0x53,
-	0x25, 0x7d, 0xe8, 0xe7, 0xf0, 0x90, 0x59, 0xe8, 0x15, 0x5f, 0x72, 0xe3,
-	0x48, 0xd3, 0x9c, 0x39, 0x1b, 0x14, 0xd9, 0x9d, 0x38, 0xcd, 0xfc, 0x8a,
-	0x9b, 0x23, 0xa1, 0xd3, 0xac, 0xd9, 0x63, 0x5a, 0xc9, 0xc7, 0xff, 0x63,
-	0x91, 0x4f, 0xad, 0x7f, 0x01, 0x47, 0xf8, 0x77, 0x7d, 0xe8, 0x80, 0x62,
-	0xaf, 0xb7, 0x66, 0xfe, 0x43, 0x5f, 0x69, 0x76, 0x2a, 0xcf, 0x86, 0x73,
-	0xa7, 0xf9, 0x5d, 0x68, 0xf9, 0xe8, 0x9f, 0xe5, 0x18, 0x08, 0xca, 0x79,
-	0x10, 0xd1, 0x8b, 0xec, 0x3f, 0x82, 0xfa, 0x30, 0xf1, 0x32, 0xf5, 0x71,
-	0xe4, 0xda, 0xd9, 0x2b, 0x3b, 0x7f, 0x55, 0xf0, 0xfa, 0xf6, 0xf8, 0x4b,
-	0x9b, 0xbd, 0xf8, 0x95, 0x79, 0x29, 0x18, 0x62, 0x4e, 0x10, 0x9b, 0xa6,
-	0x2c, 0x1c, 0xe9, 0x24, 0x3e, 0xd9, 0x67, 0x9f, 0x33, 0x69, 0x95, 0xff,
-	0xa1, 0x29, 0xca, 0x51, 0x18, 0x24, 0xce, 0x5e, 0xcc, 0x58, 0x67, 0xfb,
-	0x06, 0xde, 0x54, 0x22, 0xcc, 0x35, 0x5f, 0xc2, 0x40, 0xad, 0xd0, 0x0b,
-	0xf8, 0x77, 0xce, 0xc4, 0xa8, 0x83, 0x3a, 0xa1, 0x6b, 0x3e, 0xc3, 0x6e,
-	0xee, 0xc8, 0xa4, 0xd0, 0x07, 0xc6, 0x26, 0x23, 0x43, 0x3f, 0x06, 0x36,
-	0x57, 0x41, 0x4d, 0x2d, 0x14, 0xff, 0xdf, 0xe3, 0x67, 0x8a, 0xd0, 0x12,
-	0x3a, 0x2e, 0x18, 0xcc, 0x71, 0x53, 0x8b, 0x15, 0xd4, 0x9d, 0xda, 0xfb,
-	0x3d, 0xa5, 0x02, 0x4f, 0x3c, 0x15, 0x23, 0xef, 0x2b, 0xfc, 0xdb, 0x67,
-	0x3c, 0xf0, 0x9e, 0xa9, 0x62, 0xcd, 0xf5, 0xe0, 0x72, 0x33, 0xed, 0xfa,
-	0x54, 0x89, 0x77, 0x6b, 0x9f, 0x14, 0x8f, 0x67, 0xc3, 0x30, 0xe8, 0xb3,
-	0x8b, 0x86, 0xec, 0x17, 0x7b, 0xac, 0xfc, 0xb9, 0xb4, 0xb1, 0xce, 0xda,
-	0xaf, 0x7a, 0x3e, 0xaf, 0x85, 0xce, 0x2a, 0x55, 0xf8, 0xe0, 0x44, 0xe1,
-	0xe6, 0x72, 0x98, 0x2f, 0xae, 0x4e, 0x44, 0xfb, 0xf7, 0xd2, 0xe7, 0xd7,
-	0xae, 0x09, 0xb2, 0x97, 0x61, 0x4f, 0xb9, 0x49, 0xfa, 0xdf, 0x69, 0xf6,
-	0xbf, 0xa5, 0xbd, 0x7f, 0x6d, 0xe8, 0x11, 0x25, 0xdd, 0xe9, 0x87, 0xf9,
-	0x51, 0x79, 0xc2, 0xfc, 0xd8, 0x9d, 0x88, 0xf2, 0x7d, 0xd9, 0xdf, 0x33,
-	0xcd, 0x9f, 0x36, 0x9b, 0x66, 0xae, 0x39, 0xd2, 0x1f, 0x70, 0x06, 0x70,
-	0xa6, 0x41, 0xf6, 0x04, 0x1d, 0xf8, 0x20, 0xaa, 0x85, 0xf6, 0x42, 0xf6,
-	0xe8, 0x99, 0xe3, 0x57, 0xca, 0xf9, 0xc4, 0x3a, 0x7f, 0x97, 0xb1, 0x02,
-	0xcf, 0x2d, 0x6c, 0xc2, 0x80, 0x1b, 0xd6, 0xf9, 0x19, 0x53, 0xc7, 0x9b,
-	0xab, 0x21, 0x75, 0x3b, 0xda, 0xf2, 0x08, 0x82, 0x58, 0xc8, 0x1f, 0xc1,
-	0xc3, 0x27, 0x64, 0xaf, 0x71, 0xb2, 0xd5, 0x73, 0xc2, 0xfc, 0xfb, 0x50,
-	0xa2, 0xc0, 0xbc, 0x68, 0x9a, 0x15, 0x9b, 0x1a, 0x43, 0x2c, 0x47, 0xc4,
-	0x18, 0x69, 0xc1, 0xee, 0x43, 0x1f, 0xa0, 0x06, 0x67, 0xe7, 0x92, 0x37,
-	0xb3, 0x97, 0xec, 0x7a, 0x5a, 0x09, 0xe0, 0x07, 0x94, 0xf1, 0xd9, 0xbc,
-	0xe0, 0x14, 0xa3, 0xb5, 0xfb, 0xc4, 0x2a, 0xbc, 0xb8, 0x10, 0xc4, 0x59,
-	0x43, 0x23, 0x4e, 0x82, 0x52, 0x99, 0x30, 0xab, 0xab, 0xc9, 0x6b, 0xa5,
-	0xd3, 0x89, 0xce, 0xb8, 0xf4, 0x87, 0xda, 0x90, 0x4f, 0xc1, 0xaa, 0x72,
-	0x68, 0xcb, 0x0f, 0x01, 0xc3, 0x5e, 0xf6, 0xab, 0x4f, 0x2b, 0xd1, 0xfe,
-	0xf7, 0x9d, 0x41, 0xfc, 0x80, 0xf9, 0xe7, 0x7b, 0x79, 0x39, 0x5b, 0xc5,
-	0x1c, 0x33, 0x17, 0xa6, 0xad, 0x3c, 0x70, 0xd4, 0x57, 0xe1, 0x28, 0xe3,
-	0xe5, 0x65, 0xbd, 0x8c, 0x39, 0x4a, 0xce, 0x5a, 0x49, 0x7e, 0x7f, 0x54,
-	0xce, 0x94, 0x98, 0xcf, 0x6b, 0x76, 0xbf, 0xaf, 0xcf, 0xdf, 0x78, 0x5e,
-	0x39, 0xc0, 0xbc, 0xde, 0xd8, 0x1b, 0x52, 0x5e, 0x35, 0x93, 0xbf, 0xad,
-	0x50, 0xce, 0x07, 0xab, 0x50, 0x61, 0xc9, 0x8a, 0xd1, 0x6c, 0xa9, 0xa6,
-	0x54, 0x4b, 0x2f, 0xd7, 0x9b, 0x2e, 0xfa, 0x60, 0x25, 0x63, 0xfd, 0x18,
-	0x6b, 0x74, 0xf9, 0x09, 0xa9, 0x25, 0xec, 0x5f, 0x94, 0x2d, 0xc4, 0xc2,
-	0x82, 0x1b, 0x3c, 0x78, 0x20, 0xa0, 0xb6, 0xc8, 0x99, 0xed, 0x67, 0xf3,
-	0x1d, 0x2e, 0x39, 0x3b, 0xf5, 0x5c, 0x5e, 0x6a, 0xb9, 0xe4, 0x82, 0xd2,
-	0x7a, 0x21, 0xd4, 0x4e, 0x8a, 0x8d, 0x86, 0x5b, 0x3f, 0x9a, 0xf4, 0xc9,
-	0xf9, 0xfa, 0x11, 0x07, 0x7b, 0x6d, 0xcf, 0xa4, 0x69, 0xee, 0x69, 0xd6,
-	0x86, 0xb6, 0x38, 0x65, 0x6f, 0x39, 0x32, 0x70, 0x4e, 0x51, 0x5b, 0x26,
-	0x94, 0x1b, 0xe9, 0xfc, 0xb7, 0x2a, 0x89, 0x91, 0x34, 0xe5, 0x7c, 0xdc,
-	0x92, 0x69, 0x8a, 0x32, 0x95, 0xce, 0x16, 0x55, 0xe1, 0xf2, 0x34, 0x34,
-	0x46, 0x2d, 0xce, 0xeb, 0x4c, 0x4e, 0x81, 0x68, 0xb2, 0x1d, 0xe2, 0xff,
-	0xea, 0x80, 0x60, 0xa8, 0x4a, 0xe6, 0xe4, 0xb9, 0x69, 0xa9, 0x31, 0x8a,
-	0xe0, 0x93, 0x34, 0xd7, 0xc6, 0x95, 0x8d, 0xc0, 0xab, 0x93, 0xf6, 0xde,
-	0x7b, 0xf1, 0x2c, 0xb8, 0x75, 0xe6, 0xe1, 0x11, 0xeb, 0x2c, 0x83, 0xd0,
-	0x3f, 0x8c, 0x33, 0x19, 0xc1, 0x94, 0xc3, 0xc4, 0x94, 0x91, 0x14, 0xf1,
-	0x66, 0x4b, 0xde, 0x3e, 0x97, 0xa5, 0x7f, 0x44, 0x9f, 0x7f, 0x9a, 0x58,
-	0xf5, 0x28, 0xec, 0xbd, 0xf7, 0x86, 0xe2, 0x59, 0x85, 0x48, 0xae, 0x4b,
-	0xd9, 0x91, 0x97, 0x18, 0x9b, 0x66, 0x8c, 0xb5, 0x2b, 0xdb, 0x17, 0x3a,
-	0x94, 0xee, 0x85, 0x1e, 0x65, 0x77, 0x5e, 0x7a, 0xd6, 0xc9, 0xd6, 0x07,
-	0x4e, 0xec, 0x52, 0x76, 0xcc, 0xf5, 0x29, 0xc4, 0xb4, 0x01, 0x4f, 0xa2,
-	0x5f, 0xe9, 0x59, 0xb0, 0xe7, 0xe7, 0x5d, 0xec, 0xbb, 0x76, 0x18, 0xa5,
-	0x7e, 0x5e, 0xfe, 0xdf, 0x2b, 0x28, 0xff, 0x5b, 0x31, 0xb0, 0x4d, 0x31,
-	0xcd, 0xdb, 0xe2, 0x7f, 0x27, 0xf6, 0x30, 0x9f, 0x8d, 0xb3, 0x36, 0x1a,
-	0x55, 0x18, 0x64, 0xdf, 0x31, 0xaa, 0xdf, 0x5a, 0xdc, 0x2f, 0x13, 0x99,
-	0xe4, 0x3c, 0x85, 0xf8, 0x2b, 0xd2, 0xe5, 0xe4, 0xe1, 0x1f, 0xc8, 0xff,
-	0x81, 0xa2, 0x5c, 0x3d, 0x72, 0xa6, 0xc0, 0x7d, 0xfd, 0xbc, 0xd9, 0xf1,
-	0xc9, 0xeb, 0x72, 0x31, 0xd7, 0x63, 0x9c, 0xf8, 0xf4, 0x80, 0xa2, 0xa6,
-	0x9e, 0xb1, 0xe5, 0x5a, 0xba, 0xcc, 0x18, 0x1e, 0xb5, 0x62, 0xd8, 0x96,
-	0x6b, 0x5d, 0x51, 0xae, 0xb5, 0xb9, 0x2e, 0xeb, 0x1c, 0x17, 0xf1, 0x7a,
-	0xeb, 0xe2, 0xa4, 0x9c, 0x37, 0x93, 0xd9, 0xa5, 0xc8, 0x26, 0x72, 0x9c,
-	0x30, 0x2b, 0xb4, 0x1e, 0x65, 0xa7, 0x75, 0xfe, 0x4c, 0xce, 0x7e, 0xc9,
-	0x5e, 0x7f, 0x49, 0x2e, 0xa9, 0xe3, 0x2b, 0xfc, 0x1d, 0x33, 0x72, 0x1e,
-	0xdb, 0x34, 0x5f, 0xd3, 0x83, 0x7e, 0x91, 0xe5, 0xac, 0x2e, 0xb2, 0xc8,
-	0xb9, 0x92, 0x92, 0x3c, 0x5f, 0x2b, 0xca, 0x23, 0xb6, 0xba, 0x6e, 0xa7,
-	0xd2, 0xff, 0x09, 0xbe, 0x9d, 0xb1, 0xcf, 0x9c, 0x94, 0xe4, 0xf1, 0x27,
-	0x84, 0xff, 0x8b, 0xad, 0xe3, 0xd3, 0xc3, 0x78, 0x95, 0xf7, 0x7f, 0x9e,
-	0x29, 0xc9, 0xe5, 0xc4, 0xfc, 0x5c, 0xe9, 0x2c, 0x1d, 0x5b, 0x4a, 0x23,
-	0xa2, 0x8f, 0xd1, 0x8f, 0x6c, 0xf9, 0xe4, 0x2c, 0x5d, 0x63, 0xe1, 0xb2,
-	0x35, 0xf7, 0x8a, 0x26, 0xd9, 0x2f, 0xe3, 0x6c, 0xfe, 0xd7, 0xed, 0xd7,
-	0x94, 0xab, 0x60, 0x8f, 0x2c, 0xb4, 0x5f, 0x27, 0x6d, 0x39, 0x73, 0xa2,
-	0xe0, 0x99, 0x39, 0x60, 0xce, 0xe0, 0xb2, 0x89, 0x11, 0x3c, 0xa9, 0x9b,
-	0xe6, 0xd3, 0xcd, 0x9a, 0x9c, 0x15, 0xba, 0x50, 0x6b, 0xcd, 0x85, 0xa0,
-	0x57, 0x69, 0xb2, 0x77, 0x27, 0xe7, 0x4d, 0xfa, 0xa8, 0x03, 0x91, 0x5d,
-	0x7c, 0xa0, 0x64, 0x7b, 0x39, 0x07, 0x97, 0xa6, 0x7e, 0x44, 0x37, 0xa5,
-	0xf3, 0x70, 0x32, 0x73, 0xb9, 0x51, 0x27, 0x5d, 0x96, 0x4e, 0x9e, 0xd5,
-	0xc5, 0x5f, 0x99, 0x7d, 0xe8, 0xab, 0xf3, 0xc4, 0x0f, 0x63, 0xba, 0xdb,
-	0xc2, 0x6a, 0x47, 0x89, 0x4f, 0x26, 0x18, 0x3b, 0x8f, 0x1b, 0x4b, 0x58,
-	0xca, 0xbd, 0x8c, 0x57, 0xaf, 0xfd, 0xcf, 0x9c, 0xf8, 0x8b, 0xde, 0xd2,
-	0x6d, 0x9d, 0x79, 0xfa, 0xa4, 0xe5, 0xd6, 0xa8, 0xe4, 0xa1, 0x1f, 0x36,
-	0xc9, 0x19, 0xa8, 0xf2, 0x44, 0xe0, 0x6b, 0xb2, 0xbf, 0x55, 0x96, 0x98,
-	0xfd, 0xea, 0x05, 0x4d, 0x74, 0xa3, 0x35, 0x9f, 0xd1, 0x44, 0xae, 0x1e,
-	0x7d, 0xdc, 0xfa, 0x1f, 0xce, 0x96, 0x4d, 0xfb, 0x34, 0x89, 0x1d, 0xdf,
-	0xc6, 0x36, 0x2b, 0x27, 0x9c, 0x4e, 0xdc, 0x66, 0xe9, 0xe0, 0x64, 0xe2,
-	0x56, 0xeb, 0x73, 0x3a, 0x11, 0xb3, 0x3e, 0xff, 0x24, 0x61, 0xeb, 0x26,
-	0x97, 0xa8, 0xb7, 0x3e, 0xe7, 0x13, 0xf6, 0xd9, 0xe9, 0xd9, 0x84, 0x66,
-	0x7d, 0x3e, 0x9f, 0x88, 0x58, 0x9f, 0x67, 0x13, 0xb7, 0x5c, 0xe7, 0x8b,
-	0x3f, 0xff, 0x0f, 0x4c, 0xd3, 0x85, 0x76, 0xdc, 0x3a, 0x00, 0x00, 0x00 };
+	0xad, 0x7b, 0x0d, 0x70, 0x94, 0xf7, 0x79, 0xe7, 0xef, 0xbf, 0x1f, 0xd2,
+	0xae, 0xb4, 0x5a, 0xad, 0xf0, 0x82, 0x57, 0x89, 0x52, 0xf6, 0xf5, 0xbe,
+	0x2b, 0x2d, 0x96, 0x80, 0x77, 0x41, 0x04, 0x11, 0x6d, 0xcd, 0x56, 0x08,
+	0x21, 0x40, 0xd8, 0x32, 0x56, 0x92, 0x25, 0xc7, 0xd4, 0x2a, 0xc8, 0x20,
+	0xdb, 0x18, 0x8b, 0x86, 0xe6, 0xe4, 0xd6, 0xad, 0xd6, 0x92, 0xc0, 0x60,
+	0x56, 0xbc, 0x22, 0x82, 0x08, 0x77, 0xee, 0x26, 0xb2, 0x25, 0x2c, 0xec,
+	0xac, 0x58, 0x3b, 0xbd, 0xeb, 0xc5, 0x33, 0xc9, 0x58, 0x67, 0x6c, 0x4c,
+	0x72, 0xfe, 0xc8, 0x75, 0x3a, 0x3d, 0xf7, 0xe6, 0xee, 0xca, 0xf8, 0x83,
+	0xd8, 0x6e, 0x8c, 0xdd, 0x4c, 0x3a, 0x27, 0x52, 0xdb, 0xef, 0xfd, 0x9e,
+	0xf7, 0xdd, 0x05, 0xe2, 0xba, 0xd3, 0x99, 0xce, 0x69, 0x66, 0x67, 0xa5,
+	0xf7, 0xe3, 0xf9, 0x3f, 0xdf, 0xcf, 0xef, 0x79, 0xfe, 0x7f, 0xd5, 0x03,
+	0x15, 0x28, 0xfe, 0x54, 0xf1, 0xd3, 0x3c, 0x30, 0x78, 0x70, 0xd5, 0x8a,
+	0xe6, 0x15, 0xf6, 0x05, 0x97, 0xc7, 0x23, 0x37, 0xbf, 0xaa, 0x80, 0xde,
+	0x0f, 0xf0, 0x6f, 0xfa, 0xf9, 0xca, 0xbf, 0xed, 0x35, 0xfb, 0xc7, 0x0d,
+	0x84, 0x4a, 0x7c, 0xc9, 0x07, 0x3e, 0x57, 0xea, 0xd2, 0xd7, 0xda, 0x74,
+	0xf8, 0xdc, 0xa9, 0x93, 0xa9, 0xdd, 0x3a, 0x90, 0xce, 0x37, 0x46, 0x37,
+	0xe0, 0x53, 0x2b, 0x1b, 0xf6, 0x40, 0xae, 0x7f, 0x25, 0xf5, 0xc9, 0xd0,
+	0x4f, 0xd6, 0x6a, 0x1f, 0x4f, 0xb9, 0xe1, 0x0b, 0xa5, 0x4e, 0x23, 0x54,
+	0x0f, 0x5f, 0x1d, 0xdf, 0xf9, 0x0f, 0x0d, 0xd5, 0x6e, 0x04, 0x4b, 0xb4,
+	0x5a, 0x30, 0x62, 0x22, 0xeb, 0x4b, 0x0d, 0xa0, 0x7c, 0x0d, 0xf0, 0x6e,
+	0x2e, 0x6e, 0x8c, 0x00, 0xe3, 0xae, 0x54, 0x3c, 0xfa, 0x22, 0x0c, 0x1c,
+	0x2a, 0x44, 0xd1, 0xce, 0xcf, 0x66, 0xf3, 0x33, 0x2b, 0xea, 0x45, 0xd6,
+	0xcd, 0xe7, 0x76, 0x35, 0x03, 0x1b, 0x73, 0x06, 0x0e, 0x9b, 0xf0, 0xd5,
+	0xa6, 0x1e, 0xc6, 0x3a, 0x7e, 0x07, 0x53, 0x83, 0x78, 0x7d, 0x2c, 0x16,
+	0x7d, 0x0a, 0x5a, 0x46, 0x77, 0x6b, 0x83, 0x40, 0x63, 0x7f, 0x9f, 0xd2,
+	0x7a, 0xdf, 0x50, 0x5a, 0xf7, 0x98, 0x82, 0x4f, 0xf1, 0xb9, 0xc6, 0xbc,
+	0x7c, 0x0f, 0xe2, 0xd6, 0xbc, 0x0f, 0x97, 0xdc, 0xb2, 0xfe, 0xef, 0x52,
+	0xdf, 0x0a, 0x1e, 0xbd, 0x05, 0xa3, 0xe4, 0xc1, 0x9b, 0x52, 0x78, 0xb2,
+	0x39, 0x1e, 0x19, 0x86, 0xdc, 0x8f, 0x62, 0x43, 0x41, 0xbe, 0x35, 0x4a,
+	0x6d, 0x59, 0xa3, 0x86, 0x65, 0x9d, 0x31, 0xca, 0x91, 0x0d, 0x69, 0x11,
+	0x40, 0x61, 0xd8, 0x70, 0x21, 0x1d, 0x6a, 0x8b, 0x7a, 0xa0, 0x45, 0xee,
+	0xc1, 0x3f, 0x51, 0xe6, 0x74, 0xc2, 0x0b, 0xe7, 0xf9, 0x5e, 0x94, 0x63,
+	0x3e, 0xe4, 0x68, 0xed, 0xc9, 0x9c, 0x65, 0x5d, 0xd0, 0x3d, 0x38, 0x43,
+	0xfd, 0x0c, 0xe7, 0xff, 0xc9, 0x9a, 0xa7, 0x6e, 0x46, 0xf5, 0xd2, 0xfa,
+	0x3e, 0x4c, 0x85, 0x2c, 0x6b, 0x9a, 0xf7, 0x0e, 0xe7, 0x4b, 0x7a, 0xb6,
+	0x2c, 0x97, 0x6e, 0x59, 0xbb, 0xf5, 0xdf, 0x58, 0xbb, 0x7e, 0xeb, 0x59,
+	0xcb, 0x7a, 0xcc, 0xb8, 0x09, 0x67, 0x27, 0xda, 0xd5, 0x96, 0xd9, 0x25,
+	0xc1, 0xcd, 0x93, 0x16, 0x2e, 0x18, 0x08, 0xb9, 0x52, 0x1d, 0x6a, 0xf3,
+	0x6c, 0xa7, 0xda, 0x58, 0xd8, 0xae, 0x3a, 0xa6, 0xbf, 0xa5, 0x3a, 0x67,
+	0x7b, 0xd5, 0xa6, 0x42, 0x04, 0x33, 0x66, 0x18, 0xd3, 0x66, 0x46, 0xb5,
+	0xcf, 0xf6, 0x28, 0x47, 0x8e, 0x41, 0xd5, 0x56, 0x28, 0xd1, 0xba, 0xae,
+	0xc7, 0xcd, 0xb9, 0x14, 0x8e, 0x98, 0xe5, 0x5c, 0x67, 0xc1, 0xfa, 0x49,
+	0xc3, 0x02, 0xe5, 0x34, 0x70, 0xb4, 0xf0, 0x18, 0xb6, 0x4d, 0x5a, 0x56,
+	0x3e, 0x09, 0xe4, 0x0b, 0xc0, 0x0f, 0xcc, 0x58, 0x77, 0xbf, 0xb2, 0xac,
+	0x4d, 0x71, 0x6b, 0xe9, 0x65, 0xa3, 0x31, 0xf1, 0x12, 0xfe, 0xaf, 0x35,
+	0x15, 0x46, 0x36, 0x40, 0x1a, 0xc7, 0x68, 0xb3, 0xfb, 0xc6, 0xe0, 0x2b,
+	0x4f, 0x8d, 0xe2, 0x17, 0x39, 0xf8, 0xca, 0x52, 0x59, 0x5c, 0xc8, 0x0d,
+	0x87, 0x7c, 0x88, 0x45, 0x36, 0xab, 0xec, 0xa0, 0x0b, 0xda, 0xc0, 0xdb,
+	0xd0, 0xa2, 0xb4, 0xc7, 0xc5, 0xf3, 0x4a, 0x9b, 0x7f, 0x09, 0x5a, 0xfa,
+	0x37, 0x4a, 0xeb, 0xac, 0x75, 0x23, 0xed, 0x8a, 0xfb, 0xf0, 0x93, 0x06,
+	0xb1, 0xc9, 0x28, 0x56, 0xd8, 0xb6, 0xc9, 0x62, 0xd9, 0x35, 0xdb, 0xa4,
+	0x30, 0x4c, 0xbe, 0x0e, 0x93, 0xaf, 0x97, 0x0d, 0x2d, 0xf2, 0x24, 0xac,
+	0xa5, 0x7d, 0x86, 0xdc, 0x4b, 0x61, 0xb4, 0x60, 0x45, 0x83, 0xa9, 0x4b,
+	0xe4, 0x17, 0xd9, 0x2f, 0xa5, 0x7c, 0xd9, 0xea, 0xd4, 0xa7, 0xd6, 0x6b,
+	0x6b, 0x22, 0x78, 0xa1, 0x10, 0xc6, 0x73, 0x85, 0x10, 0x9e, 0x2d, 0xb4,
+	0xc3, 0x2c, 0x20, 0xb8, 0xad, 0xf0, 0x45, 0x7e, 0x6c, 0x21, 0xc0, 0xe7,
+	0xc9, 0x77, 0x70, 0x6b, 0xc1, 0xd3, 0x5b, 0x96, 0x42, 0xf7, 0x4f, 0x73,
+	0x43, 0x56, 0x85, 0x8e, 0xde, 0x9a, 0x94, 0x9e, 0xbe, 0x55, 0x05, 0x5a,
+	0xe8, 0x87, 0xdd, 0xaf, 0xe4, 0x5b, 0x3c, 0xfa, 0x71, 0x3f, 0xbc, 0xd4,
+	0xff, 0xc6, 0x82, 0x65, 0x8d, 0x18, 0x07, 0x56, 0xee, 0x6a, 0xf9, 0x8b,
+	0xf9, 0x6e, 0xbd, 0x0b, 0xd9, 0x42, 0x1f, 0x10, 0x4c, 0xf1, 0x9b, 0xa1,
+	0xb8, 0xbd, 0xa9, 0x3d, 0x7a, 0xee, 0x01, 0x8f, 0xe3, 0xcf, 0xe4, 0x81,
+	0x7a, 0x7f, 0xce, 0x24, 0x0f, 0xe6, 0xe1, 0x20, 0x2a, 0xa2, 0x94, 0xef,
+	0xe7, 0xe4, 0x33, 0x81, 0x1f, 0x16, 0x74, 0xf2, 0xd6, 0x44, 0x1e, 0xa3,
+	0xe4, 0xcf, 0x87, 0x5d, 0x13, 0xda, 0x78, 0x16, 0xda, 0x91, 0x29, 0x2c,
+	0x47, 0x3a, 0x1c, 0xa2, 0x0f, 0xfe, 0x39, 0x1c, 0x1a, 0x5d, 0x38, 0x6e,
+	0x62, 0x55, 0x28, 0x45, 0xfb, 0x26, 0xf1, 0x70, 0x19, 0xe2, 0xbd, 0x1f,
+	0x2b, 0x85, 0xd7, 0xe2, 0x5d, 0x18, 0xa3, 0x3c, 0x5d, 0x79, 0x3f, 0xee,
+	0x9f, 0xa8, 0xc0, 0xbd, 0x13, 0x16, 0xee, 0x4b, 0x22, 0x55, 0x41, 0x79,
+	0x12, 0xc9, 0x78, 0xf4, 0x3d, 0x78, 0xd0, 0x9e, 0xef, 0x62, 0x2c, 0x6d,
+	0x40, 0xba, 0xcc, 0x87, 0x0d, 0xf9, 0x00, 0xe3, 0x31, 0x8d, 0xd3, 0x93,
+	0x3e, 0x78, 0x57, 0xbb, 0x30, 0x15, 0x2e, 0x43, 0xa2, 0xde, 0xc5, 0x4f,
+	0x38, 0xd8, 0x36, 0x59, 0x17, 0xdc, 0x68, 0x7a, 0xb0, 0xd7, 0x74, 0x61,
+	0x68, 0xc2, 0xb2, 0xda, 0x0d, 0x0b, 0x57, 0x57, 0x87, 0xf0, 0x3c, 0xf5,
+	0x77, 0xc0, 0x8c, 0xe0, 0x6c, 0xe1, 0x51, 0xf2, 0x12, 0x76, 0xf8, 0x35,
+	0xc9, 0xbb, 0x49, 0xde, 0x4d, 0xf2, 0x6d, 0x0a, 0x9f, 0xe7, 0x19, 0x33,
+	0x06, 0xe5, 0xf2, 0x93, 0x87, 0x4a, 0xf4, 0x93, 0x8f, 0x58, 0xd2, 0x82,
+	0x2b, 0xa9, 0x65, 0x77, 0x31, 0x79, 0x2d, 0xad, 0xb7, 0xac, 0x8f, 0x57,
+	0x8b, 0x2c, 0xb4, 0xb9, 0xab, 0x4b, 0x62, 0xf4, 0xf7, 0xaa, 0x18, 0x57,
+	0x7f, 0x4b, 0xbd, 0x3d, 0x5e, 0xf0, 0x63, 0x70, 0xc2, 0xf6, 0xdb, 0x83,
+	0x65, 0xe4, 0x5b, 0xf8, 0x2a, 0xe8, 0x71, 0xc6, 0x68, 0x3c, 0xc3, 0x18,
+	0xc5, 0x56, 0xf2, 0x7c, 0x9f, 0x19, 0x6f, 0xd9, 0xae, 0x3c, 0xd8, 0x94,
+	0x0f, 0x07, 0xdb, 0x6f, 0xe0, 0x93, 0xf2, 0x4a, 0x0c, 0x52, 0xd6, 0x10,
+	0xf9, 0x0b, 0x63, 0x37, 0xf9, 0x7c, 0xae, 0xc8, 0xe7, 0x74, 0x41, 0xd6,
+	0xfa, 0x3c, 0xaf, 0x25, 0x3e, 0x91, 0x5d, 0x94, 0x0a, 0x2b, 0x54, 0x04,
+	0xb0, 0x3d, 0xff, 0x26, 0x6d, 0x51, 0x87, 0xbf, 0xa0, 0x0d, 0x5e, 0x60,
+	0x8c, 0xfc, 0xf0, 0x9a, 0xbf, 0x88, 0x3d, 0x1e, 0xa1, 0x1d, 0xb4, 0xd3,
+	0x59, 0x04, 0xd0, 0x5b, 0x48, 0xe3, 0xd0, 0x24, 0xd2, 0x33, 0xc6, 0x31,
+	0xc6, 0xfb, 0x12, 0xb8, 0xf5, 0xf2, 0x74, 0x48, 0xaf, 0xc0, 0xee, 0xe9,
+	0x30, 0x06, 0x0a, 0x6d, 0x30, 0x27, 0xc2, 0xd8, 0x47, 0xdf, 0xbc, 0x92,
+	0x4c, 0xdf, 0x17, 0x84, 0xf0, 0x1e, 0xc6, 0xfd, 0x7c, 0xe7, 0xb1, 0xc9,
+	0x30, 0xfa, 0xa9, 0xa3, 0xcd, 0xc9, 0x78, 0x8b, 0x9f, 0xd7, 0xf6, 0xf2,
+	0xda, 0x61, 0xea, 0xff, 0xbc, 0x31, 0x86, 0xde, 0x6e, 0x2d, 0x01, 0x84,
+	0xb1, 0xc7, 0x44, 0x88, 0x2e, 0xfc, 0x08, 0xf3, 0x5b, 0xe2, 0x3c, 0xff,
+	0xbe, 0xa7, 0x50, 0x41, 0x39, 0x83, 0x88, 0xe8, 0x9f, 0x58, 0xde, 0x66,
+	0xcb, 0xfa, 0xbe, 0x11, 0xbf, 0xf8, 0x96, 0xdb, 0x83, 0x87, 0x0a, 0x2e,
+	0x0c, 0x4e, 0x57, 0xe0, 0x0f, 0x27, 0x3c, 0xb8, 0xb3, 0xbe, 0x02, 0x07,
+	0xa6, 0xd3, 0x18, 0x99, 0xac, 0x40, 0xdf, 0x04, 0x96, 0xee, 0x31, 0x46,
+	0x6a, 0xca, 0xa0, 0x2d, 0xb4, 0x23, 0x81, 0xab, 0xb4, 0xc3, 0x43, 0xd3,
+	0x81, 0x60, 0x66, 0x32, 0x84, 0xc1, 0x59, 0x3f, 0x9f, 0x77, 0xf1, 0xf9,
+	0x72, 0x18, 0xab, 0x62, 0x83, 0x21, 0x08, 0x8f, 0x95, 0xd8, 0x3f, 0xed,
+	0xc7, 0x03, 0x13, 0x21, 0xec, 0x9b, 0x6c, 0xc6, 0xb8, 0x99, 0xc6, 0x51,
+	0xe6, 0x8e, 0x1f, 0x24, 0xb5, 0xee, 0x7d, 0x4a, 0x4b, 0x6f, 0x54, 0x69,
+	0x34, 0x24, 0xbd, 0xb8, 0xc4, 0x3c, 0xe4, 0x4d, 0x36, 0xb6, 0x3c, 0xcb,
+	0xdc, 0x50, 0x96, 0x0a, 0xf3, 0x6f, 0xed, 0x08, 0x63, 0x36, 0xed, 0x75,
+	0xad, 0x06, 0x16, 0x4b, 0xfc, 0x86, 0x83, 0x5b, 0xcc, 0x50, 0x70, 0x4b,
+	0xa1, 0x2e, 0xb8, 0xd9, 0x8c, 0x04, 0x37, 0x33, 0xbe, 0x36, 0x8a, 0x3f,
+	0x9a, 0x3e, 0x1c, 0x4b, 0x7e, 0x6a, 0xf5, 0xd6, 0xd8, 0xf9, 0x2c, 0xb8,
+	0x6d, 0x52, 0xcb, 0x4e, 0x41, 0x33, 0x58, 0x0d, 0x30, 0x36, 0xeb, 0xa1,
+	0xfd, 0x14, 0x6a, 0xf4, 0x66, 0xe6, 0xf1, 0x10, 0xf6, 0x33, 0xa7, 0xfc,
+	0x15, 0x73, 0x4a, 0xdf, 0xf1, 0x58, 0x68, 0x1c, 0x7e, 0xea, 0x1b, 0xd8,
+	0x75, 0x2e, 0x4c, 0x9b, 0x77, 0xe2, 0x51, 0xf2, 0xb5, 0x79, 0x4d, 0x18,
+	0xf7, 0x16, 0x42, 0xc1, 0x4e, 0xda, 0xef, 0xbd, 0x7c, 0x24, 0xb8, 0x81,
+	0xb6, 0x7c, 0x3b, 0xaf, 0x45, 0xe7, 0xf1, 0x8f, 0xe2, 0x4f, 0x09, 0xb8,
+	0x80, 0x3d, 0xc7, 0xbd, 0x98, 0x0f, 0xcb, 0x5a, 0xd4, 0xb9, 0xf9, 0x82,
+	0x15, 0xd0, 0xf5, 0xd3, 0xfb, 0xa8, 0xeb, 0x6f, 0x17, 0x02, 0x78, 0xc0,
+	0xd4, 0x12, 0x3f, 0x54, 0x01, 0xea, 0xd4, 0x47, 0x3d, 0x30, 0xc1, 0x2c,
+	0x91, 0xe7, 0x92, 0x88, 0x2e, 0x71, 0x72, 0xed, 0x81, 0x69, 0xf1, 0x13,
+	0xda, 0xde, 0xa4, 0x0f, 0xd0, 0x7f, 0x7e, 0x78, 0x2d, 0x56, 0xb5, 0x50,
+	0xd6, 0xce, 0xdd, 0x09, 0xfa, 0x8b, 0xa3, 0xa3, 0x13, 0x93, 0xa2, 0x07,
+	0x6d, 0x1c, 0xae, 0x34, 0x56, 0xae, 0xfa, 0x2b, 0xeb, 0xd2, 0x62, 0xd1,
+	0x47, 0x08, 0x43, 0xd4, 0xe1, 0x69, 0xd3, 0xb2, 0xae, 0xae, 0xfe, 0xd0,
+	0x6a, 0xb9, 0x59, 0xf4, 0x22, 0xb2, 0x3e, 0xaf, 0xa4, 0x8e, 0xd4, 0xe8,
+	0xc1, 0xff, 0x0f, 0xbe, 0xf2, 0x1d, 0xab, 0xd7, 0x96, 0x4f, 0xfc, 0xc5,
+	0x43, 0x5f, 0x7c, 0x94, 0xb4, 0x5d, 0xe8, 0x25, 0xbd, 0x07, 0x4d, 0xeb,
+	0xa3, 0xda, 0xd4, 0x67, 0x56, 0xcb, 0x5a, 0x7d, 0x60, 0x41, 0xfd, 0x0f,
+	0x5e, 0x0f, 0x63, 0x7f, 0xa1, 0x85, 0xba, 0x6b, 0xc7, 0x63, 0xd4, 0xe1,
+	0x61, 0x53, 0x72, 0x62, 0x84, 0xfe, 0x5c, 0x47, 0xff, 0xf6, 0xa8, 0x8d,
+	0x66, 0x1e, 0x9b, 0xc7, 0xb2, 0xd8, 0x44, 0x7f, 0xbf, 0x98, 0x8b, 0xb5,
+	0x3c, 0x0d, 0x2d, 0x4b, 0x19, 0x82, 0x9d, 0xd4, 0x71, 0xbb, 0xa9, 0x75,
+	0x8a, 0x4d, 0xdb, 0x99, 0x97, 0x5e, 0xcc, 0x45, 0x82, 0x6d, 0x05, 0xd1,
+	0x77, 0x5d, 0x70, 0x43, 0xe1, 0xab, 0xb4, 0xbd, 0xc2, 0xba, 0xe5, 0x3e,
+	0xe6, 0x99, 0x3b, 0xe1, 0xd8, 0xd5, 0xb1, 0xdd, 0x6b, 0xc9, 0xc6, 0xde,
+	0x0f, 0x99, 0x9f, 0xb2, 0x8b, 0x9d, 0x6b, 0x83, 0xbc, 0x56, 0xbd, 0x1a,
+	0xc1, 0x3b, 0xe8, 0x07, 0x77, 0xd3, 0x0f, 0xae, 0xae, 0xfe, 0xd4, 0x8a,
+	0xde, 0xe4, 0xf8, 0x41, 0xdb, 0xa4, 0x27, 0xd8, 0x41, 0x3d, 0x6d, 0x34,
+	0x14, 0xa6, 0x8d, 0x1c, 0x7a, 0xaf, 0x61, 0x87, 0xf4, 0xd4, 0x59, 0x23,
+	0xcd, 0x3c, 0xf2, 0xbb, 0xf0, 0xd4, 0x60, 0xea, 0x69, 0xe3, 0x51, 0x44,
+	0x1d, 0xdf, 0xc1, 0xbe, 0x09, 0x3f, 0xb2, 0x77, 0x86, 0x30, 0xd3, 0x10,
+	0xc2, 0x83, 0xa4, 0x7d, 0x25, 0xd9, 0xd8, 0xff, 0x3a, 0x75, 0x30, 0x55,
+	0x23, 0xd7, 0xd2, 0xf8, 0x91, 0xf1, 0x30, 0x70, 0x93, 0xb3, 0xf6, 0xac,
+	0xc4, 0xe8, 0x6c, 0x33, 0x0e, 0x17, 0x32, 0xca, 0xc9, 0x9b, 0x5a, 0x67,
+	0x1a, 0x3f, 0xb7, 0x24, 0x97, 0xce, 0x9a, 0xcc, 0x71, 0xd4, 0xc7, 0x28,
+	0xfd, 0x68, 0x38, 0x5f, 0x17, 0xdc, 0x44, 0x3f, 0x7a, 0x34, 0x2f, 0x32,
+	0xc5, 0x0d, 0xc3, 0x5d, 0xcb, 0xda, 0x4c, 0xfd, 0x98, 0x76, 0xcd, 0xaf,
+	0x0e, 0xe9, 0x47, 0x31, 0x6e, 0xf3, 0x36, 0xa8, 0x32, 0xc4, 0x18, 0x0c,
+	0x99, 0xea, 0x72, 0xfd, 0x00, 0x1e, 0xb5, 0xaf, 0x85, 0x83, 0x3b, 0x26,
+	0xd3, 0x2e, 0x97, 0x8e, 0x50, 0x65, 0xaa, 0x5d, 0xed, 0x60, 0xdd, 0xed,
+	0x98, 0xec, 0x50, 0x1d, 0xb3, 0x12, 0x03, 0x9d, 0x6a, 0x33, 0x6b, 0x6e,
+	0x9a, 0x35, 0x37, 0xcd, 0x9a, 0x9b, 0x26, 0x1f, 0x69, 0xd6, 0xda, 0xb6,
+	0xc2, 0xa0, 0xda, 0x2a, 0xfa, 0xa7, 0x7f, 0x3d, 0x6b, 0x3a, 0x38, 0x82,
+	0x39, 0x28, 0xb8, 0xa9, 0xb0, 0xc2, 0xe5, 0x60, 0xbb, 0x41, 0x55, 0xc4,
+	0x32, 0xbe, 0x0a, 0x9d, 0xb5, 0xcc, 0x1c, 0x54, 0x5b, 0x58, 0x6f, 0x33,
+	0xb6, 0x2e, 0x63, 0x03, 0xef, 0xb0, 0xce, 0xbe, 0xc6, 0x3a, 0x9b, 0x4f,
+	0x32, 0xae, 0x96, 0x5f, 0xb5, 0x7a, 0x17, 0x3b, 0x35, 0x61, 0x84, 0xfc,
+	0x7e, 0x9f, 0x36, 0x9b, 0x67, 0x2d, 0x6d, 0x77, 0x2b, 0xec, 0xd1, 0x51,
+	0x5d, 0xcb, 0x9c, 0x7a, 0xb8, 0xc0, 0x3a, 0x60, 0xc4, 0x5a, 0xde, 0xa7,
+	0x62, 0x0f, 0xeb, 0x5e, 0x5c, 0xbd, 0x89, 0x60, 0x47, 0x6f, 0xc3, 0xb1,
+	0x89, 0x72, 0xf4, 0x27, 0xd3, 0x8b, 0x7c, 0xc4, 0x2a, 0x9d, 0xcd, 0x78,
+	0x98, 0x4b, 0xab, 0x48, 0x2a, 0x4e, 0xbf, 0x41, 0xfa, 0x38, 0xeb, 0xc4,
+	0x98, 0xf9, 0x55, 0xe4, 0x59, 0x4f, 0x67, 0x0c, 0x0f, 0x5e, 0xcb, 0xaf,
+	0x60, 0x9e, 0x8b, 0x1b, 0x01, 0x55, 0xc1, 0xf8, 0x4d, 0x21, 0x67, 0x4a,
+	0x7e, 0xb2, 0xac, 0x19, 0xe1, 0x21, 0x1e, 0x4f, 0x0f, 0x43, 0x72, 0x96,
+	0xb5, 0xf4, 0x9e, 0x64, 0x19, 0xd6, 0xc5, 0x83, 0x58, 0xaa, 0xf7, 0xaa,
+	0xce, 0x42, 0xdc, 0x38, 0x8f, 0x6f, 0xa9, 0xbb, 0x67, 0x53, 0x8c, 0xed,
+	0x0c, 0x75, 0x53, 0x81, 0x4b, 0x61, 0xe1, 0x11, 0xd5, 0x5e, 0xdd, 0x85,
+	0x77, 0xef, 0x52, 0x08, 0xe9, 0x69, 0x5c, 0x68, 0x0e, 0xd1, 0xaf, 0x3a,
+	0x89, 0x31, 0xa2, 0x70, 0xcf, 0x45, 0x82, 0x5b, 0x69, 0x8b, 0xca, 0xb9,
+	0x3a, 0xda, 0x87, 0xbe, 0x47, 0x1d, 0xb6, 0x51, 0x87, 0x5b, 0xa6, 0x11,
+	0xaa, 0x48, 0xf5, 0xa8, 0x8e, 0x42, 0xbb, 0x6a, 0x2f, 0x68, 0xd4, 0x93,
+	0xe8, 0xe4, 0x3b, 0xc4, 0x4a, 0xe2, 0x2b, 0x25, 0x5b, 0x8a, 0xbf, 0xde,
+	0x68, 0xcf, 0x8c, 0x4b, 0x62, 0x6e, 0xdd, 0xf2, 0x14, 0xe3, 0xd1, 0x45,
+	0xbe, 0x84, 0x07, 0x1f, 0xaa, 0x1b, 0xac, 0xa5, 0x57, 0x92, 0x4c, 0x9e,
+	0x15, 0x29, 0x1c, 0x2f, 0x74, 0xd1, 0x2e, 0xab, 0x8b, 0xfe, 0x15, 0x0a,
+	0x6e, 0x9c, 0x6c, 0x57, 0x1b, 0x67, 0x17, 0x05, 0xbb, 0x69, 0xc3, 0xee,
+	0xd9, 0x88, 0xd0, 0xe5, 0xfa, 0x62, 0xdb, 0x34, 0x5c, 0xfa, 0xbf, 0x64,
+	0xcb, 0x6f, 0x93, 0x96, 0xd8, 0xd3, 0x5f, 0xf2, 0xd3, 0xe0, 0xdd, 0x93,
+	0x69, 0xbc, 0xbb, 0xda, 0xcb, 0x9a, 0x5a, 0xc2, 0x14, 0x55, 0xc5, 0xef,
+	0xd3, 0x2e, 0xe8, 0x83, 0xaa, 0x53, 0xfc, 0xc8, 0xeb, 0xac, 0x79, 0xc7,
+	0x24, 0xbc, 0x84, 0x0a, 0x51, 0x37, 0x31, 0xdd, 0x87, 0xc9, 0x78, 0xef,
+	0x39, 0xd5, 0xa5, 0xba, 0x0a, 0x52, 0x83, 0x1d, 0x9f, 0x6a, 0xa3, 0x4f,
+	0xb5, 0x93, 0x9f, 0x76, 0xfa, 0xd4, 0x16, 0xf2, 0xb3, 0xc5, 0xf6, 0x29,
+	0xf1, 0xcd, 0xdf, 0xe6, 0x65, 0x43, 0xe1, 0x6e, 0x5b, 0x2f, 0x5b, 0xf9,
+	0x6e, 0x27, 0xe5, 0xe8, 0xe4, 0x7b, 0x77, 0xf3, 0xbd, 0xbb, 0x67, 0xff,
+	0x97, 0xf0, 0x47, 0x59, 0x9c, 0xd8, 0xbf, 0x5e, 0xd3, 0x24, 0x07, 0xfc,
+	0xac, 0x88, 0x29, 0x90, 0x75, 0xa5, 0x24, 0x47, 0x0c, 0xa0, 0xbb, 0x19,
+	0xbe, 0x45, 0xa9, 0x67, 0x5b, 0xb7, 0xd7, 0x33, 0x9f, 0x31, 0x9f, 0xfa,
+	0x8e, 0x13, 0x4b, 0x33, 0x47, 0xcf, 0xb4, 0x28, 0x8c, 0x18, 0x37, 0x33,
+	0x4e, 0x0d, 0x1c, 0x29, 0x68, 0x9d, 0x51, 0xde, 0x6b, 0x1a, 0x13, 0x8c,
+	0xbf, 0x0f, 0x6d, 0xc4, 0x75, 0x91, 0x54, 0x3f, 0x22, 0x66, 0x2c, 0x72,
+	0x44, 0x69, 0xfd, 0x1b, 0xa0, 0x5d, 0x64, 0x6d, 0x18, 0x9c, 0x56, 0xda,
+	0x40, 0xad, 0x5b, 0x4b, 0xbf, 0x61, 0xe3, 0xeb, 0x7d, 0x58, 0x6e, 0x63,
+	0xb8, 0x7e, 0x24, 0x88, 0x65, 0xb7, 0x92, 0xe6, 0xde, 0x75, 0x0a, 0x97,
+	0x8d, 0x0f, 0x69, 0x47, 0x2d, 0x9d, 0x55, 0x06, 0x72, 0xcc, 0x13, 0x91,
+	0xe3, 0x82, 0xd5, 0xf7, 0x11, 0xab, 0xc3, 0x17, 0xe0, 0xb3, 0xb9, 0xb1,
+	0xd8, 0xa0, 0xcf, 0xad, 0x25, 0x88, 0xd3, 0xd3, 0xa4, 0x69, 0x14, 0x88,
+	0xdf, 0xb9, 0x46, 0x74, 0x4f, 0x91, 0x66, 0xbc, 0x48, 0x53, 0xcf, 0x83,
+	0x71, 0x73, 0x04, 0x9b, 0xe2, 0xac, 0x15, 0xcc, 0x79, 0x47, 0xa5, 0x27,
+	0x20, 0xbd, 0xf2, 0xe3, 0x06, 0xff, 0x1e, 0x54, 0x3b, 0x24, 0xa6, 0xca,
+	0x1d, 0x2b, 0x54, 0x73, 0x8d, 0xaa, 0xd4, 0x41, 0xcc, 0xd9, 0x6b, 0x0c,
+	0xc8, 0x1a, 0x03, 0xbf, 0x50, 0x5a, 0xe2, 0x9c, 0x92, 0x5c, 0xdd, 0x98,
+	0x39, 0xc7, 0x18, 0x3a, 0xac, 0xb4, 0x96, 0x63, 0x14, 0xdf, 0xaf, 0x0b,
+	0xfd, 0x83, 0xc5, 0x75, 0x06, 0xd0, 0x90, 0x67, 0x7c, 0x16, 0x7c, 0x6a,
+	0xc3, 0x44, 0x1b, 0x46, 0xa6, 0xdb, 0x30, 0x3c, 0xa1, 0x70, 0xb7, 0xb1,
+	0x18, 0x97, 0x6e, 0xb6, 0xfb, 0x94, 0xaa, 0xa5, 0x7a, 0x2d, 0x86, 0x42,
+	0xa8, 0x76, 0xe9, 0x5f, 0xc1, 0xae, 0x22, 0xc6, 0xdf, 0x74, 0xa2, 0x9b,
+	0x79, 0xdf, 0xc2, 0xfb, 0x8c, 0xa5, 0x58, 0x0d, 0xd2, 0xde, 0x54, 0x0b,
+	0xf1, 0x78, 0x9d, 0xdb, 0x89, 0xf7, 0x0f, 0x7d, 0x8e, 0x0d, 0x44, 0xff,
+	0x9f, 0xbf, 0xd7, 0x86, 0xc7, 0x27, 0xca, 0xd0, 0xb2, 0x1a, 0x77, 0x46,
+	0x50, 0xe5, 0x62, 0x8d, 0x7b, 0x73, 0xbb, 0x1a, 0xe4, 0x3d, 0xfb, 0x59,
+	0xdf, 0x97, 0x53, 0x46, 0xea, 0x4f, 0x1a, 0xe4, 0xba, 0x9d, 0x37, 0x6e,
+	0xb8, 0xde, 0xfd, 0x05, 0xd7, 0x15, 0x9e, 0x61, 0x22, 0xfb, 0x01, 0x6b,
+	0x4a, 0x3e, 0x67, 0xc1, 0x9d, 0xf2, 0xa0, 0x7f, 0x2c, 0x8a, 0x7d, 0x73,
+	0x61, 0xcc, 0xe5, 0xb4, 0xde, 0x4b, 0xec, 0x1f, 0x76, 0x35, 0xeb, 0x78,
+	0x60, 0x2e, 0x82, 0xd9, 0x1c, 0x2c, 0x7f, 0x4a, 0x9f, 0xf7, 0xab, 0x04,
+	0xf6, 0xce, 0xd5, 0xe1, 0x5c, 0x4e, 0xbf, 0x38, 0xac, 0xe2, 0x83, 0xb5,
+	0xc4, 0x1d, 0x0f, 0xce, 0x35, 0x61, 0xff, 0x9c, 0x8f, 0xef, 0x58, 0xd8,
+	0x92, 0xac, 0xe3, 0xf3, 0x2e, 0x3c, 0x7d, 0xd2, 0xb2, 0x04, 0x77, 0xf5,
+	0xcf, 0x01, 0xb3, 0xe3, 0xac, 0x45, 0x67, 0x58, 0x97, 0x9e, 0x00, 0xf6,
+	0x3e, 0xe1, 0xc2, 0xf4, 0xb8, 0x85, 0x5d, 0xc6, 0x70, 0xad, 0x8b, 0x0e,
+	0xdf, 0xcb, 0xba, 0xe1, 0x65, 0x0d, 0xbc, 0x27, 0xe4, 0xe4, 0xf3, 0x4b,
+	0xcc, 0x53, 0xf7, 0x3d, 0x91, 0xc0, 0x9b, 0xb9, 0x2c, 0xb6, 0x10, 0x9f,
+	0x0f, 0x92, 0x97, 0x37, 0x72, 0xac, 0x63, 0x73, 0x06, 0x5e, 0xcf, 0xf9,
+	0xb8, 0x4e, 0x13, 0x5e, 0xca, 0xc9, 0x33, 0xf2, 0x6c, 0x00, 0x7d, 0xe4,
+	0xe5, 0xb5, 0x5c, 0x84, 0x6b, 0x86, 0xf1, 0x53, 0x3e, 0x77, 0xef, 0x9c,
+	0xce, 0xba, 0xe5, 0xe3, 0xba, 0x51, 0xbc, 0x92, 0x0b, 0x90, 0xd7, 0x30,
+	0x6b, 0x55, 0x1f, 0x46, 0x72, 0x8d, 0x17, 0x37, 0x30, 0x51, 0x3b, 0xb5,
+	0x46, 0xae, 0xbd, 0x63, 0x75, 0xd9, 0xb1, 0x28, 0xeb, 0x94, 0xd6, 0xed,
+	0xc3, 0x70, 0xee, 0x75, 0x77, 0xa9, 0x9f, 0x7e, 0x66, 0x7c, 0xc1, 0xc6,
+	0x7e, 0x4f, 0x9b, 0xfc, 0x7d, 0x1a, 0x38, 0x67, 0x66, 0xad, 0xea, 0x14,
+	0xb1, 0x2e, 0x6b, 0xd4, 0x5b, 0x6b, 0x9a, 0xb8, 0xae, 0xde, 0xfb, 0xa2,
+	0x92, 0x7e, 0xc7, 0x83, 0xe8, 0x13, 0xa2, 0x2f, 0x62, 0xe6, 0x59, 0xe0,
+	0x47, 0xc4, 0x9f, 0x0d, 0x63, 0x9a, 0xf8, 0x7d, 0x86, 0xb8, 0xa6, 0x7b,
+	0x1e, 0xf5, 0x89, 0x07, 0x30, 0x64, 0x95, 0x11, 0x9f, 0x57, 0x13, 0xd7,
+	0xce, 0x35, 0xb1, 0x4e, 0xad, 0xb1, 0xac, 0xbf, 0x6d, 0x86, 0xe5, 0x4a,
+	0xe9, 0x46, 0xad, 0x7b, 0xfe, 0x2b, 0x55, 0xd0, 0x2f, 0x06, 0x95, 0x3e,
+	0xff, 0x16, 0xe2, 0x03, 0xe7, 0x21, 0x7a, 0x05, 0x56, 0xcc, 0x79, 0xb0,
+	0x92, 0xf2, 0x6c, 0x1c, 0xe3, 0xda, 0xc4, 0x27, 0x71, 0xca, 0xb4, 0x6d,
+	0x8c, 0x98, 0x4b, 0x0f, 0x60, 0x39, 0x75, 0xdc, 0x7f, 0xca, 0xb2, 0xca,
+	0xa9, 0xe3, 0x06, 0xda, 0x67, 0xcf, 0x09, 0x0b, 0x2f, 0x1a, 0x2f, 0x52,
+	0xa7, 0x8a, 0xb8, 0xb1, 0x99, 0xef, 0x84, 0xf9, 0xbc, 0x0f, 0x7b, 0xc7,
+	0xa4, 0x5f, 0xaa, 0xe3, 0x33, 0xaf, 0xe2, 0x58, 0x2e, 0x81, 0x26, 0xea,
+	0x2f, 0x4a, 0x9a, 0x8d, 0x7c, 0x27, 0x4a, 0x7a, 0xd1, 0xb9, 0xaf, 0x61,
+	0xf3, 0x29, 0x05, 0x3d, 0x2e, 0x3a, 0xf8, 0x1a, 0xda, 0xcf, 0x7c, 0x51,
+	0x4e, 0x60, 0x96, 0x1a, 0xd7, 0x8e, 0xcc, 0x13, 0x7f, 0x57, 0xa5, 0x86,
+	0xc0, 0xfa, 0x8d, 0x37, 0xa6, 0x14, 0x8e, 0x8f, 0xb3, 0xdf, 0x5b, 0x03,
+	0xab, 0x82, 0x32, 0xbd, 0x3e, 0xf5, 0x3b, 0x78, 0xea, 0x24, 0xf5, 0xf0,
+	0x64, 0x18, 0x3f, 0xc8, 0x79, 0xb0, 0xec, 0xb8, 0x60, 0x3a, 0x3d, 0xb1,
+	0x4f, 0x49, 0x7f, 0x24, 0x7d, 0x4b, 0x3c, 0xea, 0x55, 0x2e, 0xd4, 0x3f,
+	0xe5, 0x81, 0x7e, 0x2e, 0x0a, 0x6f, 0xbd, 0x0f, 0x7a, 0xfd, 0x1f, 0x32,
+	0xd7, 0xb8, 0x50, 0xc6, 0x5e, 0x76, 0xd3, 0x77, 0x13, 0xbc, 0x16, 0xe6,
+	0x35, 0xfc, 0x4e, 0x39, 0xdc, 0x4b, 0xdc, 0xac, 0xe1, 0x65, 0x3a, 0xf1,
+	0x98, 0xc7, 0xb2, 0xdc, 0xac, 0x0d, 0x3b, 0xbe, 0x67, 0x59, 0xb1, 0xd5,
+	0xf2, 0x7c, 0x08, 0xb1, 0x73, 0x3a, 0x9f, 0x73, 0xea, 0xe5, 0x75, 0x3c,
+	0xe6, 0xa6, 0x1f, 0x49, 0xac, 0xb2, 0xde, 0xdb, 0x3d, 0x94, 0x83, 0xdb,
+	0x9f, 0x2b, 0x08, 0xb6, 0x89, 0xda, 0x32, 0x9c, 0x1d, 0x57, 0xcc, 0xd9,
+	0x29, 0x3e, 0xbb, 0x1e, 0xee, 0xa4, 0x76, 0x24, 0x4b, 0x3f, 0xd8, 0x15,
+	0x6a, 0xc1, 0x33, 0xa6, 0x17, 0x95, 0xfa, 0x12, 0xdc, 0xdf, 0x1d, 0xc2,
+	0x33, 0xec, 0x0b, 0x68, 0xb3, 0xc4, 0x3c, 0xd8, 0x48, 0x07, 0x49, 0xcf,
+	0xf5, 0x63, 0xe8, 0xdf, 0x75, 0x31, 0xcf, 0xb9, 0xed, 0x3c, 0x57, 0x56,
+	0x0f, 0xcc, 0xe7, 0x3d, 0xb8, 0xa0, 0x3b, 0x98, 0xf0, 0x39, 0xbb, 0x66,
+	0x6b, 0xa1, 0xf9, 0x6b, 0x58, 0x50, 0x6b, 0x49, 0x2b, 0x32, 0x13, 0x14,
+	0xdd, 0x65, 0x3c, 0x8e, 0x2f, 0xfd, 0x8d, 0x5b, 0x7a, 0x8e, 0xeb, 0x7f,
+	0x57, 0xc0, 0x95, 0xd2, 0x22, 0x6d, 0x6e, 0xf8, 0x3c, 0xa9, 0xce, 0xd6,
+	0x51, 0xfd, 0x4b, 0x37, 0xf0, 0xde, 0x84, 0x91, 0xc2, 0xf5, 0x5e, 0xbb,
+	0x33, 0x67, 0xfb, 0x50, 0xa7, 0xe8, 0xfe, 0x31, 0x43, 0xf2, 0xec, 0xa0,
+	0x6a, 0x67, 0xde, 0xca, 0x7a, 0x90, 0xad, 0xe2, 0x33, 0xd4, 0x3f, 0x0e,
+	0x8f, 0x09, 0x9d, 0x83, 0x18, 0xcd, 0xc9, 0x6c, 0x63, 0x00, 0xeb, 0xcc,
+	0x58, 0xe2, 0x22, 0x7b, 0xe8, 0x43, 0x90, 0x39, 0x44, 0xe3, 0xfc, 0xcb,
+	0x4a, 0x1b, 0xbc, 0xc5, 0xad, 0xf5, 0x2f, 0x28, 0x27, 0x6f, 0xad, 0x28,
+	0xe6, 0xad, 0xe5, 0xf9, 0x25, 0xc1, 0x2e, 0xd6, 0x83, 0xae, 0xd9, 0x52,
+	0x7d, 0xe8, 0x52, 0x9b, 0xec, 0xda, 0x9a, 0x51, 0x5b, 0x67, 0x7d, 0xaa,
+	0x63, 0xc2, 0x87, 0x97, 0x89, 0xc5, 0xa6, 0x7a, 0x10, 0x5a, 0xb6, 0x06,
+	0xfe, 0xad, 0x13, 0xdd, 0x28, 0xd7, 0xa5, 0x87, 0x2c, 0xc7, 0x26, 0xbb,
+	0xae, 0xd5, 0x05, 0xbb, 0x58, 0x7f, 0xba, 0x0a, 0x3d, 0xcc, 0x7f, 0x08,
+	0xf9, 0x53, 0xce, 0xcc, 0x40, 0x72, 0xe1, 0xed, 0x7c, 0xf7, 0x62, 0x72,
+	0x11, 0xe0, 0xd4, 0x3f, 0x95, 0x61, 0x2f, 0x51, 0xbd, 0x5a, 0xe1, 0xd2,
+	0x9d, 0x3e, 0x90, 0x16, 0x7b, 0xfe, 0x7c, 0xeb, 0x85, 0xf1, 0x6e, 0xd5,
+	0x31, 0x3d, 0xe3, 0xdf, 0x68, 0xca, 0x2c, 0x62, 0xca, 0xdf, 0x4e, 0x1e,
+	0xda, 0x67, 0x9f, 0xf4, 0x6f, 0x20, 0x4f, 0x1b, 0x66, 0x3f, 0x4f, 0x53,
+	0xea, 0x4a, 0x7f, 0x6b, 0x1b, 0x63, 0x7b, 0x87, 0xf1, 0x91, 0x15, 0xfd,
+	0xa6, 0xd0, 0x99, 0x2b, 0xea, 0x33, 0x4d, 0xbe, 0xc2, 0xbe, 0x4d, 0x85,
+	0x90, 0x2f, 0x5d, 0x68, 0xf7, 0xb7, 0x99, 0xdd, 0xfe, 0x0d, 0x66, 0x8f,
+	0xbf, 0xdd, 0xdc, 0x49, 0xda, 0x5d, 0xfe, 0x0e, 0x93, 0x71, 0x5d, 0xe8,
+	0xa1, 0x5e, 0xbb, 0x31, 0x5a, 0xd8, 0x49, 0xec, 0x21, 0x34, 0x7b, 0x89,
+	0x83, 0xfc, 0x94, 0x71, 0x88, 0x32, 0xce, 0x47, 0xbc, 0x48, 0x6b, 0x5e,
+	0xea, 0x6b, 0xc4, 0xb6, 0xe3, 0x11, 0x7b, 0x16, 0x55, 0x91, 0x7a, 0xa0,
+	0x75, 0xcb, 0x09, 0xe6, 0xfb, 0xd4, 0x9e, 0xd6, 0x65, 0xa7, 0x50, 0xe3,
+	0x4d, 0x49, 0xef, 0xcc, 0x7e, 0x38, 0x1e, 0x37, 0xde, 0x43, 0x3c, 0xf2,
+	0x32, 0x9f, 0x1d, 0xa6, 0xef, 0x8e, 0xd8, 0xf3, 0x07, 0x1a, 0x24, 0xdf,
+	0x84, 0x2d, 0xa6, 0xcf, 0xbf, 0x8d, 0xbd, 0x59, 0x30, 0xa5, 0xb5, 0xdc,
+	0xee, 0x96, 0x79, 0xc8, 0xfc, 0xef, 0x05, 0xd0, 0x84, 0xce, 0x82, 0x8f,
+	0x72, 0x7d, 0x09, 0x7f, 0x7f, 0x92, 0x75, 0x0d, 0xe2, 0x87, 0x96, 0x75,
+	0x2f, 0xfb, 0x9a, 0xa3, 0xf9, 0x3a, 0x5c, 0xb6, 0x6d, 0xec, 0xc1, 0xe1,
+	0x7c, 0x14, 0xef, 0x50, 0x3e, 0xcf, 0x5c, 0x2d, 0xde, 0x1e, 0x77, 0x63,
+	0xb7, 0x71, 0x5b, 0xb1, 0x5e, 0xb8, 0x70, 0x4f, 0xe2, 0x00, 0xb1, 0x83,
+	0x0b, 0xd5, 0xc4, 0x6f, 0x0f, 0xda, 0xd7, 0xdc, 0xec, 0xff, 0xbe, 0x8e,
+	0x41, 0xa7, 0x9e, 0x90, 0xc7, 0x9d, 0xe4, 0xb1, 0xd9, 0xbf, 0x61, 0x42,
+	0xf3, 0xdf, 0x31, 0x01, 0x9f, 0x37, 0xb5, 0xab, 0xf5, 0xcc, 0x49, 0x0b,
+	0x7d, 0xc6, 0xad, 0xb8, 0x72, 0x72, 0xb8, 0xdf, 0x43, 0xff, 0xf9, 0x65,
+	0x32, 0x03, 0x73, 0x12, 0x17, 0x88, 0x3c, 0x5e, 0x0d, 0x30, 0xb7, 0x37,
+	0x24, 0xe3, 0x21, 0xd6, 0x62, 0x63, 0x96, 0xb1, 0xd9, 0x01, 0xad, 0x9f,
+	0x35, 0x39, 0xed, 0x4e, 0xc5, 0x7b, 0x47, 0x08, 0x1e, 0xab, 0xc8, 0x8f,
+	0x9f, 0xb9, 0x3b, 0x30, 0x17, 0xf5, 0xef, 0x60, 0xbd, 0x89, 0xb0, 0xbf,
+	0xf3, 0xc7, 0x71, 0x5b, 0x2d, 0xe2, 0x89, 0x05, 0xca, 0xed, 0x9d, 0x6b,
+	0xf2, 0xdf, 0xce, 0xfa, 0x71, 0x39, 0x6e, 0x0d, 0xbd, 0x68, 0x04, 0x10,
+	0x9c, 0x33, 0xa8, 0xef, 0x0c, 0x86, 0x67, 0xd9, 0x72, 0xc5, 0xd9, 0xf3,
+	0xcf, 0xb5, 0xf8, 0xb7, 0x31, 0x36, 0xab, 0x68, 0xa2, 0xc6, 0xb9, 0xb4,
+	0x5f, 0x7a, 0xbe, 0xa6, 0xb9, 0xb5, 0xe4, 0x4f, 0x7c, 0x74, 0x5f, 0xeb,
+	0x3a, 0xfa, 0x43, 0x74, 0x0e, 0x9b, 0x98, 0xe6, 0x5e, 0x22, 0xcd, 0x4c,
+	0x84, 0x18, 0x76, 0xef, 0x9a, 0x00, 0xf3, 0x94, 0xe8, 0x92, 0x7a, 0x2c,
+	0x94, 0x64, 0x92, 0xba, 0xbc, 0xa7, 0x75, 0xee, 0x94, 0xd4, 0xe5, 0x4c,
+	0x6b, 0xee, 0x94, 0x8e, 0x77, 0x58, 0x5b, 0x56, 0x24, 0x35, 0xe3, 0x9c,
+	0x8a, 0x45, 0x5e, 0xa5, 0x2c, 0x1e, 0xfc, 0xca, 0xda, 0xa5, 0xc7, 0xe7,
+	0x6f, 0x61, 0x3c, 0x55, 0x33, 0x37, 0x46, 0x98, 0xf3, 0xab, 0xe7, 0xa8,
+	0x98, 0x39, 0xb7, 0x17, 0x15, 0x11, 0xf8, 0xe2, 0x3a, 0xde, 0x3d, 0x99,
+	0xa0, 0x1e, 0xae, 0xd1, 0xdc, 0x47, 0xa8, 0xd5, 0xc7, 0x52, 0xf8, 0xc8,
+	0x53, 0xf4, 0xc5, 0x51, 0xae, 0x5b, 0x36, 0x27, 0x3c, 0xcb, 0xf3, 0x61,
+	0x3e, 0x7f, 0x7d, 0xed, 0x6a, 0xae, 0xfd, 0xd1, 0x29, 0xf1, 0xd7, 0x4c,
+	0xeb, 0x85, 0x93, 0xce, 0xda, 0xf1, 0x64, 0x02, 0x1f, 0x9e, 0xd4, 0x06,
+	0xde, 0x55, 0xb1, 0xde, 0x0b, 0x4a, 0xd6, 0x47, 0x5d, 0x15, 0xae, 0x58,
+	0xc3, 0xf1, 0xf8, 0xe0, 0x2e, 0xd2, 0x6c, 0x59, 0x4b, 0xfd, 0xdb, 0x7c,
+	0xd0, 0xe7, 0x99, 0x67, 0xbd, 0xe4, 0xc7, 0xe1, 0xa5, 0x8e, 0xb4, 0x4f,
+	0x16, 0x7b, 0x35, 0xf6, 0xa9, 0xd7, 0xf9, 0x09, 0x53, 0x0f, 0xbe, 0x1d,
+	0xcd, 0x01, 0xd4, 0xda, 0xcf, 0x85, 0xf8, 0x9c, 0xe8, 0xe1, 0xd7, 0xca,
+	0xa5, 0xbf, 0xc7, 0x3c, 0x26, 0xb9, 0x24, 0xcc, 0x1c, 0xb6, 0x53, 0x7a,
+	0xda, 0x6c, 0x96, 0xfe, 0xee, 0xa5, 0xbf, 0x6f, 0x14, 0x9f, 0x36, 0xe9,
+	0xd3, 0x26, 0x7d, 0xda, 0xd4, 0x22, 0x03, 0x88, 0x85, 0xfa, 0x68, 0xb7,
+	0x74, 0x44, 0x7c, 0xbd, 0x07, 0xbb, 0xf9, 0xd9, 0xc3, 0xfb, 0x87, 0xd9,
+	0xe7, 0x62, 0x91, 0xac, 0x79, 0x10, 0xed, 0xe6, 0x23, 0xe8, 0x9f, 0xc0,
+	0x6f, 0xfc, 0xcd, 0xe5, 0x28, 0x5f, 0x2e, 0x3d, 0xbc, 0x16, 0x3a, 0x8a,
+	0x47, 0xd8, 0x47, 0xfd, 0x5a, 0x55, 0xea, 0x9e, 0xee, 0x63, 0x4a, 0x0b,
+	0xb5, 0xb3, 0x1f, 0xde, 0x55, 0xd8, 0x49, 0xfb, 0xc6, 0xfa, 0x5f, 0x56,
+	0xec, 0xa5, 0x6a, 0xb9, 0x36, 0x63, 0xe9, 0x0e, 0xae, 0x63, 0x0a, 0x1f,
+	0x76, 0xbe, 0xfd, 0x7d, 0x88, 0x6e, 0x7f, 0xd2, 0xd0, 0xc7, 0xf5, 0x1d,
+	0x3e, 0x86, 0xd9, 0x53, 0xf6, 0x31, 0xc6, 0x76, 0xdb, 0xf1, 0xd5, 0x43,
+	0x1a, 0xd7, 0xf3, 0xd8, 0x86, 0x9c, 0xd4, 0x52, 0x0b, 0x8f, 0x1a, 0x16,
+	0x9e, 0xe6, 0xe7, 0x22, 0x73, 0xd9, 0xc8, 0x0d, 0xb9, 0xcc, 0xc5, 0xe7,
+	0x76, 0xf0, 0xb9, 0x16, 0xa6, 0xce, 0xd9, 0x69, 0x99, 0x0d, 0x1e, 0x94,
+	0xd9, 0x20, 0xf2, 0xa6, 0xe8, 0x7e, 0x00, 0x17, 0x72, 0xb1, 0x41, 0xb7,
+	0xdb, 0x1a, 0x62, 0x5c, 0x5d, 0xfc, 0x88, 0xbe, 0xfb, 0xda, 0x1a, 0xad,
+	0x9b, 0x3a, 0x4c, 0x8c, 0x29, 0x2d, 0xf2, 0x33, 0xcc, 0x6f, 0xf2, 0xa1,
+	0x31, 0xba, 0xd2, 0x1d, 0x0f, 0x9d, 0x85, 0x36, 0xdf, 0x47, 0x49, 0x9f,
+	0x2c, 0x38, 0xb9, 0x6e, 0x5d, 0x31, 0xd7, 0xb5, 0xe4, 0x2b, 0xd4, 0x1d,
+	0x13, 0xac, 0xcf, 0xd3, 0x56, 0x36, 0xc8, 0x7a, 0x55, 0x98, 0x16, 0xda,
+	0x43, 0x68, 0x4c, 0x0a, 0x2d, 0xbd, 0x73, 0x4c, 0xe1, 0x1b, 0x95, 0x88,
+	0xb3, 0x56, 0xc1, 0x28, 0xd7, 0xb3, 0x16, 0x6b, 0x52, 0xc8, 0x9b, 0x92,
+	0xda, 0xd9, 0xc5, 0xbe, 0xa5, 0x87, 0x79, 0x51, 0x30, 0xb5, 0xcc, 0x4b,
+	0x9d, 0x7c, 0xb4, 0xb1, 0x20, 0x76, 0x11, 0x9b, 0x88, 0x6d, 0x0e, 0xe2,
+	0x1e, 0x53, 0x7a, 0x7f, 0x0b, 0xe3, 0x46, 0x3c, 0xfa, 0x14, 0xc4, 0x4e,
+	0x07, 0xa9, 0x0b, 0x2f, 0x76, 0x33, 0x0f, 0xee, 0x6a, 0xa6, 0xae, 0x82,
+	0x5e, 0xec, 0xb2, 0x67, 0x09, 0x25, 0xfd, 0x79, 0x69, 0x43, 0xc5, 0x1a,
+	0x37, 0xeb, 0x75, 0xf4, 0xe8, 0xcc, 0x26, 0xdd, 0x29, 0xa1, 0x57, 0x9a,
+	0x4b, 0x3a, 0xba, 0xdb, 0x94, 0x13, 0xba, 0x16, 0xce, 0x1a, 0x0e, 0x6e,
+	0x2d, 0xe9, 0x2c, 0x42, 0xb9, 0x6a, 0xd6, 0x02, 0x2b, 0x6f, 0xc0, 0xae,
+	0x15, 0xbc, 0xb6, 0xe5, 0x3a, 0x76, 0xcd, 0x08, 0x3e, 0x26, 0x76, 0xed,
+	0xdc, 0x4a, 0xec, 0x5a, 0xaf, 0x4a, 0xb8, 0x55, 0xe6, 0x12, 0x25, 0xec,
+	0x5a, 0x5d, 0xcc, 0xd1, 0x07, 0xb1, 0x8b, 0xb8, 0xa6, 0xb6, 0x7e, 0x08,
+	0xbe, 0x55, 0xae, 0xcf, 0x5c, 0x18, 0x62, 0xbf, 0x52, 0x06, 0x2c, 0xb6,
+	0x70, 0xcb, 0xea, 0xac, 0x55, 0xae, 0xd7, 0x47, 0xcb, 0x5d, 0x32, 0x77,
+	0x8e, 0x67, 0x47, 0x98, 0x4b, 0x5c, 0xab, 0xb4, 0x6c, 0x1a, 0xbe, 0x50,
+	0x8d, 0xbe, 0xb3, 0xd8, 0x2f, 0x44, 0x7c, 0x9b, 0x89, 0x7b, 0xe2, 0xc9,
+	0x4f, 0xad, 0xa9, 0xb0, 0xd0, 0x98, 0x9f, 0xf7, 0x21, 0xfd, 0x90, 0x8f,
+	0x75, 0x68, 0x41, 0x1d, 0xc1, 0x6b, 0xf1, 0x88, 0x6f, 0x5b, 0x21, 0xeb,
+	0xdf, 0xd2, 0x70, 0x0b, 0xba, 0x4e, 0x49, 0xcd, 0x89, 0x62, 0xeb, 0xa9,
+	0x76, 0xd6, 0x19, 0x1d, 0x1d, 0x63, 0x9d, 0xec, 0xe3, 0xba, 0x55, 0xf7,
+	0xb4, 0xe8, 0x49, 0xf4, 0xac, 0x85, 0xa2, 0xae, 0x1b, 0xe7, 0xa2, 0xa5,
+	0x9e, 0xf8, 0x3d, 0xdb, 0x87, 0x46, 0x8d, 0x10, 0xf5, 0xf3, 0x2b, 0x2f,
+	0x82, 0x16, 0xce, 0x18, 0xe2, 0x7b, 0xfc, 0xdb, 0x4c, 0x63, 0x63, 0xf3,
+	0xb8, 0xe5, 0xd1, 0x65, 0xbe, 0x1d, 0xb1, 0xed, 0xb6, 0x81, 0xb5, 0xac,
+	0x7d, 0xba, 0x87, 0xb6, 0x2a, 0xcd, 0xb2, 0x6f, 0xb4, 0xd9, 0x7a, 0xff,
+	0x46, 0xe6, 0x35, 0xf6, 0xe9, 0x3e, 0x1f, 0x73, 0xa5, 0xef, 0x94, 0x85,
+	0x69, 0xe3, 0x4d, 0xeb, 0x51, 0xdd, 0x43, 0xbb, 0x7c, 0x95, 0x79, 0x57,
+	0x70, 0x49, 0xca, 0x7f, 0xfb, 0xa4, 0xc7, 0x55, 0x95, 0x42, 0x73, 0x19,
+	0x7d, 0xee, 0xd5, 0xa4, 0x33, 0x73, 0x3c, 0x96, 0xbf, 0xcd, 0xbf, 0x65,
+	0x82, 0xbd, 0x04, 0x7b, 0x5d, 0xa7, 0xbf, 0xfb, 0xaa, 0xff, 0xee, 0x09,
+	0xb7, 0xaa, 0x4d, 0xc1, 0xdd, 0xb2, 0xd6, 0xc2, 0xc7, 0xab, 0xe3, 0x83,
+	0x11, 0x17, 0x73, 0x24, 0x69, 0x99, 0xf9, 0x66, 0x7f, 0x86, 0x39, 0x79,
+	0xdb, 0x04, 0xd2, 0x32, 0x9f, 0x0d, 0xae, 0x1e, 0xee, 0x0d, 0x42, 0x66,
+	0x69, 0xf8, 0x06, 0xa3, 0x32, 0x4c, 0x9f, 0x8b, 0xb4, 0xa9, 0xf8, 0x42,
+	0x3f, 0xe2, 0x17, 0x3f, 0x76, 0xbf, 0x69, 0x3d, 0x9e, 0x5f, 0xcb, 0xe7,
+	0x3b, 0x99, 0x2f, 0xd3, 0xcc, 0x9f, 0xc3, 0x83, 0x5e, 0xc8, 0x3b, 0x5a,
+	0xe6, 0x0d, 0x15, 0xa3, 0xaf, 0xe3, 0x9b, 0x7c, 0x3e, 0xd4, 0xc1, 0x5c,
+	0x39, 0x6d, 0xc4, 0xd3, 0x1b, 0x90, 0xed, 0xac, 0x86, 0x66, 0x34, 0x28,
+	0x99, 0x7d, 0x89, 0x1d, 0x12, 0xf8, 0x39, 0xd7, 0xf4, 0xe8, 0xa2, 0xc7,
+	0xf5, 0xe8, 0x9b, 0x66, 0xfd, 0xbf, 0xe6, 0x6f, 0xa2, 0x03, 0xd1, 0xcb,
+	0x37, 0xcb, 0x50, 0xb1, 0x88, 0xb2, 0xfd, 0xdc, 0xce, 0x2b, 0x7e, 0x5d,
+	0xc7, 0x7f, 0x26, 0x3e, 0xfa, 0x4f, 0x05, 0x99, 0x71, 0x96, 0x30, 0x9f,
+	0xdd, 0x47, 0xb5, 0x2e, 0x9b, 0x4a, 0x14, 0x67, 0x9e, 0x3e, 0x7f, 0xe7,
+	0xa4, 0x85, 0x93, 0x46, 0x10, 0xd2, 0xe3, 0x97, 0x27, 0xe7, 0x89, 0x00,
+	0x9a, 0xd0, 0xc1, 0xeb, 0xed, 0x93, 0x95, 0xaa, 0x7d, 0xc2, 0xc2, 0x5f,
+	0x18, 0x5a, 0xb6, 0xcd, 0xcd, 0x98, 0x36, 0xb4, 0xb3, 0xc0, 0x3b, 0xc4,
+	0x4a, 0xe2, 0x63, 0x1e, 0x04, 0x74, 0x87, 0x56, 0xd3, 0xd4, 0x6d, 0xc4,
+	0x0f, 0x12, 0x63, 0xee, 0x15, 0x15, 0x48, 0xaa, 0x29, 0x8f, 0xe8, 0xad,
+	0x13, 0xe9, 0x42, 0xa5, 0xda, 0x4e, 0x5d, 0xde, 0xb1, 0xaa, 0x0c, 0x97,
+	0x6c, 0x5d, 0xde, 0x46, 0x5d, 0xe2, 0xf5, 0xa5, 0x70, 0x5f, 0xa8, 0x45,
+	0xa7, 0x82, 0xdd, 0x9f, 0x55, 0xb2, 0x4e, 0xa7, 0x89, 0x6f, 0x89, 0x07,
+	0x43, 0x3d, 0xf8, 0x2e, 0xf3, 0xcd, 0xa3, 0xf4, 0xd5, 0x5f, 0xe9, 0x4d,
+	0xa8, 0xf8, 0x5e, 0x33, 0xed, 0xb8, 0xd6, 0xbf, 0x79, 0x22, 0x83, 0xc7,
+	0x66, 0x2d, 0x3c, 0xc5, 0x38, 0x69, 0x48, 0x66, 0x43, 0xe5, 0xec, 0xd7,
+	0x58, 0xd3, 0x16, 0x4e, 0xd8, 0x7e, 0xbe, 0xab, 0x75, 0xfd, 0x4c, 0x04,
+	0xee, 0xef, 0xca, 0xef, 0x3b, 0x5b, 0xa3, 0x33, 0xf2, 0x9d, 0xe1, 0xb7,
+	0x85, 0x01, 0x43, 0x4b, 0x7f, 0xec, 0xae, 0x40, 0x65, 0xdc, 0xb2, 0x06,
+	0x92, 0x72, 0xbd, 0xaf, 0x35, 0x61, 0xdf, 0xdf, 0xc3, 0xef, 0xd2, 0x4c,
+	0xfa, 0x6f, 0x04, 0x0b, 0x46, 0xd3, 0x94, 0x79, 0x2b, 0xeb, 0x7b, 0x86,
+	0xf5, 0xbd, 0x36, 0xa5, 0xa5, 0x77, 0xb8, 0x65, 0xfe, 0x32, 0x7f, 0xa0,
+	0x9a, 0xd7, 0x6f, 0x2f, 0xd6, 0xf7, 0xaa, 0x53, 0x32, 0xd3, 0x23, 0x06,
+	0x84, 0xb3, 0x17, 0xd2, 0xc5, 0xfa, 0x5e, 0x31, 0xe6, 0xc1, 0x16, 0xd6,
+	0x76, 0x2f, 0xb1, 0xf8, 0xc6, 0x7c, 0x2d, 0xfc, 0x27, 0xdc, 0x88, 0x25,
+	0x7f, 0x82, 0x03, 0xf4, 0xb1, 0x03, 0x09, 0xb7, 0x8a, 0x2e, 0x71, 0x51,
+	0x4f, 0xff, 0x88, 0x7d, 0x21, 0x37, 0xaa, 0xf4, 0x9f, 0xe1, 0x81, 0x2f,
+	0xa8, 0xe9, 0x99, 0x09, 0x89, 0xed, 0x5d, 0xad, 0x5b, 0x4e, 0x39, 0x35,
+	0x3d, 0x70, 0x6a, 0x78, 0x41, 0x6a, 0x7a, 0xed, 0xea, 0x0c, 0x4e, 0x4f,
+	0xe2, 0x3b, 0x4b, 0x09, 0x1e, 0x6b, 0xb9, 0x66, 0x7d, 0x32, 0xce, 0xde,
+	0x5a, 0xeb, 0xef, 0x50, 0xf1, 0x23, 0x55, 0xcc, 0x01, 0xa7, 0x59, 0xd3,
+	0x7d, 0xa9, 0x78, 0x28, 0xe1, 0x42, 0x97, 0x97, 0xf6, 0x78, 0x9f, 0x7d,
+	0xf6, 0x5b, 0xf9, 0x28, 0x69, 0x96, 0xc1, 0xc3, 0x9a, 0xfe, 0xbe, 0x8e,
+	0xcf, 0xdc, 0xf4, 0xbd, 0x77, 0xdc, 0x3e, 0x5c, 0xcd, 0x3b, 0x35, 0xbd,
+	0xba, 0xc1, 0x1a, 0xba, 0x9c, 0x0c, 0xe0, 0x4a, 0xde, 0xa0, 0x0f, 0x66,
+	0x70, 0x98, 0x35, 0xfd, 0xb2, 0x1e, 0xc2, 0x87, 0xf9, 0x16, 0xfa, 0x65,
+	0x18, 0xbf, 0x24, 0xfe, 0x5d, 0xc5, 0x9a, 0x7e, 0x27, 0x7d, 0x2a, 0xc9,
+	0x9a, 0xde, 0x66, 0xe3, 0x8d, 0x7d, 0xad, 0x67, 0xc6, 0xed, 0x9a, 0xde,
+	0xe0, 0x62, 0x3d, 0xf4, 0x22, 0xbe, 0xc0, 0x3c, 0x61, 0xfd, 0x6a, 0x6d,
+	0x80, 0xcf, 0x52, 0x6f, 0x85, 0xd5, 0x98, 0xb2, 0x6b, 0xd0, 0x7a, 0xff,
+	0x76, 0xae, 0xbd, 0xd8, 0x8e, 0x33, 0x0b, 0x5b, 0x57, 0xbd, 0x86, 0x3f,
+	0xaa, 0x71, 0xd1, 0x0f, 0x53, 0xfe, 0x3b, 0x18, 0x6b, 0xc1, 0x54, 0x69,
+	0xe6, 0x91, 0xe0, 0x3a, 0xb7, 0xf9, 0xef, 0xa4, 0x6f, 0xdc, 0xb2, 0x8a,
+	0x99, 0x24, 0xe4, 0xc4, 0x59, 0x3b, 0xe3, 0x2c, 0xc2, 0x38, 0x5b, 0xca,
+	0x38, 0x7b, 0xdc, 0x88, 0x27, 0xd6, 0x13, 0x77, 0xbd, 0x9c, 0x97, 0x58,
+	0x6b, 0x26, 0x5d, 0x8d, 0x72, 0x0d, 0xf7, 0x4a, 0xcc, 0x6c, 0x5d, 0x35,
+	0x7c, 0xb6, 0x12, 0xa2, 0x2b, 0x7c, 0xb6, 0x98, 0x18, 0x83, 0x99, 0xe9,
+	0xe2, 0x82, 0x3b, 0x3e, 0x78, 0xab, 0x3b, 0x3e, 0xf0, 0x9e, 0x7a, 0xd3,
+	0x7a, 0x9d, 0x71, 0xb6, 0x8d, 0x71, 0xb6, 0x9d, 0x71, 0xd6, 0x66, 0x5a,
+	0x78, 0x2e, 0xa9, 0x65, 0x9a, 0x5c, 0x31, 0xa3, 0xcd, 0x85, 0xa5, 0x95,
+	0x2c, 0x0d, 0x7e, 0xc4, 0x3b, 0xff, 0x88, 0xfc, 0x5f, 0x34, 0xe2, 0xdd,
+	0x09, 0x25, 0xb1, 0x15, 0xc5, 0x07, 0x94, 0xbb, 0xbc, 0x18, 0x5b, 0x7b,
+	0xa7, 0xcf, 0x17, 0x7d, 0xa3, 0x24, 0xbb, 0x1b, 0xcf, 0x1a, 0xcc, 0xa5,
+	0x8b, 0xb4, 0x68, 0xd6, 0xd5, 0x83, 0x23, 0xd4, 0xa3, 0x3f, 0xde, 0x83,
+	0xa3, 0xac, 0x87, 0xf7, 0xb2, 0x0e, 0xdf, 0x67, 0xc6, 0x5a, 0x36, 0xb3,
+	0xff, 0xb9, 0x14, 0xd1, 0xa2, 0x51, 0xd5, 0x83, 0x3e, 0xfa, 0x70, 0x1f,
+	0xeb, 0x46, 0x9b, 0xf9, 0x6b, 0xd5, 0x41, 0xac, 0xb0, 0xa7, 0x20, 0xef,
+	0x69, 0x89, 0x5e, 0x57, 0x3f, 0x7a, 0x67, 0x25, 0xb7, 0x21, 0x74, 0x53,
+	0xaa, 0x07, 0xc7, 0xcd, 0x32, 0xf4, 0x34, 0x77, 0xa9, 0xdb, 0x0b, 0x32,
+	0x7f, 0x63, 0x3c, 0x9a, 0x8c, 0x57, 0x9b, 0x5f, 0x85, 0x7c, 0xbc, 0x0b,
+	0x39, 0x89, 0x4f, 0x73, 0xbb, 0xba, 0x73, 0x5a, 0x62, 0xbc, 0x47, 0xf5,
+	0x48, 0x0c, 0x9b, 0x83, 0xea, 0x2e, 0x89, 0x69, 0x7b, 0x66, 0x2d, 0x71,
+	0x2f, 0x7b, 0x1a, 0xb7, 0x11, 0xc7, 0x81, 0x31, 0xe5, 0xfe, 0x5e, 0x84,
+	0x71, 0xd7, 0x56, 0xe6, 0xa2, 0x9f, 0xc6, 0x68, 0x3b, 0x17, 0xda, 0x8d,
+	0xdf, 0xb1, 0xb2, 0xa1, 0x5e, 0xc6, 0x54, 0x0f, 0x0e, 0x9b, 0x5f, 0xb6,
+	0x2e, 0xdb, 0xf8, 0xa4, 0x94, 0xd7, 0xd7, 0xe3, 0x9e, 0x89, 0x25, 0xf0,
+	0xe9, 0x52, 0xb7, 0x03, 0x48, 0xd4, 0xf8, 0x50, 0xa1, 0x4b, 0xbd, 0xd9,
+	0xd7, 0x3a, 0x77, 0x42, 0x49, 0xff, 0x51, 0x8c, 0xef, 0xf5, 0xb8, 0x9f,
+	0x79, 0x60, 0x77, 0xf2, 0x1e, 0xdc, 0x17, 0xaa, 0x40, 0x90, 0x7a, 0xda,
+	0x1f, 0x0a, 0x30, 0xbf, 0xfe, 0x7e, 0x91, 0xce, 0xb3, 0x65, 0xc5, 0xbe,
+	0xfa, 0x1a, 0xb6, 0xaa, 0x65, 0x8c, 0xad, 0x9b, 0x94, 0x39, 0x51, 0xa6,
+	0x35, 0x32, 0xa9, 0x23, 0xc8, 0x7e, 0x76, 0x7d, 0x52, 0x1b, 0x5c, 0xef,
+	0x8e, 0x49, 0xaf, 0x92, 0x0b, 0x12, 0xd7, 0xe5, 0xe3, 0xf1, 0xee, 0x26,
+	0xd1, 0xb1, 0x1e, 0xc1, 0x26, 0xea, 0x69, 0x4b, 0x3e, 0xcc, 0x18, 0x5a,
+	0x28, 0x13, 0x8c, 0x94, 0xce, 0x5f, 0xa7, 0x15, 0x21, 0xad, 0xc8, 0xa4,
+	0xe0, 0xb5, 0x0c, 0xf1, 0x9a, 0xce, 0x38, 0xb4, 0xac, 0x75, 0xc4, 0x69,
+	0x81, 0x53, 0x32, 0x6f, 0x8a, 0x1d, 0x21, 0xb6, 0x6d, 0x22, 0xee, 0xed,
+	0xa1, 0x57, 0x5b, 0xb7, 0xd4, 0xc7, 0x8d, 0x36, 0x85, 0x47, 0x66, 0x9a,
+	0xe1, 0x73, 0x93, 0xe6, 0x3b, 0xf9, 0x10, 0x2e, 0xe7, 0x23, 0x78, 0x9b,
+	0xb4, 0x2f, 0xd9, 0xb4, 0xeb, 0xf0, 0x8b, 0x62, 0xde, 0x4a, 0x32, 0x6f,
+	0x6d, 0x98, 0x50, 0xf4, 0xd7, 0x28, 0x86, 0x8c, 0xbf, 0xfe, 0xec, 0xd2,
+	0xcd, 0x3e, 0xea, 0x4d, 0x64, 0xf1, 0xf0, 0x7b, 0x14, 0xfb, 0xed, 0x3c,
+	0xfd, 0xda, 0x67, 0x53, 0x35, 0xb4, 0x15, 0x75, 0x5f, 0x5d, 0x7c, 0x6f,
+	0xe5, 0x54, 0xa1, 0x28, 0xaf, 0x0e, 0xd7, 0xa9, 0x04, 0xca, 0x4e, 0x5d,
+	0xe3, 0x55, 0x97, 0xf8, 0x60, 0x65, 0x7d, 0xe4, 0xfb, 0x5c, 0xff, 0x21,
+	0x62, 0x3e, 0x8b, 0xeb, 0x5f, 0xb5, 0xd7, 0x0d, 0x73, 0x5d, 0x75, 0x0d,
+	0x1f, 0x46, 0xae, 0xbd, 0x13, 0xa2, 0xec, 0x78, 0x38, 0x42, 0xdd, 0x5d,
+	0x59, 0x23, 0xcf, 0x05, 0x70, 0x7b, 0x7e, 0x55, 0xb9, 0xe4, 0x71, 0x3f,
+	0xfb, 0x01, 0xc7, 0x97, 0x88, 0xf7, 0xcc, 0xe7, 0x79, 0x4f, 0xf0, 0xd7,
+	0x7a, 0x62, 0x8d, 0xcf, 0xeb, 0x3d, 0x4c, 0x5b, 0x94, 0xd1, 0x78, 0x72,
+	0xef, 0x8b, 0xea, 0xe8, 0x9f, 0x61, 0x90, 0xbd, 0xd0, 0x43, 0x13, 0x59,
+	0xec, 0x9f, 0xf8, 0x63, 0x7b, 0x8f, 0x6e, 0xe5, 0x6a, 0xec, 0xe1, 0x9a,
+	0xfb, 0xaa, 0x19, 0x47, 0xff, 0x2d, 0x19, 0x17, 0x8c, 0xb4, 0xbd, 0x12,
+	0x52, 0x6b, 0xe3, 0x2d, 0xb7, 0x2a, 0x0b, 0x65, 0x49, 0x0c, 0xb4, 0x37,
+	0xc7, 0x13, 0x97, 0xf1, 0x88, 0x25, 0xf3, 0x6e, 0x77, 0xb1, 0xee, 0x12,
+	0x97, 0xaa, 0x76, 0xd6, 0xde, 0xb6, 0x22, 0x56, 0xda, 0x50, 0x78, 0xf3,
+	0x73, 0x33, 0x05, 0xe9, 0xc7, 0xa5, 0xde, 0xf8, 0x55, 0x1b, 0xd7, 0x39,
+	0xcc, 0x9c, 0xfd, 0xac, 0xf1, 0x62, 0x84, 0xd5, 0x18, 0x9e, 0x55, 0x0a,
+	0x07, 0x0c, 0x2f, 0xb2, 0x61, 0x0b, 0xdb, 0xf9, 0xbd, 0x97, 0xf8, 0xe9,
+	0x5d, 0xa3, 0x0a, 0x53, 0xa1, 0x10, 0x31, 0x23, 0x73, 0xb0, 0xeb, 0xff,
+	0x78, 0x65, 0x5f, 0x27, 0xea, 0x92, 0x3d, 0xf8, 0x7f, 0x6d, 0x5f, 0x66,
+	0x15, 0xf1, 0x8b, 0xc8, 0xee, 0x57, 0xcc, 0xa1, 0x09, 0x10, 0xd3, 0xec,
+	0x32, 0xe6, 0xa3, 0x2e, 0xa4, 0xaf, 0xba, 0xa0, 0x9d, 0x7e, 0x87, 0x7d,
+	0xde, 0x43, 0xf5, 0xda, 0xe9, 0x56, 0xb7, 0x8e, 0xc1, 0xe3, 0x3e, 0x3c,
+	0x78, 0xbc, 0x03, 0xd5, 0xf6, 0x7c, 0x68, 0x94, 0x3a, 0x75, 0xb1, 0xbf,
+	0x1a, 0xfe, 0xd4, 0xc3, 0x3e, 0xeb, 0xea, 0xea, 0x87, 0xd1, 0x62, 0x5f,
+	0x1f, 0xc1, 0x9e, 0x09, 0xbf, 0xda, 0x32, 0xe1, 0x41, 0xc7, 0x9d, 0x0f,
+	0xc3, 0xbb, 0xaa, 0x97, 0x7c, 0xc9, 0x75, 0xf9, 0xfd, 0x2e, 0xf6, 0x67,
+	0xc2, 0x5f, 0x19, 0xa2, 0x4b, 0xc8, 0xdb, 0x2a, 0x1d, 0x43, 0xc7, 0x3d,
+	0x6a, 0x87, 0xf9, 0x37, 0xd6, 0x55, 0x7b, 0xcf, 0x47, 0xae, 0x55, 0xc8,
+	0x59, 0x00, 0x3e, 0x23, 0x39, 0xa7, 0x0f, 0x13, 0x8c, 0xed, 0xbb, 0xec,
+	0xf7, 0x8f, 0x97, 0x39, 0x32, 0xa5, 0xd9, 0xb7, 0xb6, 0xd3, 0x7e, 0xf2,
+	0x4c, 0x6b, 0xf1, 0xda, 0x7a, 0x9f, 0x73, 0xde, 0x40, 0x7c, 0xa1, 0x0f,
+	0xcb, 0x68, 0x84, 0xfa, 0xb8, 0x5d, 0xa7, 0x50, 0x9f, 0x67, 0x42, 0x5d,
+	0xe2, 0xf0, 0xfb, 0x80, 0x39, 0xcf, 0x9e, 0x53, 0x67, 0xde, 0xa4, 0xee,
+	0x16, 0xcb, 0xfb, 0x55, 0xbe, 0xdf, 0x7e, 0x5f, 0xf2, 0x2d, 0xb1, 0x66,
+	0x50, 0x30, 0xe7, 0x17, 0xdd, 0xff, 0x5d, 0xc8, 0x3d, 0x8f, 0xfe, 0xa7,
+	0x8c, 0xe3, 0x78, 0x77, 0xa5, 0x4b, 0xfc, 0xe7, 0x4f, 0x71, 0xdf, 0xf4,
+	0x30, 0xef, 0x0b, 0xfd, 0x83, 0xec, 0x25, 0x3c, 0xaa, 0x93, 0xf9, 0x67,
+	0xef, 0x71, 0xd7, 0xed, 0x65, 0xf8, 0x4b, 0xab, 0x7c, 0xf1, 0x10, 0xea,
+	0x93, 0x23, 0x7c, 0x5e, 0xa1, 0x9d, 0xb8, 0xf1, 0x31, 0x63, 0x03, 0x3a,
+	0x6a, 0x24, 0x07, 0x3c, 0x6b, 0xf5, 0xf5, 0x88, 0x0e, 0x15, 0x36, 0xf2,
+	0xfa, 0x73, 0xb4, 0xef, 0x93, 0x86, 0x07, 0xf5, 0x8b, 0x64, 0xd6, 0xa7,
+	0x8d, 0xa7, 0xf1, 0x75, 0x9f, 0xb3, 0xf7, 0x95, 0xb5, 0xaa, 0x75, 0x7d,
+	0xe0, 0x0e, 0x57, 0xfd, 0xf8, 0x1b, 0xf4, 0xa7, 0xb6, 0x55, 0x37, 0xde,
+	0x2b, 0xe9, 0xc4, 0x40, 0x64, 0xd5, 0x33, 0x16, 0x6e, 0x1a, 0x46, 0x68,
+	0xd5, 0x8d, 0xf6, 0x2f, 0xf1, 0x7d, 0x90, 0x31, 0x88, 0x6c, 0x75, 0x4a,
+	0xe6, 0x3f, 0x71, 0xd2, 0x39, 0x88, 0x3f, 0x2c, 0x8c, 0xe0, 0xc0, 0x44,
+	0x11, 0x5b, 0xd3, 0xb7, 0xf5, 0x55, 0xd7, 0x65, 0x7b, 0x60, 0x22, 0xde,
+	0x5b, 0x55, 0x94, 0x6d, 0x1f, 0xfb, 0x8c, 0x4a, 0xe6, 0xd8, 0xfb, 0xa9,
+	0xd3, 0x01, 0x5b, 0xa7, 0x3d, 0x30, 0xf2, 0xd7, 0xe9, 0xf6, 0x93, 0xae,
+	0x3f, 0x25, 0x7a, 0x93, 0xfd, 0xb6, 0x83, 0xd8, 0x4b, 0xba, 0xbb, 0x6f,
+	0xa0, 0xdb, 0x67, 0x5c, 0xa7, 0xbb, 0x6b, 0x22, 0x7e, 0xda, 0x55, 0xa4,
+	0xfb, 0xed, 0xe9, 0x12, 0x8d, 0x2c, 0xb6, 0xad, 0xca, 0x22, 0xbf, 0x6e,
+	0x9f, 0xb5, 0xcf, 0xd6, 0xc7, 0x59, 0xfb, 0xfa, 0xc6, 0x7a, 0x89, 0x07,
+	0xfe, 0x9a, 0xd2, 0xed, 0xbd, 0x7d, 0x07, 0x7b, 0xdd, 0x18, 0x1f, 0xda,
+	0x9b, 0x5b, 0xdc, 0x69, 0xc6, 0x76, 0xd8, 0xb7, 0xf9, 0x73, 0x33, 0x8d,
+	0x0e, 0xf6, 0x61, 0x9b, 0xcc, 0x2e, 0x7f, 0xa7, 0xe9, 0x23, 0xee, 0xaa,
+	0x54, 0x1b, 0x27, 0x64, 0xb6, 0x21, 0xb1, 0x5c, 0xc4, 0xc2, 0x05, 0xe9,
+	0xf7, 0x76, 0xb2, 0x4f, 0x58, 0x46, 0xfb, 0xf6, 0xe2, 0x48, 0xa1, 0x57,
+	0xa5, 0xc3, 0x5c, 0xc7, 0x94, 0xba, 0x02, 0xd6, 0xbc, 0x6e, 0x54, 0xd2,
+	0x97, 0xc2, 0xa9, 0x81, 0xd4, 0xc9, 0x7a, 0x0b, 0xc4, 0x28, 0xbe, 0x45,
+	0xa9, 0x6c, 0x6a, 0x7b, 0xbd, 0x1b, 0xc7, 0x6c, 0xfc, 0xa5, 0x4d, 0xf1,
+	0x33, 0x2e, 0x31, 0x73, 0xc7, 0x84, 0xd4, 0x31, 0x42, 0x48, 0x7d, 0x08,
+	0xff, 0x90, 0x9c, 0x1f, 0xa8, 0x41, 0xfa, 0xde, 0x1a, 0x48, 0x5f, 0x71,
+	0x04, 0x3f, 0xd2, 0x23, 0xbe, 0x4c, 0xc1, 0xa3, 0xb6, 0x98, 0x33, 0xfe,
+	0xad, 0x66, 0x10, 0x01, 0xf6, 0x65, 0x5d, 0xee, 0x18, 0xfb, 0x0c, 0xd1,
+	0x63, 0x67, 0xeb, 0xb2, 0x7c, 0xc6, 0xdf, 0x6e, 0x3a, 0xb9, 0xf0, 0x96,
+	0x29, 0x9f, 0xbf, 0x63, 0x32, 0x16, 0x39, 0x62, 0x63, 0xb1, 0xae, 0xd6,
+	0x58, 0xde, 0xb2, 0x5e, 0x31, 0xe6, 0xaf, 0x96, 0x3b, 0x3d, 0x48, 0x6b,
+	0x22, 0xdf, 0x84, 0xbb, 0x89, 0x9f, 0xda, 0x26, 0x9b, 0x60, 0x4c, 0x02,
+	0x27, 0x8e, 0x47, 0xb0, 0x72, 0x42, 0x3b, 0x3d, 0xe8, 0xce, 0x60, 0x7c,
+	0xb6, 0x13, 0x13, 0x05, 0xff, 0x42, 0xd4, 0x45, 0x5c, 0x9d, 0x74, 0xe1,
+	0x76, 0x63, 0xb5, 0x9a, 0xb7, 0x63, 0x5a, 0xe1, 0x2e, 0x63, 0xbb, 0xea,
+	0xb5, 0x31, 0xc5, 0x0c, 0xb1, 0x88, 0xc2, 0x4d, 0xce, 0x5c, 0xbe, 0x35,
+	0x49, 0xcc, 0x7d, 0xfb, 0x84, 0xd4, 0x77, 0x0b, 0xaf, 0x26, 0xa9, 0x97,
+	0x64, 0x36, 0xe3, 0x65, 0x0f, 0xb4, 0x4f, 0x69, 0xdd, 0x86, 0x72, 0x30,
+	0xde, 0xad, 0x33, 0x0e, 0x2e, 0x5c, 0x36, 0xd3, 0xec, 0x97, 0x1c, 0xd4,
+	0x6e, 0x68, 0x11, 0x8f, 0x2b, 0x84, 0x01, 0x9b, 0x46, 0x6f, 0xab, 0x31,
+	0x53, 0x86, 0xa5, 0x7a, 0x0f, 0x4e, 0xdb, 0x32, 0xf4, 0xb7, 0xae, 0x27,
+	0xbe, 0x7e, 0xdc, 0xcc, 0xb0, 0x07, 0x96, 0xfd, 0xd0, 0x58, 0xa2, 0xc5,
+	0xdd, 0x46, 0x0c, 0x1b, 0x8b, 0x2e, 0xa8, 0xb4, 0xca, 0x7a, 0x1a, 0xd3,
+	0x33, 0x60, 0x45, 0xa9, 0x71, 0xea, 0x9b, 0xc8, 0x18, 0x27, 0xce, 0x6a,
+	0x3b, 0xee, 0x5f, 0x48, 0xc3, 0x99, 0xdf, 0x6c, 0x32, 0xfe, 0x37, 0x2e,
+	0x85, 0xb5, 0x23, 0x69, 0xf2, 0xdd, 0xc1, 0xbc, 0x3b, 0xdf, 0xe3, 0xe1,
+	0x7d, 0x99, 0xdb, 0x75, 0xb7, 0x8e, 0xe6, 0x30, 0xef, 0x4e, 0x49, 0x5f,
+	0x85, 0x60, 0x77, 0x01, 0x32, 0x43, 0x62, 0x6f, 0xf1, 0xa9, 0x55, 0xda,
+	0x3b, 0xea, 0x9a, 0x74, 0xf6, 0xc5, 0x72, 0xb3, 0x9e, 0xe0, 0x56, 0xb3,
+	0x19, 0xc7, 0x0a, 0x9e, 0x1b, 0x68, 0xc7, 0x8f, 0xdc, 0xe2, 0x72, 0x21,
+	0xbe, 0xea, 0x2e, 0x55, 0xdc, 0x5b, 0x62, 0x9e, 0xc8, 0xd8, 0x35, 0xb1,
+	0x8c, 0x72, 0x5e, 0x38, 0x29, 0x6b, 0x7c, 0xab, 0x75, 0xf4, 0xa4, 0xd4,
+	0xc8, 0xee, 0xd6, 0x88, 0xa9, 0x75, 0x4b, 0x1f, 0x58, 0x4d, 0x3d, 0x7d,
+	0x34, 0x26, 0x35, 0x78, 0x3f, 0x6b, 0xb0, 0xb6, 0xd0, 0xae, 0xa4, 0x8e,
+	0x69, 0x09, 0xbf, 0xdb, 0x85, 0x2b, 0x0d, 0x5a, 0xe6, 0x79, 0x68, 0xbd,
+	0xce, 0xbc, 0x70, 0x67, 0x6b, 0x63, 0x11, 0x0f, 0xdf, 0x3a, 0xd3, 0x27,
+	0xe7, 0x49, 0x6c, 0x1d, 0x37, 0xe5, 0x05, 0x1b, 0x5b, 0xd6, 0x4b, 0xc9,
+	0x2e, 0xe2, 0x06, 0xc1, 0xc6, 0x72, 0xfd, 0x81, 0xd6, 0x86, 0x29, 0x1f,
+	0x79, 0x53, 0x78, 0x8f, 0x75, 0xe9, 0x48, 0xa1, 0xc4, 0xa3, 0x83, 0x9b,
+	0x37, 0x13, 0x37, 0xbb, 0x53, 0x5a, 0xcb, 0x06, 0xe2, 0x66, 0x9d, 0x3d,
+	0x84, 0x07, 0x3d, 0x78, 0xcc, 0x74, 0xfa, 0x08, 0xc1, 0xce, 0xd6, 0x49,
+	0x2d, 0x2d, 0xb8, 0xf9, 0xea, 0x6a, 0x60, 0x07, 0x71, 0xf3, 0x42, 0xce,
+	0x83, 0x0c, 0x71, 0xf3, 0x47, 0x39, 0x1f, 0xee, 0x20, 0x6e, 0xbe, 0x42,
+	0x8c, 0x75, 0x3e, 0xf9, 0x4b, 0x7c, 0xbb, 0x38, 0x13, 0xdb, 0x95, 0xf0,
+	0xd1, 0xb7, 0x05, 0x3b, 0xff, 0xa6, 0x88, 0x9d, 0xff, 0xcb, 0x3f, 0xc3,
+	0xce, 0x77, 0x13, 0x13, 0x76, 0x4d, 0xc8, 0xfe, 0xd1, 0xae, 0xd6, 0xd7,
+	0x4f, 0xc9, 0x99, 0x95, 0x5b, 0xf1, 0xee, 0xc9, 0xe1, 0x7e, 0x62, 0x65,
+	0x8c, 0x24, 0x33, 0xc8, 0x4d, 0x62, 0x09, 0x71, 0xc1, 0x4b, 0x6e, 0xae,
+	0xbb, 0x32, 0xa9, 0x19, 0x6f, 0xa8, 0x78, 0x67, 0x06, 0x71, 0xf6, 0xca,
+	0xda, 0x02, 0x4d, 0x98, 0xf6, 0xa4, 0x88, 0x8d, 0x59, 0x03, 0x97, 0x12,
+	0x3b, 0x57, 0xcd, 0x01, 0xb5, 0x73, 0x0e, 0x76, 0x96, 0x79, 0x58, 0x55,
+	0x1c, 0x7f, 0x46, 0xec, 0xcc, 0xfe, 0x96, 0xa1, 0x36, 0xd7, 0xc4, 0x18,
+	0x55, 0x38, 0x1c, 0x0f, 0xa0, 0xeb, 0x38, 0x71, 0x8f, 0x3d, 0x0f, 0xb3,
+	0x86, 0x7e, 0x6a, 0x64, 0x70, 0x74, 0xd6, 0x99, 0x87, 0x6d, 0x22, 0x7e,
+	0xf3, 0xc4, 0xc3, 0x28, 0x9f, 0xf3, 0xe0, 0x19, 0xe2, 0xe7, 0x8d, 0xb4,
+	0xf3, 0x19, 0xe2, 0xe7, 0xbb, 0x6f, 0x98, 0x89, 0x4d, 0xcd, 0xe1, 0x15,
+	0x62, 0xf9, 0xba, 0x5a, 0xc4, 0x65, 0xde, 0x61, 0x5d, 0x59, 0x13, 0xc0,
+	0x39, 0x1b, 0x3f, 0xfb, 0x17, 0xb2, 0xca, 0x91, 0xad, 0x8c, 0xb6, 0x10,
+	0xbb, 0xba, 0x68, 0xd7, 0xb6, 0x93, 0x5a, 0xe7, 0x8b, 0xd4, 0x45, 0x63,
+	0xfc, 0xbc, 0x6d, 0x8f, 0xbe, 0xa4, 0xcc, 0x4e, 0x3a, 0x5b, 0xe5, 0x5c,
+	0x55, 0x05, 0xed, 0xbd, 0x65, 0x2c, 0x96, 0xfe, 0x00, 0x4e, 0x4c, 0x26,
+	0xf2, 0x65, 0xc5, 0x7a, 0x28, 0xf7, 0xfa, 0x79, 0x2f, 0x8d, 0xce, 0x35,
+	0x8e, 0x7f, 0x27, 0xf2, 0xc7, 0x88, 0x5d, 0x65, 0xcf, 0x34, 0x14, 0xdc,
+	0x64, 0x76, 0x62, 0xdc, 0x8c, 0xa2, 0xfc, 0x5c, 0x71, 0xef, 0xf5, 0x9c,
+	0x9c, 0xc5, 0xdb, 0xd9, 0x1a, 0xfa, 0x5e, 0x09, 0x13, 0xa6, 0x89, 0xef,
+	0xc2, 0xbe, 0xdb, 0x0b, 0x82, 0x17, 0xbb, 0x71, 0xd4, 0xd4, 0x22, 0x3f,
+	0x67, 0x4c, 0xdc, 0x2b, 0xfb, 0xee, 0x37, 0xcc, 0x9e, 0x1e, 0xe4, 0x3d,
+	0xf3, 0x73, 0xb3, 0xa7, 0xc1, 0x09, 0xfc, 0xc6, 0xdd, 0x5c, 0x0e, 0xd7,
+	0x4a, 0x2f, 0x31, 0xbd, 0x16, 0x19, 0xc1, 0x23, 0xc4, 0x1c, 0xbf, 0x56,
+	0x01, 0xdd, 0xd3, 0xdf, 0xe4, 0xd6, 0x22, 0x33, 0x2a, 0xc0, 0x77, 0x77,
+	0x32, 0xbf, 0xed, 0xa4, 0x6f, 0xc4, 0x16, 0x2a, 0x94, 0x1b, 0x97, 0xbe,
+	0x6c, 0xe3, 0x51, 0x7f, 0x37, 0xaf, 0x8d, 0x17, 0x4a, 0xb8, 0xa6, 0x47,
+	0x78, 0xc5, 0xa6, 0xe3, 0x4e, 0x0e, 0xd1, 0xf3, 0xfe, 0x85, 0x4b, 0x70,
+	0x64, 0xab, 0xa4, 0xac, 0xf7, 0x8f, 0x85, 0xac, 0xde, 0xc5, 0x12, 0xc3,
+	0x3a, 0xb6, 0x99, 0xe2, 0x5f, 0x7d, 0xe4, 0xb3, 0x07, 0x87, 0xcc, 0xa5,
+	0xec, 0xdd, 0x64, 0x0e, 0xda, 0x44, 0x6c, 0xdd, 0xcd, 0x1a, 0x6c, 0x59,
+	0x83, 0x46, 0xd6, 0x6a, 0x5a, 0xab, 0x1b, 0x79, 0x35, 0x5f, 0x13, 0x21,
+	0xbe, 0x59, 0xc5, 0xda, 0xdd, 0x56, 0x68, 0xc2, 0x1b, 0x67, 0x74, 0xfa,
+	0x66, 0x3b, 0xf1, 0x7b, 0x37, 0xee, 0xa1, 0x3c, 0xdf, 0x2e, 0x7c, 0x07,
+	0xe9, 0x6f, 0x78, 0x70, 0xe4, 0x78, 0x1a, 0xeb, 0x57, 0x0d, 0xe1, 0xd2,
+	0x37, 0x7d, 0xcc, 0x55, 0x01, 0x3c, 0x7e, 0x5c, 0xf2, 0x6b, 0x09, 0x6f,
+	0xdf, 0x88, 0x45, 0x7c, 0x88, 0xda, 0x38, 0xe4, 0x8b, 0xef, 0x39, 0x18,
+	0xc5, 0xcf, 0xfe, 0xb7, 0xf4, 0x3e, 0xf3, 0xd0, 0xaa, 0x7f, 0x86, 0x67,
+	0x88, 0x5b, 0x88, 0x05, 0x2a, 0x12, 0xf6, 0xb9, 0xb7, 0x12, 0xde, 0xf5,
+	0xd0, 0x07, 0x24, 0xa6, 0x97, 0x32, 0xd6, 0x2d, 0x62, 0xe7, 0x85, 0xe2,
+	0x5c, 0xf2, 0xed, 0x93, 0xda, 0xc5, 0x43, 0x88, 0x11, 0x43, 0xa3, 0x4f,
+	0xb0, 0x9b, 0x9b, 0x78, 0xf7, 0x4a, 0x3c, 0x6e, 0x9c, 0x23, 0xde, 0x1d,
+	0xa6, 0xad, 0x3d, 0xba, 0xf8, 0x66, 0x08, 0x65, 0x73, 0x11, 0xfa, 0xa4,
+	0xcc, 0x25, 0x5f, 0xf1, 0x3b, 0x73, 0x49, 0x99, 0x85, 0xcb, 0xb9, 0x10,
+	0x74, 0x94, 0xb1, 0x77, 0x2b, 0x57, 0x59, 0xe6, 0xe4, 0x29, 0xff, 0x0e,
+	0xe6, 0xf7, 0x8c, 0x19, 0x0e, 0xee, 0x28, 0x84, 0xf8, 0xa9, 0x0b, 0x66,
+	0x0a, 0xbf, 0xc7, 0xe7, 0x23, 0xfc, 0x8e, 0x62, 0x22, 0x5f, 0x5b, 0x21,
+	0xcd, 0xc0, 0x44, 0xde, 0xc9, 0x79, 0xd1, 0xfc, 0x5e, 0xbf, 0x60, 0xcd,
+	0xb6, 0xe3, 0xce, 0xdf, 0xfa, 0x0d, 0x7f, 0x7f, 0x1e, 0xf3, 0x7b, 0xc9,
+	0xf7, 0x99, 0x93, 0x3a, 0x3e, 0x3a, 0x69, 0x63, 0xfe, 0x79, 0x62, 0xfe,
+	0x01, 0xaf, 0x5b, 0xb0, 0xe6, 0xaf, 0xac, 0xf3, 0xf1, 0x78, 0xef, 0x34,
+	0xfd, 0xa0, 0x8b, 0x74, 0x5d, 0x7a, 0xd8, 0xe6, 0xd7, 0xe1, 0xd3, 0x99,
+	0xe5, 0x5e, 0x3e, 0x99, 0xc0, 0x3b, 0xd7, 0x67, 0xa7, 0x9f, 0x94, 0xd9,
+	0x33, 0x60, 0x3c, 0xf2, 0xee, 0x5a, 0xf8, 0x5a, 0xd8, 0x6f, 0x7a, 0xf9,
+	0x7c, 0xc4, 0x7e, 0x5e, 0x66, 0xb9, 0x9f, 0x7c, 0x56, 0xc2, 0xd3, 0x1f,
+	0x5d, 0x7f, 0xe7, 0x20, 0x3b, 0x35, 0xdf, 0x79, 0xc6, 0x96, 0xdb, 0x7e,
+	0x4e, 0xe6, 0xad, 0xfe, 0x05, 0xd8, 0xf1, 0xf5, 0xfb, 0x94, 0x49, 0xec,
+	0x7b, 0xc0, 0x72, 0xfc, 0x36, 0x1c, 0xdc, 0xc6, 0x78, 0xf8, 0x2e, 0xed,
+	0xb3, 0xed, 0x5c, 0x5d, 0xf0, 0x2e, 0xb3, 0xd3, 0x96, 0xf9, 0xae, 0x73,
+	0x52, 0x93, 0xe4, 0xfe, 0x1f, 0x54, 0x08, 0x1e, 0x7f, 0x9c, 0x35, 0x6b,
+	0xd8, 0x94, 0xd9, 0x3e, 0x94, 0x27, 0x75, 0x08, 0x9b, 0xc6, 0xa3, 0x78,
+	0xdb, 0xf0, 0x17, 0xcf, 0xb0, 0x48, 0x4c, 0x0e, 0x30, 0x26, 0xc3, 0x18,
+	0x31, 0x63, 0xd1, 0xb7, 0x89, 0x4f, 0xb3, 0x64, 0xf8, 0xe8, 0x84, 0x1b,
+	0x6f, 0x13, 0x33, 0x42, 0x39, 0x67, 0x40, 0x9d, 0x77, 0x4b, 0xbf, 0x57,
+	0x22, 0x5a, 0x13, 0x6b, 0xd9, 0x8b, 0x3a, 0xe4, 0x98, 0xf3, 0xfd, 0xfa,
+	0x8f, 0x71, 0xec, 0x84, 0x0b, 0xf7, 0xb1, 0xef, 0x4b, 0xdf, 0x69, 0xf0,
+	0xef, 0xc6, 0xfe, 0xf7, 0xf1, 0x0f, 0xd6, 0x94, 0x9c, 0xb3, 0x52, 0x72,
+	0x96, 0xe3, 0x13, 0xab, 0x56, 0xd7, 0xe7, 0x9f, 0x87, 0x3e, 0x78, 0x15,
+	0x8d, 0x03, 0x0b, 0xf8, 0xc0, 0x9a, 0xe7, 0xbd, 0xf7, 0x18, 0x3f, 0x2f,
+	0x1a, 0xb1, 0x88, 0x8b, 0xc2, 0xcc, 0x87, 0xdd, 0xb8, 0xd7, 0x90, 0x7d,
+	0x26, 0x6d, 0xe0, 0x69, 0x68, 0xfd, 0x17, 0x94, 0x9c, 0xcd, 0xb9, 0x64,
+	0x65, 0x6b, 0x64, 0x5d, 0x85, 0x95, 0xcb, 0x1b, 0x3b, 0xcb, 0xa0, 0xb5,
+	0x78, 0x95, 0x6e, 0xbc, 0xaf, 0xfe, 0xa7, 0x35, 0x1f, 0xfe, 0xc4, 0x7a,
+	0x47, 0x2f, 0xd1, 0xd5, 0xa2, 0x3e, 0x77, 0x89, 0xb7, 0x3a, 0x1c, 0x33,
+	0x65, 0x7f, 0xee, 0xc7, 0xb8, 0xef, 0x84, 0x07, 0xed, 0xc9, 0x5f, 0x5a,
+	0xd9, 0xb0, 0xd0, 0x0c, 0x56, 0xa2, 0x42, 0xe8, 0x3b, 0x33, 0xeb, 0x17,
+	0x0a, 0x50, 0x1d, 0xa6, 0xe0, 0x65, 0xf1, 0xd3, 0x71, 0x58, 0xa6, 0xcc,
+	0x11, 0x2d, 0xdc, 0x91, 0x1c, 0xc2, 0x7b, 0xc9, 0xf4, 0x1f, 0xf8, 0xa0,
+	0x5d, 0xbc, 0xec, 0xd6, 0xe6, 0x9b, 0xdc, 0x51, 0xe5, 0x6f, 0xd0, 0x07,
+	0x1a, 0xec, 0x7a, 0x93, 0x67, 0xef, 0x14, 0x60, 0x6e, 0x91, 0x1e, 0x73,
+	0x1c, 0x73, 0x63, 0x59, 0x78, 0x88, 0xed, 0x86, 0x9b, 0xb5, 0xcc, 0x53,
+	0x4a, 0x8b, 0xec, 0x53, 0x51, 0x75, 0x8f, 0x3e, 0x88, 0x67, 0x8c, 0x78,
+	0xba, 0x4d, 0xd5, 0xf9, 0x3a, 0x0b, 0x25, 0xda, 0xed, 0xc4, 0x2a, 0xda,
+	0xfc, 0x65, 0x77, 0x39, 0x6a, 0x57, 0xeb, 0x9d, 0xe5, 0x6e, 0x6d, 0xf0,
+	0x6b, 0x8c, 0xaf, 0xcd, 0x85, 0x79, 0xff, 0xfb, 0x71, 0x17, 0x56, 0xd8,
+	0xfb, 0x08, 0xb9, 0xe2, 0x8c, 0x74, 0x1c, 0x5b, 0xc6, 0xac, 0xf5, 0xaf,
+	0x26, 0xb5, 0xc8, 0x53, 0x2a, 0xbb, 0x23, 0x40, 0x4c, 0x73, 0x3f, 0xf4,
+	0xe8, 0x2c, 0xeb, 0x54, 0x7b, 0xc1, 0x85, 0x5b, 0x4e, 0x09, 0xcd, 0x1c,
+	0x69, 0x1e, 0x42, 0xf9, 0x09, 0x6b, 0xfd, 0x0e, 0x43, 0x1b, 0xbc, 0xec,
+	0xce, 0xfe, 0xd7, 0x5a, 0xea, 0xad, 0x43, 0xc9, 0x3e, 0xda, 0x10, 0x71,
+	0xc5, 0x90, 0x9c, 0x87, 0x4b, 0xfc, 0x39, 0x31, 0xc5, 0x1f, 0xd3, 0x57,
+	0xdd, 0xa9, 0x20, 0xf9, 0xd4, 0x12, 0xd3, 0x90, 0xf9, 0x79, 0x14, 0x97,
+	0x8d, 0xac, 0x7f, 0x53, 0x43, 0x82, 0xd8, 0x2c, 0xc2, 0x3a, 0x18, 0xc5,
+	0x51, 0x62, 0xbc, 0x43, 0x6c, 0x09, 0xe7, 0x43, 0x3a, 0xb1, 0x59, 0x37,
+	0x5c, 0x63, 0x01, 0x35, 0x93, 0x8b, 0x19, 0xed, 0xf8, 0xf7, 0x98, 0x8f,
+	0x88, 0x8b, 0x1c, 0x42, 0xe0, 0xc4, 0xdf, 0x59, 0x55, 0xba, 0xde, 0x32,
+	0xa6, 0xb8, 0xee, 0x13, 0x11, 0xea, 0x98, 0xef, 0xc9, 0xb9, 0x15, 0xb3,
+	0x0b, 0xf7, 0x8c, 0x85, 0xf9, 0x7e, 0x15, 0x56, 0x9e, 0x88, 0xe2, 0x4a,
+	0xf2, 0x66, 0xcc, 0xd7, 0x38, 0x18, 0xc8, 0xaf, 0xd3, 0x8f, 0xd8, 0x67,
+	0x65, 0x0b, 0xba, 0xbd, 0x77, 0x74, 0xc8, 0x94, 0xfe, 0xdc, 0xc3, 0xbf,
+	0x03, 0xfc, 0x88, 0x3e, 0xbf, 0x55, 0xc4, 0x3a, 0xfb, 0x5b, 0xa3, 0x33,
+	0x6f, 0x55, 0xd8, 0x7b, 0x9a, 0x88, 0xf2, 0xb9, 0x90, 0x3d, 0x17, 0x1c,
+	0x26, 0xcd, 0xb3, 0xe3, 0xd2, 0xb7, 0xb5, 0xad, 0xf3, 0x15, 0xf7, 0xdf,
+	0xdf, 0x32, 0x5c, 0x58, 0xcf, 0xde, 0x3e, 0xa2, 0x4b, 0xbd, 0x1c, 0xd6,
+	0x6a, 0xb1, 0x0e, 0xa7, 0x43, 0x6c, 0xc2, 0xf5, 0x7f, 0x87, 0x23, 0xa1,
+	0x04, 0x73, 0xbe, 0x8e, 0x77, 0x73, 0x5f, 0x66, 0xbf, 0x53, 0x27, 0x67,
+	0x77, 0x70, 0xcb, 0x09, 0x2f, 0xd7, 0x5c, 0x4f, 0x5c, 0xb3, 0x09, 0x3f,
+	0x0b, 0x39, 0xbd, 0xc6, 0x61, 0x5e, 0x1f, 0x9d, 0x0e, 0x10, 0x8b, 0xfa,
+	0xf8, 0xb9, 0x91, 0xb7, 0x2f, 0xe2, 0x49, 0x64, 0xf9, 0xd7, 0x78, 0xf2,
+	0x11, 0x0f, 0xe8, 0xb8, 0x9a, 0x7b, 0x09, 0x57, 0x48, 0x3b, 0x3b, 0xed,
+	0xd0, 0x3c, 0x5e, 0x10, 0xba, 0xb2, 0x5e, 0x6c, 0xb0, 0xd6, 0x2d, 0xf4,
+	0x03, 0x72, 0x8e, 0xf7, 0xdf, 0xb8, 0x06, 0x91, 0xdd, 0x09, 0xf6, 0xc7,
+	0x46, 0x03, 0xda, 0x43, 0xb4, 0x97, 0x29, 0x6b, 0x68, 0xec, 0x45, 0xe5,
+	0xdd, 0x08, 0x56, 0x8c, 0x59, 0x43, 0x91, 0x94, 0x5c, 0xb7, 0xac, 0xea,
+	0xb5, 0x7a, 0xe4, 0x0d, 0xe5, 0x61, 0xad, 0xf3, 0x50, 0x07, 0xa3, 0x38,
+	0x9b, 0x6b, 0xbc, 0xf8, 0x1e, 0xb1, 0x53, 0x94, 0xbd, 0xde, 0x25, 0xf7,
+	0x28, 0x66, 0x72, 0xff, 0xb1, 0x52, 0x66, 0x04, 0xa3, 0x85, 0x80, 0x9a,
+	0xce, 0xfd, 0x49, 0xa5, 0xe4, 0xa2, 0x11, 0xfa, 0x42, 0xd3, 0x98, 0xf0,
+	0x6a, 0x0d, 0x55, 0x91, 0xce, 0x51, 0xd2, 0x99, 0x5e, 0xa3, 0x67, 0x46,
+	0x94, 0xe8, 0x2c, 0x40, 0x5c, 0xf7, 0xaa, 0xcc, 0xcf, 0xa8, 0xb7, 0xa7,
+	0xf9, 0xbc, 0xe8, 0x2d, 0x8c, 0x9f, 0x15, 0xe9, 0x3c, 0x56, 0xb8, 0x88,
+	0xe9, 0xdc, 0x25, 0xfb, 0xf7, 0x91, 0x42, 0x82, 0xb5, 0xaf, 0x0f, 0x79,
+	0xe6, 0x93, 0xb1, 0x5c, 0x63, 0x66, 0x8c, 0x7c, 0x38, 0x67, 0xee, 0xfa,
+	0xf0, 0x64, 0xf1, 0x99, 0x61, 0xbe, 0x3b, 0x7c, 0xed, 0x77, 0xd1, 0x91,
+	0xb3, 0xaf, 0xef, 0xec, 0x2b, 0x94, 0xd3, 0x76, 0x4e, 0x1f, 0x7e, 0xd8,
+	0xf4, 0xca, 0x0c, 0x1c, 0x2f, 0x8d, 0xaf, 0xc7, 0x88, 0xf1, 0x97, 0xd8,
+	0x45, 0xb9, 0x47, 0xa9, 0xcf, 0x13, 0xa6, 0xbd, 0x7f, 0x2f, 0xe7, 0xba,
+	0x98, 0xab, 0xbb, 0x5a, 0xcf, 0x10, 0x8b, 0x1d, 0x63, 0xcc, 0xec, 0x49,
+	0x36, 0x76, 0xbf, 0x4c, 0xbf, 0x4b, 0x7f, 0x5d, 0xf6, 0xc8, 0x81, 0xb1,
+	0x89, 0x6f, 0x63, 0xaa, 0xa6, 0x71, 0xe1, 0x59, 0xe6, 0x84, 0xd3, 0xcc,
+	0x53, 0x1e, 0xe6, 0x84, 0xea, 0x09, 0x62, 0x48, 0xe6, 0xa9, 0x79, 0xe6,
+	0x29, 0x8f, 0xde, 0x78, 0x71, 0x06, 0xff, 0x9d, 0x7a, 0x11, 0xfe, 0x62,
+	0x89, 0x19, 0xc8, 0xb3, 0xce, 0xfc, 0x55, 0x9f, 0xe9, 0xc7, 0xa5, 0x9b,
+	0x9d, 0x19, 0x9a, 0x9b, 0x35, 0x7b, 0x77, 0xae, 0x31, 0x34, 0x22, 0xb4,
+	0x7b, 0xb4, 0x48, 0x96, 0xb6, 0x3a, 0x62, 0x63, 0xef, 0x6e, 0xf6, 0x0b,
+	0x72, 0x8e, 0xab, 0x0a, 0x1e, 0xfa, 0xfe, 0x88, 0x21, 0xe7, 0x1b, 0x22,
+	0xc1, 0xcd, 0xb4, 0xe1, 0x88, 0xd9, 0xd8, 0x12, 0x53, 0x3b, 0x70, 0xa9,
+	0x98, 0x63, 0x1d, 0x2c, 0xad, 0x65, 0x8e, 0xa2, 0xb1, 0xfb, 0x7e, 0x7c,
+	0x03, 0xe9, 0x9a, 0xc6, 0xde, 0x71, 0xc4, 0x8c, 0x7b, 0x21, 0xe7, 0x41,
+	0x1d, 0x5a, 0xf5, 0x79, 0x37, 0xf1, 0xc8, 0x27, 0xd6, 0x52, 0xfd, 0x31,
+	0x8c, 0x13, 0x33, 0x36, 0xac, 0xd2, 0x2f, 0x7e, 0xbf, 0x78, 0xcf, 0xd9,
+	0x2b, 0x12, 0x7f, 0xf1, 0x51, 0x07, 0xe5, 0xf0, 0x2c, 0xaa, 0xe3, 0x1a,
+	0xd4, 0x85, 0x7d, 0x56, 0xf8, 0x55, 0x1c, 0xa0, 0xbf, 0x8d, 0x17, 0x14,
+	0x8c, 0xfa, 0x57, 0x31, 0x20, 0xb5, 0x89, 0xef, 0xb4, 0xe5, 0x02, 0xc4,
+	0x29, 0x11, 0x94, 0xeb, 0xb1, 0xe8, 0x30, 0xe5, 0x6b, 0x63, 0x2e, 0x1f,
+	0x65, 0x0e, 0xc9, 0x86, 0x02, 0xf6, 0xf9, 0xd5, 0x72, 0x3d, 0x62, 0xff,
+	0xcf, 0x81, 0xf4, 0x41, 0x0d, 0x53, 0xb2, 0x4f, 0x7d, 0x08, 0xaf, 0x8e,
+	0xcf, 0xe3, 0x58, 0x32, 0x8d, 0xbd, 0x35, 0x21, 0x8c, 0x99, 0x8b, 0xed,
+	0xb9, 0x81, 0xf4, 0x5b, 0x5b, 0x26, 0x0e, 0xda, 0xb3, 0xc8, 0x8d, 0x49,
+	0x57, 0xbd, 0x9c, 0xe3, 0x98, 0x66, 0xdf, 0x35, 0x6e, 0x0c, 0xe1, 0x80,
+	0xf1, 0xc7, 0x30, 0x16, 0x49, 0xee, 0x1c, 0xc1, 0xf9, 0x29, 0xa9, 0x61,
+	0xfd, 0xad, 0xcb, 0xc6, 0x44, 0x3f, 0x2e, 0x62, 0x5e, 0x1f, 0x9a, 0x6c,
+	0x0c, 0x37, 0xd7, 0xba, 0x7c, 0xca, 0xc1, 0x72, 0x4d, 0x79, 0x39, 0x73,
+	0x5d, 0x85, 0x20, 0xf5, 0x75, 0x21, 0xe9, 0x65, 0xce, 0x11, 0x7d, 0xca,
+	0x19, 0x3f, 0x47, 0xce, 0x44, 0x5e, 0x61, 0xa4, 0xf9, 0xc6, 0xfd, 0x15,
+	0xf9, 0xff, 0x83, 0x6b, 0xe7, 0x0e, 0x8b, 0xb3, 0xf1, 0x3f, 0xb7, 0x2e,
+	0xdd, 0x24, 0x72, 0x27, 0x03, 0xcc, 0xe9, 0xd1, 0xa9, 0x6b, 0xfa, 0x15,
+	0x9d, 0x9e, 0x93, 0x9a, 0x61, 0xeb, 0xdc, 0x99, 0xb7, 0x69, 0x03, 0xef,
+	0xa8, 0x46, 0xd6, 0x13, 0xfa, 0x55, 0x0d, 0xfd, 0xad, 0x09, 0xbd, 0x4b,
+	0x53, 0x9e, 0x9e, 0xab, 0xe6, 0x7a, 0xb4, 0xac, 0x7e, 0xd7, 0xc2, 0xcd,
+	0x6d, 0x70, 0xeb, 0x72, 0x7d, 0xca, 0x4a, 0x87, 0xe4, 0x77, 0x33, 0x20,
+	0xb5, 0xfc, 0x05, 0x73, 0xde, 0x5a, 0xbe, 0xd8, 0xc1, 0x86, 0x7f, 0x97,
+	0x93, 0xbd, 0xaf, 0xac, 0xc5, 0x5e, 0xfb, 0xe2, 0xdb, 0xee, 0x83, 0xf8,
+	0xdb, 0xfc, 0x21, 0xbc, 0x39, 0xee, 0x21, 0xce, 0x14, 0x59, 0xd6, 0xa3,
+	0x7a, 0x75, 0x3c, 0xfd, 0x2e, 0xf3, 0xe2, 0xc5, 0xa9, 0x92, 0x5f, 0xcc,
+	0xb5, 0xae, 0x98, 0x52, 0xa4, 0x55, 0x85, 0x32, 0xca, 0xf9, 0x53, 0xc3,
+	0x8d, 0x68, 0x11, 0xdb, 0xba, 0xc9, 0xe7, 0xee, 0x9c, 0x83, 0x79, 0x63,
+	0xf9, 0xc3, 0x01, 0x67, 0xfe, 0x15, 0x60, 0x1e, 0x1d, 0xc5, 0x91, 0x5c,
+	0x63, 0xe2, 0x3d, 0x39, 0xa7, 0xc3, 0x5e, 0xec, 0x12, 0x46, 0x71, 0x22,
+	0x57, 0xca, 0xa1, 0x11, 0x39, 0xdf, 0x9a, 0x88, 0xba, 0x9c, 0x1c, 0x19,
+	0x75, 0x69, 0xd9, 0xa8, 0xeb, 0xe6, 0x80, 0x60, 0x83, 0xe1, 0x42, 0x2c,
+	0x52, 0x0e, 0x37, 0xf6, 0x18, 0x8e, 0x7f, 0xd4, 0xcf, 0x78, 0x11, 0x5d,
+	0x24, 0x75, 0x59, 0x6a, 0xb2, 0x87, 0x35, 0x79, 0x31, 0xd2, 0x8b, 0x3d,
+	0x78, 0x4d, 0x17, 0x7d, 0xec, 0x2f, 0xe9, 0xc3, 0x38, 0x87, 0xfd, 0xd6,
+	0x7c, 0xb7, 0xf8, 0x92, 0x17, 0x87, 0x9a, 0xa6, 0xad, 0xa9, 0xb0, 0xc8,
+	0xee, 0xc6, 0x69, 0xe6, 0x57, 0xdc, 0x1c, 0x8b, 0x9c, 0x66, 0xcd, 0x1e,
+	0xd1, 0x4b, 0x3e, 0x7e, 0x57, 0x91, 0x4f, 0x3d, 0x33, 0x8b, 0x3f, 0xe1,
+	0xef, 0xf5, 0x91, 0xbd, 0xca, 0x59, 0x6f, 0xf9, 0xcc, 0xdb, 0x81, 0xd2,
+	0xec, 0x54, 0x9e, 0x8d, 0xe6, 0x09, 0x3a, 0x2b, 0x84, 0x56, 0x80, 0xfe,
+	0x59, 0x8e, 0xde, 0xb0, 0x9c, 0xf3, 0x10, 0xbd, 0xc8, 0x9e, 0x22, 0xa8,
+	0x0f, 0x0b, 0x2f, 0x51, 0x1f, 0x87, 0xae, 0x9d, 0xa9, 0x72, 0xf2, 0x57,
+	0x05, 0xaf, 0x6f, 0x4e, 0xbe, 0xb8, 0xce, 0x8f, 0xdf, 0x58, 0x97, 0xc2,
+	0x11, 0xe6, 0x04, 0xb1, 0x69, 0xc6, 0xc6, 0x91, 0x6e, 0xe2, 0x93, 0xdd,
+	0xf6, 0xf9, 0x11, 0xc6, 0x81, 0x79, 0x4d, 0x8e, 0xf9, 0x3e, 0xe2, 0xec,
+	0xb9, 0x9c, 0x7d, 0x66, 0xaf, 0xf7, 0x0d, 0x15, 0x63, 0xae, 0xf9, 0x12,
+	0x7a, 0x6b, 0x85, 0x5e, 0x28, 0xb8, 0x6d, 0x32, 0x41, 0x1d, 0xd4, 0x09,
+	0x5d, 0xeb, 0x29, 0x76, 0x73, 0x87, 0xc6, 0x84, 0x3e, 0x30, 0x32, 0x16,
+	0xeb, 0xff, 0x29, 0xb0, 0xae, 0x0a, 0xda, 0xe0, 0x6c, 0xf1, 0xff, 0x38,
+	0x7e, 0xa1, 0x84, 0x96, 0xd0, 0xf1, 0xc0, 0x64, 0x8e, 0x3b, 0x3e, 0x57,
+	0x41, 0xdd, 0x69, 0xdd, 0x3f, 0x50, 0x15, 0x78, 0xec, 0x89, 0x04, 0x79,
+	0x5f, 0x14, 0xdc, 0x3c, 0xe9, 0x83, 0xff, 0x4c, 0x15, 0x6b, 0xae, 0x0f,
+	0x97, 0x9b, 0x69, 0xd7, 0x27, 0x4a, 0xbc, 0xdb, 0x7b, 0xa3, 0x78, 0x74,
+	0x22, 0x0a, 0x93, 0x3e, 0x3b, 0x67, 0xca, 0x3e, 0xb0, 0xcf, 0xce, 0x9f,
+	0x17, 0xd7, 0xd4, 0xd9, 0x7b, 0x54, 0xcf, 0x16, 0xf4, 0xc8, 0x59, 0x55,
+	0x85, 0x0f, 0x4e, 0xcc, 0xdf, 0x5c, 0x0e, 0xeb, 0x85, 0xa5, 0xa9, 0x78,
+	0x66, 0x17, 0x7d, 0x7e, 0xc5, 0xf2, 0x30, 0x7b, 0x19, 0xf6, 0x94, 0x6b,
+	0xa5, 0xff, 0x1d, 0x60, 0xff, 0x5b, 0xda, 0xd3, 0xd7, 0xfb, 0x1f, 0x52,
+	0xd9, 0x4d, 0x41, 0x58, 0x1f, 0x95, 0xa7, 0xac, 0x8f, 0xbd, 0xa9, 0x38,
+	0xdf, 0x97, 0x3d, 0x3d, 0xcb, 0x7a, 0xab, 0xd9, 0xb2, 0xf2, 0xcd, 0xb1,
+	0x4c, 0xc8, 0x1d, 0xc2, 0x99, 0x06, 0xd9, 0x07, 0x74, 0xe1, 0x83, 0xb8,
+	0x1e, 0xd9, 0x05, 0xd9, 0x7b, 0x67, 0x8e, 0x5f, 0x2c, 0xe7, 0x0e, 0xeb,
+	0x82, 0x9d, 0xe6, 0x22, 0x3c, 0x33, 0xbb, 0x16, 0xbd, 0x5e, 0xd8, 0xe7,
+	0x62, 0x2c, 0x03, 0x6f, 0x2c, 0x85, 0xd4, 0xed, 0x78, 0xcb, 0x43, 0x08,
+	0x63, 0xb6, 0x70, 0x08, 0x0f, 0x9e, 0x90, 0xfd, 0xc5, 0x07, 0x5a, 0x7d,
+	0x27, 0xac, 0xbf, 0x8b, 0xa4, 0xe6, 0x99, 0x17, 0x2d, 0xab, 0x62, 0x6d,
+	0x63, 0x84, 0xe5, 0x88, 0x18, 0xa3, 0x57, 0xb0, 0x7b, 0xff, 0x07, 0xa8,
+	0xc1, 0xd9, 0xe9, 0xf4, 0xcd, 0xec, 0x25, 0x3b, 0x9f, 0x54, 0x21, 0x3c,
+	0x4f, 0x19, 0x9f, 0x2e, 0x08, 0x4e, 0x79, 0xb0, 0x75, 0xcb, 0x89, 0x25,
+	0x78, 0x61, 0x36, 0x8c, 0xb3, 0xa6, 0x4e, 0x9c, 0x04, 0x55, 0x99, 0xb2,
+	0xaa, 0xab, 0xc9, 0x6b, 0xa5, 0xdb, 0x8d, 0x4d, 0x49, 0xe9, 0x0f, 0xf5,
+	0xfe, 0x80, 0xc2, 0x92, 0x72, 0xe8, 0x0b, 0xfb, 0x81, 0x01, 0x3f, 0xfb,
+	0xd5, 0x27, 0x55, 0x3c, 0xf3, 0xbe, 0x3b, 0x8c, 0xe7, 0x99, 0x7f, 0x7e,
+	0x50, 0x90, 0x33, 0x53, 0xcc, 0x31, 0xd3, 0x51, 0xda, 0xca, 0x07, 0x57,
+	0x7d, 0x15, 0x0e, 0x33, 0x5e, 0x5e, 0x32, 0xca, 0x98, 0xa3, 0xe4, 0x0c,
+	0x95, 0xe4, 0xf7, 0x9d, 0x72, 0x56, 0xc4, 0x7a, 0x56, 0x77, 0xfa, 0x7d,
+	0x63, 0xe6, 0xc6, 0x73, 0xc8, 0x21, 0xe6, 0xf5, 0xc6, 0xee, 0x88, 0x7a,
+	0xc5, 0x4a, 0x7f, 0x5d, 0x51, 0xce, 0xdd, 0x55, 0xa8, 0xb0, 0x65, 0xc5,
+	0xf0, 0x44, 0xa9, 0xa6, 0x54, 0x4b, 0x2f, 0xd7, 0x9d, 0x2d, 0xfa, 0x60,
+	0x25, 0x63, 0xfd, 0x28, 0x6b, 0x74, 0xf9, 0x09, 0xa9, 0x25, 0xec, 0x5f,
+	0xd4, 0x7a, 0x62, 0x61, 0xc1, 0x0d, 0x3e, 0xdc, 0x1f, 0xd2, 0x5a, 0xe4,
+	0x2c, 0xf6, 0xd3, 0x85, 0x0e, 0x8f, 0x9c, 0x89, 0x7a, 0xa6, 0x20, 0xb5,
+	0x5c, 0x72, 0x41, 0x69, 0xbd, 0x08, 0x6a, 0xc7, 0xc4, 0x46, 0xdd, 0xad,
+	0x1f, 0x8d, 0x05, 0xe4, 0xdc, 0xfc, 0x90, 0x8b, 0xbd, 0xb6, 0x6f, 0xcc,
+	0xb2, 0xee, 0x6e, 0xd6, 0xfb, 0xd7, 0xbb, 0x65, 0x3f, 0x39, 0xd6, 0x7b,
+	0x4e, 0x69, 0x2d, 0x47, 0xd4, 0x8d, 0x74, 0x9e, 0xab, 0x92, 0x18, 0xc9,
+	0x52, 0xce, 0x47, 0x6d, 0x99, 0xf6, 0x53, 0xa6, 0xd2, 0x99, 0xa1, 0x2a,
+	0x5c, 0x1e, 0x87, 0xce, 0xa8, 0xc5, 0x79, 0x83, 0xc9, 0x29, 0x14, 0x4f,
+	0xb7, 0x43, 0xfc, 0x5f, 0xeb, 0x15, 0x0c, 0x55, 0xc9, 0x9c, 0x3c, 0x3d,
+	0x2e, 0x35, 0x46, 0x09, 0x3e, 0xc9, 0x56, 0xa7, 0x06, 0x70, 0x65, 0x0d,
+	0xf0, 0xca, 0x98, 0xb3, 0xdf, 0x5e, 0x3c, 0xe3, 0x6d, 0x9f, 0x65, 0x78,
+	0xc8, 0x3e, 0xa3, 0x20, 0xf4, 0x0f, 0xe2, 0x4c, 0x4e, 0x30, 0xe5, 0x00,
+	0x31, 0x65, 0x6c, 0x90, 0x78, 0xb3, 0xa5, 0xe0, 0x9c, 0xb7, 0x32, 0x3e,
+	0xa2, 0xcf, 0x3f, 0x49, 0xac, 0x7a, 0x18, 0xce, 0x7e, 0x7b, 0x43, 0xf1,
+	0x0c, 0x42, 0x2c, 0xdf, 0xa9, 0xb6, 0x16, 0xec, 0x33, 0x5a, 0x8c, 0xb1,
+	0x76, 0xb5, 0x79, 0xb6, 0x43, 0x6d, 0x99, 0xed, 0x52, 0x3b, 0x0a, 0xd2,
+	0xb3, 0x3e, 0xd0, 0x7a, 0xff, 0x89, 0xed, 0x6a, 0xeb, 0x74, 0x8f, 0x22,
+	0xa6, 0x0d, 0xf9, 0x52, 0x19, 0xd5, 0x35, 0xeb, 0xcc, 0xcf, 0x3b, 0xd9,
+	0x77, 0x6d, 0x35, 0x4b, 0xfd, 0xbc, 0xfc, 0x1f, 0x57, 0x58, 0xfe, 0x67,
+	0xa2, 0x77, 0xa3, 0xb2, 0xac, 0x5b, 0x93, 0x7f, 0x2d, 0xf6, 0xb0, 0x9e,
+	0x4e, 0xb2, 0x36, 0x9a, 0x55, 0xe8, 0x63, 0xdf, 0x31, 0x6c, 0x2c, 0x2b,
+	0xee, 0x97, 0x89, 0x4c, 0x72, 0x4e, 0x42, 0xfc, 0x15, 0x59, 0xf6, 0x20,
+	0xf8, 0x7b, 0xf2, 0xbf, 0xb7, 0x28, 0x57, 0x97, 0x9c, 0x23, 0xf0, 0x5e,
+	0x3f, 0x47, 0x76, 0x6c, 0xec, 0xba, 0x5c, 0x1e, 0x5e, 0x1b, 0x25, 0x3e,
+	0xdd, 0xab, 0xb4, 0xc1, 0xa7, 0x1c, 0xb9, 0x2e, 0x5e, 0x66, 0x0c, 0x0f,
+	0xdb, 0x31, 0xec, 0xc8, 0xb5, 0xb2, 0x28, 0xd7, 0x8a, 0x7c, 0xa7, 0x7d,
+	0x3e, 0x8b, 0x74, 0x5a, 0xe7, 0xc6, 0xe4, 0x1c, 0x99, 0xcc, 0x2e, 0x45,
+	0x36, 0x91, 0xe3, 0x84, 0x55, 0xa1, 0x77, 0xa9, 0x6d, 0xf6, 0xb9, 0x32,
+	0x39, 0xd3, 0x25, 0xfb, 0xfb, 0x25, 0xb9, 0xa4, 0x8e, 0x2f, 0x0a, 0x76,
+	0x4c, 0xca, 0x39, 0x6b, 0xcb, 0xfa, 0x99, 0x51, 0x11, 0x14, 0x59, 0xce,
+	0x1a, 0x22, 0x8b, 0x9c, 0x17, 0x29, 0xc9, 0xf3, 0xb5, 0xa2, 0x3c, 0x62,
+	0xab, 0xeb, 0x76, 0x2a, 0xfd, 0xff, 0xdf, 0xdb, 0x39, 0xe7, 0x2c, 0x49,
+	0x49, 0x9e, 0x60, 0x4a, 0xf8, 0xcf, 0xb7, 0x8e, 0x8e, 0x0f, 0xe0, 0x15,
+	0xde, 0xff, 0x65, 0xae, 0x24, 0x97, 0x1b, 0x33, 0xd3, 0xa5, 0x33, 0x72,
+	0x6c, 0x29, 0xcd, 0x98, 0x31, 0x42, 0x3f, 0x72, 0xe4, 0x93, 0x33, 0x72,
+	0x8d, 0xf3, 0x97, 0xed, 0xb9, 0x57, 0x3c, 0xcd, 0x7e, 0x19, 0x67, 0x0b,
+	0xbf, 0x6d, 0xbf, 0xa6, 0x7c, 0x05, 0x7b, 0x64, 0xa1, 0x3d, 0x47, 0xda,
+	0x72, 0x96, 0x44, 0xe1, 0xa9, 0x69, 0x60, 0xda, 0xe4, 0xb2, 0xa9, 0x21,
+	0x3c, 0x6e, 0x58, 0xd6, 0x93, 0xcd, 0xba, 0x9c, 0x01, 0xba, 0x50, 0x6b,
+	0xcf, 0x85, 0x60, 0x54, 0xe9, 0xb2, 0x77, 0x27, 0xe7, 0x48, 0x7a, 0xa8,
+	0x03, 0x91, 0x5d, 0x7c, 0xa0, 0x64, 0x7b, 0x39, 0xdf, 0x96, 0xa5, 0x7e,
+	0x44, 0x37, 0xa5, 0x73, 0x6e, 0x32, 0x73, 0xb9, 0x51, 0x27, 0xb7, 0xd9,
+	0x3a, 0x79, 0xda, 0x10, 0x7f, 0x65, 0xf6, 0xa1, 0xaf, 0xce, 0x10, 0x3f,
+	0x8c, 0x18, 0x5e, 0x1b, 0xab, 0x1d, 0x26, 0x3e, 0x39, 0xc2, 0xd8, 0x79,
+	0xd4, 0xbc, 0x88, 0x8b, 0xf9, 0x97, 0xf0, 0xca, 0xb5, 0xff, 0x85, 0x13,
+	0x7f, 0xf1, 0xb5, 0x6c, 0xb1, 0xcf, 0x32, 0xfd, 0x75, 0xcb, 0xb2, 0xb8,
+	0xe4, 0xa1, 0x93, 0x4d, 0x72, 0xb6, 0xa9, 0x3c, 0xf5, 0xde, 0x3a, 0xd9,
+	0xdf, 0x2a, 0x4b, 0x0d, 0x7e, 0xf5, 0x82, 0x2e, 0xba, 0xf9, 0x64, 0xf5,
+	0x19, 0x5d, 0xe4, 0xd2, 0x8d, 0x51, 0xfb, 0x7f, 0x33, 0x43, 0x6b, 0x77,
+	0xeb, 0x12, 0x3b, 0xef, 0x34, 0xb7, 0xd9, 0x39, 0x61, 0x30, 0x75, 0xab,
+	0xad, 0x83, 0x83, 0xa9, 0x65, 0x8e, 0x2e, 0x52, 0x09, 0xfb, 0xfb, 0xe1,
+	0x94, 0xa3, 0x9b, 0x5c, 0xaa, 0xde, 0xfe, 0x1e, 0x4d, 0x39, 0x67, 0xa2,
+	0xb3, 0x29, 0xdd, 0xfe, 0x1e, 0x4f, 0xc5, 0xec, 0xef, 0x23, 0xa9, 0x5b,
+	0xae, 0xf3, 0xc5, 0x9f, 0xff, 0x07, 0xd8, 0xc4, 0xd3, 0xb4, 0xb4, 0x3a,
+	0x00, 0x00, 0x00 };
 
 static const u32 bnx2_TXP_b06FwData[(0x0/4) + 1] = { 0x0 };
 static const u32 bnx2_TXP_b06FwRodata[(0x0/4) + 1] = { 0x0 };
 
 static struct fw_info bnx2_txp_fw_06 = {
-	/* Firmware version: 4.0.5 */
+	/* Firmware version: 4.4.2 */
 	.ver_major			= 0x4,
-	.ver_minor			= 0x0,
-	.ver_fix			= 0x5,
+	.ver_minor			= 0x4,
+	.ver_fix			= 0x2,
 
 	.start_addr			= 0x08000098,
 
 	.text_addr			= 0x08000000,
-	.text_len			= 0x3ad8,
+	.text_len			= 0x3ab0,
 	.text_index			= 0x0,
 	.gz_text			= bnx2_TXP_b06FwText,
 	.gz_text_len			= sizeof(bnx2_TXP_b06FwText),
@@ -4582,11 +4535,11 @@
 	.data_index			= 0x0,
 	.data				= bnx2_TXP_b06FwData,
 
-	.sbss_addr			= 0x08003b00,
+	.sbss_addr			= 0x08003ae0,
 	.sbss_len			= 0x68,
 	.sbss_index			= 0x0,
 
-	.bss_addr			= 0x08003b68,
+	.bss_addr			= 0x08003b48,
 	.bss_len			= 0x14c,
 	.bss_index			= 0x0,
 
@@ -4611,3 +4564,4 @@
 	.spad_base = BNX2_TXP_SCRATCH,
 	.mips_view_base = 0x8000000,
 };
+
diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c
index a8eb3c4..fce7451 100644
--- a/drivers/net/bnx2x_main.c
+++ b/drivers/net/bnx2x_main.c
@@ -59,8 +59,8 @@
 #include "bnx2x.h"
 #include "bnx2x_init.h"
 
-#define DRV_MODULE_VERSION	"1.45.21"
-#define DRV_MODULE_RELDATE	"2008/09/03"
+#define DRV_MODULE_VERSION	"1.45.22"
+#define DRV_MODULE_RELDATE	"2008/09/09"
 #define BNX2X_BC_VER		0x040200
 
 /* Time in jiffies before concluding the transmitter is hung */
@@ -649,15 +649,16 @@
 		BNX2X_ERR("BUG! proper val not read from IGU!\n");
 }
 
-static void bnx2x_int_disable_sync(struct bnx2x *bp)
+static void bnx2x_int_disable_sync(struct bnx2x *bp, int disable_hw)
 {
 	int msix = (bp->flags & USING_MSIX_FLAG) ? 1 : 0;
 	int i;
 
 	/* disable interrupt handling */
 	atomic_inc(&bp->intr_sem);
-	/* prevent the HW from sending interrupts */
-	bnx2x_int_disable(bp);
+	if (disable_hw)
+		/* prevent the HW from sending interrupts */
+		bnx2x_int_disable(bp);
 
 	/* make sure all ISRs are done */
 	if (msix) {
@@ -6086,9 +6087,9 @@
 	}
 }
 
-static void bnx2x_netif_stop(struct bnx2x *bp)
+static void bnx2x_netif_stop(struct bnx2x *bp, int disable_hw)
 {
-	bnx2x_int_disable_sync(bp);
+	bnx2x_int_disable_sync(bp, disable_hw);
 	if (netif_running(bp->dev)) {
 		bnx2x_napi_disable(bp);
 		netif_tx_disable(bp->dev);
@@ -6475,7 +6476,7 @@
 	for_each_queue(bp, i)
 		bnx2x_free_rx_sge_range(bp, bp->fp + i, NUM_RX_SGE);
 load_int_disable:
-	bnx2x_int_disable_sync(bp);
+	bnx2x_int_disable_sync(bp, 1);
 	/* Release IRQs */
 	bnx2x_free_irq(bp);
 load_error:
@@ -6650,7 +6651,7 @@
 	bp->rx_mode = BNX2X_RX_MODE_NONE;
 	bnx2x_set_storm_rx_mode(bp);
 
-	bnx2x_netif_stop(bp);
+	bnx2x_netif_stop(bp, 1);
 	if (!netif_running(bp->dev))
 		bnx2x_napi_disable(bp);
 	del_timer_sync(&bp->timer);
@@ -8791,7 +8792,7 @@
 	if (!netif_running(bp->dev))
 		return BNX2X_LOOPBACK_FAILED;
 
-	bnx2x_netif_stop(bp);
+	bnx2x_netif_stop(bp, 1);
 
 	if (bnx2x_run_loopback(bp, BNX2X_MAC_LOOPBACK, link_up)) {
 		DP(NETIF_MSG_PROBE, "MAC loopback failed\n");
@@ -10346,6 +10347,74 @@
 	return rc;
 }
 
+static int bnx2x_eeh_nic_unload(struct bnx2x *bp)
+{
+	int i;
+
+	bp->state = BNX2X_STATE_ERROR;
+
+	bp->rx_mode = BNX2X_RX_MODE_NONE;
+
+	bnx2x_netif_stop(bp, 0);
+
+	del_timer_sync(&bp->timer);
+	bp->stats_state = STATS_STATE_DISABLED;
+	DP(BNX2X_MSG_STATS, "stats_state - DISABLED\n");
+
+	/* Release IRQs */
+	bnx2x_free_irq(bp);
+
+	if (CHIP_IS_E1(bp)) {
+		struct mac_configuration_cmd *config =
+						bnx2x_sp(bp, mcast_config);
+
+		for (i = 0; i < config->hdr.length_6b; i++)
+			CAM_INVALIDATE(config->config_table[i]);
+	}
+
+	/* Free SKBs, SGEs, TPA pool and driver internals */
+	bnx2x_free_skbs(bp);
+	for_each_queue(bp, i)
+		bnx2x_free_rx_sge_range(bp, bp->fp + i, NUM_RX_SGE);
+	bnx2x_free_mem(bp);
+
+	bp->state = BNX2X_STATE_CLOSED;
+
+	netif_carrier_off(bp->dev);
+
+	return 0;
+}
+
+static void bnx2x_eeh_recover(struct bnx2x *bp)
+{
+	u32 val;
+
+	mutex_init(&bp->port.phy_mutex);
+
+	bp->common.shmem_base = REG_RD(bp, MISC_REG_SHARED_MEM_ADDR);
+	bp->link_params.shmem_base = bp->common.shmem_base;
+	BNX2X_DEV_INFO("shmem offset is 0x%x\n", bp->common.shmem_base);
+
+	if (!bp->common.shmem_base ||
+	    (bp->common.shmem_base < 0xA0000) ||
+	    (bp->common.shmem_base >= 0xC0000)) {
+		BNX2X_DEV_INFO("MCP not active\n");
+		bp->flags |= NO_MCP_FLAG;
+		return;
+	}
+
+	val = SHMEM_RD(bp, validity_map[BP_PORT(bp)]);
+	if ((val & (SHR_MEM_VALIDITY_DEV_INFO | SHR_MEM_VALIDITY_MB))
+		!= (SHR_MEM_VALIDITY_DEV_INFO | SHR_MEM_VALIDITY_MB))
+		BNX2X_ERR("BAD MCP validity signature\n");
+
+	if (!BP_NOMCP(bp)) {
+		bp->fw_seq = (SHMEM_RD(bp, func_mb[BP_FUNC(bp)].drv_mb_header)
+			      & DRV_MSG_SEQ_NUMBER_MASK);
+		BNX2X_DEV_INFO("fw_seq 0x%08x\n", bp->fw_seq);
+	}
+}
+
 /**
  * bnx2x_io_error_detected - called when PCI error is detected
  * @pdev: Pointer to PCI device
@@ -10365,7 +10434,7 @@
 	netif_device_detach(dev);
 
 	if (netif_running(dev))
-		bnx2x_nic_unload(bp, UNLOAD_CLOSE);
+		bnx2x_eeh_nic_unload(bp);
 
 	pci_disable_device(pdev);
 
@@ -10420,8 +10489,10 @@
 
 	rtnl_lock();
 
+	bnx2x_eeh_recover(bp);
+
 	if (netif_running(dev))
-		bnx2x_nic_load(bp, LOAD_OPEN);
+		bnx2x_nic_load(bp, LOAD_NORMAL);
 
 	netif_device_attach(dev);
 
diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c
index b211486..ade5f3f 100644
--- a/drivers/net/bonding/bond_alb.c
+++ b/drivers/net/bonding/bond_alb.c
@@ -38,6 +38,7 @@
 #include <linux/in.h>
 #include <net/ipx.h>
 #include <net/arp.h>
+#include <net/ipv6.h>
 #include <asm/byteorder.h>
 #include "bonding.h"
 #include "bond_alb.h"
@@ -81,6 +82,7 @@
 #define RLB_PROMISC_TIMEOUT	10*ALB_TIMER_TICKS_PER_SEC
 
 static const u8 mac_bcast[ETH_ALEN] = {0xff,0xff,0xff,0xff,0xff,0xff};
+static const u8 mac_v6_allmcast[ETH_ALEN] = {0x33,0x33,0x00,0x00,0x00,0x01};
 static const int alb_delta_in_ticks = HZ / ALB_TIMER_TICKS_PER_SEC;
 
 #pragma pack(1)
@@ -710,7 +712,7 @@
 	struct arp_pkt *arp = arp_pkt(skb);
 	struct slave *tx_slave = NULL;
 
-	if (arp->op_code == __constant_htons(ARPOP_REPLY)) {
+	if (arp->op_code == htons(ARPOP_REPLY)) {
 		/* the arp must be sent on the selected
 		* rx channel
 		*/
@@ -719,7 +721,7 @@
 			memcpy(arp->mac_src,tx_slave->dev->dev_addr, ETH_ALEN);
 		}
 		dprintk("Server sent ARP Reply packet\n");
-	} else if (arp->op_code == __constant_htons(ARPOP_REQUEST)) {
+	} else if (arp->op_code == htons(ARPOP_REQUEST)) {
 		/* Create an entry in the rx_hashtbl for this client as a
 		 * place holder.
 		 * When the arp reply is received the entry will be updated
@@ -1290,6 +1292,7 @@
 	u32 hash_index = 0;
 	const u8 *hash_start = NULL;
 	int res = 1;
+	struct ipv6hdr *ip6hdr;
 
 	skb_reset_mac_header(skb);
 	eth_data = eth_hdr(skb);
@@ -1319,11 +1322,32 @@
 	}
 		break;
 	case ETH_P_IPV6:
+		/* IPv6 doesn't really use broadcast mac address, but leave
+		 * that here just in case.
+		 */
 		if (memcmp(eth_data->h_dest, mac_bcast, ETH_ALEN) == 0) {
 			do_tx_balance = 0;
 			break;
 		}
 
+		/* IPv6 uses all-nodes multicast as an equivalent to
+		 * broadcasts in IPv4.
+		 */
+		if (memcmp(eth_data->h_dest, mac_v6_allmcast, ETH_ALEN) == 0) {
+			do_tx_balance = 0;
+			break;
+		}
+
+		/* Additianally, DAD probes should not be tx-balanced as that
+		 * will lead to false positives for duplicate addresses and
+		 * prevent address configuration from working.
+		 */
+		ip6hdr = ipv6_hdr(skb);
+		if (ipv6_addr_any(&ip6hdr->saddr)) {
+			do_tx_balance = 0;
+			break;
+		}
+
 		hash_start = (char *)&(ipv6_hdr(skb)->daddr);
 		hash_size = sizeof(ipv6_hdr(skb)->daddr);
 		break;
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index c792138..8e2be24 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -3702,7 +3702,7 @@
 	struct ethhdr *data = (struct ethhdr *)skb->data;
 	struct iphdr *iph = ip_hdr(skb);
 
-	if (skb->protocol == __constant_htons(ETH_P_IP)) {
+	if (skb->protocol == htons(ETH_P_IP)) {
 		return ((ntohl(iph->saddr ^ iph->daddr) & 0xffff) ^
 			(data->h_dest[5] ^ bond_dev->dev_addr[5])) % count;
 	}
@@ -3723,8 +3723,8 @@
 	__be16 *layer4hdr = (__be16 *)((u32 *)iph + iph->ihl);
 	int layer4_xor = 0;
 
-	if (skb->protocol == __constant_htons(ETH_P_IP)) {
-		if (!(iph->frag_off & __constant_htons(IP_MF|IP_OFFSET)) &&
+	if (skb->protocol == htons(ETH_P_IP)) {
+		if (!(iph->frag_off & htons(IP_MF|IP_OFFSET)) &&
 		    (iph->protocol == IPPROTO_TCP ||
 		     iph->protocol == IPPROTO_UDP)) {
 			layer4_xor = ntohs((*layer4hdr ^ *(layer4hdr + 1)));
@@ -4493,6 +4493,12 @@
 
 static const struct ethtool_ops bond_ethtool_ops = {
 	.get_drvinfo		= bond_ethtool_get_drvinfo,
+	.get_link		= ethtool_op_get_link,
+	.get_tx_csum		= ethtool_op_get_tx_csum,
+	.get_sg			= ethtool_op_get_sg,
+	.get_tso		= ethtool_op_get_tso,
+	.get_ufo		= ethtool_op_get_ufo,
+	.get_flags		= ethtool_op_get_flags,
 };
 
 /*
diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h
index fb730ec..ffb668d 100644
--- a/drivers/net/bonding/bonding.h
+++ b/drivers/net/bonding/bonding.h
@@ -32,7 +32,7 @@
 #ifdef BONDING_DEBUG
 #define dprintk(fmt, args...) \
 	printk(KERN_DEBUG     \
-	       DRV_NAME ": %s() %d: " fmt, __FUNCTION__, __LINE__ , ## args )
+	       DRV_NAME ": %s() %d: " fmt, __func__, __LINE__ , ## args )
 #else
 #define dprintk(fmt, args...)
 #endif /* BONDING_DEBUG */
@@ -333,5 +333,13 @@
 void bond_register_arp(struct bonding *);
 void bond_unregister_arp(struct bonding *);
 
+/* exported from bond_main.c */
+extern struct list_head bond_dev_list;
+extern struct bond_parm_tbl bond_lacp_tbl[];
+extern struct bond_parm_tbl bond_mode_tbl[];
+extern struct bond_parm_tbl xmit_hashtype_tbl[];
+extern struct bond_parm_tbl arp_validate_tbl[];
+extern struct bond_parm_tbl fail_over_mac_tbl[];
+
 #endif /* _LINUX_BONDING_H */
 
diff --git a/drivers/net/cassini.c b/drivers/net/cassini.c
index f1936d5..86909cf 100644
--- a/drivers/net/cassini.c
+++ b/drivers/net/cassini.c
@@ -74,6 +74,7 @@
 #include <linux/slab.h>
 #include <linux/delay.h>
 #include <linux/init.h>
+#include <linux/vmalloc.h>
 #include <linux/ioport.h>
 #include <linux/pci.h>
 #include <linux/mm.h>
@@ -91,6 +92,7 @@
 #include <linux/ip.h>
 #include <linux/tcp.h>
 #include <linux/mutex.h>
+#include <linux/firmware.h>
 
 #include <net/checksum.h>
 
@@ -197,6 +199,7 @@
 MODULE_AUTHOR("Adrian Sun (asun@darksunrising.com)");
 MODULE_DESCRIPTION("Sun Cassini(+) ethernet driver");
 MODULE_LICENSE("GPL");
+MODULE_FIRMWARE("sun/cassini.bin");
 module_param(cassini_debug, int, 0);
 MODULE_PARM_DESC(cassini_debug, "Cassini bitmapped debugging message enable value");
 module_param(link_mode, int, 0);
@@ -812,9 +815,44 @@
 	return (limit <= 0);
 }
 
+static int cas_saturn_firmware_init(struct cas *cp)
+{
+	const struct firmware *fw;
+	const char fw_name[] = "sun/cassini.bin";
+	int err;
+
+	if (PHY_NS_DP83065 != cp->phy_id)
+		return 0;
+
+	err = request_firmware(&fw, fw_name, &cp->pdev->dev);
+	if (err) {
+		printk(KERN_ERR "cassini: Failed to load firmware \"%s\"\n",
+		       fw_name);
+		return err;
+	}
+	if (fw->size < 2) {
+		printk(KERN_ERR "cassini: bogus length %zu in \"%s\"\n",
+		       fw->size, fw_name);
+		err = -EINVAL;
+		goto out;
+	}
+	cp->fw_load_addr= fw->data[1] << 8 | fw->data[0];
+	cp->fw_size = fw->size - 2;
+	cp->fw_data = vmalloc(cp->fw_size);
+	if (!cp->fw_data) {
+		err = -ENOMEM;
+		printk(KERN_ERR "cassini: \"%s\" Failed %d\n", fw_name, err);
+		goto out;
+	}
+	memcpy(cp->fw_data, &fw->data[2], cp->fw_size);
+out:
+	release_firmware(fw);
+	return err;
+}
+
 static void cas_saturn_firmware_load(struct cas *cp)
 {
-	cas_saturn_patch_t *patch = cas_saturn_patch;
+	int i;
 
 	cas_phy_powerdown(cp);
 
@@ -833,11 +871,9 @@
 
 	/* download new firmware */
 	cas_phy_write(cp, DP83065_MII_MEM, 0x1);
-	cas_phy_write(cp, DP83065_MII_REGE, patch->addr);
-	while (patch->addr) {
-		cas_phy_write(cp, DP83065_MII_REGD, patch->val);
-		patch++;
-	}
+	cas_phy_write(cp, DP83065_MII_REGE, cp->fw_load_addr);
+	for (i = 0; i < cp->fw_size; i++)
+		cas_phy_write(cp, DP83065_MII_REGD, cp->fw_data[i]);
 
 	/* enable firmware */
 	cas_phy_write(cp, DP83065_MII_REGE, 0x8ff8);
@@ -2182,7 +2218,7 @@
 	 * do any additional locking here. stick the buffer
 	 * at the end.
 	 */
-	__skb_insert(skb, flow->prev, (struct sk_buff *) flow, flow);
+	__skb_queue_tail(flow, skb);
 	if (words[0] & RX_COMP1_RELEASE_FLOW) {
 		while ((skb = __skb_dequeue(flow))) {
 			cas_skb_release(skb);
@@ -5108,6 +5144,9 @@
 	cas_reset(cp, 0);
 	if (cas_check_invariants(cp))
 		goto err_out_iounmap;
+	if (cp->cas_flags & CAS_FLAG_SATURN)
+		if (cas_saturn_firmware_init(cp))
+			goto err_out_iounmap;
 
 	cp->init_block = (struct cas_init_block *)
 		pci_alloc_consistent(pdev, sizeof(struct cas_init_block),
@@ -5217,6 +5256,9 @@
 	cp = netdev_priv(dev);
 	unregister_netdev(dev);
 
+	if (cp->fw_data)
+		vfree(cp->fw_data);
+
 	mutex_lock(&cp->pm_mutex);
 	flush_scheduled_work();
 	if (cp->hw_running)
diff --git a/drivers/net/cassini.h b/drivers/net/cassini.h
index 552af89..fd17a00 100644
--- a/drivers/net/cassini.h
+++ b/drivers/net/cassini.h
@@ -2514,1523 +2514,6 @@
 #define CAS_HP_FIRMWARE               cas_prog_null
 #endif
 
-/* firmware patch for NS_DP83065 */
-typedef struct cas_saturn_patch {
-	u16 addr;
-	u16 val;
-} cas_saturn_patch_t;
-
-#if 1
-cas_saturn_patch_t cas_saturn_patch[] = {
-{0x8200,    0x007e}, {0x8201,    0x0082}, {0x8202,    0x0009},
-{0x8203,    0x0000}, {0x8204,    0x0000}, {0x8205,    0x0000},
-{0x8206,    0x0000}, {0x8207,    0x0000}, {0x8208,    0x0000},
-{0x8209,    0x008e}, {0x820a,    0x008e}, {0x820b,    0x00ff},
-{0x820c,    0x00ce}, {0x820d,    0x0082}, {0x820e,    0x0025},
-{0x820f,    0x00ff}, {0x8210,    0x0001}, {0x8211,    0x000f},
-{0x8212,    0x00ce}, {0x8213,    0x0084}, {0x8214,    0x0026},
-{0x8215,    0x00ff}, {0x8216,    0x0001}, {0x8217,    0x0011},
-{0x8218,    0x00ce}, {0x8219,    0x0085}, {0x821a,    0x003d},
-{0x821b,    0x00df}, {0x821c,    0x00e5}, {0x821d,    0x0086},
-{0x821e,    0x0039}, {0x821f,    0x00b7}, {0x8220,    0x008f},
-{0x8221,    0x00f8}, {0x8222,    0x007e}, {0x8223,    0x00c3},
-{0x8224,    0x00c2}, {0x8225,    0x0096}, {0x8226,    0x0047},
-{0x8227,    0x0084}, {0x8228,    0x00f3}, {0x8229,    0x008a},
-{0x822a,    0x0000}, {0x822b,    0x0097}, {0x822c,    0x0047},
-{0x822d,    0x00ce}, {0x822e,    0x0082}, {0x822f,    0x0033},
-{0x8230,    0x00ff}, {0x8231,    0x0001}, {0x8232,    0x000f},
-{0x8233,    0x0096}, {0x8234,    0x0046}, {0x8235,    0x0084},
-{0x8236,    0x000c}, {0x8237,    0x0081}, {0x8238,    0x0004},
-{0x8239,    0x0027}, {0x823a,    0x000b}, {0x823b,    0x0096},
-{0x823c,    0x0046}, {0x823d,    0x0084}, {0x823e,    0x000c},
-{0x823f,    0x0081}, {0x8240,    0x0008}, {0x8241,    0x0027},
-{0x8242,    0x0057}, {0x8243,    0x007e}, {0x8244,    0x0084},
-{0x8245,    0x0025}, {0x8246,    0x0096}, {0x8247,    0x0047},
-{0x8248,    0x0084}, {0x8249,    0x00f3}, {0x824a,    0x008a},
-{0x824b,    0x0004}, {0x824c,    0x0097}, {0x824d,    0x0047},
-{0x824e,    0x00ce}, {0x824f,    0x0082}, {0x8250,    0x0054},
-{0x8251,    0x00ff}, {0x8252,    0x0001}, {0x8253,    0x000f},
-{0x8254,    0x0096}, {0x8255,    0x0046}, {0x8256,    0x0084},
-{0x8257,    0x000c}, {0x8258,    0x0081}, {0x8259,    0x0004},
-{0x825a,    0x0026}, {0x825b,    0x0038}, {0x825c,    0x00b6},
-{0x825d,    0x0012}, {0x825e,    0x0020}, {0x825f,    0x0084},
-{0x8260,    0x0020}, {0x8261,    0x0026}, {0x8262,    0x0003},
-{0x8263,    0x007e}, {0x8264,    0x0084}, {0x8265,    0x0025},
-{0x8266,    0x0096}, {0x8267,    0x007b}, {0x8268,    0x00d6},
-{0x8269,    0x007c}, {0x826a,    0x00fe}, {0x826b,    0x008f},
-{0x826c,    0x0056}, {0x826d,    0x00bd}, {0x826e,    0x00f7},
-{0x826f,    0x00b6}, {0x8270,    0x00fe}, {0x8271,    0x008f},
-{0x8272,    0x004e}, {0x8273,    0x00bd}, {0x8274,    0x00ec},
-{0x8275,    0x008e}, {0x8276,    0x00bd}, {0x8277,    0x00fa},
-{0x8278,    0x00f7}, {0x8279,    0x00bd}, {0x827a,    0x00f7},
-{0x827b,    0x0028}, {0x827c,    0x00ce}, {0x827d,    0x0082},
-{0x827e,    0x0082}, {0x827f,    0x00ff}, {0x8280,    0x0001},
-{0x8281,    0x000f}, {0x8282,    0x0096}, {0x8283,    0x0046},
-{0x8284,    0x0084}, {0x8285,    0x000c}, {0x8286,    0x0081},
-{0x8287,    0x0004}, {0x8288,    0x0026}, {0x8289,    0x000a},
-{0x828a,    0x00b6}, {0x828b,    0x0012}, {0x828c,    0x0020},
-{0x828d,    0x0084}, {0x828e,    0x0020}, {0x828f,    0x0027},
-{0x8290,    0x00b5}, {0x8291,    0x007e}, {0x8292,    0x0084},
-{0x8293,    0x0025}, {0x8294,    0x00bd}, {0x8295,    0x00f7},
-{0x8296,    0x001f}, {0x8297,    0x007e}, {0x8298,    0x0084},
-{0x8299,    0x001f}, {0x829a,    0x0096}, {0x829b,    0x0047},
-{0x829c,    0x0084}, {0x829d,    0x00f3}, {0x829e,    0x008a},
-{0x829f,    0x0008}, {0x82a0,    0x0097}, {0x82a1,    0x0047},
-{0x82a2,    0x00de}, {0x82a3,    0x00e1}, {0x82a4,    0x00ad},
-{0x82a5,    0x0000}, {0x82a6,    0x00ce}, {0x82a7,    0x0082},
-{0x82a8,    0x00af}, {0x82a9,    0x00ff}, {0x82aa,    0x0001},
-{0x82ab,    0x000f}, {0x82ac,    0x007e}, {0x82ad,    0x0084},
-{0x82ae,    0x0025}, {0x82af,    0x0096}, {0x82b0,    0x0041},
-{0x82b1,    0x0085}, {0x82b2,    0x0010}, {0x82b3,    0x0026},
-{0x82b4,    0x0006}, {0x82b5,    0x0096}, {0x82b6,    0x0023},
-{0x82b7,    0x0085}, {0x82b8,    0x0040}, {0x82b9,    0x0027},
-{0x82ba,    0x0006}, {0x82bb,    0x00bd}, {0x82bc,    0x00ed},
-{0x82bd,    0x0000}, {0x82be,    0x007e}, {0x82bf,    0x0083},
-{0x82c0,    0x00a2}, {0x82c1,    0x00de}, {0x82c2,    0x0042},
-{0x82c3,    0x00bd}, {0x82c4,    0x00eb}, {0x82c5,    0x008e},
-{0x82c6,    0x0096}, {0x82c7,    0x0024}, {0x82c8,    0x0084},
-{0x82c9,    0x0008}, {0x82ca,    0x0027}, {0x82cb,    0x0003},
-{0x82cc,    0x007e}, {0x82cd,    0x0083}, {0x82ce,    0x00df},
-{0x82cf,    0x0096}, {0x82d0,    0x007b}, {0x82d1,    0x00d6},
-{0x82d2,    0x007c}, {0x82d3,    0x00fe}, {0x82d4,    0x008f},
-{0x82d5,    0x0056}, {0x82d6,    0x00bd}, {0x82d7,    0x00f7},
-{0x82d8,    0x00b6}, {0x82d9,    0x00fe}, {0x82da,    0x008f},
-{0x82db,    0x0050}, {0x82dc,    0x00bd}, {0x82dd,    0x00ec},
-{0x82de,    0x008e}, {0x82df,    0x00bd}, {0x82e0,    0x00fa},
-{0x82e1,    0x00f7}, {0x82e2,    0x0086}, {0x82e3,    0x0011},
-{0x82e4,    0x00c6}, {0x82e5,    0x0049}, {0x82e6,    0x00bd},
-{0x82e7,    0x00e4}, {0x82e8,    0x0012}, {0x82e9,    0x00ce},
-{0x82ea,    0x0082}, {0x82eb,    0x00ef}, {0x82ec,    0x00ff},
-{0x82ed,    0x0001}, {0x82ee,    0x000f}, {0x82ef,    0x0096},
-{0x82f0,    0x0046}, {0x82f1,    0x0084}, {0x82f2,    0x000c},
-{0x82f3,    0x0081}, {0x82f4,    0x0000}, {0x82f5,    0x0027},
-{0x82f6,    0x0017}, {0x82f7,    0x00c6}, {0x82f8,    0x0049},
-{0x82f9,    0x00bd}, {0x82fa,    0x00e4}, {0x82fb,    0x0091},
-{0x82fc,    0x0024}, {0x82fd,    0x000d}, {0x82fe,    0x00b6},
-{0x82ff,    0x0012}, {0x8300,    0x0020}, {0x8301,    0x0085},
-{0x8302,    0x0020}, {0x8303,    0x0026}, {0x8304,    0x000c},
-{0x8305,    0x00ce}, {0x8306,    0x0082}, {0x8307,    0x00c1},
-{0x8308,    0x00ff}, {0x8309,    0x0001}, {0x830a,    0x000f},
-{0x830b,    0x007e}, {0x830c,    0x0084}, {0x830d,    0x0025},
-{0x830e,    0x007e}, {0x830f,    0x0084}, {0x8310,    0x0016},
-{0x8311,    0x00fe}, {0x8312,    0x008f}, {0x8313,    0x0052},
-{0x8314,    0x00bd}, {0x8315,    0x00ec}, {0x8316,    0x008e},
-{0x8317,    0x00bd}, {0x8318,    0x00fa}, {0x8319,    0x00f7},
-{0x831a,    0x0086}, {0x831b,    0x006a}, {0x831c,    0x00c6},
-{0x831d,    0x0049}, {0x831e,    0x00bd}, {0x831f,    0x00e4},
-{0x8320,    0x0012}, {0x8321,    0x00ce}, {0x8322,    0x0083},
-{0x8323,    0x0027}, {0x8324,    0x00ff}, {0x8325,    0x0001},
-{0x8326,    0x000f}, {0x8327,    0x0096}, {0x8328,    0x0046},
-{0x8329,    0x0084}, {0x832a,    0x000c}, {0x832b,    0x0081},
-{0x832c,    0x0000}, {0x832d,    0x0027}, {0x832e,    0x000a},
-{0x832f,    0x00c6}, {0x8330,    0x0049}, {0x8331,    0x00bd},
-{0x8332,    0x00e4}, {0x8333,    0x0091}, {0x8334,    0x0025},
-{0x8335,    0x0006}, {0x8336,    0x007e}, {0x8337,    0x0084},
-{0x8338,    0x0025}, {0x8339,    0x007e}, {0x833a,    0x0084},
-{0x833b,    0x0016}, {0x833c,    0x00b6}, {0x833d,    0x0018},
-{0x833e,    0x0070}, {0x833f,    0x00bb}, {0x8340,    0x0019},
-{0x8341,    0x0070}, {0x8342,    0x002a}, {0x8343,    0x0004},
-{0x8344,    0x0081}, {0x8345,    0x00af}, {0x8346,    0x002e},
-{0x8347,    0x0019}, {0x8348,    0x0096}, {0x8349,    0x007b},
-{0x834a,    0x00f6}, {0x834b,    0x0020}, {0x834c,    0x0007},
-{0x834d,    0x00fa}, {0x834e,    0x0020}, {0x834f,    0x0027},
-{0x8350,    0x00c4}, {0x8351,    0x0038}, {0x8352,    0x0081},
-{0x8353,    0x0038}, {0x8354,    0x0027}, {0x8355,    0x000b},
-{0x8356,    0x00f6}, {0x8357,    0x0020}, {0x8358,    0x0007},
-{0x8359,    0x00fa}, {0x835a,    0x0020}, {0x835b,    0x0027},
-{0x835c,    0x00cb}, {0x835d,    0x0008}, {0x835e,    0x007e},
-{0x835f,    0x0082}, {0x8360,    0x00d3}, {0x8361,    0x00bd},
-{0x8362,    0x00f7}, {0x8363,    0x0066}, {0x8364,    0x0086},
-{0x8365,    0x0074}, {0x8366,    0x00c6}, {0x8367,    0x0049},
-{0x8368,    0x00bd}, {0x8369,    0x00e4}, {0x836a,    0x0012},
-{0x836b,    0x00ce}, {0x836c,    0x0083}, {0x836d,    0x0071},
-{0x836e,    0x00ff}, {0x836f,    0x0001}, {0x8370,    0x000f},
-{0x8371,    0x0096}, {0x8372,    0x0046}, {0x8373,    0x0084},
-{0x8374,    0x000c}, {0x8375,    0x0081}, {0x8376,    0x0008},
-{0x8377,    0x0026}, {0x8378,    0x000a}, {0x8379,    0x00c6},
-{0x837a,    0x0049}, {0x837b,    0x00bd}, {0x837c,    0x00e4},
-{0x837d,    0x0091}, {0x837e,    0x0025}, {0x837f,    0x0006},
-{0x8380,    0x007e}, {0x8381,    0x0084}, {0x8382,    0x0025},
-{0x8383,    0x007e}, {0x8384,    0x0084}, {0x8385,    0x0016},
-{0x8386,    0x00bd}, {0x8387,    0x00f7}, {0x8388,    0x003e},
-{0x8389,    0x0026}, {0x838a,    0x000e}, {0x838b,    0x00bd},
-{0x838c,    0x00e5}, {0x838d,    0x0009}, {0x838e,    0x0026},
-{0x838f,    0x0006}, {0x8390,    0x00ce}, {0x8391,    0x0082},
-{0x8392,    0x00c1}, {0x8393,    0x00ff}, {0x8394,    0x0001},
-{0x8395,    0x000f}, {0x8396,    0x007e}, {0x8397,    0x0084},
-{0x8398,    0x0025}, {0x8399,    0x00fe}, {0x839a,    0x008f},
-{0x839b,    0x0054}, {0x839c,    0x00bd}, {0x839d,    0x00ec},
-{0x839e,    0x008e}, {0x839f,    0x00bd}, {0x83a0,    0x00fa},
-{0x83a1,    0x00f7}, {0x83a2,    0x00bd}, {0x83a3,    0x00f7},
-{0x83a4,    0x0033}, {0x83a5,    0x0086}, {0x83a6,    0x000f},
-{0x83a7,    0x00c6}, {0x83a8,    0x0051}, {0x83a9,    0x00bd},
-{0x83aa,    0x00e4}, {0x83ab,    0x0012}, {0x83ac,    0x00ce},
-{0x83ad,    0x0083}, {0x83ae,    0x00b2}, {0x83af,    0x00ff},
-{0x83b0,    0x0001}, {0x83b1,    0x000f}, {0x83b2,    0x0096},
-{0x83b3,    0x0046}, {0x83b4,    0x0084}, {0x83b5,    0x000c},
-{0x83b6,    0x0081}, {0x83b7,    0x0008}, {0x83b8,    0x0026},
-{0x83b9,    0x005c}, {0x83ba,    0x00b6}, {0x83bb,    0x0012},
-{0x83bc,    0x0020}, {0x83bd,    0x0084}, {0x83be,    0x003f},
-{0x83bf,    0x0081}, {0x83c0,    0x003a}, {0x83c1,    0x0027},
-{0x83c2,    0x001c}, {0x83c3,    0x0096}, {0x83c4,    0x0023},
-{0x83c5,    0x0085}, {0x83c6,    0x0040}, {0x83c7,    0x0027},
-{0x83c8,    0x0003}, {0x83c9,    0x007e}, {0x83ca,    0x0084},
-{0x83cb,    0x0025}, {0x83cc,    0x00c6}, {0x83cd,    0x0051},
-{0x83ce,    0x00bd}, {0x83cf,    0x00e4}, {0x83d0,    0x0091},
-{0x83d1,    0x0025}, {0x83d2,    0x0003}, {0x83d3,    0x007e},
-{0x83d4,    0x0084}, {0x83d5,    0x0025}, {0x83d6,    0x00ce},
-{0x83d7,    0x0082}, {0x83d8,    0x00c1}, {0x83d9,    0x00ff},
-{0x83da,    0x0001}, {0x83db,    0x000f}, {0x83dc,    0x007e},
-{0x83dd,    0x0084}, {0x83de,    0x0025}, {0x83df,    0x00bd},
-{0x83e0,    0x00f8}, {0x83e1,    0x0037}, {0x83e2,    0x007c},
-{0x83e3,    0x0000}, {0x83e4,    0x007a}, {0x83e5,    0x00ce},
-{0x83e6,    0x0083}, {0x83e7,    0x00ee}, {0x83e8,    0x00ff},
-{0x83e9,    0x0001}, {0x83ea,    0x000f}, {0x83eb,    0x007e},
-{0x83ec,    0x0084}, {0x83ed,    0x0025}, {0x83ee,    0x0096},
-{0x83ef,    0x0046}, {0x83f0,    0x0084}, {0x83f1,    0x000c},
-{0x83f2,    0x0081}, {0x83f3,    0x0008}, {0x83f4,    0x0026},
-{0x83f5,    0x0020}, {0x83f6,    0x0096}, {0x83f7,    0x0024},
-{0x83f8,    0x0084}, {0x83f9,    0x0008}, {0x83fa,    0x0026},
-{0x83fb,    0x0029}, {0x83fc,    0x00b6}, {0x83fd,    0x0018},
-{0x83fe,    0x0082}, {0x83ff,    0x00bb}, {0x8400,    0x0019},
-{0x8401,    0x0082}, {0x8402,    0x00b1}, {0x8403,    0x0001},
-{0x8404,    0x003b}, {0x8405,    0x0022}, {0x8406,    0x0009},
-{0x8407,    0x00b6}, {0x8408,    0x0012}, {0x8409,    0x0020},
-{0x840a,    0x0084}, {0x840b,    0x0037}, {0x840c,    0x0081},
-{0x840d,    0x0032}, {0x840e,    0x0027}, {0x840f,    0x0015},
-{0x8410,    0x00bd}, {0x8411,    0x00f8}, {0x8412,    0x0044},
-{0x8413,    0x007e}, {0x8414,    0x0082}, {0x8415,    0x00c1},
-{0x8416,    0x00bd}, {0x8417,    0x00f7}, {0x8418,    0x001f},
-{0x8419,    0x00bd}, {0x841a,    0x00f8}, {0x841b,    0x0044},
-{0x841c,    0x00bd}, {0x841d,    0x00fc}, {0x841e,    0x0029},
-{0x841f,    0x00ce}, {0x8420,    0x0082}, {0x8421,    0x0025},
-{0x8422,    0x00ff}, {0x8423,    0x0001}, {0x8424,    0x000f},
-{0x8425,    0x0039}, {0x8426,    0x0096}, {0x8427,    0x0047},
-{0x8428,    0x0084}, {0x8429,    0x00fc}, {0x842a,    0x008a},
-{0x842b,    0x0000}, {0x842c,    0x0097}, {0x842d,    0x0047},
-{0x842e,    0x00ce}, {0x842f,    0x0084}, {0x8430,    0x0034},
-{0x8431,    0x00ff}, {0x8432,    0x0001}, {0x8433,    0x0011},
-{0x8434,    0x0096}, {0x8435,    0x0046}, {0x8436,    0x0084},
-{0x8437,    0x0003}, {0x8438,    0x0081}, {0x8439,    0x0002},
-{0x843a,    0x0027}, {0x843b,    0x0003}, {0x843c,    0x007e},
-{0x843d,    0x0085}, {0x843e,    0x001e}, {0x843f,    0x0096},
-{0x8440,    0x0047}, {0x8441,    0x0084}, {0x8442,    0x00fc},
-{0x8443,    0x008a}, {0x8444,    0x0002}, {0x8445,    0x0097},
-{0x8446,    0x0047}, {0x8447,    0x00de}, {0x8448,    0x00e1},
-{0x8449,    0x00ad}, {0x844a,    0x0000}, {0x844b,    0x0086},
-{0x844c,    0x0001}, {0x844d,    0x00b7}, {0x844e,    0x0012},
-{0x844f,    0x0051}, {0x8450,    0x00bd}, {0x8451,    0x00f7},
-{0x8452,    0x0014}, {0x8453,    0x00b6}, {0x8454,    0x0010},
-{0x8455,    0x0031}, {0x8456,    0x0084}, {0x8457,    0x00fd},
-{0x8458,    0x00b7}, {0x8459,    0x0010}, {0x845a,    0x0031},
-{0x845b,    0x00bd}, {0x845c,    0x00f8}, {0x845d,    0x001e},
-{0x845e,    0x0096}, {0x845f,    0x0081}, {0x8460,    0x00d6},
-{0x8461,    0x0082}, {0x8462,    0x00fe}, {0x8463,    0x008f},
-{0x8464,    0x005a}, {0x8465,    0x00bd}, {0x8466,    0x00f7},
-{0x8467,    0x00b6}, {0x8468,    0x00fe}, {0x8469,    0x008f},
-{0x846a,    0x005c}, {0x846b,    0x00bd}, {0x846c,    0x00ec},
-{0x846d,    0x008e}, {0x846e,    0x00bd}, {0x846f,    0x00fa},
-{0x8470,    0x00f7}, {0x8471,    0x0086}, {0x8472,    0x0008},
-{0x8473,    0x00d6}, {0x8474,    0x0000}, {0x8475,    0x00c5},
-{0x8476,    0x0010}, {0x8477,    0x0026}, {0x8478,    0x0002},
-{0x8479,    0x008b}, {0x847a,    0x0020}, {0x847b,    0x00c6},
-{0x847c,    0x0051}, {0x847d,    0x00bd}, {0x847e,    0x00e4},
-{0x847f,    0x0012}, {0x8480,    0x00ce}, {0x8481,    0x0084},
-{0x8482,    0x0086}, {0x8483,    0x00ff}, {0x8484,    0x0001},
-{0x8485,    0x0011}, {0x8486,    0x0096}, {0x8487,    0x0046},
-{0x8488,    0x0084}, {0x8489,    0x0003}, {0x848a,    0x0081},
-{0x848b,    0x0002}, {0x848c,    0x0027}, {0x848d,    0x0003},
-{0x848e,    0x007e}, {0x848f,    0x0085}, {0x8490,    0x000f},
-{0x8491,    0x00c6}, {0x8492,    0x0051}, {0x8493,    0x00bd},
-{0x8494,    0x00e4}, {0x8495,    0x0091}, {0x8496,    0x0025},
-{0x8497,    0x0003}, {0x8498,    0x007e}, {0x8499,    0x0085},
-{0x849a,    0x001e}, {0x849b,    0x0096}, {0x849c,    0x0044},
-{0x849d,    0x0085}, {0x849e,    0x0010}, {0x849f,    0x0026},
-{0x84a0,    0x000a}, {0x84a1,    0x00b6}, {0x84a2,    0x0012},
-{0x84a3,    0x0050}, {0x84a4,    0x00ba}, {0x84a5,    0x0001},
-{0x84a6,    0x003c}, {0x84a7,    0x0085}, {0x84a8,    0x0010},
-{0x84a9,    0x0027}, {0x84aa,    0x00a8}, {0x84ab,    0x00bd},
-{0x84ac,    0x00f7}, {0x84ad,    0x0066}, {0x84ae,    0x00ce},
-{0x84af,    0x0084}, {0x84b0,    0x00b7}, {0x84b1,    0x00ff},
-{0x84b2,    0x0001}, {0x84b3,    0x0011}, {0x84b4,    0x007e},
-{0x84b5,    0x0085}, {0x84b6,    0x001e}, {0x84b7,    0x0096},
-{0x84b8,    0x0046}, {0x84b9,    0x0084}, {0x84ba,    0x0003},
-{0x84bb,    0x0081}, {0x84bc,    0x0002}, {0x84bd,    0x0026},
-{0x84be,    0x0050}, {0x84bf,    0x00b6}, {0x84c0,    0x0012},
-{0x84c1,    0x0030}, {0x84c2,    0x0084}, {0x84c3,    0x0003},
-{0x84c4,    0x0081}, {0x84c5,    0x0001}, {0x84c6,    0x0027},
-{0x84c7,    0x0003}, {0x84c8,    0x007e}, {0x84c9,    0x0085},
-{0x84ca,    0x001e}, {0x84cb,    0x0096}, {0x84cc,    0x0044},
-{0x84cd,    0x0085}, {0x84ce,    0x0010}, {0x84cf,    0x0026},
-{0x84d0,    0x0013}, {0x84d1,    0x00b6}, {0x84d2,    0x0012},
-{0x84d3,    0x0050}, {0x84d4,    0x00ba}, {0x84d5,    0x0001},
-{0x84d6,    0x003c}, {0x84d7,    0x0085}, {0x84d8,    0x0010},
-{0x84d9,    0x0026}, {0x84da,    0x0009}, {0x84db,    0x00ce},
-{0x84dc,    0x0084}, {0x84dd,    0x0053}, {0x84de,    0x00ff},
-{0x84df,    0x0001}, {0x84e0,    0x0011}, {0x84e1,    0x007e},
-{0x84e2,    0x0085}, {0x84e3,    0x001e}, {0x84e4,    0x00b6},
-{0x84e5,    0x0010}, {0x84e6,    0x0031}, {0x84e7,    0x008a},
-{0x84e8,    0x0002}, {0x84e9,    0x00b7}, {0x84ea,    0x0010},
-{0x84eb,    0x0031}, {0x84ec,    0x00bd}, {0x84ed,    0x0085},
-{0x84ee,    0x001f}, {0x84ef,    0x00bd}, {0x84f0,    0x00f8},
-{0x84f1,    0x0037}, {0x84f2,    0x007c}, {0x84f3,    0x0000},
-{0x84f4,    0x0080}, {0x84f5,    0x00ce}, {0x84f6,    0x0084},
-{0x84f7,    0x00fe}, {0x84f8,    0x00ff}, {0x84f9,    0x0001},
-{0x84fa,    0x0011}, {0x84fb,    0x007e}, {0x84fc,    0x0085},
-{0x84fd,    0x001e}, {0x84fe,    0x0096}, {0x84ff,    0x0046},
-{0x8500,    0x0084}, {0x8501,    0x0003}, {0x8502,    0x0081},
-{0x8503,    0x0002}, {0x8504,    0x0026}, {0x8505,    0x0009},
-{0x8506,    0x00b6}, {0x8507,    0x0012}, {0x8508,    0x0030},
-{0x8509,    0x0084}, {0x850a,    0x0003}, {0x850b,    0x0081},
-{0x850c,    0x0001}, {0x850d,    0x0027}, {0x850e,    0x000f},
-{0x850f,    0x00bd}, {0x8510,    0x00f8}, {0x8511,    0x0044},
-{0x8512,    0x00bd}, {0x8513,    0x00f7}, {0x8514,    0x000b},
-{0x8515,    0x00bd}, {0x8516,    0x00fc}, {0x8517,    0x0029},
-{0x8518,    0x00ce}, {0x8519,    0x0084}, {0x851a,    0x0026},
-{0x851b,    0x00ff}, {0x851c,    0x0001}, {0x851d,    0x0011},
-{0x851e,    0x0039}, {0x851f,    0x00d6}, {0x8520,    0x0022},
-{0x8521,    0x00c4}, {0x8522,    0x000f}, {0x8523,    0x00b6},
-{0x8524,    0x0012}, {0x8525,    0x0030}, {0x8526,    0x00ba},
-{0x8527,    0x0012}, {0x8528,    0x0032}, {0x8529,    0x0084},
-{0x852a,    0x0004}, {0x852b,    0x0027}, {0x852c,    0x000d},
-{0x852d,    0x0096}, {0x852e,    0x0022}, {0x852f,    0x0085},
-{0x8530,    0x0004}, {0x8531,    0x0027}, {0x8532,    0x0005},
-{0x8533,    0x00ca}, {0x8534,    0x0010}, {0x8535,    0x007e},
-{0x8536,    0x0085}, {0x8537,    0x003a}, {0x8538,    0x00ca},
-{0x8539,    0x0020}, {0x853a,    0x00d7}, {0x853b,    0x0022},
-{0x853c,    0x0039}, {0x853d,    0x0086}, {0x853e,    0x0000},
-{0x853f,    0x0097}, {0x8540,    0x0083}, {0x8541,    0x0018},
-{0x8542,    0x00ce}, {0x8543,    0x001c}, {0x8544,    0x0000},
-{0x8545,    0x00bd}, {0x8546,    0x00eb}, {0x8547,    0x0046},
-{0x8548,    0x0096}, {0x8549,    0x0057}, {0x854a,    0x0085},
-{0x854b,    0x0001}, {0x854c,    0x0027}, {0x854d,    0x0002},
-{0x854e,    0x004f}, {0x854f,    0x0039}, {0x8550,    0x0085},
-{0x8551,    0x0002}, {0x8552,    0x0027}, {0x8553,    0x0001},
-{0x8554,    0x0039}, {0x8555,    0x007f}, {0x8556,    0x008f},
-{0x8557,    0x007d}, {0x8558,    0x0086}, {0x8559,    0x0004},
-{0x855a,    0x00b7}, {0x855b,    0x0012}, {0x855c,    0x0004},
-{0x855d,    0x0086}, {0x855e,    0x0008}, {0x855f,    0x00b7},
-{0x8560,    0x0012}, {0x8561,    0x0007}, {0x8562,    0x0086},
-{0x8563,    0x0010}, {0x8564,    0x00b7}, {0x8565,    0x0012},
-{0x8566,    0x000c}, {0x8567,    0x0086}, {0x8568,    0x0007},
-{0x8569,    0x00b7}, {0x856a,    0x0012}, {0x856b,    0x0006},
-{0x856c,    0x00b6}, {0x856d,    0x008f}, {0x856e,    0x007d},
-{0x856f,    0x00b7}, {0x8570,    0x0012}, {0x8571,    0x0070},
-{0x8572,    0x0086}, {0x8573,    0x0001}, {0x8574,    0x00ba},
-{0x8575,    0x0012}, {0x8576,    0x0004}, {0x8577,    0x00b7},
-{0x8578,    0x0012}, {0x8579,    0x0004}, {0x857a,    0x0001},
-{0x857b,    0x0001}, {0x857c,    0x0001}, {0x857d,    0x0001},
-{0x857e,    0x0001}, {0x857f,    0x0001}, {0x8580,    0x00b6},
-{0x8581,    0x0012}, {0x8582,    0x0004}, {0x8583,    0x0084},
-{0x8584,    0x00fe}, {0x8585,    0x008a}, {0x8586,    0x0002},
-{0x8587,    0x00b7}, {0x8588,    0x0012}, {0x8589,    0x0004},
-{0x858a,    0x0001}, {0x858b,    0x0001}, {0x858c,    0x0001},
-{0x858d,    0x0001}, {0x858e,    0x0001}, {0x858f,    0x0001},
-{0x8590,    0x0086}, {0x8591,    0x00fd}, {0x8592,    0x00b4},
-{0x8593,    0x0012}, {0x8594,    0x0004}, {0x8595,    0x00b7},
-{0x8596,    0x0012}, {0x8597,    0x0004}, {0x8598,    0x00b6},
-{0x8599,    0x0012}, {0x859a,    0x0000}, {0x859b,    0x0084},
-{0x859c,    0x0008}, {0x859d,    0x0081}, {0x859e,    0x0008},
-{0x859f,    0x0027}, {0x85a0,    0x0016}, {0x85a1,    0x00b6},
-{0x85a2,    0x008f}, {0x85a3,    0x007d}, {0x85a4,    0x0081},
-{0x85a5,    0x000c}, {0x85a6,    0x0027}, {0x85a7,    0x0008},
-{0x85a8,    0x008b}, {0x85a9,    0x0004}, {0x85aa,    0x00b7},
-{0x85ab,    0x008f}, {0x85ac,    0x007d}, {0x85ad,    0x007e},
-{0x85ae,    0x0085}, {0x85af,    0x006c}, {0x85b0,    0x0086},
-{0x85b1,    0x0003}, {0x85b2,    0x0097}, {0x85b3,    0x0040},
-{0x85b4,    0x007e}, {0x85b5,    0x0089}, {0x85b6,    0x006e},
-{0x85b7,    0x0086}, {0x85b8,    0x0007}, {0x85b9,    0x00b7},
-{0x85ba,    0x0012}, {0x85bb,    0x0006}, {0x85bc,    0x005f},
-{0x85bd,    0x00f7}, {0x85be,    0x008f}, {0x85bf,    0x0082},
-{0x85c0,    0x005f}, {0x85c1,    0x00f7}, {0x85c2,    0x008f},
-{0x85c3,    0x007f}, {0x85c4,    0x00f7}, {0x85c5,    0x008f},
-{0x85c6,    0x0070}, {0x85c7,    0x00f7}, {0x85c8,    0x008f},
-{0x85c9,    0x0071}, {0x85ca,    0x00f7}, {0x85cb,    0x008f},
-{0x85cc,    0x0072}, {0x85cd,    0x00f7}, {0x85ce,    0x008f},
-{0x85cf,    0x0073}, {0x85d0,    0x00f7}, {0x85d1,    0x008f},
-{0x85d2,    0x0074}, {0x85d3,    0x00f7}, {0x85d4,    0x008f},
-{0x85d5,    0x0075}, {0x85d6,    0x00f7}, {0x85d7,    0x008f},
-{0x85d8,    0x0076}, {0x85d9,    0x00f7}, {0x85da,    0x008f},
-{0x85db,    0x0077}, {0x85dc,    0x00f7}, {0x85dd,    0x008f},
-{0x85de,    0x0078}, {0x85df,    0x00f7}, {0x85e0,    0x008f},
-{0x85e1,    0x0079}, {0x85e2,    0x00f7}, {0x85e3,    0x008f},
-{0x85e4,    0x007a}, {0x85e5,    0x00f7}, {0x85e6,    0x008f},
-{0x85e7,    0x007b}, {0x85e8,    0x00b6}, {0x85e9,    0x0012},
-{0x85ea,    0x0004}, {0x85eb,    0x008a}, {0x85ec,    0x0010},
-{0x85ed,    0x00b7}, {0x85ee,    0x0012}, {0x85ef,    0x0004},
-{0x85f0,    0x0086}, {0x85f1,    0x00e4}, {0x85f2,    0x00b7},
-{0x85f3,    0x0012}, {0x85f4,    0x0070}, {0x85f5,    0x00b7},
-{0x85f6,    0x0012}, {0x85f7,    0x0007}, {0x85f8,    0x00f7},
-{0x85f9,    0x0012}, {0x85fa,    0x0005}, {0x85fb,    0x00f7},
-{0x85fc,    0x0012}, {0x85fd,    0x0009}, {0x85fe,    0x0086},
-{0x85ff,    0x0008}, {0x8600,    0x00ba}, {0x8601,    0x0012},
-{0x8602,    0x0004}, {0x8603,    0x00b7}, {0x8604,    0x0012},
-{0x8605,    0x0004}, {0x8606,    0x0086}, {0x8607,    0x00f7},
-{0x8608,    0x00b4}, {0x8609,    0x0012}, {0x860a,    0x0004},
-{0x860b,    0x00b7}, {0x860c,    0x0012}, {0x860d,    0x0004},
-{0x860e,    0x0001}, {0x860f,    0x0001}, {0x8610,    0x0001},
-{0x8611,    0x0001}, {0x8612,    0x0001}, {0x8613,    0x0001},
-{0x8614,    0x00b6}, {0x8615,    0x0012}, {0x8616,    0x0008},
-{0x8617,    0x0027}, {0x8618,    0x007f}, {0x8619,    0x0081},
-{0x861a,    0x0080}, {0x861b,    0x0026}, {0x861c,    0x000b},
-{0x861d,    0x0086}, {0x861e,    0x0008}, {0x861f,    0x00ce},
-{0x8620,    0x008f}, {0x8621,    0x0079}, {0x8622,    0x00bd},
-{0x8623,    0x0089}, {0x8624,    0x007b}, {0x8625,    0x007e},
-{0x8626,    0x0086}, {0x8627,    0x008e}, {0x8628,    0x0081},
-{0x8629,    0x0040}, {0x862a,    0x0026}, {0x862b,    0x000b},
-{0x862c,    0x0086}, {0x862d,    0x0004}, {0x862e,    0x00ce},
-{0x862f,    0x008f}, {0x8630,    0x0076}, {0x8631,    0x00bd},
-{0x8632,    0x0089}, {0x8633,    0x007b}, {0x8634,    0x007e},
-{0x8635,    0x0086}, {0x8636,    0x008e}, {0x8637,    0x0081},
-{0x8638,    0x0020}, {0x8639,    0x0026}, {0x863a,    0x000b},
-{0x863b,    0x0086}, {0x863c,    0x0002}, {0x863d,    0x00ce},
-{0x863e,    0x008f}, {0x863f,    0x0073}, {0x8640,    0x00bd},
-{0x8641,    0x0089}, {0x8642,    0x007b}, {0x8643,    0x007e},
-{0x8644,    0x0086}, {0x8645,    0x008e}, {0x8646,    0x0081},
-{0x8647,    0x0010}, {0x8648,    0x0026}, {0x8649,    0x000b},
-{0x864a,    0x0086}, {0x864b,    0x0001}, {0x864c,    0x00ce},
-{0x864d,    0x008f}, {0x864e,    0x0070}, {0x864f,    0x00bd},
-{0x8650,    0x0089}, {0x8651,    0x007b}, {0x8652,    0x007e},
-{0x8653,    0x0086}, {0x8654,    0x008e}, {0x8655,    0x0081},
-{0x8656,    0x0008}, {0x8657,    0x0026}, {0x8658,    0x000b},
-{0x8659,    0x0086}, {0x865a,    0x0008}, {0x865b,    0x00ce},
-{0x865c,    0x008f}, {0x865d,    0x0079}, {0x865e,    0x00bd},
-{0x865f,    0x0089}, {0x8660,    0x007f}, {0x8661,    0x007e},
-{0x8662,    0x0086}, {0x8663,    0x008e}, {0x8664,    0x0081},
-{0x8665,    0x0004}, {0x8666,    0x0026}, {0x8667,    0x000b},
-{0x8668,    0x0086}, {0x8669,    0x0004}, {0x866a,    0x00ce},
-{0x866b,    0x008f}, {0x866c,    0x0076}, {0x866d,    0x00bd},
-{0x866e,    0x0089}, {0x866f,    0x007f}, {0x8670,    0x007e},
-{0x8671,    0x0086}, {0x8672,    0x008e}, {0x8673,    0x0081},
-{0x8674,    0x0002}, {0x8675,    0x0026}, {0x8676,    0x000b},
-{0x8677,    0x008a}, {0x8678,    0x0002}, {0x8679,    0x00ce},
-{0x867a,    0x008f}, {0x867b,    0x0073}, {0x867c,    0x00bd},
-{0x867d,    0x0089}, {0x867e,    0x007f}, {0x867f,    0x007e},
-{0x8680,    0x0086}, {0x8681,    0x008e}, {0x8682,    0x0081},
-{0x8683,    0x0001}, {0x8684,    0x0026}, {0x8685,    0x0008},
-{0x8686,    0x0086}, {0x8687,    0x0001}, {0x8688,    0x00ce},
-{0x8689,    0x008f}, {0x868a,    0x0070}, {0x868b,    0x00bd},
-{0x868c,    0x0089}, {0x868d,    0x007f}, {0x868e,    0x00b6},
-{0x868f,    0x008f}, {0x8690,    0x007f}, {0x8691,    0x0081},
-{0x8692,    0x000f}, {0x8693,    0x0026}, {0x8694,    0x0003},
-{0x8695,    0x007e}, {0x8696,    0x0087}, {0x8697,    0x0047},
-{0x8698,    0x00b6}, {0x8699,    0x0012}, {0x869a,    0x0009},
-{0x869b,    0x0084}, {0x869c,    0x0003}, {0x869d,    0x0081},
-{0x869e,    0x0003}, {0x869f,    0x0027}, {0x86a0,    0x0006},
-{0x86a1,    0x007c}, {0x86a2,    0x0012}, {0x86a3,    0x0009},
-{0x86a4,    0x007e}, {0x86a5,    0x0085}, {0x86a6,    0x00fe},
-{0x86a7,    0x00b6}, {0x86a8,    0x0012}, {0x86a9,    0x0006},
-{0x86aa,    0x0084}, {0x86ab,    0x0007}, {0x86ac,    0x0081},
-{0x86ad,    0x0007}, {0x86ae,    0x0027}, {0x86af,    0x0008},
-{0x86b0,    0x008b}, {0x86b1,    0x0001}, {0x86b2,    0x00b7},
-{0x86b3,    0x0012}, {0x86b4,    0x0006}, {0x86b5,    0x007e},
-{0x86b6,    0x0086}, {0x86b7,    0x00d5}, {0x86b8,    0x00b6},
-{0x86b9,    0x008f}, {0x86ba,    0x0082}, {0x86bb,    0x0026},
-{0x86bc,    0x000a}, {0x86bd,    0x007c}, {0x86be,    0x008f},
-{0x86bf,    0x0082}, {0x86c0,    0x004f}, {0x86c1,    0x00b7},
-{0x86c2,    0x0012}, {0x86c3,    0x0006}, {0x86c4,    0x007e},
-{0x86c5,    0x0085}, {0x86c6,    0x00c0}, {0x86c7,    0x00b6},
-{0x86c8,    0x0012}, {0x86c9,    0x0006}, {0x86ca,    0x0084},
-{0x86cb,    0x003f}, {0x86cc,    0x0081}, {0x86cd,    0x003f},
-{0x86ce,    0x0027}, {0x86cf,    0x0010}, {0x86d0,    0x008b},
-{0x86d1,    0x0008}, {0x86d2,    0x00b7}, {0x86d3,    0x0012},
-{0x86d4,    0x0006}, {0x86d5,    0x00b6}, {0x86d6,    0x0012},
-{0x86d7,    0x0009}, {0x86d8,    0x0084}, {0x86d9,    0x00fc},
-{0x86da,    0x00b7}, {0x86db,    0x0012}, {0x86dc,    0x0009},
-{0x86dd,    0x007e}, {0x86de,    0x0085}, {0x86df,    0x00fe},
-{0x86e0,    0x00ce}, {0x86e1,    0x008f}, {0x86e2,    0x0070},
-{0x86e3,    0x0018}, {0x86e4,    0x00ce}, {0x86e5,    0x008f},
-{0x86e6,    0x0084}, {0x86e7,    0x00c6}, {0x86e8,    0x000c},
-{0x86e9,    0x00bd}, {0x86ea,    0x0089}, {0x86eb,    0x006f},
-{0x86ec,    0x00ce}, {0x86ed,    0x008f}, {0x86ee,    0x0084},
-{0x86ef,    0x0018}, {0x86f0,    0x00ce}, {0x86f1,    0x008f},
-{0x86f2,    0x0070}, {0x86f3,    0x00c6}, {0x86f4,    0x000c},
-{0x86f5,    0x00bd}, {0x86f6,    0x0089}, {0x86f7,    0x006f},
-{0x86f8,    0x00d6}, {0x86f9,    0x0083}, {0x86fa,    0x00c1},
-{0x86fb,    0x004f}, {0x86fc,    0x002d}, {0x86fd,    0x0003},
-{0x86fe,    0x007e}, {0x86ff,    0x0087}, {0x8700,    0x0040},
-{0x8701,    0x00b6}, {0x8702,    0x008f}, {0x8703,    0x007f},
-{0x8704,    0x0081}, {0x8705,    0x0007}, {0x8706,    0x0027},
-{0x8707,    0x000f}, {0x8708,    0x0081}, {0x8709,    0x000b},
-{0x870a,    0x0027}, {0x870b,    0x0015}, {0x870c,    0x0081},
-{0x870d,    0x000d}, {0x870e,    0x0027}, {0x870f,    0x001b},
-{0x8710,    0x0081}, {0x8711,    0x000e}, {0x8712,    0x0027},
-{0x8713,    0x0021}, {0x8714,    0x007e}, {0x8715,    0x0087},
-{0x8716,    0x0040}, {0x8717,    0x00f7}, {0x8718,    0x008f},
-{0x8719,    0x007b}, {0x871a,    0x0086}, {0x871b,    0x0002},
-{0x871c,    0x00b7}, {0x871d,    0x008f}, {0x871e,    0x007a},
-{0x871f,    0x0020}, {0x8720,    0x001c}, {0x8721,    0x00f7},
-{0x8722,    0x008f}, {0x8723,    0x0078}, {0x8724,    0x0086},
-{0x8725,    0x0002}, {0x8726,    0x00b7}, {0x8727,    0x008f},
-{0x8728,    0x0077}, {0x8729,    0x0020}, {0x872a,    0x0012},
-{0x872b,    0x00f7}, {0x872c,    0x008f}, {0x872d,    0x0075},
-{0x872e,    0x0086}, {0x872f,    0x0002}, {0x8730,    0x00b7},
-{0x8731,    0x008f}, {0x8732,    0x0074}, {0x8733,    0x0020},
-{0x8734,    0x0008}, {0x8735,    0x00f7}, {0x8736,    0x008f},
-{0x8737,    0x0072}, {0x8738,    0x0086}, {0x8739,    0x0002},
-{0x873a,    0x00b7}, {0x873b,    0x008f}, {0x873c,    0x0071},
-{0x873d,    0x007e}, {0x873e,    0x0087}, {0x873f,    0x0047},
-{0x8740,    0x0086}, {0x8741,    0x0004}, {0x8742,    0x0097},
-{0x8743,    0x0040}, {0x8744,    0x007e}, {0x8745,    0x0089},
-{0x8746,    0x006e}, {0x8747,    0x00ce}, {0x8748,    0x008f},
-{0x8749,    0x0072}, {0x874a,    0x00bd}, {0x874b,    0x0089},
-{0x874c,    0x00f7}, {0x874d,    0x00ce}, {0x874e,    0x008f},
-{0x874f,    0x0075}, {0x8750,    0x00bd}, {0x8751,    0x0089},
-{0x8752,    0x00f7}, {0x8753,    0x00ce}, {0x8754,    0x008f},
-{0x8755,    0x0078}, {0x8756,    0x00bd}, {0x8757,    0x0089},
-{0x8758,    0x00f7}, {0x8759,    0x00ce}, {0x875a,    0x008f},
-{0x875b,    0x007b}, {0x875c,    0x00bd}, {0x875d,    0x0089},
-{0x875e,    0x00f7}, {0x875f,    0x004f}, {0x8760,    0x00b7},
-{0x8761,    0x008f}, {0x8762,    0x007d}, {0x8763,    0x00b7},
-{0x8764,    0x008f}, {0x8765,    0x0081}, {0x8766,    0x00b6},
-{0x8767,    0x008f}, {0x8768,    0x0072}, {0x8769,    0x0027},
-{0x876a,    0x0047}, {0x876b,    0x007c}, {0x876c,    0x008f},
-{0x876d,    0x007d}, {0x876e,    0x00b6}, {0x876f,    0x008f},
-{0x8770,    0x0075}, {0x8771,    0x0027}, {0x8772,    0x003f},
-{0x8773,    0x007c}, {0x8774,    0x008f}, {0x8775,    0x007d},
-{0x8776,    0x00b6}, {0x8777,    0x008f}, {0x8778,    0x0078},
-{0x8779,    0x0027}, {0x877a,    0x0037}, {0x877b,    0x007c},
-{0x877c,    0x008f}, {0x877d,    0x007d}, {0x877e,    0x00b6},
-{0x877f,    0x008f}, {0x8780,    0x007b}, {0x8781,    0x0027},
-{0x8782,    0x002f}, {0x8783,    0x007f}, {0x8784,    0x008f},
-{0x8785,    0x007d}, {0x8786,    0x007c}, {0x8787,    0x008f},
-{0x8788,    0x0081}, {0x8789,    0x007a}, {0x878a,    0x008f},
-{0x878b,    0x0072}, {0x878c,    0x0027}, {0x878d,    0x001b},
-{0x878e,    0x007c}, {0x878f,    0x008f}, {0x8790,    0x007d},
-{0x8791,    0x007a}, {0x8792,    0x008f}, {0x8793,    0x0075},
-{0x8794,    0x0027}, {0x8795,    0x0016}, {0x8796,    0x007c},
-{0x8797,    0x008f}, {0x8798,    0x007d}, {0x8799,    0x007a},
-{0x879a,    0x008f}, {0x879b,    0x0078}, {0x879c,    0x0027},
-{0x879d,    0x0011}, {0x879e,    0x007c}, {0x879f,    0x008f},
-{0x87a0,    0x007d}, {0x87a1,    0x007a}, {0x87a2,    0x008f},
-{0x87a3,    0x007b}, {0x87a4,    0x0027}, {0x87a5,    0x000c},
-{0x87a6,    0x007e}, {0x87a7,    0x0087}, {0x87a8,    0x0083},
-{0x87a9,    0x007a}, {0x87aa,    0x008f}, {0x87ab,    0x0075},
-{0x87ac,    0x007a}, {0x87ad,    0x008f}, {0x87ae,    0x0078},
-{0x87af,    0x007a}, {0x87b0,    0x008f}, {0x87b1,    0x007b},
-{0x87b2,    0x00ce}, {0x87b3,    0x00c1}, {0x87b4,    0x00fc},
-{0x87b5,    0x00f6}, {0x87b6,    0x008f}, {0x87b7,    0x007d},
-{0x87b8,    0x003a}, {0x87b9,    0x00a6}, {0x87ba,    0x0000},
-{0x87bb,    0x00b7}, {0x87bc,    0x0012}, {0x87bd,    0x0070},
-{0x87be,    0x00b6}, {0x87bf,    0x008f}, {0x87c0,    0x0072},
-{0x87c1,    0x0026}, {0x87c2,    0x0003}, {0x87c3,    0x007e},
-{0x87c4,    0x0087}, {0x87c5,    0x00fa}, {0x87c6,    0x00b6},
-{0x87c7,    0x008f}, {0x87c8,    0x0075}, {0x87c9,    0x0026},
-{0x87ca,    0x000a}, {0x87cb,    0x0018}, {0x87cc,    0x00ce},
-{0x87cd,    0x008f}, {0x87ce,    0x0073}, {0x87cf,    0x00bd},
-{0x87d0,    0x0089}, {0x87d1,    0x00d5}, {0x87d2,    0x007e},
-{0x87d3,    0x0087}, {0x87d4,    0x00fa}, {0x87d5,    0x00b6},
-{0x87d6,    0x008f}, {0x87d7,    0x0078}, {0x87d8,    0x0026},
-{0x87d9,    0x000a}, {0x87da,    0x0018}, {0x87db,    0x00ce},
-{0x87dc,    0x008f}, {0x87dd,    0x0076}, {0x87de,    0x00bd},
-{0x87df,    0x0089}, {0x87e0,    0x00d5}, {0x87e1,    0x007e},
-{0x87e2,    0x0087}, {0x87e3,    0x00fa}, {0x87e4,    0x00b6},
-{0x87e5,    0x008f}, {0x87e6,    0x007b}, {0x87e7,    0x0026},
-{0x87e8,    0x000a}, {0x87e9,    0x0018}, {0x87ea,    0x00ce},
-{0x87eb,    0x008f}, {0x87ec,    0x0079}, {0x87ed,    0x00bd},
-{0x87ee,    0x0089}, {0x87ef,    0x00d5}, {0x87f0,    0x007e},
-{0x87f1,    0x0087}, {0x87f2,    0x00fa}, {0x87f3,    0x0086},
-{0x87f4,    0x0005}, {0x87f5,    0x0097}, {0x87f6,    0x0040},
-{0x87f7,    0x007e}, {0x87f8,    0x0089}, {0x87f9,    0x0000},
-{0x87fa,    0x00b6}, {0x87fb,    0x008f}, {0x87fc,    0x0075},
-{0x87fd,    0x0081}, {0x87fe,    0x0007}, {0x87ff,    0x002e},
-{0x8800,    0x00f2}, {0x8801,    0x00f6}, {0x8802,    0x0012},
-{0x8803,    0x0006}, {0x8804,    0x00c4}, {0x8805,    0x00f8},
-{0x8806,    0x001b}, {0x8807,    0x00b7}, {0x8808,    0x0012},
-{0x8809,    0x0006}, {0x880a,    0x00b6}, {0x880b,    0x008f},
-{0x880c,    0x0078}, {0x880d,    0x0081}, {0x880e,    0x0007},
-{0x880f,    0x002e}, {0x8810,    0x00e2}, {0x8811,    0x0048},
-{0x8812,    0x0048}, {0x8813,    0x0048}, {0x8814,    0x00f6},
-{0x8815,    0x0012}, {0x8816,    0x0006}, {0x8817,    0x00c4},
-{0x8818,    0x00c7}, {0x8819,    0x001b}, {0x881a,    0x00b7},
-{0x881b,    0x0012}, {0x881c,    0x0006}, {0x881d,    0x00b6},
-{0x881e,    0x008f}, {0x881f,    0x007b}, {0x8820,    0x0081},
-{0x8821,    0x0007}, {0x8822,    0x002e}, {0x8823,    0x00cf},
-{0x8824,    0x00f6}, {0x8825,    0x0012}, {0x8826,    0x0005},
-{0x8827,    0x00c4}, {0x8828,    0x00f8}, {0x8829,    0x001b},
-{0x882a,    0x00b7}, {0x882b,    0x0012}, {0x882c,    0x0005},
-{0x882d,    0x0086}, {0x882e,    0x0000}, {0x882f,    0x00f6},
-{0x8830,    0x008f}, {0x8831,    0x0071}, {0x8832,    0x00bd},
-{0x8833,    0x0089}, {0x8834,    0x0094}, {0x8835,    0x0086},
-{0x8836,    0x0001}, {0x8837,    0x00f6}, {0x8838,    0x008f},
-{0x8839,    0x0074}, {0x883a,    0x00bd}, {0x883b,    0x0089},
-{0x883c,    0x0094}, {0x883d,    0x0086}, {0x883e,    0x0002},
-{0x883f,    0x00f6}, {0x8840,    0x008f}, {0x8841,    0x0077},
-{0x8842,    0x00bd}, {0x8843,    0x0089}, {0x8844,    0x0094},
-{0x8845,    0x0086}, {0x8846,    0x0003}, {0x8847,    0x00f6},
-{0x8848,    0x008f}, {0x8849,    0x007a}, {0x884a,    0x00bd},
-{0x884b,    0x0089}, {0x884c,    0x0094}, {0x884d,    0x00ce},
-{0x884e,    0x008f}, {0x884f,    0x0070}, {0x8850,    0x00a6},
-{0x8851,    0x0001}, {0x8852,    0x0081}, {0x8853,    0x0001},
-{0x8854,    0x0027}, {0x8855,    0x0007}, {0x8856,    0x0081},
-{0x8857,    0x0003}, {0x8858,    0x0027}, {0x8859,    0x0003},
-{0x885a,    0x007e}, {0x885b,    0x0088}, {0x885c,    0x0066},
-{0x885d,    0x00a6}, {0x885e,    0x0000}, {0x885f,    0x00b8},
-{0x8860,    0x008f}, {0x8861,    0x0081}, {0x8862,    0x0084},
-{0x8863,    0x0001}, {0x8864,    0x0026}, {0x8865,    0x000b},
-{0x8866,    0x008c}, {0x8867,    0x008f}, {0x8868,    0x0079},
-{0x8869,    0x002c}, {0x886a,    0x000e}, {0x886b,    0x0008},
-{0x886c,    0x0008}, {0x886d,    0x0008}, {0x886e,    0x007e},
-{0x886f,    0x0088}, {0x8870,    0x0050}, {0x8871,    0x00b6},
-{0x8872,    0x0012}, {0x8873,    0x0004}, {0x8874,    0x008a},
-{0x8875,    0x0040}, {0x8876,    0x00b7}, {0x8877,    0x0012},
-{0x8878,    0x0004}, {0x8879,    0x00b6}, {0x887a,    0x0012},
-{0x887b,    0x0004}, {0x887c,    0x0084}, {0x887d,    0x00fb},
-{0x887e,    0x0084}, {0x887f,    0x00ef}, {0x8880,    0x00b7},
-{0x8881,    0x0012}, {0x8882,    0x0004}, {0x8883,    0x00b6},
-{0x8884,    0x0012}, {0x8885,    0x0007}, {0x8886,    0x0036},
-{0x8887,    0x00b6}, {0x8888,    0x008f}, {0x8889,    0x007c},
-{0x888a,    0x0048}, {0x888b,    0x0048}, {0x888c,    0x00b7},
-{0x888d,    0x0012}, {0x888e,    0x0007}, {0x888f,    0x0086},
-{0x8890,    0x0001}, {0x8891,    0x00ba}, {0x8892,    0x0012},
-{0x8893,    0x0004}, {0x8894,    0x00b7}, {0x8895,    0x0012},
-{0x8896,    0x0004}, {0x8897,    0x0001}, {0x8898,    0x0001},
-{0x8899,    0x0001}, {0x889a,    0x0001}, {0x889b,    0x0001},
-{0x889c,    0x0001}, {0x889d,    0x0086}, {0x889e,    0x00fe},
-{0x889f,    0x00b4}, {0x88a0,    0x0012}, {0x88a1,    0x0004},
-{0x88a2,    0x00b7}, {0x88a3,    0x0012}, {0x88a4,    0x0004},
-{0x88a5,    0x0086}, {0x88a6,    0x0002}, {0x88a7,    0x00ba},
-{0x88a8,    0x0012}, {0x88a9,    0x0004}, {0x88aa,    0x00b7},
-{0x88ab,    0x0012}, {0x88ac,    0x0004}, {0x88ad,    0x0086},
-{0x88ae,    0x00fd}, {0x88af,    0x00b4}, {0x88b0,    0x0012},
-{0x88b1,    0x0004}, {0x88b2,    0x00b7}, {0x88b3,    0x0012},
-{0x88b4,    0x0004}, {0x88b5,    0x0032}, {0x88b6,    0x00b7},
-{0x88b7,    0x0012}, {0x88b8,    0x0007}, {0x88b9,    0x00b6},
-{0x88ba,    0x0012}, {0x88bb,    0x0000}, {0x88bc,    0x0084},
-{0x88bd,    0x0008}, {0x88be,    0x0081}, {0x88bf,    0x0008},
-{0x88c0,    0x0027}, {0x88c1,    0x000f}, {0x88c2,    0x007c},
-{0x88c3,    0x0082}, {0x88c4,    0x0008}, {0x88c5,    0x0026},
-{0x88c6,    0x0007}, {0x88c7,    0x0086}, {0x88c8,    0x0076},
-{0x88c9,    0x0097}, {0x88ca,    0x0040}, {0x88cb,    0x007e},
-{0x88cc,    0x0089}, {0x88cd,    0x006e}, {0x88ce,    0x007e},
-{0x88cf,    0x0086}, {0x88d0,    0x00ec}, {0x88d1,    0x00b6},
-{0x88d2,    0x008f}, {0x88d3,    0x007f}, {0x88d4,    0x0081},
-{0x88d5,    0x000f}, {0x88d6,    0x0027}, {0x88d7,    0x003c},
-{0x88d8,    0x00bd}, {0x88d9,    0x00e6}, {0x88da,    0x00c7},
-{0x88db,    0x00b7}, {0x88dc,    0x0012}, {0x88dd,    0x000d},
-{0x88de,    0x00bd}, {0x88df,    0x00e6}, {0x88e0,    0x00cb},
-{0x88e1,    0x00b6}, {0x88e2,    0x0012}, {0x88e3,    0x0004},
-{0x88e4,    0x008a}, {0x88e5,    0x0020}, {0x88e6,    0x00b7},
-{0x88e7,    0x0012}, {0x88e8,    0x0004}, {0x88e9,    0x00ce},
-{0x88ea,    0x00ff}, {0x88eb,    0x00ff}, {0x88ec,    0x00b6},
-{0x88ed,    0x0012}, {0x88ee,    0x0000}, {0x88ef,    0x0081},
-{0x88f0,    0x000c}, {0x88f1,    0x0026}, {0x88f2,    0x0005},
-{0x88f3,    0x0009}, {0x88f4,    0x0026}, {0x88f5,    0x00f6},
-{0x88f6,    0x0027}, {0x88f7,    0x001c}, {0x88f8,    0x00b6},
-{0x88f9,    0x0012}, {0x88fa,    0x0004}, {0x88fb,    0x0084},
-{0x88fc,    0x00df}, {0x88fd,    0x00b7}, {0x88fe,    0x0012},
-{0x88ff,    0x0004}, {0x8900,    0x0096}, {0x8901,    0x0083},
-{0x8902,    0x0081}, {0x8903,    0x0007}, {0x8904,    0x002c},
-{0x8905,    0x0005}, {0x8906,    0x007c}, {0x8907,    0x0000},
-{0x8908,    0x0083}, {0x8909,    0x0020}, {0x890a,    0x0006},
-{0x890b,    0x0096}, {0x890c,    0x0083}, {0x890d,    0x008b},
-{0x890e,    0x0008}, {0x890f,    0x0097}, {0x8910,    0x0083},
-{0x8911,    0x007e}, {0x8912,    0x0085}, {0x8913,    0x0041},
-{0x8914,    0x007f}, {0x8915,    0x008f}, {0x8916,    0x007e},
-{0x8917,    0x0086}, {0x8918,    0x0080}, {0x8919,    0x00b7},
-{0x891a,    0x0012}, {0x891b,    0x000c}, {0x891c,    0x0086},
-{0x891d,    0x0001}, {0x891e,    0x00b7}, {0x891f,    0x008f},
-{0x8920,    0x007d}, {0x8921,    0x00b6}, {0x8922,    0x0012},
-{0x8923,    0x000c}, {0x8924,    0x0084}, {0x8925,    0x007f},
-{0x8926,    0x00b7}, {0x8927,    0x0012}, {0x8928,    0x000c},
-{0x8929,    0x008a}, {0x892a,    0x0080}, {0x892b,    0x00b7},
-{0x892c,    0x0012}, {0x892d,    0x000c}, {0x892e,    0x0086},
-{0x892f,    0x000a}, {0x8930,    0x00bd}, {0x8931,    0x008a},
-{0x8932,    0x0006}, {0x8933,    0x00b6}, {0x8934,    0x0012},
-{0x8935,    0x000a}, {0x8936,    0x002a}, {0x8937,    0x0009},
-{0x8938,    0x00b6}, {0x8939,    0x0012}, {0x893a,    0x000c},
-{0x893b,    0x00ba}, {0x893c,    0x008f}, {0x893d,    0x007d},
-{0x893e,    0x00b7}, {0x893f,    0x0012}, {0x8940,    0x000c},
-{0x8941,    0x00b6}, {0x8942,    0x008f}, {0x8943,    0x007e},
-{0x8944,    0x0081}, {0x8945,    0x0060}, {0x8946,    0x0027},
-{0x8947,    0x001a}, {0x8948,    0x008b}, {0x8949,    0x0020},
-{0x894a,    0x00b7}, {0x894b,    0x008f}, {0x894c,    0x007e},
-{0x894d,    0x00b6}, {0x894e,    0x0012}, {0x894f,    0x000c},
-{0x8950,    0x0084}, {0x8951,    0x009f}, {0x8952,    0x00ba},
-{0x8953,    0x008f}, {0x8954,    0x007e}, {0x8955,    0x00b7},
-{0x8956,    0x0012}, {0x8957,    0x000c}, {0x8958,    0x00b6},
-{0x8959,    0x008f}, {0x895a,    0x007d}, {0x895b,    0x0048},
-{0x895c,    0x00b7}, {0x895d,    0x008f}, {0x895e,    0x007d},
-{0x895f,    0x007e}, {0x8960,    0x0089}, {0x8961,    0x0021},
-{0x8962,    0x00b6}, {0x8963,    0x0012}, {0x8964,    0x0004},
-{0x8965,    0x008a}, {0x8966,    0x0020}, {0x8967,    0x00b7},
-{0x8968,    0x0012}, {0x8969,    0x0004}, {0x896a,    0x00bd},
-{0x896b,    0x008a}, {0x896c,    0x000a}, {0x896d,    0x004f},
-{0x896e,    0x0039}, {0x896f,    0x00a6}, {0x8970,    0x0000},
-{0x8971,    0x0018}, {0x8972,    0x00a7}, {0x8973,    0x0000},
-{0x8974,    0x0008}, {0x8975,    0x0018}, {0x8976,    0x0008},
-{0x8977,    0x005a}, {0x8978,    0x0026}, {0x8979,    0x00f5},
-{0x897a,    0x0039}, {0x897b,    0x0036}, {0x897c,    0x006c},
-{0x897d,    0x0000}, {0x897e,    0x0032}, {0x897f,    0x00ba},
-{0x8980,    0x008f}, {0x8981,    0x007f}, {0x8982,    0x00b7},
-{0x8983,    0x008f}, {0x8984,    0x007f}, {0x8985,    0x00b6},
-{0x8986,    0x0012}, {0x8987,    0x0009}, {0x8988,    0x0084},
-{0x8989,    0x0003}, {0x898a,    0x00a7}, {0x898b,    0x0001},
-{0x898c,    0x00b6}, {0x898d,    0x0012}, {0x898e,    0x0006},
-{0x898f,    0x0084}, {0x8990,    0x003f}, {0x8991,    0x00a7},
-{0x8992,    0x0002}, {0x8993,    0x0039}, {0x8994,    0x0036},
-{0x8995,    0x0086}, {0x8996,    0x0003}, {0x8997,    0x00b7},
-{0x8998,    0x008f}, {0x8999,    0x0080}, {0x899a,    0x0032},
-{0x899b,    0x00c1}, {0x899c,    0x0000}, {0x899d,    0x0026},
-{0x899e,    0x0006}, {0x899f,    0x00b7}, {0x89a0,    0x008f},
-{0x89a1,    0x007c}, {0x89a2,    0x007e}, {0x89a3,    0x0089},
-{0x89a4,    0x00c9}, {0x89a5,    0x00c1}, {0x89a6,    0x0001},
-{0x89a7,    0x0027}, {0x89a8,    0x0018}, {0x89a9,    0x00c1},
-{0x89aa,    0x0002}, {0x89ab,    0x0027}, {0x89ac,    0x000c},
-{0x89ad,    0x00c1}, {0x89ae,    0x0003}, {0x89af,    0x0027},
-{0x89b0,    0x0000}, {0x89b1,    0x00f6}, {0x89b2,    0x008f},
-{0x89b3,    0x0080}, {0x89b4,    0x0005}, {0x89b5,    0x0005},
-{0x89b6,    0x00f7}, {0x89b7,    0x008f}, {0x89b8,    0x0080},
-{0x89b9,    0x00f6}, {0x89ba,    0x008f}, {0x89bb,    0x0080},
-{0x89bc,    0x0005}, {0x89bd,    0x0005}, {0x89be,    0x00f7},
-{0x89bf,    0x008f}, {0x89c0,    0x0080}, {0x89c1,    0x00f6},
-{0x89c2,    0x008f}, {0x89c3,    0x0080}, {0x89c4,    0x0005},
-{0x89c5,    0x0005}, {0x89c6,    0x00f7}, {0x89c7,    0x008f},
-{0x89c8,    0x0080}, {0x89c9,    0x00f6}, {0x89ca,    0x008f},
-{0x89cb,    0x0080}, {0x89cc,    0x0053}, {0x89cd,    0x00f4},
-{0x89ce,    0x0012}, {0x89cf,    0x0007}, {0x89d0,    0x001b},
-{0x89d1,    0x00b7}, {0x89d2,    0x0012}, {0x89d3,    0x0007},
-{0x89d4,    0x0039}, {0x89d5,    0x00ce}, {0x89d6,    0x008f},
-{0x89d7,    0x0070}, {0x89d8,    0x00a6}, {0x89d9,    0x0000},
-{0x89da,    0x0018}, {0x89db,    0x00e6}, {0x89dc,    0x0000},
-{0x89dd,    0x0018}, {0x89de,    0x00a7}, {0x89df,    0x0000},
-{0x89e0,    0x00e7}, {0x89e1,    0x0000}, {0x89e2,    0x00a6},
-{0x89e3,    0x0001}, {0x89e4,    0x0018}, {0x89e5,    0x00e6},
-{0x89e6,    0x0001}, {0x89e7,    0x0018}, {0x89e8,    0x00a7},
-{0x89e9,    0x0001}, {0x89ea,    0x00e7}, {0x89eb,    0x0001},
-{0x89ec,    0x00a6}, {0x89ed,    0x0002}, {0x89ee,    0x0018},
-{0x89ef,    0x00e6}, {0x89f0,    0x0002}, {0x89f1,    0x0018},
-{0x89f2,    0x00a7}, {0x89f3,    0x0002}, {0x89f4,    0x00e7},
-{0x89f5,    0x0002}, {0x89f6,    0x0039}, {0x89f7,    0x00a6},
-{0x89f8,    0x0000}, {0x89f9,    0x0084}, {0x89fa,    0x0007},
-{0x89fb,    0x00e6}, {0x89fc,    0x0000}, {0x89fd,    0x00c4},
-{0x89fe,    0x0038}, {0x89ff,    0x0054}, {0x8a00,    0x0054},
-{0x8a01,    0x0054}, {0x8a02,    0x001b}, {0x8a03,    0x00a7},
-{0x8a04,    0x0000}, {0x8a05,    0x0039}, {0x8a06,    0x004a},
-{0x8a07,    0x0026}, {0x8a08,    0x00fd}, {0x8a09,    0x0039},
-{0x8a0a,    0x0096}, {0x8a0b,    0x0022}, {0x8a0c,    0x0084},
-{0x8a0d,    0x000f}, {0x8a0e,    0x0097}, {0x8a0f,    0x0022},
-{0x8a10,    0x0086}, {0x8a11,    0x0001}, {0x8a12,    0x00b7},
-{0x8a13,    0x008f}, {0x8a14,    0x0070}, {0x8a15,    0x00b6},
-{0x8a16,    0x0012}, {0x8a17,    0x0007}, {0x8a18,    0x00b7},
-{0x8a19,    0x008f}, {0x8a1a,    0x0071}, {0x8a1b,    0x00f6},
-{0x8a1c,    0x0012}, {0x8a1d,    0x000c}, {0x8a1e,    0x00c4},
-{0x8a1f,    0x000f}, {0x8a20,    0x00c8}, {0x8a21,    0x000f},
-{0x8a22,    0x00f7}, {0x8a23,    0x008f}, {0x8a24,    0x0072},
-{0x8a25,    0x00f6}, {0x8a26,    0x008f}, {0x8a27,    0x0072},
-{0x8a28,    0x00b6}, {0x8a29,    0x008f}, {0x8a2a,    0x0071},
-{0x8a2b,    0x0084}, {0x8a2c,    0x0003}, {0x8a2d,    0x0027},
-{0x8a2e,    0x0014}, {0x8a2f,    0x0081}, {0x8a30,    0x0001},
-{0x8a31,    0x0027}, {0x8a32,    0x001c}, {0x8a33,    0x0081},
-{0x8a34,    0x0002}, {0x8a35,    0x0027}, {0x8a36,    0x0024},
-{0x8a37,    0x00f4}, {0x8a38,    0x008f}, {0x8a39,    0x0070},
-{0x8a3a,    0x0027}, {0x8a3b,    0x002a}, {0x8a3c,    0x0096},
-{0x8a3d,    0x0022}, {0x8a3e,    0x008a}, {0x8a3f,    0x0080},
-{0x8a40,    0x007e}, {0x8a41,    0x008a}, {0x8a42,    0x0064},
-{0x8a43,    0x00f4}, {0x8a44,    0x008f}, {0x8a45,    0x0070},
-{0x8a46,    0x0027}, {0x8a47,    0x001e}, {0x8a48,    0x0096},
-{0x8a49,    0x0022}, {0x8a4a,    0x008a}, {0x8a4b,    0x0010},
-{0x8a4c,    0x007e}, {0x8a4d,    0x008a}, {0x8a4e,    0x0064},
-{0x8a4f,    0x00f4}, {0x8a50,    0x008f}, {0x8a51,    0x0070},
-{0x8a52,    0x0027}, {0x8a53,    0x0012}, {0x8a54,    0x0096},
-{0x8a55,    0x0022}, {0x8a56,    0x008a}, {0x8a57,    0x0020},
-{0x8a58,    0x007e}, {0x8a59,    0x008a}, {0x8a5a,    0x0064},
-{0x8a5b,    0x00f4}, {0x8a5c,    0x008f}, {0x8a5d,    0x0070},
-{0x8a5e,    0x0027}, {0x8a5f,    0x0006}, {0x8a60,    0x0096},
-{0x8a61,    0x0022}, {0x8a62,    0x008a}, {0x8a63,    0x0040},
-{0x8a64,    0x0097}, {0x8a65,    0x0022}, {0x8a66,    0x0074},
-{0x8a67,    0x008f}, {0x8a68,    0x0071}, {0x8a69,    0x0074},
-{0x8a6a,    0x008f}, {0x8a6b,    0x0071}, {0x8a6c,    0x0078},
-{0x8a6d,    0x008f}, {0x8a6e,    0x0070}, {0x8a6f,    0x00b6},
-{0x8a70,    0x008f}, {0x8a71,    0x0070}, {0x8a72,    0x0085},
-{0x8a73,    0x0010}, {0x8a74,    0x0027}, {0x8a75,    0x00af},
-{0x8a76,    0x00d6}, {0x8a77,    0x0022}, {0x8a78,    0x00c4},
-{0x8a79,    0x0010}, {0x8a7a,    0x0058}, {0x8a7b,    0x00b6},
-{0x8a7c,    0x0012}, {0x8a7d,    0x0070}, {0x8a7e,    0x0081},
-{0x8a7f,    0x00e4}, {0x8a80,    0x0027}, {0x8a81,    0x0036},
-{0x8a82,    0x0081}, {0x8a83,    0x00e1}, {0x8a84,    0x0026},
-{0x8a85,    0x000c}, {0x8a86,    0x0096}, {0x8a87,    0x0022},
-{0x8a88,    0x0084}, {0x8a89,    0x0020}, {0x8a8a,    0x0044},
-{0x8a8b,    0x001b}, {0x8a8c,    0x00d6}, {0x8a8d,    0x0022},
-{0x8a8e,    0x00c4}, {0x8a8f,    0x00cf}, {0x8a90,    0x0020},
-{0x8a91,    0x0023}, {0x8a92,    0x0058}, {0x8a93,    0x0081},
-{0x8a94,    0x00c6}, {0x8a95,    0x0026}, {0x8a96,    0x000d},
-{0x8a97,    0x0096}, {0x8a98,    0x0022}, {0x8a99,    0x0084},
-{0x8a9a,    0x0040}, {0x8a9b,    0x0044}, {0x8a9c,    0x0044},
-{0x8a9d,    0x001b}, {0x8a9e,    0x00d6}, {0x8a9f,    0x0022},
-{0x8aa0,    0x00c4}, {0x8aa1,    0x00af}, {0x8aa2,    0x0020},
-{0x8aa3,    0x0011}, {0x8aa4,    0x0058}, {0x8aa5,    0x0081},
-{0x8aa6,    0x0027}, {0x8aa7,    0x0026}, {0x8aa8,    0x000f},
-{0x8aa9,    0x0096}, {0x8aaa,    0x0022}, {0x8aab,    0x0084},
-{0x8aac,    0x0080}, {0x8aad,    0x0044}, {0x8aae,    0x0044},
-{0x8aaf,    0x0044}, {0x8ab0,    0x001b}, {0x8ab1,    0x00d6},
-{0x8ab2,    0x0022}, {0x8ab3,    0x00c4}, {0x8ab4,    0x006f},
-{0x8ab5,    0x001b}, {0x8ab6,    0x0097}, {0x8ab7,    0x0022},
-{0x8ab8,    0x0039}, {0x8ab9,    0x0027}, {0x8aba,    0x000c},
-{0x8abb,    0x007c}, {0x8abc,    0x0082}, {0x8abd,    0x0006},
-{0x8abe,    0x00bd}, {0x8abf,    0x00d9}, {0x8ac0,    0x00ed},
-{0x8ac1,    0x00b6}, {0x8ac2,    0x0082}, {0x8ac3,    0x0007},
-{0x8ac4,    0x007e}, {0x8ac5,    0x008a}, {0x8ac6,    0x00b9},
-{0x8ac7,    0x007f}, {0x8ac8,    0x0082}, {0x8ac9,    0x0006},
-{0x8aca,    0x0039}, { 0x0, 0x0 }
-};
-#else
-cas_saturn_patch_t cas_saturn_patch[] = {
-{0x8200,    0x007e}, {0x8201,    0x0082}, {0x8202,    0x0009},
-{0x8203,    0x0000}, {0x8204,    0x0000}, {0x8205,    0x0000},
-{0x8206,    0x0000}, {0x8207,    0x0000}, {0x8208,    0x0000},
-{0x8209,    0x008e}, {0x820a,    0x008e}, {0x820b,    0x00ff},
-{0x820c,    0x00ce}, {0x820d,    0x0082}, {0x820e,    0x0025},
-{0x820f,    0x00ff}, {0x8210,    0x0001}, {0x8211,    0x000f},
-{0x8212,    0x00ce}, {0x8213,    0x0084}, {0x8214,    0x0026},
-{0x8215,    0x00ff}, {0x8216,    0x0001}, {0x8217,    0x0011},
-{0x8218,    0x00ce}, {0x8219,    0x0085}, {0x821a,    0x003d},
-{0x821b,    0x00df}, {0x821c,    0x00e5}, {0x821d,    0x0086},
-{0x821e,    0x0039}, {0x821f,    0x00b7}, {0x8220,    0x008f},
-{0x8221,    0x00f8}, {0x8222,    0x007e}, {0x8223,    0x00c3},
-{0x8224,    0x00c2}, {0x8225,    0x0096}, {0x8226,    0x0047},
-{0x8227,    0x0084}, {0x8228,    0x00f3}, {0x8229,    0x008a},
-{0x822a,    0x0000}, {0x822b,    0x0097}, {0x822c,    0x0047},
-{0x822d,    0x00ce}, {0x822e,    0x0082}, {0x822f,    0x0033},
-{0x8230,    0x00ff}, {0x8231,    0x0001}, {0x8232,    0x000f},
-{0x8233,    0x0096}, {0x8234,    0x0046}, {0x8235,    0x0084},
-{0x8236,    0x000c}, {0x8237,    0x0081}, {0x8238,    0x0004},
-{0x8239,    0x0027}, {0x823a,    0x000b}, {0x823b,    0x0096},
-{0x823c,    0x0046}, {0x823d,    0x0084}, {0x823e,    0x000c},
-{0x823f,    0x0081}, {0x8240,    0x0008}, {0x8241,    0x0027},
-{0x8242,    0x0057}, {0x8243,    0x007e}, {0x8244,    0x0084},
-{0x8245,    0x0025}, {0x8246,    0x0096}, {0x8247,    0x0047},
-{0x8248,    0x0084}, {0x8249,    0x00f3}, {0x824a,    0x008a},
-{0x824b,    0x0004}, {0x824c,    0x0097}, {0x824d,    0x0047},
-{0x824e,    0x00ce}, {0x824f,    0x0082}, {0x8250,    0x0054},
-{0x8251,    0x00ff}, {0x8252,    0x0001}, {0x8253,    0x000f},
-{0x8254,    0x0096}, {0x8255,    0x0046}, {0x8256,    0x0084},
-{0x8257,    0x000c}, {0x8258,    0x0081}, {0x8259,    0x0004},
-{0x825a,    0x0026}, {0x825b,    0x0038}, {0x825c,    0x00b6},
-{0x825d,    0x0012}, {0x825e,    0x0020}, {0x825f,    0x0084},
-{0x8260,    0x0020}, {0x8261,    0x0026}, {0x8262,    0x0003},
-{0x8263,    0x007e}, {0x8264,    0x0084}, {0x8265,    0x0025},
-{0x8266,    0x0096}, {0x8267,    0x007b}, {0x8268,    0x00d6},
-{0x8269,    0x007c}, {0x826a,    0x00fe}, {0x826b,    0x008f},
-{0x826c,    0x0056}, {0x826d,    0x00bd}, {0x826e,    0x00f7},
-{0x826f,    0x00b6}, {0x8270,    0x00fe}, {0x8271,    0x008f},
-{0x8272,    0x004e}, {0x8273,    0x00bd}, {0x8274,    0x00ec},
-{0x8275,    0x008e}, {0x8276,    0x00bd}, {0x8277,    0x00fa},
-{0x8278,    0x00f7}, {0x8279,    0x00bd}, {0x827a,    0x00f7},
-{0x827b,    0x0028}, {0x827c,    0x00ce}, {0x827d,    0x0082},
-{0x827e,    0x0082}, {0x827f,    0x00ff}, {0x8280,    0x0001},
-{0x8281,    0x000f}, {0x8282,    0x0096}, {0x8283,    0x0046},
-{0x8284,    0x0084}, {0x8285,    0x000c}, {0x8286,    0x0081},
-{0x8287,    0x0004}, {0x8288,    0x0026}, {0x8289,    0x000a},
-{0x828a,    0x00b6}, {0x828b,    0x0012}, {0x828c,    0x0020},
-{0x828d,    0x0084}, {0x828e,    0x0020}, {0x828f,    0x0027},
-{0x8290,    0x00b5}, {0x8291,    0x007e}, {0x8292,    0x0084},
-{0x8293,    0x0025}, {0x8294,    0x00bd}, {0x8295,    0x00f7},
-{0x8296,    0x001f}, {0x8297,    0x007e}, {0x8298,    0x0084},
-{0x8299,    0x001f}, {0x829a,    0x0096}, {0x829b,    0x0047},
-{0x829c,    0x0084}, {0x829d,    0x00f3}, {0x829e,    0x008a},
-{0x829f,    0x0008}, {0x82a0,    0x0097}, {0x82a1,    0x0047},
-{0x82a2,    0x00de}, {0x82a3,    0x00e1}, {0x82a4,    0x00ad},
-{0x82a5,    0x0000}, {0x82a6,    0x00ce}, {0x82a7,    0x0082},
-{0x82a8,    0x00af}, {0x82a9,    0x00ff}, {0x82aa,    0x0001},
-{0x82ab,    0x000f}, {0x82ac,    0x007e}, {0x82ad,    0x0084},
-{0x82ae,    0x0025}, {0x82af,    0x0096}, {0x82b0,    0x0041},
-{0x82b1,    0x0085}, {0x82b2,    0x0010}, {0x82b3,    0x0026},
-{0x82b4,    0x0006}, {0x82b5,    0x0096}, {0x82b6,    0x0023},
-{0x82b7,    0x0085}, {0x82b8,    0x0040}, {0x82b9,    0x0027},
-{0x82ba,    0x0006}, {0x82bb,    0x00bd}, {0x82bc,    0x00ed},
-{0x82bd,    0x0000}, {0x82be,    0x007e}, {0x82bf,    0x0083},
-{0x82c0,    0x00a2}, {0x82c1,    0x00de}, {0x82c2,    0x0042},
-{0x82c3,    0x00bd}, {0x82c4,    0x00eb}, {0x82c5,    0x008e},
-{0x82c6,    0x0096}, {0x82c7,    0x0024}, {0x82c8,    0x0084},
-{0x82c9,    0x0008}, {0x82ca,    0x0027}, {0x82cb,    0x0003},
-{0x82cc,    0x007e}, {0x82cd,    0x0083}, {0x82ce,    0x00df},
-{0x82cf,    0x0096}, {0x82d0,    0x007b}, {0x82d1,    0x00d6},
-{0x82d2,    0x007c}, {0x82d3,    0x00fe}, {0x82d4,    0x008f},
-{0x82d5,    0x0056}, {0x82d6,    0x00bd}, {0x82d7,    0x00f7},
-{0x82d8,    0x00b6}, {0x82d9,    0x00fe}, {0x82da,    0x008f},
-{0x82db,    0x0050}, {0x82dc,    0x00bd}, {0x82dd,    0x00ec},
-{0x82de,    0x008e}, {0x82df,    0x00bd}, {0x82e0,    0x00fa},
-{0x82e1,    0x00f7}, {0x82e2,    0x0086}, {0x82e3,    0x0011},
-{0x82e4,    0x00c6}, {0x82e5,    0x0049}, {0x82e6,    0x00bd},
-{0x82e7,    0x00e4}, {0x82e8,    0x0012}, {0x82e9,    0x00ce},
-{0x82ea,    0x0082}, {0x82eb,    0x00ef}, {0x82ec,    0x00ff},
-{0x82ed,    0x0001}, {0x82ee,    0x000f}, {0x82ef,    0x0096},
-{0x82f0,    0x0046}, {0x82f1,    0x0084}, {0x82f2,    0x000c},
-{0x82f3,    0x0081}, {0x82f4,    0x0000}, {0x82f5,    0x0027},
-{0x82f6,    0x0017}, {0x82f7,    0x00c6}, {0x82f8,    0x0049},
-{0x82f9,    0x00bd}, {0x82fa,    0x00e4}, {0x82fb,    0x0091},
-{0x82fc,    0x0024}, {0x82fd,    0x000d}, {0x82fe,    0x00b6},
-{0x82ff,    0x0012}, {0x8300,    0x0020}, {0x8301,    0x0085},
-{0x8302,    0x0020}, {0x8303,    0x0026}, {0x8304,    0x000c},
-{0x8305,    0x00ce}, {0x8306,    0x0082}, {0x8307,    0x00c1},
-{0x8308,    0x00ff}, {0x8309,    0x0001}, {0x830a,    0x000f},
-{0x830b,    0x007e}, {0x830c,    0x0084}, {0x830d,    0x0025},
-{0x830e,    0x007e}, {0x830f,    0x0084}, {0x8310,    0x0016},
-{0x8311,    0x00fe}, {0x8312,    0x008f}, {0x8313,    0x0052},
-{0x8314,    0x00bd}, {0x8315,    0x00ec}, {0x8316,    0x008e},
-{0x8317,    0x00bd}, {0x8318,    0x00fa}, {0x8319,    0x00f7},
-{0x831a,    0x0086}, {0x831b,    0x006a}, {0x831c,    0x00c6},
-{0x831d,    0x0049}, {0x831e,    0x00bd}, {0x831f,    0x00e4},
-{0x8320,    0x0012}, {0x8321,    0x00ce}, {0x8322,    0x0083},
-{0x8323,    0x0027}, {0x8324,    0x00ff}, {0x8325,    0x0001},
-{0x8326,    0x000f}, {0x8327,    0x0096}, {0x8328,    0x0046},
-{0x8329,    0x0084}, {0x832a,    0x000c}, {0x832b,    0x0081},
-{0x832c,    0x0000}, {0x832d,    0x0027}, {0x832e,    0x000a},
-{0x832f,    0x00c6}, {0x8330,    0x0049}, {0x8331,    0x00bd},
-{0x8332,    0x00e4}, {0x8333,    0x0091}, {0x8334,    0x0025},
-{0x8335,    0x0006}, {0x8336,    0x007e}, {0x8337,    0x0084},
-{0x8338,    0x0025}, {0x8339,    0x007e}, {0x833a,    0x0084},
-{0x833b,    0x0016}, {0x833c,    0x00b6}, {0x833d,    0x0018},
-{0x833e,    0x0070}, {0x833f,    0x00bb}, {0x8340,    0x0019},
-{0x8341,    0x0070}, {0x8342,    0x002a}, {0x8343,    0x0004},
-{0x8344,    0x0081}, {0x8345,    0x00af}, {0x8346,    0x002e},
-{0x8347,    0x0019}, {0x8348,    0x0096}, {0x8349,    0x007b},
-{0x834a,    0x00f6}, {0x834b,    0x0020}, {0x834c,    0x0007},
-{0x834d,    0x00fa}, {0x834e,    0x0020}, {0x834f,    0x0027},
-{0x8350,    0x00c4}, {0x8351,    0x0038}, {0x8352,    0x0081},
-{0x8353,    0x0038}, {0x8354,    0x0027}, {0x8355,    0x000b},
-{0x8356,    0x00f6}, {0x8357,    0x0020}, {0x8358,    0x0007},
-{0x8359,    0x00fa}, {0x835a,    0x0020}, {0x835b,    0x0027},
-{0x835c,    0x00cb}, {0x835d,    0x0008}, {0x835e,    0x007e},
-{0x835f,    0x0082}, {0x8360,    0x00d3}, {0x8361,    0x00bd},
-{0x8362,    0x00f7}, {0x8363,    0x0066}, {0x8364,    0x0086},
-{0x8365,    0x0074}, {0x8366,    0x00c6}, {0x8367,    0x0049},
-{0x8368,    0x00bd}, {0x8369,    0x00e4}, {0x836a,    0x0012},
-{0x836b,    0x00ce}, {0x836c,    0x0083}, {0x836d,    0x0071},
-{0x836e,    0x00ff}, {0x836f,    0x0001}, {0x8370,    0x000f},
-{0x8371,    0x0096}, {0x8372,    0x0046}, {0x8373,    0x0084},
-{0x8374,    0x000c}, {0x8375,    0x0081}, {0x8376,    0x0008},
-{0x8377,    0x0026}, {0x8378,    0x000a}, {0x8379,    0x00c6},
-{0x837a,    0x0049}, {0x837b,    0x00bd}, {0x837c,    0x00e4},
-{0x837d,    0x0091}, {0x837e,    0x0025}, {0x837f,    0x0006},
-{0x8380,    0x007e}, {0x8381,    0x0084}, {0x8382,    0x0025},
-{0x8383,    0x007e}, {0x8384,    0x0084}, {0x8385,    0x0016},
-{0x8386,    0x00bd}, {0x8387,    0x00f7}, {0x8388,    0x003e},
-{0x8389,    0x0026}, {0x838a,    0x000e}, {0x838b,    0x00bd},
-{0x838c,    0x00e5}, {0x838d,    0x0009}, {0x838e,    0x0026},
-{0x838f,    0x0006}, {0x8390,    0x00ce}, {0x8391,    0x0082},
-{0x8392,    0x00c1}, {0x8393,    0x00ff}, {0x8394,    0x0001},
-{0x8395,    0x000f}, {0x8396,    0x007e}, {0x8397,    0x0084},
-{0x8398,    0x0025}, {0x8399,    0x00fe}, {0x839a,    0x008f},
-{0x839b,    0x0054}, {0x839c,    0x00bd}, {0x839d,    0x00ec},
-{0x839e,    0x008e}, {0x839f,    0x00bd}, {0x83a0,    0x00fa},
-{0x83a1,    0x00f7}, {0x83a2,    0x00bd}, {0x83a3,    0x00f7},
-{0x83a4,    0x0033}, {0x83a5,    0x0086}, {0x83a6,    0x000f},
-{0x83a7,    0x00c6}, {0x83a8,    0x0051}, {0x83a9,    0x00bd},
-{0x83aa,    0x00e4}, {0x83ab,    0x0012}, {0x83ac,    0x00ce},
-{0x83ad,    0x0083}, {0x83ae,    0x00b2}, {0x83af,    0x00ff},
-{0x83b0,    0x0001}, {0x83b1,    0x000f}, {0x83b2,    0x0096},
-{0x83b3,    0x0046}, {0x83b4,    0x0084}, {0x83b5,    0x000c},
-{0x83b6,    0x0081}, {0x83b7,    0x0008}, {0x83b8,    0x0026},
-{0x83b9,    0x005c}, {0x83ba,    0x00b6}, {0x83bb,    0x0012},
-{0x83bc,    0x0020}, {0x83bd,    0x0084}, {0x83be,    0x003f},
-{0x83bf,    0x0081}, {0x83c0,    0x003a}, {0x83c1,    0x0027},
-{0x83c2,    0x001c}, {0x83c3,    0x0096}, {0x83c4,    0x0023},
-{0x83c5,    0x0085}, {0x83c6,    0x0040}, {0x83c7,    0x0027},
-{0x83c8,    0x0003}, {0x83c9,    0x007e}, {0x83ca,    0x0084},
-{0x83cb,    0x0025}, {0x83cc,    0x00c6}, {0x83cd,    0x0051},
-{0x83ce,    0x00bd}, {0x83cf,    0x00e4}, {0x83d0,    0x0091},
-{0x83d1,    0x0025}, {0x83d2,    0x0003}, {0x83d3,    0x007e},
-{0x83d4,    0x0084}, {0x83d5,    0x0025}, {0x83d6,    0x00ce},
-{0x83d7,    0x0082}, {0x83d8,    0x00c1}, {0x83d9,    0x00ff},
-{0x83da,    0x0001}, {0x83db,    0x000f}, {0x83dc,    0x007e},
-{0x83dd,    0x0084}, {0x83de,    0x0025}, {0x83df,    0x00bd},
-{0x83e0,    0x00f8}, {0x83e1,    0x0037}, {0x83e2,    0x007c},
-{0x83e3,    0x0000}, {0x83e4,    0x007a}, {0x83e5,    0x00ce},
-{0x83e6,    0x0083}, {0x83e7,    0x00ee}, {0x83e8,    0x00ff},
-{0x83e9,    0x0001}, {0x83ea,    0x000f}, {0x83eb,    0x007e},
-{0x83ec,    0x0084}, {0x83ed,    0x0025}, {0x83ee,    0x0096},
-{0x83ef,    0x0046}, {0x83f0,    0x0084}, {0x83f1,    0x000c},
-{0x83f2,    0x0081}, {0x83f3,    0x0008}, {0x83f4,    0x0026},
-{0x83f5,    0x0020}, {0x83f6,    0x0096}, {0x83f7,    0x0024},
-{0x83f8,    0x0084}, {0x83f9,    0x0008}, {0x83fa,    0x0026},
-{0x83fb,    0x0029}, {0x83fc,    0x00b6}, {0x83fd,    0x0018},
-{0x83fe,    0x0082}, {0x83ff,    0x00bb}, {0x8400,    0x0019},
-{0x8401,    0x0082}, {0x8402,    0x00b1}, {0x8403,    0x0001},
-{0x8404,    0x003b}, {0x8405,    0x0022}, {0x8406,    0x0009},
-{0x8407,    0x00b6}, {0x8408,    0x0012}, {0x8409,    0x0020},
-{0x840a,    0x0084}, {0x840b,    0x0037}, {0x840c,    0x0081},
-{0x840d,    0x0032}, {0x840e,    0x0027}, {0x840f,    0x0015},
-{0x8410,    0x00bd}, {0x8411,    0x00f8}, {0x8412,    0x0044},
-{0x8413,    0x007e}, {0x8414,    0x0082}, {0x8415,    0x00c1},
-{0x8416,    0x00bd}, {0x8417,    0x00f7}, {0x8418,    0x001f},
-{0x8419,    0x00bd}, {0x841a,    0x00f8}, {0x841b,    0x0044},
-{0x841c,    0x00bd}, {0x841d,    0x00fc}, {0x841e,    0x0029},
-{0x841f,    0x00ce}, {0x8420,    0x0082}, {0x8421,    0x0025},
-{0x8422,    0x00ff}, {0x8423,    0x0001}, {0x8424,    0x000f},
-{0x8425,    0x0039}, {0x8426,    0x0096}, {0x8427,    0x0047},
-{0x8428,    0x0084}, {0x8429,    0x00fc}, {0x842a,    0x008a},
-{0x842b,    0x0000}, {0x842c,    0x0097}, {0x842d,    0x0047},
-{0x842e,    0x00ce}, {0x842f,    0x0084}, {0x8430,    0x0034},
-{0x8431,    0x00ff}, {0x8432,    0x0001}, {0x8433,    0x0011},
-{0x8434,    0x0096}, {0x8435,    0x0046}, {0x8436,    0x0084},
-{0x8437,    0x0003}, {0x8438,    0x0081}, {0x8439,    0x0002},
-{0x843a,    0x0027}, {0x843b,    0x0003}, {0x843c,    0x007e},
-{0x843d,    0x0085}, {0x843e,    0x001e}, {0x843f,    0x0096},
-{0x8440,    0x0047}, {0x8441,    0x0084}, {0x8442,    0x00fc},
-{0x8443,    0x008a}, {0x8444,    0x0002}, {0x8445,    0x0097},
-{0x8446,    0x0047}, {0x8447,    0x00de}, {0x8448,    0x00e1},
-{0x8449,    0x00ad}, {0x844a,    0x0000}, {0x844b,    0x0086},
-{0x844c,    0x0001}, {0x844d,    0x00b7}, {0x844e,    0x0012},
-{0x844f,    0x0051}, {0x8450,    0x00bd}, {0x8451,    0x00f7},
-{0x8452,    0x0014}, {0x8453,    0x00b6}, {0x8454,    0x0010},
-{0x8455,    0x0031}, {0x8456,    0x0084}, {0x8457,    0x00fd},
-{0x8458,    0x00b7}, {0x8459,    0x0010}, {0x845a,    0x0031},
-{0x845b,    0x00bd}, {0x845c,    0x00f8}, {0x845d,    0x001e},
-{0x845e,    0x0096}, {0x845f,    0x0081}, {0x8460,    0x00d6},
-{0x8461,    0x0082}, {0x8462,    0x00fe}, {0x8463,    0x008f},
-{0x8464,    0x005a}, {0x8465,    0x00bd}, {0x8466,    0x00f7},
-{0x8467,    0x00b6}, {0x8468,    0x00fe}, {0x8469,    0x008f},
-{0x846a,    0x005c}, {0x846b,    0x00bd}, {0x846c,    0x00ec},
-{0x846d,    0x008e}, {0x846e,    0x00bd}, {0x846f,    0x00fa},
-{0x8470,    0x00f7}, {0x8471,    0x0086}, {0x8472,    0x0008},
-{0x8473,    0x00d6}, {0x8474,    0x0000}, {0x8475,    0x00c5},
-{0x8476,    0x0010}, {0x8477,    0x0026}, {0x8478,    0x0002},
-{0x8479,    0x008b}, {0x847a,    0x0020}, {0x847b,    0x00c6},
-{0x847c,    0x0051}, {0x847d,    0x00bd}, {0x847e,    0x00e4},
-{0x847f,    0x0012}, {0x8480,    0x00ce}, {0x8481,    0x0084},
-{0x8482,    0x0086}, {0x8483,    0x00ff}, {0x8484,    0x0001},
-{0x8485,    0x0011}, {0x8486,    0x0096}, {0x8487,    0x0046},
-{0x8488,    0x0084}, {0x8489,    0x0003}, {0x848a,    0x0081},
-{0x848b,    0x0002}, {0x848c,    0x0027}, {0x848d,    0x0003},
-{0x848e,    0x007e}, {0x848f,    0x0085}, {0x8490,    0x000f},
-{0x8491,    0x00c6}, {0x8492,    0x0051}, {0x8493,    0x00bd},
-{0x8494,    0x00e4}, {0x8495,    0x0091}, {0x8496,    0x0025},
-{0x8497,    0x0003}, {0x8498,    0x007e}, {0x8499,    0x0085},
-{0x849a,    0x001e}, {0x849b,    0x0096}, {0x849c,    0x0044},
-{0x849d,    0x0085}, {0x849e,    0x0010}, {0x849f,    0x0026},
-{0x84a0,    0x000a}, {0x84a1,    0x00b6}, {0x84a2,    0x0012},
-{0x84a3,    0x0050}, {0x84a4,    0x00ba}, {0x84a5,    0x0001},
-{0x84a6,    0x003c}, {0x84a7,    0x0085}, {0x84a8,    0x0010},
-{0x84a9,    0x0027}, {0x84aa,    0x00a8}, {0x84ab,    0x00bd},
-{0x84ac,    0x00f7}, {0x84ad,    0x0066}, {0x84ae,    0x00ce},
-{0x84af,    0x0084}, {0x84b0,    0x00b7}, {0x84b1,    0x00ff},
-{0x84b2,    0x0001}, {0x84b3,    0x0011}, {0x84b4,    0x007e},
-{0x84b5,    0x0085}, {0x84b6,    0x001e}, {0x84b7,    0x0096},
-{0x84b8,    0x0046}, {0x84b9,    0x0084}, {0x84ba,    0x0003},
-{0x84bb,    0x0081}, {0x84bc,    0x0002}, {0x84bd,    0x0026},
-{0x84be,    0x0050}, {0x84bf,    0x00b6}, {0x84c0,    0x0012},
-{0x84c1,    0x0030}, {0x84c2,    0x0084}, {0x84c3,    0x0003},
-{0x84c4,    0x0081}, {0x84c5,    0x0001}, {0x84c6,    0x0027},
-{0x84c7,    0x0003}, {0x84c8,    0x007e}, {0x84c9,    0x0085},
-{0x84ca,    0x001e}, {0x84cb,    0x0096}, {0x84cc,    0x0044},
-{0x84cd,    0x0085}, {0x84ce,    0x0010}, {0x84cf,    0x0026},
-{0x84d0,    0x0013}, {0x84d1,    0x00b6}, {0x84d2,    0x0012},
-{0x84d3,    0x0050}, {0x84d4,    0x00ba}, {0x84d5,    0x0001},
-{0x84d6,    0x003c}, {0x84d7,    0x0085}, {0x84d8,    0x0010},
-{0x84d9,    0x0026}, {0x84da,    0x0009}, {0x84db,    0x00ce},
-{0x84dc,    0x0084}, {0x84dd,    0x0053}, {0x84de,    0x00ff},
-{0x84df,    0x0001}, {0x84e0,    0x0011}, {0x84e1,    0x007e},
-{0x84e2,    0x0085}, {0x84e3,    0x001e}, {0x84e4,    0x00b6},
-{0x84e5,    0x0010}, {0x84e6,    0x0031}, {0x84e7,    0x008a},
-{0x84e8,    0x0002}, {0x84e9,    0x00b7}, {0x84ea,    0x0010},
-{0x84eb,    0x0031}, {0x84ec,    0x00bd}, {0x84ed,    0x0085},
-{0x84ee,    0x001f}, {0x84ef,    0x00bd}, {0x84f0,    0x00f8},
-{0x84f1,    0x0037}, {0x84f2,    0x007c}, {0x84f3,    0x0000},
-{0x84f4,    0x0080}, {0x84f5,    0x00ce}, {0x84f6,    0x0084},
-{0x84f7,    0x00fe}, {0x84f8,    0x00ff}, {0x84f9,    0x0001},
-{0x84fa,    0x0011}, {0x84fb,    0x007e}, {0x84fc,    0x0085},
-{0x84fd,    0x001e}, {0x84fe,    0x0096}, {0x84ff,    0x0046},
-{0x8500,    0x0084}, {0x8501,    0x0003}, {0x8502,    0x0081},
-{0x8503,    0x0002}, {0x8504,    0x0026}, {0x8505,    0x0009},
-{0x8506,    0x00b6}, {0x8507,    0x0012}, {0x8508,    0x0030},
-{0x8509,    0x0084}, {0x850a,    0x0003}, {0x850b,    0x0081},
-{0x850c,    0x0001}, {0x850d,    0x0027}, {0x850e,    0x000f},
-{0x850f,    0x00bd}, {0x8510,    0x00f8}, {0x8511,    0x0044},
-{0x8512,    0x00bd}, {0x8513,    0x00f7}, {0x8514,    0x000b},
-{0x8515,    0x00bd}, {0x8516,    0x00fc}, {0x8517,    0x0029},
-{0x8518,    0x00ce}, {0x8519,    0x0084}, {0x851a,    0x0026},
-{0x851b,    0x00ff}, {0x851c,    0x0001}, {0x851d,    0x0011},
-{0x851e,    0x0039}, {0x851f,    0x00d6}, {0x8520,    0x0022},
-{0x8521,    0x00c4}, {0x8522,    0x000f}, {0x8523,    0x00b6},
-{0x8524,    0x0012}, {0x8525,    0x0030}, {0x8526,    0x00ba},
-{0x8527,    0x0012}, {0x8528,    0x0032}, {0x8529,    0x0084},
-{0x852a,    0x0004}, {0x852b,    0x0027}, {0x852c,    0x000d},
-{0x852d,    0x0096}, {0x852e,    0x0022}, {0x852f,    0x0085},
-{0x8530,    0x0004}, {0x8531,    0x0027}, {0x8532,    0x0005},
-{0x8533,    0x00ca}, {0x8534,    0x0010}, {0x8535,    0x007e},
-{0x8536,    0x0085}, {0x8537,    0x003a}, {0x8538,    0x00ca},
-{0x8539,    0x0020}, {0x853a,    0x00d7}, {0x853b,    0x0022},
-{0x853c,    0x0039}, {0x853d,    0x0086}, {0x853e,    0x0000},
-{0x853f,    0x0097}, {0x8540,    0x0083}, {0x8541,    0x0018},
-{0x8542,    0x00ce}, {0x8543,    0x001c}, {0x8544,    0x0000},
-{0x8545,    0x00bd}, {0x8546,    0x00eb}, {0x8547,    0x0046},
-{0x8548,    0x0096}, {0x8549,    0x0057}, {0x854a,    0x0085},
-{0x854b,    0x0001}, {0x854c,    0x0027}, {0x854d,    0x0002},
-{0x854e,    0x004f}, {0x854f,    0x0039}, {0x8550,    0x0085},
-{0x8551,    0x0002}, {0x8552,    0x0027}, {0x8553,    0x0001},
-{0x8554,    0x0039}, {0x8555,    0x007f}, {0x8556,    0x008f},
-{0x8557,    0x007d}, {0x8558,    0x0086}, {0x8559,    0x0004},
-{0x855a,    0x00b7}, {0x855b,    0x0012}, {0x855c,    0x0004},
-{0x855d,    0x0086}, {0x855e,    0x0008}, {0x855f,    0x00b7},
-{0x8560,    0x0012}, {0x8561,    0x0007}, {0x8562,    0x0086},
-{0x8563,    0x0010}, {0x8564,    0x00b7}, {0x8565,    0x0012},
-{0x8566,    0x000c}, {0x8567,    0x0086}, {0x8568,    0x0007},
-{0x8569,    0x00b7}, {0x856a,    0x0012}, {0x856b,    0x0006},
-{0x856c,    0x00b6}, {0x856d,    0x008f}, {0x856e,    0x007d},
-{0x856f,    0x00b7}, {0x8570,    0x0012}, {0x8571,    0x0070},
-{0x8572,    0x0086}, {0x8573,    0x0001}, {0x8574,    0x00ba},
-{0x8575,    0x0012}, {0x8576,    0x0004}, {0x8577,    0x00b7},
-{0x8578,    0x0012}, {0x8579,    0x0004}, {0x857a,    0x0001},
-{0x857b,    0x0001}, {0x857c,    0x0001}, {0x857d,    0x0001},
-{0x857e,    0x0001}, {0x857f,    0x0001}, {0x8580,    0x00b6},
-{0x8581,    0x0012}, {0x8582,    0x0004}, {0x8583,    0x0084},
-{0x8584,    0x00fe}, {0x8585,    0x008a}, {0x8586,    0x0002},
-{0x8587,    0x00b7}, {0x8588,    0x0012}, {0x8589,    0x0004},
-{0x858a,    0x0001}, {0x858b,    0x0001}, {0x858c,    0x0001},
-{0x858d,    0x0001}, {0x858e,    0x0001}, {0x858f,    0x0001},
-{0x8590,    0x0086}, {0x8591,    0x00fd}, {0x8592,    0x00b4},
-{0x8593,    0x0012}, {0x8594,    0x0004}, {0x8595,    0x00b7},
-{0x8596,    0x0012}, {0x8597,    0x0004}, {0x8598,    0x00b6},
-{0x8599,    0x0012}, {0x859a,    0x0000}, {0x859b,    0x0084},
-{0x859c,    0x0008}, {0x859d,    0x0081}, {0x859e,    0x0008},
-{0x859f,    0x0027}, {0x85a0,    0x0016}, {0x85a1,    0x00b6},
-{0x85a2,    0x008f}, {0x85a3,    0x007d}, {0x85a4,    0x0081},
-{0x85a5,    0x000c}, {0x85a6,    0x0027}, {0x85a7,    0x0008},
-{0x85a8,    0x008b}, {0x85a9,    0x0004}, {0x85aa,    0x00b7},
-{0x85ab,    0x008f}, {0x85ac,    0x007d}, {0x85ad,    0x007e},
-{0x85ae,    0x0085}, {0x85af,    0x006c}, {0x85b0,    0x0086},
-{0x85b1,    0x0003}, {0x85b2,    0x0097}, {0x85b3,    0x0040},
-{0x85b4,    0x007e}, {0x85b5,    0x0089}, {0x85b6,    0x006e},
-{0x85b7,    0x0086}, {0x85b8,    0x0007}, {0x85b9,    0x00b7},
-{0x85ba,    0x0012}, {0x85bb,    0x0006}, {0x85bc,    0x005f},
-{0x85bd,    0x00f7}, {0x85be,    0x008f}, {0x85bf,    0x0082},
-{0x85c0,    0x005f}, {0x85c1,    0x00f7}, {0x85c2,    0x008f},
-{0x85c3,    0x007f}, {0x85c4,    0x00f7}, {0x85c5,    0x008f},
-{0x85c6,    0x0070}, {0x85c7,    0x00f7}, {0x85c8,    0x008f},
-{0x85c9,    0x0071}, {0x85ca,    0x00f7}, {0x85cb,    0x008f},
-{0x85cc,    0x0072}, {0x85cd,    0x00f7}, {0x85ce,    0x008f},
-{0x85cf,    0x0073}, {0x85d0,    0x00f7}, {0x85d1,    0x008f},
-{0x85d2,    0x0074}, {0x85d3,    0x00f7}, {0x85d4,    0x008f},
-{0x85d5,    0x0075}, {0x85d6,    0x00f7}, {0x85d7,    0x008f},
-{0x85d8,    0x0076}, {0x85d9,    0x00f7}, {0x85da,    0x008f},
-{0x85db,    0x0077}, {0x85dc,    0x00f7}, {0x85dd,    0x008f},
-{0x85de,    0x0078}, {0x85df,    0x00f7}, {0x85e0,    0x008f},
-{0x85e1,    0x0079}, {0x85e2,    0x00f7}, {0x85e3,    0x008f},
-{0x85e4,    0x007a}, {0x85e5,    0x00f7}, {0x85e6,    0x008f},
-{0x85e7,    0x007b}, {0x85e8,    0x00b6}, {0x85e9,    0x0012},
-{0x85ea,    0x0004}, {0x85eb,    0x008a}, {0x85ec,    0x0010},
-{0x85ed,    0x00b7}, {0x85ee,    0x0012}, {0x85ef,    0x0004},
-{0x85f0,    0x0086}, {0x85f1,    0x00e4}, {0x85f2,    0x00b7},
-{0x85f3,    0x0012}, {0x85f4,    0x0070}, {0x85f5,    0x00b7},
-{0x85f6,    0x0012}, {0x85f7,    0x0007}, {0x85f8,    0x00f7},
-{0x85f9,    0x0012}, {0x85fa,    0x0005}, {0x85fb,    0x00f7},
-{0x85fc,    0x0012}, {0x85fd,    0x0009}, {0x85fe,    0x0086},
-{0x85ff,    0x0008}, {0x8600,    0x00ba}, {0x8601,    0x0012},
-{0x8602,    0x0004}, {0x8603,    0x00b7}, {0x8604,    0x0012},
-{0x8605,    0x0004}, {0x8606,    0x0086}, {0x8607,    0x00f7},
-{0x8608,    0x00b4}, {0x8609,    0x0012}, {0x860a,    0x0004},
-{0x860b,    0x00b7}, {0x860c,    0x0012}, {0x860d,    0x0004},
-{0x860e,    0x0001}, {0x860f,    0x0001}, {0x8610,    0x0001},
-{0x8611,    0x0001}, {0x8612,    0x0001}, {0x8613,    0x0001},
-{0x8614,    0x00b6}, {0x8615,    0x0012}, {0x8616,    0x0008},
-{0x8617,    0x0027}, {0x8618,    0x007f}, {0x8619,    0x0081},
-{0x861a,    0x0080}, {0x861b,    0x0026}, {0x861c,    0x000b},
-{0x861d,    0x0086}, {0x861e,    0x0008}, {0x861f,    0x00ce},
-{0x8620,    0x008f}, {0x8621,    0x0079}, {0x8622,    0x00bd},
-{0x8623,    0x0089}, {0x8624,    0x007b}, {0x8625,    0x007e},
-{0x8626,    0x0086}, {0x8627,    0x008e}, {0x8628,    0x0081},
-{0x8629,    0x0040}, {0x862a,    0x0026}, {0x862b,    0x000b},
-{0x862c,    0x0086}, {0x862d,    0x0004}, {0x862e,    0x00ce},
-{0x862f,    0x008f}, {0x8630,    0x0076}, {0x8631,    0x00bd},
-{0x8632,    0x0089}, {0x8633,    0x007b}, {0x8634,    0x007e},
-{0x8635,    0x0086}, {0x8636,    0x008e}, {0x8637,    0x0081},
-{0x8638,    0x0020}, {0x8639,    0x0026}, {0x863a,    0x000b},
-{0x863b,    0x0086}, {0x863c,    0x0002}, {0x863d,    0x00ce},
-{0x863e,    0x008f}, {0x863f,    0x0073}, {0x8640,    0x00bd},
-{0x8641,    0x0089}, {0x8642,    0x007b}, {0x8643,    0x007e},
-{0x8644,    0x0086}, {0x8645,    0x008e}, {0x8646,    0x0081},
-{0x8647,    0x0010}, {0x8648,    0x0026}, {0x8649,    0x000b},
-{0x864a,    0x0086}, {0x864b,    0x0001}, {0x864c,    0x00ce},
-{0x864d,    0x008f}, {0x864e,    0x0070}, {0x864f,    0x00bd},
-{0x8650,    0x0089}, {0x8651,    0x007b}, {0x8652,    0x007e},
-{0x8653,    0x0086}, {0x8654,    0x008e}, {0x8655,    0x0081},
-{0x8656,    0x0008}, {0x8657,    0x0026}, {0x8658,    0x000b},
-{0x8659,    0x0086}, {0x865a,    0x0008}, {0x865b,    0x00ce},
-{0x865c,    0x008f}, {0x865d,    0x0079}, {0x865e,    0x00bd},
-{0x865f,    0x0089}, {0x8660,    0x007f}, {0x8661,    0x007e},
-{0x8662,    0x0086}, {0x8663,    0x008e}, {0x8664,    0x0081},
-{0x8665,    0x0004}, {0x8666,    0x0026}, {0x8667,    0x000b},
-{0x8668,    0x0086}, {0x8669,    0x0004}, {0x866a,    0x00ce},
-{0x866b,    0x008f}, {0x866c,    0x0076}, {0x866d,    0x00bd},
-{0x866e,    0x0089}, {0x866f,    0x007f}, {0x8670,    0x007e},
-{0x8671,    0x0086}, {0x8672,    0x008e}, {0x8673,    0x0081},
-{0x8674,    0x0002}, {0x8675,    0x0026}, {0x8676,    0x000b},
-{0x8677,    0x008a}, {0x8678,    0x0002}, {0x8679,    0x00ce},
-{0x867a,    0x008f}, {0x867b,    0x0073}, {0x867c,    0x00bd},
-{0x867d,    0x0089}, {0x867e,    0x007f}, {0x867f,    0x007e},
-{0x8680,    0x0086}, {0x8681,    0x008e}, {0x8682,    0x0081},
-{0x8683,    0x0001}, {0x8684,    0x0026}, {0x8685,    0x0008},
-{0x8686,    0x0086}, {0x8687,    0x0001}, {0x8688,    0x00ce},
-{0x8689,    0x008f}, {0x868a,    0x0070}, {0x868b,    0x00bd},
-{0x868c,    0x0089}, {0x868d,    0x007f}, {0x868e,    0x00b6},
-{0x868f,    0x008f}, {0x8690,    0x007f}, {0x8691,    0x0081},
-{0x8692,    0x000f}, {0x8693,    0x0026}, {0x8694,    0x0003},
-{0x8695,    0x007e}, {0x8696,    0x0087}, {0x8697,    0x0047},
-{0x8698,    0x00b6}, {0x8699,    0x0012}, {0x869a,    0x0009},
-{0x869b,    0x0084}, {0x869c,    0x0003}, {0x869d,    0x0081},
-{0x869e,    0x0003}, {0x869f,    0x0027}, {0x86a0,    0x0006},
-{0x86a1,    0x007c}, {0x86a2,    0x0012}, {0x86a3,    0x0009},
-{0x86a4,    0x007e}, {0x86a5,    0x0085}, {0x86a6,    0x00fe},
-{0x86a7,    0x00b6}, {0x86a8,    0x0012}, {0x86a9,    0x0006},
-{0x86aa,    0x0084}, {0x86ab,    0x0007}, {0x86ac,    0x0081},
-{0x86ad,    0x0007}, {0x86ae,    0x0027}, {0x86af,    0x0008},
-{0x86b0,    0x008b}, {0x86b1,    0x0001}, {0x86b2,    0x00b7},
-{0x86b3,    0x0012}, {0x86b4,    0x0006}, {0x86b5,    0x007e},
-{0x86b6,    0x0086}, {0x86b7,    0x00d5}, {0x86b8,    0x00b6},
-{0x86b9,    0x008f}, {0x86ba,    0x0082}, {0x86bb,    0x0026},
-{0x86bc,    0x000a}, {0x86bd,    0x007c}, {0x86be,    0x008f},
-{0x86bf,    0x0082}, {0x86c0,    0x004f}, {0x86c1,    0x00b7},
-{0x86c2,    0x0012}, {0x86c3,    0x0006}, {0x86c4,    0x007e},
-{0x86c5,    0x0085}, {0x86c6,    0x00c0}, {0x86c7,    0x00b6},
-{0x86c8,    0x0012}, {0x86c9,    0x0006}, {0x86ca,    0x0084},
-{0x86cb,    0x003f}, {0x86cc,    0x0081}, {0x86cd,    0x003f},
-{0x86ce,    0x0027}, {0x86cf,    0x0010}, {0x86d0,    0x008b},
-{0x86d1,    0x0008}, {0x86d2,    0x00b7}, {0x86d3,    0x0012},
-{0x86d4,    0x0006}, {0x86d5,    0x00b6}, {0x86d6,    0x0012},
-{0x86d7,    0x0009}, {0x86d8,    0x0084}, {0x86d9,    0x00fc},
-{0x86da,    0x00b7}, {0x86db,    0x0012}, {0x86dc,    0x0009},
-{0x86dd,    0x007e}, {0x86de,    0x0085}, {0x86df,    0x00fe},
-{0x86e0,    0x00ce}, {0x86e1,    0x008f}, {0x86e2,    0x0070},
-{0x86e3,    0x0018}, {0x86e4,    0x00ce}, {0x86e5,    0x008f},
-{0x86e6,    0x0084}, {0x86e7,    0x00c6}, {0x86e8,    0x000c},
-{0x86e9,    0x00bd}, {0x86ea,    0x0089}, {0x86eb,    0x006f},
-{0x86ec,    0x00ce}, {0x86ed,    0x008f}, {0x86ee,    0x0084},
-{0x86ef,    0x0018}, {0x86f0,    0x00ce}, {0x86f1,    0x008f},
-{0x86f2,    0x0070}, {0x86f3,    0x00c6}, {0x86f4,    0x000c},
-{0x86f5,    0x00bd}, {0x86f6,    0x0089}, {0x86f7,    0x006f},
-{0x86f8,    0x00d6}, {0x86f9,    0x0083}, {0x86fa,    0x00c1},
-{0x86fb,    0x004f}, {0x86fc,    0x002d}, {0x86fd,    0x0003},
-{0x86fe,    0x007e}, {0x86ff,    0x0087}, {0x8700,    0x0040},
-{0x8701,    0x00b6}, {0x8702,    0x008f}, {0x8703,    0x007f},
-{0x8704,    0x0081}, {0x8705,    0x0007}, {0x8706,    0x0027},
-{0x8707,    0x000f}, {0x8708,    0x0081}, {0x8709,    0x000b},
-{0x870a,    0x0027}, {0x870b,    0x0015}, {0x870c,    0x0081},
-{0x870d,    0x000d}, {0x870e,    0x0027}, {0x870f,    0x001b},
-{0x8710,    0x0081}, {0x8711,    0x000e}, {0x8712,    0x0027},
-{0x8713,    0x0021}, {0x8714,    0x007e}, {0x8715,    0x0087},
-{0x8716,    0x0040}, {0x8717,    0x00f7}, {0x8718,    0x008f},
-{0x8719,    0x007b}, {0x871a,    0x0086}, {0x871b,    0x0002},
-{0x871c,    0x00b7}, {0x871d,    0x008f}, {0x871e,    0x007a},
-{0x871f,    0x0020}, {0x8720,    0x001c}, {0x8721,    0x00f7},
-{0x8722,    0x008f}, {0x8723,    0x0078}, {0x8724,    0x0086},
-{0x8725,    0x0002}, {0x8726,    0x00b7}, {0x8727,    0x008f},
-{0x8728,    0x0077}, {0x8729,    0x0020}, {0x872a,    0x0012},
-{0x872b,    0x00f7}, {0x872c,    0x008f}, {0x872d,    0x0075},
-{0x872e,    0x0086}, {0x872f,    0x0002}, {0x8730,    0x00b7},
-{0x8731,    0x008f}, {0x8732,    0x0074}, {0x8733,    0x0020},
-{0x8734,    0x0008}, {0x8735,    0x00f7}, {0x8736,    0x008f},
-{0x8737,    0x0072}, {0x8738,    0x0086}, {0x8739,    0x0002},
-{0x873a,    0x00b7}, {0x873b,    0x008f}, {0x873c,    0x0071},
-{0x873d,    0x007e}, {0x873e,    0x0087}, {0x873f,    0x0047},
-{0x8740,    0x0086}, {0x8741,    0x0004}, {0x8742,    0x0097},
-{0x8743,    0x0040}, {0x8744,    0x007e}, {0x8745,    0x0089},
-{0x8746,    0x006e}, {0x8747,    0x00ce}, {0x8748,    0x008f},
-{0x8749,    0x0072}, {0x874a,    0x00bd}, {0x874b,    0x0089},
-{0x874c,    0x00f7}, {0x874d,    0x00ce}, {0x874e,    0x008f},
-{0x874f,    0x0075}, {0x8750,    0x00bd}, {0x8751,    0x0089},
-{0x8752,    0x00f7}, {0x8753,    0x00ce}, {0x8754,    0x008f},
-{0x8755,    0x0078}, {0x8756,    0x00bd}, {0x8757,    0x0089},
-{0x8758,    0x00f7}, {0x8759,    0x00ce}, {0x875a,    0x008f},
-{0x875b,    0x007b}, {0x875c,    0x00bd}, {0x875d,    0x0089},
-{0x875e,    0x00f7}, {0x875f,    0x004f}, {0x8760,    0x00b7},
-{0x8761,    0x008f}, {0x8762,    0x007d}, {0x8763,    0x00b7},
-{0x8764,    0x008f}, {0x8765,    0x0081}, {0x8766,    0x00b6},
-{0x8767,    0x008f}, {0x8768,    0x0072}, {0x8769,    0x0027},
-{0x876a,    0x0047}, {0x876b,    0x007c}, {0x876c,    0x008f},
-{0x876d,    0x007d}, {0x876e,    0x00b6}, {0x876f,    0x008f},
-{0x8770,    0x0075}, {0x8771,    0x0027}, {0x8772,    0x003f},
-{0x8773,    0x007c}, {0x8774,    0x008f}, {0x8775,    0x007d},
-{0x8776,    0x00b6}, {0x8777,    0x008f}, {0x8778,    0x0078},
-{0x8779,    0x0027}, {0x877a,    0x0037}, {0x877b,    0x007c},
-{0x877c,    0x008f}, {0x877d,    0x007d}, {0x877e,    0x00b6},
-{0x877f,    0x008f}, {0x8780,    0x007b}, {0x8781,    0x0027},
-{0x8782,    0x002f}, {0x8783,    0x007f}, {0x8784,    0x008f},
-{0x8785,    0x007d}, {0x8786,    0x007c}, {0x8787,    0x008f},
-{0x8788,    0x0081}, {0x8789,    0x007a}, {0x878a,    0x008f},
-{0x878b,    0x0072}, {0x878c,    0x0027}, {0x878d,    0x001b},
-{0x878e,    0x007c}, {0x878f,    0x008f}, {0x8790,    0x007d},
-{0x8791,    0x007a}, {0x8792,    0x008f}, {0x8793,    0x0075},
-{0x8794,    0x0027}, {0x8795,    0x0016}, {0x8796,    0x007c},
-{0x8797,    0x008f}, {0x8798,    0x007d}, {0x8799,    0x007a},
-{0x879a,    0x008f}, {0x879b,    0x0078}, {0x879c,    0x0027},
-{0x879d,    0x0011}, {0x879e,    0x007c}, {0x879f,    0x008f},
-{0x87a0,    0x007d}, {0x87a1,    0x007a}, {0x87a2,    0x008f},
-{0x87a3,    0x007b}, {0x87a4,    0x0027}, {0x87a5,    0x000c},
-{0x87a6,    0x007e}, {0x87a7,    0x0087}, {0x87a8,    0x0083},
-{0x87a9,    0x007a}, {0x87aa,    0x008f}, {0x87ab,    0x0075},
-{0x87ac,    0x007a}, {0x87ad,    0x008f}, {0x87ae,    0x0078},
-{0x87af,    0x007a}, {0x87b0,    0x008f}, {0x87b1,    0x007b},
-{0x87b2,    0x00ce}, {0x87b3,    0x00c1}, {0x87b4,    0x00fc},
-{0x87b5,    0x00f6}, {0x87b6,    0x008f}, {0x87b7,    0x007d},
-{0x87b8,    0x003a}, {0x87b9,    0x00a6}, {0x87ba,    0x0000},
-{0x87bb,    0x00b7}, {0x87bc,    0x0012}, {0x87bd,    0x0070},
-{0x87be,    0x00b6}, {0x87bf,    0x008f}, {0x87c0,    0x0072},
-{0x87c1,    0x0026}, {0x87c2,    0x0003}, {0x87c3,    0x007e},
-{0x87c4,    0x0087}, {0x87c5,    0x00fa}, {0x87c6,    0x00b6},
-{0x87c7,    0x008f}, {0x87c8,    0x0075}, {0x87c9,    0x0026},
-{0x87ca,    0x000a}, {0x87cb,    0x0018}, {0x87cc,    0x00ce},
-{0x87cd,    0x008f}, {0x87ce,    0x0073}, {0x87cf,    0x00bd},
-{0x87d0,    0x0089}, {0x87d1,    0x00d5}, {0x87d2,    0x007e},
-{0x87d3,    0x0087}, {0x87d4,    0x00fa}, {0x87d5,    0x00b6},
-{0x87d6,    0x008f}, {0x87d7,    0x0078}, {0x87d8,    0x0026},
-{0x87d9,    0x000a}, {0x87da,    0x0018}, {0x87db,    0x00ce},
-{0x87dc,    0x008f}, {0x87dd,    0x0076}, {0x87de,    0x00bd},
-{0x87df,    0x0089}, {0x87e0,    0x00d5}, {0x87e1,    0x007e},
-{0x87e2,    0x0087}, {0x87e3,    0x00fa}, {0x87e4,    0x00b6},
-{0x87e5,    0x008f}, {0x87e6,    0x007b}, {0x87e7,    0x0026},
-{0x87e8,    0x000a}, {0x87e9,    0x0018}, {0x87ea,    0x00ce},
-{0x87eb,    0x008f}, {0x87ec,    0x0079}, {0x87ed,    0x00bd},
-{0x87ee,    0x0089}, {0x87ef,    0x00d5}, {0x87f0,    0x007e},
-{0x87f1,    0x0087}, {0x87f2,    0x00fa}, {0x87f3,    0x0086},
-{0x87f4,    0x0005}, {0x87f5,    0x0097}, {0x87f6,    0x0040},
-{0x87f7,    0x007e}, {0x87f8,    0x0089}, {0x87f9,    0x006e},
-{0x87fa,    0x00b6}, {0x87fb,    0x008f}, {0x87fc,    0x0075},
-{0x87fd,    0x0081}, {0x87fe,    0x0007}, {0x87ff,    0x002e},
-{0x8800,    0x00f2}, {0x8801,    0x00f6}, {0x8802,    0x0012},
-{0x8803,    0x0006}, {0x8804,    0x00c4}, {0x8805,    0x00f8},
-{0x8806,    0x001b}, {0x8807,    0x00b7}, {0x8808,    0x0012},
-{0x8809,    0x0006}, {0x880a,    0x00b6}, {0x880b,    0x008f},
-{0x880c,    0x0078}, {0x880d,    0x0081}, {0x880e,    0x0007},
-{0x880f,    0x002e}, {0x8810,    0x00e2}, {0x8811,    0x0048},
-{0x8812,    0x0048}, {0x8813,    0x0048}, {0x8814,    0x00f6},
-{0x8815,    0x0012}, {0x8816,    0x0006}, {0x8817,    0x00c4},
-{0x8818,    0x00c7}, {0x8819,    0x001b}, {0x881a,    0x00b7},
-{0x881b,    0x0012}, {0x881c,    0x0006}, {0x881d,    0x00b6},
-{0x881e,    0x008f}, {0x881f,    0x007b}, {0x8820,    0x0081},
-{0x8821,    0x0007}, {0x8822,    0x002e}, {0x8823,    0x00cf},
-{0x8824,    0x00f6}, {0x8825,    0x0012}, {0x8826,    0x0005},
-{0x8827,    0x00c4}, {0x8828,    0x00f8}, {0x8829,    0x001b},
-{0x882a,    0x00b7}, {0x882b,    0x0012}, {0x882c,    0x0005},
-{0x882d,    0x0086}, {0x882e,    0x0000}, {0x882f,    0x00f6},
-{0x8830,    0x008f}, {0x8831,    0x0071}, {0x8832,    0x00bd},
-{0x8833,    0x0089}, {0x8834,    0x0094}, {0x8835,    0x0086},
-{0x8836,    0x0001}, {0x8837,    0x00f6}, {0x8838,    0x008f},
-{0x8839,    0x0074}, {0x883a,    0x00bd}, {0x883b,    0x0089},
-{0x883c,    0x0094}, {0x883d,    0x0086}, {0x883e,    0x0002},
-{0x883f,    0x00f6}, {0x8840,    0x008f}, {0x8841,    0x0077},
-{0x8842,    0x00bd}, {0x8843,    0x0089}, {0x8844,    0x0094},
-{0x8845,    0x0086}, {0x8846,    0x0003}, {0x8847,    0x00f6},
-{0x8848,    0x008f}, {0x8849,    0x007a}, {0x884a,    0x00bd},
-{0x884b,    0x0089}, {0x884c,    0x0094}, {0x884d,    0x00ce},
-{0x884e,    0x008f}, {0x884f,    0x0070}, {0x8850,    0x00a6},
-{0x8851,    0x0001}, {0x8852,    0x0081}, {0x8853,    0x0001},
-{0x8854,    0x0027}, {0x8855,    0x0007}, {0x8856,    0x0081},
-{0x8857,    0x0003}, {0x8858,    0x0027}, {0x8859,    0x0003},
-{0x885a,    0x007e}, {0x885b,    0x0088}, {0x885c,    0x0066},
-{0x885d,    0x00a6}, {0x885e,    0x0000}, {0x885f,    0x00b8},
-{0x8860,    0x008f}, {0x8861,    0x0081}, {0x8862,    0x0084},
-{0x8863,    0x0001}, {0x8864,    0x0026}, {0x8865,    0x000b},
-{0x8866,    0x008c}, {0x8867,    0x008f}, {0x8868,    0x0079},
-{0x8869,    0x002c}, {0x886a,    0x000e}, {0x886b,    0x0008},
-{0x886c,    0x0008}, {0x886d,    0x0008}, {0x886e,    0x007e},
-{0x886f,    0x0088}, {0x8870,    0x0050}, {0x8871,    0x00b6},
-{0x8872,    0x0012}, {0x8873,    0x0004}, {0x8874,    0x008a},
-{0x8875,    0x0040}, {0x8876,    0x00b7}, {0x8877,    0x0012},
-{0x8878,    0x0004}, {0x8879,    0x00b6}, {0x887a,    0x0012},
-{0x887b,    0x0004}, {0x887c,    0x0084}, {0x887d,    0x00fb},
-{0x887e,    0x0084}, {0x887f,    0x00ef}, {0x8880,    0x00b7},
-{0x8881,    0x0012}, {0x8882,    0x0004}, {0x8883,    0x00b6},
-{0x8884,    0x0012}, {0x8885,    0x0007}, {0x8886,    0x0036},
-{0x8887,    0x00b6}, {0x8888,    0x008f}, {0x8889,    0x007c},
-{0x888a,    0x0048}, {0x888b,    0x0048}, {0x888c,    0x00b7},
-{0x888d,    0x0012}, {0x888e,    0x0007}, {0x888f,    0x0086},
-{0x8890,    0x0001}, {0x8891,    0x00ba}, {0x8892,    0x0012},
-{0x8893,    0x0004}, {0x8894,    0x00b7}, {0x8895,    0x0012},
-{0x8896,    0x0004}, {0x8897,    0x0001}, {0x8898,    0x0001},
-{0x8899,    0x0001}, {0x889a,    0x0001}, {0x889b,    0x0001},
-{0x889c,    0x0001}, {0x889d,    0x0086}, {0x889e,    0x00fe},
-{0x889f,    0x00b4}, {0x88a0,    0x0012}, {0x88a1,    0x0004},
-{0x88a2,    0x00b7}, {0x88a3,    0x0012}, {0x88a4,    0x0004},
-{0x88a5,    0x0086}, {0x88a6,    0x0002}, {0x88a7,    0x00ba},
-{0x88a8,    0x0012}, {0x88a9,    0x0004}, {0x88aa,    0x00b7},
-{0x88ab,    0x0012}, {0x88ac,    0x0004}, {0x88ad,    0x0086},
-{0x88ae,    0x00fd}, {0x88af,    0x00b4}, {0x88b0,    0x0012},
-{0x88b1,    0x0004}, {0x88b2,    0x00b7}, {0x88b3,    0x0012},
-{0x88b4,    0x0004}, {0x88b5,    0x0032}, {0x88b6,    0x00b7},
-{0x88b7,    0x0012}, {0x88b8,    0x0007}, {0x88b9,    0x00b6},
-{0x88ba,    0x0012}, {0x88bb,    0x0000}, {0x88bc,    0x0084},
-{0x88bd,    0x0008}, {0x88be,    0x0081}, {0x88bf,    0x0008},
-{0x88c0,    0x0027}, {0x88c1,    0x000f}, {0x88c2,    0x007c},
-{0x88c3,    0x0082}, {0x88c4,    0x0008}, {0x88c5,    0x0026},
-{0x88c6,    0x0007}, {0x88c7,    0x0086}, {0x88c8,    0x0076},
-{0x88c9,    0x0097}, {0x88ca,    0x0040}, {0x88cb,    0x007e},
-{0x88cc,    0x0089}, {0x88cd,    0x006e}, {0x88ce,    0x007e},
-{0x88cf,    0x0086}, {0x88d0,    0x00ec}, {0x88d1,    0x00b6},
-{0x88d2,    0x008f}, {0x88d3,    0x007f}, {0x88d4,    0x0081},
-{0x88d5,    0x000f}, {0x88d6,    0x0027}, {0x88d7,    0x003c},
-{0x88d8,    0x00bd}, {0x88d9,    0x00e6}, {0x88da,    0x00c7},
-{0x88db,    0x00b7}, {0x88dc,    0x0012}, {0x88dd,    0x000d},
-{0x88de,    0x00bd}, {0x88df,    0x00e6}, {0x88e0,    0x00cb},
-{0x88e1,    0x00b6}, {0x88e2,    0x0012}, {0x88e3,    0x0004},
-{0x88e4,    0x008a}, {0x88e5,    0x0020}, {0x88e6,    0x00b7},
-{0x88e7,    0x0012}, {0x88e8,    0x0004}, {0x88e9,    0x00ce},
-{0x88ea,    0x00ff}, {0x88eb,    0x00ff}, {0x88ec,    0x00b6},
-{0x88ed,    0x0012}, {0x88ee,    0x0000}, {0x88ef,    0x0081},
-{0x88f0,    0x000c}, {0x88f1,    0x0026}, {0x88f2,    0x0005},
-{0x88f3,    0x0009}, {0x88f4,    0x0026}, {0x88f5,    0x00f6},
-{0x88f6,    0x0027}, {0x88f7,    0x001c}, {0x88f8,    0x00b6},
-{0x88f9,    0x0012}, {0x88fa,    0x0004}, {0x88fb,    0x0084},
-{0x88fc,    0x00df}, {0x88fd,    0x00b7}, {0x88fe,    0x0012},
-{0x88ff,    0x0004}, {0x8900,    0x0096}, {0x8901,    0x0083},
-{0x8902,    0x0081}, {0x8903,    0x0007}, {0x8904,    0x002c},
-{0x8905,    0x0005}, {0x8906,    0x007c}, {0x8907,    0x0000},
-{0x8908,    0x0083}, {0x8909,    0x0020}, {0x890a,    0x0006},
-{0x890b,    0x0096}, {0x890c,    0x0083}, {0x890d,    0x008b},
-{0x890e,    0x0008}, {0x890f,    0x0097}, {0x8910,    0x0083},
-{0x8911,    0x007e}, {0x8912,    0x0085}, {0x8913,    0x0041},
-{0x8914,    0x007f}, {0x8915,    0x008f}, {0x8916,    0x007e},
-{0x8917,    0x0086}, {0x8918,    0x0080}, {0x8919,    0x00b7},
-{0x891a,    0x0012}, {0x891b,    0x000c}, {0x891c,    0x0086},
-{0x891d,    0x0001}, {0x891e,    0x00b7}, {0x891f,    0x008f},
-{0x8920,    0x007d}, {0x8921,    0x00b6}, {0x8922,    0x0012},
-{0x8923,    0x000c}, {0x8924,    0x0084}, {0x8925,    0x007f},
-{0x8926,    0x00b7}, {0x8927,    0x0012}, {0x8928,    0x000c},
-{0x8929,    0x008a}, {0x892a,    0x0080}, {0x892b,    0x00b7},
-{0x892c,    0x0012}, {0x892d,    0x000c}, {0x892e,    0x0086},
-{0x892f,    0x000a}, {0x8930,    0x00bd}, {0x8931,    0x008a},
-{0x8932,    0x0006}, {0x8933,    0x00b6}, {0x8934,    0x0012},
-{0x8935,    0x000a}, {0x8936,    0x002a}, {0x8937,    0x0009},
-{0x8938,    0x00b6}, {0x8939,    0x0012}, {0x893a,    0x000c},
-{0x893b,    0x00ba}, {0x893c,    0x008f}, {0x893d,    0x007d},
-{0x893e,    0x00b7}, {0x893f,    0x0012}, {0x8940,    0x000c},
-{0x8941,    0x00b6}, {0x8942,    0x008f}, {0x8943,    0x007e},
-{0x8944,    0x0081}, {0x8945,    0x0060}, {0x8946,    0x0027},
-{0x8947,    0x001a}, {0x8948,    0x008b}, {0x8949,    0x0020},
-{0x894a,    0x00b7}, {0x894b,    0x008f}, {0x894c,    0x007e},
-{0x894d,    0x00b6}, {0x894e,    0x0012}, {0x894f,    0x000c},
-{0x8950,    0x0084}, {0x8951,    0x009f}, {0x8952,    0x00ba},
-{0x8953,    0x008f}, {0x8954,    0x007e}, {0x8955,    0x00b7},
-{0x8956,    0x0012}, {0x8957,    0x000c}, {0x8958,    0x00b6},
-{0x8959,    0x008f}, {0x895a,    0x007d}, {0x895b,    0x0048},
-{0x895c,    0x00b7}, {0x895d,    0x008f}, {0x895e,    0x007d},
-{0x895f,    0x007e}, {0x8960,    0x0089}, {0x8961,    0x0021},
-{0x8962,    0x00b6}, {0x8963,    0x0012}, {0x8964,    0x0004},
-{0x8965,    0x008a}, {0x8966,    0x0020}, {0x8967,    0x00b7},
-{0x8968,    0x0012}, {0x8969,    0x0004}, {0x896a,    0x00bd},
-{0x896b,    0x008a}, {0x896c,    0x000a}, {0x896d,    0x004f},
-{0x896e,    0x0039}, {0x896f,    0x00a6}, {0x8970,    0x0000},
-{0x8971,    0x0018}, {0x8972,    0x00a7}, {0x8973,    0x0000},
-{0x8974,    0x0008}, {0x8975,    0x0018}, {0x8976,    0x0008},
-{0x8977,    0x005a}, {0x8978,    0x0026}, {0x8979,    0x00f5},
-{0x897a,    0x0039}, {0x897b,    0x0036}, {0x897c,    0x006c},
-{0x897d,    0x0000}, {0x897e,    0x0032}, {0x897f,    0x00ba},
-{0x8980,    0x008f}, {0x8981,    0x007f}, {0x8982,    0x00b7},
-{0x8983,    0x008f}, {0x8984,    0x007f}, {0x8985,    0x00b6},
-{0x8986,    0x0012}, {0x8987,    0x0009}, {0x8988,    0x0084},
-{0x8989,    0x0003}, {0x898a,    0x00a7}, {0x898b,    0x0001},
-{0x898c,    0x00b6}, {0x898d,    0x0012}, {0x898e,    0x0006},
-{0x898f,    0x0084}, {0x8990,    0x003f}, {0x8991,    0x00a7},
-{0x8992,    0x0002}, {0x8993,    0x0039}, {0x8994,    0x0036},
-{0x8995,    0x0086}, {0x8996,    0x0003}, {0x8997,    0x00b7},
-{0x8998,    0x008f}, {0x8999,    0x0080}, {0x899a,    0x0032},
-{0x899b,    0x00c1}, {0x899c,    0x0000}, {0x899d,    0x0026},
-{0x899e,    0x0006}, {0x899f,    0x00b7}, {0x89a0,    0x008f},
-{0x89a1,    0x007c}, {0x89a2,    0x007e}, {0x89a3,    0x0089},
-{0x89a4,    0x00c9}, {0x89a5,    0x00c1}, {0x89a6,    0x0001},
-{0x89a7,    0x0027}, {0x89a8,    0x0018}, {0x89a9,    0x00c1},
-{0x89aa,    0x0002}, {0x89ab,    0x0027}, {0x89ac,    0x000c},
-{0x89ad,    0x00c1}, {0x89ae,    0x0003}, {0x89af,    0x0027},
-{0x89b0,    0x0000}, {0x89b1,    0x00f6}, {0x89b2,    0x008f},
-{0x89b3,    0x0080}, {0x89b4,    0x0005}, {0x89b5,    0x0005},
-{0x89b6,    0x00f7}, {0x89b7,    0x008f}, {0x89b8,    0x0080},
-{0x89b9,    0x00f6}, {0x89ba,    0x008f}, {0x89bb,    0x0080},
-{0x89bc,    0x0005}, {0x89bd,    0x0005}, {0x89be,    0x00f7},
-{0x89bf,    0x008f}, {0x89c0,    0x0080}, {0x89c1,    0x00f6},
-{0x89c2,    0x008f}, {0x89c3,    0x0080}, {0x89c4,    0x0005},
-{0x89c5,    0x0005}, {0x89c6,    0x00f7}, {0x89c7,    0x008f},
-{0x89c8,    0x0080}, {0x89c9,    0x00f6}, {0x89ca,    0x008f},
-{0x89cb,    0x0080}, {0x89cc,    0x0053}, {0x89cd,    0x00f4},
-{0x89ce,    0x0012}, {0x89cf,    0x0007}, {0x89d0,    0x001b},
-{0x89d1,    0x00b7}, {0x89d2,    0x0012}, {0x89d3,    0x0007},
-{0x89d4,    0x0039}, {0x89d5,    0x00ce}, {0x89d6,    0x008f},
-{0x89d7,    0x0070}, {0x89d8,    0x00a6}, {0x89d9,    0x0000},
-{0x89da,    0x0018}, {0x89db,    0x00e6}, {0x89dc,    0x0000},
-{0x89dd,    0x0018}, {0x89de,    0x00a7}, {0x89df,    0x0000},
-{0x89e0,    0x00e7}, {0x89e1,    0x0000}, {0x89e2,    0x00a6},
-{0x89e3,    0x0001}, {0x89e4,    0x0018}, {0x89e5,    0x00e6},
-{0x89e6,    0x0001}, {0x89e7,    0x0018}, {0x89e8,    0x00a7},
-{0x89e9,    0x0001}, {0x89ea,    0x00e7}, {0x89eb,    0x0001},
-{0x89ec,    0x00a6}, {0x89ed,    0x0002}, {0x89ee,    0x0018},
-{0x89ef,    0x00e6}, {0x89f0,    0x0002}, {0x89f1,    0x0018},
-{0x89f2,    0x00a7}, {0x89f3,    0x0002}, {0x89f4,    0x00e7},
-{0x89f5,    0x0002}, {0x89f6,    0x0039}, {0x89f7,    0x00a6},
-{0x89f8,    0x0000}, {0x89f9,    0x0084}, {0x89fa,    0x0007},
-{0x89fb,    0x00e6}, {0x89fc,    0x0000}, {0x89fd,    0x00c4},
-{0x89fe,    0x0038}, {0x89ff,    0x0054}, {0x8a00,    0x0054},
-{0x8a01,    0x0054}, {0x8a02,    0x001b}, {0x8a03,    0x00a7},
-{0x8a04,    0x0000}, {0x8a05,    0x0039}, {0x8a06,    0x004a},
-{0x8a07,    0x0026}, {0x8a08,    0x00fd}, {0x8a09,    0x0039},
-{0x8a0a,    0x0096}, {0x8a0b,    0x0022}, {0x8a0c,    0x0084},
-{0x8a0d,    0x000f}, {0x8a0e,    0x0097}, {0x8a0f,    0x0022},
-{0x8a10,    0x0086}, {0x8a11,    0x0001}, {0x8a12,    0x00b7},
-{0x8a13,    0x008f}, {0x8a14,    0x0070}, {0x8a15,    0x00b6},
-{0x8a16,    0x0012}, {0x8a17,    0x0007}, {0x8a18,    0x00b7},
-{0x8a19,    0x008f}, {0x8a1a,    0x0071}, {0x8a1b,    0x00f6},
-{0x8a1c,    0x0012}, {0x8a1d,    0x000c}, {0x8a1e,    0x00c4},
-{0x8a1f,    0x000f}, {0x8a20,    0x00c8}, {0x8a21,    0x000f},
-{0x8a22,    0x00f7}, {0x8a23,    0x008f}, {0x8a24,    0x0072},
-{0x8a25,    0x00f6}, {0x8a26,    0x008f}, {0x8a27,    0x0072},
-{0x8a28,    0x00b6}, {0x8a29,    0x008f}, {0x8a2a,    0x0071},
-{0x8a2b,    0x0084}, {0x8a2c,    0x0003}, {0x8a2d,    0x0027},
-{0x8a2e,    0x0014}, {0x8a2f,    0x0081}, {0x8a30,    0x0001},
-{0x8a31,    0x0027}, {0x8a32,    0x001c}, {0x8a33,    0x0081},
-{0x8a34,    0x0002}, {0x8a35,    0x0027}, {0x8a36,    0x0024},
-{0x8a37,    0x00f4}, {0x8a38,    0x008f}, {0x8a39,    0x0070},
-{0x8a3a,    0x0027}, {0x8a3b,    0x002a}, {0x8a3c,    0x0096},
-{0x8a3d,    0x0022}, {0x8a3e,    0x008a}, {0x8a3f,    0x0080},
-{0x8a40,    0x007e}, {0x8a41,    0x008a}, {0x8a42,    0x0064},
-{0x8a43,    0x00f4}, {0x8a44,    0x008f}, {0x8a45,    0x0070},
-{0x8a46,    0x0027}, {0x8a47,    0x001e}, {0x8a48,    0x0096},
-{0x8a49,    0x0022}, {0x8a4a,    0x008a}, {0x8a4b,    0x0010},
-{0x8a4c,    0x007e}, {0x8a4d,    0x008a}, {0x8a4e,    0x0064},
-{0x8a4f,    0x00f4}, {0x8a50,    0x008f}, {0x8a51,    0x0070},
-{0x8a52,    0x0027}, {0x8a53,    0x0012}, {0x8a54,    0x0096},
-{0x8a55,    0x0022}, {0x8a56,    0x008a}, {0x8a57,    0x0020},
-{0x8a58,    0x007e}, {0x8a59,    0x008a}, {0x8a5a,    0x0064},
-{0x8a5b,    0x00f4}, {0x8a5c,    0x008f}, {0x8a5d,    0x0070},
-{0x8a5e,    0x0027}, {0x8a5f,    0x0006}, {0x8a60,    0x0096},
-{0x8a61,    0x0022}, {0x8a62,    0x008a}, {0x8a63,    0x0040},
-{0x8a64,    0x0097}, {0x8a65,    0x0022}, {0x8a66,    0x0074},
-{0x8a67,    0x008f}, {0x8a68,    0x0071}, {0x8a69,    0x0074},
-{0x8a6a,    0x008f}, {0x8a6b,    0x0071}, {0x8a6c,    0x0078},
-{0x8a6d,    0x008f}, {0x8a6e,    0x0070}, {0x8a6f,    0x00b6},
-{0x8a70,    0x008f}, {0x8a71,    0x0070}, {0x8a72,    0x0085},
-{0x8a73,    0x0010}, {0x8a74,    0x0027}, {0x8a75,    0x00af},
-{0x8a76,    0x00d6}, {0x8a77,    0x0022}, {0x8a78,    0x00c4},
-{0x8a79,    0x0010}, {0x8a7a,    0x0058}, {0x8a7b,    0x00b6},
-{0x8a7c,    0x0012}, {0x8a7d,    0x0070}, {0x8a7e,    0x0081},
-{0x8a7f,    0x00e4}, {0x8a80,    0x0027}, {0x8a81,    0x0036},
-{0x8a82,    0x0081}, {0x8a83,    0x00e1}, {0x8a84,    0x0026},
-{0x8a85,    0x000c}, {0x8a86,    0x0096}, {0x8a87,    0x0022},
-{0x8a88,    0x0084}, {0x8a89,    0x0020}, {0x8a8a,    0x0044},
-{0x8a8b,    0x001b}, {0x8a8c,    0x00d6}, {0x8a8d,    0x0022},
-{0x8a8e,    0x00c4}, {0x8a8f,    0x00cf}, {0x8a90,    0x0020},
-{0x8a91,    0x0023}, {0x8a92,    0x0058}, {0x8a93,    0x0081},
-{0x8a94,    0x00c6}, {0x8a95,    0x0026}, {0x8a96,    0x000d},
-{0x8a97,    0x0096}, {0x8a98,    0x0022}, {0x8a99,    0x0084},
-{0x8a9a,    0x0040}, {0x8a9b,    0x0044}, {0x8a9c,    0x0044},
-{0x8a9d,    0x001b}, {0x8a9e,    0x00d6}, {0x8a9f,    0x0022},
-{0x8aa0,    0x00c4}, {0x8aa1,    0x00af}, {0x8aa2,    0x0020},
-{0x8aa3,    0x0011}, {0x8aa4,    0x0058}, {0x8aa5,    0x0081},
-{0x8aa6,    0x0027}, {0x8aa7,    0x0026}, {0x8aa8,    0x000f},
-{0x8aa9,    0x0096}, {0x8aaa,    0x0022}, {0x8aab,    0x0084},
-{0x8aac,    0x0080}, {0x8aad,    0x0044}, {0x8aae,    0x0044},
-{0x8aaf,    0x0044}, {0x8ab0,    0x001b}, {0x8ab1,    0x00d6},
-{0x8ab2,    0x0022}, {0x8ab3,    0x00c4}, {0x8ab4,    0x006f},
-{0x8ab5,    0x001b}, {0x8ab6,    0x0097}, {0x8ab7,    0x0022},
-{0x8ab8,    0x0039}, {0x8ab9,    0x0027}, {0x8aba,    0x000c},
-{0x8abb,    0x007c}, {0x8abc,    0x0082}, {0x8abd,    0x0006},
-{0x8abe,    0x00bd}, {0x8abf,    0x00d9}, {0x8ac0,    0x00ed},
-{0x8ac1,    0x00b6}, {0x8ac2,    0x0082}, {0x8ac3,    0x0007},
-{0x8ac4,    0x007e}, {0x8ac5,    0x008a}, {0x8ac6,    0x00b9},
-{0x8ac7,    0x007f}, {0x8ac8,    0x0082}, {0x8ac9,    0x0006},
-{0x8aca,    0x0039}, { 0x0, 0x0 }
-};
-#endif
-
-
 /* phy types */
 #define   CAS_PHY_UNKNOWN       0x00
 #define   CAS_PHY_SERDES        0x01
@@ -4389,6 +2872,11 @@
 	dma_addr_t block_dvma, tx_tiny_dvma[N_TX_RINGS];
 	struct pci_dev *pdev;
 	struct net_device *dev;
+
+	/* Firmware Info */
+	u16			fw_load_addr;
+	u32			fw_size;
+	u8			*fw_data;
 };
 
 #define TX_DESC_NEXT(r, x)  (((x) + 1) & (TX_DESC_RINGN_SIZE(r) - 1))
diff --git a/drivers/net/cpmac.c b/drivers/net/cpmac.c
index ec6b0af..017a536 100644
--- a/drivers/net/cpmac.c
+++ b/drivers/net/cpmac.c
@@ -302,13 +302,7 @@
 
 static int mii_irqs[PHY_MAX_ADDR] = { PHY_POLL, };
 
-static struct mii_bus cpmac_mii = {
-	.name = "cpmac-mii",
-	.read = cpmac_mdio_read,
-	.write = cpmac_mdio_write,
-	.reset = cpmac_mdio_reset,
-	.irq = mii_irqs,
-};
+static struct mii_bus *cpmac_mii;
 
 static int cpmac_config(struct net_device *dev, struct ifmap *map)
 {
@@ -1116,7 +1110,7 @@
 	for (phy_id = 0; phy_id < PHY_MAX_ADDR; phy_id++) {
 		if (!(pdata->phy_mask & (1 << phy_id)))
 			continue;
-		if (!cpmac_mii.phy_map[phy_id])
+		if (!cpmac_mii->phy_map[phy_id])
 			continue;
 		break;
 	}
@@ -1168,7 +1162,7 @@
 	priv->msg_enable = netif_msg_init(debug_level, 0xff);
 	memcpy(dev->dev_addr, pdata->dev_addr, sizeof(dev->dev_addr));
 
-	priv->phy = phy_connect(dev, cpmac_mii.phy_map[phy_id]->dev.bus_id,
+	priv->phy = phy_connect(dev, cpmac_mii->phy_map[phy_id]->dev.bus_id,
 				&cpmac_adjust_link, 0, PHY_INTERFACE_MODE_MII);
 	if (IS_ERR(priv->phy)) {
 		if (netif_msg_drv(priv))
@@ -1216,11 +1210,22 @@
 	u32 mask;
 	int i, res;
 
-	cpmac_mii.priv = ioremap(AR7_REGS_MDIO, 256);
+	cpmac_mii = mdiobus_alloc();
+	if (cpmac_mii == NULL)
+		return -ENOMEM;
 
-	if (!cpmac_mii.priv) {
+	cpmac_mii->name = "cpmac-mii";
+	cpmac_mii->read = cpmac_mdio_read;
+	cpmac_mii->write = cpmac_mdio_write;
+	cpmac_mii->reset = cpmac_mdio_reset;
+	cpmac_mii->irq = mii_irqs;
+
+	cpmac_mii->priv = ioremap(AR7_REGS_MDIO, 256);
+
+	if (!cpmac_mii->priv) {
 		printk(KERN_ERR "Can't ioremap mdio registers\n");
-		return -ENXIO;
+		res = -ENXIO;
+		goto fail_alloc;
 	}
 
 #warning FIXME: unhardcode gpio&reset bits
@@ -1230,10 +1235,10 @@
 	ar7_device_reset(AR7_RESET_BIT_CPMAC_HI);
 	ar7_device_reset(AR7_RESET_BIT_EPHY);
 
-	cpmac_mii.reset(&cpmac_mii);
+	cpmac_mii->reset(cpmac_mii);
 
 	for (i = 0; i < 300000; i++)
-		if ((mask = cpmac_read(cpmac_mii.priv, CPMAC_MDIO_ALIVE)))
+		if ((mask = cpmac_read(cpmac_mii->priv, CPMAC_MDIO_ALIVE)))
 			break;
 		else
 			cpu_relax();
@@ -1244,10 +1249,10 @@
 		mask = 0;
 	}
 
-	cpmac_mii.phy_mask = ~(mask | 0x80000000);
-	snprintf(cpmac_mii.id, MII_BUS_ID_SIZE, "0");
+	cpmac_mii->phy_mask = ~(mask | 0x80000000);
+	snprintf(cpmac_mii->id, MII_BUS_ID_SIZE, "0");
 
-	res = mdiobus_register(&cpmac_mii);
+	res = mdiobus_register(cpmac_mii);
 	if (res)
 		goto fail_mii;
 
@@ -1258,10 +1263,13 @@
 	return 0;
 
 fail_cpmac:
-	mdiobus_unregister(&cpmac_mii);
+	mdiobus_unregister(cpmac_mii);
 
 fail_mii:
-	iounmap(cpmac_mii.priv);
+	iounmap(cpmac_mii->priv);
+
+fail_alloc:
+	mdiobus_free(cpmac_mii);
 
 	return res;
 }
@@ -1269,8 +1277,9 @@
 void __devexit cpmac_exit(void)
 {
 	platform_driver_unregister(&cpmac_driver);
-	mdiobus_unregister(&cpmac_mii);
-	iounmap(cpmac_mii.priv);
+	mdiobus_unregister(cpmac_mii);
+	mdiobus_free(cpmac_mii);
+	iounmap(cpmac_mii->priv);
 }
 
 module_init(cpmac_init);
diff --git a/drivers/net/cs89x0.c b/drivers/net/cs89x0.c
index ea6144a..a28de81 100644
--- a/drivers/net/cs89x0.c
+++ b/drivers/net/cs89x0.c
@@ -194,6 +194,12 @@
 #define CIRRUS_DEFAULT_IRQ	VH_INTC_INT_NUM_CASCADED_INTERRUPT_1 /* Event inputs bank 1 - ID 35/bit 3 */
 static unsigned int netcard_portlist[] __used __initdata = {CIRRUS_DEFAULT_BASE, 0};
 static unsigned int cs8900_irq_map[] = {CIRRUS_DEFAULT_IRQ, 0, 0, 0};
+#elif defined(CONFIG_MACH_MX31ADS)
+#include <mach/board-mx31ads.h>
+static unsigned int netcard_portlist[] __used __initdata = {
+	PBC_BASE_ADDRESS + PBC_CS8900A_IOBASE + 0x300, 0
+};
+static unsigned cs8900_irq_map[] = {EXPIO_INT_ENET_INT, 0, 0, 0};
 #else
 static unsigned int netcard_portlist[] __used __initdata =
    { 0x300, 0x320, 0x340, 0x360, 0x200, 0x220, 0x240, 0x260, 0x280, 0x2a0, 0x2c0, 0x2e0, 0};
@@ -802,7 +808,7 @@
 	} else {
 		i = lp->isa_config & INT_NO_MASK;
 		if (lp->chip_type == CS8900) {
-#if defined(CONFIG_MACH_IXDP2351) || defined(CONFIG_ARCH_IXDP2X01) || defined(CONFIG_ARCH_PNX010X)
+#ifdef CONFIG_CS89x0_NONISA_IRQ
 		        i = cs8900_irq_map[0];
 #else
 			/* Translate the IRQ using the IRQ mapping table. */
@@ -1029,6 +1035,7 @@
 
 void  __init reset_chip(struct net_device *dev)
 {
+#if !defined(CONFIG_MACH_MX31ADS)
 #if !defined(CONFIG_MACH_IXDP2351) && !defined(CONFIG_ARCH_IXDP2X01)
 	struct net_local *lp = netdev_priv(dev);
 	int ioaddr = dev->base_addr;
@@ -1057,6 +1064,7 @@
 	reset_start_time = jiffies;
 	while( (readreg(dev, PP_SelfST) & INIT_DONE) == 0 && jiffies - reset_start_time < 2)
 		;
+#endif /* !CONFIG_MACH_MX31ADS */
 }
 
 
@@ -1304,7 +1312,7 @@
 	else
 #endif
 	{
-#if !defined(CONFIG_MACH_IXDP2351) && !defined(CONFIG_ARCH_IXDP2X01) && !defined(CONFIG_ARCH_PNX010X)
+#ifndef CONFIG_CS89x0_NONISA_IRQ
 		if (((1 << dev->irq) & lp->irq_map) == 0) {
 			printk(KERN_ERR "%s: IRQ %d is not in our map of allowable IRQs, which is %x\n",
                                dev->name, dev->irq, lp->irq_map);
@@ -1397,9 +1405,7 @@
 release_dma:
 #if ALLOW_DMA
 		free_dma(dev->dma);
-#endif
 release_irq:
-#if ALLOW_DMA
 		release_dma_buff(lp);
 #endif
                 writereg(dev, PP_LineCTL, readreg(dev, PP_LineCTL) & ~(SERIAL_TX_ON | SERIAL_RX_ON));
diff --git a/drivers/net/cxgb3/adapter.h b/drivers/net/cxgb3/adapter.h
index 2711404..bc8e241 100644
--- a/drivers/net/cxgb3/adapter.h
+++ b/drivers/net/cxgb3/adapter.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003-2007 Chelsio, Inc. All rights reserved.
+ * Copyright (c) 2003-2008 Chelsio, Inc. All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
@@ -54,7 +54,6 @@
 	struct adapter *adapter;
 	struct vlan_group *vlan_grp;
 	struct sge_qset *qs;
-	const struct port_type_info *port_type;
 	u8 port_id;
 	u8 rx_csum_offload;
 	u8 nqsets;
@@ -124,8 +123,7 @@
 	dma_addr_t phys_addr;	/* physical address of the ring */
 	unsigned int cntxt_id;	/* SGE context id for the response q */
 	spinlock_t lock;	/* guards response processing */
-	struct sk_buff *rx_head;	/* offload packet receive queue head */
-	struct sk_buff *rx_tail;	/* offload packet receive queue tail */
+	struct sk_buff_head rx_queue; /* offload packet receive queue */
 	struct sk_buff *pg_skb; /* used to build frag list in napi handler */
 
 	unsigned long offload_pkts;
@@ -241,6 +239,7 @@
 	unsigned int check_task_cnt;
 	struct delayed_work adap_check_task;
 	struct work_struct ext_intr_handler_task;
+	struct work_struct fatal_error_handler_task;
 
 	struct dentry *debugfs_root;
 
@@ -282,9 +281,11 @@
 void t3_os_ext_intr_handler(struct adapter *adapter);
 void t3_os_link_changed(struct adapter *adapter, int port_id, int link_status,
 			int speed, int duplex, int fc);
+void t3_os_phymod_changed(struct adapter *adap, int port_id);
 
 void t3_sge_start(struct adapter *adap);
 void t3_sge_stop(struct adapter *adap);
+void t3_stop_sge_timers(struct adapter *adap);
 void t3_free_sge_resources(struct adapter *adap);
 void t3_sge_err_intr_handler(struct adapter *adapter);
 irq_handler_t t3_intr_handler(struct adapter *adap, int polling);
diff --git a/drivers/net/cxgb3/ael1002.c b/drivers/net/cxgb3/ael1002.c
index ee140e6..5c3c05d 100644
--- a/drivers/net/cxgb3/ael1002.c
+++ b/drivers/net/cxgb3/ael1002.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005-2007 Chelsio, Inc. All rights reserved.
+ * Copyright (c) 2005-2008 Chelsio, Inc. All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
@@ -33,17 +33,57 @@
 #include "regs.h"
 
 enum {
+	PMD_RSD     = 10,   /* PMA/PMD receive signal detect register */
+	PCS_STAT1_X = 24,   /* 10GBASE-X PCS status 1 register */
+	PCS_STAT1_R = 32,   /* 10GBASE-R PCS status 1 register */
+	XS_LN_STAT  = 24    /* XS lane status register */
+};
+
+enum {
 	AEL100X_TX_DISABLE = 9,
 	AEL100X_TX_CONFIG1 = 0xc002,
 	AEL1002_PWR_DOWN_HI = 0xc011,
 	AEL1002_PWR_DOWN_LO = 0xc012,
 	AEL1002_XFI_EQL = 0xc015,
 	AEL1002_LB_EN = 0xc017,
-
-	LASI_CTRL = 0x9002,
-	LASI_STAT = 0x9005
+	AEL_OPT_SETTINGS = 0xc017,
+	AEL_I2C_CTRL = 0xc30a,
+	AEL_I2C_DATA = 0xc30b,
+	AEL_I2C_STAT = 0xc30c,
+	AEL2005_GPIO_CTRL = 0xc214,
+	AEL2005_GPIO_STAT = 0xc215,
 };
 
+enum { edc_none, edc_sr, edc_twinax };
+
+/* PHY module I2C device address */
+#define MODULE_DEV_ADDR 0xa0
+
+#define AEL2005_MODDET_IRQ 4
+
+struct reg_val {
+	unsigned short mmd_addr;
+	unsigned short reg_addr;
+	unsigned short clear_bits;
+	unsigned short set_bits;
+};
+
+static int set_phy_regs(struct cphy *phy, const struct reg_val *rv)
+{
+	int err;
+
+	for (err = 0; rv->mmd_addr && !err; rv++) {
+		if (rv->clear_bits == 0xffff)
+			err = mdio_write(phy, rv->mmd_addr, rv->reg_addr,
+					 rv->set_bits);
+		else
+			err = t3_mdio_change_bits(phy, rv->mmd_addr,
+						  rv->reg_addr, rv->clear_bits,
+						  rv->set_bits);
+	}
+	return err;
+}
+
 static void ael100x_txon(struct cphy *phy)
 {
 	int tx_on_gpio = phy->addr == 0 ? F_GPIO7_OUT_VAL : F_GPIO2_OUT_VAL;
@@ -84,23 +124,23 @@
 	return 0;
 }
 
-static int ael100x_get_link_status(struct cphy *phy, int *link_ok,
-				   int *speed, int *duplex, int *fc)
+/*
+ * Get link status for a 10GBASE-R device.
+ */
+static int get_link_status_r(struct cphy *phy, int *link_ok, int *speed,
+			     int *duplex, int *fc)
 {
 	if (link_ok) {
-		unsigned int status;
-		int err = mdio_read(phy, MDIO_DEV_PMA_PMD, MII_BMSR, &status);
+		unsigned int stat0, stat1, stat2;
+		int err = mdio_read(phy, MDIO_DEV_PMA_PMD, PMD_RSD, &stat0);
 
-		/*
-		 * BMSR_LSTATUS is latch-low, so if it is 0 we need to read it
-		 * once more to get the current link state.
-		 */
-		if (!err && !(status & BMSR_LSTATUS))
-			err = mdio_read(phy, MDIO_DEV_PMA_PMD, MII_BMSR,
-					&status);
+		if (!err)
+			err = mdio_read(phy, MDIO_DEV_PCS, PCS_STAT1_R, &stat1);
+		if (!err)
+			err = mdio_read(phy, MDIO_DEV_XGXS, XS_LN_STAT, &stat2);
 		if (err)
 			return err;
-		*link_ok = !!(status & BMSR_LSTATUS);
+		*link_ok = (stat0 & stat1 & (stat2 >> 12)) & 1;
 	}
 	if (speed)
 		*speed = SPEED_10000;
@@ -115,15 +155,18 @@
 	.intr_disable = ael1002_intr_noop,
 	.intr_clear = ael1002_intr_noop,
 	.intr_handler = ael1002_intr_noop,
-	.get_link_status = ael100x_get_link_status,
+	.get_link_status = get_link_status_r,
 	.power_down = ael1002_power_down,
 };
 
-void t3_ael1002_phy_prep(struct cphy *phy, struct adapter *adapter,
-			 int phy_addr, const struct mdio_ops *mdio_ops)
+int t3_ael1002_phy_prep(struct cphy *phy, struct adapter *adapter,
+			int phy_addr, const struct mdio_ops *mdio_ops)
 {
-	cphy_init(phy, adapter, phy_addr, &ael1002_ops, mdio_ops);
+	cphy_init(phy, adapter, phy_addr, &ael1002_ops, mdio_ops,
+		  SUPPORTED_10000baseT_Full | SUPPORTED_AUI | SUPPORTED_FIBRE,
+		   "10GBASE-R");
 	ael100x_txon(phy);
+	return 0;
 }
 
 static int ael1006_reset(struct cphy *phy, int wait)
@@ -131,33 +174,6 @@
 	return t3_phy_reset(phy, MDIO_DEV_PMA_PMD, wait);
 }
 
-static int ael1006_intr_enable(struct cphy *phy)
-{
-	return mdio_write(phy, MDIO_DEV_PMA_PMD, LASI_CTRL, 1);
-}
-
-static int ael1006_intr_disable(struct cphy *phy)
-{
-	return mdio_write(phy, MDIO_DEV_PMA_PMD, LASI_CTRL, 0);
-}
-
-static int ael1006_intr_clear(struct cphy *phy)
-{
-	u32 val;
-
-	return mdio_read(phy, MDIO_DEV_PMA_PMD, LASI_STAT, &val);
-}
-
-static int ael1006_intr_handler(struct cphy *phy)
-{
-	unsigned int status;
-	int err = mdio_read(phy, MDIO_DEV_PMA_PMD, LASI_STAT, &status);
-
-	if (err)
-		return err;
-	return (status & 1) ? cphy_cause_link_change : 0;
-}
-
 static int ael1006_power_down(struct cphy *phy, int enable)
 {
 	return t3_mdio_change_bits(phy, MDIO_DEV_PMA_PMD, MII_BMCR,
@@ -166,37 +182,977 @@
 
 static struct cphy_ops ael1006_ops = {
 	.reset = ael1006_reset,
-	.intr_enable = ael1006_intr_enable,
-	.intr_disable = ael1006_intr_disable,
-	.intr_clear = ael1006_intr_clear,
-	.intr_handler = ael1006_intr_handler,
-	.get_link_status = ael100x_get_link_status,
+	.intr_enable = t3_phy_lasi_intr_enable,
+	.intr_disable = t3_phy_lasi_intr_disable,
+	.intr_clear = t3_phy_lasi_intr_clear,
+	.intr_handler = t3_phy_lasi_intr_handler,
+	.get_link_status = get_link_status_r,
 	.power_down = ael1006_power_down,
 };
 
-void t3_ael1006_phy_prep(struct cphy *phy, struct adapter *adapter,
-			 int phy_addr, const struct mdio_ops *mdio_ops)
+int t3_ael1006_phy_prep(struct cphy *phy, struct adapter *adapter,
+			     int phy_addr, const struct mdio_ops *mdio_ops)
 {
-	cphy_init(phy, adapter, phy_addr, &ael1006_ops, mdio_ops);
+	cphy_init(phy, adapter, phy_addr, &ael1006_ops, mdio_ops,
+		  SUPPORTED_10000baseT_Full | SUPPORTED_AUI | SUPPORTED_FIBRE,
+		   "10GBASE-SR");
 	ael100x_txon(phy);
+	return 0;
+}
+
+static int ael2005_setup_sr_edc(struct cphy *phy)
+{
+	static struct reg_val regs[] = {
+		{ MDIO_DEV_PMA_PMD, 0xc003, 0xffff, 0x181 },
+		{ MDIO_DEV_PMA_PMD, 0xc010, 0xffff, 0x448a },
+		{ MDIO_DEV_PMA_PMD, 0xc04a, 0xffff, 0x5200 },
+		{ 0, 0, 0, 0 }
+	};
+	static u16 sr_edc[] = {
+		0xcc00, 0x2ff4,
+		0xcc01, 0x3cd4,
+		0xcc02, 0x2015,
+		0xcc03, 0x3105,
+		0xcc04, 0x6524,
+		0xcc05, 0x27ff,
+		0xcc06, 0x300f,
+		0xcc07, 0x2c8b,
+		0xcc08, 0x300b,
+		0xcc09, 0x4009,
+		0xcc0a, 0x400e,
+		0xcc0b, 0x2f72,
+		0xcc0c, 0x3002,
+		0xcc0d, 0x1002,
+		0xcc0e, 0x2172,
+		0xcc0f, 0x3012,
+		0xcc10, 0x1002,
+		0xcc11, 0x25d2,
+		0xcc12, 0x3012,
+		0xcc13, 0x1002,
+		0xcc14, 0xd01e,
+		0xcc15, 0x27d2,
+		0xcc16, 0x3012,
+		0xcc17, 0x1002,
+		0xcc18, 0x2004,
+		0xcc19, 0x3c84,
+		0xcc1a, 0x6436,
+		0xcc1b, 0x2007,
+		0xcc1c, 0x3f87,
+		0xcc1d, 0x8676,
+		0xcc1e, 0x40b7,
+		0xcc1f, 0xa746,
+		0xcc20, 0x4047,
+		0xcc21, 0x5673,
+		0xcc22, 0x2982,
+		0xcc23, 0x3002,
+		0xcc24, 0x13d2,
+		0xcc25, 0x8bbd,
+		0xcc26, 0x2862,
+		0xcc27, 0x3012,
+		0xcc28, 0x1002,
+		0xcc29, 0x2092,
+		0xcc2a, 0x3012,
+		0xcc2b, 0x1002,
+		0xcc2c, 0x5cc3,
+		0xcc2d, 0x314,
+		0xcc2e, 0x2942,
+		0xcc2f, 0x3002,
+		0xcc30, 0x1002,
+		0xcc31, 0xd019,
+		0xcc32, 0x2032,
+		0xcc33, 0x3012,
+		0xcc34, 0x1002,
+		0xcc35, 0x2a04,
+		0xcc36, 0x3c74,
+		0xcc37, 0x6435,
+		0xcc38, 0x2fa4,
+		0xcc39, 0x3cd4,
+		0xcc3a, 0x6624,
+		0xcc3b, 0x5563,
+		0xcc3c, 0x2d42,
+		0xcc3d, 0x3002,
+		0xcc3e, 0x13d2,
+		0xcc3f, 0x464d,
+		0xcc40, 0x2862,
+		0xcc41, 0x3012,
+		0xcc42, 0x1002,
+		0xcc43, 0x2032,
+		0xcc44, 0x3012,
+		0xcc45, 0x1002,
+		0xcc46, 0x2fb4,
+		0xcc47, 0x3cd4,
+		0xcc48, 0x6624,
+		0xcc49, 0x5563,
+		0xcc4a, 0x2d42,
+		0xcc4b, 0x3002,
+		0xcc4c, 0x13d2,
+		0xcc4d, 0x2ed2,
+		0xcc4e, 0x3002,
+		0xcc4f, 0x1002,
+		0xcc50, 0x2fd2,
+		0xcc51, 0x3002,
+		0xcc52, 0x1002,
+		0xcc53, 0x004,
+		0xcc54, 0x2942,
+		0xcc55, 0x3002,
+		0xcc56, 0x1002,
+		0xcc57, 0x2092,
+		0xcc58, 0x3012,
+		0xcc59, 0x1002,
+		0xcc5a, 0x5cc3,
+		0xcc5b, 0x317,
+		0xcc5c, 0x2f72,
+		0xcc5d, 0x3002,
+		0xcc5e, 0x1002,
+		0xcc5f, 0x2942,
+		0xcc60, 0x3002,
+		0xcc61, 0x1002,
+		0xcc62, 0x22cd,
+		0xcc63, 0x301d,
+		0xcc64, 0x2862,
+		0xcc65, 0x3012,
+		0xcc66, 0x1002,
+		0xcc67, 0x2ed2,
+		0xcc68, 0x3002,
+		0xcc69, 0x1002,
+		0xcc6a, 0x2d72,
+		0xcc6b, 0x3002,
+		0xcc6c, 0x1002,
+		0xcc6d, 0x628f,
+		0xcc6e, 0x2112,
+		0xcc6f, 0x3012,
+		0xcc70, 0x1002,
+		0xcc71, 0x5aa3,
+		0xcc72, 0x2dc2,
+		0xcc73, 0x3002,
+		0xcc74, 0x1312,
+		0xcc75, 0x6f72,
+		0xcc76, 0x1002,
+		0xcc77, 0x2807,
+		0xcc78, 0x31a7,
+		0xcc79, 0x20c4,
+		0xcc7a, 0x3c24,
+		0xcc7b, 0x6724,
+		0xcc7c, 0x1002,
+		0xcc7d, 0x2807,
+		0xcc7e, 0x3187,
+		0xcc7f, 0x20c4,
+		0xcc80, 0x3c24,
+		0xcc81, 0x6724,
+		0xcc82, 0x1002,
+		0xcc83, 0x2514,
+		0xcc84, 0x3c64,
+		0xcc85, 0x6436,
+		0xcc86, 0xdff4,
+		0xcc87, 0x6436,
+		0xcc88, 0x1002,
+		0xcc89, 0x40a4,
+		0xcc8a, 0x643c,
+		0xcc8b, 0x4016,
+		0xcc8c, 0x8c6c,
+		0xcc8d, 0x2b24,
+		0xcc8e, 0x3c24,
+		0xcc8f, 0x6435,
+		0xcc90, 0x1002,
+		0xcc91, 0x2b24,
+		0xcc92, 0x3c24,
+		0xcc93, 0x643a,
+		0xcc94, 0x4025,
+		0xcc95, 0x8a5a,
+		0xcc96, 0x1002,
+		0xcc97, 0x2731,
+		0xcc98, 0x3011,
+		0xcc99, 0x1001,
+		0xcc9a, 0xc7a0,
+		0xcc9b, 0x100,
+		0xcc9c, 0xc502,
+		0xcc9d, 0x53ac,
+		0xcc9e, 0xc503,
+		0xcc9f, 0xd5d5,
+		0xcca0, 0xc600,
+		0xcca1, 0x2a6d,
+		0xcca2, 0xc601,
+		0xcca3, 0x2a4c,
+		0xcca4, 0xc602,
+		0xcca5, 0x111,
+		0xcca6, 0xc60c,
+		0xcca7, 0x5900,
+		0xcca8, 0xc710,
+		0xcca9, 0x700,
+		0xccaa, 0xc718,
+		0xccab, 0x700,
+		0xccac, 0xc720,
+		0xccad, 0x4700,
+		0xccae, 0xc801,
+		0xccaf, 0x7f50,
+		0xccb0, 0xc802,
+		0xccb1, 0x7760,
+		0xccb2, 0xc803,
+		0xccb3, 0x7fce,
+		0xccb4, 0xc804,
+		0xccb5, 0x5700,
+		0xccb6, 0xc805,
+		0xccb7, 0x5f11,
+		0xccb8, 0xc806,
+		0xccb9, 0x4751,
+		0xccba, 0xc807,
+		0xccbb, 0x57e1,
+		0xccbc, 0xc808,
+		0xccbd, 0x2700,
+		0xccbe, 0xc809,
+		0xccbf, 0x000,
+		0xccc0, 0xc821,
+		0xccc1, 0x002,
+		0xccc2, 0xc822,
+		0xccc3, 0x014,
+		0xccc4, 0xc832,
+		0xccc5, 0x1186,
+		0xccc6, 0xc847,
+		0xccc7, 0x1e02,
+		0xccc8, 0xc013,
+		0xccc9, 0xf341,
+		0xccca, 0xc01a,
+		0xcccb, 0x446,
+		0xcccc, 0xc024,
+		0xcccd, 0x1000,
+		0xccce, 0xc025,
+		0xcccf, 0xa00,
+		0xccd0, 0xc026,
+		0xccd1, 0xc0c,
+		0xccd2, 0xc027,
+		0xccd3, 0xc0c,
+		0xccd4, 0xc029,
+		0xccd5, 0x0a0,
+		0xccd6, 0xc030,
+		0xccd7, 0xa00,
+		0xccd8, 0xc03c,
+		0xccd9, 0x01c,
+		0xccda, 0xc005,
+		0xccdb, 0x7a06,
+		0xccdc, 0x000,
+		0xccdd, 0x2731,
+		0xccde, 0x3011,
+		0xccdf, 0x1001,
+		0xcce0, 0xc620,
+		0xcce1, 0x000,
+		0xcce2, 0xc621,
+		0xcce3, 0x03f,
+		0xcce4, 0xc622,
+		0xcce5, 0x000,
+		0xcce6, 0xc623,
+		0xcce7, 0x000,
+		0xcce8, 0xc624,
+		0xcce9, 0x000,
+		0xccea, 0xc625,
+		0xcceb, 0x000,
+		0xccec, 0xc627,
+		0xcced, 0x000,
+		0xccee, 0xc628,
+		0xccef, 0x000,
+		0xccf0, 0xc62c,
+		0xccf1, 0x000,
+		0xccf2, 0x000,
+		0xccf3, 0x2806,
+		0xccf4, 0x3cb6,
+		0xccf5, 0xc161,
+		0xccf6, 0x6134,
+		0xccf7, 0x6135,
+		0xccf8, 0x5443,
+		0xccf9, 0x303,
+		0xccfa, 0x6524,
+		0xccfb, 0x00b,
+		0xccfc, 0x1002,
+		0xccfd, 0x2104,
+		0xccfe, 0x3c24,
+		0xccff, 0x2105,
+		0xcd00, 0x3805,
+		0xcd01, 0x6524,
+		0xcd02, 0xdff4,
+		0xcd03, 0x4005,
+		0xcd04, 0x6524,
+		0xcd05, 0x1002,
+		0xcd06, 0x5dd3,
+		0xcd07, 0x306,
+		0xcd08, 0x2ff7,
+		0xcd09, 0x38f7,
+		0xcd0a, 0x60b7,
+		0xcd0b, 0xdffd,
+		0xcd0c, 0x00a,
+		0xcd0d, 0x1002,
+		0xcd0e, 0
+	};
+	int i, err;
+
+	err = set_phy_regs(phy, regs);
+	if (err)
+		return err;
+
+	msleep(50);
+
+	for (i = 0; i < ARRAY_SIZE(sr_edc) && !err; i += 2)
+		err = mdio_write(phy, MDIO_DEV_PMA_PMD, sr_edc[i],
+				 sr_edc[i + 1]);
+	if (!err)
+		phy->priv = edc_sr;
+	return err;
+}
+
+static int ael2005_setup_twinax_edc(struct cphy *phy, int modtype)
+{
+	static struct reg_val regs[] = {
+		{ MDIO_DEV_PMA_PMD, 0xc04a, 0xffff, 0x5a00 },
+		{ 0, 0, 0, 0 }
+	};
+	static struct reg_val preemphasis[] = {
+		{ MDIO_DEV_PMA_PMD, 0xc014, 0xffff, 0xfe16 },
+		{ MDIO_DEV_PMA_PMD, 0xc015, 0xffff, 0xa000 },
+		{ 0, 0, 0, 0 }
+	};
+	static u16 twinax_edc[] = {
+		0xcc00, 0x4009,
+		0xcc01, 0x27ff,
+		0xcc02, 0x300f,
+		0xcc03, 0x40aa,
+		0xcc04, 0x401c,
+		0xcc05, 0x401e,
+		0xcc06, 0x2ff4,
+		0xcc07, 0x3cd4,
+		0xcc08, 0x2035,
+		0xcc09, 0x3145,
+		0xcc0a, 0x6524,
+		0xcc0b, 0x26a2,
+		0xcc0c, 0x3012,
+		0xcc0d, 0x1002,
+		0xcc0e, 0x29c2,
+		0xcc0f, 0x3002,
+		0xcc10, 0x1002,
+		0xcc11, 0x2072,
+		0xcc12, 0x3012,
+		0xcc13, 0x1002,
+		0xcc14, 0x22cd,
+		0xcc15, 0x301d,
+		0xcc16, 0x2e52,
+		0xcc17, 0x3012,
+		0xcc18, 0x1002,
+		0xcc19, 0x28e2,
+		0xcc1a, 0x3002,
+		0xcc1b, 0x1002,
+		0xcc1c, 0x628f,
+		0xcc1d, 0x2ac2,
+		0xcc1e, 0x3012,
+		0xcc1f, 0x1002,
+		0xcc20, 0x5553,
+		0xcc21, 0x2ae2,
+		0xcc22, 0x3002,
+		0xcc23, 0x1302,
+		0xcc24, 0x401e,
+		0xcc25, 0x2be2,
+		0xcc26, 0x3012,
+		0xcc27, 0x1002,
+		0xcc28, 0x2da2,
+		0xcc29, 0x3012,
+		0xcc2a, 0x1002,
+		0xcc2b, 0x2ba2,
+		0xcc2c, 0x3002,
+		0xcc2d, 0x1002,
+		0xcc2e, 0x5ee3,
+		0xcc2f, 0x305,
+		0xcc30, 0x400e,
+		0xcc31, 0x2bc2,
+		0xcc32, 0x3002,
+		0xcc33, 0x1002,
+		0xcc34, 0x2b82,
+		0xcc35, 0x3012,
+		0xcc36, 0x1002,
+		0xcc37, 0x5663,
+		0xcc38, 0x302,
+		0xcc39, 0x401e,
+		0xcc3a, 0x6f72,
+		0xcc3b, 0x1002,
+		0xcc3c, 0x628f,
+		0xcc3d, 0x2be2,
+		0xcc3e, 0x3012,
+		0xcc3f, 0x1002,
+		0xcc40, 0x22cd,
+		0xcc41, 0x301d,
+		0xcc42, 0x2e52,
+		0xcc43, 0x3012,
+		0xcc44, 0x1002,
+		0xcc45, 0x2522,
+		0xcc46, 0x3012,
+		0xcc47, 0x1002,
+		0xcc48, 0x2da2,
+		0xcc49, 0x3012,
+		0xcc4a, 0x1002,
+		0xcc4b, 0x2ca2,
+		0xcc4c, 0x3012,
+		0xcc4d, 0x1002,
+		0xcc4e, 0x2fa4,
+		0xcc4f, 0x3cd4,
+		0xcc50, 0x6624,
+		0xcc51, 0x410b,
+		0xcc52, 0x56b3,
+		0xcc53, 0x3c4,
+		0xcc54, 0x2fb2,
+		0xcc55, 0x3002,
+		0xcc56, 0x1002,
+		0xcc57, 0x220b,
+		0xcc58, 0x303b,
+		0xcc59, 0x56b3,
+		0xcc5a, 0x3c3,
+		0xcc5b, 0x866b,
+		0xcc5c, 0x400c,
+		0xcc5d, 0x23a2,
+		0xcc5e, 0x3012,
+		0xcc5f, 0x1002,
+		0xcc60, 0x2da2,
+		0xcc61, 0x3012,
+		0xcc62, 0x1002,
+		0xcc63, 0x2ca2,
+		0xcc64, 0x3012,
+		0xcc65, 0x1002,
+		0xcc66, 0x2fb4,
+		0xcc67, 0x3cd4,
+		0xcc68, 0x6624,
+		0xcc69, 0x56b3,
+		0xcc6a, 0x3c3,
+		0xcc6b, 0x866b,
+		0xcc6c, 0x401c,
+		0xcc6d, 0x2205,
+		0xcc6e, 0x3035,
+		0xcc6f, 0x5b53,
+		0xcc70, 0x2c52,
+		0xcc71, 0x3002,
+		0xcc72, 0x13c2,
+		0xcc73, 0x5cc3,
+		0xcc74, 0x317,
+		0xcc75, 0x2522,
+		0xcc76, 0x3012,
+		0xcc77, 0x1002,
+		0xcc78, 0x2da2,
+		0xcc79, 0x3012,
+		0xcc7a, 0x1002,
+		0xcc7b, 0x2b82,
+		0xcc7c, 0x3012,
+		0xcc7d, 0x1002,
+		0xcc7e, 0x5663,
+		0xcc7f, 0x303,
+		0xcc80, 0x401e,
+		0xcc81, 0x004,
+		0xcc82, 0x2c42,
+		0xcc83, 0x3012,
+		0xcc84, 0x1002,
+		0xcc85, 0x6f72,
+		0xcc86, 0x1002,
+		0xcc87, 0x628f,
+		0xcc88, 0x2304,
+		0xcc89, 0x3c84,
+		0xcc8a, 0x6436,
+		0xcc8b, 0xdff4,
+		0xcc8c, 0x6436,
+		0xcc8d, 0x2ff5,
+		0xcc8e, 0x3005,
+		0xcc8f, 0x8656,
+		0xcc90, 0xdfba,
+		0xcc91, 0x56a3,
+		0xcc92, 0xd05a,
+		0xcc93, 0x21c2,
+		0xcc94, 0x3012,
+		0xcc95, 0x1392,
+		0xcc96, 0xd05a,
+		0xcc97, 0x56a3,
+		0xcc98, 0xdfba,
+		0xcc99, 0x383,
+		0xcc9a, 0x6f72,
+		0xcc9b, 0x1002,
+		0xcc9c, 0x28c5,
+		0xcc9d, 0x3005,
+		0xcc9e, 0x4178,
+		0xcc9f, 0x5653,
+		0xcca0, 0x384,
+		0xcca1, 0x22b2,
+		0xcca2, 0x3012,
+		0xcca3, 0x1002,
+		0xcca4, 0x2be5,
+		0xcca5, 0x3005,
+		0xcca6, 0x41e8,
+		0xcca7, 0x5653,
+		0xcca8, 0x382,
+		0xcca9, 0x002,
+		0xccaa, 0x4258,
+		0xccab, 0x2474,
+		0xccac, 0x3c84,
+		0xccad, 0x6437,
+		0xccae, 0xdff4,
+		0xccaf, 0x6437,
+		0xccb0, 0x2ff5,
+		0xccb1, 0x3c05,
+		0xccb2, 0x8757,
+		0xccb3, 0xb888,
+		0xccb4, 0x9787,
+		0xccb5, 0xdff4,
+		0xccb6, 0x6724,
+		0xccb7, 0x866a,
+		0xccb8, 0x6f72,
+		0xccb9, 0x1002,
+		0xccba, 0x2d01,
+		0xccbb, 0x3011,
+		0xccbc, 0x1001,
+		0xccbd, 0xc620,
+		0xccbe, 0x14e5,
+		0xccbf, 0xc621,
+		0xccc0, 0xc53d,
+		0xccc1, 0xc622,
+		0xccc2, 0x3cbe,
+		0xccc3, 0xc623,
+		0xccc4, 0x4452,
+		0xccc5, 0xc624,
+		0xccc6, 0xc5c5,
+		0xccc7, 0xc625,
+		0xccc8, 0xe01e,
+		0xccc9, 0xc627,
+		0xccca, 0x000,
+		0xcccb, 0xc628,
+		0xcccc, 0x000,
+		0xcccd, 0xc62b,
+		0xccce, 0x000,
+		0xcccf, 0xc62c,
+		0xccd0, 0x000,
+		0xccd1, 0x000,
+		0xccd2, 0x2d01,
+		0xccd3, 0x3011,
+		0xccd4, 0x1001,
+		0xccd5, 0xc620,
+		0xccd6, 0x000,
+		0xccd7, 0xc621,
+		0xccd8, 0x000,
+		0xccd9, 0xc622,
+		0xccda, 0x0ce,
+		0xccdb, 0xc623,
+		0xccdc, 0x07f,
+		0xccdd, 0xc624,
+		0xccde, 0x032,
+		0xccdf, 0xc625,
+		0xcce0, 0x000,
+		0xcce1, 0xc627,
+		0xcce2, 0x000,
+		0xcce3, 0xc628,
+		0xcce4, 0x000,
+		0xcce5, 0xc62b,
+		0xcce6, 0x000,
+		0xcce7, 0xc62c,
+		0xcce8, 0x000,
+		0xcce9, 0x000,
+		0xccea, 0x2d01,
+		0xcceb, 0x3011,
+		0xccec, 0x1001,
+		0xcced, 0xc502,
+		0xccee, 0x609f,
+		0xccef, 0xc600,
+		0xccf0, 0x2a6e,
+		0xccf1, 0xc601,
+		0xccf2, 0x2a2c,
+		0xccf3, 0xc60c,
+		0xccf4, 0x5400,
+		0xccf5, 0xc710,
+		0xccf6, 0x700,
+		0xccf7, 0xc718,
+		0xccf8, 0x700,
+		0xccf9, 0xc720,
+		0xccfa, 0x4700,
+		0xccfb, 0xc728,
+		0xccfc, 0x700,
+		0xccfd, 0xc729,
+		0xccfe, 0x1207,
+		0xccff, 0xc801,
+		0xcd00, 0x7f50,
+		0xcd01, 0xc802,
+		0xcd02, 0x7760,
+		0xcd03, 0xc803,
+		0xcd04, 0x7fce,
+		0xcd05, 0xc804,
+		0xcd06, 0x520e,
+		0xcd07, 0xc805,
+		0xcd08, 0x5c11,
+		0xcd09, 0xc806,
+		0xcd0a, 0x3c51,
+		0xcd0b, 0xc807,
+		0xcd0c, 0x4061,
+		0xcd0d, 0xc808,
+		0xcd0e, 0x49c1,
+		0xcd0f, 0xc809,
+		0xcd10, 0x3840,
+		0xcd11, 0xc80a,
+		0xcd12, 0x000,
+		0xcd13, 0xc821,
+		0xcd14, 0x002,
+		0xcd15, 0xc822,
+		0xcd16, 0x046,
+		0xcd17, 0xc844,
+		0xcd18, 0x182f,
+		0xcd19, 0xc013,
+		0xcd1a, 0xf341,
+		0xcd1b, 0xc01a,
+		0xcd1c, 0x446,
+		0xcd1d, 0xc024,
+		0xcd1e, 0x1000,
+		0xcd1f, 0xc025,
+		0xcd20, 0xa00,
+		0xcd21, 0xc026,
+		0xcd22, 0xc0c,
+		0xcd23, 0xc027,
+		0xcd24, 0xc0c,
+		0xcd25, 0xc029,
+		0xcd26, 0x0a0,
+		0xcd27, 0xc030,
+		0xcd28, 0xa00,
+		0xcd29, 0xc03c,
+		0xcd2a, 0x01c,
+		0xcd2b, 0x000,
+		0xcd2c, 0x2b84,
+		0xcd2d, 0x3c74,
+		0xcd2e, 0x6435,
+		0xcd2f, 0xdff4,
+		0xcd30, 0x6435,
+		0xcd31, 0x2806,
+		0xcd32, 0x3006,
+		0xcd33, 0x8565,
+		0xcd34, 0x2b24,
+		0xcd35, 0x3c24,
+		0xcd36, 0x6436,
+		0xcd37, 0x1002,
+		0xcd38, 0x2b24,
+		0xcd39, 0x3c24,
+		0xcd3a, 0x6436,
+		0xcd3b, 0x4045,
+		0xcd3c, 0x8656,
+		0xcd3d, 0x1002,
+		0xcd3e, 0x2807,
+		0xcd3f, 0x31a7,
+		0xcd40, 0x20c4,
+		0xcd41, 0x3c24,
+		0xcd42, 0x6724,
+		0xcd43, 0x1002,
+		0xcd44, 0x2807,
+		0xcd45, 0x3187,
+		0xcd46, 0x20c4,
+		0xcd47, 0x3c24,
+		0xcd48, 0x6724,
+		0xcd49, 0x1002,
+		0xcd4a, 0x2514,
+		0xcd4b, 0x3c64,
+		0xcd4c, 0x6436,
+		0xcd4d, 0xdff4,
+		0xcd4e, 0x6436,
+		0xcd4f, 0x1002,
+		0xcd50, 0x2806,
+		0xcd51, 0x3cb6,
+		0xcd52, 0xc161,
+		0xcd53, 0x6134,
+		0xcd54, 0x6135,
+		0xcd55, 0x5443,
+		0xcd56, 0x303,
+		0xcd57, 0x6524,
+		0xcd58, 0x00b,
+		0xcd59, 0x1002,
+		0xcd5a, 0xd019,
+		0xcd5b, 0x2104,
+		0xcd5c, 0x3c24,
+		0xcd5d, 0x2105,
+		0xcd5e, 0x3805,
+		0xcd5f, 0x6524,
+		0xcd60, 0xdff4,
+		0xcd61, 0x4005,
+		0xcd62, 0x6524,
+		0xcd63, 0x2e8d,
+		0xcd64, 0x303d,
+		0xcd65, 0x5dd3,
+		0xcd66, 0x306,
+		0xcd67, 0x2ff7,
+		0xcd68, 0x38f7,
+		0xcd69, 0x60b7,
+		0xcd6a, 0xdffd,
+		0xcd6b, 0x00a,
+		0xcd6c, 0x1002,
+		0xcd6d, 0
+	};
+	int i, err;
+
+	err = set_phy_regs(phy, regs);
+	if (!err && modtype == phy_modtype_twinax_long)
+		err = set_phy_regs(phy, preemphasis);
+	if (err)
+		return err;
+
+	msleep(50);
+
+	for (i = 0; i < ARRAY_SIZE(twinax_edc) && !err; i += 2)
+		err = mdio_write(phy, MDIO_DEV_PMA_PMD, twinax_edc[i],
+				 twinax_edc[i + 1]);
+	if (!err)
+		phy->priv = edc_twinax;
+	return err;
+}
+
+static int ael2005_i2c_rd(struct cphy *phy, int dev_addr, int word_addr)
+{
+	int i, err;
+	unsigned int stat, data;
+
+	err = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL_I2C_CTRL,
+			 (dev_addr << 8) | (1 << 8) | word_addr);
+	if (err)
+		return err;
+
+	for (i = 0; i < 5; i++) {
+		msleep(1);
+		err = mdio_read(phy, MDIO_DEV_PMA_PMD, AEL_I2C_STAT, &stat);
+		if (err)
+			return err;
+		if ((stat & 3) == 1) {
+			err = mdio_read(phy, MDIO_DEV_PMA_PMD, AEL_I2C_DATA,
+					&data);
+			if (err)
+				return err;
+			return data >> 8;
+		}
+	}
+	CH_WARN(phy->adapter, "PHY %u I2C read of addr %u timed out\n",
+		phy->addr, word_addr);
+	return -ETIMEDOUT;
+}
+
+static int get_module_type(struct cphy *phy, int delay_ms)
+{
+	int v;
+	unsigned int stat;
+
+	v = mdio_read(phy, MDIO_DEV_PMA_PMD, AEL2005_GPIO_CTRL, &stat);
+	if (v)
+		return v;
+
+	if (stat & (1 << 8))			/* module absent */
+		return phy_modtype_none;
+
+	if (delay_ms)
+		msleep(delay_ms);
+
+	/* see SFF-8472 for below */
+	v = ael2005_i2c_rd(phy, MODULE_DEV_ADDR, 3);
+	if (v < 0)
+		return v;
+
+	if (v == 0x10)
+		return phy_modtype_sr;
+	if (v == 0x20)
+		return phy_modtype_lr;
+	if (v == 0x40)
+		return phy_modtype_lrm;
+
+	v = ael2005_i2c_rd(phy, MODULE_DEV_ADDR, 6);
+	if (v < 0)
+		return v;
+	if (v != 4)
+		goto unknown;
+
+	v = ael2005_i2c_rd(phy, MODULE_DEV_ADDR, 10);
+	if (v < 0)
+		return v;
+
+	if (v & 0x80) {
+		v = ael2005_i2c_rd(phy, MODULE_DEV_ADDR, 0x12);
+		if (v < 0)
+			return v;
+		return v > 10 ? phy_modtype_twinax_long : phy_modtype_twinax;
+	}
+unknown:
+	return phy_modtype_unknown;
+}
+
+static int ael2005_intr_enable(struct cphy *phy)
+{
+	int err = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL2005_GPIO_CTRL, 0x200);
+	return err ? err : t3_phy_lasi_intr_enable(phy);
+}
+
+static int ael2005_intr_disable(struct cphy *phy)
+{
+	int err = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL2005_GPIO_CTRL, 0x100);
+	return err ? err : t3_phy_lasi_intr_disable(phy);
+}
+
+static int ael2005_intr_clear(struct cphy *phy)
+{
+	int err = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL2005_GPIO_CTRL, 0xd00);
+	return err ? err : t3_phy_lasi_intr_clear(phy);
+}
+
+static int ael2005_reset(struct cphy *phy, int wait)
+{
+	static struct reg_val regs0[] = {
+		{ MDIO_DEV_PMA_PMD, 0xc001, 0, 1 << 5 },
+		{ MDIO_DEV_PMA_PMD, 0xc017, 0, 1 << 5 },
+		{ MDIO_DEV_PMA_PMD, 0xc013, 0xffff, 0xf341 },
+		{ MDIO_DEV_PMA_PMD, 0xc210, 0xffff, 0x8000 },
+		{ MDIO_DEV_PMA_PMD, 0xc210, 0xffff, 0x8100 },
+		{ MDIO_DEV_PMA_PMD, 0xc210, 0xffff, 0x8000 },
+		{ MDIO_DEV_PMA_PMD, 0xc210, 0xffff, 0 },
+		{ 0, 0, 0, 0 }
+	};
+	static struct reg_val regs1[] = {
+		{ MDIO_DEV_PMA_PMD, 0xca00, 0xffff, 0x0080 },
+		{ MDIO_DEV_PMA_PMD, 0xca12, 0xffff, 0 },
+		{ 0, 0, 0, 0 }
+	};
+
+	int err, lasi_ctrl;
+
+	err = mdio_read(phy, MDIO_DEV_PMA_PMD, LASI_CTRL, &lasi_ctrl);
+	if (err)
+		return err;
+
+	err = t3_phy_reset(phy, MDIO_DEV_PMA_PMD, 0);
+	if (err)
+		return err;
+
+	msleep(125);
+	phy->priv = edc_none;
+	err = set_phy_regs(phy, regs0);
+	if (err)
+		return err;
+
+	msleep(50);
+
+	err = get_module_type(phy, 0);
+	if (err < 0)
+		return err;
+	phy->modtype = err;
+
+	if (err == phy_modtype_twinax || err == phy_modtype_twinax_long)
+		err = ael2005_setup_twinax_edc(phy, err);
+	else
+		err = ael2005_setup_sr_edc(phy);
+	if (err)
+		return err;
+
+	err = set_phy_regs(phy, regs1);
+	if (err)
+		return err;
+
+	/* reset wipes out interrupts, reenable them if they were on */
+	if (lasi_ctrl & 1)
+		err = ael2005_intr_enable(phy);
+	return err;
+}
+
+static int ael2005_intr_handler(struct cphy *phy)
+{
+	unsigned int stat;
+	int ret, edc_needed, cause = 0;
+
+	ret = mdio_read(phy, MDIO_DEV_PMA_PMD, AEL2005_GPIO_STAT, &stat);
+	if (ret)
+		return ret;
+
+	if (stat & AEL2005_MODDET_IRQ) {
+		ret = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL2005_GPIO_CTRL,
+				 0xd00);
+		if (ret)
+			return ret;
+
+		/* modules have max 300 ms init time after hot plug */
+		ret = get_module_type(phy, 300);
+		if (ret < 0)
+			return ret;
+
+		phy->modtype = ret;
+		if (ret == phy_modtype_none)
+			edc_needed = phy->priv;       /* on unplug retain EDC */
+		else if (ret == phy_modtype_twinax ||
+			 ret == phy_modtype_twinax_long)
+			edc_needed = edc_twinax;
+		else
+			edc_needed = edc_sr;
+
+		if (edc_needed != phy->priv) {
+			ret = ael2005_reset(phy, 0);
+			return ret ? ret : cphy_cause_module_change;
+		}
+		cause = cphy_cause_module_change;
+	}
+
+	ret = t3_phy_lasi_intr_handler(phy);
+	if (ret < 0)
+		return ret;
+
+	ret |= cause;
+	return ret ? ret : cphy_cause_link_change;
+}
+
+static struct cphy_ops ael2005_ops = {
+	.reset           = ael2005_reset,
+	.intr_enable     = ael2005_intr_enable,
+	.intr_disable    = ael2005_intr_disable,
+	.intr_clear      = ael2005_intr_clear,
+	.intr_handler    = ael2005_intr_handler,
+	.get_link_status = get_link_status_r,
+	.power_down      = ael1002_power_down,
+};
+
+int t3_ael2005_phy_prep(struct cphy *phy, struct adapter *adapter,
+			int phy_addr, const struct mdio_ops *mdio_ops)
+{
+	cphy_init(phy, adapter, phy_addr, &ael2005_ops, mdio_ops,
+		  SUPPORTED_10000baseT_Full | SUPPORTED_AUI | SUPPORTED_FIBRE |
+		  SUPPORTED_IRQ, "10GBASE-R");
+	msleep(125);
+	return t3_mdio_change_bits(phy, MDIO_DEV_PMA_PMD, AEL_OPT_SETTINGS, 0,
+				   1 << 5);
+}
+
+/*
+ * Get link status for a 10GBASE-X device.
+ */
+static int get_link_status_x(struct cphy *phy, int *link_ok, int *speed,
+			     int *duplex, int *fc)
+{
+	if (link_ok) {
+		unsigned int stat0, stat1, stat2;
+		int err = mdio_read(phy, MDIO_DEV_PMA_PMD, PMD_RSD, &stat0);
+
+		if (!err)
+			err = mdio_read(phy, MDIO_DEV_PCS, PCS_STAT1_X, &stat1);
+		if (!err)
+			err = mdio_read(phy, MDIO_DEV_XGXS, XS_LN_STAT, &stat2);
+		if (err)
+			return err;
+		*link_ok = (stat0 & (stat1 >> 12) & (stat2 >> 12)) & 1;
+	}
+	if (speed)
+		*speed = SPEED_10000;
+	if (duplex)
+		*duplex = DUPLEX_FULL;
+	return 0;
 }
 
 static struct cphy_ops qt2045_ops = {
 	.reset = ael1006_reset,
-	.intr_enable = ael1006_intr_enable,
-	.intr_disable = ael1006_intr_disable,
-	.intr_clear = ael1006_intr_clear,
-	.intr_handler = ael1006_intr_handler,
-	.get_link_status = ael100x_get_link_status,
+	.intr_enable = t3_phy_lasi_intr_enable,
+	.intr_disable = t3_phy_lasi_intr_disable,
+	.intr_clear = t3_phy_lasi_intr_clear,
+	.intr_handler = t3_phy_lasi_intr_handler,
+	.get_link_status = get_link_status_x,
 	.power_down = ael1006_power_down,
 };
 
-void t3_qt2045_phy_prep(struct cphy *phy, struct adapter *adapter,
-			int phy_addr, const struct mdio_ops *mdio_ops)
+int t3_qt2045_phy_prep(struct cphy *phy, struct adapter *adapter,
+		       int phy_addr, const struct mdio_ops *mdio_ops)
 {
 	unsigned int stat;
 
-	cphy_init(phy, adapter, phy_addr, &qt2045_ops, mdio_ops);
+	cphy_init(phy, adapter, phy_addr, &qt2045_ops, mdio_ops,
+		  SUPPORTED_10000baseT_Full | SUPPORTED_AUI | SUPPORTED_TP,
+		  "10GBASE-CX4");
 
 	/*
 	 * Some cards where the PHY is supposed to be at address 0 actually
@@ -205,6 +1161,7 @@
 	if (!phy_addr && !mdio_read(phy, MDIO_DEV_PMA_PMD, MII_BMSR, &stat) &&
 	    stat == 0xffff)
 		phy->addr = 1;
+	return 0;
 }
 
 static int xaui_direct_reset(struct cphy *phy, int wait)
@@ -250,8 +1207,11 @@
 	.power_down = xaui_direct_power_down,
 };
 
-void t3_xaui_direct_phy_prep(struct cphy *phy, struct adapter *adapter,
-			     int phy_addr, const struct mdio_ops *mdio_ops)
+int t3_xaui_direct_phy_prep(struct cphy *phy, struct adapter *adapter,
+			    int phy_addr, const struct mdio_ops *mdio_ops)
 {
-	cphy_init(phy, adapter, phy_addr, &xaui_direct_ops, mdio_ops);
+	cphy_init(phy, adapter, phy_addr, &xaui_direct_ops, mdio_ops,
+		  SUPPORTED_10000baseT_Full | SUPPORTED_AUI | SUPPORTED_TP,
+		  "10GBASE-CX4");
+	return 0;
 }
diff --git a/drivers/net/cxgb3/common.h b/drivers/net/cxgb3/common.h
index 9ecf8a6..e312d31 100644
--- a/drivers/net/cxgb3/common.h
+++ b/drivers/net/cxgb3/common.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005-2007 Chelsio, Inc. All rights reserved.
+ * Copyright (c) 2005-2008 Chelsio, Inc. All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
@@ -193,22 +193,13 @@
 struct adapter_info {
 	unsigned char nports;	/* # of ports */
 	unsigned char phy_base_addr;	/* MDIO PHY base address */
-	unsigned char mdien;
-	unsigned char mdiinv;
 	unsigned int gpio_out;	/* GPIO output settings */
-	unsigned int gpio_intr;	/* GPIO IRQ enable mask */
+	unsigned char gpio_intr[MAX_NPORTS]; /* GPIO PHY IRQ pins */
 	unsigned long caps;	/* adapter capabilities */
 	const struct mdio_ops *mdio_ops;	/* MDIO operations */
 	const char *desc;	/* product description */
 };
 
-struct port_type_info {
-	void (*phy_prep)(struct cphy *phy, struct adapter *adapter,
-			 int phy_addr, const struct mdio_ops *ops);
-	unsigned int caps;
-	const char *desc;
-};
-
 struct mc5_stats {
 	unsigned long parity_err;
 	unsigned long active_rgn_full;
@@ -358,6 +349,7 @@
 	unsigned int jumbo_size;	/* # of entries in jumbo free list */
 	unsigned int txq_size[SGE_TXQ_PER_SET];	/* Tx queue sizes */
 	unsigned int cong_thres;	/* FL congestion threshold */
+	unsigned int vector;		/* Interrupt (line or vector) number */
 };
 
 struct sge_params {
@@ -525,12 +517,25 @@
 	MAC_RXFIFO_SIZE = 32768
 };
 
-/* IEEE 802.3ae specified MDIO devices */
+/* IEEE 802.3 specified MDIO devices */
 enum {
 	MDIO_DEV_PMA_PMD = 1,
 	MDIO_DEV_WIS = 2,
 	MDIO_DEV_PCS = 3,
-	MDIO_DEV_XGXS = 4
+	MDIO_DEV_XGXS = 4,
+	MDIO_DEV_ANEG = 7,
+	MDIO_DEV_VEND1 = 30,
+	MDIO_DEV_VEND2 = 31
+};
+
+/* LASI control and status registers */
+enum {
+	RX_ALARM_CTRL = 0x9000,
+	TX_ALARM_CTRL = 0x9001,
+	LASI_CTRL = 0x9002,
+	RX_ALARM_STAT = 0x9003,
+	TX_ALARM_STAT = 0x9004,
+	LASI_STAT = 0x9005
 };
 
 /* PHY loopback direction */
@@ -542,12 +547,23 @@
 /* PHY interrupt types */
 enum {
 	cphy_cause_link_change = 1,
-	cphy_cause_fifo_error = 2
+	cphy_cause_fifo_error = 2,
+	cphy_cause_module_change = 4,
+};
+
+/* PHY module types */
+enum {
+	phy_modtype_none,
+	phy_modtype_sr,
+	phy_modtype_lr,
+	phy_modtype_lrm,
+	phy_modtype_twinax,
+	phy_modtype_twinax_long,
+	phy_modtype_unknown
 };
 
 /* PHY operations */
 struct cphy_ops {
-	void (*destroy)(struct cphy *phy);
 	int (*reset)(struct cphy *phy, int wait);
 
 	int (*intr_enable)(struct cphy *phy);
@@ -568,8 +584,12 @@
 
 /* A PHY instance */
 struct cphy {
-	int addr;		/* PHY address */
+	u8 addr;			/* PHY address */
+	u8 modtype;			/* PHY module type */
+	short priv;			/* scratch pad */
+	unsigned int caps;		/* PHY capabilities */
 	struct adapter *adapter;	/* associated adapter */
+	const char *desc;		/* PHY description */
 	unsigned long fifo_errors;	/* FIFO over/under-flows */
 	const struct cphy_ops *ops;	/* PHY operations */
 	int (*mdio_read)(struct adapter *adapter, int phy_addr, int mmd_addr,
@@ -594,10 +614,13 @@
 /* Convenience initializer */
 static inline void cphy_init(struct cphy *phy, struct adapter *adapter,
 			     int phy_addr, struct cphy_ops *phy_ops,
-			     const struct mdio_ops *mdio_ops)
+			     const struct mdio_ops *mdio_ops,
+			      unsigned int caps, const char *desc)
 {
-	phy->adapter = adapter;
 	phy->addr = phy_addr;
+	phy->caps = caps;
+	phy->adapter = adapter;
+	phy->desc = desc;
 	phy->ops = phy_ops;
 	if (mdio_ops) {
 		phy->mdio_read = mdio_ops->read;
@@ -668,7 +691,12 @@
 			unsigned int set);
 int t3_phy_reset(struct cphy *phy, int mmd, int wait);
 int t3_phy_advertise(struct cphy *phy, unsigned int advert);
+int t3_phy_advertise_fiber(struct cphy *phy, unsigned int advert);
 int t3_set_phy_speed_duplex(struct cphy *phy, int speed, int duplex);
+int t3_phy_lasi_intr_enable(struct cphy *phy);
+int t3_phy_lasi_intr_disable(struct cphy *phy);
+int t3_phy_lasi_intr_clear(struct cphy *phy);
+int t3_phy_lasi_intr_handler(struct cphy *phy);
 
 void t3_intr_enable(struct adapter *adapter);
 void t3_intr_disable(struct adapter *adapter);
@@ -698,6 +726,7 @@
 int t3_init_hw(struct adapter *adapter, u32 fw_params);
 void mac_prep(struct cmac *mac, struct adapter *adapter, int index);
 void early_hw_init(struct adapter *adapter, const struct adapter_info *ai);
+int t3_reset_adapter(struct adapter *adapter);
 int t3_prep_adapter(struct adapter *adapter, const struct adapter_info *ai,
 		    int reset);
 int t3_replay_prep_adapter(struct adapter *adapter);
@@ -774,14 +803,16 @@
 int t3_sge_cqcntxt_op(struct adapter *adapter, unsigned int id, unsigned int op,
 		      unsigned int credits);
 
-void t3_vsc8211_phy_prep(struct cphy *phy, struct adapter *adapter,
-			 int phy_addr, const struct mdio_ops *mdio_ops);
-void t3_ael1002_phy_prep(struct cphy *phy, struct adapter *adapter,
-			 int phy_addr, const struct mdio_ops *mdio_ops);
-void t3_ael1006_phy_prep(struct cphy *phy, struct adapter *adapter,
-			 int phy_addr, const struct mdio_ops *mdio_ops);
-void t3_qt2045_phy_prep(struct cphy *phy, struct adapter *adapter, int phy_addr,
-			const struct mdio_ops *mdio_ops);
-void t3_xaui_direct_phy_prep(struct cphy *phy, struct adapter *adapter,
-			     int phy_addr, const struct mdio_ops *mdio_ops);
+int t3_vsc8211_phy_prep(struct cphy *phy, struct adapter *adapter,
+			int phy_addr, const struct mdio_ops *mdio_ops);
+int t3_ael1002_phy_prep(struct cphy *phy, struct adapter *adapter,
+			int phy_addr, const struct mdio_ops *mdio_ops);
+int t3_ael1006_phy_prep(struct cphy *phy, struct adapter *adapter,
+			int phy_addr, const struct mdio_ops *mdio_ops);
+int t3_ael2005_phy_prep(struct cphy *phy, struct adapter *adapter,
+			int phy_addr, const struct mdio_ops *mdio_ops);
+int t3_qt2045_phy_prep(struct cphy *phy, struct adapter *adapter, int phy_addr,
+		       const struct mdio_ops *mdio_ops);
+int t3_xaui_direct_phy_prep(struct cphy *phy, struct adapter *adapter,
+			    int phy_addr, const struct mdio_ops *mdio_ops);
 #endif				/* __CHELSIO_COMMON_H */
diff --git a/drivers/net/cxgb3/cxgb3_ctl_defs.h b/drivers/net/cxgb3/cxgb3_ctl_defs.h
index 6ad9240..1d8d46e 100644
--- a/drivers/net/cxgb3/cxgb3_ctl_defs.h
+++ b/drivers/net/cxgb3/cxgb3_ctl_defs.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003-2007 Chelsio, Inc. All rights reserved.
+ * Copyright (c) 2003-2008 Chelsio, Inc. All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
diff --git a/drivers/net/cxgb3/cxgb3_defs.h b/drivers/net/cxgb3/cxgb3_defs.h
index 45e9216..47e5376 100644
--- a/drivers/net/cxgb3/cxgb3_defs.h
+++ b/drivers/net/cxgb3/cxgb3_defs.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2006-2007 Chelsio, Inc. All rights reserved.
+ * Copyright (c) 2006-2008 Chelsio, Inc. All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
diff --git a/drivers/net/cxgb3/cxgb3_ioctl.h b/drivers/net/cxgb3/cxgb3_ioctl.h
index 68200a1..b19e437 100644
--- a/drivers/net/cxgb3/cxgb3_ioctl.h
+++ b/drivers/net/cxgb3/cxgb3_ioctl.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003-2007 Chelsio, Inc. All rights reserved.
+ * Copyright (c) 2003-2008 Chelsio, Inc. All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
@@ -92,6 +92,8 @@
 	int32_t polling;
 	int32_t lro;
 	int32_t cong_thres;
+	int32_t  vector;
+	int32_t  qnum;
 };
 
 struct ch_pktsched_params {
diff --git a/drivers/net/cxgb3/cxgb3_main.c b/drivers/net/cxgb3/cxgb3_main.c
index 5447f3e..1ace41a 100644
--- a/drivers/net/cxgb3/cxgb3_main.c
+++ b/drivers/net/cxgb3/cxgb3_main.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003-2007 Chelsio, Inc. All rights reserved.
+ * Copyright (c) 2003-2008 Chelsio, Inc. All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
@@ -208,6 +208,31 @@
 	}
 }
 
+/**
+ *	t3_os_phymod_changed - handle PHY module changes
+ *	@phy: the PHY reporting the module change
+ *	@mod_type: new module type
+ *
+ *	This is the OS-dependent handler for PHY module changes.  It is
+ *	invoked when a PHY module is removed or inserted for any OS-specific
+ *	processing.
+ */
+void t3_os_phymod_changed(struct adapter *adap, int port_id)
+{
+	static const char *mod_str[] = {
+		NULL, "SR", "LR", "LRM", "TWINAX", "TWINAX", "unknown"
+	};
+
+	const struct net_device *dev = adap->port[port_id];
+	const struct port_info *pi = netdev_priv(dev);
+
+	if (pi->phy.modtype == phy_modtype_none)
+		printk(KERN_INFO "%s: PHY module unplugged\n", dev->name);
+	else
+		printk(KERN_INFO "%s: %s PHY module inserted\n", dev->name,
+		       mod_str[pi->phy.modtype]);
+}
+
 static void cxgb_set_rxmode(struct net_device *dev)
 {
 	struct t3_rx_mode rm;
@@ -274,10 +299,10 @@
 
 		for (i = 0; i < pi->nqsets; i++, msi_idx++) {
 			snprintf(adap->msix_info[msi_idx].desc, n,
-				 "%s (queue %d)", d->name, i);
+				 "%s-%d", d->name, pi->first_qset + i);
 			adap->msix_info[msi_idx].desc[n] = 0;
 		}
- 	}
+	}
 }
 
 static int request_msix_data_irqs(struct adapter *adap)
@@ -306,6 +331,22 @@
 	return 0;
 }
 
+static void free_irq_resources(struct adapter *adapter)
+{
+	if (adapter->flags & USING_MSIX) {
+		int i, n = 0;
+
+		free_irq(adapter->msix_info[0].vec, adapter);
+		for_each_port(adapter, i)
+		    n += adap2pinfo(adapter, i)->nqsets;
+
+		for (i = 0; i < n; ++i)
+			free_irq(adapter->msix_info[i + 1].vec,
+				 &adapter->sge.qs[i]);
+	} else
+		free_irq(adapter->pdev->irq, adapter);
+}
+
 static int await_mgmt_replies(struct adapter *adap, unsigned long init_cnt,
 			      unsigned long n)
 {
@@ -473,12 +514,16 @@
 		struct port_info *pi = netdev_priv(dev);
 
 		pi->qs = &adap->sge.qs[pi->first_qset];
-		for (j = 0; j < pi->nqsets; ++j, ++qset_idx) {
+		for (j = pi->first_qset; j < pi->first_qset + pi->nqsets;
+		     ++j, ++qset_idx) {
+			if (!pi->rx_csum_offload)
+				adap->params.sge.qset[qset_idx].lro = 0;
 			err = t3_sge_alloc_qset(adap, qset_idx, 1,
 				(adap->flags & USING_MSIX) ? qset_idx + 1 :
 							     irq_idx,
 				&adap->params.sge.qset[qset_idx], ntxq, dev);
 			if (err) {
+				t3_stop_sge_timers(adap);
 				t3_free_sge_resources(adap);
 				return err;
 			}
@@ -739,11 +784,12 @@
 	t3_write_reg(adapter, A_TP_MTU_PORT_TABLE, mtus);
 }
 
-static void send_pktsched_cmd(struct adapter *adap, int sched, int qidx, int lo,
+static int send_pktsched_cmd(struct adapter *adap, int sched, int qidx, int lo,
 			      int hi, int port)
 {
 	struct sk_buff *skb;
 	struct mngt_pktsched_wr *req;
+	int ret;
 
 	skb = alloc_skb(sizeof(*req), GFP_KERNEL | __GFP_NOFAIL);
 	req = (struct mngt_pktsched_wr *)skb_put(skb, sizeof(*req));
@@ -754,20 +800,28 @@
 	req->min = lo;
 	req->max = hi;
 	req->binding = port;
-	t3_mgmt_tx(adap, skb);
+	ret = t3_mgmt_tx(adap, skb);
+
+	return ret;
 }
 
-static void bind_qsets(struct adapter *adap)
+static int bind_qsets(struct adapter *adap)
 {
-	int i, j;
+	int i, j, err = 0;
 
 	for_each_port(adap, i) {
 		const struct port_info *pi = adap2pinfo(adap, i);
 
-		for (j = 0; j < pi->nqsets; ++j)
-			send_pktsched_cmd(adap, 1, pi->first_qset + j, -1,
-					  -1, i);
+		for (j = 0; j < pi->nqsets; ++j) {
+			int ret = send_pktsched_cmd(adap, 1,
+						    pi->first_qset + j, -1,
+						    -1, i);
+			if (ret)
+				err = ret;
+		}
 	}
+
+	return err;
 }
 
 #define FW_FNAME "t3fw-%d.%d.%d.bin"
@@ -891,6 +945,13 @@
 				goto out;
 		}
 
+		/*
+		 * Clear interrupts now to catch errors if t3_init_hw fails.
+		 * We clear them again later as initialization may trigger
+		 * conditions that can interrupt.
+		 */
+		t3_intr_clear(adap);
+
 		err = t3_init_hw(adap, 0);
 		if (err)
 			goto out;
@@ -946,9 +1007,16 @@
 		t3_write_reg(adap, A_TP_INT_ENABLE, 0x7fbfffff);
 	}
 
-	if ((adap->flags & (USING_MSIX | QUEUES_BOUND)) == USING_MSIX)
-		bind_qsets(adap);
-	adap->flags |= QUEUES_BOUND;
+	if (!(adap->flags & QUEUES_BOUND)) {
+		err = bind_qsets(adap);
+		if (err) {
+			CH_ERR(adap, "failed to bind qsets, err %d\n", err);
+			t3_intr_disable(adap);
+			free_irq_resources(adap);
+			goto out;
+		}
+		adap->flags |= QUEUES_BOUND;
+	}
 
 out:
 	return err;
@@ -967,19 +1035,7 @@
 	t3_intr_disable(adapter);
 	spin_unlock_irq(&adapter->work_lock);
 
-	if (adapter->flags & USING_MSIX) {
-		int i, n = 0;
-
-		free_irq(adapter->msix_info[0].vec, adapter);
-		for_each_port(adapter, i)
-		    n += adap2pinfo(adapter, i)->nqsets;
-
-		for (i = 0; i < n; ++i)
-			free_irq(adapter->msix_info[i + 1].vec,
-				 &adapter->sge.qs[i]);
-	} else
-		free_irq(adapter->pdev->irq, adapter);
-
+	free_irq_resources(adapter);
 	flush_workqueue(cxgb3_wq);	/* wait for external IRQ handler */
 	quiesce_rx(adapter);
 }
@@ -1100,9 +1156,9 @@
 	netif_carrier_off(dev);
 	t3_mac_disable(&pi->mac, MAC_DIRECTION_TX | MAC_DIRECTION_RX);
 
-	spin_lock(&adapter->work_lock);	/* sync with update task */
+	spin_lock_irq(&adapter->work_lock);	/* sync with update task */
 	clear_bit(pi->port_id, &adapter->open_device_map);
-	spin_unlock(&adapter->work_lock);
+	spin_unlock_irq(&adapter->work_lock);
 
 	if (!(adapter->open_device_map & PORT_MASK))
 		cancel_rearming_delayed_workqueue(cxgb3_wq,
@@ -1284,8 +1340,8 @@
 	int i;
 	unsigned long tot = 0;
 
-	for (i = 0; i < p->nqsets; ++i)
-		tot += adapter->sge.qs[i + p->first_qset].port_stats[idx];
+	for (i = p->first_qset; i < p->first_qset + p->nqsets; ++i)
+		tot += adapter->sge.qs[i].port_stats[idx];
 	return tot;
 }
 
@@ -1485,11 +1541,22 @@
 
 static int set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 {
+	int cap;
 	struct port_info *p = netdev_priv(dev);
 	struct link_config *lc = &p->link_config;
 
-	if (!(lc->supported & SUPPORTED_Autoneg))
-		return -EOPNOTSUPP;	/* can't change speed/duplex */
+	if (!(lc->supported & SUPPORTED_Autoneg)) {
+		/*
+		 * PHY offers a single speed/duplex.  See if that's what's
+		 * being requested.
+		 */
+		if (cmd->autoneg == AUTONEG_DISABLE) {
+			cap = speed_duplex_to_caps(cmd->speed, cmd->duplex);
+			if (lc->supported & cap)
+				return 0;
+		}
+		return -EINVAL;
+	}
 
 	if (cmd->autoneg == AUTONEG_DISABLE) {
 		int cap = speed_duplex_to_caps(cmd->speed, cmd->duplex);
@@ -1568,8 +1635,10 @@
 		struct adapter *adap = p->adapter;
 		int i;
 
-		for (i = p->first_qset; i < p->first_qset + p->nqsets; i++)
+		for (i = p->first_qset; i < p->first_qset + p->nqsets; i++) {
+			adap->params.sge.qset[i].lro = 0;
 			adap->sge.qs[i].lro_enabled = 0;
+		}
 	}
 	return 0;
 }
@@ -1775,6 +1844,8 @@
 		int i;
 		struct qset_params *q;
 		struct ch_qset_params t;
+		int q1 = pi->first_qset;
+		int nqsets = pi->nqsets;
 
 		if (!capable(CAP_NET_ADMIN))
 			return -EPERM;
@@ -1797,6 +1868,16 @@
 			|| !in_range(t.rspq_size, MIN_RSPQ_ENTRIES,
 					MAX_RSPQ_ENTRIES))
 			return -EINVAL;
+
+		if ((adapter->flags & FULL_INIT_DONE) && t.lro > 0)
+			for_each_port(adapter, i) {
+				pi = adap2pinfo(adapter, i);
+				if (t.qset_idx >= pi->first_qset &&
+				    t.qset_idx < pi->first_qset + pi->nqsets &&
+				    !pi->rx_csum_offload)
+					return -EINVAL;
+			}
+
 		if ((adapter->flags & FULL_INIT_DONE) &&
 			(t.rspq_size >= 0 || t.fl_size[0] >= 0 ||
 			t.fl_size[1] >= 0 || t.txq_size[0] >= 0 ||
@@ -1804,6 +1885,20 @@
 			t.polling >= 0 || t.cong_thres >= 0))
 			return -EBUSY;
 
+		/* Allow setting of any available qset when offload enabled */
+		if (test_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map)) {
+			q1 = 0;
+			for_each_port(adapter, i) {
+				pi = adap2pinfo(adapter, i);
+				nqsets += pi->first_qset + pi->nqsets;
+			}
+		}
+
+		if (t.qset_idx < q1)
+			return -EINVAL;
+		if (t.qset_idx > q1 + nqsets - 1)
+			return -EINVAL;
+
 		q = &adapter->params.sge.qset[t.qset_idx];
 
 		if (t.rspq_size >= 0)
@@ -1853,13 +1948,26 @@
 	case CHELSIO_GET_QSET_PARAMS:{
 		struct qset_params *q;
 		struct ch_qset_params t;
+		int q1 = pi->first_qset;
+		int nqsets = pi->nqsets;
+		int i;
 
 		if (copy_from_user(&t, useraddr, sizeof(t)))
 			return -EFAULT;
-		if (t.qset_idx >= SGE_QSETS)
+
+		/* Display qsets for all ports when offload enabled */
+		if (test_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map)) {
+			q1 = 0;
+			for_each_port(adapter, i) {
+				pi = adap2pinfo(adapter, i);
+				nqsets = pi->first_qset + pi->nqsets;
+			}
+		}
+
+		if (t.qset_idx >= nqsets)
 			return -EINVAL;
 
-		q = &adapter->params.sge.qset[t.qset_idx];
+		q = &adapter->params.sge.qset[q1 + t.qset_idx];
 		t.rspq_size = q->rspq_size;
 		t.txq_size[0] = q->txq_size[0];
 		t.txq_size[1] = q->txq_size[1];
@@ -1870,6 +1978,12 @@
 		t.lro = q->lro;
 		t.intr_lat = q->coalesce_usecs;
 		t.cong_thres = q->cong_thres;
+		t.qnum = q1;
+
+		if (adapter->flags & USING_MSIX)
+			t.vector = adapter->msix_info[q1 + t.qset_idx + 1].vec;
+		else
+			t.vector = adapter->pdev->irq;
 
 		if (copy_to_user(useraddr, &t, sizeof(t)))
 			return -EFAULT;
@@ -2117,7 +2231,7 @@
 			mmd = data->phy_id >> 8;
 			if (!mmd)
 				mmd = MDIO_DEV_PCS;
-			else if (mmd > MDIO_DEV_XGXS)
+			else if (mmd > MDIO_DEV_VEND2)
 				return -EINVAL;
 
 			ret =
@@ -2143,7 +2257,7 @@
 			mmd = data->phy_id >> 8;
 			if (!mmd)
 				mmd = MDIO_DEV_PCS;
-			else if (mmd > MDIO_DEV_XGXS)
+			else if (mmd > MDIO_DEV_VEND2)
 				return -EINVAL;
 
 			ret =
@@ -2215,8 +2329,8 @@
 {
 	int i;
 
-	for (i = 0; i < p->nqsets; i++) {
-		struct sge_rspq *q = &adap->sge.qs[i + p->first_qset].rspq;
+	for (i = p->first_qset; i < p->first_qset + p->nqsets; i++) {
+		struct sge_rspq *q = &adap->sge.qs[i].rspq;
 
 		spin_lock_irq(&q->lock);
 		spin_unlock_irq(&q->lock);
@@ -2290,7 +2404,7 @@
 		struct net_device *dev = adapter->port[i];
 		struct port_info *p = netdev_priv(dev);
 
-		if (!(p->port_type->caps & SUPPORTED_IRQ) && netif_running(dev))
+		if (!(p->phy.caps & SUPPORTED_IRQ) && netif_running(dev))
 			t3_link_changed(adapter, i);
 	}
 }
@@ -2355,10 +2469,10 @@
 		check_t3b2_mac(adapter);
 
 	/* Schedule the next check update if any port is active. */
-	spin_lock(&adapter->work_lock);
+	spin_lock_irq(&adapter->work_lock);
 	if (adapter->open_device_map & PORT_MASK)
 		schedule_chk_task(adapter);
-	spin_unlock(&adapter->work_lock);
+	spin_unlock_irq(&adapter->work_lock);
 }
 
 /*
@@ -2403,6 +2517,96 @@
 	spin_unlock(&adapter->work_lock);
 }
 
+static int t3_adapter_error(struct adapter *adapter, int reset)
+{
+	int i, ret = 0;
+
+	/* Stop all ports */
+	for_each_port(adapter, i) {
+		struct net_device *netdev = adapter->port[i];
+
+		if (netif_running(netdev))
+			cxgb_close(netdev);
+	}
+
+	if (is_offload(adapter) &&
+	    test_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map))
+		offload_close(&adapter->tdev);
+
+	/* Stop SGE timers */
+	t3_stop_sge_timers(adapter);
+
+	adapter->flags &= ~FULL_INIT_DONE;
+
+	if (reset)
+		ret = t3_reset_adapter(adapter);
+
+	pci_disable_device(adapter->pdev);
+
+	return ret;
+}
+
+static int t3_reenable_adapter(struct adapter *adapter)
+{
+	if (pci_enable_device(adapter->pdev)) {
+		dev_err(&adapter->pdev->dev,
+			"Cannot re-enable PCI device after reset.\n");
+		goto err;
+	}
+	pci_set_master(adapter->pdev);
+	pci_restore_state(adapter->pdev);
+
+	/* Free sge resources */
+	t3_free_sge_resources(adapter);
+
+	if (t3_replay_prep_adapter(adapter))
+		goto err;
+
+	return 0;
+err:
+	return -1;
+}
+
+static void t3_resume_ports(struct adapter *adapter)
+{
+	int i;
+
+	/* Restart the ports */
+	for_each_port(adapter, i) {
+		struct net_device *netdev = adapter->port[i];
+
+		if (netif_running(netdev)) {
+			if (cxgb_open(netdev)) {
+				dev_err(&adapter->pdev->dev,
+					"can't bring device back up"
+					" after reset\n");
+				continue;
+			}
+		}
+	}
+}
+
+/*
+ * processes a fatal error.
+ * Bring the ports down, reset the chip, bring the ports back up.
+ */
+static void fatal_error_task(struct work_struct *work)
+{
+	struct adapter *adapter = container_of(work, struct adapter,
+					       fatal_error_handler_task);
+	int err = 0;
+
+	rtnl_lock();
+	err = t3_adapter_error(adapter, 1);
+	if (!err)
+		err = t3_reenable_adapter(adapter);
+	if (!err)
+		t3_resume_ports(adapter);
+
+	CH_ALERT(adapter, "adapter reset %s\n", err ? "failed" : "succeeded");
+	rtnl_unlock();
+}
+
 void t3_fatal_err(struct adapter *adapter)
 {
 	unsigned int fw_status[4];
@@ -2413,7 +2617,11 @@
 		t3_write_reg(adapter, A_XGM_RX_CTRL, 0);
 		t3_write_reg(adapter, XGM_REG(A_XGM_TX_CTRL, 1), 0);
 		t3_write_reg(adapter, XGM_REG(A_XGM_RX_CTRL, 1), 0);
+
+		spin_lock(&adapter->work_lock);
 		t3_intr_disable(adapter);
+		queue_work(cxgb3_wq, &adapter->fatal_error_handler_task);
+		spin_unlock(&adapter->work_lock);
 	}
 	CH_ALERT(adapter, "encountered fatal error, operation suspended\n");
 	if (!t3_cim_ctl_blk_read(adapter, 0xa0, 4, fw_status))
@@ -2435,23 +2643,9 @@
 					     pci_channel_state_t state)
 {
 	struct adapter *adapter = pci_get_drvdata(pdev);
-	int i;
+	int ret;
 
-	/* Stop all ports */
-	for_each_port(adapter, i) {
-		struct net_device *netdev = adapter->port[i];
-
-		if (netif_running(netdev))
-			cxgb_close(netdev);
-	}
-
-	if (is_offload(adapter) &&
-	    test_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map))
-		offload_close(&adapter->tdev);
-
-	adapter->flags &= ~FULL_INIT_DONE;
-
-	pci_disable_device(pdev);
+	ret = t3_adapter_error(adapter, 0);
 
 	/* Request a slot reset. */
 	return PCI_ERS_RESULT_NEED_RESET;
@@ -2467,22 +2661,9 @@
 {
 	struct adapter *adapter = pci_get_drvdata(pdev);
 
-	if (pci_enable_device(pdev)) {
-		dev_err(&pdev->dev,
-			"Cannot re-enable PCI device after reset.\n");
-		goto err;
-	}
-	pci_set_master(pdev);
-	pci_restore_state(pdev);
+	if (!t3_reenable_adapter(adapter))
+		return PCI_ERS_RESULT_RECOVERED;
 
-	/* Free sge resources */
-	t3_free_sge_resources(adapter);
-
-	if (t3_replay_prep_adapter(adapter))
-		goto err;
-
-	return PCI_ERS_RESULT_RECOVERED;
-err:
 	return PCI_ERS_RESULT_DISCONNECT;
 }
 
@@ -2496,22 +2677,8 @@
 static void t3_io_resume(struct pci_dev *pdev)
 {
 	struct adapter *adapter = pci_get_drvdata(pdev);
-	int i;
 
-	/* Restart the ports */
-	for_each_port(adapter, i) {
-		struct net_device *netdev = adapter->port[i];
-
-		if (netif_running(netdev)) {
-			if (cxgb_open(netdev)) {
-				dev_err(&pdev->dev,
-					"can't bring device back up"
-					" after reset\n");
-				continue;
-			}
-			netif_device_attach(netdev);
-		}
-	}
+	t3_resume_ports(adapter);
 }
 
 static struct pci_error_handlers t3_err_handler = {
@@ -2520,6 +2687,42 @@
 	.resume = t3_io_resume,
 };
 
+/*
+ * Set the number of qsets based on the number of CPUs and the number of ports,
+ * not to exceed the number of available qsets, assuming there are enough qsets
+ * per port in HW.
+ */
+static void set_nqsets(struct adapter *adap)
+{
+	int i, j = 0;
+	int num_cpus = num_online_cpus();
+	int hwports = adap->params.nports;
+	int nqsets = SGE_QSETS;
+
+	if (adap->params.rev > 0) {
+		if (hwports == 2 &&
+		    (hwports * nqsets > SGE_QSETS ||
+		     num_cpus >= nqsets / hwports))
+			nqsets /= hwports;
+		if (nqsets > num_cpus)
+			nqsets = num_cpus;
+		if (nqsets < 1 || hwports == 4)
+			nqsets = 1;
+	} else
+		nqsets = 1;
+
+	for_each_port(adap, i) {
+		struct port_info *pi = adap2pinfo(adap, i);
+
+		pi->first_qset = j;
+		pi->nqsets = nqsets;
+		j = pi->first_qset + nqsets;
+
+		dev_info(&adap->pdev->dev,
+			 "Port %d using %d queue sets.\n", i, nqsets);
+	}
+}
+
 static int __devinit cxgb_enable_msix(struct adapter *adap)
 {
 	struct msix_entry entries[SGE_QSETS + 1];
@@ -2564,7 +2767,7 @@
 		if (!test_bit(i, &adap->registered_device_map))
 			continue;
 		printk(KERN_INFO "%s: %s %s %sNIC (rev %d) %s%s\n",
-		       dev->name, ai->desc, pi->port_type->desc,
+		       dev->name, ai->desc, pi->phy.desc,
 		       is_offload(adap) ? "R" : "", adap->params.rev, buf,
 		       (adap->flags & USING_MSIX) ? " MSI-X" :
 		       (adap->flags & USING_MSI) ? " MSI" : "");
@@ -2660,6 +2863,7 @@
 
 	INIT_LIST_HEAD(&adapter->adapter_list);
 	INIT_WORK(&adapter->ext_intr_handler_task, ext_intr_task);
+	INIT_WORK(&adapter->fatal_error_handler_task, fatal_error_task);
 	INIT_DELAYED_WORK(&adapter->adap_check_task, t3_adap_check_task);
 
 	for (i = 0; i < ai->nports; ++i) {
@@ -2677,9 +2881,6 @@
 		pi = netdev_priv(netdev);
 		pi->adapter = adapter;
 		pi->rx_csum_offload = 1;
-		pi->nqsets = 1;
-		pi->first_qset = i;
-		pi->activity = 0;
 		pi->port_id = i;
 		netif_carrier_off(netdev);
 		netdev->irq = pdev->irq;
@@ -2756,6 +2957,8 @@
 	else if (msi > 0 && pci_enable_msi(pdev) == 0)
 		adapter->flags |= USING_MSI;
 
+	set_nqsets(adapter);
+
 	err = sysfs_create_group(&adapter->port[0]->dev.kobj,
 				 &cxgb3_attr_group);
 
@@ -2801,6 +3004,7 @@
 		    if (test_bit(i, &adapter->registered_device_map))
 			unregister_netdev(adapter->port[i]);
 
+		t3_stop_sge_timers(adapter);
 		t3_free_sge_resources(adapter);
 		cxgb_disable_msi(adapter);
 
diff --git a/drivers/net/cxgb3/cxgb3_offload.c b/drivers/net/cxgb3/cxgb3_offload.c
index c5b3de1..265aa8a 100644
--- a/drivers/net/cxgb3/cxgb3_offload.c
+++ b/drivers/net/cxgb3/cxgb3_offload.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2006-2007 Chelsio, Inc. All rights reserved.
+ * Copyright (c) 2006-2008 Chelsio, Inc. All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
@@ -1018,7 +1018,7 @@
 
 	skb = alloc_skb(sizeof(*req), GFP_ATOMIC);
 	if (!skb) {
-		printk(KERN_ERR "%s: cannot allocate skb!\n", __FUNCTION__);
+		printk(KERN_ERR "%s: cannot allocate skb!\n", __func__);
 		return;
 	}
 	skb->priority = CPL_PRIORITY_CONTROL;
@@ -1049,14 +1049,14 @@
 		return;
 	if (!is_offloading(newdev)) {
 		printk(KERN_WARNING "%s: Redirect to non-offload "
-		       "device ignored.\n", __FUNCTION__);
+		       "device ignored.\n", __func__);
 		return;
 	}
 	tdev = dev2t3cdev(olddev);
 	BUG_ON(!tdev);
 	if (tdev != dev2t3cdev(newdev)) {
 		printk(KERN_WARNING "%s: Redirect to different "
-		       "offload device ignored.\n", __FUNCTION__);
+		       "offload device ignored.\n", __func__);
 		return;
 	}
 
@@ -1064,7 +1064,7 @@
 	e = t3_l2t_get(tdev, new->neighbour, newdev);
 	if (!e) {
 		printk(KERN_ERR "%s: couldn't allocate new l2t entry!\n",
-		       __FUNCTION__);
+		       __func__);
 		return;
 	}
 
diff --git a/drivers/net/cxgb3/cxgb3_offload.h b/drivers/net/cxgb3/cxgb3_offload.h
index 7a37913..d514e50 100644
--- a/drivers/net/cxgb3/cxgb3_offload.h
+++ b/drivers/net/cxgb3/cxgb3_offload.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2006-2007 Chelsio, Inc. All rights reserved.
+ * Copyright (c) 2006-2008 Chelsio, Inc. All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
diff --git a/drivers/net/cxgb3/firmware_exports.h b/drivers/net/cxgb3/firmware_exports.h
index b75ddd8..0d9b0e6 100644
--- a/drivers/net/cxgb3/firmware_exports.h
+++ b/drivers/net/cxgb3/firmware_exports.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2004-2007 Chelsio, Inc. All rights reserved.
+ * Copyright (c) 2004-2008 Chelsio, Inc. All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
diff --git a/drivers/net/cxgb3/l2t.c b/drivers/net/cxgb3/l2t.c
index 825e510..4407ac9 100644
--- a/drivers/net/cxgb3/l2t.c
+++ b/drivers/net/cxgb3/l2t.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003-2007 Chelsio, Inc. All rights reserved.
+ * Copyright (c) 2003-2008 Chelsio, Inc. All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
@@ -86,6 +86,7 @@
 				  struct l2t_entry *e)
 {
 	struct cpl_l2t_write_req *req;
+	struct sk_buff *tmp;
 
 	if (!skb) {
 		skb = alloc_skb(sizeof(*req), GFP_ATOMIC);
@@ -103,13 +104,11 @@
 	memcpy(req->dst_mac, e->dmac, sizeof(req->dst_mac));
 	skb->priority = CPL_PRIORITY_CONTROL;
 	cxgb3_ofld_send(dev, skb);
-	while (e->arpq_head) {
-		skb = e->arpq_head;
-		e->arpq_head = skb->next;
-		skb->next = NULL;
+
+	skb_queue_walk_safe(&e->arpq, skb, tmp) {
+		__skb_unlink(skb, &e->arpq);
 		cxgb3_ofld_send(dev, skb);
 	}
-	e->arpq_tail = NULL;
 	e->state = L2T_STATE_VALID;
 
 	return 0;
@@ -121,12 +120,7 @@
  */
 static inline void arpq_enqueue(struct l2t_entry *e, struct sk_buff *skb)
 {
-	skb->next = NULL;
-	if (e->arpq_head)
-		e->arpq_tail->next = skb;
-	else
-		e->arpq_head = skb;
-	e->arpq_tail = skb;
+	__skb_queue_tail(&e->arpq, skb);
 }
 
 int t3_l2t_send_slow(struct t3cdev *dev, struct sk_buff *skb,
@@ -167,7 +161,7 @@
 				break;
 
 			spin_lock_bh(&e->lock);
-			if (e->arpq_head)
+			if (!skb_queue_empty(&e->arpq))
 				setup_l2e_send_pending(dev, skb, e);
 			else	/* we lost the race */
 				__kfree_skb(skb);
@@ -357,14 +351,14 @@
  * XXX: maybe we should abandon the latter behavior and just require a failure
  * handler.
  */
-static void handle_failed_resolution(struct t3cdev *dev, struct sk_buff *arpq)
+static void handle_failed_resolution(struct t3cdev *dev, struct sk_buff_head *arpq)
 {
-	while (arpq) {
-		struct sk_buff *skb = arpq;
+	struct sk_buff *skb, *tmp;
+
+	skb_queue_walk_safe(arpq, skb, tmp) {
 		struct l2t_skb_cb *cb = L2T_SKB_CB(skb);
 
-		arpq = skb->next;
-		skb->next = NULL;
+		__skb_unlink(skb, arpq);
 		if (cb->arp_failure_handler)
 			cb->arp_failure_handler(dev, skb);
 		else
@@ -378,8 +372,8 @@
  */
 void t3_l2t_update(struct t3cdev *dev, struct neighbour *neigh)
 {
+	struct sk_buff_head arpq;
 	struct l2t_entry *e;
-	struct sk_buff *arpq = NULL;
 	struct l2t_data *d = L2DATA(dev);
 	u32 addr = *(u32 *) neigh->primary_key;
 	int ifidx = neigh->dev->ifindex;
@@ -395,6 +389,8 @@
 	return;
 
 found:
+	__skb_queue_head_init(&arpq);
+
 	read_unlock(&d->lock);
 	if (atomic_read(&e->refcnt)) {
 		if (neigh != e->neigh)
@@ -402,8 +398,7 @@
 
 		if (e->state == L2T_STATE_RESOLVING) {
 			if (neigh->nud_state & NUD_FAILED) {
-				arpq = e->arpq_head;
-				e->arpq_head = e->arpq_tail = NULL;
+				skb_queue_splice_init(&e->arpq, &arpq);
 			} else if (neigh->nud_state & (NUD_CONNECTED|NUD_STALE))
 				setup_l2e_send_pending(dev, NULL, e);
 		} else {
@@ -415,8 +410,8 @@
 	}
 	spin_unlock_bh(&e->lock);
 
-	if (arpq)
-		handle_failed_resolution(dev, arpq);
+	if (!skb_queue_empty(&arpq))
+		handle_failed_resolution(dev, &arpq);
 }
 
 struct l2t_data *t3_init_l2t(unsigned int l2t_capacity)
diff --git a/drivers/net/cxgb3/l2t.h b/drivers/net/cxgb3/l2t.h
index d790013..fd3eb07 100644
--- a/drivers/net/cxgb3/l2t.h
+++ b/drivers/net/cxgb3/l2t.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003-2007 Chelsio, Inc. All rights reserved.
+ * Copyright (c) 2003-2008 Chelsio, Inc. All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
@@ -64,8 +64,7 @@
 	struct neighbour *neigh;	/* associated neighbour */
 	struct l2t_entry *first;	/* start of hash chain */
 	struct l2t_entry *next;	/* next l2t_entry on chain */
-	struct sk_buff *arpq_head;	/* queue of packets awaiting resolution */
-	struct sk_buff *arpq_tail;
+	struct sk_buff_head arpq;	/* queue of packets awaiting resolution */
 	spinlock_t lock;
 	atomic_t refcnt;	/* entry reference count */
 	u8 dmac[6];		/* neighbour's MAC address */
diff --git a/drivers/net/cxgb3/mc5.c b/drivers/net/cxgb3/mc5.c
index 4c4d6e8..3b5517b 100644
--- a/drivers/net/cxgb3/mc5.c
+++ b/drivers/net/cxgb3/mc5.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003-2007 Chelsio, Inc. All rights reserved.
+ * Copyright (c) 2003-2008 Chelsio, Inc. All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
diff --git a/drivers/net/cxgb3/regs.h b/drivers/net/cxgb3/regs.h
index 4bda27c..a035d5c2 100644
--- a/drivers/net/cxgb3/regs.h
+++ b/drivers/net/cxgb3/regs.h
@@ -573,6 +573,10 @@
 #define V_GPIO10(x) ((x) << S_GPIO10)
 #define F_GPIO10    V_GPIO10(1U)
 
+#define S_GPIO9    9
+#define V_GPIO9(x) ((x) << S_GPIO9)
+#define F_GPIO9    V_GPIO9(1U)
+
 #define S_GPIO7    7
 #define V_GPIO7(x) ((x) << S_GPIO7)
 #define F_GPIO7    V_GPIO7(1U)
diff --git a/drivers/net/cxgb3/sge.c b/drivers/net/cxgb3/sge.c
index 1b0861d..c6480be 100644
--- a/drivers/net/cxgb3/sge.c
+++ b/drivers/net/cxgb3/sge.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005-2007 Chelsio, Inc. All rights reserved.
+ * Copyright (c) 2005-2008 Chelsio, Inc. All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
@@ -351,7 +351,8 @@
 		pci_unmap_single(pdev, pci_unmap_addr(d, dma_addr),
 				 q->buf_size, PCI_DMA_FROMDEVICE);
 		if (q->use_pages) {
-			put_page(d->pg_chunk.page);
+			if (d->pg_chunk.page)
+				put_page(d->pg_chunk.page);
 			d->pg_chunk.page = NULL;
 		} else {
 			kfree_skb(d->skb);
@@ -583,7 +584,7 @@
 	memset(q->fl, 0, sizeof(struct sge_fl) * SGE_RXQ_PER_SET);
 	memset(q->txq, 0, sizeof(struct sge_txq) * SGE_TXQ_PER_SET);
 	q->txq_stopped = 0;
-	memset(&q->tx_reclaim_timer, 0, sizeof(q->tx_reclaim_timer));
+	q->tx_reclaim_timer.function = NULL; /* for t3_stop_sge_timers() */
 	kfree(q->lro_frag_tbl);
 	q->lro_nfrags = q->lro_frag_len = 0;
 }
@@ -603,9 +604,6 @@
 	int i;
 	struct pci_dev *pdev = adapter->pdev;
 
-	if (q->tx_reclaim_timer.function)
-		del_timer_sync(&q->tx_reclaim_timer);
-
 	for (i = 0; i < SGE_RXQ_PER_SET; ++i)
 		if (q->fl[i].desc) {
 			spin_lock_irq(&adapter->sge.reg_lock);
@@ -1704,16 +1702,15 @@
  */
 static inline void offload_enqueue(struct sge_rspq *q, struct sk_buff *skb)
 {
-	skb->next = skb->prev = NULL;
-	if (q->rx_tail)
-		q->rx_tail->next = skb;
-	else {
+	int was_empty = skb_queue_empty(&q->rx_queue);
+
+	__skb_queue_tail(&q->rx_queue, skb);
+
+	if (was_empty) {
 		struct sge_qset *qs = rspq_to_qset(q);
 
 		napi_schedule(&qs->napi);
-		q->rx_head = skb;
 	}
-	q->rx_tail = skb;
 }
 
 /**
@@ -1754,26 +1751,29 @@
 	int work_done = 0;
 
 	while (work_done < budget) {
-		struct sk_buff *head, *tail, *skbs[RX_BUNDLE_SIZE];
+		struct sk_buff *skb, *tmp, *skbs[RX_BUNDLE_SIZE];
+		struct sk_buff_head queue;
 		int ngathered;
 
 		spin_lock_irq(&q->lock);
-		head = q->rx_head;
-		if (!head) {
+		__skb_queue_head_init(&queue);
+		skb_queue_splice_init(&q->rx_queue, &queue);
+		if (skb_queue_empty(&queue)) {
 			napi_complete(napi);
 			spin_unlock_irq(&q->lock);
 			return work_done;
 		}
-
-		tail = q->rx_tail;
-		q->rx_head = q->rx_tail = NULL;
 		spin_unlock_irq(&q->lock);
 
-		for (ngathered = 0; work_done < budget && head; work_done++) {
-			prefetch(head->data);
-			skbs[ngathered] = head;
-			head = head->next;
-			skbs[ngathered]->next = NULL;
+		ngathered = 0;
+		skb_queue_walk_safe(&queue, skb, tmp) {
+			if (work_done >= budget)
+				break;
+			work_done++;
+
+			__skb_unlink(skb, &queue);
+			prefetch(skb->data);
+			skbs[ngathered] = skb;
 			if (++ngathered == RX_BUNDLE_SIZE) {
 				q->offload_bundles++;
 				adapter->tdev.recv(&adapter->tdev, skbs,
@@ -1781,12 +1781,10 @@
 				ngathered = 0;
 			}
 		}
-		if (head) {	/* splice remaining packets back onto Rx queue */
+		if (!skb_queue_empty(&queue)) {
+			/* splice remaining packets back onto Rx queue */
 			spin_lock_irq(&q->lock);
-			tail->next = q->rx_head;
-			if (!q->rx_head)
-				q->rx_tail = tail;
-			q->rx_head = head;
+			skb_queue_splice(&queue, &q->rx_queue);
 			spin_unlock_irq(&q->lock);
 		}
 		deliver_partial_bundle(&adapter->tdev, q, skbs, ngathered);
@@ -1937,38 +1935,6 @@
 		eh->h_proto == htons(ETH_P_IP) && ih->ihl == (sizeof(*ih) >> 2);
 }
 
-#define TCP_FLAG_MASK (TCP_FLAG_CWR | TCP_FLAG_ECE | TCP_FLAG_URG |\
-                       TCP_FLAG_ACK | TCP_FLAG_PSH | TCP_FLAG_RST |\
-		                       TCP_FLAG_SYN | TCP_FLAG_FIN)
-#define TSTAMP_WORD ((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) |\
-                     (TCPOPT_TIMESTAMP << 8) | TCPOLEN_TIMESTAMP)
-
-/**
- *	lro_segment_ok - check if a TCP segment is eligible for LRO
- *	@tcph: the TCP header of the packet
- *
- *	Returns true if a TCP packet is eligible for LRO.  This requires that
- *	the packet have only the ACK flag set and no TCP options besides
- *	time stamps.
- */
-static inline int lro_segment_ok(const struct tcphdr *tcph)
-{
-	int optlen;
-
-	if (unlikely((tcp_flag_word(tcph) & TCP_FLAG_MASK) != TCP_FLAG_ACK))
-		return 0;
-
-	optlen = (tcph->doff << 2) - sizeof(*tcph);
-	if (optlen) {
-		const u32 *opt = (const u32 *)(tcph + 1);
-
-		if (optlen != TCPOLEN_TSTAMP_ALIGNED ||
-		    *opt != htonl(TSTAMP_WORD) || !opt[2])
-			return 0;
-	}
-	return 1;
-}
-
 static int t3_get_lro_header(void **eh,  void **iph, void **tcph,
 			     u64 *hdr_flags, void *priv)
 {
@@ -1981,9 +1947,6 @@
 	*iph = (struct iphdr *)((struct ethhdr *)*eh + 1);
 	*tcph = (struct tcphdr *)((struct iphdr *)*iph + 1);
 
-	 if (!lro_segment_ok(*tcph))
-		return -1;
-
 	*hdr_flags = LRO_IPV4 | LRO_TCP;
 	return 0;
 }
@@ -2878,9 +2841,7 @@
 	struct net_lro_mgr *lro_mgr = &q->lro_mgr;
 
 	init_qset_cntxt(q, id);
-	init_timer(&q->tx_reclaim_timer);
-	q->tx_reclaim_timer.data = (unsigned long)q;
-	q->tx_reclaim_timer.function = sge_timer_cb;
+	setup_timer(&q->tx_reclaim_timer, sge_timer_cb, (unsigned long)q);
 
 	q->fl[0].desc = alloc_ring(adapter->pdev, p->fl_size,
 				   sizeof(struct rx_desc),
@@ -2934,6 +2895,7 @@
 	q->rspq.gen = 1;
 	q->rspq.size = p->rspq_size;
 	spin_lock_init(&q->rspq.lock);
+	skb_queue_head_init(&q->rspq.rx_queue);
 
 	q->txq[TXQ_ETH].stop_thres = nports *
 	    flits_to_desc(sgl_len(MAX_SKB_FRAGS + 1) + 3);
@@ -3043,6 +3005,24 @@
 }
 
 /**
+ *	t3_stop_sge_timers - stop SGE timer call backs
+ *	@adap: the adapter
+ *
+ *	Stops each SGE queue set's timer call back
+ */
+void t3_stop_sge_timers(struct adapter *adap)
+{
+	int i;
+
+	for (i = 0; i < SGE_QSETS; ++i) {
+		struct sge_qset *q = &adap->sge.qs[i];
+
+		if (q->tx_reclaim_timer.function)
+			del_timer_sync(&q->tx_reclaim_timer);
+	}
+}
+
+/**
  *	t3_free_sge_resources - free SGE resources
  *	@adap: the adapter
  *
diff --git a/drivers/net/cxgb3/t3_cpl.h b/drivers/net/cxgb3/t3_cpl.h
index 917970e..852c399 100644
--- a/drivers/net/cxgb3/t3_cpl.h
+++ b/drivers/net/cxgb3/t3_cpl.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2004-2007 Chelsio, Inc. All rights reserved.
+ * Copyright (c) 2004-2008 Chelsio, Inc. All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
diff --git a/drivers/net/cxgb3/t3_hw.c b/drivers/net/cxgb3/t3_hw.c
index 04c0e90..968f64b 100644
--- a/drivers/net/cxgb3/t3_hw.c
+++ b/drivers/net/cxgb3/t3_hw.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003-2007 Chelsio, Inc. All rights reserved.
+ * Copyright (c) 2003-2008 Chelsio, Inc. All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
@@ -194,21 +194,18 @@
 static void mi1_init(struct adapter *adap, const struct adapter_info *ai)
 {
 	u32 clkdiv = adap->params.vpd.cclk / (2 * adap->params.vpd.mdc) - 1;
-	u32 val = F_PREEN | V_MDIINV(ai->mdiinv) | V_MDIEN(ai->mdien) |
-	    V_CLKDIV(clkdiv);
+	u32 val = F_PREEN | V_CLKDIV(clkdiv);
 
-	if (!(ai->caps & SUPPORTED_10000baseT_Full))
-		val |= V_ST(1);
 	t3_write_reg(adap, A_MI1_CFG, val);
 }
 
-#define MDIO_ATTEMPTS 10
+#define MDIO_ATTEMPTS 20
 
 /*
- * MI1 read/write operations for direct-addressed PHYs.
+ * MI1 read/write operations for clause 22 PHYs.
  */
-static int mi1_read(struct adapter *adapter, int phy_addr, int mmd_addr,
-		    int reg_addr, unsigned int *valp)
+static int t3_mi1_read(struct adapter *adapter, int phy_addr, int mmd_addr,
+		       int reg_addr, unsigned int *valp)
 {
 	int ret;
 	u32 addr = V_REGADDR(reg_addr) | V_PHYADDR(phy_addr);
@@ -217,16 +214,17 @@
 		return -EINVAL;
 
 	mutex_lock(&adapter->mdio_lock);
+	t3_set_reg_field(adapter, A_MI1_CFG, V_ST(M_ST), V_ST(1));
 	t3_write_reg(adapter, A_MI1_ADDR, addr);
 	t3_write_reg(adapter, A_MI1_OP, V_MDI_OP(2));
-	ret = t3_wait_op_done(adapter, A_MI1_OP, F_BUSY, 0, MDIO_ATTEMPTS, 20);
+	ret = t3_wait_op_done(adapter, A_MI1_OP, F_BUSY, 0, MDIO_ATTEMPTS, 10);
 	if (!ret)
 		*valp = t3_read_reg(adapter, A_MI1_DATA);
 	mutex_unlock(&adapter->mdio_lock);
 	return ret;
 }
 
-static int mi1_write(struct adapter *adapter, int phy_addr, int mmd_addr,
+static int t3_mi1_write(struct adapter *adapter, int phy_addr, int mmd_addr,
 		     int reg_addr, unsigned int val)
 {
 	int ret;
@@ -236,37 +234,51 @@
 		return -EINVAL;
 
 	mutex_lock(&adapter->mdio_lock);
+	t3_set_reg_field(adapter, A_MI1_CFG, V_ST(M_ST), V_ST(1));
 	t3_write_reg(adapter, A_MI1_ADDR, addr);
 	t3_write_reg(adapter, A_MI1_DATA, val);
 	t3_write_reg(adapter, A_MI1_OP, V_MDI_OP(1));
-	ret = t3_wait_op_done(adapter, A_MI1_OP, F_BUSY, 0, MDIO_ATTEMPTS, 20);
+	ret = t3_wait_op_done(adapter, A_MI1_OP, F_BUSY, 0, MDIO_ATTEMPTS, 10);
 	mutex_unlock(&adapter->mdio_lock);
 	return ret;
 }
 
 static const struct mdio_ops mi1_mdio_ops = {
-	mi1_read,
-	mi1_write
+	t3_mi1_read,
+	t3_mi1_write
 };
 
 /*
+ * Performs the address cycle for clause 45 PHYs.
+ * Must be called with the MDIO_LOCK held.
+ */
+static int mi1_wr_addr(struct adapter *adapter, int phy_addr, int mmd_addr,
+		       int reg_addr)
+{
+	u32 addr = V_REGADDR(mmd_addr) | V_PHYADDR(phy_addr);
+
+	t3_set_reg_field(adapter, A_MI1_CFG, V_ST(M_ST), 0);
+	t3_write_reg(adapter, A_MI1_ADDR, addr);
+	t3_write_reg(adapter, A_MI1_DATA, reg_addr);
+	t3_write_reg(adapter, A_MI1_OP, V_MDI_OP(0));
+	return t3_wait_op_done(adapter, A_MI1_OP, F_BUSY, 0,
+			       MDIO_ATTEMPTS, 10);
+}
+
+/*
  * MI1 read/write operations for indirect-addressed PHYs.
  */
 static int mi1_ext_read(struct adapter *adapter, int phy_addr, int mmd_addr,
 			int reg_addr, unsigned int *valp)
 {
 	int ret;
-	u32 addr = V_REGADDR(mmd_addr) | V_PHYADDR(phy_addr);
 
 	mutex_lock(&adapter->mdio_lock);
-	t3_write_reg(adapter, A_MI1_ADDR, addr);
-	t3_write_reg(adapter, A_MI1_DATA, reg_addr);
-	t3_write_reg(adapter, A_MI1_OP, V_MDI_OP(0));
-	ret = t3_wait_op_done(adapter, A_MI1_OP, F_BUSY, 0, MDIO_ATTEMPTS, 20);
+	ret = mi1_wr_addr(adapter, phy_addr, mmd_addr, reg_addr);
 	if (!ret) {
 		t3_write_reg(adapter, A_MI1_OP, V_MDI_OP(3));
 		ret = t3_wait_op_done(adapter, A_MI1_OP, F_BUSY, 0,
-				      MDIO_ATTEMPTS, 20);
+				      MDIO_ATTEMPTS, 10);
 		if (!ret)
 			*valp = t3_read_reg(adapter, A_MI1_DATA);
 	}
@@ -278,18 +290,14 @@
 			 int reg_addr, unsigned int val)
 {
 	int ret;
-	u32 addr = V_REGADDR(mmd_addr) | V_PHYADDR(phy_addr);
 
 	mutex_lock(&adapter->mdio_lock);
-	t3_write_reg(adapter, A_MI1_ADDR, addr);
-	t3_write_reg(adapter, A_MI1_DATA, reg_addr);
-	t3_write_reg(adapter, A_MI1_OP, V_MDI_OP(0));
-	ret = t3_wait_op_done(adapter, A_MI1_OP, F_BUSY, 0, MDIO_ATTEMPTS, 20);
+	ret = mi1_wr_addr(adapter, phy_addr, mmd_addr, reg_addr);
 	if (!ret) {
 		t3_write_reg(adapter, A_MI1_DATA, val);
 		t3_write_reg(adapter, A_MI1_OP, V_MDI_OP(1));
 		ret = t3_wait_op_done(adapter, A_MI1_OP, F_BUSY, 0,
-				      MDIO_ATTEMPTS, 20);
+				      MDIO_ATTEMPTS, 10);
 	}
 	mutex_unlock(&adapter->mdio_lock);
 	return ret;
@@ -400,6 +408,29 @@
 }
 
 /**
+ *	t3_phy_advertise_fiber - set fiber PHY advertisement register
+ *	@phy: the PHY to operate on
+ *	@advert: bitmap of capabilities the PHY should advertise
+ *
+ *	Sets a fiber PHY's advertisement register to advertise the
+ *	requested capabilities.
+ */
+int t3_phy_advertise_fiber(struct cphy *phy, unsigned int advert)
+{
+	unsigned int val = 0;
+
+	if (advert & ADVERTISED_1000baseT_Half)
+		val |= ADVERTISE_1000XHALF;
+	if (advert & ADVERTISED_1000baseT_Full)
+		val |= ADVERTISE_1000XFULL;
+	if (advert & ADVERTISED_Pause)
+		val |= ADVERTISE_1000XPAUSE;
+	if (advert & ADVERTISED_Asym_Pause)
+		val |= ADVERTISE_1000XPSE_ASYM;
+	return mdio_write(phy, 0, MII_ADVERTISE, val);
+}
+
+/**
  *	t3_set_phy_speed_duplex - force PHY speed and duplex
  *	@phy: the PHY to operate on
  *	@speed: requested PHY speed
@@ -434,27 +465,52 @@
 	return mdio_write(phy, 0, MII_BMCR, ctl);
 }
 
+int t3_phy_lasi_intr_enable(struct cphy *phy)
+{
+	return mdio_write(phy, MDIO_DEV_PMA_PMD, LASI_CTRL, 1);
+}
+
+int t3_phy_lasi_intr_disable(struct cphy *phy)
+{
+	return mdio_write(phy, MDIO_DEV_PMA_PMD, LASI_CTRL, 0);
+}
+
+int t3_phy_lasi_intr_clear(struct cphy *phy)
+{
+	u32 val;
+
+	return mdio_read(phy, MDIO_DEV_PMA_PMD, LASI_STAT, &val);
+}
+
+int t3_phy_lasi_intr_handler(struct cphy *phy)
+{
+	unsigned int status;
+	int err = mdio_read(phy, MDIO_DEV_PMA_PMD, LASI_STAT, &status);
+
+	if (err)
+		return err;
+	return (status & 1) ?  cphy_cause_link_change : 0;
+}
+
 static const struct adapter_info t3_adap_info[] = {
-	{2, 0, 0, 0,
+	{2, 0,
 	 F_GPIO2_OEN | F_GPIO4_OEN |
-	 F_GPIO2_OUT_VAL | F_GPIO4_OUT_VAL, F_GPIO3 | F_GPIO5,
-	 0,
+	 F_GPIO2_OUT_VAL | F_GPIO4_OUT_VAL, { S_GPIO3, S_GPIO5 }, 0,
 	 &mi1_mdio_ops, "Chelsio PE9000"},
-	{2, 0, 0, 0,
+	{2, 0,
 	 F_GPIO2_OEN | F_GPIO4_OEN |
-	 F_GPIO2_OUT_VAL | F_GPIO4_OUT_VAL, F_GPIO3 | F_GPIO5,
-	 0,
+	 F_GPIO2_OUT_VAL | F_GPIO4_OUT_VAL, { S_GPIO3, S_GPIO5 }, 0,
 	 &mi1_mdio_ops, "Chelsio T302"},
-	{1, 0, 0, 0,
+	{1, 0,
 	 F_GPIO1_OEN | F_GPIO6_OEN | F_GPIO7_OEN | F_GPIO10_OEN |
 	 F_GPIO11_OEN | F_GPIO1_OUT_VAL | F_GPIO6_OUT_VAL | F_GPIO10_OUT_VAL,
-	 0, SUPPORTED_10000baseT_Full | SUPPORTED_AUI,
+	 { 0 }, SUPPORTED_10000baseT_Full | SUPPORTED_AUI,
 	 &mi1_mdio_ext_ops, "Chelsio T310"},
-	{2, 0, 0, 0,
+	{2, 0,
 	 F_GPIO1_OEN | F_GPIO2_OEN | F_GPIO4_OEN | F_GPIO5_OEN | F_GPIO6_OEN |
 	 F_GPIO7_OEN | F_GPIO10_OEN | F_GPIO11_OEN | F_GPIO1_OUT_VAL |
-	 F_GPIO5_OUT_VAL | F_GPIO6_OUT_VAL | F_GPIO10_OUT_VAL, 0,
-	 SUPPORTED_10000baseT_Full | SUPPORTED_AUI,
+	 F_GPIO5_OUT_VAL | F_GPIO6_OUT_VAL | F_GPIO10_OUT_VAL,
+	 { S_GPIO9, S_GPIO3 }, SUPPORTED_10000baseT_Full | SUPPORTED_AUI,
 	 &mi1_mdio_ext_ops, "Chelsio T320"},
 };
 
@@ -467,28 +523,22 @@
 	return id < ARRAY_SIZE(t3_adap_info) ? &t3_adap_info[id] : NULL;
 }
 
-#define CAPS_1G (SUPPORTED_10baseT_Full | SUPPORTED_100baseT_Full | \
-		 SUPPORTED_1000baseT_Full | SUPPORTED_Autoneg | SUPPORTED_MII)
-#define CAPS_10G (SUPPORTED_10000baseT_Full | SUPPORTED_AUI)
-
-static const struct port_type_info port_types[] = {
-	{NULL},
-	{t3_ael1002_phy_prep, CAPS_10G | SUPPORTED_FIBRE,
-	 "10GBASE-XR"},
-	{t3_vsc8211_phy_prep, CAPS_1G | SUPPORTED_TP | SUPPORTED_IRQ,
-	 "10/100/1000BASE-T"},
-	{NULL, CAPS_1G | SUPPORTED_TP | SUPPORTED_IRQ,
-	 "10/100/1000BASE-T"},
-	{t3_xaui_direct_phy_prep, CAPS_10G | SUPPORTED_TP, "10GBASE-CX4"},
-	{NULL, CAPS_10G, "10GBASE-KX4"},
-	{t3_qt2045_phy_prep, CAPS_10G | SUPPORTED_TP, "10GBASE-CX4"},
-	{t3_ael1006_phy_prep, CAPS_10G | SUPPORTED_FIBRE,
-	 "10GBASE-SR"},
-	{NULL, CAPS_10G | SUPPORTED_TP, "10GBASE-CX4"},
+struct port_type_info {
+	int (*phy_prep)(struct cphy *phy, struct adapter *adapter,
+			int phy_addr, const struct mdio_ops *ops);
 };
 
-#undef CAPS_1G
-#undef CAPS_10G
+static const struct port_type_info port_types[] = {
+	{ NULL },
+	{ t3_ael1002_phy_prep },
+	{ t3_vsc8211_phy_prep },
+	{ NULL},
+	{ t3_xaui_direct_phy_prep },
+	{ t3_ael2005_phy_prep },
+	{ t3_qt2045_phy_prep },
+	{ t3_ael1006_phy_prep },
+	{ NULL },
+};
 
 #define VPD_ENTRY(name, len) \
 	u8 name##_kword[2]; u8 name##_len; u8 name##_data[len]
@@ -1132,6 +1182,15 @@
 
 	phy->ops->get_link_status(phy, &link_ok, &speed, &duplex, &fc);
 
+	if (lc->requested_fc & PAUSE_AUTONEG)
+		fc &= lc->requested_fc;
+	else
+		fc = lc->requested_fc & (PAUSE_RX | PAUSE_TX);
+
+	if (link_ok == lc->link_ok && speed == lc->speed &&
+	    duplex == lc->duplex && fc == lc->fc)
+		return;                            /* nothing changed */
+
 	if (link_ok != lc->link_ok && adapter->params.rev > 0 &&
 	    uses_xaui(adapter)) {
 		if (link_ok)
@@ -1142,10 +1201,6 @@
 	lc->link_ok = link_ok;
 	lc->speed = speed < 0 ? SPEED_INVALID : speed;
 	lc->duplex = duplex < 0 ? DUPLEX_INVALID : duplex;
-	if (lc->requested_fc & PAUSE_AUTONEG)
-		fc &= lc->requested_fc;
-	else
-		fc = lc->requested_fc & (PAUSE_RX | PAUSE_TX);
 
 	if (link_ok && speed >= 0 && lc->autoneg == AUTONEG_ENABLE) {
 		/* Set MAC speed, duplex, and flow control to match PHY. */
@@ -1191,7 +1246,6 @@
 						   fc);
 			/* Also disables autoneg */
 			phy->ops->set_speed_duplex(phy, lc->speed, lc->duplex);
-			phy->ops->reset(phy, 0);
 		} else
 			phy->ops->autoneg_enable(phy);
 	} else {
@@ -1221,7 +1275,7 @@
 	unsigned int mask;	/* bits to check in interrupt status */
 	const char *msg;	/* message to print or NULL */
 	short stat_idx;		/* stat counter to increment or -1 */
-	unsigned short fatal:1;	/* whether the condition reported is fatal */
+	unsigned short fatal;	/* whether the condition reported is fatal */
 };
 
 /**
@@ -1682,25 +1736,23 @@
  */
 int t3_phy_intr_handler(struct adapter *adapter)
 {
-	u32 mask, gpi = adapter_info(adapter)->gpio_intr;
 	u32 i, cause = t3_read_reg(adapter, A_T3DBG_INT_CAUSE);
 
 	for_each_port(adapter, i) {
 		struct port_info *p = adap2pinfo(adapter, i);
 
-		mask = gpi - (gpi & (gpi - 1));
-		gpi -= mask;
-
-		if (!(p->port_type->caps & SUPPORTED_IRQ))
+		if (!(p->phy.caps & SUPPORTED_IRQ))
 			continue;
 
-		if (cause & mask) {
+		if (cause & (1 << adapter_info(adapter)->gpio_intr[i])) {
 			int phy_cause = p->phy.ops->intr_handler(&p->phy);
 
 			if (phy_cause & cphy_cause_link_change)
 				t3_link_changed(adapter, i);
 			if (phy_cause & cphy_cause_fifo_error)
 				p->phy.fifo_errors++;
+			if (phy_cause & cphy_cause_module_change)
+				t3_os_phymod_changed(adapter, i);
 		}
 	}
 
@@ -1763,6 +1815,17 @@
 	return 1;
 }
 
+static unsigned int calc_gpio_intr(struct adapter *adap)
+{
+	unsigned int i, gpi_intr = 0;
+
+	for_each_port(adap, i)
+		if ((adap2pinfo(adap, i)->phy.caps & SUPPORTED_IRQ) &&
+		    adapter_info(adap)->gpio_intr[i])
+			gpi_intr |= 1 << adapter_info(adap)->gpio_intr[i];
+	return gpi_intr;
+}
+
 /**
  *	t3_intr_enable - enable interrupts
  *	@adapter: the adapter whose interrupts should be enabled
@@ -1805,10 +1868,8 @@
 		t3_write_reg(adapter, A_ULPTX_INT_ENABLE, ULPTX_INTR_MASK);
 	}
 
-	t3_write_reg(adapter, A_T3DBG_GPIO_ACT_LOW,
-		     adapter_info(adapter)->gpio_intr);
-	t3_write_reg(adapter, A_T3DBG_INT_ENABLE,
-		     adapter_info(adapter)->gpio_intr);
+	t3_write_reg(adapter, A_T3DBG_INT_ENABLE, calc_gpio_intr(adapter));
+
 	if (is_pcie(adapter))
 		t3_write_reg(adapter, A_PCIE_INT_ENABLE, PCIE_INTR_MASK);
 	else
@@ -3329,6 +3390,8 @@
 	init_hw_for_avail_ports(adapter, adapter->params.nports);
 	t3_sge_init(adapter, &adapter->params.sge);
 
+	t3_write_reg(adapter, A_T3DBG_GPIO_ACT_LOW, calc_gpio_intr(adapter));
+
 	t3_write_reg(adapter, A_CIM_HOST_ACC_DATA, vpd->uclk | fw_params);
 	t3_write_reg(adapter, A_CIM_BOOT_CFG,
 		     V_BOOTADDR(FW_FLASH_BOOT_ADDR >> 2));
@@ -3488,7 +3551,7 @@
  * Older PCIe cards lose their config space during reset, PCI-X
  * ones don't.
  */
-static int t3_reset_adapter(struct adapter *adapter)
+int t3_reset_adapter(struct adapter *adapter)
 {
 	int i, save_and_restore_pcie =
 	    adapter->params.rev < T3_REV_B2 && is_pcie(adapter);
@@ -3556,7 +3619,7 @@
 		    int reset)
 {
 	int ret;
-	unsigned int i, j = 0;
+	unsigned int i, j = -1;
 
 	get_pci_mode(adapter, &adapter->params.pci);
 
@@ -3620,16 +3683,18 @@
 
 	for_each_port(adapter, i) {
 		u8 hw_addr[6];
+		const struct port_type_info *pti;
 		struct port_info *p = adap2pinfo(adapter, i);
 
-		while (!adapter->params.vpd.port_type[j])
-			++j;
+		while (!adapter->params.vpd.port_type[++j])
+			;
 
-		p->port_type = &port_types[adapter->params.vpd.port_type[j]];
-		p->port_type->phy_prep(&p->phy, adapter, ai->phy_base_addr + j,
-				       ai->mdio_ops);
+		pti = &port_types[adapter->params.vpd.port_type[j]];
+		ret = pti->phy_prep(&p->phy, adapter, ai->phy_base_addr + j,
+				    ai->mdio_ops);
+		if (ret)
+			return ret;
 		mac_prep(&p->mac, adapter, j);
-		++j;
 
 		/*
 		 * The VPD EEPROM stores the base Ethernet address for the
@@ -3643,9 +3708,9 @@
 		       ETH_ALEN);
 		memcpy(adapter->port[i]->perm_addr, hw_addr,
 		       ETH_ALEN);
-		init_link_config(&p->link_config, p->port_type->caps);
+		init_link_config(&p->link_config, p->phy.caps);
 		p->phy.ops->power_down(&p->phy, 1);
-		if (!(p->port_type->caps & SUPPORTED_IRQ))
+		if (!(p->phy.caps & SUPPORTED_IRQ))
 			adapter->params.linkpoll_period = 10;
 	}
 
@@ -3661,7 +3726,7 @@
 int t3_replay_prep_adapter(struct adapter *adapter)
 {
 	const struct adapter_info *ai = adapter->params.info;
-	unsigned int i, j = 0;
+	unsigned int i, j = -1;
 	int ret;
 
 	early_hw_init(adapter, ai);
@@ -3670,15 +3735,17 @@
 		return ret;
 
 	for_each_port(adapter, i) {
+		const struct port_type_info *pti;
 		struct port_info *p = adap2pinfo(adapter, i);
-		while (!adapter->params.vpd.port_type[j])
-			++j;
 
-		p->port_type->phy_prep(&p->phy, adapter, ai->phy_base_addr + j,
-					ai->mdio_ops);
+		while (!adapter->params.vpd.port_type[++j])
+			;
 
+		pti = &port_types[adapter->params.vpd.port_type[j]];
+		ret = pti->phy_prep(&p->phy, adapter, p->phy.addr, NULL);
+		if (ret)
+			return ret;
 		p->phy.ops->power_down(&p->phy, 1);
-		++j;
 	}
 
 return 0;
diff --git a/drivers/net/cxgb3/t3cdev.h b/drivers/net/cxgb3/t3cdev.h
index 0a21cfb..be55e9a 100644
--- a/drivers/net/cxgb3/t3cdev.h
+++ b/drivers/net/cxgb3/t3cdev.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2006-2007 Chelsio Communications.  All rights reserved.
+ * Copyright (C) 2006-2008 Chelsio Communications.  All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
diff --git a/drivers/net/cxgb3/version.h b/drivers/net/cxgb3/version.h
index 29db711..bb8698a 100644
--- a/drivers/net/cxgb3/version.h
+++ b/drivers/net/cxgb3/version.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003-2007 Chelsio, Inc. All rights reserved.
+ * Copyright (c) 2003-2008 Chelsio, Inc. All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
@@ -35,7 +35,7 @@
 #define DRV_DESC "Chelsio T3 Network Driver"
 #define DRV_NAME "cxgb3"
 /* Driver version */
-#define DRV_VERSION "1.0-ko"
+#define DRV_VERSION "1.1.0-ko"
 
 /* Firmware version */
 #define FW_VERSION_MAJOR 7
diff --git a/drivers/net/cxgb3/vsc8211.c b/drivers/net/cxgb3/vsc8211.c
index eee4285..33f956b 100644
--- a/drivers/net/cxgb3/vsc8211.c
+++ b/drivers/net/cxgb3/vsc8211.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005-2007 Chelsio, Inc. All rights reserved.
+ * Copyright (c) 2005-2008 Chelsio, Inc. All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
@@ -33,28 +33,40 @@
 
 /* VSC8211 PHY specific registers. */
 enum {
+	VSC8211_SIGDET_CTRL = 19,
+	VSC8211_EXT_CTRL = 23,
 	VSC8211_INTR_ENABLE = 25,
 	VSC8211_INTR_STATUS = 26,
+	VSC8211_LED_CTRL = 27,
 	VSC8211_AUX_CTRL_STAT = 28,
+	VSC8211_EXT_PAGE_AXS = 31,
 };
 
 enum {
 	VSC_INTR_RX_ERR = 1 << 0,
-	VSC_INTR_MS_ERR = 1 << 1,	/* master/slave resolution error */
-	VSC_INTR_CABLE = 1 << 2,	/* cable impairment */
-	VSC_INTR_FALSE_CARR = 1 << 3,	/* false carrier */
-	VSC_INTR_MEDIA_CHG = 1 << 4,	/* AMS media change */
-	VSC_INTR_RX_FIFO = 1 << 5,	/* Rx FIFO over/underflow */
-	VSC_INTR_TX_FIFO = 1 << 6,	/* Tx FIFO over/underflow */
-	VSC_INTR_DESCRAMBL = 1 << 7,	/* descrambler lock-lost */
-	VSC_INTR_SYMBOL_ERR = 1 << 8,	/* symbol error */
-	VSC_INTR_NEG_DONE = 1 << 10,	/* autoneg done */
-	VSC_INTR_NEG_ERR = 1 << 11,	/* autoneg error */
-	VSC_INTR_LINK_CHG = 1 << 13,	/* link change */
-	VSC_INTR_ENABLE = 1 << 15,	/* interrupt enable */
+	VSC_INTR_MS_ERR = 1 << 1,  /* master/slave resolution error */
+	VSC_INTR_CABLE = 1 << 2,  /* cable impairment */
+	VSC_INTR_FALSE_CARR = 1 << 3,  /* false carrier */
+	VSC_INTR_MEDIA_CHG = 1 << 4,  /* AMS media change */
+	VSC_INTR_RX_FIFO = 1 << 5,  /* Rx FIFO over/underflow */
+	VSC_INTR_TX_FIFO = 1 << 6,  /* Tx FIFO over/underflow */
+	VSC_INTR_DESCRAMBL = 1 << 7,  /* descrambler lock-lost */
+	VSC_INTR_SYMBOL_ERR = 1 << 8,  /* symbol error */
+	VSC_INTR_NEG_DONE = 1 << 10, /* autoneg done */
+	VSC_INTR_NEG_ERR = 1 << 11, /* autoneg error */
+	VSC_INTR_DPLX_CHG = 1 << 12, /* duplex change */
+	VSC_INTR_LINK_CHG = 1 << 13, /* link change */
+	VSC_INTR_SPD_CHG = 1 << 14, /* speed change */
+	VSC_INTR_ENABLE = 1 << 15, /* interrupt enable */
+};
+
+enum {
+	VSC_CTRL_CLAUSE37_VIEW = 1 << 4,   /* Switch to Clause 37 view */
+	VSC_CTRL_MEDIA_MODE_HI = 0xf000    /* High part of media mode select */
 };
 
 #define CFG_CHG_INTR_MASK (VSC_INTR_LINK_CHG | VSC_INTR_NEG_ERR | \
+			   VSC_INTR_DPLX_CHG | VSC_INTR_SPD_CHG | \
 	 		   VSC_INTR_NEG_DONE)
 #define INTR_MASK (CFG_CHG_INTR_MASK | VSC_INTR_TX_FIFO | VSC_INTR_RX_FIFO | \
 		   VSC_INTR_ENABLE)
@@ -184,6 +196,112 @@
 	return 0;
 }
 
+static int vsc8211_get_link_status_fiber(struct cphy *cphy, int *link_ok,
+					 int *speed, int *duplex, int *fc)
+{
+	unsigned int bmcr, status, lpa, adv;
+	int err, sp = -1, dplx = -1, pause = 0;
+
+	err = mdio_read(cphy, 0, MII_BMCR, &bmcr);
+	if (!err)
+		err = mdio_read(cphy, 0, MII_BMSR, &status);
+	if (err)
+		return err;
+
+	if (link_ok) {
+		/*
+		 * BMSR_LSTATUS is latch-low, so if it is 0 we need to read it
+		 * once more to get the current link state.
+		 */
+		if (!(status & BMSR_LSTATUS))
+			err = mdio_read(cphy, 0, MII_BMSR, &status);
+		if (err)
+			return err;
+		*link_ok = (status & BMSR_LSTATUS) != 0;
+	}
+	if (!(bmcr & BMCR_ANENABLE)) {
+		dplx = (bmcr & BMCR_FULLDPLX) ? DUPLEX_FULL : DUPLEX_HALF;
+		if (bmcr & BMCR_SPEED1000)
+			sp = SPEED_1000;
+		else if (bmcr & BMCR_SPEED100)
+			sp = SPEED_100;
+		else
+			sp = SPEED_10;
+	} else if (status & BMSR_ANEGCOMPLETE) {
+		err = mdio_read(cphy, 0, MII_LPA, &lpa);
+		if (!err)
+			err = mdio_read(cphy, 0, MII_ADVERTISE, &adv);
+		if (err)
+			return err;
+
+		if (adv & lpa & ADVERTISE_1000XFULL) {
+			dplx = DUPLEX_FULL;
+			sp = SPEED_1000;
+		} else if (adv & lpa & ADVERTISE_1000XHALF) {
+			dplx = DUPLEX_HALF;
+			sp = SPEED_1000;
+		}
+
+		if (fc && dplx == DUPLEX_FULL) {
+			if (lpa & adv & ADVERTISE_1000XPAUSE)
+				pause = PAUSE_RX | PAUSE_TX;
+			else if ((lpa & ADVERTISE_1000XPAUSE) &&
+				 (adv & lpa & ADVERTISE_1000XPSE_ASYM))
+				pause = PAUSE_TX;
+			else if ((lpa & ADVERTISE_1000XPSE_ASYM) &&
+				 (adv & ADVERTISE_1000XPAUSE))
+				pause = PAUSE_RX;
+		}
+	}
+	if (speed)
+		*speed = sp;
+	if (duplex)
+		*duplex = dplx;
+	if (fc)
+		*fc = pause;
+	return 0;
+}
+
+/*
+ * Enable/disable auto MDI/MDI-X in forced link speed mode.
+ */
+static int vsc8211_set_automdi(struct cphy *phy, int enable)
+{
+	int err;
+
+	err = mdio_write(phy, 0, VSC8211_EXT_PAGE_AXS, 0x52b5);
+	if (err)
+		return err;
+
+	err = mdio_write(phy, 0, 18, 0x12);
+	if (err)
+		return err;
+
+	err = mdio_write(phy, 0, 17, enable ? 0x2803 : 0x3003);
+	if (err)
+		return err;
+
+	err = mdio_write(phy, 0, 16, 0x87fa);
+	if (err)
+		return err;
+
+	err = mdio_write(phy, 0, VSC8211_EXT_PAGE_AXS, 0);
+	if (err)
+		return err;
+
+	return 0;
+}
+
+int vsc8211_set_speed_duplex(struct cphy *phy, int speed, int duplex)
+{
+	int err;
+
+	err = t3_set_phy_speed_duplex(phy, speed, duplex);
+	if (!err)
+		err = vsc8211_set_automdi(phy, 1);
+	return err;
+}
+
 static int vsc8211_power_down(struct cphy *cphy, int enable)
 {
 	return t3_mdio_change_bits(cphy, 0, MII_BMCR, BMCR_PDOWN,
@@ -221,8 +339,66 @@
 	.power_down = vsc8211_power_down,
 };
 
-void t3_vsc8211_phy_prep(struct cphy *phy, struct adapter *adapter,
-			 int phy_addr, const struct mdio_ops *mdio_ops)
+static struct cphy_ops vsc8211_fiber_ops = {
+	.reset = vsc8211_reset,
+	.intr_enable = vsc8211_intr_enable,
+	.intr_disable = vsc8211_intr_disable,
+	.intr_clear = vsc8211_intr_clear,
+	.intr_handler = vsc8211_intr_handler,
+	.autoneg_enable = vsc8211_autoneg_enable,
+	.autoneg_restart = vsc8211_autoneg_restart,
+	.advertise = t3_phy_advertise_fiber,
+	.set_speed_duplex = t3_set_phy_speed_duplex,
+	.get_link_status = vsc8211_get_link_status_fiber,
+	.power_down = vsc8211_power_down,
+};
+
+int t3_vsc8211_phy_prep(struct cphy *phy, struct adapter *adapter,
+			int phy_addr, const struct mdio_ops *mdio_ops)
 {
-	cphy_init(phy, adapter, phy_addr, &vsc8211_ops, mdio_ops);
+	int err;
+	unsigned int val;
+
+	cphy_init(phy, adapter, phy_addr, &vsc8211_ops, mdio_ops,
+		  SUPPORTED_10baseT_Full | SUPPORTED_100baseT_Full |
+		  SUPPORTED_1000baseT_Full | SUPPORTED_Autoneg | SUPPORTED_MII |
+		  SUPPORTED_TP | SUPPORTED_IRQ, "10/100/1000BASE-T");
+	msleep(20);       /* PHY needs ~10ms to start responding to MDIO */
+
+	err = mdio_read(phy, 0, VSC8211_EXT_CTRL, &val);
+	if (err)
+		return err;
+	if (val & VSC_CTRL_MEDIA_MODE_HI) {
+		/* copper interface, just need to configure the LEDs */
+		return mdio_write(phy, 0, VSC8211_LED_CTRL, 0x100);
+	}
+
+	phy->caps = SUPPORTED_1000baseT_Full | SUPPORTED_Autoneg |
+		    SUPPORTED_MII | SUPPORTED_FIBRE | SUPPORTED_IRQ;
+	phy->desc = "1000BASE-X";
+	phy->ops = &vsc8211_fiber_ops;
+
+	err = mdio_write(phy, 0, VSC8211_EXT_PAGE_AXS, 1);
+	if (err)
+		return err;
+
+	err = mdio_write(phy, 0, VSC8211_SIGDET_CTRL, 1);
+	if (err)
+		return err;
+
+	err = mdio_write(phy, 0, VSC8211_EXT_PAGE_AXS, 0);
+	if (err)
+		return err;
+
+	err = mdio_write(phy, 0, VSC8211_EXT_CTRL,
+			 val | VSC_CTRL_CLAUSE37_VIEW);
+	if (err)
+		return err;
+
+	err = vsc8211_reset(phy, 0);
+	if (err)
+		return err;
+
+	udelay(5); /* delay after reset before next SMI */
+	return 0;
 }
diff --git a/drivers/net/cxgb3/xgmac.c b/drivers/net/cxgb3/xgmac.c
index ffdc0a1..9d77869 100644
--- a/drivers/net/cxgb3/xgmac.c
+++ b/drivers/net/cxgb3/xgmac.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005-2007 Chelsio, Inc. All rights reserved.
+ * Copyright (c) 2005-2008 Chelsio, Inc. All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
diff --git a/drivers/net/e100.c b/drivers/net/e100.c
index 453115a..3d69fae 100644
--- a/drivers/net/e100.c
+++ b/drivers/net/e100.c
@@ -191,7 +191,7 @@
 #define DPRINTK(nlevel, klevel, fmt, args...) \
 	(void)((NETIF_MSG_##nlevel & nic->msg_enable) && \
 	printk(KERN_##klevel PFX "%s: %s: " fmt, nic->netdev->name, \
-		__FUNCTION__ , ## args))
+		__func__ , ## args))
 
 #define INTEL_8255X_ETHERNET_DEVICE(device_id, ich) {\
 	PCI_VENDOR_ID_INTEL, device_id, PCI_ANY_ID, PCI_ANY_ID, \
@@ -2738,9 +2738,7 @@
 		nic->flags |= wol_magic;
 
 	/* ack any pending wake events, disable PME */
-	err = pci_enable_wake(pdev, 0, 0);
-	if (err)
-		DPRINTK(PROBE, ERR, "Error clearing wake event\n");
+	pci_pme_active(pdev, false);
 
 	strcpy(netdev->name, "eth%d");
 	if((err = register_netdev(netdev))) {
diff --git a/drivers/net/e1000/e1000.h b/drivers/net/e1000/e1000.h
index 19e317e..62f6297 100644
--- a/drivers/net/e1000/e1000.h
+++ b/drivers/net/e1000/e1000.h
@@ -155,8 +155,6 @@
 #endif
 
 #define E1000_MNG_VLAN_NONE (-1)
-/* Number of packet split data buffers (not including the header buffer) */
-#define PS_PAGE_BUFFERS (MAX_PS_BUFFERS - 1)
 
 /* wrapper around a pointer to a socket buffer,
  * so a DMA handle can be stored along with the buffer */
@@ -168,14 +166,6 @@
 	u16 next_to_watch;
 };
 
-struct e1000_ps_page {
-	struct page *ps_page[PS_PAGE_BUFFERS];
-};
-
-struct e1000_ps_page_dma {
-	u64 ps_page_dma[PS_PAGE_BUFFERS];
-};
-
 struct e1000_tx_ring {
 	/* pointer to the descriptor ring memory */
 	void *desc;
@@ -213,9 +203,6 @@
 	unsigned int next_to_clean;
 	/* array of buffer information structs */
 	struct e1000_buffer *buffer_info;
-	/* arrays of page information for packet split */
-	struct e1000_ps_page *ps_page;
-	struct e1000_ps_page_dma *ps_page_dma;
 
 	/* cpu for rx queue */
 	int cpu;
@@ -228,8 +215,6 @@
 	((((R)->next_to_clean > (R)->next_to_use)			\
 	  ? 0 : (R)->count) + (R)->next_to_clean - (R)->next_to_use - 1)
 
-#define E1000_RX_DESC_PS(R, i)						\
-	(&(((union e1000_rx_desc_packet_split *)((R).desc))[i]))
 #define E1000_RX_DESC_EXT(R, i)						\
 	(&(((union e1000_rx_desc_extended *)((R).desc))[i]))
 #define E1000_GET_DESC(R, i, type)	(&(((struct type *)((R).desc))[i]))
@@ -311,10 +296,8 @@
 	u32 rx_int_delay;
 	u32 rx_abs_int_delay;
 	bool rx_csum;
-	unsigned int rx_ps_pages;
 	u32 gorcl;
 	u64 gorcl_old;
-	u16 rx_ps_bsize0;
 
 	/* OS defined structs */
 	struct net_device *netdev;
diff --git a/drivers/net/e1000/e1000_hw.c b/drivers/net/e1000/e1000_hw.c
index 9d6edf3..d04eef53 100644
--- a/drivers/net/e1000/e1000_hw.c
+++ b/drivers/net/e1000/e1000_hw.c
@@ -144,6 +144,8 @@
 static u8 e1000_calculate_mng_checksum(char *buffer, u32 length);
 static s32 e1000_configure_kmrn_for_10_100(struct e1000_hw *hw, u16 duplex);
 static s32 e1000_configure_kmrn_for_1000(struct e1000_hw *hw);
+static s32 e1000_do_read_eeprom(struct e1000_hw *hw, u16 offset, u16 words, u16 *data);
+static s32 e1000_do_write_eeprom(struct e1000_hw *hw, u16 offset, u16 words, u16 *data);
 
 /* IGP cable length table */
 static const
@@ -168,6 +170,8 @@
       83, 89, 95, 100, 105, 109, 113, 116, 119, 122, 124,
       104, 109, 114, 118, 121, 124};
 
+static DEFINE_SPINLOCK(e1000_eeprom_lock);
+
 /******************************************************************************
  * Set the phy type member in the hw struct.
  *
@@ -4904,6 +4908,15 @@
  *****************************************************************************/
 s32 e1000_read_eeprom(struct e1000_hw *hw, u16 offset, u16 words, u16 *data)
 {
+    s32 ret;
+    spin_lock(&e1000_eeprom_lock);
+    ret = e1000_do_read_eeprom(hw, offset, words, data);
+    spin_unlock(&e1000_eeprom_lock);
+    return ret;
+}
+
+static s32 e1000_do_read_eeprom(struct e1000_hw *hw, u16 offset, u16 words, u16 *data)
+{
     struct e1000_eeprom_info *eeprom = &hw->eeprom;
     u32 i = 0;
 
@@ -5236,6 +5249,16 @@
  *****************************************************************************/
 s32 e1000_write_eeprom(struct e1000_hw *hw, u16 offset, u16 words, u16 *data)
 {
+    s32 ret;
+    spin_lock(&e1000_eeprom_lock);
+    ret = e1000_do_write_eeprom(hw, offset, words, data);
+    spin_unlock(&e1000_eeprom_lock);
+    return ret;
+}
+
+
+static s32 e1000_do_write_eeprom(struct e1000_hw *hw, u16 offset, u16 words, u16 *data)
+{
     struct e1000_eeprom_info *eeprom = &hw->eeprom;
     s32 status = 0;
 
diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c
index ad6da7b..fac8215 100644
--- a/drivers/net/e1000/e1000_main.c
+++ b/drivers/net/e1000/e1000_main.c
@@ -137,15 +137,9 @@
 static bool e1000_clean_rx_irq(struct e1000_adapter *adapter,
 			       struct e1000_rx_ring *rx_ring,
 			       int *work_done, int work_to_do);
-static bool e1000_clean_rx_irq_ps(struct e1000_adapter *adapter,
-				  struct e1000_rx_ring *rx_ring,
-				  int *work_done, int work_to_do);
 static void e1000_alloc_rx_buffers(struct e1000_adapter *adapter,
                                    struct e1000_rx_ring *rx_ring,
 				   int cleaned_count);
-static void e1000_alloc_rx_buffers_ps(struct e1000_adapter *adapter,
-                                      struct e1000_rx_ring *rx_ring,
-				      int cleaned_count);
 static int e1000_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd);
 static int e1000_mii_ioctl(struct net_device *netdev, struct ifreq *ifr,
 			   int cmd);
@@ -1053,6 +1047,11 @@
 
 	netdev->features |= NETIF_F_LLTX;
 
+	netdev->vlan_features |= NETIF_F_TSO;
+	netdev->vlan_features |= NETIF_F_TSO6;
+	netdev->vlan_features |= NETIF_F_HW_CSUM;
+	netdev->vlan_features |= NETIF_F_SG;
+
 	adapter->en_mng_pt = e1000_enable_mng_pass_thru(hw);
 
 	/* initialize eeprom parameters */
@@ -1331,7 +1330,6 @@
 	pci_read_config_word(pdev, PCI_COMMAND, &hw->pci_cmd_word);
 
 	adapter->rx_buffer_len = MAXIMUM_ETHERNET_VLAN_SIZE;
-	adapter->rx_ps_bsize0 = E1000_RXBUFFER_128;
 	hw->max_frame_size = netdev->mtu +
 			     ENET_HEADER_SIZE + ETHERNET_FCS_SIZE;
 	hw->min_frame_size = MINIMUM_ETHERNET_FRAME_SIZE;
@@ -1815,26 +1813,6 @@
 	}
 	memset(rxdr->buffer_info, 0, size);
 
-	rxdr->ps_page = kcalloc(rxdr->count, sizeof(struct e1000_ps_page),
-	                        GFP_KERNEL);
-	if (!rxdr->ps_page) {
-		vfree(rxdr->buffer_info);
-		DPRINTK(PROBE, ERR,
-		"Unable to allocate memory for the receive descriptor ring\n");
-		return -ENOMEM;
-	}
-
-	rxdr->ps_page_dma = kcalloc(rxdr->count,
-	                            sizeof(struct e1000_ps_page_dma),
-	                            GFP_KERNEL);
-	if (!rxdr->ps_page_dma) {
-		vfree(rxdr->buffer_info);
-		kfree(rxdr->ps_page);
-		DPRINTK(PROBE, ERR,
-		"Unable to allocate memory for the receive descriptor ring\n");
-		return -ENOMEM;
-	}
-
 	if (hw->mac_type <= e1000_82547_rev_2)
 		desc_len = sizeof(struct e1000_rx_desc);
 	else
@@ -1852,8 +1830,6 @@
 		"Unable to allocate memory for the receive descriptor ring\n");
 setup_rx_desc_die:
 		vfree(rxdr->buffer_info);
-		kfree(rxdr->ps_page);
-		kfree(rxdr->ps_page_dma);
 		return -ENOMEM;
 	}
 
@@ -1932,11 +1908,7 @@
 static void e1000_setup_rctl(struct e1000_adapter *adapter)
 {
 	struct e1000_hw *hw = &adapter->hw;
-	u32 rctl, rfctl;
-	u32 psrctl = 0;
-#ifndef CONFIG_E1000_DISABLE_PACKET_SPLIT
-	u32 pages = 0;
-#endif
+	u32 rctl;
 
 	rctl = er32(RCTL);
 
@@ -1988,55 +1960,6 @@
 			break;
 	}
 
-#ifndef CONFIG_E1000_DISABLE_PACKET_SPLIT
-	/* 82571 and greater support packet-split where the protocol
-	 * header is placed in skb->data and the packet data is
-	 * placed in pages hanging off of skb_shinfo(skb)->nr_frags.
-	 * In the case of a non-split, skb->data is linearly filled,
-	 * followed by the page buffers.  Therefore, skb->data is
-	 * sized to hold the largest protocol header.
-	 */
-	/* allocations using alloc_page take too long for regular MTU
-	 * so only enable packet split for jumbo frames */
-	pages = PAGE_USE_COUNT(adapter->netdev->mtu);
-	if ((hw->mac_type >= e1000_82571) && (pages <= 3) &&
-	    PAGE_SIZE <= 16384 && (rctl & E1000_RCTL_LPE))
-		adapter->rx_ps_pages = pages;
-	else
-		adapter->rx_ps_pages = 0;
-#endif
-	if (adapter->rx_ps_pages) {
-		/* Configure extra packet-split registers */
-		rfctl = er32(RFCTL);
-		rfctl |= E1000_RFCTL_EXTEN;
-		/* disable packet split support for IPv6 extension headers,
-		 * because some malformed IPv6 headers can hang the RX */
-		rfctl |= (E1000_RFCTL_IPV6_EX_DIS |
-		          E1000_RFCTL_NEW_IPV6_EXT_DIS);
-
-		ew32(RFCTL, rfctl);
-
-		rctl |= E1000_RCTL_DTYP_PS;
-
-		psrctl |= adapter->rx_ps_bsize0 >>
-			E1000_PSRCTL_BSIZE0_SHIFT;
-
-		switch (adapter->rx_ps_pages) {
-		case 3:
-			psrctl |= PAGE_SIZE <<
-				E1000_PSRCTL_BSIZE3_SHIFT;
-		case 2:
-			psrctl |= PAGE_SIZE <<
-				E1000_PSRCTL_BSIZE2_SHIFT;
-		case 1:
-			psrctl |= PAGE_SIZE >>
-				E1000_PSRCTL_BSIZE1_SHIFT;
-			break;
-		}
-
-		ew32(PSRCTL, psrctl);
-	}
-
 	ew32(RCTL, rctl);
 }
 
@@ -2053,18 +1976,10 @@
 	struct e1000_hw *hw = &adapter->hw;
 	u32 rdlen, rctl, rxcsum, ctrl_ext;
 
-	if (adapter->rx_ps_pages) {
-		/* this is a 32 byte descriptor */
-		rdlen = adapter->rx_ring[0].count *
-			sizeof(union e1000_rx_desc_packet_split);
-		adapter->clean_rx = e1000_clean_rx_irq_ps;
-		adapter->alloc_rx_buf = e1000_alloc_rx_buffers_ps;
-	} else {
-		rdlen = adapter->rx_ring[0].count *
-			sizeof(struct e1000_rx_desc);
-		adapter->clean_rx = e1000_clean_rx_irq;
-		adapter->alloc_rx_buf = e1000_alloc_rx_buffers;
-	}
+	rdlen = adapter->rx_ring[0].count *
+		sizeof(struct e1000_rx_desc);
+	adapter->clean_rx = e1000_clean_rx_irq;
+	adapter->alloc_rx_buf = e1000_alloc_rx_buffers;
 
 	/* disable receives while setting up the descriptors */
 	rctl = er32(RCTL);
@@ -2109,28 +2024,14 @@
 	/* Enable 82543 Receive Checksum Offload for TCP and UDP */
 	if (hw->mac_type >= e1000_82543) {
 		rxcsum = er32(RXCSUM);
-		if (adapter->rx_csum) {
+		if (adapter->rx_csum)
 			rxcsum |= E1000_RXCSUM_TUOFL;
-
-			/* Enable 82571 IPv4 payload checksum for UDP fragments
-			 * Must be used in conjunction with packet-split. */
-			if ((hw->mac_type >= e1000_82571) &&
-			    (adapter->rx_ps_pages)) {
-				rxcsum |= E1000_RXCSUM_IPPCSE;
-			}
-		} else {
-			rxcsum &= ~E1000_RXCSUM_TUOFL;
+		else
 			/* don't need to clear IPPCSE as it defaults to 0 */
-		}
+			rxcsum &= ~E1000_RXCSUM_TUOFL;
 		ew32(RXCSUM, rxcsum);
 	}
 
-	/* enable early receives on 82573, only takes effect if using > 2048
-	 * byte total frame size.  for example only for jumbo frames */
-#define E1000_ERT_2048 0x100
-	if (hw->mac_type == e1000_82573)
-		ew32(ERT, E1000_ERT_2048);
-
 	/* Enable Receives */
 	ew32(RCTL, rctl);
 }
@@ -2256,10 +2157,6 @@
 
 	vfree(rx_ring->buffer_info);
 	rx_ring->buffer_info = NULL;
-	kfree(rx_ring->ps_page);
-	rx_ring->ps_page = NULL;
-	kfree(rx_ring->ps_page_dma);
-	rx_ring->ps_page_dma = NULL;
 
 	pci_free_consistent(pdev, rx_ring->size, rx_ring->desc, rx_ring->dma);
 
@@ -2292,11 +2189,9 @@
 {
 	struct e1000_hw *hw = &adapter->hw;
 	struct e1000_buffer *buffer_info;
-	struct e1000_ps_page *ps_page;
-	struct e1000_ps_page_dma *ps_page_dma;
 	struct pci_dev *pdev = adapter->pdev;
 	unsigned long size;
-	unsigned int i, j;
+	unsigned int i;
 
 	/* Free all the Rx ring sk_buffs */
 	for (i = 0; i < rx_ring->count; i++) {
@@ -2310,25 +2205,10 @@
 			dev_kfree_skb(buffer_info->skb);
 			buffer_info->skb = NULL;
 		}
-		ps_page = &rx_ring->ps_page[i];
-		ps_page_dma = &rx_ring->ps_page_dma[i];
-		for (j = 0; j < adapter->rx_ps_pages; j++) {
-			if (!ps_page->ps_page[j]) break;
-			pci_unmap_page(pdev,
-				       ps_page_dma->ps_page_dma[j],
-				       PAGE_SIZE, PCI_DMA_FROMDEVICE);
-			ps_page_dma->ps_page_dma[j] = 0;
-			put_page(ps_page->ps_page[j]);
-			ps_page->ps_page[j] = NULL;
-		}
 	}
 
 	size = sizeof(struct e1000_buffer) * rx_ring->count;
 	memset(rx_ring->buffer_info, 0, size);
-	size = sizeof(struct e1000_ps_page) * rx_ring->count;
-	memset(rx_ring->ps_page, 0, size);
-	size = sizeof(struct e1000_ps_page_dma) * rx_ring->count;
-	memset(rx_ring->ps_page_dma, 0, size);
 
 	/* Zero out the descriptor ring */
 
@@ -2998,32 +2878,49 @@
 	struct e1000_buffer *buffer_info;
 	unsigned int i;
 	u8 css;
+	u32 cmd_len = E1000_TXD_CMD_DEXT;
 
-	if (likely(skb->ip_summed == CHECKSUM_PARTIAL)) {
-		css = skb_transport_offset(skb);
+	if (skb->ip_summed != CHECKSUM_PARTIAL)
+		return false;
 
-		i = tx_ring->next_to_use;
-		buffer_info = &tx_ring->buffer_info[i];
-		context_desc = E1000_CONTEXT_DESC(*tx_ring, i);
-
-		context_desc->lower_setup.ip_config = 0;
-		context_desc->upper_setup.tcp_fields.tucss = css;
-		context_desc->upper_setup.tcp_fields.tucso =
-			css + skb->csum_offset;
-		context_desc->upper_setup.tcp_fields.tucse = 0;
-		context_desc->tcp_seg_setup.data = 0;
-		context_desc->cmd_and_length = cpu_to_le32(E1000_TXD_CMD_DEXT);
-
-		buffer_info->time_stamp = jiffies;
-		buffer_info->next_to_watch = i;
-
-		if (unlikely(++i == tx_ring->count)) i = 0;
-		tx_ring->next_to_use = i;
-
-		return true;
+	switch (skb->protocol) {
+	case __constant_htons(ETH_P_IP):
+		if (ip_hdr(skb)->protocol == IPPROTO_TCP)
+			cmd_len |= E1000_TXD_CMD_TCP;
+		break;
+	case __constant_htons(ETH_P_IPV6):
+		/* XXX not handling all IPV6 headers */
+		if (ipv6_hdr(skb)->nexthdr == IPPROTO_TCP)
+			cmd_len |= E1000_TXD_CMD_TCP;
+		break;
+	default:
+		if (unlikely(net_ratelimit()))
+			DPRINTK(DRV, WARNING,
+			        "checksum_partial proto=%x!\n", skb->protocol);
+		break;
 	}
 
-	return false;
+	css = skb_transport_offset(skb);
+
+	i = tx_ring->next_to_use;
+	buffer_info = &tx_ring->buffer_info[i];
+	context_desc = E1000_CONTEXT_DESC(*tx_ring, i);
+
+	context_desc->lower_setup.ip_config = 0;
+	context_desc->upper_setup.tcp_fields.tucss = css;
+	context_desc->upper_setup.tcp_fields.tucso =
+		css + skb->csum_offset;
+	context_desc->upper_setup.tcp_fields.tucse = 0;
+	context_desc->tcp_seg_setup.data = 0;
+	context_desc->cmd_and_length = cpu_to_le32(cmd_len);
+
+	buffer_info->time_stamp = jiffies;
+	buffer_info->next_to_watch = i;
+
+	if (unlikely(++i == tx_ring->count)) i = 0;
+	tx_ring->next_to_use = i;
+
+	return true;
 }
 
 #define E1000_MAX_TXD_PWR	12
@@ -4235,181 +4132,6 @@
 }
 
 /**
- * e1000_clean_rx_irq_ps - Send received data up the network stack; packet split
- * @adapter: board private structure
- **/
-
-static bool e1000_clean_rx_irq_ps(struct e1000_adapter *adapter,
-				  struct e1000_rx_ring *rx_ring,
-				  int *work_done, int work_to_do)
-{
-	union e1000_rx_desc_packet_split *rx_desc, *next_rxd;
-	struct net_device *netdev = adapter->netdev;
-	struct pci_dev *pdev = adapter->pdev;
-	struct e1000_buffer *buffer_info, *next_buffer;
-	struct e1000_ps_page *ps_page;
-	struct e1000_ps_page_dma *ps_page_dma;
-	struct sk_buff *skb;
-	unsigned int i, j;
-	u32 length, staterr;
-	int cleaned_count = 0;
-	bool cleaned = false;
-	unsigned int total_rx_bytes=0, total_rx_packets=0;
-
-	i = rx_ring->next_to_clean;
-	rx_desc = E1000_RX_DESC_PS(*rx_ring, i);
-	staterr = le32_to_cpu(rx_desc->wb.middle.status_error);
-	buffer_info = &rx_ring->buffer_info[i];
-
-	while (staterr & E1000_RXD_STAT_DD) {
-		ps_page = &rx_ring->ps_page[i];
-		ps_page_dma = &rx_ring->ps_page_dma[i];
-
-		if (unlikely(*work_done >= work_to_do))
-			break;
-		(*work_done)++;
-
-		skb = buffer_info->skb;
-
-		/* in the packet split case this is header only */
-		prefetch(skb->data - NET_IP_ALIGN);
-
-		if (++i == rx_ring->count) i = 0;
-		next_rxd = E1000_RX_DESC_PS(*rx_ring, i);
-		prefetch(next_rxd);
-
-		next_buffer = &rx_ring->buffer_info[i];
-
-		cleaned = true;
-		cleaned_count++;
-		pci_unmap_single(pdev, buffer_info->dma,
-				 buffer_info->length,
-				 PCI_DMA_FROMDEVICE);
-
-		if (unlikely(!(staterr & E1000_RXD_STAT_EOP))) {
-			E1000_DBG("%s: Packet Split buffers didn't pick up"
-				  " the full packet\n", netdev->name);
-			dev_kfree_skb_irq(skb);
-			goto next_desc;
-		}
-
-		if (unlikely(staterr & E1000_RXDEXT_ERR_FRAME_ERR_MASK)) {
-			dev_kfree_skb_irq(skb);
-			goto next_desc;
-		}
-
-		length = le16_to_cpu(rx_desc->wb.middle.length0);
-
-		if (unlikely(!length)) {
-			E1000_DBG("%s: Last part of the packet spanning"
-				  " multiple descriptors\n", netdev->name);
-			dev_kfree_skb_irq(skb);
-			goto next_desc;
-		}
-
-		/* Good Receive */
-		skb_put(skb, length);
-
-		{
-		/* this looks ugly, but it seems compiler issues make it
-		   more efficient than reusing j */
-		int l1 = le16_to_cpu(rx_desc->wb.upper.length[0]);
-
-		/* page alloc/put takes too long and effects small packet
-		 * throughput, so unsplit small packets and save the alloc/put*/
-		if (l1 && (l1 <= copybreak) && ((length + l1) <= adapter->rx_ps_bsize0)) {
-			u8 *vaddr;
-			/* there is no documentation about how to call
-			 * kmap_atomic, so we can't hold the mapping
-			 * very long */
-			pci_dma_sync_single_for_cpu(pdev,
-				ps_page_dma->ps_page_dma[0],
-				PAGE_SIZE,
-				PCI_DMA_FROMDEVICE);
-			vaddr = kmap_atomic(ps_page->ps_page[0],
-			                    KM_SKB_DATA_SOFTIRQ);
-			memcpy(skb_tail_pointer(skb), vaddr, l1);
-			kunmap_atomic(vaddr, KM_SKB_DATA_SOFTIRQ);
-			pci_dma_sync_single_for_device(pdev,
-				ps_page_dma->ps_page_dma[0],
-				PAGE_SIZE, PCI_DMA_FROMDEVICE);
-			/* remove the CRC */
-			l1 -= 4;
-			skb_put(skb, l1);
-			goto copydone;
-		} /* if */
-		}
-
-		for (j = 0; j < adapter->rx_ps_pages; j++) {
-			length = le16_to_cpu(rx_desc->wb.upper.length[j]);
-			if (!length)
-				break;
-			pci_unmap_page(pdev, ps_page_dma->ps_page_dma[j],
-					PAGE_SIZE, PCI_DMA_FROMDEVICE);
-			ps_page_dma->ps_page_dma[j] = 0;
-			skb_fill_page_desc(skb, j, ps_page->ps_page[j], 0,
-			                   length);
-			ps_page->ps_page[j] = NULL;
-			skb->len += length;
-			skb->data_len += length;
-			skb->truesize += length;
-		}
-
-		/* strip the ethernet crc, problem is we're using pages now so
-		 * this whole operation can get a little cpu intensive */
-		pskb_trim(skb, skb->len - 4);
-
-copydone:
-		total_rx_bytes += skb->len;
-		total_rx_packets++;
-
-		e1000_rx_checksum(adapter, staterr,
-				  le16_to_cpu(rx_desc->wb.lower.hi_dword.csum_ip.csum), skb);
-		skb->protocol = eth_type_trans(skb, netdev);
-
-		if (likely(rx_desc->wb.upper.header_status &
-			   cpu_to_le16(E1000_RXDPS_HDRSTAT_HDRSP)))
-			adapter->rx_hdr_split++;
-
-		if (unlikely(adapter->vlgrp && (staterr & E1000_RXD_STAT_VP))) {
-			vlan_hwaccel_receive_skb(skb, adapter->vlgrp,
-				le16_to_cpu(rx_desc->wb.middle.vlan));
-		} else {
-			netif_receive_skb(skb);
-		}
-
-		netdev->last_rx = jiffies;
-
-next_desc:
-		rx_desc->wb.middle.status_error &= cpu_to_le32(~0xFF);
-		buffer_info->skb = NULL;
-
-		/* return some buffers to hardware, one at a time is too slow */
-		if (unlikely(cleaned_count >= E1000_RX_BUFFER_WRITE)) {
-			adapter->alloc_rx_buf(adapter, rx_ring, cleaned_count);
-			cleaned_count = 0;
-		}
-
-		/* use prefetched values */
-		rx_desc = next_rxd;
-		buffer_info = next_buffer;
-
-		staterr = le32_to_cpu(rx_desc->wb.middle.status_error);
-	}
-	rx_ring->next_to_clean = i;
-
-	cleaned_count = E1000_DESC_UNUSED(rx_ring);
-	if (cleaned_count)
-		adapter->alloc_rx_buf(adapter, rx_ring, cleaned_count);
-
-	adapter->total_rx_packets += total_rx_packets;
-	adapter->total_rx_bytes += total_rx_bytes;
-	adapter->net_stats.rx_bytes += total_rx_bytes;
-	adapter->net_stats.rx_packets += total_rx_packets;
-	return cleaned;
-}
-
-/**
  * e1000_alloc_rx_buffers - Replace used receive buffers; legacy & extended
  * @adapter: address of board private structure
  **/
@@ -4521,104 +4243,6 @@
 }
 
 /**
- * e1000_alloc_rx_buffers_ps - Replace used receive buffers; packet split
- * @adapter: address of board private structure
- **/
-
-static void e1000_alloc_rx_buffers_ps(struct e1000_adapter *adapter,
-				      struct e1000_rx_ring *rx_ring,
-				      int cleaned_count)
-{
-	struct e1000_hw *hw = &adapter->hw;
-	struct net_device *netdev = adapter->netdev;
-	struct pci_dev *pdev = adapter->pdev;
-	union e1000_rx_desc_packet_split *rx_desc;
-	struct e1000_buffer *buffer_info;
-	struct e1000_ps_page *ps_page;
-	struct e1000_ps_page_dma *ps_page_dma;
-	struct sk_buff *skb;
-	unsigned int i, j;
-
-	i = rx_ring->next_to_use;
-	buffer_info = &rx_ring->buffer_info[i];
-	ps_page = &rx_ring->ps_page[i];
-	ps_page_dma = &rx_ring->ps_page_dma[i];
-
-	while (cleaned_count--) {
-		rx_desc = E1000_RX_DESC_PS(*rx_ring, i);
-
-		for (j = 0; j < PS_PAGE_BUFFERS; j++) {
-			if (j < adapter->rx_ps_pages) {
-				if (likely(!ps_page->ps_page[j])) {
-					ps_page->ps_page[j] =
-						alloc_page(GFP_ATOMIC);
-					if (unlikely(!ps_page->ps_page[j])) {
-						adapter->alloc_rx_buff_failed++;
-						goto no_buffers;
-					}
-					ps_page_dma->ps_page_dma[j] =
-						pci_map_page(pdev,
-							    ps_page->ps_page[j],
-							    0, PAGE_SIZE,
-							    PCI_DMA_FROMDEVICE);
-				}
-				/* Refresh the desc even if buffer_addrs didn't
-				 * change because each write-back erases
-				 * this info.
-				 */
-				rx_desc->read.buffer_addr[j+1] =
-				     cpu_to_le64(ps_page_dma->ps_page_dma[j]);
-			} else
-				rx_desc->read.buffer_addr[j+1] = ~cpu_to_le64(0);
-		}
-
-		skb = netdev_alloc_skb(netdev,
-		                       adapter->rx_ps_bsize0 + NET_IP_ALIGN);
-
-		if (unlikely(!skb)) {
-			adapter->alloc_rx_buff_failed++;
-			break;
-		}
-
-		/* Make buffer alignment 2 beyond a 16 byte boundary
-		 * this will result in a 16 byte aligned IP header after
-		 * the 14 byte MAC header is removed
-		 */
-		skb_reserve(skb, NET_IP_ALIGN);
-
-		buffer_info->skb = skb;
-		buffer_info->length = adapter->rx_ps_bsize0;
-		buffer_info->dma = pci_map_single(pdev, skb->data,
-						  adapter->rx_ps_bsize0,
-						  PCI_DMA_FROMDEVICE);
-
-		rx_desc->read.buffer_addr[0] = cpu_to_le64(buffer_info->dma);
-
-		if (unlikely(++i == rx_ring->count)) i = 0;
-		buffer_info = &rx_ring->buffer_info[i];
-		ps_page = &rx_ring->ps_page[i];
-		ps_page_dma = &rx_ring->ps_page_dma[i];
-	}
-
-no_buffers:
-	if (likely(rx_ring->next_to_use != i)) {
-		rx_ring->next_to_use = i;
-		if (unlikely(i-- == 0)) i = (rx_ring->count - 1);
-
-		/* Force memory writes to complete before letting h/w
-		 * know there are new descriptors to fetch.  (Only
-		 * applicable for weak-ordered memory model archs,
-		 * such as IA-64). */
-		wmb();
-		/* Hardware increments by 16 bytes, but packet split
-		 * descriptors are 32 bytes...so we increment tail
-		 * twice as much.
-		 */
-		writel(i<<1, hw->hw_addr + rx_ring->rdt);
-	}
-}
-
-/**
  * e1000_smartspeed - Workaround for SmartSpeed on 82541 and 82547 controllers.
  * @adapter:
  **/
diff --git a/drivers/net/e1000e/82571.c b/drivers/net/e1000e/82571.c
index 462351c..b2c910c 100644
--- a/drivers/net/e1000e/82571.c
+++ b/drivers/net/e1000e/82571.c
@@ -38,6 +38,7 @@
  * 82573V Gigabit Ethernet Controller (Copper)
  * 82573E Gigabit Ethernet Controller (Copper)
  * 82573L Gigabit Ethernet Controller
+ * 82574L Gigabit Network Connection
  */
 
 #include <linux/netdevice.h>
@@ -54,6 +55,8 @@
 
 #define E1000_GCR_L1_ACT_WITHOUT_L0S_RX 0x08000000
 
+#define E1000_NVM_INIT_CTRL2_MNGM 0x6000 /* Manageability Operation Mode mask */
+
 static s32 e1000_get_phy_id_82571(struct e1000_hw *hw);
 static s32 e1000_setup_copper_link_82571(struct e1000_hw *hw);
 static s32 e1000_setup_fiber_serdes_link_82571(struct e1000_hw *hw);
@@ -63,6 +66,8 @@
 static void e1000_initialize_hw_bits_82571(struct e1000_hw *hw);
 static s32 e1000_setup_link_82571(struct e1000_hw *hw);
 static void e1000_clear_hw_cntrs_82571(struct e1000_hw *hw);
+static bool e1000_check_mng_mode_82574(struct e1000_hw *hw);
+static s32 e1000_led_on_82574(struct e1000_hw *hw);
 
 /**
  *  e1000_init_phy_params_82571 - Init PHY func ptrs.
@@ -92,6 +97,9 @@
 	case e1000_82573:
 		phy->type		 = e1000_phy_m88;
 		break;
+	case e1000_82574:
+		phy->type		 = e1000_phy_bm;
+		break;
 	default:
 		return -E1000_ERR_PHY;
 		break;
@@ -111,6 +119,10 @@
 		if (phy->id != M88E1111_I_PHY_ID)
 			return -E1000_ERR_PHY;
 		break;
+	case e1000_82574:
+		if (phy->id != BME1000_E_PHY_ID_R2)
+			return -E1000_ERR_PHY;
+		break;
 	default:
 		return -E1000_ERR_PHY;
 		break;
@@ -150,6 +162,7 @@
 
 	switch (hw->mac.type) {
 	case e1000_82573:
+	case e1000_82574:
 		if (((eecd >> 15) & 0x3) == 0x3) {
 			nvm->type = e1000_nvm_flash_hw;
 			nvm->word_size = 2048;
@@ -245,6 +258,17 @@
 		break;
 	}
 
+	switch (hw->mac.type) {
+	case e1000_82574:
+		func->check_mng_mode = e1000_check_mng_mode_82574;
+		func->led_on = e1000_led_on_82574;
+		break;
+	default:
+		func->check_mng_mode = e1000e_check_mng_mode_generic;
+		func->led_on = e1000e_led_on_generic;
+		break;
+	}
+
 	return 0;
 }
 
@@ -330,6 +354,8 @@
 static s32 e1000_get_phy_id_82571(struct e1000_hw *hw)
 {
 	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val;
+	u16 phy_id = 0;
 
 	switch (hw->mac.type) {
 	case e1000_82571:
@@ -345,6 +371,20 @@
 	case e1000_82573:
 		return e1000e_get_phy_id(hw);
 		break;
+	case e1000_82574:
+		ret_val = e1e_rphy(hw, PHY_ID1, &phy_id);
+		if (ret_val)
+			return ret_val;
+
+		phy->id = (u32)(phy_id << 16);
+		udelay(20);
+		ret_val = e1e_rphy(hw, PHY_ID2, &phy_id);
+		if (ret_val)
+			return ret_val;
+
+		phy->id |= (u32)(phy_id);
+		phy->revision = (u32)(phy_id & ~PHY_REVISION_MASK);
+		break;
 	default:
 		return -E1000_ERR_PHY;
 		break;
@@ -421,7 +461,7 @@
 	if (ret_val)
 		return ret_val;
 
-	if (hw->mac.type != e1000_82573)
+	if (hw->mac.type != e1000_82573 && hw->mac.type != e1000_82574)
 		ret_val = e1000e_acquire_nvm(hw);
 
 	if (ret_val)
@@ -461,6 +501,7 @@
 
 	switch (hw->mac.type) {
 	case e1000_82573:
+	case e1000_82574:
 		ret_val = e1000_write_nvm_eewr_82571(hw, offset, words, data);
 		break;
 	case e1000_82571:
@@ -735,7 +776,7 @@
 	 * Must acquire the MDIO ownership before MAC reset.
 	 * Ownership defaults to firmware after a reset.
 	 */
-	if (hw->mac.type == e1000_82573) {
+	if (hw->mac.type == e1000_82573 || hw->mac.type == e1000_82574) {
 		extcnf_ctrl = er32(EXTCNF_CTRL);
 		extcnf_ctrl |= E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP;
 
@@ -776,7 +817,7 @@
 	 * Need to wait for Phy configuration completion before accessing
 	 * NVM and Phy.
 	 */
-	if (hw->mac.type == e1000_82573)
+	if (hw->mac.type == e1000_82573 || hw->mac.type == e1000_82574)
 		msleep(25);
 
 	/* Clear any pending interrupt events. */
@@ -843,7 +884,7 @@
 	ew32(TXDCTL(0), reg_data);
 
 	/* ...for both queues. */
-	if (mac->type != e1000_82573) {
+	if (mac->type != e1000_82573 && mac->type != e1000_82574) {
 		reg_data = er32(TXDCTL(1));
 		reg_data = (reg_data & ~E1000_TXDCTL_WTHRESH) |
 			   E1000_TXDCTL_FULL_TX_DESC_WB |
@@ -918,19 +959,28 @@
 	}
 
 	/* Device Control */
-	if (hw->mac.type == e1000_82573) {
+	if (hw->mac.type == e1000_82573 || hw->mac.type == e1000_82574) {
 		reg = er32(CTRL);
 		reg &= ~(1 << 29);
 		ew32(CTRL, reg);
 	}
 
 	/* Extended Device Control */
-	if (hw->mac.type == e1000_82573) {
+	if (hw->mac.type == e1000_82573 || hw->mac.type == e1000_82574) {
 		reg = er32(CTRL_EXT);
 		reg &= ~(1 << 23);
 		reg |= (1 << 22);
 		ew32(CTRL_EXT, reg);
 	}
+
+	/* PCI-Ex Control Register */
+	if (hw->mac.type == e1000_82574) {
+		reg = er32(GCR);
+		reg |= (1 << 22);
+		ew32(GCR, reg);
+	}
+
+	return;
 }
 
 /**
@@ -947,7 +997,7 @@
 	u32 vfta_offset = 0;
 	u32 vfta_bit_in_reg = 0;
 
-	if (hw->mac.type == e1000_82573) {
+	if (hw->mac.type == e1000_82573 || hw->mac.type == e1000_82574) {
 		if (hw->mng_cookie.vlan_id != 0) {
 			/*
 			 * The VFTA is a 4096b bit-field, each identifying
@@ -976,6 +1026,48 @@
 }
 
 /**
+ *  e1000_check_mng_mode_82574 - Check manageability is enabled
+ *  @hw: pointer to the HW structure
+ *
+ *  Reads the NVM Initialization Control Word 2 and returns true
+ *  (>0) if any manageability is enabled, else false (0).
+ **/
+static bool e1000_check_mng_mode_82574(struct e1000_hw *hw)
+{
+	u16 data;
+
+	e1000_read_nvm(hw, NVM_INIT_CONTROL2_REG, 1, &data);
+	return (data & E1000_NVM_INIT_CTRL2_MNGM) != 0;
+}
+
+/**
+ *  e1000_led_on_82574 - Turn LED on
+ *  @hw: pointer to the HW structure
+ *
+ *  Turn LED on.
+ **/
+static s32 e1000_led_on_82574(struct e1000_hw *hw)
+{
+	u32 ctrl;
+	u32 i;
+
+	ctrl = hw->mac.ledctl_mode2;
+	if (!(E1000_STATUS_LU & er32(STATUS))) {
+		/*
+		 * If no link, then turn LED on by setting the invert bit
+		 * for each LED that's "on" (0x0E) in ledctl_mode2.
+		 */
+		for (i = 0; i < 4; i++)
+			if (((hw->mac.ledctl_mode2 >> (i * 8)) & 0xFF) ==
+			    E1000_LEDCTL_MODE_LED_ON)
+				ctrl |= (E1000_LEDCTL_LED0_IVRT << (i * 8));
+	}
+	ew32(LEDCTL, ctrl);
+
+	return 0;
+}
+
+/**
  *  e1000_update_mc_addr_list_82571 - Update Multicast addresses
  *  @hw: pointer to the HW structure
  *  @mc_addr_list: array of multicast addresses to program
@@ -1018,7 +1110,8 @@
 	 * the default flow control setting, so we explicitly
 	 * set it to full.
 	 */
-	if (hw->mac.type == e1000_82573)
+	if ((hw->mac.type == e1000_82573 || hw->mac.type == e1000_82574) &&
+	    hw->fc.type == e1000_fc_default)
 		hw->fc.type = e1000_fc_full;
 
 	return e1000e_setup_link(hw);
@@ -1045,6 +1138,7 @@
 
 	switch (hw->phy.type) {
 	case e1000_phy_m88:
+	case e1000_phy_bm:
 		ret_val = e1000e_copper_link_setup_m88(hw);
 		break;
 	case e1000_phy_igp_2:
@@ -1114,11 +1208,10 @@
 		return ret_val;
 	}
 
-	if (hw->mac.type == e1000_82573 &&
+	if ((hw->mac.type == e1000_82573 || hw->mac.type == e1000_82574) &&
 	    *data == ID_LED_RESERVED_F746)
 		*data = ID_LED_DEFAULT_82573;
-	else if (*data == ID_LED_RESERVED_0000 ||
-		 *data == ID_LED_RESERVED_FFFF)
+	else if (*data == ID_LED_RESERVED_0000 || *data == ID_LED_RESERVED_FFFF)
 		*data = ID_LED_DEFAULT;
 
 	return 0;
@@ -1265,13 +1358,13 @@
 }
 
 static struct e1000_mac_operations e82571_mac_ops = {
-	.mng_mode_enab		= E1000_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT,
+	/* .check_mng_mode: mac type dependent */
 	/* .check_for_link: media type dependent */
 	.cleanup_led		= e1000e_cleanup_led_generic,
 	.clear_hw_cntrs		= e1000_clear_hw_cntrs_82571,
 	.get_bus_info		= e1000e_get_bus_info_pcie,
 	/* .get_link_up_info: media type dependent */
-	.led_on			= e1000e_led_on_generic,
+	/* .led_on: mac type dependent */
 	.led_off		= e1000e_led_off_generic,
 	.update_mc_addr_list	= e1000_update_mc_addr_list_82571,
 	.reset_hw		= e1000_reset_hw_82571,
@@ -1312,6 +1405,22 @@
 	.write_phy_reg		= e1000e_write_phy_reg_m88,
 };
 
+static struct e1000_phy_operations e82_phy_ops_bm = {
+	.acquire_phy		= e1000_get_hw_semaphore_82571,
+	.check_reset_block	= e1000e_check_reset_block_generic,
+	.commit_phy		= e1000e_phy_sw_reset,
+	.force_speed_duplex	= e1000e_phy_force_speed_duplex_m88,
+	.get_cfg_done		= e1000e_get_cfg_done,
+	.get_cable_length	= e1000e_get_cable_length_m88,
+	.get_phy_info		= e1000e_get_phy_info_m88,
+	.read_phy_reg		= e1000e_read_phy_reg_bm2,
+	.release_phy		= e1000_put_hw_semaphore_82571,
+	.reset_phy		= e1000e_phy_hw_reset_generic,
+	.set_d0_lplu_state	= e1000_set_d0_lplu_state_82571,
+	.set_d3_lplu_state	= e1000e_set_d3_lplu_state,
+	.write_phy_reg		= e1000e_write_phy_reg_bm2,
+};
+
 static struct e1000_nvm_operations e82571_nvm_ops = {
 	.acquire_nvm		= e1000_acquire_nvm_82571,
 	.read_nvm		= e1000e_read_nvm_eerd,
@@ -1375,3 +1484,21 @@
 	.nvm_ops		= &e82571_nvm_ops,
 };
 
+struct e1000_info e1000_82574_info = {
+	.mac			= e1000_82574,
+	.flags			= FLAG_HAS_HW_VLAN_FILTER
+				  | FLAG_HAS_MSIX
+				  | FLAG_HAS_JUMBO_FRAMES
+				  | FLAG_HAS_WOL
+				  | FLAG_APME_IN_CTRL3
+				  | FLAG_RX_CSUM_ENABLED
+				  | FLAG_HAS_SMART_POWER_DOWN
+				  | FLAG_HAS_AMT
+				  | FLAG_HAS_CTRLEXT_ON_LOAD,
+	.pba			= 20,
+	.get_variants		= e1000_get_variants_82571,
+	.mac_ops		= &e82571_mac_ops,
+	.phy_ops		= &e82_phy_ops_bm,
+	.nvm_ops		= &e82571_nvm_ops,
+};
+
diff --git a/drivers/net/e1000e/defines.h b/drivers/net/e1000e/defines.h
index 14b0e6c..48f79ec 100644
--- a/drivers/net/e1000e/defines.h
+++ b/drivers/net/e1000e/defines.h
@@ -71,9 +71,11 @@
 #define E1000_CTRL_EXT_RO_DIS    0x00020000 /* Relaxed Ordering disable */
 #define E1000_CTRL_EXT_LINK_MODE_MASK 0x00C00000
 #define E1000_CTRL_EXT_LINK_MODE_PCIE_SERDES  0x00C00000
+#define E1000_CTRL_EXT_EIAME          0x01000000
 #define E1000_CTRL_EXT_DRV_LOAD       0x10000000 /* Driver loaded bit for FW */
 #define E1000_CTRL_EXT_IAME           0x08000000 /* Interrupt acknowledge Auto-mask */
 #define E1000_CTRL_EXT_INT_TIMER_CLR  0x20000000 /* Clear Interrupt timers after IMS clear */
+#define E1000_CTRL_EXT_PBA_CLR        0x80000000 /* PBA Clear */
 
 /* Receive Descriptor bit definitions */
 #define E1000_RXD_STAT_DD       0x01    /* Descriptor Done */
@@ -299,6 +301,7 @@
 #define E1000_RXCSUM_IPPCSE    0x00001000   /* IP payload checksum enable */
 
 /* Header split receive */
+#define E1000_RFCTL_ACK_DIS             0x00001000
 #define E1000_RFCTL_EXTEN               0x00008000
 #define E1000_RFCTL_IPV6_EX_DIS         0x00010000
 #define E1000_RFCTL_NEW_IPV6_EXT_DIS    0x00020000
@@ -363,6 +366,11 @@
 #define E1000_ICR_RXDMT0        0x00000010 /* Rx desc min. threshold (0) */
 #define E1000_ICR_RXT0          0x00000080 /* Rx timer intr (ring 0) */
 #define E1000_ICR_INT_ASSERTED  0x80000000 /* If this bit asserted, the driver should claim the interrupt */
+#define E1000_ICR_RXQ0          0x00100000 /* Rx Queue 0 Interrupt */
+#define E1000_ICR_RXQ1          0x00200000 /* Rx Queue 1 Interrupt */
+#define E1000_ICR_TXQ0          0x00400000 /* Tx Queue 0 Interrupt */
+#define E1000_ICR_TXQ1          0x00800000 /* Tx Queue 1 Interrupt */
+#define E1000_ICR_OTHER         0x01000000 /* Other Interrupts */
 
 /*
  * This defines the bits that are set in the Interrupt Mask
@@ -386,6 +394,11 @@
 #define E1000_IMS_RXSEQ     E1000_ICR_RXSEQ     /* Rx sequence error */
 #define E1000_IMS_RXDMT0    E1000_ICR_RXDMT0    /* Rx desc min. threshold */
 #define E1000_IMS_RXT0      E1000_ICR_RXT0      /* Rx timer intr */
+#define E1000_IMS_RXQ0      E1000_ICR_RXQ0      /* Rx Queue 0 Interrupt */
+#define E1000_IMS_RXQ1      E1000_ICR_RXQ1      /* Rx Queue 1 Interrupt */
+#define E1000_IMS_TXQ0      E1000_ICR_TXQ0      /* Tx Queue 0 Interrupt */
+#define E1000_IMS_TXQ1      E1000_ICR_TXQ1      /* Tx Queue 1 Interrupt */
+#define E1000_IMS_OTHER     E1000_ICR_OTHER     /* Other Interrupts */
 
 /* Interrupt Cause Set */
 #define E1000_ICS_LSC       E1000_ICR_LSC       /* Link Status Change */
@@ -505,6 +518,7 @@
 #define NWAY_LPAR_ASM_DIR        0x0800 /* LP Asymmetric Pause Direction bit */
 
 /* Autoneg Expansion Register */
+#define NWAY_ER_LP_NWAY_CAPS     0x0001 /* LP has Auto Neg Capability */
 
 /* 1000BASE-T Control Register */
 #define CR_1000T_HD_CAPS         0x0100 /* Advertise 1000T HD capability */
@@ -540,6 +554,7 @@
 #define E1000_EECD_DO        0x00000008 /* NVM Data Out */
 #define E1000_EECD_REQ       0x00000040 /* NVM Access Request */
 #define E1000_EECD_GNT       0x00000080 /* NVM Access Grant */
+#define E1000_EECD_PRES      0x00000100 /* NVM Present */
 #define E1000_EECD_SIZE      0x00000200 /* NVM Size (0=64 word 1=256 word) */
 /* NVM Addressing bits based on type (0-small, 1-large) */
 #define E1000_EECD_ADDR_BITS 0x00000400
diff --git a/drivers/net/e1000e/e1000.h b/drivers/net/e1000e/e1000.h
index ac4e506..c55de1c 100644
--- a/drivers/net/e1000e/e1000.h
+++ b/drivers/net/e1000e/e1000.h
@@ -62,6 +62,11 @@
 	e_printk(KERN_NOTICE, adapter, format, ## arg)
 
 
+/* Interrupt modes, as used by the IntMode paramter */
+#define E1000E_INT_MODE_LEGACY		0
+#define E1000E_INT_MODE_MSI		1
+#define E1000E_INT_MODE_MSIX		2
+
 /* Tx/Rx descriptor defines */
 #define E1000_DEFAULT_TXD		256
 #define E1000_MAX_TXD			4096
@@ -95,9 +100,11 @@
 	board_82571,
 	board_82572,
 	board_82573,
+	board_82574,
 	board_80003es2lan,
 	board_ich8lan,
 	board_ich9lan,
+	board_ich10lan,
 };
 
 struct e1000_queue_stats {
@@ -146,6 +153,12 @@
 	/* array of buffer information structs */
 	struct e1000_buffer *buffer_info;
 
+	char name[IFNAMSIZ + 5];
+	u32 ims_val;
+	u32 itr_val;
+	u16 itr_register;
+	int set_itr;
+
 	struct sk_buff *rx_skb_top;
 
 	struct e1000_queue_stats stats;
@@ -257,7 +270,6 @@
 	struct net_device *netdev;
 	struct pci_dev *pdev;
 	struct net_device_stats net_stats;
-	spinlock_t stats_lock;      /* prevent concurrent stats updates */
 
 	/* structs defined in e1000_hw.h */
 	struct e1000_hw hw;
@@ -274,6 +286,9 @@
 	u32 test_icr;
 
 	u32 msg_enable;
+	struct msix_entry *msix_entries;
+	int int_mode;
+	u32 eiac_mask;
 
 	u32 eeprom_wol;
 	u32 wol;
@@ -284,6 +299,8 @@
 	unsigned long led_status;
 
 	unsigned int flags;
+	struct work_struct downshift_task;
+	struct work_struct update_phy_task;
 };
 
 struct e1000_info {
@@ -305,7 +322,9 @@
 #define FLAG_HAS_CTRLEXT_ON_LOAD          (1 << 5)
 #define FLAG_HAS_SWSM_ON_LOAD             (1 << 6)
 #define FLAG_HAS_JUMBO_FRAMES             (1 << 7)
+#define FLAG_READ_ONLY_NVM                (1 << 8)
 #define FLAG_IS_ICH                       (1 << 9)
+#define FLAG_HAS_MSIX                     (1 << 10)
 #define FLAG_HAS_SMART_POWER_DOWN         (1 << 11)
 #define FLAG_IS_QUAD_PORT_A               (1 << 12)
 #define FLAG_IS_QUAD_PORT                 (1 << 13)
@@ -364,6 +383,8 @@
 extern void e1000e_free_rx_resources(struct e1000_adapter *adapter);
 extern void e1000e_free_tx_resources(struct e1000_adapter *adapter);
 extern void e1000e_update_stats(struct e1000_adapter *adapter);
+extern void e1000e_set_interrupt_capability(struct e1000_adapter *adapter);
+extern void e1000e_reset_interrupt_capability(struct e1000_adapter *adapter);
 
 extern unsigned int copybreak;
 
@@ -372,8 +393,10 @@
 extern struct e1000_info e1000_82571_info;
 extern struct e1000_info e1000_82572_info;
 extern struct e1000_info e1000_82573_info;
+extern struct e1000_info e1000_82574_info;
 extern struct e1000_info e1000_ich8_info;
 extern struct e1000_info e1000_ich9_info;
+extern struct e1000_info e1000_ich10_info;
 extern struct e1000_info e1000_es2_info;
 
 extern s32 e1000e_read_pba_num(struct e1000_hw *hw, u32 *pba_num);
@@ -385,6 +408,7 @@
 extern bool e1000e_get_laa_state_82571(struct e1000_hw *hw);
 extern void e1000e_set_laa_state_82571(struct e1000_hw *hw, bool state);
 
+extern void e1000e_write_protect_nvm_ich8lan(struct e1000_hw *hw);
 extern void e1000e_set_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw,
 						 bool state);
 extern void e1000e_igp3_phy_powerdown_workaround_ich8lan(struct e1000_hw *hw);
@@ -446,10 +470,13 @@
 extern s32 e1000e_get_phy_info_m88(struct e1000_hw *hw);
 extern s32 e1000e_read_phy_reg_m88(struct e1000_hw *hw, u32 offset, u16 *data);
 extern s32 e1000e_write_phy_reg_m88(struct e1000_hw *hw, u32 offset, u16 data);
+extern s32 e1000e_phy_init_script_igp3(struct e1000_hw *hw);
 extern enum e1000_phy_type e1000e_get_phy_type_from_id(u32 phy_id);
 extern s32 e1000e_determine_phy_address(struct e1000_hw *hw);
 extern s32 e1000e_write_phy_reg_bm(struct e1000_hw *hw, u32 offset, u16 data);
 extern s32 e1000e_read_phy_reg_bm(struct e1000_hw *hw, u32 offset, u16 *data);
+extern s32 e1000e_read_phy_reg_bm2(struct e1000_hw *hw, u32 offset, u16 *data);
+extern s32 e1000e_write_phy_reg_bm2(struct e1000_hw *hw, u32 offset, u16 data);
 extern void e1000e_phy_force_speed_duplex_setup(struct e1000_hw *hw, u16 *phy_ctrl);
 extern s32 e1000e_write_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 data);
 extern s32 e1000e_read_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 *data);
@@ -520,7 +547,12 @@
 	return hw->phy.ops.get_phy_info(hw);
 }
 
-extern bool e1000e_check_mng_mode(struct e1000_hw *hw);
+static inline s32 e1000e_check_mng_mode(struct e1000_hw *hw)
+{
+	return hw->mac.ops.check_mng_mode(hw);
+}
+
+extern bool e1000e_check_mng_mode_generic(struct e1000_hw *hw);
 extern bool e1000e_enable_tx_pkt_filtering(struct e1000_hw *hw);
 extern s32 e1000e_mng_write_dhcp_info(struct e1000_hw *hw, u8 *buffer, u16 length);
 
diff --git a/drivers/net/e1000e/es2lan.c b/drivers/net/e1000e/es2lan.c
index dc552d7..da9c09c 100644
--- a/drivers/net/e1000e/es2lan.c
+++ b/drivers/net/e1000e/es2lan.c
@@ -1247,7 +1247,7 @@
 }
 
 static struct e1000_mac_operations es2_mac_ops = {
-	.mng_mode_enab		= E1000_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT,
+	.check_mng_mode		= e1000e_check_mng_mode_generic,
 	/* check_for_link dependent on media type */
 	.cleanup_led		= e1000e_cleanup_led_generic,
 	.clear_hw_cntrs		= e1000_clear_hw_cntrs_80003es2lan,
diff --git a/drivers/net/e1000e/ethtool.c b/drivers/net/e1000e/ethtool.c
index e21c9e0..70c11c8 100644
--- a/drivers/net/e1000e/ethtool.c
+++ b/drivers/net/e1000e/ethtool.c
@@ -432,6 +432,10 @@
 	regs_buff[11] = er32(TIDV);
 
 	regs_buff[12] = adapter->hw.phy.type;  /* PHY type (IGP=1, M88=0) */
+
+	/* ethtool doesn't use anything past this point, so all this
+	 * code is likely legacy junk for apps that may or may not
+	 * exist */
 	if (hw->phy.type == e1000_phy_m88) {
 		e1e_rphy(hw, M88E1000_PHY_SPEC_STATUS, &phy_data);
 		regs_buff[13] = (u32)phy_data; /* cable length */
@@ -447,7 +451,7 @@
 		regs_buff[22] = adapter->phy_stats.receive_errors;
 		regs_buff[23] = regs_buff[13]; /* mdix mode */
 	}
-	regs_buff[21] = adapter->phy_stats.idle_errors;  /* phy idle errors */
+	regs_buff[21] = 0; /* was idle_errors */
 	e1e_rphy(hw, PHY_1000T_STATUS, &phy_data);
 	regs_buff[24] = (u32)phy_data;  /* phy local receiver status */
 	regs_buff[25] = regs_buff[24];  /* phy remote receiver status */
@@ -529,6 +533,9 @@
 	if (eeprom->magic != (adapter->pdev->vendor | (adapter->pdev->device << 16)))
 		return -EFAULT;
 
+	if (adapter->flags & FLAG_READ_ONLY_NVM)
+		return -EINVAL;
+
 	max_len = hw->nvm.word_size * 2;
 
 	first_word = eeprom->offset >> 1;
@@ -568,6 +575,7 @@
 	 * and flush shadow RAM for 82573 controllers
 	 */
 	if ((ret_val == 0) && ((first_word <= NVM_CHECKSUM_REG) ||
+			       (hw->mac.type == e1000_82574) ||
 			       (hw->mac.type == e1000_82573)))
 		e1000e_update_nvm_checksum(hw);
 
@@ -779,8 +787,10 @@
 		toggle = 0x7FFFF3FF;
 		break;
 	case e1000_82573:
+	case e1000_82574:
 	case e1000_ich8lan:
 	case e1000_ich9lan:
+	case e1000_ich10lan:
 		toggle = 0x7FFFF033;
 		break;
 	default:
@@ -833,7 +843,9 @@
 	REG_PATTERN_TEST(E1000_TIDV, 0x0000FFFF, 0x0000FFFF);
 	for (i = 0; i < mac->rar_entry_count; i++)
 		REG_PATTERN_TEST_ARRAY(E1000_RA, ((i << 1) + 1),
-				       0x8003FFFF, 0xFFFFFFFF);
+				       ((mac->type == e1000_ich10lan) ?
+					   0x8007FFFF : 0x8003FFFF),
+				       0xFFFFFFFF);
 
 	for (i = 0; i < mac->mta_reg_count; i++)
 		REG_PATTERN_TEST_ARRAY(E1000_MTA, i, 0xFFFFFFFF, 0xFFFFFFFF);
@@ -884,10 +896,18 @@
 	u32 shared_int = 1;
 	u32 irq = adapter->pdev->irq;
 	int i;
+	int ret_val = 0;
+	int int_mode = E1000E_INT_MODE_LEGACY;
 
 	*data = 0;
 
-	/* NOTE: we don't test MSI interrupts here, yet */
+	/* NOTE: we don't test MSI/MSI-X interrupts here, yet */
+	if (adapter->int_mode == E1000E_INT_MODE_MSIX) {
+		int_mode = adapter->int_mode;
+		e1000e_reset_interrupt_capability(adapter);
+		adapter->int_mode = E1000E_INT_MODE_LEGACY;
+		e1000e_set_interrupt_capability(adapter);
+	}
 	/* Hook up test interrupt handler just for this test */
 	if (!request_irq(irq, &e1000_test_intr, IRQF_PROBE_SHARED, netdev->name,
 			 netdev)) {
@@ -895,7 +915,8 @@
 	} else if (request_irq(irq, &e1000_test_intr, IRQF_SHARED,
 		 netdev->name, netdev)) {
 		*data = 1;
-		return -1;
+		ret_val = -1;
+		goto out;
 	}
 	e_info("testing %s interrupt\n", (shared_int ? "shared" : "unshared"));
 
@@ -905,12 +926,23 @@
 
 	/* Test each interrupt */
 	for (i = 0; i < 10; i++) {
-		if ((adapter->flags & FLAG_IS_ICH) && (i == 8))
-			continue;
-
 		/* Interrupt to test */
 		mask = 1 << i;
 
+		if (adapter->flags & FLAG_IS_ICH) {
+			switch (mask) {
+			case E1000_ICR_RXSEQ:
+				continue;
+			case 0x00000100:
+				if (adapter->hw.mac.type == e1000_ich8lan ||
+				    adapter->hw.mac.type == e1000_ich9lan)
+					continue;
+				break;
+			default:
+				break;
+			}
+		}
+
 		if (!shared_int) {
 			/*
 			 * Disable the interrupt to be reported in
@@ -974,7 +1006,14 @@
 	/* Unhook test interrupt handler */
 	free_irq(irq, netdev);
 
-	return *data;
+out:
+	if (int_mode == E1000E_INT_MODE_MSIX) {
+		e1000e_reset_interrupt_capability(adapter);
+		adapter->int_mode = int_mode;
+		e1000e_set_interrupt_capability(adapter);
+	}
+
+	return ret_val;
 }
 
 static void e1000_free_desc_rings(struct e1000_adapter *adapter)
@@ -1755,11 +1794,13 @@
 static int e1000_phys_id(struct net_device *netdev, u32 data)
 {
 	struct e1000_adapter *adapter = netdev_priv(netdev);
+	struct e1000_hw *hw = &adapter->hw;
 
 	if (!data)
 		data = INT_MAX;
 
-	if (adapter->hw.phy.type == e1000_phy_ife) {
+	if ((hw->phy.type == e1000_phy_ife) ||
+	    (hw->mac.type == e1000_82574)) {
 		if (!adapter->blink_timer.function) {
 			init_timer(&adapter->blink_timer);
 			adapter->blink_timer.function =
@@ -1769,16 +1810,16 @@
 		mod_timer(&adapter->blink_timer, jiffies);
 		msleep_interruptible(data * 1000);
 		del_timer_sync(&adapter->blink_timer);
-		e1e_wphy(&adapter->hw,
-				    IFE_PHY_SPECIAL_CONTROL_LED, 0);
+		if (hw->phy.type == e1000_phy_ife)
+			e1e_wphy(hw, IFE_PHY_SPECIAL_CONTROL_LED, 0);
 	} else {
-		e1000e_blink_led(&adapter->hw);
+		e1000e_blink_led(hw);
 		msleep_interruptible(data * 1000);
 	}
 
-	adapter->hw.mac.ops.led_off(&adapter->hw);
+	hw->mac.ops.led_off(hw);
 	clear_bit(E1000_LED_ON, &adapter->led_status);
-	adapter->hw.mac.ops.cleanup_led(&adapter->hw);
+	hw->mac.ops.cleanup_led(hw);
 
 	return 0;
 }
diff --git a/drivers/net/e1000e/hw.h b/drivers/net/e1000e/hw.h
index 74f263a..f66ed37 100644
--- a/drivers/net/e1000e/hw.h
+++ b/drivers/net/e1000e/hw.h
@@ -65,7 +65,11 @@
 	E1000_ICS      = 0x000C8, /* Interrupt Cause Set - WO */
 	E1000_IMS      = 0x000D0, /* Interrupt Mask Set - RW */
 	E1000_IMC      = 0x000D8, /* Interrupt Mask Clear - WO */
+	E1000_EIAC_82574 = 0x000DC, /* Ext. Interrupt Auto Clear - RW */
 	E1000_IAM      = 0x000E0, /* Interrupt Acknowledge Auto Mask */
+	E1000_IVAR     = 0x000E4, /* Interrupt Vector Allocation - RW */
+	E1000_EITR_82574_BASE = 0x000E8, /* Interrupt Throttling - RW */
+#define E1000_EITR_82574(_n) (E1000_EITR_82574_BASE + (_n << 2))
 	E1000_RCTL     = 0x00100, /* Rx Control - RW */
 	E1000_FCTTV    = 0x00170, /* Flow Control Transmit Timer Value - RW */
 	E1000_TXCW     = 0x00178, /* Tx Configuration Word - RW */
@@ -332,6 +336,7 @@
 #define E1000_DEV_ID_82573E			0x108B
 #define E1000_DEV_ID_82573E_IAMT		0x108C
 #define E1000_DEV_ID_82573L			0x109A
+#define E1000_DEV_ID_82574L			0x10D3
 
 #define E1000_DEV_ID_80003ES2LAN_COPPER_DPT	0x1096
 #define E1000_DEV_ID_80003ES2LAN_SERDES_DPT	0x1098
@@ -346,6 +351,7 @@
 #define E1000_DEV_ID_ICH8_IFE_G			0x10C5
 #define E1000_DEV_ID_ICH8_IGP_M			0x104D
 #define E1000_DEV_ID_ICH9_IGP_AMT		0x10BD
+#define E1000_DEV_ID_ICH9_BM			0x10E5
 #define E1000_DEV_ID_ICH9_IGP_M_AMT		0x10F5
 #define E1000_DEV_ID_ICH9_IGP_M			0x10BF
 #define E1000_DEV_ID_ICH9_IGP_M_V		0x10CB
@@ -356,6 +362,10 @@
 #define E1000_DEV_ID_ICH10_R_BM_LM		0x10CC
 #define E1000_DEV_ID_ICH10_R_BM_LF		0x10CD
 #define E1000_DEV_ID_ICH10_R_BM_V		0x10CE
+#define E1000_DEV_ID_ICH10_D_BM_LM		0x10DE
+#define E1000_DEV_ID_ICH10_D_BM_LF		0x10DF
+
+#define E1000_REVISION_4 4
 
 #define E1000_FUNC_1 1
 
@@ -363,9 +373,11 @@
 	e1000_82571,
 	e1000_82572,
 	e1000_82573,
+	e1000_82574,
 	e1000_80003es2lan,
 	e1000_ich8lan,
 	e1000_ich9lan,
+	e1000_ich10lan,
 };
 
 enum e1000_media_type {
@@ -696,8 +708,7 @@
 
 /* Function pointers and static data for the MAC. */
 struct e1000_mac_operations {
-	u32			mng_mode_enab;
-
+	bool (*check_mng_mode)(struct e1000_hw *);
 	s32  (*check_for_link)(struct e1000_hw *);
 	s32  (*cleanup_led)(struct e1000_hw *);
 	void (*clear_hw_cntrs)(struct e1000_hw *);
diff --git a/drivers/net/e1000e/ich8lan.c b/drivers/net/e1000e/ich8lan.c
index 9e38452..523b971 100644
--- a/drivers/net/e1000e/ich8lan.c
+++ b/drivers/net/e1000e/ich8lan.c
@@ -43,7 +43,9 @@
  * 82567LM-2 Gigabit Network Connection
  * 82567LF-2 Gigabit Network Connection
  * 82567V-2 Gigabit Network Connection
- * 82562GT-3 10/100 Network Connection
+ * 82567LF-3 Gigabit Network Connection
+ * 82567LM-3 Gigabit Network Connection
+ * 82567LM-4 Gigabit Network Connection
  */
 
 #include <linux/netdevice.h>
@@ -58,6 +60,7 @@
 #define ICH_FLASH_HSFCTL		0x0006
 #define ICH_FLASH_FADDR			0x0008
 #define ICH_FLASH_FDATA0		0x0010
+#define ICH_FLASH_PR0			0x0074
 
 #define ICH_FLASH_READ_COMMAND_TIMEOUT	500
 #define ICH_FLASH_WRITE_COMMAND_TIMEOUT	500
@@ -150,6 +153,19 @@
 	u16 regval;
 };
 
+/* ICH Flash Protected Region */
+union ich8_flash_protected_range {
+	struct ich8_pr {
+		u32 base:13;     /* 0:12 Protected Range Base */
+		u32 reserved1:2; /* 13:14 Reserved */
+		u32 rpe:1;       /* 15 Read Protection Enable */
+		u32 limit:13;    /* 16:28 Protected Range Limit */
+		u32 reserved2:2; /* 29:30 Reserved */
+		u32 wpe:1;       /* 31 Write Protection Enable */
+	} range;
+	u32 regval;
+};
+
 static s32 e1000_setup_link_ich8lan(struct e1000_hw *hw);
 static void e1000_clear_hw_cntrs_ich8lan(struct e1000_hw *hw);
 static void e1000_initialize_hw_bits_ich8lan(struct e1000_hw *hw);
@@ -157,12 +173,15 @@
 static s32 e1000_erase_flash_bank_ich8lan(struct e1000_hw *hw, u32 bank);
 static s32 e1000_retry_write_flash_byte_ich8lan(struct e1000_hw *hw,
 						u32 offset, u8 byte);
+static s32 e1000_read_flash_byte_ich8lan(struct e1000_hw *hw, u32 offset,
+					 u8 *data);
 static s32 e1000_read_flash_word_ich8lan(struct e1000_hw *hw, u32 offset,
 					 u16 *data);
 static s32 e1000_read_flash_data_ich8lan(struct e1000_hw *hw, u32 offset,
 					 u8 size, u16 *data);
 static s32 e1000_setup_copper_link_ich8lan(struct e1000_hw *hw);
 static s32 e1000_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw);
+static s32 e1000_get_cfg_done_ich8lan(struct e1000_hw *hw);
 
 static inline u16 __er16flash(struct e1000_hw *hw, unsigned long reg)
 {
@@ -366,6 +385,9 @@
 	return 0;
 }
 
+static DEFINE_MUTEX(nvm_mutex);
+static pid_t nvm_owner = -1;
+
 /**
  *  e1000_acquire_swflag_ich8lan - Acquire software control flag
  *  @hw: pointer to the HW structure
@@ -379,6 +401,15 @@
 	u32 extcnf_ctrl;
 	u32 timeout = PHY_CFG_TIMEOUT;
 
+	might_sleep();
+
+	if (!mutex_trylock(&nvm_mutex)) {
+		WARN(1, KERN_ERR "e1000e mutex contention. Owned by pid %d\n",
+		     nvm_owner);
+		mutex_lock(&nvm_mutex);
+	}
+	nvm_owner = current->pid;
+
 	while (timeout) {
 		extcnf_ctrl = er32(EXTCNF_CTRL);
 		extcnf_ctrl |= E1000_EXTCNF_CTRL_SWFLAG;
@@ -393,6 +424,10 @@
 
 	if (!timeout) {
 		hw_dbg(hw, "FW or HW has locked the resource for too long.\n");
+		extcnf_ctrl &= ~E1000_EXTCNF_CTRL_SWFLAG;
+		ew32(EXTCNF_CTRL, extcnf_ctrl);
+		nvm_owner = -1;
+		mutex_unlock(&nvm_mutex);
 		return -E1000_ERR_CONFIG;
 	}
 
@@ -414,6 +449,25 @@
 	extcnf_ctrl = er32(EXTCNF_CTRL);
 	extcnf_ctrl &= ~E1000_EXTCNF_CTRL_SWFLAG;
 	ew32(EXTCNF_CTRL, extcnf_ctrl);
+
+	nvm_owner = -1;
+	mutex_unlock(&nvm_mutex);
+}
+
+/**
+ *  e1000_check_mng_mode_ich8lan - Checks management mode
+ *  @hw: pointer to the HW structure
+ *
+ *  This checks if the adapter has manageability enabled.
+ *  This is a function pointer entry point only called by read/write
+ *  routines for the PHY and NVM parts.
+ **/
+static bool e1000_check_mng_mode_ich8lan(struct e1000_hw *hw)
+{
+	u32 fwsm = er32(FWSM);
+
+	return (fwsm & E1000_FWSM_MODE_MASK) ==
+		(E1000_ICH_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT);
 }
 
 /**
@@ -897,6 +951,56 @@
 }
 
 /**
+ *  e1000_valid_nvm_bank_detect_ich8lan - finds out the valid bank 0 or 1
+ *  @hw: pointer to the HW structure
+ *  @bank:  pointer to the variable that returns the active bank
+ *
+ *  Reads signature byte from the NVM using the flash access registers.
+ **/
+static s32 e1000_valid_nvm_bank_detect_ich8lan(struct e1000_hw *hw, u32 *bank)
+{
+	struct e1000_nvm_info *nvm = &hw->nvm;
+	/* flash bank size is in words */
+	u32 bank1_offset = nvm->flash_bank_size * sizeof(u16);
+	u32 act_offset = E1000_ICH_NVM_SIG_WORD * 2 + 1;
+	u8 bank_high_byte = 0;
+
+	if (hw->mac.type != e1000_ich10lan) {
+		if (er32(EECD) & E1000_EECD_SEC1VAL)
+			*bank = 1;
+		else
+			*bank = 0;
+	} else {
+		/*
+		 * Make sure the signature for bank 0 is valid,
+		 * if not check for bank1
+		 */
+		e1000_read_flash_byte_ich8lan(hw, act_offset, &bank_high_byte);
+		if ((bank_high_byte & 0xC0) == 0x80) {
+			*bank = 0;
+		} else {
+			/*
+			 * find if segment 1 is valid by verifying
+			 * bit 15:14 = 10b in word 0x13
+			 */
+			e1000_read_flash_byte_ich8lan(hw,
+						      act_offset + bank1_offset,
+						      &bank_high_byte);
+
+			/* bank1 has a valid signature equivalent to SEC1V */
+			if ((bank_high_byte & 0xC0) == 0x80) {
+				*bank = 1;
+			} else {
+				hw_dbg(hw, "ERROR: EEPROM not present\n");
+				return -E1000_ERR_NVM;
+			}
+		}
+	}
+
+	return 0;
+}
+
+/**
  *  e1000_read_nvm_ich8lan - Read word(s) from the NVM
  *  @hw: pointer to the HW structure
  *  @offset: The offset (in bytes) of the word(s) to read.
@@ -912,6 +1016,7 @@
 	struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
 	u32 act_offset;
 	s32 ret_val;
+	u32 bank = 0;
 	u16 i, word;
 
 	if ((offset >= nvm->word_size) || (words > nvm->word_size - offset) ||
@@ -924,10 +1029,11 @@
 	if (ret_val)
 		return ret_val;
 
-	/* Start with the bank offset, then add the relative offset. */
-	act_offset = (er32(EECD) & E1000_EECD_SEC1VAL)
-		     ? nvm->flash_bank_size
-		     : 0;
+	ret_val = e1000_valid_nvm_bank_detect_ich8lan(hw, &bank);
+	if (ret_val)
+		return ret_val;
+
+	act_offset = (bank) ? nvm->flash_bank_size : 0;
 	act_offset += offset;
 
 	for (i = 0; i < words; i++) {
@@ -1075,6 +1181,29 @@
 }
 
 /**
+ *  e1000_read_flash_byte_ich8lan - Read byte from flash
+ *  @hw: pointer to the HW structure
+ *  @offset: The offset of the byte to read.
+ *  @data: Pointer to a byte to store the value read.
+ *
+ *  Reads a single byte from the NVM using the flash access registers.
+ **/
+static s32 e1000_read_flash_byte_ich8lan(struct e1000_hw *hw, u32 offset,
+					 u8 *data)
+{
+	s32 ret_val;
+	u16 word = 0;
+
+	ret_val = e1000_read_flash_data_ich8lan(hw, offset, 1, &word);
+	if (ret_val)
+		return ret_val;
+
+	*data = (u8)word;
+
+	return 0;
+}
+
+/**
  *  e1000_read_flash_data_ich8lan - Read byte or word from NVM
  *  @hw: pointer to the HW structure
  *  @offset: The offset (in bytes) of the byte or word to read.
@@ -1205,7 +1334,7 @@
 {
 	struct e1000_nvm_info *nvm = &hw->nvm;
 	struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
-	u32 i, act_offset, new_bank_offset, old_bank_offset;
+	u32 i, act_offset, new_bank_offset, old_bank_offset, bank;
 	s32 ret_val;
 	u16 data;
 
@@ -1225,7 +1354,11 @@
 	 * write to bank 0 etc.  We also need to erase the segment that
 	 * is going to be written
 	 */
-	if (!(er32(EECD) & E1000_EECD_SEC1VAL)) {
+	ret_val =  e1000_valid_nvm_bank_detect_ich8lan(hw, &bank);
+	if (ret_val)
+		return ret_val;
+
+	if (bank == 0) {
 		new_bank_offset = nvm->flash_bank_size;
 		old_bank_offset = 0;
 		e1000_erase_flash_bank_ich8lan(hw, 1);
@@ -1284,6 +1417,7 @@
 	 * programming failed.
 	 */
 	if (ret_val) {
+		/* Possibly read-only, see e1000e_write_protect_nvm_ich8lan() */
 		hw_dbg(hw, "Flash commit failed.\n");
 		e1000_release_swflag_ich8lan(hw);
 		return ret_val;
@@ -1374,6 +1508,49 @@
 }
 
 /**
+ *  e1000e_write_protect_nvm_ich8lan - Make the NVM read-only
+ *  @hw: pointer to the HW structure
+ *
+ *  To prevent malicious write/erase of the NVM, set it to be read-only
+ *  so that the hardware ignores all write/erase cycles of the NVM via
+ *  the flash control registers.  The shadow-ram copy of the NVM will
+ *  still be updated, however any updates to this copy will not stick
+ *  across driver reloads.
+ **/
+void e1000e_write_protect_nvm_ich8lan(struct e1000_hw *hw)
+{
+	union ich8_flash_protected_range pr0;
+	union ich8_hws_flash_status hsfsts;
+	u32 gfpreg;
+	s32 ret_val;
+
+	ret_val = e1000_acquire_swflag_ich8lan(hw);
+	if (ret_val)
+		return;
+
+	gfpreg = er32flash(ICH_FLASH_GFPREG);
+
+	/* Write-protect GbE Sector of NVM */
+	pr0.regval = er32flash(ICH_FLASH_PR0);
+	pr0.range.base = gfpreg & FLASH_GFPREG_BASE_MASK;
+	pr0.range.limit = ((gfpreg >> 16) & FLASH_GFPREG_BASE_MASK);
+	pr0.range.wpe = true;
+	ew32flash(ICH_FLASH_PR0, pr0.regval);
+
+	/*
+	 * Lock down a subset of GbE Flash Control Registers, e.g.
+	 * PR0 to prevent the write-protection from being lifted.
+	 * Once FLOCKDN is set, the registers protected by it cannot
+	 * be written until FLOCKDN is cleared by a hardware reset.
+	 */
+	hsfsts.regval = er16flash(ICH_FLASH_HSFSTS);
+	hsfsts.hsf_status.flockdn = true;
+	ew32flash(ICH_FLASH_HSFSTS, hsfsts.regval);
+
+	e1000_release_swflag_ich8lan(hw);
+}
+
+/**
  *  e1000_write_flash_data_ich8lan - Writes bytes to the NVM
  *  @hw: pointer to the HW structure
  *  @offset: The offset (in bytes) of the byte/word to read.
@@ -1720,6 +1897,9 @@
 	ew32(CTRL, (ctrl | E1000_CTRL_RST));
 	msleep(20);
 
+	/* release the swflag because it is not reset by hardware reset */
+	e1000_release_swflag_ich8lan(hw);
+
 	ret_val = e1000e_get_auto_rd_done(hw);
 	if (ret_val) {
 		/*
@@ -2189,13 +2369,14 @@
  *  'LPLU Enabled' and 'Gig Disable' to force link speed negotiation
  *  to a lower speed.
  *
- *  Should only be called for ICH9 devices.
+ *  Should only be called for ICH9 and ICH10 devices.
  **/
 void e1000e_disable_gig_wol_ich8lan(struct e1000_hw *hw)
 {
 	u32 phy_ctrl;
 
-	if (hw->mac.type == e1000_ich9lan) {
+	if ((hw->mac.type == e1000_ich10lan) ||
+	    (hw->mac.type == e1000_ich9lan)) {
 		phy_ctrl = er32(PHY_CTRL);
 		phy_ctrl |= E1000_PHY_CTRL_D0A_LPLU |
 		            E1000_PHY_CTRL_GBE_DISABLE;
@@ -2253,6 +2434,39 @@
 }
 
 /**
+ *  e1000_get_cfg_done_ich8lan - Read config done bit
+ *  @hw: pointer to the HW structure
+ *
+ *  Read the management control register for the config done bit for
+ *  completion status.  NOTE: silicon which is EEPROM-less will fail trying
+ *  to read the config done bit, so an error is *ONLY* logged and returns
+ *  E1000_SUCCESS.  If we were to return with error, EEPROM-less silicon
+ *  would not be able to be reset or change link.
+ **/
+static s32 e1000_get_cfg_done_ich8lan(struct e1000_hw *hw)
+{
+	u32 bank = 0;
+
+	e1000e_get_cfg_done(hw);
+
+	/* If EEPROM is not marked present, init the IGP 3 PHY manually */
+	if (hw->mac.type != e1000_ich10lan) {
+		if (((er32(EECD) & E1000_EECD_PRES) == 0) &&
+		    (hw->phy.type == e1000_phy_igp_3)) {
+			e1000e_phy_init_script_igp3(hw);
+		}
+	} else {
+		if (e1000_valid_nvm_bank_detect_ich8lan(hw, &bank)) {
+			/* Maybe we should do a basic PHY config */
+			hw_dbg(hw, "EEPROM not present\n");
+			return -E1000_ERR_CONFIG;
+		}
+	}
+
+	return 0;
+}
+
+/**
  *  e1000_clear_hw_cntrs_ich8lan - Clear statistical counters
  *  @hw: pointer to the HW structure
  *
@@ -2282,7 +2496,7 @@
 }
 
 static struct e1000_mac_operations ich8_mac_ops = {
-	.mng_mode_enab		= E1000_ICH_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT,
+	.check_mng_mode		= e1000_check_mng_mode_ich8lan,
 	.check_for_link		= e1000e_check_for_copper_link,
 	.cleanup_led		= e1000_cleanup_led_ich8lan,
 	.clear_hw_cntrs		= e1000_clear_hw_cntrs_ich8lan,
@@ -2302,7 +2516,7 @@
 	.check_reset_block	= e1000_check_reset_block_ich8lan,
 	.commit_phy		= NULL,
 	.force_speed_duplex	= e1000_phy_force_speed_duplex_ich8lan,
-	.get_cfg_done		= e1000e_get_cfg_done,
+	.get_cfg_done		= e1000_get_cfg_done_ich8lan,
 	.get_cable_length	= e1000e_get_cable_length_igp_2,
 	.get_phy_info		= e1000_get_phy_info_ich8lan,
 	.read_phy_reg		= e1000e_read_phy_reg_igp,
@@ -2357,3 +2571,20 @@
 	.nvm_ops		= &ich8_nvm_ops,
 };
 
+struct e1000_info e1000_ich10_info = {
+	.mac			= e1000_ich10lan,
+	.flags			= FLAG_HAS_JUMBO_FRAMES
+				  | FLAG_IS_ICH
+				  | FLAG_HAS_WOL
+				  | FLAG_RX_CSUM_ENABLED
+				  | FLAG_HAS_CTRLEXT_ON_LOAD
+				  | FLAG_HAS_AMT
+				  | FLAG_HAS_ERT
+				  | FLAG_HAS_FLASH
+				  | FLAG_APME_IN_WUC,
+	.pba			= 10,
+	.get_variants		= e1000_get_variants_ich8lan,
+	.mac_ops		= &ich8_mac_ops,
+	.phy_ops		= &ich8_phy_ops,
+	.nvm_ops		= &ich8_nvm_ops,
+};
diff --git a/drivers/net/e1000e/lib.c b/drivers/net/e1000e/lib.c
index f1f4e9d..089578f 100644
--- a/drivers/net/e1000e/lib.c
+++ b/drivers/net/e1000e/lib.c
@@ -2012,6 +2012,7 @@
 	}
 
 	msleep(10);
+	nvm->ops.release_nvm(hw);
 	return 0;
 }
 
@@ -2222,17 +2223,18 @@
 }
 
 /**
- *  e1000e_check_mng_mode - check management mode
+ *  e1000e_check_mng_mode_generic - check management mode
  *  @hw: pointer to the HW structure
  *
  *  Reads the firmware semaphore register and returns true (>0) if
  *  manageability is enabled, else false (0).
  **/
-bool e1000e_check_mng_mode(struct e1000_hw *hw)
+bool e1000e_check_mng_mode_generic(struct e1000_hw *hw)
 {
 	u32 fwsm = er32(FWSM);
 
-	return (fwsm & E1000_FWSM_MODE_MASK) == hw->mac.ops.mng_mode_enab;
+	return (fwsm & E1000_FWSM_MODE_MASK) ==
+		(E1000_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT);
 }
 
 /**
diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c
index d266510..abd492b 100644
--- a/drivers/net/e1000e/netdev.c
+++ b/drivers/net/e1000e/netdev.c
@@ -47,7 +47,7 @@
 
 #include "e1000.h"
 
-#define DRV_VERSION "0.3.3.3-k2"
+#define DRV_VERSION "0.3.3.3-k6"
 char e1000e_driver_name[] = "e1000e";
 const char e1000e_driver_version[] = DRV_VERSION;
 
@@ -55,9 +55,11 @@
 	[board_82571]		= &e1000_82571_info,
 	[board_82572]		= &e1000_82572_info,
 	[board_82573]		= &e1000_82573_info,
+	[board_82574]		= &e1000_82574_info,
 	[board_80003es2lan]	= &e1000_es2_info,
 	[board_ich8lan]		= &e1000_ich8_info,
 	[board_ich9lan]		= &e1000_ich9_info,
+	[board_ich10lan]	= &e1000_ich10_info,
 };
 
 #ifdef DEBUG
@@ -1115,6 +1117,14 @@
 	writel(0, adapter->hw.hw_addr + rx_ring->tail);
 }
 
+static void e1000e_downshift_workaround(struct work_struct *work)
+{
+	struct e1000_adapter *adapter = container_of(work,
+					struct e1000_adapter, downshift_task);
+
+	e1000e_gig_downshift_workaround_ich8lan(&adapter->hw);
+}
+
 /**
  * e1000_intr_msi - Interrupt Handler
  * @irq: interrupt number
@@ -1139,7 +1149,7 @@
 		 */
 		if ((adapter->flags & FLAG_LSC_GIG_SPEED_DROP) &&
 		    (!(er32(STATUS) & E1000_STATUS_LU)))
-			e1000e_gig_downshift_workaround_ich8lan(hw);
+			schedule_work(&adapter->downshift_task);
 
 		/*
 		 * 80003ES2LAN workaround-- For packet buffer work-around on
@@ -1179,8 +1189,8 @@
 	struct net_device *netdev = data;
 	struct e1000_adapter *adapter = netdev_priv(netdev);
 	struct e1000_hw *hw = &adapter->hw;
-
 	u32 rctl, icr = er32(ICR);
+
 	if (!icr)
 		return IRQ_NONE;  /* Not our interrupt */
 
@@ -1205,7 +1215,7 @@
 		 */
 		if ((adapter->flags & FLAG_LSC_GIG_SPEED_DROP) &&
 		    (!(er32(STATUS) & E1000_STATUS_LU)))
-			e1000e_gig_downshift_workaround_ich8lan(hw);
+			schedule_work(&adapter->downshift_task);
 
 		/*
 		 * 80003ES2LAN workaround--
@@ -1236,6 +1246,263 @@
 	return IRQ_HANDLED;
 }
 
+static irqreturn_t e1000_msix_other(int irq, void *data)
+{
+	struct net_device *netdev = data;
+	struct e1000_adapter *adapter = netdev_priv(netdev);
+	struct e1000_hw *hw = &adapter->hw;
+	u32 icr = er32(ICR);
+
+	if (!(icr & E1000_ICR_INT_ASSERTED)) {
+		ew32(IMS, E1000_IMS_OTHER);
+		return IRQ_NONE;
+	}
+
+	if (icr & adapter->eiac_mask)
+		ew32(ICS, (icr & adapter->eiac_mask));
+
+	if (icr & E1000_ICR_OTHER) {
+		if (!(icr & E1000_ICR_LSC))
+			goto no_link_interrupt;
+		hw->mac.get_link_status = 1;
+		/* guard against interrupt when we're going down */
+		if (!test_bit(__E1000_DOWN, &adapter->state))
+			mod_timer(&adapter->watchdog_timer, jiffies + 1);
+	}
+
+no_link_interrupt:
+	ew32(IMS, E1000_IMS_LSC | E1000_IMS_OTHER);
+
+	return IRQ_HANDLED;
+}
+
+
+static irqreturn_t e1000_intr_msix_tx(int irq, void *data)
+{
+	struct net_device *netdev = data;
+	struct e1000_adapter *adapter = netdev_priv(netdev);
+	struct e1000_hw *hw = &adapter->hw;
+	struct e1000_ring *tx_ring = adapter->tx_ring;
+
+
+	adapter->total_tx_bytes = 0;
+	adapter->total_tx_packets = 0;
+
+	if (!e1000_clean_tx_irq(adapter))
+		/* Ring was not completely cleaned, so fire another interrupt */
+		ew32(ICS, tx_ring->ims_val);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t e1000_intr_msix_rx(int irq, void *data)
+{
+	struct net_device *netdev = data;
+	struct e1000_adapter *adapter = netdev_priv(netdev);
+
+	/* Write the ITR value calculated at the end of the
+	 * previous interrupt.
+	 */
+	if (adapter->rx_ring->set_itr) {
+		writel(1000000000 / (adapter->rx_ring->itr_val * 256),
+		       adapter->hw.hw_addr + adapter->rx_ring->itr_register);
+		adapter->rx_ring->set_itr = 0;
+	}
+
+	if (netif_rx_schedule_prep(netdev, &adapter->napi)) {
+		adapter->total_rx_bytes = 0;
+		adapter->total_rx_packets = 0;
+		__netif_rx_schedule(netdev, &adapter->napi);
+	}
+	return IRQ_HANDLED;
+}
+
+/**
+ * e1000_configure_msix - Configure MSI-X hardware
+ *
+ * e1000_configure_msix sets up the hardware to properly
+ * generate MSI-X interrupts.
+ **/
+static void e1000_configure_msix(struct e1000_adapter *adapter)
+{
+	struct e1000_hw *hw = &adapter->hw;
+	struct e1000_ring *rx_ring = adapter->rx_ring;
+	struct e1000_ring *tx_ring = adapter->tx_ring;
+	int vector = 0;
+	u32 ctrl_ext, ivar = 0;
+
+	adapter->eiac_mask = 0;
+
+	/* Workaround issue with spurious interrupts on 82574 in MSI-X mode */
+	if (hw->mac.type == e1000_82574) {
+		u32 rfctl = er32(RFCTL);
+		rfctl |= E1000_RFCTL_ACK_DIS;
+		ew32(RFCTL, rfctl);
+	}
+
+#define E1000_IVAR_INT_ALLOC_VALID	0x8
+	/* Configure Rx vector */
+	rx_ring->ims_val = E1000_IMS_RXQ0;
+	adapter->eiac_mask |= rx_ring->ims_val;
+	if (rx_ring->itr_val)
+		writel(1000000000 / (rx_ring->itr_val * 256),
+		       hw->hw_addr + rx_ring->itr_register);
+	else
+		writel(1, hw->hw_addr + rx_ring->itr_register);
+	ivar = E1000_IVAR_INT_ALLOC_VALID | vector;
+
+	/* Configure Tx vector */
+	tx_ring->ims_val = E1000_IMS_TXQ0;
+	vector++;
+	if (tx_ring->itr_val)
+		writel(1000000000 / (tx_ring->itr_val * 256),
+		       hw->hw_addr + tx_ring->itr_register);
+	else
+		writel(1, hw->hw_addr + tx_ring->itr_register);
+	adapter->eiac_mask |= tx_ring->ims_val;
+	ivar |= ((E1000_IVAR_INT_ALLOC_VALID | vector) << 8);
+
+	/* set vector for Other Causes, e.g. link changes */
+	vector++;
+	ivar |= ((E1000_IVAR_INT_ALLOC_VALID | vector) << 16);
+	if (rx_ring->itr_val)
+		writel(1000000000 / (rx_ring->itr_val * 256),
+		       hw->hw_addr + E1000_EITR_82574(vector));
+	else
+		writel(1, hw->hw_addr + E1000_EITR_82574(vector));
+
+	/* Cause Tx interrupts on every write back */
+	ivar |= (1 << 31);
+
+	ew32(IVAR, ivar);
+
+	/* enable MSI-X PBA support */
+	ctrl_ext = er32(CTRL_EXT);
+	ctrl_ext |= E1000_CTRL_EXT_PBA_CLR;
+
+	/* Auto-Mask Other interrupts upon ICR read */
+#define E1000_EIAC_MASK_82574   0x01F00000
+	ew32(IAM, ~E1000_EIAC_MASK_82574 | E1000_IMS_OTHER);
+	ctrl_ext |= E1000_CTRL_EXT_EIAME;
+	ew32(CTRL_EXT, ctrl_ext);
+	e1e_flush();
+}
+
+void e1000e_reset_interrupt_capability(struct e1000_adapter *adapter)
+{
+	if (adapter->msix_entries) {
+		pci_disable_msix(adapter->pdev);
+		kfree(adapter->msix_entries);
+		adapter->msix_entries = NULL;
+	} else if (adapter->flags & FLAG_MSI_ENABLED) {
+		pci_disable_msi(adapter->pdev);
+		adapter->flags &= ~FLAG_MSI_ENABLED;
+	}
+
+	return;
+}
+
+/**
+ * e1000e_set_interrupt_capability - set MSI or MSI-X if supported
+ *
+ * Attempt to configure interrupts using the best available
+ * capabilities of the hardware and kernel.
+ **/
+void e1000e_set_interrupt_capability(struct e1000_adapter *adapter)
+{
+	int err;
+	int numvecs, i;
+
+
+	switch (adapter->int_mode) {
+	case E1000E_INT_MODE_MSIX:
+		if (adapter->flags & FLAG_HAS_MSIX) {
+			numvecs = 3; /* RxQ0, TxQ0 and other */
+			adapter->msix_entries = kcalloc(numvecs,
+						      sizeof(struct msix_entry),
+						      GFP_KERNEL);
+			if (adapter->msix_entries) {
+				for (i = 0; i < numvecs; i++)
+					adapter->msix_entries[i].entry = i;
+
+				err = pci_enable_msix(adapter->pdev,
+						      adapter->msix_entries,
+						      numvecs);
+				if (err == 0)
+					return;
+			}
+			/* MSI-X failed, so fall through and try MSI */
+			e_err("Failed to initialize MSI-X interrupts.  "
+			      "Falling back to MSI interrupts.\n");
+			e1000e_reset_interrupt_capability(adapter);
+		}
+		adapter->int_mode = E1000E_INT_MODE_MSI;
+		/* Fall through */
+	case E1000E_INT_MODE_MSI:
+		if (!pci_enable_msi(adapter->pdev)) {
+			adapter->flags |= FLAG_MSI_ENABLED;
+		} else {
+			adapter->int_mode = E1000E_INT_MODE_LEGACY;
+			e_err("Failed to initialize MSI interrupts.  Falling "
+			      "back to legacy interrupts.\n");
+		}
+		/* Fall through */
+	case E1000E_INT_MODE_LEGACY:
+		/* Don't do anything; this is the system default */
+		break;
+	}
+
+	return;
+}
+
+/**
+ * e1000_request_msix - Initialize MSI-X interrupts
+ *
+ * e1000_request_msix allocates MSI-X vectors and requests interrupts from the
+ * kernel.
+ **/
+static int e1000_request_msix(struct e1000_adapter *adapter)
+{
+	struct net_device *netdev = adapter->netdev;
+	int err = 0, vector = 0;
+
+	if (strlen(netdev->name) < (IFNAMSIZ - 5))
+		sprintf(adapter->rx_ring->name, "%s-rx0", netdev->name);
+	else
+		memcpy(adapter->rx_ring->name, netdev->name, IFNAMSIZ);
+	err = request_irq(adapter->msix_entries[vector].vector,
+			  &e1000_intr_msix_rx, 0, adapter->rx_ring->name,
+			  netdev);
+	if (err)
+		goto out;
+	adapter->rx_ring->itr_register = E1000_EITR_82574(vector);
+	adapter->rx_ring->itr_val = adapter->itr;
+	vector++;
+
+	if (strlen(netdev->name) < (IFNAMSIZ - 5))
+		sprintf(adapter->tx_ring->name, "%s-tx0", netdev->name);
+	else
+		memcpy(adapter->tx_ring->name, netdev->name, IFNAMSIZ);
+	err = request_irq(adapter->msix_entries[vector].vector,
+			  &e1000_intr_msix_tx, 0, adapter->tx_ring->name,
+			  netdev);
+	if (err)
+		goto out;
+	adapter->tx_ring->itr_register = E1000_EITR_82574(vector);
+	adapter->tx_ring->itr_val = adapter->itr;
+	vector++;
+
+	err = request_irq(adapter->msix_entries[vector].vector,
+			  &e1000_msix_other, 0, netdev->name, netdev);
+	if (err)
+		goto out;
+
+	e1000_configure_msix(adapter);
+	return 0;
+out:
+	return err;
+}
+
 /**
  * e1000_request_irq - initialize interrupts
  *
@@ -1245,28 +1512,32 @@
 static int e1000_request_irq(struct e1000_adapter *adapter)
 {
 	struct net_device *netdev = adapter->netdev;
-	int irq_flags = IRQF_SHARED;
 	int err;
 
-	if (!(adapter->flags & FLAG_MSI_TEST_FAILED)) {
-		err = pci_enable_msi(adapter->pdev);
-		if (!err) {
-			adapter->flags |= FLAG_MSI_ENABLED;
-			irq_flags = 0;
-		}
+	if (adapter->msix_entries) {
+		err = e1000_request_msix(adapter);
+		if (!err)
+			return err;
+		/* fall back to MSI */
+		e1000e_reset_interrupt_capability(adapter);
+		adapter->int_mode = E1000E_INT_MODE_MSI;
+		e1000e_set_interrupt_capability(adapter);
+	}
+	if (adapter->flags & FLAG_MSI_ENABLED) {
+		err = request_irq(adapter->pdev->irq, &e1000_intr_msi, 0,
+				  netdev->name, netdev);
+		if (!err)
+			return err;
+
+		/* fall back to legacy interrupt */
+		e1000e_reset_interrupt_capability(adapter);
+		adapter->int_mode = E1000E_INT_MODE_LEGACY;
 	}
 
-	err = request_irq(adapter->pdev->irq,
-			  ((adapter->flags & FLAG_MSI_ENABLED) ?
-				&e1000_intr_msi : &e1000_intr),
-			  irq_flags, netdev->name, netdev);
-	if (err) {
-		if (adapter->flags & FLAG_MSI_ENABLED) {
-			pci_disable_msi(adapter->pdev);
-			adapter->flags &= ~FLAG_MSI_ENABLED;
-		}
+	err = request_irq(adapter->pdev->irq, &e1000_intr, IRQF_SHARED,
+			  netdev->name, netdev);
+	if (err)
 		e_err("Unable to allocate interrupt, Error: %d\n", err);
-	}
 
 	return err;
 }
@@ -1275,11 +1546,21 @@
 {
 	struct net_device *netdev = adapter->netdev;
 
-	free_irq(adapter->pdev->irq, netdev);
-	if (adapter->flags & FLAG_MSI_ENABLED) {
-		pci_disable_msi(adapter->pdev);
-		adapter->flags &= ~FLAG_MSI_ENABLED;
+	if (adapter->msix_entries) {
+		int vector = 0;
+
+		free_irq(adapter->msix_entries[vector].vector, netdev);
+		vector++;
+
+		free_irq(adapter->msix_entries[vector].vector, netdev);
+		vector++;
+
+		/* Other Causes interrupt vector */
+		free_irq(adapter->msix_entries[vector].vector, netdev);
+		return;
 	}
+
+	free_irq(adapter->pdev->irq, netdev);
 }
 
 /**
@@ -1290,6 +1571,8 @@
 	struct e1000_hw *hw = &adapter->hw;
 
 	ew32(IMC, ~0);
+	if (adapter->msix_entries)
+		ew32(EIAC_82574, 0);
 	e1e_flush();
 	synchronize_irq(adapter->pdev->irq);
 }
@@ -1301,7 +1584,12 @@
 {
 	struct e1000_hw *hw = &adapter->hw;
 
-	ew32(IMS, IMS_ENABLE_MASK);
+	if (adapter->msix_entries) {
+		ew32(EIAC_82574, adapter->eiac_mask & E1000_EIAC_MASK_82574);
+		ew32(IMS, adapter->eiac_mask | E1000_IMS_OTHER | E1000_IMS_LSC);
+	} else {
+		ew32(IMS, IMS_ENABLE_MASK);
+	}
 	e1e_flush();
 }
 
@@ -1551,9 +1839,8 @@
  *      traffic pattern.  Constants in this function were computed
  *      based on theoretical maximum wire speed and thresholds were set based
  *      on testing data as well as attempting to minimize response time
- *      while increasing bulk throughput.
- *      this functionality is controlled by the InterruptThrottleRate module
- *      parameter (see e1000_param.c)
+ *      while increasing bulk throughput.  This functionality is controlled
+ *      by the InterruptThrottleRate module parameter.
  **/
 static unsigned int e1000_update_itr(struct e1000_adapter *adapter,
 				     u16 itr_setting, int packets,
@@ -1661,11 +1948,37 @@
 			     min(adapter->itr + (new_itr >> 2), new_itr) :
 			     new_itr;
 		adapter->itr = new_itr;
-		ew32(ITR, 1000000000 / (new_itr * 256));
+		adapter->rx_ring->itr_val = new_itr;
+		if (adapter->msix_entries)
+			adapter->rx_ring->set_itr = 1;
+		else
+			ew32(ITR, 1000000000 / (new_itr * 256));
 	}
 }
 
 /**
+ * e1000_alloc_queues - Allocate memory for all rings
+ * @adapter: board private structure to initialize
+ **/
+static int __devinit e1000_alloc_queues(struct e1000_adapter *adapter)
+{
+	adapter->tx_ring = kzalloc(sizeof(struct e1000_ring), GFP_KERNEL);
+	if (!adapter->tx_ring)
+		goto err;
+
+	adapter->rx_ring = kzalloc(sizeof(struct e1000_ring), GFP_KERNEL);
+	if (!adapter->rx_ring)
+		goto err;
+
+	return 0;
+err:
+	e_err("Unable to allocate memory for queues\n");
+	kfree(adapter->rx_ring);
+	kfree(adapter->tx_ring);
+	return -ENOMEM;
+}
+
+/**
  * e1000_clean - NAPI Rx polling callback
  * @napi: struct associated with this polling callback
  * @budget: amount of packets driver is allowed to process this poll
@@ -1673,12 +1986,17 @@
 static int e1000_clean(struct napi_struct *napi, int budget)
 {
 	struct e1000_adapter *adapter = container_of(napi, struct e1000_adapter, napi);
+	struct e1000_hw *hw = &adapter->hw;
 	struct net_device *poll_dev = adapter->netdev;
 	int tx_cleaned = 0, work_done = 0;
 
 	/* Must NOT use netdev_priv macro here. */
 	adapter = poll_dev->priv;
 
+	if (adapter->msix_entries &&
+	    !(adapter->rx_ring->ims_val & adapter->tx_ring->ims_val))
+		goto clean_rx;
+
 	/*
 	 * e1000_clean is called per-cpu.  This lock protects
 	 * tx_ring from being cleaned by multiple cpus
@@ -1690,6 +2008,7 @@
 		spin_unlock(&adapter->tx_queue_lock);
 	}
 
+clean_rx:
 	adapter->clean_rx(adapter, &work_done, budget);
 
 	if (tx_cleaned)
@@ -1700,7 +2019,10 @@
 		if (adapter->itr_setting & 3)
 			e1000_set_itr(adapter);
 		netif_rx_complete(poll_dev, napi);
-		e1000_irq_enable(adapter);
+		if (adapter->msix_entries)
+			ew32(IMS, adapter->rx_ring->ims_val);
+		else
+			e1000_irq_enable(adapter);
 	}
 
 	return work_done;
@@ -2496,6 +2818,8 @@
 	clear_bit(__E1000_DOWN, &adapter->state);
 
 	napi_enable(&adapter->napi);
+	if (adapter->msix_entries)
+		e1000_configure_msix(adapter);
 	e1000_irq_enable(adapter);
 
 	/* fire a link change interrupt to start the watchdog */
@@ -2579,29 +2903,18 @@
 	adapter->max_frame_size = netdev->mtu + ETH_HLEN + ETH_FCS_LEN;
 	adapter->min_frame_size = ETH_ZLEN + ETH_FCS_LEN;
 
-	adapter->tx_ring = kzalloc(sizeof(struct e1000_ring), GFP_KERNEL);
-	if (!adapter->tx_ring)
-		goto err;
+	e1000e_set_interrupt_capability(adapter);
 
-	adapter->rx_ring = kzalloc(sizeof(struct e1000_ring), GFP_KERNEL);
-	if (!adapter->rx_ring)
-		goto err;
+	if (e1000_alloc_queues(adapter))
+		return -ENOMEM;
 
 	spin_lock_init(&adapter->tx_queue_lock);
 
 	/* Explicitly disable IRQ since the NIC can be in any state. */
 	e1000_irq_disable(adapter);
 
-	spin_lock_init(&adapter->stats_lock);
-
 	set_bit(__E1000_DOWN, &adapter->state);
 	return 0;
-
-err:
-	e_err("Unable to allocate memory for queues\n");
-	kfree(adapter->rx_ring);
-	kfree(adapter->tx_ring);
-	return -ENOMEM;
 }
 
 /**
@@ -2643,6 +2956,7 @@
 
 	/* free the real vector and request a test handler */
 	e1000_free_irq(adapter);
+	e1000e_reset_interrupt_capability(adapter);
 
 	/* Assume that the test fails, if it succeeds then the test
 	 * MSI irq handler will unset this flag */
@@ -2673,6 +2987,7 @@
 	rmb();
 
 	if (adapter->flags & FLAG_MSI_TEST_FAILED) {
+		adapter->int_mode = E1000E_INT_MODE_LEGACY;
 		err = -EIO;
 		e_info("MSI interrupt test failed!\n");
 	}
@@ -2686,7 +3001,7 @@
 	/* okay so the test worked, restore settings */
 	e_dbg("%s: MSI interrupt test succeeded!\n", netdev->name);
 msi_test_failed:
-	/* restore the original vector, even if it failed */
+	e1000e_set_interrupt_capability(adapter);
 	e1000_request_irq(adapter);
 	return err;
 }
@@ -2796,7 +3111,7 @@
 	 * ignore e1000e MSI messages, which means we need to test our MSI
 	 * interrupt now
 	 */
-	{
+	if (adapter->int_mode != E1000E_INT_MODE_LEGACY) {
 		err = e1000_test_msi(adapter);
 		if (err) {
 			e_err("Interrupt allocation failed\n");
@@ -2912,6 +3227,21 @@
 	return 0;
 }
 
+/**
+ * e1000e_update_phy_task - work thread to update phy
+ * @work: pointer to our work struct
+ *
+ * this worker thread exists because we must acquire a
+ * semaphore to read the phy, which we could msleep while
+ * waiting for it, and we can't msleep in a timer.
+ **/
+static void e1000e_update_phy_task(struct work_struct *work)
+{
+	struct e1000_adapter *adapter = container_of(work,
+					struct e1000_adapter, update_phy_task);
+	e1000_get_phy_info(&adapter->hw);
+}
+
 /*
  * Need to wait a few seconds after link up to get diagnostic information from
  * the phy
@@ -2919,7 +3249,7 @@
 static void e1000_update_phy_info(unsigned long data)
 {
 	struct e1000_adapter *adapter = (struct e1000_adapter *) data;
-	e1000_get_phy_info(&adapter->hw);
+	schedule_work(&adapter->update_phy_task);
 }
 
 /**
@@ -2930,10 +3260,6 @@
 {
 	struct e1000_hw *hw = &adapter->hw;
 	struct pci_dev *pdev = adapter->pdev;
-	unsigned long irq_flags;
-	u16 phy_tmp;
-
-#define PHY_IDLE_ERROR_COUNT_MASK 0x00FF
 
 	/*
 	 * Prevent stats update while adapter is being reset, or if the pci
@@ -2944,14 +3270,6 @@
 	if (pci_channel_offline(pdev))
 		return;
 
-	spin_lock_irqsave(&adapter->stats_lock, irq_flags);
-
-	/*
-	 * these counters are modified from e1000_adjust_tbi_stats,
-	 * called from the interrupt context, so they must only
-	 * be written while holding adapter->stats_lock
-	 */
-
 	adapter->stats.crcerrs += er32(CRCERRS);
 	adapter->stats.gprc += er32(GPRC);
 	adapter->stats.gorc += er32(GORCL);
@@ -2988,7 +3306,8 @@
 
 	adapter->stats.algnerrc += er32(ALGNERRC);
 	adapter->stats.rxerrc += er32(RXERRC);
-	adapter->stats.tncrs += er32(TNCRS);
+	if (hw->mac.type != e1000_82574)
+		adapter->stats.tncrs += er32(TNCRS);
 	adapter->stats.cexterr += er32(CEXTERR);
 	adapter->stats.tsctc += er32(TSCTC);
 	adapter->stats.tsctfc += er32(TSCTFC);
@@ -3022,21 +3341,10 @@
 
 	/* Tx Dropped needs to be maintained elsewhere */
 
-	/* Phy Stats */
-	if (hw->phy.media_type == e1000_media_type_copper) {
-		if ((adapter->link_speed == SPEED_1000) &&
-		   (!e1e_rphy(hw, PHY_1000T_STATUS, &phy_tmp))) {
-			phy_tmp &= PHY_IDLE_ERROR_COUNT_MASK;
-			adapter->phy_stats.idle_errors += phy_tmp;
-		}
-	}
-
 	/* Management Stats */
 	adapter->stats.mgptc += er32(MGTPTC);
 	adapter->stats.mgprc += er32(MGTPRC);
 	adapter->stats.mgpdc += er32(MGTPDC);
-
-	spin_unlock_irqrestore(&adapter->stats_lock, irq_flags);
 }
 
 /**
@@ -3048,10 +3356,6 @@
 	struct e1000_hw *hw = &adapter->hw;
 	struct e1000_phy_regs *phy = &adapter->phy_regs;
 	int ret_val;
-	unsigned long irq_flags;
-
-
-	spin_lock_irqsave(&adapter->stats_lock, irq_flags);
 
 	if ((er32(STATUS) & E1000_STATUS_LU) &&
 	    (adapter->hw.phy.media_type == e1000_media_type_copper)) {
@@ -3082,8 +3386,6 @@
 		phy->stat1000 = 0;
 		phy->estatus = (ESTATUS_1000_TFULL | ESTATUS_1000_THALF);
 	}
-
-	spin_unlock_irqrestore(&adapter->stats_lock, irq_flags);
 }
 
 static void e1000_print_link_info(struct e1000_adapter *adapter)
@@ -3201,6 +3503,27 @@
 						   &adapter->link_duplex);
 			e1000_print_link_info(adapter);
 			/*
+			 * On supported PHYs, check for duplex mismatch only
+			 * if link has autonegotiated at 10/100 half
+			 */
+			if ((hw->phy.type == e1000_phy_igp_3 ||
+			     hw->phy.type == e1000_phy_bm) &&
+			    (hw->mac.autoneg == true) &&
+			    (adapter->link_speed == SPEED_10 ||
+			     adapter->link_speed == SPEED_100) &&
+			    (adapter->link_duplex == HALF_DUPLEX)) {
+				u16 autoneg_exp;
+
+				e1e_rphy(hw, PHY_AUTONEG_EXP, &autoneg_exp);
+
+				if (!(autoneg_exp & NWAY_ER_LP_NWAY_CAPS))
+					e_info("Autonegotiated half duplex but"
+					       " link partner cannot autoneg. "
+					       " Try forcing full duplex if "
+					       "link gets many collisions.\n");
+			}
+
+			/*
 			 * tweak tx_queue_len according to speed/duplex
 			 * and adjust the timeout factor
 			 */
@@ -3315,7 +3638,10 @@
 	}
 
 	/* Cause software interrupt to ensure Rx ring is cleaned */
-	ew32(ICS, E1000_ICS_RXDMT0);
+	if (adapter->msix_entries)
+		ew32(ICS, adapter->rx_ring->ims_val);
+	else
+		ew32(ICS, E1000_ICS_RXDMT0);
 
 	/* Force detection of hung controller every watchdog period */
 	adapter->detect_tx_hung = 1;
@@ -3423,34 +3749,50 @@
 	struct e1000_buffer *buffer_info;
 	unsigned int i;
 	u8 css;
+	u32 cmd_len = E1000_TXD_CMD_DEXT;
 
-	if (skb->ip_summed == CHECKSUM_PARTIAL) {
-		css = skb_transport_offset(skb);
+	if (skb->ip_summed != CHECKSUM_PARTIAL)
+		return 0;
 
-		i = tx_ring->next_to_use;
-		buffer_info = &tx_ring->buffer_info[i];
-		context_desc = E1000_CONTEXT_DESC(*tx_ring, i);
-
-		context_desc->lower_setup.ip_config = 0;
-		context_desc->upper_setup.tcp_fields.tucss = css;
-		context_desc->upper_setup.tcp_fields.tucso =
-					css + skb->csum_offset;
-		context_desc->upper_setup.tcp_fields.tucse = 0;
-		context_desc->tcp_seg_setup.data = 0;
-		context_desc->cmd_and_length = cpu_to_le32(E1000_TXD_CMD_DEXT);
-
-		buffer_info->time_stamp = jiffies;
-		buffer_info->next_to_watch = i;
-
-		i++;
-		if (i == tx_ring->count)
-			i = 0;
-		tx_ring->next_to_use = i;
-
-		return 1;
+	switch (skb->protocol) {
+	case __constant_htons(ETH_P_IP):
+		if (ip_hdr(skb)->protocol == IPPROTO_TCP)
+			cmd_len |= E1000_TXD_CMD_TCP;
+		break;
+	case __constant_htons(ETH_P_IPV6):
+		/* XXX not handling all IPV6 headers */
+		if (ipv6_hdr(skb)->nexthdr == IPPROTO_TCP)
+			cmd_len |= E1000_TXD_CMD_TCP;
+		break;
+	default:
+		if (unlikely(net_ratelimit()))
+			e_warn("checksum_partial proto=%x!\n", skb->protocol);
+		break;
 	}
 
-	return 0;
+	css = skb_transport_offset(skb);
+
+	i = tx_ring->next_to_use;
+	buffer_info = &tx_ring->buffer_info[i];
+	context_desc = E1000_CONTEXT_DESC(*tx_ring, i);
+
+	context_desc->lower_setup.ip_config = 0;
+	context_desc->upper_setup.tcp_fields.tucss = css;
+	context_desc->upper_setup.tcp_fields.tucso =
+				css + skb->csum_offset;
+	context_desc->upper_setup.tcp_fields.tucse = 0;
+	context_desc->tcp_seg_setup.data = 0;
+	context_desc->cmd_and_length = cpu_to_le32(cmd_len);
+
+	buffer_info->time_stamp = jiffies;
+	buffer_info->next_to_watch = i;
+
+	i++;
+	if (i == tx_ring->count)
+		i = 0;
+	tx_ring->next_to_use = i;
+
+	return 1;
 }
 
 #define E1000_MAX_PER_TXD	8192
@@ -4032,6 +4374,7 @@
 		e1000e_down(adapter);
 		e1000_free_irq(adapter);
 	}
+	e1000e_reset_interrupt_capability(adapter);
 
 	retval = pci_save_state(pdev);
 	if (retval)
@@ -4158,6 +4501,7 @@
 	pci_enable_wake(pdev, PCI_D3hot, 0);
 	pci_enable_wake(pdev, PCI_D3cold, 0);
 
+	e1000e_set_interrupt_capability(adapter);
 	if (netif_running(netdev)) {
 		err = e1000_request_irq(adapter);
 		if (err)
@@ -4335,13 +4679,15 @@
 	ret_val = e1000_read_nvm(hw, NVM_INIT_CONTROL2_REG, 1, &buf);
 	if (!(le16_to_cpu(buf) & (1 << 0))) {
 		/* Deep Smart Power Down (DSPD) */
-		e_warn("Warning: detected DSPD enabled in EEPROM\n");
+		dev_warn(&adapter->pdev->dev,
+			 "Warning: detected DSPD enabled in EEPROM\n");
 	}
 
 	ret_val = e1000_read_nvm(hw, NVM_INIT_3GIO_3, 1, &buf);
 	if (le16_to_cpu(buf) & (3 << 2)) {
 		/* ASPM enable */
-		e_warn("Warning: detected ASPM enabled in EEPROM\n");
+		dev_warn(&adapter->pdev->dev,
+			 "Warning: detected ASPM enabled in EEPROM\n");
 	}
 }
 
@@ -4467,6 +4813,8 @@
 
 	adapter->bd_number = cards_found++;
 
+	e1000e_check_options(adapter);
+
 	/* setup adapter struct */
 	err = e1000_sw_init(adapter);
 	if (err)
@@ -4482,6 +4830,10 @@
 	if (err)
 		goto err_hw_init;
 
+	if ((adapter->flags & FLAG_IS_ICH) &&
+	    (adapter->flags & FLAG_READ_ONLY_NVM))
+		e1000e_write_protect_nvm_ich8lan(&adapter->hw);
+
 	hw->mac.ops.get_bus_info(&adapter->hw);
 
 	adapter->hw.phy.autoneg_wait_to_complete = 0;
@@ -4572,8 +4924,8 @@
 
 	INIT_WORK(&adapter->reset_task, e1000_reset_task);
 	INIT_WORK(&adapter->watchdog_task, e1000_watchdog_task);
-
-	e1000e_check_options(adapter);
+	INIT_WORK(&adapter->downshift_task, e1000e_downshift_workaround);
+	INIT_WORK(&adapter->update_phy_task, e1000e_update_phy_task);
 
 	/* Initialize link parameters. User can change them with ethtool */
 	adapter->hw.mac.autoneg = 1;
@@ -4704,6 +5056,7 @@
 	if (!e1000_check_reset_block(&adapter->hw))
 		e1000_phy_hw_reset(&adapter->hw);
 
+	e1000e_reset_interrupt_capability(adapter);
 	kfree(adapter->tx_ring);
 	kfree(adapter->rx_ring);
 
@@ -4745,6 +5098,8 @@
 	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82573E_IAMT), board_82573 },
 	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82573L), board_82573 },
 
+	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82574L), board_82574 },
+
 	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_80003ES2LAN_COPPER_DPT),
 	  board_80003es2lan },
 	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_80003ES2LAN_COPPER_SPT),
@@ -4767,6 +5122,7 @@
 	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH9_IFE_GT), board_ich9lan },
 	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH9_IGP_AMT), board_ich9lan },
 	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH9_IGP_C), board_ich9lan },
+	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH9_BM), board_ich9lan },
 	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH9_IGP_M), board_ich9lan },
 	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH9_IGP_M_AMT), board_ich9lan },
 	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH9_IGP_M_V), board_ich9lan },
@@ -4775,6 +5131,9 @@
 	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH10_R_BM_LF), board_ich9lan },
 	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH10_R_BM_V), board_ich9lan },
 
+	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH10_D_BM_LM), board_ich10lan },
+	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH10_D_BM_LF), board_ich10lan },
+
 	{ }	/* terminate list */
 };
 MODULE_DEVICE_TABLE(pci, e1000_pci_tbl);
diff --git a/drivers/net/e1000e/param.c b/drivers/net/e1000e/param.c
index ed912e0..77a3d72 100644
--- a/drivers/net/e1000e/param.c
+++ b/drivers/net/e1000e/param.c
@@ -114,6 +114,15 @@
 #define DEFAULT_ITR 3
 #define MAX_ITR 100000
 #define MIN_ITR 100
+/* IntMode (Interrupt Mode)
+ *
+ * Valid Range: 0 - 2
+ *
+ * Default Value: 2 (MSI-X)
+ */
+E1000_PARAM(IntMode, "Interrupt Mode");
+#define MAX_INTMODE	2
+#define MIN_INTMODE	0
 
 /*
  * Enable Smart Power Down of the PHY
@@ -133,6 +142,15 @@
  */
 E1000_PARAM(KumeranLockLoss, "Enable Kumeran lock loss workaround");
 
+/*
+ * Write Protect NVM
+ *
+ * Valid Range: 0, 1
+ *
+ * Default Value: 1 (enabled)
+ */
+E1000_PARAM(WriteProtectNVM, "Write-protect NVM [WARNING: disabling this can lead to corrupted NVM]");
+
 struct e1000_option {
 	enum { enable_option, range_option, list_option } type;
 	const char *name;
@@ -352,6 +370,24 @@
 			adapter->itr = 20000;
 		}
 	}
+	{ /* Interrupt Mode */
+		struct e1000_option opt = {
+			.type = range_option,
+			.name = "Interrupt Mode",
+			.err  = "defaulting to 2 (MSI-X)",
+			.def  = E1000E_INT_MODE_MSIX,
+			.arg  = { .r = { .min = MIN_INTMODE,
+					 .max = MAX_INTMODE } }
+		};
+
+		if (num_IntMode > bd) {
+			unsigned int int_mode = IntMode[bd];
+			e1000_validate_option(&int_mode, &opt, adapter);
+			adapter->int_mode = int_mode;
+		} else {
+			adapter->int_mode = opt.def;
+		}
+	}
 	{ /* Smart Power Down */
 		const struct e1000_option opt = {
 			.type = enable_option,
@@ -388,4 +424,25 @@
 								       opt.def);
 		}
 	}
+	{ /* Write-protect NVM */
+		const struct e1000_option opt = {
+			.type = enable_option,
+			.name = "Write-protect NVM",
+			.err  = "defaulting to Enabled",
+			.def  = OPTION_ENABLED
+		};
+
+		if (adapter->flags & FLAG_IS_ICH) {
+			if (num_WriteProtectNVM > bd) {
+				unsigned int write_protect_nvm = WriteProtectNVM[bd];
+				e1000_validate_option(&write_protect_nvm, &opt,
+						      adapter);
+				if (write_protect_nvm)
+					adapter->flags |= FLAG_READ_ONLY_NVM;
+			} else {
+				if (opt.def)
+					adapter->flags |= FLAG_READ_ONLY_NVM;
+			}
+		}
+	}
 }
diff --git a/drivers/net/e1000e/phy.c b/drivers/net/e1000e/phy.c
index b133dcf..6cd333a 100644
--- a/drivers/net/e1000e/phy.c
+++ b/drivers/net/e1000e/phy.c
@@ -476,7 +476,9 @@
 	if (ret_val)
 		return ret_val;
 
-	if ((phy->type == e1000_phy_m88) && (phy->revision < 4)) {
+	if ((phy->type == e1000_phy_m88) &&
+	    (phy->revision < E1000_REVISION_4) &&
+	    (phy->id != BME1000_E_PHY_ID_R2)) {
 		/*
 		 * Force TX_CLK in the Extended PHY Specific Control Register
 		 * to 25MHz clock.
@@ -504,6 +506,18 @@
 			return ret_val;
 	}
 
+	if ((phy->type == e1000_phy_bm) && (phy->id == BME1000_E_PHY_ID_R2)) {
+		/* Set PHY page 0, register 29 to 0x0003 */
+		ret_val = e1e_wphy(hw, 29, 0x0003);
+		if (ret_val)
+			return ret_val;
+
+		/* Set PHY page 0, register 30 to 0x0000 */
+		ret_val = e1e_wphy(hw, 30, 0x0000);
+		if (ret_val)
+			return ret_val;
+	}
+
 	/* Commit the changes. */
 	ret_val = e1000e_commit_phy(hw);
 	if (ret_val)
@@ -1720,6 +1734,91 @@
 	return 0;
 }
 
+/**
+ *  e1000e_phy_init_script_igp3 - Inits the IGP3 PHY
+ *  @hw: pointer to the HW structure
+ *
+ *  Initializes a Intel Gigabit PHY3 when an EEPROM is not present.
+ **/
+s32 e1000e_phy_init_script_igp3(struct e1000_hw *hw)
+{
+	hw_dbg(hw, "Running IGP 3 PHY init script\n");
+
+	/* PHY init IGP 3 */
+	/* Enable rise/fall, 10-mode work in class-A */
+	e1e_wphy(hw, 0x2F5B, 0x9018);
+	/* Remove all caps from Replica path filter */
+	e1e_wphy(hw, 0x2F52, 0x0000);
+	/* Bias trimming for ADC, AFE and Driver (Default) */
+	e1e_wphy(hw, 0x2FB1, 0x8B24);
+	/* Increase Hybrid poly bias */
+	e1e_wphy(hw, 0x2FB2, 0xF8F0);
+	/* Add 4% to Tx amplitude in Gig mode */
+	e1e_wphy(hw, 0x2010, 0x10B0);
+	/* Disable trimming (TTT) */
+	e1e_wphy(hw, 0x2011, 0x0000);
+	/* Poly DC correction to 94.6% + 2% for all channels */
+	e1e_wphy(hw, 0x20DD, 0x249A);
+	/* ABS DC correction to 95.9% */
+	e1e_wphy(hw, 0x20DE, 0x00D3);
+	/* BG temp curve trim */
+	e1e_wphy(hw, 0x28B4, 0x04CE);
+	/* Increasing ADC OPAMP stage 1 currents to max */
+	e1e_wphy(hw, 0x2F70, 0x29E4);
+	/* Force 1000 ( required for enabling PHY regs configuration) */
+	e1e_wphy(hw, 0x0000, 0x0140);
+	/* Set upd_freq to 6 */
+	e1e_wphy(hw, 0x1F30, 0x1606);
+	/* Disable NPDFE */
+	e1e_wphy(hw, 0x1F31, 0xB814);
+	/* Disable adaptive fixed FFE (Default) */
+	e1e_wphy(hw, 0x1F35, 0x002A);
+	/* Enable FFE hysteresis */
+	e1e_wphy(hw, 0x1F3E, 0x0067);
+	/* Fixed FFE for short cable lengths */
+	e1e_wphy(hw, 0x1F54, 0x0065);
+	/* Fixed FFE for medium cable lengths */
+	e1e_wphy(hw, 0x1F55, 0x002A);
+	/* Fixed FFE for long cable lengths */
+	e1e_wphy(hw, 0x1F56, 0x002A);
+	/* Enable Adaptive Clip Threshold */
+	e1e_wphy(hw, 0x1F72, 0x3FB0);
+	/* AHT reset limit to 1 */
+	e1e_wphy(hw, 0x1F76, 0xC0FF);
+	/* Set AHT master delay to 127 msec */
+	e1e_wphy(hw, 0x1F77, 0x1DEC);
+	/* Set scan bits for AHT */
+	e1e_wphy(hw, 0x1F78, 0xF9EF);
+	/* Set AHT Preset bits */
+	e1e_wphy(hw, 0x1F79, 0x0210);
+	/* Change integ_factor of channel A to 3 */
+	e1e_wphy(hw, 0x1895, 0x0003);
+	/* Change prop_factor of channels BCD to 8 */
+	e1e_wphy(hw, 0x1796, 0x0008);
+	/* Change cg_icount + enable integbp for channels BCD */
+	e1e_wphy(hw, 0x1798, 0xD008);
+	/*
+	 * Change cg_icount + enable integbp + change prop_factor_master
+	 * to 8 for channel A
+	 */
+	e1e_wphy(hw, 0x1898, 0xD918);
+	/* Disable AHT in Slave mode on channel A */
+	e1e_wphy(hw, 0x187A, 0x0800);
+	/*
+	 * Enable LPLU and disable AN to 1000 in non-D0a states,
+	 * Enable SPD+B2B
+	 */
+	e1e_wphy(hw, 0x0019, 0x008D);
+	/* Enable restart AN on an1000_dis change */
+	e1e_wphy(hw, 0x001B, 0x2080);
+	/* Enable wh_fifo read clock in 10/100 modes */
+	e1e_wphy(hw, 0x0014, 0x0045);
+	/* Restart AN, Speed selection is 1000 */
+	e1e_wphy(hw, 0x0000, 0x1340);
+
+	return 0;
+}
+
 /* Internal function pointers */
 
 /**
@@ -1969,6 +2068,99 @@
 }
 
 /**
+ *  e1000e_read_phy_reg_bm2 - Read BM PHY register
+ *  @hw: pointer to the HW structure
+ *  @offset: register offset to be read
+ *  @data: pointer to the read data
+ *
+ *  Acquires semaphore, if necessary, then reads the PHY register at offset
+ *  and storing the retrieved information in data.  Release any acquired
+ *  semaphores before exiting.
+ **/
+s32 e1000e_read_phy_reg_bm2(struct e1000_hw *hw, u32 offset, u16 *data)
+{
+	s32 ret_val;
+	u16 page = (u16)(offset >> IGP_PAGE_SHIFT);
+
+	/* Page 800 works differently than the rest so it has its own func */
+	if (page == BM_WUC_PAGE) {
+		ret_val = e1000_access_phy_wakeup_reg_bm(hw, offset, data,
+							 true);
+		return ret_val;
+	}
+
+	ret_val = hw->phy.ops.acquire_phy(hw);
+	if (ret_val)
+		return ret_val;
+
+	hw->phy.addr = 1;
+
+	if (offset > MAX_PHY_MULTI_PAGE_REG) {
+
+		/* Page is shifted left, PHY expects (page x 32) */
+		ret_val = e1000e_write_phy_reg_mdic(hw, BM_PHY_PAGE_SELECT,
+						    page);
+
+		if (ret_val) {
+			hw->phy.ops.release_phy(hw);
+			return ret_val;
+		}
+	}
+
+	ret_val = e1000e_read_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset,
+					   data);
+	hw->phy.ops.release_phy(hw);
+
+	return ret_val;
+}
+
+/**
+ *  e1000e_write_phy_reg_bm2 - Write BM PHY register
+ *  @hw: pointer to the HW structure
+ *  @offset: register offset to write to
+ *  @data: data to write at register offset
+ *
+ *  Acquires semaphore, if necessary, then writes the data to PHY register
+ *  at the offset.  Release any acquired semaphores before exiting.
+ **/
+s32 e1000e_write_phy_reg_bm2(struct e1000_hw *hw, u32 offset, u16 data)
+{
+	s32 ret_val;
+	u16 page = (u16)(offset >> IGP_PAGE_SHIFT);
+
+	/* Page 800 works differently than the rest so it has its own func */
+	if (page == BM_WUC_PAGE) {
+		ret_val = e1000_access_phy_wakeup_reg_bm(hw, offset, &data,
+							 false);
+		return ret_val;
+	}
+
+	ret_val = hw->phy.ops.acquire_phy(hw);
+	if (ret_val)
+		return ret_val;
+
+	hw->phy.addr = 1;
+
+	if (offset > MAX_PHY_MULTI_PAGE_REG) {
+		/* Page is shifted left, PHY expects (page x 32) */
+		ret_val = e1000e_write_phy_reg_mdic(hw, BM_PHY_PAGE_SELECT,
+						    page);
+
+		if (ret_val) {
+			hw->phy.ops.release_phy(hw);
+			return ret_val;
+		}
+	}
+
+	ret_val = e1000e_write_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset,
+					    data);
+
+	hw->phy.ops.release_phy(hw);
+
+	return ret_val;
+}
+
+/**
  *  e1000_access_phy_wakeup_reg_bm - Read BM PHY wakeup register
  *  @hw: pointer to the HW structure
  *  @offset: register offset to be read or written
diff --git a/drivers/net/eexpress.c b/drivers/net/eexpress.c
index 795c594..b751c1b 100644
--- a/drivers/net/eexpress.c
+++ b/drivers/net/eexpress.c
@@ -8,7 +8,7 @@
  *
  * Many modifications, and currently maintained, by
  *  Philip Blundell <philb@gnu.org>
- * Added the Compaq LTE  Alan Cox <alan@redhat.com>
+ * Added the Compaq LTE  Alan Cox <alan@lxorguk.ukuu.org.uk>
  * Added MCA support Adam Fritzler
  *
  * Note - this driver is experimental still - it has problems on faster
diff --git a/drivers/net/ehea/ehea.h b/drivers/net/ehea/ehea.h
index e01926b..5524271 100644
--- a/drivers/net/ehea/ehea.h
+++ b/drivers/net/ehea/ehea.h
@@ -40,13 +40,13 @@
 #include <asm/io.h>
 
 #define DRV_NAME	"ehea"
-#define DRV_VERSION	"EHEA_0092"
+#define DRV_VERSION	"EHEA_0093"
 
 /* eHEA capability flags */
 #define DLPAR_PORT_ADD_REM 1
 #define DLPAR_MEM_ADD      2
 #define DLPAR_MEM_REM      4
-#define EHEA_CAPABILITIES  (DLPAR_PORT_ADD_REM | DLPAR_MEM_ADD)
+#define EHEA_CAPABILITIES  (DLPAR_PORT_ADD_REM | DLPAR_MEM_ADD | DLPAR_MEM_REM)
 
 #define EHEA_MSG_DEFAULT (NETIF_MSG_LINK | NETIF_MSG_TIMER \
 	| NETIF_MSG_RX_ERR | NETIF_MSG_TX_ERR)
diff --git a/drivers/net/ehea/ehea_phyp.c b/drivers/net/ehea/ehea_phyp.c
index 156eb63..2a33a61 100644
--- a/drivers/net/ehea/ehea_phyp.c
+++ b/drivers/net/ehea/ehea_phyp.c
@@ -535,7 +535,7 @@
 				       cb_logaddr,		/* R5 */
 				       0, 0, 0, 0, 0);		/* R6-R10 */
 #ifdef DEBUG
-	ehea_dmp(cb_addr, sizeof(struct hcp_query_ehea), "hcp_query_ehea");
+	ehea_dump(cb_addr, sizeof(struct hcp_query_ehea), "hcp_query_ehea");
 #endif
 	return hret;
 }
diff --git a/drivers/net/ehea/ehea_qmr.c b/drivers/net/ehea/ehea_qmr.c
index 140f05b..db8a925 100644
--- a/drivers/net/ehea/ehea_qmr.c
+++ b/drivers/net/ehea/ehea_qmr.c
@@ -595,7 +595,8 @@
 	end_section = start_section + ((nr_pages * PAGE_SIZE) / EHEA_SECTSIZE);
 	mr_len = *(unsigned long *)arg;
 
-	ehea_bmap = kzalloc(sizeof(struct ehea_bmap), GFP_KERNEL);
+	if (!ehea_bmap)
+		ehea_bmap = kzalloc(sizeof(struct ehea_bmap), GFP_KERNEL);
 	if (!ehea_bmap)
 		return -ENOMEM;
 
diff --git a/drivers/net/enc28j60.c b/drivers/net/enc28j60.c
index aa0bf6e..e1b441e 100644
--- a/drivers/net/enc28j60.c
+++ b/drivers/net/enc28j60.c
@@ -110,7 +110,7 @@
 	}
 	if (ret && netif_msg_drv(priv))
 		printk(KERN_DEBUG DRV_NAME ": %s() failed: ret = %d\n",
-			__FUNCTION__, ret);
+			__func__, ret);
 
 	return ret;
 }
@@ -131,7 +131,7 @@
 		ret = spi_write(priv->spi, priv->spi_transfer_buf, len + 1);
 		if (ret && netif_msg_drv(priv))
 			printk(KERN_DEBUG DRV_NAME ": %s() failed: ret = %d\n",
-				__FUNCTION__, ret);
+				__func__, ret);
 	}
 	return ret;
 }
@@ -156,7 +156,7 @@
 	ret = spi_write_then_read(priv->spi, tx_buf, 1, rx_buf, slen);
 	if (ret)
 		printk(KERN_DEBUG DRV_NAME ": %s() failed: ret = %d\n",
-			__FUNCTION__, ret);
+			__func__, ret);
 	else
 		val = rx_buf[slen - 1];
 
@@ -176,14 +176,14 @@
 	ret = spi_write(priv->spi, priv->spi_transfer_buf, 2);
 	if (ret && netif_msg_drv(priv))
 		printk(KERN_DEBUG DRV_NAME ": %s() failed: ret = %d\n",
-			__FUNCTION__, ret);
+			__func__, ret);
 	return ret;
 }
 
 static void enc28j60_soft_reset(struct enc28j60_net *priv)
 {
 	if (netif_msg_hw(priv))
-		printk(KERN_DEBUG DRV_NAME ": %s() enter\n", __FUNCTION__);
+		printk(KERN_DEBUG DRV_NAME ": %s() enter\n", __func__);
 
 	spi_write_op(priv, ENC28J60_SOFT_RESET, 0, ENC28J60_SOFT_RESET);
 	/* Errata workaround #1, CLKRDY check is unreliable,
@@ -357,7 +357,7 @@
 		reg = nolock_regw_read(priv, ERDPTL);
 		if (reg != addr)
 			printk(KERN_DEBUG DRV_NAME ": %s() error writing ERDPT "
-				"(0x%04x - 0x%04x)\n", __FUNCTION__, reg, addr);
+				"(0x%04x - 0x%04x)\n", __func__, reg, addr);
 	}
 #endif
 	spi_read_buf(priv, len, data);
@@ -380,7 +380,7 @@
 		if (reg != TXSTART_INIT)
 			printk(KERN_DEBUG DRV_NAME
 				": %s() ERWPT:0x%04x != 0x%04x\n",
-				__FUNCTION__, reg, TXSTART_INIT);
+				__func__, reg, TXSTART_INIT);
 	}
 #endif
 	/* Set the TXND pointer to correspond to the packet size given */
@@ -390,13 +390,13 @@
 	if (netif_msg_hw(priv))
 		printk(KERN_DEBUG DRV_NAME
 			": %s() after control byte ERWPT:0x%04x\n",
-			__FUNCTION__, nolock_regw_read(priv, EWRPTL));
+			__func__, nolock_regw_read(priv, EWRPTL));
 	/* copy the packet into the transmit buffer */
 	spi_write_buf(priv, len, data);
 	if (netif_msg_hw(priv))
 		printk(KERN_DEBUG DRV_NAME
 			 ": %s() after write packet ERWPT:0x%04x, len=%d\n",
-			 __FUNCTION__, nolock_regw_read(priv, EWRPTL), len);
+			 __func__, nolock_regw_read(priv, EWRPTL), len);
 	mutex_unlock(&priv->lock);
 }
 
@@ -495,7 +495,7 @@
 		if (netif_msg_drv(priv))
 			printk(KERN_DEBUG DRV_NAME
 				": %s() Hardware must be disabled to set "
-				"Mac address\n", __FUNCTION__);
+				"Mac address\n", __func__);
 		ret = -EBUSY;
 	}
 	mutex_unlock(&priv->lock);
@@ -575,7 +575,7 @@
 	if (start > 0x1FFF || end > 0x1FFF || start > end) {
 		if (netif_msg_drv(priv))
 			printk(KERN_ERR DRV_NAME ": %s(%d, %d) RXFIFO "
-				"bad parameters!\n", __FUNCTION__, start, end);
+				"bad parameters!\n", __func__, start, end);
 		return;
 	}
 	/* set receive buffer start + end */
@@ -591,7 +591,7 @@
 	if (start > 0x1FFF || end > 0x1FFF || start > end) {
 		if (netif_msg_drv(priv))
 			printk(KERN_ERR DRV_NAME ": %s(%d, %d) TXFIFO "
-				"bad parameters!\n", __FUNCTION__, start, end);
+				"bad parameters!\n", __func__, start, end);
 		return;
 	}
 	/* set transmit buffer start + end */
@@ -630,7 +630,7 @@
 	u8 reg;
 
 	if (netif_msg_drv(priv))
-		printk(KERN_DEBUG DRV_NAME ": %s() - %s\n", __FUNCTION__,
+		printk(KERN_DEBUG DRV_NAME ": %s() - %s\n", __func__,
 			priv->full_duplex ? "FullDuplex" : "HalfDuplex");
 
 	mutex_lock(&priv->lock);
@@ -661,7 +661,7 @@
 	if (reg == 0x00 || reg == 0xff) {
 		if (netif_msg_drv(priv))
 			printk(KERN_DEBUG DRV_NAME ": %s() Invalid RevId %d\n",
-				__FUNCTION__, reg);
+				__func__, reg);
 		return 0;
 	}
 
@@ -724,7 +724,7 @@
 	/* enable interrupts */
 	if (netif_msg_hw(priv))
 		printk(KERN_DEBUG DRV_NAME ": %s() enabling interrupts.\n",
-			__FUNCTION__);
+			__func__);
 
 	enc28j60_phy_write(priv, PHIE, PHIE_PGEIE | PHIE_PLNKIE);
 
@@ -888,7 +888,7 @@
 		if (netif_msg_rx_err(priv))
 			dev_err(&ndev->dev,
 				"%s() Invalid packet address!! 0x%04x\n",
-				__FUNCTION__, priv->next_pk_ptr);
+				__func__, priv->next_pk_ptr);
 		/* packet address corrupted: reset RX logic */
 		mutex_lock(&priv->lock);
 		nolock_reg_bfclr(priv, ECON1, ECON1_RXEN);
@@ -917,7 +917,7 @@
 	rxstat |= rsv[4];
 
 	if (netif_msg_rx_status(priv))
-		enc28j60_dump_rsv(priv, __FUNCTION__, next_packet, len, rxstat);
+		enc28j60_dump_rsv(priv, __func__, next_packet, len, rxstat);
 
 	if (!RSV_GETBIT(rxstat, RSV_RXOK)) {
 		if (netif_msg_rx_err(priv))
@@ -941,7 +941,7 @@
 			enc28j60_mem_read(priv, priv->next_pk_ptr + sizeof(rsv),
 					len, skb_put(skb, len));
 			if (netif_msg_pktdata(priv))
-				dump_packet(__FUNCTION__, skb->len, skb->data);
+				dump_packet(__func__, skb->len, skb->data);
 			skb->protocol = eth_type_trans(skb, ndev);
 			/* update statistics */
 			ndev->stats.rx_packets++;
@@ -958,7 +958,7 @@
 	erxrdpt = erxrdpt_workaround(next_packet, RXSTART_INIT, RXEND_INIT);
 	if (netif_msg_hw(priv))
 		printk(KERN_DEBUG DRV_NAME ": %s() ERXRDPT:0x%04x\n",
-			__FUNCTION__, erxrdpt);
+			__func__, erxrdpt);
 
 	mutex_lock(&priv->lock);
 	nolock_regw_write(priv, ERXRDPTL, erxrdpt);
@@ -968,7 +968,7 @@
 		reg = nolock_regw_read(priv, ERXRDPTL);
 		if (reg != erxrdpt)
 			printk(KERN_DEBUG DRV_NAME ": %s() ERXRDPT verify "
-				"error (0x%04x - 0x%04x)\n", __FUNCTION__,
+				"error (0x%04x - 0x%04x)\n", __func__,
 				reg, erxrdpt);
 	}
 #endif
@@ -1006,7 +1006,7 @@
 	mutex_unlock(&priv->lock);
 	if (netif_msg_rx_status(priv))
 		printk(KERN_DEBUG DRV_NAME ": %s() free_space = %d\n",
-			__FUNCTION__, free_space);
+			__func__, free_space);
 	return free_space;
 }
 
@@ -1022,7 +1022,7 @@
 	reg = enc28j60_phy_read(priv, PHSTAT2);
 	if (netif_msg_hw(priv))
 		printk(KERN_DEBUG DRV_NAME ": %s() PHSTAT1: %04x, "
-			"PHSTAT2: %04x\n", __FUNCTION__,
+			"PHSTAT2: %04x\n", __func__,
 			enc28j60_phy_read(priv, PHSTAT1), reg);
 	duplex = reg & PHSTAT2_DPXSTAT;
 
@@ -1095,7 +1095,7 @@
 	int intflags, loop;
 
 	if (netif_msg_intr(priv))
-		printk(KERN_DEBUG DRV_NAME ": %s() enter\n", __FUNCTION__);
+		printk(KERN_DEBUG DRV_NAME ": %s() enter\n", __func__);
 	/* disable further interrupts */
 	locked_reg_bfclr(priv, EIE, EIE_INTIE);
 
@@ -1198,7 +1198,7 @@
 	/* re-enable interrupts */
 	locked_reg_bfset(priv, EIE, EIE_INTIE);
 	if (netif_msg_intr(priv))
-		printk(KERN_DEBUG DRV_NAME ": %s() exit\n", __FUNCTION__);
+		printk(KERN_DEBUG DRV_NAME ": %s() exit\n", __func__);
 }
 
 /*
@@ -1213,7 +1213,7 @@
 			": Tx Packet Len:%d\n", priv->tx_skb->len);
 
 	if (netif_msg_pktdata(priv))
-		dump_packet(__FUNCTION__,
+		dump_packet(__func__,
 			    priv->tx_skb->len, priv->tx_skb->data);
 	enc28j60_packet_write(priv, priv->tx_skb->len, priv->tx_skb->data);
 
@@ -1254,7 +1254,7 @@
 	struct enc28j60_net *priv = netdev_priv(dev);
 
 	if (netif_msg_tx_queued(priv))
-		printk(KERN_DEBUG DRV_NAME ": %s() enter\n", __FUNCTION__);
+		printk(KERN_DEBUG DRV_NAME ": %s() enter\n", __func__);
 
 	/* If some error occurs while trying to transmit this
 	 * packet, you should return '1' from this function.
@@ -1325,7 +1325,7 @@
 	struct enc28j60_net *priv = netdev_priv(dev);
 
 	if (netif_msg_drv(priv))
-		printk(KERN_DEBUG DRV_NAME ": %s() enter\n", __FUNCTION__);
+		printk(KERN_DEBUG DRV_NAME ": %s() enter\n", __func__);
 
 	if (!is_valid_ether_addr(dev->dev_addr)) {
 		if (netif_msg_ifup(priv)) {
@@ -1363,7 +1363,7 @@
 	struct enc28j60_net *priv = netdev_priv(dev);
 
 	if (netif_msg_drv(priv))
-		printk(KERN_DEBUG DRV_NAME ": %s() enter\n", __FUNCTION__);
+		printk(KERN_DEBUG DRV_NAME ": %s() enter\n", __func__);
 
 	enc28j60_hw_disable(priv);
 	enc28j60_lowpower(priv, true);
diff --git a/drivers/net/enic/Makefile b/drivers/net/enic/Makefile
new file mode 100644
index 0000000..391c3bc
--- /dev/null
+++ b/drivers/net/enic/Makefile
@@ -0,0 +1,5 @@
+obj-$(CONFIG_ENIC) := enic.o
+
+enic-y := enic_main.o vnic_cq.o vnic_intr.o vnic_wq.o \
+	enic_res.o vnic_dev.o vnic_rq.o
+
diff --git a/drivers/net/enic/cq_desc.h b/drivers/net/enic/cq_desc.h
new file mode 100644
index 0000000..c036a8b
--- /dev/null
+++ b/drivers/net/enic/cq_desc.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2008 Cisco Systems, Inc.  All rights reserved.
+ * Copyright 2007 Nuova Systems, Inc.  All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+#ifndef _CQ_DESC_H_
+#define _CQ_DESC_H_
+
+/*
+ * Completion queue descriptor types
+ */
+enum cq_desc_types {
+	CQ_DESC_TYPE_WQ_ENET = 0,
+	CQ_DESC_TYPE_DESC_COPY = 1,
+	CQ_DESC_TYPE_WQ_EXCH = 2,
+	CQ_DESC_TYPE_RQ_ENET = 3,
+	CQ_DESC_TYPE_RQ_FCP = 4,
+};
+
+/* Completion queue descriptor: 16B
+ *
+ * All completion queues have this basic layout.  The
+ * type_specfic area is unique for each completion
+ * queue type.
+ */
+struct cq_desc {
+	__le16 completed_index;
+	__le16 q_number;
+	u8 type_specfic[11];
+	u8 type_color;
+};
+
+#define CQ_DESC_TYPE_BITS        7
+#define CQ_DESC_TYPE_MASK        ((1 << CQ_DESC_TYPE_BITS) - 1)
+#define CQ_DESC_COLOR_MASK       1
+#define CQ_DESC_Q_NUM_BITS       10
+#define CQ_DESC_Q_NUM_MASK       ((1 << CQ_DESC_Q_NUM_BITS) - 1)
+#define CQ_DESC_COMP_NDX_BITS    12
+#define CQ_DESC_COMP_NDX_MASK    ((1 << CQ_DESC_COMP_NDX_BITS) - 1)
+
+static inline void cq_desc_dec(const struct cq_desc *desc_arg,
+	u8 *type, u8 *color, u16 *q_number, u16 *completed_index)
+{
+	const struct cq_desc *desc = desc_arg;
+	const u8 type_color = desc->type_color;
+
+	*color = (type_color >> CQ_DESC_TYPE_BITS) & CQ_DESC_COLOR_MASK;
+
+	/*
+	 * Make sure color bit is read from desc *before* other fields
+	 * are read from desc.  Hardware guarantees color bit is last
+	 * bit (byte) written.  Adding the rmb() prevents the compiler
+	 * and/or CPU from reordering the reads which would potentially
+	 * result in reading stale values.
+	 */
+
+	rmb();
+
+	*type = type_color & CQ_DESC_TYPE_MASK;
+	*q_number = le16_to_cpu(desc->q_number) & CQ_DESC_Q_NUM_MASK;
+	*completed_index = le16_to_cpu(desc->completed_index) &
+		CQ_DESC_COMP_NDX_MASK;
+}
+
+#endif /* _CQ_DESC_H_ */
diff --git a/drivers/net/enic/cq_enet_desc.h b/drivers/net/enic/cq_enet_desc.h
new file mode 100644
index 0000000..03dce9e
--- /dev/null
+++ b/drivers/net/enic/cq_enet_desc.h
@@ -0,0 +1,169 @@
+/*
+ * Copyright 2008 Cisco Systems, Inc.  All rights reserved.
+ * Copyright 2007 Nuova Systems, Inc.  All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+#ifndef _CQ_ENET_DESC_H_
+#define _CQ_ENET_DESC_H_
+
+#include "cq_desc.h"
+
+/* Ethernet completion queue descriptor: 16B */
+struct cq_enet_wq_desc {
+	__le16 completed_index;
+	__le16 q_number;
+	u8 reserved[11];
+	u8 type_color;
+};
+
+static inline void cq_enet_wq_desc_dec(struct cq_enet_wq_desc *desc,
+	u8 *type, u8 *color, u16 *q_number, u16 *completed_index)
+{
+	cq_desc_dec((struct cq_desc *)desc, type,
+		color, q_number, completed_index);
+}
+
+/* Completion queue descriptor: Ethernet receive queue, 16B */
+struct cq_enet_rq_desc {
+	__le16 completed_index_flags;
+	__le16 q_number_rss_type_flags;
+	__le32 rss_hash;
+	__le16 bytes_written_flags;
+	__le16 vlan;
+	__le16 checksum_fcoe;
+	u8 flags;
+	u8 type_color;
+};
+
+#define CQ_ENET_RQ_DESC_FLAGS_INGRESS_PORT          (0x1 << 12)
+#define CQ_ENET_RQ_DESC_FLAGS_FCOE                  (0x1 << 13)
+#define CQ_ENET_RQ_DESC_FLAGS_EOP                   (0x1 << 14)
+#define CQ_ENET_RQ_DESC_FLAGS_SOP                   (0x1 << 15)
+
+#define CQ_ENET_RQ_DESC_RSS_TYPE_BITS               4
+#define CQ_ENET_RQ_DESC_RSS_TYPE_MASK \
+	((1 << CQ_ENET_RQ_DESC_RSS_TYPE_BITS) - 1)
+#define CQ_ENET_RQ_DESC_RSS_TYPE_NONE               0
+#define CQ_ENET_RQ_DESC_RSS_TYPE_IPv4               1
+#define CQ_ENET_RQ_DESC_RSS_TYPE_TCP_IPv4           2
+#define CQ_ENET_RQ_DESC_RSS_TYPE_IPv6               3
+#define CQ_ENET_RQ_DESC_RSS_TYPE_TCP_IPv6           4
+#define CQ_ENET_RQ_DESC_RSS_TYPE_IPv6_EX            5
+#define CQ_ENET_RQ_DESC_RSS_TYPE_TCP_IPv6_EX        6
+
+#define CQ_ENET_RQ_DESC_FLAGS_CSUM_NOT_CALC         (0x1 << 14)
+
+#define CQ_ENET_RQ_DESC_BYTES_WRITTEN_BITS          14
+#define CQ_ENET_RQ_DESC_BYTES_WRITTEN_MASK \
+	((1 << CQ_ENET_RQ_DESC_BYTES_WRITTEN_BITS) - 1)
+#define CQ_ENET_RQ_DESC_FLAGS_TRUNCATED             (0x1 << 14)
+#define CQ_ENET_RQ_DESC_FLAGS_VLAN_STRIPPED         (0x1 << 15)
+
+#define CQ_ENET_RQ_DESC_FCOE_SOF_BITS               4
+#define CQ_ENET_RQ_DESC_FCOE_SOF_MASK \
+	((1 << CQ_ENET_RQ_DESC_FCOE_SOF_BITS) - 1)
+#define CQ_ENET_RQ_DESC_FCOE_EOF_BITS               8
+#define CQ_ENET_RQ_DESC_FCOE_EOF_MASK \
+	((1 << CQ_ENET_RQ_DESC_FCOE_EOF_BITS) - 1)
+#define CQ_ENET_RQ_DESC_FCOE_EOF_SHIFT              8
+
+#define CQ_ENET_RQ_DESC_FLAGS_TCP_UDP_CSUM_OK       (0x1 << 0)
+#define CQ_ENET_RQ_DESC_FCOE_FC_CRC_OK              (0x1 << 0)
+#define CQ_ENET_RQ_DESC_FLAGS_UDP                   (0x1 << 1)
+#define CQ_ENET_RQ_DESC_FCOE_ENC_ERROR              (0x1 << 1)
+#define CQ_ENET_RQ_DESC_FLAGS_TCP                   (0x1 << 2)
+#define CQ_ENET_RQ_DESC_FLAGS_IPV4_CSUM_OK          (0x1 << 3)
+#define CQ_ENET_RQ_DESC_FLAGS_IPV6                  (0x1 << 4)
+#define CQ_ENET_RQ_DESC_FLAGS_IPV4                  (0x1 << 5)
+#define CQ_ENET_RQ_DESC_FLAGS_IPV4_FRAGMENT         (0x1 << 6)
+#define CQ_ENET_RQ_DESC_FLAGS_FCS_OK                (0x1 << 7)
+
+static inline void cq_enet_rq_desc_dec(struct cq_enet_rq_desc *desc,
+	u8 *type, u8 *color, u16 *q_number, u16 *completed_index,
+	u8 *ingress_port, u8 *fcoe, u8 *eop, u8 *sop, u8 *rss_type,
+	u8 *csum_not_calc, u32 *rss_hash, u16 *bytes_written, u8 *packet_error,
+	u8 *vlan_stripped, u16 *vlan, u16 *checksum, u8 *fcoe_sof,
+	u8 *fcoe_fc_crc_ok, u8 *fcoe_enc_error, u8 *fcoe_eof,
+	u8 *tcp_udp_csum_ok, u8 *udp, u8 *tcp, u8 *ipv4_csum_ok,
+	u8 *ipv6, u8 *ipv4, u8 *ipv4_fragment, u8 *fcs_ok)
+{
+	u16 completed_index_flags = le16_to_cpu(desc->completed_index_flags);
+	u16 q_number_rss_type_flags =
+		le16_to_cpu(desc->q_number_rss_type_flags);
+	u16 bytes_written_flags = le16_to_cpu(desc->bytes_written_flags);
+
+	cq_desc_dec((struct cq_desc *)desc, type,
+		color, q_number, completed_index);
+
+	*ingress_port = (completed_index_flags &
+		CQ_ENET_RQ_DESC_FLAGS_INGRESS_PORT) ? 1 : 0;
+	*fcoe = (completed_index_flags & CQ_ENET_RQ_DESC_FLAGS_FCOE) ?
+		1 : 0;
+	*eop = (completed_index_flags & CQ_ENET_RQ_DESC_FLAGS_EOP) ?
+		1 : 0;
+	*sop = (completed_index_flags & CQ_ENET_RQ_DESC_FLAGS_SOP) ?
+		1 : 0;
+
+	*rss_type = (u8)((q_number_rss_type_flags >> CQ_DESC_Q_NUM_BITS) &
+		CQ_ENET_RQ_DESC_RSS_TYPE_MASK);
+	*csum_not_calc = (q_number_rss_type_flags &
+		CQ_ENET_RQ_DESC_FLAGS_CSUM_NOT_CALC) ? 1 : 0;
+
+	*rss_hash = le32_to_cpu(desc->rss_hash);
+
+	*bytes_written = bytes_written_flags &
+		CQ_ENET_RQ_DESC_BYTES_WRITTEN_MASK;
+	*packet_error = (bytes_written_flags &
+		CQ_ENET_RQ_DESC_FLAGS_TRUNCATED) ? 1 : 0;
+	*vlan_stripped = (bytes_written_flags &
+		CQ_ENET_RQ_DESC_FLAGS_VLAN_STRIPPED) ? 1 : 0;
+
+	*vlan = le16_to_cpu(desc->vlan);
+
+	if (*fcoe) {
+		*fcoe_sof = (u8)(le16_to_cpu(desc->checksum_fcoe) &
+			CQ_ENET_RQ_DESC_FCOE_SOF_MASK);
+		*fcoe_fc_crc_ok = (desc->flags &
+			CQ_ENET_RQ_DESC_FCOE_FC_CRC_OK) ? 1 : 0;
+		*fcoe_enc_error = (desc->flags &
+			CQ_ENET_RQ_DESC_FCOE_ENC_ERROR) ? 1 : 0;
+		*fcoe_eof = (u8)((desc->checksum_fcoe >>
+			CQ_ENET_RQ_DESC_FCOE_EOF_SHIFT) &
+			CQ_ENET_RQ_DESC_FCOE_EOF_MASK);
+		*checksum = 0;
+	} else {
+		*fcoe_sof = 0;
+		*fcoe_fc_crc_ok = 0;
+		*fcoe_enc_error = 0;
+		*fcoe_eof = 0;
+		*checksum = le16_to_cpu(desc->checksum_fcoe);
+	}
+
+	*tcp_udp_csum_ok =
+		(desc->flags & CQ_ENET_RQ_DESC_FLAGS_TCP_UDP_CSUM_OK) ? 1 : 0;
+	*udp = (desc->flags & CQ_ENET_RQ_DESC_FLAGS_UDP) ? 1 : 0;
+	*tcp = (desc->flags & CQ_ENET_RQ_DESC_FLAGS_TCP) ? 1 : 0;
+	*ipv4_csum_ok =
+		(desc->flags & CQ_ENET_RQ_DESC_FLAGS_IPV4_CSUM_OK) ? 1 : 0;
+	*ipv6 = (desc->flags & CQ_ENET_RQ_DESC_FLAGS_IPV6) ? 1 : 0;
+	*ipv4 = (desc->flags & CQ_ENET_RQ_DESC_FLAGS_IPV4) ? 1 : 0;
+	*ipv4_fragment =
+		(desc->flags & CQ_ENET_RQ_DESC_FLAGS_IPV4_FRAGMENT) ? 1 : 0;
+	*fcs_ok = (desc->flags & CQ_ENET_RQ_DESC_FLAGS_FCS_OK) ? 1 : 0;
+}
+
+#endif /* _CQ_ENET_DESC_H_ */
diff --git a/drivers/net/enic/enic.h b/drivers/net/enic/enic.h
new file mode 100644
index 0000000..7f677e8
--- /dev/null
+++ b/drivers/net/enic/enic.h
@@ -0,0 +1,114 @@
+/*
+ * Copyright 2008 Cisco Systems, Inc.  All rights reserved.
+ * Copyright 2007 Nuova Systems, Inc.  All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+#ifndef _ENIC_H_
+#define _ENIC_H_
+
+#include <linux/inet_lro.h>
+
+#include "vnic_enet.h"
+#include "vnic_dev.h"
+#include "vnic_wq.h"
+#include "vnic_rq.h"
+#include "vnic_cq.h"
+#include "vnic_intr.h"
+#include "vnic_stats.h"
+#include "vnic_rss.h"
+
+#define DRV_NAME		"enic"
+#define DRV_DESCRIPTION		"Cisco 10G Ethernet Driver"
+#define DRV_VERSION		"0.0.1-18163.472-k1"
+#define DRV_COPYRIGHT		"Copyright 2008 Cisco Systems, Inc"
+#define PFX			DRV_NAME ": "
+
+#define ENIC_LRO_MAX_DESC	8
+#define ENIC_LRO_MAX_AGGR	64
+
+enum enic_cq_index {
+	ENIC_CQ_RQ,
+	ENIC_CQ_WQ,
+	ENIC_CQ_MAX,
+};
+
+enum enic_intx_intr_index {
+	ENIC_INTX_WQ_RQ,
+	ENIC_INTX_ERR,
+	ENIC_INTX_NOTIFY,
+	ENIC_INTX_MAX,
+};
+
+enum enic_msix_intr_index {
+	ENIC_MSIX_RQ,
+	ENIC_MSIX_WQ,
+	ENIC_MSIX_ERR,
+	ENIC_MSIX_NOTIFY,
+	ENIC_MSIX_MAX,
+};
+
+struct enic_msix_entry {
+	int requested;
+	char devname[IFNAMSIZ];
+	irqreturn_t (*isr)(int, void *);
+	void *devid;
+};
+
+/* Per-instance private data structure */
+struct enic {
+	struct net_device *netdev;
+	struct pci_dev *pdev;
+	struct vnic_enet_config config;
+	struct vnic_dev_bar bar0;
+	struct vnic_dev *vdev;
+	struct timer_list notify_timer;
+	struct work_struct reset;
+	struct msix_entry msix_entry[ENIC_MSIX_MAX];
+	struct enic_msix_entry msix[ENIC_MSIX_MAX];
+	u32 msg_enable;
+	spinlock_t devcmd_lock;
+	u8 mac_addr[ETH_ALEN];
+	u8 mc_addr[ENIC_MULTICAST_PERFECT_FILTERS][ETH_ALEN];
+	unsigned int mc_count;
+	int csum_rx_enabled;
+	u32 port_mtu;
+
+	/* work queue cache line section */
+	____cacheline_aligned struct vnic_wq wq[1];
+	spinlock_t wq_lock[1];
+	unsigned int wq_count;
+	struct vlan_group *vlan_group;
+
+	/* receive queue cache line section */
+	____cacheline_aligned struct vnic_rq rq[1];
+	unsigned int rq_count;
+	int (*rq_alloc_buf)(struct vnic_rq *rq);
+	struct napi_struct napi;
+	struct net_lro_mgr lro_mgr;
+	struct net_lro_desc lro_desc[ENIC_LRO_MAX_DESC];
+
+	/* interrupt resource cache line section */
+	____cacheline_aligned struct vnic_intr intr[ENIC_MSIX_MAX];
+	unsigned int intr_count;
+	u32 __iomem *legacy_pba;		/* memory-mapped */
+
+	/* completion queue cache line section */
+	____cacheline_aligned struct vnic_cq cq[ENIC_CQ_MAX];
+	unsigned int cq_count;
+};
+
+#endif /* _ENIC_H_ */
diff --git a/drivers/net/enic/enic_main.c b/drivers/net/enic/enic_main.c
new file mode 100644
index 0000000..180e968
--- /dev/null
+++ b/drivers/net/enic/enic_main.c
@@ -0,0 +1,1935 @@
+/*
+ * Copyright 2008 Cisco Systems, Inc.  All rights reserved.
+ * Copyright 2007 Nuova Systems, Inc.  All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/workqueue.h>
+#include <linux/pci.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/if_ether.h>
+#include <linux/if_vlan.h>
+#include <linux/ethtool.h>
+#include <linux/in.h>
+#include <linux/ip.h>
+#include <linux/ipv6.h>
+#include <linux/tcp.h>
+#include <net/ip6_checksum.h>
+
+#include "cq_enet_desc.h"
+#include "vnic_dev.h"
+#include "vnic_intr.h"
+#include "vnic_stats.h"
+#include "enic_res.h"
+#include "enic.h"
+
+#define ENIC_NOTIFY_TIMER_PERIOD	(2 * HZ)
+
+/* Supported devices */
+static struct pci_device_id enic_id_table[] = {
+	{ PCI_VDEVICE(CISCO, 0x0043) },
+	{ 0, }	/* end of table */
+};
+
+MODULE_DESCRIPTION(DRV_DESCRIPTION);
+MODULE_AUTHOR("Scott Feldman <scofeldm@cisco.com>");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
+MODULE_DEVICE_TABLE(pci, enic_id_table);
+
+struct enic_stat {
+	char name[ETH_GSTRING_LEN];
+	unsigned int offset;
+};
+
+#define ENIC_TX_STAT(stat)	\
+	{ .name = #stat, .offset = offsetof(struct vnic_tx_stats, stat) / 8 }
+#define ENIC_RX_STAT(stat)	\
+	{ .name = #stat, .offset = offsetof(struct vnic_rx_stats, stat) / 8 }
+
+static const struct enic_stat enic_tx_stats[] = {
+	ENIC_TX_STAT(tx_frames_ok),
+	ENIC_TX_STAT(tx_unicast_frames_ok),
+	ENIC_TX_STAT(tx_multicast_frames_ok),
+	ENIC_TX_STAT(tx_broadcast_frames_ok),
+	ENIC_TX_STAT(tx_bytes_ok),
+	ENIC_TX_STAT(tx_unicast_bytes_ok),
+	ENIC_TX_STAT(tx_multicast_bytes_ok),
+	ENIC_TX_STAT(tx_broadcast_bytes_ok),
+	ENIC_TX_STAT(tx_drops),
+	ENIC_TX_STAT(tx_errors),
+	ENIC_TX_STAT(tx_tso),
+};
+
+static const struct enic_stat enic_rx_stats[] = {
+	ENIC_RX_STAT(rx_frames_ok),
+	ENIC_RX_STAT(rx_frames_total),
+	ENIC_RX_STAT(rx_unicast_frames_ok),
+	ENIC_RX_STAT(rx_multicast_frames_ok),
+	ENIC_RX_STAT(rx_broadcast_frames_ok),
+	ENIC_RX_STAT(rx_bytes_ok),
+	ENIC_RX_STAT(rx_unicast_bytes_ok),
+	ENIC_RX_STAT(rx_multicast_bytes_ok),
+	ENIC_RX_STAT(rx_broadcast_bytes_ok),
+	ENIC_RX_STAT(rx_drop),
+	ENIC_RX_STAT(rx_no_bufs),
+	ENIC_RX_STAT(rx_errors),
+	ENIC_RX_STAT(rx_rss),
+	ENIC_RX_STAT(rx_crc_errors),
+	ENIC_RX_STAT(rx_frames_64),
+	ENIC_RX_STAT(rx_frames_127),
+	ENIC_RX_STAT(rx_frames_255),
+	ENIC_RX_STAT(rx_frames_511),
+	ENIC_RX_STAT(rx_frames_1023),
+	ENIC_RX_STAT(rx_frames_1518),
+	ENIC_RX_STAT(rx_frames_to_max),
+};
+
+static const unsigned int enic_n_tx_stats = ARRAY_SIZE(enic_tx_stats);
+static const unsigned int enic_n_rx_stats = ARRAY_SIZE(enic_rx_stats);
+
+static int enic_get_settings(struct net_device *netdev,
+	struct ethtool_cmd *ecmd)
+{
+	struct enic *enic = netdev_priv(netdev);
+
+	ecmd->supported = (SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE);
+	ecmd->advertising = (ADVERTISED_10000baseT_Full | ADVERTISED_FIBRE);
+	ecmd->port = PORT_FIBRE;
+	ecmd->transceiver = XCVR_EXTERNAL;
+
+	if (netif_carrier_ok(netdev)) {
+		ecmd->speed = vnic_dev_port_speed(enic->vdev);
+		ecmd->duplex = DUPLEX_FULL;
+	} else {
+		ecmd->speed = -1;
+		ecmd->duplex = -1;
+	}
+
+	ecmd->autoneg = AUTONEG_DISABLE;
+
+	return 0;
+}
+
+static void enic_get_drvinfo(struct net_device *netdev,
+	struct ethtool_drvinfo *drvinfo)
+{
+	struct enic *enic = netdev_priv(netdev);
+	struct vnic_devcmd_fw_info *fw_info;
+
+	spin_lock(&enic->devcmd_lock);
+	vnic_dev_fw_info(enic->vdev, &fw_info);
+	spin_unlock(&enic->devcmd_lock);
+
+	strncpy(drvinfo->driver, DRV_NAME, sizeof(drvinfo->driver));
+	strncpy(drvinfo->version, DRV_VERSION, sizeof(drvinfo->version));
+	strncpy(drvinfo->fw_version, fw_info->fw_version,
+		sizeof(drvinfo->fw_version));
+	strncpy(drvinfo->bus_info, pci_name(enic->pdev),
+		sizeof(drvinfo->bus_info));
+}
+
+static void enic_get_strings(struct net_device *netdev, u32 stringset, u8 *data)
+{
+	unsigned int i;
+
+	switch (stringset) {
+	case ETH_SS_STATS:
+		for (i = 0; i < enic_n_tx_stats; i++) {
+			memcpy(data, enic_tx_stats[i].name, ETH_GSTRING_LEN);
+			data += ETH_GSTRING_LEN;
+		}
+		for (i = 0; i < enic_n_rx_stats; i++) {
+			memcpy(data, enic_rx_stats[i].name, ETH_GSTRING_LEN);
+			data += ETH_GSTRING_LEN;
+		}
+		break;
+	}
+}
+
+static int enic_get_sset_count(struct net_device *netdev, int sset)
+{
+	switch (sset) {
+	case ETH_SS_STATS:
+		return enic_n_tx_stats + enic_n_rx_stats;
+	default:
+		return -EOPNOTSUPP;
+	}
+}
+
+static void enic_get_ethtool_stats(struct net_device *netdev,
+	struct ethtool_stats *stats, u64 *data)
+{
+	struct enic *enic = netdev_priv(netdev);
+	struct vnic_stats *vstats;
+	unsigned int i;
+
+	spin_lock(&enic->devcmd_lock);
+	vnic_dev_stats_dump(enic->vdev, &vstats);
+	spin_unlock(&enic->devcmd_lock);
+
+	for (i = 0; i < enic_n_tx_stats; i++)
+		*(data++) = ((u64 *)&vstats->tx)[enic_tx_stats[i].offset];
+	for (i = 0; i < enic_n_rx_stats; i++)
+		*(data++) = ((u64 *)&vstats->rx)[enic_rx_stats[i].offset];
+}
+
+static u32 enic_get_rx_csum(struct net_device *netdev)
+{
+	struct enic *enic = netdev_priv(netdev);
+	return enic->csum_rx_enabled;
+}
+
+static int enic_set_rx_csum(struct net_device *netdev, u32 data)
+{
+	struct enic *enic = netdev_priv(netdev);
+
+	if (data && !ENIC_SETTING(enic, RXCSUM))
+		return -EINVAL;
+
+	enic->csum_rx_enabled = !!data;
+
+	return 0;
+}
+
+static int enic_set_tx_csum(struct net_device *netdev, u32 data)
+{
+	struct enic *enic = netdev_priv(netdev);
+
+	if (data && !ENIC_SETTING(enic, TXCSUM))
+		return -EINVAL;
+
+	if (data)
+		netdev->features |= NETIF_F_HW_CSUM;
+	else
+		netdev->features &= ~NETIF_F_HW_CSUM;
+
+	return 0;
+}
+
+static int enic_set_tso(struct net_device *netdev, u32 data)
+{
+	struct enic *enic = netdev_priv(netdev);
+
+	if (data && !ENIC_SETTING(enic, TSO))
+		return -EINVAL;
+
+	if (data)
+		netdev->features |=
+			NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_TSO_ECN;
+	else
+		netdev->features &=
+			~(NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_TSO_ECN);
+
+	return 0;
+}
+
+static u32 enic_get_msglevel(struct net_device *netdev)
+{
+	struct enic *enic = netdev_priv(netdev);
+	return enic->msg_enable;
+}
+
+static void enic_set_msglevel(struct net_device *netdev, u32 value)
+{
+	struct enic *enic = netdev_priv(netdev);
+	enic->msg_enable = value;
+}
+
+static struct ethtool_ops enic_ethtool_ops = {
+	.get_settings = enic_get_settings,
+	.get_drvinfo = enic_get_drvinfo,
+	.get_msglevel = enic_get_msglevel,
+	.set_msglevel = enic_set_msglevel,
+	.get_link = ethtool_op_get_link,
+	.get_strings = enic_get_strings,
+	.get_sset_count = enic_get_sset_count,
+	.get_ethtool_stats = enic_get_ethtool_stats,
+	.get_rx_csum = enic_get_rx_csum,
+	.set_rx_csum = enic_set_rx_csum,
+	.get_tx_csum = ethtool_op_get_tx_csum,
+	.set_tx_csum = enic_set_tx_csum,
+	.get_sg = ethtool_op_get_sg,
+	.set_sg = ethtool_op_set_sg,
+	.get_tso = ethtool_op_get_tso,
+	.set_tso = enic_set_tso,
+};
+
+static void enic_free_wq_buf(struct vnic_wq *wq, struct vnic_wq_buf *buf)
+{
+	struct enic *enic = vnic_dev_priv(wq->vdev);
+
+	if (buf->sop)
+		pci_unmap_single(enic->pdev, buf->dma_addr,
+			buf->len, PCI_DMA_TODEVICE);
+	else
+		pci_unmap_page(enic->pdev, buf->dma_addr,
+			buf->len, PCI_DMA_TODEVICE);
+
+	if (buf->os_buf)
+		dev_kfree_skb_any(buf->os_buf);
+}
+
+static void enic_wq_free_buf(struct vnic_wq *wq,
+	struct cq_desc *cq_desc, struct vnic_wq_buf *buf, void *opaque)
+{
+	enic_free_wq_buf(wq, buf);
+}
+
+static int enic_wq_service(struct vnic_dev *vdev, struct cq_desc *cq_desc,
+	u8 type, u16 q_number, u16 completed_index, void *opaque)
+{
+	struct enic *enic = vnic_dev_priv(vdev);
+
+	spin_lock(&enic->wq_lock[q_number]);
+
+	vnic_wq_service(&enic->wq[q_number], cq_desc,
+		completed_index, enic_wq_free_buf,
+		opaque);
+
+	if (netif_queue_stopped(enic->netdev) &&
+	    vnic_wq_desc_avail(&enic->wq[q_number]) >= MAX_SKB_FRAGS + 1)
+		netif_wake_queue(enic->netdev);
+
+	spin_unlock(&enic->wq_lock[q_number]);
+
+	return 0;
+}
+
+static void enic_log_q_error(struct enic *enic)
+{
+	unsigned int i;
+	u32 error_status;
+
+	for (i = 0; i < enic->wq_count; i++) {
+		error_status = vnic_wq_error_status(&enic->wq[i]);
+		if (error_status)
+			printk(KERN_ERR PFX "%s: WQ[%d] error_status %d\n",
+				enic->netdev->name, i, error_status);
+	}
+
+	for (i = 0; i < enic->rq_count; i++) {
+		error_status = vnic_rq_error_status(&enic->rq[i]);
+		if (error_status)
+			printk(KERN_ERR PFX "%s: RQ[%d] error_status %d\n",
+				enic->netdev->name, i, error_status);
+	}
+}
+
+static void enic_link_check(struct enic *enic)
+{
+	int link_status = vnic_dev_link_status(enic->vdev);
+	int carrier_ok = netif_carrier_ok(enic->netdev);
+
+	if (link_status && !carrier_ok) {
+		printk(KERN_INFO PFX "%s: Link UP\n", enic->netdev->name);
+		netif_carrier_on(enic->netdev);
+	} else if (!link_status && carrier_ok) {
+		printk(KERN_INFO PFX "%s: Link DOWN\n", enic->netdev->name);
+		netif_carrier_off(enic->netdev);
+	}
+}
+
+static void enic_mtu_check(struct enic *enic)
+{
+	u32 mtu = vnic_dev_mtu(enic->vdev);
+
+	if (mtu != enic->port_mtu) {
+		if (mtu < enic->netdev->mtu)
+			printk(KERN_WARNING PFX
+				"%s: interface MTU (%d) set higher "
+				"than switch port MTU (%d)\n",
+				enic->netdev->name, enic->netdev->mtu, mtu);
+		enic->port_mtu = mtu;
+	}
+}
+
+static void enic_msglvl_check(struct enic *enic)
+{
+	u32 msg_enable = vnic_dev_msg_lvl(enic->vdev);
+
+	if (msg_enable != enic->msg_enable) {
+		printk(KERN_INFO PFX "%s: msg lvl changed from 0x%x to 0x%x\n",
+			enic->netdev->name, enic->msg_enable, msg_enable);
+		enic->msg_enable = msg_enable;
+	}
+}
+
+static void enic_notify_check(struct enic *enic)
+{
+	enic_msglvl_check(enic);
+	enic_mtu_check(enic);
+	enic_link_check(enic);
+}
+
+#define ENIC_TEST_INTR(pba, i) (pba & (1 << i))
+
+static irqreturn_t enic_isr_legacy(int irq, void *data)
+{
+	struct net_device *netdev = data;
+	struct enic *enic = netdev_priv(netdev);
+	u32 pba;
+
+	vnic_intr_mask(&enic->intr[ENIC_INTX_WQ_RQ]);
+
+	pba = vnic_intr_legacy_pba(enic->legacy_pba);
+	if (!pba) {
+		vnic_intr_unmask(&enic->intr[ENIC_INTX_WQ_RQ]);
+		return IRQ_NONE;	/* not our interrupt */
+	}
+
+	if (ENIC_TEST_INTR(pba, ENIC_INTX_NOTIFY))
+		enic_notify_check(enic);
+
+	if (ENIC_TEST_INTR(pba, ENIC_INTX_ERR)) {
+		enic_log_q_error(enic);
+		/* schedule recovery from WQ/RQ error */
+		schedule_work(&enic->reset);
+		return IRQ_HANDLED;
+	}
+
+	if (ENIC_TEST_INTR(pba, ENIC_INTX_WQ_RQ)) {
+		if (netif_rx_schedule_prep(netdev, &enic->napi))
+			__netif_rx_schedule(netdev, &enic->napi);
+	} else {
+		vnic_intr_unmask(&enic->intr[ENIC_INTX_WQ_RQ]);
+	}
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t enic_isr_msi(int irq, void *data)
+{
+	struct enic *enic = data;
+
+	/* With MSI, there is no sharing of interrupts, so this is
+	 * our interrupt and there is no need to ack it.  The device
+	 * is not providing per-vector masking, so the OS will not
+	 * write to PCI config space to mask/unmask the interrupt.
+	 * We're using mask_on_assertion for MSI, so the device
+	 * automatically masks the interrupt when the interrupt is
+	 * generated.  Later, when exiting polling, the interrupt
+	 * will be unmasked (see enic_poll).
+	 *
+	 * Also, the device uses the same PCIe Traffic Class (TC)
+	 * for Memory Write data and MSI, so there are no ordering
+	 * issues; the MSI will always arrive at the Root Complex
+	 * _after_ corresponding Memory Writes (i.e. descriptor
+	 * writes).
+	 */
+
+	netif_rx_schedule(enic->netdev, &enic->napi);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t enic_isr_msix_rq(int irq, void *data)
+{
+	struct enic *enic = data;
+
+	/* schedule NAPI polling for RQ cleanup */
+	netif_rx_schedule(enic->netdev, &enic->napi);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t enic_isr_msix_wq(int irq, void *data)
+{
+	struct enic *enic = data;
+	unsigned int wq_work_to_do = -1; /* no limit */
+	unsigned int wq_work_done;
+
+	wq_work_done = vnic_cq_service(&enic->cq[ENIC_CQ_WQ],
+		wq_work_to_do, enic_wq_service, NULL);
+
+	vnic_intr_return_credits(&enic->intr[ENIC_MSIX_WQ],
+		wq_work_done,
+		1 /* unmask intr */,
+		1 /* reset intr timer */);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t enic_isr_msix_err(int irq, void *data)
+{
+	struct enic *enic = data;
+
+	enic_log_q_error(enic);
+
+	/* schedule recovery from WQ/RQ error */
+	schedule_work(&enic->reset);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t enic_isr_msix_notify(int irq, void *data)
+{
+	struct enic *enic = data;
+
+	enic_notify_check(enic);
+	vnic_intr_unmask(&enic->intr[ENIC_MSIX_NOTIFY]);
+
+	return IRQ_HANDLED;
+}
+
+static inline void enic_queue_wq_skb_cont(struct enic *enic,
+	struct vnic_wq *wq, struct sk_buff *skb,
+	unsigned int len_left)
+{
+	skb_frag_t *frag;
+
+	/* Queue additional data fragments */
+	for (frag = skb_shinfo(skb)->frags; len_left; frag++) {
+		len_left -= frag->size;
+		enic_queue_wq_desc_cont(wq, skb,
+			pci_map_page(enic->pdev, frag->page,
+				frag->page_offset, frag->size,
+				PCI_DMA_TODEVICE),
+			frag->size,
+			(len_left == 0));	/* EOP? */
+	}
+}
+
+static inline void enic_queue_wq_skb_vlan(struct enic *enic,
+	struct vnic_wq *wq, struct sk_buff *skb,
+	int vlan_tag_insert, unsigned int vlan_tag)
+{
+	unsigned int head_len = skb_headlen(skb);
+	unsigned int len_left = skb->len - head_len;
+	int eop = (len_left == 0);
+
+	/* Queue the main skb fragment */
+	enic_queue_wq_desc(wq, skb,
+		pci_map_single(enic->pdev, skb->data,
+			head_len, PCI_DMA_TODEVICE),
+		head_len,
+		vlan_tag_insert, vlan_tag,
+		eop);
+
+	if (!eop)
+		enic_queue_wq_skb_cont(enic, wq, skb, len_left);
+}
+
+static inline void enic_queue_wq_skb_csum_l4(struct enic *enic,
+	struct vnic_wq *wq, struct sk_buff *skb,
+	int vlan_tag_insert, unsigned int vlan_tag)
+{
+	unsigned int head_len = skb_headlen(skb);
+	unsigned int len_left = skb->len - head_len;
+	unsigned int hdr_len = skb_transport_offset(skb);
+	unsigned int csum_offset = hdr_len + skb->csum_offset;
+	int eop = (len_left == 0);
+
+	/* Queue the main skb fragment */
+	enic_queue_wq_desc_csum_l4(wq, skb,
+		pci_map_single(enic->pdev, skb->data,
+			head_len, PCI_DMA_TODEVICE),
+		head_len,
+		csum_offset,
+		hdr_len,
+		vlan_tag_insert, vlan_tag,
+		eop);
+
+	if (!eop)
+		enic_queue_wq_skb_cont(enic, wq, skb, len_left);
+}
+
+static inline void enic_queue_wq_skb_tso(struct enic *enic,
+	struct vnic_wq *wq, struct sk_buff *skb, unsigned int mss,
+	int vlan_tag_insert, unsigned int vlan_tag)
+{
+	unsigned int head_len = skb_headlen(skb);
+	unsigned int len_left = skb->len - head_len;
+	unsigned int hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb);
+	int eop = (len_left == 0);
+
+	/* Preload TCP csum field with IP pseudo hdr calculated
+	 * with IP length set to zero.  HW will later add in length
+	 * to each TCP segment resulting from the TSO.
+	 */
+
+	if (skb->protocol == __constant_htons(ETH_P_IP)) {
+		ip_hdr(skb)->check = 0;
+		tcp_hdr(skb)->check = ~csum_tcpudp_magic(ip_hdr(skb)->saddr,
+			ip_hdr(skb)->daddr, 0, IPPROTO_TCP, 0);
+	} else if (skb->protocol == __constant_htons(ETH_P_IPV6)) {
+		tcp_hdr(skb)->check = ~csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
+			&ipv6_hdr(skb)->daddr, 0, IPPROTO_TCP, 0);
+	}
+
+	/* Queue the main skb fragment */
+	enic_queue_wq_desc_tso(wq, skb,
+		pci_map_single(enic->pdev, skb->data,
+			head_len, PCI_DMA_TODEVICE),
+		head_len,
+		mss, hdr_len,
+		vlan_tag_insert, vlan_tag,
+		eop);
+
+	if (!eop)
+		enic_queue_wq_skb_cont(enic, wq, skb, len_left);
+}
+
+static inline void enic_queue_wq_skb(struct enic *enic,
+	struct vnic_wq *wq, struct sk_buff *skb)
+{
+	unsigned int mss = skb_shinfo(skb)->gso_size;
+	unsigned int vlan_tag = 0;
+	int vlan_tag_insert = 0;
+
+	if (enic->vlan_group && vlan_tx_tag_present(skb)) {
+		/* VLAN tag from trunking driver */
+		vlan_tag_insert = 1;
+		vlan_tag = vlan_tx_tag_get(skb);
+	}
+
+	if (mss)
+		enic_queue_wq_skb_tso(enic, wq, skb, mss,
+			vlan_tag_insert, vlan_tag);
+	else if	(skb->ip_summed == CHECKSUM_PARTIAL)
+		enic_queue_wq_skb_csum_l4(enic, wq, skb,
+			vlan_tag_insert, vlan_tag);
+	else
+		enic_queue_wq_skb_vlan(enic, wq, skb,
+			vlan_tag_insert, vlan_tag);
+}
+
+/* netif_tx_lock held, process context with BHs disabled */
+static int enic_hard_start_xmit(struct sk_buff *skb, struct net_device *netdev)
+{
+	struct enic *enic = netdev_priv(netdev);
+	struct vnic_wq *wq = &enic->wq[0];
+	unsigned long flags;
+
+	if (skb->len <= 0) {
+		dev_kfree_skb(skb);
+		return NETDEV_TX_OK;
+	}
+
+	/* Non-TSO sends must fit within ENIC_NON_TSO_MAX_DESC descs,
+	 * which is very likely.  In the off chance it's going to take
+	 * more than * ENIC_NON_TSO_MAX_DESC, linearize the skb.
+	 */
+
+	if (skb_shinfo(skb)->gso_size == 0 &&
+	    skb_shinfo(skb)->nr_frags + 1 > ENIC_NON_TSO_MAX_DESC &&
+	    skb_linearize(skb)) {
+		dev_kfree_skb(skb);
+		return NETDEV_TX_OK;
+	}
+
+	spin_lock_irqsave(&enic->wq_lock[0], flags);
+
+	if (vnic_wq_desc_avail(wq) < skb_shinfo(skb)->nr_frags + 1) {
+		netif_stop_queue(netdev);
+		/* This is a hard error, log it */
+		printk(KERN_ERR PFX "%s: BUG! Tx ring full when "
+			"queue awake!\n", netdev->name);
+		spin_unlock_irqrestore(&enic->wq_lock[0], flags);
+		return NETDEV_TX_BUSY;
+	}
+
+	enic_queue_wq_skb(enic, wq, skb);
+
+	if (vnic_wq_desc_avail(wq) < MAX_SKB_FRAGS + 1)
+		netif_stop_queue(netdev);
+
+	netdev->trans_start = jiffies;
+
+	spin_unlock_irqrestore(&enic->wq_lock[0], flags);
+
+	return NETDEV_TX_OK;
+}
+
+/* dev_base_lock rwlock held, nominally process context */
+static struct net_device_stats *enic_get_stats(struct net_device *netdev)
+{
+	struct enic *enic = netdev_priv(netdev);
+	struct net_device_stats *net_stats = &netdev->stats;
+	struct vnic_stats *stats;
+
+	spin_lock(&enic->devcmd_lock);
+	vnic_dev_stats_dump(enic->vdev, &stats);
+	spin_unlock(&enic->devcmd_lock);
+
+	net_stats->tx_packets = stats->tx.tx_frames_ok;
+	net_stats->tx_bytes = stats->tx.tx_bytes_ok;
+	net_stats->tx_errors = stats->tx.tx_errors;
+	net_stats->tx_dropped = stats->tx.tx_drops;
+
+	net_stats->rx_packets = stats->rx.rx_frames_ok;
+	net_stats->rx_bytes = stats->rx.rx_bytes_ok;
+	net_stats->rx_errors = stats->rx.rx_errors;
+	net_stats->multicast = stats->rx.rx_multicast_frames_ok;
+	net_stats->rx_crc_errors = stats->rx.rx_crc_errors;
+	net_stats->rx_dropped = stats->rx.rx_no_bufs;
+
+	return net_stats;
+}
+
+static void enic_reset_mcaddrs(struct enic *enic)
+{
+	enic->mc_count = 0;
+}
+
+static int enic_set_mac_addr(struct net_device *netdev, char *addr)
+{
+	if (!is_valid_ether_addr(addr))
+		return -EADDRNOTAVAIL;
+
+	memcpy(netdev->dev_addr, addr, netdev->addr_len);
+
+	return 0;
+}
+
+/* netif_tx_lock held, BHs disabled */
+static void enic_set_multicast_list(struct net_device *netdev)
+{
+	struct enic *enic = netdev_priv(netdev);
+	struct dev_mc_list *list = netdev->mc_list;
+	int directed = 1;
+	int multicast = (netdev->flags & IFF_MULTICAST) ? 1 : 0;
+	int broadcast = (netdev->flags & IFF_BROADCAST) ? 1 : 0;
+	int promisc = (netdev->flags & IFF_PROMISC) ? 1 : 0;
+	int allmulti = (netdev->flags & IFF_ALLMULTI) ||
+	    (netdev->mc_count > ENIC_MULTICAST_PERFECT_FILTERS);
+	u8 mc_addr[ENIC_MULTICAST_PERFECT_FILTERS][ETH_ALEN];
+	unsigned int mc_count = netdev->mc_count;
+	unsigned int i, j;
+
+	if (mc_count > ENIC_MULTICAST_PERFECT_FILTERS)
+		mc_count = ENIC_MULTICAST_PERFECT_FILTERS;
+
+	spin_lock(&enic->devcmd_lock);
+
+	vnic_dev_packet_filter(enic->vdev, directed,
+		multicast, broadcast, promisc, allmulti);
+
+	/* Is there an easier way?  Trying to minimize to
+	 * calls to add/del multicast addrs.  We keep the
+	 * addrs from the last call in enic->mc_addr and
+	 * look for changes to add/del.
+	 */
+
+	for (i = 0; list && i < mc_count; i++) {
+		memcpy(mc_addr[i], list->dmi_addr, ETH_ALEN);
+		list = list->next;
+	}
+
+	for (i = 0; i < enic->mc_count; i++) {
+		for (j = 0; j < mc_count; j++)
+			if (compare_ether_addr(enic->mc_addr[i],
+				mc_addr[j]) == 0)
+				break;
+		if (j == mc_count)
+			enic_del_multicast_addr(enic, enic->mc_addr[i]);
+	}
+
+	for (i = 0; i < mc_count; i++) {
+		for (j = 0; j < enic->mc_count; j++)
+			if (compare_ether_addr(mc_addr[i],
+				enic->mc_addr[j]) == 0)
+				break;
+		if (j == enic->mc_count)
+			enic_add_multicast_addr(enic, mc_addr[i]);
+	}
+
+	/* Save the list to compare against next time
+	 */
+
+	for (i = 0; i < mc_count; i++)
+		memcpy(enic->mc_addr[i], mc_addr[i], ETH_ALEN);
+
+	enic->mc_count = mc_count;
+
+	spin_unlock(&enic->devcmd_lock);
+}
+
+/* rtnl lock is held */
+static void enic_vlan_rx_register(struct net_device *netdev,
+	struct vlan_group *vlan_group)
+{
+	struct enic *enic = netdev_priv(netdev);
+	enic->vlan_group = vlan_group;
+}
+
+/* rtnl lock is held */
+static void enic_vlan_rx_add_vid(struct net_device *netdev, u16 vid)
+{
+	struct enic *enic = netdev_priv(netdev);
+
+	spin_lock(&enic->devcmd_lock);
+	enic_add_vlan(enic, vid);
+	spin_unlock(&enic->devcmd_lock);
+}
+
+/* rtnl lock is held */
+static void enic_vlan_rx_kill_vid(struct net_device *netdev, u16 vid)
+{
+	struct enic *enic = netdev_priv(netdev);
+
+	spin_lock(&enic->devcmd_lock);
+	enic_del_vlan(enic, vid);
+	spin_unlock(&enic->devcmd_lock);
+}
+
+/* netif_tx_lock held, BHs disabled */
+static void enic_tx_timeout(struct net_device *netdev)
+{
+	struct enic *enic = netdev_priv(netdev);
+	schedule_work(&enic->reset);
+}
+
+static void enic_free_rq_buf(struct vnic_rq *rq, struct vnic_rq_buf *buf)
+{
+	struct enic *enic = vnic_dev_priv(rq->vdev);
+
+	if (!buf->os_buf)
+		return;
+
+	pci_unmap_single(enic->pdev, buf->dma_addr,
+		buf->len, PCI_DMA_FROMDEVICE);
+	dev_kfree_skb_any(buf->os_buf);
+}
+
+static inline struct sk_buff *enic_rq_alloc_skb(unsigned int size)
+{
+	struct sk_buff *skb;
+
+	skb = dev_alloc_skb(size + NET_IP_ALIGN);
+
+	if (skb)
+		skb_reserve(skb, NET_IP_ALIGN);
+
+	return skb;
+}
+
+static int enic_rq_alloc_buf(struct vnic_rq *rq)
+{
+	struct enic *enic = vnic_dev_priv(rq->vdev);
+	struct sk_buff *skb;
+	unsigned int len = enic->netdev->mtu + ETH_HLEN;
+	unsigned int os_buf_index = 0;
+	dma_addr_t dma_addr;
+
+	skb = enic_rq_alloc_skb(len);
+	if (!skb)
+		return -ENOMEM;
+
+	dma_addr = pci_map_single(enic->pdev, skb->data,
+		len, PCI_DMA_FROMDEVICE);
+
+	enic_queue_rq_desc(rq, skb, os_buf_index,
+		dma_addr, len);
+
+	return 0;
+}
+
+static int enic_get_skb_header(struct sk_buff *skb, void **iphdr,
+	void **tcph, u64 *hdr_flags, void *priv)
+{
+	struct cq_enet_rq_desc *cq_desc = priv;
+	unsigned int ip_len;
+	struct iphdr *iph;
+
+	u8 type, color, eop, sop, ingress_port, vlan_stripped;
+	u8 fcoe, fcoe_sof, fcoe_fc_crc_ok, fcoe_enc_error, fcoe_eof;
+	u8 tcp_udp_csum_ok, udp, tcp, ipv4_csum_ok;
+	u8 ipv6, ipv4, ipv4_fragment, fcs_ok, rss_type, csum_not_calc;
+	u8 packet_error;
+	u16 q_number, completed_index, bytes_written, vlan, checksum;
+	u32 rss_hash;
+
+	cq_enet_rq_desc_dec(cq_desc,
+		&type, &color, &q_number, &completed_index,
+		&ingress_port, &fcoe, &eop, &sop, &rss_type,
+		&csum_not_calc, &rss_hash, &bytes_written,
+		&packet_error, &vlan_stripped, &vlan, &checksum,
+		&fcoe_sof, &fcoe_fc_crc_ok, &fcoe_enc_error,
+		&fcoe_eof, &tcp_udp_csum_ok, &udp, &tcp,
+		&ipv4_csum_ok, &ipv6, &ipv4, &ipv4_fragment,
+		&fcs_ok);
+
+	if (!(ipv4 && tcp && !ipv4_fragment))
+		return -1;
+
+	skb_reset_network_header(skb);
+	iph = ip_hdr(skb);
+
+	ip_len = ip_hdrlen(skb);
+	skb_set_transport_header(skb, ip_len);
+
+	/* check if ip header and tcp header are complete */
+	if (ntohs(iph->tot_len) < ip_len + tcp_hdrlen(skb))
+		return -1;
+
+	*hdr_flags = LRO_IPV4 | LRO_TCP;
+	*tcph = tcp_hdr(skb);
+	*iphdr = iph;
+
+	return 0;
+}
+
+static void enic_rq_indicate_buf(struct vnic_rq *rq,
+	struct cq_desc *cq_desc, struct vnic_rq_buf *buf,
+	int skipped, void *opaque)
+{
+	struct enic *enic = vnic_dev_priv(rq->vdev);
+	struct sk_buff *skb;
+
+	u8 type, color, eop, sop, ingress_port, vlan_stripped;
+	u8 fcoe, fcoe_sof, fcoe_fc_crc_ok, fcoe_enc_error, fcoe_eof;
+	u8 tcp_udp_csum_ok, udp, tcp, ipv4_csum_ok;
+	u8 ipv6, ipv4, ipv4_fragment, fcs_ok, rss_type, csum_not_calc;
+	u8 packet_error;
+	u16 q_number, completed_index, bytes_written, vlan, checksum;
+	u32 rss_hash;
+
+	if (skipped)
+		return;
+
+	skb = buf->os_buf;
+	prefetch(skb->data - NET_IP_ALIGN);
+	pci_unmap_single(enic->pdev, buf->dma_addr,
+		buf->len, PCI_DMA_FROMDEVICE);
+
+	cq_enet_rq_desc_dec((struct cq_enet_rq_desc *)cq_desc,
+		&type, &color, &q_number, &completed_index,
+		&ingress_port, &fcoe, &eop, &sop, &rss_type,
+		&csum_not_calc, &rss_hash, &bytes_written,
+		&packet_error, &vlan_stripped, &vlan, &checksum,
+		&fcoe_sof, &fcoe_fc_crc_ok, &fcoe_enc_error,
+		&fcoe_eof, &tcp_udp_csum_ok, &udp, &tcp,
+		&ipv4_csum_ok, &ipv6, &ipv4, &ipv4_fragment,
+		&fcs_ok);
+
+	if (packet_error) {
+
+		if (bytes_written > 0 && !fcs_ok) {
+			if (net_ratelimit())
+				printk(KERN_ERR PFX
+					"%s: packet error: bad FCS\n",
+					enic->netdev->name);
+		}
+
+		dev_kfree_skb_any(skb);
+
+		return;
+	}
+
+	if (eop && bytes_written > 0) {
+
+		/* Good receive
+		 */
+
+		skb_put(skb, bytes_written);
+		skb->protocol = eth_type_trans(skb, enic->netdev);
+
+		if (enic->csum_rx_enabled && !csum_not_calc) {
+			skb->csum = htons(checksum);
+			skb->ip_summed = CHECKSUM_COMPLETE;
+		}
+
+		skb->dev = enic->netdev;
+		enic->netdev->last_rx = jiffies;
+
+		if (enic->vlan_group && vlan_stripped) {
+
+			if (ENIC_SETTING(enic, LRO) && ipv4)
+				lro_vlan_hwaccel_receive_skb(&enic->lro_mgr,
+					skb, enic->vlan_group,
+					vlan, cq_desc);
+			else
+				vlan_hwaccel_receive_skb(skb,
+					enic->vlan_group, vlan);
+
+		} else {
+
+			if (ENIC_SETTING(enic, LRO) && ipv4)
+				lro_receive_skb(&enic->lro_mgr, skb, cq_desc);
+			else
+				netif_receive_skb(skb);
+
+		}
+
+	} else {
+
+		/* Buffer overflow
+		 */
+
+		dev_kfree_skb_any(skb);
+	}
+}
+
+static int enic_rq_service(struct vnic_dev *vdev, struct cq_desc *cq_desc,
+	u8 type, u16 q_number, u16 completed_index, void *opaque)
+{
+	struct enic *enic = vnic_dev_priv(vdev);
+
+	vnic_rq_service(&enic->rq[q_number], cq_desc,
+		completed_index, VNIC_RQ_RETURN_DESC,
+		enic_rq_indicate_buf, opaque);
+
+	return 0;
+}
+
+static void enic_rq_drop_buf(struct vnic_rq *rq,
+	struct cq_desc *cq_desc, struct vnic_rq_buf *buf,
+	int skipped, void *opaque)
+{
+	struct enic *enic = vnic_dev_priv(rq->vdev);
+	struct sk_buff *skb = buf->os_buf;
+
+	if (skipped)
+		return;
+
+	pci_unmap_single(enic->pdev, buf->dma_addr,
+		buf->len, PCI_DMA_FROMDEVICE);
+
+	dev_kfree_skb_any(skb);
+}
+
+static int enic_rq_service_drop(struct vnic_dev *vdev, struct cq_desc *cq_desc,
+	u8 type, u16 q_number, u16 completed_index, void *opaque)
+{
+	struct enic *enic = vnic_dev_priv(vdev);
+
+	vnic_rq_service(&enic->rq[q_number], cq_desc,
+		completed_index, VNIC_RQ_RETURN_DESC,
+		enic_rq_drop_buf, opaque);
+
+	return 0;
+}
+
+static int enic_poll(struct napi_struct *napi, int budget)
+{
+	struct enic *enic = container_of(napi, struct enic, napi);
+	struct net_device *netdev = enic->netdev;
+	unsigned int rq_work_to_do = budget;
+	unsigned int wq_work_to_do = -1; /* no limit */
+	unsigned int  work_done, rq_work_done, wq_work_done;
+
+	/* Service RQ (first) and WQ
+	 */
+
+	rq_work_done = vnic_cq_service(&enic->cq[ENIC_CQ_RQ],
+		rq_work_to_do, enic_rq_service, NULL);
+
+	wq_work_done = vnic_cq_service(&enic->cq[ENIC_CQ_WQ],
+		wq_work_to_do, enic_wq_service, NULL);
+
+	/* Accumulate intr event credits for this polling
+	 * cycle.  An intr event is the completion of a
+	 * a WQ or RQ packet.
+	 */
+
+	work_done = rq_work_done + wq_work_done;
+
+	if (work_done > 0)
+		vnic_intr_return_credits(&enic->intr[ENIC_INTX_WQ_RQ],
+			work_done,
+			0 /* don't unmask intr */,
+			0 /* don't reset intr timer */);
+
+	if (rq_work_done > 0) {
+
+		/* Replenish RQ
+		 */
+
+		vnic_rq_fill(&enic->rq[0], enic_rq_alloc_buf);
+
+	} else {
+
+		/* If no work done, flush all LROs and exit polling
+		 */
+
+		if (ENIC_SETTING(enic, LRO))
+			lro_flush_all(&enic->lro_mgr);
+
+		netif_rx_complete(netdev, napi);
+		vnic_intr_unmask(&enic->intr[ENIC_MSIX_RQ]);
+	}
+
+	return rq_work_done;
+}
+
+static int enic_poll_msix(struct napi_struct *napi, int budget)
+{
+	struct enic *enic = container_of(napi, struct enic, napi);
+	struct net_device *netdev = enic->netdev;
+	unsigned int work_to_do = budget;
+	unsigned int work_done;
+
+	/* Service RQ
+	 */
+
+	work_done = vnic_cq_service(&enic->cq[ENIC_CQ_RQ],
+		work_to_do, enic_rq_service, NULL);
+
+	if (work_done > 0) {
+
+		/* Replenish RQ
+		 */
+
+		vnic_rq_fill(&enic->rq[0], enic_rq_alloc_buf);
+
+		/* Accumulate intr event credits for this polling
+		 * cycle.  An intr event is the completion of a
+		 * a WQ or RQ packet.
+		 */
+
+		vnic_intr_return_credits(&enic->intr[ENIC_MSIX_RQ],
+			work_done,
+			0 /* don't unmask intr */,
+			0 /* don't reset intr timer */);
+	} else {
+
+		/* If no work done, flush all LROs and exit polling
+		 */
+
+		if (ENIC_SETTING(enic, LRO))
+			lro_flush_all(&enic->lro_mgr);
+
+		netif_rx_complete(netdev, napi);
+		vnic_intr_unmask(&enic->intr[ENIC_MSIX_RQ]);
+	}
+
+	return work_done;
+}
+
+static void enic_notify_timer(unsigned long data)
+{
+	struct enic *enic = (struct enic *)data;
+
+	enic_notify_check(enic);
+
+	mod_timer(&enic->notify_timer,
+		round_jiffies(jiffies + ENIC_NOTIFY_TIMER_PERIOD));
+}
+
+static void enic_free_intr(struct enic *enic)
+{
+	struct net_device *netdev = enic->netdev;
+	unsigned int i;
+
+	switch (vnic_dev_get_intr_mode(enic->vdev)) {
+	case VNIC_DEV_INTR_MODE_INTX:
+		free_irq(enic->pdev->irq, netdev);
+		break;
+	case VNIC_DEV_INTR_MODE_MSI:
+		free_irq(enic->pdev->irq, enic);
+		break;
+	case VNIC_DEV_INTR_MODE_MSIX:
+		for (i = 0; i < ARRAY_SIZE(enic->msix); i++)
+			if (enic->msix[i].requested)
+				free_irq(enic->msix_entry[i].vector,
+					enic->msix[i].devid);
+		break;
+	default:
+		break;
+	}
+}
+
+static int enic_request_intr(struct enic *enic)
+{
+	struct net_device *netdev = enic->netdev;
+	unsigned int i;
+	int err = 0;
+
+	switch (vnic_dev_get_intr_mode(enic->vdev)) {
+
+	case VNIC_DEV_INTR_MODE_INTX:
+
+		err = request_irq(enic->pdev->irq, enic_isr_legacy,
+			IRQF_SHARED, netdev->name, netdev);
+		break;
+
+	case VNIC_DEV_INTR_MODE_MSI:
+
+		err = request_irq(enic->pdev->irq, enic_isr_msi,
+			0, netdev->name, enic);
+		break;
+
+	case VNIC_DEV_INTR_MODE_MSIX:
+
+		sprintf(enic->msix[ENIC_MSIX_RQ].devname,
+			"%.11s-rx-0", netdev->name);
+		enic->msix[ENIC_MSIX_RQ].isr = enic_isr_msix_rq;
+		enic->msix[ENIC_MSIX_RQ].devid = enic;
+
+		sprintf(enic->msix[ENIC_MSIX_WQ].devname,
+			"%.11s-tx-0", netdev->name);
+		enic->msix[ENIC_MSIX_WQ].isr = enic_isr_msix_wq;
+		enic->msix[ENIC_MSIX_WQ].devid = enic;
+
+		sprintf(enic->msix[ENIC_MSIX_ERR].devname,
+			"%.11s-err", netdev->name);
+		enic->msix[ENIC_MSIX_ERR].isr = enic_isr_msix_err;
+		enic->msix[ENIC_MSIX_ERR].devid = enic;
+
+		sprintf(enic->msix[ENIC_MSIX_NOTIFY].devname,
+			"%.11s-notify", netdev->name);
+		enic->msix[ENIC_MSIX_NOTIFY].isr = enic_isr_msix_notify;
+		enic->msix[ENIC_MSIX_NOTIFY].devid = enic;
+
+		for (i = 0; i < ARRAY_SIZE(enic->msix); i++) {
+			err = request_irq(enic->msix_entry[i].vector,
+				enic->msix[i].isr, 0,
+				enic->msix[i].devname,
+				enic->msix[i].devid);
+			if (err) {
+				enic_free_intr(enic);
+				break;
+			}
+			enic->msix[i].requested = 1;
+		}
+
+		break;
+
+	default:
+		break;
+	}
+
+	return err;
+}
+
+static int enic_notify_set(struct enic *enic)
+{
+	int err;
+
+	switch (vnic_dev_get_intr_mode(enic->vdev)) {
+	case VNIC_DEV_INTR_MODE_INTX:
+		err = vnic_dev_notify_set(enic->vdev, ENIC_INTX_NOTIFY);
+		break;
+	case VNIC_DEV_INTR_MODE_MSIX:
+		err = vnic_dev_notify_set(enic->vdev, ENIC_MSIX_NOTIFY);
+		break;
+	default:
+		err = vnic_dev_notify_set(enic->vdev, -1 /* no intr */);
+		break;
+	}
+
+	return err;
+}
+
+static void enic_notify_timer_start(struct enic *enic)
+{
+	switch (vnic_dev_get_intr_mode(enic->vdev)) {
+	case VNIC_DEV_INTR_MODE_MSI:
+		mod_timer(&enic->notify_timer, jiffies);
+		break;
+	default:
+		/* Using intr for notification for INTx/MSI-X */
+		break;
+	};
+}
+
+/* rtnl lock is held, process context */
+static int enic_open(struct net_device *netdev)
+{
+	struct enic *enic = netdev_priv(netdev);
+	unsigned int i;
+	int err;
+
+	err = enic_request_intr(enic);
+	if (err) {
+		printk(KERN_ERR PFX "%s: Unable to request irq.\n",
+			netdev->name);
+		return err;
+	}
+
+	err = enic_notify_set(enic);
+	if (err) {
+		printk(KERN_ERR PFX
+			"%s: Failed to alloc notify buffer, aborting.\n",
+			netdev->name);
+		goto err_out_free_intr;
+	}
+
+	for (i = 0; i < enic->rq_count; i++) {
+		err = vnic_rq_fill(&enic->rq[i], enic_rq_alloc_buf);
+		if (err) {
+			printk(KERN_ERR PFX
+				"%s: Unable to alloc receive buffers.\n",
+				netdev->name);
+			goto err_out_notify_unset;
+		}
+	}
+
+	for (i = 0; i < enic->wq_count; i++)
+		vnic_wq_enable(&enic->wq[i]);
+	for (i = 0; i < enic->rq_count; i++)
+		vnic_rq_enable(&enic->rq[i]);
+
+	enic_add_station_addr(enic);
+	enic_set_multicast_list(netdev);
+
+	netif_wake_queue(netdev);
+	napi_enable(&enic->napi);
+	vnic_dev_enable(enic->vdev);
+
+	for (i = 0; i < enic->intr_count; i++)
+		vnic_intr_unmask(&enic->intr[i]);
+
+	enic_notify_timer_start(enic);
+
+	return 0;
+
+err_out_notify_unset:
+	vnic_dev_notify_unset(enic->vdev);
+err_out_free_intr:
+	enic_free_intr(enic);
+
+	return err;
+}
+
+/* rtnl lock is held, process context */
+static int enic_stop(struct net_device *netdev)
+{
+	struct enic *enic = netdev_priv(netdev);
+	unsigned int i;
+	int err;
+
+	del_timer_sync(&enic->notify_timer);
+
+	vnic_dev_disable(enic->vdev);
+	napi_disable(&enic->napi);
+	netif_stop_queue(netdev);
+
+	for (i = 0; i < enic->intr_count; i++)
+		vnic_intr_mask(&enic->intr[i]);
+
+	for (i = 0; i < enic->wq_count; i++) {
+		err = vnic_wq_disable(&enic->wq[i]);
+		if (err)
+			return err;
+	}
+	for (i = 0; i < enic->rq_count; i++) {
+		err = vnic_rq_disable(&enic->rq[i]);
+		if (err)
+			return err;
+	}
+
+	vnic_dev_notify_unset(enic->vdev);
+	enic_free_intr(enic);
+
+	(void)vnic_cq_service(&enic->cq[ENIC_CQ_RQ],
+		-1, enic_rq_service_drop, NULL);
+	(void)vnic_cq_service(&enic->cq[ENIC_CQ_WQ],
+		-1, enic_wq_service, NULL);
+
+	for (i = 0; i < enic->wq_count; i++)
+		vnic_wq_clean(&enic->wq[i], enic_free_wq_buf);
+	for (i = 0; i < enic->rq_count; i++)
+		vnic_rq_clean(&enic->rq[i], enic_free_rq_buf);
+	for (i = 0; i < enic->cq_count; i++)
+		vnic_cq_clean(&enic->cq[i]);
+	for (i = 0; i < enic->intr_count; i++)
+		vnic_intr_clean(&enic->intr[i]);
+
+	return 0;
+}
+
+static int enic_change_mtu(struct net_device *netdev, int new_mtu)
+{
+	struct enic *enic = netdev_priv(netdev);
+	int running = netif_running(netdev);
+
+	if (new_mtu < ENIC_MIN_MTU || new_mtu > ENIC_MAX_MTU)
+		return -EINVAL;
+
+	if (running)
+		enic_stop(netdev);
+
+	netdev->mtu = new_mtu;
+
+	if (netdev->mtu > enic->port_mtu)
+		printk(KERN_WARNING PFX
+			"%s: interface MTU (%d) set higher "
+			"than port MTU (%d)\n",
+			netdev->name, netdev->mtu, enic->port_mtu);
+
+	if (running)
+		enic_open(netdev);
+
+	return 0;
+}
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void enic_poll_controller(struct net_device *netdev)
+{
+	struct enic *enic = netdev_priv(netdev);
+	struct vnic_dev *vdev = enic->vdev;
+
+	switch (vnic_dev_get_intr_mode(vdev)) {
+	case VNIC_DEV_INTR_MODE_MSIX:
+		enic_isr_msix_rq(enic->pdev->irq, enic);
+		enic_isr_msix_wq(enic->pdev->irq, enic);
+		break;
+	case VNIC_DEV_INTR_MODE_MSI:
+		enic_isr_msi(enic->pdev->irq, enic);
+		break;
+	case VNIC_DEV_INTR_MODE_INTX:
+		enic_isr_legacy(enic->pdev->irq, netdev);
+		break;
+	default:
+		break;
+	}
+}
+#endif
+
+static int enic_dev_wait(struct vnic_dev *vdev,
+	int (*start)(struct vnic_dev *, int),
+	int (*finished)(struct vnic_dev *, int *),
+	int arg)
+{
+	unsigned long time;
+	int done;
+	int err;
+
+	BUG_ON(in_interrupt());
+
+	err = start(vdev, arg);
+	if (err)
+		return err;
+
+	/* Wait for func to complete...2 seconds max
+	 */
+
+	time = jiffies + (HZ * 2);
+	do {
+
+		err = finished(vdev, &done);
+		if (err)
+			return err;
+
+		if (done)
+			return 0;
+
+		schedule_timeout_uninterruptible(HZ / 10);
+
+	} while (time_after(time, jiffies));
+
+	return -ETIMEDOUT;
+}
+
+static int enic_dev_open(struct enic *enic)
+{
+	int err;
+
+	err = enic_dev_wait(enic->vdev, vnic_dev_open,
+		vnic_dev_open_done, 0);
+	if (err)
+		printk(KERN_ERR PFX
+			"vNIC device open failed, err %d.\n", err);
+
+	return err;
+}
+
+static int enic_dev_soft_reset(struct enic *enic)
+{
+	int err;
+
+	err = enic_dev_wait(enic->vdev, vnic_dev_soft_reset,
+		vnic_dev_soft_reset_done, 0);
+	if (err)
+		printk(KERN_ERR PFX
+			"vNIC soft reset failed, err %d.\n", err);
+
+	return err;
+}
+
+static void enic_reset(struct work_struct *work)
+{
+	struct enic *enic = container_of(work, struct enic, reset);
+
+	if (!netif_running(enic->netdev))
+		return;
+
+	rtnl_lock();
+
+	spin_lock(&enic->devcmd_lock);
+	vnic_dev_hang_notify(enic->vdev);
+	spin_unlock(&enic->devcmd_lock);
+
+	enic_stop(enic->netdev);
+	enic_dev_soft_reset(enic);
+	enic_reset_mcaddrs(enic);
+	enic_init_vnic_resources(enic);
+	enic_open(enic->netdev);
+
+	rtnl_unlock();
+}
+
+static int enic_set_intr_mode(struct enic *enic)
+{
+	unsigned int n = ARRAY_SIZE(enic->rq);
+	unsigned int m = ARRAY_SIZE(enic->wq);
+	unsigned int i;
+
+	/* Set interrupt mode (INTx, MSI, MSI-X) depending
+	 * system capabilities.
+	 *
+	 * Try MSI-X first
+	 *
+	 * We need n RQs, m WQs, n+m CQs, and n+m+2 INTRs
+	 * (the second to last INTR is used for WQ/RQ errors)
+	 * (the last INTR is used for notifications)
+	 */
+
+	BUG_ON(ARRAY_SIZE(enic->msix_entry) < n + m + 2);
+	for (i = 0; i < n + m + 2; i++)
+		enic->msix_entry[i].entry = i;
+
+	if (enic->config.intr_mode < 1 &&
+	    enic->rq_count >= n &&
+	    enic->wq_count >= m &&
+	    enic->cq_count >= n + m &&
+	    enic->intr_count >= n + m + 2 &&
+	    !pci_enable_msix(enic->pdev, enic->msix_entry, n + m + 2)) {
+
+		enic->rq_count = n;
+		enic->wq_count = m;
+		enic->cq_count = n + m;
+		enic->intr_count = n + m + 2;
+
+		vnic_dev_set_intr_mode(enic->vdev, VNIC_DEV_INTR_MODE_MSIX);
+
+		return 0;
+	}
+
+	/* Next try MSI
+	 *
+	 * We need 1 RQ, 1 WQ, 2 CQs, and 1 INTR
+	 */
+
+	if (enic->config.intr_mode < 2 &&
+	    enic->rq_count >= 1 &&
+	    enic->wq_count >= 1 &&
+	    enic->cq_count >= 2 &&
+	    enic->intr_count >= 1 &&
+	    !pci_enable_msi(enic->pdev)) {
+
+		enic->rq_count = 1;
+		enic->wq_count = 1;
+		enic->cq_count = 2;
+		enic->intr_count = 1;
+
+		vnic_dev_set_intr_mode(enic->vdev, VNIC_DEV_INTR_MODE_MSI);
+
+		return 0;
+	}
+
+	/* Next try INTx
+	 *
+	 * We need 1 RQ, 1 WQ, 2 CQs, and 3 INTRs
+	 * (the first INTR is used for WQ/RQ)
+	 * (the second INTR is used for WQ/RQ errors)
+	 * (the last INTR is used for notifications)
+	 */
+
+	if (enic->config.intr_mode < 3 &&
+	    enic->rq_count >= 1 &&
+	    enic->wq_count >= 1 &&
+	    enic->cq_count >= 2 &&
+	    enic->intr_count >= 3) {
+
+		enic->rq_count = 1;
+		enic->wq_count = 1;
+		enic->cq_count = 2;
+		enic->intr_count = 3;
+
+		vnic_dev_set_intr_mode(enic->vdev, VNIC_DEV_INTR_MODE_INTX);
+
+		return 0;
+	}
+
+	vnic_dev_set_intr_mode(enic->vdev, VNIC_DEV_INTR_MODE_UNKNOWN);
+
+	return -EINVAL;
+}
+
+static void enic_clear_intr_mode(struct enic *enic)
+{
+	switch (vnic_dev_get_intr_mode(enic->vdev)) {
+	case VNIC_DEV_INTR_MODE_MSIX:
+		pci_disable_msix(enic->pdev);
+		break;
+	case VNIC_DEV_INTR_MODE_MSI:
+		pci_disable_msi(enic->pdev);
+		break;
+	default:
+		break;
+	}
+
+	vnic_dev_set_intr_mode(enic->vdev, VNIC_DEV_INTR_MODE_UNKNOWN);
+}
+
+static void enic_iounmap(struct enic *enic)
+{
+	if (enic->bar0.vaddr)
+		iounmap(enic->bar0.vaddr);
+}
+
+static int __devinit enic_probe(struct pci_dev *pdev,
+	const struct pci_device_id *ent)
+{
+	struct net_device *netdev;
+	struct enic *enic;
+	int using_dac = 0;
+	unsigned int i;
+	int err;
+
+	const u8 rss_default_cpu = 0;
+	const u8 rss_hash_type = 0;
+	const u8 rss_hash_bits = 0;
+	const u8 rss_base_cpu = 0;
+	const u8 rss_enable = 0;
+	const u8 tso_ipid_split_en = 0;
+	const u8 ig_vlan_strip_en = 1;
+
+	/* Allocate net device structure and initialize.  Private
+	 * instance data is initialized to zero.
+	 */
+
+	netdev = alloc_etherdev(sizeof(struct enic));
+	if (!netdev) {
+		printk(KERN_ERR PFX "Etherdev alloc failed, aborting.\n");
+		return -ENOMEM;
+	}
+
+	pci_set_drvdata(pdev, netdev);
+
+	SET_NETDEV_DEV(netdev, &pdev->dev);
+
+	enic = netdev_priv(netdev);
+	enic->netdev = netdev;
+	enic->pdev = pdev;
+
+	/* Setup PCI resources
+	 */
+
+	err = pci_enable_device(pdev);
+	if (err) {
+		printk(KERN_ERR PFX
+			"Cannot enable PCI device, aborting.\n");
+		goto err_out_free_netdev;
+	}
+
+	err = pci_request_regions(pdev, DRV_NAME);
+	if (err) {
+		printk(KERN_ERR PFX
+			"Cannot request PCI regions, aborting.\n");
+		goto err_out_disable_device;
+	}
+
+	pci_set_master(pdev);
+
+	/* Query PCI controller on system for DMA addressing
+	 * limitation for the device.  Try 40-bit first, and
+	 * fail to 32-bit.
+	 */
+
+	err = pci_set_dma_mask(pdev, DMA_40BIT_MASK);
+	if (err) {
+		err = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
+		if (err) {
+			printk(KERN_ERR PFX
+				"No usable DMA configuration, aborting.\n");
+			goto err_out_release_regions;
+		}
+		err = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
+		if (err) {
+			printk(KERN_ERR PFX
+				"Unable to obtain 32-bit DMA "
+				"for consistent allocations, aborting.\n");
+			goto err_out_release_regions;
+		}
+	} else {
+		err = pci_set_consistent_dma_mask(pdev, DMA_40BIT_MASK);
+		if (err) {
+			printk(KERN_ERR PFX
+				"Unable to obtain 40-bit DMA "
+				"for consistent allocations, aborting.\n");
+			goto err_out_release_regions;
+		}
+		using_dac = 1;
+	}
+
+	/* Map vNIC resources from BAR0
+	 */
+
+	if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) {
+		printk(KERN_ERR PFX
+			"BAR0 not memory-map'able, aborting.\n");
+		err = -ENODEV;
+		goto err_out_release_regions;
+	}
+
+	enic->bar0.vaddr = pci_iomap(pdev, 0, enic->bar0.len);
+	enic->bar0.bus_addr = pci_resource_start(pdev, 0);
+	enic->bar0.len = pci_resource_len(pdev, 0);
+
+	if (!enic->bar0.vaddr) {
+		printk(KERN_ERR PFX
+			"Cannot memory-map BAR0 res hdr, aborting.\n");
+		err = -ENODEV;
+		goto err_out_release_regions;
+	}
+
+	/* Register vNIC device
+	 */
+
+	enic->vdev = vnic_dev_register(NULL, enic, pdev, &enic->bar0);
+	if (!enic->vdev) {
+		printk(KERN_ERR PFX
+			"vNIC registration failed, aborting.\n");
+		err = -ENODEV;
+		goto err_out_iounmap;
+	}
+
+	/* Issue device open to get device in known state
+	 */
+
+	err = enic_dev_open(enic);
+	if (err) {
+		printk(KERN_ERR PFX
+			"vNIC dev open failed, aborting.\n");
+		goto err_out_vnic_unregister;
+	}
+
+	/* Issue device init to initialize the vnic-to-switch link.
+	 * We'll start with carrier off and wait for link UP
+	 * notification later to turn on carrier.  We don't need
+	 * to wait here for the vnic-to-switch link initialization
+	 * to complete; link UP notification is the indication that
+	 * the process is complete.
+	 */
+
+	netif_carrier_off(netdev);
+
+	err = vnic_dev_init(enic->vdev, 0);
+	if (err) {
+		printk(KERN_ERR PFX
+			"vNIC dev init failed, aborting.\n");
+		goto err_out_dev_close;
+	}
+
+	/* Get vNIC configuration
+	 */
+
+	err = enic_get_vnic_config(enic);
+	if (err) {
+		printk(KERN_ERR PFX
+			"Get vNIC configuration failed, aborting.\n");
+		goto err_out_dev_close;
+	}
+
+	/* Get available resource counts
+	*/
+
+	enic_get_res_counts(enic);
+
+	/* Set interrupt mode based on resource counts and system
+	 * capabilities
+	*/
+
+	err = enic_set_intr_mode(enic);
+	if (err) {
+		printk(KERN_ERR PFX
+			"Failed to set intr mode, aborting.\n");
+		goto err_out_dev_close;
+	}
+
+	/* Allocate and configure vNIC resources
+	 */
+
+	err = enic_alloc_vnic_resources(enic);
+	if (err) {
+		printk(KERN_ERR PFX
+			"Failed to alloc vNIC resources, aborting.\n");
+		goto err_out_free_vnic_resources;
+	}
+
+	enic_init_vnic_resources(enic);
+
+	/* Enable VLAN tag stripping.  RSS not enabled (yet).
+	 */
+
+	err = enic_set_nic_cfg(enic,
+		rss_default_cpu, rss_hash_type,
+		rss_hash_bits, rss_base_cpu,
+		rss_enable, tso_ipid_split_en,
+		ig_vlan_strip_en);
+	if (err) {
+		printk(KERN_ERR PFX
+			"Failed to config nic, aborting.\n");
+		goto err_out_free_vnic_resources;
+	}
+
+	/* Setup notification timer, HW reset task, and locks
+	 */
+
+	init_timer(&enic->notify_timer);
+	enic->notify_timer.function = enic_notify_timer;
+	enic->notify_timer.data = (unsigned long)enic;
+
+	INIT_WORK(&enic->reset, enic_reset);
+
+	for (i = 0; i < enic->wq_count; i++)
+		spin_lock_init(&enic->wq_lock[i]);
+
+	spin_lock_init(&enic->devcmd_lock);
+
+	/* Register net device
+	 */
+
+	enic->port_mtu = enic->config.mtu;
+	(void)enic_change_mtu(netdev, enic->port_mtu);
+
+	err = enic_set_mac_addr(netdev, enic->mac_addr);
+	if (err) {
+		printk(KERN_ERR PFX
+			"Invalid MAC address, aborting.\n");
+		goto err_out_free_vnic_resources;
+	}
+
+	netdev->open = enic_open;
+	netdev->stop = enic_stop;
+	netdev->hard_start_xmit = enic_hard_start_xmit;
+	netdev->get_stats = enic_get_stats;
+	netdev->set_multicast_list = enic_set_multicast_list;
+	netdev->change_mtu = enic_change_mtu;
+	netdev->vlan_rx_register = enic_vlan_rx_register;
+	netdev->vlan_rx_add_vid = enic_vlan_rx_add_vid;
+	netdev->vlan_rx_kill_vid = enic_vlan_rx_kill_vid;
+	netdev->tx_timeout = enic_tx_timeout;
+	netdev->watchdog_timeo = 2 * HZ;
+	netdev->ethtool_ops = &enic_ethtool_ops;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	netdev->poll_controller = enic_poll_controller;
+#endif
+
+	switch (vnic_dev_get_intr_mode(enic->vdev)) {
+	default:
+		netif_napi_add(netdev, &enic->napi, enic_poll, 64);
+		break;
+	case VNIC_DEV_INTR_MODE_MSIX:
+		netif_napi_add(netdev, &enic->napi, enic_poll_msix, 64);
+		break;
+	}
+
+	netdev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
+	if (ENIC_SETTING(enic, TXCSUM))
+		netdev->features |= NETIF_F_SG | NETIF_F_HW_CSUM;
+	if (ENIC_SETTING(enic, TSO))
+		netdev->features |= NETIF_F_TSO |
+			NETIF_F_TSO6 | NETIF_F_TSO_ECN;
+	if (using_dac)
+		netdev->features |= NETIF_F_HIGHDMA;
+
+
+	enic->csum_rx_enabled = ENIC_SETTING(enic, RXCSUM);
+
+	if (ENIC_SETTING(enic, LRO)) {
+		enic->lro_mgr.max_aggr = ENIC_LRO_MAX_AGGR;
+		enic->lro_mgr.max_desc = ENIC_LRO_MAX_DESC;
+		enic->lro_mgr.lro_arr = enic->lro_desc;
+		enic->lro_mgr.get_skb_header = enic_get_skb_header;
+		enic->lro_mgr.features	= LRO_F_NAPI | LRO_F_EXTRACT_VLAN_ID;
+		enic->lro_mgr.dev = netdev;
+		enic->lro_mgr.ip_summed = CHECKSUM_COMPLETE;
+		enic->lro_mgr.ip_summed_aggr = CHECKSUM_UNNECESSARY;
+	}
+
+	err = register_netdev(netdev);
+	if (err) {
+		printk(KERN_ERR PFX
+			"Cannot register net device, aborting.\n");
+		goto err_out_free_vnic_resources;
+	}
+
+	return 0;
+
+err_out_free_vnic_resources:
+	enic_free_vnic_resources(enic);
+err_out_dev_close:
+	vnic_dev_close(enic->vdev);
+err_out_vnic_unregister:
+	enic_clear_intr_mode(enic);
+	vnic_dev_unregister(enic->vdev);
+err_out_iounmap:
+	enic_iounmap(enic);
+err_out_release_regions:
+	pci_release_regions(pdev);
+err_out_disable_device:
+	pci_disable_device(pdev);
+err_out_free_netdev:
+	pci_set_drvdata(pdev, NULL);
+	free_netdev(netdev);
+
+	return err;
+}
+
+static void __devexit enic_remove(struct pci_dev *pdev)
+{
+	struct net_device *netdev = pci_get_drvdata(pdev);
+
+	if (netdev) {
+		struct enic *enic = netdev_priv(netdev);
+
+		flush_scheduled_work();
+		unregister_netdev(netdev);
+		enic_free_vnic_resources(enic);
+		vnic_dev_close(enic->vdev);
+		enic_clear_intr_mode(enic);
+		vnic_dev_unregister(enic->vdev);
+		enic_iounmap(enic);
+		pci_release_regions(pdev);
+		pci_disable_device(pdev);
+		pci_set_drvdata(pdev, NULL);
+		free_netdev(netdev);
+	}
+}
+
+static struct pci_driver enic_driver = {
+	.name = DRV_NAME,
+	.id_table = enic_id_table,
+	.probe = enic_probe,
+	.remove = __devexit_p(enic_remove),
+};
+
+static int __init enic_init_module(void)
+{
+	printk(KERN_INFO PFX "%s, ver %s\n", DRV_DESCRIPTION, DRV_VERSION);
+
+	return pci_register_driver(&enic_driver);
+}
+
+static void __exit enic_cleanup_module(void)
+{
+	pci_unregister_driver(&enic_driver);
+}
+
+module_init(enic_init_module);
+module_exit(enic_cleanup_module);
diff --git a/drivers/net/enic/enic_res.c b/drivers/net/enic/enic_res.c
new file mode 100644
index 0000000..95184b9
--- /dev/null
+++ b/drivers/net/enic/enic_res.c
@@ -0,0 +1,370 @@
+/*
+ * Copyright 2008 Cisco Systems, Inc.  All rights reserved.
+ * Copyright 2007 Nuova Systems, Inc.  All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/netdevice.h>
+
+#include "wq_enet_desc.h"
+#include "rq_enet_desc.h"
+#include "cq_enet_desc.h"
+#include "vnic_resource.h"
+#include "vnic_enet.h"
+#include "vnic_dev.h"
+#include "vnic_wq.h"
+#include "vnic_rq.h"
+#include "vnic_cq.h"
+#include "vnic_intr.h"
+#include "vnic_stats.h"
+#include "vnic_nic.h"
+#include "vnic_rss.h"
+#include "enic_res.h"
+#include "enic.h"
+
+int enic_get_vnic_config(struct enic *enic)
+{
+	struct vnic_enet_config *c = &enic->config;
+	int err;
+
+	err = vnic_dev_mac_addr(enic->vdev, enic->mac_addr);
+	if (err) {
+		printk(KERN_ERR PFX "Error getting MAC addr, %d\n", err);
+		return err;
+	}
+
+#define GET_CONFIG(m) \
+	do { \
+		err = vnic_dev_spec(enic->vdev, \
+			offsetof(struct vnic_enet_config, m), \
+			sizeof(c->m), &c->m); \
+		if (err) { \
+			printk(KERN_ERR PFX \
+				"Error getting %s, %d\n", #m, err); \
+			return err; \
+		} \
+	} while (0)
+
+	GET_CONFIG(flags);
+	GET_CONFIG(wq_desc_count);
+	GET_CONFIG(rq_desc_count);
+	GET_CONFIG(mtu);
+	GET_CONFIG(intr_timer);
+	GET_CONFIG(intr_timer_type);
+	GET_CONFIG(intr_mode);
+
+	c->wq_desc_count =
+		min_t(u32, ENIC_MAX_WQ_DESCS,
+		max_t(u32, ENIC_MIN_WQ_DESCS,
+		c->wq_desc_count));
+	c->wq_desc_count &= 0xfffffff0; /* must be aligned to groups of 16 */
+
+	c->rq_desc_count =
+		min_t(u32, ENIC_MAX_RQ_DESCS,
+		max_t(u32, ENIC_MIN_RQ_DESCS,
+		c->rq_desc_count));
+	c->rq_desc_count &= 0xfffffff0; /* must be aligned to groups of 16 */
+
+	if (c->mtu == 0)
+		c->mtu = 1500;
+	c->mtu = min_t(u16, ENIC_MAX_MTU,
+		max_t(u16, ENIC_MIN_MTU,
+		c->mtu));
+
+	c->intr_timer = min_t(u16, VNIC_INTR_TIMER_MAX, c->intr_timer);
+
+	printk(KERN_INFO PFX "vNIC MAC addr %02x:%02x:%02x:%02x:%02x:%02x "
+		"wq/rq %d/%d\n",
+		enic->mac_addr[0], enic->mac_addr[1], enic->mac_addr[2],
+		enic->mac_addr[3], enic->mac_addr[4], enic->mac_addr[5],
+		c->wq_desc_count, c->rq_desc_count);
+	printk(KERN_INFO PFX "vNIC mtu %d csum tx/rx %d/%d tso/lro %d/%d "
+		"intr timer %d\n",
+		c->mtu, ENIC_SETTING(enic, TXCSUM),
+		ENIC_SETTING(enic, RXCSUM), ENIC_SETTING(enic, TSO),
+		ENIC_SETTING(enic, LRO), c->intr_timer);
+
+	return 0;
+}
+
+void enic_add_station_addr(struct enic *enic)
+{
+	vnic_dev_add_addr(enic->vdev, enic->mac_addr);
+}
+
+void enic_add_multicast_addr(struct enic *enic, u8 *addr)
+{
+	vnic_dev_add_addr(enic->vdev, addr);
+}
+
+void enic_del_multicast_addr(struct enic *enic, u8 *addr)
+{
+	vnic_dev_del_addr(enic->vdev, addr);
+}
+
+void enic_add_vlan(struct enic *enic, u16 vlanid)
+{
+	u64 a0 = vlanid, a1 = 0;
+	int wait = 1000;
+	int err;
+
+	err = vnic_dev_cmd(enic->vdev, CMD_VLAN_ADD, &a0, &a1, wait);
+	if (err)
+		printk(KERN_ERR PFX "Can't add vlan id, %d\n", err);
+}
+
+void enic_del_vlan(struct enic *enic, u16 vlanid)
+{
+	u64 a0 = vlanid, a1 = 0;
+	int wait = 1000;
+	int err;
+
+	err = vnic_dev_cmd(enic->vdev, CMD_VLAN_DEL, &a0, &a1, wait);
+	if (err)
+		printk(KERN_ERR PFX "Can't delete vlan id, %d\n", err);
+}
+
+int enic_set_nic_cfg(struct enic *enic, u8 rss_default_cpu, u8 rss_hash_type,
+	u8 rss_hash_bits, u8 rss_base_cpu, u8 rss_enable, u8 tso_ipid_split_en,
+	u8 ig_vlan_strip_en)
+{
+	u64 a0, a1;
+	u32 nic_cfg;
+	int wait = 1000;
+
+	vnic_set_nic_cfg(&nic_cfg, rss_default_cpu,
+		rss_hash_type, rss_hash_bits, rss_base_cpu,
+		rss_enable, tso_ipid_split_en, ig_vlan_strip_en);
+
+	a0 = nic_cfg;
+	a1 = 0;
+
+	return vnic_dev_cmd(enic->vdev, CMD_NIC_CFG, &a0, &a1, wait);
+}
+
+void enic_free_vnic_resources(struct enic *enic)
+{
+	unsigned int i;
+
+	for (i = 0; i < enic->wq_count; i++)
+		vnic_wq_free(&enic->wq[i]);
+	for (i = 0; i < enic->rq_count; i++)
+		vnic_rq_free(&enic->rq[i]);
+	for (i = 0; i < enic->cq_count; i++)
+		vnic_cq_free(&enic->cq[i]);
+	for (i = 0; i < enic->intr_count; i++)
+		vnic_intr_free(&enic->intr[i]);
+}
+
+void enic_get_res_counts(struct enic *enic)
+{
+	enic->wq_count = vnic_dev_get_res_count(enic->vdev, RES_TYPE_WQ);
+	enic->rq_count = vnic_dev_get_res_count(enic->vdev, RES_TYPE_RQ);
+	enic->cq_count = vnic_dev_get_res_count(enic->vdev, RES_TYPE_CQ);
+	enic->intr_count = vnic_dev_get_res_count(enic->vdev,
+		RES_TYPE_INTR_CTRL);
+
+	printk(KERN_INFO PFX "vNIC resources avail: "
+		"wq %d rq %d cq %d intr %d\n",
+		enic->wq_count, enic->rq_count,
+		enic->cq_count, enic->intr_count);
+}
+
+void enic_init_vnic_resources(struct enic *enic)
+{
+	enum vnic_dev_intr_mode intr_mode;
+	unsigned int mask_on_assertion;
+	unsigned int interrupt_offset;
+	unsigned int error_interrupt_enable;
+	unsigned int error_interrupt_offset;
+	unsigned int cq_index;
+	unsigned int i;
+
+	intr_mode = vnic_dev_get_intr_mode(enic->vdev);
+
+	/* Init RQ/WQ resources.
+	 *
+	 * RQ[0 - n-1] point to CQ[0 - n-1]
+	 * WQ[0 - m-1] point to CQ[n - n+m-1]
+	 *
+	 * Error interrupt is not enabled for MSI.
+	 */
+
+	switch (intr_mode) {
+	case VNIC_DEV_INTR_MODE_INTX:
+	case VNIC_DEV_INTR_MODE_MSIX:
+		error_interrupt_enable = 1;
+		error_interrupt_offset = enic->intr_count - 2;
+		break;
+	default:
+		error_interrupt_enable = 0;
+		error_interrupt_offset = 0;
+		break;
+	}
+
+	for (i = 0; i < enic->rq_count; i++) {
+		cq_index = i;
+		vnic_rq_init(&enic->rq[i],
+			cq_index,
+			error_interrupt_enable,
+			error_interrupt_offset);
+	}
+
+	for (i = 0; i < enic->wq_count; i++) {
+		cq_index = enic->rq_count + i;
+		vnic_wq_init(&enic->wq[i],
+			cq_index,
+			error_interrupt_enable,
+			error_interrupt_offset);
+	}
+
+	/* Init CQ resources
+	 *
+	 * CQ[0 - n+m-1] point to INTR[0] for INTx, MSI
+	 * CQ[0 - n+m-1] point to INTR[0 - n+m-1] for MSI-X
+	 */
+
+	for (i = 0; i < enic->cq_count; i++) {
+
+		switch (intr_mode) {
+		case VNIC_DEV_INTR_MODE_MSIX:
+			interrupt_offset = i;
+			break;
+		default:
+			interrupt_offset = 0;
+			break;
+		}
+
+		vnic_cq_init(&enic->cq[i],
+			0 /* flow_control_enable */,
+			1 /* color_enable */,
+			0 /* cq_head */,
+			0 /* cq_tail */,
+			1 /* cq_tail_color */,
+			1 /* interrupt_enable */,
+			1 /* cq_entry_enable */,
+			0 /* cq_message_enable */,
+			interrupt_offset,
+			0 /* cq_message_addr */);
+	}
+
+	/* Init INTR resources
+	 *
+	 * mask_on_assertion is not used for INTx due to the level-
+	 * triggered nature of INTx
+	 */
+
+	switch (intr_mode) {
+	case VNIC_DEV_INTR_MODE_MSI:
+	case VNIC_DEV_INTR_MODE_MSIX:
+		mask_on_assertion = 1;
+		break;
+	default:
+		mask_on_assertion = 0;
+		break;
+	}
+
+	for (i = 0; i < enic->intr_count; i++) {
+		vnic_intr_init(&enic->intr[i],
+			enic->config.intr_timer,
+			enic->config.intr_timer_type,
+			mask_on_assertion);
+	}
+
+	/* Clear LIF stats
+	 */
+
+	vnic_dev_stats_clear(enic->vdev);
+}
+
+int enic_alloc_vnic_resources(struct enic *enic)
+{
+	enum vnic_dev_intr_mode intr_mode;
+	unsigned int i;
+	int err;
+
+	intr_mode = vnic_dev_get_intr_mode(enic->vdev);
+
+	printk(KERN_INFO PFX "vNIC resources used:  "
+		"wq %d rq %d cq %d intr %d intr mode %s\n",
+		enic->wq_count, enic->rq_count,
+		enic->cq_count, enic->intr_count,
+		intr_mode == VNIC_DEV_INTR_MODE_INTX ? "legacy PCI INTx" :
+		intr_mode == VNIC_DEV_INTR_MODE_MSI ? "MSI" :
+		intr_mode == VNIC_DEV_INTR_MODE_MSIX ? "MSI-X" :
+		"unknown"
+		);
+
+	/* Allocate queue resources
+	 */
+
+	for (i = 0; i < enic->wq_count; i++) {
+		err = vnic_wq_alloc(enic->vdev, &enic->wq[i], i,
+			enic->config.wq_desc_count,
+			sizeof(struct wq_enet_desc));
+		if (err)
+			goto err_out_cleanup;
+	}
+
+	for (i = 0; i < enic->rq_count; i++) {
+		err = vnic_rq_alloc(enic->vdev, &enic->rq[i], i,
+			enic->config.rq_desc_count,
+			sizeof(struct rq_enet_desc));
+		if (err)
+			goto err_out_cleanup;
+	}
+
+	for (i = 0; i < enic->cq_count; i++) {
+		if (i < enic->rq_count)
+			err = vnic_cq_alloc(enic->vdev, &enic->cq[i], i,
+				enic->config.rq_desc_count,
+				sizeof(struct cq_enet_rq_desc));
+		else
+			err = vnic_cq_alloc(enic->vdev, &enic->cq[i], i,
+				enic->config.wq_desc_count,
+				sizeof(struct cq_enet_wq_desc));
+		if (err)
+			goto err_out_cleanup;
+	}
+
+	for (i = 0; i < enic->intr_count; i++) {
+		err = vnic_intr_alloc(enic->vdev, &enic->intr[i], i);
+		if (err)
+			goto err_out_cleanup;
+	}
+
+	/* Hook remaining resource
+	 */
+
+	enic->legacy_pba = vnic_dev_get_res(enic->vdev,
+		RES_TYPE_INTR_PBA_LEGACY, 0);
+	if (!enic->legacy_pba && intr_mode == VNIC_DEV_INTR_MODE_INTX) {
+		printk(KERN_ERR PFX "Failed to hook legacy pba resource\n");
+		err = -ENODEV;
+		goto err_out_cleanup;
+	}
+
+	return 0;
+
+err_out_cleanup:
+	enic_free_vnic_resources(enic);
+
+	return err;
+}
diff --git a/drivers/net/enic/enic_res.h b/drivers/net/enic/enic_res.h
new file mode 100644
index 0000000..68534a2
--- /dev/null
+++ b/drivers/net/enic/enic_res.h
@@ -0,0 +1,151 @@
+/*
+ * Copyright 2008 Cisco Systems, Inc.  All rights reserved.
+ * Copyright 2007 Nuova Systems, Inc.  All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+#ifndef _ENIC_RES_H_
+#define _ENIC_RES_H_
+
+#include "wq_enet_desc.h"
+#include "rq_enet_desc.h"
+#include "vnic_wq.h"
+#include "vnic_rq.h"
+
+#define ENIC_MIN_WQ_DESCS		64
+#define ENIC_MAX_WQ_DESCS		4096
+#define ENIC_MIN_RQ_DESCS		64
+#define ENIC_MAX_RQ_DESCS		4096
+
+#define ENIC_MIN_MTU			576  /* minimum for IPv4 */
+#define ENIC_MAX_MTU			9000
+
+#define ENIC_MULTICAST_PERFECT_FILTERS	32
+
+#define ENIC_NON_TSO_MAX_DESC		16
+
+#define ENIC_SETTING(enic, f) ((enic->config.flags & VENETF_##f) ? 1 : 0)
+
+static inline void enic_queue_wq_desc_ex(struct vnic_wq *wq,
+	void *os_buf, dma_addr_t dma_addr, unsigned int len,
+	unsigned int mss_or_csum_offset, unsigned int hdr_len,
+	int vlan_tag_insert, unsigned int vlan_tag,
+	int offload_mode, int cq_entry, int sop, int eop)
+{
+	struct wq_enet_desc *desc = vnic_wq_next_desc(wq);
+
+	wq_enet_desc_enc(desc,
+		(u64)dma_addr | VNIC_PADDR_TARGET,
+		(u16)len,
+		(u16)mss_or_csum_offset,
+		(u16)hdr_len, (u8)offload_mode,
+		(u8)eop, (u8)cq_entry,
+		0, /* fcoe_encap */
+		(u8)vlan_tag_insert,
+		(u16)vlan_tag,
+		0 /* loopback */);
+
+	wmb();
+
+	vnic_wq_post(wq, os_buf, dma_addr, len, sop, eop);
+}
+
+static inline void enic_queue_wq_desc_cont(struct vnic_wq *wq,
+	void *os_buf, dma_addr_t dma_addr, unsigned int len, int eop)
+{
+	enic_queue_wq_desc_ex(wq, os_buf, dma_addr, len,
+		0, 0, 0, 0, 0,
+		eop, 0 /* !SOP */, eop);
+}
+
+static inline void enic_queue_wq_desc(struct vnic_wq *wq, void *os_buf,
+	dma_addr_t dma_addr, unsigned int len, int vlan_tag_insert,
+	unsigned int vlan_tag, int eop)
+{
+	enic_queue_wq_desc_ex(wq, os_buf, dma_addr, len,
+		0, 0, vlan_tag_insert, vlan_tag,
+		WQ_ENET_OFFLOAD_MODE_CSUM,
+		eop, 1 /* SOP */, eop);
+}
+
+static inline void enic_queue_wq_desc_csum(struct vnic_wq *wq,
+	void *os_buf, dma_addr_t dma_addr, unsigned int len,
+	int ip_csum, int tcpudp_csum, int vlan_tag_insert,
+	unsigned int vlan_tag, int eop)
+{
+	enic_queue_wq_desc_ex(wq, os_buf, dma_addr, len,
+		(ip_csum ? 1 : 0) + (tcpudp_csum ? 2 : 0),
+		0, vlan_tag_insert, vlan_tag,
+		WQ_ENET_OFFLOAD_MODE_CSUM,
+		eop, 1 /* SOP */, eop);
+}
+
+static inline void enic_queue_wq_desc_csum_l4(struct vnic_wq *wq,
+	void *os_buf, dma_addr_t dma_addr, unsigned int len,
+	unsigned int csum_offset, unsigned int hdr_len,
+	int vlan_tag_insert, unsigned int vlan_tag, int eop)
+{
+	enic_queue_wq_desc_ex(wq, os_buf, dma_addr, len,
+		csum_offset, hdr_len, vlan_tag_insert, vlan_tag,
+		WQ_ENET_OFFLOAD_MODE_CSUM_L4,
+		eop, 1 /* SOP */, eop);
+}
+
+static inline void enic_queue_wq_desc_tso(struct vnic_wq *wq,
+	void *os_buf, dma_addr_t dma_addr, unsigned int len,
+	unsigned int mss, unsigned int hdr_len, int vlan_tag_insert,
+	unsigned int vlan_tag, int eop)
+{
+	enic_queue_wq_desc_ex(wq, os_buf, dma_addr, len,
+		mss, hdr_len, vlan_tag_insert, vlan_tag,
+		WQ_ENET_OFFLOAD_MODE_TSO,
+		eop, 1 /* SOP */, eop);
+}
+
+static inline void enic_queue_rq_desc(struct vnic_rq *rq,
+	void *os_buf, unsigned int os_buf_index,
+	dma_addr_t dma_addr, unsigned int len)
+{
+	struct rq_enet_desc *desc = vnic_rq_next_desc(rq);
+	u8 type = os_buf_index ?
+		RQ_ENET_TYPE_NOT_SOP : RQ_ENET_TYPE_ONLY_SOP;
+
+	rq_enet_desc_enc(desc,
+		(u64)dma_addr | VNIC_PADDR_TARGET,
+		type, (u16)len);
+
+	wmb();
+
+	vnic_rq_post(rq, os_buf, os_buf_index, dma_addr, len);
+}
+
+struct enic;
+
+int enic_get_vnic_config(struct enic *);
+void enic_add_station_addr(struct enic *enic);
+void enic_add_multicast_addr(struct enic *enic, u8 *addr);
+void enic_del_multicast_addr(struct enic *enic, u8 *addr);
+void enic_add_vlan(struct enic *enic, u16 vlanid);
+void enic_del_vlan(struct enic *enic, u16 vlanid);
+int enic_set_nic_cfg(struct enic *enic, u8 rss_default_cpu, u8 rss_hash_type,
+	u8 rss_hash_bits, u8 rss_base_cpu, u8 rss_enable, u8 tso_ipid_split_en,
+	u8 ig_vlan_strip_en);
+void enic_get_res_counts(struct enic *enic);
+void enic_init_vnic_resources(struct enic *enic);
+int enic_alloc_vnic_resources(struct enic *);
+void enic_free_vnic_resources(struct enic *);
+
+#endif /* _ENIC_RES_H_ */
diff --git a/drivers/net/enic/rq_enet_desc.h b/drivers/net/enic/rq_enet_desc.h
new file mode 100644
index 0000000..a06e649
--- /dev/null
+++ b/drivers/net/enic/rq_enet_desc.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2008 Cisco Systems, Inc.  All rights reserved.
+ * Copyright 2007 Nuova Systems, Inc.  All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+#ifndef _RQ_ENET_DESC_H_
+#define _RQ_ENET_DESC_H_
+
+/* Ethernet receive queue descriptor: 16B */
+struct rq_enet_desc {
+	__le64 address;
+	__le16 length_type;
+	u8 reserved[6];
+};
+
+enum rq_enet_type_types {
+	RQ_ENET_TYPE_ONLY_SOP = 0,
+	RQ_ENET_TYPE_NOT_SOP = 1,
+	RQ_ENET_TYPE_RESV2 = 2,
+	RQ_ENET_TYPE_RESV3 = 3,
+};
+
+#define RQ_ENET_ADDR_BITS		64
+#define RQ_ENET_LEN_BITS		14
+#define RQ_ENET_LEN_MASK		((1 << RQ_ENET_LEN_BITS) - 1)
+#define RQ_ENET_TYPE_BITS		2
+#define RQ_ENET_TYPE_MASK		((1 << RQ_ENET_TYPE_BITS) - 1)
+
+static inline void rq_enet_desc_enc(struct rq_enet_desc *desc,
+	u64 address, u8 type, u16 length)
+{
+	desc->address = cpu_to_le64(address);
+	desc->length_type = cpu_to_le16((length & RQ_ENET_LEN_MASK) |
+		((type & RQ_ENET_TYPE_MASK) << RQ_ENET_LEN_BITS));
+}
+
+static inline void rq_enet_desc_dec(struct rq_enet_desc *desc,
+	u64 *address, u8 *type, u16 *length)
+{
+	*address = le64_to_cpu(desc->address);
+	*length = le16_to_cpu(desc->length_type) & RQ_ENET_LEN_MASK;
+	*type = (u8)((le16_to_cpu(desc->length_type) >> RQ_ENET_LEN_BITS) &
+		RQ_ENET_TYPE_MASK);
+}
+
+#endif /* _RQ_ENET_DESC_H_ */
diff --git a/drivers/net/enic/vnic_cq.c b/drivers/net/enic/vnic_cq.c
new file mode 100644
index 0000000..020ae6c
--- /dev/null
+++ b/drivers/net/enic/vnic_cq.c
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2008 Cisco Systems, Inc.  All rights reserved.
+ * Copyright 2007 Nuova Systems, Inc.  All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+
+#include "vnic_dev.h"
+#include "vnic_cq.h"
+
+void vnic_cq_free(struct vnic_cq *cq)
+{
+	vnic_dev_free_desc_ring(cq->vdev, &cq->ring);
+
+	cq->ctrl = NULL;
+}
+
+int vnic_cq_alloc(struct vnic_dev *vdev, struct vnic_cq *cq, unsigned int index,
+	unsigned int desc_count, unsigned int desc_size)
+{
+	int err;
+
+	cq->index = index;
+	cq->vdev = vdev;
+
+	cq->ctrl = vnic_dev_get_res(vdev, RES_TYPE_CQ, index);
+	if (!cq->ctrl) {
+		printk(KERN_ERR "Failed to hook CQ[%d] resource\n", index);
+		return -EINVAL;
+	}
+
+	err = vnic_dev_alloc_desc_ring(vdev, &cq->ring, desc_count, desc_size);
+	if (err)
+		return err;
+
+	return 0;
+}
+
+void vnic_cq_init(struct vnic_cq *cq, unsigned int flow_control_enable,
+	unsigned int color_enable, unsigned int cq_head, unsigned int cq_tail,
+	unsigned int cq_tail_color, unsigned int interrupt_enable,
+	unsigned int cq_entry_enable, unsigned int cq_message_enable,
+	unsigned int interrupt_offset, u64 cq_message_addr)
+{
+	u64 paddr;
+
+	paddr = (u64)cq->ring.base_addr | VNIC_PADDR_TARGET;
+	writeq(paddr, &cq->ctrl->ring_base);
+	iowrite32(cq->ring.desc_count, &cq->ctrl->ring_size);
+	iowrite32(flow_control_enable, &cq->ctrl->flow_control_enable);
+	iowrite32(color_enable, &cq->ctrl->color_enable);
+	iowrite32(cq_head, &cq->ctrl->cq_head);
+	iowrite32(cq_tail, &cq->ctrl->cq_tail);
+	iowrite32(cq_tail_color, &cq->ctrl->cq_tail_color);
+	iowrite32(interrupt_enable, &cq->ctrl->interrupt_enable);
+	iowrite32(cq_entry_enable, &cq->ctrl->cq_entry_enable);
+	iowrite32(cq_message_enable, &cq->ctrl->cq_message_enable);
+	iowrite32(interrupt_offset, &cq->ctrl->interrupt_offset);
+	writeq(cq_message_addr, &cq->ctrl->cq_message_addr);
+}
+
+void vnic_cq_clean(struct vnic_cq *cq)
+{
+	cq->to_clean = 0;
+	cq->last_color = 0;
+
+	iowrite32(0, &cq->ctrl->cq_head);
+	iowrite32(0, &cq->ctrl->cq_tail);
+	iowrite32(1, &cq->ctrl->cq_tail_color);
+
+	vnic_dev_clear_desc_ring(&cq->ring);
+}
diff --git a/drivers/net/enic/vnic_cq.h b/drivers/net/enic/vnic_cq.h
new file mode 100644
index 0000000..114763c
--- /dev/null
+++ b/drivers/net/enic/vnic_cq.h
@@ -0,0 +1,113 @@
+/*
+ * Copyright 2008 Cisco Systems, Inc.  All rights reserved.
+ * Copyright 2007 Nuova Systems, Inc.  All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+#ifndef _VNIC_CQ_H_
+#define _VNIC_CQ_H_
+
+#include "cq_desc.h"
+#include "vnic_dev.h"
+
+/* Completion queue control */
+struct vnic_cq_ctrl {
+	u64 ring_base;			/* 0x00 */
+	u32 ring_size;			/* 0x08 */
+	u32 pad0;
+	u32 flow_control_enable;	/* 0x10 */
+	u32 pad1;
+	u32 color_enable;		/* 0x18 */
+	u32 pad2;
+	u32 cq_head;			/* 0x20 */
+	u32 pad3;
+	u32 cq_tail;			/* 0x28 */
+	u32 pad4;
+	u32 cq_tail_color;		/* 0x30 */
+	u32 pad5;
+	u32 interrupt_enable;		/* 0x38 */
+	u32 pad6;
+	u32 cq_entry_enable;		/* 0x40 */
+	u32 pad7;
+	u32 cq_message_enable;		/* 0x48 */
+	u32 pad8;
+	u32 interrupt_offset;		/* 0x50 */
+	u32 pad9;
+	u64 cq_message_addr;		/* 0x58 */
+	u32 pad10;
+};
+
+struct vnic_cq {
+	unsigned int index;
+	struct vnic_dev *vdev;
+	struct vnic_cq_ctrl __iomem *ctrl;              /* memory-mapped */
+	struct vnic_dev_ring ring;
+	unsigned int to_clean;
+	unsigned int last_color;
+};
+
+static inline unsigned int vnic_cq_service(struct vnic_cq *cq,
+	unsigned int work_to_do,
+	int (*q_service)(struct vnic_dev *vdev, struct cq_desc *cq_desc,
+	u8 type, u16 q_number, u16 completed_index, void *opaque),
+	void *opaque)
+{
+	struct cq_desc *cq_desc;
+	unsigned int work_done = 0;
+	u16 q_number, completed_index;
+	u8 type, color;
+
+	cq_desc = (struct cq_desc *)((u8 *)cq->ring.descs +
+		cq->ring.desc_size * cq->to_clean);
+	cq_desc_dec(cq_desc, &type, &color,
+		&q_number, &completed_index);
+
+	while (color != cq->last_color) {
+
+		if ((*q_service)(cq->vdev, cq_desc, type,
+			q_number, completed_index, opaque))
+			break;
+
+		cq->to_clean++;
+		if (cq->to_clean == cq->ring.desc_count) {
+			cq->to_clean = 0;
+			cq->last_color = cq->last_color ? 0 : 1;
+		}
+
+		cq_desc = (struct cq_desc *)((u8 *)cq->ring.descs +
+			cq->ring.desc_size * cq->to_clean);
+		cq_desc_dec(cq_desc, &type, &color,
+			&q_number, &completed_index);
+
+		work_done++;
+		if (work_done >= work_to_do)
+			break;
+	}
+
+	return work_done;
+}
+
+void vnic_cq_free(struct vnic_cq *cq);
+int vnic_cq_alloc(struct vnic_dev *vdev, struct vnic_cq *cq, unsigned int index,
+	unsigned int desc_count, unsigned int desc_size);
+void vnic_cq_init(struct vnic_cq *cq, unsigned int flow_control_enable,
+	unsigned int color_enable, unsigned int cq_head, unsigned int cq_tail,
+	unsigned int cq_tail_color, unsigned int interrupt_enable,
+	unsigned int cq_entry_enable, unsigned int message_enable,
+	unsigned int interrupt_offset, u64 message_addr);
+void vnic_cq_clean(struct vnic_cq *cq);
+
+#endif /* _VNIC_CQ_H_ */
diff --git a/drivers/net/enic/vnic_dev.c b/drivers/net/enic/vnic_dev.c
new file mode 100644
index 0000000..4d104f5
--- /dev/null
+++ b/drivers/net/enic/vnic_dev.c
@@ -0,0 +1,674 @@
+/*
+ * Copyright 2008 Cisco Systems, Inc.  All rights reserved.
+ * Copyright 2007 Nuova Systems, Inc.  All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/if_ether.h>
+
+#include "vnic_resource.h"
+#include "vnic_devcmd.h"
+#include "vnic_dev.h"
+#include "vnic_stats.h"
+
+struct vnic_res {
+	void __iomem *vaddr;
+	unsigned int count;
+};
+
+struct vnic_dev {
+	void *priv;
+	struct pci_dev *pdev;
+	struct vnic_res res[RES_TYPE_MAX];
+	enum vnic_dev_intr_mode intr_mode;
+	struct vnic_devcmd __iomem *devcmd;
+	struct vnic_devcmd_notify *notify;
+	struct vnic_devcmd_notify notify_copy;
+	dma_addr_t notify_pa;
+	u32 *linkstatus;
+	dma_addr_t linkstatus_pa;
+	struct vnic_stats *stats;
+	dma_addr_t stats_pa;
+	struct vnic_devcmd_fw_info *fw_info;
+	dma_addr_t fw_info_pa;
+};
+
+#define VNIC_MAX_RES_HDR_SIZE \
+	(sizeof(struct vnic_resource_header) + \
+	sizeof(struct vnic_resource) * RES_TYPE_MAX)
+#define VNIC_RES_STRIDE	128
+
+void *vnic_dev_priv(struct vnic_dev *vdev)
+{
+	return vdev->priv;
+}
+
+static int vnic_dev_discover_res(struct vnic_dev *vdev,
+	struct vnic_dev_bar *bar)
+{
+	struct vnic_resource_header __iomem *rh;
+	struct vnic_resource __iomem *r;
+	u8 type;
+
+	if (bar->len < VNIC_MAX_RES_HDR_SIZE) {
+		printk(KERN_ERR "vNIC BAR0 res hdr length error\n");
+		return -EINVAL;
+	}
+
+	rh = bar->vaddr;
+	if (!rh) {
+		printk(KERN_ERR "vNIC BAR0 res hdr not mem-mapped\n");
+		return -EINVAL;
+	}
+
+	if (ioread32(&rh->magic) != VNIC_RES_MAGIC ||
+	    ioread32(&rh->version) != VNIC_RES_VERSION) {
+		printk(KERN_ERR "vNIC BAR0 res magic/version error "
+			"exp (%lx/%lx) curr (%x/%x)\n",
+			VNIC_RES_MAGIC, VNIC_RES_VERSION,
+			ioread32(&rh->magic), ioread32(&rh->version));
+		return -EINVAL;
+	}
+
+	r = (struct vnic_resource __iomem *)(rh + 1);
+
+	while ((type = ioread8(&r->type)) != RES_TYPE_EOL) {
+
+		u8 bar_num = ioread8(&r->bar);
+		u32 bar_offset = ioread32(&r->bar_offset);
+		u32 count = ioread32(&r->count);
+		u32 len;
+
+		r++;
+
+		if (bar_num != 0)  /* only mapping in BAR0 resources */
+			continue;
+
+		switch (type) {
+		case RES_TYPE_WQ:
+		case RES_TYPE_RQ:
+		case RES_TYPE_CQ:
+		case RES_TYPE_INTR_CTRL:
+			/* each count is stride bytes long */
+			len = count * VNIC_RES_STRIDE;
+			if (len + bar_offset > bar->len) {
+				printk(KERN_ERR "vNIC BAR0 resource %d "
+					"out-of-bounds, offset 0x%x + "
+					"size 0x%x > bar len 0x%lx\n",
+					type, bar_offset,
+					len,
+					bar->len);
+				return -EINVAL;
+			}
+			break;
+		case RES_TYPE_INTR_PBA_LEGACY:
+		case RES_TYPE_DEVCMD:
+			len = count;
+			break;
+		default:
+			continue;
+		}
+
+		vdev->res[type].count = count;
+		vdev->res[type].vaddr = (char __iomem *)bar->vaddr + bar_offset;
+	}
+
+	return 0;
+}
+
+unsigned int vnic_dev_get_res_count(struct vnic_dev *vdev,
+	enum vnic_res_type type)
+{
+	return vdev->res[type].count;
+}
+
+void __iomem *vnic_dev_get_res(struct vnic_dev *vdev, enum vnic_res_type type,
+	unsigned int index)
+{
+	if (!vdev->res[type].vaddr)
+		return NULL;
+
+	switch (type) {
+	case RES_TYPE_WQ:
+	case RES_TYPE_RQ:
+	case RES_TYPE_CQ:
+	case RES_TYPE_INTR_CTRL:
+		return (char __iomem *)vdev->res[type].vaddr +
+			index * VNIC_RES_STRIDE;
+	default:
+		return (char __iomem *)vdev->res[type].vaddr;
+	}
+}
+
+unsigned int vnic_dev_desc_ring_size(struct vnic_dev_ring *ring,
+	unsigned int desc_count, unsigned int desc_size)
+{
+	/* The base address of the desc rings must be 512 byte aligned.
+	 * Descriptor count is aligned to groups of 32 descriptors.  A
+	 * count of 0 means the maximum 4096 descriptors.  Descriptor
+	 * size is aligned to 16 bytes.
+	 */
+
+	unsigned int count_align = 32;
+	unsigned int desc_align = 16;
+
+	ring->base_align = 512;
+
+	if (desc_count == 0)
+		desc_count = 4096;
+
+	ring->desc_count = ALIGN(desc_count, count_align);
+
+	ring->desc_size = ALIGN(desc_size, desc_align);
+
+	ring->size = ring->desc_count * ring->desc_size;
+	ring->size_unaligned = ring->size + ring->base_align;
+
+	return ring->size_unaligned;
+}
+
+void vnic_dev_clear_desc_ring(struct vnic_dev_ring *ring)
+{
+	memset(ring->descs, 0, ring->size);
+}
+
+int vnic_dev_alloc_desc_ring(struct vnic_dev *vdev, struct vnic_dev_ring *ring,
+	unsigned int desc_count, unsigned int desc_size)
+{
+	vnic_dev_desc_ring_size(ring, desc_count, desc_size);
+
+	ring->descs_unaligned = pci_alloc_consistent(vdev->pdev,
+		ring->size_unaligned,
+		&ring->base_addr_unaligned);
+
+	if (!ring->descs_unaligned) {
+		printk(KERN_ERR
+		  "Failed to allocate ring (size=%d), aborting\n",
+			(int)ring->size);
+		return -ENOMEM;
+	}
+
+	ring->base_addr = ALIGN(ring->base_addr_unaligned,
+		ring->base_align);
+	ring->descs = (u8 *)ring->descs_unaligned +
+		(ring->base_addr - ring->base_addr_unaligned);
+
+	vnic_dev_clear_desc_ring(ring);
+
+	ring->desc_avail = ring->desc_count - 1;
+
+	return 0;
+}
+
+void vnic_dev_free_desc_ring(struct vnic_dev *vdev, struct vnic_dev_ring *ring)
+{
+	if (ring->descs) {
+		pci_free_consistent(vdev->pdev,
+			ring->size_unaligned,
+			ring->descs_unaligned,
+			ring->base_addr_unaligned);
+		ring->descs = NULL;
+	}
+}
+
+int vnic_dev_cmd(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd,
+	u64 *a0, u64 *a1, int wait)
+{
+	struct vnic_devcmd __iomem *devcmd = vdev->devcmd;
+	int delay;
+	u32 status;
+	int dev_cmd_err[] = {
+		/* convert from fw's version of error.h to host's version */
+		0,	/* ERR_SUCCESS */
+		EINVAL,	/* ERR_EINVAL */
+		EFAULT,	/* ERR_EFAULT */
+		EPERM,	/* ERR_EPERM */
+		EBUSY,  /* ERR_EBUSY */
+	};
+	int err;
+
+	status = ioread32(&devcmd->status);
+	if (status & STAT_BUSY) {
+		printk(KERN_ERR "Busy devcmd %d\n", _CMD_N(cmd));
+		return -EBUSY;
+	}
+
+	if (_CMD_DIR(cmd) & _CMD_DIR_WRITE) {
+		writeq(*a0, &devcmd->args[0]);
+		writeq(*a1, &devcmd->args[1]);
+		wmb();
+	}
+
+	iowrite32(cmd, &devcmd->cmd);
+
+	if ((_CMD_FLAGS(cmd) & _CMD_FLAGS_NOWAIT))
+			return 0;
+
+	for (delay = 0; delay < wait; delay++) {
+
+		udelay(100);
+
+		status = ioread32(&devcmd->status);
+		if (!(status & STAT_BUSY)) {
+
+			if (status & STAT_ERROR) {
+				err = dev_cmd_err[(int)readq(&devcmd->args[0])];
+				printk(KERN_ERR "Error %d devcmd %d\n",
+					err, _CMD_N(cmd));
+				return -err;
+			}
+
+			if (_CMD_DIR(cmd) & _CMD_DIR_READ) {
+				rmb();
+				*a0 = readq(&devcmd->args[0]);
+				*a1 = readq(&devcmd->args[1]);
+			}
+
+			return 0;
+		}
+	}
+
+	printk(KERN_ERR "Timedout devcmd %d\n", _CMD_N(cmd));
+	return -ETIMEDOUT;
+}
+
+int vnic_dev_fw_info(struct vnic_dev *vdev,
+	struct vnic_devcmd_fw_info **fw_info)
+{
+	u64 a0, a1 = 0;
+	int wait = 1000;
+	int err = 0;
+
+	if (!vdev->fw_info) {
+		vdev->fw_info = pci_alloc_consistent(vdev->pdev,
+			sizeof(struct vnic_devcmd_fw_info),
+			&vdev->fw_info_pa);
+		if (!vdev->fw_info)
+			return -ENOMEM;
+
+		a0 = vdev->fw_info_pa;
+
+		/* only get fw_info once and cache it */
+		err = vnic_dev_cmd(vdev, CMD_MCPU_FW_INFO, &a0, &a1, wait);
+	}
+
+	*fw_info = vdev->fw_info;
+
+	return err;
+}
+
+int vnic_dev_spec(struct vnic_dev *vdev, unsigned int offset, unsigned int size,
+	void *value)
+{
+	u64 a0, a1;
+	int wait = 1000;
+	int err;
+
+	a0 = offset;
+	a1 = size;
+
+	err = vnic_dev_cmd(vdev, CMD_DEV_SPEC, &a0, &a1, wait);
+
+	switch (size) {
+	case 1: *(u8 *)value = (u8)a0; break;
+	case 2: *(u16 *)value = (u16)a0; break;
+	case 4: *(u32 *)value = (u32)a0; break;
+	case 8: *(u64 *)value = a0; break;
+	default: BUG(); break;
+	}
+
+	return err;
+}
+
+int vnic_dev_stats_clear(struct vnic_dev *vdev)
+{
+	u64 a0 = 0, a1 = 0;
+	int wait = 1000;
+	return vnic_dev_cmd(vdev, CMD_STATS_CLEAR, &a0, &a1, wait);
+}
+
+int vnic_dev_stats_dump(struct vnic_dev *vdev, struct vnic_stats **stats)
+{
+	u64 a0, a1;
+	int wait = 1000;
+
+	if (!vdev->stats) {
+		vdev->stats = pci_alloc_consistent(vdev->pdev,
+			sizeof(struct vnic_stats), &vdev->stats_pa);
+		if (!vdev->stats)
+			return -ENOMEM;
+	}
+
+	*stats = vdev->stats;
+	a0 = vdev->stats_pa;
+	a1 = sizeof(struct vnic_stats);
+
+	return vnic_dev_cmd(vdev, CMD_STATS_DUMP, &a0, &a1, wait);
+}
+
+int vnic_dev_close(struct vnic_dev *vdev)
+{
+	u64 a0 = 0, a1 = 0;
+	int wait = 1000;
+	return vnic_dev_cmd(vdev, CMD_CLOSE, &a0, &a1, wait);
+}
+
+int vnic_dev_enable(struct vnic_dev *vdev)
+{
+	u64 a0 = 0, a1 = 0;
+	int wait = 1000;
+	return vnic_dev_cmd(vdev, CMD_ENABLE, &a0, &a1, wait);
+}
+
+int vnic_dev_disable(struct vnic_dev *vdev)
+{
+	u64 a0 = 0, a1 = 0;
+	int wait = 1000;
+	return vnic_dev_cmd(vdev, CMD_DISABLE, &a0, &a1, wait);
+}
+
+int vnic_dev_open(struct vnic_dev *vdev, int arg)
+{
+	u64 a0 = (u32)arg, a1 = 0;
+	int wait = 1000;
+	return vnic_dev_cmd(vdev, CMD_OPEN, &a0, &a1, wait);
+}
+
+int vnic_dev_open_done(struct vnic_dev *vdev, int *done)
+{
+	u64 a0 = 0, a1 = 0;
+	int wait = 1000;
+	int err;
+
+	*done = 0;
+
+	err = vnic_dev_cmd(vdev, CMD_OPEN_STATUS, &a0, &a1, wait);
+	if (err)
+		return err;
+
+	*done = (a0 == 0);
+
+	return 0;
+}
+
+int vnic_dev_soft_reset(struct vnic_dev *vdev, int arg)
+{
+	u64 a0 = (u32)arg, a1 = 0;
+	int wait = 1000;
+	return vnic_dev_cmd(vdev, CMD_SOFT_RESET, &a0, &a1, wait);
+}
+
+int vnic_dev_soft_reset_done(struct vnic_dev *vdev, int *done)
+{
+	u64 a0 = 0, a1 = 0;
+	int wait = 1000;
+	int err;
+
+	*done = 0;
+
+	err = vnic_dev_cmd(vdev, CMD_SOFT_RESET_STATUS, &a0, &a1, wait);
+	if (err)
+		return err;
+
+	*done = (a0 == 0);
+
+	return 0;
+}
+
+int vnic_dev_hang_notify(struct vnic_dev *vdev)
+{
+	u64 a0, a1;
+	int wait = 1000;
+	return vnic_dev_cmd(vdev, CMD_HANG_NOTIFY, &a0, &a1, wait);
+}
+
+int vnic_dev_mac_addr(struct vnic_dev *vdev, u8 *mac_addr)
+{
+	u64 a0, a1;
+	int wait = 1000;
+	int err, i;
+
+	for (i = 0; i < ETH_ALEN; i++)
+		mac_addr[i] = 0;
+
+	err = vnic_dev_cmd(vdev, CMD_MAC_ADDR, &a0, &a1, wait);
+	if (err)
+		return err;
+
+	for (i = 0; i < ETH_ALEN; i++)
+		mac_addr[i] = ((u8 *)&a0)[i];
+
+	return 0;
+}
+
+void vnic_dev_packet_filter(struct vnic_dev *vdev, int directed, int multicast,
+	int broadcast, int promisc, int allmulti)
+{
+	u64 a0, a1 = 0;
+	int wait = 1000;
+	int err;
+
+	a0 = (directed ? CMD_PFILTER_DIRECTED : 0) |
+	     (multicast ? CMD_PFILTER_MULTICAST : 0) |
+	     (broadcast ? CMD_PFILTER_BROADCAST : 0) |
+	     (promisc ? CMD_PFILTER_PROMISCUOUS : 0) |
+	     (allmulti ? CMD_PFILTER_ALL_MULTICAST : 0);
+
+	err = vnic_dev_cmd(vdev, CMD_PACKET_FILTER, &a0, &a1, wait);
+	if (err)
+		printk(KERN_ERR "Can't set packet filter\n");
+}
+
+void vnic_dev_add_addr(struct vnic_dev *vdev, u8 *addr)
+{
+	u64 a0 = 0, a1 = 0;
+	int wait = 1000;
+	int err;
+	int i;
+
+	for (i = 0; i < ETH_ALEN; i++)
+		((u8 *)&a0)[i] = addr[i];
+
+	err = vnic_dev_cmd(vdev, CMD_ADDR_ADD, &a0, &a1, wait);
+	if (err)
+		printk(KERN_ERR
+			"Can't add addr [%02x:%02x:%02x:%02x:%02x:%02x], %d\n",
+			addr[0], addr[1], addr[2], addr[3], addr[4], addr[5],
+			err);
+}
+
+void vnic_dev_del_addr(struct vnic_dev *vdev, u8 *addr)
+{
+	u64 a0 = 0, a1 = 0;
+	int wait = 1000;
+	int err;
+	int i;
+
+	for (i = 0; i < ETH_ALEN; i++)
+		((u8 *)&a0)[i] = addr[i];
+
+	err = vnic_dev_cmd(vdev, CMD_ADDR_DEL, &a0, &a1, wait);
+	if (err)
+		printk(KERN_ERR
+			"Can't del addr [%02x:%02x:%02x:%02x:%02x:%02x], %d\n",
+			addr[0], addr[1], addr[2], addr[3], addr[4], addr[5],
+			err);
+}
+
+int vnic_dev_notify_set(struct vnic_dev *vdev, u16 intr)
+{
+	u64 a0, a1;
+	int wait = 1000;
+
+	if (!vdev->notify) {
+		vdev->notify = pci_alloc_consistent(vdev->pdev,
+			sizeof(struct vnic_devcmd_notify),
+			&vdev->notify_pa);
+		if (!vdev->notify)
+			return -ENOMEM;
+	}
+
+	a0 = vdev->notify_pa;
+	a1 = ((u64)intr << 32) & 0x0000ffff00000000ULL;
+	a1 += sizeof(struct vnic_devcmd_notify);
+
+	return vnic_dev_cmd(vdev, CMD_NOTIFY, &a0, &a1, wait);
+}
+
+void vnic_dev_notify_unset(struct vnic_dev *vdev)
+{
+	u64 a0, a1;
+	int wait = 1000;
+
+	a0 = 0;  /* paddr = 0 to unset notify buffer */
+	a1 = 0x0000ffff00000000ULL; /* intr num = -1 to unreg for intr */
+	a1 += sizeof(struct vnic_devcmd_notify);
+
+	vnic_dev_cmd(vdev, CMD_NOTIFY, &a0, &a1, wait);
+}
+
+static int vnic_dev_notify_ready(struct vnic_dev *vdev)
+{
+	u32 *words;
+	unsigned int nwords = sizeof(struct vnic_devcmd_notify) / 4;
+	unsigned int i;
+	u32 csum;
+
+	if (!vdev->notify)
+		return 0;
+
+	do {
+		csum = 0;
+		memcpy(&vdev->notify_copy, vdev->notify,
+			sizeof(struct vnic_devcmd_notify));
+		words = (u32 *)&vdev->notify_copy;
+		for (i = 1; i < nwords; i++)
+			csum += words[i];
+	} while (csum != words[0]);
+
+	return 1;
+}
+
+int vnic_dev_init(struct vnic_dev *vdev, int arg)
+{
+	u64 a0 = (u32)arg, a1 = 0;
+	int wait = 1000;
+	return vnic_dev_cmd(vdev, CMD_INIT, &a0, &a1, wait);
+}
+
+int vnic_dev_link_status(struct vnic_dev *vdev)
+{
+	if (vdev->linkstatus)
+		return *vdev->linkstatus;
+
+	if (!vnic_dev_notify_ready(vdev))
+		return 0;
+
+	return vdev->notify_copy.link_state;
+}
+
+u32 vnic_dev_port_speed(struct vnic_dev *vdev)
+{
+	if (!vnic_dev_notify_ready(vdev))
+		return 0;
+
+	return vdev->notify_copy.port_speed;
+}
+
+u32 vnic_dev_msg_lvl(struct vnic_dev *vdev)
+{
+	if (!vnic_dev_notify_ready(vdev))
+		return 0;
+
+	return vdev->notify_copy.msglvl;
+}
+
+u32 vnic_dev_mtu(struct vnic_dev *vdev)
+{
+	if (!vnic_dev_notify_ready(vdev))
+		return 0;
+
+	return vdev->notify_copy.mtu;
+}
+
+void vnic_dev_set_intr_mode(struct vnic_dev *vdev,
+	enum vnic_dev_intr_mode intr_mode)
+{
+	vdev->intr_mode = intr_mode;
+}
+
+enum vnic_dev_intr_mode vnic_dev_get_intr_mode(
+	struct vnic_dev *vdev)
+{
+	return vdev->intr_mode;
+}
+
+void vnic_dev_unregister(struct vnic_dev *vdev)
+{
+	if (vdev) {
+		if (vdev->notify)
+			pci_free_consistent(vdev->pdev,
+				sizeof(struct vnic_devcmd_notify),
+				vdev->notify,
+				vdev->notify_pa);
+		if (vdev->linkstatus)
+			pci_free_consistent(vdev->pdev,
+				sizeof(u32),
+				vdev->linkstatus,
+				vdev->linkstatus_pa);
+		if (vdev->stats)
+			pci_free_consistent(vdev->pdev,
+				sizeof(struct vnic_dev),
+				vdev->stats, vdev->stats_pa);
+		if (vdev->fw_info)
+			pci_free_consistent(vdev->pdev,
+				sizeof(struct vnic_devcmd_fw_info),
+				vdev->fw_info, vdev->fw_info_pa);
+		kfree(vdev);
+	}
+}
+
+struct vnic_dev *vnic_dev_register(struct vnic_dev *vdev,
+	void *priv, struct pci_dev *pdev, struct vnic_dev_bar *bar)
+{
+	if (!vdev) {
+		vdev = kzalloc(sizeof(struct vnic_dev), GFP_ATOMIC);
+		if (!vdev)
+			return NULL;
+	}
+
+	vdev->priv = priv;
+	vdev->pdev = pdev;
+
+	if (vnic_dev_discover_res(vdev, bar))
+		goto err_out;
+
+	vdev->devcmd = vnic_dev_get_res(vdev, RES_TYPE_DEVCMD, 0);
+	if (!vdev->devcmd)
+		goto err_out;
+
+	return vdev;
+
+err_out:
+	vnic_dev_unregister(vdev);
+	return NULL;
+}
+
diff --git a/drivers/net/enic/vnic_dev.h b/drivers/net/enic/vnic_dev.h
new file mode 100644
index 0000000..b9dc182
--- /dev/null
+++ b/drivers/net/enic/vnic_dev.h
@@ -0,0 +1,120 @@
+/*
+ * Copyright 2008 Cisco Systems, Inc.  All rights reserved.
+ * Copyright 2007 Nuova Systems, Inc.  All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+#ifndef _VNIC_DEV_H_
+#define _VNIC_DEV_H_
+
+#include "vnic_resource.h"
+#include "vnic_devcmd.h"
+
+#ifndef VNIC_PADDR_TARGET
+#define VNIC_PADDR_TARGET	0x0000000000000000ULL
+#endif
+
+#ifndef readq
+static inline u64 readq(void __iomem *reg)
+{
+	return (((u64)readl(reg + 0x4UL) << 32) |
+		(u64)readl(reg));
+}
+
+static inline void writeq(u64 val, void __iomem *reg)
+{
+	writel(val & 0xffffffff, reg);
+	writel(val >> 32, reg + 0x4UL);
+}
+#endif
+
+enum vnic_dev_intr_mode {
+	VNIC_DEV_INTR_MODE_UNKNOWN,
+	VNIC_DEV_INTR_MODE_INTX,
+	VNIC_DEV_INTR_MODE_MSI,
+	VNIC_DEV_INTR_MODE_MSIX,
+};
+
+struct vnic_dev_bar {
+	void __iomem *vaddr;
+	dma_addr_t bus_addr;
+	unsigned long len;
+};
+
+struct vnic_dev_ring {
+	void *descs;
+	size_t size;
+	dma_addr_t base_addr;
+	size_t base_align;
+	void *descs_unaligned;
+	size_t size_unaligned;
+	dma_addr_t base_addr_unaligned;
+	unsigned int desc_size;
+	unsigned int desc_count;
+	unsigned int desc_avail;
+};
+
+struct vnic_dev;
+struct vnic_stats;
+
+void *vnic_dev_priv(struct vnic_dev *vdev);
+unsigned int vnic_dev_get_res_count(struct vnic_dev *vdev,
+	enum vnic_res_type type);
+void __iomem *vnic_dev_get_res(struct vnic_dev *vdev, enum vnic_res_type type,
+	unsigned int index);
+unsigned int vnic_dev_desc_ring_size(struct vnic_dev_ring *ring,
+	unsigned int desc_count, unsigned int desc_size);
+void vnic_dev_clear_desc_ring(struct vnic_dev_ring *ring);
+int vnic_dev_alloc_desc_ring(struct vnic_dev *vdev, struct vnic_dev_ring *ring,
+	unsigned int desc_count, unsigned int desc_size);
+void vnic_dev_free_desc_ring(struct vnic_dev *vdev,
+	struct vnic_dev_ring *ring);
+int vnic_dev_cmd(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd,
+	u64 *a0, u64 *a1, int wait);
+int vnic_dev_fw_info(struct vnic_dev *vdev,
+	struct vnic_devcmd_fw_info **fw_info);
+int vnic_dev_spec(struct vnic_dev *vdev, unsigned int offset, unsigned int size,
+	void *value);
+int vnic_dev_stats_clear(struct vnic_dev *vdev);
+int vnic_dev_stats_dump(struct vnic_dev *vdev, struct vnic_stats **stats);
+int vnic_dev_hang_notify(struct vnic_dev *vdev);
+void vnic_dev_packet_filter(struct vnic_dev *vdev, int directed, int multicast,
+	int broadcast, int promisc, int allmulti);
+void vnic_dev_add_addr(struct vnic_dev *vdev, u8 *addr);
+void vnic_dev_del_addr(struct vnic_dev *vdev, u8 *addr);
+int vnic_dev_mac_addr(struct vnic_dev *vdev, u8 *mac_addr);
+int vnic_dev_notify_set(struct vnic_dev *vdev, u16 intr);
+void vnic_dev_notify_unset(struct vnic_dev *vdev);
+int vnic_dev_link_status(struct vnic_dev *vdev);
+u32 vnic_dev_port_speed(struct vnic_dev *vdev);
+u32 vnic_dev_msg_lvl(struct vnic_dev *vdev);
+u32 vnic_dev_mtu(struct vnic_dev *vdev);
+int vnic_dev_close(struct vnic_dev *vdev);
+int vnic_dev_enable(struct vnic_dev *vdev);
+int vnic_dev_disable(struct vnic_dev *vdev);
+int vnic_dev_open(struct vnic_dev *vdev, int arg);
+int vnic_dev_open_done(struct vnic_dev *vdev, int *done);
+int vnic_dev_init(struct vnic_dev *vdev, int arg);
+int vnic_dev_soft_reset(struct vnic_dev *vdev, int arg);
+int vnic_dev_soft_reset_done(struct vnic_dev *vdev, int *done);
+void vnic_dev_set_intr_mode(struct vnic_dev *vdev,
+	enum vnic_dev_intr_mode intr_mode);
+enum vnic_dev_intr_mode vnic_dev_get_intr_mode(struct vnic_dev *vdev);
+void vnic_dev_unregister(struct vnic_dev *vdev);
+struct vnic_dev *vnic_dev_register(struct vnic_dev *vdev,
+	void *priv, struct pci_dev *pdev, struct vnic_dev_bar *bar);
+
+#endif /* _VNIC_DEV_H_ */
diff --git a/drivers/net/enic/vnic_devcmd.h b/drivers/net/enic/vnic_devcmd.h
new file mode 100644
index 0000000..d8617a3
--- /dev/null
+++ b/drivers/net/enic/vnic_devcmd.h
@@ -0,0 +1,282 @@
+/*
+ * Copyright 2008 Cisco Systems, Inc.  All rights reserved.
+ * Copyright 2007 Nuova Systems, Inc.  All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+#ifndef _VNIC_DEVCMD_H_
+#define _VNIC_DEVCMD_H_
+
+#define _CMD_NBITS      14
+#define _CMD_VTYPEBITS	10
+#define _CMD_FLAGSBITS  6
+#define _CMD_DIRBITS	2
+
+#define _CMD_NMASK      ((1 << _CMD_NBITS)-1)
+#define _CMD_VTYPEMASK  ((1 << _CMD_VTYPEBITS)-1)
+#define _CMD_FLAGSMASK  ((1 << _CMD_FLAGSBITS)-1)
+#define _CMD_DIRMASK    ((1 << _CMD_DIRBITS)-1)
+
+#define _CMD_NSHIFT     0
+#define _CMD_VTYPESHIFT (_CMD_NSHIFT+_CMD_NBITS)
+#define _CMD_FLAGSSHIFT (_CMD_VTYPESHIFT+_CMD_VTYPEBITS)
+#define _CMD_DIRSHIFT   (_CMD_FLAGSSHIFT+_CMD_FLAGSBITS)
+
+/*
+ * Direction bits (from host perspective).
+ */
+#define _CMD_DIR_NONE   0U
+#define _CMD_DIR_WRITE  1U
+#define _CMD_DIR_READ   2U
+#define _CMD_DIR_RW     (_CMD_DIR_WRITE | _CMD_DIR_READ)
+
+/*
+ * Flag bits.
+ */
+#define _CMD_FLAGS_NONE 0U
+#define _CMD_FLAGS_NOWAIT 1U
+
+/*
+ * vNIC type bits.
+ */
+#define _CMD_VTYPE_NONE  0U
+#define _CMD_VTYPE_ENET  1U
+#define _CMD_VTYPE_FC    2U
+#define _CMD_VTYPE_SCSI  4U
+#define _CMD_VTYPE_ALL   (_CMD_VTYPE_ENET | _CMD_VTYPE_FC | _CMD_VTYPE_SCSI)
+
+/*
+ * Used to create cmds..
+*/
+#define _CMDCF(dir, flags, vtype, nr)  \
+	(((dir)   << _CMD_DIRSHIFT) | \
+	((flags) << _CMD_FLAGSSHIFT) | \
+	((vtype) << _CMD_VTYPESHIFT) | \
+	((nr)    << _CMD_NSHIFT))
+#define _CMDC(dir, vtype, nr)    _CMDCF(dir, 0, vtype, nr)
+#define _CMDCNW(dir, vtype, nr)  _CMDCF(dir, _CMD_FLAGS_NOWAIT, vtype, nr)
+
+/*
+ * Used to decode cmds..
+*/
+#define _CMD_DIR(cmd)            (((cmd) >> _CMD_DIRSHIFT) & _CMD_DIRMASK)
+#define _CMD_FLAGS(cmd)          (((cmd) >> _CMD_FLAGSSHIFT) & _CMD_FLAGSMASK)
+#define _CMD_VTYPE(cmd)          (((cmd) >> _CMD_VTYPESHIFT) & _CMD_VTYPEMASK)
+#define _CMD_N(cmd)              (((cmd) >> _CMD_NSHIFT) & _CMD_NMASK)
+
+enum vnic_devcmd_cmd {
+	CMD_NONE                = _CMDC(_CMD_DIR_NONE, _CMD_VTYPE_NONE, 0),
+
+	/* mcpu fw info in mem: (u64)a0=paddr to struct vnic_devcmd_fw_info */
+	CMD_MCPU_FW_INFO        = _CMDC(_CMD_DIR_WRITE, _CMD_VTYPE_ALL, 1),
+
+	/* dev-specific block member:
+	 *    in: (u16)a0=offset,(u8)a1=size
+	 *    out: a0=value */
+	CMD_DEV_SPEC            = _CMDC(_CMD_DIR_RW, _CMD_VTYPE_ALL, 2),
+
+	/* stats clear */
+	CMD_STATS_CLEAR         = _CMDCNW(_CMD_DIR_NONE, _CMD_VTYPE_ALL, 3),
+
+	/* stats dump in mem: (u64)a0=paddr to stats area,
+	 *                    (u16)a1=sizeof stats area */
+	CMD_STATS_DUMP          = _CMDC(_CMD_DIR_WRITE, _CMD_VTYPE_ALL, 4),
+
+	/* set Rx packet filter: (u32)a0=filters (see CMD_PFILTER_*) */
+	CMD_PACKET_FILTER	= _CMDCNW(_CMD_DIR_WRITE, _CMD_VTYPE_ENET, 7),
+
+	/* hang detection notification */
+	CMD_HANG_NOTIFY         = _CMDC(_CMD_DIR_NONE, _CMD_VTYPE_ALL, 8),
+
+	/* MAC address in (u48)a0 */
+	CMD_MAC_ADDR            = _CMDC(_CMD_DIR_READ,
+					_CMD_VTYPE_ENET | _CMD_VTYPE_FC, 9),
+
+	/* disable/enable promisc mode: (u8)a0=0/1 */
+/***** XXX DEPRECATED *****/
+	CMD_PROMISC_MODE        = _CMDCNW(_CMD_DIR_WRITE, _CMD_VTYPE_ENET, 10),
+
+	/* disable/enable all-multi mode: (u8)a0=0/1 */
+/***** XXX DEPRECATED *****/
+	CMD_ALLMULTI_MODE       = _CMDCNW(_CMD_DIR_WRITE, _CMD_VTYPE_ENET, 11),
+
+	/* add addr from (u48)a0 */
+	CMD_ADDR_ADD            = _CMDCNW(_CMD_DIR_WRITE,
+					_CMD_VTYPE_ENET | _CMD_VTYPE_FC, 12),
+
+	/* del addr from (u48)a0 */
+	CMD_ADDR_DEL            = _CMDCNW(_CMD_DIR_WRITE,
+					_CMD_VTYPE_ENET | _CMD_VTYPE_FC, 13),
+
+	/* add VLAN id in (u16)a0 */
+	CMD_VLAN_ADD            = _CMDCNW(_CMD_DIR_WRITE, _CMD_VTYPE_ENET, 14),
+
+	/* del VLAN id in (u16)a0 */
+	CMD_VLAN_DEL            = _CMDCNW(_CMD_DIR_WRITE, _CMD_VTYPE_ENET, 15),
+
+	/* nic_cfg in (u32)a0 */
+	CMD_NIC_CFG             = _CMDCNW(_CMD_DIR_WRITE, _CMD_VTYPE_ALL, 16),
+
+	/* union vnic_rss_key in mem: (u64)a0=paddr, (u16)a1=len */
+	CMD_RSS_KEY             = _CMDC(_CMD_DIR_WRITE, _CMD_VTYPE_ENET, 17),
+
+	/* union vnic_rss_cpu in mem: (u64)a0=paddr, (u16)a1=len */
+	CMD_RSS_CPU             = _CMDC(_CMD_DIR_WRITE, _CMD_VTYPE_ENET, 18),
+
+	/* initiate softreset */
+	CMD_SOFT_RESET          = _CMDCNW(_CMD_DIR_NONE, _CMD_VTYPE_ALL, 19),
+
+	/* softreset status:
+	 *    out: a0=0 reset complete, a0=1 reset in progress */
+	CMD_SOFT_RESET_STATUS   = _CMDC(_CMD_DIR_READ, _CMD_VTYPE_ALL, 20),
+
+	/* set struct vnic_devcmd_notify buffer in mem:
+	 * in:
+	 *   (u64)a0=paddr to notify (set paddr=0 to unset)
+	 *   (u32)a1 & 0x00000000ffffffff=sizeof(struct vnic_devcmd_notify)
+	 *   (u16)a1 & 0x0000ffff00000000=intr num (-1 for no intr)
+	 * out:
+	 *   (u32)a1 = effective size
+	 */
+	CMD_NOTIFY              = _CMDC(_CMD_DIR_RW, _CMD_VTYPE_ALL, 21),
+
+	/* UNDI API: (u64)a0=paddr to s_PXENV_UNDI_ struct,
+	 *           (u8)a1=PXENV_UNDI_xxx */
+	CMD_UNDI                = _CMDC(_CMD_DIR_WRITE, _CMD_VTYPE_ENET, 22),
+
+	/* initiate open sequence (u32)a0=flags (see CMD_OPENF_*) */
+	CMD_OPEN		= _CMDCNW(_CMD_DIR_WRITE, _CMD_VTYPE_ALL, 23),
+
+	/* open status:
+	 *    out: a0=0 open complete, a0=1 open in progress */
+	CMD_OPEN_STATUS		= _CMDC(_CMD_DIR_READ, _CMD_VTYPE_ALL, 24),
+
+	/* close vnic */
+	CMD_CLOSE		= _CMDC(_CMD_DIR_NONE, _CMD_VTYPE_ALL, 25),
+
+	/* initialize virtual link: (u32)a0=flags (see CMD_INITF_*) */
+	CMD_INIT		= _CMDCNW(_CMD_DIR_READ, _CMD_VTYPE_ALL, 26),
+
+	/* variant of CMD_INIT, with provisioning info
+	 *     (u64)a0=paddr of vnic_devcmd_provinfo
+	 *     (u32)a1=sizeof provision info */
+	CMD_INIT_PROV_INFO	= _CMDC(_CMD_DIR_WRITE, _CMD_VTYPE_ENET, 27),
+
+	/* enable virtual link */
+	CMD_ENABLE		= _CMDCNW(_CMD_DIR_WRITE, _CMD_VTYPE_ALL, 28),
+
+	/* disable virtual link */
+	CMD_DISABLE		= _CMDC(_CMD_DIR_NONE, _CMD_VTYPE_ALL, 29),
+
+	/* stats dump all vnics on uplink in mem: (u64)a0=paddr (u32)a1=uif */
+	CMD_STATS_DUMP_ALL	= _CMDC(_CMD_DIR_WRITE, _CMD_VTYPE_ALL, 30),
+
+	/* init status:
+	 *    out: a0=0 init complete, a0=1 init in progress
+	 *         if a0=0, a1=errno */
+	CMD_INIT_STATUS		= _CMDC(_CMD_DIR_READ, _CMD_VTYPE_ALL, 31),
+
+	/* INT13 API: (u64)a0=paddr to vnic_int13_params struct
+	 *            (u8)a1=INT13_CMD_xxx */
+	CMD_INT13               = _CMDC(_CMD_DIR_WRITE, _CMD_VTYPE_FC, 32),
+
+	/* logical uplink enable/disable: (u64)a0: 0/1=disable/enable */
+	CMD_LOGICAL_UPLINK      = _CMDCNW(_CMD_DIR_WRITE, _CMD_VTYPE_ENET, 33),
+
+	/* undo initialize of virtual link */
+	CMD_DEINIT		= _CMDCNW(_CMD_DIR_NONE, _CMD_VTYPE_ALL, 34),
+};
+
+/* flags for CMD_OPEN */
+#define CMD_OPENF_OPROM		0x1	/* open coming from option rom */
+
+/* flags for CMD_INIT */
+#define CMD_INITF_DEFAULT_MAC	0x1	/* init with default mac addr */
+
+/* flags for CMD_PACKET_FILTER */
+#define CMD_PFILTER_DIRECTED		0x01
+#define CMD_PFILTER_MULTICAST		0x02
+#define CMD_PFILTER_BROADCAST		0x04
+#define CMD_PFILTER_PROMISCUOUS		0x08
+#define CMD_PFILTER_ALL_MULTICAST	0x10
+
+enum vnic_devcmd_status {
+	STAT_NONE = 0,
+	STAT_BUSY = 1 << 0,	/* cmd in progress */
+	STAT_ERROR = 1 << 1,	/* last cmd caused error (code in a0) */
+};
+
+enum vnic_devcmd_error {
+	ERR_SUCCESS = 0,
+	ERR_EINVAL = 1,
+	ERR_EFAULT = 2,
+	ERR_EPERM = 3,
+	ERR_EBUSY = 4,
+	ERR_ECMDUNKNOWN = 5,
+	ERR_EBADSTATE = 6,
+	ERR_ENOMEM = 7,
+	ERR_ETIMEDOUT = 8,
+	ERR_ELINKDOWN = 9,
+};
+
+struct vnic_devcmd_fw_info {
+	char fw_version[32];
+	char fw_build[32];
+	char hw_version[32];
+	char hw_serial_number[32];
+};
+
+struct vnic_devcmd_notify {
+	u32 csum;		/* checksum over following words */
+
+	u32 link_state;		/* link up == 1 */
+	u32 port_speed;		/* effective port speed (rate limit) */
+	u32 mtu;		/* MTU */
+	u32 msglvl;		/* requested driver msg lvl */
+	u32 uif;		/* uplink interface */
+	u32 status;		/* status bits (see VNIC_STF_*) */
+	u32 error;		/* error code (see ERR_*) for first ERR */
+};
+#define VNIC_STF_FATAL_ERR	0x0001	/* fatal fw error */
+
+struct vnic_devcmd_provinfo {
+	u8 oui[3];
+	u8 type;
+	u8 data[0];
+};
+
+/*
+ * Writing cmd register causes STAT_BUSY to get set in status register.
+ * When cmd completes, STAT_BUSY will be cleared.
+ *
+ * If cmd completed successfully STAT_ERROR will be clear
+ * and args registers contain cmd-specific results.
+ *
+ * If cmd error, STAT_ERROR will be set and args[0] contains error code.
+ *
+ * status register is read-only.  While STAT_BUSY is set,
+ * all other register contents are read-only.
+ */
+
+/* Make sizeof(vnic_devcmd) a power-of-2 for I/O BAR. */
+#define VNIC_DEVCMD_NARGS 15
+struct vnic_devcmd {
+	u32 status;			/* RO */
+	u32 cmd;			/* RW */
+	u64 args[VNIC_DEVCMD_NARGS];	/* RW cmd args (little-endian) */
+};
+
+#endif /* _VNIC_DEVCMD_H_ */
diff --git a/drivers/net/enic/vnic_enet.h b/drivers/net/enic/vnic_enet.h
new file mode 100644
index 0000000..6332ac9
--- /dev/null
+++ b/drivers/net/enic/vnic_enet.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2008 Cisco Systems, Inc.  All rights reserved.
+ * Copyright 2007 Nuova Systems, Inc.  All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+#ifndef _VNIC_ENIC_H_
+#define _VNIC_ENIC_H_
+
+/* Device-specific region: enet configuration */
+struct vnic_enet_config {
+	u32 flags;
+	u32 wq_desc_count;
+	u32 rq_desc_count;
+	u16 mtu;
+	u16 intr_timer;
+	u8 intr_timer_type;
+	u8 intr_mode;
+	char devname[16];
+};
+
+#define VENETF_TSO		0x1	/* TSO enabled */
+#define VENETF_LRO		0x2	/* LRO enabled */
+#define VENETF_RXCSUM		0x4	/* RX csum enabled */
+#define VENETF_TXCSUM		0x8	/* TX csum enabled */
+#define VENETF_RSS		0x10	/* RSS enabled */
+#define VENETF_RSSHASH_IPV4	0x20	/* Hash on IPv4 fields */
+#define VENETF_RSSHASH_TCPIPV4	0x40	/* Hash on TCP + IPv4 fields */
+#define VENETF_RSSHASH_IPV6	0x80	/* Hash on IPv6 fields */
+#define VENETF_RSSHASH_TCPIPV6	0x100	/* Hash on TCP + IPv6 fields */
+#define VENETF_RSSHASH_IPV6_EX	0x200	/* Hash on IPv6 extended fields */
+#define VENETF_RSSHASH_TCPIPV6_EX 0x400	/* Hash on TCP + IPv6 ext. fields */
+
+#endif /* _VNIC_ENIC_H_ */
diff --git a/drivers/net/enic/vnic_intr.c b/drivers/net/enic/vnic_intr.c
new file mode 100644
index 0000000..ddc38f8
--- /dev/null
+++ b/drivers/net/enic/vnic_intr.c
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2008 Cisco Systems, Inc.  All rights reserved.
+ * Copyright 2007 Nuova Systems, Inc.  All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+
+#include "vnic_dev.h"
+#include "vnic_intr.h"
+
+void vnic_intr_free(struct vnic_intr *intr)
+{
+	intr->ctrl = NULL;
+}
+
+int vnic_intr_alloc(struct vnic_dev *vdev, struct vnic_intr *intr,
+	unsigned int index)
+{
+	intr->index = index;
+	intr->vdev = vdev;
+
+	intr->ctrl = vnic_dev_get_res(vdev, RES_TYPE_INTR_CTRL, index);
+	if (!intr->ctrl) {
+		printk(KERN_ERR "Failed to hook INTR[%d].ctrl resource\n",
+			index);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+void vnic_intr_init(struct vnic_intr *intr, unsigned int coalescing_timer,
+	unsigned int coalescing_type, unsigned int mask_on_assertion)
+{
+	iowrite32(coalescing_timer, &intr->ctrl->coalescing_timer);
+	iowrite32(coalescing_type, &intr->ctrl->coalescing_type);
+	iowrite32(mask_on_assertion, &intr->ctrl->mask_on_assertion);
+	iowrite32(0, &intr->ctrl->int_credits);
+}
+
+void vnic_intr_clean(struct vnic_intr *intr)
+{
+	iowrite32(0, &intr->ctrl->int_credits);
+}
diff --git a/drivers/net/enic/vnic_intr.h b/drivers/net/enic/vnic_intr.h
new file mode 100644
index 0000000..ccc4081
--- /dev/null
+++ b/drivers/net/enic/vnic_intr.h
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2008 Cisco Systems, Inc.  All rights reserved.
+ * Copyright 2007 Nuova Systems, Inc.  All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+#ifndef _VNIC_INTR_H_
+#define _VNIC_INTR_H_
+
+#include <linux/pci.h>
+
+#include "vnic_dev.h"
+
+#define VNIC_INTR_TIMER_MAX		0xffff
+
+#define VNIC_INTR_TIMER_TYPE_ABS	0
+#define VNIC_INTR_TIMER_TYPE_QUIET	1
+
+/* Interrupt control */
+struct vnic_intr_ctrl {
+	u32 coalescing_timer;		/* 0x00 */
+	u32 pad0;
+	u32 coalescing_value;		/* 0x08 */
+	u32 pad1;
+	u32 coalescing_type;		/* 0x10 */
+	u32 pad2;
+	u32 mask_on_assertion;		/* 0x18 */
+	u32 pad3;
+	u32 mask;			/* 0x20 */
+	u32 pad4;
+	u32 int_credits;		/* 0x28 */
+	u32 pad5;
+	u32 int_credit_return;		/* 0x30 */
+	u32 pad6;
+};
+
+struct vnic_intr {
+	unsigned int index;
+	struct vnic_dev *vdev;
+	struct vnic_intr_ctrl __iomem *ctrl;		/* memory-mapped */
+};
+
+static inline void vnic_intr_unmask(struct vnic_intr *intr)
+{
+	iowrite32(0, &intr->ctrl->mask);
+}
+
+static inline void vnic_intr_mask(struct vnic_intr *intr)
+{
+	iowrite32(1, &intr->ctrl->mask);
+}
+
+static inline void vnic_intr_return_credits(struct vnic_intr *intr,
+	unsigned int credits, int unmask, int reset_timer)
+{
+#define VNIC_INTR_UNMASK_SHIFT		16
+#define VNIC_INTR_RESET_TIMER_SHIFT	17
+
+	u32 int_credit_return = (credits & 0xffff) |
+		(unmask ? (1 << VNIC_INTR_UNMASK_SHIFT) : 0) |
+		(reset_timer ? (1 << VNIC_INTR_RESET_TIMER_SHIFT) : 0);
+
+	iowrite32(int_credit_return, &intr->ctrl->int_credit_return);
+}
+
+static inline u32 vnic_intr_legacy_pba(u32 __iomem *legacy_pba)
+{
+	/* get and ack interrupt in one read (clear-and-ack-on-read) */
+	return ioread32(legacy_pba);
+}
+
+void vnic_intr_free(struct vnic_intr *intr);
+int vnic_intr_alloc(struct vnic_dev *vdev, struct vnic_intr *intr,
+	unsigned int index);
+void vnic_intr_init(struct vnic_intr *intr, unsigned int coalescing_timer,
+	unsigned int coalescing_type, unsigned int mask_on_assertion);
+void vnic_intr_clean(struct vnic_intr *intr);
+
+#endif /* _VNIC_INTR_H_ */
diff --git a/drivers/net/enic/vnic_nic.h b/drivers/net/enic/vnic_nic.h
new file mode 100644
index 0000000..dadf26f
--- /dev/null
+++ b/drivers/net/enic/vnic_nic.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2008 Cisco Systems, Inc.  All rights reserved.
+ * Copyright 2007 Nuova Systems, Inc.  All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+#ifndef _VNIC_NIC_H_
+#define _VNIC_NIC_H_
+
+#define NIC_CFG_RSS_DEFAULT_CPU_MASK_FIELD	0xffUL
+#define NIC_CFG_RSS_DEFAULT_CPU_SHIFT		0
+#define NIC_CFG_RSS_HASH_TYPE			(0xffUL << 8)
+#define NIC_CFG_RSS_HASH_TYPE_MASK_FIELD	0xffUL
+#define NIC_CFG_RSS_HASH_TYPE_SHIFT		8
+#define NIC_CFG_RSS_HASH_BITS			(7UL << 16)
+#define NIC_CFG_RSS_HASH_BITS_MASK_FIELD	7UL
+#define NIC_CFG_RSS_HASH_BITS_SHIFT		16
+#define NIC_CFG_RSS_BASE_CPU			(7UL << 19)
+#define NIC_CFG_RSS_BASE_CPU_MASK_FIELD		7UL
+#define NIC_CFG_RSS_BASE_CPU_SHIFT		19
+#define NIC_CFG_RSS_ENABLE			(1UL << 22)
+#define NIC_CFG_RSS_ENABLE_MASK_FIELD		1UL
+#define NIC_CFG_RSS_ENABLE_SHIFT		22
+#define NIC_CFG_TSO_IPID_SPLIT_EN		(1UL << 23)
+#define NIC_CFG_TSO_IPID_SPLIT_EN_MASK_FIELD	1UL
+#define NIC_CFG_TSO_IPID_SPLIT_EN_SHIFT		23
+#define NIC_CFG_IG_VLAN_STRIP_EN		(1UL << 24)
+#define NIC_CFG_IG_VLAN_STRIP_EN_MASK_FIELD	1UL
+#define NIC_CFG_IG_VLAN_STRIP_EN_SHIFT		24
+
+static inline void vnic_set_nic_cfg(u32 *nic_cfg,
+	u8 rss_default_cpu, u8 rss_hash_type,
+	u8 rss_hash_bits, u8 rss_base_cpu,
+	u8 rss_enable, u8 tso_ipid_split_en,
+	u8 ig_vlan_strip_en)
+{
+	*nic_cfg = (rss_default_cpu & NIC_CFG_RSS_DEFAULT_CPU_MASK_FIELD) |
+		((rss_hash_type & NIC_CFG_RSS_HASH_TYPE_MASK_FIELD)
+			<< NIC_CFG_RSS_HASH_TYPE_SHIFT) |
+		((rss_hash_bits & NIC_CFG_RSS_HASH_BITS_MASK_FIELD)
+			<< NIC_CFG_RSS_HASH_BITS_SHIFT) |
+		((rss_base_cpu & NIC_CFG_RSS_BASE_CPU_MASK_FIELD)
+			<< NIC_CFG_RSS_BASE_CPU_SHIFT) |
+		((rss_enable & NIC_CFG_RSS_ENABLE_MASK_FIELD)
+			<< NIC_CFG_RSS_ENABLE_SHIFT) |
+		((tso_ipid_split_en & NIC_CFG_TSO_IPID_SPLIT_EN_MASK_FIELD)
+			<< NIC_CFG_TSO_IPID_SPLIT_EN_SHIFT) |
+		((ig_vlan_strip_en & NIC_CFG_IG_VLAN_STRIP_EN_MASK_FIELD)
+			<< NIC_CFG_IG_VLAN_STRIP_EN_SHIFT);
+}
+
+#endif /* _VNIC_NIC_H_ */
diff --git a/drivers/net/enic/vnic_resource.h b/drivers/net/enic/vnic_resource.h
new file mode 100644
index 0000000..144d281
--- /dev/null
+++ b/drivers/net/enic/vnic_resource.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2008 Cisco Systems, Inc.  All rights reserved.
+ * Copyright 2007 Nuova Systems, Inc.  All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+#ifndef _VNIC_RESOURCE_H_
+#define _VNIC_RESOURCE_H_
+
+#define VNIC_RES_MAGIC		0x766E6963L	/* 'vnic' */
+#define VNIC_RES_VERSION	0x00000000L
+
+/* vNIC resource types */
+enum vnic_res_type {
+	RES_TYPE_EOL,			/* End-of-list */
+	RES_TYPE_WQ,			/* Work queues */
+	RES_TYPE_RQ,			/* Receive queues */
+	RES_TYPE_CQ,			/* Completion queues */
+	RES_TYPE_RSVD1,
+	RES_TYPE_NIC_CFG,		/* Enet NIC config registers */
+	RES_TYPE_RSVD2,
+	RES_TYPE_RSVD3,
+	RES_TYPE_RSVD4,
+	RES_TYPE_RSVD5,
+	RES_TYPE_INTR_CTRL,		/* Interrupt ctrl table */
+	RES_TYPE_INTR_TABLE,		/* MSI/MSI-X Interrupt table */
+	RES_TYPE_INTR_PBA,		/* MSI/MSI-X PBA table */
+	RES_TYPE_INTR_PBA_LEGACY,	/* Legacy intr status, r2c */
+	RES_TYPE_RSVD6,
+	RES_TYPE_RSVD7,
+	RES_TYPE_DEVCMD,		/* Device command region */
+	RES_TYPE_PASS_THRU_PAGE,	/* Pass-thru page */
+
+	RES_TYPE_MAX,			/* Count of resource types */
+};
+
+struct vnic_resource_header {
+	u32 magic;
+	u32 version;
+};
+
+struct vnic_resource {
+	u8 type;
+	u8 bar;
+	u8 pad[2];
+	u32 bar_offset;
+	u32 count;
+};
+
+#endif /* _VNIC_RESOURCE_H_ */
diff --git a/drivers/net/enic/vnic_rq.c b/drivers/net/enic/vnic_rq.c
new file mode 100644
index 0000000..9365e63
--- /dev/null
+++ b/drivers/net/enic/vnic_rq.c
@@ -0,0 +1,199 @@
+/*
+ * Copyright 2008 Cisco Systems, Inc.  All rights reserved.
+ * Copyright 2007 Nuova Systems, Inc.  All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+
+#include "vnic_dev.h"
+#include "vnic_rq.h"
+
+static int vnic_rq_alloc_bufs(struct vnic_rq *rq)
+{
+	struct vnic_rq_buf *buf;
+	struct vnic_dev *vdev;
+	unsigned int i, j, count = rq->ring.desc_count;
+	unsigned int blks = VNIC_RQ_BUF_BLKS_NEEDED(count);
+
+	vdev = rq->vdev;
+
+	for (i = 0; i < blks; i++) {
+		rq->bufs[i] = kzalloc(VNIC_RQ_BUF_BLK_SZ, GFP_ATOMIC);
+		if (!rq->bufs[i]) {
+			printk(KERN_ERR "Failed to alloc rq_bufs\n");
+			return -ENOMEM;
+		}
+	}
+
+	for (i = 0; i < blks; i++) {
+		buf = rq->bufs[i];
+		for (j = 0; j < VNIC_RQ_BUF_BLK_ENTRIES; j++) {
+			buf->index = i * VNIC_RQ_BUF_BLK_ENTRIES + j;
+			buf->desc = (u8 *)rq->ring.descs +
+				rq->ring.desc_size * buf->index;
+			if (buf->index + 1 == count) {
+				buf->next = rq->bufs[0];
+				break;
+			} else if (j + 1 == VNIC_RQ_BUF_BLK_ENTRIES) {
+				buf->next = rq->bufs[i + 1];
+			} else {
+				buf->next = buf + 1;
+				buf++;
+			}
+		}
+	}
+
+	rq->to_use = rq->to_clean = rq->bufs[0];
+	rq->buf_index = 0;
+
+	return 0;
+}
+
+void vnic_rq_free(struct vnic_rq *rq)
+{
+	struct vnic_dev *vdev;
+	unsigned int i;
+
+	vdev = rq->vdev;
+
+	vnic_dev_free_desc_ring(vdev, &rq->ring);
+
+	for (i = 0; i < VNIC_RQ_BUF_BLKS_MAX; i++) {
+		kfree(rq->bufs[i]);
+		rq->bufs[i] = NULL;
+	}
+
+	rq->ctrl = NULL;
+}
+
+int vnic_rq_alloc(struct vnic_dev *vdev, struct vnic_rq *rq, unsigned int index,
+	unsigned int desc_count, unsigned int desc_size)
+{
+	int err;
+
+	rq->index = index;
+	rq->vdev = vdev;
+
+	rq->ctrl = vnic_dev_get_res(vdev, RES_TYPE_RQ, index);
+	if (!rq->ctrl) {
+		printk(KERN_ERR "Failed to hook RQ[%d] resource\n", index);
+		return -EINVAL;
+	}
+
+	vnic_rq_disable(rq);
+
+	err = vnic_dev_alloc_desc_ring(vdev, &rq->ring, desc_count, desc_size);
+	if (err)
+		return err;
+
+	err = vnic_rq_alloc_bufs(rq);
+	if (err) {
+		vnic_rq_free(rq);
+		return err;
+	}
+
+	return 0;
+}
+
+void vnic_rq_init(struct vnic_rq *rq, unsigned int cq_index,
+	unsigned int error_interrupt_enable,
+	unsigned int error_interrupt_offset)
+{
+	u64 paddr;
+	u32 fetch_index;
+
+	paddr = (u64)rq->ring.base_addr | VNIC_PADDR_TARGET;
+	writeq(paddr, &rq->ctrl->ring_base);
+	iowrite32(rq->ring.desc_count, &rq->ctrl->ring_size);
+	iowrite32(cq_index, &rq->ctrl->cq_index);
+	iowrite32(error_interrupt_enable, &rq->ctrl->error_interrupt_enable);
+	iowrite32(error_interrupt_offset, &rq->ctrl->error_interrupt_offset);
+	iowrite32(0, &rq->ctrl->dropped_packet_count);
+	iowrite32(0, &rq->ctrl->error_status);
+
+	/* Use current fetch_index as the ring starting point */
+	fetch_index = ioread32(&rq->ctrl->fetch_index);
+	rq->to_use = rq->to_clean =
+		&rq->bufs[fetch_index / VNIC_RQ_BUF_BLK_ENTRIES]
+			[fetch_index % VNIC_RQ_BUF_BLK_ENTRIES];
+	iowrite32(fetch_index, &rq->ctrl->posted_index);
+
+	rq->buf_index = 0;
+}
+
+unsigned int vnic_rq_error_status(struct vnic_rq *rq)
+{
+	return ioread32(&rq->ctrl->error_status);
+}
+
+void vnic_rq_enable(struct vnic_rq *rq)
+{
+	iowrite32(1, &rq->ctrl->enable);
+}
+
+int vnic_rq_disable(struct vnic_rq *rq)
+{
+	unsigned int wait;
+
+	iowrite32(0, &rq->ctrl->enable);
+
+	/* Wait for HW to ACK disable request */
+	for (wait = 0; wait < 100; wait++) {
+		if (!(ioread32(&rq->ctrl->running)))
+			return 0;
+		udelay(1);
+	}
+
+	printk(KERN_ERR "Failed to disable RQ[%d]\n", rq->index);
+
+	return -ETIMEDOUT;
+}
+
+void vnic_rq_clean(struct vnic_rq *rq,
+	void (*buf_clean)(struct vnic_rq *rq, struct vnic_rq_buf *buf))
+{
+	struct vnic_rq_buf *buf;
+	u32 fetch_index;
+
+	BUG_ON(ioread32(&rq->ctrl->enable));
+
+	buf = rq->to_clean;
+
+	while (vnic_rq_desc_used(rq) > 0) {
+
+		(*buf_clean)(rq, buf);
+
+		buf = rq->to_clean = buf->next;
+		rq->ring.desc_avail++;
+	}
+
+	/* Use current fetch_index as the ring starting point */
+	fetch_index = ioread32(&rq->ctrl->fetch_index);
+	rq->to_use = rq->to_clean =
+		&rq->bufs[fetch_index / VNIC_RQ_BUF_BLK_ENTRIES]
+			[fetch_index % VNIC_RQ_BUF_BLK_ENTRIES];
+	iowrite32(fetch_index, &rq->ctrl->posted_index);
+
+	rq->buf_index = 0;
+
+	vnic_dev_clear_desc_ring(&rq->ring);
+}
+
diff --git a/drivers/net/enic/vnic_rq.h b/drivers/net/enic/vnic_rq.h
new file mode 100644
index 0000000..82bfca6
--- /dev/null
+++ b/drivers/net/enic/vnic_rq.h
@@ -0,0 +1,204 @@
+/*
+ * Copyright 2008 Cisco Systems, Inc.  All rights reserved.
+ * Copyright 2007 Nuova Systems, Inc.  All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+#ifndef _VNIC_RQ_H_
+#define _VNIC_RQ_H_
+
+#include <linux/pci.h>
+
+#include "vnic_dev.h"
+#include "vnic_cq.h"
+
+/* Receive queue control */
+struct vnic_rq_ctrl {
+	u64 ring_base;			/* 0x00 */
+	u32 ring_size;			/* 0x08 */
+	u32 pad0;
+	u32 posted_index;		/* 0x10 */
+	u32 pad1;
+	u32 cq_index;			/* 0x18 */
+	u32 pad2;
+	u32 enable;			/* 0x20 */
+	u32 pad3;
+	u32 running;			/* 0x28 */
+	u32 pad4;
+	u32 fetch_index;		/* 0x30 */
+	u32 pad5;
+	u32 error_interrupt_enable;	/* 0x38 */
+	u32 pad6;
+	u32 error_interrupt_offset;	/* 0x40 */
+	u32 pad7;
+	u32 error_status;		/* 0x48 */
+	u32 pad8;
+	u32 dropped_packet_count;	/* 0x50 */
+	u32 pad9;
+	u32 dropped_packet_count_rc;	/* 0x58 */
+	u32 pad10;
+};
+
+/* Break the vnic_rq_buf allocations into blocks of 64 entries */
+#define VNIC_RQ_BUF_BLK_ENTRIES 64
+#define VNIC_RQ_BUF_BLK_SZ \
+	(VNIC_RQ_BUF_BLK_ENTRIES * sizeof(struct vnic_rq_buf))
+#define VNIC_RQ_BUF_BLKS_NEEDED(entries) \
+	DIV_ROUND_UP(entries, VNIC_RQ_BUF_BLK_ENTRIES)
+#define VNIC_RQ_BUF_BLKS_MAX VNIC_RQ_BUF_BLKS_NEEDED(4096)
+
+struct vnic_rq_buf {
+	struct vnic_rq_buf *next;
+	dma_addr_t dma_addr;
+	void *os_buf;
+	unsigned int os_buf_index;
+	unsigned int len;
+	unsigned int index;
+	void *desc;
+};
+
+struct vnic_rq {
+	unsigned int index;
+	struct vnic_dev *vdev;
+	struct vnic_rq_ctrl __iomem *ctrl;              /* memory-mapped */
+	struct vnic_dev_ring ring;
+	struct vnic_rq_buf *bufs[VNIC_RQ_BUF_BLKS_MAX];
+	struct vnic_rq_buf *to_use;
+	struct vnic_rq_buf *to_clean;
+	void *os_buf_head;
+	unsigned int buf_index;
+	unsigned int pkts_outstanding;
+};
+
+static inline unsigned int vnic_rq_desc_avail(struct vnic_rq *rq)
+{
+	/* how many does SW own? */
+	return rq->ring.desc_avail;
+}
+
+static inline unsigned int vnic_rq_desc_used(struct vnic_rq *rq)
+{
+	/* how many does HW own? */
+	return rq->ring.desc_count - rq->ring.desc_avail - 1;
+}
+
+static inline void *vnic_rq_next_desc(struct vnic_rq *rq)
+{
+	return rq->to_use->desc;
+}
+
+static inline unsigned int vnic_rq_next_index(struct vnic_rq *rq)
+{
+	return rq->to_use->index;
+}
+
+static inline unsigned int vnic_rq_next_buf_index(struct vnic_rq *rq)
+{
+	return rq->buf_index++;
+}
+
+static inline void vnic_rq_post(struct vnic_rq *rq,
+	void *os_buf, unsigned int os_buf_index,
+	dma_addr_t dma_addr, unsigned int len)
+{
+	struct vnic_rq_buf *buf = rq->to_use;
+
+	buf->os_buf = os_buf;
+	buf->os_buf_index = os_buf_index;
+	buf->dma_addr = dma_addr;
+	buf->len = len;
+
+	buf = buf->next;
+	rq->to_use = buf;
+	rq->ring.desc_avail--;
+
+	/* Move the posted_index every nth descriptor
+	 */
+
+#ifndef VNIC_RQ_RETURN_RATE
+#define VNIC_RQ_RETURN_RATE		0xf	/* keep 2^n - 1 */
+#endif
+
+	if ((buf->index & VNIC_RQ_RETURN_RATE) == 0)
+		iowrite32(buf->index, &rq->ctrl->posted_index);
+}
+
+static inline void vnic_rq_return_descs(struct vnic_rq *rq, unsigned int count)
+{
+	rq->ring.desc_avail += count;
+}
+
+enum desc_return_options {
+	VNIC_RQ_RETURN_DESC,
+	VNIC_RQ_DEFER_RETURN_DESC,
+};
+
+static inline void vnic_rq_service(struct vnic_rq *rq,
+	struct cq_desc *cq_desc, u16 completed_index,
+	int desc_return, void (*buf_service)(struct vnic_rq *rq,
+	struct cq_desc *cq_desc, struct vnic_rq_buf *buf,
+	int skipped, void *opaque), void *opaque)
+{
+	struct vnic_rq_buf *buf;
+	int skipped;
+
+	buf = rq->to_clean;
+	while (1) {
+
+		skipped = (buf->index != completed_index);
+
+		(*buf_service)(rq, cq_desc, buf, skipped, opaque);
+
+		if (desc_return == VNIC_RQ_RETURN_DESC)
+			rq->ring.desc_avail++;
+
+		rq->to_clean = buf->next;
+
+		if (!skipped)
+			break;
+
+		buf = rq->to_clean;
+	}
+}
+
+static inline int vnic_rq_fill(struct vnic_rq *rq,
+	int (*buf_fill)(struct vnic_rq *rq))
+{
+	int err;
+
+	while (vnic_rq_desc_avail(rq) > 1) {
+
+		err = (*buf_fill)(rq);
+		if (err)
+			return err;
+	}
+
+	return 0;
+}
+
+void vnic_rq_free(struct vnic_rq *rq);
+int vnic_rq_alloc(struct vnic_dev *vdev, struct vnic_rq *rq, unsigned int index,
+	unsigned int desc_count, unsigned int desc_size);
+void vnic_rq_init(struct vnic_rq *rq, unsigned int cq_index,
+	unsigned int error_interrupt_enable,
+	unsigned int error_interrupt_offset);
+unsigned int vnic_rq_error_status(struct vnic_rq *rq);
+void vnic_rq_enable(struct vnic_rq *rq);
+int vnic_rq_disable(struct vnic_rq *rq);
+void vnic_rq_clean(struct vnic_rq *rq,
+	void (*buf_clean)(struct vnic_rq *rq, struct vnic_rq_buf *buf));
+
+#endif /* _VNIC_RQ_H_ */
diff --git a/drivers/net/enic/vnic_rss.h b/drivers/net/enic/vnic_rss.h
new file mode 100644
index 0000000..e325d65
--- /dev/null
+++ b/drivers/net/enic/vnic_rss.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2008 Cisco Systems, Inc.  All rights reserved.
+ * Copyright 2007 Nuova Systems, Inc.  All rights reserved.
+ */
+
+#ifndef _VNIC_RSS_H_
+#define _VNIC_RSS_H_
+
+/* RSS key array */
+union vnic_rss_key {
+	struct {
+		u8 b[10];
+		u8 b_pad[6];
+	} key[4];
+	u64 raw[8];
+};
+
+/* RSS cpu array */
+union vnic_rss_cpu {
+	struct {
+		u8 b[4] ;
+		u8 b_pad[4];
+	} cpu[32];
+	u64 raw[32];
+};
+
+void vnic_set_rss_key(union vnic_rss_key *rss_key, u8 *key);
+void vnic_set_rss_cpu(union vnic_rss_cpu *rss_cpu, u8 *cpu);
+void vnic_get_rss_key(union vnic_rss_key *rss_key, u8 *key);
+void vnic_get_rss_cpu(union vnic_rss_cpu *rss_cpu, u8 *cpu);
+
+#endif /* _VNIC_RSS_H_ */
diff --git a/drivers/net/enic/vnic_stats.h b/drivers/net/enic/vnic_stats.h
new file mode 100644
index 0000000..9ff9614
--- /dev/null
+++ b/drivers/net/enic/vnic_stats.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2008 Cisco Systems, Inc.  All rights reserved.
+ * Copyright 2007 Nuova Systems, Inc.  All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+#ifndef _VNIC_STATS_H_
+#define _VNIC_STATS_H_
+
+/* Tx statistics */
+struct vnic_tx_stats {
+	u64 tx_frames_ok;
+	u64 tx_unicast_frames_ok;
+	u64 tx_multicast_frames_ok;
+	u64 tx_broadcast_frames_ok;
+	u64 tx_bytes_ok;
+	u64 tx_unicast_bytes_ok;
+	u64 tx_multicast_bytes_ok;
+	u64 tx_broadcast_bytes_ok;
+	u64 tx_drops;
+	u64 tx_errors;
+	u64 tx_tso;
+	u64 rsvd[16];
+};
+
+/* Rx statistics */
+struct vnic_rx_stats {
+	u64 rx_frames_ok;
+	u64 rx_frames_total;
+	u64 rx_unicast_frames_ok;
+	u64 rx_multicast_frames_ok;
+	u64 rx_broadcast_frames_ok;
+	u64 rx_bytes_ok;
+	u64 rx_unicast_bytes_ok;
+	u64 rx_multicast_bytes_ok;
+	u64 rx_broadcast_bytes_ok;
+	u64 rx_drop;
+	u64 rx_no_bufs;
+	u64 rx_errors;
+	u64 rx_rss;
+	u64 rx_crc_errors;
+	u64 rx_frames_64;
+	u64 rx_frames_127;
+	u64 rx_frames_255;
+	u64 rx_frames_511;
+	u64 rx_frames_1023;
+	u64 rx_frames_1518;
+	u64 rx_frames_to_max;
+	u64 rsvd[16];
+};
+
+struct vnic_stats {
+	struct vnic_tx_stats tx;
+	struct vnic_rx_stats rx;
+};
+
+#endif /* _VNIC_STATS_H_ */
diff --git a/drivers/net/enic/vnic_wq.c b/drivers/net/enic/vnic_wq.c
new file mode 100644
index 0000000..a576d04
--- /dev/null
+++ b/drivers/net/enic/vnic_wq.c
@@ -0,0 +1,184 @@
+/*
+ * Copyright 2008 Cisco Systems, Inc.  All rights reserved.
+ * Copyright 2007 Nuova Systems, Inc.  All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+
+#include "vnic_dev.h"
+#include "vnic_wq.h"
+
+static int vnic_wq_alloc_bufs(struct vnic_wq *wq)
+{
+	struct vnic_wq_buf *buf;
+	struct vnic_dev *vdev;
+	unsigned int i, j, count = wq->ring.desc_count;
+	unsigned int blks = VNIC_WQ_BUF_BLKS_NEEDED(count);
+
+	vdev = wq->vdev;
+
+	for (i = 0; i < blks; i++) {
+		wq->bufs[i] = kzalloc(VNIC_WQ_BUF_BLK_SZ, GFP_ATOMIC);
+		if (!wq->bufs[i]) {
+			printk(KERN_ERR "Failed to alloc wq_bufs\n");
+			return -ENOMEM;
+		}
+	}
+
+	for (i = 0; i < blks; i++) {
+		buf = wq->bufs[i];
+		for (j = 0; j < VNIC_WQ_BUF_BLK_ENTRIES; j++) {
+			buf->index = i * VNIC_WQ_BUF_BLK_ENTRIES + j;
+			buf->desc = (u8 *)wq->ring.descs +
+				wq->ring.desc_size * buf->index;
+			if (buf->index + 1 == count) {
+				buf->next = wq->bufs[0];
+				break;
+			} else if (j + 1 == VNIC_WQ_BUF_BLK_ENTRIES) {
+				buf->next = wq->bufs[i + 1];
+			} else {
+				buf->next = buf + 1;
+				buf++;
+			}
+		}
+	}
+
+	wq->to_use = wq->to_clean = wq->bufs[0];
+
+	return 0;
+}
+
+void vnic_wq_free(struct vnic_wq *wq)
+{
+	struct vnic_dev *vdev;
+	unsigned int i;
+
+	vdev = wq->vdev;
+
+	vnic_dev_free_desc_ring(vdev, &wq->ring);
+
+	for (i = 0; i < VNIC_WQ_BUF_BLKS_MAX; i++) {
+		kfree(wq->bufs[i]);
+		wq->bufs[i] = NULL;
+	}
+
+	wq->ctrl = NULL;
+}
+
+int vnic_wq_alloc(struct vnic_dev *vdev, struct vnic_wq *wq, unsigned int index,
+	unsigned int desc_count, unsigned int desc_size)
+{
+	int err;
+
+	wq->index = index;
+	wq->vdev = vdev;
+
+	wq->ctrl = vnic_dev_get_res(vdev, RES_TYPE_WQ, index);
+	if (!wq->ctrl) {
+		printk(KERN_ERR "Failed to hook WQ[%d] resource\n", index);
+		return -EINVAL;
+	}
+
+	vnic_wq_disable(wq);
+
+	err = vnic_dev_alloc_desc_ring(vdev, &wq->ring, desc_count, desc_size);
+	if (err)
+		return err;
+
+	err = vnic_wq_alloc_bufs(wq);
+	if (err) {
+		vnic_wq_free(wq);
+		return err;
+	}
+
+	return 0;
+}
+
+void vnic_wq_init(struct vnic_wq *wq, unsigned int cq_index,
+	unsigned int error_interrupt_enable,
+	unsigned int error_interrupt_offset)
+{
+	u64 paddr;
+
+	paddr = (u64)wq->ring.base_addr | VNIC_PADDR_TARGET;
+	writeq(paddr, &wq->ctrl->ring_base);
+	iowrite32(wq->ring.desc_count, &wq->ctrl->ring_size);
+	iowrite32(0, &wq->ctrl->fetch_index);
+	iowrite32(0, &wq->ctrl->posted_index);
+	iowrite32(cq_index, &wq->ctrl->cq_index);
+	iowrite32(error_interrupt_enable, &wq->ctrl->error_interrupt_enable);
+	iowrite32(error_interrupt_offset, &wq->ctrl->error_interrupt_offset);
+	iowrite32(0, &wq->ctrl->error_status);
+}
+
+unsigned int vnic_wq_error_status(struct vnic_wq *wq)
+{
+	return ioread32(&wq->ctrl->error_status);
+}
+
+void vnic_wq_enable(struct vnic_wq *wq)
+{
+	iowrite32(1, &wq->ctrl->enable);
+}
+
+int vnic_wq_disable(struct vnic_wq *wq)
+{
+	unsigned int wait;
+
+	iowrite32(0, &wq->ctrl->enable);
+
+	/* Wait for HW to ACK disable request */
+	for (wait = 0; wait < 100; wait++) {
+		if (!(ioread32(&wq->ctrl->running)))
+			return 0;
+		udelay(1);
+	}
+
+	printk(KERN_ERR "Failed to disable WQ[%d]\n", wq->index);
+
+	return -ETIMEDOUT;
+}
+
+void vnic_wq_clean(struct vnic_wq *wq,
+	void (*buf_clean)(struct vnic_wq *wq, struct vnic_wq_buf *buf))
+{
+	struct vnic_wq_buf *buf;
+
+	BUG_ON(ioread32(&wq->ctrl->enable));
+
+	buf = wq->to_clean;
+
+	while (vnic_wq_desc_used(wq) > 0) {
+
+		(*buf_clean)(wq, buf);
+
+		buf = wq->to_clean = buf->next;
+		wq->ring.desc_avail++;
+	}
+
+	wq->to_use = wq->to_clean = wq->bufs[0];
+
+	iowrite32(0, &wq->ctrl->fetch_index);
+	iowrite32(0, &wq->ctrl->posted_index);
+	iowrite32(0, &wq->ctrl->error_status);
+
+	vnic_dev_clear_desc_ring(&wq->ring);
+}
diff --git a/drivers/net/enic/vnic_wq.h b/drivers/net/enic/vnic_wq.h
new file mode 100644
index 0000000..7081828
--- /dev/null
+++ b/drivers/net/enic/vnic_wq.h
@@ -0,0 +1,154 @@
+/*
+ * Copyright 2008 Cisco Systems, Inc.  All rights reserved.
+ * Copyright 2007 Nuova Systems, Inc.  All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+#ifndef _VNIC_WQ_H_
+#define _VNIC_WQ_H_
+
+#include <linux/pci.h>
+
+#include "vnic_dev.h"
+#include "vnic_cq.h"
+
+/* Work queue control */
+struct vnic_wq_ctrl {
+	u64 ring_base;			/* 0x00 */
+	u32 ring_size;			/* 0x08 */
+	u32 pad0;
+	u32 posted_index;		/* 0x10 */
+	u32 pad1;
+	u32 cq_index;			/* 0x18 */
+	u32 pad2;
+	u32 enable;			/* 0x20 */
+	u32 pad3;
+	u32 running;			/* 0x28 */
+	u32 pad4;
+	u32 fetch_index;		/* 0x30 */
+	u32 pad5;
+	u32 dca_value;			/* 0x38 */
+	u32 pad6;
+	u32 error_interrupt_enable;	/* 0x40 */
+	u32 pad7;
+	u32 error_interrupt_offset;	/* 0x48 */
+	u32 pad8;
+	u32 error_status;		/* 0x50 */
+	u32 pad9;
+};
+
+struct vnic_wq_buf {
+	struct vnic_wq_buf *next;
+	dma_addr_t dma_addr;
+	void *os_buf;
+	unsigned int len;
+	unsigned int index;
+	int sop;
+	void *desc;
+};
+
+/* Break the vnic_wq_buf allocations into blocks of 64 entries */
+#define VNIC_WQ_BUF_BLK_ENTRIES 64
+#define VNIC_WQ_BUF_BLK_SZ \
+	(VNIC_WQ_BUF_BLK_ENTRIES * sizeof(struct vnic_wq_buf))
+#define VNIC_WQ_BUF_BLKS_NEEDED(entries) \
+	DIV_ROUND_UP(entries, VNIC_WQ_BUF_BLK_ENTRIES)
+#define VNIC_WQ_BUF_BLKS_MAX VNIC_WQ_BUF_BLKS_NEEDED(4096)
+
+struct vnic_wq {
+	unsigned int index;
+	struct vnic_dev *vdev;
+	struct vnic_wq_ctrl __iomem *ctrl;              /* memory-mapped */
+	struct vnic_dev_ring ring;
+	struct vnic_wq_buf *bufs[VNIC_WQ_BUF_BLKS_MAX];
+	struct vnic_wq_buf *to_use;
+	struct vnic_wq_buf *to_clean;
+	unsigned int pkts_outstanding;
+};
+
+static inline unsigned int vnic_wq_desc_avail(struct vnic_wq *wq)
+{
+	/* how many does SW own? */
+	return wq->ring.desc_avail;
+}
+
+static inline unsigned int vnic_wq_desc_used(struct vnic_wq *wq)
+{
+	/* how many does HW own? */
+	return wq->ring.desc_count - wq->ring.desc_avail - 1;
+}
+
+static inline void *vnic_wq_next_desc(struct vnic_wq *wq)
+{
+	return wq->to_use->desc;
+}
+
+static inline void vnic_wq_post(struct vnic_wq *wq,
+	void *os_buf, dma_addr_t dma_addr,
+	unsigned int len, int sop, int eop)
+{
+	struct vnic_wq_buf *buf = wq->to_use;
+
+	buf->sop = sop;
+	buf->os_buf = eop ? os_buf : NULL;
+	buf->dma_addr = dma_addr;
+	buf->len = len;
+
+	buf = buf->next;
+	if (eop)
+		iowrite32(buf->index, &wq->ctrl->posted_index);
+	wq->to_use = buf;
+
+	wq->ring.desc_avail--;
+}
+
+static inline void vnic_wq_service(struct vnic_wq *wq,
+	struct cq_desc *cq_desc, u16 completed_index,
+	void (*buf_service)(struct vnic_wq *wq,
+	struct cq_desc *cq_desc, struct vnic_wq_buf *buf, void *opaque),
+	void *opaque)
+{
+	struct vnic_wq_buf *buf;
+
+	buf = wq->to_clean;
+	while (1) {
+
+		(*buf_service)(wq, cq_desc, buf, opaque);
+
+		wq->ring.desc_avail++;
+
+		wq->to_clean = buf->next;
+
+		if (buf->index == completed_index)
+			break;
+
+		buf = wq->to_clean;
+	}
+}
+
+void vnic_wq_free(struct vnic_wq *wq);
+int vnic_wq_alloc(struct vnic_dev *vdev, struct vnic_wq *wq, unsigned int index,
+	unsigned int desc_count, unsigned int desc_size);
+void vnic_wq_init(struct vnic_wq *wq, unsigned int cq_index,
+	unsigned int error_interrupt_enable,
+	unsigned int error_interrupt_offset);
+unsigned int vnic_wq_error_status(struct vnic_wq *wq);
+void vnic_wq_enable(struct vnic_wq *wq);
+int vnic_wq_disable(struct vnic_wq *wq);
+void vnic_wq_clean(struct vnic_wq *wq,
+	void (*buf_clean)(struct vnic_wq *wq, struct vnic_wq_buf *buf));
+
+#endif /* _VNIC_WQ_H_ */
diff --git a/drivers/net/enic/wq_enet_desc.h b/drivers/net/enic/wq_enet_desc.h
new file mode 100644
index 0000000..483596c
--- /dev/null
+++ b/drivers/net/enic/wq_enet_desc.h
@@ -0,0 +1,98 @@
+/*
+ * Copyright 2008 Cisco Systems, Inc.  All rights reserved.
+ * Copyright 2007 Nuova Systems, Inc.  All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+#ifndef _WQ_ENET_DESC_H_
+#define _WQ_ENET_DESC_H_
+
+/* Ethernet work queue descriptor: 16B */
+struct wq_enet_desc {
+	__le64 address;
+	__le16 length;
+	__le16 mss_loopback;
+	__le16 header_length_flags;
+	__le16 vlan_tag;
+};
+
+#define WQ_ENET_ADDR_BITS		64
+#define WQ_ENET_LEN_BITS		14
+#define WQ_ENET_LEN_MASK		((1 << WQ_ENET_LEN_BITS) - 1)
+#define WQ_ENET_MSS_BITS		14
+#define WQ_ENET_MSS_MASK		((1 << WQ_ENET_MSS_BITS) - 1)
+#define WQ_ENET_MSS_SHIFT		2
+#define WQ_ENET_LOOPBACK_SHIFT		1
+#define WQ_ENET_HDRLEN_BITS		10
+#define WQ_ENET_HDRLEN_MASK		((1 << WQ_ENET_HDRLEN_BITS) - 1)
+#define WQ_ENET_FLAGS_OM_BITS		2
+#define WQ_ENET_FLAGS_OM_MASK		((1 << WQ_ENET_FLAGS_OM_BITS) - 1)
+#define WQ_ENET_FLAGS_EOP_SHIFT		12
+#define WQ_ENET_FLAGS_CQ_ENTRY_SHIFT	13
+#define WQ_ENET_FLAGS_FCOE_ENCAP_SHIFT	14
+#define WQ_ENET_FLAGS_VLAN_TAG_INSERT_SHIFT	15
+
+#define WQ_ENET_OFFLOAD_MODE_CSUM	0
+#define WQ_ENET_OFFLOAD_MODE_RESERVED	1
+#define WQ_ENET_OFFLOAD_MODE_CSUM_L4	2
+#define WQ_ENET_OFFLOAD_MODE_TSO	3
+
+static inline void wq_enet_desc_enc(struct wq_enet_desc *desc,
+	u64 address, u16 length, u16 mss, u16 header_length,
+	u8 offload_mode, u8 eop, u8 cq_entry, u8 fcoe_encap,
+	u8 vlan_tag_insert, u16 vlan_tag, u8 loopback)
+{
+	desc->address = cpu_to_le64(address);
+	desc->length = cpu_to_le16(length & WQ_ENET_LEN_MASK);
+	desc->mss_loopback = cpu_to_le16((mss & WQ_ENET_MSS_MASK) <<
+		WQ_ENET_MSS_SHIFT | (loopback & 1) << WQ_ENET_LOOPBACK_SHIFT);
+	desc->header_length_flags = cpu_to_le16(
+		(header_length & WQ_ENET_HDRLEN_MASK) |
+		(offload_mode & WQ_ENET_FLAGS_OM_MASK) << WQ_ENET_HDRLEN_BITS |
+		(eop & 1) << WQ_ENET_FLAGS_EOP_SHIFT |
+		(cq_entry & 1) << WQ_ENET_FLAGS_CQ_ENTRY_SHIFT |
+		(fcoe_encap & 1) << WQ_ENET_FLAGS_FCOE_ENCAP_SHIFT |
+		(vlan_tag_insert & 1) << WQ_ENET_FLAGS_VLAN_TAG_INSERT_SHIFT);
+	desc->vlan_tag = cpu_to_le16(vlan_tag);
+}
+
+static inline void wq_enet_desc_dec(struct wq_enet_desc *desc,
+	u64 *address, u16 *length, u16 *mss, u16 *header_length,
+	u8 *offload_mode, u8 *eop, u8 *cq_entry, u8 *fcoe_encap,
+	u8 *vlan_tag_insert, u16 *vlan_tag, u8 *loopback)
+{
+	*address = le64_to_cpu(desc->address);
+	*length = le16_to_cpu(desc->length) & WQ_ENET_LEN_MASK;
+	*mss = (le16_to_cpu(desc->mss_loopback) >> WQ_ENET_MSS_SHIFT) &
+		WQ_ENET_MSS_MASK;
+	*loopback = (u8)((le16_to_cpu(desc->mss_loopback) >>
+		WQ_ENET_LOOPBACK_SHIFT) & 1);
+	*header_length = le16_to_cpu(desc->header_length_flags) &
+		WQ_ENET_HDRLEN_MASK;
+	*offload_mode = (u8)((le16_to_cpu(desc->header_length_flags) >>
+		WQ_ENET_HDRLEN_BITS) & WQ_ENET_FLAGS_OM_MASK);
+	*eop = (u8)((le16_to_cpu(desc->header_length_flags) >>
+		WQ_ENET_FLAGS_EOP_SHIFT) & 1);
+	*cq_entry = (u8)((le16_to_cpu(desc->header_length_flags) >>
+		WQ_ENET_FLAGS_CQ_ENTRY_SHIFT) & 1);
+	*fcoe_encap = (u8)((le16_to_cpu(desc->header_length_flags) >>
+		WQ_ENET_FLAGS_FCOE_ENCAP_SHIFT) & 1);
+	*vlan_tag_insert = (u8)((le16_to_cpu(desc->header_length_flags) >>
+		WQ_ENET_FLAGS_VLAN_TAG_INSERT_SHIFT) & 1);
+	*vlan_tag = le16_to_cpu(desc->vlan_tag);
+}
+
+#endif /* _WQ_ENET_DESC_H_ */
diff --git a/drivers/net/fealnx.c b/drivers/net/fealnx.c
index 3c1364d..b455ae9 100644
--- a/drivers/net/fealnx.c
+++ b/drivers/net/fealnx.c
@@ -431,7 +431,7 @@
 static void getlinkstatus(struct net_device *dev);
 static void netdev_timer(unsigned long data);
 static void reset_timer(unsigned long data);
-static void tx_timeout(struct net_device *dev);
+static void fealnx_tx_timeout(struct net_device *dev);
 static void init_ring(struct net_device *dev);
 static int start_tx(struct sk_buff *skb, struct net_device *dev);
 static irqreturn_t intr_handler(int irq, void *dev_instance);
@@ -658,7 +658,7 @@
 	dev->set_multicast_list = &set_rx_mode;
 	dev->do_ioctl = &mii_ioctl;
 	dev->ethtool_ops = &netdev_ethtool_ops;
-	dev->tx_timeout = &tx_timeout;
+	dev->tx_timeout = &fealnx_tx_timeout;
 	dev->watchdog_timeo = TX_TIMEOUT;
 
 	err = register_netdev(dev);
@@ -1198,7 +1198,7 @@
 }
 
 
-static void tx_timeout(struct net_device *dev)
+static void fealnx_tx_timeout(struct net_device *dev)
 {
 	struct netdev_private *np = netdev_priv(dev);
 	void __iomem *ioaddr = np->mem;
diff --git a/drivers/net/fec_mpc52xx_phy.c b/drivers/net/fec_mpc52xx_phy.c
index f563444..08e18bc 100644
--- a/drivers/net/fec_mpc52xx_phy.c
+++ b/drivers/net/fec_mpc52xx_phy.c
@@ -83,7 +83,7 @@
 	int err;
 	int i;
 
-	bus = kzalloc(sizeof(*bus), GFP_KERNEL);
+	bus = mdiobus_alloc();
 	if (bus == NULL)
 		return -ENOMEM;
 	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
@@ -127,7 +127,7 @@
 	snprintf(bus->id, MII_BUS_ID_SIZE, "%x", res.start);
 	bus->priv = priv;
 
-	bus->dev = dev;
+	bus->parent = dev;
 	dev_set_drvdata(dev, bus);
 
 	/* set MII speed */
@@ -150,7 +150,7 @@
 			irq_dispose_mapping(bus->irq[i]);
 	kfree(bus->irq);
 	kfree(priv);
-	kfree(bus);
+	mdiobus_free(bus);
 
 	return err;
 }
@@ -171,7 +171,7 @@
 			irq_dispose_mapping(bus->irq[i]);
 	kfree(priv);
 	kfree(bus->irq);
-	kfree(bus);
+	mdiobus_free(bus);
 
 	return 0;
 }
diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c
index 0b6ecef..cc7328b 100644
--- a/drivers/net/forcedeth.c
+++ b/drivers/net/forcedeth.c
@@ -337,7 +337,7 @@
 	NvRegMSIXIrqStatus = 0x3f0,
 
 	NvRegPowerState2 = 0x600,
-#define NVREG_POWERSTATE2_POWERUP_MASK		0x0F11
+#define NVREG_POWERSTATE2_POWERUP_MASK		0x0F15
 #define NVREG_POWERSTATE2_POWERUP_REV_A3	0x0001
 #define NVREG_POWERSTATE2_PHY_RESET		0x0004
 };
@@ -5643,6 +5643,7 @@
 		dev->dev_addr[4] = (np->orig_mac[0] >>  8) & 0xff;
 		dev->dev_addr[5] = (np->orig_mac[0] >>  0) & 0xff;
 		writel(txreg|NVREG_TRANSMITPOLL_MAC_ADDR_REV, base + NvRegTransmitPoll);
+		printk(KERN_DEBUG "nv_probe: set workaround bit for reversed mac addr\n");
 	}
 	memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
 
@@ -5890,14 +5891,12 @@
 	}
 }
 
-static void __devexit nv_remove(struct pci_dev *pci_dev)
+static void nv_restore_mac_addr(struct pci_dev *pci_dev)
 {
 	struct net_device *dev = pci_get_drvdata(pci_dev);
 	struct fe_priv *np = netdev_priv(dev);
 	u8 __iomem *base = get_hwbase(dev);
 
-	unregister_netdev(dev);
-
 	/* special op: write back the misordered MAC address - otherwise
 	 * the next nv_probe would see a wrong address.
 	 */
@@ -5905,6 +5904,15 @@
 	writel(np->orig_mac[1], base + NvRegMacAddrB);
 	writel(readl(base + NvRegTransmitPoll) & ~NVREG_TRANSMITPOLL_MAC_ADDR_REV,
 	       base + NvRegTransmitPoll);
+}
+
+static void __devexit nv_remove(struct pci_dev *pci_dev)
+{
+	struct net_device *dev = pci_get_drvdata(pci_dev);
+
+	unregister_netdev(dev);
+
+	nv_restore_mac_addr(pci_dev);
 
 	/* restore any phy related changes */
 	nv_restore_phy(dev);
@@ -5975,6 +5983,8 @@
 	if (netif_running(dev))
 		nv_close(dev);
 
+	nv_restore_mac_addr(pdev);
+
 	pci_disable_device(pdev);
 	if (system_state == SYSTEM_POWER_OFF) {
 		if (pci_enable_wake(pdev, PCI_D3cold, np->wolenabled))
diff --git a/drivers/net/fs_enet/fs_enet-main.c b/drivers/net/fs_enet/fs_enet-main.c
index 9d46182..cb51c1fb 100644
--- a/drivers/net/fs_enet/fs_enet-main.c
+++ b/drivers/net/fs_enet/fs_enet-main.c
@@ -664,23 +664,6 @@
 	return NETDEV_TX_OK;
 }
 
-static int fs_request_irq(struct net_device *dev, int irq, const char *name,
-		irq_handler_t irqf)
-{
-	struct fs_enet_private *fep = netdev_priv(dev);
-
-	(*fep->ops->pre_request_irq)(dev, irq);
-	return request_irq(irq, irqf, IRQF_SHARED, name, dev);
-}
-
-static void fs_free_irq(struct net_device *dev, int irq)
-{
-	struct fs_enet_private *fep = netdev_priv(dev);
-
-	free_irq(irq, dev);
-	(*fep->ops->post_free_irq)(dev, irq);
-}
-
 static void fs_timeout(struct net_device *dev)
 {
 	struct fs_enet_private *fep = netdev_priv(dev);
@@ -800,7 +783,8 @@
 		napi_enable(&fep->napi);
 
 	/* Install our interrupt handler. */
-	r = fs_request_irq(dev, fep->interrupt, "fs_enet-mac", fs_enet_interrupt);
+	r = request_irq(fep->interrupt, fs_enet_interrupt, IRQF_SHARED,
+			"fs_enet-mac", dev);
 	if (r != 0) {
 		printk(KERN_ERR DRV_MODULE_NAME
 		       ": %s Could not allocate FS_ENET IRQ!", dev->name);
@@ -842,7 +826,7 @@
 	/* release any irqs */
 	phy_disconnect(fep->phydev);
 	fep->phydev = NULL;
-	fs_free_irq(dev, fep->interrupt);
+	free_irq(fep->interrupt, dev);
 
 	return 0;
 }
diff --git a/drivers/net/fs_enet/fs_enet.h b/drivers/net/fs_enet/fs_enet.h
index db46d2e..85a4bab 100644
--- a/drivers/net/fs_enet/fs_enet.h
+++ b/drivers/net/fs_enet/fs_enet.h
@@ -34,8 +34,6 @@
 	void (*adjust_link)(struct net_device *dev);
 	void (*restart)(struct net_device *dev);
 	void (*stop)(struct net_device *dev);
-	void (*pre_request_irq)(struct net_device *dev, int irq);
-	void (*post_free_irq)(struct net_device *dev, int irq);
 	void (*napi_clear_rx_event)(struct net_device *dev);
 	void (*napi_enable_rx)(struct net_device *dev);
 	void (*napi_disable_rx)(struct net_device *dev);
diff --git a/drivers/net/fs_enet/mac-fcc.c b/drivers/net/fs_enet/mac-fcc.c
index 1c7ef81..22e5a84 100644
--- a/drivers/net/fs_enet/mac-fcc.c
+++ b/drivers/net/fs_enet/mac-fcc.c
@@ -421,16 +421,6 @@
 	fs_cleanup_bds(dev);
 }
 
-static void pre_request_irq(struct net_device *dev, int irq)
-{
-	/* nothing */
-}
-
-static void post_free_irq(struct net_device *dev, int irq)
-{
-	/* nothing */
-}
-
 static void napi_clear_rx_event(struct net_device *dev)
 {
 	struct fs_enet_private *fep = netdev_priv(dev);
@@ -540,8 +530,6 @@
 	.set_multicast_list	= set_multicast_list,
 	.restart		= restart,
 	.stop			= stop,
-	.pre_request_irq	= pre_request_irq,
-	.post_free_irq		= post_free_irq,
 	.napi_clear_rx_event	= napi_clear_rx_event,
 	.napi_enable_rx		= napi_enable_rx,
 	.napi_disable_rx	= napi_disable_rx,
diff --git a/drivers/net/fs_enet/mac-fec.c b/drivers/net/fs_enet/mac-fec.c
index 0a7d1c5..14e5753 100644
--- a/drivers/net/fs_enet/mac-fec.c
+++ b/drivers/net/fs_enet/mac-fec.c
@@ -313,11 +313,7 @@
 	 * Clear any outstanding interrupt.
 	 */
 	FW(fecp, ievent, 0xffc0);
-#ifndef CONFIG_PPC_MERGE
-	FW(fecp, ivec, (fep->interrupt / 2) << 29);
-#else
 	FW(fecp, ivec, (virq_to_hw(fep->interrupt) / 2) << 29);
-#endif
 
 	/*
 	 * adjust to speed (only for DUET & RMII)
@@ -413,30 +409,6 @@
 	}
 }
 
-static void pre_request_irq(struct net_device *dev, int irq)
-{
-#ifndef CONFIG_PPC_MERGE
-	immap_t *immap = fs_enet_immap;
-	u32 siel;
-
-	/* SIU interrupt */
-	if (irq >= SIU_IRQ0 && irq < SIU_LEVEL7) {
-
-		siel = in_be32(&immap->im_siu_conf.sc_siel);
-		if ((irq & 1) == 0)
-			siel |= (0x80000000 >> irq);
-		else
-			siel &= ~(0x80000000 >> (irq & ~1));
-		out_be32(&immap->im_siu_conf.sc_siel, siel);
-	}
-#endif
-}
-
-static void post_free_irq(struct net_device *dev, int irq)
-{
-	/* nothing */
-}
-
 static void napi_clear_rx_event(struct net_device *dev)
 {
 	struct fs_enet_private *fep = netdev_priv(dev);
@@ -529,8 +501,6 @@
 	.set_multicast_list	= set_multicast_list,
 	.restart		= restart,
 	.stop			= stop,
-	.pre_request_irq	= pre_request_irq,
-	.post_free_irq		= post_free_irq,
 	.napi_clear_rx_event	= napi_clear_rx_event,
 	.napi_enable_rx		= napi_enable_rx,
 	.napi_disable_rx	= napi_disable_rx,
diff --git a/drivers/net/fs_enet/mac-scc.c b/drivers/net/fs_enet/mac-scc.c
index 22f50dd..008cdd9 100644
--- a/drivers/net/fs_enet/mac-scc.c
+++ b/drivers/net/fs_enet/mac-scc.c
@@ -377,30 +377,6 @@
 	fs_cleanup_bds(dev);
 }
 
-static void pre_request_irq(struct net_device *dev, int irq)
-{
-#ifndef CONFIG_PPC_MERGE
-	immap_t *immap = fs_enet_immap;
-	u32 siel;
-
-	/* SIU interrupt */
-	if (irq >= SIU_IRQ0 && irq < SIU_LEVEL7) {
-
-		siel = in_be32(&immap->im_siu_conf.sc_siel);
-		if ((irq & 1) == 0)
-			siel |= (0x80000000 >> irq);
-		else
-			siel &= ~(0x80000000 >> (irq & ~1));
-		out_be32(&immap->im_siu_conf.sc_siel, siel);
-	}
-#endif
-}
-
-static void post_free_irq(struct net_device *dev, int irq)
-{
-	/* nothing */
-}
-
 static void napi_clear_rx_event(struct net_device *dev)
 {
 	struct fs_enet_private *fep = netdev_priv(dev);
@@ -494,8 +470,6 @@
 	.set_multicast_list	= set_multicast_list,
 	.restart		= restart,
 	.stop			= stop,
-	.pre_request_irq	= pre_request_irq,
-	.post_free_irq		= post_free_irq,
 	.napi_clear_rx_event	= napi_clear_rx_event,
 	.napi_enable_rx		= napi_enable_rx,
 	.napi_disable_rx	= napi_disable_rx,
diff --git a/drivers/net/fs_enet/mii-bitbang.c b/drivers/net/fs_enet/mii-bitbang.c
index be4b72f..49b6645 100644
--- a/drivers/net/fs_enet/mii-bitbang.c
+++ b/drivers/net/fs_enet/mii-bitbang.c
@@ -203,7 +203,7 @@
 		if (!strcmp(np->type, "ethernet-phy"))
 			add_phy(new_bus, np);
 
-	new_bus->dev = &ofdev->dev;
+	new_bus->parent = &ofdev->dev;
 	dev_set_drvdata(&ofdev->dev, new_bus);
 
 	ret = mdiobus_register(new_bus);
@@ -218,9 +218,9 @@
 out_unmap_regs:
 	iounmap(bitbang->dir);
 out_free_bus:
-	kfree(new_bus);
-out_free_priv:
 	free_mdio_bitbang(new_bus);
+out_free_priv:
+	kfree(bitbang);
 out:
 	return ret;
 }
@@ -231,12 +231,11 @@
 	struct bb_info *bitbang = bus->priv;
 
 	mdiobus_unregister(bus);
-	free_mdio_bitbang(bus);
 	dev_set_drvdata(&ofdev->dev, NULL);
 	kfree(bus->irq);
+	free_mdio_bitbang(bus);
 	iounmap(bitbang->dir);
 	kfree(bitbang);
-	kfree(bus);
 
 	return 0;
 }
diff --git a/drivers/net/fs_enet/mii-fec.c b/drivers/net/fs_enet/mii-fec.c
index 695f74c..28077cc 100644
--- a/drivers/net/fs_enet/mii-fec.c
+++ b/drivers/net/fs_enet/mii-fec.c
@@ -128,7 +128,7 @@
 	struct fec_info *fec;
 	int ret = -ENOMEM, i;
 
-	new_bus = kzalloc(sizeof(struct mii_bus), GFP_KERNEL);
+	new_bus = mdiobus_alloc();
 	if (!new_bus)
 		goto out;
 
@@ -172,7 +172,7 @@
 		if (!strcmp(np->type, "ethernet-phy"))
 			add_phy(new_bus, np);
 
-	new_bus->dev = &ofdev->dev;
+	new_bus->parent = &ofdev->dev;
 	dev_set_drvdata(&ofdev->dev, new_bus);
 
 	ret = mdiobus_register(new_bus);
@@ -190,7 +190,7 @@
 out_fec:
 	kfree(fec);
 out_mii:
-	kfree(new_bus);
+	mdiobus_free(new_bus);
 out:
 	return ret;
 }
@@ -205,7 +205,7 @@
 	kfree(bus->irq);
 	iounmap(fec->fecp);
 	kfree(fec);
-	kfree(bus);
+	mdiobus_free(bus);
 
 	return 0;
 }
diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c
index 4320a98..b5bb7ae 100644
--- a/drivers/net/gianfar.c
+++ b/drivers/net/gianfar.c
@@ -339,6 +339,9 @@
 	/* Enable most messages by default */
 	priv->msg_enable = (NETIF_MSG_IFUP << 1 ) - 1;
 
+	/* Carrier starts down, phylib will bring it up */
+	netif_carrier_off(dev);
+
 	err = register_netdev(dev);
 
 	if (err) {
diff --git a/drivers/net/gianfar_mii.c b/drivers/net/gianfar_mii.c
index ebcfb27..bf73eea 100644
--- a/drivers/net/gianfar_mii.c
+++ b/drivers/net/gianfar_mii.c
@@ -136,12 +136,12 @@
 
 	/* Wait until the bus is free */
 	while ((gfar_read(&regs->miimind) & MIIMIND_BUSY) &&
-			timeout--)
+			--timeout)
 		cpu_relax();
 
 	mutex_unlock(&bus->mdio_lock);
 
-	if(timeout <= 0) {
+	if(timeout == 0) {
 		printk(KERN_ERR "%s: The MII Bus is stuck!\n",
 				bus->name);
 		return -EBUSY;
@@ -164,8 +164,7 @@
 	if (NULL == dev)
 		return -EINVAL;
 
-	new_bus = kzalloc(sizeof(struct mii_bus), GFP_KERNEL);
-
+	new_bus = mdiobus_alloc();
 	if (NULL == new_bus)
 		return -ENOMEM;
 
@@ -196,7 +195,7 @@
 
 	new_bus->irq = pdata->irq;
 
-	new_bus->dev = dev;
+	new_bus->parent = dev;
 	dev_set_drvdata(dev, new_bus);
 
 	/*
@@ -211,19 +210,21 @@
 	gfar_write(&enet_regs->tbipa, 0);
 	for (i = PHY_MAX_ADDR; i > 0; i--) {
 		u32 phy_id;
-		int r;
 
-		r = get_phy_id(new_bus, i, &phy_id);
-		if (r)
-			return r;
+		err = get_phy_id(new_bus, i, &phy_id);
+		if (err)
+			goto bus_register_fail;
 
 		if (phy_id == 0xffffffff)
 			break;
 	}
 
 	/* The bus is full.  We don't support using 31 PHYs, sorry */
-	if (i == 0)
-		return -EBUSY;
+	if (i == 0) {
+		err = -EBUSY;
+
+		goto bus_register_fail;
+	}
 
 	gfar_write(&enet_regs->tbipa, i);
 
@@ -240,7 +241,7 @@
 bus_register_fail:
 	iounmap(regs);
 reg_map_fail:
-	kfree(new_bus);
+	mdiobus_free(new_bus);
 
 	return err;
 }
@@ -256,7 +257,7 @@
 
 	iounmap((void __iomem *)bus->priv);
 	bus->priv = NULL;
-	kfree(bus);
+	mdiobus_free(bus);
 
 	return 0;
 }
diff --git a/drivers/net/hp-plus.c b/drivers/net/hp-plus.c
index 8239939..fbbd3e6 100644
--- a/drivers/net/hp-plus.c
+++ b/drivers/net/hp-plus.c
@@ -139,7 +139,7 @@
 #ifndef MODULE
 struct net_device * __init hp_plus_probe(int unit)
 {
-	struct net_device *dev = alloc_ei_netdev();
+	struct net_device *dev = alloc_eip_netdev();
 	int err;
 
 	if (!dev)
@@ -284,7 +284,7 @@
 	int option_reg;
 	int retval;
 
-	if ((retval = request_irq(dev->irq, ei_interrupt, 0, dev->name, dev))) {
+	if ((retval = request_irq(dev->irq, eip_interrupt, 0, dev->name, dev))) {
 	    return retval;
 	}
 
@@ -302,7 +302,7 @@
 	/* Select the operational page. */
 	outw(Perf_Page, ioaddr + HP_PAGING);
 
-	ei_open(dev);
+	eip_open(dev);
 	return 0;
 }
 
@@ -313,7 +313,7 @@
 	int option_reg = inw(ioaddr + HPP_OPTION);
 
 	free_irq(dev->irq, dev);
-	ei_close(dev);
+	eip_close(dev);
 	outw((option_reg & ~EnableIRQ) | MemDisable | NICReset | ChipReset,
 		 ioaddr + HPP_OPTION);
 
diff --git a/drivers/net/ibm_newemac/Kconfig b/drivers/net/ibm_newemac/Kconfig
index 70a3272..bcec732 100644
--- a/drivers/net/ibm_newemac/Kconfig
+++ b/drivers/net/ibm_newemac/Kconfig
@@ -1,6 +1,6 @@
 config IBM_NEW_EMAC
 	tristate "IBM EMAC Ethernet support"
-	depends on PPC_DCR && PPC_MERGE
+	depends on PPC_DCR
 	select CRC32
 	help
 	  This driver supports the IBM EMAC family of Ethernet controllers
diff --git a/drivers/net/ibm_newemac/core.c b/drivers/net/ibm_newemac/core.c
index ccd9d90..58dfd32 100644
--- a/drivers/net/ibm_newemac/core.c
+++ b/drivers/net/ibm_newemac/core.c
@@ -130,6 +130,7 @@
 					     const char *error)
 {
 	if (emac_has_feature(dev, EMAC_FTR_440GX_PHY_CLK_FIX |
+				  EMAC_FTR_460EX_PHY_CLK_FIX |
 				  EMAC_FTR_440EP_PHY_CLK_FIX))
 		DBG(dev, "%s" NL, error);
 	else if (net_ratelimit())
@@ -351,10 +352,24 @@
 		emac_tx_disable(dev);
 	}
 
+#ifdef CONFIG_PPC_DCR_NATIVE
+	/* Enable internal clock source */
+	if (emac_has_feature(dev, EMAC_FTR_460EX_PHY_CLK_FIX))
+		dcri_clrset(SDR0, SDR0_ETH_CFG,
+			    0, SDR0_ETH_CFG_ECS << dev->cell_index);
+#endif
+
 	out_be32(&p->mr0, EMAC_MR0_SRST);
 	while ((in_be32(&p->mr0) & EMAC_MR0_SRST) && n)
 		--n;
 
+#ifdef CONFIG_PPC_DCR_NATIVE
+	 /* Enable external clock source */
+	if (emac_has_feature(dev, EMAC_FTR_460EX_PHY_CLK_FIX))
+		dcri_clrset(SDR0, SDR0_ETH_CFG,
+			    SDR0_ETH_CFG_ECS << dev->cell_index, 0);
+#endif
+
 	if (n) {
 		dev->reset_failed = 0;
 		return 0;
@@ -2559,6 +2574,9 @@
 	/* Check EMAC version */
 	if (of_device_is_compatible(np, "ibm,emac4sync")) {
 		dev->features |= (EMAC_FTR_EMAC4 | EMAC_FTR_EMAC4SYNC);
+		if (of_device_is_compatible(np, "ibm,emac-460ex") ||
+		    of_device_is_compatible(np, "ibm,emac-460gt"))
+			dev->features |= EMAC_FTR_460EX_PHY_CLK_FIX;
 	} else if (of_device_is_compatible(np, "ibm,emac4")) {
 		dev->features |= EMAC_FTR_EMAC4;
 		if (of_device_is_compatible(np, "ibm,emac-440gx"))
diff --git a/drivers/net/ibm_newemac/core.h b/drivers/net/ibm_newemac/core.h
index 6545e69..5ca70e5 100644
--- a/drivers/net/ibm_newemac/core.h
+++ b/drivers/net/ibm_newemac/core.h
@@ -317,6 +317,10 @@
  * The 405EX and 460EX contain the EMAC4SYNC core
  */
 #define EMAC_FTR_EMAC4SYNC		0x00000200
+/*
+ * Set if we need phy clock workaround for 460ex or 460gt
+ */
+#define EMAC_FTR_460EX_PHY_CLK_FIX	0x00000400
 
 
 /* Right now, we don't quite handle the always/possible masks on the
@@ -341,6 +345,7 @@
 #ifdef CONFIG_IBM_NEW_EMAC_RGMII
 	    EMAC_FTR_HAS_RGMII	|
 #endif
+	EMAC_FTR_460EX_PHY_CLK_FIX |
 	EMAC_FTR_440EP_PHY_CLK_FIX,
 };
 
diff --git a/drivers/net/ibm_newemac/mal.h b/drivers/net/ibm_newemac/mal.h
index eaa7262..717dc38 100644
--- a/drivers/net/ibm_newemac/mal.h
+++ b/drivers/net/ibm_newemac/mal.h
@@ -102,7 +102,7 @@
 /* MAL V1 IER bits */
 #define   MAL1_IER_NWE		0x00000008
 #define   MAL1_IER_SOC_EVENTS	MAL1_IER_NWE
-#define   MAL1_IER_EVENTS	(MAL1_IER_SOC_EVENTS | MAL_IER_OTE | \
+#define   MAL1_IER_EVENTS	(MAL1_IER_SOC_EVENTS | MAL_IER_DE | \
 				 MAL_IER_OTE | MAL_IER_OE | MAL_IER_PE)
 
 /* MAL V2 IER bits */
@@ -110,7 +110,7 @@
 #define   MAL2_IER_PRE		0x00000040
 #define   MAL2_IER_PWE		0x00000020
 #define   MAL2_IER_SOC_EVENTS	(MAL2_IER_PT | MAL2_IER_PRE | MAL2_IER_PWE)
-#define   MAL2_IER_EVENTS	(MAL2_IER_SOC_EVENTS | MAL_IER_OTE | \
+#define   MAL2_IER_EVENTS	(MAL2_IER_SOC_EVENTS | MAL_IER_DE | \
 				 MAL_IER_OTE | MAL_IER_OE | MAL_IER_PE)
 
 
diff --git a/drivers/net/ibm_newemac/phy.c b/drivers/net/ibm_newemac/phy.c
index 37bfeea..9164abb 100644
--- a/drivers/net/ibm_newemac/phy.c
+++ b/drivers/net/ibm_newemac/phy.c
@@ -321,7 +321,7 @@
 
 static int m88e1111_init(struct mii_phy *phy)
 {
-	pr_debug("%s: Marvell 88E1111 Ethernet\n", __FUNCTION__);
+	pr_debug("%s: Marvell 88E1111 Ethernet\n", __func__);
 	phy_write(phy, 0x14, 0x0ce3);
 	phy_write(phy, 0x18, 0x4101);
 	phy_write(phy, 0x09, 0x0e00);
diff --git a/drivers/net/ibmlana.c b/drivers/net/ibmlana.c
index 95e3464..f027647 100644
--- a/drivers/net/ibmlana.c
+++ b/drivers/net/ibmlana.c
@@ -71,7 +71,7 @@
   June 1st, 2000
 	corrected version codes, added support for the latest 2.3 changes
   Oct 28th, 2002
-  	cleaned up for the 2.5 tree <alan@redhat.com>
+	cleaned up for the 2.5 tree <alan@lxorguk.ukuu.org.uk>
 
  *************************************************************************/
 
diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c
index 634c4c9..93d02ef 100644
--- a/drivers/net/igb/igb_main.c
+++ b/drivers/net/igb/igb_main.c
@@ -3563,10 +3563,6 @@
 	struct net_device *netdev = adapter->netdev;
 	int work_done = 0;
 
-	/* Keep link state information with original netdev */
-	if (!netif_carrier_ok(netdev))
-		goto quit_polling;
-
 #ifdef CONFIG_DCA
 	if (adapter->flags & IGB_FLAG_DCA_ENABLED)
 		igb_update_rx_dca(rx_ring);
@@ -3576,7 +3572,6 @@
 
 	/* If not enough Rx work done, exit the polling mode */
 	if ((work_done == 0) || !netif_running(netdev)) {
-quit_polling:
 		netif_rx_complete(netdev, napi);
 
 		if (adapter->itr_setting & 3) {
@@ -3617,16 +3612,14 @@
 	unsigned int i;
 	u32 head, oldhead;
 	unsigned int count = 0;
-	bool cleaned = false;
-	bool retval = true;
 	unsigned int total_bytes = 0, total_packets = 0;
+	bool retval = true;
 
 	rmb();
 	head = get_head(tx_ring);
 	i = tx_ring->next_to_clean;
 	while (1) {
 		while (i != head) {
-			cleaned = true;
 			tx_desc = E1000_TX_DESC(*tx_ring, i);
 			buffer_info = &tx_ring->buffer_info[i];
 			skb = buffer_info->skb;
@@ -3643,7 +3636,6 @@
 			}
 
 			igb_unmap_and_free_tx_resource(adapter, buffer_info);
-			tx_desc->upper.data = 0;
 
 			i++;
 			if (i == tx_ring->count)
@@ -3665,7 +3657,7 @@
 done_cleaning:
 	tx_ring->next_to_clean = i;
 
-	if (unlikely(cleaned &&
+	if (unlikely(count &&
 		     netif_carrier_ok(netdev) &&
 		     IGB_DESC_UNUSED(tx_ring) >= IGB_TX_QUEUE_WAKE)) {
 		/* Make sure that anybody stopping the queue after this
diff --git a/drivers/net/irda/pxaficp_ir.c b/drivers/net/irda/pxaficp_ir.c
index 4aa61a1..c5b02b6 100644
--- a/drivers/net/irda/pxaficp_ir.c
+++ b/drivers/net/irda/pxaficp_ir.c
@@ -572,8 +572,8 @@
 	ICCR2 = ICCR2_TXP | ICCR2_TRIG_32;
 
 	/* configure DMAC */
-	DRCMR17 = si->rxdma | DRCMR_MAPVLD;
-	DRCMR18 = si->txdma | DRCMR_MAPVLD;
+	DRCMR(17) = si->rxdma | DRCMR_MAPVLD;
+	DRCMR(18) = si->txdma | DRCMR_MAPVLD;
 
 	/* force SIR reinitialization */
 	si->speed = 4000000;
@@ -602,8 +602,8 @@
 	/* disable the STUART or FICP clocks */
 	pxa_irda_disable_clk(si);
 
-	DRCMR17 = 0;
-	DRCMR18 = 0;
+	DRCMR(17) = 0;
+	DRCMR(18) = 0;
 
 	local_irq_restore(flags);
 
diff --git a/drivers/net/irda/vlsi_ir.c b/drivers/net/irda/vlsi_ir.c
index 18f4b3a..9c926d2 100644
--- a/drivers/net/irda/vlsi_ir.c
+++ b/drivers/net/irda/vlsi_ir.c
@@ -165,7 +165,7 @@
 	unsigned iobase = pci_resource_start(pdev, 0);
 	unsigned i;
 
-	seq_printf(seq, "\n%s (vid/did: %04x/%04x)\n",
+	seq_printf(seq, "\n%s (vid/did: [%04x:%04x])\n",
 		   pci_name(pdev), (int)pdev->vendor, (int)pdev->device);
 	seq_printf(seq, "pci-power-state: %u\n", (unsigned) pdev->current_state);
 	seq_printf(seq, "resources: irq=%u / io=0x%04x / dma_mask=0x%016Lx\n",
diff --git a/drivers/net/ixgb/ixgb.h b/drivers/net/ixgb/ixgb.h
index 804698f..d85717e 100644
--- a/drivers/net/ixgb/ixgb.h
+++ b/drivers/net/ixgb/ixgb.h
@@ -85,7 +85,7 @@
 #define DPRINTK(nlevel, klevel, fmt, args...) \
 	(void)((NETIF_MSG_##nlevel & adapter->msg_enable) && \
 	printk(KERN_##klevel PFX "%s: %s: " fmt, adapter->netdev->name, \
-		__FUNCTION__ , ## args))
+		__func__ , ## args))
 
 
 /* TX/RX descriptor defines */
diff --git a/drivers/net/ixgb/ixgb_main.c b/drivers/net/ixgb/ixgb_main.c
index aa75385c..be3c7dc 100644
--- a/drivers/net/ixgb/ixgb_main.c
+++ b/drivers/net/ixgb/ixgb_main.c
@@ -977,15 +977,17 @@
 
 	for (i = 0; i < rx_ring->count; i++) {
 		buffer_info = &rx_ring->buffer_info[i];
-		if (buffer_info->skb) {
-
+		if (buffer_info->dma) {
 			pci_unmap_single(pdev,
 					 buffer_info->dma,
 					 buffer_info->length,
 					 PCI_DMA_FROMDEVICE);
+			buffer_info->dma = 0;
+			buffer_info->length = 0;
+		}
 
+		if (buffer_info->skb) {
 			dev_kfree_skb(buffer_info->skb);
-
 			buffer_info->skb = NULL;
 		}
 	}
diff --git a/drivers/net/ixgbe/ixgbe.h b/drivers/net/ixgbe/ixgbe.h
index 956914a..2198b77 100644
--- a/drivers/net/ixgbe/ixgbe.h
+++ b/drivers/net/ixgbe/ixgbe.h
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel 10 Gigabit PCI Express Linux driver
-  Copyright(c) 1999 - 2007 Intel Corporation.
+  Copyright(c) 1999 - 2008 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
@@ -20,7 +20,6 @@
   the file called "COPYING".
 
   Contact Information:
-  Linux NICS <linux.nics@intel.com>
   e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
   Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
 
@@ -37,17 +36,15 @@
 #include "ixgbe_type.h"
 #include "ixgbe_common.h"
 
-#ifdef CONFIG_DCA
+#if defined(CONFIG_DCA) || defined(CONFIG_DCA_MODULE)
 #include <linux/dca.h>
 #endif
 
-#define IXGBE_ERR(args...) printk(KERN_ERR "ixgbe: " args)
-
 #define PFX "ixgbe: "
 #define DPRINTK(nlevel, klevel, fmt, args...) \
 	((void)((NETIF_MSG_##nlevel & adapter->msg_enable) && \
 	printk(KERN_##klevel PFX "%s: %s: " fmt, adapter->netdev->name, \
-		__FUNCTION__ , ## args)))
+		__func__ , ## args)))
 
 /* TX/RX descriptor defines */
 #define IXGBE_DEFAULT_TXD		   1024
@@ -58,23 +55,14 @@
 #define IXGBE_MAX_RXD			   4096
 #define IXGBE_MIN_RXD			     64
 
-#define IXGBE_DEFAULT_RXQ			   1
-#define IXGBE_MAX_RXQ				   1
-#define IXGBE_MIN_RXQ				   1
-
-#define IXGBE_DEFAULT_ITR_RX_USECS	    125  /*   8k irqs/sec */
-#define IXGBE_DEFAULT_ITR_TX_USECS	    250  /*   4k irqs/sec */
-#define IXGBE_MIN_ITR_USECS		    100  /* 500k irqs/sec */
-#define IXGBE_MAX_ITR_USECS		  10000  /* 100  irqs/sec */
-
 /* flow control */
 #define IXGBE_DEFAULT_FCRTL		0x10000
-#define IXGBE_MIN_FCRTL			      0
+#define IXGBE_MIN_FCRTL			   0x40
 #define IXGBE_MAX_FCRTL			0x7FF80
 #define IXGBE_DEFAULT_FCRTH		0x20000
-#define IXGBE_MIN_FCRTH			      0
+#define IXGBE_MIN_FCRTH			  0x600
 #define IXGBE_MAX_FCRTH			0x7FFF0
-#define IXGBE_DEFAULT_FCPAUSE		 0x6800  /* may be too long */
+#define IXGBE_DEFAULT_FCPAUSE		 0xFFFF
 #define IXGBE_MIN_FCPAUSE		      0
 #define IXGBE_MAX_FCPAUSE		 0xFFFF
 
@@ -88,9 +76,6 @@
 
 #define MAXIMUM_ETHERNET_VLAN_SIZE (ETH_FRAME_LEN + ETH_FCS_LEN + VLAN_HLEN)
 
-/* How many Tx Descriptors do we need to call netif_wake_queue? */
-#define IXGBE_TX_QUEUE_WAKE 16
-
 /* How many Rx Buffers do we bundle into one write to the hardware ? */
 #define IXGBE_RX_BUFFER_WRITE	16	/* Must be power of 2 */
 
@@ -119,6 +104,7 @@
 	dma_addr_t dma;
 	struct page *page;
 	dma_addr_t page_dma;
+	unsigned int page_offset;
 };
 
 struct ixgbe_queue_stats {
@@ -150,22 +136,20 @@
 		      * offset associated with this ring, which is different
 		      * for DCE and RSS modes */
 
-#ifdef CONFIG_DCA
+#if defined(CONFIG_DCA) || defined(CONFIG_DCA_MODULE)
 	/* cpu for tx queue */
 	int cpu;
 #endif
 	struct net_lro_mgr lro_mgr;
 	bool lro_used;
 	struct ixgbe_queue_stats stats;
-	u8 v_idx; /* maps directly to the index for this ring in the hardware
-		   * vector array, can also be used for finding the bit in EICR
-		   * and friends that represents the vector for this ring */
+	u16 v_idx; /* maps directly to the index for this ring in the hardware
+	           * vector array, can also be used for finding the bit in EICR
+	           * and friends that represents the vector for this ring */
 
-	u32 eims_value;
-	u16 itr_register;
 
-	char name[IFNAMSIZ + 5];
 	u16 work_limit;                /* max work per interrupt */
+	u16 rx_buf_len;
 };
 
 #define RING_F_VMDQ 1
@@ -190,8 +174,8 @@
 	DECLARE_BITMAP(txr_idx, MAX_TX_QUEUES); /* Tx ring indices */
 	u8 rxr_count;     /* Rx ring count assigned to this vector */
 	u8 txr_count;     /* Tx ring count assigned to this vector */
-	u8 tx_eitr;
-	u8 rx_eitr;
+	u8 tx_itr;
+	u8 rx_itr;
 	u32 eitr;
 };
 
@@ -228,7 +212,6 @@
 	struct timer_list watchdog_timer;
 	struct vlan_group *vlgrp;
 	u16 bd_number;
-	u16 rx_buf_len;
 	struct work_struct reset_task;
 	struct ixgbe_q_vector q_vector[MAX_MSIX_Q_VECTORS];
 	char name[MAX_MSIX_COUNT][IFNAMSIZ + 5];
@@ -240,7 +223,9 @@
 
 	/* TX */
 	struct ixgbe_ring *tx_ring;	/* One per active queue */
+	int num_tx_queues;
 	u64 restart_queue;
+	u64 hw_csum_tx_good;
 	u64 lsc_int;
 	u64 hw_tso_ctxt;
 	u64 hw_tso6_ctxt;
@@ -249,12 +234,10 @@
 
 	/* RX */
 	struct ixgbe_ring *rx_ring;	/* One per active queue */
-	u64 hw_csum_tx_good;
+	int num_rx_queues;
 	u64 hw_csum_rx_error;
 	u64 hw_csum_rx_good;
 	u64 non_eop_descs;
-	int num_tx_queues;
-	int num_rx_queues;
 	int num_msix_vectors;
 	struct ixgbe_ring_feature ring_feature[3];
 	struct msix_entry *msix_entries;
@@ -267,15 +250,28 @@
 	 * thus the additional *_CAPABLE flags.
 	 */
 	u32 flags;
-#define IXGBE_FLAG_RX_CSUM_ENABLED              (u32)(1 << 0)
-#define IXGBE_FLAG_MSI_ENABLED                  (u32)(1 << 1)
-#define IXGBE_FLAG_MSIX_ENABLED                 (u32)(1 << 2)
-#define IXGBE_FLAG_RX_PS_ENABLED                (u32)(1 << 3)
-#define IXGBE_FLAG_IN_NETPOLL                   (u32)(1 << 4)
-#define IXGBE_FLAG_IMIR_ENABLED                 (u32)(1 << 5)
-#define IXGBE_FLAG_RSS_ENABLED                  (u32)(1 << 6)
-#define IXGBE_FLAG_VMDQ_ENABLED                 (u32)(1 << 7)
-#define IXGBE_FLAG_DCA_ENABLED                  (u32)(1 << 8)
+#define IXGBE_FLAG_RX_CSUM_ENABLED              (u32)(1)
+#define IXGBE_FLAG_MSI_CAPABLE                  (u32)(1 << 1)
+#define IXGBE_FLAG_MSI_ENABLED                  (u32)(1 << 2)
+#define IXGBE_FLAG_MSIX_CAPABLE                 (u32)(1 << 3)
+#define IXGBE_FLAG_MSIX_ENABLED                 (u32)(1 << 4)
+#define IXGBE_FLAG_RX_1BUF_CAPABLE              (u32)(1 << 6)
+#define IXGBE_FLAG_RX_PS_CAPABLE                (u32)(1 << 7)
+#define IXGBE_FLAG_RX_PS_ENABLED                (u32)(1 << 8)
+#define IXGBE_FLAG_IN_NETPOLL                   (u32)(1 << 9)
+#define IXGBE_FLAG_DCA_ENABLED                  (u32)(1 << 10)
+#define IXGBE_FLAG_DCA_CAPABLE                  (u32)(1 << 11)
+#define IXGBE_FLAG_IMIR_ENABLED                 (u32)(1 << 12)
+#define IXGBE_FLAG_MQ_CAPABLE                   (u32)(1 << 13)
+#define IXGBE_FLAG_RSS_ENABLED                  (u32)(1 << 16)
+#define IXGBE_FLAG_RSS_CAPABLE                  (u32)(1 << 17)
+#define IXGBE_FLAG_VMDQ_CAPABLE                 (u32)(1 << 18)
+#define IXGBE_FLAG_VMDQ_ENABLED                 (u32)(1 << 19)
+#define IXGBE_FLAG_NEED_LINK_UPDATE             (u32)(1 << 22)
+#define IXGBE_FLAG_IN_WATCHDOG_TASK             (u32)(1 << 23)
+
+/* default to trying for four seconds */
+#define IXGBE_TRY_LINK_TIMEOUT (4 * HZ)
 
 	/* OS defined structs */
 	struct net_device *netdev;
@@ -288,14 +284,21 @@
 	struct ixgbe_hw_stats stats;
 
 	/* Interrupt Throttle Rate */
-	u32 rx_eitr;
-	u32 tx_eitr;
+	u32 eitr_param;
 
 	unsigned long state;
 	u64 tx_busy;
 	u64 lro_aggregated;
 	u64 lro_flushed;
 	u64 lro_no_desc;
+	unsigned int tx_ring_count;
+	unsigned int rx_ring_count;
+
+	u32 link_speed;
+	bool link_up;
+	unsigned long link_check_timeout;
+
+	struct work_struct watchdog_task;
 };
 
 enum ixbge_state_t {
@@ -317,11 +320,11 @@
 extern void ixgbe_down(struct ixgbe_adapter *adapter);
 extern void ixgbe_reinit_locked(struct ixgbe_adapter *adapter);
 extern void ixgbe_reset(struct ixgbe_adapter *adapter);
-extern void ixgbe_update_stats(struct ixgbe_adapter *adapter);
 extern void ixgbe_set_ethtool_ops(struct net_device *netdev);
-extern int ixgbe_setup_rx_resources(struct ixgbe_adapter *adapter,
-				    struct ixgbe_ring *rxdr);
-extern int ixgbe_setup_tx_resources(struct ixgbe_adapter *adapter,
-				    struct ixgbe_ring *txdr);
+extern int ixgbe_setup_rx_resources(struct ixgbe_adapter *, struct ixgbe_ring *);
+extern int ixgbe_setup_tx_resources(struct ixgbe_adapter *, struct ixgbe_ring *);
+extern void ixgbe_free_rx_resources(struct ixgbe_adapter *, struct ixgbe_ring *);
+extern void ixgbe_free_tx_resources(struct ixgbe_adapter *, struct ixgbe_ring *);
+extern void ixgbe_update_stats(struct ixgbe_adapter *adapter);
 
 #endif /* _IXGBE_H_ */
diff --git a/drivers/net/ixgbe/ixgbe_82598.c b/drivers/net/ixgbe/ixgbe_82598.c
index f96358b..7cddcfb 100644
--- a/drivers/net/ixgbe/ixgbe_82598.c
+++ b/drivers/net/ixgbe/ixgbe_82598.c
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel 10 Gigabit PCI Express Linux driver
-  Copyright(c) 1999 - 2007 Intel Corporation.
+  Copyright(c) 1999 - 2008 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
@@ -20,7 +20,6 @@
   the file called "COPYING".
 
   Contact Information:
-  Linux NICS <linux.nics@intel.com>
   e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
   Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
 
@@ -36,67 +35,62 @@
 #define IXGBE_82598_MAX_TX_QUEUES 32
 #define IXGBE_82598_MAX_RX_QUEUES 64
 #define IXGBE_82598_RAR_ENTRIES   16
+#define IXGBE_82598_MC_TBL_SIZE  128
+#define IXGBE_82598_VFT_TBL_SIZE 128
 
-static s32 ixgbe_get_invariants_82598(struct ixgbe_hw *hw);
-static s32 ixgbe_get_link_settings_82598(struct ixgbe_hw *hw, u32 *speed,
-					 bool *autoneg);
-static s32 ixgbe_get_copper_link_settings_82598(struct ixgbe_hw *hw,
-						u32 *speed, bool *autoneg);
-static enum ixgbe_media_type ixgbe_get_media_type_82598(struct ixgbe_hw *hw);
-static s32 ixgbe_setup_mac_link_82598(struct ixgbe_hw *hw);
-static s32 ixgbe_check_mac_link_82598(struct ixgbe_hw *hw, u32 *speed,
-				      bool *link_up);
-static s32 ixgbe_setup_mac_link_speed_82598(struct ixgbe_hw *hw, u32 speed,
-					    bool autoneg,
-					    bool autoneg_wait_to_complete);
+static s32 ixgbe_get_copper_link_capabilities_82598(struct ixgbe_hw *hw,
+                                             ixgbe_link_speed *speed,
+                                             bool *autoneg);
 static s32 ixgbe_setup_copper_link_82598(struct ixgbe_hw *hw);
-static s32 ixgbe_setup_copper_link_speed_82598(struct ixgbe_hw *hw, u32 speed,
-					       bool autoneg,
-					       bool autoneg_wait_to_complete);
-static s32 ixgbe_reset_hw_82598(struct ixgbe_hw *hw);
+static s32 ixgbe_setup_copper_link_speed_82598(struct ixgbe_hw *hw,
+                                               ixgbe_link_speed speed,
+                                               bool autoneg,
+                                               bool autoneg_wait_to_complete);
 
-
+/**
+ */
 static s32 ixgbe_get_invariants_82598(struct ixgbe_hw *hw)
 {
-	hw->mac.num_rx_queues = IXGBE_82598_MAX_RX_QUEUES;
-	hw->mac.num_tx_queues = IXGBE_82598_MAX_TX_QUEUES;
-	hw->mac.num_rx_addrs = IXGBE_82598_RAR_ENTRIES;
+	struct ixgbe_mac_info *mac = &hw->mac;
+	struct ixgbe_phy_info *phy = &hw->phy;
 
-	/* PHY ops are filled in by default properly for Fiber only */
-	if (hw->mac.ops.get_media_type(hw) == ixgbe_media_type_copper) {
-		hw->mac.ops.setup_link = &ixgbe_setup_copper_link_82598;
-		hw->mac.ops.setup_link_speed = &ixgbe_setup_copper_link_speed_82598;
-		hw->mac.ops.get_link_settings =
-				&ixgbe_get_copper_link_settings_82598;
+	/* Call PHY identify routine to get the phy type */
+	ixgbe_identify_phy_generic(hw);
 
-		/* Call PHY identify routine to get the phy type */
-		ixgbe_identify_phy(hw);
-
-		switch (hw->phy.type) {
-		case ixgbe_phy_tn:
-			hw->phy.ops.setup_link = &ixgbe_setup_tnx_phy_link;
-			hw->phy.ops.check_link = &ixgbe_check_tnx_phy_link;
-			hw->phy.ops.setup_link_speed =
-					&ixgbe_setup_tnx_phy_link_speed;
-			break;
-		default:
-			break;
-		}
+	/* PHY Init */
+	switch (phy->type) {
+	default:
+		break;
 	}
 
+	if (mac->ops.get_media_type(hw) == ixgbe_media_type_copper) {
+		mac->ops.setup_link = &ixgbe_setup_copper_link_82598;
+		mac->ops.setup_link_speed =
+		                     &ixgbe_setup_copper_link_speed_82598;
+		mac->ops.get_link_capabilities =
+		                     &ixgbe_get_copper_link_capabilities_82598;
+	}
+
+	mac->mcft_size = IXGBE_82598_MC_TBL_SIZE;
+	mac->vft_size = IXGBE_82598_VFT_TBL_SIZE;
+	mac->num_rar_entries = IXGBE_82598_RAR_ENTRIES;
+	mac->max_rx_queues = IXGBE_82598_MAX_RX_QUEUES;
+	mac->max_tx_queues = IXGBE_82598_MAX_TX_QUEUES;
+
 	return 0;
 }
 
 /**
- *  ixgbe_get_link_settings_82598 - Determines default link settings
+ *  ixgbe_get_link_capabilities_82598 - Determines link capabilities
  *  @hw: pointer to hardware structure
  *  @speed: pointer to link speed
  *  @autoneg: boolean auto-negotiation value
  *
- *  Determines the default link settings by reading the AUTOC register.
+ *  Determines the link capabilities by reading the AUTOC register.
  **/
-static s32 ixgbe_get_link_settings_82598(struct ixgbe_hw *hw, u32 *speed,
-					 bool *autoneg)
+static s32 ixgbe_get_link_capabilities_82598(struct ixgbe_hw *hw,
+                                             ixgbe_link_speed *speed,
+                                             bool *autoneg)
 {
 	s32 status = 0;
 	s32 autoc_reg;
@@ -145,15 +139,16 @@
 }
 
 /**
- *  ixgbe_get_copper_link_settings_82598 - Determines default link settings
+ *  ixgbe_get_copper_link_capabilities_82598 - Determines link capabilities
  *  @hw: pointer to hardware structure
  *  @speed: pointer to link speed
  *  @autoneg: boolean auto-negotiation value
  *
- *  Determines the default link settings by reading the AUTOC register.
+ *  Determines the link capabilities by reading the AUTOC register.
  **/
-static s32 ixgbe_get_copper_link_settings_82598(struct ixgbe_hw *hw,
-						u32 *speed, bool *autoneg)
+s32 ixgbe_get_copper_link_capabilities_82598(struct ixgbe_hw *hw,
+                                             ixgbe_link_speed *speed,
+                                             bool *autoneg)
 {
 	s32 status = IXGBE_ERR_LINK_SETUP;
 	u16 speed_ability;
@@ -161,9 +156,9 @@
 	*speed = 0;
 	*autoneg = true;
 
-	status = ixgbe_read_phy_reg(hw, IXGBE_MDIO_PHY_SPEED_ABILITY,
-				    IXGBE_MDIO_PMA_PMD_DEV_TYPE,
-				    &speed_ability);
+	status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_PHY_SPEED_ABILITY,
+	                              IXGBE_MDIO_PMA_PMD_DEV_TYPE,
+	                              &speed_ability);
 
 	if (status == 0) {
 		if (speed_ability & IXGBE_MDIO_PHY_SPEED_10G)
@@ -191,11 +186,9 @@
 	case IXGBE_DEV_ID_82598AF_SINGLE_PORT:
 	case IXGBE_DEV_ID_82598EB_CX4:
 	case IXGBE_DEV_ID_82598_CX4_DUAL_PORT:
+	case IXGBE_DEV_ID_82598EB_XF_LR:
 		media_type = ixgbe_media_type_fiber;
 		break;
-	case IXGBE_DEV_ID_82598AT_DUAL_PORT:
-		media_type = ixgbe_media_type_copper;
-		break;
 	default:
 		media_type = ixgbe_media_type_unknown;
 		break;
@@ -205,6 +198,122 @@
 }
 
 /**
+ *  ixgbe_setup_fc_82598 - Configure flow control settings
+ *  @hw: pointer to hardware structure
+ *  @packetbuf_num: packet buffer number (0-7)
+ *
+ *  Configures the flow control settings based on SW configuration.  This
+ *  function is used for 802.3x flow control configuration only.
+ **/
+s32 ixgbe_setup_fc_82598(struct ixgbe_hw *hw, s32 packetbuf_num)
+{
+	u32 frctl_reg;
+	u32 rmcs_reg;
+
+	if (packetbuf_num < 0 || packetbuf_num > 7) {
+		hw_dbg(hw, "Invalid packet buffer number [%d], expected range is"
+		          " 0-7\n", packetbuf_num);
+	}
+
+	frctl_reg = IXGBE_READ_REG(hw, IXGBE_FCTRL);
+	frctl_reg &= ~(IXGBE_FCTRL_RFCE | IXGBE_FCTRL_RPFCE);
+
+	rmcs_reg = IXGBE_READ_REG(hw, IXGBE_RMCS);
+	rmcs_reg &= ~(IXGBE_RMCS_TFCE_PRIORITY | IXGBE_RMCS_TFCE_802_3X);
+
+	/*
+	 * 10 gig parts do not have a word in the EEPROM to determine the
+	 * default flow control setting, so we explicitly set it to full.
+	 */
+	if (hw->fc.type == ixgbe_fc_default)
+		hw->fc.type = ixgbe_fc_full;
+
+	/*
+	 * We want to save off the original Flow Control configuration just in
+	 * case we get disconnected and then reconnected into a different hub
+	 * or switch with different Flow Control capabilities.
+	 */
+	hw->fc.original_type = hw->fc.type;
+
+	/*
+	 * The possible values of the "flow_control" parameter are:
+	 * 0: Flow control is completely disabled
+	 * 1: Rx flow control is enabled (we can receive pause frames but not
+	 *    send pause frames).
+	 * 2: Tx flow control is enabled (we can send pause frames but we do not
+	 *    support receiving pause frames)
+	 * 3: Both Rx and Tx flow control (symmetric) are enabled.
+	 * other: Invalid.
+	 */
+	switch (hw->fc.type) {
+	case ixgbe_fc_none:
+		break;
+	case ixgbe_fc_rx_pause:
+		/*
+		 * Rx Flow control is enabled,
+		 * and Tx Flow control is disabled.
+		 */
+		frctl_reg |= IXGBE_FCTRL_RFCE;
+		break;
+	case ixgbe_fc_tx_pause:
+		/*
+		 * Tx Flow control is enabled, and Rx Flow control is disabled,
+		 * by a software over-ride.
+		 */
+		rmcs_reg |= IXGBE_RMCS_TFCE_802_3X;
+		break;
+	case ixgbe_fc_full:
+		/*
+		 * Flow control (both Rx and Tx) is enabled by a software
+		 * over-ride.
+		 */
+		frctl_reg |= IXGBE_FCTRL_RFCE;
+		rmcs_reg |= IXGBE_RMCS_TFCE_802_3X;
+		break;
+	default:
+		/* We should never get here.  The value should be 0-3. */
+		hw_dbg(hw, "Flow control param set incorrectly\n");
+		break;
+	}
+
+	/* Enable 802.3x based flow control settings. */
+	IXGBE_WRITE_REG(hw, IXGBE_FCTRL, frctl_reg);
+	IXGBE_WRITE_REG(hw, IXGBE_RMCS, rmcs_reg);
+
+	/*
+	 * Check for invalid software configuration, zeros are completely
+	 * invalid for all parameters used past this point, and if we enable
+	 * flow control with zero water marks, we blast flow control packets.
+	 */
+	if (!hw->fc.low_water || !hw->fc.high_water || !hw->fc.pause_time) {
+		hw_dbg(hw, "Flow control structure initialized incorrectly\n");
+		return IXGBE_ERR_INVALID_LINK_SETTINGS;
+	}
+
+	/*
+	 * We need to set up the Receive Threshold high and low water
+	 * marks as well as (optionally) enabling the transmission of
+	 * XON frames.
+	 */
+	if (hw->fc.type & ixgbe_fc_tx_pause) {
+		if (hw->fc.send_xon) {
+			IXGBE_WRITE_REG(hw, IXGBE_FCRTL(packetbuf_num),
+			                (hw->fc.low_water | IXGBE_FCRTL_XONE));
+		} else {
+			IXGBE_WRITE_REG(hw, IXGBE_FCRTL(packetbuf_num),
+			                hw->fc.low_water);
+		}
+		IXGBE_WRITE_REG(hw, IXGBE_FCRTH(packetbuf_num),
+		                (hw->fc.high_water)|IXGBE_FCRTH_FCEN);
+	}
+
+	IXGBE_WRITE_REG(hw, IXGBE_FCTTV(0), hw->fc.pause_time);
+	IXGBE_WRITE_REG(hw, IXGBE_FCRTV, (hw->fc.pause_time >> 1));
+
+	return 0;
+}
+
+/**
  *  ixgbe_setup_mac_link_82598 - Configures MAC link settings
  *  @hw: pointer to hardware structure
  *
@@ -248,8 +357,7 @@
 			}
 			if (!(links_reg & IXGBE_LINKS_KX_AN_COMP)) {
 				status = IXGBE_ERR_AUTONEG_NOT_COMPLETE;
-				hw_dbg(hw,
-				       "Autonegotiation did not complete.\n");
+				hw_dbg(hw, "Autonegotiation did not complete.\n");
 			}
 		}
 	}
@@ -259,8 +367,8 @@
 	 * case we get disconnected and then reconnected into a different hub
 	 * or switch with different Flow Control capabilities.
 	 */
-	hw->fc.type = hw->fc.original_type;
-	ixgbe_setup_fc(hw, 0);
+	hw->fc.original_type = hw->fc.type;
+	ixgbe_setup_fc_82598(hw, 0);
 
 	/* Add delay to filter out noises during initial link setup */
 	msleep(50);
@@ -273,20 +381,35 @@
  *  @hw: pointer to hardware structure
  *  @speed: pointer to link speed
  *  @link_up: true is link is up, false otherwise
+ *  @link_up_wait_to_complete: bool used to wait for link up or not
  *
  *  Reads the links register to determine if link is up and the current speed
  **/
-static s32 ixgbe_check_mac_link_82598(struct ixgbe_hw *hw, u32 *speed,
-				      bool *link_up)
+static s32 ixgbe_check_mac_link_82598(struct ixgbe_hw *hw,
+                                      ixgbe_link_speed *speed, bool *link_up,
+                                      bool link_up_wait_to_complete)
 {
 	u32 links_reg;
+	u32 i;
 
 	links_reg = IXGBE_READ_REG(hw, IXGBE_LINKS);
-
-	if (links_reg & IXGBE_LINKS_UP)
-		*link_up = true;
-	else
-		*link_up = false;
+	if (link_up_wait_to_complete) {
+		for (i = 0; i < IXGBE_LINK_UP_TIME; i++) {
+			if (links_reg & IXGBE_LINKS_UP) {
+				*link_up = true;
+				break;
+			} else {
+				*link_up = false;
+			}
+			msleep(100);
+			links_reg = IXGBE_READ_REG(hw, IXGBE_LINKS);
+		}
+	} else {
+		if (links_reg & IXGBE_LINKS_UP)
+			*link_up = true;
+		else
+			*link_up = false;
+	}
 
 	if (links_reg & IXGBE_LINKS_SPEED)
 		*speed = IXGBE_LINK_SPEED_10GB_FULL;
@@ -296,6 +419,7 @@
 	return 0;
 }
 
+
 /**
  *  ixgbe_setup_mac_link_speed_82598 - Set MAC link speed
  *  @hw: pointer to hardware structure
@@ -306,18 +430,18 @@
  *  Set the link speed in the AUTOC register and restarts link.
  **/
 static s32 ixgbe_setup_mac_link_speed_82598(struct ixgbe_hw *hw,
-					    u32 speed, bool autoneg,
-					    bool autoneg_wait_to_complete)
+                                            ixgbe_link_speed speed, bool autoneg,
+                                            bool autoneg_wait_to_complete)
 {
 	s32 status = 0;
 
 	/* If speed is 10G, then check for CX4 or XAUI. */
 	if ((speed == IXGBE_LINK_SPEED_10GB_FULL) &&
-	    (!(hw->mac.link_attach_type & IXGBE_AUTOC_10G_KX4)))
+	    (!(hw->mac.link_attach_type & IXGBE_AUTOC_10G_KX4))) {
 		hw->mac.link_mode_select = IXGBE_AUTOC_LMS_10G_LINK_NO_AN;
-	else if ((speed == IXGBE_LINK_SPEED_1GB_FULL) && (!autoneg))
+	} else if ((speed == IXGBE_LINK_SPEED_1GB_FULL) && (!autoneg)) {
 		hw->mac.link_mode_select = IXGBE_AUTOC_LMS_1G_LINK_NO_AN;
-	else if (autoneg) {
+	} else if (autoneg) {
 		/* BX mode - Autonegotiate 1G */
 		if (!(hw->mac.link_attach_type & IXGBE_AUTOC_1G_PMA_PMD))
 			hw->mac.link_mode_select = IXGBE_AUTOC_LMS_1G_AN;
@@ -336,7 +460,7 @@
 		 * ixgbe_hw This will write the AUTOC register based on the new
 		 * stored values
 		 */
-		hw->mac.ops.setup_link(hw);
+		ixgbe_setup_mac_link_82598(hw);
 	}
 
 	return status;
@@ -354,18 +478,17 @@
  **/
 static s32 ixgbe_setup_copper_link_82598(struct ixgbe_hw *hw)
 {
-	s32 status = 0;
+	s32 status;
 
 	/* Restart autonegotiation on PHY */
-	if (hw->phy.ops.setup_link)
-		status = hw->phy.ops.setup_link(hw);
+	status = hw->phy.ops.setup_link(hw);
 
-	/* Set MAC to KX/KX4 autoneg, which defaultis to Parallel detection */
+	/* Set MAC to KX/KX4 autoneg, which defaults to Parallel detection */
 	hw->mac.link_attach_type = (IXGBE_AUTOC_10G_KX4 | IXGBE_AUTOC_1G_KX);
 	hw->mac.link_mode_select = IXGBE_AUTOC_LMS_KX4_AN;
 
 	/* Set up MAC */
-	hw->mac.ops.setup_link(hw);
+	ixgbe_setup_mac_link_82598(hw);
 
 	return status;
 }
@@ -379,23 +502,23 @@
  *
  *  Sets the link speed in the AUTOC register in the MAC and restarts link.
  **/
-static s32 ixgbe_setup_copper_link_speed_82598(struct ixgbe_hw *hw, u32 speed,
-					       bool autoneg,
-					       bool autoneg_wait_to_complete)
+static s32 ixgbe_setup_copper_link_speed_82598(struct ixgbe_hw *hw,
+                                               ixgbe_link_speed speed,
+                                               bool autoneg,
+                                               bool autoneg_wait_to_complete)
 {
-	s32 status = 0;
+	s32 status;
 
 	/* Setup the PHY according to input speed */
-	if (hw->phy.ops.setup_link_speed)
-		status = hw->phy.ops.setup_link_speed(hw, speed, autoneg,
-						autoneg_wait_to_complete);
+	status = hw->phy.ops.setup_link_speed(hw, speed, autoneg,
+	                                      autoneg_wait_to_complete);
 
 	/* Set MAC to KX/KX4 autoneg, which defaults to Parallel detection */
 	hw->mac.link_attach_type = (IXGBE_AUTOC_10G_KX4 | IXGBE_AUTOC_1G_KX);
 	hw->mac.link_mode_select = IXGBE_AUTOC_LMS_KX4_AN;
 
 	/* Set up MAC */
-	hw->mac.ops.setup_link(hw);
+	ixgbe_setup_mac_link_82598(hw);
 
 	return status;
 }
@@ -404,7 +527,7 @@
  *  ixgbe_reset_hw_82598 - Performs hardware reset
  *  @hw: pointer to hardware structure
  *
- *  Resets the hardware by reseting the transmit and receive units, masks and
+ *  Resets the hardware by resetting the transmit and receive units, masks and
  *  clears all interrupts, performing a PHY reset, and performing a link (MAC)
  *  reset.
  **/
@@ -418,35 +541,44 @@
 	u8  analog_val;
 
 	/* Call adapter stop to disable tx/rx and clear interrupts */
-	ixgbe_stop_adapter(hw);
+	hw->mac.ops.stop_adapter(hw);
 
 	/*
-	 * Power up the Atlas TX lanes if they are currently powered down.
-	 * Atlas TX lanes are powered down for MAC loopback tests, but
+	 * Power up the Atlas Tx lanes if they are currently powered down.
+	 * Atlas Tx lanes are powered down for MAC loopback tests, but
 	 * they are not automatically restored on reset.
 	 */
-	ixgbe_read_analog_reg8(hw, IXGBE_ATLAS_PDN_LPBK, &analog_val);
+	hw->mac.ops.read_analog_reg8(hw, IXGBE_ATLAS_PDN_LPBK, &analog_val);
 	if (analog_val & IXGBE_ATLAS_PDN_TX_REG_EN) {
-		/* Enable TX Atlas so packets can be transmitted again */
-		ixgbe_read_analog_reg8(hw, IXGBE_ATLAS_PDN_LPBK, &analog_val);
+		/* Enable Tx Atlas so packets can be transmitted again */
+		hw->mac.ops.read_analog_reg8(hw, IXGBE_ATLAS_PDN_LPBK,
+		                             &analog_val);
 		analog_val &= ~IXGBE_ATLAS_PDN_TX_REG_EN;
-		ixgbe_write_analog_reg8(hw, IXGBE_ATLAS_PDN_LPBK, analog_val);
+		hw->mac.ops.write_analog_reg8(hw, IXGBE_ATLAS_PDN_LPBK,
+		                              analog_val);
 
-		ixgbe_read_analog_reg8(hw, IXGBE_ATLAS_PDN_10G, &analog_val);
+		hw->mac.ops.read_analog_reg8(hw, IXGBE_ATLAS_PDN_10G,
+		                             &analog_val);
 		analog_val &= ~IXGBE_ATLAS_PDN_TX_10G_QL_ALL;
-		ixgbe_write_analog_reg8(hw, IXGBE_ATLAS_PDN_10G, analog_val);
+		hw->mac.ops.write_analog_reg8(hw, IXGBE_ATLAS_PDN_10G,
+		                              analog_val);
 
-		ixgbe_read_analog_reg8(hw, IXGBE_ATLAS_PDN_1G, &analog_val);
+		hw->mac.ops.read_analog_reg8(hw, IXGBE_ATLAS_PDN_1G,
+		                             &analog_val);
 		analog_val &= ~IXGBE_ATLAS_PDN_TX_1G_QL_ALL;
-		ixgbe_write_analog_reg8(hw, IXGBE_ATLAS_PDN_1G, analog_val);
+		hw->mac.ops.write_analog_reg8(hw, IXGBE_ATLAS_PDN_1G,
+		                              analog_val);
 
-		ixgbe_read_analog_reg8(hw, IXGBE_ATLAS_PDN_AN, &analog_val);
+		hw->mac.ops.read_analog_reg8(hw, IXGBE_ATLAS_PDN_AN,
+		                             &analog_val);
 		analog_val &= ~IXGBE_ATLAS_PDN_TX_AN_QL_ALL;
-		ixgbe_write_analog_reg8(hw, IXGBE_ATLAS_PDN_AN, analog_val);
+		hw->mac.ops.write_analog_reg8(hw, IXGBE_ATLAS_PDN_AN,
+		                              analog_val);
 	}
 
 	/* Reset PHY */
-	ixgbe_reset_phy(hw);
+	if (hw->phy.reset_disable == false)
+		hw->phy.ops.reset(hw);
 
 	/*
 	 * Prevent the PCI-E bus from from hanging by disabling PCI-E master
@@ -499,29 +631,311 @@
 		IXGBE_WRITE_REG(hw, IXGBE_AUTOC, autoc);
 	} else {
 		hw->mac.link_attach_type =
-					 (autoc & IXGBE_AUTOC_LMS_ATTACH_TYPE);
+		                         (autoc & IXGBE_AUTOC_LMS_ATTACH_TYPE);
 		hw->mac.link_mode_select = (autoc & IXGBE_AUTOC_LMS_MASK);
 		hw->mac.link_settings_loaded = true;
 	}
 
 	/* Store the permanent mac address */
-	ixgbe_get_mac_addr(hw, hw->mac.perm_addr);
+	hw->mac.ops.get_mac_addr(hw, hw->mac.perm_addr);
 
 	return status;
 }
 
+/**
+ *  ixgbe_set_vmdq_82598 - Associate a VMDq set index with a rx address
+ *  @hw: pointer to hardware struct
+ *  @rar: receive address register index to associate with a VMDq index
+ *  @vmdq: VMDq set index
+ **/
+s32 ixgbe_set_vmdq_82598(struct ixgbe_hw *hw, u32 rar, u32 vmdq)
+{
+	u32 rar_high;
+
+	rar_high = IXGBE_READ_REG(hw, IXGBE_RAH(rar));
+	rar_high &= ~IXGBE_RAH_VIND_MASK;
+	rar_high |= ((vmdq << IXGBE_RAH_VIND_SHIFT) & IXGBE_RAH_VIND_MASK);
+	IXGBE_WRITE_REG(hw, IXGBE_RAH(rar), rar_high);
+	return 0;
+}
+
+/**
+ *  ixgbe_clear_vmdq_82598 - Disassociate a VMDq set index from an rx address
+ *  @hw: pointer to hardware struct
+ *  @rar: receive address register index to associate with a VMDq index
+ *  @vmdq: VMDq clear index (not used in 82598, but elsewhere)
+ **/
+static s32 ixgbe_clear_vmdq_82598(struct ixgbe_hw *hw, u32 rar, u32 vmdq)
+{
+	u32 rar_high;
+	u32 rar_entries = hw->mac.num_rar_entries;
+
+	if (rar < rar_entries) {
+		rar_high = IXGBE_READ_REG(hw, IXGBE_RAH(rar));
+		if (rar_high & IXGBE_RAH_VIND_MASK) {
+			rar_high &= ~IXGBE_RAH_VIND_MASK;
+			IXGBE_WRITE_REG(hw, IXGBE_RAH(rar), rar_high);
+		}
+	} else {
+		hw_dbg(hw, "RAR index %d is out of range.\n", rar);
+	}
+
+	return 0;
+}
+
+/**
+ *  ixgbe_set_vfta_82598 - Set VLAN filter table
+ *  @hw: pointer to hardware structure
+ *  @vlan: VLAN id to write to VLAN filter
+ *  @vind: VMDq output index that maps queue to VLAN id in VFTA
+ *  @vlan_on: boolean flag to turn on/off VLAN in VFTA
+ *
+ *  Turn on/off specified VLAN in the VLAN filter table.
+ **/
+s32 ixgbe_set_vfta_82598(struct ixgbe_hw *hw, u32 vlan, u32 vind,
+                         bool vlan_on)
+{
+	u32 regindex;
+	u32 bitindex;
+	u32 bits;
+	u32 vftabyte;
+
+	if (vlan > 4095)
+		return IXGBE_ERR_PARAM;
+
+	/* Determine 32-bit word position in array */
+	regindex = (vlan >> 5) & 0x7F;   /* upper seven bits */
+
+	/* Determine the location of the (VMD) queue index */
+	vftabyte =  ((vlan >> 3) & 0x03); /* bits (4:3) indicating byte array */
+	bitindex = (vlan & 0x7) << 2;    /* lower 3 bits indicate nibble */
+
+	/* Set the nibble for VMD queue index */
+	bits = IXGBE_READ_REG(hw, IXGBE_VFTAVIND(vftabyte, regindex));
+	bits &= (~(0x0F << bitindex));
+	bits |= (vind << bitindex);
+	IXGBE_WRITE_REG(hw, IXGBE_VFTAVIND(vftabyte, regindex), bits);
+
+	/* Determine the location of the bit for this VLAN id */
+	bitindex = vlan & 0x1F;   /* lower five bits */
+
+	bits = IXGBE_READ_REG(hw, IXGBE_VFTA(regindex));
+	if (vlan_on)
+		/* Turn on this VLAN id */
+		bits |= (1 << bitindex);
+	else
+		/* Turn off this VLAN id */
+		bits &= ~(1 << bitindex);
+	IXGBE_WRITE_REG(hw, IXGBE_VFTA(regindex), bits);
+
+	return 0;
+}
+
+/**
+ *  ixgbe_clear_vfta_82598 - Clear VLAN filter table
+ *  @hw: pointer to hardware structure
+ *
+ *  Clears the VLAN filer table, and the VMDq index associated with the filter
+ **/
+static s32 ixgbe_clear_vfta_82598(struct ixgbe_hw *hw)
+{
+	u32 offset;
+	u32 vlanbyte;
+
+	for (offset = 0; offset < hw->mac.vft_size; offset++)
+		IXGBE_WRITE_REG(hw, IXGBE_VFTA(offset), 0);
+
+	for (vlanbyte = 0; vlanbyte < 4; vlanbyte++)
+		for (offset = 0; offset < hw->mac.vft_size; offset++)
+			IXGBE_WRITE_REG(hw, IXGBE_VFTAVIND(vlanbyte, offset),
+			                0);
+
+	return 0;
+}
+
+/**
+ *  ixgbe_blink_led_start_82598 - Blink LED based on index.
+ *  @hw: pointer to hardware structure
+ *  @index: led number to blink
+ **/
+static s32 ixgbe_blink_led_start_82598(struct ixgbe_hw *hw, u32 index)
+{
+	ixgbe_link_speed speed = 0;
+	bool link_up = 0;
+	u32 autoc_reg = IXGBE_READ_REG(hw, IXGBE_AUTOC);
+	u32 led_reg = IXGBE_READ_REG(hw, IXGBE_LEDCTL);
+
+	/*
+	 * Link must be up to auto-blink the LEDs on the 82598EB MAC;
+	 * force it if link is down.
+	 */
+	hw->mac.ops.check_link(hw, &speed, &link_up, false);
+
+	if (!link_up) {
+		autoc_reg |= IXGBE_AUTOC_FLU;
+		IXGBE_WRITE_REG(hw, IXGBE_AUTOC, autoc_reg);
+		msleep(10);
+	}
+
+	led_reg &= ~IXGBE_LED_MODE_MASK(index);
+	led_reg |= IXGBE_LED_BLINK(index);
+	IXGBE_WRITE_REG(hw, IXGBE_LEDCTL, led_reg);
+	IXGBE_WRITE_FLUSH(hw);
+
+	return 0;
+}
+
+/**
+ *  ixgbe_blink_led_stop_82598 - Stop blinking LED based on index.
+ *  @hw: pointer to hardware structure
+ *  @index: led number to stop blinking
+ **/
+static s32 ixgbe_blink_led_stop_82598(struct ixgbe_hw *hw, u32 index)
+{
+	u32 autoc_reg = IXGBE_READ_REG(hw, IXGBE_AUTOC);
+	u32 led_reg = IXGBE_READ_REG(hw, IXGBE_LEDCTL);
+
+	autoc_reg &= ~IXGBE_AUTOC_FLU;
+	autoc_reg |= IXGBE_AUTOC_AN_RESTART;
+	IXGBE_WRITE_REG(hw, IXGBE_AUTOC, autoc_reg);
+
+	led_reg &= ~IXGBE_LED_MODE_MASK(index);
+	led_reg &= ~IXGBE_LED_BLINK(index);
+	led_reg |= IXGBE_LED_LINK_ACTIVE << IXGBE_LED_MODE_SHIFT(index);
+	IXGBE_WRITE_REG(hw, IXGBE_LEDCTL, led_reg);
+	IXGBE_WRITE_FLUSH(hw);
+
+	return 0;
+}
+
+/**
+ *  ixgbe_read_analog_reg8_82598 - Reads 8 bit Atlas analog register
+ *  @hw: pointer to hardware structure
+ *  @reg: analog register to read
+ *  @val: read value
+ *
+ *  Performs read operation to Atlas analog register specified.
+ **/
+s32 ixgbe_read_analog_reg8_82598(struct ixgbe_hw *hw, u32 reg, u8 *val)
+{
+	u32  atlas_ctl;
+
+	IXGBE_WRITE_REG(hw, IXGBE_ATLASCTL,
+	                IXGBE_ATLASCTL_WRITE_CMD | (reg << 8));
+	IXGBE_WRITE_FLUSH(hw);
+	udelay(10);
+	atlas_ctl = IXGBE_READ_REG(hw, IXGBE_ATLASCTL);
+	*val = (u8)atlas_ctl;
+
+	return 0;
+}
+
+/**
+ *  ixgbe_write_analog_reg8_82598 - Writes 8 bit Atlas analog register
+ *  @hw: pointer to hardware structure
+ *  @reg: atlas register to write
+ *  @val: value to write
+ *
+ *  Performs write operation to Atlas analog register specified.
+ **/
+s32 ixgbe_write_analog_reg8_82598(struct ixgbe_hw *hw, u32 reg, u8 val)
+{
+	u32  atlas_ctl;
+
+	atlas_ctl = (reg << 8) | val;
+	IXGBE_WRITE_REG(hw, IXGBE_ATLASCTL, atlas_ctl);
+	IXGBE_WRITE_FLUSH(hw);
+	udelay(10);
+
+	return 0;
+}
+
+/**
+ *  ixgbe_get_supported_physical_layer_82598 - Returns physical layer type
+ *  @hw: pointer to hardware structure
+ *
+ *  Determines physical layer capabilities of the current configuration.
+ **/
+s32 ixgbe_get_supported_physical_layer_82598(struct ixgbe_hw *hw)
+{
+	s32 physical_layer = IXGBE_PHYSICAL_LAYER_UNKNOWN;
+
+	switch (hw->device_id) {
+	case IXGBE_DEV_ID_82598EB_CX4:
+	case IXGBE_DEV_ID_82598_CX4_DUAL_PORT:
+		physical_layer = IXGBE_PHYSICAL_LAYER_10GBASE_CX4;
+		break;
+	case IXGBE_DEV_ID_82598AF_DUAL_PORT:
+	case IXGBE_DEV_ID_82598AF_SINGLE_PORT:
+		physical_layer = IXGBE_PHYSICAL_LAYER_10GBASE_SR;
+		break;
+	case IXGBE_DEV_ID_82598EB_XF_LR:
+		physical_layer = IXGBE_PHYSICAL_LAYER_10GBASE_LR;
+		break;
+
+	default:
+		physical_layer = IXGBE_PHYSICAL_LAYER_UNKNOWN;
+		break;
+	}
+
+	return physical_layer;
+}
+
 static struct ixgbe_mac_operations mac_ops_82598 = {
-	.reset			= &ixgbe_reset_hw_82598,
+	.init_hw		= &ixgbe_init_hw_generic,
+	.reset_hw		= &ixgbe_reset_hw_82598,
+	.start_hw		= &ixgbe_start_hw_generic,
+	.clear_hw_cntrs		= &ixgbe_clear_hw_cntrs_generic,
 	.get_media_type		= &ixgbe_get_media_type_82598,
+	.get_supported_physical_layer = &ixgbe_get_supported_physical_layer_82598,
+	.get_mac_addr		= &ixgbe_get_mac_addr_generic,
+	.stop_adapter		= &ixgbe_stop_adapter_generic,
+	.read_analog_reg8	= &ixgbe_read_analog_reg8_82598,
+	.write_analog_reg8	= &ixgbe_write_analog_reg8_82598,
 	.setup_link		= &ixgbe_setup_mac_link_82598,
-	.check_link		= &ixgbe_check_mac_link_82598,
 	.setup_link_speed	= &ixgbe_setup_mac_link_speed_82598,
-	.get_link_settings	= &ixgbe_get_link_settings_82598,
+	.check_link		= &ixgbe_check_mac_link_82598,
+	.get_link_capabilities	= &ixgbe_get_link_capabilities_82598,
+	.led_on			= &ixgbe_led_on_generic,
+	.led_off		= &ixgbe_led_off_generic,
+	.blink_led_start	= &ixgbe_blink_led_start_82598,
+	.blink_led_stop		= &ixgbe_blink_led_stop_82598,
+	.set_rar		= &ixgbe_set_rar_generic,
+	.clear_rar		= &ixgbe_clear_rar_generic,
+	.set_vmdq		= &ixgbe_set_vmdq_82598,
+	.clear_vmdq		= &ixgbe_clear_vmdq_82598,
+	.init_rx_addrs		= &ixgbe_init_rx_addrs_generic,
+	.update_uc_addr_list	= &ixgbe_update_uc_addr_list_generic,
+	.update_mc_addr_list	= &ixgbe_update_mc_addr_list_generic,
+	.enable_mc		= &ixgbe_enable_mc_generic,
+	.disable_mc		= &ixgbe_disable_mc_generic,
+	.clear_vfta		= &ixgbe_clear_vfta_82598,
+	.set_vfta		= &ixgbe_set_vfta_82598,
+	.setup_fc		= &ixgbe_setup_fc_82598,
+};
+
+static struct ixgbe_eeprom_operations eeprom_ops_82598 = {
+	.init_params		= &ixgbe_init_eeprom_params_generic,
+	.read			= &ixgbe_read_eeprom_generic,
+	.validate_checksum	= &ixgbe_validate_eeprom_checksum_generic,
+	.update_checksum	= &ixgbe_update_eeprom_checksum_generic,
+};
+
+static struct ixgbe_phy_operations phy_ops_82598 = {
+	.identify		= &ixgbe_identify_phy_generic,
+	/* .identify_sfp	= &ixgbe_identify_sfp_module_generic, */
+	.reset			= &ixgbe_reset_phy_generic,
+	.read_reg		= &ixgbe_read_phy_reg_generic,
+	.write_reg		= &ixgbe_write_phy_reg_generic,
+	.setup_link		= &ixgbe_setup_phy_link_generic,
+	.setup_link_speed	= &ixgbe_setup_phy_link_speed_generic,
 };
 
 struct ixgbe_info ixgbe_82598_info = {
 	.mac			= ixgbe_mac_82598EB,
 	.get_invariants		= &ixgbe_get_invariants_82598,
 	.mac_ops		= &mac_ops_82598,
+	.eeprom_ops		= &eeprom_ops_82598,
+	.phy_ops		= &phy_ops_82598,
 };
 
diff --git a/drivers/net/ixgbe/ixgbe_common.c b/drivers/net/ixgbe/ixgbe_common.c
index 7fd6aeb..f67c684 100644
--- a/drivers/net/ixgbe/ixgbe_common.c
+++ b/drivers/net/ixgbe/ixgbe_common.c
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel 10 Gigabit PCI Express Linux driver
-  Copyright(c) 1999 - 2007 Intel Corporation.
+  Copyright(c) 1999 - 2008 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
@@ -20,7 +20,6 @@
   the file called "COPYING".
 
   Contact Information:
-  Linux NICS <linux.nics@intel.com>
   e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
   Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
 
@@ -33,20 +32,28 @@
 #include "ixgbe_common.h"
 #include "ixgbe_phy.h"
 
-static s32 ixgbe_clear_hw_cntrs(struct ixgbe_hw *hw);
-
 static s32 ixgbe_poll_eeprom_eerd_done(struct ixgbe_hw *hw);
+static s32 ixgbe_acquire_eeprom(struct ixgbe_hw *hw);
 static s32 ixgbe_get_eeprom_semaphore(struct ixgbe_hw *hw);
 static void ixgbe_release_eeprom_semaphore(struct ixgbe_hw *hw);
+static s32 ixgbe_ready_eeprom(struct ixgbe_hw *hw);
+static void ixgbe_standby_eeprom(struct ixgbe_hw *hw);
+static void ixgbe_shift_out_eeprom_bits(struct ixgbe_hw *hw, u16 data,
+                                        u16 count);
+static u16 ixgbe_shift_in_eeprom_bits(struct ixgbe_hw *hw, u16 count);
+static void ixgbe_raise_eeprom_clk(struct ixgbe_hw *hw, u32 *eec);
+static void ixgbe_lower_eeprom_clk(struct ixgbe_hw *hw, u32 *eec);
+static void ixgbe_release_eeprom(struct ixgbe_hw *hw);
 static u16 ixgbe_calc_eeprom_checksum(struct ixgbe_hw *hw);
 
-static s32 ixgbe_clear_vfta(struct ixgbe_hw *hw);
-static s32 ixgbe_init_rx_addrs(struct ixgbe_hw *hw);
+static void ixgbe_enable_rar(struct ixgbe_hw *hw, u32 index);
+static void ixgbe_disable_rar(struct ixgbe_hw *hw, u32 index);
 static s32 ixgbe_mta_vector(struct ixgbe_hw *hw, u8 *mc_addr);
 static void ixgbe_add_mc_addr(struct ixgbe_hw *hw, u8 *mc_addr);
+static void ixgbe_add_uc_addr(struct ixgbe_hw *hw, u8 *addr, u32 vmdq);
 
 /**
- *  ixgbe_start_hw - Prepare hardware for TX/RX
+ *  ixgbe_start_hw_generic - Prepare hardware for Tx/Rx
  *  @hw: pointer to hardware structure
  *
  *  Starts the hardware by filling the bus info structure and media type, clears
@@ -54,7 +61,7 @@
  *  table, VLAN filter table, calls routine to set up link and flow control
  *  settings, and leaves transmit and receive units disabled and uninitialized
  **/
-s32 ixgbe_start_hw(struct ixgbe_hw *hw)
+s32 ixgbe_start_hw_generic(struct ixgbe_hw *hw)
 {
 	u32 ctrl_ext;
 
@@ -62,22 +69,22 @@
 	hw->phy.media_type = hw->mac.ops.get_media_type(hw);
 
 	/* Identify the PHY */
-	ixgbe_identify_phy(hw);
+	hw->phy.ops.identify(hw);
 
 	/*
 	 * Store MAC address from RAR0, clear receive address registers, and
 	 * clear the multicast table
 	 */
-	ixgbe_init_rx_addrs(hw);
+	hw->mac.ops.init_rx_addrs(hw);
 
 	/* Clear the VLAN filter table */
-	ixgbe_clear_vfta(hw);
+	hw->mac.ops.clear_vfta(hw);
 
 	/* Set up link */
 	hw->mac.ops.setup_link(hw);
 
 	/* Clear statistics registers */
-	ixgbe_clear_hw_cntrs(hw);
+	hw->mac.ops.clear_hw_cntrs(hw);
 
 	/* Set No Snoop Disable */
 	ctrl_ext = IXGBE_READ_REG(hw, IXGBE_CTRL_EXT);
@@ -92,34 +99,34 @@
 }
 
 /**
- *  ixgbe_init_hw - Generic hardware initialization
+ *  ixgbe_init_hw_generic - Generic hardware initialization
  *  @hw: pointer to hardware structure
  *
- *  Initialize the hardware by reseting the hardware, filling the bus info
+ *  Initialize the hardware by resetting the hardware, filling the bus info
  *  structure and media type, clears all on chip counters, initializes receive
  *  address registers, multicast table, VLAN filter table, calls routine to set
  *  up link and flow control settings, and leaves transmit and receive units
  *  disabled and uninitialized
  **/
-s32 ixgbe_init_hw(struct ixgbe_hw *hw)
+s32 ixgbe_init_hw_generic(struct ixgbe_hw *hw)
 {
 	/* Reset the hardware */
-	hw->mac.ops.reset(hw);
+	hw->mac.ops.reset_hw(hw);
 
 	/* Start the HW */
-	ixgbe_start_hw(hw);
+	hw->mac.ops.start_hw(hw);
 
 	return 0;
 }
 
 /**
- *  ixgbe_clear_hw_cntrs - Generic clear hardware counters
+ *  ixgbe_clear_hw_cntrs_generic - Generic clear hardware counters
  *  @hw: pointer to hardware structure
  *
  *  Clears all hardware statistics counters by reading them from the hardware
  *  Statistics counters are clear on read.
  **/
-static s32 ixgbe_clear_hw_cntrs(struct ixgbe_hw *hw)
+s32 ixgbe_clear_hw_cntrs_generic(struct ixgbe_hw *hw)
 {
 	u16 i = 0;
 
@@ -191,7 +198,36 @@
 }
 
 /**
- *  ixgbe_get_mac_addr - Generic get MAC address
+ *  ixgbe_read_pba_num_generic - Reads part number from EEPROM
+ *  @hw: pointer to hardware structure
+ *  @pba_num: stores the part number from the EEPROM
+ *
+ *  Reads the part number from the EEPROM.
+ **/
+s32 ixgbe_read_pba_num_generic(struct ixgbe_hw *hw, u32 *pba_num)
+{
+	s32 ret_val;
+	u16 data;
+
+	ret_val = hw->eeprom.ops.read(hw, IXGBE_PBANUM0_PTR, &data);
+	if (ret_val) {
+		hw_dbg(hw, "NVM Read Error\n");
+		return ret_val;
+	}
+	*pba_num = (u32)(data << 16);
+
+	ret_val = hw->eeprom.ops.read(hw, IXGBE_PBANUM1_PTR, &data);
+	if (ret_val) {
+		hw_dbg(hw, "NVM Read Error\n");
+		return ret_val;
+	}
+	*pba_num |= data;
+
+	return 0;
+}
+
+/**
+ *  ixgbe_get_mac_addr_generic - Generic get MAC address
  *  @hw: pointer to hardware structure
  *  @mac_addr: Adapter MAC address
  *
@@ -199,7 +235,7 @@
  *  A reset of the adapter must be performed prior to calling this function
  *  in order for the MAC address to have been loaded from the EEPROM into RAR0
  **/
-s32 ixgbe_get_mac_addr(struct ixgbe_hw *hw, u8 *mac_addr)
+s32 ixgbe_get_mac_addr_generic(struct ixgbe_hw *hw, u8 *mac_addr)
 {
 	u32 rar_high;
 	u32 rar_low;
@@ -217,30 +253,8 @@
 	return 0;
 }
 
-s32 ixgbe_read_part_num(struct ixgbe_hw *hw, u32 *part_num)
-{
-	s32 ret_val;
-	u16 data;
-
-	ret_val = ixgbe_read_eeprom(hw, IXGBE_PBANUM0_PTR, &data);
-	if (ret_val) {
-		hw_dbg(hw, "NVM Read Error\n");
-		return ret_val;
-	}
-	*part_num = (u32)(data << 16);
-
-	ret_val = ixgbe_read_eeprom(hw, IXGBE_PBANUM1_PTR, &data);
-	if (ret_val) {
-		hw_dbg(hw, "NVM Read Error\n");
-		return ret_val;
-	}
-	*part_num |= data;
-
-	return 0;
-}
-
 /**
- *  ixgbe_stop_adapter - Generic stop TX/RX units
+ *  ixgbe_stop_adapter_generic - Generic stop Tx/Rx units
  *  @hw: pointer to hardware structure
  *
  *  Sets the adapter_stopped flag within ixgbe_hw struct. Clears interrupts,
@@ -248,7 +262,7 @@
  *  the shared code and drivers to determine if the adapter is in a stopped
  *  state and should not touch the hardware.
  **/
-s32 ixgbe_stop_adapter(struct ixgbe_hw *hw)
+s32 ixgbe_stop_adapter_generic(struct ixgbe_hw *hw)
 {
 	u32 number_of_queues;
 	u32 reg_val;
@@ -264,6 +278,7 @@
 	reg_val = IXGBE_READ_REG(hw, IXGBE_RXCTRL);
 	reg_val &= ~(IXGBE_RXCTRL_RXEN);
 	IXGBE_WRITE_REG(hw, IXGBE_RXCTRL, reg_val);
+	IXGBE_WRITE_FLUSH(hw);
 	msleep(2);
 
 	/* Clear interrupt mask to stop from interrupts being generated */
@@ -273,7 +288,7 @@
 	IXGBE_READ_REG(hw, IXGBE_EICR);
 
 	/* Disable the transmit unit.  Each queue must be disabled. */
-	number_of_queues = hw->mac.num_tx_queues;
+	number_of_queues = hw->mac.max_tx_queues;
 	for (i = 0; i < number_of_queues; i++) {
 		reg_val = IXGBE_READ_REG(hw, IXGBE_TXDCTL(i));
 		if (reg_val & IXGBE_TXDCTL_ENABLE) {
@@ -282,15 +297,22 @@
 		}
 	}
 
+	/*
+	 * Prevent the PCI-E bus from from hanging by disabling PCI-E master
+	 * access and verify no pending requests
+	 */
+	if (ixgbe_disable_pcie_master(hw) != 0)
+		hw_dbg(hw, "PCI-E Master disable polling has failed.\n");
+
 	return 0;
 }
 
 /**
- *  ixgbe_led_on - Turns on the software controllable LEDs.
+ *  ixgbe_led_on_generic - Turns on the software controllable LEDs.
  *  @hw: pointer to hardware structure
  *  @index: led number to turn on
  **/
-s32 ixgbe_led_on(struct ixgbe_hw *hw, u32 index)
+s32 ixgbe_led_on_generic(struct ixgbe_hw *hw, u32 index)
 {
 	u32 led_reg = IXGBE_READ_REG(hw, IXGBE_LEDCTL);
 
@@ -304,11 +326,11 @@
 }
 
 /**
- *  ixgbe_led_off - Turns off the software controllable LEDs.
+ *  ixgbe_led_off_generic - Turns off the software controllable LEDs.
  *  @hw: pointer to hardware structure
  *  @index: led number to turn off
  **/
-s32 ixgbe_led_off(struct ixgbe_hw *hw, u32 index)
+s32 ixgbe_led_off_generic(struct ixgbe_hw *hw, u32 index)
 {
 	u32 led_reg = IXGBE_READ_REG(hw, IXGBE_LEDCTL);
 
@@ -321,15 +343,14 @@
 	return 0;
 }
 
-
 /**
- *  ixgbe_init_eeprom - Initialize EEPROM params
+ *  ixgbe_init_eeprom_params_generic - Initialize EEPROM params
  *  @hw: pointer to hardware structure
  *
  *  Initializes the EEPROM parameters ixgbe_eeprom_info within the
  *  ixgbe_hw struct in order to set up EEPROM access.
  **/
-s32 ixgbe_init_eeprom(struct ixgbe_hw *hw)
+s32 ixgbe_init_eeprom_params_generic(struct ixgbe_hw *hw)
 {
 	struct ixgbe_eeprom_info *eeprom = &hw->eeprom;
 	u32 eec;
@@ -337,6 +358,9 @@
 
 	if (eeprom->type == ixgbe_eeprom_uninitialized) {
 		eeprom->type = ixgbe_eeprom_none;
+		/* Set default semaphore delay to 10ms which is a well
+		 * tested value */
+		eeprom->semaphore_delay = 10;
 
 		/*
 		 * Check for EEPROM present first.
@@ -369,18 +393,85 @@
 }
 
 /**
- *  ixgbe_read_eeprom - Read EEPROM word using EERD
+ *  ixgbe_read_eeprom_bit_bang_generic - Read EEPROM word using bit-bang
+ *  @hw: pointer to hardware structure
+ *  @offset: offset within the EEPROM to be read
+ *  @data: read 16 bit value from EEPROM
+ *
+ *  Reads 16 bit value from EEPROM through bit-bang method
+ **/
+s32 ixgbe_read_eeprom_bit_bang_generic(struct ixgbe_hw *hw, u16 offset,
+                                       u16 *data)
+{
+	s32 status;
+	u16 word_in;
+	u8 read_opcode = IXGBE_EEPROM_READ_OPCODE_SPI;
+
+	hw->eeprom.ops.init_params(hw);
+
+	if (offset >= hw->eeprom.word_size) {
+		status = IXGBE_ERR_EEPROM;
+		goto out;
+	}
+
+	/* Prepare the EEPROM for reading  */
+	status = ixgbe_acquire_eeprom(hw);
+
+	if (status == 0) {
+		if (ixgbe_ready_eeprom(hw) != 0) {
+			ixgbe_release_eeprom(hw);
+			status = IXGBE_ERR_EEPROM;
+		}
+	}
+
+	if (status == 0) {
+		ixgbe_standby_eeprom(hw);
+
+		/*
+		 * Some SPI eeproms use the 8th address bit embedded in the
+		 * opcode
+		 */
+		if ((hw->eeprom.address_bits == 8) && (offset >= 128))
+			read_opcode |= IXGBE_EEPROM_A8_OPCODE_SPI;
+
+		/* Send the READ command (opcode + addr) */
+		ixgbe_shift_out_eeprom_bits(hw, read_opcode,
+		                            IXGBE_EEPROM_OPCODE_BITS);
+		ixgbe_shift_out_eeprom_bits(hw, (u16)(offset*2),
+		                            hw->eeprom.address_bits);
+
+		/* Read the data. */
+		word_in = ixgbe_shift_in_eeprom_bits(hw, 16);
+		*data = (word_in >> 8) | (word_in << 8);
+
+		/* End this read operation */
+		ixgbe_release_eeprom(hw);
+	}
+
+out:
+	return status;
+}
+
+/**
+ *  ixgbe_read_eeprom_generic - Read EEPROM word using EERD
  *  @hw: pointer to hardware structure
  *  @offset: offset of  word in the EEPROM to read
  *  @data: word read from the EEPROM
  *
  *  Reads a 16 bit word from the EEPROM using the EERD register.
  **/
-s32 ixgbe_read_eeprom(struct ixgbe_hw *hw, u16 offset, u16 *data)
+s32 ixgbe_read_eeprom_generic(struct ixgbe_hw *hw, u16 offset, u16 *data)
 {
 	u32 eerd;
 	s32 status;
 
+	hw->eeprom.ops.init_params(hw);
+
+	if (offset >= hw->eeprom.word_size) {
+		status = IXGBE_ERR_EEPROM;
+		goto out;
+	}
+
 	eerd = (offset << IXGBE_EEPROM_READ_ADDR_SHIFT) +
 	       IXGBE_EEPROM_READ_REG_START;
 
@@ -389,10 +480,11 @@
 
 	if (status == 0)
 		*data = (IXGBE_READ_REG(hw, IXGBE_EERD) >>
-			IXGBE_EEPROM_READ_REG_DATA);
+		         IXGBE_EEPROM_READ_REG_DATA);
 	else
 		hw_dbg(hw, "Eeprom read timed out\n");
 
+out:
 	return status;
 }
 
@@ -420,6 +512,58 @@
 }
 
 /**
+ *  ixgbe_acquire_eeprom - Acquire EEPROM using bit-bang
+ *  @hw: pointer to hardware structure
+ *
+ *  Prepares EEPROM for access using bit-bang method. This function should
+ *  be called before issuing a command to the EEPROM.
+ **/
+static s32 ixgbe_acquire_eeprom(struct ixgbe_hw *hw)
+{
+	s32 status = 0;
+	u32 eec;
+	u32 i;
+
+	if (ixgbe_acquire_swfw_sync(hw, IXGBE_GSSR_EEP_SM) != 0)
+		status = IXGBE_ERR_SWFW_SYNC;
+
+	if (status == 0) {
+		eec = IXGBE_READ_REG(hw, IXGBE_EEC);
+
+		/* Request EEPROM Access */
+		eec |= IXGBE_EEC_REQ;
+		IXGBE_WRITE_REG(hw, IXGBE_EEC, eec);
+
+		for (i = 0; i < IXGBE_EEPROM_GRANT_ATTEMPTS; i++) {
+			eec = IXGBE_READ_REG(hw, IXGBE_EEC);
+			if (eec & IXGBE_EEC_GNT)
+				break;
+			udelay(5);
+		}
+
+		/* Release if grant not acquired */
+		if (!(eec & IXGBE_EEC_GNT)) {
+			eec &= ~IXGBE_EEC_REQ;
+			IXGBE_WRITE_REG(hw, IXGBE_EEC, eec);
+			hw_dbg(hw, "Could not acquire EEPROM grant\n");
+
+			ixgbe_release_swfw_sync(hw, IXGBE_GSSR_EEP_SM);
+			status = IXGBE_ERR_EEPROM;
+		}
+	}
+
+	/* Setup EEPROM for Read/Write */
+	if (status == 0) {
+		/* Clear CS and SK */
+		eec &= ~(IXGBE_EEC_CS | IXGBE_EEC_SK);
+		IXGBE_WRITE_REG(hw, IXGBE_EEC, eec);
+		IXGBE_WRITE_FLUSH(hw);
+		udelay(1);
+	}
+	return status;
+}
+
+/**
  *  ixgbe_get_eeprom_semaphore - Get hardware semaphore
  *  @hw: pointer to hardware structure
  *
@@ -475,7 +619,7 @@
 		 */
 		if (i >= timeout) {
 			hw_dbg(hw, "Driver can't access the Eeprom - Semaphore "
-				 "not granted.\n");
+			       "not granted.\n");
 			ixgbe_release_eeprom_semaphore(hw);
 			status = IXGBE_ERR_EEPROM;
 		}
@@ -503,6 +647,217 @@
 }
 
 /**
+ *  ixgbe_ready_eeprom - Polls for EEPROM ready
+ *  @hw: pointer to hardware structure
+ **/
+static s32 ixgbe_ready_eeprom(struct ixgbe_hw *hw)
+{
+	s32 status = 0;
+	u16 i;
+	u8 spi_stat_reg;
+
+	/*
+	 * Read "Status Register" repeatedly until the LSB is cleared.  The
+	 * EEPROM will signal that the command has been completed by clearing
+	 * bit 0 of the internal status register.  If it's not cleared within
+	 * 5 milliseconds, then error out.
+	 */
+	for (i = 0; i < IXGBE_EEPROM_MAX_RETRY_SPI; i += 5) {
+		ixgbe_shift_out_eeprom_bits(hw, IXGBE_EEPROM_RDSR_OPCODE_SPI,
+		                            IXGBE_EEPROM_OPCODE_BITS);
+		spi_stat_reg = (u8)ixgbe_shift_in_eeprom_bits(hw, 8);
+		if (!(spi_stat_reg & IXGBE_EEPROM_STATUS_RDY_SPI))
+			break;
+
+		udelay(5);
+		ixgbe_standby_eeprom(hw);
+	};
+
+	/*
+	 * On some parts, SPI write time could vary from 0-20mSec on 3.3V
+	 * devices (and only 0-5mSec on 5V devices)
+	 */
+	if (i >= IXGBE_EEPROM_MAX_RETRY_SPI) {
+		hw_dbg(hw, "SPI EEPROM Status error\n");
+		status = IXGBE_ERR_EEPROM;
+	}
+
+	return status;
+}
+
+/**
+ *  ixgbe_standby_eeprom - Returns EEPROM to a "standby" state
+ *  @hw: pointer to hardware structure
+ **/
+static void ixgbe_standby_eeprom(struct ixgbe_hw *hw)
+{
+	u32 eec;
+
+	eec = IXGBE_READ_REG(hw, IXGBE_EEC);
+
+	/* Toggle CS to flush commands */
+	eec |= IXGBE_EEC_CS;
+	IXGBE_WRITE_REG(hw, IXGBE_EEC, eec);
+	IXGBE_WRITE_FLUSH(hw);
+	udelay(1);
+	eec &= ~IXGBE_EEC_CS;
+	IXGBE_WRITE_REG(hw, IXGBE_EEC, eec);
+	IXGBE_WRITE_FLUSH(hw);
+	udelay(1);
+}
+
+/**
+ *  ixgbe_shift_out_eeprom_bits - Shift data bits out to the EEPROM.
+ *  @hw: pointer to hardware structure
+ *  @data: data to send to the EEPROM
+ *  @count: number of bits to shift out
+ **/
+static void ixgbe_shift_out_eeprom_bits(struct ixgbe_hw *hw, u16 data,
+                                        u16 count)
+{
+	u32 eec;
+	u32 mask;
+	u32 i;
+
+	eec = IXGBE_READ_REG(hw, IXGBE_EEC);
+
+	/*
+	 * Mask is used to shift "count" bits of "data" out to the EEPROM
+	 * one bit at a time.  Determine the starting bit based on count
+	 */
+	mask = 0x01 << (count - 1);
+
+	for (i = 0; i < count; i++) {
+		/*
+		 * A "1" is shifted out to the EEPROM by setting bit "DI" to a
+		 * "1", and then raising and then lowering the clock (the SK
+		 * bit controls the clock input to the EEPROM).  A "0" is
+		 * shifted out to the EEPROM by setting "DI" to "0" and then
+		 * raising and then lowering the clock.
+		 */
+		if (data & mask)
+			eec |= IXGBE_EEC_DI;
+		else
+			eec &= ~IXGBE_EEC_DI;
+
+		IXGBE_WRITE_REG(hw, IXGBE_EEC, eec);
+		IXGBE_WRITE_FLUSH(hw);
+
+		udelay(1);
+
+		ixgbe_raise_eeprom_clk(hw, &eec);
+		ixgbe_lower_eeprom_clk(hw, &eec);
+
+		/*
+		 * Shift mask to signify next bit of data to shift in to the
+		 * EEPROM
+		 */
+		mask = mask >> 1;
+	};
+
+	/* We leave the "DI" bit set to "0" when we leave this routine. */
+	eec &= ~IXGBE_EEC_DI;
+	IXGBE_WRITE_REG(hw, IXGBE_EEC, eec);
+	IXGBE_WRITE_FLUSH(hw);
+}
+
+/**
+ *  ixgbe_shift_in_eeprom_bits - Shift data bits in from the EEPROM
+ *  @hw: pointer to hardware structure
+ **/
+static u16 ixgbe_shift_in_eeprom_bits(struct ixgbe_hw *hw, u16 count)
+{
+	u32 eec;
+	u32 i;
+	u16 data = 0;
+
+	/*
+	 * In order to read a register from the EEPROM, we need to shift
+	 * 'count' bits in from the EEPROM. Bits are "shifted in" by raising
+	 * the clock input to the EEPROM (setting the SK bit), and then reading
+	 * the value of the "DO" bit.  During this "shifting in" process the
+	 * "DI" bit should always be clear.
+	 */
+	eec = IXGBE_READ_REG(hw, IXGBE_EEC);
+
+	eec &= ~(IXGBE_EEC_DO | IXGBE_EEC_DI);
+
+	for (i = 0; i < count; i++) {
+		data = data << 1;
+		ixgbe_raise_eeprom_clk(hw, &eec);
+
+		eec = IXGBE_READ_REG(hw, IXGBE_EEC);
+
+		eec &= ~(IXGBE_EEC_DI);
+		if (eec & IXGBE_EEC_DO)
+			data |= 1;
+
+		ixgbe_lower_eeprom_clk(hw, &eec);
+	}
+
+	return data;
+}
+
+/**
+ *  ixgbe_raise_eeprom_clk - Raises the EEPROM's clock input.
+ *  @hw: pointer to hardware structure
+ *  @eec: EEC register's current value
+ **/
+static void ixgbe_raise_eeprom_clk(struct ixgbe_hw *hw, u32 *eec)
+{
+	/*
+	 * Raise the clock input to the EEPROM
+	 * (setting the SK bit), then delay
+	 */
+	*eec = *eec | IXGBE_EEC_SK;
+	IXGBE_WRITE_REG(hw, IXGBE_EEC, *eec);
+	IXGBE_WRITE_FLUSH(hw);
+	udelay(1);
+}
+
+/**
+ *  ixgbe_lower_eeprom_clk - Lowers the EEPROM's clock input.
+ *  @hw: pointer to hardware structure
+ *  @eecd: EECD's current value
+ **/
+static void ixgbe_lower_eeprom_clk(struct ixgbe_hw *hw, u32 *eec)
+{
+	/*
+	 * Lower the clock input to the EEPROM (clearing the SK bit), then
+	 * delay
+	 */
+	*eec = *eec & ~IXGBE_EEC_SK;
+	IXGBE_WRITE_REG(hw, IXGBE_EEC, *eec);
+	IXGBE_WRITE_FLUSH(hw);
+	udelay(1);
+}
+
+/**
+ *  ixgbe_release_eeprom - Release EEPROM, release semaphores
+ *  @hw: pointer to hardware structure
+ **/
+static void ixgbe_release_eeprom(struct ixgbe_hw *hw)
+{
+	u32 eec;
+
+	eec = IXGBE_READ_REG(hw, IXGBE_EEC);
+
+	eec |= IXGBE_EEC_CS;  /* Pull CS high */
+	eec &= ~IXGBE_EEC_SK; /* Lower SCK */
+
+	IXGBE_WRITE_REG(hw, IXGBE_EEC, eec);
+	IXGBE_WRITE_FLUSH(hw);
+
+	udelay(1);
+
+	/* Stop requesting EEPROM access */
+	eec &= ~IXGBE_EEC_REQ;
+	IXGBE_WRITE_REG(hw, IXGBE_EEC, eec);
+
+	ixgbe_release_swfw_sync(hw, IXGBE_GSSR_EEP_SM);
+}
+
+/**
  *  ixgbe_calc_eeprom_checksum - Calculates and returns the checksum
  *  @hw: pointer to hardware structure
  **/
@@ -517,7 +872,7 @@
 
 	/* Include 0x0-0x3F in the checksum */
 	for (i = 0; i < IXGBE_EEPROM_CHECKSUM; i++) {
-		if (ixgbe_read_eeprom(hw, i, &word) != 0) {
+		if (hw->eeprom.ops.read(hw, i, &word) != 0) {
 			hw_dbg(hw, "EEPROM read failed\n");
 			break;
 		}
@@ -526,15 +881,15 @@
 
 	/* Include all data from pointers except for the fw pointer */
 	for (i = IXGBE_PCIE_ANALOG_PTR; i < IXGBE_FW_PTR; i++) {
-		ixgbe_read_eeprom(hw, i, &pointer);
+		hw->eeprom.ops.read(hw, i, &pointer);
 
 		/* Make sure the pointer seems valid */
 		if (pointer != 0xFFFF && pointer != 0) {
-			ixgbe_read_eeprom(hw, pointer, &length);
+			hw->eeprom.ops.read(hw, pointer, &length);
 
 			if (length != 0xFFFF && length != 0) {
 				for (j = pointer+1; j <= pointer+length; j++) {
-					ixgbe_read_eeprom(hw, j, &word);
+					hw->eeprom.ops.read(hw, j, &word);
 					checksum += word;
 				}
 			}
@@ -547,14 +902,15 @@
 }
 
 /**
- *  ixgbe_validate_eeprom_checksum - Validate EEPROM checksum
+ *  ixgbe_validate_eeprom_checksum_generic - Validate EEPROM checksum
  *  @hw: pointer to hardware structure
  *  @checksum_val: calculated checksum
  *
  *  Performs checksum calculation and validates the EEPROM checksum.  If the
  *  caller does not need checksum_val, the value can be NULL.
  **/
-s32 ixgbe_validate_eeprom_checksum(struct ixgbe_hw *hw, u16 *checksum_val)
+s32 ixgbe_validate_eeprom_checksum_generic(struct ixgbe_hw *hw,
+                                           u16 *checksum_val)
 {
 	s32 status;
 	u16 checksum;
@@ -565,12 +921,12 @@
 	 * not continue or we could be in for a very long wait while every
 	 * EEPROM read fails
 	 */
-	status = ixgbe_read_eeprom(hw, 0, &checksum);
+	status = hw->eeprom.ops.read(hw, 0, &checksum);
 
 	if (status == 0) {
 		checksum = ixgbe_calc_eeprom_checksum(hw);
 
-		ixgbe_read_eeprom(hw, IXGBE_EEPROM_CHECKSUM, &read_checksum);
+		hw->eeprom.ops.read(hw, IXGBE_EEPROM_CHECKSUM, &read_checksum);
 
 		/*
 		 * Verify read checksum from EEPROM is the same as
@@ -590,6 +946,33 @@
 }
 
 /**
+ *  ixgbe_update_eeprom_checksum_generic - Updates the EEPROM checksum
+ *  @hw: pointer to hardware structure
+ **/
+s32 ixgbe_update_eeprom_checksum_generic(struct ixgbe_hw *hw)
+{
+	s32 status;
+	u16 checksum;
+
+	/*
+	 * Read the first word from the EEPROM. If this times out or fails, do
+	 * not continue or we could be in for a very long wait while every
+	 * EEPROM read fails
+	 */
+	status = hw->eeprom.ops.read(hw, 0, &checksum);
+
+	if (status == 0) {
+		checksum = ixgbe_calc_eeprom_checksum(hw);
+		status = hw->eeprom.ops.write(hw, IXGBE_EEPROM_CHECKSUM,
+		                            checksum);
+	} else {
+		hw_dbg(hw, "EEPROM read failed\n");
+	}
+
+	return status;
+}
+
+/**
  *  ixgbe_validate_mac_addr - Validate MAC address
  *  @mac_addr: pointer to MAC address.
  *
@@ -607,61 +990,140 @@
 		status = IXGBE_ERR_INVALID_MAC_ADDR;
 	/* Reject the zero address */
 	else if (mac_addr[0] == 0 && mac_addr[1] == 0 && mac_addr[2] == 0 &&
-		 mac_addr[3] == 0 && mac_addr[4] == 0 && mac_addr[5] == 0)
+	         mac_addr[3] == 0 && mac_addr[4] == 0 && mac_addr[5] == 0)
 		status = IXGBE_ERR_INVALID_MAC_ADDR;
 
 	return status;
 }
 
 /**
- *  ixgbe_set_rar - Set RX address register
+ *  ixgbe_set_rar_generic - Set Rx address register
  *  @hw: pointer to hardware structure
- *  @addr: Address to put into receive address register
  *  @index: Receive address register to write
- *  @vind: Vind to set RAR to
+ *  @addr: Address to put into receive address register
+ *  @vmdq: VMDq "set" or "pool" index
  *  @enable_addr: set flag that address is active
  *
  *  Puts an ethernet address into a receive address register.
  **/
-s32 ixgbe_set_rar(struct ixgbe_hw *hw, u32 index, u8 *addr, u32 vind,
-		  u32 enable_addr)
+s32 ixgbe_set_rar_generic(struct ixgbe_hw *hw, u32 index, u8 *addr, u32 vmdq,
+                          u32 enable_addr)
 {
 	u32 rar_low, rar_high;
+	u32 rar_entries = hw->mac.num_rar_entries;
 
-	/*
-	 * HW expects these in little endian so we reverse the byte order from
-	 * network order (big endian) to little endian
-	 */
-	rar_low = ((u32)addr[0] |
-		   ((u32)addr[1] << 8) |
-		   ((u32)addr[2] << 16) |
-		   ((u32)addr[3] << 24));
+	/* setup VMDq pool selection before this RAR gets enabled */
+	hw->mac.ops.set_vmdq(hw, index, vmdq);
 
-	rar_high = ((u32)addr[4] |
-		    ((u32)addr[5] << 8) |
-		    ((vind << IXGBE_RAH_VIND_SHIFT) & IXGBE_RAH_VIND_MASK));
+	/* Make sure we are using a valid rar index range */
+	if (index < rar_entries) {
+		/*
+		 * HW expects these in little endian so we reverse the byte
+		 * order from network order (big endian) to little endian
+		 */
+		rar_low = ((u32)addr[0] |
+		           ((u32)addr[1] << 8) |
+		           ((u32)addr[2] << 16) |
+		           ((u32)addr[3] << 24));
+		/*
+		 * Some parts put the VMDq setting in the extra RAH bits,
+		 * so save everything except the lower 16 bits that hold part
+		 * of the address and the address valid bit.
+		 */
+		rar_high = IXGBE_READ_REG(hw, IXGBE_RAH(index));
+		rar_high &= ~(0x0000FFFF | IXGBE_RAH_AV);
+		rar_high |= ((u32)addr[4] | ((u32)addr[5] << 8));
 
-	if (enable_addr != 0)
-		rar_high |= IXGBE_RAH_AV;
+		if (enable_addr != 0)
+			rar_high |= IXGBE_RAH_AV;
 
-	IXGBE_WRITE_REG(hw, IXGBE_RAL(index), rar_low);
-	IXGBE_WRITE_REG(hw, IXGBE_RAH(index), rar_high);
+		IXGBE_WRITE_REG(hw, IXGBE_RAL(index), rar_low);
+		IXGBE_WRITE_REG(hw, IXGBE_RAH(index), rar_high);
+	} else {
+		hw_dbg(hw, "RAR index %d is out of range.\n", index);
+	}
 
 	return 0;
 }
 
 /**
- *  ixgbe_init_rx_addrs - Initializes receive address filters.
+ *  ixgbe_clear_rar_generic - Remove Rx address register
+ *  @hw: pointer to hardware structure
+ *  @index: Receive address register to write
+ *
+ *  Clears an ethernet address from a receive address register.
+ **/
+s32 ixgbe_clear_rar_generic(struct ixgbe_hw *hw, u32 index)
+{
+	u32 rar_high;
+	u32 rar_entries = hw->mac.num_rar_entries;
+
+	/* Make sure we are using a valid rar index range */
+	if (index < rar_entries) {
+		/*
+		 * Some parts put the VMDq setting in the extra RAH bits,
+		 * so save everything except the lower 16 bits that hold part
+		 * of the address and the address valid bit.
+		 */
+		rar_high = IXGBE_READ_REG(hw, IXGBE_RAH(index));
+		rar_high &= ~(0x0000FFFF | IXGBE_RAH_AV);
+
+		IXGBE_WRITE_REG(hw, IXGBE_RAL(index), 0);
+		IXGBE_WRITE_REG(hw, IXGBE_RAH(index), rar_high);
+	} else {
+		hw_dbg(hw, "RAR index %d is out of range.\n", index);
+	}
+
+	/* clear VMDq pool/queue selection for this RAR */
+	hw->mac.ops.clear_vmdq(hw, index, IXGBE_CLEAR_VMDQ_ALL);
+
+	return 0;
+}
+
+/**
+ *  ixgbe_enable_rar - Enable Rx address register
+ *  @hw: pointer to hardware structure
+ *  @index: index into the RAR table
+ *
+ *  Enables the select receive address register.
+ **/
+static void ixgbe_enable_rar(struct ixgbe_hw *hw, u32 index)
+{
+	u32 rar_high;
+
+	rar_high = IXGBE_READ_REG(hw, IXGBE_RAH(index));
+	rar_high |= IXGBE_RAH_AV;
+	IXGBE_WRITE_REG(hw, IXGBE_RAH(index), rar_high);
+}
+
+/**
+ *  ixgbe_disable_rar - Disable Rx address register
+ *  @hw: pointer to hardware structure
+ *  @index: index into the RAR table
+ *
+ *  Disables the select receive address register.
+ **/
+static void ixgbe_disable_rar(struct ixgbe_hw *hw, u32 index)
+{
+	u32 rar_high;
+
+	rar_high = IXGBE_READ_REG(hw, IXGBE_RAH(index));
+	rar_high &= (~IXGBE_RAH_AV);
+	IXGBE_WRITE_REG(hw, IXGBE_RAH(index), rar_high);
+}
+
+/**
+ *  ixgbe_init_rx_addrs_generic - Initializes receive address filters.
  *  @hw: pointer to hardware structure
  *
  *  Places the MAC address in receive address register 0 and clears the rest
- *  of the receive addresss registers. Clears the multicast table. Assumes
+ *  of the receive address registers. Clears the multicast table. Assumes
  *  the receiver is in reset when the routine is called.
  **/
-static s32 ixgbe_init_rx_addrs(struct ixgbe_hw *hw)
+s32 ixgbe_init_rx_addrs_generic(struct ixgbe_hw *hw)
 {
 	u32 i;
-	u32 rar_entries = hw->mac.num_rx_addrs;
+	u32 rar_entries = hw->mac.num_rar_entries;
 
 	/*
 	 * If the current mac address is valid, assume it is a software override
@@ -671,29 +1133,30 @@
 	if (ixgbe_validate_mac_addr(hw->mac.addr) ==
 	    IXGBE_ERR_INVALID_MAC_ADDR) {
 		/* Get the MAC address from the RAR0 for later reference */
-		ixgbe_get_mac_addr(hw, hw->mac.addr);
+		hw->mac.ops.get_mac_addr(hw, hw->mac.addr);
 
 		hw_dbg(hw, " Keeping Current RAR0 Addr =%.2X %.2X %.2X ",
-			  hw->mac.addr[0], hw->mac.addr[1],
-			  hw->mac.addr[2]);
+		       hw->mac.addr[0], hw->mac.addr[1],
+		       hw->mac.addr[2]);
 		hw_dbg(hw, "%.2X %.2X %.2X\n", hw->mac.addr[3],
-			  hw->mac.addr[4], hw->mac.addr[5]);
+		       hw->mac.addr[4], hw->mac.addr[5]);
 	} else {
 		/* Setup the receive address. */
 		hw_dbg(hw, "Overriding MAC Address in RAR[0]\n");
 		hw_dbg(hw, " New MAC Addr =%.2X %.2X %.2X ",
-			  hw->mac.addr[0], hw->mac.addr[1],
-			  hw->mac.addr[2]);
+		       hw->mac.addr[0], hw->mac.addr[1],
+		       hw->mac.addr[2]);
 		hw_dbg(hw, "%.2X %.2X %.2X\n", hw->mac.addr[3],
-			  hw->mac.addr[4], hw->mac.addr[5]);
+		       hw->mac.addr[4], hw->mac.addr[5]);
 
-		ixgbe_set_rar(hw, 0, hw->mac.addr, 0, IXGBE_RAH_AV);
+		hw->mac.ops.set_rar(hw, 0, hw->mac.addr, 0, IXGBE_RAH_AV);
 	}
+	hw->addr_ctrl.overflow_promisc = 0;
 
 	hw->addr_ctrl.rar_used_count = 1;
 
 	/* Zero out the other receive addresses. */
-	hw_dbg(hw, "Clearing RAR[1-15]\n");
+	hw_dbg(hw, "Clearing RAR[1-%d]\n", rar_entries - 1);
 	for (i = 1; i < rar_entries; i++) {
 		IXGBE_WRITE_REG(hw, IXGBE_RAL(i), 0);
 		IXGBE_WRITE_REG(hw, IXGBE_RAH(i), 0);
@@ -705,9 +1168,113 @@
 	IXGBE_WRITE_REG(hw, IXGBE_MCSTCTRL, hw->mac.mc_filter_type);
 
 	hw_dbg(hw, " Clearing MTA\n");
-	for (i = 0; i < IXGBE_MC_TBL_SIZE; i++)
+	for (i = 0; i < hw->mac.mcft_size; i++)
 		IXGBE_WRITE_REG(hw, IXGBE_MTA(i), 0);
 
+	if (hw->mac.ops.init_uta_tables)
+		hw->mac.ops.init_uta_tables(hw);
+
+	return 0;
+}
+
+/**
+ *  ixgbe_add_uc_addr - Adds a secondary unicast address.
+ *  @hw: pointer to hardware structure
+ *  @addr: new address
+ *
+ *  Adds it to unused receive address register or goes into promiscuous mode.
+ **/
+static void ixgbe_add_uc_addr(struct ixgbe_hw *hw, u8 *addr, u32 vmdq)
+{
+	u32 rar_entries = hw->mac.num_rar_entries;
+	u32 rar;
+
+	hw_dbg(hw, " UC Addr = %.2X %.2X %.2X %.2X %.2X %.2X\n",
+	          addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
+
+	/*
+	 * Place this address in the RAR if there is room,
+	 * else put the controller into promiscuous mode
+	 */
+	if (hw->addr_ctrl.rar_used_count < rar_entries) {
+		rar = hw->addr_ctrl.rar_used_count -
+		      hw->addr_ctrl.mc_addr_in_rar_count;
+		hw->mac.ops.set_rar(hw, rar, addr, vmdq, IXGBE_RAH_AV);
+		hw_dbg(hw, "Added a secondary address to RAR[%d]\n", rar);
+		hw->addr_ctrl.rar_used_count++;
+	} else {
+		hw->addr_ctrl.overflow_promisc++;
+	}
+
+	hw_dbg(hw, "ixgbe_add_uc_addr Complete\n");
+}
+
+/**
+ *  ixgbe_update_uc_addr_list_generic - Updates MAC list of secondary addresses
+ *  @hw: pointer to hardware structure
+ *  @addr_list: the list of new addresses
+ *  @addr_count: number of addresses
+ *  @next: iterator function to walk the address list
+ *
+ *  The given list replaces any existing list.  Clears the secondary addrs from
+ *  receive address registers.  Uses unused receive address registers for the
+ *  first secondary addresses, and falls back to promiscuous mode as needed.
+ *
+ *  Drivers using secondary unicast addresses must set user_set_promisc when
+ *  manually putting the device into promiscuous mode.
+ **/
+s32 ixgbe_update_uc_addr_list_generic(struct ixgbe_hw *hw, u8 *addr_list,
+                              u32 addr_count, ixgbe_mc_addr_itr next)
+{
+	u8 *addr;
+	u32 i;
+	u32 old_promisc_setting = hw->addr_ctrl.overflow_promisc;
+	u32 uc_addr_in_use;
+	u32 fctrl;
+	u32 vmdq;
+
+	/*
+	 * Clear accounting of old secondary address list,
+	 * don't count RAR[0]
+	 */
+	uc_addr_in_use = hw->addr_ctrl.rar_used_count -
+	                 hw->addr_ctrl.mc_addr_in_rar_count - 1;
+	hw->addr_ctrl.rar_used_count -= uc_addr_in_use;
+	hw->addr_ctrl.overflow_promisc = 0;
+
+	/* Zero out the other receive addresses */
+	hw_dbg(hw, "Clearing RAR[1-%d]\n", uc_addr_in_use);
+	for (i = 1; i <= uc_addr_in_use; i++) {
+		IXGBE_WRITE_REG(hw, IXGBE_RAL(i), 0);
+		IXGBE_WRITE_REG(hw, IXGBE_RAH(i), 0);
+	}
+
+	/* Add the new addresses */
+	for (i = 0; i < addr_count; i++) {
+		hw_dbg(hw, " Adding the secondary addresses:\n");
+		addr = next(hw, &addr_list, &vmdq);
+		ixgbe_add_uc_addr(hw, addr, vmdq);
+	}
+
+	if (hw->addr_ctrl.overflow_promisc) {
+		/* enable promisc if not already in overflow or set by user */
+		if (!old_promisc_setting && !hw->addr_ctrl.user_set_promisc) {
+			hw_dbg(hw, " Entering address overflow promisc mode\n");
+			fctrl = IXGBE_READ_REG(hw, IXGBE_FCTRL);
+			fctrl |= IXGBE_FCTRL_UPE;
+			IXGBE_WRITE_REG(hw, IXGBE_FCTRL, fctrl);
+		}
+	} else {
+		/* only disable if set by overflow, not by user */
+		if (old_promisc_setting && !hw->addr_ctrl.user_set_promisc) {
+			hw_dbg(hw, " Leaving address overflow promisc mode\n");
+			fctrl = IXGBE_READ_REG(hw, IXGBE_FCTRL);
+			fctrl &= ~IXGBE_FCTRL_UPE;
+			IXGBE_WRITE_REG(hw, IXGBE_FCTRL, fctrl);
+		}
+	}
+
+	hw_dbg(hw, "ixgbe_update_uc_addr_list_generic Complete\n");
 	return 0;
 }
 
@@ -720,7 +1287,7 @@
  *  bit-vector to set in the multicast table. The hardware uses 12 bits, from
  *  incoming rx multicast addresses, to determine the bit-vector to check in
  *  the MTA. Which of the 4 combination, of 12-bits, the hardware uses is set
- *  by the MO field of the MCSTCTRL. The MO field is set during initalization
+ *  by the MO field of the MCSTCTRL. The MO field is set during initialization
  *  to mc_filter_type.
  **/
 static s32 ixgbe_mta_vector(struct ixgbe_hw *hw, u8 *mc_addr)
@@ -728,19 +1295,19 @@
 	u32 vector = 0;
 
 	switch (hw->mac.mc_filter_type) {
-	case 0:	  /* use bits [47:36] of the address */
+	case 0:   /* use bits [47:36] of the address */
 		vector = ((mc_addr[4] >> 4) | (((u16)mc_addr[5]) << 4));
 		break;
-	case 1:	  /* use bits [46:35] of the address */
+	case 1:   /* use bits [46:35] of the address */
 		vector = ((mc_addr[4] >> 3) | (((u16)mc_addr[5]) << 5));
 		break;
-	case 2:	  /* use bits [45:34] of the address */
+	case 2:   /* use bits [45:34] of the address */
 		vector = ((mc_addr[4] >> 2) | (((u16)mc_addr[5]) << 6));
 		break;
-	case 3:	  /* use bits [43:32] of the address */
+	case 3:   /* use bits [43:32] of the address */
 		vector = ((mc_addr[4]) | (((u16)mc_addr[5]) << 8));
 		break;
-	default:	 /* Invalid mc_filter_type */
+	default:  /* Invalid mc_filter_type */
 		hw_dbg(hw, "MC filter type param set incorrectly\n");
 		break;
 	}
@@ -794,21 +1361,22 @@
  **/
 static void ixgbe_add_mc_addr(struct ixgbe_hw *hw, u8 *mc_addr)
 {
-	u32 rar_entries = hw->mac.num_rx_addrs;
+	u32 rar_entries = hw->mac.num_rar_entries;
+	u32 rar;
 
 	hw_dbg(hw, " MC Addr =%.2X %.2X %.2X %.2X %.2X %.2X\n",
-		  mc_addr[0], mc_addr[1], mc_addr[2],
-		  mc_addr[3], mc_addr[4], mc_addr[5]);
+	       mc_addr[0], mc_addr[1], mc_addr[2],
+	       mc_addr[3], mc_addr[4], mc_addr[5]);
 
 	/*
 	 * Place this multicast address in the RAR if there is room,
 	 * else put it in the MTA
 	 */
 	if (hw->addr_ctrl.rar_used_count < rar_entries) {
-		ixgbe_set_rar(hw, hw->addr_ctrl.rar_used_count,
-			      mc_addr, 0, IXGBE_RAH_AV);
-		hw_dbg(hw, "Added a multicast address to RAR[%d]\n",
-			  hw->addr_ctrl.rar_used_count);
+		/* use RAR from the end up for multicast */
+		rar = rar_entries - hw->addr_ctrl.mc_addr_in_rar_count - 1;
+		hw->mac.ops.set_rar(hw, rar, mc_addr, 0, IXGBE_RAH_AV);
+		hw_dbg(hw, "Added a multicast address to RAR[%d]\n", rar);
 		hw->addr_ctrl.rar_used_count++;
 		hw->addr_ctrl.mc_addr_in_rar_count++;
 	} else {
@@ -819,22 +1387,23 @@
 }
 
 /**
- *  ixgbe_update_mc_addr_list - Updates MAC list of multicast addresses
+ *  ixgbe_update_mc_addr_list_generic - Updates MAC list of multicast addresses
  *  @hw: pointer to hardware structure
  *  @mc_addr_list: the list of new multicast addresses
  *  @mc_addr_count: number of addresses
- *  @pad: number of bytes between addresses in the list
+ *  @next: iterator function to walk the multicast address list
  *
  *  The given list replaces any existing list. Clears the MC addrs from receive
- *  address registers and the multicast table. Uses unsed receive address
+ *  address registers and the multicast table. Uses unused receive address
  *  registers for the first multicast addresses, and hashes the rest into the
  *  multicast table.
  **/
-s32 ixgbe_update_mc_addr_list(struct ixgbe_hw *hw, u8 *mc_addr_list,
-			      u32 mc_addr_count, u32 pad)
+s32 ixgbe_update_mc_addr_list_generic(struct ixgbe_hw *hw, u8 *mc_addr_list,
+                                      u32 mc_addr_count, ixgbe_mc_addr_itr next)
 {
 	u32 i;
-	u32 rar_entries = hw->mac.num_rx_addrs;
+	u32 rar_entries = hw->mac.num_rar_entries;
+	u32 vmdq;
 
 	/*
 	 * Set the new number of MC addresses that we are being requested to
@@ -846,7 +1415,8 @@
 	hw->addr_ctrl.mta_in_use = 0;
 
 	/* Zero out the other receive addresses. */
-	hw_dbg(hw, "Clearing RAR[1-15]\n");
+	hw_dbg(hw, "Clearing RAR[%d-%d]\n", hw->addr_ctrl.rar_used_count,
+	          rar_entries - 1);
 	for (i = hw->addr_ctrl.rar_used_count; i < rar_entries; i++) {
 		IXGBE_WRITE_REG(hw, IXGBE_RAL(i), 0);
 		IXGBE_WRITE_REG(hw, IXGBE_RAH(i), 0);
@@ -854,186 +1424,67 @@
 
 	/* Clear the MTA */
 	hw_dbg(hw, " Clearing MTA\n");
-	for (i = 0; i < IXGBE_MC_TBL_SIZE; i++)
+	for (i = 0; i < hw->mac.mcft_size; i++)
 		IXGBE_WRITE_REG(hw, IXGBE_MTA(i), 0);
 
 	/* Add the new addresses */
 	for (i = 0; i < mc_addr_count; i++) {
 		hw_dbg(hw, " Adding the multicast addresses:\n");
-		ixgbe_add_mc_addr(hw, mc_addr_list +
-				  (i * (IXGBE_ETH_LENGTH_OF_ADDRESS + pad)));
+		ixgbe_add_mc_addr(hw, next(hw, &mc_addr_list, &vmdq));
 	}
 
 	/* Enable mta */
 	if (hw->addr_ctrl.mta_in_use > 0)
 		IXGBE_WRITE_REG(hw, IXGBE_MCSTCTRL,
-				IXGBE_MCSTCTRL_MFE | hw->mac.mc_filter_type);
+		                IXGBE_MCSTCTRL_MFE | hw->mac.mc_filter_type);
 
-	hw_dbg(hw, "ixgbe_update_mc_addr_list Complete\n");
+	hw_dbg(hw, "ixgbe_update_mc_addr_list_generic Complete\n");
 	return 0;
 }
 
 /**
- *  ixgbe_clear_vfta - Clear VLAN filter table
+ *  ixgbe_enable_mc_generic - Enable multicast address in RAR
  *  @hw: pointer to hardware structure
  *
- *  Clears the VLAN filer table, and the VMDq index associated with the filter
+ *  Enables multicast address in RAR and the use of the multicast hash table.
  **/
-static s32 ixgbe_clear_vfta(struct ixgbe_hw *hw)
+s32 ixgbe_enable_mc_generic(struct ixgbe_hw *hw)
 {
-	u32 offset;
-	u32 vlanbyte;
+	u32 i;
+	u32 rar_entries = hw->mac.num_rar_entries;
+	struct ixgbe_addr_filter_info *a = &hw->addr_ctrl;
 
-	for (offset = 0; offset < IXGBE_VLAN_FILTER_TBL_SIZE; offset++)
-		IXGBE_WRITE_REG(hw, IXGBE_VFTA(offset), 0);
+	if (a->mc_addr_in_rar_count > 0)
+		for (i = (rar_entries - a->mc_addr_in_rar_count);
+		     i < rar_entries; i++)
+			ixgbe_enable_rar(hw, i);
 
-	for (vlanbyte = 0; vlanbyte < 4; vlanbyte++)
-		for (offset = 0; offset < IXGBE_VLAN_FILTER_TBL_SIZE; offset++)
-			IXGBE_WRITE_REG(hw, IXGBE_VFTAVIND(vlanbyte, offset),
-					0);
+	if (a->mta_in_use > 0)
+		IXGBE_WRITE_REG(hw, IXGBE_MCSTCTRL, IXGBE_MCSTCTRL_MFE |
+		                hw->mac.mc_filter_type);
 
 	return 0;
 }
 
 /**
- *  ixgbe_set_vfta - Set VLAN filter table
+ *  ixgbe_disable_mc_generic - Disable multicast address in RAR
  *  @hw: pointer to hardware structure
- *  @vlan: VLAN id to write to VLAN filter
- *  @vind: VMDq output index that maps queue to VLAN id in VFTA
- *  @vlan_on: boolean flag to turn on/off VLAN in VFTA
  *
- *  Turn on/off specified VLAN in the VLAN filter table.
+ *  Disables multicast address in RAR and the use of the multicast hash table.
  **/
-s32 ixgbe_set_vfta(struct ixgbe_hw *hw, u32 vlan, u32 vind,
-		   bool vlan_on)
+s32 ixgbe_disable_mc_generic(struct ixgbe_hw *hw)
 {
-	u32 VftaIndex;
-	u32 BitOffset;
-	u32 VftaReg;
-	u32 VftaByte;
+	u32 i;
+	u32 rar_entries = hw->mac.num_rar_entries;
+	struct ixgbe_addr_filter_info *a = &hw->addr_ctrl;
 
-	/* Determine 32-bit word position in array */
-	VftaIndex = (vlan >> 5) & 0x7F;   /* upper seven bits */
+	if (a->mc_addr_in_rar_count > 0)
+		for (i = (rar_entries - a->mc_addr_in_rar_count);
+		     i < rar_entries; i++)
+			ixgbe_disable_rar(hw, i);
 
-	/* Determine the location of the (VMD) queue index */
-	VftaByte =  ((vlan >> 3) & 0x03); /* bits (4:3) indicating byte array */
-	BitOffset = (vlan & 0x7) << 2;    /* lower 3 bits indicate nibble */
-
-	/* Set the nibble for VMD queue index */
-	VftaReg = IXGBE_READ_REG(hw, IXGBE_VFTAVIND(VftaByte, VftaIndex));
-	VftaReg &= (~(0x0F << BitOffset));
-	VftaReg |= (vind << BitOffset);
-	IXGBE_WRITE_REG(hw, IXGBE_VFTAVIND(VftaByte, VftaIndex), VftaReg);
-
-	/* Determine the location of the bit for this VLAN id */
-	BitOffset = vlan & 0x1F;	   /* lower five bits */
-
-	VftaReg = IXGBE_READ_REG(hw, IXGBE_VFTA(VftaIndex));
-	if (vlan_on)
-		/* Turn on this VLAN id */
-		VftaReg |= (1 << BitOffset);
-	else
-		/* Turn off this VLAN id */
-		VftaReg &= ~(1 << BitOffset);
-	IXGBE_WRITE_REG(hw, IXGBE_VFTA(VftaIndex), VftaReg);
-
-	return 0;
-}
-
-/**
- *  ixgbe_setup_fc - Configure flow control settings
- *  @hw: pointer to hardware structure
- *  @packetbuf_num: packet buffer number (0-7)
- *
- *  Configures the flow control settings based on SW configuration.
- *  This function is used for 802.3x flow control configuration only.
- **/
-s32 ixgbe_setup_fc(struct ixgbe_hw *hw, s32 packetbuf_num)
-{
-	u32 frctl_reg;
-	u32 rmcs_reg;
-
-	if (packetbuf_num < 0 || packetbuf_num > 7)
-		hw_dbg(hw, "Invalid packet buffer number [%d], expected range "
-		       "is 0-7\n", packetbuf_num);
-
-	frctl_reg = IXGBE_READ_REG(hw, IXGBE_FCTRL);
-	frctl_reg &= ~(IXGBE_FCTRL_RFCE | IXGBE_FCTRL_RPFCE);
-
-	rmcs_reg = IXGBE_READ_REG(hw, IXGBE_RMCS);
-	rmcs_reg &= ~(IXGBE_RMCS_TFCE_PRIORITY | IXGBE_RMCS_TFCE_802_3X);
-
-	/*
-	 * We want to save off the original Flow Control configuration just in
-	 * case we get disconnected and then reconnected into a different hub
-	 * or switch with different Flow Control capabilities.
-	 */
-	hw->fc.type = hw->fc.original_type;
-
-	/*
-	 * The possible values of the "flow_control" parameter are:
-	 * 0: Flow control is completely disabled
-	 * 1: Rx flow control is enabled (we can receive pause frames but not
-	 *    send pause frames).
-	 * 2: Tx flow control is enabled (we can send pause frames but we do not
-	 *    support receiving pause frames)
-	 * 3: Both Rx and TX flow control (symmetric) are enabled.
-	 * other: Invalid.
-	 */
-	switch (hw->fc.type) {
-	case ixgbe_fc_none:
-		break;
-	case ixgbe_fc_rx_pause:
-		/*
-		 * RX Flow control is enabled,
-		 * and TX Flow control is disabled.
-		 */
-		frctl_reg |= IXGBE_FCTRL_RFCE;
-		break;
-	case ixgbe_fc_tx_pause:
-		/*
-		 * TX Flow control is enabled, and RX Flow control is disabled,
-		 * by a software over-ride.
-		 */
-		rmcs_reg |= IXGBE_RMCS_TFCE_802_3X;
-		break;
-	case ixgbe_fc_full:
-		/*
-		 * Flow control (both RX and TX) is enabled by a software
-		 * over-ride.
-		 */
-		frctl_reg |= IXGBE_FCTRL_RFCE;
-		rmcs_reg |= IXGBE_RMCS_TFCE_802_3X;
-		break;
-	default:
-		/* We should never get here.  The value should be 0-3. */
-		hw_dbg(hw, "Flow control param set incorrectly\n");
-		break;
-	}
-
-	/* Enable 802.3x based flow control settings. */
-	IXGBE_WRITE_REG(hw, IXGBE_FCTRL, frctl_reg);
-	IXGBE_WRITE_REG(hw, IXGBE_RMCS, rmcs_reg);
-
-	/*
-	 * We need to set up the Receive Threshold high and low water
-	 * marks as well as (optionally) enabling the transmission of
-	 * XON frames.
-	 */
-	if (hw->fc.type & ixgbe_fc_tx_pause) {
-		if (hw->fc.send_xon) {
-			IXGBE_WRITE_REG(hw, IXGBE_FCRTL(packetbuf_num),
-					(hw->fc.low_water | IXGBE_FCRTL_XONE));
-		} else {
-			IXGBE_WRITE_REG(hw, IXGBE_FCRTL(packetbuf_num),
-					hw->fc.low_water);
-		}
-		IXGBE_WRITE_REG(hw, IXGBE_FCRTH(packetbuf_num),
-				(hw->fc.high_water)|IXGBE_FCRTH_FCEN);
-	}
-
-	IXGBE_WRITE_REG(hw, IXGBE_FCTTV(0), hw->fc.pause_time);
-	IXGBE_WRITE_REG(hw, IXGBE_FCRTV, (hw->fc.pause_time >> 1));
+	if (a->mta_in_use > 0)
+		IXGBE_WRITE_REG(hw, IXGBE_MCSTCTRL, hw->mac.mc_filter_type);
 
 	return 0;
 }
@@ -1049,13 +1500,24 @@
  **/
 s32 ixgbe_disable_pcie_master(struct ixgbe_hw *hw)
 {
-	u32 ctrl;
-	s32 i;
+	u32 i;
+	u32 reg_val;
+	u32 number_of_queues;
 	s32 status = IXGBE_ERR_MASTER_REQUESTS_PENDING;
 
-	ctrl = IXGBE_READ_REG(hw, IXGBE_CTRL);
-	ctrl |= IXGBE_CTRL_GIO_DIS;
-	IXGBE_WRITE_REG(hw, IXGBE_CTRL, ctrl);
+	/* Disable the receive unit by stopping each queue */
+	number_of_queues = hw->mac.max_rx_queues;
+	for (i = 0; i < number_of_queues; i++) {
+		reg_val = IXGBE_READ_REG(hw, IXGBE_RXDCTL(i));
+		if (reg_val & IXGBE_RXDCTL_ENABLE) {
+			reg_val &= ~IXGBE_RXDCTL_ENABLE;
+			IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(i), reg_val);
+		}
+	}
+
+	reg_val = IXGBE_READ_REG(hw, IXGBE_CTRL);
+	reg_val |= IXGBE_CTRL_GIO_DIS;
+	IXGBE_WRITE_REG(hw, IXGBE_CTRL, reg_val);
 
 	for (i = 0; i < IXGBE_PCI_MASTER_DISABLE_TIMEOUT; i++) {
 		if (!(IXGBE_READ_REG(hw, IXGBE_STATUS) & IXGBE_STATUS_GIO)) {
@@ -1070,11 +1532,11 @@
 
 
 /**
- *  ixgbe_acquire_swfw_sync - Aquire SWFW semaphore
+ *  ixgbe_acquire_swfw_sync - Acquire SWFW semaphore
  *  @hw: pointer to hardware structure
- *  @mask: Mask to specify wich semaphore to acquire
+ *  @mask: Mask to specify which semaphore to acquire
  *
- *  Aquires the SWFW semaphore throught the GSSR register for the specified
+ *  Acquires the SWFW semaphore thought the GSSR register for the specified
  *  function (CSR, PHY0, PHY1, EEPROM, Flash)
  **/
 s32 ixgbe_acquire_swfw_sync(struct ixgbe_hw *hw, u16 mask)
@@ -1116,9 +1578,9 @@
 /**
  *  ixgbe_release_swfw_sync - Release SWFW semaphore
  *  @hw: pointer to hardware structure
- *  @mask: Mask to specify wich semaphore to release
+ *  @mask: Mask to specify which semaphore to release
  *
- *  Releases the SWFW semaphore throught the GSSR register for the specified
+ *  Releases the SWFW semaphore thought the GSSR register for the specified
  *  function (CSR, PHY0, PHY1, EEPROM, Flash)
  **/
 void ixgbe_release_swfw_sync(struct ixgbe_hw *hw, u16 mask)
@@ -1135,45 +1597,3 @@
 	ixgbe_release_eeprom_semaphore(hw);
 }
 
-/**
- *  ixgbe_read_analog_reg8 - Reads 8 bit Atlas analog register
- *  @hw: pointer to hardware structure
- *  @reg: analog register to read
- *  @val: read value
- *
- *  Performs write operation to analog register specified.
- **/
-s32 ixgbe_read_analog_reg8(struct ixgbe_hw *hw, u32 reg, u8 *val)
-{
-	u32  atlas_ctl;
-
-	IXGBE_WRITE_REG(hw, IXGBE_ATLASCTL,
-			IXGBE_ATLASCTL_WRITE_CMD | (reg << 8));
-	IXGBE_WRITE_FLUSH(hw);
-	udelay(10);
-	atlas_ctl = IXGBE_READ_REG(hw, IXGBE_ATLASCTL);
-	*val = (u8)atlas_ctl;
-
-	return 0;
-}
-
-/**
- *  ixgbe_write_analog_reg8 - Writes 8 bit Atlas analog register
- *  @hw: pointer to hardware structure
- *  @reg: atlas register to write
- *  @val: value to write
- *
- *  Performs write operation to Atlas analog register specified.
- **/
-s32 ixgbe_write_analog_reg8(struct ixgbe_hw *hw, u32 reg, u8 val)
-{
-	u32  atlas_ctl;
-
-	atlas_ctl = (reg << 8) | val;
-	IXGBE_WRITE_REG(hw, IXGBE_ATLASCTL, atlas_ctl);
-	IXGBE_WRITE_FLUSH(hw);
-	udelay(10);
-
-	return 0;
-}
-
diff --git a/drivers/net/ixgbe/ixgbe_common.h b/drivers/net/ixgbe/ixgbe_common.h
index de6ddd5..192f8d0 100644
--- a/drivers/net/ixgbe/ixgbe_common.h
+++ b/drivers/net/ixgbe/ixgbe_common.h
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel 10 Gigabit PCI Express Linux driver
-  Copyright(c) 1999 - 2007 Intel Corporation.
+  Copyright(c) 1999 - 2008 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
@@ -20,7 +20,6 @@
   the file called "COPYING".
 
   Contact Information:
-  Linux NICS <linux.nics@intel.com>
   e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
   Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
 
@@ -31,34 +30,45 @@
 
 #include "ixgbe_type.h"
 
-s32 ixgbe_init_hw(struct ixgbe_hw *hw);
-s32 ixgbe_start_hw(struct ixgbe_hw *hw);
-s32 ixgbe_get_mac_addr(struct ixgbe_hw *hw, u8 *mac_addr);
-s32 ixgbe_stop_adapter(struct ixgbe_hw *hw);
-s32 ixgbe_read_part_num(struct ixgbe_hw *hw, u32 *part_num);
+s32 ixgbe_init_ops_generic(struct ixgbe_hw *hw);
+s32 ixgbe_init_hw_generic(struct ixgbe_hw *hw);
+s32 ixgbe_start_hw_generic(struct ixgbe_hw *hw);
+s32 ixgbe_clear_hw_cntrs_generic(struct ixgbe_hw *hw);
+s32 ixgbe_read_pba_num_generic(struct ixgbe_hw *hw, u32 *pba_num);
+s32 ixgbe_get_mac_addr_generic(struct ixgbe_hw *hw, u8 *mac_addr);
+s32 ixgbe_get_bus_info_generic(struct ixgbe_hw *hw);
+s32 ixgbe_stop_adapter_generic(struct ixgbe_hw *hw);
 
-s32 ixgbe_led_on(struct ixgbe_hw *hw, u32 index);
-s32 ixgbe_led_off(struct ixgbe_hw *hw, u32 index);
+s32 ixgbe_led_on_generic(struct ixgbe_hw *hw, u32 index);
+s32 ixgbe_led_off_generic(struct ixgbe_hw *hw, u32 index);
 
-s32 ixgbe_init_eeprom(struct ixgbe_hw *hw);
-s32 ixgbe_read_eeprom(struct ixgbe_hw *hw, u16 offset, u16 *data);
-s32 ixgbe_validate_eeprom_checksum(struct ixgbe_hw *hw, u16 *checksum_val);
+s32 ixgbe_init_eeprom_params_generic(struct ixgbe_hw *hw);
+s32 ixgbe_read_eeprom_generic(struct ixgbe_hw *hw, u16 offset, u16 *data);
+s32 ixgbe_read_eeprom_bit_bang_generic(struct ixgbe_hw *hw, u16 offset,
+                                       u16 *data);
+s32 ixgbe_validate_eeprom_checksum_generic(struct ixgbe_hw *hw,
+                                           u16 *checksum_val);
+s32 ixgbe_update_eeprom_checksum_generic(struct ixgbe_hw *hw);
 
-s32 ixgbe_set_rar(struct ixgbe_hw *hw, u32 index, u8 *addr, u32 vind,
-		  u32 enable_addr);
-s32 ixgbe_update_mc_addr_list(struct ixgbe_hw *hw, u8 *mc_addr_list,
-			      u32 mc_addr_count, u32 pad);
-s32 ixgbe_set_vfta(struct ixgbe_hw *hw, u32 vlan, u32 vind, bool vlan_on);
+s32 ixgbe_set_rar_generic(struct ixgbe_hw *hw, u32 index, u8 *addr, u32 vmdq,
+                          u32 enable_addr);
+s32 ixgbe_clear_rar_generic(struct ixgbe_hw *hw, u32 index);
+s32 ixgbe_init_rx_addrs_generic(struct ixgbe_hw *hw);
+s32 ixgbe_update_mc_addr_list_generic(struct ixgbe_hw *hw, u8 *mc_addr_list,
+                                      u32 mc_addr_count,
+                                      ixgbe_mc_addr_itr func);
+s32 ixgbe_update_uc_addr_list_generic(struct ixgbe_hw *hw, u8 *addr_list,
+                                      u32 addr_count, ixgbe_mc_addr_itr func);
+s32 ixgbe_enable_mc_generic(struct ixgbe_hw *hw);
+s32 ixgbe_disable_mc_generic(struct ixgbe_hw *hw);
+
 s32 ixgbe_validate_mac_addr(u8 *mac_addr);
-
-s32 ixgbe_setup_fc(struct ixgbe_hw *hw, s32 packtetbuf_num);
-
 s32 ixgbe_acquire_swfw_sync(struct ixgbe_hw *hw, u16 mask);
 void ixgbe_release_swfw_sync(struct ixgbe_hw *hw, u16 mask);
 s32 ixgbe_disable_pcie_master(struct ixgbe_hw *hw);
 
-s32 ixgbe_read_analog_reg8(struct ixgbe_hw *hw, u32 reg, u8 *val);
-s32 ixgbe_write_analog_reg8(struct ixgbe_hw *hw, u32 reg, u8 val);
+s32 ixgbe_read_analog_reg8_generic(struct ixgbe_hw *hw, u32 reg, u8 *val);
+s32 ixgbe_write_analog_reg8_generic(struct ixgbe_hw *hw, u32 reg, u8 val);
 
 #define IXGBE_WRITE_REG(a, reg, value) writel((value), ((a)->hw_addr + (reg)))
 
diff --git a/drivers/net/ixgbe/ixgbe_ethtool.c b/drivers/net/ixgbe/ixgbe_ethtool.c
index 3efe5dd..81a9c4b 100644
--- a/drivers/net/ixgbe/ixgbe_ethtool.c
+++ b/drivers/net/ixgbe/ixgbe_ethtool.c
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel 10 Gigabit PCI Express Linux driver
-  Copyright(c) 1999 - 2007 Intel Corporation.
+  Copyright(c) 1999 - 2008 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
@@ -20,7 +20,6 @@
   the file called "COPYING".
 
   Contact Information:
-  Linux NICS <linux.nics@intel.com>
   e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
   Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
 
@@ -48,7 +47,7 @@
 };
 
 #define IXGBE_STAT(m) sizeof(((struct ixgbe_adapter *)0)->m), \
-		      offsetof(struct ixgbe_adapter, m)
+                             offsetof(struct ixgbe_adapter, m)
 static struct ixgbe_stats ixgbe_gstrings_stats[] = {
 	{"rx_packets", IXGBE_STAT(net_stats.rx_packets)},
 	{"tx_packets", IXGBE_STAT(net_stats.tx_packets)},
@@ -95,14 +94,15 @@
 };
 
 #define IXGBE_QUEUE_STATS_LEN \
-		((((struct ixgbe_adapter *)netdev->priv)->num_tx_queues + \
-		 ((struct ixgbe_adapter *)netdev->priv)->num_rx_queues) * \
-		 (sizeof(struct ixgbe_queue_stats) / sizeof(u64)))
-#define IXGBE_GLOBAL_STATS_LEN	ARRAY_SIZE(ixgbe_gstrings_stats)
+                ((((struct ixgbe_adapter *)netdev->priv)->num_tx_queues + \
+                 ((struct ixgbe_adapter *)netdev->priv)->num_rx_queues) * \
+                 (sizeof(struct ixgbe_queue_stats) / sizeof(u64)))
+#define IXGBE_STATS_LEN (IXGBE_GLOBAL_STATS_LEN + IXGBE_QUEUE_STATS_LEN)
+#define IXGBE_GLOBAL_STATS_LEN ARRAY_SIZE(ixgbe_gstrings_stats)
 #define IXGBE_STATS_LEN (IXGBE_GLOBAL_STATS_LEN + IXGBE_QUEUE_STATS_LEN)
 
 static int ixgbe_get_settings(struct net_device *netdev,
-			      struct ethtool_cmd *ecmd)
+                              struct ethtool_cmd *ecmd)
 {
 	struct ixgbe_adapter *adapter = netdev_priv(netdev);
 	struct ixgbe_hw *hw = &adapter->hw;
@@ -114,7 +114,7 @@
 	ecmd->transceiver = XCVR_EXTERNAL;
 	if (hw->phy.media_type == ixgbe_media_type_copper) {
 		ecmd->supported |= (SUPPORTED_1000baseT_Full |
-				    SUPPORTED_TP | SUPPORTED_Autoneg);
+		                    SUPPORTED_TP | SUPPORTED_Autoneg);
 
 		ecmd->advertising = (ADVERTISED_TP | ADVERTISED_Autoneg);
 		if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_10GB_FULL)
@@ -126,14 +126,15 @@
 	} else {
 		ecmd->supported |= SUPPORTED_FIBRE;
 		ecmd->advertising = (ADVERTISED_10000baseT_Full |
-				     ADVERTISED_FIBRE);
+		                     ADVERTISED_FIBRE);
 		ecmd->port = PORT_FIBRE;
+		ecmd->autoneg = AUTONEG_DISABLE;
 	}
 
-	adapter->hw.mac.ops.check_link(hw, &(link_speed), &link_up);
+	hw->mac.ops.check_link(hw, &link_speed, &link_up, false);
 	if (link_up) {
 		ecmd->speed = (link_speed == IXGBE_LINK_SPEED_10GB_FULL) ?
-				SPEED_10000 : SPEED_1000;
+		               SPEED_10000 : SPEED_1000;
 		ecmd->duplex = DUPLEX_FULL;
 	} else {
 		ecmd->speed = -1;
@@ -144,7 +145,7 @@
 }
 
 static int ixgbe_set_settings(struct net_device *netdev,
-			      struct ethtool_cmd *ecmd)
+                              struct ethtool_cmd *ecmd)
 {
 	struct ixgbe_adapter *adapter = netdev_priv(netdev);
 	struct ixgbe_hw *hw = &adapter->hw;
@@ -164,7 +165,7 @@
 }
 
 static void ixgbe_get_pauseparam(struct net_device *netdev,
-				 struct ethtool_pauseparam *pause)
+                                 struct ethtool_pauseparam *pause)
 {
 	struct ixgbe_adapter *adapter = netdev_priv(netdev);
 	struct ixgbe_hw *hw = &adapter->hw;
@@ -182,7 +183,7 @@
 }
 
 static int ixgbe_set_pauseparam(struct net_device *netdev,
-				struct ethtool_pauseparam *pause)
+                                struct ethtool_pauseparam *pause)
 {
 	struct ixgbe_adapter *adapter = netdev_priv(netdev);
 	struct ixgbe_hw *hw = &adapter->hw;
@@ -233,15 +234,15 @@
 
 static u32 ixgbe_get_tx_csum(struct net_device *netdev)
 {
-	return (netdev->features & NETIF_F_HW_CSUM) != 0;
+	return (netdev->features & NETIF_F_IP_CSUM) != 0;
 }
 
 static int ixgbe_set_tx_csum(struct net_device *netdev, u32 data)
 {
 	if (data)
-		netdev->features |= NETIF_F_HW_CSUM;
+		netdev->features |= (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM);
 	else
-		netdev->features &= ~NETIF_F_HW_CSUM;
+		netdev->features &= ~(NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM);
 
 	return 0;
 }
@@ -281,7 +282,7 @@
 #define IXGBE_GET_STAT(_A_, _R_) _A_->stats._R_
 
 static void ixgbe_get_regs(struct net_device *netdev,
-			   struct ethtool_regs *regs, void *p)
+                           struct ethtool_regs *regs, void *p)
 {
 	struct ixgbe_adapter *adapter = netdev_priv(netdev);
 	struct ixgbe_hw *hw = &adapter->hw;
@@ -315,7 +316,9 @@
 	regs_buff[17] = IXGBE_READ_REG(hw, IXGBE_GRC);
 
 	/* Interrupt */
-	regs_buff[18] = IXGBE_READ_REG(hw, IXGBE_EICR);
+	/* don't read EICR because it can clear interrupt causes, instead
+	 * read EICS which is a shadow but doesn't clear EICR */
+	regs_buff[18] = IXGBE_READ_REG(hw, IXGBE_EICS);
 	regs_buff[19] = IXGBE_READ_REG(hw, IXGBE_EICS);
 	regs_buff[20] = IXGBE_READ_REG(hw, IXGBE_EIMS);
 	regs_buff[21] = IXGBE_READ_REG(hw, IXGBE_EIMC);
@@ -325,7 +328,7 @@
 	regs_buff[25] = IXGBE_READ_REG(hw, IXGBE_IVAR(0));
 	regs_buff[26] = IXGBE_READ_REG(hw, IXGBE_MSIXT);
 	regs_buff[27] = IXGBE_READ_REG(hw, IXGBE_MSIXPBA);
-	regs_buff[28] = IXGBE_READ_REG(hw, IXGBE_PBACL);
+	regs_buff[28] = IXGBE_READ_REG(hw, IXGBE_PBACL(0));
 	regs_buff[29] = IXGBE_READ_REG(hw, IXGBE_GPIE);
 
 	/* Flow Control */
@@ -371,7 +374,7 @@
 		regs_buff[482 + i] = IXGBE_READ_REG(hw, IXGBE_RAL(i));
 	for (i = 0; i < 16; i++)
 		regs_buff[498 + i] = IXGBE_READ_REG(hw, IXGBE_RAH(i));
-	regs_buff[514] = IXGBE_READ_REG(hw, IXGBE_PSRTYPE);
+	regs_buff[514] = IXGBE_READ_REG(hw, IXGBE_PSRTYPE(0));
 	regs_buff[515] = IXGBE_READ_REG(hw, IXGBE_FCTRL);
 	regs_buff[516] = IXGBE_READ_REG(hw, IXGBE_VLNCTRL);
 	regs_buff[517] = IXGBE_READ_REG(hw, IXGBE_MCSTCTRL);
@@ -419,7 +422,6 @@
 	regs_buff[827] = IXGBE_READ_REG(hw, IXGBE_WUPM);
 	regs_buff[828] = IXGBE_READ_REG(hw, IXGBE_FHFT);
 
-	/* DCE */
 	regs_buff[829] = IXGBE_READ_REG(hw, IXGBE_RMCS);
 	regs_buff[830] = IXGBE_READ_REG(hw, IXGBE_DPMCS);
 	regs_buff[831] = IXGBE_READ_REG(hw, IXGBE_PDPMCS);
@@ -539,21 +541,17 @@
 	/* Diagnostic */
 	regs_buff[1071] = IXGBE_READ_REG(hw, IXGBE_RDSTATCTL);
 	for (i = 0; i < 8; i++)
-		regs_buff[1072] = IXGBE_READ_REG(hw, IXGBE_RDSTAT(i));
+		regs_buff[1072 + i] = IXGBE_READ_REG(hw, IXGBE_RDSTAT(i));
 	regs_buff[1080] = IXGBE_READ_REG(hw, IXGBE_RDHMPN);
-	regs_buff[1081] = IXGBE_READ_REG(hw, IXGBE_RIC_DW0);
-	regs_buff[1082] = IXGBE_READ_REG(hw, IXGBE_RIC_DW1);
-	regs_buff[1083] = IXGBE_READ_REG(hw, IXGBE_RIC_DW2);
-	regs_buff[1084] = IXGBE_READ_REG(hw, IXGBE_RIC_DW3);
+	for (i = 0; i < 4; i++)
+		regs_buff[1081 + i] = IXGBE_READ_REG(hw, IXGBE_RIC_DW(i));
 	regs_buff[1085] = IXGBE_READ_REG(hw, IXGBE_RDPROBE);
 	regs_buff[1086] = IXGBE_READ_REG(hw, IXGBE_TDSTATCTL);
 	for (i = 0; i < 8; i++)
-		regs_buff[1087] = IXGBE_READ_REG(hw, IXGBE_TDSTAT(i));
+		regs_buff[1087 + i] = IXGBE_READ_REG(hw, IXGBE_TDSTAT(i));
 	regs_buff[1095] = IXGBE_READ_REG(hw, IXGBE_TDHMPN);
-	regs_buff[1096] = IXGBE_READ_REG(hw, IXGBE_TIC_DW0);
-	regs_buff[1097] = IXGBE_READ_REG(hw, IXGBE_TIC_DW1);
-	regs_buff[1098] = IXGBE_READ_REG(hw, IXGBE_TIC_DW2);
-	regs_buff[1099] = IXGBE_READ_REG(hw, IXGBE_TIC_DW3);
+	for (i = 0; i < 4; i++)
+		regs_buff[1096 + i] = IXGBE_READ_REG(hw, IXGBE_TIC_DW(i));
 	regs_buff[1100] = IXGBE_READ_REG(hw, IXGBE_TDPROBE);
 	regs_buff[1101] = IXGBE_READ_REG(hw, IXGBE_TXBUFCTRL);
 	regs_buff[1102] = IXGBE_READ_REG(hw, IXGBE_TXBUFDATA0);
@@ -566,7 +564,7 @@
 	regs_buff[1109] = IXGBE_READ_REG(hw, IXGBE_RXBUFDATA2);
 	regs_buff[1110] = IXGBE_READ_REG(hw, IXGBE_RXBUFDATA3);
 	for (i = 0; i < 8; i++)
-		regs_buff[1111] = IXGBE_READ_REG(hw, IXGBE_PCIE_DIAG(i));
+		regs_buff[1111 + i] = IXGBE_READ_REG(hw, IXGBE_PCIE_DIAG(i));
 	regs_buff[1119] = IXGBE_READ_REG(hw, IXGBE_RFVAL);
 	regs_buff[1120] = IXGBE_READ_REG(hw, IXGBE_MDFTC1);
 	regs_buff[1121] = IXGBE_READ_REG(hw, IXGBE_MDFTC2);
@@ -585,7 +583,7 @@
 }
 
 static int ixgbe_get_eeprom(struct net_device *netdev,
-			    struct ethtool_eeprom *eeprom, u8 *bytes)
+                            struct ethtool_eeprom *eeprom, u8 *bytes)
 {
 	struct ixgbe_adapter *adapter = netdev_priv(netdev);
 	struct ixgbe_hw *hw = &adapter->hw;
@@ -608,8 +606,8 @@
 		return -ENOMEM;
 
 	for (i = 0; i < eeprom_len; i++) {
-		if ((ret_val = ixgbe_read_eeprom(hw, first_word + i,
-						 &eeprom_buff[i])))
+		if ((ret_val = hw->eeprom.ops.read(hw, first_word + i,
+		    &eeprom_buff[i])))
 			break;
 	}
 
@@ -624,7 +622,7 @@
 }
 
 static void ixgbe_get_drvinfo(struct net_device *netdev,
-			      struct ethtool_drvinfo *drvinfo)
+                              struct ethtool_drvinfo *drvinfo)
 {
 	struct ixgbe_adapter *adapter = netdev_priv(netdev);
 
@@ -637,7 +635,7 @@
 }
 
 static void ixgbe_get_ringparam(struct net_device *netdev,
-				struct ethtool_ringparam *ring)
+                                struct ethtool_ringparam *ring)
 {
 	struct ixgbe_adapter *adapter = netdev_priv(netdev);
 	struct ixgbe_ring *tx_ring = adapter->tx_ring;
@@ -654,15 +652,12 @@
 }
 
 static int ixgbe_set_ringparam(struct net_device *netdev,
-			       struct ethtool_ringparam *ring)
+                               struct ethtool_ringparam *ring)
 {
 	struct ixgbe_adapter *adapter = netdev_priv(netdev);
-	struct ixgbe_tx_buffer *old_buf;
-	struct ixgbe_rx_buffer *old_rx_buf;
-	void *old_desc;
+	struct ixgbe_ring *temp_ring;
 	int i, err;
-	u32 new_rx_count, new_tx_count, old_size;
-	dma_addr_t old_dma;
+	u32 new_rx_count, new_tx_count;
 
 	if ((ring->rx_mini_pending) || (ring->rx_jumbo_pending))
 		return -EINVAL;
@@ -681,6 +676,15 @@
 		return 0;
 	}
 
+	if (adapter->num_tx_queues > adapter->num_rx_queues)
+		temp_ring = vmalloc(adapter->num_tx_queues *
+		                    sizeof(struct ixgbe_ring));
+	else
+		temp_ring = vmalloc(adapter->num_rx_queues *
+		                    sizeof(struct ixgbe_ring));
+	if (!temp_ring)
+		return -ENOMEM;
+
 	while (test_and_set_bit(__IXGBE_RESETTING, &adapter->state))
 		msleep(1);
 
@@ -693,66 +697,61 @@
 	 * to the tx and rx ring structs.
 	 */
 	if (new_tx_count != adapter->tx_ring->count) {
+		memcpy(temp_ring, adapter->tx_ring,
+		       adapter->num_tx_queues * sizeof(struct ixgbe_ring));
+
 		for (i = 0; i < adapter->num_tx_queues; i++) {
-			/* Save existing descriptor ring */
-			old_buf = adapter->tx_ring[i].tx_buffer_info;
-			old_desc = adapter->tx_ring[i].desc;
-			old_size = adapter->tx_ring[i].size;
-			old_dma = adapter->tx_ring[i].dma;
-			/* Try to allocate a new one */
-			adapter->tx_ring[i].tx_buffer_info = NULL;
-			adapter->tx_ring[i].desc = NULL;
-			adapter->tx_ring[i].count = new_tx_count;
-			err = ixgbe_setup_tx_resources(adapter,
-						       &adapter->tx_ring[i]);
+			temp_ring[i].count = new_tx_count;
+			err = ixgbe_setup_tx_resources(adapter, &temp_ring[i]);
 			if (err) {
-				/* Restore the old one so at least
-				   the adapter still works, even if
-				   we failed the request */
-				adapter->tx_ring[i].tx_buffer_info = old_buf;
-				adapter->tx_ring[i].desc = old_desc;
-				adapter->tx_ring[i].size = old_size;
-				adapter->tx_ring[i].dma = old_dma;
+				while (i) {
+					i--;
+					ixgbe_free_tx_resources(adapter,
+					                        &temp_ring[i]);
+				}
 				goto err_setup;
 			}
-			/* Free the old buffer manually */
-			vfree(old_buf);
-			pci_free_consistent(adapter->pdev, old_size,
-					    old_desc, old_dma);
 		}
+
+		for (i = 0; i < adapter->num_tx_queues; i++)
+			ixgbe_free_tx_resources(adapter, &adapter->tx_ring[i]);
+
+		memcpy(adapter->tx_ring, temp_ring,
+		       adapter->num_tx_queues * sizeof(struct ixgbe_ring));
+
+		adapter->tx_ring_count = new_tx_count;
 	}
 
 	if (new_rx_count != adapter->rx_ring->count) {
+		memcpy(temp_ring, adapter->rx_ring,
+		       adapter->num_rx_queues * sizeof(struct ixgbe_ring));
+
 		for (i = 0; i < adapter->num_rx_queues; i++) {
-
-			old_rx_buf = adapter->rx_ring[i].rx_buffer_info;
-			old_desc = adapter->rx_ring[i].desc;
-			old_size = adapter->rx_ring[i].size;
-			old_dma = adapter->rx_ring[i].dma;
-
-			adapter->rx_ring[i].rx_buffer_info = NULL;
-			adapter->rx_ring[i].desc = NULL;
-			adapter->rx_ring[i].dma = 0;
-			adapter->rx_ring[i].count = new_rx_count;
-			err = ixgbe_setup_rx_resources(adapter,
-						       &adapter->rx_ring[i]);
+			temp_ring[i].count = new_rx_count;
+			err = ixgbe_setup_rx_resources(adapter, &temp_ring[i]);
 			if (err) {
-				adapter->rx_ring[i].rx_buffer_info = old_rx_buf;
-				adapter->rx_ring[i].desc = old_desc;
-				adapter->rx_ring[i].size = old_size;
-				adapter->rx_ring[i].dma = old_dma;
+				while (i) {
+					i--;
+					ixgbe_free_rx_resources(adapter,
+					                        &temp_ring[i]);
+				}
 				goto err_setup;
 			}
-
-			vfree(old_rx_buf);
-			pci_free_consistent(adapter->pdev, old_size, old_desc,
-					    old_dma);
 		}
+
+		for (i = 0; i < adapter->num_rx_queues; i++)
+			ixgbe_free_rx_resources(adapter, &adapter->rx_ring[i]);
+
+		memcpy(adapter->rx_ring, temp_ring,
+		       adapter->num_rx_queues * sizeof(struct ixgbe_ring));
+
+		adapter->rx_ring_count = new_rx_count;
 	}
 
+	/* success! */
 	err = 0;
 err_setup:
-	if (netif_running(adapter->netdev))
+	if (netif_running(netdev))
 		ixgbe_up(adapter);
 
 	clear_bit(__IXGBE_RESETTING, &adapter->state);
@@ -770,7 +769,7 @@
 }
 
 static void ixgbe_get_ethtool_stats(struct net_device *netdev,
-				    struct ethtool_stats *stats, u64 *data)
+                                    struct ethtool_stats *stats, u64 *data)
 {
 	struct ixgbe_adapter *adapter = netdev_priv(netdev);
 	u64 *queue_stat;
@@ -778,12 +777,20 @@
 	int j, k;
 	int i;
 	u64 aggregated = 0, flushed = 0, no_desc = 0;
+	for (i = 0; i < adapter->num_rx_queues; i++) {
+		aggregated += adapter->rx_ring[i].lro_mgr.stats.aggregated;
+		flushed += adapter->rx_ring[i].lro_mgr.stats.flushed;
+		no_desc += adapter->rx_ring[i].lro_mgr.stats.no_desc;
+	}
+	adapter->lro_aggregated = aggregated;
+	adapter->lro_flushed = flushed;
+	adapter->lro_no_desc = no_desc;
 
 	ixgbe_update_stats(adapter);
 	for (i = 0; i < IXGBE_GLOBAL_STATS_LEN; i++) {
 		char *p = (char *)adapter + ixgbe_gstrings_stats[i].stat_offset;
 		data[i] = (ixgbe_gstrings_stats[i].sizeof_stat ==
-			   sizeof(u64)) ? *(u64 *)p : *(u32 *)p;
+		           sizeof(u64)) ? *(u64 *)p : *(u32 *)p;
 	}
 	for (j = 0; j < adapter->num_tx_queues; j++) {
 		queue_stat = (u64 *)&adapter->tx_ring[j].stats;
@@ -792,24 +799,18 @@
 		i += k;
 	}
 	for (j = 0; j < adapter->num_rx_queues; j++) {
-		aggregated += adapter->rx_ring[j].lro_mgr.stats.aggregated;
-		flushed += adapter->rx_ring[j].lro_mgr.stats.flushed;
-		no_desc += adapter->rx_ring[j].lro_mgr.stats.no_desc;
 		queue_stat = (u64 *)&adapter->rx_ring[j].stats;
 		for (k = 0; k < stat_count; k++)
 			data[i + k] = queue_stat[k];
 		i += k;
 	}
-	adapter->lro_aggregated = aggregated;
-	adapter->lro_flushed = flushed;
-	adapter->lro_no_desc = no_desc;
 }
 
 static void ixgbe_get_strings(struct net_device *netdev, u32 stringset,
-			      u8 *data)
+                              u8 *data)
 {
 	struct ixgbe_adapter *adapter = netdev_priv(netdev);
-	u8 *p = data;
+	char *p = (char *)data;
 	int i;
 
 	switch (stringset) {
@@ -831,14 +832,14 @@
 			sprintf(p, "rx_queue_%u_bytes", i);
 			p += ETH_GSTRING_LEN;
 		}
-/*		BUG_ON(p - data != IXGBE_STATS_LEN * ETH_GSTRING_LEN); */
+		/* BUG_ON(p - data != IXGBE_STATS_LEN * ETH_GSTRING_LEN); */
 		break;
 	}
 }
 
 
 static void ixgbe_get_wol(struct net_device *netdev,
-			  struct ethtool_wolinfo *wol)
+                          struct ethtool_wolinfo *wol)
 {
 	wol->supported = 0;
 	wol->wolopts = 0;
@@ -859,16 +860,17 @@
 static int ixgbe_phys_id(struct net_device *netdev, u32 data)
 {
 	struct ixgbe_adapter *adapter = netdev_priv(netdev);
-	u32 led_reg = IXGBE_READ_REG(&adapter->hw, IXGBE_LEDCTL);
+	struct ixgbe_hw *hw = &adapter->hw;
+	u32 led_reg = IXGBE_READ_REG(hw, IXGBE_LEDCTL);
 	u32 i;
 
 	if (!data || data > 300)
 		data = 300;
 
 	for (i = 0; i < (data * 1000); i += 400) {
-		ixgbe_led_on(&adapter->hw, IXGBE_LED_ON);
+		hw->mac.ops.led_on(hw, IXGBE_LED_ON);
 		msleep_interruptible(200);
-		ixgbe_led_off(&adapter->hw, IXGBE_LED_ON);
+		hw->mac.ops.led_off(hw, IXGBE_LED_ON);
 		msleep_interruptible(200);
 	}
 
@@ -879,67 +881,75 @@
 }
 
 static int ixgbe_get_coalesce(struct net_device *netdev,
-			      struct ethtool_coalesce *ec)
+                              struct ethtool_coalesce *ec)
 {
 	struct ixgbe_adapter *adapter = netdev_priv(netdev);
 
-	if (adapter->rx_eitr < IXGBE_MIN_ITR_USECS)
-		ec->rx_coalesce_usecs = adapter->rx_eitr;
-	else
-		ec->rx_coalesce_usecs = 1000000 / adapter->rx_eitr;
-
-	if (adapter->tx_eitr < IXGBE_MIN_ITR_USECS)
-		ec->tx_coalesce_usecs = adapter->tx_eitr;
-	else
-		ec->tx_coalesce_usecs = 1000000 / adapter->tx_eitr;
-
 	ec->tx_max_coalesced_frames_irq = adapter->tx_ring[0].work_limit;
+
+	/* only valid if in constant ITR mode */
+	switch (adapter->itr_setting) {
+	case 0:
+		/* throttling disabled */
+		ec->rx_coalesce_usecs = 0;
+		break;
+	case 1:
+		/* dynamic ITR mode */
+		ec->rx_coalesce_usecs = 1;
+		break;
+	default:
+		/* fixed interrupt rate mode */
+		ec->rx_coalesce_usecs = 1000000/adapter->eitr_param;
+		break;
+	}
 	return 0;
 }
 
 static int ixgbe_set_coalesce(struct net_device *netdev,
-			      struct ethtool_coalesce *ec)
+                              struct ethtool_coalesce *ec)
 {
 	struct ixgbe_adapter *adapter = netdev_priv(netdev);
-
-	if ((ec->rx_coalesce_usecs > IXGBE_MAX_ITR_USECS) ||
-	    ((ec->rx_coalesce_usecs != 0) &&
-	     (ec->rx_coalesce_usecs != 1) &&
-	     (ec->rx_coalesce_usecs != 3) &&
-	     (ec->rx_coalesce_usecs < IXGBE_MIN_ITR_USECS)))
-		return -EINVAL;
-	if ((ec->tx_coalesce_usecs > IXGBE_MAX_ITR_USECS) ||
-	    ((ec->tx_coalesce_usecs != 0) &&
-	     (ec->tx_coalesce_usecs != 1) &&
-	     (ec->tx_coalesce_usecs != 3) &&
-	     (ec->tx_coalesce_usecs < IXGBE_MIN_ITR_USECS)))
-		return -EINVAL;
-
-	/* convert to rate of irq's per second */
-	if (ec->rx_coalesce_usecs < IXGBE_MIN_ITR_USECS)
-		adapter->rx_eitr = ec->rx_coalesce_usecs;
-	else
-		adapter->rx_eitr = (1000000 / ec->rx_coalesce_usecs);
-
-	if (ec->tx_coalesce_usecs < IXGBE_MIN_ITR_USECS)
-		adapter->tx_eitr = ec->rx_coalesce_usecs;
-	else
-		adapter->tx_eitr = (1000000 / ec->tx_coalesce_usecs);
+	struct ixgbe_hw *hw = &adapter->hw;
+	int i;
 
 	if (ec->tx_max_coalesced_frames_irq)
-		adapter->tx_ring[0].work_limit =
-					ec->tx_max_coalesced_frames_irq;
+		adapter->tx_ring[0].work_limit = ec->tx_max_coalesced_frames_irq;
 
-	if (netif_running(netdev)) {
-		ixgbe_down(adapter);
-		ixgbe_up(adapter);
+	if (ec->rx_coalesce_usecs > 1) {
+		/* store the value in ints/second */
+		adapter->eitr_param = 1000000/ec->rx_coalesce_usecs;
+
+		/* static value of interrupt rate */
+		adapter->itr_setting = adapter->eitr_param;
+		/* clear the lower bit */
+		adapter->itr_setting &= ~1;
+	} else if (ec->rx_coalesce_usecs == 1) {
+		/* 1 means dynamic mode */
+		adapter->eitr_param = 20000;
+		adapter->itr_setting = 1;
+	} else {
+		/* any other value means disable eitr, which is best
+		 * served by setting the interrupt rate very high */
+		adapter->eitr_param = 3000000;
+		adapter->itr_setting = 0;
+	}
+
+	for (i = 0; i < adapter->num_msix_vectors - NON_Q_VECTORS; i++) {
+		struct ixgbe_q_vector *q_vector = &adapter->q_vector[i];
+		if (q_vector->txr_count && !q_vector->rxr_count)
+			q_vector->eitr = (adapter->eitr_param >> 1);
+		else
+			/* rx only or mixed */
+			q_vector->eitr = adapter->eitr_param;
+		IXGBE_WRITE_REG(hw, IXGBE_EITR(i),
+		                EITR_INTS_PER_SEC_TO_REG(q_vector->eitr));
 	}
 
 	return 0;
 }
 
 
-static struct ethtool_ops ixgbe_ethtool_ops = {
+static const struct ethtool_ops ixgbe_ethtool_ops = {
 	.get_settings           = ixgbe_get_settings,
 	.set_settings           = ixgbe_set_settings,
 	.get_drvinfo            = ixgbe_get_drvinfo,
@@ -966,7 +976,7 @@
 	.set_tso                = ixgbe_set_tso,
 	.get_strings            = ixgbe_get_strings,
 	.phys_id                = ixgbe_phys_id,
-	.get_sset_count		= ixgbe_get_sset_count,
+	.get_sset_count         = ixgbe_get_sset_count,
 	.get_ethtool_stats      = ixgbe_get_ethtool_stats,
 	.get_coalesce           = ixgbe_get_coalesce,
 	.set_coalesce           = ixgbe_set_coalesce,
diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c
index a417be7..ca17af4 100644
--- a/drivers/net/ixgbe/ixgbe_main.c
+++ b/drivers/net/ixgbe/ixgbe_main.c
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel 10 Gigabit PCI Express Linux driver
-  Copyright(c) 1999 - 2007 Intel Corporation.
+  Copyright(c) 1999 - 2008 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
@@ -20,7 +20,6 @@
   the file called "COPYING".
 
   Contact Information:
-  Linux NICS <linux.nics@intel.com>
   e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
   Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
 
@@ -46,15 +45,14 @@
 
 char ixgbe_driver_name[] = "ixgbe";
 static const char ixgbe_driver_string[] =
-	"Intel(R) 10 Gigabit PCI Express Network Driver";
+                              "Intel(R) 10 Gigabit PCI Express Network Driver";
 
-#define DRV_VERSION "1.3.18-k4"
+#define DRV_VERSION "1.3.30-k2"
 const char ixgbe_driver_version[] = DRV_VERSION;
-static const char ixgbe_copyright[] =
-	 "Copyright (c) 1999-2007 Intel Corporation.";
+static char ixgbe_copyright[] = "Copyright (c) 1999-2007 Intel Corporation.";
 
 static const struct ixgbe_info *ixgbe_info_tbl[] = {
-	[board_82598]			= &ixgbe_82598_info,
+	[board_82598] = &ixgbe_82598_info,
 };
 
 /* ixgbe_pci_tbl - PCI Device ID Table
@@ -74,15 +72,17 @@
 	 board_82598 },
 	{PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598_CX4_DUAL_PORT),
 	 board_82598 },
+	{PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598EB_XF_LR),
+	 board_82598 },
 
 	/* required last entry */
 	{0, }
 };
 MODULE_DEVICE_TABLE(pci, ixgbe_pci_tbl);
 
-#ifdef CONFIG_DCA
+#if defined(CONFIG_DCA) || defined(CONFIG_DCA_MODULE)
 static int ixgbe_notify_dca(struct notifier_block *, unsigned long event,
-			    void *p);
+                            void *p);
 static struct notifier_block dca_notifier = {
 	.notifier_call = ixgbe_notify_dca,
 	.next          = NULL,
@@ -104,7 +104,7 @@
 	/* Let firmware take over control of h/w */
 	ctrl_ext = IXGBE_READ_REG(&adapter->hw, IXGBE_CTRL_EXT);
 	IXGBE_WRITE_REG(&adapter->hw, IXGBE_CTRL_EXT,
-			ctrl_ext & ~IXGBE_CTRL_EXT_DRV_LOAD);
+	                ctrl_ext & ~IXGBE_CTRL_EXT_DRV_LOAD);
 }
 
 static void ixgbe_get_hw_control(struct ixgbe_adapter *adapter)
@@ -114,24 +114,11 @@
 	/* Let firmware know the driver has taken over */
 	ctrl_ext = IXGBE_READ_REG(&adapter->hw, IXGBE_CTRL_EXT);
 	IXGBE_WRITE_REG(&adapter->hw, IXGBE_CTRL_EXT,
-			ctrl_ext | IXGBE_CTRL_EXT_DRV_LOAD);
+	                ctrl_ext | IXGBE_CTRL_EXT_DRV_LOAD);
 }
 
-#ifdef DEBUG
-/**
- * ixgbe_get_hw_dev_name - return device name string
- * used by hardware layer to print debugging information
- **/
-char *ixgbe_get_hw_dev_name(struct ixgbe_hw *hw)
-{
-	struct ixgbe_adapter *adapter = hw->back;
-	struct net_device *netdev = adapter->netdev;
-	return netdev->name;
-}
-#endif
-
 static void ixgbe_set_ivar(struct ixgbe_adapter *adapter, u16 int_alloc_entry,
-			   u8 msix_vector)
+                           u8 msix_vector)
 {
 	u32 ivar, index;
 
@@ -144,13 +131,12 @@
 }
 
 static void ixgbe_unmap_and_free_tx_resource(struct ixgbe_adapter *adapter,
-					     struct ixgbe_tx_buffer
-					     *tx_buffer_info)
+                                             struct ixgbe_tx_buffer
+                                             *tx_buffer_info)
 {
 	if (tx_buffer_info->dma) {
-		pci_unmap_page(adapter->pdev,
-			       tx_buffer_info->dma,
-			       tx_buffer_info->length, PCI_DMA_TODEVICE);
+		pci_unmap_page(adapter->pdev, tx_buffer_info->dma,
+		               tx_buffer_info->length, PCI_DMA_TODEVICE);
 		tx_buffer_info->dma = 0;
 	}
 	if (tx_buffer_info->skb) {
@@ -161,107 +147,120 @@
 }
 
 static inline bool ixgbe_check_tx_hang(struct ixgbe_adapter *adapter,
-				       struct ixgbe_ring *tx_ring,
-				       unsigned int eop,
-				       union ixgbe_adv_tx_desc *eop_desc)
+                                       struct ixgbe_ring *tx_ring,
+                                       unsigned int eop)
 {
+	struct ixgbe_hw *hw = &adapter->hw;
+	u32 head, tail;
+
 	/* Detect a transmit hang in hardware, this serializes the
-	 * check with the clearing of time_stamp and movement of i */
+	 * check with the clearing of time_stamp and movement of eop */
+	head = IXGBE_READ_REG(hw, tx_ring->head);
+	tail = IXGBE_READ_REG(hw, tx_ring->tail);
 	adapter->detect_tx_hung = false;
-	if (tx_ring->tx_buffer_info[eop].dma &&
+	if ((head != tail) &&
+	    tx_ring->tx_buffer_info[eop].time_stamp &&
 	    time_after(jiffies, tx_ring->tx_buffer_info[eop].time_stamp + HZ) &&
 	    !(IXGBE_READ_REG(&adapter->hw, IXGBE_TFCS) & IXGBE_TFCS_TXOFF)) {
 		/* detected Tx unit hang */
+		union ixgbe_adv_tx_desc *tx_desc;
+		tx_desc = IXGBE_TX_DESC_ADV(*tx_ring, eop);
 		DPRINTK(DRV, ERR, "Detected Tx Unit Hang\n"
-			"  TDH                  <%x>\n"
-			"  TDT                  <%x>\n"
+			"  Tx Queue             <%d>\n"
+			"  TDH, TDT             <%x>, <%x>\n"
 			"  next_to_use          <%x>\n"
 			"  next_to_clean        <%x>\n"
 			"tx_buffer_info[next_to_clean]\n"
 			"  time_stamp           <%lx>\n"
-			"  next_to_watch        <%x>\n"
-			"  jiffies              <%lx>\n"
-			"  next_to_watch.status <%x>\n",
-			readl(adapter->hw.hw_addr + tx_ring->head),
-			readl(adapter->hw.hw_addr + tx_ring->tail),
-			tx_ring->next_to_use,
-			tx_ring->next_to_clean,
-			tx_ring->tx_buffer_info[eop].time_stamp,
-			eop, jiffies, eop_desc->wb.status);
+			"  jiffies              <%lx>\n",
+			tx_ring->queue_index,
+			head, tail,
+			tx_ring->next_to_use, eop,
+			tx_ring->tx_buffer_info[eop].time_stamp, jiffies);
 		return true;
 	}
 
 	return false;
 }
 
-#define IXGBE_MAX_TXD_PWR	14
-#define IXGBE_MAX_DATA_PER_TXD	(1 << IXGBE_MAX_TXD_PWR)
+#define IXGBE_MAX_TXD_PWR       14
+#define IXGBE_MAX_DATA_PER_TXD  (1 << IXGBE_MAX_TXD_PWR)
 
 /* Tx Descriptors needed, worst case */
 #define TXD_USE_COUNT(S) (((S) >> IXGBE_MAX_TXD_PWR) + \
 			 (((S) & (IXGBE_MAX_DATA_PER_TXD - 1)) ? 1 : 0))
 #define DESC_NEEDED (TXD_USE_COUNT(IXGBE_MAX_DATA_PER_TXD) /* skb->data */ + \
-	MAX_SKB_FRAGS * TXD_USE_COUNT(PAGE_SIZE) + 1)	/* for context */
+	MAX_SKB_FRAGS * TXD_USE_COUNT(PAGE_SIZE) + 1) /* for context */
+
+#define GET_TX_HEAD_FROM_RING(ring) (\
+	*(volatile u32 *) \
+	((union ixgbe_adv_tx_desc *)(ring)->desc + (ring)->count))
+static void ixgbe_tx_timeout(struct net_device *netdev);
 
 /**
  * ixgbe_clean_tx_irq - Reclaim resources after transmit completes
  * @adapter: board private structure
+ * @tx_ring: tx ring to clean
  **/
 static bool ixgbe_clean_tx_irq(struct ixgbe_adapter *adapter,
-				    struct ixgbe_ring *tx_ring)
+                               struct ixgbe_ring *tx_ring)
 {
-	struct net_device *netdev = adapter->netdev;
-	union ixgbe_adv_tx_desc *tx_desc, *eop_desc;
+	union ixgbe_adv_tx_desc *tx_desc;
 	struct ixgbe_tx_buffer *tx_buffer_info;
-	unsigned int i, eop;
-	bool cleaned = false;
-	unsigned int total_tx_bytes = 0, total_tx_packets = 0;
+	struct net_device *netdev = adapter->netdev;
+	struct sk_buff *skb;
+	unsigned int i;
+	u32 head, oldhead;
+	unsigned int count = 0;
+	unsigned int total_bytes = 0, total_packets = 0;
 
+	rmb();
+	head = GET_TX_HEAD_FROM_RING(tx_ring);
+	head = le32_to_cpu(head);
 	i = tx_ring->next_to_clean;
-	eop = tx_ring->tx_buffer_info[i].next_to_watch;
-	eop_desc = IXGBE_TX_DESC_ADV(*tx_ring, eop);
-	while (eop_desc->wb.status & cpu_to_le32(IXGBE_TXD_STAT_DD)) {
-		cleaned = false;
-		while (!cleaned) {
+	while (1) {
+		while (i != head) {
 			tx_desc = IXGBE_TX_DESC_ADV(*tx_ring, i);
 			tx_buffer_info = &tx_ring->tx_buffer_info[i];
-			cleaned = (i == eop);
+			skb = tx_buffer_info->skb;
 
-			tx_ring->stats.bytes += tx_buffer_info->length;
-			if (cleaned) {
-				struct sk_buff *skb = tx_buffer_info->skb;
+			if (skb) {
 				unsigned int segs, bytecount;
+
+				/* gso_segs is currently only valid for tcp */
 				segs = skb_shinfo(skb)->gso_segs ?: 1;
 				/* multiply data chunks by size of headers */
 				bytecount = ((segs - 1) * skb_headlen(skb)) +
-					    skb->len;
-				total_tx_packets += segs;
-				total_tx_bytes += bytecount;
+				            skb->len;
+				total_packets += segs;
+				total_bytes += bytecount;
 			}
+
 			ixgbe_unmap_and_free_tx_resource(adapter,
-							 tx_buffer_info);
-			tx_desc->wb.status = 0;
+			                                 tx_buffer_info);
 
 			i++;
 			if (i == tx_ring->count)
 				i = 0;
+
+			count++;
+			if (count == tx_ring->count)
+				goto done_cleaning;
 		}
+		oldhead = head;
+		rmb();
+		head = GET_TX_HEAD_FROM_RING(tx_ring);
+		head = le32_to_cpu(head);
+		if (head == oldhead)
+			goto done_cleaning;
+	} /* while (1) */
 
-		tx_ring->stats.packets++;
-
-		eop = tx_ring->tx_buffer_info[i].next_to_watch;
-		eop_desc = IXGBE_TX_DESC_ADV(*tx_ring, eop);
-
-		/* weight of a sort for tx, avoid endless transmit cleanup */
-		if (total_tx_packets >= tx_ring->work_limit)
-			break;
-	}
-
+done_cleaning:
 	tx_ring->next_to_clean = i;
 
 #define TX_WAKE_THRESHOLD (DESC_NEEDED * 2)
-	if (total_tx_packets && netif_carrier_ok(netdev) &&
-	    (IXGBE_DESC_UNUSED(tx_ring) >= TX_WAKE_THRESHOLD)) {
+	if (unlikely(count && netif_carrier_ok(netdev) &&
+	             (IXGBE_DESC_UNUSED(tx_ring) >= TX_WAKE_THRESHOLD))) {
 		/* Make sure that anybody stopping the queue after this
 		 * sees the new next_to_clean.
 		 */
@@ -269,59 +268,68 @@
 		if (__netif_subqueue_stopped(netdev, tx_ring->queue_index) &&
 		    !test_bit(__IXGBE_DOWN, &adapter->state)) {
 			netif_wake_subqueue(netdev, tx_ring->queue_index);
-			adapter->restart_queue++;
+			++adapter->restart_queue;
 		}
 	}
 
-	if (adapter->detect_tx_hung)
-		if (ixgbe_check_tx_hang(adapter, tx_ring, eop, eop_desc))
-			netif_stop_subqueue(netdev, tx_ring->queue_index);
+	if (adapter->detect_tx_hung) {
+		if (ixgbe_check_tx_hang(adapter, tx_ring, i)) {
+			/* schedule immediate reset if we believe we hung */
+			DPRINTK(PROBE, INFO,
+			        "tx hang %d detected, resetting adapter\n",
+			        adapter->tx_timeout_count + 1);
+			ixgbe_tx_timeout(adapter->netdev);
+		}
+	}
 
-	if (total_tx_packets >= tx_ring->work_limit)
-		IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS, tx_ring->eims_value);
+	/* re-arm the interrupt */
+	if ((total_packets >= tx_ring->work_limit) ||
+	    (count == tx_ring->count))
+		IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS, tx_ring->v_idx);
 
-	tx_ring->total_bytes += total_tx_bytes;
-	tx_ring->total_packets += total_tx_packets;
-	adapter->net_stats.tx_bytes += total_tx_bytes;
-	adapter->net_stats.tx_packets += total_tx_packets;
-	cleaned = total_tx_packets ? true : false;
-	return cleaned;
+	tx_ring->total_bytes += total_bytes;
+	tx_ring->total_packets += total_packets;
+	tx_ring->stats.bytes += total_bytes;
+	tx_ring->stats.packets += total_packets;
+	adapter->net_stats.tx_bytes += total_bytes;
+	adapter->net_stats.tx_packets += total_packets;
+	return (total_packets ? true : false);
 }
 
-#ifdef CONFIG_DCA
+#if defined(CONFIG_DCA) || defined(CONFIG_DCA_MODULE)
 static void ixgbe_update_rx_dca(struct ixgbe_adapter *adapter,
-				struct ixgbe_ring *rxr)
+                                struct ixgbe_ring *rx_ring)
 {
 	u32 rxctrl;
 	int cpu = get_cpu();
-	int q = rxr - adapter->rx_ring;
+	int q = rx_ring - adapter->rx_ring;
 
-	if (rxr->cpu != cpu) {
+	if (rx_ring->cpu != cpu) {
 		rxctrl = IXGBE_READ_REG(&adapter->hw, IXGBE_DCA_RXCTRL(q));
 		rxctrl &= ~IXGBE_DCA_RXCTRL_CPUID_MASK;
-		rxctrl |= dca_get_tag(cpu);
+		rxctrl |= dca3_get_tag(&adapter->pdev->dev, cpu);
 		rxctrl |= IXGBE_DCA_RXCTRL_DESC_DCA_EN;
 		rxctrl |= IXGBE_DCA_RXCTRL_HEAD_DCA_EN;
 		IXGBE_WRITE_REG(&adapter->hw, IXGBE_DCA_RXCTRL(q), rxctrl);
-		rxr->cpu = cpu;
+		rx_ring->cpu = cpu;
 	}
 	put_cpu();
 }
 
 static void ixgbe_update_tx_dca(struct ixgbe_adapter *adapter,
-				struct ixgbe_ring *txr)
+                                struct ixgbe_ring *tx_ring)
 {
 	u32 txctrl;
 	int cpu = get_cpu();
-	int q = txr - adapter->tx_ring;
+	int q = tx_ring - adapter->tx_ring;
 
-	if (txr->cpu != cpu) {
+	if (tx_ring->cpu != cpu) {
 		txctrl = IXGBE_READ_REG(&adapter->hw, IXGBE_DCA_TXCTRL(q));
 		txctrl &= ~IXGBE_DCA_TXCTRL_CPUID_MASK;
-		txctrl |= dca_get_tag(cpu);
+		txctrl |= dca3_get_tag(&adapter->pdev->dev, cpu);
 		txctrl |= IXGBE_DCA_TXCTRL_DESC_DCA_EN;
 		IXGBE_WRITE_REG(&adapter->hw, IXGBE_DCA_TXCTRL(q), txctrl);
-		txr->cpu = cpu;
+		tx_ring->cpu = cpu;
 	}
 	put_cpu();
 }
@@ -351,11 +359,14 @@
 
 	switch (event) {
 	case DCA_PROVIDER_ADD:
-		adapter->flags |= IXGBE_FLAG_DCA_ENABLED;
+		/* if we're already enabled, don't do it again */
+		if (adapter->flags & IXGBE_FLAG_DCA_ENABLED)
+			break;
 		/* Always use CB2 mode, difference is masked
 		 * in the CB driver. */
 		IXGBE_WRITE_REG(&adapter->hw, IXGBE_DCA_CTRL, 2);
 		if (dca_add_requester(dev) == 0) {
+			adapter->flags |= IXGBE_FLAG_DCA_ENABLED;
 			ixgbe_setup_dca(adapter);
 			break;
 		}
@@ -372,7 +383,7 @@
 	return 0;
 }
 
-#endif /* CONFIG_DCA */
+#endif /* CONFIG_DCA or CONFIG_DCA_MODULE */
 /**
  * ixgbe_receive_skb - Send a completed packet up the stack
  * @adapter: board private structure
@@ -382,8 +393,8 @@
  * @rx_desc: rx descriptor
  **/
 static void ixgbe_receive_skb(struct ixgbe_adapter *adapter,
-			      struct sk_buff *skb, u8 status,
-			      struct ixgbe_ring *ring,
+                              struct sk_buff *skb, u8 status,
+                              struct ixgbe_ring *ring,
                               union ixgbe_adv_rx_desc *rx_desc)
 {
 	bool is_vlan = (status & IXGBE_RXD_STAT_VP);
@@ -420,14 +431,12 @@
  * @skb: skb currently being received and modified
  **/
 static inline void ixgbe_rx_checksum(struct ixgbe_adapter *adapter,
-					 u32 status_err,
-					 struct sk_buff *skb)
+                                     u32 status_err, struct sk_buff *skb)
 {
 	skb->ip_summed = CHECKSUM_NONE;
 
-	/* Ignore Checksum bit is set, or rx csum disabled */
-	if ((status_err & IXGBE_RXD_STAT_IXSM) ||
-	    !(adapter->flags & IXGBE_FLAG_RX_CSUM_ENABLED))
+	/* Rx csum disabled */
+	if (!(adapter->flags & IXGBE_FLAG_RX_CSUM_ENABLED))
 		return;
 
 	/* if IP and error */
@@ -455,37 +464,44 @@
  * @adapter: address of board private structure
  **/
 static void ixgbe_alloc_rx_buffers(struct ixgbe_adapter *adapter,
-				       struct ixgbe_ring *rx_ring,
-				       int cleaned_count)
+                                   struct ixgbe_ring *rx_ring,
+                                   int cleaned_count)
 {
-	struct net_device *netdev = adapter->netdev;
 	struct pci_dev *pdev = adapter->pdev;
 	union ixgbe_adv_rx_desc *rx_desc;
-	struct ixgbe_rx_buffer *rx_buffer_info;
-	struct sk_buff *skb;
+	struct ixgbe_rx_buffer *bi;
 	unsigned int i;
-	unsigned int bufsz = adapter->rx_buf_len + NET_IP_ALIGN;
+	unsigned int bufsz = rx_ring->rx_buf_len + NET_IP_ALIGN;
 
 	i = rx_ring->next_to_use;
-	rx_buffer_info = &rx_ring->rx_buffer_info[i];
+	bi = &rx_ring->rx_buffer_info[i];
 
 	while (cleaned_count--) {
 		rx_desc = IXGBE_RX_DESC_ADV(*rx_ring, i);
 
-		if (!rx_buffer_info->page &&
-				(adapter->flags & IXGBE_FLAG_RX_PS_ENABLED)) {
-			rx_buffer_info->page = alloc_page(GFP_ATOMIC);
-			if (!rx_buffer_info->page) {
-				adapter->alloc_rx_page_failed++;
-				goto no_buffers;
+		if (!bi->page_dma &&
+		    (adapter->flags & IXGBE_FLAG_RX_PS_ENABLED)) {
+			if (!bi->page) {
+				bi->page = alloc_page(GFP_ATOMIC);
+				if (!bi->page) {
+					adapter->alloc_rx_page_failed++;
+					goto no_buffers;
+				}
+				bi->page_offset = 0;
+			} else {
+				/* use a half page if we're re-using */
+				bi->page_offset ^= (PAGE_SIZE / 2);
 			}
-			rx_buffer_info->page_dma =
-			    pci_map_page(pdev, rx_buffer_info->page,
-					 0, PAGE_SIZE, PCI_DMA_FROMDEVICE);
+
+			bi->page_dma = pci_map_page(pdev, bi->page,
+			                            bi->page_offset,
+			                            (PAGE_SIZE / 2),
+			                            PCI_DMA_FROMDEVICE);
 		}
 
-		if (!rx_buffer_info->skb) {
-			skb = netdev_alloc_skb(netdev, bufsz);
+		if (!bi->skb) {
+			struct sk_buff *skb = netdev_alloc_skb(adapter->netdev,
+			                                       bufsz);
 
 			if (!skb) {
 				adapter->alloc_rx_buff_failed++;
@@ -499,28 +515,25 @@
 			 */
 			skb_reserve(skb, NET_IP_ALIGN);
 
-			rx_buffer_info->skb = skb;
-			rx_buffer_info->dma = pci_map_single(pdev, skb->data,
-							  bufsz,
-							  PCI_DMA_FROMDEVICE);
+			bi->skb = skb;
+			bi->dma = pci_map_single(pdev, skb->data, bufsz,
+			                         PCI_DMA_FROMDEVICE);
 		}
 		/* Refresh the desc even if buffer_addrs didn't change because
 		 * each write-back erases this info. */
 		if (adapter->flags & IXGBE_FLAG_RX_PS_ENABLED) {
-			rx_desc->read.pkt_addr =
-			    cpu_to_le64(rx_buffer_info->page_dma);
-			rx_desc->read.hdr_addr =
-					cpu_to_le64(rx_buffer_info->dma);
+			rx_desc->read.pkt_addr = cpu_to_le64(bi->page_dma);
+			rx_desc->read.hdr_addr = cpu_to_le64(bi->dma);
 		} else {
-			rx_desc->read.pkt_addr =
-					cpu_to_le64(rx_buffer_info->dma);
+			rx_desc->read.pkt_addr = cpu_to_le64(bi->dma);
 		}
 
 		i++;
 		if (i == rx_ring->count)
 			i = 0;
-		rx_buffer_info = &rx_ring->rx_buffer_info[i];
+		bi = &rx_ring->rx_buffer_info[i];
 	}
+
 no_buffers:
 	if (rx_ring->next_to_use != i) {
 		rx_ring->next_to_use = i;
@@ -538,46 +551,54 @@
 	}
 }
 
-static bool ixgbe_clean_rx_irq(struct ixgbe_adapter *adapter,
-			       struct ixgbe_ring *rx_ring,
-			       int *work_done, int work_to_do)
+static inline u16 ixgbe_get_hdr_info(union ixgbe_adv_rx_desc *rx_desc)
 {
-	struct net_device *netdev = adapter->netdev;
+	return rx_desc->wb.lower.lo_dword.hs_rss.hdr_info;
+}
+
+static inline u16 ixgbe_get_pkt_info(union ixgbe_adv_rx_desc *rx_desc)
+{
+	return rx_desc->wb.lower.lo_dword.hs_rss.pkt_info;
+}
+
+static bool ixgbe_clean_rx_irq(struct ixgbe_adapter *adapter,
+                               struct ixgbe_ring *rx_ring,
+                               int *work_done, int work_to_do)
+{
 	struct pci_dev *pdev = adapter->pdev;
 	union ixgbe_adv_rx_desc *rx_desc, *next_rxd;
 	struct ixgbe_rx_buffer *rx_buffer_info, *next_buffer;
 	struct sk_buff *skb;
 	unsigned int i;
-	u32 upper_len, len, staterr;
+	u32 len, staterr;
 	u16 hdr_info;
 	bool cleaned = false;
 	int cleaned_count = 0;
 	unsigned int total_rx_bytes = 0, total_rx_packets = 0;
 
 	i = rx_ring->next_to_clean;
-	upper_len = 0;
 	rx_desc = IXGBE_RX_DESC_ADV(*rx_ring, i);
 	staterr = le32_to_cpu(rx_desc->wb.upper.status_error);
 	rx_buffer_info = &rx_ring->rx_buffer_info[i];
 
 	while (staterr & IXGBE_RXD_STAT_DD) {
+		u32 upper_len = 0;
 		if (*work_done >= work_to_do)
 			break;
 		(*work_done)++;
 
 		if (adapter->flags & IXGBE_FLAG_RX_PS_ENABLED) {
-			hdr_info =
-			    le16_to_cpu(rx_desc->wb.lower.lo_dword.hdr_info);
-			len =
-			    ((hdr_info & IXGBE_RXDADV_HDRBUFLEN_MASK) >>
-			     IXGBE_RXDADV_HDRBUFLEN_SHIFT);
+			hdr_info = le16_to_cpu(ixgbe_get_hdr_info(rx_desc));
+			len = (hdr_info & IXGBE_RXDADV_HDRBUFLEN_MASK) >>
+			       IXGBE_RXDADV_HDRBUFLEN_SHIFT;
 			if (hdr_info & IXGBE_RXDADV_SPH)
 				adapter->rx_hdr_split++;
 			if (len > IXGBE_RX_HDR_SIZE)
 				len = IXGBE_RX_HDR_SIZE;
 			upper_len = le16_to_cpu(rx_desc->wb.upper.length);
-		} else
+		} else {
 			len = le16_to_cpu(rx_desc->wb.upper.length);
+		}
 
 		cleaned = true;
 		skb = rx_buffer_info->skb;
@@ -586,18 +607,25 @@
 
 		if (len && !skb_shinfo(skb)->nr_frags) {
 			pci_unmap_single(pdev, rx_buffer_info->dma,
-					 adapter->rx_buf_len + NET_IP_ALIGN,
-					 PCI_DMA_FROMDEVICE);
+			                 rx_ring->rx_buf_len + NET_IP_ALIGN,
+			                 PCI_DMA_FROMDEVICE);
 			skb_put(skb, len);
 		}
 
 		if (upper_len) {
 			pci_unmap_page(pdev, rx_buffer_info->page_dma,
-				       PAGE_SIZE, PCI_DMA_FROMDEVICE);
+			               PAGE_SIZE / 2, PCI_DMA_FROMDEVICE);
 			rx_buffer_info->page_dma = 0;
 			skb_fill_page_desc(skb, skb_shinfo(skb)->nr_frags,
-					   rx_buffer_info->page, 0, upper_len);
-			rx_buffer_info->page = NULL;
+			                   rx_buffer_info->page,
+			                   rx_buffer_info->page_offset,
+			                   upper_len);
+
+			if ((rx_ring->rx_buf_len > (PAGE_SIZE / 2)) ||
+			    (page_count(rx_buffer_info->page) != 1))
+				rx_buffer_info->page = NULL;
+			else
+				get_page(rx_buffer_info->page);
 
 			skb->len += upper_len;
 			skb->data_len += upper_len;
@@ -620,6 +648,7 @@
 			rx_buffer_info->skb = next_buffer->skb;
 			rx_buffer_info->dma = next_buffer->dma;
 			next_buffer->skb = skb;
+			next_buffer->dma = 0;
 			adapter->non_eop_descs++;
 			goto next_desc;
 		}
@@ -635,9 +664,9 @@
 		total_rx_bytes += skb->len;
 		total_rx_packets++;
 
-		skb->protocol = eth_type_trans(skb, netdev);
+		skb->protocol = eth_type_trans(skb, adapter->netdev);
 		ixgbe_receive_skb(adapter, skb, staterr, rx_ring, rx_desc);
-		netdev->last_rx = jiffies;
+		adapter->netdev->last_rx = jiffies;
 
 next_desc:
 		rx_desc->wb.upper.status_error = 0;
@@ -666,9 +695,6 @@
 	if (cleaned_count)
 		ixgbe_alloc_rx_buffers(adapter, rx_ring, cleaned_count);
 
-	adapter->net_stats.rx_bytes += total_rx_bytes;
-	adapter->net_stats.rx_packets += total_rx_packets;
-
 	rx_ring->total_packets += total_rx_packets;
 	rx_ring->total_bytes += total_rx_bytes;
 	adapter->net_stats.rx_bytes += total_rx_bytes;
@@ -700,43 +726,43 @@
 		q_vector = &adapter->q_vector[v_idx];
 		/* XXX for_each_bit(...) */
 		r_idx = find_first_bit(q_vector->rxr_idx,
-				      adapter->num_rx_queues);
+		                       adapter->num_rx_queues);
 
 		for (i = 0; i < q_vector->rxr_count; i++) {
 			j = adapter->rx_ring[r_idx].reg_idx;
 			ixgbe_set_ivar(adapter, IXGBE_IVAR_RX_QUEUE(j), v_idx);
 			r_idx = find_next_bit(q_vector->rxr_idx,
-					      adapter->num_rx_queues,
-					      r_idx + 1);
+			                      adapter->num_rx_queues,
+			                      r_idx + 1);
 		}
 		r_idx = find_first_bit(q_vector->txr_idx,
-				       adapter->num_tx_queues);
+		                       adapter->num_tx_queues);
 
 		for (i = 0; i < q_vector->txr_count; i++) {
 			j = adapter->tx_ring[r_idx].reg_idx;
 			ixgbe_set_ivar(adapter, IXGBE_IVAR_TX_QUEUE(j), v_idx);
 			r_idx = find_next_bit(q_vector->txr_idx,
-					      adapter->num_tx_queues,
-					      r_idx + 1);
+			                      adapter->num_tx_queues,
+			                      r_idx + 1);
 		}
 
-		/* if this is a tx only vector use half the irq (tx) rate */
+		/* if this is a tx only vector halve the interrupt rate */
 		if (q_vector->txr_count && !q_vector->rxr_count)
-			q_vector->eitr = adapter->tx_eitr;
+			q_vector->eitr = (adapter->eitr_param >> 1);
 		else
-			/* rx only or mixed */
-			q_vector->eitr = adapter->rx_eitr;
+			/* rx only */
+			q_vector->eitr = adapter->eitr_param;
 
 		IXGBE_WRITE_REG(&adapter->hw, IXGBE_EITR(v_idx),
-				EITR_INTS_PER_SEC_TO_REG(q_vector->eitr));
+		                EITR_INTS_PER_SEC_TO_REG(q_vector->eitr));
 	}
 
 	ixgbe_set_ivar(adapter, IXGBE_IVAR_OTHER_CAUSES_INDEX, v_idx);
 	IXGBE_WRITE_REG(&adapter->hw, IXGBE_EITR(v_idx), 1950);
 
-	/* set up to autoclear timer, lsc, and the vectors */
+	/* set up to autoclear timer, and the vectors */
 	mask = IXGBE_EIMS_ENABLE_MASK;
-	mask &= ~IXGBE_EIMS_OTHER;
+	mask &= ~(IXGBE_EIMS_OTHER | IXGBE_EIMS_LSC);
 	IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIAC, mask);
 }
 
@@ -766,8 +792,8 @@
  *      parameter (see ixgbe_param.c)
  **/
 static u8 ixgbe_update_itr(struct ixgbe_adapter *adapter,
-			   u32 eitr, u8 itr_setting,
-			   int packets, int bytes)
+                           u32 eitr, u8 itr_setting,
+                           int packets, int bytes)
 {
 	unsigned int retval = itr_setting;
 	u32 timepassed_us;
@@ -814,40 +840,40 @@
 	u32 new_itr;
 	u8 current_itr, ret_itr;
 	int i, r_idx, v_idx = ((void *)q_vector - (void *)(adapter->q_vector)) /
-			      sizeof(struct ixgbe_q_vector);
+	                       sizeof(struct ixgbe_q_vector);
 	struct ixgbe_ring *rx_ring, *tx_ring;
 
 	r_idx = find_first_bit(q_vector->txr_idx, adapter->num_tx_queues);
 	for (i = 0; i < q_vector->txr_count; i++) {
 		tx_ring = &(adapter->tx_ring[r_idx]);
 		ret_itr = ixgbe_update_itr(adapter, q_vector->eitr,
-					   q_vector->tx_eitr,
-					   tx_ring->total_packets,
-					   tx_ring->total_bytes);
+		                           q_vector->tx_itr,
+		                           tx_ring->total_packets,
+		                           tx_ring->total_bytes);
 		/* if the result for this queue would decrease interrupt
 		 * rate for this vector then use that result */
-		q_vector->tx_eitr = ((q_vector->tx_eitr > ret_itr) ?
-				    q_vector->tx_eitr - 1 : ret_itr);
+		q_vector->tx_itr = ((q_vector->tx_itr > ret_itr) ?
+		                    q_vector->tx_itr - 1 : ret_itr);
 		r_idx = find_next_bit(q_vector->txr_idx, adapter->num_tx_queues,
-				      r_idx + 1);
+		                      r_idx + 1);
 	}
 
 	r_idx = find_first_bit(q_vector->rxr_idx, adapter->num_rx_queues);
 	for (i = 0; i < q_vector->rxr_count; i++) {
 		rx_ring = &(adapter->rx_ring[r_idx]);
 		ret_itr = ixgbe_update_itr(adapter, q_vector->eitr,
-					   q_vector->rx_eitr,
-					   rx_ring->total_packets,
-					   rx_ring->total_bytes);
+		                           q_vector->rx_itr,
+		                           rx_ring->total_packets,
+		                           rx_ring->total_bytes);
 		/* if the result for this queue would decrease interrupt
 		 * rate for this vector then use that result */
-		q_vector->rx_eitr = ((q_vector->rx_eitr > ret_itr) ?
-				    q_vector->rx_eitr - 1 : ret_itr);
+		q_vector->rx_itr = ((q_vector->rx_itr > ret_itr) ?
+		                    q_vector->rx_itr - 1 : ret_itr);
 		r_idx = find_next_bit(q_vector->rxr_idx, adapter->num_rx_queues,
-				      r_idx + 1);
+		                      r_idx + 1);
 	}
 
-	current_itr = max(q_vector->rx_eitr, q_vector->tx_eitr);
+	current_itr = max(q_vector->rx_itr, q_vector->tx_itr);
 
 	switch (current_itr) {
 	/* counts and packets in update_itr are dependent on these numbers */
@@ -871,13 +897,27 @@
 		itr_reg = EITR_INTS_PER_SEC_TO_REG(new_itr);
 		/* must write high and low 16 bits to reset counter */
 		DPRINTK(TX_ERR, DEBUG, "writing eitr(%d): %08X\n", v_idx,
-			itr_reg);
+		        itr_reg);
 		IXGBE_WRITE_REG(hw, IXGBE_EITR(v_idx), itr_reg | (itr_reg)<<16);
 	}
 
 	return;
 }
 
+
+static void ixgbe_check_lsc(struct ixgbe_adapter *adapter)
+{
+	struct ixgbe_hw *hw = &adapter->hw;
+
+	adapter->lsc_int++;
+	adapter->flags |= IXGBE_FLAG_NEED_LINK_UPDATE;
+	adapter->link_check_timeout = jiffies;
+	if (!test_bit(__IXGBE_DOWN, &adapter->state)) {
+		IXGBE_WRITE_REG(hw, IXGBE_EIMC, IXGBE_EIMC_LSC);
+		schedule_work(&adapter->watchdog_task);
+	}
+}
+
 static irqreturn_t ixgbe_msix_lsc(int irq, void *data)
 {
 	struct net_device *netdev = data;
@@ -885,11 +925,8 @@
 	struct ixgbe_hw *hw = &adapter->hw;
 	u32 eicr = IXGBE_READ_REG(hw, IXGBE_EICR);
 
-	if (eicr & IXGBE_EICR_LSC) {
-		adapter->lsc_int++;
-		if (!test_bit(__IXGBE_DOWN, &adapter->state))
-			mod_timer(&adapter->watchdog_timer, jiffies);
-	}
+	if (eicr & IXGBE_EICR_LSC)
+		ixgbe_check_lsc(adapter);
 
 	if (!test_bit(__IXGBE_DOWN, &adapter->state))
 		IXGBE_WRITE_REG(hw, IXGBE_EIMS, IXGBE_EIMS_OTHER);
@@ -901,7 +938,7 @@
 {
 	struct ixgbe_q_vector *q_vector = data;
 	struct ixgbe_adapter  *adapter = q_vector->adapter;
-	struct ixgbe_ring     *txr;
+	struct ixgbe_ring     *tx_ring;
 	int i, r_idx;
 
 	if (!q_vector->txr_count)
@@ -909,16 +946,16 @@
 
 	r_idx = find_first_bit(q_vector->txr_idx, adapter->num_tx_queues);
 	for (i = 0; i < q_vector->txr_count; i++) {
-		txr = &(adapter->tx_ring[r_idx]);
-#ifdef CONFIG_DCA
+		tx_ring = &(adapter->tx_ring[r_idx]);
+#if defined(CONFIG_DCA) || defined(CONFIG_DCA_MODULE)
 		if (adapter->flags & IXGBE_FLAG_DCA_ENABLED)
-			ixgbe_update_tx_dca(adapter, txr);
+			ixgbe_update_tx_dca(adapter, tx_ring);
 #endif
-		txr->total_bytes = 0;
-		txr->total_packets = 0;
-		ixgbe_clean_tx_irq(adapter, txr);
+		tx_ring->total_bytes = 0;
+		tx_ring->total_packets = 0;
+		ixgbe_clean_tx_irq(adapter, tx_ring);
 		r_idx = find_next_bit(q_vector->txr_idx, adapter->num_tx_queues,
-				      r_idx + 1);
+		                      r_idx + 1);
 	}
 
 	return IRQ_HANDLED;
@@ -933,18 +970,26 @@
 {
 	struct ixgbe_q_vector *q_vector = data;
 	struct ixgbe_adapter  *adapter = q_vector->adapter;
-	struct ixgbe_ring  *rxr;
+	struct ixgbe_ring  *rx_ring;
 	int r_idx;
+	int i;
 
 	r_idx = find_first_bit(q_vector->rxr_idx, adapter->num_rx_queues);
+	for (i = 0;  i < q_vector->rxr_count; i++) {
+		rx_ring = &(adapter->rx_ring[r_idx]);
+		rx_ring->total_bytes = 0;
+		rx_ring->total_packets = 0;
+		r_idx = find_next_bit(q_vector->rxr_idx, adapter->num_rx_queues,
+		                      r_idx + 1);
+	}
+
 	if (!q_vector->rxr_count)
 		return IRQ_HANDLED;
 
-	rxr = &(adapter->rx_ring[r_idx]);
+	r_idx = find_first_bit(q_vector->rxr_idx, adapter->num_rx_queues);
+	rx_ring = &(adapter->rx_ring[r_idx]);
 	/* disable interrupts on this vector only */
-	IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC, rxr->v_idx);
-	rxr->total_bytes = 0;
-	rxr->total_packets = 0;
+	IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC, rx_ring->v_idx);
 	netif_rx_schedule(adapter->netdev, &q_vector->napi);
 
 	return IRQ_HANDLED;
@@ -963,39 +1008,90 @@
  * @napi: napi struct with our devices info in it
  * @budget: amount of work driver is allowed to do this pass, in packets
  *
+ * This function is optimized for cleaning one queue only on a single
+ * q_vector!!!
  **/
 static int ixgbe_clean_rxonly(struct napi_struct *napi, int budget)
 {
 	struct ixgbe_q_vector *q_vector =
-			       container_of(napi, struct ixgbe_q_vector, napi);
+	                       container_of(napi, struct ixgbe_q_vector, napi);
 	struct ixgbe_adapter *adapter = q_vector->adapter;
-	struct ixgbe_ring *rxr;
+	struct ixgbe_ring *rx_ring = NULL;
 	int work_done = 0;
 	long r_idx;
 
 	r_idx = find_first_bit(q_vector->rxr_idx, adapter->num_rx_queues);
-	rxr = &(adapter->rx_ring[r_idx]);
-#ifdef CONFIG_DCA
+	rx_ring = &(adapter->rx_ring[r_idx]);
+#if defined(CONFIG_DCA) || defined(CONFIG_DCA_MODULE)
 	if (adapter->flags & IXGBE_FLAG_DCA_ENABLED)
-		ixgbe_update_rx_dca(adapter, rxr);
+		ixgbe_update_rx_dca(adapter, rx_ring);
 #endif
 
-	ixgbe_clean_rx_irq(adapter, rxr, &work_done, budget);
+	ixgbe_clean_rx_irq(adapter, rx_ring, &work_done, budget);
 
 	/* If all Rx work done, exit the polling mode */
 	if (work_done < budget) {
 		netif_rx_complete(adapter->netdev, napi);
-		if (adapter->rx_eitr < IXGBE_MIN_ITR_USECS)
+		if (adapter->itr_setting & 3)
 			ixgbe_set_itr_msix(q_vector);
 		if (!test_bit(__IXGBE_DOWN, &adapter->state))
-			IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS, rxr->v_idx);
+			IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS, rx_ring->v_idx);
 	}
 
 	return work_done;
 }
 
+/**
+ * ixgbe_clean_rxonly_many - msix (aka one shot) rx clean routine
+ * @napi: napi struct with our devices info in it
+ * @budget: amount of work driver is allowed to do this pass, in packets
+ *
+ * This function will clean more than one rx queue associated with a
+ * q_vector.
+ **/
+static int ixgbe_clean_rxonly_many(struct napi_struct *napi, int budget)
+{
+	struct ixgbe_q_vector *q_vector =
+	                       container_of(napi, struct ixgbe_q_vector, napi);
+	struct ixgbe_adapter *adapter = q_vector->adapter;
+	struct ixgbe_ring *rx_ring = NULL;
+	int work_done = 0, i;
+	long r_idx;
+	u16 enable_mask = 0;
+
+	/* attempt to distribute budget to each queue fairly, but don't allow
+	 * the budget to go below 1 because we'll exit polling */
+	budget /= (q_vector->rxr_count ?: 1);
+	budget = max(budget, 1);
+	r_idx = find_first_bit(q_vector->rxr_idx, adapter->num_rx_queues);
+	for (i = 0; i < q_vector->rxr_count; i++) {
+		rx_ring = &(adapter->rx_ring[r_idx]);
+#if defined(CONFIG_DCA) || defined(CONFIG_DCA_MODULE)
+		if (adapter->flags & IXGBE_FLAG_DCA_ENABLED)
+			ixgbe_update_rx_dca(adapter, rx_ring);
+#endif
+		ixgbe_clean_rx_irq(adapter, rx_ring, &work_done, budget);
+		enable_mask |= rx_ring->v_idx;
+		r_idx = find_next_bit(q_vector->rxr_idx, adapter->num_rx_queues,
+		                      r_idx + 1);
+	}
+
+	r_idx = find_first_bit(q_vector->rxr_idx, adapter->num_rx_queues);
+	rx_ring = &(adapter->rx_ring[r_idx]);
+	/* If all Rx work done, exit the polling mode */
+	if (work_done < budget) {
+		netif_rx_complete(adapter->netdev, napi);
+		if (adapter->itr_setting & 3)
+			ixgbe_set_itr_msix(q_vector);
+		if (!test_bit(__IXGBE_DOWN, &adapter->state))
+			IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS, enable_mask);
+		return 0;
+	}
+
+	return work_done;
+}
 static inline void map_vector_to_rxq(struct ixgbe_adapter *a, int v_idx,
-				     int r_idx)
+                                     int r_idx)
 {
 	a->q_vector[v_idx].adapter = a;
 	set_bit(r_idx, a->q_vector[v_idx].rxr_idx);
@@ -1004,7 +1100,7 @@
 }
 
 static inline void map_vector_to_txq(struct ixgbe_adapter *a, int v_idx,
-				     int r_idx)
+                                     int r_idx)
 {
 	a->q_vector[v_idx].adapter = a;
 	set_bit(r_idx, a->q_vector[v_idx].txr_idx);
@@ -1024,7 +1120,7 @@
  * mapping configurations in here.
  **/
 static int ixgbe_map_rings_to_vectors(struct ixgbe_adapter *adapter,
-				      int vectors)
+                                      int vectors)
 {
 	int v_start = 0;
 	int rxr_idx = 0, txr_idx = 0;
@@ -1101,28 +1197,28 @@
 		goto out;
 
 #define SET_HANDLER(_v) ((!(_v)->rxr_count) ? &ixgbe_msix_clean_tx : \
-			 (!(_v)->txr_count) ? &ixgbe_msix_clean_rx : \
-			 &ixgbe_msix_clean_many)
+                         (!(_v)->txr_count) ? &ixgbe_msix_clean_rx : \
+                         &ixgbe_msix_clean_many)
 	for (vector = 0; vector < q_vectors; vector++) {
 		handler = SET_HANDLER(&adapter->q_vector[vector]);
 		sprintf(adapter->name[vector], "%s:v%d-%s",
-			netdev->name, vector,
-			(handler == &ixgbe_msix_clean_rx) ? "Rx" :
-			 ((handler == &ixgbe_msix_clean_tx) ? "Tx" : "TxRx"));
+		        netdev->name, vector,
+		        (handler == &ixgbe_msix_clean_rx) ? "Rx" :
+		         ((handler == &ixgbe_msix_clean_tx) ? "Tx" : "TxRx"));
 		err = request_irq(adapter->msix_entries[vector].vector,
-				  handler, 0, adapter->name[vector],
-				  &(adapter->q_vector[vector]));
+		                  handler, 0, adapter->name[vector],
+		                  &(adapter->q_vector[vector]));
 		if (err) {
 			DPRINTK(PROBE, ERR,
-				"request_irq failed for MSIX interrupt "
-				"Error: %d\n", err);
+			        "request_irq failed for MSIX interrupt "
+			        "Error: %d\n", err);
 			goto free_queue_irqs;
 		}
 	}
 
 	sprintf(adapter->name[vector], "%s:lsc", netdev->name);
 	err = request_irq(adapter->msix_entries[vector].vector,
-			  &ixgbe_msix_lsc, 0, adapter->name[vector], netdev);
+	                  &ixgbe_msix_lsc, 0, adapter->name[vector], netdev);
 	if (err) {
 		DPRINTK(PROBE, ERR,
 			"request_irq for msix_lsc failed: %d\n", err);
@@ -1134,7 +1230,7 @@
 free_queue_irqs:
 	for (i = vector - 1; i >= 0; i--)
 		free_irq(adapter->msix_entries[--vector].vector,
-			 &(adapter->q_vector[i]));
+		         &(adapter->q_vector[i]));
 	adapter->flags &= ~IXGBE_FLAG_MSIX_ENABLED;
 	pci_disable_msix(adapter->pdev);
 	kfree(adapter->msix_entries);
@@ -1152,16 +1248,16 @@
 	struct ixgbe_ring *rx_ring = &adapter->rx_ring[0];
 	struct ixgbe_ring *tx_ring = &adapter->tx_ring[0];
 
-	q_vector->tx_eitr = ixgbe_update_itr(adapter, new_itr,
-					     q_vector->tx_eitr,
-					     tx_ring->total_packets,
-					     tx_ring->total_bytes);
-	q_vector->rx_eitr = ixgbe_update_itr(adapter, new_itr,
-					     q_vector->rx_eitr,
-					     rx_ring->total_packets,
-					     rx_ring->total_bytes);
+	q_vector->tx_itr = ixgbe_update_itr(adapter, new_itr,
+	                                    q_vector->tx_itr,
+	                                    tx_ring->total_packets,
+	                                    tx_ring->total_bytes);
+	q_vector->rx_itr = ixgbe_update_itr(adapter, new_itr,
+	                                    q_vector->rx_itr,
+	                                    rx_ring->total_packets,
+	                                    rx_ring->total_bytes);
 
-	current_itr = max(q_vector->rx_eitr, q_vector->tx_eitr);
+	current_itr = max(q_vector->rx_itr, q_vector->tx_itr);
 
 	switch (current_itr) {
 	/* counts and packets in update_itr are dependent on these numbers */
@@ -1206,19 +1302,19 @@
 	struct ixgbe_hw *hw = &adapter->hw;
 	u32 eicr;
 
-
 	/* for NAPI, using EIAM to auto-mask tx/rx interrupt bits on read
 	 * therefore no explict interrupt disable is necessary */
 	eicr = IXGBE_READ_REG(hw, IXGBE_EICR);
-	if (!eicr)
+	if (!eicr) {
+		/* shared interrupt alert!
+		 * make sure interrupts are enabled because the read will
+		 * have disabled interrupts due to EIAM */
+		ixgbe_irq_enable(adapter);
 		return IRQ_NONE;	/* Not our interrupt */
-
-	if (eicr & IXGBE_EICR_LSC) {
-		adapter->lsc_int++;
-		if (!test_bit(__IXGBE_DOWN, &adapter->state))
-			mod_timer(&adapter->watchdog_timer, jiffies);
 	}
 
+	if (eicr & IXGBE_EICR_LSC)
+		ixgbe_check_lsc(adapter);
 
 	if (netif_rx_schedule_prep(netdev, &adapter->q_vector[0].napi)) {
 		adapter->tx_ring[0].total_packets = 0;
@@ -1261,10 +1357,10 @@
 		err = ixgbe_request_msix_irqs(adapter);
 	} else if (adapter->flags & IXGBE_FLAG_MSI_ENABLED) {
 		err = request_irq(adapter->pdev->irq, &ixgbe_intr, 0,
-				  netdev->name, netdev);
+		                  netdev->name, netdev);
 	} else {
 		err = request_irq(adapter->pdev->irq, &ixgbe_intr, IRQF_SHARED,
-				  netdev->name, netdev);
+		                  netdev->name, netdev);
 	}
 
 	if (err)
@@ -1288,7 +1384,7 @@
 		i--;
 		for (; i >= 0; i--) {
 			free_irq(adapter->msix_entries[i].vector,
-				 &(adapter->q_vector[i]));
+			         &(adapter->q_vector[i]));
 		}
 
 		ixgbe_reset_q_vectors(adapter);
@@ -1335,7 +1431,7 @@
 	struct ixgbe_hw *hw = &adapter->hw;
 
 	IXGBE_WRITE_REG(hw, IXGBE_EITR(0),
-			EITR_INTS_PER_SEC_TO_REG(adapter->rx_eitr));
+	                EITR_INTS_PER_SEC_TO_REG(adapter->eitr_param));
 
 	ixgbe_set_ivar(adapter, IXGBE_IVAR_RX_QUEUE(0), 0);
 	ixgbe_set_ivar(adapter, IXGBE_IVAR_TX_QUEUE(0), 0);
@@ -1347,26 +1443,31 @@
 }
 
 /**
- * ixgbe_configure_tx - Configure 8254x Transmit Unit after Reset
+ * ixgbe_configure_tx - Configure 8259x Transmit Unit after Reset
  * @adapter: board private structure
  *
  * Configure the Tx unit of the MAC after a reset.
  **/
 static void ixgbe_configure_tx(struct ixgbe_adapter *adapter)
 {
-	u64 tdba;
+	u64 tdba, tdwba;
 	struct ixgbe_hw *hw = &adapter->hw;
 	u32 i, j, tdlen, txctrl;
 
 	/* Setup the HW Tx Head and Tail descriptor pointers */
 	for (i = 0; i < adapter->num_tx_queues; i++) {
-		j = adapter->tx_ring[i].reg_idx;
-		tdba = adapter->tx_ring[i].dma;
-		tdlen = adapter->tx_ring[i].count *
-			sizeof(union ixgbe_adv_tx_desc);
+		struct ixgbe_ring *ring = &adapter->tx_ring[i];
+		j = ring->reg_idx;
+		tdba = ring->dma;
+		tdlen = ring->count * sizeof(union ixgbe_adv_tx_desc);
 		IXGBE_WRITE_REG(hw, IXGBE_TDBAL(j),
-				(tdba & DMA_32BIT_MASK));
+		                (tdba & DMA_32BIT_MASK));
 		IXGBE_WRITE_REG(hw, IXGBE_TDBAH(j), (tdba >> 32));
+		tdwba = ring->dma +
+		        (ring->count * sizeof(union ixgbe_adv_tx_desc));
+		tdwba |= IXGBE_TDWBAL_HEAD_WB_ENABLE;
+		IXGBE_WRITE_REG(hw, IXGBE_TDWBAL(j), tdwba & DMA_32BIT_MASK);
+		IXGBE_WRITE_REG(hw, IXGBE_TDWBAH(j), (tdwba >> 32));
 		IXGBE_WRITE_REG(hw, IXGBE_TDLEN(j), tdlen);
 		IXGBE_WRITE_REG(hw, IXGBE_TDH(j), 0);
 		IXGBE_WRITE_REG(hw, IXGBE_TDT(j), 0);
@@ -1375,20 +1476,66 @@
 		/* Disable Tx Head Writeback RO bit, since this hoses
 		 * bookkeeping if things aren't delivered in order.
 		 */
-		txctrl = IXGBE_READ_REG(hw, IXGBE_DCA_TXCTRL(i));
+		txctrl = IXGBE_READ_REG(hw, IXGBE_DCA_TXCTRL(j));
 		txctrl &= ~IXGBE_DCA_TXCTRL_TX_WB_RO_EN;
-		IXGBE_WRITE_REG(hw, IXGBE_DCA_TXCTRL(i), txctrl);
+		IXGBE_WRITE_REG(hw, IXGBE_DCA_TXCTRL(j), txctrl);
 	}
 }
 
-#define PAGE_USE_COUNT(S) (((S) >> PAGE_SHIFT) + \
-			(((S) & (PAGE_SIZE - 1)) ? 1 : 0))
+#define IXGBE_SRRCTL_BSIZEHDRSIZE_SHIFT	2
 
-#define IXGBE_SRRCTL_BSIZEHDRSIZE_SHIFT			2
+static void ixgbe_configure_srrctl(struct ixgbe_adapter *adapter, int index)
+{
+	struct ixgbe_ring *rx_ring;
+	u32 srrctl;
+	int queue0;
+	unsigned long mask;
+
+	/* program one srrctl register per VMDq index */
+	if (adapter->flags & IXGBE_FLAG_VMDQ_ENABLED) {
+		long shift, len;
+		mask = (unsigned long) adapter->ring_feature[RING_F_RSS].mask;
+		len = sizeof(adapter->ring_feature[RING_F_VMDQ].mask) * 8;
+		shift = find_first_bit(&mask, len);
+		queue0 = index & mask;
+		index = (index & mask) >> shift;
+	/* program one srrctl per RSS queue since RDRXCTL.MVMEN is enabled */
+	} else {
+		mask = (unsigned long) adapter->ring_feature[RING_F_RSS].mask;
+		queue0 = index & mask;
+		index = index & mask;
+	}
+
+	rx_ring = &adapter->rx_ring[queue0];
+
+	srrctl = IXGBE_READ_REG(&adapter->hw, IXGBE_SRRCTL(index));
+
+	srrctl &= ~IXGBE_SRRCTL_BSIZEHDR_MASK;
+	srrctl &= ~IXGBE_SRRCTL_BSIZEPKT_MASK;
+
+	if (adapter->flags & IXGBE_FLAG_RX_PS_ENABLED) {
+		srrctl |= IXGBE_RXBUFFER_2048 >> IXGBE_SRRCTL_BSIZEPKT_SHIFT;
+		srrctl |= IXGBE_SRRCTL_DESCTYPE_HDR_SPLIT_ALWAYS;
+		srrctl |= ((IXGBE_RX_HDR_SIZE <<
+		            IXGBE_SRRCTL_BSIZEHDRSIZE_SHIFT) &
+		           IXGBE_SRRCTL_BSIZEHDR_MASK);
+	} else {
+		srrctl |= IXGBE_SRRCTL_DESCTYPE_ADV_ONEBUF;
+
+		if (rx_ring->rx_buf_len == MAXIMUM_ETHERNET_VLAN_SIZE)
+			srrctl |= IXGBE_RXBUFFER_2048 >>
+			          IXGBE_SRRCTL_BSIZEPKT_SHIFT;
+		else
+			srrctl |= rx_ring->rx_buf_len >>
+			          IXGBE_SRRCTL_BSIZEPKT_SHIFT;
+	}
+	IXGBE_WRITE_REG(&adapter->hw, IXGBE_SRRCTL(index), srrctl);
+}
+
 /**
  * ixgbe_get_skb_hdr - helper function for LRO header processing
  * @skb: pointer to sk_buff to be added to LRO packet
- * @iphdr: pointer to tcp header structure
+ * @iphdr: pointer to ip header structure
  * @tcph: pointer to tcp header structure
  * @hdr_flags: pointer to header flags
  * @priv: private data
@@ -1399,8 +1546,8 @@
 	union ixgbe_adv_rx_desc *rx_desc = priv;
 
 	/* Verify that this is a valid IPv4 TCP packet */
-	if (!(rx_desc->wb.lower.lo_dword.pkt_info &
-	    (IXGBE_RXDADV_PKTTYPE_IPV4 | IXGBE_RXDADV_PKTTYPE_TCP)))
+	if (!((ixgbe_get_pkt_info(rx_desc) & IXGBE_RXDADV_PKTTYPE_IPV4) &&
+	     (ixgbe_get_pkt_info(rx_desc) & IXGBE_RXDADV_PKTTYPE_TCP)))
 		return -1;
 
 	/* Set network headers */
@@ -1412,8 +1559,11 @@
 	return 0;
 }
 
+#define PAGE_USE_COUNT(S) (((S) >> PAGE_SHIFT) + \
+                           (((S) & (PAGE_SIZE - 1)) ? 1 : 0))
+
 /**
- * ixgbe_configure_rx - Configure 8254x Receive Unit after Reset
+ * ixgbe_configure_rx - Configure 8259x Receive Unit after Reset
  * @adapter: board private structure
  *
  * Configure the Rx unit of the MAC after a reset.
@@ -1426,25 +1576,26 @@
 	int max_frame = netdev->mtu + ETH_HLEN + ETH_FCS_LEN;
 	int i, j;
 	u32 rdlen, rxctrl, rxcsum;
-	u32 random[10];
+	static const u32 seed[10] = { 0xE291D73D, 0x1805EC6C, 0x2A94B30D,
+	                  0xA54F2BEC, 0xEA49AF7C, 0xE214AD3D, 0xB855AABE,
+	                  0x6A3E67EA, 0x14364D17, 0x3BED200D};
 	u32 fctrl, hlreg0;
 	u32 pages;
-	u32 reta = 0, mrqc, srrctl;
+	u32 reta = 0, mrqc;
+	u32 rdrxctl;
+	int rx_buf_len;
 
 	/* Decide whether to use packet split mode or not */
-	if (netdev->mtu > ETH_DATA_LEN)
-		adapter->flags |= IXGBE_FLAG_RX_PS_ENABLED;
-	else
-		adapter->flags &= ~IXGBE_FLAG_RX_PS_ENABLED;
+	adapter->flags |= IXGBE_FLAG_RX_PS_ENABLED;
 
 	/* Set the RX buffer length according to the mode */
 	if (adapter->flags & IXGBE_FLAG_RX_PS_ENABLED) {
-		adapter->rx_buf_len = IXGBE_RX_HDR_SIZE;
+		rx_buf_len = IXGBE_RX_HDR_SIZE;
 	} else {
 		if (netdev->mtu <= ETH_DATA_LEN)
-			adapter->rx_buf_len = MAXIMUM_ETHERNET_VLAN_SIZE;
+			rx_buf_len = MAXIMUM_ETHERNET_VLAN_SIZE;
 		else
-			adapter->rx_buf_len = ALIGN(max_frame, 1024);
+			rx_buf_len = ALIGN(max_frame, 1024);
 	}
 
 	fctrl = IXGBE_READ_REG(&adapter->hw, IXGBE_FCTRL);
@@ -1461,28 +1612,6 @@
 
 	pages = PAGE_USE_COUNT(adapter->netdev->mtu);
 
-	srrctl = IXGBE_READ_REG(&adapter->hw, IXGBE_SRRCTL(0));
-	srrctl &= ~IXGBE_SRRCTL_BSIZEHDR_MASK;
-	srrctl &= ~IXGBE_SRRCTL_BSIZEPKT_MASK;
-
-	if (adapter->flags & IXGBE_FLAG_RX_PS_ENABLED) {
-		srrctl |= PAGE_SIZE >> IXGBE_SRRCTL_BSIZEPKT_SHIFT;
-		srrctl |= IXGBE_SRRCTL_DESCTYPE_HDR_SPLIT_ALWAYS;
-		srrctl |= ((IXGBE_RX_HDR_SIZE <<
-			    IXGBE_SRRCTL_BSIZEHDRSIZE_SHIFT) &
-			   IXGBE_SRRCTL_BSIZEHDR_MASK);
-	} else {
-		srrctl |= IXGBE_SRRCTL_DESCTYPE_ADV_ONEBUF;
-
-		if (adapter->rx_buf_len == MAXIMUM_ETHERNET_VLAN_SIZE)
-			srrctl |=
-			     IXGBE_RXBUFFER_2048 >> IXGBE_SRRCTL_BSIZEPKT_SHIFT;
-		else
-			srrctl |=
-			     adapter->rx_buf_len >> IXGBE_SRRCTL_BSIZEPKT_SHIFT;
-	}
-	IXGBE_WRITE_REG(&adapter->hw, IXGBE_SRRCTL(0), srrctl);
-
 	rdlen = adapter->rx_ring[0].count * sizeof(union ixgbe_adv_rx_desc);
 	/* disable receives while setting up the descriptors */
 	rxctrl = IXGBE_READ_REG(hw, IXGBE_RXCTRL);
@@ -1492,25 +1621,43 @@
 	 * the Base and Length of the Rx Descriptor Ring */
 	for (i = 0; i < adapter->num_rx_queues; i++) {
 		rdba = adapter->rx_ring[i].dma;
-		IXGBE_WRITE_REG(hw, IXGBE_RDBAL(i), (rdba & DMA_32BIT_MASK));
-		IXGBE_WRITE_REG(hw, IXGBE_RDBAH(i), (rdba >> 32));
-		IXGBE_WRITE_REG(hw, IXGBE_RDLEN(i), rdlen);
-		IXGBE_WRITE_REG(hw, IXGBE_RDH(i), 0);
-		IXGBE_WRITE_REG(hw, IXGBE_RDT(i), 0);
-		adapter->rx_ring[i].head = IXGBE_RDH(i);
-		adapter->rx_ring[i].tail = IXGBE_RDT(i);
+		j = adapter->rx_ring[i].reg_idx;
+		IXGBE_WRITE_REG(hw, IXGBE_RDBAL(j), (rdba & DMA_32BIT_MASK));
+		IXGBE_WRITE_REG(hw, IXGBE_RDBAH(j), (rdba >> 32));
+		IXGBE_WRITE_REG(hw, IXGBE_RDLEN(j), rdlen);
+		IXGBE_WRITE_REG(hw, IXGBE_RDH(j), 0);
+		IXGBE_WRITE_REG(hw, IXGBE_RDT(j), 0);
+		adapter->rx_ring[i].head = IXGBE_RDH(j);
+		adapter->rx_ring[i].tail = IXGBE_RDT(j);
+		adapter->rx_ring[i].rx_buf_len = rx_buf_len;
+		/* Intitial LRO Settings */
+		adapter->rx_ring[i].lro_mgr.max_aggr = IXGBE_MAX_LRO_AGGREGATE;
+		adapter->rx_ring[i].lro_mgr.max_desc = IXGBE_MAX_LRO_DESCRIPTORS;
+		adapter->rx_ring[i].lro_mgr.get_skb_header = ixgbe_get_skb_hdr;
+		adapter->rx_ring[i].lro_mgr.features = LRO_F_EXTRACT_VLAN_ID;
+		if (!(adapter->flags & IXGBE_FLAG_IN_NETPOLL))
+			adapter->rx_ring[i].lro_mgr.features |= LRO_F_NAPI;
+		adapter->rx_ring[i].lro_mgr.dev = adapter->netdev;
+		adapter->rx_ring[i].lro_mgr.ip_summed = CHECKSUM_UNNECESSARY;
+		adapter->rx_ring[i].lro_mgr.ip_summed_aggr = CHECKSUM_UNNECESSARY;
+
+		ixgbe_configure_srrctl(adapter, j);
 	}
 
-	/* Intitial LRO Settings */
-	adapter->rx_ring[i].lro_mgr.max_aggr = IXGBE_MAX_LRO_AGGREGATE;
-	adapter->rx_ring[i].lro_mgr.max_desc = IXGBE_MAX_LRO_DESCRIPTORS;
-	adapter->rx_ring[i].lro_mgr.get_skb_header = ixgbe_get_skb_hdr;
-	adapter->rx_ring[i].lro_mgr.features = LRO_F_EXTRACT_VLAN_ID;
-	if (!(adapter->flags & IXGBE_FLAG_IN_NETPOLL))
-		adapter->rx_ring[i].lro_mgr.features |= LRO_F_NAPI;
-	adapter->rx_ring[i].lro_mgr.dev = adapter->netdev;
-	adapter->rx_ring[i].lro_mgr.ip_summed = CHECKSUM_UNNECESSARY;
-	adapter->rx_ring[i].lro_mgr.ip_summed_aggr = CHECKSUM_UNNECESSARY;
+	/*
+	 * For VMDq support of different descriptor types or
+	 * buffer sizes through the use of multiple SRRCTL
+	 * registers, RDRXCTL.MVMEN must be set to 1
+	 *
+	 * also, the manual doesn't mention it clearly but DCA hints
+	 * will only use queue 0's tags unless this bit is set.  Side
+	 * effects of setting this bit are only that SRRCTL must be
+	 * fully programmed [0..15]
+	 */
+	rdrxctl = IXGBE_READ_REG(hw, IXGBE_RDRXCTL);
+	rdrxctl |= IXGBE_RDRXCTL_MVMEN;
+	IXGBE_WRITE_REG(hw, IXGBE_RDRXCTL, rdrxctl);
+
 
 	if (adapter->flags & IXGBE_FLAG_RSS_ENABLED) {
 		/* Fill out redirection table */
@@ -1525,22 +1672,20 @@
 		}
 
 		/* Fill out hash function seeds */
-		/* XXX use a random constant here to glue certain flows */
-		get_random_bytes(&random[0], 40);
 		for (i = 0; i < 10; i++)
-			IXGBE_WRITE_REG(hw, IXGBE_RSSRK(i), random[i]);
+			IXGBE_WRITE_REG(hw, IXGBE_RSSRK(i), seed[i]);
 
 		mrqc = IXGBE_MRQC_RSSEN
 		    /* Perform hash on these packet types */
-		    | IXGBE_MRQC_RSS_FIELD_IPV4
-		    | IXGBE_MRQC_RSS_FIELD_IPV4_TCP
-		    | IXGBE_MRQC_RSS_FIELD_IPV4_UDP
-		    | IXGBE_MRQC_RSS_FIELD_IPV6_EX_TCP
-		    | IXGBE_MRQC_RSS_FIELD_IPV6_EX
-		    | IXGBE_MRQC_RSS_FIELD_IPV6
-		    | IXGBE_MRQC_RSS_FIELD_IPV6_TCP
-		    | IXGBE_MRQC_RSS_FIELD_IPV6_UDP
-		    | IXGBE_MRQC_RSS_FIELD_IPV6_EX_UDP;
+		       | IXGBE_MRQC_RSS_FIELD_IPV4
+		       | IXGBE_MRQC_RSS_FIELD_IPV4_TCP
+		       | IXGBE_MRQC_RSS_FIELD_IPV4_UDP
+		       | IXGBE_MRQC_RSS_FIELD_IPV6_EX_TCP
+		       | IXGBE_MRQC_RSS_FIELD_IPV6_EX
+		       | IXGBE_MRQC_RSS_FIELD_IPV6
+		       | IXGBE_MRQC_RSS_FIELD_IPV6_TCP
+		       | IXGBE_MRQC_RSS_FIELD_IPV6_UDP
+		       | IXGBE_MRQC_RSS_FIELD_IPV6_EX_UDP;
 		IXGBE_WRITE_REG(hw, IXGBE_MRQC, mrqc);
 	}
 
@@ -1562,7 +1707,7 @@
 }
 
 static void ixgbe_vlan_rx_register(struct net_device *netdev,
-				   struct vlan_group *grp)
+                                   struct vlan_group *grp)
 {
 	struct ixgbe_adapter *adapter = netdev_priv(netdev);
 	u32 ctrl;
@@ -1586,14 +1731,16 @@
 static void ixgbe_vlan_rx_add_vid(struct net_device *netdev, u16 vid)
 {
 	struct ixgbe_adapter *adapter = netdev_priv(netdev);
+	struct ixgbe_hw *hw = &adapter->hw;
 
 	/* add VID to filter table */
-	ixgbe_set_vfta(&adapter->hw, vid, 0, true);
+	hw->mac.ops.set_vfta(&adapter->hw, vid, 0, true);
 }
 
 static void ixgbe_vlan_rx_kill_vid(struct net_device *netdev, u16 vid)
 {
 	struct ixgbe_adapter *adapter = netdev_priv(netdev);
+	struct ixgbe_hw *hw = &adapter->hw;
 
 	if (!test_bit(__IXGBE_DOWN, &adapter->state))
 		ixgbe_irq_disable(adapter);
@@ -1604,7 +1751,7 @@
 		ixgbe_irq_enable(adapter);
 
 	/* remove VID from filter table */
-	ixgbe_set_vfta(&adapter->hw, vid, 0, false);
+	hw->mac.ops.set_vfta(&adapter->hw, vid, 0, false);
 }
 
 static void ixgbe_restore_vlan(struct ixgbe_adapter *adapter)
@@ -1621,23 +1768,37 @@
 	}
 }
 
+static u8 *ixgbe_addr_list_itr(struct ixgbe_hw *hw, u8 **mc_addr_ptr, u32 *vmdq)
+{
+	struct dev_mc_list *mc_ptr;
+	u8 *addr = *mc_addr_ptr;
+	*vmdq = 0;
+
+	mc_ptr = container_of(addr, struct dev_mc_list, dmi_addr[0]);
+	if (mc_ptr->next)
+		*mc_addr_ptr = mc_ptr->next->dmi_addr;
+	else
+		*mc_addr_ptr = NULL;
+
+	return addr;
+}
+
 /**
- * ixgbe_set_multi - Multicast and Promiscuous mode set
+ * ixgbe_set_rx_mode - Unicast, Multicast and Promiscuous mode set
  * @netdev: network interface device structure
  *
- * The set_multi entry point is called whenever the multicast address
- * list or the network interface flags are updated.  This routine is
- * responsible for configuring the hardware for proper multicast,
- * promiscuous mode, and all-multi behavior.
+ * The set_rx_method entry point is called whenever the unicast/multicast
+ * address list or the network interface flags are updated.  This routine is
+ * responsible for configuring the hardware for proper unicast, multicast and
+ * promiscuous mode.
  **/
-static void ixgbe_set_multi(struct net_device *netdev)
+static void ixgbe_set_rx_mode(struct net_device *netdev)
 {
 	struct ixgbe_adapter *adapter = netdev_priv(netdev);
 	struct ixgbe_hw *hw = &adapter->hw;
-	struct dev_mc_list *mc_ptr;
-	u8 *mta_list;
 	u32 fctrl, vlnctrl;
-	int i;
+	u8 *addr_list = NULL;
+	int addr_count = 0;
 
 	/* Check for Promiscuous and All Multicast modes */
 
@@ -1645,6 +1806,7 @@
 	vlnctrl = IXGBE_READ_REG(hw, IXGBE_VLNCTRL);
 
 	if (netdev->flags & IFF_PROMISC) {
+		hw->addr_ctrl.user_set_promisc = 1;
 		fctrl |= (IXGBE_FCTRL_UPE | IXGBE_FCTRL_MPE);
 		vlnctrl &= ~IXGBE_VLNCTRL_VFE;
 	} else {
@@ -1655,33 +1817,25 @@
 			fctrl &= ~(IXGBE_FCTRL_UPE | IXGBE_FCTRL_MPE);
 		}
 		vlnctrl |= IXGBE_VLNCTRL_VFE;
+		hw->addr_ctrl.user_set_promisc = 0;
 	}
 
 	IXGBE_WRITE_REG(hw, IXGBE_FCTRL, fctrl);
 	IXGBE_WRITE_REG(hw, IXGBE_VLNCTRL, vlnctrl);
 
-	if (netdev->mc_count) {
-		mta_list = kcalloc(netdev->mc_count, ETH_ALEN, GFP_ATOMIC);
-		if (!mta_list)
-			return;
+	/* reprogram secondary unicast list */
+	addr_count = netdev->uc_count;
+	if (addr_count)
+		addr_list = netdev->uc_list->dmi_addr;
+	hw->mac.ops.update_uc_addr_list(hw, addr_list, addr_count,
+	                                  ixgbe_addr_list_itr);
 
-		/* Shared function expects packed array of only addresses. */
-		mc_ptr = netdev->mc_list;
-
-		for (i = 0; i < netdev->mc_count; i++) {
-			if (!mc_ptr)
-				break;
-			memcpy(mta_list + (i * ETH_ALEN), mc_ptr->dmi_addr,
-			       ETH_ALEN);
-			mc_ptr = mc_ptr->next;
-		}
-
-		ixgbe_update_mc_addr_list(hw, mta_list, i, 0);
-		kfree(mta_list);
-	} else {
-		ixgbe_update_mc_addr_list(hw, NULL, 0, 0);
-	}
-
+	/* reprogram multicast list */
+	addr_count = netdev->mc_count;
+	if (addr_count)
+		addr_list = netdev->mc_list->dmi_addr;
+	hw->mac.ops.update_mc_addr_list(hw, addr_list, addr_count,
+	                                ixgbe_addr_list_itr);
 }
 
 static void ixgbe_napi_enable_all(struct ixgbe_adapter *adapter)
@@ -1695,10 +1849,16 @@
 		q_vectors = 1;
 
 	for (q_idx = 0; q_idx < q_vectors; q_idx++) {
+		struct napi_struct *napi;
 		q_vector = &adapter->q_vector[q_idx];
 		if (!q_vector->rxr_count)
 			continue;
-		napi_enable(&q_vector->napi);
+		napi = &q_vector->napi;
+		if ((adapter->flags & IXGBE_FLAG_MSIX_ENABLED) &&
+		    (q_vector->rxr_count > 1))
+			napi->poll = &ixgbe_clean_rxonly_many;
+
+		napi_enable(napi);
 	}
 }
 
@@ -1725,7 +1885,7 @@
 	struct net_device *netdev = adapter->netdev;
 	int i;
 
-	ixgbe_set_multi(netdev);
+	ixgbe_set_rx_mode(netdev);
 
 	ixgbe_restore_vlan(adapter);
 
@@ -1733,7 +1893,7 @@
 	ixgbe_configure_rx(adapter);
 	for (i = 0; i < adapter->num_rx_queues; i++)
 		ixgbe_alloc_rx_buffers(adapter, &adapter->rx_ring[i],
-					   (adapter->rx_ring[i].count - 1));
+		                       (adapter->rx_ring[i].count - 1));
 }
 
 static int ixgbe_up_complete(struct ixgbe_adapter *adapter)
@@ -1751,7 +1911,7 @@
 	    (adapter->flags & IXGBE_FLAG_MSI_ENABLED)) {
 		if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED) {
 			gpie = (IXGBE_GPIE_MSIX_MODE | IXGBE_GPIE_EIAME |
-				IXGBE_GPIE_PBA_SUPPORT | IXGBE_GPIE_OCD);
+			        IXGBE_GPIE_PBA_SUPPORT | IXGBE_GPIE_OCD);
 		} else {
 			/* MSI only */
 			gpie = 0;
@@ -1778,6 +1938,8 @@
 	for (i = 0; i < adapter->num_tx_queues; i++) {
 		j = adapter->tx_ring[i].reg_idx;
 		txdctl = IXGBE_READ_REG(hw, IXGBE_TXDCTL(j));
+		/* enable WTHRESH=8 descriptors, to encourage burst writeback */
+		txdctl |= (8 << 16);
 		txdctl |= IXGBE_TXDCTL_ENABLE;
 		IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(j), txdctl);
 	}
@@ -1812,6 +1974,8 @@
 
 	/* bring the link up in the watchdog, this could race with our first
 	 * link up interrupt but shouldn't be a problem */
+	adapter->flags |= IXGBE_FLAG_NEED_LINK_UPDATE;
+	adapter->link_check_timeout = jiffies;
 	mod_timer(&adapter->watchdog_timer, jiffies);
 	return 0;
 }
@@ -1836,58 +2000,22 @@
 
 void ixgbe_reset(struct ixgbe_adapter *adapter)
 {
-	if (ixgbe_init_hw(&adapter->hw))
-		DPRINTK(PROBE, ERR, "Hardware Error\n");
+	struct ixgbe_hw *hw = &adapter->hw;
+	if (hw->mac.ops.init_hw(hw))
+		dev_err(&adapter->pdev->dev, "Hardware Error\n");
 
 	/* reprogram the RAR[0] in case user changed it. */
-	ixgbe_set_rar(&adapter->hw, 0, adapter->hw.mac.addr, 0, IXGBE_RAH_AV);
+	hw->mac.ops.set_rar(hw, 0, hw->mac.addr, 0, IXGBE_RAH_AV);
 
 }
 
-#ifdef CONFIG_PM
-static int ixgbe_resume(struct pci_dev *pdev)
-{
-	struct net_device *netdev = pci_get_drvdata(pdev);
-	struct ixgbe_adapter *adapter = netdev_priv(netdev);
-	u32 err;
-
-	pci_set_power_state(pdev, PCI_D0);
-	pci_restore_state(pdev);
-	err = pci_enable_device(pdev);
-	if (err) {
-		printk(KERN_ERR "ixgbe: Cannot enable PCI device from " \
-				"suspend\n");
-		return err;
-	}
-	pci_set_master(pdev);
-
-	pci_enable_wake(pdev, PCI_D3hot, 0);
-	pci_enable_wake(pdev, PCI_D3cold, 0);
-
-	if (netif_running(netdev)) {
-		err = ixgbe_request_irq(adapter);
-		if (err)
-			return err;
-	}
-
-	ixgbe_reset(adapter);
-
-	if (netif_running(netdev))
-		ixgbe_up(adapter);
-
-	netif_device_attach(netdev);
-
-	return 0;
-}
-#endif
-
 /**
  * ixgbe_clean_rx_ring - Free Rx Buffers per Queue
  * @adapter: board private structure
  * @rx_ring: ring to free buffers from
  **/
 static void ixgbe_clean_rx_ring(struct ixgbe_adapter *adapter,
-				struct ixgbe_ring *rx_ring)
+                                struct ixgbe_ring *rx_ring)
 {
 	struct pci_dev *pdev = adapter->pdev;
 	unsigned long size;
@@ -1901,8 +2029,8 @@
 		rx_buffer_info = &rx_ring->rx_buffer_info[i];
 		if (rx_buffer_info->dma) {
 			pci_unmap_single(pdev, rx_buffer_info->dma,
-					 adapter->rx_buf_len,
-					 PCI_DMA_FROMDEVICE);
+			                 rx_ring->rx_buf_len,
+			                 PCI_DMA_FROMDEVICE);
 			rx_buffer_info->dma = 0;
 		}
 		if (rx_buffer_info->skb) {
@@ -1911,12 +2039,12 @@
 		}
 		if (!rx_buffer_info->page)
 			continue;
-		pci_unmap_page(pdev, rx_buffer_info->page_dma, PAGE_SIZE,
-			       PCI_DMA_FROMDEVICE);
+		pci_unmap_page(pdev, rx_buffer_info->page_dma, PAGE_SIZE / 2,
+		               PCI_DMA_FROMDEVICE);
 		rx_buffer_info->page_dma = 0;
-
 		put_page(rx_buffer_info->page);
 		rx_buffer_info->page = NULL;
+		rx_buffer_info->page_offset = 0;
 	}
 
 	size = sizeof(struct ixgbe_rx_buffer) * rx_ring->count;
@@ -1938,7 +2066,7 @@
  * @tx_ring: ring to be cleaned
  **/
 static void ixgbe_clean_tx_ring(struct ixgbe_adapter *adapter,
-				struct ixgbe_ring *tx_ring)
+                                struct ixgbe_ring *tx_ring)
 {
 	struct ixgbe_tx_buffer *tx_buffer_info;
 	unsigned long size;
@@ -1991,75 +2119,64 @@
 void ixgbe_down(struct ixgbe_adapter *adapter)
 {
 	struct net_device *netdev = adapter->netdev;
+	struct ixgbe_hw *hw = &adapter->hw;
 	u32 rxctrl;
+	u32 txdctl;
+	int i, j;
 
 	/* signal that we are down to the interrupt handler */
 	set_bit(__IXGBE_DOWN, &adapter->state);
 
 	/* disable receives */
-	rxctrl = IXGBE_READ_REG(&adapter->hw, IXGBE_RXCTRL);
-	IXGBE_WRITE_REG(&adapter->hw, IXGBE_RXCTRL,
-			rxctrl & ~IXGBE_RXCTRL_RXEN);
+	rxctrl = IXGBE_READ_REG(hw, IXGBE_RXCTRL);
+	IXGBE_WRITE_REG(hw, IXGBE_RXCTRL, rxctrl & ~IXGBE_RXCTRL_RXEN);
 
 	netif_tx_disable(netdev);
 
-	/* disable transmits in the hardware */
-
-	/* flush both disables */
-	IXGBE_WRITE_FLUSH(&adapter->hw);
+	IXGBE_WRITE_FLUSH(hw);
 	msleep(10);
 
+	netif_tx_stop_all_queues(netdev);
+
 	ixgbe_irq_disable(adapter);
 
 	ixgbe_napi_disable_all(adapter);
+
 	del_timer_sync(&adapter->watchdog_timer);
+	cancel_work_sync(&adapter->watchdog_task);
+
+	/* disable transmits in the hardware now that interrupts are off */
+	for (i = 0; i < adapter->num_tx_queues; i++) {
+		j = adapter->tx_ring[i].reg_idx;
+		txdctl = IXGBE_READ_REG(hw, IXGBE_TXDCTL(j));
+		IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(j),
+		                (txdctl & ~IXGBE_TXDCTL_ENABLE));
+	}
 
 	netif_carrier_off(netdev);
-	netif_tx_stop_all_queues(netdev);
 
+#if defined(CONFIG_DCA) || defined(CONFIG_DCA_MODULE)
+	if (adapter->flags & IXGBE_FLAG_DCA_ENABLED) {
+		adapter->flags &= ~IXGBE_FLAG_DCA_ENABLED;
+		dca_remove_requester(&adapter->pdev->dev);
+	}
+
+#endif
 	if (!pci_channel_offline(adapter->pdev))
 		ixgbe_reset(adapter);
 	ixgbe_clean_all_tx_rings(adapter);
 	ixgbe_clean_all_rx_rings(adapter);
 
-}
-
-static int ixgbe_suspend(struct pci_dev *pdev, pm_message_t state)
-{
-	struct net_device *netdev = pci_get_drvdata(pdev);
-	struct ixgbe_adapter *adapter = netdev_priv(netdev);
-#ifdef CONFIG_PM
-	int retval = 0;
-#endif
-
-	netif_device_detach(netdev);
-
-	if (netif_running(netdev)) {
-		ixgbe_down(adapter);
-		ixgbe_free_irq(adapter);
+#if defined(CONFIG_DCA) || defined(CONFIG_DCA_MODULE)
+	/* since we reset the hardware DCA settings were cleared */
+	if (dca_add_requester(&adapter->pdev->dev) == 0) {
+		adapter->flags |= IXGBE_FLAG_DCA_ENABLED;
+		/* always use CB2 mode, difference is masked
+		 * in the CB driver */
+		IXGBE_WRITE_REG(hw, IXGBE_DCA_CTRL, 2);
+		ixgbe_setup_dca(adapter);
 	}
-
-#ifdef CONFIG_PM
-	retval = pci_save_state(pdev);
-	if (retval)
-		return retval;
 #endif
-
-	pci_enable_wake(pdev, PCI_D3hot, 0);
-	pci_enable_wake(pdev, PCI_D3cold, 0);
-
-	ixgbe_release_hw_control(adapter);
-
-	pci_disable_device(pdev);
-
-	pci_set_power_state(pdev, pci_choose_state(pdev, state));
-
-	return 0;
-}
-
-static void ixgbe_shutdown(struct pci_dev *pdev)
-{
-	ixgbe_suspend(pdev, PMSG_SUSPEND);
 }
 
 /**
@@ -2072,11 +2189,11 @@
 static int ixgbe_poll(struct napi_struct *napi, int budget)
 {
 	struct ixgbe_q_vector *q_vector = container_of(napi,
-					  struct ixgbe_q_vector, napi);
+	                                          struct ixgbe_q_vector, napi);
 	struct ixgbe_adapter *adapter = q_vector->adapter;
-	int tx_cleaned = 0, work_done = 0;
+	int tx_cleaned, work_done = 0;
 
-#ifdef CONFIG_DCA
+#if defined(CONFIG_DCA) || defined(CONFIG_DCA_MODULE)
 	if (adapter->flags & IXGBE_FLAG_DCA_ENABLED) {
 		ixgbe_update_tx_dca(adapter, adapter->tx_ring);
 		ixgbe_update_rx_dca(adapter, adapter->rx_ring);
@@ -2092,12 +2209,11 @@
 	/* If budget not fully consumed, exit the polling mode */
 	if (work_done < budget) {
 		netif_rx_complete(adapter->netdev, napi);
-		if (adapter->rx_eitr < IXGBE_MIN_ITR_USECS)
+		if (adapter->itr_setting & 3)
 			ixgbe_set_itr(adapter);
 		if (!test_bit(__IXGBE_DOWN, &adapter->state))
 			ixgbe_irq_enable(adapter);
 	}
-
 	return work_done;
 }
 
@@ -2123,56 +2239,9 @@
 	ixgbe_reinit_locked(adapter);
 }
 
-static void ixgbe_acquire_msix_vectors(struct ixgbe_adapter *adapter,
-				       int vectors)
+static void ixgbe_set_num_queues(struct ixgbe_adapter *adapter)
 {
-	int err, vector_threshold;
-
-	/* We'll want at least 3 (vector_threshold):
-	 * 1) TxQ[0] Cleanup
-	 * 2) RxQ[0] Cleanup
-	 * 3) Other (Link Status Change, etc.)
-	 * 4) TCP Timer (optional)
-	 */
-	vector_threshold = MIN_MSIX_COUNT;
-
-	/* The more we get, the more we will assign to Tx/Rx Cleanup
-	 * for the separate queues...where Rx Cleanup >= Tx Cleanup.
-	 * Right now, we simply care about how many we'll get; we'll
-	 * set them up later while requesting irq's.
-	 */
-	while (vectors >= vector_threshold) {
-		err = pci_enable_msix(adapter->pdev, adapter->msix_entries,
-				      vectors);
-		if (!err) /* Success in acquiring all requested vectors. */
-			break;
-		else if (err < 0)
-			vectors = 0; /* Nasty failure, quit now */
-		else /* err == number of vectors we should try again with */
-			vectors = err;
-	}
-
-	if (vectors < vector_threshold) {
-		/* Can't allocate enough MSI-X interrupts?  Oh well.
-		 * This just means we'll go with either a single MSI
-		 * vector or fall back to legacy interrupts.
-		 */
-		DPRINTK(HW, DEBUG, "Unable to allocate MSI-X interrupts\n");
-		adapter->flags &= ~IXGBE_FLAG_MSIX_ENABLED;
-		kfree(adapter->msix_entries);
-		adapter->msix_entries = NULL;
-		adapter->flags &= ~IXGBE_FLAG_RSS_ENABLED;
-		adapter->num_tx_queues = 1;
-		adapter->num_rx_queues = 1;
-	} else {
-		adapter->flags |= IXGBE_FLAG_MSIX_ENABLED; /* Woot! */
-		adapter->num_msix_vectors = vectors;
-	}
-}
-
-static void __devinit ixgbe_set_num_queues(struct ixgbe_adapter *adapter)
-{
-	int nrq, ntq;
+	int nrq = 1, ntq = 1;
 	int feature_mask = 0, rss_i, rss_m;
 
 	/* Number of supported queues */
@@ -2210,6 +2279,52 @@
 	adapter->num_tx_queues = ntq;
 }
 
+static void ixgbe_acquire_msix_vectors(struct ixgbe_adapter *adapter,
+                                       int vectors)
+{
+	int err, vector_threshold;
+
+	/* We'll want at least 3 (vector_threshold):
+	 * 1) TxQ[0] Cleanup
+	 * 2) RxQ[0] Cleanup
+	 * 3) Other (Link Status Change, etc.)
+	 * 4) TCP Timer (optional)
+	 */
+	vector_threshold = MIN_MSIX_COUNT;
+
+	/* The more we get, the more we will assign to Tx/Rx Cleanup
+	 * for the separate queues...where Rx Cleanup >= Tx Cleanup.
+	 * Right now, we simply care about how many we'll get; we'll
+	 * set them up later while requesting irq's.
+	 */
+	while (vectors >= vector_threshold) {
+		err = pci_enable_msix(adapter->pdev, adapter->msix_entries,
+		                      vectors);
+		if (!err) /* Success in acquiring all requested vectors. */
+			break;
+		else if (err < 0)
+			vectors = 0; /* Nasty failure, quit now */
+		else /* err == number of vectors we should try again with */
+			vectors = err;
+	}
+
+	if (vectors < vector_threshold) {
+		/* Can't allocate enough MSI-X interrupts?  Oh well.
+		 * This just means we'll go with either a single MSI
+		 * vector or fall back to legacy interrupts.
+		 */
+		DPRINTK(HW, DEBUG, "Unable to allocate MSI-X interrupts\n");
+		adapter->flags &= ~IXGBE_FLAG_MSIX_ENABLED;
+		kfree(adapter->msix_entries);
+		adapter->msix_entries = NULL;
+		adapter->flags &= ~IXGBE_FLAG_RSS_ENABLED;
+		ixgbe_set_num_queues(adapter);
+	} else {
+		adapter->flags |= IXGBE_FLAG_MSIX_ENABLED; /* Woot! */
+		adapter->num_msix_vectors = vectors;
+	}
+}
+
 /**
  * ixgbe_cache_ring_register - Descriptor ring to register mapping
  * @adapter: board private structure to initialize
@@ -2219,9 +2334,6 @@
  **/
 static void __devinit ixgbe_cache_ring_register(struct ixgbe_adapter *adapter)
 {
-	/* TODO: Remove all uses of the indices in the cases where multiple
-	 *       features are OR'd together, if the feature set makes sense.
-	 */
 	int feature_mask = 0, rss_i;
 	int i, txr_idx, rxr_idx;
 
@@ -2262,21 +2374,22 @@
 	int i;
 
 	adapter->tx_ring = kcalloc(adapter->num_tx_queues,
-				   sizeof(struct ixgbe_ring), GFP_KERNEL);
+	                           sizeof(struct ixgbe_ring), GFP_KERNEL);
 	if (!adapter->tx_ring)
 		goto err_tx_ring_allocation;
 
 	adapter->rx_ring = kcalloc(adapter->num_rx_queues,
-				   sizeof(struct ixgbe_ring), GFP_KERNEL);
+	                           sizeof(struct ixgbe_ring), GFP_KERNEL);
 	if (!adapter->rx_ring)
 		goto err_rx_ring_allocation;
 
 	for (i = 0; i < adapter->num_tx_queues; i++) {
-		adapter->tx_ring[i].count = IXGBE_DEFAULT_TXD;
+		adapter->tx_ring[i].count = adapter->tx_ring_count;
 		adapter->tx_ring[i].queue_index = i;
 	}
+
 	for (i = 0; i < adapter->num_rx_queues; i++) {
-		adapter->rx_ring[i].count = IXGBE_DEFAULT_RXD;
+		adapter->rx_ring[i].count = adapter->rx_ring_count;
 		adapter->rx_ring[i].queue_index = i;
 	}
 
@@ -2298,25 +2411,19 @@
  * capabilities of the hardware and the kernel.
  **/
 static int __devinit ixgbe_set_interrupt_capability(struct ixgbe_adapter
-						    *adapter)
+                                                    *adapter)
 {
 	int err = 0;
 	int vector, v_budget;
 
 	/*
-	 * Set the default interrupt throttle rate.
-	 */
-	adapter->rx_eitr = (1000000 / IXGBE_DEFAULT_ITR_RX_USECS);
-	adapter->tx_eitr = (1000000 / IXGBE_DEFAULT_ITR_TX_USECS);
-
-	/*
 	 * It's easy to be greedy for MSI-X vectors, but it really
 	 * doesn't do us much good if we have a lot more vectors
 	 * than CPU's.  So let's be conservative and only ask for
 	 * (roughly) twice the number of vectors as there are CPU's.
 	 */
 	v_budget = min(adapter->num_rx_queues + adapter->num_tx_queues,
-		       (int)(num_online_cpus() * 2)) + NON_Q_VECTORS;
+	               (int)(num_online_cpus() * 2)) + NON_Q_VECTORS;
 
 	/*
 	 * At the same time, hardware can only support a maximum of
@@ -2330,7 +2437,7 @@
 	/* A failure in MSI-X entry allocation isn't fatal, but it does
 	 * mean we disable MSI-X capabilities of the adapter. */
 	adapter->msix_entries = kcalloc(v_budget,
-					sizeof(struct msix_entry), GFP_KERNEL);
+	                                sizeof(struct msix_entry), GFP_KERNEL);
 	if (!adapter->msix_entries) {
 		adapter->flags &= ~IXGBE_FLAG_RSS_ENABLED;
 		ixgbe_set_num_queues(adapter);
@@ -2339,7 +2446,7 @@
 		err = ixgbe_alloc_queues(adapter);
 		if (err) {
 			DPRINTK(PROBE, ERR, "Unable to allocate memory "
-					    "for queues\n");
+			        "for queues\n");
 			goto out;
 		}
 
@@ -2360,7 +2467,7 @@
 		adapter->flags |= IXGBE_FLAG_MSI_ENABLED;
 	} else {
 		DPRINTK(HW, DEBUG, "Unable to allocate MSI interrupt, "
-				   "falling back to legacy.  Error: %d\n", err);
+		        "falling back to legacy.  Error: %d\n", err);
 		/* reset err */
 		err = 0;
 	}
@@ -2416,9 +2523,9 @@
 	}
 
 	DPRINTK(DRV, INFO, "Multiqueue %s: Rx Queue count = %u, "
-			   "Tx Queue count = %u\n",
-		(adapter->num_rx_queues > 1) ? "Enabled" :
-		"Disabled", adapter->num_rx_queues, adapter->num_tx_queues);
+	        "Tx Queue count = %u\n",
+	        (adapter->num_rx_queues > 1) ? "Enabled" :
+	        "Disabled", adapter->num_rx_queues, adapter->num_tx_queues);
 
 	set_bit(__IXGBE_DOWN, &adapter->state);
 
@@ -2445,33 +2552,44 @@
 	struct pci_dev *pdev = adapter->pdev;
 	unsigned int rss;
 
+	/* PCI config space info */
+
+	hw->vendor_id = pdev->vendor;
+	hw->device_id = pdev->device;
+	hw->revision_id = pdev->revision;
+	hw->subsystem_vendor_id = pdev->subsystem_vendor;
+	hw->subsystem_device_id = pdev->subsystem_device;
+
 	/* Set capability flags */
 	rss = min(IXGBE_MAX_RSS_INDICES, (int)num_online_cpus());
 	adapter->ring_feature[RING_F_RSS].indices = rss;
 	adapter->flags |= IXGBE_FLAG_RSS_ENABLED;
 
-	/* Enable Dynamic interrupt throttling by default */
-	adapter->rx_eitr = 1;
-	adapter->tx_eitr = 1;
-
 	/* default flow control settings */
-	hw->fc.original_type = ixgbe_fc_full;
-	hw->fc.type = ixgbe_fc_full;
+	hw->fc.original_type = ixgbe_fc_none;
+	hw->fc.type = ixgbe_fc_none;
+	hw->fc.high_water = IXGBE_DEFAULT_FCRTH;
+	hw->fc.low_water = IXGBE_DEFAULT_FCRTL;
+	hw->fc.pause_time = IXGBE_DEFAULT_FCPAUSE;
+	hw->fc.send_xon = true;
 
 	/* select 10G link by default */
 	hw->mac.link_mode_select = IXGBE_AUTOC_LMS_10G_LINK_NO_AN;
-	if (hw->mac.ops.reset(hw)) {
-		dev_err(&pdev->dev, "HW Init failed\n");
-		return -EIO;
-	}
-	if (hw->mac.ops.setup_link_speed(hw, IXGBE_LINK_SPEED_10GB_FULL, true,
-					 false)) {
-		dev_err(&pdev->dev, "Link Speed setup failed\n");
-		return -EIO;
-	}
+
+	/* enable itr by default in dynamic mode */
+	adapter->itr_setting = 1;
+	adapter->eitr_param = 20000;
+
+	/* set defaults for eitr in MegaBytes */
+	adapter->eitr_low = 10;
+	adapter->eitr_high = 20;
+
+	/* set default ring sizes */
+	adapter->tx_ring_count = IXGBE_DEFAULT_TXD;
+	adapter->rx_ring_count = IXGBE_DEFAULT_RXD;
 
 	/* initialize eeprom parameters */
-	if (ixgbe_init_eeprom(hw)) {
+	if (ixgbe_init_eeprom_params_generic(hw)) {
 		dev_err(&pdev->dev, "EEPROM initialization failed\n");
 		return -EIO;
 	}
@@ -2487,105 +2605,157 @@
 /**
  * ixgbe_setup_tx_resources - allocate Tx resources (Descriptors)
  * @adapter: board private structure
- * @txdr:    tx descriptor ring (for a specific queue) to setup
+ * @tx_ring:    tx descriptor ring (for a specific queue) to setup
  *
  * Return 0 on success, negative on failure
  **/
 int ixgbe_setup_tx_resources(struct ixgbe_adapter *adapter,
-			     struct ixgbe_ring *txdr)
+                             struct ixgbe_ring *tx_ring)
 {
 	struct pci_dev *pdev = adapter->pdev;
 	int size;
 
-	size = sizeof(struct ixgbe_tx_buffer) * txdr->count;
-	txdr->tx_buffer_info = vmalloc(size);
-	if (!txdr->tx_buffer_info) {
-		DPRINTK(PROBE, ERR,
-		"Unable to allocate memory for the transmit descriptor ring\n");
-		return -ENOMEM;
-	}
-	memset(txdr->tx_buffer_info, 0, size);
+	size = sizeof(struct ixgbe_tx_buffer) * tx_ring->count;
+	tx_ring->tx_buffer_info = vmalloc(size);
+	if (!tx_ring->tx_buffer_info)
+		goto err;
+	memset(tx_ring->tx_buffer_info, 0, size);
 
 	/* round up to nearest 4K */
-	txdr->size = txdr->count * sizeof(union ixgbe_adv_tx_desc);
-	txdr->size = ALIGN(txdr->size, 4096);
+	tx_ring->size = tx_ring->count * sizeof(union ixgbe_adv_tx_desc) +
+	                sizeof(u32);
+	tx_ring->size = ALIGN(tx_ring->size, 4096);
 
-	txdr->desc = pci_alloc_consistent(pdev, txdr->size, &txdr->dma);
-	if (!txdr->desc) {
-		vfree(txdr->tx_buffer_info);
-		DPRINTK(PROBE, ERR,
-			"Memory allocation failed for the tx desc ring\n");
-		return -ENOMEM;
+	tx_ring->desc = pci_alloc_consistent(pdev, tx_ring->size,
+	                                     &tx_ring->dma);
+	if (!tx_ring->desc)
+		goto err;
+
+	tx_ring->next_to_use = 0;
+	tx_ring->next_to_clean = 0;
+	tx_ring->work_limit = tx_ring->count;
+	return 0;
+
+err:
+	vfree(tx_ring->tx_buffer_info);
+	tx_ring->tx_buffer_info = NULL;
+	DPRINTK(PROBE, ERR, "Unable to allocate memory for the transmit "
+	                    "descriptor ring\n");
+	return -ENOMEM;
+}
+
+/**
+ * ixgbe_setup_all_tx_resources - allocate all queues Tx resources
+ * @adapter: board private structure
+ *
+ * If this function returns with an error, then it's possible one or
+ * more of the rings is populated (while the rest are not).  It is the
+ * callers duty to clean those orphaned rings.
+ *
+ * Return 0 on success, negative on failure
+ **/
+static int ixgbe_setup_all_tx_resources(struct ixgbe_adapter *adapter)
+{
+	int i, err = 0;
+
+	for (i = 0; i < adapter->num_tx_queues; i++) {
+		err = ixgbe_setup_tx_resources(adapter, &adapter->tx_ring[i]);
+		if (!err)
+			continue;
+		DPRINTK(PROBE, ERR, "Allocation for Tx Queue %u failed\n", i);
+		break;
 	}
 
-	txdr->next_to_use = 0;
-	txdr->next_to_clean = 0;
-	txdr->work_limit = txdr->count;
-
-	return 0;
+	return err;
 }
 
 /**
  * ixgbe_setup_rx_resources - allocate Rx resources (Descriptors)
  * @adapter: board private structure
- * @rxdr:    rx descriptor ring (for a specific queue) to setup
+ * @rx_ring:    rx descriptor ring (for a specific queue) to setup
  *
  * Returns 0 on success, negative on failure
  **/
 int ixgbe_setup_rx_resources(struct ixgbe_adapter *adapter,
-			     struct ixgbe_ring *rxdr)
+                             struct ixgbe_ring *rx_ring)
 {
 	struct pci_dev *pdev = adapter->pdev;
 	int size;
 
 	size = sizeof(struct net_lro_desc) * IXGBE_MAX_LRO_DESCRIPTORS;
-	rxdr->lro_mgr.lro_arr = vmalloc(size);
-	if (!rxdr->lro_mgr.lro_arr)
+	rx_ring->lro_mgr.lro_arr = vmalloc(size);
+	if (!rx_ring->lro_mgr.lro_arr)
 		return -ENOMEM;
-	memset(rxdr->lro_mgr.lro_arr, 0, size);
+	memset(rx_ring->lro_mgr.lro_arr, 0, size);
 
-	size = sizeof(struct ixgbe_rx_buffer) * rxdr->count;
-	rxdr->rx_buffer_info = vmalloc(size);
-	if (!rxdr->rx_buffer_info) {
+	size = sizeof(struct ixgbe_rx_buffer) * rx_ring->count;
+	rx_ring->rx_buffer_info = vmalloc(size);
+	if (!rx_ring->rx_buffer_info) {
 		DPRINTK(PROBE, ERR,
-			"vmalloc allocation failed for the rx desc ring\n");
+		        "vmalloc allocation failed for the rx desc ring\n");
 		goto alloc_failed;
 	}
-	memset(rxdr->rx_buffer_info, 0, size);
+	memset(rx_ring->rx_buffer_info, 0, size);
 
 	/* Round up to nearest 4K */
-	rxdr->size = rxdr->count * sizeof(union ixgbe_adv_rx_desc);
-	rxdr->size = ALIGN(rxdr->size, 4096);
+	rx_ring->size = rx_ring->count * sizeof(union ixgbe_adv_rx_desc);
+	rx_ring->size = ALIGN(rx_ring->size, 4096);
 
-	rxdr->desc = pci_alloc_consistent(pdev, rxdr->size, &rxdr->dma);
+	rx_ring->desc = pci_alloc_consistent(pdev, rx_ring->size, &rx_ring->dma);
 
-	if (!rxdr->desc) {
+	if (!rx_ring->desc) {
 		DPRINTK(PROBE, ERR,
-			"Memory allocation failed for the rx desc ring\n");
-		vfree(rxdr->rx_buffer_info);
+		        "Memory allocation failed for the rx desc ring\n");
+		vfree(rx_ring->rx_buffer_info);
 		goto alloc_failed;
 	}
 
-	rxdr->next_to_clean = 0;
-	rxdr->next_to_use = 0;
+	rx_ring->next_to_clean = 0;
+	rx_ring->next_to_use = 0;
 
 	return 0;
 
 alloc_failed:
-	vfree(rxdr->lro_mgr.lro_arr);
-	rxdr->lro_mgr.lro_arr = NULL;
+	vfree(rx_ring->lro_mgr.lro_arr);
+	rx_ring->lro_mgr.lro_arr = NULL;
 	return -ENOMEM;
 }
 
 /**
+ * ixgbe_setup_all_rx_resources - allocate all queues Rx resources
+ * @adapter: board private structure
+ *
+ * If this function returns with an error, then it's possible one or
+ * more of the rings is populated (while the rest are not).  It is the
+ * callers duty to clean those orphaned rings.
+ *
+ * Return 0 on success, negative on failure
+ **/
+
+static int ixgbe_setup_all_rx_resources(struct ixgbe_adapter *adapter)
+{
+	int i, err = 0;
+
+	for (i = 0; i < adapter->num_rx_queues; i++) {
+		err = ixgbe_setup_rx_resources(adapter, &adapter->rx_ring[i]);
+		if (!err)
+			continue;
+		DPRINTK(PROBE, ERR, "Allocation for Rx Queue %u failed\n", i);
+		break;
+	}
+
+	return err;
+}
+
+/**
  * ixgbe_free_tx_resources - Free Tx Resources per Queue
  * @adapter: board private structure
  * @tx_ring: Tx descriptor ring for a specific queue
  *
  * Free all transmit software resources
  **/
-static void ixgbe_free_tx_resources(struct ixgbe_adapter *adapter,
-				    struct ixgbe_ring *tx_ring)
+void ixgbe_free_tx_resources(struct ixgbe_adapter *adapter,
+                             struct ixgbe_ring *tx_ring)
 {
 	struct pci_dev *pdev = adapter->pdev;
 
@@ -2620,8 +2790,8 @@
  *
  * Free all receive software resources
  **/
-static void ixgbe_free_rx_resources(struct ixgbe_adapter *adapter,
-				    struct ixgbe_ring *rx_ring)
+void ixgbe_free_rx_resources(struct ixgbe_adapter *adapter,
+                             struct ixgbe_ring *rx_ring)
 {
 	struct pci_dev *pdev = adapter->pdev;
 
@@ -2653,59 +2823,6 @@
 }
 
 /**
- * ixgbe_setup_all_tx_resources - allocate all queues Tx resources
- * @adapter: board private structure
- *
- * If this function returns with an error, then it's possible one or
- * more of the rings is populated (while the rest are not).  It is the
- * callers duty to clean those orphaned rings.
- *
- * Return 0 on success, negative on failure
- **/
-static int ixgbe_setup_all_tx_resources(struct ixgbe_adapter *adapter)
-{
-	int i, err = 0;
-
-	for (i = 0; i < adapter->num_tx_queues; i++) {
-		err = ixgbe_setup_tx_resources(adapter, &adapter->tx_ring[i]);
-		if (err) {
-			DPRINTK(PROBE, ERR,
-				"Allocation for Tx Queue %u failed\n", i);
-			break;
-		}
-	}
-
-	return err;
-}
-
-/**
- * ixgbe_setup_all_rx_resources - allocate all queues Rx resources
- * @adapter: board private structure
- *
- * If this function returns with an error, then it's possible one or
- * more of the rings is populated (while the rest are not).  It is the
- * callers duty to clean those orphaned rings.
- *
- * Return 0 on success, negative on failure
- **/
-
-static int ixgbe_setup_all_rx_resources(struct ixgbe_adapter *adapter)
-{
-	int i, err = 0;
-
-	for (i = 0; i < adapter->num_rx_queues; i++) {
-		err = ixgbe_setup_rx_resources(adapter, &adapter->rx_ring[i]);
-		if (err) {
-			DPRINTK(PROBE, ERR,
-				"Allocation for Rx Queue %u failed\n", i);
-			break;
-		}
-	}
-
-	return err;
-}
-
-/**
  * ixgbe_change_mtu - Change the Maximum Transfer Unit
  * @netdev: network interface device structure
  * @new_mtu: new value for maximum frame size
@@ -2717,12 +2834,12 @@
 	struct ixgbe_adapter *adapter = netdev_priv(netdev);
 	int max_frame = new_mtu + ETH_HLEN + ETH_FCS_LEN;
 
-	if ((max_frame < (ETH_ZLEN + ETH_FCS_LEN)) ||
-	    (max_frame > IXGBE_MAX_JUMBO_FRAME_SIZE))
+	/* MTU < 68 is an error and causes problems on some kernels */
+	if ((new_mtu < 68) || (max_frame > IXGBE_MAX_JUMBO_FRAME_SIZE))
 		return -EINVAL;
 
 	DPRINTK(PROBE, INFO, "changing MTU from %d to %d\n",
-		netdev->mtu, new_mtu);
+	        netdev->mtu, new_mtu);
 	/* must set new MTU before calling down or up */
 	netdev->mtu = new_mtu;
 
@@ -2817,6 +2934,135 @@
 }
 
 /**
+ * ixgbe_napi_add_all - prep napi structs for use
+ * @adapter: private struct
+ * helper function to napi_add each possible q_vector->napi
+ */
+static void ixgbe_napi_add_all(struct ixgbe_adapter *adapter)
+{
+	int q_idx, q_vectors;
+	int (*poll)(struct napi_struct *, int);
+
+	if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED) {
+		poll = &ixgbe_clean_rxonly;
+		/* Only enable as many vectors as we have rx queues. */
+		q_vectors = adapter->num_rx_queues;
+	} else {
+		poll = &ixgbe_poll;
+		/* only one q_vector for legacy modes */
+		q_vectors = 1;
+	}
+
+	for (q_idx = 0; q_idx < q_vectors; q_idx++) {
+		struct ixgbe_q_vector *q_vector = &adapter->q_vector[q_idx];
+		netif_napi_add(adapter->netdev, &q_vector->napi, (*poll), 64);
+	}
+}
+
+static void ixgbe_napi_del_all(struct ixgbe_adapter *adapter)
+{
+	int q_idx;
+	int q_vectors = adapter->num_msix_vectors - NON_Q_VECTORS;
+
+	/* legacy and MSI only use one vector */
+	if (!(adapter->flags & IXGBE_FLAG_MSIX_ENABLED))
+		q_vectors = 1;
+
+	for (q_idx = 0; q_idx < q_vectors; q_idx++) {
+		struct ixgbe_q_vector *q_vector = &adapter->q_vector[q_idx];
+		if (!q_vector->rxr_count)
+			continue;
+		netif_napi_del(&q_vector->napi);
+	}
+}
+
+#ifdef CONFIG_PM
+static int ixgbe_resume(struct pci_dev *pdev)
+{
+	struct net_device *netdev = pci_get_drvdata(pdev);
+	struct ixgbe_adapter *adapter = netdev_priv(netdev);
+	u32 err;
+
+	pci_set_power_state(pdev, PCI_D0);
+	pci_restore_state(pdev);
+	err = pci_enable_device(pdev);
+	if (err) {
+		printk(KERN_ERR "ixgbe: Cannot enable PCI device from "
+				"suspend\n");
+		return err;
+	}
+	pci_set_master(pdev);
+
+	pci_enable_wake(pdev, PCI_D3hot, 0);
+	pci_enable_wake(pdev, PCI_D3cold, 0);
+
+	err = ixgbe_init_interrupt_scheme(adapter);
+	if (err) {
+		printk(KERN_ERR "ixgbe: Cannot initialize interrupts for "
+		                "device\n");
+		return err;
+	}
+
+	ixgbe_napi_add_all(adapter);
+	ixgbe_reset(adapter);
+
+	if (netif_running(netdev)) {
+		err = ixgbe_open(adapter->netdev);
+		if (err)
+			return err;
+	}
+
+	netif_device_attach(netdev);
+
+	return 0;
+}
+
+#endif /* CONFIG_PM */
+static int ixgbe_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+	struct net_device *netdev = pci_get_drvdata(pdev);
+	struct ixgbe_adapter *adapter = netdev_priv(netdev);
+#ifdef CONFIG_PM
+	int retval = 0;
+#endif
+
+	netif_device_detach(netdev);
+
+	if (netif_running(netdev)) {
+		ixgbe_down(adapter);
+		ixgbe_free_irq(adapter);
+		ixgbe_free_all_tx_resources(adapter);
+		ixgbe_free_all_rx_resources(adapter);
+	}
+	ixgbe_reset_interrupt_capability(adapter);
+	ixgbe_napi_del_all(adapter);
+	kfree(adapter->tx_ring);
+	kfree(adapter->rx_ring);
+
+#ifdef CONFIG_PM
+	retval = pci_save_state(pdev);
+	if (retval)
+		return retval;
+#endif
+
+	pci_enable_wake(pdev, PCI_D3hot, 0);
+	pci_enable_wake(pdev, PCI_D3cold, 0);
+
+	ixgbe_release_hw_control(adapter);
+
+	pci_disable_device(pdev);
+
+	pci_set_power_state(pdev, pci_choose_state(pdev, state));
+
+	return 0;
+}
+
+static void ixgbe_shutdown(struct pci_dev *pdev)
+{
+	ixgbe_suspend(pdev, PMSG_SUSPEND);
+}
+
+/**
  * ixgbe_update_stats - Update the board statistics counters.
  * @adapter: board private structure
  **/
@@ -2889,7 +3135,7 @@
 
 	/* Rx Errors */
 	adapter->net_stats.rx_errors = adapter->stats.crcerrs +
-						adapter->stats.rlec;
+	                               adapter->stats.rlec;
 	adapter->net_stats.rx_dropped = 0;
 	adapter->net_stats.rx_length_errors = adapter->stats.rlec;
 	adapter->net_stats.rx_crc_errors = adapter->stats.crcerrs;
@@ -2903,27 +3149,74 @@
 static void ixgbe_watchdog(unsigned long data)
 {
 	struct ixgbe_adapter *adapter = (struct ixgbe_adapter *)data;
-	struct net_device *netdev = adapter->netdev;
-	bool link_up;
-	u32 link_speed = 0;
+	struct ixgbe_hw *hw = &adapter->hw;
 
-	adapter->hw.mac.ops.check_link(&adapter->hw, &(link_speed), &link_up);
+	/* Do the watchdog outside of interrupt context due to the lovely
+	 * delays that some of the newer hardware requires */
+	if (!test_bit(__IXGBE_DOWN, &adapter->state)) {
+		/* Cause software interrupt to ensure rx rings are cleaned */
+		if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED) {
+			u32 eics =
+			 (1 << (adapter->num_msix_vectors - NON_Q_VECTORS)) - 1;
+			IXGBE_WRITE_REG(hw, IXGBE_EICS, eics);
+		} else {
+			/* For legacy and MSI interrupts don't set any bits that
+			 * are enabled for EIAM, because this operation would
+			 * set *both* EIMS and EICS for any bit in EIAM */
+			IXGBE_WRITE_REG(hw, IXGBE_EICS,
+                                    (IXGBE_EICS_TCP_TIMER | IXGBE_EICS_OTHER));
+		}
+		/* Reset the timer */
+		mod_timer(&adapter->watchdog_timer,
+		          round_jiffies(jiffies + 2 * HZ));
+	}
+
+	schedule_work(&adapter->watchdog_task);
+}
+
+/**
+ * ixgbe_watchdog_task - worker thread to bring link up
+ * @work: pointer to work_struct containing our data
+ **/
+static void ixgbe_watchdog_task(struct work_struct *work)
+{
+	struct ixgbe_adapter *adapter = container_of(work,
+	                                             struct ixgbe_adapter,
+	                                             watchdog_task);
+	struct net_device *netdev = adapter->netdev;
+	struct ixgbe_hw *hw = &adapter->hw;
+	u32 link_speed = adapter->link_speed;
+	bool link_up = adapter->link_up;
+
+	adapter->flags |= IXGBE_FLAG_IN_WATCHDOG_TASK;
+
+	if (adapter->flags & IXGBE_FLAG_NEED_LINK_UPDATE) {
+		hw->mac.ops.check_link(hw, &link_speed, &link_up, false);
+		if (link_up ||
+		    time_after(jiffies, (adapter->link_check_timeout +
+		                         IXGBE_TRY_LINK_TIMEOUT))) {
+			IXGBE_WRITE_REG(hw, IXGBE_EIMS, IXGBE_EIMC_LSC);
+			adapter->flags &= ~IXGBE_FLAG_NEED_LINK_UPDATE;
+		}
+		adapter->link_up = link_up;
+		adapter->link_speed = link_speed;
+	}
 
 	if (link_up) {
 		if (!netif_carrier_ok(netdev)) {
-			u32 frctl = IXGBE_READ_REG(&adapter->hw, IXGBE_FCTRL);
-			u32 rmcs = IXGBE_READ_REG(&adapter->hw, IXGBE_RMCS);
+			u32 frctl = IXGBE_READ_REG(hw, IXGBE_FCTRL);
+			u32 rmcs = IXGBE_READ_REG(hw, IXGBE_RMCS);
 #define FLOW_RX (frctl & IXGBE_FCTRL_RFCE)
 #define FLOW_TX (rmcs & IXGBE_RMCS_TFCE_802_3X)
 			DPRINTK(LINK, INFO, "NIC Link is Up %s, "
-				"Flow Control: %s\n",
-				(link_speed == IXGBE_LINK_SPEED_10GB_FULL ?
-				 "10 Gbps" :
-				 (link_speed == IXGBE_LINK_SPEED_1GB_FULL ?
-				  "1 Gbps" : "unknown speed")),
-				((FLOW_RX && FLOW_TX) ? "RX/TX" :
-				 (FLOW_RX ? "RX" :
-				 (FLOW_TX ? "TX" : "None"))));
+			        "Flow Control: %s\n",
+			        (link_speed == IXGBE_LINK_SPEED_10GB_FULL ?
+			         "10 Gbps" :
+			         (link_speed == IXGBE_LINK_SPEED_1GB_FULL ?
+			          "1 Gbps" : "unknown speed")),
+			        ((FLOW_RX && FLOW_TX) ? "RX/TX" :
+			         (FLOW_RX ? "RX" :
+			         (FLOW_TX ? "TX" : "None"))));
 
 			netif_carrier_on(netdev);
 			netif_tx_wake_all_queues(netdev);
@@ -2932,6 +3225,8 @@
 			adapter->detect_tx_hung = true;
 		}
 	} else {
+		adapter->link_up = false;
+		adapter->link_speed = 0;
 		if (netif_carrier_ok(netdev)) {
 			DPRINTK(LINK, INFO, "NIC Link is Down\n");
 			netif_carrier_off(netdev);
@@ -2940,36 +3235,19 @@
 	}
 
 	ixgbe_update_stats(adapter);
-
-	if (!test_bit(__IXGBE_DOWN, &adapter->state)) {
-		/* Cause software interrupt to ensure rx rings are cleaned */
-		if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED) {
-			u32 eics =
-			 (1 << (adapter->num_msix_vectors - NON_Q_VECTORS)) - 1;
-			IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS, eics);
-		} else {
-			/* for legacy and MSI interrupts don't set any bits that
-			 * are enabled for EIAM, because this operation would
-			 * set *both* EIMS and EICS for any bit in EIAM */
-			IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS,
-				     (IXGBE_EICS_TCP_TIMER | IXGBE_EICS_OTHER));
-		}
-		/* Reset the timer */
-		mod_timer(&adapter->watchdog_timer,
-			  round_jiffies(jiffies + 2 * HZ));
-	}
+	adapter->flags &= ~IXGBE_FLAG_IN_WATCHDOG_TASK;
 }
 
 static int ixgbe_tso(struct ixgbe_adapter *adapter,
-			 struct ixgbe_ring *tx_ring, struct sk_buff *skb,
-			 u32 tx_flags, u8 *hdr_len)
+                     struct ixgbe_ring *tx_ring, struct sk_buff *skb,
+                     u32 tx_flags, u8 *hdr_len)
 {
 	struct ixgbe_adv_tx_context_desc *context_desc;
 	unsigned int i;
 	int err;
 	struct ixgbe_tx_buffer *tx_buffer_info;
-	u32 vlan_macip_lens = 0, type_tucmd_mlhl = 0;
-	u32 mss_l4len_idx = 0, l4len;
+	u32 vlan_macip_lens = 0, type_tucmd_mlhl;
+	u32 mss_l4len_idx, l4len;
 
 	if (skb_is_gso(skb)) {
 		if (skb_header_cloned(skb)) {
@@ -2985,16 +3263,16 @@
 			iph->tot_len = 0;
 			iph->check = 0;
 			tcp_hdr(skb)->check = ~csum_tcpudp_magic(iph->saddr,
-								 iph->daddr, 0,
-								 IPPROTO_TCP,
-								 0);
+			                                         iph->daddr, 0,
+			                                         IPPROTO_TCP,
+			                                         0);
 			adapter->hw_tso_ctxt++;
 		} else if (skb_shinfo(skb)->gso_type == SKB_GSO_TCPV6) {
 			ipv6_hdr(skb)->payload_len = 0;
 			tcp_hdr(skb)->check =
 			    ~csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
-					     &ipv6_hdr(skb)->daddr,
-					     0, IPPROTO_TCP, 0);
+			                     &ipv6_hdr(skb)->daddr,
+			                     0, IPPROTO_TCP, 0);
 			adapter->hw_tso6_ctxt++;
 		}
 
@@ -3008,7 +3286,7 @@
 			vlan_macip_lens |=
 			    (tx_flags & IXGBE_TX_FLAGS_VLAN_MASK);
 		vlan_macip_lens |= ((skb_network_offset(skb)) <<
-				    IXGBE_ADVTXD_MACLEN_SHIFT);
+		                    IXGBE_ADVTXD_MACLEN_SHIFT);
 		*hdr_len += skb_network_offset(skb);
 		vlan_macip_lens |=
 		    (skb_transport_header(skb) - skb_network_header(skb));
@@ -3018,8 +3296,8 @@
 		context_desc->seqnum_seed = 0;
 
 		/* ADV DTYP TUCMD MKRLOC/ISCSIHEDLEN */
-		type_tucmd_mlhl |= (IXGBE_TXD_CMD_DEXT |
-				    IXGBE_ADVTXD_DTYP_CTXT);
+		type_tucmd_mlhl = (IXGBE_TXD_CMD_DEXT |
+		                   IXGBE_ADVTXD_DTYP_CTXT);
 
 		if (skb->protocol == htons(ETH_P_IP))
 			type_tucmd_mlhl |= IXGBE_ADVTXD_TUCMD_IPV4;
@@ -3027,9 +3305,11 @@
 		context_desc->type_tucmd_mlhl = cpu_to_le32(type_tucmd_mlhl);
 
 		/* MSS L4LEN IDX */
-		mss_l4len_idx |=
+		mss_l4len_idx =
 		    (skb_shinfo(skb)->gso_size << IXGBE_ADVTXD_MSS_SHIFT);
 		mss_l4len_idx |= (l4len << IXGBE_ADVTXD_L4LEN_SHIFT);
+		/* use index 1 for TSO */
+		mss_l4len_idx |= (1 << IXGBE_ADVTXD_IDX_SHIFT);
 		context_desc->mss_l4len_idx = cpu_to_le32(mss_l4len_idx);
 
 		tx_buffer_info->time_stamp = jiffies;
@@ -3046,8 +3326,8 @@
 }
 
 static bool ixgbe_tx_csum(struct ixgbe_adapter *adapter,
-				   struct ixgbe_ring *tx_ring,
-				   struct sk_buff *skb, u32 tx_flags)
+                          struct ixgbe_ring *tx_ring,
+                          struct sk_buff *skb, u32 tx_flags)
 {
 	struct ixgbe_adv_tx_context_desc *context_desc;
 	unsigned int i;
@@ -3064,16 +3344,16 @@
 			vlan_macip_lens |=
 			    (tx_flags & IXGBE_TX_FLAGS_VLAN_MASK);
 		vlan_macip_lens |= (skb_network_offset(skb) <<
-				    IXGBE_ADVTXD_MACLEN_SHIFT);
+		                    IXGBE_ADVTXD_MACLEN_SHIFT);
 		if (skb->ip_summed == CHECKSUM_PARTIAL)
 			vlan_macip_lens |= (skb_transport_header(skb) -
-					    skb_network_header(skb));
+			                    skb_network_header(skb));
 
 		context_desc->vlan_macip_lens = cpu_to_le32(vlan_macip_lens);
 		context_desc->seqnum_seed = 0;
 
 		type_tucmd_mlhl |= (IXGBE_TXD_CMD_DEXT |
-				    IXGBE_ADVTXD_DTYP_CTXT);
+		                    IXGBE_ADVTXD_DTYP_CTXT);
 
 		if (skb->ip_summed == CHECKSUM_PARTIAL) {
 			switch (skb->protocol) {
@@ -3081,16 +3361,14 @@
 				type_tucmd_mlhl |= IXGBE_ADVTXD_TUCMD_IPV4;
 				if (ip_hdr(skb)->protocol == IPPROTO_TCP)
 					type_tucmd_mlhl |=
-						IXGBE_ADVTXD_TUCMD_L4T_TCP;
+					        IXGBE_ADVTXD_TUCMD_L4T_TCP;
 				break;
-
 			case __constant_htons(ETH_P_IPV6):
 				/* XXX what about other V6 headers?? */
 				if (ipv6_hdr(skb)->nexthdr == IPPROTO_TCP)
 					type_tucmd_mlhl |=
-						IXGBE_ADVTXD_TUCMD_L4T_TCP;
+					        IXGBE_ADVTXD_TUCMD_L4T_TCP;
 				break;
-
 			default:
 				if (unlikely(net_ratelimit())) {
 					DPRINTK(PROBE, WARNING,
@@ -3102,10 +3380,12 @@
 		}
 
 		context_desc->type_tucmd_mlhl = cpu_to_le32(type_tucmd_mlhl);
+		/* use index zero for tx checksum offload */
 		context_desc->mss_l4len_idx = 0;
 
 		tx_buffer_info->time_stamp = jiffies;
 		tx_buffer_info->next_to_watch = i;
+
 		adapter->hw_csum_tx_good++;
 		i++;
 		if (i == tx_ring->count)
@@ -3114,12 +3394,13 @@
 
 		return true;
 	}
+
 	return false;
 }
 
 static int ixgbe_tx_map(struct ixgbe_adapter *adapter,
-			struct ixgbe_ring *tx_ring,
-			struct sk_buff *skb, unsigned int first)
+                        struct ixgbe_ring *tx_ring,
+                        struct sk_buff *skb, unsigned int first)
 {
 	struct ixgbe_tx_buffer *tx_buffer_info;
 	unsigned int len = skb->len;
@@ -3137,8 +3418,8 @@
 
 		tx_buffer_info->length = size;
 		tx_buffer_info->dma = pci_map_single(adapter->pdev,
-						  skb->data + offset,
-						  size, PCI_DMA_TODEVICE);
+		                                     skb->data + offset,
+		                                     size, PCI_DMA_TODEVICE);
 		tx_buffer_info->time_stamp = jiffies;
 		tx_buffer_info->next_to_watch = i;
 
@@ -3163,9 +3444,10 @@
 
 			tx_buffer_info->length = size;
 			tx_buffer_info->dma = pci_map_page(adapter->pdev,
-							frag->page,
-							offset,
-							size, PCI_DMA_TODEVICE);
+			                                   frag->page,
+			                                   offset,
+			                                   size,
+			                                   PCI_DMA_TODEVICE);
 			tx_buffer_info->time_stamp = jiffies;
 			tx_buffer_info->next_to_watch = i;
 
@@ -3188,8 +3470,8 @@
 }
 
 static void ixgbe_tx_queue(struct ixgbe_adapter *adapter,
-			       struct ixgbe_ring *tx_ring,
-			       int tx_flags, int count, u32 paylen, u8 hdr_len)
+                           struct ixgbe_ring *tx_ring,
+                           int tx_flags, int count, u32 paylen, u8 hdr_len)
 {
 	union ixgbe_adv_tx_desc *tx_desc = NULL;
 	struct ixgbe_tx_buffer *tx_buffer_info;
@@ -3208,15 +3490,17 @@
 		cmd_type_len |= IXGBE_ADVTXD_DCMD_TSE;
 
 		olinfo_status |= IXGBE_TXD_POPTS_TXSM <<
-						IXGBE_ADVTXD_POPTS_SHIFT;
+		                 IXGBE_ADVTXD_POPTS_SHIFT;
 
+		/* use index 1 context for tso */
+		olinfo_status |= (1 << IXGBE_ADVTXD_IDX_SHIFT);
 		if (tx_flags & IXGBE_TX_FLAGS_IPV4)
 			olinfo_status |= IXGBE_TXD_POPTS_IXSM <<
-						IXGBE_ADVTXD_POPTS_SHIFT;
+			                 IXGBE_ADVTXD_POPTS_SHIFT;
 
 	} else if (tx_flags & IXGBE_TX_FLAGS_CSUM)
 		olinfo_status |= IXGBE_TXD_POPTS_TXSM <<
-						IXGBE_ADVTXD_POPTS_SHIFT;
+		                 IXGBE_ADVTXD_POPTS_SHIFT;
 
 	olinfo_status |= ((paylen - hdr_len) << IXGBE_ADVTXD_PAYLEN_SHIFT);
 
@@ -3226,9 +3510,8 @@
 		tx_desc = IXGBE_TX_DESC_ADV(*tx_ring, i);
 		tx_desc->read.buffer_addr = cpu_to_le64(tx_buffer_info->dma);
 		tx_desc->read.cmd_type_len =
-			cpu_to_le32(cmd_type_len | tx_buffer_info->length);
+		        cpu_to_le32(cmd_type_len | tx_buffer_info->length);
 		tx_desc->read.olinfo_status = cpu_to_le32(olinfo_status);
-
 		i++;
 		if (i == tx_ring->count)
 			i = 0;
@@ -3249,7 +3532,7 @@
 }
 
 static int __ixgbe_maybe_stop_tx(struct net_device *netdev,
-				 struct ixgbe_ring *tx_ring, int size)
+                                 struct ixgbe_ring *tx_ring, int size)
 {
 	struct ixgbe_adapter *adapter = netdev_priv(netdev);
 
@@ -3265,61 +3548,52 @@
 		return -EBUSY;
 
 	/* A reprieve! - use start_queue because it doesn't call schedule */
-	netif_wake_subqueue(netdev, tx_ring->queue_index);
+	netif_start_subqueue(netdev, tx_ring->queue_index);
 	++adapter->restart_queue;
 	return 0;
 }
 
 static int ixgbe_maybe_stop_tx(struct net_device *netdev,
-			       struct ixgbe_ring *tx_ring, int size)
+                              struct ixgbe_ring *tx_ring, int size)
 {
 	if (likely(IXGBE_DESC_UNUSED(tx_ring) >= size))
 		return 0;
 	return __ixgbe_maybe_stop_tx(netdev, tx_ring, size);
 }
 
-
 static int ixgbe_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
 {
 	struct ixgbe_adapter *adapter = netdev_priv(netdev);
 	struct ixgbe_ring *tx_ring;
-	unsigned int len = skb->len;
 	unsigned int first;
 	unsigned int tx_flags = 0;
 	u8 hdr_len = 0;
 	int r_idx = 0, tso;
-	unsigned int mss = 0;
 	int count = 0;
 	unsigned int f;
-	unsigned int nr_frags = skb_shinfo(skb)->nr_frags;
-	len -= skb->data_len;
+
 	r_idx = (adapter->num_tx_queues - 1) & skb->queue_mapping;
 	tx_ring = &adapter->tx_ring[r_idx];
 
-
-	if (skb->len <= 0) {
-		dev_kfree_skb(skb);
-		return NETDEV_TX_OK;
+	if (adapter->vlgrp && vlan_tx_tag_present(skb)) {
+		tx_flags |= vlan_tx_tag_get(skb);
+		tx_flags <<= IXGBE_TX_FLAGS_VLAN_SHIFT;
+		tx_flags |= IXGBE_TX_FLAGS_VLAN;
 	}
-	mss = skb_shinfo(skb)->gso_size;
-
-	if (mss)
-		count++;
-	else if (skb->ip_summed == CHECKSUM_PARTIAL)
+	/* three things can cause us to need a context descriptor */
+	if (skb_is_gso(skb) ||
+	    (skb->ip_summed == CHECKSUM_PARTIAL) ||
+	    (tx_flags & IXGBE_TX_FLAGS_VLAN))
 		count++;
 
-	count += TXD_USE_COUNT(len);
-	for (f = 0; f < nr_frags; f++)
+	count += TXD_USE_COUNT(skb_headlen(skb));
+	for (f = 0; f < skb_shinfo(skb)->nr_frags; f++)
 		count += TXD_USE_COUNT(skb_shinfo(skb)->frags[f].size);
 
 	if (ixgbe_maybe_stop_tx(netdev, tx_ring, count)) {
 		adapter->tx_busy++;
 		return NETDEV_TX_BUSY;
 	}
-	if (adapter->vlgrp && vlan_tx_tag_present(skb)) {
-		tx_flags |= IXGBE_TX_FLAGS_VLAN;
-		tx_flags |= (vlan_tx_tag_get(skb) << IXGBE_TX_FLAGS_VLAN_SHIFT);
-	}
 
 	if (skb->protocol == htons(ETH_P_IP))
 		tx_flags |= IXGBE_TX_FLAGS_IPV4;
@@ -3333,12 +3607,12 @@
 	if (tso)
 		tx_flags |= IXGBE_TX_FLAGS_TSO;
 	else if (ixgbe_tx_csum(adapter, tx_ring, skb, tx_flags) &&
-		 (skb->ip_summed == CHECKSUM_PARTIAL))
+	         (skb->ip_summed == CHECKSUM_PARTIAL))
 		tx_flags |= IXGBE_TX_FLAGS_CSUM;
 
 	ixgbe_tx_queue(adapter, tx_ring, tx_flags,
-			   ixgbe_tx_map(adapter, tx_ring, skb, first),
-			   skb->len, hdr_len);
+	               ixgbe_tx_map(adapter, tx_ring, skb, first),
+	               skb->len, hdr_len);
 
 	netdev->trans_start = jiffies;
 
@@ -3372,15 +3646,16 @@
 static int ixgbe_set_mac(struct net_device *netdev, void *p)
 {
 	struct ixgbe_adapter *adapter = netdev_priv(netdev);
+	struct ixgbe_hw *hw = &adapter->hw;
 	struct sockaddr *addr = p;
 
 	if (!is_valid_ether_addr(addr->sa_data))
 		return -EADDRNOTAVAIL;
 
 	memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len);
-	memcpy(adapter->hw.mac.addr, addr->sa_data, netdev->addr_len);
+	memcpy(hw->mac.addr, addr->sa_data, netdev->addr_len);
 
-	ixgbe_set_rar(&adapter->hw, 0, adapter->hw.mac.addr, 0, IXGBE_RAH_AV);
+	hw->mac.ops.set_rar(hw, 0, hw->mac.addr, 0, IXGBE_RAH_AV);
 
 	return 0;
 }
@@ -3404,28 +3679,19 @@
 #endif
 
 /**
- * ixgbe_napi_add_all - prep napi structs for use
- * @adapter: private struct
- * helper function to napi_add each possible q_vector->napi
- */
-static void ixgbe_napi_add_all(struct ixgbe_adapter *adapter)
+ * ixgbe_link_config - set up initial link with default speed and duplex
+ * @hw: pointer to private hardware struct
+ *
+ * Returns 0 on success, negative on failure
+ **/
+static int ixgbe_link_config(struct ixgbe_hw *hw)
 {
-	int i, q_vectors = adapter->num_msix_vectors - NON_Q_VECTORS;
-	int (*poll)(struct napi_struct *, int);
+	u32 autoneg = IXGBE_LINK_SPEED_10GB_FULL;
 
-	if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED) {
-		poll = &ixgbe_clean_rxonly;
-	} else {
-		poll = &ixgbe_poll;
-		/* only one q_vector for legacy modes */
-		q_vectors = 1;
-	}
+	/* must always autoneg for both 1G and 10G link */
+	hw->mac.autoneg = true;
 
-	for (i = 0; i < q_vectors; i++) {
-		struct ixgbe_q_vector *q_vector = &adapter->q_vector[i];
-		netif_napi_add(adapter->netdev, &q_vector->napi,
-			       (*poll), 64);
-	}
+	return hw->mac.ops.setup_link_speed(hw, autoneg, true, true);
 }
 
 /**
@@ -3440,17 +3706,16 @@
  * and a hardware reset occur.
  **/
 static int __devinit ixgbe_probe(struct pci_dev *pdev,
-				 const struct pci_device_id *ent)
+                                 const struct pci_device_id *ent)
 {
 	struct net_device *netdev;
 	struct ixgbe_adapter *adapter = NULL;
 	struct ixgbe_hw *hw;
 	const struct ixgbe_info *ii = ixgbe_info_tbl[ent->driver_data];
-	unsigned long mmio_start, mmio_len;
 	static int cards_found;
 	int i, err, pci_using_dac;
 	u16 link_status, link_speed, link_width;
-	u32 part_num;
+	u32 part_num, eec;
 
 	err = pci_enable_device(pdev);
 	if (err)
@@ -3465,7 +3730,7 @@
 			err = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
 			if (err) {
 				dev_err(&pdev->dev, "No usable DMA "
-					"configuration, aborting\n");
+				        "configuration, aborting\n");
 				goto err_dma;
 			}
 		}
@@ -3498,10 +3763,8 @@
 	hw->back = adapter;
 	adapter->msg_enable = (1 << DEFAULT_DEBUG_LEVEL_SHIFT) - 1;
 
-	mmio_start = pci_resource_start(pdev, 0);
-	mmio_len = pci_resource_len(pdev, 0);
-
-	hw->hw_addr = ioremap(mmio_start, mmio_len);
+	hw->hw_addr = ioremap(pci_resource_start(pdev, 0),
+	                      pci_resource_len(pdev, 0));
 	if (!hw->hw_addr) {
 		err = -EIO;
 		goto err_ioremap;
@@ -3516,7 +3779,8 @@
 	netdev->stop = &ixgbe_close;
 	netdev->hard_start_xmit = &ixgbe_xmit_frame;
 	netdev->get_stats = &ixgbe_get_stats;
-	netdev->set_multicast_list = &ixgbe_set_multi;
+	netdev->set_rx_mode = &ixgbe_set_rx_mode;
+	netdev->set_multicast_list = &ixgbe_set_rx_mode;
 	netdev->set_mac_address = &ixgbe_set_mac;
 	netdev->change_mtu = &ixgbe_change_mtu;
 	ixgbe_set_ethtool_ops(netdev);
@@ -3530,22 +3794,23 @@
 #endif
 	strcpy(netdev->name, pci_name(pdev));
 
-	netdev->mem_start = mmio_start;
-	netdev->mem_end = mmio_start + mmio_len;
-
 	adapter->bd_number = cards_found;
 
-	/* PCI config space info */
-	hw->vendor_id = pdev->vendor;
-	hw->device_id = pdev->device;
-	hw->revision_id = pdev->revision;
-	hw->subsystem_vendor_id = pdev->subsystem_vendor;
-	hw->subsystem_device_id = pdev->subsystem_device;
-
 	/* Setup hw api */
 	memcpy(&hw->mac.ops, ii->mac_ops, sizeof(hw->mac.ops));
 	hw->mac.type  = ii->mac;
 
+	/* EEPROM */
+	memcpy(&hw->eeprom.ops, ii->eeprom_ops, sizeof(hw->eeprom.ops));
+	eec = IXGBE_READ_REG(hw, IXGBE_EEC);
+	/* If EEPROM is valid (bit 8 = 1), use default otherwise use bit bang */
+	if (!(eec & (1 << 8)))
+		hw->eeprom.ops.read = &ixgbe_read_eeprom_bit_bang_generic;
+
+	/* PHY */
+	memcpy(&hw->phy.ops, ii->phy_ops, sizeof(hw->phy.ops));
+	/* phy->sfp_type = ixgbe_sfp_type_unknown; */
+
 	err = ii->get_invariants(hw);
 	if (err)
 		goto err_hw_init;
@@ -3555,26 +3820,34 @@
 	if (err)
 		goto err_sw_init;
 
-	netdev->features = NETIF_F_SG |
-			   NETIF_F_HW_CSUM |
-			   NETIF_F_HW_VLAN_TX |
-			   NETIF_F_HW_VLAN_RX |
-			   NETIF_F_HW_VLAN_FILTER;
+	/* reset_hw fills in the perm_addr as well */
+	err = hw->mac.ops.reset_hw(hw);
+	if (err) {
+		dev_err(&adapter->pdev->dev, "HW Init failed: %d\n", err);
+		goto err_sw_init;
+	}
 
-	netdev->features |= NETIF_F_LRO;
+	netdev->features = NETIF_F_SG |
+	                   NETIF_F_IP_CSUM |
+	                   NETIF_F_HW_VLAN_TX |
+	                   NETIF_F_HW_VLAN_RX |
+	                   NETIF_F_HW_VLAN_FILTER;
+
+	netdev->features |= NETIF_F_IPV6_CSUM;
 	netdev->features |= NETIF_F_TSO;
 	netdev->features |= NETIF_F_TSO6;
+	netdev->features |= NETIF_F_LRO;
 
 	netdev->vlan_features |= NETIF_F_TSO;
 	netdev->vlan_features |= NETIF_F_TSO6;
-	netdev->vlan_features |= NETIF_F_HW_CSUM;
+	netdev->vlan_features |= NETIF_F_IP_CSUM;
 	netdev->vlan_features |= NETIF_F_SG;
 
 	if (pci_using_dac)
 		netdev->features |= NETIF_F_HIGHDMA;
 
 	/* make sure the EEPROM is good */
-	if (ixgbe_validate_eeprom_checksum(hw, NULL) < 0) {
+	if (hw->eeprom.ops.validate_checksum(hw, NULL) < 0) {
 		dev_err(&pdev->dev, "The EEPROM Checksum Is Not Valid\n");
 		err = -EIO;
 		goto err_eeprom;
@@ -3583,7 +3856,8 @@
 	memcpy(netdev->dev_addr, hw->mac.perm_addr, netdev->addr_len);
 	memcpy(netdev->perm_addr, hw->mac.perm_addr, netdev->addr_len);
 
-	if (ixgbe_validate_mac_addr(netdev->dev_addr)) {
+	if (ixgbe_validate_mac_addr(netdev->perm_addr)) {
+		dev_err(&pdev->dev, "invalid MAC address\n");
 		err = -EIO;
 		goto err_eeprom;
 	}
@@ -3593,13 +3867,7 @@
 	adapter->watchdog_timer.data = (unsigned long)adapter;
 
 	INIT_WORK(&adapter->reset_task, ixgbe_reset_task);
-
-	/* initialize default flow control settings */
-	hw->fc.original_type = ixgbe_fc_full;
-	hw->fc.type = ixgbe_fc_full;
-	hw->fc.high_water = IXGBE_DEFAULT_FCRTH;
-	hw->fc.low_water = IXGBE_DEFAULT_FCRTL;
-	hw->fc.pause_time = IXGBE_DEFAULT_FCPAUSE;
+	INIT_WORK(&adapter->watchdog_task, ixgbe_watchdog_task);
 
 	err = ixgbe_init_interrupt_scheme(adapter);
 	if (err)
@@ -3610,32 +3878,39 @@
 	link_speed = link_status & IXGBE_PCI_LINK_SPEED;
 	link_width = link_status & IXGBE_PCI_LINK_WIDTH;
 	dev_info(&pdev->dev, "(PCI Express:%s:%s) "
-		 "%02x:%02x:%02x:%02x:%02x:%02x\n",
-		((link_speed == IXGBE_PCI_LINK_SPEED_5000) ? "5.0Gb/s" :
-		 (link_speed == IXGBE_PCI_LINK_SPEED_2500) ? "2.5Gb/s" :
-		 "Unknown"),
-		((link_width == IXGBE_PCI_LINK_WIDTH_8) ? "Width x8" :
-		 (link_width == IXGBE_PCI_LINK_WIDTH_4) ? "Width x4" :
-		 (link_width == IXGBE_PCI_LINK_WIDTH_2) ? "Width x2" :
-		 (link_width == IXGBE_PCI_LINK_WIDTH_1) ? "Width x1" :
-		 "Unknown"),
-		netdev->dev_addr[0], netdev->dev_addr[1], netdev->dev_addr[2],
-		netdev->dev_addr[3], netdev->dev_addr[4], netdev->dev_addr[5]);
-	ixgbe_read_part_num(hw, &part_num);
+	         "%02x:%02x:%02x:%02x:%02x:%02x\n",
+	        ((link_speed == IXGBE_PCI_LINK_SPEED_5000) ? "5.0Gb/s" :
+	         (link_speed == IXGBE_PCI_LINK_SPEED_2500) ? "2.5Gb/s" :
+	         "Unknown"),
+	        ((link_width == IXGBE_PCI_LINK_WIDTH_8) ? "Width x8" :
+	         (link_width == IXGBE_PCI_LINK_WIDTH_4) ? "Width x4" :
+	         (link_width == IXGBE_PCI_LINK_WIDTH_2) ? "Width x2" :
+	         (link_width == IXGBE_PCI_LINK_WIDTH_1) ? "Width x1" :
+	         "Unknown"),
+	        netdev->dev_addr[0], netdev->dev_addr[1], netdev->dev_addr[2],
+	        netdev->dev_addr[3], netdev->dev_addr[4], netdev->dev_addr[5]);
+	ixgbe_read_pba_num_generic(hw, &part_num);
 	dev_info(&pdev->dev, "MAC: %d, PHY: %d, PBA No: %06x-%03x\n",
-		 hw->mac.type, hw->phy.type,
-		 (part_num >> 8), (part_num & 0xff));
+	         hw->mac.type, hw->phy.type,
+	         (part_num >> 8), (part_num & 0xff));
 
 	if (link_width <= IXGBE_PCI_LINK_WIDTH_4) {
 		dev_warn(&pdev->dev, "PCI-Express bandwidth available for "
-			 "this card is not sufficient for optimal "
-			 "performance.\n");
+		         "this card is not sufficient for optimal "
+		         "performance.\n");
 		dev_warn(&pdev->dev, "For optimal performance a x8 "
-			 "PCI-Express slot is required.\n");
+		         "PCI-Express slot is required.\n");
 	}
 
 	/* reset the hardware with the new settings */
-	ixgbe_start_hw(hw);
+	hw->mac.ops.start_hw(hw);
+
+	/* link_config depends on start_hw being called at least once */
+	err = ixgbe_link_config(hw);
+	if (err) {
+		dev_err(&pdev->dev, "setup_link_speed FAILED %d\n", err);
+		goto err_register;
+	}
 
 	netif_carrier_off(netdev);
 	netif_tx_stop_all_queues(netdev);
@@ -3647,7 +3922,7 @@
 	if (err)
 		goto err_register;
 
-#ifdef CONFIG_DCA
+#if defined(CONFIG_DCA) || defined(CONFIG_DCA_MODULE)
 	if (dca_add_requester(&pdev->dev) == 0) {
 		adapter->flags |= IXGBE_FLAG_DCA_ENABLED;
 		/* always use CB2 mode, difference is masked
@@ -3697,7 +3972,7 @@
 
 	flush_scheduled_work();
 
-#ifdef CONFIG_DCA
+#if defined(CONFIG_DCA) || defined(CONFIG_DCA_MODULE)
 	if (adapter->flags & IXGBE_FLAG_DCA_ENABLED) {
 		adapter->flags &= ~IXGBE_FLAG_DCA_ENABLED;
 		dca_remove_requester(&pdev->dev);
@@ -3715,6 +3990,7 @@
 	pci_release_regions(pdev);
 
 	DPRINTK(PROBE, INFO, "complete\n");
+	ixgbe_napi_del_all(adapter);
 	kfree(adapter->tx_ring);
 	kfree(adapter->rx_ring);
 
@@ -3732,7 +4008,7 @@
  * this device has been detected.
  */
 static pci_ers_result_t ixgbe_io_error_detected(struct pci_dev *pdev,
-						pci_channel_state_t state)
+                                                pci_channel_state_t state)
 {
 	struct net_device *netdev = pci_get_drvdata(pdev);
 	struct ixgbe_adapter *adapter = netdev->priv;
@@ -3743,7 +4019,7 @@
 		ixgbe_down(adapter);
 	pci_disable_device(pdev);
 
-	/* Request a slot slot reset. */
+	/* Request a slot reset. */
 	return PCI_ERS_RESULT_NEED_RESET;
 }
 
@@ -3760,7 +4036,7 @@
 
 	if (pci_enable_device(pdev)) {
 		DPRINTK(PROBE, ERR,
-			"Cannot re-enable PCI device after reset.\n");
+		        "Cannot re-enable PCI device after reset.\n");
 		return PCI_ERS_RESULT_DISCONNECT;
 	}
 	pci_set_master(pdev);
@@ -3794,7 +4070,6 @@
 	}
 
 	netif_device_attach(netdev);
-
 }
 
 static struct pci_error_handlers ixgbe_err_handler = {
@@ -3830,13 +4105,14 @@
 
 	printk(KERN_INFO "%s: %s\n", ixgbe_driver_name, ixgbe_copyright);
 
-#ifdef CONFIG_DCA
+#if defined(CONFIG_DCA) || defined(CONFIG_DCA_MODULE)
 	dca_register_notify(&dca_notifier);
 
 #endif
 	ret = pci_register_driver(&ixgbe_driver);
 	return ret;
 }
+
 module_init(ixgbe_init_module);
 
 /**
@@ -3847,24 +4123,24 @@
  **/
 static void __exit ixgbe_exit_module(void)
 {
-#ifdef CONFIG_DCA
+#if defined(CONFIG_DCA) || defined(CONFIG_DCA_MODULE)
 	dca_unregister_notify(&dca_notifier);
 #endif
 	pci_unregister_driver(&ixgbe_driver);
 }
 
-#ifdef CONFIG_DCA
+#if defined(CONFIG_DCA) || defined(CONFIG_DCA_MODULE)
 static int ixgbe_notify_dca(struct notifier_block *nb, unsigned long event,
-			    void *p)
+                            void *p)
 {
 	int ret_val;
 
 	ret_val = driver_for_each_device(&ixgbe_driver.driver, NULL, &event,
-					 __ixgbe_notify_dca);
+	                                 __ixgbe_notify_dca);
 
 	return ret_val ? NOTIFY_BAD : NOTIFY_DONE;
 }
-#endif /* CONFIG_DCA */
+#endif /* CONFIG_DCA or CONFIG_DCA_MODULE */
 
 module_exit(ixgbe_exit_module);
 
diff --git a/drivers/net/ixgbe/ixgbe_phy.c b/drivers/net/ixgbe/ixgbe_phy.c
index 8002931..764035a 100644
--- a/drivers/net/ixgbe/ixgbe_phy.c
+++ b/drivers/net/ixgbe/ixgbe_phy.c
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel 10 Gigabit PCI Express Linux driver
-  Copyright(c) 1999 - 2007 Intel Corporation.
+  Copyright(c) 1999 - 2008 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
@@ -20,7 +20,6 @@
   the file called "COPYING".
 
   Contact Information:
-  Linux NICS <linux.nics@intel.com>
   e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
   Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
 
@@ -33,32 +32,36 @@
 #include "ixgbe_common.h"
 #include "ixgbe_phy.h"
 
+static bool ixgbe_validate_phy_addr(struct ixgbe_hw *hw, u32 phy_addr);
 static enum ixgbe_phy_type ixgbe_get_phy_type_from_id(u32 phy_id);
 static s32 ixgbe_get_phy_id(struct ixgbe_hw *hw);
-static bool ixgbe_validate_phy_addr(struct ixgbe_hw *hw, u32 phy_addr);
-static s32 ixgbe_write_phy_reg(struct ixgbe_hw *hw, u32 reg_addr,
-			       u32 device_type, u16 phy_data);
 
 /**
- *  ixgbe_identify_phy - Get physical layer module
+ *  ixgbe_identify_phy_generic - Get physical layer module
  *  @hw: pointer to hardware structure
  *
  *  Determines the physical layer module found on the current adapter.
  **/
-s32 ixgbe_identify_phy(struct ixgbe_hw *hw)
+s32 ixgbe_identify_phy_generic(struct ixgbe_hw *hw)
 {
 	s32 status = IXGBE_ERR_PHY_ADDR_INVALID;
 	u32 phy_addr;
 
-	for (phy_addr = 0; phy_addr < IXGBE_MAX_PHY_ADDR; phy_addr++) {
-		if (ixgbe_validate_phy_addr(hw, phy_addr)) {
-			hw->phy.addr = phy_addr;
-			ixgbe_get_phy_id(hw);
-			hw->phy.type = ixgbe_get_phy_type_from_id(hw->phy.id);
-			status = 0;
-			break;
+	if (hw->phy.type == ixgbe_phy_unknown) {
+		for (phy_addr = 0; phy_addr < IXGBE_MAX_PHY_ADDR; phy_addr++) {
+			if (ixgbe_validate_phy_addr(hw, phy_addr)) {
+				hw->phy.addr = phy_addr;
+				ixgbe_get_phy_id(hw);
+				hw->phy.type =
+				        ixgbe_get_phy_type_from_id(hw->phy.id);
+				status = 0;
+				break;
+			}
 		}
+	} else {
+		status = 0;
 	}
+
 	return status;
 }
 
@@ -73,10 +76,8 @@
 	bool valid = false;
 
 	hw->phy.addr = phy_addr;
-	ixgbe_read_phy_reg(hw,
-			   IXGBE_MDIO_PHY_ID_HIGH,
-			   IXGBE_MDIO_PMA_PMD_DEV_TYPE,
-			   &phy_id);
+	hw->phy.ops.read_reg(hw, IXGBE_MDIO_PHY_ID_HIGH,
+	                     IXGBE_MDIO_PMA_PMD_DEV_TYPE, &phy_id);
 
 	if (phy_id != 0xFFFF && phy_id != 0x0)
 		valid = true;
@@ -95,21 +96,18 @@
 	u16 phy_id_high = 0;
 	u16 phy_id_low = 0;
 
-	status = ixgbe_read_phy_reg(hw,
-				   IXGBE_MDIO_PHY_ID_HIGH,
-				   IXGBE_MDIO_PMA_PMD_DEV_TYPE,
-				   &phy_id_high);
+	status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_PHY_ID_HIGH,
+	                              IXGBE_MDIO_PMA_PMD_DEV_TYPE,
+	                              &phy_id_high);
 
 	if (status == 0) {
 		hw->phy.id = (u32)(phy_id_high << 16);
-		status = ixgbe_read_phy_reg(hw,
-					   IXGBE_MDIO_PHY_ID_LOW,
-					   IXGBE_MDIO_PMA_PMD_DEV_TYPE,
-					   &phy_id_low);
+		status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_PHY_ID_LOW,
+		                              IXGBE_MDIO_PMA_PMD_DEV_TYPE,
+		                              &phy_id_low);
 		hw->phy.id |= (u32)(phy_id_low & IXGBE_PHY_REVISION_MASK);
 		hw->phy.revision = (u32)(phy_id_low & ~IXGBE_PHY_REVISION_MASK);
 	}
-
 	return status;
 }
 
@@ -123,9 +121,6 @@
 	enum ixgbe_phy_type phy_type;
 
 	switch (phy_id) {
-	case TN1010_PHY_ID:
-		phy_type = ixgbe_phy_tn;
-		break;
 	case QT2022_PHY_ID:
 		phy_type = ixgbe_phy_qt;
 		break;
@@ -138,32 +133,31 @@
 }
 
 /**
- *  ixgbe_reset_phy - Performs a PHY reset
+ *  ixgbe_reset_phy_generic - Performs a PHY reset
  *  @hw: pointer to hardware structure
  **/
-s32 ixgbe_reset_phy(struct ixgbe_hw *hw)
+s32 ixgbe_reset_phy_generic(struct ixgbe_hw *hw)
 {
 	/*
 	 * Perform soft PHY reset to the PHY_XS.
 	 * This will cause a soft reset to the PHY
 	 */
-	return ixgbe_write_phy_reg(hw, IXGBE_MDIO_PHY_XS_CONTROL,
-				   IXGBE_MDIO_PHY_XS_DEV_TYPE,
-				   IXGBE_MDIO_PHY_XS_RESET);
+	return hw->phy.ops.write_reg(hw, IXGBE_MDIO_PHY_XS_CONTROL,
+	                             IXGBE_MDIO_PHY_XS_DEV_TYPE,
+	                             IXGBE_MDIO_PHY_XS_RESET);
 }
 
 /**
- *  ixgbe_read_phy_reg - Reads a value from a specified PHY register
+ *  ixgbe_read_phy_reg_generic - Reads a value from a specified PHY register
  *  @hw: pointer to hardware structure
  *  @reg_addr: 32 bit address of PHY register to read
  *  @phy_data: Pointer to read data from PHY register
  **/
-s32 ixgbe_read_phy_reg(struct ixgbe_hw *hw, u32 reg_addr,
-		       u32 device_type, u16 *phy_data)
+s32 ixgbe_read_phy_reg_generic(struct ixgbe_hw *hw, u32 reg_addr,
+                               u32 device_type, u16 *phy_data)
 {
 	u32 command;
 	u32 i;
-	u32 timeout = 10;
 	u32 data;
 	s32 status = 0;
 	u16 gssr;
@@ -179,9 +173,9 @@
 	if (status == 0) {
 		/* Setup and write the address cycle command */
 		command = ((reg_addr << IXGBE_MSCA_NP_ADDR_SHIFT)  |
-			   (device_type << IXGBE_MSCA_DEV_TYPE_SHIFT) |
-			   (hw->phy.addr << IXGBE_MSCA_PHY_ADDR_SHIFT) |
-			   (IXGBE_MSCA_ADDR_CYCLE | IXGBE_MSCA_MDI_COMMAND));
+		           (device_type << IXGBE_MSCA_DEV_TYPE_SHIFT) |
+		           (hw->phy.addr << IXGBE_MSCA_PHY_ADDR_SHIFT) |
+		           (IXGBE_MSCA_ADDR_CYCLE | IXGBE_MSCA_MDI_COMMAND));
 
 		IXGBE_WRITE_REG(hw, IXGBE_MSCA, command);
 
@@ -190,7 +184,7 @@
 		 * The MDI Command bit will clear when the operation is
 		 * complete
 		 */
-		for (i = 0; i < timeout; i++) {
+		for (i = 0; i < IXGBE_MDIO_COMMAND_TIMEOUT; i++) {
 			udelay(10);
 
 			command = IXGBE_READ_REG(hw, IXGBE_MSCA);
@@ -210,9 +204,9 @@
 			 * command
 			 */
 			command = ((reg_addr << IXGBE_MSCA_NP_ADDR_SHIFT)  |
-				   (device_type << IXGBE_MSCA_DEV_TYPE_SHIFT) |
-				   (hw->phy.addr << IXGBE_MSCA_PHY_ADDR_SHIFT) |
-				   (IXGBE_MSCA_READ | IXGBE_MSCA_MDI_COMMAND));
+			           (device_type << IXGBE_MSCA_DEV_TYPE_SHIFT) |
+			           (hw->phy.addr << IXGBE_MSCA_PHY_ADDR_SHIFT) |
+			           (IXGBE_MSCA_READ | IXGBE_MSCA_MDI_COMMAND));
 
 			IXGBE_WRITE_REG(hw, IXGBE_MSCA, command);
 
@@ -221,7 +215,7 @@
 			 * completed. The MDI Command bit will clear when the
 			 * operation is complete
 			 */
-			for (i = 0; i < timeout; i++) {
+			for (i = 0; i < IXGBE_MDIO_COMMAND_TIMEOUT; i++) {
 				udelay(10);
 
 				command = IXGBE_READ_REG(hw, IXGBE_MSCA);
@@ -231,8 +225,7 @@
 			}
 
 			if ((command & IXGBE_MSCA_MDI_COMMAND) != 0) {
-				hw_dbg(hw,
-				       "PHY read command didn't complete\n");
+				hw_dbg(hw, "PHY read command didn't complete\n");
 				status = IXGBE_ERR_PHY;
 			} else {
 				/*
@@ -247,22 +240,22 @@
 
 		ixgbe_release_swfw_sync(hw, gssr);
 	}
+
 	return status;
 }
 
 /**
- *  ixgbe_write_phy_reg - Writes a value to specified PHY register
+ *  ixgbe_write_phy_reg_generic - Writes a value to specified PHY register
  *  @hw: pointer to hardware structure
  *  @reg_addr: 32 bit PHY register to write
  *  @device_type: 5 bit device type
  *  @phy_data: Data to write to the PHY register
  **/
-static s32 ixgbe_write_phy_reg(struct ixgbe_hw *hw, u32 reg_addr,
-			       u32 device_type, u16 phy_data)
+s32 ixgbe_write_phy_reg_generic(struct ixgbe_hw *hw, u32 reg_addr,
+                                u32 device_type, u16 phy_data)
 {
 	u32 command;
 	u32 i;
-	u32 timeout = 10;
 	s32 status = 0;
 	u16 gssr;
 
@@ -280,9 +273,9 @@
 
 		/* Setup and write the address cycle command */
 		command = ((reg_addr << IXGBE_MSCA_NP_ADDR_SHIFT)  |
-			   (device_type << IXGBE_MSCA_DEV_TYPE_SHIFT) |
-			   (hw->phy.addr << IXGBE_MSCA_PHY_ADDR_SHIFT) |
-			   (IXGBE_MSCA_ADDR_CYCLE | IXGBE_MSCA_MDI_COMMAND));
+		           (device_type << IXGBE_MSCA_DEV_TYPE_SHIFT) |
+		           (hw->phy.addr << IXGBE_MSCA_PHY_ADDR_SHIFT) |
+		           (IXGBE_MSCA_ADDR_CYCLE | IXGBE_MSCA_MDI_COMMAND));
 
 		IXGBE_WRITE_REG(hw, IXGBE_MSCA, command);
 
@@ -291,19 +284,19 @@
 		 * The MDI Command bit will clear when the operation is
 		 * complete
 		 */
-		for (i = 0; i < timeout; i++) {
+		for (i = 0; i < IXGBE_MDIO_COMMAND_TIMEOUT; i++) {
 			udelay(10);
 
 			command = IXGBE_READ_REG(hw, IXGBE_MSCA);
 
-			if ((command & IXGBE_MSCA_MDI_COMMAND) == 0) {
-				hw_dbg(hw, "PHY address cmd didn't complete\n");
+			if ((command & IXGBE_MSCA_MDI_COMMAND) == 0)
 				break;
-			}
 		}
 
-		if ((command & IXGBE_MSCA_MDI_COMMAND) != 0)
+		if ((command & IXGBE_MSCA_MDI_COMMAND) != 0) {
+			hw_dbg(hw, "PHY address cmd didn't complete\n");
 			status = IXGBE_ERR_PHY;
+		}
 
 		if (status == 0) {
 			/*
@@ -311,9 +304,9 @@
 			 * command
 			 */
 			command = ((reg_addr << IXGBE_MSCA_NP_ADDR_SHIFT)  |
-				   (device_type << IXGBE_MSCA_DEV_TYPE_SHIFT) |
-				   (hw->phy.addr << IXGBE_MSCA_PHY_ADDR_SHIFT) |
-				   (IXGBE_MSCA_WRITE | IXGBE_MSCA_MDI_COMMAND));
+			           (device_type << IXGBE_MSCA_DEV_TYPE_SHIFT) |
+			           (hw->phy.addr << IXGBE_MSCA_PHY_ADDR_SHIFT) |
+			           (IXGBE_MSCA_WRITE | IXGBE_MSCA_MDI_COMMAND));
 
 			IXGBE_WRITE_REG(hw, IXGBE_MSCA, command);
 
@@ -322,20 +315,19 @@
 			 * completed. The MDI Command bit will clear when the
 			 * operation is complete
 			 */
-			for (i = 0; i < timeout; i++) {
+			for (i = 0; i < IXGBE_MDIO_COMMAND_TIMEOUT; i++) {
 				udelay(10);
 
 				command = IXGBE_READ_REG(hw, IXGBE_MSCA);
 
-				if ((command & IXGBE_MSCA_MDI_COMMAND) == 0) {
-					hw_dbg(hw, "PHY write command did not "
-						  "complete.\n");
+				if ((command & IXGBE_MSCA_MDI_COMMAND) == 0)
 					break;
-				}
 			}
 
-			if ((command & IXGBE_MSCA_MDI_COMMAND) != 0)
+			if ((command & IXGBE_MSCA_MDI_COMMAND) != 0) {
+				hw_dbg(hw, "PHY address cmd didn't complete\n");
 				status = IXGBE_ERR_PHY;
+			}
 		}
 
 		ixgbe_release_swfw_sync(hw, gssr);
@@ -345,67 +337,54 @@
 }
 
 /**
- *  ixgbe_setup_tnx_phy_link - Set and restart autoneg
+ *  ixgbe_setup_phy_link_generic - Set and restart autoneg
  *  @hw: pointer to hardware structure
  *
  *  Restart autonegotiation and PHY and waits for completion.
  **/
-s32 ixgbe_setup_tnx_phy_link(struct ixgbe_hw *hw)
+s32 ixgbe_setup_phy_link_generic(struct ixgbe_hw *hw)
 {
 	s32 status = IXGBE_NOT_IMPLEMENTED;
 	u32 time_out;
 	u32 max_time_out = 10;
-	u16 autoneg_speed_selection_register = 0x10;
-	u16 autoneg_restart_mask = 0x0200;
-	u16 autoneg_complete_mask = 0x0020;
-	u16 autoneg_reg = 0;
+	u16 autoneg_reg = IXGBE_MII_AUTONEG_REG;
 
 	/*
 	 * Set advertisement settings in PHY based on autoneg_advertised
 	 * settings. If autoneg_advertised = 0, then advertise default values
-	 * txn devices cannot be "forced" to a autoneg 10G and fail.  But can
+	 * tnx devices cannot be "forced" to a autoneg 10G and fail.  But can
 	 * for a 1G.
 	 */
-	ixgbe_read_phy_reg(hw,
-		  autoneg_speed_selection_register,
-		  IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
-		  &autoneg_reg);
+	hw->phy.ops.read_reg(hw, IXGBE_MII_SPEED_SELECTION_REG,
+	                     IXGBE_MDIO_AUTO_NEG_DEV_TYPE, &autoneg_reg);
 
 	if (hw->phy.autoneg_advertised == IXGBE_LINK_SPEED_1GB_FULL)
 		autoneg_reg &= 0xEFFF; /* 0 in bit 12 is 1G operation */
 	else
 		autoneg_reg |= 0x1000; /* 1 in bit 12 is 10G/1G operation */
 
-	ixgbe_write_phy_reg(hw,
-		  autoneg_speed_selection_register,
-		  IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
-		  autoneg_reg);
-
+	hw->phy.ops.write_reg(hw, IXGBE_MII_SPEED_SELECTION_REG,
+	                      IXGBE_MDIO_AUTO_NEG_DEV_TYPE, autoneg_reg);
 
 	/* Restart PHY autonegotiation and wait for completion */
-	ixgbe_read_phy_reg(hw,
-		  IXGBE_MDIO_AUTO_NEG_CONTROL,
-		  IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
-		  &autoneg_reg);
+	hw->phy.ops.read_reg(hw, IXGBE_MDIO_AUTO_NEG_CONTROL,
+	                     IXGBE_MDIO_AUTO_NEG_DEV_TYPE, &autoneg_reg);
 
-	autoneg_reg |= autoneg_restart_mask;
+	autoneg_reg |= IXGBE_MII_RESTART;
 
-	ixgbe_write_phy_reg(hw,
-		  IXGBE_MDIO_AUTO_NEG_CONTROL,
-		  IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
-		  autoneg_reg);
+	hw->phy.ops.write_reg(hw, IXGBE_MDIO_AUTO_NEG_CONTROL,
+	                      IXGBE_MDIO_AUTO_NEG_DEV_TYPE, autoneg_reg);
 
 	/* Wait for autonegotiation to finish */
 	for (time_out = 0; time_out < max_time_out; time_out++) {
 		udelay(10);
 		/* Restart PHY autonegotiation and wait for completion */
-		status = ixgbe_read_phy_reg(hw,
-					    IXGBE_MDIO_AUTO_NEG_STATUS,
-					    IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
-					    &autoneg_reg);
+		status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_AUTO_NEG_STATUS,
+		                              IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
+		                              &autoneg_reg);
 
-		autoneg_reg &= autoneg_complete_mask;
-		if (autoneg_reg == autoneg_complete_mask) {
+		autoneg_reg &= IXGBE_MII_AUTONEG_COMPLETE;
+		if (autoneg_reg == IXGBE_MII_AUTONEG_COMPLETE) {
 			status = 0;
 			break;
 		}
@@ -418,64 +397,17 @@
 }
 
 /**
- *  ixgbe_check_tnx_phy_link - Determine link and speed status
- *  @hw: pointer to hardware structure
- *
- *  Reads the VS1 register to determine if link is up and the current speed for
- *  the PHY.
- **/
-s32 ixgbe_check_tnx_phy_link(struct ixgbe_hw *hw, u32 *speed,
-			     bool *link_up)
-{
-	s32 status = 0;
-	u32 time_out;
-	u32 max_time_out = 10;
-	u16 phy_link = 0;
-	u16 phy_speed = 0;
-	u16 phy_data = 0;
-
-	/* Initialize speed and link to default case */
-	*link_up = false;
-	*speed = IXGBE_LINK_SPEED_10GB_FULL;
-
-	/*
-	 * Check current speed and link status of the PHY register.
-	 * This is a vendor specific register and may have to
-	 * be changed for other copper PHYs.
-	 */
-	for (time_out = 0; time_out < max_time_out; time_out++) {
-		udelay(10);
-		if (phy_link == IXGBE_MDIO_VENDOR_SPECIFIC_1_LINK_STATUS) {
-			*link_up = true;
-			if (phy_speed ==
-			    IXGBE_MDIO_VENDOR_SPECIFIC_1_SPEED_STATUS)
-				*speed = IXGBE_LINK_SPEED_1GB_FULL;
-			break;
-		} else {
-			status = ixgbe_read_phy_reg(hw,
-				     IXGBE_MDIO_VENDOR_SPECIFIC_1_STATUS,
-				     IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE,
-				     &phy_data);
-			phy_link = phy_data &
-				IXGBE_MDIO_VENDOR_SPECIFIC_1_LINK_STATUS;
-			phy_speed = phy_data &
-				IXGBE_MDIO_VENDOR_SPECIFIC_1_SPEED_STATUS;
-		}
-	}
-
-	return status;
-}
-
-/**
- *  ixgbe_setup_tnx_phy_link_speed - Sets the auto advertised capabilities
+ *  ixgbe_setup_phy_link_speed_generic - Sets the auto advertised capabilities
  *  @hw: pointer to hardware structure
  *  @speed: new link speed
  *  @autoneg: true if autonegotiation enabled
  **/
-s32 ixgbe_setup_tnx_phy_link_speed(struct ixgbe_hw *hw, u32 speed,
-				   bool autoneg,
-				   bool autoneg_wait_to_complete)
+s32 ixgbe_setup_phy_link_speed_generic(struct ixgbe_hw *hw,
+                                       ixgbe_link_speed speed,
+                                       bool autoneg,
+                                       bool autoneg_wait_to_complete)
 {
+
 	/*
 	 * Clear autoneg_advertised and set new values based on input link
 	 * speed.
@@ -484,11 +416,13 @@
 
 	if (speed & IXGBE_LINK_SPEED_10GB_FULL)
 		hw->phy.autoneg_advertised |= IXGBE_LINK_SPEED_10GB_FULL;
+
 	if (speed & IXGBE_LINK_SPEED_1GB_FULL)
 		hw->phy.autoneg_advertised |= IXGBE_LINK_SPEED_1GB_FULL;
 
 	/* Setup link based on the new speed settings */
-	ixgbe_setup_tnx_phy_link(hw);
+	hw->phy.ops.setup_link(hw);
 
 	return 0;
 }
+
diff --git a/drivers/net/ixgbe/ixgbe_phy.h b/drivers/net/ixgbe/ixgbe_phy.h
index aa3ea72..9bfe3f2 100644
--- a/drivers/net/ixgbe/ixgbe_phy.h
+++ b/drivers/net/ixgbe/ixgbe_phy.h
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel 10 Gigabit PCI Express Linux driver
-  Copyright(c) 1999 - 2007 Intel Corporation.
+  Copyright(c) 1999 - 2008 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
@@ -20,7 +20,6 @@
   the file called "COPYING".
 
   Contact Information:
-  Linux NICS <linux.nics@intel.com>
   e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
   Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
 
@@ -30,20 +29,52 @@
 #define _IXGBE_PHY_H_
 
 #include "ixgbe_type.h"
+#define IXGBE_I2C_EEPROM_DEV_ADDR    0xA0
 
-s32 ixgbe_setup_phy_link(struct ixgbe_hw *hw);
-s32 ixgbe_check_phy_link(struct ixgbe_hw *hw, u32 *speed, bool *link_up);
-s32 ixgbe_setup_phy_link_speed(struct ixgbe_hw *hw, u32 speed, bool autoneg,
-			       bool autoneg_wait_to_complete);
-s32 ixgbe_identify_phy(struct ixgbe_hw *hw);
-s32 ixgbe_reset_phy(struct ixgbe_hw *hw);
-s32 ixgbe_read_phy_reg(struct ixgbe_hw *hw, u32 reg_addr,
-			       u32 device_type, u16 *phy_data);
+/* EEPROM byte offsets */
+#define IXGBE_SFF_IDENTIFIER         0x0
+#define IXGBE_SFF_IDENTIFIER_SFP     0x3
+#define IXGBE_SFF_VENDOR_OUI_BYTE0   0x25
+#define IXGBE_SFF_VENDOR_OUI_BYTE1   0x26
+#define IXGBE_SFF_VENDOR_OUI_BYTE2   0x27
+#define IXGBE_SFF_1GBE_COMP_CODES    0x6
+#define IXGBE_SFF_10GBE_COMP_CODES   0x3
+#define IXGBE_SFF_TRANSMISSION_MEDIA 0x9
 
-/* PHY specific */
-s32 ixgbe_setup_tnx_phy_link(struct ixgbe_hw *hw);
-s32 ixgbe_check_tnx_phy_link(struct ixgbe_hw *hw, u32 *speed, bool *link_up);
-s32 ixgbe_setup_tnx_phy_link_speed(struct ixgbe_hw *hw, u32 speed, bool autoneg,
-				  bool autoneg_wait_to_complete);
+/* Bitmasks */
+#define IXGBE_SFF_TWIN_AX_CAPABLE            0x80
+#define IXGBE_SFF_1GBASESX_CAPABLE           0x1
+#define IXGBE_SFF_10GBASESR_CAPABLE          0x10
+#define IXGBE_SFF_10GBASELR_CAPABLE          0x20
+#define IXGBE_I2C_EEPROM_READ_MASK           0x100
+#define IXGBE_I2C_EEPROM_STATUS_MASK         0x3
+#define IXGBE_I2C_EEPROM_STATUS_NO_OPERATION 0x0
+#define IXGBE_I2C_EEPROM_STATUS_PASS         0x1
+#define IXGBE_I2C_EEPROM_STATUS_FAIL         0x2
+#define IXGBE_I2C_EEPROM_STATUS_IN_PROGRESS  0x3
+
+/* Bit-shift macros */
+#define IXGBE_SFF_VENDOR_OUI_BYTE0_SHIFT    12
+#define IXGBE_SFF_VENDOR_OUI_BYTE1_SHIFT    8
+#define IXGBE_SFF_VENDOR_OUI_BYTE2_SHIFT    4
+
+/* Vendor OUIs: format of OUI is 0x[byte0][byte1][byte2][00] */
+#define IXGBE_SFF_VENDOR_OUI_TYCO     0x00407600
+#define IXGBE_SFF_VENDOR_OUI_FTL      0x00906500
+#define IXGBE_SFF_VENDOR_OUI_AVAGO    0x00176A00
+
+
+s32 ixgbe_init_phy_ops_generic(struct ixgbe_hw *hw);
+s32 ixgbe_identify_phy_generic(struct ixgbe_hw *hw);
+s32 ixgbe_reset_phy_generic(struct ixgbe_hw *hw);
+s32 ixgbe_read_phy_reg_generic(struct ixgbe_hw *hw, u32 reg_addr,
+                               u32 device_type, u16 *phy_data);
+s32 ixgbe_write_phy_reg_generic(struct ixgbe_hw *hw, u32 reg_addr,
+                                u32 device_type, u16 phy_data);
+s32 ixgbe_setup_phy_link_generic(struct ixgbe_hw *hw);
+s32 ixgbe_setup_phy_link_speed_generic(struct ixgbe_hw *hw,
+                                       ixgbe_link_speed speed,
+                                       bool autoneg,
+                                       bool autoneg_wait_to_complete);
 
 #endif /* _IXGBE_PHY_H_ */
diff --git a/drivers/net/ixgbe/ixgbe_type.h b/drivers/net/ixgbe/ixgbe_type.h
index c0282a2..c6f8fa1 100644
--- a/drivers/net/ixgbe/ixgbe_type.h
+++ b/drivers/net/ixgbe/ixgbe_type.h
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel 10 Gigabit PCI Express Linux driver
-  Copyright(c) 1999 - 2007 Intel Corporation.
+  Copyright(c) 1999 - 2008 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
@@ -20,7 +20,6 @@
   the file called "COPYING".
 
   Contact Information:
-  Linux NICS <linux.nics@intel.com>
   e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
   Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
 
@@ -37,9 +36,9 @@
 /* Device IDs */
 #define IXGBE_DEV_ID_82598AF_DUAL_PORT   0x10C6
 #define IXGBE_DEV_ID_82598AF_SINGLE_PORT 0x10C7
-#define IXGBE_DEV_ID_82598AT_DUAL_PORT   0x10C8
 #define IXGBE_DEV_ID_82598EB_CX4         0x10DD
 #define IXGBE_DEV_ID_82598_CX4_DUAL_PORT 0x10EC
+#define IXGBE_DEV_ID_82598EB_XF_LR       0x10F4
 
 /* General Registers */
 #define IXGBE_CTRL      0x00000
@@ -70,11 +69,11 @@
 #define IXGBE_EIMC      0x00888
 #define IXGBE_EIAC      0x00810
 #define IXGBE_EIAM      0x00890
-#define IXGBE_EITR(_i) (0x00820 + ((_i) * 4)) /* 0x820-0x86c */
-#define IXGBE_IVAR(_i) (0x00900 + ((_i) * 4)) /* 24 at 0x900-0x960 */
+#define IXGBE_EITR(_i)  (((_i) <= 23) ? (0x00820 + ((_i) * 4)) : (0x012300 + ((_i) * 4)))
+#define IXGBE_IVAR(_i)  (0x00900 + ((_i) * 4)) /* 24 at 0x900-0x960 */
 #define IXGBE_MSIXT     0x00000 /* MSI-X Table. 0x0000 - 0x01C */
 #define IXGBE_MSIXPBA   0x02000 /* MSI-X Pending bit array */
-#define IXGBE_PBACL     0x11068
+#define IXGBE_PBACL(_i) (((_i) == 0) ? (0x11068) : (0x110C0 + ((_i) * 4)))
 #define IXGBE_GPIE      0x00898
 
 /* Flow Control Registers */
@@ -86,20 +85,33 @@
 #define IXGBE_TFCS      0x0CE00
 
 /* Receive DMA Registers */
-#define IXGBE_RDBAL(_i) (0x01000 + ((_i) * 0x40)) /* 64 of each (0-63)*/
-#define IXGBE_RDBAH(_i) (0x01004 + ((_i) * 0x40))
-#define IXGBE_RDLEN(_i) (0x01008 + ((_i) * 0x40))
-#define IXGBE_RDH(_i)   (0x01010 + ((_i) * 0x40))
-#define IXGBE_RDT(_i)   (0x01018 + ((_i) * 0x40))
-#define IXGBE_RXDCTL(_i) (0x01028 + ((_i) * 0x40))
-#define IXGBE_RSCCTL(_i) (0x0102C + ((_i) * 0x40))
-#define IXGBE_SRRCTL(_i) (0x02100 + ((_i) * 4))
-					     /* array of 16 (0x02100-0x0213C) */
-#define IXGBE_DCA_RXCTRL(_i)    (0x02200 + ((_i) * 4))
-					     /* array of 16 (0x02200-0x0223C) */
-#define IXGBE_RDRXCTL    0x02F00
+#define IXGBE_RDBAL(_i) (((_i) < 64) ? (0x01000 + ((_i) * 0x40)) : (0x0D000 + ((_i - 64) * 0x40)))
+#define IXGBE_RDBAH(_i) (((_i) < 64) ? (0x01004 + ((_i) * 0x40)) : (0x0D004 + ((_i - 64) * 0x40)))
+#define IXGBE_RDLEN(_i) (((_i) < 64) ? (0x01008 + ((_i) * 0x40)) : (0x0D008 + ((_i - 64) * 0x40)))
+#define IXGBE_RDH(_i)   (((_i) < 64) ? (0x01010 + ((_i) * 0x40)) : (0x0D010 + ((_i - 64) * 0x40)))
+#define IXGBE_RDT(_i)   (((_i) < 64) ? (0x01018 + ((_i) * 0x40)) : (0x0D018 + ((_i - 64) * 0x40)))
+#define IXGBE_RXDCTL(_i) (((_i) < 64) ? (0x01028 + ((_i) * 0x40)) : (0x0D028 + ((_i - 64) * 0x40)))
+/*
+ * Split and Replication Receive Control Registers
+ * 00-15 : 0x02100 + n*4
+ * 16-64 : 0x01014 + n*0x40
+ * 64-127: 0x0D014 + (n-64)*0x40
+ */
+#define IXGBE_SRRCTL(_i) (((_i) <= 15) ? (0x02100 + ((_i) * 4)) : \
+                          (((_i) < 64) ? (0x01014 + ((_i) * 0x40)) : \
+                          (0x0D014 + ((_i - 64) * 0x40))))
+/*
+ * Rx DCA Control Register:
+ * 00-15 : 0x02200 + n*4
+ * 16-64 : 0x0100C + n*0x40
+ * 64-127: 0x0D00C + (n-64)*0x40
+ */
+#define IXGBE_DCA_RXCTRL(_i)    (((_i) <= 15) ? (0x02200 + ((_i) * 4)) : \
+                                 (((_i) < 64) ? (0x0100C + ((_i) * 0x40)) : \
+                                 (0x0D00C + ((_i - 64) * 0x40))))
+#define IXGBE_RDRXCTL           0x02F00
 #define IXGBE_RXPBSIZE(_i)      (0x03C00 + ((_i) * 4))
-					     /* 8 of these 0x03C00 - 0x03C1C */
+                                             /* 8 of these 0x03C00 - 0x03C1C */
 #define IXGBE_RXCTRL    0x03000
 #define IXGBE_DROPEN    0x03D04
 #define IXGBE_RXPBSIZE_SHIFT 10
@@ -107,29 +119,32 @@
 /* Receive Registers */
 #define IXGBE_RXCSUM    0x05000
 #define IXGBE_RFCTL     0x05008
+#define IXGBE_DRECCCTL  0x02F08
+#define IXGBE_DRECCCTL_DISABLE 0
+/* Multicast Table Array - 128 entries */
 #define IXGBE_MTA(_i)   (0x05200 + ((_i) * 4))
-				   /* Multicast Table Array - 128 entries */
-#define IXGBE_RAL(_i)   (0x05400 + ((_i) * 8)) /* 16 of these (0-15) */
-#define IXGBE_RAH(_i)   (0x05404 + ((_i) * 8)) /* 16 of these (0-15) */
-#define IXGBE_PSRTYPE   0x05480
-				   /* 0x5480-0x54BC Packet split receive type */
+#define IXGBE_RAL(_i)   (((_i) <= 15) ? (0x05400 + ((_i) * 8)) : (0x0A200 + ((_i) * 8)))
+#define IXGBE_RAH(_i)   (((_i) <= 15) ? (0x05404 + ((_i) * 8)) : (0x0A204 + ((_i) * 8)))
+/* Packet split receive type */
+#define IXGBE_PSRTYPE(_i)    (((_i) <= 15) ? (0x05480 + ((_i) * 4)) : (0x0EA00 + ((_i) * 4)))
+/* array of 4096 1-bit vlan filters */
 #define IXGBE_VFTA(_i)  (0x0A000 + ((_i) * 4))
-					 /* array of 4096 1-bit vlan filters */
+/*array of 4096 4-bit vlan vmdq indices */
 #define IXGBE_VFTAVIND(_j, _i)  (0x0A200 + ((_j) * 0x200) + ((_i) * 4))
-				     /*array of 4096 4-bit vlan vmdq indicies */
 #define IXGBE_FCTRL     0x05080
 #define IXGBE_VLNCTRL   0x05088
 #define IXGBE_MCSTCTRL  0x05090
 #define IXGBE_MRQC      0x05818
-#define IXGBE_VMD_CTL   0x0581C
 #define IXGBE_IMIR(_i)  (0x05A80 + ((_i) * 4))  /* 8 of these (0-7) */
 #define IXGBE_IMIREXT(_i)       (0x05AA0 + ((_i) * 4))  /* 8 of these (0-7) */
 #define IXGBE_IMIRVP    0x05AC0
+#define IXGBE_VMD_CTL   0x0581C
 #define IXGBE_RETA(_i)  (0x05C00 + ((_i) * 4))  /* 32 of these (0-31) */
 #define IXGBE_RSSRK(_i) (0x05C80 + ((_i) * 4))  /* 10 of these (0-9) */
 
+
 /* Transmit DMA registers */
-#define IXGBE_TDBAL(_i) (0x06000 + ((_i) * 0x40))/* 32 of these (0-31)*/
+#define IXGBE_TDBAL(_i) (0x06000 + ((_i) * 0x40)) /* 32 of these (0-31)*/
 #define IXGBE_TDBAH(_i) (0x06004 + ((_i) * 0x40))
 #define IXGBE_TDLEN(_i) (0x06008 + ((_i) * 0x40))
 #define IXGBE_TDH(_i)   (0x06010 + ((_i) * 0x40))
@@ -138,11 +153,10 @@
 #define IXGBE_TDWBAL(_i) (0x06038 + ((_i) * 0x40))
 #define IXGBE_TDWBAH(_i) (0x0603C + ((_i) * 0x40))
 #define IXGBE_DTXCTL    0x07E00
-#define IXGBE_DCA_TXCTRL(_i)    (0x07200 + ((_i) * 4))
-					      /* there are 16 of these (0-15) */
+
+#define IXGBE_DCA_TXCTRL(_i)    (0x07200 + ((_i) * 4)) /* 16 of these (0-15) */
 #define IXGBE_TIPG      0x0CB00
-#define IXGBE_TXPBSIZE(_i)      (0x0CC00 + ((_i) *0x04))
-						      /* there are 8 of these */
+#define IXGBE_TXPBSIZE(_i)      (0x0CC00 + ((_i) * 4)) /* 8 of these */
 #define IXGBE_MNGTXMAP  0x0CD10
 #define IXGBE_TIPG_FIBER_DEFAULT 3
 #define IXGBE_TXPBSIZE_SHIFT    10
@@ -154,6 +168,7 @@
 #define IXGBE_IPAV      0x05838
 #define IXGBE_IP4AT     0x05840 /* IPv4 table 0x5840-0x5858 */
 #define IXGBE_IP6AT     0x05880 /* IPv6 table 0x5880-0x588F */
+
 #define IXGBE_WUPL      0x05900
 #define IXGBE_WUPM      0x05A00 /* wake up pkt memory 0x5A00-0x5A7C */
 #define IXGBE_FHFT      0x09000 /* Flex host filter table 9000-93FC */
@@ -170,6 +185,8 @@
 #define IXGBE_TDPT2TCCR(_i)     (0x0CD20 + ((_i) * 4)) /* 8 of these (0-7) */
 #define IXGBE_TDPT2TCSR(_i)     (0x0CD40 + ((_i) * 4)) /* 8 of these (0-7) */
 
+
+
 /* Stats registers */
 #define IXGBE_CRCERRS   0x04000
 #define IXGBE_ILLERRC   0x04004
@@ -224,7 +241,7 @@
 #define IXGBE_XEC       0x04120
 
 #define IXGBE_RQSMR(_i) (0x02300 + ((_i) * 4)) /* 16 of these */
-#define IXGBE_TQSMR(_i) (0x07300 + ((_i) * 4)) /* 8 of these */
+#define IXGBE_TQSMR(_i) (((_i) <= 7) ? (0x07300 + ((_i) * 4)) : (0x08600 + ((_i) * 4)))
 
 #define IXGBE_QPRC(_i) (0x01030 + ((_i) * 0x40)) /* 16 of these */
 #define IXGBE_QPTC(_i) (0x06030 + ((_i) * 0x40)) /* 16 of these */
@@ -275,23 +292,17 @@
 #define IXGBE_DCA_CTRL  0x11074
 
 /* Diagnostic Registers */
-#define IXGBE_RDSTATCTL 0x02C20
-#define IXGBE_RDSTAT(_i) (0x02C00 + ((_i) * 4)) /* 0x02C00-0x02C1C */
-#define IXGBE_RDHMPN    0x02F08
-#define IXGBE_RIC_DW0   0x02F10
-#define IXGBE_RIC_DW1   0x02F14
-#define IXGBE_RIC_DW2   0x02F18
-#define IXGBE_RIC_DW3   0x02F1C
-#define IXGBE_RDPROBE   0x02F20
-#define IXGBE_TDSTATCTL 0x07C20
-#define IXGBE_TDSTAT(_i) (0x07C00 + ((_i) * 4)) /* 0x07C00 - 0x07C1C */
-#define IXGBE_TDHMPN    0x07F08
-#define IXGBE_TIC_DW0   0x07F10
-#define IXGBE_TIC_DW1   0x07F14
-#define IXGBE_TIC_DW2   0x07F18
-#define IXGBE_TIC_DW3   0x07F1C
-#define IXGBE_TDPROBE   0x07F20
-#define IXGBE_TXBUFCTRL 0x0C600
+#define IXGBE_RDSTATCTL   0x02C20
+#define IXGBE_RDSTAT(_i)  (0x02C00 + ((_i) * 4)) /* 0x02C00-0x02C1C */
+#define IXGBE_RDHMPN      0x02F08
+#define IXGBE_RIC_DW(_i)  (0x02F10 + ((_i) * 4))
+#define IXGBE_RDPROBE     0x02F20
+#define IXGBE_TDSTATCTL   0x07C20
+#define IXGBE_TDSTAT(_i)  (0x07C00 + ((_i) * 4)) /* 0x07C00 - 0x07C1C */
+#define IXGBE_TDHMPN      0x07F08
+#define IXGBE_TIC_DW(_i)  (0x07F10 + ((_i) * 4))
+#define IXGBE_TDPROBE     0x07F20
+#define IXGBE_TXBUFCTRL   0x0C600
 #define IXGBE_TXBUFDATA0  0x0C610
 #define IXGBE_TXBUFDATA1  0x0C614
 #define IXGBE_TXBUFDATA2  0x0C618
@@ -356,12 +367,10 @@
 #define IXGBE_ANLP2     0x042B4
 #define IXGBE_ATLASCTL  0x04800
 
-/* RSCCTL Bit Masks */
-#define IXGBE_RSCCTL_RSCEN          0x01
-#define IXGBE_RSCCTL_MAXDESC_1      0x00
-#define IXGBE_RSCCTL_MAXDESC_4      0x04
-#define IXGBE_RSCCTL_MAXDESC_8      0x08
-#define IXGBE_RSCCTL_MAXDESC_16     0x0C
+/* RDRXCTL Bit Masks */
+#define IXGBE_RDRXCTL_RDMTS_1_2     0x00000000 /* Rx Desc Min Threshold Size */
+#define IXGBE_RDRXCTL_MVMEN         0x00000020
+#define IXGBE_RDRXCTL_DMAIDONE      0x00000008 /* DMA init cycle done */
 
 /* CTRL Bit Masks */
 #define IXGBE_CTRL_GIO_DIS      0x00000004 /* Global IO Master Disable bit */
@@ -394,7 +403,7 @@
 
 #define IXGBE_DCA_TXCTRL_CPUID_MASK 0x0000001F /* Tx CPUID Mask */
 #define IXGBE_DCA_TXCTRL_DESC_DCA_EN (1 << 5) /* DCA Tx Desc enable */
-#define IXGBE_DCA_TXCTRL_TX_WB_RO_EN (1 << 11) /* TX Desc writeback RO bit */
+#define IXGBE_DCA_TXCTRL_TX_WB_RO_EN (1 << 11) /* Tx Desc writeback RO bit */
 #define IXGBE_DCA_MAX_QUEUES_82598   16 /* DCA regs only on 16 queues */
 
 /* MSCA Bit Masks */
@@ -418,10 +427,10 @@
 #define IXGBE_MSCA_MDI_IN_PROG_EN    0x80000000 /* MDI in progress enable */
 
 /* MSRWD bit masks */
-#define IXGBE_MSRWD_WRITE_DATA_MASK  0x0000FFFF
-#define IXGBE_MSRWD_WRITE_DATA_SHIFT 0
-#define IXGBE_MSRWD_READ_DATA_MASK   0xFFFF0000
-#define IXGBE_MSRWD_READ_DATA_SHIFT  16
+#define IXGBE_MSRWD_WRITE_DATA_MASK     0x0000FFFF
+#define IXGBE_MSRWD_WRITE_DATA_SHIFT    0
+#define IXGBE_MSRWD_READ_DATA_MASK      0xFFFF0000
+#define IXGBE_MSRWD_READ_DATA_SHIFT     16
 
 /* Atlas registers */
 #define IXGBE_ATLAS_PDN_LPBK    0x24
@@ -436,6 +445,7 @@
 #define IXGBE_ATLAS_PDN_TX_1G_QL_ALL    0xF0
 #define IXGBE_ATLAS_PDN_TX_AN_QL_ALL    0xF0
 
+
 /* Device Type definitions for new protocol MDIO commands */
 #define IXGBE_MDIO_PMA_PMD_DEV_TYPE               0x1
 #define IXGBE_MDIO_PCS_DEV_TYPE                   0x3
@@ -443,6 +453,8 @@
 #define IXGBE_MDIO_AUTO_NEG_DEV_TYPE              0x7
 #define IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE     0x1E   /* Device 30 */
 
+#define IXGBE_MDIO_COMMAND_TIMEOUT     100 /* PHY Timeout for 1 GB mode */
+
 #define IXGBE_MDIO_VENDOR_SPECIFIC_1_CONTROL      0x0    /* VS1 Control Reg */
 #define IXGBE_MDIO_VENDOR_SPECIFIC_1_STATUS       0x1    /* VS1 Status Reg */
 #define IXGBE_MDIO_VENDOR_SPECIFIC_1_LINK_STATUS  0x0008 /* 1 = Link Up */
@@ -456,23 +468,39 @@
 #define IXGBE_MDIO_PHY_XS_RESET        0x8000 /* PHY_XS Reset */
 #define IXGBE_MDIO_PHY_ID_HIGH         0x2 /* PHY ID High Reg*/
 #define IXGBE_MDIO_PHY_ID_LOW          0x3 /* PHY ID Low Reg*/
-#define IXGBE_MDIO_PHY_SPEED_ABILITY   0x4 /* Speed Abilty Reg */
+#define IXGBE_MDIO_PHY_SPEED_ABILITY   0x4 /* Speed Ability Reg */
 #define IXGBE_MDIO_PHY_SPEED_10G       0x0001 /* 10G capable */
 #define IXGBE_MDIO_PHY_SPEED_1G        0x0010 /* 1G capable */
 
+#define IXGBE_MDIO_PMA_PMD_SDA_SCL_ADDR     0xC30A /* PHY_XS SDA/SCL Address Reg */
+#define IXGBE_MDIO_PMA_PMD_SDA_SCL_DATA     0xC30B /* PHY_XS SDA/SCL Data Reg */
+#define IXGBE_MDIO_PMA_PMD_SDA_SCL_STAT     0xC30C /* PHY_XS SDA/SCL Status Reg */
+
+/* MII clause 22/28 definitions */
+#define IXGBE_MDIO_PHY_LOW_POWER_MODE  0x0800
+
+#define IXGBE_MII_SPEED_SELECTION_REG  0x10
+#define IXGBE_MII_RESTART              0x200
+#define IXGBE_MII_AUTONEG_COMPLETE     0x20
+#define IXGBE_MII_AUTONEG_REG          0x0
+
 #define IXGBE_PHY_REVISION_MASK        0xFFFFFFF0
 #define IXGBE_MAX_PHY_ADDR             32
 
 /* PHY IDs*/
-#define TN1010_PHY_ID    0x00A19410
 #define QT2022_PHY_ID    0x0043A400
 
+/* PHY Types */
+#define IXGBE_M88E1145_E_PHY_ID  0x01410CD0
+
 /* General purpose Interrupt Enable */
-#define IXGBE_GPIE_MSIX_MODE      0x00000010 /* MSI-X mode */
-#define IXGBE_GPIE_OCD            0x00000020 /* Other Clear Disable */
-#define IXGBE_GPIE_EIMEN          0x00000040 /* Immediate Interrupt Enable */
-#define IXGBE_GPIE_EIAME          0x40000000
-#define IXGBE_GPIE_PBA_SUPPORT    0x80000000
+#define IXGBE_SDP0_GPIEN         0x00000001 /* SDP0 */
+#define IXGBE_SDP1_GPIEN         0x00000002 /* SDP1 */
+#define IXGBE_GPIE_MSIX_MODE     0x00000010 /* MSI-X mode */
+#define IXGBE_GPIE_OCD           0x00000020 /* Other Clear Disable */
+#define IXGBE_GPIE_EIMEN         0x00000040 /* Immediate Interrupt Enable */
+#define IXGBE_GPIE_EIAME         0x40000000
+#define IXGBE_GPIE_PBA_SUPPORT   0x80000000
 
 /* Transmit Flow Control status */
 #define IXGBE_TFCS_TXOFF         0x00000001
@@ -533,7 +561,7 @@
 #define IXGBE_PAP_TXPAUSECNT_MASK   0x0000FFFF /* Pause counter mask */
 
 /* RMCS Bit Masks */
-#define IXGBE_RMCS_RRM          0x00000002 /* Receive Recylce Mode enable */
+#define IXGBE_RMCS_RRM          0x00000002 /* Receive Recycle Mode enable */
 /* Receive Arbitration Control: 0 Round Robin, 1 DFP */
 #define IXGBE_RMCS_RAC          0x00000004
 #define IXGBE_RMCS_DFP          IXGBE_RMCS_RAC /* Deficit Fixed Priority ena */
@@ -541,12 +569,15 @@
 #define IXGBE_RMCS_TFCE_PRIORITY 0x00000010 /* Tx Priority flow control ena */
 #define IXGBE_RMCS_ARBDIS       0x00000040 /* Arbitration disable bit */
 
+
 /* Interrupt register bitmasks */
 
 /* Extended Interrupt Cause Read */
 #define IXGBE_EICR_RTX_QUEUE    0x0000FFFF /* RTx Queue Interrupt */
 #define IXGBE_EICR_LSC          0x00100000 /* Link Status Change */
-#define IXGBE_EICR_MNG          0x00400000 /* Managability Event Interrupt */
+#define IXGBE_EICR_MNG          0x00400000 /* Manageability Event Interrupt */
+#define IXGBE_EICR_GPI_SDP0     0x01000000 /* Gen Purpose Interrupt on SDP0 */
+#define IXGBE_EICR_GPI_SDP1     0x02000000 /* Gen Purpose Interrupt on SDP1 */
 #define IXGBE_EICR_PBUR         0x10000000 /* Packet Buffer Handler Error */
 #define IXGBE_EICR_DHER         0x20000000 /* Descriptor Handler Error */
 #define IXGBE_EICR_TCP_TIMER    0x40000000 /* TCP Timer */
@@ -554,11 +585,12 @@
 
 /* Extended Interrupt Cause Set */
 #define IXGBE_EICS_RTX_QUEUE    IXGBE_EICR_RTX_QUEUE /* RTx Queue Interrupt */
-#define IXGBE_EICS_LSC          IXGBE_EICR_LSC /* Link Status Change */
-#define IXGBE_EICR_GPI_SDP0     0x01000000 /* Gen Purpose Interrupt on SDP0 */
-#define IXGBE_EICS_MNG          IXGBE_EICR_MNG /* MNG Event Interrupt */
-#define IXGBE_EICS_PBUR         IXGBE_EICR_PBUR /* Pkt Buf Handler Error */
-#define IXGBE_EICS_DHER         IXGBE_EICR_DHER /* Desc Handler Error */
+#define IXGBE_EICS_LSC          IXGBE_EICR_LSC       /* Link Status Change */
+#define IXGBE_EICS_MNG          IXGBE_EICR_MNG       /* MNG Event Interrupt */
+#define IXGBE_EICS_GPI_SDP0     IXGBE_EICR_GPI_SDP0  /* SDP0 Gen Purpose Int */
+#define IXGBE_EICS_GPI_SDP1     IXGBE_EICR_GPI_SDP1  /* SDP1 Gen Purpose Int */
+#define IXGBE_EICS_PBUR         IXGBE_EICR_PBUR      /* Pkt Buf Handler Err */
+#define IXGBE_EICS_DHER         IXGBE_EICR_DHER      /* Desc Handler Error */
 #define IXGBE_EICS_TCP_TIMER    IXGBE_EICR_TCP_TIMER /* TCP Timer */
 #define IXGBE_EICS_OTHER        IXGBE_EICR_OTHER     /* INT Cause Active */
 
@@ -566,7 +598,9 @@
 #define IXGBE_EIMS_RTX_QUEUE    IXGBE_EICR_RTX_QUEUE /* RTx Queue Interrupt */
 #define IXGBE_EIMS_LSC          IXGBE_EICR_LSC       /* Link Status Change */
 #define IXGBE_EIMS_MNG          IXGBE_EICR_MNG       /* MNG Event Interrupt */
-#define IXGBE_EIMS_PBUR         IXGBE_EICR_PBUR      /* Pkt Buf Handler Error */
+#define IXGBE_EIMS_GPI_SDP0     IXGBE_EICR_GPI_SDP0  /* SDP0 Gen Purpose Int */
+#define IXGBE_EIMS_GPI_SDP1     IXGBE_EICR_GPI_SDP1  /* SDP1 Gen Purpose Int */
+#define IXGBE_EIMS_PBUR         IXGBE_EICR_PBUR      /* Pkt Buf Handler Err */
 #define IXGBE_EIMS_DHER         IXGBE_EICR_DHER      /* Descr Handler Error */
 #define IXGBE_EIMS_TCP_TIMER    IXGBE_EICR_TCP_TIMER /* TCP Timer */
 #define IXGBE_EIMS_OTHER        IXGBE_EICR_OTHER     /* INT Cause Active */
@@ -575,18 +609,20 @@
 #define IXGBE_EIMC_RTX_QUEUE    IXGBE_EICR_RTX_QUEUE /* RTx Queue Interrupt */
 #define IXGBE_EIMC_LSC          IXGBE_EICR_LSC       /* Link Status Change */
 #define IXGBE_EIMC_MNG          IXGBE_EICR_MNG       /* MNG Event Interrupt */
-#define IXGBE_EIMC_PBUR         IXGBE_EICR_PBUR      /* Pkt Buf Handler Error */
-#define IXGBE_EIMC_DHER         IXGBE_EICR_DHER      /* Desc Handler Error */
+#define IXGBE_EIMC_GPI_SDP0     IXGBE_EICR_GPI_SDP0  /* SDP0 Gen Purpose Int */
+#define IXGBE_EIMC_GPI_SDP1     IXGBE_EICR_GPI_SDP1  /* SDP1 Gen Purpose Int */
+#define IXGBE_EIMC_PBUR         IXGBE_EICR_PBUR      /* Pkt Buf Handler Err */
+#define IXGBE_EIMC_DHER         IXGBE_EICR_DHER      /* Desc Handler Err */
 #define IXGBE_EIMC_TCP_TIMER    IXGBE_EICR_TCP_TIMER /* TCP Timer */
 #define IXGBE_EIMC_OTHER        IXGBE_EICR_OTHER     /* INT Cause Active */
 
-#define IXGBE_EIMS_ENABLE_MASK (\
-				IXGBE_EIMS_RTX_QUEUE       | \
-				IXGBE_EIMS_LSC             | \
-				IXGBE_EIMS_TCP_TIMER       | \
-				IXGBE_EIMS_OTHER)
+#define IXGBE_EIMS_ENABLE_MASK ( \
+                                IXGBE_EIMS_RTX_QUEUE       | \
+                                IXGBE_EIMS_LSC             | \
+                                IXGBE_EIMS_TCP_TIMER       | \
+                                IXGBE_EIMS_OTHER)
 
-/* Immediate Interrupt RX (A.K.A. Low Latency Interrupt) */
+/* Immediate Interrupt Rx (A.K.A. Low Latency Interrupt) */
 #define IXGBE_IMIR_PORT_IM_EN     0x00010000  /* TCP port enable */
 #define IXGBE_IMIR_PORT_BP        0x00020000  /* TCP port check bypass */
 #define IXGBE_IMIREXT_SIZE_BP     0x00001000  /* Packet size bypass */
@@ -623,6 +659,7 @@
 #define IXGBE_VLNCTRL_VFE       0x40000000  /* bit 30 */
 #define IXGBE_VLNCTRL_VME       0x80000000  /* bit 31 */
 
+
 #define IXGBE_ETHERNET_IEEE_VLAN_TYPE 0x8100  /* 802.1q protocol */
 
 /* STATUS Bit Masks */
@@ -670,16 +707,16 @@
 #define IXGBE_AUTOC_AN_RESTART  0x00001000
 #define IXGBE_AUTOC_FLU         0x00000001
 #define IXGBE_AUTOC_LMS_SHIFT   13
-#define IXGBE_AUTOC_LMS_MASK   (0x7 << IXGBE_AUTOC_LMS_SHIFT)
-#define IXGBE_AUTOC_LMS_1G_LINK_NO_AN  (0x0 << IXGBE_AUTOC_LMS_SHIFT)
-#define IXGBE_AUTOC_LMS_10G_LINK_NO_AN (0x1 << IXGBE_AUTOC_LMS_SHIFT)
-#define IXGBE_AUTOC_LMS_1G_AN  (0x2 << IXGBE_AUTOC_LMS_SHIFT)
-#define IXGBE_AUTOC_LMS_KX4_AN (0x4 << IXGBE_AUTOC_LMS_SHIFT)
-#define IXGBE_AUTOC_LMS_KX4_AN_1G_AN   (0x6 << IXGBE_AUTOC_LMS_SHIFT)
-#define IXGBE_AUTOC_LMS_ATTACH_TYPE    (0x7 << IXGBE_AUTOC_10G_PMA_PMD_SHIFT)
+#define IXGBE_AUTOC_LMS_MASK            (0x7 << IXGBE_AUTOC_LMS_SHIFT)
+#define IXGBE_AUTOC_LMS_1G_LINK_NO_AN   (0x0 << IXGBE_AUTOC_LMS_SHIFT)
+#define IXGBE_AUTOC_LMS_10G_LINK_NO_AN  (0x1 << IXGBE_AUTOC_LMS_SHIFT)
+#define IXGBE_AUTOC_LMS_1G_AN           (0x2 << IXGBE_AUTOC_LMS_SHIFT)
+#define IXGBE_AUTOC_LMS_KX4_AN          (0x4 << IXGBE_AUTOC_LMS_SHIFT)
+#define IXGBE_AUTOC_LMS_KX4_AN_1G_AN    (0x6 << IXGBE_AUTOC_LMS_SHIFT)
+#define IXGBE_AUTOC_LMS_ATTACH_TYPE     (0x7 << IXGBE_AUTOC_10G_PMA_PMD_SHIFT)
 
-#define IXGBE_AUTOC_1G_PMA_PMD      0x00000200
-#define IXGBE_AUTOC_10G_PMA_PMD     0x00000180
+#define IXGBE_AUTOC_1G_PMA_PMD         0x00000200
+#define IXGBE_AUTOC_10G_PMA_PMD        0x00000180
 #define IXGBE_AUTOC_10G_PMA_PMD_SHIFT 7
 #define IXGBE_AUTOC_1G_PMA_PMD_SHIFT 9
 #define IXGBE_AUTOC_10G_XAUI   (0x0 << IXGBE_AUTOC_10G_PMA_PMD_SHIFT)
@@ -705,6 +742,7 @@
 #define IXGBE_LINKS_TL_FAULT    0x00001000
 #define IXGBE_LINKS_SIGNAL      0x00000F00
 
+#define IXGBE_LINK_UP_TIME      90 /* 9.0 Seconds */
 #define IXGBE_AUTO_NEG_TIME     45 /* 4.5 Seconds */
 
 /* SW Semaphore Register bitmasks */
@@ -759,6 +797,11 @@
 #define IXGBE_PBANUM0_PTR       0x15
 #define IXGBE_PBANUM1_PTR       0x16
 
+/* Legacy EEPROM word offsets */
+#define IXGBE_ISCSI_BOOT_CAPS           0x0033
+#define IXGBE_ISCSI_SETUP_PORT_0        0x0030
+#define IXGBE_ISCSI_SETUP_PORT_1        0x0034
+
 /* EEPROM Commands - SPI */
 #define IXGBE_EEPROM_MAX_RETRY_SPI      5000 /* Max wait 5ms for RDY signal */
 #define IXGBE_EEPROM_STATUS_RDY_SPI     0x01
@@ -766,7 +809,7 @@
 #define IXGBE_EEPROM_WRITE_OPCODE_SPI   0x02  /* EEPROM write opcode */
 #define IXGBE_EEPROM_A8_OPCODE_SPI      0x08  /* opcode bit-3 = addr bit-8 */
 #define IXGBE_EEPROM_WREN_OPCODE_SPI    0x06  /* EEPROM set Write Ena latch */
-/* EEPROM reset Write Enbale latch */
+/* EEPROM reset Write Enable latch */
 #define IXGBE_EEPROM_WRDI_OPCODE_SPI    0x04
 #define IXGBE_EEPROM_RDSR_OPCODE_SPI    0x05  /* EEPROM read Status reg */
 #define IXGBE_EEPROM_WRSR_OPCODE_SPI    0x01  /* EEPROM write Status reg */
@@ -805,26 +848,20 @@
 /* Number of 100 microseconds we wait for PCI Express master disable */
 #define IXGBE_PCI_MASTER_DISABLE_TIMEOUT 800
 
-/* PHY Types */
-#define IXGBE_M88E1145_E_PHY_ID  0x01410CD0
-
 /* Check whether address is multicast.  This is little-endian specific check.*/
 #define IXGBE_IS_MULTICAST(Address) \
-		(bool)(((u8 *)(Address))[0] & ((u8)0x01))
+                (bool)(((u8 *)(Address))[0] & ((u8)0x01))
 
 /* Check whether an address is broadcast. */
 #define IXGBE_IS_BROADCAST(Address)                      \
-		((((u8 *)(Address))[0] == ((u8)0xff)) && \
-		(((u8 *)(Address))[1] == ((u8)0xff)))
+                ((((u8 *)(Address))[0] == ((u8)0xff)) && \
+                (((u8 *)(Address))[1] == ((u8)0xff)))
 
 /* RAH */
 #define IXGBE_RAH_VIND_MASK     0x003C0000
 #define IXGBE_RAH_VIND_SHIFT    18
 #define IXGBE_RAH_AV            0x80000000
-
-/* Filters */
-#define IXGBE_MC_TBL_SIZE       128  /* Multicast Filter Table (4096 bits) */
-#define IXGBE_VLAN_FILTER_TBL_SIZE 128  /* VLAN Filter Table (4096 bits) */
+#define IXGBE_CLEAR_VMDQ_ALL    0xFFFFFFFF
 
 /* Header split receive */
 #define IXGBE_RFCTL_ISCSI_DIS       0x00000001
@@ -853,7 +890,7 @@
 #define IXGBE_MAX_FRAME_SZ      0x40040000
 
 #define IXGBE_TDWBAL_HEAD_WB_ENABLE   0x1      /* Tx head write-back enable */
-#define IXGBE_TDWBAL_SEQNUM_WB_ENABLE 0x2      /* Tx seq. # write-back enable */
+#define IXGBE_TDWBAL_SEQNUM_WB_ENABLE 0x2      /* Tx seq# write-back enable */
 
 /* Receive Config masks */
 #define IXGBE_RXCTRL_RXEN       0x00000001  /* Enable Receiver */
@@ -866,7 +903,7 @@
 #define IXGBE_FCTRL_BAM 0x00000400 /* Broadcast Accept Mode */
 #define IXGBE_FCTRL_PMCF 0x00001000 /* Pass MAC Control Frames */
 #define IXGBE_FCTRL_DPF 0x00002000 /* Discard Pause Frame */
-/* Receive Priority Flow Control Enbale */
+/* Receive Priority Flow Control Enable */
 #define IXGBE_FCTRL_RPFCE 0x00004000
 #define IXGBE_FCTRL_RFCE 0x00008000 /* Receive Flow Control Ena */
 
@@ -896,9 +933,8 @@
 /* Receive Descriptor bit definitions */
 #define IXGBE_RXD_STAT_DD       0x01    /* Descriptor Done */
 #define IXGBE_RXD_STAT_EOP      0x02    /* End of Packet */
-#define IXGBE_RXD_STAT_IXSM     0x04    /* Ignore checksum */
 #define IXGBE_RXD_STAT_VP       0x08    /* IEEE VLAN Packet */
-#define IXGBE_RXD_STAT_UDPCS    0x10    /* UDP xsum caculated */
+#define IXGBE_RXD_STAT_UDPCS    0x10    /* UDP xsum calculated */
 #define IXGBE_RXD_STAT_L4CS     0x20    /* L4 xsum calculated */
 #define IXGBE_RXD_STAT_IPCS     0x40    /* IP xsum calculated */
 #define IXGBE_RXD_STAT_PIF      0x80    /* passed in-exact filter */
@@ -914,7 +950,7 @@
 #define IXGBE_RXD_ERR_USE       0x20    /* Undersize Error */
 #define IXGBE_RXD_ERR_TCPE      0x40    /* TCP/UDP Checksum Error */
 #define IXGBE_RXD_ERR_IPE       0x80    /* IP Checksum Error */
-#define IXGBE_RXDADV_HBO        0x00800000
+#define IXGBE_RXDADV_ERR_HBO    0x00800000 /*Header Buffer Overflow */
 #define IXGBE_RXDADV_ERR_CE     0x01000000 /* CRC Error */
 #define IXGBE_RXDADV_ERR_LE     0x02000000 /* Length Error */
 #define IXGBE_RXDADV_ERR_PE     0x08000000 /* Packet Error */
@@ -928,15 +964,17 @@
 #define IXGBE_RXD_CFI_MASK      0x1000  /* CFI is bit 12 */
 #define IXGBE_RXD_CFI_SHIFT     12
 
+
 /* SRRCTL bit definitions */
-#define IXGBE_SRRCTL_BSIZEPKT_SHIFT 10     /* so many KBs */
-#define IXGBE_SRRCTL_BSIZEPKT_MASK  0x0000007F
-#define IXGBE_SRRCTL_BSIZEHDR_MASK  0x00003F00
-#define IXGBE_SRRCTL_DESCTYPE_LEGACY 0x00000000
+#define IXGBE_SRRCTL_BSIZEPKT_SHIFT     10     /* so many KBs */
+#define IXGBE_SRRCTL_BSIZEPKT_MASK      0x0000007F
+#define IXGBE_SRRCTL_BSIZEHDR_MASK      0x00003F00
+#define IXGBE_SRRCTL_DESCTYPE_LEGACY    0x00000000
 #define IXGBE_SRRCTL_DESCTYPE_ADV_ONEBUF 0x02000000
 #define IXGBE_SRRCTL_DESCTYPE_HDR_SPLIT  0x04000000
 #define IXGBE_SRRCTL_DESCTYPE_HDR_REPLICATION_LARGE_PKT 0x08000000
 #define IXGBE_SRRCTL_DESCTYPE_HDR_SPLIT_ALWAYS 0x0A000000
+#define IXGBE_SRRCTL_DESCTYPE_MASK      0x0E000000
 
 #define IXGBE_RXDPS_HDRSTAT_HDRSP       0x00008000
 #define IXGBE_RXDPS_HDRSTAT_HDRLEN_MASK 0x000003FF
@@ -970,21 +1008,20 @@
 #define IXGBE_RXDADV_PKTTYPE_UDP        0x00000200 /* UDP hdr present */
 #define IXGBE_RXDADV_PKTTYPE_SCTP       0x00000400 /* SCTP hdr present */
 #define IXGBE_RXDADV_PKTTYPE_NFS        0x00000800 /* NFS hdr present */
-
 /* Masks to determine if packets should be dropped due to frame errors */
-#define IXGBE_RXD_ERR_FRAME_ERR_MASK (\
-				      IXGBE_RXD_ERR_CE | \
-				      IXGBE_RXD_ERR_LE | \
-				      IXGBE_RXD_ERR_PE | \
-				      IXGBE_RXD_ERR_OSE | \
-				      IXGBE_RXD_ERR_USE)
+#define IXGBE_RXD_ERR_FRAME_ERR_MASK ( \
+                                      IXGBE_RXD_ERR_CE | \
+                                      IXGBE_RXD_ERR_LE | \
+                                      IXGBE_RXD_ERR_PE | \
+                                      IXGBE_RXD_ERR_OSE | \
+                                      IXGBE_RXD_ERR_USE)
 
-#define IXGBE_RXDADV_ERR_FRAME_ERR_MASK (\
-				      IXGBE_RXDADV_ERR_CE | \
-				      IXGBE_RXDADV_ERR_LE | \
-				      IXGBE_RXDADV_ERR_PE | \
-				      IXGBE_RXDADV_ERR_OSE | \
-				      IXGBE_RXDADV_ERR_USE)
+#define IXGBE_RXDADV_ERR_FRAME_ERR_MASK ( \
+                                      IXGBE_RXDADV_ERR_CE | \
+                                      IXGBE_RXDADV_ERR_LE | \
+                                      IXGBE_RXDADV_ERR_PE | \
+                                      IXGBE_RXDADV_ERR_OSE | \
+                                      IXGBE_RXDADV_ERR_USE)
 
 /* Multicast bit mask */
 #define IXGBE_MCSTCTRL_MFE      0x4
@@ -1000,6 +1037,7 @@
 #define IXGBE_RX_DESC_SPECIAL_PRI_SHIFT  0x000D /* Priority in upper 3 of 16 */
 #define IXGBE_TX_DESC_SPECIAL_PRI_SHIFT  IXGBE_RX_DESC_SPECIAL_PRI_SHIFT
 
+
 /* Transmit Descriptor - Legacy */
 struct ixgbe_legacy_tx_desc {
 	u64 buffer_addr;       /* Address of the descriptor's data buffer */
@@ -1007,15 +1045,15 @@
 		__le32 data;
 		struct {
 			__le16 length;    /* Data buffer length */
-			u8 cso; /* Checksum offset */
-			u8 cmd; /* Descriptor control */
+			u8 cso;           /* Checksum offset */
+			u8 cmd;           /* Descriptor control */
 		} flags;
 	} lower;
 	union {
 		__le32 data;
 		struct {
-			u8 status;     /* Descriptor status */
-			u8 css; /* Checksum start */
+			u8 status;        /* Descriptor status */
+			u8 css;           /* Checksum start */
 			__le16 vlan;
 		} fields;
 	} upper;
@@ -1024,7 +1062,7 @@
 /* Transmit Descriptor - Advanced */
 union ixgbe_adv_tx_desc {
 	struct {
-		__le64 buffer_addr;       /* Address of descriptor's data buf */
+		__le64 buffer_addr;      /* Address of descriptor's data buf */
 		__le32 cmd_type_len;
 		__le32 olinfo_status;
 	} read;
@@ -1039,9 +1077,9 @@
 struct ixgbe_legacy_rx_desc {
 	__le64 buffer_addr; /* Address of the descriptor's data buffer */
 	__le16 length;      /* Length of data DMAed into data buffer */
-	u16 csum;        /* Packet checksum */
-	u8 status;       /* Descriptor status */
-	u8 errors;       /* Descriptor Errors */
+	__le16 csum;        /* Packet checksum */
+	u8 status;          /* Descriptor status */
+	u8 errors;          /* Descriptor Errors */
 	__le16 vlan;
 };
 
@@ -1053,15 +1091,18 @@
 	} read;
 	struct {
 		struct {
-			struct {
-				__le16 pkt_info; /* RSS type, Packet type */
-				__le16 hdr_info; /* Split Header, header len */
+			union {
+				__le32 data;
+				struct {
+					__le16 pkt_info; /* RSS, Pkt type */
+					__le16 hdr_info; /* Splithdr, hdrlen */
+				} hs_rss;
 			} lo_dword;
 			union {
 				__le32 rss; /* RSS Hash */
 				struct {
 					__le16 ip_id; /* IP id */
-					u16 csum; /* Packet Checksum */
+					__le16 csum; /* Packet Checksum */
 				} csum_ip;
 			} hi_dword;
 		} lower;
@@ -1082,49 +1123,69 @@
 };
 
 /* Adv Transmit Descriptor Config Masks */
-#define IXGBE_ADVTXD_DTALEN_MASK      0x0000FFFF /* Data buffer length(bytes) */
+#define IXGBE_ADVTXD_DTALEN_MASK      0x0000FFFF /* Data buf length(bytes) */
 #define IXGBE_ADVTXD_DTYP_MASK  0x00F00000 /* DTYP mask */
 #define IXGBE_ADVTXD_DTYP_CTXT  0x00200000 /* Advanced Context Desc */
 #define IXGBE_ADVTXD_DTYP_DATA  0x00300000 /* Advanced Data Descriptor */
 #define IXGBE_ADVTXD_DCMD_EOP   IXGBE_TXD_CMD_EOP  /* End of Packet */
 #define IXGBE_ADVTXD_DCMD_IFCS  IXGBE_TXD_CMD_IFCS /* Insert FCS */
-#define IXGBE_ADVTXD_DCMD_RDMA  0x04000000 /* RDMA */
 #define IXGBE_ADVTXD_DCMD_RS    IXGBE_TXD_CMD_RS   /* Report Status */
-#define IXGBE_ADVTXD_DCMD_DDTYP_ISCSI 0x10000000     /* DDP hdr type or iSCSI */
+#define IXGBE_ADVTXD_DCMD_DDTYP_ISCSI 0x10000000    /* DDP hdr type or iSCSI */
 #define IXGBE_ADVTXD_DCMD_DEXT  IXGBE_TXD_CMD_DEXT /* Desc ext (1=Adv) */
 #define IXGBE_ADVTXD_DCMD_VLE   IXGBE_TXD_CMD_VLE  /* VLAN pkt enable */
 #define IXGBE_ADVTXD_DCMD_TSE   0x80000000 /* TCP Seg enable */
 #define IXGBE_ADVTXD_STAT_DD    IXGBE_TXD_STAT_DD  /* Descriptor Done */
-#define IXGBE_ADVTXD_STAT_SN_CRC      0x00000002 /* NXTSEQ/SEED present in WB */
+#define IXGBE_ADVTXD_STAT_SN_CRC      0x00000002 /* NXTSEQ/SEED pres in WB */
 #define IXGBE_ADVTXD_STAT_RSV   0x0000000C /* STA Reserved */
 #define IXGBE_ADVTXD_IDX_SHIFT  4 /* Adv desc Index shift */
+#define IXGBE_ADVTXD_CC         0x00000080 /* Check Context */
 #define IXGBE_ADVTXD_POPTS_SHIFT      8  /* Adv desc POPTS shift */
 #define IXGBE_ADVTXD_POPTS_IXSM (IXGBE_TXD_POPTS_IXSM << \
-				IXGBE_ADVTXD_POPTS_SHIFT)
+                                 IXGBE_ADVTXD_POPTS_SHIFT)
 #define IXGBE_ADVTXD_POPTS_TXSM (IXGBE_TXD_POPTS_TXSM << \
-				IXGBE_ADVTXD_POPTS_SHIFT)
-#define IXGBE_ADVTXD_POPTS_EOM  0x00000400 /* Enable L bit-RDMA DDP hdr */
-#define IXGBE_ADVTXD_POPTS_ISCO_1ST   0x00000000 /* 1st TSO of iSCSI PDU */
-#define IXGBE_ADVTXD_POPTS_ISCO_MDL   0x00000800 /* Middle TSO of iSCSI PDU */
-#define IXGBE_ADVTXD_POPTS_ISCO_LAST  0x00001000 /* Last TSO of iSCSI PDU */
-#define IXGBE_ADVTXD_POPTS_ISCO_FULL 0x00001800 /* 1st&Last TSO-full iSCSI PDU*/
-#define IXGBE_ADVTXD_POPTS_RSV  0x00002000 /* POPTS Reserved */
-#define IXGBE_ADVTXD_PAYLEN_SHIFT  14 /* Adv desc PAYLEN shift */
-#define IXGBE_ADVTXD_MACLEN_SHIFT  9  /* Adv ctxt desc mac len shift */
-#define IXGBE_ADVTXD_VLAN_SHIFT    16  /* Adv ctxt vlan tag shift */
-#define IXGBE_ADVTXD_TUCMD_IPV4    0x00000400  /* IP Packet Type: 1=IPv4 */
-#define IXGBE_ADVTXD_TUCMD_IPV6    0x00000000  /* IP Packet Type: 0=IPv6 */
-#define IXGBE_ADVTXD_TUCMD_L4T_UDP 0x00000000  /* L4 Packet TYPE of UDP */
-#define IXGBE_ADVTXD_TUCMD_L4T_TCP 0x00000800  /* L4 Packet TYPE of TCP */
-#define IXGBE_ADVTXD_TUCMD_MKRREQ  0x00002000 /* Req requires Markers and CRC */
-#define IXGBE_ADVTXD_L4LEN_SHIFT   8  /* Adv ctxt L4LEN shift */
-#define IXGBE_ADVTXD_MSS_SHIFT     16  /* Adv ctxt MSS shift */
+                                 IXGBE_ADVTXD_POPTS_SHIFT)
+#define IXGBE_ADVTXD_POPTS_ISCO_1ST  0x00000000 /* 1st TSO of iSCSI PDU */
+#define IXGBE_ADVTXD_POPTS_ISCO_MDL  0x00000800 /* Middle TSO of iSCSI PDU */
+#define IXGBE_ADVTXD_POPTS_ISCO_LAST 0x00001000 /* Last TSO of iSCSI PDU */
+#define IXGBE_ADVTXD_POPTS_ISCO_FULL 0x00001800 /* 1st&Last TSO-full iSCSI PDU */
+#define IXGBE_ADVTXD_POPTS_RSV       0x00002000 /* POPTS Reserved */
+#define IXGBE_ADVTXD_PAYLEN_SHIFT    14 /* Adv desc PAYLEN shift */
+#define IXGBE_ADVTXD_MACLEN_SHIFT    9  /* Adv ctxt desc mac len shift */
+#define IXGBE_ADVTXD_VLAN_SHIFT      16  /* Adv ctxt vlan tag shift */
+#define IXGBE_ADVTXD_TUCMD_IPV4      0x00000400  /* IP Packet Type: 1=IPv4 */
+#define IXGBE_ADVTXD_TUCMD_IPV6      0x00000000  /* IP Packet Type: 0=IPv6 */
+#define IXGBE_ADVTXD_TUCMD_L4T_UDP   0x00000000  /* L4 Packet TYPE of UDP */
+#define IXGBE_ADVTXD_TUCMD_L4T_TCP   0x00000800  /* L4 Packet TYPE of TCP */
+#define IXGBE_ADVTXD_TUCMD_L4T_SCTP  0x00001000  /* L4 Packet TYPE of SCTP */
+#define IXGBE_ADVTXD_TUCMD_MKRREQ    0x00002000 /*Req requires Markers and CRC*/
+#define IXGBE_ADVTXD_L4LEN_SHIFT     8  /* Adv ctxt L4LEN shift */
+#define IXGBE_ADVTXD_MSS_SHIFT       16  /* Adv ctxt MSS shift */
 
+/* Autonegotiation advertised speeds */
+typedef u32 ixgbe_autoneg_advertised;
 /* Link speed */
+typedef u32 ixgbe_link_speed;
 #define IXGBE_LINK_SPEED_UNKNOWN   0
 #define IXGBE_LINK_SPEED_100_FULL  0x0008
 #define IXGBE_LINK_SPEED_1GB_FULL  0x0020
 #define IXGBE_LINK_SPEED_10GB_FULL 0x0080
+#define IXGBE_LINK_SPEED_82598_AUTONEG (IXGBE_LINK_SPEED_1GB_FULL | \
+                                        IXGBE_LINK_SPEED_10GB_FULL)
+
+/* Physical layer type */
+typedef u32 ixgbe_physical_layer;
+#define IXGBE_PHYSICAL_LAYER_UNKNOWN      0
+#define IXGBE_PHYSICAL_LAYER_10GBASE_T    0x0001
+#define IXGBE_PHYSICAL_LAYER_1000BASE_T   0x0002
+#define IXGBE_PHYSICAL_LAYER_100BASE_T    0x0004
+#define IXGBE_PHYSICAL_LAYER_SFP_PLUS_CU  0x0008
+#define IXGBE_PHYSICAL_LAYER_10GBASE_LR   0x0010
+#define IXGBE_PHYSICAL_LAYER_10GBASE_LRM  0x0020
+#define IXGBE_PHYSICAL_LAYER_10GBASE_SR   0x0040
+#define IXGBE_PHYSICAL_LAYER_10GBASE_KX4  0x0080
+#define IXGBE_PHYSICAL_LAYER_10GBASE_CX4  0x0100
+#define IXGBE_PHYSICAL_LAYER_1000BASE_KX  0x0200
+#define IXGBE_PHYSICAL_LAYER_1000BASE_BX  0x0400
 
 
 enum ixgbe_eeprom_type {
@@ -1141,16 +1202,38 @@
 
 enum ixgbe_phy_type {
 	ixgbe_phy_unknown = 0,
-	ixgbe_phy_tn,
 	ixgbe_phy_qt,
-	ixgbe_phy_xaui
+	ixgbe_phy_xaui,
+	ixgbe_phy_tw_tyco,
+	ixgbe_phy_tw_unknown,
+	ixgbe_phy_sfp_avago,
+	ixgbe_phy_sfp_ftl,
+	ixgbe_phy_sfp_unknown,
+	ixgbe_phy_generic
+};
+
+/*
+ * SFP+ module type IDs:
+ *
+ * ID	Module Type
+ * =============
+ * 0	SFP_DA_CU
+ * 1	SFP_SR
+ * 2	SFP_LR
+ */
+enum ixgbe_sfp_type {
+	ixgbe_sfp_type_da_cu = 0,
+	ixgbe_sfp_type_sr = 1,
+	ixgbe_sfp_type_lr = 2,
+	ixgbe_sfp_type_unknown = 0xFFFF
 };
 
 enum ixgbe_media_type {
 	ixgbe_media_type_unknown = 0,
 	ixgbe_media_type_fiber,
 	ixgbe_media_type_copper,
-	ixgbe_media_type_backplane
+	ixgbe_media_type_backplane,
+	ixgbe_media_type_virtual
 };
 
 /* Flow Control Settings */
@@ -1167,6 +1250,8 @@
 	u32 rar_used_count;
 	u32 mc_addr_in_rar_count;
 	u32 mta_in_use;
+	u32 overflow_promisc;
+	bool user_set_promisc;
 };
 
 /* Flow control parameters */
@@ -1242,57 +1327,118 @@
 /* forward declaration */
 struct ixgbe_hw;
 
+/* iterator type for walking multicast address lists */
+typedef u8* (*ixgbe_mc_addr_itr) (struct ixgbe_hw *hw, u8 **mc_addr_ptr,
+                                  u32 *vmdq);
+
+/* Function pointer table */
+struct ixgbe_eeprom_operations {
+	s32 (*init_params)(struct ixgbe_hw *);
+	s32 (*read)(struct ixgbe_hw *, u16, u16 *);
+	s32 (*write)(struct ixgbe_hw *, u16, u16);
+	s32 (*validate_checksum)(struct ixgbe_hw *, u16 *);
+	s32 (*update_checksum)(struct ixgbe_hw *);
+};
+
 struct ixgbe_mac_operations {
-	s32 (*reset)(struct ixgbe_hw *);
+	s32 (*init_hw)(struct ixgbe_hw *);
+	s32 (*reset_hw)(struct ixgbe_hw *);
+	s32 (*start_hw)(struct ixgbe_hw *);
+	s32 (*clear_hw_cntrs)(struct ixgbe_hw *);
 	enum ixgbe_media_type (*get_media_type)(struct ixgbe_hw *);
+	s32 (*get_supported_physical_layer)(struct ixgbe_hw *);
+	s32 (*get_mac_addr)(struct ixgbe_hw *, u8 *);
+	s32 (*stop_adapter)(struct ixgbe_hw *);
+	s32 (*get_bus_info)(struct ixgbe_hw *);
+	s32 (*read_analog_reg8)(struct ixgbe_hw*, u32, u8*);
+	s32 (*write_analog_reg8)(struct ixgbe_hw*, u32, u8);
+
+	/* Link */
 	s32 (*setup_link)(struct ixgbe_hw *);
-	s32 (*check_link)(struct ixgbe_hw *, u32 *, bool *);
-	s32 (*setup_link_speed)(struct ixgbe_hw *, u32, bool, bool);
-	s32 (*get_link_settings)(struct ixgbe_hw *, u32 *, bool *);
+	s32 (*setup_link_speed)(struct ixgbe_hw *, ixgbe_link_speed, bool,
+	                        bool);
+	s32 (*check_link)(struct ixgbe_hw *, ixgbe_link_speed *, bool *, bool);
+	s32 (*get_link_capabilities)(struct ixgbe_hw *, ixgbe_link_speed *,
+	                             bool *);
+
+	/* LED */
+	s32 (*led_on)(struct ixgbe_hw *, u32);
+	s32 (*led_off)(struct ixgbe_hw *, u32);
+	s32 (*blink_led_start)(struct ixgbe_hw *, u32);
+	s32 (*blink_led_stop)(struct ixgbe_hw *, u32);
+
+	/* RAR, Multicast, VLAN */
+	s32 (*set_rar)(struct ixgbe_hw *, u32, u8 *, u32, u32);
+	s32 (*clear_rar)(struct ixgbe_hw *, u32);
+	s32 (*set_vmdq)(struct ixgbe_hw *, u32, u32);
+	s32 (*clear_vmdq)(struct ixgbe_hw *, u32, u32);
+	s32 (*init_rx_addrs)(struct ixgbe_hw *);
+	s32 (*update_uc_addr_list)(struct ixgbe_hw *, u8 *, u32,
+	                           ixgbe_mc_addr_itr);
+	s32 (*update_mc_addr_list)(struct ixgbe_hw *, u8 *, u32,
+	                           ixgbe_mc_addr_itr);
+	s32 (*enable_mc)(struct ixgbe_hw *);
+	s32 (*disable_mc)(struct ixgbe_hw *);
+	s32 (*clear_vfta)(struct ixgbe_hw *);
+	s32 (*set_vfta)(struct ixgbe_hw *, u32, u32, bool);
+	s32 (*init_uta_tables)(struct ixgbe_hw *);
+
+	/* Flow Control */
+	s32 (*setup_fc)(struct ixgbe_hw *, s32);
 };
 
 struct ixgbe_phy_operations {
+	s32 (*identify)(struct ixgbe_hw *);
+	s32 (*identify_sfp)(struct ixgbe_hw *);
+	s32 (*reset)(struct ixgbe_hw *);
+	s32 (*read_reg)(struct ixgbe_hw *, u32, u32, u16 *);
+	s32 (*write_reg)(struct ixgbe_hw *, u32, u32, u16);
 	s32 (*setup_link)(struct ixgbe_hw *);
-	s32 (*check_link)(struct ixgbe_hw *, u32 *, bool *);
-	s32 (*setup_link_speed)(struct ixgbe_hw *, u32, bool, bool);
-};
-
-struct ixgbe_mac_info {
-	struct ixgbe_mac_operations	ops;
-	enum ixgbe_mac_type		type;
-	u8				addr[IXGBE_ETH_LENGTH_OF_ADDRESS];
-	u8				perm_addr[IXGBE_ETH_LENGTH_OF_ADDRESS];
-	s32				mc_filter_type;
-	u32				num_rx_queues;
-	u32				num_tx_queues;
-	u32				num_rx_addrs;
-	u32				link_attach_type;
-	u32				link_mode_select;
-	bool				link_settings_loaded;
+	s32 (*setup_link_speed)(struct ixgbe_hw *, ixgbe_link_speed, bool,
+	                        bool);
+	s32 (*read_i2c_byte)(struct ixgbe_hw *, u8, u8, u8 *);
+	s32 (*write_i2c_byte)(struct ixgbe_hw *, u8, u8, u8);
+	s32 (*read_i2c_eeprom)(struct ixgbe_hw *, u8 , u8 *);
+	s32 (*write_i2c_eeprom)(struct ixgbe_hw *, u8, u8);
 };
 
 struct ixgbe_eeprom_info {
-	enum ixgbe_eeprom_type		type;
-	u16				word_size;
-	u16				address_bits;
+	struct ixgbe_eeprom_operations  ops;
+	enum ixgbe_eeprom_type          type;
+	u32				semaphore_delay;
+	u16                             word_size;
+	u16                             address_bits;
+};
+
+struct ixgbe_mac_info {
+	struct ixgbe_mac_operations     ops;
+	enum ixgbe_mac_type             type;
+	u8                              addr[IXGBE_ETH_LENGTH_OF_ADDRESS];
+	u8                              perm_addr[IXGBE_ETH_LENGTH_OF_ADDRESS];
+	s32                             mc_filter_type;
+	u32                             mcft_size;
+	u32                             vft_size;
+	u32                             num_rar_entries;
+	u32                             max_tx_queues;
+	u32                             max_rx_queues;
+	u32                             link_attach_type;
+	u32                             link_mode_select;
+	bool                            link_settings_loaded;
+	bool                            autoneg;
+	bool                            autoneg_failed;
 };
 
 struct ixgbe_phy_info {
-	struct ixgbe_phy_operations	ops;
-
-	enum ixgbe_phy_type		type;
-	u32				addr;
-	u32				id;
-	u32				revision;
-	enum ixgbe_media_type		media_type;
-	u32				autoneg_advertised;
-	bool				autoneg_wait_to_complete;
-};
-
-struct ixgbe_info {
-	enum ixgbe_mac_type		mac;
-	s32 				(*get_invariants)(struct ixgbe_hw *);
-	struct ixgbe_mac_operations	*mac_ops;
+	struct ixgbe_phy_operations     ops;
+	enum ixgbe_phy_type             type;
+	u32                             addr;
+	u32                             id;
+	enum ixgbe_sfp_type             sfp_type;
+	u32                             revision;
+	enum ixgbe_media_type           media_type;
+	bool                            reset_disable;
+	ixgbe_autoneg_advertised        autoneg_advertised;
+	bool                            autoneg_wait_to_complete;
 };
 
 struct ixgbe_hw {
@@ -1311,6 +1457,15 @@
 	bool				adapter_stopped;
 };
 
+struct ixgbe_info {
+	enum ixgbe_mac_type		mac;
+	s32 				(*get_invariants)(struct ixgbe_hw *);
+	struct ixgbe_mac_operations	*mac_ops;
+	struct ixgbe_eeprom_operations	*eeprom_ops;
+	struct ixgbe_phy_operations	*phy_ops;
+};
+
+
 /* Error Codes */
 #define IXGBE_ERR_EEPROM                        -1
 #define IXGBE_ERR_EEPROM_CHECKSUM               -2
@@ -1329,6 +1484,8 @@
 #define IXGBE_ERR_RESET_FAILED                  -15
 #define IXGBE_ERR_SWFW_SYNC                     -16
 #define IXGBE_ERR_PHY_ADDR_INVALID              -17
+#define IXGBE_ERR_I2C                           -18
+#define IXGBE_ERR_SFP_NOT_SUPPORTED             -19
 #define IXGBE_NOT_IMPLEMENTED                   0x7FFFFFFF
 
 #endif /* _IXGBE_TYPE_H_ */
diff --git a/drivers/net/jme.c b/drivers/net/jme.c
new file mode 100644
index 0000000..81c6cdc
--- /dev/null
+++ b/drivers/net/jme.c
@@ -0,0 +1,3038 @@
+/*
+ * JMicron JMC2x0 series PCIe Ethernet Linux Device Driver
+ *
+ * Copyright 2008 JMicron Technology Corporation
+ * http://www.jmicron.com/
+ *
+ * Author: Guo-Fu Tseng <cooldavid@cooldavid.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+#include <linux/mii.h>
+#include <linux/crc32.h>
+#include <linux/delay.h>
+#include <linux/spinlock.h>
+#include <linux/in.h>
+#include <linux/ip.h>
+#include <linux/ipv6.h>
+#include <linux/tcp.h>
+#include <linux/udp.h>
+#include <linux/if_vlan.h>
+#include <net/ip6_checksum.h>
+#include "jme.h"
+
+static int force_pseudohp = -1;
+static int no_pseudohp = -1;
+static int no_extplug = -1;
+module_param(force_pseudohp, int, 0);
+MODULE_PARM_DESC(force_pseudohp,
+	"Enable pseudo hot-plug feature manually by driver instead of BIOS.");
+module_param(no_pseudohp, int, 0);
+MODULE_PARM_DESC(no_pseudohp, "Disable pseudo hot-plug feature.");
+module_param(no_extplug, int, 0);
+MODULE_PARM_DESC(no_extplug,
+	"Do not use external plug signal for pseudo hot-plug.");
+
+static int
+jme_mdio_read(struct net_device *netdev, int phy, int reg)
+{
+	struct jme_adapter *jme = netdev_priv(netdev);
+	int i, val, again = (reg == MII_BMSR) ? 1 : 0;
+
+read_again:
+	jwrite32(jme, JME_SMI, SMI_OP_REQ |
+				smi_phy_addr(phy) |
+				smi_reg_addr(reg));
+
+	wmb();
+	for (i = JME_PHY_TIMEOUT * 50 ; i > 0 ; --i) {
+		udelay(20);
+		val = jread32(jme, JME_SMI);
+		if ((val & SMI_OP_REQ) == 0)
+			break;
+	}
+
+	if (i == 0) {
+		jeprintk(jme->pdev, "phy(%d) read timeout : %d\n", phy, reg);
+		return 0;
+	}
+
+	if (again--)
+		goto read_again;
+
+	return (val & SMI_DATA_MASK) >> SMI_DATA_SHIFT;
+}
+
+static void
+jme_mdio_write(struct net_device *netdev,
+				int phy, int reg, int val)
+{
+	struct jme_adapter *jme = netdev_priv(netdev);
+	int i;
+
+	jwrite32(jme, JME_SMI, SMI_OP_WRITE | SMI_OP_REQ |
+		((val << SMI_DATA_SHIFT) & SMI_DATA_MASK) |
+		smi_phy_addr(phy) | smi_reg_addr(reg));
+
+	wmb();
+	for (i = JME_PHY_TIMEOUT * 50 ; i > 0 ; --i) {
+		udelay(20);
+		if ((jread32(jme, JME_SMI) & SMI_OP_REQ) == 0)
+			break;
+	}
+
+	if (i == 0)
+		jeprintk(jme->pdev, "phy(%d) write timeout : %d\n", phy, reg);
+
+	return;
+}
+
+static inline void
+jme_reset_phy_processor(struct jme_adapter *jme)
+{
+	u32 val;
+
+	jme_mdio_write(jme->dev,
+			jme->mii_if.phy_id,
+			MII_ADVERTISE, ADVERTISE_ALL |
+			ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM);
+
+	if (jme->pdev->device == PCI_DEVICE_ID_JMICRON_JMC250)
+		jme_mdio_write(jme->dev,
+				jme->mii_if.phy_id,
+				MII_CTRL1000,
+				ADVERTISE_1000FULL | ADVERTISE_1000HALF);
+
+	val = jme_mdio_read(jme->dev,
+				jme->mii_if.phy_id,
+				MII_BMCR);
+
+	jme_mdio_write(jme->dev,
+			jme->mii_if.phy_id,
+			MII_BMCR, val | BMCR_RESET);
+
+	return;
+}
+
+static void
+jme_setup_wakeup_frame(struct jme_adapter *jme,
+		u32 *mask, u32 crc, int fnr)
+{
+	int i;
+
+	/*
+	 * Setup CRC pattern
+	 */
+	jwrite32(jme, JME_WFOI, WFOI_CRC_SEL | (fnr & WFOI_FRAME_SEL));
+	wmb();
+	jwrite32(jme, JME_WFODP, crc);
+	wmb();
+
+	/*
+	 * Setup Mask
+	 */
+	for (i = 0 ; i < WAKEUP_FRAME_MASK_DWNR ; ++i) {
+		jwrite32(jme, JME_WFOI,
+				((i << WFOI_MASK_SHIFT) & WFOI_MASK_SEL) |
+				(fnr & WFOI_FRAME_SEL));
+		wmb();
+		jwrite32(jme, JME_WFODP, mask[i]);
+		wmb();
+	}
+}
+
+static inline void
+jme_reset_mac_processor(struct jme_adapter *jme)
+{
+	u32 mask[WAKEUP_FRAME_MASK_DWNR] = {0, 0, 0, 0};
+	u32 crc = 0xCDCDCDCD;
+	u32 gpreg0;
+	int i;
+
+	jwrite32(jme, JME_GHC, jme->reg_ghc | GHC_SWRST);
+	udelay(2);
+	jwrite32(jme, JME_GHC, jme->reg_ghc);
+
+	jwrite32(jme, JME_RXDBA_LO, 0x00000000);
+	jwrite32(jme, JME_RXDBA_HI, 0x00000000);
+	jwrite32(jme, JME_RXQDC, 0x00000000);
+	jwrite32(jme, JME_RXNDA, 0x00000000);
+	jwrite32(jme, JME_TXDBA_LO, 0x00000000);
+	jwrite32(jme, JME_TXDBA_HI, 0x00000000);
+	jwrite32(jme, JME_TXQDC, 0x00000000);
+	jwrite32(jme, JME_TXNDA, 0x00000000);
+
+	jwrite32(jme, JME_RXMCHT_LO, 0x00000000);
+	jwrite32(jme, JME_RXMCHT_HI, 0x00000000);
+	for (i = 0 ; i < WAKEUP_FRAME_NR ; ++i)
+		jme_setup_wakeup_frame(jme, mask, crc, i);
+	if (jme->fpgaver)
+		gpreg0 = GPREG0_DEFAULT | GPREG0_LNKINTPOLL;
+	else
+		gpreg0 = GPREG0_DEFAULT;
+	jwrite32(jme, JME_GPREG0, gpreg0);
+	jwrite32(jme, JME_GPREG1, GPREG1_DEFAULT);
+}
+
+static inline void
+jme_reset_ghc_speed(struct jme_adapter *jme)
+{
+	jme->reg_ghc &= ~(GHC_SPEED_1000M | GHC_DPX);
+	jwrite32(jme, JME_GHC, jme->reg_ghc);
+}
+
+static inline void
+jme_clear_pm(struct jme_adapter *jme)
+{
+	jwrite32(jme, JME_PMCS, 0xFFFF0000 | jme->reg_pmcs);
+	pci_set_power_state(jme->pdev, PCI_D0);
+	pci_enable_wake(jme->pdev, PCI_D0, false);
+}
+
+static int
+jme_reload_eeprom(struct jme_adapter *jme)
+{
+	u32 val;
+	int i;
+
+	val = jread32(jme, JME_SMBCSR);
+
+	if (val & SMBCSR_EEPROMD) {
+		val |= SMBCSR_CNACK;
+		jwrite32(jme, JME_SMBCSR, val);
+		val |= SMBCSR_RELOAD;
+		jwrite32(jme, JME_SMBCSR, val);
+		mdelay(12);
+
+		for (i = JME_EEPROM_RELOAD_TIMEOUT; i > 0; --i) {
+			mdelay(1);
+			if ((jread32(jme, JME_SMBCSR) & SMBCSR_RELOAD) == 0)
+				break;
+		}
+
+		if (i == 0) {
+			jeprintk(jme->pdev, "eeprom reload timeout\n");
+			return -EIO;
+		}
+	}
+
+	return 0;
+}
+
+static void
+jme_load_macaddr(struct net_device *netdev)
+{
+	struct jme_adapter *jme = netdev_priv(netdev);
+	unsigned char macaddr[6];
+	u32 val;
+
+	spin_lock_bh(&jme->macaddr_lock);
+	val = jread32(jme, JME_RXUMA_LO);
+	macaddr[0] = (val >>  0) & 0xFF;
+	macaddr[1] = (val >>  8) & 0xFF;
+	macaddr[2] = (val >> 16) & 0xFF;
+	macaddr[3] = (val >> 24) & 0xFF;
+	val = jread32(jme, JME_RXUMA_HI);
+	macaddr[4] = (val >>  0) & 0xFF;
+	macaddr[5] = (val >>  8) & 0xFF;
+	memcpy(netdev->dev_addr, macaddr, 6);
+	spin_unlock_bh(&jme->macaddr_lock);
+}
+
+static inline void
+jme_set_rx_pcc(struct jme_adapter *jme, int p)
+{
+	switch (p) {
+	case PCC_OFF:
+		jwrite32(jme, JME_PCCRX0,
+			((PCC_OFF_TO << PCCRXTO_SHIFT) & PCCRXTO_MASK) |
+			((PCC_OFF_CNT << PCCRX_SHIFT) & PCCRX_MASK));
+		break;
+	case PCC_P1:
+		jwrite32(jme, JME_PCCRX0,
+			((PCC_P1_TO << PCCRXTO_SHIFT) & PCCRXTO_MASK) |
+			((PCC_P1_CNT << PCCRX_SHIFT) & PCCRX_MASK));
+		break;
+	case PCC_P2:
+		jwrite32(jme, JME_PCCRX0,
+			((PCC_P2_TO << PCCRXTO_SHIFT) & PCCRXTO_MASK) |
+			((PCC_P2_CNT << PCCRX_SHIFT) & PCCRX_MASK));
+		break;
+	case PCC_P3:
+		jwrite32(jme, JME_PCCRX0,
+			((PCC_P3_TO << PCCRXTO_SHIFT) & PCCRXTO_MASK) |
+			((PCC_P3_CNT << PCCRX_SHIFT) & PCCRX_MASK));
+		break;
+	default:
+		break;
+	}
+	wmb();
+
+	if (!(test_bit(JME_FLAG_POLL, &jme->flags)))
+		msg_rx_status(jme, "Switched to PCC_P%d\n", p);
+}
+
+static void
+jme_start_irq(struct jme_adapter *jme)
+{
+	register struct dynpcc_info *dpi = &(jme->dpi);
+
+	jme_set_rx_pcc(jme, PCC_P1);
+	dpi->cur		= PCC_P1;
+	dpi->attempt		= PCC_P1;
+	dpi->cnt		= 0;
+
+	jwrite32(jme, JME_PCCTX,
+			((PCC_TX_TO << PCCTXTO_SHIFT) & PCCTXTO_MASK) |
+			((PCC_TX_CNT << PCCTX_SHIFT) & PCCTX_MASK) |
+			PCCTXQ0_EN
+		);
+
+	/*
+	 * Enable Interrupts
+	 */
+	jwrite32(jme, JME_IENS, INTR_ENABLE);
+}
+
+static inline void
+jme_stop_irq(struct jme_adapter *jme)
+{
+	/*
+	 * Disable Interrupts
+	 */
+	jwrite32f(jme, JME_IENC, INTR_ENABLE);
+}
+
+static inline void
+jme_enable_shadow(struct jme_adapter *jme)
+{
+	jwrite32(jme,
+		 JME_SHBA_LO,
+		 ((u32)jme->shadow_dma & ~((u32)0x1F)) | SHBA_POSTEN);
+}
+
+static inline void
+jme_disable_shadow(struct jme_adapter *jme)
+{
+	jwrite32(jme, JME_SHBA_LO, 0x0);
+}
+
+static u32
+jme_linkstat_from_phy(struct jme_adapter *jme)
+{
+	u32 phylink, bmsr;
+
+	phylink = jme_mdio_read(jme->dev, jme->mii_if.phy_id, 17);
+	bmsr = jme_mdio_read(jme->dev, jme->mii_if.phy_id, MII_BMSR);
+	if (bmsr & BMSR_ANCOMP)
+		phylink |= PHY_LINK_AUTONEG_COMPLETE;
+
+	return phylink;
+}
+
+static inline void
+jme_set_phyfifoa(struct jme_adapter *jme)
+{
+	jme_mdio_write(jme->dev, jme->mii_if.phy_id, 27, 0x0004);
+}
+
+static inline void
+jme_set_phyfifob(struct jme_adapter *jme)
+{
+	jme_mdio_write(jme->dev, jme->mii_if.phy_id, 27, 0x0000);
+}
+
+static int
+jme_check_link(struct net_device *netdev, int testonly)
+{
+	struct jme_adapter *jme = netdev_priv(netdev);
+	u32 phylink, ghc, cnt = JME_SPDRSV_TIMEOUT, bmcr, gpreg1;
+	char linkmsg[64];
+	int rc = 0;
+
+	linkmsg[0] = '\0';
+
+	if (jme->fpgaver)
+		phylink = jme_linkstat_from_phy(jme);
+	else
+		phylink = jread32(jme, JME_PHY_LINK);
+
+	if (phylink & PHY_LINK_UP) {
+		if (!(phylink & PHY_LINK_AUTONEG_COMPLETE)) {
+			/*
+			 * If we did not enable AN
+			 * Speed/Duplex Info should be obtained from SMI
+			 */
+			phylink = PHY_LINK_UP;
+
+			bmcr = jme_mdio_read(jme->dev,
+						jme->mii_if.phy_id,
+						MII_BMCR);
+
+			phylink |= ((bmcr & BMCR_SPEED1000) &&
+					(bmcr & BMCR_SPEED100) == 0) ?
+					PHY_LINK_SPEED_1000M :
+					(bmcr & BMCR_SPEED100) ?
+					PHY_LINK_SPEED_100M :
+					PHY_LINK_SPEED_10M;
+
+			phylink |= (bmcr & BMCR_FULLDPLX) ?
+					 PHY_LINK_DUPLEX : 0;
+
+			strcat(linkmsg, "Forced: ");
+		} else {
+			/*
+			 * Keep polling for speed/duplex resolve complete
+			 */
+			while (!(phylink & PHY_LINK_SPEEDDPU_RESOLVED) &&
+				--cnt) {
+
+				udelay(1);
+
+				if (jme->fpgaver)
+					phylink = jme_linkstat_from_phy(jme);
+				else
+					phylink = jread32(jme, JME_PHY_LINK);
+			}
+			if (!cnt)
+				jeprintk(jme->pdev,
+					"Waiting speed resolve timeout.\n");
+
+			strcat(linkmsg, "ANed: ");
+		}
+
+		if (jme->phylink == phylink) {
+			rc = 1;
+			goto out;
+		}
+		if (testonly)
+			goto out;
+
+		jme->phylink = phylink;
+
+		ghc = jme->reg_ghc & ~(GHC_SPEED_10M |
+					GHC_SPEED_100M |
+					GHC_SPEED_1000M |
+					GHC_DPX);
+		switch (phylink & PHY_LINK_SPEED_MASK) {
+		case PHY_LINK_SPEED_10M:
+			ghc |= GHC_SPEED_10M;
+			strcat(linkmsg, "10 Mbps, ");
+			break;
+		case PHY_LINK_SPEED_100M:
+			ghc |= GHC_SPEED_100M;
+			strcat(linkmsg, "100 Mbps, ");
+			break;
+		case PHY_LINK_SPEED_1000M:
+			ghc |= GHC_SPEED_1000M;
+			strcat(linkmsg, "1000 Mbps, ");
+			break;
+		default:
+			break;
+		}
+
+		if (phylink & PHY_LINK_DUPLEX) {
+			jwrite32(jme, JME_TXMCS, TXMCS_DEFAULT);
+			ghc |= GHC_DPX;
+		} else {
+			jwrite32(jme, JME_TXMCS, TXMCS_DEFAULT |
+						TXMCS_BACKOFF |
+						TXMCS_CARRIERSENSE |
+						TXMCS_COLLISION);
+			jwrite32(jme, JME_TXTRHD, TXTRHD_TXPEN |
+				((0x2000 << TXTRHD_TXP_SHIFT) & TXTRHD_TXP) |
+				TXTRHD_TXREN |
+				((8 << TXTRHD_TXRL_SHIFT) & TXTRHD_TXRL));
+		}
+		strcat(linkmsg, (phylink & PHY_LINK_DUPLEX) ?
+					"Full-Duplex, " :
+					"Half-Duplex, ");
+
+		if (phylink & PHY_LINK_MDI_STAT)
+			strcat(linkmsg, "MDI-X");
+		else
+			strcat(linkmsg, "MDI");
+
+		gpreg1 = GPREG1_DEFAULT;
+		if (is_buggy250(jme->pdev->device, jme->chiprev)) {
+			if (!(phylink & PHY_LINK_DUPLEX))
+				gpreg1 |= GPREG1_HALFMODEPATCH;
+			switch (phylink & PHY_LINK_SPEED_MASK) {
+			case PHY_LINK_SPEED_10M:
+				jme_set_phyfifoa(jme);
+				gpreg1 |= GPREG1_RSSPATCH;
+				break;
+			case PHY_LINK_SPEED_100M:
+				jme_set_phyfifob(jme);
+				gpreg1 |= GPREG1_RSSPATCH;
+				break;
+			case PHY_LINK_SPEED_1000M:
+				jme_set_phyfifoa(jme);
+				break;
+			default:
+				break;
+			}
+		}
+		jwrite32(jme, JME_GPREG1, gpreg1);
+
+		jme->reg_ghc = ghc;
+		jwrite32(jme, JME_GHC, ghc);
+
+		msg_link(jme, "Link is up at %s.\n", linkmsg);
+		netif_carrier_on(netdev);
+	} else {
+		if (testonly)
+			goto out;
+
+		msg_link(jme, "Link is down.\n");
+		jme->phylink = 0;
+		netif_carrier_off(netdev);
+	}
+
+out:
+	return rc;
+}
+
+static int
+jme_setup_tx_resources(struct jme_adapter *jme)
+{
+	struct jme_ring *txring = &(jme->txring[0]);
+
+	txring->alloc = dma_alloc_coherent(&(jme->pdev->dev),
+				   TX_RING_ALLOC_SIZE(jme->tx_ring_size),
+				   &(txring->dmaalloc),
+				   GFP_ATOMIC);
+
+	if (!txring->alloc) {
+		txring->desc = NULL;
+		txring->dmaalloc = 0;
+		txring->dma = 0;
+		return -ENOMEM;
+	}
+
+	/*
+	 * 16 Bytes align
+	 */
+	txring->desc		= (void *)ALIGN((unsigned long)(txring->alloc),
+						RING_DESC_ALIGN);
+	txring->dma		= ALIGN(txring->dmaalloc, RING_DESC_ALIGN);
+	txring->next_to_use	= 0;
+	atomic_set(&txring->next_to_clean, 0);
+	atomic_set(&txring->nr_free, jme->tx_ring_size);
+
+	/*
+	 * Initialize Transmit Descriptors
+	 */
+	memset(txring->alloc, 0, TX_RING_ALLOC_SIZE(jme->tx_ring_size));
+	memset(txring->bufinf, 0,
+		sizeof(struct jme_buffer_info) * jme->tx_ring_size);
+
+	return 0;
+}
+
+static void
+jme_free_tx_resources(struct jme_adapter *jme)
+{
+	int i;
+	struct jme_ring *txring = &(jme->txring[0]);
+	struct jme_buffer_info *txbi = txring->bufinf;
+
+	if (txring->alloc) {
+		for (i = 0 ; i < jme->tx_ring_size ; ++i) {
+			txbi = txring->bufinf + i;
+			if (txbi->skb) {
+				dev_kfree_skb(txbi->skb);
+				txbi->skb = NULL;
+			}
+			txbi->mapping		= 0;
+			txbi->len		= 0;
+			txbi->nr_desc		= 0;
+			txbi->start_xmit	= 0;
+		}
+
+		dma_free_coherent(&(jme->pdev->dev),
+				  TX_RING_ALLOC_SIZE(jme->tx_ring_size),
+				  txring->alloc,
+				  txring->dmaalloc);
+
+		txring->alloc		= NULL;
+		txring->desc		= NULL;
+		txring->dmaalloc	= 0;
+		txring->dma		= 0;
+	}
+	txring->next_to_use	= 0;
+	atomic_set(&txring->next_to_clean, 0);
+	atomic_set(&txring->nr_free, 0);
+
+}
+
+static inline void
+jme_enable_tx_engine(struct jme_adapter *jme)
+{
+	/*
+	 * Select Queue 0
+	 */
+	jwrite32(jme, JME_TXCS, TXCS_DEFAULT | TXCS_SELECT_QUEUE0);
+	wmb();
+
+	/*
+	 * Setup TX Queue 0 DMA Bass Address
+	 */
+	jwrite32(jme, JME_TXDBA_LO, (__u64)jme->txring[0].dma & 0xFFFFFFFFUL);
+	jwrite32(jme, JME_TXDBA_HI, (__u64)(jme->txring[0].dma) >> 32);
+	jwrite32(jme, JME_TXNDA, (__u64)jme->txring[0].dma & 0xFFFFFFFFUL);
+
+	/*
+	 * Setup TX Descptor Count
+	 */
+	jwrite32(jme, JME_TXQDC, jme->tx_ring_size);
+
+	/*
+	 * Enable TX Engine
+	 */
+	wmb();
+	jwrite32(jme, JME_TXCS, jme->reg_txcs |
+				TXCS_SELECT_QUEUE0 |
+				TXCS_ENABLE);
+
+}
+
+static inline void
+jme_restart_tx_engine(struct jme_adapter *jme)
+{
+	/*
+	 * Restart TX Engine
+	 */
+	jwrite32(jme, JME_TXCS, jme->reg_txcs |
+				TXCS_SELECT_QUEUE0 |
+				TXCS_ENABLE);
+}
+
+static inline void
+jme_disable_tx_engine(struct jme_adapter *jme)
+{
+	int i;
+	u32 val;
+
+	/*
+	 * Disable TX Engine
+	 */
+	jwrite32(jme, JME_TXCS, jme->reg_txcs | TXCS_SELECT_QUEUE0);
+	wmb();
+
+	val = jread32(jme, JME_TXCS);
+	for (i = JME_TX_DISABLE_TIMEOUT ; (val & TXCS_ENABLE) && i > 0 ; --i) {
+		mdelay(1);
+		val = jread32(jme, JME_TXCS);
+		rmb();
+	}
+
+	if (!i)
+		jeprintk(jme->pdev, "Disable TX engine timeout.\n");
+}
+
+static void
+jme_set_clean_rxdesc(struct jme_adapter *jme, int i)
+{
+	struct jme_ring *rxring = jme->rxring;
+	register struct rxdesc *rxdesc = rxring->desc;
+	struct jme_buffer_info *rxbi = rxring->bufinf;
+	rxdesc += i;
+	rxbi += i;
+
+	rxdesc->dw[0] = 0;
+	rxdesc->dw[1] = 0;
+	rxdesc->desc1.bufaddrh	= cpu_to_le32((__u64)rxbi->mapping >> 32);
+	rxdesc->desc1.bufaddrl	= cpu_to_le32(
+					(__u64)rxbi->mapping & 0xFFFFFFFFUL);
+	rxdesc->desc1.datalen	= cpu_to_le16(rxbi->len);
+	if (jme->dev->features & NETIF_F_HIGHDMA)
+		rxdesc->desc1.flags = RXFLAG_64BIT;
+	wmb();
+	rxdesc->desc1.flags	|= RXFLAG_OWN | RXFLAG_INT;
+}
+
+static int
+jme_make_new_rx_buf(struct jme_adapter *jme, int i)
+{
+	struct jme_ring *rxring = &(jme->rxring[0]);
+	struct jme_buffer_info *rxbi = rxring->bufinf + i;
+	struct sk_buff *skb;
+
+	skb = netdev_alloc_skb(jme->dev,
+		jme->dev->mtu + RX_EXTRA_LEN);
+	if (unlikely(!skb))
+		return -ENOMEM;
+
+	rxbi->skb = skb;
+	rxbi->len = skb_tailroom(skb);
+	rxbi->mapping = pci_map_page(jme->pdev,
+					virt_to_page(skb->data),
+					offset_in_page(skb->data),
+					rxbi->len,
+					PCI_DMA_FROMDEVICE);
+
+	return 0;
+}
+
+static void
+jme_free_rx_buf(struct jme_adapter *jme, int i)
+{
+	struct jme_ring *rxring = &(jme->rxring[0]);
+	struct jme_buffer_info *rxbi = rxring->bufinf;
+	rxbi += i;
+
+	if (rxbi->skb) {
+		pci_unmap_page(jme->pdev,
+				 rxbi->mapping,
+				 rxbi->len,
+				 PCI_DMA_FROMDEVICE);
+		dev_kfree_skb(rxbi->skb);
+		rxbi->skb = NULL;
+		rxbi->mapping = 0;
+		rxbi->len = 0;
+	}
+}
+
+static void
+jme_free_rx_resources(struct jme_adapter *jme)
+{
+	int i;
+	struct jme_ring *rxring = &(jme->rxring[0]);
+
+	if (rxring->alloc) {
+		for (i = 0 ; i < jme->rx_ring_size ; ++i)
+			jme_free_rx_buf(jme, i);
+
+		dma_free_coherent(&(jme->pdev->dev),
+				  RX_RING_ALLOC_SIZE(jme->rx_ring_size),
+				  rxring->alloc,
+				  rxring->dmaalloc);
+		rxring->alloc    = NULL;
+		rxring->desc     = NULL;
+		rxring->dmaalloc = 0;
+		rxring->dma      = 0;
+	}
+	rxring->next_to_use   = 0;
+	atomic_set(&rxring->next_to_clean, 0);
+}
+
+static int
+jme_setup_rx_resources(struct jme_adapter *jme)
+{
+	int i;
+	struct jme_ring *rxring = &(jme->rxring[0]);
+
+	rxring->alloc = dma_alloc_coherent(&(jme->pdev->dev),
+				   RX_RING_ALLOC_SIZE(jme->rx_ring_size),
+				   &(rxring->dmaalloc),
+				   GFP_ATOMIC);
+	if (!rxring->alloc) {
+		rxring->desc = NULL;
+		rxring->dmaalloc = 0;
+		rxring->dma = 0;
+		return -ENOMEM;
+	}
+
+	/*
+	 * 16 Bytes align
+	 */
+	rxring->desc		= (void *)ALIGN((unsigned long)(rxring->alloc),
+						RING_DESC_ALIGN);
+	rxring->dma		= ALIGN(rxring->dmaalloc, RING_DESC_ALIGN);
+	rxring->next_to_use	= 0;
+	atomic_set(&rxring->next_to_clean, 0);
+
+	/*
+	 * Initiallize Receive Descriptors
+	 */
+	for (i = 0 ; i < jme->rx_ring_size ; ++i) {
+		if (unlikely(jme_make_new_rx_buf(jme, i))) {
+			jme_free_rx_resources(jme);
+			return -ENOMEM;
+		}
+
+		jme_set_clean_rxdesc(jme, i);
+	}
+
+	return 0;
+}
+
+static inline void
+jme_enable_rx_engine(struct jme_adapter *jme)
+{
+	/*
+	 * Select Queue 0
+	 */
+	jwrite32(jme, JME_RXCS, jme->reg_rxcs |
+				RXCS_QUEUESEL_Q0);
+	wmb();
+
+	/*
+	 * Setup RX DMA Bass Address
+	 */
+	jwrite32(jme, JME_RXDBA_LO, (__u64)jme->rxring[0].dma & 0xFFFFFFFFUL);
+	jwrite32(jme, JME_RXDBA_HI, (__u64)(jme->rxring[0].dma) >> 32);
+	jwrite32(jme, JME_RXNDA, (__u64)jme->rxring[0].dma & 0xFFFFFFFFUL);
+
+	/*
+	 * Setup RX Descriptor Count
+	 */
+	jwrite32(jme, JME_RXQDC, jme->rx_ring_size);
+
+	/*
+	 * Setup Unicast Filter
+	 */
+	jme_set_multi(jme->dev);
+
+	/*
+	 * Enable RX Engine
+	 */
+	wmb();
+	jwrite32(jme, JME_RXCS, jme->reg_rxcs |
+				RXCS_QUEUESEL_Q0 |
+				RXCS_ENABLE |
+				RXCS_QST);
+}
+
+static inline void
+jme_restart_rx_engine(struct jme_adapter *jme)
+{
+	/*
+	 * Start RX Engine
+	 */
+	jwrite32(jme, JME_RXCS, jme->reg_rxcs |
+				RXCS_QUEUESEL_Q0 |
+				RXCS_ENABLE |
+				RXCS_QST);
+}
+
+static inline void
+jme_disable_rx_engine(struct jme_adapter *jme)
+{
+	int i;
+	u32 val;
+
+	/*
+	 * Disable RX Engine
+	 */
+	jwrite32(jme, JME_RXCS, jme->reg_rxcs);
+	wmb();
+
+	val = jread32(jme, JME_RXCS);
+	for (i = JME_RX_DISABLE_TIMEOUT ; (val & RXCS_ENABLE) && i > 0 ; --i) {
+		mdelay(1);
+		val = jread32(jme, JME_RXCS);
+		rmb();
+	}
+
+	if (!i)
+		jeprintk(jme->pdev, "Disable RX engine timeout.\n");
+
+}
+
+static int
+jme_rxsum_ok(struct jme_adapter *jme, u16 flags)
+{
+	if (!(flags & (RXWBFLAG_TCPON | RXWBFLAG_UDPON | RXWBFLAG_IPV4)))
+		return false;
+
+	if (unlikely(!(flags & RXWBFLAG_MF) &&
+	(flags & RXWBFLAG_TCPON) && !(flags & RXWBFLAG_TCPCS))) {
+		msg_rx_err(jme, "TCP Checksum error.\n");
+		goto out_sumerr;
+	}
+
+	if (unlikely(!(flags & RXWBFLAG_MF) &&
+	(flags & RXWBFLAG_UDPON) && !(flags & RXWBFLAG_UDPCS))) {
+		msg_rx_err(jme, "UDP Checksum error.\n");
+		goto out_sumerr;
+	}
+
+	if (unlikely((flags & RXWBFLAG_IPV4) && !(flags & RXWBFLAG_IPCS))) {
+		msg_rx_err(jme, "IPv4 Checksum error.\n");
+		goto out_sumerr;
+	}
+
+	return true;
+
+out_sumerr:
+	return false;
+}
+
+static void
+jme_alloc_and_feed_skb(struct jme_adapter *jme, int idx)
+{
+	struct jme_ring *rxring = &(jme->rxring[0]);
+	struct rxdesc *rxdesc = rxring->desc;
+	struct jme_buffer_info *rxbi = rxring->bufinf;
+	struct sk_buff *skb;
+	int framesize;
+
+	rxdesc += idx;
+	rxbi += idx;
+
+	skb = rxbi->skb;
+	pci_dma_sync_single_for_cpu(jme->pdev,
+					rxbi->mapping,
+					rxbi->len,
+					PCI_DMA_FROMDEVICE);
+
+	if (unlikely(jme_make_new_rx_buf(jme, idx))) {
+		pci_dma_sync_single_for_device(jme->pdev,
+						rxbi->mapping,
+						rxbi->len,
+						PCI_DMA_FROMDEVICE);
+
+		++(NET_STAT(jme).rx_dropped);
+	} else {
+		framesize = le16_to_cpu(rxdesc->descwb.framesize)
+				- RX_PREPAD_SIZE;
+
+		skb_reserve(skb, RX_PREPAD_SIZE);
+		skb_put(skb, framesize);
+		skb->protocol = eth_type_trans(skb, jme->dev);
+
+		if (jme_rxsum_ok(jme, rxdesc->descwb.flags))
+			skb->ip_summed = CHECKSUM_UNNECESSARY;
+		else
+			skb->ip_summed = CHECKSUM_NONE;
+
+		if (rxdesc->descwb.flags & RXWBFLAG_TAGON) {
+			if (jme->vlgrp) {
+				jme->jme_vlan_rx(skb, jme->vlgrp,
+					le32_to_cpu(rxdesc->descwb.vlan));
+				NET_STAT(jme).rx_bytes += 4;
+			}
+		} else {
+			jme->jme_rx(skb);
+		}
+
+		if ((le16_to_cpu(rxdesc->descwb.flags) & RXWBFLAG_DEST) ==
+				RXWBFLAG_DEST_MUL)
+			++(NET_STAT(jme).multicast);
+
+		jme->dev->last_rx = jiffies;
+		NET_STAT(jme).rx_bytes += framesize;
+		++(NET_STAT(jme).rx_packets);
+	}
+
+	jme_set_clean_rxdesc(jme, idx);
+
+}
+
+static int
+jme_process_receive(struct jme_adapter *jme, int limit)
+{
+	struct jme_ring *rxring = &(jme->rxring[0]);
+	struct rxdesc *rxdesc = rxring->desc;
+	int i, j, ccnt, desccnt, mask = jme->rx_ring_mask;
+
+	if (unlikely(!atomic_dec_and_test(&jme->rx_cleaning)))
+		goto out_inc;
+
+	if (unlikely(atomic_read(&jme->link_changing) != 1))
+		goto out_inc;
+
+	if (unlikely(!netif_carrier_ok(jme->dev)))
+		goto out_inc;
+
+	i = atomic_read(&rxring->next_to_clean);
+	while (limit-- > 0) {
+		rxdesc = rxring->desc;
+		rxdesc += i;
+
+		if ((rxdesc->descwb.flags & RXWBFLAG_OWN) ||
+		!(rxdesc->descwb.desccnt & RXWBDCNT_WBCPL))
+			goto out;
+
+		desccnt = rxdesc->descwb.desccnt & RXWBDCNT_DCNT;
+
+		if (unlikely(desccnt > 1 ||
+		rxdesc->descwb.errstat & RXWBERR_ALLERR)) {
+
+			if (rxdesc->descwb.errstat & RXWBERR_CRCERR)
+				++(NET_STAT(jme).rx_crc_errors);
+			else if (rxdesc->descwb.errstat & RXWBERR_OVERUN)
+				++(NET_STAT(jme).rx_fifo_errors);
+			else
+				++(NET_STAT(jme).rx_errors);
+
+			if (desccnt > 1)
+				limit -= desccnt - 1;
+
+			for (j = i, ccnt = desccnt ; ccnt-- ; ) {
+				jme_set_clean_rxdesc(jme, j);
+				j = (j + 1) & (mask);
+			}
+
+		} else {
+			jme_alloc_and_feed_skb(jme, i);
+		}
+
+		i = (i + desccnt) & (mask);
+	}
+
+out:
+	atomic_set(&rxring->next_to_clean, i);
+
+out_inc:
+	atomic_inc(&jme->rx_cleaning);
+
+	return limit > 0 ? limit : 0;
+
+}
+
+static void
+jme_attempt_pcc(struct dynpcc_info *dpi, int atmp)
+{
+	if (likely(atmp == dpi->cur)) {
+		dpi->cnt = 0;
+		return;
+	}
+
+	if (dpi->attempt == atmp) {
+		++(dpi->cnt);
+	} else {
+		dpi->attempt = atmp;
+		dpi->cnt = 0;
+	}
+
+}
+
+static void
+jme_dynamic_pcc(struct jme_adapter *jme)
+{
+	register struct dynpcc_info *dpi = &(jme->dpi);
+
+	if ((NET_STAT(jme).rx_bytes - dpi->last_bytes) > PCC_P3_THRESHOLD)
+		jme_attempt_pcc(dpi, PCC_P3);
+	else if ((NET_STAT(jme).rx_packets - dpi->last_pkts) > PCC_P2_THRESHOLD
+	|| dpi->intr_cnt > PCC_INTR_THRESHOLD)
+		jme_attempt_pcc(dpi, PCC_P2);
+	else
+		jme_attempt_pcc(dpi, PCC_P1);
+
+	if (unlikely(dpi->attempt != dpi->cur && dpi->cnt > 5)) {
+		if (dpi->attempt < dpi->cur)
+			tasklet_schedule(&jme->rxclean_task);
+		jme_set_rx_pcc(jme, dpi->attempt);
+		dpi->cur = dpi->attempt;
+		dpi->cnt = 0;
+	}
+}
+
+static void
+jme_start_pcc_timer(struct jme_adapter *jme)
+{
+	struct dynpcc_info *dpi = &(jme->dpi);
+	dpi->last_bytes		= NET_STAT(jme).rx_bytes;
+	dpi->last_pkts		= NET_STAT(jme).rx_packets;
+	dpi->intr_cnt		= 0;
+	jwrite32(jme, JME_TMCSR,
+		TMCSR_EN | ((0xFFFFFF - PCC_INTERVAL_US) & TMCSR_CNT));
+}
+
+static inline void
+jme_stop_pcc_timer(struct jme_adapter *jme)
+{
+	jwrite32(jme, JME_TMCSR, 0);
+}
+
+static void
+jme_shutdown_nic(struct jme_adapter *jme)
+{
+	u32 phylink;
+
+	phylink = jme_linkstat_from_phy(jme);
+
+	if (!(phylink & PHY_LINK_UP)) {
+		/*
+		 * Disable all interrupt before issue timer
+		 */
+		jme_stop_irq(jme);
+		jwrite32(jme, JME_TIMER2, TMCSR_EN | 0xFFFFFE);
+	}
+}
+
+static void
+jme_pcc_tasklet(unsigned long arg)
+{
+	struct jme_adapter *jme = (struct jme_adapter *)arg;
+	struct net_device *netdev = jme->dev;
+
+	if (unlikely(test_bit(JME_FLAG_SHUTDOWN, &jme->flags))) {
+		jme_shutdown_nic(jme);
+		return;
+	}
+
+	if (unlikely(!netif_carrier_ok(netdev) ||
+		(atomic_read(&jme->link_changing) != 1)
+	)) {
+		jme_stop_pcc_timer(jme);
+		return;
+	}
+
+	if (!(test_bit(JME_FLAG_POLL, &jme->flags)))
+		jme_dynamic_pcc(jme);
+
+	jme_start_pcc_timer(jme);
+}
+
+static inline void
+jme_polling_mode(struct jme_adapter *jme)
+{
+	jme_set_rx_pcc(jme, PCC_OFF);
+}
+
+static inline void
+jme_interrupt_mode(struct jme_adapter *jme)
+{
+	jme_set_rx_pcc(jme, PCC_P1);
+}
+
+static inline int
+jme_pseudo_hotplug_enabled(struct jme_adapter *jme)
+{
+	u32 apmc;
+	apmc = jread32(jme, JME_APMC);
+	return apmc & JME_APMC_PSEUDO_HP_EN;
+}
+
+static void
+jme_start_shutdown_timer(struct jme_adapter *jme)
+{
+	u32 apmc;
+
+	apmc = jread32(jme, JME_APMC) | JME_APMC_PCIE_SD_EN;
+	apmc &= ~JME_APMC_EPIEN_CTRL;
+	if (!no_extplug) {
+		jwrite32f(jme, JME_APMC, apmc | JME_APMC_EPIEN_CTRL_EN);
+		wmb();
+	}
+	jwrite32f(jme, JME_APMC, apmc);
+
+	jwrite32f(jme, JME_TIMER2, 0);
+	set_bit(JME_FLAG_SHUTDOWN, &jme->flags);
+	jwrite32(jme, JME_TMCSR,
+		TMCSR_EN | ((0xFFFFFF - APMC_PHP_SHUTDOWN_DELAY) & TMCSR_CNT));
+}
+
+static void
+jme_stop_shutdown_timer(struct jme_adapter *jme)
+{
+	u32 apmc;
+
+	jwrite32f(jme, JME_TMCSR, 0);
+	jwrite32f(jme, JME_TIMER2, 0);
+	clear_bit(JME_FLAG_SHUTDOWN, &jme->flags);
+
+	apmc = jread32(jme, JME_APMC);
+	apmc &= ~(JME_APMC_PCIE_SD_EN | JME_APMC_EPIEN_CTRL);
+	jwrite32f(jme, JME_APMC, apmc | JME_APMC_EPIEN_CTRL_DIS);
+	wmb();
+	jwrite32f(jme, JME_APMC, apmc);
+}
+
+static void
+jme_link_change_tasklet(unsigned long arg)
+{
+	struct jme_adapter *jme = (struct jme_adapter *)arg;
+	struct net_device *netdev = jme->dev;
+	int rc;
+
+	while (!atomic_dec_and_test(&jme->link_changing)) {
+		atomic_inc(&jme->link_changing);
+		msg_intr(jme, "Get link change lock failed.\n");
+		while (atomic_read(&jme->link_changing) != 1)
+			msg_intr(jme, "Waiting link change lock.\n");
+	}
+
+	if (jme_check_link(netdev, 1) && jme->old_mtu == netdev->mtu)
+		goto out;
+
+	jme->old_mtu = netdev->mtu;
+	netif_stop_queue(netdev);
+	if (jme_pseudo_hotplug_enabled(jme))
+		jme_stop_shutdown_timer(jme);
+
+	jme_stop_pcc_timer(jme);
+	tasklet_disable(&jme->txclean_task);
+	tasklet_disable(&jme->rxclean_task);
+	tasklet_disable(&jme->rxempty_task);
+
+	if (netif_carrier_ok(netdev)) {
+		jme_reset_ghc_speed(jme);
+		jme_disable_rx_engine(jme);
+		jme_disable_tx_engine(jme);
+		jme_reset_mac_processor(jme);
+		jme_free_rx_resources(jme);
+		jme_free_tx_resources(jme);
+
+		if (test_bit(JME_FLAG_POLL, &jme->flags))
+			jme_polling_mode(jme);
+
+		netif_carrier_off(netdev);
+	}
+
+	jme_check_link(netdev, 0);
+	if (netif_carrier_ok(netdev)) {
+		rc = jme_setup_rx_resources(jme);
+		if (rc) {
+			jeprintk(jme->pdev, "Allocating resources for RX error"
+				", Device STOPPED!\n");
+			goto out_enable_tasklet;
+		}
+
+		rc = jme_setup_tx_resources(jme);
+		if (rc) {
+			jeprintk(jme->pdev, "Allocating resources for TX error"
+				", Device STOPPED!\n");
+			goto err_out_free_rx_resources;
+		}
+
+		jme_enable_rx_engine(jme);
+		jme_enable_tx_engine(jme);
+
+		netif_start_queue(netdev);
+
+		if (test_bit(JME_FLAG_POLL, &jme->flags))
+			jme_interrupt_mode(jme);
+
+		jme_start_pcc_timer(jme);
+	} else if (jme_pseudo_hotplug_enabled(jme)) {
+		jme_start_shutdown_timer(jme);
+	}
+
+	goto out_enable_tasklet;
+
+err_out_free_rx_resources:
+	jme_free_rx_resources(jme);
+out_enable_tasklet:
+	tasklet_enable(&jme->txclean_task);
+	tasklet_hi_enable(&jme->rxclean_task);
+	tasklet_hi_enable(&jme->rxempty_task);
+out:
+	atomic_inc(&jme->link_changing);
+}
+
+static void
+jme_rx_clean_tasklet(unsigned long arg)
+{
+	struct jme_adapter *jme = (struct jme_adapter *)arg;
+	struct dynpcc_info *dpi = &(jme->dpi);
+
+	jme_process_receive(jme, jme->rx_ring_size);
+	++(dpi->intr_cnt);
+
+}
+
+static int
+jme_poll(JME_NAPI_HOLDER(holder), JME_NAPI_WEIGHT(budget))
+{
+	struct jme_adapter *jme = jme_napi_priv(holder);
+	struct net_device *netdev = jme->dev;
+	int rest;
+
+	rest = jme_process_receive(jme, JME_NAPI_WEIGHT_VAL(budget));
+
+	while (atomic_read(&jme->rx_empty) > 0) {
+		atomic_dec(&jme->rx_empty);
+		++(NET_STAT(jme).rx_dropped);
+		jme_restart_rx_engine(jme);
+	}
+	atomic_inc(&jme->rx_empty);
+
+	if (rest) {
+		JME_RX_COMPLETE(netdev, holder);
+		jme_interrupt_mode(jme);
+	}
+
+	JME_NAPI_WEIGHT_SET(budget, rest);
+	return JME_NAPI_WEIGHT_VAL(budget) - rest;
+}
+
+static void
+jme_rx_empty_tasklet(unsigned long arg)
+{
+	struct jme_adapter *jme = (struct jme_adapter *)arg;
+
+	if (unlikely(atomic_read(&jme->link_changing) != 1))
+		return;
+
+	if (unlikely(!netif_carrier_ok(jme->dev)))
+		return;
+
+	msg_rx_status(jme, "RX Queue Full!\n");
+
+	jme_rx_clean_tasklet(arg);
+
+	while (atomic_read(&jme->rx_empty) > 0) {
+		atomic_dec(&jme->rx_empty);
+		++(NET_STAT(jme).rx_dropped);
+		jme_restart_rx_engine(jme);
+	}
+	atomic_inc(&jme->rx_empty);
+}
+
+static void
+jme_wake_queue_if_stopped(struct jme_adapter *jme)
+{
+	struct jme_ring *txring = jme->txring;
+
+	smp_wmb();
+	if (unlikely(netif_queue_stopped(jme->dev) &&
+	atomic_read(&txring->nr_free) >= (jme->tx_wake_threshold))) {
+		msg_tx_done(jme, "TX Queue Waked.\n");
+		netif_wake_queue(jme->dev);
+	}
+
+}
+
+static void
+jme_tx_clean_tasklet(unsigned long arg)
+{
+	struct jme_adapter *jme = (struct jme_adapter *)arg;
+	struct jme_ring *txring = &(jme->txring[0]);
+	struct txdesc *txdesc = txring->desc;
+	struct jme_buffer_info *txbi = txring->bufinf, *ctxbi, *ttxbi;
+	int i, j, cnt = 0, max, err, mask;
+
+	tx_dbg(jme, "Into txclean.\n");
+
+	if (unlikely(!atomic_dec_and_test(&jme->tx_cleaning)))
+		goto out;
+
+	if (unlikely(atomic_read(&jme->link_changing) != 1))
+		goto out;
+
+	if (unlikely(!netif_carrier_ok(jme->dev)))
+		goto out;
+
+	max = jme->tx_ring_size - atomic_read(&txring->nr_free);
+	mask = jme->tx_ring_mask;
+
+	for (i = atomic_read(&txring->next_to_clean) ; cnt < max ; ) {
+
+		ctxbi = txbi + i;
+
+		if (likely(ctxbi->skb &&
+		!(txdesc[i].descwb.flags & TXWBFLAG_OWN))) {
+
+			tx_dbg(jme, "txclean: %d+%d@%lu\n",
+					i, ctxbi->nr_desc, jiffies);
+
+			err = txdesc[i].descwb.flags & TXWBFLAG_ALLERR;
+
+			for (j = 1 ; j < ctxbi->nr_desc ; ++j) {
+				ttxbi = txbi + ((i + j) & (mask));
+				txdesc[(i + j) & (mask)].dw[0] = 0;
+
+				pci_unmap_page(jme->pdev,
+						 ttxbi->mapping,
+						 ttxbi->len,
+						 PCI_DMA_TODEVICE);
+
+				ttxbi->mapping = 0;
+				ttxbi->len = 0;
+			}
+
+			dev_kfree_skb(ctxbi->skb);
+
+			cnt += ctxbi->nr_desc;
+
+			if (unlikely(err)) {
+				++(NET_STAT(jme).tx_carrier_errors);
+			} else {
+				++(NET_STAT(jme).tx_packets);
+				NET_STAT(jme).tx_bytes += ctxbi->len;
+			}
+
+			ctxbi->skb = NULL;
+			ctxbi->len = 0;
+			ctxbi->start_xmit = 0;
+
+		} else {
+			break;
+		}
+
+		i = (i + ctxbi->nr_desc) & mask;
+
+		ctxbi->nr_desc = 0;
+	}
+
+	tx_dbg(jme, "txclean: done %d@%lu.\n", i, jiffies);
+	atomic_set(&txring->next_to_clean, i);
+	atomic_add(cnt, &txring->nr_free);
+
+	jme_wake_queue_if_stopped(jme);
+
+out:
+	atomic_inc(&jme->tx_cleaning);
+}
+
+static void
+jme_intr_msi(struct jme_adapter *jme, u32 intrstat)
+{
+	/*
+	 * Disable interrupt
+	 */
+	jwrite32f(jme, JME_IENC, INTR_ENABLE);
+
+	if (intrstat & (INTR_LINKCH | INTR_SWINTR)) {
+		/*
+		 * Link change event is critical
+		 * all other events are ignored
+		 */
+		jwrite32(jme, JME_IEVE, intrstat);
+		tasklet_schedule(&jme->linkch_task);
+		goto out_reenable;
+	}
+
+	if (intrstat & INTR_TMINTR) {
+		jwrite32(jme, JME_IEVE, INTR_TMINTR);
+		tasklet_schedule(&jme->pcc_task);
+	}
+
+	if (intrstat & (INTR_PCCTXTO | INTR_PCCTX)) {
+		jwrite32(jme, JME_IEVE, INTR_PCCTXTO | INTR_PCCTX | INTR_TX0);
+		tasklet_schedule(&jme->txclean_task);
+	}
+
+	if ((intrstat & (INTR_PCCRX0TO | INTR_PCCRX0 | INTR_RX0EMP))) {
+		jwrite32(jme, JME_IEVE, (intrstat & (INTR_PCCRX0TO |
+						     INTR_PCCRX0 |
+						     INTR_RX0EMP)) |
+					INTR_RX0);
+	}
+
+	if (test_bit(JME_FLAG_POLL, &jme->flags)) {
+		if (intrstat & INTR_RX0EMP)
+			atomic_inc(&jme->rx_empty);
+
+		if ((intrstat & (INTR_PCCRX0TO | INTR_PCCRX0 | INTR_RX0EMP))) {
+			if (likely(JME_RX_SCHEDULE_PREP(jme))) {
+				jme_polling_mode(jme);
+				JME_RX_SCHEDULE(jme);
+			}
+		}
+	} else {
+		if (intrstat & INTR_RX0EMP) {
+			atomic_inc(&jme->rx_empty);
+			tasklet_hi_schedule(&jme->rxempty_task);
+		} else if (intrstat & (INTR_PCCRX0TO | INTR_PCCRX0)) {
+			tasklet_hi_schedule(&jme->rxclean_task);
+		}
+	}
+
+out_reenable:
+	/*
+	 * Re-enable interrupt
+	 */
+	jwrite32f(jme, JME_IENS, INTR_ENABLE);
+}
+
+static irqreturn_t
+jme_intr(int irq, void *dev_id)
+{
+	struct net_device *netdev = dev_id;
+	struct jme_adapter *jme = netdev_priv(netdev);
+	u32 intrstat;
+
+	intrstat = jread32(jme, JME_IEVE);
+
+	/*
+	 * Check if it's really an interrupt for us
+	 */
+	if (unlikely((intrstat & INTR_ENABLE) == 0))
+		return IRQ_NONE;
+
+	/*
+	 * Check if the device still exist
+	 */
+	if (unlikely(intrstat == ~((typeof(intrstat))0)))
+		return IRQ_NONE;
+
+	jme_intr_msi(jme, intrstat);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t
+jme_msi(int irq, void *dev_id)
+{
+	struct net_device *netdev = dev_id;
+	struct jme_adapter *jme = netdev_priv(netdev);
+	u32 intrstat;
+
+	pci_dma_sync_single_for_cpu(jme->pdev,
+				    jme->shadow_dma,
+				    sizeof(u32) * SHADOW_REG_NR,
+				    PCI_DMA_FROMDEVICE);
+	intrstat = jme->shadow_regs[SHADOW_IEVE];
+	jme->shadow_regs[SHADOW_IEVE] = 0;
+
+	jme_intr_msi(jme, intrstat);
+
+	return IRQ_HANDLED;
+}
+
+static void
+jme_reset_link(struct jme_adapter *jme)
+{
+	jwrite32(jme, JME_TMCSR, TMCSR_SWIT);
+}
+
+static void
+jme_restart_an(struct jme_adapter *jme)
+{
+	u32 bmcr;
+
+	spin_lock_bh(&jme->phy_lock);
+	bmcr = jme_mdio_read(jme->dev, jme->mii_if.phy_id, MII_BMCR);
+	bmcr |= (BMCR_ANENABLE | BMCR_ANRESTART);
+	jme_mdio_write(jme->dev, jme->mii_if.phy_id, MII_BMCR, bmcr);
+	spin_unlock_bh(&jme->phy_lock);
+}
+
+static int
+jme_request_irq(struct jme_adapter *jme)
+{
+	int rc;
+	struct net_device *netdev = jme->dev;
+	irq_handler_t handler = jme_intr;
+	int irq_flags = IRQF_SHARED;
+
+	if (!pci_enable_msi(jme->pdev)) {
+		set_bit(JME_FLAG_MSI, &jme->flags);
+		handler = jme_msi;
+		irq_flags = 0;
+	}
+
+	rc = request_irq(jme->pdev->irq, handler, irq_flags, netdev->name,
+			  netdev);
+	if (rc) {
+		jeprintk(jme->pdev,
+			"Unable to request %s interrupt (return: %d)\n",
+			test_bit(JME_FLAG_MSI, &jme->flags) ? "MSI" : "INTx",
+			rc);
+
+		if (test_bit(JME_FLAG_MSI, &jme->flags)) {
+			pci_disable_msi(jme->pdev);
+			clear_bit(JME_FLAG_MSI, &jme->flags);
+		}
+	} else {
+		netdev->irq = jme->pdev->irq;
+	}
+
+	return rc;
+}
+
+static void
+jme_free_irq(struct jme_adapter *jme)
+{
+	free_irq(jme->pdev->irq, jme->dev);
+	if (test_bit(JME_FLAG_MSI, &jme->flags)) {
+		pci_disable_msi(jme->pdev);
+		clear_bit(JME_FLAG_MSI, &jme->flags);
+		jme->dev->irq = jme->pdev->irq;
+	}
+}
+
+static int
+jme_open(struct net_device *netdev)
+{
+	struct jme_adapter *jme = netdev_priv(netdev);
+	int rc;
+
+	jme_clear_pm(jme);
+	JME_NAPI_ENABLE(jme);
+
+	tasklet_enable(&jme->txclean_task);
+	tasklet_hi_enable(&jme->rxclean_task);
+	tasklet_hi_enable(&jme->rxempty_task);
+
+	rc = jme_request_irq(jme);
+	if (rc)
+		goto err_out;
+
+	jme_enable_shadow(jme);
+	jme_start_irq(jme);
+
+	if (test_bit(JME_FLAG_SSET, &jme->flags))
+		jme_set_settings(netdev, &jme->old_ecmd);
+	else
+		jme_reset_phy_processor(jme);
+
+	jme_reset_link(jme);
+
+	return 0;
+
+err_out:
+	netif_stop_queue(netdev);
+	netif_carrier_off(netdev);
+	return rc;
+}
+
+#ifdef CONFIG_PM
+static void
+jme_set_100m_half(struct jme_adapter *jme)
+{
+	u32 bmcr, tmp;
+
+	bmcr = jme_mdio_read(jme->dev, jme->mii_if.phy_id, MII_BMCR);
+	tmp = bmcr & ~(BMCR_ANENABLE | BMCR_SPEED100 |
+		       BMCR_SPEED1000 | BMCR_FULLDPLX);
+	tmp |= BMCR_SPEED100;
+
+	if (bmcr != tmp)
+		jme_mdio_write(jme->dev, jme->mii_if.phy_id, MII_BMCR, tmp);
+
+	if (jme->fpgaver)
+		jwrite32(jme, JME_GHC, GHC_SPEED_100M | GHC_LINK_POLL);
+	else
+		jwrite32(jme, JME_GHC, GHC_SPEED_100M);
+}
+
+#define JME_WAIT_LINK_TIME 2000 /* 2000ms */
+static void
+jme_wait_link(struct jme_adapter *jme)
+{
+	u32 phylink, to = JME_WAIT_LINK_TIME;
+
+	mdelay(1000);
+	phylink = jme_linkstat_from_phy(jme);
+	while (!(phylink & PHY_LINK_UP) && (to -= 10) > 0) {
+		mdelay(10);
+		phylink = jme_linkstat_from_phy(jme);
+	}
+}
+#endif
+
+static inline void
+jme_phy_off(struct jme_adapter *jme)
+{
+	jme_mdio_write(jme->dev, jme->mii_if.phy_id, MII_BMCR, BMCR_PDOWN);
+}
+
+static int
+jme_close(struct net_device *netdev)
+{
+	struct jme_adapter *jme = netdev_priv(netdev);
+
+	netif_stop_queue(netdev);
+	netif_carrier_off(netdev);
+
+	jme_stop_irq(jme);
+	jme_disable_shadow(jme);
+	jme_free_irq(jme);
+
+	JME_NAPI_DISABLE(jme);
+
+	tasklet_kill(&jme->linkch_task);
+	tasklet_kill(&jme->txclean_task);
+	tasklet_kill(&jme->rxclean_task);
+	tasklet_kill(&jme->rxempty_task);
+
+	jme_reset_ghc_speed(jme);
+	jme_disable_rx_engine(jme);
+	jme_disable_tx_engine(jme);
+	jme_reset_mac_processor(jme);
+	jme_free_rx_resources(jme);
+	jme_free_tx_resources(jme);
+	jme->phylink = 0;
+	jme_phy_off(jme);
+
+	return 0;
+}
+
+static int
+jme_alloc_txdesc(struct jme_adapter *jme,
+			struct sk_buff *skb)
+{
+	struct jme_ring *txring = jme->txring;
+	int idx, nr_alloc, mask = jme->tx_ring_mask;
+
+	idx = txring->next_to_use;
+	nr_alloc = skb_shinfo(skb)->nr_frags + 2;
+
+	if (unlikely(atomic_read(&txring->nr_free) < nr_alloc))
+		return -1;
+
+	atomic_sub(nr_alloc, &txring->nr_free);
+
+	txring->next_to_use = (txring->next_to_use + nr_alloc) & mask;
+
+	return idx;
+}
+
+static void
+jme_fill_tx_map(struct pci_dev *pdev,
+		struct txdesc *txdesc,
+		struct jme_buffer_info *txbi,
+		struct page *page,
+		u32 page_offset,
+		u32 len,
+		u8 hidma)
+{
+	dma_addr_t dmaaddr;
+
+	dmaaddr = pci_map_page(pdev,
+				page,
+				page_offset,
+				len,
+				PCI_DMA_TODEVICE);
+
+	pci_dma_sync_single_for_device(pdev,
+				       dmaaddr,
+				       len,
+				       PCI_DMA_TODEVICE);
+
+	txdesc->dw[0] = 0;
+	txdesc->dw[1] = 0;
+	txdesc->desc2.flags	= TXFLAG_OWN;
+	txdesc->desc2.flags	|= (hidma) ? TXFLAG_64BIT : 0;
+	txdesc->desc2.datalen	= cpu_to_le16(len);
+	txdesc->desc2.bufaddrh	= cpu_to_le32((__u64)dmaaddr >> 32);
+	txdesc->desc2.bufaddrl	= cpu_to_le32(
+					(__u64)dmaaddr & 0xFFFFFFFFUL);
+
+	txbi->mapping = dmaaddr;
+	txbi->len = len;
+}
+
+static void
+jme_map_tx_skb(struct jme_adapter *jme, struct sk_buff *skb, int idx)
+{
+	struct jme_ring *txring = jme->txring;
+	struct txdesc *txdesc = txring->desc, *ctxdesc;
+	struct jme_buffer_info *txbi = txring->bufinf, *ctxbi;
+	u8 hidma = jme->dev->features & NETIF_F_HIGHDMA;
+	int i, nr_frags = skb_shinfo(skb)->nr_frags;
+	int mask = jme->tx_ring_mask;
+	struct skb_frag_struct *frag;
+	u32 len;
+
+	for (i = 0 ; i < nr_frags ; ++i) {
+		frag = &skb_shinfo(skb)->frags[i];
+		ctxdesc = txdesc + ((idx + i + 2) & (mask));
+		ctxbi = txbi + ((idx + i + 2) & (mask));
+
+		jme_fill_tx_map(jme->pdev, ctxdesc, ctxbi, frag->page,
+				 frag->page_offset, frag->size, hidma);
+	}
+
+	len = skb_is_nonlinear(skb) ? skb_headlen(skb) : skb->len;
+	ctxdesc = txdesc + ((idx + 1) & (mask));
+	ctxbi = txbi + ((idx + 1) & (mask));
+	jme_fill_tx_map(jme->pdev, ctxdesc, ctxbi, virt_to_page(skb->data),
+			offset_in_page(skb->data), len, hidma);
+
+}
+
+static int
+jme_expand_header(struct jme_adapter *jme, struct sk_buff *skb)
+{
+	if (unlikely(skb_shinfo(skb)->gso_size &&
+			skb_header_cloned(skb) &&
+			pskb_expand_head(skb, 0, 0, GFP_ATOMIC))) {
+		dev_kfree_skb(skb);
+		return -1;
+	}
+
+	return 0;
+}
+
+static int
+jme_tx_tso(struct sk_buff *skb,
+		u16 *mss, u8 *flags)
+{
+	*mss = skb_shinfo(skb)->gso_size << TXDESC_MSS_SHIFT;
+	if (*mss) {
+		*flags |= TXFLAG_LSEN;
+
+		if (skb->protocol == htons(ETH_P_IP)) {
+			struct iphdr *iph = ip_hdr(skb);
+
+			iph->check = 0;
+			tcp_hdr(skb)->check = ~csum_tcpudp_magic(iph->saddr,
+								iph->daddr, 0,
+								IPPROTO_TCP,
+								0);
+		} else {
+			struct ipv6hdr *ip6h = ipv6_hdr(skb);
+
+			tcp_hdr(skb)->check = ~csum_ipv6_magic(&ip6h->saddr,
+								&ip6h->daddr, 0,
+								IPPROTO_TCP,
+								0);
+		}
+
+		return 0;
+	}
+
+	return 1;
+}
+
+static void
+jme_tx_csum(struct jme_adapter *jme, struct sk_buff *skb, u8 *flags)
+{
+	if (skb->ip_summed == CHECKSUM_PARTIAL) {
+		u8 ip_proto;
+
+		switch (skb->protocol) {
+		case htons(ETH_P_IP):
+			ip_proto = ip_hdr(skb)->protocol;
+			break;
+		case htons(ETH_P_IPV6):
+			ip_proto = ipv6_hdr(skb)->nexthdr;
+			break;
+		default:
+			ip_proto = 0;
+			break;
+		}
+
+		switch (ip_proto) {
+		case IPPROTO_TCP:
+			*flags |= TXFLAG_TCPCS;
+			break;
+		case IPPROTO_UDP:
+			*flags |= TXFLAG_UDPCS;
+			break;
+		default:
+			msg_tx_err(jme, "Error upper layer protocol.\n");
+			break;
+		}
+	}
+}
+
+static inline void
+jme_tx_vlan(struct sk_buff *skb, u16 *vlan, u8 *flags)
+{
+	if (vlan_tx_tag_present(skb)) {
+		*flags |= TXFLAG_TAGON;
+		*vlan = vlan_tx_tag_get(skb);
+	}
+}
+
+static int
+jme_fill_first_tx_desc(struct jme_adapter *jme, struct sk_buff *skb, int idx)
+{
+	struct jme_ring *txring = jme->txring;
+	struct txdesc *txdesc;
+	struct jme_buffer_info *txbi;
+	u8 flags;
+
+	txdesc = (struct txdesc *)txring->desc + idx;
+	txbi = txring->bufinf + idx;
+
+	txdesc->dw[0] = 0;
+	txdesc->dw[1] = 0;
+	txdesc->dw[2] = 0;
+	txdesc->dw[3] = 0;
+	txdesc->desc1.pktsize = cpu_to_le16(skb->len);
+	/*
+	 * Set OWN bit at final.
+	 * When kernel transmit faster than NIC.
+	 * And NIC trying to send this descriptor before we tell
+	 * it to start sending this TX queue.
+	 * Other fields are already filled correctly.
+	 */
+	wmb();
+	flags = TXFLAG_OWN | TXFLAG_INT;
+	/*
+	 * Set checksum flags while not tso
+	 */
+	if (jme_tx_tso(skb, &txdesc->desc1.mss, &flags))
+		jme_tx_csum(jme, skb, &flags);
+	jme_tx_vlan(skb, &txdesc->desc1.vlan, &flags);
+	txdesc->desc1.flags = flags;
+	/*
+	 * Set tx buffer info after telling NIC to send
+	 * For better tx_clean timing
+	 */
+	wmb();
+	txbi->nr_desc = skb_shinfo(skb)->nr_frags + 2;
+	txbi->skb = skb;
+	txbi->len = skb->len;
+	txbi->start_xmit = jiffies;
+	if (!txbi->start_xmit)
+		txbi->start_xmit = (0UL-1);
+
+	return 0;
+}
+
+static void
+jme_stop_queue_if_full(struct jme_adapter *jme)
+{
+	struct jme_ring *txring = jme->txring;
+	struct jme_buffer_info *txbi = txring->bufinf;
+	int idx = atomic_read(&txring->next_to_clean);
+
+	txbi += idx;
+
+	smp_wmb();
+	if (unlikely(atomic_read(&txring->nr_free) < (MAX_SKB_FRAGS+2))) {
+		netif_stop_queue(jme->dev);
+		msg_tx_queued(jme, "TX Queue Paused.\n");
+		smp_wmb();
+		if (atomic_read(&txring->nr_free)
+			>= (jme->tx_wake_threshold)) {
+			netif_wake_queue(jme->dev);
+			msg_tx_queued(jme, "TX Queue Fast Waked.\n");
+		}
+	}
+
+	if (unlikely(txbi->start_xmit &&
+			(jiffies - txbi->start_xmit) >= TX_TIMEOUT &&
+			txbi->skb)) {
+		netif_stop_queue(jme->dev);
+		msg_tx_queued(jme, "TX Queue Stopped %d@%lu.\n", idx, jiffies);
+	}
+}
+
+/*
+ * This function is already protected by netif_tx_lock()
+ */
+
+static int
+jme_start_xmit(struct sk_buff *skb, struct net_device *netdev)
+{
+	struct jme_adapter *jme = netdev_priv(netdev);
+	int idx;
+
+	if (unlikely(jme_expand_header(jme, skb))) {
+		++(NET_STAT(jme).tx_dropped);
+		return NETDEV_TX_OK;
+	}
+
+	idx = jme_alloc_txdesc(jme, skb);
+
+	if (unlikely(idx < 0)) {
+		netif_stop_queue(netdev);
+		msg_tx_err(jme, "BUG! Tx ring full when queue awake!\n");
+
+		return NETDEV_TX_BUSY;
+	}
+
+	jme_map_tx_skb(jme, skb, idx);
+	jme_fill_first_tx_desc(jme, skb, idx);
+
+	jwrite32(jme, JME_TXCS, jme->reg_txcs |
+				TXCS_SELECT_QUEUE0 |
+				TXCS_QUEUE0S |
+				TXCS_ENABLE);
+	netdev->trans_start = jiffies;
+
+	tx_dbg(jme, "xmit: %d+%d@%lu\n", idx,
+			skb_shinfo(skb)->nr_frags + 2,
+			jiffies);
+	jme_stop_queue_if_full(jme);
+
+	return NETDEV_TX_OK;
+}
+
+static int
+jme_set_macaddr(struct net_device *netdev, void *p)
+{
+	struct jme_adapter *jme = netdev_priv(netdev);
+	struct sockaddr *addr = p;
+	u32 val;
+
+	if (netif_running(netdev))
+		return -EBUSY;
+
+	spin_lock_bh(&jme->macaddr_lock);
+	memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len);
+
+	val = (addr->sa_data[3] & 0xff) << 24 |
+	      (addr->sa_data[2] & 0xff) << 16 |
+	      (addr->sa_data[1] & 0xff) <<  8 |
+	      (addr->sa_data[0] & 0xff);
+	jwrite32(jme, JME_RXUMA_LO, val);
+	val = (addr->sa_data[5] & 0xff) << 8 |
+	      (addr->sa_data[4] & 0xff);
+	jwrite32(jme, JME_RXUMA_HI, val);
+	spin_unlock_bh(&jme->macaddr_lock);
+
+	return 0;
+}
+
+static void
+jme_set_multi(struct net_device *netdev)
+{
+	struct jme_adapter *jme = netdev_priv(netdev);
+	u32 mc_hash[2] = {};
+	int i;
+
+	spin_lock_bh(&jme->rxmcs_lock);
+
+	jme->reg_rxmcs |= RXMCS_BRDFRAME | RXMCS_UNIFRAME;
+
+	if (netdev->flags & IFF_PROMISC) {
+		jme->reg_rxmcs |= RXMCS_ALLFRAME;
+	} else if (netdev->flags & IFF_ALLMULTI) {
+		jme->reg_rxmcs |= RXMCS_ALLMULFRAME;
+	} else if (netdev->flags & IFF_MULTICAST) {
+		struct dev_mc_list *mclist;
+		int bit_nr;
+
+		jme->reg_rxmcs |= RXMCS_MULFRAME | RXMCS_MULFILTERED;
+		for (i = 0, mclist = netdev->mc_list;
+			mclist && i < netdev->mc_count;
+			++i, mclist = mclist->next) {
+
+			bit_nr = ether_crc(ETH_ALEN, mclist->dmi_addr) & 0x3F;
+			mc_hash[bit_nr >> 5] |= 1 << (bit_nr & 0x1F);
+		}
+
+		jwrite32(jme, JME_RXMCHT_LO, mc_hash[0]);
+		jwrite32(jme, JME_RXMCHT_HI, mc_hash[1]);
+	}
+
+	wmb();
+	jwrite32(jme, JME_RXMCS, jme->reg_rxmcs);
+
+	spin_unlock_bh(&jme->rxmcs_lock);
+}
+
+static int
+jme_change_mtu(struct net_device *netdev, int new_mtu)
+{
+	struct jme_adapter *jme = netdev_priv(netdev);
+
+	if (new_mtu == jme->old_mtu)
+		return 0;
+
+	if (((new_mtu + ETH_HLEN) > MAX_ETHERNET_JUMBO_PACKET_SIZE) ||
+		((new_mtu) < IPV6_MIN_MTU))
+		return -EINVAL;
+
+	if (new_mtu > 4000) {
+		jme->reg_rxcs &= ~RXCS_FIFOTHNP;
+		jme->reg_rxcs |= RXCS_FIFOTHNP_64QW;
+		jme_restart_rx_engine(jme);
+	} else {
+		jme->reg_rxcs &= ~RXCS_FIFOTHNP;
+		jme->reg_rxcs |= RXCS_FIFOTHNP_128QW;
+		jme_restart_rx_engine(jme);
+	}
+
+	if (new_mtu > 1900) {
+		netdev->features &= ~(NETIF_F_HW_CSUM |
+				NETIF_F_TSO |
+				NETIF_F_TSO6);
+	} else {
+		if (test_bit(JME_FLAG_TXCSUM, &jme->flags))
+			netdev->features |= NETIF_F_HW_CSUM;
+		if (test_bit(JME_FLAG_TSO, &jme->flags))
+			netdev->features |= NETIF_F_TSO | NETIF_F_TSO6;
+	}
+
+	netdev->mtu = new_mtu;
+	jme_reset_link(jme);
+
+	return 0;
+}
+
+static void
+jme_tx_timeout(struct net_device *netdev)
+{
+	struct jme_adapter *jme = netdev_priv(netdev);
+
+	jme->phylink = 0;
+	jme_reset_phy_processor(jme);
+	if (test_bit(JME_FLAG_SSET, &jme->flags))
+		jme_set_settings(netdev, &jme->old_ecmd);
+
+	/*
+	 * Force to Reset the link again
+	 */
+	jme_reset_link(jme);
+}
+
+static void
+jme_vlan_rx_register(struct net_device *netdev, struct vlan_group *grp)
+{
+	struct jme_adapter *jme = netdev_priv(netdev);
+
+	jme->vlgrp = grp;
+}
+
+static void
+jme_get_drvinfo(struct net_device *netdev,
+		     struct ethtool_drvinfo *info)
+{
+	struct jme_adapter *jme = netdev_priv(netdev);
+
+	strcpy(info->driver, DRV_NAME);
+	strcpy(info->version, DRV_VERSION);
+	strcpy(info->bus_info, pci_name(jme->pdev));
+}
+
+static int
+jme_get_regs_len(struct net_device *netdev)
+{
+	return JME_REG_LEN;
+}
+
+static void
+mmapio_memcpy(struct jme_adapter *jme, u32 *p, u32 reg, int len)
+{
+	int i;
+
+	for (i = 0 ; i < len ; i += 4)
+		p[i >> 2] = jread32(jme, reg + i);
+}
+
+static void
+mdio_memcpy(struct jme_adapter *jme, u32 *p, int reg_nr)
+{
+	int i;
+	u16 *p16 = (u16 *)p;
+
+	for (i = 0 ; i < reg_nr ; ++i)
+		p16[i] = jme_mdio_read(jme->dev, jme->mii_if.phy_id, i);
+}
+
+static void
+jme_get_regs(struct net_device *netdev, struct ethtool_regs *regs, void *p)
+{
+	struct jme_adapter *jme = netdev_priv(netdev);
+	u32 *p32 = (u32 *)p;
+
+	memset(p, 0xFF, JME_REG_LEN);
+
+	regs->version = 1;
+	mmapio_memcpy(jme, p32, JME_MAC, JME_MAC_LEN);
+
+	p32 += 0x100 >> 2;
+	mmapio_memcpy(jme, p32, JME_PHY, JME_PHY_LEN);
+
+	p32 += 0x100 >> 2;
+	mmapio_memcpy(jme, p32, JME_MISC, JME_MISC_LEN);
+
+	p32 += 0x100 >> 2;
+	mmapio_memcpy(jme, p32, JME_RSS, JME_RSS_LEN);
+
+	p32 += 0x100 >> 2;
+	mdio_memcpy(jme, p32, JME_PHY_REG_NR);
+}
+
+static int
+jme_get_coalesce(struct net_device *netdev, struct ethtool_coalesce *ecmd)
+{
+	struct jme_adapter *jme = netdev_priv(netdev);
+
+	ecmd->tx_coalesce_usecs = PCC_TX_TO;
+	ecmd->tx_max_coalesced_frames = PCC_TX_CNT;
+
+	if (test_bit(JME_FLAG_POLL, &jme->flags)) {
+		ecmd->use_adaptive_rx_coalesce = false;
+		ecmd->rx_coalesce_usecs = 0;
+		ecmd->rx_max_coalesced_frames = 0;
+		return 0;
+	}
+
+	ecmd->use_adaptive_rx_coalesce = true;
+
+	switch (jme->dpi.cur) {
+	case PCC_P1:
+		ecmd->rx_coalesce_usecs = PCC_P1_TO;
+		ecmd->rx_max_coalesced_frames = PCC_P1_CNT;
+		break;
+	case PCC_P2:
+		ecmd->rx_coalesce_usecs = PCC_P2_TO;
+		ecmd->rx_max_coalesced_frames = PCC_P2_CNT;
+		break;
+	case PCC_P3:
+		ecmd->rx_coalesce_usecs = PCC_P3_TO;
+		ecmd->rx_max_coalesced_frames = PCC_P3_CNT;
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int
+jme_set_coalesce(struct net_device *netdev, struct ethtool_coalesce *ecmd)
+{
+	struct jme_adapter *jme = netdev_priv(netdev);
+	struct dynpcc_info *dpi = &(jme->dpi);
+
+	if (netif_running(netdev))
+		return -EBUSY;
+
+	if (ecmd->use_adaptive_rx_coalesce
+	&& test_bit(JME_FLAG_POLL, &jme->flags)) {
+		clear_bit(JME_FLAG_POLL, &jme->flags);
+		jme->jme_rx = netif_rx;
+		jme->jme_vlan_rx = vlan_hwaccel_rx;
+		dpi->cur		= PCC_P1;
+		dpi->attempt		= PCC_P1;
+		dpi->cnt		= 0;
+		jme_set_rx_pcc(jme, PCC_P1);
+		jme_interrupt_mode(jme);
+	} else if (!(ecmd->use_adaptive_rx_coalesce)
+	&& !(test_bit(JME_FLAG_POLL, &jme->flags))) {
+		set_bit(JME_FLAG_POLL, &jme->flags);
+		jme->jme_rx = netif_receive_skb;
+		jme->jme_vlan_rx = vlan_hwaccel_receive_skb;
+		jme_interrupt_mode(jme);
+	}
+
+	return 0;
+}
+
+static void
+jme_get_pauseparam(struct net_device *netdev,
+			struct ethtool_pauseparam *ecmd)
+{
+	struct jme_adapter *jme = netdev_priv(netdev);
+	u32 val;
+
+	ecmd->tx_pause = (jme->reg_txpfc & TXPFC_PF_EN) != 0;
+	ecmd->rx_pause = (jme->reg_rxmcs & RXMCS_FLOWCTRL) != 0;
+
+	spin_lock_bh(&jme->phy_lock);
+	val = jme_mdio_read(jme->dev, jme->mii_if.phy_id, MII_ADVERTISE);
+	spin_unlock_bh(&jme->phy_lock);
+
+	ecmd->autoneg =
+		(val & (ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM)) != 0;
+}
+
+static int
+jme_set_pauseparam(struct net_device *netdev,
+			struct ethtool_pauseparam *ecmd)
+{
+	struct jme_adapter *jme = netdev_priv(netdev);
+	u32 val;
+
+	if (((jme->reg_txpfc & TXPFC_PF_EN) != 0) ^
+		(ecmd->tx_pause != 0)) {
+
+		if (ecmd->tx_pause)
+			jme->reg_txpfc |= TXPFC_PF_EN;
+		else
+			jme->reg_txpfc &= ~TXPFC_PF_EN;
+
+		jwrite32(jme, JME_TXPFC, jme->reg_txpfc);
+	}
+
+	spin_lock_bh(&jme->rxmcs_lock);
+	if (((jme->reg_rxmcs & RXMCS_FLOWCTRL) != 0) ^
+		(ecmd->rx_pause != 0)) {
+
+		if (ecmd->rx_pause)
+			jme->reg_rxmcs |= RXMCS_FLOWCTRL;
+		else
+			jme->reg_rxmcs &= ~RXMCS_FLOWCTRL;
+
+		jwrite32(jme, JME_RXMCS, jme->reg_rxmcs);
+	}
+	spin_unlock_bh(&jme->rxmcs_lock);
+
+	spin_lock_bh(&jme->phy_lock);
+	val = jme_mdio_read(jme->dev, jme->mii_if.phy_id, MII_ADVERTISE);
+	if (((val & (ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM)) != 0) ^
+		(ecmd->autoneg != 0)) {
+
+		if (ecmd->autoneg)
+			val |= (ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM);
+		else
+			val &= ~(ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM);
+
+		jme_mdio_write(jme->dev, jme->mii_if.phy_id,
+				MII_ADVERTISE, val);
+	}
+	spin_unlock_bh(&jme->phy_lock);
+
+	return 0;
+}
+
+static void
+jme_get_wol(struct net_device *netdev,
+		struct ethtool_wolinfo *wol)
+{
+	struct jme_adapter *jme = netdev_priv(netdev);
+
+	wol->supported = WAKE_MAGIC | WAKE_PHY;
+
+	wol->wolopts = 0;
+
+	if (jme->reg_pmcs & (PMCS_LFEN | PMCS_LREN))
+		wol->wolopts |= WAKE_PHY;
+
+	if (jme->reg_pmcs & PMCS_MFEN)
+		wol->wolopts |= WAKE_MAGIC;
+
+}
+
+static int
+jme_set_wol(struct net_device *netdev,
+		struct ethtool_wolinfo *wol)
+{
+	struct jme_adapter *jme = netdev_priv(netdev);
+
+	if (wol->wolopts & (WAKE_MAGICSECURE |
+				WAKE_UCAST |
+				WAKE_MCAST |
+				WAKE_BCAST |
+				WAKE_ARP))
+		return -EOPNOTSUPP;
+
+	jme->reg_pmcs = 0;
+
+	if (wol->wolopts & WAKE_PHY)
+		jme->reg_pmcs |= PMCS_LFEN | PMCS_LREN;
+
+	if (wol->wolopts & WAKE_MAGIC)
+		jme->reg_pmcs |= PMCS_MFEN;
+
+	jwrite32(jme, JME_PMCS, jme->reg_pmcs);
+
+	return 0;
+}
+
+static int
+jme_get_settings(struct net_device *netdev,
+		     struct ethtool_cmd *ecmd)
+{
+	struct jme_adapter *jme = netdev_priv(netdev);
+	int rc;
+
+	spin_lock_bh(&jme->phy_lock);
+	rc = mii_ethtool_gset(&(jme->mii_if), ecmd);
+	spin_unlock_bh(&jme->phy_lock);
+	return rc;
+}
+
+static int
+jme_set_settings(struct net_device *netdev,
+		     struct ethtool_cmd *ecmd)
+{
+	struct jme_adapter *jme = netdev_priv(netdev);
+	int rc, fdc = 0;
+
+	if (ecmd->speed == SPEED_1000 && ecmd->autoneg != AUTONEG_ENABLE)
+		return -EINVAL;
+
+	if (jme->mii_if.force_media &&
+	ecmd->autoneg != AUTONEG_ENABLE &&
+	(jme->mii_if.full_duplex != ecmd->duplex))
+		fdc = 1;
+
+	spin_lock_bh(&jme->phy_lock);
+	rc = mii_ethtool_sset(&(jme->mii_if), ecmd);
+	spin_unlock_bh(&jme->phy_lock);
+
+	if (!rc && fdc)
+		jme_reset_link(jme);
+
+	if (!rc) {
+		set_bit(JME_FLAG_SSET, &jme->flags);
+		jme->old_ecmd = *ecmd;
+	}
+
+	return rc;
+}
+
+static u32
+jme_get_link(struct net_device *netdev)
+{
+	struct jme_adapter *jme = netdev_priv(netdev);
+	return jread32(jme, JME_PHY_LINK) & PHY_LINK_UP;
+}
+
+static u32
+jme_get_msglevel(struct net_device *netdev)
+{
+	struct jme_adapter *jme = netdev_priv(netdev);
+	return jme->msg_enable;
+}
+
+static void
+jme_set_msglevel(struct net_device *netdev, u32 value)
+{
+	struct jme_adapter *jme = netdev_priv(netdev);
+	jme->msg_enable = value;
+}
+
+static u32
+jme_get_rx_csum(struct net_device *netdev)
+{
+	struct jme_adapter *jme = netdev_priv(netdev);
+	return jme->reg_rxmcs & RXMCS_CHECKSUM;
+}
+
+static int
+jme_set_rx_csum(struct net_device *netdev, u32 on)
+{
+	struct jme_adapter *jme = netdev_priv(netdev);
+
+	spin_lock_bh(&jme->rxmcs_lock);
+	if (on)
+		jme->reg_rxmcs |= RXMCS_CHECKSUM;
+	else
+		jme->reg_rxmcs &= ~RXMCS_CHECKSUM;
+	jwrite32(jme, JME_RXMCS, jme->reg_rxmcs);
+	spin_unlock_bh(&jme->rxmcs_lock);
+
+	return 0;
+}
+
+static int
+jme_set_tx_csum(struct net_device *netdev, u32 on)
+{
+	struct jme_adapter *jme = netdev_priv(netdev);
+
+	if (on) {
+		set_bit(JME_FLAG_TXCSUM, &jme->flags);
+		if (netdev->mtu <= 1900)
+			netdev->features |= NETIF_F_HW_CSUM;
+	} else {
+		clear_bit(JME_FLAG_TXCSUM, &jme->flags);
+		netdev->features &= ~NETIF_F_HW_CSUM;
+	}
+
+	return 0;
+}
+
+static int
+jme_set_tso(struct net_device *netdev, u32 on)
+{
+	struct jme_adapter *jme = netdev_priv(netdev);
+
+	if (on) {
+		set_bit(JME_FLAG_TSO, &jme->flags);
+		if (netdev->mtu <= 1900)
+			netdev->features |= NETIF_F_TSO | NETIF_F_TSO6;
+	} else {
+		clear_bit(JME_FLAG_TSO, &jme->flags);
+		netdev->features &= ~(NETIF_F_TSO | NETIF_F_TSO6);
+	}
+
+	return 0;
+}
+
+static int
+jme_nway_reset(struct net_device *netdev)
+{
+	struct jme_adapter *jme = netdev_priv(netdev);
+	jme_restart_an(jme);
+	return 0;
+}
+
+static u8
+jme_smb_read(struct jme_adapter *jme, unsigned int addr)
+{
+	u32 val;
+	int to;
+
+	val = jread32(jme, JME_SMBCSR);
+	to = JME_SMB_BUSY_TIMEOUT;
+	while ((val & SMBCSR_BUSY) && --to) {
+		msleep(1);
+		val = jread32(jme, JME_SMBCSR);
+	}
+	if (!to) {
+		msg_hw(jme, "SMB Bus Busy.\n");
+		return 0xFF;
+	}
+
+	jwrite32(jme, JME_SMBINTF,
+		((addr << SMBINTF_HWADDR_SHIFT) & SMBINTF_HWADDR) |
+		SMBINTF_HWRWN_READ |
+		SMBINTF_HWCMD);
+
+	val = jread32(jme, JME_SMBINTF);
+	to = JME_SMB_BUSY_TIMEOUT;
+	while ((val & SMBINTF_HWCMD) && --to) {
+		msleep(1);
+		val = jread32(jme, JME_SMBINTF);
+	}
+	if (!to) {
+		msg_hw(jme, "SMB Bus Busy.\n");
+		return 0xFF;
+	}
+
+	return (val & SMBINTF_HWDATR) >> SMBINTF_HWDATR_SHIFT;
+}
+
+static void
+jme_smb_write(struct jme_adapter *jme, unsigned int addr, u8 data)
+{
+	u32 val;
+	int to;
+
+	val = jread32(jme, JME_SMBCSR);
+	to = JME_SMB_BUSY_TIMEOUT;
+	while ((val & SMBCSR_BUSY) && --to) {
+		msleep(1);
+		val = jread32(jme, JME_SMBCSR);
+	}
+	if (!to) {
+		msg_hw(jme, "SMB Bus Busy.\n");
+		return;
+	}
+
+	jwrite32(jme, JME_SMBINTF,
+		((data << SMBINTF_HWDATW_SHIFT) & SMBINTF_HWDATW) |
+		((addr << SMBINTF_HWADDR_SHIFT) & SMBINTF_HWADDR) |
+		SMBINTF_HWRWN_WRITE |
+		SMBINTF_HWCMD);
+
+	val = jread32(jme, JME_SMBINTF);
+	to = JME_SMB_BUSY_TIMEOUT;
+	while ((val & SMBINTF_HWCMD) && --to) {
+		msleep(1);
+		val = jread32(jme, JME_SMBINTF);
+	}
+	if (!to) {
+		msg_hw(jme, "SMB Bus Busy.\n");
+		return;
+	}
+
+	mdelay(2);
+}
+
+static int
+jme_get_eeprom_len(struct net_device *netdev)
+{
+	struct jme_adapter *jme = netdev_priv(netdev);
+	u32 val;
+	val = jread32(jme, JME_SMBCSR);
+	return (val & SMBCSR_EEPROMD) ? JME_SMB_LEN : 0;
+}
+
+static int
+jme_get_eeprom(struct net_device *netdev,
+		struct ethtool_eeprom *eeprom, u8 *data)
+{
+	struct jme_adapter *jme = netdev_priv(netdev);
+	int i, offset = eeprom->offset, len = eeprom->len;
+
+	/*
+	 * ethtool will check the boundary for us
+	 */
+	eeprom->magic = JME_EEPROM_MAGIC;
+	for (i = 0 ; i < len ; ++i)
+		data[i] = jme_smb_read(jme, i + offset);
+
+	return 0;
+}
+
+static int
+jme_set_eeprom(struct net_device *netdev,
+		struct ethtool_eeprom *eeprom, u8 *data)
+{
+	struct jme_adapter *jme = netdev_priv(netdev);
+	int i, offset = eeprom->offset, len = eeprom->len;
+
+	if (eeprom->magic != JME_EEPROM_MAGIC)
+		return -EINVAL;
+
+	/*
+	 * ethtool will check the boundary for us
+	 */
+	for (i = 0 ; i < len ; ++i)
+		jme_smb_write(jme, i + offset, data[i]);
+
+	return 0;
+}
+
+static const struct ethtool_ops jme_ethtool_ops = {
+	.get_drvinfo            = jme_get_drvinfo,
+	.get_regs_len		= jme_get_regs_len,
+	.get_regs		= jme_get_regs,
+	.get_coalesce		= jme_get_coalesce,
+	.set_coalesce		= jme_set_coalesce,
+	.get_pauseparam		= jme_get_pauseparam,
+	.set_pauseparam		= jme_set_pauseparam,
+	.get_wol		= jme_get_wol,
+	.set_wol		= jme_set_wol,
+	.get_settings		= jme_get_settings,
+	.set_settings		= jme_set_settings,
+	.get_link		= jme_get_link,
+	.get_msglevel           = jme_get_msglevel,
+	.set_msglevel           = jme_set_msglevel,
+	.get_rx_csum		= jme_get_rx_csum,
+	.set_rx_csum		= jme_set_rx_csum,
+	.set_tx_csum		= jme_set_tx_csum,
+	.set_tso		= jme_set_tso,
+	.set_sg			= ethtool_op_set_sg,
+	.nway_reset             = jme_nway_reset,
+	.get_eeprom_len		= jme_get_eeprom_len,
+	.get_eeprom		= jme_get_eeprom,
+	.set_eeprom		= jme_set_eeprom,
+};
+
+static int
+jme_pci_dma64(struct pci_dev *pdev)
+{
+	if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK))
+		if (!pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK))
+			return 1;
+
+	if (!pci_set_dma_mask(pdev, DMA_40BIT_MASK))
+		if (!pci_set_consistent_dma_mask(pdev, DMA_40BIT_MASK))
+			return 1;
+
+	if (!pci_set_dma_mask(pdev, DMA_32BIT_MASK))
+		if (!pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK))
+			return 0;
+
+	return -1;
+}
+
+static inline void
+jme_phy_init(struct jme_adapter *jme)
+{
+	u16 reg26;
+
+	reg26 = jme_mdio_read(jme->dev, jme->mii_if.phy_id, 26);
+	jme_mdio_write(jme->dev, jme->mii_if.phy_id, 26, reg26 | 0x1000);
+}
+
+static inline void
+jme_check_hw_ver(struct jme_adapter *jme)
+{
+	u32 chipmode;
+
+	chipmode = jread32(jme, JME_CHIPMODE);
+
+	jme->fpgaver = (chipmode & CM_FPGAVER_MASK) >> CM_FPGAVER_SHIFT;
+	jme->chiprev = (chipmode & CM_CHIPREV_MASK) >> CM_CHIPREV_SHIFT;
+}
+
+static int __devinit
+jme_init_one(struct pci_dev *pdev,
+	     const struct pci_device_id *ent)
+{
+	int rc = 0, using_dac, i;
+	struct net_device *netdev;
+	struct jme_adapter *jme;
+	u16 bmcr, bmsr;
+	u32 apmc;
+
+	/*
+	 * set up PCI device basics
+	 */
+	rc = pci_enable_device(pdev);
+	if (rc) {
+		jeprintk(pdev, "Cannot enable PCI device.\n");
+		goto err_out;
+	}
+
+	using_dac = jme_pci_dma64(pdev);
+	if (using_dac < 0) {
+		jeprintk(pdev, "Cannot set PCI DMA Mask.\n");
+		rc = -EIO;
+		goto err_out_disable_pdev;
+	}
+
+	if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) {
+		jeprintk(pdev, "No PCI resource region found.\n");
+		rc = -ENOMEM;
+		goto err_out_disable_pdev;
+	}
+
+	rc = pci_request_regions(pdev, DRV_NAME);
+	if (rc) {
+		jeprintk(pdev, "Cannot obtain PCI resource region.\n");
+		goto err_out_disable_pdev;
+	}
+
+	pci_set_master(pdev);
+
+	/*
+	 * alloc and init net device
+	 */
+	netdev = alloc_etherdev(sizeof(*jme));
+	if (!netdev) {
+		jeprintk(pdev, "Cannot allocate netdev structure.\n");
+		rc = -ENOMEM;
+		goto err_out_release_regions;
+	}
+	netdev->open			= jme_open;
+	netdev->stop			= jme_close;
+	netdev->hard_start_xmit		= jme_start_xmit;
+	netdev->set_mac_address		= jme_set_macaddr;
+	netdev->set_multicast_list	= jme_set_multi;
+	netdev->change_mtu		= jme_change_mtu;
+	netdev->ethtool_ops		= &jme_ethtool_ops;
+	netdev->tx_timeout		= jme_tx_timeout;
+	netdev->watchdog_timeo		= TX_TIMEOUT;
+	netdev->vlan_rx_register	= jme_vlan_rx_register;
+	NETDEV_GET_STATS(netdev, &jme_get_stats);
+	netdev->features		=	NETIF_F_HW_CSUM |
+						NETIF_F_SG |
+						NETIF_F_TSO |
+						NETIF_F_TSO6 |
+						NETIF_F_HW_VLAN_TX |
+						NETIF_F_HW_VLAN_RX;
+	if (using_dac)
+		netdev->features	|=	NETIF_F_HIGHDMA;
+
+	SET_NETDEV_DEV(netdev, &pdev->dev);
+	pci_set_drvdata(pdev, netdev);
+
+	/*
+	 * init adapter info
+	 */
+	jme = netdev_priv(netdev);
+	jme->pdev = pdev;
+	jme->dev = netdev;
+	jme->jme_rx = netif_rx;
+	jme->jme_vlan_rx = vlan_hwaccel_rx;
+	jme->old_mtu = netdev->mtu = 1500;
+	jme->phylink = 0;
+	jme->tx_ring_size = 1 << 10;
+	jme->tx_ring_mask = jme->tx_ring_size - 1;
+	jme->tx_wake_threshold = 1 << 9;
+	jme->rx_ring_size = 1 << 9;
+	jme->rx_ring_mask = jme->rx_ring_size - 1;
+	jme->msg_enable = JME_DEF_MSG_ENABLE;
+	jme->regs = ioremap(pci_resource_start(pdev, 0),
+			     pci_resource_len(pdev, 0));
+	if (!(jme->regs)) {
+		jeprintk(pdev, "Mapping PCI resource region error.\n");
+		rc = -ENOMEM;
+		goto err_out_free_netdev;
+	}
+	jme->shadow_regs = pci_alloc_consistent(pdev,
+						sizeof(u32) * SHADOW_REG_NR,
+						&(jme->shadow_dma));
+	if (!(jme->shadow_regs)) {
+		jeprintk(pdev, "Allocating shadow register mapping error.\n");
+		rc = -ENOMEM;
+		goto err_out_unmap;
+	}
+
+	if (no_pseudohp) {
+		apmc = jread32(jme, JME_APMC) & ~JME_APMC_PSEUDO_HP_EN;
+		jwrite32(jme, JME_APMC, apmc);
+	} else if (force_pseudohp) {
+		apmc = jread32(jme, JME_APMC) | JME_APMC_PSEUDO_HP_EN;
+		jwrite32(jme, JME_APMC, apmc);
+	}
+
+	NETIF_NAPI_SET(netdev, &jme->napi, jme_poll, jme->rx_ring_size >> 2)
+
+	spin_lock_init(&jme->phy_lock);
+	spin_lock_init(&jme->macaddr_lock);
+	spin_lock_init(&jme->rxmcs_lock);
+
+	atomic_set(&jme->link_changing, 1);
+	atomic_set(&jme->rx_cleaning, 1);
+	atomic_set(&jme->tx_cleaning, 1);
+	atomic_set(&jme->rx_empty, 1);
+
+	tasklet_init(&jme->pcc_task,
+		     &jme_pcc_tasklet,
+		     (unsigned long) jme);
+	tasklet_init(&jme->linkch_task,
+		     &jme_link_change_tasklet,
+		     (unsigned long) jme);
+	tasklet_init(&jme->txclean_task,
+		     &jme_tx_clean_tasklet,
+		     (unsigned long) jme);
+	tasklet_init(&jme->rxclean_task,
+		     &jme_rx_clean_tasklet,
+		     (unsigned long) jme);
+	tasklet_init(&jme->rxempty_task,
+		     &jme_rx_empty_tasklet,
+		     (unsigned long) jme);
+	tasklet_disable_nosync(&jme->txclean_task);
+	tasklet_disable_nosync(&jme->rxclean_task);
+	tasklet_disable_nosync(&jme->rxempty_task);
+	jme->dpi.cur = PCC_P1;
+
+	jme->reg_ghc = 0;
+	jme->reg_rxcs = RXCS_DEFAULT;
+	jme->reg_rxmcs = RXMCS_DEFAULT;
+	jme->reg_txpfc = 0;
+	jme->reg_pmcs = PMCS_MFEN;
+	set_bit(JME_FLAG_TXCSUM, &jme->flags);
+	set_bit(JME_FLAG_TSO, &jme->flags);
+
+	/*
+	 * Get Max Read Req Size from PCI Config Space
+	 */
+	pci_read_config_byte(pdev, PCI_DCSR_MRRS, &jme->mrrs);
+	jme->mrrs &= PCI_DCSR_MRRS_MASK;
+	switch (jme->mrrs) {
+	case MRRS_128B:
+		jme->reg_txcs = TXCS_DEFAULT | TXCS_DMASIZE_128B;
+		break;
+	case MRRS_256B:
+		jme->reg_txcs = TXCS_DEFAULT | TXCS_DMASIZE_256B;
+		break;
+	default:
+		jme->reg_txcs = TXCS_DEFAULT | TXCS_DMASIZE_512B;
+		break;
+	};
+
+	/*
+	 * Must check before reset_mac_processor
+	 */
+	jme_check_hw_ver(jme);
+	jme->mii_if.dev = netdev;
+	if (jme->fpgaver) {
+		jme->mii_if.phy_id = 0;
+		for (i = 1 ; i < 32 ; ++i) {
+			bmcr = jme_mdio_read(netdev, i, MII_BMCR);
+			bmsr = jme_mdio_read(netdev, i, MII_BMSR);
+			if (bmcr != 0xFFFFU && (bmcr != 0 || bmsr != 0)) {
+				jme->mii_if.phy_id = i;
+				break;
+			}
+		}
+
+		if (!jme->mii_if.phy_id) {
+			rc = -EIO;
+			jeprintk(pdev, "Can not find phy_id.\n");
+			 goto err_out_free_shadow;
+		}
+
+		jme->reg_ghc |= GHC_LINK_POLL;
+	} else {
+		jme->mii_if.phy_id = 1;
+	}
+	if (pdev->device == PCI_DEVICE_ID_JMICRON_JMC250)
+		jme->mii_if.supports_gmii = true;
+	else
+		jme->mii_if.supports_gmii = false;
+	jme->mii_if.mdio_read = jme_mdio_read;
+	jme->mii_if.mdio_write = jme_mdio_write;
+
+	jme_clear_pm(jme);
+	jme_set_phyfifoa(jme);
+	pci_read_config_byte(pdev, PCI_REVISION_ID, &jme->rev);
+	if (!jme->fpgaver)
+		jme_phy_init(jme);
+	jme_phy_off(jme);
+
+	/*
+	 * Reset MAC processor and reload EEPROM for MAC Address
+	 */
+	jme_reset_mac_processor(jme);
+	rc = jme_reload_eeprom(jme);
+	if (rc) {
+		jeprintk(pdev,
+			"Reload eeprom for reading MAC Address error.\n");
+		goto err_out_free_shadow;
+	}
+	jme_load_macaddr(netdev);
+
+	/*
+	 * Tell stack that we are not ready to work until open()
+	 */
+	netif_carrier_off(netdev);
+	netif_stop_queue(netdev);
+
+	/*
+	 * Register netdev
+	 */
+	rc = register_netdev(netdev);
+	if (rc) {
+		jeprintk(pdev, "Cannot register net device.\n");
+		goto err_out_free_shadow;
+	}
+
+	msg_probe(jme,
+		"JMC250 gigabit%s ver:%x rev:%x "
+		"macaddr:%02x:%02x:%02x:%02x:%02x:%02x\n",
+		(jme->fpgaver != 0) ? " (FPGA)" : "",
+		(jme->fpgaver != 0) ? jme->fpgaver : jme->chiprev,
+		jme->rev,
+		netdev->dev_addr[0],
+		netdev->dev_addr[1],
+		netdev->dev_addr[2],
+		netdev->dev_addr[3],
+		netdev->dev_addr[4],
+		netdev->dev_addr[5]);
+
+	return 0;
+
+err_out_free_shadow:
+	pci_free_consistent(pdev,
+			    sizeof(u32) * SHADOW_REG_NR,
+			    jme->shadow_regs,
+			    jme->shadow_dma);
+err_out_unmap:
+	iounmap(jme->regs);
+err_out_free_netdev:
+	pci_set_drvdata(pdev, NULL);
+	free_netdev(netdev);
+err_out_release_regions:
+	pci_release_regions(pdev);
+err_out_disable_pdev:
+	pci_disable_device(pdev);
+err_out:
+	return rc;
+}
+
+static void __devexit
+jme_remove_one(struct pci_dev *pdev)
+{
+	struct net_device *netdev = pci_get_drvdata(pdev);
+	struct jme_adapter *jme = netdev_priv(netdev);
+
+	unregister_netdev(netdev);
+	pci_free_consistent(pdev,
+			    sizeof(u32) * SHADOW_REG_NR,
+			    jme->shadow_regs,
+			    jme->shadow_dma);
+	iounmap(jme->regs);
+	pci_set_drvdata(pdev, NULL);
+	free_netdev(netdev);
+	pci_release_regions(pdev);
+	pci_disable_device(pdev);
+
+}
+
+#ifdef CONFIG_PM
+static int
+jme_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+	struct net_device *netdev = pci_get_drvdata(pdev);
+	struct jme_adapter *jme = netdev_priv(netdev);
+
+	atomic_dec(&jme->link_changing);
+
+	netif_device_detach(netdev);
+	netif_stop_queue(netdev);
+	jme_stop_irq(jme);
+
+	tasklet_disable(&jme->txclean_task);
+	tasklet_disable(&jme->rxclean_task);
+	tasklet_disable(&jme->rxempty_task);
+
+	jme_disable_shadow(jme);
+
+	if (netif_carrier_ok(netdev)) {
+		if (test_bit(JME_FLAG_POLL, &jme->flags))
+			jme_polling_mode(jme);
+
+		jme_stop_pcc_timer(jme);
+		jme_reset_ghc_speed(jme);
+		jme_disable_rx_engine(jme);
+		jme_disable_tx_engine(jme);
+		jme_reset_mac_processor(jme);
+		jme_free_rx_resources(jme);
+		jme_free_tx_resources(jme);
+		netif_carrier_off(netdev);
+		jme->phylink = 0;
+	}
+
+	tasklet_enable(&jme->txclean_task);
+	tasklet_hi_enable(&jme->rxclean_task);
+	tasklet_hi_enable(&jme->rxempty_task);
+
+	pci_save_state(pdev);
+	if (jme->reg_pmcs) {
+		jme_set_100m_half(jme);
+
+		if (jme->reg_pmcs & (PMCS_LFEN | PMCS_LREN))
+			jme_wait_link(jme);
+
+		jwrite32(jme, JME_PMCS, jme->reg_pmcs);
+
+		pci_enable_wake(pdev, PCI_D3cold, true);
+	} else {
+		jme_phy_off(jme);
+	}
+	pci_set_power_state(pdev, PCI_D3cold);
+
+	return 0;
+}
+
+static int
+jme_resume(struct pci_dev *pdev)
+{
+	struct net_device *netdev = pci_get_drvdata(pdev);
+	struct jme_adapter *jme = netdev_priv(netdev);
+
+	jme_clear_pm(jme);
+	pci_restore_state(pdev);
+
+	if (test_bit(JME_FLAG_SSET, &jme->flags))
+		jme_set_settings(netdev, &jme->old_ecmd);
+	else
+		jme_reset_phy_processor(jme);
+
+	jme_enable_shadow(jme);
+	jme_start_irq(jme);
+	netif_device_attach(netdev);
+
+	atomic_inc(&jme->link_changing);
+
+	jme_reset_link(jme);
+
+	return 0;
+}
+#endif
+
+static struct pci_device_id jme_pci_tbl[] = {
+	{ PCI_VDEVICE(JMICRON, PCI_DEVICE_ID_JMICRON_JMC250) },
+	{ PCI_VDEVICE(JMICRON, PCI_DEVICE_ID_JMICRON_JMC260) },
+	{ }
+};
+
+static struct pci_driver jme_driver = {
+	.name           = DRV_NAME,
+	.id_table       = jme_pci_tbl,
+	.probe          = jme_init_one,
+	.remove         = __devexit_p(jme_remove_one),
+#ifdef CONFIG_PM
+	.suspend        = jme_suspend,
+	.resume         = jme_resume,
+#endif /* CONFIG_PM */
+};
+
+static int __init
+jme_init_module(void)
+{
+	printk(KERN_INFO PFX "JMicron JMC250 gigabit ethernet "
+	       "driver version %s\n", DRV_VERSION);
+	return pci_register_driver(&jme_driver);
+}
+
+static void __exit
+jme_cleanup_module(void)
+{
+	pci_unregister_driver(&jme_driver);
+}
+
+module_init(jme_init_module);
+module_exit(jme_cleanup_module);
+
+MODULE_AUTHOR("Guo-Fu Tseng <cooldavid@cooldavid.org>");
+MODULE_DESCRIPTION("JMicron JMC2x0 PCI Express Ethernet driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
+MODULE_DEVICE_TABLE(pci, jme_pci_tbl);
+
diff --git a/drivers/net/jme.h b/drivers/net/jme.h
new file mode 100644
index 0000000..f863aee
--- /dev/null
+++ b/drivers/net/jme.h
@@ -0,0 +1,1229 @@
+/*
+ * JMicron JMC2x0 series PCIe Ethernet Linux Device Driver
+ *
+ * Copyright 2008 JMicron Technology Corporation
+ * http://www.jmicron.com/
+ *
+ * Author: Guo-Fu Tseng <cooldavid@cooldavid.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef __JME_H_INCLUDED__
+#define __JME_H_INCLUDEE__
+
+#define DRV_NAME	"jme"
+#define DRV_VERSION	"1.0.3"
+#define PFX		DRV_NAME ": "
+
+#define PCI_DEVICE_ID_JMICRON_JMC250	0x0250
+#define PCI_DEVICE_ID_JMICRON_JMC260	0x0260
+
+/*
+ * Message related definitions
+ */
+#define JME_DEF_MSG_ENABLE \
+	(NETIF_MSG_PROBE | \
+	NETIF_MSG_LINK | \
+	NETIF_MSG_RX_ERR | \
+	NETIF_MSG_TX_ERR | \
+	NETIF_MSG_HW)
+
+#define jeprintk(pdev, fmt, args...) \
+	printk(KERN_ERR PFX fmt, ## args)
+
+#ifdef TX_DEBUG
+#define tx_dbg(priv, fmt, args...) \
+	printk(KERN_DEBUG "%s: " fmt, (priv)->dev->name, ## args)
+#else
+#define tx_dbg(priv, fmt, args...)
+#endif
+
+#define jme_msg(msglvl, type, priv, fmt, args...) \
+	if (netif_msg_##type(priv)) \
+		printk(msglvl "%s: " fmt, (priv)->dev->name, ## args)
+
+#define msg_probe(priv, fmt, args...) \
+	jme_msg(KERN_INFO, probe, priv, fmt, ## args)
+
+#define msg_link(priv, fmt, args...) \
+	jme_msg(KERN_INFO, link, priv, fmt, ## args)
+
+#define msg_intr(priv, fmt, args...) \
+	jme_msg(KERN_INFO, intr, priv, fmt, ## args)
+
+#define msg_rx_err(priv, fmt, args...) \
+	jme_msg(KERN_ERR, rx_err, priv, fmt, ## args)
+
+#define msg_rx_status(priv, fmt, args...) \
+	jme_msg(KERN_INFO, rx_status, priv, fmt, ## args)
+
+#define msg_tx_err(priv, fmt, args...) \
+	jme_msg(KERN_ERR, tx_err, priv, fmt, ## args)
+
+#define msg_tx_done(priv, fmt, args...) \
+	jme_msg(KERN_INFO, tx_done, priv, fmt, ## args)
+
+#define msg_tx_queued(priv, fmt, args...) \
+	jme_msg(KERN_INFO, tx_queued, priv, fmt, ## args)
+
+#define msg_hw(priv, fmt, args...) \
+	jme_msg(KERN_ERR, hw, priv, fmt, ## args)
+
+/*
+ * Extra PCI Configuration space interface
+ */
+#define PCI_DCSR_MRRS		0x59
+#define PCI_DCSR_MRRS_MASK	0x70
+
+enum pci_dcsr_mrrs_vals {
+	MRRS_128B	= 0x00,
+	MRRS_256B	= 0x10,
+	MRRS_512B	= 0x20,
+	MRRS_1024B	= 0x30,
+	MRRS_2048B	= 0x40,
+	MRRS_4096B	= 0x50,
+};
+
+#define PCI_SPI			0xB0
+
+enum pci_spi_bits {
+	SPI_EN		= 0x10,
+	SPI_MISO	= 0x08,
+	SPI_MOSI	= 0x04,
+	SPI_SCLK	= 0x02,
+	SPI_CS		= 0x01,
+};
+
+struct jme_spi_op {
+	void __user *uwbuf;
+	void __user *urbuf;
+	__u8	wn;	/* Number of write actions */
+	__u8	rn;	/* Number of read actions */
+	__u8	bitn;	/* Number of bits per action */
+	__u8	spd;	/* The maxim acceptable speed of controller, in MHz.*/
+	__u8	mode;	/* CPOL, CPHA, and Duplex mode of SPI */
+
+	/* Internal use only */
+	u8	*kwbuf;
+	u8	*krbuf;
+	u8	sr;
+	u16	halfclk; /* Half of clock cycle calculated from spd, in ns */
+};
+
+enum jme_spi_op_bits {
+	SPI_MODE_CPHA	= 0x01,
+	SPI_MODE_CPOL	= 0x02,
+	SPI_MODE_DUP	= 0x80,
+};
+
+#define HALF_US 500	/* 500 ns */
+#define JMESPIIOCTL	SIOCDEVPRIVATE
+
+/*
+ * Dynamic(adaptive)/Static PCC values
+ */
+enum dynamic_pcc_values {
+	PCC_OFF		= 0,
+	PCC_P1		= 1,
+	PCC_P2		= 2,
+	PCC_P3		= 3,
+
+	PCC_OFF_TO	= 0,
+	PCC_P1_TO	= 1,
+	PCC_P2_TO	= 64,
+	PCC_P3_TO	= 128,
+
+	PCC_OFF_CNT	= 0,
+	PCC_P1_CNT	= 1,
+	PCC_P2_CNT	= 16,
+	PCC_P3_CNT	= 32,
+};
+struct dynpcc_info {
+	unsigned long	last_bytes;
+	unsigned long	last_pkts;
+	unsigned long	intr_cnt;
+	unsigned char	cur;
+	unsigned char	attempt;
+	unsigned char	cnt;
+};
+#define PCC_INTERVAL_US	100000
+#define PCC_INTERVAL (HZ / (1000000 / PCC_INTERVAL_US))
+#define PCC_P3_THRESHOLD (2 * 1024 * 1024)
+#define PCC_P2_THRESHOLD 800
+#define PCC_INTR_THRESHOLD 800
+#define PCC_TX_TO 1000
+#define PCC_TX_CNT 8
+
+/*
+ * TX/RX Descriptors
+ *
+ * TX/RX Ring DESC Count Must be multiple of 16 and <= 1024
+ */
+#define RING_DESC_ALIGN		16	/* Descriptor alignment */
+#define TX_DESC_SIZE		16
+#define TX_RING_NR		8
+#define TX_RING_ALLOC_SIZE(s)	((s * TX_DESC_SIZE) + RING_DESC_ALIGN)
+
+struct txdesc {
+	union {
+		__u8	all[16];
+		__le32	dw[4];
+		struct {
+			/* DW0 */
+			__le16	vlan;
+			__u8	rsv1;
+			__u8	flags;
+
+			/* DW1 */
+			__le16	datalen;
+			__le16	mss;
+
+			/* DW2 */
+			__le16	pktsize;
+			__le16	rsv2;
+
+			/* DW3 */
+			__le32	bufaddr;
+		} desc1;
+		struct {
+			/* DW0 */
+			__le16	rsv1;
+			__u8	rsv2;
+			__u8	flags;
+
+			/* DW1 */
+			__le16	datalen;
+			__le16	rsv3;
+
+			/* DW2 */
+			__le32	bufaddrh;
+
+			/* DW3 */
+			__le32	bufaddrl;
+		} desc2;
+		struct {
+			/* DW0 */
+			__u8	ehdrsz;
+			__u8	rsv1;
+			__u8	rsv2;
+			__u8	flags;
+
+			/* DW1 */
+			__le16	trycnt;
+			__le16	segcnt;
+
+			/* DW2 */
+			__le16	pktsz;
+			__le16	rsv3;
+
+			/* DW3 */
+			__le32	bufaddrl;
+		} descwb;
+	};
+};
+
+enum jme_txdesc_flags_bits {
+	TXFLAG_OWN	= 0x80,
+	TXFLAG_INT	= 0x40,
+	TXFLAG_64BIT	= 0x20,
+	TXFLAG_TCPCS	= 0x10,
+	TXFLAG_UDPCS	= 0x08,
+	TXFLAG_IPCS	= 0x04,
+	TXFLAG_LSEN	= 0x02,
+	TXFLAG_TAGON	= 0x01,
+};
+
+#define TXDESC_MSS_SHIFT	2
+enum jme_rxdescwb_flags_bits {
+	TXWBFLAG_OWN	= 0x80,
+	TXWBFLAG_INT	= 0x40,
+	TXWBFLAG_TMOUT	= 0x20,
+	TXWBFLAG_TRYOUT	= 0x10,
+	TXWBFLAG_COL	= 0x08,
+
+	TXWBFLAG_ALLERR	= TXWBFLAG_TMOUT |
+			  TXWBFLAG_TRYOUT |
+			  TXWBFLAG_COL,
+};
+
+#define RX_DESC_SIZE		16
+#define RX_RING_NR		4
+#define RX_RING_ALLOC_SIZE(s)	((s * RX_DESC_SIZE) + RING_DESC_ALIGN)
+#define RX_BUF_DMA_ALIGN	8
+#define RX_PREPAD_SIZE		10
+#define ETH_CRC_LEN		2
+#define RX_VLANHDR_LEN		2
+#define RX_EXTRA_LEN		(RX_PREPAD_SIZE + \
+				ETH_HLEN + \
+				ETH_CRC_LEN + \
+				RX_VLANHDR_LEN + \
+				RX_BUF_DMA_ALIGN)
+
+struct rxdesc {
+	union {
+		__u8	all[16];
+		__le32	dw[4];
+		struct {
+			/* DW0 */
+			__le16	rsv2;
+			__u8	rsv1;
+			__u8	flags;
+
+			/* DW1 */
+			__le16	datalen;
+			__le16	wbcpl;
+
+			/* DW2 */
+			__le32	bufaddrh;
+
+			/* DW3 */
+			__le32	bufaddrl;
+		} desc1;
+		struct {
+			/* DW0 */
+			__le16	vlan;
+			__le16	flags;
+
+			/* DW1 */
+			__le16	framesize;
+			__u8	errstat;
+			__u8	desccnt;
+
+			/* DW2 */
+			__le32	rsshash;
+
+			/* DW3 */
+			__u8	hashfun;
+			__u8	hashtype;
+			__le16	resrv;
+		} descwb;
+	};
+};
+
+enum jme_rxdesc_flags_bits {
+	RXFLAG_OWN	= 0x80,
+	RXFLAG_INT	= 0x40,
+	RXFLAG_64BIT	= 0x20,
+};
+
+enum jme_rxwbdesc_flags_bits {
+	RXWBFLAG_OWN		= 0x8000,
+	RXWBFLAG_INT		= 0x4000,
+	RXWBFLAG_MF		= 0x2000,
+	RXWBFLAG_64BIT		= 0x2000,
+	RXWBFLAG_TCPON		= 0x1000,
+	RXWBFLAG_UDPON		= 0x0800,
+	RXWBFLAG_IPCS		= 0x0400,
+	RXWBFLAG_TCPCS		= 0x0200,
+	RXWBFLAG_UDPCS		= 0x0100,
+	RXWBFLAG_TAGON		= 0x0080,
+	RXWBFLAG_IPV4		= 0x0040,
+	RXWBFLAG_IPV6		= 0x0020,
+	RXWBFLAG_PAUSE		= 0x0010,
+	RXWBFLAG_MAGIC		= 0x0008,
+	RXWBFLAG_WAKEUP		= 0x0004,
+	RXWBFLAG_DEST		= 0x0003,
+	RXWBFLAG_DEST_UNI	= 0x0001,
+	RXWBFLAG_DEST_MUL	= 0x0002,
+	RXWBFLAG_DEST_BRO	= 0x0003,
+};
+
+enum jme_rxwbdesc_desccnt_mask {
+	RXWBDCNT_WBCPL	= 0x80,
+	RXWBDCNT_DCNT	= 0x7F,
+};
+
+enum jme_rxwbdesc_errstat_bits {
+	RXWBERR_LIMIT	= 0x80,
+	RXWBERR_MIIER	= 0x40,
+	RXWBERR_NIBON	= 0x20,
+	RXWBERR_COLON	= 0x10,
+	RXWBERR_ABORT	= 0x08,
+	RXWBERR_SHORT	= 0x04,
+	RXWBERR_OVERUN	= 0x02,
+	RXWBERR_CRCERR	= 0x01,
+	RXWBERR_ALLERR	= 0xFF,
+};
+
+/*
+ * Buffer information corresponding to ring descriptors.
+ */
+struct jme_buffer_info {
+	struct sk_buff *skb;
+	dma_addr_t mapping;
+	int len;
+	int nr_desc;
+	unsigned long start_xmit;
+};
+
+/*
+ * The structure holding buffer information and ring descriptors all together.
+ */
+#define MAX_RING_DESC_NR	1024
+struct jme_ring {
+	void *alloc;		/* pointer to allocated memory */
+	void *desc;		/* pointer to ring memory  */
+	dma_addr_t dmaalloc;	/* phys address of ring alloc */
+	dma_addr_t dma;		/* phys address for ring dma */
+
+	/* Buffer information corresponding to each descriptor */
+	struct jme_buffer_info bufinf[MAX_RING_DESC_NR];
+
+	int next_to_use;
+	atomic_t next_to_clean;
+	atomic_t nr_free;
+};
+
+#define NET_STAT(priv) (priv->dev->stats)
+#define NETDEV_GET_STATS(netdev, fun_ptr)
+#define DECLARE_NET_DEVICE_STATS
+
+#define DECLARE_NAPI_STRUCT struct napi_struct napi;
+#define NETIF_NAPI_SET(dev, napis, pollfn, q) \
+	netif_napi_add(dev, napis, pollfn, q);
+#define JME_NAPI_HOLDER(holder) struct napi_struct *holder
+#define JME_NAPI_WEIGHT(w) int w
+#define JME_NAPI_WEIGHT_VAL(w) w
+#define JME_NAPI_WEIGHT_SET(w, r)
+#define JME_RX_COMPLETE(dev, napis) netif_rx_complete(dev, napis)
+#define JME_NAPI_ENABLE(priv) napi_enable(&priv->napi);
+#define JME_NAPI_DISABLE(priv) \
+	if (!napi_disable_pending(&priv->napi)) \
+		napi_disable(&priv->napi);
+#define JME_RX_SCHEDULE_PREP(priv) \
+	netif_rx_schedule_prep(priv->dev, &priv->napi)
+#define JME_RX_SCHEDULE(priv) \
+	__netif_rx_schedule(priv->dev, &priv->napi);
+
+/*
+ * Jmac Adapter Private data
+ */
+#define SHADOW_REG_NR 8
+struct jme_adapter {
+	struct pci_dev          *pdev;
+	struct net_device       *dev;
+	void __iomem            *regs;
+	dma_addr_t		shadow_dma;
+	u32			*shadow_regs;
+	struct mii_if_info	mii_if;
+	struct jme_ring		rxring[RX_RING_NR];
+	struct jme_ring		txring[TX_RING_NR];
+	spinlock_t		phy_lock;
+	spinlock_t		macaddr_lock;
+	spinlock_t		rxmcs_lock;
+	struct tasklet_struct	rxempty_task;
+	struct tasklet_struct	rxclean_task;
+	struct tasklet_struct	txclean_task;
+	struct tasklet_struct	linkch_task;
+	struct tasklet_struct	pcc_task;
+	unsigned long		flags;
+	u32			reg_txcs;
+	u32			reg_txpfc;
+	u32			reg_rxcs;
+	u32			reg_rxmcs;
+	u32			reg_ghc;
+	u32			reg_pmcs;
+	u32			phylink;
+	u32			tx_ring_size;
+	u32			tx_ring_mask;
+	u32			tx_wake_threshold;
+	u32			rx_ring_size;
+	u32			rx_ring_mask;
+	u8			mrrs;
+	unsigned int		fpgaver;
+	unsigned int		chiprev;
+	u8			rev;
+	u32			msg_enable;
+	struct ethtool_cmd	old_ecmd;
+	unsigned int		old_mtu;
+	struct vlan_group	*vlgrp;
+	struct dynpcc_info	dpi;
+	atomic_t		intr_sem;
+	atomic_t		link_changing;
+	atomic_t		tx_cleaning;
+	atomic_t		rx_cleaning;
+	atomic_t		rx_empty;
+	int			(*jme_rx)(struct sk_buff *skb);
+	int			(*jme_vlan_rx)(struct sk_buff *skb,
+					  struct vlan_group *grp,
+					  unsigned short vlan_tag);
+	DECLARE_NAPI_STRUCT
+	DECLARE_NET_DEVICE_STATS
+};
+
+enum shadow_reg_val {
+	SHADOW_IEVE = 0,
+};
+
+enum jme_flags_bits {
+	JME_FLAG_MSI		= 1,
+	JME_FLAG_SSET		= 2,
+	JME_FLAG_TXCSUM		= 3,
+	JME_FLAG_TSO		= 4,
+	JME_FLAG_POLL		= 5,
+	JME_FLAG_SHUTDOWN	= 6,
+};
+
+#define TX_TIMEOUT		(5 * HZ)
+#define JME_REG_LEN		0x500
+#define MAX_ETHERNET_JUMBO_PACKET_SIZE 9216
+
+static inline struct jme_adapter*
+jme_napi_priv(struct napi_struct *napi)
+{
+	struct jme_adapter *jme;
+	jme = container_of(napi, struct jme_adapter, napi);
+	return jme;
+}
+
+/*
+ * MMaped I/O Resters
+ */
+enum jme_iomap_offsets {
+	JME_MAC		= 0x0000,
+	JME_PHY		= 0x0400,
+	JME_MISC	= 0x0800,
+	JME_RSS		= 0x0C00,
+};
+
+enum jme_iomap_lens {
+	JME_MAC_LEN	= 0x80,
+	JME_PHY_LEN	= 0x58,
+	JME_MISC_LEN	= 0x98,
+	JME_RSS_LEN	= 0xFF,
+};
+
+enum jme_iomap_regs {
+	JME_TXCS	= JME_MAC | 0x00, /* Transmit Control and Status */
+	JME_TXDBA_LO	= JME_MAC | 0x04, /* Transmit Queue Desc Base Addr */
+	JME_TXDBA_HI	= JME_MAC | 0x08, /* Transmit Queue Desc Base Addr */
+	JME_TXQDC	= JME_MAC | 0x0C, /* Transmit Queue Desc Count */
+	JME_TXNDA	= JME_MAC | 0x10, /* Transmit Queue Next Desc Addr */
+	JME_TXMCS	= JME_MAC | 0x14, /* Transmit MAC Control Status */
+	JME_TXPFC	= JME_MAC | 0x18, /* Transmit Pause Frame Control */
+	JME_TXTRHD	= JME_MAC | 0x1C, /* Transmit Timer/Retry@Half-Dup */
+
+	JME_RXCS	= JME_MAC | 0x20, /* Receive Control and Status */
+	JME_RXDBA_LO	= JME_MAC | 0x24, /* Receive Queue Desc Base Addr */
+	JME_RXDBA_HI	= JME_MAC | 0x28, /* Receive Queue Desc Base Addr */
+	JME_RXQDC	= JME_MAC | 0x2C, /* Receive Queue Desc Count */
+	JME_RXNDA	= JME_MAC | 0x30, /* Receive Queue Next Desc Addr */
+	JME_RXMCS	= JME_MAC | 0x34, /* Receive MAC Control Status */
+	JME_RXUMA_LO	= JME_MAC | 0x38, /* Receive Unicast MAC Address */
+	JME_RXUMA_HI	= JME_MAC | 0x3C, /* Receive Unicast MAC Address */
+	JME_RXMCHT_LO	= JME_MAC | 0x40, /* Recv Multicast Addr HashTable */
+	JME_RXMCHT_HI	= JME_MAC | 0x44, /* Recv Multicast Addr HashTable */
+	JME_WFODP	= JME_MAC | 0x48, /* Wakeup Frame Output Data Port */
+	JME_WFOI	= JME_MAC | 0x4C, /* Wakeup Frame Output Interface */
+
+	JME_SMI		= JME_MAC | 0x50, /* Station Management Interface */
+	JME_GHC		= JME_MAC | 0x54, /* Global Host Control */
+	JME_PMCS	= JME_MAC | 0x60, /* Power Management Control/Stat */
+
+
+	JME_PHY_CS	= JME_PHY | 0x28, /* PHY Ctrl and Status Register */
+	JME_PHY_LINK	= JME_PHY | 0x30, /* PHY Link Status Register */
+	JME_SMBCSR	= JME_PHY | 0x40, /* SMB Control and Status */
+	JME_SMBINTF	= JME_PHY | 0x44, /* SMB Interface */
+
+
+	JME_TMCSR	= JME_MISC | 0x00, /* Timer Control/Status Register */
+	JME_GPREG0	= JME_MISC | 0x08, /* General purpose REG-0 */
+	JME_GPREG1	= JME_MISC | 0x0C, /* General purpose REG-1 */
+	JME_IEVE	= JME_MISC | 0x20, /* Interrupt Event Status */
+	JME_IREQ	= JME_MISC | 0x24, /* Intr Req Status(For Debug) */
+	JME_IENS	= JME_MISC | 0x28, /* Intr Enable - Setting Port */
+	JME_IENC	= JME_MISC | 0x2C, /* Interrupt Enable - Clear Port */
+	JME_PCCRX0	= JME_MISC | 0x30, /* PCC Control for RX Queue 0 */
+	JME_PCCTX	= JME_MISC | 0x40, /* PCC Control for TX Queues */
+	JME_CHIPMODE	= JME_MISC | 0x44, /* Identify FPGA Version */
+	JME_SHBA_HI	= JME_MISC | 0x48, /* Shadow Register Base HI */
+	JME_SHBA_LO	= JME_MISC | 0x4C, /* Shadow Register Base LO */
+	JME_TIMER1	= JME_MISC | 0x70, /* Timer1 */
+	JME_TIMER2	= JME_MISC | 0x74, /* Timer2 */
+	JME_APMC	= JME_MISC | 0x7C, /* Aggressive Power Mode Control */
+	JME_PCCSRX0	= JME_MISC | 0x80, /* PCC Status of RX0 */
+};
+
+/*
+ * TX Control/Status Bits
+ */
+enum jme_txcs_bits {
+	TXCS_QUEUE7S	= 0x00008000,
+	TXCS_QUEUE6S	= 0x00004000,
+	TXCS_QUEUE5S	= 0x00002000,
+	TXCS_QUEUE4S	= 0x00001000,
+	TXCS_QUEUE3S	= 0x00000800,
+	TXCS_QUEUE2S	= 0x00000400,
+	TXCS_QUEUE1S	= 0x00000200,
+	TXCS_QUEUE0S	= 0x00000100,
+	TXCS_FIFOTH	= 0x000000C0,
+	TXCS_DMASIZE	= 0x00000030,
+	TXCS_BURST	= 0x00000004,
+	TXCS_ENABLE	= 0x00000001,
+};
+
+enum jme_txcs_value {
+	TXCS_FIFOTH_16QW	= 0x000000C0,
+	TXCS_FIFOTH_12QW	= 0x00000080,
+	TXCS_FIFOTH_8QW		= 0x00000040,
+	TXCS_FIFOTH_4QW		= 0x00000000,
+
+	TXCS_DMASIZE_64B	= 0x00000000,
+	TXCS_DMASIZE_128B	= 0x00000010,
+	TXCS_DMASIZE_256B	= 0x00000020,
+	TXCS_DMASIZE_512B	= 0x00000030,
+
+	TXCS_SELECT_QUEUE0	= 0x00000000,
+	TXCS_SELECT_QUEUE1	= 0x00010000,
+	TXCS_SELECT_QUEUE2	= 0x00020000,
+	TXCS_SELECT_QUEUE3	= 0x00030000,
+	TXCS_SELECT_QUEUE4	= 0x00040000,
+	TXCS_SELECT_QUEUE5	= 0x00050000,
+	TXCS_SELECT_QUEUE6	= 0x00060000,
+	TXCS_SELECT_QUEUE7	= 0x00070000,
+
+	TXCS_DEFAULT		= TXCS_FIFOTH_4QW |
+				  TXCS_BURST,
+};
+
+#define JME_TX_DISABLE_TIMEOUT 10 /* 10 msec */
+
+/*
+ * TX MAC Control/Status Bits
+ */
+enum jme_txmcs_bit_masks {
+	TXMCS_IFG2		= 0xC0000000,
+	TXMCS_IFG1		= 0x30000000,
+	TXMCS_TTHOLD		= 0x00000300,
+	TXMCS_FBURST		= 0x00000080,
+	TXMCS_CARRIEREXT	= 0x00000040,
+	TXMCS_DEFER		= 0x00000020,
+	TXMCS_BACKOFF		= 0x00000010,
+	TXMCS_CARRIERSENSE	= 0x00000008,
+	TXMCS_COLLISION		= 0x00000004,
+	TXMCS_CRC		= 0x00000002,
+	TXMCS_PADDING		= 0x00000001,
+};
+
+enum jme_txmcs_values {
+	TXMCS_IFG2_6_4		= 0x00000000,
+	TXMCS_IFG2_8_5		= 0x40000000,
+	TXMCS_IFG2_10_6		= 0x80000000,
+	TXMCS_IFG2_12_7		= 0xC0000000,
+
+	TXMCS_IFG1_8_4		= 0x00000000,
+	TXMCS_IFG1_12_6		= 0x10000000,
+	TXMCS_IFG1_16_8		= 0x20000000,
+	TXMCS_IFG1_20_10	= 0x30000000,
+
+	TXMCS_TTHOLD_1_8	= 0x00000000,
+	TXMCS_TTHOLD_1_4	= 0x00000100,
+	TXMCS_TTHOLD_1_2	= 0x00000200,
+	TXMCS_TTHOLD_FULL	= 0x00000300,
+
+	TXMCS_DEFAULT		= TXMCS_IFG2_8_5 |
+				  TXMCS_IFG1_16_8 |
+				  TXMCS_TTHOLD_FULL |
+				  TXMCS_DEFER |
+				  TXMCS_CRC |
+				  TXMCS_PADDING,
+};
+
+enum jme_txpfc_bits_masks {
+	TXPFC_VLAN_TAG		= 0xFFFF0000,
+	TXPFC_VLAN_EN		= 0x00008000,
+	TXPFC_PF_EN		= 0x00000001,
+};
+
+enum jme_txtrhd_bits_masks {
+	TXTRHD_TXPEN		= 0x80000000,
+	TXTRHD_TXP		= 0x7FFFFF00,
+	TXTRHD_TXREN		= 0x00000080,
+	TXTRHD_TXRL		= 0x0000007F,
+};
+
+enum jme_txtrhd_shifts {
+	TXTRHD_TXP_SHIFT	= 8,
+	TXTRHD_TXRL_SHIFT	= 0,
+};
+
+/*
+ * RX Control/Status Bits
+ */
+enum jme_rxcs_bit_masks {
+	/* FIFO full threshold for transmitting Tx Pause Packet */
+	RXCS_FIFOTHTP	= 0x30000000,
+	/* FIFO threshold for processing next packet */
+	RXCS_FIFOTHNP	= 0x0C000000,
+	RXCS_DMAREQSZ	= 0x03000000, /* DMA Request Size */
+	RXCS_QUEUESEL	= 0x00030000, /* Queue selection */
+	RXCS_RETRYGAP	= 0x0000F000, /* RX Desc full retry gap */
+	RXCS_RETRYCNT	= 0x00000F00, /* RX Desc full retry counter */
+	RXCS_WAKEUP	= 0x00000040, /* Enable receive wakeup packet */
+	RXCS_MAGIC	= 0x00000020, /* Enable receive magic packet */
+	RXCS_SHORT	= 0x00000010, /* Enable receive short packet */
+	RXCS_ABORT	= 0x00000008, /* Enable receive errorr packet */
+	RXCS_QST	= 0x00000004, /* Receive queue start */
+	RXCS_SUSPEND	= 0x00000002,
+	RXCS_ENABLE	= 0x00000001,
+};
+
+enum jme_rxcs_values {
+	RXCS_FIFOTHTP_16T	= 0x00000000,
+	RXCS_FIFOTHTP_32T	= 0x10000000,
+	RXCS_FIFOTHTP_64T	= 0x20000000,
+	RXCS_FIFOTHTP_128T	= 0x30000000,
+
+	RXCS_FIFOTHNP_16QW	= 0x00000000,
+	RXCS_FIFOTHNP_32QW	= 0x04000000,
+	RXCS_FIFOTHNP_64QW	= 0x08000000,
+	RXCS_FIFOTHNP_128QW	= 0x0C000000,
+
+	RXCS_DMAREQSZ_16B	= 0x00000000,
+	RXCS_DMAREQSZ_32B	= 0x01000000,
+	RXCS_DMAREQSZ_64B	= 0x02000000,
+	RXCS_DMAREQSZ_128B	= 0x03000000,
+
+	RXCS_QUEUESEL_Q0	= 0x00000000,
+	RXCS_QUEUESEL_Q1	= 0x00010000,
+	RXCS_QUEUESEL_Q2	= 0x00020000,
+	RXCS_QUEUESEL_Q3	= 0x00030000,
+
+	RXCS_RETRYGAP_256ns	= 0x00000000,
+	RXCS_RETRYGAP_512ns	= 0x00001000,
+	RXCS_RETRYGAP_1024ns	= 0x00002000,
+	RXCS_RETRYGAP_2048ns	= 0x00003000,
+	RXCS_RETRYGAP_4096ns	= 0x00004000,
+	RXCS_RETRYGAP_8192ns	= 0x00005000,
+	RXCS_RETRYGAP_16384ns	= 0x00006000,
+	RXCS_RETRYGAP_32768ns	= 0x00007000,
+
+	RXCS_RETRYCNT_0		= 0x00000000,
+	RXCS_RETRYCNT_4		= 0x00000100,
+	RXCS_RETRYCNT_8		= 0x00000200,
+	RXCS_RETRYCNT_12	= 0x00000300,
+	RXCS_RETRYCNT_16	= 0x00000400,
+	RXCS_RETRYCNT_20	= 0x00000500,
+	RXCS_RETRYCNT_24	= 0x00000600,
+	RXCS_RETRYCNT_28	= 0x00000700,
+	RXCS_RETRYCNT_32	= 0x00000800,
+	RXCS_RETRYCNT_36	= 0x00000900,
+	RXCS_RETRYCNT_40	= 0x00000A00,
+	RXCS_RETRYCNT_44	= 0x00000B00,
+	RXCS_RETRYCNT_48	= 0x00000C00,
+	RXCS_RETRYCNT_52	= 0x00000D00,
+	RXCS_RETRYCNT_56	= 0x00000E00,
+	RXCS_RETRYCNT_60	= 0x00000F00,
+
+	RXCS_DEFAULT		= RXCS_FIFOTHTP_128T |
+				  RXCS_FIFOTHNP_128QW |
+				  RXCS_DMAREQSZ_128B |
+				  RXCS_RETRYGAP_256ns |
+				  RXCS_RETRYCNT_32,
+};
+
+#define JME_RX_DISABLE_TIMEOUT 10 /* 10 msec */
+
+/*
+ * RX MAC Control/Status Bits
+ */
+enum jme_rxmcs_bits {
+	RXMCS_ALLFRAME		= 0x00000800,
+	RXMCS_BRDFRAME		= 0x00000400,
+	RXMCS_MULFRAME		= 0x00000200,
+	RXMCS_UNIFRAME		= 0x00000100,
+	RXMCS_ALLMULFRAME	= 0x00000080,
+	RXMCS_MULFILTERED	= 0x00000040,
+	RXMCS_RXCOLLDEC		= 0x00000020,
+	RXMCS_FLOWCTRL		= 0x00000008,
+	RXMCS_VTAGRM		= 0x00000004,
+	RXMCS_PREPAD		= 0x00000002,
+	RXMCS_CHECKSUM		= 0x00000001,
+
+	RXMCS_DEFAULT		= RXMCS_VTAGRM |
+				  RXMCS_PREPAD |
+				  RXMCS_FLOWCTRL |
+				  RXMCS_CHECKSUM,
+};
+
+/*
+ * Wakeup Frame setup interface registers
+ */
+#define WAKEUP_FRAME_NR	8
+#define WAKEUP_FRAME_MASK_DWNR	4
+
+enum jme_wfoi_bit_masks {
+	WFOI_MASK_SEL		= 0x00000070,
+	WFOI_CRC_SEL		= 0x00000008,
+	WFOI_FRAME_SEL		= 0x00000007,
+};
+
+enum jme_wfoi_shifts {
+	WFOI_MASK_SHIFT		= 4,
+};
+
+/*
+ * SMI Related definitions
+ */
+enum jme_smi_bit_mask {
+	SMI_DATA_MASK		= 0xFFFF0000,
+	SMI_REG_ADDR_MASK	= 0x0000F800,
+	SMI_PHY_ADDR_MASK	= 0x000007C0,
+	SMI_OP_WRITE		= 0x00000020,
+	/* Set to 1, after req done it'll be cleared to 0 */
+	SMI_OP_REQ		= 0x00000010,
+	SMI_OP_MDIO		= 0x00000008, /* Software assess In/Out */
+	SMI_OP_MDOE		= 0x00000004, /* Software Output Enable */
+	SMI_OP_MDC		= 0x00000002, /* Software CLK Control */
+	SMI_OP_MDEN		= 0x00000001, /* Software access Enable */
+};
+
+enum jme_smi_bit_shift {
+	SMI_DATA_SHIFT		= 16,
+	SMI_REG_ADDR_SHIFT	= 11,
+	SMI_PHY_ADDR_SHIFT	= 6,
+};
+
+static inline u32 smi_reg_addr(int x)
+{
+	return (x << SMI_REG_ADDR_SHIFT) & SMI_REG_ADDR_MASK;
+}
+
+static inline u32 smi_phy_addr(int x)
+{
+	return (x << SMI_PHY_ADDR_SHIFT) & SMI_PHY_ADDR_MASK;
+}
+
+#define JME_PHY_TIMEOUT 100 /* 100 msec */
+#define JME_PHY_REG_NR 32
+
+/*
+ * Global Host Control
+ */
+enum jme_ghc_bit_mask {
+	GHC_SWRST	= 0x40000000,
+	GHC_DPX		= 0x00000040,
+	GHC_SPEED	= 0x00000030,
+	GHC_LINK_POLL	= 0x00000001,
+};
+
+enum jme_ghc_speed_val {
+	GHC_SPEED_10M	= 0x00000010,
+	GHC_SPEED_100M	= 0x00000020,
+	GHC_SPEED_1000M	= 0x00000030,
+};
+
+/*
+ * Power management control and status register
+ */
+enum jme_pmcs_bit_masks {
+	PMCS_WF7DET	= 0x80000000,
+	PMCS_WF6DET	= 0x40000000,
+	PMCS_WF5DET	= 0x20000000,
+	PMCS_WF4DET	= 0x10000000,
+	PMCS_WF3DET	= 0x08000000,
+	PMCS_WF2DET	= 0x04000000,
+	PMCS_WF1DET	= 0x02000000,
+	PMCS_WF0DET	= 0x01000000,
+	PMCS_LFDET	= 0x00040000,
+	PMCS_LRDET	= 0x00020000,
+	PMCS_MFDET	= 0x00010000,
+	PMCS_WF7EN	= 0x00008000,
+	PMCS_WF6EN	= 0x00004000,
+	PMCS_WF5EN	= 0x00002000,
+	PMCS_WF4EN	= 0x00001000,
+	PMCS_WF3EN	= 0x00000800,
+	PMCS_WF2EN	= 0x00000400,
+	PMCS_WF1EN	= 0x00000200,
+	PMCS_WF0EN	= 0x00000100,
+	PMCS_LFEN	= 0x00000004,
+	PMCS_LREN	= 0x00000002,
+	PMCS_MFEN	= 0x00000001,
+};
+
+/*
+ * Giga PHY Status Registers
+ */
+enum jme_phy_link_bit_mask {
+	PHY_LINK_SPEED_MASK		= 0x0000C000,
+	PHY_LINK_DUPLEX			= 0x00002000,
+	PHY_LINK_SPEEDDPU_RESOLVED	= 0x00000800,
+	PHY_LINK_UP			= 0x00000400,
+	PHY_LINK_AUTONEG_COMPLETE	= 0x00000200,
+	PHY_LINK_MDI_STAT		= 0x00000040,
+};
+
+enum jme_phy_link_speed_val {
+	PHY_LINK_SPEED_10M		= 0x00000000,
+	PHY_LINK_SPEED_100M		= 0x00004000,
+	PHY_LINK_SPEED_1000M		= 0x00008000,
+};
+
+#define JME_SPDRSV_TIMEOUT	500	/* 500 us */
+
+/*
+ * SMB Control and Status
+ */
+enum jme_smbcsr_bit_mask {
+	SMBCSR_CNACK	= 0x00020000,
+	SMBCSR_RELOAD	= 0x00010000,
+	SMBCSR_EEPROMD	= 0x00000020,
+	SMBCSR_INITDONE	= 0x00000010,
+	SMBCSR_BUSY	= 0x0000000F,
+};
+
+enum jme_smbintf_bit_mask {
+	SMBINTF_HWDATR	= 0xFF000000,
+	SMBINTF_HWDATW	= 0x00FF0000,
+	SMBINTF_HWADDR	= 0x0000FF00,
+	SMBINTF_HWRWN	= 0x00000020,
+	SMBINTF_HWCMD	= 0x00000010,
+	SMBINTF_FASTM	= 0x00000008,
+	SMBINTF_GPIOSCL	= 0x00000004,
+	SMBINTF_GPIOSDA	= 0x00000002,
+	SMBINTF_GPIOEN	= 0x00000001,
+};
+
+enum jme_smbintf_vals {
+	SMBINTF_HWRWN_READ	= 0x00000020,
+	SMBINTF_HWRWN_WRITE	= 0x00000000,
+};
+
+enum jme_smbintf_shifts {
+	SMBINTF_HWDATR_SHIFT	= 24,
+	SMBINTF_HWDATW_SHIFT	= 16,
+	SMBINTF_HWADDR_SHIFT	= 8,
+};
+
+#define JME_EEPROM_RELOAD_TIMEOUT 2000 /* 2000 msec */
+#define JME_SMB_BUSY_TIMEOUT 20 /* 20 msec */
+#define JME_SMB_LEN 256
+#define JME_EEPROM_MAGIC 0x250
+
+/*
+ * Timer Control/Status Register
+ */
+enum jme_tmcsr_bit_masks {
+	TMCSR_SWIT	= 0x80000000,
+	TMCSR_EN	= 0x01000000,
+	TMCSR_CNT	= 0x00FFFFFF,
+};
+
+/*
+ * General Purpose REG-0
+ */
+enum jme_gpreg0_masks {
+	GPREG0_DISSH		= 0xFF000000,
+	GPREG0_PCIRLMT		= 0x00300000,
+	GPREG0_PCCNOMUTCLR	= 0x00040000,
+	GPREG0_LNKINTPOLL	= 0x00001000,
+	GPREG0_PCCTMR		= 0x00000300,
+	GPREG0_PHYADDR		= 0x0000001F,
+};
+
+enum jme_gpreg0_vals {
+	GPREG0_DISSH_DW7	= 0x80000000,
+	GPREG0_DISSH_DW6	= 0x40000000,
+	GPREG0_DISSH_DW5	= 0x20000000,
+	GPREG0_DISSH_DW4	= 0x10000000,
+	GPREG0_DISSH_DW3	= 0x08000000,
+	GPREG0_DISSH_DW2	= 0x04000000,
+	GPREG0_DISSH_DW1	= 0x02000000,
+	GPREG0_DISSH_DW0	= 0x01000000,
+	GPREG0_DISSH_ALL	= 0xFF000000,
+
+	GPREG0_PCIRLMT_8	= 0x00000000,
+	GPREG0_PCIRLMT_6	= 0x00100000,
+	GPREG0_PCIRLMT_5	= 0x00200000,
+	GPREG0_PCIRLMT_4	= 0x00300000,
+
+	GPREG0_PCCTMR_16ns	= 0x00000000,
+	GPREG0_PCCTMR_256ns	= 0x00000100,
+	GPREG0_PCCTMR_1us	= 0x00000200,
+	GPREG0_PCCTMR_1ms	= 0x00000300,
+
+	GPREG0_PHYADDR_1	= 0x00000001,
+
+	GPREG0_DEFAULT		= GPREG0_PCIRLMT_4 |
+				  GPREG0_PCCTMR_1us |
+				  GPREG0_PHYADDR_1,
+};
+
+/*
+ * General Purpose REG-1
+ * Note: All theses bits defined here are for
+ *       Chip mode revision 0x11 only
+ */
+enum jme_gpreg1_masks {
+	GPREG1_INTRDELAYUNIT	= 0x00000018,
+	GPREG1_INTRDELAYENABLE	= 0x00000007,
+};
+
+enum jme_gpreg1_vals {
+	GPREG1_RSSPATCH		= 0x00000040,
+	GPREG1_HALFMODEPATCH	= 0x00000020,
+
+	GPREG1_INTDLYUNIT_16NS	= 0x00000000,
+	GPREG1_INTDLYUNIT_256NS	= 0x00000008,
+	GPREG1_INTDLYUNIT_1US	= 0x00000010,
+	GPREG1_INTDLYUNIT_16US	= 0x00000018,
+
+	GPREG1_INTDLYEN_1U	= 0x00000001,
+	GPREG1_INTDLYEN_2U	= 0x00000002,
+	GPREG1_INTDLYEN_3U	= 0x00000003,
+	GPREG1_INTDLYEN_4U	= 0x00000004,
+	GPREG1_INTDLYEN_5U	= 0x00000005,
+	GPREG1_INTDLYEN_6U	= 0x00000006,
+	GPREG1_INTDLYEN_7U	= 0x00000007,
+
+	GPREG1_DEFAULT		= 0x00000000,
+};
+
+/*
+ * Interrupt Status Bits
+ */
+enum jme_interrupt_bits {
+	INTR_SWINTR	= 0x80000000,
+	INTR_TMINTR	= 0x40000000,
+	INTR_LINKCH	= 0x20000000,
+	INTR_PAUSERCV	= 0x10000000,
+	INTR_MAGICRCV	= 0x08000000,
+	INTR_WAKERCV	= 0x04000000,
+	INTR_PCCRX0TO	= 0x02000000,
+	INTR_PCCRX1TO	= 0x01000000,
+	INTR_PCCRX2TO	= 0x00800000,
+	INTR_PCCRX3TO	= 0x00400000,
+	INTR_PCCTXTO	= 0x00200000,
+	INTR_PCCRX0	= 0x00100000,
+	INTR_PCCRX1	= 0x00080000,
+	INTR_PCCRX2	= 0x00040000,
+	INTR_PCCRX3	= 0x00020000,
+	INTR_PCCTX	= 0x00010000,
+	INTR_RX3EMP	= 0x00008000,
+	INTR_RX2EMP	= 0x00004000,
+	INTR_RX1EMP	= 0x00002000,
+	INTR_RX0EMP	= 0x00001000,
+	INTR_RX3	= 0x00000800,
+	INTR_RX2	= 0x00000400,
+	INTR_RX1	= 0x00000200,
+	INTR_RX0	= 0x00000100,
+	INTR_TX7	= 0x00000080,
+	INTR_TX6	= 0x00000040,
+	INTR_TX5	= 0x00000020,
+	INTR_TX4	= 0x00000010,
+	INTR_TX3	= 0x00000008,
+	INTR_TX2	= 0x00000004,
+	INTR_TX1	= 0x00000002,
+	INTR_TX0	= 0x00000001,
+};
+
+static const u32 INTR_ENABLE = INTR_SWINTR |
+				 INTR_TMINTR |
+				 INTR_LINKCH |
+				 INTR_PCCRX0TO |
+				 INTR_PCCRX0 |
+				 INTR_PCCTXTO |
+				 INTR_PCCTX |
+				 INTR_RX0EMP;
+
+/*
+ * PCC Control Registers
+ */
+enum jme_pccrx_masks {
+	PCCRXTO_MASK	= 0xFFFF0000,
+	PCCRX_MASK	= 0x0000FF00,
+};
+
+enum jme_pcctx_masks {
+	PCCTXTO_MASK	= 0xFFFF0000,
+	PCCTX_MASK	= 0x0000FF00,
+	PCCTX_QS_MASK	= 0x000000FF,
+};
+
+enum jme_pccrx_shifts {
+	PCCRXTO_SHIFT	= 16,
+	PCCRX_SHIFT	= 8,
+};
+
+enum jme_pcctx_shifts {
+	PCCTXTO_SHIFT	= 16,
+	PCCTX_SHIFT	= 8,
+};
+
+enum jme_pcctx_bits {
+	PCCTXQ0_EN	= 0x00000001,
+	PCCTXQ1_EN	= 0x00000002,
+	PCCTXQ2_EN	= 0x00000004,
+	PCCTXQ3_EN	= 0x00000008,
+	PCCTXQ4_EN	= 0x00000010,
+	PCCTXQ5_EN	= 0x00000020,
+	PCCTXQ6_EN	= 0x00000040,
+	PCCTXQ7_EN	= 0x00000080,
+};
+
+/*
+ * Chip Mode Register
+ */
+enum jme_chipmode_bit_masks {
+	CM_FPGAVER_MASK		= 0xFFFF0000,
+	CM_CHIPREV_MASK		= 0x0000FF00,
+	CM_CHIPMODE_MASK	= 0x0000000F,
+};
+
+enum jme_chipmode_shifts {
+	CM_FPGAVER_SHIFT	= 16,
+	CM_CHIPREV_SHIFT	= 8,
+};
+
+/*
+ * Shadow base address register bits
+ */
+enum jme_shadow_base_address_bits {
+	SHBA_POSTEN	= 0x1,
+};
+
+/*
+ * Aggressive Power Mode Control
+ */
+enum jme_apmc_bits {
+	JME_APMC_PCIE_SD_EN	= 0x40000000,
+	JME_APMC_PSEUDO_HP_EN	= 0x20000000,
+	JME_APMC_EPIEN		= 0x04000000,
+	JME_APMC_EPIEN_CTRL	= 0x03000000,
+};
+
+enum jme_apmc_values {
+	JME_APMC_EPIEN_CTRL_EN	= 0x02000000,
+	JME_APMC_EPIEN_CTRL_DIS	= 0x01000000,
+};
+
+#define APMC_PHP_SHUTDOWN_DELAY	(10 * 1000 * 1000)
+
+#ifdef REG_DEBUG
+static char *MAC_REG_NAME[] = {
+	"JME_TXCS",      "JME_TXDBA_LO",  "JME_TXDBA_HI", "JME_TXQDC",
+	"JME_TXNDA",     "JME_TXMCS",     "JME_TXPFC",    "JME_TXTRHD",
+	"JME_RXCS",      "JME_RXDBA_LO",  "JME_RXDBA_HI", "JME_RXQDC",
+	"JME_RXNDA",     "JME_RXMCS",     "JME_RXUMA_LO", "JME_RXUMA_HI",
+	"JME_RXMCHT_LO", "JME_RXMCHT_HI", "JME_WFODP",    "JME_WFOI",
+	"JME_SMI",       "JME_GHC",       "UNKNOWN",      "UNKNOWN",
+	"JME_PMCS"};
+
+static char *PE_REG_NAME[] = {
+	"UNKNOWN",      "UNKNOWN",     "UNKNOWN",    "UNKNOWN",
+	"UNKNOWN",      "UNKNOWN",     "UNKNOWN",    "UNKNOWN",
+	"UNKNOWN",      "UNKNOWN",     "JME_PHY_CS", "UNKNOWN",
+	"JME_PHY_LINK", "UNKNOWN",     "UNKNOWN",    "UNKNOWN",
+	"JME_SMBCSR",   "JME_SMBINTF"};
+
+static char *MISC_REG_NAME[] = {
+	"JME_TMCSR",  "JME_GPIO",     "JME_GPREG0",  "JME_GPREG1",
+	"JME_IEVE",   "JME_IREQ",     "JME_IENS",    "JME_IENC",
+	"JME_PCCRX0", "JME_PCCRX1",   "JME_PCCRX2",  "JME_PCCRX3",
+	"JME_PCCTX0", "JME_CHIPMODE", "JME_SHBA_HI", "JME_SHBA_LO",
+	"UNKNOWN",    "UNKNOWN",      "UNKNOWN",     "UNKNOWN",
+	"UNKNOWN",    "UNKNOWN",      "UNKNOWN",     "UNKNOWN",
+	"UNKNOWN",    "UNKNOWN",      "UNKNOWN",     "UNKNOWN",
+	"JME_TIMER1", "JME_TIMER2",   "UNKNOWN",     "JME_APMC",
+	"JME_PCCSRX0"};
+
+static inline void reg_dbg(const struct jme_adapter *jme,
+		const char *msg, u32 val, u32 reg)
+{
+	const char *regname;
+	switch (reg & 0xF00) {
+	case 0x000:
+		regname = MAC_REG_NAME[(reg & 0xFF) >> 2];
+		break;
+	case 0x400:
+		regname = PE_REG_NAME[(reg & 0xFF) >> 2];
+		break;
+	case 0x800:
+		regname = MISC_REG_NAME[(reg & 0xFF) >> 2];
+		break;
+	default:
+		regname = PE_REG_NAME[0];
+	}
+	printk(KERN_DEBUG "%s: %-20s %08x@%s\n", jme->dev->name,
+			msg, val, regname);
+}
+#else
+static inline void reg_dbg(const struct jme_adapter *jme,
+		const char *msg, u32 val, u32 reg) {}
+#endif
+
+/*
+ * Read/Write MMaped I/O Registers
+ */
+static inline u32 jread32(struct jme_adapter *jme, u32 reg)
+{
+	return readl(jme->regs + reg);
+}
+
+static inline void jwrite32(struct jme_adapter *jme, u32 reg, u32 val)
+{
+	reg_dbg(jme, "REG WRITE", val, reg);
+	writel(val, jme->regs + reg);
+	reg_dbg(jme, "VAL AFTER WRITE", readl(jme->regs + reg), reg);
+}
+
+static inline void jwrite32f(struct jme_adapter *jme, u32 reg, u32 val)
+{
+	/*
+	 * Read after write should cause flush
+	 */
+	reg_dbg(jme, "REG WRITE FLUSH", val, reg);
+	writel(val, jme->regs + reg);
+	readl(jme->regs + reg);
+	reg_dbg(jme, "VAL AFTER WRITE", readl(jme->regs + reg), reg);
+}
+
+/*
+ * PHY Regs
+ */
+enum jme_phy_reg17_bit_masks {
+	PREG17_SPEED		= 0xC000,
+	PREG17_DUPLEX		= 0x2000,
+	PREG17_SPDRSV		= 0x0800,
+	PREG17_LNKUP		= 0x0400,
+	PREG17_MDI		= 0x0040,
+};
+
+enum jme_phy_reg17_vals {
+	PREG17_SPEED_10M	= 0x0000,
+	PREG17_SPEED_100M	= 0x4000,
+	PREG17_SPEED_1000M	= 0x8000,
+};
+
+#define BMSR_ANCOMP               0x0020
+
+/*
+ * Workaround
+ */
+static inline int is_buggy250(unsigned short device, unsigned int chiprev)
+{
+	return device == PCI_DEVICE_ID_JMICRON_JMC250 && chiprev == 0x11;
+}
+
+/*
+ * Function prototypes
+ */
+static int jme_set_settings(struct net_device *netdev,
+				struct ethtool_cmd *ecmd);
+static void jme_set_multi(struct net_device *netdev);
+
+#endif
diff --git a/drivers/net/lib8390.c b/drivers/net/lib8390.c
index 00d59ab..f80dcc1 100644
--- a/drivers/net/lib8390.c
+++ b/drivers/net/lib8390.c
@@ -530,9 +530,9 @@
 #ifdef CONFIG_NET_POLL_CONTROLLER
 static void __ei_poll(struct net_device *dev)
 {
-	disable_irq_lockdep(dev->irq);
+	disable_irq(dev->irq);
 	__ei_interrupt(dev->irq, dev);
-	enable_irq_lockdep(dev->irq);
+	enable_irq(dev->irq);
 }
 #endif
 
diff --git a/drivers/net/macb.c b/drivers/net/macb.c
index 84c77f1..01f7a31 100644
--- a/drivers/net/macb.c
+++ b/drivers/net/macb.c
@@ -195,8 +195,8 @@
 
 	/* find the first phy */
 	for (phy_addr = 0; phy_addr < PHY_MAX_ADDR; phy_addr++) {
-		if (bp->mii_bus.phy_map[phy_addr]) {
-			phydev = bp->mii_bus.phy_map[phy_addr];
+		if (bp->mii_bus->phy_map[phy_addr]) {
+			phydev = bp->mii_bus->phy_map[phy_addr];
 			break;
 		}
 	}
@@ -244,30 +244,36 @@
 	/* Enable managment port */
 	macb_writel(bp, NCR, MACB_BIT(MPE));
 
-	bp->mii_bus.name = "MACB_mii_bus";
-	bp->mii_bus.read = &macb_mdio_read;
-	bp->mii_bus.write = &macb_mdio_write;
-	bp->mii_bus.reset = &macb_mdio_reset;
-	snprintf(bp->mii_bus.id, MII_BUS_ID_SIZE, "%x", bp->pdev->id);
-	bp->mii_bus.priv = bp;
-	bp->mii_bus.dev = &bp->dev->dev;
-	pdata = bp->pdev->dev.platform_data;
-
-	if (pdata)
-		bp->mii_bus.phy_mask = pdata->phy_mask;
-
-	bp->mii_bus.irq = kmalloc(sizeof(int)*PHY_MAX_ADDR, GFP_KERNEL);
-	if (!bp->mii_bus.irq) {
+	bp->mii_bus = mdiobus_alloc();
+	if (bp->mii_bus == NULL) {
 		err = -ENOMEM;
 		goto err_out;
 	}
 
+	bp->mii_bus->name = "MACB_mii_bus";
+	bp->mii_bus->read = &macb_mdio_read;
+	bp->mii_bus->write = &macb_mdio_write;
+	bp->mii_bus->reset = &macb_mdio_reset;
+	snprintf(bp->mii_bus->id, MII_BUS_ID_SIZE, "%x", bp->pdev->id);
+	bp->mii_bus->priv = bp;
+	bp->mii_bus->parent = &bp->dev->dev;
+	pdata = bp->pdev->dev.platform_data;
+
+	if (pdata)
+		bp->mii_bus->phy_mask = pdata->phy_mask;
+
+	bp->mii_bus->irq = kmalloc(sizeof(int)*PHY_MAX_ADDR, GFP_KERNEL);
+	if (!bp->mii_bus->irq) {
+		err = -ENOMEM;
+		goto err_out_free_mdiobus;
+	}
+
 	for (i = 0; i < PHY_MAX_ADDR; i++)
-		bp->mii_bus.irq[i] = PHY_POLL;
+		bp->mii_bus->irq[i] = PHY_POLL;
 
-	platform_set_drvdata(bp->dev, &bp->mii_bus);
+	platform_set_drvdata(bp->dev, bp->mii_bus);
 
-	if (mdiobus_register(&bp->mii_bus))
+	if (mdiobus_register(bp->mii_bus))
 		goto err_out_free_mdio_irq;
 
 	if (macb_mii_probe(bp->dev) != 0) {
@@ -277,9 +283,11 @@
 	return 0;
 
 err_out_unregister_bus:
-	mdiobus_unregister(&bp->mii_bus);
+	mdiobus_unregister(bp->mii_bus);
 err_out_free_mdio_irq:
-	kfree(bp->mii_bus.irq);
+	kfree(bp->mii_bus->irq);
+err_out_free_mdiobus:
+	mdiobus_free(bp->mii_bus);
 err_out:
 	return err;
 }
@@ -1261,8 +1269,9 @@
 		bp = netdev_priv(dev);
 		if (bp->phy_dev)
 			phy_disconnect(bp->phy_dev);
-		mdiobus_unregister(&bp->mii_bus);
-		kfree(bp->mii_bus.irq);
+		mdiobus_unregister(bp->mii_bus);
+		kfree(bp->mii_bus->irq);
+		mdiobus_free(bp->mii_bus);
 		unregister_netdev(dev);
 		free_irq(dev->irq, dev);
 		iounmap(bp->regs);
diff --git a/drivers/net/macb.h b/drivers/net/macb.h
index 57b85ac..d3212f6 100644
--- a/drivers/net/macb.h
+++ b/drivers/net/macb.h
@@ -384,7 +384,7 @@
 
 	unsigned int		rx_pending, tx_pending;
 
-	struct mii_bus		mii_bus;
+	struct mii_bus		*mii_bus;
 	struct phy_device	*phy_dev;
 	unsigned int 		link;
 	unsigned int 		speed;
diff --git a/drivers/net/macmace.c b/drivers/net/macmace.c
index 51ad376..85587a66 100644
--- a/drivers/net/macmace.c
+++ b/drivers/net/macmace.c
@@ -9,7 +9,7 @@
  *	2 of the License, or (at your option) any later version.
  *
  *	Copyright (C) 1996 Paul Mackerras.
- *	Copyright (C) 1998 Alan Cox <alan@redhat.com>
+ *	Copyright (C) 1998 Alan Cox <alan@lxorguk.ukuu.org.uk>
  *
  *	Modified heavily by Joshua M. Thompson based on Dave Huang's NetBSD driver
  *
diff --git a/drivers/net/meth.c b/drivers/net/meth.c
index 0a97c26..a1e22ed 100644
--- a/drivers/net/meth.c
+++ b/drivers/net/meth.c
@@ -41,7 +41,7 @@
 #endif
 
 #if MFE_DEBUG>=1
-#define DPRINTK(str,args...) printk(KERN_DEBUG "meth: %s: " str, __FUNCTION__ , ## args)
+#define DPRINTK(str,args...) printk(KERN_DEBUG "meth: %s: " str, __func__ , ## args)
 #define MFE_RX_DEBUG 2
 #else
 #define DPRINTK(str,args...)
diff --git a/drivers/net/mipsnet.c b/drivers/net/mipsnet.c
index 6d343ef..4e7a5fa 100644
--- a/drivers/net/mipsnet.c
+++ b/drivers/net/mipsnet.c
@@ -203,7 +203,7 @@
 
 out_badirq:
 	printk(KERN_INFO "%s: %s(): irq %d for unknown device\n",
-	       dev->name, __FUNCTION__, irq);
+	       dev->name, __func__, irq);
 	return ret;
 }
 
diff --git a/drivers/net/mlx4/alloc.c b/drivers/net/mlx4/alloc.c
index 096bca5..b411b79 100644
--- a/drivers/net/mlx4/alloc.c
+++ b/drivers/net/mlx4/alloc.c
@@ -33,6 +33,7 @@
 
 #include <linux/errno.h>
 #include <linux/slab.h>
+#include <linux/mm.h>
 #include <linux/bitmap.h>
 #include <linux/dma-mapping.h>
 #include <linux/vmalloc.h>
diff --git a/drivers/net/mlx4/mr.c b/drivers/net/mlx4/mr.c
index 62071d9..d1dd5b4 100644
--- a/drivers/net/mlx4/mr.c
+++ b/drivers/net/mlx4/mr.c
@@ -67,11 +67,10 @@
 #define MLX4_MPT_FLAG_PHYSICAL	    (1 <<  9)
 #define MLX4_MPT_FLAG_REGION	    (1 <<  8)
 
-#define MLX4_MPT_PD_FLAG_FAST_REG   (1 << 26)
+#define MLX4_MPT_PD_FLAG_FAST_REG   (1 << 27)
+#define MLX4_MPT_PD_FLAG_RAE	    (1 << 28)
 #define MLX4_MPT_PD_FLAG_EN_INV	    (3 << 24)
 
-#define MLX4_MTT_FLAG_PRESENT		1
-
 #define MLX4_MPT_STATUS_SW		0xF0
 #define MLX4_MPT_STATUS_HW		0x00
 
@@ -348,7 +347,10 @@
 	if (mr->mtt.order >= 0 && mr->mtt.page_shift == 0) {
 		/* fast register MR in free state */
 		mpt_entry->flags    |= cpu_to_be32(MLX4_MPT_FLAG_FREE);
-		mpt_entry->pd_flags |= cpu_to_be32(MLX4_MPT_PD_FLAG_FAST_REG);
+		mpt_entry->pd_flags |= cpu_to_be32(MLX4_MPT_PD_FLAG_FAST_REG |
+						   MLX4_MPT_PD_FLAG_RAE);
+		mpt_entry->mtt_sz    = cpu_to_be32((1 << mr->mtt.order) *
+						   MLX4_MTT_ENTRY_PER_SEG);
 	} else {
 		mpt_entry->flags    |= cpu_to_be32(MLX4_MPT_FLAG_SW_OWNS);
 	}
diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c
index 0a18b9e..a9c8c08 100644
--- a/drivers/net/mv643xx_eth.c
+++ b/drivers/net/mv643xx_eth.c
@@ -38,6 +38,7 @@
 #include <linux/init.h>
 #include <linux/dma-mapping.h>
 #include <linux/in.h>
+#include <linux/ip.h>
 #include <linux/tcp.h>
 #include <linux/udp.h>
 #include <linux/etherdevice.h>
@@ -48,30 +49,28 @@
 #include <linux/kernel.h>
 #include <linux/spinlock.h>
 #include <linux/workqueue.h>
-#include <linux/mii.h>
+#include <linux/phy.h>
 #include <linux/mv643xx_eth.h>
 #include <asm/io.h>
 #include <asm/types.h>
 #include <asm/system.h>
 
 static char mv643xx_eth_driver_name[] = "mv643xx_eth";
-static char mv643xx_eth_driver_version[] = "1.3";
+static char mv643xx_eth_driver_version[] = "1.4";
 
-#define MV643XX_ETH_CHECKSUM_OFFLOAD_TX
-#define MV643XX_ETH_NAPI
-#define MV643XX_ETH_TX_FAST_REFILL
-
-#ifdef MV643XX_ETH_CHECKSUM_OFFLOAD_TX
-#define MAX_DESCS_PER_SKB	(MAX_SKB_FRAGS + 1)
-#else
-#define MAX_DESCS_PER_SKB	1
-#endif
 
 /*
  * Registers shared between all ports.
  */
 #define PHY_ADDR			0x0000
 #define SMI_REG				0x0004
+#define  SMI_BUSY			0x10000000
+#define  SMI_READ_VALID			0x08000000
+#define  SMI_OPCODE_READ		0x04000000
+#define  SMI_OPCODE_WRITE		0x00000000
+#define ERR_INT_CAUSE			0x0080
+#define  ERR_INT_SMI_DONE		0x00000010
+#define ERR_INT_MASK			0x0084
 #define WINDOW_BASE(w)			(0x0200 + ((w) << 3))
 #define WINDOW_SIZE(w)			(0x0204 + ((w) << 3))
 #define WINDOW_REMAP_HIGH(w)		(0x0280 + ((w) << 2))
@@ -104,16 +103,12 @@
 #define TX_BW_MTU(p)			(0x0458 + ((p) << 10))
 #define TX_BW_BURST(p)			(0x045c + ((p) << 10))
 #define INT_CAUSE(p)			(0x0460 + ((p) << 10))
-#define  INT_TX_END_0			0x00080000
 #define  INT_TX_END			0x07f80000
-#define  INT_RX				0x0007fbfc
+#define  INT_RX				0x000003fc
 #define  INT_EXT			0x00000002
 #define INT_CAUSE_EXT(p)		(0x0464 + ((p) << 10))
-#define  INT_EXT_LINK			0x00100000
-#define  INT_EXT_PHY			0x00010000
-#define  INT_EXT_TX_ERROR_0		0x00000100
-#define  INT_EXT_TX_0			0x00000001
-#define  INT_EXT_TX			0x0000ffff
+#define  INT_EXT_LINK_PHY		0x00110000
+#define  INT_EXT_TX			0x000000ff
 #define INT_MASK(p)			(0x0468 + ((p) << 10))
 #define INT_MASK_EXT(p)			(0x046c + ((p) << 10))
 #define TX_FIFO_URGENT_THRESHOLD(p)	(0x0474 + ((p) << 10))
@@ -171,8 +166,8 @@
 #define FORCE_LINK_PASS				(1 << 1)
 #define SERIAL_PORT_ENABLE			(1 << 0)
 
-#define DEFAULT_RX_QUEUE_SIZE		400
-#define DEFAULT_TX_QUEUE_SIZE		800
+#define DEFAULT_RX_QUEUE_SIZE		128
+#define DEFAULT_TX_QUEUE_SIZE		256
 
 
 /*
@@ -249,9 +244,23 @@
 	void __iomem *base;
 
 	/*
-	 * Protects access to SMI_REG, which is shared between ports.
+	 * Points at the right SMI instance to use.
 	 */
-	spinlock_t phy_lock;
+	struct mv643xx_eth_shared_private *smi;
+
+	/*
+	 * Provides access to local SMI interface.
+	 */
+	struct mii_bus *smi_bus;
+
+	/*
+	 * If we have access to the error interrupt pin (which is
+	 * somewhat misnamed as it not only reflects internal errors
+	 * but also reflects SMI completion), use that to wait for
+	 * SMI access completion instead of polling the SMI busy bit.
+	 */
+	int err_interrupt;
+	wait_queue_head_t smi_busy_wait;
 
 	/*
 	 * Per-port MBUS window access register value.
@@ -263,9 +272,13 @@
 	 */
 	unsigned int t_clk;
 	int extended_rx_coal_limit;
-	int tx_bw_control_moved;
+	int tx_bw_control;
 };
 
+#define TX_BW_CONTROL_ABSENT		0
+#define TX_BW_CONTROL_OLD_LAYOUT	1
+#define TX_BW_CONTROL_NEW_LAYOUT	2
+
 
 /* per-port *****************************************************************/
 struct mib_counters {
@@ -314,8 +327,6 @@
 	dma_addr_t rx_desc_dma;
 	int rx_desc_area_size;
 	struct sk_buff **rx_skb;
-
-	struct timer_list rx_oom;
 };
 
 struct tx_queue {
@@ -330,7 +341,12 @@
 	struct tx_desc *tx_desc_area;
 	dma_addr_t tx_desc_dma;
 	int tx_desc_area_size;
-	struct sk_buff **tx_skb;
+
+	struct sk_buff_head tx_skb;
+
+	unsigned long tx_packets;
+	unsigned long tx_bytes;
+	unsigned long tx_dropped;
 };
 
 struct mv643xx_eth_private {
@@ -339,14 +355,24 @@
 
 	struct net_device *dev;
 
-	struct mv643xx_eth_shared_private *shared_smi;
-	int phy_addr;
+	struct phy_device *phy;
 
-	spinlock_t lock;
-
+	struct timer_list mib_counters_timer;
+	spinlock_t mib_counters_lock;
 	struct mib_counters mib_counters;
+
 	struct work_struct tx_timeout_task;
-	struct mii_if_info mii;
+
+	struct napi_struct napi;
+	u8 work_link;
+	u8 work_tx;
+	u8 work_tx_end;
+	u8 work_rx;
+	u8 work_rx_refill;
+	u8 work_rx_oom;
+
+	int skb_size;
+	struct sk_buff_head rx_recycle;
 
 	/*
 	 * RX state.
@@ -354,9 +380,8 @@
 	int default_rx_ring_size;
 	unsigned long rx_desc_sram_addr;
 	int rx_desc_sram_size;
-	u8 rxq_mask;
-	int rxq_primary;
-	struct napi_struct napi;
+	int rxq_count;
+	struct timer_list rx_oom;
 	struct rx_queue rxq[8];
 
 	/*
@@ -365,12 +390,8 @@
 	int default_tx_ring_size;
 	unsigned long tx_desc_sram_addr;
 	int tx_desc_sram_size;
-	u8 txq_mask;
-	int txq_primary;
+	int txq_count;
 	struct tx_queue txq[8];
-#ifdef MV643XX_ETH_TX_FAST_REFILL
-	int tx_clean_threshold;
-#endif
 };
 
 
@@ -440,94 +461,21 @@
 		udelay(10);
 }
 
-static void __txq_maybe_wake(struct tx_queue *txq)
+static void txq_maybe_wake(struct tx_queue *txq)
 {
 	struct mv643xx_eth_private *mp = txq_to_mp(txq);
+	struct netdev_queue *nq = netdev_get_tx_queue(mp->dev, txq->index);
 
-	/*
-	 * netif_{stop,wake}_queue() flow control only applies to
-	 * the primary queue.
-	 */
-	BUG_ON(txq->index != mp->txq_primary);
-
-	if (txq->tx_ring_size - txq->tx_desc_count >= MAX_DESCS_PER_SKB)
-		netif_wake_queue(mp->dev);
-}
-
-
-/* rx ***********************************************************************/
-static void txq_reclaim(struct tx_queue *txq, int force);
-
-static void rxq_refill(struct rx_queue *rxq)
-{
-	struct mv643xx_eth_private *mp = rxq_to_mp(rxq);
-	unsigned long flags;
-
-	spin_lock_irqsave(&mp->lock, flags);
-
-	while (rxq->rx_desc_count < rxq->rx_ring_size) {
-		int skb_size;
-		struct sk_buff *skb;
-		int unaligned;
-		int rx;
-
-		/*
-		 * Reserve 2+14 bytes for an ethernet header (the
-		 * hardware automatically prepends 2 bytes of dummy
-		 * data to each received packet), 16 bytes for up to
-		 * four VLAN tags, and 4 bytes for the trailing FCS
-		 * -- 36 bytes total.
-		 */
-		skb_size = mp->dev->mtu + 36;
-
-		/*
-		 * Make sure that the skb size is a multiple of 8
-		 * bytes, as the lower three bits of the receive
-		 * descriptor's buffer size field are ignored by
-		 * the hardware.
-		 */
-		skb_size = (skb_size + 7) & ~7;
-
-		skb = dev_alloc_skb(skb_size + dma_get_cache_alignment() - 1);
-		if (skb == NULL)
-			break;
-
-		unaligned = (u32)skb->data & (dma_get_cache_alignment() - 1);
-		if (unaligned)
-			skb_reserve(skb, dma_get_cache_alignment() - unaligned);
-
-		rxq->rx_desc_count++;
-		rx = rxq->rx_used_desc;
-		rxq->rx_used_desc = (rx + 1) % rxq->rx_ring_size;
-
-		rxq->rx_desc_area[rx].buf_ptr = dma_map_single(NULL, skb->data,
-						skb_size, DMA_FROM_DEVICE);
-		rxq->rx_desc_area[rx].buf_size = skb_size;
-		rxq->rx_skb[rx] = skb;
-		wmb();
-		rxq->rx_desc_area[rx].cmd_sts = BUFFER_OWNED_BY_DMA |
-						RX_ENABLE_INTERRUPT;
-		wmb();
-
-		/*
-		 * The hardware automatically prepends 2 bytes of
-		 * dummy data to each received packet, so that the
-		 * IP header ends up 16-byte aligned.
-		 */
-		skb_reserve(skb, 2);
+	if (netif_tx_queue_stopped(nq)) {
+		__netif_tx_lock(nq, smp_processor_id());
+		if (txq->tx_ring_size - txq->tx_desc_count >= MAX_SKB_FRAGS + 1)
+			netif_tx_wake_queue(nq);
+		__netif_tx_unlock(nq);
 	}
-
-	if (rxq->rx_desc_count != rxq->rx_ring_size)
-		mod_timer(&rxq->rx_oom, jiffies + (HZ / 10));
-
-	spin_unlock_irqrestore(&mp->lock, flags);
 }
 
-static inline void rxq_refill_timer_wrapper(unsigned long data)
-{
-	rxq_refill((struct rx_queue *)data);
-}
 
+/* rx napi ******************************************************************/
 static int rxq_process(struct rx_queue *rxq, int budget)
 {
 	struct mv643xx_eth_private *mp = rxq_to_mp(rxq);
@@ -539,31 +487,31 @@
 		struct rx_desc *rx_desc;
 		unsigned int cmd_sts;
 		struct sk_buff *skb;
-		unsigned long flags;
-
-		spin_lock_irqsave(&mp->lock, flags);
+		u16 byte_cnt;
 
 		rx_desc = &rxq->rx_desc_area[rxq->rx_curr_desc];
 
 		cmd_sts = rx_desc->cmd_sts;
-		if (cmd_sts & BUFFER_OWNED_BY_DMA) {
-			spin_unlock_irqrestore(&mp->lock, flags);
+		if (cmd_sts & BUFFER_OWNED_BY_DMA)
 			break;
-		}
 		rmb();
 
 		skb = rxq->rx_skb[rxq->rx_curr_desc];
 		rxq->rx_skb[rxq->rx_curr_desc] = NULL;
 
-		rxq->rx_curr_desc = (rxq->rx_curr_desc + 1) % rxq->rx_ring_size;
+		rxq->rx_curr_desc++;
+		if (rxq->rx_curr_desc == rxq->rx_ring_size)
+			rxq->rx_curr_desc = 0;
 
-		spin_unlock_irqrestore(&mp->lock, flags);
-
-		dma_unmap_single(NULL, rx_desc->buf_ptr + 2,
+		dma_unmap_single(NULL, rx_desc->buf_ptr,
 				 rx_desc->buf_size, DMA_FROM_DEVICE);
 		rxq->rx_desc_count--;
 		rx++;
 
+		mp->work_rx_refill |= 1 << rxq->index;
+
+		byte_cnt = rx_desc->byte_cnt;
+
 		/*
 		 * Update statistics.
 		 *
@@ -573,7 +521,7 @@
 		 * byte CRC at the end of the packet (which we do count).
 		 */
 		stats->rx_packets++;
-		stats->rx_bytes += rx_desc->byte_cnt - 2;
+		stats->rx_bytes += byte_cnt - 2;
 
 		/*
 		 * In case we received a packet without first / last bits
@@ -596,72 +544,84 @@
 			if (cmd_sts & ERROR_SUMMARY)
 				stats->rx_errors++;
 
-			dev_kfree_skb_irq(skb);
+			dev_kfree_skb(skb);
 		} else {
 			/*
 			 * The -4 is for the CRC in the trailer of the
 			 * received packet
 			 */
-			skb_put(skb, rx_desc->byte_cnt - 2 - 4);
+			skb_put(skb, byte_cnt - 2 - 4);
 
-			if (cmd_sts & LAYER_4_CHECKSUM_OK) {
+			if (cmd_sts & LAYER_4_CHECKSUM_OK)
 				skb->ip_summed = CHECKSUM_UNNECESSARY;
-				skb->csum = htons(
-					(cmd_sts & 0x0007fff8) >> 3);
-			}
 			skb->protocol = eth_type_trans(skb, mp->dev);
-#ifdef MV643XX_ETH_NAPI
 			netif_receive_skb(skb);
-#else
-			netif_rx(skb);
-#endif
 		}
 
 		mp->dev->last_rx = jiffies;
 	}
 
-	rxq_refill(rxq);
+	if (rx < budget)
+		mp->work_rx &= ~(1 << rxq->index);
 
 	return rx;
 }
 
-#ifdef MV643XX_ETH_NAPI
-static int mv643xx_eth_poll(struct napi_struct *napi, int budget)
+static int rxq_refill(struct rx_queue *rxq, int budget)
 {
-	struct mv643xx_eth_private *mp;
-	int rx;
-	int i;
+	struct mv643xx_eth_private *mp = rxq_to_mp(rxq);
+	int refilled;
 
-	mp = container_of(napi, struct mv643xx_eth_private, napi);
+	refilled = 0;
+	while (refilled < budget && rxq->rx_desc_count < rxq->rx_ring_size) {
+		struct sk_buff *skb;
+		int unaligned;
+		int rx;
 
-#ifdef MV643XX_ETH_TX_FAST_REFILL
-	if (++mp->tx_clean_threshold > 5) {
-		mp->tx_clean_threshold = 0;
-		for (i = 0; i < 8; i++)
-			if (mp->txq_mask & (1 << i))
-				txq_reclaim(mp->txq + i, 0);
+		skb = __skb_dequeue(&mp->rx_recycle);
+		if (skb == NULL)
+			skb = dev_alloc_skb(mp->skb_size +
+					    dma_get_cache_alignment() - 1);
 
-		if (netif_carrier_ok(mp->dev)) {
-			spin_lock_irq(&mp->lock);
-			__txq_maybe_wake(mp->txq + mp->txq_primary);
-			spin_unlock_irq(&mp->lock);
+		if (skb == NULL) {
+			mp->work_rx_oom |= 1 << rxq->index;
+			goto oom;
 		}
-	}
-#endif
 
-	rx = 0;
-	for (i = 7; rx < budget && i >= 0; i--)
-		if (mp->rxq_mask & (1 << i))
-			rx += rxq_process(mp->rxq + i, budget - rx);
+		unaligned = (u32)skb->data & (dma_get_cache_alignment() - 1);
+		if (unaligned)
+			skb_reserve(skb, dma_get_cache_alignment() - unaligned);
 
-	if (rx < budget) {
-		netif_rx_complete(mp->dev, napi);
-		wrl(mp, INT_MASK(mp->port_num), INT_TX_END | INT_RX | INT_EXT);
+		refilled++;
+		rxq->rx_desc_count++;
+
+		rx = rxq->rx_used_desc++;
+		if (rxq->rx_used_desc == rxq->rx_ring_size)
+			rxq->rx_used_desc = 0;
+
+		rxq->rx_desc_area[rx].buf_ptr = dma_map_single(NULL, skb->data,
+						mp->skb_size, DMA_FROM_DEVICE);
+		rxq->rx_desc_area[rx].buf_size = mp->skb_size;
+		rxq->rx_skb[rx] = skb;
+		wmb();
+		rxq->rx_desc_area[rx].cmd_sts = BUFFER_OWNED_BY_DMA |
+						RX_ENABLE_INTERRUPT;
+		wmb();
+
+		/*
+		 * The hardware automatically prepends 2 bytes of
+		 * dummy data to each received packet, so that the
+		 * IP header ends up 16-byte aligned.
+		 */
+		skb_reserve(skb, 2);
 	}
 
-	return rx;
+	if (refilled < budget)
+		mp->work_rx_refill &= ~(1 << rxq->index);
+
+oom:
+	return refilled;
 }
-#endif
 
 
 /* tx ***********************************************************************/
@@ -684,8 +644,9 @@
 
 	BUG_ON(txq->tx_desc_count >= txq->tx_ring_size);
 
-	tx_desc_curr = txq->tx_curr_desc;
-	txq->tx_curr_desc = (tx_desc_curr + 1) % txq->tx_ring_size;
+	tx_desc_curr = txq->tx_curr_desc++;
+	if (txq->tx_curr_desc == txq->tx_ring_size)
+		txq->tx_curr_desc = 0;
 
 	BUG_ON(txq->tx_curr_desc == txq->tx_used_desc);
 
@@ -714,10 +675,8 @@
 			desc->cmd_sts = BUFFER_OWNED_BY_DMA |
 					ZERO_PADDING | TX_LAST_DESC |
 					TX_ENABLE_INTERRUPT;
-			txq->tx_skb[tx_index] = skb;
 		} else {
 			desc->cmd_sts = BUFFER_OWNED_BY_DMA;
-			txq->tx_skb[tx_index] = NULL;
 		}
 
 		desc->l4i_chk = 0;
@@ -734,144 +693,228 @@
 	return (__force __be16)sum;
 }
 
-static void txq_submit_skb(struct tx_queue *txq, struct sk_buff *skb)
+static int txq_submit_skb(struct tx_queue *txq, struct sk_buff *skb)
 {
 	struct mv643xx_eth_private *mp = txq_to_mp(txq);
 	int nr_frags = skb_shinfo(skb)->nr_frags;
 	int tx_index;
 	struct tx_desc *desc;
 	u32 cmd_sts;
+	u16 l4i_chk;
 	int length;
 
 	cmd_sts = TX_FIRST_DESC | GEN_CRC | BUFFER_OWNED_BY_DMA;
+	l4i_chk = 0;
+
+	if (skb->ip_summed == CHECKSUM_PARTIAL) {
+		int tag_bytes;
+
+		BUG_ON(skb->protocol != htons(ETH_P_IP) &&
+		       skb->protocol != htons(ETH_P_8021Q));
+
+		tag_bytes = (void *)ip_hdr(skb) - (void *)skb->data - ETH_HLEN;
+		if (unlikely(tag_bytes & ~12)) {
+			if (skb_checksum_help(skb) == 0)
+				goto no_csum;
+			kfree_skb(skb);
+			return 1;
+		}
+
+		if (tag_bytes & 4)
+			cmd_sts |= MAC_HDR_EXTRA_4_BYTES;
+		if (tag_bytes & 8)
+			cmd_sts |= MAC_HDR_EXTRA_8_BYTES;
+
+		cmd_sts |= GEN_TCP_UDP_CHECKSUM |
+			   GEN_IP_V4_CHECKSUM   |
+			   ip_hdr(skb)->ihl << TX_IHL_SHIFT;
+
+		switch (ip_hdr(skb)->protocol) {
+		case IPPROTO_UDP:
+			cmd_sts |= UDP_FRAME;
+			l4i_chk = ntohs(sum16_as_be(udp_hdr(skb)->check));
+			break;
+		case IPPROTO_TCP:
+			l4i_chk = ntohs(sum16_as_be(tcp_hdr(skb)->check));
+			break;
+		default:
+			BUG();
+		}
+	} else {
+no_csum:
+		/* Errata BTS #50, IHL must be 5 if no HW checksum */
+		cmd_sts |= 5 << TX_IHL_SHIFT;
+	}
 
 	tx_index = txq_alloc_desc_index(txq);
 	desc = &txq->tx_desc_area[tx_index];
 
 	if (nr_frags) {
 		txq_submit_frag_skb(txq, skb);
-
 		length = skb_headlen(skb);
-		txq->tx_skb[tx_index] = NULL;
 	} else {
 		cmd_sts |= ZERO_PADDING | TX_LAST_DESC | TX_ENABLE_INTERRUPT;
 		length = skb->len;
-		txq->tx_skb[tx_index] = skb;
 	}
 
+	desc->l4i_chk = l4i_chk;
 	desc->byte_cnt = length;
 	desc->buf_ptr = dma_map_single(NULL, skb->data, length, DMA_TO_DEVICE);
 
-	if (skb->ip_summed == CHECKSUM_PARTIAL) {
-		int mac_hdr_len;
-
-		BUG_ON(skb->protocol != htons(ETH_P_IP) &&
-		       skb->protocol != htons(ETH_P_8021Q));
-
-		cmd_sts |= GEN_TCP_UDP_CHECKSUM |
-			   GEN_IP_V4_CHECKSUM   |
-			   ip_hdr(skb)->ihl << TX_IHL_SHIFT;
-
-		mac_hdr_len = (void *)ip_hdr(skb) - (void *)skb->data;
-		switch (mac_hdr_len - ETH_HLEN) {
-		case 0:
-			break;
-		case 4:
-			cmd_sts |= MAC_HDR_EXTRA_4_BYTES;
-			break;
-		case 8:
-			cmd_sts |= MAC_HDR_EXTRA_8_BYTES;
-			break;
-		case 12:
-			cmd_sts |= MAC_HDR_EXTRA_4_BYTES;
-			cmd_sts |= MAC_HDR_EXTRA_8_BYTES;
-			break;
-		default:
-			if (net_ratelimit())
-				dev_printk(KERN_ERR, &txq_to_mp(txq)->dev->dev,
-				   "mac header length is %d?!\n", mac_hdr_len);
-			break;
-		}
-
-		switch (ip_hdr(skb)->protocol) {
-		case IPPROTO_UDP:
-			cmd_sts |= UDP_FRAME;
-			desc->l4i_chk = ntohs(sum16_as_be(udp_hdr(skb)->check));
-			break;
-		case IPPROTO_TCP:
-			desc->l4i_chk = ntohs(sum16_as_be(tcp_hdr(skb)->check));
-			break;
-		default:
-			BUG();
-		}
-	} else {
-		/* Errata BTS #50, IHL must be 5 if no HW checksum */
-		cmd_sts |= 5 << TX_IHL_SHIFT;
-		desc->l4i_chk = 0;
-	}
+	__skb_queue_tail(&txq->tx_skb, skb);
 
 	/* ensure all other descriptors are written before first cmd_sts */
 	wmb();
 	desc->cmd_sts = cmd_sts;
 
-	/* clear TX_END interrupt status */
-	wrl(mp, INT_CAUSE(mp->port_num), ~(INT_TX_END_0 << txq->index));
-	rdl(mp, INT_CAUSE(mp->port_num));
+	/* clear TX_END status */
+	mp->work_tx_end &= ~(1 << txq->index);
 
 	/* ensure all descriptors are written before poking hardware */
 	wmb();
 	txq_enable(txq);
 
 	txq->tx_desc_count += nr_frags + 1;
+
+	return 0;
 }
 
 static int mv643xx_eth_xmit(struct sk_buff *skb, struct net_device *dev)
 {
 	struct mv643xx_eth_private *mp = netdev_priv(dev);
-	struct net_device_stats *stats = &dev->stats;
+	int queue;
 	struct tx_queue *txq;
-	unsigned long flags;
+	struct netdev_queue *nq;
+
+	queue = skb_get_queue_mapping(skb);
+	txq = mp->txq + queue;
+	nq = netdev_get_tx_queue(dev, queue);
 
 	if (has_tiny_unaligned_frags(skb) && __skb_linearize(skb)) {
-		stats->tx_dropped++;
+		txq->tx_dropped++;
 		dev_printk(KERN_DEBUG, &dev->dev,
 			   "failed to linearize skb with tiny "
 			   "unaligned fragment\n");
 		return NETDEV_TX_BUSY;
 	}
 
-	spin_lock_irqsave(&mp->lock, flags);
-
-	txq = mp->txq + mp->txq_primary;
-
-	if (txq->tx_ring_size - txq->tx_desc_count < MAX_DESCS_PER_SKB) {
-		spin_unlock_irqrestore(&mp->lock, flags);
-		if (txq->index == mp->txq_primary && net_ratelimit())
-			dev_printk(KERN_ERR, &dev->dev,
-				   "primary tx queue full?!\n");
+	if (txq->tx_ring_size - txq->tx_desc_count < MAX_SKB_FRAGS + 1) {
+		if (net_ratelimit())
+			dev_printk(KERN_ERR, &dev->dev, "tx queue full?!\n");
 		kfree_skb(skb);
 		return NETDEV_TX_OK;
 	}
 
-	txq_submit_skb(txq, skb);
-	stats->tx_bytes += skb->len;
-	stats->tx_packets++;
-	dev->trans_start = jiffies;
-
-	if (txq->index == mp->txq_primary) {
+	if (!txq_submit_skb(txq, skb)) {
 		int entries_left;
 
+		txq->tx_bytes += skb->len;
+		txq->tx_packets++;
+		dev->trans_start = jiffies;
+
 		entries_left = txq->tx_ring_size - txq->tx_desc_count;
-		if (entries_left < MAX_DESCS_PER_SKB)
-			netif_stop_queue(dev);
+		if (entries_left < MAX_SKB_FRAGS + 1)
+			netif_tx_stop_queue(nq);
 	}
 
-	spin_unlock_irqrestore(&mp->lock, flags);
-
 	return NETDEV_TX_OK;
 }
 
 
+/* tx napi ******************************************************************/
+static void txq_kick(struct tx_queue *txq)
+{
+	struct mv643xx_eth_private *mp = txq_to_mp(txq);
+	struct netdev_queue *nq = netdev_get_tx_queue(mp->dev, txq->index);
+	u32 hw_desc_ptr;
+	u32 expected_ptr;
+
+	__netif_tx_lock(nq, smp_processor_id());
+
+	if (rdl(mp, TXQ_COMMAND(mp->port_num)) & (1 << txq->index))
+		goto out;
+
+	hw_desc_ptr = rdl(mp, TXQ_CURRENT_DESC_PTR(mp->port_num, txq->index));
+	expected_ptr = (u32)txq->tx_desc_dma +
+				txq->tx_curr_desc * sizeof(struct tx_desc);
+
+	if (hw_desc_ptr != expected_ptr)
+		txq_enable(txq);
+
+out:
+	__netif_tx_unlock(nq);
+
+	mp->work_tx_end &= ~(1 << txq->index);
+}
+
+static int txq_reclaim(struct tx_queue *txq, int budget, int force)
+{
+	struct mv643xx_eth_private *mp = txq_to_mp(txq);
+	struct netdev_queue *nq = netdev_get_tx_queue(mp->dev, txq->index);
+	int reclaimed;
+
+	__netif_tx_lock(nq, smp_processor_id());
+
+	reclaimed = 0;
+	while (reclaimed < budget && txq->tx_desc_count > 0) {
+		int tx_index;
+		struct tx_desc *desc;
+		u32 cmd_sts;
+		struct sk_buff *skb;
+
+		tx_index = txq->tx_used_desc;
+		desc = &txq->tx_desc_area[tx_index];
+		cmd_sts = desc->cmd_sts;
+
+		if (cmd_sts & BUFFER_OWNED_BY_DMA) {
+			if (!force)
+				break;
+			desc->cmd_sts = cmd_sts & ~BUFFER_OWNED_BY_DMA;
+		}
+
+		txq->tx_used_desc = tx_index + 1;
+		if (txq->tx_used_desc == txq->tx_ring_size)
+			txq->tx_used_desc = 0;
+
+		reclaimed++;
+		txq->tx_desc_count--;
+
+		skb = NULL;
+		if (cmd_sts & TX_LAST_DESC)
+			skb = __skb_dequeue(&txq->tx_skb);
+
+		if (cmd_sts & ERROR_SUMMARY) {
+			dev_printk(KERN_INFO, &mp->dev->dev, "tx error\n");
+			mp->dev->stats.tx_errors++;
+		}
+
+		if (cmd_sts & TX_FIRST_DESC) {
+			dma_unmap_single(NULL, desc->buf_ptr,
+					 desc->byte_cnt, DMA_TO_DEVICE);
+		} else {
+			dma_unmap_page(NULL, desc->buf_ptr,
+				       desc->byte_cnt, DMA_TO_DEVICE);
+		}
+
+		if (skb != NULL) {
+			if (skb_queue_len(&mp->rx_recycle) <
+					mp->default_rx_ring_size &&
+			    skb_recycle_check(skb, mp->skb_size))
+				__skb_queue_head(&mp->rx_recycle, skb);
+			else
+				dev_kfree_skb(skb);
+		}
+	}
+
+	__netif_tx_unlock(nq);
+
+	if (reclaimed < budget)
+		mp->work_tx &= ~(1 << txq->index);
+
+	return reclaimed;
+}
+
+
 /* tx rate control **********************************************************/
 /*
  * Set total maximum TX rate (shared by all TX queues for this port)
@@ -895,14 +938,17 @@
 	if (bucket_size > 65535)
 		bucket_size = 65535;
 
-	if (mp->shared->tx_bw_control_moved) {
-		wrl(mp, TX_BW_RATE_MOVED(mp->port_num), token_rate);
-		wrl(mp, TX_BW_MTU_MOVED(mp->port_num), mtu);
-		wrl(mp, TX_BW_BURST_MOVED(mp->port_num), bucket_size);
-	} else {
+	switch (mp->shared->tx_bw_control) {
+	case TX_BW_CONTROL_OLD_LAYOUT:
 		wrl(mp, TX_BW_RATE(mp->port_num), token_rate);
 		wrl(mp, TX_BW_MTU(mp->port_num), mtu);
 		wrl(mp, TX_BW_BURST(mp->port_num), bucket_size);
+		break;
+	case TX_BW_CONTROL_NEW_LAYOUT:
+		wrl(mp, TX_BW_RATE_MOVED(mp->port_num), token_rate);
+		wrl(mp, TX_BW_MTU_MOVED(mp->port_num), mtu);
+		wrl(mp, TX_BW_BURST_MOVED(mp->port_num), bucket_size);
+		break;
 	}
 }
 
@@ -934,14 +980,21 @@
 	/*
 	 * Turn on fixed priority mode.
 	 */
-	if (mp->shared->tx_bw_control_moved)
-		off = TXQ_FIX_PRIO_CONF_MOVED(mp->port_num);
-	else
+	off = 0;
+	switch (mp->shared->tx_bw_control) {
+	case TX_BW_CONTROL_OLD_LAYOUT:
 		off = TXQ_FIX_PRIO_CONF(mp->port_num);
+		break;
+	case TX_BW_CONTROL_NEW_LAYOUT:
+		off = TXQ_FIX_PRIO_CONF_MOVED(mp->port_num);
+		break;
+	}
 
-	val = rdl(mp, off);
-	val |= 1 << txq->index;
-	wrl(mp, off, val);
+	if (off) {
+		val = rdl(mp, off);
+		val |= 1 << txq->index;
+		wrl(mp, off, val);
+	}
 }
 
 static void txq_set_wrr(struct tx_queue *txq, int weight)
@@ -953,95 +1006,147 @@
 	/*
 	 * Turn off fixed priority mode.
 	 */
-	if (mp->shared->tx_bw_control_moved)
-		off = TXQ_FIX_PRIO_CONF_MOVED(mp->port_num);
-	else
+	off = 0;
+	switch (mp->shared->tx_bw_control) {
+	case TX_BW_CONTROL_OLD_LAYOUT:
 		off = TXQ_FIX_PRIO_CONF(mp->port_num);
+		break;
+	case TX_BW_CONTROL_NEW_LAYOUT:
+		off = TXQ_FIX_PRIO_CONF_MOVED(mp->port_num);
+		break;
+	}
 
-	val = rdl(mp, off);
-	val &= ~(1 << txq->index);
-	wrl(mp, off, val);
+	if (off) {
+		val = rdl(mp, off);
+		val &= ~(1 << txq->index);
+		wrl(mp, off, val);
 
-	/*
-	 * Configure WRR weight for this queue.
-	 */
-	off = TXQ_BW_WRR_CONF(mp->port_num, txq->index);
+		/*
+		 * Configure WRR weight for this queue.
+		 */
+		off = TXQ_BW_WRR_CONF(mp->port_num, txq->index);
 
-	val = rdl(mp, off);
-	val = (val & ~0xff) | (weight & 0xff);
-	wrl(mp, off, val);
+		val = rdl(mp, off);
+		val = (val & ~0xff) | (weight & 0xff);
+		wrl(mp, off, val);
+	}
 }
 
 
 /* mii management interface *************************************************/
-#define SMI_BUSY		0x10000000
-#define SMI_READ_VALID		0x08000000
-#define SMI_OPCODE_READ		0x04000000
-#define SMI_OPCODE_WRITE	0x00000000
-
-static void smi_reg_read(struct mv643xx_eth_private *mp, unsigned int addr,
-			 unsigned int reg, unsigned int *value)
+static irqreturn_t mv643xx_eth_err_irq(int irq, void *dev_id)
 {
-	void __iomem *smi_reg = mp->shared_smi->base + SMI_REG;
-	unsigned long flags;
-	int i;
+	struct mv643xx_eth_shared_private *msp = dev_id;
 
-	/* the SMI register is a shared resource */
-	spin_lock_irqsave(&mp->shared_smi->phy_lock, flags);
+	if (readl(msp->base + ERR_INT_CAUSE) & ERR_INT_SMI_DONE) {
+		writel(~ERR_INT_SMI_DONE, msp->base + ERR_INT_CAUSE);
+		wake_up(&msp->smi_busy_wait);
+		return IRQ_HANDLED;
+	}
 
-	/* wait for the SMI register to become available */
-	for (i = 0; readl(smi_reg) & SMI_BUSY; i++) {
-		if (i == 1000) {
-			printk("%s: PHY busy timeout\n", mp->dev->name);
-			goto out;
+	return IRQ_NONE;
+}
+
+static int smi_is_done(struct mv643xx_eth_shared_private *msp)
+{
+	return !(readl(msp->base + SMI_REG) & SMI_BUSY);
+}
+
+static int smi_wait_ready(struct mv643xx_eth_shared_private *msp)
+{
+	if (msp->err_interrupt == NO_IRQ) {
+		int i;
+
+		for (i = 0; !smi_is_done(msp); i++) {
+			if (i == 10)
+				return -ETIMEDOUT;
+			msleep(10);
 		}
-		udelay(10);
+
+		return 0;
+	}
+
+	if (!wait_event_timeout(msp->smi_busy_wait, smi_is_done(msp),
+				msecs_to_jiffies(100)))
+		return -ETIMEDOUT;
+
+	return 0;
+}
+
+static int smi_bus_read(struct mii_bus *bus, int addr, int reg)
+{
+	struct mv643xx_eth_shared_private *msp = bus->priv;
+	void __iomem *smi_reg = msp->base + SMI_REG;
+	int ret;
+
+	if (smi_wait_ready(msp)) {
+		printk("mv643xx_eth: SMI bus busy timeout\n");
+		return -ETIMEDOUT;
 	}
 
 	writel(SMI_OPCODE_READ | (reg << 21) | (addr << 16), smi_reg);
 
-	/* now wait for the data to be valid */
-	for (i = 0; !(readl(smi_reg) & SMI_READ_VALID); i++) {
-		if (i == 1000) {
-			printk("%s: PHY read timeout\n", mp->dev->name);
-			goto out;
-		}
-		udelay(10);
+	if (smi_wait_ready(msp)) {
+		printk("mv643xx_eth: SMI bus busy timeout\n");
+		return -ETIMEDOUT;
 	}
 
-	*value = readl(smi_reg) & 0xffff;
-out:
-	spin_unlock_irqrestore(&mp->shared_smi->phy_lock, flags);
+	ret = readl(smi_reg);
+	if (!(ret & SMI_READ_VALID)) {
+		printk("mv643xx_eth: SMI bus read not valid\n");
+		return -ENODEV;
+	}
+
+	return ret & 0xffff;
 }
 
-static void smi_reg_write(struct mv643xx_eth_private *mp,
-			  unsigned int addr,
-			  unsigned int reg, unsigned int value)
+static int smi_bus_write(struct mii_bus *bus, int addr, int reg, u16 val)
 {
-	void __iomem *smi_reg = mp->shared_smi->base + SMI_REG;
-	unsigned long flags;
-	int i;
+	struct mv643xx_eth_shared_private *msp = bus->priv;
+	void __iomem *smi_reg = msp->base + SMI_REG;
 
-	/* the SMI register is a shared resource */
-	spin_lock_irqsave(&mp->shared_smi->phy_lock, flags);
-
-	/* wait for the SMI register to become available */
-	for (i = 0; readl(smi_reg) & SMI_BUSY; i++) {
-		if (i == 1000) {
-			printk("%s: PHY busy timeout\n", mp->dev->name);
-			goto out;
-		}
-		udelay(10);
+	if (smi_wait_ready(msp)) {
+		printk("mv643xx_eth: SMI bus busy timeout\n");
+		return -ETIMEDOUT;
 	}
 
 	writel(SMI_OPCODE_WRITE | (reg << 21) |
-		(addr << 16) | (value & 0xffff), smi_reg);
-out:
-	spin_unlock_irqrestore(&mp->shared_smi->phy_lock, flags);
+		(addr << 16) | (val & 0xffff), smi_reg);
+
+	if (smi_wait_ready(msp)) {
+		printk("mv643xx_eth: SMI bus busy timeout\n");
+		return -ETIMEDOUT;
+	}
+
+	return 0;
 }
 
 
-/* mib counters *************************************************************/
+/* statistics ***************************************************************/
+static struct net_device_stats *mv643xx_eth_get_stats(struct net_device *dev)
+{
+	struct mv643xx_eth_private *mp = netdev_priv(dev);
+	struct net_device_stats *stats = &dev->stats;
+	unsigned long tx_packets = 0;
+	unsigned long tx_bytes = 0;
+	unsigned long tx_dropped = 0;
+	int i;
+
+	for (i = 0; i < mp->txq_count; i++) {
+		struct tx_queue *txq = mp->txq + i;
+
+		tx_packets += txq->tx_packets;
+		tx_bytes += txq->tx_bytes;
+		tx_dropped += txq->tx_dropped;
+	}
+
+	stats->tx_packets = tx_packets;
+	stats->tx_bytes = tx_bytes;
+	stats->tx_dropped = tx_dropped;
+
+	return stats;
+}
+
 static inline u32 mib_read(struct mv643xx_eth_private *mp, int offset)
 {
 	return rdl(mp, MIB_COUNTERS(mp->port_num) + offset);
@@ -1059,6 +1164,7 @@
 {
 	struct mib_counters *p = &mp->mib_counters;
 
+	spin_lock(&mp->mib_counters_lock);
 	p->good_octets_received += mib_read(mp, 0x00);
 	p->good_octets_received += (u64)mib_read(mp, 0x04) << 32;
 	p->bad_octets_received += mib_read(mp, 0x08);
@@ -1091,6 +1197,16 @@
 	p->bad_crc_event += mib_read(mp, 0x74);
 	p->collision += mib_read(mp, 0x78);
 	p->late_collision += mib_read(mp, 0x7c);
+	spin_unlock(&mp->mib_counters_lock);
+
+	mod_timer(&mp->mib_counters_timer, jiffies + 30 * HZ);
+}
+
+static void mib_counters_timer_wrapper(unsigned long _mp)
+{
+	struct mv643xx_eth_private *mp = (void *)_mp;
+
+	mib_counters_update(mp);
 }
 
 
@@ -1156,9 +1272,9 @@
 	struct mv643xx_eth_private *mp = netdev_priv(dev);
 	int err;
 
-	spin_lock_irq(&mp->lock);
-	err = mii_ethtool_gset(&mp->mii, cmd);
-	spin_unlock_irq(&mp->lock);
+	err = phy_read_status(mp->phy);
+	if (err == 0)
+		err = phy_ethtool_gset(mp->phy, cmd);
 
 	/*
 	 * The MAC does not support 1000baseT_Half.
@@ -1206,18 +1322,13 @@
 static int mv643xx_eth_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 {
 	struct mv643xx_eth_private *mp = netdev_priv(dev);
-	int err;
 
 	/*
 	 * The MAC does not support 1000baseT_Half.
 	 */
 	cmd->advertising &= ~ADVERTISED_1000baseT_Half;
 
-	spin_lock_irq(&mp->lock);
-	err = mii_ethtool_sset(&mp->mii, cmd);
-	spin_unlock_irq(&mp->lock);
-
-	return err;
+	return phy_ethtool_sset(mp->phy, cmd);
 }
 
 static int mv643xx_eth_set_settings_phyless(struct net_device *dev, struct ethtool_cmd *cmd)
@@ -1239,7 +1350,7 @@
 {
 	struct mv643xx_eth_private *mp = netdev_priv(dev);
 
-	return mii_nway_restart(&mp->mii);
+	return genphy_restart_aneg(mp->phy);
 }
 
 static int mv643xx_eth_nway_reset_phyless(struct net_device *dev)
@@ -1249,14 +1360,7 @@
 
 static u32 mv643xx_eth_get_link(struct net_device *dev)
 {
-	struct mv643xx_eth_private *mp = netdev_priv(dev);
-
-	return mii_link_ok(&mp->mii);
-}
-
-static u32 mv643xx_eth_get_link_phyless(struct net_device *dev)
-{
-	return 1;
+	return !!netif_carrier_ok(dev);
 }
 
 static void mv643xx_eth_get_strings(struct net_device *dev,
@@ -1277,9 +1381,10 @@
 					  struct ethtool_stats *stats,
 					  uint64_t *data)
 {
-	struct mv643xx_eth_private *mp = dev->priv;
+	struct mv643xx_eth_private *mp = netdev_priv(dev);
 	int i;
 
+	mv643xx_eth_get_stats(dev);
 	mib_counters_update(mp);
 
 	for (i = 0; i < ARRAY_SIZE(mv643xx_eth_stats); i++) {
@@ -1323,7 +1428,7 @@
 	.set_settings		= mv643xx_eth_set_settings_phyless,
 	.get_drvinfo		= mv643xx_eth_get_drvinfo,
 	.nway_reset		= mv643xx_eth_nway_reset_phyless,
-	.get_link		= mv643xx_eth_get_link_phyless,
+	.get_link		= mv643xx_eth_get_link,
 	.set_sg			= ethtool_op_set_sg,
 	.get_strings		= mv643xx_eth_get_strings,
 	.get_ethtool_stats	= mv643xx_eth_get_ethtool_stats,
@@ -1487,7 +1592,7 @@
 
 	size = rxq->rx_ring_size * sizeof(struct rx_desc);
 
-	if (index == mp->rxq_primary && size <= mp->rx_desc_sram_size) {
+	if (index == 0 && size <= mp->rx_desc_sram_size) {
 		rxq->rx_desc_area = ioremap(mp->rx_desc_sram_addr,
 						mp->rx_desc_sram_size);
 		rxq->rx_desc_dma = mp->rx_desc_sram_addr;
@@ -1515,20 +1620,21 @@
 
 	rx_desc = (struct rx_desc *)rxq->rx_desc_area;
 	for (i = 0; i < rxq->rx_ring_size; i++) {
-		int nexti = (i + 1) % rxq->rx_ring_size;
+		int nexti;
+
+		nexti = i + 1;
+		if (nexti == rxq->rx_ring_size)
+			nexti = 0;
+
 		rx_desc[i].next_desc_ptr = rxq->rx_desc_dma +
 					nexti * sizeof(struct rx_desc);
 	}
 
-	init_timer(&rxq->rx_oom);
-	rxq->rx_oom.data = (unsigned long)rxq;
-	rxq->rx_oom.function = rxq_refill_timer_wrapper;
-
 	return 0;
 
 
 out_free:
-	if (index == mp->rxq_primary && size <= mp->rx_desc_sram_size)
+	if (index == 0 && size <= mp->rx_desc_sram_size)
 		iounmap(rxq->rx_desc_area);
 	else
 		dma_free_coherent(NULL, size,
@@ -1546,8 +1652,6 @@
 
 	rxq_disable(rxq);
 
-	del_timer_sync(&rxq->rx_oom);
-
 	for (i = 0; i < rxq->rx_ring_size; i++) {
 		if (rxq->rx_skb[i]) {
 			dev_kfree_skb(rxq->rx_skb[i]);
@@ -1561,7 +1665,7 @@
 			   rxq->rx_desc_count);
 	}
 
-	if (rxq->index == mp->rxq_primary &&
+	if (rxq->index == 0 &&
 	    rxq->rx_desc_area_size <= mp->rx_desc_sram_size)
 		iounmap(rxq->rx_desc_area);
 	else
@@ -1588,7 +1692,7 @@
 
 	size = txq->tx_ring_size * sizeof(struct tx_desc);
 
-	if (index == mp->txq_primary && size <= mp->tx_desc_sram_size) {
+	if (index == 0 && size <= mp->tx_desc_sram_size) {
 		txq->tx_desc_area = ioremap(mp->tx_desc_sram_addr,
 						mp->tx_desc_sram_size);
 		txq->tx_desc_dma = mp->tx_desc_sram_addr;
@@ -1601,97 +1705,29 @@
 	if (txq->tx_desc_area == NULL) {
 		dev_printk(KERN_ERR, &mp->dev->dev,
 			   "can't allocate tx ring (%d bytes)\n", size);
-		goto out;
+		return -ENOMEM;
 	}
 	memset(txq->tx_desc_area, 0, size);
 
 	txq->tx_desc_area_size = size;
-	txq->tx_skb = kmalloc(txq->tx_ring_size * sizeof(*txq->tx_skb),
-								GFP_KERNEL);
-	if (txq->tx_skb == NULL) {
-		dev_printk(KERN_ERR, &mp->dev->dev,
-			   "can't allocate tx skb ring\n");
-		goto out_free;
-	}
 
 	tx_desc = (struct tx_desc *)txq->tx_desc_area;
 	for (i = 0; i < txq->tx_ring_size; i++) {
 		struct tx_desc *txd = tx_desc + i;
-		int nexti = (i + 1) % txq->tx_ring_size;
+		int nexti;
+
+		nexti = i + 1;
+		if (nexti == txq->tx_ring_size)
+			nexti = 0;
 
 		txd->cmd_sts = 0;
 		txd->next_desc_ptr = txq->tx_desc_dma +
 					nexti * sizeof(struct tx_desc);
 	}
 
+	skb_queue_head_init(&txq->tx_skb);
+
 	return 0;
-
-
-out_free:
-	if (index == mp->txq_primary && size <= mp->tx_desc_sram_size)
-		iounmap(txq->tx_desc_area);
-	else
-		dma_free_coherent(NULL, size,
-				  txq->tx_desc_area,
-				  txq->tx_desc_dma);
-
-out:
-	return -ENOMEM;
-}
-
-static void txq_reclaim(struct tx_queue *txq, int force)
-{
-	struct mv643xx_eth_private *mp = txq_to_mp(txq);
-	unsigned long flags;
-
-	spin_lock_irqsave(&mp->lock, flags);
-	while (txq->tx_desc_count > 0) {
-		int tx_index;
-		struct tx_desc *desc;
-		u32 cmd_sts;
-		struct sk_buff *skb;
-		dma_addr_t addr;
-		int count;
-
-		tx_index = txq->tx_used_desc;
-		desc = &txq->tx_desc_area[tx_index];
-		cmd_sts = desc->cmd_sts;
-
-		if (cmd_sts & BUFFER_OWNED_BY_DMA) {
-			if (!force)
-				break;
-			desc->cmd_sts = cmd_sts & ~BUFFER_OWNED_BY_DMA;
-		}
-
-		txq->tx_used_desc = (tx_index + 1) % txq->tx_ring_size;
-		txq->tx_desc_count--;
-
-		addr = desc->buf_ptr;
-		count = desc->byte_cnt;
-		skb = txq->tx_skb[tx_index];
-		txq->tx_skb[tx_index] = NULL;
-
-		if (cmd_sts & ERROR_SUMMARY) {
-			dev_printk(KERN_INFO, &mp->dev->dev, "tx error\n");
-			mp->dev->stats.tx_errors++;
-		}
-
-		/*
-		 * Drop mp->lock while we free the skb.
-		 */
-		spin_unlock_irqrestore(&mp->lock, flags);
-
-		if (cmd_sts & TX_FIRST_DESC)
-			dma_unmap_single(NULL, addr, count, DMA_TO_DEVICE);
-		else
-			dma_unmap_page(NULL, addr, count, DMA_TO_DEVICE);
-
-		if (skb)
-			dev_kfree_skb_irq(skb);
-
-		spin_lock_irqsave(&mp->lock, flags);
-	}
-	spin_unlock_irqrestore(&mp->lock, flags);
 }
 
 static void txq_deinit(struct tx_queue *txq)
@@ -1699,22 +1735,67 @@
 	struct mv643xx_eth_private *mp = txq_to_mp(txq);
 
 	txq_disable(txq);
-	txq_reclaim(txq, 1);
+	txq_reclaim(txq, txq->tx_ring_size, 1);
 
 	BUG_ON(txq->tx_used_desc != txq->tx_curr_desc);
 
-	if (txq->index == mp->txq_primary &&
+	if (txq->index == 0 &&
 	    txq->tx_desc_area_size <= mp->tx_desc_sram_size)
 		iounmap(txq->tx_desc_area);
 	else
 		dma_free_coherent(NULL, txq->tx_desc_area_size,
 				  txq->tx_desc_area, txq->tx_desc_dma);
-
-	kfree(txq->tx_skb);
 }
 
 
 /* netdev ops and related ***************************************************/
+static int mv643xx_eth_collect_events(struct mv643xx_eth_private *mp)
+{
+	u32 int_cause;
+	u32 int_cause_ext;
+
+	int_cause = rdl(mp, INT_CAUSE(mp->port_num)) &
+			(INT_TX_END | INT_RX | INT_EXT);
+	if (int_cause == 0)
+		return 0;
+
+	int_cause_ext = 0;
+	if (int_cause & INT_EXT)
+		int_cause_ext = rdl(mp, INT_CAUSE_EXT(mp->port_num));
+
+	int_cause &= INT_TX_END | INT_RX;
+	if (int_cause) {
+		wrl(mp, INT_CAUSE(mp->port_num), ~int_cause);
+		mp->work_tx_end |= ((int_cause & INT_TX_END) >> 19) &
+				~(rdl(mp, TXQ_COMMAND(mp->port_num)) & 0xff);
+		mp->work_rx |= (int_cause & INT_RX) >> 2;
+	}
+
+	int_cause_ext &= INT_EXT_LINK_PHY | INT_EXT_TX;
+	if (int_cause_ext) {
+		wrl(mp, INT_CAUSE_EXT(mp->port_num), ~int_cause_ext);
+		if (int_cause_ext & INT_EXT_LINK_PHY)
+			mp->work_link = 1;
+		mp->work_tx |= int_cause_ext & INT_EXT_TX;
+	}
+
+	return 1;
+}
+
+static irqreturn_t mv643xx_eth_irq(int irq, void *dev_id)
+{
+	struct net_device *dev = (struct net_device *)dev_id;
+	struct mv643xx_eth_private *mp = netdev_priv(dev);
+
+	if (unlikely(!mv643xx_eth_collect_events(mp)))
+		return IRQ_NONE;
+
+	wrl(mp, INT_MASK(mp->port_num), 0);
+	napi_schedule(&mp->napi);
+
+	return IRQ_HANDLED;
+}
+
 static void handle_link_event(struct mv643xx_eth_private *mp)
 {
 	struct net_device *dev = mp->dev;
@@ -1731,15 +1812,12 @@
 			printk(KERN_INFO "%s: link down\n", dev->name);
 
 			netif_carrier_off(dev);
-			netif_stop_queue(dev);
 
-			for (i = 0; i < 8; i++) {
+			for (i = 0; i < mp->txq_count; i++) {
 				struct tx_queue *txq = mp->txq + i;
 
-				if (mp->txq_mask & (1 << i)) {
-					txq_reclaim(txq, 1);
-					txq_reset_hw_ptr(txq);
-				}
+				txq_reclaim(txq, txq->tx_ring_size, 1);
+				txq_reset_hw_ptr(txq);
 			}
 		}
 		return;
@@ -1767,119 +1845,93 @@
 			 speed, duplex ? "full" : "half",
 			 fc ? "en" : "dis");
 
-	if (!netif_carrier_ok(dev)) {
+	if (!netif_carrier_ok(dev))
 		netif_carrier_on(dev);
-		netif_wake_queue(dev);
-	}
 }
 
-static irqreturn_t mv643xx_eth_irq(int irq, void *dev_id)
+static int mv643xx_eth_poll(struct napi_struct *napi, int budget)
 {
-	struct net_device *dev = (struct net_device *)dev_id;
-	struct mv643xx_eth_private *mp = netdev_priv(dev);
-	u32 int_cause;
-	u32 int_cause_ext;
+	struct mv643xx_eth_private *mp;
+	int work_done;
 
-	int_cause = rdl(mp, INT_CAUSE(mp->port_num)) &
-			(INT_TX_END | INT_RX | INT_EXT);
-	if (int_cause == 0)
-		return IRQ_NONE;
+	mp = container_of(napi, struct mv643xx_eth_private, napi);
 
-	int_cause_ext = 0;
-	if (int_cause & INT_EXT) {
-		int_cause_ext = rdl(mp, INT_CAUSE_EXT(mp->port_num))
-				& (INT_EXT_LINK | INT_EXT_PHY | INT_EXT_TX);
-		wrl(mp, INT_CAUSE_EXT(mp->port_num), ~int_cause_ext);
-	}
+	mp->work_rx_refill |= mp->work_rx_oom;
+	mp->work_rx_oom = 0;
 
-	if (int_cause_ext & (INT_EXT_PHY | INT_EXT_LINK))
-		handle_link_event(mp);
+	work_done = 0;
+	while (work_done < budget) {
+		u8 queue_mask;
+		int queue;
+		int work_tbd;
 
-	/*
-	 * RxBuffer or RxError set for any of the 8 queues?
-	 */
-#ifdef MV643XX_ETH_NAPI
-	if (int_cause & INT_RX) {
-		wrl(mp, INT_CAUSE(mp->port_num), ~(int_cause & INT_RX));
-		wrl(mp, INT_MASK(mp->port_num), 0x00000000);
-		rdl(mp, INT_MASK(mp->port_num));
-
-		netif_rx_schedule(dev, &mp->napi);
-	}
-#else
-	if (int_cause & INT_RX) {
-		int i;
-
-		for (i = 7; i >= 0; i--)
-			if (mp->rxq_mask & (1 << i))
-				rxq_process(mp->rxq + i, INT_MAX);
-	}
-#endif
-
-	/*
-	 * TxBuffer or TxError set for any of the 8 queues?
-	 */
-	if (int_cause_ext & INT_EXT_TX) {
-		int i;
-
-		for (i = 0; i < 8; i++)
-			if (mp->txq_mask & (1 << i))
-				txq_reclaim(mp->txq + i, 0);
-
-		/*
-		 * Enough space again in the primary TX queue for a
-		 * full packet?
-		 */
-		if (netif_carrier_ok(dev)) {
-			spin_lock(&mp->lock);
-			__txq_maybe_wake(mp->txq + mp->txq_primary);
-			spin_unlock(&mp->lock);
+		if (mp->work_link) {
+			mp->work_link = 0;
+			handle_link_event(mp);
+			continue;
 		}
-	}
 
-	/*
-	 * Any TxEnd interrupts?
-	 */
-	if (int_cause & INT_TX_END) {
-		int i;
-
-		wrl(mp, INT_CAUSE(mp->port_num), ~(int_cause & INT_TX_END));
-
-		spin_lock(&mp->lock);
-		for (i = 0; i < 8; i++) {
-			struct tx_queue *txq = mp->txq + i;
-			u32 hw_desc_ptr;
-			u32 expected_ptr;
-
-			if ((int_cause & (INT_TX_END_0 << i)) == 0)
+		queue_mask = mp->work_tx | mp->work_tx_end |
+				mp->work_rx | mp->work_rx_refill;
+		if (!queue_mask) {
+			if (mv643xx_eth_collect_events(mp))
 				continue;
-
-			hw_desc_ptr =
-				rdl(mp, TXQ_CURRENT_DESC_PTR(mp->port_num, i));
-			expected_ptr = (u32)txq->tx_desc_dma +
-				txq->tx_curr_desc * sizeof(struct tx_desc);
-
-			if (hw_desc_ptr != expected_ptr)
-				txq_enable(txq);
+			break;
 		}
-		spin_unlock(&mp->lock);
+
+		queue = fls(queue_mask) - 1;
+		queue_mask = 1 << queue;
+
+		work_tbd = budget - work_done;
+		if (work_tbd > 16)
+			work_tbd = 16;
+
+		if (mp->work_tx_end & queue_mask) {
+			txq_kick(mp->txq + queue);
+		} else if (mp->work_tx & queue_mask) {
+			work_done += txq_reclaim(mp->txq + queue, work_tbd, 0);
+			txq_maybe_wake(mp->txq + queue);
+		} else if (mp->work_rx & queue_mask) {
+			work_done += rxq_process(mp->rxq + queue, work_tbd);
+		} else if (mp->work_rx_refill & queue_mask) {
+			work_done += rxq_refill(mp->rxq + queue, work_tbd);
+		} else {
+			BUG();
+		}
 	}
 
-	return IRQ_HANDLED;
+	if (work_done < budget) {
+		if (mp->work_rx_oom)
+			mod_timer(&mp->rx_oom, jiffies + (HZ / 10));
+		napi_complete(napi);
+		wrl(mp, INT_MASK(mp->port_num), INT_TX_END | INT_RX | INT_EXT);
+	}
+
+	return work_done;
+}
+
+static inline void oom_timer_wrapper(unsigned long data)
+{
+	struct mv643xx_eth_private *mp = (void *)data;
+
+	napi_schedule(&mp->napi);
 }
 
 static void phy_reset(struct mv643xx_eth_private *mp)
 {
-	unsigned int data;
+	int data;
 
-	smi_reg_read(mp, mp->phy_addr, MII_BMCR, &data);
+	data = phy_read(mp->phy, MII_BMCR);
+	if (data < 0)
+		return;
+
 	data |= BMCR_RESET;
-	smi_reg_write(mp, mp->phy_addr, MII_BMCR, data);
+	if (phy_write(mp->phy, MII_BMCR, data) < 0)
+		return;
 
 	do {
-		udelay(1);
-		smi_reg_read(mp, mp->phy_addr, MII_BMCR, &data);
-	} while (data & BMCR_RESET);
+		data = phy_read(mp->phy, MII_BMCR);
+	} while (data >= 0 && data & BMCR_RESET);
 }
 
 static void port_start(struct mv643xx_eth_private *mp)
@@ -1890,7 +1942,7 @@
 	/*
 	 * Perform PHY reset, if there is a PHY.
 	 */
-	if (mp->phy_addr != -1) {
+	if (mp->phy != NULL) {
 		struct ethtool_cmd cmd;
 
 		mv643xx_eth_get_settings(mp->dev, &cmd);
@@ -1907,7 +1959,7 @@
 	wrl(mp, PORT_SERIAL_CONTROL(mp->port_num), pscr);
 
 	pscr |= DO_NOT_FORCE_LINK_FAIL;
-	if (mp->phy_addr == -1)
+	if (mp->phy == NULL)
 		pscr |= FORCE_LINK_PASS;
 	wrl(mp, PORT_SERIAL_CONTROL(mp->port_num), pscr);
 
@@ -1917,12 +1969,9 @@
 	 * Configure TX path and queues.
 	 */
 	tx_set_rate(mp, 1000000000, 16777216);
-	for (i = 0; i < 8; i++) {
+	for (i = 0; i < mp->txq_count; i++) {
 		struct tx_queue *txq = mp->txq + i;
 
-		if ((mp->txq_mask & (1 << i)) == 0)
-			continue;
-
 		txq_reset_hw_ptr(txq);
 		txq_set_rate(txq, 1000000000, 16777216);
 		txq_set_fixed_prio_mode(txq);
@@ -1935,9 +1984,10 @@
 
 	/*
 	 * Receive all unmatched unicast, TCP, UDP, BPDU and broadcast
-	 * frames to RX queue #0.
+	 * frames to RX queue #0, and include the pseudo-header when
+	 * calculating receive checksums.
 	 */
-	wrl(mp, PORT_CONFIG(mp->port_num), 0x00000000);
+	wrl(mp, PORT_CONFIG(mp->port_num), 0x02000000);
 
 	/*
 	 * Treat BPDUs as normal multicasts, and disable partition mode.
@@ -1947,14 +1997,11 @@
 	/*
 	 * Enable the receive queues.
 	 */
-	for (i = 0; i < 8; i++) {
+	for (i = 0; i < mp->rxq_count; i++) {
 		struct rx_queue *rxq = mp->rxq + i;
 		int off = RXQ_CURRENT_DESC_PTR(mp->port_num, i);
 		u32 addr;
 
-		if ((mp->rxq_mask & (1 << i)) == 0)
-			continue;
-
 		addr = (u32)rxq->rx_desc_dma;
 		addr += rxq->rx_curr_desc * sizeof(struct rx_desc);
 		wrl(mp, off, addr);
@@ -1993,6 +2040,26 @@
 	wrl(mp, TX_FIFO_URGENT_THRESHOLD(mp->port_num), (coal & 0x3fff) << 4);
 }
 
+static void mv643xx_eth_recalc_skb_size(struct mv643xx_eth_private *mp)
+{
+	int skb_size;
+
+	/*
+	 * Reserve 2+14 bytes for an ethernet header (the hardware
+	 * automatically prepends 2 bytes of dummy data to each
+	 * received packet), 16 bytes for up to four VLAN tags, and
+	 * 4 bytes for the trailing FCS -- 36 bytes total.
+	 */
+	skb_size = mp->dev->mtu + 36;
+
+	/*
+	 * Make sure that the skb size is a multiple of 8 bytes, as
+	 * the lower three bits of the receive descriptor's buffer
+	 * size field are ignored by the hardware.
+	 */
+	mp->skb_size = (skb_size + 7) & ~7;
+}
+
 static int mv643xx_eth_open(struct net_device *dev)
 {
 	struct mv643xx_eth_private *mp = netdev_priv(dev);
@@ -2004,8 +2071,7 @@
 	rdl(mp, INT_CAUSE_EXT(mp->port_num));
 
 	err = request_irq(dev->irq, mv643xx_eth_irq,
-			  IRQF_SHARED | IRQF_SAMPLE_RANDOM,
-			  dev->name, dev);
+			  IRQF_SHARED, dev->name, dev);
 	if (err) {
 		dev_printk(KERN_ERR, &dev->dev, "can't assign irq\n");
 		return -EAGAIN;
@@ -2013,58 +2079,53 @@
 
 	init_mac_tables(mp);
 
-	for (i = 0; i < 8; i++) {
-		if ((mp->rxq_mask & (1 << i)) == 0)
-			continue;
+	mv643xx_eth_recalc_skb_size(mp);
 
+	napi_enable(&mp->napi);
+
+	skb_queue_head_init(&mp->rx_recycle);
+
+	for (i = 0; i < mp->rxq_count; i++) {
 		err = rxq_init(mp, i);
 		if (err) {
 			while (--i >= 0)
-				if (mp->rxq_mask & (1 << i))
-					rxq_deinit(mp->rxq + i);
+				rxq_deinit(mp->rxq + i);
 			goto out;
 		}
 
-		rxq_refill(mp->rxq + i);
+		rxq_refill(mp->rxq + i, INT_MAX);
 	}
 
-	for (i = 0; i < 8; i++) {
-		if ((mp->txq_mask & (1 << i)) == 0)
-			continue;
+	if (mp->work_rx_oom) {
+		mp->rx_oom.expires = jiffies + (HZ / 10);
+		add_timer(&mp->rx_oom);
+	}
 
+	for (i = 0; i < mp->txq_count; i++) {
 		err = txq_init(mp, i);
 		if (err) {
 			while (--i >= 0)
-				if (mp->txq_mask & (1 << i))
-					txq_deinit(mp->txq + i);
+				txq_deinit(mp->txq + i);
 			goto out_free;
 		}
 	}
 
-#ifdef MV643XX_ETH_NAPI
-	napi_enable(&mp->napi);
-#endif
-
 	netif_carrier_off(dev);
-	netif_stop_queue(dev);
 
 	port_start(mp);
 
 	set_rx_coal(mp, 0);
 	set_tx_coal(mp, 0);
 
-	wrl(mp, INT_MASK_EXT(mp->port_num),
-	    INT_EXT_LINK | INT_EXT_PHY | INT_EXT_TX);
-
+	wrl(mp, INT_MASK_EXT(mp->port_num), INT_EXT_LINK_PHY | INT_EXT_TX);
 	wrl(mp, INT_MASK(mp->port_num), INT_TX_END | INT_RX | INT_EXT);
 
 	return 0;
 
 
 out_free:
-	for (i = 0; i < 8; i++)
-		if (mp->rxq_mask & (1 << i))
-			rxq_deinit(mp->rxq + i);
+	for (i = 0; i < mp->rxq_count; i++)
+		rxq_deinit(mp->rxq + i);
 out:
 	free_irq(dev->irq, dev);
 
@@ -2076,12 +2137,10 @@
 	unsigned int data;
 	int i;
 
-	for (i = 0; i < 8; i++) {
-		if (mp->rxq_mask & (1 << i))
-			rxq_disable(mp->rxq + i);
-		if (mp->txq_mask & (1 << i))
-			txq_disable(mp->txq + i);
-	}
+	for (i = 0; i < mp->rxq_count; i++)
+		rxq_disable(mp->rxq + i);
+	for (i = 0; i < mp->txq_count; i++)
+		txq_disable(mp->txq + i);
 
 	while (1) {
 		u32 ps = rdl(mp, PORT_STATUS(mp->port_num));
@@ -2107,23 +2166,26 @@
 	wrl(mp, INT_MASK(mp->port_num), 0x00000000);
 	rdl(mp, INT_MASK(mp->port_num));
 
-#ifdef MV643XX_ETH_NAPI
+	del_timer_sync(&mp->mib_counters_timer);
+
 	napi_disable(&mp->napi);
-#endif
+
+	del_timer_sync(&mp->rx_oom);
+
 	netif_carrier_off(dev);
-	netif_stop_queue(dev);
 
 	free_irq(dev->irq, dev);
 
 	port_reset(mp);
+	mv643xx_eth_get_stats(dev);
 	mib_counters_update(mp);
 
-	for (i = 0; i < 8; i++) {
-		if (mp->rxq_mask & (1 << i))
-			rxq_deinit(mp->rxq + i);
-		if (mp->txq_mask & (1 << i))
-			txq_deinit(mp->txq + i);
-	}
+	skb_queue_purge(&mp->rx_recycle);
+
+	for (i = 0; i < mp->rxq_count; i++)
+		rxq_deinit(mp->rxq + i);
+	for (i = 0; i < mp->txq_count; i++)
+		txq_deinit(mp->txq + i);
 
 	return 0;
 }
@@ -2132,8 +2194,8 @@
 {
 	struct mv643xx_eth_private *mp = netdev_priv(dev);
 
-	if (mp->phy_addr != -1)
-		return generic_mii_ioctl(&mp->mii, if_mii(ifr), cmd, NULL);
+	if (mp->phy != NULL)
+		return phy_mii_ioctl(mp->phy, if_mii(ifr), cmd);
 
 	return -EOPNOTSUPP;
 }
@@ -2146,6 +2208,7 @@
 		return -EINVAL;
 
 	dev->mtu = new_mtu;
+	mv643xx_eth_recalc_skb_size(mp);
 	tx_set_rate(mp, 1000000000, 16777216);
 
 	if (!netif_running(dev))
@@ -2173,12 +2236,10 @@
 
 	mp = container_of(ugly, struct mv643xx_eth_private, tx_timeout_task);
 	if (netif_running(mp->dev)) {
-		netif_stop_queue(mp->dev);
-
+		netif_tx_stop_all_queues(mp->dev);
 		port_reset(mp);
 		port_start(mp);
-
-		__txq_maybe_wake(mp->txq + mp->txq_primary);
+		netif_tx_wake_all_queues(mp->dev);
 	}
 }
 
@@ -2205,22 +2266,6 @@
 }
 #endif
 
-static int mv643xx_eth_mdio_read(struct net_device *dev, int addr, int reg)
-{
-	struct mv643xx_eth_private *mp = netdev_priv(dev);
-	int val;
-
-	smi_reg_read(mp, addr, reg, &val);
-
-	return val;
-}
-
-static void mv643xx_eth_mdio_write(struct net_device *dev, int addr, int reg, int val)
-{
-	struct mv643xx_eth_private *mp = netdev_priv(dev);
-	smi_reg_write(mp, addr, reg, val);
-}
-
 
 /* platform glue ************************************************************/
 static void
@@ -2272,14 +2317,20 @@
 		msp->extended_rx_coal_limit = 0;
 
 	/*
-	 * Check whether the TX rate control registers are in the
-	 * old or the new place.
+	 * Check whether the MAC supports TX rate control, and if
+	 * yes, whether its associated registers are in the old or
+	 * the new place.
 	 */
 	writel(1, msp->base + TX_BW_MTU_MOVED(0));
-	if (readl(msp->base + TX_BW_MTU_MOVED(0)) & 1)
-		msp->tx_bw_control_moved = 1;
-	else
-		msp->tx_bw_control_moved = 0;
+	if (readl(msp->base + TX_BW_MTU_MOVED(0)) & 1) {
+		msp->tx_bw_control = TX_BW_CONTROL_NEW_LAYOUT;
+	} else {
+		writel(7, msp->base + TX_BW_RATE(0));
+		if (readl(msp->base + TX_BW_RATE(0)) & 7)
+			msp->tx_bw_control = TX_BW_CONTROL_OLD_LAYOUT;
+		else
+			msp->tx_bw_control = TX_BW_CONTROL_ABSENT;
+	}
 }
 
 static int mv643xx_eth_shared_probe(struct platform_device *pdev)
@@ -2309,7 +2360,45 @@
 	if (msp->base == NULL)
 		goto out_free;
 
-	spin_lock_init(&msp->phy_lock);
+	/*
+	 * Set up and register SMI bus.
+	 */
+	if (pd == NULL || pd->shared_smi == NULL) {
+		msp->smi_bus = mdiobus_alloc();
+		if (msp->smi_bus == NULL)
+			goto out_unmap;
+
+		msp->smi_bus->priv = msp;
+		msp->smi_bus->name = "mv643xx_eth smi";
+		msp->smi_bus->read = smi_bus_read;
+		msp->smi_bus->write = smi_bus_write,
+		snprintf(msp->smi_bus->id, MII_BUS_ID_SIZE, "%d", pdev->id);
+		msp->smi_bus->parent = &pdev->dev;
+		msp->smi_bus->phy_mask = 0xffffffff;
+		if (mdiobus_register(msp->smi_bus) < 0)
+			goto out_free_mii_bus;
+		msp->smi = msp;
+	} else {
+		msp->smi = platform_get_drvdata(pd->shared_smi);
+	}
+
+	msp->err_interrupt = NO_IRQ;
+	init_waitqueue_head(&msp->smi_busy_wait);
+
+	/*
+	 * Check whether the error interrupt is hooked up.
+	 */
+	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+	if (res != NULL) {
+		int err;
+
+		err = request_irq(res->start, mv643xx_eth_err_irq,
+				  IRQF_SHARED, "mv643xx_eth", msp);
+		if (!err) {
+			writel(ERR_INT_SMI_DONE, msp->base + ERR_INT_MASK);
+			msp->err_interrupt = res->start;
+		}
+	}
 
 	/*
 	 * (Re-)program MBUS remapping windows if we are asked to.
@@ -2327,6 +2416,10 @@
 
 	return 0;
 
+out_free_mii_bus:
+	mdiobus_free(msp->smi_bus);
+out_unmap:
+	iounmap(msp->base);
 out_free:
 	kfree(msp);
 out:
@@ -2336,7 +2429,14 @@
 static int mv643xx_eth_shared_remove(struct platform_device *pdev)
 {
 	struct mv643xx_eth_shared_private *msp = platform_get_drvdata(pdev);
+	struct mv643xx_eth_shared_platform_data *pd = pdev->dev.platform_data;
 
+	if (pd == NULL || pd->shared_smi == NULL) {
+		mdiobus_free(msp->smi_bus);
+		mdiobus_unregister(msp->smi_bus);
+	}
+	if (msp->err_interrupt != NO_IRQ)
+		free_irq(msp->err_interrupt, msp);
 	iounmap(msp->base);
 	kfree(msp);
 
@@ -2382,33 +2482,13 @@
 	else
 		uc_addr_get(mp, dev->dev_addr);
 
-	if (pd->phy_addr == -1) {
-		mp->shared_smi = NULL;
-		mp->phy_addr = -1;
-	} else {
-		mp->shared_smi = mp->shared;
-		if (pd->shared_smi != NULL)
-			mp->shared_smi = platform_get_drvdata(pd->shared_smi);
-
-		if (pd->force_phy_addr || pd->phy_addr) {
-			mp->phy_addr = pd->phy_addr & 0x3f;
-			phy_addr_set(mp, mp->phy_addr);
-		} else {
-			mp->phy_addr = phy_addr_get(mp);
-		}
-	}
-
 	mp->default_rx_ring_size = DEFAULT_RX_QUEUE_SIZE;
 	if (pd->rx_queue_size)
 		mp->default_rx_ring_size = pd->rx_queue_size;
 	mp->rx_desc_sram_addr = pd->rx_sram_addr;
 	mp->rx_desc_sram_size = pd->rx_sram_size;
 
-	if (pd->rx_queue_mask)
-		mp->rxq_mask = pd->rx_queue_mask;
-	else
-		mp->rxq_mask = 0x01;
-	mp->rxq_primary = fls(mp->rxq_mask) - 1;
+	mp->rxq_count = pd->rx_queue_count ? : 1;
 
 	mp->default_tx_ring_size = DEFAULT_TX_QUEUE_SIZE;
 	if (pd->tx_queue_size)
@@ -2416,76 +2496,63 @@
 	mp->tx_desc_sram_addr = pd->tx_sram_addr;
 	mp->tx_desc_sram_size = pd->tx_sram_size;
 
-	if (pd->tx_queue_mask)
-		mp->txq_mask = pd->tx_queue_mask;
-	else
-		mp->txq_mask = 0x01;
-	mp->txq_primary = fls(mp->txq_mask) - 1;
+	mp->txq_count = pd->tx_queue_count ? : 1;
 }
 
-static int phy_detect(struct mv643xx_eth_private *mp)
+static struct phy_device *phy_scan(struct mv643xx_eth_private *mp,
+				   int phy_addr)
 {
-	unsigned int data;
-	unsigned int data2;
+	struct mii_bus *bus = mp->shared->smi->smi_bus;
+	struct phy_device *phydev;
+	int start;
+	int num;
+	int i;
 
-	smi_reg_read(mp, mp->phy_addr, MII_BMCR, &data);
-	smi_reg_write(mp, mp->phy_addr, MII_BMCR, data ^ BMCR_ANENABLE);
-
-	smi_reg_read(mp, mp->phy_addr, MII_BMCR, &data2);
-	if (((data ^ data2) & BMCR_ANENABLE) == 0)
-		return -ENODEV;
-
-	smi_reg_write(mp, mp->phy_addr, MII_BMCR, data);
-
-	return 0;
-}
-
-static int phy_init(struct mv643xx_eth_private *mp,
-		    struct mv643xx_eth_platform_data *pd)
-{
-	struct ethtool_cmd cmd;
-	int err;
-
-	err = phy_detect(mp);
-	if (err) {
-		dev_printk(KERN_INFO, &mp->dev->dev,
-			   "no PHY detected at addr %d\n", mp->phy_addr);
-		return err;
+	if (phy_addr == MV643XX_ETH_PHY_ADDR_DEFAULT) {
+		start = phy_addr_get(mp) & 0x1f;
+		num = 32;
+	} else {
+		start = phy_addr & 0x1f;
+		num = 1;
 	}
+
+	phydev = NULL;
+	for (i = 0; i < num; i++) {
+		int addr = (start + i) & 0x1f;
+
+		if (bus->phy_map[addr] == NULL)
+			mdiobus_scan(bus, addr);
+
+		if (phydev == NULL) {
+			phydev = bus->phy_map[addr];
+			if (phydev != NULL)
+				phy_addr_set(mp, addr);
+		}
+	}
+
+	return phydev;
+}
+
+static void phy_init(struct mv643xx_eth_private *mp, int speed, int duplex)
+{
+	struct phy_device *phy = mp->phy;
+
 	phy_reset(mp);
 
-	mp->mii.phy_id = mp->phy_addr;
-	mp->mii.phy_id_mask = 0x3f;
-	mp->mii.reg_num_mask = 0x1f;
-	mp->mii.dev = mp->dev;
-	mp->mii.mdio_read = mv643xx_eth_mdio_read;
-	mp->mii.mdio_write = mv643xx_eth_mdio_write;
+	phy_attach(mp->dev, phy->dev.bus_id, 0, PHY_INTERFACE_MODE_GMII);
 
-	mp->mii.supports_gmii = mii_check_gmii_support(&mp->mii);
-
-	memset(&cmd, 0, sizeof(cmd));
-
-	cmd.port = PORT_MII;
-	cmd.transceiver = XCVR_INTERNAL;
-	cmd.phy_address = mp->phy_addr;
-	if (pd->speed == 0) {
-		cmd.autoneg = AUTONEG_ENABLE;
-		cmd.speed = SPEED_100;
-		cmd.advertising = ADVERTISED_10baseT_Half  |
-				  ADVERTISED_10baseT_Full  |
-				  ADVERTISED_100baseT_Half |
-				  ADVERTISED_100baseT_Full;
-		if (mp->mii.supports_gmii)
-			cmd.advertising |= ADVERTISED_1000baseT_Full;
+	if (speed == 0) {
+		phy->autoneg = AUTONEG_ENABLE;
+		phy->speed = 0;
+		phy->duplex = 0;
+		phy->advertising = phy->supported | ADVERTISED_Autoneg;
 	} else {
-		cmd.autoneg = AUTONEG_DISABLE;
-		cmd.speed = pd->speed;
-		cmd.duplex = pd->duplex;
+		phy->autoneg = AUTONEG_DISABLE;
+		phy->advertising = 0;
+		phy->speed = speed;
+		phy->duplex = duplex;
 	}
-
-	mv643xx_eth_set_settings(mp->dev, &cmd);
-
-	return 0;
+	phy_start_aneg(phy);
 }
 
 static void init_pscr(struct mv643xx_eth_private *mp, int speed, int duplex)
@@ -2499,7 +2566,7 @@
 	}
 
 	pscr = MAX_RX_PACKET_9700BYTE | SERIAL_PORT_CONTROL_RESERVED;
-	if (mp->phy_addr == -1) {
+	if (mp->phy == NULL) {
 		pscr |= DISABLE_AUTO_NEG_SPEED_GMII;
 		if (speed == SPEED_1000)
 			pscr |= SET_GMII_SPEED_TO_1000;
@@ -2538,7 +2605,7 @@
 		return -ENODEV;
 	}
 
-	dev = alloc_etherdev(sizeof(struct mv643xx_eth_private));
+	dev = alloc_etherdev_mq(sizeof(struct mv643xx_eth_private), 8);
 	if (!dev)
 		return -ENOMEM;
 
@@ -2549,33 +2616,47 @@
 	mp->port_num = pd->port_number;
 
 	mp->dev = dev;
-#ifdef MV643XX_ETH_NAPI
-	netif_napi_add(dev, &mp->napi, mv643xx_eth_poll, 64);
-#endif
 
 	set_params(mp, pd);
+	dev->real_num_tx_queues = mp->txq_count;
 
-	spin_lock_init(&mp->lock);
+	if (pd->phy_addr != MV643XX_ETH_PHY_NONE)
+		mp->phy = phy_scan(mp, pd->phy_addr);
 
-	mib_counters_clear(mp);
-	INIT_WORK(&mp->tx_timeout_task, tx_timeout_task);
-
-	if (mp->phy_addr != -1) {
-		err = phy_init(mp, pd);
-		if (err)
-			goto out;
-
+	if (mp->phy != NULL) {
+		phy_init(mp, pd->speed, pd->duplex);
 		SET_ETHTOOL_OPS(dev, &mv643xx_eth_ethtool_ops);
 	} else {
 		SET_ETHTOOL_OPS(dev, &mv643xx_eth_ethtool_ops_phyless);
 	}
+
 	init_pscr(mp, pd->speed, pd->duplex);
 
 
+	mib_counters_clear(mp);
+
+	init_timer(&mp->mib_counters_timer);
+	mp->mib_counters_timer.data = (unsigned long)mp;
+	mp->mib_counters_timer.function = mib_counters_timer_wrapper;
+	mp->mib_counters_timer.expires = jiffies + 30 * HZ;
+	add_timer(&mp->mib_counters_timer);
+
+	spin_lock_init(&mp->mib_counters_lock);
+
+	INIT_WORK(&mp->tx_timeout_task, tx_timeout_task);
+
+	netif_napi_add(dev, &mp->napi, mv643xx_eth_poll, 128);
+
+	init_timer(&mp->rx_oom);
+	mp->rx_oom.data = (unsigned long)mp;
+	mp->rx_oom.function = oom_timer_wrapper;
+
+
 	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
 	BUG_ON(!res);
 	dev->irq = res->start;
 
+	dev->get_stats = mv643xx_eth_get_stats;
 	dev->hard_start_xmit = mv643xx_eth_xmit;
 	dev->open = mv643xx_eth_open;
 	dev->stop = mv643xx_eth_stop;
@@ -2590,14 +2671,8 @@
 	dev->watchdog_timeo = 2 * HZ;
 	dev->base_addr = 0;
 
-#ifdef MV643XX_ETH_CHECKSUM_OFFLOAD_TX
-	/*
-	 * Zero copy can only work if we use Discovery II memory. Else, we will
-	 * have to map the buffers to ISA memory which is only 16 MB
-	 */
 	dev->features = NETIF_F_SG | NETIF_F_IP_CSUM;
 	dev->vlan_features = NETIF_F_SG | NETIF_F_IP_CSUM;
-#endif
 
 	SET_NETDEV_DEV(dev, &pdev->dev);
 
@@ -2611,16 +2686,6 @@
 	dev_printk(KERN_NOTICE, &dev->dev, "port %d with MAC address %s\n",
 		   mp->port_num, print_mac(mac, dev->dev_addr));
 
-	if (dev->features & NETIF_F_SG)
-		dev_printk(KERN_NOTICE, &dev->dev, "scatter/gather enabled\n");
-
-	if (dev->features & NETIF_F_IP_CSUM)
-		dev_printk(KERN_NOTICE, &dev->dev, "tx checksum offload\n");
-
-#ifdef MV643XX_ETH_NAPI
-	dev_printk(KERN_NOTICE, &dev->dev, "napi enabled\n");
-#endif
-
 	if (mp->tx_desc_sram_size > 0)
 		dev_printk(KERN_NOTICE, &dev->dev, "configured with sram\n");
 
@@ -2637,6 +2702,8 @@
 	struct mv643xx_eth_private *mp = platform_get_drvdata(pdev);
 
 	unregister_netdev(mp->dev);
+	if (mp->phy != NULL)
+		phy_detach(mp->phy);
 	flush_scheduled_work();
 	free_netdev(mp->dev);
 
diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c
index d6524db..6dce901 100644
--- a/drivers/net/myri10ge/myri10ge.c
+++ b/drivers/net/myri10ge/myri10ge.c
@@ -75,7 +75,7 @@
 #include "myri10ge_mcp.h"
 #include "myri10ge_mcp_gen_header.h"
 
-#define MYRI10GE_VERSION_STR "1.4.3-1.358"
+#define MYRI10GE_VERSION_STR "1.4.3-1.369"
 
 MODULE_DESCRIPTION("Myricom 10G driver (10GbE)");
 MODULE_AUTHOR("Maintainer: help@myri.com");
@@ -102,6 +102,8 @@
 #define MYRI10GE_ALLOC_SIZE ((1 << MYRI10GE_ALLOC_ORDER) * PAGE_SIZE)
 #define MYRI10GE_MAX_FRAGS_PER_FRAME (MYRI10GE_MAX_ETHER_MTU/MYRI10GE_ALLOC_SIZE + 1)
 
+#define MYRI10GE_MAX_SLICES 32
+
 struct myri10ge_rx_buffer_state {
 	struct page *page;
 	int page_offset;
@@ -138,6 +140,8 @@
 
 struct myri10ge_tx_buf {
 	struct mcp_kreq_ether_send __iomem *lanai;	/* lanai ptr for sendq */
+	__be32 __iomem *send_go;	/* "go" doorbell ptr */
+	__be32 __iomem *send_stop;	/* "stop" doorbell ptr */
 	struct mcp_kreq_ether_send *req_list;	/* host shadow of sendq */
 	char *req_bytes;
 	struct myri10ge_tx_buffer_state *info;
@@ -149,6 +153,7 @@
 	int done ____cacheline_aligned;	/* transmit slots completed     */
 	int pkt_done;		/* packets completed */
 	int wake_queue;
+	int queue_active;
 };
 
 struct myri10ge_rx_done {
@@ -183,7 +188,7 @@
 	dma_addr_t fw_stats_bus;
 	int watchdog_tx_done;
 	int watchdog_tx_req;
-#ifdef CONFIG_DCA
+#if (defined CONFIG_DCA) || (defined CONFIG_DCA_MODULE)
 	int cached_dca_tag;
 	int cpu;
 	__be32 __iomem *dca_tag;
@@ -215,7 +220,7 @@
 	int msi_enabled;
 	int msix_enabled;
 	struct msix_entry *msix_vectors;
-#ifdef CONFIG_DCA
+#if (defined CONFIG_DCA) || (defined CONFIG_DCA_MODULE)
 	int dca_enabled;
 #endif
 	u32 link_state;
@@ -418,6 +423,12 @@
 			return -ENOSYS;
 		} else if (result == MXGEFW_CMD_ERROR_UNALIGNED) {
 			return -E2BIG;
+		} else if (result == MXGEFW_CMD_ERROR_RANGE &&
+			   cmd == MXGEFW_CMD_ENABLE_RSS_QUEUES &&
+			   (data->
+			    data1 & MXGEFW_SLICE_ENABLE_MULTIPLE_TX_QUEUES) !=
+			   0) {
+			return -ERANGE;
 		} else {
 			dev_err(&mgp->pdev->dev,
 				"command %d failed, result = %d\n",
@@ -891,7 +902,7 @@
 	struct myri10ge_slice_state *ss;
 	int i, status;
 	size_t bytes;
-#ifdef CONFIG_DCA
+#if (defined CONFIG_DCA) || (defined CONFIG_DCA_MODULE)
 	unsigned long dca_tag_off;
 #endif
 
@@ -947,9 +958,24 @@
 		 */
 
 		cmd.data0 = mgp->num_slices;
-		cmd.data1 = 1;	/* use MSI-X */
+		cmd.data1 = MXGEFW_SLICE_INTR_MODE_ONE_PER_SLICE;
+		if (mgp->dev->real_num_tx_queues > 1)
+			cmd.data1 |= MXGEFW_SLICE_ENABLE_MULTIPLE_TX_QUEUES;
 		status = myri10ge_send_cmd(mgp, MXGEFW_CMD_ENABLE_RSS_QUEUES,
 					   &cmd, 0);
+
+		/* Firmware older than 1.4.32 only supports multiple
+		 * RX queues, so if we get an error, first retry using a
+		 * single TX queue before giving up */
+		if (status != 0 && mgp->dev->real_num_tx_queues > 1) {
+			mgp->dev->real_num_tx_queues = 1;
+			cmd.data0 = mgp->num_slices;
+			cmd.data1 = MXGEFW_SLICE_INTR_MODE_ONE_PER_SLICE;
+			status = myri10ge_send_cmd(mgp,
+						   MXGEFW_CMD_ENABLE_RSS_QUEUES,
+						   &cmd, 0);
+		}
+
 		if (status != 0) {
 			dev_err(&mgp->pdev->dev,
 				"failed to set number of slices\n");
@@ -986,7 +1012,7 @@
 	}
 	put_be32(htonl(mgp->intr_coal_delay), mgp->intr_coal_delay_ptr);
 
-#ifdef CONFIG_DCA
+#if (defined CONFIG_DCA) || (defined CONFIG_DCA_MODULE)
 	status = myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_DCA_OFFSET, &cmd, 0);
 	dca_tag_off = cmd.data0;
 	for (i = 0; i < mgp->num_slices; i++) {
@@ -1025,7 +1051,7 @@
 	return status;
 }
 
-#ifdef CONFIG_DCA
+#if (defined CONFIG_DCA) || (defined CONFIG_DCA_MODULE)
 static void
 myri10ge_write_dca(struct myri10ge_slice_state *ss, int cpu, int tag)
 {
@@ -1060,8 +1086,9 @@
 	}
 	err = dca_add_requester(&pdev->dev);
 	if (err) {
-		dev_err(&pdev->dev,
-			"dca_add_requester() failed, err=%d\n", err);
+		if (err != -ENODEV)
+			dev_err(&pdev->dev,
+				"dca_add_requester() failed, err=%d\n", err);
 		return;
 	}
 	mgp->dca_enabled = 1;
@@ -1316,6 +1343,7 @@
 {
 	struct pci_dev *pdev = ss->mgp->pdev;
 	struct myri10ge_tx_buf *tx = &ss->tx;
+	struct netdev_queue *dev_queue;
 	struct sk_buff *skb;
 	int idx, len;
 
@@ -1349,11 +1377,31 @@
 					       PCI_DMA_TODEVICE);
 		}
 	}
+
+	dev_queue = netdev_get_tx_queue(ss->dev, ss - ss->mgp->ss);
+	/*
+	 * Make a minimal effort to prevent the NIC from polling an
+	 * idle tx queue.  If we can't get the lock we leave the queue
+	 * active. In this case, either a thread was about to start
+	 * using the queue anyway, or we lost a race and the NIC will
+	 * waste some of its resources polling an inactive queue for a
+	 * while.
+	 */
+
+	if ((ss->mgp->dev->real_num_tx_queues > 1) &&
+	    __netif_tx_trylock(dev_queue)) {
+		if (tx->req == tx->done) {
+			tx->queue_active = 0;
+			put_be32(htonl(1), tx->send_stop);
+		}
+		__netif_tx_unlock(dev_queue);
+	}
+
 	/* start the queue if we've stopped it */
-	if (netif_queue_stopped(ss->dev)
+	if (netif_tx_queue_stopped(dev_queue)
 	    && tx->req - tx->done < (tx->mask >> 1)) {
 		tx->wake_queue++;
-		netif_wake_queue(ss->dev);
+		netif_tx_wake_queue(dev_queue);
 	}
 }
 
@@ -1457,7 +1505,7 @@
 	struct net_device *netdev = ss->mgp->dev;
 	int work_done;
 
-#ifdef CONFIG_DCA
+#if (defined CONFIG_DCA) || (defined CONFIG_DCA_MODULE)
 	if (ss->mgp->dca_enabled)
 		myri10ge_update_dca(ss);
 #endif
@@ -1481,9 +1529,9 @@
 	u32 send_done_count;
 	int i;
 
-	/* an interrupt on a non-zero slice is implicitly valid
-	 * since MSI-X irqs are not shared */
-	if (ss != mgp->ss) {
+	/* an interrupt on a non-zero receive-only slice is implicitly
+	 * valid  since MSI-X irqs are not shared */
+	if ((mgp->dev->real_num_tx_queues == 1) && (ss != mgp->ss)) {
 		netif_rx_schedule(ss->dev, &ss->napi);
 		return (IRQ_HANDLED);
 	}
@@ -1525,7 +1573,9 @@
 		barrier();
 	}
 
-	myri10ge_check_statblock(mgp);
+	/* Only slice 0 updates stats */
+	if (ss == mgp->ss)
+		myri10ge_check_statblock(mgp);
 
 	put_be32(htonl(3), ss->irq_claim + 1);
 	return (IRQ_HANDLED);
@@ -1686,8 +1736,8 @@
 	"tx_boundary", "WC", "irq", "MSI", "MSIX",
 	"read_dma_bw_MBs", "write_dma_bw_MBs", "read_write_dma_bw_MBs",
 	"serial_number", "watchdog_resets",
-#ifdef CONFIG_DCA
-	"dca_capable", "dca_enabled",
+#if (defined CONFIG_DCA) || (defined CONFIG_DCA_MODULE)
+	"dca_capable_firmware", "dca_device_present",
 #endif
 	"link_changes", "link_up", "dropped_link_overflow",
 	"dropped_link_error_or_filtered",
@@ -1765,7 +1815,7 @@
 	data[i++] = (unsigned int)mgp->read_write_dma;
 	data[i++] = (unsigned int)mgp->serial_number;
 	data[i++] = (unsigned int)mgp->watchdog_resets;
-#ifdef CONFIG_DCA
+#if (defined CONFIG_DCA) || (defined CONFIG_DCA_MODULE)
 	data[i++] = (unsigned int)(mgp->ss[0].dca_tag != NULL);
 	data[i++] = (unsigned int)(mgp->dca_enabled);
 #endif
@@ -1883,6 +1933,7 @@
 	/* ensure req_list entries are aligned to 8 bytes */
 	ss->tx.req_list = (struct mcp_kreq_ether_send *)
 	    ALIGN((unsigned long)ss->tx.req_bytes, 8);
+	ss->tx.queue_active = 0;
 
 	bytes = rx_ring_entries * sizeof(*ss->rx_small.shadow);
 	ss->rx_small.shadow = kzalloc(bytes, GFP_KERNEL);
@@ -2200,11 +2251,14 @@
 	int status;
 
 	ss = &mgp->ss[slice];
-	cmd.data0 = 0;		/* single slice for now */
-	status = myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_SEND_OFFSET, &cmd, 0);
-	ss->tx.lanai = (struct mcp_kreq_ether_send __iomem *)
-	    (mgp->sram + cmd.data0);
-
+	status = 0;
+	if (slice == 0 || (mgp->dev->real_num_tx_queues > 1)) {
+		cmd.data0 = slice;
+		status = myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_SEND_OFFSET,
+					   &cmd, 0);
+		ss->tx.lanai = (struct mcp_kreq_ether_send __iomem *)
+		    (mgp->sram + cmd.data0);
+	}
 	cmd.data0 = slice;
 	status |= myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_SMALL_RX_OFFSET,
 				    &cmd, 0);
@@ -2216,6 +2270,10 @@
 	ss->rx_big.lanai = (struct mcp_kreq_ether_recv __iomem *)
 	    (mgp->sram + cmd.data0);
 
+	ss->tx.send_go = (__iomem __be32 *)
+	    (mgp->sram + MXGEFW_ETH_SEND_GO + 64 * slice);
+	ss->tx.send_stop = (__iomem __be32 *)
+	    (mgp->sram + MXGEFW_ETH_SEND_STOP + 64 * slice);
 	return status;
 
 }
@@ -2229,7 +2287,7 @@
 	ss = &mgp->ss[slice];
 	cmd.data0 = MYRI10GE_LOWPART_TO_U32(ss->fw_stats_bus);
 	cmd.data1 = MYRI10GE_HIGHPART_TO_U32(ss->fw_stats_bus);
-	cmd.data2 = sizeof(struct mcp_irq_data);
+	cmd.data2 = sizeof(struct mcp_irq_data) | (slice << 16);
 	status = myri10ge_send_cmd(mgp, MXGEFW_CMD_SET_STATS_DMA_V2, &cmd, 0);
 	if (status == -ENOSYS) {
 		dma_addr_t bus = ss->fw_stats_bus;
@@ -2270,7 +2328,9 @@
 
 	if (mgp->num_slices > 1) {
 		cmd.data0 = mgp->num_slices;
-		cmd.data1 = 1;	/* use MSI-X */
+		cmd.data1 = MXGEFW_SLICE_INTR_MODE_ONE_PER_SLICE;
+		if (mgp->dev->real_num_tx_queues > 1)
+			cmd.data1 |= MXGEFW_SLICE_ENABLE_MULTIPLE_TX_QUEUES;
 		status = myri10ge_send_cmd(mgp, MXGEFW_CMD_ENABLE_RSS_QUEUES,
 					   &cmd, 0);
 		if (status != 0) {
@@ -2291,6 +2351,7 @@
 			printk(KERN_ERR
 			       "myri10ge: %s: failed to setup rss tables\n",
 			       dev->name);
+			goto abort_with_nothing;
 		}
 
 		/* just enable an identity mapping */
@@ -2361,7 +2422,11 @@
 		status = myri10ge_allocate_rings(ss);
 		if (status != 0)
 			goto abort_with_rings;
-		if (slice == 0)
+
+		/* only firmware which supports multiple TX queues
+		 * supports setting up the tx stats on non-zero
+		 * slices */
+		if (slice == 0 || mgp->dev->real_num_tx_queues > 1)
 			status = myri10ge_set_stats(mgp, slice);
 		if (status) {
 			printk(KERN_ERR
@@ -2427,7 +2492,8 @@
 	mgp->running = MYRI10GE_ETH_RUNNING;
 	mgp->watchdog_timer.expires = jiffies + myri10ge_watchdog_timeout * HZ;
 	add_timer(&mgp->watchdog_timer);
-	netif_wake_queue(dev);
+	netif_tx_wake_all_queues(dev);
+
 	return 0;
 
 abort_with_rings:
@@ -2460,7 +2526,8 @@
 		napi_disable(&mgp->ss[i].napi);
 	}
 	netif_carrier_off(dev);
-	netif_stop_queue(dev);
+
+	netif_tx_stop_all_queues(dev);
 	old_down_cnt = mgp->down_cnt;
 	mb();
 	status = myri10ge_send_cmd(mgp, MXGEFW_CMD_ETHERNET_DOWN, &cmd, 0);
@@ -2565,18 +2632,21 @@
 	struct mcp_kreq_ether_send *req;
 	struct myri10ge_tx_buf *tx;
 	struct skb_frag_struct *frag;
+	struct netdev_queue *netdev_queue;
 	dma_addr_t bus;
 	u32 low;
 	__be32 high_swapped;
 	unsigned int len;
 	int idx, last_idx, avail, frag_cnt, frag_idx, count, mss, max_segments;
-	u16 pseudo_hdr_offset, cksum_offset;
+	u16 pseudo_hdr_offset, cksum_offset, queue;
 	int cum_len, seglen, boundary, rdma_count;
 	u8 flags, odd_flag;
 
-	/* always transmit through slot 0 */
-	ss = mgp->ss;
+	queue = skb_get_queue_mapping(skb);
+	ss = &mgp->ss[queue];
+	netdev_queue = netdev_get_tx_queue(mgp->dev, queue);
 	tx = &ss->tx;
+
 again:
 	req = tx->req_list;
 	avail = tx->mask - 1 - (tx->req - tx->done);
@@ -2592,7 +2662,7 @@
 	if ((unlikely(avail < max_segments))) {
 		/* we are out of transmit resources */
 		tx->stop_queue++;
-		netif_stop_queue(dev);
+		netif_tx_stop_queue(netdev_queue);
 		return 1;
 	}
 
@@ -2785,10 +2855,16 @@
 	idx = ((count - 1) + tx->req) & tx->mask;
 	tx->info[idx].last = 1;
 	myri10ge_submit_req(tx, tx->req_list, count);
+	/* if using multiple tx queues, make sure NIC polls the
+	 * current slice */
+	if ((mgp->dev->real_num_tx_queues > 1) && tx->queue_active == 0) {
+		tx->queue_active = 1;
+		put_be32(htonl(1), tx->send_go);
+	}
 	tx->pkt_start++;
 	if ((avail - count) < MXGEFW_MAX_SEND_DESC) {
 		tx->stop_queue++;
-		netif_stop_queue(dev);
+		netif_tx_stop_queue(netdev_queue);
 	}
 	dev->trans_start = jiffies;
 	return 0;
@@ -3366,20 +3442,21 @@
 		for (i = 0; i < mgp->num_slices; i++) {
 			tx = &mgp->ss[i].tx;
 			printk(KERN_INFO
-			       "myri10ge: %s: (%d): %d %d %d %d %d\n",
-			       mgp->dev->name, i, tx->req, tx->done,
-			       tx->pkt_start, tx->pkt_done,
+			       "myri10ge: %s: (%d): %d %d %d %d %d %d\n",
+			       mgp->dev->name, i, tx->queue_active, tx->req,
+			       tx->done, tx->pkt_start, tx->pkt_done,
 			       (int)ntohl(mgp->ss[i].fw_stats->
 					  send_done_count));
 			msleep(2000);
 			printk(KERN_INFO
-			       "myri10ge: %s: (%d): %d %d %d %d %d\n",
-			       mgp->dev->name, i, tx->req, tx->done,
-			       tx->pkt_start, tx->pkt_done,
+			       "myri10ge: %s: (%d): %d %d %d %d %d %d\n",
+			       mgp->dev->name, i, tx->queue_active, tx->req,
+			       tx->done, tx->pkt_start, tx->pkt_done,
 			       (int)ntohl(mgp->ss[i].fw_stats->
 					  send_done_count));
 		}
 	}
+
 	rtnl_lock();
 	myri10ge_close(mgp->dev);
 	status = myri10ge_load_firmware(mgp, 1);
@@ -3434,10 +3511,14 @@
 			/* nic seems like it might be stuck.. */
 			if (rx_pause_cnt != mgp->watchdog_pause) {
 				if (net_ratelimit())
-					printk(KERN_WARNING "myri10ge %s:"
+					printk(KERN_WARNING
+					       "myri10ge %s slice %d:"
 					       "TX paused, check link partner\n",
-					       mgp->dev->name);
+					       mgp->dev->name, i);
 			} else {
+				printk(KERN_WARNING
+				       "myri10ge %s slice %d stuck:",
+				       mgp->dev->name, i);
 				reset_needed = 1;
 			}
 		}
@@ -3652,7 +3733,7 @@
 	int status = -ENXIO;
 	int dac_enabled;
 
-	netdev = alloc_etherdev(sizeof(*mgp));
+	netdev = alloc_etherdev_mq(sizeof(*mgp), MYRI10GE_MAX_SLICES);
 	if (netdev == NULL) {
 		dev_err(dev, "Could not allocate ethernet device\n");
 		return -ENOMEM;
@@ -3757,13 +3838,13 @@
 		dev_err(&pdev->dev, "failed to alloc slice state\n");
 		goto abort_with_firmware;
 	}
-
+	netdev->real_num_tx_queues = mgp->num_slices;
 	status = myri10ge_reset(mgp);
 	if (status != 0) {
 		dev_err(&pdev->dev, "failed reset\n");
 		goto abort_with_slices;
 	}
-#ifdef CONFIG_DCA
+#if (defined CONFIG_DCA) || (defined CONFIG_DCA_MODULE)
 	myri10ge_setup_dca(mgp);
 #endif
 	pci_set_drvdata(pdev, mgp);
@@ -3781,6 +3862,7 @@
 	netdev->set_multicast_list = myri10ge_set_multicast_list;
 	netdev->set_mac_address = myri10ge_set_mac_address;
 	netdev->features = mgp->features;
+
 	if (dac_enabled)
 		netdev->features |= NETIF_F_HIGHDMA;
 
@@ -3866,7 +3948,7 @@
 	netdev = mgp->dev;
 	unregister_netdev(netdev);
 
-#ifdef CONFIG_DCA
+#if (defined CONFIG_DCA) || (defined CONFIG_DCA_MODULE)
 	myri10ge_teardown_dca(mgp);
 #endif
 	myri10ge_dummy_rdma(mgp, 0);
@@ -3911,7 +3993,7 @@
 #endif
 };
 
-#ifdef CONFIG_DCA
+#if (defined CONFIG_DCA) || (defined CONFIG_DCA_MODULE)
 static int
 myri10ge_notify_dca(struct notifier_block *nb, unsigned long event, void *p)
 {
@@ -3936,16 +4018,17 @@
 	printk(KERN_INFO "%s: Version %s\n", myri10ge_driver.name,
 	       MYRI10GE_VERSION_STR);
 
-	if (myri10ge_rss_hash > MXGEFW_RSS_HASH_TYPE_SRC_PORT ||
-	    myri10ge_rss_hash < MXGEFW_RSS_HASH_TYPE_IPV4) {
+	if (myri10ge_rss_hash > MXGEFW_RSS_HASH_TYPE_MAX) {
 		printk(KERN_ERR
 		       "%s: Illegal rssh hash type %d, defaulting to source port\n",
 		       myri10ge_driver.name, myri10ge_rss_hash);
 		myri10ge_rss_hash = MXGEFW_RSS_HASH_TYPE_SRC_PORT;
 	}
-#ifdef CONFIG_DCA
+#if (defined CONFIG_DCA) || (defined CONFIG_DCA_MODULE)
 	dca_register_notify(&myri10ge_dca_notifier);
 #endif
+	if (myri10ge_max_slices > MYRI10GE_MAX_SLICES)
+		myri10ge_max_slices = MYRI10GE_MAX_SLICES;
 
 	return pci_register_driver(&myri10ge_driver);
 }
@@ -3954,7 +4037,7 @@
 
 static __exit void myri10ge_cleanup_module(void)
 {
-#ifdef CONFIG_DCA
+#if (defined CONFIG_DCA) || (defined CONFIG_DCA_MODULE)
 	dca_unregister_notify(&myri10ge_dca_notifier);
 #endif
 	pci_unregister_driver(&myri10ge_driver);
diff --git a/drivers/net/myri_sbus.c b/drivers/net/myri_sbus.c
index 656a260..3ad7589 100644
--- a/drivers/net/myri_sbus.c
+++ b/drivers/net/myri_sbus.c
@@ -1,6 +1,6 @@
 /* myri_sbus.c: MyriCOM MyriNET SBUS card driver.
  *
- * Copyright (C) 1996, 1999, 2006 David S. Miller (davem@davemloft.net)
+ * Copyright (C) 1996, 1999, 2006, 2008 David S. Miller (davem@davemloft.net)
  */
 
 static char version[] =
@@ -22,6 +22,9 @@
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
 #include <linux/bitops.h>
+#include <linux/dma-mapping.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 
 #include <net/dst.h>
 #include <net/arp.h>
@@ -33,7 +36,6 @@
 #include <asm/dma.h>
 #include <asm/byteorder.h>
 #include <asm/idprom.h>
-#include <asm/sbus.h>
 #include <asm/openprom.h>
 #include <asm/oplib.h>
 #include <asm/auxio.h>
@@ -243,7 +245,8 @@
 			u32 dma_addr;
 
 			dma_addr = sbus_readl(&rxd->myri_scatters[0].addr);
-			sbus_unmap_single(mp->myri_sdev, dma_addr, RX_ALLOC_SIZE, SBUS_DMA_FROMDEVICE);
+			dma_unmap_single(&mp->myri_op->dev, dma_addr,
+					 RX_ALLOC_SIZE, DMA_FROM_DEVICE);
 			dev_kfree_skb(mp->rx_skbs[i]);
 			mp->rx_skbs[i] = NULL;
 		}
@@ -259,7 +262,9 @@
 			u32 dma_addr;
 
 			dma_addr = sbus_readl(&txd->myri_gathers[0].addr);
-			sbus_unmap_single(mp->myri_sdev, dma_addr, (skb->len + 3) & ~3, SBUS_DMA_TODEVICE);
+			dma_unmap_single(&mp->myri_op->dev, dma_addr,
+					 (skb->len + 3) & ~3,
+					 DMA_TO_DEVICE);
 			dev_kfree_skb(mp->tx_skbs[i]);
 			mp->tx_skbs[i] = NULL;
 		}
@@ -288,7 +293,9 @@
 		skb->dev = dev;
 		skb_put(skb, RX_ALLOC_SIZE);
 
-		dma_addr = sbus_map_single(mp->myri_sdev, skb->data, RX_ALLOC_SIZE, SBUS_DMA_FROMDEVICE);
+		dma_addr = dma_map_single(&mp->myri_op->dev,
+					  skb->data, RX_ALLOC_SIZE,
+					  DMA_FROM_DEVICE);
 		sbus_writel(dma_addr, &rxd[i].myri_scatters[0].addr);
 		sbus_writel(RX_ALLOC_SIZE, &rxd[i].myri_scatters[0].len);
 		sbus_writel(i, &rxd[i].ctx);
@@ -344,7 +351,8 @@
 
 		DTX(("SKB[%d] ", entry));
 		dma_addr = sbus_readl(&sq->myri_txd[entry].myri_gathers[0].addr);
-		sbus_unmap_single(mp->myri_sdev, dma_addr, skb->len, SBUS_DMA_TODEVICE);
+		dma_unmap_single(&mp->myri_op->dev, dma_addr,
+				 skb->len, DMA_TO_DEVICE);
 		dev_kfree_skb(skb);
 		mp->tx_skbs[entry] = NULL;
 		dev->stats.tx_packets++;
@@ -423,9 +431,9 @@
 
 		/* Check for errors. */
 		DRX(("rxd[%d]: %p len[%d] csum[%08x] ", entry, rxd, len, csum));
-		sbus_dma_sync_single_for_cpu(mp->myri_sdev,
-					     sbus_readl(&rxd->myri_scatters[0].addr),
-					     RX_ALLOC_SIZE, SBUS_DMA_FROMDEVICE);
+		dma_sync_single_for_cpu(&mp->myri_op->dev,
+					sbus_readl(&rxd->myri_scatters[0].addr),
+					RX_ALLOC_SIZE, DMA_FROM_DEVICE);
 		if (len < (ETH_HLEN + MYRI_PAD_LEN) || (skb->data[0] != MYRI_PAD_LEN)) {
 			DRX(("ERROR["));
 			dev->stats.rx_errors++;
@@ -442,10 +450,10 @@
 			drops++;
 			DRX(("DROP "));
 			dev->stats.rx_dropped++;
-			sbus_dma_sync_single_for_device(mp->myri_sdev,
-							sbus_readl(&rxd->myri_scatters[0].addr),
-							RX_ALLOC_SIZE,
-							SBUS_DMA_FROMDEVICE);
+			dma_sync_single_for_device(&mp->myri_op->dev,
+						   sbus_readl(&rxd->myri_scatters[0].addr),
+						   RX_ALLOC_SIZE,
+						   DMA_FROM_DEVICE);
 			sbus_writel(RX_ALLOC_SIZE, &rxd->myri_scatters[0].len);
 			sbus_writel(index, &rxd->ctx);
 			sbus_writel(1, &rxd->num_sg);
@@ -464,17 +472,17 @@
 				DRX(("skb_alloc(FAILED) "));
 				goto drop_it;
 			}
-			sbus_unmap_single(mp->myri_sdev,
-					  sbus_readl(&rxd->myri_scatters[0].addr),
-					  RX_ALLOC_SIZE,
-					  SBUS_DMA_FROMDEVICE);
+			dma_unmap_single(&mp->myri_op->dev,
+					 sbus_readl(&rxd->myri_scatters[0].addr),
+					 RX_ALLOC_SIZE,
+					 DMA_FROM_DEVICE);
 			mp->rx_skbs[index] = new_skb;
 			new_skb->dev = dev;
 			skb_put(new_skb, RX_ALLOC_SIZE);
-			dma_addr = sbus_map_single(mp->myri_sdev,
-						   new_skb->data,
-						   RX_ALLOC_SIZE,
-						   SBUS_DMA_FROMDEVICE);
+			dma_addr = dma_map_single(&mp->myri_op->dev,
+						  new_skb->data,
+						  RX_ALLOC_SIZE,
+						  DMA_FROM_DEVICE);
 			sbus_writel(dma_addr, &rxd->myri_scatters[0].addr);
 			sbus_writel(RX_ALLOC_SIZE, &rxd->myri_scatters[0].len);
 			sbus_writel(index, &rxd->ctx);
@@ -500,10 +508,10 @@
 
 			/* Reuse original ring buffer. */
 			DRX(("reuse "));
-			sbus_dma_sync_single_for_device(mp->myri_sdev,
-							sbus_readl(&rxd->myri_scatters[0].addr),
-							RX_ALLOC_SIZE,
-							SBUS_DMA_FROMDEVICE);
+			dma_sync_single_for_device(&mp->myri_op->dev,
+						   sbus_readl(&rxd->myri_scatters[0].addr),
+						   RX_ALLOC_SIZE,
+						   DMA_FROM_DEVICE);
 			sbus_writel(RX_ALLOC_SIZE, &rxd->myri_scatters[0].len);
 			sbus_writel(index, &rxd->ctx);
 			sbus_writel(1, &rxd->num_sg);
@@ -652,7 +660,8 @@
 		sbus_writew((skb->data[4] << 8) | skb->data[5], &txd->addr[3]);
 	}
 
-	dma_addr = sbus_map_single(mp->myri_sdev, skb->data, len, SBUS_DMA_TODEVICE);
+	dma_addr = dma_map_single(&mp->myri_op->dev, skb->data,
+				  len, DMA_TO_DEVICE);
 	sbus_writel(dma_addr, &txd->myri_gathers[0].addr);
 	sbus_writel(len, &txd->myri_gathers[0].len);
 	sbus_writel(1, &txd->num_sg);
@@ -891,30 +900,30 @@
 	.cache_update	= myri_header_cache_update,
 };
 
-static int __devinit myri_ether_init(struct sbus_dev *sdev)
+static int __devinit myri_sbus_probe(struct of_device *op, const struct of_device_id *match)
 {
-	static int num;
+	struct device_node *dp = op->node;
 	static unsigned version_printed;
 	struct net_device *dev;
-	struct myri_eth *mp;
-	unsigned char prop_buf[32];
-	int i;
 	DECLARE_MAC_BUF(mac);
+	struct myri_eth *mp;
+	const void *prop;
+	static int num;
+	int i, len;
 
-	DET(("myri_ether_init(%p,%d):\n", sdev, num));
+	DET(("myri_ether_init(%p,%d):\n", op, num));
 	dev = alloc_etherdev(sizeof(struct myri_eth));
-
 	if (!dev)
 		return -ENOMEM;
 
 	if (version_printed++ == 0)
 		printk(version);
 
-	SET_NETDEV_DEV(dev, &sdev->ofdev.dev);
+	SET_NETDEV_DEV(dev, &op->dev);
 
-	mp = (struct myri_eth *) dev->priv;
+	mp = netdev_priv(dev);
 	spin_lock_init(&mp->irq_lock);
-	mp->myri_sdev = sdev;
+	mp->myri_op = op;
 
 	/* Clean out skb arrays. */
 	for (i = 0; i < (RX_RING_SIZE + 1); i++)
@@ -924,55 +933,44 @@
 		mp->tx_skbs[i] = NULL;
 
 	/* First check for EEPROM information. */
-	i = prom_getproperty(sdev->prom_node, "myrinet-eeprom-info",
-			     (char *)&mp->eeprom, sizeof(struct myri_eeprom));
-	DET(("prom_getprop(myrinet-eeprom-info) returns %d\n", i));
-	if (i == 0 || i == -1) {
+	prop = of_get_property(dp, "myrinet-eeprom-info", &len);
+
+	if (prop)
+		memcpy(&mp->eeprom, prop, sizeof(struct myri_eeprom));
+	if (!prop) {
 		/* No eeprom property, must cook up the values ourselves. */
 		DET(("No EEPROM: "));
 		mp->eeprom.bus_type = BUS_TYPE_SBUS;
-		mp->eeprom.cpuvers = prom_getintdefault(sdev->prom_node,"cpu_version",0);
-		mp->eeprom.cval = prom_getintdefault(sdev->prom_node,"clock_value",0);
-		mp->eeprom.ramsz = prom_getintdefault(sdev->prom_node,"sram_size",0);
-		DET(("cpuvers[%d] cval[%d] ramsz[%d]\n", mp->eeprom.cpuvers,
-		     mp->eeprom.cval, mp->eeprom.ramsz));
-		if (mp->eeprom.cpuvers == 0) {
-			DET(("EEPROM: cpuvers was zero, setting to %04x\n",CPUVERS_2_3));
+		mp->eeprom.cpuvers =
+			of_getintprop_default(dp, "cpu_version", 0);
+		mp->eeprom.cval =
+			of_getintprop_default(dp, "clock_value", 0);
+		mp->eeprom.ramsz = of_getintprop_default(dp, "sram_size", 0);
+		if (!mp->eeprom.cpuvers)
 			mp->eeprom.cpuvers = CPUVERS_2_3;
-		}
-		if (mp->eeprom.cpuvers < CPUVERS_3_0) {
-			DET(("EEPROM: cpuvers < CPUVERS_3_0, clockval set to zero.\n"));
+		if (mp->eeprom.cpuvers < CPUVERS_3_0)
 			mp->eeprom.cval = 0;
-		}
-		if (mp->eeprom.ramsz == 0) {
-			DET(("EEPROM: ramsz == 0, setting to 128k\n"));
+		if (!mp->eeprom.ramsz)
 			mp->eeprom.ramsz = (128 * 1024);
-		}
-		i = prom_getproperty(sdev->prom_node, "myrinet-board-id",
-				     &prop_buf[0], 10);
-		DET(("EEPROM: prom_getprop(myrinet-board-id) returns %d\n", i));
-		if ((i != 0) && (i != -1))
-			memcpy(&mp->eeprom.id[0], &prop_buf[0], 6);
+
+		prop = of_get_property(dp, "myrinet-board-id", &len);
+		if (prop)
+			memcpy(&mp->eeprom.id[0], prop, 6);
 		else
 			set_boardid_from_idprom(mp, num);
-		i = prom_getproperty(sdev->prom_node, "fpga_version",
-				     &mp->eeprom.fvers[0], 32);
-		DET(("EEPROM: prom_getprop(fpga_version) returns %d\n", i));
-		if (i == 0 || i == -1)
+
+		prop = of_get_property(dp, "fpga_version", &len);
+		if (prop)
+			memcpy(&mp->eeprom.fvers[0], prop, 32);
+		else
 			memset(&mp->eeprom.fvers[0], 0, 32);
 
 		if (mp->eeprom.cpuvers == CPUVERS_4_1) {
-			DET(("EEPROM: cpuvers CPUVERS_4_1, "));
-			if (mp->eeprom.ramsz == (128 * 1024)) {
-				DET(("ramsize 128k, setting to 256k, "));
+			if (mp->eeprom.ramsz == (128 * 1024))
 				mp->eeprom.ramsz = (256 * 1024);
-			}
-			if ((mp->eeprom.cval==0x40414041)||(mp->eeprom.cval==0x90449044)){
-				DET(("changing cval from %08x to %08x ",
-				     mp->eeprom.cval, 0x50e450e4));
+			if ((mp->eeprom.cval == 0x40414041) ||
+			    (mp->eeprom.cval == 0x90449044))
 				mp->eeprom.cval = 0x50e450e4;
-			}
-			DET(("\n"));
 		}
 	}
 #ifdef DEBUG_DETECT
@@ -991,8 +989,8 @@
 		 * XXX only a valid version for PCI cards?  Ask feldy...
 		 */
 		DET(("Mapping regs for cpuvers < CPUVERS_4_0\n"));
-		mp->regs = sbus_ioremap(&sdev->resource[0], 0,
-					mp->reg_size, "MyriCOM Regs");
+		mp->regs = of_ioremap(&op->resource[0], 0,
+				      mp->reg_size, "MyriCOM Regs");
 		if (!mp->regs) {
 			printk("MyriCOM: Cannot map MyriCOM registers.\n");
 			goto err;
@@ -1001,13 +999,12 @@
 		mp->lregs = mp->lanai + (0x10000 * 2);
 	} else {
 		DET(("Mapping regs for cpuvers >= CPUVERS_4_0\n"));
-		mp->cregs = sbus_ioremap(&sdev->resource[0], 0,
-					 PAGE_SIZE, "MyriCOM Control Regs");
-		mp->lregs = sbus_ioremap(&sdev->resource[0], (256 * 1024),
+		mp->cregs = of_ioremap(&op->resource[0], 0,
+				       PAGE_SIZE, "MyriCOM Control Regs");
+		mp->lregs = of_ioremap(&op->resource[0], (256 * 1024),
 					 PAGE_SIZE, "MyriCOM LANAI Regs");
-		mp->lanai =
-			sbus_ioremap(&sdev->resource[0], (512 * 1024),
-				     mp->eeprom.ramsz, "MyriCOM SRAM");
+		mp->lanai = of_ioremap(&op->resource[0], (512 * 1024),
+				       mp->eeprom.ramsz, "MyriCOM SRAM");
 	}
 	DET(("Registers mapped: cregs[%p] lregs[%p] lanai[%p]\n",
 	     mp->cregs, mp->lregs, mp->lanai));
@@ -1039,16 +1036,15 @@
 	myri_reset_on(mp->cregs);
 
 	/* Get the supported DVMA burst sizes from our SBUS. */
-	mp->myri_bursts = prom_getintdefault(mp->myri_sdev->bus->prom_node,
-					     "burst-sizes", 0x00);
-
-	if (!sbus_can_burst64(sdev))
+	mp->myri_bursts = of_getintprop_default(dp->parent,
+						"burst-sizes", 0x00);
+	if (!sbus_can_burst64())
 		mp->myri_bursts &= ~(DMA_BURST64);
 
 	DET(("MYRI bursts %02x\n", mp->myri_bursts));
 
 	/* Encode SBUS interrupt level in second control register. */
-	i = prom_getint(sdev->prom_node, "interrupts");
+	i = of_getintprop_default(dp, "interrupts", 0);
 	if (i == 0)
 		i = 4;
 	DET(("prom_getint(interrupts)==%d, irqlvl set to %04x\n",
@@ -1063,7 +1059,7 @@
 	dev->tx_timeout = &myri_tx_timeout;
 	dev->watchdog_timeo = 5*HZ;
 	dev->set_multicast_list = &myri_set_multicast;
-	dev->irq = sdev->irqs[0];
+	dev->irq = op->irqs[0];
 
 	/* Register interrupt handler now. */
 	DET(("Requesting MYRIcom IRQ line.\n"));
@@ -1088,7 +1084,7 @@
 		goto err_free_irq;
 	}
 
-	dev_set_drvdata(&sdev->ofdev.dev, mp);
+	dev_set_drvdata(&op->dev, mp);
 
 	num++;
 
@@ -1105,39 +1101,31 @@
 	return -ENODEV;
 }
 
-
-static int __devinit myri_sbus_probe(struct of_device *dev, const struct of_device_id *match)
+static int __devexit myri_sbus_remove(struct of_device *op)
 {
-	struct sbus_dev *sdev = to_sbus_device(&dev->dev);
-
-	return myri_ether_init(sdev);
-}
-
-static int __devexit myri_sbus_remove(struct of_device *dev)
-{
-	struct myri_eth *mp = dev_get_drvdata(&dev->dev);
+	struct myri_eth *mp = dev_get_drvdata(&op->dev);
 	struct net_device *net_dev = mp->dev;
 
-	unregister_netdevice(net_dev);
+	unregister_netdev(net_dev);
 
 	free_irq(net_dev->irq, net_dev);
 
 	if (mp->eeprom.cpuvers < CPUVERS_4_0) {
-		sbus_iounmap(mp->regs, mp->reg_size);
+		of_iounmap(&op->resource[0], mp->regs, mp->reg_size);
 	} else {
-		sbus_iounmap(mp->cregs, PAGE_SIZE);
-		sbus_iounmap(mp->lregs, (256 * 1024));
-		sbus_iounmap(mp->lanai, (512 * 1024));
+		of_iounmap(&op->resource[0], mp->cregs, PAGE_SIZE);
+		of_iounmap(&op->resource[0], mp->lregs, (256 * 1024));
+		of_iounmap(&op->resource[0], mp->lanai, (512 * 1024));
 	}
 
 	free_netdev(net_dev);
 
-	dev_set_drvdata(&dev->dev, NULL);
+	dev_set_drvdata(&op->dev, NULL);
 
 	return 0;
 }
 
-static struct of_device_id myri_sbus_match[] = {
+static const struct of_device_id myri_sbus_match[] = {
 	{
 		.name = "MYRICOM,mlanai",
 	},
@@ -1158,7 +1146,7 @@
 
 static int __init myri_sbus_init(void)
 {
-	return of_register_driver(&myri_sbus_driver, &sbus_bus_type);
+	return of_register_driver(&myri_sbus_driver, &of_bus_type);
 }
 
 static void __exit myri_sbus_exit(void)
diff --git a/drivers/net/myri_sbus.h b/drivers/net/myri_sbus.h
index 5d93fcc..ff363e9 100644
--- a/drivers/net/myri_sbus.h
+++ b/drivers/net/myri_sbus.h
@@ -288,7 +288,7 @@
 	struct myri_eeprom		eeprom;		/* Local copy of EEPROM.      */
 	unsigned int			reg_size;	/* Size of register space.    */
 	unsigned int			shmem_base;	/* Offset to shared ram.      */
-	struct sbus_dev			*myri_sdev;	/* Our SBUS device struct.    */
+	struct of_device		*myri_op;	/* Our OF device struct.    */
 };
 
 /* We use this to acquire receive skb's that we can DMA directly into. */
diff --git a/drivers/net/natsemi.c b/drivers/net/natsemi.c
index b238ed0..f7fa394 100644
--- a/drivers/net/natsemi.c
+++ b/drivers/net/natsemi.c
@@ -612,7 +612,7 @@
 static void check_link(struct net_device *dev);
 static void netdev_timer(unsigned long data);
 static void dump_ring(struct net_device *dev);
-static void tx_timeout(struct net_device *dev);
+static void ns_tx_timeout(struct net_device *dev);
 static int alloc_ring(struct net_device *dev);
 static void refill_rx(struct net_device *dev);
 static void init_ring(struct net_device *dev);
@@ -920,7 +920,7 @@
 	dev->set_multicast_list = &set_rx_mode;
 	dev->change_mtu = &natsemi_change_mtu;
 	dev->do_ioctl = &netdev_ioctl;
-	dev->tx_timeout = &tx_timeout;
+	dev->tx_timeout = &ns_tx_timeout;
 	dev->watchdog_timeo = TX_TIMEOUT;
 
 #ifdef CONFIG_NET_POLL_CONTROLLER
@@ -1875,7 +1875,7 @@
 	}
 }
 
-static void tx_timeout(struct net_device *dev)
+static void ns_tx_timeout(struct net_device *dev)
 {
 	struct netdev_private *np = netdev_priv(dev);
 	void __iomem * ioaddr = ns_ioaddr(dev);
@@ -3232,7 +3232,7 @@
  * suspend/resume synchronization:
  * entry points:
  *   netdev_open, netdev_close, netdev_ioctl, set_rx_mode, intr_handler,
- *   start_tx, tx_timeout
+ *   start_tx, ns_tx_timeout
  *
  * No function accesses the hardware without checking np->hands_off.
  *	the check occurs under spin_lock_irq(&np->lock);
diff --git a/drivers/net/ne.c b/drivers/net/ne.c
index fa3ceca..eb681c0 100644
--- a/drivers/net/ne.c
+++ b/drivers/net/ne.c
@@ -64,6 +64,25 @@
 
 /* Do we support clones that don't adhere to 14,15 of the SAprom ? */
 #define SUPPORT_NE_BAD_CLONES
+/* 0xbad = bad sig or no reset ack */
+#define BAD 0xbad
+
+#define MAX_NE_CARDS	4	/* Max number of NE cards per module */
+static struct platform_device *pdev_ne[MAX_NE_CARDS];
+static int io[MAX_NE_CARDS];
+static int irq[MAX_NE_CARDS];
+static int bad[MAX_NE_CARDS];
+
+#ifdef MODULE
+module_param_array(io, int, NULL, 0);
+module_param_array(irq, int, NULL, 0);
+module_param_array(bad, int, NULL, 0);
+MODULE_PARM_DESC(io, "I/O base address(es),required");
+MODULE_PARM_DESC(irq, "IRQ number(s)");
+MODULE_PARM_DESC(bad, "Accept card(s) with bad signatures");
+MODULE_DESCRIPTION("NE1000/NE2000 ISA/PnP Ethernet driver");
+MODULE_LICENSE("GPL");
+#endif /* MODULE */
 
 /* Do we perform extra sanity checks on stuff ? */
 /* #define NE_SANITY_CHECK */
@@ -74,6 +93,10 @@
 /* Do we have a non std. amount of memory? (in units of 256 byte pages) */
 /* #define PACKETBUF_MEMSIZE	0x40 */
 
+/* This is set up so that no ISA autoprobe takes place. We can't guarantee
+that the ne2k probe is the last 8390 based probe to take place (as it
+is at boot) and so the probe will get confused by any other 8390 cards.
+ISA device autoprobes on a running machine are not recommended anyway. */
 #if !defined(MODULE) && (defined(CONFIG_ISA) || defined(CONFIG_M32R))
 /* Do we need a portlist for the ISA auto-probe ? */
 #define NEEDS_PORTLIST
@@ -192,8 +215,13 @@
 #endif
 
 	/* First check any supplied i/o locations. User knows best. <cough> */
-	if (base_addr > 0x1ff)	/* Check a single specified location. */
-		return ne_probe1(dev, base_addr);
+	if (base_addr > 0x1ff) {	/* Check a single specified location. */
+		int ret = ne_probe1(dev, base_addr);
+		if (ret)
+			printk(KERN_WARNING "ne.c: No NE*000 card found at "
+				"i/o = %#lx\n", base_addr);
+		return ret;
+	}
 	else if (base_addr != 0)	/* Don't probe at all. */
 		return -ENXIO;
 
@@ -214,28 +242,6 @@
 	return -ENODEV;
 }
 
-#ifndef MODULE
-struct net_device * __init ne_probe(int unit)
-{
-	struct net_device *dev = alloc_eip_netdev();
-	int err;
-
-	if (!dev)
-		return ERR_PTR(-ENOMEM);
-
-	sprintf(dev->name, "eth%d", unit);
-	netdev_boot_setup_check(dev);
-
-	err = do_ne_probe(dev);
-	if (err)
-		goto out;
-	return dev;
-out:
-	free_netdev(dev);
-	return ERR_PTR(err);
-}
-#endif
-
 static int __init ne_probe_isapnp(struct net_device *dev)
 {
 	int i;
@@ -329,7 +335,7 @@
 	   with an otherwise unused dev->mem_end value of "0xBAD" will
 	   cause the driver to skip these parts of the probe. */
 
-	bad_card = ((dev->base_addr != 0) && (dev->mem_end == 0xbad));
+	bad_card = ((dev->base_addr != 0) && (dev->mem_end == BAD));
 
 	/* Reset card. Who knows what dain-bramaged state it was left in. */
 
@@ -806,46 +812,95 @@
 static int __init ne_drv_probe(struct platform_device *pdev)
 {
 	struct net_device *dev;
+	int err, this_dev = pdev->id;
 	struct resource *res;
-	int err, irq;
-
-	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
-	irq = platform_get_irq(pdev, 0);
-	if (!res || irq < 0)
-		return -ENODEV;
 
 	dev = alloc_eip_netdev();
 	if (!dev)
 		return -ENOMEM;
-	dev->irq = irq;
-	dev->base_addr = res->start;
+
+	/* ne.c doesn't populate resources in platform_device, but
+	 * rbtx4927_ne_init and rbtx4938_ne_init do register devices
+	 * with resources.
+	 */
+	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+	if (res) {
+		dev->base_addr = res->start;
+		dev->irq = platform_get_irq(pdev, 0);
+	} else {
+		if (this_dev < 0 || this_dev >= MAX_NE_CARDS)
+			return -EINVAL;
+		dev->base_addr = io[this_dev];
+		dev->irq = irq[this_dev];
+		dev->mem_end = bad[this_dev];
+	}
 	err = do_ne_probe(dev);
 	if (err) {
 		free_netdev(dev);
 		return err;
 	}
 	platform_set_drvdata(pdev, dev);
+
+	/* Update with any values found by probing, don't update if
+	 * resources were specified.
+	 */
+	if (!res) {
+		io[this_dev] = dev->base_addr;
+		irq[this_dev] = dev->irq;
+	}
 	return 0;
 }
 
-static int __exit ne_drv_remove(struct platform_device *pdev)
+static int ne_drv_remove(struct platform_device *pdev)
 {
 	struct net_device *dev = platform_get_drvdata(pdev);
 
-	unregister_netdev(dev);
-	free_irq(dev->irq, dev);
-	release_region(dev->base_addr, NE_IO_EXTENT);
-	free_netdev(dev);
+	if (dev) {
+		struct pnp_dev *idev = (struct pnp_dev *)ei_status.priv;
+		netif_device_detach(dev);
+		unregister_netdev(dev);
+		if (idev)
+			pnp_device_detach(idev);
+		/* Careful ne_drv_remove can be called twice, once from
+		 * the platform_driver.remove and again when the
+		 * platform_device is being removed.
+		 */
+		ei_status.priv = 0;
+		free_irq(dev->irq, dev);
+		release_region(dev->base_addr, NE_IO_EXTENT);
+		free_netdev(dev);
+		platform_set_drvdata(pdev, NULL);
+	}
 	return 0;
 }
 
+/* Remove unused devices or all if true. */
+static void ne_loop_rm_unreg(int all)
+{
+	int this_dev;
+	struct platform_device *pdev;
+	for (this_dev = 0; this_dev < MAX_NE_CARDS; this_dev++) {
+		pdev = pdev_ne[this_dev];
+		/* No network device == unused */
+		if (pdev && (!platform_get_drvdata(pdev) || all)) {
+			ne_drv_remove(pdev);
+			platform_device_unregister(pdev);
+			pdev_ne[this_dev] = NULL;
+		}
+	}
+}
+
 #ifdef CONFIG_PM
 static int ne_drv_suspend(struct platform_device *pdev, pm_message_t state)
 {
 	struct net_device *dev = platform_get_drvdata(pdev);
 
-	if (netif_running(dev))
+	if (netif_running(dev)) {
+		struct pnp_dev *idev = (struct pnp_dev *)ei_status.priv;
 		netif_device_detach(dev);
+		if (idev)
+			pnp_stop_dev(idev);
+	}
 	return 0;
 }
 
@@ -854,6 +909,9 @@
 	struct net_device *dev = platform_get_drvdata(pdev);
 
 	if (netif_running(dev)) {
+		struct pnp_dev *idev = (struct pnp_dev *)ei_status.priv;
+		if (idev)
+			pnp_start_dev(idev);
 		ne_reset_8390(dev);
 		NS8390p_init(dev, 1);
 		netif_device_attach(dev);
@@ -866,7 +924,7 @@
 #endif
 
 static struct platform_driver ne_driver = {
-	.remove		= __exit_p(ne_drv_remove),
+	.remove		= ne_drv_remove,
 	.suspend	= ne_drv_suspend,
 	.resume		= ne_drv_resume,
 	.driver		= {
@@ -875,91 +933,96 @@
 	},
 };
 
+static void __init ne_add_devices(void)
+{
+	int this_dev;
+	struct platform_device *pdev;
+
+	for (this_dev = 0; this_dev < MAX_NE_CARDS; this_dev++) {
+		if (pdev_ne[this_dev])
+			continue;
+		pdev = platform_device_register_simple(
+			DRV_NAME, this_dev, NULL, 0);
+		if (IS_ERR(pdev))
+			continue;
+		pdev_ne[this_dev] = pdev;
+	}
+}
+
+#ifdef MODULE
+int __init init_module()
+{
+	int retval;
+	ne_add_devices();
+	retval = platform_driver_probe(&ne_driver, ne_drv_probe);
+	if (retval) {
+		if (io[0] == 0)
+			printk(KERN_NOTICE "ne.c: You must supply \"io=0xNNN\""
+				" value(s) for ISA cards.\n");
+		ne_loop_rm_unreg(1);
+		return retval;
+	}
+
+	/* Unregister unused platform_devices. */
+	ne_loop_rm_unreg(0);
+	return retval;
+}
+#else /* MODULE */
 static int __init ne_init(void)
 {
-	return platform_driver_probe(&ne_driver, ne_drv_probe);
+	int retval = platform_driver_probe(&ne_driver, ne_drv_probe);
+
+	/* Unregister unused platform_devices. */
+	ne_loop_rm_unreg(0);
+	return retval;
 }
+module_init(ne_init);
+
+struct net_device * __init ne_probe(int unit)
+{
+	int this_dev;
+	struct net_device *dev;
+
+	/* Find an empty slot, that is no net_device and zero io port. */
+	this_dev = 0;
+	while ((pdev_ne[this_dev] && platform_get_drvdata(pdev_ne[this_dev])) ||
+		io[this_dev]) {
+		if (++this_dev == MAX_NE_CARDS)
+			return ERR_PTR(-ENOMEM);
+	}
+
+	/* Get irq, io from kernel command line */
+	dev = alloc_eip_netdev();
+	if (!dev)
+		return ERR_PTR(-ENOMEM);
+
+	sprintf(dev->name, "eth%d", unit);
+	netdev_boot_setup_check(dev);
+
+	io[this_dev] = dev->base_addr;
+	irq[this_dev] = dev->irq;
+	bad[this_dev] = dev->mem_end;
+
+	free_netdev(dev);
+
+	ne_add_devices();
+
+	/* return the first device found */
+	for (this_dev = 0; this_dev < MAX_NE_CARDS; this_dev++) {
+		if (pdev_ne[this_dev]) {
+			dev = platform_get_drvdata(pdev_ne[this_dev]);
+			if (dev)
+				return dev;
+		}
+	}
+
+	return ERR_PTR(-ENODEV);
+}
+#endif /* MODULE */
 
 static void __exit ne_exit(void)
 {
 	platform_driver_unregister(&ne_driver);
+	ne_loop_rm_unreg(1);
 }
-
-#ifdef MODULE
-#define MAX_NE_CARDS	4	/* Max number of NE cards per module */
-static struct net_device *dev_ne[MAX_NE_CARDS];
-static int io[MAX_NE_CARDS];
-static int irq[MAX_NE_CARDS];
-static int bad[MAX_NE_CARDS];	/* 0xbad = bad sig or no reset ack */
-
-module_param_array(io, int, NULL, 0);
-module_param_array(irq, int, NULL, 0);
-module_param_array(bad, int, NULL, 0);
-MODULE_PARM_DESC(io, "I/O base address(es),required");
-MODULE_PARM_DESC(irq, "IRQ number(s)");
-MODULE_PARM_DESC(bad, "Accept card(s) with bad signatures");
-MODULE_DESCRIPTION("NE1000/NE2000 ISA/PnP Ethernet driver");
-MODULE_LICENSE("GPL");
-
-/* This is set up so that no ISA autoprobe takes place. We can't guarantee
-that the ne2k probe is the last 8390 based probe to take place (as it
-is at boot) and so the probe will get confused by any other 8390 cards.
-ISA device autoprobes on a running machine are not recommended anyway. */
-
-int __init init_module(void)
-{
-	int this_dev, found = 0;
-	int plat_found = !ne_init();
-
-	for (this_dev = 0; this_dev < MAX_NE_CARDS; this_dev++) {
-		struct net_device *dev = alloc_eip_netdev();
-		if (!dev)
-			break;
-		dev->irq = irq[this_dev];
-		dev->mem_end = bad[this_dev];
-		dev->base_addr = io[this_dev];
-		if (do_ne_probe(dev) == 0) {
-			dev_ne[found++] = dev;
-			continue;
-		}
-		free_netdev(dev);
-		if (found || plat_found)
-			break;
-		if (io[this_dev] != 0)
-			printk(KERN_WARNING "ne.c: No NE*000 card found at i/o = %#x\n", io[this_dev]);
-		else
-			printk(KERN_NOTICE "ne.c: You must supply \"io=0xNNN\" value(s) for ISA cards.\n");
-		return -ENXIO;
-	}
-	if (found || plat_found)
-		return 0;
-	return -ENODEV;
-}
-
-static void cleanup_card(struct net_device *dev)
-{
-	struct pnp_dev *idev = (struct pnp_dev *)ei_status.priv;
-	if (idev)
-		pnp_device_detach(idev);
-	free_irq(dev->irq, dev);
-	release_region(dev->base_addr, NE_IO_EXTENT);
-}
-
-void __exit cleanup_module(void)
-{
-	int this_dev;
-
-	ne_exit();
-	for (this_dev = 0; this_dev < MAX_NE_CARDS; this_dev++) {
-		struct net_device *dev = dev_ne[this_dev];
-		if (dev) {
-			unregister_netdev(dev);
-			cleanup_card(dev);
-			free_netdev(dev);
-		}
-	}
-}
-#else /* MODULE */
-module_init(ne_init);
 module_exit(ne_exit);
-#endif /* MODULE */
diff --git a/drivers/net/netx-eth.c b/drivers/net/netx-eth.c
index 3f9af75..b9bed82 100644
--- a/drivers/net/netx-eth.c
+++ b/drivers/net/netx-eth.c
@@ -189,7 +189,7 @@
 
 		if ((status & ISR_CON_HI) || (status & ISR_IND_HI))
 			printk("%s: unexpected status: 0x%08x\n",
-			    __FUNCTION__, status);
+			    __func__, status);
 
 		fill_level =
 		    readl(NETX_PFIFO_FILL_LEVEL(IND_FIFO_PORT_LO(priv->id)));
diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h
index 244ab49..f8e601c 100644
--- a/drivers/net/netxen/netxen_nic.h
+++ b/drivers/net/netxen/netxen_nic.h
@@ -742,7 +742,7 @@
 	} while (0)
 #else
 #define DPRINTK(klevel, fmt, args...)	do { \
-	printk(KERN_##klevel PFX "%s: %s: " fmt, __FUNCTION__,\
+	printk(KERN_##klevel PFX "%s: %s: " fmt, __func__,\
 		(adapter != NULL && adapter->netdev != NULL) ? \
 		adapter->netdev->name : NULL, \
 		## args); } while(0)
diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c
index 008fd66..6ef3f0d 100644
--- a/drivers/net/netxen/netxen_nic_main.c
+++ b/drivers/net/netxen/netxen_nic_main.c
@@ -77,18 +77,18 @@
 
 /*  PCI Device ID Table  */
 #define ENTRY(device) \
-	{PCI_DEVICE(0x4040, (device)), \
+	{PCI_DEVICE(PCI_VENDOR_ID_NETXEN, (device)), \
 	.class = PCI_CLASS_NETWORK_ETHERNET << 8, .class_mask = ~0}
 
 static struct pci_device_id netxen_pci_tbl[] __devinitdata = {
-	ENTRY(0x0001),
-	ENTRY(0x0002),
-	ENTRY(0x0003),
-	ENTRY(0x0004),
-	ENTRY(0x0005),
-	ENTRY(0x0024),
-	ENTRY(0x0025),
-	ENTRY(0x0100),
+	ENTRY(PCI_DEVICE_ID_NX2031_10GXSR),
+	ENTRY(PCI_DEVICE_ID_NX2031_10GCX4),
+	ENTRY(PCI_DEVICE_ID_NX2031_4GCU),
+	ENTRY(PCI_DEVICE_ID_NX2031_IMEZ),
+	ENTRY(PCI_DEVICE_ID_NX2031_HMEZ),
+	ENTRY(PCI_DEVICE_ID_NX2031_XG_MGMT),
+	ENTRY(PCI_DEVICE_ID_NX2031_XG_MGMT2),
+	ENTRY(PCI_DEVICE_ID_NX3031),
 	{0,}
 };
 
@@ -241,7 +241,7 @@
 	case NETXEN_BRDTYPE_P3_REF_QG:
 	case NETXEN_BRDTYPE_P3_4_GB:
 	case NETXEN_BRDTYPE_P3_4_GB_MM:
-		adapter->msix_supported = 0;
+		adapter->msix_supported = !!use_msi_x;
 		adapter->max_rx_desc_count = MAX_RCV_DESCRIPTORS_10G;
 		break;
 
diff --git a/drivers/net/niu.c b/drivers/net/niu.c
index e3be81e..ebc8127 100644
--- a/drivers/net/niu.c
+++ b/drivers/net/niu.c
@@ -9130,7 +9130,7 @@
 	return 0;
 }
 
-static struct of_device_id niu_match[] = {
+static const struct of_device_id niu_match[] = {
 	{
 		.name = "network",
 		.compatible = "SUNW,niusl",
diff --git a/drivers/net/pci-skeleton.c b/drivers/net/pci-skeleton.c
index 53451c3..0a575fe 100644
--- a/drivers/net/pci-skeleton.c
+++ b/drivers/net/pci-skeleton.c
@@ -119,7 +119,7 @@
 
 #ifdef NETDRV_DEBUG
 /* note: prints function name for you */
-#  define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args)
+#  define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __func__ , ## args)
 #else
 #  define DPRINTK(fmt, args...)
 #endif
@@ -130,7 +130,7 @@
 #  define assert(expr) \
         if(!(expr)) {					\
         printk( "Assertion failed! %s,%s,%s,line=%d\n",	\
-        #expr,__FILE__,__FUNCTION__,__LINE__);		\
+        #expr,__FILE__,__func__,__LINE__);		\
         }
 #endif
 
diff --git a/drivers/net/pcmcia/3c574_cs.c b/drivers/net/pcmcia/3c574_cs.c
index 7112fd5..08c4dd8 100644
--- a/drivers/net/pcmcia/3c574_cs.c
+++ b/drivers/net/pcmcia/3c574_cs.c
@@ -355,9 +355,10 @@
 	for (i = j = 0; j < 0x400; j += 0x20) {
 		link->io.BasePort1 = j ^ 0x300;
 		i = pcmcia_request_io(link, &link->io);
-		if (i == CS_SUCCESS) break;
+		if (i == 0)
+			break;
 	}
-	if (i != CS_SUCCESS) {
+	if (i != 0) {
 		cs_error(link, RequestIO, i);
 		goto failed;
 	}
@@ -377,7 +378,7 @@
 	tuple.TupleDataMax = 64;
 	tuple.TupleOffset = 0;
 	tuple.DesiredTuple = 0x88;
-	if (pcmcia_get_first_tuple(link, &tuple) == CS_SUCCESS) {
+	if (pcmcia_get_first_tuple(link, &tuple) == 0) {
 		pcmcia_get_tuple_data(link, &tuple);
 		for (i = 0; i < 3; i++)
 			phys_addr[i] = htons(le16_to_cpu(buf[i]));
diff --git a/drivers/net/pcmcia/3c589_cs.c b/drivers/net/pcmcia/3c589_cs.c
index 549a645..c235cdb 100644
--- a/drivers/net/pcmcia/3c589_cs.c
+++ b/drivers/net/pcmcia/3c589_cs.c
@@ -15,7 +15,7 @@
     incorporated herein by reference.
     Donald Becker may be reached at becker@scyld.com
     
-    Updated for 2.5.x by Alan Cox <alan@redhat.com>
+    Updated for 2.5.x by Alan Cox <alan@lxorguk.ukuu.org.uk>
 
 ======================================================================*/
 
@@ -278,9 +278,10 @@
 	if (multi && (j & 0x80)) continue;
 	link->io.BasePort1 = j ^ 0x300;
 	i = pcmcia_request_io(link, &link->io);
-	if (i == CS_SUCCESS) break;
+	if (i == 0)
+		break;
     }
-    if (i != CS_SUCCESS) {
+    if (i != 0) {
 	cs_error(link, RequestIO, i);
 	goto failed;
     }
@@ -295,7 +296,7 @@
     /* The 3c589 has an extra EEPROM for configuration info, including
        the hardware address.  The 3c562 puts the address in the CIS. */
     tuple.DesiredTuple = 0x88;
-    if (pcmcia_get_first_tuple(link, &tuple) == CS_SUCCESS) {
+    if (pcmcia_get_first_tuple(link, &tuple) == 0) {
 	pcmcia_get_tuple_data(link, &tuple);
 	for (i = 0; i < 3; i++)
 	    phys_addr[i] = htons(le16_to_cpu(buf[i]));
diff --git a/drivers/net/pcmcia/axnet_cs.c b/drivers/net/pcmcia/axnet_cs.c
index 52bf11b..b37a498 100644
--- a/drivers/net/pcmcia/axnet_cs.c
+++ b/drivers/net/pcmcia/axnet_cs.c
@@ -262,7 +262,7 @@
 	if (link->io.NumPorts2 > 0) {
 	    /* for master/slave multifunction cards */
 	    link->io.Attributes2 = IO_DATA_PATH_WIDTH_8;
-	    link->irq.Attributes = 
+	    link->irq.Attributes =
 		IRQ_TYPE_DYNAMIC_SHARING|IRQ_FIRST_SHARED;
 	}
     } else {
@@ -276,7 +276,8 @@
 	    link->io.BasePort1 = j ^ 0x300;
 	    link->io.BasePort2 = (j ^ 0x300) + 0x10;
 	    ret = pcmcia_request_io(link, &link->io);
-	    if (ret == CS_SUCCESS) return ret;
+	    if (ret == 0)
+		    return ret;
 	}
 	return ret;
     } else {
@@ -284,59 +285,50 @@
     }
 }
 
+static int axnet_configcheck(struct pcmcia_device *p_dev,
+			     cistpl_cftable_entry_t *cfg,
+			     cistpl_cftable_entry_t *dflt,
+			     unsigned int vcc,
+			     void *priv_data)
+{
+	int i;
+	cistpl_io_t *io = &cfg->io;
+
+	if (cfg->index == 0 || cfg->io.nwin == 0)
+		return -ENODEV;
+
+	p_dev->conf.ConfigIndex = 0x05;
+	/* For multifunction cards, by convention, we configure the
+	   network function with window 0, and serial with window 1 */
+	if (io->nwin > 1) {
+		i = (io->win[1].len > io->win[0].len);
+		p_dev->io.BasePort2 = io->win[1-i].base;
+		p_dev->io.NumPorts2 = io->win[1-i].len;
+	} else {
+		i = p_dev->io.NumPorts2 = 0;
+	}
+	p_dev->io.BasePort1 = io->win[i].base;
+	p_dev->io.NumPorts1 = io->win[i].len;
+	p_dev->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK;
+	if (p_dev->io.NumPorts1 + p_dev->io.NumPorts2 >= 32)
+		return try_io_port(p_dev);
+
+	return -ENODEV;
+}
+
 static int axnet_config(struct pcmcia_device *link)
 {
     struct net_device *dev = link->priv;
     axnet_dev_t *info = PRIV(dev);
-    tuple_t tuple;
-    cisparse_t parse;
     int i, j, last_ret, last_fn;
-    u_short buf[64];
     DECLARE_MAC_BUF(mac);
 
     DEBUG(0, "axnet_config(0x%p)\n", link);
 
-    tuple.Attributes = 0;
-    tuple.TupleData = (cisdata_t *)buf;
-    tuple.TupleDataMax = sizeof(buf);
-    tuple.TupleOffset = 0;
-
     /* don't trust the CIS on this; Linksys got it wrong */
     link->conf.Present = 0x63;
-
-    tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
-    tuple.Attributes = 0;
-    CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple));
-    while (last_ret == CS_SUCCESS) {
-	cistpl_cftable_entry_t *cfg = &(parse.cftable_entry);
-	cistpl_io_t *io = &(parse.cftable_entry.io);
-	
-	if (pcmcia_get_tuple_data(link, &tuple) != 0 ||
-		pcmcia_parse_tuple(link, &tuple, &parse) != 0 ||
-		cfg->index == 0 || cfg->io.nwin == 0)
-	    goto next_entry;
-	
-	link->conf.ConfigIndex = 0x05;
-	/* For multifunction cards, by convention, we configure the
-	   network function with window 0, and serial with window 1 */
-	if (io->nwin > 1) {
-	    i = (io->win[1].len > io->win[0].len);
-	    link->io.BasePort2 = io->win[1-i].base;
-	    link->io.NumPorts2 = io->win[1-i].len;
-	} else {
-	    i = link->io.NumPorts2 = 0;
-	}
-	link->io.BasePort1 = io->win[i].base;
-	link->io.NumPorts1 = io->win[i].len;
-	link->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK;
-	if (link->io.NumPorts1 + link->io.NumPorts2 >= 32) {
-	    last_ret = try_io_port(link);
-	    if (last_ret == CS_SUCCESS) break;
-	}
-    next_entry:
-	last_ret = pcmcia_get_next_tuple(link, &tuple);
-    }
-    if (last_ret != CS_SUCCESS) {
+    last_ret = pcmcia_loop_config(link, axnet_configcheck, NULL);
+    if (last_ret != 0) {
 	cs_error(link, RequestIO, last_ret);
 	goto failed;
     }
diff --git a/drivers/net/pcmcia/com20020_cs.c b/drivers/net/pcmcia/com20020_cs.c
index ea9414c4..831090c 100644
--- a/drivers/net/pcmcia/com20020_cs.c
+++ b/drivers/net/pcmcia/com20020_cs.c
@@ -260,21 +260,21 @@
     DEBUG(0, "com20020_config(0x%p)\n", link);
 
     DEBUG(1,"arcnet: baseport1 is %Xh\n", link->io.BasePort1);
-    i = !CS_SUCCESS;
+    i = -ENODEV;
     if (!link->io.BasePort1)
     {
 	for (ioaddr = 0x100; ioaddr < 0x400; ioaddr += 0x10)
 	{
 	    link->io.BasePort1 = ioaddr;
 	    i = pcmcia_request_io(link, &link->io);
-	    if (i == CS_SUCCESS)
+	    if (i == 0)
 		break;
 	}
     }
     else
 	i = pcmcia_request_io(link, &link->io);
     
-    if (i != CS_SUCCESS)
+    if (i != 0)
     {
 	DEBUG(1,"arcnet: requestIO failed totally!\n");
 	goto failed;
@@ -287,7 +287,7 @@
 	   link->irq.AssignedIRQ,
 	   link->irq.IRQInfo1, link->irq.IRQInfo2);
     i = pcmcia_request_irq(link, &link->irq);
-    if (i != CS_SUCCESS)
+    if (i != 0)
     {
 	DEBUG(1,"arcnet: requestIRQ failed totally!\n");
 	goto failed;
diff --git a/drivers/net/pcmcia/fmvj18x_cs.c b/drivers/net/pcmcia/fmvj18x_cs.c
index a550c9b..69d916d 100644
--- a/drivers/net/pcmcia/fmvj18x_cs.c
+++ b/drivers/net/pcmcia/fmvj18x_cs.c
@@ -309,7 +309,8 @@
 	    printk(KERN_NOTICE "fmvj18x_cs: out of resource for serial\n");
 	}
 	ret = pcmcia_request_io(link, &link->io);
-	if (ret == CS_SUCCESS) return ret;
+	if (ret == 0)
+		return ret;
     }
     return ret;
 }
@@ -325,7 +326,7 @@
     for (ioaddr = 0x300; ioaddr < 0x3e0; ioaddr += 0x20) {
 	link->io.BasePort1 = ioaddr;
 	ret = pcmcia_request_io(link, &link->io);
-	if (ret == CS_SUCCESS) {
+	if (ret == 0) {
 	    /* calculate ConfigIndex value */
 	    link->conf.ConfigIndex = 
 		((link->io.BasePort1 & 0x0f0) >> 3) | 0x22;
@@ -356,12 +357,12 @@
     tuple.TupleOffset = 0;
     tuple.DesiredTuple = CISTPL_FUNCE;
     tuple.TupleOffset = 0;
-    if (pcmcia_get_first_tuple(link, &tuple) == CS_SUCCESS) {
+    if (pcmcia_get_first_tuple(link, &tuple) == 0) {
 	/* Yes, I have CISTPL_FUNCE. Let's check CISTPL_MANFID */
 	tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
 	CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple));
 	CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple));
-	CS_CHECK(ParseTuple, pcmcia_parse_tuple(link, &tuple, &parse));
+	CS_CHECK(ParseTuple, pcmcia_parse_tuple(&tuple, &parse));
 	link->conf.ConfigIndex = parse.cftable_entry.index;
 	switch (link->manf_id) {
 	case MANFID_TDK:
@@ -430,10 +431,10 @@
     	link->irq.Attributes =
 		IRQ_TYPE_DYNAMIC_SHARING|IRQ_FIRST_SHARED|IRQ_HANDLE_PRESENT;
 	ret = mfc_try_io_port(link);
-	if (ret != CS_SUCCESS) goto cs_failed;
+	if (ret != 0) goto cs_failed;
     } else if (cardtype == UNGERMANN) {
 	ret = ungermann_try_io_port(link);
-	if (ret != CS_SUCCESS) goto cs_failed;
+	if (ret != 0) goto cs_failed;
     } else { 
 	CS_CHECK(RequestIO, pcmcia_request_io(link, &link->io));
     }
@@ -565,7 +566,7 @@
     req.Base = 0; req.Size = 0;
     req.AccessSpeed = 0;
     i = pcmcia_request_window(&link, &req, &link->win);
-    if (i != CS_SUCCESS) {
+    if (i != 0) {
 	cs_error(link, RequestWindow, i);
 	return -1;
     }
@@ -599,7 +600,7 @@
 
     iounmap(base);
     j = pcmcia_release_window(link->win);
-    if (j != CS_SUCCESS)
+    if (j != 0)
 	cs_error(link, ReleaseWindow, j);
     return (i != 0x200) ? 0 : -1;
 
@@ -620,7 +621,7 @@
     req.Base = 0; req.Size = 0;
     req.AccessSpeed = 0;
     i = pcmcia_request_window(&link, &req, &link->win);
-    if (i != CS_SUCCESS) {
+    if (i != 0) {
 	cs_error(link, RequestWindow, i);
 	return -1;
     }
@@ -642,7 +643,7 @@
 
     iounmap(base);
     j = pcmcia_release_window(link->win);
-    if (j != CS_SUCCESS)
+    if (j != 0)
 	cs_error(link, ReleaseWindow, j);
     return 0;
 
diff --git a/drivers/net/pcmcia/ibmtr_cs.c b/drivers/net/pcmcia/ibmtr_cs.c
index 4eafa4f..cf3cca4 100644
--- a/drivers/net/pcmcia/ibmtr_cs.c
+++ b/drivers/net/pcmcia/ibmtr_cs.c
@@ -238,7 +238,7 @@
     /* Try PRIMARY card at 0xA20-0xA23 */
     link->io.BasePort1 = 0xA20;
     i = pcmcia_request_io(link, &link->io);
-    if (i != CS_SUCCESS) {
+    if (i != 0) {
 	/* Couldn't get 0xA20-0xA23.  Try ALTERNATE at 0xA24-0xA27. */
 	link->io.BasePort1 = 0xA24;
 	CS_CHECK(RequestIO, pcmcia_request_io(link, &link->io));
diff --git a/drivers/net/pcmcia/nmclan_cs.c b/drivers/net/pcmcia/nmclan_cs.c
index cfcbea9..448cd40 100644
--- a/drivers/net/pcmcia/nmclan_cs.c
+++ b/drivers/net/pcmcia/nmclan_cs.c
@@ -69,7 +69,7 @@
 History
 -------------------------------------------------------------------------------
 Log: nmclan_cs.c,v
- * 2.5.75-ac1 2003/07/11 Alan Cox <alan@redhat.com>
+ * 2.5.75-ac1 2003/07/11 Alan Cox <alan@lxorguk.ukuu.org.uk>
  * Fixed hang on card eject as we probe it
  * Cleaned up to use new style locking.
  *
@@ -925,7 +925,7 @@
   printk(KERN_NOTICE "%s: transmit timed out -- ", dev->name);
 #if RESET_ON_TIMEOUT
   printk("resetting card\n");
-  pcmcia_reset_card(link, NULL);
+  pcmcia_reset_card(link->socket);
 #else /* #if RESET_ON_TIMEOUT */
   printk("NOT resetting card\n");
 #endif /* #if RESET_ON_TIMEOUT */
diff --git a/drivers/net/pcmcia/pcnet_cs.c b/drivers/net/pcmcia/pcnet_cs.c
index ebc1ae6..e40d630 100644
--- a/drivers/net/pcmcia/pcnet_cs.c
+++ b/drivers/net/pcmcia/pcnet_cs.c
@@ -310,7 +310,7 @@
     req.Base = 0; req.Size = 0;
     req.AccessSpeed = 0;
     i = pcmcia_request_window(&link, &req, &link->win);
-    if (i != CS_SUCCESS) {
+    if (i != 0) {
 	cs_error(link, RequestWindow, i);
 	return NULL;
     }
@@ -333,7 +333,7 @@
 
     iounmap(virt);
     j = pcmcia_release_window(link->win);
-    if (j != CS_SUCCESS)
+    if (j != 0)
 	cs_error(link, ReleaseWindow, j);
     return (i < NR_INFO) ? hw_info+i : NULL;
 } /* get_hwinfo */
@@ -504,7 +504,8 @@
 	    link->io.BasePort1 = j ^ 0x300;
 	    link->io.BasePort2 = (j ^ 0x300) + 0x10;
 	    ret = pcmcia_request_io(link, &link->io);
-	    if (ret == CS_SUCCESS) return ret;
+	    if (ret == 0)
+		    return ret;
 	}
 	return ret;
     } else {
@@ -512,58 +513,53 @@
     }
 }
 
+static int pcnet_confcheck(struct pcmcia_device *p_dev,
+			   cistpl_cftable_entry_t *cfg,
+			   cistpl_cftable_entry_t *dflt,
+			   unsigned int vcc,
+			   void *priv_data)
+{
+	int *has_shmem = priv_data;
+	int i;
+	cistpl_io_t *io = &cfg->io;
+
+	if (cfg->index == 0 || cfg->io.nwin == 0)
+		return -EINVAL;
+
+	/* For multifunction cards, by convention, we configure the
+	   network function with window 0, and serial with window 1 */
+	if (io->nwin > 1) {
+		i = (io->win[1].len > io->win[0].len);
+		p_dev->io.BasePort2 = io->win[1-i].base;
+		p_dev->io.NumPorts2 = io->win[1-i].len;
+	} else {
+		i = p_dev->io.NumPorts2 = 0;
+	}
+
+	*has_shmem = ((cfg->mem.nwin == 1) &&
+		      (cfg->mem.win[0].len >= 0x4000));
+	p_dev->io.BasePort1 = io->win[i].base;
+	p_dev->io.NumPorts1 = io->win[i].len;
+	p_dev->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK;
+	if (p_dev->io.NumPorts1 + p_dev->io.NumPorts2 >= 32)
+		return try_io_port(p_dev);
+
+	return 0;
+}
+
 static int pcnet_config(struct pcmcia_device *link)
 {
     struct net_device *dev = link->priv;
     pcnet_dev_t *info = PRIV(dev);
-    tuple_t tuple;
-    cisparse_t parse;
-    int i, last_ret, last_fn, start_pg, stop_pg, cm_offset;
+    int last_ret, last_fn, start_pg, stop_pg, cm_offset;
     int has_shmem = 0;
-    u_short buf[64];
     hw_info_t *local_hw_info;
     DECLARE_MAC_BUF(mac);
 
     DEBUG(0, "pcnet_config(0x%p)\n", link);
 
-    tuple.TupleData = (cisdata_t *)buf;
-    tuple.TupleDataMax = sizeof(buf);
-    tuple.TupleOffset = 0;
-    tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
-    tuple.Attributes = 0;
-    CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple));
-    while (last_ret == CS_SUCCESS) {
-	cistpl_cftable_entry_t *cfg = &(parse.cftable_entry);
-	cistpl_io_t *io = &(parse.cftable_entry.io);
-
-	if (pcmcia_get_tuple_data(link, &tuple) != 0 ||
-			pcmcia_parse_tuple(link, &tuple, &parse) != 0 ||
-			cfg->index == 0 || cfg->io.nwin == 0)
-		goto next_entry;
-
-	link->conf.ConfigIndex = cfg->index;
-	/* For multifunction cards, by convention, we configure the
-	   network function with window 0, and serial with window 1 */
-	if (io->nwin > 1) {
-	    i = (io->win[1].len > io->win[0].len);
-	    link->io.BasePort2 = io->win[1-i].base;
-	    link->io.NumPorts2 = io->win[1-i].len;
-	} else {
-	    i = link->io.NumPorts2 = 0;
-	}
-	has_shmem = ((cfg->mem.nwin == 1) &&
-		     (cfg->mem.win[0].len >= 0x4000));
-	link->io.BasePort1 = io->win[i].base;
-	link->io.NumPorts1 = io->win[i].len;
-	link->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK;
-	if (link->io.NumPorts1 + link->io.NumPorts2 >= 32) {
-	    last_ret = try_io_port(link);
-	    if (last_ret == CS_SUCCESS) break;
-	}
-    next_entry:
-	last_ret = pcmcia_get_next_tuple(link, &tuple);
-    }
-    if (last_ret != CS_SUCCESS) {
+    last_ret = pcmcia_loop_config(link, pcnet_confcheck, &has_shmem);
+    if (last_ret) {
 	cs_error(link, RequestIO, last_ret);
 	goto failed;
     }
diff --git a/drivers/net/pcmcia/smc91c92_cs.c b/drivers/net/pcmcia/smc91c92_cs.c
index 250eb19..c74d665 100644
--- a/drivers/net/pcmcia/smc91c92_cs.c
+++ b/drivers/net/pcmcia/smc91c92_cs.c
@@ -409,10 +409,13 @@
 {
 	int i;
 
-	if ((i = pcmcia_get_first_tuple(handle, tuple)) != CS_SUCCESS ||
-			(i = pcmcia_get_tuple_data(handle, tuple)) != CS_SUCCESS)
+	i = pcmcia_get_first_tuple(handle, tuple);
+	if (i != 0)
 		return i;
-	return pcmcia_parse_tuple(handle, tuple, parse);
+	i = pcmcia_get_tuple_data(handle, tuple);
+	if (i != 0)
+		return i;
+	return pcmcia_parse_tuple(tuple, parse);
 }
 
 static int next_tuple(struct pcmcia_device *handle, tuple_t *tuple,
@@ -420,10 +423,10 @@
 {
 	int i;
 
-	if ((i = pcmcia_get_next_tuple(handle, tuple)) != CS_SUCCESS ||
-			(i = pcmcia_get_tuple_data(handle, tuple)) != CS_SUCCESS)
+	if ((i = pcmcia_get_next_tuple(handle, tuple)) != 0 ||
+			(i = pcmcia_get_tuple_data(handle, tuple)) != 0)
 		return i;
-	return pcmcia_parse_tuple(handle, tuple, parse);
+	return pcmcia_parse_tuple(tuple, parse);
 }
 
 /*======================================================================
@@ -459,27 +462,36 @@
     return 0;
 }
 
+static int mhz_mfc_config_check(struct pcmcia_device *p_dev,
+				cistpl_cftable_entry_t *cf,
+				cistpl_cftable_entry_t *dflt,
+				unsigned int vcc,
+				void *priv_data)
+{
+	int k;
+	p_dev->io.BasePort2 = cf->io.win[0].base;
+	for (k = 0; k < 0x400; k += 0x10) {
+		if (k & 0x80)
+			continue;
+		p_dev->io.BasePort1 = k ^ 0x300;
+		if (!pcmcia_request_io(p_dev, &p_dev->io))
+			return 0;
+	}
+	return -ENODEV;
+}
+
 static int mhz_mfc_config(struct pcmcia_device *link)
 {
     struct net_device *dev = link->priv;
     struct smc_private *smc = netdev_priv(dev);
     struct smc_cfg_mem *cfg_mem;
-    tuple_t *tuple;
-    cisparse_t *parse;
-    cistpl_cftable_entry_t *cf;
-    u_char *buf;
     win_req_t req;
     memreq_t mem;
-    int i, k;
+    int i;
 
     cfg_mem = kmalloc(sizeof(struct smc_cfg_mem), GFP_KERNEL);
     if (!cfg_mem)
-        return CS_OUT_OF_RESOURCE;
-
-    tuple = &cfg_mem->tuple;
-    parse = &cfg_mem->parse;
-    cf = &parse->cftable_entry;
-    buf = cfg_mem->buf;
+	    return -ENOMEM;
 
     link->conf.Attributes |= CONF_ENABLE_SPKR;
     link->conf.Status = CCSR_AUDIO_ENA;
@@ -489,27 +501,9 @@
     link->io.Attributes2 = IO_DATA_PATH_WIDTH_8;
     link->io.NumPorts2 = 8;
 
-    tuple->Attributes = tuple->TupleOffset = 0;
-    tuple->TupleData = (cisdata_t *)buf;
-    tuple->TupleDataMax = 255;
-    tuple->DesiredTuple = CISTPL_CFTABLE_ENTRY;
-
-    i = first_tuple(link, tuple, parse);
     /* The Megahertz combo cards have modem-like CIS entries, so
        we have to explicitly try a bunch of port combinations. */
-    while (i == CS_SUCCESS) {
-	link->conf.ConfigIndex = cf->index;
-	link->io.BasePort2 = cf->io.win[0].base;
-	for (k = 0; k < 0x400; k += 0x10) {
-	    if (k & 0x80) continue;
-	    link->io.BasePort1 = k ^ 0x300;
-	    i = pcmcia_request_io(link, &link->io);
-	    if (i == CS_SUCCESS) break;
-	}
-	if (i == CS_SUCCESS) break;
-	i = next_tuple(link, tuple, parse);
-    }
-    if (i != CS_SUCCESS)
+    if (pcmcia_loop_config(link, mhz_mfc_config_check, NULL))
 	goto free_cfg_mem;
     dev->base_addr = link->io.BasePort1;
 
@@ -518,7 +512,7 @@
     req.Base = req.Size = 0;
     req.AccessSpeed = 0;
     i = pcmcia_request_window(&link, &req, &link->win);
-    if (i != CS_SUCCESS)
+    if (i != 0)
 	goto free_cfg_mem;
     smc->base = ioremap(req.Base, req.Size);
     mem.CardOffset = mem.Page = 0;
@@ -526,14 +520,14 @@
 	mem.CardOffset = link->conf.ConfigBase;
     i = pcmcia_map_mem_page(link->win, &mem);
 
-    if ((i == CS_SUCCESS)
+    if ((i == 0)
 	&& (smc->manfid == MANFID_MEGAHERTZ)
 	&& (smc->cardid == PRODID_MEGAHERTZ_EM3288))
 	mhz_3288_power(link);
 
 free_cfg_mem:
     kfree(cfg_mem);
-    return i;
+    return -ENODEV;
 }
 
 static int mhz_setup(struct pcmcia_device *link)
@@ -560,12 +554,12 @@
     /* Read the station address from the CIS.  It is stored as the last
        (fourth) string in the Version 1 Version/ID tuple. */
     tuple->DesiredTuple = CISTPL_VERS_1;
-    if (first_tuple(link, tuple, parse) != CS_SUCCESS) {
+    if (first_tuple(link, tuple, parse) != 0) {
 	rc = -1;
 	goto free_cfg_mem;
     }
     /* Ugh -- the EM1144 card has two VERS_1 tuples!?! */
-    if (next_tuple(link, tuple, parse) != CS_SUCCESS)
+    if (next_tuple(link, tuple, parse) != 0)
 	first_tuple(link, tuple, parse);
     if (parse->version_1.ns > 3) {
 	station_addr = parse->version_1.str + parse->version_1.ofs[3];
@@ -577,11 +571,11 @@
 
     /* Another possibility: for the EM3288, in a special tuple */
     tuple->DesiredTuple = 0x81;
-    if (pcmcia_get_first_tuple(link, tuple) != CS_SUCCESS) {
+    if (pcmcia_get_first_tuple(link, tuple) != 0) {
 	rc = -1;
 	goto free_cfg_mem;
     }
-    if (pcmcia_get_tuple_data(link, tuple) != CS_SUCCESS) {
+    if (pcmcia_get_tuple_data(link, tuple) != 0) {
 	rc = -1;
 	goto free_cfg_mem;
     }
@@ -660,46 +654,27 @@
 
 /*====================================================================*/
 
+static int smc_configcheck(struct pcmcia_device *p_dev,
+			   cistpl_cftable_entry_t *cf,
+			   cistpl_cftable_entry_t *dflt,
+			   unsigned int vcc,
+			   void *priv_data)
+{
+	p_dev->io.BasePort1 = cf->io.win[0].base;
+	p_dev->io.IOAddrLines = cf->io.flags & CISTPL_IO_LINES_MASK;
+	return pcmcia_request_io(p_dev, &p_dev->io);
+}
+
 static int smc_config(struct pcmcia_device *link)
 {
     struct net_device *dev = link->priv;
-    struct smc_cfg_mem *cfg_mem;
-    tuple_t *tuple;
-    cisparse_t *parse;
-    cistpl_cftable_entry_t *cf;
-    u_char *buf;
     int i;
 
-    cfg_mem = kmalloc(sizeof(struct smc_cfg_mem), GFP_KERNEL);
-    if (!cfg_mem)
-	return CS_OUT_OF_RESOURCE;
-
-    tuple = &cfg_mem->tuple;
-    parse = &cfg_mem->parse;
-    cf = &parse->cftable_entry;
-    buf = cfg_mem->buf;
-
-    tuple->Attributes = tuple->TupleOffset = 0;
-    tuple->TupleData = (cisdata_t *)buf;
-    tuple->TupleDataMax = 255;
-    tuple->DesiredTuple = CISTPL_CFTABLE_ENTRY;
-
     link->io.NumPorts1 = 16;
-    i = first_tuple(link, tuple, parse);
-    while (i != CS_NO_MORE_ITEMS) {
-	if (i == CS_SUCCESS) {
-	    link->conf.ConfigIndex = cf->index;
-	    link->io.BasePort1 = cf->io.win[0].base;
-	    link->io.IOAddrLines = cf->io.flags & CISTPL_IO_LINES_MASK;
-	    i = pcmcia_request_io(link, &link->io);
-	    if (i == CS_SUCCESS) break;
-	}
-	i = next_tuple(link, tuple, parse);
-    }
-    if (i == CS_SUCCESS)
-	dev->base_addr = link->io.BasePort1;
+    i = pcmcia_loop_config(link, smc_configcheck, NULL);
+    if (!i)
+	    dev->base_addr = link->io.BasePort1;
 
-    kfree(cfg_mem);
     return i;
 }
 
@@ -715,7 +690,7 @@
 
     cfg_mem = kmalloc(sizeof(struct smc_cfg_mem), GFP_KERNEL);
     if (!cfg_mem)
-	return CS_OUT_OF_RESOURCE;
+	    return -ENOMEM;
 
     tuple = &cfg_mem->tuple;
     parse = &cfg_mem->parse;
@@ -728,12 +703,12 @@
     /* Check for a LAN function extension tuple */
     tuple->DesiredTuple = CISTPL_FUNCE;
     i = first_tuple(link, tuple, parse);
-    while (i == CS_SUCCESS) {
+    while (i == 0) {
 	if (parse->funce.type == CISTPL_FUNCE_LAN_NODE_ID)
 	    break;
 	i = next_tuple(link, tuple, parse);
     }
-    if (i == CS_SUCCESS) {
+    if (i == 0) {
 	node_id = (cistpl_lan_node_id_t *)parse->funce.data;
 	if (node_id->nb == 6) {
 	    for (i = 0; i < 6; i++)
@@ -780,9 +755,10 @@
     for (i = j = 0; j < 4; j++) {
 	link->io.BasePort2 = com[j];
 	i = pcmcia_request_io(link, &link->io);
-	if (i == CS_SUCCESS) break;
+	if (i == 0)
+		break;
     }
-    if (i != CS_SUCCESS) {
+    if (i != 0) {
 	/* Fallback: turn off hard decode */
 	link->conf.ConfigIndex = 0x03;
 	link->io.NumPorts2 = 0;
@@ -815,13 +791,13 @@
     /* Read the station address from tuple 0x90, subtuple 0x04 */
     tuple->DesiredTuple = 0x90;
     i = pcmcia_get_first_tuple(link, tuple);
-    while (i == CS_SUCCESS) {
+    while (i == 0) {
 	i = pcmcia_get_tuple_data(link, tuple);
-	if ((i != CS_SUCCESS) || (buf[0] == 0x04))
+	if ((i != 0) || (buf[0] == 0x04))
 	    break;
 	i = pcmcia_get_next_tuple(link, tuple);
     }
-    if (i != CS_SUCCESS) {
+    if (i != 0) {
 	rc = -1;
 	goto free_cfg_mem;
     }
@@ -959,8 +935,11 @@
 
 ======================================================================*/
 
-#define CS_EXIT_TEST(ret, svc, label) \
-if (ret != CS_SUCCESS) { cs_error(link, svc, ret); goto label; }
+#define CS_EXIT_TEST(ret, svc, label)	\
+if (ret != 0) {				\
+	cs_error(link, svc, ret);	\
+	goto label; 			\
+}
 
 static int smc91c92_config(struct pcmcia_device *link)
 {
diff --git a/drivers/net/pcmcia/xirc2ps_cs.c b/drivers/net/pcmcia/xirc2ps_cs.c
index f6c4698..e1fd585 100644
--- a/drivers/net/pcmcia/xirc2ps_cs.c
+++ b/drivers/net/pcmcia/xirc2ps_cs.c
@@ -353,7 +353,7 @@
  * Some more prototypes
  */
 static int do_start_xmit(struct sk_buff *skb, struct net_device *dev);
-static void do_tx_timeout(struct net_device *dev);
+static void xirc_tx_timeout(struct net_device *dev);
 static void xirc2ps_tx_timeout_task(struct work_struct *work);
 static struct net_device_stats *do_get_stats(struct net_device *dev);
 static void set_addresses(struct net_device *dev);
@@ -377,7 +377,7 @@
 
 	if ((err = pcmcia_get_first_tuple(handle, tuple)) == 0 &&
 			(err = pcmcia_get_tuple_data(handle, tuple)) == 0)
-		err = pcmcia_parse_tuple(handle, tuple, parse);
+		err = pcmcia_parse_tuple(tuple, parse);
 	return err;
 }
 
@@ -388,7 +388,7 @@
 
 	if ((err = pcmcia_get_next_tuple(handle, tuple)) == 0 &&
 			(err = pcmcia_get_tuple_data(handle, tuple)) == 0)
-		err = pcmcia_parse_tuple(handle, tuple, parse);
+		err = pcmcia_parse_tuple(tuple, parse);
 	return err;
 }
 
@@ -590,7 +590,7 @@
     dev->open = &do_open;
     dev->stop = &do_stop;
 #ifdef HAVE_TX_TIMEOUT
-    dev->tx_timeout = do_tx_timeout;
+    dev->tx_timeout = xirc_tx_timeout;
     dev->watchdog_timeo = TX_TIMEOUT;
     INIT_WORK(&local->tx_timeout_task, xirc2ps_tx_timeout_task);
 #endif
@@ -715,6 +715,47 @@
 	return 0;
 }
 
+static int
+xirc2ps_config_modem(struct pcmcia_device *p_dev,
+		     cistpl_cftable_entry_t *cf,
+		     cistpl_cftable_entry_t *dflt,
+		     unsigned int vcc,
+		     void *priv_data)
+{
+	unsigned int ioaddr;
+
+	if (cf->io.nwin > 0  &&  (cf->io.win[0].base & 0xf) == 8) {
+		for (ioaddr = 0x300; ioaddr < 0x400; ioaddr += 0x10) {
+			p_dev->io.BasePort2 = cf->io.win[0].base;
+			p_dev->io.BasePort1 = ioaddr;
+			if (!pcmcia_request_io(p_dev, &p_dev->io))
+				return 0;
+		}
+	}
+	return -ENODEV;
+}
+
+static int
+xirc2ps_config_check(struct pcmcia_device *p_dev,
+		     cistpl_cftable_entry_t *cf,
+		     cistpl_cftable_entry_t *dflt,
+		     unsigned int vcc,
+		     void *priv_data)
+{
+	int *pass = priv_data;
+
+	if (cf->io.nwin > 0 && (cf->io.win[0].base & 0xf) == 8) {
+		p_dev->io.BasePort2 = cf->io.win[0].base;
+		p_dev->io.BasePort1 = p_dev->io.BasePort2
+			+ (*pass ? (cf->index & 0x20 ? -24:8)
+			   : (cf->index & 0x20 ?   8:-24));
+		if (!pcmcia_request_io(p_dev, &p_dev->io))
+			return 0;
+	}
+	return -ENODEV;
+
+}
+
 /****************
  * xirc2ps_config() is scheduled to run after a CARD_INSERTION event
  * is received, to configure the PCMCIA socket, and to make the
@@ -725,13 +766,12 @@
 {
     struct net_device *dev = link->priv;
     local_info_t *local = netdev_priv(dev);
+    unsigned int ioaddr;
     tuple_t tuple;
     cisparse_t parse;
-    unsigned int ioaddr;
     int err, i;
     u_char buf[64];
     cistpl_lan_node_id_t *node_id = (cistpl_lan_node_id_t*)parse.funce.data;
-    cistpl_cftable_entry_t *cf = &parse.cftable_entry;
     DECLARE_MAC_BUF(mac);
 
     local->dingo_ccr = NULL;
@@ -846,19 +886,8 @@
 	    /* Take the Modem IO port from the CIS and scan for a free
 	     * Ethernet port */
 	    link->io.NumPorts1 = 16; /* no Mako stuff anymore */
-	    tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
-	    for (err = first_tuple(link, &tuple, &parse); !err;
-				 err = next_tuple(link, &tuple, &parse)) {
-		if (cf->io.nwin > 0  &&  (cf->io.win[0].base & 0xf) == 8) {
-		    for (ioaddr = 0x300; ioaddr < 0x400; ioaddr += 0x10) {
-			link->conf.ConfigIndex = cf->index ;
-			link->io.BasePort2 = cf->io.win[0].base;
-			link->io.BasePort1 = ioaddr;
-			if (!(err=pcmcia_request_io(link, &link->io)))
-			    goto port_found;
-		    }
-		}
-	    }
+	    if (!pcmcia_loop_config(link, xirc2ps_config_modem, NULL))
+		    goto port_found;
 	} else {
 	    link->io.NumPorts1 = 18;
 	    /* We do 2 passes here: The first one uses the regular mapping and
@@ -866,21 +895,9 @@
 	     * mirrored every 32 bytes. Actually we use a mirrored port for
 	     * the Mako if (on the first pass) the COR bit 5 is set.
 	     */
-	    for (pass=0; pass < 2; pass++) {
-		tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
-		for (err = first_tuple(link, &tuple, &parse); !err;
-				     err = next_tuple(link, &tuple, &parse)){
-		    if (cf->io.nwin > 0  &&  (cf->io.win[0].base & 0xf) == 8){
-			link->conf.ConfigIndex = cf->index ;
-			link->io.BasePort2 = cf->io.win[0].base;
-			link->io.BasePort1 = link->io.BasePort2
-				    + (pass ? (cf->index & 0x20 ? -24:8)
-					    : (cf->index & 0x20 ?   8:-24));
-			if (!(err=pcmcia_request_io(link, &link->io)))
+	    for (pass=0; pass < 2; pass++)
+		    if (!pcmcia_loop_config(link, xirc2ps_config_check, &pass))
 			    goto port_found;
-		    }
-		}
-	    }
 	    /* if special option:
 	     * try to configure as Ethernet only.
 	     * .... */
@@ -1335,7 +1352,7 @@
 }
 
 static void
-do_tx_timeout(struct net_device *dev)
+xirc_tx_timeout(struct net_device *dev)
 {
     local_info_t *lp = netdev_priv(dev);
     lp->stats.tx_errors++;
diff --git a/drivers/net/phy/fixed.c b/drivers/net/phy/fixed.c
index 4e07956..cf24cc3 100644
--- a/drivers/net/phy/fixed.c
+++ b/drivers/net/phy/fixed.c
@@ -24,7 +24,7 @@
 
 struct fixed_mdio_bus {
 	int irqs[PHY_MAX_ADDR];
-	struct mii_bus mii_bus;
+	struct mii_bus *mii_bus;
 	struct list_head phys;
 };
 
@@ -115,8 +115,7 @@
 
 static int fixed_mdio_read(struct mii_bus *bus, int phy_id, int reg_num)
 {
-	struct fixed_mdio_bus *fmb = container_of(bus, struct fixed_mdio_bus,
-						  mii_bus);
+	struct fixed_mdio_bus *fmb = bus->priv;
 	struct fixed_phy *fp;
 
 	if (reg_num >= MII_REGS_NUM)
@@ -213,19 +212,28 @@
 		goto err_pdev;
 	}
 
-	snprintf(fmb->mii_bus.id, MII_BUS_ID_SIZE, "0");
-	fmb->mii_bus.name = "Fixed MDIO Bus";
-	fmb->mii_bus.dev = &pdev->dev;
-	fmb->mii_bus.read = &fixed_mdio_read;
-	fmb->mii_bus.write = &fixed_mdio_write;
-	fmb->mii_bus.irq = fmb->irqs;
-
-	ret = mdiobus_register(&fmb->mii_bus);
-	if (ret)
+	fmb->mii_bus = mdiobus_alloc();
+	if (fmb->mii_bus == NULL) {
+		ret = -ENOMEM;
 		goto err_mdiobus_reg;
+	}
+
+	snprintf(fmb->mii_bus->id, MII_BUS_ID_SIZE, "0");
+	fmb->mii_bus->name = "Fixed MDIO Bus";
+	fmb->mii_bus->priv = fmb;
+	fmb->mii_bus->parent = &pdev->dev;
+	fmb->mii_bus->read = &fixed_mdio_read;
+	fmb->mii_bus->write = &fixed_mdio_write;
+	fmb->mii_bus->irq = fmb->irqs;
+
+	ret = mdiobus_register(fmb->mii_bus);
+	if (ret)
+		goto err_mdiobus_alloc;
 
 	return 0;
 
+err_mdiobus_alloc:
+	mdiobus_free(fmb->mii_bus);
 err_mdiobus_reg:
 	platform_device_unregister(pdev);
 err_pdev:
@@ -238,7 +246,8 @@
 	struct fixed_mdio_bus *fmb = &platform_fmb;
 	struct fixed_phy *fp, *tmp;
 
-	mdiobus_unregister(&fmb->mii_bus);
+	mdiobus_unregister(fmb->mii_bus);
+	mdiobus_free(fmb->mii_bus);
 	platform_device_unregister(pdev);
 
 	list_for_each_entry_safe(fp, tmp, &fmb->phys, node) {
diff --git a/drivers/net/phy/mdio-bitbang.c b/drivers/net/phy/mdio-bitbang.c
index c01b780..2576055 100644
--- a/drivers/net/phy/mdio-bitbang.c
+++ b/drivers/net/phy/mdio-bitbang.c
@@ -165,7 +165,7 @@
 {
 	struct mii_bus *bus;
 
-	bus = kzalloc(sizeof(struct mii_bus), GFP_KERNEL);
+	bus = mdiobus_alloc();
 	if (!bus)
 		return NULL;
 
@@ -184,7 +184,7 @@
 	struct mdiobb_ctrl *ctrl = bus->priv;
 
 	module_put(ctrl->ops->owner);
-	kfree(bus);
+	mdiobus_free(bus);
 }
 EXPORT_SYMBOL(free_mdio_bitbang);
 
diff --git a/drivers/net/phy/mdio-ofgpio.c b/drivers/net/phy/mdio-ofgpio.c
index 7edfc0c..2ff9775 100644
--- a/drivers/net/phy/mdio-ofgpio.c
+++ b/drivers/net/phy/mdio-ofgpio.c
@@ -122,7 +122,7 @@
 
 	new_bus = alloc_mdio_bitbang(&bitbang->ctrl);
 	if (!new_bus)
-		goto out_free_priv;
+		goto out_free_bitbang;
 
 	new_bus->name = "GPIO Bitbanged MII",
 
@@ -142,7 +142,7 @@
 		if (!strcmp(np->type, "ethernet-phy"))
 			add_phy(new_bus, np);
 
-	new_bus->dev = &ofdev->dev;
+	new_bus->parent = &ofdev->dev;
 	dev_set_drvdata(&ofdev->dev, new_bus);
 
 	ret = mdiobus_register(new_bus);
@@ -155,9 +155,9 @@
 	dev_set_drvdata(&ofdev->dev, NULL);
 	kfree(new_bus->irq);
 out_free_bus:
-	kfree(new_bus);
-out_free_priv:
 	free_mdio_bitbang(new_bus);
+out_free_bitbang:
+	kfree(bitbang);
 out:
 	return ret;
 }
@@ -168,11 +168,10 @@
 	struct mdio_gpio_info *bitbang = bus->priv;
 
 	mdiobus_unregister(bus);
+	kfree(bus->irq);
 	free_mdio_bitbang(bus);
 	dev_set_drvdata(&ofdev->dev, NULL);
-	kfree(bus->irq);
 	kfree(bitbang);
-	kfree(bus);
 
 	return 0;
 }
diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c
index 94e0b7e..d0ed1ef 100644
--- a/drivers/net/phy/mdio_bus.c
+++ b/drivers/net/phy/mdio_bus.c
@@ -36,6 +36,43 @@
 #include <asm/uaccess.h>
 
 /**
+ * mdiobus_alloc - allocate a mii_bus structure
+ *
+ * Description: called by a bus driver to allocate an mii_bus
+ * structure to fill in.
+ */
+struct mii_bus *mdiobus_alloc(void)
+{
+	struct mii_bus *bus;
+
+	bus = kzalloc(sizeof(*bus), GFP_KERNEL);
+	if (bus != NULL)
+		bus->state = MDIOBUS_ALLOCATED;
+
+	return bus;
+}
+EXPORT_SYMBOL(mdiobus_alloc);
+
+/**
+ * mdiobus_release - mii_bus device release callback
+ * @d: the target struct device that contains the mii_bus
+ *
+ * Description: called when the last reference to an mii_bus is
+ * dropped, to free the underlying memory.
+ */
+static void mdiobus_release(struct device *d)
+{
+	struct mii_bus *bus = to_mii_bus(d);
+	BUG_ON(bus->state != MDIOBUS_RELEASED);
+	kfree(bus);
+}
+
+static struct class mdio_bus_class = {
+	.name		= "mdio_bus",
+	.dev_release	= mdiobus_release,
+};
+
+/**
  * mdiobus_register - bring up all the PHYs on a given bus and attach them to bus
  * @bus: target mii_bus
  *
@@ -54,55 +91,36 @@
 			NULL == bus->write)
 		return -EINVAL;
 
+	BUG_ON(bus->state != MDIOBUS_ALLOCATED &&
+	       bus->state != MDIOBUS_UNREGISTERED);
+
+	bus->dev.parent = bus->parent;
+	bus->dev.class = &mdio_bus_class;
+	bus->dev.groups = NULL;
+	memcpy(bus->dev.bus_id, bus->id, MII_BUS_ID_SIZE);
+
+	err = device_register(&bus->dev);
+	if (err) {
+		printk(KERN_ERR "mii_bus %s failed to register\n", bus->id);
+		return -EINVAL;
+	}
+
+	bus->state = MDIOBUS_REGISTERED;
+
 	mutex_init(&bus->mdio_lock);
 
 	if (bus->reset)
 		bus->reset(bus);
 
 	for (i = 0; i < PHY_MAX_ADDR; i++) {
-		struct phy_device *phydev;
+		bus->phy_map[i] = NULL;
+		if ((bus->phy_mask & (1 << i)) == 0) {
+			struct phy_device *phydev;
 
-		if (bus->phy_mask & (1 << i)) {
-			bus->phy_map[i] = NULL;
-			continue;
+			phydev = mdiobus_scan(bus, i);
+			if (IS_ERR(phydev))
+				err = PTR_ERR(phydev);
 		}
-
-		phydev = get_phy_device(bus, i);
-
-		if (IS_ERR(phydev))
-			return PTR_ERR(phydev);
-
-		/* There's a PHY at this address
-		 * We need to set:
-		 * 1) IRQ
-		 * 2) bus_id
-		 * 3) parent
-		 * 4) bus
-		 * 5) mii_bus
-		 * And, we need to register it */
-		if (phydev) {
-			phydev->irq = bus->irq[i];
-
-			phydev->dev.parent = bus->dev;
-			phydev->dev.bus = &mdio_bus_type;
-			snprintf(phydev->dev.bus_id, BUS_ID_SIZE, PHY_ID_FMT, bus->id, i);
-
-			phydev->bus = bus;
-
-			/* Run all of the fixups for this PHY */
-			phy_scan_fixups(phydev);
-
-			err = device_register(&phydev->dev);
-
-			if (err) {
-				printk(KERN_ERR "phy %d failed to register\n",
-						i);
-				phy_device_free(phydev);
-				phydev = NULL;
-			}
-		}
-
-		bus->phy_map[i] = phydev;
 	}
 
 	pr_info("%s: probed\n", bus->name);
@@ -115,6 +133,10 @@
 {
 	int i;
 
+	BUG_ON(bus->state != MDIOBUS_REGISTERED);
+	bus->state = MDIOBUS_UNREGISTERED;
+
+	device_unregister(&bus->dev);
 	for (i = 0; i < PHY_MAX_ADDR; i++) {
 		if (bus->phy_map[i])
 			device_unregister(&bus->phy_map[i]->dev);
@@ -123,6 +145,122 @@
 EXPORT_SYMBOL(mdiobus_unregister);
 
 /**
+ * mdiobus_free - free a struct mii_bus
+ * @bus: mii_bus to free
+ *
+ * This function releases the reference to the underlying device
+ * object in the mii_bus.  If this is the last reference, the mii_bus
+ * will be freed.
+ */
+void mdiobus_free(struct mii_bus *bus)
+{
+	/*
+	 * For compatibility with error handling in drivers.
+	 */
+	if (bus->state == MDIOBUS_ALLOCATED) {
+		kfree(bus);
+		return;
+	}
+
+	BUG_ON(bus->state != MDIOBUS_UNREGISTERED);
+	bus->state = MDIOBUS_RELEASED;
+
+	put_device(&bus->dev);
+}
+EXPORT_SYMBOL(mdiobus_free);
+
+struct phy_device *mdiobus_scan(struct mii_bus *bus, int addr)
+{
+	struct phy_device *phydev;
+	int err;
+
+	phydev = get_phy_device(bus, addr);
+	if (IS_ERR(phydev) || phydev == NULL)
+		return phydev;
+
+	/* There's a PHY at this address
+	 * We need to set:
+	 * 1) IRQ
+	 * 2) bus_id
+	 * 3) parent
+	 * 4) bus
+	 * 5) mii_bus
+	 * And, we need to register it */
+
+	phydev->irq = bus->irq != NULL ? bus->irq[addr] : PHY_POLL;
+
+	phydev->dev.parent = bus->parent;
+	phydev->dev.bus = &mdio_bus_type;
+	snprintf(phydev->dev.bus_id, BUS_ID_SIZE, PHY_ID_FMT, bus->id, addr);
+
+	phydev->bus = bus;
+
+	/* Run all of the fixups for this PHY */
+	phy_scan_fixups(phydev);
+
+	err = device_register(&phydev->dev);
+	if (err) {
+		printk(KERN_ERR "phy %d failed to register\n", addr);
+		phy_device_free(phydev);
+		phydev = NULL;
+	}
+
+	bus->phy_map[addr] = phydev;
+
+	return phydev;
+}
+EXPORT_SYMBOL(mdiobus_scan);
+
+/**
+ * mdiobus_read - Convenience function for reading a given MII mgmt register
+ * @bus: the mii_bus struct
+ * @addr: the phy address
+ * @regnum: register number to read
+ *
+ * NOTE: MUST NOT be called from interrupt context,
+ * because the bus read/write functions may wait for an interrupt
+ * to conclude the operation.
+ */
+int mdiobus_read(struct mii_bus *bus, int addr, u16 regnum)
+{
+	int retval;
+
+	BUG_ON(in_interrupt());
+
+	mutex_lock(&bus->mdio_lock);
+	retval = bus->read(bus, addr, regnum);
+	mutex_unlock(&bus->mdio_lock);
+
+	return retval;
+}
+EXPORT_SYMBOL(mdiobus_read);
+
+/**
+ * mdiobus_write - Convenience function for writing a given MII mgmt register
+ * @bus: the mii_bus struct
+ * @addr: the phy address
+ * @regnum: register number to write
+ * @val: value to write to @regnum
+ *
+ * NOTE: MUST NOT be called from interrupt context,
+ * because the bus read/write functions may wait for an interrupt
+ * to conclude the operation.
+ */
+int mdiobus_write(struct mii_bus *bus, int addr, u16 regnum, u16 val)
+{
+	int err;
+
+	BUG_ON(in_interrupt());
+
+	mutex_lock(&bus->mdio_lock);
+	err = bus->write(bus, addr, regnum, val);
+	mutex_unlock(&bus->mdio_lock);
+
+	return err;
+}
+EXPORT_SYMBOL(mdiobus_write);
+
+/**
  * mdio_bus_match - determine if given PHY driver supports the given PHY device
  * @dev: target PHY device
  * @drv: given PHY driver
@@ -174,10 +312,20 @@
 
 int __init mdio_bus_init(void)
 {
-	return bus_register(&mdio_bus_type);
+	int ret;
+
+	ret = class_register(&mdio_bus_class);
+	if (!ret) {
+		ret = bus_register(&mdio_bus_type);
+		if (ret)
+			class_unregister(&mdio_bus_class);
+	}
+
+	return ret;
 }
 
 void mdio_bus_exit(void)
 {
+	class_unregister(&mdio_bus_class);
 	bus_unregister(&mdio_bus_type);
 }
diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
index 45cc291..df4e625 100644
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -58,55 +58,6 @@
 
 
 /**
- * phy_read - Convenience function for reading a given PHY register
- * @phydev: the phy_device struct
- * @regnum: register number to read
- *
- * NOTE: MUST NOT be called from interrupt context,
- * because the bus read/write functions may wait for an interrupt
- * to conclude the operation.
- */
-int phy_read(struct phy_device *phydev, u16 regnum)
-{
-	int retval;
-	struct mii_bus *bus = phydev->bus;
-
-	BUG_ON(in_interrupt());
-
-	mutex_lock(&bus->mdio_lock);
-	retval = bus->read(bus, phydev->addr, regnum);
-	mutex_unlock(&bus->mdio_lock);
-
-	return retval;
-}
-EXPORT_SYMBOL(phy_read);
-
-/**
- * phy_write - Convenience function for writing a given PHY register
- * @phydev: the phy_device struct
- * @regnum: register number to write
- * @val: value to write to @regnum
- *
- * NOTE: MUST NOT be called from interrupt context,
- * because the bus read/write functions may wait for an interrupt
- * to conclude the operation.
- */
-int phy_write(struct phy_device *phydev, u16 regnum, u16 val)
-{
-	int err;
-	struct mii_bus *bus = phydev->bus;
-
-	BUG_ON(in_interrupt());
-
-	mutex_lock(&bus->mdio_lock);
-	err = bus->write(bus, phydev->addr, regnum, val);
-	mutex_unlock(&bus->mdio_lock);
-
-	return err;
-}
-EXPORT_SYMBOL(phy_write);
-
-/**
  * phy_clear_interrupt - Ack the phy device's interrupt
  * @phydev: the phy_device struct
  *
@@ -366,7 +317,8 @@
 	switch (cmd) {
 	case SIOCGMIIPHY:
 		mii_data->phy_id = phydev->addr;
-		break;
+		/* fall through */
+
 	case SIOCGMIIREG:
 		mii_data->val_out = phy_read(phydev, mii_data->reg_num);
 		break;
@@ -413,7 +365,7 @@
 		break;
 
 	default:
-		return -ENOTTY;
+		return -EOPNOTSUPP;
 	}
 
 	return 0;
@@ -728,6 +680,12 @@
 	if (err)
 		goto irq_enable_err;
 
+	/* Stop timer and run the state queue now.  The work function for
+	 * state_queue will start the timer up again.
+	 */
+	del_timer(&phydev->phy_timer);
+	schedule_work(&phydev->state_queue);
+
 	return;
 
 irq_enable_err:
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index 16a0e7d..f11e900 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -419,13 +419,14 @@
  *
  * Description: Writes MII_ADVERTISE with the appropriate values,
  *   after sanitizing the values to make sure we only advertise
- *   what is supported.
+ *   what is supported.  Returns < 0 on error, 0 if the PHY's advertisement
+ *   hasn't changed, and > 0 if it has changed.
  */
 int genphy_config_advert(struct phy_device *phydev)
 {
 	u32 advertise;
-	int adv;
-	int err;
+	int oldadv, adv;
+	int err, changed = 0;
 
 	/* Only allow advertising what
 	 * this PHY supports */
@@ -433,7 +434,7 @@
 	advertise = phydev->advertising;
 
 	/* Setup standard advertisement */
-	adv = phy_read(phydev, MII_ADVERTISE);
+	oldadv = adv = phy_read(phydev, MII_ADVERTISE);
 
 	if (adv < 0)
 		return adv;
@@ -453,15 +454,18 @@
 	if (advertise & ADVERTISED_Asym_Pause)
 		adv |= ADVERTISE_PAUSE_ASYM;
 
-	err = phy_write(phydev, MII_ADVERTISE, adv);
+	if (adv != oldadv) {
+		err = phy_write(phydev, MII_ADVERTISE, adv);
 
-	if (err < 0)
-		return err;
+		if (err < 0)
+			return err;
+		changed = 1;
+	}
 
 	/* Configure gigabit if it's supported */
 	if (phydev->supported & (SUPPORTED_1000baseT_Half |
 				SUPPORTED_1000baseT_Full)) {
-		adv = phy_read(phydev, MII_CTRL1000);
+		oldadv = adv = phy_read(phydev, MII_CTRL1000);
 
 		if (adv < 0)
 			return adv;
@@ -471,13 +475,17 @@
 			adv |= ADVERTISE_1000HALF;
 		if (advertise & SUPPORTED_1000baseT_Full)
 			adv |= ADVERTISE_1000FULL;
-		err = phy_write(phydev, MII_CTRL1000, adv);
 
-		if (err < 0)
-			return err;
+		if (adv != oldadv) {
+			err = phy_write(phydev, MII_CTRL1000, adv);
+
+			if (err < 0)
+				return err;
+			changed = 1;
+		}
 	}
 
-	return adv;
+	return changed;
 }
 EXPORT_SYMBOL(genphy_config_advert);
 
@@ -549,6 +557,7 @@
 
 	return ctl;
 }
+EXPORT_SYMBOL(genphy_restart_aneg);
 
 
 /**
@@ -561,19 +570,22 @@
  */
 int genphy_config_aneg(struct phy_device *phydev)
 {
-	int err = 0;
+	int result = 0;
 
 	if (AUTONEG_ENABLE == phydev->autoneg) {
-		err = genphy_config_advert(phydev);
+		int result = genphy_config_advert(phydev);
 
-		if (err < 0)
-			return err;
+		if (result < 0) /* error */
+			return result;
 
-		err = genphy_restart_aneg(phydev);
+		/* Only restart aneg if we are advertising something different
+		 * than we were before.	 */
+		if (result > 0)
+			result = genphy_restart_aneg(phydev);
 	} else
-		err = genphy_setup_forced(phydev);
+		result = genphy_setup_forced(phydev);
 
-	return err;
+	return result;
 }
 EXPORT_SYMBOL(genphy_config_aneg);
 
diff --git a/drivers/net/ppp_generic.c b/drivers/net/ppp_generic.c
index ddccc07..0ca0fcb 100644
--- a/drivers/net/ppp_generic.c
+++ b/drivers/net/ppp_generic.c
@@ -1833,9 +1833,11 @@
 
 	/* If the queue is getting long, don't wait any longer for packets
 	   before the start of the queue. */
-	if (skb_queue_len(&ppp->mrq) >= PPP_MP_MAX_QLEN
-	    && seq_before(ppp->minseq, ppp->mrq.next->sequence))
-		ppp->minseq = ppp->mrq.next->sequence;
+	if (skb_queue_len(&ppp->mrq) >= PPP_MP_MAX_QLEN) {
+		struct sk_buff *skb = skb_peek(&ppp->mrq);
+		if (seq_before(ppp->minseq, skb->sequence))
+			ppp->minseq = skb->sequence;
+	}
 
 	/* Pull completed packets off the queue and receive them. */
 	while ((skb = ppp_mp_reconstruct(ppp)))
@@ -1861,10 +1863,11 @@
 
 	/* N.B. we don't need to lock the list lock because we have the
 	   ppp unit receive-side lock. */
-	for (p = list->next; p != (struct sk_buff *)list; p = p->next)
+	skb_queue_walk(list, p) {
 		if (seq_before(seq, p->sequence))
 			break;
-	__skb_insert(skb, p->prev, p, list);
+	}
+	__skb_queue_before(list, p, skb);
 }
 
 /*
diff --git a/drivers/net/pppol2tp.c b/drivers/net/pppol2tp.c
index ff175e8..185b1df 100644
--- a/drivers/net/pppol2tp.c
+++ b/drivers/net/pppol2tp.c
@@ -353,7 +353,7 @@
 	spin_lock_bh(&session->reorder_q.lock);
 	skb_queue_walk_safe(&session->reorder_q, skbp, tmp) {
 		if (PPPOL2TP_SKB_CB(skbp)->ns > ns) {
-			__skb_insert(skb, skbp->prev, skbp, &session->reorder_q);
+			__skb_queue_before(&session->reorder_q, skbp, skb);
 			PRINTK(session->debug, PPPOL2TP_MSG_SEQ, KERN_DEBUG,
 			       "%s: pkt %hu, inserted before %hu, reorder_q len=%d\n",
 			       session->name, ns, PPPOL2TP_SKB_CB(skbp)->ns,
diff --git a/drivers/net/qlge/Makefile b/drivers/net/qlge/Makefile
new file mode 100644
index 0000000..8a19765
--- /dev/null
+++ b/drivers/net/qlge/Makefile
@@ -0,0 +1,7 @@
+#
+# Makefile for the Qlogic 10GbE PCI Express ethernet driver
+#
+
+obj-$(CONFIG_QLGE) += qlge.o
+
+qlge-objs := qlge_main.o qlge_dbg.o qlge_mpi.o qlge_ethtool.o
diff --git a/drivers/net/qlge/qlge.h b/drivers/net/qlge/qlge.h
new file mode 100644
index 0000000..38116f9
--- /dev/null
+++ b/drivers/net/qlge/qlge.h
@@ -0,0 +1,1593 @@
+/*
+ * QLogic QLA41xx NIC HBA Driver
+ * Copyright (c)  2003-2006 QLogic Corporation
+ *
+ * See LICENSE.qlge for copyright and licensing details.
+ */
+#ifndef _QLGE_H_
+#define _QLGE_H_
+
+#include <linux/pci.h>
+#include <linux/netdevice.h>
+
+/*
+ * General definitions...
+ */
+#define DRV_NAME  	"qlge"
+#define DRV_STRING 	"QLogic 10 Gigabit PCI-E Ethernet Driver "
+#define DRV_VERSION	"v1.00.00-b3"
+
+#define PFX "qlge: "
+#define QPRINTK(qdev, nlevel, klevel, fmt, args...)     \
+       do {       \
+	if (!((qdev)->msg_enable & NETIF_MSG_##nlevel))		\
+		;						\
+	else							\
+		dev_printk(KERN_##klevel, &((qdev)->pdev->dev),	\
+			   "%s: " fmt, __func__, ##args);  \
+       } while (0)
+
+#define QLGE_VENDOR_ID    0x1077
+#define QLGE_DEVICE_ID1    0x8012
+#define QLGE_DEVICE_ID   0x8000
+
+#define MAX_RX_RINGS 128
+#define MAX_TX_RINGS 128
+
+#define NUM_TX_RING_ENTRIES	256
+#define NUM_RX_RING_ENTRIES	256
+
+#define NUM_SMALL_BUFFERS   512
+#define NUM_LARGE_BUFFERS   512
+
+#define SMALL_BUFFER_SIZE 256
+#define LARGE_BUFFER_SIZE	PAGE_SIZE
+#define MAX_SPLIT_SIZE 1023
+#define QLGE_SB_PAD 32
+
+#define DFLT_COALESCE_WAIT 100	/* 100 usec wait for coalescing */
+#define MAX_INTER_FRAME_WAIT 10	/* 10 usec max interframe-wait for coalescing */
+#define DFLT_INTER_FRAME_WAIT (MAX_INTER_FRAME_WAIT/2)
+#define UDELAY_COUNT 3
+#define UDELAY_DELAY 10
+
+
+#define TX_DESC_PER_IOCB 8
+/* The maximum number of frags we handle is based
+ * on PAGE_SIZE...
+ */
+#if (PAGE_SHIFT == 12) || (PAGE_SHIFT == 13)	/* 4k & 8k pages */
+#define TX_DESC_PER_OAL ((MAX_SKB_FRAGS - TX_DESC_PER_IOCB) + 2)
+#else /* all other page sizes */
+#define TX_DESC_PER_OAL 0
+#endif
+
+#define DB_PAGE_SIZE 4096
+
+/*
+ * Processor Address Register (PROC_ADDR) bit definitions.
+ */
+enum {
+
+	/* Misc. stuff */
+	MAILBOX_COUNT = 16,
+
+	PROC_ADDR_RDY = (1 << 31),
+	PROC_ADDR_R = (1 << 30),
+	PROC_ADDR_ERR = (1 << 29),
+	PROC_ADDR_DA = (1 << 28),
+	PROC_ADDR_FUNC0_MBI = 0x00001180,
+	PROC_ADDR_FUNC0_MBO = (PROC_ADDR_FUNC0_MBI + MAILBOX_COUNT),
+	PROC_ADDR_FUNC0_CTL = 0x000011a1,
+	PROC_ADDR_FUNC2_MBI = 0x00001280,
+	PROC_ADDR_FUNC2_MBO = (PROC_ADDR_FUNC2_MBI + MAILBOX_COUNT),
+	PROC_ADDR_FUNC2_CTL = 0x000012a1,
+	PROC_ADDR_MPI_RISC = 0x00000000,
+	PROC_ADDR_MDE = 0x00010000,
+	PROC_ADDR_REGBLOCK = 0x00020000,
+	PROC_ADDR_RISC_REG = 0x00030000,
+};
+
+/*
+ * System Register (SYS) bit definitions.
+ */
+enum {
+	SYS_EFE = (1 << 0),
+	SYS_FAE = (1 << 1),
+	SYS_MDC = (1 << 2),
+	SYS_DST = (1 << 3),
+	SYS_DWC = (1 << 4),
+	SYS_EVW = (1 << 5),
+	SYS_OMP_DLY_MASK = 0x3f000000,
+	/*
+	 * There are no values defined as of edit #15.
+	 */
+	SYS_ODI = (1 << 14),
+};
+
+/*
+ *  Reset/Failover Register (RST_FO) bit definitions.
+ */
+enum {
+	RST_FO_TFO = (1 << 0),
+	RST_FO_RR_MASK = 0x00060000,
+	RST_FO_RR_CQ_CAM = 0x00000000,
+	RST_FO_RR_DROP = 0x00000001,
+	RST_FO_RR_DQ = 0x00000002,
+	RST_FO_RR_RCV_FUNC_CQ = 0x00000003,
+	RST_FO_FRB = (1 << 12),
+	RST_FO_MOP = (1 << 13),
+	RST_FO_REG = (1 << 14),
+	RST_FO_FR = (1 << 15),
+};
+
+/*
+ * Function Specific Control Register (FSC) bit definitions.
+ */
+enum {
+	FSC_DBRST_MASK = 0x00070000,
+	FSC_DBRST_256 = 0x00000000,
+	FSC_DBRST_512 = 0x00000001,
+	FSC_DBRST_768 = 0x00000002,
+	FSC_DBRST_1024 = 0x00000003,
+	FSC_DBL_MASK = 0x00180000,
+	FSC_DBL_DBRST = 0x00000000,
+	FSC_DBL_MAX_PLD = 0x00000008,
+	FSC_DBL_MAX_BRST = 0x00000010,
+	FSC_DBL_128_BYTES = 0x00000018,
+	FSC_EC = (1 << 5),
+	FSC_EPC_MASK = 0x00c00000,
+	FSC_EPC_INBOUND = (1 << 6),
+	FSC_EPC_OUTBOUND = (1 << 7),
+	FSC_VM_PAGESIZE_MASK = 0x07000000,
+	FSC_VM_PAGE_2K = 0x00000100,
+	FSC_VM_PAGE_4K = 0x00000200,
+	FSC_VM_PAGE_8K = 0x00000300,
+	FSC_VM_PAGE_64K = 0x00000600,
+	FSC_SH = (1 << 11),
+	FSC_DSB = (1 << 12),
+	FSC_STE = (1 << 13),
+	FSC_FE = (1 << 15),
+};
+
+/*
+ *  Host Command Status Register (CSR) bit definitions.
+ */
+enum {
+	CSR_ERR_STS_MASK = 0x0000003f,
+	/*
+	 * There are no valued defined as of edit #15.
+	 */
+	CSR_RR = (1 << 8),
+	CSR_HRI = (1 << 9),
+	CSR_RP = (1 << 10),
+	CSR_CMD_PARM_SHIFT = 22,
+	CSR_CMD_NOP = 0x00000000,
+	CSR_CMD_SET_RST = 0x1000000,
+	CSR_CMD_CLR_RST = 0x20000000,
+	CSR_CMD_SET_PAUSE = 0x30000000,
+	CSR_CMD_CLR_PAUSE = 0x40000000,
+	CSR_CMD_SET_H2R_INT = 0x50000000,
+	CSR_CMD_CLR_H2R_INT = 0x60000000,
+	CSR_CMD_PAR_EN = 0x70000000,
+	CSR_CMD_SET_BAD_PAR = 0x80000000,
+	CSR_CMD_CLR_BAD_PAR = 0x90000000,
+	CSR_CMD_CLR_R2PCI_INT = 0xa0000000,
+};
+
+/*
+ *  Configuration Register (CFG) bit definitions.
+ */
+enum {
+	CFG_LRQ = (1 << 0),
+	CFG_DRQ = (1 << 1),
+	CFG_LR = (1 << 2),
+	CFG_DR = (1 << 3),
+	CFG_LE = (1 << 5),
+	CFG_LCQ = (1 << 6),
+	CFG_DCQ = (1 << 7),
+	CFG_Q_SHIFT = 8,
+	CFG_Q_MASK = 0x7f000000,
+};
+
+/*
+ *  Status Register (STS) bit definitions.
+ */
+enum {
+	STS_FE = (1 << 0),
+	STS_PI = (1 << 1),
+	STS_PL0 = (1 << 2),
+	STS_PL1 = (1 << 3),
+	STS_PI0 = (1 << 4),
+	STS_PI1 = (1 << 5),
+	STS_FUNC_ID_MASK = 0x000000c0,
+	STS_FUNC_ID_SHIFT = 6,
+	STS_F0E = (1 << 8),
+	STS_F1E = (1 << 9),
+	STS_F2E = (1 << 10),
+	STS_F3E = (1 << 11),
+	STS_NFE = (1 << 12),
+};
+
+/*
+ * Interrupt Enable Register (INTR_EN) bit definitions.
+ */
+enum {
+	INTR_EN_INTR_MASK = 0x007f0000,
+	INTR_EN_TYPE_MASK = 0x03000000,
+	INTR_EN_TYPE_ENABLE = 0x00000100,
+	INTR_EN_TYPE_DISABLE = 0x00000200,
+	INTR_EN_TYPE_READ = 0x00000300,
+	INTR_EN_IHD = (1 << 13),
+	INTR_EN_IHD_MASK = (INTR_EN_IHD << 16),
+	INTR_EN_EI = (1 << 14),
+	INTR_EN_EN = (1 << 15),
+};
+
+/*
+ * Interrupt Mask Register (INTR_MASK) bit definitions.
+ */
+enum {
+	INTR_MASK_PI = (1 << 0),
+	INTR_MASK_HL0 = (1 << 1),
+	INTR_MASK_LH0 = (1 << 2),
+	INTR_MASK_HL1 = (1 << 3),
+	INTR_MASK_LH1 = (1 << 4),
+	INTR_MASK_SE = (1 << 5),
+	INTR_MASK_LSC = (1 << 6),
+	INTR_MASK_MC = (1 << 7),
+	INTR_MASK_LINK_IRQS = INTR_MASK_LSC | INTR_MASK_SE | INTR_MASK_MC,
+};
+
+/*
+ *  Register (REV_ID) bit definitions.
+ */
+enum {
+	REV_ID_MASK = 0x0000000f,
+	REV_ID_NICROLL_SHIFT = 0,
+	REV_ID_NICREV_SHIFT = 4,
+	REV_ID_XGROLL_SHIFT = 8,
+	REV_ID_XGREV_SHIFT = 12,
+	REV_ID_CHIPREV_SHIFT = 28,
+};
+
+/*
+ *  Force ECC Error Register (FRC_ECC_ERR) bit definitions.
+ */
+enum {
+	FRC_ECC_ERR_VW = (1 << 12),
+	FRC_ECC_ERR_VB = (1 << 13),
+	FRC_ECC_ERR_NI = (1 << 14),
+	FRC_ECC_ERR_NO = (1 << 15),
+	FRC_ECC_PFE_SHIFT = 16,
+	FRC_ECC_ERR_DO = (1 << 18),
+	FRC_ECC_P14 = (1 << 19),
+};
+
+/*
+ *  Error Status Register (ERR_STS) bit definitions.
+ */
+enum {
+	ERR_STS_NOF = (1 << 0),
+	ERR_STS_NIF = (1 << 1),
+	ERR_STS_DRP = (1 << 2),
+	ERR_STS_XGP = (1 << 3),
+	ERR_STS_FOU = (1 << 4),
+	ERR_STS_FOC = (1 << 5),
+	ERR_STS_FOF = (1 << 6),
+	ERR_STS_FIU = (1 << 7),
+	ERR_STS_FIC = (1 << 8),
+	ERR_STS_FIF = (1 << 9),
+	ERR_STS_MOF = (1 << 10),
+	ERR_STS_TA = (1 << 11),
+	ERR_STS_MA = (1 << 12),
+	ERR_STS_MPE = (1 << 13),
+	ERR_STS_SCE = (1 << 14),
+	ERR_STS_STE = (1 << 15),
+	ERR_STS_FOW = (1 << 16),
+	ERR_STS_UE = (1 << 17),
+	ERR_STS_MCH = (1 << 26),
+	ERR_STS_LOC_SHIFT = 27,
+};
+
+/*
+ *  RAM Debug Address Register (RAM_DBG_ADDR) bit definitions.
+ */
+enum {
+	RAM_DBG_ADDR_FW = (1 << 30),
+	RAM_DBG_ADDR_FR = (1 << 31),
+};
+
+/*
+ * Semaphore Register (SEM) bit definitions.
+ */
+enum {
+	/*
+	 * Example:
+	 * reg = SEM_XGMAC0_MASK | (SEM_SET << SEM_XGMAC0_SHIFT)
+	 */
+	SEM_CLEAR = 0,
+	SEM_SET = 1,
+	SEM_FORCE = 3,
+	SEM_XGMAC0_SHIFT = 0,
+	SEM_XGMAC1_SHIFT = 2,
+	SEM_ICB_SHIFT = 4,
+	SEM_MAC_ADDR_SHIFT = 6,
+	SEM_FLASH_SHIFT = 8,
+	SEM_PROBE_SHIFT = 10,
+	SEM_RT_IDX_SHIFT = 12,
+	SEM_PROC_REG_SHIFT = 14,
+	SEM_XGMAC0_MASK = 0x00030000,
+	SEM_XGMAC1_MASK = 0x000c0000,
+	SEM_ICB_MASK = 0x00300000,
+	SEM_MAC_ADDR_MASK = 0x00c00000,
+	SEM_FLASH_MASK = 0x03000000,
+	SEM_PROBE_MASK = 0x0c000000,
+	SEM_RT_IDX_MASK = 0x30000000,
+	SEM_PROC_REG_MASK = 0xc0000000,
+};
+
+/*
+ *  10G MAC Address  Register (XGMAC_ADDR) bit definitions.
+ */
+enum {
+	XGMAC_ADDR_RDY = (1 << 31),
+	XGMAC_ADDR_R = (1 << 30),
+	XGMAC_ADDR_XME = (1 << 29),
+
+	/* XGMAC control registers */
+	PAUSE_SRC_LO = 0x00000100,
+	PAUSE_SRC_HI = 0x00000104,
+	GLOBAL_CFG = 0x00000108,
+	GLOBAL_CFG_RESET = (1 << 0),
+	GLOBAL_CFG_JUMBO = (1 << 6),
+	GLOBAL_CFG_TX_STAT_EN = (1 << 10),
+	GLOBAL_CFG_RX_STAT_EN = (1 << 11),
+	TX_CFG = 0x0000010c,
+	TX_CFG_RESET = (1 << 0),
+	TX_CFG_EN = (1 << 1),
+	TX_CFG_PREAM = (1 << 2),
+	RX_CFG = 0x00000110,
+	RX_CFG_RESET = (1 << 0),
+	RX_CFG_EN = (1 << 1),
+	RX_CFG_PREAM = (1 << 2),
+	FLOW_CTL = 0x0000011c,
+	PAUSE_OPCODE = 0x00000120,
+	PAUSE_TIMER = 0x00000124,
+	PAUSE_FRM_DEST_LO = 0x00000128,
+	PAUSE_FRM_DEST_HI = 0x0000012c,
+	MAC_TX_PARAMS = 0x00000134,
+	MAC_TX_PARAMS_JUMBO = (1 << 31),
+	MAC_TX_PARAMS_SIZE_SHIFT = 16,
+	MAC_RX_PARAMS = 0x00000138,
+	MAC_SYS_INT = 0x00000144,
+	MAC_SYS_INT_MASK = 0x00000148,
+	MAC_MGMT_INT = 0x0000014c,
+	MAC_MGMT_IN_MASK = 0x00000150,
+	EXT_ARB_MODE = 0x000001fc,
+
+	/* XGMAC TX statistics  registers */
+	TX_PKTS = 0x00000200,
+	TX_BYTES = 0x00000208,
+	TX_MCAST_PKTS = 0x00000210,
+	TX_BCAST_PKTS = 0x00000218,
+	TX_UCAST_PKTS = 0x00000220,
+	TX_CTL_PKTS = 0x00000228,
+	TX_PAUSE_PKTS = 0x00000230,
+	TX_64_PKT = 0x00000238,
+	TX_65_TO_127_PKT = 0x00000240,
+	TX_128_TO_255_PKT = 0x00000248,
+	TX_256_511_PKT = 0x00000250,
+	TX_512_TO_1023_PKT = 0x00000258,
+	TX_1024_TO_1518_PKT = 0x00000260,
+	TX_1519_TO_MAX_PKT = 0x00000268,
+	TX_UNDERSIZE_PKT = 0x00000270,
+	TX_OVERSIZE_PKT = 0x00000278,
+
+	/* XGMAC statistics control registers */
+	RX_HALF_FULL_DET = 0x000002a0,
+	TX_HALF_FULL_DET = 0x000002a4,
+	RX_OVERFLOW_DET = 0x000002a8,
+	TX_OVERFLOW_DET = 0x000002ac,
+	RX_HALF_FULL_MASK = 0x000002b0,
+	TX_HALF_FULL_MASK = 0x000002b4,
+	RX_OVERFLOW_MASK = 0x000002b8,
+	TX_OVERFLOW_MASK = 0x000002bc,
+	STAT_CNT_CTL = 0x000002c0,
+	STAT_CNT_CTL_CLEAR_TX = (1 << 0),
+	STAT_CNT_CTL_CLEAR_RX = (1 << 1),
+	AUX_RX_HALF_FULL_DET = 0x000002d0,
+	AUX_TX_HALF_FULL_DET = 0x000002d4,
+	AUX_RX_OVERFLOW_DET = 0x000002d8,
+	AUX_TX_OVERFLOW_DET = 0x000002dc,
+	AUX_RX_HALF_FULL_MASK = 0x000002f0,
+	AUX_TX_HALF_FULL_MASK = 0x000002f4,
+	AUX_RX_OVERFLOW_MASK = 0x000002f8,
+	AUX_TX_OVERFLOW_MASK = 0x000002fc,
+
+	/* XGMAC RX statistics  registers */
+	RX_BYTES = 0x00000300,
+	RX_BYTES_OK = 0x00000308,
+	RX_PKTS = 0x00000310,
+	RX_PKTS_OK = 0x00000318,
+	RX_BCAST_PKTS = 0x00000320,
+	RX_MCAST_PKTS = 0x00000328,
+	RX_UCAST_PKTS = 0x00000330,
+	RX_UNDERSIZE_PKTS = 0x00000338,
+	RX_OVERSIZE_PKTS = 0x00000340,
+	RX_JABBER_PKTS = 0x00000348,
+	RX_UNDERSIZE_FCERR_PKTS = 0x00000350,
+	RX_DROP_EVENTS = 0x00000358,
+	RX_FCERR_PKTS = 0x00000360,
+	RX_ALIGN_ERR = 0x00000368,
+	RX_SYMBOL_ERR = 0x00000370,
+	RX_MAC_ERR = 0x00000378,
+	RX_CTL_PKTS = 0x00000380,
+	RX_PAUSE_PKTS = 0x00000384,
+	RX_64_PKTS = 0x00000390,
+	RX_65_TO_127_PKTS = 0x00000398,
+	RX_128_255_PKTS = 0x000003a0,
+	RX_256_511_PKTS = 0x000003a8,
+	RX_512_TO_1023_PKTS = 0x000003b0,
+	RX_1024_TO_1518_PKTS = 0x000003b8,
+	RX_1519_TO_MAX_PKTS = 0x000003c0,
+	RX_LEN_ERR_PKTS = 0x000003c8,
+
+	/* XGMAC MDIO control registers */
+	MDIO_TX_DATA = 0x00000400,
+	MDIO_RX_DATA = 0x00000410,
+	MDIO_CMD = 0x00000420,
+	MDIO_PHY_ADDR = 0x00000430,
+	MDIO_PORT = 0x00000440,
+	MDIO_STATUS = 0x00000450,
+
+	/* XGMAC AUX statistics  registers */
+};
+
+/*
+ *  Enhanced Transmission Schedule Registers (NIC_ETS,CNA_ETS) bit definitions.
+ */
+enum {
+	ETS_QUEUE_SHIFT = 29,
+	ETS_REF = (1 << 26),
+	ETS_RS = (1 << 27),
+	ETS_P = (1 << 28),
+	ETS_FC_COS_SHIFT = 23,
+};
+
+/*
+ *  Flash Address Register (FLASH_ADDR) bit definitions.
+ */
+enum {
+	FLASH_ADDR_RDY = (1 << 31),
+	FLASH_ADDR_R = (1 << 30),
+	FLASH_ADDR_ERR = (1 << 29),
+};
+
+/*
+ *  Stop CQ Processing Register (CQ_STOP) bit definitions.
+ */
+enum {
+	CQ_STOP_QUEUE_MASK = (0x007f0000),
+	CQ_STOP_TYPE_MASK = (0x03000000),
+	CQ_STOP_TYPE_START = 0x00000100,
+	CQ_STOP_TYPE_STOP = 0x00000200,
+	CQ_STOP_TYPE_READ = 0x00000300,
+	CQ_STOP_EN = (1 << 15),
+};
+
+/*
+ *  MAC Protocol Address Index Register (MAC_ADDR_IDX) bit definitions.
+ */
+enum {
+	MAC_ADDR_IDX_SHIFT = 4,
+	MAC_ADDR_TYPE_SHIFT = 16,
+	MAC_ADDR_TYPE_MASK = 0x000f0000,
+	MAC_ADDR_TYPE_CAM_MAC = 0x00000000,
+	MAC_ADDR_TYPE_MULTI_MAC = 0x00010000,
+	MAC_ADDR_TYPE_VLAN = 0x00020000,
+	MAC_ADDR_TYPE_MULTI_FLTR = 0x00030000,
+	MAC_ADDR_TYPE_FC_MAC = 0x00040000,
+	MAC_ADDR_TYPE_MGMT_MAC = 0x00050000,
+	MAC_ADDR_TYPE_MGMT_VLAN = 0x00060000,
+	MAC_ADDR_TYPE_MGMT_V4 = 0x00070000,
+	MAC_ADDR_TYPE_MGMT_V6 = 0x00080000,
+	MAC_ADDR_TYPE_MGMT_TU_DP = 0x00090000,
+	MAC_ADDR_ADR = (1 << 25),
+	MAC_ADDR_RS = (1 << 26),
+	MAC_ADDR_E = (1 << 27),
+	MAC_ADDR_MR = (1 << 30),
+	MAC_ADDR_MW = (1 << 31),
+	MAX_MULTICAST_ENTRIES = 32,
+};
+
+/*
+ *  MAC Protocol Address Index Register (SPLT_HDR) bit definitions.
+ */
+enum {
+	SPLT_HDR_EP = (1 << 31),
+};
+
+/*
+ *  FCoE Receive Configuration Register (FC_RCV_CFG) bit definitions.
+ */
+enum {
+	FC_RCV_CFG_ECT = (1 << 15),
+	FC_RCV_CFG_DFH = (1 << 20),
+	FC_RCV_CFG_DVF = (1 << 21),
+	FC_RCV_CFG_RCE = (1 << 27),
+	FC_RCV_CFG_RFE = (1 << 28),
+	FC_RCV_CFG_TEE = (1 << 29),
+	FC_RCV_CFG_TCE = (1 << 30),
+	FC_RCV_CFG_TFE = (1 << 31),
+};
+
+/*
+ *  NIC Receive Configuration Register (NIC_RCV_CFG) bit definitions.
+ */
+enum {
+	NIC_RCV_CFG_PPE = (1 << 0),
+	NIC_RCV_CFG_VLAN_MASK = 0x00060000,
+	NIC_RCV_CFG_VLAN_ALL = 0x00000000,
+	NIC_RCV_CFG_VLAN_MATCH_ONLY = 0x00000002,
+	NIC_RCV_CFG_VLAN_MATCH_AND_NON = 0x00000004,
+	NIC_RCV_CFG_VLAN_NONE_AND_NON = 0x00000006,
+	NIC_RCV_CFG_RV = (1 << 3),
+	NIC_RCV_CFG_DFQ_MASK = (0x7f000000),
+	NIC_RCV_CFG_DFQ_SHIFT = 8,
+	NIC_RCV_CFG_DFQ = 0,	/* HARDCODE default queue to 0. */
+};
+
+/*
+ *   Mgmt Receive Configuration Register (MGMT_RCV_CFG) bit definitions.
+ */
+enum {
+	MGMT_RCV_CFG_ARP = (1 << 0),
+	MGMT_RCV_CFG_DHC = (1 << 1),
+	MGMT_RCV_CFG_DHS = (1 << 2),
+	MGMT_RCV_CFG_NP = (1 << 3),
+	MGMT_RCV_CFG_I6N = (1 << 4),
+	MGMT_RCV_CFG_I6R = (1 << 5),
+	MGMT_RCV_CFG_DH6 = (1 << 6),
+	MGMT_RCV_CFG_UD1 = (1 << 7),
+	MGMT_RCV_CFG_UD0 = (1 << 8),
+	MGMT_RCV_CFG_BCT = (1 << 9),
+	MGMT_RCV_CFG_MCT = (1 << 10),
+	MGMT_RCV_CFG_DM = (1 << 11),
+	MGMT_RCV_CFG_RM = (1 << 12),
+	MGMT_RCV_CFG_STL = (1 << 13),
+	MGMT_RCV_CFG_VLAN_MASK = 0xc0000000,
+	MGMT_RCV_CFG_VLAN_ALL = 0x00000000,
+	MGMT_RCV_CFG_VLAN_MATCH_ONLY = 0x00004000,
+	MGMT_RCV_CFG_VLAN_MATCH_AND_NON = 0x00008000,
+	MGMT_RCV_CFG_VLAN_NONE_AND_NON = 0x0000c000,
+};
+
+/*
+ *  Routing Index Register (RT_IDX) bit definitions.
+ */
+enum {
+	RT_IDX_IDX_SHIFT = 8,
+	RT_IDX_TYPE_MASK = 0x000f0000,
+	RT_IDX_TYPE_RT = 0x00000000,
+	RT_IDX_TYPE_RT_INV = 0x00010000,
+	RT_IDX_TYPE_NICQ = 0x00020000,
+	RT_IDX_TYPE_NICQ_INV = 0x00030000,
+	RT_IDX_DST_MASK = 0x00700000,
+	RT_IDX_DST_RSS = 0x00000000,
+	RT_IDX_DST_CAM_Q = 0x00100000,
+	RT_IDX_DST_COS_Q = 0x00200000,
+	RT_IDX_DST_DFLT_Q = 0x00300000,
+	RT_IDX_DST_DEST_Q = 0x00400000,
+	RT_IDX_RS = (1 << 26),
+	RT_IDX_E = (1 << 27),
+	RT_IDX_MR = (1 << 30),
+	RT_IDX_MW = (1 << 31),
+
+	/* Nic Queue format - type 2 bits */
+	RT_IDX_BCAST = (1 << 0),
+	RT_IDX_MCAST = (1 << 1),
+	RT_IDX_MCAST_MATCH = (1 << 2),
+	RT_IDX_MCAST_REG_MATCH = (1 << 3),
+	RT_IDX_MCAST_HASH_MATCH = (1 << 4),
+	RT_IDX_FC_MACH = (1 << 5),
+	RT_IDX_ETH_FCOE = (1 << 6),
+	RT_IDX_CAM_HIT = (1 << 7),
+	RT_IDX_CAM_BIT0 = (1 << 8),
+	RT_IDX_CAM_BIT1 = (1 << 9),
+	RT_IDX_VLAN_TAG = (1 << 10),
+	RT_IDX_VLAN_MATCH = (1 << 11),
+	RT_IDX_VLAN_FILTER = (1 << 12),
+	RT_IDX_ETH_SKIP1 = (1 << 13),
+	RT_IDX_ETH_SKIP2 = (1 << 14),
+	RT_IDX_BCAST_MCAST_MATCH = (1 << 15),
+	RT_IDX_802_3 = (1 << 16),
+	RT_IDX_LLDP = (1 << 17),
+	RT_IDX_UNUSED018 = (1 << 18),
+	RT_IDX_UNUSED019 = (1 << 19),
+	RT_IDX_UNUSED20 = (1 << 20),
+	RT_IDX_UNUSED21 = (1 << 21),
+	RT_IDX_ERR = (1 << 22),
+	RT_IDX_VALID = (1 << 23),
+	RT_IDX_TU_CSUM_ERR = (1 << 24),
+	RT_IDX_IP_CSUM_ERR = (1 << 25),
+	RT_IDX_MAC_ERR = (1 << 26),
+	RT_IDX_RSS_TCP6 = (1 << 27),
+	RT_IDX_RSS_TCP4 = (1 << 28),
+	RT_IDX_RSS_IPV6 = (1 << 29),
+	RT_IDX_RSS_IPV4 = (1 << 30),
+	RT_IDX_RSS_MATCH = (1 << 31),
+
+	/* Hierarchy for the NIC Queue Mask */
+	RT_IDX_ALL_ERR_SLOT = 0,
+	RT_IDX_MAC_ERR_SLOT = 0,
+	RT_IDX_IP_CSUM_ERR_SLOT = 1,
+	RT_IDX_TCP_UDP_CSUM_ERR_SLOT = 2,
+	RT_IDX_BCAST_SLOT = 3,
+	RT_IDX_MCAST_MATCH_SLOT = 4,
+	RT_IDX_ALLMULTI_SLOT = 5,
+	RT_IDX_UNUSED6_SLOT = 6,
+	RT_IDX_UNUSED7_SLOT = 7,
+	RT_IDX_RSS_MATCH_SLOT = 8,
+	RT_IDX_RSS_IPV4_SLOT = 8,
+	RT_IDX_RSS_IPV6_SLOT = 9,
+	RT_IDX_RSS_TCP4_SLOT = 10,
+	RT_IDX_RSS_TCP6_SLOT = 11,
+	RT_IDX_CAM_HIT_SLOT = 12,
+	RT_IDX_UNUSED013 = 13,
+	RT_IDX_UNUSED014 = 14,
+	RT_IDX_PROMISCUOUS_SLOT = 15,
+	RT_IDX_MAX_SLOTS = 16,
+};
+
+/*
+ * Control Register Set Map
+ */
+enum {
+	PROC_ADDR = 0,		/* Use semaphore */
+	PROC_DATA = 0x04,	/* Use semaphore */
+	SYS = 0x08,
+	RST_FO = 0x0c,
+	FSC = 0x10,
+	CSR = 0x14,
+	LED = 0x18,
+	ICB_RID = 0x1c,		/* Use semaphore */
+	ICB_L = 0x20,		/* Use semaphore */
+	ICB_H = 0x24,		/* Use semaphore */
+	CFG = 0x28,
+	BIOS_ADDR = 0x2c,
+	STS = 0x30,
+	INTR_EN = 0x34,
+	INTR_MASK = 0x38,
+	ISR1 = 0x3c,
+	ISR2 = 0x40,
+	ISR3 = 0x44,
+	ISR4 = 0x48,
+	REV_ID = 0x4c,
+	FRC_ECC_ERR = 0x50,
+	ERR_STS = 0x54,
+	RAM_DBG_ADDR = 0x58,
+	RAM_DBG_DATA = 0x5c,
+	ECC_ERR_CNT = 0x60,
+	SEM = 0x64,
+	GPIO_1 = 0x68,		/* Use semaphore */
+	GPIO_2 = 0x6c,		/* Use semaphore */
+	GPIO_3 = 0x70,		/* Use semaphore */
+	RSVD2 = 0x74,
+	XGMAC_ADDR = 0x78,	/* Use semaphore */
+	XGMAC_DATA = 0x7c,	/* Use semaphore */
+	NIC_ETS = 0x80,
+	CNA_ETS = 0x84,
+	FLASH_ADDR = 0x88,	/* Use semaphore */
+	FLASH_DATA = 0x8c,	/* Use semaphore */
+	CQ_STOP = 0x90,
+	PAGE_TBL_RID = 0x94,
+	WQ_PAGE_TBL_LO = 0x98,
+	WQ_PAGE_TBL_HI = 0x9c,
+	CQ_PAGE_TBL_LO = 0xa0,
+	CQ_PAGE_TBL_HI = 0xa4,
+	MAC_ADDR_IDX = 0xa8,	/* Use semaphore */
+	MAC_ADDR_DATA = 0xac,	/* Use semaphore */
+	COS_DFLT_CQ1 = 0xb0,
+	COS_DFLT_CQ2 = 0xb4,
+	ETYPE_SKIP1 = 0xb8,
+	ETYPE_SKIP2 = 0xbc,
+	SPLT_HDR = 0xc0,
+	FC_PAUSE_THRES = 0xc4,
+	NIC_PAUSE_THRES = 0xc8,
+	FC_ETHERTYPE = 0xcc,
+	FC_RCV_CFG = 0xd0,
+	NIC_RCV_CFG = 0xd4,
+	FC_COS_TAGS = 0xd8,
+	NIC_COS_TAGS = 0xdc,
+	MGMT_RCV_CFG = 0xe0,
+	RT_IDX = 0xe4,
+	RT_DATA = 0xe8,
+	RSVD7 = 0xec,
+	XG_SERDES_ADDR = 0xf0,
+	XG_SERDES_DATA = 0xf4,
+	PRB_MX_ADDR = 0xf8,	/* Use semaphore */
+	PRB_MX_DATA = 0xfc,	/* Use semaphore */
+};
+
+/*
+ * CAM output format.
+ */
+enum {
+	CAM_OUT_ROUTE_FC = 0,
+	CAM_OUT_ROUTE_NIC = 1,
+	CAM_OUT_FUNC_SHIFT = 2,
+	CAM_OUT_RV = (1 << 4),
+	CAM_OUT_SH = (1 << 15),
+	CAM_OUT_CQ_ID_SHIFT = 5,
+};
+
+/*
+ * Mailbox  definitions
+ */
+enum {
+	/* Asynchronous Event Notifications */
+	AEN_SYS_ERR = 0x00008002,
+	AEN_LINK_UP = 0x00008011,
+	AEN_LINK_DOWN = 0x00008012,
+	AEN_IDC_CMPLT = 0x00008100,
+	AEN_IDC_REQ = 0x00008101,
+	AEN_FW_INIT_DONE = 0x00008400,
+	AEN_FW_INIT_FAIL = 0x00008401,
+
+	/* Mailbox Command Opcodes. */
+	MB_CMD_NOP = 0x00000000,
+	MB_CMD_EX_FW = 0x00000002,
+	MB_CMD_MB_TEST = 0x00000006,
+	MB_CMD_CSUM_TEST = 0x00000007,	/* Verify Checksum */
+	MB_CMD_ABOUT_FW = 0x00000008,
+	MB_CMD_LOAD_RISC_RAM = 0x0000000b,
+	MB_CMD_DUMP_RISC_RAM = 0x0000000c,
+	MB_CMD_WRITE_RAM = 0x0000000d,
+	MB_CMD_READ_RAM = 0x0000000f,
+	MB_CMD_STOP_FW = 0x00000014,
+	MB_CMD_MAKE_SYS_ERR = 0x0000002a,
+	MB_CMD_INIT_FW = 0x00000060,
+	MB_CMD_GET_INIT_CB = 0x00000061,
+	MB_CMD_GET_FW_STATE = 0x00000069,
+	MB_CMD_IDC_REQ = 0x00000100,	/* Inter-Driver Communication */
+	MB_CMD_IDC_ACK = 0x00000101,	/* Inter-Driver Communication */
+	MB_CMD_SET_WOL_MODE = 0x00000110,	/* Wake On Lan */
+	MB_WOL_DISABLE = 0x00000000,
+	MB_WOL_MAGIC_PKT = 0x00000001,
+	MB_WOL_FLTR = 0x00000002,
+	MB_WOL_UCAST = 0x00000004,
+	MB_WOL_MCAST = 0x00000008,
+	MB_WOL_BCAST = 0x00000010,
+	MB_WOL_LINK_UP = 0x00000020,
+	MB_WOL_LINK_DOWN = 0x00000040,
+	MB_CMD_SET_WOL_FLTR = 0x00000111,	/* Wake On Lan Filter */
+	MB_CMD_CLEAR_WOL_FLTR = 0x00000112,	/* Wake On Lan Filter */
+	MB_CMD_SET_WOL_MAGIC = 0x00000113,	/* Wake On Lan Magic Packet */
+	MB_CMD_CLEAR_WOL_MAGIC = 0x00000114,	/* Wake On Lan Magic Packet */
+	MB_CMD_PORT_RESET = 0x00000120,
+	MB_CMD_SET_PORT_CFG = 0x00000122,
+	MB_CMD_GET_PORT_CFG = 0x00000123,
+	MB_CMD_SET_ASIC_VOLTS = 0x00000130,
+	MB_CMD_GET_SNS_DATA = 0x00000131,	/* Temp and Volt Sense data. */
+
+	/* Mailbox Command Status. */
+	MB_CMD_STS_GOOD = 0x00004000,	/* Success. */
+	MB_CMD_STS_INTRMDT = 0x00001000,	/* Intermediate Complete. */
+	MB_CMD_STS_ERR = 0x00004005,	/* Error. */
+};
+
+struct mbox_params {
+	u32 mbox_in[MAILBOX_COUNT];
+	u32 mbox_out[MAILBOX_COUNT];
+	int in_count;
+	int out_count;
+};
+
+struct flash_params {
+	u8 dev_id_str[4];
+	u16 size;
+	u16 csum;
+	u16 ver;
+	u16 sub_dev_id;
+	u8 mac_addr[6];
+	u16 res;
+};
+
+
+/*
+ * doorbell space for the rx ring context
+ */
+struct rx_doorbell_context {
+	u32 cnsmr_idx;		/* 0x00 */
+	u32 valid;		/* 0x04 */
+	u32 reserved[4];	/* 0x08-0x14 */
+	u32 lbq_prod_idx;	/* 0x18 */
+	u32 sbq_prod_idx;	/* 0x1c */
+};
+
+/*
+ * doorbell space for the tx ring context
+ */
+struct tx_doorbell_context {
+	u32 prod_idx;		/* 0x00 */
+	u32 valid;		/* 0x04 */
+	u32 reserved[4];	/* 0x08-0x14 */
+	u32 lbq_prod_idx;	/* 0x18 */
+	u32 sbq_prod_idx;	/* 0x1c */
+};
+
+/* DATA STRUCTURES SHARED WITH HARDWARE. */
+
+struct bq_element {
+	u32 addr_lo;
+#define BQ_END	0x00000001
+#define BQ_CONT	0x00000002
+#define BQ_MASK	0x00000003
+	u32 addr_hi;
+} __attribute((packed));
+
+struct tx_buf_desc {
+	__le64 addr;
+	__le32 len;
+#define TX_DESC_LEN_MASK	0x000fffff
+#define TX_DESC_C	0x40000000
+#define TX_DESC_E	0x80000000
+} __attribute((packed));
+
+/*
+ * IOCB Definitions...
+ */
+
+#define OPCODE_OB_MAC_IOCB 			0x01
+#define OPCODE_OB_MAC_TSO_IOCB		0x02
+#define OPCODE_IB_MAC_IOCB			0x20
+#define OPCODE_IB_MPI_IOCB			0x21
+#define OPCODE_IB_AE_IOCB			0x3f
+
+struct ob_mac_iocb_req {
+	u8 opcode;
+	u8 flags1;
+#define OB_MAC_IOCB_REQ_OI	0x01
+#define OB_MAC_IOCB_REQ_I	0x02
+#define OB_MAC_IOCB_REQ_D	0x08
+#define OB_MAC_IOCB_REQ_F	0x10
+	u8 flags2;
+	u8 flags3;
+#define OB_MAC_IOCB_DFP	0x02
+#define OB_MAC_IOCB_V	0x04
+	__le32 reserved1[2];
+	__le16 frame_len;
+#define OB_MAC_IOCB_LEN_MASK 0x3ffff
+	__le16 reserved2;
+	__le32 tid;
+	__le32 txq_idx;
+	__le32 reserved3;
+	__le16 vlan_tci;
+	__le16 reserved4;
+	struct tx_buf_desc tbd[TX_DESC_PER_IOCB];
+} __attribute((packed));
+
+struct ob_mac_iocb_rsp {
+	u8 opcode;		/* */
+	u8 flags1;		/* */
+#define OB_MAC_IOCB_RSP_OI	0x01	/* */
+#define OB_MAC_IOCB_RSP_I	0x02	/* */
+#define OB_MAC_IOCB_RSP_E	0x08	/* */
+#define OB_MAC_IOCB_RSP_S	0x10	/* too Short */
+#define OB_MAC_IOCB_RSP_L	0x20	/* too Large */
+#define OB_MAC_IOCB_RSP_P	0x40	/* Padded */
+	u8 flags2;		/* */
+	u8 flags3;		/* */
+#define OB_MAC_IOCB_RSP_B	0x80	/* */
+	__le32 tid;
+	__le32 txq_idx;
+	__le32 reserved[13];
+} __attribute((packed));
+
+struct ob_mac_tso_iocb_req {
+	u8 opcode;
+	u8 flags1;
+#define OB_MAC_TSO_IOCB_OI	0x01
+#define OB_MAC_TSO_IOCB_I	0x02
+#define OB_MAC_TSO_IOCB_D	0x08
+#define OB_MAC_TSO_IOCB_IP4	0x40
+#define OB_MAC_TSO_IOCB_IP6	0x80
+	u8 flags2;
+#define OB_MAC_TSO_IOCB_LSO	0x20
+#define OB_MAC_TSO_IOCB_UC	0x40
+#define OB_MAC_TSO_IOCB_TC	0x80
+	u8 flags3;
+#define OB_MAC_TSO_IOCB_IC	0x01
+#define OB_MAC_TSO_IOCB_DFP	0x02
+#define OB_MAC_TSO_IOCB_V	0x04
+	__le32 reserved1[2];
+	__le32 frame_len;
+	__le32 tid;
+	__le32 txq_idx;
+	__le16 total_hdrs_len;
+	__le16 net_trans_offset;
+#define OB_MAC_TRANSPORT_HDR_SHIFT 6
+	__le16 vlan_tci;
+	__le16 mss;
+	struct tx_buf_desc tbd[TX_DESC_PER_IOCB];
+} __attribute((packed));
+
+struct ob_mac_tso_iocb_rsp {
+	u8 opcode;
+	u8 flags1;
+#define OB_MAC_TSO_IOCB_RSP_OI	0x01
+#define OB_MAC_TSO_IOCB_RSP_I	0x02
+#define OB_MAC_TSO_IOCB_RSP_E	0x08
+#define OB_MAC_TSO_IOCB_RSP_S	0x10
+#define OB_MAC_TSO_IOCB_RSP_L	0x20
+#define OB_MAC_TSO_IOCB_RSP_P	0x40
+	u8 flags2;		/* */
+	u8 flags3;		/* */
+#define OB_MAC_TSO_IOCB_RSP_B	0x8000
+	__le32 tid;
+	__le32 txq_idx;
+	__le32 reserved2[13];
+} __attribute((packed));
+
+struct ib_mac_iocb_rsp {
+	u8 opcode;		/* 0x20 */
+	u8 flags1;
+#define IB_MAC_IOCB_RSP_OI	0x01	/* Overide intr delay */
+#define IB_MAC_IOCB_RSP_I	0x02	/* Disble Intr Generation */
+#define IB_MAC_IOCB_RSP_TE	0x04	/* Checksum error */
+#define IB_MAC_IOCB_RSP_NU	0x08	/* No checksum rcvd */
+#define IB_MAC_IOCB_RSP_IE	0x10	/* IPv4 checksum error */
+#define IB_MAC_IOCB_RSP_M_MASK	0x60	/* Multicast info */
+#define IB_MAC_IOCB_RSP_M_NONE	0x00	/* Not mcast frame */
+#define IB_MAC_IOCB_RSP_M_HASH	0x20	/* HASH mcast frame */
+#define IB_MAC_IOCB_RSP_M_REG 	0x40	/* Registered mcast frame */
+#define IB_MAC_IOCB_RSP_M_PROM 	0x60	/* Promiscuous mcast frame */
+#define IB_MAC_IOCB_RSP_B	0x80	/* Broadcast frame */
+	u8 flags2;
+#define IB_MAC_IOCB_RSP_P	0x01	/* Promiscuous frame */
+#define IB_MAC_IOCB_RSP_V	0x02	/* Vlan tag present */
+#define IB_MAC_IOCB_RSP_ERR_MASK	0x1c	/*  */
+#define IB_MAC_IOCB_RSP_ERR_CODE_ERR	0x04
+#define IB_MAC_IOCB_RSP_ERR_OVERSIZE	0x08
+#define IB_MAC_IOCB_RSP_ERR_UNDERSIZE	0x10
+#define IB_MAC_IOCB_RSP_ERR_PREAMBLE	0x14
+#define IB_MAC_IOCB_RSP_ERR_FRAME_LEN	0x18
+#define IB_MAC_IOCB_RSP_ERR_CRC		0x1c
+#define IB_MAC_IOCB_RSP_U	0x20	/* UDP packet */
+#define IB_MAC_IOCB_RSP_T	0x40	/* TCP packet */
+#define IB_MAC_IOCB_RSP_FO	0x80	/* Failover port */
+	u8 flags3;
+#define IB_MAC_IOCB_RSP_RSS_MASK	0x07	/* RSS mask */
+#define IB_MAC_IOCB_RSP_M_NONE	0x00	/* No RSS match */
+#define IB_MAC_IOCB_RSP_M_IPV4	0x04	/* IPv4 RSS match */
+#define IB_MAC_IOCB_RSP_M_IPV6	0x02	/* IPv6 RSS match */
+#define IB_MAC_IOCB_RSP_M_TCP_V4 	0x05	/* TCP with IPv4 */
+#define IB_MAC_IOCB_RSP_M_TCP_V6 	0x03	/* TCP with IPv6 */
+#define IB_MAC_IOCB_RSP_V4	0x08	/* IPV4 */
+#define IB_MAC_IOCB_RSP_V6	0x10	/* IPV6 */
+#define IB_MAC_IOCB_RSP_IH	0x20	/* Split after IP header */
+#define IB_MAC_IOCB_RSP_DS	0x40	/* data is in small buffer */
+#define IB_MAC_IOCB_RSP_DL	0x80	/* data is in large buffer */
+	__le32 data_len;	/* */
+	__le32 data_addr_lo;	/* */
+	__le32 data_addr_hi;	/* */
+	__le32 rss;		/* */
+	__le16 vlan_id;		/* 12 bits */
+#define IB_MAC_IOCB_RSP_C	0x1000	/* VLAN CFI bit */
+#define IB_MAC_IOCB_RSP_COS_SHIFT	12	/* class of service value */
+
+	__le16 reserved1;
+	__le32 reserved2[6];
+	__le32 flags4;
+#define IB_MAC_IOCB_RSP_HV	0x20000000	/* */
+#define IB_MAC_IOCB_RSP_HS	0x40000000	/* */
+#define IB_MAC_IOCB_RSP_HL	0x80000000	/* */
+	__le32 hdr_len;		/* */
+	__le32 hdr_addr_lo;	/* */
+	__le32 hdr_addr_hi;	/* */
+} __attribute((packed));
+
+struct ib_ae_iocb_rsp {
+	u8 opcode;
+	u8 flags1;
+#define IB_AE_IOCB_RSP_OI		0x01
+#define IB_AE_IOCB_RSP_I		0x02
+	u8 event;
+#define LINK_UP_EVENT              0x00
+#define LINK_DOWN_EVENT            0x01
+#define CAM_LOOKUP_ERR_EVENT       0x06
+#define SOFT_ECC_ERROR_EVENT       0x07
+#define MGMT_ERR_EVENT             0x08
+#define TEN_GIG_MAC_EVENT          0x09
+#define GPI0_H2L_EVENT       	0x10
+#define GPI0_L2H_EVENT       	0x20
+#define GPI1_H2L_EVENT       	0x11
+#define GPI1_L2H_EVENT       	0x21
+#define PCI_ERR_ANON_BUF_RD        0x40
+	u8 q_id;
+	__le32 reserved[15];
+} __attribute((packed));
+
+/*
+ * These three structures are for generic
+ * handling of ib and ob iocbs.
+ */
+struct ql_net_rsp_iocb {
+	u8 opcode;
+	u8 flags0;
+	__le16 length;
+	__le32 tid;
+	__le32 reserved[14];
+} __attribute((packed));
+
+struct net_req_iocb {
+	u8 opcode;
+	u8 flags0;
+	__le16 flags1;
+	__le32 tid;
+	__le32 reserved1[30];
+} __attribute((packed));
+
+/*
+ * tx ring initialization control block for chip.
+ * It is defined as:
+ * "Work Queue Initialization Control Block"
+ */
+struct wqicb {
+	__le16 len;
+#define Q_LEN_V		(1 << 4)
+#define Q_LEN_CPP_CONT	0x0000
+#define Q_LEN_CPP_16	0x0001
+#define Q_LEN_CPP_32	0x0002
+#define Q_LEN_CPP_64	0x0003
+	__le16 flags;
+#define Q_PRI_SHIFT	1
+#define Q_FLAGS_LC	0x1000
+#define Q_FLAGS_LB	0x2000
+#define Q_FLAGS_LI	0x4000
+#define Q_FLAGS_LO	0x8000
+	__le16 cq_id_rss;
+#define Q_CQ_ID_RSS_RV 0x8000
+	__le16 rid;
+	__le32 addr_lo;
+	__le32 addr_hi;
+	__le32 cnsmr_idx_addr_lo;
+	__le32 cnsmr_idx_addr_hi;
+} __attribute((packed));
+
+/*
+ * rx ring initialization control block for chip.
+ * It is defined as:
+ * "Completion Queue Initialization Control Block"
+ */
+struct cqicb {
+	u8 msix_vect;
+	u8 reserved1;
+	u8 reserved2;
+	u8 flags;
+#define FLAGS_LV	0x08
+#define FLAGS_LS	0x10
+#define FLAGS_LL	0x20
+#define FLAGS_LI	0x40
+#define FLAGS_LC	0x80
+	__le16 len;
+#define LEN_V		(1 << 4)
+#define LEN_CPP_CONT	0x0000
+#define LEN_CPP_32	0x0001
+#define LEN_CPP_64	0x0002
+#define LEN_CPP_128	0x0003
+	__le16 rid;
+	__le32 addr_lo;
+	__le32 addr_hi;
+	__le32 prod_idx_addr_lo;
+	__le32 prod_idx_addr_hi;
+	__le16 pkt_delay;
+	__le16 irq_delay;
+	__le32 lbq_addr_lo;
+	__le32 lbq_addr_hi;
+	__le16 lbq_buf_size;
+	__le16 lbq_len;		/* entry count */
+	__le32 sbq_addr_lo;
+	__le32 sbq_addr_hi;
+	__le16 sbq_buf_size;
+	__le16 sbq_len;		/* entry count */
+} __attribute((packed));
+
+struct ricb {
+	u8 base_cq;
+#define RSS_L4K 0x80
+	u8 flags;
+#define RSS_L6K 0x01
+#define RSS_LI  0x02
+#define RSS_LB  0x04
+#define RSS_LM  0x08
+#define RSS_RI4 0x10
+#define RSS_RT4 0x20
+#define RSS_RI6 0x40
+#define RSS_RT6 0x80
+	__le16 mask;
+	__le32 hash_cq_id[256];
+	__le32 ipv6_hash_key[10];
+	__le32 ipv4_hash_key[4];
+} __attribute((packed));
+
+/* SOFTWARE/DRIVER DATA STRUCTURES. */
+
+struct oal {
+	struct tx_buf_desc oal[TX_DESC_PER_OAL];
+};
+
+struct map_list {
+	DECLARE_PCI_UNMAP_ADDR(mapaddr);
+	DECLARE_PCI_UNMAP_LEN(maplen);
+};
+
+struct tx_ring_desc {
+	struct sk_buff *skb;
+	struct ob_mac_iocb_req *queue_entry;
+	int index;
+	struct oal oal;
+	struct map_list map[MAX_SKB_FRAGS + 1];
+	int map_cnt;
+	struct tx_ring_desc *next;
+};
+
+struct bq_desc {
+	union {
+		struct page *lbq_page;
+		struct sk_buff *skb;
+	} p;
+	struct bq_element *bq;
+	int index;
+	 DECLARE_PCI_UNMAP_ADDR(mapaddr);
+	 DECLARE_PCI_UNMAP_LEN(maplen);
+};
+
+#define QL_TXQ_IDX(qdev, skb) (smp_processor_id()%(qdev->tx_ring_count))
+
+struct tx_ring {
+	/*
+	 * queue info.
+	 */
+	struct wqicb wqicb;	/* structure used to inform chip of new queue */
+	void *wq_base;		/* pci_alloc:virtual addr for tx */
+	dma_addr_t wq_base_dma;	/* pci_alloc:dma addr for tx */
+	u32 *cnsmr_idx_sh_reg;	/* shadow copy of consumer idx */
+	dma_addr_t cnsmr_idx_sh_reg_dma;	/* dma-shadow copy of consumer */
+	u32 wq_size;		/* size in bytes of queue area */
+	u32 wq_len;		/* number of entries in queue */
+	void __iomem *prod_idx_db_reg;	/* doorbell area index reg at offset 0x00 */
+	void __iomem *valid_db_reg;	/* doorbell area valid reg at offset 0x04 */
+	u16 prod_idx;		/* current value for prod idx */
+	u16 cq_id;		/* completion (rx) queue for tx completions */
+	u8 wq_id;		/* queue id for this entry */
+	u8 reserved1[3];
+	struct tx_ring_desc *q;	/* descriptor list for the queue */
+	spinlock_t lock;
+	atomic_t tx_count;	/* counts down for every outstanding IO */
+	atomic_t queue_stopped;	/* Turns queue off when full. */
+	struct delayed_work tx_work;
+	struct ql_adapter *qdev;
+};
+
+/*
+ * Type of inbound queue.
+ */
+enum {
+	DEFAULT_Q = 2,		/* Handles slow queue and chip/MPI events. */
+	TX_Q = 3,		/* Handles outbound completions. */
+	RX_Q = 4,		/* Handles inbound completions. */
+};
+
+struct rx_ring {
+	struct cqicb cqicb;	/* The chip's completion queue init control block. */
+
+	/* Completion queue elements. */
+	void *cq_base;
+	dma_addr_t cq_base_dma;
+	u32 cq_size;
+	u32 cq_len;
+	u16 cq_id;
+	u32 *prod_idx_sh_reg;	/* Shadowed producer register. */
+	dma_addr_t prod_idx_sh_reg_dma;
+	void __iomem *cnsmr_idx_db_reg;	/* PCI doorbell mem area + 0 */
+	u32 cnsmr_idx;		/* current sw idx */
+	struct ql_net_rsp_iocb *curr_entry;	/* next entry on queue */
+	void __iomem *valid_db_reg;	/* PCI doorbell mem area + 0x04 */
+
+	/* Large buffer queue elements. */
+	u32 lbq_len;		/* entry count */
+	u32 lbq_size;		/* size in bytes of queue */
+	u32 lbq_buf_size;
+	void *lbq_base;
+	dma_addr_t lbq_base_dma;
+	void *lbq_base_indirect;
+	dma_addr_t lbq_base_indirect_dma;
+	struct bq_desc *lbq;	/* array of control blocks */
+	void __iomem *lbq_prod_idx_db_reg;	/* PCI doorbell mem area + 0x18 */
+	u32 lbq_prod_idx;	/* current sw prod idx */
+	u32 lbq_curr_idx;	/* next entry we expect */
+	u32 lbq_clean_idx;	/* beginning of new descs */
+	u32 lbq_free_cnt;	/* free buffer desc cnt */
+
+	/* Small buffer queue elements. */
+	u32 sbq_len;		/* entry count */
+	u32 sbq_size;		/* size in bytes of queue */
+	u32 sbq_buf_size;
+	void *sbq_base;
+	dma_addr_t sbq_base_dma;
+	void *sbq_base_indirect;
+	dma_addr_t sbq_base_indirect_dma;
+	struct bq_desc *sbq;	/* array of control blocks */
+	void __iomem *sbq_prod_idx_db_reg; /* PCI doorbell mem area + 0x1c */
+	u32 sbq_prod_idx;	/* current sw prod idx */
+	u32 sbq_curr_idx;	/* next entry we expect */
+	u32 sbq_clean_idx;	/* beginning of new descs */
+	u32 sbq_free_cnt;	/* free buffer desc cnt */
+
+	/* Misc. handler elements. */
+	u32 type;		/* Type of queue, tx, rx, or default. */
+	u32 irq;		/* Which vector this ring is assigned. */
+	u32 cpu;		/* Which CPU this should run on. */
+	char name[IFNAMSIZ + 5];
+	struct napi_struct napi;
+	struct delayed_work rx_work;
+	u8 reserved;
+	struct ql_adapter *qdev;
+};
+
+/*
+ * RSS Initialization Control Block
+ */
+struct hash_id {
+	u8 value[4];
+};
+
+struct nic_stats {
+	/*
+	 * These stats come from offset 200h to 278h
+	 * in the XGMAC register.
+	 */
+	u64 tx_pkts;
+	u64 tx_bytes;
+	u64 tx_mcast_pkts;
+	u64 tx_bcast_pkts;
+	u64 tx_ucast_pkts;
+	u64 tx_ctl_pkts;
+	u64 tx_pause_pkts;
+	u64 tx_64_pkt;
+	u64 tx_65_to_127_pkt;
+	u64 tx_128_to_255_pkt;
+	u64 tx_256_511_pkt;
+	u64 tx_512_to_1023_pkt;
+	u64 tx_1024_to_1518_pkt;
+	u64 tx_1519_to_max_pkt;
+	u64 tx_undersize_pkt;
+	u64 tx_oversize_pkt;
+
+	/*
+	 * These stats come from offset 300h to 3C8h
+	 * in the XGMAC register.
+	 */
+	u64 rx_bytes;
+	u64 rx_bytes_ok;
+	u64 rx_pkts;
+	u64 rx_pkts_ok;
+	u64 rx_bcast_pkts;
+	u64 rx_mcast_pkts;
+	u64 rx_ucast_pkts;
+	u64 rx_undersize_pkts;
+	u64 rx_oversize_pkts;
+	u64 rx_jabber_pkts;
+	u64 rx_undersize_fcerr_pkts;
+	u64 rx_drop_events;
+	u64 rx_fcerr_pkts;
+	u64 rx_align_err;
+	u64 rx_symbol_err;
+	u64 rx_mac_err;
+	u64 rx_ctl_pkts;
+	u64 rx_pause_pkts;
+	u64 rx_64_pkts;
+	u64 rx_65_to_127_pkts;
+	u64 rx_128_255_pkts;
+	u64 rx_256_511_pkts;
+	u64 rx_512_to_1023_pkts;
+	u64 rx_1024_to_1518_pkts;
+	u64 rx_1519_to_max_pkts;
+	u64 rx_len_err_pkts;
+};
+
+/*
+ * intr_context structure is used during initialization
+ * to hook the interrupts.  It is also used in a single
+ * irq environment as a context to the ISR.
+ */
+struct intr_context {
+	struct ql_adapter *qdev;
+	u32 intr;
+	u32 hooked;
+	u32 intr_en_mask;	/* value/mask used to enable this intr */
+	u32 intr_dis_mask;	/* value/mask used to disable this intr */
+	u32 intr_read_mask;	/* value/mask used to read this intr */
+	char name[IFNAMSIZ * 2];
+	atomic_t irq_cnt;	/* irq_cnt is used in single vector
+				 * environment.  It's incremented for each
+				 * irq handler that is scheduled.  When each
+				 * handler finishes it decrements irq_cnt and
+				 * enables interrupts if it's zero. */
+	irq_handler_t handler;
+};
+
+/* adapter flags definitions. */
+enum {
+	QL_ADAPTER_UP = (1 << 0),	/* Adapter has been brought up. */
+	QL_LEGACY_ENABLED = (1 << 3),
+	QL_MSI_ENABLED = (1 << 3),
+	QL_MSIX_ENABLED = (1 << 4),
+	QL_DMA64 = (1 << 5),
+	QL_PROMISCUOUS = (1 << 6),
+	QL_ALLMULTI = (1 << 7),
+};
+
+/* link_status bit definitions */
+enum {
+	LOOPBACK_MASK = 0x00000700,
+	LOOPBACK_PCS = 0x00000100,
+	LOOPBACK_HSS = 0x00000200,
+	LOOPBACK_EXT = 0x00000300,
+	PAUSE_MASK = 0x000000c0,
+	PAUSE_STD = 0x00000040,
+	PAUSE_PRI = 0x00000080,
+	SPEED_MASK = 0x00000038,
+	SPEED_100Mb = 0x00000000,
+	SPEED_1Gb = 0x00000008,
+	SPEED_10Gb = 0x00000010,
+	LINK_TYPE_MASK = 0x00000007,
+	LINK_TYPE_XFI = 0x00000001,
+	LINK_TYPE_XAUI = 0x00000002,
+	LINK_TYPE_XFI_BP = 0x00000003,
+	LINK_TYPE_XAUI_BP = 0x00000004,
+	LINK_TYPE_10GBASET = 0x00000005,
+};
+
+/*
+ * The main Adapter structure definition.
+ * This structure has all fields relevant to the hardware.
+ */
+struct ql_adapter {
+	struct ricb ricb;
+	unsigned long flags;
+	u32 wol;
+
+	struct nic_stats nic_stats;
+
+	struct vlan_group *vlgrp;
+
+	/* PCI Configuration information for this device */
+	struct pci_dev *pdev;
+	struct net_device *ndev;	/* Parent NET device */
+
+	/* Hardware information */
+	u32 chip_rev_id;
+	u32 func;		/* PCI function for this adapter */
+
+	spinlock_t adapter_lock;
+	spinlock_t hw_lock;
+	spinlock_t stats_lock;
+	spinlock_t legacy_lock;	/* used for maintaining legacy intr sync */
+
+	/* PCI Bus Relative Register Addresses */
+	void __iomem *reg_base;
+	void __iomem *doorbell_area;
+	u32 doorbell_area_size;
+
+	u32 msg_enable;
+
+	/* Page for Shadow Registers */
+	void *rx_ring_shadow_reg_area;
+	dma_addr_t rx_ring_shadow_reg_dma;
+	void *tx_ring_shadow_reg_area;
+	dma_addr_t tx_ring_shadow_reg_dma;
+
+	u32 mailbox_in;
+	u32 mailbox_out;
+
+	int tx_ring_size;
+	int rx_ring_size;
+	u32 intr_count;
+	struct msix_entry *msi_x_entry;
+	struct intr_context intr_context[MAX_RX_RINGS];
+
+	int (*legacy_check) (struct ql_adapter *);
+
+	int tx_ring_count;	/* One per online CPU. */
+	u32 rss_ring_first_cq_id;/* index of first inbound (rss) rx_ring */
+	u32 rss_ring_count;	/* One per online CPU.  */
+	/*
+	 * rx_ring_count =
+	 *  one default queue +
+	 *  (CPU count * outbound completion rx_ring) +
+	 *  (CPU count * inbound (RSS) completion rx_ring)
+	 */
+	int rx_ring_count;
+	int ring_mem_size;
+	void *ring_mem;
+	struct rx_ring *rx_ring;
+	int rx_csum;
+	struct tx_ring *tx_ring;
+	u32 default_rx_queue;
+
+	u16 rx_coalesce_usecs;	/* cqicb->int_delay */
+	u16 rx_max_coalesced_frames;	/* cqicb->pkt_int_delay */
+	u16 tx_coalesce_usecs;	/* cqicb->int_delay */
+	u16 tx_max_coalesced_frames;	/* cqicb->pkt_int_delay */
+
+	u32 xg_sem_mask;
+	u32 port_link_up;
+	u32 port_init;
+	u32 link_status;
+
+	struct flash_params flash;
+
+	struct net_device_stats stats;
+	struct workqueue_struct *q_workqueue;
+	struct workqueue_struct *workqueue;
+	struct delayed_work asic_reset_work;
+	struct delayed_work mpi_reset_work;
+	struct delayed_work mpi_work;
+};
+
+/*
+ * Typical Register accessor for memory mapped device.
+ */
+static inline u32 ql_read32(const struct ql_adapter *qdev, int reg)
+{
+	return readl(qdev->reg_base + reg);
+}
+
+/*
+ * Typical Register accessor for memory mapped device.
+ */
+static inline void ql_write32(const struct ql_adapter *qdev, int reg, u32 val)
+{
+	writel(val, qdev->reg_base + reg);
+}
+
+/*
+ * Doorbell Registers:
+ * Doorbell registers are virtual registers in the PCI memory space.
+ * The space is allocated by the chip during PCI initialization.  The
+ * device driver finds the doorbell address in BAR 3 in PCI config space.
+ * The registers are used to control outbound and inbound queues. For
+ * example, the producer index for an outbound queue.  Each queue uses
+ * 1 4k chunk of memory.  The lower half of the space is for outbound
+ * queues. The upper half is for inbound queues.
+ */
+static inline void ql_write_db_reg(u32 val, void __iomem *addr)
+{
+	writel(val, addr);
+	mmiowb();
+}
+
+/*
+ * Shadow Registers:
+ * Outbound queues have a consumer index that is maintained by the chip.
+ * Inbound queues have a producer index that is maintained by the chip.
+ * For lower overhead, these registers are "shadowed" to host memory
+ * which allows the device driver to track the queue progress without
+ * PCI reads. When an entry is placed on an inbound queue, the chip will
+ * update the relevant index register and then copy the value to the
+ * shadow register in host memory.
+ */
+static inline unsigned int ql_read_sh_reg(const volatile void  *addr)
+{
+	return *(volatile unsigned int __force *)addr;
+}
+
+extern char qlge_driver_name[];
+extern const char qlge_driver_version[];
+extern const struct ethtool_ops qlge_ethtool_ops;
+
+extern int ql_sem_spinlock(struct ql_adapter *qdev, u32 sem_mask);
+extern void ql_sem_unlock(struct ql_adapter *qdev, u32 sem_mask);
+extern int ql_read_xgmac_reg(struct ql_adapter *qdev, u32 reg, u32 *data);
+extern int ql_get_mac_addr_reg(struct ql_adapter *qdev, u32 type, u16 index,
+			       u32 *value);
+extern int ql_get_routing_reg(struct ql_adapter *qdev, u32 index, u32 *value);
+extern int ql_write_cfg(struct ql_adapter *qdev, void *ptr, int size, u32 bit,
+			u16 q_id);
+void ql_queue_fw_error(struct ql_adapter *qdev);
+void ql_mpi_work(struct work_struct *work);
+void ql_mpi_reset_work(struct work_struct *work);
+int ql_wait_reg_rdy(struct ql_adapter *qdev, u32 reg, u32 bit, u32 ebit);
+void ql_queue_asic_error(struct ql_adapter *qdev);
+void ql_enable_completion_interrupt(struct ql_adapter *qdev, u32 intr);
+void ql_set_ethtool_ops(struct net_device *ndev);
+int ql_read_xgmac_reg64(struct ql_adapter *qdev, u32 reg, u64 *data);
+
+#if 1
+#define QL_ALL_DUMP
+#define QL_REG_DUMP
+#define QL_DEV_DUMP
+#define QL_CB_DUMP
+/* #define QL_IB_DUMP */
+/* #define QL_OB_DUMP */
+#endif
+
+#ifdef QL_REG_DUMP
+extern void ql_dump_xgmac_control_regs(struct ql_adapter *qdev);
+extern void ql_dump_routing_entries(struct ql_adapter *qdev);
+extern void ql_dump_regs(struct ql_adapter *qdev);
+#define QL_DUMP_REGS(qdev) ql_dump_regs(qdev)
+#define QL_DUMP_ROUTE(qdev) ql_dump_routing_entries(qdev)
+#define QL_DUMP_XGMAC_CONTROL_REGS(qdev) ql_dump_xgmac_control_regs(qdev)
+#else
+#define QL_DUMP_REGS(qdev)
+#define QL_DUMP_ROUTE(qdev)
+#define QL_DUMP_XGMAC_CONTROL_REGS(qdev)
+#endif
+
+#ifdef QL_STAT_DUMP
+extern void ql_dump_stat(struct ql_adapter *qdev);
+#define QL_DUMP_STAT(qdev) ql_dump_stat(qdev)
+#else
+#define QL_DUMP_STAT(qdev)
+#endif
+
+#ifdef QL_DEV_DUMP
+extern void ql_dump_qdev(struct ql_adapter *qdev);
+#define QL_DUMP_QDEV(qdev) ql_dump_qdev(qdev)
+#else
+#define QL_DUMP_QDEV(qdev)
+#endif
+
+#ifdef QL_CB_DUMP
+extern void ql_dump_wqicb(struct wqicb *wqicb);
+extern void ql_dump_tx_ring(struct tx_ring *tx_ring);
+extern void ql_dump_ricb(struct ricb *ricb);
+extern void ql_dump_cqicb(struct cqicb *cqicb);
+extern void ql_dump_rx_ring(struct rx_ring *rx_ring);
+extern void ql_dump_hw_cb(struct ql_adapter *qdev, int size, u32 bit, u16 q_id);
+#define QL_DUMP_RICB(ricb) ql_dump_ricb(ricb)
+#define QL_DUMP_WQICB(wqicb) ql_dump_wqicb(wqicb)
+#define QL_DUMP_TX_RING(tx_ring) ql_dump_tx_ring(tx_ring)
+#define QL_DUMP_CQICB(cqicb) ql_dump_cqicb(cqicb)
+#define QL_DUMP_RX_RING(rx_ring) ql_dump_rx_ring(rx_ring)
+#define QL_DUMP_HW_CB(qdev, size, bit, q_id) \
+		ql_dump_hw_cb(qdev, size, bit, q_id)
+#else
+#define QL_DUMP_RICB(ricb)
+#define QL_DUMP_WQICB(wqicb)
+#define QL_DUMP_TX_RING(tx_ring)
+#define QL_DUMP_CQICB(cqicb)
+#define QL_DUMP_RX_RING(rx_ring)
+#define QL_DUMP_HW_CB(qdev, size, bit, q_id)
+#endif
+
+#ifdef QL_OB_DUMP
+extern void ql_dump_tx_desc(struct tx_buf_desc *tbd);
+extern void ql_dump_ob_mac_iocb(struct ob_mac_iocb_req *ob_mac_iocb);
+extern void ql_dump_ob_mac_rsp(struct ob_mac_iocb_rsp *ob_mac_rsp);
+#define QL_DUMP_OB_MAC_IOCB(ob_mac_iocb) ql_dump_ob_mac_iocb(ob_mac_iocb)
+#define QL_DUMP_OB_MAC_RSP(ob_mac_rsp) ql_dump_ob_mac_rsp(ob_mac_rsp)
+#else
+#define QL_DUMP_OB_MAC_IOCB(ob_mac_iocb)
+#define QL_DUMP_OB_MAC_RSP(ob_mac_rsp)
+#endif
+
+#ifdef QL_IB_DUMP
+extern void ql_dump_ib_mac_rsp(struct ib_mac_iocb_rsp *ib_mac_rsp);
+#define QL_DUMP_IB_MAC_RSP(ib_mac_rsp) ql_dump_ib_mac_rsp(ib_mac_rsp)
+#else
+#define QL_DUMP_IB_MAC_RSP(ib_mac_rsp)
+#endif
+
+#ifdef	QL_ALL_DUMP
+extern void ql_dump_all(struct ql_adapter *qdev);
+#define QL_DUMP_ALL(qdev) ql_dump_all(qdev)
+#else
+#define QL_DUMP_ALL(qdev)
+#endif
+
+#endif /* _QLGE_H_ */
diff --git a/drivers/net/qlge/qlge_dbg.c b/drivers/net/qlge/qlge_dbg.c
new file mode 100644
index 0000000..47df304
--- /dev/null
+++ b/drivers/net/qlge/qlge_dbg.c
@@ -0,0 +1,858 @@
+#include "qlge.h"
+
+#ifdef QL_REG_DUMP
+static void ql_dump_intr_states(struct ql_adapter *qdev)
+{
+	int i;
+	u32 value;
+	for (i = 0; i < qdev->intr_count; i++) {
+		ql_write32(qdev, INTR_EN, qdev->intr_context[i].intr_read_mask);
+		value = ql_read32(qdev, INTR_EN);
+		printk(KERN_ERR PFX
+		       "%s: Interrupt %d is %s.\n",
+		       qdev->ndev->name, i,
+		       (value & INTR_EN_EN ? "enabled" : "disabled"));
+	}
+}
+
+void ql_dump_xgmac_control_regs(struct ql_adapter *qdev)
+{
+	u32 data;
+	if (ql_sem_spinlock(qdev, qdev->xg_sem_mask)) {
+		printk(KERN_ERR "%s: Couldn't get xgmac sem.\n", __func__);
+		return;
+	}
+	ql_read_xgmac_reg(qdev, PAUSE_SRC_LO, &data);
+	printk(KERN_ERR PFX "%s: PAUSE_SRC_LO = 0x%.08x.\n", qdev->ndev->name,
+	       data);
+	ql_read_xgmac_reg(qdev, PAUSE_SRC_HI, &data);
+	printk(KERN_ERR PFX "%s: PAUSE_SRC_HI = 0x%.08x.\n", qdev->ndev->name,
+	       data);
+	ql_read_xgmac_reg(qdev, GLOBAL_CFG, &data);
+	printk(KERN_ERR PFX "%s: GLOBAL_CFG = 0x%.08x.\n", qdev->ndev->name,
+	       data);
+	ql_read_xgmac_reg(qdev, TX_CFG, &data);
+	printk(KERN_ERR PFX "%s: TX_CFG = 0x%.08x.\n", qdev->ndev->name, data);
+	ql_read_xgmac_reg(qdev, RX_CFG, &data);
+	printk(KERN_ERR PFX "%s: RX_CFG = 0x%.08x.\n", qdev->ndev->name, data);
+	ql_read_xgmac_reg(qdev, FLOW_CTL, &data);
+	printk(KERN_ERR PFX "%s: FLOW_CTL = 0x%.08x.\n", qdev->ndev->name,
+	       data);
+	ql_read_xgmac_reg(qdev, PAUSE_OPCODE, &data);
+	printk(KERN_ERR PFX "%s: PAUSE_OPCODE = 0x%.08x.\n", qdev->ndev->name,
+	       data);
+	ql_read_xgmac_reg(qdev, PAUSE_TIMER, &data);
+	printk(KERN_ERR PFX "%s: PAUSE_TIMER = 0x%.08x.\n", qdev->ndev->name,
+	       data);
+	ql_read_xgmac_reg(qdev, PAUSE_FRM_DEST_LO, &data);
+	printk(KERN_ERR PFX "%s: PAUSE_FRM_DEST_LO = 0x%.08x.\n",
+	       qdev->ndev->name, data);
+	ql_read_xgmac_reg(qdev, PAUSE_FRM_DEST_HI, &data);
+	printk(KERN_ERR PFX "%s: PAUSE_FRM_DEST_HI = 0x%.08x.\n",
+	       qdev->ndev->name, data);
+	ql_read_xgmac_reg(qdev, MAC_TX_PARAMS, &data);
+	printk(KERN_ERR PFX "%s: MAC_TX_PARAMS = 0x%.08x.\n", qdev->ndev->name,
+	       data);
+	ql_read_xgmac_reg(qdev, MAC_RX_PARAMS, &data);
+	printk(KERN_ERR PFX "%s: MAC_RX_PARAMS = 0x%.08x.\n", qdev->ndev->name,
+	       data);
+	ql_read_xgmac_reg(qdev, MAC_SYS_INT, &data);
+	printk(KERN_ERR PFX "%s: MAC_SYS_INT = 0x%.08x.\n", qdev->ndev->name,
+	       data);
+	ql_read_xgmac_reg(qdev, MAC_SYS_INT_MASK, &data);
+	printk(KERN_ERR PFX "%s: MAC_SYS_INT_MASK = 0x%.08x.\n",
+	       qdev->ndev->name, data);
+	ql_read_xgmac_reg(qdev, MAC_MGMT_INT, &data);
+	printk(KERN_ERR PFX "%s: MAC_MGMT_INT = 0x%.08x.\n", qdev->ndev->name,
+	       data);
+	ql_read_xgmac_reg(qdev, MAC_MGMT_IN_MASK, &data);
+	printk(KERN_ERR PFX "%s: MAC_MGMT_IN_MASK = 0x%.08x.\n",
+	       qdev->ndev->name, data);
+	ql_read_xgmac_reg(qdev, EXT_ARB_MODE, &data);
+	printk(KERN_ERR PFX "%s: EXT_ARB_MODE = 0x%.08x.\n", qdev->ndev->name,
+	       data);
+	ql_sem_unlock(qdev, qdev->xg_sem_mask);
+
+}
+
+static void ql_dump_ets_regs(struct ql_adapter *qdev)
+{
+}
+
+static void ql_dump_cam_entries(struct ql_adapter *qdev)
+{
+	int i;
+	u32 value[3];
+	for (i = 0; i < 4; i++) {
+		if (ql_get_mac_addr_reg(qdev, MAC_ADDR_TYPE_CAM_MAC, i, value)) {
+			printk(KERN_ERR PFX
+			       "%s: Failed read of mac index register.\n",
+			       __func__);
+			return;
+		} else {
+			if (value[0])
+				printk(KERN_ERR PFX
+				       "%s: CAM index %d CAM Lookup Lower = 0x%.08x:%.08x, Output = 0x%.08x.\n",
+				       qdev->ndev->name, i, value[1], value[0],
+				       value[2]);
+		}
+	}
+	for (i = 0; i < 32; i++) {
+		if (ql_get_mac_addr_reg
+		    (qdev, MAC_ADDR_TYPE_MULTI_MAC, i, value)) {
+			printk(KERN_ERR PFX
+			       "%s: Failed read of mac index register.\n",
+			       __func__);
+			return;
+		} else {
+			if (value[0])
+				printk(KERN_ERR PFX
+				       "%s: MCAST index %d CAM Lookup Lower = 0x%.08x:%.08x.\n",
+				       qdev->ndev->name, i, value[1], value[0]);
+		}
+	}
+}
+
+void ql_dump_routing_entries(struct ql_adapter *qdev)
+{
+	int i;
+	u32 value;
+	for (i = 0; i < 16; i++) {
+		value = 0;
+		if (ql_get_routing_reg(qdev, i, &value)) {
+			printk(KERN_ERR PFX
+			       "%s: Failed read of routing index register.\n",
+			       __func__);
+			return;
+		} else {
+			if (value)
+				printk(KERN_ERR PFX
+				       "%s: Routing Mask %d = 0x%.08x.\n",
+				       qdev->ndev->name, i, value);
+		}
+	}
+}
+
+void ql_dump_regs(struct ql_adapter *qdev)
+{
+	printk(KERN_ERR PFX "reg dump for function #%d.\n", qdev->func);
+	printk(KERN_ERR PFX "SYS	 			= 0x%x.\n",
+	       ql_read32(qdev, SYS));
+	printk(KERN_ERR PFX "RST_FO 			= 0x%x.\n",
+	       ql_read32(qdev, RST_FO));
+	printk(KERN_ERR PFX "FSC 				= 0x%x.\n",
+	       ql_read32(qdev, FSC));
+	printk(KERN_ERR PFX "CSR 				= 0x%x.\n",
+	       ql_read32(qdev, CSR));
+	printk(KERN_ERR PFX "ICB_RID 			= 0x%x.\n",
+	       ql_read32(qdev, ICB_RID));
+	printk(KERN_ERR PFX "ICB_L 				= 0x%x.\n",
+	       ql_read32(qdev, ICB_L));
+	printk(KERN_ERR PFX "ICB_H 				= 0x%x.\n",
+	       ql_read32(qdev, ICB_H));
+	printk(KERN_ERR PFX "CFG 				= 0x%x.\n",
+	       ql_read32(qdev, CFG));
+	printk(KERN_ERR PFX "BIOS_ADDR 			= 0x%x.\n",
+	       ql_read32(qdev, BIOS_ADDR));
+	printk(KERN_ERR PFX "STS 				= 0x%x.\n",
+	       ql_read32(qdev, STS));
+	printk(KERN_ERR PFX "INTR_EN			= 0x%x.\n",
+	       ql_read32(qdev, INTR_EN));
+	printk(KERN_ERR PFX "INTR_MASK 			= 0x%x.\n",
+	       ql_read32(qdev, INTR_MASK));
+	printk(KERN_ERR PFX "ISR1 				= 0x%x.\n",
+	       ql_read32(qdev, ISR1));
+	printk(KERN_ERR PFX "ISR2 				= 0x%x.\n",
+	       ql_read32(qdev, ISR2));
+	printk(KERN_ERR PFX "ISR3 				= 0x%x.\n",
+	       ql_read32(qdev, ISR3));
+	printk(KERN_ERR PFX "ISR4 				= 0x%x.\n",
+	       ql_read32(qdev, ISR4));
+	printk(KERN_ERR PFX "REV_ID 			= 0x%x.\n",
+	       ql_read32(qdev, REV_ID));
+	printk(KERN_ERR PFX "FRC_ECC_ERR 			= 0x%x.\n",
+	       ql_read32(qdev, FRC_ECC_ERR));
+	printk(KERN_ERR PFX "ERR_STS 			= 0x%x.\n",
+	       ql_read32(qdev, ERR_STS));
+	printk(KERN_ERR PFX "RAM_DBG_ADDR 			= 0x%x.\n",
+	       ql_read32(qdev, RAM_DBG_ADDR));
+	printk(KERN_ERR PFX "RAM_DBG_DATA 			= 0x%x.\n",
+	       ql_read32(qdev, RAM_DBG_DATA));
+	printk(KERN_ERR PFX "ECC_ERR_CNT 			= 0x%x.\n",
+	       ql_read32(qdev, ECC_ERR_CNT));
+	printk(KERN_ERR PFX "SEM 				= 0x%x.\n",
+	       ql_read32(qdev, SEM));
+	printk(KERN_ERR PFX "GPIO_1 			= 0x%x.\n",
+	       ql_read32(qdev, GPIO_1));
+	printk(KERN_ERR PFX "GPIO_2 			= 0x%x.\n",
+	       ql_read32(qdev, GPIO_2));
+	printk(KERN_ERR PFX "GPIO_3 			= 0x%x.\n",
+	       ql_read32(qdev, GPIO_3));
+	printk(KERN_ERR PFX "XGMAC_ADDR 			= 0x%x.\n",
+	       ql_read32(qdev, XGMAC_ADDR));
+	printk(KERN_ERR PFX "XGMAC_DATA 			= 0x%x.\n",
+	       ql_read32(qdev, XGMAC_DATA));
+	printk(KERN_ERR PFX "NIC_ETS 			= 0x%x.\n",
+	       ql_read32(qdev, NIC_ETS));
+	printk(KERN_ERR PFX "CNA_ETS 			= 0x%x.\n",
+	       ql_read32(qdev, CNA_ETS));
+	printk(KERN_ERR PFX "FLASH_ADDR 			= 0x%x.\n",
+	       ql_read32(qdev, FLASH_ADDR));
+	printk(KERN_ERR PFX "FLASH_DATA 			= 0x%x.\n",
+	       ql_read32(qdev, FLASH_DATA));
+	printk(KERN_ERR PFX "CQ_STOP 			= 0x%x.\n",
+	       ql_read32(qdev, CQ_STOP));
+	printk(KERN_ERR PFX "PAGE_TBL_RID 			= 0x%x.\n",
+	       ql_read32(qdev, PAGE_TBL_RID));
+	printk(KERN_ERR PFX "WQ_PAGE_TBL_LO 		= 0x%x.\n",
+	       ql_read32(qdev, WQ_PAGE_TBL_LO));
+	printk(KERN_ERR PFX "WQ_PAGE_TBL_HI 		= 0x%x.\n",
+	       ql_read32(qdev, WQ_PAGE_TBL_HI));
+	printk(KERN_ERR PFX "CQ_PAGE_TBL_LO 		= 0x%x.\n",
+	       ql_read32(qdev, CQ_PAGE_TBL_LO));
+	printk(KERN_ERR PFX "CQ_PAGE_TBL_HI 		= 0x%x.\n",
+	       ql_read32(qdev, CQ_PAGE_TBL_HI));
+	printk(KERN_ERR PFX "COS_DFLT_CQ1 			= 0x%x.\n",
+	       ql_read32(qdev, COS_DFLT_CQ1));
+	printk(KERN_ERR PFX "COS_DFLT_CQ2 			= 0x%x.\n",
+	       ql_read32(qdev, COS_DFLT_CQ2));
+	printk(KERN_ERR PFX "SPLT_HDR 			= 0x%x.\n",
+	       ql_read32(qdev, SPLT_HDR));
+	printk(KERN_ERR PFX "FC_PAUSE_THRES 		= 0x%x.\n",
+	       ql_read32(qdev, FC_PAUSE_THRES));
+	printk(KERN_ERR PFX "NIC_PAUSE_THRES 		= 0x%x.\n",
+	       ql_read32(qdev, NIC_PAUSE_THRES));
+	printk(KERN_ERR PFX "FC_ETHERTYPE 			= 0x%x.\n",
+	       ql_read32(qdev, FC_ETHERTYPE));
+	printk(KERN_ERR PFX "FC_RCV_CFG 			= 0x%x.\n",
+	       ql_read32(qdev, FC_RCV_CFG));
+	printk(KERN_ERR PFX "NIC_RCV_CFG 			= 0x%x.\n",
+	       ql_read32(qdev, NIC_RCV_CFG));
+	printk(KERN_ERR PFX "FC_COS_TAGS 			= 0x%x.\n",
+	       ql_read32(qdev, FC_COS_TAGS));
+	printk(KERN_ERR PFX "NIC_COS_TAGS 			= 0x%x.\n",
+	       ql_read32(qdev, NIC_COS_TAGS));
+	printk(KERN_ERR PFX "MGMT_RCV_CFG 			= 0x%x.\n",
+	       ql_read32(qdev, MGMT_RCV_CFG));
+	printk(KERN_ERR PFX "XG_SERDES_ADDR 		= 0x%x.\n",
+	       ql_read32(qdev, XG_SERDES_ADDR));
+	printk(KERN_ERR PFX "XG_SERDES_DATA 		= 0x%x.\n",
+	       ql_read32(qdev, XG_SERDES_DATA));
+	printk(KERN_ERR PFX "PRB_MX_ADDR 			= 0x%x.\n",
+	       ql_read32(qdev, PRB_MX_ADDR));
+	printk(KERN_ERR PFX "PRB_MX_DATA 			= 0x%x.\n",
+	       ql_read32(qdev, PRB_MX_DATA));
+	ql_dump_intr_states(qdev);
+	ql_dump_xgmac_control_regs(qdev);
+	ql_dump_ets_regs(qdev);
+	ql_dump_cam_entries(qdev);
+	ql_dump_routing_entries(qdev);
+}
+#endif
+
+#ifdef QL_STAT_DUMP
+void ql_dump_stat(struct ql_adapter *qdev)
+{
+	printk(KERN_ERR "%s: Enter.\n", __func__);
+	printk(KERN_ERR "tx_pkts = %ld\n",
+	       (unsigned long)qdev->nic_stats.tx_pkts);
+	printk(KERN_ERR "tx_bytes = %ld\n",
+	       (unsigned long)qdev->nic_stats.tx_bytes);
+	printk(KERN_ERR "tx_mcast_pkts = %ld.\n",
+	       (unsigned long)qdev->nic_stats.tx_mcast_pkts);
+	printk(KERN_ERR "tx_bcast_pkts = %ld.\n",
+	       (unsigned long)qdev->nic_stats.tx_bcast_pkts);
+	printk(KERN_ERR "tx_ucast_pkts = %ld.\n",
+	       (unsigned long)qdev->nic_stats.tx_ucast_pkts);
+	printk(KERN_ERR "tx_ctl_pkts = %ld.\n",
+	       (unsigned long)qdev->nic_stats.tx_ctl_pkts);
+	printk(KERN_ERR "tx_pause_pkts = %ld.\n",
+	       (unsigned long)qdev->nic_stats.tx_pause_pkts);
+	printk(KERN_ERR "tx_64_pkt = %ld.\n",
+	       (unsigned long)qdev->nic_stats.tx_64_pkt);
+	printk(KERN_ERR "tx_65_to_127_pkt = %ld.\n",
+	       (unsigned long)qdev->nic_stats.tx_65_to_127_pkt);
+	printk(KERN_ERR "tx_128_to_255_pkt = %ld.\n",
+	       (unsigned long)qdev->nic_stats.tx_128_to_255_pkt);
+	printk(KERN_ERR "tx_256_511_pkt = %ld.\n",
+	       (unsigned long)qdev->nic_stats.tx_256_511_pkt);
+	printk(KERN_ERR "tx_512_to_1023_pkt = %ld.\n",
+	       (unsigned long)qdev->nic_stats.tx_512_to_1023_pkt);
+	printk(KERN_ERR "tx_1024_to_1518_pkt = %ld.\n",
+	       (unsigned long)qdev->nic_stats.tx_1024_to_1518_pkt);
+	printk(KERN_ERR "tx_1519_to_max_pkt = %ld.\n",
+	       (unsigned long)qdev->nic_stats.tx_1519_to_max_pkt);
+	printk(KERN_ERR "tx_undersize_pkt = %ld.\n",
+	       (unsigned long)qdev->nic_stats.tx_undersize_pkt);
+	printk(KERN_ERR "tx_oversize_pkt = %ld.\n",
+	       (unsigned long)qdev->nic_stats.tx_oversize_pkt);
+	printk(KERN_ERR "rx_bytes = %ld.\n",
+	       (unsigned long)qdev->nic_stats.rx_bytes);
+	printk(KERN_ERR "rx_bytes_ok = %ld.\n",
+	       (unsigned long)qdev->nic_stats.rx_bytes_ok);
+	printk(KERN_ERR "rx_pkts = %ld.\n",
+	       (unsigned long)qdev->nic_stats.rx_pkts);
+	printk(KERN_ERR "rx_pkts_ok = %ld.\n",
+	       (unsigned long)qdev->nic_stats.rx_pkts_ok);
+	printk(KERN_ERR "rx_bcast_pkts = %ld.\n",
+	       (unsigned long)qdev->nic_stats.rx_bcast_pkts);
+	printk(KERN_ERR "rx_mcast_pkts = %ld.\n",
+	       (unsigned long)qdev->nic_stats.rx_mcast_pkts);
+	printk(KERN_ERR "rx_ucast_pkts = %ld.\n",
+	       (unsigned long)qdev->nic_stats.rx_ucast_pkts);
+	printk(KERN_ERR "rx_undersize_pkts = %ld.\n",
+	       (unsigned long)qdev->nic_stats.rx_undersize_pkts);
+	printk(KERN_ERR "rx_oversize_pkts = %ld.\n",
+	       (unsigned long)qdev->nic_stats.rx_oversize_pkts);
+	printk(KERN_ERR "rx_jabber_pkts = %ld.\n",
+	       (unsigned long)qdev->nic_stats.rx_jabber_pkts);
+	printk(KERN_ERR "rx_undersize_fcerr_pkts = %ld.\n",
+	       (unsigned long)qdev->nic_stats.rx_undersize_fcerr_pkts);
+	printk(KERN_ERR "rx_drop_events = %ld.\n",
+	       (unsigned long)qdev->nic_stats.rx_drop_events);
+	printk(KERN_ERR "rx_fcerr_pkts = %ld.\n",
+	       (unsigned long)qdev->nic_stats.rx_fcerr_pkts);
+	printk(KERN_ERR "rx_align_err = %ld.\n",
+	       (unsigned long)qdev->nic_stats.rx_align_err);
+	printk(KERN_ERR "rx_symbol_err = %ld.\n",
+	       (unsigned long)qdev->nic_stats.rx_symbol_err);
+	printk(KERN_ERR "rx_mac_err = %ld.\n",
+	       (unsigned long)qdev->nic_stats.rx_mac_err);
+	printk(KERN_ERR "rx_ctl_pkts = %ld.\n",
+	       (unsigned long)qdev->nic_stats.rx_ctl_pkts);
+	printk(KERN_ERR "rx_pause_pkts = %ld.\n",
+	       (unsigned long)qdev->nic_stats.rx_pause_pkts);
+	printk(KERN_ERR "rx_64_pkts = %ld.\n",
+	       (unsigned long)qdev->nic_stats.rx_64_pkts);
+	printk(KERN_ERR "rx_65_to_127_pkts = %ld.\n",
+	       (unsigned long)qdev->nic_stats.rx_65_to_127_pkts);
+	printk(KERN_ERR "rx_128_255_pkts = %ld.\n",
+	       (unsigned long)qdev->nic_stats.rx_128_255_pkts);
+	printk(KERN_ERR "rx_256_511_pkts = %ld.\n",
+	       (unsigned long)qdev->nic_stats.rx_256_511_pkts);
+	printk(KERN_ERR "rx_512_to_1023_pkts = %ld.\n",
+	       (unsigned long)qdev->nic_stats.rx_512_to_1023_pkts);
+	printk(KERN_ERR "rx_1024_to_1518_pkts = %ld.\n",
+	       (unsigned long)qdev->nic_stats.rx_1024_to_1518_pkts);
+	printk(KERN_ERR "rx_1519_to_max_pkts = %ld.\n",
+	       (unsigned long)qdev->nic_stats.rx_1519_to_max_pkts);
+	printk(KERN_ERR "rx_len_err_pkts = %ld.\n",
+	       (unsigned long)qdev->nic_stats.rx_len_err_pkts);
+};
+#endif
+
+#ifdef QL_DEV_DUMP
+void ql_dump_qdev(struct ql_adapter *qdev)
+{
+	int i;
+	printk(KERN_ERR PFX "qdev->flags 			= %lx.\n",
+	       qdev->flags);
+	printk(KERN_ERR PFX "qdev->vlgrp 			= %p.\n",
+	       qdev->vlgrp);
+	printk(KERN_ERR PFX "qdev->pdev 			= %p.\n",
+	       qdev->pdev);
+	printk(KERN_ERR PFX "qdev->ndev 			= %p.\n",
+	       qdev->ndev);
+	printk(KERN_ERR PFX "qdev->chip_rev_id 		= %d.\n",
+	       qdev->chip_rev_id);
+	printk(KERN_ERR PFX "qdev->reg_base 		= %p.\n",
+	       qdev->reg_base);
+	printk(KERN_ERR PFX "qdev->doorbell_area 	= %p.\n",
+	       qdev->doorbell_area);
+	printk(KERN_ERR PFX "qdev->doorbell_area_size 	= %d.\n",
+	       qdev->doorbell_area_size);
+	printk(KERN_ERR PFX "msg_enable 		= %x.\n",
+	       qdev->msg_enable);
+	printk(KERN_ERR PFX "qdev->rx_ring_shadow_reg_area	= %p.\n",
+	       qdev->rx_ring_shadow_reg_area);
+	printk(KERN_ERR PFX "qdev->rx_ring_shadow_reg_dma 	= %llx.\n",
+	       (unsigned long long) qdev->rx_ring_shadow_reg_dma);
+	printk(KERN_ERR PFX "qdev->tx_ring_shadow_reg_area	= %p.\n",
+	       qdev->tx_ring_shadow_reg_area);
+	printk(KERN_ERR PFX "qdev->tx_ring_shadow_reg_dma	= %llx.\n",
+	       (unsigned long long) qdev->tx_ring_shadow_reg_dma);
+	printk(KERN_ERR PFX "qdev->intr_count 		= %d.\n",
+	       qdev->intr_count);
+	if (qdev->msi_x_entry)
+		for (i = 0; i < qdev->intr_count; i++) {
+			printk(KERN_ERR PFX
+			       "msi_x_entry.[%d]vector	= %d.\n", i,
+			       qdev->msi_x_entry[i].vector);
+			printk(KERN_ERR PFX
+			       "msi_x_entry.[%d]entry	= %d.\n", i,
+			       qdev->msi_x_entry[i].entry);
+		}
+	for (i = 0; i < qdev->intr_count; i++) {
+		printk(KERN_ERR PFX
+		       "intr_context[%d].qdev		= %p.\n", i,
+		       qdev->intr_context[i].qdev);
+		printk(KERN_ERR PFX
+		       "intr_context[%d].intr		= %d.\n", i,
+		       qdev->intr_context[i].intr);
+		printk(KERN_ERR PFX
+		       "intr_context[%d].hooked		= %d.\n", i,
+		       qdev->intr_context[i].hooked);
+		printk(KERN_ERR PFX
+		       "intr_context[%d].intr_en_mask	= 0x%08x.\n", i,
+		       qdev->intr_context[i].intr_en_mask);
+		printk(KERN_ERR PFX
+		       "intr_context[%d].intr_dis_mask	= 0x%08x.\n", i,
+		       qdev->intr_context[i].intr_dis_mask);
+		printk(KERN_ERR PFX
+		       "intr_context[%d].intr_read_mask	= 0x%08x.\n", i,
+		       qdev->intr_context[i].intr_read_mask);
+	}
+	printk(KERN_ERR PFX "qdev->tx_ring_count = %d.\n", qdev->tx_ring_count);
+	printk(KERN_ERR PFX "qdev->rx_ring_count = %d.\n", qdev->rx_ring_count);
+	printk(KERN_ERR PFX "qdev->ring_mem_size = %d.\n", qdev->ring_mem_size);
+	printk(KERN_ERR PFX "qdev->ring_mem 	= %p.\n", qdev->ring_mem);
+	printk(KERN_ERR PFX "qdev->intr_count 	= %d.\n", qdev->intr_count);
+	printk(KERN_ERR PFX "qdev->tx_ring		= %p.\n",
+	       qdev->tx_ring);
+	printk(KERN_ERR PFX "qdev->rss_ring_first_cq_id 	= %d.\n",
+	       qdev->rss_ring_first_cq_id);
+	printk(KERN_ERR PFX "qdev->rss_ring_count 	= %d.\n",
+	       qdev->rss_ring_count);
+	printk(KERN_ERR PFX "qdev->rx_ring	= %p.\n", qdev->rx_ring);
+	printk(KERN_ERR PFX "qdev->default_rx_queue	= %d.\n",
+	       qdev->default_rx_queue);
+	printk(KERN_ERR PFX "qdev->xg_sem_mask		= 0x%08x.\n",
+	       qdev->xg_sem_mask);
+	printk(KERN_ERR PFX "qdev->port_link_up		= 0x%08x.\n",
+	       qdev->port_link_up);
+	printk(KERN_ERR PFX "qdev->port_init		= 0x%08x.\n",
+	       qdev->port_init);
+
+}
+#endif
+
+#ifdef QL_CB_DUMP
+void ql_dump_wqicb(struct wqicb *wqicb)
+{
+	printk(KERN_ERR PFX "Dumping wqicb stuff...\n");
+	printk(KERN_ERR PFX "wqicb->len = 0x%x.\n", le16_to_cpu(wqicb->len));
+	printk(KERN_ERR PFX "wqicb->flags = %x.\n", le16_to_cpu(wqicb->flags));
+	printk(KERN_ERR PFX "wqicb->cq_id_rss = %d.\n",
+	       le16_to_cpu(wqicb->cq_id_rss));
+	printk(KERN_ERR PFX "wqicb->rid = 0x%x.\n", le16_to_cpu(wqicb->rid));
+	printk(KERN_ERR PFX "wqicb->wq_addr_lo = 0x%.08x.\n",
+	       le32_to_cpu(wqicb->addr_lo));
+	printk(KERN_ERR PFX "wqicb->wq_addr_hi = 0x%.08x.\n",
+	       le32_to_cpu(wqicb->addr_hi));
+	printk(KERN_ERR PFX "wqicb->wq_cnsmr_idx_addr_lo = 0x%.08x.\n",
+	       le32_to_cpu(wqicb->cnsmr_idx_addr_lo));
+	printk(KERN_ERR PFX "wqicb->wq_cnsmr_idx_addr_hi = 0x%.08x.\n",
+	       le32_to_cpu(wqicb->cnsmr_idx_addr_hi));
+}
+
+void ql_dump_tx_ring(struct tx_ring *tx_ring)
+{
+	if (tx_ring == NULL)
+		return;
+	printk(KERN_ERR PFX
+	       "===================== Dumping tx_ring %d ===============.\n",
+	       tx_ring->wq_id);
+	printk(KERN_ERR PFX "tx_ring->base = %p.\n", tx_ring->wq_base);
+	printk(KERN_ERR PFX "tx_ring->base_dma = 0x%llx.\n",
+	       (unsigned long long) tx_ring->wq_base_dma);
+	printk(KERN_ERR PFX "tx_ring->cnsmr_idx_sh_reg = %p.\n",
+	       tx_ring->cnsmr_idx_sh_reg);
+	printk(KERN_ERR PFX "tx_ring->cnsmr_idx_sh_reg_dma = 0x%llx.\n",
+	       (unsigned long long) tx_ring->cnsmr_idx_sh_reg_dma);
+	printk(KERN_ERR PFX "tx_ring->size = %d.\n", tx_ring->wq_size);
+	printk(KERN_ERR PFX "tx_ring->len = %d.\n", tx_ring->wq_len);
+	printk(KERN_ERR PFX "tx_ring->prod_idx_db_reg = %p.\n",
+	       tx_ring->prod_idx_db_reg);
+	printk(KERN_ERR PFX "tx_ring->valid_db_reg = %p.\n",
+	       tx_ring->valid_db_reg);
+	printk(KERN_ERR PFX "tx_ring->prod_idx = %d.\n", tx_ring->prod_idx);
+	printk(KERN_ERR PFX "tx_ring->cq_id = %d.\n", tx_ring->cq_id);
+	printk(KERN_ERR PFX "tx_ring->wq_id = %d.\n", tx_ring->wq_id);
+	printk(KERN_ERR PFX "tx_ring->q = %p.\n", tx_ring->q);
+	printk(KERN_ERR PFX "tx_ring->tx_count = %d.\n",
+	       atomic_read(&tx_ring->tx_count));
+}
+
+void ql_dump_ricb(struct ricb *ricb)
+{
+	int i;
+	printk(KERN_ERR PFX
+	       "===================== Dumping ricb ===============.\n");
+	printk(KERN_ERR PFX "Dumping ricb stuff...\n");
+
+	printk(KERN_ERR PFX "ricb->base_cq = %d.\n", ricb->base_cq & 0x1f);
+	printk(KERN_ERR PFX "ricb->flags = %s%s%s%s%s%s%s%s%s.\n",
+	       ricb->base_cq & RSS_L4K ? "RSS_L4K " : "",
+	       ricb->flags & RSS_L6K ? "RSS_L6K " : "",
+	       ricb->flags & RSS_LI ? "RSS_LI " : "",
+	       ricb->flags & RSS_LB ? "RSS_LB " : "",
+	       ricb->flags & RSS_LM ? "RSS_LM " : "",
+	       ricb->flags & RSS_RI4 ? "RSS_RI4 " : "",
+	       ricb->flags & RSS_RT4 ? "RSS_RT4 " : "",
+	       ricb->flags & RSS_RI6 ? "RSS_RI6 " : "",
+	       ricb->flags & RSS_RT6 ? "RSS_RT6 " : "");
+	printk(KERN_ERR PFX "ricb->mask = 0x%.04x.\n", le16_to_cpu(ricb->mask));
+	for (i = 0; i < 16; i++)
+		printk(KERN_ERR PFX "ricb->hash_cq_id[%d] = 0x%.08x.\n", i,
+		       le32_to_cpu(ricb->hash_cq_id[i]));
+	for (i = 0; i < 10; i++)
+		printk(KERN_ERR PFX "ricb->ipv6_hash_key[%d] = 0x%.08x.\n", i,
+		       le32_to_cpu(ricb->ipv6_hash_key[i]));
+	for (i = 0; i < 4; i++)
+		printk(KERN_ERR PFX "ricb->ipv4_hash_key[%d] = 0x%.08x.\n", i,
+		       le32_to_cpu(ricb->ipv4_hash_key[i]));
+}
+
+void ql_dump_cqicb(struct cqicb *cqicb)
+{
+	printk(KERN_ERR PFX "Dumping cqicb stuff...\n");
+
+	printk(KERN_ERR PFX "cqicb->msix_vect = %d.\n", cqicb->msix_vect);
+	printk(KERN_ERR PFX "cqicb->flags = %x.\n", cqicb->flags);
+	printk(KERN_ERR PFX "cqicb->len = %d.\n", le16_to_cpu(cqicb->len));
+	printk(KERN_ERR PFX "cqicb->addr_lo = %x.\n",
+	       le32_to_cpu(cqicb->addr_lo));
+	printk(KERN_ERR PFX "cqicb->addr_hi = %x.\n",
+	       le32_to_cpu(cqicb->addr_hi));
+	printk(KERN_ERR PFX "cqicb->prod_idx_addr_lo = %x.\n",
+	       le32_to_cpu(cqicb->prod_idx_addr_lo));
+	printk(KERN_ERR PFX "cqicb->prod_idx_addr_hi = %x.\n",
+	       le32_to_cpu(cqicb->prod_idx_addr_hi));
+	printk(KERN_ERR PFX "cqicb->pkt_delay = 0x%.04x.\n",
+	       le16_to_cpu(cqicb->pkt_delay));
+	printk(KERN_ERR PFX "cqicb->irq_delay = 0x%.04x.\n",
+	       le16_to_cpu(cqicb->irq_delay));
+	printk(KERN_ERR PFX "cqicb->lbq_addr_lo = %x.\n",
+	       le32_to_cpu(cqicb->lbq_addr_lo));
+	printk(KERN_ERR PFX "cqicb->lbq_addr_hi = %x.\n",
+	       le32_to_cpu(cqicb->lbq_addr_hi));
+	printk(KERN_ERR PFX "cqicb->lbq_buf_size = 0x%.04x.\n",
+	       le16_to_cpu(cqicb->lbq_buf_size));
+	printk(KERN_ERR PFX "cqicb->lbq_len = 0x%.04x.\n",
+	       le16_to_cpu(cqicb->lbq_len));
+	printk(KERN_ERR PFX "cqicb->sbq_addr_lo = %x.\n",
+	       le32_to_cpu(cqicb->sbq_addr_lo));
+	printk(KERN_ERR PFX "cqicb->sbq_addr_hi = %x.\n",
+	       le32_to_cpu(cqicb->sbq_addr_hi));
+	printk(KERN_ERR PFX "cqicb->sbq_buf_size = 0x%.04x.\n",
+	       le16_to_cpu(cqicb->sbq_buf_size));
+	printk(KERN_ERR PFX "cqicb->sbq_len = 0x%.04x.\n",
+	       le16_to_cpu(cqicb->sbq_len));
+}
+
+void ql_dump_rx_ring(struct rx_ring *rx_ring)
+{
+	if (rx_ring == NULL)
+		return;
+	printk(KERN_ERR PFX
+	       "===================== Dumping rx_ring %d ===============.\n",
+	       rx_ring->cq_id);
+	printk(KERN_ERR PFX "Dumping rx_ring %d, type = %s%s%s.\n",
+	       rx_ring->cq_id, rx_ring->type == DEFAULT_Q ? "DEFAULT" : "",
+	       rx_ring->type == TX_Q ? "OUTBOUND COMPLETIONS" : "",
+	       rx_ring->type == RX_Q ? "INBOUND_COMPLETIONS" : "");
+	printk(KERN_ERR PFX "rx_ring->cqicb = %p.\n", &rx_ring->cqicb);
+	printk(KERN_ERR PFX "rx_ring->cq_base = %p.\n", rx_ring->cq_base);
+	printk(KERN_ERR PFX "rx_ring->cq_base_dma = %llx.\n",
+	       (unsigned long long) rx_ring->cq_base_dma);
+	printk(KERN_ERR PFX "rx_ring->cq_size = %d.\n", rx_ring->cq_size);
+	printk(KERN_ERR PFX "rx_ring->cq_len = %d.\n", rx_ring->cq_len);
+	printk(KERN_ERR PFX
+	       "rx_ring->prod_idx_sh_reg, addr = %p, value = %d.\n",
+	       rx_ring->prod_idx_sh_reg,
+	       rx_ring->prod_idx_sh_reg ? *(rx_ring->prod_idx_sh_reg) : 0);
+	printk(KERN_ERR PFX "rx_ring->prod_idx_sh_reg_dma = %llx.\n",
+	       (unsigned long long) rx_ring->prod_idx_sh_reg_dma);
+	printk(KERN_ERR PFX "rx_ring->cnsmr_idx_db_reg = %p.\n",
+	       rx_ring->cnsmr_idx_db_reg);
+	printk(KERN_ERR PFX "rx_ring->cnsmr_idx = %d.\n", rx_ring->cnsmr_idx);
+	printk(KERN_ERR PFX "rx_ring->curr_entry = %p.\n", rx_ring->curr_entry);
+	printk(KERN_ERR PFX "rx_ring->valid_db_reg = %p.\n",
+	       rx_ring->valid_db_reg);
+
+	printk(KERN_ERR PFX "rx_ring->lbq_base = %p.\n", rx_ring->lbq_base);
+	printk(KERN_ERR PFX "rx_ring->lbq_base_dma = %llx.\n",
+	       (unsigned long long) rx_ring->lbq_base_dma);
+	printk(KERN_ERR PFX "rx_ring->lbq_base_indirect = %p.\n",
+	       rx_ring->lbq_base_indirect);
+	printk(KERN_ERR PFX "rx_ring->lbq_base_indirect_dma = %llx.\n",
+	       (unsigned long long) rx_ring->lbq_base_indirect_dma);
+	printk(KERN_ERR PFX "rx_ring->lbq = %p.\n", rx_ring->lbq);
+	printk(KERN_ERR PFX "rx_ring->lbq_len = %d.\n", rx_ring->lbq_len);
+	printk(KERN_ERR PFX "rx_ring->lbq_size = %d.\n", rx_ring->lbq_size);
+	printk(KERN_ERR PFX "rx_ring->lbq_prod_idx_db_reg = %p.\n",
+	       rx_ring->lbq_prod_idx_db_reg);
+	printk(KERN_ERR PFX "rx_ring->lbq_prod_idx = %d.\n",
+	       rx_ring->lbq_prod_idx);
+	printk(KERN_ERR PFX "rx_ring->lbq_curr_idx = %d.\n",
+	       rx_ring->lbq_curr_idx);
+	printk(KERN_ERR PFX "rx_ring->lbq_clean_idx = %d.\n",
+	       rx_ring->lbq_clean_idx);
+	printk(KERN_ERR PFX "rx_ring->lbq_free_cnt = %d.\n",
+	       rx_ring->lbq_free_cnt);
+	printk(KERN_ERR PFX "rx_ring->lbq_buf_size = %d.\n",
+	       rx_ring->lbq_buf_size);
+
+	printk(KERN_ERR PFX "rx_ring->sbq_base = %p.\n", rx_ring->sbq_base);
+	printk(KERN_ERR PFX "rx_ring->sbq_base_dma = %llx.\n",
+	       (unsigned long long) rx_ring->sbq_base_dma);
+	printk(KERN_ERR PFX "rx_ring->sbq_base_indirect = %p.\n",
+	       rx_ring->sbq_base_indirect);
+	printk(KERN_ERR PFX "rx_ring->sbq_base_indirect_dma = %llx.\n",
+	       (unsigned long long) rx_ring->sbq_base_indirect_dma);
+	printk(KERN_ERR PFX "rx_ring->sbq = %p.\n", rx_ring->sbq);
+	printk(KERN_ERR PFX "rx_ring->sbq_len = %d.\n", rx_ring->sbq_len);
+	printk(KERN_ERR PFX "rx_ring->sbq_size = %d.\n", rx_ring->sbq_size);
+	printk(KERN_ERR PFX "rx_ring->sbq_prod_idx_db_reg addr = %p.\n",
+	       rx_ring->sbq_prod_idx_db_reg);
+	printk(KERN_ERR PFX "rx_ring->sbq_prod_idx = %d.\n",
+	       rx_ring->sbq_prod_idx);
+	printk(KERN_ERR PFX "rx_ring->sbq_curr_idx = %d.\n",
+	       rx_ring->sbq_curr_idx);
+	printk(KERN_ERR PFX "rx_ring->sbq_clean_idx = %d.\n",
+	       rx_ring->sbq_clean_idx);
+	printk(KERN_ERR PFX "rx_ring->sbq_free_cnt = %d.\n",
+	       rx_ring->sbq_free_cnt);
+	printk(KERN_ERR PFX "rx_ring->sbq_buf_size = %d.\n",
+	       rx_ring->sbq_buf_size);
+	printk(KERN_ERR PFX "rx_ring->cq_id = %d.\n", rx_ring->cq_id);
+	printk(KERN_ERR PFX "rx_ring->irq = %d.\n", rx_ring->irq);
+	printk(KERN_ERR PFX "rx_ring->cpu = %d.\n", rx_ring->cpu);
+	printk(KERN_ERR PFX "rx_ring->qdev = %p.\n", rx_ring->qdev);
+}
+
+void ql_dump_hw_cb(struct ql_adapter *qdev, int size, u32 bit, u16 q_id)
+{
+	void *ptr;
+
+	printk(KERN_ERR PFX "%s: Enter.\n", __func__);
+
+	ptr = kmalloc(size, GFP_ATOMIC);
+	if (ptr == NULL) {
+		printk(KERN_ERR PFX "%s: Couldn't allocate a buffer.\n",
+		       __func__);
+		return;
+	}
+
+	if (ql_write_cfg(qdev, ptr, size, bit, q_id)) {
+		printk(KERN_ERR "%s: Failed to upload control block!\n",
+		       __func__);
+		goto fail_it;
+	}
+	switch (bit) {
+	case CFG_DRQ:
+		ql_dump_wqicb((struct wqicb *)ptr);
+		break;
+	case CFG_DCQ:
+		ql_dump_cqicb((struct cqicb *)ptr);
+		break;
+	case CFG_DR:
+		ql_dump_ricb((struct ricb *)ptr);
+		break;
+	default:
+		printk(KERN_ERR PFX "%s: Invalid bit value = %x.\n",
+		       __func__, bit);
+		break;
+	}
+fail_it:
+	kfree(ptr);
+}
+#endif
+
+#ifdef QL_OB_DUMP
+void ql_dump_tx_desc(struct tx_buf_desc *tbd)
+{
+	printk(KERN_ERR PFX "tbd->addr  = 0x%llx\n",
+	       le64_to_cpu((u64) tbd->addr));
+	printk(KERN_ERR PFX "tbd->len   = %d\n",
+	       le32_to_cpu(tbd->len & TX_DESC_LEN_MASK));
+	printk(KERN_ERR PFX "tbd->flags = %s %s\n",
+	       tbd->len & TX_DESC_C ? "C" : ".",
+	       tbd->len & TX_DESC_E ? "E" : ".");
+	tbd++;
+	printk(KERN_ERR PFX "tbd->addr  = 0x%llx\n",
+	       le64_to_cpu((u64) tbd->addr));
+	printk(KERN_ERR PFX "tbd->len   = %d\n",
+	       le32_to_cpu(tbd->len & TX_DESC_LEN_MASK));
+	printk(KERN_ERR PFX "tbd->flags = %s %s\n",
+	       tbd->len & TX_DESC_C ? "C" : ".",
+	       tbd->len & TX_DESC_E ? "E" : ".");
+	tbd++;
+	printk(KERN_ERR PFX "tbd->addr  = 0x%llx\n",
+	       le64_to_cpu((u64) tbd->addr));
+	printk(KERN_ERR PFX "tbd->len   = %d\n",
+	       le32_to_cpu(tbd->len & TX_DESC_LEN_MASK));
+	printk(KERN_ERR PFX "tbd->flags = %s %s\n",
+	       tbd->len & TX_DESC_C ? "C" : ".",
+	       tbd->len & TX_DESC_E ? "E" : ".");
+
+}
+
+void ql_dump_ob_mac_iocb(struct ob_mac_iocb_req *ob_mac_iocb)
+{
+	struct ob_mac_tso_iocb_req *ob_mac_tso_iocb =
+	    (struct ob_mac_tso_iocb_req *)ob_mac_iocb;
+	struct tx_buf_desc *tbd;
+	u16 frame_len;
+
+	printk(KERN_ERR PFX "%s\n", __func__);
+	printk(KERN_ERR PFX "opcode         = %s\n",
+	       (ob_mac_iocb->opcode == OPCODE_OB_MAC_IOCB) ? "MAC" : "TSO");
+	printk(KERN_ERR PFX "flags1          = %s %s %s %s %s\n",
+	       ob_mac_tso_iocb->flags1 & OB_MAC_TSO_IOCB_OI ? "OI" : "",
+	       ob_mac_tso_iocb->flags1 & OB_MAC_TSO_IOCB_I ? "I" : "",
+	       ob_mac_tso_iocb->flags1 & OB_MAC_TSO_IOCB_D ? "D" : "",
+	       ob_mac_tso_iocb->flags1 & OB_MAC_TSO_IOCB_IP4 ? "IP4" : "",
+	       ob_mac_tso_iocb->flags1 & OB_MAC_TSO_IOCB_IP6 ? "IP6" : "");
+	printk(KERN_ERR PFX "flags2          = %s %s %s\n",
+	       ob_mac_tso_iocb->flags2 & OB_MAC_TSO_IOCB_LSO ? "LSO" : "",
+	       ob_mac_tso_iocb->flags2 & OB_MAC_TSO_IOCB_UC ? "UC" : "",
+	       ob_mac_tso_iocb->flags2 & OB_MAC_TSO_IOCB_TC ? "TC" : "");
+	printk(KERN_ERR PFX "flags3          = %s %s %s \n",
+	       ob_mac_tso_iocb->flags3 & OB_MAC_TSO_IOCB_IC ? "IC" : "",
+	       ob_mac_tso_iocb->flags3 & OB_MAC_TSO_IOCB_DFP ? "DFP" : "",
+	       ob_mac_tso_iocb->flags3 & OB_MAC_TSO_IOCB_V ? "V" : "");
+	printk(KERN_ERR PFX "tid = %x\n", ob_mac_iocb->tid);
+	printk(KERN_ERR PFX "txq_idx = %d\n", ob_mac_iocb->txq_idx);
+	printk(KERN_ERR PFX "vlan_tci      = %x\n", ob_mac_tso_iocb->vlan_tci);
+	if (ob_mac_iocb->opcode == OPCODE_OB_MAC_TSO_IOCB) {
+		printk(KERN_ERR PFX "frame_len      = %d\n",
+		       le32_to_cpu(ob_mac_tso_iocb->frame_len));
+		printk(KERN_ERR PFX "mss      = %d\n",
+		       le16_to_cpu(ob_mac_tso_iocb->mss));
+		printk(KERN_ERR PFX "prot_hdr_len   = %d\n",
+		       le16_to_cpu(ob_mac_tso_iocb->total_hdrs_len));
+		printk(KERN_ERR PFX "hdr_offset     = 0x%.04x\n",
+		       le16_to_cpu(ob_mac_tso_iocb->net_trans_offset));
+		frame_len = le32_to_cpu(ob_mac_tso_iocb->frame_len);
+	} else {
+		printk(KERN_ERR PFX "frame_len      = %d\n",
+		       le16_to_cpu(ob_mac_iocb->frame_len));
+		frame_len = le16_to_cpu(ob_mac_iocb->frame_len);
+	}
+	tbd = &ob_mac_iocb->tbd[0];
+	ql_dump_tx_desc(tbd);
+}
+
+void ql_dump_ob_mac_rsp(struct ob_mac_iocb_rsp *ob_mac_rsp)
+{
+	printk(KERN_ERR PFX "%s\n", __func__);
+	printk(KERN_ERR PFX "opcode         = %d\n", ob_mac_rsp->opcode);
+	printk(KERN_ERR PFX "flags          = %s %s %s %s %s %s %s\n",
+	       ob_mac_rsp->flags1 & OB_MAC_IOCB_RSP_OI ? "OI" : ".",
+	       ob_mac_rsp->flags1 & OB_MAC_IOCB_RSP_I ? "I" : ".",
+	       ob_mac_rsp->flags1 & OB_MAC_IOCB_RSP_E ? "E" : ".",
+	       ob_mac_rsp->flags1 & OB_MAC_IOCB_RSP_S ? "S" : ".",
+	       ob_mac_rsp->flags1 & OB_MAC_IOCB_RSP_L ? "L" : ".",
+	       ob_mac_rsp->flags1 & OB_MAC_IOCB_RSP_P ? "P" : ".",
+	       ob_mac_rsp->flags2 & OB_MAC_IOCB_RSP_B ? "B" : ".");
+	printk(KERN_ERR PFX "tid = %x\n", ob_mac_rsp->tid);
+}
+#endif
+
+#ifdef QL_IB_DUMP
+void ql_dump_ib_mac_rsp(struct ib_mac_iocb_rsp *ib_mac_rsp)
+{
+	printk(KERN_ERR PFX "%s\n", __func__);
+	printk(KERN_ERR PFX "opcode         = 0x%x\n", ib_mac_rsp->opcode);
+	printk(KERN_ERR PFX "flags1 = %s%s%s%s%s%s\n",
+	       ib_mac_rsp->flags1 & IB_MAC_IOCB_RSP_OI ? "OI " : "",
+	       ib_mac_rsp->flags1 & IB_MAC_IOCB_RSP_I ? "I " : "",
+	       ib_mac_rsp->flags1 & IB_MAC_IOCB_RSP_TE ? "TE " : "",
+	       ib_mac_rsp->flags1 & IB_MAC_IOCB_RSP_NU ? "NU " : "",
+	       ib_mac_rsp->flags1 & IB_MAC_IOCB_RSP_IE ? "IE " : "",
+	       ib_mac_rsp->flags1 & IB_MAC_IOCB_RSP_B ? "B " : "");
+
+	if (ib_mac_rsp->flags1 & IB_MAC_IOCB_RSP_M_MASK)
+		printk(KERN_ERR PFX "%s%s%s Multicast.\n",
+		       (ib_mac_rsp->flags1 & IB_MAC_IOCB_RSP_M_MASK) ==
+		       IB_MAC_IOCB_RSP_M_HASH ? "Hash" : "",
+		       (ib_mac_rsp->flags1 & IB_MAC_IOCB_RSP_M_MASK) ==
+		       IB_MAC_IOCB_RSP_M_REG ? "Registered" : "",
+		       (ib_mac_rsp->flags1 & IB_MAC_IOCB_RSP_M_MASK) ==
+		       IB_MAC_IOCB_RSP_M_PROM ? "Promiscuous" : "");
+
+	printk(KERN_ERR PFX "flags2 = %s%s%s%s%s\n",
+	       (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_P) ? "P " : "",
+	       (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_V) ? "V " : "",
+	       (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_U) ? "U " : "",
+	       (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_T) ? "T " : "",
+	       (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_FO) ? "FO " : "");
+
+	if (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_ERR_MASK)
+		printk(KERN_ERR PFX "%s%s%s%s%s error.\n",
+		       (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_ERR_MASK) ==
+		       IB_MAC_IOCB_RSP_ERR_OVERSIZE ? "oversize" : "",
+		       (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_ERR_MASK) ==
+		       IB_MAC_IOCB_RSP_ERR_UNDERSIZE ? "undersize" : "",
+		       (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_ERR_MASK) ==
+		       IB_MAC_IOCB_RSP_ERR_PREAMBLE ? "preamble" : "",
+		       (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_ERR_MASK) ==
+		       IB_MAC_IOCB_RSP_ERR_FRAME_LEN ? "frame length" : "",
+		       (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_ERR_MASK) ==
+		       IB_MAC_IOCB_RSP_ERR_CRC ? "CRC" : "");
+
+	printk(KERN_ERR PFX "flags3 = %s%s.\n",
+	       ib_mac_rsp->flags3 & IB_MAC_IOCB_RSP_DS ? "DS " : "",
+	       ib_mac_rsp->flags3 & IB_MAC_IOCB_RSP_DL ? "DL " : "");
+
+	if (ib_mac_rsp->flags3 & IB_MAC_IOCB_RSP_RSS_MASK)
+		printk(KERN_ERR PFX "RSS flags = %s%s%s%s.\n",
+		       ((ib_mac_rsp->flags3 & IB_MAC_IOCB_RSP_RSS_MASK) ==
+			IB_MAC_IOCB_RSP_M_IPV4) ? "IPv4 RSS" : "",
+		       ((ib_mac_rsp->flags3 & IB_MAC_IOCB_RSP_RSS_MASK) ==
+			IB_MAC_IOCB_RSP_M_IPV6) ? "IPv6 RSS " : "",
+		       ((ib_mac_rsp->flags3 & IB_MAC_IOCB_RSP_RSS_MASK) ==
+			IB_MAC_IOCB_RSP_M_TCP_V4) ? "TCP/IPv4 RSS" : "",
+		       ((ib_mac_rsp->flags3 & IB_MAC_IOCB_RSP_RSS_MASK) ==
+			IB_MAC_IOCB_RSP_M_TCP_V6) ? "TCP/IPv6 RSS" : "");
+
+	printk(KERN_ERR PFX "data_len	= %d\n",
+	       le32_to_cpu(ib_mac_rsp->data_len));
+	printk(KERN_ERR PFX "data_addr_hi    = 0x%x\n",
+	       le32_to_cpu(ib_mac_rsp->data_addr_hi));
+	printk(KERN_ERR PFX "data_addr_lo    = 0x%x\n",
+	       le32_to_cpu(ib_mac_rsp->data_addr_lo));
+	if (ib_mac_rsp->flags3 & IB_MAC_IOCB_RSP_RSS_MASK)
+		printk(KERN_ERR PFX "rss    = %x\n",
+		       le32_to_cpu(ib_mac_rsp->rss));
+	if (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_V)
+		printk(KERN_ERR PFX "vlan_id    = %x\n",
+		       le16_to_cpu(ib_mac_rsp->vlan_id));
+
+	printk(KERN_ERR PFX "flags4 = %s%s%s.\n",
+	       le32_to_cpu(ib_mac_rsp->
+			   flags4) & IB_MAC_IOCB_RSP_HV ? "HV " : "",
+	       le32_to_cpu(ib_mac_rsp->
+			   flags4) & IB_MAC_IOCB_RSP_HS ? "HS " : "",
+	       le32_to_cpu(ib_mac_rsp->
+			   flags4) & IB_MAC_IOCB_RSP_HL ? "HL " : "");
+
+	if (le32_to_cpu(ib_mac_rsp->flags4) & IB_MAC_IOCB_RSP_HV) {
+		printk(KERN_ERR PFX "hdr length	= %d.\n",
+		       le32_to_cpu(ib_mac_rsp->hdr_len));
+		printk(KERN_ERR PFX "hdr addr_hi    = 0x%x.\n",
+		       le32_to_cpu(ib_mac_rsp->hdr_addr_hi));
+		printk(KERN_ERR PFX "hdr addr_lo    = 0x%x.\n",
+		       le32_to_cpu(ib_mac_rsp->hdr_addr_lo));
+	}
+}
+#endif
+
+#ifdef QL_ALL_DUMP
+void ql_dump_all(struct ql_adapter *qdev)
+{
+	int i;
+
+	QL_DUMP_REGS(qdev);
+	QL_DUMP_QDEV(qdev);
+	for (i = 0; i < qdev->tx_ring_count; i++) {
+		QL_DUMP_TX_RING(&qdev->tx_ring[i]);
+		QL_DUMP_WQICB((struct wqicb *)&qdev->tx_ring[i]);
+	}
+	for (i = 0; i < qdev->rx_ring_count; i++) {
+		QL_DUMP_RX_RING(&qdev->rx_ring[i]);
+		QL_DUMP_CQICB((struct cqicb *)&qdev->rx_ring[i]);
+	}
+}
+#endif
diff --git a/drivers/net/qlge/qlge_ethtool.c b/drivers/net/qlge/qlge_ethtool.c
new file mode 100644
index 0000000..b62fbd4
--- /dev/null
+++ b/drivers/net/qlge/qlge_ethtool.c
@@ -0,0 +1,414 @@
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/list.h>
+#include <linux/pci.h>
+#include <linux/dma-mapping.h>
+#include <linux/pagemap.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/dmapool.h>
+#include <linux/mempool.h>
+#include <linux/spinlock.h>
+#include <linux/kthread.h>
+#include <linux/interrupt.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/in.h>
+#include <linux/ip.h>
+#include <linux/ipv6.h>
+#include <net/ipv6.h>
+#include <linux/tcp.h>
+#include <linux/udp.h>
+#include <linux/if_arp.h>
+#include <linux/if_ether.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+#include <linux/skbuff.h>
+#include <linux/rtnetlink.h>
+#include <linux/if_vlan.h>
+#include <linux/delay.h>
+#include <linux/mm.h>
+#include <linux/vmalloc.h>
+
+#include <linux/version.h>
+
+#include "qlge.h"
+
+static int ql_update_ring_coalescing(struct ql_adapter *qdev)
+{
+	int i, status = 0;
+	struct rx_ring *rx_ring;
+	struct cqicb *cqicb;
+
+	if (!netif_running(qdev->ndev))
+		return status;
+
+	spin_lock(&qdev->hw_lock);
+	/* Skip the default queue, and update the outbound handler
+	 * queues if they changed.
+	 */
+	cqicb = (struct cqicb *)&qdev->rx_ring[1];
+	if (le16_to_cpu(cqicb->irq_delay) != qdev->tx_coalesce_usecs ||
+	    le16_to_cpu(cqicb->pkt_delay) != qdev->tx_max_coalesced_frames) {
+		for (i = 1; i < qdev->rss_ring_first_cq_id; i++, rx_ring++) {
+			rx_ring = &qdev->rx_ring[i];
+			cqicb = (struct cqicb *)rx_ring;
+			cqicb->irq_delay = le16_to_cpu(qdev->tx_coalesce_usecs);
+			cqicb->pkt_delay =
+			    le16_to_cpu(qdev->tx_max_coalesced_frames);
+			cqicb->flags = FLAGS_LI;
+			status = ql_write_cfg(qdev, cqicb, sizeof(cqicb),
+						CFG_LCQ, rx_ring->cq_id);
+			if (status) {
+				QPRINTK(qdev, IFUP, ERR,
+					"Failed to load CQICB.\n");
+				goto exit;
+			}
+		}
+	}
+
+	/* Update the inbound (RSS) handler queues if they changed. */
+	cqicb = (struct cqicb *)&qdev->rx_ring[qdev->rss_ring_first_cq_id];
+	if (le16_to_cpu(cqicb->irq_delay) != qdev->rx_coalesce_usecs ||
+	    le16_to_cpu(cqicb->pkt_delay) != qdev->rx_max_coalesced_frames) {
+		for (i = qdev->rss_ring_first_cq_id;
+		     i <= qdev->rss_ring_first_cq_id + qdev->rss_ring_count;
+		     i++) {
+			rx_ring = &qdev->rx_ring[i];
+			cqicb = (struct cqicb *)rx_ring;
+			cqicb->irq_delay = le16_to_cpu(qdev->rx_coalesce_usecs);
+			cqicb->pkt_delay =
+			    le16_to_cpu(qdev->rx_max_coalesced_frames);
+			cqicb->flags = FLAGS_LI;
+			status = ql_write_cfg(qdev, cqicb, sizeof(cqicb),
+						CFG_LCQ, rx_ring->cq_id);
+			if (status) {
+				QPRINTK(qdev, IFUP, ERR,
+					"Failed to load CQICB.\n");
+				goto exit;
+			}
+		}
+	}
+exit:
+	spin_unlock(&qdev->hw_lock);
+	return status;
+}
+
+void ql_update_stats(struct ql_adapter *qdev)
+{
+	u32 i;
+	u64 data;
+	u64 *iter = &qdev->nic_stats.tx_pkts;
+
+	spin_lock(&qdev->stats_lock);
+	if (ql_sem_spinlock(qdev, qdev->xg_sem_mask)) {
+			QPRINTK(qdev, DRV, ERR,
+				"Couldn't get xgmac sem.\n");
+		goto quit;
+	}
+	/*
+	 * Get TX statistics.
+	 */
+	for (i = 0x200; i < 0x280; i += 8) {
+		if (ql_read_xgmac_reg64(qdev, i, &data)) {
+			QPRINTK(qdev, DRV, ERR,
+				"Error reading status register 0x%.04x.\n", i);
+			goto end;
+		} else
+			*iter = data;
+		iter++;
+	}
+
+	/*
+	 * Get RX statistics.
+	 */
+	for (i = 0x300; i < 0x3d0; i += 8) {
+		if (ql_read_xgmac_reg64(qdev, i, &data)) {
+			QPRINTK(qdev, DRV, ERR,
+				"Error reading status register 0x%.04x.\n", i);
+			goto end;
+		} else
+			*iter = data;
+		iter++;
+	}
+
+end:
+	ql_sem_unlock(qdev, qdev->xg_sem_mask);
+quit:
+	spin_unlock(&qdev->stats_lock);
+
+	QL_DUMP_STAT(qdev);
+
+	return;
+}
+
+static char ql_stats_str_arr[][ETH_GSTRING_LEN] = {
+	{"tx_pkts"},
+	{"tx_bytes"},
+	{"tx_mcast_pkts"},
+	{"tx_bcast_pkts"},
+	{"tx_ucast_pkts"},
+	{"tx_ctl_pkts"},
+	{"tx_pause_pkts"},
+	{"tx_64_pkts"},
+	{"tx_65_to_127_pkts"},
+	{"tx_128_to_255_pkts"},
+	{"tx_256_511_pkts"},
+	{"tx_512_to_1023_pkts"},
+	{"tx_1024_to_1518_pkts"},
+	{"tx_1519_to_max_pkts"},
+	{"tx_undersize_pkts"},
+	{"tx_oversize_pkts"},
+	{"rx_bytes"},
+	{"rx_bytes_ok"},
+	{"rx_pkts"},
+	{"rx_pkts_ok"},
+	{"rx_bcast_pkts"},
+	{"rx_mcast_pkts"},
+	{"rx_ucast_pkts"},
+	{"rx_undersize_pkts"},
+	{"rx_oversize_pkts"},
+	{"rx_jabber_pkts"},
+	{"rx_undersize_fcerr_pkts"},
+	{"rx_drop_events"},
+	{"rx_fcerr_pkts"},
+	{"rx_align_err"},
+	{"rx_symbol_err"},
+	{"rx_mac_err"},
+	{"rx_ctl_pkts"},
+	{"rx_pause_pkts"},
+	{"rx_64_pkts"},
+	{"rx_65_to_127_pkts"},
+	{"rx_128_255_pkts"},
+	{"rx_256_511_pkts"},
+	{"rx_512_to_1023_pkts"},
+	{"rx_1024_to_1518_pkts"},
+	{"rx_1519_to_max_pkts"},
+	{"rx_len_err_pkts"},
+};
+
+static void ql_get_strings(struct net_device *dev, u32 stringset, u8 *buf)
+{
+	switch (stringset) {
+	case ETH_SS_STATS:
+		memcpy(buf, ql_stats_str_arr, sizeof(ql_stats_str_arr));
+		break;
+	}
+}
+
+static int ql_get_sset_count(struct net_device *dev, int sset)
+{
+	switch (sset) {
+	case ETH_SS_STATS:
+		return ARRAY_SIZE(ql_stats_str_arr);
+	default:
+		return -EOPNOTSUPP;
+	}
+}
+
+static void
+ql_get_ethtool_stats(struct net_device *ndev,
+		     struct ethtool_stats *stats, u64 *data)
+{
+	struct ql_adapter *qdev = netdev_priv(ndev);
+	struct nic_stats *s = &qdev->nic_stats;
+
+	ql_update_stats(qdev);
+
+	*data++ = s->tx_pkts;
+	*data++ = s->tx_bytes;
+	*data++ = s->tx_mcast_pkts;
+	*data++ = s->tx_bcast_pkts;
+	*data++ = s->tx_ucast_pkts;
+	*data++ = s->tx_ctl_pkts;
+	*data++ = s->tx_pause_pkts;
+	*data++ = s->tx_64_pkt;
+	*data++ = s->tx_65_to_127_pkt;
+	*data++ = s->tx_128_to_255_pkt;
+	*data++ = s->tx_256_511_pkt;
+	*data++ = s->tx_512_to_1023_pkt;
+	*data++ = s->tx_1024_to_1518_pkt;
+	*data++ = s->tx_1519_to_max_pkt;
+	*data++ = s->tx_undersize_pkt;
+	*data++ = s->tx_oversize_pkt;
+	*data++ = s->rx_bytes;
+	*data++ = s->rx_bytes_ok;
+	*data++ = s->rx_pkts;
+	*data++ = s->rx_pkts_ok;
+	*data++ = s->rx_bcast_pkts;
+	*data++ = s->rx_mcast_pkts;
+	*data++ = s->rx_ucast_pkts;
+	*data++ = s->rx_undersize_pkts;
+	*data++ = s->rx_oversize_pkts;
+	*data++ = s->rx_jabber_pkts;
+	*data++ = s->rx_undersize_fcerr_pkts;
+	*data++ = s->rx_drop_events;
+	*data++ = s->rx_fcerr_pkts;
+	*data++ = s->rx_align_err;
+	*data++ = s->rx_symbol_err;
+	*data++ = s->rx_mac_err;
+	*data++ = s->rx_ctl_pkts;
+	*data++ = s->rx_pause_pkts;
+	*data++ = s->rx_64_pkts;
+	*data++ = s->rx_65_to_127_pkts;
+	*data++ = s->rx_128_255_pkts;
+	*data++ = s->rx_256_511_pkts;
+	*data++ = s->rx_512_to_1023_pkts;
+	*data++ = s->rx_1024_to_1518_pkts;
+	*data++ = s->rx_1519_to_max_pkts;
+	*data++ = s->rx_len_err_pkts;
+}
+
+static int ql_get_settings(struct net_device *ndev,
+			      struct ethtool_cmd *ecmd)
+{
+	struct ql_adapter *qdev = netdev_priv(ndev);
+
+	ecmd->supported = SUPPORTED_10000baseT_Full;
+	ecmd->advertising = ADVERTISED_10000baseT_Full;
+	ecmd->autoneg = AUTONEG_ENABLE;
+	ecmd->transceiver = XCVR_EXTERNAL;
+	if ((qdev->link_status & LINK_TYPE_MASK) == LINK_TYPE_10GBASET) {
+		ecmd->supported |= (SUPPORTED_TP | SUPPORTED_Autoneg);
+		ecmd->advertising |= (ADVERTISED_TP | ADVERTISED_Autoneg);
+		ecmd->port = PORT_TP;
+	} else {
+		ecmd->supported |= SUPPORTED_FIBRE;
+		ecmd->advertising |= ADVERTISED_FIBRE;
+		ecmd->port = PORT_FIBRE;
+	}
+
+	ecmd->speed = SPEED_10000;
+	ecmd->duplex = DUPLEX_FULL;
+
+	return 0;
+}
+
+static void ql_get_drvinfo(struct net_device *ndev,
+			   struct ethtool_drvinfo *drvinfo)
+{
+	struct ql_adapter *qdev = netdev_priv(ndev);
+	strncpy(drvinfo->driver, qlge_driver_name, 32);
+	strncpy(drvinfo->version, qlge_driver_version, 32);
+	strncpy(drvinfo->fw_version, "N/A", 32);
+	strncpy(drvinfo->bus_info, pci_name(qdev->pdev), 32);
+	drvinfo->n_stats = 0;
+	drvinfo->testinfo_len = 0;
+	drvinfo->regdump_len = 0;
+	drvinfo->eedump_len = 0;
+}
+
+static int ql_get_coalesce(struct net_device *dev, struct ethtool_coalesce *c)
+{
+	struct ql_adapter *qdev = netdev_priv(dev);
+
+	c->rx_coalesce_usecs = qdev->rx_coalesce_usecs;
+	c->tx_coalesce_usecs = qdev->tx_coalesce_usecs;
+
+	/* This chip coalesces as follows:
+	 * If a packet arrives, hold off interrupts until
+	 * cqicb->int_delay expires, but if no other packets arrive don't
+	 * wait longer than cqicb->pkt_int_delay. But ethtool doesn't use a
+	 * timer to coalesce on a frame basis.  So, we have to take ethtool's
+	 * max_coalesced_frames value and convert it to a delay in microseconds.
+	 * We do this by using a basic thoughput of 1,000,000 frames per
+	 * second @ (1024 bytes).  This means one frame per usec. So it's a
+	 * simple one to one ratio.
+	 */
+	c->rx_max_coalesced_frames = qdev->rx_max_coalesced_frames;
+	c->tx_max_coalesced_frames = qdev->tx_max_coalesced_frames;
+
+	return 0;
+}
+
+static int ql_set_coalesce(struct net_device *ndev, struct ethtool_coalesce *c)
+{
+	struct ql_adapter *qdev = netdev_priv(ndev);
+
+	/* Validate user parameters. */
+	if (c->rx_coalesce_usecs > qdev->rx_ring_size / 2)
+		return -EINVAL;
+       /* Don't wait more than 10 usec. */
+	if (c->rx_max_coalesced_frames > MAX_INTER_FRAME_WAIT)
+		return -EINVAL;
+	if (c->tx_coalesce_usecs > qdev->tx_ring_size / 2)
+		return -EINVAL;
+	if (c->tx_max_coalesced_frames > MAX_INTER_FRAME_WAIT)
+		return -EINVAL;
+
+	/* Verify a change took place before updating the hardware. */
+	if (qdev->rx_coalesce_usecs == c->rx_coalesce_usecs &&
+	    qdev->tx_coalesce_usecs == c->tx_coalesce_usecs &&
+	    qdev->rx_max_coalesced_frames == c->rx_max_coalesced_frames &&
+	    qdev->tx_max_coalesced_frames == c->tx_max_coalesced_frames)
+		return 0;
+
+	qdev->rx_coalesce_usecs = c->rx_coalesce_usecs;
+	qdev->tx_coalesce_usecs = c->tx_coalesce_usecs;
+	qdev->rx_max_coalesced_frames = c->rx_max_coalesced_frames;
+	qdev->tx_max_coalesced_frames = c->tx_max_coalesced_frames;
+
+	return ql_update_ring_coalescing(qdev);
+}
+
+static u32 ql_get_rx_csum(struct net_device *netdev)
+{
+	struct ql_adapter *qdev = netdev_priv(netdev);
+	return qdev->rx_csum;
+}
+
+static int ql_set_rx_csum(struct net_device *netdev, uint32_t data)
+{
+	struct ql_adapter *qdev = netdev_priv(netdev);
+	qdev->rx_csum = data;
+	return 0;
+}
+
+static int ql_set_tso(struct net_device *ndev, uint32_t data)
+{
+
+	if (data) {
+		ndev->features |= NETIF_F_TSO;
+		ndev->features |= NETIF_F_TSO6;
+	} else {
+		ndev->features &= ~NETIF_F_TSO;
+		ndev->features &= ~NETIF_F_TSO6;
+	}
+	return 0;
+}
+
+static u32 ql_get_msglevel(struct net_device *ndev)
+{
+	struct ql_adapter *qdev = netdev_priv(ndev);
+	return qdev->msg_enable;
+}
+
+static void ql_set_msglevel(struct net_device *ndev, u32 value)
+{
+	struct ql_adapter *qdev = netdev_priv(ndev);
+	qdev->msg_enable = value;
+}
+
+const struct ethtool_ops qlge_ethtool_ops = {
+	.get_settings = ql_get_settings,
+	.get_drvinfo = ql_get_drvinfo,
+	.get_msglevel = ql_get_msglevel,
+	.set_msglevel = ql_set_msglevel,
+	.get_link = ethtool_op_get_link,
+	.get_rx_csum = ql_get_rx_csum,
+	.set_rx_csum = ql_set_rx_csum,
+	.get_tx_csum = ethtool_op_get_tx_csum,
+	.get_sg = ethtool_op_get_sg,
+	.set_sg = ethtool_op_set_sg,
+	.get_tso = ethtool_op_get_tso,
+	.set_tso = ql_set_tso,
+	.get_coalesce = ql_get_coalesce,
+	.set_coalesce = ql_set_coalesce,
+	.get_sset_count = ql_get_sset_count,
+	.get_strings = ql_get_strings,
+	.get_ethtool_stats = ql_get_ethtool_stats,
+};
+
diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c
new file mode 100644
index 0000000..4b2caa6
--- /dev/null
+++ b/drivers/net/qlge/qlge_main.c
@@ -0,0 +1,3956 @@
+/*
+ * QLogic qlge NIC HBA Driver
+ * Copyright (c)  2003-2008 QLogic Corporation
+ * See LICENSE.qlge for copyright and licensing details.
+ * Author:     Linux qlge network device driver by
+ *                      Ron Mercer <ron.mercer@qlogic.com>
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/list.h>
+#include <linux/pci.h>
+#include <linux/dma-mapping.h>
+#include <linux/pagemap.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/dmapool.h>
+#include <linux/mempool.h>
+#include <linux/spinlock.h>
+#include <linux/kthread.h>
+#include <linux/interrupt.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/in.h>
+#include <linux/ip.h>
+#include <linux/ipv6.h>
+#include <net/ipv6.h>
+#include <linux/tcp.h>
+#include <linux/udp.h>
+#include <linux/if_arp.h>
+#include <linux/if_ether.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+#include <linux/skbuff.h>
+#include <linux/rtnetlink.h>
+#include <linux/if_vlan.h>
+#include <linux/delay.h>
+#include <linux/mm.h>
+#include <linux/vmalloc.h>
+#include <net/ip6_checksum.h>
+
+#include "qlge.h"
+
+char qlge_driver_name[] = DRV_NAME;
+const char qlge_driver_version[] = DRV_VERSION;
+
+MODULE_AUTHOR("Ron Mercer <ron.mercer@qlogic.com>");
+MODULE_DESCRIPTION(DRV_STRING " ");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
+
+static const u32 default_msg =
+    NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK |
+/* NETIF_MSG_TIMER |	*/
+    NETIF_MSG_IFDOWN |
+    NETIF_MSG_IFUP |
+    NETIF_MSG_RX_ERR |
+    NETIF_MSG_TX_ERR |
+    NETIF_MSG_TX_QUEUED |
+    NETIF_MSG_INTR | NETIF_MSG_TX_DONE | NETIF_MSG_RX_STATUS |
+/* NETIF_MSG_PKTDATA | */
+    NETIF_MSG_HW | NETIF_MSG_WOL | 0;
+
+static int debug = 0x00007fff;	/* defaults above */
+module_param(debug, int, 0);
+MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)");
+
+#define MSIX_IRQ 0
+#define MSI_IRQ 1
+#define LEG_IRQ 2
+static int irq_type = MSIX_IRQ;
+module_param(irq_type, int, MSIX_IRQ);
+MODULE_PARM_DESC(irq_type, "0 = MSI-X, 1 = MSI, 2 = Legacy.");
+
+static struct pci_device_id qlge_pci_tbl[] __devinitdata = {
+	{PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, QLGE_DEVICE_ID)},
+	{PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, QLGE_DEVICE_ID1)},
+	/* required last entry */
+	{0,}
+};
+
+MODULE_DEVICE_TABLE(pci, qlge_pci_tbl);
+
+/* This hardware semaphore causes exclusive access to
+ * resources shared between the NIC driver, MPI firmware,
+ * FCOE firmware and the FC driver.
+ */
+static int ql_sem_trylock(struct ql_adapter *qdev, u32 sem_mask)
+{
+	u32 sem_bits = 0;
+
+	switch (sem_mask) {
+	case SEM_XGMAC0_MASK:
+		sem_bits = SEM_SET << SEM_XGMAC0_SHIFT;
+		break;
+	case SEM_XGMAC1_MASK:
+		sem_bits = SEM_SET << SEM_XGMAC1_SHIFT;
+		break;
+	case SEM_ICB_MASK:
+		sem_bits = SEM_SET << SEM_ICB_SHIFT;
+		break;
+	case SEM_MAC_ADDR_MASK:
+		sem_bits = SEM_SET << SEM_MAC_ADDR_SHIFT;
+		break;
+	case SEM_FLASH_MASK:
+		sem_bits = SEM_SET << SEM_FLASH_SHIFT;
+		break;
+	case SEM_PROBE_MASK:
+		sem_bits = SEM_SET << SEM_PROBE_SHIFT;
+		break;
+	case SEM_RT_IDX_MASK:
+		sem_bits = SEM_SET << SEM_RT_IDX_SHIFT;
+		break;
+	case SEM_PROC_REG_MASK:
+		sem_bits = SEM_SET << SEM_PROC_REG_SHIFT;
+		break;
+	default:
+		QPRINTK(qdev, PROBE, ALERT, "Bad Semaphore mask!.\n");
+		return -EINVAL;
+	}
+
+	ql_write32(qdev, SEM, sem_bits | sem_mask);
+	return !(ql_read32(qdev, SEM) & sem_bits);
+}
+
+int ql_sem_spinlock(struct ql_adapter *qdev, u32 sem_mask)
+{
+	unsigned int seconds = 3;
+	do {
+		if (!ql_sem_trylock(qdev, sem_mask))
+			return 0;
+		ssleep(1);
+	} while (--seconds);
+	return -ETIMEDOUT;
+}
+
+void ql_sem_unlock(struct ql_adapter *qdev, u32 sem_mask)
+{
+	ql_write32(qdev, SEM, sem_mask);
+	ql_read32(qdev, SEM);	/* flush */
+}
+
+/* This function waits for a specific bit to come ready
+ * in a given register.  It is used mostly by the initialize
+ * process, but is also used in kernel thread API such as
+ * netdev->set_multi, netdev->set_mac_address, netdev->vlan_rx_add_vid.
+ */
+int ql_wait_reg_rdy(struct ql_adapter *qdev, u32 reg, u32 bit, u32 err_bit)
+{
+	u32 temp;
+	int count = UDELAY_COUNT;
+
+	while (count) {
+		temp = ql_read32(qdev, reg);
+
+		/* check for errors */
+		if (temp & err_bit) {
+			QPRINTK(qdev, PROBE, ALERT,
+				"register 0x%.08x access error, value = 0x%.08x!.\n",
+				reg, temp);
+			return -EIO;
+		} else if (temp & bit)
+			return 0;
+		udelay(UDELAY_DELAY);
+		count--;
+	}
+	QPRINTK(qdev, PROBE, ALERT,
+		"Timed out waiting for reg %x to come ready.\n", reg);
+	return -ETIMEDOUT;
+}
+
+/* The CFG register is used to download TX and RX control blocks
+ * to the chip. This function waits for an operation to complete.
+ */
+static int ql_wait_cfg(struct ql_adapter *qdev, u32 bit)
+{
+	int count = UDELAY_COUNT;
+	u32 temp;
+
+	while (count) {
+		temp = ql_read32(qdev, CFG);
+		if (temp & CFG_LE)
+			return -EIO;
+		if (!(temp & bit))
+			return 0;
+		udelay(UDELAY_DELAY);
+		count--;
+	}
+	return -ETIMEDOUT;
+}
+
+
+/* Used to issue init control blocks to hw. Maps control block,
+ * sets address, triggers download, waits for completion.
+ */
+int ql_write_cfg(struct ql_adapter *qdev, void *ptr, int size, u32 bit,
+		 u16 q_id)
+{
+	u64 map;
+	int status = 0;
+	int direction;
+	u32 mask;
+	u32 value;
+
+	direction =
+	    (bit & (CFG_LRQ | CFG_LR | CFG_LCQ)) ? PCI_DMA_TODEVICE :
+	    PCI_DMA_FROMDEVICE;
+
+	map = pci_map_single(qdev->pdev, ptr, size, direction);
+	if (pci_dma_mapping_error(qdev->pdev, map)) {
+		QPRINTK(qdev, IFUP, ERR, "Couldn't map DMA area.\n");
+		return -ENOMEM;
+	}
+
+	status = ql_wait_cfg(qdev, bit);
+	if (status) {
+		QPRINTK(qdev, IFUP, ERR,
+			"Timed out waiting for CFG to come ready.\n");
+		goto exit;
+	}
+
+	status = ql_sem_spinlock(qdev, SEM_ICB_MASK);
+	if (status)
+		goto exit;
+	ql_write32(qdev, ICB_L, (u32) map);
+	ql_write32(qdev, ICB_H, (u32) (map >> 32));
+	ql_sem_unlock(qdev, SEM_ICB_MASK);	/* does flush too */
+
+	mask = CFG_Q_MASK | (bit << 16);
+	value = bit | (q_id << CFG_Q_SHIFT);
+	ql_write32(qdev, CFG, (mask | value));
+
+	/*
+	 * Wait for the bit to clear after signaling hw.
+	 */
+	status = ql_wait_cfg(qdev, bit);
+exit:
+	pci_unmap_single(qdev->pdev, map, size, direction);
+	return status;
+}
+
+/* Get a specific MAC address from the CAM.  Used for debug and reg dump. */
+int ql_get_mac_addr_reg(struct ql_adapter *qdev, u32 type, u16 index,
+			u32 *value)
+{
+	u32 offset = 0;
+	int status;
+
+	status = ql_sem_spinlock(qdev, SEM_MAC_ADDR_MASK);
+	if (status)
+		return status;
+	switch (type) {
+	case MAC_ADDR_TYPE_MULTI_MAC:
+	case MAC_ADDR_TYPE_CAM_MAC:
+		{
+			status =
+			    ql_wait_reg_rdy(qdev,
+				MAC_ADDR_IDX, MAC_ADDR_MW, MAC_ADDR_E);
+			if (status)
+				goto exit;
+			ql_write32(qdev, MAC_ADDR_IDX, (offset++) | /* offset */
+				   (index << MAC_ADDR_IDX_SHIFT) | /* index */
+				   MAC_ADDR_ADR | MAC_ADDR_RS | type); /* type */
+			status =
+			    ql_wait_reg_rdy(qdev,
+				MAC_ADDR_IDX, MAC_ADDR_MR, MAC_ADDR_E);
+			if (status)
+				goto exit;
+			*value++ = ql_read32(qdev, MAC_ADDR_DATA);
+			status =
+			    ql_wait_reg_rdy(qdev,
+				MAC_ADDR_IDX, MAC_ADDR_MW, MAC_ADDR_E);
+			if (status)
+				goto exit;
+			ql_write32(qdev, MAC_ADDR_IDX, (offset++) | /* offset */
+				   (index << MAC_ADDR_IDX_SHIFT) | /* index */
+				   MAC_ADDR_ADR | MAC_ADDR_RS | type); /* type */
+			status =
+			    ql_wait_reg_rdy(qdev,
+				MAC_ADDR_IDX, MAC_ADDR_MR, MAC_ADDR_E);
+			if (status)
+				goto exit;
+			*value++ = ql_read32(qdev, MAC_ADDR_DATA);
+			if (type == MAC_ADDR_TYPE_CAM_MAC) {
+				status =
+				    ql_wait_reg_rdy(qdev,
+					MAC_ADDR_IDX, MAC_ADDR_MW, MAC_ADDR_E);
+				if (status)
+					goto exit;
+				ql_write32(qdev, MAC_ADDR_IDX, (offset++) | /* offset */
+					   (index << MAC_ADDR_IDX_SHIFT) | /* index */
+					   MAC_ADDR_ADR | MAC_ADDR_RS | type); /* type */
+				status =
+				    ql_wait_reg_rdy(qdev, MAC_ADDR_IDX,
+						    MAC_ADDR_MR, MAC_ADDR_E);
+				if (status)
+					goto exit;
+				*value++ = ql_read32(qdev, MAC_ADDR_DATA);
+			}
+			break;
+		}
+	case MAC_ADDR_TYPE_VLAN:
+	case MAC_ADDR_TYPE_MULTI_FLTR:
+	default:
+		QPRINTK(qdev, IFUP, CRIT,
+			"Address type %d not yet supported.\n", type);
+		status = -EPERM;
+	}
+exit:
+	ql_sem_unlock(qdev, SEM_MAC_ADDR_MASK);
+	return status;
+}
+
+/* Set up a MAC, multicast or VLAN address for the
+ * inbound frame matching.
+ */
+static int ql_set_mac_addr_reg(struct ql_adapter *qdev, u8 *addr, u32 type,
+			       u16 index)
+{
+	u32 offset = 0;
+	int status = 0;
+
+	status = ql_sem_spinlock(qdev, SEM_MAC_ADDR_MASK);
+	if (status)
+		return status;
+	switch (type) {
+	case MAC_ADDR_TYPE_MULTI_MAC:
+	case MAC_ADDR_TYPE_CAM_MAC:
+		{
+			u32 cam_output;
+			u32 upper = (addr[0] << 8) | addr[1];
+			u32 lower =
+			    (addr[2] << 24) | (addr[3] << 16) | (addr[4] << 8) |
+			    (addr[5]);
+
+			QPRINTK(qdev, IFUP, INFO,
+				"Adding %s address %02x:%02x:%02x:%02x:%02x:%02x"
+				" at index %d in the CAM.\n",
+				((type ==
+				  MAC_ADDR_TYPE_MULTI_MAC) ? "MULTICAST" :
+				 "UNICAST"), addr[0], addr[1], addr[2], addr[3],
+				addr[4], addr[5], index);
+
+			status =
+			    ql_wait_reg_rdy(qdev,
+				MAC_ADDR_IDX, MAC_ADDR_MW, MAC_ADDR_E);
+			if (status)
+				goto exit;
+			ql_write32(qdev, MAC_ADDR_IDX, (offset++) | /* offset */
+				   (index << MAC_ADDR_IDX_SHIFT) | /* index */
+				   type);	/* type */
+			ql_write32(qdev, MAC_ADDR_DATA, lower);
+			status =
+			    ql_wait_reg_rdy(qdev,
+				MAC_ADDR_IDX, MAC_ADDR_MW, MAC_ADDR_E);
+			if (status)
+				goto exit;
+			ql_write32(qdev, MAC_ADDR_IDX, (offset++) | /* offset */
+				   (index << MAC_ADDR_IDX_SHIFT) | /* index */
+				   type);	/* type */
+			ql_write32(qdev, MAC_ADDR_DATA, upper);
+			status =
+			    ql_wait_reg_rdy(qdev,
+				MAC_ADDR_IDX, MAC_ADDR_MW, MAC_ADDR_E);
+			if (status)
+				goto exit;
+			ql_write32(qdev, MAC_ADDR_IDX, (offset) |	/* offset */
+				   (index << MAC_ADDR_IDX_SHIFT) |	/* index */
+				   type);	/* type */
+			/* This field should also include the queue id
+			   and possibly the function id.  Right now we hardcode
+			   the route field to NIC core.
+			 */
+			if (type == MAC_ADDR_TYPE_CAM_MAC) {
+				cam_output = (CAM_OUT_ROUTE_NIC |
+					      (qdev->
+					       func << CAM_OUT_FUNC_SHIFT) |
+					      (qdev->
+					       rss_ring_first_cq_id <<
+					       CAM_OUT_CQ_ID_SHIFT));
+				if (qdev->vlgrp)
+					cam_output |= CAM_OUT_RV;
+				/* route to NIC core */
+				ql_write32(qdev, MAC_ADDR_DATA, cam_output);
+			}
+			break;
+		}
+	case MAC_ADDR_TYPE_VLAN:
+		{
+			u32 enable_bit = *((u32 *) &addr[0]);
+			/* For VLAN, the addr actually holds a bit that
+			 * either enables or disables the vlan id we are
+			 * addressing. It's either MAC_ADDR_E on or off.
+			 * That's bit-27 we're talking about.
+			 */
+			QPRINTK(qdev, IFUP, INFO, "%s VLAN ID %d %s the CAM.\n",
+				(enable_bit ? "Adding" : "Removing"),
+				index, (enable_bit ? "to" : "from"));
+
+			status =
+			    ql_wait_reg_rdy(qdev,
+				MAC_ADDR_IDX, MAC_ADDR_MW, MAC_ADDR_E);
+			if (status)
+				goto exit;
+			ql_write32(qdev, MAC_ADDR_IDX, offset |	/* offset */
+				   (index << MAC_ADDR_IDX_SHIFT) |	/* index */
+				   type |	/* type */
+				   enable_bit);	/* enable/disable */
+			break;
+		}
+	case MAC_ADDR_TYPE_MULTI_FLTR:
+	default:
+		QPRINTK(qdev, IFUP, CRIT,
+			"Address type %d not yet supported.\n", type);
+		status = -EPERM;
+	}
+exit:
+	ql_sem_unlock(qdev, SEM_MAC_ADDR_MASK);
+	return status;
+}
+
+/* Get a specific frame routing value from the CAM.
+ * Used for debug and reg dump.
+ */
+int ql_get_routing_reg(struct ql_adapter *qdev, u32 index, u32 *value)
+{
+	int status = 0;
+
+	status = ql_sem_spinlock(qdev, SEM_RT_IDX_MASK);
+	if (status)
+		goto exit;
+
+	status = ql_wait_reg_rdy(qdev, RT_IDX, RT_IDX_MW, RT_IDX_E);
+	if (status)
+		goto exit;
+
+	ql_write32(qdev, RT_IDX,
+		   RT_IDX_TYPE_NICQ | RT_IDX_RS | (index << RT_IDX_IDX_SHIFT));
+	status = ql_wait_reg_rdy(qdev, RT_IDX, RT_IDX_MR, RT_IDX_E);
+	if (status)
+		goto exit;
+	*value = ql_read32(qdev, RT_DATA);
+exit:
+	ql_sem_unlock(qdev, SEM_RT_IDX_MASK);
+	return status;
+}
+
+/* The NIC function for this chip has 16 routing indexes.  Each one can be used
+ * to route different frame types to various inbound queues.  We send broadcast/
+ * multicast/error frames to the default queue for slow handling,
+ * and CAM hit/RSS frames to the fast handling queues.
+ */
+static int ql_set_routing_reg(struct ql_adapter *qdev, u32 index, u32 mask,
+			      int enable)
+{
+	int status;
+	u32 value = 0;
+
+	status = ql_sem_spinlock(qdev, SEM_RT_IDX_MASK);
+	if (status)
+		return status;
+
+	QPRINTK(qdev, IFUP, DEBUG,
+		"%s %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s mask %s the routing reg.\n",
+		(enable ? "Adding" : "Removing"),
+		((index == RT_IDX_ALL_ERR_SLOT) ? "MAC ERROR/ALL ERROR" : ""),
+		((index == RT_IDX_IP_CSUM_ERR_SLOT) ? "IP CSUM ERROR" : ""),
+		((index ==
+		  RT_IDX_TCP_UDP_CSUM_ERR_SLOT) ? "TCP/UDP CSUM ERROR" : ""),
+		((index == RT_IDX_BCAST_SLOT) ? "BROADCAST" : ""),
+		((index == RT_IDX_MCAST_MATCH_SLOT) ? "MULTICAST MATCH" : ""),
+		((index == RT_IDX_ALLMULTI_SLOT) ? "ALL MULTICAST MATCH" : ""),
+		((index == RT_IDX_UNUSED6_SLOT) ? "UNUSED6" : ""),
+		((index == RT_IDX_UNUSED7_SLOT) ? "UNUSED7" : ""),
+		((index == RT_IDX_RSS_MATCH_SLOT) ? "RSS ALL/IPV4 MATCH" : ""),
+		((index == RT_IDX_RSS_IPV6_SLOT) ? "RSS IPV6" : ""),
+		((index == RT_IDX_RSS_TCP4_SLOT) ? "RSS TCP4" : ""),
+		((index == RT_IDX_RSS_TCP6_SLOT) ? "RSS TCP6" : ""),
+		((index == RT_IDX_CAM_HIT_SLOT) ? "CAM HIT" : ""),
+		((index == RT_IDX_UNUSED013) ? "UNUSED13" : ""),
+		((index == RT_IDX_UNUSED014) ? "UNUSED14" : ""),
+		((index == RT_IDX_PROMISCUOUS_SLOT) ? "PROMISCUOUS" : ""),
+		(enable ? "to" : "from"));
+
+	switch (mask) {
+	case RT_IDX_CAM_HIT:
+		{
+			value = RT_IDX_DST_CAM_Q |	/* dest */
+			    RT_IDX_TYPE_NICQ |	/* type */
+			    (RT_IDX_CAM_HIT_SLOT << RT_IDX_IDX_SHIFT);/* index */
+			break;
+		}
+	case RT_IDX_VALID:	/* Promiscuous Mode frames. */
+		{
+			value = RT_IDX_DST_DFLT_Q |	/* dest */
+			    RT_IDX_TYPE_NICQ |	/* type */
+			    (RT_IDX_PROMISCUOUS_SLOT << RT_IDX_IDX_SHIFT);/* index */
+			break;
+		}
+	case RT_IDX_ERR:	/* Pass up MAC,IP,TCP/UDP error frames. */
+		{
+			value = RT_IDX_DST_DFLT_Q |	/* dest */
+			    RT_IDX_TYPE_NICQ |	/* type */
+			    (RT_IDX_ALL_ERR_SLOT << RT_IDX_IDX_SHIFT);/* index */
+			break;
+		}
+	case RT_IDX_BCAST:	/* Pass up Broadcast frames to default Q. */
+		{
+			value = RT_IDX_DST_DFLT_Q |	/* dest */
+			    RT_IDX_TYPE_NICQ |	/* type */
+			    (RT_IDX_BCAST_SLOT << RT_IDX_IDX_SHIFT);/* index */
+			break;
+		}
+	case RT_IDX_MCAST:	/* Pass up All Multicast frames. */
+		{
+			value = RT_IDX_DST_CAM_Q |	/* dest */
+			    RT_IDX_TYPE_NICQ |	/* type */
+			    (RT_IDX_ALLMULTI_SLOT << RT_IDX_IDX_SHIFT);/* index */
+			break;
+		}
+	case RT_IDX_MCAST_MATCH:	/* Pass up matched Multicast frames. */
+		{
+			value = RT_IDX_DST_CAM_Q |	/* dest */
+			    RT_IDX_TYPE_NICQ |	/* type */
+			    (RT_IDX_MCAST_MATCH_SLOT << RT_IDX_IDX_SHIFT);/* index */
+			break;
+		}
+	case RT_IDX_RSS_MATCH:	/* Pass up matched RSS frames. */
+		{
+			value = RT_IDX_DST_RSS |	/* dest */
+			    RT_IDX_TYPE_NICQ |	/* type */
+			    (RT_IDX_RSS_MATCH_SLOT << RT_IDX_IDX_SHIFT);/* index */
+			break;
+		}
+	case 0:		/* Clear the E-bit on an entry. */
+		{
+			value = RT_IDX_DST_DFLT_Q |	/* dest */
+			    RT_IDX_TYPE_NICQ |	/* type */
+			    (index << RT_IDX_IDX_SHIFT);/* index */
+			break;
+		}
+	default:
+		QPRINTK(qdev, IFUP, ERR, "Mask type %d not yet supported.\n",
+			mask);
+		status = -EPERM;
+		goto exit;
+	}
+
+	if (value) {
+		status = ql_wait_reg_rdy(qdev, RT_IDX, RT_IDX_MW, 0);
+		if (status)
+			goto exit;
+		value |= (enable ? RT_IDX_E : 0);
+		ql_write32(qdev, RT_IDX, value);
+		ql_write32(qdev, RT_DATA, enable ? mask : 0);
+	}
+exit:
+	ql_sem_unlock(qdev, SEM_RT_IDX_MASK);
+	return status;
+}
+
+static void ql_enable_interrupts(struct ql_adapter *qdev)
+{
+	ql_write32(qdev, INTR_EN, (INTR_EN_EI << 16) | INTR_EN_EI);
+}
+
+static void ql_disable_interrupts(struct ql_adapter *qdev)
+{
+	ql_write32(qdev, INTR_EN, (INTR_EN_EI << 16));
+}
+
+/* If we're running with multiple MSI-X vectors then we enable on the fly.
+ * Otherwise, we may have multiple outstanding workers and don't want to
+ * enable until the last one finishes. In this case, the irq_cnt gets
+ * incremented everytime we queue a worker and decremented everytime
+ * a worker finishes.  Once it hits zero we enable the interrupt.
+ */
+void ql_enable_completion_interrupt(struct ql_adapter *qdev, u32 intr)
+{
+	if (likely(test_bit(QL_MSIX_ENABLED, &qdev->flags)))
+		ql_write32(qdev, INTR_EN,
+			   qdev->intr_context[intr].intr_en_mask);
+	else {
+		if (qdev->legacy_check)
+			spin_lock(&qdev->legacy_lock);
+		if (atomic_dec_and_test(&qdev->intr_context[intr].irq_cnt)) {
+			QPRINTK(qdev, INTR, ERR, "Enabling interrupt %d.\n",
+				intr);
+			ql_write32(qdev, INTR_EN,
+				   qdev->intr_context[intr].intr_en_mask);
+		} else {
+			QPRINTK(qdev, INTR, ERR,
+				"Skip enable, other queue(s) are active.\n");
+		}
+		if (qdev->legacy_check)
+			spin_unlock(&qdev->legacy_lock);
+	}
+}
+
+static u32 ql_disable_completion_interrupt(struct ql_adapter *qdev, u32 intr)
+{
+	u32 var = 0;
+
+	if (likely(test_bit(QL_MSIX_ENABLED, &qdev->flags)))
+		goto exit;
+	else if (!atomic_read(&qdev->intr_context[intr].irq_cnt)) {
+		ql_write32(qdev, INTR_EN,
+			   qdev->intr_context[intr].intr_dis_mask);
+		var = ql_read32(qdev, STS);
+	}
+	atomic_inc(&qdev->intr_context[intr].irq_cnt);
+exit:
+	return var;
+}
+
+static void ql_enable_all_completion_interrupts(struct ql_adapter *qdev)
+{
+	int i;
+	for (i = 0; i < qdev->intr_count; i++) {
+		/* The enable call does a atomic_dec_and_test
+		 * and enables only if the result is zero.
+		 * So we precharge it here.
+		 */
+		atomic_set(&qdev->intr_context[i].irq_cnt, 1);
+		ql_enable_completion_interrupt(qdev, i);
+	}
+
+}
+
+int ql_read_flash_word(struct ql_adapter *qdev, int offset, u32 *data)
+{
+	int status = 0;
+	/* wait for reg to come ready */
+	status = ql_wait_reg_rdy(qdev,
+			FLASH_ADDR, FLASH_ADDR_RDY, FLASH_ADDR_ERR);
+	if (status)
+		goto exit;
+	/* set up for reg read */
+	ql_write32(qdev, FLASH_ADDR, FLASH_ADDR_R | offset);
+	/* wait for reg to come ready */
+	status = ql_wait_reg_rdy(qdev,
+			FLASH_ADDR, FLASH_ADDR_RDY, FLASH_ADDR_ERR);
+	if (status)
+		goto exit;
+	/* get the data */
+	*data = ql_read32(qdev, FLASH_DATA);
+exit:
+	return status;
+}
+
+static int ql_get_flash_params(struct ql_adapter *qdev)
+{
+	int i;
+	int status;
+	u32 *p = (u32 *)&qdev->flash;
+
+	if (ql_sem_spinlock(qdev, SEM_FLASH_MASK))
+		return -ETIMEDOUT;
+
+	for (i = 0; i < sizeof(qdev->flash) / sizeof(u32); i++, p++) {
+		status = ql_read_flash_word(qdev, i, p);
+		if (status) {
+			QPRINTK(qdev, IFUP, ERR, "Error reading flash.\n");
+			goto exit;
+		}
+
+	}
+exit:
+	ql_sem_unlock(qdev, SEM_FLASH_MASK);
+	return status;
+}
+
+/* xgmac register are located behind the xgmac_addr and xgmac_data
+ * register pair.  Each read/write requires us to wait for the ready
+ * bit before reading/writing the data.
+ */
+static int ql_write_xgmac_reg(struct ql_adapter *qdev, u32 reg, u32 data)
+{
+	int status;
+	/* wait for reg to come ready */
+	status = ql_wait_reg_rdy(qdev,
+			XGMAC_ADDR, XGMAC_ADDR_RDY, XGMAC_ADDR_XME);
+	if (status)
+		return status;
+	/* write the data to the data reg */
+	ql_write32(qdev, XGMAC_DATA, data);
+	/* trigger the write */
+	ql_write32(qdev, XGMAC_ADDR, reg);
+	return status;
+}
+
+/* xgmac register are located behind the xgmac_addr and xgmac_data
+ * register pair.  Each read/write requires us to wait for the ready
+ * bit before reading/writing the data.
+ */
+int ql_read_xgmac_reg(struct ql_adapter *qdev, u32 reg, u32 *data)
+{
+	int status = 0;
+	/* wait for reg to come ready */
+	status = ql_wait_reg_rdy(qdev,
+			XGMAC_ADDR, XGMAC_ADDR_RDY, XGMAC_ADDR_XME);
+	if (status)
+		goto exit;
+	/* set up for reg read */
+	ql_write32(qdev, XGMAC_ADDR, reg | XGMAC_ADDR_R);
+	/* wait for reg to come ready */
+	status = ql_wait_reg_rdy(qdev,
+			XGMAC_ADDR, XGMAC_ADDR_RDY, XGMAC_ADDR_XME);
+	if (status)
+		goto exit;
+	/* get the data */
+	*data = ql_read32(qdev, XGMAC_DATA);
+exit:
+	return status;
+}
+
+/* This is used for reading the 64-bit statistics regs. */
+int ql_read_xgmac_reg64(struct ql_adapter *qdev, u32 reg, u64 *data)
+{
+	int status = 0;
+	u32 hi = 0;
+	u32 lo = 0;
+
+	status = ql_read_xgmac_reg(qdev, reg, &lo);
+	if (status)
+		goto exit;
+
+	status = ql_read_xgmac_reg(qdev, reg + 4, &hi);
+	if (status)
+		goto exit;
+
+	*data = (u64) lo | ((u64) hi << 32);
+
+exit:
+	return status;
+}
+
+/* Take the MAC Core out of reset.
+ * Enable statistics counting.
+ * Take the transmitter/receiver out of reset.
+ * This functionality may be done in the MPI firmware at a
+ * later date.
+ */
+static int ql_port_initialize(struct ql_adapter *qdev)
+{
+	int status = 0;
+	u32 data;
+
+	if (ql_sem_trylock(qdev, qdev->xg_sem_mask)) {
+		/* Another function has the semaphore, so
+		 * wait for the port init bit to come ready.
+		 */
+		QPRINTK(qdev, LINK, INFO,
+			"Another function has the semaphore, so wait for the port init bit to come ready.\n");
+		status = ql_wait_reg_rdy(qdev, STS, qdev->port_init, 0);
+		if (status) {
+			QPRINTK(qdev, LINK, CRIT,
+				"Port initialize timed out.\n");
+		}
+		return status;
+	}
+
+	QPRINTK(qdev, LINK, INFO, "Got xgmac semaphore!.\n");
+	/* Set the core reset. */
+	status = ql_read_xgmac_reg(qdev, GLOBAL_CFG, &data);
+	if (status)
+		goto end;
+	data |= GLOBAL_CFG_RESET;
+	status = ql_write_xgmac_reg(qdev, GLOBAL_CFG, data);
+	if (status)
+		goto end;
+
+	/* Clear the core reset and turn on jumbo for receiver. */
+	data &= ~GLOBAL_CFG_RESET;	/* Clear core reset. */
+	data |= GLOBAL_CFG_JUMBO;	/* Turn on jumbo. */
+	data |= GLOBAL_CFG_TX_STAT_EN;
+	data |= GLOBAL_CFG_RX_STAT_EN;
+	status = ql_write_xgmac_reg(qdev, GLOBAL_CFG, data);
+	if (status)
+		goto end;
+
+	/* Enable transmitter, and clear it's reset. */
+	status = ql_read_xgmac_reg(qdev, TX_CFG, &data);
+	if (status)
+		goto end;
+	data &= ~TX_CFG_RESET;	/* Clear the TX MAC reset. */
+	data |= TX_CFG_EN;	/* Enable the transmitter. */
+	status = ql_write_xgmac_reg(qdev, TX_CFG, data);
+	if (status)
+		goto end;
+
+	/* Enable receiver and clear it's reset. */
+	status = ql_read_xgmac_reg(qdev, RX_CFG, &data);
+	if (status)
+		goto end;
+	data &= ~RX_CFG_RESET;	/* Clear the RX MAC reset. */
+	data |= RX_CFG_EN;	/* Enable the receiver. */
+	status = ql_write_xgmac_reg(qdev, RX_CFG, data);
+	if (status)
+		goto end;
+
+	/* Turn on jumbo. */
+	status =
+	    ql_write_xgmac_reg(qdev, MAC_TX_PARAMS, MAC_TX_PARAMS_JUMBO | (0x2580 << 16));
+	if (status)
+		goto end;
+	status =
+	    ql_write_xgmac_reg(qdev, MAC_RX_PARAMS, 0x2580);
+	if (status)
+		goto end;
+
+	/* Signal to the world that the port is enabled.        */
+	ql_write32(qdev, STS, ((qdev->port_init << 16) | qdev->port_init));
+end:
+	ql_sem_unlock(qdev, qdev->xg_sem_mask);
+	return status;
+}
+
+/* Get the next large buffer. */
+struct bq_desc *ql_get_curr_lbuf(struct rx_ring *rx_ring)
+{
+	struct bq_desc *lbq_desc = &rx_ring->lbq[rx_ring->lbq_curr_idx];
+	rx_ring->lbq_curr_idx++;
+	if (rx_ring->lbq_curr_idx == rx_ring->lbq_len)
+		rx_ring->lbq_curr_idx = 0;
+	rx_ring->lbq_free_cnt++;
+	return lbq_desc;
+}
+
+/* Get the next small buffer. */
+struct bq_desc *ql_get_curr_sbuf(struct rx_ring *rx_ring)
+{
+	struct bq_desc *sbq_desc = &rx_ring->sbq[rx_ring->sbq_curr_idx];
+	rx_ring->sbq_curr_idx++;
+	if (rx_ring->sbq_curr_idx == rx_ring->sbq_len)
+		rx_ring->sbq_curr_idx = 0;
+	rx_ring->sbq_free_cnt++;
+	return sbq_desc;
+}
+
+/* Update an rx ring index. */
+static void ql_update_cq(struct rx_ring *rx_ring)
+{
+	rx_ring->cnsmr_idx++;
+	rx_ring->curr_entry++;
+	if (unlikely(rx_ring->cnsmr_idx == rx_ring->cq_len)) {
+		rx_ring->cnsmr_idx = 0;
+		rx_ring->curr_entry = rx_ring->cq_base;
+	}
+}
+
+static void ql_write_cq_idx(struct rx_ring *rx_ring)
+{
+	ql_write_db_reg(rx_ring->cnsmr_idx, rx_ring->cnsmr_idx_db_reg);
+}
+
+/* Process (refill) a large buffer queue. */
+static void ql_update_lbq(struct ql_adapter *qdev, struct rx_ring *rx_ring)
+{
+	int clean_idx = rx_ring->lbq_clean_idx;
+	struct bq_desc *lbq_desc;
+	struct bq_element *bq;
+	u64 map;
+	int i;
+
+	while (rx_ring->lbq_free_cnt > 16) {
+		for (i = 0; i < 16; i++) {
+			QPRINTK(qdev, RX_STATUS, DEBUG,
+				"lbq: try cleaning clean_idx = %d.\n",
+				clean_idx);
+			lbq_desc = &rx_ring->lbq[clean_idx];
+			bq = lbq_desc->bq;
+			if (lbq_desc->p.lbq_page == NULL) {
+				QPRINTK(qdev, RX_STATUS, DEBUG,
+					"lbq: getting new page for index %d.\n",
+					lbq_desc->index);
+				lbq_desc->p.lbq_page = alloc_page(GFP_ATOMIC);
+				if (lbq_desc->p.lbq_page == NULL) {
+					QPRINTK(qdev, RX_STATUS, ERR,
+						"Couldn't get a page.\n");
+					return;
+				}
+				map = pci_map_page(qdev->pdev,
+						   lbq_desc->p.lbq_page,
+						   0, PAGE_SIZE,
+						   PCI_DMA_FROMDEVICE);
+				if (pci_dma_mapping_error(qdev->pdev, map)) {
+					QPRINTK(qdev, RX_STATUS, ERR,
+						"PCI mapping failed.\n");
+					return;
+				}
+				pci_unmap_addr_set(lbq_desc, mapaddr, map);
+				pci_unmap_len_set(lbq_desc, maplen, PAGE_SIZE);
+				bq->addr_lo =	/*lbq_desc->addr_lo = */
+				    cpu_to_le32(map);
+				bq->addr_hi =	/*lbq_desc->addr_hi = */
+				    cpu_to_le32(map >> 32);
+			}
+			clean_idx++;
+			if (clean_idx == rx_ring->lbq_len)
+				clean_idx = 0;
+		}
+
+		rx_ring->lbq_clean_idx = clean_idx;
+		rx_ring->lbq_prod_idx += 16;
+		if (rx_ring->lbq_prod_idx == rx_ring->lbq_len)
+			rx_ring->lbq_prod_idx = 0;
+		QPRINTK(qdev, RX_STATUS, DEBUG,
+			"lbq: updating prod idx = %d.\n",
+			rx_ring->lbq_prod_idx);
+		ql_write_db_reg(rx_ring->lbq_prod_idx,
+				rx_ring->lbq_prod_idx_db_reg);
+		rx_ring->lbq_free_cnt -= 16;
+	}
+}
+
+/* Process (refill) a small buffer queue. */
+static void ql_update_sbq(struct ql_adapter *qdev, struct rx_ring *rx_ring)
+{
+	int clean_idx = rx_ring->sbq_clean_idx;
+	struct bq_desc *sbq_desc;
+	struct bq_element *bq;
+	u64 map;
+	int i;
+
+	while (rx_ring->sbq_free_cnt > 16) {
+		for (i = 0; i < 16; i++) {
+			sbq_desc = &rx_ring->sbq[clean_idx];
+			QPRINTK(qdev, RX_STATUS, DEBUG,
+				"sbq: try cleaning clean_idx = %d.\n",
+				clean_idx);
+			bq = sbq_desc->bq;
+			if (sbq_desc->p.skb == NULL) {
+				QPRINTK(qdev, RX_STATUS, DEBUG,
+					"sbq: getting new skb for index %d.\n",
+					sbq_desc->index);
+				sbq_desc->p.skb =
+				    netdev_alloc_skb(qdev->ndev,
+						     rx_ring->sbq_buf_size);
+				if (sbq_desc->p.skb == NULL) {
+					QPRINTK(qdev, PROBE, ERR,
+						"Couldn't get an skb.\n");
+					rx_ring->sbq_clean_idx = clean_idx;
+					return;
+				}
+				skb_reserve(sbq_desc->p.skb, QLGE_SB_PAD);
+				map = pci_map_single(qdev->pdev,
+						     sbq_desc->p.skb->data,
+						     rx_ring->sbq_buf_size /
+						     2, PCI_DMA_FROMDEVICE);
+				pci_unmap_addr_set(sbq_desc, mapaddr, map);
+				pci_unmap_len_set(sbq_desc, maplen,
+						  rx_ring->sbq_buf_size / 2);
+				bq->addr_lo = cpu_to_le32(map);
+				bq->addr_hi = cpu_to_le32(map >> 32);
+			}
+
+			clean_idx++;
+			if (clean_idx == rx_ring->sbq_len)
+				clean_idx = 0;
+		}
+		rx_ring->sbq_clean_idx = clean_idx;
+		rx_ring->sbq_prod_idx += 16;
+		if (rx_ring->sbq_prod_idx == rx_ring->sbq_len)
+			rx_ring->sbq_prod_idx = 0;
+		QPRINTK(qdev, RX_STATUS, DEBUG,
+			"sbq: updating prod idx = %d.\n",
+			rx_ring->sbq_prod_idx);
+		ql_write_db_reg(rx_ring->sbq_prod_idx,
+				rx_ring->sbq_prod_idx_db_reg);
+
+		rx_ring->sbq_free_cnt -= 16;
+	}
+}
+
+static void ql_update_buffer_queues(struct ql_adapter *qdev,
+				    struct rx_ring *rx_ring)
+{
+	ql_update_sbq(qdev, rx_ring);
+	ql_update_lbq(qdev, rx_ring);
+}
+
+/* Unmaps tx buffers.  Can be called from send() if a pci mapping
+ * fails at some stage, or from the interrupt when a tx completes.
+ */
+static void ql_unmap_send(struct ql_adapter *qdev,
+			  struct tx_ring_desc *tx_ring_desc, int mapped)
+{
+	int i;
+	for (i = 0; i < mapped; i++) {
+		if (i == 0 || (i == 7 && mapped > 7)) {
+			/*
+			 * Unmap the skb->data area, or the
+			 * external sglist (AKA the Outbound
+			 * Address List (OAL)).
+			 * If its the zeroeth element, then it's
+			 * the skb->data area.  If it's the 7th
+			 * element and there is more than 6 frags,
+			 * then its an OAL.
+			 */
+			if (i == 7) {
+				QPRINTK(qdev, TX_DONE, DEBUG,
+					"unmapping OAL area.\n");
+			}
+			pci_unmap_single(qdev->pdev,
+					 pci_unmap_addr(&tx_ring_desc->map[i],
+							mapaddr),
+					 pci_unmap_len(&tx_ring_desc->map[i],
+						       maplen),
+					 PCI_DMA_TODEVICE);
+		} else {
+			QPRINTK(qdev, TX_DONE, DEBUG, "unmapping frag %d.\n",
+				i);
+			pci_unmap_page(qdev->pdev,
+				       pci_unmap_addr(&tx_ring_desc->map[i],
+						      mapaddr),
+				       pci_unmap_len(&tx_ring_desc->map[i],
+						     maplen), PCI_DMA_TODEVICE);
+		}
+	}
+
+}
+
+/* Map the buffers for this transmit.  This will return
+ * NETDEV_TX_BUSY or NETDEV_TX_OK based on success.
+ */
+static int ql_map_send(struct ql_adapter *qdev,
+		       struct ob_mac_iocb_req *mac_iocb_ptr,
+		       struct sk_buff *skb, struct tx_ring_desc *tx_ring_desc)
+{
+	int len = skb_headlen(skb);
+	dma_addr_t map;
+	int frag_idx, err, map_idx = 0;
+	struct tx_buf_desc *tbd = mac_iocb_ptr->tbd;
+	int frag_cnt = skb_shinfo(skb)->nr_frags;
+
+	if (frag_cnt) {
+		QPRINTK(qdev, TX_QUEUED, DEBUG, "frag_cnt = %d.\n", frag_cnt);
+	}
+	/*
+	 * Map the skb buffer first.
+	 */
+	map = pci_map_single(qdev->pdev, skb->data, len, PCI_DMA_TODEVICE);
+
+	err = pci_dma_mapping_error(qdev->pdev, map);
+	if (err) {
+		QPRINTK(qdev, TX_QUEUED, ERR,
+			"PCI mapping failed with error: %d\n", err);
+
+		return NETDEV_TX_BUSY;
+	}
+
+	tbd->len = cpu_to_le32(len);
+	tbd->addr = cpu_to_le64(map);
+	pci_unmap_addr_set(&tx_ring_desc->map[map_idx], mapaddr, map);
+	pci_unmap_len_set(&tx_ring_desc->map[map_idx], maplen, len);
+	map_idx++;
+
+	/*
+	 * This loop fills the remainder of the 8 address descriptors
+	 * in the IOCB.  If there are more than 7 fragments, then the
+	 * eighth address desc will point to an external list (OAL).
+	 * When this happens, the remainder of the frags will be stored
+	 * in this list.
+	 */
+	for (frag_idx = 0; frag_idx < frag_cnt; frag_idx++, map_idx++) {
+		skb_frag_t *frag = &skb_shinfo(skb)->frags[frag_idx];
+		tbd++;
+		if (frag_idx == 6 && frag_cnt > 7) {
+			/* Let's tack on an sglist.
+			 * Our control block will now
+			 * look like this:
+			 * iocb->seg[0] = skb->data
+			 * iocb->seg[1] = frag[0]
+			 * iocb->seg[2] = frag[1]
+			 * iocb->seg[3] = frag[2]
+			 * iocb->seg[4] = frag[3]
+			 * iocb->seg[5] = frag[4]
+			 * iocb->seg[6] = frag[5]
+			 * iocb->seg[7] = ptr to OAL (external sglist)
+			 * oal->seg[0] = frag[6]
+			 * oal->seg[1] = frag[7]
+			 * oal->seg[2] = frag[8]
+			 * oal->seg[3] = frag[9]
+			 * oal->seg[4] = frag[10]
+			 *      etc...
+			 */
+			/* Tack on the OAL in the eighth segment of IOCB. */
+			map = pci_map_single(qdev->pdev, &tx_ring_desc->oal,
+					     sizeof(struct oal),
+					     PCI_DMA_TODEVICE);
+			err = pci_dma_mapping_error(qdev->pdev, map);
+			if (err) {
+				QPRINTK(qdev, TX_QUEUED, ERR,
+					"PCI mapping outbound address list with error: %d\n",
+					err);
+				goto map_error;
+			}
+
+			tbd->addr = cpu_to_le64(map);
+			/*
+			 * The length is the number of fragments
+			 * that remain to be mapped times the length
+			 * of our sglist (OAL).
+			 */
+			tbd->len =
+			    cpu_to_le32((sizeof(struct tx_buf_desc) *
+					 (frag_cnt - frag_idx)) | TX_DESC_C);
+			pci_unmap_addr_set(&tx_ring_desc->map[map_idx], mapaddr,
+					   map);
+			pci_unmap_len_set(&tx_ring_desc->map[map_idx], maplen,
+					  sizeof(struct oal));
+			tbd = (struct tx_buf_desc *)&tx_ring_desc->oal;
+			map_idx++;
+		}
+
+		map =
+		    pci_map_page(qdev->pdev, frag->page,
+				 frag->page_offset, frag->size,
+				 PCI_DMA_TODEVICE);
+
+		err = pci_dma_mapping_error(qdev->pdev, map);
+		if (err) {
+			QPRINTK(qdev, TX_QUEUED, ERR,
+				"PCI mapping frags failed with error: %d.\n",
+				err);
+			goto map_error;
+		}
+
+		tbd->addr = cpu_to_le64(map);
+		tbd->len = cpu_to_le32(frag->size);
+		pci_unmap_addr_set(&tx_ring_desc->map[map_idx], mapaddr, map);
+		pci_unmap_len_set(&tx_ring_desc->map[map_idx], maplen,
+				  frag->size);
+
+	}
+	/* Save the number of segments we've mapped. */
+	tx_ring_desc->map_cnt = map_idx;
+	/* Terminate the last segment. */
+	tbd->len = cpu_to_le32(le32_to_cpu(tbd->len) | TX_DESC_E);
+	return NETDEV_TX_OK;
+
+map_error:
+	/*
+	 * If the first frag mapping failed, then i will be zero.
+	 * This causes the unmap of the skb->data area.  Otherwise
+	 * we pass in the number of frags that mapped successfully
+	 * so they can be umapped.
+	 */
+	ql_unmap_send(qdev, tx_ring_desc, map_idx);
+	return NETDEV_TX_BUSY;
+}
+
+void ql_realign_skb(struct sk_buff *skb, int len)
+{
+	void *temp_addr = skb->data;
+
+	/* Undo the skb_reserve(skb,32) we did before
+	 * giving to hardware, and realign data on
+	 * a 2-byte boundary.
+	 */
+	skb->data -= QLGE_SB_PAD - NET_IP_ALIGN;
+	skb->tail -= QLGE_SB_PAD - NET_IP_ALIGN;
+	skb_copy_to_linear_data(skb, temp_addr,
+		(unsigned int)len);
+}
+
+/*
+ * This function builds an skb for the given inbound
+ * completion.  It will be rewritten for readability in the near
+ * future, but for not it works well.
+ */
+static struct sk_buff *ql_build_rx_skb(struct ql_adapter *qdev,
+				       struct rx_ring *rx_ring,
+				       struct ib_mac_iocb_rsp *ib_mac_rsp)
+{
+	struct bq_desc *lbq_desc;
+	struct bq_desc *sbq_desc;
+	struct sk_buff *skb = NULL;
+	u32 length = le32_to_cpu(ib_mac_rsp->data_len);
+       u32 hdr_len = le32_to_cpu(ib_mac_rsp->hdr_len);
+
+	/*
+	 * Handle the header buffer if present.
+	 */
+	if (ib_mac_rsp->flags4 & IB_MAC_IOCB_RSP_HV &&
+	    ib_mac_rsp->flags4 & IB_MAC_IOCB_RSP_HS) {
+		QPRINTK(qdev, RX_STATUS, DEBUG, "Header of %d bytes in small buffer.\n", hdr_len);
+		/*
+		 * Headers fit nicely into a small buffer.
+		 */
+		sbq_desc = ql_get_curr_sbuf(rx_ring);
+		pci_unmap_single(qdev->pdev,
+				pci_unmap_addr(sbq_desc, mapaddr),
+				pci_unmap_len(sbq_desc, maplen),
+				PCI_DMA_FROMDEVICE);
+		skb = sbq_desc->p.skb;
+		ql_realign_skb(skb, hdr_len);
+		skb_put(skb, hdr_len);
+		sbq_desc->p.skb = NULL;
+	}
+
+	/*
+	 * Handle the data buffer(s).
+	 */
+	if (unlikely(!length)) {	/* Is there data too? */
+		QPRINTK(qdev, RX_STATUS, DEBUG,
+			"No Data buffer in this packet.\n");
+		return skb;
+	}
+
+	if (ib_mac_rsp->flags3 & IB_MAC_IOCB_RSP_DS) {
+		if (ib_mac_rsp->flags4 & IB_MAC_IOCB_RSP_HS) {
+			QPRINTK(qdev, RX_STATUS, DEBUG,
+				"Headers in small, data of %d bytes in small, combine them.\n", length);
+			/*
+			 * Data is less than small buffer size so it's
+			 * stuffed in a small buffer.
+			 * For this case we append the data
+			 * from the "data" small buffer to the "header" small
+			 * buffer.
+			 */
+			sbq_desc = ql_get_curr_sbuf(rx_ring);
+			pci_dma_sync_single_for_cpu(qdev->pdev,
+						    pci_unmap_addr
+						    (sbq_desc, mapaddr),
+						    pci_unmap_len
+						    (sbq_desc, maplen),
+						    PCI_DMA_FROMDEVICE);
+			memcpy(skb_put(skb, length),
+			       sbq_desc->p.skb->data, length);
+			pci_dma_sync_single_for_device(qdev->pdev,
+						       pci_unmap_addr
+						       (sbq_desc,
+							mapaddr),
+						       pci_unmap_len
+						       (sbq_desc,
+							maplen),
+						       PCI_DMA_FROMDEVICE);
+		} else {
+			QPRINTK(qdev, RX_STATUS, DEBUG,
+				"%d bytes in a single small buffer.\n", length);
+			sbq_desc = ql_get_curr_sbuf(rx_ring);
+			skb = sbq_desc->p.skb;
+			ql_realign_skb(skb, length);
+			skb_put(skb, length);
+			pci_unmap_single(qdev->pdev,
+					 pci_unmap_addr(sbq_desc,
+							mapaddr),
+					 pci_unmap_len(sbq_desc,
+						       maplen),
+					 PCI_DMA_FROMDEVICE);
+			sbq_desc->p.skb = NULL;
+		}
+	} else if (ib_mac_rsp->flags3 & IB_MAC_IOCB_RSP_DL) {
+		if (ib_mac_rsp->flags4 & IB_MAC_IOCB_RSP_HS) {
+			QPRINTK(qdev, RX_STATUS, DEBUG,
+				"Header in small, %d bytes in large. Chain large to small!\n", length);
+			/*
+			 * The data is in a single large buffer.  We
+			 * chain it to the header buffer's skb and let
+			 * it rip.
+			 */
+			lbq_desc = ql_get_curr_lbuf(rx_ring);
+			pci_unmap_page(qdev->pdev,
+				       pci_unmap_addr(lbq_desc,
+						      mapaddr),
+				       pci_unmap_len(lbq_desc, maplen),
+				       PCI_DMA_FROMDEVICE);
+			QPRINTK(qdev, RX_STATUS, DEBUG,
+				"Chaining page to skb.\n");
+			skb_fill_page_desc(skb, 0, lbq_desc->p.lbq_page,
+					   0, length);
+			skb->len += length;
+			skb->data_len += length;
+			skb->truesize += length;
+			lbq_desc->p.lbq_page = NULL;
+		} else {
+			/*
+			 * The headers and data are in a single large buffer. We
+			 * copy it to a new skb and let it go. This can happen with
+			 * jumbo mtu on a non-TCP/UDP frame.
+			 */
+			lbq_desc = ql_get_curr_lbuf(rx_ring);
+			skb = netdev_alloc_skb(qdev->ndev, length);
+			if (skb == NULL) {
+				QPRINTK(qdev, PROBE, DEBUG,
+					"No skb available, drop the packet.\n");
+				return NULL;
+			}
+			skb_reserve(skb, NET_IP_ALIGN);
+			QPRINTK(qdev, RX_STATUS, DEBUG,
+				"%d bytes of headers and data in large. Chain page to new skb and pull tail.\n", length);
+			skb_fill_page_desc(skb, 0, lbq_desc->p.lbq_page,
+					   0, length);
+			skb->len += length;
+			skb->data_len += length;
+			skb->truesize += length;
+			length -= length;
+			lbq_desc->p.lbq_page = NULL;
+			__pskb_pull_tail(skb,
+				(ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_V) ?
+				VLAN_ETH_HLEN : ETH_HLEN);
+		}
+	} else {
+		/*
+		 * The data is in a chain of large buffers
+		 * pointed to by a small buffer.  We loop
+		 * thru and chain them to the our small header
+		 * buffer's skb.
+		 * frags:  There are 18 max frags and our small
+		 *         buffer will hold 32 of them. The thing is,
+		 *         we'll use 3 max for our 9000 byte jumbo
+		 *         frames.  If the MTU goes up we could
+		 *          eventually be in trouble.
+		 */
+		int size, offset, i = 0;
+		struct bq_element *bq, bq_array[8];
+		sbq_desc = ql_get_curr_sbuf(rx_ring);
+		pci_unmap_single(qdev->pdev,
+				 pci_unmap_addr(sbq_desc, mapaddr),
+				 pci_unmap_len(sbq_desc, maplen),
+				 PCI_DMA_FROMDEVICE);
+		if (!(ib_mac_rsp->flags4 & IB_MAC_IOCB_RSP_HS)) {
+			/*
+			 * This is an non TCP/UDP IP frame, so
+			 * the headers aren't split into a small
+			 * buffer.  We have to use the small buffer
+			 * that contains our sg list as our skb to
+			 * send upstairs. Copy the sg list here to
+			 * a local buffer and use it to find the
+			 * pages to chain.
+			 */
+			QPRINTK(qdev, RX_STATUS, DEBUG,
+				"%d bytes of headers & data in chain of large.\n", length);
+			skb = sbq_desc->p.skb;
+			bq = &bq_array[0];
+			memcpy(bq, skb->data, sizeof(bq_array));
+			sbq_desc->p.skb = NULL;
+			skb_reserve(skb, NET_IP_ALIGN);
+		} else {
+			QPRINTK(qdev, RX_STATUS, DEBUG,
+				"Headers in small, %d bytes of data in chain of large.\n", length);
+			bq = (struct bq_element *)sbq_desc->p.skb->data;
+		}
+		while (length > 0) {
+			lbq_desc = ql_get_curr_lbuf(rx_ring);
+			if ((bq->addr_lo & ~BQ_MASK) != lbq_desc->bq->addr_lo) {
+				QPRINTK(qdev, RX_STATUS, ERR,
+					"Panic!!! bad large buffer address, expected 0x%.08x, got 0x%.08x.\n",
+					lbq_desc->bq->addr_lo, bq->addr_lo);
+				return NULL;
+			}
+			pci_unmap_page(qdev->pdev,
+				       pci_unmap_addr(lbq_desc,
+						      mapaddr),
+				       pci_unmap_len(lbq_desc,
+						     maplen),
+				       PCI_DMA_FROMDEVICE);
+			size = (length < PAGE_SIZE) ? length : PAGE_SIZE;
+			offset = 0;
+
+			QPRINTK(qdev, RX_STATUS, DEBUG,
+				"Adding page %d to skb for %d bytes.\n",
+				i, size);
+			skb_fill_page_desc(skb, i, lbq_desc->p.lbq_page,
+					   offset, size);
+			skb->len += size;
+			skb->data_len += size;
+			skb->truesize += size;
+			length -= size;
+			lbq_desc->p.lbq_page = NULL;
+			bq++;
+			i++;
+		}
+		__pskb_pull_tail(skb, (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_V) ?
+				VLAN_ETH_HLEN : ETH_HLEN);
+	}
+	return skb;
+}
+
+/* Process an inbound completion from an rx ring. */
+static void ql_process_mac_rx_intr(struct ql_adapter *qdev,
+				   struct rx_ring *rx_ring,
+				   struct ib_mac_iocb_rsp *ib_mac_rsp)
+{
+	struct net_device *ndev = qdev->ndev;
+	struct sk_buff *skb = NULL;
+
+	QL_DUMP_IB_MAC_RSP(ib_mac_rsp);
+
+	skb = ql_build_rx_skb(qdev, rx_ring, ib_mac_rsp);
+	if (unlikely(!skb)) {
+		QPRINTK(qdev, RX_STATUS, DEBUG,
+			"No skb available, drop packet.\n");
+		return;
+	}
+
+	prefetch(skb->data);
+	skb->dev = ndev;
+	if (ib_mac_rsp->flags1 & IB_MAC_IOCB_RSP_M_MASK) {
+		QPRINTK(qdev, RX_STATUS, DEBUG, "%s%s%s Multicast.\n",
+			(ib_mac_rsp->flags1 & IB_MAC_IOCB_RSP_M_MASK) ==
+			IB_MAC_IOCB_RSP_M_HASH ? "Hash" : "",
+			(ib_mac_rsp->flags1 & IB_MAC_IOCB_RSP_M_MASK) ==
+			IB_MAC_IOCB_RSP_M_REG ? "Registered" : "",
+			(ib_mac_rsp->flags1 & IB_MAC_IOCB_RSP_M_MASK) ==
+			IB_MAC_IOCB_RSP_M_PROM ? "Promiscuous" : "");
+	}
+	if (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_P) {
+		QPRINTK(qdev, RX_STATUS, DEBUG, "Promiscuous Packet.\n");
+	}
+	if (ib_mac_rsp->flags1 & (IB_MAC_IOCB_RSP_IE | IB_MAC_IOCB_RSP_TE)) {
+		QPRINTK(qdev, RX_STATUS, ERR,
+			"Bad checksum for this %s packet.\n",
+			((ib_mac_rsp->
+			  flags2 & IB_MAC_IOCB_RSP_T) ? "TCP" : "UDP"));
+		skb->ip_summed = CHECKSUM_NONE;
+	} else if (qdev->rx_csum &&
+		   ((ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_T) ||
+		    ((ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_U) &&
+		     !(ib_mac_rsp->flags1 & IB_MAC_IOCB_RSP_NU)))) {
+		QPRINTK(qdev, RX_STATUS, DEBUG, "RX checksum done!\n");
+		skb->ip_summed = CHECKSUM_UNNECESSARY;
+	}
+	qdev->stats.rx_packets++;
+	qdev->stats.rx_bytes += skb->len;
+	skb->protocol = eth_type_trans(skb, ndev);
+	if (qdev->vlgrp && (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_V)) {
+		QPRINTK(qdev, RX_STATUS, DEBUG,
+			"Passing a VLAN packet upstream.\n");
+		vlan_hwaccel_rx(skb, qdev->vlgrp,
+				le16_to_cpu(ib_mac_rsp->vlan_id));
+	} else {
+		QPRINTK(qdev, RX_STATUS, DEBUG,
+			"Passing a normal packet upstream.\n");
+		netif_rx(skb);
+	}
+	ndev->last_rx = jiffies;
+}
+
+/* Process an outbound completion from an rx ring. */
+static void ql_process_mac_tx_intr(struct ql_adapter *qdev,
+				   struct ob_mac_iocb_rsp *mac_rsp)
+{
+	struct tx_ring *tx_ring;
+	struct tx_ring_desc *tx_ring_desc;
+
+	QL_DUMP_OB_MAC_RSP(mac_rsp);
+	tx_ring = &qdev->tx_ring[mac_rsp->txq_idx];
+	tx_ring_desc = &tx_ring->q[mac_rsp->tid];
+	ql_unmap_send(qdev, tx_ring_desc, tx_ring_desc->map_cnt);
+	qdev->stats.tx_bytes += tx_ring_desc->map_cnt;
+	qdev->stats.tx_packets++;
+	dev_kfree_skb(tx_ring_desc->skb);
+	tx_ring_desc->skb = NULL;
+
+	if (unlikely(mac_rsp->flags1 & (OB_MAC_IOCB_RSP_E |
+					OB_MAC_IOCB_RSP_S |
+					OB_MAC_IOCB_RSP_L |
+					OB_MAC_IOCB_RSP_P | OB_MAC_IOCB_RSP_B))) {
+		if (mac_rsp->flags1 & OB_MAC_IOCB_RSP_E) {
+			QPRINTK(qdev, TX_DONE, WARNING,
+				"Total descriptor length did not match transfer length.\n");
+		}
+		if (mac_rsp->flags1 & OB_MAC_IOCB_RSP_S) {
+			QPRINTK(qdev, TX_DONE, WARNING,
+				"Frame too short to be legal, not sent.\n");
+		}
+		if (mac_rsp->flags1 & OB_MAC_IOCB_RSP_L) {
+			QPRINTK(qdev, TX_DONE, WARNING,
+				"Frame too long, but sent anyway.\n");
+		}
+		if (mac_rsp->flags1 & OB_MAC_IOCB_RSP_B) {
+			QPRINTK(qdev, TX_DONE, WARNING,
+				"PCI backplane error. Frame not sent.\n");
+		}
+	}
+	atomic_inc(&tx_ring->tx_count);
+}
+
+/* Fire up a handler to reset the MPI processor. */
+void ql_queue_fw_error(struct ql_adapter *qdev)
+{
+	netif_stop_queue(qdev->ndev);
+	netif_carrier_off(qdev->ndev);
+	queue_delayed_work(qdev->workqueue, &qdev->mpi_reset_work, 0);
+}
+
+void ql_queue_asic_error(struct ql_adapter *qdev)
+{
+	netif_stop_queue(qdev->ndev);
+	netif_carrier_off(qdev->ndev);
+	ql_disable_interrupts(qdev);
+	queue_delayed_work(qdev->workqueue, &qdev->asic_reset_work, 0);
+}
+
+static void ql_process_chip_ae_intr(struct ql_adapter *qdev,
+				    struct ib_ae_iocb_rsp *ib_ae_rsp)
+{
+	switch (ib_ae_rsp->event) {
+	case MGMT_ERR_EVENT:
+		QPRINTK(qdev, RX_ERR, ERR,
+			"Management Processor Fatal Error.\n");
+		ql_queue_fw_error(qdev);
+		return;
+
+	case CAM_LOOKUP_ERR_EVENT:
+		QPRINTK(qdev, LINK, ERR,
+			"Multiple CAM hits lookup occurred.\n");
+		QPRINTK(qdev, DRV, ERR, "This event shouldn't occur.\n");
+		ql_queue_asic_error(qdev);
+		return;
+
+	case SOFT_ECC_ERROR_EVENT:
+		QPRINTK(qdev, RX_ERR, ERR, "Soft ECC error detected.\n");
+		ql_queue_asic_error(qdev);
+		break;
+
+	case PCI_ERR_ANON_BUF_RD:
+		QPRINTK(qdev, RX_ERR, ERR,
+			"PCI error occurred when reading anonymous buffers from rx_ring %d.\n",
+			ib_ae_rsp->q_id);
+		ql_queue_asic_error(qdev);
+		break;
+
+	default:
+		QPRINTK(qdev, DRV, ERR, "Unexpected event %d.\n",
+			ib_ae_rsp->event);
+		ql_queue_asic_error(qdev);
+		break;
+	}
+}
+
+static int ql_clean_outbound_rx_ring(struct rx_ring *rx_ring)
+{
+	struct ql_adapter *qdev = rx_ring->qdev;
+	u32 prod = ql_read_sh_reg(rx_ring->prod_idx_sh_reg);
+	struct ob_mac_iocb_rsp *net_rsp = NULL;
+	int count = 0;
+
+	/* While there are entries in the completion queue. */
+	while (prod != rx_ring->cnsmr_idx) {
+
+		QPRINTK(qdev, RX_STATUS, DEBUG,
+			"cq_id = %d, prod = %d, cnsmr = %d.\n.", rx_ring->cq_id,
+			prod, rx_ring->cnsmr_idx);
+
+		net_rsp = (struct ob_mac_iocb_rsp *)rx_ring->curr_entry;
+		rmb();
+		switch (net_rsp->opcode) {
+
+		case OPCODE_OB_MAC_TSO_IOCB:
+		case OPCODE_OB_MAC_IOCB:
+			ql_process_mac_tx_intr(qdev, net_rsp);
+			break;
+		default:
+			QPRINTK(qdev, RX_STATUS, DEBUG,
+				"Hit default case, not handled! dropping the packet, opcode = %x.\n",
+				net_rsp->opcode);
+		}
+		count++;
+		ql_update_cq(rx_ring);
+		prod = ql_read_sh_reg(rx_ring->prod_idx_sh_reg);
+	}
+	ql_write_cq_idx(rx_ring);
+	if (netif_queue_stopped(qdev->ndev) && net_rsp != NULL) {
+		struct tx_ring *tx_ring = &qdev->tx_ring[net_rsp->txq_idx];
+		if (atomic_read(&tx_ring->queue_stopped) &&
+		    (atomic_read(&tx_ring->tx_count) > (tx_ring->wq_len / 4)))
+			/*
+			 * The queue got stopped because the tx_ring was full.
+			 * Wake it up, because it's now at least 25% empty.
+			 */
+			netif_wake_queue(qdev->ndev);
+	}
+
+	return count;
+}
+
+static int ql_clean_inbound_rx_ring(struct rx_ring *rx_ring, int budget)
+{
+	struct ql_adapter *qdev = rx_ring->qdev;
+	u32 prod = ql_read_sh_reg(rx_ring->prod_idx_sh_reg);
+	struct ql_net_rsp_iocb *net_rsp;
+	int count = 0;
+
+	/* While there are entries in the completion queue. */
+	while (prod != rx_ring->cnsmr_idx) {
+
+		QPRINTK(qdev, RX_STATUS, DEBUG,
+			"cq_id = %d, prod = %d, cnsmr = %d.\n.", rx_ring->cq_id,
+			prod, rx_ring->cnsmr_idx);
+
+		net_rsp = rx_ring->curr_entry;
+		rmb();
+		switch (net_rsp->opcode) {
+		case OPCODE_IB_MAC_IOCB:
+			ql_process_mac_rx_intr(qdev, rx_ring,
+					       (struct ib_mac_iocb_rsp *)
+					       net_rsp);
+			break;
+
+		case OPCODE_IB_AE_IOCB:
+			ql_process_chip_ae_intr(qdev, (struct ib_ae_iocb_rsp *)
+						net_rsp);
+			break;
+		default:
+			{
+				QPRINTK(qdev, RX_STATUS, DEBUG,
+					"Hit default case, not handled! dropping the packet, opcode = %x.\n",
+					net_rsp->opcode);
+			}
+		}
+		count++;
+		ql_update_cq(rx_ring);
+		prod = ql_read_sh_reg(rx_ring->prod_idx_sh_reg);
+		if (count == budget)
+			break;
+	}
+	ql_update_buffer_queues(qdev, rx_ring);
+	ql_write_cq_idx(rx_ring);
+	return count;
+}
+
+static int ql_napi_poll_msix(struct napi_struct *napi, int budget)
+{
+	struct rx_ring *rx_ring = container_of(napi, struct rx_ring, napi);
+	struct ql_adapter *qdev = rx_ring->qdev;
+	int work_done = ql_clean_inbound_rx_ring(rx_ring, budget);
+
+	QPRINTK(qdev, RX_STATUS, DEBUG, "Enter, NAPI POLL cq_id = %d.\n",
+		rx_ring->cq_id);
+
+	if (work_done < budget) {
+		__netif_rx_complete(qdev->ndev, napi);
+		ql_enable_completion_interrupt(qdev, rx_ring->irq);
+	}
+	return work_done;
+}
+
+static void ql_vlan_rx_register(struct net_device *ndev, struct vlan_group *grp)
+{
+	struct ql_adapter *qdev = netdev_priv(ndev);
+
+	qdev->vlgrp = grp;
+	if (grp) {
+		QPRINTK(qdev, IFUP, DEBUG, "Turning on VLAN in NIC_RCV_CFG.\n");
+		ql_write32(qdev, NIC_RCV_CFG, NIC_RCV_CFG_VLAN_MASK |
+			   NIC_RCV_CFG_VLAN_MATCH_AND_NON);
+	} else {
+		QPRINTK(qdev, IFUP, DEBUG,
+			"Turning off VLAN in NIC_RCV_CFG.\n");
+		ql_write32(qdev, NIC_RCV_CFG, NIC_RCV_CFG_VLAN_MASK);
+	}
+}
+
+static void ql_vlan_rx_add_vid(struct net_device *ndev, u16 vid)
+{
+	struct ql_adapter *qdev = netdev_priv(ndev);
+	u32 enable_bit = MAC_ADDR_E;
+
+	spin_lock(&qdev->hw_lock);
+	if (ql_set_mac_addr_reg
+	    (qdev, (u8 *) &enable_bit, MAC_ADDR_TYPE_VLAN, vid)) {
+		QPRINTK(qdev, IFUP, ERR, "Failed to init vlan address.\n");
+	}
+	spin_unlock(&qdev->hw_lock);
+}
+
+static void ql_vlan_rx_kill_vid(struct net_device *ndev, u16 vid)
+{
+	struct ql_adapter *qdev = netdev_priv(ndev);
+	u32 enable_bit = 0;
+
+	spin_lock(&qdev->hw_lock);
+	if (ql_set_mac_addr_reg
+	    (qdev, (u8 *) &enable_bit, MAC_ADDR_TYPE_VLAN, vid)) {
+		QPRINTK(qdev, IFUP, ERR, "Failed to clear vlan address.\n");
+	}
+	spin_unlock(&qdev->hw_lock);
+
+}
+
+/* Worker thread to process a given rx_ring that is dedicated
+ * to outbound completions.
+ */
+static void ql_tx_clean(struct work_struct *work)
+{
+	struct rx_ring *rx_ring =
+	    container_of(work, struct rx_ring, rx_work.work);
+	ql_clean_outbound_rx_ring(rx_ring);
+	ql_enable_completion_interrupt(rx_ring->qdev, rx_ring->irq);
+
+}
+
+/* Worker thread to process a given rx_ring that is dedicated
+ * to inbound completions.
+ */
+static void ql_rx_clean(struct work_struct *work)
+{
+	struct rx_ring *rx_ring =
+	    container_of(work, struct rx_ring, rx_work.work);
+	ql_clean_inbound_rx_ring(rx_ring, 64);
+	ql_enable_completion_interrupt(rx_ring->qdev, rx_ring->irq);
+}
+
+/* MSI-X Multiple Vector Interrupt Handler for outbound completions. */
+static irqreturn_t qlge_msix_tx_isr(int irq, void *dev_id)
+{
+	struct rx_ring *rx_ring = dev_id;
+	queue_delayed_work_on(rx_ring->cpu, rx_ring->qdev->q_workqueue,
+			      &rx_ring->rx_work, 0);
+	return IRQ_HANDLED;
+}
+
+/* MSI-X Multiple Vector Interrupt Handler for inbound completions. */
+static irqreturn_t qlge_msix_rx_isr(int irq, void *dev_id)
+{
+	struct rx_ring *rx_ring = dev_id;
+	struct ql_adapter *qdev = rx_ring->qdev;
+	netif_rx_schedule(qdev->ndev, &rx_ring->napi);
+	return IRQ_HANDLED;
+}
+
+/* We check here to see if we're already handling a legacy
+ * interrupt.  If we are, then it must belong to another
+ * chip with which we're sharing the interrupt line.
+ */
+int ql_legacy_check(struct ql_adapter *qdev)
+{
+	int err;
+	spin_lock(&qdev->legacy_lock);
+	err = atomic_read(&qdev->intr_context[0].irq_cnt);
+	spin_unlock(&qdev->legacy_lock);
+	return err;
+}
+
+/* This handles a fatal error, MPI activity, and the default
+ * rx_ring in an MSI-X multiple vector environment.
+ * In MSI/Legacy environment it also process the rest of
+ * the rx_rings.
+ */
+static irqreturn_t qlge_isr(int irq, void *dev_id)
+{
+	struct rx_ring *rx_ring = dev_id;
+	struct ql_adapter *qdev = rx_ring->qdev;
+	struct intr_context *intr_context = &qdev->intr_context[0];
+	u32 var;
+	int i;
+	int work_done = 0;
+
+	if (qdev->legacy_check && qdev->legacy_check(qdev)) {
+		QPRINTK(qdev, INTR, INFO, "Already busy, not our interrupt.\n");
+		return IRQ_NONE;	/* Not our interrupt */
+	}
+
+	var = ql_read32(qdev, STS);
+
+	/*
+	 * Check for fatal error.
+	 */
+	if (var & STS_FE) {
+		ql_queue_asic_error(qdev);
+		QPRINTK(qdev, INTR, ERR, "Got fatal error, STS = %x.\n", var);
+		var = ql_read32(qdev, ERR_STS);
+		QPRINTK(qdev, INTR, ERR,
+			"Resetting chip. Error Status Register = 0x%x\n", var);
+		return IRQ_HANDLED;
+	}
+
+	/*
+	 * Check MPI processor activity.
+	 */
+	if (var & STS_PI) {
+		/*
+		 * We've got an async event or mailbox completion.
+		 * Handle it and clear the source of the interrupt.
+		 */
+		QPRINTK(qdev, INTR, ERR, "Got MPI processor interrupt.\n");
+		ql_disable_completion_interrupt(qdev, intr_context->intr);
+		queue_delayed_work_on(smp_processor_id(), qdev->workqueue,
+				      &qdev->mpi_work, 0);
+		work_done++;
+	}
+
+	/*
+	 * Check the default queue and wake handler if active.
+	 */
+	rx_ring = &qdev->rx_ring[0];
+	if (ql_read_sh_reg(rx_ring->prod_idx_sh_reg) != rx_ring->cnsmr_idx) {
+		QPRINTK(qdev, INTR, INFO, "Waking handler for rx_ring[0].\n");
+		ql_disable_completion_interrupt(qdev, intr_context->intr);
+		queue_delayed_work_on(smp_processor_id(), qdev->q_workqueue,
+				      &rx_ring->rx_work, 0);
+		work_done++;
+	}
+
+	if (!test_bit(QL_MSIX_ENABLED, &qdev->flags)) {
+		/*
+		 * Start the DPC for each active queue.
+		 */
+		for (i = 1; i < qdev->rx_ring_count; i++) {
+			rx_ring = &qdev->rx_ring[i];
+			if (ql_read_sh_reg(rx_ring->prod_idx_sh_reg) !=
+			    rx_ring->cnsmr_idx) {
+				QPRINTK(qdev, INTR, INFO,
+					"Waking handler for rx_ring[%d].\n", i);
+				ql_disable_completion_interrupt(qdev,
+								intr_context->
+								intr);
+				if (i < qdev->rss_ring_first_cq_id)
+					queue_delayed_work_on(rx_ring->cpu,
+							      qdev->q_workqueue,
+							      &rx_ring->rx_work,
+							      0);
+				else
+					netif_rx_schedule(qdev->ndev,
+							  &rx_ring->napi);
+				work_done++;
+			}
+		}
+	}
+	return work_done ? IRQ_HANDLED : IRQ_NONE;
+}
+
+static int ql_tso(struct sk_buff *skb, struct ob_mac_tso_iocb_req *mac_iocb_ptr)
+{
+
+	if (skb_is_gso(skb)) {
+		int err;
+		if (skb_header_cloned(skb)) {
+			err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC);
+			if (err)
+				return err;
+		}
+
+		mac_iocb_ptr->opcode = OPCODE_OB_MAC_TSO_IOCB;
+		mac_iocb_ptr->flags3 |= OB_MAC_TSO_IOCB_IC;
+		mac_iocb_ptr->frame_len = cpu_to_le32((u32) skb->len);
+		mac_iocb_ptr->total_hdrs_len =
+		    cpu_to_le16(skb_transport_offset(skb) + tcp_hdrlen(skb));
+		mac_iocb_ptr->net_trans_offset =
+		    cpu_to_le16(skb_network_offset(skb) |
+				skb_transport_offset(skb)
+				<< OB_MAC_TRANSPORT_HDR_SHIFT);
+		mac_iocb_ptr->mss = cpu_to_le16(skb_shinfo(skb)->gso_size);
+		mac_iocb_ptr->flags2 |= OB_MAC_TSO_IOCB_LSO;
+		if (likely(skb->protocol == htons(ETH_P_IP))) {
+			struct iphdr *iph = ip_hdr(skb);
+			iph->check = 0;
+			mac_iocb_ptr->flags1 |= OB_MAC_TSO_IOCB_IP4;
+			tcp_hdr(skb)->check = ~csum_tcpudp_magic(iph->saddr,
+								 iph->daddr, 0,
+								 IPPROTO_TCP,
+								 0);
+		} else if (skb->protocol == htons(ETH_P_IPV6)) {
+			mac_iocb_ptr->flags1 |= OB_MAC_TSO_IOCB_IP6;
+			tcp_hdr(skb)->check =
+			    ~csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
+					     &ipv6_hdr(skb)->daddr,
+					     0, IPPROTO_TCP, 0);
+		}
+		return 1;
+	}
+	return 0;
+}
+
+static void ql_hw_csum_setup(struct sk_buff *skb,
+			     struct ob_mac_tso_iocb_req *mac_iocb_ptr)
+{
+	int len;
+	struct iphdr *iph = ip_hdr(skb);
+	u16 *check;
+	mac_iocb_ptr->opcode = OPCODE_OB_MAC_TSO_IOCB;
+	mac_iocb_ptr->frame_len = cpu_to_le32((u32) skb->len);
+	mac_iocb_ptr->net_trans_offset =
+		cpu_to_le16(skb_network_offset(skb) |
+		skb_transport_offset(skb) << OB_MAC_TRANSPORT_HDR_SHIFT);
+
+	mac_iocb_ptr->flags1 |= OB_MAC_TSO_IOCB_IP4;
+	len = (ntohs(iph->tot_len) - (iph->ihl << 2));
+	if (likely(iph->protocol == IPPROTO_TCP)) {
+		check = &(tcp_hdr(skb)->check);
+		mac_iocb_ptr->flags2 |= OB_MAC_TSO_IOCB_TC;
+		mac_iocb_ptr->total_hdrs_len =
+		    cpu_to_le16(skb_transport_offset(skb) +
+				(tcp_hdr(skb)->doff << 2));
+	} else {
+		check = &(udp_hdr(skb)->check);
+		mac_iocb_ptr->flags2 |= OB_MAC_TSO_IOCB_UC;
+		mac_iocb_ptr->total_hdrs_len =
+		    cpu_to_le16(skb_transport_offset(skb) +
+				sizeof(struct udphdr));
+	}
+	*check = ~csum_tcpudp_magic(iph->saddr,
+				    iph->daddr, len, iph->protocol, 0);
+}
+
+static int qlge_send(struct sk_buff *skb, struct net_device *ndev)
+{
+	struct tx_ring_desc *tx_ring_desc;
+	struct ob_mac_iocb_req *mac_iocb_ptr;
+	struct ql_adapter *qdev = netdev_priv(ndev);
+	int tso;
+	struct tx_ring *tx_ring;
+	u32 tx_ring_idx = (u32) QL_TXQ_IDX(qdev, skb);
+
+	tx_ring = &qdev->tx_ring[tx_ring_idx];
+
+	if (unlikely(atomic_read(&tx_ring->tx_count) < 2)) {
+		QPRINTK(qdev, TX_QUEUED, INFO,
+			"%s: shutting down tx queue %d du to lack of resources.\n",
+			__func__, tx_ring_idx);
+		netif_stop_queue(ndev);
+		atomic_inc(&tx_ring->queue_stopped);
+		return NETDEV_TX_BUSY;
+	}
+	tx_ring_desc = &tx_ring->q[tx_ring->prod_idx];
+	mac_iocb_ptr = tx_ring_desc->queue_entry;
+	memset((void *)mac_iocb_ptr, 0, sizeof(mac_iocb_ptr));
+	if (ql_map_send(qdev, mac_iocb_ptr, skb, tx_ring_desc) != NETDEV_TX_OK) {
+		QPRINTK(qdev, TX_QUEUED, ERR, "Could not map the segments.\n");
+		return NETDEV_TX_BUSY;
+	}
+
+	mac_iocb_ptr->opcode = OPCODE_OB_MAC_IOCB;
+	mac_iocb_ptr->tid = tx_ring_desc->index;
+	/* We use the upper 32-bits to store the tx queue for this IO.
+	 * When we get the completion we can use it to establish the context.
+	 */
+	mac_iocb_ptr->txq_idx = tx_ring_idx;
+	tx_ring_desc->skb = skb;
+
+	mac_iocb_ptr->frame_len = cpu_to_le16((u16) skb->len);
+
+	if (qdev->vlgrp && vlan_tx_tag_present(skb)) {
+		QPRINTK(qdev, TX_QUEUED, DEBUG, "Adding a vlan tag %d.\n",
+			vlan_tx_tag_get(skb));
+		mac_iocb_ptr->flags3 |= OB_MAC_IOCB_V;
+		mac_iocb_ptr->vlan_tci = cpu_to_le16(vlan_tx_tag_get(skb));
+	}
+	tso = ql_tso(skb, (struct ob_mac_tso_iocb_req *)mac_iocb_ptr);
+	if (tso < 0) {
+		dev_kfree_skb_any(skb);
+		return NETDEV_TX_OK;
+	} else if (unlikely(!tso) && (skb->ip_summed == CHECKSUM_PARTIAL)) {
+		ql_hw_csum_setup(skb,
+				 (struct ob_mac_tso_iocb_req *)mac_iocb_ptr);
+	}
+	QL_DUMP_OB_MAC_IOCB(mac_iocb_ptr);
+	tx_ring->prod_idx++;
+	if (tx_ring->prod_idx == tx_ring->wq_len)
+		tx_ring->prod_idx = 0;
+	wmb();
+
+	ql_write_db_reg(tx_ring->prod_idx, tx_ring->prod_idx_db_reg);
+	ndev->trans_start = jiffies;
+	QPRINTK(qdev, TX_QUEUED, DEBUG, "tx queued, slot %d, len %d\n",
+		tx_ring->prod_idx, skb->len);
+
+	atomic_dec(&tx_ring->tx_count);
+	return NETDEV_TX_OK;
+}
+
+static void ql_free_shadow_space(struct ql_adapter *qdev)
+{
+	if (qdev->rx_ring_shadow_reg_area) {
+		pci_free_consistent(qdev->pdev,
+				    PAGE_SIZE,
+				    qdev->rx_ring_shadow_reg_area,
+				    qdev->rx_ring_shadow_reg_dma);
+		qdev->rx_ring_shadow_reg_area = NULL;
+	}
+	if (qdev->tx_ring_shadow_reg_area) {
+		pci_free_consistent(qdev->pdev,
+				    PAGE_SIZE,
+				    qdev->tx_ring_shadow_reg_area,
+				    qdev->tx_ring_shadow_reg_dma);
+		qdev->tx_ring_shadow_reg_area = NULL;
+	}
+}
+
+static int ql_alloc_shadow_space(struct ql_adapter *qdev)
+{
+	qdev->rx_ring_shadow_reg_area =
+	    pci_alloc_consistent(qdev->pdev,
+				 PAGE_SIZE, &qdev->rx_ring_shadow_reg_dma);
+	if (qdev->rx_ring_shadow_reg_area == NULL) {
+		QPRINTK(qdev, IFUP, ERR,
+			"Allocation of RX shadow space failed.\n");
+		return -ENOMEM;
+	}
+	qdev->tx_ring_shadow_reg_area =
+	    pci_alloc_consistent(qdev->pdev, PAGE_SIZE,
+				 &qdev->tx_ring_shadow_reg_dma);
+	if (qdev->tx_ring_shadow_reg_area == NULL) {
+		QPRINTK(qdev, IFUP, ERR,
+			"Allocation of TX shadow space failed.\n");
+		goto err_wqp_sh_area;
+	}
+	return 0;
+
+err_wqp_sh_area:
+	pci_free_consistent(qdev->pdev,
+			    PAGE_SIZE,
+			    qdev->rx_ring_shadow_reg_area,
+			    qdev->rx_ring_shadow_reg_dma);
+	return -ENOMEM;
+}
+
+static void ql_init_tx_ring(struct ql_adapter *qdev, struct tx_ring *tx_ring)
+{
+	struct tx_ring_desc *tx_ring_desc;
+	int i;
+	struct ob_mac_iocb_req *mac_iocb_ptr;
+
+	mac_iocb_ptr = tx_ring->wq_base;
+	tx_ring_desc = tx_ring->q;
+	for (i = 0; i < tx_ring->wq_len; i++) {
+		tx_ring_desc->index = i;
+		tx_ring_desc->skb = NULL;
+		tx_ring_desc->queue_entry = mac_iocb_ptr;
+		mac_iocb_ptr++;
+		tx_ring_desc++;
+	}
+	atomic_set(&tx_ring->tx_count, tx_ring->wq_len);
+	atomic_set(&tx_ring->queue_stopped, 0);
+}
+
+static void ql_free_tx_resources(struct ql_adapter *qdev,
+				 struct tx_ring *tx_ring)
+{
+	if (tx_ring->wq_base) {
+		pci_free_consistent(qdev->pdev, tx_ring->wq_size,
+				    tx_ring->wq_base, tx_ring->wq_base_dma);
+		tx_ring->wq_base = NULL;
+	}
+	kfree(tx_ring->q);
+	tx_ring->q = NULL;
+}
+
+static int ql_alloc_tx_resources(struct ql_adapter *qdev,
+				 struct tx_ring *tx_ring)
+{
+	tx_ring->wq_base =
+	    pci_alloc_consistent(qdev->pdev, tx_ring->wq_size,
+				 &tx_ring->wq_base_dma);
+
+	if ((tx_ring->wq_base == NULL)
+	    || tx_ring->wq_base_dma & (tx_ring->wq_size - 1)) {
+		QPRINTK(qdev, IFUP, ERR, "tx_ring alloc failed.\n");
+		return -ENOMEM;
+	}
+	tx_ring->q =
+	    kmalloc(tx_ring->wq_len * sizeof(struct tx_ring_desc), GFP_KERNEL);
+	if (tx_ring->q == NULL)
+		goto err;
+
+	return 0;
+err:
+	pci_free_consistent(qdev->pdev, tx_ring->wq_size,
+			    tx_ring->wq_base, tx_ring->wq_base_dma);
+	return -ENOMEM;
+}
+
+void ql_free_lbq_buffers(struct ql_adapter *qdev, struct rx_ring *rx_ring)
+{
+	int i;
+	struct bq_desc *lbq_desc;
+
+	for (i = 0; i < rx_ring->lbq_len; i++) {
+		lbq_desc = &rx_ring->lbq[i];
+		if (lbq_desc->p.lbq_page) {
+			pci_unmap_page(qdev->pdev,
+				       pci_unmap_addr(lbq_desc, mapaddr),
+				       pci_unmap_len(lbq_desc, maplen),
+				       PCI_DMA_FROMDEVICE);
+
+			put_page(lbq_desc->p.lbq_page);
+			lbq_desc->p.lbq_page = NULL;
+		}
+		lbq_desc->bq->addr_lo = 0;
+		lbq_desc->bq->addr_hi = 0;
+	}
+}
+
+/*
+ * Allocate and map a page for each element of the lbq.
+ */
+static int ql_alloc_lbq_buffers(struct ql_adapter *qdev,
+				struct rx_ring *rx_ring)
+{
+	int i;
+	struct bq_desc *lbq_desc;
+	u64 map;
+	struct bq_element *bq = rx_ring->lbq_base;
+
+	for (i = 0; i < rx_ring->lbq_len; i++) {
+		lbq_desc = &rx_ring->lbq[i];
+		memset(lbq_desc, 0, sizeof(lbq_desc));
+		lbq_desc->bq = bq;
+		lbq_desc->index = i;
+		lbq_desc->p.lbq_page = alloc_page(GFP_ATOMIC);
+		if (unlikely(!lbq_desc->p.lbq_page)) {
+			QPRINTK(qdev, IFUP, ERR, "failed alloc_page().\n");
+			goto mem_error;
+		} else {
+			map = pci_map_page(qdev->pdev,
+					   lbq_desc->p.lbq_page,
+					   0, PAGE_SIZE, PCI_DMA_FROMDEVICE);
+			if (pci_dma_mapping_error(qdev->pdev, map)) {
+				QPRINTK(qdev, IFUP, ERR,
+					"PCI mapping failed.\n");
+				goto mem_error;
+			}
+			pci_unmap_addr_set(lbq_desc, mapaddr, map);
+			pci_unmap_len_set(lbq_desc, maplen, PAGE_SIZE);
+			bq->addr_lo = cpu_to_le32(map);
+			bq->addr_hi = cpu_to_le32(map >> 32);
+		}
+		bq++;
+	}
+	return 0;
+mem_error:
+	ql_free_lbq_buffers(qdev, rx_ring);
+	return -ENOMEM;
+}
+
+void ql_free_sbq_buffers(struct ql_adapter *qdev, struct rx_ring *rx_ring)
+{
+	int i;
+	struct bq_desc *sbq_desc;
+
+	for (i = 0; i < rx_ring->sbq_len; i++) {
+		sbq_desc = &rx_ring->sbq[i];
+		if (sbq_desc == NULL) {
+			QPRINTK(qdev, IFUP, ERR, "sbq_desc %d is NULL.\n", i);
+			return;
+		}
+		if (sbq_desc->p.skb) {
+			pci_unmap_single(qdev->pdev,
+					 pci_unmap_addr(sbq_desc, mapaddr),
+					 pci_unmap_len(sbq_desc, maplen),
+					 PCI_DMA_FROMDEVICE);
+			dev_kfree_skb(sbq_desc->p.skb);
+			sbq_desc->p.skb = NULL;
+		}
+		if (sbq_desc->bq == NULL) {
+			QPRINTK(qdev, IFUP, ERR, "sbq_desc->bq %d is NULL.\n",
+				i);
+			return;
+		}
+		sbq_desc->bq->addr_lo = 0;
+		sbq_desc->bq->addr_hi = 0;
+	}
+}
+
+/* Allocate and map an skb for each element of the sbq. */
+static int ql_alloc_sbq_buffers(struct ql_adapter *qdev,
+				struct rx_ring *rx_ring)
+{
+	int i;
+	struct bq_desc *sbq_desc;
+	struct sk_buff *skb;
+	u64 map;
+	struct bq_element *bq = rx_ring->sbq_base;
+
+	for (i = 0; i < rx_ring->sbq_len; i++) {
+		sbq_desc = &rx_ring->sbq[i];
+		memset(sbq_desc, 0, sizeof(sbq_desc));
+		sbq_desc->index = i;
+		sbq_desc->bq = bq;
+		skb = netdev_alloc_skb(qdev->ndev, rx_ring->sbq_buf_size);
+		if (unlikely(!skb)) {
+			/* Better luck next round */
+			QPRINTK(qdev, IFUP, ERR,
+				"small buff alloc failed for %d bytes at index %d.\n",
+				rx_ring->sbq_buf_size, i);
+			goto mem_err;
+		}
+		skb_reserve(skb, QLGE_SB_PAD);
+		sbq_desc->p.skb = skb;
+		/*
+		 * Map only half the buffer. Because the
+		 * other half may get some data copied to it
+		 * when the completion arrives.
+		 */
+		map = pci_map_single(qdev->pdev,
+				     skb->data,
+				     rx_ring->sbq_buf_size / 2,
+				     PCI_DMA_FROMDEVICE);
+		if (pci_dma_mapping_error(qdev->pdev, map)) {
+			QPRINTK(qdev, IFUP, ERR, "PCI mapping failed.\n");
+			goto mem_err;
+		}
+		pci_unmap_addr_set(sbq_desc, mapaddr, map);
+		pci_unmap_len_set(sbq_desc, maplen, rx_ring->sbq_buf_size / 2);
+		bq->addr_lo =	/*sbq_desc->addr_lo = */
+		    cpu_to_le32(map);
+		bq->addr_hi =	/*sbq_desc->addr_hi = */
+		    cpu_to_le32(map >> 32);
+		bq++;
+	}
+	return 0;
+mem_err:
+	ql_free_sbq_buffers(qdev, rx_ring);
+	return -ENOMEM;
+}
+
+static void ql_free_rx_resources(struct ql_adapter *qdev,
+				 struct rx_ring *rx_ring)
+{
+	if (rx_ring->sbq_len)
+		ql_free_sbq_buffers(qdev, rx_ring);
+	if (rx_ring->lbq_len)
+		ql_free_lbq_buffers(qdev, rx_ring);
+
+	/* Free the small buffer queue. */
+	if (rx_ring->sbq_base) {
+		pci_free_consistent(qdev->pdev,
+				    rx_ring->sbq_size,
+				    rx_ring->sbq_base, rx_ring->sbq_base_dma);
+		rx_ring->sbq_base = NULL;
+	}
+
+	/* Free the small buffer queue control blocks. */
+	kfree(rx_ring->sbq);
+	rx_ring->sbq = NULL;
+
+	/* Free the large buffer queue. */
+	if (rx_ring->lbq_base) {
+		pci_free_consistent(qdev->pdev,
+				    rx_ring->lbq_size,
+				    rx_ring->lbq_base, rx_ring->lbq_base_dma);
+		rx_ring->lbq_base = NULL;
+	}
+
+	/* Free the large buffer queue control blocks. */
+	kfree(rx_ring->lbq);
+	rx_ring->lbq = NULL;
+
+	/* Free the rx queue. */
+	if (rx_ring->cq_base) {
+		pci_free_consistent(qdev->pdev,
+				    rx_ring->cq_size,
+				    rx_ring->cq_base, rx_ring->cq_base_dma);
+		rx_ring->cq_base = NULL;
+	}
+}
+
+/* Allocate queues and buffers for this completions queue based
+ * on the values in the parameter structure. */
+static int ql_alloc_rx_resources(struct ql_adapter *qdev,
+				 struct rx_ring *rx_ring)
+{
+
+	/*
+	 * Allocate the completion queue for this rx_ring.
+	 */
+	rx_ring->cq_base =
+	    pci_alloc_consistent(qdev->pdev, rx_ring->cq_size,
+				 &rx_ring->cq_base_dma);
+
+	if (rx_ring->cq_base == NULL) {
+		QPRINTK(qdev, IFUP, ERR, "rx_ring alloc failed.\n");
+		return -ENOMEM;
+	}
+
+	if (rx_ring->sbq_len) {
+		/*
+		 * Allocate small buffer queue.
+		 */
+		rx_ring->sbq_base =
+		    pci_alloc_consistent(qdev->pdev, rx_ring->sbq_size,
+					 &rx_ring->sbq_base_dma);
+
+		if (rx_ring->sbq_base == NULL) {
+			QPRINTK(qdev, IFUP, ERR,
+				"Small buffer queue allocation failed.\n");
+			goto err_mem;
+		}
+
+		/*
+		 * Allocate small buffer queue control blocks.
+		 */
+		rx_ring->sbq =
+		    kmalloc(rx_ring->sbq_len * sizeof(struct bq_desc),
+			    GFP_KERNEL);
+		if (rx_ring->sbq == NULL) {
+			QPRINTK(qdev, IFUP, ERR,
+				"Small buffer queue control block allocation failed.\n");
+			goto err_mem;
+		}
+
+		if (ql_alloc_sbq_buffers(qdev, rx_ring)) {
+			QPRINTK(qdev, IFUP, ERR,
+				"Small buffer allocation failed.\n");
+			goto err_mem;
+		}
+	}
+
+	if (rx_ring->lbq_len) {
+		/*
+		 * Allocate large buffer queue.
+		 */
+		rx_ring->lbq_base =
+		    pci_alloc_consistent(qdev->pdev, rx_ring->lbq_size,
+					 &rx_ring->lbq_base_dma);
+
+		if (rx_ring->lbq_base == NULL) {
+			QPRINTK(qdev, IFUP, ERR,
+				"Large buffer queue allocation failed.\n");
+			goto err_mem;
+		}
+		/*
+		 * Allocate large buffer queue control blocks.
+		 */
+		rx_ring->lbq =
+		    kmalloc(rx_ring->lbq_len * sizeof(struct bq_desc),
+			    GFP_KERNEL);
+		if (rx_ring->lbq == NULL) {
+			QPRINTK(qdev, IFUP, ERR,
+				"Large buffer queue control block allocation failed.\n");
+			goto err_mem;
+		}
+
+		/*
+		 * Allocate the buffers.
+		 */
+		if (ql_alloc_lbq_buffers(qdev, rx_ring)) {
+			QPRINTK(qdev, IFUP, ERR,
+				"Large buffer allocation failed.\n");
+			goto err_mem;
+		}
+	}
+
+	return 0;
+
+err_mem:
+	ql_free_rx_resources(qdev, rx_ring);
+	return -ENOMEM;
+}
+
+static void ql_tx_ring_clean(struct ql_adapter *qdev)
+{
+	struct tx_ring *tx_ring;
+	struct tx_ring_desc *tx_ring_desc;
+	int i, j;
+
+	/*
+	 * Loop through all queues and free
+	 * any resources.
+	 */
+	for (j = 0; j < qdev->tx_ring_count; j++) {
+		tx_ring = &qdev->tx_ring[j];
+		for (i = 0; i < tx_ring->wq_len; i++) {
+			tx_ring_desc = &tx_ring->q[i];
+			if (tx_ring_desc && tx_ring_desc->skb) {
+				QPRINTK(qdev, IFDOWN, ERR,
+				"Freeing lost SKB %p, from queue %d, index %d.\n",
+					tx_ring_desc->skb, j,
+					tx_ring_desc->index);
+				ql_unmap_send(qdev, tx_ring_desc,
+					      tx_ring_desc->map_cnt);
+				dev_kfree_skb(tx_ring_desc->skb);
+				tx_ring_desc->skb = NULL;
+			}
+		}
+	}
+}
+
+static void ql_free_ring_cb(struct ql_adapter *qdev)
+{
+	kfree(qdev->ring_mem);
+}
+
+static int ql_alloc_ring_cb(struct ql_adapter *qdev)
+{
+	/* Allocate space for tx/rx ring control blocks. */
+	qdev->ring_mem_size =
+	    (qdev->tx_ring_count * sizeof(struct tx_ring)) +
+	    (qdev->rx_ring_count * sizeof(struct rx_ring));
+	qdev->ring_mem = kmalloc(qdev->ring_mem_size, GFP_KERNEL);
+	if (qdev->ring_mem == NULL) {
+		return -ENOMEM;
+	} else {
+		qdev->rx_ring = qdev->ring_mem;
+		qdev->tx_ring = qdev->ring_mem +
+		    (qdev->rx_ring_count * sizeof(struct rx_ring));
+	}
+	return 0;
+}
+
+static void ql_free_mem_resources(struct ql_adapter *qdev)
+{
+	int i;
+
+	for (i = 0; i < qdev->tx_ring_count; i++)
+		ql_free_tx_resources(qdev, &qdev->tx_ring[i]);
+	for (i = 0; i < qdev->rx_ring_count; i++)
+		ql_free_rx_resources(qdev, &qdev->rx_ring[i]);
+	ql_free_shadow_space(qdev);
+}
+
+static int ql_alloc_mem_resources(struct ql_adapter *qdev)
+{
+	int i;
+
+	/* Allocate space for our shadow registers and such. */
+	if (ql_alloc_shadow_space(qdev))
+		return -ENOMEM;
+
+	for (i = 0; i < qdev->rx_ring_count; i++) {
+		if (ql_alloc_rx_resources(qdev, &qdev->rx_ring[i]) != 0) {
+			QPRINTK(qdev, IFUP, ERR,
+				"RX resource allocation failed.\n");
+			goto err_mem;
+		}
+	}
+	/* Allocate tx queue resources */
+	for (i = 0; i < qdev->tx_ring_count; i++) {
+		if (ql_alloc_tx_resources(qdev, &qdev->tx_ring[i]) != 0) {
+			QPRINTK(qdev, IFUP, ERR,
+				"TX resource allocation failed.\n");
+			goto err_mem;
+		}
+	}
+	return 0;
+
+err_mem:
+	ql_free_mem_resources(qdev);
+	return -ENOMEM;
+}
+
+/* Set up the rx ring control block and pass it to the chip.
+ * The control block is defined as
+ * "Completion Queue Initialization Control Block", or cqicb.
+ */
+static int ql_start_rx_ring(struct ql_adapter *qdev, struct rx_ring *rx_ring)
+{
+	struct cqicb *cqicb = &rx_ring->cqicb;
+	void *shadow_reg = qdev->rx_ring_shadow_reg_area +
+	    (rx_ring->cq_id * sizeof(u64) * 4);
+	u64 shadow_reg_dma = qdev->rx_ring_shadow_reg_dma +
+	    (rx_ring->cq_id * sizeof(u64) * 4);
+	void __iomem *doorbell_area =
+	    qdev->doorbell_area + (DB_PAGE_SIZE * (128 + rx_ring->cq_id));
+	int err = 0;
+	u16 bq_len;
+
+	/* Set up the shadow registers for this ring. */
+	rx_ring->prod_idx_sh_reg = shadow_reg;
+	rx_ring->prod_idx_sh_reg_dma = shadow_reg_dma;
+	shadow_reg += sizeof(u64);
+	shadow_reg_dma += sizeof(u64);
+	rx_ring->lbq_base_indirect = shadow_reg;
+	rx_ring->lbq_base_indirect_dma = shadow_reg_dma;
+	shadow_reg += sizeof(u64);
+	shadow_reg_dma += sizeof(u64);
+	rx_ring->sbq_base_indirect = shadow_reg;
+	rx_ring->sbq_base_indirect_dma = shadow_reg_dma;
+
+	/* PCI doorbell mem area + 0x00 for consumer index register */
+	rx_ring->cnsmr_idx_db_reg = (u32 *) doorbell_area;
+	rx_ring->cnsmr_idx = 0;
+	rx_ring->curr_entry = rx_ring->cq_base;
+
+	/* PCI doorbell mem area + 0x04 for valid register */
+	rx_ring->valid_db_reg = doorbell_area + 0x04;
+
+	/* PCI doorbell mem area + 0x18 for large buffer consumer */
+	rx_ring->lbq_prod_idx_db_reg = (u32 *) (doorbell_area + 0x18);
+
+	/* PCI doorbell mem area + 0x1c */
+	rx_ring->sbq_prod_idx_db_reg = (u32 *) (doorbell_area + 0x1c);
+
+	memset((void *)cqicb, 0, sizeof(struct cqicb));
+	cqicb->msix_vect = rx_ring->irq;
+
+	cqicb->len = cpu_to_le16(rx_ring->cq_len | LEN_V | LEN_CPP_CONT);
+
+	cqicb->addr_lo = cpu_to_le32(rx_ring->cq_base_dma);
+	cqicb->addr_hi = cpu_to_le32((u64) rx_ring->cq_base_dma >> 32);
+
+	cqicb->prod_idx_addr_lo = cpu_to_le32(rx_ring->prod_idx_sh_reg_dma);
+	cqicb->prod_idx_addr_hi =
+	    cpu_to_le32((u64) rx_ring->prod_idx_sh_reg_dma >> 32);
+
+	/*
+	 * Set up the control block load flags.
+	 */
+	cqicb->flags = FLAGS_LC |	/* Load queue base address */
+	    FLAGS_LV |		/* Load MSI-X vector */
+	    FLAGS_LI;		/* Load irq delay values */
+	if (rx_ring->lbq_len) {
+		cqicb->flags |= FLAGS_LL;	/* Load lbq values */
+		*((u64 *) rx_ring->lbq_base_indirect) = rx_ring->lbq_base_dma;
+		cqicb->lbq_addr_lo =
+		    cpu_to_le32(rx_ring->lbq_base_indirect_dma);
+		cqicb->lbq_addr_hi =
+		    cpu_to_le32((u64) rx_ring->lbq_base_indirect_dma >> 32);
+		cqicb->lbq_buf_size = cpu_to_le32(rx_ring->lbq_buf_size);
+		bq_len = (u16) rx_ring->lbq_len;
+		cqicb->lbq_len = cpu_to_le16(bq_len);
+		rx_ring->lbq_prod_idx = rx_ring->lbq_len - 16;
+		rx_ring->lbq_curr_idx = 0;
+		rx_ring->lbq_clean_idx = rx_ring->lbq_prod_idx;
+		rx_ring->lbq_free_cnt = 16;
+	}
+	if (rx_ring->sbq_len) {
+		cqicb->flags |= FLAGS_LS;	/* Load sbq values */
+		*((u64 *) rx_ring->sbq_base_indirect) = rx_ring->sbq_base_dma;
+		cqicb->sbq_addr_lo =
+		    cpu_to_le32(rx_ring->sbq_base_indirect_dma);
+		cqicb->sbq_addr_hi =
+		    cpu_to_le32((u64) rx_ring->sbq_base_indirect_dma >> 32);
+		cqicb->sbq_buf_size =
+		    cpu_to_le16(((rx_ring->sbq_buf_size / 2) + 8) & 0xfffffff8);
+		bq_len = (u16) rx_ring->sbq_len;
+		cqicb->sbq_len = cpu_to_le16(bq_len);
+		rx_ring->sbq_prod_idx = rx_ring->sbq_len - 16;
+		rx_ring->sbq_curr_idx = 0;
+		rx_ring->sbq_clean_idx = rx_ring->sbq_prod_idx;
+		rx_ring->sbq_free_cnt = 16;
+	}
+	switch (rx_ring->type) {
+	case TX_Q:
+		/* If there's only one interrupt, then we use
+		 * worker threads to process the outbound
+		 * completion handling rx_rings. We do this so
+		 * they can be run on multiple CPUs. There is
+		 * room to play with this more where we would only
+		 * run in a worker if there are more than x number
+		 * of outbound completions on the queue and more
+		 * than one queue active.  Some threshold that
+		 * would indicate a benefit in spite of the cost
+		 * of a context switch.
+		 * If there's more than one interrupt, then the
+		 * outbound completions are processed in the ISR.
+		 */
+		if (!test_bit(QL_MSIX_ENABLED, &qdev->flags))
+			INIT_DELAYED_WORK(&rx_ring->rx_work, ql_tx_clean);
+		else {
+			/* With all debug warnings on we see a WARN_ON message
+			 * when we free the skb in the interrupt context.
+			 */
+			INIT_DELAYED_WORK(&rx_ring->rx_work, ql_tx_clean);
+		}
+		cqicb->irq_delay = cpu_to_le16(qdev->tx_coalesce_usecs);
+		cqicb->pkt_delay = cpu_to_le16(qdev->tx_max_coalesced_frames);
+		break;
+	case DEFAULT_Q:
+		INIT_DELAYED_WORK(&rx_ring->rx_work, ql_rx_clean);
+		cqicb->irq_delay = 0;
+		cqicb->pkt_delay = 0;
+		break;
+	case RX_Q:
+		/* Inbound completion handling rx_rings run in
+		 * separate NAPI contexts.
+		 */
+		netif_napi_add(qdev->ndev, &rx_ring->napi, ql_napi_poll_msix,
+			       64);
+		cqicb->irq_delay = cpu_to_le16(qdev->rx_coalesce_usecs);
+		cqicb->pkt_delay = cpu_to_le16(qdev->rx_max_coalesced_frames);
+		break;
+	default:
+		QPRINTK(qdev, IFUP, DEBUG, "Invalid rx_ring->type = %d.\n",
+			rx_ring->type);
+	}
+	QPRINTK(qdev, IFUP, INFO, "Initializing rx work queue.\n");
+	err = ql_write_cfg(qdev, cqicb, sizeof(struct cqicb),
+			   CFG_LCQ, rx_ring->cq_id);
+	if (err) {
+		QPRINTK(qdev, IFUP, ERR, "Failed to load CQICB.\n");
+		return err;
+	}
+	QPRINTK(qdev, IFUP, INFO, "Successfully loaded CQICB.\n");
+	/*
+	 * Advance the producer index for the buffer queues.
+	 */
+	wmb();
+	if (rx_ring->lbq_len)
+		ql_write_db_reg(rx_ring->lbq_prod_idx,
+				rx_ring->lbq_prod_idx_db_reg);
+	if (rx_ring->sbq_len)
+		ql_write_db_reg(rx_ring->sbq_prod_idx,
+				rx_ring->sbq_prod_idx_db_reg);
+	return err;
+}
+
+static int ql_start_tx_ring(struct ql_adapter *qdev, struct tx_ring *tx_ring)
+{
+	struct wqicb *wqicb = (struct wqicb *)tx_ring;
+	void __iomem *doorbell_area =
+	    qdev->doorbell_area + (DB_PAGE_SIZE * tx_ring->wq_id);
+	void *shadow_reg = qdev->tx_ring_shadow_reg_area +
+	    (tx_ring->wq_id * sizeof(u64));
+	u64 shadow_reg_dma = qdev->tx_ring_shadow_reg_dma +
+	    (tx_ring->wq_id * sizeof(u64));
+	int err = 0;
+
+	/*
+	 * Assign doorbell registers for this tx_ring.
+	 */
+	/* TX PCI doorbell mem area for tx producer index */
+	tx_ring->prod_idx_db_reg = (u32 *) doorbell_area;
+	tx_ring->prod_idx = 0;
+	/* TX PCI doorbell mem area + 0x04 */
+	tx_ring->valid_db_reg = doorbell_area + 0x04;
+
+	/*
+	 * Assign shadow registers for this tx_ring.
+	 */
+	tx_ring->cnsmr_idx_sh_reg = shadow_reg;
+	tx_ring->cnsmr_idx_sh_reg_dma = shadow_reg_dma;
+
+	wqicb->len = cpu_to_le16(tx_ring->wq_len | Q_LEN_V | Q_LEN_CPP_CONT);
+	wqicb->flags = cpu_to_le16(Q_FLAGS_LC |
+				   Q_FLAGS_LB | Q_FLAGS_LI | Q_FLAGS_LO);
+	wqicb->cq_id_rss = cpu_to_le16(tx_ring->cq_id);
+	wqicb->rid = 0;
+	wqicb->addr_lo = cpu_to_le32(tx_ring->wq_base_dma);
+	wqicb->addr_hi = cpu_to_le32((u64) tx_ring->wq_base_dma >> 32);
+
+	wqicb->cnsmr_idx_addr_lo = cpu_to_le32(tx_ring->cnsmr_idx_sh_reg_dma);
+	wqicb->cnsmr_idx_addr_hi =
+	    cpu_to_le32((u64) tx_ring->cnsmr_idx_sh_reg_dma >> 32);
+
+	ql_init_tx_ring(qdev, tx_ring);
+
+	err = ql_write_cfg(qdev, wqicb, sizeof(wqicb), CFG_LRQ,
+			   (u16) tx_ring->wq_id);
+	if (err) {
+		QPRINTK(qdev, IFUP, ERR, "Failed to load tx_ring.\n");
+		return err;
+	}
+	QPRINTK(qdev, IFUP, INFO, "Successfully loaded WQICB.\n");
+	return err;
+}
+
+static void ql_disable_msix(struct ql_adapter *qdev)
+{
+	if (test_bit(QL_MSIX_ENABLED, &qdev->flags)) {
+		pci_disable_msix(qdev->pdev);
+		clear_bit(QL_MSIX_ENABLED, &qdev->flags);
+		kfree(qdev->msi_x_entry);
+		qdev->msi_x_entry = NULL;
+	} else if (test_bit(QL_MSI_ENABLED, &qdev->flags)) {
+		pci_disable_msi(qdev->pdev);
+		clear_bit(QL_MSI_ENABLED, &qdev->flags);
+	}
+}
+
+static void ql_enable_msix(struct ql_adapter *qdev)
+{
+	int i;
+
+	qdev->intr_count = 1;
+	/* Get the MSIX vectors. */
+	if (irq_type == MSIX_IRQ) {
+		/* Try to alloc space for the msix struct,
+		 * if it fails then go to MSI/legacy.
+		 */
+		qdev->msi_x_entry = kcalloc(qdev->rx_ring_count,
+					    sizeof(struct msix_entry),
+					    GFP_KERNEL);
+		if (!qdev->msi_x_entry) {
+			irq_type = MSI_IRQ;
+			goto msi;
+		}
+
+		for (i = 0; i < qdev->rx_ring_count; i++)
+			qdev->msi_x_entry[i].entry = i;
+
+		if (!pci_enable_msix
+		    (qdev->pdev, qdev->msi_x_entry, qdev->rx_ring_count)) {
+			set_bit(QL_MSIX_ENABLED, &qdev->flags);
+			qdev->intr_count = qdev->rx_ring_count;
+			QPRINTK(qdev, IFUP, INFO,
+				"MSI-X Enabled, got %d vectors.\n",
+				qdev->intr_count);
+			return;
+		} else {
+			kfree(qdev->msi_x_entry);
+			qdev->msi_x_entry = NULL;
+			QPRINTK(qdev, IFUP, WARNING,
+				"MSI-X Enable failed, trying MSI.\n");
+			irq_type = MSI_IRQ;
+		}
+	}
+msi:
+	if (irq_type == MSI_IRQ) {
+		if (!pci_enable_msi(qdev->pdev)) {
+			set_bit(QL_MSI_ENABLED, &qdev->flags);
+			QPRINTK(qdev, IFUP, INFO,
+				"Running with MSI interrupts.\n");
+			return;
+		}
+	}
+	irq_type = LEG_IRQ;
+	spin_lock_init(&qdev->legacy_lock);
+	qdev->legacy_check = ql_legacy_check;
+	QPRINTK(qdev, IFUP, DEBUG, "Running with legacy interrupts.\n");
+}
+
+/*
+ * Here we build the intr_context structures based on
+ * our rx_ring count and intr vector count.
+ * The intr_context structure is used to hook each vector
+ * to possibly different handlers.
+ */
+static void ql_resolve_queues_to_irqs(struct ql_adapter *qdev)
+{
+	int i = 0;
+	struct intr_context *intr_context = &qdev->intr_context[0];
+
+	ql_enable_msix(qdev);
+
+	if (likely(test_bit(QL_MSIX_ENABLED, &qdev->flags))) {
+		/* Each rx_ring has it's
+		 * own intr_context since we have separate
+		 * vectors for each queue.
+		 * This only true when MSI-X is enabled.
+		 */
+		for (i = 0; i < qdev->intr_count; i++, intr_context++) {
+			qdev->rx_ring[i].irq = i;
+			intr_context->intr = i;
+			intr_context->qdev = qdev;
+			/*
+			 * We set up each vectors enable/disable/read bits so
+			 * there's no bit/mask calculations in the critical path.
+			 */
+			intr_context->intr_en_mask =
+			    INTR_EN_TYPE_MASK | INTR_EN_INTR_MASK |
+			    INTR_EN_TYPE_ENABLE | INTR_EN_IHD_MASK | INTR_EN_IHD
+			    | i;
+			intr_context->intr_dis_mask =
+			    INTR_EN_TYPE_MASK | INTR_EN_INTR_MASK |
+			    INTR_EN_TYPE_DISABLE | INTR_EN_IHD_MASK |
+			    INTR_EN_IHD | i;
+			intr_context->intr_read_mask =
+			    INTR_EN_TYPE_MASK | INTR_EN_INTR_MASK |
+			    INTR_EN_TYPE_READ | INTR_EN_IHD_MASK | INTR_EN_IHD |
+			    i;
+
+			if (i == 0) {
+				/*
+				 * Default queue handles bcast/mcast plus
+				 * async events.  Needs buffers.
+				 */
+				intr_context->handler = qlge_isr;
+				sprintf(intr_context->name, "%s-default-queue",
+					qdev->ndev->name);
+			} else if (i < qdev->rss_ring_first_cq_id) {
+				/*
+				 * Outbound queue is for outbound completions only.
+				 */
+				intr_context->handler = qlge_msix_tx_isr;
+				sprintf(intr_context->name, "%s-txq-%d",
+					qdev->ndev->name, i);
+			} else {
+				/*
+				 * Inbound queues handle unicast frames only.
+				 */
+				intr_context->handler = qlge_msix_rx_isr;
+				sprintf(intr_context->name, "%s-rxq-%d",
+					qdev->ndev->name, i);
+			}
+		}
+	} else {
+		/*
+		 * All rx_rings use the same intr_context since
+		 * there is only one vector.
+		 */
+		intr_context->intr = 0;
+		intr_context->qdev = qdev;
+		/*
+		 * We set up each vectors enable/disable/read bits so
+		 * there's no bit/mask calculations in the critical path.
+		 */
+		intr_context->intr_en_mask =
+		    INTR_EN_TYPE_MASK | INTR_EN_INTR_MASK | INTR_EN_TYPE_ENABLE;
+		intr_context->intr_dis_mask =
+		    INTR_EN_TYPE_MASK | INTR_EN_INTR_MASK |
+		    INTR_EN_TYPE_DISABLE;
+		intr_context->intr_read_mask =
+		    INTR_EN_TYPE_MASK | INTR_EN_INTR_MASK | INTR_EN_TYPE_READ;
+		/*
+		 * Single interrupt means one handler for all rings.
+		 */
+		intr_context->handler = qlge_isr;
+		sprintf(intr_context->name, "%s-single_irq", qdev->ndev->name);
+		for (i = 0; i < qdev->rx_ring_count; i++)
+			qdev->rx_ring[i].irq = 0;
+	}
+}
+
+static void ql_free_irq(struct ql_adapter *qdev)
+{
+	int i;
+	struct intr_context *intr_context = &qdev->intr_context[0];
+
+	for (i = 0; i < qdev->intr_count; i++, intr_context++) {
+		if (intr_context->hooked) {
+			if (test_bit(QL_MSIX_ENABLED, &qdev->flags)) {
+				free_irq(qdev->msi_x_entry[i].vector,
+					 &qdev->rx_ring[i]);
+				QPRINTK(qdev, IFDOWN, ERR,
+					"freeing msix interrupt %d.\n", i);
+			} else {
+				free_irq(qdev->pdev->irq, &qdev->rx_ring[0]);
+				QPRINTK(qdev, IFDOWN, ERR,
+					"freeing msi interrupt %d.\n", i);
+			}
+		}
+	}
+	ql_disable_msix(qdev);
+}
+
+static int ql_request_irq(struct ql_adapter *qdev)
+{
+	int i;
+	int status = 0;
+	struct pci_dev *pdev = qdev->pdev;
+	struct intr_context *intr_context = &qdev->intr_context[0];
+
+	ql_resolve_queues_to_irqs(qdev);
+
+	for (i = 0; i < qdev->intr_count; i++, intr_context++) {
+		atomic_set(&intr_context->irq_cnt, 0);
+		if (test_bit(QL_MSIX_ENABLED, &qdev->flags)) {
+			status = request_irq(qdev->msi_x_entry[i].vector,
+					     intr_context->handler,
+					     0,
+					     intr_context->name,
+					     &qdev->rx_ring[i]);
+			if (status) {
+				QPRINTK(qdev, IFUP, ERR,
+					"Failed request for MSIX interrupt %d.\n",
+					i);
+				goto err_irq;
+			} else {
+				QPRINTK(qdev, IFUP, INFO,
+					"Hooked intr %d, queue type %s%s%s, with name %s.\n",
+					i,
+					qdev->rx_ring[i].type ==
+					DEFAULT_Q ? "DEFAULT_Q" : "",
+					qdev->rx_ring[i].type ==
+					TX_Q ? "TX_Q" : "",
+					qdev->rx_ring[i].type ==
+					RX_Q ? "RX_Q" : "", intr_context->name);
+			}
+		} else {
+			QPRINTK(qdev, IFUP, DEBUG,
+				"trying msi or legacy interrupts.\n");
+			QPRINTK(qdev, IFUP, DEBUG,
+				"%s: irq = %d.\n", __func__, pdev->irq);
+			QPRINTK(qdev, IFUP, DEBUG,
+				"%s: context->name = %s.\n", __func__,
+			       intr_context->name);
+			QPRINTK(qdev, IFUP, DEBUG,
+				"%s: dev_id = 0x%p.\n", __func__,
+			       &qdev->rx_ring[0]);
+			status =
+			    request_irq(pdev->irq, qlge_isr,
+					test_bit(QL_MSI_ENABLED,
+						 &qdev->
+						 flags) ? 0 : IRQF_SHARED,
+					intr_context->name, &qdev->rx_ring[0]);
+			if (status)
+				goto err_irq;
+
+			QPRINTK(qdev, IFUP, ERR,
+				"Hooked intr %d, queue type %s%s%s, with name %s.\n",
+				i,
+				qdev->rx_ring[0].type ==
+				DEFAULT_Q ? "DEFAULT_Q" : "",
+				qdev->rx_ring[0].type == TX_Q ? "TX_Q" : "",
+				qdev->rx_ring[0].type == RX_Q ? "RX_Q" : "",
+				intr_context->name);
+		}
+		intr_context->hooked = 1;
+	}
+	return status;
+err_irq:
+	QPRINTK(qdev, IFUP, ERR, "Failed to get the interrupts!!!/n");
+	ql_free_irq(qdev);
+	return status;
+}
+
+static int ql_start_rss(struct ql_adapter *qdev)
+{
+	struct ricb *ricb = &qdev->ricb;
+	int status = 0;
+	int i;
+	u8 *hash_id = (u8 *) ricb->hash_cq_id;
+
+	memset((void *)ricb, 0, sizeof(ricb));
+
+	ricb->base_cq = qdev->rss_ring_first_cq_id | RSS_L4K;
+	ricb->flags =
+	    (RSS_L6K | RSS_LI | RSS_LB | RSS_LM | RSS_RI4 | RSS_RI6 | RSS_RT4 |
+	     RSS_RT6);
+	ricb->mask = cpu_to_le16(qdev->rss_ring_count - 1);
+
+	/*
+	 * Fill out the Indirection Table.
+	 */
+	for (i = 0; i < 32; i++)
+		hash_id[i] = i & 1;
+
+	/*
+	 * Random values for the IPv6 and IPv4 Hash Keys.
+	 */
+	get_random_bytes((void *)&ricb->ipv6_hash_key[0], 40);
+	get_random_bytes((void *)&ricb->ipv4_hash_key[0], 16);
+
+	QPRINTK(qdev, IFUP, INFO, "Initializing RSS.\n");
+
+	status = ql_write_cfg(qdev, ricb, sizeof(ricb), CFG_LR, 0);
+	if (status) {
+		QPRINTK(qdev, IFUP, ERR, "Failed to load RICB.\n");
+		return status;
+	}
+	QPRINTK(qdev, IFUP, INFO, "Successfully loaded RICB.\n");
+	return status;
+}
+
+/* Initialize the frame-to-queue routing. */
+static int ql_route_initialize(struct ql_adapter *qdev)
+{
+	int status = 0;
+	int i;
+
+	/* Clear all the entries in the routing table. */
+	for (i = 0; i < 16; i++) {
+		status = ql_set_routing_reg(qdev, i, 0, 0);
+		if (status) {
+			QPRINTK(qdev, IFUP, ERR,
+				"Failed to init routing register for CAM packets.\n");
+			return status;
+		}
+	}
+
+	status = ql_set_routing_reg(qdev, RT_IDX_ALL_ERR_SLOT, RT_IDX_ERR, 1);
+	if (status) {
+		QPRINTK(qdev, IFUP, ERR,
+			"Failed to init routing register for error packets.\n");
+		return status;
+	}
+	status = ql_set_routing_reg(qdev, RT_IDX_BCAST_SLOT, RT_IDX_BCAST, 1);
+	if (status) {
+		QPRINTK(qdev, IFUP, ERR,
+			"Failed to init routing register for broadcast packets.\n");
+		return status;
+	}
+	/* If we have more than one inbound queue, then turn on RSS in the
+	 * routing block.
+	 */
+	if (qdev->rss_ring_count > 1) {
+		status = ql_set_routing_reg(qdev, RT_IDX_RSS_MATCH_SLOT,
+					RT_IDX_RSS_MATCH, 1);
+		if (status) {
+			QPRINTK(qdev, IFUP, ERR,
+				"Failed to init routing register for MATCH RSS packets.\n");
+			return status;
+		}
+	}
+
+	status = ql_set_routing_reg(qdev, RT_IDX_CAM_HIT_SLOT,
+				    RT_IDX_CAM_HIT, 1);
+	if (status) {
+		QPRINTK(qdev, IFUP, ERR,
+			"Failed to init routing register for CAM packets.\n");
+		return status;
+	}
+	return status;
+}
+
+static int ql_adapter_initialize(struct ql_adapter *qdev)
+{
+	u32 value, mask;
+	int i;
+	int status = 0;
+
+	/*
+	 * Set up the System register to halt on errors.
+	 */
+	value = SYS_EFE | SYS_FAE;
+	mask = value << 16;
+	ql_write32(qdev, SYS, mask | value);
+
+	/* Set the default queue. */
+	value = NIC_RCV_CFG_DFQ;
+	mask = NIC_RCV_CFG_DFQ_MASK;
+	ql_write32(qdev, NIC_RCV_CFG, (mask | value));
+
+	/* Set the MPI interrupt to enabled. */
+	ql_write32(qdev, INTR_MASK, (INTR_MASK_PI << 16) | INTR_MASK_PI);
+
+	/* Enable the function, set pagesize, enable error checking. */
+	value = FSC_FE | FSC_EPC_INBOUND | FSC_EPC_OUTBOUND |
+	    FSC_EC | FSC_VM_PAGE_4K | FSC_SH;
+
+	/* Set/clear header splitting. */
+	mask = FSC_VM_PAGESIZE_MASK |
+	    FSC_DBL_MASK | FSC_DBRST_MASK | (value << 16);
+	ql_write32(qdev, FSC, mask | value);
+
+	ql_write32(qdev, SPLT_HDR, SPLT_HDR_EP |
+		min(SMALL_BUFFER_SIZE, MAX_SPLIT_SIZE));
+
+	/* Start up the rx queues. */
+	for (i = 0; i < qdev->rx_ring_count; i++) {
+		status = ql_start_rx_ring(qdev, &qdev->rx_ring[i]);
+		if (status) {
+			QPRINTK(qdev, IFUP, ERR,
+				"Failed to start rx ring[%d].\n", i);
+			return status;
+		}
+	}
+
+	/* If there is more than one inbound completion queue
+	 * then download a RICB to configure RSS.
+	 */
+	if (qdev->rss_ring_count > 1) {
+		status = ql_start_rss(qdev);
+		if (status) {
+			QPRINTK(qdev, IFUP, ERR, "Failed to start RSS.\n");
+			return status;
+		}
+	}
+
+	/* Start up the tx queues. */
+	for (i = 0; i < qdev->tx_ring_count; i++) {
+		status = ql_start_tx_ring(qdev, &qdev->tx_ring[i]);
+		if (status) {
+			QPRINTK(qdev, IFUP, ERR,
+				"Failed to start tx ring[%d].\n", i);
+			return status;
+		}
+	}
+
+	status = ql_port_initialize(qdev);
+	if (status) {
+		QPRINTK(qdev, IFUP, ERR, "Failed to start port.\n");
+		return status;
+	}
+
+	status = ql_set_mac_addr_reg(qdev, (u8 *) qdev->ndev->perm_addr,
+				     MAC_ADDR_TYPE_CAM_MAC, qdev->func);
+	if (status) {
+		QPRINTK(qdev, IFUP, ERR, "Failed to init mac address.\n");
+		return status;
+	}
+
+	status = ql_route_initialize(qdev);
+	if (status) {
+		QPRINTK(qdev, IFUP, ERR, "Failed to init routing table.\n");
+		return status;
+	}
+
+	/* Start NAPI for the RSS queues. */
+	for (i = qdev->rss_ring_first_cq_id; i < qdev->rx_ring_count; i++) {
+		QPRINTK(qdev, IFUP, INFO, "Enabling NAPI for rx_ring[%d].\n",
+			i);
+		napi_enable(&qdev->rx_ring[i].napi);
+	}
+
+	return status;
+}
+
+/* Issue soft reset to chip. */
+static int ql_adapter_reset(struct ql_adapter *qdev)
+{
+	u32 value;
+	int max_wait_time;
+	int status = 0;
+	int resetCnt = 0;
+
+#define MAX_RESET_CNT   1
+issueReset:
+	resetCnt++;
+	QPRINTK(qdev, IFDOWN, DEBUG, "Issue soft reset to chip.\n");
+	ql_write32(qdev, RST_FO, (RST_FO_FR << 16) | RST_FO_FR);
+	/* Wait for reset to complete. */
+	max_wait_time = 3;
+	QPRINTK(qdev, IFDOWN, DEBUG, "Wait %d seconds for reset to complete.\n",
+		max_wait_time);
+	do {
+		value = ql_read32(qdev, RST_FO);
+		if ((value & RST_FO_FR) == 0)
+			break;
+
+		ssleep(1);
+	} while ((--max_wait_time));
+	if (value & RST_FO_FR) {
+		QPRINTK(qdev, IFDOWN, ERR,
+			"Stuck in SoftReset:  FSC_SR:0x%08x\n", value);
+		if (resetCnt < MAX_RESET_CNT)
+			goto issueReset;
+	}
+	if (max_wait_time == 0) {
+		status = -ETIMEDOUT;
+		QPRINTK(qdev, IFDOWN, ERR,
+			"ETIMEOUT!!! errored out of resetting the chip!\n");
+	}
+
+	return status;
+}
+
+static void ql_display_dev_info(struct net_device *ndev)
+{
+	struct ql_adapter *qdev = (struct ql_adapter *)netdev_priv(ndev);
+
+	QPRINTK(qdev, PROBE, INFO,
+		"Function #%d, NIC Roll %d, NIC Rev = %d, "
+		"XG Roll = %d, XG Rev = %d.\n",
+		qdev->func,
+		qdev->chip_rev_id & 0x0000000f,
+		qdev->chip_rev_id >> 4 & 0x0000000f,
+		qdev->chip_rev_id >> 8 & 0x0000000f,
+		qdev->chip_rev_id >> 12 & 0x0000000f);
+	QPRINTK(qdev, PROBE, INFO,
+		"MAC address %02x:%02x:%02x:%02x:%02x:%02x\n",
+		ndev->dev_addr[0], ndev->dev_addr[1],
+		ndev->dev_addr[2], ndev->dev_addr[3], ndev->dev_addr[4],
+		ndev->dev_addr[5]);
+}
+
+static int ql_adapter_down(struct ql_adapter *qdev)
+{
+	struct net_device *ndev = qdev->ndev;
+	int i, status = 0;
+	struct rx_ring *rx_ring;
+
+	netif_stop_queue(ndev);
+	netif_carrier_off(ndev);
+
+	cancel_delayed_work_sync(&qdev->asic_reset_work);
+	cancel_delayed_work_sync(&qdev->mpi_reset_work);
+	cancel_delayed_work_sync(&qdev->mpi_work);
+
+	/* The default queue at index 0 is always processed in
+	 * a workqueue.
+	 */
+	cancel_delayed_work_sync(&qdev->rx_ring[0].rx_work);
+
+	/* The rest of the rx_rings are processed in
+	 * a workqueue only if it's a single interrupt
+	 * environment (MSI/Legacy).
+	 */
+	for (i = 1; i > qdev->rx_ring_count; i++) {
+		rx_ring = &qdev->rx_ring[i];
+		/* Only the RSS rings use NAPI on multi irq
+		 * environment.  Outbound completion processing
+		 * is done in interrupt context.
+		 */
+		if (i >= qdev->rss_ring_first_cq_id) {
+			napi_disable(&rx_ring->napi);
+		} else {
+			cancel_delayed_work_sync(&rx_ring->rx_work);
+		}
+	}
+
+	clear_bit(QL_ADAPTER_UP, &qdev->flags);
+
+	ql_disable_interrupts(qdev);
+
+	ql_tx_ring_clean(qdev);
+
+	spin_lock(&qdev->hw_lock);
+	status = ql_adapter_reset(qdev);
+	if (status)
+		QPRINTK(qdev, IFDOWN, ERR, "reset(func #%d) FAILED!\n",
+			qdev->func);
+	spin_unlock(&qdev->hw_lock);
+	return status;
+}
+
+static int ql_adapter_up(struct ql_adapter *qdev)
+{
+	int err = 0;
+
+	spin_lock(&qdev->hw_lock);
+	err = ql_adapter_initialize(qdev);
+	if (err) {
+		QPRINTK(qdev, IFUP, INFO, "Unable to initialize adapter.\n");
+		spin_unlock(&qdev->hw_lock);
+		goto err_init;
+	}
+	spin_unlock(&qdev->hw_lock);
+	set_bit(QL_ADAPTER_UP, &qdev->flags);
+	ql_enable_interrupts(qdev);
+	ql_enable_all_completion_interrupts(qdev);
+	if ((ql_read32(qdev, STS) & qdev->port_init)) {
+		netif_carrier_on(qdev->ndev);
+		netif_start_queue(qdev->ndev);
+	}
+
+	return 0;
+err_init:
+	ql_adapter_reset(qdev);
+	return err;
+}
+
+static int ql_cycle_adapter(struct ql_adapter *qdev)
+{
+	int status;
+
+	status = ql_adapter_down(qdev);
+	if (status)
+		goto error;
+
+	status = ql_adapter_up(qdev);
+	if (status)
+		goto error;
+
+	return status;
+error:
+	QPRINTK(qdev, IFUP, ALERT,
+		"Driver up/down cycle failed, closing device\n");
+	rtnl_lock();
+	dev_close(qdev->ndev);
+	rtnl_unlock();
+	return status;
+}
+
+static void ql_release_adapter_resources(struct ql_adapter *qdev)
+{
+	ql_free_mem_resources(qdev);
+	ql_free_irq(qdev);
+}
+
+static int ql_get_adapter_resources(struct ql_adapter *qdev)
+{
+	int status = 0;
+
+	if (ql_alloc_mem_resources(qdev)) {
+		QPRINTK(qdev, IFUP, ERR, "Unable to  allocate memory.\n");
+		return -ENOMEM;
+	}
+	status = ql_request_irq(qdev);
+	if (status)
+		goto err_irq;
+	return status;
+err_irq:
+	ql_free_mem_resources(qdev);
+	return status;
+}
+
+static int qlge_close(struct net_device *ndev)
+{
+	struct ql_adapter *qdev = netdev_priv(ndev);
+
+	/*
+	 * Wait for device to recover from a reset.
+	 * (Rarely happens, but possible.)
+	 */
+	while (!test_bit(QL_ADAPTER_UP, &qdev->flags))
+		msleep(1);
+	ql_adapter_down(qdev);
+	ql_release_adapter_resources(qdev);
+	ql_free_ring_cb(qdev);
+	return 0;
+}
+
+static int ql_configure_rings(struct ql_adapter *qdev)
+{
+	int i;
+	struct rx_ring *rx_ring;
+	struct tx_ring *tx_ring;
+	int cpu_cnt = num_online_cpus();
+
+	/*
+	 * For each processor present we allocate one
+	 * rx_ring for outbound completions, and one
+	 * rx_ring for inbound completions.  Plus there is
+	 * always the one default queue.  For the CPU
+	 * counts we end up with the following rx_rings:
+	 * rx_ring count =
+	 *  one default queue +
+	 *  (CPU count * outbound completion rx_ring) +
+	 *  (CPU count * inbound (RSS) completion rx_ring)
+	 * To keep it simple we limit the total number of
+	 * queues to < 32, so we truncate CPU to 8.
+	 * This limitation can be removed when requested.
+	 */
+
+	if (cpu_cnt > 8)
+		cpu_cnt = 8;
+
+	/*
+	 * rx_ring[0] is always the default queue.
+	 */
+	/* Allocate outbound completion ring for each CPU. */
+	qdev->tx_ring_count = cpu_cnt;
+	/* Allocate inbound completion (RSS) ring for each CPU. */
+	qdev->rss_ring_count = cpu_cnt;
+	/* cq_id for the first inbound ring handler. */
+	qdev->rss_ring_first_cq_id = cpu_cnt + 1;
+	/*
+	 * qdev->rx_ring_count:
+	 * Total number of rx_rings.  This includes the one
+	 * default queue, a number of outbound completion
+	 * handler rx_rings, and the number of inbound
+	 * completion handler rx_rings.
+	 */
+	qdev->rx_ring_count = qdev->tx_ring_count + qdev->rss_ring_count + 1;
+
+	if (ql_alloc_ring_cb(qdev))
+		return -ENOMEM;
+
+	for (i = 0; i < qdev->tx_ring_count; i++) {
+		tx_ring = &qdev->tx_ring[i];
+		memset((void *)tx_ring, 0, sizeof(tx_ring));
+		tx_ring->qdev = qdev;
+		tx_ring->wq_id = i;
+		tx_ring->wq_len = qdev->tx_ring_size;
+		tx_ring->wq_size =
+		    tx_ring->wq_len * sizeof(struct ob_mac_iocb_req);
+
+		/*
+		 * The completion queue ID for the tx rings start
+		 * immediately after the default Q ID, which is zero.
+		 */
+		tx_ring->cq_id = i + 1;
+	}
+
+	for (i = 0; i < qdev->rx_ring_count; i++) {
+		rx_ring = &qdev->rx_ring[i];
+		memset((void *)rx_ring, 0, sizeof(rx_ring));
+		rx_ring->qdev = qdev;
+		rx_ring->cq_id = i;
+		rx_ring->cpu = i % cpu_cnt;	/* CPU to run handler on. */
+		if (i == 0) {	/* Default queue at index 0. */
+			/*
+			 * Default queue handles bcast/mcast plus
+			 * async events.  Needs buffers.
+			 */
+			rx_ring->cq_len = qdev->rx_ring_size;
+			rx_ring->cq_size =
+			    rx_ring->cq_len * sizeof(struct ql_net_rsp_iocb);
+			rx_ring->lbq_len = NUM_LARGE_BUFFERS;
+			rx_ring->lbq_size =
+			    rx_ring->lbq_len * sizeof(struct bq_element);
+			rx_ring->lbq_buf_size = LARGE_BUFFER_SIZE;
+			rx_ring->sbq_len = NUM_SMALL_BUFFERS;
+			rx_ring->sbq_size =
+			    rx_ring->sbq_len * sizeof(struct bq_element);
+			rx_ring->sbq_buf_size = SMALL_BUFFER_SIZE * 2;
+			rx_ring->type = DEFAULT_Q;
+		} else if (i < qdev->rss_ring_first_cq_id) {
+			/*
+			 * Outbound queue handles outbound completions only.
+			 */
+			/* outbound cq is same size as tx_ring it services. */
+			rx_ring->cq_len = qdev->tx_ring_size;
+			rx_ring->cq_size =
+			    rx_ring->cq_len * sizeof(struct ql_net_rsp_iocb);
+			rx_ring->lbq_len = 0;
+			rx_ring->lbq_size = 0;
+			rx_ring->lbq_buf_size = 0;
+			rx_ring->sbq_len = 0;
+			rx_ring->sbq_size = 0;
+			rx_ring->sbq_buf_size = 0;
+			rx_ring->type = TX_Q;
+		} else {	/* Inbound completions (RSS) queues */
+			/*
+			 * Inbound queues handle unicast frames only.
+			 */
+			rx_ring->cq_len = qdev->rx_ring_size;
+			rx_ring->cq_size =
+			    rx_ring->cq_len * sizeof(struct ql_net_rsp_iocb);
+			rx_ring->lbq_len = NUM_LARGE_BUFFERS;
+			rx_ring->lbq_size =
+			    rx_ring->lbq_len * sizeof(struct bq_element);
+			rx_ring->lbq_buf_size = LARGE_BUFFER_SIZE;
+			rx_ring->sbq_len = NUM_SMALL_BUFFERS;
+			rx_ring->sbq_size =
+			    rx_ring->sbq_len * sizeof(struct bq_element);
+			rx_ring->sbq_buf_size = SMALL_BUFFER_SIZE * 2;
+			rx_ring->type = RX_Q;
+		}
+	}
+	return 0;
+}
+
+static int qlge_open(struct net_device *ndev)
+{
+	int err = 0;
+	struct ql_adapter *qdev = netdev_priv(ndev);
+
+	err = ql_configure_rings(qdev);
+	if (err)
+		return err;
+
+	err = ql_get_adapter_resources(qdev);
+	if (err)
+		goto error_up;
+
+	err = ql_adapter_up(qdev);
+	if (err)
+		goto error_up;
+
+	return err;
+
+error_up:
+	ql_release_adapter_resources(qdev);
+	ql_free_ring_cb(qdev);
+	return err;
+}
+
+static int qlge_change_mtu(struct net_device *ndev, int new_mtu)
+{
+	struct ql_adapter *qdev = netdev_priv(ndev);
+
+	if (ndev->mtu == 1500 && new_mtu == 9000) {
+		QPRINTK(qdev, IFUP, ERR, "Changing to jumbo MTU.\n");
+	} else if (ndev->mtu == 9000 && new_mtu == 1500) {
+		QPRINTK(qdev, IFUP, ERR, "Changing to normal MTU.\n");
+	} else if ((ndev->mtu == 1500 && new_mtu == 1500) ||
+		   (ndev->mtu == 9000 && new_mtu == 9000)) {
+		return 0;
+	} else
+		return -EINVAL;
+	ndev->mtu = new_mtu;
+	return 0;
+}
+
+static struct net_device_stats *qlge_get_stats(struct net_device
+					       *ndev)
+{
+	struct ql_adapter *qdev = netdev_priv(ndev);
+	return &qdev->stats;
+}
+
+static void qlge_set_multicast_list(struct net_device *ndev)
+{
+	struct ql_adapter *qdev = (struct ql_adapter *)netdev_priv(ndev);
+	struct dev_mc_list *mc_ptr;
+	int i;
+
+	spin_lock(&qdev->hw_lock);
+	/*
+	 * Set or clear promiscuous mode if a
+	 * transition is taking place.
+	 */
+	if (ndev->flags & IFF_PROMISC) {
+		if (!test_bit(QL_PROMISCUOUS, &qdev->flags)) {
+			if (ql_set_routing_reg
+			    (qdev, RT_IDX_PROMISCUOUS_SLOT, RT_IDX_VALID, 1)) {
+				QPRINTK(qdev, HW, ERR,
+					"Failed to set promiscous mode.\n");
+			} else {
+				set_bit(QL_PROMISCUOUS, &qdev->flags);
+			}
+		}
+	} else {
+		if (test_bit(QL_PROMISCUOUS, &qdev->flags)) {
+			if (ql_set_routing_reg
+			    (qdev, RT_IDX_PROMISCUOUS_SLOT, RT_IDX_VALID, 0)) {
+				QPRINTK(qdev, HW, ERR,
+					"Failed to clear promiscous mode.\n");
+			} else {
+				clear_bit(QL_PROMISCUOUS, &qdev->flags);
+			}
+		}
+	}
+
+	/*
+	 * Set or clear all multicast mode if a
+	 * transition is taking place.
+	 */
+	if ((ndev->flags & IFF_ALLMULTI) ||
+	    (ndev->mc_count > MAX_MULTICAST_ENTRIES)) {
+		if (!test_bit(QL_ALLMULTI, &qdev->flags)) {
+			if (ql_set_routing_reg
+			    (qdev, RT_IDX_ALLMULTI_SLOT, RT_IDX_MCAST, 1)) {
+				QPRINTK(qdev, HW, ERR,
+					"Failed to set all-multi mode.\n");
+			} else {
+				set_bit(QL_ALLMULTI, &qdev->flags);
+			}
+		}
+	} else {
+		if (test_bit(QL_ALLMULTI, &qdev->flags)) {
+			if (ql_set_routing_reg
+			    (qdev, RT_IDX_ALLMULTI_SLOT, RT_IDX_MCAST, 0)) {
+				QPRINTK(qdev, HW, ERR,
+					"Failed to clear all-multi mode.\n");
+			} else {
+				clear_bit(QL_ALLMULTI, &qdev->flags);
+			}
+		}
+	}
+
+	if (ndev->mc_count) {
+		for (i = 0, mc_ptr = ndev->mc_list; mc_ptr;
+		     i++, mc_ptr = mc_ptr->next)
+			if (ql_set_mac_addr_reg(qdev, (u8 *) mc_ptr->dmi_addr,
+						MAC_ADDR_TYPE_MULTI_MAC, i)) {
+				QPRINTK(qdev, HW, ERR,
+					"Failed to loadmulticast address.\n");
+				goto exit;
+			}
+		if (ql_set_routing_reg
+		    (qdev, RT_IDX_MCAST_MATCH_SLOT, RT_IDX_MCAST_MATCH, 1)) {
+			QPRINTK(qdev, HW, ERR,
+				"Failed to set multicast match mode.\n");
+		} else {
+			set_bit(QL_ALLMULTI, &qdev->flags);
+		}
+	}
+exit:
+	spin_unlock(&qdev->hw_lock);
+}
+
+static int qlge_set_mac_address(struct net_device *ndev, void *p)
+{
+	struct ql_adapter *qdev = (struct ql_adapter *)netdev_priv(ndev);
+	struct sockaddr *addr = p;
+
+	if (netif_running(ndev))
+		return -EBUSY;
+
+	if (!is_valid_ether_addr(addr->sa_data))
+		return -EADDRNOTAVAIL;
+	memcpy(ndev->dev_addr, addr->sa_data, ndev->addr_len);
+
+	spin_lock(&qdev->hw_lock);
+	if (ql_set_mac_addr_reg(qdev, (u8 *) ndev->dev_addr,
+			MAC_ADDR_TYPE_CAM_MAC, qdev->func)) {/* Unicast */
+		QPRINTK(qdev, HW, ERR, "Failed to load MAC address.\n");
+		return -1;
+	}
+	spin_unlock(&qdev->hw_lock);
+
+	return 0;
+}
+
+static void qlge_tx_timeout(struct net_device *ndev)
+{
+	struct ql_adapter *qdev = (struct ql_adapter *)netdev_priv(ndev);
+	queue_delayed_work(qdev->workqueue, &qdev->asic_reset_work, 0);
+}
+
+static void ql_asic_reset_work(struct work_struct *work)
+{
+	struct ql_adapter *qdev =
+	    container_of(work, struct ql_adapter, asic_reset_work.work);
+	ql_cycle_adapter(qdev);
+}
+
+static void ql_get_board_info(struct ql_adapter *qdev)
+{
+	qdev->func =
+	    (ql_read32(qdev, STS) & STS_FUNC_ID_MASK) >> STS_FUNC_ID_SHIFT;
+	if (qdev->func) {
+		qdev->xg_sem_mask = SEM_XGMAC1_MASK;
+		qdev->port_link_up = STS_PL1;
+		qdev->port_init = STS_PI1;
+		qdev->mailbox_in = PROC_ADDR_MPI_RISC | PROC_ADDR_FUNC2_MBI;
+		qdev->mailbox_out = PROC_ADDR_MPI_RISC | PROC_ADDR_FUNC2_MBO;
+	} else {
+		qdev->xg_sem_mask = SEM_XGMAC0_MASK;
+		qdev->port_link_up = STS_PL0;
+		qdev->port_init = STS_PI0;
+		qdev->mailbox_in = PROC_ADDR_MPI_RISC | PROC_ADDR_FUNC0_MBI;
+		qdev->mailbox_out = PROC_ADDR_MPI_RISC | PROC_ADDR_FUNC0_MBO;
+	}
+	qdev->chip_rev_id = ql_read32(qdev, REV_ID);
+}
+
+static void ql_release_all(struct pci_dev *pdev)
+{
+	struct net_device *ndev = pci_get_drvdata(pdev);
+	struct ql_adapter *qdev = netdev_priv(ndev);
+
+	if (qdev->workqueue) {
+		destroy_workqueue(qdev->workqueue);
+		qdev->workqueue = NULL;
+	}
+	if (qdev->q_workqueue) {
+		destroy_workqueue(qdev->q_workqueue);
+		qdev->q_workqueue = NULL;
+	}
+	if (qdev->reg_base)
+		iounmap((void *)qdev->reg_base);
+	if (qdev->doorbell_area)
+		iounmap(qdev->doorbell_area);
+	pci_release_regions(pdev);
+	pci_set_drvdata(pdev, NULL);
+}
+
+static int __devinit ql_init_device(struct pci_dev *pdev,
+				    struct net_device *ndev, int cards_found)
+{
+	struct ql_adapter *qdev = netdev_priv(ndev);
+	int pos, err = 0;
+	u16 val16;
+
+	memset((void *)qdev, 0, sizeof(qdev));
+	err = pci_enable_device(pdev);
+	if (err) {
+		dev_err(&pdev->dev, "PCI device enable failed.\n");
+		return err;
+	}
+
+	pos = pci_find_capability(pdev, PCI_CAP_ID_EXP);
+	if (pos <= 0) {
+		dev_err(&pdev->dev, PFX "Cannot find PCI Express capability, "
+			"aborting.\n");
+		goto err_out;
+	} else {
+		pci_read_config_word(pdev, pos + PCI_EXP_DEVCTL, &val16);
+		val16 &= ~PCI_EXP_DEVCTL_NOSNOOP_EN;
+		val16 |= (PCI_EXP_DEVCTL_CERE |
+			  PCI_EXP_DEVCTL_NFERE |
+			  PCI_EXP_DEVCTL_FERE | PCI_EXP_DEVCTL_URRE);
+		pci_write_config_word(pdev, pos + PCI_EXP_DEVCTL, val16);
+	}
+
+	err = pci_request_regions(pdev, DRV_NAME);
+	if (err) {
+		dev_err(&pdev->dev, "PCI region request failed.\n");
+		goto err_out;
+	}
+
+	pci_set_master(pdev);
+	if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK)) {
+		set_bit(QL_DMA64, &qdev->flags);
+		err = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK);
+	} else {
+		err = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
+		if (!err)
+		       err = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
+	}
+
+	if (err) {
+		dev_err(&pdev->dev, "No usable DMA configuration.\n");
+		goto err_out;
+	}
+
+	pci_set_drvdata(pdev, ndev);
+	qdev->reg_base =
+	    ioremap_nocache(pci_resource_start(pdev, 1),
+			    pci_resource_len(pdev, 1));
+	if (!qdev->reg_base) {
+		dev_err(&pdev->dev, "Register mapping failed.\n");
+		err = -ENOMEM;
+		goto err_out;
+	}
+
+	qdev->doorbell_area_size = pci_resource_len(pdev, 3);
+	qdev->doorbell_area =
+	    ioremap_nocache(pci_resource_start(pdev, 3),
+			    pci_resource_len(pdev, 3));
+	if (!qdev->doorbell_area) {
+		dev_err(&pdev->dev, "Doorbell register mapping failed.\n");
+		err = -ENOMEM;
+		goto err_out;
+	}
+
+	ql_get_board_info(qdev);
+	qdev->ndev = ndev;
+	qdev->pdev = pdev;
+	qdev->msg_enable = netif_msg_init(debug, default_msg);
+	spin_lock_init(&qdev->hw_lock);
+	spin_lock_init(&qdev->stats_lock);
+
+	/* make sure the EEPROM is good */
+	err = ql_get_flash_params(qdev);
+	if (err) {
+		dev_err(&pdev->dev, "Invalid FLASH.\n");
+		goto err_out;
+	}
+
+	if (!is_valid_ether_addr(qdev->flash.mac_addr))
+		goto err_out;
+
+	memcpy(ndev->dev_addr, qdev->flash.mac_addr, ndev->addr_len);
+	memcpy(ndev->perm_addr, ndev->dev_addr, ndev->addr_len);
+
+	/* Set up the default ring sizes. */
+	qdev->tx_ring_size = NUM_TX_RING_ENTRIES;
+	qdev->rx_ring_size = NUM_RX_RING_ENTRIES;
+
+	/* Set up the coalescing parameters. */
+	qdev->rx_coalesce_usecs = DFLT_COALESCE_WAIT;
+	qdev->tx_coalesce_usecs = DFLT_COALESCE_WAIT;
+	qdev->rx_max_coalesced_frames = DFLT_INTER_FRAME_WAIT;
+	qdev->tx_max_coalesced_frames = DFLT_INTER_FRAME_WAIT;
+
+	/*
+	 * Set up the operating parameters.
+	 */
+	qdev->rx_csum = 1;
+
+	qdev->q_workqueue = create_workqueue(ndev->name);
+	qdev->workqueue = create_singlethread_workqueue(ndev->name);
+	INIT_DELAYED_WORK(&qdev->asic_reset_work, ql_asic_reset_work);
+	INIT_DELAYED_WORK(&qdev->mpi_reset_work, ql_mpi_reset_work);
+	INIT_DELAYED_WORK(&qdev->mpi_work, ql_mpi_work);
+
+	if (!cards_found) {
+		dev_info(&pdev->dev, "%s\n", DRV_STRING);
+		dev_info(&pdev->dev, "Driver name: %s, Version: %s.\n",
+			 DRV_NAME, DRV_VERSION);
+	}
+	return 0;
+err_out:
+	ql_release_all(pdev);
+	pci_disable_device(pdev);
+	return err;
+}
+
+static int __devinit qlge_probe(struct pci_dev *pdev,
+				const struct pci_device_id *pci_entry)
+{
+	struct net_device *ndev = NULL;
+	struct ql_adapter *qdev = NULL;
+	static int cards_found = 0;
+	int err = 0;
+
+	ndev = alloc_etherdev(sizeof(struct ql_adapter));
+	if (!ndev)
+		return -ENOMEM;
+
+	err = ql_init_device(pdev, ndev, cards_found);
+	if (err < 0) {
+		free_netdev(ndev);
+		return err;
+	}
+
+	qdev = netdev_priv(ndev);
+	SET_NETDEV_DEV(ndev, &pdev->dev);
+	ndev->features = (0
+			  | NETIF_F_IP_CSUM
+			  | NETIF_F_SG
+			  | NETIF_F_TSO
+			  | NETIF_F_TSO6
+			  | NETIF_F_TSO_ECN
+			  | NETIF_F_HW_VLAN_TX
+			  | NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_FILTER);
+
+	if (test_bit(QL_DMA64, &qdev->flags))
+		ndev->features |= NETIF_F_HIGHDMA;
+
+	/*
+	 * Set up net_device structure.
+	 */
+	ndev->tx_queue_len = qdev->tx_ring_size;
+	ndev->irq = pdev->irq;
+	ndev->open = qlge_open;
+	ndev->stop = qlge_close;
+	ndev->hard_start_xmit = qlge_send;
+	SET_ETHTOOL_OPS(ndev, &qlge_ethtool_ops);
+	ndev->change_mtu = qlge_change_mtu;
+	ndev->get_stats = qlge_get_stats;
+	ndev->set_multicast_list = qlge_set_multicast_list;
+	ndev->set_mac_address = qlge_set_mac_address;
+	ndev->tx_timeout = qlge_tx_timeout;
+	ndev->watchdog_timeo = 10 * HZ;
+	ndev->vlan_rx_register = ql_vlan_rx_register;
+	ndev->vlan_rx_add_vid = ql_vlan_rx_add_vid;
+	ndev->vlan_rx_kill_vid = ql_vlan_rx_kill_vid;
+	err = register_netdev(ndev);
+	if (err) {
+		dev_err(&pdev->dev, "net device registration failed.\n");
+		ql_release_all(pdev);
+		pci_disable_device(pdev);
+		return err;
+	}
+	netif_carrier_off(ndev);
+	netif_stop_queue(ndev);
+	ql_display_dev_info(ndev);
+	cards_found++;
+	return 0;
+}
+
+static void __devexit qlge_remove(struct pci_dev *pdev)
+{
+	struct net_device *ndev = pci_get_drvdata(pdev);
+	unregister_netdev(ndev);
+	ql_release_all(pdev);
+	pci_disable_device(pdev);
+	free_netdev(ndev);
+}
+
+/*
+ * This callback is called by the PCI subsystem whenever
+ * a PCI bus error is detected.
+ */
+static pci_ers_result_t qlge_io_error_detected(struct pci_dev *pdev,
+					       enum pci_channel_state state)
+{
+	struct net_device *ndev = pci_get_drvdata(pdev);
+	struct ql_adapter *qdev = netdev_priv(ndev);
+
+	if (netif_running(ndev))
+		ql_adapter_down(qdev);
+
+	pci_disable_device(pdev);
+
+	/* Request a slot reset. */
+	return PCI_ERS_RESULT_NEED_RESET;
+}
+
+/*
+ * This callback is called after the PCI buss has been reset.
+ * Basically, this tries to restart the card from scratch.
+ * This is a shortened version of the device probe/discovery code,
+ * it resembles the first-half of the () routine.
+ */
+static pci_ers_result_t qlge_io_slot_reset(struct pci_dev *pdev)
+{
+	struct net_device *ndev = pci_get_drvdata(pdev);
+	struct ql_adapter *qdev = netdev_priv(ndev);
+
+	if (pci_enable_device(pdev)) {
+		QPRINTK(qdev, IFUP, ERR,
+			"Cannot re-enable PCI device after reset.\n");
+		return PCI_ERS_RESULT_DISCONNECT;
+	}
+
+	pci_set_master(pdev);
+
+	netif_carrier_off(ndev);
+	netif_stop_queue(ndev);
+	ql_adapter_reset(qdev);
+
+	/* Make sure the EEPROM is good */
+	memcpy(ndev->perm_addr, ndev->dev_addr, ndev->addr_len);
+
+	if (!is_valid_ether_addr(ndev->perm_addr)) {
+		QPRINTK(qdev, IFUP, ERR, "After reset, invalid MAC address.\n");
+		return PCI_ERS_RESULT_DISCONNECT;
+	}
+
+	return PCI_ERS_RESULT_RECOVERED;
+}
+
+static void qlge_io_resume(struct pci_dev *pdev)
+{
+	struct net_device *ndev = pci_get_drvdata(pdev);
+	struct ql_adapter *qdev = netdev_priv(ndev);
+
+	pci_set_master(pdev);
+
+	if (netif_running(ndev)) {
+		if (ql_adapter_up(qdev)) {
+			QPRINTK(qdev, IFUP, ERR,
+				"Device initialization failed after reset.\n");
+			return;
+		}
+	}
+
+	netif_device_attach(ndev);
+}
+
+static struct pci_error_handlers qlge_err_handler = {
+	.error_detected = qlge_io_error_detected,
+	.slot_reset = qlge_io_slot_reset,
+	.resume = qlge_io_resume,
+};
+
+static int qlge_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+	struct net_device *ndev = pci_get_drvdata(pdev);
+	struct ql_adapter *qdev = netdev_priv(ndev);
+	int err;
+
+	netif_device_detach(ndev);
+
+	if (netif_running(ndev)) {
+		err = ql_adapter_down(qdev);
+		if (!err)
+			return err;
+	}
+
+	err = pci_save_state(pdev);
+	if (err)
+		return err;
+
+	pci_disable_device(pdev);
+
+	pci_set_power_state(pdev, pci_choose_state(pdev, state));
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int qlge_resume(struct pci_dev *pdev)
+{
+	struct net_device *ndev = pci_get_drvdata(pdev);
+	struct ql_adapter *qdev = netdev_priv(ndev);
+	int err;
+
+	pci_set_power_state(pdev, PCI_D0);
+	pci_restore_state(pdev);
+	err = pci_enable_device(pdev);
+	if (err) {
+		QPRINTK(qdev, IFUP, ERR, "Cannot enable PCI device from suspend\n");
+		return err;
+	}
+	pci_set_master(pdev);
+
+	pci_enable_wake(pdev, PCI_D3hot, 0);
+	pci_enable_wake(pdev, PCI_D3cold, 0);
+
+	if (netif_running(ndev)) {
+		err = ql_adapter_up(qdev);
+		if (err)
+			return err;
+	}
+
+	netif_device_attach(ndev);
+
+	return 0;
+}
+#endif /* CONFIG_PM */
+
+static void qlge_shutdown(struct pci_dev *pdev)
+{
+	qlge_suspend(pdev, PMSG_SUSPEND);
+}
+
+static struct pci_driver qlge_driver = {
+	.name = DRV_NAME,
+	.id_table = qlge_pci_tbl,
+	.probe = qlge_probe,
+	.remove = __devexit_p(qlge_remove),
+#ifdef CONFIG_PM
+	.suspend = qlge_suspend,
+	.resume = qlge_resume,
+#endif
+	.shutdown = qlge_shutdown,
+	.err_handler = &qlge_err_handler
+};
+
+static int __init qlge_init_module(void)
+{
+	return pci_register_driver(&qlge_driver);
+}
+
+static void __exit qlge_exit(void)
+{
+	pci_unregister_driver(&qlge_driver);
+}
+
+module_init(qlge_init_module);
+module_exit(qlge_exit);
diff --git a/drivers/net/qlge/qlge_mpi.c b/drivers/net/qlge/qlge_mpi.c
new file mode 100644
index 0000000..24fe344
--- /dev/null
+++ b/drivers/net/qlge/qlge_mpi.c
@@ -0,0 +1,150 @@
+#include "qlge.h"
+
+static int ql_read_mbox_reg(struct ql_adapter *qdev, u32 reg, u32 *data)
+{
+	int status;
+	/* wait for reg to come ready */
+	status = ql_wait_reg_rdy(qdev, PROC_ADDR, PROC_ADDR_RDY, PROC_ADDR_ERR);
+	if (status)
+		goto exit;
+	/* set up for reg read */
+	ql_write32(qdev, PROC_ADDR, reg | PROC_ADDR_R);
+	/* wait for reg to come ready */
+	status = ql_wait_reg_rdy(qdev, PROC_ADDR, PROC_ADDR_RDY, PROC_ADDR_ERR);
+	if (status)
+		goto exit;
+	/* get the data */
+	*data = ql_read32(qdev, PROC_DATA);
+exit:
+	return status;
+}
+
+int ql_get_mb_sts(struct ql_adapter *qdev, struct mbox_params *mbcp)
+{
+	int i, status;
+
+	status = ql_sem_spinlock(qdev, SEM_PROC_REG_MASK);
+	if (status)
+		return -EBUSY;
+	for (i = 0; i < mbcp->out_count; i++) {
+		status =
+		    ql_read_mbox_reg(qdev, qdev->mailbox_out + i,
+				     &mbcp->mbox_out[i]);
+		if (status) {
+			QPRINTK(qdev, DRV, ERR, "Failed mailbox read.\n");
+			break;
+		}
+	}
+	ql_sem_unlock(qdev, SEM_PROC_REG_MASK);	/* does flush too */
+	return status;
+}
+
+static void ql_link_up(struct ql_adapter *qdev, struct mbox_params *mbcp)
+{
+	mbcp->out_count = 2;
+
+	if (ql_get_mb_sts(qdev, mbcp))
+		goto exit;
+
+	qdev->link_status = mbcp->mbox_out[1];
+	QPRINTK(qdev, DRV, ERR, "Link Up.\n");
+	QPRINTK(qdev, DRV, INFO, "Link Status = 0x%.08x.\n", mbcp->mbox_out[1]);
+	if (!netif_carrier_ok(qdev->ndev)) {
+		QPRINTK(qdev, LINK, INFO, "Link is Up.\n");
+		netif_carrier_on(qdev->ndev);
+		netif_wake_queue(qdev->ndev);
+	}
+exit:
+	/* Clear the MPI firmware status. */
+	ql_write32(qdev, CSR, CSR_CMD_CLR_R2PCI_INT);
+}
+
+static void ql_link_down(struct ql_adapter *qdev, struct mbox_params *mbcp)
+{
+	mbcp->out_count = 3;
+
+	if (ql_get_mb_sts(qdev, mbcp)) {
+		QPRINTK(qdev, DRV, ERR, "Firmware did not initialize!\n");
+		goto exit;
+	}
+
+	if (netif_carrier_ok(qdev->ndev)) {
+		QPRINTK(qdev, LINK, INFO, "Link is Down.\n");
+		netif_carrier_off(qdev->ndev);
+		netif_stop_queue(qdev->ndev);
+	}
+	QPRINTK(qdev, DRV, ERR, "Link Down.\n");
+	QPRINTK(qdev, DRV, ERR, "Link Status = 0x%.08x.\n", mbcp->mbox_out[1]);
+exit:
+	/* Clear the MPI firmware status. */
+	ql_write32(qdev, CSR, CSR_CMD_CLR_R2PCI_INT);
+}
+
+static void ql_init_fw_done(struct ql_adapter *qdev, struct mbox_params *mbcp)
+{
+	mbcp->out_count = 2;
+
+	if (ql_get_mb_sts(qdev, mbcp)) {
+		QPRINTK(qdev, DRV, ERR, "Firmware did not initialize!\n");
+		goto exit;
+	}
+	QPRINTK(qdev, DRV, ERR, "Firmware initialized!\n");
+	QPRINTK(qdev, DRV, ERR, "Firmware status = 0x%.08x.\n",
+		mbcp->mbox_out[0]);
+	QPRINTK(qdev, DRV, ERR, "Firmware Revision  = 0x%.08x.\n",
+		mbcp->mbox_out[1]);
+exit:
+	/* Clear the MPI firmware status. */
+	ql_write32(qdev, CSR, CSR_CMD_CLR_R2PCI_INT);
+}
+
+void ql_mpi_work(struct work_struct *work)
+{
+	struct ql_adapter *qdev =
+	    container_of(work, struct ql_adapter, mpi_work.work);
+	struct mbox_params mbc;
+	struct mbox_params *mbcp = &mbc;
+	mbcp->out_count = 1;
+
+	while (ql_read32(qdev, STS) & STS_PI) {
+		if (ql_get_mb_sts(qdev, mbcp)) {
+			QPRINTK(qdev, DRV, ERR,
+				"Could not read MPI, resetting ASIC!\n");
+			ql_queue_asic_error(qdev);
+		}
+
+		switch (mbcp->mbox_out[0]) {
+		case AEN_LINK_UP:
+			ql_link_up(qdev, mbcp);
+			break;
+		case AEN_LINK_DOWN:
+			ql_link_down(qdev, mbcp);
+			break;
+		case AEN_FW_INIT_DONE:
+			ql_init_fw_done(qdev, mbcp);
+			break;
+		case MB_CMD_STS_GOOD:
+			break;
+		case AEN_FW_INIT_FAIL:
+		case AEN_SYS_ERR:
+		case MB_CMD_STS_ERR:
+			ql_queue_fw_error(qdev);
+		default:
+			/* Clear the MPI firmware status. */
+			ql_write32(qdev, CSR, CSR_CMD_CLR_R2PCI_INT);
+			break;
+		}
+	}
+	ql_enable_completion_interrupt(qdev, 0);
+}
+
+void ql_mpi_reset_work(struct work_struct *work)
+{
+	struct ql_adapter *qdev =
+	    container_of(work, struct ql_adapter, mpi_reset_work.work);
+	QPRINTK(qdev, DRV, ERR,
+		"Enter, qdev = %p..\n", qdev);
+	ql_write32(qdev, CSR, CSR_CMD_SET_RST);
+	msleep(50);
+	ql_write32(qdev, CSR, CSR_CMD_CLR_RST);
+}
diff --git a/drivers/net/r6040.c b/drivers/net/r6040.c
index 5d86281..34fe7ef 100644
--- a/drivers/net/r6040.c
+++ b/drivers/net/r6040.c
@@ -265,7 +265,7 @@
 				le32_to_cpu(lp->tx_insert_ptr->buf),
 				MAX_BUF_SIZE, PCI_DMA_TODEVICE);
 			dev_kfree_skb(lp->tx_insert_ptr->skb_ptr);
-			lp->rx_insert_ptr->skb_ptr = NULL;
+			lp->tx_insert_ptr->skb_ptr = NULL;
 		}
 		lp->tx_insert_ptr = lp->tx_insert_ptr->vndescp;
 	}
@@ -370,7 +370,7 @@
 	/* Reset internal state machine */
 	iowrite16(2, ioaddr + MAC_SM);
 	iowrite16(0, ioaddr + MAC_SM);
-	udelay(5000);
+	mdelay(5);
 
 	/* MAC Bus Control Register */
 	iowrite16(MBCR_DEFAULT, ioaddr + MBCR);
@@ -806,7 +806,7 @@
 	iowrite16(0x01, ioaddr + MCR1); /* Reset MAC */
 	iowrite16(2, ioaddr + MAC_SM); /* Reset internal state machine */
 	iowrite16(0, ioaddr + MAC_SM);
-	udelay(5000);
+	mdelay(5);
 
 	/* Restore MAC Address */
 	adrp = (u16 *) dev->dev_addr;
diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c
index 0f6f974..c821da2 100644
--- a/drivers/net/r8169.c
+++ b/drivers/net/r8169.c
@@ -36,7 +36,7 @@
 #define assert(expr) \
 	if (!(expr)) {					\
 		printk( "Assertion failed! %s,%s,%s,line=%d\n",	\
-		#expr,__FILE__,__FUNCTION__,__LINE__);		\
+		#expr,__FILE__,__func__,__LINE__);		\
 	}
 #define dprintk(fmt, args...) \
 	do { printk(KERN_DEBUG PFX fmt, ## args); } while (0)
@@ -61,6 +61,7 @@
 /* MAC address length */
 #define MAC_ADDR_LEN	6
 
+#define MAX_READ_REQUEST_SHIFT	12
 #define RX_FIFO_THRESH	7	/* 7 means NO threshold, Rx buffer level before first PCI xfer. */
 #define RX_DMA_BURST	6	/* Maximum PCI burst, '6' is 1024 */
 #define TX_DMA_BURST	6	/* Maximum PCI burst, '6' is 1024 */
@@ -95,6 +96,10 @@
 	RTL_GIGA_MAC_VER_04 = 0x04, // 8169SB
 	RTL_GIGA_MAC_VER_05 = 0x05, // 8110SCd
 	RTL_GIGA_MAC_VER_06 = 0x06, // 8110SCe
+	RTL_GIGA_MAC_VER_07 = 0x07, // 8102e
+	RTL_GIGA_MAC_VER_08 = 0x08, // 8102e
+	RTL_GIGA_MAC_VER_09 = 0x09, // 8102e
+	RTL_GIGA_MAC_VER_10 = 0x0a, // 8101e
 	RTL_GIGA_MAC_VER_11 = 0x0b, // 8168Bb
 	RTL_GIGA_MAC_VER_12 = 0x0c, // 8168Be
 	RTL_GIGA_MAC_VER_13 = 0x0d, // 8101Eb
@@ -104,7 +109,12 @@
 	RTL_GIGA_MAC_VER_17 = 0x10, // 8168Bf
 	RTL_GIGA_MAC_VER_18 = 0x12, // 8168CP
 	RTL_GIGA_MAC_VER_19 = 0x13, // 8168C
-	RTL_GIGA_MAC_VER_20 = 0x14  // 8168C
+	RTL_GIGA_MAC_VER_20 = 0x14, // 8168C
+	RTL_GIGA_MAC_VER_21 = 0x15, // 8168C
+	RTL_GIGA_MAC_VER_22 = 0x16, // 8168C
+	RTL_GIGA_MAC_VER_23 = 0x17, // 8168CP
+	RTL_GIGA_MAC_VER_24 = 0x18, // 8168CP
+	RTL_GIGA_MAC_VER_25 = 0x19  // 8168D
 };
 
 #define _R(NAME,MAC,MASK) \
@@ -121,6 +131,10 @@
 	_R("RTL8169sb/8110sb",	RTL_GIGA_MAC_VER_04, 0xff7e1880), // 8169SB
 	_R("RTL8169sc/8110sc",	RTL_GIGA_MAC_VER_05, 0xff7e1880), // 8110SCd
 	_R("RTL8169sc/8110sc",	RTL_GIGA_MAC_VER_06, 0xff7e1880), // 8110SCe
+	_R("RTL8102e",		RTL_GIGA_MAC_VER_07, 0xff7e1880), // PCI-E
+	_R("RTL8102e",		RTL_GIGA_MAC_VER_08, 0xff7e1880), // PCI-E
+	_R("RTL8102e",		RTL_GIGA_MAC_VER_09, 0xff7e1880), // PCI-E
+	_R("RTL8101e",		RTL_GIGA_MAC_VER_10, 0xff7e1880), // PCI-E
 	_R("RTL8168b/8111b",	RTL_GIGA_MAC_VER_11, 0xff7e1880), // PCI-E
 	_R("RTL8168b/8111b",	RTL_GIGA_MAC_VER_12, 0xff7e1880), // PCI-E
 	_R("RTL8101e",		RTL_GIGA_MAC_VER_13, 0xff7e1880), // PCI-E 8139
@@ -130,7 +144,12 @@
 	_R("RTL8101e",		RTL_GIGA_MAC_VER_16, 0xff7e1880), // PCI-E
 	_R("RTL8168cp/8111cp",	RTL_GIGA_MAC_VER_18, 0xff7e1880), // PCI-E
 	_R("RTL8168c/8111c",	RTL_GIGA_MAC_VER_19, 0xff7e1880), // PCI-E
-	_R("RTL8168c/8111c",	RTL_GIGA_MAC_VER_20, 0xff7e1880)  // PCI-E
+	_R("RTL8168c/8111c",	RTL_GIGA_MAC_VER_20, 0xff7e1880), // PCI-E
+	_R("RTL8168c/8111c",	RTL_GIGA_MAC_VER_21, 0xff7e1880), // PCI-E
+	_R("RTL8168c/8111c",	RTL_GIGA_MAC_VER_22, 0xff7e1880), // PCI-E
+	_R("RTL8168cp/8111cp",	RTL_GIGA_MAC_VER_23, 0xff7e1880), // PCI-E
+	_R("RTL8168cp/8111cp",	RTL_GIGA_MAC_VER_24, 0xff7e1880), // PCI-E
+	_R("RTL8168d/8111d",	RTL_GIGA_MAC_VER_25, 0xff7e1880)  // PCI-E
 };
 #undef _R
 
@@ -196,9 +215,6 @@
 	Config5		= 0x56,
 	MultiIntr	= 0x5c,
 	PHYAR		= 0x60,
-	TBICSR		= 0x64,
-	TBI_ANAR	= 0x68,
-	TBI_LPAR	= 0x6a,
 	PHYstatus	= 0x6c,
 	RxMaxSize	= 0xda,
 	CPlusCmd	= 0xe0,
@@ -212,6 +228,32 @@
 	FuncForceEvent	= 0xfc,
 };
 
+enum rtl8110_registers {
+	TBICSR			= 0x64,
+	TBI_ANAR		= 0x68,
+	TBI_LPAR		= 0x6a,
+};
+
+enum rtl8168_8101_registers {
+	CSIDR			= 0x64,
+	CSIAR			= 0x68,
+#define	CSIAR_FLAG			0x80000000
+#define	CSIAR_WRITE_CMD			0x80000000
+#define	CSIAR_BYTE_ENABLE		0x0f
+#define	CSIAR_BYTE_ENABLE_SHIFT		12
+#define	CSIAR_ADDR_MASK			0x0fff
+
+	EPHYAR			= 0x80,
+#define	EPHYAR_FLAG			0x80000000
+#define	EPHYAR_WRITE_CMD		0x80000000
+#define	EPHYAR_REG_MASK			0x1f
+#define	EPHYAR_REG_SHIFT		16
+#define	EPHYAR_DATA_MASK		0xffff
+	DBG_REG			= 0xd1,
+#define	FIX_NAK_1			(1 << 4)
+#define	FIX_NAK_2			(1 << 3)
+};
+
 enum rtl_register_content {
 	/* InterruptStatusBits */
 	SYSErr		= 0x8000,
@@ -265,7 +307,13 @@
 	TxDMAShift = 8,	/* DMA burst value (0-7) is shift this many bits */
 
 	/* Config1 register p.24 */
+	LEDS1		= (1 << 7),
+	LEDS0		= (1 << 6),
 	MSIEnable	= (1 << 5),	/* Enable Message Signaled Interrupt */
+	Speed_down	= (1 << 4),
+	MEMMAP		= (1 << 3),
+	IOMAP		= (1 << 2),
+	VPD		= (1 << 1),
 	PMEnable	= (1 << 0),	/* Power Management Enable */
 
 	/* Config2 register p. 25 */
@@ -275,6 +323,7 @@
 	/* Config3 register p.25 */
 	MagicPacket	= (1 << 5),	/* Wake up when receives a Magic Packet */
 	LinkUp		= (1 << 4),	/* Wake up when the cable connection is re-established */
+	Beacon_en	= (1 << 0),	/* 8168 only. Reserved in the 8168b */
 
 	/* Config5 register p.27 */
 	BWF		= (1 << 6),	/* Accept Broadcast wakeup frame */
@@ -292,7 +341,16 @@
 	TBINwComplete	= 0x01000000,
 
 	/* CPlusCmd p.31 */
-	PktCntrDisable	= (1 << 7),	// 8168
+	EnableBist	= (1 << 15),	// 8168 8101
+	Mac_dbgo_oe	= (1 << 14),	// 8168 8101
+	Normal_mode	= (1 << 13),	// unused
+	Force_half_dup	= (1 << 12),	// 8168 8101
+	Force_rxflow_en	= (1 << 11),	// 8168 8101
+	Force_txflow_en	= (1 << 10),	// 8168 8101
+	Cxpl_dbg_sel	= (1 << 9),	// 8168 8101
+	ASF		= (1 << 8),	// 8168 8101
+	PktCntrDisable	= (1 << 7),	// 8168 8101
+	Mac_dbgo_sel	= 0x001c,	// 8168
 	RxVlan		= (1 << 6),
 	RxChkSum	= (1 << 5),
 	PCIDAC		= (1 << 4),
@@ -370,8 +428,9 @@
 };
 
 enum features {
-	RTL_FEATURE_WOL	= (1 << 0),
-	RTL_FEATURE_MSI	= (1 << 1),
+	RTL_FEATURE_WOL		= (1 << 0),
+	RTL_FEATURE_MSI		= (1 << 1),
+	RTL_FEATURE_GMII	= (1 << 2),
 };
 
 struct rtl8169_private {
@@ -406,13 +465,16 @@
 	struct vlan_group *vlgrp;
 #endif
 	int (*set_speed)(struct net_device *, u8 autoneg, u16 speed, u8 duplex);
-	void (*get_settings)(struct net_device *, struct ethtool_cmd *);
+	int (*get_settings)(struct net_device *, struct ethtool_cmd *);
 	void (*phy_reset_enable)(void __iomem *);
 	void (*hw_start)(struct net_device *);
 	unsigned int (*phy_reset_pending)(void __iomem *);
 	unsigned int (*link_ok)(void __iomem *);
+	int pcie_cap;
 	struct delayed_work task;
 	unsigned features;
+
+	struct mii_if_info mii;
 };
 
 MODULE_AUTHOR("Realtek and the Linux r8169 crew <netdev@vger.kernel.org>");
@@ -482,6 +544,94 @@
 	return value;
 }
 
+static void mdio_patch(void __iomem *ioaddr, int reg_addr, int value)
+{
+	mdio_write(ioaddr, reg_addr, mdio_read(ioaddr, reg_addr) | value);
+}
+
+static void rtl_mdio_write(struct net_device *dev, int phy_id, int location,
+			   int val)
+{
+	struct rtl8169_private *tp = netdev_priv(dev);
+	void __iomem *ioaddr = tp->mmio_addr;
+
+	mdio_write(ioaddr, location, val);
+}
+
+static int rtl_mdio_read(struct net_device *dev, int phy_id, int location)
+{
+	struct rtl8169_private *tp = netdev_priv(dev);
+	void __iomem *ioaddr = tp->mmio_addr;
+
+	return mdio_read(ioaddr, location);
+}
+
+static void rtl_ephy_write(void __iomem *ioaddr, int reg_addr, int value)
+{
+	unsigned int i;
+
+	RTL_W32(EPHYAR, EPHYAR_WRITE_CMD | (value & EPHYAR_DATA_MASK) |
+		(reg_addr & EPHYAR_REG_MASK) << EPHYAR_REG_SHIFT);
+
+	for (i = 0; i < 100; i++) {
+		if (!(RTL_R32(EPHYAR) & EPHYAR_FLAG))
+			break;
+		udelay(10);
+	}
+}
+
+static u16 rtl_ephy_read(void __iomem *ioaddr, int reg_addr)
+{
+	u16 value = 0xffff;
+	unsigned int i;
+
+	RTL_W32(EPHYAR, (reg_addr & EPHYAR_REG_MASK) << EPHYAR_REG_SHIFT);
+
+	for (i = 0; i < 100; i++) {
+		if (RTL_R32(EPHYAR) & EPHYAR_FLAG) {
+			value = RTL_R32(EPHYAR) & EPHYAR_DATA_MASK;
+			break;
+		}
+		udelay(10);
+	}
+
+	return value;
+}
+
+static void rtl_csi_write(void __iomem *ioaddr, int addr, int value)
+{
+	unsigned int i;
+
+	RTL_W32(CSIDR, value);
+	RTL_W32(CSIAR, CSIAR_WRITE_CMD | (addr & CSIAR_ADDR_MASK) |
+		CSIAR_BYTE_ENABLE << CSIAR_BYTE_ENABLE_SHIFT);
+
+	for (i = 0; i < 100; i++) {
+		if (!(RTL_R32(CSIAR) & CSIAR_FLAG))
+			break;
+		udelay(10);
+	}
+}
+
+static u32 rtl_csi_read(void __iomem *ioaddr, int addr)
+{
+	u32 value = ~0x00;
+	unsigned int i;
+
+	RTL_W32(CSIAR, (addr & CSIAR_ADDR_MASK) |
+		CSIAR_BYTE_ENABLE << CSIAR_BYTE_ENABLE_SHIFT);
+
+	for (i = 0; i < 100; i++) {
+		if (RTL_R32(CSIAR) & CSIAR_FLAG) {
+			value = RTL_R32(CSIDR);
+			break;
+		}
+		udelay(10);
+	}
+
+	return value;
+}
+
 static void rtl8169_irq_mask_and_ack(void __iomem *ioaddr)
 {
 	RTL_W16(IntrMask, 0x0000);
@@ -619,6 +769,7 @@
 		tp->features |= RTL_FEATURE_WOL;
 	else
 		tp->features &= ~RTL_FEATURE_WOL;
+	device_set_wakeup_enable(&tp->pci_dev->dev, wol->wolopts);
 
 	spin_unlock_irq(&tp->lock);
 
@@ -705,8 +856,12 @@
 		}
 	}
 
-	/* The 8100e/8101e do Fast Ethernet only. */
-	if ((tp->mac_version == RTL_GIGA_MAC_VER_13) ||
+	/* The 8100e/8101e/8102e do Fast Ethernet only. */
+	if ((tp->mac_version == RTL_GIGA_MAC_VER_07) ||
+	    (tp->mac_version == RTL_GIGA_MAC_VER_08) ||
+	    (tp->mac_version == RTL_GIGA_MAC_VER_09) ||
+	    (tp->mac_version == RTL_GIGA_MAC_VER_10) ||
+	    (tp->mac_version == RTL_GIGA_MAC_VER_13) ||
 	    (tp->mac_version == RTL_GIGA_MAC_VER_14) ||
 	    (tp->mac_version == RTL_GIGA_MAC_VER_15) ||
 	    (tp->mac_version == RTL_GIGA_MAC_VER_16)) {
@@ -720,9 +875,13 @@
 
 	auto_nego |= ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM;
 
-	if ((tp->mac_version == RTL_GIGA_MAC_VER_12) ||
-	    (tp->mac_version == RTL_GIGA_MAC_VER_17)) {
-		/* Vendor specific (0x1f) and reserved (0x0e) MII registers. */
+	if ((tp->mac_version == RTL_GIGA_MAC_VER_11) ||
+	    (tp->mac_version == RTL_GIGA_MAC_VER_12) ||
+	    (tp->mac_version >= RTL_GIGA_MAC_VER_17)) {
+		/*
+		 * Wake up the PHY.
+		 * Vendor specific (0x1f) and reserved (0x0e) MII registers.
+		 */
 		mdio_write(ioaddr, 0x1f, 0x0000);
 		mdio_write(ioaddr, 0x0e, 0x0000);
 	}
@@ -850,7 +1009,7 @@
 
 #endif
 
-static void rtl8169_gset_tbi(struct net_device *dev, struct ethtool_cmd *cmd)
+static int rtl8169_gset_tbi(struct net_device *dev, struct ethtool_cmd *cmd)
 {
 	struct rtl8169_private *tp = netdev_priv(dev);
 	void __iomem *ioaddr = tp->mmio_addr;
@@ -867,65 +1026,29 @@
 
 	cmd->speed = SPEED_1000;
 	cmd->duplex = DUPLEX_FULL; /* Always set */
+
+	return 0;
 }
 
-static void rtl8169_gset_xmii(struct net_device *dev, struct ethtool_cmd *cmd)
+static int rtl8169_gset_xmii(struct net_device *dev, struct ethtool_cmd *cmd)
 {
 	struct rtl8169_private *tp = netdev_priv(dev);
-	void __iomem *ioaddr = tp->mmio_addr;
-	u8 status;
 
-	cmd->supported = SUPPORTED_10baseT_Half |
-			 SUPPORTED_10baseT_Full |
-			 SUPPORTED_100baseT_Half |
-			 SUPPORTED_100baseT_Full |
-			 SUPPORTED_1000baseT_Full |
-			 SUPPORTED_Autoneg |
-			 SUPPORTED_TP;
-
-	cmd->autoneg = 1;
-	cmd->advertising = ADVERTISED_TP | ADVERTISED_Autoneg;
-
-	if (tp->phy_auto_nego_reg & ADVERTISE_10HALF)
-		cmd->advertising |= ADVERTISED_10baseT_Half;
-	if (tp->phy_auto_nego_reg & ADVERTISE_10FULL)
-		cmd->advertising |= ADVERTISED_10baseT_Full;
-	if (tp->phy_auto_nego_reg & ADVERTISE_100HALF)
-		cmd->advertising |= ADVERTISED_100baseT_Half;
-	if (tp->phy_auto_nego_reg & ADVERTISE_100FULL)
-		cmd->advertising |= ADVERTISED_100baseT_Full;
-	if (tp->phy_1000_ctrl_reg & ADVERTISE_1000FULL)
-		cmd->advertising |= ADVERTISED_1000baseT_Full;
-
-	status = RTL_R8(PHYstatus);
-
-	if (status & _1000bpsF)
-		cmd->speed = SPEED_1000;
-	else if (status & _100bps)
-		cmd->speed = SPEED_100;
-	else if (status & _10bps)
-		cmd->speed = SPEED_10;
-
-	if (status & TxFlowCtrl)
-		cmd->advertising |= ADVERTISED_Asym_Pause;
-	if (status & RxFlowCtrl)
-		cmd->advertising |= ADVERTISED_Pause;
-
-	cmd->duplex = ((status & _1000bpsF) || (status & FullDup)) ?
-		      DUPLEX_FULL : DUPLEX_HALF;
+	return mii_ethtool_gset(&tp->mii, cmd);
 }
 
 static int rtl8169_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 {
 	struct rtl8169_private *tp = netdev_priv(dev);
 	unsigned long flags;
+	int rc;
 
 	spin_lock_irqsave(&tp->lock, flags);
 
-	tp->get_settings(dev, cmd);
+	rc = tp->get_settings(dev, cmd);
 
 	spin_unlock_irqrestore(&tp->lock, flags);
-	return 0;
+	return rc;
 }
 
 static void rtl8169_get_regs(struct net_device *dev, struct ethtool_regs *regs,
@@ -1103,11 +1226,19 @@
 		u32 val;
 		int mac_version;
 	} mac_info[] = {
-		/* 8168B family. */
-		{ 0x7c800000, 0x3c800000,	RTL_GIGA_MAC_VER_18 },
+		/* 8168D family. */
+		{ 0x7c800000, 0x28000000,	RTL_GIGA_MAC_VER_25 },
+
+		/* 8168C family. */
+		{ 0x7cf00000, 0x3ca00000,	RTL_GIGA_MAC_VER_24 },
+		{ 0x7cf00000, 0x3c900000,	RTL_GIGA_MAC_VER_23 },
+		{ 0x7cf00000, 0x3c800000,	RTL_GIGA_MAC_VER_18 },
+		{ 0x7c800000, 0x3c800000,	RTL_GIGA_MAC_VER_24 },
 		{ 0x7cf00000, 0x3c000000,	RTL_GIGA_MAC_VER_19 },
 		{ 0x7cf00000, 0x3c200000,	RTL_GIGA_MAC_VER_20 },
-		{ 0x7c800000, 0x3c000000,	RTL_GIGA_MAC_VER_20 },
+		{ 0x7cf00000, 0x3c300000,	RTL_GIGA_MAC_VER_21 },
+		{ 0x7cf00000, 0x3c400000,	RTL_GIGA_MAC_VER_22 },
+		{ 0x7c800000, 0x3c000000,	RTL_GIGA_MAC_VER_22 },
 
 		/* 8168B family. */
 		{ 0x7cf00000, 0x38000000,	RTL_GIGA_MAC_VER_12 },
@@ -1116,8 +1247,17 @@
 		{ 0x7c800000, 0x30000000,	RTL_GIGA_MAC_VER_11 },
 
 		/* 8101 family. */
+		{ 0x7cf00000, 0x34a00000,	RTL_GIGA_MAC_VER_09 },
+		{ 0x7cf00000, 0x24a00000,	RTL_GIGA_MAC_VER_09 },
+		{ 0x7cf00000, 0x34900000,	RTL_GIGA_MAC_VER_08 },
+		{ 0x7cf00000, 0x24900000,	RTL_GIGA_MAC_VER_08 },
+		{ 0x7cf00000, 0x34800000,	RTL_GIGA_MAC_VER_07 },
+		{ 0x7cf00000, 0x24800000,	RTL_GIGA_MAC_VER_07 },
 		{ 0x7cf00000, 0x34000000,	RTL_GIGA_MAC_VER_13 },
+		{ 0x7cf00000, 0x34300000,	RTL_GIGA_MAC_VER_10 },
 		{ 0x7cf00000, 0x34200000,	RTL_GIGA_MAC_VER_16 },
+		{ 0x7c800000, 0x34800000,	RTL_GIGA_MAC_VER_09 },
+		{ 0x7c800000, 0x24800000,	RTL_GIGA_MAC_VER_09 },
 		{ 0x7c800000, 0x34000000,	RTL_GIGA_MAC_VER_16 },
 		/* FIXME: where did these entries come from ? -- FR */
 		{ 0xfc800000, 0x38800000,	RTL_GIGA_MAC_VER_15 },
@@ -1228,7 +1368,31 @@
 	rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init));
 }
 
-static void rtl8168cp_hw_phy_config(void __iomem *ioaddr)
+static void rtl8168bb_hw_phy_config(void __iomem *ioaddr)
+{
+	struct phy_reg phy_reg_init[] = {
+		{ 0x10, 0xf41b },
+		{ 0x1f, 0x0000 }
+	};
+
+	mdio_write(ioaddr, 0x1f, 0x0001);
+	mdio_patch(ioaddr, 0x16, 1 << 0);
+
+	rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init));
+}
+
+static void rtl8168bef_hw_phy_config(void __iomem *ioaddr)
+{
+	struct phy_reg phy_reg_init[] = {
+		{ 0x1f, 0x0001 },
+		{ 0x10, 0xf41b },
+		{ 0x1f, 0x0000 }
+	};
+
+	rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init));
+}
+
+static void rtl8168cp_1_hw_phy_config(void __iomem *ioaddr)
 {
 	struct phy_reg phy_reg_init[] = {
 		{ 0x1f, 0x0000 },
@@ -1241,7 +1405,22 @@
 	rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init));
 }
 
-static void rtl8168c_hw_phy_config(void __iomem *ioaddr)
+static void rtl8168cp_2_hw_phy_config(void __iomem *ioaddr)
+{
+	struct phy_reg phy_reg_init[] = {
+		{ 0x1f, 0x0001 },
+		{ 0x1d, 0x3d98 },
+		{ 0x1f, 0x0000 }
+	};
+
+	mdio_write(ioaddr, 0x1f, 0x0000);
+	mdio_patch(ioaddr, 0x14, 1 << 5);
+	mdio_patch(ioaddr, 0x0d, 1 << 5);
+
+	rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init));
+}
+
+static void rtl8168c_1_hw_phy_config(void __iomem *ioaddr)
 {
 	struct phy_reg phy_reg_init[] = {
 		{ 0x1f, 0x0001 },
@@ -1257,26 +1436,158 @@
 		{ 0x1f, 0x0003 },
 		{ 0x12, 0xc096 },
 		{ 0x16, 0x000a },
+		{ 0x1f, 0x0000 },
+		{ 0x1f, 0x0000 },
+		{ 0x09, 0x2000 },
+		{ 0x09, 0x0000 }
+	};
+
+	rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init));
+
+	mdio_patch(ioaddr, 0x14, 1 << 5);
+	mdio_patch(ioaddr, 0x0d, 1 << 5);
+	mdio_write(ioaddr, 0x1f, 0x0000);
+}
+
+static void rtl8168c_2_hw_phy_config(void __iomem *ioaddr)
+{
+	struct phy_reg phy_reg_init[] = {
+		{ 0x1f, 0x0001 },
+		{ 0x12, 0x2300 },
+		{ 0x03, 0x802f },
+		{ 0x02, 0x4f02 },
+		{ 0x01, 0x0409 },
+		{ 0x00, 0xf099 },
+		{ 0x04, 0x9800 },
+		{ 0x04, 0x9000 },
+		{ 0x1d, 0x3d98 },
+		{ 0x1f, 0x0002 },
+		{ 0x0c, 0x7eb8 },
+		{ 0x06, 0x0761 },
+		{ 0x1f, 0x0003 },
+		{ 0x16, 0x0f0a },
 		{ 0x1f, 0x0000 }
 	};
 
 	rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init));
+
+	mdio_patch(ioaddr, 0x16, 1 << 0);
+	mdio_patch(ioaddr, 0x14, 1 << 5);
+	mdio_patch(ioaddr, 0x0d, 1 << 5);
+	mdio_write(ioaddr, 0x1f, 0x0000);
 }
 
-static void rtl8168cx_hw_phy_config(void __iomem *ioaddr)
+static void rtl8168c_3_hw_phy_config(void __iomem *ioaddr)
 {
 	struct phy_reg phy_reg_init[] = {
-		{ 0x1f, 0x0000 },
+		{ 0x1f, 0x0001 },
 		{ 0x12, 0x2300 },
-		{ 0x1f, 0x0003 },
-		{ 0x16, 0x0f0a },
-		{ 0x1f, 0x0000 },
+		{ 0x1d, 0x3d98 },
 		{ 0x1f, 0x0002 },
 		{ 0x0c, 0x7eb8 },
+		{ 0x06, 0x5461 },
+		{ 0x1f, 0x0003 },
+		{ 0x16, 0x0f0a },
 		{ 0x1f, 0x0000 }
 	};
 
 	rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init));
+
+	mdio_patch(ioaddr, 0x16, 1 << 0);
+	mdio_patch(ioaddr, 0x14, 1 << 5);
+	mdio_patch(ioaddr, 0x0d, 1 << 5);
+	mdio_write(ioaddr, 0x1f, 0x0000);
+}
+
+static void rtl8168c_4_hw_phy_config(void __iomem *ioaddr)
+{
+	rtl8168c_3_hw_phy_config(ioaddr);
+}
+
+static void rtl8168d_hw_phy_config(void __iomem *ioaddr)
+{
+	struct phy_reg phy_reg_init_0[] = {
+		{ 0x1f, 0x0001 },
+		{ 0x09, 0x2770 },
+		{ 0x08, 0x04d0 },
+		{ 0x0b, 0xad15 },
+		{ 0x0c, 0x5bf0 },
+		{ 0x1c, 0xf101 },
+		{ 0x1f, 0x0003 },
+		{ 0x14, 0x94d7 },
+		{ 0x12, 0xf4d6 },
+		{ 0x09, 0xca0f },
+		{ 0x1f, 0x0002 },
+		{ 0x0b, 0x0b10 },
+		{ 0x0c, 0xd1f7 },
+		{ 0x1f, 0x0002 },
+		{ 0x06, 0x5461 },
+		{ 0x1f, 0x0002 },
+		{ 0x05, 0x6662 },
+		{ 0x1f, 0x0000 },
+		{ 0x14, 0x0060 },
+		{ 0x1f, 0x0000 },
+		{ 0x0d, 0xf8a0 },
+		{ 0x1f, 0x0005 },
+		{ 0x05, 0xffc2 }
+	};
+
+	rtl_phy_write(ioaddr, phy_reg_init_0, ARRAY_SIZE(phy_reg_init_0));
+
+	if (mdio_read(ioaddr, 0x06) == 0xc400) {
+		struct phy_reg phy_reg_init_1[] = {
+			{ 0x1f, 0x0005 },
+			{ 0x01, 0x0300 },
+			{ 0x1f, 0x0000 },
+			{ 0x11, 0x401c },
+			{ 0x16, 0x4100 },
+			{ 0x1f, 0x0005 },
+			{ 0x07, 0x0010 },
+			{ 0x05, 0x83dc },
+			{ 0x06, 0x087d },
+			{ 0x05, 0x8300 },
+			{ 0x06, 0x0101 },
+			{ 0x06, 0x05f8 },
+			{ 0x06, 0xf9fa },
+			{ 0x06, 0xfbef },
+			{ 0x06, 0x79e2 },
+			{ 0x06, 0x835f },
+			{ 0x06, 0xe0f8 },
+			{ 0x06, 0x9ae1 },
+			{ 0x06, 0xf89b },
+			{ 0x06, 0xef31 },
+			{ 0x06, 0x3b65 },
+			{ 0x06, 0xaa07 },
+			{ 0x06, 0x81e4 },
+			{ 0x06, 0xf89a },
+			{ 0x06, 0xe5f8 },
+			{ 0x06, 0x9baf },
+			{ 0x06, 0x06ae },
+			{ 0x05, 0x83dc },
+			{ 0x06, 0x8300 },
+		};
+
+		rtl_phy_write(ioaddr, phy_reg_init_1,
+			      ARRAY_SIZE(phy_reg_init_1));
+	}
+
+	mdio_write(ioaddr, 0x1f, 0x0000);
+}
+
+static void rtl8102e_hw_phy_config(void __iomem *ioaddr)
+{
+	struct phy_reg phy_reg_init[] = {
+		{ 0x1f, 0x0003 },
+		{ 0x08, 0x441d },
+		{ 0x01, 0x9100 },
+		{ 0x1f, 0x0000 }
+	};
+
+	mdio_write(ioaddr, 0x1f, 0x0000);
+	mdio_patch(ioaddr, 0x11, 1 << 12);
+	mdio_patch(ioaddr, 0x19, 1 << 13);
+
+	rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init));
 }
 
 static void rtl_hw_phy_config(struct net_device *dev)
@@ -1296,15 +1607,43 @@
 	case RTL_GIGA_MAC_VER_04:
 		rtl8169sb_hw_phy_config(ioaddr);
 		break;
+	case RTL_GIGA_MAC_VER_07:
+	case RTL_GIGA_MAC_VER_08:
+	case RTL_GIGA_MAC_VER_09:
+		rtl8102e_hw_phy_config(ioaddr);
+		break;
+	case RTL_GIGA_MAC_VER_11:
+		rtl8168bb_hw_phy_config(ioaddr);
+		break;
+	case RTL_GIGA_MAC_VER_12:
+		rtl8168bef_hw_phy_config(ioaddr);
+		break;
+	case RTL_GIGA_MAC_VER_17:
+		rtl8168bef_hw_phy_config(ioaddr);
+		break;
 	case RTL_GIGA_MAC_VER_18:
-		rtl8168cp_hw_phy_config(ioaddr);
+		rtl8168cp_1_hw_phy_config(ioaddr);
 		break;
 	case RTL_GIGA_MAC_VER_19:
-		rtl8168c_hw_phy_config(ioaddr);
+		rtl8168c_1_hw_phy_config(ioaddr);
 		break;
 	case RTL_GIGA_MAC_VER_20:
-		rtl8168cx_hw_phy_config(ioaddr);
+		rtl8168c_2_hw_phy_config(ioaddr);
 		break;
+	case RTL_GIGA_MAC_VER_21:
+		rtl8168c_3_hw_phy_config(ioaddr);
+		break;
+	case RTL_GIGA_MAC_VER_22:
+		rtl8168c_4_hw_phy_config(ioaddr);
+		break;
+	case RTL_GIGA_MAC_VER_23:
+	case RTL_GIGA_MAC_VER_24:
+		rtl8168cp_2_hw_phy_config(ioaddr);
+		break;
+	case RTL_GIGA_MAC_VER_25:
+		rtl8168d_hw_phy_config(ioaddr);
+		break;
+
 	default:
 		break;
 	}
@@ -1513,7 +1852,7 @@
 	unsigned int align;
 	u16 intr_event;
 	u16 napi_event;
-	unsigned msi;
+	unsigned features;
 } rtl_cfg_infos [] = {
 	[RTL_CFG_0] = {
 		.hw_start	= rtl_hw_start_8169,
@@ -1522,7 +1861,7 @@
 		.intr_event	= SYSErr | LinkChg | RxOverflow |
 				  RxFIFOOver | TxErr | TxOK | RxOK | RxErr,
 		.napi_event	= RxFIFOOver | TxErr | TxOK | RxOK | RxOverflow,
-		.msi		= 0
+		.features	= RTL_FEATURE_GMII
 	},
 	[RTL_CFG_1] = {
 		.hw_start	= rtl_hw_start_8168,
@@ -1531,7 +1870,7 @@
 		.intr_event	= SYSErr | LinkChg | RxOverflow |
 				  TxErr | TxOK | RxOK | RxErr,
 		.napi_event	= TxErr | TxOK | RxOK | RxOverflow,
-		.msi		= RTL_FEATURE_MSI
+		.features	= RTL_FEATURE_GMII | RTL_FEATURE_MSI
 	},
 	[RTL_CFG_2] = {
 		.hw_start	= rtl_hw_start_8101,
@@ -1540,7 +1879,7 @@
 		.intr_event	= SYSErr | LinkChg | RxOverflow | PCSTimeout |
 				  RxFIFOOver | TxErr | TxOK | RxOK | RxErr,
 		.napi_event	= RxFIFOOver | TxErr | TxOK | RxOK | RxOverflow,
-		.msi		= RTL_FEATURE_MSI
+		.features	= RTL_FEATURE_MSI
 	}
 };
 
@@ -1552,7 +1891,7 @@
 	u8 cfg2;
 
 	cfg2 = RTL_R8(Config2) & ~MSIEnable;
-	if (cfg->msi) {
+	if (cfg->features & RTL_FEATURE_MSI) {
 		if (pci_enable_msi(pdev)) {
 			dev_info(&pdev->dev, "no MSI. Back to INTx.\n");
 		} else {
@@ -1572,12 +1911,81 @@
 	}
 }
 
+static int rtl_eeprom_read(struct pci_dev *pdev, int cap, int addr, __le32 *val)
+{
+	int ret, count = 100;
+	u16 status = 0;
+	u32 value;
+
+	ret = pci_write_config_word(pdev, cap + PCI_VPD_ADDR, addr);
+	if (ret < 0)
+		return ret;
+
+	do {
+		udelay(10);
+		ret = pci_read_config_word(pdev, cap + PCI_VPD_ADDR, &status);
+		if (ret < 0)
+			return ret;
+	} while (!(status & PCI_VPD_ADDR_F) && --count);
+
+	if (!(status & PCI_VPD_ADDR_F))
+		return -ETIMEDOUT;
+
+	ret = pci_read_config_dword(pdev, cap + PCI_VPD_DATA, &value);
+	if (ret < 0)
+		return ret;
+
+	*val = cpu_to_le32(value);
+
+	return 0;
+}
+
+static void rtl_init_mac_address(struct rtl8169_private *tp,
+				 void __iomem *ioaddr)
+{
+	struct pci_dev *pdev = tp->pci_dev;
+	u8 cfg1;
+	int vpd_cap;
+	u8 mac[8];
+	DECLARE_MAC_BUF(buf);
+
+	cfg1 = RTL_R8(Config1);
+	if (!(cfg1  & VPD)) {
+		dprintk("VPD access not enabled, enabling\n");
+		RTL_W8(Cfg9346, Cfg9346_Unlock);
+		RTL_W8(Config1, cfg1 | VPD);
+		RTL_W8(Cfg9346, Cfg9346_Lock);
+	}
+
+	vpd_cap = pci_find_capability(pdev, PCI_CAP_ID_VPD);
+	if (!vpd_cap)
+		return;
+
+	/* MAC address is stored in EEPROM at offset 0x0e
+	 * Realtek says: "The VPD address does not have to be a DWORD-aligned
+	 * address as defined in the PCI 2.2 Specifications, but the VPD data
+	 * is always consecutive 4-byte data starting from the VPD address
+	 * specified."
+	 */
+	if (rtl_eeprom_read(pdev, vpd_cap, 0x000e, (__le32*)&mac[0]) < 0 ||
+	    rtl_eeprom_read(pdev, vpd_cap, 0x0012, (__le32*)&mac[4]) < 0) {
+		dprintk("Reading MAC address from EEPROM failed\n");
+		return;
+	}
+
+	dprintk("MAC address found in EEPROM: %s\n", print_mac(buf, mac));
+
+	/* Write MAC address */
+	rtl_rar_set(tp, mac);
+}
+
 static int __devinit
 rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
 	const struct rtl_cfg_info *cfg = rtl_cfg_infos + ent->driver_data;
 	const unsigned int region = cfg->region;
 	struct rtl8169_private *tp;
+	struct mii_if_info *mii;
 	struct net_device *dev;
 	void __iomem *ioaddr;
 	unsigned int i;
@@ -1602,6 +2010,14 @@
 	tp->pci_dev = pdev;
 	tp->msg_enable = netif_msg_init(debug.msg_enable, R8169_MSG_DEFAULT);
 
+	mii = &tp->mii;
+	mii->dev = dev;
+	mii->mdio_read = rtl_mdio_read;
+	mii->mdio_write = rtl_mdio_write;
+	mii->phy_id_mask = 0x1f;
+	mii->reg_num_mask = 0x1f;
+	mii->supports_gmii = !!(cfg->features & RTL_FEATURE_GMII);
+
 	/* enable device (incl. PCI PM wakeup and hotplug setup) */
 	rc = pci_enable_device(pdev);
 	if (rc < 0) {
@@ -1670,6 +2086,10 @@
 		goto err_out_free_res_4;
 	}
 
+	tp->pcie_cap = pci_find_capability(pdev, PCI_CAP_ID_EXP);
+	if (!tp->pcie_cap && netif_msg_probe(tp))
+		dev_info(&pdev->dev, "no PCI Express capability\n");
+
 	/* Unneeded ? Don't mess with Mrs. Murphy. */
 	rtl8169_irq_mask_and_ack(ioaddr);
 
@@ -1706,6 +2126,10 @@
 	RTL_W8(Cfg9346, Cfg9346_Unlock);
 	RTL_W8(Config1, RTL_R8(Config1) | PMEnable);
 	RTL_W8(Config5, RTL_R8(Config5) & PMEStatus);
+	if ((RTL_R8(Config3) & (LinkUp | MagicPacket)) != 0)
+		tp->features |= RTL_FEATURE_WOL;
+	if ((RTL_R8(Config5) & (UWF | BWF | MWF)) != 0)
+		tp->features |= RTL_FEATURE_WOL;
 	tp->features |= rtl_try_msi(pdev, ioaddr, cfg);
 	RTL_W8(Cfg9346, Cfg9346_Lock);
 
@@ -1728,7 +2152,13 @@
 		dev->do_ioctl = rtl8169_ioctl;
 	}
 
-	/* Get MAC address.  FIXME: read EEPROM */
+	spin_lock_init(&tp->lock);
+
+	tp->mmio_addr = ioaddr;
+
+	rtl_init_mac_address(tp, ioaddr);
+
+	/* Get MAC address */
 	for (i = 0; i < MAC_ADDR_LEN; i++)
 		dev->dev_addr[i] = RTL_R8(MAC0 + i);
 	memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
@@ -1758,7 +2188,6 @@
 #endif
 
 	tp->intr_mask = 0xffff;
-	tp->mmio_addr = ioaddr;
 	tp->align = cfg->align;
 	tp->hw_start = cfg->hw_start;
 	tp->intr_event = cfg->intr_event;
@@ -1768,8 +2197,6 @@
 	tp->timer.data = (unsigned long) dev;
 	tp->timer.function = rtl8169_phy_timer;
 
-	spin_lock_init(&tp->lock);
-
 	rc = register_netdev(dev);
 	if (rc < 0)
 		goto err_out_msi_5;
@@ -1791,6 +2218,7 @@
 	}
 
 	rtl8169_init_phy(dev, tp);
+	device_set_wakeup_enable(&pdev->dev, tp->features & RTL_FEATURE_WOL);
 
 out:
 	return rc;
@@ -2061,12 +2489,209 @@
 	RTL_W16(IntrMask, tp->intr_event);
 }
 
+static void rtl_tx_performance_tweak(struct pci_dev *pdev, u16 force)
+{
+	struct net_device *dev = pci_get_drvdata(pdev);
+	struct rtl8169_private *tp = netdev_priv(dev);
+	int cap = tp->pcie_cap;
+
+	if (cap) {
+		u16 ctl;
+
+		pci_read_config_word(pdev, cap + PCI_EXP_DEVCTL, &ctl);
+		ctl = (ctl & ~PCI_EXP_DEVCTL_READRQ) | force;
+		pci_write_config_word(pdev, cap + PCI_EXP_DEVCTL, ctl);
+	}
+}
+
+static void rtl_csi_access_enable(void __iomem *ioaddr)
+{
+	u32 csi;
+
+	csi = rtl_csi_read(ioaddr, 0x070c) & 0x00ffffff;
+	rtl_csi_write(ioaddr, 0x070c, csi | 0x27000000);
+}
+
+struct ephy_info {
+	unsigned int offset;
+	u16 mask;
+	u16 bits;
+};
+
+static void rtl_ephy_init(void __iomem *ioaddr, struct ephy_info *e, int len)
+{
+	u16 w;
+
+	while (len-- > 0) {
+		w = (rtl_ephy_read(ioaddr, e->offset) & ~e->mask) | e->bits;
+		rtl_ephy_write(ioaddr, e->offset, w);
+		e++;
+	}
+}
+
+static void rtl_disable_clock_request(struct pci_dev *pdev)
+{
+	struct net_device *dev = pci_get_drvdata(pdev);
+	struct rtl8169_private *tp = netdev_priv(dev);
+	int cap = tp->pcie_cap;
+
+	if (cap) {
+		u16 ctl;
+
+		pci_read_config_word(pdev, cap + PCI_EXP_LNKCTL, &ctl);
+		ctl &= ~PCI_EXP_LNKCTL_CLKREQ_EN;
+		pci_write_config_word(pdev, cap + PCI_EXP_LNKCTL, ctl);
+	}
+}
+
+#define R8168_CPCMD_QUIRK_MASK (\
+	EnableBist | \
+	Mac_dbgo_oe | \
+	Force_half_dup | \
+	Force_rxflow_en | \
+	Force_txflow_en | \
+	Cxpl_dbg_sel | \
+	ASF | \
+	PktCntrDisable | \
+	Mac_dbgo_sel)
+
+static void rtl_hw_start_8168bb(void __iomem *ioaddr, struct pci_dev *pdev)
+{
+	RTL_W8(Config3, RTL_R8(Config3) & ~Beacon_en);
+
+	RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R8168_CPCMD_QUIRK_MASK);
+
+	rtl_tx_performance_tweak(pdev,
+		(0x5 << MAX_READ_REQUEST_SHIFT) | PCI_EXP_DEVCTL_NOSNOOP_EN);
+}
+
+static void rtl_hw_start_8168bef(void __iomem *ioaddr, struct pci_dev *pdev)
+{
+	rtl_hw_start_8168bb(ioaddr, pdev);
+
+	RTL_W8(EarlyTxThres, EarlyTxThld);
+
+	RTL_W8(Config4, RTL_R8(Config4) & ~(1 << 0));
+}
+
+static void __rtl_hw_start_8168cp(void __iomem *ioaddr, struct pci_dev *pdev)
+{
+	RTL_W8(Config1, RTL_R8(Config1) | Speed_down);
+
+	RTL_W8(Config3, RTL_R8(Config3) & ~Beacon_en);
+
+	rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
+
+	rtl_disable_clock_request(pdev);
+
+	RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R8168_CPCMD_QUIRK_MASK);
+}
+
+static void rtl_hw_start_8168cp_1(void __iomem *ioaddr, struct pci_dev *pdev)
+{
+	static struct ephy_info e_info_8168cp[] = {
+		{ 0x01, 0,	0x0001 },
+		{ 0x02, 0x0800,	0x1000 },
+		{ 0x03, 0,	0x0042 },
+		{ 0x06, 0x0080,	0x0000 },
+		{ 0x07, 0,	0x2000 }
+	};
+
+	rtl_csi_access_enable(ioaddr);
+
+	rtl_ephy_init(ioaddr, e_info_8168cp, ARRAY_SIZE(e_info_8168cp));
+
+	__rtl_hw_start_8168cp(ioaddr, pdev);
+}
+
+static void rtl_hw_start_8168cp_2(void __iomem *ioaddr, struct pci_dev *pdev)
+{
+	rtl_csi_access_enable(ioaddr);
+
+	RTL_W8(Config3, RTL_R8(Config3) & ~Beacon_en);
+
+	rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
+
+	RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R8168_CPCMD_QUIRK_MASK);
+}
+
+static void rtl_hw_start_8168cp_3(void __iomem *ioaddr, struct pci_dev *pdev)
+{
+	rtl_csi_access_enable(ioaddr);
+
+	RTL_W8(Config3, RTL_R8(Config3) & ~Beacon_en);
+
+	/* Magic. */
+	RTL_W8(DBG_REG, 0x20);
+
+	RTL_W8(EarlyTxThres, EarlyTxThld);
+
+	rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
+
+	RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R8168_CPCMD_QUIRK_MASK);
+}
+
+static void rtl_hw_start_8168c_1(void __iomem *ioaddr, struct pci_dev *pdev)
+{
+	static struct ephy_info e_info_8168c_1[] = {
+		{ 0x02, 0x0800,	0x1000 },
+		{ 0x03, 0,	0x0002 },
+		{ 0x06, 0x0080,	0x0000 }
+	};
+
+	rtl_csi_access_enable(ioaddr);
+
+	RTL_W8(DBG_REG, 0x06 | FIX_NAK_1 | FIX_NAK_2);
+
+	rtl_ephy_init(ioaddr, e_info_8168c_1, ARRAY_SIZE(e_info_8168c_1));
+
+	__rtl_hw_start_8168cp(ioaddr, pdev);
+}
+
+static void rtl_hw_start_8168c_2(void __iomem *ioaddr, struct pci_dev *pdev)
+{
+	static struct ephy_info e_info_8168c_2[] = {
+		{ 0x01, 0,	0x0001 },
+		{ 0x03, 0x0400,	0x0220 }
+	};
+
+	rtl_csi_access_enable(ioaddr);
+
+	rtl_ephy_init(ioaddr, e_info_8168c_2, ARRAY_SIZE(e_info_8168c_2));
+
+	__rtl_hw_start_8168cp(ioaddr, pdev);
+}
+
+static void rtl_hw_start_8168c_3(void __iomem *ioaddr, struct pci_dev *pdev)
+{
+	rtl_hw_start_8168c_2(ioaddr, pdev);
+}
+
+static void rtl_hw_start_8168c_4(void __iomem *ioaddr, struct pci_dev *pdev)
+{
+	rtl_csi_access_enable(ioaddr);
+
+	__rtl_hw_start_8168cp(ioaddr, pdev);
+}
+
+static void rtl_hw_start_8168d(void __iomem *ioaddr, struct pci_dev *pdev)
+{
+	rtl_csi_access_enable(ioaddr);
+
+	rtl_disable_clock_request(pdev);
+
+	RTL_W8(EarlyTxThres, EarlyTxThld);
+
+	rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
+
+	RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R8168_CPCMD_QUIRK_MASK);
+}
+
 static void rtl_hw_start_8168(struct net_device *dev)
 {
 	struct rtl8169_private *tp = netdev_priv(dev);
 	void __iomem *ioaddr = tp->mmio_addr;
 	struct pci_dev *pdev = tp->pci_dev;
-	u8 ctl;
 
 	RTL_W8(Cfg9346, Cfg9346_Unlock);
 
@@ -2074,17 +2699,10 @@
 
 	rtl_set_rx_max_size(ioaddr);
 
-	rtl_set_rx_tx_config_registers(tp);
-
 	tp->cp_cmd |= RTL_R16(CPlusCmd) | PktCntrDisable | INTT_1;
 
 	RTL_W16(CPlusCmd, tp->cp_cmd);
 
-	/* Tx performance tweak. */
-	pci_read_config_byte(pdev, 0x69, &ctl);
-	ctl = (ctl & ~0x70) | 0x50;
-	pci_write_config_byte(pdev, 0x69, ctl);
-
 	RTL_W16(IntrMitigate, 0x5151);
 
 	/* Work around for RxFIFO overflow. */
@@ -2095,21 +2713,134 @@
 
 	rtl_set_rx_tx_desc_registers(tp, ioaddr);
 
-	RTL_W8(Cfg9346, Cfg9346_Lock);
+	rtl_set_rx_mode(dev);
+
+	RTL_W32(TxConfig, (TX_DMA_BURST << TxDMAShift) |
+		(InterFrameGap << TxInterFrameGapShift));
 
 	RTL_R8(IntrMask);
 
-	RTL_W32(RxMissed, 0);
+	switch (tp->mac_version) {
+	case RTL_GIGA_MAC_VER_11:
+		rtl_hw_start_8168bb(ioaddr, pdev);
+	break;
 
-	rtl_set_rx_mode(dev);
+	case RTL_GIGA_MAC_VER_12:
+	case RTL_GIGA_MAC_VER_17:
+		rtl_hw_start_8168bef(ioaddr, pdev);
+	break;
+
+	case RTL_GIGA_MAC_VER_18:
+		rtl_hw_start_8168cp_1(ioaddr, pdev);
+	break;
+
+	case RTL_GIGA_MAC_VER_19:
+		rtl_hw_start_8168c_1(ioaddr, pdev);
+	break;
+
+	case RTL_GIGA_MAC_VER_20:
+		rtl_hw_start_8168c_2(ioaddr, pdev);
+	break;
+
+	case RTL_GIGA_MAC_VER_21:
+		rtl_hw_start_8168c_3(ioaddr, pdev);
+	break;
+
+	case RTL_GIGA_MAC_VER_22:
+		rtl_hw_start_8168c_4(ioaddr, pdev);
+	break;
+
+	case RTL_GIGA_MAC_VER_23:
+		rtl_hw_start_8168cp_2(ioaddr, pdev);
+	break;
+
+	case RTL_GIGA_MAC_VER_24:
+		rtl_hw_start_8168cp_3(ioaddr, pdev);
+	break;
+
+	case RTL_GIGA_MAC_VER_25:
+		rtl_hw_start_8168d(ioaddr, pdev);
+	break;
+
+	default:
+		printk(KERN_ERR PFX "%s: unknown chipset (mac_version = %d).\n",
+			dev->name, tp->mac_version);
+	break;
+	}
 
 	RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb);
 
+	RTL_W8(Cfg9346, Cfg9346_Lock);
+
 	RTL_W16(MultiIntr, RTL_R16(MultiIntr) & 0xF000);
 
 	RTL_W16(IntrMask, tp->intr_event);
 }
 
+#define R810X_CPCMD_QUIRK_MASK (\
+	EnableBist | \
+	Mac_dbgo_oe | \
+	Force_half_dup | \
+	Force_half_dup | \
+	Force_txflow_en | \
+	Cxpl_dbg_sel | \
+	ASF | \
+	PktCntrDisable | \
+	PCIDAC | \
+	PCIMulRW)
+
+static void rtl_hw_start_8102e_1(void __iomem *ioaddr, struct pci_dev *pdev)
+{
+	static struct ephy_info e_info_8102e_1[] = {
+		{ 0x01,	0, 0x6e65 },
+		{ 0x02,	0, 0x091f },
+		{ 0x03,	0, 0xc2f9 },
+		{ 0x06,	0, 0xafb5 },
+		{ 0x07,	0, 0x0e00 },
+		{ 0x19,	0, 0xec80 },
+		{ 0x01,	0, 0x2e65 },
+		{ 0x01,	0, 0x6e65 }
+	};
+	u8 cfg1;
+
+	rtl_csi_access_enable(ioaddr);
+
+	RTL_W8(DBG_REG, FIX_NAK_1);
+
+	rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
+
+	RTL_W8(Config1,
+	       LEDS1 | LEDS0 | Speed_down | MEMMAP | IOMAP | VPD | PMEnable);
+	RTL_W8(Config3, RTL_R8(Config3) & ~Beacon_en);
+
+	cfg1 = RTL_R8(Config1);
+	if ((cfg1 & LEDS0) && (cfg1 & LEDS1))
+		RTL_W8(Config1, cfg1 & ~LEDS0);
+
+	RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R810X_CPCMD_QUIRK_MASK);
+
+	rtl_ephy_init(ioaddr, e_info_8102e_1, ARRAY_SIZE(e_info_8102e_1));
+}
+
+static void rtl_hw_start_8102e_2(void __iomem *ioaddr, struct pci_dev *pdev)
+{
+	rtl_csi_access_enable(ioaddr);
+
+	rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
+
+	RTL_W8(Config1, MEMMAP | IOMAP | VPD | PMEnable);
+	RTL_W8(Config3, RTL_R8(Config3) & ~Beacon_en);
+
+	RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R810X_CPCMD_QUIRK_MASK);
+}
+
+static void rtl_hw_start_8102e_3(void __iomem *ioaddr, struct pci_dev *pdev)
+{
+	rtl_hw_start_8102e_2(ioaddr, pdev);
+
+	rtl_ephy_write(ioaddr, 0x03, 0xc2f9);
+}
+
 static void rtl_hw_start_8101(struct net_device *dev)
 {
 	struct rtl8169_private *tp = netdev_priv(dev);
@@ -2118,8 +2849,26 @@
 
 	if ((tp->mac_version == RTL_GIGA_MAC_VER_13) ||
 	    (tp->mac_version == RTL_GIGA_MAC_VER_16)) {
-		pci_write_config_word(pdev, 0x68, 0x00);
-		pci_write_config_word(pdev, 0x69, 0x08);
+		int cap = tp->pcie_cap;
+
+		if (cap) {
+			pci_write_config_word(pdev, cap + PCI_EXP_DEVCTL,
+					      PCI_EXP_DEVCTL_NOSNOOP_EN);
+		}
+	}
+
+	switch (tp->mac_version) {
+	case RTL_GIGA_MAC_VER_07:
+		rtl_hw_start_8102e_1(ioaddr, pdev);
+		break;
+
+	case RTL_GIGA_MAC_VER_08:
+		rtl_hw_start_8102e_3(ioaddr, pdev);
+		break;
+
+	case RTL_GIGA_MAC_VER_09:
+		rtl_hw_start_8102e_2(ioaddr, pdev);
+		break;
 	}
 
 	RTL_W8(Cfg9346, Cfg9346_Unlock);
@@ -2143,8 +2892,6 @@
 
 	RTL_R8(IntrMask);
 
-	RTL_W32(RxMissed, 0);
-
 	rtl_set_rx_mode(dev);
 
 	RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb);
@@ -2922,6 +3669,17 @@
 	return work_done;
 }
 
+static void rtl8169_rx_missed(struct net_device *dev, void __iomem *ioaddr)
+{
+	struct rtl8169_private *tp = netdev_priv(dev);
+
+	if (tp->mac_version > RTL_GIGA_MAC_VER_06)
+		return;
+
+	dev->stats.rx_missed_errors += (RTL_R32(RxMissed) & 0xffffff);
+	RTL_W32(RxMissed, 0);
+}
+
 static void rtl8169_down(struct net_device *dev)
 {
 	struct rtl8169_private *tp = netdev_priv(dev);
@@ -2939,9 +3697,7 @@
 
 	rtl8169_asic_down(ioaddr);
 
-	/* Update the error counts. */
-	dev->stats.rx_missed_errors += RTL_R32(RxMissed);
-	RTL_W32(RxMissed, 0);
+	rtl8169_rx_missed(dev, ioaddr);
 
 	spin_unlock_irq(&tp->lock);
 
@@ -3063,8 +3819,7 @@
 
 	if (netif_running(dev)) {
 		spin_lock_irqsave(&tp->lock, flags);
-		dev->stats.rx_missed_errors += RTL_R32(RxMissed);
-		RTL_W32(RxMissed, 0);
+		rtl8169_rx_missed(dev, ioaddr);
 		spin_unlock_irqrestore(&tp->lock, flags);
 	}
 
@@ -3089,8 +3844,7 @@
 
 	rtl8169_asic_down(ioaddr);
 
-	dev->stats.rx_missed_errors += RTL_R32(RxMissed);
-	RTL_W32(RxMissed, 0);
+	rtl8169_rx_missed(dev, ioaddr);
 
 	spin_unlock_irq(&tp->lock);
 
@@ -3121,6 +3875,11 @@
 	return 0;
 }
 
+static void rtl_shutdown(struct pci_dev *pdev)
+{
+	rtl8169_suspend(pdev, PMSG_SUSPEND);
+}
+
 #endif /* CONFIG_PM */
 
 static struct pci_driver rtl8169_pci_driver = {
@@ -3131,6 +3890,7 @@
 #ifdef CONFIG_PM
 	.suspend	= rtl8169_suspend,
 	.resume		= rtl8169_resume,
+	.shutdown	= rtl_shutdown,
 #endif
 };
 
diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c
index a2b0730..6a1375f 100644
--- a/drivers/net/s2io.c
+++ b/drivers/net/s2io.c
@@ -371,9 +371,6 @@
 				flags[i]);
 }
 
-/* A flag indicating whether 'RX_PA_CFG_STRIP_VLAN_TAG' bit is set or not */
-static int vlan_strip_flag;
-
 /* Unregister the vlan */
 static void s2io_vlan_rx_kill_vid(struct net_device *dev, unsigned long vid)
 {
@@ -2303,7 +2300,7 @@
 		val64 = readq(&bar0->rx_pa_cfg);
 		val64 &= ~RX_PA_CFG_STRIP_VLAN_TAG;
 		writeq(val64, &bar0->rx_pa_cfg);
-		vlan_strip_flag = 0;
+		nic->vlan_strip_flag = 0;
 	}
 
 	/*
@@ -3136,7 +3133,7 @@
 		if (skb == NULL) {
 			spin_unlock_irqrestore(&fifo_data->tx_lock, flags);
 			DBG_PRINT(ERR_DBG, "%s: Null skb ",
-			__FUNCTION__);
+			__func__);
 			DBG_PRINT(ERR_DBG, "in Tx Free Intr\n");
 			return;
 		}
@@ -3496,7 +3493,7 @@
 	unsigned long long mem_alloc_cnt, mem_free_cnt, watchdog_cnt;
 
 	DBG_PRINT(INIT_DBG,"%s - Resetting XFrame card %s\n",
-			__FUNCTION__, sp->dev->name);
+			__func__, sp->dev->name);
 
 	/* Back up  the PCI-X CMD reg, dont want to lose MMRBC, OST settings */
 	pci_read_config_word(sp->pdev, PCIX_COMMAND_REGISTER, &(pci_cmd));
@@ -3518,7 +3515,7 @@
 	}
 
 	if (check_pci_device_id(val16) == (u16)PCI_ANY_ID) {
-		DBG_PRINT(ERR_DBG,"%s SW_Reset failed!\n", __FUNCTION__);
+		DBG_PRINT(ERR_DBG,"%s SW_Reset failed!\n", __func__);
 	}
 
 	pci_write_config_word(sp->pdev, PCIX_COMMAND_REGISTER, pci_cmd);
@@ -3768,7 +3765,7 @@
 		val64 = (s2BIT(7) | s2BIT(15) | vBIT(msix_index, 26, 6));
 		writeq(val64, &bar0->xmsi_access);
 		if (wait_for_msix_trans(nic, msix_index)) {
-			DBG_PRINT(ERR_DBG, "failed in %s\n", __FUNCTION__);
+			DBG_PRINT(ERR_DBG, "failed in %s\n", __func__);
 			continue;
 		}
 	}
@@ -3789,7 +3786,7 @@
 		val64 = (s2BIT(15) | vBIT(msix_index, 26, 6));
 		writeq(val64, &bar0->xmsi_access);
 		if (wait_for_msix_trans(nic, msix_index)) {
-			DBG_PRINT(ERR_DBG, "failed in %s\n", __FUNCTION__);
+			DBG_PRINT(ERR_DBG, "failed in %s\n", __func__);
 			continue;
 		}
 		addr = readq(&bar0->xmsi_address);
@@ -3812,7 +3809,7 @@
 			       GFP_KERNEL);
 	if (!nic->entries) {
 		DBG_PRINT(INFO_DBG, "%s: Memory allocation failed\n", \
-			__FUNCTION__);
+			__func__);
 		nic->mac_control.stats_info->sw_stat.mem_alloc_fail_cnt++;
 		return -ENOMEM;
 	}
@@ -3826,7 +3823,7 @@
 				   GFP_KERNEL);
 	if (!nic->s2io_entries) {
 		DBG_PRINT(INFO_DBG, "%s: Memory allocation failed\n",
-			__FUNCTION__);
+			__func__);
 		nic->mac_control.stats_info->sw_stat.mem_alloc_fail_cnt++;
 		kfree(nic->entries);
 		nic->mac_control.stats_info->sw_stat.mem_freed
@@ -5010,7 +5007,7 @@
 			val64 = readq(&bar0->rx_pa_cfg);
 			val64 &= ~RX_PA_CFG_STRIP_VLAN_TAG;
 			writeq(val64, &bar0->rx_pa_cfg);
-			vlan_strip_flag = 0;
+			sp->vlan_strip_flag = 0;
 		}
 
 		val64 = readq(&bar0->mac_cfg);
@@ -5032,7 +5029,7 @@
 			val64 = readq(&bar0->rx_pa_cfg);
 			val64 |= RX_PA_CFG_STRIP_VLAN_TAG;
 			writeq(val64, &bar0->rx_pa_cfg);
-			vlan_strip_flag = 1;
+			sp->vlan_strip_flag = 1;
 		}
 
 		val64 = readq(&bar0->mac_cfg);
@@ -6746,7 +6743,7 @@
 		ret = s2io_card_up(sp);
 		if (ret) {
 			DBG_PRINT(ERR_DBG, "%s: Device bring up failed\n",
-				  __FUNCTION__);
+				  __func__);
 			return ret;
 		}
 		s2io_wake_all_tx_queue(sp);
@@ -7530,7 +7527,7 @@
 					default:
 						DBG_PRINT(ERR_DBG,
 							"%s: Samadhana!!\n",
-							 __FUNCTION__);
+							 __func__);
 						BUG();
 				}
 			}
@@ -7781,7 +7778,7 @@
 		return -ENOMEM;
 	}
 	if ((ret = pci_request_regions(pdev, s2io_driver_name))) {
-		DBG_PRINT(ERR_DBG, "%s: Request Regions failed - %x \n", __FUNCTION__, ret);
+		DBG_PRINT(ERR_DBG, "%s: Request Regions failed - %x \n", __func__, ret);
 		pci_disable_device(pdev);
 		return -ENODEV;
 	}
@@ -7998,7 +7995,7 @@
 	if (sp->device_type & XFRAME_II_DEVICE) {
 		mode = s2io_verify_pci_mode(sp);
 		if (mode < 0) {
-			DBG_PRINT(ERR_DBG, "%s: ", __FUNCTION__);
+			DBG_PRINT(ERR_DBG, "%s: ", __func__);
 			DBG_PRINT(ERR_DBG, " Unsupported PCI bus mode\n");
 			ret = -EBADSLT;
 			goto set_swap_failed;
@@ -8175,8 +8172,8 @@
 		    break;
 	}
 	if (sp->config.multiq) {
-	for (i = 0; i < sp->config.tx_fifo_num; i++)
-		mac_control->fifos[i].multiq = config->multiq;
+		for (i = 0; i < sp->config.tx_fifo_num; i++)
+			mac_control->fifos[i].multiq = config->multiq;
 		DBG_PRINT(ERR_DBG, "%s: Multiqueue support enabled\n",
 			dev->name);
 	} else
@@ -8206,6 +8203,11 @@
 	/* Initialize device name */
 	sprintf(sp->name, "%s Neterion %s", dev->name, sp->product_name);
 
+	if (vlan_tag_strip)
+		sp->vlan_strip_flag = 1;
+	else
+		sp->vlan_strip_flag = 0;
+
 	/*
 	 * Make Link state as off at this point, when the Link change
 	 * interrupt comes the state will be automatically changed to
@@ -8299,7 +8301,7 @@
 
 	if (!(rxdp->Control_1 & RXD_FRAME_PROTO_TCP)) {
 		DBG_PRINT(INIT_DBG,"%s: Non-TCP frames not supported for LRO\n",
-			  __FUNCTION__);
+			  __func__);
 		return -1;
 	}
 
@@ -8311,7 +8313,7 @@
 		 * If vlan stripping is disabled and the frame is VLAN tagged,
 		 * shift the offset by the VLAN header size bytes.
 		 */
-		if ((!vlan_strip_flag) &&
+		if ((!sp->vlan_strip_flag) &&
 			(rxdp->Control_1 & RXD_FRAME_VLAN_TAG))
 			ip_off += HEADER_VLAN_SIZE;
 	} else {
@@ -8330,7 +8332,7 @@
 static int check_for_socket_match(struct lro *lro, struct iphdr *ip,
 				  struct tcphdr *tcp)
 {
-	DBG_PRINT(INFO_DBG,"%s: Been here...\n", __FUNCTION__);
+	DBG_PRINT(INFO_DBG,"%s: Been here...\n", __func__);
 	if ((lro->iph->saddr != ip->saddr) || (lro->iph->daddr != ip->daddr) ||
 	   (lro->tcph->source != tcp->source) || (lro->tcph->dest != tcp->dest))
 		return -1;
@@ -8345,7 +8347,7 @@
 static void initiate_new_session(struct lro *lro, u8 *l2h,
 	struct iphdr *ip, struct tcphdr *tcp, u32 tcp_pyld_len, u16 vlan_tag)
 {
-	DBG_PRINT(INFO_DBG,"%s: Been here...\n", __FUNCTION__);
+	DBG_PRINT(INFO_DBG,"%s: Been here...\n", __func__);
 	lro->l2h = l2h;
 	lro->iph = ip;
 	lro->tcph = tcp;
@@ -8375,7 +8377,7 @@
 	struct tcphdr *tcp = lro->tcph;
 	__sum16 nchk;
 	struct stat_block *statinfo = sp->mac_control.stats_info;
-	DBG_PRINT(INFO_DBG,"%s: Been here...\n", __FUNCTION__);
+	DBG_PRINT(INFO_DBG,"%s: Been here...\n", __func__);
 
 	/* Update L3 header */
 	ip->tot_len = htons(lro->total_len);
@@ -8403,7 +8405,7 @@
 static void aggregate_new_rx(struct lro *lro, struct iphdr *ip,
 		struct tcphdr *tcp, u32 l4_pyld)
 {
-	DBG_PRINT(INFO_DBG,"%s: Been here...\n", __FUNCTION__);
+	DBG_PRINT(INFO_DBG,"%s: Been here...\n", __func__);
 	lro->total_len += l4_pyld;
 	lro->frags_len += l4_pyld;
 	lro->tcp_next_seq += l4_pyld;
@@ -8427,7 +8429,7 @@
 {
 	u8 *ptr;
 
-	DBG_PRINT(INFO_DBG,"%s: Been here...\n", __FUNCTION__);
+	DBG_PRINT(INFO_DBG,"%s: Been here...\n", __func__);
 
 	if (!tcp_pyld_len) {
 		/* Runt frame or a pure ack */
@@ -8509,7 +8511,7 @@
 
 			if ((*lro)->tcp_next_seq != ntohl(tcph->seq)) {
 				DBG_PRINT(INFO_DBG, "%s:Out of order. expected "
-					  "0x%x, actual 0x%x\n", __FUNCTION__,
+					  "0x%x, actual 0x%x\n", __func__,
 					  (*lro)->tcp_next_seq,
 					  ntohl(tcph->seq));
 
@@ -8549,7 +8551,7 @@
 
 	if (ret == 0) { /* sessions exceeded */
 		DBG_PRINT(INFO_DBG,"%s:All LRO sessions already in use\n",
-			  __FUNCTION__);
+			  __func__);
 		*lro = NULL;
 		return ret;
 	}
@@ -8571,7 +8573,7 @@
 			break;
 		default:
 			DBG_PRINT(ERR_DBG,"%s:Dont know, can't say!!\n",
-				__FUNCTION__);
+				__func__);
 			break;
 	}
 
@@ -8592,7 +8594,7 @@
 
 	skb->protocol = eth_type_trans(skb, dev);
 	if (sp->vlgrp && vlan_tag
-		&& (vlan_strip_flag)) {
+		&& (sp->vlan_strip_flag)) {
 		/* Queueing the vlan frame to the upper layer */
 		if (sp->config.napi)
 			vlan_hwaccel_receive_skb(skb, sp->vlgrp, vlan_tag);
diff --git a/drivers/net/s2io.h b/drivers/net/s2io.h
index 6722a2f..55cb943 100644
--- a/drivers/net/s2io.h
+++ b/drivers/net/s2io.h
@@ -962,6 +962,7 @@
 	int task_flag;
 	unsigned long long start_time;
 	struct vlan_group *vlgrp;
+	int vlan_strip_flag;
 #define MSIX_FLG                0xA5
 	int num_entries;
 	struct msix_entry *entries;
diff --git a/drivers/net/sb1250-mac.c b/drivers/net/sb1250-mac.c
index fe41e4e..2615d46 100644
--- a/drivers/net/sb1250-mac.c
+++ b/drivers/net/sb1250-mac.c
@@ -256,7 +256,7 @@
 	struct net_device	*sbm_dev;	/* pointer to linux device */
 	struct napi_struct	napi;
 	struct phy_device	*phy_dev;	/* the associated PHY device */
-	struct mii_bus		mii_bus;	/* the MII bus */
+	struct mii_bus		*mii_bus;	/* the MII bus */
 	int			phy_irq[PHY_MAX_ADDR];
 	spinlock_t		sbm_lock;	/* spin lock */
 	int			sbm_devflags;	/* current device flags */
@@ -2069,9 +2069,10 @@
 static int sbmac_start_tx(struct sk_buff *skb, struct net_device *dev)
 {
 	struct sbmac_softc *sc = netdev_priv(dev);
+	unsigned long flags;
 
 	/* lock eth irq */
-	spin_lock_irq (&sc->sbm_lock);
+	spin_lock_irqsave(&sc->sbm_lock, flags);
 
 	/*
 	 * Put the buffer on the transmit ring.  If we
@@ -2081,14 +2082,14 @@
 	if (sbdma_add_txbuffer(&(sc->sbm_txdma),skb)) {
 		/* XXX save skb that we could not send */
 		netif_stop_queue(dev);
-		spin_unlock_irq(&sc->sbm_lock);
+		spin_unlock_irqrestore(&sc->sbm_lock, flags);
 
 		return 1;
 	}
 
 	dev->trans_start = jiffies;
 
-	spin_unlock_irq (&sc->sbm_lock);
+	spin_unlock_irqrestore(&sc->sbm_lock, flags);
 
 	return 0;
 }
@@ -2347,10 +2348,17 @@
 	/* This is needed for PASS2 for Rx H/W checksum feature */
 	sbmac_set_iphdr_offset(sc);
 
+	sc->mii_bus = mdiobus_alloc();
+	if (sc->mii_bus == NULL) {
+		sbmac_uninitctx(sc);
+		return -ENOMEM;
+	}
+
 	err = register_netdev(dev);
 	if (err) {
 		printk(KERN_ERR "%s.%d: unable to register netdev\n",
 		       sbmac_string, idx);
+		mdiobus_free(sc->mii_bus);
 		sbmac_uninitctx(sc);
 		return err;
 	}
@@ -2368,17 +2376,17 @@
 	pr_info("%s: SiByte Ethernet at 0x%08Lx, address: %s\n",
 	       dev->name, base, print_mac(mac, eaddr));
 
-	sc->mii_bus.name = sbmac_mdio_string;
-	snprintf(sc->mii_bus.id, MII_BUS_ID_SIZE, "%x", idx);
-	sc->mii_bus.priv = sc;
-	sc->mii_bus.read = sbmac_mii_read;
-	sc->mii_bus.write = sbmac_mii_write;
-	sc->mii_bus.irq = sc->phy_irq;
+	sc->mii_bus->name = sbmac_mdio_string;
+	snprintf(sc->mii_bus->id, MII_BUS_ID_SIZE, "%x", idx);
+	sc->mii_bus->priv = sc;
+	sc->mii_bus->read = sbmac_mii_read;
+	sc->mii_bus->write = sbmac_mii_write;
+	sc->mii_bus->irq = sc->phy_irq;
 	for (i = 0; i < PHY_MAX_ADDR; ++i)
-		sc->mii_bus.irq[i] = SBMAC_PHY_INT;
+		sc->mii_bus->irq[i] = SBMAC_PHY_INT;
 
-	sc->mii_bus.dev = &pldev->dev;
-	dev_set_drvdata(&pldev->dev, &sc->mii_bus);
+	sc->mii_bus->parent = &pldev->dev;
+	dev_set_drvdata(&pldev->dev, sc->mii_bus);
 
 	return 0;
 }
@@ -2409,7 +2417,7 @@
 	/*
 	 * Probe PHY address
 	 */
-	err = mdiobus_register(&sc->mii_bus);
+	err = mdiobus_register(sc->mii_bus);
 	if (err) {
 		printk(KERN_ERR "%s: unable to register MDIO bus\n",
 		       dev->name);
@@ -2446,7 +2454,7 @@
 	return 0;
 
 out_unregister:
-	mdiobus_unregister(&sc->mii_bus);
+	mdiobus_unregister(sc->mii_bus);
 
 out_unirq:
 	free_irq(dev->irq, dev);
@@ -2462,7 +2470,7 @@
 	int i;
 
 	for (i = 0; i < PHY_MAX_ADDR; i++) {
-		phy_dev = sc->mii_bus.phy_map[i];
+		phy_dev = sc->mii_bus->phy_map[i];
 		if (phy_dev)
 			break;
 	}
@@ -2568,14 +2576,15 @@
 static void sbmac_tx_timeout (struct net_device *dev)
 {
 	struct sbmac_softc *sc = netdev_priv(dev);
+	unsigned long flags;
 
-	spin_lock_irq (&sc->sbm_lock);
+	spin_lock_irqsave(&sc->sbm_lock, flags);
 
 
 	dev->trans_start = jiffies;
 	dev->stats.tx_errors++;
 
-	spin_unlock_irq (&sc->sbm_lock);
+	spin_unlock_irqrestore(&sc->sbm_lock, flags);
 
 	printk (KERN_WARNING "%s: Transmit timed out\n",dev->name);
 }
@@ -2639,7 +2648,7 @@
 	phy_disconnect(sc->phy_dev);
 	sc->phy_dev = NULL;
 
-	mdiobus_unregister(&sc->mii_bus);
+	mdiobus_unregister(sc->mii_bus);
 
 	free_irq(dev->irq, dev);
 
@@ -2748,6 +2757,7 @@
 
 	unregister_netdev(dev);
 	sbmac_uninitctx(sc);
+	mdiobus_free(sc->mii_bus);
 	iounmap(sc->sbm_base);
 	free_netdev(dev);
 
diff --git a/drivers/net/sfc/bitfield.h b/drivers/net/sfc/bitfield.h
index 2c79d27..d95c218 100644
--- a/drivers/net/sfc/bitfield.h
+++ b/drivers/net/sfc/bitfield.h
@@ -52,9 +52,9 @@
  *
  * The maximum width mask that can be generated is 64 bits.
  */
-#define EFX_MASK64(field)					\
-	(EFX_WIDTH(field) == 64 ? ~((u64) 0) :		\
-	 (((((u64) 1) << EFX_WIDTH(field))) - 1))
+#define EFX_MASK64(width)			\
+	((width) == 64 ? ~((u64) 0) :		\
+	 (((((u64) 1) << (width))) - 1))
 
 /* Mask equal in width to the specified field.
  *
@@ -63,9 +63,9 @@
  * The maximum width mask that can be generated is 32 bits.  Use
  * EFX_MASK64 for higher width fields.
  */
-#define EFX_MASK32(field)					\
-	(EFX_WIDTH(field) == 32 ? ~((u32) 0) :		\
-	 (((((u32) 1) << EFX_WIDTH(field))) - 1))
+#define EFX_MASK32(width)			\
+	((width) == 32 ? ~((u32) 0) :		\
+	 (((((u32) 1) << (width))) - 1))
 
 /* A doubleword (i.e. 4 byte) datatype - little-endian in HW */
 typedef union efx_dword {
@@ -138,44 +138,49 @@
 	EFX_EXTRACT_NATIVE(le32_to_cpu(element), min, max, low, high)
 
 #define EFX_EXTRACT_OWORD64(oword, low, high)				\
-	(EFX_EXTRACT64((oword).u64[0], 0, 63, low, high) |		\
-	 EFX_EXTRACT64((oword).u64[1], 64, 127, low, high))
+	((EFX_EXTRACT64((oword).u64[0], 0, 63, low, high) |		\
+	  EFX_EXTRACT64((oword).u64[1], 64, 127, low, high)) &		\
+	 EFX_MASK64(high + 1 - low))
 
 #define EFX_EXTRACT_QWORD64(qword, low, high)				\
-	EFX_EXTRACT64((qword).u64[0], 0, 63, low, high)
+	(EFX_EXTRACT64((qword).u64[0], 0, 63, low, high) &		\
+	 EFX_MASK64(high + 1 - low))
 
 #define EFX_EXTRACT_OWORD32(oword, low, high)				\
-	(EFX_EXTRACT32((oword).u32[0], 0, 31, low, high) |		\
-	 EFX_EXTRACT32((oword).u32[1], 32, 63, low, high) |		\
-	 EFX_EXTRACT32((oword).u32[2], 64, 95, low, high) |		\
-	 EFX_EXTRACT32((oword).u32[3], 96, 127, low, high))
+	((EFX_EXTRACT32((oword).u32[0], 0, 31, low, high) |		\
+	  EFX_EXTRACT32((oword).u32[1], 32, 63, low, high) |		\
+	  EFX_EXTRACT32((oword).u32[2], 64, 95, low, high) |		\
+	  EFX_EXTRACT32((oword).u32[3], 96, 127, low, high)) &		\
+	 EFX_MASK32(high + 1 - low))
 
 #define EFX_EXTRACT_QWORD32(qword, low, high)				\
-	(EFX_EXTRACT32((qword).u32[0], 0, 31, low, high) |		\
-	 EFX_EXTRACT32((qword).u32[1], 32, 63, low, high))
+	((EFX_EXTRACT32((qword).u32[0], 0, 31, low, high) |		\
+	  EFX_EXTRACT32((qword).u32[1], 32, 63, low, high)) &		\
+	 EFX_MASK32(high + 1 - low))
 
-#define EFX_EXTRACT_DWORD(dword, low, high)				\
-	EFX_EXTRACT32((dword).u32[0], 0, 31, low, high)
+#define EFX_EXTRACT_DWORD(dword, low, high)			\
+	(EFX_EXTRACT32((dword).u32[0], 0, 31, low, high) &	\
+	 EFX_MASK32(high + 1 - low))
 
-#define EFX_OWORD_FIELD64(oword, field)					\
-	(EFX_EXTRACT_OWORD64(oword, EFX_LOW_BIT(field), EFX_HIGH_BIT(field)) \
-	 & EFX_MASK64(field))
+#define EFX_OWORD_FIELD64(oword, field)				\
+	EFX_EXTRACT_OWORD64(oword, EFX_LOW_BIT(field),		\
+			    EFX_HIGH_BIT(field))
 
-#define EFX_QWORD_FIELD64(qword, field)					\
-	(EFX_EXTRACT_QWORD64(qword, EFX_LOW_BIT(field), EFX_HIGH_BIT(field)) \
-	 & EFX_MASK64(field))
+#define EFX_QWORD_FIELD64(qword, field)				\
+	EFX_EXTRACT_QWORD64(qword, EFX_LOW_BIT(field),		\
+			    EFX_HIGH_BIT(field))
 
-#define EFX_OWORD_FIELD32(oword, field)					\
-	(EFX_EXTRACT_OWORD32(oword, EFX_LOW_BIT(field), EFX_HIGH_BIT(field)) \
-	 & EFX_MASK32(field))
+#define EFX_OWORD_FIELD32(oword, field)				\
+	EFX_EXTRACT_OWORD32(oword, EFX_LOW_BIT(field),		\
+			    EFX_HIGH_BIT(field))
 
-#define EFX_QWORD_FIELD32(qword, field)					\
-	(EFX_EXTRACT_QWORD32(qword, EFX_LOW_BIT(field), EFX_HIGH_BIT(field)) \
-	 & EFX_MASK32(field))
+#define EFX_QWORD_FIELD32(qword, field)				\
+	EFX_EXTRACT_QWORD32(qword, EFX_LOW_BIT(field),		\
+			    EFX_HIGH_BIT(field))
 
-#define EFX_DWORD_FIELD(dword, field)					   \
-	(EFX_EXTRACT_DWORD(dword, EFX_LOW_BIT(field), EFX_HIGH_BIT(field)) \
-	 & EFX_MASK32(field))
+#define EFX_DWORD_FIELD(dword, field)				\
+	EFX_EXTRACT_DWORD(dword, EFX_LOW_BIT(field),		\
+			  EFX_HIGH_BIT(field))
 
 #define EFX_OWORD_IS_ZERO64(oword)					\
 	(((oword).u64[0] | (oword).u64[1]) == (__force __le64) 0)
@@ -411,69 +416,102 @@
  * for read-modify-write operations.
  *
  */
-
 #define EFX_INVERT_OWORD(oword) do {		\
 	(oword).u64[0] = ~((oword).u64[0]);	\
 	(oword).u64[1] = ~((oword).u64[1]);	\
 	} while (0)
 
-#define EFX_INSERT_FIELD64(...)					\
-	cpu_to_le64(EFX_INSERT_FIELD_NATIVE(__VA_ARGS__))
+#define EFX_AND_OWORD(oword, from, mask)			\
+	do {							\
+		(oword).u64[0] = (from).u64[0] & (mask).u64[0];	\
+		(oword).u64[1] = (from).u64[1] & (mask).u64[1];	\
+	} while (0)
 
-#define EFX_INSERT_FIELD32(...)					\
-	cpu_to_le32(EFX_INSERT_FIELD_NATIVE(__VA_ARGS__))
+#define EFX_OR_OWORD(oword, from, mask)				\
+	do {							\
+		(oword).u64[0] = (from).u64[0] | (mask).u64[0];	\
+		(oword).u64[1] = (from).u64[1] | (mask).u64[1];	\
+	} while (0)
 
-#define EFX_INPLACE_MASK64(min, max, field)			\
-	EFX_INSERT_FIELD64(min, max, field, EFX_MASK64(field))
+#define EFX_INSERT64(min, max, low, high, value)			\
+	cpu_to_le64(EFX_INSERT_NATIVE(min, max, low, high, value))
 
-#define EFX_INPLACE_MASK32(min, max, field)			\
-	EFX_INSERT_FIELD32(min, max, field, EFX_MASK32(field))
+#define EFX_INSERT32(min, max, low, high, value)			\
+	cpu_to_le32(EFX_INSERT_NATIVE(min, max, low, high, value))
 
-#define EFX_SET_OWORD_FIELD64(oword, field, value) do {			\
+#define EFX_INPLACE_MASK64(min, max, low, high)				\
+	EFX_INSERT64(min, max, low, high, EFX_MASK64(high + 1 - low))
+
+#define EFX_INPLACE_MASK32(min, max, low, high)				\
+	EFX_INSERT32(min, max, low, high, EFX_MASK32(high + 1 - low))
+
+#define EFX_SET_OWORD64(oword, low, high, value) do {			\
 	(oword).u64[0] = (((oword).u64[0] 				\
-			   & ~EFX_INPLACE_MASK64(0,  63, field))	\
-			  | EFX_INSERT_FIELD64(0,  63, field, value));  \
+			   & ~EFX_INPLACE_MASK64(0,  63, low, high))	\
+			  | EFX_INSERT64(0,  63, low, high, value));	\
 	(oword).u64[1] = (((oword).u64[1] 				\
-			   & ~EFX_INPLACE_MASK64(64, 127, field))	\
-			  | EFX_INSERT_FIELD64(64, 127, field, value)); \
+			   & ~EFX_INPLACE_MASK64(64, 127, low, high))	\
+			  | EFX_INSERT64(64, 127, low, high, value));	\
 	} while (0)
 
-#define EFX_SET_QWORD_FIELD64(qword, field, value) do {			\
+#define EFX_SET_QWORD64(qword, low, high, value) do {			\
 	(qword).u64[0] = (((qword).u64[0] 				\
-			   & ~EFX_INPLACE_MASK64(0, 63, field))		\
-			  | EFX_INSERT_FIELD64(0, 63, field, value));	\
+			   & ~EFX_INPLACE_MASK64(0, 63, low, high))	\
+			  | EFX_INSERT64(0, 63, low, high, value));	\
 	} while (0)
 
-#define EFX_SET_OWORD_FIELD32(oword, field, value) do {			\
+#define EFX_SET_OWORD32(oword, low, high, value) do {			\
 	(oword).u32[0] = (((oword).u32[0] 				\
-			   & ~EFX_INPLACE_MASK32(0, 31, field))		\
-			  | EFX_INSERT_FIELD32(0, 31, field, value));	\
+			   & ~EFX_INPLACE_MASK32(0, 31, low, high))	\
+			  | EFX_INSERT32(0, 31, low, high, value));	\
 	(oword).u32[1] = (((oword).u32[1] 				\
-			   & ~EFX_INPLACE_MASK32(32, 63, field))	\
-			  | EFX_INSERT_FIELD32(32, 63, field, value));	\
+			   & ~EFX_INPLACE_MASK32(32, 63, low, high))	\
+			  | EFX_INSERT32(32, 63, low, high, value));	\
 	(oword).u32[2] = (((oword).u32[2] 				\
-			   & ~EFX_INPLACE_MASK32(64, 95, field))	\
-			  | EFX_INSERT_FIELD32(64, 95, field, value));	\
+			   & ~EFX_INPLACE_MASK32(64, 95, low, high))	\
+			  | EFX_INSERT32(64, 95, low, high, value));	\
 	(oword).u32[3] = (((oword).u32[3] 				\
-			   & ~EFX_INPLACE_MASK32(96, 127, field))	\
-			  | EFX_INSERT_FIELD32(96, 127, field, value));	\
+			   & ~EFX_INPLACE_MASK32(96, 127, low, high))	\
+			  | EFX_INSERT32(96, 127, low, high, value));	\
 	} while (0)
 
-#define EFX_SET_QWORD_FIELD32(qword, field, value) do {			\
+#define EFX_SET_QWORD32(qword, low, high, value) do {			\
 	(qword).u32[0] = (((qword).u32[0] 				\
-			   & ~EFX_INPLACE_MASK32(0, 31, field))		\
-			  | EFX_INSERT_FIELD32(0, 31, field, value));	\
+			   & ~EFX_INPLACE_MASK32(0, 31, low, high))	\
+			  | EFX_INSERT32(0, 31, low, high, value));	\
 	(qword).u32[1] = (((qword).u32[1] 				\
-			   & ~EFX_INPLACE_MASK32(32, 63, field))	\
-			  | EFX_INSERT_FIELD32(32, 63, field, value));	\
+			   & ~EFX_INPLACE_MASK32(32, 63, low, high))	\
+			  | EFX_INSERT32(32, 63, low, high, value));	\
 	} while (0)
 
-#define EFX_SET_DWORD_FIELD(dword, field, value) do {			\
-	(dword).u32[0] = (((dword).u32[0] 				\
-			   & ~EFX_INPLACE_MASK32(0, 31, field))		\
-			  | EFX_INSERT_FIELD32(0, 31, field, value));	\
+#define EFX_SET_DWORD32(dword, low, high, value) do {			\
+	(dword).u32[0] = (((dword).u32[0]				\
+			   & ~EFX_INPLACE_MASK32(0, 31, low, high))	\
+			  | EFX_INSERT32(0, 31, low, high, value));	\
 	} while (0)
 
+#define EFX_SET_OWORD_FIELD64(oword, field, value)			\
+	EFX_SET_OWORD64(oword, EFX_LOW_BIT(field),			\
+			 EFX_HIGH_BIT(field), value)
+
+#define EFX_SET_QWORD_FIELD64(qword, field, value)			\
+	EFX_SET_QWORD64(qword, EFX_LOW_BIT(field),			\
+			 EFX_HIGH_BIT(field), value)
+
+#define EFX_SET_OWORD_FIELD32(oword, field, value)			\
+	EFX_SET_OWORD32(oword, EFX_LOW_BIT(field),			\
+			 EFX_HIGH_BIT(field), value)
+
+#define EFX_SET_QWORD_FIELD32(qword, field, value)			\
+	EFX_SET_QWORD32(qword, EFX_LOW_BIT(field),			\
+			 EFX_HIGH_BIT(field), value)
+
+#define EFX_SET_DWORD_FIELD(dword, field, value)			\
+	EFX_SET_DWORD32(dword, EFX_LOW_BIT(field),			\
+			 EFX_HIGH_BIT(field), value)
+
+
+
 #if BITS_PER_LONG == 64
 #define EFX_SET_OWORD_FIELD EFX_SET_OWORD_FIELD64
 #define EFX_SET_QWORD_FIELD EFX_SET_QWORD_FIELD64
@@ -502,4 +540,10 @@
 #define EFX_DMA_TYPE_WIDTH(width) \
 	(((width) < DMA_ADDR_T_WIDTH) ? (width) : DMA_ADDR_T_WIDTH)
 
+
+/* Static initialiser */
+#define EFX_OWORD32(a, b, c, d)						\
+	{ .u32 = { __constant_cpu_to_le32(a), __constant_cpu_to_le32(b), \
+		   __constant_cpu_to_le32(c), __constant_cpu_to_le32(d) } }
+
 #endif /* EFX_BITFIELD_H */
diff --git a/drivers/net/sfc/boards.c b/drivers/net/sfc/boards.c
index d3d3dd0..99e6023 100644
--- a/drivers/net/sfc/boards.c
+++ b/drivers/net/sfc/boards.c
@@ -31,23 +31,23 @@
 		mod_timer(&bl->timer, jiffies + BLINK_INTERVAL);
 }
 
-static void board_blink(struct efx_nic *efx, int blink)
+static void board_blink(struct efx_nic *efx, bool blink)
 {
 	struct efx_blinker *blinker = &efx->board_info.blinker;
 
 	/* The rtnl mutex serialises all ethtool ioctls, so
 	 * nothing special needs doing here. */
 	if (blink) {
-		blinker->resubmit = 1;
-		blinker->state = 0;
+		blinker->resubmit = true;
+		blinker->state = false;
 		setup_timer(&blinker->timer, blink_led_timer,
 			    (unsigned long)efx);
 		mod_timer(&blinker->timer, jiffies + BLINK_INTERVAL);
 	} else {
-		blinker->resubmit = 0;
+		blinker->resubmit = false;
 		if (blinker->timer.function)
 			del_timer_sync(&blinker->timer);
-		efx->board_info.set_fault_led(efx, 0);
+		efx->board_info.set_fault_led(efx, false);
 	}
 }
 
@@ -78,7 +78,7 @@
 	return 0;
 }
 
-static void sfe4002_fault_led(struct efx_nic *efx, int state)
+static void sfe4002_fault_led(struct efx_nic *efx, bool state)
 {
 	xfp_set_led(efx, SFE4002_FAULT_LED, state ? QUAKE_LED_ON :
 			QUAKE_LED_OFF);
diff --git a/drivers/net/sfc/boards.h b/drivers/net/sfc/boards.h
index e5e8443..c6e01b6 100644
--- a/drivers/net/sfc/boards.h
+++ b/drivers/net/sfc/boards.h
@@ -21,7 +21,5 @@
 
 extern int efx_set_board_info(struct efx_nic *efx, u16 revision_info);
 extern int sfe4001_init(struct efx_nic *efx);
-/* Are we putting the PHY into flash config mode */
-extern unsigned int sfe4001_phy_flash_cfg;
 
 #endif
diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c
index 45c72ee..06ea71c 100644
--- a/drivers/net/sfc/efx.c
+++ b/drivers/net/sfc/efx.c
@@ -28,7 +28,6 @@
 #include "efx.h"
 #include "mdio_10g.h"
 #include "falcon.h"
-#include "workarounds.h"
 #include "mac.h"
 
 #define EFX_MAX_MTU (9 * 1024)
@@ -52,7 +51,7 @@
  * This sets the default for new devices.  It can be controlled later
  * using ethtool.
  */
-static int lro = 1;
+static int lro = true;
 module_param(lro, int, 0644);
 MODULE_PARM_DESC(lro, "Large receive offload acceleration");
 
@@ -65,7 +64,7 @@
  * This is forced to 0 for MSI interrupt mode as the interrupt vector
  * is not written
  */
-static unsigned int separate_tx_and_rx_channels = 1;
+static unsigned int separate_tx_and_rx_channels = true;
 
 /* This is the weight assigned to each of the (per-channel) virtual
  * NAPI devices.
@@ -81,7 +80,7 @@
 /* This controls whether or not the hardware monitor will trigger a
  * reset when it detects an error condition.
  */
-static unsigned int monitor_reset = 1;
+static unsigned int monitor_reset = true;
 
 /* This controls whether or not the driver will initialise devices
  * with invalid MAC addresses stored in the EEPROM or flash.  If true,
@@ -141,8 +140,7 @@
 
 #define EFX_ASSERT_RESET_SERIALISED(efx)		\
 	do {						\
-		if ((efx->state == STATE_RUNNING) ||	\
-		    (efx->state == STATE_RESETTING))	\
+		if (efx->state == STATE_RUNNING)	\
 			ASSERT_RTNL();			\
 	} while (0)
 
@@ -159,16 +157,18 @@
  * never be concurrently called more than once on the same channel,
  * though different channels may be being processed concurrently.
  */
-static inline int efx_process_channel(struct efx_channel *channel, int rx_quota)
+static int efx_process_channel(struct efx_channel *channel, int rx_quota)
 {
-	int rxdmaqs;
-	struct efx_rx_queue *rx_queue;
+	struct efx_nic *efx = channel->efx;
+	int rx_packets;
 
-	if (unlikely(channel->efx->reset_pending != RESET_TYPE_NONE ||
+	if (unlikely(efx->reset_pending != RESET_TYPE_NONE ||
 		     !channel->enabled))
-		return rx_quota;
+		return 0;
 
-	rxdmaqs = falcon_process_eventq(channel, &rx_quota);
+	rx_packets = falcon_process_eventq(channel, rx_quota);
+	if (rx_packets == 0)
+		return 0;
 
 	/* Deliver last RX packet. */
 	if (channel->rx_pkt) {
@@ -180,16 +180,9 @@
 	efx_flush_lro(channel);
 	efx_rx_strategy(channel);
 
-	/* Refill descriptor rings as necessary */
-	rx_queue = &channel->efx->rx_queue[0];
-	while (rxdmaqs) {
-		if (rxdmaqs & 0x01)
-			efx_fast_push_rx_descriptors(rx_queue);
-		rx_queue++;
-		rxdmaqs >>= 1;
-	}
+	efx_fast_push_rx_descriptors(&efx->rx_queue[channel->channel]);
 
-	return rx_quota;
+	return rx_packets;
 }
 
 /* Mark channel as finished processing
@@ -203,7 +196,7 @@
 	/* The interrupt handler for this channel may set work_pending
 	 * as soon as we acknowledge the events we've seen.  Make sure
 	 * it's cleared before then. */
-	channel->work_pending = 0;
+	channel->work_pending = false;
 	smp_wmb();
 
 	falcon_eventq_read_ack(channel);
@@ -219,14 +212,12 @@
 	struct efx_channel *channel =
 		container_of(napi, struct efx_channel, napi_str);
 	struct net_device *napi_dev = channel->napi_dev;
-	int unused;
 	int rx_packets;
 
 	EFX_TRACE(channel->efx, "channel %d NAPI poll executing on CPU %d\n",
 		  channel->channel, raw_smp_processor_id());
 
-	unused = efx_process_channel(channel, budget);
-	rx_packets = (budget - unused);
+	rx_packets = efx_process_channel(channel, budget);
 
 	if (rx_packets < budget) {
 		/* There is no race here; although napi_disable() will
@@ -260,7 +251,7 @@
 	falcon_disable_interrupts(efx);
 	if (efx->legacy_irq)
 		synchronize_irq(efx->legacy_irq);
-	if (channel->has_interrupt && channel->irq)
+	if (channel->irq)
 		synchronize_irq(channel->irq);
 
 	/* Wait for any NAPI processing to complete */
@@ -290,13 +281,13 @@
 }
 
 /* Prepare channel's event queue */
-static int efx_init_eventq(struct efx_channel *channel)
+static void efx_init_eventq(struct efx_channel *channel)
 {
 	EFX_LOG(channel->efx, "chan %d init event queue\n", channel->channel);
 
 	channel->eventq_read_ptr = 0;
 
-	return falcon_init_eventq(channel);
+	falcon_init_eventq(channel);
 }
 
 static void efx_fini_eventq(struct efx_channel *channel)
@@ -362,12 +353,11 @@
  * to propagate configuration changes (mtu, checksum offload), or
  * to clear hardware error conditions
  */
-static int efx_init_channels(struct efx_nic *efx)
+static void efx_init_channels(struct efx_nic *efx)
 {
 	struct efx_tx_queue *tx_queue;
 	struct efx_rx_queue *rx_queue;
 	struct efx_channel *channel;
-	int rc = 0;
 
 	/* Calculate the rx buffer allocation parameters required to
 	 * support the current MTU, including padding for header
@@ -382,36 +372,20 @@
 	efx_for_each_channel(channel, efx) {
 		EFX_LOG(channel->efx, "init chan %d\n", channel->channel);
 
-		rc = efx_init_eventq(channel);
-		if (rc)
-			goto err;
+		efx_init_eventq(channel);
 
-		efx_for_each_channel_tx_queue(tx_queue, channel) {
-			rc = efx_init_tx_queue(tx_queue);
-			if (rc)
-				goto err;
-		}
+		efx_for_each_channel_tx_queue(tx_queue, channel)
+			efx_init_tx_queue(tx_queue);
 
 		/* The rx buffer allocation strategy is MTU dependent */
 		efx_rx_strategy(channel);
 
-		efx_for_each_channel_rx_queue(rx_queue, channel) {
-			rc = efx_init_rx_queue(rx_queue);
-			if (rc)
-				goto err;
-		}
+		efx_for_each_channel_rx_queue(rx_queue, channel)
+			efx_init_rx_queue(rx_queue);
 
 		WARN_ON(channel->rx_pkt != NULL);
 		efx_rx_strategy(channel);
 	}
-
-	return 0;
-
- err:
-	EFX_ERR(efx, "failed to initialise channel %d\n",
-		channel ? channel->channel : -1);
-	efx_fini_channels(efx);
-	return rc;
 }
 
 /* This enables event queue processing and packet transmission.
@@ -432,8 +406,8 @@
 	/* The interrupt handler for this channel may set work_pending
 	 * as soon as we enable it.  Make sure it's cleared before
 	 * then.  Similarly, make sure it sees the enabled flag set. */
-	channel->work_pending = 0;
-	channel->enabled = 1;
+	channel->work_pending = false;
+	channel->enabled = true;
 	smp_wmb();
 
 	napi_enable(&channel->napi_str);
@@ -456,7 +430,7 @@
 
 	EFX_LOG(channel->efx, "stop chan %d\n", channel->channel);
 
-	channel->enabled = 0;
+	channel->enabled = false;
 	napi_disable(&channel->napi_str);
 
 	/* Ensure that any worker threads have exited or will be no-ops */
@@ -471,10 +445,17 @@
 	struct efx_channel *channel;
 	struct efx_tx_queue *tx_queue;
 	struct efx_rx_queue *rx_queue;
+	int rc;
 
 	EFX_ASSERT_RESET_SERIALISED(efx);
 	BUG_ON(efx->port_enabled);
 
+	rc = falcon_flush_queues(efx);
+	if (rc)
+		EFX_ERR(efx, "failed to flush queues\n");
+	else
+		EFX_LOG(efx, "successfully flushed all queues\n");
+
 	efx_for_each_channel(channel, efx) {
 		EFX_LOG(channel->efx, "shut down chan %d\n", channel->channel);
 
@@ -482,13 +463,6 @@
 			efx_fini_rx_queue(rx_queue);
 		efx_for_each_channel_tx_queue(tx_queue, channel)
 			efx_fini_tx_queue(tx_queue);
-	}
-
-	/* Do the event queues last so that we can handle flush events
-	 * for all DMA queues. */
-	efx_for_each_channel(channel, efx) {
-		EFX_LOG(channel->efx, "shut down evq %d\n", channel->channel);
-
 		efx_fini_eventq(channel);
 	}
 }
@@ -526,8 +500,6 @@
  */
 static void efx_link_status_changed(struct efx_nic *efx)
 {
-	int carrier_ok;
-
 	/* SFC Bug 5356: A net_dev notifier is registered, so we must ensure
 	 * that no events are triggered between unregister_netdev() and the
 	 * driver unloading. A more general condition is that NETDEV_CHANGE
@@ -535,8 +507,12 @@
 	if (!netif_running(efx->net_dev))
 		return;
 
-	carrier_ok = netif_carrier_ok(efx->net_dev) ? 1 : 0;
-	if (efx->link_up != carrier_ok) {
+	if (efx->port_inhibited) {
+		netif_carrier_off(efx->net_dev);
+		return;
+	}
+
+	if (efx->link_up != netif_carrier_ok(efx->net_dev)) {
 		efx->n_link_state_changes++;
 
 		if (efx->link_up)
@@ -577,13 +553,19 @@
 
 /* This call reinitialises the MAC to pick up new PHY settings. The
  * caller must hold the mac_lock */
-static void __efx_reconfigure_port(struct efx_nic *efx)
+void __efx_reconfigure_port(struct efx_nic *efx)
 {
 	WARN_ON(!mutex_is_locked(&efx->mac_lock));
 
 	EFX_LOG(efx, "reconfiguring MAC from PHY settings on CPU %d\n",
 		raw_smp_processor_id());
 
+	/* Serialise the promiscuous flag with efx_set_multicast_list. */
+	if (efx_dev_registered(efx)) {
+		netif_addr_lock_bh(efx->net_dev);
+		netif_addr_unlock_bh(efx->net_dev);
+	}
+
 	falcon_reconfigure_xmac(efx);
 
 	/* Inform kernel of loss/gain of carrier */
@@ -661,7 +643,8 @@
 	if (rc)
 		return rc;
 
-	efx->port_initialized = 1;
+	efx->port_initialized = true;
+	efx->stats_enabled = true;
 
 	/* Reconfigure port to program MAC registers */
 	falcon_reconfigure_xmac(efx);
@@ -678,7 +661,7 @@
 	BUG_ON(efx->port_enabled);
 
 	mutex_lock(&efx->mac_lock);
-	efx->port_enabled = 1;
+	efx->port_enabled = true;
 	__efx_reconfigure_port(efx);
 	mutex_unlock(&efx->mac_lock);
 }
@@ -692,7 +675,7 @@
 	EFX_LOG(efx, "stop port\n");
 
 	mutex_lock(&efx->mac_lock);
-	efx->port_enabled = 0;
+	efx->port_enabled = false;
 	mutex_unlock(&efx->mac_lock);
 
 	/* Serialise against efx_set_multicast_list() */
@@ -710,9 +693,9 @@
 		return;
 
 	falcon_fini_xmac(efx);
-	efx->port_initialized = 0;
+	efx->port_initialized = false;
 
-	efx->link_up = 0;
+	efx->link_up = false;
 	efx_link_status_changed(efx);
 }
 
@@ -797,7 +780,7 @@
 	return 0;
 
  fail4:
-	release_mem_region(efx->membase_phys, efx->type->mem_map_size);
+	pci_release_region(efx->pci_dev, efx->type->mem_bar);
  fail3:
 	efx->membase_phys = 0;
  fail2:
@@ -823,53 +806,61 @@
 	pci_disable_device(efx->pci_dev);
 }
 
-/* Probe the number and type of interrupts we are able to obtain. */
+/* Get number of RX queues wanted.  Return number of online CPU
+ * packages in the expectation that an IRQ balancer will spread
+ * interrupts across them. */
+static int efx_wanted_rx_queues(void)
+{
+	cpumask_t core_mask;
+	int count;
+	int cpu;
+
+	cpus_clear(core_mask);
+	count = 0;
+	for_each_online_cpu(cpu) {
+		if (!cpu_isset(cpu, core_mask)) {
+			++count;
+			cpus_or(core_mask, core_mask,
+				topology_core_siblings(cpu));
+		}
+	}
+
+	return count;
+}
+
+/* Probe the number and type of interrupts we are able to obtain, and
+ * the resulting numbers of channels and RX queues.
+ */
 static void efx_probe_interrupts(struct efx_nic *efx)
 {
-	int max_channel = efx->type->phys_addr_channels - 1;
-	struct msix_entry xentries[EFX_MAX_CHANNELS];
+	int max_channels =
+		min_t(int, efx->type->phys_addr_channels, EFX_MAX_CHANNELS);
 	int rc, i;
 
 	if (efx->interrupt_mode == EFX_INT_MODE_MSIX) {
-		BUG_ON(!pci_find_capability(efx->pci_dev, PCI_CAP_ID_MSIX));
+		struct msix_entry xentries[EFX_MAX_CHANNELS];
+		int wanted_ints;
 
-		if (rss_cpus == 0) {
-			cpumask_t core_mask;
-			int cpu;
+		/* We want one RX queue and interrupt per CPU package
+		 * (or as specified by the rss_cpus module parameter).
+		 * We will need one channel per interrupt.
+		 */
+		wanted_ints = rss_cpus ? rss_cpus : efx_wanted_rx_queues();
+		efx->n_rx_queues = min(wanted_ints, max_channels);
 
-			cpus_clear(core_mask);
-			efx->rss_queues = 0;
-			for_each_online_cpu(cpu) {
-				if (!cpu_isset(cpu, core_mask)) {
-					++efx->rss_queues;
-					cpus_or(core_mask, core_mask,
-						topology_core_siblings(cpu));
-				}
-			}
-		} else {
-			efx->rss_queues = rss_cpus;
-		}
-
-		efx->rss_queues = min(efx->rss_queues, max_channel + 1);
-		efx->rss_queues = min(efx->rss_queues, EFX_MAX_CHANNELS);
-
-		/* Request maximum number of MSI interrupts, and fill out
-		 * the channel interrupt information the allowed allocation */
-		for (i = 0; i < efx->rss_queues; i++)
+		for (i = 0; i < efx->n_rx_queues; i++)
 			xentries[i].entry = i;
-		rc = pci_enable_msix(efx->pci_dev, xentries, efx->rss_queues);
+		rc = pci_enable_msix(efx->pci_dev, xentries, efx->n_rx_queues);
 		if (rc > 0) {
-			EFX_BUG_ON_PARANOID(rc >= efx->rss_queues);
-			efx->rss_queues = rc;
+			EFX_BUG_ON_PARANOID(rc >= efx->n_rx_queues);
+			efx->n_rx_queues = rc;
 			rc = pci_enable_msix(efx->pci_dev, xentries,
-					     efx->rss_queues);
+					     efx->n_rx_queues);
 		}
 
 		if (rc == 0) {
-			for (i = 0; i < efx->rss_queues; i++) {
-				efx->channel[i].has_interrupt = 1;
+			for (i = 0; i < efx->n_rx_queues; i++)
 				efx->channel[i].irq = xentries[i].vector;
-			}
 		} else {
 			/* Fall back to single channel MSI */
 			efx->interrupt_mode = EFX_INT_MODE_MSI;
@@ -879,11 +870,10 @@
 
 	/* Try single interrupt MSI */
 	if (efx->interrupt_mode == EFX_INT_MODE_MSI) {
-		efx->rss_queues = 1;
+		efx->n_rx_queues = 1;
 		rc = pci_enable_msi(efx->pci_dev);
 		if (rc == 0) {
 			efx->channel[0].irq = efx->pci_dev->irq;
-			efx->channel[0].has_interrupt = 1;
 		} else {
 			EFX_ERR(efx, "could not enable MSI\n");
 			efx->interrupt_mode = EFX_INT_MODE_LEGACY;
@@ -892,10 +882,7 @@
 
 	/* Assume legacy interrupts */
 	if (efx->interrupt_mode == EFX_INT_MODE_LEGACY) {
-		efx->rss_queues = 1;
-		/* Every channel is interruptible */
-		for (i = 0; i < EFX_MAX_CHANNELS; i++)
-			efx->channel[i].has_interrupt = 1;
+		efx->n_rx_queues = 1;
 		efx->legacy_irq = efx->pci_dev->irq;
 	}
 }
@@ -905,7 +892,7 @@
 	struct efx_channel *channel;
 
 	/* Remove MSI/MSI-X interrupts */
-	efx_for_each_channel_with_interrupt(channel, efx)
+	efx_for_each_channel(channel, efx)
 		channel->irq = 0;
 	pci_disable_msi(efx->pci_dev);
 	pci_disable_msix(efx->pci_dev);
@@ -914,45 +901,22 @@
 	efx->legacy_irq = 0;
 }
 
-/* Select number of used resources
- * Should be called after probe_interrupts()
- */
-static void efx_select_used(struct efx_nic *efx)
+static void efx_set_channels(struct efx_nic *efx)
 {
 	struct efx_tx_queue *tx_queue;
 	struct efx_rx_queue *rx_queue;
-	int i;
 
-	/* TX queues.  One per port per channel with TX capability
-	 * (more than one per port won't work on Linux, due to out
-	 *  of order issues... but will be fine on Solaris)
-	 */
-	tx_queue = &efx->tx_queue[0];
+	efx_for_each_tx_queue(tx_queue, efx) {
+		if (!EFX_INT_MODE_USE_MSI(efx) && separate_tx_and_rx_channels)
+			tx_queue->channel = &efx->channel[1];
+		else
+			tx_queue->channel = &efx->channel[0];
+		tx_queue->channel->used_flags |= EFX_USED_BY_TX;
+	}
 
-	/* Perform this for each channel with TX capabilities.
-	 * At the moment, we only support a single TX queue
-	 */
-	tx_queue->used = 1;
-	if ((!EFX_INT_MODE_USE_MSI(efx)) && separate_tx_and_rx_channels)
-		tx_queue->channel = &efx->channel[1];
-	else
-		tx_queue->channel = &efx->channel[0];
-	tx_queue->channel->used_flags |= EFX_USED_BY_TX;
-	tx_queue++;
-
-	/* RX queues.  Each has a dedicated channel. */
-	for (i = 0; i < EFX_MAX_RX_QUEUES; i++) {
-		rx_queue = &efx->rx_queue[i];
-
-		if (i < efx->rss_queues) {
-			rx_queue->used = 1;
-			/* If we allow multiple RX queues per channel
-			 * we need to decide that here
-			 */
-			rx_queue->channel = &efx->channel[rx_queue->queue];
-			rx_queue->channel->used_flags |= EFX_USED_BY_RX;
-			rx_queue++;
-		}
+	efx_for_each_rx_queue(rx_queue, efx) {
+		rx_queue->channel = &efx->channel[rx_queue->queue];
+		rx_queue->channel->used_flags |= EFX_USED_BY_RX;
 	}
 }
 
@@ -971,8 +935,7 @@
 	 * in MSI-X interrupts. */
 	efx_probe_interrupts(efx);
 
-	/* Determine number of RX queues and TX queues */
-	efx_select_used(efx);
+	efx_set_channels(efx);
 
 	/* Initialise the interrupt moderation settings */
 	efx_init_irq_moderation(efx, tx_irq_mod_usec, rx_irq_mod_usec);
@@ -1058,7 +1021,8 @@
 	/* Mark the port as enabled so port reconfigurations can start, then
 	 * restart the transmit interface early so the watchdog timer stops */
 	efx_start_port(efx);
-	efx_wake_queue(efx);
+	if (efx_dev_registered(efx))
+		efx_wake_queue(efx);
 
 	efx_for_each_channel(channel, efx)
 		efx_start_channel(channel);
@@ -1109,7 +1073,7 @@
 	falcon_disable_interrupts(efx);
 	if (efx->legacy_irq)
 		synchronize_irq(efx->legacy_irq);
-	efx_for_each_channel_with_interrupt(channel, efx) {
+	efx_for_each_channel(channel, efx) {
 		if (channel->irq)
 			synchronize_irq(channel->irq);
 	}
@@ -1128,13 +1092,12 @@
 
 	/* Isolate the MAC from the TX and RX engines, so that queue
 	 * flushes will complete in a timely fashion. */
-	falcon_deconfigure_mac_wrapper(efx);
 	falcon_drain_tx_fifo(efx);
 
 	/* Stop the kernel transmit interface late, so the watchdog
 	 * timer isn't ticking over the flush */
-	efx_stop_queue(efx);
 	if (efx_dev_registered(efx)) {
+		efx_stop_queue(efx);
 		netif_tx_lock_bh(efx->net_dev);
 		netif_tx_unlock_bh(efx->net_dev);
 	}
@@ -1151,24 +1114,16 @@
 }
 
 /* A convinience function to safely flush all the queues */
-int efx_flush_queues(struct efx_nic *efx)
+void efx_flush_queues(struct efx_nic *efx)
 {
-	int rc;
-
 	EFX_ASSERT_RESET_SERIALISED(efx);
 
 	efx_stop_all(efx);
 
 	efx_fini_channels(efx);
-	rc = efx_init_channels(efx);
-	if (rc) {
-		efx_schedule_reset(efx, RESET_TYPE_DISABLE);
-		return rc;
-	}
+	efx_init_channels(efx);
 
 	efx_start_all(efx);
-
-	return 0;
 }
 
 /**************************************************************************
@@ -1249,7 +1204,7 @@
  */
 static int efx_ioctl(struct net_device *net_dev, struct ifreq *ifr, int cmd)
 {
-	struct efx_nic *efx = net_dev->priv;
+	struct efx_nic *efx = netdev_priv(net_dev);
 
 	EFX_ASSERT_RESET_SERIALISED(efx);
 
@@ -1303,10 +1258,10 @@
  */
 static void efx_netpoll(struct net_device *net_dev)
 {
-	struct efx_nic *efx = net_dev->priv;
+	struct efx_nic *efx = netdev_priv(net_dev);
 	struct efx_channel *channel;
 
-	efx_for_each_channel_with_interrupt(channel, efx)
+	efx_for_each_channel(channel, efx)
 		efx_schedule_channel(channel);
 }
 
@@ -1321,12 +1276,15 @@
 /* Context: process, rtnl_lock() held. */
 static int efx_net_open(struct net_device *net_dev)
 {
-	struct efx_nic *efx = net_dev->priv;
+	struct efx_nic *efx = netdev_priv(net_dev);
 	EFX_ASSERT_RESET_SERIALISED(efx);
 
 	EFX_LOG(efx, "opening device %s on CPU %d\n", net_dev->name,
 		raw_smp_processor_id());
 
+	if (efx->phy_mode & PHY_MODE_SPECIAL)
+		return -EBUSY;
+
 	efx_start_all(efx);
 	return 0;
 }
@@ -1337,8 +1295,7 @@
  */
 static int efx_net_stop(struct net_device *net_dev)
 {
-	struct efx_nic *efx = net_dev->priv;
-	int rc;
+	struct efx_nic *efx = netdev_priv(net_dev);
 
 	EFX_LOG(efx, "closing %s on CPU %d\n", net_dev->name,
 		raw_smp_processor_id());
@@ -1346,9 +1303,7 @@
 	/* Stop the device and flush all the channels */
 	efx_stop_all(efx);
 	efx_fini_channels(efx);
-	rc = efx_init_channels(efx);
-	if (rc)
-		efx_schedule_reset(efx, RESET_TYPE_DISABLE);
+	efx_init_channels(efx);
 
 	return 0;
 }
@@ -1356,7 +1311,7 @@
 /* Context: process, dev_base_lock or RTNL held, non-blocking. */
 static struct net_device_stats *efx_net_stats(struct net_device *net_dev)
 {
-	struct efx_nic *efx = net_dev->priv;
+	struct efx_nic *efx = netdev_priv(net_dev);
 	struct efx_mac_stats *mac_stats = &efx->mac_stats;
 	struct net_device_stats *stats = &net_dev->stats;
 
@@ -1366,7 +1321,7 @@
 	 */
 	if (!spin_trylock(&efx->stats_lock))
 		return stats;
-	if (efx->state == STATE_RUNNING) {
+	if (efx->stats_enabled) {
 		falcon_update_stats_xmac(efx);
 		falcon_update_nic_stats(efx);
 	}
@@ -1403,7 +1358,7 @@
 /* Context: netif_tx_lock held, BHs disabled. */
 static void efx_watchdog(struct net_device *net_dev)
 {
-	struct efx_nic *efx = net_dev->priv;
+	struct efx_nic *efx = netdev_priv(net_dev);
 
 	EFX_ERR(efx, "TX stuck with stop_count=%d port_enabled=%d: %s\n",
 		atomic_read(&efx->netif_stop_count), efx->port_enabled,
@@ -1417,7 +1372,7 @@
 /* Context: process, rtnl_lock() held. */
 static int efx_change_mtu(struct net_device *net_dev, int new_mtu)
 {
-	struct efx_nic *efx = net_dev->priv;
+	struct efx_nic *efx = netdev_priv(net_dev);
 	int rc = 0;
 
 	EFX_ASSERT_RESET_SERIALISED(efx);
@@ -1431,21 +1386,15 @@
 
 	efx_fini_channels(efx);
 	net_dev->mtu = new_mtu;
-	rc = efx_init_channels(efx);
-	if (rc)
-		goto fail;
+	efx_init_channels(efx);
 
 	efx_start_all(efx);
 	return rc;
-
- fail:
-	efx_schedule_reset(efx, RESET_TYPE_DISABLE);
-	return rc;
 }
 
 static int efx_set_mac_address(struct net_device *net_dev, void *data)
 {
-	struct efx_nic *efx = net_dev->priv;
+	struct efx_nic *efx = netdev_priv(net_dev);
 	struct sockaddr *addr = data;
 	char *new_addr = addr->sa_data;
 
@@ -1466,26 +1415,19 @@
 	return 0;
 }
 
-/* Context: netif_tx_lock held, BHs disabled. */
+/* Context: netif_addr_lock held, BHs disabled. */
 static void efx_set_multicast_list(struct net_device *net_dev)
 {
-	struct efx_nic *efx = net_dev->priv;
+	struct efx_nic *efx = netdev_priv(net_dev);
 	struct dev_mc_list *mc_list = net_dev->mc_list;
 	union efx_multicast_hash *mc_hash = &efx->multicast_hash;
-	int promiscuous;
+	bool promiscuous = !!(net_dev->flags & IFF_PROMISC);
+	bool changed = (efx->promiscuous != promiscuous);
 	u32 crc;
 	int bit;
 	int i;
 
-	/* Set per-MAC promiscuity flag and reconfigure MAC if necessary */
-	promiscuous = (net_dev->flags & IFF_PROMISC) ? 1 : 0;
-	if (efx->promiscuous != promiscuous) {
-		efx->promiscuous = promiscuous;
-		/* Close the window between efx_stop_port() and efx_flush_all()
-		 * by only queuing work when the port is enabled. */
-		if (efx->port_enabled)
-			queue_work(efx->workqueue, &efx->reconfigure_work);
-	}
+	efx->promiscuous = promiscuous;
 
 	/* Build multicast hash table */
 	if (promiscuous || (net_dev->flags & IFF_ALLMULTI)) {
@@ -1500,6 +1442,13 @@
 		}
 	}
 
+	if (!efx->port_enabled)
+		/* Delay pushing settings until efx_start_port() */
+		return;
+
+	if (changed)
+		queue_work(efx->workqueue, &efx->reconfigure_work);
+
 	/* Create and activate new global multicast hash table */
 	falcon_set_multicast_hash(efx);
 }
@@ -1510,7 +1459,7 @@
 	struct net_device *net_dev = ptr;
 
 	if (net_dev->open == efx_net_open && event == NETDEV_CHANGENAME) {
-		struct efx_nic *efx = net_dev->priv;
+		struct efx_nic *efx = netdev_priv(net_dev);
 
 		strcpy(efx->name, net_dev->name);
 	}
@@ -1568,7 +1517,7 @@
 	if (!efx->net_dev)
 		return;
 
-	BUG_ON(efx->net_dev->priv != efx);
+	BUG_ON(netdev_priv(efx->net_dev) != efx);
 
 	/* Free up any skbs still remaining. This has to happen before
 	 * we try to unregister the netdev as running their destructors
@@ -1588,49 +1537,60 @@
  *
  **************************************************************************/
 
-/* The final hardware and software finalisation before reset. */
-static int efx_reset_down(struct efx_nic *efx, struct ethtool_cmd *ecmd)
+/* Tears down the entire software state and most of the hardware state
+ * before reset.  */
+void efx_reset_down(struct efx_nic *efx, struct ethtool_cmd *ecmd)
 {
 	int rc;
 
 	EFX_ASSERT_RESET_SERIALISED(efx);
 
+	/* The net_dev->get_stats handler is quite slow, and will fail
+	 * if a fetch is pending over reset. Serialise against it. */
+	spin_lock(&efx->stats_lock);
+	efx->stats_enabled = false;
+	spin_unlock(&efx->stats_lock);
+
+	efx_stop_all(efx);
+	mutex_lock(&efx->mac_lock);
+
 	rc = falcon_xmac_get_settings(efx, ecmd);
-	if (rc) {
+	if (rc)
 		EFX_ERR(efx, "could not back up PHY settings\n");
-		goto fail;
-	}
 
 	efx_fini_channels(efx);
-	return 0;
-
- fail:
-	return rc;
 }
 
-/* The first part of software initialisation after a hardware reset
- * This function does not handle serialisation with the kernel, it
- * assumes the caller has done this */
-static int efx_reset_up(struct efx_nic *efx, struct ethtool_cmd *ecmd)
+/* This function will always ensure that the locks acquired in
+ * efx_reset_down() are released. A failure return code indicates
+ * that we were unable to reinitialise the hardware, and the
+ * driver should be disabled. If ok is false, then the rx and tx
+ * engines are not restarted, pending a RESET_DISABLE. */
+int efx_reset_up(struct efx_nic *efx, struct ethtool_cmd *ecmd, bool ok)
 {
 	int rc;
 
-	rc = efx_init_channels(efx);
-	if (rc)
-		goto fail1;
+	EFX_ASSERT_RESET_SERIALISED(efx);
 
-	/* Restore MAC and PHY settings. */
-	rc = falcon_xmac_set_settings(efx, ecmd);
+	rc = falcon_init_nic(efx);
 	if (rc) {
-		EFX_ERR(efx, "could not restore PHY settings\n");
-		goto fail2;
+		EFX_ERR(efx, "failed to initialise NIC\n");
+		ok = false;
 	}
 
-	return 0;
+	if (ok) {
+		efx_init_channels(efx);
 
- fail2:
-	efx_fini_channels(efx);
- fail1:
+		if (falcon_xmac_set_settings(efx, ecmd))
+			EFX_ERR(efx, "could not restore PHY settings\n");
+	}
+
+	mutex_unlock(&efx->mac_lock);
+
+	if (ok) {
+		efx_start_all(efx);
+		efx->stats_enabled = true;
+	}
 	return rc;
 }
 
@@ -1659,25 +1619,14 @@
 		goto unlock_rtnl;
 	}
 
-	efx->state = STATE_RESETTING;
 	EFX_INFO(efx, "resetting (%d)\n", method);
 
-	/* The net_dev->get_stats handler is quite slow, and will fail
-	 * if a fetch is pending over reset. Serialise against it. */
-	spin_lock(&efx->stats_lock);
-	spin_unlock(&efx->stats_lock);
-
-	efx_stop_all(efx);
-	mutex_lock(&efx->mac_lock);
-
-	rc = efx_reset_down(efx, &ecmd);
-	if (rc)
-		goto fail1;
+	efx_reset_down(efx, &ecmd);
 
 	rc = falcon_reset_hw(efx, method);
 	if (rc) {
 		EFX_ERR(efx, "failed to reset hardware\n");
-		goto fail2;
+		goto fail;
 	}
 
 	/* Allow resets to be rescheduled. */
@@ -1689,46 +1638,27 @@
 	 * can respond to requests. */
 	pci_set_master(efx->pci_dev);
 
-	/* Reinitialise device. This is appropriate in the RESET_TYPE_DISABLE
-	 * case so the driver can talk to external SRAM */
-	rc = falcon_init_nic(efx);
-	if (rc) {
-		EFX_ERR(efx, "failed to initialise NIC\n");
-		goto fail3;
-	}
-
 	/* Leave device stopped if necessary */
 	if (method == RESET_TYPE_DISABLE) {
-		/* Reinitialise the device anyway so the driver unload sequence
-		 * can talk to the external SRAM */
-		falcon_init_nic(efx);
 		rc = -EIO;
-		goto fail4;
+		goto fail;
 	}
 
-	rc = efx_reset_up(efx, &ecmd);
+	rc = efx_reset_up(efx, &ecmd, true);
 	if (rc)
-		goto fail5;
+		goto disable;
 
-	mutex_unlock(&efx->mac_lock);
 	EFX_LOG(efx, "reset complete\n");
-
-	efx->state = STATE_RUNNING;
-	efx_start_all(efx);
-
  unlock_rtnl:
 	rtnl_unlock();
 	return 0;
 
- fail5:
- fail4:
- fail3:
- fail2:
- fail1:
+ fail:
+	efx_reset_up(efx, &ecmd, false);
+ disable:
 	EFX_ERR(efx, "has been disabled\n");
 	efx->state = STATE_DISABLED;
 
-	mutex_unlock(&efx->mac_lock);
 	rtnl_unlock();
 	efx_unregister_netdev(efx);
 	efx_fini_port(efx);
@@ -1801,7 +1731,7 @@
  *
  * Dummy PHY/MAC/Board operations
  *
- * Can be used where the MAC does not implement this operation
+ * Can be used for some unimplemented operations
  * Needed so all function pointers are valid and do not have to be tested
  * before use
  *
@@ -1811,7 +1741,7 @@
 	return 0;
 }
 void efx_port_dummy_op_void(struct efx_nic *efx) {}
-void efx_port_dummy_op_blink(struct efx_nic *efx, int blink) {}
+void efx_port_dummy_op_blink(struct efx_nic *efx, bool blink) {}
 
 static struct efx_phy_operations efx_dummy_phy_operations = {
 	.init		 = efx_port_dummy_op_int,
@@ -1819,20 +1749,14 @@
 	.check_hw        = efx_port_dummy_op_int,
 	.fini		 = efx_port_dummy_op_void,
 	.clear_interrupt = efx_port_dummy_op_void,
-	.reset_xaui      = efx_port_dummy_op_void,
 };
 
-/* Dummy board operations */
-static int efx_nic_dummy_op_int(struct efx_nic *nic)
-{
-	return 0;
-}
-
 static struct efx_board efx_dummy_board_info = {
-	.init    = efx_nic_dummy_op_int,
-	.init_leds = efx_port_dummy_op_int,
-	.set_fault_led = efx_port_dummy_op_blink,
-	.fini	= efx_port_dummy_op_void,
+	.init		= efx_port_dummy_op_int,
+	.init_leds	= efx_port_dummy_op_int,
+	.set_fault_led	= efx_port_dummy_op_blink,
+	.blink		= efx_port_dummy_op_blink,
+	.fini		= efx_port_dummy_op_void,
 };
 
 /**************************************************************************
@@ -1865,7 +1789,7 @@
 	efx->board_info = efx_dummy_board_info;
 
 	efx->net_dev = net_dev;
-	efx->rx_checksum_enabled = 1;
+	efx->rx_checksum_enabled = true;
 	spin_lock_init(&efx->netif_stop_lock);
 	spin_lock_init(&efx->stats_lock);
 	mutex_init(&efx->mac_lock);
@@ -1878,10 +1802,9 @@
 		channel = &efx->channel[i];
 		channel->efx = efx;
 		channel->channel = i;
-		channel->evqnum = i;
-		channel->work_pending = 0;
+		channel->work_pending = false;
 	}
-	for (i = 0; i < EFX_MAX_TX_QUEUES; i++) {
+	for (i = 0; i < EFX_TX_QUEUE_COUNT; i++) {
 		tx_queue = &efx->tx_queue[i];
 		tx_queue->efx = efx;
 		tx_queue->queue = i;
@@ -2056,19 +1979,16 @@
 		goto fail5;
 	}
 
-	rc = efx_init_channels(efx);
-	if (rc)
-		goto fail6;
+	efx_init_channels(efx);
 
 	rc = falcon_init_interrupt(efx);
 	if (rc)
-		goto fail7;
+		goto fail6;
 
 	return 0;
 
- fail7:
-	efx_fini_channels(efx);
  fail6:
+	efx_fini_channels(efx);
 	efx_fini_port(efx);
  fail5:
  fail4:
@@ -2105,7 +2025,10 @@
 			      NETIF_F_HIGHDMA | NETIF_F_TSO);
 	if (lro)
 		net_dev->features |= NETIF_F_LRO;
-	efx = net_dev->priv;
+	/* Mask for features that also apply to VLAN devices */
+	net_dev->vlan_features |= (NETIF_F_ALL_CSUM | NETIF_F_SG |
+				   NETIF_F_HIGHDMA | NETIF_F_TSO);
+	efx = netdev_priv(net_dev);
 	pci_set_drvdata(pci_dev, efx);
 	rc = efx_init_struct(efx, type, pci_dev, net_dev);
 	if (rc)
diff --git a/drivers/net/sfc/efx.h b/drivers/net/sfc/efx.h
index 3b2f69f..d02937b 100644
--- a/drivers/net/sfc/efx.h
+++ b/drivers/net/sfc/efx.h
@@ -28,15 +28,21 @@
 /* RX */
 extern void efx_xmit_done(struct efx_tx_queue *tx_queue, unsigned int index);
 extern void efx_rx_packet(struct efx_rx_queue *rx_queue, unsigned int index,
-			  unsigned int len, int checksummed, int discard);
+			  unsigned int len, bool checksummed, bool discard);
 extern void efx_schedule_slow_fill(struct efx_rx_queue *rx_queue, int delay);
 
 /* Channels */
 extern void efx_process_channel_now(struct efx_channel *channel);
-extern int efx_flush_queues(struct efx_nic *efx);
+extern void efx_flush_queues(struct efx_nic *efx);
 
 /* Ports */
 extern void efx_reconfigure_port(struct efx_nic *efx);
+extern void __efx_reconfigure_port(struct efx_nic *efx);
+
+/* Reset handling */
+extern void efx_reset_down(struct efx_nic *efx, struct ethtool_cmd *ecmd);
+extern int efx_reset_up(struct efx_nic *efx, struct ethtool_cmd *ecmd,
+			bool ok);
 
 /* Global */
 extern void efx_schedule_reset(struct efx_nic *efx, enum reset_type type);
@@ -50,7 +56,7 @@
 /* Dummy PHY ops for PHY drivers */
 extern int efx_port_dummy_op_int(struct efx_nic *efx);
 extern void efx_port_dummy_op_void(struct efx_nic *efx);
-extern void efx_port_dummy_op_blink(struct efx_nic *efx, int blink);
+extern void efx_port_dummy_op_blink(struct efx_nic *efx, bool blink);
 
 
 extern unsigned int efx_monitor_interval;
@@ -59,7 +65,7 @@
 {
 	EFX_TRACE(channel->efx, "channel %d scheduling NAPI poll on CPU%d\n",
 		  channel->channel, raw_smp_processor_id());
-	channel->work_pending = 1;
+	channel->work_pending = true;
 
 	netif_rx_schedule(channel->napi_dev, &channel->napi_str);
 }
diff --git a/drivers/net/sfc/enum.h b/drivers/net/sfc/enum.h
index c53290d..cec15db 100644
--- a/drivers/net/sfc/enum.h
+++ b/drivers/net/sfc/enum.h
@@ -52,12 +52,11 @@
 #define LOOPBACK_MASK(_efx)			\
 	(1 << (_efx)->loopback_mode)
 
-#define LOOPBACK_INTERNAL(_efx)						\
-	((LOOPBACKS_10G_INTERNAL & LOOPBACK_MASK(_efx)) ? 1 : 0)
+#define LOOPBACK_INTERNAL(_efx)				\
+	(!!(LOOPBACKS_10G_INTERNAL & LOOPBACK_MASK(_efx)))
 
-#define LOOPBACK_OUT_OF(_from, _to, _mask)		\
-	(((LOOPBACK_MASK(_from) & (_mask)) &&		\
-	  ((LOOPBACK_MASK(_to) & (_mask)) == 0)) ? 1 : 0)
+#define LOOPBACK_OUT_OF(_from, _to, _mask)				\
+	((LOOPBACK_MASK(_from) & (_mask)) && !(LOOPBACK_MASK(_to) & (_mask)))
 
 /*****************************************************************************/
 
diff --git a/drivers/net/sfc/ethtool.c b/drivers/net/sfc/ethtool.c
index e2c75d1..fa98af5 100644
--- a/drivers/net/sfc/ethtool.c
+++ b/drivers/net/sfc/ethtool.c
@@ -17,6 +17,7 @@
 #include "ethtool.h"
 #include "falcon.h"
 #include "gmii.h"
+#include "spi.h"
 #include "mac.h"
 
 const char *efx_loopback_mode_names[] = {
@@ -32,8 +33,6 @@
 	[LOOPBACK_NETWORK]	= "NETWORK",
 };
 
-static int efx_ethtool_set_tx_csum(struct net_device *net_dev, u32 enable);
-
 struct ethtool_string {
 	char name[ETH_GSTRING_LEN];
 };
@@ -173,6 +172,11 @@
 /* Number of ethtool statistics */
 #define EFX_ETHTOOL_NUM_STATS ARRAY_SIZE(efx_ethtool_stats)
 
+/* EEPROM range with gPXE configuration */
+#define EFX_ETHTOOL_EEPROM_MAGIC 0xEFAB
+#define EFX_ETHTOOL_EEPROM_MIN 0x100U
+#define EFX_ETHTOOL_EEPROM_MAX 0x400U
+
 /**************************************************************************
  *
  * Ethtool operations
@@ -183,7 +187,7 @@
 /* Identify device by flashing LEDs */
 static int efx_ethtool_phys_id(struct net_device *net_dev, u32 seconds)
 {
-	struct efx_nic *efx = net_dev->priv;
+	struct efx_nic *efx = netdev_priv(net_dev);
 
 	efx->board_info.blink(efx, 1);
 	schedule_timeout_interruptible(seconds * HZ);
@@ -195,7 +199,7 @@
 int efx_ethtool_get_settings(struct net_device *net_dev,
 			     struct ethtool_cmd *ecmd)
 {
-	struct efx_nic *efx = net_dev->priv;
+	struct efx_nic *efx = netdev_priv(net_dev);
 	int rc;
 
 	mutex_lock(&efx->mac_lock);
@@ -209,7 +213,7 @@
 int efx_ethtool_set_settings(struct net_device *net_dev,
 			     struct ethtool_cmd *ecmd)
 {
-	struct efx_nic *efx = net_dev->priv;
+	struct efx_nic *efx = netdev_priv(net_dev);
 	int rc;
 
 	mutex_lock(&efx->mac_lock);
@@ -224,7 +228,7 @@
 static void efx_ethtool_get_drvinfo(struct net_device *net_dev,
 				    struct ethtool_drvinfo *info)
 {
-	struct efx_nic *efx = net_dev->priv;
+	struct efx_nic *efx = netdev_priv(net_dev);
 
 	strlcpy(info->driver, EFX_DRIVER_NAME, sizeof(info->driver));
 	strlcpy(info->version, EFX_DRIVER_VERSION, sizeof(info->version));
@@ -329,7 +333,10 @@
 	unsigned int n = 0;
 	enum efx_loopback_mode mode;
 
-	/* Interrupt */
+	efx_fill_test(n++, strings, data, &tests->mii,
+		      "core", 0, "mii", NULL);
+	efx_fill_test(n++, strings, data, &tests->nvram,
+		      "core", 0, "nvram", NULL);
 	efx_fill_test(n++, strings, data, &tests->interrupt,
 		      "core", 0, "interrupt", NULL);
 
@@ -349,16 +356,17 @@
 			      "eventq.poll", NULL);
 	}
 
-	/* PHY presence */
-	efx_fill_test(n++, strings, data, &tests->phy_ok,
-		      EFX_PORT_NAME, "phy_ok", NULL);
+	efx_fill_test(n++, strings, data, &tests->registers,
+		      "core", 0, "registers", NULL);
+	efx_fill_test(n++, strings, data, &tests->phy,
+		      EFX_PORT_NAME, "phy", NULL);
 
 	/* Loopback tests */
 	efx_fill_test(n++, strings, data, &tests->loopback_speed,
 		      EFX_PORT_NAME, "loopback.speed", NULL);
 	efx_fill_test(n++, strings, data, &tests->loopback_full_duplex,
 		      EFX_PORT_NAME, "loopback.full_duplex", NULL);
-	for (mode = LOOPBACK_NONE; mode < LOOPBACK_TEST_MAX; mode++) {
+	for (mode = LOOPBACK_NONE; mode <= LOOPBACK_TEST_MAX; mode++) {
 		if (!(efx->loopback_modes & (1 << mode)))
 			continue;
 		n = efx_fill_loopback_test(efx,
@@ -369,22 +377,24 @@
 	return n;
 }
 
-static int efx_ethtool_get_stats_count(struct net_device *net_dev)
+static int efx_ethtool_get_sset_count(struct net_device *net_dev,
+				      int string_set)
 {
-	return EFX_ETHTOOL_NUM_STATS;
-}
-
-static int efx_ethtool_self_test_count(struct net_device *net_dev)
-{
-	struct efx_nic *efx = net_dev->priv;
-
-	return efx_ethtool_fill_self_tests(efx, NULL, NULL, NULL);
+	switch (string_set) {
+	case ETH_SS_STATS:
+		return EFX_ETHTOOL_NUM_STATS;
+	case ETH_SS_TEST:
+		return efx_ethtool_fill_self_tests(netdev_priv(net_dev),
+						   NULL, NULL, NULL);
+	default:
+		return -EINVAL;
+	}
 }
 
 static void efx_ethtool_get_strings(struct net_device *net_dev,
 				    u32 string_set, u8 *strings)
 {
-	struct efx_nic *efx = net_dev->priv;
+	struct efx_nic *efx = netdev_priv(net_dev);
 	struct ethtool_string *ethtool_strings =
 		(struct ethtool_string *)strings;
 	int i;
@@ -410,7 +420,7 @@
 				  struct ethtool_stats *stats,
 				  u64 *data)
 {
-	struct efx_nic *efx = net_dev->priv;
+	struct efx_nic *efx = netdev_priv(net_dev);
 	struct efx_mac_stats *mac_stats = &efx->mac_stats;
 	struct efx_ethtool_stat *stat;
 	struct efx_channel *channel;
@@ -442,60 +452,21 @@
 	}
 }
 
-static int efx_ethtool_set_tso(struct net_device *net_dev, u32 enable)
-{
-	int rc;
-
-	/* Our TSO requires TX checksumming, so force TX checksumming
-	 * on when TSO is enabled.
-	 */
-	if (enable) {
-		rc = efx_ethtool_set_tx_csum(net_dev, 1);
-		if (rc)
-			return rc;
-	}
-
-	return ethtool_op_set_tso(net_dev, enable);
-}
-
-static int efx_ethtool_set_tx_csum(struct net_device *net_dev, u32 enable)
-{
-	struct efx_nic *efx = net_dev->priv;
-	int rc;
-
-	rc = ethtool_op_set_tx_csum(net_dev, enable);
-	if (rc)
-		return rc;
-
-	efx_flush_queues(efx);
-
-	/* Our TSO requires TX checksumming, so disable TSO when
-	 * checksumming is disabled
-	 */
-	if (!enable) {
-		rc = efx_ethtool_set_tso(net_dev, 0);
-		if (rc)
-			return rc;
-	}
-
-	return 0;
-}
-
 static int efx_ethtool_set_rx_csum(struct net_device *net_dev, u32 enable)
 {
-	struct efx_nic *efx = net_dev->priv;
+	struct efx_nic *efx = netdev_priv(net_dev);
 
 	/* No way to stop the hardware doing the checks; we just
 	 * ignore the result.
 	 */
-	efx->rx_checksum_enabled = (enable ? 1 : 0);
+	efx->rx_checksum_enabled = !!enable;
 
 	return 0;
 }
 
 static u32 efx_ethtool_get_rx_csum(struct net_device *net_dev)
 {
-	struct efx_nic *efx = net_dev->priv;
+	struct efx_nic *efx = netdev_priv(net_dev);
 
 	return efx->rx_checksum_enabled;
 }
@@ -503,7 +474,7 @@
 static void efx_ethtool_self_test(struct net_device *net_dev,
 				  struct ethtool_test *test, u64 *data)
 {
-	struct efx_nic *efx = net_dev->priv;
+	struct efx_nic *efx = netdev_priv(net_dev);
 	struct efx_self_tests efx_tests;
 	int offline, already_up;
 	int rc;
@@ -533,15 +504,9 @@
 		goto out;
 
 	/* Perform offline tests only if online tests passed */
-	if (offline) {
-		/* Stop the kernel from sending packets during the test. */
-		efx_stop_queue(efx);
-		rc = efx_flush_queues(efx);
-		if (!rc)
-			rc = efx_offline_test(efx, &efx_tests,
-					      efx->loopback_modes);
-		efx_wake_queue(efx);
-	}
+	if (offline)
+		rc = efx_offline_test(efx, &efx_tests,
+				      efx->loopback_modes);
 
  out:
 	if (!already_up)
@@ -561,22 +526,65 @@
 /* Restart autonegotiation */
 static int efx_ethtool_nway_reset(struct net_device *net_dev)
 {
-	struct efx_nic *efx = net_dev->priv;
+	struct efx_nic *efx = netdev_priv(net_dev);
 
 	return mii_nway_restart(&efx->mii);
 }
 
 static u32 efx_ethtool_get_link(struct net_device *net_dev)
 {
-	struct efx_nic *efx = net_dev->priv;
+	struct efx_nic *efx = netdev_priv(net_dev);
 
 	return efx->link_up;
 }
 
+static int efx_ethtool_get_eeprom_len(struct net_device *net_dev)
+{
+	struct efx_nic *efx = netdev_priv(net_dev);
+	struct efx_spi_device *spi = efx->spi_eeprom;
+
+	if (!spi)
+		return 0;
+	return min(spi->size, EFX_ETHTOOL_EEPROM_MAX) -
+		min(spi->size, EFX_ETHTOOL_EEPROM_MIN);
+}
+
+static int efx_ethtool_get_eeprom(struct net_device *net_dev,
+				  struct ethtool_eeprom *eeprom, u8 *buf)
+{
+	struct efx_nic *efx = netdev_priv(net_dev);
+	struct efx_spi_device *spi = efx->spi_eeprom;
+	size_t len;
+	int rc;
+
+	rc = falcon_spi_read(spi, eeprom->offset + EFX_ETHTOOL_EEPROM_MIN,
+			     eeprom->len, &len, buf);
+	eeprom->magic = EFX_ETHTOOL_EEPROM_MAGIC;
+	eeprom->len = len;
+	return rc;
+}
+
+static int efx_ethtool_set_eeprom(struct net_device *net_dev,
+				  struct ethtool_eeprom *eeprom, u8 *buf)
+{
+	struct efx_nic *efx = netdev_priv(net_dev);
+	struct efx_spi_device *spi = efx->spi_eeprom;
+	size_t len;
+	int rc;
+
+	if (eeprom->magic != EFX_ETHTOOL_EEPROM_MAGIC)
+		return -EINVAL;
+
+	rc = falcon_spi_write(spi, eeprom->offset + EFX_ETHTOOL_EEPROM_MIN,
+			      eeprom->len, &len, buf);
+	eeprom->len = len;
+	return rc;
+}
+
 static int efx_ethtool_get_coalesce(struct net_device *net_dev,
 				    struct ethtool_coalesce *coalesce)
 {
-	struct efx_nic *efx = net_dev->priv;
+	struct efx_nic *efx = netdev_priv(net_dev);
 	struct efx_tx_queue *tx_queue;
 	struct efx_rx_queue *rx_queue;
 	struct efx_channel *channel;
@@ -614,7 +622,7 @@
 static int efx_ethtool_set_coalesce(struct net_device *net_dev,
 				    struct ethtool_coalesce *coalesce)
 {
-	struct efx_nic *efx = net_dev->priv;
+	struct efx_nic *efx = netdev_priv(net_dev);
 	struct efx_channel *channel;
 	struct efx_tx_queue *tx_queue;
 	unsigned tx_usecs, rx_usecs;
@@ -657,7 +665,7 @@
 static int efx_ethtool_set_pauseparam(struct net_device *net_dev,
 				      struct ethtool_pauseparam *pause)
 {
-	struct efx_nic *efx = net_dev->priv;
+	struct efx_nic *efx = netdev_priv(net_dev);
 	enum efx_fc_type flow_control = efx->flow_control;
 	int rc;
 
@@ -680,11 +688,11 @@
 static void efx_ethtool_get_pauseparam(struct net_device *net_dev,
 				       struct ethtool_pauseparam *pause)
 {
-	struct efx_nic *efx = net_dev->priv;
+	struct efx_nic *efx = netdev_priv(net_dev);
 
-	pause->rx_pause = (efx->flow_control & EFX_FC_RX) ? 1 : 0;
-	pause->tx_pause = (efx->flow_control & EFX_FC_TX) ? 1 : 0;
-	pause->autoneg = (efx->flow_control & EFX_FC_AUTO) ? 1 : 0;
+	pause->rx_pause = !!(efx->flow_control & EFX_FC_RX);
+	pause->tx_pause = !!(efx->flow_control & EFX_FC_TX);
+	pause->autoneg = !!(efx->flow_control & EFX_FC_AUTO);
 }
 
 
@@ -694,6 +702,9 @@
 	.get_drvinfo		= efx_ethtool_get_drvinfo,
 	.nway_reset		= efx_ethtool_nway_reset,
 	.get_link		= efx_ethtool_get_link,
+	.get_eeprom_len		= efx_ethtool_get_eeprom_len,
+	.get_eeprom		= efx_ethtool_get_eeprom,
+	.set_eeprom		= efx_ethtool_set_eeprom,
 	.get_coalesce		= efx_ethtool_get_coalesce,
 	.set_coalesce		= efx_ethtool_set_coalesce,
 	.get_pauseparam         = efx_ethtool_get_pauseparam,
@@ -701,17 +712,16 @@
 	.get_rx_csum		= efx_ethtool_get_rx_csum,
 	.set_rx_csum		= efx_ethtool_set_rx_csum,
 	.get_tx_csum		= ethtool_op_get_tx_csum,
-	.set_tx_csum		= efx_ethtool_set_tx_csum,
+	.set_tx_csum		= ethtool_op_set_tx_csum,
 	.get_sg			= ethtool_op_get_sg,
 	.set_sg			= ethtool_op_set_sg,
 	.get_tso		= ethtool_op_get_tso,
-	.set_tso		= efx_ethtool_set_tso,
+	.set_tso		= ethtool_op_set_tso,
 	.get_flags		= ethtool_op_get_flags,
 	.set_flags		= ethtool_op_set_flags,
-	.self_test_count	= efx_ethtool_self_test_count,
+	.get_sset_count		= efx_ethtool_get_sset_count,
 	.self_test		= efx_ethtool_self_test,
 	.get_strings		= efx_ethtool_get_strings,
 	.phys_id		= efx_ethtool_phys_id,
-	.get_stats_count	= efx_ethtool_get_stats_count,
 	.get_ethtool_stats	= efx_ethtool_get_stats,
 };
diff --git a/drivers/net/sfc/falcon.c b/drivers/net/sfc/falcon.c
index 9138ee5..31ed1f4 100644
--- a/drivers/net/sfc/falcon.c
+++ b/drivers/net/sfc/falcon.c
@@ -108,10 +108,10 @@
 /* Max number of internal errors. After this resets will not be performed */
 #define FALCON_MAX_INT_ERRORS 4
 
-/* Maximum period that we wait for flush events. If the flush event
- * doesn't arrive in this period of time then we check if the queue
- * was disabled anyway. */
-#define FALCON_FLUSH_TIMEOUT 10 /* 10ms */
+/* We poll for events every FLUSH_INTERVAL ms, and check FLUSH_POLL_COUNT times
+ */
+#define FALCON_FLUSH_INTERVAL 10
+#define FALCON_FLUSH_POLL_COUNT 100
 
 /**************************************************************************
  *
@@ -242,7 +242,7 @@
  * falcon_alloc_special_buffer()) in Falcon's buffer table, allowing
  * it to be used for event queues, descriptor rings etc.
  */
-static int
+static void
 falcon_init_special_buffer(struct efx_nic *efx,
 			   struct efx_special_buffer *buffer)
 {
@@ -266,8 +266,6 @@
 				     BUF_OWNER_ID_FBUF, 0);
 		falcon_write_sram(efx, &buf_desc, index);
 	}
-
-	return 0;
 }
 
 /* Unmaps a buffer from Falcon and clears the buffer table entries */
@@ -449,16 +447,15 @@
 					   sizeof(efx_qword_t));
 }
 
-int falcon_init_tx(struct efx_tx_queue *tx_queue)
+void falcon_init_tx(struct efx_tx_queue *tx_queue)
 {
 	efx_oword_t tx_desc_ptr;
 	struct efx_nic *efx = tx_queue->efx;
-	int rc;
+
+	tx_queue->flushed = false;
 
 	/* Pin TX descriptor ring */
-	rc = falcon_init_special_buffer(efx, &tx_queue->txd);
-	if (rc)
-		return rc;
+	falcon_init_special_buffer(efx, &tx_queue->txd);
 
 	/* Push TX descriptor ring to card */
 	EFX_POPULATE_OWORD_10(tx_desc_ptr,
@@ -466,7 +463,7 @@
 			      TX_ISCSI_DDIG_EN, 0,
 			      TX_ISCSI_HDIG_EN, 0,
 			      TX_DESCQ_BUF_BASE_ID, tx_queue->txd.index,
-			      TX_DESCQ_EVQ_ID, tx_queue->channel->evqnum,
+			      TX_DESCQ_EVQ_ID, tx_queue->channel->channel,
 			      TX_DESCQ_OWNER_ID, 0,
 			      TX_DESCQ_LABEL, tx_queue->queue,
 			      TX_DESCQ_SIZE, FALCON_TXD_RING_ORDER,
@@ -474,9 +471,9 @@
 			      TX_NON_IP_DROP_DIS_B0, 1);
 
 	if (falcon_rev(efx) >= FALCON_REV_B0) {
-		int csum = !(efx->net_dev->features & NETIF_F_IP_CSUM);
-		EFX_SET_OWORD_FIELD(tx_desc_ptr, TX_IP_CHKSM_DIS_B0, csum);
-		EFX_SET_OWORD_FIELD(tx_desc_ptr, TX_TCP_CHKSM_DIS_B0, csum);
+		int csum = tx_queue->queue == EFX_TX_QUEUE_OFFLOAD_CSUM;
+		EFX_SET_OWORD_FIELD(tx_desc_ptr, TX_IP_CHKSM_DIS_B0, !csum);
+		EFX_SET_OWORD_FIELD(tx_desc_ptr, TX_TCP_CHKSM_DIS_B0, !csum);
 	}
 
 	falcon_write_table(efx, &tx_desc_ptr, efx->type->txd_ptr_tbl_base,
@@ -485,73 +482,28 @@
 	if (falcon_rev(efx) < FALCON_REV_B0) {
 		efx_oword_t reg;
 
-		BUG_ON(tx_queue->queue >= 128); /* HW limit */
+		/* Only 128 bits in this register */
+		BUILD_BUG_ON(EFX_TX_QUEUE_COUNT >= 128);
 
 		falcon_read(efx, &reg, TX_CHKSM_CFG_REG_KER_A1);
-		if (efx->net_dev->features & NETIF_F_IP_CSUM)
+		if (tx_queue->queue == EFX_TX_QUEUE_OFFLOAD_CSUM)
 			clear_bit_le(tx_queue->queue, (void *)&reg);
 		else
 			set_bit_le(tx_queue->queue, (void *)&reg);
 		falcon_write(efx, &reg, TX_CHKSM_CFG_REG_KER_A1);
 	}
-
-	return 0;
 }
 
-static int falcon_flush_tx_queue(struct efx_tx_queue *tx_queue)
+static void falcon_flush_tx_queue(struct efx_tx_queue *tx_queue)
 {
 	struct efx_nic *efx = tx_queue->efx;
-	struct efx_channel *channel = &efx->channel[0];
 	efx_oword_t tx_flush_descq;
-	unsigned int read_ptr, i;
 
 	/* Post a flush command */
 	EFX_POPULATE_OWORD_2(tx_flush_descq,
 			     TX_FLUSH_DESCQ_CMD, 1,
 			     TX_FLUSH_DESCQ, tx_queue->queue);
 	falcon_write(efx, &tx_flush_descq, TX_FLUSH_DESCQ_REG_KER);
-	msleep(FALCON_FLUSH_TIMEOUT);
-
-	if (EFX_WORKAROUND_7803(efx))
-		return 0;
-
-	/* Look for a flush completed event */
-	read_ptr = channel->eventq_read_ptr;
-	for (i = 0; i < FALCON_EVQ_SIZE; ++i) {
-		efx_qword_t *event = falcon_event(channel, read_ptr);
-		int ev_code, ev_sub_code, ev_queue;
-		if (!falcon_event_present(event))
-			break;
-
-		ev_code = EFX_QWORD_FIELD(*event, EV_CODE);
-		ev_sub_code = EFX_QWORD_FIELD(*event, DRIVER_EV_SUB_CODE);
-		ev_queue = EFX_QWORD_FIELD(*event, DRIVER_EV_TX_DESCQ_ID);
-		if ((ev_sub_code == TX_DESCQ_FLS_DONE_EV_DECODE) &&
-		    (ev_queue == tx_queue->queue)) {
-			EFX_LOG(efx, "tx queue %d flush command succesful\n",
-				tx_queue->queue);
-			return 0;
-		}
-
-		read_ptr = (read_ptr + 1) & FALCON_EVQ_MASK;
-	}
-
-	if (EFX_WORKAROUND_11557(efx)) {
-		efx_oword_t reg;
-		int enabled;
-
-		falcon_read_table(efx, &reg, efx->type->txd_ptr_tbl_base,
-				  tx_queue->queue);
-		enabled = EFX_OWORD_FIELD(reg, TX_DESCQ_EN);
-		if (!enabled) {
-			EFX_LOG(efx, "tx queue %d disabled without a "
-				"flush event seen\n", tx_queue->queue);
-			return 0;
-		}
-	}
-
-	EFX_ERR(efx, "tx queue %d flush command timed out\n", tx_queue->queue);
-	return -ETIMEDOUT;
 }
 
 void falcon_fini_tx(struct efx_tx_queue *tx_queue)
@@ -559,9 +511,8 @@
 	struct efx_nic *efx = tx_queue->efx;
 	efx_oword_t tx_desc_ptr;
 
-	/* Stop the hardware using the queue */
-	if (falcon_flush_tx_queue(tx_queue))
-		EFX_ERR(efx, "failed to flush tx queue %d\n", tx_queue->queue);
+	/* The queue should have been flushed */
+	WARN_ON(!tx_queue->flushed);
 
 	/* Remove TX descriptor ring from card */
 	EFX_ZERO_OWORD(tx_desc_ptr);
@@ -638,29 +589,28 @@
 					   sizeof(efx_qword_t));
 }
 
-int falcon_init_rx(struct efx_rx_queue *rx_queue)
+void falcon_init_rx(struct efx_rx_queue *rx_queue)
 {
 	efx_oword_t rx_desc_ptr;
 	struct efx_nic *efx = rx_queue->efx;
-	int rc;
-	int is_b0 = falcon_rev(efx) >= FALCON_REV_B0;
-	int iscsi_digest_en = is_b0;
+	bool is_b0 = falcon_rev(efx) >= FALCON_REV_B0;
+	bool iscsi_digest_en = is_b0;
 
 	EFX_LOG(efx, "RX queue %d ring in special buffers %d-%d\n",
 		rx_queue->queue, rx_queue->rxd.index,
 		rx_queue->rxd.index + rx_queue->rxd.entries - 1);
 
+	rx_queue->flushed = false;
+
 	/* Pin RX descriptor ring */
-	rc = falcon_init_special_buffer(efx, &rx_queue->rxd);
-	if (rc)
-		return rc;
+	falcon_init_special_buffer(efx, &rx_queue->rxd);
 
 	/* Push RX descriptor ring to card */
 	EFX_POPULATE_OWORD_10(rx_desc_ptr,
 			      RX_ISCSI_DDIG_EN, iscsi_digest_en,
 			      RX_ISCSI_HDIG_EN, iscsi_digest_en,
 			      RX_DESCQ_BUF_BASE_ID, rx_queue->rxd.index,
-			      RX_DESCQ_EVQ_ID, rx_queue->channel->evqnum,
+			      RX_DESCQ_EVQ_ID, rx_queue->channel->channel,
 			      RX_DESCQ_OWNER_ID, 0,
 			      RX_DESCQ_LABEL, rx_queue->queue,
 			      RX_DESCQ_SIZE, FALCON_RXD_RING_ORDER,
@@ -670,14 +620,11 @@
 			      RX_DESCQ_EN, 1);
 	falcon_write_table(efx, &rx_desc_ptr, efx->type->rxd_ptr_tbl_base,
 			   rx_queue->queue);
-	return 0;
 }
 
-static int falcon_flush_rx_queue(struct efx_rx_queue *rx_queue)
+static void falcon_flush_rx_queue(struct efx_rx_queue *rx_queue)
 {
 	struct efx_nic *efx = rx_queue->efx;
-	struct efx_channel *channel = &efx->channel[0];
-	unsigned int read_ptr, i;
 	efx_oword_t rx_flush_descq;
 
 	/* Post a flush command */
@@ -685,75 +632,15 @@
 			     RX_FLUSH_DESCQ_CMD, 1,
 			     RX_FLUSH_DESCQ, rx_queue->queue);
 	falcon_write(efx, &rx_flush_descq, RX_FLUSH_DESCQ_REG_KER);
-	msleep(FALCON_FLUSH_TIMEOUT);
-
-	if (EFX_WORKAROUND_7803(efx))
-		return 0;
-
-	/* Look for a flush completed event */
-	read_ptr = channel->eventq_read_ptr;
-	for (i = 0; i < FALCON_EVQ_SIZE; ++i) {
-		efx_qword_t *event = falcon_event(channel, read_ptr);
-		int ev_code, ev_sub_code, ev_queue, ev_failed;
-		if (!falcon_event_present(event))
-			break;
-
-		ev_code = EFX_QWORD_FIELD(*event, EV_CODE);
-		ev_sub_code = EFX_QWORD_FIELD(*event, DRIVER_EV_SUB_CODE);
-		ev_queue = EFX_QWORD_FIELD(*event, DRIVER_EV_RX_DESCQ_ID);
-		ev_failed = EFX_QWORD_FIELD(*event, DRIVER_EV_RX_FLUSH_FAIL);
-
-		if ((ev_sub_code == RX_DESCQ_FLS_DONE_EV_DECODE) &&
-		    (ev_queue == rx_queue->queue)) {
-			if (ev_failed) {
-				EFX_INFO(efx, "rx queue %d flush command "
-					 "failed\n", rx_queue->queue);
-				return -EAGAIN;
-			} else {
-				EFX_LOG(efx, "rx queue %d flush command "
-					"succesful\n", rx_queue->queue);
-				return 0;
-			}
-		}
-
-		read_ptr = (read_ptr + 1) & FALCON_EVQ_MASK;
-	}
-
-	if (EFX_WORKAROUND_11557(efx)) {
-		efx_oword_t reg;
-		int enabled;
-
-		falcon_read_table(efx, &reg, efx->type->rxd_ptr_tbl_base,
-				  rx_queue->queue);
-		enabled = EFX_OWORD_FIELD(reg, RX_DESCQ_EN);
-		if (!enabled) {
-			EFX_LOG(efx, "rx queue %d disabled without a "
-				"flush event seen\n", rx_queue->queue);
-			return 0;
-		}
-	}
-
-	EFX_ERR(efx, "rx queue %d flush command timed out\n", rx_queue->queue);
-	return -ETIMEDOUT;
 }
 
 void falcon_fini_rx(struct efx_rx_queue *rx_queue)
 {
 	efx_oword_t rx_desc_ptr;
 	struct efx_nic *efx = rx_queue->efx;
-	int i, rc;
 
-	/* Try and flush the rx queue. This may need to be repeated */
-	for (i = 0; i < 5; i++) {
-		rc = falcon_flush_rx_queue(rx_queue);
-		if (rc == -EAGAIN)
-			continue;
-		break;
-	}
-	if (rc) {
-		EFX_ERR(efx, "failed to flush rx queue %d\n", rx_queue->queue);
-		efx_schedule_reset(efx, RESET_TYPE_INVISIBLE);
-	}
+	/* The queue should already have been flushed */
+	WARN_ON(!rx_queue->flushed);
 
 	/* Remove RX descriptor ring from card */
 	EFX_ZERO_OWORD(rx_desc_ptr);
@@ -793,7 +680,7 @@
 
 	EFX_POPULATE_DWORD_1(reg, EVQ_RPTR_DWORD, channel->eventq_read_ptr);
 	falcon_writel_table(efx, &reg, efx->type->evq_rptr_tbl_base,
-			    channel->evqnum);
+			    channel->channel);
 }
 
 /* Use HW to insert a SW defined event */
@@ -802,7 +689,7 @@
 	efx_oword_t drv_ev_reg;
 
 	EFX_POPULATE_OWORD_2(drv_ev_reg,
-			     DRV_EV_QID, channel->evqnum,
+			     DRV_EV_QID, channel->channel,
 			     DRV_EV_DATA,
 			     EFX_QWORD_FIELD64(*event, WHOLE_EVENT));
 	falcon_write(channel->efx, &drv_ev_reg, DRV_EV_REG_KER);
@@ -813,8 +700,8 @@
  * Falcon batches TX completion events; the message we receive is of
  * the form "complete all TX events up to this index".
  */
-static inline void falcon_handle_tx_event(struct efx_channel *channel,
-					  efx_qword_t *event)
+static void falcon_handle_tx_event(struct efx_channel *channel,
+				   efx_qword_t *event)
 {
 	unsigned int tx_ev_desc_ptr;
 	unsigned int tx_ev_q_label;
@@ -847,39 +734,19 @@
 	}
 }
 
-/* Check received packet's destination MAC address. */
-static int check_dest_mac(struct efx_rx_queue *rx_queue,
-			  const efx_qword_t *event)
-{
-	struct efx_rx_buffer *rx_buf;
-	struct efx_nic *efx = rx_queue->efx;
-	int rx_ev_desc_ptr;
-	struct ethhdr *eh;
-
-	if (efx->promiscuous)
-		return 1;
-
-	rx_ev_desc_ptr = EFX_QWORD_FIELD(*event, RX_EV_DESC_PTR);
-	rx_buf = efx_rx_buffer(rx_queue, rx_ev_desc_ptr);
-	eh = (struct ethhdr *)rx_buf->data;
-	if (memcmp(eh->h_dest, efx->net_dev->dev_addr, ETH_ALEN))
-		return 0;
-	return 1;
-}
-
 /* Detect errors included in the rx_evt_pkt_ok bit. */
 static void falcon_handle_rx_not_ok(struct efx_rx_queue *rx_queue,
 				    const efx_qword_t *event,
-				    unsigned *rx_ev_pkt_ok,
-				    int *discard, int byte_count)
+				    bool *rx_ev_pkt_ok,
+				    bool *discard)
 {
 	struct efx_nic *efx = rx_queue->efx;
-	unsigned rx_ev_buf_owner_id_err, rx_ev_ip_hdr_chksum_err;
-	unsigned rx_ev_tcp_udp_chksum_err, rx_ev_eth_crc_err;
-	unsigned rx_ev_frm_trunc, rx_ev_drib_nib, rx_ev_tobe_disc;
-	unsigned rx_ev_pkt_type, rx_ev_other_err, rx_ev_pause_frm;
-	unsigned rx_ev_ip_frag_err, rx_ev_hdr_type, rx_ev_mcast_pkt;
-	int snap, non_ip;
+	bool rx_ev_buf_owner_id_err, rx_ev_ip_hdr_chksum_err;
+	bool rx_ev_tcp_udp_chksum_err, rx_ev_eth_crc_err;
+	bool rx_ev_frm_trunc, rx_ev_drib_nib, rx_ev_tobe_disc;
+	bool rx_ev_other_err, rx_ev_pause_frm;
+	bool rx_ev_ip_frag_err, rx_ev_hdr_type, rx_ev_mcast_pkt;
+	unsigned rx_ev_pkt_type;
 
 	rx_ev_hdr_type = EFX_QWORD_FIELD(*event, RX_EV_HDR_TYPE);
 	rx_ev_mcast_pkt = EFX_QWORD_FIELD(*event, RX_EV_MCAST_PKT);
@@ -903,41 +770,6 @@
 			   rx_ev_buf_owner_id_err | rx_ev_eth_crc_err |
 			   rx_ev_frm_trunc | rx_ev_ip_hdr_chksum_err);
 
-	snap = (rx_ev_pkt_type == RX_EV_PKT_TYPE_LLC_DECODE) ||
-		(rx_ev_pkt_type == RX_EV_PKT_TYPE_VLAN_LLC_DECODE);
-	non_ip = (rx_ev_hdr_type == RX_EV_HDR_TYPE_NON_IP_DECODE);
-
-	/* SFC bug 5475/8970: The Falcon XMAC incorrectly calculates the
-	 * length field of an LLC frame, which sets TOBE_DISC. We could set
-	 * PASS_LEN_ERR, but we want the MAC to filter out short frames (to
-	 * protect the RX block).
-	 *
-	 * bug5475 - LLC/SNAP: Falcon identifies SNAP packets.
-	 * bug8970 - LLC/noSNAP: Falcon does not provide an LLC flag.
-	 *                       LLC can't encapsulate IP, so by definition
-	 *                       these packets are NON_IP.
-	 *
-	 * Unicast mismatch will also cause TOBE_DISC, so the driver needs
-	 * to check this.
-	 */
-	if (EFX_WORKAROUND_5475(efx) && rx_ev_tobe_disc && (snap || non_ip)) {
-		/* If all the other flags are zero then we can state the
-		 * entire packet is ok, which will flag to the kernel not
-		 * to recalculate checksums.
-		 */
-		if (!(non_ip | rx_ev_other_err | rx_ev_pause_frm))
-			*rx_ev_pkt_ok = 1;
-
-		rx_ev_tobe_disc = 0;
-
-		/* TOBE_DISC is set for unicast mismatch.  But given that
-		 * we can't trust TOBE_DISC here, we must validate the dest
-		 * MAC address ourselves.
-		 */
-		if (!rx_ev_mcast_pkt && !check_dest_mac(rx_queue, event))
-			rx_ev_tobe_disc = 1;
-	}
-
 	/* Count errors that are not in MAC stats. */
 	if (rx_ev_frm_trunc)
 		++rx_queue->channel->n_rx_frm_trunc;
@@ -961,7 +793,7 @@
 #ifdef EFX_ENABLE_DEBUG
 	if (rx_ev_other_err) {
 		EFX_INFO_RL(efx, " RX queue %d unexpected RX event "
-			    EFX_QWORD_FMT "%s%s%s%s%s%s%s%s%s\n",
+			    EFX_QWORD_FMT "%s%s%s%s%s%s%s%s\n",
 			    rx_queue->queue, EFX_QWORD_VAL(*event),
 			    rx_ev_buf_owner_id_err ? " [OWNER_ID_ERR]" : "",
 			    rx_ev_ip_hdr_chksum_err ?
@@ -972,8 +804,7 @@
 			    rx_ev_frm_trunc ? " [FRM_TRUNC]" : "",
 			    rx_ev_drib_nib ? " [DRIB_NIB]" : "",
 			    rx_ev_tobe_disc ? " [TOBE_DISC]" : "",
-			    rx_ev_pause_frm ? " [PAUSE]" : "",
-			    snap ? " [SNAP/LLC]" : "");
+			    rx_ev_pause_frm ? " [PAUSE]" : "");
 	}
 #endif
 
@@ -1006,13 +837,13 @@
  * Also "is multicast" and "matches multicast filter" flags can be used to
  * discard non-matching multicast packets.
  */
-static inline int falcon_handle_rx_event(struct efx_channel *channel,
-					 const efx_qword_t *event)
+static void falcon_handle_rx_event(struct efx_channel *channel,
+				   const efx_qword_t *event)
 {
-	unsigned int rx_ev_q_label, rx_ev_desc_ptr, rx_ev_byte_cnt;
-	unsigned int rx_ev_pkt_ok, rx_ev_hdr_type, rx_ev_mcast_pkt;
+	unsigned int rx_ev_desc_ptr, rx_ev_byte_cnt;
+	unsigned int rx_ev_hdr_type, rx_ev_mcast_pkt;
 	unsigned expected_ptr;
-	int discard = 0, checksummed;
+	bool rx_ev_pkt_ok, discard = false, checksummed;
 	struct efx_rx_queue *rx_queue;
 	struct efx_nic *efx = channel->efx;
 
@@ -1022,16 +853,14 @@
 	rx_ev_hdr_type = EFX_QWORD_FIELD(*event, RX_EV_HDR_TYPE);
 	WARN_ON(EFX_QWORD_FIELD(*event, RX_EV_JUMBO_CONT));
 	WARN_ON(EFX_QWORD_FIELD(*event, RX_EV_SOP) != 1);
+	WARN_ON(EFX_QWORD_FIELD(*event, RX_EV_Q_LABEL) != channel->channel);
 
-	rx_ev_q_label = EFX_QWORD_FIELD(*event, RX_EV_Q_LABEL);
-	rx_queue = &efx->rx_queue[rx_ev_q_label];
+	rx_queue = &efx->rx_queue[channel->channel];
 
 	rx_ev_desc_ptr = EFX_QWORD_FIELD(*event, RX_EV_DESC_PTR);
 	expected_ptr = rx_queue->removed_count & FALCON_RXD_RING_MASK;
-	if (unlikely(rx_ev_desc_ptr != expected_ptr)) {
+	if (unlikely(rx_ev_desc_ptr != expected_ptr))
 		falcon_handle_rx_bad_index(rx_queue, rx_ev_desc_ptr);
-		return rx_ev_q_label;
-	}
 
 	if (likely(rx_ev_pkt_ok)) {
 		/* If packet is marked as OK and packet type is TCP/IPv4 or
@@ -1040,8 +869,8 @@
 		checksummed = RX_EV_HDR_TYPE_HAS_CHECKSUMS(rx_ev_hdr_type);
 	} else {
 		falcon_handle_rx_not_ok(rx_queue, event, &rx_ev_pkt_ok,
-					&discard, rx_ev_byte_cnt);
-		checksummed = 0;
+					&discard);
+		checksummed = false;
 	}
 
 	/* Detect multicast packets that didn't match the filter */
@@ -1051,14 +880,12 @@
 			EFX_QWORD_FIELD(*event, RX_EV_MCAST_HASH_MATCH);
 
 		if (unlikely(!rx_ev_mcast_hash_match))
-			discard = 1;
+			discard = true;
 	}
 
 	/* Handle received packet */
 	efx_rx_packet(rx_queue, rx_ev_desc_ptr, rx_ev_byte_cnt,
 		      checksummed, discard);
-
-	return rx_ev_q_label;
 }
 
 /* Global events are basically PHY events */
@@ -1066,23 +893,23 @@
 				       efx_qword_t *event)
 {
 	struct efx_nic *efx = channel->efx;
-	int is_phy_event = 0, handled = 0;
+	bool is_phy_event = false, handled = false;
 
 	/* Check for interrupt on either port.  Some boards have a
 	 * single PHY wired to the interrupt line for port 1. */
 	if (EFX_QWORD_FIELD(*event, G_PHY0_INTR) ||
 	    EFX_QWORD_FIELD(*event, G_PHY1_INTR) ||
 	    EFX_QWORD_FIELD(*event, XG_PHY_INTR))
-		is_phy_event = 1;
+		is_phy_event = true;
 
 	if ((falcon_rev(efx) >= FALCON_REV_B0) &&
-	    EFX_OWORD_FIELD(*event, XG_MNT_INTR_B0))
-		is_phy_event = 1;
+	    EFX_QWORD_FIELD(*event, XG_MNT_INTR_B0))
+		is_phy_event = true;
 
 	if (is_phy_event) {
 		efx->phy_op->clear_interrupt(efx);
 		queue_work(efx->workqueue, &efx->reconfigure_work);
-		handled = 1;
+		handled = true;
 	}
 
 	if (EFX_QWORD_FIELD_VER(efx, *event, RX_RECOVERY)) {
@@ -1092,7 +919,7 @@
 		atomic_inc(&efx->rx_reset);
 		efx_schedule_reset(efx, EFX_WORKAROUND_6555(efx) ?
 				   RESET_TYPE_RX_RECOVERY : RESET_TYPE_DISABLE);
-		handled = 1;
+		handled = true;
 	}
 
 	if (!handled)
@@ -1163,13 +990,12 @@
 	}
 }
 
-int falcon_process_eventq(struct efx_channel *channel, int *rx_quota)
+int falcon_process_eventq(struct efx_channel *channel, int rx_quota)
 {
 	unsigned int read_ptr;
 	efx_qword_t event, *p_event;
 	int ev_code;
-	int rxq;
-	int rxdmaqs = 0;
+	int rx_packets = 0;
 
 	read_ptr = channel->eventq_read_ptr;
 
@@ -1191,9 +1017,8 @@
 
 		switch (ev_code) {
 		case RX_IP_EV_DECODE:
-			rxq = falcon_handle_rx_event(channel, &event);
-			rxdmaqs |= (1 << rxq);
-			(*rx_quota)--;
+			falcon_handle_rx_event(channel, &event);
+			++rx_packets;
 			break;
 		case TX_IP_EV_DECODE:
 			falcon_handle_tx_event(channel, &event);
@@ -1220,10 +1045,10 @@
 		/* Increment read pointer */
 		read_ptr = (read_ptr + 1) & FALCON_EVQ_MASK;
 
-	} while (*rx_quota);
+	} while (rx_packets < rx_quota);
 
 	channel->eventq_read_ptr = read_ptr;
-	return rxdmaqs;
+	return rx_packets;
 }
 
 void falcon_set_int_moderation(struct efx_channel *channel)
@@ -1251,7 +1076,7 @@
 				     TIMER_VAL, 0);
 	}
 	falcon_writel_page_locked(efx, &timer_cmd, TIMER_CMD_REG_KER,
-				  channel->evqnum);
+				  channel->channel);
 
 }
 
@@ -1265,20 +1090,17 @@
 	return falcon_alloc_special_buffer(efx, &channel->eventq, evq_size);
 }
 
-int falcon_init_eventq(struct efx_channel *channel)
+void falcon_init_eventq(struct efx_channel *channel)
 {
 	efx_oword_t evq_ptr;
 	struct efx_nic *efx = channel->efx;
-	int rc;
 
 	EFX_LOG(efx, "channel %d event queue in special buffers %d-%d\n",
 		channel->channel, channel->eventq.index,
 		channel->eventq.index + channel->eventq.entries - 1);
 
 	/* Pin event queue buffer */
-	rc = falcon_init_special_buffer(efx, &channel->eventq);
-	if (rc)
-		return rc;
+	falcon_init_special_buffer(efx, &channel->eventq);
 
 	/* Fill event queue with all ones (i.e. empty events) */
 	memset(channel->eventq.addr, 0xff, channel->eventq.len);
@@ -1289,11 +1111,9 @@
 			     EVQ_SIZE, FALCON_EVQ_ORDER,
 			     EVQ_BUF_BASE_ID, channel->eventq.index);
 	falcon_write_table(efx, &evq_ptr, efx->type->evq_ptr_tbl_base,
-			   channel->evqnum);
+			   channel->channel);
 
 	falcon_set_int_moderation(channel);
-
-	return 0;
 }
 
 void falcon_fini_eventq(struct efx_channel *channel)
@@ -1304,7 +1124,7 @@
 	/* Remove event queue from card */
 	EFX_ZERO_OWORD(eventq_ptr);
 	falcon_write_table(efx, &eventq_ptr, efx->type->evq_ptr_tbl_base,
-			   channel->evqnum);
+			   channel->channel);
 
 	/* Unpin event queue */
 	falcon_fini_special_buffer(efx, &channel->eventq);
@@ -1331,6 +1151,121 @@
 	falcon_generate_event(channel, &test_event);
 }
 
+/**************************************************************************
+ *
+ * Flush handling
+ *
+ **************************************************************************/
+
+
+static void falcon_poll_flush_events(struct efx_nic *efx)
+{
+	struct efx_channel *channel = &efx->channel[0];
+	struct efx_tx_queue *tx_queue;
+	struct efx_rx_queue *rx_queue;
+	unsigned int read_ptr, i;
+
+	read_ptr = channel->eventq_read_ptr;
+	for (i = 0; i < FALCON_EVQ_SIZE; ++i) {
+		efx_qword_t *event = falcon_event(channel, read_ptr);
+		int ev_code, ev_sub_code, ev_queue;
+		bool ev_failed;
+		if (!falcon_event_present(event))
+			break;
+
+		ev_code = EFX_QWORD_FIELD(*event, EV_CODE);
+		if (ev_code != DRIVER_EV_DECODE)
+			continue;
+
+		ev_sub_code = EFX_QWORD_FIELD(*event, DRIVER_EV_SUB_CODE);
+		switch (ev_sub_code) {
+		case TX_DESCQ_FLS_DONE_EV_DECODE:
+			ev_queue = EFX_QWORD_FIELD(*event,
+						   DRIVER_EV_TX_DESCQ_ID);
+			if (ev_queue < EFX_TX_QUEUE_COUNT) {
+				tx_queue = efx->tx_queue + ev_queue;
+				tx_queue->flushed = true;
+			}
+			break;
+		case RX_DESCQ_FLS_DONE_EV_DECODE:
+			ev_queue = EFX_QWORD_FIELD(*event,
+						   DRIVER_EV_RX_DESCQ_ID);
+			ev_failed = EFX_QWORD_FIELD(*event,
+						    DRIVER_EV_RX_FLUSH_FAIL);
+			if (ev_queue < efx->n_rx_queues) {
+				rx_queue = efx->rx_queue + ev_queue;
+
+				/* retry the rx flush */
+				if (ev_failed)
+					falcon_flush_rx_queue(rx_queue);
+				else
+					rx_queue->flushed = true;
+			}
+			break;
+		}
+
+		read_ptr = (read_ptr + 1) & FALCON_EVQ_MASK;
+	}
+}
+
+/* Handle tx and rx flushes at the same time, since they run in
+ * parallel in the hardware and there's no reason for us to
+ * serialise them */
+int falcon_flush_queues(struct efx_nic *efx)
+{
+	struct efx_rx_queue *rx_queue;
+	struct efx_tx_queue *tx_queue;
+	int i;
+	bool outstanding;
+
+	/* Issue flush requests */
+	efx_for_each_tx_queue(tx_queue, efx) {
+		tx_queue->flushed = false;
+		falcon_flush_tx_queue(tx_queue);
+	}
+	efx_for_each_rx_queue(rx_queue, efx) {
+		rx_queue->flushed = false;
+		falcon_flush_rx_queue(rx_queue);
+	}
+
+	/* Poll the evq looking for flush completions. Since we're not pushing
+	 * any more rx or tx descriptors at this point, we're in no danger of
+	 * overflowing the evq whilst we wait */
+	for (i = 0; i < FALCON_FLUSH_POLL_COUNT; ++i) {
+		msleep(FALCON_FLUSH_INTERVAL);
+		falcon_poll_flush_events(efx);
+
+		/* Check if every queue has been succesfully flushed */
+		outstanding = false;
+		efx_for_each_tx_queue(tx_queue, efx)
+			outstanding |= !tx_queue->flushed;
+		efx_for_each_rx_queue(rx_queue, efx)
+			outstanding |= !rx_queue->flushed;
+		if (!outstanding)
+			return 0;
+	}
+
+	/* Mark the queues as all flushed. We're going to return failure
+	 * leading to a reset, or fake up success anyway. "flushed" now
+	 * indicates that we tried to flush. */
+	efx_for_each_tx_queue(tx_queue, efx) {
+		if (!tx_queue->flushed)
+			EFX_ERR(efx, "tx queue %d flush command timed out\n",
+				tx_queue->queue);
+		tx_queue->flushed = true;
+	}
+	efx_for_each_rx_queue(rx_queue, efx) {
+		if (!rx_queue->flushed)
+			EFX_ERR(efx, "rx queue %d flush command timed out\n",
+				rx_queue->queue);
+		rx_queue->flushed = true;
+	}
+
+	if (EFX_WORKAROUND_7803(efx))
+		return 0;
+
+	return -ETIMEDOUT;
+}
 
 /**************************************************************************
  *
@@ -1371,7 +1306,7 @@
 
 	/* Force processing of all the channels to get the EVQ RPTRs up to
 	   date */
-	efx_for_each_channel_with_interrupt(channel, efx)
+	efx_for_each_channel(channel, efx)
 		efx_schedule_channel(channel);
 }
 
@@ -1439,10 +1374,11 @@
 			EFX_OWORD_FMT "\n", EFX_OWORD_VAL(reg));
 	}
 
-	/* Disable DMA bus mastering on both devices */
+	/* Disable both devices */
 	pci_disable_device(efx->pci_dev);
 	if (FALCON_IS_DUAL_FUNC(efx))
 		pci_disable_device(nic_data->pci_dev2);
+	falcon_disable_interrupts(efx);
 
 	if (++n_int_errors < FALCON_MAX_INT_ERRORS) {
 		EFX_ERR(efx, "SYSTEM ERROR - reset scheduled\n");
@@ -1589,7 +1525,7 @@
 	     offset < RX_RSS_INDIR_TBL_B0 + 0x800;
 	     offset += 0x10) {
 		EFX_POPULATE_DWORD_1(dword, RX_RSS_INDIR_ENT_B0,
-				     i % efx->rss_queues);
+				     i % efx->n_rx_queues);
 		falcon_writel(efx, &dword, offset);
 		i++;
 	}
@@ -1621,7 +1557,7 @@
 	}
 
 	/* Hook MSI or MSI-X interrupt */
-	efx_for_each_channel_with_interrupt(channel, efx) {
+	efx_for_each_channel(channel, efx) {
 		rc = request_irq(channel->irq, falcon_msi_interrupt,
 				 IRQF_PROBE_SHARED, /* Not shared */
 				 efx->name, channel);
@@ -1634,7 +1570,7 @@
 	return 0;
 
  fail2:
-	efx_for_each_channel_with_interrupt(channel, efx)
+	efx_for_each_channel(channel, efx)
 		free_irq(channel->irq, channel);
  fail1:
 	return rc;
@@ -1646,7 +1582,7 @@
 	efx_oword_t reg;
 
 	/* Disable MSI/MSI-X interrupts */
-	efx_for_each_channel_with_interrupt(channel, efx) {
+	efx_for_each_channel(channel, efx) {
 		if (channel->irq)
 			free_irq(channel->irq, channel);
 	}
@@ -1669,69 +1605,200 @@
  **************************************************************************
  */
 
-#define FALCON_SPI_MAX_LEN sizeof(efx_oword_t)
+#define FALCON_SPI_MAX_LEN ((unsigned) sizeof(efx_oword_t))
 
 /* Wait for SPI command completion */
 static int falcon_spi_wait(struct efx_nic *efx)
 {
+	unsigned long timeout = jiffies + DIV_ROUND_UP(HZ, 10);
 	efx_oword_t reg;
-	int cmd_en, timer_active;
-	int count;
+	bool cmd_en, timer_active;
 
-	count = 0;
-	do {
+	for (;;) {
 		falcon_read(efx, &reg, EE_SPI_HCMD_REG_KER);
 		cmd_en = EFX_OWORD_FIELD(reg, EE_SPI_HCMD_CMD_EN);
 		timer_active = EFX_OWORD_FIELD(reg, EE_WR_TIMER_ACTIVE);
 		if (!cmd_en && !timer_active)
 			return 0;
-		udelay(10);
-	} while (++count < 10000); /* wait upto 100msec */
-	EFX_ERR(efx, "timed out waiting for SPI\n");
-	return -ETIMEDOUT;
+		if (time_after_eq(jiffies, timeout)) {
+			EFX_ERR(efx, "timed out waiting for SPI\n");
+			return -ETIMEDOUT;
+		}
+		cpu_relax();
+	}
 }
 
-static int
-falcon_spi_read(struct efx_nic *efx, int device_id, unsigned int command,
-		unsigned int address, unsigned int addr_len,
-		void *data, unsigned int len)
+static int falcon_spi_cmd(const struct efx_spi_device *spi,
+			  unsigned int command, int address,
+			  const void *in, void *out, unsigned int len)
 {
+	struct efx_nic *efx = spi->efx;
+	bool addressed = (address >= 0);
+	bool reading = (out != NULL);
 	efx_oword_t reg;
 	int rc;
 
-	BUG_ON(len > FALCON_SPI_MAX_LEN);
+	/* Input validation */
+	if (len > FALCON_SPI_MAX_LEN)
+		return -EINVAL;
 
 	/* Check SPI not currently being accessed */
 	rc = falcon_spi_wait(efx);
 	if (rc)
 		return rc;
 
-	/* Program address register */
-	EFX_POPULATE_OWORD_1(reg, EE_SPI_HADR_ADR, address);
-	falcon_write(efx, &reg, EE_SPI_HADR_REG_KER);
+	/* Program address register, if we have an address */
+	if (addressed) {
+		EFX_POPULATE_OWORD_1(reg, EE_SPI_HADR_ADR, address);
+		falcon_write(efx, &reg, EE_SPI_HADR_REG_KER);
+	}
 
-	/* Issue read command */
+	/* Program data register, if we have data */
+	if (in != NULL) {
+		memcpy(&reg, in, len);
+		falcon_write(efx, &reg, EE_SPI_HDATA_REG_KER);
+	}
+
+	/* Issue read/write command */
 	EFX_POPULATE_OWORD_7(reg,
 			     EE_SPI_HCMD_CMD_EN, 1,
-			     EE_SPI_HCMD_SF_SEL, device_id,
+			     EE_SPI_HCMD_SF_SEL, spi->device_id,
 			     EE_SPI_HCMD_DABCNT, len,
-			     EE_SPI_HCMD_READ, EE_SPI_READ,
+			     EE_SPI_HCMD_READ, reading,
 			     EE_SPI_HCMD_DUBCNT, 0,
-			     EE_SPI_HCMD_ADBCNT, addr_len,
+			     EE_SPI_HCMD_ADBCNT,
+			     (addressed ? spi->addr_len : 0),
 			     EE_SPI_HCMD_ENC, command);
 	falcon_write(efx, &reg, EE_SPI_HCMD_REG_KER);
 
-	/* Wait for read to complete */
+	/* Wait for read/write to complete */
 	rc = falcon_spi_wait(efx);
 	if (rc)
 		return rc;
 
 	/* Read data */
-	falcon_read(efx, &reg, EE_SPI_HDATA_REG_KER);
-	memcpy(data, &reg, len);
+	if (out != NULL) {
+		falcon_read(efx, &reg, EE_SPI_HDATA_REG_KER);
+		memcpy(out, &reg, len);
+	}
+
 	return 0;
 }
 
+static unsigned int
+falcon_spi_write_limit(const struct efx_spi_device *spi, unsigned int start)
+{
+	return min(FALCON_SPI_MAX_LEN,
+		   (spi->block_size - (start & (spi->block_size - 1))));
+}
+
+static inline u8
+efx_spi_munge_command(const struct efx_spi_device *spi,
+		      const u8 command, const unsigned int address)
+{
+	return command | (((address >> 8) & spi->munge_address) << 3);
+}
+
+
+static int falcon_spi_fast_wait(const struct efx_spi_device *spi)
+{
+	u8 status;
+	int i, rc;
+
+	/* Wait up to 1000us for flash/EEPROM to finish a fast operation. */
+	for (i = 0; i < 50; i++) {
+		udelay(20);
+
+		rc = falcon_spi_cmd(spi, SPI_RDSR, -1, NULL,
+				    &status, sizeof(status));
+		if (rc)
+			return rc;
+		if (!(status & SPI_STATUS_NRDY))
+			return 0;
+	}
+	EFX_ERR(spi->efx,
+		"timed out waiting for device %d last status=0x%02x\n",
+		spi->device_id, status);
+	return -ETIMEDOUT;
+}
+
+int falcon_spi_read(const struct efx_spi_device *spi, loff_t start,
+		    size_t len, size_t *retlen, u8 *buffer)
+{
+	unsigned int command, block_len, pos = 0;
+	int rc = 0;
+
+	while (pos < len) {
+		block_len = min((unsigned int)len - pos,
+				FALCON_SPI_MAX_LEN);
+
+		command = efx_spi_munge_command(spi, SPI_READ, start + pos);
+		rc = falcon_spi_cmd(spi, command, start + pos, NULL,
+				    buffer + pos, block_len);
+		if (rc)
+			break;
+		pos += block_len;
+
+		/* Avoid locking up the system */
+		cond_resched();
+		if (signal_pending(current)) {
+			rc = -EINTR;
+			break;
+		}
+	}
+
+	if (retlen)
+		*retlen = pos;
+	return rc;
+}
+
+int falcon_spi_write(const struct efx_spi_device *spi, loff_t start,
+		     size_t len, size_t *retlen, const u8 *buffer)
+{
+	u8 verify_buffer[FALCON_SPI_MAX_LEN];
+	unsigned int command, block_len, pos = 0;
+	int rc = 0;
+
+	while (pos < len) {
+		rc = falcon_spi_cmd(spi, SPI_WREN, -1, NULL, NULL, 0);
+		if (rc)
+			break;
+
+		block_len = min((unsigned int)len - pos,
+				falcon_spi_write_limit(spi, start + pos));
+		command = efx_spi_munge_command(spi, SPI_WRITE, start + pos);
+		rc = falcon_spi_cmd(spi, command, start + pos,
+				    buffer + pos, NULL, block_len);
+		if (rc)
+			break;
+
+		rc = falcon_spi_fast_wait(spi);
+		if (rc)
+			break;
+
+		command = efx_spi_munge_command(spi, SPI_READ, start + pos);
+		rc = falcon_spi_cmd(spi, command, start + pos,
+				    NULL, verify_buffer, block_len);
+		if (memcmp(verify_buffer, buffer + pos, block_len)) {
+			rc = -EIO;
+			break;
+		}
+
+		pos += block_len;
+
+		/* Avoid locking up the system */
+		cond_resched();
+		if (signal_pending(current)) {
+			rc = -EINTR;
+			break;
+		}
+	}
+
+	if (retlen)
+		*retlen = pos;
+	return rc;
+}
+
 /**************************************************************************
  *
  * MAC wrapper
@@ -1812,7 +1879,7 @@
 {
 	efx_oword_t reg;
 	int link_speed;
-	unsigned int tx_fc;
+	bool tx_fc;
 
 	if (efx->link_options & GM_LPA_10000)
 		link_speed = 0x3;
@@ -1847,7 +1914,7 @@
 	/* Transmission of pause frames when RX crosses the threshold is
 	 * covered by RX_XOFF_MAC_EN and XM_TX_CFG_REG:XM_FCNTL.
 	 * Action on receipt of pause frames is controller by XM_DIS_FCNTL */
-	tx_fc = (efx->flow_control & EFX_FC_TX) ? 1 : 0;
+	tx_fc = !!(efx->flow_control & EFX_FC_TX);
 	falcon_read(efx, &reg, RX_CFG_REG_KER);
 	EFX_SET_OWORD_FIELD_VER(efx, reg, RX_XOFF_MAC_EN, tx_fc);
 
@@ -1887,8 +1954,10 @@
 
 	/* Wait for transfer to complete */
 	for (i = 0; i < 400; i++) {
-		if (*(volatile u32 *)dma_done == FALCON_STATS_DONE)
+		if (*(volatile u32 *)dma_done == FALCON_STATS_DONE) {
+			rmb(); /* Ensure the stats are valid. */
 			return 0;
+		}
 		udelay(10);
 	}
 
@@ -1951,7 +2020,7 @@
 static void falcon_mdio_write(struct net_device *net_dev, int phy_id,
 			      int addr, int value)
 {
-	struct efx_nic *efx = net_dev->priv;
+	struct efx_nic *efx = netdev_priv(net_dev);
 	unsigned int phy_id2 = phy_id & FALCON_PHY_ID_ID_MASK;
 	efx_oword_t reg;
 
@@ -2019,7 +2088,7 @@
  * could be read, -1 will be returned. */
 static int falcon_mdio_read(struct net_device *net_dev, int phy_id, int addr)
 {
-	struct efx_nic *efx = net_dev->priv;
+	struct efx_nic *efx = netdev_priv(net_dev);
 	unsigned int phy_addr = phy_id & FALCON_PHY_ID_ID_MASK;
 	efx_oword_t reg;
 	int value = -1;
@@ -2120,7 +2189,7 @@
 		return rc;
 
 	/* Set up GMII structure for PHY */
-	efx->mii.supports_gmii = 1;
+	efx->mii.supports_gmii = true;
 	falcon_init_mdio(&efx->mii);
 
 	/* Hardware flow ctrl. FalconA RX FIFO too small for pause generation */
@@ -2168,6 +2237,170 @@
 	falcon_write(efx, &mc_hash->oword[1], MAC_MCAST_HASH_REG1_KER);
 }
 
+
+/**************************************************************************
+ *
+ * Falcon test code
+ *
+ **************************************************************************/
+
+int falcon_read_nvram(struct efx_nic *efx, struct falcon_nvconfig *nvconfig_out)
+{
+	struct falcon_nvconfig *nvconfig;
+	struct efx_spi_device *spi;
+	void *region;
+	int rc, magic_num, struct_ver;
+	__le16 *word, *limit;
+	u32 csum;
+
+	region = kmalloc(NVCONFIG_END, GFP_KERNEL);
+	if (!region)
+		return -ENOMEM;
+	nvconfig = region + NVCONFIG_OFFSET;
+
+	spi = efx->spi_flash ? efx->spi_flash : efx->spi_eeprom;
+	rc = falcon_spi_read(spi, 0, NVCONFIG_END, NULL, region);
+	if (rc) {
+		EFX_ERR(efx, "Failed to read %s\n",
+			efx->spi_flash ? "flash" : "EEPROM");
+		rc = -EIO;
+		goto out;
+	}
+
+	magic_num = le16_to_cpu(nvconfig->board_magic_num);
+	struct_ver = le16_to_cpu(nvconfig->board_struct_ver);
+
+	rc = -EINVAL;
+	if (magic_num != NVCONFIG_BOARD_MAGIC_NUM) {
+		EFX_ERR(efx, "NVRAM bad magic 0x%x\n", magic_num);
+		goto out;
+	}
+	if (struct_ver < 2) {
+		EFX_ERR(efx, "NVRAM has ancient version 0x%x\n", struct_ver);
+		goto out;
+	} else if (struct_ver < 4) {
+		word = &nvconfig->board_magic_num;
+		limit = (__le16 *) (nvconfig + 1);
+	} else {
+		word = region;
+		limit = region + NVCONFIG_END;
+	}
+	for (csum = 0; word < limit; ++word)
+		csum += le16_to_cpu(*word);
+
+	if (~csum & 0xffff) {
+		EFX_ERR(efx, "NVRAM has incorrect checksum\n");
+		goto out;
+	}
+
+	rc = 0;
+	if (nvconfig_out)
+		memcpy(nvconfig_out, nvconfig, sizeof(*nvconfig));
+
+ out:
+	kfree(region);
+	return rc;
+}
+
+/* Registers tested in the falcon register test */
+static struct {
+	unsigned address;
+	efx_oword_t mask;
+} efx_test_registers[] = {
+	{ ADR_REGION_REG_KER,
+	  EFX_OWORD32(0x0001FFFF, 0x0001FFFF, 0x0001FFFF, 0x0001FFFF) },
+	{ RX_CFG_REG_KER,
+	  EFX_OWORD32(0xFFFFFFFE, 0x00017FFF, 0x00000000, 0x00000000) },
+	{ TX_CFG_REG_KER,
+	  EFX_OWORD32(0x7FFF0037, 0x00000000, 0x00000000, 0x00000000) },
+	{ TX_CFG2_REG_KER,
+	  EFX_OWORD32(0xFFFEFE80, 0x1FFFFFFF, 0x020000FE, 0x007FFFFF) },
+	{ MAC0_CTRL_REG_KER,
+	  EFX_OWORD32(0xFFFF0000, 0x00000000, 0x00000000, 0x00000000) },
+	{ SRM_TX_DC_CFG_REG_KER,
+	  EFX_OWORD32(0x001FFFFF, 0x00000000, 0x00000000, 0x00000000) },
+	{ RX_DC_CFG_REG_KER,
+	  EFX_OWORD32(0x0000000F, 0x00000000, 0x00000000, 0x00000000) },
+	{ RX_DC_PF_WM_REG_KER,
+	  EFX_OWORD32(0x000003FF, 0x00000000, 0x00000000, 0x00000000) },
+	{ DP_CTRL_REG,
+	  EFX_OWORD32(0x00000FFF, 0x00000000, 0x00000000, 0x00000000) },
+	{ XM_GLB_CFG_REG,
+	  EFX_OWORD32(0x00000C68, 0x00000000, 0x00000000, 0x00000000) },
+	{ XM_TX_CFG_REG,
+	  EFX_OWORD32(0x00080164, 0x00000000, 0x00000000, 0x00000000) },
+	{ XM_RX_CFG_REG,
+	  EFX_OWORD32(0x07100A0C, 0x00000000, 0x00000000, 0x00000000) },
+	{ XM_RX_PARAM_REG,
+	  EFX_OWORD32(0x00001FF8, 0x00000000, 0x00000000, 0x00000000) },
+	{ XM_FC_REG,
+	  EFX_OWORD32(0xFFFF0001, 0x00000000, 0x00000000, 0x00000000) },
+	{ XM_ADR_LO_REG,
+	  EFX_OWORD32(0xFFFFFFFF, 0x00000000, 0x00000000, 0x00000000) },
+	{ XX_SD_CTL_REG,
+	  EFX_OWORD32(0x0003FF0F, 0x00000000, 0x00000000, 0x00000000) },
+};
+
+static bool efx_masked_compare_oword(const efx_oword_t *a, const efx_oword_t *b,
+				     const efx_oword_t *mask)
+{
+	return ((a->u64[0] ^ b->u64[0]) & mask->u64[0]) ||
+		((a->u64[1] ^ b->u64[1]) & mask->u64[1]);
+}
+
+int falcon_test_registers(struct efx_nic *efx)
+{
+	unsigned address = 0, i, j;
+	efx_oword_t mask, imask, original, reg, buf;
+
+	/* Falcon should be in loopback to isolate the XMAC from the PHY */
+	WARN_ON(!LOOPBACK_INTERNAL(efx));
+
+	for (i = 0; i < ARRAY_SIZE(efx_test_registers); ++i) {
+		address = efx_test_registers[i].address;
+		mask = imask = efx_test_registers[i].mask;
+		EFX_INVERT_OWORD(imask);
+
+		falcon_read(efx, &original, address);
+
+		/* bit sweep on and off */
+		for (j = 0; j < 128; j++) {
+			if (!EFX_EXTRACT_OWORD32(mask, j, j))
+				continue;
+
+			/* Test this testable bit can be set in isolation */
+			EFX_AND_OWORD(reg, original, mask);
+			EFX_SET_OWORD32(reg, j, j, 1);
+
+			falcon_write(efx, &reg, address);
+			falcon_read(efx, &buf, address);
+
+			if (efx_masked_compare_oword(&reg, &buf, &mask))
+				goto fail;
+
+			/* Test this testable bit can be cleared in isolation */
+			EFX_OR_OWORD(reg, original, mask);
+			EFX_SET_OWORD32(reg, j, j, 0);
+
+			falcon_write(efx, &reg, address);
+			falcon_read(efx, &buf, address);
+
+			if (efx_masked_compare_oword(&reg, &buf, &mask))
+				goto fail;
+		}
+
+		falcon_write(efx, &original, address);
+	}
+
+	return 0;
+
+fail:
+	EFX_ERR(efx, "wrote "EFX_OWORD_FMT" read "EFX_OWORD_FMT
+		" at address 0x%x mask "EFX_OWORD_FMT"\n", EFX_OWORD_VAL(reg),
+		EFX_OWORD_VAL(buf), address, EFX_OWORD_VAL(mask));
+	return -EIO;
+}
+
 /**************************************************************************
  *
  * Device reset
@@ -2305,68 +2538,103 @@
 	return -ETIMEDOUT;
 }
 
+static int falcon_spi_device_init(struct efx_nic *efx,
+				  struct efx_spi_device **spi_device_ret,
+				  unsigned int device_id, u32 device_type)
+{
+	struct efx_spi_device *spi_device;
+
+	if (device_type != 0) {
+		spi_device = kmalloc(sizeof(*spi_device), GFP_KERNEL);
+		if (!spi_device)
+			return -ENOMEM;
+		spi_device->device_id = device_id;
+		spi_device->size =
+			1 << SPI_DEV_TYPE_FIELD(device_type, SPI_DEV_TYPE_SIZE);
+		spi_device->addr_len =
+			SPI_DEV_TYPE_FIELD(device_type, SPI_DEV_TYPE_ADDR_LEN);
+		spi_device->munge_address = (spi_device->size == 1 << 9 &&
+					     spi_device->addr_len == 1);
+		spi_device->block_size =
+			1 << SPI_DEV_TYPE_FIELD(device_type,
+						SPI_DEV_TYPE_BLOCK_SIZE);
+
+		spi_device->efx = efx;
+	} else {
+		spi_device = NULL;
+	}
+
+	kfree(*spi_device_ret);
+	*spi_device_ret = spi_device;
+	return 0;
+}
+
+
+static void falcon_remove_spi_devices(struct efx_nic *efx)
+{
+	kfree(efx->spi_eeprom);
+	efx->spi_eeprom = NULL;
+	kfree(efx->spi_flash);
+	efx->spi_flash = NULL;
+}
+
 /* Extract non-volatile configuration */
 static int falcon_probe_nvconfig(struct efx_nic *efx)
 {
 	struct falcon_nvconfig *nvconfig;
-	efx_oword_t nic_stat;
-	int device_id;
-	unsigned addr_len;
-	size_t offset, len;
-	int magic_num, struct_ver, board_rev;
+	int board_rev;
 	int rc;
 
-	/* Find the boot device. */
-	falcon_read(efx, &nic_stat, NIC_STAT_REG);
-	if (EFX_OWORD_FIELD(nic_stat, SF_PRST)) {
-		device_id = EE_SPI_FLASH;
-		addr_len = 3;
-	} else if (EFX_OWORD_FIELD(nic_stat, EE_PRST)) {
-		device_id = EE_SPI_EEPROM;
-		addr_len = 2;
-	} else {
-		return -ENODEV;
-	}
-
 	nvconfig = kmalloc(sizeof(*nvconfig), GFP_KERNEL);
+	if (!nvconfig)
+		return -ENOMEM;
 
-	/* Read the whole configuration structure into memory. */
-	for (offset = 0; offset < sizeof(*nvconfig); offset += len) {
-		len = min(sizeof(*nvconfig) - offset,
-			  (size_t) FALCON_SPI_MAX_LEN);
-		rc = falcon_spi_read(efx, device_id, SPI_READ,
-				     NVCONFIG_BASE + offset, addr_len,
-				     (char *)nvconfig + offset, len);
-		if (rc)
-			goto out;
+	rc = falcon_read_nvram(efx, nvconfig);
+	if (rc == -EINVAL) {
+		EFX_ERR(efx, "NVRAM is invalid therefore using defaults\n");
+		efx->phy_type = PHY_TYPE_NONE;
+		efx->mii.phy_id = PHY_ADDR_INVALID;
+		board_rev = 0;
+		rc = 0;
+	} else if (rc) {
+		goto fail1;
+	} else {
+		struct falcon_nvconfig_board_v2 *v2 = &nvconfig->board_v2;
+		struct falcon_nvconfig_board_v3 *v3 = &nvconfig->board_v3;
+
+		efx->phy_type = v2->port0_phy_type;
+		efx->mii.phy_id = v2->port0_phy_addr;
+		board_rev = le16_to_cpu(v2->board_revision);
+
+		if (le16_to_cpu(nvconfig->board_struct_ver) >= 3) {
+			__le32 fl = v3->spi_device_type[EE_SPI_FLASH];
+			__le32 ee = v3->spi_device_type[EE_SPI_EEPROM];
+			rc = falcon_spi_device_init(efx, &efx->spi_flash,
+						    EE_SPI_FLASH,
+						    le32_to_cpu(fl));
+			if (rc)
+				goto fail2;
+			rc = falcon_spi_device_init(efx, &efx->spi_eeprom,
+						    EE_SPI_EEPROM,
+						    le32_to_cpu(ee));
+			if (rc)
+				goto fail2;
+		}
 	}
 
 	/* Read the MAC addresses */
 	memcpy(efx->mac_address, nvconfig->mac_address[0], ETH_ALEN);
 
-	/* Read the board configuration. */
-	magic_num = le16_to_cpu(nvconfig->board_magic_num);
-	struct_ver = le16_to_cpu(nvconfig->board_struct_ver);
-
-	if (magic_num != NVCONFIG_BOARD_MAGIC_NUM || struct_ver < 2) {
-		EFX_ERR(efx, "Non volatile memory bad magic=%x ver=%x "
-			"therefore using defaults\n", magic_num, struct_ver);
-		efx->phy_type = PHY_TYPE_NONE;
-		efx->mii.phy_id = PHY_ADDR_INVALID;
-		board_rev = 0;
-	} else {
-		struct falcon_nvconfig_board_v2 *v2 = &nvconfig->board_v2;
-
-		efx->phy_type = v2->port0_phy_type;
-		efx->mii.phy_id = v2->port0_phy_addr;
-		board_rev = le16_to_cpu(v2->board_revision);
-	}
-
 	EFX_LOG(efx, "PHY is %d phy_id %d\n", efx->phy_type, efx->mii.phy_id);
 
 	efx_set_board_info(efx, board_rev);
 
- out:
+	kfree(nvconfig);
+	return 0;
+
+ fail2:
+	falcon_remove_spi_devices(efx);
+ fail1:
 	kfree(nvconfig);
 	return rc;
 }
@@ -2417,6 +2685,86 @@
 	return 0;
 }
 
+/* Probe all SPI devices on the NIC */
+static void falcon_probe_spi_devices(struct efx_nic *efx)
+{
+	efx_oword_t nic_stat, gpio_ctl, ee_vpd_cfg;
+	bool has_flash, has_eeprom, boot_is_external;
+
+	falcon_read(efx, &gpio_ctl, GPIO_CTL_REG_KER);
+	falcon_read(efx, &nic_stat, NIC_STAT_REG);
+	falcon_read(efx, &ee_vpd_cfg, EE_VPD_CFG_REG_KER);
+
+	has_flash = EFX_OWORD_FIELD(nic_stat, SF_PRST);
+	has_eeprom = EFX_OWORD_FIELD(nic_stat, EE_PRST);
+	boot_is_external = EFX_OWORD_FIELD(gpio_ctl, BOOTED_USING_NVDEVICE);
+
+	if (has_flash) {
+		/* Default flash SPI device: Atmel AT25F1024
+		 * 128 KB, 24-bit address, 32 KB erase block,
+		 * 256 B write block
+		 */
+		u32 flash_device_type =
+			(17 << SPI_DEV_TYPE_SIZE_LBN)
+			| (3 << SPI_DEV_TYPE_ADDR_LEN_LBN)
+			| (0x52 << SPI_DEV_TYPE_ERASE_CMD_LBN)
+			| (15 << SPI_DEV_TYPE_ERASE_SIZE_LBN)
+			| (8 << SPI_DEV_TYPE_BLOCK_SIZE_LBN);
+
+		falcon_spi_device_init(efx, &efx->spi_flash,
+				       EE_SPI_FLASH, flash_device_type);
+
+		if (!boot_is_external) {
+			/* Disable VPD and set clock dividers to safe
+			 * values for initial programming.
+			 */
+			EFX_LOG(efx, "Booted from internal ASIC settings;"
+				" setting SPI config\n");
+			EFX_POPULATE_OWORD_3(ee_vpd_cfg, EE_VPD_EN, 0,
+					     /* 125 MHz / 7 ~= 20 MHz */
+					     EE_SF_CLOCK_DIV, 7,
+					     /* 125 MHz / 63 ~= 2 MHz */
+					     EE_EE_CLOCK_DIV, 63);
+			falcon_write(efx, &ee_vpd_cfg, EE_VPD_CFG_REG_KER);
+		}
+	}
+
+	if (has_eeprom) {
+		u32 eeprom_device_type;
+
+		/* If it has no flash, it must have a large EEPROM
+		 * for chip config; otherwise check whether 9-bit
+		 * addressing is used for VPD configuration
+		 */
+		if (has_flash &&
+		    (!boot_is_external ||
+		     EFX_OWORD_FIELD(ee_vpd_cfg, EE_VPD_EN_AD9_MODE))) {
+			/* Default SPI device: Atmel AT25040 or similar
+			 * 512 B, 9-bit address, 8 B write block
+			 */
+			eeprom_device_type =
+				(9 << SPI_DEV_TYPE_SIZE_LBN)
+				| (1 << SPI_DEV_TYPE_ADDR_LEN_LBN)
+				| (3 << SPI_DEV_TYPE_BLOCK_SIZE_LBN);
+		} else {
+			/* "Large" SPI device: Atmel AT25640 or similar
+			 * 8 KB, 16-bit address, 32 B write block
+			 */
+			eeprom_device_type =
+				(13 << SPI_DEV_TYPE_SIZE_LBN)
+				| (2 << SPI_DEV_TYPE_ADDR_LEN_LBN)
+				| (5 << SPI_DEV_TYPE_BLOCK_SIZE_LBN);
+		}
+
+		falcon_spi_device_init(efx, &efx->spi_eeprom,
+				       EE_SPI_EEPROM, eeprom_device_type);
+	}
+
+	EFX_LOG(efx, "flash is %s, EEPROM is %s\n",
+		(has_flash ? "present" : "absent"),
+		(has_eeprom ? "present" : "absent"));
+}
+
 int falcon_probe_nic(struct efx_nic *efx)
 {
 	struct falcon_nic_data *nic_data;
@@ -2424,6 +2772,8 @@
 
 	/* Allocate storage for hardware specific data */
 	nic_data = kzalloc(sizeof(*nic_data), GFP_KERNEL);
+	if (!nic_data)
+		return -ENOMEM;
 	efx->nic_data = nic_data;
 
 	/* Determine number of ports etc. */
@@ -2467,6 +2817,8 @@
 		(unsigned long long)efx->irq_status.dma_addr,
 		efx->irq_status.addr, virt_to_phys(efx->irq_status.addr));
 
+	falcon_probe_spi_devices(efx);
+
 	/* Read in the non-volatile configuration */
 	rc = falcon_probe_nvconfig(efx);
 	if (rc)
@@ -2486,6 +2838,7 @@
 	return 0;
 
  fail5:
+	falcon_remove_spi_devices(efx);
 	falcon_free_buffer(efx, &efx->irq_status);
  fail4:
  fail3:
@@ -2573,19 +2926,14 @@
 	EFX_INVERT_OWORD(temp);
 	falcon_write(efx, &temp, FATAL_INTR_REG_KER);
 
-	/* Set number of RSS queues for receive path. */
-	falcon_read(efx, &temp, RX_FILTER_CTL_REG);
-	if (falcon_rev(efx) >= FALCON_REV_B0)
-		EFX_SET_OWORD_FIELD(temp, NUM_KER, 0);
-	else
-		EFX_SET_OWORD_FIELD(temp, NUM_KER, efx->rss_queues - 1);
 	if (EFX_WORKAROUND_7244(efx)) {
+		falcon_read(efx, &temp, RX_FILTER_CTL_REG);
 		EFX_SET_OWORD_FIELD(temp, UDP_FULL_SRCH_LIMIT, 8);
 		EFX_SET_OWORD_FIELD(temp, UDP_WILD_SRCH_LIMIT, 8);
 		EFX_SET_OWORD_FIELD(temp, TCP_FULL_SRCH_LIMIT, 8);
 		EFX_SET_OWORD_FIELD(temp, TCP_WILD_SRCH_LIMIT, 8);
+		falcon_write(efx, &temp, RX_FILTER_CTL_REG);
 	}
-	falcon_write(efx, &temp, RX_FILTER_CTL_REG);
 
 	falcon_setup_rss_indir_table(efx);
 
@@ -2641,8 +2989,8 @@
 		  rx_xoff_thresh_bytes : efx->type->rx_xoff_thresh);
 	EFX_SET_OWORD_FIELD_VER(efx, temp, RX_XOFF_MAC_TH, thresh / 256);
 	/* RX control FIFO thresholds [32 entries] */
-	EFX_SET_OWORD_FIELD_VER(efx, temp, RX_XON_TX_TH, 25);
-	EFX_SET_OWORD_FIELD_VER(efx, temp, RX_XOFF_TX_TH, 20);
+	EFX_SET_OWORD_FIELD_VER(efx, temp, RX_XON_TX_TH, 20);
+	EFX_SET_OWORD_FIELD_VER(efx, temp, RX_XOFF_TX_TH, 25);
 	falcon_write(efx, &temp, RX_CFG_REG_KER);
 
 	/* Set destination of both TX and RX Flush events */
@@ -2662,6 +3010,7 @@
 	rc = i2c_del_adapter(&efx->i2c_adap);
 	BUG_ON(rc);
 
+	falcon_remove_spi_devices(efx);
 	falcon_free_buffer(efx, &efx->irq_status);
 
 	falcon_reset_hw(efx, RESET_TYPE_ALL);
diff --git a/drivers/net/sfc/falcon.h b/drivers/net/sfc/falcon.h
index 492f9bc..be025ba 100644
--- a/drivers/net/sfc/falcon.h
+++ b/drivers/net/sfc/falcon.h
@@ -40,24 +40,24 @@
 
 /* TX data path */
 extern int falcon_probe_tx(struct efx_tx_queue *tx_queue);
-extern int falcon_init_tx(struct efx_tx_queue *tx_queue);
+extern void falcon_init_tx(struct efx_tx_queue *tx_queue);
 extern void falcon_fini_tx(struct efx_tx_queue *tx_queue);
 extern void falcon_remove_tx(struct efx_tx_queue *tx_queue);
 extern void falcon_push_buffers(struct efx_tx_queue *tx_queue);
 
 /* RX data path */
 extern int falcon_probe_rx(struct efx_rx_queue *rx_queue);
-extern int falcon_init_rx(struct efx_rx_queue *rx_queue);
+extern void falcon_init_rx(struct efx_rx_queue *rx_queue);
 extern void falcon_fini_rx(struct efx_rx_queue *rx_queue);
 extern void falcon_remove_rx(struct efx_rx_queue *rx_queue);
 extern void falcon_notify_rx_desc(struct efx_rx_queue *rx_queue);
 
 /* Event data path */
 extern int falcon_probe_eventq(struct efx_channel *channel);
-extern int falcon_init_eventq(struct efx_channel *channel);
+extern void falcon_init_eventq(struct efx_channel *channel);
 extern void falcon_fini_eventq(struct efx_channel *channel);
 extern void falcon_remove_eventq(struct efx_channel *channel);
-extern int falcon_process_eventq(struct efx_channel *channel, int *rx_quota);
+extern int falcon_process_eventq(struct efx_channel *channel, int rx_quota);
 extern void falcon_eventq_read_ack(struct efx_channel *channel);
 
 /* Ports */
@@ -65,7 +65,7 @@
 extern void falcon_remove_port(struct efx_nic *efx);
 
 /* MAC/PHY */
-extern int falcon_xaui_link_ok(struct efx_nic *efx);
+extern bool falcon_xaui_link_ok(struct efx_nic *efx);
 extern int falcon_dma_stats(struct efx_nic *efx,
 			    unsigned int done_offset);
 extern void falcon_drain_tx_fifo(struct efx_nic *efx);
@@ -86,6 +86,7 @@
 extern int falcon_probe_nic(struct efx_nic *efx);
 extern int falcon_probe_resources(struct efx_nic *efx);
 extern int falcon_init_nic(struct efx_nic *efx);
+extern int falcon_flush_queues(struct efx_nic *efx);
 extern int falcon_reset_hw(struct efx_nic *efx, enum reset_type method);
 extern void falcon_remove_resources(struct efx_nic *efx);
 extern void falcon_remove_nic(struct efx_nic *efx);
@@ -93,6 +94,12 @@
 extern void falcon_set_multicast_hash(struct efx_nic *efx);
 extern int falcon_reset_xaui(struct efx_nic *efx);
 
+/* Tests */
+struct falcon_nvconfig;
+extern int falcon_read_nvram(struct efx_nic *efx,
+			     struct falcon_nvconfig *nvconfig);
+extern int falcon_test_registers(struct efx_nic *efx);
+
 /**************************************************************************
  *
  * Falcon MAC stats
diff --git a/drivers/net/sfc/falcon_hwdefs.h b/drivers/net/sfc/falcon_hwdefs.h
index 6d00311..5d584b0 100644
--- a/drivers/net/sfc/falcon_hwdefs.h
+++ b/drivers/net/sfc/falcon_hwdefs.h
@@ -92,6 +92,17 @@
 /* SPI host data register */
 #define EE_SPI_HDATA_REG_KER 0x0120
 
+/* SPI/VPD config register */
+#define EE_VPD_CFG_REG_KER 0x0140
+#define EE_VPD_EN_LBN 0
+#define EE_VPD_EN_WIDTH 1
+#define EE_VPD_EN_AD9_MODE_LBN 1
+#define EE_VPD_EN_AD9_MODE_WIDTH 1
+#define EE_EE_CLOCK_DIV_LBN 112
+#define EE_EE_CLOCK_DIV_WIDTH 7
+#define EE_SF_CLOCK_DIV_LBN 120
+#define EE_SF_CLOCK_DIV_WIDTH 7
+
 /* PCIE CORE ACCESS REG */
 #define PCIE_CORE_ADDR_PCIE_DEVICE_CTRL_STAT 0x68
 #define PCIE_CORE_ADDR_PCIE_LINK_CTRL_STAT 0x70
@@ -106,7 +117,6 @@
 #define SF_PRST_WIDTH 1
 #define EE_PRST_LBN 8
 #define EE_PRST_WIDTH 1
-/* See pic_mode_t for decoding of this field */
 /* These bit definitions are extrapolated from the list of numerical
  * values for STRAP_PINS.
  */
@@ -115,6 +125,9 @@
 #define STRAP_PCIE_LBN 0
 #define STRAP_PCIE_WIDTH 1
 
+#define BOOTED_USING_NVDEVICE_LBN 3
+#define BOOTED_USING_NVDEVICE_WIDTH 1
+
 /* GPIO control register */
 #define GPIO_CTL_REG_KER 0x0210
 #define GPIO_OUTPUTS_LBN   (16)
@@ -479,18 +492,8 @@
 #define MAC_MCAST_HASH_REG0_KER 0xca0
 #define MAC_MCAST_HASH_REG1_KER 0xcb0
 
-/* GMAC registers */
-#define FALCON_GMAC_REGBANK 0xe00
-#define FALCON_GMAC_REGBANK_SIZE 0x200
-#define FALCON_GMAC_REG_SIZE 0x10
-
-/* XMAC registers */
-#define FALCON_XMAC_REGBANK 0x1200
-#define FALCON_XMAC_REGBANK_SIZE 0x200
-#define FALCON_XMAC_REG_SIZE 0x10
-
 /* XGMAC address register low */
-#define XM_ADR_LO_REG_MAC 0x00
+#define XM_ADR_LO_REG 0x1200
 #define XM_ADR_3_LBN 24
 #define XM_ADR_3_WIDTH 8
 #define XM_ADR_2_LBN 16
@@ -501,14 +504,14 @@
 #define XM_ADR_0_WIDTH 8
 
 /* XGMAC address register high */
-#define XM_ADR_HI_REG_MAC 0x01
+#define XM_ADR_HI_REG 0x1210
 #define XM_ADR_5_LBN 8
 #define XM_ADR_5_WIDTH 8
 #define XM_ADR_4_LBN 0
 #define XM_ADR_4_WIDTH 8
 
 /* XGMAC global configuration */
-#define XM_GLB_CFG_REG_MAC 0x02
+#define XM_GLB_CFG_REG 0x1220
 #define XM_RX_STAT_EN_LBN 11
 #define XM_RX_STAT_EN_WIDTH 1
 #define XM_TX_STAT_EN_LBN 10
@@ -521,7 +524,7 @@
 #define XM_CORE_RST_WIDTH 1
 
 /* XGMAC transmit configuration */
-#define XM_TX_CFG_REG_MAC 0x03
+#define XM_TX_CFG_REG 0x1230
 #define XM_IPG_LBN 16
 #define XM_IPG_WIDTH 4
 #define XM_FCNTL_LBN 10
@@ -536,7 +539,7 @@
 #define XM_TXEN_WIDTH 1
 
 /* XGMAC receive configuration */
-#define XM_RX_CFG_REG_MAC 0x04
+#define XM_RX_CFG_REG 0x1240
 #define XM_PASS_CRC_ERR_LBN 25
 #define XM_PASS_CRC_ERR_WIDTH 1
 #define XM_ACPT_ALL_MCAST_LBN 11
@@ -549,7 +552,7 @@
 #define XM_RXEN_WIDTH 1
 
 /* XGMAC management interrupt mask register */
-#define XM_MGT_INT_MSK_REG_MAC_B0 0x5
+#define XM_MGT_INT_MSK_REG_B0 0x1250
 #define XM_MSK_PRMBLE_ERR_LBN 2
 #define XM_MSK_PRMBLE_ERR_WIDTH 1
 #define XM_MSK_RMTFLT_LBN 1
@@ -558,29 +561,29 @@
 #define XM_MSK_LCLFLT_WIDTH 1
 
 /* XGMAC flow control register */
-#define XM_FC_REG_MAC 0x7
+#define XM_FC_REG 0x1270
 #define XM_PAUSE_TIME_LBN 16
 #define XM_PAUSE_TIME_WIDTH 16
 #define XM_DIS_FCNTL_LBN 0
 #define XM_DIS_FCNTL_WIDTH 1
 
 /* XGMAC pause time count register */
-#define XM_PAUSE_TIME_REG_MAC 0x9
+#define XM_PAUSE_TIME_REG 0x1290
 
 /* XGMAC transmit parameter register */
-#define XM_TX_PARAM_REG_MAC 0x0d
+#define XM_TX_PARAM_REG 0x012d0
 #define XM_TX_JUMBO_MODE_LBN 31
 #define XM_TX_JUMBO_MODE_WIDTH 1
 #define XM_MAX_TX_FRM_SIZE_LBN 16
 #define XM_MAX_TX_FRM_SIZE_WIDTH 14
 
 /* XGMAC receive parameter register */
-#define XM_RX_PARAM_REG_MAC 0x0e
+#define XM_RX_PARAM_REG 0x12e0
 #define XM_MAX_RX_FRM_SIZE_LBN 0
 #define XM_MAX_RX_FRM_SIZE_WIDTH 14
 
 /* XGMAC management interrupt status register */
-#define XM_MGT_INT_REG_MAC_B0 0x0f
+#define XM_MGT_INT_REG_B0 0x12f0
 #define XM_PRMBLE_ERR 2
 #define XM_PRMBLE_WIDTH 1
 #define XM_RMTFLT_LBN 1
@@ -589,7 +592,7 @@
 #define XM_LCLFLT_WIDTH 1
 
 /* XGXS/XAUI powerdown/reset register */
-#define XX_PWR_RST_REG_MAC 0x10
+#define XX_PWR_RST_REG 0x1300
 
 #define XX_PWRDND_EN_LBN 15
 #define XX_PWRDND_EN_WIDTH 1
@@ -619,7 +622,7 @@
 #define XX_RST_XX_EN_WIDTH 1
 
 /* XGXS/XAUI powerdown/reset control register */
-#define XX_SD_CTL_REG_MAC 0x11
+#define XX_SD_CTL_REG 0x1310
 #define XX_HIDRVD_LBN 15
 #define XX_HIDRVD_WIDTH 1
 #define XX_LODRVD_LBN 14
@@ -645,7 +648,7 @@
 #define XX_LPBKA_LBN 0
 #define XX_LPBKA_WIDTH 1
 
-#define XX_TXDRV_CTL_REG_MAC 0x12
+#define XX_TXDRV_CTL_REG 0x1320
 #define XX_DEQD_LBN 28
 #define XX_DEQD_WIDTH 4
 #define XX_DEQC_LBN 24
@@ -664,7 +667,7 @@
 #define XX_DTXA_WIDTH 4
 
 /* XAUI XGXS core status register */
-#define XX_CORE_STAT_REG_MAC 0x16
+#define XX_CORE_STAT_REG 0x1360
 #define XX_FORCE_SIG_LBN 24
 #define XX_FORCE_SIG_WIDTH 8
 #define XX_FORCE_SIG_DECODE_FORCED 0xff
@@ -1127,7 +1130,28 @@
 	__le16 board_revision;
 } __packed;
 
-#define NVCONFIG_BASE 0x300
+/* Board configuration v3 extra information */
+struct falcon_nvconfig_board_v3 {
+	__le32 spi_device_type[2];
+} __packed;
+
+/* Bit numbers for spi_device_type */
+#define SPI_DEV_TYPE_SIZE_LBN 0
+#define SPI_DEV_TYPE_SIZE_WIDTH 5
+#define SPI_DEV_TYPE_ADDR_LEN_LBN 6
+#define SPI_DEV_TYPE_ADDR_LEN_WIDTH 2
+#define SPI_DEV_TYPE_ERASE_CMD_LBN 8
+#define SPI_DEV_TYPE_ERASE_CMD_WIDTH 8
+#define SPI_DEV_TYPE_ERASE_SIZE_LBN 16
+#define SPI_DEV_TYPE_ERASE_SIZE_WIDTH 5
+#define SPI_DEV_TYPE_BLOCK_SIZE_LBN 24
+#define SPI_DEV_TYPE_BLOCK_SIZE_WIDTH 5
+#define SPI_DEV_TYPE_FIELD(type, field)					\
+	(((type) >> EFX_LOW_BIT(field)) & EFX_MASK32(EFX_WIDTH(field)))
+
+#define NVCONFIG_OFFSET 0x300
+#define NVCONFIG_END 0x400
+
 #define NVCONFIG_BOARD_MAGIC_NUM 0xFA1C
 struct falcon_nvconfig {
 	efx_oword_t ee_vpd_cfg_reg;			/* 0x300 */
@@ -1144,6 +1168,8 @@
 	__le16 board_struct_ver;
 	__le16 board_checksum;
 	struct falcon_nvconfig_board_v2 board_v2;
+	efx_oword_t ee_base_page_reg;			/* 0x3B0 */
+	struct falcon_nvconfig_board_v3 board_v3;
 } __packed;
 
 #endif /* EFX_FALCON_HWDEFS_H */
diff --git a/drivers/net/sfc/falcon_io.h b/drivers/net/sfc/falcon_io.h
index 6670cdf..c16da31 100644
--- a/drivers/net/sfc/falcon_io.h
+++ b/drivers/net/sfc/falcon_io.h
@@ -13,7 +13,6 @@
 
 #include <linux/io.h>
 #include <linux/spinlock.h>
-#include "net_driver.h"
 
 /**************************************************************************
  *
diff --git a/drivers/net/sfc/falcon_xmac.c b/drivers/net/sfc/falcon_xmac.c
index 55c0d97..d401231 100644
--- a/drivers/net/sfc/falcon_xmac.c
+++ b/drivers/net/sfc/falcon_xmac.c
@@ -23,56 +23,24 @@
 
 /**************************************************************************
  *
- * MAC register access
- *
- **************************************************************************/
-
-/* Offset of an XMAC register within Falcon */
-#define FALCON_XMAC_REG(mac_reg)					\
-	(FALCON_XMAC_REGBANK + ((mac_reg) * FALCON_XMAC_REG_SIZE))
-
-void falcon_xmac_writel(struct efx_nic *efx,
-			 efx_dword_t *value, unsigned int mac_reg)
-{
-	efx_oword_t temp;
-
-	EFX_POPULATE_OWORD_1(temp, MAC_DATA, EFX_DWORD_FIELD(*value, MAC_DATA));
-	falcon_write(efx, &temp, FALCON_XMAC_REG(mac_reg));
-}
-
-void falcon_xmac_readl(struct efx_nic *efx,
-		       efx_dword_t *value, unsigned int mac_reg)
-{
-	efx_oword_t temp;
-
-	falcon_read(efx, &temp, FALCON_XMAC_REG(mac_reg));
-	EFX_POPULATE_DWORD_1(*value, MAC_DATA, EFX_OWORD_FIELD(temp, MAC_DATA));
-}
-
-/**************************************************************************
- *
  * MAC operations
  *
  *************************************************************************/
 static int falcon_reset_xmac(struct efx_nic *efx)
 {
-	efx_dword_t reg;
+	efx_oword_t reg;
 	int count;
 
-	EFX_POPULATE_DWORD_1(reg, XM_CORE_RST, 1);
-	falcon_xmac_writel(efx, &reg, XM_GLB_CFG_REG_MAC);
+	EFX_POPULATE_OWORD_1(reg, XM_CORE_RST, 1);
+	falcon_write(efx, &reg, XM_GLB_CFG_REG);
 
 	for (count = 0; count < 10000; count++) {	/* wait upto 100ms */
-		falcon_xmac_readl(efx, &reg, XM_GLB_CFG_REG_MAC);
-		if (EFX_DWORD_FIELD(reg, XM_CORE_RST) == 0)
+		falcon_read(efx, &reg, XM_GLB_CFG_REG);
+		if (EFX_OWORD_FIELD(reg, XM_CORE_RST) == 0)
 			return 0;
 		udelay(10);
 	}
 
-	/* This often fails when DSP is disabled, ignore it */
-	if (sfe4001_phy_flash_cfg != 0)
-		return 0;
-
 	EFX_ERR(efx, "timed out waiting for XMAC core reset\n");
 	return -ETIMEDOUT;
 }
@@ -80,25 +48,25 @@
 /* Configure the XAUI driver that is an output from Falcon */
 static void falcon_setup_xaui(struct efx_nic *efx)
 {
-	efx_dword_t sdctl, txdrv;
+	efx_oword_t sdctl, txdrv;
 
 	/* Move the XAUI into low power, unless there is no PHY, in
 	 * which case the XAUI will have to drive a cable. */
 	if (efx->phy_type == PHY_TYPE_NONE)
 		return;
 
-	falcon_xmac_readl(efx, &sdctl, XX_SD_CTL_REG_MAC);
-	EFX_SET_DWORD_FIELD(sdctl, XX_HIDRVD, XX_SD_CTL_DRV_DEFAULT);
-	EFX_SET_DWORD_FIELD(sdctl, XX_LODRVD, XX_SD_CTL_DRV_DEFAULT);
-	EFX_SET_DWORD_FIELD(sdctl, XX_HIDRVC, XX_SD_CTL_DRV_DEFAULT);
-	EFX_SET_DWORD_FIELD(sdctl, XX_LODRVC, XX_SD_CTL_DRV_DEFAULT);
-	EFX_SET_DWORD_FIELD(sdctl, XX_HIDRVB, XX_SD_CTL_DRV_DEFAULT);
-	EFX_SET_DWORD_FIELD(sdctl, XX_LODRVB, XX_SD_CTL_DRV_DEFAULT);
-	EFX_SET_DWORD_FIELD(sdctl, XX_HIDRVA, XX_SD_CTL_DRV_DEFAULT);
-	EFX_SET_DWORD_FIELD(sdctl, XX_LODRVA, XX_SD_CTL_DRV_DEFAULT);
-	falcon_xmac_writel(efx, &sdctl, XX_SD_CTL_REG_MAC);
+	falcon_read(efx, &sdctl, XX_SD_CTL_REG);
+	EFX_SET_OWORD_FIELD(sdctl, XX_HIDRVD, XX_SD_CTL_DRV_DEFAULT);
+	EFX_SET_OWORD_FIELD(sdctl, XX_LODRVD, XX_SD_CTL_DRV_DEFAULT);
+	EFX_SET_OWORD_FIELD(sdctl, XX_HIDRVC, XX_SD_CTL_DRV_DEFAULT);
+	EFX_SET_OWORD_FIELD(sdctl, XX_LODRVC, XX_SD_CTL_DRV_DEFAULT);
+	EFX_SET_OWORD_FIELD(sdctl, XX_HIDRVB, XX_SD_CTL_DRV_DEFAULT);
+	EFX_SET_OWORD_FIELD(sdctl, XX_LODRVB, XX_SD_CTL_DRV_DEFAULT);
+	EFX_SET_OWORD_FIELD(sdctl, XX_HIDRVA, XX_SD_CTL_DRV_DEFAULT);
+	EFX_SET_OWORD_FIELD(sdctl, XX_LODRVA, XX_SD_CTL_DRV_DEFAULT);
+	falcon_write(efx, &sdctl, XX_SD_CTL_REG);
 
-	EFX_POPULATE_DWORD_8(txdrv,
+	EFX_POPULATE_OWORD_8(txdrv,
 			     XX_DEQD, XX_TXDRV_DEQ_DEFAULT,
 			     XX_DEQC, XX_TXDRV_DEQ_DEFAULT,
 			     XX_DEQB, XX_TXDRV_DEQ_DEFAULT,
@@ -107,93 +75,21 @@
 			     XX_DTXC, XX_TXDRV_DTX_DEFAULT,
 			     XX_DTXB, XX_TXDRV_DTX_DEFAULT,
 			     XX_DTXA, XX_TXDRV_DTX_DEFAULT);
-	falcon_xmac_writel(efx, &txdrv, XX_TXDRV_CTL_REG_MAC);
+	falcon_write(efx, &txdrv, XX_TXDRV_CTL_REG);
 }
 
-static void falcon_hold_xaui_in_rst(struct efx_nic *efx)
+int falcon_reset_xaui(struct efx_nic *efx)
 {
-	efx_dword_t reg;
-
-	EFX_ZERO_DWORD(reg);
-	EFX_SET_DWORD_FIELD(reg, XX_PWRDNA_EN, 1);
-	EFX_SET_DWORD_FIELD(reg, XX_PWRDNB_EN, 1);
-	EFX_SET_DWORD_FIELD(reg, XX_PWRDNC_EN, 1);
-	EFX_SET_DWORD_FIELD(reg, XX_PWRDND_EN, 1);
-	EFX_SET_DWORD_FIELD(reg, XX_RSTPLLAB_EN, 1);
-	EFX_SET_DWORD_FIELD(reg, XX_RSTPLLCD_EN, 1);
-	EFX_SET_DWORD_FIELD(reg, XX_RESETA_EN, 1);
-	EFX_SET_DWORD_FIELD(reg, XX_RESETB_EN, 1);
-	EFX_SET_DWORD_FIELD(reg, XX_RESETC_EN, 1);
-	EFX_SET_DWORD_FIELD(reg, XX_RESETD_EN, 1);
-	EFX_SET_DWORD_FIELD(reg, XX_RSTXGXSRX_EN, 1);
-	EFX_SET_DWORD_FIELD(reg, XX_RSTXGXSTX_EN, 1);
-	falcon_xmac_writel(efx, &reg, XX_PWR_RST_REG_MAC);
-	udelay(10);
-}
-
-static int _falcon_reset_xaui_a(struct efx_nic *efx)
-{
-	efx_dword_t reg;
-
-	falcon_hold_xaui_in_rst(efx);
-	falcon_xmac_readl(efx, &reg, XX_PWR_RST_REG_MAC);
-
-	/* Follow the RAMBUS XAUI data reset sequencing
-	 * Channels A and B first: power down, reset PLL, reset, clear
-	 */
-	EFX_SET_DWORD_FIELD(reg, XX_PWRDNA_EN, 0);
-	EFX_SET_DWORD_FIELD(reg, XX_PWRDNB_EN, 0);
-	falcon_xmac_writel(efx, &reg, XX_PWR_RST_REG_MAC);
-	udelay(10);
-
-	EFX_SET_DWORD_FIELD(reg, XX_RSTPLLAB_EN, 0);
-	falcon_xmac_writel(efx, &reg, XX_PWR_RST_REG_MAC);
-	udelay(10);
-
-	EFX_SET_DWORD_FIELD(reg, XX_RESETA_EN, 0);
-	EFX_SET_DWORD_FIELD(reg, XX_RESETB_EN, 0);
-	falcon_xmac_writel(efx, &reg, XX_PWR_RST_REG_MAC);
-	udelay(10);
-
-	/* Channels C and D: power down, reset PLL, reset, clear */
-	EFX_SET_DWORD_FIELD(reg, XX_PWRDNC_EN, 0);
-	EFX_SET_DWORD_FIELD(reg, XX_PWRDND_EN, 0);
-	falcon_xmac_writel(efx, &reg, XX_PWR_RST_REG_MAC);
-	udelay(10);
-
-	EFX_SET_DWORD_FIELD(reg, XX_RSTPLLCD_EN, 0);
-	falcon_xmac_writel(efx, &reg, XX_PWR_RST_REG_MAC);
-	udelay(10);
-
-	EFX_SET_DWORD_FIELD(reg, XX_RESETC_EN, 0);
-	EFX_SET_DWORD_FIELD(reg, XX_RESETD_EN, 0);
-	falcon_xmac_writel(efx, &reg, XX_PWR_RST_REG_MAC);
-	udelay(10);
-
-	/* Setup XAUI */
-	falcon_setup_xaui(efx);
-	udelay(10);
-
-	/* Take XGXS out of reset */
-	EFX_ZERO_DWORD(reg);
-	falcon_xmac_writel(efx, &reg, XX_PWR_RST_REG_MAC);
-	udelay(10);
-
-	return 0;
-}
-
-static int _falcon_reset_xaui_b(struct efx_nic *efx)
-{
-	efx_dword_t reg;
+	efx_oword_t reg;
 	int count;
 
 	EFX_POPULATE_DWORD_1(reg, XX_RST_XX_EN, 1);
-	falcon_xmac_writel(efx, &reg, XX_PWR_RST_REG_MAC);
+	falcon_write(efx, &reg, XX_PWR_RST_REG);
 
 	/* Give some time for the link to establish */
 	for (count = 0; count < 1000; count++) { /* wait upto 10ms */
-		falcon_xmac_readl(efx, &reg, XX_PWR_RST_REG_MAC);
-		if (EFX_DWORD_FIELD(reg, XX_RST_XX_EN) == 0) {
+		falcon_read(efx, &reg, XX_PWR_RST_REG);
+		if (EFX_OWORD_FIELD(reg, XX_RST_XX_EN) == 0) {
 			falcon_setup_xaui(efx);
 			return 0;
 		}
@@ -203,55 +99,41 @@
 	return -ETIMEDOUT;
 }
 
-int falcon_reset_xaui(struct efx_nic *efx)
+static bool falcon_xgmii_status(struct efx_nic *efx)
 {
-	int rc;
-
-	if (EFX_WORKAROUND_9388(efx)) {
-		falcon_hold_xaui_in_rst(efx);
-		efx->phy_op->reset_xaui(efx);
-		rc = _falcon_reset_xaui_a(efx);
-	} else {
-		rc = _falcon_reset_xaui_b(efx);
-	}
-	return rc;
-}
-
-static int falcon_xgmii_status(struct efx_nic *efx)
-{
-	efx_dword_t reg;
+	efx_oword_t reg;
 
 	if (falcon_rev(efx) < FALCON_REV_B0)
-		return 1;
+		return true;
 
 	/* The ISR latches, so clear it and re-read */
-	falcon_xmac_readl(efx, &reg, XM_MGT_INT_REG_MAC_B0);
-	falcon_xmac_readl(efx, &reg, XM_MGT_INT_REG_MAC_B0);
+	falcon_read(efx, &reg, XM_MGT_INT_REG_B0);
+	falcon_read(efx, &reg, XM_MGT_INT_REG_B0);
 
-	if (EFX_DWORD_FIELD(reg, XM_LCLFLT) ||
-	    EFX_DWORD_FIELD(reg, XM_RMTFLT)) {
+	if (EFX_OWORD_FIELD(reg, XM_LCLFLT) ||
+	    EFX_OWORD_FIELD(reg, XM_RMTFLT)) {
 		EFX_INFO(efx, "MGT_INT: "EFX_DWORD_FMT"\n", EFX_DWORD_VAL(reg));
-		return 0;
+		return false;
 	}
 
-	return 1;
+	return true;
 }
 
-static void falcon_mask_status_intr(struct efx_nic *efx, int enable)
+static void falcon_mask_status_intr(struct efx_nic *efx, bool enable)
 {
-	efx_dword_t reg;
+	efx_oword_t reg;
 
 	if ((falcon_rev(efx) < FALCON_REV_B0) || LOOPBACK_INTERNAL(efx))
 		return;
 
 	/* Flush the ISR */
 	if (enable)
-		falcon_xmac_readl(efx, &reg, XM_MGT_INT_REG_MAC_B0);
+		falcon_read(efx, &reg, XM_MGT_INT_REG_B0);
 
-	EFX_POPULATE_DWORD_2(reg,
+	EFX_POPULATE_OWORD_2(reg,
 			     XM_MSK_RMTFLT, !enable,
 			     XM_MSK_LCLFLT, !enable);
-	falcon_xmac_writel(efx, &reg, XM_MGT_INT_MSK_REG_MAC_B0);
+	falcon_write(efx, &reg, XM_MGT_INT_MSK_REG_B0);
 }
 
 int falcon_init_xmac(struct efx_nic *efx)
@@ -274,7 +156,7 @@
 	if (rc)
 		goto fail2;
 
-	falcon_mask_status_intr(efx, 1);
+	falcon_mask_status_intr(efx, true);
 	return 0;
 
  fail2:
@@ -283,34 +165,34 @@
 	return rc;
 }
 
-int falcon_xaui_link_ok(struct efx_nic *efx)
+bool falcon_xaui_link_ok(struct efx_nic *efx)
 {
-	efx_dword_t reg;
-	int align_done, sync_status, link_ok = 0;
+	efx_oword_t reg;
+	bool align_done, link_ok = false;
+	int sync_status;
 
 	if (LOOPBACK_INTERNAL(efx))
-		return 1;
+		return true;
 
 	/* Read link status */
-	falcon_xmac_readl(efx, &reg, XX_CORE_STAT_REG_MAC);
+	falcon_read(efx, &reg, XX_CORE_STAT_REG);
 
-	align_done = EFX_DWORD_FIELD(reg, XX_ALIGN_DONE);
-	sync_status = EFX_DWORD_FIELD(reg, XX_SYNC_STAT);
+	align_done = EFX_OWORD_FIELD(reg, XX_ALIGN_DONE);
+	sync_status = EFX_OWORD_FIELD(reg, XX_SYNC_STAT);
 	if (align_done && (sync_status == XX_SYNC_STAT_DECODE_SYNCED))
-		link_ok = 1;
+		link_ok = true;
 
 	/* Clear link status ready for next read */
-	EFX_SET_DWORD_FIELD(reg, XX_COMMA_DET, XX_COMMA_DET_RESET);
-	EFX_SET_DWORD_FIELD(reg, XX_CHARERR, XX_CHARERR_RESET);
-	EFX_SET_DWORD_FIELD(reg, XX_DISPERR, XX_DISPERR_RESET);
-	falcon_xmac_writel(efx, &reg, XX_CORE_STAT_REG_MAC);
+	EFX_SET_OWORD_FIELD(reg, XX_COMMA_DET, XX_COMMA_DET_RESET);
+	EFX_SET_OWORD_FIELD(reg, XX_CHARERR, XX_CHARERR_RESET);
+	EFX_SET_OWORD_FIELD(reg, XX_DISPERR, XX_DISPERR_RESET);
+	falcon_write(efx, &reg, XX_CORE_STAT_REG);
 
 	/* If the link is up, then check the phy side of the xaui link
 	 * (error conditions from the wire side propoagate back through
 	 * the phy to the xaui side). */
 	if (efx->link_up && link_ok) {
-		int has_phyxs = efx->phy_op->mmds & (1 << MDIO_MMD_PHYXS);
-		if (has_phyxs)
+		if (efx->phy_op->mmds & (1 << MDIO_MMD_PHYXS))
 			link_ok = mdio_clause45_phyxgxs_lane_sync(efx);
 	}
 
@@ -325,15 +207,15 @@
 static void falcon_reconfigure_xmac_core(struct efx_nic *efx)
 {
 	unsigned int max_frame_len;
-	efx_dword_t reg;
-	int rx_fc = (efx->flow_control & EFX_FC_RX) ? 1 : 0;
+	efx_oword_t reg;
+	bool rx_fc = !!(efx->flow_control & EFX_FC_RX);
 
 	/* Configure MAC  - cut-thru mode is hard wired on */
 	EFX_POPULATE_DWORD_3(reg,
 			     XM_RX_JUMBO_MODE, 1,
 			     XM_TX_STAT_EN, 1,
 			     XM_RX_STAT_EN, 1);
-	falcon_xmac_writel(efx, &reg, XM_GLB_CFG_REG_MAC);
+	falcon_write(efx, &reg, XM_GLB_CFG_REG);
 
 	/* Configure TX */
 	EFX_POPULATE_DWORD_6(reg,
@@ -343,7 +225,7 @@
 			     XM_TXCRC, 1,
 			     XM_FCNTL, 1,
 			     XM_IPG, 0x3);
-	falcon_xmac_writel(efx, &reg, XM_TX_CFG_REG_MAC);
+	falcon_write(efx, &reg, XM_TX_CFG_REG);
 
 	/* Configure RX */
 	EFX_POPULATE_DWORD_5(reg,
@@ -352,21 +234,21 @@
 			     XM_ACPT_ALL_MCAST, 1,
 			     XM_ACPT_ALL_UCAST, efx->promiscuous,
 			     XM_PASS_CRC_ERR, 1);
-	falcon_xmac_writel(efx, &reg, XM_RX_CFG_REG_MAC);
+	falcon_write(efx, &reg, XM_RX_CFG_REG);
 
 	/* Set frame length */
 	max_frame_len = EFX_MAX_FRAME_LEN(efx->net_dev->mtu);
 	EFX_POPULATE_DWORD_1(reg, XM_MAX_RX_FRM_SIZE, max_frame_len);
-	falcon_xmac_writel(efx, &reg, XM_RX_PARAM_REG_MAC);
+	falcon_write(efx, &reg, XM_RX_PARAM_REG);
 	EFX_POPULATE_DWORD_2(reg,
 			     XM_MAX_TX_FRM_SIZE, max_frame_len,
 			     XM_TX_JUMBO_MODE, 1);
-	falcon_xmac_writel(efx, &reg, XM_TX_PARAM_REG_MAC);
+	falcon_write(efx, &reg, XM_TX_PARAM_REG);
 
 	EFX_POPULATE_DWORD_2(reg,
 			     XM_PAUSE_TIME, 0xfffe, /* MAX PAUSE TIME */
-			     XM_DIS_FCNTL, rx_fc ? 0 : 1);
-	falcon_xmac_writel(efx, &reg, XM_FC_REG_MAC);
+			     XM_DIS_FCNTL, !rx_fc);
+	falcon_write(efx, &reg, XM_FC_REG);
 
 	/* Set MAC address */
 	EFX_POPULATE_DWORD_4(reg,
@@ -374,83 +256,75 @@
 			     XM_ADR_1, efx->net_dev->dev_addr[1],
 			     XM_ADR_2, efx->net_dev->dev_addr[2],
 			     XM_ADR_3, efx->net_dev->dev_addr[3]);
-	falcon_xmac_writel(efx, &reg, XM_ADR_LO_REG_MAC);
+	falcon_write(efx, &reg, XM_ADR_LO_REG);
 	EFX_POPULATE_DWORD_2(reg,
 			     XM_ADR_4, efx->net_dev->dev_addr[4],
 			     XM_ADR_5, efx->net_dev->dev_addr[5]);
-	falcon_xmac_writel(efx, &reg, XM_ADR_HI_REG_MAC);
+	falcon_write(efx, &reg, XM_ADR_HI_REG);
 }
 
 static void falcon_reconfigure_xgxs_core(struct efx_nic *efx)
 {
-	efx_dword_t reg;
-	int xgxs_loopback = (efx->loopback_mode == LOOPBACK_XGXS) ? 1 : 0;
-	int xaui_loopback = (efx->loopback_mode == LOOPBACK_XAUI) ? 1 : 0;
-	int xgmii_loopback =
-		(efx->loopback_mode == LOOPBACK_XGMII) ? 1 : 0;
+	efx_oword_t reg;
+	bool xgxs_loopback = (efx->loopback_mode == LOOPBACK_XGXS);
+	bool xaui_loopback = (efx->loopback_mode == LOOPBACK_XAUI);
+	bool xgmii_loopback = (efx->loopback_mode == LOOPBACK_XGMII);
 
 	/* XGXS block is flaky and will need to be reset if moving
 	 * into our out of XGMII, XGXS or XAUI loopbacks. */
 	if (EFX_WORKAROUND_5147(efx)) {
-		int old_xgmii_loopback, old_xgxs_loopback, old_xaui_loopback;
-		int reset_xgxs;
+		bool old_xgmii_loopback, old_xgxs_loopback, old_xaui_loopback;
+		bool reset_xgxs;
 
-		falcon_xmac_readl(efx, &reg, XX_CORE_STAT_REG_MAC);
-		old_xgxs_loopback = EFX_DWORD_FIELD(reg, XX_XGXS_LB_EN);
-		old_xgmii_loopback = EFX_DWORD_FIELD(reg, XX_XGMII_LB_EN);
+		falcon_read(efx, &reg, XX_CORE_STAT_REG);
+		old_xgxs_loopback = EFX_OWORD_FIELD(reg, XX_XGXS_LB_EN);
+		old_xgmii_loopback = EFX_OWORD_FIELD(reg, XX_XGMII_LB_EN);
 
-		falcon_xmac_readl(efx, &reg, XX_SD_CTL_REG_MAC);
-		old_xaui_loopback = EFX_DWORD_FIELD(reg, XX_LPBKA);
+		falcon_read(efx, &reg, XX_SD_CTL_REG);
+		old_xaui_loopback = EFX_OWORD_FIELD(reg, XX_LPBKA);
 
 		/* The PHY driver may have turned XAUI off */
 		reset_xgxs = ((xgxs_loopback != old_xgxs_loopback) ||
 			      (xaui_loopback != old_xaui_loopback) ||
 			      (xgmii_loopback != old_xgmii_loopback));
-		if (reset_xgxs) {
-			falcon_xmac_readl(efx, &reg, XX_PWR_RST_REG_MAC);
-			EFX_SET_DWORD_FIELD(reg, XX_RSTXGXSTX_EN, 1);
-			EFX_SET_DWORD_FIELD(reg, XX_RSTXGXSRX_EN, 1);
-			falcon_xmac_writel(efx, &reg, XX_PWR_RST_REG_MAC);
-			udelay(1);
-			EFX_SET_DWORD_FIELD(reg, XX_RSTXGXSTX_EN, 0);
-			EFX_SET_DWORD_FIELD(reg, XX_RSTXGXSRX_EN, 0);
-			falcon_xmac_writel(efx, &reg, XX_PWR_RST_REG_MAC);
-			udelay(1);
-		}
+
+		if (reset_xgxs)
+			falcon_reset_xaui(efx);
 	}
 
-	falcon_xmac_readl(efx, &reg, XX_CORE_STAT_REG_MAC);
-	EFX_SET_DWORD_FIELD(reg, XX_FORCE_SIG,
+	falcon_read(efx, &reg, XX_CORE_STAT_REG);
+	EFX_SET_OWORD_FIELD(reg, XX_FORCE_SIG,
 			    (xgxs_loopback || xaui_loopback) ?
 			    XX_FORCE_SIG_DECODE_FORCED : 0);
-	EFX_SET_DWORD_FIELD(reg, XX_XGXS_LB_EN, xgxs_loopback);
-	EFX_SET_DWORD_FIELD(reg, XX_XGMII_LB_EN, xgmii_loopback);
-	falcon_xmac_writel(efx, &reg, XX_CORE_STAT_REG_MAC);
+	EFX_SET_OWORD_FIELD(reg, XX_XGXS_LB_EN, xgxs_loopback);
+	EFX_SET_OWORD_FIELD(reg, XX_XGMII_LB_EN, xgmii_loopback);
+	falcon_write(efx, &reg, XX_CORE_STAT_REG);
 
-	falcon_xmac_readl(efx, &reg, XX_SD_CTL_REG_MAC);
-	EFX_SET_DWORD_FIELD(reg, XX_LPBKD, xaui_loopback);
-	EFX_SET_DWORD_FIELD(reg, XX_LPBKC, xaui_loopback);
-	EFX_SET_DWORD_FIELD(reg, XX_LPBKB, xaui_loopback);
-	EFX_SET_DWORD_FIELD(reg, XX_LPBKA, xaui_loopback);
-	falcon_xmac_writel(efx, &reg, XX_SD_CTL_REG_MAC);
+	falcon_read(efx, &reg, XX_SD_CTL_REG);
+	EFX_SET_OWORD_FIELD(reg, XX_LPBKD, xaui_loopback);
+	EFX_SET_OWORD_FIELD(reg, XX_LPBKC, xaui_loopback);
+	EFX_SET_OWORD_FIELD(reg, XX_LPBKB, xaui_loopback);
+	EFX_SET_OWORD_FIELD(reg, XX_LPBKA, xaui_loopback);
+	falcon_write(efx, &reg, XX_SD_CTL_REG);
 }
 
 
 /* Try and bring the Falcon side of the Falcon-Phy XAUI link fails
  * to come back up. Bash it until it comes back up */
-static int falcon_check_xaui_link_up(struct efx_nic *efx)
+static bool falcon_check_xaui_link_up(struct efx_nic *efx)
 {
 	int max_tries, tries;
 	tries = EFX_WORKAROUND_5147(efx) ? 5 : 1;
 	max_tries = tries;
 
 	if ((efx->loopback_mode == LOOPBACK_NETWORK) ||
-	    (efx->phy_type == PHY_TYPE_NONE))
-		return 0;
+	    (efx->phy_type == PHY_TYPE_NONE) ||
+	    efx_phy_mode_disabled(efx->phy_mode))
+		return false;
 
 	while (tries) {
 		if (falcon_xaui_link_ok(efx))
-			return 1;
+			return true;
 
 		EFX_LOG(efx, "%s Clobbering XAUI (%d tries left).\n",
 			__func__, tries);
@@ -461,18 +335,22 @@
 
 	EFX_LOG(efx, "Failed to bring XAUI link back up in %d tries!\n",
 		max_tries);
-	return 0;
+	return false;
 }
 
 void falcon_reconfigure_xmac(struct efx_nic *efx)
 {
-	int xaui_link_ok;
+	bool xaui_link_ok;
 
-	falcon_mask_status_intr(efx, 0);
+	falcon_mask_status_intr(efx, false);
 
 	falcon_deconfigure_mac_wrapper(efx);
 
-	efx->tx_disabled = LOOPBACK_INTERNAL(efx);
+	/* Reconfigure the PHY, disabling transmit in mac level loopback. */
+	if (LOOPBACK_INTERNAL(efx))
+		efx->phy_mode |= PHY_MODE_TX_DISABLED;
+	else
+		efx->phy_mode &= ~PHY_MODE_TX_DISABLED;
 	efx->phy_op->reconfigure(efx);
 
 	falcon_reconfigure_xgxs_core(efx);
@@ -484,7 +362,7 @@
 	xaui_link_ok = falcon_check_xaui_link_up(efx);
 
 	if (xaui_link_ok && efx->link_up)
-		falcon_mask_status_intr(efx, 1);
+		falcon_mask_status_intr(efx, true);
 }
 
 void falcon_fini_xmac(struct efx_nic *efx)
@@ -554,21 +432,23 @@
 
 	/* Update derived statistics */
 	mac_stats->tx_good_bytes =
-		(mac_stats->tx_bytes - mac_stats->tx_bad_bytes);
+		(mac_stats->tx_bytes - mac_stats->tx_bad_bytes -
+		 mac_stats->tx_control * 64);
 	mac_stats->rx_bad_bytes =
-		(mac_stats->rx_bytes - mac_stats->rx_good_bytes);
+		(mac_stats->rx_bytes - mac_stats->rx_good_bytes -
+		 mac_stats->rx_control * 64);
 }
 
 int falcon_check_xmac(struct efx_nic *efx)
 {
-	unsigned xaui_link_ok;
+	bool xaui_link_ok;
 	int rc;
 
 	if ((efx->loopback_mode == LOOPBACK_NETWORK) ||
-	    (efx->phy_type == PHY_TYPE_NONE))
+	    efx_phy_mode_disabled(efx->phy_mode))
 		return 0;
 
-	falcon_mask_status_intr(efx, 0);
+	falcon_mask_status_intr(efx, false);
 	xaui_link_ok = falcon_xaui_link_ok(efx);
 
 	if (EFX_WORKAROUND_5147(efx) && !xaui_link_ok)
@@ -579,7 +459,7 @@
 
 	/* Unmask interrupt if everything was (and still is) ok */
 	if (xaui_link_ok && efx->link_up)
-		falcon_mask_status_intr(efx, 1);
+		falcon_mask_status_intr(efx, true);
 
 	return rc;
 }
@@ -620,7 +500,7 @@
 
 int falcon_xmac_set_pause(struct efx_nic *efx, enum efx_fc_type flow_control)
 {
-	int reset;
+	bool reset;
 
 	if (flow_control & EFX_FC_AUTO) {
 		EFX_LOG(efx, "10G does not support flow control "
diff --git a/drivers/net/sfc/mac.h b/drivers/net/sfc/mac.h
index edd07d4..a31571c 100644
--- a/drivers/net/sfc/mac.h
+++ b/drivers/net/sfc/mac.h
@@ -13,10 +13,6 @@
 
 #include "net_driver.h"
 
-extern void falcon_xmac_writel(struct efx_nic *efx,
-			       efx_dword_t *value, unsigned int mac_reg);
-extern void falcon_xmac_readl(struct efx_nic *efx,
-			      efx_dword_t *value, unsigned int mac_reg);
 extern int falcon_init_xmac(struct efx_nic *efx);
 extern void falcon_reconfigure_xmac(struct efx_nic *efx);
 extern void falcon_update_stats_xmac(struct efx_nic *efx);
diff --git a/drivers/net/sfc/mdio_10g.c b/drivers/net/sfc/mdio_10g.c
index c4f540e..003e48d 100644
--- a/drivers/net/sfc/mdio_10g.c
+++ b/drivers/net/sfc/mdio_10g.c
@@ -159,20 +159,21 @@
 	return 0;
 }
 
-int mdio_clause45_links_ok(struct efx_nic *efx, unsigned int mmd_mask)
+bool mdio_clause45_links_ok(struct efx_nic *efx, unsigned int mmd_mask)
 {
 	int phy_id = efx->mii.phy_id;
 	int status;
-	int ok = 1;
+	bool ok = true;
 	int mmd = 0;
-	int good;
 
 	/* If the port is in loopback, then we should only consider a subset
 	 * of mmd's */
 	if (LOOPBACK_INTERNAL(efx))
-		return 1;
+		return true;
 	else if (efx->loopback_mode == LOOPBACK_NETWORK)
-		return 0;
+		return false;
+	else if (efx_phy_mode_disabled(efx->phy_mode))
+		return false;
 	else if (efx->loopback_mode == LOOPBACK_PHYXS)
 		mmd_mask &= ~(MDIO_MMDREG_DEVS0_PHYXS |
 			      MDIO_MMDREG_DEVS0_PCS |
@@ -192,8 +193,7 @@
 			status = mdio_clause45_read(efx, phy_id,
 						    mmd, MDIO_MMDREG_STAT1);
 
-			good = status & (1 << MDIO_MMDREG_STAT1_LINK_LBN);
-			ok = ok && good;
+			ok = ok && (status & (1 << MDIO_MMDREG_STAT1_LINK_LBN));
 		}
 		mmd_mask = (mmd_mask >> 1);
 		mmd++;
@@ -208,7 +208,7 @@
 
 	ctrl1 = ctrl2 = mdio_clause45_read(efx, phy_id, MDIO_MMD_PMAPMD,
 					   MDIO_MMDREG_TXDIS);
-	if (efx->tx_disabled)
+	if (efx->phy_mode & PHY_MODE_TX_DISABLED)
 		ctrl2 |= (1 << MDIO_MMDREG_TXDIS_GLOBAL_LBN);
 	else
 		ctrl1 &= ~(1 << MDIO_MMDREG_TXDIS_GLOBAL_LBN);
diff --git a/drivers/net/sfc/mdio_10g.h b/drivers/net/sfc/mdio_10g.h
index cb99f3f..19c42ea 100644
--- a/drivers/net/sfc/mdio_10g.h
+++ b/drivers/net/sfc/mdio_10g.h
@@ -199,18 +199,19 @@
 	return (id_hi << 16) | (id_low);
 }
 
-static inline int mdio_clause45_phyxgxs_lane_sync(struct efx_nic *efx)
+static inline bool mdio_clause45_phyxgxs_lane_sync(struct efx_nic *efx)
 {
-	int i, sync, lane_status;
+	int i, lane_status;
+	bool sync;
 
 	for (i = 0; i < 2; ++i)
 		lane_status = mdio_clause45_read(efx, efx->mii.phy_id,
 						 MDIO_MMD_PHYXS,
 						 MDIO_PHYXS_LANE_STATE);
 
-	sync = (lane_status & (1 << MDIO_PHYXS_LANE_ALIGNED_LBN)) != 0;
+	sync = !!(lane_status & (1 << MDIO_PHYXS_LANE_ALIGNED_LBN));
 	if (!sync)
-		EFX_INFO(efx, "XGXS lane status: %x\n", lane_status);
+		EFX_LOG(efx, "XGXS lane status: %x\n", lane_status);
 	return sync;
 }
 
@@ -230,8 +231,8 @@
 			     unsigned int mmd_mask, unsigned int fatal_mask);
 
 /* Check the link status of specified mmds in bit mask */
-extern int mdio_clause45_links_ok(struct efx_nic *efx,
-				  unsigned int mmd_mask);
+extern bool mdio_clause45_links_ok(struct efx_nic *efx,
+				   unsigned int mmd_mask);
 
 /* Generic transmit disable support though PMAPMD */
 extern void mdio_clause45_transmit_disable(struct efx_nic *efx);
diff --git a/drivers/net/sfc/net_driver.h b/drivers/net/sfc/net_driver.h
index 219c74a..cdb11fa 100644
--- a/drivers/net/sfc/net_driver.h
+++ b/drivers/net/sfc/net_driver.h
@@ -88,9 +88,12 @@
  **************************************************************************/
 
 #define EFX_MAX_CHANNELS 32
-#define EFX_MAX_TX_QUEUES 1
 #define EFX_MAX_RX_QUEUES EFX_MAX_CHANNELS
 
+#define EFX_TX_QUEUE_OFFLOAD_CSUM	0
+#define EFX_TX_QUEUE_NO_CSUM		1
+#define EFX_TX_QUEUE_COUNT		2
+
 /**
  * struct efx_special_buffer - An Efx special buffer
  * @addr: CPU base address of the buffer
@@ -127,7 +130,6 @@
  *	This field is zero when the queue slot is empty.
  * @continuation: True if this fragment is not the end of a packet.
  * @unmap_single: True if pci_unmap_single should be used.
- * @unmap_addr: DMA address to unmap
  * @unmap_len: Length of this fragment to unmap
  */
 struct efx_tx_buffer {
@@ -135,9 +137,8 @@
 	struct efx_tso_header *tsoh;
 	dma_addr_t dma_addr;
 	unsigned short len;
-	unsigned char continuation;
-	unsigned char unmap_single;
-	dma_addr_t unmap_addr;
+	bool continuation;
+	bool unmap_single;
 	unsigned short unmap_len;
 };
 
@@ -156,13 +157,13 @@
  *
  * @efx: The associated Efx NIC
  * @queue: DMA queue number
- * @used: Queue is used by net driver
  * @channel: The associated channel
  * @buffer: The software buffer ring
  * @txd: The hardware descriptor ring
+ * @flushed: Used when handling queue flushing
  * @read_count: Current read pointer.
  *	This is the number of buffers that have been removed from both rings.
- * @stopped: Stopped flag.
+ * @stopped: Stopped count.
  *	Set if this TX queue is currently stopping its port.
  * @insert_count: Current insert pointer
  *	This is the number of buffers that have been added to the
@@ -188,11 +189,11 @@
 	/* Members which don't change on the fast path */
 	struct efx_nic *efx ____cacheline_aligned_in_smp;
 	int queue;
-	int used;
 	struct efx_channel *channel;
 	struct efx_nic *nic;
 	struct efx_tx_buffer *buffer;
 	struct efx_special_buffer txd;
+	bool flushed;
 
 	/* Members used mainly on the completion path */
 	unsigned int read_count ____cacheline_aligned_in_smp;
@@ -232,7 +233,6 @@
  * struct efx_rx_queue - An Efx RX queue
  * @efx: The associated Efx NIC
  * @queue: DMA queue number
- * @used: Queue is used by net driver
  * @channel: The associated channel
  * @buffer: The software buffer ring
  * @rxd: The hardware descriptor ring
@@ -262,11 +262,11 @@
  *	the remaining space in the allocation.
  * @buf_dma_addr: Page's DMA address.
  * @buf_data: Page's host address.
+ * @flushed: Use when handling queue flushing
  */
 struct efx_rx_queue {
 	struct efx_nic *efx;
 	int queue;
-	int used;
 	struct efx_channel *channel;
 	struct efx_rx_buffer *buffer;
 	struct efx_special_buffer rxd;
@@ -288,6 +288,7 @@
 	struct page *buf_page;
 	dma_addr_t buf_dma_addr;
 	char *buf_data;
+	bool flushed;
 };
 
 /**
@@ -325,12 +326,10 @@
  * queue.
  *
  * @efx: Associated Efx NIC
- * @evqnum: Event queue number
  * @channel: Channel instance number
  * @used_flags: Channel is used by net driver
  * @enabled: Channel enabled indicator
  * @irq: IRQ number (MSI and MSI-X only)
- * @has_interrupt: Channel has an interrupt
  * @irq_moderation: IRQ moderation value (in us)
  * @napi_dev: Net device used with NAPI
  * @napi_str: NAPI control structure
@@ -357,17 +356,14 @@
  */
 struct efx_channel {
 	struct efx_nic *efx;
-	int evqnum;
 	int channel;
 	int used_flags;
-	int enabled;
+	bool enabled;
 	int irq;
-	unsigned int has_interrupt;
 	unsigned int irq_moderation;
 	struct net_device *napi_dev;
 	struct napi_struct napi_str;
-	struct work_struct reset_work;
-	int work_pending;
+	bool work_pending;
 	struct efx_special_buffer eventq;
 	unsigned int eventq_read_ptr;
 	unsigned int last_eventq_read_ptr;
@@ -390,7 +386,7 @@
 	 * access with prefetches.
 	 */
 	struct efx_rx_buffer *rx_pkt;
-	int rx_pkt_csummed;
+	bool rx_pkt_csummed;
 
 };
 
@@ -403,8 +399,8 @@
  */
 struct efx_blinker {
 	int led_num;
-	int state;
-	int resubmit;
+	bool state;
+	bool resubmit;
 	struct timer_list timer;
 };
 
@@ -432,8 +428,8 @@
 	 * have a separate init callback that happens later than
 	 * board init. */
 	int (*init_leds)(struct efx_nic *efx);
-	void (*set_fault_led) (struct efx_nic *efx, int state);
-	void (*blink) (struct efx_nic *efx, int start);
+	void (*set_fault_led) (struct efx_nic *efx, bool state);
+	void (*blink) (struct efx_nic *efx, bool start);
 	void (*fini) (struct efx_nic *nic);
 	struct efx_blinker blinker;
 	struct i2c_client *hwmon_client, *ioexp_client;
@@ -467,8 +463,7 @@
 	STATE_INIT = 0,
 	STATE_RUNNING = 1,
 	STATE_FINI = 2,
-	STATE_RESETTING = 3, /* rtnl_lock always held */
-	STATE_DISABLED = 4,
+	STATE_DISABLED = 3,
 	STATE_MAX,
 };
 
@@ -479,7 +474,7 @@
  * This is the equivalent of NET_IP_ALIGN [which controls the alignment
  * of the skb->head for hardware DMA].
  */
-#if defined(__i386__) || defined(__x86_64__)
+#ifdef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
 #define EFX_PAGE_IP_ALIGN 0
 #else
 #define EFX_PAGE_IP_ALIGN NET_IP_ALIGN
@@ -512,7 +507,6 @@
  * @clear_interrupt: Clear down interrupt
  * @blink: Blink LEDs
  * @check_hw: Check hardware
- * @reset_xaui: Reset XAUI side of PHY for (software sequenced reset)
  * @mmds: MMD presence mask
  * @loopbacks: Supported loopback modes mask
  */
@@ -522,11 +516,28 @@
 	void (*reconfigure) (struct efx_nic *efx);
 	void (*clear_interrupt) (struct efx_nic *efx);
 	int (*check_hw) (struct efx_nic *efx);
-	void (*reset_xaui) (struct efx_nic *efx);
+	int (*test) (struct efx_nic *efx);
 	int mmds;
 	unsigned loopbacks;
 };
 
+/**
+ * @enum efx_phy_mode - PHY operating mode flags
+ * @PHY_MODE_NORMAL: on and should pass traffic
+ * @PHY_MODE_TX_DISABLED: on with TX disabled
+ * @PHY_MODE_SPECIAL: on but will not pass traffic
+ */
+enum efx_phy_mode {
+	PHY_MODE_NORMAL		= 0,
+	PHY_MODE_TX_DISABLED	= 1,
+	PHY_MODE_SPECIAL	= 8,
+};
+
+static inline bool efx_phy_mode_disabled(enum efx_phy_mode mode)
+{
+	return !!(mode & ~PHY_MODE_TX_DISABLED);
+}
+
 /*
  * Efx extended statistics
  *
@@ -632,7 +643,7 @@
  * @tx_queue: TX DMA queues
  * @rx_queue: RX DMA queues
  * @channel: Channels
- * @rss_queues: Number of RSS queues
+ * @n_rx_queues: Number of RX queues
  * @rx_buffer_len: RX buffer length
  * @rx_buffer_order: Order (log2) of number of pages for each RX buffer
  * @irq_status: Interrupt status buffer
@@ -640,15 +651,20 @@
  *	This register is written with the SMP processor ID whenever an
  *	interrupt is handled.  It is used by falcon_test_interrupt()
  *	to verify that an interrupt has occurred.
+ * @spi_flash: SPI flash device
+ *	This field will be %NULL if no flash device is present.
+ * @spi_eeprom: SPI EEPROM device
+ *	This field will be %NULL if no EEPROM device is present.
  * @n_rx_nodesc_drop_cnt: RX no descriptor drop count
  * @nic_data: Hardware dependant state
- * @mac_lock: MAC access lock. Protects @port_enabled, efx_monitor() and
- *	efx_reconfigure_port()
+ * @mac_lock: MAC access lock. Protects @port_enabled, @phy_mode,
+ *	@port_inhibited, efx_monitor() and efx_reconfigure_port()
  * @port_enabled: Port enabled indicator.
  *	Serialises efx_stop_all(), efx_start_all() and efx_monitor() and
  *	efx_reconfigure_work with kernel interfaces. Safe to read under any
  *	one of the rtnl_lock, mac_lock, or netif_tx_lock, but all three must
  *	be held to modify it.
+ * @port_inhibited: If set, the netif_carrier is always off. Hold the mac_lock
  * @port_initialized: Port initialized?
  * @net_dev: Operating system network device. Consider holding the rtnl lock
  * @rx_checksum_enabled: RX checksumming enabled
@@ -658,14 +674,16 @@
  *	can provide.  Generic code converts these into a standard
  *	&struct net_device_stats.
  * @stats_buffer: DMA buffer for statistics
- * @stats_lock: Statistics update lock
+ * @stats_lock: Statistics update lock. Serialises statistics fetches
+ * @stats_enabled: Temporarily disable statistics fetches.
+ *	Serialised by @stats_lock
  * @mac_address: Permanent MAC address
  * @phy_type: PHY type
  * @phy_lock: PHY access lock
  * @phy_op: PHY interface
  * @phy_data: PHY private data (including PHY-specific stats)
  * @mii: PHY interface
- * @tx_disabled: PHY transmitter turned off
+ * @phy_mode: PHY operating mode. Serialised by @mac_lock.
  * @link_up: Link status
  * @link_options: Link options (MII/GMII format)
  * @n_link_state_changes: Number of times the link has changed state
@@ -700,27 +718,31 @@
 	enum nic_state state;
 	enum reset_type reset_pending;
 
-	struct efx_tx_queue tx_queue[EFX_MAX_TX_QUEUES];
+	struct efx_tx_queue tx_queue[EFX_TX_QUEUE_COUNT];
 	struct efx_rx_queue rx_queue[EFX_MAX_RX_QUEUES];
 	struct efx_channel channel[EFX_MAX_CHANNELS];
 
-	int rss_queues;
+	int n_rx_queues;
 	unsigned int rx_buffer_len;
 	unsigned int rx_buffer_order;
 
 	struct efx_buffer irq_status;
 	volatile signed int last_irq_cpu;
 
+	struct efx_spi_device *spi_flash;
+	struct efx_spi_device *spi_eeprom;
+
 	unsigned n_rx_nodesc_drop_cnt;
 
 	struct falcon_nic_data *nic_data;
 
 	struct mutex mac_lock;
-	int port_enabled;
+	bool port_enabled;
+	bool port_inhibited;
 
-	int port_initialized;
+	bool port_initialized;
 	struct net_device *net_dev;
-	int rx_checksum_enabled;
+	bool rx_checksum_enabled;
 
 	atomic_t netif_stop_count;
 	spinlock_t netif_stop_lock;
@@ -728,6 +750,7 @@
 	struct efx_mac_stats mac_stats;
 	struct efx_buffer stats_buffer;
 	spinlock_t stats_lock;
+	bool stats_enabled;
 
 	unsigned char mac_address[ETH_ALEN];
 
@@ -736,13 +759,13 @@
 	struct efx_phy_operations *phy_op;
 	void *phy_data;
 	struct mii_if_info mii;
-	unsigned tx_disabled;
+	enum efx_phy_mode phy_mode;
 
-	int link_up;
+	bool link_up;
 	unsigned int link_options;
 	unsigned int n_link_state_changes;
 
-	int promiscuous;
+	bool promiscuous;
 	union efx_multicast_hash multicast_hash;
 	enum efx_fc_type flow_control;
 	struct work_struct reconfigure_work;
@@ -829,50 +852,33 @@
 			continue;					\
 		else
 
-/* Iterate over all used channels with interrupts */
-#define efx_for_each_channel_with_interrupt(_channel, _efx)		\
-	for (_channel = &_efx->channel[0];				\
-	     _channel < &_efx->channel[EFX_MAX_CHANNELS];		\
-	     _channel++)						\
-		if (!(_channel->used_flags && _channel->has_interrupt))	\
-			continue;					\
-		else
-
 /* Iterate over all used TX queues */
 #define efx_for_each_tx_queue(_tx_queue, _efx)				\
 	for (_tx_queue = &_efx->tx_queue[0];				\
-	     _tx_queue < &_efx->tx_queue[EFX_MAX_TX_QUEUES];		\
-	     _tx_queue++)						\
-		if (!_tx_queue->used)					\
-			continue;					\
-		else
+	     _tx_queue < &_efx->tx_queue[EFX_TX_QUEUE_COUNT];		\
+	     _tx_queue++)
 
 /* Iterate over all TX queues belonging to a channel */
 #define efx_for_each_channel_tx_queue(_tx_queue, _channel)		\
 	for (_tx_queue = &_channel->efx->tx_queue[0];			\
-	     _tx_queue < &_channel->efx->tx_queue[EFX_MAX_TX_QUEUES];	\
+	     _tx_queue < &_channel->efx->tx_queue[EFX_TX_QUEUE_COUNT];	\
 	     _tx_queue++)						\
-		if ((!_tx_queue->used) ||				\
-		    (_tx_queue->channel != _channel))			\
+		if (_tx_queue->channel != _channel)			\
 			continue;					\
 		else
 
 /* Iterate over all used RX queues */
 #define efx_for_each_rx_queue(_rx_queue, _efx)				\
 	for (_rx_queue = &_efx->rx_queue[0];				\
-	     _rx_queue < &_efx->rx_queue[EFX_MAX_RX_QUEUES];		\
-	     _rx_queue++)						\
-		if (!_rx_queue->used)					\
-			continue;					\
-		else
+	     _rx_queue < &_efx->rx_queue[_efx->n_rx_queues];		\
+	     _rx_queue++)
 
 /* Iterate over all RX queues belonging to a channel */
 #define efx_for_each_channel_rx_queue(_rx_queue, _channel)		\
-	for (_rx_queue = &_channel->efx->rx_queue[0];			\
-	     _rx_queue < &_channel->efx->rx_queue[EFX_MAX_RX_QUEUES];	\
-	     _rx_queue++)						\
-		if ((!_rx_queue->used) ||				\
-		    (_rx_queue->channel != _channel))			\
+	for (_rx_queue = &_channel->efx->rx_queue[_channel->channel];	\
+	     _rx_queue;							\
+	     _rx_queue = NULL)						\
+		if (_rx_queue->channel != _channel)			\
 			continue;					\
 		else
 
@@ -886,13 +892,13 @@
 }
 
 /* Set bit in a little-endian bitfield */
-static inline void set_bit_le(int nr, unsigned char *addr)
+static inline void set_bit_le(unsigned nr, unsigned char *addr)
 {
 	addr[nr / 8] |= (1 << (nr % 8));
 }
 
 /* Clear bit in a little-endian bitfield */
-static inline void clear_bit_le(int nr, unsigned char *addr)
+static inline void clear_bit_le(unsigned nr, unsigned char *addr)
 {
 	addr[nr / 8] &= ~(1 << (nr % 8));
 }
diff --git a/drivers/net/sfc/phy.h b/drivers/net/sfc/phy.h
index 9d02c84..f746536 100644
--- a/drivers/net/sfc/phy.h
+++ b/drivers/net/sfc/phy.h
@@ -15,15 +15,7 @@
  */
 extern struct efx_phy_operations falcon_tenxpress_phy_ops;
 
-enum tenxpress_state {
-	TENXPRESS_STATUS_OFF = 0,
-	TENXPRESS_STATUS_OTEMP = 1,
-	TENXPRESS_STATUS_NORMAL = 2,
-};
-
-extern void tenxpress_set_state(struct efx_nic *efx,
-				enum tenxpress_state state);
-extern void tenxpress_phy_blink(struct efx_nic *efx, int blink);
+extern void tenxpress_phy_blink(struct efx_nic *efx, bool blink);
 extern void tenxpress_crc_err(struct efx_nic *efx);
 
 /****************************************************************************
diff --git a/drivers/net/sfc/rx.c b/drivers/net/sfc/rx.c
index 0d27dd3..0f805da 100644
--- a/drivers/net/sfc/rx.c
+++ b/drivers/net/sfc/rx.c
@@ -212,8 +212,8 @@
  * and populates a struct efx_rx_buffer with the relevant
  * information.  Return a negative error code or 0 on success.
  */
-static inline int efx_init_rx_buffer_skb(struct efx_rx_queue *rx_queue,
-					 struct efx_rx_buffer *rx_buf)
+static int efx_init_rx_buffer_skb(struct efx_rx_queue *rx_queue,
+				  struct efx_rx_buffer *rx_buf)
 {
 	struct efx_nic *efx = rx_queue->efx;
 	struct net_device *net_dev = efx->net_dev;
@@ -252,8 +252,8 @@
  * and populates a struct efx_rx_buffer with the relevant
  * information.  Return a negative error code or 0 on success.
  */
-static inline int efx_init_rx_buffer_page(struct efx_rx_queue *rx_queue,
-					  struct efx_rx_buffer *rx_buf)
+static int efx_init_rx_buffer_page(struct efx_rx_queue *rx_queue,
+				   struct efx_rx_buffer *rx_buf)
 {
 	struct efx_nic *efx = rx_queue->efx;
 	int bytes, space, offset;
@@ -319,8 +319,8 @@
  * and populates a struct efx_rx_buffer with the relevant
  * information.
  */
-static inline int efx_init_rx_buffer(struct efx_rx_queue *rx_queue,
-				     struct efx_rx_buffer *new_rx_buf)
+static int efx_init_rx_buffer(struct efx_rx_queue *rx_queue,
+			      struct efx_rx_buffer *new_rx_buf)
 {
 	int rc = 0;
 
@@ -340,8 +340,8 @@
 	return rc;
 }
 
-static inline void efx_unmap_rx_buffer(struct efx_nic *efx,
-				       struct efx_rx_buffer *rx_buf)
+static void efx_unmap_rx_buffer(struct efx_nic *efx,
+				struct efx_rx_buffer *rx_buf)
 {
 	if (rx_buf->page) {
 		EFX_BUG_ON_PARANOID(rx_buf->skb);
@@ -357,8 +357,8 @@
 	}
 }
 
-static inline void efx_free_rx_buffer(struct efx_nic *efx,
-				      struct efx_rx_buffer *rx_buf)
+static void efx_free_rx_buffer(struct efx_nic *efx,
+			       struct efx_rx_buffer *rx_buf)
 {
 	if (rx_buf->page) {
 		__free_pages(rx_buf->page, efx->rx_buffer_order);
@@ -369,8 +369,8 @@
 	}
 }
 
-static inline void efx_fini_rx_buffer(struct efx_rx_queue *rx_queue,
-				      struct efx_rx_buffer *rx_buf)
+static void efx_fini_rx_buffer(struct efx_rx_queue *rx_queue,
+			       struct efx_rx_buffer *rx_buf)
 {
 	efx_unmap_rx_buffer(rx_queue->efx, rx_buf);
 	efx_free_rx_buffer(rx_queue->efx, rx_buf);
@@ -506,10 +506,10 @@
 		efx_schedule_slow_fill(rx_queue, 1);
 }
 
-static inline void efx_rx_packet__check_len(struct efx_rx_queue *rx_queue,
-					    struct efx_rx_buffer *rx_buf,
-					    int len, int *discard,
-					    int *leak_packet)
+static void efx_rx_packet__check_len(struct efx_rx_queue *rx_queue,
+				     struct efx_rx_buffer *rx_buf,
+				     int len, bool *discard,
+				     bool *leak_packet)
 {
 	struct efx_nic *efx = rx_queue->efx;
 	unsigned max_len = rx_buf->len - efx->type->rx_buffer_padding;
@@ -520,7 +520,7 @@
 	/* The packet must be discarded, but this is only a fatal error
 	 * if the caller indicated it was
 	 */
-	*discard = 1;
+	*discard = true;
 
 	if ((len > rx_buf->len) && EFX_WORKAROUND_8071(efx)) {
 		EFX_ERR_RL(efx, " RX queue %d seriously overlength "
@@ -546,8 +546,8 @@
  * Handles driverlink veto, and passes the fragment up via
  * the appropriate LRO method
  */
-static inline void efx_rx_packet_lro(struct efx_channel *channel,
-				     struct efx_rx_buffer *rx_buf)
+static void efx_rx_packet_lro(struct efx_channel *channel,
+			      struct efx_rx_buffer *rx_buf)
 {
 	struct net_lro_mgr *lro_mgr = &channel->lro_mgr;
 	void *priv = channel;
@@ -574,9 +574,9 @@
 }
 
 /* Allocate and construct an SKB around a struct page.*/
-static inline struct sk_buff *efx_rx_mk_skb(struct efx_rx_buffer *rx_buf,
-					    struct efx_nic *efx,
-					    int hdr_len)
+static struct sk_buff *efx_rx_mk_skb(struct efx_rx_buffer *rx_buf,
+				     struct efx_nic *efx,
+				     int hdr_len)
 {
 	struct sk_buff *skb;
 
@@ -621,11 +621,11 @@
 }
 
 void efx_rx_packet(struct efx_rx_queue *rx_queue, unsigned int index,
-		   unsigned int len, int checksummed, int discard)
+		   unsigned int len, bool checksummed, bool discard)
 {
 	struct efx_nic *efx = rx_queue->efx;
 	struct efx_rx_buffer *rx_buf;
-	int leak_packet = 0;
+	bool leak_packet = false;
 
 	rx_buf = efx_rx_buffer(rx_queue, index);
 	EFX_BUG_ON_PARANOID(!rx_buf->data);
@@ -683,11 +683,11 @@
 
 /* Handle a received packet.  Second half: Touches packet payload. */
 void __efx_rx_packet(struct efx_channel *channel,
-		     struct efx_rx_buffer *rx_buf, int checksummed)
+		     struct efx_rx_buffer *rx_buf, bool checksummed)
 {
 	struct efx_nic *efx = channel->efx;
 	struct sk_buff *skb;
-	int lro = efx->net_dev->features & NETIF_F_LRO;
+	bool lro = !!(efx->net_dev->features & NETIF_F_LRO);
 
 	/* If we're in loopback test, then pass the packet directly to the
 	 * loopback layer, and free the rx_buf here
@@ -789,27 +789,18 @@
 	/* Allocate RX buffers */
 	rxq_size = (efx->type->rxd_ring_mask + 1) * sizeof(*rx_queue->buffer);
 	rx_queue->buffer = kzalloc(rxq_size, GFP_KERNEL);
-	if (!rx_queue->buffer) {
-		rc = -ENOMEM;
-		goto fail1;
-	}
+	if (!rx_queue->buffer)
+		return -ENOMEM;
 
 	rc = falcon_probe_rx(rx_queue);
-	if (rc)
-		goto fail2;
-
-	return 0;
-
- fail2:
-	kfree(rx_queue->buffer);
-	rx_queue->buffer = NULL;
- fail1:
-	rx_queue->used = 0;
-
+	if (rc) {
+		kfree(rx_queue->buffer);
+		rx_queue->buffer = NULL;
+	}
 	return rc;
 }
 
-int efx_init_rx_queue(struct efx_rx_queue *rx_queue)
+void efx_init_rx_queue(struct efx_rx_queue *rx_queue)
 {
 	struct efx_nic *efx = rx_queue->efx;
 	unsigned int max_fill, trigger, limit;
@@ -833,7 +824,7 @@
 	rx_queue->fast_fill_limit = limit;
 
 	/* Set up RX descriptor ring */
-	return falcon_init_rx(rx_queue);
+	falcon_init_rx(rx_queue);
 }
 
 void efx_fini_rx_queue(struct efx_rx_queue *rx_queue)
@@ -872,7 +863,6 @@
 
 	kfree(rx_queue->buffer);
 	rx_queue->buffer = NULL;
-	rx_queue->used = 0;
 }
 
 void efx_flush_lro(struct efx_channel *channel)
diff --git a/drivers/net/sfc/rx.h b/drivers/net/sfc/rx.h
index f35e377..0e88a9d 100644
--- a/drivers/net/sfc/rx.h
+++ b/drivers/net/sfc/rx.h
@@ -14,7 +14,7 @@
 
 int efx_probe_rx_queue(struct efx_rx_queue *rx_queue);
 void efx_remove_rx_queue(struct efx_rx_queue *rx_queue);
-int efx_init_rx_queue(struct efx_rx_queue *rx_queue);
+void efx_init_rx_queue(struct efx_rx_queue *rx_queue);
 void efx_fini_rx_queue(struct efx_rx_queue *rx_queue);
 
 int efx_lro_init(struct net_lro_mgr *lro_mgr, struct efx_nic *efx);
@@ -24,6 +24,6 @@
 void efx_fast_push_rx_descriptors(struct efx_rx_queue *rx_queue);
 void efx_rx_work(struct work_struct *data);
 void __efx_rx_packet(struct efx_channel *channel,
-		     struct efx_rx_buffer *rx_buf, int checksummed);
+		     struct efx_rx_buffer *rx_buf, bool checksummed);
 
 #endif /* EFX_RX_H */
diff --git a/drivers/net/sfc/selftest.c b/drivers/net/sfc/selftest.c
index 3b2de9f..362956e 100644
--- a/drivers/net/sfc/selftest.c
+++ b/drivers/net/sfc/selftest.c
@@ -27,6 +27,9 @@
 #include "boards.h"
 #include "workarounds.h"
 #include "mac.h"
+#include "spi.h"
+#include "falcon_io.h"
+#include "mdio_10g.h"
 
 /*
  * Loopback test packet structure
@@ -51,7 +54,7 @@
 	"Hello world! This is an Efx loopback test in progress!";
 
 /**
- * efx_selftest_state - persistent state during a selftest
+ * efx_loopback_state - persistent state during a loopback selftest
  * @flush:		Drop all packets in efx_loopback_rx_packet
  * @packet_count:	Number of packets being used in this test
  * @skbs:		An array of skbs transmitted
@@ -59,10 +62,14 @@
  * @rx_bad:		RX bad packet count
  * @payload:		Payload used in tests
  */
-struct efx_selftest_state {
-	int flush;
+struct efx_loopback_state {
+	bool flush;
 	int packet_count;
 	struct sk_buff **skbs;
+
+	/* Checksums are being offloaded */
+	bool offload_csum;
+
 	atomic_t rx_good;
 	atomic_t rx_bad;
 	struct efx_loopback_payload payload;
@@ -70,21 +77,65 @@
 
 /**************************************************************************
  *
- * Configurable values
+ * MII, NVRAM and register tests
  *
  **************************************************************************/
 
-/* Level of loopback testing
- *
- * The maximum packet burst length is 16**(n-1), i.e.
- *
- * - Level 0 : no packets
- * - Level 1 : 1 packet
- * - Level 2 : 17 packets (1 * 1 packet, 1 * 16 packets)
- * - Level 3 : 273 packets (1 * 1 packet, 1 * 16 packet, 1 * 256 packets)
- *
- */
-static unsigned int loopback_test_level = 3;
+static int efx_test_mii(struct efx_nic *efx, struct efx_self_tests *tests)
+{
+	int rc = 0;
+	u16 physid1, physid2;
+	struct mii_if_info *mii = &efx->mii;
+	struct net_device *net_dev = efx->net_dev;
+
+	if (efx->phy_type == PHY_TYPE_NONE)
+		return 0;
+
+	mutex_lock(&efx->mac_lock);
+	tests->mii = -1;
+
+	physid1 = mii->mdio_read(net_dev, mii->phy_id, MII_PHYSID1);
+	physid2 = mii->mdio_read(net_dev, mii->phy_id, MII_PHYSID2);
+
+	if ((physid1 == 0x0000) || (physid1 == 0xffff) ||
+	    (physid2 == 0x0000) || (physid2 == 0xffff)) {
+		EFX_ERR(efx, "no MII PHY present with ID %d\n",
+			mii->phy_id);
+		rc = -EINVAL;
+		goto out;
+	}
+
+	rc = mdio_clause45_check_mmds(efx, efx->phy_op->mmds, 0);
+	if (rc)
+		goto out;
+
+out:
+	mutex_unlock(&efx->mac_lock);
+	tests->mii = rc ? -1 : 1;
+	return rc;
+}
+
+static int efx_test_nvram(struct efx_nic *efx, struct efx_self_tests *tests)
+{
+	int rc;
+
+	rc = falcon_read_nvram(efx, NULL);
+	tests->nvram = rc ? -1 : 1;
+	return rc;
+}
+
+static int efx_test_chip(struct efx_nic *efx, struct efx_self_tests *tests)
+{
+	int rc;
+
+	/* Not supported on A-series silicon */
+	if (falcon_rev(efx) < FALCON_REV_B0)
+		return 0;
+
+	rc = falcon_test_registers(efx);
+	tests->registers = rc ? -1 : 1;
+	return rc;
+}
 
 /**************************************************************************
  *
@@ -107,7 +158,7 @@
 
 	/* ACK each interrupting event queue. Receiving an interrupt due to
 	 * traffic before a test event is raised is considered a pass */
-	efx_for_each_channel_with_interrupt(channel, efx) {
+	efx_for_each_channel(channel, efx) {
 		if (channel->work_pending)
 			efx_process_channel_now(channel);
 		if (efx->last_irq_cpu >= 0)
@@ -132,41 +183,6 @@
 	return 0;
 }
 
-/* Test generation and receipt of non-interrupting events */
-static int efx_test_eventq(struct efx_channel *channel,
-			   struct efx_self_tests *tests)
-{
-	unsigned int magic;
-
-	/* Channel specific code, limited to 20 bits */
-	magic = (0x00010150 + channel->channel);
-	EFX_LOG(channel->efx, "channel %d testing event queue with code %x\n",
-		channel->channel, magic);
-
-	tests->eventq_dma[channel->channel] = -1;
-	tests->eventq_int[channel->channel] = 1;	/* fake pass */
-	tests->eventq_poll[channel->channel] = 1;	/* fake pass */
-
-	/* Reset flag and zero magic word */
-	channel->efx->last_irq_cpu = -1;
-	channel->eventq_magic = 0;
-	smp_wmb();
-
-	falcon_generate_test_event(channel, magic);
-	udelay(1);
-
-	efx_process_channel_now(channel);
-	if (channel->eventq_magic != magic) {
-		EFX_ERR(channel->efx, "channel %d  failed to see test event\n",
-			channel->channel);
-		return -ETIMEDOUT;
-	} else {
-		tests->eventq_dma[channel->channel] = 1;
-	}
-
-	return 0;
-}
-
 /* Test generation and receipt of interrupting events */
 static int efx_test_eventq_irq(struct efx_channel *channel,
 			       struct efx_self_tests *tests)
@@ -230,39 +246,18 @@
 	return 0;
 }
 
-/**************************************************************************
- *
- * PHY testing
- *
- **************************************************************************/
-
-/* Check PHY presence by reading the PHY ID registers */
-static int efx_test_phy(struct efx_nic *efx,
-			struct efx_self_tests *tests)
+static int efx_test_phy(struct efx_nic *efx, struct efx_self_tests *tests)
 {
-	u16 physid1, physid2;
-	struct mii_if_info *mii = &efx->mii;
-	struct net_device *net_dev = efx->net_dev;
+	int rc;
 
-	if (efx->phy_type == PHY_TYPE_NONE)
+	if (!efx->phy_op->test)
 		return 0;
 
-	EFX_LOG(efx, "testing PHY presence\n");
-	tests->phy_ok = -1;
-
-	physid1 = mii->mdio_read(net_dev, mii->phy_id, MII_PHYSID1);
-	physid2 = mii->mdio_read(net_dev, mii->phy_id, MII_PHYSID2);
-
-	if ((physid1 != 0x0000) && (physid1 != 0xffff) &&
-	    (physid2 != 0x0000) && (physid2 != 0xffff)) {
-		EFX_LOG(efx, "found MII PHY %d ID 0x%x:%x\n",
-			mii->phy_id, physid1, physid2);
-		tests->phy_ok = 1;
-		return 0;
-	}
-
-	EFX_ERR(efx, "no MII PHY present with ID %d\n", mii->phy_id);
-	return -ENODEV;
+	mutex_lock(&efx->mac_lock);
+	rc = efx->phy_op->test(efx);
+	mutex_unlock(&efx->mac_lock);
+	tests->phy = rc ? -1 : 1;
+	return rc;
 }
 
 /**************************************************************************
@@ -278,7 +273,7 @@
 void efx_loopback_rx_packet(struct efx_nic *efx,
 			    const char *buf_ptr, int pkt_len)
 {
-	struct efx_selftest_state *state = efx->loopback_selftest;
+	struct efx_loopback_state *state = efx->loopback_selftest;
 	struct efx_loopback_payload *received;
 	struct efx_loopback_payload *payload;
 
@@ -289,11 +284,12 @@
 		return;
 
 	payload = &state->payload;
-	
+
 	received = (struct efx_loopback_payload *) buf_ptr;
 	received->ip.saddr = payload->ip.saddr;
-	received->ip.check = payload->ip.check;
-	
+	if (state->offload_csum)
+		received->ip.check = payload->ip.check;
+
 	/* Check that header exists */
 	if (pkt_len < sizeof(received->header)) {
 		EFX_ERR(efx, "saw runt RX packet (length %d) in %s loopback "
@@ -362,7 +358,7 @@
 /* Initialise an efx_selftest_state for a new iteration */
 static void efx_iterate_state(struct efx_nic *efx)
 {
-	struct efx_selftest_state *state = efx->loopback_selftest;
+	struct efx_loopback_state *state = efx->loopback_selftest;
 	struct net_device *net_dev = efx->net_dev;
 	struct efx_loopback_payload *payload = &state->payload;
 
@@ -395,17 +391,17 @@
 	smp_wmb();
 }
 
-static int efx_tx_loopback(struct efx_tx_queue *tx_queue)
+static int efx_begin_loopback(struct efx_tx_queue *tx_queue)
 {
 	struct efx_nic *efx = tx_queue->efx;
-	struct efx_selftest_state *state = efx->loopback_selftest;
+	struct efx_loopback_state *state = efx->loopback_selftest;
 	struct efx_loopback_payload *payload;
 	struct sk_buff *skb;
 	int i, rc;
 
 	/* Transmit N copies of buffer */
 	for (i = 0; i < state->packet_count; i++) {
-		/* Allocate an skb, holding an extra reference for 
+		/* Allocate an skb, holding an extra reference for
 		 * transmit completion counting */
 		skb = alloc_skb(sizeof(state->payload), GFP_KERNEL);
 		if (!skb)
@@ -444,11 +440,25 @@
 	return 0;
 }
 
-static int efx_rx_loopback(struct efx_tx_queue *tx_queue,
-			   struct efx_loopback_self_tests *lb_tests)
+static int efx_poll_loopback(struct efx_nic *efx)
+{
+	struct efx_loopback_state *state = efx->loopback_selftest;
+	struct efx_channel *channel;
+
+	/* NAPI polling is not enabled, so process channels
+	 * synchronously */
+	efx_for_each_channel(channel, efx) {
+		if (channel->work_pending)
+			efx_process_channel_now(channel);
+	}
+	return atomic_read(&state->rx_good) == state->packet_count;
+}
+
+static int efx_end_loopback(struct efx_tx_queue *tx_queue,
+			    struct efx_loopback_self_tests *lb_tests)
 {
 	struct efx_nic *efx = tx_queue->efx;
-	struct efx_selftest_state *state = efx->loopback_selftest;
+	struct efx_loopback_state *state = efx->loopback_selftest;
 	struct sk_buff *skb;
 	int tx_done = 0, rx_good, rx_bad;
 	int i, rc = 0;
@@ -507,11 +517,10 @@
 		  struct efx_loopback_self_tests *lb_tests)
 {
 	struct efx_nic *efx = tx_queue->efx;
-	struct efx_selftest_state *state = efx->loopback_selftest;
-	struct efx_channel *channel;
-	int i, rc = 0;
+	struct efx_loopback_state *state = efx->loopback_selftest;
+	int i, begin_rc, end_rc;
 
-	for (i = 0; i < loopback_test_level; i++) {
+	for (i = 0; i < 3; i++) {
 		/* Determine how many packets to send */
 		state->packet_count = (efx->type->txd_ring_mask + 1) / 3;
 		state->packet_count = min(1 << (i << 2), state->packet_count);
@@ -519,30 +528,31 @@
 				      state->packet_count, GFP_KERNEL);
 		if (!state->skbs)
 			return -ENOMEM;
-		state->flush = 0;
+		state->flush = false;
 
 		EFX_LOG(efx, "TX queue %d testing %s loopback with %d "
 			"packets\n", tx_queue->queue, LOOPBACK_MODE(efx),
 			state->packet_count);
 
 		efx_iterate_state(efx);
-		rc = efx_tx_loopback(tx_queue);
-		
-		/* NAPI polling is not enabled, so process channels synchronously */
-		schedule_timeout_uninterruptible(HZ / 50);
-		efx_for_each_channel_with_interrupt(channel, efx) {
-			if (channel->work_pending)
-				efx_process_channel_now(channel);
+		begin_rc = efx_begin_loopback(tx_queue);
+
+		/* This will normally complete very quickly, but be
+		 * prepared to wait up to 100 ms. */
+		msleep(1);
+		if (!efx_poll_loopback(efx)) {
+			msleep(100);
+			efx_poll_loopback(efx);
 		}
 
-		rc |= efx_rx_loopback(tx_queue, lb_tests);
+		end_rc = efx_end_loopback(tx_queue, lb_tests);
 		kfree(state->skbs);
 
-		if (rc) {
+		if (begin_rc || end_rc) {
 			/* Wait a while to ensure there are no packets
 			 * floating around after a failure. */
 			schedule_timeout_uninterruptible(HZ / 10);
-			return rc;
+			return begin_rc ? begin_rc : end_rc;
 		}
 	}
 
@@ -550,49 +560,36 @@
 		"of %d packets\n", tx_queue->queue, LOOPBACK_MODE(efx),
 		state->packet_count);
 
-	return rc;
+	return 0;
 }
 
-static int efx_test_loopbacks(struct efx_nic *efx,
+static int efx_test_loopbacks(struct efx_nic *efx, struct ethtool_cmd ecmd,
 			      struct efx_self_tests *tests,
 			      unsigned int loopback_modes)
 {
-	struct efx_selftest_state *state = efx->loopback_selftest;
-	struct ethtool_cmd ecmd, ecmd_loopback;
+	enum efx_loopback_mode mode;
+	struct efx_loopback_state *state;
 	struct efx_tx_queue *tx_queue;
-	enum efx_loopback_mode old_mode, mode;
-	int count, rc = 0, link_up;
-	
-	rc = efx_ethtool_get_settings(efx->net_dev, &ecmd);
-	if (rc) {
-		EFX_ERR(efx, "could not get GMII settings\n");
-		return rc;
-	}
-	old_mode = efx->loopback_mode;
+	bool link_up;
+	int count, rc = 0;
 
-	/* Disable autonegotiation for the purposes of loopback */
-	memcpy(&ecmd_loopback, &ecmd, sizeof(ecmd_loopback));
-	if (ecmd_loopback.autoneg == AUTONEG_ENABLE) {
-		ecmd_loopback.autoneg = AUTONEG_DISABLE;
-		ecmd_loopback.duplex = DUPLEX_FULL;
-		ecmd_loopback.speed = SPEED_10000;
-	}
-
-	rc = efx_ethtool_set_settings(efx->net_dev, &ecmd_loopback);
-	if (rc) {
-		EFX_ERR(efx, "could not disable autonegotiation\n");
-		goto out;
-	}
-	tests->loopback_speed = ecmd_loopback.speed;
-	tests->loopback_full_duplex = ecmd_loopback.duplex;
+	/* Set the port loopback_selftest member. From this point on
+	 * all received packets will be dropped. Mark the state as
+	 * "flushing" so all inflight packets are dropped */
+	state = kzalloc(sizeof(*state), GFP_KERNEL);
+	if (state == NULL)
+		return -ENOMEM;
+	BUG_ON(efx->loopback_selftest);
+	state->flush = true;
+	efx->loopback_selftest = state;
 
 	/* Test all supported loopback modes */
-	for (mode = LOOPBACK_NONE; mode < LOOPBACK_TEST_MAX; mode++) {
+	for (mode = LOOPBACK_NONE; mode <= LOOPBACK_TEST_MAX; mode++) {
 		if (!(loopback_modes & (1 << mode)))
 			continue;
 
 		/* Move the port into the specified loopback mode. */
-		state->flush = 1;
+		state->flush = true;
 		efx->loopback_mode = mode;
 		efx_reconfigure_port(efx);
 
@@ -616,7 +613,7 @@
 			 */
 			link_up = efx->link_up;
 			if (!falcon_xaui_link_ok(efx))
-				link_up = 0;
+				link_up = false;
 
 		} while ((++count < 20) && !link_up);
 
@@ -634,18 +631,21 @@
 
 		/* Test every TX queue */
 		efx_for_each_tx_queue(tx_queue, efx) {
-			rc |= efx_test_loopback(tx_queue,
-						&tests->loopback[mode]);
+			state->offload_csum = (tx_queue->queue ==
+					       EFX_TX_QUEUE_OFFLOAD_CSUM);
+			rc = efx_test_loopback(tx_queue,
+					       &tests->loopback[mode]);
 			if (rc)
 				goto out;
 		}
 	}
 
  out:
-	/* Take out of loopback and restore PHY settings */
-	state->flush = 1;
-	efx->loopback_mode = old_mode;
-	efx_ethtool_set_settings(efx->net_dev, &ecmd);
+	/* Remove the flush. The caller will remove the loopback setting */
+	state->flush = true;
+	efx->loopback_selftest = NULL;
+	wmb();
+	kfree(state);
 
 	return rc;
 }
@@ -661,23 +661,27 @@
 int efx_online_test(struct efx_nic *efx, struct efx_self_tests *tests)
 {
 	struct efx_channel *channel;
-	int rc = 0;
+	int rc, rc2 = 0;
 
-	EFX_LOG(efx, "performing online self-tests\n");
+	rc = efx_test_mii(efx, tests);
+	if (rc && !rc2)
+		rc2 = rc;
 
-	rc |= efx_test_interrupts(efx, tests);
+	rc = efx_test_nvram(efx, tests);
+	if (rc && !rc2)
+		rc2 = rc;
+
+	rc = efx_test_interrupts(efx, tests);
+	if (rc && !rc2)
+		rc2 = rc;
+
 	efx_for_each_channel(channel, efx) {
-		if (channel->has_interrupt)
-			rc |= efx_test_eventq_irq(channel, tests);
-		else
-			rc |= efx_test_eventq(channel, tests);
+		rc = efx_test_eventq_irq(channel, tests);
+		if (rc && !rc2)
+			rc2 = rc;
 	}
-	rc |= efx_test_phy(efx, tests);
 
-	if (rc)
-		EFX_ERR(efx, "failed online self-tests\n");
-
-	return rc;
+	return rc2;
 }
 
 /* Offline (i.e. disruptive) testing
@@ -685,35 +689,66 @@
 int efx_offline_test(struct efx_nic *efx,
 		     struct efx_self_tests *tests, unsigned int loopback_modes)
 {
-	struct efx_selftest_state *state;
-	int rc = 0;
+	enum efx_loopback_mode loopback_mode = efx->loopback_mode;
+	int phy_mode = efx->phy_mode;
+	struct ethtool_cmd ecmd, ecmd_test;
+	int rc, rc2 = 0;
 
-	EFX_LOG(efx, "performing offline self-tests\n");
+	/* force the carrier state off so the kernel doesn't transmit during
+	 * the loopback test, and the watchdog timeout doesn't fire. Also put
+	 * falcon into loopback for the register test.
+	 */
+	mutex_lock(&efx->mac_lock);
+	efx->port_inhibited = true;
+	if (efx->loopback_modes)
+		efx->loopback_mode = __ffs(efx->loopback_modes);
+	__efx_reconfigure_port(efx);
+	mutex_unlock(&efx->mac_lock);
 
-	/* Create a selftest_state structure to hold state for the test */
-	state = kzalloc(sizeof(*state), GFP_KERNEL);
-	if (state == NULL) {
-		rc = -ENOMEM;
-		goto out;
+	/* free up all consumers of SRAM (including all the queues) */
+	efx_reset_down(efx, &ecmd);
+
+	rc = efx_test_chip(efx, tests);
+	if (rc && !rc2)
+		rc2 = rc;
+
+	/* reset the chip to recover from the register test */
+	rc = falcon_reset_hw(efx, RESET_TYPE_ALL);
+
+	/* Modify the saved ecmd so that when efx_reset_up() restores the phy
+	 * state, AN is disabled, and the phy is powered, and out of loopback */
+	memcpy(&ecmd_test, &ecmd, sizeof(ecmd_test));
+	if (ecmd_test.autoneg == AUTONEG_ENABLE) {
+		ecmd_test.autoneg = AUTONEG_DISABLE;
+		ecmd_test.duplex = DUPLEX_FULL;
+		ecmd_test.speed = SPEED_10000;
+	}
+	efx->loopback_mode = LOOPBACK_NONE;
+
+	rc = efx_reset_up(efx, &ecmd_test, rc == 0);
+	if (rc) {
+		EFX_ERR(efx, "Unable to recover from chip test\n");
+		efx_schedule_reset(efx, RESET_TYPE_DISABLE);
+		return rc;
 	}
 
-	/* Set the port loopback_selftest member. From this point on
-	 * all received packets will be dropped. Mark the state as
-	 * "flushing" so all inflight packets are dropped */
-	BUG_ON(efx->loopback_selftest);
-	state->flush = 1;
-	efx->loopback_selftest = state;
+	tests->loopback_speed = ecmd_test.speed;
+	tests->loopback_full_duplex = ecmd_test.duplex;
 
-	rc = efx_test_loopbacks(efx, tests, loopback_modes);
+	rc = efx_test_phy(efx, tests);
+	if (rc && !rc2)
+		rc2 = rc;
 
-	efx->loopback_selftest = NULL;
-	wmb();
-	kfree(state);
+	rc = efx_test_loopbacks(efx, ecmd_test, tests, loopback_modes);
+	if (rc && !rc2)
+		rc2 = rc;
 
- out:
-	if (rc)
-		EFX_ERR(efx, "failed offline self-tests\n");
+	/* restore the PHY to the previous state */
+	efx->loopback_mode = loopback_mode;
+	efx->phy_mode = phy_mode;
+	efx->port_inhibited = false;
+	efx_ethtool_set_settings(efx->net_dev, &ecmd);
 
-	return rc;
+	return rc2;
 }
 
diff --git a/drivers/net/sfc/selftest.h b/drivers/net/sfc/selftest.h
index f6999c2..fc15df1 100644
--- a/drivers/net/sfc/selftest.h
+++ b/drivers/net/sfc/selftest.h
@@ -18,8 +18,8 @@
  */
 
 struct efx_loopback_self_tests {
-	int tx_sent[EFX_MAX_TX_QUEUES];
-	int tx_done[EFX_MAX_TX_QUEUES];
+	int tx_sent[EFX_TX_QUEUE_COUNT];
+	int tx_done[EFX_TX_QUEUE_COUNT];
 	int rx_good;
 	int rx_bad;
 };
@@ -29,14 +29,19 @@
  * indicates failure.
  */
 struct efx_self_tests {
+	/* online tests */
+	int mii;
+	int nvram;
 	int interrupt;
 	int eventq_dma[EFX_MAX_CHANNELS];
 	int eventq_int[EFX_MAX_CHANNELS];
 	int eventq_poll[EFX_MAX_CHANNELS];
-	int phy_ok;
+	/* offline tests */
+	int registers;
+	int phy;
 	int loopback_speed;
 	int loopback_full_duplex;
-	struct efx_loopback_self_tests loopback[LOOPBACK_TEST_MAX];
+	struct efx_loopback_self_tests loopback[LOOPBACK_TEST_MAX + 1];
 };
 
 extern void efx_loopback_rx_packet(struct efx_nic *efx,
diff --git a/drivers/net/sfc/sfe4001.c b/drivers/net/sfc/sfe4001.c
index b278495..fe4e3fd 100644
--- a/drivers/net/sfc/sfe4001.c
+++ b/drivers/net/sfc/sfe4001.c
@@ -13,11 +13,13 @@
  * the PHY
  */
 #include <linux/delay.h>
+#include "net_driver.h"
 #include "efx.h"
 #include "phy.h"
 #include "boards.h"
 #include "falcon.h"
 #include "falcon_hwdefs.h"
+#include "falcon_io.h"
 #include "mac.h"
 
 /**************************************************************************
@@ -120,65 +122,159 @@
 	i2c_smbus_read_byte_data(hwmon_client, RSL);
 }
 
+static int sfe4001_poweron(struct efx_nic *efx)
+{
+	struct i2c_client *hwmon_client = efx->board_info.hwmon_client;
+	struct i2c_client *ioexp_client = efx->board_info.ioexp_client;
+	unsigned int i, j;
+	int rc;
+	u8 out;
+
+	/* Clear any previous over-temperature alert */
+	rc = i2c_smbus_read_byte_data(hwmon_client, RSL);
+	if (rc < 0)
+		return rc;
+
+	/* Enable port 0 and port 1 outputs on IO expander */
+	rc = i2c_smbus_write_byte_data(ioexp_client, P0_CONFIG, 0x00);
+	if (rc)
+		return rc;
+	rc = i2c_smbus_write_byte_data(ioexp_client, P1_CONFIG,
+				       0xff & ~(1 << P1_SPARE_LBN));
+	if (rc)
+		goto fail_on;
+
+	/* If PHY power is on, turn it all off and wait 1 second to
+	 * ensure a full reset.
+	 */
+	rc = i2c_smbus_read_byte_data(ioexp_client, P0_OUT);
+	if (rc < 0)
+		goto fail_on;
+	out = 0xff & ~((0 << P0_EN_1V2_LBN) | (0 << P0_EN_2V5_LBN) |
+		       (0 << P0_EN_3V3X_LBN) | (0 << P0_EN_5V_LBN) |
+		       (0 << P0_EN_1V0X_LBN));
+	if (rc != out) {
+		EFX_INFO(efx, "power-cycling PHY\n");
+		rc = i2c_smbus_write_byte_data(ioexp_client, P0_OUT, out);
+		if (rc)
+			goto fail_on;
+		schedule_timeout_uninterruptible(HZ);
+	}
+
+	for (i = 0; i < 20; ++i) {
+		/* Turn on 1.2V, 2.5V, 3.3V and 5V power rails */
+		out = 0xff & ~((1 << P0_EN_1V2_LBN) | (1 << P0_EN_2V5_LBN) |
+			       (1 << P0_EN_3V3X_LBN) | (1 << P0_EN_5V_LBN) |
+			       (1 << P0_X_TRST_LBN));
+		if (efx->phy_mode & PHY_MODE_SPECIAL)
+			out |= 1 << P0_EN_3V3X_LBN;
+
+		rc = i2c_smbus_write_byte_data(ioexp_client, P0_OUT, out);
+		if (rc)
+			goto fail_on;
+		msleep(10);
+
+		/* Turn on 1V power rail */
+		out &= ~(1 << P0_EN_1V0X_LBN);
+		rc = i2c_smbus_write_byte_data(ioexp_client, P0_OUT, out);
+		if (rc)
+			goto fail_on;
+
+		EFX_INFO(efx, "waiting for DSP boot (attempt %d)...\n", i);
+
+		/* In flash config mode, DSP does not turn on AFE, so
+		 * just wait 1 second.
+		 */
+		if (efx->phy_mode & PHY_MODE_SPECIAL) {
+			schedule_timeout_uninterruptible(HZ);
+			return 0;
+		}
+
+		for (j = 0; j < 10; ++j) {
+			msleep(100);
+
+			/* Check DSP has asserted AFE power line */
+			rc = i2c_smbus_read_byte_data(ioexp_client, P1_IN);
+			if (rc < 0)
+				goto fail_on;
+			if (rc & (1 << P1_AFE_PWD_LBN))
+				return 0;
+		}
+	}
+
+	EFX_INFO(efx, "timed out waiting for DSP boot\n");
+	rc = -ETIMEDOUT;
+fail_on:
+	sfe4001_poweroff(efx);
+	return rc;
+}
+
+/* On SFE4001 rev A2 and later, we can control the FLASH_CFG_1 pin
+ * using the 3V3X output of the IO-expander.  Allow the user to set
+ * this when the device is stopped, and keep it stopped then.
+ */
+
+static ssize_t show_phy_flash_cfg(struct device *dev,
+				  struct device_attribute *attr, char *buf)
+{
+	struct efx_nic *efx = pci_get_drvdata(to_pci_dev(dev));
+	return sprintf(buf, "%d\n", !!(efx->phy_mode & PHY_MODE_SPECIAL));
+}
+
+static ssize_t set_phy_flash_cfg(struct device *dev,
+				 struct device_attribute *attr,
+				 const char *buf, size_t count)
+{
+	struct efx_nic *efx = pci_get_drvdata(to_pci_dev(dev));
+	enum efx_phy_mode old_mode, new_mode;
+	int err;
+
+	rtnl_lock();
+	old_mode = efx->phy_mode;
+	if (count == 0 || *buf == '0')
+		new_mode = old_mode & ~PHY_MODE_SPECIAL;
+	else
+		new_mode = PHY_MODE_SPECIAL;
+	if (old_mode == new_mode) {
+		err = 0;
+	} else if (efx->state != STATE_RUNNING || netif_running(efx->net_dev)) {
+		err = -EBUSY;
+	} else {
+		efx->phy_mode = new_mode;
+		err = sfe4001_poweron(efx);
+		efx_reconfigure_port(efx);
+	}
+	rtnl_unlock();
+
+	return err ? err : count;
+}
+
+static DEVICE_ATTR(phy_flash_cfg, 0644, show_phy_flash_cfg, set_phy_flash_cfg);
+
 static void sfe4001_fini(struct efx_nic *efx)
 {
 	EFX_INFO(efx, "%s\n", __func__);
 
+	device_remove_file(&efx->pci_dev->dev, &dev_attr_phy_flash_cfg);
 	sfe4001_poweroff(efx);
- 	i2c_unregister_device(efx->board_info.ioexp_client);
- 	i2c_unregister_device(efx->board_info.hwmon_client);
+	i2c_unregister_device(efx->board_info.ioexp_client);
+	i2c_unregister_device(efx->board_info.hwmon_client);
 }
 
-/* The P0_EN_3V3X line on SFE4001 boards (from A2 onward) is connected
- * to the FLASH_CFG_1 input on the DSP.  We must keep it high at power-
- * up to allow writing the flash (done through MDIO from userland).
- */
-unsigned int sfe4001_phy_flash_cfg;
-module_param_named(phy_flash_cfg, sfe4001_phy_flash_cfg, uint, 0444);
-MODULE_PARM_DESC(phy_flash_cfg,
-		 "Force PHY to enter flash configuration mode");
-
 /* This board uses an I2C expander to provider power to the PHY, which needs to
  * be turned on before the PHY can be used.
  * Context: Process context, rtnl lock held
  */
 int sfe4001_init(struct efx_nic *efx)
 {
-	struct i2c_client *hwmon_client, *ioexp_client;
-	unsigned int count;
+	struct i2c_client *hwmon_client;
 	int rc;
-	u8 out;
-	efx_dword_t reg;
 
 	hwmon_client = i2c_new_dummy(&efx->i2c_adap, MAX6647);
 	if (!hwmon_client)
 		return -EIO;
 	efx->board_info.hwmon_client = hwmon_client;
 
-	ioexp_client = i2c_new_dummy(&efx->i2c_adap, PCA9539);
-	if (!ioexp_client) {
-		rc = -EIO;
-		goto fail_hwmon;
-	}
-	efx->board_info.ioexp_client = ioexp_client;
-
-	/* 10Xpress has fixed-function LED pins, so there is no board-specific
-	 * blink code. */
-	efx->board_info.blink = tenxpress_phy_blink;
-
-	/* Ensure that XGXS and XAUI SerDes are held in reset */
-	EFX_POPULATE_DWORD_7(reg, XX_PWRDNA_EN, 1,
-			     XX_PWRDNB_EN, 1,
-			     XX_RSTPLLAB_EN, 1,
-			     XX_RESETA_EN, 1,
-			     XX_RESETB_EN, 1,
-			     XX_RSTXGXSRX_EN, 1,
-			     XX_RSTXGXSTX_EN, 1);
-	falcon_xmac_writel(efx, &reg, XX_PWR_RST_REG_MAC);
-	udelay(10);
-
-	efx->board_info.fini = sfe4001_fini;
-
 	/* Set DSP over-temperature alert threshold */
 	EFX_INFO(efx, "DSP cut-out at %dC\n", xgphy_max_temperature);
 	rc = i2c_smbus_write_byte_data(hwmon_client, WLHO,
@@ -195,78 +291,34 @@
 		goto fail_ioexp;
 	}
 
-	/* Clear any previous over-temperature alert */
-	rc = i2c_smbus_read_byte_data(hwmon_client, RSL);
-	if (rc < 0)
-		goto fail_ioexp;
+	efx->board_info.ioexp_client = i2c_new_dummy(&efx->i2c_adap, PCA9539);
+	if (!efx->board_info.ioexp_client) {
+		rc = -EIO;
+		goto fail_hwmon;
+	}
 
-	/* Enable port 0 and port 1 outputs on IO expander */
-	rc = i2c_smbus_write_byte_data(ioexp_client, P0_CONFIG, 0x00);
+	/* 10Xpress has fixed-function LED pins, so there is no board-specific
+	 * blink code. */
+	efx->board_info.blink = tenxpress_phy_blink;
+
+	efx->board_info.fini = sfe4001_fini;
+
+	rc = sfe4001_poweron(efx);
 	if (rc)
 		goto fail_ioexp;
-	rc = i2c_smbus_write_byte_data(ioexp_client, P1_CONFIG,
-				       0xff & ~(1 << P1_SPARE_LBN));
+
+	rc = device_create_file(&efx->pci_dev->dev, &dev_attr_phy_flash_cfg);
 	if (rc)
 		goto fail_on;
 
-	/* Turn all power off then wait 1 sec. This ensures PHY is reset */
-	out = 0xff & ~((0 << P0_EN_1V2_LBN) | (0 << P0_EN_2V5_LBN) |
-		       (0 << P0_EN_3V3X_LBN) | (0 << P0_EN_5V_LBN) |
-		       (0 << P0_EN_1V0X_LBN));
-	rc = i2c_smbus_write_byte_data(ioexp_client, P0_OUT, out);
-	if (rc)
-		goto fail_on;
-
-	schedule_timeout_uninterruptible(HZ);
-	count = 0;
-	do {
-		/* Turn on 1.2V, 2.5V, 3.3V and 5V power rails */
-		out = 0xff & ~((1 << P0_EN_1V2_LBN) | (1 << P0_EN_2V5_LBN) |
-			       (1 << P0_EN_3V3X_LBN) | (1 << P0_EN_5V_LBN) |
-			       (1 << P0_X_TRST_LBN));
-		if (sfe4001_phy_flash_cfg)
-			out |= 1 << P0_EN_3V3X_LBN;
-
-		rc = i2c_smbus_write_byte_data(ioexp_client, P0_OUT, out);
-		if (rc)
-			goto fail_on;
-		msleep(10);
-
-		/* Turn on 1V power rail */
-		out &= ~(1 << P0_EN_1V0X_LBN);
-		rc = i2c_smbus_write_byte_data(ioexp_client, P0_OUT, out);
-		if (rc)
-			goto fail_on;
-
-		EFX_INFO(efx, "waiting for power (attempt %d)...\n", count);
-
-		schedule_timeout_uninterruptible(HZ);
-
-		/* Check DSP is powered */
-		rc = i2c_smbus_read_byte_data(ioexp_client, P1_IN);
-		if (rc < 0)
-			goto fail_on;
-		if (rc & (1 << P1_AFE_PWD_LBN))
-			goto done;
-
-		/* DSP doesn't look powered in flash config mode */
-		if (sfe4001_phy_flash_cfg)
-			goto done;
-	} while (++count < 20);
-
-	EFX_INFO(efx, "timed out waiting for power\n");
-	rc = -ETIMEDOUT;
-	goto fail_on;
-
-done:
 	EFX_INFO(efx, "PHY is powered on\n");
 	return 0;
 
 fail_on:
 	sfe4001_poweroff(efx);
 fail_ioexp:
- 	i2c_unregister_device(ioexp_client);
+	i2c_unregister_device(efx->board_info.ioexp_client);
 fail_hwmon:
- 	i2c_unregister_device(hwmon_client);
+	i2c_unregister_device(hwmon_client);
 	return rc;
 }
diff --git a/drivers/net/sfc/spi.h b/drivers/net/sfc/spi.h
index 34412f3..feef619 100644
--- a/drivers/net/sfc/spi.h
+++ b/drivers/net/sfc/spi.h
@@ -19,53 +19,48 @@
  *
  *************************************************************************/
 
-/*
- * Commands common to all known devices.
- *
+#define SPI_WRSR 0x01		/* Write status register */
+#define SPI_WRITE 0x02		/* Write data to memory array */
+#define SPI_READ 0x03		/* Read data from memory array */
+#define SPI_WRDI 0x04		/* Reset write enable latch */
+#define SPI_RDSR 0x05		/* Read status register */
+#define SPI_WREN 0x06		/* Set write enable latch */
+
+#define SPI_STATUS_WPEN 0x80	/* Write-protect pin enabled */
+#define SPI_STATUS_BP2 0x10	/* Block protection bit 2 */
+#define SPI_STATUS_BP1 0x08	/* Block protection bit 1 */
+#define SPI_STATUS_BP0 0x04	/* Block protection bit 0 */
+#define SPI_STATUS_WEN 0x02	/* State of the write enable latch */
+#define SPI_STATUS_NRDY 0x01	/* Device busy flag */
+
+/**
+ * struct efx_spi_device - an Efx SPI (Serial Peripheral Interface) device
+ * @efx:		The Efx controller that owns this device
+ * @device_id:		Controller's id for the device
+ * @size:		Size (in bytes)
+ * @addr_len:		Number of address bytes in read/write commands
+ * @munge_address:	Flag whether addresses should be munged.
+ *	Some devices with 9-bit addresses (e.g. AT25040A EEPROM)
+ *	use bit 3 of the command byte as address bit A8, rather
+ *	than having a two-byte address.  If this flag is set, then
+ *	commands should be munged in this way.
+ * @block_size:		Write block size (in bytes).
+ *	Write commands are limited to blocks with this size and alignment.
+ * @read:		Read function for the device
+ * @write:		Write function for the device
  */
+struct efx_spi_device {
+	struct efx_nic *efx;
+	int device_id;
+	unsigned int size;
+	unsigned int addr_len;
+	unsigned int munge_address:1;
+	unsigned int block_size;
+};
 
-/* Write status register */
-#define SPI_WRSR 0x01
-
-/* Write data to memory array */
-#define SPI_WRITE 0x02
-
-/* Read data from memory array */
-#define SPI_READ 0x03
-
-/* Reset write enable latch */
-#define SPI_WRDI 0x04
-
-/* Read status register */
-#define SPI_RDSR 0x05
-
-/* Set write enable latch */
-#define SPI_WREN 0x06
-
-/* SST: Enable write to status register */
-#define SPI_SST_EWSR 0x50
-
-/*
- * Status register bits.  Not all bits are supported on all devices.
- *
- */
-
-/* Write-protect pin enabled */
-#define SPI_STATUS_WPEN 0x80
-
-/* Block protection bit 2 */
-#define SPI_STATUS_BP2 0x10
-
-/* Block protection bit 1 */
-#define SPI_STATUS_BP1 0x08
-
-/* Block protection bit 0 */
-#define SPI_STATUS_BP0 0x04
-
-/* State of the write enable latch */
-#define SPI_STATUS_WEN 0x02
-
-/* Device busy flag */
-#define SPI_STATUS_NRDY 0x01
+int falcon_spi_read(const struct efx_spi_device *spi, loff_t start,
+		    size_t len, size_t *retlen, u8 *buffer);
+int falcon_spi_write(const struct efx_spi_device *spi, loff_t start,
+		     size_t len, size_t *retlen, const u8 *buffer);
 
 #endif /* EFX_SPI_H */
diff --git a/drivers/net/sfc/tenxpress.c b/drivers/net/sfc/tenxpress.c
index c014606..d507c93 100644
--- a/drivers/net/sfc/tenxpress.c
+++ b/drivers/net/sfc/tenxpress.c
@@ -65,25 +65,10 @@
 #define PMA_PMD_LED_DEFAULT	(PMA_PMD_LED_OFF << PMA_PMD_LED_RX_LBN)
 
 
-/* Self test (BIST) control register */
-#define PMA_PMD_BIST_CTRL_REG	(0xc014)
-#define PMA_PMD_BIST_BER_LBN	(2)	/* Run BER test */
-#define PMA_PMD_BIST_CONT_LBN	(1)	/* Run continuous BIST until cleared */
-#define PMA_PMD_BIST_SINGLE_LBN	(0)	/* Run 1 BIST iteration (self clears) */
-/* Self test status register */
-#define PMA_PMD_BIST_STAT_REG	(0xc015)
-#define PMA_PMD_BIST_ENX_LBN	(3)
-#define PMA_PMD_BIST_PMA_LBN	(2)
-#define PMA_PMD_BIST_RXD_LBN	(1)
-#define PMA_PMD_BIST_AFE_LBN	(0)
-
 /* Special Software reset register */
 #define PMA_PMD_EXT_CTRL_REG 49152
 #define PMA_PMD_EXT_SSR_LBN 15
 
-#define BIST_MAX_DELAY	(1000)
-#define BIST_POLL_DELAY	(10)
-
 /* Misc register defines */
 #define PCS_CLOCK_CTRL_REG 0xd801
 #define PLL312_RST_N_LBN 2
@@ -119,27 +104,12 @@
 		 "Max number of CRC errors before XAUI reset");
 
 struct tenxpress_phy_data {
-	enum tenxpress_state state;
 	enum efx_loopback_mode loopback_mode;
 	atomic_t bad_crc_count;
-	int tx_disabled;
+	enum efx_phy_mode phy_mode;
 	int bad_lp_tries;
 };
 
-static int tenxpress_state_is(struct efx_nic *efx, int state)
-{
-	struct tenxpress_phy_data *phy_data = efx->phy_data;
-	return (phy_data != NULL) && (state == phy_data->state);
-}
-
-void tenxpress_set_state(struct efx_nic *efx,
-				enum tenxpress_state state)
-{
-	struct tenxpress_phy_data *phy_data = efx->phy_data;
-	if (phy_data != NULL)
-		phy_data->state = state;
-}
-
 void tenxpress_crc_err(struct efx_nic *efx)
 {
 	struct tenxpress_phy_data *phy_data = efx->phy_data;
@@ -176,8 +146,6 @@
 	return 0;
 }
 
-static void tenxpress_reset_xaui(struct efx_nic *efx);
-
 static int tenxpress_init(struct efx_nic *efx)
 {
 	int rc, reg;
@@ -214,15 +182,12 @@
 	if (!phy_data)
 		return -ENOMEM;
 	efx->phy_data = phy_data;
+	phy_data->phy_mode = efx->phy_mode;
 
-	tenxpress_set_state(efx, TENXPRESS_STATUS_NORMAL);
-
-	if (!sfe4001_phy_flash_cfg) {
-		rc = mdio_clause45_wait_reset_mmds(efx,
-						   TENXPRESS_REQUIRED_DEVS);
-		if (rc < 0)
-			goto fail;
-	}
+	rc = mdio_clause45_wait_reset_mmds(efx,
+					   TENXPRESS_REQUIRED_DEVS);
+	if (rc < 0)
+		goto fail;
 
 	rc = mdio_clause45_check_mmds(efx, TENXPRESS_REQUIRED_DEVS, 0);
 	if (rc < 0)
@@ -249,7 +214,10 @@
 {
 	int rc, reg;
 
-	EFX_TRACE(efx, "%s\n", __func__);
+	/* The XGMAC clock is driven from the SFC7101/SFT9001 312MHz clock, so
+	 * a special software reset can glitch the XGMAC sufficiently for stats
+	 * requests to fail. Since we don't ofen special_reset, just lock. */
+	spin_lock(&efx->stats_lock);
 
 	/* Initiate reset */
 	reg = mdio_clause45_read(efx, efx->mii.phy_id,
@@ -258,23 +226,25 @@
 	mdio_clause45_write(efx, efx->mii.phy_id, MDIO_MMD_PMAPMD,
 			    PMA_PMD_EXT_CTRL_REG, reg);
 
-	msleep(200);
+	mdelay(200);
 
 	/* Wait for the blocks to come out of reset */
 	rc = mdio_clause45_wait_reset_mmds(efx,
 					   TENXPRESS_REQUIRED_DEVS);
 	if (rc < 0)
-		return rc;
+		goto unlock;
 
 	/* Try and reconfigure the device */
 	rc = tenxpress_init(efx);
 	if (rc < 0)
-		return rc;
+		goto unlock;
 
-	return 0;
+unlock:
+	spin_unlock(&efx->stats_lock);
+	return rc;
 }
 
-static void tenxpress_set_bad_lp(struct efx_nic *efx, int bad_lp)
+static void tenxpress_set_bad_lp(struct efx_nic *efx, bool bad_lp)
 {
 	struct tenxpress_phy_data *pd = efx->phy_data;
 	int reg;
@@ -311,15 +281,15 @@
  * into a non-10GBT port and if so warn the user that they won't get
  * link any time soon as we are 10GBT only, unless caller specified
  * not to do this check (it isn't useful in loopback) */
-static int tenxpress_link_ok(struct efx_nic *efx, int check_lp)
+static bool tenxpress_link_ok(struct efx_nic *efx, bool check_lp)
 {
-	int ok = mdio_clause45_links_ok(efx, TENXPRESS_REQUIRED_DEVS);
+	bool ok = mdio_clause45_links_ok(efx, TENXPRESS_REQUIRED_DEVS);
 
 	if (ok) {
-		tenxpress_set_bad_lp(efx, 0);
+		tenxpress_set_bad_lp(efx, false);
 	} else if (check_lp) {
 		/* Are we plugged into the wrong sort of link? */
-		int bad_lp = 0;
+		bool bad_lp = false;
 		int phy_id = efx->mii.phy_id;
 		int an_stat = mdio_clause45_read(efx, phy_id, MDIO_MMD_AN,
 						 MDIO_AN_STATUS);
@@ -332,7 +302,7 @@
 		 * bit has the advantage of not clearing when autoneg
 		 * restarts. */
 		if (!(xphy_stat & (1 << PMA_PMD_XSTAT_FLP_LBN))) {
-			tenxpress_set_bad_lp(efx, 0);
+			tenxpress_set_bad_lp(efx, false);
 			return ok;
 		}
 
@@ -367,16 +337,19 @@
 static void tenxpress_phy_reconfigure(struct efx_nic *efx)
 {
 	struct tenxpress_phy_data *phy_data = efx->phy_data;
-	int loop_change = LOOPBACK_OUT_OF(phy_data, efx,
-					  TENXPRESS_LOOPBACKS);
+	bool loop_change = LOOPBACK_OUT_OF(phy_data, efx,
+					   TENXPRESS_LOOPBACKS);
 
-	if (!tenxpress_state_is(efx, TENXPRESS_STATUS_NORMAL))
+	if (efx->phy_mode & PHY_MODE_SPECIAL) {
+		phy_data->phy_mode = efx->phy_mode;
 		return;
+	}
 
 	/* When coming out of transmit disable, coming out of low power
 	 * mode, or moving out of any PHY internal loopback mode,
 	 * perform a special software reset */
-	if ((phy_data->tx_disabled && !efx->tx_disabled) ||
+	if ((efx->phy_mode == PHY_MODE_NORMAL &&
+	     phy_data->phy_mode != PHY_MODE_NORMAL) ||
 	    loop_change) {
 		tenxpress_special_reset(efx);
 		falcon_reset_xaui(efx);
@@ -386,9 +359,9 @@
 	mdio_clause45_phy_reconfigure(efx);
 	tenxpress_phyxs_loopback(efx);
 
-	phy_data->tx_disabled = efx->tx_disabled;
 	phy_data->loopback_mode = efx->loopback_mode;
-	efx->link_up = tenxpress_link_ok(efx, 0);
+	phy_data->phy_mode = efx->phy_mode;
+	efx->link_up = tenxpress_link_ok(efx, false);
 	efx->link_options = GM_LPA_10000FULL;
 }
 
@@ -402,16 +375,14 @@
 static int tenxpress_phy_check_hw(struct efx_nic *efx)
 {
 	struct tenxpress_phy_data *phy_data = efx->phy_data;
-	int phy_up = tenxpress_state_is(efx, TENXPRESS_STATUS_NORMAL);
-	int link_ok;
+	bool link_ok;
 
-	link_ok = phy_up && tenxpress_link_ok(efx, 1);
+	link_ok = tenxpress_link_ok(efx, true);
 
 	if (link_ok != efx->link_up)
 		falcon_xmac_sim_phy_event(efx);
 
-	/* Nothing to check if we've already shut down the PHY */
-	if (!phy_up)
+	if (phy_data->phy_mode != PHY_MODE_NORMAL)
 		return 0;
 
 	if (atomic_read(&phy_data->bad_crc_count) > crc_error_reset_threshold) {
@@ -444,7 +415,7 @@
 
 /* Set the RX and TX LEDs and Link LED flashing. The other LEDs
  * (which probably aren't wired anyway) are left in AUTO mode */
-void tenxpress_phy_blink(struct efx_nic *efx, int blink)
+void tenxpress_phy_blink(struct efx_nic *efx, bool blink)
 {
 	int reg;
 
@@ -459,52 +430,10 @@
 			    PMA_PMD_LED_OVERR_REG, reg);
 }
 
-static void tenxpress_reset_xaui(struct efx_nic *efx)
+static int tenxpress_phy_test(struct efx_nic *efx)
 {
-	int phy = efx->mii.phy_id;
-	int clk_ctrl, test_select, soft_rst2;
-
-	/* Real work is done on clock_ctrl other resets are thought to be
-	 * optional but make the reset more reliable
-	 */
-
-	/* Read */
-	clk_ctrl = mdio_clause45_read(efx, phy, MDIO_MMD_PCS,
-				      PCS_CLOCK_CTRL_REG);
-	test_select = mdio_clause45_read(efx, phy, MDIO_MMD_PCS,
-					 PCS_TEST_SELECT_REG);
-	soft_rst2 = mdio_clause45_read(efx, phy, MDIO_MMD_PCS,
-				       PCS_SOFT_RST2_REG);
-
-	/* Put in reset */
-	test_select &= ~(1 << CLK312_EN_LBN);
-	mdio_clause45_write(efx, phy, MDIO_MMD_PCS,
-			    PCS_TEST_SELECT_REG, test_select);
-
-	soft_rst2 &= ~((1 << XGXS_RST_N_LBN) | (1 << SERDES_RST_N_LBN));
-	mdio_clause45_write(efx, phy, MDIO_MMD_PCS,
-			    PCS_SOFT_RST2_REG, soft_rst2);
-
-	clk_ctrl &= ~(1 << PLL312_RST_N_LBN);
-	mdio_clause45_write(efx, phy, MDIO_MMD_PCS,
-			    PCS_CLOCK_CTRL_REG, clk_ctrl);
-	udelay(10);
-
-	/* Remove reset */
-	clk_ctrl |= (1 << PLL312_RST_N_LBN);
-	mdio_clause45_write(efx, phy, MDIO_MMD_PCS,
-			    PCS_CLOCK_CTRL_REG, clk_ctrl);
-	udelay(10);
-
-	soft_rst2 |= ((1 << XGXS_RST_N_LBN) | (1 << SERDES_RST_N_LBN));
-	mdio_clause45_write(efx, phy, MDIO_MMD_PCS,
-			    PCS_SOFT_RST2_REG, soft_rst2);
-	udelay(10);
-
-	test_select |= (1 << CLK312_EN_LBN);
-	mdio_clause45_write(efx, phy, MDIO_MMD_PCS,
-			    PCS_TEST_SELECT_REG, test_select);
-	udelay(10);
+	/* BIST is automatically run after a special software reset */
+	return tenxpress_special_reset(efx);
 }
 
 struct efx_phy_operations falcon_tenxpress_phy_ops = {
@@ -513,7 +442,7 @@
 	.check_hw         = tenxpress_phy_check_hw,
 	.fini             = tenxpress_phy_fini,
 	.clear_interrupt  = tenxpress_phy_clear_interrupt,
-	.reset_xaui       = tenxpress_reset_xaui,
+	.test             = tenxpress_phy_test,
 	.mmds             = TENXPRESS_REQUIRED_DEVS,
 	.loopbacks        = TENXPRESS_LOOPBACKS,
 };
diff --git a/drivers/net/sfc/tx.c b/drivers/net/sfc/tx.c
index 5e8374a..da3e9ff 100644
--- a/drivers/net/sfc/tx.c
+++ b/drivers/net/sfc/tx.c
@@ -47,7 +47,7 @@
  * We want to be able to nest calls to netif_stop_queue(), since each
  * channel can have an individual stop on the queue.
  */
-inline void efx_wake_queue(struct efx_nic *efx)
+void efx_wake_queue(struct efx_nic *efx)
 {
 	local_bh_disable();
 	if (atomic_dec_and_lock(&efx->netif_stop_count,
@@ -59,19 +59,21 @@
 	local_bh_enable();
 }
 
-static inline void efx_dequeue_buffer(struct efx_tx_queue *tx_queue,
-				      struct efx_tx_buffer *buffer)
+static void efx_dequeue_buffer(struct efx_tx_queue *tx_queue,
+			       struct efx_tx_buffer *buffer)
 {
 	if (buffer->unmap_len) {
 		struct pci_dev *pci_dev = tx_queue->efx->pci_dev;
+		dma_addr_t unmap_addr = (buffer->dma_addr + buffer->len -
+					 buffer->unmap_len);
 		if (buffer->unmap_single)
-			pci_unmap_single(pci_dev, buffer->unmap_addr,
-					 buffer->unmap_len, PCI_DMA_TODEVICE);
+			pci_unmap_single(pci_dev, unmap_addr, buffer->unmap_len,
+					 PCI_DMA_TODEVICE);
 		else
-			pci_unmap_page(pci_dev, buffer->unmap_addr,
-				       buffer->unmap_len, PCI_DMA_TODEVICE);
+			pci_unmap_page(pci_dev, unmap_addr, buffer->unmap_len,
+				       PCI_DMA_TODEVICE);
 		buffer->unmap_len = 0;
-		buffer->unmap_single = 0;
+		buffer->unmap_single = false;
 	}
 
 	if (buffer->skb) {
@@ -103,13 +105,13 @@
 };
 
 static int efx_enqueue_skb_tso(struct efx_tx_queue *tx_queue,
-			       const struct sk_buff *skb);
+			       struct sk_buff *skb);
 static void efx_fini_tso(struct efx_tx_queue *tx_queue);
 static void efx_tsoh_heap_free(struct efx_tx_queue *tx_queue,
 			       struct efx_tso_header *tsoh);
 
-static inline void efx_tsoh_free(struct efx_tx_queue *tx_queue,
-				 struct efx_tx_buffer *buffer)
+static void efx_tsoh_free(struct efx_tx_queue *tx_queue,
+			  struct efx_tx_buffer *buffer)
 {
 	if (buffer->tsoh) {
 		if (likely(!buffer->tsoh->unmap_len)) {
@@ -136,8 +138,8 @@
  * Returns NETDEV_TX_OK or NETDEV_TX_BUSY
  * You must hold netif_tx_lock() to call this function.
  */
-static inline int efx_enqueue_skb(struct efx_tx_queue *tx_queue,
-				  const struct sk_buff *skb)
+static int efx_enqueue_skb(struct efx_tx_queue *tx_queue,
+			   struct sk_buff *skb)
 {
 	struct efx_nic *efx = tx_queue->efx;
 	struct pci_dev *pci_dev = efx->pci_dev;
@@ -148,7 +150,7 @@
 	unsigned int len, unmap_len = 0, fill_level, insert_ptr, misalign;
 	dma_addr_t dma_addr, unmap_addr = 0;
 	unsigned int dma_len;
-	unsigned unmap_single;
+	bool unmap_single;
 	int q_space, i = 0;
 	int rc = NETDEV_TX_OK;
 
@@ -167,7 +169,7 @@
 	 * since this is more efficient on machines with sparse
 	 * memory.
 	 */
-	unmap_single = 1;
+	unmap_single = true;
 	dma_addr = pci_map_single(pci_dev, skb->data, len, PCI_DMA_TODEVICE);
 
 	/* Process all fragments */
@@ -213,7 +215,7 @@
 			EFX_BUG_ON_PARANOID(buffer->tsoh);
 			EFX_BUG_ON_PARANOID(buffer->skb);
 			EFX_BUG_ON_PARANOID(buffer->len);
-			EFX_BUG_ON_PARANOID(buffer->continuation != 1);
+			EFX_BUG_ON_PARANOID(!buffer->continuation);
 			EFX_BUG_ON_PARANOID(buffer->unmap_len);
 
 			dma_len = (((~dma_addr) & efx->type->tx_dma_mask) + 1);
@@ -233,7 +235,6 @@
 		} while (len);
 
 		/* Transfer ownership of the unmapping to the final buffer */
-		buffer->unmap_addr = unmap_addr;
 		buffer->unmap_single = unmap_single;
 		buffer->unmap_len = unmap_len;
 		unmap_len = 0;
@@ -247,14 +248,14 @@
 		page_offset = fragment->page_offset;
 		i++;
 		/* Map for DMA */
-		unmap_single = 0;
+		unmap_single = false;
 		dma_addr = pci_map_page(pci_dev, page, page_offset, len,
 					PCI_DMA_TODEVICE);
 	}
 
 	/* Transfer ownership of the skb to the final buffer */
 	buffer->skb = skb;
-	buffer->continuation = 0;
+	buffer->continuation = false;
 
 	/* Pass off to hardware */
 	falcon_push_buffers(tx_queue);
@@ -287,9 +288,14 @@
 	}
 
 	/* Free the fragment we were mid-way through pushing */
-	if (unmap_len)
-		pci_unmap_page(pci_dev, unmap_addr, unmap_len,
-			       PCI_DMA_TODEVICE);
+	if (unmap_len) {
+		if (unmap_single)
+			pci_unmap_single(pci_dev, unmap_addr, unmap_len,
+					 PCI_DMA_TODEVICE);
+		else
+			pci_unmap_page(pci_dev, unmap_addr, unmap_len,
+				       PCI_DMA_TODEVICE);
+	}
 
 	return rc;
 }
@@ -299,8 +305,8 @@
  * This removes packets from the TX queue, up to and including the
  * specified index.
  */
-static inline void efx_dequeue_buffers(struct efx_tx_queue *tx_queue,
-				       unsigned int index)
+static void efx_dequeue_buffers(struct efx_tx_queue *tx_queue,
+				unsigned int index)
 {
 	struct efx_nic *efx = tx_queue->efx;
 	unsigned int stop_index, read_ptr;
@@ -320,7 +326,7 @@
 		}
 
 		efx_dequeue_buffer(tx_queue, buffer);
-		buffer->continuation = 1;
+		buffer->continuation = true;
 		buffer->len = 0;
 
 		++tx_queue->read_count;
@@ -367,8 +373,15 @@
  */
 int efx_hard_start_xmit(struct sk_buff *skb, struct net_device *net_dev)
 {
-	struct efx_nic *efx = net_dev->priv;
-	return efx_xmit(efx, &efx->tx_queue[0], skb);
+	struct efx_nic *efx = netdev_priv(net_dev);
+	struct efx_tx_queue *tx_queue;
+
+	if (likely(skb->ip_summed == CHECKSUM_PARTIAL))
+		tx_queue = &efx->tx_queue[EFX_TX_QUEUE_OFFLOAD_CSUM];
+	else
+		tx_queue = &efx->tx_queue[EFX_TX_QUEUE_NO_CSUM];
+
+	return efx_xmit(efx, tx_queue, skb);
 }
 
 void efx_xmit_done(struct efx_tx_queue *tx_queue, unsigned int index)
@@ -412,30 +425,25 @@
 	/* Allocate software ring */
 	txq_size = (efx->type->txd_ring_mask + 1) * sizeof(*tx_queue->buffer);
 	tx_queue->buffer = kzalloc(txq_size, GFP_KERNEL);
-	if (!tx_queue->buffer) {
-		rc = -ENOMEM;
-		goto fail1;
-	}
+	if (!tx_queue->buffer)
+		return -ENOMEM;
 	for (i = 0; i <= efx->type->txd_ring_mask; ++i)
-		tx_queue->buffer[i].continuation = 1;
+		tx_queue->buffer[i].continuation = true;
 
 	/* Allocate hardware ring */
 	rc = falcon_probe_tx(tx_queue);
 	if (rc)
-		goto fail2;
+		goto fail;
 
 	return 0;
 
- fail2:
+ fail:
 	kfree(tx_queue->buffer);
 	tx_queue->buffer = NULL;
- fail1:
-	tx_queue->used = 0;
-
 	return rc;
 }
 
-int efx_init_tx_queue(struct efx_tx_queue *tx_queue)
+void efx_init_tx_queue(struct efx_tx_queue *tx_queue)
 {
 	EFX_LOG(tx_queue->efx, "initialising TX queue %d\n", tx_queue->queue);
 
@@ -446,7 +454,7 @@
 	BUG_ON(tx_queue->stopped);
 
 	/* Set up TX descriptor ring */
-	return falcon_init_tx(tx_queue);
+	falcon_init_tx(tx_queue);
 }
 
 void efx_release_tx_buffers(struct efx_tx_queue *tx_queue)
@@ -461,7 +469,7 @@
 		buffer = &tx_queue->buffer[tx_queue->read_count &
 					   tx_queue->efx->type->txd_ring_mask];
 		efx_dequeue_buffer(tx_queue, buffer);
-		buffer->continuation = 1;
+		buffer->continuation = true;
 		buffer->len = 0;
 
 		++tx_queue->read_count;
@@ -494,7 +502,6 @@
 
 	kfree(tx_queue->buffer);
 	tx_queue->buffer = NULL;
-	tx_queue->used = 0;
 }
 
 
@@ -509,7 +516,7 @@
 /* Number of bytes inserted at the start of a TSO header buffer,
  * similar to NET_IP_ALIGN.
  */
-#if defined(__i386__) || defined(__x86_64__)
+#ifdef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
 #define TSOH_OFFSET	0
 #else
 #define TSOH_OFFSET	NET_IP_ALIGN
@@ -533,47 +540,37 @@
 
 /**
  * struct tso_state - TSO state for an SKB
- * @remaining_len: Bytes of data we've yet to segment
+ * @out_len: Remaining length in current segment
  * @seqnum: Current sequence number
+ * @ipv4_id: Current IPv4 ID, host endian
  * @packet_space: Remaining space in current packet
- * @ifc: Input fragment cursor.
- *	Where we are in the current fragment of the incoming SKB.  These
- *	values get updated in place when we split a fragment over
- *	multiple packets.
- * @p: Parameters.
- *	These values are set once at the start of the TSO send and do
- *	not get changed as the routine progresses.
+ * @dma_addr: DMA address of current position
+ * @in_len: Remaining length in current SKB fragment
+ * @unmap_len: Length of SKB fragment
+ * @unmap_addr: DMA address of SKB fragment
+ * @unmap_single: DMA single vs page mapping flag
+ * @header_len: Number of bytes of header
+ * @full_packet_size: Number of bytes to put in each outgoing segment
  *
  * The state used during segmentation.  It is put into this data structure
  * just to make it easy to pass into inline functions.
  */
 struct tso_state {
-	unsigned remaining_len;
+	/* Output position */
+	unsigned out_len;
 	unsigned seqnum;
+	unsigned ipv4_id;
 	unsigned packet_space;
 
-	struct {
-		/* DMA address of current position */
-		dma_addr_t dma_addr;
-		/* Remaining length */
-		unsigned int len;
-		/* DMA address and length of the whole fragment */
-		unsigned int unmap_len;
-		dma_addr_t unmap_addr;
-		struct page *page;
-		unsigned page_off;
-	} ifc;
+	/* Input position */
+	dma_addr_t dma_addr;
+	unsigned in_len;
+	unsigned unmap_len;
+	dma_addr_t unmap_addr;
+	bool unmap_single;
 
-	struct {
-		/* The number of bytes of header */
-		unsigned int header_length;
-
-		/* The number of bytes to put in each outgoing segment. */
-		int full_packet_size;
-
-		/* Current IPv4 ID, host endian. */
-		unsigned ipv4_id;
-	} p;
+	unsigned header_len;
+	int full_packet_size;
 };
 
 
@@ -581,11 +578,24 @@
  * Verify that our various assumptions about sk_buffs and the conditions
  * under which TSO will be attempted hold true.
  */
-static inline void efx_tso_check_safe(const struct sk_buff *skb)
+static void efx_tso_check_safe(struct sk_buff *skb)
 {
-	EFX_BUG_ON_PARANOID(skb->protocol != htons(ETH_P_IP));
+	__be16 protocol = skb->protocol;
+
 	EFX_BUG_ON_PARANOID(((struct ethhdr *)skb->data)->h_proto !=
-			    skb->protocol);
+			    protocol);
+	if (protocol == htons(ETH_P_8021Q)) {
+		/* Find the encapsulated protocol; reset network header
+		 * and transport header based on that. */
+		struct vlan_ethhdr *veh = (struct vlan_ethhdr *)skb->data;
+		protocol = veh->h_vlan_encapsulated_proto;
+		skb_set_network_header(skb, sizeof(*veh));
+		if (protocol == htons(ETH_P_IP))
+			skb_set_transport_header(skb, sizeof(*veh) +
+						 4 * ip_hdr(skb)->ihl);
+	}
+
+	EFX_BUG_ON_PARANOID(protocol != htons(ETH_P_IP));
 	EFX_BUG_ON_PARANOID(ip_hdr(skb)->protocol != IPPROTO_TCP);
 	EFX_BUG_ON_PARANOID((PTR_DIFF(tcp_hdr(skb), skb->data)
 			     + (tcp_hdr(skb)->doff << 2u)) >
@@ -685,18 +695,14 @@
  * @tx_queue:		Efx TX queue
  * @dma_addr:		DMA address of fragment
  * @len:		Length of fragment
- * @skb:		Only non-null for end of last segment
- * @end_of_packet:	True if last fragment in a packet
- * @unmap_addr:		DMA address of fragment for unmapping
- * @unmap_len:		Only set this in last segment of a fragment
+ * @final_buffer:	The final buffer inserted into the queue
  *
  * Push descriptors onto the TX queue.  Return 0 on success or 1 if
  * @tx_queue full.
  */
 static int efx_tx_queue_insert(struct efx_tx_queue *tx_queue,
 			       dma_addr_t dma_addr, unsigned len,
-			       const struct sk_buff *skb, int end_of_packet,
-			       dma_addr_t unmap_addr, unsigned unmap_len)
+			       struct efx_tx_buffer **final_buffer)
 {
 	struct efx_tx_buffer *buffer;
 	struct efx_nic *efx = tx_queue->efx;
@@ -724,8 +730,10 @@
 			fill_level = (tx_queue->insert_count
 				      - tx_queue->old_read_count);
 			q_space = efx->type->txd_ring_mask - 1 - fill_level;
-			if (unlikely(q_space-- <= 0))
+			if (unlikely(q_space-- <= 0)) {
+				*final_buffer = NULL;
 				return 1;
+			}
 			smp_mb();
 			--tx_queue->stopped;
 		}
@@ -742,7 +750,7 @@
 		EFX_BUG_ON_PARANOID(buffer->len);
 		EFX_BUG_ON_PARANOID(buffer->unmap_len);
 		EFX_BUG_ON_PARANOID(buffer->skb);
-		EFX_BUG_ON_PARANOID(buffer->continuation != 1);
+		EFX_BUG_ON_PARANOID(!buffer->continuation);
 		EFX_BUG_ON_PARANOID(buffer->tsoh);
 
 		buffer->dma_addr = dma_addr;
@@ -765,10 +773,7 @@
 
 	EFX_BUG_ON_PARANOID(!len);
 	buffer->len = len;
-	buffer->skb = skb;
-	buffer->continuation = !end_of_packet;
-	buffer->unmap_addr = unmap_addr;
-	buffer->unmap_len = unmap_len;
+	*final_buffer = buffer;
 	return 0;
 }
 
@@ -780,8 +785,8 @@
  * a single fragment, and we know it doesn't cross a page boundary.  It
  * also allows us to not worry about end-of-packet etc.
  */
-static inline void efx_tso_put_header(struct efx_tx_queue *tx_queue,
-				      struct efx_tso_header *tsoh, unsigned len)
+static void efx_tso_put_header(struct efx_tx_queue *tx_queue,
+			       struct efx_tso_header *tsoh, unsigned len)
 {
 	struct efx_tx_buffer *buffer;
 
@@ -791,7 +796,7 @@
 	EFX_BUG_ON_PARANOID(buffer->len);
 	EFX_BUG_ON_PARANOID(buffer->unmap_len);
 	EFX_BUG_ON_PARANOID(buffer->skb);
-	EFX_BUG_ON_PARANOID(buffer->continuation != 1);
+	EFX_BUG_ON_PARANOID(!buffer->continuation);
 	EFX_BUG_ON_PARANOID(buffer->tsoh);
 	buffer->len = len;
 	buffer->dma_addr = tsoh->dma_addr;
@@ -805,6 +810,7 @@
 static void efx_enqueue_unwind(struct efx_tx_queue *tx_queue)
 {
 	struct efx_tx_buffer *buffer;
+	dma_addr_t unmap_addr;
 
 	/* Work backwards until we hit the original insert pointer value */
 	while (tx_queue->insert_count != tx_queue->write_count) {
@@ -814,11 +820,18 @@
 		efx_tsoh_free(tx_queue, buffer);
 		EFX_BUG_ON_PARANOID(buffer->skb);
 		buffer->len = 0;
-		buffer->continuation = 1;
+		buffer->continuation = true;
 		if (buffer->unmap_len) {
-			pci_unmap_page(tx_queue->efx->pci_dev,
-				       buffer->unmap_addr,
-				       buffer->unmap_len, PCI_DMA_TODEVICE);
+			unmap_addr = (buffer->dma_addr + buffer->len -
+				      buffer->unmap_len);
+			if (buffer->unmap_single)
+				pci_unmap_single(tx_queue->efx->pci_dev,
+						 unmap_addr, buffer->unmap_len,
+						 PCI_DMA_TODEVICE);
+			else
+				pci_unmap_page(tx_queue->efx->pci_dev,
+					       unmap_addr, buffer->unmap_len,
+					       PCI_DMA_TODEVICE);
 			buffer->unmap_len = 0;
 		}
 	}
@@ -826,50 +839,57 @@
 
 
 /* Parse the SKB header and initialise state. */
-static inline void tso_start(struct tso_state *st, const struct sk_buff *skb)
+static void tso_start(struct tso_state *st, const struct sk_buff *skb)
 {
 	/* All ethernet/IP/TCP headers combined size is TCP header size
 	 * plus offset of TCP header relative to start of packet.
 	 */
-	st->p.header_length = ((tcp_hdr(skb)->doff << 2u)
-			       + PTR_DIFF(tcp_hdr(skb), skb->data));
-	st->p.full_packet_size = (st->p.header_length
-				  + skb_shinfo(skb)->gso_size);
+	st->header_len = ((tcp_hdr(skb)->doff << 2u)
+			  + PTR_DIFF(tcp_hdr(skb), skb->data));
+	st->full_packet_size = st->header_len + skb_shinfo(skb)->gso_size;
 
-	st->p.ipv4_id = ntohs(ip_hdr(skb)->id);
+	st->ipv4_id = ntohs(ip_hdr(skb)->id);
 	st->seqnum = ntohl(tcp_hdr(skb)->seq);
 
 	EFX_BUG_ON_PARANOID(tcp_hdr(skb)->urg);
 	EFX_BUG_ON_PARANOID(tcp_hdr(skb)->syn);
 	EFX_BUG_ON_PARANOID(tcp_hdr(skb)->rst);
 
-	st->packet_space = st->p.full_packet_size;
-	st->remaining_len = skb->len - st->p.header_length;
+	st->packet_space = st->full_packet_size;
+	st->out_len = skb->len - st->header_len;
+	st->unmap_len = 0;
+	st->unmap_single = false;
 }
 
-
-/**
- * tso_get_fragment - record fragment details and map for DMA
- * @st:			TSO state
- * @efx:		Efx NIC
- * @data:		Pointer to fragment data
- * @len:		Length of fragment
- *
- * Record fragment details and map for DMA.  Return 0 on success, or
- * -%ENOMEM if DMA mapping fails.
- */
-static inline int tso_get_fragment(struct tso_state *st, struct efx_nic *efx,
-				   int len, struct page *page, int page_off)
+static int tso_get_fragment(struct tso_state *st, struct efx_nic *efx,
+			    skb_frag_t *frag)
 {
+	st->unmap_addr = pci_map_page(efx->pci_dev, frag->page,
+				      frag->page_offset, frag->size,
+				      PCI_DMA_TODEVICE);
+	if (likely(!pci_dma_mapping_error(efx->pci_dev, st->unmap_addr))) {
+		st->unmap_single = false;
+		st->unmap_len = frag->size;
+		st->in_len = frag->size;
+		st->dma_addr = st->unmap_addr;
+		return 0;
+	}
+	return -ENOMEM;
+}
 
-	st->ifc.unmap_addr = pci_map_page(efx->pci_dev, page, page_off,
-					  len, PCI_DMA_TODEVICE);
-	if (likely(!pci_dma_mapping_error(efx->pci_dev, st->ifc.unmap_addr))) {
-		st->ifc.unmap_len = len;
-		st->ifc.len = len;
-		st->ifc.dma_addr = st->ifc.unmap_addr;
-		st->ifc.page = page;
-		st->ifc.page_off = page_off;
+static int tso_get_head_fragment(struct tso_state *st, struct efx_nic *efx,
+				 const struct sk_buff *skb)
+{
+	int hl = st->header_len;
+	int len = skb_headlen(skb) - hl;
+
+	st->unmap_addr = pci_map_single(efx->pci_dev, skb->data + hl,
+					len, PCI_DMA_TODEVICE);
+	if (likely(!pci_dma_mapping_error(efx->pci_dev, st->unmap_addr))) {
+		st->unmap_single = true;
+		st->unmap_len = len;
+		st->in_len = len;
+		st->dma_addr = st->unmap_addr;
 		return 0;
 	}
 	return -ENOMEM;
@@ -886,36 +906,45 @@
  * of fragment or end-of-packet.  Return 0 on success, 1 if not enough
  * space in @tx_queue.
  */
-static inline int tso_fill_packet_with_fragment(struct efx_tx_queue *tx_queue,
-						const struct sk_buff *skb,
-						struct tso_state *st)
+static int tso_fill_packet_with_fragment(struct efx_tx_queue *tx_queue,
+					 const struct sk_buff *skb,
+					 struct tso_state *st)
 {
-
+	struct efx_tx_buffer *buffer;
 	int n, end_of_packet, rc;
 
-	if (st->ifc.len == 0)
+	if (st->in_len == 0)
 		return 0;
 	if (st->packet_space == 0)
 		return 0;
 
-	EFX_BUG_ON_PARANOID(st->ifc.len <= 0);
+	EFX_BUG_ON_PARANOID(st->in_len <= 0);
 	EFX_BUG_ON_PARANOID(st->packet_space <= 0);
 
-	n = min(st->ifc.len, st->packet_space);
+	n = min(st->in_len, st->packet_space);
 
 	st->packet_space -= n;
-	st->remaining_len -= n;
-	st->ifc.len -= n;
-	st->ifc.page_off += n;
-	end_of_packet = st->remaining_len == 0 || st->packet_space == 0;
+	st->out_len -= n;
+	st->in_len -= n;
 
-	rc = efx_tx_queue_insert(tx_queue, st->ifc.dma_addr, n,
-				 st->remaining_len ? NULL : skb,
-				 end_of_packet, st->ifc.unmap_addr,
-				 st->ifc.len ? 0 : st->ifc.unmap_len);
+	rc = efx_tx_queue_insert(tx_queue, st->dma_addr, n, &buffer);
+	if (likely(rc == 0)) {
+		if (st->out_len == 0)
+			/* Transfer ownership of the skb */
+			buffer->skb = skb;
 
-	st->ifc.dma_addr += n;
+		end_of_packet = st->out_len == 0 || st->packet_space == 0;
+		buffer->continuation = !end_of_packet;
 
+		if (st->in_len == 0) {
+			/* Transfer ownership of the pci mapping */
+			buffer->unmap_len = st->unmap_len;
+			buffer->unmap_single = st->unmap_single;
+			st->unmap_len = 0;
+		}
+	}
+
+	st->dma_addr += n;
 	return rc;
 }
 
@@ -929,9 +958,9 @@
  * Generate a new header and prepare for the new packet.  Return 0 on
  * success, or -1 if failed to alloc header.
  */
-static inline int tso_start_new_packet(struct efx_tx_queue *tx_queue,
-				       const struct sk_buff *skb,
-				       struct tso_state *st)
+static int tso_start_new_packet(struct efx_tx_queue *tx_queue,
+				const struct sk_buff *skb,
+				struct tso_state *st)
 {
 	struct efx_tso_header *tsoh;
 	struct iphdr *tsoh_iph;
@@ -940,7 +969,7 @@
 	u8 *header;
 
 	/* Allocate a DMA-mapped header buffer. */
-	if (likely(TSOH_SIZE(st->p.header_length) <= TSOH_STD_SIZE)) {
+	if (likely(TSOH_SIZE(st->header_len) <= TSOH_STD_SIZE)) {
 		if (tx_queue->tso_headers_free == NULL) {
 			if (efx_tsoh_block_alloc(tx_queue))
 				return -1;
@@ -951,7 +980,7 @@
 		tsoh->unmap_len = 0;
 	} else {
 		tx_queue->tso_long_headers++;
-		tsoh = efx_tsoh_heap_alloc(tx_queue, st->p.header_length);
+		tsoh = efx_tsoh_heap_alloc(tx_queue, st->header_len);
 		if (unlikely(!tsoh))
 			return -1;
 	}
@@ -961,33 +990,32 @@
 	tsoh_iph = (struct iphdr *)(header + SKB_IPV4_OFF(skb));
 
 	/* Copy and update the headers. */
-	memcpy(header, skb->data, st->p.header_length);
+	memcpy(header, skb->data, st->header_len);
 
 	tsoh_th->seq = htonl(st->seqnum);
 	st->seqnum += skb_shinfo(skb)->gso_size;
-	if (st->remaining_len > skb_shinfo(skb)->gso_size) {
+	if (st->out_len > skb_shinfo(skb)->gso_size) {
 		/* This packet will not finish the TSO burst. */
-		ip_length = st->p.full_packet_size - ETH_HDR_LEN(skb);
+		ip_length = st->full_packet_size - ETH_HDR_LEN(skb);
 		tsoh_th->fin = 0;
 		tsoh_th->psh = 0;
 	} else {
 		/* This packet will be the last in the TSO burst. */
-		ip_length = (st->p.header_length - ETH_HDR_LEN(skb)
-			     + st->remaining_len);
+		ip_length = st->header_len - ETH_HDR_LEN(skb) + st->out_len;
 		tsoh_th->fin = tcp_hdr(skb)->fin;
 		tsoh_th->psh = tcp_hdr(skb)->psh;
 	}
 	tsoh_iph->tot_len = htons(ip_length);
 
 	/* Linux leaves suitable gaps in the IP ID space for us to fill. */
-	tsoh_iph->id = htons(st->p.ipv4_id);
-	st->p.ipv4_id++;
+	tsoh_iph->id = htons(st->ipv4_id);
+	st->ipv4_id++;
 
 	st->packet_space = skb_shinfo(skb)->gso_size;
 	++tx_queue->tso_packets;
 
 	/* Form a descriptor for this header. */
-	efx_tso_put_header(tx_queue, tsoh, st->p.header_length);
+	efx_tso_put_header(tx_queue, tsoh, st->header_len);
 
 	return 0;
 }
@@ -1005,11 +1033,11 @@
  * %NETDEV_TX_OK or %NETDEV_TX_BUSY.
  */
 static int efx_enqueue_skb_tso(struct efx_tx_queue *tx_queue,
-			       const struct sk_buff *skb)
+			       struct sk_buff *skb)
 {
+	struct efx_nic *efx = tx_queue->efx;
 	int frag_i, rc, rc2 = NETDEV_TX_OK;
 	struct tso_state state;
-	skb_frag_t *f;
 
 	/* Verify TSO is safe - these checks should never fail. */
 	efx_tso_check_safe(skb);
@@ -1021,29 +1049,16 @@
 	/* Assume that skb header area contains exactly the headers, and
 	 * all payload is in the frag list.
 	 */
-	if (skb_headlen(skb) == state.p.header_length) {
+	if (skb_headlen(skb) == state.header_len) {
 		/* Grab the first payload fragment. */
 		EFX_BUG_ON_PARANOID(skb_shinfo(skb)->nr_frags < 1);
 		frag_i = 0;
-		f = &skb_shinfo(skb)->frags[frag_i];
-		rc = tso_get_fragment(&state, tx_queue->efx,
-				      f->size, f->page, f->page_offset);
+		rc = tso_get_fragment(&state, efx,
+				      skb_shinfo(skb)->frags + frag_i);
 		if (rc)
 			goto mem_err;
 	} else {
-		/* It may look like this code fragment assumes that the
-		 * skb->data portion does not cross a page boundary, but
-		 * that is not the case.  It is guaranteed to be direct
-		 * mapped memory, and therefore is physically contiguous,
-		 * and so DMA will work fine.  kmap_atomic() on this region
-		 * will just return the direct mapping, so that will work
-		 * too.
-		 */
-		int page_off = (unsigned long)skb->data & (PAGE_SIZE - 1);
-		int hl = state.p.header_length;
-		rc = tso_get_fragment(&state, tx_queue->efx,
-				      skb_headlen(skb) - hl,
-				      virt_to_page(skb->data), page_off + hl);
+		rc = tso_get_head_fragment(&state, efx, skb);
 		if (rc)
 			goto mem_err;
 		frag_i = -1;
@@ -1058,13 +1073,12 @@
 			goto stop;
 
 		/* Move onto the next fragment? */
-		if (state.ifc.len == 0) {
+		if (state.in_len == 0) {
 			if (++frag_i >= skb_shinfo(skb)->nr_frags)
 				/* End of payload reached. */
 				break;
-			f = &skb_shinfo(skb)->frags[frag_i];
-			rc = tso_get_fragment(&state, tx_queue->efx,
-					      f->size, f->page, f->page_offset);
+			rc = tso_get_fragment(&state, efx,
+					      skb_shinfo(skb)->frags + frag_i);
 			if (rc)
 				goto mem_err;
 		}
@@ -1082,8 +1096,7 @@
 	return NETDEV_TX_OK;
 
  mem_err:
-	EFX_ERR(tx_queue->efx, "Out of memory for TSO headers, or PCI mapping"
-		" error\n");
+	EFX_ERR(efx, "Out of memory for TSO headers, or PCI mapping error\n");
 	dev_kfree_skb_any((struct sk_buff *)skb);
 	goto unwind;
 
@@ -1092,9 +1105,19 @@
 
 	/* Stop the queue if it wasn't stopped before. */
 	if (tx_queue->stopped == 1)
-		efx_stop_queue(tx_queue->efx);
+		efx_stop_queue(efx);
 
  unwind:
+	/* Free the DMA mapping we were in the process of writing out */
+	if (state.unmap_len) {
+		if (state.unmap_single)
+			pci_unmap_single(efx->pci_dev, state.unmap_addr,
+					 state.unmap_len, PCI_DMA_TODEVICE);
+		else
+			pci_unmap_page(efx->pci_dev, state.unmap_addr,
+				       state.unmap_len, PCI_DMA_TODEVICE);
+	}
+
 	efx_enqueue_unwind(tx_queue);
 	return rc2;
 }
diff --git a/drivers/net/sfc/tx.h b/drivers/net/sfc/tx.h
index 1526a73..5e1cc23 100644
--- a/drivers/net/sfc/tx.h
+++ b/drivers/net/sfc/tx.h
@@ -15,7 +15,7 @@
 
 int efx_probe_tx_queue(struct efx_tx_queue *tx_queue);
 void efx_remove_tx_queue(struct efx_tx_queue *tx_queue);
-int efx_init_tx_queue(struct efx_tx_queue *tx_queue);
+void efx_init_tx_queue(struct efx_tx_queue *tx_queue);
 void efx_fini_tx_queue(struct efx_tx_queue *tx_queue);
 
 int efx_hard_start_xmit(struct sk_buff *skb, struct net_device *net_dev);
diff --git a/drivers/net/sfc/workarounds.h b/drivers/net/sfc/workarounds.h
index 35ab19c2..fa7b49d 100644
--- a/drivers/net/sfc/workarounds.h
+++ b/drivers/net/sfc/workarounds.h
@@ -20,14 +20,10 @@
 
 /* XAUI resets if link not detected */
 #define EFX_WORKAROUND_5147 EFX_WORKAROUND_ALWAYS
-/* SNAP frames have TOBE_DISC set */
-#define EFX_WORKAROUND_5475 EFX_WORKAROUND_ALWAYS
 /* RX PCIe double split performance issue */
 #define EFX_WORKAROUND_7575 EFX_WORKAROUND_ALWAYS
 /* TX pkt parser problem with <= 16 byte TXes */
 #define EFX_WORKAROUND_9141 EFX_WORKAROUND_ALWAYS
-/* XGXS and XAUI reset sequencing in SW */
-#define EFX_WORKAROUND_9388 EFX_WORKAROUND_ALWAYS
 /* Low rate CRC errors require XAUI reset */
 #define EFX_WORKAROUND_10750 EFX_WORKAROUND_ALWAYS
 /* TX_EV_PKT_ERR can be caused by a dangling TX descriptor
diff --git a/drivers/net/sfc/xfp_phy.c b/drivers/net/sfc/xfp_phy.c
index f3684ad..276151d 100644
--- a/drivers/net/sfc/xfp_phy.c
+++ b/drivers/net/sfc/xfp_phy.c
@@ -40,7 +40,7 @@
 }
 
 struct xfp_phy_data {
-	int tx_disabled;
+	enum efx_phy_mode phy_mode;
 };
 
 #define XFP_MAX_RESET_TIME 500
@@ -93,7 +93,7 @@
 		 " %x)\n", devid, MDIO_ID_OUI(devid), MDIO_ID_MODEL(devid),
 		 MDIO_ID_REV(devid));
 
-	phy_data->tx_disabled = efx->tx_disabled;
+	phy_data->phy_mode = efx->phy_mode;
 
 	rc = xfp_reset_phy(efx);
 
@@ -136,13 +136,14 @@
 	struct xfp_phy_data *phy_data = efx->phy_data;
 
 	/* Reset the PHY when moving from tx off to tx on */
-	if (phy_data->tx_disabled && !efx->tx_disabled)
+	if (!(efx->phy_mode & PHY_MODE_TX_DISABLED) &&
+	    (phy_data->phy_mode & PHY_MODE_TX_DISABLED))
 		xfp_reset_phy(efx);
 
 	mdio_clause45_transmit_disable(efx);
 	mdio_clause45_phy_reconfigure(efx);
 
-	phy_data->tx_disabled = efx->tx_disabled;
+	phy_data->phy_mode = efx->phy_mode;
 	efx->link_up = xfp_link_ok(efx);
 	efx->link_options = GM_LPA_10000FULL;
 }
@@ -151,7 +152,7 @@
 static void xfp_phy_fini(struct efx_nic *efx)
 {
 	/* Clobber the LED if it was blinking */
-	efx->board_info.blink(efx, 0);
+	efx->board_info.blink(efx, false);
 
 	/* Free the context block */
 	kfree(efx->phy_data);
@@ -164,7 +165,6 @@
 	.check_hw        = xfp_phy_check_hw,
 	.fini            = xfp_phy_fini,
 	.clear_interrupt = xfp_phy_clear_interrupt,
-	.reset_xaui      = efx_port_dummy_op_void,
 	.mmds            = XFP_REQUIRED_DEVS,
 	.loopbacks       = XFP_LOOPBACKS,
 };
diff --git a/drivers/net/sh_eth.c b/drivers/net/sh_eth.c
index 1c370e6..b39d1cc 100644
--- a/drivers/net/sh_eth.c
+++ b/drivers/net/sh_eth.c
@@ -1140,7 +1140,7 @@
 
 	/* Hook up MII support for ethtool */
 	mdp->mii_bus->name = "sh_mii";
-	mdp->mii_bus->dev = &ndev->dev;
+	mdp->mii_bus->parent = &ndev->dev;
 	mdp->mii_bus->id[0] = id;
 
 	/* PHY IRQ */
@@ -1166,7 +1166,7 @@
 	kfree(mdp->mii_bus->irq);
 
 out_free_bus:
-	kfree(mdp->mii_bus);
+	free_mdio_bitbang(mdp->mii_bus);
 
 out_free_bitbang:
 	kfree(bitbang);
diff --git a/drivers/net/skfp/pmf.c b/drivers/net/skfp/pmf.c
index ea85de9..79e665e 100644
--- a/drivers/net/skfp/pmf.c
+++ b/drivers/net/skfp/pmf.c
@@ -44,17 +44,10 @@
 				     int set, int local);
 static int port_to_mib(struct s_smc *smc, int p);
 
-#define MOFFSS(e)	((int)&(((struct fddi_mib *)0)->e))
-#define MOFFSA(e)	((int) (((struct fddi_mib *)0)->e))
-
-#define MOFFMS(e)	((int)&(((struct fddi_mib_m *)0)->e))
-#define MOFFMA(e)	((int) (((struct fddi_mib_m *)0)->e))
-
-#define MOFFAS(e)	((int)&(((struct fddi_mib_a *)0)->e))
-#define MOFFAA(e)	((int) (((struct fddi_mib_a *)0)->e))
-
-#define MOFFPS(e)	((int)&(((struct fddi_mib_p *)0)->e))
-#define MOFFPA(e)	((int) (((struct fddi_mib_p *)0)->e))
+#define MOFFSS(e)	offsetof(struct fddi_mib, e)
+#define MOFFMS(e)	offsetof(struct fddi_mib_m, e)
+#define MOFFAS(e)	offsetof(struct fddi_mib_a, e)
+#define MOFFPS(e)	offsetof(struct fddi_mib_p, e)
 
 
 #define AC_G	0x01		/* Get */
@@ -87,8 +80,8 @@
 	{ SMT_P100D,AC_G,	MOFFSS(fddiSMTOpVersionId),	"S"	} ,
 	{ SMT_P100E,AC_G,	MOFFSS(fddiSMTHiVersionId),	"S"	} ,
 	{ SMT_P100F,AC_G,	MOFFSS(fddiSMTLoVersionId),	"S"	} ,
-	{ SMT_P1010,AC_G,	MOFFSA(fddiSMTManufacturerData), "D" } ,
-	{ SMT_P1011,AC_GR,	MOFFSA(fddiSMTUserData),	"D"	} ,
+	{ SMT_P1010,AC_G,	MOFFSS(fddiSMTManufacturerData), "D" } ,
+	{ SMT_P1011,AC_GR,	MOFFSS(fddiSMTUserData),	"D"	} ,
 	{ SMT_P1012,AC_G,	MOFFSS(fddiSMTMIBVersionId),	"S"	} ,
 
 	/* StationConfigGrp */
@@ -103,7 +96,7 @@
 	{ SMT_P101D,AC_GR,	MOFFSS(fddiSMTTT_Notify),	"wS"	} ,
 	{ SMT_P101E,AC_GR,	MOFFSS(fddiSMTStatRptPolicy),	"bB"	} ,
 	{ SMT_P101F,AC_GR,	MOFFSS(fddiSMTTrace_MaxExpiration),"lL"	} ,
-	{ SMT_P1020,AC_G,	MOFFSA(fddiSMTPORTIndexes),	"II"	} ,
+	{ SMT_P1020,AC_G,	MOFFSS(fddiSMTPORTIndexes),	"II"	} ,
 	{ SMT_P1021,AC_G,	MOFFSS(fddiSMTMACIndexes),	"I"	} ,
 	{ SMT_P1022,AC_G,	MOFFSS(fddiSMTBypassPresent),	"F"	} ,
 
@@ -117,8 +110,8 @@
 
 	/* MIBOperationGrp */
 	{ SMT_P1032,AC_GROUP	} ,
-	{ SMT_P1033,AC_G,	MOFFSA(fddiSMTTimeStamp),"P"		} ,
-	{ SMT_P1034,AC_G,	MOFFSA(fddiSMTTransitionTimeStamp),"P"	} ,
+	{ SMT_P1033,AC_G,	MOFFSS(fddiSMTTimeStamp),"P"		} ,
+	{ SMT_P1034,AC_G,	MOFFSS(fddiSMTTransitionTimeStamp),"P"	} ,
 	/* NOTE : SMT_P1035 is already swapped ! SMT_P_SETCOUNT */
 	{ SMT_P1035,AC_G,	MOFFSS(fddiSMTSetCount),"4P"		} ,
 	{ SMT_P1036,AC_G,	MOFFSS(fddiSMTLastSetStationId),"8"	} ,
@@ -129,7 +122,7 @@
 	 * PRIVATE EXTENSIONS
 	 * only accessible locally to get/set passwd
 	 */
-	{ SMT_P10F0,AC_GR,	MOFFSA(fddiPRPMFPasswd),	"8"	} ,
+	{ SMT_P10F0,AC_GR,	MOFFSS(fddiPRPMFPasswd),	"8"	} ,
 	{ SMT_P10F1,AC_GR,	MOFFSS(fddiPRPMFStation),	"8"	} ,
 #ifdef	ESS
 	{ SMT_P10F2,AC_GR,	MOFFSS(fddiESSPayload),		"lL"	} ,
@@ -245,7 +238,7 @@
 	{ SMT_P400E,AC_GR,	MOFFPS(fddiPORTConnectionPolicies),"bB"	} ,
 	{ SMT_P400F,AC_G,	MOFFPS(fddiPORTMacIndicated),	"2"	} ,
 	{ SMT_P4010,AC_G,	MOFFPS(fddiPORTCurrentPath),	"E"	} ,
-	{ SMT_P4011,AC_GR,	MOFFPA(fddiPORTRequestedPaths),	"l4"	} ,
+	{ SMT_P4011,AC_GR,	MOFFPS(fddiPORTRequestedPaths),	"l4"	} ,
 	{ SMT_P4012,AC_G,	MOFFPS(fddiPORTMACPlacement),	"S"	} ,
 	{ SMT_P4013,AC_G,	MOFFPS(fddiPORTAvailablePaths),	"B"	} ,
 	{ SMT_P4016,AC_G,	MOFFPS(fddiPORTPMDClass),	"E"	} ,
diff --git a/drivers/net/skge.c b/drivers/net/skge.c
index 2e26dce..43f4c73 100644
--- a/drivers/net/skge.c
+++ b/drivers/net/skge.c
@@ -319,6 +319,7 @@
 	struct skge_port *skge = netdev_priv(dev);
 	const struct skge_hw *hw = skge->hw;
 	u32 supported = skge_supported_modes(hw);
+	int err = 0;
 
 	if (ecmd->autoneg == AUTONEG_ENABLE) {
 		ecmd->advertising = supported;
@@ -367,8 +368,14 @@
 	skge->autoneg = ecmd->autoneg;
 	skge->advertising = ecmd->advertising;
 
-	if (netif_running(dev))
-		skge_phy_reset(skge);
+	if (netif_running(dev)) {
+		skge_down(dev);
+		err = skge_up(dev);
+		if (err) {
+			dev_close(dev);
+			return err;
+		}
+	}
 
 	return (0);
 }
@@ -494,7 +501,7 @@
 			       struct ethtool_ringparam *p)
 {
 	struct skge_port *skge = netdev_priv(dev);
-	int err;
+	int err = 0;
 
 	if (p->rx_pending == 0 || p->rx_pending > MAX_RX_RING_SIZE ||
 	    p->tx_pending < TX_LOW_WATER || p->tx_pending > MAX_TX_RING_SIZE)
@@ -510,7 +517,7 @@
 			dev_close(dev);
 	}
 
-	return 0;
+	return err;
 }
 
 static u32 skge_get_msglevel(struct net_device *netdev)
@@ -593,6 +600,7 @@
 {
 	struct skge_port *skge = netdev_priv(dev);
 	struct ethtool_pauseparam old;
+	int err = 0;
 
 	skge_get_pauseparam(dev, &old);
 
@@ -609,8 +617,14 @@
 			skge->flow_control = FLOW_MODE_NONE;
 	}
 
-	if (netif_running(dev))
-		skge_phy_reset(skge);
+	if (netif_running(dev)) {
+		skge_down(dev);
+		err = skge_up(dev);
+		if (err) {
+			dev_close(dev);
+			return err;
+		}
+	}
 
 	return 0;
 }
diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c
index e24b25c..3813d15 100644
--- a/drivers/net/sky2.c
+++ b/drivers/net/sky2.c
@@ -3034,7 +3034,8 @@
 	struct sky2_port *sky2 = netdev_priv(dev);
 	struct sky2_hw *hw = sky2->hw;
 
-	if (wol->wolopts & ~sky2_wol_supported(sky2->hw))
+	if ((wol->wolopts & ~sky2_wol_supported(sky2->hw))
+	    || !device_can_wakeup(&hw->pdev->dev))
 		return -EOPNOTSUPP;
 
 	sky2->wol = wol->wolopts;
@@ -3045,6 +3046,8 @@
 		sky2_write32(hw, B0_CTST, sky2->wol
 			     ? Y2_HW_WOL_ON : Y2_HW_WOL_OFF);
 
+	device_set_wakeup_enable(&hw->pdev->dev, sky2->wol);
+
 	if (!netif_running(dev))
 		sky2_wol_init(sky2);
 	return 0;
@@ -3732,27 +3735,63 @@
 	return 1 << ( ((reg2 & PCI_VPD_ROM_SZ) >> 14) + 8);
 }
 
-static u32 sky2_vpd_read(struct sky2_hw *hw, int cap, u16 offset)
+static int sky2_vpd_wait(const struct sky2_hw *hw, int cap, u16 busy)
 {
-	u32 val;
+	unsigned long start = jiffies;
 
-	sky2_pci_write16(hw, cap + PCI_VPD_ADDR, offset);
+	while ( (sky2_pci_read16(hw, cap + PCI_VPD_ADDR) & PCI_VPD_ADDR_F) == busy) {
+		/* Can take up to 10.6 ms for write */
+		if (time_after(jiffies, start + HZ/4)) {
+			dev_err(&hw->pdev->dev, PFX "VPD cycle timed out");
+			return -ETIMEDOUT;
+		}
+		mdelay(1);
+	}
 
-	do {
-		offset = sky2_pci_read16(hw, cap + PCI_VPD_ADDR);
-	} while (!(offset & PCI_VPD_ADDR_F));
-
-	val = sky2_pci_read32(hw, cap + PCI_VPD_DATA);
-	return val;
+	return 0;
 }
 
-static void sky2_vpd_write(struct sky2_hw *hw, int cap, u16 offset, u32 val)
+static int sky2_vpd_read(struct sky2_hw *hw, int cap, void *data,
+			 u16 offset, size_t length)
 {
-	sky2_pci_write16(hw, cap + PCI_VPD_DATA, val);
-	sky2_pci_write32(hw, cap + PCI_VPD_ADDR, offset | PCI_VPD_ADDR_F);
-	do {
-		offset = sky2_pci_read16(hw, cap + PCI_VPD_ADDR);
-	} while (offset & PCI_VPD_ADDR_F);
+	int rc = 0;
+
+	while (length > 0) {
+		u32 val;
+
+		sky2_pci_write16(hw, cap + PCI_VPD_ADDR, offset);
+		rc = sky2_vpd_wait(hw, cap, 0);
+		if (rc)
+			break;
+
+		val = sky2_pci_read32(hw, cap + PCI_VPD_DATA);
+
+		memcpy(data, &val, min(sizeof(val), length));
+		offset += sizeof(u32);
+		data += sizeof(u32);
+		length -= sizeof(u32);
+	}
+
+	return rc;
+}
+
+static int sky2_vpd_write(struct sky2_hw *hw, int cap, const void *data,
+			  u16 offset, unsigned int length)
+{
+	unsigned int i;
+	int rc = 0;
+
+	for (i = 0; i < length; i += sizeof(u32)) {
+		u32 val = *(u32 *)(data + i);
+
+		sky2_pci_write32(hw, cap + PCI_VPD_DATA, val);
+		sky2_pci_write32(hw, cap + PCI_VPD_ADDR, offset | PCI_VPD_ADDR_F);
+
+		rc = sky2_vpd_wait(hw, cap, PCI_VPD_ADDR_F);
+		if (rc)
+			break;
+	}
+	return rc;
 }
 
 static int sky2_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
@@ -3760,24 +3799,13 @@
 {
 	struct sky2_port *sky2 = netdev_priv(dev);
 	int cap = pci_find_capability(sky2->hw->pdev, PCI_CAP_ID_VPD);
-	int length = eeprom->len;
-	u16 offset = eeprom->offset;
 
 	if (!cap)
 		return -EINVAL;
 
 	eeprom->magic = SKY2_EEPROM_MAGIC;
 
-	while (length > 0) {
-		u32 val = sky2_vpd_read(sky2->hw, cap, offset);
-		int n = min_t(int, length, sizeof(val));
-
-		memcpy(data, &val, n);
-		length -= n;
-		data += n;
-		offset += n;
-	}
-	return 0;
+	return sky2_vpd_read(sky2->hw, cap, data, eeprom->offset, eeprom->len);
 }
 
 static int sky2_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
@@ -3785,8 +3813,6 @@
 {
 	struct sky2_port *sky2 = netdev_priv(dev);
 	int cap = pci_find_capability(sky2->hw->pdev, PCI_CAP_ID_VPD);
-	int length = eeprom->len;
-	u16 offset = eeprom->offset;
 
 	if (!cap)
 		return -EINVAL;
@@ -3794,21 +3820,11 @@
 	if (eeprom->magic != SKY2_EEPROM_MAGIC)
 		return -EINVAL;
 
-	while (length > 0) {
-		u32 val;
-		int n = min_t(int, length, sizeof(val));
+	/* Partial writes not supported */
+	if ((eeprom->offset & 3) || (eeprom->len & 3))
+		return -EINVAL;
 
-		if (n < sizeof(val))
-			val = sky2_vpd_read(sky2->hw, cap, offset);
-		memcpy(&val, data, n);
-
-		sky2_vpd_write(sky2->hw, cap, offset, val);
-
-		length -= n;
-		data += n;
-		offset += n;
-	}
-	return 0;
+	return sky2_vpd_write(sky2->hw, cap, data, eeprom->offset, eeprom->len);
 }
 
 
@@ -4166,16 +4182,67 @@
 	return err;
 }
 
-static int __devinit pci_wake_enabled(struct pci_dev *dev)
-{
-	int pm  = pci_find_capability(dev, PCI_CAP_ID_PM);
-	u16 value;
+/*
+ * Read and parse the first part of Vital Product Data
+ */
+#define VPD_SIZE	128
+#define VPD_MAGIC	0x82
 
-	if (!pm)
-		return 0;
-	if (pci_read_config_word(dev, pm + PCI_PM_CTRL, &value))
-		return 0;
-	return value & PCI_PM_CTRL_PME_ENABLE;
+static void __devinit sky2_vpd_info(struct sky2_hw *hw)
+{
+	int cap = pci_find_capability(hw->pdev, PCI_CAP_ID_VPD);
+	const u8 *p;
+	u8 *vpd_buf = NULL;
+	u16 len;
+	static struct vpd_tag {
+		char tag[2];
+		char *label;
+	} vpd_tags[] = {
+		{ "PN",	"Part Number" },
+		{ "EC", "Engineering Level" },
+		{ "MN", "Manufacturer" },
+	};
+
+	if (!cap)
+		goto out;
+
+	vpd_buf = kmalloc(VPD_SIZE, GFP_KERNEL);
+	if (!vpd_buf)
+		goto out;
+
+	if (sky2_vpd_read(hw, cap, vpd_buf, 0, VPD_SIZE))
+		goto out;
+
+	if (vpd_buf[0] != VPD_MAGIC)
+		goto out;
+	len = vpd_buf[1];
+	if (len == 0 || len > VPD_SIZE - 4)
+		goto out;
+	p = vpd_buf + 3;
+	dev_info(&hw->pdev->dev, "%.*s\n", len, p);
+	p += len;
+
+	while (p < vpd_buf + VPD_SIZE - 4) {
+		int i;
+
+		if (!memcmp("RW", p, 2))	/* end marker */
+			break;
+
+		len = p[2];
+		if (len > (p - vpd_buf) - 4)
+			break;
+
+		for (i = 0; i < ARRAY_SIZE(vpd_tags); i++) {
+			if (!memcmp(vpd_tags[i].tag, p, 2)) {
+				printk(KERN_DEBUG " %s: %.*s\n",
+				       vpd_tags[i].label, len, p + 3);
+				break;
+			}
+		}
+		p += len + 3;
+	}
+out:
+	kfree(vpd_buf);
 }
 
 /* This driver supports yukon2 chipset only */
@@ -4238,7 +4305,7 @@
 		}
 	}
 
-	wol_default = pci_wake_enabled(pdev) ? WAKE_MAGIC : 0;
+	wol_default = device_may_wakeup(&pdev->dev) ? WAKE_MAGIC : 0;
 
 	err = -ENOMEM;
 	hw = kzalloc(sizeof(*hw), GFP_KERNEL);
@@ -4276,13 +4343,13 @@
 	if (err)
 		goto err_out_iounmap;
 
-	dev_info(&pdev->dev, "v%s addr 0x%llx irq %d Yukon-2 %s rev %d\n",
-		 DRV_VERSION, (unsigned long long)pci_resource_start(pdev, 0),
-		 pdev->irq, sky2_name(hw->chip_id, buf1, sizeof(buf1)),
-		 hw->chip_rev);
+	dev_info(&pdev->dev, "Yukon-2 %s chip revision %d\n",
+		 sky2_name(hw->chip_id, buf1, sizeof(buf1)), hw->chip_rev);
 
 	sky2_reset(hw);
 
+	sky2_vpd_info(hw);
+
 	dev = sky2_init_netdev(hw, 0, using_dac, wol_default);
 	if (!dev) {
 		err = -ENOMEM;
@@ -4533,6 +4600,8 @@
 
 static int __init sky2_init_module(void)
 {
+	pr_info(PFX "driver version " DRV_VERSION "\n");
+
 	sky2_debug_init();
 	return pci_register_driver(&sky2_driver);
 }
diff --git a/drivers/net/smc911x.c b/drivers/net/smc911x.c
index c587162..8aa7460 100644
--- a/drivers/net/smc911x.c
+++ b/drivers/net/smc911x.c
@@ -183,7 +183,7 @@
 	unsigned int reg, timeout=0, resets=1;
 	unsigned long flags;
 
-	DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __FUNCTION__);
+	DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __func__);
 
 	/*	 Take out of PM setting first */
 	if ((SMC_GET_PMT_CTRL(lp) & PMT_CTRL_READY_) == 0) {
@@ -272,7 +272,7 @@
 	unsigned mask, cfg, cr;
 	unsigned long flags;
 
-	DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __FUNCTION__);
+	DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __func__);
 
 	SMC_SET_MAC_ADDR(lp, dev->dev_addr);
 
@@ -329,7 +329,7 @@
 	unsigned cr;
 	unsigned long flags;
 
-	DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", CARDNAME, __FUNCTION__);
+	DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", CARDNAME, __func__);
 
 	/* Disable IRQ's */
 	SMC_SET_INT_EN(lp, 0);
@@ -348,7 +348,7 @@
 	struct smc911x_local *lp = netdev_priv(dev);
 	unsigned int fifo_count, timeout, reg;
 
-	DBG(SMC_DEBUG_FUNC | SMC_DEBUG_RX, "%s: --> %s\n", CARDNAME, __FUNCTION__);
+	DBG(SMC_DEBUG_FUNC | SMC_DEBUG_RX, "%s: --> %s\n", CARDNAME, __func__);
 	fifo_count = SMC_GET_RX_FIFO_INF(lp) & 0xFFFF;
 	if (fifo_count <= 4) {
 		/* Manually dump the packet data */
@@ -382,7 +382,7 @@
 	unsigned char *data;
 
 	DBG(SMC_DEBUG_FUNC | SMC_DEBUG_RX, "%s: --> %s\n",
-		dev->name, __FUNCTION__);
+		dev->name, __func__);
 	status = SMC_GET_RX_STS_FIFO(lp);
 	DBG(SMC_DEBUG_RX, "%s: Rx pkt len %d status 0x%08x \n",
 		dev->name, (status & 0x3fff0000) >> 16, status & 0xc000ffff);
@@ -460,7 +460,7 @@
 	unsigned char *buf;
 	unsigned long flags;
 
-	DBG(SMC_DEBUG_FUNC | SMC_DEBUG_TX, "%s: --> %s\n", dev->name, __FUNCTION__);
+	DBG(SMC_DEBUG_FUNC | SMC_DEBUG_TX, "%s: --> %s\n", dev->name, __func__);
 	BUG_ON(lp->pending_tx_skb == NULL);
 
 	skb = lp->pending_tx_skb;
@@ -524,7 +524,7 @@
 	unsigned long flags;
 
 	DBG(SMC_DEBUG_FUNC | SMC_DEBUG_TX, "%s: --> %s\n",
-		dev->name, __FUNCTION__);
+		dev->name, __func__);
 
 	BUG_ON(lp->pending_tx_skb != NULL);
 
@@ -596,7 +596,7 @@
 	unsigned int tx_status;
 
 	DBG(SMC_DEBUG_FUNC | SMC_DEBUG_TX, "%s: --> %s\n",
-		dev->name, __FUNCTION__);
+		dev->name, __func__);
 
 	/* Collect the TX status */
 	while (((SMC_GET_TX_FIFO_INF(lp) & TX_FIFO_INF_TSUSED_) >> 16) != 0) {
@@ -647,7 +647,7 @@
 	SMC_GET_MII(lp, phyreg, phyaddr, phydata);
 
 	DBG(SMC_DEBUG_MISC, "%s: phyaddr=0x%x, phyreg=0x%02x, phydata=0x%04x\n",
-		__FUNCTION__, phyaddr, phyreg, phydata);
+		__func__, phyaddr, phyreg, phydata);
 	return phydata;
 }
 
@@ -661,7 +661,7 @@
 	struct smc911x_local *lp = netdev_priv(dev);
 
 	DBG(SMC_DEBUG_MISC, "%s: phyaddr=0x%x, phyreg=0x%x, phydata=0x%x\n",
-		__FUNCTION__, phyaddr, phyreg, phydata);
+		__func__, phyaddr, phyreg, phydata);
 
 	SMC_SET_MII(lp, phyreg, phyaddr, phydata);
 }
@@ -676,7 +676,7 @@
 	int phyaddr;
 	unsigned int cfg, id1, id2;
 
-	DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __FUNCTION__);
+	DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __func__);
 
 	lp->phy_type = 0;
 
@@ -685,8 +685,10 @@
 	 * PHY#1 to PHY#31, and then PHY#0 last.
 	 */
 	switch(lp->version) {
-		case 0x115:
-		case 0x117:
+		case CHIP_9115:
+		case CHIP_9117:
+		case CHIP_9215:
+		case CHIP_9217:
 			cfg = SMC_GET_HW_CFG(lp);
 			if (cfg & HW_CFG_EXT_PHY_DET_) {
 				cfg &= ~HW_CFG_PHY_CLK_SEL_;
@@ -722,6 +724,9 @@
 						break;
 					}
 				}
+				if (phyaddr < 32)
+					/* Found an external PHY */
+					break;
 			}
 		default:
 			/* Internal media only */
@@ -746,7 +751,7 @@
 	int phyaddr = lp->mii.phy_id;
 	int bmcr;
 
-	DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __FUNCTION__);
+	DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __func__);
 
 	/* Enter Link Disable state */
 	SMC_GET_PHY_BMCR(lp, phyaddr, bmcr);
@@ -793,7 +798,7 @@
 	unsigned long flags;
 	unsigned int reg;
 
-	DBG(SMC_DEBUG_FUNC, "%s: --> %s()\n", dev->name, __FUNCTION__);
+	DBG(SMC_DEBUG_FUNC, "%s: --> %s()\n", dev->name, __func__);
 
 	spin_lock_irqsave(&lp->lock, flags);
 	reg = SMC_GET_PMT_CTRL(lp);
@@ -852,7 +857,7 @@
 	int phyaddr = lp->mii.phy_id;
 	unsigned int bmcr, cr;
 
-	DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __FUNCTION__);
+	DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __func__);
 
 	if (mii_check_media(&lp->mii, netif_msg_link(lp), init)) {
 		/* duplex state has changed */
@@ -892,7 +897,7 @@
 	int status;
 	unsigned long flags;
 
-	DBG(SMC_DEBUG_FUNC, "%s: --> %s()\n", dev->name, __FUNCTION__);
+	DBG(SMC_DEBUG_FUNC, "%s: --> %s()\n", dev->name, __func__);
 
 	/*
 	 * We should not be called if phy_type is zero.
@@ -985,7 +990,7 @@
 	int phyaddr = lp->mii.phy_id;
 	int status;
 
-	DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __FUNCTION__);
+	DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __func__);
 
 	if (lp->phy_type == 0)
 		return;
@@ -1013,7 +1018,7 @@
 	unsigned int rx_overrun=0, cr, pkts;
 	unsigned long flags;
 
-	DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __FUNCTION__);
+	DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __func__);
 
 	spin_lock_irqsave(&lp->lock, flags);
 
@@ -1174,8 +1179,6 @@
 
 	spin_unlock_irqrestore(&lp->lock, flags);
 
-	DBG(3, "%s: Interrupt done (%d loops)\n", dev->name, 8-timeout);
-
 	return IRQ_HANDLED;
 }
 
@@ -1188,7 +1191,7 @@
 	struct sk_buff *skb = lp->current_tx_skb;
 	unsigned long flags;
 
-	DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __FUNCTION__);
+	DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __func__);
 
 	DBG(SMC_DEBUG_TX | SMC_DEBUG_DMA, "%s: TX DMA irq handler\n", dev->name);
 	/* Clear the DMA interrupt sources */
@@ -1224,7 +1227,7 @@
 	unsigned long flags;
 	unsigned int pkts;
 
-	DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __FUNCTION__);
+	DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __func__);
 	DBG(SMC_DEBUG_RX | SMC_DEBUG_DMA, "%s: RX DMA irq handler\n", dev->name);
 	/* Clear the DMA interrupt sources */
 	SMC_DMA_ACK_IRQ(dev, dma);
@@ -1272,7 +1275,7 @@
 	int status, mask;
 	unsigned long flags;
 
-	DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __FUNCTION__);
+	DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __func__);
 
 	spin_lock_irqsave(&lp->lock, flags);
 	status = SMC_GET_INT(lp);
@@ -1310,7 +1313,7 @@
 	unsigned int mcr, update_multicast = 0;
 	unsigned long flags;
 
-	DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __FUNCTION__);
+	DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __func__);
 
 	spin_lock_irqsave(&lp->lock, flags);
 	SMC_GET_MAC_CR(lp, mcr);
@@ -1412,7 +1415,7 @@
 {
 	struct smc911x_local *lp = netdev_priv(dev);
 
-	DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __FUNCTION__);
+	DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __func__);
 
 	/*
 	 * Check that the address is valid.  If its not, refuse
@@ -1420,7 +1423,7 @@
 	 * address using ifconfig eth0 hw ether xx:xx:xx:xx:xx:xx
 	 */
 	if (!is_valid_ether_addr(dev->dev_addr)) {
-		PRINTK("%s: no valid ethernet hw addr\n", __FUNCTION__);
+		PRINTK("%s: no valid ethernet hw addr\n", __func__);
 		return -EINVAL;
 	}
 
@@ -1449,7 +1452,7 @@
 {
 	struct smc911x_local *lp = netdev_priv(dev);
 
-	DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __FUNCTION__);
+	DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __func__);
 
 	netif_stop_queue(dev);
 	netif_carrier_off(dev);
@@ -1483,7 +1486,7 @@
 	int ret, status;
 	unsigned long flags;
 
-	DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __FUNCTION__);
+	DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __func__);
 	cmd->maxtxpkt = 1;
 	cmd->maxrxpkt = 1;
 
@@ -1621,7 +1624,7 @@
 	for(timeout=10;(e2p_cmd & E2P_CMD_EPC_BUSY_) && timeout; timeout--) {
 		if (e2p_cmd & E2P_CMD_EPC_TIMEOUT_) {
 			PRINTK("%s: %s timeout waiting for EEPROM to respond\n",
-				dev->name, __FUNCTION__);
+				dev->name, __func__);
 			return -EFAULT;
 		}
 		mdelay(1);
@@ -1629,7 +1632,7 @@
 	}
 	if (timeout == 0) {
 		PRINTK("%s: %s timeout waiting for EEPROM CMD not busy\n",
-			dev->name, __FUNCTION__);
+			dev->name, __func__);
 		return -ETIMEDOUT;
 	}
 	return 0;
@@ -1742,7 +1745,7 @@
 	int timeout = 20;
 	unsigned long cookie;
 
-	DBG(SMC_DEBUG_FUNC, "--> %s\n", __FUNCTION__);
+	DBG(SMC_DEBUG_FUNC, "--> %s\n", __func__);
 
 	cookie = probe_irq_on();
 
@@ -1808,7 +1811,7 @@
 	const char *version_string;
 	unsigned long irq_flags;
 
-	DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __FUNCTION__);
+	DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __func__);
 
 	/* First, see if the endian word is recognized */
 	val = SMC_GET_BYTE_TEST(lp);
@@ -2058,7 +2061,7 @@
 	unsigned int *addr;
 	int ret;
 
-	DBG(SMC_DEBUG_FUNC, "--> %s\n",  __FUNCTION__);
+	DBG(SMC_DEBUG_FUNC, "--> %s\n",  __func__);
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	if (!res) {
 		ret = -ENODEV;
@@ -2129,7 +2132,7 @@
 	struct smc911x_local *lp = netdev_priv(ndev);
 	struct resource *res;
 
-	DBG(SMC_DEBUG_FUNC, "--> %s\n", __FUNCTION__);
+	DBG(SMC_DEBUG_FUNC, "--> %s\n", __func__);
 	platform_set_drvdata(pdev, NULL);
 
 	unregister_netdev(ndev);
@@ -2159,7 +2162,7 @@
 	struct net_device *ndev = platform_get_drvdata(dev);
 	struct smc911x_local *lp = netdev_priv(ndev);
 
-	DBG(SMC_DEBUG_FUNC, "--> %s\n", __FUNCTION__);
+	DBG(SMC_DEBUG_FUNC, "--> %s\n", __func__);
 	if (ndev) {
 		if (netif_running(ndev)) {
 			netif_device_detach(ndev);
@@ -2177,7 +2180,7 @@
 {
 	struct net_device *ndev = platform_get_drvdata(dev);
 
-	DBG(SMC_DEBUG_FUNC, "--> %s\n", __FUNCTION__);
+	DBG(SMC_DEBUG_FUNC, "--> %s\n", __func__);
 	if (ndev) {
 		struct smc911x_local *lp = netdev_priv(ndev);
 
diff --git a/drivers/net/smc911x.h b/drivers/net/smc911x.h
index 2abfc28..bf6240f 100644
--- a/drivers/net/smc911x.h
+++ b/drivers/net/smc911x.h
@@ -666,10 +666,13 @@
 #define LAN911X_INTERNAL_PHY_ID		(0x0007C000)
 
 /* Chip ID values */
-#define CHIP_9115	0x115
-#define CHIP_9116	0x116
-#define CHIP_9117	0x117
-#define CHIP_9118	0x118
+#define CHIP_9115	0x0115
+#define CHIP_9116	0x0116
+#define CHIP_9117	0x0117
+#define CHIP_9118	0x0118
+#define CHIP_9215	0x115A
+#define CHIP_9217	0x117A
+#define CHIP_9218	0x118A
 
 struct chip_id {
 	u16 id;
@@ -681,6 +684,9 @@
 	{ CHIP_9116, "LAN9116" },
 	{ CHIP_9117, "LAN9117" },
 	{ CHIP_9118, "LAN9118" },
+	{ CHIP_9215, "LAN9215" },
+	{ CHIP_9217, "LAN9217" },
+	{ CHIP_9218, "LAN9218" },
 	{ 0, NULL },
 };
 
diff --git a/drivers/net/smc91x.c b/drivers/net/smc91x.c
index 24768c1..c70870e 100644
--- a/drivers/net/smc91x.c
+++ b/drivers/net/smc91x.c
@@ -270,7 +270,7 @@
 	unsigned int ctl, cfg;
 	struct sk_buff *pending_skb;
 
-	DBG(2, "%s: %s\n", dev->name, __FUNCTION__);
+	DBG(2, "%s: %s\n", dev->name, __func__);
 
 	/* Disable all interrupts, block TX tasklet */
 	spin_lock_irq(&lp->lock);
@@ -363,7 +363,7 @@
 	void __iomem *ioaddr = lp->base;
 	int mask;
 
-	DBG(2, "%s: %s\n", dev->name, __FUNCTION__);
+	DBG(2, "%s: %s\n", dev->name, __func__);
 
 	/* see the header file for options in TCR/RCR DEFAULT */
 	SMC_SELECT_BANK(lp, 0);
@@ -397,7 +397,7 @@
 	void __iomem *ioaddr = lp->base;
 	struct sk_buff *pending_skb;
 
-	DBG(2, "%s: %s\n", CARDNAME, __FUNCTION__);
+	DBG(2, "%s: %s\n", CARDNAME, __func__);
 
 	/* no more interrupts for me */
 	spin_lock_irq(&lp->lock);
@@ -430,7 +430,7 @@
 	void __iomem *ioaddr = lp->base;
 	unsigned int packet_number, status, packet_len;
 
-	DBG(3, "%s: %s\n", dev->name, __FUNCTION__);
+	DBG(3, "%s: %s\n", dev->name, __func__);
 
 	packet_number = SMC_GET_RXFIFO(lp);
 	if (unlikely(packet_number & RXFIFO_REMPTY)) {
@@ -577,7 +577,7 @@
 	unsigned int packet_no, len;
 	unsigned char *buf;
 
-	DBG(3, "%s: %s\n", dev->name, __FUNCTION__);
+	DBG(3, "%s: %s\n", dev->name, __func__);
 
 	if (!smc_special_trylock(&lp->lock)) {
 		netif_stop_queue(dev);
@@ -662,7 +662,7 @@
 	void __iomem *ioaddr = lp->base;
 	unsigned int numPages, poll_count, status;
 
-	DBG(3, "%s: %s\n", dev->name, __FUNCTION__);
+	DBG(3, "%s: %s\n", dev->name, __func__);
 
 	BUG_ON(lp->pending_tx_skb != NULL);
 
@@ -734,7 +734,7 @@
 	void __iomem *ioaddr = lp->base;
 	unsigned int saved_packet, packet_no, tx_status, pkt_len;
 
-	DBG(3, "%s: %s\n", dev->name, __FUNCTION__);
+	DBG(3, "%s: %s\n", dev->name, __func__);
 
 	/* If the TX FIFO is empty then nothing to do */
 	packet_no = SMC_GET_TXFIFO(lp);
@@ -856,7 +856,7 @@
 	SMC_SET_MII(lp, SMC_GET_MII(lp) & ~(MII_MCLK|MII_MDOE|MII_MDO));
 
 	DBG(3, "%s: phyaddr=0x%x, phyreg=0x%x, phydata=0x%x\n",
-		__FUNCTION__, phyaddr, phyreg, phydata);
+		__func__, phyaddr, phyreg, phydata);
 
 	SMC_SELECT_BANK(lp, 2);
 	return phydata;
@@ -883,7 +883,7 @@
 	SMC_SET_MII(lp, SMC_GET_MII(lp) & ~(MII_MCLK|MII_MDOE|MII_MDO));
 
 	DBG(3, "%s: phyaddr=0x%x, phyreg=0x%x, phydata=0x%x\n",
-		__FUNCTION__, phyaddr, phyreg, phydata);
+		__func__, phyaddr, phyreg, phydata);
 
 	SMC_SELECT_BANK(lp, 2);
 }
@@ -896,7 +896,7 @@
 	struct smc_local *lp = netdev_priv(dev);
 	int phyaddr;
 
-	DBG(2, "%s: %s\n", dev->name, __FUNCTION__);
+	DBG(2, "%s: %s\n", dev->name, __func__);
 
 	lp->phy_type = 0;
 
@@ -935,7 +935,7 @@
 	int phyaddr = lp->mii.phy_id;
 	int bmcr, cfg1;
 
-	DBG(3, "%s: %s\n", dev->name, __FUNCTION__);
+	DBG(3, "%s: %s\n", dev->name, __func__);
 
 	/* Enter Link Disable state */
 	cfg1 = smc_phy_read(dev, phyaddr, PHY_CFG1_REG);
@@ -1168,7 +1168,7 @@
 	int phyaddr = lp->mii.phy_id;
 	int phy18;
 
-	DBG(2, "%s: %s\n", dev->name, __FUNCTION__);
+	DBG(2, "%s: %s\n", dev->name, __func__);
 
 	if (lp->phy_type == 0)
 		return;
@@ -1236,7 +1236,7 @@
 	int status, mask, timeout, card_stats;
 	int saved_pointer;
 
-	DBG(3, "%s: %s\n", dev->name, __FUNCTION__);
+	DBG(3, "%s: %s\n", dev->name, __func__);
 
 	spin_lock(&lp->lock);
 
@@ -1358,7 +1358,7 @@
 	void __iomem *ioaddr = lp->base;
 	int status, mask, eph_st, meminfo, fifo;
 
-	DBG(2, "%s: %s\n", dev->name, __FUNCTION__);
+	DBG(2, "%s: %s\n", dev->name, __func__);
 
 	spin_lock_irq(&lp->lock);
 	status = SMC_GET_INT(lp);
@@ -1402,7 +1402,7 @@
 	unsigned char multicast_table[8];
 	int update_multicast = 0;
 
-	DBG(2, "%s: %s\n", dev->name, __FUNCTION__);
+	DBG(2, "%s: %s\n", dev->name, __func__);
 
 	if (dev->flags & IFF_PROMISC) {
 		DBG(2, "%s: RCR_PRMS\n", dev->name);
@@ -1505,7 +1505,7 @@
 {
 	struct smc_local *lp = netdev_priv(dev);
 
-	DBG(2, "%s: %s\n", dev->name, __FUNCTION__);
+	DBG(2, "%s: %s\n", dev->name, __func__);
 
 	/*
 	 * Check that the address is valid.  If its not, refuse
@@ -1513,14 +1513,16 @@
 	 * address using ifconfig eth0 hw ether xx:xx:xx:xx:xx:xx
 	 */
 	if (!is_valid_ether_addr(dev->dev_addr)) {
-		PRINTK("%s: no valid ethernet hw addr\n", __FUNCTION__);
+		PRINTK("%s: no valid ethernet hw addr\n", __func__);
 		return -EINVAL;
 	}
 
 	/* Setup the default Register Modes */
 	lp->tcr_cur_mode = TCR_DEFAULT;
 	lp->rcr_cur_mode = RCR_DEFAULT;
-	lp->rpc_cur_mode = RPC_DEFAULT;
+	lp->rpc_cur_mode = RPC_DEFAULT |
+				lp->cfg.leda << RPC_LSXA_SHFT |
+				lp->cfg.ledb << RPC_LSXB_SHFT;
 
 	/*
 	 * If we are not using a MII interface, we need to
@@ -1557,7 +1559,7 @@
 {
 	struct smc_local *lp = netdev_priv(dev);
 
-	DBG(2, "%s: %s\n", dev->name, __FUNCTION__);
+	DBG(2, "%s: %s\n", dev->name, __func__);
 
 	netif_stop_queue(dev);
 	netif_carrier_off(dev);
@@ -1700,7 +1702,7 @@
 	int timeout = 20;
 	unsigned long cookie;
 
-	DBG(2, "%s: %s\n", CARDNAME, __FUNCTION__);
+	DBG(2, "%s: %s\n", CARDNAME, __func__);
 
 	cookie = probe_irq_on();
 
@@ -1778,7 +1780,7 @@
 	const char *version_string;
 	DECLARE_MAC_BUF(mac);
 
-	DBG(2, "%s: %s\n", CARDNAME, __FUNCTION__);
+	DBG(2, "%s: %s\n", CARDNAME, __func__);
 
 	/* First, see if the high byte is 0x33 */
 	val = SMC_CURRENT_BANK(lp);
@@ -1961,7 +1963,8 @@
 		if (dev->dma != (unsigned char)-1)
 			printk(" DMA %d", dev->dma);
 
-		printk("%s%s\n", nowait ? " [nowait]" : "",
+		printk("%s%s\n",
+			lp->cfg.flags & SMC91X_NOWAIT ? " [nowait]" : "",
 			THROTTLE_TX_PKTS ? " [throttle_tx]" : "");
 
 		if (!is_valid_ether_addr(dev->dev_addr)) {
@@ -2157,6 +2160,11 @@
 		lp->cfg.flags |= (nowait) ? SMC91X_NOWAIT : 0;
 	}
 
+	if (!lp->cfg.leda && !lp->cfg.ledb) {
+		lp->cfg.leda = RPC_LSA_DEFAULT;
+		lp->cfg.ledb = RPC_LSB_DEFAULT;
+	}
+
 	ndev->dma = (unsigned char)-1;
 
 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "smc91x-regs");
diff --git a/drivers/net/smc91x.h b/drivers/net/smc91x.h
index 997e7f1..a07cc93 100644
--- a/drivers/net/smc91x.h
+++ b/drivers/net/smc91x.h
@@ -43,7 +43,8 @@
 #if defined(CONFIG_ARCH_LUBBOCK) ||\
     defined(CONFIG_MACH_MAINSTONE) ||\
     defined(CONFIG_MACH_ZYLONITE) ||\
-    defined(CONFIG_MACH_LITTLETON)
+    defined(CONFIG_MACH_LITTLETON) ||\
+    defined(CONFIG_ARCH_VIPER)
 
 #include <asm/mach-types.h>
 
@@ -446,6 +447,8 @@
 #define SMC_CAN_USE_32BIT	1
 #define SMC_NOWAIT		1
 
+#define SMC_IO_SHIFT		(lp->io_shift)
+
 #define SMC_inb(a, r)		readb((a) + (r))
 #define SMC_inw(a, r)		readw((a) + (r))
 #define SMC_inl(a, r)		readl((a) + (r))
@@ -778,14 +781,6 @@
 #define RPC_ANEG	0x0800	// When 1 PHY is in Auto-Negotiate Mode
 #define RPC_LSXA_SHFT	5	// Bits to shift LS2A,LS1A,LS0A to lsb
 #define RPC_LSXB_SHFT	2	// Bits to get LS2B,LS1B,LS0B to lsb
-#define RPC_LED_100_10	(0x00)	// LED = 100Mbps OR's with 10Mbps link detect
-#define RPC_LED_RES	(0x01)	// LED = Reserved
-#define RPC_LED_10	(0x02)	// LED = 10Mbps link detect
-#define RPC_LED_FD	(0x03)	// LED = Full Duplex Mode
-#define RPC_LED_TX_RX	(0x04)	// LED = TX or RX packet occurred
-#define RPC_LED_100	(0x05)	// LED = 100Mbps link dectect
-#define RPC_LED_TX	(0x06)	// LED = TX packet occurred
-#define RPC_LED_RX	(0x07)	// LED = RX packet occurred
 
 #ifndef RPC_LSA_DEFAULT
 #define RPC_LSA_DEFAULT	RPC_LED_100
@@ -794,7 +789,7 @@
 #define RPC_LSB_DEFAULT RPC_LED_FD
 #endif
 
-#define RPC_DEFAULT (RPC_ANEG | (RPC_LSA_DEFAULT << RPC_LSXA_SHFT) | (RPC_LSB_DEFAULT << RPC_LSXB_SHFT) | RPC_SPEED | RPC_DPLX)
+#define RPC_DEFAULT (RPC_ANEG | RPC_SPEED | RPC_DPLX)
 
 
 /* Bank 0 0x0C is reserved */
diff --git a/drivers/net/sunbmac.c b/drivers/net/sunbmac.c
index 0e4a88d..018d0fc 100644
--- a/drivers/net/sunbmac.c
+++ b/drivers/net/sunbmac.c
@@ -1,7 +1,6 @@
-/* $Id: sunbmac.c,v 1.30 2002/01/15 06:48:55 davem Exp $
- * sunbmac.c: Driver for Sparc BigMAC 100baseT ethernet adapters.
+/* sunbmac.c: Driver for Sparc BigMAC 100baseT ethernet adapters.
  *
- * Copyright (C) 1997, 1998, 1999, 2003 David S. Miller (davem@redhat.com)
+ * Copyright (C) 1997, 1998, 1999, 2003, 2008 David S. Miller (davem@davemloft.net)
  */
 
 #include <linux/module.h>
@@ -23,6 +22,9 @@
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
 #include <linux/bitops.h>
+#include <linux/dma-mapping.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 
 #include <asm/auxio.h>
 #include <asm/byteorder.h>
@@ -32,15 +34,14 @@
 #include <asm/openprom.h>
 #include <asm/oplib.h>
 #include <asm/pgtable.h>
-#include <asm/sbus.h>
 #include <asm/system.h>
 
 #include "sunbmac.h"
 
 #define DRV_NAME	"sunbmac"
-#define DRV_VERSION	"2.0"
-#define DRV_RELDATE	"11/24/03"
-#define DRV_AUTHOR	"David S. Miller (davem@redhat.com)"
+#define DRV_VERSION	"2.1"
+#define DRV_RELDATE	"August 26, 2008"
+#define DRV_AUTHOR	"David S. Miller (davem@davemloft.net)"
 
 static char version[] =
 	DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE " " DRV_AUTHOR "\n";
@@ -96,8 +97,8 @@
 
 static void qec_init(struct bigmac *bp)
 {
+	struct of_device *qec_op = bp->qec_op;
 	void __iomem *gregs = bp->gregs;
-	struct sbus_dev *qec_sdev = bp->qec_sdev;
 	u8 bsizes = bp->bigmac_bursts;
 	u32 regval;
 
@@ -112,13 +113,13 @@
 	sbus_writel(GLOB_PSIZE_2048, gregs + GLOB_PSIZE);
 
 	/* All of memsize is given to bigmac. */
-	sbus_writel(qec_sdev->reg_addrs[1].reg_size,
+	sbus_writel(resource_size(&qec_op->resource[1]),
 		    gregs + GLOB_MSIZE);
 
 	/* Half to the transmitter, half to the receiver. */
-	sbus_writel(qec_sdev->reg_addrs[1].reg_size >> 1,
+	sbus_writel(resource_size(&qec_op->resource[1]) >> 1,
 		    gregs + GLOB_TSIZE);
-	sbus_writel(qec_sdev->reg_addrs[1].reg_size >> 1,
+	sbus_writel(resource_size(&qec_op->resource[1]) >> 1,
 		    gregs + GLOB_RSIZE);
 }
 
@@ -239,9 +240,10 @@
 		skb_reserve(skb, 34);
 
 		bb->be_rxd[i].rx_addr =
-			sbus_map_single(bp->bigmac_sdev, skb->data,
-					RX_BUF_ALLOC_SIZE - 34,
-					SBUS_DMA_FROMDEVICE);
+			dma_map_single(&bp->bigmac_op->dev,
+				       skb->data,
+				       RX_BUF_ALLOC_SIZE - 34,
+				       DMA_FROM_DEVICE);
 		bb->be_rxd[i].rx_flags =
 			(RXD_OWN | ((RX_BUF_ALLOC_SIZE - 34) & RXD_LENGTH));
 	}
@@ -776,9 +778,9 @@
 		skb = bp->tx_skbs[elem];
 		bp->enet_stats.tx_packets++;
 		bp->enet_stats.tx_bytes += skb->len;
-		sbus_unmap_single(bp->bigmac_sdev,
-				  this->tx_addr, skb->len,
-				  SBUS_DMA_TODEVICE);
+		dma_unmap_single(&bp->bigmac_op->dev,
+				 this->tx_addr, skb->len,
+				 DMA_TO_DEVICE);
 
 		DTX(("skb(%p) ", skb));
 		bp->tx_skbs[elem] = NULL;
@@ -831,18 +833,19 @@
 				drops++;
 				goto drop_it;
 			}
-			sbus_unmap_single(bp->bigmac_sdev,
-					  this->rx_addr,
-					  RX_BUF_ALLOC_SIZE - 34,
-					  SBUS_DMA_FROMDEVICE);
+			dma_unmap_single(&bp->bigmac_op->dev,
+					 this->rx_addr,
+					 RX_BUF_ALLOC_SIZE - 34,
+					 DMA_FROM_DEVICE);
 			bp->rx_skbs[elem] = new_skb;
 			new_skb->dev = bp->dev;
 			skb_put(new_skb, ETH_FRAME_LEN);
 			skb_reserve(new_skb, 34);
-			this->rx_addr = sbus_map_single(bp->bigmac_sdev,
-							new_skb->data,
-							RX_BUF_ALLOC_SIZE - 34,
-							SBUS_DMA_FROMDEVICE);
+			this->rx_addr =
+				dma_map_single(&bp->bigmac_op->dev,
+					       new_skb->data,
+					       RX_BUF_ALLOC_SIZE - 34,
+					       DMA_FROM_DEVICE);
 			this->rx_flags =
 				(RXD_OWN | ((RX_BUF_ALLOC_SIZE - 34) & RXD_LENGTH));
 
@@ -857,13 +860,13 @@
 			}
 			skb_reserve(copy_skb, 2);
 			skb_put(copy_skb, len);
-			sbus_dma_sync_single_for_cpu(bp->bigmac_sdev,
-						     this->rx_addr, len,
-						     SBUS_DMA_FROMDEVICE);
+			dma_sync_single_for_cpu(&bp->bigmac_op->dev,
+						this->rx_addr, len,
+						DMA_FROM_DEVICE);
 			skb_copy_to_linear_data(copy_skb, (unsigned char *)skb->data, len);
-			sbus_dma_sync_single_for_device(bp->bigmac_sdev,
-							this->rx_addr, len,
-							SBUS_DMA_FROMDEVICE);
+			dma_sync_single_for_device(&bp->bigmac_op->dev,
+						   this->rx_addr, len,
+						   DMA_FROM_DEVICE);
 
 			/* Reuse original ring buffer. */
 			this->rx_flags =
@@ -959,7 +962,8 @@
 	u32 mapping;
 
 	len = skb->len;
-	mapping = sbus_map_single(bp->bigmac_sdev, skb->data, len, SBUS_DMA_TODEVICE);
+	mapping = dma_map_single(&bp->bigmac_op->dev, skb->data,
+				 len, DMA_TO_DEVICE);
 
 	/* Avoid a race... */
 	spin_lock_irq(&bp->lock);
@@ -1051,12 +1055,8 @@
 /* Ethtool support... */
 static void bigmac_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
 {
-	struct bigmac *bp = dev->priv;
-
 	strcpy(info->driver, "sunbmac");
 	strcpy(info->version, "2.0");
-	sprintf(info->bus_info, "SBUS:%d",
-		bp->qec_sdev->slot);
 }
 
 static u32 bigmac_get_link(struct net_device *dev)
@@ -1075,14 +1075,15 @@
 	.get_link		= bigmac_get_link,
 };
 
-static int __devinit bigmac_ether_init(struct sbus_dev *qec_sdev)
+static int __devinit bigmac_ether_init(struct of_device *op,
+				       struct of_device *qec_op)
 {
-	struct net_device *dev;
 	static int version_printed;
-	struct bigmac *bp;
+	struct net_device *dev;
 	u8 bsizes, bsizes_more;
-	int i;
 	DECLARE_MAC_BUF(mac);
+	struct bigmac *bp;
+	int i;
 
 	/* Get a new device struct for this interface. */
 	dev = alloc_etherdev(sizeof(struct bigmac));
@@ -1092,32 +1093,21 @@
 	if (version_printed++ == 0)
 		printk(KERN_INFO "%s", version);
 
-	dev->base_addr = (long) qec_sdev;
 	for (i = 0; i < 6; i++)
 		dev->dev_addr[i] = idprom->id_ethaddr[i];
 
 	/* Setup softc, with backpointers to QEC and BigMAC SBUS device structs. */
-	bp = dev->priv;
-	bp->qec_sdev = qec_sdev;
-	bp->bigmac_sdev = qec_sdev->child;
+	bp = netdev_priv(dev);
+	bp->qec_op = qec_op;
+	bp->bigmac_op = op;
 
-	SET_NETDEV_DEV(dev, &bp->bigmac_sdev->ofdev.dev);
+	SET_NETDEV_DEV(dev, &op->dev);
 
 	spin_lock_init(&bp->lock);
 
-	/* Verify the registers we expect, are actually there. */
-	if ((bp->bigmac_sdev->num_registers != 3) ||
-	   (bp->qec_sdev->num_registers != 2)) {
-		printk(KERN_ERR "BIGMAC: Device does not have 2 and 3 regs, it has %d and %d.\n",
-		       bp->qec_sdev->num_registers,
-		       bp->bigmac_sdev->num_registers);
-		printk(KERN_ERR "BIGMAC: Would you like that for here or to go?\n");
-		goto fail_and_cleanup;
-	}
-
 	/* Map in QEC global control registers. */
-	bp->gregs = sbus_ioremap(&bp->qec_sdev->resource[0], 0,
-				 GLOB_REG_SIZE, "BigMAC QEC GLobal Regs");
+	bp->gregs = of_ioremap(&qec_op->resource[0], 0,
+			       GLOB_REG_SIZE, "BigMAC QEC GLobal Regs");
 	if (!bp->gregs) {
 		printk(KERN_ERR "BIGMAC: Cannot map QEC global registers.\n");
 		goto fail_and_cleanup;
@@ -1134,13 +1124,8 @@
 		goto fail_and_cleanup;
 
 	/* Get supported SBUS burst sizes. */
-	bsizes = prom_getintdefault(bp->qec_sdev->prom_node,
-				    "burst-sizes",
-				    0xff);
-
-	bsizes_more = prom_getintdefault(bp->qec_sdev->bus->prom_node,
-					 "burst-sizes",
-					 0xff);
+	bsizes = of_getintprop_default(qec_op->node, "burst-sizes", 0xff);
+	bsizes_more = of_getintprop_default(qec_op->node, "burst-sizes", 0xff);
 
 	bsizes &= 0xff;
 	if (bsizes_more != 0xff)
@@ -1154,16 +1139,16 @@
 	qec_init(bp);
 
 	/* Map in the BigMAC channel registers. */
-	bp->creg = sbus_ioremap(&bp->bigmac_sdev->resource[0], 0,
-				CREG_REG_SIZE, "BigMAC QEC Channel Regs");
+	bp->creg = of_ioremap(&op->resource[0], 0,
+			      CREG_REG_SIZE, "BigMAC QEC Channel Regs");
 	if (!bp->creg) {
 		printk(KERN_ERR "BIGMAC: Cannot map QEC channel registers.\n");
 		goto fail_and_cleanup;
 	}
 
 	/* Map in the BigMAC control registers. */
-	bp->bregs = sbus_ioremap(&bp->bigmac_sdev->resource[1], 0,
-				 BMAC_REG_SIZE, "BigMAC Primary Regs");
+	bp->bregs = of_ioremap(&op->resource[1], 0,
+			       BMAC_REG_SIZE, "BigMAC Primary Regs");
 	if (!bp->bregs) {
 		printk(KERN_ERR "BIGMAC: Cannot map BigMAC primary registers.\n");
 		goto fail_and_cleanup;
@@ -1172,8 +1157,8 @@
 	/* Map in the BigMAC transceiver registers, this is how you poke at
 	 * the BigMAC's PHY.
 	 */
-	bp->tregs = sbus_ioremap(&bp->bigmac_sdev->resource[2], 0,
-				 TCVR_REG_SIZE, "BigMAC Transceiver Regs");
+	bp->tregs = of_ioremap(&op->resource[2], 0,
+			       TCVR_REG_SIZE, "BigMAC Transceiver Regs");
 	if (!bp->tregs) {
 		printk(KERN_ERR "BIGMAC: Cannot map BigMAC transceiver registers.\n");
 		goto fail_and_cleanup;
@@ -1183,17 +1168,17 @@
 	bigmac_stop(bp);
 
 	/* Allocate transmit/receive descriptor DVMA block. */
-	bp->bmac_block = sbus_alloc_consistent(bp->bigmac_sdev,
-					       PAGE_SIZE,
-					       &bp->bblock_dvma);
+	bp->bmac_block = dma_alloc_coherent(&bp->bigmac_op->dev,
+					    PAGE_SIZE,
+					    &bp->bblock_dvma, GFP_ATOMIC);
 	if (bp->bmac_block == NULL || bp->bblock_dvma == 0) {
 		printk(KERN_ERR "BIGMAC: Cannot allocate consistent DMA.\n");
 		goto fail_and_cleanup;
 	}
 
 	/* Get the board revision of this BigMAC. */
-	bp->board_rev = prom_getintdefault(bp->bigmac_sdev->prom_node,
-					   "board-version", 1);
+	bp->board_rev = of_getintprop_default(bp->bigmac_op->node,
+					      "board-version", 1);
 
 	/* Init auto-negotiation timer state. */
 	init_timer(&bp->bigmac_timer);
@@ -1217,7 +1202,7 @@
 	dev->watchdog_timeo = 5*HZ;
 
 	/* Finish net device registration. */
-	dev->irq = bp->bigmac_sdev->irqs[0];
+	dev->irq = bp->bigmac_op->irqs[0];
 	dev->dma = 0;
 
 	if (register_netdev(dev)) {
@@ -1225,7 +1210,7 @@
 		goto fail_and_cleanup;
 	}
 
-	dev_set_drvdata(&bp->bigmac_sdev->ofdev.dev, bp);
+	dev_set_drvdata(&bp->bigmac_op->dev, bp);
 
 	printk(KERN_INFO "%s: BigMAC 100baseT Ethernet %s\n",
 	       dev->name, print_mac(mac, dev->dev_addr));
@@ -1236,66 +1221,67 @@
 	/* Something went wrong, undo whatever we did so far. */
 	/* Free register mappings if any. */
 	if (bp->gregs)
-		sbus_iounmap(bp->gregs, GLOB_REG_SIZE);
+		of_iounmap(&qec_op->resource[0], bp->gregs, GLOB_REG_SIZE);
 	if (bp->creg)
-		sbus_iounmap(bp->creg, CREG_REG_SIZE);
+		of_iounmap(&op->resource[0], bp->creg, CREG_REG_SIZE);
 	if (bp->bregs)
-		sbus_iounmap(bp->bregs, BMAC_REG_SIZE);
+		of_iounmap(&op->resource[1], bp->bregs, BMAC_REG_SIZE);
 	if (bp->tregs)
-		sbus_iounmap(bp->tregs, TCVR_REG_SIZE);
+		of_iounmap(&op->resource[2], bp->tregs, TCVR_REG_SIZE);
 
 	if (bp->bmac_block)
-		sbus_free_consistent(bp->bigmac_sdev,
-				     PAGE_SIZE,
-				     bp->bmac_block,
-				     bp->bblock_dvma);
+		dma_free_coherent(&bp->bigmac_op->dev,
+				  PAGE_SIZE,
+				  bp->bmac_block,
+				  bp->bblock_dvma);
 
 	/* This also frees the co-located 'dev->priv' */
 	free_netdev(dev);
 	return -ENODEV;
 }
 
-/* QEC can be the parent of either QuadEthernet or
- * a BigMAC.  We want the latter.
+/* QEC can be the parent of either QuadEthernet or a BigMAC.  We want
+ * the latter.
  */
-static int __devinit bigmac_sbus_probe(struct of_device *dev, const struct of_device_id *match)
+static int __devinit bigmac_sbus_probe(struct of_device *op,
+				       const struct of_device_id *match)
 {
-	struct sbus_dev *sdev = to_sbus_device(&dev->dev);
-	struct device_node *dp = dev->node;
+	struct device *parent = op->dev.parent;
+	struct of_device *qec_op;
 
-	if (!strcmp(dp->name, "be"))
-		sdev = sdev->parent;
+	qec_op = to_of_device(parent);
 
-	return bigmac_ether_init(sdev);
+	return bigmac_ether_init(op, qec_op);
 }
 
-static int __devexit bigmac_sbus_remove(struct of_device *dev)
+static int __devexit bigmac_sbus_remove(struct of_device *op)
 {
-	struct bigmac *bp = dev_get_drvdata(&dev->dev);
+	struct bigmac *bp = dev_get_drvdata(&op->dev);
+	struct device *parent = op->dev.parent;
 	struct net_device *net_dev = bp->dev;
+	struct of_device *qec_op;
 
-	unregister_netdevice(net_dev);
+	qec_op = to_of_device(parent);
 
-	sbus_iounmap(bp->gregs, GLOB_REG_SIZE);
-	sbus_iounmap(bp->creg, CREG_REG_SIZE);
-	sbus_iounmap(bp->bregs, BMAC_REG_SIZE);
-	sbus_iounmap(bp->tregs, TCVR_REG_SIZE);
-	sbus_free_consistent(bp->bigmac_sdev,
-			     PAGE_SIZE,
-			     bp->bmac_block,
-			     bp->bblock_dvma);
+	unregister_netdev(net_dev);
+
+	of_iounmap(&qec_op->resource[0], bp->gregs, GLOB_REG_SIZE);
+	of_iounmap(&op->resource[0], bp->creg, CREG_REG_SIZE);
+	of_iounmap(&op->resource[1], bp->bregs, BMAC_REG_SIZE);
+	of_iounmap(&op->resource[2], bp->tregs, TCVR_REG_SIZE);
+	dma_free_coherent(&op->dev,
+			  PAGE_SIZE,
+			  bp->bmac_block,
+			  bp->bblock_dvma);
 
 	free_netdev(net_dev);
 
-	dev_set_drvdata(&dev->dev, NULL);
+	dev_set_drvdata(&op->dev, NULL);
 
 	return 0;
 }
 
-static struct of_device_id bigmac_sbus_match[] = {
-	{
-		.name = "qec",
-	},
+static const struct of_device_id bigmac_sbus_match[] = {
 	{
 		.name = "be",
 	},
@@ -1313,7 +1299,7 @@
 
 static int __init bigmac_init(void)
 {
-	return of_register_driver(&bigmac_sbus_driver, &sbus_bus_type);
+	return of_register_driver(&bigmac_sbus_driver, &of_bus_type);
 }
 
 static void __exit bigmac_exit(void)
diff --git a/drivers/net/sunbmac.h b/drivers/net/sunbmac.h
index b563d3c..8840bc0 100644
--- a/drivers/net/sunbmac.h
+++ b/drivers/net/sunbmac.h
@@ -329,8 +329,8 @@
 	unsigned int		timer_ticks;
 
 	struct net_device_stats	enet_stats;
-	struct sbus_dev		*qec_sdev;
-	struct sbus_dev		*bigmac_sdev;
+	struct of_device	*qec_op;
+	struct of_device	*bigmac_op;
 	struct net_device	*dev;
 };
 
diff --git a/drivers/net/sundance.c b/drivers/net/sundance.c
index 7d5561b..f860ea1 100644
--- a/drivers/net/sundance.c
+++ b/drivers/net/sundance.c
@@ -409,6 +409,7 @@
 static int  eeprom_read(void __iomem *ioaddr, int location);
 static int  mdio_read(struct net_device *dev, int phy_id, int location);
 static void mdio_write(struct net_device *dev, int phy_id, int location, int value);
+static int  mdio_wait_link(struct net_device *dev, int wait);
 static int  netdev_open(struct net_device *dev);
 static void check_duplex(struct net_device *dev);
 static void netdev_timer(unsigned long data);
@@ -785,6 +786,24 @@
 	return;
 }
 
+static int mdio_wait_link(struct net_device *dev, int wait)
+{
+	int bmsr;
+	int phy_id;
+	struct netdev_private *np;
+
+	np = netdev_priv(dev);
+	phy_id = np->phys[0];
+
+	do {
+		bmsr = mdio_read(dev, phy_id, MII_BMSR);
+		if (bmsr & 0x0004)
+			return 0;
+		mdelay(1);
+	} while (--wait > 0);
+	return -1;
+}
+
 static int netdev_open(struct net_device *dev)
 {
 	struct netdev_private *np = netdev_priv(dev);
@@ -1393,41 +1412,51 @@
 	int speed;
 
 	if (intr_status & LinkChange) {
-		if (np->an_enable) {
-			mii_advertise = mdio_read (dev, np->phys[0], MII_ADVERTISE);
-			mii_lpa= mdio_read (dev, np->phys[0], MII_LPA);
-			mii_advertise &= mii_lpa;
-			printk (KERN_INFO "%s: Link changed: ", dev->name);
-			if (mii_advertise & ADVERTISE_100FULL) {
-				np->speed = 100;
-				printk ("100Mbps, full duplex\n");
-			} else if (mii_advertise & ADVERTISE_100HALF) {
-				np->speed = 100;
-				printk ("100Mbps, half duplex\n");
-			} else if (mii_advertise & ADVERTISE_10FULL) {
-				np->speed = 10;
-				printk ("10Mbps, full duplex\n");
-			} else if (mii_advertise & ADVERTISE_10HALF) {
-				np->speed = 10;
-				printk ("10Mbps, half duplex\n");
-			} else
-				printk ("\n");
+		if (mdio_wait_link(dev, 10) == 0) {
+			printk(KERN_INFO "%s: Link up\n", dev->name);
+			if (np->an_enable) {
+				mii_advertise = mdio_read(dev, np->phys[0],
+							   MII_ADVERTISE);
+				mii_lpa = mdio_read(dev, np->phys[0], MII_LPA);
+				mii_advertise &= mii_lpa;
+				printk(KERN_INFO "%s: Link changed: ",
+					dev->name);
+				if (mii_advertise & ADVERTISE_100FULL) {
+					np->speed = 100;
+					printk("100Mbps, full duplex\n");
+				} else if (mii_advertise & ADVERTISE_100HALF) {
+					np->speed = 100;
+					printk("100Mbps, half duplex\n");
+				} else if (mii_advertise & ADVERTISE_10FULL) {
+					np->speed = 10;
+					printk("10Mbps, full duplex\n");
+				} else if (mii_advertise & ADVERTISE_10HALF) {
+					np->speed = 10;
+					printk("10Mbps, half duplex\n");
+				} else
+					printk("\n");
 
+			} else {
+				mii_ctl = mdio_read(dev, np->phys[0], MII_BMCR);
+				speed = (mii_ctl & BMCR_SPEED100) ? 100 : 10;
+				np->speed = speed;
+				printk(KERN_INFO "%s: Link changed: %dMbps ,",
+					dev->name, speed);
+				printk("%s duplex.\n",
+					(mii_ctl & BMCR_FULLDPLX) ?
+						"full" : "half");
+			}
+			check_duplex(dev);
+			if (np->flowctrl && np->mii_if.full_duplex) {
+				iowrite16(ioread16(ioaddr + MulticastFilter1+2) | 0x0200,
+					ioaddr + MulticastFilter1+2);
+				iowrite16(ioread16(ioaddr + MACCtrl0) | EnbFlowCtrl,
+					ioaddr + MACCtrl0);
+			}
+			netif_carrier_on(dev);
 		} else {
-			mii_ctl = mdio_read (dev, np->phys[0], MII_BMCR);
-			speed = (mii_ctl & BMCR_SPEED100) ? 100 : 10;
-			np->speed = speed;
-			printk (KERN_INFO "%s: Link changed: %dMbps ,",
-				dev->name, speed);
-			printk ("%s duplex.\n", (mii_ctl & BMCR_FULLDPLX) ?
-				"full" : "half");
-		}
-		check_duplex (dev);
-		if (np->flowctrl && np->mii_if.full_duplex) {
-			iowrite16(ioread16(ioaddr + MulticastFilter1+2) | 0x0200,
-				ioaddr + MulticastFilter1+2);
-			iowrite16(ioread16(ioaddr + MACCtrl0) | EnbFlowCtrl,
-				ioaddr + MACCtrl0);
+			printk(KERN_INFO "%s: Link down\n", dev->name);
+			netif_carrier_off(dev);
 		}
 	}
 	if (intr_status & StatsMax) {
diff --git a/drivers/net/sunhme.c b/drivers/net/sunhme.c
index b79d5f0..f1ebeb5 100644
--- a/drivers/net/sunhme.c
+++ b/drivers/net/sunhme.c
@@ -3,7 +3,7 @@
  *           "Happy Meal Ethernet" found on SunSwift SBUS cards.
  *
  * Copyright (C) 1996, 1998, 1999, 2002, 2003,
-		 2006 David S. Miller (davem@davemloft.net)
+ *		2006, 2008 David S. Miller (davem@davemloft.net)
  *
  * Changes :
  * 2000/11/11 Willy Tarreau <willy AT meta-x.org>
@@ -34,6 +34,7 @@
 #include <linux/skbuff.h>
 #include <linux/mm.h>
 #include <linux/bitops.h>
+#include <linux/dma-mapping.h>
 
 #include <asm/system.h>
 #include <asm/io.h>
@@ -41,8 +42,9 @@
 #include <asm/byteorder.h>
 
 #ifdef CONFIG_SPARC
+#include <linux/of.h>
+#include <linux/of_device.h>
 #include <asm/idprom.h>
-#include <asm/sbus.h>
 #include <asm/openprom.h>
 #include <asm/oplib.h>
 #include <asm/prom.h>
@@ -60,8 +62,8 @@
 #include "sunhme.h"
 
 #define DRV_NAME	"sunhme"
-#define DRV_VERSION	"3.00"
-#define DRV_RELDATE	"June 23, 2006"
+#define DRV_VERSION	"3.10"
+#define DRV_RELDATE	"August 26, 2008"
 #define DRV_AUTHOR	"David S. Miller (davem@davemloft.net)"
 
 static char version[] =
@@ -251,13 +253,13 @@
 #define hme_read_desc32(__hp, __p) \
 	((__hp)->read_desc32(__p))
 #define hme_dma_map(__hp, __ptr, __size, __dir) \
-	((__hp)->dma_map((__hp)->happy_dev, (__ptr), (__size), (__dir)))
+	((__hp)->dma_map((__hp)->dma_dev, (__ptr), (__size), (__dir)))
 #define hme_dma_unmap(__hp, __addr, __size, __dir) \
-	((__hp)->dma_unmap((__hp)->happy_dev, (__addr), (__size), (__dir)))
+	((__hp)->dma_unmap((__hp)->dma_dev, (__addr), (__size), (__dir)))
 #define hme_dma_sync_for_cpu(__hp, __addr, __size, __dir) \
-	((__hp)->dma_sync_for_cpu((__hp)->happy_dev, (__addr), (__size), (__dir)))
+	((__hp)->dma_sync_for_cpu((__hp)->dma_dev, (__addr), (__size), (__dir)))
 #define hme_dma_sync_for_device(__hp, __addr, __size, __dir) \
-	((__hp)->dma_sync_for_device((__hp)->happy_dev, (__addr), (__size), (__dir)))
+	((__hp)->dma_sync_for_device((__hp)->dma_dev, (__addr), (__size), (__dir)))
 #else
 #ifdef CONFIG_SBUS
 /* SBUS only compilation */
@@ -277,13 +279,13 @@
 } while(0)
 #define hme_read_desc32(__hp, __p)	((__force u32)(hme32)*(__p))
 #define hme_dma_map(__hp, __ptr, __size, __dir) \
-	sbus_map_single((__hp)->happy_dev, (__ptr), (__size), (__dir))
+	dma_map_single((__hp)->dma_dev, (__ptr), (__size), (__dir))
 #define hme_dma_unmap(__hp, __addr, __size, __dir) \
-	sbus_unmap_single((__hp)->happy_dev, (__addr), (__size), (__dir))
+	dma_unmap_single((__hp)->dma_dev, (__addr), (__size), (__dir))
 #define hme_dma_sync_for_cpu(__hp, __addr, __size, __dir) \
-	sbus_dma_sync_single_for_cpu((__hp)->happy_dev, (__addr), (__size), (__dir))
+	dma_dma_sync_single_for_cpu((__hp)->dma_dev, (__addr), (__size), (__dir))
 #define hme_dma_sync_for_device(__hp, __addr, __size, __dir) \
-	sbus_dma_sync_single_for_device((__hp)->happy_dev, (__addr), (__size), (__dir))
+	dma_dma_sync_single_for_device((__hp)->dma_dev, (__addr), (__size), (__dir))
 #else
 /* PCI only compilation */
 #define hme_write32(__hp, __reg, __val) \
@@ -305,36 +307,17 @@
 	return le32_to_cpup((__le32 *)p);
 }
 #define hme_dma_map(__hp, __ptr, __size, __dir) \
-	pci_map_single((__hp)->happy_dev, (__ptr), (__size), (__dir))
+	pci_map_single((__hp)->dma_dev, (__ptr), (__size), (__dir))
 #define hme_dma_unmap(__hp, __addr, __size, __dir) \
-	pci_unmap_single((__hp)->happy_dev, (__addr), (__size), (__dir))
+	pci_unmap_single((__hp)->dma_dev, (__addr), (__size), (__dir))
 #define hme_dma_sync_for_cpu(__hp, __addr, __size, __dir) \
-	pci_dma_sync_single_for_cpu((__hp)->happy_dev, (__addr), (__size), (__dir))
+	pci_dma_sync_single_for_cpu((__hp)->dma_dev, (__addr), (__size), (__dir))
 #define hme_dma_sync_for_device(__hp, __addr, __size, __dir) \
-	pci_dma_sync_single_for_device((__hp)->happy_dev, (__addr), (__size), (__dir))
+	pci_dma_sync_single_for_device((__hp)->dma_dev, (__addr), (__size), (__dir))
 #endif
 #endif
 
 
-#ifdef SBUS_DMA_BIDIRECTIONAL
-#	define DMA_BIDIRECTIONAL	SBUS_DMA_BIDIRECTIONAL
-#else
-#	define DMA_BIDIRECTIONAL	0
-#endif
-
-#ifdef SBUS_DMA_FROMDEVICE
-#	define DMA_FROMDEVICE		SBUS_DMA_FROMDEVICE
-#else
-#	define DMA_TODEVICE		1
-#endif
-
-#ifdef SBUS_DMA_TODEVICE
-#	define DMA_TODEVICE		SBUS_DMA_TODEVICE
-#else
-#	define DMA_FROMDEVICE		2
-#endif
-
-
 /* Oh yes, the MIF BitBang is mighty fun to program.  BitBucket is more like it. */
 static void BB_PUT_BIT(struct happy_meal *hp, void __iomem *tregs, int bit)
 {
@@ -1224,7 +1207,8 @@
 
 			rxd = &hp->happy_block->happy_meal_rxd[i];
 			dma_addr = hme_read_desc32(hp, &rxd->rx_addr);
-			hme_dma_unmap(hp, dma_addr, RX_BUF_ALLOC_SIZE, DMA_FROMDEVICE);
+			dma_unmap_single(hp->dma_dev, dma_addr,
+					 RX_BUF_ALLOC_SIZE, DMA_FROM_DEVICE);
 			dev_kfree_skb_any(skb);
 			hp->rx_skbs[i] = NULL;
 		}
@@ -1242,10 +1226,10 @@
 			for (frag = 0; frag <= skb_shinfo(skb)->nr_frags; frag++) {
 				txd = &hp->happy_block->happy_meal_txd[i];
 				dma_addr = hme_read_desc32(hp, &txd->tx_addr);
-				hme_dma_unmap(hp, dma_addr,
-					      (hme_read_desc32(hp, &txd->tx_flags)
-					       & TXFLAG_SIZE),
-					      DMA_TODEVICE);
+				dma_unmap_single(hp->dma_dev, dma_addr,
+						 (hme_read_desc32(hp, &txd->tx_flags)
+						  & TXFLAG_SIZE),
+						 DMA_TO_DEVICE);
 
 				if (frag != skb_shinfo(skb)->nr_frags)
 					i++;
@@ -1287,7 +1271,8 @@
 		skb_put(skb, (ETH_FRAME_LEN + RX_OFFSET + 4));
 		hme_write_rxd(hp, &hb->happy_meal_rxd[i],
 			      (RXFLAG_OWN | ((RX_BUF_ALLOC_SIZE - RX_OFFSET) << 16)),
-			      hme_dma_map(hp, skb->data, RX_BUF_ALLOC_SIZE, DMA_FROMDEVICE));
+			      dma_map_single(hp->dma_dev, skb->data, RX_BUF_ALLOC_SIZE,
+					     DMA_FROM_DEVICE));
 		skb_reserve(skb, RX_OFFSET);
 	}
 
@@ -1593,7 +1578,7 @@
 	if ((hp->happy_bursts & DMA_BURST64) &&
 	    ((hp->happy_flags & HFLAG_PCI) != 0
 #ifdef CONFIG_SBUS
-	     || sbus_can_burst64(hp->happy_dev)
+	     || sbus_can_burst64()
 #endif
 	     || 0)) {
 		u32 gcfg = GREG_CFG_BURST64;
@@ -1603,11 +1588,13 @@
 		 * do not.  -DaveM
 		 */
 #ifdef CONFIG_SBUS
-		if ((hp->happy_flags & HFLAG_PCI) == 0 &&
-		    sbus_can_dma_64bit(hp->happy_dev)) {
-			sbus_set_sbus64(hp->happy_dev,
-					hp->happy_bursts);
-			gcfg |= GREG_CFG_64BIT;
+		if ((hp->happy_flags & HFLAG_PCI) == 0) {
+			struct of_device *op = hp->happy_dev;
+			if (sbus_can_dma_64bit()) {
+				sbus_set_sbus64(&op->dev,
+						hp->happy_bursts);
+				gcfg |= GREG_CFG_64BIT;
+			}
 		}
 #endif
 
@@ -1966,7 +1953,7 @@
 			dma_len = hme_read_desc32(hp, &this->tx_flags);
 
 			dma_len &= TXFLAG_SIZE;
-			hme_dma_unmap(hp, dma_addr, dma_len, DMA_TODEVICE);
+			dma_unmap_single(hp->dma_dev, dma_addr, dma_len, DMA_TO_DEVICE);
 
 			elem = NEXT_TX(elem);
 			this = &txbase[elem];
@@ -2044,13 +2031,14 @@
 				drops++;
 				goto drop_it;
 			}
-			hme_dma_unmap(hp, dma_addr, RX_BUF_ALLOC_SIZE, DMA_FROMDEVICE);
+			dma_unmap_single(hp->dma_dev, dma_addr, RX_BUF_ALLOC_SIZE, DMA_FROM_DEVICE);
 			hp->rx_skbs[elem] = new_skb;
 			new_skb->dev = dev;
 			skb_put(new_skb, (ETH_FRAME_LEN + RX_OFFSET + 4));
 			hme_write_rxd(hp, this,
 				      (RXFLAG_OWN|((RX_BUF_ALLOC_SIZE-RX_OFFSET)<<16)),
-				      hme_dma_map(hp, new_skb->data, RX_BUF_ALLOC_SIZE, DMA_FROMDEVICE));
+				      dma_map_single(hp->dma_dev, new_skb->data, RX_BUF_ALLOC_SIZE,
+						     DMA_FROM_DEVICE));
 			skb_reserve(new_skb, RX_OFFSET);
 
 			/* Trim the original skb for the netif. */
@@ -2065,10 +2053,9 @@
 
 			skb_reserve(copy_skb, 2);
 			skb_put(copy_skb, len);
-			hme_dma_sync_for_cpu(hp, dma_addr, len, DMA_FROMDEVICE);
+			dma_sync_single_for_cpu(hp->dma_dev, dma_addr, len, DMA_FROM_DEVICE);
 			skb_copy_from_linear_data(skb, copy_skb->data, len);
-			hme_dma_sync_for_device(hp, dma_addr, len, DMA_FROMDEVICE);
-
+			dma_sync_single_for_device(hp->dma_dev, dma_addr, len, DMA_FROM_DEVICE);
 			/* Reuse original ring buffer. */
 			hme_write_rxd(hp, this,
 				      (RXFLAG_OWN|((RX_BUF_ALLOC_SIZE-RX_OFFSET)<<16)),
@@ -2300,7 +2287,7 @@
 		u32 mapping, len;
 
 		len = skb->len;
-		mapping = hme_dma_map(hp, skb->data, len, DMA_TODEVICE);
+		mapping = dma_map_single(hp->dma_dev, skb->data, len, DMA_TO_DEVICE);
 		tx_flags |= (TXFLAG_SOP | TXFLAG_EOP);
 		hme_write_txd(hp, &hp->happy_block->happy_meal_txd[entry],
 			      (tx_flags | (len & TXFLAG_SIZE)),
@@ -2314,7 +2301,8 @@
 		 * Otherwise we could race with the device.
 		 */
 		first_len = skb_headlen(skb);
-		first_mapping = hme_dma_map(hp, skb->data, first_len, DMA_TODEVICE);
+		first_mapping = dma_map_single(hp->dma_dev, skb->data, first_len,
+					       DMA_TO_DEVICE);
 		entry = NEXT_TX(entry);
 
 		for (frag = 0; frag < skb_shinfo(skb)->nr_frags; frag++) {
@@ -2322,10 +2310,9 @@
 			u32 len, mapping, this_txflags;
 
 			len = this_frag->size;
-			mapping = hme_dma_map(hp,
-					      ((void *) page_address(this_frag->page) +
-					       this_frag->page_offset),
-					      len, DMA_TODEVICE);
+			mapping = dma_map_page(hp->dma_dev, this_frag->page,
+					       this_frag->page_offset, len,
+					       DMA_TO_DEVICE);
 			this_txflags = tx_flags;
 			if (frag == skb_shinfo(skb)->nr_frags - 1)
 				this_txflags |= TXFLAG_EOP;
@@ -2493,9 +2480,12 @@
 	}
 #ifdef CONFIG_SBUS
 	else {
-		struct sbus_dev *sdev = hp->happy_dev;
-		sprintf(info->bus_info, "SBUS:%d",
-			sdev->slot);
+		const struct linux_prom_registers *regs;
+		struct of_device *op = hp->happy_dev;
+		regs = of_get_property(op->node, "regs", NULL);
+		if (regs)
+			sprintf(info->bus_info, "SBUS:%d",
+				regs->which_io);
 	}
 #endif
 }
@@ -2521,63 +2511,21 @@
 static int hme_version_printed;
 
 #ifdef CONFIG_SBUS
-void __devinit quattro_get_ranges(struct quattro *qp)
-{
-	struct sbus_dev *sdev = qp->quattro_dev;
-	int err;
-
-	err = prom_getproperty(sdev->prom_node,
-			       "ranges",
-			       (char *)&qp->ranges[0],
-			       sizeof(qp->ranges));
-	if (err == 0 || err == -1) {
-		qp->nranges = 0;
-		return;
-	}
-	qp->nranges = (err / sizeof(struct linux_prom_ranges));
-}
-
-static void __devinit quattro_apply_ranges(struct quattro *qp, struct happy_meal *hp)
-{
-	struct sbus_dev *sdev = hp->happy_dev;
-	int rng;
-
-	for (rng = 0; rng < qp->nranges; rng++) {
-		struct linux_prom_ranges *rngp = &qp->ranges[rng];
-		int reg;
-
-		for (reg = 0; reg < 5; reg++) {
-			if (sdev->reg_addrs[reg].which_io ==
-			    rngp->ot_child_space)
-				break;
-		}
-		if (reg == 5)
-			continue;
-
-		sdev->reg_addrs[reg].which_io = rngp->ot_parent_space;
-		sdev->reg_addrs[reg].phys_addr += rngp->ot_parent_base;
-	}
-}
-
 /* Given a happy meal sbus device, find it's quattro parent.
  * If none exist, allocate and return a new one.
  *
  * Return NULL on failure.
  */
-static struct quattro * __devinit quattro_sbus_find(struct sbus_dev *goal_sdev)
+static struct quattro * __devinit quattro_sbus_find(struct of_device *child)
 {
-	struct sbus_dev *sdev;
+	struct device *parent = child->dev.parent;
+	struct of_device *op;
 	struct quattro *qp;
-	int i;
 
-	for (qp = qfe_sbus_list; qp != NULL; qp = qp->next) {
-		for (i = 0, sdev = qp->quattro_dev;
-		     (sdev != NULL) && (i < 4);
-		     sdev = sdev->next, i++) {
-			if (sdev == goal_sdev)
-				return qp;
-		}
-	}
+	op = to_of_device(parent);
+	qp = dev_get_drvdata(&op->dev);
+	if (qp)
+		return qp;
 
 	qp = kmalloc(sizeof(struct quattro), GFP_KERNEL);
 	if (qp != NULL) {
@@ -2586,10 +2534,11 @@
 		for (i = 0; i < 4; i++)
 			qp->happy_meals[i] = NULL;
 
-		qp->quattro_dev = goal_sdev;
+		qp->quattro_dev = child;
 		qp->next = qfe_sbus_list;
 		qfe_sbus_list = qp;
-		quattro_get_ranges(qp);
+
+		dev_set_drvdata(&op->dev, qp);
 	}
 	return qp;
 }
@@ -2602,10 +2551,10 @@
 	struct quattro *qp;
 
 	for (qp = qfe_sbus_list; qp != NULL; qp = qp->next) {
-		struct sbus_dev *sdev = qp->quattro_dev;
+		struct of_device *op = qp->quattro_dev;
 		int err;
 
-		err = request_irq(sdev->irqs[0],
+		err = request_irq(op->irqs[0],
 				  quattro_sbus_interrupt,
 				  IRQF_SHARED, "Quattro",
 				  qp);
@@ -2621,9 +2570,9 @@
 	struct quattro *qp;
 
 	for (qp = qfe_sbus_list; qp != NULL; qp = qp->next) {
-		struct sbus_dev *sdev = qp->quattro_dev;
+		struct of_device *op = qp->quattro_dev;
 
-		free_irq(sdev->irqs[0], qp);
+		free_irq(op->irqs[0], qp);
 	}
 }
 #endif /* CONFIG_SBUS */
@@ -2660,9 +2609,9 @@
 #endif /* CONFIG_PCI */
 
 #ifdef CONFIG_SBUS
-static int __devinit happy_meal_sbus_probe_one(struct sbus_dev *sdev, int is_qfe)
+static int __devinit happy_meal_sbus_probe_one(struct of_device *op, int is_qfe)
 {
-	struct device_node *dp = sdev->ofdev.node;
+	struct device_node *dp = op->node, *sbus_dp;
 	struct quattro *qp = NULL;
 	struct happy_meal *hp;
 	struct net_device *dev;
@@ -2671,7 +2620,7 @@
 	DECLARE_MAC_BUF(mac);
 
 	if (is_qfe) {
-		qp = quattro_sbus_find(sdev);
+		qp = quattro_sbus_find(op);
 		if (qp == NULL)
 			goto err_out;
 		for (qfe_slot = 0; qfe_slot < 4; qfe_slot++)
@@ -2685,7 +2634,7 @@
 	dev = alloc_etherdev(sizeof(struct happy_meal));
 	if (!dev)
 		goto err_out;
-	SET_NETDEV_DEV(dev, &sdev->ofdev.dev);
+	SET_NETDEV_DEV(dev, &op->dev);
 
 	if (hme_version_printed++ == 0)
 		printk(KERN_INFO "%s", version);
@@ -2713,56 +2662,50 @@
 			memcpy(dev->dev_addr, idprom->id_ethaddr, 6);
 	}
 
-	hp = dev->priv;
+	hp = netdev_priv(dev);
 
-	hp->happy_dev = sdev;
+	hp->happy_dev = op;
+	hp->dma_dev = &op->dev;
 
 	spin_lock_init(&hp->happy_lock);
 
 	err = -ENODEV;
-	if (sdev->num_registers != 5) {
-		printk(KERN_ERR "happymeal: Device needs 5 regs, has %d.\n",
-		       sdev->num_registers);
-		goto err_out_free_netdev;
-	}
-
 	if (qp != NULL) {
 		hp->qfe_parent = qp;
 		hp->qfe_ent = qfe_slot;
 		qp->happy_meals[qfe_slot] = dev;
-		quattro_apply_ranges(qp, hp);
 	}
 
-	hp->gregs = sbus_ioremap(&sdev->resource[0], 0,
-				 GREG_REG_SIZE, "HME Global Regs");
+	hp->gregs = of_ioremap(&op->resource[0], 0,
+			       GREG_REG_SIZE, "HME Global Regs");
 	if (!hp->gregs) {
 		printk(KERN_ERR "happymeal: Cannot map global registers.\n");
 		goto err_out_free_netdev;
 	}
 
-	hp->etxregs = sbus_ioremap(&sdev->resource[1], 0,
-				   ETX_REG_SIZE, "HME TX Regs");
+	hp->etxregs = of_ioremap(&op->resource[1], 0,
+				 ETX_REG_SIZE, "HME TX Regs");
 	if (!hp->etxregs) {
 		printk(KERN_ERR "happymeal: Cannot map MAC TX registers.\n");
 		goto err_out_iounmap;
 	}
 
-	hp->erxregs = sbus_ioremap(&sdev->resource[2], 0,
-				   ERX_REG_SIZE, "HME RX Regs");
+	hp->erxregs = of_ioremap(&op->resource[2], 0,
+				 ERX_REG_SIZE, "HME RX Regs");
 	if (!hp->erxregs) {
 		printk(KERN_ERR "happymeal: Cannot map MAC RX registers.\n");
 		goto err_out_iounmap;
 	}
 
-	hp->bigmacregs = sbus_ioremap(&sdev->resource[3], 0,
-				      BMAC_REG_SIZE, "HME BIGMAC Regs");
+	hp->bigmacregs = of_ioremap(&op->resource[3], 0,
+				    BMAC_REG_SIZE, "HME BIGMAC Regs");
 	if (!hp->bigmacregs) {
 		printk(KERN_ERR "happymeal: Cannot map BIGMAC registers.\n");
 		goto err_out_iounmap;
 	}
 
-	hp->tcvregs = sbus_ioremap(&sdev->resource[4], 0,
-				   TCVR_REG_SIZE, "HME Tranceiver Regs");
+	hp->tcvregs = of_ioremap(&op->resource[4], 0,
+				 TCVR_REG_SIZE, "HME Tranceiver Regs");
 	if (!hp->tcvregs) {
 		printk(KERN_ERR "happymeal: Cannot map TCVR registers.\n");
 		goto err_out_iounmap;
@@ -2781,13 +2724,18 @@
 	if (qp != NULL)
 		hp->happy_flags |= HFLAG_QUATTRO;
 
+	sbus_dp = to_of_device(op->dev.parent)->node;
+	if (is_qfe)
+		sbus_dp = to_of_device(op->dev.parent->parent)->node;
+
 	/* Get the supported DVMA burst sizes from our Happy SBUS. */
-	hp->happy_bursts = of_getintprop_default(sdev->bus->ofdev.node,
+	hp->happy_bursts = of_getintprop_default(sbus_dp,
 						 "burst-sizes", 0x00);
 
-	hp->happy_block = sbus_alloc_consistent(hp->happy_dev,
-						PAGE_SIZE,
-						&hp->hblock_dvma);
+	hp->happy_block = dma_alloc_coherent(hp->dma_dev,
+					     PAGE_SIZE,
+					     &hp->hblock_dvma,
+					     GFP_ATOMIC);
 	err = -ENOMEM;
 	if (!hp->happy_block) {
 		printk(KERN_ERR "happymeal: Cannot allocate descriptors.\n");
@@ -2816,19 +2764,13 @@
 	/* Happy Meal can do it all... */
 	dev->features |= NETIF_F_SG | NETIF_F_HW_CSUM;
 
-	dev->irq = sdev->irqs[0];
+	dev->irq = op->irqs[0];
 
 #if defined(CONFIG_SBUS) && defined(CONFIG_PCI)
-	/* Hook up PCI register/dma accessors. */
+	/* Hook up SBUS register/descriptor accessors. */
 	hp->read_desc32 = sbus_hme_read_desc32;
 	hp->write_txd = sbus_hme_write_txd;
 	hp->write_rxd = sbus_hme_write_rxd;
-	hp->dma_map = (u32 (*)(void *, void *, long, int))sbus_map_single;
-	hp->dma_unmap = (void (*)(void *, u32, long, int))sbus_unmap_single;
-	hp->dma_sync_for_cpu = (void (*)(void *, u32, long, int))
-		sbus_dma_sync_single_for_cpu;
-	hp->dma_sync_for_device = (void (*)(void *, u32, long, int))
-		sbus_dma_sync_single_for_device;
 	hp->read32 = sbus_hme_read32;
 	hp->write32 = sbus_hme_write32;
 #endif
@@ -2843,10 +2785,10 @@
 	if (register_netdev(hp->dev)) {
 		printk(KERN_ERR "happymeal: Cannot register net device, "
 		       "aborting.\n");
-		goto err_out_free_consistent;
+		goto err_out_free_coherent;
 	}
 
-	dev_set_drvdata(&sdev->ofdev.dev, hp);
+	dev_set_drvdata(&op->dev, hp);
 
 	if (qfe_slot != -1)
 		printk(KERN_INFO "%s: Quattro HME slot %d (SBUS) 10/100baseT Ethernet ",
@@ -2859,23 +2801,23 @@
 
 	return 0;
 
-err_out_free_consistent:
-	sbus_free_consistent(hp->happy_dev,
-			     PAGE_SIZE,
-			     hp->happy_block,
-			     hp->hblock_dvma);
+err_out_free_coherent:
+	dma_free_coherent(hp->dma_dev,
+			  PAGE_SIZE,
+			  hp->happy_block,
+			  hp->hblock_dvma);
 
 err_out_iounmap:
 	if (hp->gregs)
-		sbus_iounmap(hp->gregs, GREG_REG_SIZE);
+		of_iounmap(&op->resource[0], hp->gregs, GREG_REG_SIZE);
 	if (hp->etxregs)
-		sbus_iounmap(hp->etxregs, ETX_REG_SIZE);
+		of_iounmap(&op->resource[1], hp->etxregs, ETX_REG_SIZE);
 	if (hp->erxregs)
-		sbus_iounmap(hp->erxregs, ERX_REG_SIZE);
+		of_iounmap(&op->resource[2], hp->erxregs, ERX_REG_SIZE);
 	if (hp->bigmacregs)
-		sbus_iounmap(hp->bigmacregs, BMAC_REG_SIZE);
+		of_iounmap(&op->resource[3], hp->bigmacregs, BMAC_REG_SIZE);
 	if (hp->tcvregs)
-		sbus_iounmap(hp->tcvregs, TCVR_REG_SIZE);
+		of_iounmap(&op->resource[4], hp->tcvregs, TCVR_REG_SIZE);
 
 err_out_free_netdev:
 	free_netdev(dev);
@@ -3035,6 +2977,7 @@
 	memset(hp, 0, sizeof(*hp));
 
 	hp->happy_dev = pdev;
+	hp->dma_dev = &pdev->dev;
 
 	spin_lock_init(&hp->happy_lock);
 
@@ -3121,7 +3064,7 @@
 #endif
 
 	hp->happy_block = (struct hmeal_init_block *)
-		pci_alloc_consistent(pdev, PAGE_SIZE, &hp->hblock_dvma);
+		dma_alloc_coherent(&pdev->dev, PAGE_SIZE, &hp->hblock_dvma, GFP_KERNEL);
 
 	err = -ENODEV;
 	if (!hp->happy_block) {
@@ -3151,16 +3094,10 @@
 	dev->features |= NETIF_F_SG | NETIF_F_HW_CSUM;
 
 #if defined(CONFIG_SBUS) && defined(CONFIG_PCI)
-	/* Hook up PCI register/dma accessors. */
+	/* Hook up PCI register/descriptor accessors. */
 	hp->read_desc32 = pci_hme_read_desc32;
 	hp->write_txd = pci_hme_write_txd;
 	hp->write_rxd = pci_hme_write_rxd;
-	hp->dma_map = (u32 (*)(void *, void *, long, int))pci_map_single;
-	hp->dma_unmap = (void (*)(void *, u32, long, int))pci_unmap_single;
-	hp->dma_sync_for_cpu = (void (*)(void *, u32, long, int))
-		pci_dma_sync_single_for_cpu;
-	hp->dma_sync_for_device = (void (*)(void *, u32, long, int))
-		pci_dma_sync_single_for_device;
 	hp->read32 = pci_hme_read32;
 	hp->write32 = pci_hme_write32;
 #endif
@@ -3231,10 +3168,8 @@
 
 	unregister_netdev(net_dev);
 
-	pci_free_consistent(hp->happy_dev,
-			    PAGE_SIZE,
-			    hp->happy_block,
-			    hp->hblock_dvma);
+	dma_free_coherent(hp->dma_dev, PAGE_SIZE,
+			  hp->happy_block, hp->hblock_dvma);
 	iounmap(hp->gregs);
 	pci_release_regions(hp->happy_dev);
 
@@ -3279,46 +3214,45 @@
 #endif
 
 #ifdef CONFIG_SBUS
-static int __devinit hme_sbus_probe(struct of_device *dev, const struct of_device_id *match)
+static int __devinit hme_sbus_probe(struct of_device *op, const struct of_device_id *match)
 {
-	struct sbus_dev *sdev = to_sbus_device(&dev->dev);
-	struct device_node *dp = dev->node;
+	struct device_node *dp = op->node;
 	const char *model = of_get_property(dp, "model", NULL);
 	int is_qfe = (match->data != NULL);
 
 	if (!is_qfe && model && !strcmp(model, "SUNW,sbus-qfe"))
 		is_qfe = 1;
 
-	return happy_meal_sbus_probe_one(sdev, is_qfe);
+	return happy_meal_sbus_probe_one(op, is_qfe);
 }
 
-static int __devexit hme_sbus_remove(struct of_device *dev)
+static int __devexit hme_sbus_remove(struct of_device *op)
 {
-	struct happy_meal *hp = dev_get_drvdata(&dev->dev);
+	struct happy_meal *hp = dev_get_drvdata(&op->dev);
 	struct net_device *net_dev = hp->dev;
 
 	unregister_netdev(net_dev);
 
 	/* XXX qfe parent interrupt... */
 
-	sbus_iounmap(hp->gregs, GREG_REG_SIZE);
-	sbus_iounmap(hp->etxregs, ETX_REG_SIZE);
-	sbus_iounmap(hp->erxregs, ERX_REG_SIZE);
-	sbus_iounmap(hp->bigmacregs, BMAC_REG_SIZE);
-	sbus_iounmap(hp->tcvregs, TCVR_REG_SIZE);
-	sbus_free_consistent(hp->happy_dev,
-			     PAGE_SIZE,
-			     hp->happy_block,
-			     hp->hblock_dvma);
+	of_iounmap(&op->resource[0], hp->gregs, GREG_REG_SIZE);
+	of_iounmap(&op->resource[1], hp->etxregs, ETX_REG_SIZE);
+	of_iounmap(&op->resource[2], hp->erxregs, ERX_REG_SIZE);
+	of_iounmap(&op->resource[3], hp->bigmacregs, BMAC_REG_SIZE);
+	of_iounmap(&op->resource[4], hp->tcvregs, TCVR_REG_SIZE);
+	dma_free_coherent(hp->dma_dev,
+			  PAGE_SIZE,
+			  hp->happy_block,
+			  hp->hblock_dvma);
 
 	free_netdev(net_dev);
 
-	dev_set_drvdata(&dev->dev, NULL);
+	dev_set_drvdata(&op->dev, NULL);
 
 	return 0;
 }
 
-static struct of_device_id hme_sbus_match[] = {
+static const struct of_device_id hme_sbus_match[] = {
 	{
 		.name = "SUNW,hme",
 	},
@@ -3346,7 +3280,7 @@
 {
 	int err;
 
-	err = of_register_driver(&hme_sbus_driver, &sbus_bus_type);
+	err = of_register_driver(&hme_sbus_driver, &of_bus_type);
 	if (!err)
 		quattro_sbus_register_irqs();
 
diff --git a/drivers/net/sunhme.h b/drivers/net/sunhme.h
index 4da5539..efd2ca0 100644
--- a/drivers/net/sunhme.h
+++ b/drivers/net/sunhme.h
@@ -405,14 +405,11 @@
 	u32 (*read_desc32)(hme32 *);
 	void (*write_txd)(struct happy_meal_txd *, u32, u32);
 	void (*write_rxd)(struct happy_meal_rxd *, u32, u32);
-	u32 (*dma_map)(void *, void *, long, int);
-	void (*dma_unmap)(void *, u32, long, int);
-	void (*dma_sync_for_cpu)(void *, u32, long, int);
-	void (*dma_sync_for_device)(void *, u32, long, int);
 #endif
 
-	/* This is either a sbus_dev or a pci_dev. */
+	/* This is either an of_device or a pci_dev. */
 	void			  *happy_dev;
+	struct device		  *dma_dev;
 
 	spinlock_t		  happy_lock;
 
diff --git a/drivers/net/sunlance.c b/drivers/net/sunlance.c
index 4e994f8..704301a 100644
--- a/drivers/net/sunlance.c
+++ b/drivers/net/sunlance.c
@@ -91,6 +91,9 @@
 #include <linux/skbuff.h>
 #include <linux/ethtool.h>
 #include <linux/bitops.h>
+#include <linux/dma-mapping.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 
 #include <asm/system.h>
 #include <asm/io.h>
@@ -98,7 +101,6 @@
 #include <asm/pgtable.h>
 #include <asm/byteorder.h>	/* Used by the checksum routines */
 #include <asm/idprom.h>
-#include <asm/sbus.h>
 #include <asm/prom.h>
 #include <asm/auxio.h>		/* For tpe-link-test? setting */
 #include <asm/irq.h>
@@ -248,7 +250,7 @@
 	int		rx_new, tx_new;
 	int		rx_old, tx_old;
 
-	struct sbus_dma *ledma;	/* If set this points to ledma	*/
+	struct of_device *ledma;	/* If set this points to ledma	*/
 	char		tpe;		/* cable-selection is TPE	*/
 	char		auto_select;	/* cable-selection by carrier	*/
 	char		burst_sizes;	/* ledma SBus burst sizes	*/
@@ -263,7 +265,8 @@
 	char	       	       *name;
 	dma_addr_t		init_block_dvma;
 	struct net_device      *dev;		  /* Backpointer	*/
-	struct sbus_dev	       *sdev;
+	struct of_device       *op;
+	struct of_device       *lebuffer;
 	struct timer_list       multicast_timer;
 };
 
@@ -1272,27 +1275,29 @@
 static void lance_free_hwresources(struct lance_private *lp)
 {
 	if (lp->lregs)
-		sbus_iounmap(lp->lregs, LANCE_REG_SIZE);
+		of_iounmap(&lp->op->resource[0], lp->lregs, LANCE_REG_SIZE);
+	if (lp->dregs) {
+		struct of_device *ledma = lp->ledma;
+
+		of_iounmap(&ledma->resource[0], lp->dregs,
+			   resource_size(&ledma->resource[0]));
+	}
 	if (lp->init_block_iomem) {
-		sbus_iounmap(lp->init_block_iomem,
-			     sizeof(struct lance_init_block));
+		of_iounmap(&lp->lebuffer->resource[0], lp->init_block_iomem,
+			   sizeof(struct lance_init_block));
 	} else if (lp->init_block_mem) {
-		sbus_free_consistent(lp->sdev,
-				     sizeof(struct lance_init_block),
-				     lp->init_block_mem,
-				     lp->init_block_dvma);
+		dma_free_coherent(&lp->op->dev,
+				  sizeof(struct lance_init_block),
+				  lp->init_block_mem,
+				  lp->init_block_dvma);
 	}
 }
 
 /* Ethtool support... */
 static void sparc_lance_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
 {
-	struct lance_private *lp = netdev_priv(dev);
-
 	strcpy(info->driver, "sunlance");
 	strcpy(info->version, "2.02");
-	sprintf(info->bus_info, "SBUS:%d",
-		lp->sdev->slot);
 }
 
 static u32 sparc_lance_get_link(struct net_device *dev)
@@ -1308,16 +1313,16 @@
 	.get_link		= sparc_lance_get_link,
 };
 
-static int __devinit sparc_lance_probe_one(struct sbus_dev *sdev,
-					   struct sbus_dma *ledma,
-					   struct sbus_dev *lebuffer)
+static int __devinit sparc_lance_probe_one(struct of_device *op,
+					   struct of_device *ledma,
+					   struct of_device *lebuffer)
 {
+	struct device_node *dp = op->node;
 	static unsigned version_printed;
-	struct device_node *dp = sdev->ofdev.node;
-	struct net_device *dev;
 	struct lance_private *lp;
-	int    i;
+	struct net_device *dev;
 	DECLARE_MAC_BUF(mac);
+	int    i;
 
 	dev = alloc_etherdev(sizeof(struct lance_private) + 8);
 	if (!dev)
@@ -1338,14 +1343,27 @@
 		dev->dev_addr[i] = idprom->id_ethaddr[i];
 
 	/* Get the IO region */
-	lp->lregs = sbus_ioremap(&sdev->resource[0], 0,
-				 LANCE_REG_SIZE, lancestr);
+	lp->lregs = of_ioremap(&op->resource[0], 0,
+			       LANCE_REG_SIZE, lancestr);
 	if (!lp->lregs) {
 		printk(KERN_ERR "SunLance: Cannot map registers.\n");
 		goto fail;
 	}
 
-	lp->sdev = sdev;
+	lp->ledma = ledma;
+	if (lp->ledma) {
+		lp->dregs = of_ioremap(&ledma->resource[0], 0,
+				       resource_size(&ledma->resource[0]),
+				       "ledma");
+		if (!lp->dregs) {
+			printk(KERN_ERR "SunLance: Cannot map "
+			       "ledma registers.\n");
+			goto fail;
+		}
+	}
+
+	lp->op = op;
+	lp->lebuffer = lebuffer;
 	if (lebuffer) {
 		/* sanity check */
 		if (lebuffer->resource[0].start & 7) {
@@ -1353,8 +1371,8 @@
 			goto fail;
 		}
 		lp->init_block_iomem =
-			sbus_ioremap(&lebuffer->resource[0], 0,
-				     sizeof(struct lance_init_block), "lebuffer");
+			of_ioremap(&lebuffer->resource[0], 0,
+				   sizeof(struct lance_init_block), "lebuffer");
 		if (!lp->init_block_iomem) {
 			printk(KERN_ERR "SunLance: Cannot map PIO buffer.\n");
 			goto fail;
@@ -1366,9 +1384,10 @@
 		lp->tx = lance_tx_pio;
 	} else {
 		lp->init_block_mem =
-			sbus_alloc_consistent(sdev, sizeof(struct lance_init_block),
-					      &lp->init_block_dvma);
-		if (!lp->init_block_mem || lp->init_block_dvma == 0) {
+			dma_alloc_coherent(&op->dev,
+					   sizeof(struct lance_init_block),
+					   &lp->init_block_dvma, GFP_ATOMIC);
+		if (!lp->init_block_mem) {
 			printk(KERN_ERR "SunLance: Cannot allocate consistent DMA memory.\n");
 			goto fail;
 		}
@@ -1383,13 +1402,13 @@
 						      LE_C3_BCON));
 
 	lp->name = lancestr;
-	lp->ledma = ledma;
 
 	lp->burst_sizes = 0;
 	if (lp->ledma) {
-		struct device_node *ledma_dp = ledma->sdev->ofdev.node;
-		const char *prop;
+		struct device_node *ledma_dp = ledma->node;
+		struct device_node *sbus_dp;
 		unsigned int sbmask;
+		const char *prop;
 		u32 csr;
 
 		/* Find burst-size property for ledma */
@@ -1397,7 +1416,8 @@
 							"burst-sizes", 0);
 
 		/* ledma may be capable of fast bursts, but sbus may not. */
-		sbmask = of_getintprop_default(ledma_dp, "burst-sizes",
+		sbus_dp = ledma_dp->parent;
+		sbmask = of_getintprop_default(sbus_dp, "burst-sizes",
 					       DMA_BURSTBITS);
 		lp->burst_sizes &= sbmask;
 
@@ -1435,8 +1455,6 @@
 			lp->tpe = 1;
 		}
 
-		lp->dregs = ledma->regs;
-
 		/* Reset ledma */
 		csr = sbus_readl(lp->dregs + DMA_CSR);
 		sbus_writel(csr | DMA_RST_ENET, lp->dregs + DMA_CSR);
@@ -1446,7 +1464,7 @@
 		lp->dregs = NULL;
 
 	lp->dev = dev;
-	SET_NETDEV_DEV(dev, &sdev->ofdev.dev);
+	SET_NETDEV_DEV(dev, &op->dev);
 	dev->open = &lance_open;
 	dev->stop = &lance_close;
 	dev->hard_start_xmit = &lance_start_xmit;
@@ -1455,9 +1473,7 @@
 	dev->set_multicast_list = &lance_set_multicast;
 	dev->ethtool_ops = &sparc_lance_ethtool_ops;
 
-	dev->irq = sdev->irqs[0];
-
-	dev->dma = 0;
+	dev->irq = op->irqs[0];
 
 	/* We cannot sleep if the chip is busy during a
 	 * multicast list update event, because such events
@@ -1473,7 +1489,7 @@
 		goto fail;
 	}
 
-	dev_set_drvdata(&sdev->ofdev.dev, lp);
+	dev_set_drvdata(&op->dev, lp);
 
 	printk(KERN_INFO "%s: LANCE %s\n",
 	       dev->name, print_mac(mac, dev->dev_addr));
@@ -1486,80 +1502,25 @@
 	return -ENODEV;
 }
 
-/* On 4m, find the associated dma for the lance chip */
-static struct sbus_dma * __devinit find_ledma(struct sbus_dev *sdev)
+static int __devinit sunlance_sbus_probe(struct of_device *op, const struct of_device_id *match)
 {
-	struct sbus_dma *p;
-
-	for_each_dvma(p) {
-		if (p->sdev == sdev)
-			return p;
-	}
-	return NULL;
-}
-
-#ifdef CONFIG_SUN4
-
-#include <asm/sun4paddr.h>
-#include <asm/machines.h>
-
-/* Find all the lance cards on the system and initialize them */
-static struct sbus_dev sun4_sdev;
-static int __devinit sparc_lance_init(void)
-{
-	if ((idprom->id_machtype == (SM_SUN4|SM_4_330)) ||
-	    (idprom->id_machtype == (SM_SUN4|SM_4_470))) {
-		memset(&sun4_sdev, 0, sizeof(struct sbus_dev));
-		sun4_sdev.reg_addrs[0].phys_addr = sun4_eth_physaddr;
-		sun4_sdev.irqs[0] = 6;
-		return sparc_lance_probe_one(&sun4_sdev, NULL, NULL);
-	}
-	return -ENODEV;
-}
-
-static int __exit sunlance_sun4_remove(void)
-{
-	struct lance_private *lp = dev_get_drvdata(&sun4_sdev.ofdev.dev);
-	struct net_device *net_dev = lp->dev;
-
-	unregister_netdev(net_dev);
-
-	lance_free_hwresources(lp);
-
-	free_netdev(net_dev);
-
-	dev_set_drvdata(&sun4_sdev.ofdev.dev, NULL);
-
-	return 0;
-}
-
-#else /* !CONFIG_SUN4 */
-
-static int __devinit sunlance_sbus_probe(struct of_device *dev, const struct of_device_id *match)
-{
-	struct sbus_dev *sdev = to_sbus_device(&dev->dev);
+	struct of_device *parent = to_of_device(op->dev.parent);
+	struct device_node *parent_dp = parent->node;
 	int err;
 
-	if (sdev->parent) {
-		struct of_device *parent = &sdev->parent->ofdev;
-
-		if (!strcmp(parent->node->name, "ledma")) {
-			struct sbus_dma *ledma = find_ledma(to_sbus_device(&parent->dev));
-
-			err = sparc_lance_probe_one(sdev, ledma, NULL);
-		} else if (!strcmp(parent->node->name, "lebuffer")) {
-			err = sparc_lance_probe_one(sdev, NULL, to_sbus_device(&parent->dev));
-		} else
-			err = sparc_lance_probe_one(sdev, NULL, NULL);
+	if (!strcmp(parent_dp->name, "ledma")) {
+		err = sparc_lance_probe_one(op, parent, NULL);
+	} else if (!strcmp(parent_dp->name, "lebuffer")) {
+		err = sparc_lance_probe_one(op, NULL, parent);
 	} else
-		err = sparc_lance_probe_one(sdev, NULL, NULL);
+		err = sparc_lance_probe_one(op, NULL, NULL);
 
 	return err;
 }
 
-static int __devexit sunlance_sbus_remove(struct of_device *dev)
+static int __devexit sunlance_sbus_remove(struct of_device *op)
 {
-	struct lance_private *lp = dev_get_drvdata(&dev->dev);
+	struct lance_private *lp = dev_get_drvdata(&op->dev);
 	struct net_device *net_dev = lp->dev;
 
 	unregister_netdev(net_dev);
@@ -1568,12 +1529,12 @@
 
 	free_netdev(net_dev);
 
-	dev_set_drvdata(&dev->dev, NULL);
+	dev_set_drvdata(&op->dev, NULL);
 
 	return 0;
 }
 
-static struct of_device_id sunlance_sbus_match[] = {
+static const struct of_device_id sunlance_sbus_match[] = {
 	{
 		.name = "le",
 	},
@@ -1593,17 +1554,12 @@
 /* Find all the lance cards on the system and initialize them */
 static int __init sparc_lance_init(void)
 {
-	return of_register_driver(&sunlance_sbus_driver, &sbus_bus_type);
+	return of_register_driver(&sunlance_sbus_driver, &of_bus_type);
 }
-#endif /* !CONFIG_SUN4 */
 
 static void __exit sparc_lance_exit(void)
 {
-#ifdef CONFIG_SUN4
-	sunlance_sun4_remove();
-#else
 	of_unregister_driver(&sunlance_sbus_driver);
-#endif
 }
 
 module_init(sparc_lance_init);
diff --git a/drivers/net/sunqe.c b/drivers/net/sunqe.c
index e811331..f636447 100644
--- a/drivers/net/sunqe.c
+++ b/drivers/net/sunqe.c
@@ -3,7 +3,7 @@
  *          controller out there can be most efficiently programmed
  *          if you make it look like a LANCE.
  *
- * Copyright (C) 1996, 1999, 2003, 2006 David S. Miller (davem@davemloft.net)
+ * Copyright (C) 1996, 1999, 2003, 2006, 2008 David S. Miller (davem@davemloft.net)
  */
 
 #include <linux/module.h>
@@ -24,13 +24,15 @@
 #include <linux/skbuff.h>
 #include <linux/ethtool.h>
 #include <linux/bitops.h>
+#include <linux/dma-mapping.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 
 #include <asm/system.h>
 #include <asm/io.h>
 #include <asm/dma.h>
 #include <asm/byteorder.h>
 #include <asm/idprom.h>
-#include <asm/sbus.h>
 #include <asm/openprom.h>
 #include <asm/oplib.h>
 #include <asm/auxio.h>
@@ -40,8 +42,8 @@
 #include "sunqe.h"
 
 #define DRV_NAME	"sunqe"
-#define DRV_VERSION	"4.0"
-#define DRV_RELDATE	"June 23, 2006"
+#define DRV_VERSION	"4.1"
+#define DRV_RELDATE	"August 27, 2008"
 #define DRV_AUTHOR	"David S. Miller (davem@davemloft.net)"
 
 static char version[] =
@@ -690,12 +692,18 @@
 /* Ethtool support... */
 static void qe_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
 {
+	const struct linux_prom_registers *regs;
 	struct sunqe *qep = dev->priv;
+	struct of_device *op;
 
 	strcpy(info->driver, "sunqe");
 	strcpy(info->version, "3.0");
-	sprintf(info->bus_info, "SBUS:%d",
-		qep->qe_sdev->slot);
+
+	op = qep->op;
+	regs = of_get_property(op->node, "reg", NULL);
+	if (regs)
+		sprintf(info->bus_info, "SBUS:%d", regs->which_io);
+
 }
 
 static u32 qe_get_link(struct net_device *dev)
@@ -717,11 +725,11 @@
 };
 
 /* This is only called once at boot time for each card probed. */
-static inline void qec_init_once(struct sunqec *qecp, struct sbus_dev *qsdev)
+static void qec_init_once(struct sunqec *qecp, struct of_device *op)
 {
 	u8 bsizes = qecp->qec_bursts;
 
-	if (sbus_can_burst64(qsdev) && (bsizes & DMA_BURST64)) {
+	if (sbus_can_burst64() && (bsizes & DMA_BURST64)) {
 		sbus_writel(GLOB_CTRL_B64, qecp->gregs + GLOB_CTRL);
 	} else if (bsizes & DMA_BURST32) {
 		sbus_writel(GLOB_CTRL_B32, qecp->gregs + GLOB_CTRL);
@@ -735,15 +743,15 @@
 	sbus_writel(GLOB_PSIZE_2048, qecp->gregs + GLOB_PSIZE);
 
 	/* Set the local memsize register, divided up to one piece per QE channel. */
-	sbus_writel((qsdev->reg_addrs[1].reg_size >> 2),
+	sbus_writel((resource_size(&op->resource[1]) >> 2),
 		    qecp->gregs + GLOB_MSIZE);
 
 	/* Divide up the local QEC memory amongst the 4 QE receiver and
 	 * transmitter FIFOs.  Basically it is (total / 2 / num_channels).
 	 */
-	sbus_writel((qsdev->reg_addrs[1].reg_size >> 2) >> 1,
+	sbus_writel((resource_size(&op->resource[1]) >> 2) >> 1,
 		    qecp->gregs + GLOB_TSIZE);
-	sbus_writel((qsdev->reg_addrs[1].reg_size >> 2) >> 1,
+	sbus_writel((resource_size(&op->resource[1]) >> 2) >> 1,
 		    qecp->gregs + GLOB_RSIZE);
 }
 
@@ -767,24 +775,21 @@
 	return bsizes;
 }
 
-static struct sunqec * __devinit get_qec(struct sbus_dev *child_sdev)
+static struct sunqec * __devinit get_qec(struct of_device *child)
 {
-	struct sbus_dev *qec_sdev = child_sdev->parent;
+	struct of_device *op = to_of_device(child->dev.parent);
 	struct sunqec *qecp;
 
-	for (qecp = root_qec_dev; qecp; qecp = qecp->next_module) {
-		if (qecp->qec_sdev == qec_sdev)
-			break;
-	}
+	qecp = dev_get_drvdata(&op->dev);
 	if (!qecp) {
 		qecp = kzalloc(sizeof(struct sunqec), GFP_KERNEL);
 		if (qecp) {
 			u32 ctrl;
 
-			qecp->qec_sdev = qec_sdev;
-			qecp->gregs = sbus_ioremap(&qec_sdev->resource[0], 0,
-						   GLOB_REG_SIZE,
-						   "QEC Global Registers");
+			qecp->op = op;
+			qecp->gregs = of_ioremap(&op->resource[0], 0,
+						 GLOB_REG_SIZE,
+						 "QEC Global Registers");
 			if (!qecp->gregs)
 				goto fail;
 
@@ -799,16 +804,18 @@
 			if (qec_global_reset(qecp->gregs))
 				goto fail;
 
-			qecp->qec_bursts = qec_get_burst(qec_sdev->ofdev.node);
+			qecp->qec_bursts = qec_get_burst(op->node);
 
-			qec_init_once(qecp, qec_sdev);
+			qec_init_once(qecp, op);
 
-			if (request_irq(qec_sdev->irqs[0], &qec_interrupt,
+			if (request_irq(op->irqs[0], &qec_interrupt,
 					IRQF_SHARED, "qec", (void *) qecp)) {
 				printk(KERN_ERR "qec: Can't register irq.\n");
 				goto fail;
 			}
 
+			dev_set_drvdata(&op->dev, qecp);
+
 			qecp->next_module = root_qec_dev;
 			root_qec_dev = qecp;
 		}
@@ -818,17 +825,17 @@
 
 fail:
 	if (qecp->gregs)
-		sbus_iounmap(qecp->gregs, GLOB_REG_SIZE);
+		of_iounmap(&op->resource[0], qecp->gregs, GLOB_REG_SIZE);
 	kfree(qecp);
 	return NULL;
 }
 
-static int __devinit qec_ether_init(struct sbus_dev *sdev)
+static int __devinit qec_ether_init(struct of_device *op)
 {
 	static unsigned version_printed;
 	struct net_device *dev;
-	struct sunqe *qe;
 	struct sunqec *qecp;
+	struct sunqe *qe;
 	int i, res;
 
 	if (version_printed++ == 0)
@@ -842,49 +849,42 @@
 
 	qe = netdev_priv(dev);
 
-	i = of_getintprop_default(sdev->ofdev.node, "channel#", -1);
-	if (i == -1) {
-		struct sbus_dev *td = sdev->parent->child;
-		i = 0;
-		while (td != sdev) {
-			td = td->next;
-			i++;
-		}
-	}
+	res = -ENODEV;
+
+	i = of_getintprop_default(op->node, "channel#", -1);
+	if (i == -1)
+		goto fail;
 	qe->channel = i;
 	spin_lock_init(&qe->lock);
 
-	res = -ENODEV;
-	qecp = get_qec(sdev);
+	qecp = get_qec(op);
 	if (!qecp)
 		goto fail;
 
 	qecp->qes[qe->channel] = qe;
 	qe->dev = dev;
 	qe->parent = qecp;
-	qe->qe_sdev = sdev;
+	qe->op = op;
 
 	res = -ENOMEM;
-	qe->qcregs = sbus_ioremap(&qe->qe_sdev->resource[0], 0,
-				  CREG_REG_SIZE, "QEC Channel Registers");
+	qe->qcregs = of_ioremap(&op->resource[0], 0,
+				CREG_REG_SIZE, "QEC Channel Registers");
 	if (!qe->qcregs) {
 		printk(KERN_ERR "qe: Cannot map channel registers.\n");
 		goto fail;
 	}
 
-	qe->mregs = sbus_ioremap(&qe->qe_sdev->resource[1], 0,
-				 MREGS_REG_SIZE, "QE MACE Registers");
+	qe->mregs = of_ioremap(&op->resource[1], 0,
+			       MREGS_REG_SIZE, "QE MACE Registers");
 	if (!qe->mregs) {
 		printk(KERN_ERR "qe: Cannot map MACE registers.\n");
 		goto fail;
 	}
 
-	qe->qe_block = sbus_alloc_consistent(qe->qe_sdev,
-					     PAGE_SIZE,
-					     &qe->qblock_dvma);
-	qe->buffers = sbus_alloc_consistent(qe->qe_sdev,
-					    sizeof(struct sunqe_buffers),
-					    &qe->buffers_dvma);
+	qe->qe_block = dma_alloc_coherent(&op->dev, PAGE_SIZE,
+					  &qe->qblock_dvma, GFP_ATOMIC);
+	qe->buffers = dma_alloc_coherent(&op->dev, sizeof(struct sunqe_buffers),
+					 &qe->buffers_dvma, GFP_ATOMIC);
 	if (qe->qe_block == NULL || qe->qblock_dvma == 0 ||
 	    qe->buffers == NULL || qe->buffers_dvma == 0)
 		goto fail;
@@ -892,7 +892,7 @@
 	/* Stop this QE. */
 	qe_stop(qe);
 
-	SET_NETDEV_DEV(dev, &sdev->ofdev.dev);
+	SET_NETDEV_DEV(dev, &op->dev);
 
 	dev->open = qe_open;
 	dev->stop = qe_close;
@@ -900,7 +900,7 @@
 	dev->set_multicast_list = qe_set_multicast;
 	dev->tx_timeout = qe_tx_timeout;
 	dev->watchdog_timeo = 5*HZ;
-	dev->irq = sdev->irqs[0];
+	dev->irq = op->irqs[0];
 	dev->dma = 0;
 	dev->ethtool_ops = &qe_ethtool_ops;
 
@@ -908,7 +908,7 @@
 	if (res)
 		goto fail;
 
-	dev_set_drvdata(&sdev->ofdev.dev, qe);
+	dev_set_drvdata(&op->dev, qe);
 
 	printk(KERN_INFO "%s: qe channel[%d] ", dev->name, qe->channel);
 	for (i = 0; i < 6; i++)
@@ -922,58 +922,50 @@
 
 fail:
 	if (qe->qcregs)
-		sbus_iounmap(qe->qcregs, CREG_REG_SIZE);
+		of_iounmap(&op->resource[0], qe->qcregs, CREG_REG_SIZE);
 	if (qe->mregs)
-		sbus_iounmap(qe->mregs, MREGS_REG_SIZE);
+		of_iounmap(&op->resource[1], qe->mregs, MREGS_REG_SIZE);
 	if (qe->qe_block)
-		sbus_free_consistent(qe->qe_sdev,
-				     PAGE_SIZE,
-				     qe->qe_block,
-				     qe->qblock_dvma);
+		dma_free_coherent(&op->dev, PAGE_SIZE,
+				  qe->qe_block, qe->qblock_dvma);
 	if (qe->buffers)
-		sbus_free_consistent(qe->qe_sdev,
-				     sizeof(struct sunqe_buffers),
-				     qe->buffers,
-				     qe->buffers_dvma);
+		dma_free_coherent(&op->dev,
+				  sizeof(struct sunqe_buffers),
+				  qe->buffers,
+				  qe->buffers_dvma);
 
 	free_netdev(dev);
 
 	return res;
 }
 
-static int __devinit qec_sbus_probe(struct of_device *dev, const struct of_device_id *match)
+static int __devinit qec_sbus_probe(struct of_device *op, const struct of_device_id *match)
 {
-	struct sbus_dev *sdev = to_sbus_device(&dev->dev);
-
-	return qec_ether_init(sdev);
+	return qec_ether_init(op);
 }
 
-static int __devexit qec_sbus_remove(struct of_device *dev)
+static int __devexit qec_sbus_remove(struct of_device *op)
 {
-	struct sunqe *qp = dev_get_drvdata(&dev->dev);
+	struct sunqe *qp = dev_get_drvdata(&op->dev);
 	struct net_device *net_dev = qp->dev;
 
 	unregister_netdev(net_dev);
 
-	sbus_iounmap(qp->qcregs, CREG_REG_SIZE);
-	sbus_iounmap(qp->mregs, MREGS_REG_SIZE);
-	sbus_free_consistent(qp->qe_sdev,
-			     PAGE_SIZE,
-			     qp->qe_block,
-			     qp->qblock_dvma);
-	sbus_free_consistent(qp->qe_sdev,
-			     sizeof(struct sunqe_buffers),
-			     qp->buffers,
-			     qp->buffers_dvma);
+	of_iounmap(&op->resource[0], qp->qcregs, CREG_REG_SIZE);
+	of_iounmap(&op->resource[1], qp->mregs, MREGS_REG_SIZE);
+	dma_free_coherent(&op->dev, PAGE_SIZE,
+			  qp->qe_block, qp->qblock_dvma);
+	dma_free_coherent(&op->dev, sizeof(struct sunqe_buffers),
+			  qp->buffers, qp->buffers_dvma);
 
 	free_netdev(net_dev);
 
-	dev_set_drvdata(&dev->dev, NULL);
+	dev_set_drvdata(&op->dev, NULL);
 
 	return 0;
 }
 
-static struct of_device_id qec_sbus_match[] = {
+static const struct of_device_id qec_sbus_match[] = {
 	{
 		.name = "qe",
 	},
@@ -991,7 +983,7 @@
 
 static int __init qec_init(void)
 {
-	return of_register_driver(&qec_sbus_driver, &sbus_bus_type);
+	return of_register_driver(&qec_sbus_driver, &of_bus_type);
 }
 
 static void __exit qec_exit(void)
@@ -1000,11 +992,11 @@
 
 	while (root_qec_dev) {
 		struct sunqec *next = root_qec_dev->next_module;
+		struct of_device *op = root_qec_dev->op;
 
-		free_irq(root_qec_dev->qec_sdev->irqs[0],
-			 (void *) root_qec_dev);
-		sbus_iounmap(root_qec_dev->gregs, GLOB_REG_SIZE);
-
+		free_irq(op->irqs[0], (void *) root_qec_dev);
+		of_iounmap(&op->resource[0], root_qec_dev->gregs,
+			   GLOB_REG_SIZE);
 		kfree(root_qec_dev);
 
 		root_qec_dev = next;
diff --git a/drivers/net/sunqe.h b/drivers/net/sunqe.h
index 347c8dd..5813a7b 100644
--- a/drivers/net/sunqe.h
+++ b/drivers/net/sunqe.h
@@ -314,7 +314,7 @@
 	void __iomem		*gregs;		/* QEC Global Registers         */
 	struct sunqe		*qes[4];	/* Each child MACE              */
 	unsigned int            qec_bursts;	/* Support burst sizes          */
-	struct sbus_dev		*qec_sdev;	/* QEC's SBUS device            */
+	struct of_device	*op;		/* QEC's OF device              */
 	struct sunqec		*next_module;	/* List of all QECs in system   */
 };
 
@@ -342,7 +342,7 @@
 	__u32				buffers_dvma;	/* DVMA visible address.       */
 	struct sunqec			*parent;
 	u8				mconfig;	/* Base MACE mconfig value     */
-	struct sbus_dev			*qe_sdev;	/* QE's SBUS device struct     */
+	struct of_device		*op;		/* QE's OF device struct       */
 	struct net_device		*dev;		/* QE's netdevice struct       */
 	int				channel;	/* Who am I?                   */
 };
diff --git a/drivers/net/sunvnet.c b/drivers/net/sunvnet.c
index 6415ce1..a720065 100644
--- a/drivers/net/sunvnet.c
+++ b/drivers/net/sunvnet.c
@@ -1,6 +1,6 @@
 /* sunvnet.c: Sun LDOM Virtual Network Driver.
  *
- * Copyright (C) 2007 David S. Miller <davem@davemloft.net>
+ * Copyright (C) 2007, 2008 David S. Miller <davem@davemloft.net>
  */
 
 #include <linux/module.h>
@@ -1260,7 +1260,7 @@
 	return 0;
 }
 
-static struct vio_device_id vnet_port_match[] = {
+static const struct vio_device_id vnet_port_match[] = {
 	{
 		.type = "vnet-port",
 	},
diff --git a/drivers/net/tc35815.c b/drivers/net/tc35815.c
index 8487ace..df20caf 100644
--- a/drivers/net/tc35815.c
+++ b/drivers/net/tc35815.c
@@ -424,7 +424,7 @@
 	 */
 	spinlock_t lock;
 
-	struct mii_bus mii_bus;
+	struct mii_bus *mii_bus;
 	struct phy_device *phy_dev;
 	int duplex;
 	int speed;
@@ -704,13 +704,13 @@
 
 	/* find the first phy */
 	for (phy_addr = 0; phy_addr < PHY_MAX_ADDR; phy_addr++) {
-		if (lp->mii_bus.phy_map[phy_addr]) {
+		if (lp->mii_bus->phy_map[phy_addr]) {
 			if (phydev) {
 				printk(KERN_ERR "%s: multiple PHYs found\n",
 				       dev->name);
 				return -EINVAL;
 			}
-			phydev = lp->mii_bus.phy_map[phy_addr];
+			phydev = lp->mii_bus->phy_map[phy_addr];
 			break;
 		}
 	}
@@ -762,23 +762,29 @@
 	int err;
 	int i;
 
-	lp->mii_bus.name = "tc35815_mii_bus";
-	lp->mii_bus.read = tc_mdio_read;
-	lp->mii_bus.write = tc_mdio_write;
-	snprintf(lp->mii_bus.id, MII_BUS_ID_SIZE, "%x",
-		 (lp->pci_dev->bus->number << 8) | lp->pci_dev->devfn);
-	lp->mii_bus.priv = dev;
-	lp->mii_bus.dev = &lp->pci_dev->dev;
-	lp->mii_bus.irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL);
-	if (!lp->mii_bus.irq) {
+	lp->mii_bus = mdiobus_alloc();
+	if (lp->mii_bus == NULL) {
 		err = -ENOMEM;
 		goto err_out;
 	}
 
-	for (i = 0; i < PHY_MAX_ADDR; i++)
-		lp->mii_bus.irq[i] = PHY_POLL;
+	lp->mii_bus->name = "tc35815_mii_bus";
+	lp->mii_bus->read = tc_mdio_read;
+	lp->mii_bus->write = tc_mdio_write;
+	snprintf(lp->mii_bus->id, MII_BUS_ID_SIZE, "%x",
+		 (lp->pci_dev->bus->number << 8) | lp->pci_dev->devfn);
+	lp->mii_bus->priv = dev;
+	lp->mii_bus->parent = &lp->pci_dev->dev;
+	lp->mii_bus->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL);
+	if (!lp->mii_bus->irq) {
+		err = -ENOMEM;
+		goto err_out_free_mii_bus;
+	}
 
-	err = mdiobus_register(&lp->mii_bus);
+	for (i = 0; i < PHY_MAX_ADDR; i++)
+		lp->mii_bus->irq[i] = PHY_POLL;
+
+	err = mdiobus_register(lp->mii_bus);
 	if (err)
 		goto err_out_free_mdio_irq;
 	err = tc_mii_probe(dev);
@@ -787,9 +793,11 @@
 	return 0;
 
 err_out_unregister_bus:
-	mdiobus_unregister(&lp->mii_bus);
+	mdiobus_unregister(lp->mii_bus);
 err_out_free_mdio_irq:
-	kfree(lp->mii_bus.irq);
+	kfree(lp->mii_bus->irq);
+err_out_free_mii_bus:
+	mdiobus_free(lp->mii_bus);
 err_out:
 	return err;
 }
@@ -961,8 +969,9 @@
 	struct tc35815_local *lp = netdev_priv(dev);
 
 	phy_disconnect(lp->phy_dev);
-	mdiobus_unregister(&lp->mii_bus);
-	kfree(lp->mii_bus.irq);
+	mdiobus_unregister(lp->mii_bus);
+	kfree(lp->mii_bus->irq);
+	mdiobus_free(lp->mii_bus);
 	unregister_netdev(dev);
 	free_netdev(dev);
 	pci_set_drvdata(pdev, NULL);
diff --git a/drivers/net/tehuti.h b/drivers/net/tehuti.h
index 7db48f1..efaf84d 100644
--- a/drivers/net/tehuti.h
+++ b/drivers/net/tehuti.h
@@ -539,22 +539,22 @@
 
 #define ERR(fmt, args...) printk(KERN_ERR fmt, ## args)
 #define DBG2(fmt, args...)	\
-	printk(KERN_ERR  "%s:%-5d: " fmt, __FUNCTION__, __LINE__, ## args)
+	printk(KERN_ERR  "%s:%-5d: " fmt, __func__, __LINE__, ## args)
 
 #define BDX_ASSERT(x) BUG_ON(x)
 
 #ifdef DEBUG
 
 #define ENTER          do { \
-	printk(KERN_ERR  "%s:%-5d: ENTER\n", __FUNCTION__, __LINE__); \
+	printk(KERN_ERR  "%s:%-5d: ENTER\n", __func__, __LINE__); \
 } while (0)
 
 #define RET(args...)   do { \
-	printk(KERN_ERR  "%s:%-5d: RETURN\n", __FUNCTION__, __LINE__); \
+	printk(KERN_ERR  "%s:%-5d: RETURN\n", __func__, __LINE__); \
 return args; } while (0)
 
 #define DBG(fmt, args...)	\
-	printk(KERN_ERR  "%s:%-5d: " fmt, __FUNCTION__, __LINE__, ## args)
+	printk(KERN_ERR  "%s:%-5d: " fmt, __func__, __LINE__, ## args)
 #else
 #define ENTER         do {  } while (0)
 #define RET(args...)   return args
diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c
index 71d2c5c..eb9f8f3 100644
--- a/drivers/net/tg3.c
+++ b/drivers/net/tg3.c
@@ -876,7 +876,7 @@
 {
 	u32 val;
 
-	if (tp->mdio_bus.phy_map[PHY_ADDR]->interface !=
+	if (tp->mdio_bus->phy_map[PHY_ADDR]->interface !=
 	    PHY_INTERFACE_MODE_RGMII)
 		return;
 
@@ -920,9 +920,9 @@
 static void tg3_mdio_start(struct tg3 *tp)
 {
 	if (tp->tg3_flags3 & TG3_FLG3_MDIOBUS_INITED) {
-		mutex_lock(&tp->mdio_bus.mdio_lock);
+		mutex_lock(&tp->mdio_bus->mdio_lock);
 		tp->tg3_flags3 &= ~TG3_FLG3_MDIOBUS_PAUSED;
-		mutex_unlock(&tp->mdio_bus.mdio_lock);
+		mutex_unlock(&tp->mdio_bus->mdio_lock);
 	}
 
 	tp->mi_mode &= ~MAC_MI_MODE_AUTO_POLL;
@@ -936,9 +936,9 @@
 static void tg3_mdio_stop(struct tg3 *tp)
 {
 	if (tp->tg3_flags3 & TG3_FLG3_MDIOBUS_INITED) {
-		mutex_lock(&tp->mdio_bus.mdio_lock);
+		mutex_lock(&tp->mdio_bus->mdio_lock);
 		tp->tg3_flags3 |= TG3_FLG3_MDIOBUS_PAUSED;
-		mutex_unlock(&tp->mdio_bus.mdio_lock);
+		mutex_unlock(&tp->mdio_bus->mdio_lock);
 	}
 }
 
@@ -947,7 +947,6 @@
 	int i;
 	u32 reg;
 	struct phy_device *phydev;
-	struct mii_bus *mdio_bus = &tp->mdio_bus;
 
 	tg3_mdio_start(tp);
 
@@ -955,21 +954,23 @@
 	    (tp->tg3_flags3 & TG3_FLG3_MDIOBUS_INITED))
 		return 0;
 
-	memset(mdio_bus, 0, sizeof(*mdio_bus));
+	tp->mdio_bus = mdiobus_alloc();
+	if (tp->mdio_bus == NULL)
+		return -ENOMEM;
 
-	mdio_bus->name     = "tg3 mdio bus";
-	snprintf(mdio_bus->id, MII_BUS_ID_SIZE, "%x",
+	tp->mdio_bus->name     = "tg3 mdio bus";
+	snprintf(tp->mdio_bus->id, MII_BUS_ID_SIZE, "%x",
 		 (tp->pdev->bus->number << 8) | tp->pdev->devfn);
-	mdio_bus->priv     = tp;
-	mdio_bus->dev      = &tp->pdev->dev;
-	mdio_bus->read     = &tg3_mdio_read;
-	mdio_bus->write    = &tg3_mdio_write;
-	mdio_bus->reset    = &tg3_mdio_reset;
-	mdio_bus->phy_mask = ~(1 << PHY_ADDR);
-	mdio_bus->irq      = &tp->mdio_irq[0];
+	tp->mdio_bus->priv     = tp;
+	tp->mdio_bus->parent   = &tp->pdev->dev;
+	tp->mdio_bus->read     = &tg3_mdio_read;
+	tp->mdio_bus->write    = &tg3_mdio_write;
+	tp->mdio_bus->reset    = &tg3_mdio_reset;
+	tp->mdio_bus->phy_mask = ~(1 << PHY_ADDR);
+	tp->mdio_bus->irq      = &tp->mdio_irq[0];
 
 	for (i = 0; i < PHY_MAX_ADDR; i++)
-		mdio_bus->irq[i] = PHY_POLL;
+		tp->mdio_bus->irq[i] = PHY_POLL;
 
 	/* The bus registration will look for all the PHYs on the mdio bus.
 	 * Unfortunately, it does not ensure the PHY is powered up before
@@ -979,7 +980,7 @@
 	if (tg3_readphy(tp, MII_BMCR, &reg) || (reg & BMCR_PDOWN))
 		tg3_bmcr_reset(tp);
 
-	i = mdiobus_register(mdio_bus);
+	i = mdiobus_register(tp->mdio_bus);
 	if (i) {
 		printk(KERN_WARNING "%s: mdiobus_reg failed (0x%x)\n",
 			tp->dev->name, i);
@@ -988,7 +989,7 @@
 
 	tp->tg3_flags3 |= TG3_FLG3_MDIOBUS_INITED;
 
-	phydev = tp->mdio_bus.phy_map[PHY_ADDR];
+	phydev = tp->mdio_bus->phy_map[PHY_ADDR];
 
 	switch (phydev->phy_id) {
 	case TG3_PHY_ID_BCM50610:
@@ -1014,7 +1015,8 @@
 {
 	if (tp->tg3_flags3 & TG3_FLG3_MDIOBUS_INITED) {
 		tp->tg3_flags3 &= ~TG3_FLG3_MDIOBUS_INITED;
-		mdiobus_unregister(&tp->mdio_bus);
+		mdiobus_unregister(tp->mdio_bus);
+		mdiobus_free(tp->mdio_bus);
 		tp->tg3_flags3 &= ~TG3_FLG3_MDIOBUS_PAUSED;
 	}
 }
@@ -1220,7 +1222,7 @@
 	u32 old_tx_mode = tp->tx_mode;
 
 	if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB)
-		autoneg = tp->mdio_bus.phy_map[PHY_ADDR]->autoneg;
+		autoneg = tp->mdio_bus->phy_map[PHY_ADDR]->autoneg;
 	else
 		autoneg = tp->link_config.autoneg;
 
@@ -1257,7 +1259,7 @@
 	u8 oldflowctrl, linkmesg = 0;
 	u32 mac_mode, lcl_adv, rmt_adv;
 	struct tg3 *tp = netdev_priv(dev);
-	struct phy_device *phydev = tp->mdio_bus.phy_map[PHY_ADDR];
+	struct phy_device *phydev = tp->mdio_bus->phy_map[PHY_ADDR];
 
 	spin_lock(&tp->lock);
 
@@ -1334,7 +1336,7 @@
 	/* Bring the PHY back to a known state. */
 	tg3_bmcr_reset(tp);
 
-	phydev = tp->mdio_bus.phy_map[PHY_ADDR];
+	phydev = tp->mdio_bus->phy_map[PHY_ADDR];
 
 	/* Attach the MAC to the PHY. */
 	phydev = phy_connect(tp->dev, phydev->dev.bus_id, tg3_adjust_link,
@@ -1367,7 +1369,7 @@
 	if (!(tp->tg3_flags3 & TG3_FLG3_PHY_CONNECTED))
 		return;
 
-	phydev = tp->mdio_bus.phy_map[PHY_ADDR];
+	phydev = tp->mdio_bus->phy_map[PHY_ADDR];
 
 	if (tp->link_config.phy_is_low_power) {
 		tp->link_config.phy_is_low_power = 0;
@@ -1387,13 +1389,13 @@
 	if (!(tp->tg3_flags3 & TG3_FLG3_PHY_CONNECTED))
 		return;
 
-	phy_stop(tp->mdio_bus.phy_map[PHY_ADDR]);
+	phy_stop(tp->mdio_bus->phy_map[PHY_ADDR]);
 }
 
 static void tg3_phy_fini(struct tg3 *tp)
 {
 	if (tp->tg3_flags3 & TG3_FLG3_PHY_CONNECTED) {
-		phy_disconnect(tp->mdio_bus.phy_map[PHY_ADDR]);
+		phy_disconnect(tp->mdio_bus->phy_map[PHY_ADDR]);
 		tp->tg3_flags3 &= ~TG3_FLG3_PHY_CONNECTED;
 	}
 }
@@ -2049,7 +2051,7 @@
 			struct phy_device *phydev;
 			u32 advertising;
 
-			phydev = tp->mdio_bus.phy_map[PHY_ADDR];
+			phydev = tp->mdio_bus->phy_map[PHY_ADDR];
 
 			tp->link_config.phy_is_low_power = 1;
 
@@ -3861,10 +3863,7 @@
 			return;
 		}
 
-		pci_unmap_single(tp->pdev,
-				 pci_unmap_addr(ri, mapping),
-				 skb_headlen(skb),
-				 PCI_DMA_TODEVICE);
+		skb_dma_unmap(&tp->pdev->dev, skb, DMA_TO_DEVICE);
 
 		ri->skb = NULL;
 
@@ -3874,12 +3873,6 @@
 			ri = &tp->tx_buffers[sw_idx];
 			if (unlikely(ri->skb != NULL || sw_idx == hw_idx))
 				tx_bug = 1;
-
-			pci_unmap_page(tp->pdev,
-				       pci_unmap_addr(ri, mapping),
-				       skb_shinfo(skb)->frags[i].size,
-				       PCI_DMA_TODEVICE);
-
 			sw_idx = NEXT_TX(sw_idx);
 		}
 
@@ -4633,12 +4626,16 @@
 	} else {
 		/* New SKB is guaranteed to be linear. */
 		entry = *start;
-		new_addr = pci_map_single(tp->pdev, new_skb->data, new_skb->len,
-					  PCI_DMA_TODEVICE);
+		ret = skb_dma_map(&tp->pdev->dev, new_skb, DMA_TO_DEVICE);
+		new_addr = skb_shinfo(new_skb)->dma_maps[0];
+
 		/* Make sure new skb does not cross any 4G boundaries.
 		 * Drop the packet if it does.
 		 */
-		if (tg3_4g_overflow_test(new_addr, new_skb->len)) {
+		if (ret || tg3_4g_overflow_test(new_addr, new_skb->len)) {
+			if (!ret)
+				skb_dma_unmap(&tp->pdev->dev, new_skb,
+					      DMA_TO_DEVICE);
 			ret = -1;
 			dev_kfree_skb(new_skb);
 			new_skb = NULL;
@@ -4652,18 +4649,8 @@
 	/* Now clean up the sw ring entries. */
 	i = 0;
 	while (entry != last_plus_one) {
-		int len;
-
-		if (i == 0)
-			len = skb_headlen(skb);
-		else
-			len = skb_shinfo(skb)->frags[i-1].size;
-		pci_unmap_single(tp->pdev,
-				 pci_unmap_addr(&tp->tx_buffers[entry], mapping),
-				 len, PCI_DMA_TODEVICE);
 		if (i == 0) {
 			tp->tx_buffers[entry].skb = new_skb;
-			pci_unmap_addr_set(&tp->tx_buffers[entry], mapping, new_addr);
 		} else {
 			tp->tx_buffers[entry].skb = NULL;
 		}
@@ -4671,6 +4658,7 @@
 		i++;
 	}
 
+	skb_dma_unmap(&tp->pdev->dev, skb, DMA_TO_DEVICE);
 	dev_kfree_skb(skb);
 
 	return ret;
@@ -4705,8 +4693,9 @@
 static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
 	struct tg3 *tp = netdev_priv(dev);
-	dma_addr_t mapping;
 	u32 len, entry, base_flags, mss;
+	struct skb_shared_info *sp;
+	dma_addr_t mapping;
 
 	len = skb_headlen(skb);
 
@@ -4765,11 +4754,16 @@
 			       (vlan_tx_tag_get(skb) << 16));
 #endif
 
-	/* Queue skb data, a.k.a. the main skb fragment. */
-	mapping = pci_map_single(tp->pdev, skb->data, len, PCI_DMA_TODEVICE);
+	if (skb_dma_map(&tp->pdev->dev, skb, DMA_TO_DEVICE)) {
+		dev_kfree_skb(skb);
+		goto out_unlock;
+	}
+
+	sp = skb_shinfo(skb);
+
+	mapping = sp->dma_maps[0];
 
 	tp->tx_buffers[entry].skb = skb;
-	pci_unmap_addr_set(&tp->tx_buffers[entry], mapping, mapping);
 
 	tg3_set_txd(tp, entry, mapping, len, base_flags,
 		    (skb_shinfo(skb)->nr_frags == 0) | (mss << 1));
@@ -4785,13 +4779,8 @@
 			skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
 
 			len = frag->size;
-			mapping = pci_map_page(tp->pdev,
-					       frag->page,
-					       frag->page_offset,
-					       len, PCI_DMA_TODEVICE);
-
+			mapping = sp->dma_maps[i + 1];
 			tp->tx_buffers[entry].skb = NULL;
-			pci_unmap_addr_set(&tp->tx_buffers[entry], mapping, mapping);
 
 			tg3_set_txd(tp, entry, mapping, len,
 				    base_flags, (i == last) | (mss << 1));
@@ -4859,9 +4848,10 @@
 static int tg3_start_xmit_dma_bug(struct sk_buff *skb, struct net_device *dev)
 {
 	struct tg3 *tp = netdev_priv(dev);
-	dma_addr_t mapping;
 	u32 len, entry, base_flags, mss;
+	struct skb_shared_info *sp;
 	int would_hit_hwbug;
+	dma_addr_t mapping;
 
 	len = skb_headlen(skb);
 
@@ -4942,11 +4932,16 @@
 			       (vlan_tx_tag_get(skb) << 16));
 #endif
 
-	/* Queue skb data, a.k.a. the main skb fragment. */
-	mapping = pci_map_single(tp->pdev, skb->data, len, PCI_DMA_TODEVICE);
+	if (skb_dma_map(&tp->pdev->dev, skb, DMA_TO_DEVICE)) {
+		dev_kfree_skb(skb);
+		goto out_unlock;
+	}
+
+	sp = skb_shinfo(skb);
+
+	mapping = sp->dma_maps[0];
 
 	tp->tx_buffers[entry].skb = skb;
-	pci_unmap_addr_set(&tp->tx_buffers[entry], mapping, mapping);
 
 	would_hit_hwbug = 0;
 
@@ -4969,13 +4964,9 @@
 			skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
 
 			len = frag->size;
-			mapping = pci_map_page(tp->pdev,
-					       frag->page,
-					       frag->page_offset,
-					       len, PCI_DMA_TODEVICE);
+			mapping = sp->dma_maps[i + 1];
 
 			tp->tx_buffers[entry].skb = NULL;
-			pci_unmap_addr_set(&tp->tx_buffers[entry], mapping, mapping);
 
 			if (tg3_4g_overflow_test(mapping, len))
 				would_hit_hwbug = 1;
@@ -5128,7 +5119,6 @@
 	for (i = 0; i < TG3_TX_RING_SIZE; ) {
 		struct tx_ring_info *txp;
 		struct sk_buff *skb;
-		int j;
 
 		txp = &tp->tx_buffers[i];
 		skb = txp->skb;
@@ -5138,22 +5128,11 @@
 			continue;
 		}
 
-		pci_unmap_single(tp->pdev,
-				 pci_unmap_addr(txp, mapping),
-				 skb_headlen(skb),
-				 PCI_DMA_TODEVICE);
+		skb_dma_unmap(&tp->pdev->dev, skb, DMA_TO_DEVICE);
+
 		txp->skb = NULL;
 
-		i++;
-
-		for (j = 0; j < skb_shinfo(skb)->nr_frags; j++) {
-			txp = &tp->tx_buffers[i & (TG3_TX_RING_SIZE - 1)];
-			pci_unmap_page(tp->pdev,
-				       pci_unmap_addr(txp, mapping),
-				       skb_shinfo(skb)->frags[j].size,
-				       PCI_DMA_TODEVICE);
-			i++;
-		}
+		i += skb_shinfo(skb)->nr_frags + 1;
 
 		dev_kfree_skb_any(skb);
 	}
@@ -8977,7 +8956,7 @@
 	if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) {
 		if (!(tp->tg3_flags3 & TG3_FLG3_PHY_CONNECTED))
 			return -EAGAIN;
-		return phy_ethtool_gset(tp->mdio_bus.phy_map[PHY_ADDR], cmd);
+		return phy_ethtool_gset(tp->mdio_bus->phy_map[PHY_ADDR], cmd);
 	}
 
 	cmd->supported = (SUPPORTED_Autoneg);
@@ -9018,7 +8997,7 @@
 	if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) {
 		if (!(tp->tg3_flags3 & TG3_FLG3_PHY_CONNECTED))
 			return -EAGAIN;
-		return phy_ethtool_sset(tp->mdio_bus.phy_map[PHY_ADDR], cmd);
+		return phy_ethtool_sset(tp->mdio_bus->phy_map[PHY_ADDR], cmd);
 	}
 
 	if (tp->tg3_flags2 & TG3_FLG2_ANY_SERDES) {
@@ -9166,7 +9145,7 @@
 	if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) {
 		if (!(tp->tg3_flags3 & TG3_FLG3_PHY_CONNECTED))
 			return -EAGAIN;
-		r = phy_start_aneg(tp->mdio_bus.phy_map[PHY_ADDR]);
+		r = phy_start_aneg(tp->mdio_bus->phy_map[PHY_ADDR]);
 	} else {
 		u32 bmcr;
 
@@ -9283,7 +9262,7 @@
 			u32 newadv;
 			struct phy_device *phydev;
 
-			phydev = tp->mdio_bus.phy_map[PHY_ADDR];
+			phydev = tp->mdio_bus->phy_map[PHY_ADDR];
 
 			if (epause->rx_pause) {
 				if (epause->tx_pause)
@@ -10265,7 +10244,7 @@
 	if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) {
 		if (!(tp->tg3_flags3 & TG3_FLG3_PHY_CONNECTED))
 			return -EAGAIN;
-		return phy_mii_ioctl(tp->mdio_bus.phy_map[PHY_ADDR], data, cmd);
+		return phy_mii_ioctl(tp->mdio_bus->phy_map[PHY_ADDR], data, cmd);
 	}
 
 	switch(cmd) {
diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h
index f5b8cab..be252ab 100644
--- a/drivers/net/tg3.h
+++ b/drivers/net/tg3.h
@@ -2197,7 +2197,6 @@
 
 struct tx_ring_info {
 	struct sk_buff			*skb;
-	DECLARE_PCI_UNMAP_ADDR(mapping)
 	u32				prev_vlan_tag;
 };
 
@@ -2557,7 +2556,7 @@
 	int				msi_cap;
 	int				pcix_cap;
 
-	struct mii_bus			mdio_bus;
+	struct mii_bus			*mdio_bus;
 	int				mdio_irq[PHY_MAX_ADDR];
 
 	/* PHY info */
diff --git a/drivers/net/tlan.c b/drivers/net/tlan.c
index ec871f6..c41d687 100644
--- a/drivers/net/tlan.c
+++ b/drivers/net/tlan.c
@@ -29,7 +29,8 @@
  *
  *	Tigran Aivazian <tigran@sco.com>:	TLan_PciProbe() now uses
  *						new PCI BIOS interface.
- *	Alan Cox	<alan@redhat.com>:	Fixed the out of memory
+ *	Alan Cox	<alan@lxorguk.ukuu.org.uk>:
+ *						Fixed the out of memory
  *						handling.
  *
  *	Torben Mathiasen <torben.mathiasen@compaq.com> New Maintainer!
diff --git a/drivers/net/tokenring/smctr.c b/drivers/net/tokenring/smctr.c
index fa73e6e..ed50d28 100644
--- a/drivers/net/tokenring/smctr.c
+++ b/drivers/net/tokenring/smctr.c
@@ -25,7 +25,7 @@
  *  To do:
  *    1. Multicast support.
  *
- *  Initial 2.5 cleanup Alan Cox <alan@redhat.com>  2002/10/28
+ *  Initial 2.5 cleanup Alan Cox <alan@lxorguk.ukuu.org.uk>  2002/10/28
  */
 
 #include <linux/module.h>
diff --git a/drivers/net/tsi108_eth.c b/drivers/net/tsi108_eth.c
index 43fde99..eb1da6f 100644
--- a/drivers/net/tsi108_eth.c
+++ b/drivers/net/tsi108_eth.c
@@ -263,7 +263,7 @@
 			return;
 		udelay(10);
 	}
-	printk(KERN_ERR "%s function time out \n", __FUNCTION__);
+	printk(KERN_ERR "%s function time out \n", __func__);
 }
 
 static int mii_speed(struct mii_if_info *mii)
@@ -1059,7 +1059,7 @@
 			return;
 		udelay(10);
 	}
-	printk(KERN_ERR "%s function time out \n", __FUNCTION__);
+	printk(KERN_ERR "%s function time out \n", __func__);
 }
 
 static void tsi108_reset_ether(struct tsi108_prv_data * data)
@@ -1244,7 +1244,7 @@
 		udelay(10);
 	}
 	if (i == 0)
-		printk(KERN_ERR "%s function time out \n", __FUNCTION__);
+		printk(KERN_ERR "%s function time out \n", __func__);
 
 	if (data->phy_type == TSI108_PHY_BCM54XX) {
 		tsi108_write_mii(data, 0x09, 0x0300);
diff --git a/drivers/net/tulip/de2104x.c b/drivers/net/tulip/de2104x.c
index 9281d06..124d5d6 100644
--- a/drivers/net/tulip/de2104x.c
+++ b/drivers/net/tulip/de2104x.c
@@ -1418,7 +1418,6 @@
 
 	de_free_rings(de);
 	de_adapter_sleep(de);
-	pci_disable_device(de->pdev);
 	return 0;
 }
 
@@ -1689,6 +1688,7 @@
 	unsigned i;
 
 	dw32 (ROMCmd, 0);	/* Reset the pointer with a dummy write. */
+	udelay(5);
 
 	for (i = 0; i < 6; i++) {
 		int value, boguscnt = 100000;
diff --git a/drivers/net/tulip/de4x5.c b/drivers/net/tulip/de4x5.c
index 617ef41..6444cbe 100644
--- a/drivers/net/tulip/de4x5.c
+++ b/drivers/net/tulip/de4x5.c
@@ -832,7 +832,7 @@
 	s32 csr14;                          /* Saved SIA TX/RX Register     */
 	s32 csr15;                          /* Saved SIA General Register   */
 	int save_cnt;                       /* Flag if state already saved  */
-	struct sk_buff *skb;                /* Save the (re-ordered) skb's  */
+	struct sk_buff_head queue;          /* Save the (re-ordered) skb's  */
     } cache;
     struct de4x5_srom srom;                 /* A copy of the SROM           */
     int cfrv;				    /* Card CFRV copy */
@@ -1128,6 +1128,7 @@
 	printk("      which has an Ethernet PROM CRC error.\n");
 	return -ENXIO;
     } else {
+	skb_queue_head_init(&lp->cache.queue);
 	lp->cache.gepc = GEP_INIT;
 	lp->asBit = GEP_SLNK;
 	lp->asPolarity = GEP_SLNK;
@@ -1487,7 +1488,7 @@
 	}
     } else if (skb->len > 0) {
 	/* If we already have stuff queued locally, use that first */
-	if (lp->cache.skb && !lp->interrupt) {
+	if (!skb_queue_empty(&lp->cache.queue) && !lp->interrupt) {
 	    de4x5_put_cache(dev, skb);
 	    skb = de4x5_get_cache(dev);
 	}
@@ -1580,7 +1581,7 @@
 
     /* Load the TX ring with any locally stored packets */
     if (!test_and_set_bit(0, (void *)&lp->cache.lock)) {
-	while (lp->cache.skb && !netif_queue_stopped(dev) && lp->tx_enable) {
+	while (!skb_queue_empty(&lp->cache.queue) && !netif_queue_stopped(dev) && lp->tx_enable) {
 	    de4x5_queue_pkt(de4x5_get_cache(dev), dev);
 	}
 	lp->cache.lock = 0;
@@ -3679,11 +3680,7 @@
     }
 
     /* Unload the locally queued packets */
-    while (lp->cache.skb) {
-	dev_kfree_skb(de4x5_get_cache(dev));
-    }
-
-    return;
+    __skb_queue_purge(&lp->cache.queue);
 }
 
 /*
@@ -3781,43 +3778,24 @@
 de4x5_put_cache(struct net_device *dev, struct sk_buff *skb)
 {
     struct de4x5_private *lp = netdev_priv(dev);
-    struct sk_buff *p;
 
-    if (lp->cache.skb) {
-	for (p=lp->cache.skb; p->next; p=p->next);
-	p->next = skb;
-    } else {
-	lp->cache.skb = skb;
-    }
-    skb->next = NULL;
-
-    return;
+    __skb_queue_tail(&lp->cache.queue, skb);
 }
 
 static void
 de4x5_putb_cache(struct net_device *dev, struct sk_buff *skb)
 {
     struct de4x5_private *lp = netdev_priv(dev);
-    struct sk_buff *p = lp->cache.skb;
 
-    lp->cache.skb = skb;
-    skb->next = p;
-
-    return;
+    __skb_queue_head(&lp->cache.queue, skb);
 }
 
 static struct sk_buff *
 de4x5_get_cache(struct net_device *dev)
 {
     struct de4x5_private *lp = netdev_priv(dev);
-    struct sk_buff *p = lp->cache.skb;
 
-    if (p) {
-	lp->cache.skb = p->next;
-	p->next = NULL;
-    }
-
-    return p;
+    return __skb_dequeue(&lp->cache.queue);
 }
 
 /*
diff --git a/drivers/net/tulip/dmfe.c b/drivers/net/tulip/dmfe.c
index 6562004..8e46a51 100644
--- a/drivers/net/tulip/dmfe.c
+++ b/drivers/net/tulip/dmfe.c
@@ -23,7 +23,7 @@
     Marcelo Tosatti <marcelo@conectiva.com.br> :
     Made it compile in 2.3 (device to net_device)
 
-    Alan Cox <alan@redhat.com> :
+    Alan Cox <alan@lxorguk.ukuu.org.uk> :
     Cleaned up for kernel merge.
     Removed the back compatibility support
     Reformatted, fixing spelling etc as I went
@@ -49,7 +49,7 @@
     support.  Updated PCI resource allocation.  Do not
     forget to unmap PCI mapped skbs.
 
-    Alan Cox <alan@redhat.com>
+    Alan Cox <alan@lxorguk.ukuu.org.uk>
     Added new PCI identifiers provided by Clear Zhang at ALi
     for their 1563 ethernet device.
 
diff --git a/drivers/net/ucc_geth.c b/drivers/net/ucc_geth.c
index 8f944e5..c87747b 100644
--- a/drivers/net/ucc_geth.c
+++ b/drivers/net/ucc_geth.c
@@ -400,7 +400,7 @@
 	enet_addr_cont = kmalloc(sizeof(struct enet_addr_container), GFP_KERNEL);
 	if (!enet_addr_cont) {
 		ugeth_err("%s: No memory for enet_addr_container object.",
-			  __FUNCTION__);
+			  __func__);
 		return NULL;
 	}
 
@@ -427,7 +427,7 @@
 	struct ucc_geth_82xx_address_filtering_pram *p_82xx_addr_filt;
 
 	if (!(paddr_num < NUM_OF_PADDRS)) {
-		ugeth_warn("%s: Illegal paddr_num.", __FUNCTION__);
+		ugeth_warn("%s: Illegal paddr_num.", __func__);
 		return -EINVAL;
 	}
 
@@ -447,7 +447,7 @@
 	struct ucc_geth_82xx_address_filtering_pram __iomem *p_82xx_addr_filt;
 
 	if (!(paddr_num < NUM_OF_PADDRS)) {
-		ugeth_warn("%s: Illagel paddr_num.", __FUNCTION__);
+		ugeth_warn("%s: Illagel paddr_num.", __func__);
 		return -EINVAL;
 	}
 
@@ -1441,7 +1441,7 @@
 	u32 upsmr, maccfg2, tbiBaseAddress;
 	u16 value;
 
-	ugeth_vdbg("%s: IN", __FUNCTION__);
+	ugeth_vdbg("%s: IN", __func__);
 
 	ug_info = ugeth->ug_info;
 	ug_regs = ugeth->ug_regs;
@@ -1504,7 +1504,7 @@
 	if (ret_val != 0) {
 		if (netif_msg_probe(ugeth))
 			ugeth_err("%s: Preamble length must be between 3 and 7 inclusive.",
-			     __FUNCTION__);
+			     __func__);
 		return ret_val;
 	}
 
@@ -1744,7 +1744,7 @@
 	/* check if the UCC number is in range. */
 	if (ugeth->ug_info->uf_info.ucc_num >= UCC_MAX_NUM) {
 		if (netif_msg_probe(ugeth))
-			ugeth_err("%s: ucc_num out of range.", __FUNCTION__);
+			ugeth_err("%s: ucc_num out of range.", __func__);
 		return -EINVAL;
 	}
 
@@ -1773,7 +1773,7 @@
 	/* check if the UCC number is in range. */
 	if (ugeth->ug_info->uf_info.ucc_num >= UCC_MAX_NUM) {
 		if (netif_msg_probe(ugeth))
-			ugeth_err("%s: ucc_num out of range.", __FUNCTION__);
+			ugeth_err("%s: ucc_num out of range.", __func__);
 		return -EINVAL;
 	}
 
@@ -2062,7 +2062,7 @@
 		ugeth_warn
 		    ("%s: multicast address added to paddr will have no "
 		     "effect - is this what you wanted?",
-		     __FUNCTION__);
+		     __func__);
 
 	ugeth->indAddrRegUsed[paddr_num] = 1;	/* mark this paddr as used */
 	/* store address in our database */
@@ -2278,7 +2278,7 @@
 	struct phy_device *phydev = ugeth->phydev;
 	u32 tempval;
 
-	ugeth_vdbg("%s: IN", __FUNCTION__);
+	ugeth_vdbg("%s: IN", __func__);
 
 	/* Disable the controller */
 	ugeth_disable(ugeth, COMM_DIR_RX_AND_TX);
@@ -2315,7 +2315,7 @@
 	      (uf_info->bd_mem_part == MEM_PART_MURAM))) {
 		if (netif_msg_probe(ugeth))
 			ugeth_err("%s: Bad memory partition value.",
-					__FUNCTION__);
+					__func__);
 		return -EINVAL;
 	}
 
@@ -2327,7 +2327,7 @@
 			if (netif_msg_probe(ugeth))
 				ugeth_err
 				    ("%s: Rx BD ring length must be multiple of 4, no smaller than 8.",
-					__FUNCTION__);
+					__func__);
 			return -EINVAL;
 		}
 	}
@@ -2338,7 +2338,7 @@
 			if (netif_msg_probe(ugeth))
 				ugeth_err
 				    ("%s: Tx BD ring length must be no smaller than 2.",
-				     __FUNCTION__);
+				     __func__);
 			return -EINVAL;
 		}
 	}
@@ -2349,21 +2349,21 @@
 		if (netif_msg_probe(ugeth))
 			ugeth_err
 			    ("%s: max_rx_buf_length must be non-zero multiple of 128.",
-			     __FUNCTION__);
+			     __func__);
 		return -EINVAL;
 	}
 
 	/* num Tx queues */
 	if (ug_info->numQueuesTx > NUM_TX_QUEUES) {
 		if (netif_msg_probe(ugeth))
-			ugeth_err("%s: number of tx queues too large.", __FUNCTION__);
+			ugeth_err("%s: number of tx queues too large.", __func__);
 		return -EINVAL;
 	}
 
 	/* num Rx queues */
 	if (ug_info->numQueuesRx > NUM_RX_QUEUES) {
 		if (netif_msg_probe(ugeth))
-			ugeth_err("%s: number of rx queues too large.", __FUNCTION__);
+			ugeth_err("%s: number of rx queues too large.", __func__);
 		return -EINVAL;
 	}
 
@@ -2374,7 +2374,7 @@
 				ugeth_err
 				    ("%s: VLAN priority table entry must not be"
 					" larger than number of Rx queues.",
-				     __FUNCTION__);
+				     __func__);
 			return -EINVAL;
 		}
 	}
@@ -2386,7 +2386,7 @@
 				ugeth_err
 				    ("%s: IP priority table entry must not be"
 					" larger than number of Rx queues.",
-				     __FUNCTION__);
+				     __func__);
 			return -EINVAL;
 		}
 	}
@@ -2394,7 +2394,7 @@
 	if (ug_info->cam && !ug_info->ecamptr) {
 		if (netif_msg_probe(ugeth))
 			ugeth_err("%s: If cam mode is chosen, must supply cam ptr.",
-				  __FUNCTION__);
+				  __func__);
 		return -EINVAL;
 	}
 
@@ -2404,7 +2404,7 @@
 		if (netif_msg_probe(ugeth))
 			ugeth_err("%s: Number of station addresses greater than 1 "
 				  "not allowed in extended parsing mode.",
-				  __FUNCTION__);
+				  __func__);
 		return -EINVAL;
 	}
 
@@ -2418,7 +2418,7 @@
 	/* Initialize the general fast UCC block. */
 	if (ucc_fast_init(uf_info, &ugeth->uccf)) {
 		if (netif_msg_probe(ugeth))
-			ugeth_err("%s: Failed to init uccf.", __FUNCTION__);
+			ugeth_err("%s: Failed to init uccf.", __func__);
 		ucc_geth_memclean(ugeth);
 		return -ENOMEM;
 	}
@@ -2448,7 +2448,7 @@
 	u8 __iomem *endOfRing;
 	u8 numThreadsRxNumerical, numThreadsTxNumerical;
 
-	ugeth_vdbg("%s: IN", __FUNCTION__);
+	ugeth_vdbg("%s: IN", __func__);
 	uccf = ugeth->uccf;
 	ug_info = ugeth->ug_info;
 	uf_info = &ug_info->uf_info;
@@ -2474,7 +2474,7 @@
 	default:
 		if (netif_msg_ifup(ugeth))
 			ugeth_err("%s: Bad number of Rx threads value.",
-				       	__FUNCTION__);
+				       	__func__);
 		ucc_geth_memclean(ugeth);
 		return -EINVAL;
 		break;
@@ -2499,7 +2499,7 @@
 	default:
 		if (netif_msg_ifup(ugeth))
 			ugeth_err("%s: Bad number of Tx threads value.",
-				       	__FUNCTION__);
+				       	__func__);
 		ucc_geth_memclean(ugeth);
 		return -EINVAL;
 		break;
@@ -2553,7 +2553,7 @@
 	if (ret_val != 0) {
 		if (netif_msg_ifup(ugeth))
 			ugeth_err("%s: IPGIFG initialization parameter too large.",
-				  __FUNCTION__);
+				  __func__);
 		ucc_geth_memclean(ugeth);
 		return ret_val;
 	}
@@ -2571,7 +2571,7 @@
 	if (ret_val != 0) {
 		if (netif_msg_ifup(ugeth))
 			ugeth_err("%s: Half Duplex initialization parameter too large.",
-			  __FUNCTION__);
+			  __func__);
 		ucc_geth_memclean(ugeth);
 		return ret_val;
 	}
@@ -2626,7 +2626,7 @@
 			if (netif_msg_ifup(ugeth))
 				ugeth_err
 				    ("%s: Can not allocate memory for Tx bd rings.",
-				     __FUNCTION__);
+				     __func__);
 			ucc_geth_memclean(ugeth);
 			return -ENOMEM;
 		}
@@ -2662,7 +2662,7 @@
 			if (netif_msg_ifup(ugeth))
 				ugeth_err
 				    ("%s: Can not allocate memory for Rx bd rings.",
-				     __FUNCTION__);
+				     __func__);
 			ucc_geth_memclean(ugeth);
 			return -ENOMEM;
 		}
@@ -2678,7 +2678,7 @@
 		if (ugeth->tx_skbuff[j] == NULL) {
 			if (netif_msg_ifup(ugeth))
 				ugeth_err("%s: Could not allocate tx_skbuff",
-					  __FUNCTION__);
+					  __func__);
 			ucc_geth_memclean(ugeth);
 			return -ENOMEM;
 		}
@@ -2710,7 +2710,7 @@
 		if (ugeth->rx_skbuff[j] == NULL) {
 			if (netif_msg_ifup(ugeth))
 				ugeth_err("%s: Could not allocate rx_skbuff",
-					  __FUNCTION__);
+					  __func__);
 			ucc_geth_memclean(ugeth);
 			return -ENOMEM;
 		}
@@ -2744,7 +2744,7 @@
 		if (netif_msg_ifup(ugeth))
 			ugeth_err
 			    ("%s: Can not allocate DPRAM memory for p_tx_glbl_pram.",
-			     __FUNCTION__);
+			     __func__);
 		ucc_geth_memclean(ugeth);
 		return -ENOMEM;
 	}
@@ -2767,7 +2767,7 @@
 		if (netif_msg_ifup(ugeth))
 			ugeth_err
 			    ("%s: Can not allocate DPRAM memory for p_thread_data_tx.",
-			     __FUNCTION__);
+			     __func__);
 		ucc_geth_memclean(ugeth);
 		return -ENOMEM;
 	}
@@ -2797,7 +2797,7 @@
 		if (netif_msg_ifup(ugeth))
 			ugeth_err
 			    ("%s: Can not allocate DPRAM memory for p_send_q_mem_reg.",
-			     __FUNCTION__);
+			     __func__);
 		ucc_geth_memclean(ugeth);
 		return -ENOMEM;
 	}
@@ -2841,7 +2841,7 @@
 			if (netif_msg_ifup(ugeth))
 				ugeth_err
 				 ("%s: Can not allocate DPRAM memory for p_scheduler.",
-				     __FUNCTION__);
+				     __func__);
 			ucc_geth_memclean(ugeth);
 			return -ENOMEM;
 		}
@@ -2892,7 +2892,7 @@
 				ugeth_err
 				    ("%s: Can not allocate DPRAM memory for"
 					" p_tx_fw_statistics_pram.",
-				       	__FUNCTION__);
+				       	__func__);
 			ucc_geth_memclean(ugeth);
 			return -ENOMEM;
 		}
@@ -2932,7 +2932,7 @@
 		if (netif_msg_ifup(ugeth))
 			ugeth_err
 			    ("%s: Can not allocate DPRAM memory for p_rx_glbl_pram.",
-			     __FUNCTION__);
+			     __func__);
 		ucc_geth_memclean(ugeth);
 		return -ENOMEM;
 	}
@@ -2954,7 +2954,7 @@
 		if (netif_msg_ifup(ugeth))
 			ugeth_err
 			    ("%s: Can not allocate DPRAM memory for p_thread_data_rx.",
-			     __FUNCTION__);
+			     __func__);
 		ucc_geth_memclean(ugeth);
 		return -ENOMEM;
 	}
@@ -2978,7 +2978,7 @@
 			if (netif_msg_ifup(ugeth))
 				ugeth_err
 					("%s: Can not allocate DPRAM memory for"
-					" p_rx_fw_statistics_pram.", __FUNCTION__);
+					" p_rx_fw_statistics_pram.", __func__);
 			ucc_geth_memclean(ugeth);
 			return -ENOMEM;
 		}
@@ -3001,7 +3001,7 @@
 		if (netif_msg_ifup(ugeth))
 			ugeth_err
 			    ("%s: Can not allocate DPRAM memory for"
-				" p_rx_irq_coalescing_tbl.", __FUNCTION__);
+				" p_rx_irq_coalescing_tbl.", __func__);
 		ucc_geth_memclean(ugeth);
 		return -ENOMEM;
 	}
@@ -3070,7 +3070,7 @@
 		if (netif_msg_ifup(ugeth))
 			ugeth_err
 			    ("%s: Can not allocate DPRAM memory for p_rx_bd_qs_tbl.",
-			     __FUNCTION__);
+			     __func__);
 		ucc_geth_memclean(ugeth);
 		return -ENOMEM;
 	}
@@ -3147,7 +3147,7 @@
 		if (!ug_info->extendedFilteringChainPointer) {
 			if (netif_msg_ifup(ugeth))
 				ugeth_err("%s: Null Extended Filtering Chain Pointer.",
-					  __FUNCTION__);
+					  __func__);
 			ucc_geth_memclean(ugeth);
 			return -EINVAL;
 		}
@@ -3161,7 +3161,7 @@
 			if (netif_msg_ifup(ugeth))
 				ugeth_err
 					("%s: Can not allocate DPRAM memory for"
-					" p_exf_glbl_param.", __FUNCTION__);
+					" p_exf_glbl_param.", __func__);
 			ucc_geth_memclean(ugeth);
 			return -ENOMEM;
 		}
@@ -3209,7 +3209,7 @@
 		if (netif_msg_ifup(ugeth))
 			ugeth_err
 			    ("%s: Can not allocate memory for"
-				" p_UccInitEnetParamShadows.", __FUNCTION__);
+				" p_UccInitEnetParamShadows.", __func__);
 		ucc_geth_memclean(ugeth);
 		return -ENOMEM;
 	}
@@ -3244,7 +3244,7 @@
 		QE_FLTR_LARGEST_EXTERNAL_TABLE_LOOKUP_KEY_SIZE_16_BYTES)) {
 		if (netif_msg_ifup(ugeth))
 			ugeth_err("%s: Invalid largest External Lookup Key Size.",
-				  __FUNCTION__);
+				  __func__);
 		ucc_geth_memclean(ugeth);
 		return -EINVAL;
 	}
@@ -3271,7 +3271,7 @@
 		ug_info->riscRx, 1)) != 0) {
 		if (netif_msg_ifup(ugeth))
 				ugeth_err("%s: Can not fill p_init_enet_param_shadow.",
-					__FUNCTION__);
+					__func__);
 		ucc_geth_memclean(ugeth);
 		return ret_val;
 	}
@@ -3287,7 +3287,7 @@
 				    ug_info->riscTx, 0)) != 0) {
 		if (netif_msg_ifup(ugeth))
 			ugeth_err("%s: Can not fill p_init_enet_param_shadow.",
-				  __FUNCTION__);
+				  __func__);
 		ucc_geth_memclean(ugeth);
 		return ret_val;
 	}
@@ -3297,7 +3297,7 @@
 		if ((ret_val = rx_bd_buffer_set(ugeth, (u8) i)) != 0) {
 			if (netif_msg_ifup(ugeth))
 				ugeth_err("%s: Can not fill Rx bds with buffers.",
-					  __FUNCTION__);
+					  __func__);
 			ucc_geth_memclean(ugeth);
 			return ret_val;
 		}
@@ -3309,7 +3309,7 @@
 		if (netif_msg_ifup(ugeth))
 			ugeth_err
 			    ("%s: Can not allocate DPRAM memory for p_init_enet_pram.",
-			     __FUNCTION__);
+			     __func__);
 		ucc_geth_memclean(ugeth);
 		return -ENOMEM;
 	}
@@ -3360,7 +3360,7 @@
 {
 	struct ucc_geth_private *ugeth = netdev_priv(dev);
 
-	ugeth_vdbg("%s: IN", __FUNCTION__);
+	ugeth_vdbg("%s: IN", __func__);
 
 	dev->stats.tx_errors++;
 
@@ -3386,7 +3386,7 @@
 	u32 bd_status;
 	u8 txQ = 0;
 
-	ugeth_vdbg("%s: IN", __FUNCTION__);
+	ugeth_vdbg("%s: IN", __func__);
 
 	spin_lock_irq(&ugeth->lock);
 
@@ -3459,7 +3459,7 @@
 	u8 *bdBuffer;
 	struct net_device *dev;
 
-	ugeth_vdbg("%s: IN", __FUNCTION__);
+	ugeth_vdbg("%s: IN", __func__);
 
 	dev = ugeth->dev;
 
@@ -3481,7 +3481,7 @@
 		    (bd_status & R_ERRORS_FATAL)) {
 			if (netif_msg_rx_err(ugeth))
 				ugeth_err("%s, %d: ERROR!!! skb - 0x%08x",
-					   __FUNCTION__, __LINE__, (u32) skb);
+					   __func__, __LINE__, (u32) skb);
 			if (skb)
 				dev_kfree_skb_any(skb);
 
@@ -3507,7 +3507,7 @@
 		skb = get_new_skb(ugeth, bd);
 		if (!skb) {
 			if (netif_msg_rx_err(ugeth))
-				ugeth_warn("%s: No Rx Data Buffer", __FUNCTION__);
+				ugeth_warn("%s: No Rx Data Buffer", __func__);
 			dev->stats.rx_dropped++;
 			break;
 		}
@@ -3613,7 +3613,7 @@
 	register u32 tx_mask;
 	u8 i;
 
-	ugeth_vdbg("%s: IN", __FUNCTION__);
+	ugeth_vdbg("%s: IN", __func__);
 
 	uccf = ugeth->uccf;
 	ug_info = ugeth->ug_info;
@@ -3683,13 +3683,13 @@
 	struct ucc_geth_private *ugeth = netdev_priv(dev);
 	int err;
 
-	ugeth_vdbg("%s: IN", __FUNCTION__);
+	ugeth_vdbg("%s: IN", __func__);
 
 	/* Test station address */
 	if (dev->dev_addr[0] & ENET_GROUP_ADDR) {
 		if (netif_msg_ifup(ugeth))
 			ugeth_err("%s: Multicast address used for station address"
-				  " - is this what you wanted?", __FUNCTION__);
+				  " - is this what you wanted?", __func__);
 		return -EINVAL;
 	}
 
@@ -3772,7 +3772,7 @@
 {
 	struct ucc_geth_private *ugeth = netdev_priv(dev);
 
-	ugeth_vdbg("%s: IN", __FUNCTION__);
+	ugeth_vdbg("%s: IN", __func__);
 
 	napi_disable(&ugeth->napi);
 
@@ -3840,7 +3840,7 @@
 		PHY_INTERFACE_MODE_TBI, PHY_INTERFACE_MODE_RTBI,
 	};
 
-	ugeth_vdbg("%s: IN", __FUNCTION__);
+	ugeth_vdbg("%s: IN", __func__);
 
 	prop = of_get_property(np, "cell-index", NULL);
 	if (!prop) {
@@ -3857,7 +3857,7 @@
 	if (ug_info == NULL) {
 		if (netif_msg_probe(&debug))
 			ugeth_err("%s: [%d] Missing additional data!",
-				       	__FUNCTION__, ucc_num);
+				       	__func__, ucc_num);
 		return -ENODEV;
 	}
 
diff --git a/drivers/net/ucc_geth_mii.c b/drivers/net/ucc_geth_mii.c
index 6d9e7ad..c001d26 100644
--- a/drivers/net/ucc_geth_mii.c
+++ b/drivers/net/ucc_geth_mii.c
@@ -141,8 +141,7 @@
 	struct resource res;
 	int k, err = 0;
 
-	new_bus = kzalloc(sizeof(struct mii_bus), GFP_KERNEL);
-
+	new_bus = mdiobus_alloc();
 	if (NULL == new_bus)
 		return -ENOMEM;
 
@@ -187,7 +186,7 @@
 
 	new_bus->priv = (void __force *)regs;
 
-	new_bus->dev = device;
+	new_bus->parent = device;
 	dev_set_drvdata(device, new_bus);
 
 	/* Read MII management master from device tree */
@@ -235,7 +234,7 @@
 ioremap_fail:
 	kfree(new_bus->irq);
 reg_map_fail:
-	kfree(new_bus);
+	mdiobus_free(new_bus);
 
 	return err;
 }
@@ -251,7 +250,7 @@
 
 	iounmap((void __iomem *)bus->priv);
 	bus->priv = NULL;
-	kfree(bus);
+	mdiobus_free(bus);
 
 	return 0;
 }
diff --git a/drivers/net/usb/Kconfig b/drivers/net/usb/Kconfig
index 0973b6e..8ee2103 100644
--- a/drivers/net/usb/Kconfig
+++ b/drivers/net/usb/Kconfig
@@ -188,6 +188,14 @@
 	  This option adds support for Davicom DM9601 based USB 1.1
 	  10/100 Ethernet adapters.
 
+config USB_NET_SMSC95XX
+	tristate "SMSC LAN95XX based USB 2.0 10/100 ethernet devices"
+	depends on USB_USBNET
+	select CRC32
+	help
+	  This option adds support for SMSC LAN95XX based USB 2.0
+	  10/100 Ethernet adapters.
+
 config USB_NET_GL620A
 	tristate "GeneSys GL620USB-A based cables"
 	depends on USB_USBNET
diff --git a/drivers/net/usb/Makefile b/drivers/net/usb/Makefile
index 24800c1..88a87eeb3 100644
--- a/drivers/net/usb/Makefile
+++ b/drivers/net/usb/Makefile
@@ -10,6 +10,7 @@
 obj-$(CONFIG_USB_NET_AX8817X)	+= asix.o
 obj-$(CONFIG_USB_NET_CDCETHER)	+= cdc_ether.o
 obj-$(CONFIG_USB_NET_DM9601)	+= dm9601.o
+obj-$(CONFIG_USB_NET_SMSC95XX)	+= smsc95xx.o
 obj-$(CONFIG_USB_NET_GL620A)	+= gl620a.o
 obj-$(CONFIG_USB_NET_NET1080)	+= net1080.o
 obj-$(CONFIG_USB_NET_PLUSB)	+= plusb.o
@@ -19,6 +20,3 @@
 obj-$(CONFIG_USB_NET_MCS7830)	+= mcs7830.o
 obj-$(CONFIG_USB_USBNET)	+= usbnet.o
 
-ifeq ($(CONFIG_USB_DEBUG),y)
-EXTRA_CFLAGS += -DDEBUG
-endif
diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c
index 6e42b5a..1164c52 100644
--- a/drivers/net/usb/hso.c
+++ b/drivers/net/usb/hso.c
@@ -92,9 +92,6 @@
 
 #define	HSO_NET_TX_TIMEOUT		(HZ*10)
 
-/* Serial port defines and structs. */
-#define HSO_SERIAL_FLAG_RX_SENT		0
-
 #define HSO_SERIAL_MAGIC		0x48534f31
 
 /* Number of ttys to handle */
@@ -179,6 +176,12 @@
 	unsigned long flags;
 };
 
+enum rx_ctrl_state{
+	RX_IDLE,
+	RX_SENT,
+	RX_PENDING
+};
+
 struct hso_serial {
 	struct hso_device *parent;
 	int magic;
@@ -205,7 +208,7 @@
 	struct usb_endpoint_descriptor *in_endp;
 	struct usb_endpoint_descriptor *out_endp;
 
-	unsigned long flags;
+	enum rx_ctrl_state rx_state;
 	u8 rts_state;
 	u8 dtr_state;
 	unsigned tx_urb_used:1;
@@ -216,6 +219,15 @@
 	spinlock_t serial_lock;
 
 	int (*write_data) (struct hso_serial *serial);
+	/* Hacks required to get flow control
+	 * working on the serial receive buffers
+	 * so as not to drop characters on the floor.
+	 */
+	int  curr_rx_urb_idx;
+	u16  curr_rx_urb_offset;
+	u8   rx_urb_filled[MAX_RX_URBS];
+	struct tasklet_struct unthrottle_tasklet;
+	struct work_struct    retry_unthrottle_workqueue;
 };
 
 struct hso_device {
@@ -271,7 +283,7 @@
 static int hso_serial_tiocmset(struct tty_struct *tty, struct file *file,
 			       unsigned int set, unsigned int clear);
 static void ctrl_callback(struct urb *urb);
-static void put_rxbuf_data(struct urb *urb, struct hso_serial *serial);
+static int put_rxbuf_data(struct urb *urb, struct hso_serial *serial);
 static void hso_kick_transmit(struct hso_serial *serial);
 /* Helper functions */
 static int hso_mux_submit_intr_urb(struct hso_shared_int *mux_int,
@@ -287,6 +299,8 @@
 static void hso_free_shared_int(struct hso_shared_int *shared_int);
 static int hso_stop_net_device(struct hso_device *hso_dev);
 static void hso_serial_ref_free(struct kref *ref);
+static void hso_std_serial_read_bulk_callback(struct urb *urb);
+static int hso_mux_serial_read(struct hso_serial *serial);
 static void async_get_intf(struct work_struct *data);
 static void async_put_intf(struct work_struct *data);
 static int hso_put_activity(struct hso_device *hso_dev);
@@ -458,6 +472,17 @@
 }
 static DEVICE_ATTR(hsotype, S_IRUGO, hso_sysfs_show_porttype, NULL);
 
+static int hso_urb_to_index(struct hso_serial *serial, struct urb *urb)
+{
+	int idx;
+
+	for (idx = 0; idx < serial->num_rx_urbs; idx++)
+		if (serial->rx_urb[idx] == urb)
+			return idx;
+	dev_err(serial->parent->dev, "hso_urb_to_index failed\n");
+	return -1;
+}
+
 /* converts mux value to a port spec value */
 static u32 hso_mux_to_port(int mux)
 {
@@ -1039,6 +1064,158 @@
 	return;
 }
 
+static void hso_resubmit_rx_bulk_urb(struct hso_serial *serial, struct urb *urb)
+{
+	int result;
+#ifdef CONFIG_HSO_AUTOPM
+	usb_mark_last_busy(urb->dev);
+#endif
+	/* We are done with this URB, resubmit it. Prep the USB to wait for
+	 * another frame */
+	usb_fill_bulk_urb(urb, serial->parent->usb,
+			  usb_rcvbulkpipe(serial->parent->usb,
+					  serial->in_endp->
+					  bEndpointAddress & 0x7F),
+			  urb->transfer_buffer, serial->rx_data_length,
+			  hso_std_serial_read_bulk_callback, serial);
+	/* Give this to the USB subsystem so it can tell us when more data
+	 * arrives. */
+	result = usb_submit_urb(urb, GFP_ATOMIC);
+	if (result) {
+		dev_err(&urb->dev->dev, "%s failed submit serial rx_urb %d\n",
+			__func__, result);
+	}
+}
+
+
+
+
+static void put_rxbuf_data_and_resubmit_bulk_urb(struct hso_serial *serial)
+{
+	int count;
+	struct urb *curr_urb;
+
+	while (serial->rx_urb_filled[serial->curr_rx_urb_idx]) {
+		curr_urb = serial->rx_urb[serial->curr_rx_urb_idx];
+		count = put_rxbuf_data(curr_urb, serial);
+		if (count == -1)
+			return;
+		if (count == 0) {
+			serial->curr_rx_urb_idx++;
+			if (serial->curr_rx_urb_idx >= serial->num_rx_urbs)
+				serial->curr_rx_urb_idx = 0;
+			hso_resubmit_rx_bulk_urb(serial, curr_urb);
+		}
+	}
+}
+
+static void put_rxbuf_data_and_resubmit_ctrl_urb(struct hso_serial *serial)
+{
+	int count = 0;
+	struct urb *urb;
+
+	urb = serial->rx_urb[0];
+	if (serial->open_count > 0) {
+		count = put_rxbuf_data(urb, serial);
+		if (count == -1)
+			return;
+	}
+	/* Re issue a read as long as we receive data. */
+
+	if (count == 0 && ((urb->actual_length != 0) ||
+			   (serial->rx_state == RX_PENDING))) {
+		serial->rx_state = RX_SENT;
+		hso_mux_serial_read(serial);
+	} else
+		serial->rx_state = RX_IDLE;
+}
+
+
+/* read callback for Diag and CS port */
+static void hso_std_serial_read_bulk_callback(struct urb *urb)
+{
+	struct hso_serial *serial = urb->context;
+	int status = urb->status;
+
+	/* sanity check */
+	if (!serial) {
+		D1("serial == NULL");
+		return;
+	} else if (status) {
+		log_usb_status(status, __func__);
+		return;
+	}
+
+	D4("\n--- Got serial_read_bulk callback %02x ---", status);
+	D1("Actual length = %d\n", urb->actual_length);
+	DUMP1(urb->transfer_buffer, urb->actual_length);
+
+	/* Anyone listening? */
+	if (serial->open_count == 0)
+		return;
+
+	if (status == 0) {
+		if (serial->parent->port_spec & HSO_INFO_CRC_BUG) {
+			u32 rest;
+			u8 crc_check[4] = { 0xDE, 0xAD, 0xBE, 0xEF };
+			rest =
+			    urb->actual_length %
+			    serial->in_endp->wMaxPacketSize;
+			if (((rest == 5) || (rest == 6))
+			    && !memcmp(((u8 *) urb->transfer_buffer) +
+				       urb->actual_length - 4, crc_check, 4)) {
+				urb->actual_length -= 4;
+			}
+		}
+		/* Valid data, handle RX data */
+		spin_lock(&serial->serial_lock);
+		serial->rx_urb_filled[hso_urb_to_index(serial, urb)] = 1;
+		put_rxbuf_data_and_resubmit_bulk_urb(serial);
+		spin_unlock(&serial->serial_lock);
+	} else if (status == -ENOENT || status == -ECONNRESET) {
+		/* Unlinked - check for throttled port. */
+		D2("Port %d, successfully unlinked urb", serial->minor);
+		spin_lock(&serial->serial_lock);
+		serial->rx_urb_filled[hso_urb_to_index(serial, urb)] = 0;
+		hso_resubmit_rx_bulk_urb(serial, urb);
+		spin_unlock(&serial->serial_lock);
+	} else {
+		D2("Port %d, status = %d for read urb", serial->minor, status);
+		return;
+	}
+}
+
+/*
+ * This needs to be a tasklet otherwise we will
+ * end up recursively calling this function.
+ */
+void hso_unthrottle_tasklet(struct hso_serial *serial)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&serial->serial_lock, flags);
+	if ((serial->parent->port_spec & HSO_INTF_MUX))
+		put_rxbuf_data_and_resubmit_ctrl_urb(serial);
+	else
+		put_rxbuf_data_and_resubmit_bulk_urb(serial);
+	spin_unlock_irqrestore(&serial->serial_lock, flags);
+}
+
+static	void hso_unthrottle(struct tty_struct *tty)
+{
+	struct hso_serial *serial = get_serial_by_tty(tty);
+
+	tasklet_hi_schedule(&serial->unthrottle_tasklet);
+}
+
+void hso_unthrottle_workfunc(struct work_struct *work)
+{
+	struct hso_serial *serial =
+	    container_of(work, struct hso_serial,
+			 retry_unthrottle_workqueue);
+	hso_unthrottle_tasklet(serial);
+}
+
 /* open the requested serial port */
 static int hso_serial_open(struct tty_struct *tty, struct file *filp)
 {
@@ -1064,13 +1241,18 @@
 	tty->driver_data = serial;
 	serial->tty = tty;
 
-	/* check for port allready opened, if not set the termios */
+	/* check for port already opened, if not set the termios */
 	serial->open_count++;
 	if (serial->open_count == 1) {
 		tty->low_latency = 1;
-		serial->flags = 0;
+		serial->rx_state = RX_IDLE;
 		/* Force default termio settings */
 		_hso_serial_set_termios(tty, NULL);
+		tasklet_init(&serial->unthrottle_tasklet,
+			     (void (*)(unsigned long))hso_unthrottle_tasklet,
+			     (unsigned long)serial);
+		INIT_WORK(&serial->retry_unthrottle_workqueue,
+			  hso_unthrottle_workfunc);
 		result = hso_start_serial_device(serial->parent, GFP_KERNEL);
 		if (result) {
 			hso_stop_serial_device(serial->parent);
@@ -1117,9 +1299,13 @@
 		}
 		if (!usb_gone)
 			hso_stop_serial_device(serial->parent);
+		tasklet_kill(&serial->unthrottle_tasklet);
+		cancel_work_sync(&serial->retry_unthrottle_workqueue);
 	}
+
 	if (!usb_gone)
 		usb_autopm_put_interface(serial->parent->interface);
+
 	mutex_unlock(&serial->parent->mutex);
 }
 
@@ -1422,15 +1608,21 @@
 								   (1 << i));
 			if (serial != NULL) {
 				D1("Pending read interrupt on port %d\n", i);
-				if (!test_and_set_bit(HSO_SERIAL_FLAG_RX_SENT,
-						      &serial->flags)) {
+				spin_lock(&serial->serial_lock);
+				if (serial->rx_state == RX_IDLE) {
 					/* Setup and send a ctrl req read on
 					 * port i */
-					hso_mux_serial_read(serial);
+				if (!serial->rx_urb_filled[0]) {
+						serial->rx_state = RX_SENT;
+						hso_mux_serial_read(serial);
+					} else
+						serial->rx_state = RX_PENDING;
+
 				} else {
 					D1("Already pending a read on "
 					   "port %d\n", i);
 				}
+				spin_unlock(&serial->serial_lock);
 			}
 		}
 	}
@@ -1532,16 +1724,10 @@
 	if (req->bRequestType ==
 	    (USB_DIR_IN | USB_TYPE_OPTION_VENDOR | USB_RECIP_INTERFACE)) {
 		/* response to a read command */
-		if (serial->open_count > 0) {
-			/* handle RX data the normal way */
-			put_rxbuf_data(urb, serial);
-		}
-
-		/* Re issue a read as long as we receive data. */
-		if (urb->actual_length != 0)
-			hso_mux_serial_read(serial);
-		else
-			clear_bit(HSO_SERIAL_FLAG_RX_SENT, &serial->flags);
+		serial->rx_urb_filled[0] = 1;
+		spin_lock(&serial->serial_lock);
+		put_rxbuf_data_and_resubmit_ctrl_urb(serial);
+		spin_unlock(&serial->serial_lock);
 	} else {
 		hso_put_activity(serial->parent);
 		if (serial->tty)
@@ -1552,91 +1738,42 @@
 }
 
 /* handle RX data for serial port */
-static void put_rxbuf_data(struct urb *urb, struct hso_serial *serial)
+static int put_rxbuf_data(struct urb *urb, struct hso_serial *serial)
 {
 	struct tty_struct *tty = serial->tty;
-
+	int write_length_remaining = 0;
+	int curr_write_len;
 	/* Sanity check */
 	if (urb == NULL || serial == NULL) {
 		D1("serial = NULL");
-		return;
+		return -2;
 	}
 
 	/* Push data to tty */
-	if (tty && urb->actual_length) {
+	if (tty) {
+		write_length_remaining = urb->actual_length -
+			serial->curr_rx_urb_offset;
 		D1("data to push to tty");
-		tty_insert_flip_string(tty, urb->transfer_buffer,
-				       urb->actual_length);
-		tty_flip_buffer_push(tty);
-	}
-}
-
-/* read callback for Diag and CS port */
-static void hso_std_serial_read_bulk_callback(struct urb *urb)
-{
-	struct hso_serial *serial = urb->context;
-	int result;
-	int status = urb->status;
-
-	/* sanity check */
-	if (!serial) {
-		D1("serial == NULL");
-		return;
-	} else if (status) {
-		log_usb_status(status, __func__);
-		return;
-	}
-
-	D4("\n--- Got serial_read_bulk callback %02x ---", status);
-	D1("Actual length = %d\n", urb->actual_length);
-	DUMP1(urb->transfer_buffer, urb->actual_length);
-
-	/* Anyone listening? */
-	if (serial->open_count == 0)
-		return;
-
-	if (status == 0) {
-		if (serial->parent->port_spec & HSO_INFO_CRC_BUG) {
-			u32 rest;
-			u8 crc_check[4] = { 0xDE, 0xAD, 0xBE, 0xEF };
-			rest =
-			    urb->actual_length %
-			    serial->in_endp->wMaxPacketSize;
-			if (((rest == 5) || (rest == 6))
-			    && !memcmp(((u8 *) urb->transfer_buffer) +
-				       urb->actual_length - 4, crc_check, 4)) {
-				urb->actual_length -= 4;
-			}
+		while (write_length_remaining) {
+			if (test_bit(TTY_THROTTLED, &tty->flags))
+				return -1;
+			curr_write_len =  tty_insert_flip_string
+				(tty, urb->transfer_buffer +
+				 serial->curr_rx_urb_offset,
+				 write_length_remaining);
+			serial->curr_rx_urb_offset += curr_write_len;
+			write_length_remaining -= curr_write_len;
+			tty_flip_buffer_push(tty);
 		}
-		/* Valid data, handle RX data */
-		put_rxbuf_data(urb, serial);
-	} else if (status == -ENOENT || status == -ECONNRESET) {
-		/* Unlinked - check for throttled port. */
-		D2("Port %d, successfully unlinked urb", serial->minor);
-	} else {
-		D2("Port %d, status = %d for read urb", serial->minor, status);
-		return;
 	}
-
-	usb_mark_last_busy(urb->dev);
-
-	/* We are done with this URB, resubmit it. Prep the USB to wait for
-	 * another frame */
-	usb_fill_bulk_urb(urb, serial->parent->usb,
-			  usb_rcvbulkpipe(serial->parent->usb,
-					  serial->in_endp->
-					  bEndpointAddress & 0x7F),
-			  urb->transfer_buffer, serial->rx_data_length,
-			  hso_std_serial_read_bulk_callback, serial);
-	/* Give this to the USB subsystem so it can tell us when more data
-	 * arrives. */
-	result = usb_submit_urb(urb, GFP_ATOMIC);
-	if (result) {
-		dev_err(&urb->dev->dev, "%s failed submit serial rx_urb %d",
-			__func__, result);
+	if (write_length_remaining == 0) {
+		serial->curr_rx_urb_offset = 0;
+		serial->rx_urb_filled[hso_urb_to_index(serial, urb)] = 0;
 	}
+	return write_length_remaining;
 }
 
+
 /* Base driver functions */
 
 static void hso_log_port(struct hso_device *hso_dev)
@@ -1794,9 +1931,13 @@
 		return -ENODEV;
 
 	for (i = 0; i < serial->num_rx_urbs; i++) {
-		if (serial->rx_urb[i])
+		if (serial->rx_urb[i]) {
 				usb_kill_urb(serial->rx_urb[i]);
+				serial->rx_urb_filled[i] = 0;
+		}
 	}
+	serial->curr_rx_urb_idx = 0;
+	serial->curr_rx_urb_offset = 0;
 
 	if (serial->tx_urb)
 		usb_kill_urb(serial->tx_urb);
@@ -2211,14 +2352,14 @@
 				     USB_DIR_IN);
 	if (!serial->in_endp) {
 		dev_err(&interface->dev, "Failed to find BULK IN ep\n");
-		goto exit;
+		goto exit2;
 	}
 
 	if (!
 	    (serial->out_endp =
 	     hso_get_ep(interface, USB_ENDPOINT_XFER_BULK, USB_DIR_OUT))) {
 		dev_err(&interface->dev, "Failed to find BULK IN ep\n");
-		goto exit;
+		goto exit2;
 	}
 
 	serial->write_data = hso_std_serial_write_data;
@@ -2231,9 +2372,10 @@
 
 	/* done, return it */
 	return hso_dev;
+
+exit2:
+	hso_serial_common_free(serial);
 exit:
-	if (hso_dev && serial)
-		hso_serial_common_free(serial);
 	kfree(serial);
 	hso_free_device(hso_dev);
 	return NULL;
@@ -2740,6 +2882,7 @@
 	.chars_in_buffer = hso_serial_chars_in_buffer,
 	.tiocmget = hso_serial_tiocmget,
 	.tiocmset = hso_serial_tiocmset,
+	.unthrottle = hso_unthrottle
 };
 
 static struct usb_driver hso_driver = {
diff --git a/drivers/net/usb/mcs7830.c b/drivers/net/usb/mcs7830.c
index ca9d00c..b514350 100644
--- a/drivers/net/usb/mcs7830.c
+++ b/drivers/net/usb/mcs7830.c
@@ -118,7 +118,7 @@
 
 	if (urb->status < 0)
 		printk(KERN_DEBUG "%s() failed with %d\n",
-		       __FUNCTION__, urb->status);
+		       __func__, urb->status);
 
 	kfree(req);
 	usb_free_urb(urb);
diff --git a/drivers/net/usb/pegasus.c b/drivers/net/usb/pegasus.c
index 8c19307..38b90e7 100644
--- a/drivers/net/usb/pegasus.c
+++ b/drivers/net/usb/pegasus.c
@@ -119,7 +119,7 @@
 	default:
 		if (netif_msg_drv(pegasus) && printk_ratelimit())
 			dev_dbg(&pegasus->intf->dev, "%s, status %d\n",
-				__FUNCTION__, urb->status);
+				__func__, urb->status);
 	}
 	pegasus->flags &= ~ETH_REGS_CHANGED;
 	wake_up(&pegasus->ctrl_wait);
@@ -136,7 +136,7 @@
 	if (!buffer) {
 		if (netif_msg_drv(pegasus))
 			dev_warn(&pegasus->intf->dev, "out of memory in %s\n",
-					__FUNCTION__);
+					__func__);
 		return -ENOMEM;
 	}
 	add_wait_queue(&pegasus->ctrl_wait, &wait);
@@ -224,7 +224,7 @@
 			netif_device_detach(pegasus->net);
 		if (netif_msg_drv(pegasus))
 			dev_err(&pegasus->intf->dev, "%s, status %d\n",
-					__FUNCTION__, ret);
+					__func__, ret);
 		goto out;
 	}
 
@@ -246,7 +246,7 @@
 	if (!tmp) {
 		if (netif_msg_drv(pegasus))
 			dev_warn(&pegasus->intf->dev, "out of memory in %s\n",
-					__FUNCTION__);
+					__func__);
 		return -ENOMEM;
 	}
 	memcpy(tmp, &data, 1);
@@ -277,7 +277,7 @@
 			netif_device_detach(pegasus->net);
 		if (netif_msg_drv(pegasus) && printk_ratelimit())
 			dev_err(&pegasus->intf->dev, "%s, status %d\n",
-					__FUNCTION__, ret);
+					__func__, ret);
 		goto out;
 	}
 
@@ -310,7 +310,7 @@
 			netif_device_detach(pegasus->net);
 		if (netif_msg_drv(pegasus))
 			dev_err(&pegasus->intf->dev, "%s, status %d\n",
-					__FUNCTION__, ret);
+					__func__, ret);
 	}
 
 	return ret;
@@ -341,7 +341,7 @@
 	}
 fail:
 	if (netif_msg_drv(pegasus))
-		dev_warn(&pegasus->intf->dev, "%s failed\n", __FUNCTION__);
+		dev_warn(&pegasus->intf->dev, "%s failed\n", __func__);
 
 	return ret;
 }
@@ -378,7 +378,7 @@
 
 fail:
 	if (netif_msg_drv(pegasus))
-		dev_warn(&pegasus->intf->dev, "%s failed\n", __FUNCTION__);
+		dev_warn(&pegasus->intf->dev, "%s failed\n", __func__);
 	return -ETIMEDOUT;
 }
 
@@ -415,7 +415,7 @@
 
 fail:
 	if (netif_msg_drv(pegasus))
-		dev_warn(&pegasus->intf->dev, "%s failed\n", __FUNCTION__);
+		dev_warn(&pegasus->intf->dev, "%s failed\n", __func__);
 	return -ETIMEDOUT;
 }
 
@@ -463,7 +463,7 @@
 		return ret;
 fail:
 	if (netif_msg_drv(pegasus))
-		dev_warn(&pegasus->intf->dev, "%s failed\n", __FUNCTION__);
+		dev_warn(&pegasus->intf->dev, "%s failed\n", __func__);
 	return -ETIMEDOUT;
 }
 #endif				/* PEGASUS_WRITE_EEPROM */
diff --git a/drivers/net/usb/smsc95xx.c b/drivers/net/usb/smsc95xx.c
new file mode 100644
index 0000000..51e2f5d
--- /dev/null
+++ b/drivers/net/usb/smsc95xx.c
@@ -0,0 +1,1225 @@
+ /***************************************************************************
+ *
+ * Copyright (C) 2007-2008 SMSC
+ *
+ * This program is free software; you can redistribute it and/or
+ * 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/kmod.h>
+#include <linux/init.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+#include <linux/mii.h>
+#include <linux/usb.h>
+#include <linux/crc32.h>
+#include <linux/usb/usbnet.h>
+#include "smsc95xx.h"
+
+#define SMSC_CHIPNAME			"smsc95xx"
+#define SMSC_DRIVER_VERSION		"1.0.3"
+#define HS_USB_PKT_SIZE			(512)
+#define FS_USB_PKT_SIZE			(64)
+#define DEFAULT_HS_BURST_CAP_SIZE	(16 * 1024 + 5 * HS_USB_PKT_SIZE)
+#define DEFAULT_FS_BURST_CAP_SIZE	(6 * 1024 + 33 * FS_USB_PKT_SIZE)
+#define DEFAULT_BULK_IN_DELAY		(0x00002000)
+#define MAX_SINGLE_PACKET_SIZE		(2048)
+#define LAN95XX_EEPROM_MAGIC		(0x9500)
+#define EEPROM_MAC_OFFSET		(0x01)
+#define DEFAULT_RX_CSUM_ENABLE		(true)
+#define SMSC95XX_INTERNAL_PHY_ID	(1)
+#define SMSC95XX_TX_OVERHEAD		(8)
+#define FLOW_CTRL_TX			(1)
+#define FLOW_CTRL_RX			(2)
+
+struct smsc95xx_priv {
+	u32 mac_cr;
+	spinlock_t mac_cr_lock;
+	bool use_rx_csum;
+};
+
+struct usb_context {
+	struct usb_ctrlrequest req;
+	struct completion notify;
+	struct usbnet *dev;
+};
+
+int turbo_mode = true;
+module_param(turbo_mode, bool, 0644);
+MODULE_PARM_DESC(turbo_mode, "Enable multiple frames per Rx transaction");
+
+static int smsc95xx_read_reg(struct usbnet *dev, u32 index, u32 *data)
+{
+	u32 *buf = kmalloc(4, GFP_KERNEL);
+	int ret;
+
+	BUG_ON(!dev);
+
+	if (!buf)
+		return -ENOMEM;
+
+	ret = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0),
+		USB_VENDOR_REQUEST_READ_REGISTER,
+		USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+		00, index, buf, 4, USB_CTRL_GET_TIMEOUT);
+
+	if (unlikely(ret < 0))
+		devwarn(dev, "Failed to read register index 0x%08x", index);
+
+	le32_to_cpus(buf);
+	*data = *buf;
+	kfree(buf);
+
+	return ret;
+}
+
+static int smsc95xx_write_reg(struct usbnet *dev, u32 index, u32 data)
+{
+	u32 *buf = kmalloc(4, GFP_KERNEL);
+	int ret;
+
+	BUG_ON(!dev);
+
+	if (!buf)
+		return -ENOMEM;
+
+	*buf = data;
+	cpu_to_le32s(buf);
+
+	ret = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0),
+		USB_VENDOR_REQUEST_WRITE_REGISTER,
+		USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+		00, index, buf, 4, USB_CTRL_SET_TIMEOUT);
+
+	if (unlikely(ret < 0))
+		devwarn(dev, "Failed to write register index 0x%08x", index);
+
+	kfree(buf);
+
+	return ret;
+}
+
+/* Loop until the read is completed with timeout
+ * called with phy_mutex held */
+static int smsc95xx_phy_wait_not_busy(struct usbnet *dev)
+{
+	unsigned long start_time = jiffies;
+	u32 val;
+
+	do {
+		smsc95xx_read_reg(dev, MII_ADDR, &val);
+		if (!(val & MII_BUSY_))
+			return 0;
+	} while (!time_after(jiffies, start_time + HZ));
+
+	return -EIO;
+}
+
+static int smsc95xx_mdio_read(struct net_device *netdev, int phy_id, int idx)
+{
+	struct usbnet *dev = netdev_priv(netdev);
+	u32 val, addr;
+
+	mutex_lock(&dev->phy_mutex);
+
+	/* confirm MII not busy */
+	if (smsc95xx_phy_wait_not_busy(dev)) {
+		devwarn(dev, "MII is busy in smsc95xx_mdio_read");
+		mutex_unlock(&dev->phy_mutex);
+		return -EIO;
+	}
+
+	/* set the address, index & direction (read from PHY) */
+	phy_id &= dev->mii.phy_id_mask;
+	idx &= dev->mii.reg_num_mask;
+	addr = (phy_id << 11) | (idx << 6) | MII_READ_;
+	smsc95xx_write_reg(dev, MII_ADDR, addr);
+
+	if (smsc95xx_phy_wait_not_busy(dev)) {
+		devwarn(dev, "Timed out reading MII reg %02X", idx);
+		mutex_unlock(&dev->phy_mutex);
+		return -EIO;
+	}
+
+	smsc95xx_read_reg(dev, MII_DATA, &val);
+
+	mutex_unlock(&dev->phy_mutex);
+
+	return (u16)(val & 0xFFFF);
+}
+
+static void smsc95xx_mdio_write(struct net_device *netdev, int phy_id, int idx,
+				int regval)
+{
+	struct usbnet *dev = netdev_priv(netdev);
+	u32 val, addr;
+
+	mutex_lock(&dev->phy_mutex);
+
+	/* confirm MII not busy */
+	if (smsc95xx_phy_wait_not_busy(dev)) {
+		devwarn(dev, "MII is busy in smsc95xx_mdio_write");
+		mutex_unlock(&dev->phy_mutex);
+		return;
+	}
+
+	val = regval;
+	smsc95xx_write_reg(dev, MII_DATA, val);
+
+	/* set the address, index & direction (write to PHY) */
+	phy_id &= dev->mii.phy_id_mask;
+	idx &= dev->mii.reg_num_mask;
+	addr = (phy_id << 11) | (idx << 6) | MII_WRITE_;
+	smsc95xx_write_reg(dev, MII_ADDR, addr);
+
+	if (smsc95xx_phy_wait_not_busy(dev))
+		devwarn(dev, "Timed out writing MII reg %02X", idx);
+
+	mutex_unlock(&dev->phy_mutex);
+}
+
+static int smsc95xx_wait_eeprom(struct usbnet *dev)
+{
+	unsigned long start_time = jiffies;
+	u32 val;
+
+	do {
+		smsc95xx_read_reg(dev, E2P_CMD, &val);
+		if (!(val & E2P_CMD_BUSY_) || (val & E2P_CMD_TIMEOUT_))
+			break;
+		udelay(40);
+	} while (!time_after(jiffies, start_time + HZ));
+
+	if (val & (E2P_CMD_TIMEOUT_ | E2P_CMD_BUSY_)) {
+		devwarn(dev, "EEPROM read operation timeout");
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int smsc95xx_eeprom_confirm_not_busy(struct usbnet *dev)
+{
+	unsigned long start_time = jiffies;
+	u32 val;
+
+	do {
+		smsc95xx_read_reg(dev, E2P_CMD, &val);
+
+		if (!(val & E2P_CMD_LOADED_)) {
+			devwarn(dev, "No EEPROM present");
+			return -EIO;
+		}
+
+		if (!(val & E2P_CMD_BUSY_))
+			return 0;
+
+		udelay(40);
+	} while (!time_after(jiffies, start_time + HZ));
+
+	devwarn(dev, "EEPROM is busy");
+	return -EIO;
+}
+
+static int smsc95xx_read_eeprom(struct usbnet *dev, u32 offset, u32 length,
+				u8 *data)
+{
+	u32 val;
+	int i, ret;
+
+	BUG_ON(!dev);
+	BUG_ON(!data);
+
+	ret = smsc95xx_eeprom_confirm_not_busy(dev);
+	if (ret)
+		return ret;
+
+	for (i = 0; i < length; i++) {
+		val = E2P_CMD_BUSY_ | E2P_CMD_READ_ | (offset & E2P_CMD_ADDR_);
+		smsc95xx_write_reg(dev, E2P_CMD, val);
+
+		ret = smsc95xx_wait_eeprom(dev);
+		if (ret < 0)
+			return ret;
+
+		smsc95xx_read_reg(dev, E2P_DATA, &val);
+
+		data[i] = val & 0xFF;
+		offset++;
+	}
+
+	return 0;
+}
+
+static int smsc95xx_write_eeprom(struct usbnet *dev, u32 offset, u32 length,
+				 u8 *data)
+{
+	u32 val;
+	int i, ret;
+
+	BUG_ON(!dev);
+	BUG_ON(!data);
+
+	ret = smsc95xx_eeprom_confirm_not_busy(dev);
+	if (ret)
+		return ret;
+
+	/* Issue write/erase enable command */
+	val = E2P_CMD_BUSY_ | E2P_CMD_EWEN_;
+	smsc95xx_write_reg(dev, E2P_CMD, val);
+
+	ret = smsc95xx_wait_eeprom(dev);
+	if (ret < 0)
+		return ret;
+
+	for (i = 0; i < length; i++) {
+
+		/* Fill data register */
+		val = data[i];
+		smsc95xx_write_reg(dev, E2P_DATA, val);
+
+		/* Send "write" command */
+		val = E2P_CMD_BUSY_ | E2P_CMD_WRITE_ | (offset & E2P_CMD_ADDR_);
+		smsc95xx_write_reg(dev, E2P_CMD, val);
+
+		ret = smsc95xx_wait_eeprom(dev);
+		if (ret < 0)
+			return ret;
+
+		offset++;
+	}
+
+	return 0;
+}
+
+static void smsc95xx_async_cmd_callback(struct urb *urb, struct pt_regs *regs)
+{
+	struct usb_context *usb_context = urb->context;
+	struct usbnet *dev = usb_context->dev;
+
+	if (urb->status < 0)
+		devwarn(dev, "async callback failed with %d", urb->status);
+
+	complete(&usb_context->notify);
+
+	kfree(usb_context);
+	usb_free_urb(urb);
+}
+
+static int smsc95xx_write_reg_async(struct usbnet *dev, u16 index, u32 *data)
+{
+	struct usb_context *usb_context;
+	int status;
+	struct urb *urb;
+	const u16 size = 4;
+
+	urb = usb_alloc_urb(0, GFP_ATOMIC);
+	if (!urb) {
+		devwarn(dev, "Error allocating URB");
+		return -ENOMEM;
+	}
+
+	usb_context = kmalloc(sizeof(struct usb_context), GFP_ATOMIC);
+	if (usb_context == NULL) {
+		devwarn(dev, "Error allocating control msg");
+		usb_free_urb(urb);
+		return -ENOMEM;
+	}
+
+	usb_context->req.bRequestType =
+		USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE;
+	usb_context->req.bRequest = USB_VENDOR_REQUEST_WRITE_REGISTER;
+	usb_context->req.wValue = 00;
+	usb_context->req.wIndex = cpu_to_le16(index);
+	usb_context->req.wLength = cpu_to_le16(size);
+	init_completion(&usb_context->notify);
+
+	usb_fill_control_urb(urb, dev->udev, usb_sndctrlpipe(dev->udev, 0),
+		(void *)&usb_context->req, data, size,
+		(usb_complete_t)smsc95xx_async_cmd_callback,
+		(void *)usb_context);
+
+	status = usb_submit_urb(urb, GFP_ATOMIC);
+	if (status < 0) {
+		devwarn(dev, "Error submitting control msg, sts=%d", status);
+		kfree(usb_context);
+		usb_free_urb(urb);
+	}
+
+	return status;
+}
+
+/* returns hash bit number for given MAC address
+ * example:
+ * 01 00 5E 00 00 01 -> returns bit number 31 */
+static unsigned int smsc95xx_hash(char addr[ETH_ALEN])
+{
+	return (ether_crc(ETH_ALEN, addr) >> 26) & 0x3f;
+}
+
+static void smsc95xx_set_multicast(struct net_device *netdev)
+{
+	struct usbnet *dev = netdev_priv(netdev);
+	struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]);
+	u32 hash_hi = 0;
+	u32 hash_lo = 0;
+	unsigned long flags;
+
+	spin_lock_irqsave(&pdata->mac_cr_lock, flags);
+
+	if (dev->net->flags & IFF_PROMISC) {
+		if (netif_msg_drv(dev))
+			devdbg(dev, "promiscuous mode enabled");
+		pdata->mac_cr |= MAC_CR_PRMS_;
+		pdata->mac_cr &= ~(MAC_CR_MCPAS_ | MAC_CR_HPFILT_);
+	} else if (dev->net->flags & IFF_ALLMULTI) {
+		if (netif_msg_drv(dev))
+			devdbg(dev, "receive all multicast enabled");
+		pdata->mac_cr |= MAC_CR_MCPAS_;
+		pdata->mac_cr &= ~(MAC_CR_PRMS_ | MAC_CR_HPFILT_);
+	} else if (dev->net->mc_count > 0) {
+		struct dev_mc_list *mc_list = dev->net->mc_list;
+		int count = 0;
+
+		pdata->mac_cr |= MAC_CR_HPFILT_;
+		pdata->mac_cr &= ~(MAC_CR_PRMS_ | MAC_CR_MCPAS_);
+
+		while (mc_list) {
+			count++;
+			if (mc_list->dmi_addrlen == ETH_ALEN) {
+				u32 bitnum = smsc95xx_hash(mc_list->dmi_addr);
+				u32 mask = 0x01 << (bitnum & 0x1F);
+				if (bitnum & 0x20)
+					hash_hi |= mask;
+				else
+					hash_lo |= mask;
+			} else {
+				devwarn(dev, "dmi_addrlen != 6");
+			}
+			mc_list = mc_list->next;
+		}
+
+		if (count != ((u32)dev->net->mc_count))
+			devwarn(dev, "mc_count != dev->mc_count");
+
+		if (netif_msg_drv(dev))
+			devdbg(dev, "HASHH=0x%08X, HASHL=0x%08X", hash_hi,
+				hash_lo);
+	} else {
+		if (netif_msg_drv(dev))
+			devdbg(dev, "receive own packets only");
+		pdata->mac_cr &=
+			~(MAC_CR_PRMS_ | MAC_CR_MCPAS_ | MAC_CR_HPFILT_);
+	}
+
+	spin_unlock_irqrestore(&pdata->mac_cr_lock, flags);
+
+	/* Initiate async writes, as we can't wait for completion here */
+	smsc95xx_write_reg_async(dev, HASHH, &hash_hi);
+	smsc95xx_write_reg_async(dev, HASHL, &hash_lo);
+	smsc95xx_write_reg_async(dev, MAC_CR, &pdata->mac_cr);
+}
+
+static u8 smsc95xx_resolve_flowctrl_fulldplx(u16 lcladv, u16 rmtadv)
+{
+	u8 cap = 0;
+
+	if (lcladv & ADVERTISE_PAUSE_CAP) {
+		if (lcladv & ADVERTISE_PAUSE_ASYM) {
+			if (rmtadv & LPA_PAUSE_CAP)
+				cap = FLOW_CTRL_TX | FLOW_CTRL_RX;
+			else if (rmtadv & LPA_PAUSE_ASYM)
+				cap = FLOW_CTRL_RX;
+		} else {
+			if (rmtadv & LPA_PAUSE_CAP)
+				cap = FLOW_CTRL_TX | FLOW_CTRL_RX;
+		}
+	} else if (lcladv & ADVERTISE_PAUSE_ASYM) {
+		if ((rmtadv & LPA_PAUSE_CAP) && (rmtadv & LPA_PAUSE_ASYM))
+			cap = FLOW_CTRL_TX;
+	}
+
+	return cap;
+}
+
+static void smsc95xx_phy_update_flowcontrol(struct usbnet *dev, u8 duplex,
+					    u16 lcladv, u16 rmtadv)
+{
+	u32 flow, afc_cfg = 0;
+
+	int ret = smsc95xx_read_reg(dev, AFC_CFG, &afc_cfg);
+	if (ret < 0) {
+		devwarn(dev, "error reading AFC_CFG");
+		return;
+	}
+
+	if (duplex == DUPLEX_FULL) {
+		u8 cap = smsc95xx_resolve_flowctrl_fulldplx(lcladv, rmtadv);
+
+		if (cap & FLOW_CTRL_RX)
+			flow = 0xFFFF0002;
+		else
+			flow = 0;
+
+		if (cap & FLOW_CTRL_TX)
+			afc_cfg |= 0xF;
+		else
+			afc_cfg &= ~0xF;
+
+		if (netif_msg_link(dev))
+			devdbg(dev, "rx pause %s, tx pause %s",
+				(cap & FLOW_CTRL_RX ? "enabled" : "disabled"),
+				(cap & FLOW_CTRL_TX ? "enabled" : "disabled"));
+	} else {
+		if (netif_msg_link(dev))
+			devdbg(dev, "half duplex");
+		flow = 0;
+		afc_cfg |= 0xF;
+	}
+
+	smsc95xx_write_reg(dev, FLOW, flow);
+	smsc95xx_write_reg(dev,	AFC_CFG, afc_cfg);
+}
+
+static int smsc95xx_link_reset(struct usbnet *dev)
+{
+	struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]);
+	struct mii_if_info *mii = &dev->mii;
+	struct ethtool_cmd ecmd;
+	unsigned long flags;
+	u16 lcladv, rmtadv;
+	u32 intdata;
+
+	/* clear interrupt status */
+	smsc95xx_mdio_read(dev->net, mii->phy_id, PHY_INT_SRC);
+	intdata = 0xFFFFFFFF;
+	smsc95xx_write_reg(dev, INT_STS, intdata);
+
+	mii_check_media(mii, 1, 1);
+	mii_ethtool_gset(&dev->mii, &ecmd);
+	lcladv = smsc95xx_mdio_read(dev->net, mii->phy_id, MII_ADVERTISE);
+	rmtadv = smsc95xx_mdio_read(dev->net, mii->phy_id, MII_LPA);
+
+	if (netif_msg_link(dev))
+		devdbg(dev, "speed: %d duplex: %d lcladv: %04x rmtadv: %04x",
+			ecmd.speed, ecmd.duplex, lcladv, rmtadv);
+
+	spin_lock_irqsave(&pdata->mac_cr_lock, flags);
+	if (ecmd.duplex != DUPLEX_FULL) {
+		pdata->mac_cr &= ~MAC_CR_FDPX_;
+		pdata->mac_cr |= MAC_CR_RCVOWN_;
+	} else {
+		pdata->mac_cr &= ~MAC_CR_RCVOWN_;
+		pdata->mac_cr |= MAC_CR_FDPX_;
+	}
+	spin_unlock_irqrestore(&pdata->mac_cr_lock, flags);
+
+	smsc95xx_write_reg(dev, MAC_CR, pdata->mac_cr);
+
+	smsc95xx_phy_update_flowcontrol(dev, ecmd.duplex, lcladv, rmtadv);
+
+	return 0;
+}
+
+static void smsc95xx_status(struct usbnet *dev, struct urb *urb)
+{
+	u32 intdata;
+
+	if (urb->actual_length != 4) {
+		devwarn(dev, "unexpected urb length %d", urb->actual_length);
+		return;
+	}
+
+	memcpy(&intdata, urb->transfer_buffer, 4);
+	le32_to_cpus(&intdata);
+
+	if (netif_msg_link(dev))
+		devdbg(dev, "intdata: 0x%08X", intdata);
+
+	if (intdata & INT_ENP_PHY_INT_)
+		usbnet_defer_kevent(dev, EVENT_LINK_RESET);
+	else
+		devwarn(dev, "unexpected interrupt, intdata=0x%08X", intdata);
+}
+
+/* Enable or disable Rx checksum offload engine */
+static int smsc95xx_set_rx_csum(struct usbnet *dev, bool enable)
+{
+	u32 read_buf;
+	int ret = smsc95xx_read_reg(dev, COE_CR, &read_buf);
+	if (ret < 0) {
+		devwarn(dev, "Failed to read COE_CR: %d", ret);
+		return ret;
+	}
+
+	if (enable)
+		read_buf |= Rx_COE_EN_;
+	else
+		read_buf &= ~Rx_COE_EN_;
+
+	ret = smsc95xx_write_reg(dev, COE_CR, read_buf);
+	if (ret < 0) {
+		devwarn(dev, "Failed to write COE_CR: %d", ret);
+		return ret;
+	}
+
+	if (netif_msg_hw(dev))
+		devdbg(dev, "COE_CR = 0x%08x", read_buf);
+	return 0;
+}
+
+static int smsc95xx_ethtool_get_eeprom_len(struct net_device *net)
+{
+	return MAX_EEPROM_SIZE;
+}
+
+static int smsc95xx_ethtool_get_eeprom(struct net_device *netdev,
+				       struct ethtool_eeprom *ee, u8 *data)
+{
+	struct usbnet *dev = netdev_priv(netdev);
+
+	ee->magic = LAN95XX_EEPROM_MAGIC;
+
+	return smsc95xx_read_eeprom(dev, ee->offset, ee->len, data);
+}
+
+static int smsc95xx_ethtool_set_eeprom(struct net_device *netdev,
+				       struct ethtool_eeprom *ee, u8 *data)
+{
+	struct usbnet *dev = netdev_priv(netdev);
+
+	if (ee->magic != LAN95XX_EEPROM_MAGIC) {
+		devwarn(dev, "EEPROM: magic value mismatch, magic = 0x%x",
+			ee->magic);
+		return -EINVAL;
+	}
+
+	return smsc95xx_write_eeprom(dev, ee->offset, ee->len, data);
+}
+
+static u32 smsc95xx_ethtool_get_rx_csum(struct net_device *netdev)
+{
+	struct usbnet *dev = netdev_priv(netdev);
+	struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]);
+
+	return pdata->use_rx_csum;
+}
+
+static int smsc95xx_ethtool_set_rx_csum(struct net_device *netdev, u32 val)
+{
+	struct usbnet *dev = netdev_priv(netdev);
+	struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]);
+
+	pdata->use_rx_csum = !!val;
+
+	return smsc95xx_set_rx_csum(dev, pdata->use_rx_csum);
+}
+
+static struct ethtool_ops smsc95xx_ethtool_ops = {
+	.get_link	= usbnet_get_link,
+	.nway_reset	= usbnet_nway_reset,
+	.get_drvinfo	= usbnet_get_drvinfo,
+	.get_msglevel	= usbnet_get_msglevel,
+	.set_msglevel	= usbnet_set_msglevel,
+	.get_settings	= usbnet_get_settings,
+	.set_settings	= usbnet_set_settings,
+	.get_eeprom_len	= smsc95xx_ethtool_get_eeprom_len,
+	.get_eeprom	= smsc95xx_ethtool_get_eeprom,
+	.set_eeprom	= smsc95xx_ethtool_set_eeprom,
+	.get_rx_csum	= smsc95xx_ethtool_get_rx_csum,
+	.set_rx_csum	= smsc95xx_ethtool_set_rx_csum,
+};
+
+static int smsc95xx_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd)
+{
+	struct usbnet *dev = netdev_priv(netdev);
+
+	if (!netif_running(netdev))
+		return -EINVAL;
+
+	return generic_mii_ioctl(&dev->mii, if_mii(rq), cmd, NULL);
+}
+
+static void smsc95xx_init_mac_address(struct usbnet *dev)
+{
+	/* try reading mac address from EEPROM */
+	if (smsc95xx_read_eeprom(dev, EEPROM_MAC_OFFSET, ETH_ALEN,
+			dev->net->dev_addr) == 0) {
+		if (is_valid_ether_addr(dev->net->dev_addr)) {
+			/* eeprom values are valid so use them */
+			if (netif_msg_ifup(dev))
+				devdbg(dev, "MAC address read from EEPROM");
+			return;
+		}
+	}
+
+	/* no eeprom, or eeprom values are invalid. generate random MAC */
+	random_ether_addr(dev->net->dev_addr);
+	if (netif_msg_ifup(dev))
+		devdbg(dev, "MAC address set to random_ether_addr");
+}
+
+static int smsc95xx_set_mac_address(struct usbnet *dev)
+{
+	u32 addr_lo = dev->net->dev_addr[0] | dev->net->dev_addr[1] << 8 |
+		dev->net->dev_addr[2] << 16 | dev->net->dev_addr[3] << 24;
+	u32 addr_hi = dev->net->dev_addr[4] | dev->net->dev_addr[5] << 8;
+	int ret;
+
+	ret = smsc95xx_write_reg(dev, ADDRL, addr_lo);
+	if (ret < 0) {
+		devwarn(dev, "Failed to write ADDRL: %d", ret);
+		return ret;
+	}
+
+	ret = smsc95xx_write_reg(dev, ADDRH, addr_hi);
+	if (ret < 0) {
+		devwarn(dev, "Failed to write ADDRH: %d", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+/* starts the TX path */
+static void smsc95xx_start_tx_path(struct usbnet *dev)
+{
+	struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]);
+	unsigned long flags;
+	u32 reg_val;
+
+	/* Enable Tx at MAC */
+	spin_lock_irqsave(&pdata->mac_cr_lock, flags);
+	pdata->mac_cr |= MAC_CR_TXEN_;
+	spin_unlock_irqrestore(&pdata->mac_cr_lock, flags);
+
+	smsc95xx_write_reg(dev, MAC_CR, pdata->mac_cr);
+
+	/* Enable Tx at SCSRs */
+	reg_val = TX_CFG_ON_;
+	smsc95xx_write_reg(dev, TX_CFG, reg_val);
+}
+
+/* Starts the Receive path */
+static void smsc95xx_start_rx_path(struct usbnet *dev)
+{
+	struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]);
+	unsigned long flags;
+
+	spin_lock_irqsave(&pdata->mac_cr_lock, flags);
+	pdata->mac_cr |= MAC_CR_RXEN_;
+	spin_unlock_irqrestore(&pdata->mac_cr_lock, flags);
+
+	smsc95xx_write_reg(dev, MAC_CR, pdata->mac_cr);
+}
+
+static int smsc95xx_phy_initialize(struct usbnet *dev)
+{
+	/* Initialize MII structure */
+	dev->mii.dev = dev->net;
+	dev->mii.mdio_read = smsc95xx_mdio_read;
+	dev->mii.mdio_write = smsc95xx_mdio_write;
+	dev->mii.phy_id_mask = 0x1f;
+	dev->mii.reg_num_mask = 0x1f;
+	dev->mii.phy_id = SMSC95XX_INTERNAL_PHY_ID;
+
+	smsc95xx_mdio_write(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET);
+	smsc95xx_mdio_write(dev->net, dev->mii.phy_id, MII_ADVERTISE,
+		ADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP |
+		ADVERTISE_PAUSE_ASYM);
+
+	/* read to clear */
+	smsc95xx_mdio_read(dev->net, dev->mii.phy_id, PHY_INT_SRC);
+
+	smsc95xx_mdio_write(dev->net, dev->mii.phy_id, PHY_INT_MASK,
+		PHY_INT_MASK_DEFAULT_);
+	mii_nway_restart(&dev->mii);
+
+	if (netif_msg_ifup(dev))
+		devdbg(dev, "phy initialised succesfully");
+	return 0;
+}
+
+static int smsc95xx_reset(struct usbnet *dev)
+{
+	struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]);
+	u32 read_buf, write_buf, burst_cap;
+	int ret = 0, timeout;
+	DECLARE_MAC_BUF(mac);
+
+	if (netif_msg_ifup(dev))
+		devdbg(dev, "entering smsc95xx_reset");
+
+	write_buf = HW_CFG_LRST_;
+	ret = smsc95xx_write_reg(dev, HW_CFG, write_buf);
+	if (ret < 0) {
+		devwarn(dev, "Failed to write HW_CFG_LRST_ bit in HW_CFG "
+			"register, ret = %d", ret);
+		return ret;
+	}
+
+	timeout = 0;
+	do {
+		ret = smsc95xx_read_reg(dev, HW_CFG, &read_buf);
+		if (ret < 0) {
+			devwarn(dev, "Failed to read HW_CFG: %d", ret);
+			return ret;
+		}
+		msleep(10);
+		timeout++;
+	} while ((read_buf & HW_CFG_LRST_) && (timeout < 100));
+
+	if (timeout >= 100) {
+		devwarn(dev, "timeout waiting for completion of Lite Reset");
+		return ret;
+	}
+
+	write_buf = PM_CTL_PHY_RST_;
+	ret = smsc95xx_write_reg(dev, PM_CTRL, write_buf);
+	if (ret < 0) {
+		devwarn(dev, "Failed to write PM_CTRL: %d", ret);
+		return ret;
+	}
+
+	timeout = 0;
+	do {
+		ret = smsc95xx_read_reg(dev, PM_CTRL, &read_buf);
+		if (ret < 0) {
+			devwarn(dev, "Failed to read PM_CTRL: %d", ret);
+			return ret;
+		}
+		msleep(10);
+		timeout++;
+	} while ((read_buf & PM_CTL_PHY_RST_) && (timeout < 100));
+
+	if (timeout >= 100) {
+		devwarn(dev, "timeout waiting for PHY Reset");
+		return ret;
+	}
+
+	smsc95xx_init_mac_address(dev);
+
+	ret = smsc95xx_set_mac_address(dev);
+	if (ret < 0)
+		return ret;
+
+	if (netif_msg_ifup(dev))
+		devdbg(dev, "MAC Address: %s",
+			print_mac(mac, dev->net->dev_addr));
+
+	ret = smsc95xx_read_reg(dev, HW_CFG, &read_buf);
+	if (ret < 0) {
+		devwarn(dev, "Failed to read HW_CFG: %d", ret);
+		return ret;
+	}
+
+	if (netif_msg_ifup(dev))
+		devdbg(dev, "Read Value from HW_CFG : 0x%08x", read_buf);
+
+	read_buf |= HW_CFG_BIR_;
+
+	ret = smsc95xx_write_reg(dev, HW_CFG, read_buf);
+	if (ret < 0) {
+		devwarn(dev, "Failed to write HW_CFG_BIR_ bit in HW_CFG "
+			"register, ret = %d", ret);
+		return ret;
+	}
+
+	ret = smsc95xx_read_reg(dev, HW_CFG, &read_buf);
+	if (ret < 0) {
+		devwarn(dev, "Failed to read HW_CFG: %d", ret);
+		return ret;
+	}
+	if (netif_msg_ifup(dev))
+		devdbg(dev, "Read Value from HW_CFG after writing "
+			"HW_CFG_BIR_: 0x%08x", read_buf);
+
+	if (!turbo_mode) {
+		burst_cap = 0;
+		dev->rx_urb_size = MAX_SINGLE_PACKET_SIZE;
+	} else if (dev->udev->speed == USB_SPEED_HIGH) {
+		burst_cap = DEFAULT_HS_BURST_CAP_SIZE / HS_USB_PKT_SIZE;
+		dev->rx_urb_size = DEFAULT_HS_BURST_CAP_SIZE;
+	} else {
+		burst_cap = DEFAULT_FS_BURST_CAP_SIZE / FS_USB_PKT_SIZE;
+		dev->rx_urb_size = DEFAULT_FS_BURST_CAP_SIZE;
+	}
+
+	if (netif_msg_ifup(dev))
+		devdbg(dev, "rx_urb_size=%ld", (ulong)dev->rx_urb_size);
+
+	ret = smsc95xx_write_reg(dev, BURST_CAP, burst_cap);
+	if (ret < 0) {
+		devwarn(dev, "Failed to write BURST_CAP: %d", ret);
+		return ret;
+	}
+
+	ret = smsc95xx_read_reg(dev, BURST_CAP, &read_buf);
+	if (ret < 0) {
+		devwarn(dev, "Failed to read BURST_CAP: %d", ret);
+		return ret;
+	}
+	if (netif_msg_ifup(dev))
+		devdbg(dev, "Read Value from BURST_CAP after writing: 0x%08x",
+			read_buf);
+
+	read_buf = DEFAULT_BULK_IN_DELAY;
+	ret = smsc95xx_write_reg(dev, BULK_IN_DLY, read_buf);
+	if (ret < 0) {
+		devwarn(dev, "ret = %d", ret);
+		return ret;
+	}
+
+	ret = smsc95xx_read_reg(dev, BULK_IN_DLY, &read_buf);
+	if (ret < 0) {
+		devwarn(dev, "Failed to read BULK_IN_DLY: %d", ret);
+		return ret;
+	}
+	if (netif_msg_ifup(dev))
+		devdbg(dev, "Read Value from BULK_IN_DLY after writing: "
+			"0x%08x", read_buf);
+
+	ret = smsc95xx_read_reg(dev, HW_CFG, &read_buf);
+	if (ret < 0) {
+		devwarn(dev, "Failed to read HW_CFG: %d", ret);
+		return ret;
+	}
+	if (netif_msg_ifup(dev))
+		devdbg(dev, "Read Value from HW_CFG: 0x%08x", read_buf);
+
+	if (turbo_mode)
+		read_buf |= (HW_CFG_MEF_ | HW_CFG_BCE_);
+
+	read_buf &= ~HW_CFG_RXDOFF_;
+
+	/* set Rx data offset=2, Make IP header aligns on word boundary. */
+	read_buf |= NET_IP_ALIGN << 9;
+
+	ret = smsc95xx_write_reg(dev, HW_CFG, read_buf);
+	if (ret < 0) {
+		devwarn(dev, "Failed to write HW_CFG register, ret=%d", ret);
+		return ret;
+	}
+
+	ret = smsc95xx_read_reg(dev, HW_CFG, &read_buf);
+	if (ret < 0) {
+		devwarn(dev, "Failed to read HW_CFG: %d", ret);
+		return ret;
+	}
+	if (netif_msg_ifup(dev))
+		devdbg(dev, "Read Value from HW_CFG after writing: 0x%08x",
+			read_buf);
+
+	write_buf = 0xFFFFFFFF;
+	ret = smsc95xx_write_reg(dev, INT_STS, write_buf);
+	if (ret < 0) {
+		devwarn(dev, "Failed to write INT_STS register, ret=%d", ret);
+		return ret;
+	}
+
+	ret = smsc95xx_read_reg(dev, ID_REV, &read_buf);
+	if (ret < 0) {
+		devwarn(dev, "Failed to read ID_REV: %d", ret);
+		return ret;
+	}
+	if (netif_msg_ifup(dev))
+		devdbg(dev, "ID_REV = 0x%08x", read_buf);
+
+	/* Init Tx */
+	write_buf = 0;
+	ret = smsc95xx_write_reg(dev, FLOW, write_buf);
+	if (ret < 0) {
+		devwarn(dev, "Failed to write FLOW: %d", ret);
+		return ret;
+	}
+
+	read_buf = AFC_CFG_DEFAULT;
+	ret = smsc95xx_write_reg(dev, AFC_CFG, read_buf);
+	if (ret < 0) {
+		devwarn(dev, "Failed to write AFC_CFG: %d", ret);
+		return ret;
+	}
+
+	/* Don't need mac_cr_lock during initialisation */
+	ret = smsc95xx_read_reg(dev, MAC_CR, &pdata->mac_cr);
+	if (ret < 0) {
+		devwarn(dev, "Failed to read MAC_CR: %d", ret);
+		return ret;
+	}
+
+	/* Init Rx */
+	/* Set Vlan */
+	write_buf = (u32)ETH_P_8021Q;
+	ret = smsc95xx_write_reg(dev, VLAN1, write_buf);
+	if (ret < 0) {
+		devwarn(dev, "Failed to write VAN1: %d", ret);
+		return ret;
+	}
+
+	/* Enable or disable Rx checksum offload engine */
+	ret = smsc95xx_set_rx_csum(dev, pdata->use_rx_csum);
+	if (ret < 0) {
+		devwarn(dev, "Failed to set Rx csum offload: %d", ret);
+		return ret;
+	}
+
+	smsc95xx_set_multicast(dev->net);
+
+	if (smsc95xx_phy_initialize(dev) < 0)
+		return -EIO;
+
+	ret = smsc95xx_read_reg(dev, INT_EP_CTL, &read_buf);
+	if (ret < 0) {
+		devwarn(dev, "Failed to read INT_EP_CTL: %d", ret);
+		return ret;
+	}
+
+	/* enable PHY interrupts */
+	read_buf |= INT_EP_CTL_PHY_INT_;
+
+	ret = smsc95xx_write_reg(dev, INT_EP_CTL, read_buf);
+	if (ret < 0) {
+		devwarn(dev, "Failed to write INT_EP_CTL: %d", ret);
+		return ret;
+	}
+
+	smsc95xx_start_tx_path(dev);
+	smsc95xx_start_rx_path(dev);
+
+	if (netif_msg_ifup(dev))
+		devdbg(dev, "smsc95xx_reset, return 0");
+	return 0;
+}
+
+static int smsc95xx_bind(struct usbnet *dev, struct usb_interface *intf)
+{
+	struct smsc95xx_priv *pdata = NULL;
+	int ret;
+
+	printk(KERN_INFO SMSC_CHIPNAME " v" SMSC_DRIVER_VERSION "\n");
+
+	ret = usbnet_get_endpoints(dev, intf);
+	if (ret < 0) {
+		devwarn(dev, "usbnet_get_endpoints failed: %d", ret);
+		return ret;
+	}
+
+	dev->data[0] = (unsigned long)kzalloc(sizeof(struct smsc95xx_priv),
+		GFP_KERNEL);
+
+	pdata = (struct smsc95xx_priv *)(dev->data[0]);
+	if (!pdata) {
+		devwarn(dev, "Unable to allocate struct smsc95xx_priv");
+		return -ENOMEM;
+	}
+
+	spin_lock_init(&pdata->mac_cr_lock);
+
+	pdata->use_rx_csum = DEFAULT_RX_CSUM_ENABLE;
+
+	/* Init all registers */
+	ret = smsc95xx_reset(dev);
+
+	dev->net->do_ioctl = smsc95xx_ioctl;
+	dev->net->ethtool_ops = &smsc95xx_ethtool_ops;
+	dev->net->set_multicast_list = smsc95xx_set_multicast;
+	dev->net->flags |= IFF_MULTICAST;
+	dev->net->hard_header_len += SMSC95XX_TX_OVERHEAD;
+	return 0;
+}
+
+static void smsc95xx_unbind(struct usbnet *dev, struct usb_interface *intf)
+{
+	struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]);
+	if (pdata) {
+		if (netif_msg_ifdown(dev))
+			devdbg(dev, "free pdata");
+		kfree(pdata);
+		pdata = NULL;
+		dev->data[0] = 0;
+	}
+}
+
+static void smsc95xx_rx_csum_offload(struct sk_buff *skb)
+{
+	skb->csum = *(u16 *)(skb_tail_pointer(skb) - 2);
+	skb->ip_summed = CHECKSUM_COMPLETE;
+	skb_trim(skb, skb->len - 2);
+}
+
+static int smsc95xx_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
+{
+	struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]);
+
+	while (skb->len > 0) {
+		u32 header, align_count;
+		struct sk_buff *ax_skb;
+		unsigned char *packet;
+		u16 size;
+
+		memcpy(&header, skb->data, sizeof(header));
+		le32_to_cpus(&header);
+		skb_pull(skb, 4 + NET_IP_ALIGN);
+		packet = skb->data;
+
+		/* get the packet length */
+		size = (u16)((header & RX_STS_FL_) >> 16);
+		align_count = (4 - ((size + NET_IP_ALIGN) % 4)) % 4;
+
+		if (unlikely(header & RX_STS_ES_)) {
+			if (netif_msg_rx_err(dev))
+				devdbg(dev, "Error header=0x%08x", header);
+			dev->stats.rx_errors++;
+			dev->stats.rx_dropped++;
+
+			if (header & RX_STS_CRC_) {
+				dev->stats.rx_crc_errors++;
+			} else {
+				if (header & (RX_STS_TL_ | RX_STS_RF_))
+					dev->stats.rx_frame_errors++;
+
+				if ((header & RX_STS_LE_) &&
+					(!(header & RX_STS_FT_)))
+					dev->stats.rx_length_errors++;
+			}
+		} else {
+			/* ETH_FRAME_LEN + 4(CRC) + 2(COE) + 4(Vlan) */
+			if (unlikely(size > (ETH_FRAME_LEN + 12))) {
+				if (netif_msg_rx_err(dev))
+					devdbg(dev, "size err header=0x%08x",
+						header);
+				return 0;
+			}
+
+			/* last frame in this batch */
+			if (skb->len == size) {
+				if (pdata->use_rx_csum)
+					smsc95xx_rx_csum_offload(skb);
+
+				skb->truesize = size + sizeof(struct sk_buff);
+
+				return 1;
+			}
+
+			ax_skb = skb_clone(skb, GFP_ATOMIC);
+			if (unlikely(!ax_skb)) {
+				devwarn(dev, "Error allocating skb");
+				return 0;
+			}
+
+			ax_skb->len = size;
+			ax_skb->data = packet;
+			skb_set_tail_pointer(ax_skb, size);
+
+			if (pdata->use_rx_csum)
+				smsc95xx_rx_csum_offload(ax_skb);
+
+			ax_skb->truesize = size + sizeof(struct sk_buff);
+
+			usbnet_skb_return(dev, ax_skb);
+		}
+
+		skb_pull(skb, size);
+
+		/* padding bytes before the next frame starts */
+		if (skb->len)
+			skb_pull(skb, align_count);
+	}
+
+	if (unlikely(skb->len < 0)) {
+		devwarn(dev, "invalid rx length<0 %d", skb->len);
+		return 0;
+	}
+
+	return 1;
+}
+
+static struct sk_buff *smsc95xx_tx_fixup(struct usbnet *dev,
+					 struct sk_buff *skb, gfp_t flags)
+{
+	u32 tx_cmd_a, tx_cmd_b;
+
+	if (skb_headroom(skb) < SMSC95XX_TX_OVERHEAD) {
+		struct sk_buff *skb2 = skb_copy_expand(skb,
+			SMSC95XX_TX_OVERHEAD, 0, flags);
+		dev_kfree_skb_any(skb);
+		skb = skb2;
+		if (!skb)
+			return NULL;
+	}
+
+	skb_push(skb, 4);
+	tx_cmd_b = (u32)(skb->len - 4);
+	cpu_to_le32s(&tx_cmd_b);
+	memcpy(skb->data, &tx_cmd_b, 4);
+
+	skb_push(skb, 4);
+	tx_cmd_a = (u32)(skb->len - 8) | TX_CMD_A_FIRST_SEG_ |
+		TX_CMD_A_LAST_SEG_;
+	cpu_to_le32s(&tx_cmd_a);
+	memcpy(skb->data, &tx_cmd_a, 4);
+
+	return skb;
+}
+
+static const struct driver_info smsc95xx_info = {
+	.description	= "smsc95xx USB 2.0 Ethernet",
+	.bind		= smsc95xx_bind,
+	.unbind		= smsc95xx_unbind,
+	.link_reset	= smsc95xx_link_reset,
+	.reset		= smsc95xx_reset,
+	.rx_fixup	= smsc95xx_rx_fixup,
+	.tx_fixup	= smsc95xx_tx_fixup,
+	.status		= smsc95xx_status,
+	.flags		= FLAG_ETHER,
+};
+
+static const struct usb_device_id products[] = {
+	{
+		/* SMSC9500 USB Ethernet Device */
+		USB_DEVICE(0x0424, 0x9500),
+		.driver_info = (unsigned long) &smsc95xx_info,
+	},
+	{ },		/* END */
+};
+MODULE_DEVICE_TABLE(usb, products);
+
+static struct usb_driver smsc95xx_driver = {
+	.name		= "smsc95xx",
+	.id_table	= products,
+	.probe		= usbnet_probe,
+	.suspend	= usbnet_suspend,
+	.resume		= usbnet_resume,
+	.disconnect	= usbnet_disconnect,
+};
+
+static int __init smsc95xx_init(void)
+{
+	return usb_register(&smsc95xx_driver);
+}
+module_init(smsc95xx_init);
+
+static void __exit smsc95xx_exit(void)
+{
+	usb_deregister(&smsc95xx_driver);
+}
+module_exit(smsc95xx_exit);
+
+MODULE_AUTHOR("Nancy Lin");
+MODULE_AUTHOR("Steve Glendinning <steve.glendinning@smsc.com>");
+MODULE_DESCRIPTION("SMSC95XX USB 2.0 Ethernet Devices");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/usb/smsc95xx.h b/drivers/net/usb/smsc95xx.h
new file mode 100644
index 0000000..66b5c84
--- /dev/null
+++ b/drivers/net/usb/smsc95xx.h
@@ -0,0 +1,253 @@
+ /***************************************************************************
+ *
+ * Copyright (C) 2007-2008 SMSC
+ *
+ * This program is free software; you can redistribute it and/or
+ * 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 _SMSC95XX_H
+#define _SMSC95XX_H
+
+/* Tx command words */
+#define TX_CMD_A_DATA_OFFSET_		(0x001F0000)
+#define TX_CMD_A_FIRST_SEG_		(0x00002000)
+#define TX_CMD_A_LAST_SEG_		(0x00001000)
+#define TX_CMD_A_BUF_SIZE_		(0x000007FF)
+
+#define TX_CMD_B_CSUM_ENABLE		(0x00004000)
+#define TX_CMD_B_ADD_CRC_DISABLE_	(0x00002000)
+#define TX_CMD_B_DISABLE_PADDING_	(0x00001000)
+#define TX_CMD_B_PKT_BYTE_LENGTH_	(0x000007FF)
+
+/* Rx status word */
+#define RX_STS_FF_			(0x40000000)	/* Filter Fail */
+#define RX_STS_FL_			(0x3FFF0000)	/* Frame Length */
+#define RX_STS_ES_			(0x00008000)	/* Error Summary */
+#define RX_STS_BF_			(0x00002000)	/* Broadcast Frame */
+#define RX_STS_LE_			(0x00001000)	/* Length Error */
+#define RX_STS_RF_			(0x00000800)	/* Runt Frame */
+#define RX_STS_MF_			(0x00000400)	/* Multicast Frame */
+#define RX_STS_TL_			(0x00000080)	/* Frame too long */
+#define RX_STS_CS_			(0x00000040)	/* Collision Seen */
+#define RX_STS_FT_			(0x00000020)	/* Frame Type */
+#define RX_STS_RW_			(0x00000010)	/* Receive Watchdog */
+#define RX_STS_ME_			(0x00000008)	/* Mii Error */
+#define RX_STS_DB_			(0x00000004)	/* Dribbling */
+#define RX_STS_CRC_			(0x00000002)	/* CRC Error */
+
+/* SCSRs */
+#define ID_REV				(0x00)
+#define ID_REV_CHIP_ID_MASK_		(0xFFFF0000)
+#define ID_REV_CHIP_REV_MASK_		(0x0000FFFF)
+#define ID_REV_CHIP_ID_9500_		(0x9500)
+
+#define INT_STS				(0x08)
+#define INT_STS_TX_STOP_		(0x00020000)
+#define INT_STS_RX_STOP_		(0x00010000)
+#define INT_STS_PHY_INT_		(0x00008000)
+#define INT_STS_TXE_			(0x00004000)
+#define INT_STS_TDFU_			(0x00002000)
+#define INT_STS_TDFO_			(0x00001000)
+#define INT_STS_RXDF_			(0x00000800)
+#define INT_STS_GPIOS_			(0x000007FF)
+
+#define RX_CFG				(0x0C)
+#define RX_FIFO_FLUSH_			(0x00000001)
+
+#define TX_CFG				(0x10)
+#define TX_CFG_ON_			(0x00000004)
+#define TX_CFG_STOP_			(0x00000002)
+#define TX_CFG_FIFO_FLUSH_		(0x00000001)
+
+#define HW_CFG				(0x14)
+#define HW_CFG_BIR_			(0x00001000)
+#define HW_CFG_LEDB_			(0x00000800)
+#define HW_CFG_RXDOFF_			(0x00000600)
+#define HW_CFG_DRP_			(0x00000040)
+#define HW_CFG_MEF_			(0x00000020)
+#define HW_CFG_LRST_			(0x00000008)
+#define HW_CFG_PSEL_			(0x00000004)
+#define HW_CFG_BCE_			(0x00000002)
+#define HW_CFG_SRST_			(0x00000001)
+
+#define PM_CTRL				(0x20)
+#define PM_CTL_DEV_RDY_			(0x00000080)
+#define PM_CTL_SUS_MODE_		(0x00000060)
+#define PM_CTL_SUS_MODE_0		(0x00000000)
+#define PM_CTL_SUS_MODE_1		(0x00000020)
+#define PM_CTL_SUS_MODE_2		(0x00000060)
+#define PM_CTL_PHY_RST_			(0x00000010)
+#define PM_CTL_WOL_EN_			(0x00000008)
+#define PM_CTL_ED_EN_			(0x00000004)
+#define PM_CTL_WUPS_			(0x00000003)
+#define PM_CTL_WUPS_NO_			(0x00000000)
+#define PM_CTL_WUPS_ED_			(0x00000001)
+#define PM_CTL_WUPS_WOL_		(0x00000002)
+#define PM_CTL_WUPS_MULTI_		(0x00000003)
+
+#define LED_GPIO_CFG			(0x24)
+
+#define GPIO_CFG			(0x28)
+
+#define AFC_CFG				(0x2C)
+
+/* Hi watermark = 15.5Kb (~10 mtu pkts) */
+/* low watermark = 3k (~2 mtu pkts) */
+/* backpressure duration = ~ 350us */
+/* Apply FC on any frame. */
+#define AFC_CFG_DEFAULT			(0x00F830A1)
+
+#define E2P_CMD				(0x30)
+#define E2P_CMD_BUSY_			(0x80000000)
+#define E2P_CMD_MASK_			(0x70000000)
+#define E2P_CMD_READ_			(0x00000000)
+#define E2P_CMD_EWDS_			(0x10000000)
+#define E2P_CMD_EWEN_			(0x20000000)
+#define E2P_CMD_WRITE_			(0x30000000)
+#define E2P_CMD_WRAL_			(0x40000000)
+#define E2P_CMD_ERASE_			(0x50000000)
+#define E2P_CMD_ERAL_			(0x60000000)
+#define E2P_CMD_RELOAD_			(0x70000000)
+#define E2P_CMD_TIMEOUT_		(0x00000400)
+#define E2P_CMD_LOADED_			(0x00000200)
+#define E2P_CMD_ADDR_			(0x000001FF)
+
+#define MAX_EEPROM_SIZE			(512)
+
+#define E2P_DATA			(0x34)
+#define E2P_DATA_MASK_			(0x000000FF)
+
+#define BURST_CAP			(0x38)
+
+#define GPIO_WAKE			(0x64)
+
+#define INT_EP_CTL			(0x68)
+#define INT_EP_CTL_INTEP_		(0x80000000)
+#define INT_EP_CTL_MACRTO_		(0x00080000)
+#define INT_EP_CTL_TX_STOP_		(0x00020000)
+#define INT_EP_CTL_RX_STOP_		(0x00010000)
+#define INT_EP_CTL_PHY_INT_		(0x00008000)
+#define INT_EP_CTL_TXE_			(0x00004000)
+#define INT_EP_CTL_TDFU_		(0x00002000)
+#define INT_EP_CTL_TDFO_		(0x00001000)
+#define INT_EP_CTL_RXDF_		(0x00000800)
+#define INT_EP_CTL_GPIOS_		(0x000007FF)
+
+#define BULK_IN_DLY			(0x6C)
+
+/* MAC CSRs */
+#define MAC_CR				(0x100)
+#define MAC_CR_RXALL_			(0x80000000)
+#define MAC_CR_RCVOWN_			(0x00800000)
+#define MAC_CR_LOOPBK_			(0x00200000)
+#define MAC_CR_FDPX_			(0x00100000)
+#define MAC_CR_MCPAS_			(0x00080000)
+#define MAC_CR_PRMS_			(0x00040000)
+#define MAC_CR_INVFILT_			(0x00020000)
+#define MAC_CR_PASSBAD_			(0x00010000)
+#define MAC_CR_HFILT_			(0x00008000)
+#define MAC_CR_HPFILT_			(0x00002000)
+#define MAC_CR_LCOLL_			(0x00001000)
+#define MAC_CR_BCAST_			(0x00000800)
+#define MAC_CR_DISRTY_			(0x00000400)
+#define MAC_CR_PADSTR_			(0x00000100)
+#define MAC_CR_BOLMT_MASK		(0x000000C0)
+#define MAC_CR_DFCHK_			(0x00000020)
+#define MAC_CR_TXEN_			(0x00000008)
+#define MAC_CR_RXEN_			(0x00000004)
+
+#define ADDRH				(0x104)
+
+#define ADDRL				(0x108)
+
+#define HASHH				(0x10C)
+
+#define HASHL				(0x110)
+
+#define MII_ADDR			(0x114)
+#define MII_WRITE_			(0x02)
+#define MII_BUSY_			(0x01)
+#define MII_READ_			(0x00) /* ~of MII Write bit */
+
+#define MII_DATA			(0x118)
+
+#define FLOW				(0x11C)
+#define FLOW_FCPT_			(0xFFFF0000)
+#define FLOW_FCPASS_			(0x00000004)
+#define FLOW_FCEN_			(0x00000002)
+#define FLOW_FCBSY_			(0x00000001)
+
+#define VLAN1				(0x120)
+
+#define VLAN2				(0x124)
+
+#define WUFF				(0x128)
+
+#define WUCSR				(0x12C)
+
+#define COE_CR				(0x130)
+#define Tx_COE_EN_			(0x00010000)
+#define Rx_COE_MODE_			(0x00000002)
+#define Rx_COE_EN_			(0x00000001)
+
+/* Vendor-specific PHY Definitions */
+
+/* Mode Control/Status Register */
+#define PHY_MODE_CTRL_STS		(17)
+#define MODE_CTRL_STS_EDPWRDOWN_	((u16)0x2000)
+#define MODE_CTRL_STS_ENERGYON_		((u16)0x0002)
+
+#define SPECIAL_CTRL_STS		(27)
+#define SPECIAL_CTRL_STS_OVRRD_AMDIX_	((u16)0x8000)
+#define SPECIAL_CTRL_STS_AMDIX_ENABLE_	((u16)0x4000)
+#define SPECIAL_CTRL_STS_AMDIX_STATE_	((u16)0x2000)
+
+#define PHY_INT_SRC			(29)
+#define PHY_INT_SRC_ENERGY_ON_		((u16)0x0080)
+#define PHY_INT_SRC_ANEG_COMP_		((u16)0x0040)
+#define PHY_INT_SRC_REMOTE_FAULT_	((u16)0x0020)
+#define PHY_INT_SRC_LINK_DOWN_		((u16)0x0010)
+
+#define PHY_INT_MASK			(30)
+#define PHY_INT_MASK_ENERGY_ON_		((u16)0x0080)
+#define PHY_INT_MASK_ANEG_COMP_		((u16)0x0040)
+#define PHY_INT_MASK_REMOTE_FAULT_	((u16)0x0020)
+#define PHY_INT_MASK_LINK_DOWN_		((u16)0x0010)
+#define PHY_INT_MASK_DEFAULT_		(PHY_INT_MASK_ANEG_COMP_ | \
+					 PHY_INT_MASK_LINK_DOWN_)
+
+#define PHY_SPECIAL			(31)
+#define PHY_SPECIAL_SPD_		((u16)0x001C)
+#define PHY_SPECIAL_SPD_10HALF_		((u16)0x0004)
+#define PHY_SPECIAL_SPD_10FULL_		((u16)0x0014)
+#define PHY_SPECIAL_SPD_100HALF_	((u16)0x0008)
+#define PHY_SPECIAL_SPD_100FULL_	((u16)0x0018)
+
+/* USB Vendor Requests */
+#define USB_VENDOR_REQUEST_WRITE_REGISTER	0xA0
+#define USB_VENDOR_REQUEST_READ_REGISTER	0xA1
+#define USB_VENDOR_REQUEST_GET_STATS		0xA2
+
+/* Interrupt Endpoint status word bitfields */
+#define INT_ENP_TX_STOP_		((u32)BIT(17))
+#define INT_ENP_RX_STOP_		((u32)BIT(16))
+#define INT_ENP_PHY_INT_		((u32)BIT(15))
+#define INT_ENP_TXE_			((u32)BIT(14))
+#define INT_ENP_TDFU_			((u32)BIT(13))
+#define INT_ENP_TDFO_			((u32)BIT(12))
+#define INT_ENP_RXDF_			((u32)BIT(11))
+
+#endif /* _SMSC95XX_H */
diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c
index 8463efb..02d25c74 100644
--- a/drivers/net/usb/usbnet.c
+++ b/drivers/net/usb/usbnet.c
@@ -512,14 +512,13 @@
 	int			count = 0;
 
 	spin_lock_irqsave (&q->lock, flags);
-	for (skb = q->next; skb != (struct sk_buff *) q; skb = skbnext) {
+	skb_queue_walk_safe(q, skb, skbnext) {
 		struct skb_data		*entry;
 		struct urb		*urb;
 		int			retval;
 
 		entry = (struct skb_data *) skb->cb;
 		urb = entry->urb;
-		skbnext = skb->next;
 
 		// during some PM-driven resume scenarios,
 		// these (async) unlinks complete immediately
diff --git a/drivers/net/via-rhine.c b/drivers/net/via-rhine.c
index 96dff04..5b78700 100644
--- a/drivers/net/via-rhine.c
+++ b/drivers/net/via-rhine.c
@@ -914,7 +914,7 @@
 
 	/* Fill in the Rx buffers.  Handle allocation failure gracefully. */
 	for (i = 0; i < RX_RING_SIZE; i++) {
-		struct sk_buff *skb = dev_alloc_skb(rp->rx_buf_sz);
+		struct sk_buff *skb = netdev_alloc_skb(dev, rp->rx_buf_sz);
 		rp->rx_skbuff[i] = skb;
 		if (skb == NULL)
 			break;
@@ -1473,8 +1473,8 @@
 			/* Check if the packet is long enough to accept without
 			   copying to a minimally-sized skbuff. */
 			if (pkt_len < rx_copybreak &&
-				(skb = dev_alloc_skb(pkt_len + 2)) != NULL) {
-				skb_reserve(skb, 2);	/* 16 byte align the IP header */
+				(skb = netdev_alloc_skb(dev, pkt_len + NET_IP_ALIGN)) != NULL) {
+				skb_reserve(skb, NET_IP_ALIGN);	/* 16 byte align the IP header */
 				pci_dma_sync_single_for_cpu(rp->pdev,
 							    rp->rx_skbuff_dma[entry],
 							    rp->rx_buf_sz,
@@ -1518,7 +1518,7 @@
 		struct sk_buff *skb;
 		entry = rp->dirty_rx % RX_RING_SIZE;
 		if (rp->rx_skbuff[entry] == NULL) {
-			skb = dev_alloc_skb(rp->rx_buf_sz);
+			skb = netdev_alloc_skb(dev, rp->rx_buf_sz);
 			rp->rx_skbuff[entry] = skb;
 			if (skb == NULL)
 				break;	/* Better luck next round. */
diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c
index 007c129..2dced38 100644
--- a/drivers/net/via-velocity.c
+++ b/drivers/net/via-velocity.c
@@ -12,7 +12,7 @@
  *	Scatter gather
  *	More testing
  *
- * The changes are (c) Copyright 2004, Red Hat Inc. <alan@redhat.com>
+ * The changes are (c) Copyright 2004, Red Hat Inc. <alan@lxorguk.ukuu.org.uk>
  * Additional fixes and clean up: Francois Romieu
  *
  * This source has not been verified for use in safety critical systems.
@@ -1272,7 +1272,7 @@
 			continue;
 		pci_unmap_single(vptr->pdev, rd_info->skb_dma, vptr->rx.buf_sz,
 				 PCI_DMA_FROMDEVICE);
-		rd_info->skb_dma = (dma_addr_t) NULL;
+		rd_info->skb_dma = 0;
 
 		dev_kfree_skb(rd_info->skb);
 		rd_info->skb = NULL;
@@ -1333,7 +1333,7 @@
 			if (td_info->skb_dma[i]) {
 				pci_unmap_single(vptr->pdev, td_info->skb_dma[i],
 					td_info->skb->len, PCI_DMA_TODEVICE);
-				td_info->skb_dma[i] = (dma_addr_t) NULL;
+				td_info->skb_dma[i] = 0;
 			}
 		}
 		dev_kfree_skb(td_info->skb);
diff --git a/drivers/net/via-velocity.h b/drivers/net/via-velocity.h
index 1b95b04..29a3309 100644
--- a/drivers/net/via-velocity.h
+++ b/drivers/net/via-velocity.h
@@ -1381,7 +1381,7 @@
 #define ASSERT(x) { \
 	if (!(x)) { \
 		printk(KERN_ERR "assertion %s failed: file %s line %d\n", #x,\
-			__FUNCTION__, __LINE__);\
+			__func__, __LINE__);\
 		BUG(); \
 	}\
 }
diff --git a/drivers/net/wan/Kconfig b/drivers/net/wan/Kconfig
index 2ae2ec4..21efd99 100644
--- a/drivers/net/wan/Kconfig
+++ b/drivers/net/wan/Kconfig
@@ -205,7 +205,7 @@
 
 config PC300
 	tristate "Cyclades-PC300 support (RS-232/V.35, X.21, T1/E1 boards)"
-	depends on HDLC && PCI
+	depends on HDLC && PCI && BROKEN
 	---help---
 	  Driver for the Cyclades-PC300 synchronous communication boards.
 
diff --git a/drivers/net/wan/cycx_drv.c b/drivers/net/wan/cycx_drv.c
index d14e667..a5ddc6c 100644
--- a/drivers/net/wan/cycx_drv.c
+++ b/drivers/net/wan/cycx_drv.c
@@ -407,7 +407,7 @@
 	if (cfm->version != CFM_VERSION) {
 		printk(KERN_ERR "%s:%s: firmware format %u rejected! "
 				"Expecting %u.\n",
-				modname, __FUNCTION__, cfm->version, CFM_VERSION);
+				modname, __func__, cfm->version, CFM_VERSION);
 		return -EINVAL;
 	}
 
@@ -420,7 +420,7 @@
 */
 	if (cksum != cfm->checksum) {
 		printk(KERN_ERR "%s:%s: firmware corrupted!\n",
-				modname, __FUNCTION__);
+				modname, __func__);
 		printk(KERN_ERR " cdsize = 0x%x (expected 0x%lx)\n",
 				len - (int)sizeof(struct cycx_firmware) - 1,
 				cfm->info.codesize);
@@ -432,7 +432,7 @@
 	/* If everything is ok, set reset, data and code pointers */
 	img_hdr = (struct cycx_fw_header *)&cfm->image;
 #ifdef FIRMWARE_DEBUG
-	printk(KERN_INFO "%s:%s: image sizes\n", __FUNCTION__, modname);
+	printk(KERN_INFO "%s:%s: image sizes\n", __func__, modname);
 	printk(KERN_INFO " reset=%lu\n", img_hdr->reset_size);
 	printk(KERN_INFO "  data=%lu\n", img_hdr->data_size);
 	printk(KERN_INFO "  code=%lu\n", img_hdr->code_size);
diff --git a/drivers/net/wan/cycx_x25.c b/drivers/net/wan/cycx_x25.c
index d3b28b0..5a7303d 100644
--- a/drivers/net/wan/cycx_x25.c
+++ b/drivers/net/wan/cycx_x25.c
@@ -874,7 +874,7 @@
 		nibble_to_byte(d + (sizeloc >> 1), rem, sizerem, sizeloc & 1);
 
 	dprintk(1, KERN_INFO "%s:lcn=%d, local=%s, remote=%s\n",
-			  __FUNCTION__, lcn, loc, rem);
+			  __func__, lcn, loc, rem);
 
 	dev = cycx_x25_get_dev_by_dte_addr(wandev, rem);
 	if (!dev) {
@@ -902,7 +902,7 @@
 	cycx_peek(&card->hw, cmd->buf, &lcn, sizeof(lcn));
 	cycx_peek(&card->hw, cmd->buf + 1, &key, sizeof(key));
 	dprintk(1, KERN_INFO "%s: %s:lcn=%d, key=%d\n",
-			  card->devname, __FUNCTION__, lcn, key);
+			  card->devname, __func__, lcn, key);
 
 	dev = cycx_x25_get_dev_by_lcn(wandev, -key);
 	if (!dev) {
@@ -929,7 +929,7 @@
 
 	cycx_peek(&card->hw, cmd->buf, &lcn, sizeof(lcn));
 	dprintk(1, KERN_INFO "%s: %s:lcn=%d\n",
-			  card->devname, __FUNCTION__, lcn);
+			  card->devname, __func__, lcn);
 	dev = cycx_x25_get_dev_by_lcn(wandev, lcn);
 	if (!dev) {
 		/* Invalid channel, discard packet */
@@ -950,7 +950,7 @@
 	u8 lcn;
 
 	cycx_peek(&card->hw, cmd->buf, &lcn, sizeof(lcn));
-	dprintk(1, KERN_INFO "%s:lcn=%d\n", __FUNCTION__, lcn);
+	dprintk(1, KERN_INFO "%s:lcn=%d\n", __func__, lcn);
 
 	dev = cycx_x25_get_dev_by_lcn(wandev, lcn);
 	if (dev) {
@@ -1381,7 +1381,7 @@
 		cycx_x25_chan_disconnect(dev);
 	else
 		printk(KERN_ERR "%s: %s for svc (%s) not connected!\n",
-				chan->card->devname, __FUNCTION__, dev->name);
+				chan->card->devname, __func__, dev->name);
 }
 
 /* Set logical channel state. */
@@ -1485,7 +1485,7 @@
 	unsigned char *ptr;
 
 	if ((skb = dev_alloc_skb(1)) == NULL) {
-		printk(KERN_ERR "%s: out of memory\n", __FUNCTION__);
+		printk(KERN_ERR "%s: out of memory\n", __func__);
 		return;
 	}
 
diff --git a/drivers/net/wan/dscc4.c b/drivers/net/wan/dscc4.c
index f5d55ad..5f1ccb2 100644
--- a/drivers/net/wan/dscc4.c
+++ b/drivers/net/wan/dscc4.c
@@ -647,7 +647,7 @@
 
 	skb = dpriv->rx_skbuff[dpriv->rx_current++%RX_RING_SIZE];
 	if (!skb) {
-		printk(KERN_DEBUG "%s: skb=0 (%s)\n", dev->name, __FUNCTION__);
+		printk(KERN_DEBUG "%s: skb=0 (%s)\n", dev->name, __func__);
 		goto refill;
 	}
 	pkt_len = TO_SIZE(le32_to_cpu(rx_fd->state2));
diff --git a/drivers/net/wan/hdlc_x25.c b/drivers/net/wan/hdlc_x25.c
index 8b7e5d2..cbcbf6f 100644
--- a/drivers/net/wan/hdlc_x25.c
+++ b/drivers/net/wan/hdlc_x25.c
@@ -163,15 +163,17 @@
 
 static int x25_rx(struct sk_buff *skb)
 {
+	struct net_device *dev = skb->dev;
+
 	if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) {
-		skb->dev->stats.rx_dropped++;
+		dev->stats.rx_dropped++;
 		return NET_RX_DROP;
 	}
 
-	if (lapb_data_received(skb->dev, skb) == LAPB_OK)
+	if (lapb_data_received(dev, skb) == LAPB_OK)
 		return NET_RX_SUCCESS;
 
-	skb->dev->stats.rx_errors++;
+	dev->stats.rx_errors++;
 	dev_kfree_skb_any(skb);
 	return NET_RX_DROP;
 }
diff --git a/drivers/net/wan/pc300_tty.c b/drivers/net/wan/pc300_tty.c
index 4518d0a..4917a94 100644
--- a/drivers/net/wan/pc300_tty.c
+++ b/drivers/net/wan/pc300_tty.c
@@ -548,7 +548,7 @@
 {
 	st_cpc_tty_area    *cpc_tty; 
 
-	CPC_TTY_DBG("%s: set:%x clear:%x\n", __FUNCTION__, set, clear);
+	CPC_TTY_DBG("%s: set:%x clear:%x\n", __func__, set, clear);
 
 	if (!tty || !tty->driver_data ) {
 	   	CPC_TTY_DBG("hdlcX-tty: no TTY to chars in buffer\n");	
diff --git a/drivers/net/wan/sbni.c b/drivers/net/wan/sbni.c
index 6596cd0..f972fef 100644
--- a/drivers/net/wan/sbni.c
+++ b/drivers/net/wan/sbni.c
@@ -856,7 +856,7 @@
 		len = SBNI_MIN_LEN;
 
 	nl->tx_buf_p	= skb;
-	nl->tx_frameno	= (len + nl->maxframe - 1) / nl->maxframe;
+	nl->tx_frameno	= DIV_ROUND_UP(len, nl->maxframe);
 	nl->framelen	= len < nl->maxframe  ?  len  :  nl->maxframe;
 
 	outb( inb( dev->base_addr + CSR0 ) | TR_REQ,  dev->base_addr + CSR0 );
diff --git a/drivers/net/wan/z85230.c b/drivers/net/wan/z85230.c
index 243bd8d..ccd9cd3 100644
--- a/drivers/net/wan/z85230.c
+++ b/drivers/net/wan/z85230.c
@@ -18,7 +18,8 @@
  *	DMA now uses get_free_page as kmalloc buffers may span a 64K 
  *	boundary.
  *
- *	Modified for SMP safety and SMP locking by Alan Cox <alan@redhat.com>
+ *	Modified for SMP safety and SMP locking by Alan Cox
+ *					<alan@lxorguk.ukuu.org.uk>
  *
  *	Performance
  *
diff --git a/drivers/net/wan/z85230.h b/drivers/net/wan/z85230.h
index 4f37239..85b3e78 100644
--- a/drivers/net/wan/z85230.h
+++ b/drivers/net/wan/z85230.h
@@ -2,7 +2,7 @@
  *	Description of Z8530 Z85C30 and Z85230 communications chips
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
- * Copyright (C) 1998 Alan Cox <alan@redhat.com>
+ * Copyright (C) 1998 Alan Cox <alan@lxorguk.ukuu.org.uk>
  */
 
 #ifndef _Z8530_H
diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig
index 9931b5a..45bdf0b 100644
--- a/drivers/net/wireless/Kconfig
+++ b/drivers/net/wireless/Kconfig
@@ -300,6 +300,19 @@
 	---help---
 	  Debugging support.
 
+config LIBERTAS_THINFIRM
+	tristate "Marvell 8xxx Libertas WLAN driver support with thin firmware"
+	depends on WLAN_80211 && MAC80211
+	select FW_LOADER
+	---help---
+	  A library for Marvell Libertas 8xxx devices using thinfirm.
+
+config LIBERTAS_THINFIRM_USB
+	tristate "Marvell Libertas 8388 USB 802.11b/g cards with thin firmware"
+	depends on LIBERTAS_THINFIRM && USB
+	---help---
+	  A driver for Marvell Libertas 8388 USB devices using thinfirm.
+
 config AIRO
 	tristate "Cisco/Aironet 34X/35X/4500/4800 ISA and PCI cards"
 	depends on ISA_DMA_API && WLAN_80211 && (PCI || BROKEN)
@@ -322,6 +335,9 @@
 	tristate "Hermes chipset 802.11b support (Orinoco/Prism2/Symbol)"
 	depends on (PPC_PMAC || PCI || PCMCIA) && WLAN_80211
 	select WIRELESS_EXT
+	select FW_LOADER
+	select CRYPTO
+	select CRYPTO_MICHAEL_MIC
 	---help---
 	  A driver for 802.11b wireless cards based on the "Hermes" or
 	  Intersil HFA384x (Prism 2) MAC controller.  This includes the vast
@@ -411,7 +427,6 @@
 config PCMCIA_SPECTRUM
 	tristate "Symbol Spectrum24 Trilogy PCMCIA card support"
 	depends on PCMCIA && HERMES
-	select FW_LOADER
 	---help---
 
 	  This is a driver for 802.11b cards using RAM-loadable Symbol
diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile
index 59aa89e..59d2d80 100644
--- a/drivers/net/wireless/Makefile
+++ b/drivers/net/wireless/Makefile
@@ -16,7 +16,7 @@
 obj-$(CONFIG_PCMCIA_NETWAVE)	+= netwave_cs.o
 obj-$(CONFIG_PCMCIA_WAVELAN)	+= wavelan_cs.o
 
-obj-$(CONFIG_HERMES)		+= orinoco.o hermes.o
+obj-$(CONFIG_HERMES)		+= orinoco.o hermes.o hermes_dld.o
 obj-$(CONFIG_PCMCIA_HERMES)	+= orinoco_cs.o
 obj-$(CONFIG_APPLE_AIRPORT)	+= airport.o
 obj-$(CONFIG_PLX_HERMES)	+= orinoco_plx.o
@@ -48,6 +48,8 @@
 obj-$(CONFIG_USB_ZD1201)	+= zd1201.o
 obj-$(CONFIG_LIBERTAS)		+= libertas/
 
+obj-$(CONFIG_LIBERTAS_THINFIRM)	+= libertas_tf/
+
 rtl8180-objs		:= rtl8180_dev.o rtl8180_rtl8225.o rtl8180_sa2400.o rtl8180_max2820.o rtl8180_grf5101.o
 rtl8187-objs		:= rtl8187_dev.o rtl8187_rtl8225.o
 
diff --git a/drivers/net/wireless/adm8211.c b/drivers/net/wireless/adm8211.c
index 3333d45..b2c050b 100644
--- a/drivers/net/wireless/adm8211.c
+++ b/drivers/net/wireless/adm8211.c
@@ -765,11 +765,11 @@
 
 	priv->soft_rx_crc = 0;
 	switch (priv->mode) {
-	case IEEE80211_IF_TYPE_STA:
+	case NL80211_IFTYPE_STATION:
 		priv->nar &= ~(ADM8211_NAR_PR | ADM8211_NAR_EA);
 		priv->nar |= ADM8211_NAR_ST | ADM8211_NAR_SR;
 		break;
-	case IEEE80211_IF_TYPE_IBSS:
+	case NL80211_IFTYPE_ADHOC:
 		priv->nar &= ~ADM8211_NAR_PR;
 		priv->nar |= ADM8211_NAR_EA | ADM8211_NAR_ST | ADM8211_NAR_SR;
 
@@ -777,7 +777,7 @@
 		if (priv->pdev->revision >= ADM8211_REV_BA)
 			priv->soft_rx_crc = 1;
 		break;
-	case IEEE80211_IF_TYPE_MNTR:
+	case NL80211_IFTYPE_MONITOR:
 		priv->nar &= ~(ADM8211_NAR_EA | ADM8211_NAR_ST);
 		priv->nar |= ADM8211_NAR_PR | ADM8211_NAR_SR;
 		break;
@@ -1410,11 +1410,11 @@
 				 struct ieee80211_if_init_conf *conf)
 {
 	struct adm8211_priv *priv = dev->priv;
-	if (priv->mode != IEEE80211_IF_TYPE_MNTR)
+	if (priv->mode != NL80211_IFTYPE_MONITOR)
 		return -EOPNOTSUPP;
 
 	switch (conf->type) {
-	case IEEE80211_IF_TYPE_STA:
+	case NL80211_IFTYPE_STATION:
 		priv->mode = conf->type;
 		break;
 	default:
@@ -1437,7 +1437,7 @@
 				     struct ieee80211_if_init_conf *conf)
 {
 	struct adm8211_priv *priv = dev->priv;
-	priv->mode = IEEE80211_IF_TYPE_MNTR;
+	priv->mode = NL80211_IFTYPE_MONITOR;
 }
 
 static int adm8211_init_rings(struct ieee80211_hw *dev)
@@ -1556,7 +1556,7 @@
 	ADM8211_CSR_WRITE(IER, ADM8211_IER_NIE | ADM8211_IER_AIE |
 			       ADM8211_IER_RCIE | ADM8211_IER_TCIE |
 			       ADM8211_IER_TDUIE | ADM8211_IER_GPTIE);
-	priv->mode = IEEE80211_IF_TYPE_MNTR;
+	priv->mode = NL80211_IFTYPE_MONITOR;
 	adm8211_update_mode(dev);
 	ADM8211_CSR_WRITE(RDR, 0);
 
@@ -1571,7 +1571,7 @@
 {
 	struct adm8211_priv *priv = dev->priv;
 
-	priv->mode = IEEE80211_IF_TYPE_INVALID;
+	priv->mode = NL80211_IFTYPE_UNSPECIFIED;
 	priv->nar = 0;
 	ADM8211_CSR_WRITE(NAR, 0);
 	ADM8211_CSR_WRITE(IER, 0);
@@ -1884,6 +1884,7 @@
 	dev->extra_tx_headroom = sizeof(struct adm8211_tx_hdr);
 	/* dev->flags = IEEE80211_HW_RX_INCLUDES_FCS in promisc mode */
 	dev->flags = IEEE80211_HW_SIGNAL_UNSPEC;
+	dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
 
 	dev->channel_change_time = 1000;
 	dev->max_signal = 100;    /* FIXME: find better value */
@@ -1895,7 +1896,7 @@
 	priv->tx_power = 0x40;
 	priv->lpf_cutoff = 0xFF;
 	priv->lnags_threshold = 0xFF;
-	priv->mode = IEEE80211_IF_TYPE_INVALID;
+	priv->mode = NL80211_IFTYPE_UNSPECIFIED;
 
 	/* Power-on issue. EEPROM won't read correctly without */
 	if (pdev->revision >= ADM8211_REV_BA) {
@@ -1985,7 +1986,7 @@
 	struct ieee80211_hw *dev = pci_get_drvdata(pdev);
 	struct adm8211_priv *priv = dev->priv;
 
-	if (priv->mode != IEEE80211_IF_TYPE_INVALID) {
+	if (priv->mode != NL80211_IFTYPE_UNSPECIFIED) {
 		ieee80211_stop_queues(dev);
 		adm8211_stop(dev);
 	}
@@ -2003,7 +2004,7 @@
 	pci_set_power_state(pdev, PCI_D0);
 	pci_restore_state(pdev);
 
-	if (priv->mode != IEEE80211_IF_TYPE_INVALID) {
+	if (priv->mode != NL80211_IFTYPE_UNSPECIFIED) {
 		adm8211_start(dev);
 		ieee80211_wake_queues(dev);
 	}
diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c
index b5cd850..370133e 100644
--- a/drivers/net/wireless/airo.c
+++ b/drivers/net/wireless/airo.c
@@ -1915,7 +1915,7 @@
 	struct airo_info *ai = dev->priv;
 
 	if (!skb) {
-		airo_print_err(dev->name, "%s: skb == NULL!",__FUNCTION__);
+		airo_print_err(dev->name, "%s: skb == NULL!",__func__);
 		return 0;
 	}
 	npacks = skb_queue_len (&ai->txq);
@@ -1964,7 +1964,7 @@
 	if ((skb = skb_dequeue(&ai->txq)) == NULL) {
 		airo_print_err(dev->name,
 			"%s: Dequeue'd zero in send_packet()",
-			__FUNCTION__);
+			__func__);
 		return 0;
 	}
 
@@ -2115,7 +2115,7 @@
 	u32 *fids = priv->fids;
 
 	if ( skb == NULL ) {
-		airo_print_err(dev->name, "%s: skb == NULL!", __FUNCTION__);
+		airo_print_err(dev->name, "%s: skb == NULL!", __func__);
 		return 0;
 	}
 
@@ -2186,7 +2186,7 @@
 	}
 
 	if ( skb == NULL ) {
-		airo_print_err(dev->name, "%s: skb == NULL!", __FUNCTION__);
+		airo_print_err(dev->name, "%s: skb == NULL!", __func__);
 		return 0;
 	}
 
@@ -4127,7 +4127,7 @@
 		if (test_bit(FLAG_ENABLED, &ai->flags) && (RID_WEP_TEMP != rid))
 			airo_print_err(ai->dev->name,
 				"%s: MAC should be disabled (rid=%04x)",
-				__FUNCTION__, rid);
+				__func__, rid);
 		memset(&cmd, 0, sizeof(cmd));
 		memset(&rsp, 0, sizeof(rsp));
 
@@ -4142,7 +4142,7 @@
 			&ai->config_desc.rid_desc, sizeof(Rid));
 
 		if (len < 4 || len > 2047) {
-			airo_print_err(ai->dev->name, "%s: len=%d", __FUNCTION__, len);
+			airo_print_err(ai->dev->name, "%s: len=%d", __func__, len);
 			rc = -1;
 		} else {
 			memcpy((char *)ai->config_desc.virtual_host_addr,
@@ -4151,9 +4151,9 @@
 			rc = issuecommand(ai, &cmd, &rsp);
 			if ((rc & 0xff00) != 0) {
 				airo_print_err(ai->dev->name, "%s: Write rid Error %d",
-						__FUNCTION__, rc);
+						__func__, rc);
 				airo_print_err(ai->dev->name, "%s: Cmd=%04x",
-						__FUNCTION__, cmd.cmd);
+						__func__, cmd.cmd);
 			}
 
 			if ((rsp.status & 0x7f00))
@@ -7107,7 +7107,7 @@
  */
 static int airo_set_scan(struct net_device *dev,
 			 struct iw_request_info *info,
-			 struct iw_param *vwrq,
+			 struct iw_point *dwrq,
 			 char *extra)
 {
 	struct airo_info *ai = dev->priv;
diff --git a/drivers/net/wireless/airo_cs.c b/drivers/net/wireless/airo_cs.c
index f123553..27696c2 100644
--- a/drivers/net/wireless/airo_cs.c
+++ b/drivers/net/wireless/airo_cs.c
@@ -147,7 +147,7 @@
 	DEBUG(0, "airo_attach()\n");
 
 	/* Interrupt setup */
-	p_dev->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
+	p_dev->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING;
 	p_dev->irq.IRQInfo1 = IRQ_LEVEL_ID;
 	p_dev->irq.Handler = NULL;
 	
@@ -206,126 +206,123 @@
 #define CS_CHECK(fn, ret) \
 do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)
 
+static int airo_cs_config_check(struct pcmcia_device *p_dev,
+				cistpl_cftable_entry_t *cfg,
+				cistpl_cftable_entry_t *dflt,
+				unsigned int vcc,
+				void *priv_data)
+{
+	win_req_t *req = priv_data;
+
+	if (cfg->index == 0)
+		return -ENODEV;
+
+	/* Does this card need audio output? */
+	if (cfg->flags & CISTPL_CFTABLE_AUDIO) {
+		p_dev->conf.Attributes |= CONF_ENABLE_SPKR;
+		p_dev->conf.Status = CCSR_AUDIO_ENA;
+	}
+
+	/* Use power settings for Vcc and Vpp if present */
+	/*  Note that the CIS values need to be rescaled */
+	if (cfg->vpp1.present & (1<<CISTPL_POWER_VNOM))
+		p_dev->conf.Vpp = cfg->vpp1.param[CISTPL_POWER_VNOM]/10000;
+	else if (dflt->vpp1.present & (1<<CISTPL_POWER_VNOM))
+		p_dev->conf.Vpp = dflt->vpp1.param[CISTPL_POWER_VNOM]/10000;
+
+	/* Do we need to allocate an interrupt? */
+	if (cfg->irq.IRQInfo1 || dflt->irq.IRQInfo1)
+		p_dev->conf.Attributes |= CONF_ENABLE_IRQ;
+
+	/* IO window settings */
+	p_dev->io.NumPorts1 = p_dev->io.NumPorts2 = 0;
+	if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) {
+		cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io;
+		p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
+		if (!(io->flags & CISTPL_IO_8BIT))
+			p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_16;
+		if (!(io->flags & CISTPL_IO_16BIT))
+			p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
+		p_dev->io.BasePort1 = io->win[0].base;
+		p_dev->io.NumPorts1 = io->win[0].len;
+		if (io->nwin > 1) {
+			p_dev->io.Attributes2 = p_dev->io.Attributes1;
+			p_dev->io.BasePort2 = io->win[1].base;
+			p_dev->io.NumPorts2 = io->win[1].len;
+		}
+	}
+
+	/* This reserves IO space but doesn't actually enable it */
+	if (pcmcia_request_io(p_dev, &p_dev->io) != 0)
+		return -ENODEV;
+
+	/*
+	  Now set up a common memory window, if needed.  There is room
+	  in the struct pcmcia_device structure for one memory window handle,
+	  but if the base addresses need to be saved, or if multiple
+	  windows are needed, the info should go in the private data
+	  structure for this device.
+
+	  Note that the memory window base is a physical address, and
+	  needs to be mapped to virtual space with ioremap() before it
+	  is used.
+	*/
+	if ((cfg->mem.nwin > 0) || (dflt->mem.nwin > 0)) {
+		cistpl_mem_t *mem = (cfg->mem.nwin) ? &cfg->mem : &dflt->mem;
+		memreq_t map;
+		req->Attributes = WIN_DATA_WIDTH_16|WIN_MEMORY_TYPE_CM;
+		req->Base = mem->win[0].host_addr;
+		req->Size = mem->win[0].len;
+		req->AccessSpeed = 0;
+		if (pcmcia_request_window(&p_dev, req, &p_dev->win) != 0)
+			return -ENODEV;
+		map.Page = 0;
+		map.CardOffset = mem->win[0].card_addr;
+		if (pcmcia_map_mem_page(p_dev->win, &map) != 0)
+			return -ENODEV;
+	}
+	/* If we got this far, we're cool! */
+	return 0;
+}
+
+
 static int airo_config(struct pcmcia_device *link)
 {
-	tuple_t tuple;
-	cisparse_t parse;
 	local_info_t *dev;
+	win_req_t *req;
 	int last_fn, last_ret;
-	u_char buf[64];
-	win_req_t req;
-	memreq_t map;
 
 	dev = link->priv;
 
 	DEBUG(0, "airo_config(0x%p)\n", link);
 
+	req = kzalloc(sizeof(win_req_t), GFP_KERNEL);
+	if (!req)
+		return -ENOMEM;
+
 	/*
-	  In this loop, we scan the CIS for configuration table entries,
-	  each of which describes a valid card configuration, including
-	  voltage, IO window, memory window, and interrupt settings.
-	  
-	  We make no assumptions about the card to be configured: we use
-	  just the information available in the CIS.  In an ideal world,
-	  this would work for any PCMCIA card, but it requires a complete
-	  and accurate CIS.  In practice, a driver usually "knows" most of
-	  these things without consulting the CIS, and most client drivers
-	  will only use the CIS to fill in implementation-defined details.
+	 * In this loop, we scan the CIS for configuration table
+	 * entries, each of which describes a valid card
+	 * configuration, including voltage, IO window, memory window,
+	 * and interrupt settings.
+	 *
+	 * We make no assumptions about the card to be configured: we
+	 * use just the information available in the CIS.  In an ideal
+	 * world, this would work for any PCMCIA card, but it requires
+	 * a complete and accurate CIS.  In practice, a driver usually
+	 * "knows" most of these things without consulting the CIS,
+	 * and most client drivers will only use the CIS to fill in
+	 * implementation-defined details.
+	 */
+	last_ret = pcmcia_loop_config(link, airo_cs_config_check, req);
+	if (last_ret)
+		goto failed;
+
+	/*
+	  Allocate an interrupt line.  Note that this does not assign a
+	  handler to the interrupt, unless the 'Handler' member of the
+	  irq structure is initialized.
 	*/
-	tuple.Attributes = 0;
-	tuple.TupleData = buf;
-	tuple.TupleDataMax = sizeof(buf);
-	tuple.TupleOffset = 0;
-	tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
-	CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple));
-	while (1) {
-		cistpl_cftable_entry_t dflt = { 0 };
-		cistpl_cftable_entry_t *cfg = &(parse.cftable_entry);
-		if (pcmcia_get_tuple_data(link, &tuple) != 0 ||
-				pcmcia_parse_tuple(link, &tuple, &parse) != 0)
-			goto next_entry;
-		
-		if (cfg->flags & CISTPL_CFTABLE_DEFAULT) dflt = *cfg;
-		if (cfg->index == 0) goto next_entry;
-		link->conf.ConfigIndex = cfg->index;
-		
-		/* Does this card need audio output? */
-		if (cfg->flags & CISTPL_CFTABLE_AUDIO) {
-			link->conf.Attributes |= CONF_ENABLE_SPKR;
-			link->conf.Status = CCSR_AUDIO_ENA;
-		}
-		
-		/* Use power settings for Vcc and Vpp if present */
-		/*  Note that the CIS values need to be rescaled */
-		if (cfg->vpp1.present & (1<<CISTPL_POWER_VNOM))
-			link->conf.Vpp =
-				cfg->vpp1.param[CISTPL_POWER_VNOM]/10000;
-		else if (dflt.vpp1.present & (1<<CISTPL_POWER_VNOM))
-			link->conf.Vpp =
-				dflt.vpp1.param[CISTPL_POWER_VNOM]/10000;
-		
-		/* Do we need to allocate an interrupt? */
-		if (cfg->irq.IRQInfo1 || dflt.irq.IRQInfo1)
-			link->conf.Attributes |= CONF_ENABLE_IRQ;
-		
-		/* IO window settings */
-		link->io.NumPorts1 = link->io.NumPorts2 = 0;
-		if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) {
-			cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt.io;
-			link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
-			if (!(io->flags & CISTPL_IO_8BIT))
-				link->io.Attributes1 = IO_DATA_PATH_WIDTH_16;
-			if (!(io->flags & CISTPL_IO_16BIT))
-				link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
-			link->io.BasePort1 = io->win[0].base;
-			link->io.NumPorts1 = io->win[0].len;
-			if (io->nwin > 1) {
-				link->io.Attributes2 = link->io.Attributes1;
-				link->io.BasePort2 = io->win[1].base;
-				link->io.NumPorts2 = io->win[1].len;
-			}
-		}
-		
-		/* This reserves IO space but doesn't actually enable it */
-		if (pcmcia_request_io(link, &link->io) != 0)
-			goto next_entry;
-		
-		/*
-		  Now set up a common memory window, if needed.  There is room
-		  in the struct pcmcia_device structure for one memory window handle,
-		  but if the base addresses need to be saved, or if multiple
-		  windows are needed, the info should go in the private data
-		  structure for this device.
-		  
-		  Note that the memory window base is a physical address, and
-		  needs to be mapped to virtual space with ioremap() before it
-		  is used.
-		*/
-		if ((cfg->mem.nwin > 0) || (dflt.mem.nwin > 0)) {
-			cistpl_mem_t *mem =
-				(cfg->mem.nwin) ? &cfg->mem : &dflt.mem;
-			req.Attributes = WIN_DATA_WIDTH_16|WIN_MEMORY_TYPE_CM;
-			req.Base = mem->win[0].host_addr;
-			req.Size = mem->win[0].len;
-			req.AccessSpeed = 0;
-			if (pcmcia_request_window(&link, &req, &link->win) != 0)
-				goto next_entry;
-			map.Page = 0; map.CardOffset = mem->win[0].card_addr;
-			if (pcmcia_map_mem_page(link->win, &map) != 0)
-				goto next_entry;
-		}
-		/* If we got this far, we're cool! */
-		break;
-		
-	next_entry:
-		CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(link, &tuple));
-	}
-	
-    /*
-      Allocate an interrupt line.  Note that this does not assign a
-      handler to the interrupt, unless the 'Handler' member of the
-      irq structure is initialized.
-    */
 	if (link->conf.Attributes & CONF_ENABLE_IRQ)
 		CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq));
 	
@@ -362,14 +359,17 @@
 		printk(" & 0x%04x-0x%04x", link->io.BasePort2,
 		       link->io.BasePort2+link->io.NumPorts2-1);
 	if (link->win)
-		printk(", mem 0x%06lx-0x%06lx", req.Base,
-		       req.Base+req.Size-1);
+		printk(", mem 0x%06lx-0x%06lx", req->Base,
+		       req->Base+req->Size-1);
 	printk("\n");
+	kfree(req);
 	return 0;
 
  cs_failed:
 	cs_error(link, last_fn, last_ret);
+ failed:
 	airo_release(link);
+	kfree(req);
 	return -ENODEV;
 } /* airo_config */
 
diff --git a/drivers/net/wireless/airport.c b/drivers/net/wireless/airport.c
index 6f7eb9f..ce03a2e 100644
--- a/drivers/net/wireless/airport.c
+++ b/drivers/net/wireless/airport.c
@@ -180,7 +180,8 @@
 	}
 
 	/* Allocate space for private device-specific data */
-	dev = alloc_orinocodev(sizeof(*card), airport_hard_reset);
+	dev = alloc_orinocodev(sizeof(*card), &mdev->ofdev.dev,
+			       airport_hard_reset, NULL);
 	if (! dev) {
 		printk(KERN_ERR PFX "Cannot allocate network device\n");
 		return -ENODEV;
diff --git a/drivers/net/wireless/ath5k/Makefile b/drivers/net/wireless/ath5k/Makefile
index 564ecd0..719cfae 100644
--- a/drivers/net/wireless/ath5k/Makefile
+++ b/drivers/net/wireless/ath5k/Makefile
@@ -1,6 +1,14 @@
-ath5k-y				+= base.o
-ath5k-y				+= hw.o
+ath5k-y				+= caps.o
 ath5k-y				+= initvals.o
+ath5k-y				+= eeprom.o
+ath5k-y				+= gpio.o
+ath5k-y				+= desc.o
+ath5k-y				+= dma.o
+ath5k-y				+= qcu.o
+ath5k-y				+= pcu.o
 ath5k-y				+= phy.o
+ath5k-y				+= reset.o
+ath5k-y				+= attach.o
+ath5k-y				+= base.o
 ath5k-$(CONFIG_ATH5K_DEBUG)	+= debug.o
 obj-$(CONFIG_ATH5K)		+= ath5k.o
diff --git a/drivers/net/wireless/ath5k/ath5k.h b/drivers/net/wireless/ath5k/ath5k.h
index 9102eea..53ea439 100644
--- a/drivers/net/wireless/ath5k/ath5k.h
+++ b/drivers/net/wireless/ath5k/ath5k.h
@@ -18,18 +18,23 @@
 #ifndef _ATH5K_H
 #define _ATH5K_H
 
-/* Set this to 1 to disable regulatory domain restrictions for channel tests.
- * WARNING: This is for debuging only and has side effects (eg. scan takes too
- * long and results timeouts). It's also illegal to tune to some of the
- * supported frequencies in some countries, so use this at your own risk,
- * you've been warned. */
+/* TODO: Clean up channel debuging -doesn't work anyway- and start
+ * working on reg. control code using all available eeprom information
+ * -rev. engineering needed- */
 #define CHAN_DEBUG	0
 
 #include <linux/io.h>
 #include <linux/types.h>
 #include <net/mac80211.h>
 
-#include "hw.h"
+/* RX/TX descriptor hw structs
+ * TODO: Driver part should only see sw structs */
+#include "desc.h"
+
+/* EEPROM structs/offsets
+ * TODO: Make a more generic struct (eg. add more stuff to ath5k_capabilities)
+ * and clean up common bits, then introduce set/get functions in eeprom.c */
+#include "eeprom.h"
 
 /* PCI IDs */
 #define PCI_DEVICE_ID_ATHEROS_AR5210 		0x0007 /* AR5210 */
@@ -87,7 +92,92 @@
 	ATH5K_PRINTK_LIMIT(_sc, KERN_ERR, _fmt, ##__VA_ARGS__)
 
 /*
+ * AR5K REGISTER ACCESS
+ */
+
+/* Some macros to read/write fields */
+
+/* First shift, then mask */
+#define AR5K_REG_SM(_val, _flags)					\
+	(((_val) << _flags##_S) & (_flags))
+
+/* First mask, then shift */
+#define AR5K_REG_MS(_val, _flags)					\
+	(((_val) & (_flags)) >> _flags##_S)
+
+/* Some registers can hold multiple values of interest. For this
+ * reason when we want to write to these registers we must first
+ * retrieve the values which we do not want to clear (lets call this
+ * old_data) and then set the register with this and our new_value:
+ * ( old_data | new_value) */
+#define AR5K_REG_WRITE_BITS(ah, _reg, _flags, _val)			\
+	ath5k_hw_reg_write(ah, (ath5k_hw_reg_read(ah, _reg) & ~(_flags)) | \
+	    (((_val) << _flags##_S) & (_flags)), _reg)
+
+#define AR5K_REG_MASKED_BITS(ah, _reg, _flags, _mask)			\
+	ath5k_hw_reg_write(ah, (ath5k_hw_reg_read(ah, _reg) &		\
+			(_mask)) | (_flags), _reg)
+
+#define AR5K_REG_ENABLE_BITS(ah, _reg, _flags)				\
+	ath5k_hw_reg_write(ah, ath5k_hw_reg_read(ah, _reg) | (_flags), _reg)
+
+#define AR5K_REG_DISABLE_BITS(ah, _reg, _flags)			\
+	ath5k_hw_reg_write(ah, ath5k_hw_reg_read(ah, _reg) & ~(_flags), _reg)
+
+/* Access to PHY registers */
+#define AR5K_PHY_READ(ah, _reg)					\
+	ath5k_hw_reg_read(ah, (ah)->ah_phy + ((_reg) << 2))
+
+#define AR5K_PHY_WRITE(ah, _reg, _val)					\
+	ath5k_hw_reg_write(ah, _val, (ah)->ah_phy + ((_reg) << 2))
+
+/* Access QCU registers per queue */
+#define AR5K_REG_READ_Q(ah, _reg, _queue)				\
+	(ath5k_hw_reg_read(ah, _reg) & (1 << _queue))			\
+
+#define AR5K_REG_WRITE_Q(ah, _reg, _queue)				\
+	ath5k_hw_reg_write(ah, (1 << _queue), _reg)
+
+#define AR5K_Q_ENABLE_BITS(_reg, _queue) do {				\
+	_reg |= 1 << _queue;						\
+} while (0)
+
+#define AR5K_Q_DISABLE_BITS(_reg, _queue) do {				\
+	_reg &= ~(1 << _queue);						\
+} while (0)
+
+/* Used while writing initvals */
+#define AR5K_REG_WAIT(_i) do {						\
+	if (_i % 64)							\
+		udelay(1);						\
+} while (0)
+
+/* Register dumps are done per operation mode */
+#define AR5K_INI_RFGAIN_5GHZ		0
+#define AR5K_INI_RFGAIN_2GHZ		1
+
+/* TODO: Clean this up */
+#define AR5K_INI_VAL_11A		0
+#define AR5K_INI_VAL_11A_TURBO		1
+#define AR5K_INI_VAL_11B		2
+#define AR5K_INI_VAL_11G		3
+#define AR5K_INI_VAL_11G_TURBO		4
+#define AR5K_INI_VAL_XR			0
+#define AR5K_INI_VAL_MAX		5
+
+#define AR5K_RF5111_INI_RF_MAX_BANKS	AR5K_MAX_RF_BANKS
+#define AR5K_RF5112_INI_RF_MAX_BANKS	AR5K_MAX_RF_BANKS
+
+/* Used for BSSID etc manipulation */
+#define AR5K_LOW_ID(_a)(				\
+(_a)[0] | (_a)[1] << 8 | (_a)[2] << 16 | (_a)[3] << 24	\
+)
+
+#define AR5K_HIGH_ID(_a)	((_a)[4] | (_a)[5] << 8)
+
+/*
  * Some tuneable values (these should be changeable by the user)
+ * TODO: Make use of them and add more options OR use debug/configfs
  */
 #define AR5K_TUNE_DMA_BEACON_RESP		2
 #define AR5K_TUNE_SW_BEACON_RESP		10
@@ -98,13 +188,13 @@
 #define AR5K_TUNE_REGISTER_TIMEOUT		20000
 /* Register for RSSI threshold has a mask of 0xff, so 255 seems to
  * be the max value. */
-#define AR5K_TUNE_RSSI_THRES                   129
+#define AR5K_TUNE_RSSI_THRES			129
 /* This must be set when setting the RSSI threshold otherwise it can
  * prevent a reset. If AR5K_RSSI_THR is read after writing to it
  * the BMISS_THRES will be seen as 0, seems harware doesn't keep
  * track of it. Max value depends on harware. For AR5210 this is just 7.
  * For AR5211+ this seems to be up to 255. */
-#define AR5K_TUNE_BMISS_THRES                  7
+#define AR5K_TUNE_BMISS_THRES			7
 #define AR5K_TUNE_REGISTER_DWELL_TIME		20000
 #define AR5K_TUNE_BEACON_INTERVAL		100
 #define AR5K_TUNE_AIFS				2
@@ -123,6 +213,55 @@
 #define AR5K_TUNE_ANT_DIVERSITY			true
 #define AR5K_TUNE_HWTXTRIES			4
 
+#define AR5K_INIT_CARR_SENSE_EN			1
+
+/*Swap RX/TX Descriptor for big endian archs*/
+#if defined(__BIG_ENDIAN)
+#define AR5K_INIT_CFG	(		\
+	AR5K_CFG_SWTD | AR5K_CFG_SWRD	\
+)
+#else
+#define AR5K_INIT_CFG	0x00000000
+#endif
+
+/* Initial values */
+#define AR5K_INIT_TX_LATENCY			502
+#define AR5K_INIT_USEC				39
+#define AR5K_INIT_USEC_TURBO			79
+#define AR5K_INIT_USEC_32			31
+#define AR5K_INIT_SLOT_TIME			396
+#define AR5K_INIT_SLOT_TIME_TURBO		480
+#define AR5K_INIT_ACK_CTS_TIMEOUT		1024
+#define AR5K_INIT_ACK_CTS_TIMEOUT_TURBO		0x08000800
+#define AR5K_INIT_PROG_IFS			920
+#define AR5K_INIT_PROG_IFS_TURBO		960
+#define AR5K_INIT_EIFS				3440
+#define AR5K_INIT_EIFS_TURBO			6880
+#define AR5K_INIT_SIFS				560
+#define AR5K_INIT_SIFS_TURBO			480
+#define AR5K_INIT_SH_RETRY			10
+#define AR5K_INIT_LG_RETRY			AR5K_INIT_SH_RETRY
+#define AR5K_INIT_SSH_RETRY			32
+#define AR5K_INIT_SLG_RETRY			AR5K_INIT_SSH_RETRY
+#define AR5K_INIT_TX_RETRY			10
+
+#define AR5K_INIT_TRANSMIT_LATENCY		(			\
+	(AR5K_INIT_TX_LATENCY << 14) | (AR5K_INIT_USEC_32 << 7) |	\
+	(AR5K_INIT_USEC)						\
+)
+#define AR5K_INIT_TRANSMIT_LATENCY_TURBO	(			\
+	(AR5K_INIT_TX_LATENCY << 14) | (AR5K_INIT_USEC_32 << 7) |	\
+	(AR5K_INIT_USEC_TURBO)						\
+)
+#define AR5K_INIT_PROTO_TIME_CNTRL		(			\
+	(AR5K_INIT_CARR_SENSE_EN << 26) | (AR5K_INIT_EIFS << 12) |	\
+	(AR5K_INIT_PROG_IFS)						\
+)
+#define AR5K_INIT_PROTO_TIME_CNTRL_TURBO	(			\
+	(AR5K_INIT_CARR_SENSE_EN << 26) | (AR5K_INIT_EIFS_TURBO << 12) | \
+	(AR5K_INIT_PROG_IFS_TURBO)					\
+)
+
 /* token to use for aifs, cwmin, cwmax in MadWiFi */
 #define	AR5K_TXQ_USEDEFAULT	((u32) -1)
 
@@ -142,7 +281,9 @@
 	AR5K_RF5112	= 2,
 	AR5K_RF2413	= 3,
 	AR5K_RF5413	= 4,
-	AR5K_RF2425	= 5,
+	AR5K_RF2316	= 5,
+	AR5K_RF2317	= 6,
+	AR5K_RF2425	= 7,
 };
 
 /*
@@ -150,7 +291,7 @@
  */
 
 enum ath5k_srev_type {
-	AR5K_VERSION_VER,
+	AR5K_VERSION_MAC,
 	AR5K_VERSION_RAD,
 };
 
@@ -162,23 +303,24 @@
 
 #define AR5K_SREV_UNKNOWN	0xffff
 
-#define AR5K_SREV_VER_AR5210	0x00
-#define AR5K_SREV_VER_AR5311	0x10
-#define AR5K_SREV_VER_AR5311A	0x20
-#define AR5K_SREV_VER_AR5311B	0x30
-#define AR5K_SREV_VER_AR5211	0x40
-#define AR5K_SREV_VER_AR5212	0x50
-#define AR5K_SREV_VER_AR5213	0x55
-#define AR5K_SREV_VER_AR5213A	0x59
-#define AR5K_SREV_VER_AR2413	0x78
-#define AR5K_SREV_VER_AR2414	0x79
-#define AR5K_SREV_VER_AR2424	0xa0 /* PCI-E */
-#define AR5K_SREV_VER_AR5424	0xa3 /* PCI-E */
-#define AR5K_SREV_VER_AR5413	0xa4
-#define AR5K_SREV_VER_AR5414	0xa5
-#define AR5K_SREV_VER_AR5416	0xc0 /* PCI-E */
-#define AR5K_SREV_VER_AR5418	0xca /* PCI-E */
-#define AR5K_SREV_VER_AR2425	0xe2 /* PCI-E */
+#define AR5K_SREV_AR5210	0x00 /* Crete */
+#define AR5K_SREV_AR5311	0x10 /* Maui 1 */
+#define AR5K_SREV_AR5311A	0x20 /* Maui 2 */
+#define AR5K_SREV_AR5311B	0x30 /* Spirit */
+#define AR5K_SREV_AR5211	0x40 /* Oahu */
+#define AR5K_SREV_AR5212	0x50 /* Venice */
+#define AR5K_SREV_AR5213	0x55 /* ??? */
+#define AR5K_SREV_AR5213A	0x59 /* Hainan */
+#define AR5K_SREV_AR2413	0x78 /* Griffin lite */
+#define AR5K_SREV_AR2414	0x70 /* Griffin */
+#define AR5K_SREV_AR5424	0x90 /* Condor */
+#define AR5K_SREV_AR5413	0xa4 /* Eagle lite */
+#define AR5K_SREV_AR5414	0xa0 /* Eagle */
+#define AR5K_SREV_AR2415	0xb0 /* Cobra */
+#define AR5K_SREV_AR5416	0xc0 /* PCI-E */
+#define AR5K_SREV_AR5418	0xca /* PCI-E */
+#define AR5K_SREV_AR2425	0xe0 /* Swan */
+#define AR5K_SREV_AR2417	0xf0 /* Nala */
 
 #define AR5K_SREV_RAD_5110	0x00
 #define AR5K_SREV_RAD_5111	0x10
@@ -190,13 +332,22 @@
 #define AR5K_SREV_RAD_2112	0x40
 #define AR5K_SREV_RAD_2112A	0x45
 #define	AR5K_SREV_RAD_2112B	0x46
-#define AR5K_SREV_RAD_SC0	0x50	/* Found on 2413/2414 */
-#define AR5K_SREV_RAD_SC1	0x60	/* Found on 5413/5414 */
-#define AR5K_SREV_RAD_SC2	0xa0	/* Found on 2424-5/5424 */
-#define AR5K_SREV_RAD_5133	0xc0	/* MIMO found on 5418 */
+#define AR5K_SREV_RAD_2413	0x50
+#define AR5K_SREV_RAD_5413	0x60
+#define AR5K_SREV_RAD_2316	0x70
+#define AR5K_SREV_RAD_2317	0x80
+#define AR5K_SREV_RAD_5424	0xa0 /* Mostly same as 5413 */
+#define AR5K_SREV_RAD_2425	0xa2
+#define AR5K_SREV_RAD_5133	0xc0
+
+#define AR5K_SREV_PHY_5211	0x30
+#define AR5K_SREV_PHY_5212	0x41
+#define AR5K_SREV_PHY_2112B	0x43
+#define AR5K_SREV_PHY_2413	0x45
+#define AR5K_SREV_PHY_5413	0x61
+#define AR5K_SREV_PHY_2425	0x70
 
 /* IEEE defs */
-
 #define IEEE80211_MAX_LEN       2500
 
 /* TODO add support to mac80211 for vendor-specific rates and modes */
@@ -268,27 +419,21 @@
 	AR5K_MODE_MAX		=	5
 };
 
-/* adding this flag to rate_code enables short preamble, see ar5212_reg.h */
-#define AR5K_SET_SHORT_PREAMBLE 0x04
-
-#define HAS_SHPREAMBLE(_ix) \
-	(rt->rates[_ix].modulation == IEEE80211_RATE_SHORT_PREAMBLE)
-#define SHPREAMBLE_FLAG(_ix) \
-	(HAS_SHPREAMBLE(_ix) ? AR5K_SET_SHORT_PREAMBLE : 0)
-
 
 /****************\
   TX DEFINITIONS
 \****************/
 
 /*
- * TX Status
+ * TX Status descriptor
  */
 struct ath5k_tx_status {
 	u16	ts_seqnum;
 	u16	ts_tstamp;
 	u8	ts_status;
-	u8	ts_rate;
+	u8	ts_rate[4];
+	u8	ts_retry[4];
+	u8	ts_final_idx;
 	s8	ts_rssi;
 	u8	ts_shortretry;
 	u8	ts_longretry;
@@ -354,7 +499,6 @@
 	AR5K_TX_QUEUE_ID_XR_DATA	= 9,
 };
 
-
 /*
  * Flags to set hw queue's parameters...
  */
@@ -387,7 +531,8 @@
 
 /*
  * Transmit packet types.
- * These are not fully used inside OpenHAL yet
+ * used on tx control descriptor
+ * TODO: Use them inside base.c corectly
  */
 enum ath5k_pkt_type {
 	AR5K_PKT_TYPE_NORMAL		= 0,
@@ -430,7 +575,7 @@
 \****************/
 
 /*
- * RX Status
+ * RX Status descriptor
  */
 struct ath5k_rx_status {
 	u16	rs_datalen;
@@ -494,34 +639,59 @@
 #define TSF_TO_TU(_tsf) (u32)((_tsf) >> 10)
 
 
+/*******************************\
+  GAIN OPTIMIZATION DEFINITIONS
+\*******************************/
+
+enum ath5k_rfgain {
+	AR5K_RFGAIN_INACTIVE = 0,
+	AR5K_RFGAIN_READ_REQUESTED,
+	AR5K_RFGAIN_NEED_CHANGE,
+};
+
+#define AR5K_GAIN_CRN_FIX_BITS_5111		4
+#define AR5K_GAIN_CRN_FIX_BITS_5112		7
+#define AR5K_GAIN_CRN_MAX_FIX_BITS		AR5K_GAIN_CRN_FIX_BITS_5112
+#define AR5K_GAIN_DYN_ADJUST_HI_MARGIN		15
+#define AR5K_GAIN_DYN_ADJUST_LO_MARGIN		20
+#define AR5K_GAIN_CCK_PROBE_CORR		5
+#define AR5K_GAIN_CCK_OFDM_GAIN_DELTA		15
+#define AR5K_GAIN_STEP_COUNT			10
+#define AR5K_GAIN_PARAM_TX_CLIP			0
+#define AR5K_GAIN_PARAM_PD_90			1
+#define AR5K_GAIN_PARAM_PD_84			2
+#define AR5K_GAIN_PARAM_GAIN_SEL		3
+#define AR5K_GAIN_PARAM_MIX_ORN			0
+#define AR5K_GAIN_PARAM_PD_138			1
+#define AR5K_GAIN_PARAM_PD_137			2
+#define AR5K_GAIN_PARAM_PD_136			3
+#define AR5K_GAIN_PARAM_PD_132			4
+#define AR5K_GAIN_PARAM_PD_131			5
+#define AR5K_GAIN_PARAM_PD_130			6
+#define AR5K_GAIN_CHECK_ADJUST(_g) 		\
+	((_g)->g_current <= (_g)->g_low || (_g)->g_current >= (_g)->g_high)
+
+struct ath5k_gain_opt_step {
+	s16				gos_param[AR5K_GAIN_CRN_MAX_FIX_BITS];
+	s32				gos_gain;
+};
+
+struct ath5k_gain {
+	u32			g_step_idx;
+	u32			g_current;
+	u32			g_target;
+	u32			g_low;
+	u32			g_high;
+	u32			g_f_corr;
+	u32			g_active;
+	const struct ath5k_gain_opt_step	*g_step;
+};
+
+
 /********************\
   COMMON DEFINITIONS
 \********************/
 
-/*
- * Atheros hardware descriptor
- * This is read and written to by the hardware
- */
-struct ath5k_desc {
-	u32	ds_link;	/* physical address of the next descriptor */
-	u32	ds_data;	/* physical address of data buffer (skb) */
-
-	union {
-		struct ath5k_hw_5210_tx_desc	ds_tx5210;
-		struct ath5k_hw_5212_tx_desc	ds_tx5212;
-		struct ath5k_hw_all_rx_desc	ds_rx;
-	} ud;
-} __packed;
-
-#define AR5K_RXDESC_INTREQ	0x0020
-
-#define AR5K_TXDESC_CLRDMASK	0x0001
-#define AR5K_TXDESC_NOACK	0x0002	/*[5211+]*/
-#define AR5K_TXDESC_RTSENA	0x0004
-#define AR5K_TXDESC_CTSENA	0x0008
-#define AR5K_TXDESC_INTREQ	0x0010
-#define AR5K_TXDESC_VEOL	0x0020	/*[5211+]*/
-
 #define AR5K_SLOT_TIME_9	396
 #define AR5K_SLOT_TIME_20	880
 #define AR5K_SLOT_TIME_MAX	0xffff
@@ -553,167 +723,79 @@
 #define CHANNEL_MODES		CHANNEL_ALL
 
 /*
- * Used internaly in OpenHAL (ar5211.c/ar5212.c
- * for reset_tx_queue). Also see struct struct ieee80211_channel.
+ * Used internaly for reset_tx_queue).
+ * Also see struct struct ieee80211_channel.
  */
 #define IS_CHAN_XR(_c)	((_c.hw_value & CHANNEL_XR) != 0)
 #define IS_CHAN_B(_c)	((_c.hw_value & CHANNEL_B) != 0)
 
 /*
- * The following structure will be used to map 2GHz channels to
+ * The following structure is used to map 2GHz channels to
  * 5GHz Atheros channels.
+ * TODO: Clean up
  */
 struct ath5k_athchan_2ghz {
 	u32	a2_flags;
 	u16	a2_athchan;
 };
 
-/*
- * Rate definitions
- * TODO: Clean them up or move them on mac80211 -most of these infos are
- * 	 used by the rate control algorytm on MadWiFi.
- */
 
-/* Max number of rates on the rate table and what it seems
- * Atheros hardware supports */
-#define AR5K_MAX_RATES 32
+/******************\
+  RATE DEFINITIONS
+\******************/
 
 /**
- * struct ath5k_rate - rate structure
- * @valid: is this a valid rate for rate control (remove)
- * @modulation: respective mac80211 modulation
- * @rate_kbps: rate in kbit/s
- * @rate_code: hardware rate value, used in &struct ath5k_desc, on RX on
- *     &struct ath5k_rx_status.rs_rate and on TX on
- *     &struct ath5k_tx_status.ts_rate. Seems the ar5xxx harware supports
- *     up to 32 rates, indexed by 1-32. This means we really only need
- *     6 bits for the rate_code.
- * @dot11_rate: respective IEEE-802.11 rate value
- * @control_rate: index of rate assumed to be used to send control frames.
- *     This can be used to set override the value on the rate duration
- *     registers. This is only useful if we can override in the harware at
- *     what rate we want to send control frames at. Note that IEEE-802.11
- *     Ch. 9.6 (after IEEE 802.11g changes) defines the rate at which we
- *     should send ACK/CTS, if we change this value we can be breaking
- *     the spec.
+ * Seems the ar5xxx harware supports up to 32 rates, indexed by 1-32.
  *
- * This structure is used to get the RX rate or set the TX rate on the
+ * The rate code is used to get the RX rate or set the TX rate on the
  * hardware descriptors. It is also used for internal modulation control
  * and settings.
  *
- * On RX after the &struct ath5k_desc is parsed by the appropriate
- * ah_proc_rx_desc() the respective hardware rate value is set in
- * &struct ath5k_rx_status.rs_rate. On TX the desired rate is set in
- * &struct ath5k_tx_status.ts_rate which is later used to setup the
- * &struct ath5k_desc correctly. This is the hardware rate map we are
- * aware of:
+ * This is the hardware rate map we are aware of:
  *
- * rate_code   1       2       3       4       5       6       7       8
+ * rate_code   0x01    0x02    0x03    0x04    0x05    0x06    0x07    0x08
  * rate_kbps   3000    1000    ?       ?       ?       2000    500     48000
  *
- * rate_code   9       10      11      12      13      14      15      16
+ * rate_code   0x09    0x0A    0x0B    0x0C    0x0D    0x0E    0x0F    0x10
  * rate_kbps   24000   12000   6000    54000   36000   18000   9000    ?
  *
  * rate_code   17      18      19      20      21      22      23      24
  * rate_kbps   ?       ?       ?       ?       ?       ?       ?       11000
  *
  * rate_code   25      26      27      28      29      30      31      32
- * rate_kbps   5500    2000    1000    ?       ?       ?       ?       ?
+ * rate_kbps   5500    2000    1000    11000S  5500S   2000S   ?       ?
  *
+ * "S" indicates CCK rates with short preamble.
+ *
+ * AR5211 has different rate codes for CCK (802.11B) rates. It only uses the
+ * lowest 4 bits, so they are the same as below with a 0xF mask.
+ * (0xB, 0xA, 0x9 and 0x8 for 1M, 2M, 5.5M and 11M).
+ * We handle this in ath5k_setup_bands().
  */
-struct ath5k_rate {
-	u8	valid;
-	u32	modulation;
-	u16	rate_kbps;
-	u8	rate_code;
-	u8	dot11_rate;
-	u8	control_rate;
-};
+#define AR5K_MAX_RATES 32
 
-/* XXX: GRR all this stuff to get leds blinking ??? (check out setcurmode) */
-struct ath5k_rate_table {
-	u16	rate_count;
-	u8	rate_code_to_index[AR5K_MAX_RATES];	/* Back-mapping */
-	struct ath5k_rate rates[AR5K_MAX_RATES];
-};
+/* B */
+#define ATH5K_RATE_CODE_1M	0x1B
+#define ATH5K_RATE_CODE_2M	0x1A
+#define ATH5K_RATE_CODE_5_5M	0x19
+#define ATH5K_RATE_CODE_11M	0x18
+/* A and G */
+#define ATH5K_RATE_CODE_6M	0x0B
+#define ATH5K_RATE_CODE_9M	0x0F
+#define ATH5K_RATE_CODE_12M	0x0A
+#define ATH5K_RATE_CODE_18M	0x0E
+#define ATH5K_RATE_CODE_24M	0x09
+#define ATH5K_RATE_CODE_36M	0x0D
+#define ATH5K_RATE_CODE_48M	0x08
+#define ATH5K_RATE_CODE_54M	0x0C
+/* XR */
+#define ATH5K_RATE_CODE_XR_500K	0x07
+#define ATH5K_RATE_CODE_XR_1M	0x02
+#define ATH5K_RATE_CODE_XR_2M	0x06
+#define ATH5K_RATE_CODE_XR_3M	0x01
 
-/*
- * Rate tables...
- * TODO: CLEAN THIS !!!
- */
-#define AR5K_RATES_11A { 8, {					\
-	255, 255, 255, 255, 255, 255, 255, 255, 6, 4, 2, 0,	\
-	7, 5, 3, 1, 255, 255, 255, 255, 255, 255, 255, 255,	\
-	255, 255, 255, 255, 255, 255, 255, 255 }, {		\
-	{ 1, 0, 6000, 11, 140, 0 },		\
-	{ 1, 0, 9000, 15, 18, 0 },		\
-	{ 1, 0, 12000, 10, 152, 2 },		\
-	{ 1, 0, 18000, 14, 36, 2 },		\
-	{ 1, 0, 24000, 9, 176, 4 },		\
-	{ 1, 0, 36000, 13, 72, 4 },		\
-	{ 1, 0, 48000, 8, 96, 4 },		\
-	{ 1, 0, 54000, 12, 108, 4 } }		\
-}
-
-#define AR5K_RATES_11B { 4, {						\
-	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,	\
-	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,	\
-	3, 2, 1, 0, 255, 255, 255, 255 }, {				\
-	{ 1, 0, 1000, 27, 130, 0 },	\
-	{ 1, IEEE80211_RATE_SHORT_PREAMBLE, 2000, 26, 132, 1 },	\
-	{ 1, IEEE80211_RATE_SHORT_PREAMBLE, 5500, 25, 139, 1 },	\
-	{ 1, IEEE80211_RATE_SHORT_PREAMBLE, 11000, 24, 150, 1 } }	\
-}
-
-#define AR5K_RATES_11G { 12, {					\
-	255, 255, 255, 255, 255, 255, 255, 255, 10, 8, 6, 4,	\
-	11, 9, 7, 5, 255, 255, 255, 255, 255, 255, 255, 255,	\
-	3, 2, 1, 0, 255, 255, 255, 255 }, {			\
-	{ 1, 0, 1000, 27, 2, 0 },		\
-	{ 1, IEEE80211_RATE_SHORT_PREAMBLE, 2000, 26, 4, 1 },		\
-	{ 1, IEEE80211_RATE_SHORT_PREAMBLE, 5500, 25, 11, 1 },		\
-	{ 1, IEEE80211_RATE_SHORT_PREAMBLE, 11000, 24, 22, 1 },	\
-	{ 0, 0, 6000, 11, 12, 4 },	\
-	{ 0, 0, 9000, 15, 18, 4 },	\
-	{ 1, 0, 12000, 10, 24, 6 },	\
-	{ 1, 0, 18000, 14, 36, 6 },	\
-	{ 1, 0, 24000, 9, 48, 8 },	\
-	{ 1, 0, 36000, 13, 72, 8 },	\
-	{ 1, 0, 48000, 8, 96, 8 },	\
-	{ 1, 0, 54000, 12, 108, 8 } }	\
-}
-
-#define AR5K_RATES_TURBO { 8, {					\
-	255, 255, 255, 255, 255, 255, 255, 255, 6, 4, 2, 0,	\
-	7, 5, 3, 1, 255, 255, 255, 255, 255, 255, 255, 255,	\
-	255, 255, 255, 255, 255, 255, 255, 255 }, {		\
-	{ 1, MODULATION_TURBO, 6000, 11, 140, 0 },	\
-	{ 1, MODULATION_TURBO, 9000, 15, 18, 0 },	\
-	{ 1, MODULATION_TURBO, 12000, 10, 152, 2 },	\
-	{ 1, MODULATION_TURBO, 18000, 14, 36, 2 },	\
-	{ 1, MODULATION_TURBO, 24000, 9, 176, 4 },	\
-	{ 1, MODULATION_TURBO, 36000, 13, 72, 4 },	\
-	{ 1, MODULATION_TURBO, 48000, 8, 96, 4 },	\
-	{ 1, MODULATION_TURBO, 54000, 12, 108, 4 } }	\
-}
-
-#define AR5K_RATES_XR { 12, {					\
-	255, 3, 1, 255, 255, 255, 2, 0, 10, 8, 6, 4,		\
-	11, 9, 7, 5, 255, 255, 255, 255, 255, 255, 255, 255,	\
-	255, 255, 255, 255, 255, 255, 255, 255 }, {		\
-	{ 1, MODULATION_XR, 500, 7, 129, 0 },		\
-	{ 1, MODULATION_XR, 1000, 2, 139, 1 },		\
-	{ 1, MODULATION_XR, 2000, 6, 150, 2 },		\
-	{ 1, MODULATION_XR, 3000, 1, 150, 3 },		\
-	{ 1, 0, 6000, 11, 140, 4 },	\
-	{ 1, 0, 9000, 15, 18, 4 },	\
-	{ 1, 0, 12000, 10, 152, 6 },	\
-	{ 1, 0, 18000, 14, 36, 6 },	\
-	{ 1, 0, 24000, 9, 176, 8 },	\
-	{ 1, 0, 36000, 13, 72, 8 },	\
-	{ 1, 0, 48000, 8, 96, 8 },	\
-	{ 1, 0, 54000, 12, 108, 8 } }	\
-}
+/* adding this flag to rate_code enables short preamble */
+#define AR5K_SET_SHORT_PREAMBLE 0x04
 
 /*
  * Crypto definitions
@@ -735,7 +817,6 @@
 		return (false);			\
 } while (0)
 
-
 enum ath5k_ant_setting {
 	AR5K_ANT_VARIABLE	= 0,	/* variable by programming */
 	AR5K_ANT_FIXED_A	= 1,	/* fixed to 11a frequencies */
@@ -846,7 +927,8 @@
 
 /*
  * These match net80211 definitions (not used in
- * d80211).
+ * mac80211).
+ * TODO: Clean this up
  */
 #define AR5K_LED_INIT	0 /*IEEE80211_S_INIT*/
 #define AR5K_LED_SCAN	1 /*IEEE80211_S_SCAN*/
@@ -862,7 +944,8 @@
 /*
  * Chipset capabilities -see ath5k_hw_get_capability-
  * get_capability function is not yet fully implemented
- * in OpenHAL so most of these don't work yet...
+ * in ath5k so most of these don't work yet...
+ * TODO: Implement these & merge with _TUNE_ stuff above
  */
 enum ath5k_capability_type {
 	AR5K_CAP_REG_DMN		= 0,	/* Used to get current reg. domain id */
@@ -931,6 +1014,7 @@
 #define AR5K_MAX_GPIO		10
 #define AR5K_MAX_RF_BANKS	8
 
+/* TODO: Clean up and merge with ath5k_softc */
 struct ath5k_hw {
 	u32			ah_magic;
 
@@ -939,7 +1023,7 @@
 
 	enum ath5k_int		ah_imr;
 
-	enum ieee80211_if_types	ah_op_mode;
+	enum nl80211_iftype	ah_op_mode;
 	enum ath5k_power_mode	ah_power_mode;
 	struct ieee80211_channel ah_current_channel;
 	bool			ah_turbo;
@@ -1023,11 +1107,13 @@
 	/*
 	 * Function pointers
 	 */
+	int (*ah_setup_rx_desc)(struct ath5k_hw *ah, struct ath5k_desc *desc,
+				u32 size, unsigned int flags);
 	int (*ah_setup_tx_desc)(struct ath5k_hw *, struct ath5k_desc *,
 		unsigned int, unsigned int, enum ath5k_pkt_type, unsigned int,
 		unsigned int, unsigned int, unsigned int, unsigned int,
 		unsigned int, unsigned int, unsigned int);
-	int (*ah_setup_xtx_desc)(struct ath5k_hw *, struct ath5k_desc *,
+	int (*ah_setup_mrr_tx_desc)(struct ath5k_hw *, struct ath5k_desc *,
 		unsigned int, unsigned int, unsigned int, unsigned int,
 		unsigned int, unsigned int);
 	int (*ah_proc_tx_desc)(struct ath5k_hw *, struct ath5k_desc *,
@@ -1040,33 +1126,38 @@
  * Prototypes
  */
 
-/* General Functions */
-extern int ath5k_hw_register_timeout(struct ath5k_hw *ah, u32 reg, u32 flag, u32 val, bool is_set);
 /* Attach/Detach Functions */
 extern struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version);
-extern const struct ath5k_rate_table *ath5k_hw_get_rate_table(struct ath5k_hw *ah, unsigned int mode);
 extern void ath5k_hw_detach(struct ath5k_hw *ah);
+
 /* Reset Functions */
-extern int ath5k_hw_reset(struct ath5k_hw *ah, enum ieee80211_if_types op_mode, struct ieee80211_channel *channel, bool change_channel);
+extern int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial);
+extern int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode, struct ieee80211_channel *channel, bool change_channel);
 /* Power management functions */
 extern int ath5k_hw_set_power(struct ath5k_hw *ah, enum ath5k_power_mode mode, bool set_chip, u16 sleep_duration);
+
 /* DMA Related Functions */
-extern void ath5k_hw_start_rx(struct ath5k_hw *ah);
+extern void ath5k_hw_start_rx_dma(struct ath5k_hw *ah);
 extern int ath5k_hw_stop_rx_dma(struct ath5k_hw *ah);
-extern u32 ath5k_hw_get_rx_buf(struct ath5k_hw *ah);
-extern void ath5k_hw_put_rx_buf(struct ath5k_hw *ah, u32 phys_addr);
-extern int ath5k_hw_tx_start(struct ath5k_hw *ah, unsigned int queue);
+extern u32 ath5k_hw_get_rxdp(struct ath5k_hw *ah);
+extern void ath5k_hw_set_rxdp(struct ath5k_hw *ah, u32 phys_addr);
+extern int ath5k_hw_start_tx_dma(struct ath5k_hw *ah, unsigned int queue);
 extern int ath5k_hw_stop_tx_dma(struct ath5k_hw *ah, unsigned int queue);
-extern u32 ath5k_hw_get_tx_buf(struct ath5k_hw *ah, unsigned int queue);
-extern int ath5k_hw_put_tx_buf(struct ath5k_hw *ah, unsigned int queue, u32 phys_addr);
+extern u32 ath5k_hw_get_txdp(struct ath5k_hw *ah, unsigned int queue);
+extern int ath5k_hw_set_txdp(struct ath5k_hw *ah, unsigned int queue,
+				u32 phys_addr);
 extern int ath5k_hw_update_tx_triglevel(struct ath5k_hw *ah, bool increase);
 /* Interrupt handling */
 extern bool ath5k_hw_is_intr_pending(struct ath5k_hw *ah);
 extern int ath5k_hw_get_isr(struct ath5k_hw *ah, enum ath5k_int *interrupt_mask);
-extern enum ath5k_int ath5k_hw_set_intr(struct ath5k_hw *ah, enum ath5k_int new_mask);
+extern enum ath5k_int ath5k_hw_set_imr(struct ath5k_hw *ah, enum
+ath5k_int new_mask);
 extern void ath5k_hw_update_mib_counters(struct ath5k_hw *ah, struct ieee80211_low_level_stats *stats);
+
 /* EEPROM access functions */
-extern int ath5k_hw_set_regdomain(struct ath5k_hw *ah, u16 regdomain);
+extern int ath5k_eeprom_init(struct ath5k_hw *ah);
+extern int ath5k_eeprom_read_mac(struct ath5k_hw *ah, u8 *mac);
+
 /* Protocol Control Unit Functions */
 extern int ath5k_hw_set_opmode(struct ath5k_hw *ah);
 /* BSSID Functions */
@@ -1076,14 +1167,14 @@
 extern int ath5k_hw_set_bssid_mask(struct ath5k_hw *ah, const u8 *mask);
 /* Receive start/stop functions */
 extern void ath5k_hw_start_rx_pcu(struct ath5k_hw *ah);
-extern void ath5k_hw_stop_pcu_recv(struct ath5k_hw *ah);
+extern void ath5k_hw_stop_rx_pcu(struct ath5k_hw *ah);
 /* RX Filter functions */
 extern void ath5k_hw_set_mcast_filter(struct ath5k_hw *ah, u32 filter0, u32 filter1);
-extern int ath5k_hw_set_mcast_filterindex(struct ath5k_hw *ah, u32 index);
+extern int ath5k_hw_set_mcast_filter_idx(struct ath5k_hw *ah, u32 index);
 extern int ath5k_hw_clear_mcast_filter_idx(struct ath5k_hw *ah, u32 index);
 extern u32 ath5k_hw_get_rx_filter(struct ath5k_hw *ah);
 extern void ath5k_hw_set_rx_filter(struct ath5k_hw *ah, u32 filter);
-/* Beacon related functions */
+/* Beacon control functions */
 extern u32 ath5k_hw_get_tsf32(struct ath5k_hw *ah);
 extern u64 ath5k_hw_get_tsf64(struct ath5k_hw *ah);
 extern void ath5k_hw_reset_tsf(struct ath5k_hw *ah);
@@ -1105,61 +1196,129 @@
 extern int ath5k_hw_is_key_valid(struct ath5k_hw *ah, u16 entry);
 extern int ath5k_hw_set_key(struct ath5k_hw *ah, u16 entry, const struct ieee80211_key_conf *key, const u8 *mac);
 extern int ath5k_hw_set_key_lladdr(struct ath5k_hw *ah, u16 entry, const u8 *mac);
+
 /* Queue Control Unit, DFS Control Unit Functions */
-extern int ath5k_hw_setup_tx_queue(struct ath5k_hw *ah, enum ath5k_tx_queue queue_type, struct ath5k_txq_info *queue_info);
-extern int ath5k_hw_setup_tx_queueprops(struct ath5k_hw *ah, int queue, const struct ath5k_txq_info *queue_info);
 extern int ath5k_hw_get_tx_queueprops(struct ath5k_hw *ah, int queue, struct ath5k_txq_info *queue_info);
+extern int ath5k_hw_set_tx_queueprops(struct ath5k_hw *ah, int queue,
+				const struct ath5k_txq_info *queue_info);
+extern int ath5k_hw_setup_tx_queue(struct ath5k_hw *ah,
+				enum ath5k_tx_queue queue_type,
+				struct ath5k_txq_info *queue_info);
+extern u32 ath5k_hw_num_tx_pending(struct ath5k_hw *ah, unsigned int queue);
 extern void ath5k_hw_release_tx_queue(struct ath5k_hw *ah, unsigned int queue);
 extern int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue);
-extern u32 ath5k_hw_num_tx_pending(struct ath5k_hw *ah, unsigned int queue);
-extern int ath5k_hw_set_slot_time(struct ath5k_hw *ah, unsigned int slot_time);
 extern unsigned int ath5k_hw_get_slot_time(struct ath5k_hw *ah);
+extern int ath5k_hw_set_slot_time(struct ath5k_hw *ah, unsigned int slot_time);
+
 /* Hardware Descriptor Functions */
-extern int ath5k_hw_setup_rx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc, u32 size, unsigned int flags);
+extern int ath5k_hw_init_desc_functions(struct ath5k_hw *ah);
+
 /* GPIO Functions */
 extern void ath5k_hw_set_ledstate(struct ath5k_hw *ah, unsigned int state);
-extern int ath5k_hw_set_gpio_output(struct ath5k_hw *ah, u32 gpio);
 extern int ath5k_hw_set_gpio_input(struct ath5k_hw *ah, u32 gpio);
+extern int ath5k_hw_set_gpio_output(struct ath5k_hw *ah, u32 gpio);
 extern u32 ath5k_hw_get_gpio(struct ath5k_hw *ah, u32 gpio);
 extern int ath5k_hw_set_gpio(struct ath5k_hw *ah, u32 gpio, u32 val);
 extern void ath5k_hw_set_gpio_intr(struct ath5k_hw *ah, unsigned int gpio, u32 interrupt_level);
-/* Misc functions */
-extern int ath5k_hw_get_capability(struct ath5k_hw *ah, enum ath5k_capability_type cap_type, u32 capability, u32 *result);
 
+/* Misc functions */
+int ath5k_hw_set_capabilities(struct ath5k_hw *ah);
+extern int ath5k_hw_get_capability(struct ath5k_hw *ah, enum ath5k_capability_type cap_type, u32 capability, u32 *result);
+extern int ath5k_hw_enable_pspoll(struct ath5k_hw *ah, u8 *bssid, u16 assoc_id);
+extern int ath5k_hw_disable_pspoll(struct ath5k_hw *ah);
 
 /* Initial register settings functions */
 extern int ath5k_hw_write_initvals(struct ath5k_hw *ah, u8 mode, bool change_channel);
+
 /* Initialize RF */
 extern int ath5k_hw_rfregs(struct ath5k_hw *ah, struct ieee80211_channel *channel, unsigned int mode);
 extern int ath5k_hw_rfgain(struct ath5k_hw *ah, unsigned int freq);
 extern enum ath5k_rfgain ath5k_hw_get_rf_gain(struct ath5k_hw *ah);
 extern int ath5k_hw_set_rfgain_opt(struct ath5k_hw *ah);
-
-
 /* PHY/RF channel functions */
 extern bool ath5k_channel_ok(struct ath5k_hw *ah, u16 freq, unsigned int flags);
 extern int ath5k_hw_channel(struct ath5k_hw *ah, struct ieee80211_channel *channel);
 /* PHY calibration */
 extern int ath5k_hw_phy_calibrate(struct ath5k_hw *ah, struct ieee80211_channel *channel);
-extern int ath5k_hw_phy_disable(struct ath5k_hw *ah);
+extern int ath5k_hw_noise_floor_calibration(struct ath5k_hw *ah, short freq);
 /* Misc PHY functions */
 extern u16 ath5k_hw_radio_revision(struct ath5k_hw *ah, unsigned int chan);
 extern void ath5k_hw_set_def_antenna(struct ath5k_hw *ah, unsigned int ant);
 extern unsigned int ath5k_hw_get_def_antenna(struct ath5k_hw *ah);
-extern int ath5k_hw_noise_floor_calibration(struct ath5k_hw *ah, short freq);
+extern int ath5k_hw_phy_disable(struct ath5k_hw *ah);
 /* TX power setup */
 extern int ath5k_hw_txpower(struct ath5k_hw *ah, struct ieee80211_channel *channel, unsigned int txpower);
 extern int ath5k_hw_set_txpower_limit(struct ath5k_hw *ah, unsigned int power);
 
+/*
+ * Functions used internaly
+ */
 
+/*
+ * Translate usec to hw clock units
+ */
+static inline unsigned int ath5k_hw_htoclock(unsigned int usec, bool turbo)
+{
+	return turbo ? (usec * 80) : (usec * 40);
+}
+
+/*
+ * Translate hw clock units to usec
+ */
+static inline unsigned int ath5k_hw_clocktoh(unsigned int clock, bool turbo)
+{
+	return turbo ? (clock / 80) : (clock / 40);
+}
+
+/*
+ * Read from a register
+ */
 static inline u32 ath5k_hw_reg_read(struct ath5k_hw *ah, u16 reg)
 {
 	return ioread32(ah->ah_iobase + reg);
 }
 
+/*
+ * Write to a register
+ */
 static inline void ath5k_hw_reg_write(struct ath5k_hw *ah, u32 val, u16 reg)
 {
 	iowrite32(val, ah->ah_iobase + reg);
 }
 
+#if defined(_ATH5K_RESET) || defined(_ATH5K_PHY)
+/*
+ * Check if a register write has been completed
+ */
+static int ath5k_hw_register_timeout(struct ath5k_hw *ah, u32 reg, u32 flag,
+		u32 val, bool is_set)
+{
+	int i;
+	u32 data;
+
+	for (i = AR5K_TUNE_REGISTER_TIMEOUT; i > 0; i--) {
+		data = ath5k_hw_reg_read(ah, reg);
+		if (is_set && (data & flag))
+			break;
+		else if ((data & flag) == val)
+			break;
+		udelay(15);
+	}
+
+	return (i <= 0) ? -EAGAIN : 0;
+}
+#endif
+
+static inline u32 ath5k_hw_bitswap(u32 val, unsigned int bits)
+{
+	u32 retval = 0, bit, i;
+
+	for (i = 0; i < bits; i++) {
+		bit = (val >> i) & 1;
+		retval = (retval << 1) | bit;
+	}
+
+	return retval;
+}
+
 #endif
diff --git a/drivers/net/wireless/ath5k/attach.c b/drivers/net/wireless/ath5k/attach.c
new file mode 100644
index 0000000..51d5698
--- /dev/null
+++ b/drivers/net/wireless/ath5k/attach.c
@@ -0,0 +1,359 @@
+/*
+ * Copyright (c) 2004-2008 Reyk Floeter <reyk@openbsd.org>
+ * Copyright (c) 2006-2008 Nick Kossifidis <mickflemm@gmail.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+/*************************************\
+* Attach/Detach Functions and helpers *
+\*************************************/
+
+#include <linux/pci.h>
+#include "ath5k.h"
+#include "reg.h"
+#include "debug.h"
+#include "base.h"
+
+/**
+ * ath5k_hw_post - Power On Self Test helper function
+ *
+ * @ah: The &struct ath5k_hw
+ */
+static int ath5k_hw_post(struct ath5k_hw *ah)
+{
+
+	int i, c;
+	u16 cur_reg;
+	u16 regs[2] = {AR5K_STA_ID0, AR5K_PHY(8)};
+	u32 var_pattern;
+	u32 static_pattern[4] = {
+		0x55555555,	0xaaaaaaaa,
+		0x66666666,	0x99999999
+	};
+	u32 init_val;
+	u32 cur_val;
+
+	for (c = 0; c < 2; c++) {
+
+		cur_reg = regs[c];
+
+		/* Save previous value */
+		init_val = ath5k_hw_reg_read(ah, cur_reg);
+
+		for (i = 0; i < 256; i++) {
+			var_pattern = i << 16 | i;
+			ath5k_hw_reg_write(ah, var_pattern, cur_reg);
+			cur_val = ath5k_hw_reg_read(ah, cur_reg);
+
+			if (cur_val != var_pattern) {
+				ATH5K_ERR(ah->ah_sc, "POST Failed !!!\n");
+				return -EAGAIN;
+			}
+
+			/* Found on ndiswrapper dumps */
+			var_pattern = 0x0039080f;
+			ath5k_hw_reg_write(ah, var_pattern, cur_reg);
+		}
+
+		for (i = 0; i < 4; i++) {
+			var_pattern = static_pattern[i];
+			ath5k_hw_reg_write(ah, var_pattern, cur_reg);
+			cur_val = ath5k_hw_reg_read(ah, cur_reg);
+
+			if (cur_val != var_pattern) {
+				ATH5K_ERR(ah->ah_sc, "POST Failed !!!\n");
+				return -EAGAIN;
+			}
+
+			/* Found on ndiswrapper dumps */
+			var_pattern = 0x003b080f;
+			ath5k_hw_reg_write(ah, var_pattern, cur_reg);
+		}
+
+		/* Restore previous value */
+		ath5k_hw_reg_write(ah, init_val, cur_reg);
+
+	}
+
+	return 0;
+
+}
+
+/**
+ * ath5k_hw_attach - Check if hw is supported and init the needed structs
+ *
+ * @sc: The &struct ath5k_softc we got from the driver's attach function
+ * @mac_version: The mac version id (check out ath5k.h) based on pci id
+ *
+ * Check if the device is supported, perform a POST and initialize the needed
+ * structs. Returns -ENOMEM if we don't have memory for the needed structs,
+ * -ENODEV if the device is not supported or prints an error msg if something
+ * else went wrong.
+ */
+struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version)
+{
+	struct ath5k_hw *ah;
+	struct pci_dev *pdev = sc->pdev;
+	u8 mac[ETH_ALEN];
+	int ret;
+	u32 srev;
+
+	/*If we passed the test malloc a ath5k_hw struct*/
+	ah = kzalloc(sizeof(struct ath5k_hw), GFP_KERNEL);
+	if (ah == NULL) {
+		ret = -ENOMEM;
+		ATH5K_ERR(sc, "out of memory\n");
+		goto err;
+	}
+
+	ah->ah_sc = sc;
+	ah->ah_iobase = sc->iobase;
+
+	/*
+	 * HW information
+	 */
+	ah->ah_op_mode = NL80211_IFTYPE_STATION;
+	ah->ah_radar.r_enabled = AR5K_TUNE_RADAR_ALERT;
+	ah->ah_turbo = false;
+	ah->ah_txpower.txp_tpc = AR5K_TUNE_TPC_TXPOWER;
+	ah->ah_imr = 0;
+	ah->ah_atim_window = 0;
+	ah->ah_aifs = AR5K_TUNE_AIFS;
+	ah->ah_cw_min = AR5K_TUNE_CWMIN;
+	ah->ah_limit_tx_retries = AR5K_INIT_TX_RETRY;
+	ah->ah_software_retry = false;
+	ah->ah_ant_diversity = AR5K_TUNE_ANT_DIVERSITY;
+
+	/*
+	 * Set the mac version based on the pci id
+	 */
+	ah->ah_version = mac_version;
+
+	/*Fill the ath5k_hw struct with the needed functions*/
+	ret = ath5k_hw_init_desc_functions(ah);
+	if (ret)
+		goto err_free;
+
+	/* Bring device out of sleep and reset it's units */
+	ret = ath5k_hw_nic_wakeup(ah, CHANNEL_B, true);
+	if (ret)
+		goto err_free;
+
+	/* Get MAC, PHY and RADIO revisions */
+	srev = ath5k_hw_reg_read(ah, AR5K_SREV);
+	ah->ah_mac_srev = srev;
+	ah->ah_mac_version = AR5K_REG_MS(srev, AR5K_SREV_VER);
+	ah->ah_mac_revision = AR5K_REG_MS(srev, AR5K_SREV_REV);
+	ah->ah_phy_revision = ath5k_hw_reg_read(ah, AR5K_PHY_CHIP_ID) &
+			0xffffffff;
+	ah->ah_radio_5ghz_revision = ath5k_hw_radio_revision(ah,
+			CHANNEL_5GHZ);
+	ah->ah_phy = AR5K_PHY(0);
+
+	/* Try to identify radio chip based on it's srev */
+	switch (ah->ah_radio_5ghz_revision & 0xf0) {
+	case AR5K_SREV_RAD_5111:
+		ah->ah_radio = AR5K_RF5111;
+		ah->ah_single_chip = false;
+		ah->ah_radio_2ghz_revision = ath5k_hw_radio_revision(ah,
+							CHANNEL_2GHZ);
+		ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5111;
+		break;
+	case AR5K_SREV_RAD_5112:
+	case AR5K_SREV_RAD_2112:
+		ah->ah_radio = AR5K_RF5112;
+		ah->ah_single_chip = false;
+		ah->ah_radio_2ghz_revision = ath5k_hw_radio_revision(ah,
+							CHANNEL_2GHZ);
+		ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5112;
+		break;
+	case AR5K_SREV_RAD_2413:
+		ah->ah_radio = AR5K_RF2413;
+		ah->ah_single_chip = true;
+		ah->ah_phy_spending = AR5K_PHY_SPENDING_RF2413;
+		break;
+	case AR5K_SREV_RAD_5413:
+		ah->ah_radio = AR5K_RF5413;
+		ah->ah_single_chip = true;
+		ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5413;
+		break;
+	case AR5K_SREV_RAD_2316:
+		ah->ah_radio = AR5K_RF2316;
+		ah->ah_single_chip = true;
+		ah->ah_phy_spending = AR5K_PHY_SPENDING_RF2316;
+		break;
+	case AR5K_SREV_RAD_2317:
+		ah->ah_radio = AR5K_RF2317;
+		ah->ah_single_chip = true;
+		ah->ah_phy_spending = AR5K_PHY_SPENDING_RF2317;
+		break;
+	case AR5K_SREV_RAD_5424:
+		if (ah->ah_mac_version == AR5K_SREV_AR2425 ||
+		ah->ah_mac_version == AR5K_SREV_AR2417){
+			ah->ah_radio = AR5K_RF2425;
+			ah->ah_single_chip = true;
+			ah->ah_phy_spending = AR5K_PHY_SPENDING_RF2425;
+		} else {
+			ah->ah_radio = AR5K_RF5413;
+			ah->ah_single_chip = true;
+			ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5413;
+		}
+		break;
+	default:
+		/* Identify radio based on mac/phy srev */
+		if (ah->ah_version == AR5K_AR5210) {
+			ah->ah_radio = AR5K_RF5110;
+			ah->ah_single_chip = false;
+		} else if (ah->ah_version == AR5K_AR5211) {
+			ah->ah_radio = AR5K_RF5111;
+			ah->ah_single_chip = false;
+			ah->ah_radio_2ghz_revision = ath5k_hw_radio_revision(ah,
+								CHANNEL_2GHZ);
+		} else if (ah->ah_mac_version == (AR5K_SREV_AR2425 >> 4) ||
+		ah->ah_mac_version == (AR5K_SREV_AR2417 >> 4) ||
+		ah->ah_phy_revision == AR5K_SREV_PHY_2425) {
+			ah->ah_radio = AR5K_RF2425;
+			ah->ah_single_chip = true;
+			ah->ah_radio_5ghz_revision = AR5K_SREV_RAD_2425;
+			ah->ah_phy_spending = AR5K_PHY_SPENDING_RF2425;
+		} else if (srev == AR5K_SREV_AR5213A &&
+		ah->ah_phy_revision == AR5K_SREV_PHY_2112B) {
+			ah->ah_radio = AR5K_RF5112;
+			ah->ah_single_chip = false;
+			ah->ah_radio_5ghz_revision = AR5K_SREV_RAD_2112B;
+		} else if (ah->ah_mac_version == (AR5K_SREV_AR2415 >> 4)) {
+			ah->ah_radio = AR5K_RF2316;
+			ah->ah_single_chip = true;
+			ah->ah_radio_5ghz_revision = AR5K_SREV_RAD_2316;
+			ah->ah_phy_spending = AR5K_PHY_SPENDING_RF2316;
+		} else if (ah->ah_mac_version == (AR5K_SREV_AR5414 >> 4) ||
+		ah->ah_phy_revision == AR5K_SREV_PHY_5413) {
+			ah->ah_radio = AR5K_RF5413;
+			ah->ah_single_chip = true;
+			ah->ah_radio_5ghz_revision = AR5K_SREV_RAD_5413;
+			ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5413;
+		} else if (ah->ah_mac_version == (AR5K_SREV_AR2414 >> 4) ||
+		ah->ah_phy_revision == AR5K_SREV_PHY_2413) {
+			ah->ah_radio = AR5K_RF2413;
+			ah->ah_single_chip = true;
+			ah->ah_radio_5ghz_revision = AR5K_SREV_RAD_2413;
+			ah->ah_phy_spending = AR5K_PHY_SPENDING_RF2413;
+		} else {
+			ATH5K_ERR(sc, "Couldn't identify radio revision.\n");
+			ret = -ENODEV;
+			goto err_free;
+		}
+	}
+
+
+	/* Return on unsuported chips (unsupported eeprom etc) */
+	if ((srev >= AR5K_SREV_AR5416) &&
+	(srev < AR5K_SREV_AR2425)) {
+		ATH5K_ERR(sc, "Device not yet supported.\n");
+		ret = -ENODEV;
+		goto err_free;
+	}
+
+	/*
+	 * Write PCI-E power save settings
+	 */
+	if ((ah->ah_version == AR5K_AR5212) && (pdev->is_pcie)) {
+		ath5k_hw_reg_write(ah, 0x9248fc00, AR5K_PCIE_SERDES);
+		ath5k_hw_reg_write(ah, 0x24924924, AR5K_PCIE_SERDES);
+		/* Shut off RX when elecidle is asserted */
+		ath5k_hw_reg_write(ah, 0x28000039, AR5K_PCIE_SERDES);
+		ath5k_hw_reg_write(ah, 0x53160824, AR5K_PCIE_SERDES);
+		/* TODO: EEPROM work */
+		ath5k_hw_reg_write(ah, 0xe5980579, AR5K_PCIE_SERDES);
+		/* Shut off PLL and CLKREQ active in L1 */
+		ath5k_hw_reg_write(ah, 0x001defff, AR5K_PCIE_SERDES);
+		/* Preserce other settings */
+		ath5k_hw_reg_write(ah, 0x1aaabe40, AR5K_PCIE_SERDES);
+		ath5k_hw_reg_write(ah, 0xbe105554, AR5K_PCIE_SERDES);
+		ath5k_hw_reg_write(ah, 0x000e3007, AR5K_PCIE_SERDES);
+		/* Reset SERDES to load new settings */
+		ath5k_hw_reg_write(ah, 0x00000000, AR5K_PCIE_SERDES_RESET);
+		mdelay(1);
+	}
+
+	/*
+	 * POST
+	 */
+	ret = ath5k_hw_post(ah);
+	if (ret)
+		goto err_free;
+
+	/* Enable pci core retry fix on Hainan (5213A) and later chips */
+	if (srev >= AR5K_SREV_AR5213A)
+		ath5k_hw_reg_write(ah, AR5K_PCICFG_RETRY_FIX, AR5K_PCICFG);
+
+	/*
+	 * Get card capabilities, calibration values etc
+	 * TODO: EEPROM work
+	 */
+	ret = ath5k_eeprom_init(ah);
+	if (ret) {
+		ATH5K_ERR(sc, "unable to init EEPROM\n");
+		goto err_free;
+	}
+
+	/* Get misc capabilities */
+	ret = ath5k_hw_set_capabilities(ah);
+	if (ret) {
+		ATH5K_ERR(sc, "unable to get device capabilities: 0x%04x\n",
+			sc->pdev->device);
+		goto err_free;
+	}
+
+	/* Set MAC address */
+	ret = ath5k_eeprom_read_mac(ah, mac);
+	if (ret) {
+		ATH5K_ERR(sc, "unable to read address from EEPROM: 0x%04x\n",
+			sc->pdev->device);
+		goto err_free;
+	}
+
+	ath5k_hw_set_lladdr(ah, mac);
+	/* Set BSSID to bcast address: ff:ff:ff:ff:ff:ff for now */
+	memset(ah->ah_bssid, 0xff, ETH_ALEN);
+	ath5k_hw_set_associd(ah, ah->ah_bssid, 0);
+	ath5k_hw_set_opmode(ah);
+
+	ath5k_hw_set_rfgain_opt(ah);
+
+	return ah;
+err_free:
+	kfree(ah);
+err:
+	return ERR_PTR(ret);
+}
+
+/**
+ * ath5k_hw_detach - Free the ath5k_hw struct
+ *
+ * @ah: The &struct ath5k_hw
+ */
+void ath5k_hw_detach(struct ath5k_hw *ah)
+{
+	ATH5K_TRACE(ah->ah_sc);
+
+	__set_bit(ATH_STAT_INVALID, ah->ah_sc->status);
+
+	if (ah->ah_rf_banks != NULL)
+		kfree(ah->ah_rf_banks);
+
+	/* assume interrupts are down */
+	kfree(ah);
+}
diff --git a/drivers/net/wireless/ath5k/base.c b/drivers/net/wireless/ath5k/base.c
index 0676c6d..9b95c40 100644
--- a/drivers/net/wireless/ath5k/base.c
+++ b/drivers/net/wireless/ath5k/base.c
@@ -72,7 +72,7 @@
 MODULE_DESCRIPTION("Support for 5xxx series of Atheros 802.11 wireless LAN cards.");
 MODULE_SUPPORTED_DEVICE("Atheros 5xxx WLAN cards");
 MODULE_LICENSE("Dual BSD/GPL");
-MODULE_VERSION("0.5.0 (EXPERIMENTAL)");
+MODULE_VERSION("0.6.0 (EXPERIMENTAL)");
 
 
 /* Known PCI ids */
@@ -93,45 +93,94 @@
 	{ PCI_VDEVICE(ATHEROS, 0x0019), .driver_data = AR5K_AR5212 }, /* 5212 combatible */
 	{ PCI_VDEVICE(ATHEROS, 0x001a), .driver_data = AR5K_AR5212 }, /* 2413 Griffin-lite */
 	{ PCI_VDEVICE(ATHEROS, 0x001b), .driver_data = AR5K_AR5212 }, /* 5413 Eagle */
-	{ PCI_VDEVICE(ATHEROS, 0x001c), .driver_data = AR5K_AR5212 }, /* 5424 Condor (PCI-E)*/
+	{ PCI_VDEVICE(ATHEROS, 0x001c), .driver_data = AR5K_AR5212 }, /* PCI-E cards */
+	{ PCI_VDEVICE(ATHEROS, 0x001d), .driver_data = AR5K_AR5212 }, /* 2417 Nala */
 	{ 0 }
 };
 MODULE_DEVICE_TABLE(pci, ath5k_pci_id_table);
 
 /* Known SREVs */
 static struct ath5k_srev_name srev_names[] = {
-	{ "5210",	AR5K_VERSION_VER,	AR5K_SREV_VER_AR5210 },
-	{ "5311",	AR5K_VERSION_VER,	AR5K_SREV_VER_AR5311 },
-	{ "5311A",	AR5K_VERSION_VER,	AR5K_SREV_VER_AR5311A },
-	{ "5311B",	AR5K_VERSION_VER,	AR5K_SREV_VER_AR5311B },
-	{ "5211",	AR5K_VERSION_VER,	AR5K_SREV_VER_AR5211 },
-	{ "5212",	AR5K_VERSION_VER,	AR5K_SREV_VER_AR5212 },
-	{ "5213",	AR5K_VERSION_VER,	AR5K_SREV_VER_AR5213 },
-	{ "5213A",	AR5K_VERSION_VER,	AR5K_SREV_VER_AR5213A },
-	{ "2413",	AR5K_VERSION_VER,	AR5K_SREV_VER_AR2413 },
-	{ "2414",	AR5K_VERSION_VER,	AR5K_SREV_VER_AR2414 },
-	{ "2424",	AR5K_VERSION_VER,	AR5K_SREV_VER_AR2424 },
-	{ "5424",	AR5K_VERSION_VER,	AR5K_SREV_VER_AR5424 },
-	{ "5413",	AR5K_VERSION_VER,	AR5K_SREV_VER_AR5413 },
-	{ "5414",	AR5K_VERSION_VER,	AR5K_SREV_VER_AR5414 },
-	{ "5416",	AR5K_VERSION_VER,	AR5K_SREV_VER_AR5416 },
-	{ "5418",	AR5K_VERSION_VER,	AR5K_SREV_VER_AR5418 },
-	{ "2425",	AR5K_VERSION_VER,	AR5K_SREV_VER_AR2425 },
-	{ "xxxxx",	AR5K_VERSION_VER,	AR5K_SREV_UNKNOWN },
+	{ "5210",	AR5K_VERSION_MAC,	AR5K_SREV_AR5210 },
+	{ "5311",	AR5K_VERSION_MAC,	AR5K_SREV_AR5311 },
+	{ "5311A",	AR5K_VERSION_MAC,	AR5K_SREV_AR5311A },
+	{ "5311B",	AR5K_VERSION_MAC,	AR5K_SREV_AR5311B },
+	{ "5211",	AR5K_VERSION_MAC,	AR5K_SREV_AR5211 },
+	{ "5212",	AR5K_VERSION_MAC,	AR5K_SREV_AR5212 },
+	{ "5213",	AR5K_VERSION_MAC,	AR5K_SREV_AR5213 },
+	{ "5213A",	AR5K_VERSION_MAC,	AR5K_SREV_AR5213A },
+	{ "2413",	AR5K_VERSION_MAC,	AR5K_SREV_AR2413 },
+	{ "2414",	AR5K_VERSION_MAC,	AR5K_SREV_AR2414 },
+	{ "5424",	AR5K_VERSION_MAC,	AR5K_SREV_AR5424 },
+	{ "5413",	AR5K_VERSION_MAC,	AR5K_SREV_AR5413 },
+	{ "5414",	AR5K_VERSION_MAC,	AR5K_SREV_AR5414 },
+	{ "2415",	AR5K_VERSION_MAC,	AR5K_SREV_AR2415 },
+	{ "5416",	AR5K_VERSION_MAC,	AR5K_SREV_AR5416 },
+	{ "5418",	AR5K_VERSION_MAC,	AR5K_SREV_AR5418 },
+	{ "2425",	AR5K_VERSION_MAC,	AR5K_SREV_AR2425 },
+	{ "2417",	AR5K_VERSION_MAC,	AR5K_SREV_AR2417 },
+	{ "xxxxx",	AR5K_VERSION_MAC,	AR5K_SREV_UNKNOWN },
 	{ "5110",	AR5K_VERSION_RAD,	AR5K_SREV_RAD_5110 },
 	{ "5111",	AR5K_VERSION_RAD,	AR5K_SREV_RAD_5111 },
+	{ "5111A",	AR5K_VERSION_RAD,	AR5K_SREV_RAD_5111A },
 	{ "2111",	AR5K_VERSION_RAD,	AR5K_SREV_RAD_2111 },
 	{ "5112",	AR5K_VERSION_RAD,	AR5K_SREV_RAD_5112 },
 	{ "5112A",	AR5K_VERSION_RAD,	AR5K_SREV_RAD_5112A },
+	{ "5112B",	AR5K_VERSION_RAD,	AR5K_SREV_RAD_5112B },
 	{ "2112",	AR5K_VERSION_RAD,	AR5K_SREV_RAD_2112 },
 	{ "2112A",	AR5K_VERSION_RAD,	AR5K_SREV_RAD_2112A },
-	{ "SChip",	AR5K_VERSION_RAD,	AR5K_SREV_RAD_SC0 },
-	{ "SChip",	AR5K_VERSION_RAD,	AR5K_SREV_RAD_SC1 },
-	{ "SChip",	AR5K_VERSION_RAD,	AR5K_SREV_RAD_SC2 },
+	{ "2112B",	AR5K_VERSION_RAD,	AR5K_SREV_RAD_2112B },
+	{ "2413",	AR5K_VERSION_RAD,	AR5K_SREV_RAD_2413 },
+	{ "5413",	AR5K_VERSION_RAD,	AR5K_SREV_RAD_5413 },
+	{ "2316",	AR5K_VERSION_RAD,	AR5K_SREV_RAD_2316 },
+	{ "2317",	AR5K_VERSION_RAD,	AR5K_SREV_RAD_2317 },
+	{ "5424",	AR5K_VERSION_RAD,	AR5K_SREV_RAD_5424 },
 	{ "5133",	AR5K_VERSION_RAD,	AR5K_SREV_RAD_5133 },
 	{ "xxxxx",	AR5K_VERSION_RAD,	AR5K_SREV_UNKNOWN },
 };
 
+static struct ieee80211_rate ath5k_rates[] = {
+	{ .bitrate = 10,
+	  .hw_value = ATH5K_RATE_CODE_1M, },
+	{ .bitrate = 20,
+	  .hw_value = ATH5K_RATE_CODE_2M,
+	  .hw_value_short = ATH5K_RATE_CODE_2M | AR5K_SET_SHORT_PREAMBLE,
+	  .flags = IEEE80211_RATE_SHORT_PREAMBLE },
+	{ .bitrate = 55,
+	  .hw_value = ATH5K_RATE_CODE_5_5M,
+	  .hw_value_short = ATH5K_RATE_CODE_5_5M | AR5K_SET_SHORT_PREAMBLE,
+	  .flags = IEEE80211_RATE_SHORT_PREAMBLE },
+	{ .bitrate = 110,
+	  .hw_value = ATH5K_RATE_CODE_11M,
+	  .hw_value_short = ATH5K_RATE_CODE_11M | AR5K_SET_SHORT_PREAMBLE,
+	  .flags = IEEE80211_RATE_SHORT_PREAMBLE },
+	{ .bitrate = 60,
+	  .hw_value = ATH5K_RATE_CODE_6M,
+	  .flags = 0 },
+	{ .bitrate = 90,
+	  .hw_value = ATH5K_RATE_CODE_9M,
+	  .flags = 0 },
+	{ .bitrate = 120,
+	  .hw_value = ATH5K_RATE_CODE_12M,
+	  .flags = 0 },
+	{ .bitrate = 180,
+	  .hw_value = ATH5K_RATE_CODE_18M,
+	  .flags = 0 },
+	{ .bitrate = 240,
+	  .hw_value = ATH5K_RATE_CODE_24M,
+	  .flags = 0 },
+	{ .bitrate = 360,
+	  .hw_value = ATH5K_RATE_CODE_36M,
+	  .flags = 0 },
+	{ .bitrate = 480,
+	  .hw_value = ATH5K_RATE_CODE_48M,
+	  .flags = 0 },
+	{ .bitrate = 540,
+	  .hw_value = ATH5K_RATE_CODE_54M,
+	  .flags = 0 },
+	/* XR missing */
+};
+
 /*
  * Prototypes - PCI stack related functions
  */
@@ -162,7 +211,8 @@
  * Prototypes - MAC 802.11 stack related functions
  */
 static int ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb);
-static int ath5k_reset(struct ieee80211_hw *hw);
+static int ath5k_reset(struct ath5k_softc *sc, bool stop, bool change_channel);
+static int ath5k_reset_wake(struct ath5k_softc *sc);
 static int ath5k_start(struct ieee80211_hw *hw);
 static void ath5k_stop(struct ieee80211_hw *hw);
 static int ath5k_add_interface(struct ieee80211_hw *hw,
@@ -218,20 +268,16 @@
 			struct ieee80211_hw *hw);
 /* Channel/mode setup */
 static inline short ath5k_ieee2mhz(short chan);
-static unsigned int ath5k_copy_rates(struct ieee80211_rate *rates,
-				const struct ath5k_rate_table *rt,
-				unsigned int max);
 static unsigned int ath5k_copy_channels(struct ath5k_hw *ah,
 				struct ieee80211_channel *channels,
 				unsigned int mode,
 				unsigned int max);
-static int 	ath5k_getchannels(struct ieee80211_hw *hw);
+static int 	ath5k_setup_bands(struct ieee80211_hw *hw);
 static int 	ath5k_chan_set(struct ath5k_softc *sc,
 				struct ieee80211_channel *chan);
 static void	ath5k_setcurmode(struct ath5k_softc *sc,
 				unsigned int mode);
 static void	ath5k_mode_setup(struct ath5k_softc *sc);
-static void	ath5k_set_total_hw_rates(struct ath5k_softc *sc);
 
 /* Descriptor setup */
 static int	ath5k_desc_alloc(struct ath5k_softc *sc,
@@ -351,7 +397,11 @@
 	for (i = 0; i < ARRAY_SIZE(srev_names); i++) {
 		if (srev_names[i].sr_type != type)
 			continue;
-		if ((val & 0xff) < srev_names[i + 1].sr_val) {
+
+		if ((val & 0xf0) == srev_names[i].sr_val)
+			name = srev_names[i].sr_name;
+
+		if ((val & 0xff) == srev_names[i].sr_val) {
 			name = srev_names[i].sr_name;
 			break;
 		}
@@ -446,6 +496,12 @@
 	hw->flags = IEEE80211_HW_RX_INCLUDES_FCS |
 		    IEEE80211_HW_SIGNAL_DBM |
 		    IEEE80211_HW_NOISE_DBM;
+
+	hw->wiphy->interface_modes =
+		BIT(NL80211_IFTYPE_STATION) |
+		BIT(NL80211_IFTYPE_ADHOC) |
+		BIT(NL80211_IFTYPE_MESH_POINT);
+
 	hw->extra_tx_headroom = 2;
 	hw->channel_change_time = 5000;
 	sc = hw->priv;
@@ -462,7 +518,7 @@
 
 	sc->iobase = mem; /* So we can unmap it on detach */
 	sc->cachelsz = csz * sizeof(u32); /* convert to bytes */
-	sc->opmode = IEEE80211_IF_TYPE_STA;
+	sc->opmode = NL80211_IFTYPE_STATION;
 	mutex_init(&sc->lock);
 	spin_lock_init(&sc->rxbuflock);
 	spin_lock_init(&sc->txbuflock);
@@ -485,13 +541,19 @@
 		goto err_irq;
 	}
 
+	/* set up multi-rate retry capabilities */
+	if (sc->ah->ah_version == AR5K_AR5212) {
+		hw->max_altrates = 3;
+		hw->max_altrate_tries = 11;
+	}
+
 	/* Finish private driver data initialization */
 	ret = ath5k_attach(pdev, hw);
 	if (ret)
 		goto err_ah;
 
 	ATH5K_INFO(sc, "Atheros AR%s chip found (MAC: 0x%x, PHY: 0x%x)\n",
-			ath5k_chip_name(AR5K_VERSION_VER,sc->ah->ah_mac_srev),
+			ath5k_chip_name(AR5K_VERSION_MAC, sc->ah->ah_mac_srev),
 					sc->ah->ah_mac_srev,
 					sc->ah->ah_phy_revision);
 
@@ -646,7 +708,6 @@
 #endif /* CONFIG_PM */
 
 
-
 /***********************\
 * Driver Initialization *
 \***********************/
@@ -669,7 +730,7 @@
 	 * return false w/o doing anything.  MAC's that do
 	 * support it will return true w/o doing anything.
 	 */
-	ret = ah->ah_setup_xtx_desc(ah, NULL, 0, 0, 0, 0, 0, 0);
+	ret = ah->ah_setup_mrr_tx_desc(ah, NULL, 0, 0, 0, 0, 0, 0);
 	if (ret < 0)
 		goto err;
 	if (ret > 0)
@@ -688,15 +749,12 @@
 	 * on settings like the phy mode and regulatory
 	 * domain restrictions.
 	 */
-	ret = ath5k_getchannels(hw);
+	ret = ath5k_setup_bands(hw);
 	if (ret) {
 		ATH5K_ERR(sc, "can't get channels\n");
 		goto err;
 	}
 
-	/* Set *_rates so we can map hw rate index */
-	ath5k_set_total_hw_rates(sc);
-
 	/* NB: setup here so ath5k_rate_update is happy */
 	if (test_bit(AR5K_MODE_11A, ah->ah_modes))
 		ath5k_setcurmode(sc, AR5K_MODE_11A);
@@ -813,27 +871,6 @@
 }
 
 static unsigned int
-ath5k_copy_rates(struct ieee80211_rate *rates,
-		const struct ath5k_rate_table *rt,
-		unsigned int max)
-{
-	unsigned int i, count;
-
-	if (rt == NULL)
-		return 0;
-
-	for (i = 0, count = 0; i < rt->rate_count && max > 0; i++) {
-		rates[count].bitrate = rt->rates[i].rate_kbps / 100;
-		rates[count].hw_value = rt->rates[i].rate_code;
-		rates[count].flags = rt->rates[i].modulation;
-		count++;
-		max--;
-	}
-
-	return count;
-}
-
-static unsigned int
 ath5k_copy_channels(struct ath5k_hw *ah,
 		struct ieee80211_channel *channels,
 		unsigned int mode,
@@ -895,74 +932,97 @@
 	return count;
 }
 
+static void
+ath5k_setup_rate_idx(struct ath5k_softc *sc, struct ieee80211_supported_band *b)
+{
+	u8 i;
+
+	for (i = 0; i < AR5K_MAX_RATES; i++)
+		sc->rate_idx[b->band][i] = -1;
+
+	for (i = 0; i < b->n_bitrates; i++) {
+		sc->rate_idx[b->band][b->bitrates[i].hw_value] = i;
+		if (b->bitrates[i].hw_value_short)
+			sc->rate_idx[b->band][b->bitrates[i].hw_value_short] = i;
+	}
+}
+
 static int
-ath5k_getchannels(struct ieee80211_hw *hw)
+ath5k_setup_bands(struct ieee80211_hw *hw)
 {
 	struct ath5k_softc *sc = hw->priv;
 	struct ath5k_hw *ah = sc->ah;
-	struct ieee80211_supported_band *sbands = sc->sbands;
-	const struct ath5k_rate_table *hw_rates;
-	unsigned int max_r, max_c, count_r, count_c;
-	int mode2g = AR5K_MODE_11G;
+	struct ieee80211_supported_band *sband;
+	int max_c, count_c = 0;
+	int i;
 
 	BUILD_BUG_ON(ARRAY_SIZE(sc->sbands) < IEEE80211_NUM_BANDS);
-
-	max_r = ARRAY_SIZE(sc->rates);
 	max_c = ARRAY_SIZE(sc->channels);
-	count_r = count_c = 0;
 
 	/* 2GHz band */
-	if (!test_bit(AR5K_MODE_11G, sc->ah->ah_capabilities.cap_mode)) {
-		mode2g = AR5K_MODE_11B;
-		if (!test_bit(AR5K_MODE_11B,
-			sc->ah->ah_capabilities.cap_mode))
-			mode2g = -1;
-	}
+	sband = &sc->sbands[IEEE80211_BAND_2GHZ];
+	sband->band = IEEE80211_BAND_2GHZ;
+	sband->bitrates = &sc->rates[IEEE80211_BAND_2GHZ][0];
 
-	if (mode2g > 0) {
-		struct ieee80211_supported_band *sband =
-			&sbands[IEEE80211_BAND_2GHZ];
+	if (test_bit(AR5K_MODE_11G, sc->ah->ah_capabilities.cap_mode)) {
+		/* G mode */
+		memcpy(sband->bitrates, &ath5k_rates[0],
+		       sizeof(struct ieee80211_rate) * 12);
+		sband->n_bitrates = 12;
 
-		sband->bitrates = sc->rates;
 		sband->channels = sc->channels;
-
-		sband->band = IEEE80211_BAND_2GHZ;
 		sband->n_channels = ath5k_copy_channels(ah, sband->channels,
-					mode2g, max_c);
-
-		hw_rates = ath5k_hw_get_rate_table(ah, mode2g);
-		sband->n_bitrates = ath5k_copy_rates(sband->bitrates,
-					hw_rates, max_r);
-
-		count_c = sband->n_channels;
-		count_r = sband->n_bitrates;
+					AR5K_MODE_11G, max_c);
 
 		hw->wiphy->bands[IEEE80211_BAND_2GHZ] = sband;
-
-		max_r -= count_r;
+		count_c = sband->n_channels;
 		max_c -= count_c;
+	} else if (test_bit(AR5K_MODE_11B, sc->ah->ah_capabilities.cap_mode)) {
+		/* B mode */
+		memcpy(sband->bitrates, &ath5k_rates[0],
+		       sizeof(struct ieee80211_rate) * 4);
+		sband->n_bitrates = 4;
 
+		/* 5211 only supports B rates and uses 4bit rate codes
+		 * (e.g normally we have 0x1B for 1M, but on 5211 we have 0x0B)
+		 * fix them up here:
+		 */
+		if (ah->ah_version == AR5K_AR5211) {
+			for (i = 0; i < 4; i++) {
+				sband->bitrates[i].hw_value =
+					sband->bitrates[i].hw_value & 0xF;
+				sband->bitrates[i].hw_value_short =
+					sband->bitrates[i].hw_value_short & 0xF;
+			}
+		}
+
+		sband->channels = sc->channels;
+		sband->n_channels = ath5k_copy_channels(ah, sband->channels,
+					AR5K_MODE_11B, max_c);
+
+		hw->wiphy->bands[IEEE80211_BAND_2GHZ] = sband;
+		count_c = sband->n_channels;
+		max_c -= count_c;
 	}
+	ath5k_setup_rate_idx(sc, sband);
 
-	/* 5GHz band */
-
+	/* 5GHz band, A mode */
 	if (test_bit(AR5K_MODE_11A, sc->ah->ah_capabilities.cap_mode)) {
-		struct ieee80211_supported_band *sband =
-			&sbands[IEEE80211_BAND_5GHZ];
-
-		sband->bitrates = &sc->rates[count_r];
-		sband->channels = &sc->channels[count_c];
-
+		sband = &sc->sbands[IEEE80211_BAND_5GHZ];
 		sband->band = IEEE80211_BAND_5GHZ;
+		sband->bitrates = &sc->rates[IEEE80211_BAND_5GHZ][0];
+
+		memcpy(sband->bitrates, &ath5k_rates[4],
+		       sizeof(struct ieee80211_rate) * 8);
+		sband->n_bitrates = 8;
+
+		sband->channels = &sc->channels[count_c];
 		sband->n_channels = ath5k_copy_channels(ah, sband->channels,
 					AR5K_MODE_11A, max_c);
 
-		hw_rates = ath5k_hw_get_rate_table(ah, AR5K_MODE_11A);
-		sband->n_bitrates = ath5k_copy_rates(sband->bitrates,
-					hw_rates, max_r);
-
 		hw->wiphy->bands[IEEE80211_BAND_5GHZ] = sband;
 	}
+	ath5k_setup_rate_idx(sc, sband);
 
 	ath5k_debug_dump_bands(sc);
 
@@ -978,9 +1038,6 @@
 static int
 ath5k_chan_set(struct ath5k_softc *sc, struct ieee80211_channel *chan)
 {
-	struct ath5k_hw *ah = sc->ah;
-	int ret;
-
 	ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "(%u MHz) -> (%u MHz)\n",
 		sc->curchan->center_freq, chan->center_freq);
 
@@ -996,41 +1053,7 @@
 		 * hardware at the new frequency, and then re-enable
 		 * the relevant bits of the h/w.
 		 */
-		ath5k_hw_set_intr(ah, 0);	/* disable interrupts */
-		ath5k_txq_cleanup(sc);		/* clear pending tx frames */
-		ath5k_rx_stop(sc);		/* turn off frame recv */
-		ret = ath5k_hw_reset(ah, sc->opmode, sc->curchan, true);
-		if (ret) {
-			ATH5K_ERR(sc, "%s: unable to reset channel "
-				"(%u Mhz)\n", __func__, chan->center_freq);
-			return ret;
-		}
-
-		ath5k_hw_set_txpower_limit(sc->ah, 0);
-
-		/*
-		 * Re-enable rx framework.
-		 */
-		ret = ath5k_rx_start(sc);
-		if (ret) {
-			ATH5K_ERR(sc, "%s: unable to restart recv logic\n",
-					__func__);
-			return ret;
-		}
-
-		/*
-		 * Change channels and update the h/w rate map
-		 * if we're switching; e.g. 11a to 11b/g.
-		 *
-		 * XXX needed?
-		 */
-/*		ath5k_chan_change(sc, chan); */
-
-		ath5k_beacon_config(sc);
-		/*
-		 * Re-enable interrupts.
-		 */
-		ath5k_hw_set_intr(ah, sc->imask);
+		return ath5k_reset(sc, true, true);
 	}
 
 	return 0;
@@ -1068,75 +1091,13 @@
 	ATH5K_DBG(sc, ATH5K_DEBUG_MODE, "RX filter 0x%x\n", rfilt);
 }
 
-/*
- * Match the hw provided rate index (through descriptors)
- * to an index for sc->curband->bitrates, so it can be used
- * by the stack.
- *
- * This one is a little bit tricky but i think i'm right
- * about this...
- *
- * We have 4 rate tables in the following order:
- * XR (4 rates)
- * 802.11a (8 rates)
- * 802.11b (4 rates)
- * 802.11g (12 rates)
- * that make the hw rate table.
- *
- * Lets take a 5211 for example that supports a and b modes only.
- * First comes the 802.11a table and then 802.11b (total 12 rates).
- * When hw returns eg. 11 it points to the last 802.11b rate (11Mbit),
- * if it returns 2 it points to the second 802.11a rate etc.
- *
- * Same goes for 5212 who has xr/a/b/g support (total 28 rates).
- * First comes the XR table, then 802.11a, 802.11b and 802.11g.
- * When hw returns eg. 27 it points to the last 802.11g rate (54Mbits) etc
- */
-static void
-ath5k_set_total_hw_rates(struct ath5k_softc *sc) {
-
-	struct ath5k_hw *ah = sc->ah;
-
-	if (test_bit(AR5K_MODE_11A, ah->ah_modes))
-		sc->a_rates = 8;
-
-	if (test_bit(AR5K_MODE_11B, ah->ah_modes))
-		sc->b_rates = 4;
-
-	if (test_bit(AR5K_MODE_11G, ah->ah_modes))
-		sc->g_rates = 12;
-
-	/* XXX: Need to see what what happens when
-		xr disable bits in eeprom are set */
-	if (ah->ah_version >= AR5K_AR5212)
-		sc->xr_rates = 4;
-
-}
-
 static inline int
-ath5k_hw_to_driver_rix(struct ath5k_softc *sc, int hw_rix) {
-
-	int mac80211_rix;
-
-	if(sc->curband->band == IEEE80211_BAND_2GHZ) {
-		/* We setup a g ratetable for both b/g modes */
-		mac80211_rix =
-			hw_rix - sc->b_rates - sc->a_rates - sc->xr_rates;
-	} else {
-		mac80211_rix = hw_rix - sc->xr_rates;
-	}
-
-	/* Something went wrong, fallback to basic rate for this band */
-	if ((mac80211_rix >= sc->curband->n_bitrates) ||
-		(mac80211_rix <= 0 ))
-		mac80211_rix = 1;
-
-	return mac80211_rix;
+ath5k_hw_to_driver_rix(struct ath5k_softc *sc, int hw_rix)
+{
+	WARN_ON(hw_rix < 0 || hw_rix > AR5K_MAX_RATES);
+	return sc->rate_idx[sc->curband->band][hw_rix];
 }
 
-
-
-
 /***************\
 * Buffers setup *
 \***************/
@@ -1199,7 +1160,7 @@
 	ds = bf->desc;
 	ds->ds_link = bf->daddr;	/* link to self */
 	ds->ds_data = bf->skbaddr;
-	ath5k_hw_setup_rx_desc(ah, ds,
+	ah->ah_setup_rx_desc(ah, ds,
 		skb_tailroom(skb),	/* buffer size */
 		0);
 
@@ -1218,7 +1179,9 @@
 	struct sk_buff *skb = bf->skb;
 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
 	unsigned int pktlen, flags, keyidx = AR5K_TXKEYIX_INVALID;
-	int ret;
+	struct ieee80211_rate *rate;
+	unsigned int mrr_rate[3], mrr_tries[3];
+	int i, ret;
 
 	flags = AR5K_TXDESC_INTREQ | AR5K_TXDESC_CLRDMASK;
 
@@ -1233,7 +1196,7 @@
 
 	if (info->control.hw_key) {
 		keyidx = info->control.hw_key->hw_key_idx;
-		pktlen += info->control.icv_len;
+		pktlen += info->control.hw_key->icv_len;
 	}
 	ret = ah->ah_setup_tx_desc(ah, ds, pktlen,
 		ieee80211_get_hdrlen_from_skb(skb), AR5K_PKT_TYPE_NORMAL,
@@ -1243,6 +1206,22 @@
 	if (ret)
 		goto err_unmap;
 
+	memset(mrr_rate, 0, sizeof(mrr_rate));
+	memset(mrr_tries, 0, sizeof(mrr_tries));
+	for (i = 0; i < 3; i++) {
+		rate = ieee80211_get_alt_retry_rate(sc->hw, info, i);
+		if (!rate)
+			break;
+
+		mrr_rate[i] = rate->hw_value;
+		mrr_tries[i] = info->control.retries[i].limit;
+	}
+
+	ah->ah_setup_mrr_tx_desc(ah, ds,
+		mrr_rate[0], mrr_tries[0],
+		mrr_rate[1], mrr_tries[1],
+		mrr_rate[2], mrr_tries[2]);
+
 	ds->ds_link = 0;
 	ds->ds_data = bf->skbaddr;
 
@@ -1250,12 +1229,12 @@
 	list_add_tail(&bf->list, &txq->q);
 	sc->tx_stats[txq->qnum].len++;
 	if (txq->link == NULL) /* is this first packet? */
-		ath5k_hw_put_tx_buf(ah, txq->qnum, bf->daddr);
+		ath5k_hw_set_txdp(ah, txq->qnum, bf->daddr);
 	else /* no, so only link it */
 		*txq->link = bf->daddr;
 
 	txq->link = &ds->ds_link;
-	ath5k_hw_tx_start(ah, txq->qnum);
+	ath5k_hw_start_tx_dma(ah, txq->qnum);
 	mmiowb();
 	spin_unlock_bh(&txq->lock);
 
@@ -1433,7 +1412,8 @@
 	ret = ath5k_hw_get_tx_queueprops(ah, sc->bhalq, &qi);
 	if (ret)
 		return ret;
-	if (sc->opmode == IEEE80211_IF_TYPE_AP) {
+	if (sc->opmode == NL80211_IFTYPE_AP ||
+		sc->opmode == NL80211_IFTYPE_MESH_POINT) {
 		/*
 		 * Always burst out beacon and CAB traffic
 		 * (aifs = cwmin = cwmax = 0)
@@ -1441,7 +1421,7 @@
 		qi.tqi_aifs = 0;
 		qi.tqi_cw_min = 0;
 		qi.tqi_cw_max = 0;
-	} else if (sc->opmode == IEEE80211_IF_TYPE_IBSS) {
+	} else if (sc->opmode == NL80211_IFTYPE_ADHOC) {
 		/*
 		 * Adhoc mode; backoff between 0 and (2 * cw_min).
 		 */
@@ -1454,7 +1434,7 @@
 		"beacon queueprops tqi_aifs:%d tqi_cw_min:%d tqi_cw_max:%d\n",
 		qi.tqi_aifs, qi.tqi_cw_min, qi.tqi_cw_max);
 
-	ret = ath5k_hw_setup_tx_queueprops(ah, sc->bhalq, &qi);
+	ret = ath5k_hw_set_tx_queueprops(ah, sc->bhalq, &qi);
 	if (ret) {
 		ATH5K_ERR(sc, "%s: unable to update parameters for beacon "
 			"hardware queue!\n", __func__);
@@ -1503,14 +1483,14 @@
 		/* don't touch the hardware if marked invalid */
 		ath5k_hw_stop_tx_dma(ah, sc->bhalq);
 		ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "beacon queue %x\n",
-			ath5k_hw_get_tx_buf(ah, sc->bhalq));
+			ath5k_hw_get_txdp(ah, sc->bhalq));
 		for (i = 0; i < ARRAY_SIZE(sc->txqs); i++)
 			if (sc->txqs[i].setup) {
 				ath5k_hw_stop_tx_dma(ah, sc->txqs[i].qnum);
 				ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "txq [%u] %x, "
 					"link %p\n",
 					sc->txqs[i].qnum,
-					ath5k_hw_get_tx_buf(ah,
+					ath5k_hw_get_txdp(ah,
 							sc->txqs[i].qnum),
 					sc->txqs[i].link);
 			}
@@ -1570,8 +1550,8 @@
 	bf = list_first_entry(&sc->rxbuf, struct ath5k_buf, list);
 	spin_unlock_bh(&sc->rxbuflock);
 
-	ath5k_hw_put_rx_buf(ah, bf->daddr);
-	ath5k_hw_start_rx(ah);		/* enable recv descriptors */
+	ath5k_hw_set_rxdp(ah, bf->daddr);
+	ath5k_hw_start_rx_dma(ah);	/* enable recv descriptors */
 	ath5k_mode_setup(sc);		/* set filters, etc. */
 	ath5k_hw_start_rx_pcu(ah);	/* re-enable PCU/DMA engine */
 
@@ -1588,7 +1568,7 @@
 {
 	struct ath5k_hw *ah = sc->ah;
 
-	ath5k_hw_stop_pcu_recv(ah);	/* disable PCU */
+	ath5k_hw_stop_rx_pcu(ah);	/* disable PCU */
 	ath5k_hw_set_rx_filter(ah, 0);	/* clear recv filter */
 	ath5k_hw_stop_rx_dma(ah);	/* disable DMA engine */
 
@@ -1602,7 +1582,7 @@
 		struct sk_buff *skb, struct ath5k_rx_status *rs)
 {
 	struct ieee80211_hdr *hdr = (void *)skb->data;
-	unsigned int keyix, hlen = ieee80211_get_hdrlen_from_skb(skb);
+	unsigned int keyix, hlen;
 
 	if (!(rs->rs_status & AR5K_RXERR_DECRYPT) &&
 			rs->rs_keyix != AR5K_RXKEYIX_INVALID)
@@ -1611,6 +1591,7 @@
 	/* Apparently when a default key is used to decrypt the packet
 	   the hw does not set the index used to decrypt.  In such cases
 	   get the index from the packet. */
+	hlen = ieee80211_hdrlen(hdr->frame_control);
 	if (ieee80211_has_protected(hdr->frame_control) &&
 	    !(rs->rs_status & AR5K_RXERR_DECRYPT) &&
 	    skb->len >= hlen + 4) {
@@ -1768,7 +1749,7 @@
 			/* let crypto-error packets fall through in MNTR */
 			if ((rs.rs_status &
 				~(AR5K_RXERR_DECRYPT|AR5K_RXERR_MIC)) ||
-					sc->opmode != IEEE80211_IF_TYPE_MNTR)
+					sc->opmode != NL80211_IFTYPE_MONITOR)
 				goto next;
 		}
 accept:
@@ -1824,10 +1805,14 @@
 		rxs.rate_idx = ath5k_hw_to_driver_rix(sc, rs.rs_rate);
 		rxs.flag |= ath5k_rx_decrypted(sc, ds, skb, &rs);
 
+		if (rxs.rate_idx >= 0 && rs.rs_rate ==
+		    sc->curband->bitrates[rxs.rate_idx].hw_value_short)
+			rxs.flag |= RX_FLAG_SHORTPRE;
+
 		ath5k_debug_dump_skb(sc, skb, "RX  ", 0);
 
 		/* check beacons in IBSS mode */
-		if (sc->opmode == IEEE80211_IF_TYPE_IBSS)
+		if (sc->opmode == NL80211_IFTYPE_ADHOC)
 			ath5k_check_ibss_tsf(sc, skb, &rxs);
 
 		__ieee80211_rx(sc->hw, skb, &rxs);
@@ -1853,7 +1838,7 @@
 	struct ath5k_desc *ds;
 	struct sk_buff *skb;
 	struct ieee80211_tx_info *info;
-	int ret;
+	int i, ret;
 
 	spin_lock(&txq->lock);
 	list_for_each_entry_safe(bf, bf0, &txq->q, list) {
@@ -1875,7 +1860,25 @@
 		pci_unmap_single(sc->pdev, bf->skbaddr, skb->len,
 				PCI_DMA_TODEVICE);
 
-		info->status.retry_count = ts.ts_shortretry + ts.ts_longretry / 6;
+		memset(&info->status, 0, sizeof(info->status));
+		info->tx_rate_idx = ath5k_hw_to_driver_rix(sc,
+				ts.ts_rate[ts.ts_final_idx]);
+		info->status.retry_count = ts.ts_longretry;
+
+		for (i = 0; i < 4; i++) {
+			struct ieee80211_tx_altrate *r =
+				&info->status.retries[i];
+
+			if (ts.ts_rate[i]) {
+				r->rate_idx = ath5k_hw_to_driver_rix(sc, ts.ts_rate[i]);
+				r->limit = ts.ts_retry[i];
+			} else {
+				r->rate_idx = -1;
+				r->limit = 0;
+			}
+		}
+
+		info->status.excessive_retries = 0;
 		if (unlikely(ts.ts_status)) {
 			sc->ll_stats.dot11ACKFailureCount++;
 			if (ts.ts_status & AR5K_TXERR_XRETRY)
@@ -1942,7 +1945,7 @@
 	ds = bf->desc;
 
 	flags = AR5K_TXDESC_NOACK;
-	if (sc->opmode == IEEE80211_IF_TYPE_IBSS && ath5k_hw_hasveol(ah)) {
+	if (sc->opmode == NL80211_IFTYPE_ADHOC && ath5k_hw_hasveol(ah)) {
 		ds->ds_link = bf->daddr;	/* self-linked */
 		flags |= AR5K_TXDESC_VEOL;
 		/*
@@ -1991,8 +1994,8 @@
 
 	ATH5K_DBG_UNLIMIT(sc, ATH5K_DEBUG_BEACON, "in beacon_send\n");
 
-	if (unlikely(bf->skb == NULL || sc->opmode == IEEE80211_IF_TYPE_STA ||
-			sc->opmode == IEEE80211_IF_TYPE_MNTR)) {
+	if (unlikely(bf->skb == NULL || sc->opmode == NL80211_IFTYPE_STATION ||
+			sc->opmode == NL80211_IFTYPE_MONITOR)) {
 		ATH5K_WARN(sc, "bf=%p bf_skb=%p\n", bf, bf ? bf->skb : NULL);
 		return;
 	}
@@ -2032,8 +2035,8 @@
 		/* NB: hw still stops DMA, so proceed */
 	}
 
-	ath5k_hw_put_tx_buf(ah, sc->bhalq, bf->daddr);
-	ath5k_hw_tx_start(ah, sc->bhalq);
+	ath5k_hw_set_txdp(ah, sc->bhalq, bf->daddr);
+	ath5k_hw_start_tx_dma(ah, sc->bhalq);
 	ATH5K_DBG(sc, ATH5K_DEBUG_BEACON, "TXDP[%u] = %llx (%p)\n",
 		sc->bhalq, (unsigned long long)bf->daddr, bf->desc);
 
@@ -2162,13 +2165,13 @@
 {
 	struct ath5k_hw *ah = sc->ah;
 
-	ath5k_hw_set_intr(ah, 0);
+	ath5k_hw_set_imr(ah, 0);
 	sc->bmisscount = 0;
 	sc->imask &= ~(AR5K_INT_BMISS | AR5K_INT_SWBA);
 
-	if (sc->opmode == IEEE80211_IF_TYPE_STA) {
+	if (sc->opmode == NL80211_IFTYPE_STATION) {
 		sc->imask |= AR5K_INT_BMISS;
-	} else if (sc->opmode == IEEE80211_IF_TYPE_IBSS) {
+	} else if (sc->opmode == NL80211_IFTYPE_ADHOC) {
 		/*
 		 * In IBSS mode we use a self-linked tx descriptor and let the
 		 * hardware send the beacons automatically. We have to load it
@@ -2188,7 +2191,7 @@
 	}
 	/* TODO else AP */
 
-	ath5k_hw_set_intr(ah, sc->imask);
+	ath5k_hw_set_imr(ah, sc->imask);
 }
 
 
@@ -2220,36 +2223,13 @@
 	 */
 	sc->curchan = sc->hw->conf.channel;
 	sc->curband = &sc->sbands[sc->curchan->band];
-	ret = ath5k_hw_reset(sc->ah, sc->opmode, sc->curchan, false);
-	if (ret) {
-		ATH5K_ERR(sc, "unable to reset hardware: %d\n", ret);
-		goto done;
-	}
-	/*
-	 * This is needed only to setup initial state
-	 * but it's best done after a reset.
-	 */
-	ath5k_hw_set_txpower_limit(sc->ah, 0);
-
-	/*
-	 * Setup the hardware after reset: the key cache
-	 * is filled as needed and the receive engine is
-	 * set going.  Frame transmit is handled entirely
-	 * in the frame output path; there's nothing to do
-	 * here except setup the interrupt mask.
-	 */
-	ret = ath5k_rx_start(sc);
-	if (ret)
-		goto done;
-
-	/*
-	 * Enable interrupts.
-	 */
 	sc->imask = AR5K_INT_RX | AR5K_INT_TX | AR5K_INT_RXEOL |
 		AR5K_INT_RXORN | AR5K_INT_FATAL | AR5K_INT_GLOBAL |
 		AR5K_INT_MIB;
+	ret = ath5k_reset(sc, false, false);
+	if (ret)
+		goto done;
 
-	ath5k_hw_set_intr(sc->ah, sc->imask);
 	/* Set ack to be sent at low bit-rates */
 	ath5k_hw_set_ack_bitrate_high(sc->ah, false);
 
@@ -2290,7 +2270,7 @@
 
 	if (!test_bit(ATH_STAT_INVALID, sc->status)) {
 		ath5k_led_off(sc);
-		ath5k_hw_set_intr(ah, 0);
+		ath5k_hw_set_imr(ah, 0);
 		synchronize_irq(sc->pdev->irq);
 	}
 	ath5k_txq_cleanup(sc);
@@ -2396,7 +2376,7 @@
 				* transmission time) in order to detect wether
 				* automatic TSF updates happened.
 				*/
-				if (sc->opmode == IEEE80211_IF_TYPE_IBSS) {
+				if (sc->opmode == NL80211_IFTYPE_ADHOC) {
 					 /* XXX: only if VEOL suppported */
 					u64 tsf = ath5k_hw_get_tsf64(ah);
 					sc->nexttbtt += sc->bintval;
@@ -2451,7 +2431,7 @@
 {
 	struct ath5k_softc *sc = (void *)data;
 
-	ath5k_reset(sc->hw);
+	ath5k_reset_wake(sc);
 }
 
 /*
@@ -2474,7 +2454,7 @@
 		 * to load new gain values.
 		 */
 		ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "calibration, resetting\n");
-		ath5k_reset(sc->hw);
+		ath5k_reset_wake(sc);
 	}
 	if (ath5k_hw_phy_calibrate(ah, sc->curchan))
 		ATH5K_ERR(sc, "calibration of channel %u failed\n",
@@ -2626,7 +2606,7 @@
 
 	ath5k_debug_dump_skb(sc, skb, "TX  ", 1);
 
-	if (sc->opmode == IEEE80211_IF_TYPE_MNTR)
+	if (sc->opmode == NL80211_IFTYPE_MONITOR)
 		ATH5K_DBG(sc, ATH5K_DEBUG_XMIT, "tx in monitor (scan?)\n");
 
 	/*
@@ -2675,48 +2655,67 @@
 }
 
 static int
-ath5k_reset(struct ieee80211_hw *hw)
+ath5k_reset(struct ath5k_softc *sc, bool stop, bool change_channel)
 {
-	struct ath5k_softc *sc = hw->priv;
 	struct ath5k_hw *ah = sc->ah;
 	int ret;
 
 	ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "resetting\n");
 
-	ath5k_hw_set_intr(ah, 0);
-	ath5k_txq_cleanup(sc);
-	ath5k_rx_stop(sc);
-
+	if (stop) {
+		ath5k_hw_set_imr(ah, 0);
+		ath5k_txq_cleanup(sc);
+		ath5k_rx_stop(sc);
+	}
 	ret = ath5k_hw_reset(ah, sc->opmode, sc->curchan, true);
-	if (unlikely(ret)) {
+	if (ret) {
 		ATH5K_ERR(sc, "can't reset hardware (%d)\n", ret);
 		goto err;
 	}
+
+	/*
+	 * This is needed only to setup initial state
+	 * but it's best done after a reset.
+	 */
 	ath5k_hw_set_txpower_limit(sc->ah, 0);
 
 	ret = ath5k_rx_start(sc);
-	if (unlikely(ret)) {
+	if (ret) {
 		ATH5K_ERR(sc, "can't start recv logic\n");
 		goto err;
 	}
+
 	/*
-	 * We may be doing a reset in response to an ioctl
-	 * that changes the channel so update any state that
-	 * might change as a result.
+	 * Change channels and update the h/w rate map if we're switching;
+	 * e.g. 11a to 11b/g.
+	 *
+	 * We may be doing a reset in response to an ioctl that changes the
+	 * channel so update any state that might change as a result.
 	 *
 	 * XXX needed?
 	 */
 /*	ath5k_chan_change(sc, c); */
-	ath5k_beacon_config(sc);
-	/* intrs are started by ath5k_beacon_config */
 
-	ieee80211_wake_queues(hw);
+	ath5k_beacon_config(sc);
+	/* intrs are enabled by ath5k_beacon_config */
 
 	return 0;
 err:
 	return ret;
 }
 
+static int
+ath5k_reset_wake(struct ath5k_softc *sc)
+{
+	int ret;
+
+	ret = ath5k_reset(sc, true, true);
+	if (!ret)
+		ieee80211_wake_queues(sc->hw);
+
+	return ret;
+}
+
 static int ath5k_start(struct ieee80211_hw *hw)
 {
 	return ath5k_init(hw->priv);
@@ -2742,9 +2741,9 @@
 	sc->vif = conf->vif;
 
 	switch (conf->type) {
-	case IEEE80211_IF_TYPE_STA:
-	case IEEE80211_IF_TYPE_IBSS:
-	case IEEE80211_IF_TYPE_MNTR:
+	case NL80211_IFTYPE_STATION:
+	case NL80211_IFTYPE_ADHOC:
+	case NL80211_IFTYPE_MONITOR:
 		sc->opmode = conf->type;
 		break;
 	default:
@@ -2815,7 +2814,7 @@
 	}
 
 	if (conf->changed & IEEE80211_IFCC_BEACON &&
-	    vif->type == IEEE80211_IF_TYPE_IBSS) {
+	    vif->type == NL80211_IFTYPE_ADHOC) {
 		struct sk_buff *beacon = ieee80211_beacon_get(hw, vif);
 		if (!beacon) {
 			ret = -ENOMEM;
@@ -2827,7 +2826,7 @@
 
 	mutex_unlock(&sc->lock);
 
-	return ath5k_reset(hw);
+	return ath5k_reset_wake(sc);
 unlock:
 	mutex_unlock(&sc->lock);
 	return ret;
@@ -2934,16 +2933,17 @@
 
 	/* XXX move these to mac80211, and add a beacon IFF flag to mac80211 */
 
-	if (sc->opmode == IEEE80211_IF_TYPE_MNTR)
+	if (sc->opmode == NL80211_IFTYPE_MONITOR)
 		rfilt |= AR5K_RX_FILTER_CONTROL | AR5K_RX_FILTER_BEACON |
 			AR5K_RX_FILTER_PROBEREQ | AR5K_RX_FILTER_PROM;
-	if (sc->opmode != IEEE80211_IF_TYPE_STA)
+	if (sc->opmode != NL80211_IFTYPE_STATION)
 		rfilt |= AR5K_RX_FILTER_PROBEREQ;
-	if (sc->opmode != IEEE80211_IF_TYPE_AP &&
+	if (sc->opmode != NL80211_IFTYPE_AP &&
+		sc->opmode != NL80211_IFTYPE_MESH_POINT &&
 		test_bit(ATH_STAT_PROMISC, sc->status))
 		rfilt |= AR5K_RX_FILTER_PROM;
-	if (sc->opmode == IEEE80211_IF_TYPE_STA ||
-		sc->opmode == IEEE80211_IF_TYPE_IBSS) {
+	if (sc->opmode == NL80211_IFTYPE_STATION ||
+		sc->opmode == NL80211_IFTYPE_ADHOC) {
 		rfilt |= AR5K_RX_FILTER_BEACON;
 	}
 
@@ -3048,7 +3048,7 @@
 	 * in IBSS mode we need to update the beacon timers too.
 	 * this will also reset the TSF if we call it with 0
 	 */
-	if (sc->opmode == IEEE80211_IF_TYPE_IBSS)
+	if (sc->opmode == NL80211_IFTYPE_ADHOC)
 		ath5k_beacon_update_timers(sc, 0);
 	else
 		ath5k_hw_reset_tsf(sc->ah);
@@ -3063,7 +3063,7 @@
 
 	ath5k_debug_dump_skb(sc, skb, "BC  ", 1);
 
-	if (sc->opmode != IEEE80211_IF_TYPE_IBSS) {
+	if (sc->opmode != NL80211_IFTYPE_ADHOC) {
 		ret = -EIO;
 		goto end;
 	}
diff --git a/drivers/net/wireless/ath5k/base.h b/drivers/net/wireless/ath5k/base.h
index 7ec2f37..9d0b728 100644
--- a/drivers/net/wireless/ath5k/base.h
+++ b/drivers/net/wireless/ath5k/base.h
@@ -111,17 +111,13 @@
 	struct ieee80211_hw	*hw;		/* IEEE 802.11 common */
 	struct ieee80211_supported_band sbands[IEEE80211_NUM_BANDS];
 	struct ieee80211_channel channels[ATH_CHAN_MAX];
-	struct ieee80211_rate	rates[AR5K_MAX_RATES * IEEE80211_NUM_BANDS];
-	enum ieee80211_if_types	opmode;
+	struct ieee80211_rate	rates[IEEE80211_NUM_BANDS][AR5K_MAX_RATES];
+	u8			rate_idx[IEEE80211_NUM_BANDS][AR5K_MAX_RATES];
+	enum nl80211_iftype	opmode;
 	struct ath5k_hw		*ah;		/* Atheros HW */
 
 	struct ieee80211_supported_band		*curband;
 
-	u8			a_rates;
-	u8			b_rates;
-	u8			g_rates;
-	u8			xr_rates;
-
 #ifdef CONFIG_ATH5K_DEBUG
 	struct ath5k_dbg_info	debug;		/* debug info */
 #endif /* CONFIG_ATH5K_DEBUG */
diff --git a/drivers/net/wireless/ath5k/caps.c b/drivers/net/wireless/ath5k/caps.c
new file mode 100644
index 0000000..150f5ed
--- /dev/null
+++ b/drivers/net/wireless/ath5k/caps.c
@@ -0,0 +1,193 @@
+/*
+ * Copyright (c) 2004-2008 Reyk Floeter <reyk@openbsd.org>
+ * Copyright (c) 2006-2008 Nick Kossifidis <mickflemm@gmail.com>
+ * Copyright (c) 2007-2008 Jiri Slaby <jirislaby@gmail.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+/**************\
+* Capabilities *
+\**************/
+
+#include "ath5k.h"
+#include "reg.h"
+#include "debug.h"
+#include "base.h"
+
+/*
+ * Fill the capabilities struct
+ * TODO: Merge this with EEPROM code when we are done with it
+ */
+int ath5k_hw_set_capabilities(struct ath5k_hw *ah)
+{
+	u16 ee_header;
+
+	ATH5K_TRACE(ah->ah_sc);
+	/* Capabilities stored in the EEPROM */
+	ee_header = ah->ah_capabilities.cap_eeprom.ee_header;
+
+	if (ah->ah_version == AR5K_AR5210) {
+		/*
+		 * Set radio capabilities
+		 * (The AR5110 only supports the middle 5GHz band)
+		 */
+		ah->ah_capabilities.cap_range.range_5ghz_min = 5120;
+		ah->ah_capabilities.cap_range.range_5ghz_max = 5430;
+		ah->ah_capabilities.cap_range.range_2ghz_min = 0;
+		ah->ah_capabilities.cap_range.range_2ghz_max = 0;
+
+		/* Set supported modes */
+		__set_bit(AR5K_MODE_11A, ah->ah_capabilities.cap_mode);
+		__set_bit(AR5K_MODE_11A_TURBO, ah->ah_capabilities.cap_mode);
+	} else {
+		/*
+		 * XXX The tranceiver supports frequencies from 4920 to 6100GHz
+		 * XXX and from 2312 to 2732GHz. There are problems with the
+		 * XXX current ieee80211 implementation because the IEEE
+		 * XXX channel mapping does not support negative channel
+		 * XXX numbers (2312MHz is channel -19). Of course, this
+		 * XXX doesn't matter because these channels are out of range
+		 * XXX but some regulation domains like MKK (Japan) will
+		 * XXX support frequencies somewhere around 4.8GHz.
+		 */
+
+		/*
+		 * Set radio capabilities
+		 */
+
+		if (AR5K_EEPROM_HDR_11A(ee_header)) {
+			/* 4920 */
+			ah->ah_capabilities.cap_range.range_5ghz_min = 5005;
+			ah->ah_capabilities.cap_range.range_5ghz_max = 6100;
+
+			/* Set supported modes */
+			__set_bit(AR5K_MODE_11A,
+					ah->ah_capabilities.cap_mode);
+			__set_bit(AR5K_MODE_11A_TURBO,
+					ah->ah_capabilities.cap_mode);
+			if (ah->ah_version == AR5K_AR5212)
+				__set_bit(AR5K_MODE_11G_TURBO,
+						ah->ah_capabilities.cap_mode);
+		}
+
+		/* Enable  802.11b if a 2GHz capable radio (2111/5112) is
+		 * connected */
+		if (AR5K_EEPROM_HDR_11B(ee_header) ||
+				AR5K_EEPROM_HDR_11G(ee_header)) {
+			/* 2312 */
+			ah->ah_capabilities.cap_range.range_2ghz_min = 2412;
+			ah->ah_capabilities.cap_range.range_2ghz_max = 2732;
+
+			if (AR5K_EEPROM_HDR_11B(ee_header))
+				__set_bit(AR5K_MODE_11B,
+						ah->ah_capabilities.cap_mode);
+
+			if (AR5K_EEPROM_HDR_11G(ee_header))
+				__set_bit(AR5K_MODE_11G,
+						ah->ah_capabilities.cap_mode);
+		}
+	}
+
+	/* GPIO */
+	ah->ah_gpio_npins = AR5K_NUM_GPIO;
+
+	/* Set number of supported TX queues */
+	if (ah->ah_version == AR5K_AR5210)
+		ah->ah_capabilities.cap_queues.q_tx_num =
+			AR5K_NUM_TX_QUEUES_NOQCU;
+	else
+		ah->ah_capabilities.cap_queues.q_tx_num = AR5K_NUM_TX_QUEUES;
+
+	return 0;
+}
+
+/* Main function used by the driver part to check caps */
+int ath5k_hw_get_capability(struct ath5k_hw *ah,
+		enum ath5k_capability_type cap_type,
+		u32 capability, u32 *result)
+{
+	ATH5K_TRACE(ah->ah_sc);
+
+	switch (cap_type) {
+	case AR5K_CAP_NUM_TXQUEUES:
+		if (result) {
+			if (ah->ah_version == AR5K_AR5210)
+				*result = AR5K_NUM_TX_QUEUES_NOQCU;
+			else
+				*result = AR5K_NUM_TX_QUEUES;
+			goto yes;
+		}
+	case AR5K_CAP_VEOL:
+		goto yes;
+	case AR5K_CAP_COMPRESSION:
+		if (ah->ah_version == AR5K_AR5212)
+			goto yes;
+		else
+			goto no;
+	case AR5K_CAP_BURST:
+		goto yes;
+	case AR5K_CAP_TPC:
+		goto yes;
+	case AR5K_CAP_BSSIDMASK:
+		if (ah->ah_version == AR5K_AR5212)
+			goto yes;
+		else
+			goto no;
+	case AR5K_CAP_XR:
+		if (ah->ah_version == AR5K_AR5212)
+			goto yes;
+		else
+			goto no;
+	default:
+		goto no;
+	}
+
+no:
+	return -EINVAL;
+yes:
+	return 0;
+}
+
+/*
+ * TODO: Following functions should be part of a new function
+ * set_capability
+ */
+
+int ath5k_hw_enable_pspoll(struct ath5k_hw *ah, u8 *bssid,
+		u16 assoc_id)
+{
+	ATH5K_TRACE(ah->ah_sc);
+
+	if (ah->ah_version == AR5K_AR5210) {
+		AR5K_REG_DISABLE_BITS(ah, AR5K_STA_ID1,
+			AR5K_STA_ID1_NO_PSPOLL | AR5K_STA_ID1_DEFAULT_ANTENNA);
+		return 0;
+	}
+
+	return -EIO;
+}
+
+int ath5k_hw_disable_pspoll(struct ath5k_hw *ah)
+{
+	ATH5K_TRACE(ah->ah_sc);
+
+	if (ah->ah_version == AR5K_AR5210) {
+		AR5K_REG_ENABLE_BITS(ah, AR5K_STA_ID1,
+			AR5K_STA_ID1_NO_PSPOLL | AR5K_STA_ID1_DEFAULT_ANTENNA);
+		return 0;
+	}
+
+	return -EIO;
+}
diff --git a/drivers/net/wireless/ath5k/debug.c b/drivers/net/wireless/ath5k/debug.c
index 6fa6c8e0..8f92d67 100644
--- a/drivers/net/wireless/ath5k/debug.c
+++ b/drivers/net/wireless/ath5k/debug.c
@@ -58,8 +58,8 @@
  * THE POSSIBILITY OF SUCH DAMAGES.
  */
 
-#include "debug.h"
 #include "base.h"
+#include "debug.h"
 
 static unsigned int ath5k_debug;
 module_param_named(debug, ath5k_debug, uint, 0);
@@ -525,7 +525,7 @@
 		return;
 
 	printk(KERN_DEBUG "rx queue %x, link %p\n",
-		ath5k_hw_get_rx_buf(ah), sc->rxlink);
+		ath5k_hw_get_rxdp(ah), sc->rxlink);
 
 	spin_lock_bh(&sc->rxbuflock);
 	list_for_each_entry(bf, &sc->rxbuf, list) {
diff --git a/drivers/net/wireless/ath5k/desc.c b/drivers/net/wireless/ath5k/desc.c
new file mode 100644
index 0000000..dd13740
--- /dev/null
+++ b/drivers/net/wireless/ath5k/desc.c
@@ -0,0 +1,692 @@
+/*
+ * Copyright (c) 2004-2008 Reyk Floeter <reyk@openbsd.org>
+ * Copyright (c) 2006-2008 Nick Kossifidis <mickflemm@gmail.com>
+ * Copyright (c) 2007-2008 Pavel Roskin <proski@gnu.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+/******************************\
+ Hardware Descriptor Functions
+\******************************/
+
+#include "ath5k.h"
+#include "reg.h"
+#include "debug.h"
+#include "base.h"
+
+/*
+ * TX Descriptors
+ */
+
+/*
+ * Initialize the 2-word tx control descriptor on 5210/5211
+ */
+static int
+ath5k_hw_setup_2word_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc,
+	unsigned int pkt_len, unsigned int hdr_len, enum ath5k_pkt_type type,
+	unsigned int tx_power, unsigned int tx_rate0, unsigned int tx_tries0,
+	unsigned int key_index, unsigned int antenna_mode, unsigned int flags,
+	unsigned int rtscts_rate, unsigned int rtscts_duration)
+{
+	u32 frame_type;
+	struct ath5k_hw_2w_tx_ctl *tx_ctl;
+	unsigned int frame_len;
+
+	tx_ctl = &desc->ud.ds_tx5210.tx_ctl;
+
+	/*
+	 * Validate input
+	 * - Zero retries don't make sense.
+	 * - A zero rate will put the HW into a mode where it continously sends
+	 *   noise on the channel, so it is important to avoid this.
+	 */
+	if (unlikely(tx_tries0 == 0)) {
+		ATH5K_ERR(ah->ah_sc, "zero retries\n");
+		WARN_ON(1);
+		return -EINVAL;
+	}
+	if (unlikely(tx_rate0 == 0)) {
+		ATH5K_ERR(ah->ah_sc, "zero rate\n");
+		WARN_ON(1);
+		return -EINVAL;
+	}
+
+	/* Clear descriptor */
+	memset(&desc->ud.ds_tx5210, 0, sizeof(struct ath5k_hw_5210_tx_desc));
+
+	/* Setup control descriptor */
+
+	/* Verify and set frame length */
+
+	/* remove padding we might have added before */
+	frame_len = pkt_len - (hdr_len & 3) + FCS_LEN;
+
+	if (frame_len & ~AR5K_2W_TX_DESC_CTL0_FRAME_LEN)
+		return -EINVAL;
+
+	tx_ctl->tx_control_0 = frame_len & AR5K_2W_TX_DESC_CTL0_FRAME_LEN;
+
+	/* Verify and set buffer length */
+
+	/* NB: beacon's BufLen must be a multiple of 4 bytes */
+	if (type == AR5K_PKT_TYPE_BEACON)
+		pkt_len = roundup(pkt_len, 4);
+
+	if (pkt_len & ~AR5K_2W_TX_DESC_CTL1_BUF_LEN)
+		return -EINVAL;
+
+	tx_ctl->tx_control_1 = pkt_len & AR5K_2W_TX_DESC_CTL1_BUF_LEN;
+
+	/*
+	 * Verify and set header length
+	 * XXX: I only found that on 5210 code, does it work on 5211 ?
+	 */
+	if (ah->ah_version == AR5K_AR5210) {
+		if (hdr_len & ~AR5K_2W_TX_DESC_CTL0_HEADER_LEN)
+			return -EINVAL;
+		tx_ctl->tx_control_0 |=
+			AR5K_REG_SM(hdr_len, AR5K_2W_TX_DESC_CTL0_HEADER_LEN);
+	}
+
+	/*Diferences between 5210-5211*/
+	if (ah->ah_version == AR5K_AR5210) {
+		switch (type) {
+		case AR5K_PKT_TYPE_BEACON:
+		case AR5K_PKT_TYPE_PROBE_RESP:
+			frame_type = AR5K_AR5210_TX_DESC_FRAME_TYPE_NO_DELAY;
+		case AR5K_PKT_TYPE_PIFS:
+			frame_type = AR5K_AR5210_TX_DESC_FRAME_TYPE_PIFS;
+		default:
+			frame_type = type /*<< 2 ?*/;
+		}
+
+		tx_ctl->tx_control_0 |=
+		AR5K_REG_SM(frame_type, AR5K_2W_TX_DESC_CTL0_FRAME_TYPE) |
+		AR5K_REG_SM(tx_rate0, AR5K_2W_TX_DESC_CTL0_XMIT_RATE);
+
+	} else {
+		tx_ctl->tx_control_0 |=
+			AR5K_REG_SM(tx_rate0, AR5K_2W_TX_DESC_CTL0_XMIT_RATE) |
+			AR5K_REG_SM(antenna_mode,
+				AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT);
+		tx_ctl->tx_control_1 |=
+			AR5K_REG_SM(type, AR5K_2W_TX_DESC_CTL1_FRAME_TYPE);
+	}
+#define _TX_FLAGS(_c, _flag)					\
+	if (flags & AR5K_TXDESC_##_flag) {			\
+		tx_ctl->tx_control_##_c |=			\
+			AR5K_2W_TX_DESC_CTL##_c##_##_flag;	\
+	}
+
+	_TX_FLAGS(0, CLRDMASK);
+	_TX_FLAGS(0, VEOL);
+	_TX_FLAGS(0, INTREQ);
+	_TX_FLAGS(0, RTSENA);
+	_TX_FLAGS(1, NOACK);
+
+#undef _TX_FLAGS
+
+	/*
+	 * WEP crap
+	 */
+	if (key_index != AR5K_TXKEYIX_INVALID) {
+		tx_ctl->tx_control_0 |=
+			AR5K_2W_TX_DESC_CTL0_ENCRYPT_KEY_VALID;
+		tx_ctl->tx_control_1 |=
+			AR5K_REG_SM(key_index,
+			AR5K_2W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX);
+	}
+
+	/*
+	 * RTS/CTS Duration [5210 ?]
+	 */
+	if ((ah->ah_version == AR5K_AR5210) &&
+			(flags & (AR5K_TXDESC_RTSENA | AR5K_TXDESC_CTSENA)))
+		tx_ctl->tx_control_1 |= rtscts_duration &
+				AR5K_2W_TX_DESC_CTL1_RTS_DURATION;
+
+	return 0;
+}
+
+/*
+ * Initialize the 4-word tx control descriptor on 5212
+ */
+static int ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *ah,
+	struct ath5k_desc *desc, unsigned int pkt_len, unsigned int hdr_len,
+	enum ath5k_pkt_type type, unsigned int tx_power, unsigned int tx_rate0,
+	unsigned int tx_tries0, unsigned int key_index,
+	unsigned int antenna_mode, unsigned int flags,
+	unsigned int rtscts_rate,
+	unsigned int rtscts_duration)
+{
+	struct ath5k_hw_4w_tx_ctl *tx_ctl;
+	unsigned int frame_len;
+
+	ATH5K_TRACE(ah->ah_sc);
+	tx_ctl = &desc->ud.ds_tx5212.tx_ctl;
+
+	/*
+	 * Validate input
+	 * - Zero retries don't make sense.
+	 * - A zero rate will put the HW into a mode where it continously sends
+	 *   noise on the channel, so it is important to avoid this.
+	 */
+	if (unlikely(tx_tries0 == 0)) {
+		ATH5K_ERR(ah->ah_sc, "zero retries\n");
+		WARN_ON(1);
+		return -EINVAL;
+	}
+	if (unlikely(tx_rate0 == 0)) {
+		ATH5K_ERR(ah->ah_sc, "zero rate\n");
+		WARN_ON(1);
+		return -EINVAL;
+	}
+
+	/* Clear descriptor */
+	memset(&desc->ud.ds_tx5212, 0, sizeof(struct ath5k_hw_5212_tx_desc));
+
+	/* Setup control descriptor */
+
+	/* Verify and set frame length */
+
+	/* remove padding we might have added before */
+	frame_len = pkt_len - (hdr_len & 3) + FCS_LEN;
+
+	if (frame_len & ~AR5K_4W_TX_DESC_CTL0_FRAME_LEN)
+		return -EINVAL;
+
+	tx_ctl->tx_control_0 = frame_len & AR5K_4W_TX_DESC_CTL0_FRAME_LEN;
+
+	/* Verify and set buffer length */
+
+	/* NB: beacon's BufLen must be a multiple of 4 bytes */
+	if (type == AR5K_PKT_TYPE_BEACON)
+		pkt_len = roundup(pkt_len, 4);
+
+	if (pkt_len & ~AR5K_4W_TX_DESC_CTL1_BUF_LEN)
+		return -EINVAL;
+
+	tx_ctl->tx_control_1 = pkt_len & AR5K_4W_TX_DESC_CTL1_BUF_LEN;
+
+	tx_ctl->tx_control_0 |=
+		AR5K_REG_SM(tx_power, AR5K_4W_TX_DESC_CTL0_XMIT_POWER) |
+		AR5K_REG_SM(antenna_mode, AR5K_4W_TX_DESC_CTL0_ANT_MODE_XMIT);
+	tx_ctl->tx_control_1 |= AR5K_REG_SM(type,
+					AR5K_4W_TX_DESC_CTL1_FRAME_TYPE);
+	tx_ctl->tx_control_2 = AR5K_REG_SM(tx_tries0 + AR5K_TUNE_HWTXTRIES,
+					AR5K_4W_TX_DESC_CTL2_XMIT_TRIES0);
+	tx_ctl->tx_control_3 = tx_rate0 & AR5K_4W_TX_DESC_CTL3_XMIT_RATE0;
+
+#define _TX_FLAGS(_c, _flag)					\
+	if (flags & AR5K_TXDESC_##_flag) {			\
+		tx_ctl->tx_control_##_c |=			\
+			AR5K_4W_TX_DESC_CTL##_c##_##_flag;	\
+	}
+
+	_TX_FLAGS(0, CLRDMASK);
+	_TX_FLAGS(0, VEOL);
+	_TX_FLAGS(0, INTREQ);
+	_TX_FLAGS(0, RTSENA);
+	_TX_FLAGS(0, CTSENA);
+	_TX_FLAGS(1, NOACK);
+
+#undef _TX_FLAGS
+
+	/*
+	 * WEP crap
+	 */
+	if (key_index != AR5K_TXKEYIX_INVALID) {
+		tx_ctl->tx_control_0 |= AR5K_4W_TX_DESC_CTL0_ENCRYPT_KEY_VALID;
+		tx_ctl->tx_control_1 |= AR5K_REG_SM(key_index,
+				AR5K_4W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX);
+	}
+
+	/*
+	 * RTS/CTS
+	 */
+	if (flags & (AR5K_TXDESC_RTSENA | AR5K_TXDESC_CTSENA)) {
+		if ((flags & AR5K_TXDESC_RTSENA) &&
+				(flags & AR5K_TXDESC_CTSENA))
+			return -EINVAL;
+		tx_ctl->tx_control_2 |= rtscts_duration &
+				AR5K_4W_TX_DESC_CTL2_RTS_DURATION;
+		tx_ctl->tx_control_3 |= AR5K_REG_SM(rtscts_rate,
+				AR5K_4W_TX_DESC_CTL3_RTS_CTS_RATE);
+	}
+
+	return 0;
+}
+
+/*
+ * Initialize a 4-word multi rate retry tx control descriptor on 5212
+ */
+static int
+ath5k_hw_setup_mrr_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc,
+	unsigned int tx_rate1, u_int tx_tries1, u_int tx_rate2,
+	u_int tx_tries2, unsigned int tx_rate3, u_int tx_tries3)
+{
+	struct ath5k_hw_4w_tx_ctl *tx_ctl;
+
+	/*
+	 * Rates can be 0 as long as the retry count is 0 too.
+	 * A zero rate and nonzero retry count will put the HW into a mode where
+	 * it continously sends noise on the channel, so it is important to
+	 * avoid this.
+	 */
+	if (unlikely((tx_rate1 == 0 && tx_tries1 != 0) ||
+		     (tx_rate2 == 0 && tx_tries2 != 0) ||
+		     (tx_rate3 == 0 && tx_tries3 != 0))) {
+		ATH5K_ERR(ah->ah_sc, "zero rate\n");
+		WARN_ON(1);
+		return -EINVAL;
+	}
+
+	if (ah->ah_version == AR5K_AR5212) {
+		tx_ctl = &desc->ud.ds_tx5212.tx_ctl;
+
+#define _XTX_TRIES(_n)							\
+	if (tx_tries##_n) {						\
+		tx_ctl->tx_control_2 |=					\
+		    AR5K_REG_SM(tx_tries##_n,				\
+		    AR5K_4W_TX_DESC_CTL2_XMIT_TRIES##_n);		\
+		tx_ctl->tx_control_3 |=					\
+		    AR5K_REG_SM(tx_rate##_n,				\
+		    AR5K_4W_TX_DESC_CTL3_XMIT_RATE##_n);		\
+	}
+
+		_XTX_TRIES(1);
+		_XTX_TRIES(2);
+		_XTX_TRIES(3);
+
+#undef _XTX_TRIES
+
+		return 1;
+	}
+
+	return 0;
+}
+
+/* no mrr support for cards older than 5212 */
+static int
+ath5k_hw_setup_no_mrr(struct ath5k_hw *ah, struct ath5k_desc *desc,
+	unsigned int tx_rate1, u_int tx_tries1, u_int tx_rate2,
+	u_int tx_tries2, unsigned int tx_rate3, u_int tx_tries3)
+{
+	return 0;
+}
+
+/*
+ * Proccess the tx status descriptor on 5210/5211
+ */
+static int ath5k_hw_proc_2word_tx_status(struct ath5k_hw *ah,
+		struct ath5k_desc *desc, struct ath5k_tx_status *ts)
+{
+	struct ath5k_hw_2w_tx_ctl *tx_ctl;
+	struct ath5k_hw_tx_status *tx_status;
+
+	ATH5K_TRACE(ah->ah_sc);
+
+	tx_ctl = &desc->ud.ds_tx5210.tx_ctl;
+	tx_status = &desc->ud.ds_tx5210.tx_stat;
+
+	/* No frame has been send or error */
+	if (unlikely((tx_status->tx_status_1 & AR5K_DESC_TX_STATUS1_DONE) == 0))
+		return -EINPROGRESS;
+
+	/*
+	 * Get descriptor status
+	 */
+	ts->ts_tstamp = AR5K_REG_MS(tx_status->tx_status_0,
+		AR5K_DESC_TX_STATUS0_SEND_TIMESTAMP);
+	ts->ts_shortretry = AR5K_REG_MS(tx_status->tx_status_0,
+		AR5K_DESC_TX_STATUS0_SHORT_RETRY_COUNT);
+	ts->ts_longretry = AR5K_REG_MS(tx_status->tx_status_0,
+		AR5K_DESC_TX_STATUS0_LONG_RETRY_COUNT);
+	/*TODO: ts->ts_virtcol + test*/
+	ts->ts_seqnum = AR5K_REG_MS(tx_status->tx_status_1,
+		AR5K_DESC_TX_STATUS1_SEQ_NUM);
+	ts->ts_rssi = AR5K_REG_MS(tx_status->tx_status_1,
+		AR5K_DESC_TX_STATUS1_ACK_SIG_STRENGTH);
+	ts->ts_antenna = 1;
+	ts->ts_status = 0;
+	ts->ts_rate[0] = AR5K_REG_MS(tx_ctl->tx_control_0,
+		AR5K_2W_TX_DESC_CTL0_XMIT_RATE);
+	ts->ts_retry[0] = ts->ts_longretry;
+	ts->ts_final_idx = 0;
+
+	if (!(tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FRAME_XMIT_OK)) {
+		if (tx_status->tx_status_0 &
+				AR5K_DESC_TX_STATUS0_EXCESSIVE_RETRIES)
+			ts->ts_status |= AR5K_TXERR_XRETRY;
+
+		if (tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FIFO_UNDERRUN)
+			ts->ts_status |= AR5K_TXERR_FIFO;
+
+		if (tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FILTERED)
+			ts->ts_status |= AR5K_TXERR_FILT;
+	}
+
+	return 0;
+}
+
+/*
+ * Proccess a tx status descriptor on 5212
+ */
+static int ath5k_hw_proc_4word_tx_status(struct ath5k_hw *ah,
+		struct ath5k_desc *desc, struct ath5k_tx_status *ts)
+{
+	struct ath5k_hw_4w_tx_ctl *tx_ctl;
+	struct ath5k_hw_tx_status *tx_status;
+
+	ATH5K_TRACE(ah->ah_sc);
+
+	tx_ctl = &desc->ud.ds_tx5212.tx_ctl;
+	tx_status = &desc->ud.ds_tx5212.tx_stat;
+
+	/* No frame has been send or error */
+	if (unlikely(!(tx_status->tx_status_1 & AR5K_DESC_TX_STATUS1_DONE)))
+		return -EINPROGRESS;
+
+	/*
+	 * Get descriptor status
+	 */
+	ts->ts_tstamp = AR5K_REG_MS(tx_status->tx_status_0,
+		AR5K_DESC_TX_STATUS0_SEND_TIMESTAMP);
+	ts->ts_shortretry = AR5K_REG_MS(tx_status->tx_status_0,
+		AR5K_DESC_TX_STATUS0_SHORT_RETRY_COUNT);
+	ts->ts_longretry = AR5K_REG_MS(tx_status->tx_status_0,
+		AR5K_DESC_TX_STATUS0_LONG_RETRY_COUNT);
+	ts->ts_seqnum = AR5K_REG_MS(tx_status->tx_status_1,
+		AR5K_DESC_TX_STATUS1_SEQ_NUM);
+	ts->ts_rssi = AR5K_REG_MS(tx_status->tx_status_1,
+		AR5K_DESC_TX_STATUS1_ACK_SIG_STRENGTH);
+	ts->ts_antenna = (tx_status->tx_status_1 &
+		AR5K_DESC_TX_STATUS1_XMIT_ANTENNA) ? 2 : 1;
+	ts->ts_status = 0;
+
+	ts->ts_final_idx = AR5K_REG_MS(tx_status->tx_status_1,
+			AR5K_DESC_TX_STATUS1_FINAL_TS_INDEX);
+
+	/* The longretry counter has the number of un-acked retries
+	 * for the final rate. To get the total number of retries
+	 * we have to add the retry counters for the other rates
+	 * as well
+	 */
+	ts->ts_retry[ts->ts_final_idx] = ts->ts_longretry;
+	switch (ts->ts_final_idx) {
+	case 3:
+		ts->ts_rate[3] = AR5K_REG_MS(tx_ctl->tx_control_3,
+			AR5K_4W_TX_DESC_CTL3_XMIT_RATE3);
+
+		ts->ts_retry[2] = AR5K_REG_MS(tx_ctl->tx_control_2,
+			AR5K_4W_TX_DESC_CTL2_XMIT_TRIES2);
+		ts->ts_longretry += ts->ts_retry[2];
+		/* fall through */
+	case 2:
+		ts->ts_rate[2] = AR5K_REG_MS(tx_ctl->tx_control_3,
+			AR5K_4W_TX_DESC_CTL3_XMIT_RATE2);
+
+		ts->ts_retry[1] = AR5K_REG_MS(tx_ctl->tx_control_2,
+			AR5K_4W_TX_DESC_CTL2_XMIT_TRIES1);
+		ts->ts_longretry += ts->ts_retry[1];
+		/* fall through */
+	case 1:
+		ts->ts_rate[1] = AR5K_REG_MS(tx_ctl->tx_control_3,
+			AR5K_4W_TX_DESC_CTL3_XMIT_RATE1);
+
+		ts->ts_retry[0] = AR5K_REG_MS(tx_ctl->tx_control_2,
+			AR5K_4W_TX_DESC_CTL2_XMIT_TRIES1);
+		ts->ts_longretry += ts->ts_retry[0];
+		/* fall through */
+	case 0:
+		ts->ts_rate[0] = tx_ctl->tx_control_3 &
+			AR5K_4W_TX_DESC_CTL3_XMIT_RATE0;
+		break;
+	}
+
+	/* TX error */
+	if (!(tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FRAME_XMIT_OK)) {
+		if (tx_status->tx_status_0 &
+				AR5K_DESC_TX_STATUS0_EXCESSIVE_RETRIES)
+			ts->ts_status |= AR5K_TXERR_XRETRY;
+
+		if (tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FIFO_UNDERRUN)
+			ts->ts_status |= AR5K_TXERR_FIFO;
+
+		if (tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FILTERED)
+			ts->ts_status |= AR5K_TXERR_FILT;
+	}
+
+	return 0;
+}
+
+/*
+ * RX Descriptors
+ */
+
+/*
+ * Initialize an rx control descriptor
+ */
+static int ath5k_hw_setup_rx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc,
+			u32 size, unsigned int flags)
+{
+	struct ath5k_hw_rx_ctl *rx_ctl;
+
+	ATH5K_TRACE(ah->ah_sc);
+	rx_ctl = &desc->ud.ds_rx.rx_ctl;
+
+	/*
+	 * Clear the descriptor
+	 * If we don't clean the status descriptor,
+	 * while scanning we get too many results,
+	 * most of them virtual, after some secs
+	 * of scanning system hangs. M.F.
+	*/
+	memset(&desc->ud.ds_rx, 0, sizeof(struct ath5k_hw_all_rx_desc));
+
+	/* Setup descriptor */
+	rx_ctl->rx_control_1 = size & AR5K_DESC_RX_CTL1_BUF_LEN;
+	if (unlikely(rx_ctl->rx_control_1 != size))
+		return -EINVAL;
+
+	if (flags & AR5K_RXDESC_INTREQ)
+		rx_ctl->rx_control_1 |= AR5K_DESC_RX_CTL1_INTREQ;
+
+	return 0;
+}
+
+/*
+ * Proccess the rx status descriptor on 5210/5211
+ */
+static int ath5k_hw_proc_5210_rx_status(struct ath5k_hw *ah,
+		struct ath5k_desc *desc, struct ath5k_rx_status *rs)
+{
+	struct ath5k_hw_rx_status *rx_status;
+
+	rx_status = &desc->ud.ds_rx.u.rx_stat;
+
+	/* No frame received / not ready */
+	if (unlikely(!(rx_status->rx_status_1 &
+	AR5K_5210_RX_DESC_STATUS1_DONE)))
+		return -EINPROGRESS;
+
+	/*
+	 * Frame receive status
+	 */
+	rs->rs_datalen = rx_status->rx_status_0 &
+		AR5K_5210_RX_DESC_STATUS0_DATA_LEN;
+	rs->rs_rssi = AR5K_REG_MS(rx_status->rx_status_0,
+		AR5K_5210_RX_DESC_STATUS0_RECEIVE_SIGNAL);
+	rs->rs_rate = AR5K_REG_MS(rx_status->rx_status_0,
+		AR5K_5210_RX_DESC_STATUS0_RECEIVE_RATE);
+	rs->rs_antenna = rx_status->rx_status_0 &
+		AR5K_5210_RX_DESC_STATUS0_RECEIVE_ANTENNA;
+	rs->rs_more = rx_status->rx_status_0 &
+		AR5K_5210_RX_DESC_STATUS0_MORE;
+	/* TODO: this timestamp is 13 bit, later on we assume 15 bit */
+	rs->rs_tstamp = AR5K_REG_MS(rx_status->rx_status_1,
+		AR5K_5210_RX_DESC_STATUS1_RECEIVE_TIMESTAMP);
+	rs->rs_status = 0;
+	rs->rs_phyerr = 0;
+
+	/*
+	 * Key table status
+	 */
+	if (rx_status->rx_status_1 & AR5K_5210_RX_DESC_STATUS1_KEY_INDEX_VALID)
+		rs->rs_keyix = AR5K_REG_MS(rx_status->rx_status_1,
+			AR5K_5210_RX_DESC_STATUS1_KEY_INDEX);
+	else
+		rs->rs_keyix = AR5K_RXKEYIX_INVALID;
+
+	/*
+	 * Receive/descriptor errors
+	 */
+	if (!(rx_status->rx_status_1 &
+	AR5K_5210_RX_DESC_STATUS1_FRAME_RECEIVE_OK)) {
+		if (rx_status->rx_status_1 &
+				AR5K_5210_RX_DESC_STATUS1_CRC_ERROR)
+			rs->rs_status |= AR5K_RXERR_CRC;
+
+		if (rx_status->rx_status_1 &
+				AR5K_5210_RX_DESC_STATUS1_FIFO_OVERRUN)
+			rs->rs_status |= AR5K_RXERR_FIFO;
+
+		if (rx_status->rx_status_1 &
+				AR5K_5210_RX_DESC_STATUS1_PHY_ERROR) {
+			rs->rs_status |= AR5K_RXERR_PHY;
+			rs->rs_phyerr |= AR5K_REG_MS(rx_status->rx_status_1,
+				AR5K_5210_RX_DESC_STATUS1_PHY_ERROR);
+		}
+
+		if (rx_status->rx_status_1 &
+				AR5K_5210_RX_DESC_STATUS1_DECRYPT_CRC_ERROR)
+			rs->rs_status |= AR5K_RXERR_DECRYPT;
+	}
+
+	return 0;
+}
+
+/*
+ * Proccess the rx status descriptor on 5212
+ */
+static int ath5k_hw_proc_5212_rx_status(struct ath5k_hw *ah,
+		struct ath5k_desc *desc, struct ath5k_rx_status *rs)
+{
+	struct ath5k_hw_rx_status *rx_status;
+	struct ath5k_hw_rx_error *rx_err;
+
+	ATH5K_TRACE(ah->ah_sc);
+	rx_status = &desc->ud.ds_rx.u.rx_stat;
+
+	/* Overlay on error */
+	rx_err = &desc->ud.ds_rx.u.rx_err;
+
+	/* No frame received / not ready */
+	if (unlikely(!(rx_status->rx_status_1 &
+	AR5K_5212_RX_DESC_STATUS1_DONE)))
+		return -EINPROGRESS;
+
+	/*
+	 * Frame receive status
+	 */
+	rs->rs_datalen = rx_status->rx_status_0 &
+		AR5K_5212_RX_DESC_STATUS0_DATA_LEN;
+	rs->rs_rssi = AR5K_REG_MS(rx_status->rx_status_0,
+		AR5K_5212_RX_DESC_STATUS0_RECEIVE_SIGNAL);
+	rs->rs_rate = AR5K_REG_MS(rx_status->rx_status_0,
+		AR5K_5212_RX_DESC_STATUS0_RECEIVE_RATE);
+	rs->rs_antenna = rx_status->rx_status_0 &
+		AR5K_5212_RX_DESC_STATUS0_RECEIVE_ANTENNA;
+	rs->rs_more = rx_status->rx_status_0 &
+		AR5K_5212_RX_DESC_STATUS0_MORE;
+	rs->rs_tstamp = AR5K_REG_MS(rx_status->rx_status_1,
+		AR5K_5212_RX_DESC_STATUS1_RECEIVE_TIMESTAMP);
+	rs->rs_status = 0;
+	rs->rs_phyerr = 0;
+
+	/*
+	 * Key table status
+	 */
+	if (rx_status->rx_status_1 & AR5K_5212_RX_DESC_STATUS1_KEY_INDEX_VALID)
+		rs->rs_keyix = AR5K_REG_MS(rx_status->rx_status_1,
+				AR5K_5212_RX_DESC_STATUS1_KEY_INDEX);
+	else
+		rs->rs_keyix = AR5K_RXKEYIX_INVALID;
+
+	/*
+	 * Receive/descriptor errors
+	 */
+	if (!(rx_status->rx_status_1 &
+	AR5K_5212_RX_DESC_STATUS1_FRAME_RECEIVE_OK)) {
+		if (rx_status->rx_status_1 &
+				AR5K_5212_RX_DESC_STATUS1_CRC_ERROR)
+			rs->rs_status |= AR5K_RXERR_CRC;
+
+		if (rx_status->rx_status_1 &
+				AR5K_5212_RX_DESC_STATUS1_PHY_ERROR) {
+			rs->rs_status |= AR5K_RXERR_PHY;
+			rs->rs_phyerr |= AR5K_REG_MS(rx_err->rx_error_1,
+					   AR5K_RX_DESC_ERROR1_PHY_ERROR_CODE);
+		}
+
+		if (rx_status->rx_status_1 &
+				AR5K_5212_RX_DESC_STATUS1_DECRYPT_CRC_ERROR)
+			rs->rs_status |= AR5K_RXERR_DECRYPT;
+
+		if (rx_status->rx_status_1 &
+				AR5K_5212_RX_DESC_STATUS1_MIC_ERROR)
+			rs->rs_status |= AR5K_RXERR_MIC;
+	}
+
+	return 0;
+}
+
+/*
+ * Init function pointers inside ath5k_hw struct
+ */
+int ath5k_hw_init_desc_functions(struct ath5k_hw *ah)
+{
+
+	if (ah->ah_version != AR5K_AR5210 &&
+		ah->ah_version != AR5K_AR5211 &&
+		ah->ah_version != AR5K_AR5212)
+			return -ENOTSUPP;
+
+	/* XXX: What is this magic value and where is it used ? */
+	if (ah->ah_version == AR5K_AR5212)
+		ah->ah_magic = AR5K_EEPROM_MAGIC_5212;
+	else if (ah->ah_version == AR5K_AR5211)
+		ah->ah_magic = AR5K_EEPROM_MAGIC_5211;
+
+	if (ah->ah_version == AR5K_AR5212) {
+		ah->ah_setup_rx_desc = ath5k_hw_setup_rx_desc;
+		ah->ah_setup_tx_desc = ath5k_hw_setup_4word_tx_desc;
+		ah->ah_setup_mrr_tx_desc = ath5k_hw_setup_mrr_tx_desc;
+		ah->ah_proc_tx_desc = ath5k_hw_proc_4word_tx_status;
+	} else {
+		ah->ah_setup_rx_desc = ath5k_hw_setup_rx_desc;
+		ah->ah_setup_tx_desc = ath5k_hw_setup_2word_tx_desc;
+		ah->ah_setup_mrr_tx_desc = ath5k_hw_setup_no_mrr;
+		ah->ah_proc_tx_desc = ath5k_hw_proc_2word_tx_status;
+	}
+
+	if (ah->ah_version == AR5K_AR5212)
+		ah->ah_proc_rx_desc = ath5k_hw_proc_5212_rx_status;
+	else if (ah->ah_version <= AR5K_AR5211)
+		ah->ah_proc_rx_desc = ath5k_hw_proc_5210_rx_status;
+
+	return 0;
+}
+
diff --git a/drivers/net/wireless/ath5k/desc.h b/drivers/net/wireless/ath5k/desc.h
new file mode 100644
index 0000000..56158c8
--- /dev/null
+++ b/drivers/net/wireless/ath5k/desc.h
@@ -0,0 +1,332 @@
+/*
+ * Copyright (c) 2004-2008 Reyk Floeter <reyk@openbsd.org>
+ * Copyright (c) 2006-2008 Nick Kossifidis <mickflemm@gmail.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+/*
+ * Internal RX/TX descriptor structures
+ * (rX: reserved fields possibily used by future versions of the ar5k chipset)
+ */
+
+/*
+ * common hardware RX control descriptor
+ */
+struct ath5k_hw_rx_ctl {
+	u32	rx_control_0; /* RX control word 0 */
+	u32	rx_control_1; /* RX control word 1 */
+} __packed;
+
+/* RX control word 0 field/sflags */
+#define AR5K_DESC_RX_CTL0			0x00000000
+
+/* RX control word 1 fields/flags */
+#define AR5K_DESC_RX_CTL1_BUF_LEN		0x00000fff
+#define AR5K_DESC_RX_CTL1_INTREQ		0x00002000
+
+/*
+ * common hardware RX status descriptor
+ * 5210/11 and 5212 differ only in the flags defined below
+ */
+struct ath5k_hw_rx_status {
+	u32	rx_status_0; /* RX status word 0 */
+	u32	rx_status_1; /* RX status word 1 */
+} __packed;
+
+/* 5210/5211 */
+/* RX status word 0 fields/flags */
+#define AR5K_5210_RX_DESC_STATUS0_DATA_LEN		0x00000fff
+#define AR5K_5210_RX_DESC_STATUS0_MORE			0x00001000
+#define AR5K_5210_RX_DESC_STATUS0_RECEIVE_RATE		0x00078000
+#define AR5K_5210_RX_DESC_STATUS0_RECEIVE_RATE_S	15
+#define AR5K_5210_RX_DESC_STATUS0_RECEIVE_SIGNAL	0x07f80000
+#define AR5K_5210_RX_DESC_STATUS0_RECEIVE_SIGNAL_S	19
+#define AR5K_5210_RX_DESC_STATUS0_RECEIVE_ANTENNA	0x38000000
+#define AR5K_5210_RX_DESC_STATUS0_RECEIVE_ANTENNA_S	27
+
+/* RX status word 1 fields/flags */
+#define AR5K_5210_RX_DESC_STATUS1_DONE			0x00000001
+#define AR5K_5210_RX_DESC_STATUS1_FRAME_RECEIVE_OK	0x00000002
+#define AR5K_5210_RX_DESC_STATUS1_CRC_ERROR		0x00000004
+#define AR5K_5210_RX_DESC_STATUS1_FIFO_OVERRUN		0x00000008
+#define AR5K_5210_RX_DESC_STATUS1_DECRYPT_CRC_ERROR	0x00000010
+#define AR5K_5210_RX_DESC_STATUS1_PHY_ERROR		0x000000e0
+#define AR5K_5210_RX_DESC_STATUS1_PHY_ERROR_S		5
+#define AR5K_5210_RX_DESC_STATUS1_KEY_INDEX_VALID	0x00000100
+#define AR5K_5210_RX_DESC_STATUS1_KEY_INDEX		0x00007e00
+#define AR5K_5210_RX_DESC_STATUS1_KEY_INDEX_S		9
+#define AR5K_5210_RX_DESC_STATUS1_RECEIVE_TIMESTAMP	0x0fff8000
+#define AR5K_5210_RX_DESC_STATUS1_RECEIVE_TIMESTAMP_S	15
+#define AR5K_5210_RX_DESC_STATUS1_KEY_CACHE_MISS	0x10000000
+
+/* 5212 */
+/* RX status word 0 fields/flags */
+#define AR5K_5212_RX_DESC_STATUS0_DATA_LEN		0x00000fff
+#define AR5K_5212_RX_DESC_STATUS0_MORE			0x00001000
+#define AR5K_5212_RX_DESC_STATUS0_DECOMP_CRC_ERROR	0x00002000
+#define AR5K_5212_RX_DESC_STATUS0_RECEIVE_RATE		0x000f8000
+#define AR5K_5212_RX_DESC_STATUS0_RECEIVE_RATE_S	15
+#define AR5K_5212_RX_DESC_STATUS0_RECEIVE_SIGNAL	0x0ff00000
+#define AR5K_5212_RX_DESC_STATUS0_RECEIVE_SIGNAL_S	20
+#define AR5K_5212_RX_DESC_STATUS0_RECEIVE_ANTENNA	0xf0000000
+#define AR5K_5212_RX_DESC_STATUS0_RECEIVE_ANTENNA_S	28
+
+/* RX status word 1 fields/flags */
+#define AR5K_5212_RX_DESC_STATUS1_DONE			0x00000001
+#define AR5K_5212_RX_DESC_STATUS1_FRAME_RECEIVE_OK	0x00000002
+#define AR5K_5212_RX_DESC_STATUS1_CRC_ERROR		0x00000004
+#define AR5K_5212_RX_DESC_STATUS1_DECRYPT_CRC_ERROR	0x00000008
+#define AR5K_5212_RX_DESC_STATUS1_PHY_ERROR		0x00000010
+#define AR5K_5212_RX_DESC_STATUS1_MIC_ERROR		0x00000020
+#define AR5K_5212_RX_DESC_STATUS1_KEY_INDEX_VALID	0x00000100
+#define AR5K_5212_RX_DESC_STATUS1_KEY_INDEX		0x0000fe00
+#define AR5K_5212_RX_DESC_STATUS1_KEY_INDEX_S		9
+#define AR5K_5212_RX_DESC_STATUS1_RECEIVE_TIMESTAMP	0x7fff0000
+#define AR5K_5212_RX_DESC_STATUS1_RECEIVE_TIMESTAMP_S	16
+#define AR5K_5212_RX_DESC_STATUS1_KEY_CACHE_MISS	0x80000000
+
+/*
+ * common hardware RX error descriptor
+ */
+struct ath5k_hw_rx_error {
+	u32	rx_error_0; /* RX status word 0 */
+	u32	rx_error_1; /* RX status word 1 */
+} __packed;
+
+/* RX error word 0 fields/flags */
+#define AR5K_RX_DESC_ERROR0			0x00000000
+
+/* RX error word 1 fields/flags */
+#define AR5K_RX_DESC_ERROR1_PHY_ERROR_CODE	0x0000ff00
+#define AR5K_RX_DESC_ERROR1_PHY_ERROR_CODE_S	8
+
+/* PHY Error codes */
+#define AR5K_DESC_RX_PHY_ERROR_NONE		0x00
+#define AR5K_DESC_RX_PHY_ERROR_TIMING		0x20
+#define AR5K_DESC_RX_PHY_ERROR_PARITY		0x40
+#define AR5K_DESC_RX_PHY_ERROR_RATE		0x60
+#define AR5K_DESC_RX_PHY_ERROR_LENGTH		0x80
+#define AR5K_DESC_RX_PHY_ERROR_64QAM		0xa0
+#define AR5K_DESC_RX_PHY_ERROR_SERVICE		0xc0
+#define AR5K_DESC_RX_PHY_ERROR_TRANSMITOVR	0xe0
+
+/*
+ * 5210/5211 hardware 2-word TX control descriptor
+ */
+struct ath5k_hw_2w_tx_ctl {
+	u32	tx_control_0; /* TX control word 0 */
+	u32	tx_control_1; /* TX control word 1 */
+} __packed;
+
+/* TX control word 0 fields/flags */
+#define AR5K_2W_TX_DESC_CTL0_FRAME_LEN		0x00000fff
+#define AR5K_2W_TX_DESC_CTL0_HEADER_LEN		0x0003f000 /*[5210 ?]*/
+#define AR5K_2W_TX_DESC_CTL0_HEADER_LEN_S	12
+#define AR5K_2W_TX_DESC_CTL0_XMIT_RATE		0x003c0000
+#define AR5K_2W_TX_DESC_CTL0_XMIT_RATE_S	18
+#define AR5K_2W_TX_DESC_CTL0_RTSENA		0x00400000
+#define AR5K_2W_TX_DESC_CTL0_CLRDMASK		0x01000000
+#define AR5K_2W_TX_DESC_CTL0_LONG_PACKET	0x00800000 /*[5210]*/
+#define AR5K_2W_TX_DESC_CTL0_VEOL		0x00800000 /*[5211]*/
+#define AR5K_2W_TX_DESC_CTL0_FRAME_TYPE		0x1c000000 /*[5210]*/
+#define AR5K_2W_TX_DESC_CTL0_FRAME_TYPE_S	26
+#define AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT_5210	0x02000000
+#define AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT_5211	0x1e000000
+
+#define AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT			\
+		(ah->ah_version == AR5K_AR5210 ?		\
+		AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT_5210 :	\
+		AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT_5211)
+
+#define AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT_S	25
+#define AR5K_2W_TX_DESC_CTL0_INTREQ		0x20000000
+#define AR5K_2W_TX_DESC_CTL0_ENCRYPT_KEY_VALID	0x40000000
+
+/* TX control word 1 fields/flags */
+#define AR5K_2W_TX_DESC_CTL1_BUF_LEN		0x00000fff
+#define AR5K_2W_TX_DESC_CTL1_MORE		0x00001000
+#define AR5K_2W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX_5210	0x0007e000
+#define AR5K_2W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX_5211	0x000fe000
+
+#define AR5K_2W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX				\
+			(ah->ah_version == AR5K_AR5210 ?		\
+			AR5K_2W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX_5210 :	\
+			AR5K_2W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX_5211)
+
+#define AR5K_2W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX_S	13
+#define AR5K_2W_TX_DESC_CTL1_FRAME_TYPE		0x00700000 /*[5211]*/
+#define AR5K_2W_TX_DESC_CTL1_FRAME_TYPE_S	20
+#define AR5K_2W_TX_DESC_CTL1_NOACK		0x00800000 /*[5211]*/
+#define AR5K_2W_TX_DESC_CTL1_RTS_DURATION	0xfff80000 /*[5210 ?]*/
+
+/* Frame types */
+#define AR5K_AR5210_TX_DESC_FRAME_TYPE_NORMAL   0x00
+#define AR5K_AR5210_TX_DESC_FRAME_TYPE_ATIM     0x04
+#define AR5K_AR5210_TX_DESC_FRAME_TYPE_PSPOLL   0x08
+#define AR5K_AR5210_TX_DESC_FRAME_TYPE_NO_DELAY 0x0c
+#define AR5K_AR5210_TX_DESC_FRAME_TYPE_PIFS     0x10
+
+/*
+ * 5212 hardware 4-word TX control descriptor
+ */
+struct ath5k_hw_4w_tx_ctl {
+	u32	tx_control_0; /* TX control word 0 */
+
+#define AR5K_4W_TX_DESC_CTL0_FRAME_LEN		0x00000fff
+#define AR5K_4W_TX_DESC_CTL0_XMIT_POWER		0x003f0000
+#define AR5K_4W_TX_DESC_CTL0_XMIT_POWER_S	16
+#define AR5K_4W_TX_DESC_CTL0_RTSENA		0x00400000
+#define AR5K_4W_TX_DESC_CTL0_VEOL		0x00800000
+#define AR5K_4W_TX_DESC_CTL0_CLRDMASK		0x01000000
+#define AR5K_4W_TX_DESC_CTL0_ANT_MODE_XMIT	0x1e000000
+#define AR5K_4W_TX_DESC_CTL0_ANT_MODE_XMIT_S	25
+#define AR5K_4W_TX_DESC_CTL0_INTREQ		0x20000000
+#define AR5K_4W_TX_DESC_CTL0_ENCRYPT_KEY_VALID	0x40000000
+#define AR5K_4W_TX_DESC_CTL0_CTSENA		0x80000000
+
+	u32	tx_control_1; /* TX control word 1 */
+
+#define AR5K_4W_TX_DESC_CTL1_BUF_LEN		0x00000fff
+#define AR5K_4W_TX_DESC_CTL1_MORE		0x00001000
+#define AR5K_4W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX	0x000fe000
+#define AR5K_4W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX_S	13
+#define AR5K_4W_TX_DESC_CTL1_FRAME_TYPE		0x00f00000
+#define AR5K_4W_TX_DESC_CTL1_FRAME_TYPE_S	20
+#define AR5K_4W_TX_DESC_CTL1_NOACK		0x01000000
+#define AR5K_4W_TX_DESC_CTL1_COMP_PROC		0x06000000
+#define AR5K_4W_TX_DESC_CTL1_COMP_PROC_S	25
+#define AR5K_4W_TX_DESC_CTL1_COMP_IV_LEN	0x18000000
+#define AR5K_4W_TX_DESC_CTL1_COMP_IV_LEN_S	27
+#define AR5K_4W_TX_DESC_CTL1_COMP_ICV_LEN	0x60000000
+#define AR5K_4W_TX_DESC_CTL1_COMP_ICV_LEN_S	29
+
+	u32	tx_control_2; /* TX control word 2 */
+
+#define AR5K_4W_TX_DESC_CTL2_RTS_DURATION		0x00007fff
+#define AR5K_4W_TX_DESC_CTL2_DURATION_UPDATE_ENABLE	0x00008000
+#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES0		0x000f0000
+#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES0_S		16
+#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES1		0x00f00000
+#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES1_S		20
+#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES2		0x0f000000
+#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES2_S		24
+#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES3		0xf0000000
+#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES3_S		28
+
+	u32	tx_control_3; /* TX control word 3 */
+
+#define AR5K_4W_TX_DESC_CTL3_XMIT_RATE0		0x0000001f
+#define AR5K_4W_TX_DESC_CTL3_XMIT_RATE1		0x000003e0
+#define AR5K_4W_TX_DESC_CTL3_XMIT_RATE1_S	5
+#define AR5K_4W_TX_DESC_CTL3_XMIT_RATE2		0x00007c00
+#define AR5K_4W_TX_DESC_CTL3_XMIT_RATE2_S	10
+#define AR5K_4W_TX_DESC_CTL3_XMIT_RATE3		0x000f8000
+#define AR5K_4W_TX_DESC_CTL3_XMIT_RATE3_S	15
+#define AR5K_4W_TX_DESC_CTL3_RTS_CTS_RATE	0x01f00000
+#define AR5K_4W_TX_DESC_CTL3_RTS_CTS_RATE_S	20
+} __packed;
+
+/*
+ * Common TX status descriptor
+ */
+struct ath5k_hw_tx_status {
+	u32	tx_status_0; /* TX status word 0 */
+	u32	tx_status_1; /* TX status word 1 */
+} __packed;
+
+/* TX status word 0 fields/flags */
+#define AR5K_DESC_TX_STATUS0_FRAME_XMIT_OK	0x00000001
+#define AR5K_DESC_TX_STATUS0_EXCESSIVE_RETRIES	0x00000002
+#define AR5K_DESC_TX_STATUS0_FIFO_UNDERRUN	0x00000004
+#define AR5K_DESC_TX_STATUS0_FILTERED		0x00000008
+/*???
+#define AR5K_DESC_TX_STATUS0_RTS_FAIL_COUNT	0x000000f0
+#define AR5K_DESC_TX_STATUS0_RTS_FAIL_COUNT_S	4
+*/
+#define AR5K_DESC_TX_STATUS0_SHORT_RETRY_COUNT	0x000000f0
+#define AR5K_DESC_TX_STATUS0_SHORT_RETRY_COUNT_S	4
+/*???
+#define AR5K_DESC_TX_STATUS0_DATA_FAIL_COUNT	0x00000f00
+#define AR5K_DESC_TX_STATUS0_DATA_FAIL_COUNT_S	8
+*/
+#define AR5K_DESC_TX_STATUS0_LONG_RETRY_COUNT	0x00000f00
+#define AR5K_DESC_TX_STATUS0_LONG_RETRY_COUNT_S	8
+#define AR5K_DESC_TX_STATUS0_VIRT_COLL_COUNT	0x0000f000
+#define AR5K_DESC_TX_STATUS0_VIRT_COLL_COUNT_S	12
+#define AR5K_DESC_TX_STATUS0_SEND_TIMESTAMP	0xffff0000
+#define AR5K_DESC_TX_STATUS0_SEND_TIMESTAMP_S	16
+
+/* TX status word 1 fields/flags */
+#define AR5K_DESC_TX_STATUS1_DONE		0x00000001
+#define AR5K_DESC_TX_STATUS1_SEQ_NUM		0x00001ffe
+#define AR5K_DESC_TX_STATUS1_SEQ_NUM_S		1
+#define AR5K_DESC_TX_STATUS1_ACK_SIG_STRENGTH	0x001fe000
+#define AR5K_DESC_TX_STATUS1_ACK_SIG_STRENGTH_S	13
+#define AR5K_DESC_TX_STATUS1_FINAL_TS_INDEX	0x00600000
+#define AR5K_DESC_TX_STATUS1_FINAL_TS_INDEX_S	21
+#define AR5K_DESC_TX_STATUS1_COMP_SUCCESS	0x00800000
+#define AR5K_DESC_TX_STATUS1_XMIT_ANTENNA	0x01000000
+
+/*
+ * 5210/5211 hardware TX descriptor
+ */
+struct ath5k_hw_5210_tx_desc {
+	struct ath5k_hw_2w_tx_ctl	tx_ctl;
+	struct ath5k_hw_tx_status	tx_stat;
+} __packed;
+
+/*
+ * 5212 hardware TX descriptor
+ */
+struct ath5k_hw_5212_tx_desc {
+	struct ath5k_hw_4w_tx_ctl	tx_ctl;
+	struct ath5k_hw_tx_status	tx_stat;
+} __packed;
+
+/*
+ * common hardware RX descriptor
+ */
+struct ath5k_hw_all_rx_desc {
+	struct ath5k_hw_rx_ctl			rx_ctl;
+	union {
+		struct ath5k_hw_rx_status	rx_stat;
+		struct ath5k_hw_rx_error	rx_err;
+	} u;
+} __packed;
+
+/*
+ * Atheros hardware descriptor
+ * This is read and written to by the hardware
+ */
+struct ath5k_desc {
+	u32	ds_link;	/* physical address of the next descriptor */
+	u32	ds_data;	/* physical address of data buffer (skb) */
+
+	union {
+		struct ath5k_hw_5210_tx_desc	ds_tx5210;
+		struct ath5k_hw_5212_tx_desc	ds_tx5212;
+		struct ath5k_hw_all_rx_desc	ds_rx;
+	} ud;
+} __packed;
+
+#define AR5K_RXDESC_INTREQ	0x0020
+
+#define AR5K_TXDESC_CLRDMASK	0x0001
+#define AR5K_TXDESC_NOACK	0x0002	/*[5211+]*/
+#define AR5K_TXDESC_RTSENA	0x0004
+#define AR5K_TXDESC_CTSENA	0x0008
+#define AR5K_TXDESC_INTREQ	0x0010
+#define AR5K_TXDESC_VEOL	0x0020	/*[5211+]*/
+
diff --git a/drivers/net/wireless/ath5k/dma.c b/drivers/net/wireless/ath5k/dma.c
new file mode 100644
index 0000000..7adceb2
--- /dev/null
+++ b/drivers/net/wireless/ath5k/dma.c
@@ -0,0 +1,605 @@
+/*
+ * Copyright (c) 2004-2008 Reyk Floeter <reyk@openbsd.org>
+ * Copyright (c) 2006-2008 Nick Kossifidis <mickflemm@gmail.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+/*************************************\
+* DMA and interrupt masking functions *
+\*************************************/
+
+/*
+ * dma.c - DMA and interrupt masking functions
+ *
+ * Here we setup descriptor pointers (rxdp/txdp) start/stop dma engine and
+ * handle queue setup for 5210 chipset (rest are handled on qcu.c).
+ * Also we setup interrupt mask register (IMR) and read the various iterrupt
+ * status registers (ISR).
+ *
+ * TODO: Handle SISR on 5211+ and introduce a function to return the queue
+ * number that resulted the interrupt.
+ */
+
+#include "ath5k.h"
+#include "reg.h"
+#include "debug.h"
+#include "base.h"
+
+/*********\
+* Receive *
+\*********/
+
+/**
+ * ath5k_hw_start_rx_dma - Start DMA receive
+ *
+ * @ah:	The &struct ath5k_hw
+ */
+void ath5k_hw_start_rx_dma(struct ath5k_hw *ah)
+{
+	ATH5K_TRACE(ah->ah_sc);
+	ath5k_hw_reg_write(ah, AR5K_CR_RXE, AR5K_CR);
+	ath5k_hw_reg_read(ah, AR5K_CR);
+}
+
+/**
+ * ath5k_hw_stop_rx_dma - Stop DMA receive
+ *
+ * @ah:	The &struct ath5k_hw
+ */
+int ath5k_hw_stop_rx_dma(struct ath5k_hw *ah)
+{
+	unsigned int i;
+
+	ATH5K_TRACE(ah->ah_sc);
+	ath5k_hw_reg_write(ah, AR5K_CR_RXD, AR5K_CR);
+
+	/*
+	 * It may take some time to disable the DMA receive unit
+	 */
+	for (i = 1000; i > 0 &&
+			(ath5k_hw_reg_read(ah, AR5K_CR) & AR5K_CR_RXE) != 0;
+			i--)
+		udelay(10);
+
+	return i ? 0 : -EBUSY;
+}
+
+/**
+ * ath5k_hw_get_rxdp - Get RX Descriptor's address
+ *
+ * @ah: The &struct ath5k_hw
+ *
+ * XXX: Is RXDP read and clear ?
+ */
+u32 ath5k_hw_get_rxdp(struct ath5k_hw *ah)
+{
+	return ath5k_hw_reg_read(ah, AR5K_RXDP);
+}
+
+/**
+ * ath5k_hw_set_rxdp - Set RX Descriptor's address
+ *
+ * @ah: The &struct ath5k_hw
+ * @phys_addr: RX descriptor address
+ *
+ * XXX: Should we check if rx is enabled before setting rxdp ?
+ */
+void ath5k_hw_set_rxdp(struct ath5k_hw *ah, u32 phys_addr)
+{
+	ATH5K_TRACE(ah->ah_sc);
+
+	ath5k_hw_reg_write(ah, phys_addr, AR5K_RXDP);
+}
+
+
+/**********\
+* Transmit *
+\**********/
+
+/**
+ * ath5k_hw_start_tx_dma - Start DMA transmit for a specific queue
+ *
+ * @ah: The &struct ath5k_hw
+ * @queue: The hw queue number
+ *
+ * Start DMA transmit for a specific queue and since 5210 doesn't have
+ * QCU/DCU, set up queue parameters for 5210 here based on queue type (one
+ * queue for normal data and one queue for beacons). For queue setup
+ * on newer chips check out qcu.c. Returns -EINVAL if queue number is out
+ * of range or if queue is already disabled.
+ *
+ * NOTE: Must be called after setting up tx control descriptor for that
+ * queue (see below).
+ */
+int ath5k_hw_start_tx_dma(struct ath5k_hw *ah, unsigned int queue)
+{
+	u32 tx_queue;
+
+	ATH5K_TRACE(ah->ah_sc);
+	AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num);
+
+	/* Return if queue is declared inactive */
+	if (ah->ah_txq[queue].tqi_type == AR5K_TX_QUEUE_INACTIVE)
+		return -EIO;
+
+	if (ah->ah_version == AR5K_AR5210) {
+		tx_queue = ath5k_hw_reg_read(ah, AR5K_CR);
+
+		/*
+		 * Set the queue by type on 5210
+		 */
+		switch (ah->ah_txq[queue].tqi_type) {
+		case AR5K_TX_QUEUE_DATA:
+			tx_queue |= AR5K_CR_TXE0 & ~AR5K_CR_TXD0;
+			break;
+		case AR5K_TX_QUEUE_BEACON:
+			tx_queue |= AR5K_CR_TXE1 & ~AR5K_CR_TXD1;
+			ath5k_hw_reg_write(ah, AR5K_BCR_TQ1V | AR5K_BCR_BDMAE,
+					AR5K_BSR);
+			break;
+		case AR5K_TX_QUEUE_CAB:
+			tx_queue |= AR5K_CR_TXE1 & ~AR5K_CR_TXD1;
+			ath5k_hw_reg_write(ah, AR5K_BCR_TQ1FV | AR5K_BCR_TQ1V |
+				AR5K_BCR_BDMAE, AR5K_BSR);
+			break;
+		default:
+			return -EINVAL;
+		}
+		/* Start queue */
+		ath5k_hw_reg_write(ah, tx_queue, AR5K_CR);
+		ath5k_hw_reg_read(ah, AR5K_CR);
+	} else {
+		/* Return if queue is disabled */
+		if (AR5K_REG_READ_Q(ah, AR5K_QCU_TXD, queue))
+			return -EIO;
+
+		/* Start queue */
+		AR5K_REG_WRITE_Q(ah, AR5K_QCU_TXE, queue);
+	}
+
+	return 0;
+}
+
+/**
+ * ath5k_hw_stop_tx_dma - Stop DMA transmit on a specific queue
+ *
+ * @ah: The &struct ath5k_hw
+ * @queue: The hw queue number
+ *
+ * Stop DMA transmit on a specific hw queue and drain queue so we don't
+ * have any pending frames. Returns -EBUSY if we still have pending frames,
+ * -EINVAL if queue number is out of range.
+ *
+ */
+int ath5k_hw_stop_tx_dma(struct ath5k_hw *ah, unsigned int queue)
+{
+	unsigned int i = 40;
+	u32 tx_queue, pending;
+
+	ATH5K_TRACE(ah->ah_sc);
+	AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num);
+
+	/* Return if queue is declared inactive */
+	if (ah->ah_txq[queue].tqi_type == AR5K_TX_QUEUE_INACTIVE)
+		return -EIO;
+
+	if (ah->ah_version == AR5K_AR5210) {
+		tx_queue = ath5k_hw_reg_read(ah, AR5K_CR);
+
+		/*
+		 * Set by queue type
+		 */
+		switch (ah->ah_txq[queue].tqi_type) {
+		case AR5K_TX_QUEUE_DATA:
+			tx_queue |= AR5K_CR_TXD0 & ~AR5K_CR_TXE0;
+			break;
+		case AR5K_TX_QUEUE_BEACON:
+		case AR5K_TX_QUEUE_CAB:
+			/* XXX Fix me... */
+			tx_queue |= AR5K_CR_TXD1 & ~AR5K_CR_TXD1;
+			ath5k_hw_reg_write(ah, 0, AR5K_BSR);
+			break;
+		default:
+			return -EINVAL;
+		}
+
+		/* Stop queue */
+		ath5k_hw_reg_write(ah, tx_queue, AR5K_CR);
+		ath5k_hw_reg_read(ah, AR5K_CR);
+	} else {
+		/*
+		 * Schedule TX disable and wait until queue is empty
+		 */
+		AR5K_REG_WRITE_Q(ah, AR5K_QCU_TXD, queue);
+
+		/*Check for pending frames*/
+		do {
+			pending = ath5k_hw_reg_read(ah,
+				AR5K_QUEUE_STATUS(queue)) &
+				AR5K_QCU_STS_FRMPENDCNT;
+			udelay(100);
+		} while (--i && pending);
+
+		/* For 2413+ order PCU to drop packets using
+		 * QUIET mechanism */
+		if (ah->ah_mac_version >= (AR5K_SREV_AR2414 >> 4) &&
+		pending){
+			/* Set periodicity and duration */
+			ath5k_hw_reg_write(ah,
+				AR5K_REG_SM(100, AR5K_QUIET_CTL2_QT_PER)|
+				AR5K_REG_SM(10, AR5K_QUIET_CTL2_QT_DUR),
+				AR5K_QUIET_CTL2);
+
+			/* Enable quiet period for current TSF */
+			ath5k_hw_reg_write(ah,
+				AR5K_QUIET_CTL1_QT_EN |
+				AR5K_REG_SM(ath5k_hw_reg_read(ah,
+						AR5K_TSF_L32_5211) >> 10,
+						AR5K_QUIET_CTL1_NEXT_QT_TSF),
+				AR5K_QUIET_CTL1);
+
+			/* Force channel idle high */
+			AR5K_REG_ENABLE_BITS(ah, AR5K_DIAG_SW_5211,
+					AR5K_DIAG_SW_CHANEL_IDLE_HIGH);
+
+			/* Wait a while and disable mechanism */
+			udelay(200);
+			AR5K_REG_DISABLE_BITS(ah, AR5K_QUIET_CTL1,
+						AR5K_QUIET_CTL1_QT_EN);
+
+			/* Re-check for pending frames */
+			i = 40;
+			do {
+				pending = ath5k_hw_reg_read(ah,
+					AR5K_QUEUE_STATUS(queue)) &
+					AR5K_QCU_STS_FRMPENDCNT;
+				udelay(100);
+			} while (--i && pending);
+
+			AR5K_REG_DISABLE_BITS(ah, AR5K_DIAG_SW_5211,
+					AR5K_DIAG_SW_CHANEL_IDLE_HIGH);
+		}
+
+		/* Clear register */
+		ath5k_hw_reg_write(ah, 0, AR5K_QCU_TXD);
+		if (pending)
+			return -EBUSY;
+	}
+
+	/* TODO: Check for success on 5210 else return error */
+	return 0;
+}
+
+/**
+ * ath5k_hw_get_txdp - Get TX Descriptor's address for a specific queue
+ *
+ * @ah: The &struct ath5k_hw
+ * @queue: The hw queue number
+ *
+ * Get TX descriptor's address for a specific queue. For 5210 we ignore
+ * the queue number and use tx queue type since we only have 2 queues.
+ * We use TXDP0 for normal data queue and TXDP1 for beacon queue.
+ * For newer chips with QCU/DCU we just read the corresponding TXDP register.
+ *
+ * XXX: Is TXDP read and clear ?
+ */
+u32 ath5k_hw_get_txdp(struct ath5k_hw *ah, unsigned int queue)
+{
+	u16 tx_reg;
+
+	ATH5K_TRACE(ah->ah_sc);
+	AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num);
+
+	/*
+	 * Get the transmit queue descriptor pointer from the selected queue
+	 */
+	/*5210 doesn't have QCU*/
+	if (ah->ah_version == AR5K_AR5210) {
+		switch (ah->ah_txq[queue].tqi_type) {
+		case AR5K_TX_QUEUE_DATA:
+			tx_reg = AR5K_NOQCU_TXDP0;
+			break;
+		case AR5K_TX_QUEUE_BEACON:
+		case AR5K_TX_QUEUE_CAB:
+			tx_reg = AR5K_NOQCU_TXDP1;
+			break;
+		default:
+			return 0xffffffff;
+		}
+	} else {
+		tx_reg = AR5K_QUEUE_TXDP(queue);
+	}
+
+	return ath5k_hw_reg_read(ah, tx_reg);
+}
+
+/**
+ * ath5k_hw_set_txdp - Set TX Descriptor's address for a specific queue
+ *
+ * @ah: The &struct ath5k_hw
+ * @queue: The hw queue number
+ *
+ * Set TX descriptor's address for a specific queue. For 5210 we ignore
+ * the queue number and we use tx queue type since we only have 2 queues
+ * so as above we use TXDP0 for normal data queue and TXDP1 for beacon queue.
+ * For newer chips with QCU/DCU we just set the corresponding TXDP register.
+ * Returns -EINVAL if queue type is invalid for 5210 and -EIO if queue is still
+ * active.
+ */
+int ath5k_hw_set_txdp(struct ath5k_hw *ah, unsigned int queue, u32 phys_addr)
+{
+	u16 tx_reg;
+
+	ATH5K_TRACE(ah->ah_sc);
+	AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num);
+
+	/*
+	 * Set the transmit queue descriptor pointer register by type
+	 * on 5210
+	 */
+	if (ah->ah_version == AR5K_AR5210) {
+		switch (ah->ah_txq[queue].tqi_type) {
+		case AR5K_TX_QUEUE_DATA:
+			tx_reg = AR5K_NOQCU_TXDP0;
+			break;
+		case AR5K_TX_QUEUE_BEACON:
+		case AR5K_TX_QUEUE_CAB:
+			tx_reg = AR5K_NOQCU_TXDP1;
+			break;
+		default:
+			return -EINVAL;
+		}
+	} else {
+		/*
+		 * Set the transmit queue descriptor pointer for
+		 * the selected queue on QCU for 5211+
+		 * (this won't work if the queue is still active)
+		 */
+		if (AR5K_REG_READ_Q(ah, AR5K_QCU_TXE, queue))
+			return -EIO;
+
+		tx_reg = AR5K_QUEUE_TXDP(queue);
+	}
+
+	/* Set descriptor pointer */
+	ath5k_hw_reg_write(ah, phys_addr, tx_reg);
+
+	return 0;
+}
+
+/**
+ * ath5k_hw_update_tx_triglevel - Update tx trigger level
+ *
+ * @ah: The &struct ath5k_hw
+ * @increase: Flag to force increase of trigger level
+ *
+ * This function increases/decreases the tx trigger level for the tx fifo
+ * buffer (aka FIFO threshold) that is used to indicate when PCU flushes
+ * the buffer and transmits it's data. Lowering this results sending small
+ * frames more quickly but can lead to tx underruns, raising it a lot can
+ * result other problems (i think bmiss is related). Right now we start with
+ * the lowest possible (64Bytes) and if we get tx underrun we increase it using
+ * the increase flag. Returns -EIO if we have have reached maximum/minimum.
+ *
+ * XXX: Link this with tx DMA size ?
+ * XXX: Use it to save interrupts ?
+ * TODO: Needs testing, i think it's related to bmiss...
+ */
+int ath5k_hw_update_tx_triglevel(struct ath5k_hw *ah, bool increase)
+{
+	u32 trigger_level, imr;
+	int ret = -EIO;
+
+	ATH5K_TRACE(ah->ah_sc);
+
+	/*
+	 * Disable interrupts by setting the mask
+	 */
+	imr = ath5k_hw_set_imr(ah, ah->ah_imr & ~AR5K_INT_GLOBAL);
+
+	trigger_level = AR5K_REG_MS(ath5k_hw_reg_read(ah, AR5K_TXCFG),
+			AR5K_TXCFG_TXFULL);
+
+	if (!increase) {
+		if (--trigger_level < AR5K_TUNE_MIN_TX_FIFO_THRES)
+			goto done;
+	} else
+		trigger_level +=
+			((AR5K_TUNE_MAX_TX_FIFO_THRES - trigger_level) / 2);
+
+	/*
+	 * Update trigger level on success
+	 */
+	if (ah->ah_version == AR5K_AR5210)
+		ath5k_hw_reg_write(ah, trigger_level, AR5K_TRIG_LVL);
+	else
+		AR5K_REG_WRITE_BITS(ah, AR5K_TXCFG,
+				AR5K_TXCFG_TXFULL, trigger_level);
+
+	ret = 0;
+
+done:
+	/*
+	 * Restore interrupt mask
+	 */
+	ath5k_hw_set_imr(ah, imr);
+
+	return ret;
+}
+
+/*******************\
+* Interrupt masking *
+\*******************/
+
+/**
+ * ath5k_hw_is_intr_pending - Check if we have pending interrupts
+ *
+ * @ah: The &struct ath5k_hw
+ *
+ * Check if we have pending interrupts to process. Returns 1 if we
+ * have pending interrupts and 0 if we haven't.
+ */
+bool ath5k_hw_is_intr_pending(struct ath5k_hw *ah)
+{
+	ATH5K_TRACE(ah->ah_sc);
+	return ath5k_hw_reg_read(ah, AR5K_INTPEND) == 1 ? 1 : 0;
+}
+
+/**
+ * ath5k_hw_get_isr - Get interrupt status
+ *
+ * @ah: The @struct ath5k_hw
+ * @interrupt_mask: Driver's interrupt mask used to filter out
+ * interrupts in sw.
+ *
+ * This function is used inside our interrupt handler to determine the reason
+ * for the interrupt by reading Primary Interrupt Status Register. Returns an
+ * abstract interrupt status mask which is mostly ISR with some uncommon bits
+ * being mapped on some standard non hw-specific positions
+ * (check out &ath5k_int).
+ *
+ * NOTE: We use read-and-clear register, so after this function is called ISR
+ * is zeroed.
+ *
+ * XXX: Why filter interrupts in sw with interrupt_mask ? No benefit at all
+ * plus it can be misleading (one might thing that we save interrupts this way)
+ */
+int ath5k_hw_get_isr(struct ath5k_hw *ah, enum ath5k_int *interrupt_mask)
+{
+	u32 data;
+
+	ATH5K_TRACE(ah->ah_sc);
+
+	/*
+	 * Read interrupt status from the Interrupt Status register
+	 * on 5210
+	 */
+	if (ah->ah_version == AR5K_AR5210) {
+		data = ath5k_hw_reg_read(ah, AR5K_ISR);
+		if (unlikely(data == AR5K_INT_NOCARD)) {
+			*interrupt_mask = data;
+			return -ENODEV;
+		}
+	} else {
+		/*
+		 * Read interrupt status from the Read-And-Clear
+		 * shadow register.
+		 * Note: PISR/SISR Not available on 5210
+		 */
+		data = ath5k_hw_reg_read(ah, AR5K_RAC_PISR);
+	}
+
+	/*
+	 * Get abstract interrupt mask (driver-compatible)
+	 */
+	*interrupt_mask = (data & AR5K_INT_COMMON) & ah->ah_imr;
+
+	if (unlikely(data == AR5K_INT_NOCARD))
+		return -ENODEV;
+
+	if (data & (AR5K_ISR_RXOK | AR5K_ISR_RXERR))
+		*interrupt_mask |= AR5K_INT_RX;
+
+	if (data & (AR5K_ISR_TXOK | AR5K_ISR_TXERR
+		| AR5K_ISR_TXDESC | AR5K_ISR_TXEOL))
+		*interrupt_mask |= AR5K_INT_TX;
+
+	if (ah->ah_version != AR5K_AR5210) {
+		/*HIU = Host Interface Unit (PCI etc)*/
+		if (unlikely(data & (AR5K_ISR_HIUERR)))
+			*interrupt_mask |= AR5K_INT_FATAL;
+
+		/*Beacon Not Ready*/
+		if (unlikely(data & (AR5K_ISR_BNR)))
+			*interrupt_mask |= AR5K_INT_BNR;
+	}
+
+	/*
+	 * XXX: BMISS interrupts may occur after association.
+	 * I found this on 5210 code but it needs testing. If this is
+	 * true we should disable them before assoc and re-enable them
+	 * after a successfull assoc + some jiffies.
+	 */
+#if 0
+	interrupt_mask &= ~AR5K_INT_BMISS;
+#endif
+
+	/*
+	 * In case we didn't handle anything,
+	 * print the register value.
+	 */
+	if (unlikely(*interrupt_mask == 0 && net_ratelimit()))
+		ATH5K_PRINTF("0x%08x\n", data);
+
+	return 0;
+}
+
+/**
+ * ath5k_hw_set_imr - Set interrupt mask
+ *
+ * @ah: The &struct ath5k_hw
+ * @new_mask: The new interrupt mask to be set
+ *
+ * Set the interrupt mask in hw to save interrupts. We do that by mapping
+ * ath5k_int bits to hw-specific bits to remove abstraction and writing
+ * Interrupt Mask Register.
+ */
+enum ath5k_int ath5k_hw_set_imr(struct ath5k_hw *ah, enum ath5k_int new_mask)
+{
+	enum ath5k_int old_mask, int_mask;
+
+	/*
+	 * Disable card interrupts to prevent any race conditions
+	 * (they will be re-enabled afterwards).
+	 */
+	ath5k_hw_reg_write(ah, AR5K_IER_DISABLE, AR5K_IER);
+	ath5k_hw_reg_read(ah, AR5K_IER);
+
+	old_mask = ah->ah_imr;
+
+	/*
+	 * Add additional, chipset-dependent interrupt mask flags
+	 * and write them to the IMR (interrupt mask register).
+	 */
+	int_mask = new_mask & AR5K_INT_COMMON;
+
+	if (new_mask & AR5K_INT_RX)
+		int_mask |= AR5K_IMR_RXOK | AR5K_IMR_RXERR | AR5K_IMR_RXORN |
+			AR5K_IMR_RXDESC;
+
+	if (new_mask & AR5K_INT_TX)
+		int_mask |= AR5K_IMR_TXOK | AR5K_IMR_TXERR | AR5K_IMR_TXDESC |
+			AR5K_IMR_TXURN;
+
+	if (ah->ah_version != AR5K_AR5210) {
+		if (new_mask & AR5K_INT_FATAL) {
+			int_mask |= AR5K_IMR_HIUERR;
+			AR5K_REG_ENABLE_BITS(ah, AR5K_SIMR2, AR5K_SIMR2_MCABT |
+					AR5K_SIMR2_SSERR | AR5K_SIMR2_DPERR);
+		}
+	}
+
+	ath5k_hw_reg_write(ah, int_mask, AR5K_PIMR);
+
+	/* Store new interrupt mask */
+	ah->ah_imr = new_mask;
+
+	/* ..re-enable interrupts */
+	ath5k_hw_reg_write(ah, AR5K_IER_ENABLE, AR5K_IER);
+	ath5k_hw_reg_read(ah, AR5K_IER);
+
+	return old_mask;
+}
+
diff --git a/drivers/net/wireless/ath5k/eeprom.c b/drivers/net/wireless/ath5k/eeprom.c
new file mode 100644
index 0000000..a883839
--- /dev/null
+++ b/drivers/net/wireless/ath5k/eeprom.c
@@ -0,0 +1,466 @@
+/*
+ * Copyright (c) 2004-2008 Reyk Floeter <reyk@openbsd.org>
+ * Copyright (c) 2006-2008 Nick Kossifidis <mickflemm@gmail.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+/*************************************\
+* EEPROM access functions and helpers *
+\*************************************/
+
+#include "ath5k.h"
+#include "reg.h"
+#include "debug.h"
+#include "base.h"
+
+/*
+ * Read from eeprom
+ */
+static int ath5k_hw_eeprom_read(struct ath5k_hw *ah, u32 offset, u16 *data)
+{
+	u32 status, timeout;
+
+	ATH5K_TRACE(ah->ah_sc);
+	/*
+	 * Initialize EEPROM access
+	 */
+	if (ah->ah_version == AR5K_AR5210) {
+		AR5K_REG_ENABLE_BITS(ah, AR5K_PCICFG, AR5K_PCICFG_EEAE);
+		(void)ath5k_hw_reg_read(ah, AR5K_EEPROM_BASE + (4 * offset));
+	} else {
+		ath5k_hw_reg_write(ah, offset, AR5K_EEPROM_BASE);
+		AR5K_REG_ENABLE_BITS(ah, AR5K_EEPROM_CMD,
+				AR5K_EEPROM_CMD_READ);
+	}
+
+	for (timeout = AR5K_TUNE_REGISTER_TIMEOUT; timeout > 0; timeout--) {
+		status = ath5k_hw_reg_read(ah, AR5K_EEPROM_STATUS);
+		if (status & AR5K_EEPROM_STAT_RDDONE) {
+			if (status & AR5K_EEPROM_STAT_RDERR)
+				return -EIO;
+			*data = (u16)(ath5k_hw_reg_read(ah, AR5K_EEPROM_DATA) &
+					0xffff);
+			return 0;
+		}
+		udelay(15);
+	}
+
+	return -ETIMEDOUT;
+}
+
+/*
+ * Translate binary channel representation in EEPROM to frequency
+ */
+static u16 ath5k_eeprom_bin2freq(struct ath5k_hw *ah, u16 bin,
+				unsigned int mode)
+{
+	u16 val;
+
+	if (bin == AR5K_EEPROM_CHANNEL_DIS)
+		return bin;
+
+	if (mode == AR5K_EEPROM_MODE_11A) {
+		if (ah->ah_ee_version > AR5K_EEPROM_VERSION_3_2)
+			val = (5 * bin) + 4800;
+		else
+			val = bin > 62 ? (10 * 62) + (5 * (bin - 62)) + 5100 :
+				(bin * 10) + 5100;
+	} else {
+		if (ah->ah_ee_version > AR5K_EEPROM_VERSION_3_2)
+			val = bin + 2300;
+		else
+			val = bin + 2400;
+	}
+
+	return val;
+}
+
+/*
+ * Read antenna infos from eeprom
+ */
+static int ath5k_eeprom_read_ants(struct ath5k_hw *ah, u32 *offset,
+		unsigned int mode)
+{
+	struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
+	u32 o = *offset;
+	u16 val;
+	int ret, i = 0;
+
+	AR5K_EEPROM_READ(o++, val);
+	ee->ee_switch_settling[mode]	= (val >> 8) & 0x7f;
+	ee->ee_ant_tx_rx[mode]		= (val >> 2) & 0x3f;
+	ee->ee_ant_control[mode][i]	= (val << 4) & 0x3f;
+
+	AR5K_EEPROM_READ(o++, val);
+	ee->ee_ant_control[mode][i++]	|= (val >> 12) & 0xf;
+	ee->ee_ant_control[mode][i++]	= (val >> 6) & 0x3f;
+	ee->ee_ant_control[mode][i++]	= val & 0x3f;
+
+	AR5K_EEPROM_READ(o++, val);
+	ee->ee_ant_control[mode][i++]	= (val >> 10) & 0x3f;
+	ee->ee_ant_control[mode][i++]	= (val >> 4) & 0x3f;
+	ee->ee_ant_control[mode][i]	= (val << 2) & 0x3f;
+
+	AR5K_EEPROM_READ(o++, val);
+	ee->ee_ant_control[mode][i++]	|= (val >> 14) & 0x3;
+	ee->ee_ant_control[mode][i++]	= (val >> 8) & 0x3f;
+	ee->ee_ant_control[mode][i++]	= (val >> 2) & 0x3f;
+	ee->ee_ant_control[mode][i]	= (val << 4) & 0x3f;
+
+	AR5K_EEPROM_READ(o++, val);
+	ee->ee_ant_control[mode][i++]	|= (val >> 12) & 0xf;
+	ee->ee_ant_control[mode][i++]	= (val >> 6) & 0x3f;
+	ee->ee_ant_control[mode][i++]	= val & 0x3f;
+
+	/* Get antenna modes */
+	ah->ah_antenna[mode][0] =
+	    (ee->ee_ant_control[mode][0] << 4) | 0x1;
+	ah->ah_antenna[mode][AR5K_ANT_FIXED_A] =
+	     ee->ee_ant_control[mode][1] 	|
+	    (ee->ee_ant_control[mode][2] << 6) 	|
+	    (ee->ee_ant_control[mode][3] << 12) |
+	    (ee->ee_ant_control[mode][4] << 18) |
+	    (ee->ee_ant_control[mode][5] << 24);
+	ah->ah_antenna[mode][AR5K_ANT_FIXED_B] =
+	     ee->ee_ant_control[mode][6] 	|
+	    (ee->ee_ant_control[mode][7] << 6) 	|
+	    (ee->ee_ant_control[mode][8] << 12) |
+	    (ee->ee_ant_control[mode][9] << 18) |
+	    (ee->ee_ant_control[mode][10] << 24);
+
+	/* return new offset */
+	*offset = o;
+
+	return 0;
+}
+
+/*
+ * Read supported modes from eeprom
+ */
+static int ath5k_eeprom_read_modes(struct ath5k_hw *ah, u32 *offset,
+		unsigned int mode)
+{
+	struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
+	u32 o = *offset;
+	u16 val;
+	int ret;
+
+	AR5K_EEPROM_READ(o++, val);
+	ee->ee_tx_end2xlna_enable[mode]	= (val >> 8) & 0xff;
+	ee->ee_thr_62[mode]		= val & 0xff;
+
+	if (ah->ah_ee_version <= AR5K_EEPROM_VERSION_3_2)
+		ee->ee_thr_62[mode] = mode == AR5K_EEPROM_MODE_11A ? 15 : 28;
+
+	AR5K_EEPROM_READ(o++, val);
+	ee->ee_tx_end2xpa_disable[mode]	= (val >> 8) & 0xff;
+	ee->ee_tx_frm2xpa_enable[mode]	= val & 0xff;
+
+	AR5K_EEPROM_READ(o++, val);
+	ee->ee_pga_desired_size[mode]	= (val >> 8) & 0xff;
+
+	if ((val & 0xff) & 0x80)
+		ee->ee_noise_floor_thr[mode] = -((((val & 0xff) ^ 0xff)) + 1);
+	else
+		ee->ee_noise_floor_thr[mode] = val & 0xff;
+
+	if (ah->ah_ee_version <= AR5K_EEPROM_VERSION_3_2)
+		ee->ee_noise_floor_thr[mode] =
+		    mode == AR5K_EEPROM_MODE_11A ? -54 : -1;
+
+	AR5K_EEPROM_READ(o++, val);
+	ee->ee_xlna_gain[mode]		= (val >> 5) & 0xff;
+	ee->ee_x_gain[mode]		= (val >> 1) & 0xf;
+	ee->ee_xpd[mode]		= val & 0x1;
+
+	if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0)
+		ee->ee_fixed_bias[mode] = (val >> 13) & 0x1;
+
+	if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_3_3) {
+		AR5K_EEPROM_READ(o++, val);
+		ee->ee_false_detect[mode] = (val >> 6) & 0x7f;
+
+		if (mode == AR5K_EEPROM_MODE_11A)
+			ee->ee_xr_power[mode] = val & 0x3f;
+		else {
+			ee->ee_ob[mode][0] = val & 0x7;
+			ee->ee_db[mode][0] = (val >> 3) & 0x7;
+		}
+	}
+
+	if (ah->ah_ee_version < AR5K_EEPROM_VERSION_3_4) {
+		ee->ee_i_gain[mode] = AR5K_EEPROM_I_GAIN;
+		ee->ee_cck_ofdm_power_delta = AR5K_EEPROM_CCK_OFDM_DELTA;
+	} else {
+		ee->ee_i_gain[mode] = (val >> 13) & 0x7;
+
+		AR5K_EEPROM_READ(o++, val);
+		ee->ee_i_gain[mode] |= (val << 3) & 0x38;
+
+		if (mode == AR5K_EEPROM_MODE_11G)
+			ee->ee_cck_ofdm_power_delta = (val >> 3) & 0xff;
+	}
+
+	if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0 &&
+			mode == AR5K_EEPROM_MODE_11A) {
+		ee->ee_i_cal[mode] = (val >> 8) & 0x3f;
+		ee->ee_q_cal[mode] = (val >> 3) & 0x1f;
+	}
+
+	if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_6 &&
+	    mode == AR5K_EEPROM_MODE_11G)
+		ee->ee_scaled_cck_delta = (val >> 11) & 0x1f;
+
+	/* return new offset */
+	*offset = o;
+
+	return 0;
+}
+
+/*
+ * Initialize eeprom & capabilities structs
+ */
+int ath5k_eeprom_init(struct ath5k_hw *ah)
+{
+	struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
+	unsigned int mode, i;
+	int ret;
+	u32 offset;
+	u16 val;
+
+	/* Initial TX thermal adjustment values */
+	ee->ee_tx_clip = 4;
+	ee->ee_pwd_84 = ee->ee_pwd_90 = 1;
+	ee->ee_gain_select = 1;
+
+	/*
+	 * Read values from EEPROM and store them in the capability structure
+	 */
+	AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MAGIC, ee_magic);
+	AR5K_EEPROM_READ_HDR(AR5K_EEPROM_PROTECT, ee_protect);
+	AR5K_EEPROM_READ_HDR(AR5K_EEPROM_REG_DOMAIN, ee_regdomain);
+	AR5K_EEPROM_READ_HDR(AR5K_EEPROM_VERSION, ee_version);
+	AR5K_EEPROM_READ_HDR(AR5K_EEPROM_HDR, ee_header);
+
+	/* Return if we have an old EEPROM */
+	if (ah->ah_ee_version < AR5K_EEPROM_VERSION_3_0)
+		return 0;
+
+#ifdef notyet
+	/*
+	 * Validate the checksum of the EEPROM date. There are some
+	 * devices with invalid EEPROMs.
+	 */
+	for (cksum = 0, offset = 0; offset < AR5K_EEPROM_INFO_MAX; offset++) {
+		AR5K_EEPROM_READ(AR5K_EEPROM_INFO(offset), val);
+		cksum ^= val;
+	}
+	if (cksum != AR5K_EEPROM_INFO_CKSUM) {
+		ATH5K_ERR(ah->ah_sc, "Invalid EEPROM checksum 0x%04x\n", cksum);
+		return -EIO;
+	}
+#endif
+
+	AR5K_EEPROM_READ_HDR(AR5K_EEPROM_ANT_GAIN(ah->ah_ee_version),
+	    ee_ant_gain);
+
+	if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0) {
+		AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC0, ee_misc0);
+		AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC1, ee_misc1);
+	}
+
+	if (ah->ah_ee_version < AR5K_EEPROM_VERSION_3_3) {
+		AR5K_EEPROM_READ(AR5K_EEPROM_OBDB0_2GHZ, val);
+		ee->ee_ob[AR5K_EEPROM_MODE_11B][0] = val & 0x7;
+		ee->ee_db[AR5K_EEPROM_MODE_11B][0] = (val >> 3) & 0x7;
+
+		AR5K_EEPROM_READ(AR5K_EEPROM_OBDB1_2GHZ, val);
+		ee->ee_ob[AR5K_EEPROM_MODE_11G][0] = val & 0x7;
+		ee->ee_db[AR5K_EEPROM_MODE_11G][0] = (val >> 3) & 0x7;
+	}
+
+	/*
+	 * Get conformance test limit values
+	 */
+	offset = AR5K_EEPROM_CTL(ah->ah_ee_version);
+	ee->ee_ctls = AR5K_EEPROM_N_CTLS(ah->ah_ee_version);
+
+	for (i = 0; i < ee->ee_ctls; i++) {
+		AR5K_EEPROM_READ(offset++, val);
+		ee->ee_ctl[i] = (val >> 8) & 0xff;
+		ee->ee_ctl[i + 1] = val & 0xff;
+	}
+
+	/*
+	 * Get values for 802.11a (5GHz)
+	 */
+	mode = AR5K_EEPROM_MODE_11A;
+
+	ee->ee_turbo_max_power[mode] =
+			AR5K_EEPROM_HDR_T_5GHZ_DBM(ee->ee_header);
+
+	offset = AR5K_EEPROM_MODES_11A(ah->ah_ee_version);
+
+	ret = ath5k_eeprom_read_ants(ah, &offset, mode);
+	if (ret)
+		return ret;
+
+	AR5K_EEPROM_READ(offset++, val);
+	ee->ee_adc_desired_size[mode]	= (s8)((val >> 8) & 0xff);
+	ee->ee_ob[mode][3]		= (val >> 5) & 0x7;
+	ee->ee_db[mode][3]		= (val >> 2) & 0x7;
+	ee->ee_ob[mode][2]		= (val << 1) & 0x7;
+
+	AR5K_EEPROM_READ(offset++, val);
+	ee->ee_ob[mode][2]		|= (val >> 15) & 0x1;
+	ee->ee_db[mode][2]		= (val >> 12) & 0x7;
+	ee->ee_ob[mode][1]		= (val >> 9) & 0x7;
+	ee->ee_db[mode][1]		= (val >> 6) & 0x7;
+	ee->ee_ob[mode][0]		= (val >> 3) & 0x7;
+	ee->ee_db[mode][0]		= val & 0x7;
+
+	ret = ath5k_eeprom_read_modes(ah, &offset, mode);
+	if (ret)
+		return ret;
+
+	if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_1) {
+		AR5K_EEPROM_READ(offset++, val);
+		ee->ee_margin_tx_rx[mode] = val & 0x3f;
+	}
+
+	/*
+	 * Get values for 802.11b (2.4GHz)
+	 */
+	mode = AR5K_EEPROM_MODE_11B;
+	offset = AR5K_EEPROM_MODES_11B(ah->ah_ee_version);
+
+	ret = ath5k_eeprom_read_ants(ah, &offset, mode);
+	if (ret)
+		return ret;
+
+	AR5K_EEPROM_READ(offset++, val);
+	ee->ee_adc_desired_size[mode]	= (s8)((val >> 8) & 0xff);
+	ee->ee_ob[mode][1]		= (val >> 4) & 0x7;
+	ee->ee_db[mode][1]		= val & 0x7;
+
+	ret = ath5k_eeprom_read_modes(ah, &offset, mode);
+	if (ret)
+		return ret;
+
+	if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0) {
+		AR5K_EEPROM_READ(offset++, val);
+		ee->ee_cal_pier[mode][0] =
+			ath5k_eeprom_bin2freq(ah, val & 0xff, mode);
+		ee->ee_cal_pier[mode][1] =
+			ath5k_eeprom_bin2freq(ah, (val >> 8) & 0xff, mode);
+
+		AR5K_EEPROM_READ(offset++, val);
+		ee->ee_cal_pier[mode][2] =
+			ath5k_eeprom_bin2freq(ah, val & 0xff, mode);
+	}
+
+	if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_1)
+		ee->ee_margin_tx_rx[mode] = (val >> 8) & 0x3f;
+
+	/*
+	 * Get values for 802.11g (2.4GHz)
+	 */
+	mode = AR5K_EEPROM_MODE_11G;
+	offset = AR5K_EEPROM_MODES_11G(ah->ah_ee_version);
+
+	ret = ath5k_eeprom_read_ants(ah, &offset, mode);
+	if (ret)
+		return ret;
+
+	AR5K_EEPROM_READ(offset++, val);
+	ee->ee_adc_desired_size[mode]	= (s8)((val >> 8) & 0xff);
+	ee->ee_ob[mode][1]		= (val >> 4) & 0x7;
+	ee->ee_db[mode][1]		= val & 0x7;
+
+	ret = ath5k_eeprom_read_modes(ah, &offset, mode);
+	if (ret)
+		return ret;
+
+	if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0) {
+		AR5K_EEPROM_READ(offset++, val);
+		ee->ee_cal_pier[mode][0] =
+			ath5k_eeprom_bin2freq(ah, val & 0xff, mode);
+		ee->ee_cal_pier[mode][1] =
+			ath5k_eeprom_bin2freq(ah, (val >> 8) & 0xff, mode);
+
+		AR5K_EEPROM_READ(offset++, val);
+		ee->ee_turbo_max_power[mode] = val & 0x7f;
+		ee->ee_xr_power[mode] = (val >> 7) & 0x3f;
+
+		AR5K_EEPROM_READ(offset++, val);
+		ee->ee_cal_pier[mode][2] =
+			ath5k_eeprom_bin2freq(ah, val & 0xff, mode);
+
+		if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_1)
+			ee->ee_margin_tx_rx[mode] = (val >> 8) & 0x3f;
+
+		AR5K_EEPROM_READ(offset++, val);
+		ee->ee_i_cal[mode] = (val >> 8) & 0x3f;
+		ee->ee_q_cal[mode] = (val >> 3) & 0x1f;
+
+		if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_2) {
+			AR5K_EEPROM_READ(offset++, val);
+			ee->ee_cck_ofdm_gain_delta = val & 0xff;
+		}
+	}
+
+	/*
+	 * Read 5GHz EEPROM channels
+	 */
+
+	return 0;
+}
+
+/*
+ * Read the MAC address from eeprom
+ */
+int ath5k_eeprom_read_mac(struct ath5k_hw *ah, u8 *mac)
+{
+	u8 mac_d[ETH_ALEN];
+	u32 total, offset;
+	u16 data;
+	int octet, ret;
+
+	memset(mac, 0, ETH_ALEN);
+	memset(mac_d, 0, ETH_ALEN);
+
+	ret = ath5k_hw_eeprom_read(ah, 0x20, &data);
+	if (ret)
+		return ret;
+
+	for (offset = 0x1f, octet = 0, total = 0; offset >= 0x1d; offset--) {
+		ret = ath5k_hw_eeprom_read(ah, offset, &data);
+		if (ret)
+			return ret;
+
+		total += data;
+		mac_d[octet + 1] = data & 0xff;
+		mac_d[octet] = data >> 8;
+		octet += 2;
+	}
+
+	memcpy(mac, mac_d, ETH_ALEN);
+
+	if (!total || total == 3 * 0xffff)
+		return -EINVAL;
+
+	return 0;
+}
+
diff --git a/drivers/net/wireless/ath5k/eeprom.h b/drivers/net/wireless/ath5k/eeprom.h
new file mode 100644
index 0000000..a468ecf
--- /dev/null
+++ b/drivers/net/wireless/ath5k/eeprom.h
@@ -0,0 +1,215 @@
+/*
+ * Copyright (c) 2004-2008 Reyk Floeter <reyk@openbsd.org>
+ * Copyright (c) 2006-2008 Nick Kossifidis <mickflemm@gmail.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+/*
+ * Common ar5xxx EEPROM data offsets (set these on AR5K_EEPROM_BASE)
+ */
+#define AR5K_EEPROM_MAGIC		0x003d	/* EEPROM Magic number */
+#define AR5K_EEPROM_MAGIC_VALUE		0x5aa5	/* Default - found on EEPROM */
+#define AR5K_EEPROM_MAGIC_5212		0x0000145c /* 5212 */
+#define AR5K_EEPROM_MAGIC_5211		0x0000145b /* 5211 */
+#define AR5K_EEPROM_MAGIC_5210		0x0000145a /* 5210 */
+
+#define AR5K_EEPROM_PROTECT		0x003f	/* EEPROM protect status */
+#define AR5K_EEPROM_PROTECT_RD_0_31	0x0001	/* Read protection bit for offsets 0x0 - 0x1f */
+#define AR5K_EEPROM_PROTECT_WR_0_31	0x0002	/* Write protection bit for offsets 0x0 - 0x1f */
+#define AR5K_EEPROM_PROTECT_RD_32_63	0x0004	/* 0x20 - 0x3f */
+#define AR5K_EEPROM_PROTECT_WR_32_63	0x0008
+#define AR5K_EEPROM_PROTECT_RD_64_127	0x0010	/* 0x40 - 0x7f */
+#define AR5K_EEPROM_PROTECT_WR_64_127	0x0020
+#define AR5K_EEPROM_PROTECT_RD_128_191	0x0040	/* 0x80 - 0xbf (regdom) */
+#define AR5K_EEPROM_PROTECT_WR_128_191	0x0080
+#define AR5K_EEPROM_PROTECT_RD_192_207	0x0100	/* 0xc0 - 0xcf */
+#define AR5K_EEPROM_PROTECT_WR_192_207	0x0200
+#define AR5K_EEPROM_PROTECT_RD_208_223	0x0400	/* 0xd0 - 0xdf */
+#define AR5K_EEPROM_PROTECT_WR_208_223	0x0800
+#define AR5K_EEPROM_PROTECT_RD_224_239	0x1000	/* 0xe0 - 0xef */
+#define AR5K_EEPROM_PROTECT_WR_224_239	0x2000
+#define AR5K_EEPROM_PROTECT_RD_240_255	0x4000	/* 0xf0 - 0xff */
+#define AR5K_EEPROM_PROTECT_WR_240_255	0x8000
+#define AR5K_EEPROM_REG_DOMAIN		0x00bf	/* EEPROM regdom */
+#define AR5K_EEPROM_INFO_BASE		0x00c0	/* EEPROM header */
+#define AR5K_EEPROM_INFO_MAX		(0x400 - AR5K_EEPROM_INFO_BASE)
+#define AR5K_EEPROM_INFO_CKSUM		0xffff
+#define AR5K_EEPROM_INFO(_n)		(AR5K_EEPROM_INFO_BASE + (_n))
+
+#define AR5K_EEPROM_VERSION		AR5K_EEPROM_INFO(1)	/* EEPROM Version */
+#define AR5K_EEPROM_VERSION_3_0		0x3000	/* No idea what's going on before this version */
+#define AR5K_EEPROM_VERSION_3_1		0x3001	/* ob/db values for 2Ghz (ar5211_rfregs) */
+#define AR5K_EEPROM_VERSION_3_2		0x3002	/* different frequency representation (eeprom_bin2freq) */
+#define AR5K_EEPROM_VERSION_3_3		0x3003	/* offsets changed, has 32 CTLs (see below) and ee_false_detect (eeprom_read_modes) */
+#define AR5K_EEPROM_VERSION_3_4		0x3004	/* has ee_i_gain ee_cck_ofdm_power_delta (eeprom_read_modes) */
+#define AR5K_EEPROM_VERSION_4_0		0x4000	/* has ee_misc*, ee_cal_pier, ee_turbo_max_power and ee_xr_power (eeprom_init) */
+#define AR5K_EEPROM_VERSION_4_1		0x4001	/* has ee_margin_tx_rx (eeprom_init) */
+#define AR5K_EEPROM_VERSION_4_2		0x4002	/* has ee_cck_ofdm_gain_delta (eeprom_init) */
+#define AR5K_EEPROM_VERSION_4_3		0x4003
+#define AR5K_EEPROM_VERSION_4_4		0x4004
+#define AR5K_EEPROM_VERSION_4_5		0x4005
+#define AR5K_EEPROM_VERSION_4_6		0x4006	/* has ee_scaled_cck_delta */
+#define AR5K_EEPROM_VERSION_4_7		0x4007
+
+#define AR5K_EEPROM_MODE_11A		0
+#define AR5K_EEPROM_MODE_11B		1
+#define AR5K_EEPROM_MODE_11G		2
+
+#define AR5K_EEPROM_HDR			AR5K_EEPROM_INFO(2)	/* Header that contains the device caps */
+#define AR5K_EEPROM_HDR_11A(_v)		(((_v) >> AR5K_EEPROM_MODE_11A) & 0x1)
+#define AR5K_EEPROM_HDR_11B(_v)		(((_v) >> AR5K_EEPROM_MODE_11B) & 0x1)
+#define AR5K_EEPROM_HDR_11G(_v)		(((_v) >> AR5K_EEPROM_MODE_11G) & 0x1)
+#define AR5K_EEPROM_HDR_T_2GHZ_DIS(_v)	(((_v) >> 3) & 0x1)	/* Disable turbo for 2Ghz (?) */
+#define AR5K_EEPROM_HDR_T_5GHZ_DBM(_v)	(((_v) >> 4) & 0x7f)	/* Max turbo power for a/XR mode (eeprom_init) */
+#define AR5K_EEPROM_HDR_DEVICE(_v)	(((_v) >> 11) & 0x7)
+#define AR5K_EEPROM_HDR_T_5GHZ_DIS(_v)	(((_v) >> 15) & 0x1)	/* Disable turbo for 5Ghz (?) */
+#define AR5K_EEPROM_HDR_RFKILL(_v)	(((_v) >> 14) & 0x1)	/* Device has RFKill support */
+
+#define AR5K_EEPROM_RFKILL_GPIO_SEL	0x0000001c
+#define AR5K_EEPROM_RFKILL_GPIO_SEL_S	2
+#define AR5K_EEPROM_RFKILL_POLARITY	0x00000002
+#define AR5K_EEPROM_RFKILL_POLARITY_S	1
+
+/* Newer EEPROMs are using a different offset */
+#define AR5K_EEPROM_OFF(_v, _v3_0, _v3_3) \
+	(((_v) >= AR5K_EEPROM_VERSION_3_3) ? _v3_3 : _v3_0)
+
+#define AR5K_EEPROM_ANT_GAIN(_v)	AR5K_EEPROM_OFF(_v, 0x00c4, 0x00c3)
+#define AR5K_EEPROM_ANT_GAIN_5GHZ(_v)	((int8_t)(((_v) >> 8) & 0xff))
+#define AR5K_EEPROM_ANT_GAIN_2GHZ(_v)	((int8_t)((_v) & 0xff))
+
+/* calibration settings */
+#define AR5K_EEPROM_MODES_11A(_v)	AR5K_EEPROM_OFF(_v, 0x00c5, 0x00d4)
+#define AR5K_EEPROM_MODES_11B(_v)	AR5K_EEPROM_OFF(_v, 0x00d0, 0x00f2)
+#define AR5K_EEPROM_MODES_11G(_v)	AR5K_EEPROM_OFF(_v, 0x00da, 0x010d)
+#define AR5K_EEPROM_CTL(_v)		AR5K_EEPROM_OFF(_v, 0x00e4, 0x0128)	/* Conformance test limits */
+
+/* [3.1 - 3.3] */
+#define AR5K_EEPROM_OBDB0_2GHZ		0x00ec
+#define AR5K_EEPROM_OBDB1_2GHZ		0x00ed
+
+/* Misc values available since EEPROM 4.0 */
+#define AR5K_EEPROM_MISC0		0x00c4
+#define AR5K_EEPROM_EARSTART(_v)	((_v) & 0xfff)
+#define AR5K_EEPROM_EEMAP(_v)		(((_v) >> 14) & 0x3)
+#define AR5K_EEPROM_MISC1		0x00c5
+#define AR5K_EEPROM_TARGET_PWRSTART(_v)	((_v) & 0xfff)
+#define AR5K_EEPROM_HAS32KHZCRYSTAL(_v)	(((_v) >> 14) & 0x1)
+
+
+/* Some EEPROM defines */
+#define AR5K_EEPROM_EEP_SCALE		100
+#define AR5K_EEPROM_EEP_DELTA		10
+#define AR5K_EEPROM_N_MODES		3
+#define AR5K_EEPROM_N_5GHZ_CHAN		10
+#define AR5K_EEPROM_N_2GHZ_CHAN		3
+#define AR5K_EEPROM_MAX_CHAN		10
+#define AR5K_EEPROM_N_PCDAC		11
+#define AR5K_EEPROM_N_TEST_FREQ		8
+#define AR5K_EEPROM_N_EDGES		8
+#define AR5K_EEPROM_N_INTERCEPTS	11
+#define AR5K_EEPROM_FREQ_M(_v)		AR5K_EEPROM_OFF(_v, 0x7f, 0xff)
+#define AR5K_EEPROM_PCDAC_M		0x3f
+#define AR5K_EEPROM_PCDAC_START		1
+#define AR5K_EEPROM_PCDAC_STOP		63
+#define AR5K_EEPROM_PCDAC_STEP		1
+#define AR5K_EEPROM_NON_EDGE_M		0x40
+#define AR5K_EEPROM_CHANNEL_POWER	8
+#define AR5K_EEPROM_N_OBDB		4
+#define AR5K_EEPROM_OBDB_DIS		0xffff
+#define AR5K_EEPROM_CHANNEL_DIS		0xff
+#define AR5K_EEPROM_SCALE_OC_DELTA(_x)	(((_x) * 2) / 10)
+#define AR5K_EEPROM_N_CTLS(_v)		AR5K_EEPROM_OFF(_v, 16, 32)
+#define AR5K_EEPROM_MAX_CTLS		32
+#define AR5K_EEPROM_N_XPD_PER_CHANNEL	4
+#define AR5K_EEPROM_N_XPD0_POINTS	4
+#define AR5K_EEPROM_N_XPD3_POINTS	3
+#define AR5K_EEPROM_N_INTERCEPT_10_2GHZ	35
+#define AR5K_EEPROM_N_INTERCEPT_10_5GHZ	55
+#define AR5K_EEPROM_POWER_M		0x3f
+#define AR5K_EEPROM_POWER_MIN		0
+#define AR5K_EEPROM_POWER_MAX		3150
+#define AR5K_EEPROM_POWER_STEP		50
+#define AR5K_EEPROM_POWER_TABLE_SIZE	64
+#define AR5K_EEPROM_N_POWER_LOC_11B	4
+#define AR5K_EEPROM_N_POWER_LOC_11G	6
+#define AR5K_EEPROM_I_GAIN		10
+#define AR5K_EEPROM_CCK_OFDM_DELTA	15
+#define AR5K_EEPROM_N_IQ_CAL		2
+
+#define AR5K_EEPROM_READ(_o, _v) do {			\
+	ret = ath5k_hw_eeprom_read(ah, (_o), &(_v));	\
+	if (ret)					\
+		return ret;				\
+} while (0)
+
+#define AR5K_EEPROM_READ_HDR(_o, _v)					\
+	AR5K_EEPROM_READ(_o, ah->ah_capabilities.cap_eeprom._v);	\
+
+/* Struct to hold EEPROM calibration data */
+struct ath5k_eeprom_info {
+	u16	ee_magic;
+	u16	ee_protect;
+	u16	ee_regdomain;
+	u16	ee_version;
+	u16	ee_header;
+	u16	ee_ant_gain;
+	u16	ee_misc0;
+	u16	ee_misc1;
+	u16	ee_cck_ofdm_gain_delta;
+	u16	ee_cck_ofdm_power_delta;
+	u16	ee_scaled_cck_delta;
+
+	/* Used for tx thermal adjustment (eeprom_init, rfregs) */
+	u16	ee_tx_clip;
+	u16	ee_pwd_84;
+	u16	ee_pwd_90;
+	u16	ee_gain_select;
+
+	/* RF Calibration settings (reset, rfregs) */
+	u16	ee_i_cal[AR5K_EEPROM_N_MODES];
+	u16	ee_q_cal[AR5K_EEPROM_N_MODES];
+	u16	ee_fixed_bias[AR5K_EEPROM_N_MODES];
+	u16	ee_turbo_max_power[AR5K_EEPROM_N_MODES];
+	u16	ee_xr_power[AR5K_EEPROM_N_MODES];
+	u16	ee_switch_settling[AR5K_EEPROM_N_MODES];
+	u16	ee_ant_tx_rx[AR5K_EEPROM_N_MODES];
+	u16	ee_ant_control[AR5K_EEPROM_N_MODES][AR5K_EEPROM_N_PCDAC];
+	u16	ee_ob[AR5K_EEPROM_N_MODES][AR5K_EEPROM_N_OBDB];
+	u16	ee_db[AR5K_EEPROM_N_MODES][AR5K_EEPROM_N_OBDB];
+	u16	ee_tx_end2xlna_enable[AR5K_EEPROM_N_MODES];
+	u16	ee_tx_end2xpa_disable[AR5K_EEPROM_N_MODES];
+	u16	ee_tx_frm2xpa_enable[AR5K_EEPROM_N_MODES];
+	u16	ee_thr_62[AR5K_EEPROM_N_MODES];
+	u16	ee_xlna_gain[AR5K_EEPROM_N_MODES];
+	u16	ee_xpd[AR5K_EEPROM_N_MODES];
+	u16	ee_x_gain[AR5K_EEPROM_N_MODES];
+	u16	ee_i_gain[AR5K_EEPROM_N_MODES];
+	u16	ee_margin_tx_rx[AR5K_EEPROM_N_MODES];
+
+	/* Unused */
+	u16	ee_false_detect[AR5K_EEPROM_N_MODES];
+	u16	ee_cal_pier[AR5K_EEPROM_N_MODES][AR5K_EEPROM_N_2GHZ_CHAN];
+	u16	ee_channel[AR5K_EEPROM_N_MODES][AR5K_EEPROM_MAX_CHAN]; /*empty*/
+
+	/* Conformance test limits (Unused) */
+	u16	ee_ctls;
+	u16	ee_ctl[AR5K_EEPROM_MAX_CTLS];
+
+	/* Noise Floor Calibration settings */
+	s16	ee_noise_floor_thr[AR5K_EEPROM_N_MODES];
+	s8	ee_adc_desired_size[AR5K_EEPROM_N_MODES];
+	s8	ee_pga_desired_size[AR5K_EEPROM_N_MODES];
+};
diff --git a/drivers/net/wireless/ath5k/gpio.c b/drivers/net/wireless/ath5k/gpio.c
new file mode 100644
index 0000000..b77205a
--- /dev/null
+++ b/drivers/net/wireless/ath5k/gpio.c
@@ -0,0 +1,176 @@
+/*
+ * Copyright (c) 2004-2008 Reyk Floeter <reyk@openbsd.org>
+ * Copyright (c) 2006-2008 Nick Kossifidis <mickflemm@gmail.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+/****************\
+  GPIO Functions
+\****************/
+
+#include "ath5k.h"
+#include "reg.h"
+#include "debug.h"
+#include "base.h"
+
+/*
+ * Set led state
+ */
+void ath5k_hw_set_ledstate(struct ath5k_hw *ah, unsigned int state)
+{
+	u32 led;
+	/*5210 has different led mode handling*/
+	u32 led_5210;
+
+	ATH5K_TRACE(ah->ah_sc);
+
+	/*Reset led status*/
+	if (ah->ah_version != AR5K_AR5210)
+		AR5K_REG_DISABLE_BITS(ah, AR5K_PCICFG,
+			AR5K_PCICFG_LEDMODE |  AR5K_PCICFG_LED);
+	else
+		AR5K_REG_DISABLE_BITS(ah, AR5K_PCICFG, AR5K_PCICFG_LED);
+
+	/*
+	 * Some blinking values, define at your wish
+	 */
+	switch (state) {
+	case AR5K_LED_SCAN:
+	case AR5K_LED_AUTH:
+		led = AR5K_PCICFG_LEDMODE_PROP | AR5K_PCICFG_LED_PEND;
+		led_5210 = AR5K_PCICFG_LED_PEND | AR5K_PCICFG_LED_BCTL;
+		break;
+
+	case AR5K_LED_INIT:
+		led = AR5K_PCICFG_LEDMODE_PROP | AR5K_PCICFG_LED_NONE;
+		led_5210 = AR5K_PCICFG_LED_PEND;
+		break;
+
+	case AR5K_LED_ASSOC:
+	case AR5K_LED_RUN:
+		led = AR5K_PCICFG_LEDMODE_PROP | AR5K_PCICFG_LED_ASSOC;
+		led_5210 = AR5K_PCICFG_LED_ASSOC;
+		break;
+
+	default:
+		led = AR5K_PCICFG_LEDMODE_PROM | AR5K_PCICFG_LED_NONE;
+		led_5210 = AR5K_PCICFG_LED_PEND;
+		break;
+	}
+
+	/*Write new status to the register*/
+	if (ah->ah_version != AR5K_AR5210)
+		AR5K_REG_ENABLE_BITS(ah, AR5K_PCICFG, led);
+	else
+		AR5K_REG_ENABLE_BITS(ah, AR5K_PCICFG, led_5210);
+}
+
+/*
+ * Set GPIO inputs
+ */
+int ath5k_hw_set_gpio_input(struct ath5k_hw *ah, u32 gpio)
+{
+	ATH5K_TRACE(ah->ah_sc);
+	if (gpio > AR5K_NUM_GPIO)
+		return -EINVAL;
+
+	ath5k_hw_reg_write(ah,
+		(ath5k_hw_reg_read(ah, AR5K_GPIOCR) & ~AR5K_GPIOCR_OUT(gpio))
+		| AR5K_GPIOCR_IN(gpio), AR5K_GPIOCR);
+
+	return 0;
+}
+
+/*
+ * Set GPIO outputs
+ */
+int ath5k_hw_set_gpio_output(struct ath5k_hw *ah, u32 gpio)
+{
+	ATH5K_TRACE(ah->ah_sc);
+	if (gpio > AR5K_NUM_GPIO)
+		return -EINVAL;
+
+	ath5k_hw_reg_write(ah,
+		(ath5k_hw_reg_read(ah, AR5K_GPIOCR) & ~AR5K_GPIOCR_OUT(gpio))
+		| AR5K_GPIOCR_OUT(gpio), AR5K_GPIOCR);
+
+	return 0;
+}
+
+/*
+ * Get GPIO state
+ */
+u32 ath5k_hw_get_gpio(struct ath5k_hw *ah, u32 gpio)
+{
+	ATH5K_TRACE(ah->ah_sc);
+	if (gpio > AR5K_NUM_GPIO)
+		return 0xffffffff;
+
+	/* GPIO input magic */
+	return ((ath5k_hw_reg_read(ah, AR5K_GPIODI) & AR5K_GPIODI_M) >> gpio) &
+		0x1;
+}
+
+/*
+ * Set GPIO state
+ */
+int ath5k_hw_set_gpio(struct ath5k_hw *ah, u32 gpio, u32 val)
+{
+	u32 data;
+	ATH5K_TRACE(ah->ah_sc);
+
+	if (gpio > AR5K_NUM_GPIO)
+		return -EINVAL;
+
+	/* GPIO output magic */
+	data = ath5k_hw_reg_read(ah, AR5K_GPIODO);
+
+	data &= ~(1 << gpio);
+	data |= (val & 1) << gpio;
+
+	ath5k_hw_reg_write(ah, data, AR5K_GPIODO);
+
+	return 0;
+}
+
+/*
+ * Initialize the GPIO interrupt (RFKill switch)
+ */
+void ath5k_hw_set_gpio_intr(struct ath5k_hw *ah, unsigned int gpio,
+		u32 interrupt_level)
+{
+	u32 data;
+
+	ATH5K_TRACE(ah->ah_sc);
+	if (gpio > AR5K_NUM_GPIO)
+		return;
+
+	/*
+	 * Set the GPIO interrupt
+	 */
+	data = (ath5k_hw_reg_read(ah, AR5K_GPIOCR) &
+		~(AR5K_GPIOCR_INT_SEL(gpio) | AR5K_GPIOCR_INT_SELH |
+		AR5K_GPIOCR_INT_ENA | AR5K_GPIOCR_OUT(gpio))) |
+		(AR5K_GPIOCR_INT_SEL(gpio) | AR5K_GPIOCR_INT_ENA);
+
+	ath5k_hw_reg_write(ah, interrupt_level ? data :
+		(data | AR5K_GPIOCR_INT_SELH), AR5K_GPIOCR);
+
+	ah->ah_imr |= AR5K_IMR_GPIO;
+
+	/* Enable GPIO interrupts */
+	AR5K_REG_ENABLE_BITS(ah, AR5K_PIMR, AR5K_IMR_GPIO);
+}
+
diff --git a/drivers/net/wireless/ath5k/hw.c b/drivers/net/wireless/ath5k/hw.c
deleted file mode 100644
index ad1a5b4..0000000
--- a/drivers/net/wireless/ath5k/hw.c
+++ /dev/null
@@ -1,4529 +0,0 @@
-/*
- * Copyright (c) 2004-2007 Reyk Floeter <reyk@openbsd.org>
- * Copyright (c) 2006-2007 Nick Kossifidis <mickflemm@gmail.com>
- * Copyright (c) 2007 Matthew W. S. Bell  <mentor@madwifi.org>
- * Copyright (c) 2007 Luis Rodriguez <mcgrof@winlab.rutgers.edu>
- * Copyright (c) 2007 Pavel Roskin <proski@gnu.org>
- * Copyright (c) 2007 Jiri Slaby <jirislaby@gmail.com>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- *
- */
-
-/*
- * HW related functions for Atheros Wireless LAN devices.
- */
-
-#include <linux/pci.h>
-#include <linux/delay.h>
-
-#include "reg.h"
-#include "base.h"
-#include "debug.h"
-
-/* Rate tables */
-static const struct ath5k_rate_table ath5k_rt_11a = AR5K_RATES_11A;
-static const struct ath5k_rate_table ath5k_rt_11b = AR5K_RATES_11B;
-static const struct ath5k_rate_table ath5k_rt_11g = AR5K_RATES_11G;
-static const struct ath5k_rate_table ath5k_rt_turbo = AR5K_RATES_TURBO;
-static const struct ath5k_rate_table ath5k_rt_xr = AR5K_RATES_XR;
-
-/* Prototypes */
-static int ath5k_hw_nic_reset(struct ath5k_hw *, u32);
-static int ath5k_hw_nic_wakeup(struct ath5k_hw *, int, bool);
-static int ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *, struct ath5k_desc *,
-	unsigned int, unsigned int, enum ath5k_pkt_type, unsigned int,
-	unsigned int, unsigned int, unsigned int, unsigned int, unsigned int,
-	unsigned int, unsigned int);
-static int ath5k_hw_setup_xr_tx_desc(struct ath5k_hw *, struct ath5k_desc *,
-	unsigned int, unsigned int, unsigned int, unsigned int, unsigned int,
-	unsigned int);
-static int ath5k_hw_proc_4word_tx_status(struct ath5k_hw *, struct ath5k_desc *,
-					 struct ath5k_tx_status *);
-static int ath5k_hw_setup_2word_tx_desc(struct ath5k_hw *, struct ath5k_desc *,
-	unsigned int, unsigned int, enum ath5k_pkt_type, unsigned int,
-	unsigned int, unsigned int, unsigned int, unsigned int, unsigned int,
-	unsigned int, unsigned int);
-static int ath5k_hw_proc_2word_tx_status(struct ath5k_hw *, struct ath5k_desc *,
-					 struct ath5k_tx_status *);
-static int ath5k_hw_proc_5212_rx_status(struct ath5k_hw *, struct ath5k_desc *,
-					struct ath5k_rx_status *);
-static int ath5k_hw_proc_5210_rx_status(struct ath5k_hw *, struct ath5k_desc *,
-					struct ath5k_rx_status *);
-static int ath5k_hw_get_capabilities(struct ath5k_hw *);
-
-static int ath5k_eeprom_init(struct ath5k_hw *);
-static int ath5k_eeprom_read_mac(struct ath5k_hw *, u8 *);
-
-static int ath5k_hw_enable_pspoll(struct ath5k_hw *, u8 *, u16);
-static int ath5k_hw_disable_pspoll(struct ath5k_hw *);
-
-/*
- * Enable to overwrite the country code (use "00" for debug)
- */
-#if 0
-#define COUNTRYCODE "00"
-#endif
-
-/*******************\
-  General Functions
-\*******************/
-
-/*
- * Functions used internaly
- */
-
-static inline unsigned int ath5k_hw_htoclock(unsigned int usec, bool turbo)
-{
-	return turbo ? (usec * 80) : (usec * 40);
-}
-
-static inline unsigned int ath5k_hw_clocktoh(unsigned int clock, bool turbo)
-{
-	return turbo ? (clock / 80) : (clock / 40);
-}
-
-/*
- * Check if a register write has been completed
- */
-int ath5k_hw_register_timeout(struct ath5k_hw *ah, u32 reg, u32 flag, u32 val,
-		bool is_set)
-{
-	int i;
-	u32 data;
-
-	for (i = AR5K_TUNE_REGISTER_TIMEOUT; i > 0; i--) {
-		data = ath5k_hw_reg_read(ah, reg);
-		if (is_set && (data & flag))
-			break;
-		else if ((data & flag) == val)
-			break;
-		udelay(15);
-	}
-
-	return (i <= 0) ? -EAGAIN : 0;
-}
-
-
-/***************************************\
-	Attach/Detach Functions
-\***************************************/
-
-/*
- * Power On Self Test helper function
- */
-static int ath5k_hw_post(struct ath5k_hw *ah)
-{
-
-	int i, c;
-	u16 cur_reg;
-	u16 regs[2] = {AR5K_STA_ID0, AR5K_PHY(8)};
-	u32 var_pattern;
-	u32 static_pattern[4] = {
-		0x55555555,	0xaaaaaaaa,
-		0x66666666,	0x99999999
-	};
-	u32 init_val;
-	u32 cur_val;
-
-	for (c = 0; c < 2; c++) {
-
-		cur_reg = regs[c];
-
-		/* Save previous value */
-		init_val = ath5k_hw_reg_read(ah, cur_reg);
-
-		for (i = 0; i < 256; i++) {
-			var_pattern = i << 16 | i;
-			ath5k_hw_reg_write(ah, var_pattern, cur_reg);
-			cur_val = ath5k_hw_reg_read(ah, cur_reg);
-
-			if (cur_val != var_pattern) {
-				ATH5K_ERR(ah->ah_sc, "POST Failed !!!\n");
-				return -EAGAIN;
-			}
-
-			/* Found on ndiswrapper dumps */
-			var_pattern = 0x0039080f;
-			ath5k_hw_reg_write(ah, var_pattern, cur_reg);
-		}
-
-		for (i = 0; i < 4; i++) {
-			var_pattern = static_pattern[i];
-			ath5k_hw_reg_write(ah, var_pattern, cur_reg);
-			cur_val = ath5k_hw_reg_read(ah, cur_reg);
-
-			if (cur_val != var_pattern) {
-				ATH5K_ERR(ah->ah_sc, "POST Failed !!!\n");
-				return -EAGAIN;
-			}
-
-			/* Found on ndiswrapper dumps */
-			var_pattern = 0x003b080f;
-			ath5k_hw_reg_write(ah, var_pattern, cur_reg);
-		}
-
-		/* Restore previous value */
-		ath5k_hw_reg_write(ah, init_val, cur_reg);
-
-	}
-
-	return 0;
-
-}
-
-/*
- * Check if the device is supported and initialize the needed structs
- */
-struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version)
-{
-	struct ath5k_hw *ah;
-	struct pci_dev *pdev = sc->pdev;
-	u8 mac[ETH_ALEN];
-	int ret;
-	u32 srev;
-
-	/*If we passed the test malloc a ath5k_hw struct*/
-	ah = kzalloc(sizeof(struct ath5k_hw), GFP_KERNEL);
-	if (ah == NULL) {
-		ret = -ENOMEM;
-		ATH5K_ERR(sc, "out of memory\n");
-		goto err;
-	}
-
-	ah->ah_sc = sc;
-	ah->ah_iobase = sc->iobase;
-
-	/*
-	 * HW information
-	 */
-
-	ah->ah_op_mode = IEEE80211_IF_TYPE_STA;
-	ah->ah_radar.r_enabled = AR5K_TUNE_RADAR_ALERT;
-	ah->ah_turbo = false;
-	ah->ah_txpower.txp_tpc = AR5K_TUNE_TPC_TXPOWER;
-	ah->ah_imr = 0;
-	ah->ah_atim_window = 0;
-	ah->ah_aifs = AR5K_TUNE_AIFS;
-	ah->ah_cw_min = AR5K_TUNE_CWMIN;
-	ah->ah_limit_tx_retries = AR5K_INIT_TX_RETRY;
-	ah->ah_software_retry = false;
-	ah->ah_ant_diversity = AR5K_TUNE_ANT_DIVERSITY;
-
-	/*
-	 * Set the mac revision based on the pci id
-	 */
-	ah->ah_version = mac_version;
-
-	/*Fill the ath5k_hw struct with the needed functions*/
-	if (ah->ah_version == AR5K_AR5212)
-		ah->ah_magic = AR5K_EEPROM_MAGIC_5212;
-	else if (ah->ah_version == AR5K_AR5211)
-		ah->ah_magic = AR5K_EEPROM_MAGIC_5211;
-
-	if (ah->ah_version == AR5K_AR5212) {
-		ah->ah_setup_tx_desc = ath5k_hw_setup_4word_tx_desc;
-		ah->ah_setup_xtx_desc = ath5k_hw_setup_xr_tx_desc;
-		ah->ah_proc_tx_desc = ath5k_hw_proc_4word_tx_status;
-	} else {
-		ah->ah_setup_tx_desc = ath5k_hw_setup_2word_tx_desc;
-		ah->ah_setup_xtx_desc = ath5k_hw_setup_xr_tx_desc;
-		ah->ah_proc_tx_desc = ath5k_hw_proc_2word_tx_status;
-	}
-
-	if (ah->ah_version == AR5K_AR5212)
-		ah->ah_proc_rx_desc = ath5k_hw_proc_5212_rx_status;
-	else if (ah->ah_version <= AR5K_AR5211)
-		ah->ah_proc_rx_desc = ath5k_hw_proc_5210_rx_status;
-
-	/* Bring device out of sleep and reset it's units */
-	ret = ath5k_hw_nic_wakeup(ah, AR5K_INIT_MODE, true);
-	if (ret)
-		goto err_free;
-
-	/* Get MAC, PHY and RADIO revisions */
-	srev = ath5k_hw_reg_read(ah, AR5K_SREV);
-	ah->ah_mac_srev = srev;
-	ah->ah_mac_version = AR5K_REG_MS(srev, AR5K_SREV_VER);
-	ah->ah_mac_revision = AR5K_REG_MS(srev, AR5K_SREV_REV);
-	ah->ah_phy_revision = ath5k_hw_reg_read(ah, AR5K_PHY_CHIP_ID) &
-			0xffffffff;
-	ah->ah_radio_5ghz_revision = ath5k_hw_radio_revision(ah,
-			CHANNEL_5GHZ);
-
-	if (ah->ah_version == AR5K_AR5210)
-		ah->ah_radio_2ghz_revision = 0;
-	else
-		ah->ah_radio_2ghz_revision = ath5k_hw_radio_revision(ah,
-				CHANNEL_2GHZ);
-
-	/* Return on unsuported chips (unsupported eeprom etc) */
-	if ((srev >= AR5K_SREV_VER_AR5416) &&
-	(srev < AR5K_SREV_VER_AR2425)) {
-		ATH5K_ERR(sc, "Device not yet supported.\n");
-		ret = -ENODEV;
-		goto err_free;
-	} else if (srev == AR5K_SREV_VER_AR2425) {
-		ATH5K_WARN(sc, "Support for RF2425 is under development.\n");
-	}
-
-	/* Identify single chip solutions */
-	if (((srev <= AR5K_SREV_VER_AR5414) &&
-	(srev >= AR5K_SREV_VER_AR2413)) ||
-	(srev == AR5K_SREV_VER_AR2425)) {
-		ah->ah_single_chip = true;
-	} else {
-		ah->ah_single_chip = false;
-	}
-
-	/* Single chip radio */
-	if (ah->ah_radio_2ghz_revision == ah->ah_radio_5ghz_revision)
-		ah->ah_radio_2ghz_revision = 0;
-
-	/* Identify the radio chip*/
-	if (ah->ah_version == AR5K_AR5210) {
-		ah->ah_radio = AR5K_RF5110;
-	/*
-	 * Register returns 0x0/0x04 for radio revision
-	 * so ath5k_hw_radio_revision doesn't parse the value
-	 * correctly. For now we are based on mac's srev to
-	 * identify RF2425 radio.
-	 */
-	} else if (srev == AR5K_SREV_VER_AR2425) {
-		ah->ah_radio = AR5K_RF2425;
-		ah->ah_phy_spending = AR5K_PHY_SPENDING_RF2425;
-	} else if (ah->ah_radio_5ghz_revision < AR5K_SREV_RAD_5112) {
-		ah->ah_radio = AR5K_RF5111;
-		ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5111;
-	} else if (ah->ah_radio_5ghz_revision < AR5K_SREV_RAD_SC0) {
-		ah->ah_radio = AR5K_RF5112;
-		ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5112;
-	} else if (ah->ah_radio_5ghz_revision < AR5K_SREV_RAD_SC1) {
-		ah->ah_radio = AR5K_RF2413;
-		ah->ah_phy_spending = AR5K_PHY_SPENDING_RF2413;
-	} else if (ah->ah_radio_5ghz_revision < AR5K_SREV_RAD_SC2) {
-		ah->ah_radio = AR5K_RF5413;
-		ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5413;
-	} else if (ah->ah_radio_5ghz_revision < AR5K_SREV_RAD_5133) {
-		/* AR5424 */
-		if (srev >= AR5K_SREV_VER_AR5424) {
-			ah->ah_radio = AR5K_RF5413;
-			ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5413;
-		/* AR2424 */
-		} else {
-			ah->ah_radio = AR5K_RF2413; /* For testing */
-			ah->ah_phy_spending = AR5K_PHY_SPENDING_RF2413;
-		}
-	}
-	ah->ah_phy = AR5K_PHY(0);
-
-	/*
-	 * Write PCI-E power save settings
-	 */
-	if ((ah->ah_version == AR5K_AR5212) && (pdev->is_pcie)) {
-		ath5k_hw_reg_write(ah, 0x9248fc00, 0x4080);
-		ath5k_hw_reg_write(ah, 0x24924924, 0x4080);
-		ath5k_hw_reg_write(ah, 0x28000039, 0x4080);
-		ath5k_hw_reg_write(ah, 0x53160824, 0x4080);
-		ath5k_hw_reg_write(ah, 0xe5980579, 0x4080);
-		ath5k_hw_reg_write(ah, 0x001defff, 0x4080);
-		ath5k_hw_reg_write(ah, 0x1aaabe40, 0x4080);
-		ath5k_hw_reg_write(ah, 0xbe105554, 0x4080);
-		ath5k_hw_reg_write(ah, 0x000e3007, 0x4080);
-		ath5k_hw_reg_write(ah, 0x00000000, 0x4084);
-	}
-
-	/*
-	 * POST
-	 */
-	ret = ath5k_hw_post(ah);
-	if (ret)
-		goto err_free;
-
-	/* Write AR5K_PCICFG_UNK on 2112B and later chips */
-	if (ah->ah_radio_5ghz_revision > AR5K_SREV_RAD_2112B ||
-	srev > AR5K_SREV_VER_AR2413) {
-		ath5k_hw_reg_write(ah, AR5K_PCICFG_UNK, AR5K_PCICFG);
-	}
-
-	/*
-	 * Get card capabilities, values, ...
-	 */
-	ret = ath5k_eeprom_init(ah);
-	if (ret) {
-		ATH5K_ERR(sc, "unable to init EEPROM\n");
-		goto err_free;
-	}
-
-	/* Get misc capabilities */
-	ret = ath5k_hw_get_capabilities(ah);
-	if (ret) {
-		ATH5K_ERR(sc, "unable to get device capabilities: 0x%04x\n",
-			sc->pdev->device);
-		goto err_free;
-	}
-
-	/* Get MAC address */
-	ret = ath5k_eeprom_read_mac(ah, mac);
-	if (ret) {
-		ATH5K_ERR(sc, "unable to read address from EEPROM: 0x%04x\n",
-			sc->pdev->device);
-		goto err_free;
-	}
-
-	ath5k_hw_set_lladdr(ah, mac);
-	/* Set BSSID to bcast address: ff:ff:ff:ff:ff:ff for now */
-	memset(ah->ah_bssid, 0xff, ETH_ALEN);
-	ath5k_hw_set_associd(ah, ah->ah_bssid, 0);
-	ath5k_hw_set_opmode(ah);
-
-	ath5k_hw_set_rfgain_opt(ah);
-
-	return ah;
-err_free:
-	kfree(ah);
-err:
-	return ERR_PTR(ret);
-}
-
-/*
- * Bring up MAC + PHY Chips
- */
-static int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial)
-{
-	struct pci_dev *pdev = ah->ah_sc->pdev;
-	u32 turbo, mode, clock, bus_flags;
-	int ret;
-
-	turbo = 0;
-	mode = 0;
-	clock = 0;
-
-	ATH5K_TRACE(ah->ah_sc);
-
-	/* Wakeup the device */
-	ret = ath5k_hw_set_power(ah, AR5K_PM_AWAKE, true, 0);
-	if (ret) {
-		ATH5K_ERR(ah->ah_sc, "failed to wakeup the MAC Chip\n");
-		return ret;
-	}
-
-	if (ah->ah_version != AR5K_AR5210) {
-		/*
-		 * Get channel mode flags
-		 */
-
-		if (ah->ah_radio >= AR5K_RF5112) {
-			mode = AR5K_PHY_MODE_RAD_RF5112;
-			clock = AR5K_PHY_PLL_RF5112;
-		} else {
-			mode = AR5K_PHY_MODE_RAD_RF5111;	/*Zero*/
-			clock = AR5K_PHY_PLL_RF5111;		/*Zero*/
-		}
-
-		if (flags & CHANNEL_2GHZ) {
-			mode |= AR5K_PHY_MODE_FREQ_2GHZ;
-			clock |= AR5K_PHY_PLL_44MHZ;
-
-			if (flags & CHANNEL_CCK) {
-				mode |= AR5K_PHY_MODE_MOD_CCK;
-			} else if (flags & CHANNEL_OFDM) {
-				/* XXX Dynamic OFDM/CCK is not supported by the
-				 * AR5211 so we set MOD_OFDM for plain g (no
-				 * CCK headers) operation. We need to test
-				 * this, 5211 might support ofdm-only g after
-				 * all, there are also initial register values
-				 * in the code for g mode (see initvals.c). */
-				if (ah->ah_version == AR5K_AR5211)
-					mode |= AR5K_PHY_MODE_MOD_OFDM;
-				else
-					mode |= AR5K_PHY_MODE_MOD_DYN;
-			} else {
-				ATH5K_ERR(ah->ah_sc,
-					"invalid radio modulation mode\n");
-				return -EINVAL;
-			}
-		} else if (flags & CHANNEL_5GHZ) {
-			mode |= AR5K_PHY_MODE_FREQ_5GHZ;
-			clock |= AR5K_PHY_PLL_40MHZ;
-
-			if (flags & CHANNEL_OFDM)
-				mode |= AR5K_PHY_MODE_MOD_OFDM;
-			else {
-				ATH5K_ERR(ah->ah_sc,
-					"invalid radio modulation mode\n");
-				return -EINVAL;
-			}
-		} else {
-			ATH5K_ERR(ah->ah_sc, "invalid radio frequency mode\n");
-			return -EINVAL;
-		}
-
-		if (flags & CHANNEL_TURBO)
-			turbo = AR5K_PHY_TURBO_MODE | AR5K_PHY_TURBO_SHORT;
-	} else { /* Reset the device */
-
-		/* ...enable Atheros turbo mode if requested */
-		if (flags & CHANNEL_TURBO)
-			ath5k_hw_reg_write(ah, AR5K_PHY_TURBO_MODE,
-					AR5K_PHY_TURBO);
-	}
-
-	/* reseting PCI on PCI-E cards results card to hang
-	 * and always return 0xffff... so we ingore that flag
-	 * for PCI-E cards */
-	bus_flags = (pdev->is_pcie) ? 0 : AR5K_RESET_CTL_PCI;
-
-	/* Reset chipset */
-	ret = ath5k_hw_nic_reset(ah, AR5K_RESET_CTL_PCU |
-		AR5K_RESET_CTL_BASEBAND | bus_flags);
-	if (ret) {
-		ATH5K_ERR(ah->ah_sc, "failed to reset the MAC Chip\n");
-		return -EIO;
-	}
-
-	if (ah->ah_version == AR5K_AR5210)
-		udelay(2300);
-
-	/* ...wakeup again!*/
-	ret = ath5k_hw_set_power(ah, AR5K_PM_AWAKE, true, 0);
-	if (ret) {
-		ATH5K_ERR(ah->ah_sc, "failed to resume the MAC Chip\n");
-		return ret;
-	}
-
-	/* ...final warm reset */
-	if (ath5k_hw_nic_reset(ah, 0)) {
-		ATH5K_ERR(ah->ah_sc, "failed to warm reset the MAC Chip\n");
-		return -EIO;
-	}
-
-	if (ah->ah_version != AR5K_AR5210) {
-		/* ...set the PHY operating mode */
-		ath5k_hw_reg_write(ah, clock, AR5K_PHY_PLL);
-		udelay(300);
-
-		ath5k_hw_reg_write(ah, mode, AR5K_PHY_MODE);
-		ath5k_hw_reg_write(ah, turbo, AR5K_PHY_TURBO);
-	}
-
-	return 0;
-}
-
-/*
- * Get the rate table for a specific operation mode
- */
-const struct ath5k_rate_table *ath5k_hw_get_rate_table(struct ath5k_hw *ah,
-		unsigned int mode)
-{
-	ATH5K_TRACE(ah->ah_sc);
-
-	if (!test_bit(mode, ah->ah_capabilities.cap_mode))
-		return NULL;
-
-	/* Get rate tables */
-	switch (mode) {
-	case AR5K_MODE_11A:
-		return &ath5k_rt_11a;
-	case AR5K_MODE_11A_TURBO:
-		return &ath5k_rt_turbo;
-	case AR5K_MODE_11B:
-		return &ath5k_rt_11b;
-	case AR5K_MODE_11G:
-		return &ath5k_rt_11g;
-	case AR5K_MODE_11G_TURBO:
-		return &ath5k_rt_xr;
-	}
-
-	return NULL;
-}
-
-/*
- * Free the ath5k_hw struct
- */
-void ath5k_hw_detach(struct ath5k_hw *ah)
-{
-	ATH5K_TRACE(ah->ah_sc);
-
-	__set_bit(ATH_STAT_INVALID, ah->ah_sc->status);
-
-	if (ah->ah_rf_banks != NULL)
-		kfree(ah->ah_rf_banks);
-
-	/* assume interrupts are down */
-	kfree(ah);
-}
-
-/****************************\
-  Reset function and helpers
-\****************************/
-
-/**
- * ath5k_hw_write_ofdm_timings - set OFDM timings on AR5212
- *
- * @ah: the &struct ath5k_hw
- * @channel: the currently set channel upon reset
- *
- * Write the OFDM timings for the AR5212 upon reset. This is a helper for
- * ath5k_hw_reset(). This seems to tune the PLL a specified frequency
- * depending on the bandwidth of the channel.
- *
- */
-static inline int ath5k_hw_write_ofdm_timings(struct ath5k_hw *ah,
-	struct ieee80211_channel *channel)
-{
-	/* Get exponent and mantissa and set it */
-	u32 coef_scaled, coef_exp, coef_man,
-		ds_coef_exp, ds_coef_man, clock;
-
-	if (!(ah->ah_version == AR5K_AR5212) ||
-		!(channel->hw_value & CHANNEL_OFDM))
-		BUG();
-
-	/* Seems there are two PLLs, one for baseband sampling and one
-	 * for tuning. Tuning basebands are 40 MHz or 80MHz when in
-	 * turbo. */
-	clock = channel->hw_value & CHANNEL_TURBO ? 80 : 40;
-	coef_scaled = ((5 * (clock << 24)) / 2) /
-	channel->center_freq;
-
-	for (coef_exp = 31; coef_exp > 0; coef_exp--)
-		if ((coef_scaled >> coef_exp) & 0x1)
-			break;
-
-	if (!coef_exp)
-		return -EINVAL;
-
-	coef_exp = 14 - (coef_exp - 24);
-	coef_man = coef_scaled +
-		(1 << (24 - coef_exp - 1));
-	ds_coef_man = coef_man >> (24 - coef_exp);
-	ds_coef_exp = coef_exp - 16;
-
-	AR5K_REG_WRITE_BITS(ah, AR5K_PHY_TIMING_3,
-		AR5K_PHY_TIMING_3_DSC_MAN, ds_coef_man);
-	AR5K_REG_WRITE_BITS(ah, AR5K_PHY_TIMING_3,
-		AR5K_PHY_TIMING_3_DSC_EXP, ds_coef_exp);
-
-	return 0;
-}
-
-/**
- * ath5k_hw_write_rate_duration - set rate duration during hw resets
- *
- * @ah: the &struct ath5k_hw
- * @mode: one of enum ath5k_driver_mode
- *
- * Write the rate duration table for the current mode upon hw reset. This
- * is a helper for ath5k_hw_reset(). It seems all this is doing is setting
- * an ACK timeout for the hardware for the current mode for each rate. The
- * rates which are capable of short preamble (802.11b rates 2Mbps, 5.5Mbps,
- * and 11Mbps) have another register for the short preamble ACK timeout
- * calculation.
- *
- */
-static inline void ath5k_hw_write_rate_duration(struct ath5k_hw *ah,
-       unsigned int mode)
-{
-	struct ath5k_softc *sc = ah->ah_sc;
-	const struct ath5k_rate_table *rt;
-	struct ieee80211_rate srate = {};
-	unsigned int i;
-
-	/* Get rate table for the current operating mode */
-	rt = ath5k_hw_get_rate_table(ah, mode);
-
-	/* Write rate duration table */
-	for (i = 0; i < rt->rate_count; i++) {
-		const struct ath5k_rate *rate, *control_rate;
-
-		u32 reg;
-		u16 tx_time;
-
-		rate = &rt->rates[i];
-		control_rate = &rt->rates[rate->control_rate];
-
-		/* Set ACK timeout */
-		reg = AR5K_RATE_DUR(rate->rate_code);
-
-		srate.bitrate = control_rate->rate_kbps/100;
-
-		/* An ACK frame consists of 10 bytes. If you add the FCS,
-		 * which ieee80211_generic_frame_duration() adds,
-		 * its 14 bytes. Note we use the control rate and not the
-		 * actual rate for this rate. See mac80211 tx.c
-		 * ieee80211_duration() for a brief description of
-		 * what rate we should choose to TX ACKs. */
-		tx_time = le16_to_cpu(ieee80211_generic_frame_duration(sc->hw,
-							sc->vif, 10, &srate));
-
-		ath5k_hw_reg_write(ah, tx_time, reg);
-
-		if (!HAS_SHPREAMBLE(i))
-			continue;
-
-		/*
-		 * We're not distinguishing short preamble here,
-		 * This is true, all we'll get is a longer value here
-		 * which is not necessarilly bad. We could use
-		 * export ieee80211_frame_duration() but that needs to be
-		 * fixed first to be properly used by mac802111 drivers:
-		 *
-		 *  - remove erp stuff and let the routine figure ofdm
-		 *    erp rates
-		 *  - remove passing argument ieee80211_local as
-		 *    drivers don't have access to it
-		 *  - move drivers using ieee80211_generic_frame_duration()
-		 *    to this
-		 */
-		ath5k_hw_reg_write(ah, tx_time,
-			reg + (AR5K_SET_SHORT_PREAMBLE << 2));
-	}
-}
-
-/*
- * Main reset function
- */
-int ath5k_hw_reset(struct ath5k_hw *ah, enum ieee80211_if_types op_mode,
-	struct ieee80211_channel *channel, bool change_channel)
-{
-	struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
-	struct pci_dev *pdev = ah->ah_sc->pdev;
-	u32 data, s_seq, s_ant, s_led[3], dma_size;
-	unsigned int i, mode, freq, ee_mode, ant[2];
-	int ret;
-
-	ATH5K_TRACE(ah->ah_sc);
-
-	s_seq = 0;
-	s_ant = 0;
-	ee_mode = 0;
-	freq = 0;
-	mode = 0;
-
-	/*
-	 * Save some registers before a reset
-	 */
-	/*DCU/Antenna selection not available on 5210*/
-	if (ah->ah_version != AR5K_AR5210) {
-		if (change_channel) {
-			/* Seq number for queue 0 -do this for all queues ? */
-			s_seq = ath5k_hw_reg_read(ah,
-					AR5K_QUEUE_DFS_SEQNUM(0));
-			/*Default antenna*/
-			s_ant = ath5k_hw_reg_read(ah, AR5K_DEFAULT_ANTENNA);
-		}
-	}
-
-	/*GPIOs*/
-	s_led[0] = ath5k_hw_reg_read(ah, AR5K_PCICFG) & AR5K_PCICFG_LEDSTATE;
-	s_led[1] = ath5k_hw_reg_read(ah, AR5K_GPIOCR);
-	s_led[2] = ath5k_hw_reg_read(ah, AR5K_GPIODO);
-
-	if (change_channel && ah->ah_rf_banks != NULL)
-		ath5k_hw_get_rf_gain(ah);
-
-
-	/*Wakeup the device*/
-	ret = ath5k_hw_nic_wakeup(ah, channel->hw_value, false);
-	if (ret)
-		return ret;
-
-	/*
-	 * Initialize operating mode
-	 */
-	ah->ah_op_mode = op_mode;
-
-	/*
-	 * 5111/5112 Settings
-	 * 5210 only comes with RF5110
-	 */
-	if (ah->ah_version != AR5K_AR5210) {
-		if (ah->ah_radio != AR5K_RF5111 &&
-			ah->ah_radio != AR5K_RF5112 &&
-			ah->ah_radio != AR5K_RF5413 &&
-			ah->ah_radio != AR5K_RF2413 &&
-			ah->ah_radio != AR5K_RF2425) {
-			ATH5K_ERR(ah->ah_sc,
-				"invalid phy radio: %u\n", ah->ah_radio);
-			return -EINVAL;
-		}
-
-		switch (channel->hw_value & CHANNEL_MODES) {
-		case CHANNEL_A:
-			mode = AR5K_MODE_11A;
-			freq = AR5K_INI_RFGAIN_5GHZ;
-			ee_mode = AR5K_EEPROM_MODE_11A;
-			break;
-		case CHANNEL_G:
-			mode = AR5K_MODE_11G;
-			freq = AR5K_INI_RFGAIN_2GHZ;
-			ee_mode = AR5K_EEPROM_MODE_11G;
-			break;
-		case CHANNEL_B:
-			mode = AR5K_MODE_11B;
-			freq = AR5K_INI_RFGAIN_2GHZ;
-			ee_mode = AR5K_EEPROM_MODE_11B;
-			break;
-		case CHANNEL_T:
-			mode = AR5K_MODE_11A_TURBO;
-			freq = AR5K_INI_RFGAIN_5GHZ;
-			ee_mode = AR5K_EEPROM_MODE_11A;
-			break;
-		/*Is this ok on 5211 too ?*/
-		case CHANNEL_TG:
-			mode = AR5K_MODE_11G_TURBO;
-			freq = AR5K_INI_RFGAIN_2GHZ;
-			ee_mode = AR5K_EEPROM_MODE_11G;
-			break;
-		case CHANNEL_XR:
-			if (ah->ah_version == AR5K_AR5211) {
-				ATH5K_ERR(ah->ah_sc,
-					"XR mode not available on 5211");
-				return -EINVAL;
-			}
-			mode = AR5K_MODE_XR;
-			freq = AR5K_INI_RFGAIN_5GHZ;
-			ee_mode = AR5K_EEPROM_MODE_11A;
-			break;
-		default:
-			ATH5K_ERR(ah->ah_sc,
-				"invalid channel: %d\n", channel->center_freq);
-			return -EINVAL;
-		}
-
-		/* PHY access enable */
-		ath5k_hw_reg_write(ah, AR5K_PHY_SHIFT_5GHZ, AR5K_PHY(0));
-
-	}
-
-	ret = ath5k_hw_write_initvals(ah, mode, change_channel);
-	if (ret)
-		return ret;
-
-	/*
-	 * 5211/5212 Specific
-	 */
-	if (ah->ah_version != AR5K_AR5210) {
-		/*
-		 * Write initial RF gain settings
-		 * This should work for both 5111/5112
-		 */
-		ret = ath5k_hw_rfgain(ah, freq);
-		if (ret)
-			return ret;
-
-		mdelay(1);
-
-		/*
-		 * Write some more initial register settings
-		 */
-		if (ah->ah_version == AR5K_AR5212) {
-			ath5k_hw_reg_write(ah, 0x0002a002, 0x982c);
-
-			if (channel->hw_value == CHANNEL_G)
-				if (ah->ah_mac_srev < AR5K_SREV_VER_AR2413)
-					ath5k_hw_reg_write(ah, 0x00f80d80,
-								0x994c);
-				else if (ah->ah_mac_srev < AR5K_SREV_VER_AR2424)
-					ath5k_hw_reg_write(ah, 0x00380140,
-								0x994c);
-				else if (ah->ah_mac_srev < AR5K_SREV_VER_AR2425)
-					ath5k_hw_reg_write(ah, 0x00fc0ec0,
-								0x994c);
-				else /* 2425 */
-					ath5k_hw_reg_write(ah, 0x00fc0fc0,
-								0x994c);
-			else
-				ath5k_hw_reg_write(ah, 0x00000000, 0x994c);
-
-			/* Some bits are disabled here, we know nothing about
-			 * register 0xa228 yet, most of the times this ends up
-			 * with a value 0x9b5 -haven't seen any dump with
-			 * a different value- */
-			/* Got this from decompiling binary HAL */
-			data = ath5k_hw_reg_read(ah, 0xa228);
-			data &= 0xfffffdff;
-			ath5k_hw_reg_write(ah, data, 0xa228);
-
-			data = ath5k_hw_reg_read(ah, 0xa228);
-			data &= 0xfffe03ff;
-			ath5k_hw_reg_write(ah, data, 0xa228);
-			data = 0;
-
-			/* Just write 0x9b5 ? */
-			/* ath5k_hw_reg_write(ah, 0x000009b5, 0xa228); */
-			ath5k_hw_reg_write(ah, 0x0000000f, AR5K_SEQ_MASK);
-			ath5k_hw_reg_write(ah, 0x00000000, 0xa254);
-			ath5k_hw_reg_write(ah, 0x0000000e, AR5K_PHY_SCAL);
-		}
-
-		/* Fix for first revision of the RF5112 RF chipset */
-		if (ah->ah_radio >= AR5K_RF5112 &&
-				ah->ah_radio_5ghz_revision <
-				AR5K_SREV_RAD_5112A) {
-			ath5k_hw_reg_write(ah, AR5K_PHY_CCKTXCTL_WORLD,
-					AR5K_PHY_CCKTXCTL);
-			if (channel->hw_value & CHANNEL_5GHZ)
-				data = 0xffb81020;
-			else
-				data = 0xffb80d20;
-			ath5k_hw_reg_write(ah, data, AR5K_PHY_FRAME_CTL);
-			data = 0;
-		}
-
-		/*
-		 * Set TX power (FIXME)
-		 */
-		ret = ath5k_hw_txpower(ah, channel, AR5K_TUNE_DEFAULT_TXPOWER);
-		if (ret)
-			return ret;
-
-		/* Write rate duration table only on AR5212 and if
-		 * virtual interface has already been brought up
-		 * XXX: rethink this after new mode changes to
-		 * mac80211 are integrated */
-		if (ah->ah_version == AR5K_AR5212 &&
-			ah->ah_sc->vif != NULL)
-			ath5k_hw_write_rate_duration(ah, mode);
-
-		/*
-		 * Write RF registers
-		 */
-		ret = ath5k_hw_rfregs(ah, channel, mode);
-		if (ret)
-			return ret;
-
-		/*
-		 * Configure additional registers
-		 */
-
-		/* Write OFDM timings on 5212*/
-		if (ah->ah_version == AR5K_AR5212 &&
-			channel->hw_value & CHANNEL_OFDM) {
-			ret = ath5k_hw_write_ofdm_timings(ah, channel);
-			if (ret)
-				return ret;
-		}
-
-		/*Enable/disable 802.11b mode on 5111
-		(enable 2111 frequency converter + CCK)*/
-		if (ah->ah_radio == AR5K_RF5111) {
-			if (mode == AR5K_MODE_11B)
-				AR5K_REG_ENABLE_BITS(ah, AR5K_TXCFG,
-				    AR5K_TXCFG_B_MODE);
-			else
-				AR5K_REG_DISABLE_BITS(ah, AR5K_TXCFG,
-				    AR5K_TXCFG_B_MODE);
-		}
-
-		/*
-		 * Set channel and calibrate the PHY
-		 */
-		ret = ath5k_hw_channel(ah, channel);
-		if (ret)
-			return ret;
-
-		/* Set antenna mode */
-		AR5K_REG_MASKED_BITS(ah, AR5K_PHY_ANT_CTL,
-			ah->ah_antenna[ee_mode][0], 0xfffffc06);
-
-		/*
-		 * In case a fixed antenna was set as default
-		 * write the same settings on both AR5K_PHY_ANT_SWITCH_TABLE
-		 * registers.
-		 */
-		if (s_ant != 0){
-			if (s_ant == AR5K_ANT_FIXED_A) /* 1 - Main */
-				ant[0] = ant[1] = AR5K_ANT_FIXED_A;
-			else	/* 2 - Aux */
-				ant[0] = ant[1] = AR5K_ANT_FIXED_B;
-		} else {
-			ant[0] = AR5K_ANT_FIXED_A;
-			ant[1] = AR5K_ANT_FIXED_B;
-		}
-
-		ath5k_hw_reg_write(ah, ah->ah_antenna[ee_mode][ant[0]],
-			AR5K_PHY_ANT_SWITCH_TABLE_0);
-		ath5k_hw_reg_write(ah, ah->ah_antenna[ee_mode][ant[1]],
-			AR5K_PHY_ANT_SWITCH_TABLE_1);
-
-		/* Commit values from EEPROM */
-		if (ah->ah_radio == AR5K_RF5111)
-			AR5K_REG_WRITE_BITS(ah, AR5K_PHY_FRAME_CTL,
-			    AR5K_PHY_FRAME_CTL_TX_CLIP, ee->ee_tx_clip);
-
-		ath5k_hw_reg_write(ah,
-			AR5K_PHY_NF_SVAL(ee->ee_noise_floor_thr[ee_mode]),
-			AR5K_PHY_NFTHRES);
-
-		AR5K_REG_MASKED_BITS(ah, AR5K_PHY_SETTLING,
-			(ee->ee_switch_settling[ee_mode] << 7) & 0x3f80,
-			0xffffc07f);
-		AR5K_REG_MASKED_BITS(ah, AR5K_PHY_GAIN,
-			(ee->ee_ant_tx_rx[ee_mode] << 12) & 0x3f000,
-			0xfffc0fff);
-		AR5K_REG_MASKED_BITS(ah, AR5K_PHY_DESIRED_SIZE,
-			(ee->ee_adc_desired_size[ee_mode] & 0x00ff) |
-			((ee->ee_pga_desired_size[ee_mode] << 8) & 0xff00),
-			0xffff0000);
-
-		ath5k_hw_reg_write(ah,
-			(ee->ee_tx_end2xpa_disable[ee_mode] << 24) |
-			(ee->ee_tx_end2xpa_disable[ee_mode] << 16) |
-			(ee->ee_tx_frm2xpa_enable[ee_mode] << 8) |
-			(ee->ee_tx_frm2xpa_enable[ee_mode]), AR5K_PHY_RF_CTL4);
-
-		AR5K_REG_MASKED_BITS(ah, AR5K_PHY_RF_CTL3,
-			ee->ee_tx_end2xlna_enable[ee_mode] << 8, 0xffff00ff);
-		AR5K_REG_MASKED_BITS(ah, AR5K_PHY_NF,
-			(ee->ee_thr_62[ee_mode] << 12) & 0x7f000, 0xfff80fff);
-		AR5K_REG_MASKED_BITS(ah, AR5K_PHY_OFDM_SELFCORR, 4, 0xffffff01);
-
-		AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_IQ,
-		    AR5K_PHY_IQ_CORR_ENABLE |
-		    (ee->ee_i_cal[ee_mode] << AR5K_PHY_IQ_CORR_Q_I_COFF_S) |
-		    ee->ee_q_cal[ee_mode]);
-
-		if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_1)
-			AR5K_REG_WRITE_BITS(ah, AR5K_PHY_GAIN_2GHZ,
-				AR5K_PHY_GAIN_2GHZ_MARGIN_TXRX,
-				ee->ee_margin_tx_rx[ee_mode]);
-
-	} else {
-		mdelay(1);
-		/* Disable phy and wait */
-		ath5k_hw_reg_write(ah, AR5K_PHY_ACT_DISABLE, AR5K_PHY_ACT);
-		mdelay(1);
-	}
-
-	/*
-	 * Restore saved values
-	 */
-	/*DCU/Antenna selection not available on 5210*/
-	if (ah->ah_version != AR5K_AR5210) {
-		ath5k_hw_reg_write(ah, s_seq, AR5K_QUEUE_DFS_SEQNUM(0));
-		ath5k_hw_reg_write(ah, s_ant, AR5K_DEFAULT_ANTENNA);
-	}
-	AR5K_REG_ENABLE_BITS(ah, AR5K_PCICFG, s_led[0]);
-	ath5k_hw_reg_write(ah, s_led[1], AR5K_GPIOCR);
-	ath5k_hw_reg_write(ah, s_led[2], AR5K_GPIODO);
-
-	/*
-	 * Misc
-	 */
-	/* XXX: add ah->aid once mac80211 gives this to us */
-	ath5k_hw_set_associd(ah, ah->ah_bssid, 0);
-
-	ath5k_hw_set_opmode(ah);
-	/*PISR/SISR Not available on 5210*/
-	if (ah->ah_version != AR5K_AR5210) {
-		ath5k_hw_reg_write(ah, 0xffffffff, AR5K_PISR);
-		/* If we later allow tuning for this, store into sc structure */
-		data = AR5K_TUNE_RSSI_THRES |
-			AR5K_TUNE_BMISS_THRES << AR5K_RSSI_THR_BMISS_S;
-		ath5k_hw_reg_write(ah, data, AR5K_RSSI_THR);
-	}
-
-	/*
-	 * Set Rx/Tx DMA Configuration
-	 *
-	 * Set maximum DMA size (512) except for PCI-E cards since
-	 * it causes rx overruns and tx errors (tested on 5424 but since
-	 * rx overruns also occur on 5416/5418 with madwifi we set 128
-	 * for all PCI-E cards to be safe).
-	 *
-	 * In dumps this is 128 for allchips.
-	 *
-	 * XXX: need to check 5210 for this
-	 * TODO: Check out tx triger level, it's always 64 on dumps but I
-	 * guess we can tweak it and see how it goes ;-)
-	 */
-	dma_size = (pdev->is_pcie) ? AR5K_DMASIZE_128B : AR5K_DMASIZE_512B;
-	if (ah->ah_version != AR5K_AR5210) {
-		AR5K_REG_WRITE_BITS(ah, AR5K_TXCFG,
-			AR5K_TXCFG_SDMAMR, dma_size);
-		AR5K_REG_WRITE_BITS(ah, AR5K_RXCFG,
-			AR5K_RXCFG_SDMAMW, dma_size);
-	}
-
-	/*
-	 * Enable the PHY and wait until completion
-	 */
-	ath5k_hw_reg_write(ah, AR5K_PHY_ACT_ENABLE, AR5K_PHY_ACT);
-
-	/*
-	 * On 5211+ read activation -> rx delay
-	 * and use it.
-	 */
-	if (ah->ah_version != AR5K_AR5210) {
-		data = ath5k_hw_reg_read(ah, AR5K_PHY_RX_DELAY) &
-			AR5K_PHY_RX_DELAY_M;
-		data = (channel->hw_value & CHANNEL_CCK) ?
-			((data << 2) / 22) : (data / 10);
-
-		udelay(100 + (2 * data));
-		data = 0;
-	} else {
-		mdelay(1);
-	}
-
-	/*
-	 * Perform ADC test (?)
-	 */
-	data = ath5k_hw_reg_read(ah, AR5K_PHY_TST1);
-	ath5k_hw_reg_write(ah, AR5K_PHY_TST1_TXHOLD, AR5K_PHY_TST1);
-	for (i = 0; i <= 20; i++) {
-		if (!(ath5k_hw_reg_read(ah, AR5K_PHY_ADC_TEST) & 0x10))
-			break;
-		udelay(200);
-	}
-	ath5k_hw_reg_write(ah, data, AR5K_PHY_TST1);
-	data = 0;
-
-	/*
-	 * Start automatic gain calibration
-	 *
-	 * During AGC calibration RX path is re-routed to
-	 * a signal detector so we don't receive anything.
-	 *
-	 * This method is used to calibrate some static offsets
-	 * used together with on-the fly I/Q calibration (the
-	 * one performed via ath5k_hw_phy_calibrate), that doesn't
-	 * interrupt rx path.
-	 *
-	 * If we are in a noisy environment AGC calibration may time
-	 * out.
-	 */
-	AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_AGCCTL,
-				AR5K_PHY_AGCCTL_CAL);
-
-	/* At the same time start I/Q calibration for QAM constellation
-	 * -no need for CCK- */
-	ah->ah_calibration = false;
-	if (!(mode == AR5K_MODE_11B)) {
-		ah->ah_calibration = true;
-		AR5K_REG_WRITE_BITS(ah, AR5K_PHY_IQ,
-				AR5K_PHY_IQ_CAL_NUM_LOG_MAX, 15);
-		AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_IQ,
-				AR5K_PHY_IQ_RUN);
-	}
-
-	/* Wait for gain calibration to finish (we check for I/Q calibration
-	 * during ath5k_phy_calibrate) */
-	if (ath5k_hw_register_timeout(ah, AR5K_PHY_AGCCTL,
-			AR5K_PHY_AGCCTL_CAL, 0, false)) {
-		ATH5K_ERR(ah->ah_sc, "gain calibration timeout (%uMHz)\n",
-			channel->center_freq);
-		return -EAGAIN;
-	}
-
-	/*
-	 * Start noise floor calibration
-	 *
-	 * If we run NF calibration before AGC, it always times out.
-	 * Binary HAL starts NF and AGC calibration at the same time
-	 * and only waits for AGC to finish. I believe that's wrong because
-	 * during NF calibration, rx path is also routed to a detector, so if
-	 * it doesn't finish we won't have RX.
-	 *
-	 * XXX: Find an interval that's OK for all cards...
-	 */
-	ret = ath5k_hw_noise_floor_calibration(ah, channel->center_freq);
-	if (ret)
-		return ret;
-
-	/*
-	 * Reset queues and start beacon timers at the end of the reset routine
-	 */
-	for (i = 0; i < ah->ah_capabilities.cap_queues.q_tx_num; i++) {
-		/*No QCU on 5210*/
-		if (ah->ah_version != AR5K_AR5210)
-			AR5K_REG_WRITE_Q(ah, AR5K_QUEUE_QCUMASK(i), i);
-
-		ret = ath5k_hw_reset_tx_queue(ah, i);
-		if (ret) {
-			ATH5K_ERR(ah->ah_sc,
-				"failed to reset TX queue #%d\n", i);
-			return ret;
-		}
-	}
-
-	/* Pre-enable interrupts on 5211/5212*/
-	if (ah->ah_version != AR5K_AR5210)
-		ath5k_hw_set_intr(ah, AR5K_INT_RX | AR5K_INT_TX |
-				AR5K_INT_FATAL);
-
-	/*
-	 * Set RF kill flags if supported by the device (read from the EEPROM)
-	 * Disable gpio_intr for now since it results system hang.
-	 * TODO: Handle this in ath5k_intr
-	 */
-#if 0
-	if (AR5K_EEPROM_HDR_RFKILL(ah->ah_capabilities.cap_eeprom.ee_header)) {
-		ath5k_hw_set_gpio_input(ah, 0);
-		ah->ah_gpio[0] = ath5k_hw_get_gpio(ah, 0);
-		if (ah->ah_gpio[0] == 0)
-			ath5k_hw_set_gpio_intr(ah, 0, 1);
-		else
-			ath5k_hw_set_gpio_intr(ah, 0, 0);
-	}
-#endif
-
-	/*
-	 * Set the 32MHz reference clock on 5212 phy clock sleep register
-	 *
-	 * TODO: Find out how to switch to external 32Khz clock to save power
-	 */
-	if (ah->ah_version == AR5K_AR5212) {
-		ath5k_hw_reg_write(ah, AR5K_PHY_SCR_32MHZ, AR5K_PHY_SCR);
-		ath5k_hw_reg_write(ah, AR5K_PHY_SLMT_32MHZ, AR5K_PHY_SLMT);
-		ath5k_hw_reg_write(ah, AR5K_PHY_SCAL_32MHZ, AR5K_PHY_SCAL);
-		ath5k_hw_reg_write(ah, AR5K_PHY_SCLOCK_32MHZ, AR5K_PHY_SCLOCK);
-		ath5k_hw_reg_write(ah, AR5K_PHY_SDELAY_32MHZ, AR5K_PHY_SDELAY);
-		ath5k_hw_reg_write(ah, ah->ah_phy_spending, AR5K_PHY_SPENDING);
-
-		data = ath5k_hw_reg_read(ah, AR5K_USEC_5211) & 0xffffc07f ;
-		data |= (ah->ah_phy_spending == AR5K_PHY_SPENDING_18) ?
-						0x00000f80 : 0x00001380 ;
-		ath5k_hw_reg_write(ah, data, AR5K_USEC_5211);
-		data = 0;
-	}
-
-	if (ah->ah_version == AR5K_AR5212) {
-		ath5k_hw_reg_write(ah, 0x000100aa, 0x8118);
-		ath5k_hw_reg_write(ah, 0x00003210, 0x811c);
-		ath5k_hw_reg_write(ah, 0x00000052, 0x8108);
-		if (ah->ah_mac_srev >= AR5K_SREV_VER_AR2413)
-			ath5k_hw_reg_write(ah, 0x00000004, 0x8120);
-	}
-
-	/*
-	 * Disable beacons and reset the register
-	 */
-	AR5K_REG_DISABLE_BITS(ah, AR5K_BEACON, AR5K_BEACON_ENABLE |
-			AR5K_BEACON_RESET_TSF);
-
-	return 0;
-}
-
-/*
- * Reset chipset
- */
-static int ath5k_hw_nic_reset(struct ath5k_hw *ah, u32 val)
-{
-	int ret;
-	u32 mask = val ? val : ~0U;
-
-	ATH5K_TRACE(ah->ah_sc);
-
-	/* Read-and-clear RX Descriptor Pointer*/
-	ath5k_hw_reg_read(ah, AR5K_RXDP);
-
-	/*
-	 * Reset the device and wait until success
-	 */
-	ath5k_hw_reg_write(ah, val, AR5K_RESET_CTL);
-
-	/* Wait at least 128 PCI clocks */
-	udelay(15);
-
-	if (ah->ah_version == AR5K_AR5210) {
-		val &= AR5K_RESET_CTL_CHIP;
-		mask &= AR5K_RESET_CTL_CHIP;
-	} else {
-		val &= AR5K_RESET_CTL_PCU | AR5K_RESET_CTL_BASEBAND;
-		mask &= AR5K_RESET_CTL_PCU | AR5K_RESET_CTL_BASEBAND;
-	}
-
-	ret = ath5k_hw_register_timeout(ah, AR5K_RESET_CTL, mask, val, false);
-
-	/*
-	 * Reset configuration register (for hw byte-swap). Note that this
-	 * is only set for big endian. We do the necessary magic in
-	 * AR5K_INIT_CFG.
-	 */
-	if ((val & AR5K_RESET_CTL_PCU) == 0)
-		ath5k_hw_reg_write(ah, AR5K_INIT_CFG, AR5K_CFG);
-
-	return ret;
-}
-
-/*
- * Power management functions
- */
-
-/*
- * Sleep control
- */
-int ath5k_hw_set_power(struct ath5k_hw *ah, enum ath5k_power_mode mode,
-		bool set_chip, u16 sleep_duration)
-{
-	unsigned int i;
-	u32 staid, data;
-
-	ATH5K_TRACE(ah->ah_sc);
-	staid = ath5k_hw_reg_read(ah, AR5K_STA_ID1);
-
-	switch (mode) {
-	case AR5K_PM_AUTO:
-		staid &= ~AR5K_STA_ID1_DEFAULT_ANTENNA;
-		/* fallthrough */
-	case AR5K_PM_NETWORK_SLEEP:
-		if (set_chip)
-			ath5k_hw_reg_write(ah,
-				AR5K_SLEEP_CTL_SLE_ALLOW |
-				sleep_duration,
-				AR5K_SLEEP_CTL);
-
-		staid |= AR5K_STA_ID1_PWR_SV;
-		break;
-
-	case AR5K_PM_FULL_SLEEP:
-		if (set_chip)
-			ath5k_hw_reg_write(ah, AR5K_SLEEP_CTL_SLE_SLP,
-				AR5K_SLEEP_CTL);
-
-		staid |= AR5K_STA_ID1_PWR_SV;
-		break;
-
-	case AR5K_PM_AWAKE:
-
-		staid &= ~AR5K_STA_ID1_PWR_SV;
-
-		if (!set_chip)
-			goto commit;
-
-		/* Preserve sleep duration */
-		data = ath5k_hw_reg_read(ah, AR5K_SLEEP_CTL);
-		if( data & 0xffc00000 ){
-			data = 0;
-		} else {
-			data = data & 0xfffcffff;
-		}
-
-		ath5k_hw_reg_write(ah, data, AR5K_SLEEP_CTL);
-		udelay(15);
-
-		for (i = 50; i > 0; i--) {
-			/* Check if the chip did wake up */
-			if ((ath5k_hw_reg_read(ah, AR5K_PCICFG) &
-					AR5K_PCICFG_SPWR_DN) == 0)
-				break;
-
-			/* Wait a bit and retry */
-			udelay(200);
-			ath5k_hw_reg_write(ah, data, AR5K_SLEEP_CTL);
-		}
-
-		/* Fail if the chip didn't wake up */
-		if (i <= 0)
-			return -EIO;
-
-		break;
-
-	default:
-		return -EINVAL;
-	}
-
-commit:
-	ah->ah_power_mode = mode;
-	ath5k_hw_reg_write(ah, staid, AR5K_STA_ID1);
-
-	return 0;
-}
-
-/***********************\
-  DMA Related Functions
-\***********************/
-
-/*
- * Receive functions
- */
-
-/*
- * Start DMA receive
- */
-void ath5k_hw_start_rx(struct ath5k_hw *ah)
-{
-	ATH5K_TRACE(ah->ah_sc);
-	ath5k_hw_reg_write(ah, AR5K_CR_RXE, AR5K_CR);
-	ath5k_hw_reg_read(ah, AR5K_CR);
-}
-
-/*
- * Stop DMA receive
- */
-int ath5k_hw_stop_rx_dma(struct ath5k_hw *ah)
-{
-	unsigned int i;
-
-	ATH5K_TRACE(ah->ah_sc);
-	ath5k_hw_reg_write(ah, AR5K_CR_RXD, AR5K_CR);
-
-	/*
-	 * It may take some time to disable the DMA receive unit
-	 */
-	for (i = 2000; i > 0 &&
-			(ath5k_hw_reg_read(ah, AR5K_CR) & AR5K_CR_RXE) != 0;
-			i--)
-		udelay(10);
-
-	return i ? 0 : -EBUSY;
-}
-
-/*
- * Get the address of the RX Descriptor
- */
-u32 ath5k_hw_get_rx_buf(struct ath5k_hw *ah)
-{
-	return ath5k_hw_reg_read(ah, AR5K_RXDP);
-}
-
-/*
- * Set the address of the RX Descriptor
- */
-void ath5k_hw_put_rx_buf(struct ath5k_hw *ah, u32 phys_addr)
-{
-	ATH5K_TRACE(ah->ah_sc);
-
-	/*TODO:Shouldn't we check if RX is enabled first ?*/
-	ath5k_hw_reg_write(ah, phys_addr, AR5K_RXDP);
-}
-
-/*
- * Transmit functions
- */
-
-/*
- * Start DMA transmit for a specific queue
- * (see also QCU/DCU functions)
- */
-int ath5k_hw_tx_start(struct ath5k_hw *ah, unsigned int queue)
-{
-	u32 tx_queue;
-
-	ATH5K_TRACE(ah->ah_sc);
-	AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num);
-
-	/* Return if queue is declared inactive */
-	if (ah->ah_txq[queue].tqi_type == AR5K_TX_QUEUE_INACTIVE)
-		return -EIO;
-
-	if (ah->ah_version == AR5K_AR5210) {
-		tx_queue = ath5k_hw_reg_read(ah, AR5K_CR);
-
-		/*
-		 * Set the queue by type on 5210
-		 */
-		switch (ah->ah_txq[queue].tqi_type) {
-		case AR5K_TX_QUEUE_DATA:
-			tx_queue |= AR5K_CR_TXE0 & ~AR5K_CR_TXD0;
-			break;
-		case AR5K_TX_QUEUE_BEACON:
-			tx_queue |= AR5K_CR_TXE1 & ~AR5K_CR_TXD1;
-			ath5k_hw_reg_write(ah, AR5K_BCR_TQ1V | AR5K_BCR_BDMAE,
-					AR5K_BSR);
-			break;
-		case AR5K_TX_QUEUE_CAB:
-			tx_queue |= AR5K_CR_TXE1 & ~AR5K_CR_TXD1;
-			ath5k_hw_reg_write(ah, AR5K_BCR_TQ1FV | AR5K_BCR_TQ1V |
-				AR5K_BCR_BDMAE, AR5K_BSR);
-			break;
-		default:
-			return -EINVAL;
-		}
-		/* Start queue */
-		ath5k_hw_reg_write(ah, tx_queue, AR5K_CR);
-		ath5k_hw_reg_read(ah, AR5K_CR);
-	} else {
-		/* Return if queue is disabled */
-		if (AR5K_REG_READ_Q(ah, AR5K_QCU_TXD, queue))
-			return -EIO;
-
-		/* Start queue */
-		AR5K_REG_WRITE_Q(ah, AR5K_QCU_TXE, queue);
-	}
-
-	return 0;
-}
-
-/*
- * Stop DMA transmit for a specific queue
- * (see also QCU/DCU functions)
- */
-int ath5k_hw_stop_tx_dma(struct ath5k_hw *ah, unsigned int queue)
-{
-	unsigned int i = 100;
-	u32 tx_queue, pending;
-
-	ATH5K_TRACE(ah->ah_sc);
-	AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num);
-
-	/* Return if queue is declared inactive */
-	if (ah->ah_txq[queue].tqi_type == AR5K_TX_QUEUE_INACTIVE)
-		return -EIO;
-
-	if (ah->ah_version == AR5K_AR5210) {
-		tx_queue = ath5k_hw_reg_read(ah, AR5K_CR);
-
-		/*
-		 * Set by queue type
-		 */
-		switch (ah->ah_txq[queue].tqi_type) {
-		case AR5K_TX_QUEUE_DATA:
-			tx_queue |= AR5K_CR_TXD0 & ~AR5K_CR_TXE0;
-			break;
-		case AR5K_TX_QUEUE_BEACON:
-		case AR5K_TX_QUEUE_CAB:
-			/* XXX Fix me... */
-			tx_queue |= AR5K_CR_TXD1 & ~AR5K_CR_TXD1;
-			ath5k_hw_reg_write(ah, 0, AR5K_BSR);
-			break;
-		default:
-			return -EINVAL;
-		}
-
-		/* Stop queue */
-		ath5k_hw_reg_write(ah, tx_queue, AR5K_CR);
-		ath5k_hw_reg_read(ah, AR5K_CR);
-	} else {
-		/*
-		 * Schedule TX disable and wait until queue is empty
-		 */
-		AR5K_REG_WRITE_Q(ah, AR5K_QCU_TXD, queue);
-
-		/*Check for pending frames*/
-		do {
-			pending = ath5k_hw_reg_read(ah,
-				AR5K_QUEUE_STATUS(queue)) &
-				AR5K_QCU_STS_FRMPENDCNT;
-			udelay(100);
-		} while (--i && pending);
-
-		/* Clear register */
-		ath5k_hw_reg_write(ah, 0, AR5K_QCU_TXD);
-		if (pending)
-			return -EBUSY;
-	}
-
-	/* TODO: Check for success else return error */
-	return 0;
-}
-
-/*
- * Get the address of the TX Descriptor for a specific queue
- * (see also QCU/DCU functions)
- */
-u32 ath5k_hw_get_tx_buf(struct ath5k_hw *ah, unsigned int queue)
-{
-	u16 tx_reg;
-
-	ATH5K_TRACE(ah->ah_sc);
-	AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num);
-
-	/*
-	 * Get the transmit queue descriptor pointer from the selected queue
-	 */
-	/*5210 doesn't have QCU*/
-	if (ah->ah_version == AR5K_AR5210) {
-		switch (ah->ah_txq[queue].tqi_type) {
-		case AR5K_TX_QUEUE_DATA:
-			tx_reg = AR5K_NOQCU_TXDP0;
-			break;
-		case AR5K_TX_QUEUE_BEACON:
-		case AR5K_TX_QUEUE_CAB:
-			tx_reg = AR5K_NOQCU_TXDP1;
-			break;
-		default:
-			return 0xffffffff;
-		}
-	} else {
-		tx_reg = AR5K_QUEUE_TXDP(queue);
-	}
-
-	return ath5k_hw_reg_read(ah, tx_reg);
-}
-
-/*
- * Set the address of the TX Descriptor for a specific queue
- * (see also QCU/DCU functions)
- */
-int ath5k_hw_put_tx_buf(struct ath5k_hw *ah, unsigned int queue, u32 phys_addr)
-{
-	u16 tx_reg;
-
-	ATH5K_TRACE(ah->ah_sc);
-	AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num);
-
-	/*
-	 * Set the transmit queue descriptor pointer register by type
-	 * on 5210
-	 */
-	if (ah->ah_version == AR5K_AR5210) {
-		switch (ah->ah_txq[queue].tqi_type) {
-		case AR5K_TX_QUEUE_DATA:
-			tx_reg = AR5K_NOQCU_TXDP0;
-			break;
-		case AR5K_TX_QUEUE_BEACON:
-		case AR5K_TX_QUEUE_CAB:
-			tx_reg = AR5K_NOQCU_TXDP1;
-			break;
-		default:
-			return -EINVAL;
-		}
-	} else {
-		/*
-		 * Set the transmit queue descriptor pointer for
-		 * the selected queue on QCU for 5211+
-		 * (this won't work if the queue is still active)
-		 */
-		if (AR5K_REG_READ_Q(ah, AR5K_QCU_TXE, queue))
-			return -EIO;
-
-		tx_reg = AR5K_QUEUE_TXDP(queue);
-	}
-
-	/* Set descriptor pointer */
-	ath5k_hw_reg_write(ah, phys_addr, tx_reg);
-
-	return 0;
-}
-
-/*
- * Update tx trigger level
- */
-int ath5k_hw_update_tx_triglevel(struct ath5k_hw *ah, bool increase)
-{
-	u32 trigger_level, imr;
-	int ret = -EIO;
-
-	ATH5K_TRACE(ah->ah_sc);
-
-	/*
-	 * Disable interrupts by setting the mask
-	 */
-	imr = ath5k_hw_set_intr(ah, ah->ah_imr & ~AR5K_INT_GLOBAL);
-
-	/*TODO: Boundary check on trigger_level*/
-	trigger_level = AR5K_REG_MS(ath5k_hw_reg_read(ah, AR5K_TXCFG),
-			AR5K_TXCFG_TXFULL);
-
-	if (!increase) {
-		if (--trigger_level < AR5K_TUNE_MIN_TX_FIFO_THRES)
-			goto done;
-	} else
-		trigger_level +=
-			((AR5K_TUNE_MAX_TX_FIFO_THRES - trigger_level) / 2);
-
-	/*
-	 * Update trigger level on success
-	 */
-	if (ah->ah_version == AR5K_AR5210)
-		ath5k_hw_reg_write(ah, trigger_level, AR5K_TRIG_LVL);
-	else
-		AR5K_REG_WRITE_BITS(ah, AR5K_TXCFG,
-				AR5K_TXCFG_TXFULL, trigger_level);
-
-	ret = 0;
-
-done:
-	/*
-	 * Restore interrupt mask
-	 */
-	ath5k_hw_set_intr(ah, imr);
-
-	return ret;
-}
-
-/*
- * Interrupt handling
- */
-
-/*
- * Check if we have pending interrupts
- */
-bool ath5k_hw_is_intr_pending(struct ath5k_hw *ah)
-{
-	ATH5K_TRACE(ah->ah_sc);
-	return ath5k_hw_reg_read(ah, AR5K_INTPEND);
-}
-
-/*
- * Get interrupt mask (ISR)
- */
-int ath5k_hw_get_isr(struct ath5k_hw *ah, enum ath5k_int *interrupt_mask)
-{
-	u32 data;
-
-	ATH5K_TRACE(ah->ah_sc);
-
-	/*
-	 * Read interrupt status from the Interrupt Status register
-	 * on 5210
-	 */
-	if (ah->ah_version == AR5K_AR5210) {
-		data = ath5k_hw_reg_read(ah, AR5K_ISR);
-		if (unlikely(data == AR5K_INT_NOCARD)) {
-			*interrupt_mask = data;
-			return -ENODEV;
-		}
-	} else {
-		/*
-		 * Read interrupt status from the Read-And-Clear shadow register
-		 * Note: PISR/SISR Not available on 5210
-		 */
-		data = ath5k_hw_reg_read(ah, AR5K_RAC_PISR);
-	}
-
-	/*
-	 * Get abstract interrupt mask (driver-compatible)
-	 */
-	*interrupt_mask = (data & AR5K_INT_COMMON) & ah->ah_imr;
-
-	if (unlikely(data == AR5K_INT_NOCARD))
-		return -ENODEV;
-
-	if (data & (AR5K_ISR_RXOK | AR5K_ISR_RXERR))
-		*interrupt_mask |= AR5K_INT_RX;
-
-	if (data & (AR5K_ISR_TXOK | AR5K_ISR_TXERR
-		| AR5K_ISR_TXDESC | AR5K_ISR_TXEOL))
-		*interrupt_mask |= AR5K_INT_TX;
-
-	if (ah->ah_version != AR5K_AR5210) {
-		/*HIU = Host Interface Unit (PCI etc)*/
-		if (unlikely(data & (AR5K_ISR_HIUERR)))
-			*interrupt_mask |= AR5K_INT_FATAL;
-
-		/*Beacon Not Ready*/
-		if (unlikely(data & (AR5K_ISR_BNR)))
-			*interrupt_mask |= AR5K_INT_BNR;
-	}
-
-	/*
-	 * XXX: BMISS interrupts may occur after association.
-	 * I found this on 5210 code but it needs testing. If this is
-	 * true we should disable them before assoc and re-enable them
-	 * after a successfull assoc + some jiffies.
-	 */
-#if 0
-	interrupt_mask &= ~AR5K_INT_BMISS;
-#endif
-
-	/*
-	 * In case we didn't handle anything,
-	 * print the register value.
-	 */
-	if (unlikely(*interrupt_mask == 0 && net_ratelimit()))
-		ATH5K_PRINTF("0x%08x\n", data);
-
-	return 0;
-}
-
-/*
- * Set interrupt mask
- */
-enum ath5k_int ath5k_hw_set_intr(struct ath5k_hw *ah, enum ath5k_int new_mask)
-{
-	enum ath5k_int old_mask, int_mask;
-
-	/*
-	 * Disable card interrupts to prevent any race conditions
-	 * (they will be re-enabled afterwards).
-	 */
-	ath5k_hw_reg_write(ah, AR5K_IER_DISABLE, AR5K_IER);
-	ath5k_hw_reg_read(ah, AR5K_IER);
-
-	old_mask = ah->ah_imr;
-
-	/*
-	 * Add additional, chipset-dependent interrupt mask flags
-	 * and write them to the IMR (interrupt mask register).
-	 */
-	int_mask = new_mask & AR5K_INT_COMMON;
-
-	if (new_mask & AR5K_INT_RX)
-		int_mask |= AR5K_IMR_RXOK | AR5K_IMR_RXERR | AR5K_IMR_RXORN |
-			AR5K_IMR_RXDESC;
-
-	if (new_mask & AR5K_INT_TX)
-		int_mask |= AR5K_IMR_TXOK | AR5K_IMR_TXERR | AR5K_IMR_TXDESC |
-			AR5K_IMR_TXURN;
-
-	if (ah->ah_version != AR5K_AR5210) {
-		if (new_mask & AR5K_INT_FATAL) {
-			int_mask |= AR5K_IMR_HIUERR;
-			AR5K_REG_ENABLE_BITS(ah, AR5K_SIMR2, AR5K_SIMR2_MCABT |
-					AR5K_SIMR2_SSERR | AR5K_SIMR2_DPERR);
-		}
-	}
-
-	ath5k_hw_reg_write(ah, int_mask, AR5K_PIMR);
-
-	/* Store new interrupt mask */
-	ah->ah_imr = new_mask;
-
-	/* ..re-enable interrupts */
-	ath5k_hw_reg_write(ah, AR5K_IER_ENABLE, AR5K_IER);
-	ath5k_hw_reg_read(ah, AR5K_IER);
-
-	return old_mask;
-}
-
-
-/*************************\
-  EEPROM access functions
-\*************************/
-
-/*
- * Read from eeprom
- */
-static int ath5k_hw_eeprom_read(struct ath5k_hw *ah, u32 offset, u16 *data)
-{
-	u32 status, timeout;
-
-	ATH5K_TRACE(ah->ah_sc);
-	/*
-	 * Initialize EEPROM access
-	 */
-	if (ah->ah_version == AR5K_AR5210) {
-		AR5K_REG_ENABLE_BITS(ah, AR5K_PCICFG, AR5K_PCICFG_EEAE);
-		(void)ath5k_hw_reg_read(ah, AR5K_EEPROM_BASE + (4 * offset));
-	} else {
-		ath5k_hw_reg_write(ah, offset, AR5K_EEPROM_BASE);
-		AR5K_REG_ENABLE_BITS(ah, AR5K_EEPROM_CMD,
-				AR5K_EEPROM_CMD_READ);
-	}
-
-	for (timeout = AR5K_TUNE_REGISTER_TIMEOUT; timeout > 0; timeout--) {
-		status = ath5k_hw_reg_read(ah, AR5K_EEPROM_STATUS);
-		if (status & AR5K_EEPROM_STAT_RDDONE) {
-			if (status & AR5K_EEPROM_STAT_RDERR)
-				return -EIO;
-			*data = (u16)(ath5k_hw_reg_read(ah, AR5K_EEPROM_DATA) &
-					0xffff);
-			return 0;
-		}
-		udelay(15);
-	}
-
-	return -ETIMEDOUT;
-}
-
-/*
- * Write to eeprom - currently disabled, use at your own risk
- */
-#if 0
-static int ath5k_hw_eeprom_write(struct ath5k_hw *ah, u32 offset, u16 data)
-{
-
-	u32 status, timeout;
-
-	ATH5K_TRACE(ah->ah_sc);
-
-	/*
-	 * Initialize eeprom access
-	 */
-
-	if (ah->ah_version == AR5K_AR5210) {
-		AR5K_REG_ENABLE_BITS(ah, AR5K_PCICFG, AR5K_PCICFG_EEAE);
-	} else {
-		AR5K_REG_ENABLE_BITS(ah, AR5K_EEPROM_CMD,
-				AR5K_EEPROM_CMD_RESET);
-	}
-
-	/*
-	 * Write data to data register
-	 */
-
-	if (ah->ah_version == AR5K_AR5210) {
-		ath5k_hw_reg_write(ah, data, AR5K_EEPROM_BASE + (4 * offset));
-	} else {
-		ath5k_hw_reg_write(ah, offset, AR5K_EEPROM_BASE);
-		ath5k_hw_reg_write(ah, data, AR5K_EEPROM_DATA);
-		AR5K_REG_ENABLE_BITS(ah, AR5K_EEPROM_CMD,
-				AR5K_EEPROM_CMD_WRITE);
-	}
-
-	/*
-	 * Check status
-	 */
-
-	for (timeout = AR5K_TUNE_REGISTER_TIMEOUT; timeout > 0; timeout--) {
-		status = ath5k_hw_reg_read(ah, AR5K_EEPROM_STATUS);
-		if (status & AR5K_EEPROM_STAT_WRDONE) {
-			if (status & AR5K_EEPROM_STAT_WRERR)
-				return EIO;
-			return 0;
-		}
-		udelay(15);
-	}
-
-	ATH5K_ERR(ah->ah_sc, "EEPROM Write is disabled!");
-	return -EIO;
-}
-#endif
-
-/*
- * Translate binary channel representation in EEPROM to frequency
- */
-static u16 ath5k_eeprom_bin2freq(struct ath5k_hw *ah, u16 bin, unsigned int mode)
-{
-	u16 val;
-
-	if (bin == AR5K_EEPROM_CHANNEL_DIS)
-		return bin;
-
-	if (mode == AR5K_EEPROM_MODE_11A) {
-		if (ah->ah_ee_version > AR5K_EEPROM_VERSION_3_2)
-			val = (5 * bin) + 4800;
-		else
-			val = bin > 62 ? (10 * 62) + (5 * (bin - 62)) + 5100 :
-				(bin * 10) + 5100;
-	} else {
-		if (ah->ah_ee_version > AR5K_EEPROM_VERSION_3_2)
-			val = bin + 2300;
-		else
-			val = bin + 2400;
-	}
-
-	return val;
-}
-
-/*
- * Read antenna infos from eeprom
- */
-static int ath5k_eeprom_read_ants(struct ath5k_hw *ah, u32 *offset,
-		unsigned int mode)
-{
-	struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
-	u32 o = *offset;
-	u16 val;
-	int ret, i = 0;
-
-	AR5K_EEPROM_READ(o++, val);
-	ee->ee_switch_settling[mode]	= (val >> 8) & 0x7f;
-	ee->ee_ant_tx_rx[mode]		= (val >> 2) & 0x3f;
-	ee->ee_ant_control[mode][i]	= (val << 4) & 0x3f;
-
-	AR5K_EEPROM_READ(o++, val);
-	ee->ee_ant_control[mode][i++]	|= (val >> 12) & 0xf;
-	ee->ee_ant_control[mode][i++]	= (val >> 6) & 0x3f;
-	ee->ee_ant_control[mode][i++]	= val & 0x3f;
-
-	AR5K_EEPROM_READ(o++, val);
-	ee->ee_ant_control[mode][i++]	= (val >> 10) & 0x3f;
-	ee->ee_ant_control[mode][i++]	= (val >> 4) & 0x3f;
-	ee->ee_ant_control[mode][i]	= (val << 2) & 0x3f;
-
-	AR5K_EEPROM_READ(o++, val);
-	ee->ee_ant_control[mode][i++]	|= (val >> 14) & 0x3;
-	ee->ee_ant_control[mode][i++]	= (val >> 8) & 0x3f;
-	ee->ee_ant_control[mode][i++]	= (val >> 2) & 0x3f;
-	ee->ee_ant_control[mode][i]	= (val << 4) & 0x3f;
-
-	AR5K_EEPROM_READ(o++, val);
-	ee->ee_ant_control[mode][i++]	|= (val >> 12) & 0xf;
-	ee->ee_ant_control[mode][i++]	= (val >> 6) & 0x3f;
-	ee->ee_ant_control[mode][i++]	= val & 0x3f;
-
-	/* Get antenna modes */
-	ah->ah_antenna[mode][0] =
-	    (ee->ee_ant_control[mode][0] << 4) | 0x1;
-	ah->ah_antenna[mode][AR5K_ANT_FIXED_A] =
-	     ee->ee_ant_control[mode][1] 	|
-	    (ee->ee_ant_control[mode][2] << 6) 	|
-	    (ee->ee_ant_control[mode][3] << 12) |
-	    (ee->ee_ant_control[mode][4] << 18) |
-	    (ee->ee_ant_control[mode][5] << 24);
-	ah->ah_antenna[mode][AR5K_ANT_FIXED_B] =
-	     ee->ee_ant_control[mode][6] 	|
-	    (ee->ee_ant_control[mode][7] << 6) 	|
-	    (ee->ee_ant_control[mode][8] << 12) |
-	    (ee->ee_ant_control[mode][9] << 18) |
-	    (ee->ee_ant_control[mode][10] << 24);
-
-	/* return new offset */
-	*offset = o;
-
-	return 0;
-}
-
-/*
- * Read supported modes from eeprom
- */
-static int ath5k_eeprom_read_modes(struct ath5k_hw *ah, u32 *offset,
-		unsigned int mode)
-{
-	struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
-	u32 o = *offset;
-	u16 val;
-	int ret;
-
-	AR5K_EEPROM_READ(o++, val);
-	ee->ee_tx_end2xlna_enable[mode]	= (val >> 8) & 0xff;
-	ee->ee_thr_62[mode]		= val & 0xff;
-
-	if (ah->ah_ee_version <= AR5K_EEPROM_VERSION_3_2)
-		ee->ee_thr_62[mode] = mode == AR5K_EEPROM_MODE_11A ? 15 : 28;
-
-	AR5K_EEPROM_READ(o++, val);
-	ee->ee_tx_end2xpa_disable[mode]	= (val >> 8) & 0xff;
-	ee->ee_tx_frm2xpa_enable[mode]	= val & 0xff;
-
-	AR5K_EEPROM_READ(o++, val);
-	ee->ee_pga_desired_size[mode]	= (val >> 8) & 0xff;
-
-	if ((val & 0xff) & 0x80)
-		ee->ee_noise_floor_thr[mode] = -((((val & 0xff) ^ 0xff)) + 1);
-	else
-		ee->ee_noise_floor_thr[mode] = val & 0xff;
-
-	if (ah->ah_ee_version <= AR5K_EEPROM_VERSION_3_2)
-		ee->ee_noise_floor_thr[mode] =
-		    mode == AR5K_EEPROM_MODE_11A ? -54 : -1;
-
-	AR5K_EEPROM_READ(o++, val);
-	ee->ee_xlna_gain[mode]		= (val >> 5) & 0xff;
-	ee->ee_x_gain[mode]		= (val >> 1) & 0xf;
-	ee->ee_xpd[mode]		= val & 0x1;
-
-	if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0)
-		ee->ee_fixed_bias[mode] = (val >> 13) & 0x1;
-
-	if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_3_3) {
-		AR5K_EEPROM_READ(o++, val);
-		ee->ee_false_detect[mode] = (val >> 6) & 0x7f;
-
-		if (mode == AR5K_EEPROM_MODE_11A)
-			ee->ee_xr_power[mode] = val & 0x3f;
-		else {
-			ee->ee_ob[mode][0] = val & 0x7;
-			ee->ee_db[mode][0] = (val >> 3) & 0x7;
-		}
-	}
-
-	if (ah->ah_ee_version < AR5K_EEPROM_VERSION_3_4) {
-		ee->ee_i_gain[mode] = AR5K_EEPROM_I_GAIN;
-		ee->ee_cck_ofdm_power_delta = AR5K_EEPROM_CCK_OFDM_DELTA;
-	} else {
-		ee->ee_i_gain[mode] = (val >> 13) & 0x7;
-
-		AR5K_EEPROM_READ(o++, val);
-		ee->ee_i_gain[mode] |= (val << 3) & 0x38;
-
-		if (mode == AR5K_EEPROM_MODE_11G)
-			ee->ee_cck_ofdm_power_delta = (val >> 3) & 0xff;
-	}
-
-	if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0 &&
-			mode == AR5K_EEPROM_MODE_11A) {
-		ee->ee_i_cal[mode] = (val >> 8) & 0x3f;
-		ee->ee_q_cal[mode] = (val >> 3) & 0x1f;
-	}
-
-	if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_6 &&
-	    mode == AR5K_EEPROM_MODE_11G)
-		ee->ee_scaled_cck_delta = (val >> 11) & 0x1f;
-
-	/* return new offset */
-	*offset = o;
-
-	return 0;
-}
-
-/*
- * Initialize eeprom & capabilities structs
- */
-static int ath5k_eeprom_init(struct ath5k_hw *ah)
-{
-	struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
-	unsigned int mode, i;
-	int ret;
-	u32 offset;
-	u16 val;
-
-	/* Initial TX thermal adjustment values */
-	ee->ee_tx_clip = 4;
-	ee->ee_pwd_84 = ee->ee_pwd_90 = 1;
-	ee->ee_gain_select = 1;
-
-	/*
-	 * Read values from EEPROM and store them in the capability structure
-	 */
-	AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MAGIC, ee_magic);
-	AR5K_EEPROM_READ_HDR(AR5K_EEPROM_PROTECT, ee_protect);
-	AR5K_EEPROM_READ_HDR(AR5K_EEPROM_REG_DOMAIN, ee_regdomain);
-	AR5K_EEPROM_READ_HDR(AR5K_EEPROM_VERSION, ee_version);
-	AR5K_EEPROM_READ_HDR(AR5K_EEPROM_HDR, ee_header);
-
-	/* Return if we have an old EEPROM */
-	if (ah->ah_ee_version < AR5K_EEPROM_VERSION_3_0)
-		return 0;
-
-#ifdef notyet
-	/*
-	 * Validate the checksum of the EEPROM date. There are some
-	 * devices with invalid EEPROMs.
-	 */
-	for (cksum = 0, offset = 0; offset < AR5K_EEPROM_INFO_MAX; offset++) {
-		AR5K_EEPROM_READ(AR5K_EEPROM_INFO(offset), val);
-		cksum ^= val;
-	}
-	if (cksum != AR5K_EEPROM_INFO_CKSUM) {
-		ATH5K_ERR(ah->ah_sc, "Invalid EEPROM checksum 0x%04x\n", cksum);
-		return -EIO;
-	}
-#endif
-
-	AR5K_EEPROM_READ_HDR(AR5K_EEPROM_ANT_GAIN(ah->ah_ee_version),
-	    ee_ant_gain);
-
-	if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0) {
-		AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC0, ee_misc0);
-		AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC1, ee_misc1);
-	}
-
-	if (ah->ah_ee_version < AR5K_EEPROM_VERSION_3_3) {
-		AR5K_EEPROM_READ(AR5K_EEPROM_OBDB0_2GHZ, val);
-		ee->ee_ob[AR5K_EEPROM_MODE_11B][0] = val & 0x7;
-		ee->ee_db[AR5K_EEPROM_MODE_11B][0] = (val >> 3) & 0x7;
-
-		AR5K_EEPROM_READ(AR5K_EEPROM_OBDB1_2GHZ, val);
-		ee->ee_ob[AR5K_EEPROM_MODE_11G][0] = val & 0x7;
-		ee->ee_db[AR5K_EEPROM_MODE_11G][0] = (val >> 3) & 0x7;
-	}
-
-	/*
-	 * Get conformance test limit values
-	 */
-	offset = AR5K_EEPROM_CTL(ah->ah_ee_version);
-	ee->ee_ctls = AR5K_EEPROM_N_CTLS(ah->ah_ee_version);
-
-	for (i = 0; i < ee->ee_ctls; i++) {
-		AR5K_EEPROM_READ(offset++, val);
-		ee->ee_ctl[i] = (val >> 8) & 0xff;
-		ee->ee_ctl[i + 1] = val & 0xff;
-	}
-
-	/*
-	 * Get values for 802.11a (5GHz)
-	 */
-	mode = AR5K_EEPROM_MODE_11A;
-
-	ee->ee_turbo_max_power[mode] =
-			AR5K_EEPROM_HDR_T_5GHZ_DBM(ee->ee_header);
-
-	offset = AR5K_EEPROM_MODES_11A(ah->ah_ee_version);
-
-	ret = ath5k_eeprom_read_ants(ah, &offset, mode);
-	if (ret)
-		return ret;
-
-	AR5K_EEPROM_READ(offset++, val);
-	ee->ee_adc_desired_size[mode]	= (s8)((val >> 8) & 0xff);
-	ee->ee_ob[mode][3]		= (val >> 5) & 0x7;
-	ee->ee_db[mode][3]		= (val >> 2) & 0x7;
-	ee->ee_ob[mode][2]		= (val << 1) & 0x7;
-
-	AR5K_EEPROM_READ(offset++, val);
-	ee->ee_ob[mode][2]		|= (val >> 15) & 0x1;
-	ee->ee_db[mode][2]		= (val >> 12) & 0x7;
-	ee->ee_ob[mode][1]		= (val >> 9) & 0x7;
-	ee->ee_db[mode][1]		= (val >> 6) & 0x7;
-	ee->ee_ob[mode][0]		= (val >> 3) & 0x7;
-	ee->ee_db[mode][0]		= val & 0x7;
-
-	ret = ath5k_eeprom_read_modes(ah, &offset, mode);
-	if (ret)
-		return ret;
-
-	if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_1) {
-		AR5K_EEPROM_READ(offset++, val);
-		ee->ee_margin_tx_rx[mode] = val & 0x3f;
-	}
-
-	/*
-	 * Get values for 802.11b (2.4GHz)
-	 */
-	mode = AR5K_EEPROM_MODE_11B;
-	offset = AR5K_EEPROM_MODES_11B(ah->ah_ee_version);
-
-	ret = ath5k_eeprom_read_ants(ah, &offset, mode);
-	if (ret)
-		return ret;
-
-	AR5K_EEPROM_READ(offset++, val);
-	ee->ee_adc_desired_size[mode]	= (s8)((val >> 8) & 0xff);
-	ee->ee_ob[mode][1]		= (val >> 4) & 0x7;
-	ee->ee_db[mode][1]		= val & 0x7;
-
-	ret = ath5k_eeprom_read_modes(ah, &offset, mode);
-	if (ret)
-		return ret;
-
-	if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0) {
-		AR5K_EEPROM_READ(offset++, val);
-		ee->ee_cal_pier[mode][0] =
-			ath5k_eeprom_bin2freq(ah, val & 0xff, mode);
-		ee->ee_cal_pier[mode][1] =
-			ath5k_eeprom_bin2freq(ah, (val >> 8) & 0xff, mode);
-
-		AR5K_EEPROM_READ(offset++, val);
-		ee->ee_cal_pier[mode][2] =
-			ath5k_eeprom_bin2freq(ah, val & 0xff, mode);
-	}
-
-	if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_1)
-		ee->ee_margin_tx_rx[mode] = (val >> 8) & 0x3f;
-
-	/*
-	 * Get values for 802.11g (2.4GHz)
-	 */
-	mode = AR5K_EEPROM_MODE_11G;
-	offset = AR5K_EEPROM_MODES_11G(ah->ah_ee_version);
-
-	ret = ath5k_eeprom_read_ants(ah, &offset, mode);
-	if (ret)
-		return ret;
-
-	AR5K_EEPROM_READ(offset++, val);
-	ee->ee_adc_desired_size[mode]	= (s8)((val >> 8) & 0xff);
-	ee->ee_ob[mode][1]		= (val >> 4) & 0x7;
-	ee->ee_db[mode][1]		= val & 0x7;
-
-	ret = ath5k_eeprom_read_modes(ah, &offset, mode);
-	if (ret)
-		return ret;
-
-	if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0) {
-		AR5K_EEPROM_READ(offset++, val);
-		ee->ee_cal_pier[mode][0] =
-			ath5k_eeprom_bin2freq(ah, val & 0xff, mode);
-		ee->ee_cal_pier[mode][1] =
-			ath5k_eeprom_bin2freq(ah, (val >> 8) & 0xff, mode);
-
-		AR5K_EEPROM_READ(offset++, val);
-		ee->ee_turbo_max_power[mode] = val & 0x7f;
-		ee->ee_xr_power[mode] = (val >> 7) & 0x3f;
-
-		AR5K_EEPROM_READ(offset++, val);
-		ee->ee_cal_pier[mode][2] =
-			ath5k_eeprom_bin2freq(ah, val & 0xff, mode);
-
-		if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_1)
-			ee->ee_margin_tx_rx[mode] = (val >> 8) & 0x3f;
-
-		AR5K_EEPROM_READ(offset++, val);
-		ee->ee_i_cal[mode] = (val >> 8) & 0x3f;
-		ee->ee_q_cal[mode] = (val >> 3) & 0x1f;
-
-		if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_2) {
-			AR5K_EEPROM_READ(offset++, val);
-			ee->ee_cck_ofdm_gain_delta = val & 0xff;
-		}
-	}
-
-	/*
-	 * Read 5GHz EEPROM channels
-	 */
-
-	return 0;
-}
-
-/*
- * Read the MAC address from eeprom
- */
-static int ath5k_eeprom_read_mac(struct ath5k_hw *ah, u8 *mac)
-{
-	u8 mac_d[ETH_ALEN];
-	u32 total, offset;
-	u16 data;
-	int octet, ret;
-
-	memset(mac, 0, ETH_ALEN);
-	memset(mac_d, 0, ETH_ALEN);
-
-	ret = ath5k_hw_eeprom_read(ah, 0x20, &data);
-	if (ret)
-		return ret;
-
-	for (offset = 0x1f, octet = 0, total = 0; offset >= 0x1d; offset--) {
-		ret = ath5k_hw_eeprom_read(ah, offset, &data);
-		if (ret)
-			return ret;
-
-		total += data;
-		mac_d[octet + 1] = data & 0xff;
-		mac_d[octet] = data >> 8;
-		octet += 2;
-	}
-
-	memcpy(mac, mac_d, ETH_ALEN);
-
-	if (!total || total == 3 * 0xffff)
-		return -EINVAL;
-
-	return 0;
-}
-
-/*
- * Fill the capabilities struct
- */
-static int ath5k_hw_get_capabilities(struct ath5k_hw *ah)
-{
-	u16 ee_header;
-
-	ATH5K_TRACE(ah->ah_sc);
-	/* Capabilities stored in the EEPROM */
-	ee_header = ah->ah_capabilities.cap_eeprom.ee_header;
-
-	if (ah->ah_version == AR5K_AR5210) {
-		/*
-		 * Set radio capabilities
-		 * (The AR5110 only supports the middle 5GHz band)
-		 */
-		ah->ah_capabilities.cap_range.range_5ghz_min = 5120;
-		ah->ah_capabilities.cap_range.range_5ghz_max = 5430;
-		ah->ah_capabilities.cap_range.range_2ghz_min = 0;
-		ah->ah_capabilities.cap_range.range_2ghz_max = 0;
-
-		/* Set supported modes */
-		__set_bit(AR5K_MODE_11A, ah->ah_capabilities.cap_mode);
-		__set_bit(AR5K_MODE_11A_TURBO, ah->ah_capabilities.cap_mode);
-	} else {
-		/*
-		 * XXX The tranceiver supports frequencies from 4920 to 6100GHz
-		 * XXX and from 2312 to 2732GHz. There are problems with the
-		 * XXX current ieee80211 implementation because the IEEE
-		 * XXX channel mapping does not support negative channel
-		 * XXX numbers (2312MHz is channel -19). Of course, this
-		 * XXX doesn't matter because these channels are out of range
-		 * XXX but some regulation domains like MKK (Japan) will
-		 * XXX support frequencies somewhere around 4.8GHz.
-		 */
-
-		/*
-		 * Set radio capabilities
-		 */
-
-		if (AR5K_EEPROM_HDR_11A(ee_header)) {
-			ah->ah_capabilities.cap_range.range_5ghz_min = 5005; /* 4920 */
-			ah->ah_capabilities.cap_range.range_5ghz_max = 6100;
-
-			/* Set supported modes */
-			__set_bit(AR5K_MODE_11A,
-					ah->ah_capabilities.cap_mode);
-			__set_bit(AR5K_MODE_11A_TURBO,
-					ah->ah_capabilities.cap_mode);
-			if (ah->ah_version == AR5K_AR5212)
-				__set_bit(AR5K_MODE_11G_TURBO,
-						ah->ah_capabilities.cap_mode);
-		}
-
-		/* Enable  802.11b if a 2GHz capable radio (2111/5112) is
-		 * connected */
-		if (AR5K_EEPROM_HDR_11B(ee_header) ||
-				AR5K_EEPROM_HDR_11G(ee_header)) {
-			ah->ah_capabilities.cap_range.range_2ghz_min = 2412; /* 2312 */
-			ah->ah_capabilities.cap_range.range_2ghz_max = 2732;
-
-			if (AR5K_EEPROM_HDR_11B(ee_header))
-				__set_bit(AR5K_MODE_11B,
-						ah->ah_capabilities.cap_mode);
-
-			if (AR5K_EEPROM_HDR_11G(ee_header))
-				__set_bit(AR5K_MODE_11G,
-						ah->ah_capabilities.cap_mode);
-		}
-	}
-
-	/* GPIO */
-	ah->ah_gpio_npins = AR5K_NUM_GPIO;
-
-	/* Set number of supported TX queues */
-	if (ah->ah_version == AR5K_AR5210)
-		ah->ah_capabilities.cap_queues.q_tx_num =
-			AR5K_NUM_TX_QUEUES_NOQCU;
-	else
-		ah->ah_capabilities.cap_queues.q_tx_num = AR5K_NUM_TX_QUEUES;
-
-	return 0;
-}
-
-/*********************************\
-  Protocol Control Unit Functions
-\*********************************/
-
-/*
- * Set Operation mode
- */
-int ath5k_hw_set_opmode(struct ath5k_hw *ah)
-{
-	u32 pcu_reg, beacon_reg, low_id, high_id;
-
-	pcu_reg = 0;
-	beacon_reg = 0;
-
-	ATH5K_TRACE(ah->ah_sc);
-
-	switch (ah->ah_op_mode) {
-	case IEEE80211_IF_TYPE_IBSS:
-		pcu_reg |= AR5K_STA_ID1_ADHOC | AR5K_STA_ID1_DESC_ANTENNA |
-			(ah->ah_version == AR5K_AR5210 ?
-				AR5K_STA_ID1_NO_PSPOLL : 0);
-		beacon_reg |= AR5K_BCR_ADHOC;
-		break;
-
-	case IEEE80211_IF_TYPE_AP:
-		pcu_reg |= AR5K_STA_ID1_AP | AR5K_STA_ID1_RTS_DEF_ANTENNA |
-			(ah->ah_version == AR5K_AR5210 ?
-				AR5K_STA_ID1_NO_PSPOLL : 0);
-		beacon_reg |= AR5K_BCR_AP;
-		break;
-
-	case IEEE80211_IF_TYPE_STA:
-		pcu_reg |= AR5K_STA_ID1_DEFAULT_ANTENNA |
-			(ah->ah_version == AR5K_AR5210 ?
-				AR5K_STA_ID1_PWR_SV : 0);
-	case IEEE80211_IF_TYPE_MNTR:
-		pcu_reg |= AR5K_STA_ID1_DEFAULT_ANTENNA |
-			(ah->ah_version == AR5K_AR5210 ?
-				AR5K_STA_ID1_NO_PSPOLL : 0);
-		break;
-
-	default:
-		return -EINVAL;
-	}
-
-	/*
-	 * Set PCU registers
-	 */
-	low_id = AR5K_LOW_ID(ah->ah_sta_id);
-	high_id = AR5K_HIGH_ID(ah->ah_sta_id);
-	ath5k_hw_reg_write(ah, low_id, AR5K_STA_ID0);
-	ath5k_hw_reg_write(ah, pcu_reg | high_id, AR5K_STA_ID1);
-
-	/*
-	 * Set Beacon Control Register on 5210
-	 */
-	if (ah->ah_version == AR5K_AR5210)
-		ath5k_hw_reg_write(ah, beacon_reg, AR5K_BCR);
-
-	return 0;
-}
-
-/*
- * BSSID Functions
- */
-
-/*
- * Get station id
- */
-void ath5k_hw_get_lladdr(struct ath5k_hw *ah, u8 *mac)
-{
-	ATH5K_TRACE(ah->ah_sc);
-	memcpy(mac, ah->ah_sta_id, ETH_ALEN);
-}
-
-/*
- * Set station id
- */
-int ath5k_hw_set_lladdr(struct ath5k_hw *ah, const u8 *mac)
-{
-	u32 low_id, high_id;
-
-	ATH5K_TRACE(ah->ah_sc);
-	/* Set new station ID */
-	memcpy(ah->ah_sta_id, mac, ETH_ALEN);
-
-	low_id = AR5K_LOW_ID(mac);
-	high_id = AR5K_HIGH_ID(mac);
-
-	ath5k_hw_reg_write(ah, low_id, AR5K_STA_ID0);
-	ath5k_hw_reg_write(ah, high_id, AR5K_STA_ID1);
-
-	return 0;
-}
-
-/*
- * Set BSSID
- */
-void ath5k_hw_set_associd(struct ath5k_hw *ah, const u8 *bssid, u16 assoc_id)
-{
-	u32 low_id, high_id;
-	u16 tim_offset = 0;
-
-	/*
-	 * Set simple BSSID mask on 5212
-	 */
-	if (ah->ah_version == AR5K_AR5212) {
-		ath5k_hw_reg_write(ah, 0xffffffff, AR5K_BSS_IDM0);
-		ath5k_hw_reg_write(ah, 0xffffffff, AR5K_BSS_IDM1);
-	}
-
-	/*
-	 * Set BSSID which triggers the "SME Join" operation
-	 */
-	low_id = AR5K_LOW_ID(bssid);
-	high_id = AR5K_HIGH_ID(bssid);
-	ath5k_hw_reg_write(ah, low_id, AR5K_BSS_ID0);
-	ath5k_hw_reg_write(ah, high_id | ((assoc_id & 0x3fff) <<
-				AR5K_BSS_ID1_AID_S), AR5K_BSS_ID1);
-
-	if (assoc_id == 0) {
-		ath5k_hw_disable_pspoll(ah);
-		return;
-	}
-
-	AR5K_REG_WRITE_BITS(ah, AR5K_BEACON, AR5K_BEACON_TIM,
-			tim_offset ? tim_offset + 4 : 0);
-
-	ath5k_hw_enable_pspoll(ah, NULL, 0);
-}
-/**
- * ath5k_hw_set_bssid_mask - set common bits we should listen to
- *
- * The bssid_mask is a utility used by AR5212 hardware to inform the hardware
- * which bits of the interface's MAC address should be looked at when trying
- * to decide which packets to ACK. In station mode every bit matters. In AP
- * mode with a single BSS every bit matters as well. In AP mode with
- * multiple BSSes not every bit matters.
- *
- * @ah: the &struct ath5k_hw
- * @mask: the bssid_mask, a u8 array of size ETH_ALEN
- *
- * Note that this is a simple filter and *does* not filter out all
- * relevant frames. Some non-relevant frames will get through, probability
- * jocks are welcomed to compute.
- *
- * When handling multiple BSSes (or VAPs) you can get the BSSID mask by
- * computing the set of:
- *
- *     ~ ( MAC XOR BSSID )
- *
- * When you do this you are essentially computing the common bits. Later it
- * is assumed the harware will "and" (&) the BSSID mask with the MAC address
- * to obtain the relevant bits which should match on the destination frame.
- *
- * Simple example: on your card you have have two BSSes you have created with
- * BSSID-01 and BSSID-02. Lets assume BSSID-01 will not use the MAC address.
- * There is another BSSID-03 but you are not part of it. For simplicity's sake,
- * assuming only 4 bits for a mac address and for BSSIDs you can then have:
- *
- *                  \
- * MAC:                0001 |
- * BSSID-01:   0100 | --> Belongs to us
- * BSSID-02:   1001 |
- *                  /
- * -------------------
- * BSSID-03:   0110  | --> External
- * -------------------
- *
- * Our bssid_mask would then be:
- *
- *             On loop iteration for BSSID-01:
- *             ~(0001 ^ 0100)  -> ~(0101)
- *                             ->   1010
- *             bssid_mask      =    1010
- *
- *             On loop iteration for BSSID-02:
- *             bssid_mask &= ~(0001   ^   1001)
- *             bssid_mask =   (1010)  & ~(0001 ^ 1001)
- *             bssid_mask =   (1010)  & ~(1001)
- *             bssid_mask =   (1010)  &  (0110)
- *             bssid_mask =   0010
- *
- * A bssid_mask of 0010 means "only pay attention to the second least
- * significant bit". This is because its the only bit common
- * amongst the MAC and all BSSIDs we support. To findout what the real
- * common bit is we can simply "&" the bssid_mask now with any BSSID we have
- * or our MAC address (we assume the hardware uses the MAC address).
- *
- * Now, suppose there's an incoming frame for BSSID-03:
- *
- * IFRAME-01:  0110
- *
- * An easy eye-inspeciton of this already should tell you that this frame
- * will not pass our check. This is beacuse the bssid_mask tells the
- * hardware to only look at the second least significant bit and the
- * common bit amongst the MAC and BSSIDs is 0, this frame has the 2nd LSB
- * as 1, which does not match 0.
- *
- * So with IFRAME-01 we *assume* the hardware will do:
- *
- *     allow = (IFRAME-01 & bssid_mask) == (bssid_mask & MAC) ? 1 : 0;
- *  --> allow = (0110 & 0010) == (0010 & 0001) ? 1 : 0;
- *  --> allow = (0010) == 0000 ? 1 : 0;
- *  --> allow = 0
- *
- *  Lets now test a frame that should work:
- *
- * IFRAME-02:  0001 (we should allow)
- *
- *     allow = (0001 & 1010) == 1010
- *
- *     allow = (IFRAME-02 & bssid_mask) == (bssid_mask & MAC) ? 1 : 0;
- *  --> allow = (0001 & 0010) ==  (0010 & 0001) ? 1 :0;
- *  --> allow = (0010) == (0010)
- *  --> allow = 1
- *
- * Other examples:
- *
- * IFRAME-03:  0100 --> allowed
- * IFRAME-04:  1001 --> allowed
- * IFRAME-05:  1101 --> allowed but its not for us!!!
- *
- */
-int ath5k_hw_set_bssid_mask(struct ath5k_hw *ah, const u8 *mask)
-{
-	u32 low_id, high_id;
-	ATH5K_TRACE(ah->ah_sc);
-
-	if (ah->ah_version == AR5K_AR5212) {
-		low_id = AR5K_LOW_ID(mask);
-		high_id = AR5K_HIGH_ID(mask);
-
-		ath5k_hw_reg_write(ah, low_id, AR5K_BSS_IDM0);
-		ath5k_hw_reg_write(ah, high_id, AR5K_BSS_IDM1);
-
-		return 0;
-	}
-
-	return -EIO;
-}
-
-/*
- * Receive start/stop functions
- */
-
-/*
- * Start receive on PCU
- */
-void ath5k_hw_start_rx_pcu(struct ath5k_hw *ah)
-{
-	ATH5K_TRACE(ah->ah_sc);
-	AR5K_REG_DISABLE_BITS(ah, AR5K_DIAG_SW, AR5K_DIAG_SW_DIS_RX);
-
-	/* TODO: ANI Support */
-}
-
-/*
- * Stop receive on PCU
- */
-void ath5k_hw_stop_pcu_recv(struct ath5k_hw *ah)
-{
-	ATH5K_TRACE(ah->ah_sc);
-	AR5K_REG_ENABLE_BITS(ah, AR5K_DIAG_SW, AR5K_DIAG_SW_DIS_RX);
-
-	/* TODO: ANI Support */
-}
-
-/*
- * RX Filter functions
- */
-
-/*
- * Set multicast filter
- */
-void ath5k_hw_set_mcast_filter(struct ath5k_hw *ah, u32 filter0, u32 filter1)
-{
-	ATH5K_TRACE(ah->ah_sc);
-	/* Set the multicat filter */
-	ath5k_hw_reg_write(ah, filter0, AR5K_MCAST_FILTER0);
-	ath5k_hw_reg_write(ah, filter1, AR5K_MCAST_FILTER1);
-}
-
-/*
- * Set multicast filter by index
- */
-int ath5k_hw_set_mcast_filterindex(struct ath5k_hw *ah, u32 index)
-{
-
-	ATH5K_TRACE(ah->ah_sc);
-	if (index >= 64)
-		return -EINVAL;
-	else if (index >= 32)
-		AR5K_REG_ENABLE_BITS(ah, AR5K_MCAST_FILTER1,
-				(1 << (index - 32)));
-	else
-		AR5K_REG_ENABLE_BITS(ah, AR5K_MCAST_FILTER0, (1 << index));
-
-	return 0;
-}
-
-/*
- * Clear Multicast filter by index
- */
-int ath5k_hw_clear_mcast_filter_idx(struct ath5k_hw *ah, u32 index)
-{
-
-	ATH5K_TRACE(ah->ah_sc);
-	if (index >= 64)
-		return -EINVAL;
-	else if (index >= 32)
-		AR5K_REG_DISABLE_BITS(ah, AR5K_MCAST_FILTER1,
-				(1 << (index - 32)));
-	else
-		AR5K_REG_DISABLE_BITS(ah, AR5K_MCAST_FILTER0, (1 << index));
-
-	return 0;
-}
-
-/*
- * Get current rx filter
- */
-u32 ath5k_hw_get_rx_filter(struct ath5k_hw *ah)
-{
-	u32 data, filter = 0;
-
-	ATH5K_TRACE(ah->ah_sc);
-	filter = ath5k_hw_reg_read(ah, AR5K_RX_FILTER);
-
-	/*Radar detection for 5212*/
-	if (ah->ah_version == AR5K_AR5212) {
-		data = ath5k_hw_reg_read(ah, AR5K_PHY_ERR_FIL);
-
-		if (data & AR5K_PHY_ERR_FIL_RADAR)
-			filter |= AR5K_RX_FILTER_RADARERR;
-		if (data & (AR5K_PHY_ERR_FIL_OFDM | AR5K_PHY_ERR_FIL_CCK))
-			filter |= AR5K_RX_FILTER_PHYERR;
-	}
-
-	return filter;
-}
-
-/*
- * Set rx filter
- */
-void ath5k_hw_set_rx_filter(struct ath5k_hw *ah, u32 filter)
-{
-	u32 data = 0;
-
-	ATH5K_TRACE(ah->ah_sc);
-
-	/* Set PHY error filter register on 5212*/
-	if (ah->ah_version == AR5K_AR5212) {
-		if (filter & AR5K_RX_FILTER_RADARERR)
-			data |= AR5K_PHY_ERR_FIL_RADAR;
-		if (filter & AR5K_RX_FILTER_PHYERR)
-			data |= AR5K_PHY_ERR_FIL_OFDM | AR5K_PHY_ERR_FIL_CCK;
-	}
-
-	/*
-	 * The AR5210 uses promiscous mode to detect radar activity
-	 */
-	if (ah->ah_version == AR5K_AR5210 &&
-			(filter & AR5K_RX_FILTER_RADARERR)) {
-		filter &= ~AR5K_RX_FILTER_RADARERR;
-		filter |= AR5K_RX_FILTER_PROM;
-	}
-
-	/*Zero length DMA*/
-	if (data)
-		AR5K_REG_ENABLE_BITS(ah, AR5K_RXCFG, AR5K_RXCFG_ZLFDMA);
-	else
-		AR5K_REG_DISABLE_BITS(ah, AR5K_RXCFG, AR5K_RXCFG_ZLFDMA);
-
-	/*Write RX Filter register*/
-	ath5k_hw_reg_write(ah, filter & 0xff, AR5K_RX_FILTER);
-
-	/*Write PHY error filter register on 5212*/
-	if (ah->ah_version == AR5K_AR5212)
-		ath5k_hw_reg_write(ah, data, AR5K_PHY_ERR_FIL);
-
-}
-
-/*
- * Beacon related functions
- */
-
-/*
- * Get a 32bit TSF
- */
-u32 ath5k_hw_get_tsf32(struct ath5k_hw *ah)
-{
-	ATH5K_TRACE(ah->ah_sc);
-	return ath5k_hw_reg_read(ah, AR5K_TSF_L32);
-}
-
-/*
- * Get the full 64bit TSF
- */
-u64 ath5k_hw_get_tsf64(struct ath5k_hw *ah)
-{
-	u64 tsf = ath5k_hw_reg_read(ah, AR5K_TSF_U32);
-	ATH5K_TRACE(ah->ah_sc);
-
-	return ath5k_hw_reg_read(ah, AR5K_TSF_L32) | (tsf << 32);
-}
-
-/*
- * Force a TSF reset
- */
-void ath5k_hw_reset_tsf(struct ath5k_hw *ah)
-{
-	ATH5K_TRACE(ah->ah_sc);
-	AR5K_REG_ENABLE_BITS(ah, AR5K_BEACON, AR5K_BEACON_RESET_TSF);
-}
-
-/*
- * Initialize beacon timers
- */
-void ath5k_hw_init_beacon(struct ath5k_hw *ah, u32 next_beacon, u32 interval)
-{
-	u32 timer1, timer2, timer3;
-
-	ATH5K_TRACE(ah->ah_sc);
-	/*
-	 * Set the additional timers by mode
-	 */
-	switch (ah->ah_op_mode) {
-	case IEEE80211_IF_TYPE_STA:
-		if (ah->ah_version == AR5K_AR5210) {
-			timer1 = 0xffffffff;
-			timer2 = 0xffffffff;
-		} else {
-			timer1 = 0x0000ffff;
-			timer2 = 0x0007ffff;
-		}
-		break;
-
-	default:
-		timer1 = (next_beacon - AR5K_TUNE_DMA_BEACON_RESP) << 3;
-		timer2 = (next_beacon - AR5K_TUNE_SW_BEACON_RESP) << 3;
-	}
-
-	timer3 = next_beacon + (ah->ah_atim_window ? ah->ah_atim_window : 1);
-
-	/*
-	 * Set the beacon register and enable all timers.
-	 * (next beacon, DMA beacon, software beacon, ATIM window time)
-	 */
-	ath5k_hw_reg_write(ah, next_beacon, AR5K_TIMER0);
-	ath5k_hw_reg_write(ah, timer1, AR5K_TIMER1);
-	ath5k_hw_reg_write(ah, timer2, AR5K_TIMER2);
-	ath5k_hw_reg_write(ah, timer3, AR5K_TIMER3);
-
-	ath5k_hw_reg_write(ah, interval & (AR5K_BEACON_PERIOD |
-			AR5K_BEACON_RESET_TSF | AR5K_BEACON_ENABLE),
-		AR5K_BEACON);
-}
-
-#if 0
-/*
- * Set beacon timers
- */
-int ath5k_hw_set_beacon_timers(struct ath5k_hw *ah,
-		const struct ath5k_beacon_state *state)
-{
-	u32 cfp_period, next_cfp, dtim, interval, next_beacon;
-
-	/*
-	 * TODO: should be changed through *state
-	 * review struct ath5k_beacon_state struct
-	 *
-	 * XXX: These are used for cfp period bellow, are they
-	 * ok ? Is it O.K. for tsf here to be 0 or should we use
-	 * get_tsf ?
-	 */
-	u32 dtim_count = 0; /* XXX */
-	u32 cfp_count = 0; /* XXX */
-	u32 tsf = 0; /* XXX */
-
-	ATH5K_TRACE(ah->ah_sc);
-	/* Return on an invalid beacon state */
-	if (state->bs_interval < 1)
-		return -EINVAL;
-
-	interval = state->bs_interval;
-	dtim = state->bs_dtim_period;
-
-	/*
-	 * PCF support?
-	 */
-	if (state->bs_cfp_period > 0) {
-		/*
-		 * Enable PCF mode and set the CFP
-		 * (Contention Free Period) and timer registers
-		 */
-		cfp_period = state->bs_cfp_period * state->bs_dtim_period *
-			state->bs_interval;
-		next_cfp = (cfp_count * state->bs_dtim_period + dtim_count) *
-			state->bs_interval;
-
-		AR5K_REG_ENABLE_BITS(ah, AR5K_STA_ID1,
-				AR5K_STA_ID1_DEFAULT_ANTENNA |
-				AR5K_STA_ID1_PCF);
-		ath5k_hw_reg_write(ah, cfp_period, AR5K_CFP_PERIOD);
-		ath5k_hw_reg_write(ah, state->bs_cfp_max_duration,
-				AR5K_CFP_DUR);
-		ath5k_hw_reg_write(ah, (tsf + (next_cfp == 0 ? cfp_period :
-						next_cfp)) << 3, AR5K_TIMER2);
-	} else {
-		/* Disable PCF mode */
-		AR5K_REG_DISABLE_BITS(ah, AR5K_STA_ID1,
-				AR5K_STA_ID1_DEFAULT_ANTENNA |
-				AR5K_STA_ID1_PCF);
-	}
-
-	/*
-	 * Enable the beacon timer register
-	 */
-	ath5k_hw_reg_write(ah, state->bs_next_beacon, AR5K_TIMER0);
-
-	/*
-	 * Start the beacon timers
-	 */
-	ath5k_hw_reg_write(ah, (ath5k_hw_reg_read(ah, AR5K_BEACON) &~
-		(AR5K_BEACON_PERIOD | AR5K_BEACON_TIM)) |
-		AR5K_REG_SM(state->bs_tim_offset ? state->bs_tim_offset + 4 : 0,
-		AR5K_BEACON_TIM) | AR5K_REG_SM(state->bs_interval,
-		AR5K_BEACON_PERIOD), AR5K_BEACON);
-
-	/*
-	 * Write new beacon miss threshold, if it appears to be valid
-	 * XXX: Figure out right values for min <= bs_bmiss_threshold <= max
-	 * and return if its not in range. We can test this by reading value and
-	 * setting value to a largest value and seeing which values register.
-	 */
-
-	AR5K_REG_WRITE_BITS(ah, AR5K_RSSI_THR, AR5K_RSSI_THR_BMISS,
-			state->bs_bmiss_threshold);
-
-	/*
-	 * Set sleep control register
-	 * XXX: Didn't find this in 5210 code but since this register
-	 * exists also in ar5k's 5210 headers i leave it as common code.
-	 */
-	AR5K_REG_WRITE_BITS(ah, AR5K_SLEEP_CTL, AR5K_SLEEP_CTL_SLDUR,
-			(state->bs_sleep_duration - 3) << 3);
-
-	/*
-	 * Set enhanced sleep registers on 5212
-	 */
-	if (ah->ah_version == AR5K_AR5212) {
-		if (state->bs_sleep_duration > state->bs_interval &&
-				roundup(state->bs_sleep_duration, interval) ==
-				state->bs_sleep_duration)
-			interval = state->bs_sleep_duration;
-
-		if (state->bs_sleep_duration > dtim && (dtim == 0 ||
-				roundup(state->bs_sleep_duration, dtim) ==
-				state->bs_sleep_duration))
-			dtim = state->bs_sleep_duration;
-
-		if (interval > dtim)
-			return -EINVAL;
-
-		next_beacon = interval == dtim ? state->bs_next_dtim :
-			state->bs_next_beacon;
-
-		ath5k_hw_reg_write(ah,
-			AR5K_REG_SM((state->bs_next_dtim - 3) << 3,
-			AR5K_SLEEP0_NEXT_DTIM) |
-			AR5K_REG_SM(10, AR5K_SLEEP0_CABTO) |
-			AR5K_SLEEP0_ENH_SLEEP_EN |
-			AR5K_SLEEP0_ASSUME_DTIM, AR5K_SLEEP0);
-
-		ath5k_hw_reg_write(ah, AR5K_REG_SM((next_beacon - 3) << 3,
-			AR5K_SLEEP1_NEXT_TIM) |
-			AR5K_REG_SM(10, AR5K_SLEEP1_BEACON_TO), AR5K_SLEEP1);
-
-		ath5k_hw_reg_write(ah,
-			AR5K_REG_SM(interval, AR5K_SLEEP2_TIM_PER) |
-			AR5K_REG_SM(dtim, AR5K_SLEEP2_DTIM_PER), AR5K_SLEEP2);
-	}
-
-	return 0;
-}
-
-/*
- * Reset beacon timers
- */
-void ath5k_hw_reset_beacon(struct ath5k_hw *ah)
-{
-	ATH5K_TRACE(ah->ah_sc);
-	/*
-	 * Disable beacon timer
-	 */
-	ath5k_hw_reg_write(ah, 0, AR5K_TIMER0);
-
-	/*
-	 * Disable some beacon register values
-	 */
-	AR5K_REG_DISABLE_BITS(ah, AR5K_STA_ID1,
-			AR5K_STA_ID1_DEFAULT_ANTENNA | AR5K_STA_ID1_PCF);
-	ath5k_hw_reg_write(ah, AR5K_BEACON_PERIOD, AR5K_BEACON);
-}
-
-/*
- * Wait for beacon queue to finish
- */
-int ath5k_hw_beaconq_finish(struct ath5k_hw *ah, unsigned long phys_addr)
-{
-	unsigned int i;
-	int ret;
-
-	ATH5K_TRACE(ah->ah_sc);
-
-	/* 5210 doesn't have QCU*/
-	if (ah->ah_version == AR5K_AR5210) {
-		/*
-		 * Wait for beaconn queue to finish by checking
-		 * Control Register and Beacon Status Register.
-		 */
-		for (i = AR5K_TUNE_BEACON_INTERVAL / 2; i > 0; i--) {
-			if (!(ath5k_hw_reg_read(ah, AR5K_BSR) & AR5K_BSR_TXQ1F)
-					||
-			    !(ath5k_hw_reg_read(ah, AR5K_CR) & AR5K_BSR_TXQ1F))
-				break;
-			udelay(10);
-		}
-
-		/* Timeout... */
-		if (i <= 0) {
-			/*
-			 * Re-schedule the beacon queue
-			 */
-			ath5k_hw_reg_write(ah, phys_addr, AR5K_NOQCU_TXDP1);
-			ath5k_hw_reg_write(ah, AR5K_BCR_TQ1V | AR5K_BCR_BDMAE,
-					AR5K_BCR);
-
-			return -EIO;
-		}
-		ret = 0;
-	} else {
-	/*5211/5212*/
-		ret = ath5k_hw_register_timeout(ah,
-			AR5K_QUEUE_STATUS(AR5K_TX_QUEUE_ID_BEACON),
-			AR5K_QCU_STS_FRMPENDCNT, 0, false);
-
-		if (AR5K_REG_READ_Q(ah, AR5K_QCU_TXE, AR5K_TX_QUEUE_ID_BEACON))
-			return -EIO;
-	}
-
-	return ret;
-}
-#endif
-
-/*
- * Update mib counters (statistics)
- */
-void ath5k_hw_update_mib_counters(struct ath5k_hw *ah,
-		struct ieee80211_low_level_stats  *stats)
-{
-	ATH5K_TRACE(ah->ah_sc);
-
-	/* Read-And-Clear */
-	stats->dot11ACKFailureCount += ath5k_hw_reg_read(ah, AR5K_ACK_FAIL);
-	stats->dot11RTSFailureCount += ath5k_hw_reg_read(ah, AR5K_RTS_FAIL);
-	stats->dot11RTSSuccessCount += ath5k_hw_reg_read(ah, AR5K_RTS_OK);
-	stats->dot11FCSErrorCount += ath5k_hw_reg_read(ah, AR5K_FCS_FAIL);
-
-	/* XXX: Should we use this to track beacon count ?
-	 * -we read it anyway to clear the register */
-	ath5k_hw_reg_read(ah, AR5K_BEACON_CNT);
-
-	/* Reset profile count registers on 5212*/
-	if (ah->ah_version == AR5K_AR5212) {
-		ath5k_hw_reg_write(ah, 0, AR5K_PROFCNT_TX);
-		ath5k_hw_reg_write(ah, 0, AR5K_PROFCNT_RX);
-		ath5k_hw_reg_write(ah, 0, AR5K_PROFCNT_RXCLR);
-		ath5k_hw_reg_write(ah, 0, AR5K_PROFCNT_CYCLE);
-	}
-}
-
-/** ath5k_hw_set_ack_bitrate - set bitrate for ACKs
- *
- * @ah: the &struct ath5k_hw
- * @high: determines if to use low bit rate or now
- */
-void ath5k_hw_set_ack_bitrate_high(struct ath5k_hw *ah, bool high)
-{
-	if (ah->ah_version != AR5K_AR5212)
-		return;
-	else {
-		u32 val = AR5K_STA_ID1_BASE_RATE_11B | AR5K_STA_ID1_ACKCTS_6MB;
-		if (high)
-			AR5K_REG_ENABLE_BITS(ah, AR5K_STA_ID1, val);
-		else
-			AR5K_REG_DISABLE_BITS(ah, AR5K_STA_ID1, val);
-	}
-}
-
-
-/*
- * ACK/CTS Timeouts
- */
-
-/*
- * Set ACK timeout on PCU
- */
-int ath5k_hw_set_ack_timeout(struct ath5k_hw *ah, unsigned int timeout)
-{
-	ATH5K_TRACE(ah->ah_sc);
-	if (ath5k_hw_clocktoh(AR5K_REG_MS(0xffffffff, AR5K_TIME_OUT_ACK),
-			ah->ah_turbo) <= timeout)
-		return -EINVAL;
-
-	AR5K_REG_WRITE_BITS(ah, AR5K_TIME_OUT, AR5K_TIME_OUT_ACK,
-		ath5k_hw_htoclock(timeout, ah->ah_turbo));
-
-	return 0;
-}
-
-/*
- * Read the ACK timeout from PCU
- */
-unsigned int ath5k_hw_get_ack_timeout(struct ath5k_hw *ah)
-{
-	ATH5K_TRACE(ah->ah_sc);
-
-	return ath5k_hw_clocktoh(AR5K_REG_MS(ath5k_hw_reg_read(ah,
-			AR5K_TIME_OUT), AR5K_TIME_OUT_ACK), ah->ah_turbo);
-}
-
-/*
- * Set CTS timeout on PCU
- */
-int ath5k_hw_set_cts_timeout(struct ath5k_hw *ah, unsigned int timeout)
-{
-	ATH5K_TRACE(ah->ah_sc);
-	if (ath5k_hw_clocktoh(AR5K_REG_MS(0xffffffff, AR5K_TIME_OUT_CTS),
-			ah->ah_turbo) <= timeout)
-		return -EINVAL;
-
-	AR5K_REG_WRITE_BITS(ah, AR5K_TIME_OUT, AR5K_TIME_OUT_CTS,
-			ath5k_hw_htoclock(timeout, ah->ah_turbo));
-
-	return 0;
-}
-
-/*
- * Read CTS timeout from PCU
- */
-unsigned int ath5k_hw_get_cts_timeout(struct ath5k_hw *ah)
-{
-	ATH5K_TRACE(ah->ah_sc);
-	return ath5k_hw_clocktoh(AR5K_REG_MS(ath5k_hw_reg_read(ah,
-			AR5K_TIME_OUT), AR5K_TIME_OUT_CTS), ah->ah_turbo);
-}
-
-/*
- * Key table (WEP) functions
- */
-
-int ath5k_hw_reset_key(struct ath5k_hw *ah, u16 entry)
-{
-	unsigned int i;
-
-	ATH5K_TRACE(ah->ah_sc);
-	AR5K_ASSERT_ENTRY(entry, AR5K_KEYTABLE_SIZE);
-
-	for (i = 0; i < AR5K_KEYCACHE_SIZE; i++)
-		ath5k_hw_reg_write(ah, 0, AR5K_KEYTABLE_OFF(entry, i));
-
-	/*
-	 * Set NULL encryption on AR5212+
-	 *
-	 * Note: AR5K_KEYTABLE_TYPE -> AR5K_KEYTABLE_OFF(entry, 5)
-	 *       AR5K_KEYTABLE_TYPE_NULL -> 0x00000007
-	 *
-	 * Note2: Windows driver (ndiswrapper) sets this to
-	 *        0x00000714 instead of 0x00000007
-	 */
-	if (ah->ah_version > AR5K_AR5211)
-		ath5k_hw_reg_write(ah, AR5K_KEYTABLE_TYPE_NULL,
-				AR5K_KEYTABLE_TYPE(entry));
-
-	return 0;
-}
-
-int ath5k_hw_is_key_valid(struct ath5k_hw *ah, u16 entry)
-{
-	ATH5K_TRACE(ah->ah_sc);
-	AR5K_ASSERT_ENTRY(entry, AR5K_KEYTABLE_SIZE);
-
-	/* Check the validation flag at the end of the entry */
-	return ath5k_hw_reg_read(ah, AR5K_KEYTABLE_MAC1(entry)) &
-		AR5K_KEYTABLE_VALID;
-}
-
-int ath5k_hw_set_key(struct ath5k_hw *ah, u16 entry,
-		const struct ieee80211_key_conf *key, const u8 *mac)
-{
-	unsigned int i;
-	__le32 key_v[5] = {};
-	u32 keytype;
-
-	ATH5K_TRACE(ah->ah_sc);
-
-	/* key->keylen comes in from mac80211 in bytes */
-
-	if (key->keylen > AR5K_KEYTABLE_SIZE / 8)
-		return -EOPNOTSUPP;
-
-	switch (key->keylen) {
-	/* WEP 40-bit   = 40-bit  entered key + 24 bit IV = 64-bit */
-	case 40 / 8:
-		memcpy(&key_v[0], key->key, 5);
-		keytype = AR5K_KEYTABLE_TYPE_40;
-		break;
-
-	/* WEP 104-bit  = 104-bit entered key + 24-bit IV = 128-bit */
-	case 104 / 8:
-		memcpy(&key_v[0], &key->key[0], 6);
-		memcpy(&key_v[2], &key->key[6], 6);
-		memcpy(&key_v[4], &key->key[12], 1);
-		keytype = AR5K_KEYTABLE_TYPE_104;
-		break;
-	/* WEP 128-bit  = 128-bit entered key + 24 bit IV = 152-bit */
-	case 128 / 8:
-		memcpy(&key_v[0], &key->key[0], 6);
-		memcpy(&key_v[2], &key->key[6], 6);
-		memcpy(&key_v[4], &key->key[12], 4);
-		keytype = AR5K_KEYTABLE_TYPE_128;
-		break;
-
-	default:
-		return -EINVAL; /* shouldn't happen */
-	}
-
-	for (i = 0; i < ARRAY_SIZE(key_v); i++)
-		ath5k_hw_reg_write(ah, le32_to_cpu(key_v[i]),
-				AR5K_KEYTABLE_OFF(entry, i));
-
-	ath5k_hw_reg_write(ah, keytype, AR5K_KEYTABLE_TYPE(entry));
-
-	return ath5k_hw_set_key_lladdr(ah, entry, mac);
-}
-
-int ath5k_hw_set_key_lladdr(struct ath5k_hw *ah, u16 entry, const u8 *mac)
-{
-	u32 low_id, high_id;
-
-	ATH5K_TRACE(ah->ah_sc);
-	 /* Invalid entry (key table overflow) */
-	AR5K_ASSERT_ENTRY(entry, AR5K_KEYTABLE_SIZE);
-
-	/* MAC may be NULL if it's a broadcast key. In this case no need to
-	 * to compute AR5K_LOW_ID and AR5K_HIGH_ID as we already know it. */
-	if (unlikely(mac == NULL)) {
-		low_id = 0xffffffff;
-		high_id = 0xffff | AR5K_KEYTABLE_VALID;
-	} else {
-		low_id = AR5K_LOW_ID(mac);
-		high_id = AR5K_HIGH_ID(mac) | AR5K_KEYTABLE_VALID;
-	}
-
-	ath5k_hw_reg_write(ah, low_id, AR5K_KEYTABLE_MAC0(entry));
-	ath5k_hw_reg_write(ah, high_id, AR5K_KEYTABLE_MAC1(entry));
-
-	return 0;
-}
-
-
-/********************************************\
-Queue Control Unit, DFS Control Unit Functions
-\********************************************/
-
-/*
- * Initialize a transmit queue
- */
-int ath5k_hw_setup_tx_queue(struct ath5k_hw *ah, enum ath5k_tx_queue queue_type,
-		struct ath5k_txq_info *queue_info)
-{
-	unsigned int queue;
-	int ret;
-
-	ATH5K_TRACE(ah->ah_sc);
-
-	/*
-	 * Get queue by type
-	 */
-	/*5210 only has 2 queues*/
-	if (ah->ah_version == AR5K_AR5210) {
-		switch (queue_type) {
-		case AR5K_TX_QUEUE_DATA:
-			queue = AR5K_TX_QUEUE_ID_NOQCU_DATA;
-			break;
-		case AR5K_TX_QUEUE_BEACON:
-		case AR5K_TX_QUEUE_CAB:
-			queue = AR5K_TX_QUEUE_ID_NOQCU_BEACON;
-			break;
-		default:
-			return -EINVAL;
-		}
-	} else {
-		switch (queue_type) {
-		case AR5K_TX_QUEUE_DATA:
-			for (queue = AR5K_TX_QUEUE_ID_DATA_MIN;
-				ah->ah_txq[queue].tqi_type !=
-				AR5K_TX_QUEUE_INACTIVE; queue++) {
-
-				if (queue > AR5K_TX_QUEUE_ID_DATA_MAX)
-					return -EINVAL;
-			}
-			break;
-		case AR5K_TX_QUEUE_UAPSD:
-			queue = AR5K_TX_QUEUE_ID_UAPSD;
-			break;
-		case AR5K_TX_QUEUE_BEACON:
-			queue = AR5K_TX_QUEUE_ID_BEACON;
-			break;
-		case AR5K_TX_QUEUE_CAB:
-			queue = AR5K_TX_QUEUE_ID_CAB;
-			break;
-		case AR5K_TX_QUEUE_XR_DATA:
-			if (ah->ah_version != AR5K_AR5212)
-				ATH5K_ERR(ah->ah_sc,
-					"XR data queues only supported in"
-					" 5212!\n");
-			queue = AR5K_TX_QUEUE_ID_XR_DATA;
-			break;
-		default:
-			return -EINVAL;
-		}
-	}
-
-	/*
-	 * Setup internal queue structure
-	 */
-	memset(&ah->ah_txq[queue], 0, sizeof(struct ath5k_txq_info));
-	ah->ah_txq[queue].tqi_type = queue_type;
-
-	if (queue_info != NULL) {
-		queue_info->tqi_type = queue_type;
-		ret = ath5k_hw_setup_tx_queueprops(ah, queue, queue_info);
-		if (ret)
-			return ret;
-	}
-	/*
-	 * We use ah_txq_status to hold a temp value for
-	 * the Secondary interrupt mask registers on 5211+
-	 * check out ath5k_hw_reset_tx_queue
-	 */
-	AR5K_Q_ENABLE_BITS(ah->ah_txq_status, queue);
-
-	return queue;
-}
-
-/*
- * Setup a transmit queue
- */
-int ath5k_hw_setup_tx_queueprops(struct ath5k_hw *ah, int queue,
-				const struct ath5k_txq_info *queue_info)
-{
-	ATH5K_TRACE(ah->ah_sc);
-	AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num);
-
-	if (ah->ah_txq[queue].tqi_type == AR5K_TX_QUEUE_INACTIVE)
-		return -EIO;
-
-	memcpy(&ah->ah_txq[queue], queue_info, sizeof(struct ath5k_txq_info));
-
-	/*XXX: Is this supported on 5210 ?*/
-	if ((queue_info->tqi_type == AR5K_TX_QUEUE_DATA &&
-			((queue_info->tqi_subtype == AR5K_WME_AC_VI) ||
-			(queue_info->tqi_subtype == AR5K_WME_AC_VO))) ||
-			queue_info->tqi_type == AR5K_TX_QUEUE_UAPSD)
-		ah->ah_txq[queue].tqi_flags |= AR5K_TXQ_FLAG_POST_FR_BKOFF_DIS;
-
-	return 0;
-}
-
-/*
- * Get properties for a specific transmit queue
- */
-int ath5k_hw_get_tx_queueprops(struct ath5k_hw *ah, int queue,
-		struct ath5k_txq_info *queue_info)
-{
-	ATH5K_TRACE(ah->ah_sc);
-	memcpy(queue_info, &ah->ah_txq[queue], sizeof(struct ath5k_txq_info));
-	return 0;
-}
-
-/*
- * Set a transmit queue inactive
- */
-void ath5k_hw_release_tx_queue(struct ath5k_hw *ah, unsigned int queue)
-{
-	ATH5K_TRACE(ah->ah_sc);
-	if (WARN_ON(queue >= ah->ah_capabilities.cap_queues.q_tx_num))
-		return;
-
-	/* This queue will be skipped in further operations */
-	ah->ah_txq[queue].tqi_type = AR5K_TX_QUEUE_INACTIVE;
-	/*For SIMR setup*/
-	AR5K_Q_DISABLE_BITS(ah->ah_txq_status, queue);
-}
-
-/*
- * Set DFS params for a transmit queue
- */
-int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue)
-{
-	u32 cw_min, cw_max, retry_lg, retry_sh;
-	struct ath5k_txq_info *tq = &ah->ah_txq[queue];
-
-	ATH5K_TRACE(ah->ah_sc);
-	AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num);
-
-	tq = &ah->ah_txq[queue];
-
-	if (tq->tqi_type == AR5K_TX_QUEUE_INACTIVE)
-		return 0;
-
-	if (ah->ah_version == AR5K_AR5210) {
-		/* Only handle data queues, others will be ignored */
-		if (tq->tqi_type != AR5K_TX_QUEUE_DATA)
-			return 0;
-
-		/* Set Slot time */
-		ath5k_hw_reg_write(ah, ah->ah_turbo ?
-			AR5K_INIT_SLOT_TIME_TURBO : AR5K_INIT_SLOT_TIME,
-			AR5K_SLOT_TIME);
-		/* Set ACK_CTS timeout */
-		ath5k_hw_reg_write(ah, ah->ah_turbo ?
-			AR5K_INIT_ACK_CTS_TIMEOUT_TURBO :
-			AR5K_INIT_ACK_CTS_TIMEOUT, AR5K_SLOT_TIME);
-		/* Set Transmit Latency */
-		ath5k_hw_reg_write(ah, ah->ah_turbo ?
-			AR5K_INIT_TRANSMIT_LATENCY_TURBO :
-			AR5K_INIT_TRANSMIT_LATENCY, AR5K_USEC_5210);
-		/* Set IFS0 */
-		if (ah->ah_turbo)
-			 ath5k_hw_reg_write(ah, ((AR5K_INIT_SIFS_TURBO +
-				(ah->ah_aifs + tq->tqi_aifs) *
-				AR5K_INIT_SLOT_TIME_TURBO) <<
-				AR5K_IFS0_DIFS_S) | AR5K_INIT_SIFS_TURBO,
-				AR5K_IFS0);
-		else
-			ath5k_hw_reg_write(ah, ((AR5K_INIT_SIFS +
-				(ah->ah_aifs + tq->tqi_aifs) *
-				AR5K_INIT_SLOT_TIME) << AR5K_IFS0_DIFS_S) |
-				AR5K_INIT_SIFS, AR5K_IFS0);
-
-		/* Set IFS1 */
-		ath5k_hw_reg_write(ah, ah->ah_turbo ?
-			AR5K_INIT_PROTO_TIME_CNTRL_TURBO :
-			AR5K_INIT_PROTO_TIME_CNTRL, AR5K_IFS1);
-		/* Set AR5K_PHY_SETTLING */
-		ath5k_hw_reg_write(ah, ah->ah_turbo ?
-			(ath5k_hw_reg_read(ah, AR5K_PHY_SETTLING) & ~0x7F)
-			| 0x38 :
-			(ath5k_hw_reg_read(ah, AR5K_PHY_SETTLING) & ~0x7F)
-			| 0x1C,
-			AR5K_PHY_SETTLING);
-		/* Set Frame Control Register */
-		ath5k_hw_reg_write(ah, ah->ah_turbo ?
-			(AR5K_PHY_FRAME_CTL_INI | AR5K_PHY_TURBO_MODE |
-			AR5K_PHY_TURBO_SHORT | 0x2020) :
-			(AR5K_PHY_FRAME_CTL_INI | 0x1020),
-			AR5K_PHY_FRAME_CTL_5210);
-	}
-
-	/*
-	 * Calculate cwmin/max by channel mode
-	 */
-	cw_min = ah->ah_cw_min = AR5K_TUNE_CWMIN;
-	cw_max = ah->ah_cw_max = AR5K_TUNE_CWMAX;
-	ah->ah_aifs = AR5K_TUNE_AIFS;
-	/*XR is only supported on 5212*/
-	if (IS_CHAN_XR(ah->ah_current_channel) &&
-			ah->ah_version == AR5K_AR5212) {
-		cw_min = ah->ah_cw_min = AR5K_TUNE_CWMIN_XR;
-		cw_max = ah->ah_cw_max = AR5K_TUNE_CWMAX_XR;
-		ah->ah_aifs = AR5K_TUNE_AIFS_XR;
-	/*B mode is not supported on 5210*/
-	} else if (IS_CHAN_B(ah->ah_current_channel) &&
-			ah->ah_version != AR5K_AR5210) {
-		cw_min = ah->ah_cw_min = AR5K_TUNE_CWMIN_11B;
-		cw_max = ah->ah_cw_max = AR5K_TUNE_CWMAX_11B;
-		ah->ah_aifs = AR5K_TUNE_AIFS_11B;
-	}
-
-	cw_min = 1;
-	while (cw_min < ah->ah_cw_min)
-		cw_min = (cw_min << 1) | 1;
-
-	cw_min = tq->tqi_cw_min < 0 ? (cw_min >> (-tq->tqi_cw_min)) :
-		((cw_min << tq->tqi_cw_min) + (1 << tq->tqi_cw_min) - 1);
-	cw_max = tq->tqi_cw_max < 0 ? (cw_max >> (-tq->tqi_cw_max)) :
-		((cw_max << tq->tqi_cw_max) + (1 << tq->tqi_cw_max) - 1);
-
-	/*
-	 * Calculate and set retry limits
-	 */
-	if (ah->ah_software_retry) {
-		/* XXX Need to test this */
-		retry_lg = ah->ah_limit_tx_retries;
-		retry_sh = retry_lg = retry_lg > AR5K_DCU_RETRY_LMT_SH_RETRY ?
-			AR5K_DCU_RETRY_LMT_SH_RETRY : retry_lg;
-	} else {
-		retry_lg = AR5K_INIT_LG_RETRY;
-		retry_sh = AR5K_INIT_SH_RETRY;
-	}
-
-	/*No QCU/DCU [5210]*/
-	if (ah->ah_version == AR5K_AR5210) {
-		ath5k_hw_reg_write(ah,
-			(cw_min << AR5K_NODCU_RETRY_LMT_CW_MIN_S)
-			| AR5K_REG_SM(AR5K_INIT_SLG_RETRY,
-				AR5K_NODCU_RETRY_LMT_SLG_RETRY)
-			| AR5K_REG_SM(AR5K_INIT_SSH_RETRY,
-				AR5K_NODCU_RETRY_LMT_SSH_RETRY)
-			| AR5K_REG_SM(retry_lg, AR5K_NODCU_RETRY_LMT_LG_RETRY)
-			| AR5K_REG_SM(retry_sh, AR5K_NODCU_RETRY_LMT_SH_RETRY),
-			AR5K_NODCU_RETRY_LMT);
-	} else {
-		/*QCU/DCU [5211+]*/
-		ath5k_hw_reg_write(ah,
-			AR5K_REG_SM(AR5K_INIT_SLG_RETRY,
-				AR5K_DCU_RETRY_LMT_SLG_RETRY) |
-			AR5K_REG_SM(AR5K_INIT_SSH_RETRY,
-				AR5K_DCU_RETRY_LMT_SSH_RETRY) |
-			AR5K_REG_SM(retry_lg, AR5K_DCU_RETRY_LMT_LG_RETRY) |
-			AR5K_REG_SM(retry_sh, AR5K_DCU_RETRY_LMT_SH_RETRY),
-			AR5K_QUEUE_DFS_RETRY_LIMIT(queue));
-
-	/*===Rest is also for QCU/DCU only [5211+]===*/
-
-		/*
-		 * Set initial content window (cw_min/cw_max)
-		 * and arbitrated interframe space (aifs)...
-		 */
-		ath5k_hw_reg_write(ah,
-			AR5K_REG_SM(cw_min, AR5K_DCU_LCL_IFS_CW_MIN) |
-			AR5K_REG_SM(cw_max, AR5K_DCU_LCL_IFS_CW_MAX) |
-			AR5K_REG_SM(ah->ah_aifs + tq->tqi_aifs,
-				AR5K_DCU_LCL_IFS_AIFS),
-			AR5K_QUEUE_DFS_LOCAL_IFS(queue));
-
-		/*
-		 * Set misc registers
-		 */
-		ath5k_hw_reg_write(ah, AR5K_QCU_MISC_DCU_EARLY,
-			AR5K_QUEUE_MISC(queue));
-
-		if (tq->tqi_cbr_period) {
-			ath5k_hw_reg_write(ah, AR5K_REG_SM(tq->tqi_cbr_period,
-				AR5K_QCU_CBRCFG_INTVAL) |
-				AR5K_REG_SM(tq->tqi_cbr_overflow_limit,
-				AR5K_QCU_CBRCFG_ORN_THRES),
-				AR5K_QUEUE_CBRCFG(queue));
-			AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue),
-				AR5K_QCU_MISC_FRSHED_CBR);
-			if (tq->tqi_cbr_overflow_limit)
-				AR5K_REG_ENABLE_BITS(ah,
-					AR5K_QUEUE_MISC(queue),
-					AR5K_QCU_MISC_CBR_THRES_ENABLE);
-		}
-
-		if (tq->tqi_ready_time)
-			ath5k_hw_reg_write(ah, AR5K_REG_SM(tq->tqi_ready_time,
-				AR5K_QCU_RDYTIMECFG_INTVAL) |
-				AR5K_QCU_RDYTIMECFG_ENABLE,
-				AR5K_QUEUE_RDYTIMECFG(queue));
-
-		if (tq->tqi_burst_time) {
-			ath5k_hw_reg_write(ah, AR5K_REG_SM(tq->tqi_burst_time,
-				AR5K_DCU_CHAN_TIME_DUR) |
-				AR5K_DCU_CHAN_TIME_ENABLE,
-				AR5K_QUEUE_DFS_CHANNEL_TIME(queue));
-
-			if (tq->tqi_flags & AR5K_TXQ_FLAG_RDYTIME_EXP_POLICY_ENABLE)
-				AR5K_REG_ENABLE_BITS(ah,
-					AR5K_QUEUE_MISC(queue),
-					AR5K_QCU_MISC_RDY_VEOL_POLICY);
-		}
-
-		if (tq->tqi_flags & AR5K_TXQ_FLAG_BACKOFF_DISABLE)
-			ath5k_hw_reg_write(ah, AR5K_DCU_MISC_POST_FR_BKOFF_DIS,
-				AR5K_QUEUE_DFS_MISC(queue));
-
-		if (tq->tqi_flags & AR5K_TXQ_FLAG_FRAG_BURST_BACKOFF_ENABLE)
-			ath5k_hw_reg_write(ah, AR5K_DCU_MISC_BACKOFF_FRAG,
-				AR5K_QUEUE_DFS_MISC(queue));
-
-		/*
-		 * Set registers by queue type
-		 */
-		switch (tq->tqi_type) {
-		case AR5K_TX_QUEUE_BEACON:
-			AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue),
-				AR5K_QCU_MISC_FRSHED_DBA_GT |
-				AR5K_QCU_MISC_CBREXP_BCN |
-				AR5K_QCU_MISC_BCN_ENABLE);
-
-			AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_DFS_MISC(queue),
-				(AR5K_DCU_MISC_ARBLOCK_CTL_GLOBAL <<
-				AR5K_DCU_MISC_ARBLOCK_CTL_S) |
-				AR5K_DCU_MISC_POST_FR_BKOFF_DIS |
-				AR5K_DCU_MISC_BCN_ENABLE);
-
-			ath5k_hw_reg_write(ah, ((AR5K_TUNE_BEACON_INTERVAL -
-				(AR5K_TUNE_SW_BEACON_RESP -
-				AR5K_TUNE_DMA_BEACON_RESP) -
-				AR5K_TUNE_ADDITIONAL_SWBA_BACKOFF) * 1024) |
-				AR5K_QCU_RDYTIMECFG_ENABLE,
-				AR5K_QUEUE_RDYTIMECFG(queue));
-			break;
-
-		case AR5K_TX_QUEUE_CAB:
-			AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue),
-				AR5K_QCU_MISC_FRSHED_DBA_GT |
-				AR5K_QCU_MISC_CBREXP |
-				AR5K_QCU_MISC_CBREXP_BCN);
-
-			AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_DFS_MISC(queue),
-				(AR5K_DCU_MISC_ARBLOCK_CTL_GLOBAL <<
-				AR5K_DCU_MISC_ARBLOCK_CTL_S));
-			break;
-
-		case AR5K_TX_QUEUE_UAPSD:
-			AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue),
-				AR5K_QCU_MISC_CBREXP);
-			break;
-
-		case AR5K_TX_QUEUE_DATA:
-		default:
-			break;
-		}
-
-		/*
-		 * Enable interrupts for this tx queue
-		 * in the secondary interrupt mask registers
-		 */
-		if (tq->tqi_flags & AR5K_TXQ_FLAG_TXOKINT_ENABLE)
-			AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txok, queue);
-
-		if (tq->tqi_flags & AR5K_TXQ_FLAG_TXERRINT_ENABLE)
-			AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txerr, queue);
-
-		if (tq->tqi_flags & AR5K_TXQ_FLAG_TXURNINT_ENABLE)
-			AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txurn, queue);
-
-		if (tq->tqi_flags & AR5K_TXQ_FLAG_TXDESCINT_ENABLE)
-			AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txdesc, queue);
-
-		if (tq->tqi_flags & AR5K_TXQ_FLAG_TXEOLINT_ENABLE)
-			AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txeol, queue);
-
-
-		/* Update secondary interrupt mask registers */
-		ah->ah_txq_imr_txok &= ah->ah_txq_status;
-		ah->ah_txq_imr_txerr &= ah->ah_txq_status;
-		ah->ah_txq_imr_txurn &= ah->ah_txq_status;
-		ah->ah_txq_imr_txdesc &= ah->ah_txq_status;
-		ah->ah_txq_imr_txeol &= ah->ah_txq_status;
-
-		ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_txok,
-			AR5K_SIMR0_QCU_TXOK) |
-			AR5K_REG_SM(ah->ah_txq_imr_txdesc,
-			AR5K_SIMR0_QCU_TXDESC), AR5K_SIMR0);
-		ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_txerr,
-			AR5K_SIMR1_QCU_TXERR) |
-			AR5K_REG_SM(ah->ah_txq_imr_txeol,
-			AR5K_SIMR1_QCU_TXEOL), AR5K_SIMR1);
-		ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_txurn,
-			AR5K_SIMR2_QCU_TXURN), AR5K_SIMR2);
-	}
-
-	return 0;
-}
-
-/*
- * Get number of pending frames
- * for a specific queue [5211+]
- */
-u32 ath5k_hw_num_tx_pending(struct ath5k_hw *ah, unsigned int queue) {
-	ATH5K_TRACE(ah->ah_sc);
-	AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num);
-
-	/* Return if queue is declared inactive */
-	if (ah->ah_txq[queue].tqi_type == AR5K_TX_QUEUE_INACTIVE)
-		return false;
-
-	/* XXX: How about AR5K_CFG_TXCNT ? */
-	if (ah->ah_version == AR5K_AR5210)
-		return false;
-
-	return AR5K_QUEUE_STATUS(queue) & AR5K_QCU_STS_FRMPENDCNT;
-}
-
-/*
- * Set slot time
- */
-int ath5k_hw_set_slot_time(struct ath5k_hw *ah, unsigned int slot_time)
-{
-	ATH5K_TRACE(ah->ah_sc);
-	if (slot_time < AR5K_SLOT_TIME_9 || slot_time > AR5K_SLOT_TIME_MAX)
-		return -EINVAL;
-
-	if (ah->ah_version == AR5K_AR5210)
-		ath5k_hw_reg_write(ah, ath5k_hw_htoclock(slot_time,
-				ah->ah_turbo), AR5K_SLOT_TIME);
-	else
-		ath5k_hw_reg_write(ah, slot_time, AR5K_DCU_GBL_IFS_SLOT);
-
-	return 0;
-}
-
-/*
- * Get slot time
- */
-unsigned int ath5k_hw_get_slot_time(struct ath5k_hw *ah)
-{
-	ATH5K_TRACE(ah->ah_sc);
-	if (ah->ah_version == AR5K_AR5210)
-		return ath5k_hw_clocktoh(ath5k_hw_reg_read(ah,
-				AR5K_SLOT_TIME) & 0xffff, ah->ah_turbo);
-	else
-		return ath5k_hw_reg_read(ah, AR5K_DCU_GBL_IFS_SLOT) & 0xffff;
-}
-
-
-/******************************\
- Hardware Descriptor Functions
-\******************************/
-
-/*
- * TX Descriptor
- */
-
-/*
- * Initialize the 2-word tx descriptor on 5210/5211
- */
-static int
-ath5k_hw_setup_2word_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc,
-	unsigned int pkt_len, unsigned int hdr_len, enum ath5k_pkt_type type,
-	unsigned int tx_power, unsigned int tx_rate0, unsigned int tx_tries0,
-	unsigned int key_index, unsigned int antenna_mode, unsigned int flags,
-	unsigned int rtscts_rate, unsigned int rtscts_duration)
-{
-	u32 frame_type;
-	struct ath5k_hw_2w_tx_ctl *tx_ctl;
-	unsigned int frame_len;
-
-	tx_ctl = &desc->ud.ds_tx5210.tx_ctl;
-
-	/*
-	 * Validate input
-	 * - Zero retries don't make sense.
-	 * - A zero rate will put the HW into a mode where it continously sends
-	 *   noise on the channel, so it is important to avoid this.
-	 */
-	if (unlikely(tx_tries0 == 0)) {
-		ATH5K_ERR(ah->ah_sc, "zero retries\n");
-		WARN_ON(1);
-		return -EINVAL;
-	}
-	if (unlikely(tx_rate0 == 0)) {
-		ATH5K_ERR(ah->ah_sc, "zero rate\n");
-		WARN_ON(1);
-		return -EINVAL;
-	}
-
-	/* Clear descriptor */
-	memset(&desc->ud.ds_tx5210, 0, sizeof(struct ath5k_hw_5210_tx_desc));
-
-	/* Setup control descriptor */
-
-	/* Verify and set frame length */
-
-	/* remove padding we might have added before */
-	frame_len = pkt_len - (hdr_len & 3) + FCS_LEN;
-
-	if (frame_len & ~AR5K_2W_TX_DESC_CTL0_FRAME_LEN)
-		return -EINVAL;
-
-	tx_ctl->tx_control_0 = frame_len & AR5K_2W_TX_DESC_CTL0_FRAME_LEN;
-
-	/* Verify and set buffer length */
-
-	/* NB: beacon's BufLen must be a multiple of 4 bytes */
-	if(type == AR5K_PKT_TYPE_BEACON)
-		pkt_len = roundup(pkt_len, 4);
-
-	if (pkt_len & ~AR5K_2W_TX_DESC_CTL1_BUF_LEN)
-		return -EINVAL;
-
-	tx_ctl->tx_control_1 = pkt_len & AR5K_2W_TX_DESC_CTL1_BUF_LEN;
-
-	/*
-	 * Verify and set header length
-	 * XXX: I only found that on 5210 code, does it work on 5211 ?
-	 */
-	if (ah->ah_version == AR5K_AR5210) {
-		if (hdr_len & ~AR5K_2W_TX_DESC_CTL0_HEADER_LEN)
-			return -EINVAL;
-		tx_ctl->tx_control_0 |=
-			AR5K_REG_SM(hdr_len, AR5K_2W_TX_DESC_CTL0_HEADER_LEN);
-	}
-
-	/*Diferences between 5210-5211*/
-	if (ah->ah_version == AR5K_AR5210) {
-		switch (type) {
-		case AR5K_PKT_TYPE_BEACON:
-		case AR5K_PKT_TYPE_PROBE_RESP:
-			frame_type = AR5K_AR5210_TX_DESC_FRAME_TYPE_NO_DELAY;
-		case AR5K_PKT_TYPE_PIFS:
-			frame_type = AR5K_AR5210_TX_DESC_FRAME_TYPE_PIFS;
-		default:
-			frame_type = type /*<< 2 ?*/;
-		}
-
-		tx_ctl->tx_control_0 |=
-			AR5K_REG_SM(frame_type, AR5K_2W_TX_DESC_CTL0_FRAME_TYPE) |
-			AR5K_REG_SM(tx_rate0, AR5K_2W_TX_DESC_CTL0_XMIT_RATE);
-	} else {
-		tx_ctl->tx_control_0 |=
-			AR5K_REG_SM(tx_rate0, AR5K_2W_TX_DESC_CTL0_XMIT_RATE) |
-			AR5K_REG_SM(antenna_mode, AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT);
-		tx_ctl->tx_control_1 |=
-			AR5K_REG_SM(type, AR5K_2W_TX_DESC_CTL1_FRAME_TYPE);
-	}
-#define _TX_FLAGS(_c, _flag)						\
-	if (flags & AR5K_TXDESC_##_flag)				\
-		tx_ctl->tx_control_##_c |=				\
-			AR5K_2W_TX_DESC_CTL##_c##_##_flag
-
-	_TX_FLAGS(0, CLRDMASK);
-	_TX_FLAGS(0, VEOL);
-	_TX_FLAGS(0, INTREQ);
-	_TX_FLAGS(0, RTSENA);
-	_TX_FLAGS(1, NOACK);
-
-#undef _TX_FLAGS
-
-	/*
-	 * WEP crap
-	 */
-	if (key_index != AR5K_TXKEYIX_INVALID) {
-		tx_ctl->tx_control_0 |=
-			AR5K_2W_TX_DESC_CTL0_ENCRYPT_KEY_VALID;
-		tx_ctl->tx_control_1 |=
-			AR5K_REG_SM(key_index,
-			AR5K_2W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX);
-	}
-
-	/*
-	 * RTS/CTS Duration [5210 ?]
-	 */
-	if ((ah->ah_version == AR5K_AR5210) &&
-			(flags & (AR5K_TXDESC_RTSENA | AR5K_TXDESC_CTSENA)))
-		tx_ctl->tx_control_1 |= rtscts_duration &
-				AR5K_2W_TX_DESC_CTL1_RTS_DURATION;
-
-	return 0;
-}
-
-/*
- * Initialize the 4-word tx descriptor on 5212
- */
-static int ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *ah,
-	struct ath5k_desc *desc, unsigned int pkt_len, unsigned int hdr_len,
-	enum ath5k_pkt_type type, unsigned int tx_power, unsigned int tx_rate0,
-	unsigned int tx_tries0, unsigned int key_index,
-	unsigned int antenna_mode, unsigned int flags, unsigned int rtscts_rate,
-	unsigned int rtscts_duration)
-{
-	struct ath5k_hw_4w_tx_ctl *tx_ctl;
-	unsigned int frame_len;
-
-	ATH5K_TRACE(ah->ah_sc);
-	tx_ctl = &desc->ud.ds_tx5212.tx_ctl;
-
-	/*
-	 * Validate input
-	 * - Zero retries don't make sense.
-	 * - A zero rate will put the HW into a mode where it continously sends
-	 *   noise on the channel, so it is important to avoid this.
-	 */
-	if (unlikely(tx_tries0 == 0)) {
-		ATH5K_ERR(ah->ah_sc, "zero retries\n");
-		WARN_ON(1);
-		return -EINVAL;
-	}
-	if (unlikely(tx_rate0 == 0)) {
-		ATH5K_ERR(ah->ah_sc, "zero rate\n");
-		WARN_ON(1);
-		return -EINVAL;
-	}
-
-	/* Clear descriptor */
-	memset(&desc->ud.ds_tx5212, 0, sizeof(struct ath5k_hw_5212_tx_desc));
-
-	/* Setup control descriptor */
-
-	/* Verify and set frame length */
-
-	/* remove padding we might have added before */
-	frame_len = pkt_len - (hdr_len & 3) + FCS_LEN;
-
-	if (frame_len & ~AR5K_4W_TX_DESC_CTL0_FRAME_LEN)
-		return -EINVAL;
-
-	tx_ctl->tx_control_0 = frame_len & AR5K_4W_TX_DESC_CTL0_FRAME_LEN;
-
-	/* Verify and set buffer length */
-
-	/* NB: beacon's BufLen must be a multiple of 4 bytes */
-	if(type == AR5K_PKT_TYPE_BEACON)
-		pkt_len = roundup(pkt_len, 4);
-
-	if (pkt_len & ~AR5K_4W_TX_DESC_CTL1_BUF_LEN)
-		return -EINVAL;
-
-	tx_ctl->tx_control_1 = pkt_len & AR5K_4W_TX_DESC_CTL1_BUF_LEN;
-
-	tx_ctl->tx_control_0 |=
-		AR5K_REG_SM(tx_power, AR5K_4W_TX_DESC_CTL0_XMIT_POWER) |
-		AR5K_REG_SM(antenna_mode, AR5K_4W_TX_DESC_CTL0_ANT_MODE_XMIT);
-	tx_ctl->tx_control_1 |= AR5K_REG_SM(type,
-					AR5K_4W_TX_DESC_CTL1_FRAME_TYPE);
-	tx_ctl->tx_control_2 = AR5K_REG_SM(tx_tries0 + AR5K_TUNE_HWTXTRIES,
-					AR5K_4W_TX_DESC_CTL2_XMIT_TRIES0);
-	tx_ctl->tx_control_3 = tx_rate0 & AR5K_4W_TX_DESC_CTL3_XMIT_RATE0;
-
-#define _TX_FLAGS(_c, _flag)			\
-	if (flags & AR5K_TXDESC_##_flag)	\
-		tx_ctl->tx_control_##_c |=	\
-			AR5K_4W_TX_DESC_CTL##_c##_##_flag
-
-	_TX_FLAGS(0, CLRDMASK);
-	_TX_FLAGS(0, VEOL);
-	_TX_FLAGS(0, INTREQ);
-	_TX_FLAGS(0, RTSENA);
-	_TX_FLAGS(0, CTSENA);
-	_TX_FLAGS(1, NOACK);
-
-#undef _TX_FLAGS
-
-	/*
-	 * WEP crap
-	 */
-	if (key_index != AR5K_TXKEYIX_INVALID) {
-		tx_ctl->tx_control_0 |= AR5K_4W_TX_DESC_CTL0_ENCRYPT_KEY_VALID;
-		tx_ctl->tx_control_1 |= AR5K_REG_SM(key_index,
-				AR5K_4W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX);
-	}
-
-	/*
-	 * RTS/CTS
-	 */
-	if (flags & (AR5K_TXDESC_RTSENA | AR5K_TXDESC_CTSENA)) {
-		if ((flags & AR5K_TXDESC_RTSENA) &&
-				(flags & AR5K_TXDESC_CTSENA))
-			return -EINVAL;
-		tx_ctl->tx_control_2 |= rtscts_duration &
-				AR5K_4W_TX_DESC_CTL2_RTS_DURATION;
-		tx_ctl->tx_control_3 |= AR5K_REG_SM(rtscts_rate,
-				AR5K_4W_TX_DESC_CTL3_RTS_CTS_RATE);
-	}
-
-	return 0;
-}
-
-/*
- * Initialize a 4-word multirate tx descriptor on 5212
- */
-static int
-ath5k_hw_setup_xr_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc,
-	unsigned int tx_rate1, u_int tx_tries1, u_int tx_rate2, u_int tx_tries2,
-	unsigned int tx_rate3, u_int tx_tries3)
-{
-	struct ath5k_hw_4w_tx_ctl *tx_ctl;
-
-	/*
-	 * Rates can be 0 as long as the retry count is 0 too.
-	 * A zero rate and nonzero retry count will put the HW into a mode where
-	 * it continously sends noise on the channel, so it is important to
-	 * avoid this.
-	 */
-	if (unlikely((tx_rate1 == 0 && tx_tries1 != 0) ||
-		     (tx_rate2 == 0 && tx_tries2 != 0) ||
-		     (tx_rate3 == 0 && tx_tries3 != 0))) {
-		ATH5K_ERR(ah->ah_sc, "zero rate\n");
-		WARN_ON(1);
-		return -EINVAL;
-	}
-
-	if (ah->ah_version == AR5K_AR5212) {
-		tx_ctl = &desc->ud.ds_tx5212.tx_ctl;
-
-#define _XTX_TRIES(_n)							\
-	if (tx_tries##_n) {						\
-		tx_ctl->tx_control_2 |=				\
-		    AR5K_REG_SM(tx_tries##_n,				\
-		    AR5K_4W_TX_DESC_CTL2_XMIT_TRIES##_n);		\
-		tx_ctl->tx_control_3 |=				\
-		    AR5K_REG_SM(tx_rate##_n,				\
-		    AR5K_4W_TX_DESC_CTL3_XMIT_RATE##_n);		\
-	}
-
-		_XTX_TRIES(1);
-		_XTX_TRIES(2);
-		_XTX_TRIES(3);
-
-#undef _XTX_TRIES
-
-		return 1;
-	}
-
-	return 0;
-}
-
-/*
- * Proccess the tx status descriptor on 5210/5211
- */
-static int ath5k_hw_proc_2word_tx_status(struct ath5k_hw *ah,
-		struct ath5k_desc *desc, struct ath5k_tx_status *ts)
-{
-	struct ath5k_hw_2w_tx_ctl *tx_ctl;
-	struct ath5k_hw_tx_status *tx_status;
-
-	ATH5K_TRACE(ah->ah_sc);
-
-	tx_ctl = &desc->ud.ds_tx5210.tx_ctl;
-	tx_status = &desc->ud.ds_tx5210.tx_stat;
-
-	/* No frame has been send or error */
-	if (unlikely((tx_status->tx_status_1 & AR5K_DESC_TX_STATUS1_DONE) == 0))
-		return -EINPROGRESS;
-
-	/*
-	 * Get descriptor status
-	 */
-	ts->ts_tstamp = AR5K_REG_MS(tx_status->tx_status_0,
-		AR5K_DESC_TX_STATUS0_SEND_TIMESTAMP);
-	ts->ts_shortretry = AR5K_REG_MS(tx_status->tx_status_0,
-		AR5K_DESC_TX_STATUS0_SHORT_RETRY_COUNT);
-	ts->ts_longretry = AR5K_REG_MS(tx_status->tx_status_0,
-		AR5K_DESC_TX_STATUS0_LONG_RETRY_COUNT);
-	/*TODO: ts->ts_virtcol + test*/
-	ts->ts_seqnum = AR5K_REG_MS(tx_status->tx_status_1,
-		AR5K_DESC_TX_STATUS1_SEQ_NUM);
-	ts->ts_rssi = AR5K_REG_MS(tx_status->tx_status_1,
-		AR5K_DESC_TX_STATUS1_ACK_SIG_STRENGTH);
-	ts->ts_antenna = 1;
-	ts->ts_status = 0;
-	ts->ts_rate = AR5K_REG_MS(tx_ctl->tx_control_0,
-		AR5K_2W_TX_DESC_CTL0_XMIT_RATE);
-
-	if ((tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FRAME_XMIT_OK) == 0){
-		if (tx_status->tx_status_0 &
-				AR5K_DESC_TX_STATUS0_EXCESSIVE_RETRIES)
-			ts->ts_status |= AR5K_TXERR_XRETRY;
-
-		if (tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FIFO_UNDERRUN)
-			ts->ts_status |= AR5K_TXERR_FIFO;
-
-		if (tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FILTERED)
-			ts->ts_status |= AR5K_TXERR_FILT;
-	}
-
-	return 0;
-}
-
-/*
- * Proccess a tx descriptor on 5212
- */
-static int ath5k_hw_proc_4word_tx_status(struct ath5k_hw *ah,
-		struct ath5k_desc *desc, struct ath5k_tx_status *ts)
-{
-	struct ath5k_hw_4w_tx_ctl *tx_ctl;
-	struct ath5k_hw_tx_status *tx_status;
-
-	ATH5K_TRACE(ah->ah_sc);
-
-	tx_ctl = &desc->ud.ds_tx5212.tx_ctl;
-	tx_status = &desc->ud.ds_tx5212.tx_stat;
-
-	/* No frame has been send or error */
-	if (unlikely((tx_status->tx_status_1 & AR5K_DESC_TX_STATUS1_DONE) == 0))
-		return -EINPROGRESS;
-
-	/*
-	 * Get descriptor status
-	 */
-	ts->ts_tstamp = AR5K_REG_MS(tx_status->tx_status_0,
-		AR5K_DESC_TX_STATUS0_SEND_TIMESTAMP);
-	ts->ts_shortretry = AR5K_REG_MS(tx_status->tx_status_0,
-		AR5K_DESC_TX_STATUS0_SHORT_RETRY_COUNT);
-	ts->ts_longretry = AR5K_REG_MS(tx_status->tx_status_0,
-		AR5K_DESC_TX_STATUS0_LONG_RETRY_COUNT);
-	ts->ts_seqnum = AR5K_REG_MS(tx_status->tx_status_1,
-		AR5K_DESC_TX_STATUS1_SEQ_NUM);
-	ts->ts_rssi = AR5K_REG_MS(tx_status->tx_status_1,
-		AR5K_DESC_TX_STATUS1_ACK_SIG_STRENGTH);
-	ts->ts_antenna = (tx_status->tx_status_1 &
-		AR5K_DESC_TX_STATUS1_XMIT_ANTENNA) ? 2 : 1;
-	ts->ts_status = 0;
-
-	switch (AR5K_REG_MS(tx_status->tx_status_1,
-			AR5K_DESC_TX_STATUS1_FINAL_TS_INDEX)) {
-	case 0:
-		ts->ts_rate = tx_ctl->tx_control_3 &
-			AR5K_4W_TX_DESC_CTL3_XMIT_RATE0;
-		break;
-	case 1:
-		ts->ts_rate = AR5K_REG_MS(tx_ctl->tx_control_3,
-			AR5K_4W_TX_DESC_CTL3_XMIT_RATE1);
-		ts->ts_longretry += AR5K_REG_MS(tx_ctl->tx_control_2,
-			AR5K_4W_TX_DESC_CTL2_XMIT_TRIES1);
-		break;
-	case 2:
-		ts->ts_rate = AR5K_REG_MS(tx_ctl->tx_control_3,
-			AR5K_4W_TX_DESC_CTL3_XMIT_RATE2);
-		ts->ts_longretry += AR5K_REG_MS(tx_ctl->tx_control_2,
-			AR5K_4W_TX_DESC_CTL2_XMIT_TRIES2);
-		break;
-	case 3:
-		ts->ts_rate = AR5K_REG_MS(tx_ctl->tx_control_3,
-			AR5K_4W_TX_DESC_CTL3_XMIT_RATE3);
-		ts->ts_longretry += AR5K_REG_MS(tx_ctl->tx_control_2,
-			AR5K_4W_TX_DESC_CTL2_XMIT_TRIES3);
-		break;
-	}
-
-	if ((tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FRAME_XMIT_OK) == 0){
-		if (tx_status->tx_status_0 &
-				AR5K_DESC_TX_STATUS0_EXCESSIVE_RETRIES)
-			ts->ts_status |= AR5K_TXERR_XRETRY;
-
-		if (tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FIFO_UNDERRUN)
-			ts->ts_status |= AR5K_TXERR_FIFO;
-
-		if (tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FILTERED)
-			ts->ts_status |= AR5K_TXERR_FILT;
-	}
-
-	return 0;
-}
-
-/*
- * RX Descriptor
- */
-
-/*
- * Initialize an rx descriptor
- */
-int ath5k_hw_setup_rx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc,
-			u32 size, unsigned int flags)
-{
-	struct ath5k_hw_rx_ctl *rx_ctl;
-
-	ATH5K_TRACE(ah->ah_sc);
-	rx_ctl = &desc->ud.ds_rx.rx_ctl;
-
-	/*
-	 * Clear the descriptor
-	 * If we don't clean the status descriptor,
-	 * while scanning we get too many results,
-	 * most of them virtual, after some secs
-	 * of scanning system hangs. M.F.
-	*/
-	memset(&desc->ud.ds_rx, 0, sizeof(struct ath5k_hw_all_rx_desc));
-
-	/* Setup descriptor */
-	rx_ctl->rx_control_1 = size & AR5K_DESC_RX_CTL1_BUF_LEN;
-	if (unlikely(rx_ctl->rx_control_1 != size))
-		return -EINVAL;
-
-	if (flags & AR5K_RXDESC_INTREQ)
-		rx_ctl->rx_control_1 |= AR5K_DESC_RX_CTL1_INTREQ;
-
-	return 0;
-}
-
-/*
- * Proccess the rx status descriptor on 5210/5211
- */
-static int ath5k_hw_proc_5210_rx_status(struct ath5k_hw *ah,
-		struct ath5k_desc *desc, struct ath5k_rx_status *rs)
-{
-	struct ath5k_hw_rx_status *rx_status;
-
-	rx_status = &desc->ud.ds_rx.u.rx_stat;
-
-	/* No frame received / not ready */
-	if (unlikely((rx_status->rx_status_1 & AR5K_5210_RX_DESC_STATUS1_DONE)
-				== 0))
-		return -EINPROGRESS;
-
-	/*
-	 * Frame receive status
-	 */
-	rs->rs_datalen = rx_status->rx_status_0 &
-		AR5K_5210_RX_DESC_STATUS0_DATA_LEN;
-	rs->rs_rssi = AR5K_REG_MS(rx_status->rx_status_0,
-		AR5K_5210_RX_DESC_STATUS0_RECEIVE_SIGNAL);
-	rs->rs_rate = AR5K_REG_MS(rx_status->rx_status_0,
-		AR5K_5210_RX_DESC_STATUS0_RECEIVE_RATE);
-	rs->rs_antenna = rx_status->rx_status_0 &
-		AR5K_5210_RX_DESC_STATUS0_RECEIVE_ANTENNA;
-	rs->rs_more = rx_status->rx_status_0 &
-		AR5K_5210_RX_DESC_STATUS0_MORE;
-	/* TODO: this timestamp is 13 bit, later on we assume 15 bit */
-	rs->rs_tstamp = AR5K_REG_MS(rx_status->rx_status_1,
-		AR5K_5210_RX_DESC_STATUS1_RECEIVE_TIMESTAMP);
-	rs->rs_status = 0;
-	rs->rs_phyerr = 0;
-
-	/*
-	 * Key table status
-	 */
-	if (rx_status->rx_status_1 & AR5K_5210_RX_DESC_STATUS1_KEY_INDEX_VALID)
-		rs->rs_keyix = AR5K_REG_MS(rx_status->rx_status_1,
-			AR5K_5210_RX_DESC_STATUS1_KEY_INDEX);
-	else
-		rs->rs_keyix = AR5K_RXKEYIX_INVALID;
-
-	/*
-	 * Receive/descriptor errors
-	 */
-	if ((rx_status->rx_status_1 &
-			AR5K_5210_RX_DESC_STATUS1_FRAME_RECEIVE_OK) == 0) {
-		if (rx_status->rx_status_1 &
-				AR5K_5210_RX_DESC_STATUS1_CRC_ERROR)
-			rs->rs_status |= AR5K_RXERR_CRC;
-
-		if (rx_status->rx_status_1 &
-				AR5K_5210_RX_DESC_STATUS1_FIFO_OVERRUN)
-			rs->rs_status |= AR5K_RXERR_FIFO;
-
-		if (rx_status->rx_status_1 &
-				AR5K_5210_RX_DESC_STATUS1_PHY_ERROR) {
-			rs->rs_status |= AR5K_RXERR_PHY;
-			rs->rs_phyerr |= AR5K_REG_MS(rx_status->rx_status_1,
-					   AR5K_5210_RX_DESC_STATUS1_PHY_ERROR);
-		}
-
-		if (rx_status->rx_status_1 &
-				AR5K_5210_RX_DESC_STATUS1_DECRYPT_CRC_ERROR)
-			rs->rs_status |= AR5K_RXERR_DECRYPT;
-	}
-
-	return 0;
-}
-
-/*
- * Proccess the rx status descriptor on 5212
- */
-static int ath5k_hw_proc_5212_rx_status(struct ath5k_hw *ah,
-		struct ath5k_desc *desc, struct ath5k_rx_status *rs)
-{
-	struct ath5k_hw_rx_status *rx_status;
-	struct ath5k_hw_rx_error *rx_err;
-
-	ATH5K_TRACE(ah->ah_sc);
-	rx_status = &desc->ud.ds_rx.u.rx_stat;
-
-	/* Overlay on error */
-	rx_err = &desc->ud.ds_rx.u.rx_err;
-
-	/* No frame received / not ready */
-	if (unlikely((rx_status->rx_status_1 & AR5K_5212_RX_DESC_STATUS1_DONE)
-				== 0))
-		return -EINPROGRESS;
-
-	/*
-	 * Frame receive status
-	 */
-	rs->rs_datalen = rx_status->rx_status_0 &
-		AR5K_5212_RX_DESC_STATUS0_DATA_LEN;
-	rs->rs_rssi = AR5K_REG_MS(rx_status->rx_status_0,
-		AR5K_5212_RX_DESC_STATUS0_RECEIVE_SIGNAL);
-	rs->rs_rate = AR5K_REG_MS(rx_status->rx_status_0,
-		AR5K_5212_RX_DESC_STATUS0_RECEIVE_RATE);
-	rs->rs_antenna = rx_status->rx_status_0 &
-		AR5K_5212_RX_DESC_STATUS0_RECEIVE_ANTENNA;
-	rs->rs_more = rx_status->rx_status_0 &
-		AR5K_5212_RX_DESC_STATUS0_MORE;
-	rs->rs_tstamp = AR5K_REG_MS(rx_status->rx_status_1,
-		AR5K_5212_RX_DESC_STATUS1_RECEIVE_TIMESTAMP);
-	rs->rs_status = 0;
-	rs->rs_phyerr = 0;
-
-	/*
-	 * Key table status
-	 */
-	if (rx_status->rx_status_1 & AR5K_5212_RX_DESC_STATUS1_KEY_INDEX_VALID)
-		rs->rs_keyix = AR5K_REG_MS(rx_status->rx_status_1,
-				AR5K_5212_RX_DESC_STATUS1_KEY_INDEX);
-	else
-		rs->rs_keyix = AR5K_RXKEYIX_INVALID;
-
-	/*
-	 * Receive/descriptor errors
-	 */
-	if ((rx_status->rx_status_1 &
-			AR5K_5212_RX_DESC_STATUS1_FRAME_RECEIVE_OK) == 0) {
-		if (rx_status->rx_status_1 &
-				AR5K_5212_RX_DESC_STATUS1_CRC_ERROR)
-			rs->rs_status |= AR5K_RXERR_CRC;
-
-		if (rx_status->rx_status_1 &
-				AR5K_5212_RX_DESC_STATUS1_PHY_ERROR) {
-			rs->rs_status |= AR5K_RXERR_PHY;
-			rs->rs_phyerr |= AR5K_REG_MS(rx_err->rx_error_1,
-					   AR5K_RX_DESC_ERROR1_PHY_ERROR_CODE);
-		}
-
-		if (rx_status->rx_status_1 &
-				AR5K_5212_RX_DESC_STATUS1_DECRYPT_CRC_ERROR)
-			rs->rs_status |= AR5K_RXERR_DECRYPT;
-
-		if (rx_status->rx_status_1 &
-				AR5K_5212_RX_DESC_STATUS1_MIC_ERROR)
-			rs->rs_status |= AR5K_RXERR_MIC;
-	}
-
-	return 0;
-}
-
-
-/****************\
-  GPIO Functions
-\****************/
-
-/*
- * Set led state
- */
-void ath5k_hw_set_ledstate(struct ath5k_hw *ah, unsigned int state)
-{
-	u32 led;
-	/*5210 has different led mode handling*/
-	u32 led_5210;
-
-	ATH5K_TRACE(ah->ah_sc);
-
-	/*Reset led status*/
-	if (ah->ah_version != AR5K_AR5210)
-		AR5K_REG_DISABLE_BITS(ah, AR5K_PCICFG,
-			AR5K_PCICFG_LEDMODE |  AR5K_PCICFG_LED);
-	else
-		AR5K_REG_DISABLE_BITS(ah, AR5K_PCICFG, AR5K_PCICFG_LED);
-
-	/*
-	 * Some blinking values, define at your wish
-	 */
-	switch (state) {
-	case AR5K_LED_SCAN:
-	case AR5K_LED_AUTH:
-		led = AR5K_PCICFG_LEDMODE_PROP | AR5K_PCICFG_LED_PEND;
-		led_5210 = AR5K_PCICFG_LED_PEND | AR5K_PCICFG_LED_BCTL;
-		break;
-
-	case AR5K_LED_INIT:
-		led = AR5K_PCICFG_LEDMODE_PROP | AR5K_PCICFG_LED_NONE;
-		led_5210 = AR5K_PCICFG_LED_PEND;
-		break;
-
-	case AR5K_LED_ASSOC:
-	case AR5K_LED_RUN:
-		led = AR5K_PCICFG_LEDMODE_PROP | AR5K_PCICFG_LED_ASSOC;
-		led_5210 = AR5K_PCICFG_LED_ASSOC;
-		break;
-
-	default:
-		led = AR5K_PCICFG_LEDMODE_PROM | AR5K_PCICFG_LED_NONE;
-		led_5210 = AR5K_PCICFG_LED_PEND;
-		break;
-	}
-
-	/*Write new status to the register*/
-	if (ah->ah_version != AR5K_AR5210)
-		AR5K_REG_ENABLE_BITS(ah, AR5K_PCICFG, led);
-	else
-		AR5K_REG_ENABLE_BITS(ah, AR5K_PCICFG, led_5210);
-}
-
-/*
- * Set GPIO outputs
- */
-int ath5k_hw_set_gpio_output(struct ath5k_hw *ah, u32 gpio)
-{
-	ATH5K_TRACE(ah->ah_sc);
-	if (gpio > AR5K_NUM_GPIO)
-		return -EINVAL;
-
-	ath5k_hw_reg_write(ah, (ath5k_hw_reg_read(ah, AR5K_GPIOCR) &~
-		AR5K_GPIOCR_OUT(gpio)) | AR5K_GPIOCR_OUT(gpio), AR5K_GPIOCR);
-
-	return 0;
-}
-
-/*
- * Set GPIO inputs
- */
-int ath5k_hw_set_gpio_input(struct ath5k_hw *ah, u32 gpio)
-{
-	ATH5K_TRACE(ah->ah_sc);
-	if (gpio > AR5K_NUM_GPIO)
-		return -EINVAL;
-
-	ath5k_hw_reg_write(ah, (ath5k_hw_reg_read(ah, AR5K_GPIOCR) &~
-		AR5K_GPIOCR_OUT(gpio)) | AR5K_GPIOCR_IN(gpio), AR5K_GPIOCR);
-
-	return 0;
-}
-
-/*
- * Get GPIO state
- */
-u32 ath5k_hw_get_gpio(struct ath5k_hw *ah, u32 gpio)
-{
-	ATH5K_TRACE(ah->ah_sc);
-	if (gpio > AR5K_NUM_GPIO)
-		return 0xffffffff;
-
-	/* GPIO input magic */
-	return ((ath5k_hw_reg_read(ah, AR5K_GPIODI) & AR5K_GPIODI_M) >> gpio) &
-		0x1;
-}
-
-/*
- * Set GPIO state
- */
-int ath5k_hw_set_gpio(struct ath5k_hw *ah, u32 gpio, u32 val)
-{
-	u32 data;
-	ATH5K_TRACE(ah->ah_sc);
-
-	if (gpio > AR5K_NUM_GPIO)
-		return -EINVAL;
-
-	/* GPIO output magic */
-	data = ath5k_hw_reg_read(ah, AR5K_GPIODO);
-
-	data &= ~(1 << gpio);
-	data |= (val & 1) << gpio;
-
-	ath5k_hw_reg_write(ah, data, AR5K_GPIODO);
-
-	return 0;
-}
-
-/*
- * Initialize the GPIO interrupt (RFKill switch)
- */
-void ath5k_hw_set_gpio_intr(struct ath5k_hw *ah, unsigned int gpio,
-		u32 interrupt_level)
-{
-	u32 data;
-
-	ATH5K_TRACE(ah->ah_sc);
-	if (gpio > AR5K_NUM_GPIO)
-		return;
-
-	/*
-	 * Set the GPIO interrupt
-	 */
-	data = (ath5k_hw_reg_read(ah, AR5K_GPIOCR) &
-		~(AR5K_GPIOCR_INT_SEL(gpio) | AR5K_GPIOCR_INT_SELH |
-		AR5K_GPIOCR_INT_ENA | AR5K_GPIOCR_OUT(gpio))) |
-		(AR5K_GPIOCR_INT_SEL(gpio) | AR5K_GPIOCR_INT_ENA);
-
-	ath5k_hw_reg_write(ah, interrupt_level ? data :
-		(data | AR5K_GPIOCR_INT_SELH), AR5K_GPIOCR);
-
-	ah->ah_imr |= AR5K_IMR_GPIO;
-
-	/* Enable GPIO interrupts */
-	AR5K_REG_ENABLE_BITS(ah, AR5K_PIMR, AR5K_IMR_GPIO);
-}
-
-
-
-
-/****************\
-  Misc functions
-\****************/
-
-int ath5k_hw_get_capability(struct ath5k_hw *ah,
-		enum ath5k_capability_type cap_type,
-		u32 capability, u32 *result)
-{
-	ATH5K_TRACE(ah->ah_sc);
-
-	switch (cap_type) {
-	case AR5K_CAP_NUM_TXQUEUES:
-		if (result) {
-			if (ah->ah_version == AR5K_AR5210)
-				*result = AR5K_NUM_TX_QUEUES_NOQCU;
-			else
-				*result = AR5K_NUM_TX_QUEUES;
-			goto yes;
-		}
-	case AR5K_CAP_VEOL:
-		goto yes;
-	case AR5K_CAP_COMPRESSION:
-		if (ah->ah_version == AR5K_AR5212)
-			goto yes;
-		else
-			goto no;
-	case AR5K_CAP_BURST:
-		goto yes;
-	case AR5K_CAP_TPC:
-		goto yes;
-	case AR5K_CAP_BSSIDMASK:
-		if (ah->ah_version == AR5K_AR5212)
-			goto yes;
-		else
-			goto no;
-	case AR5K_CAP_XR:
-		if (ah->ah_version == AR5K_AR5212)
-			goto yes;
-		else
-			goto no;
-	default:
-		goto no;
-	}
-
-no:
-	return -EINVAL;
-yes:
-	return 0;
-}
-
-static int ath5k_hw_enable_pspoll(struct ath5k_hw *ah, u8 *bssid,
-		u16 assoc_id)
-{
-	ATH5K_TRACE(ah->ah_sc);
-
-	if (ah->ah_version == AR5K_AR5210) {
-		AR5K_REG_DISABLE_BITS(ah, AR5K_STA_ID1,
-			AR5K_STA_ID1_NO_PSPOLL | AR5K_STA_ID1_DEFAULT_ANTENNA);
-		return 0;
-	}
-
-	return -EIO;
-}
-
-static int ath5k_hw_disable_pspoll(struct ath5k_hw *ah)
-{
-	ATH5K_TRACE(ah->ah_sc);
-
-	if (ah->ah_version == AR5K_AR5210) {
-		AR5K_REG_ENABLE_BITS(ah, AR5K_STA_ID1,
-			AR5K_STA_ID1_NO_PSPOLL | AR5K_STA_ID1_DEFAULT_ANTENNA);
-		return 0;
-	}
-
-	return -EIO;
-}
diff --git a/drivers/net/wireless/ath5k/hw.h b/drivers/net/wireless/ath5k/hw.h
deleted file mode 100644
index 64fca8d..0000000
--- a/drivers/net/wireless/ath5k/hw.h
+++ /dev/null
@@ -1,616 +0,0 @@
-/*
- * Copyright (c) 2004-2007 Reyk Floeter <reyk@openbsd.org>
- * Copyright (c) 2006-2007 Nick Kossifidis <mickflemm@gmail.com>
- * Copyright (c) 2007 Matthew W. S. Bell  <mentor@madwifi.org>
- * Copyright (c) 2007 Luis Rodriguez <mcgrof@winlab.rutgers.edu>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <linux/delay.h>
-
-/*
- * Gain settings
- */
-
-enum ath5k_rfgain {
-	AR5K_RFGAIN_INACTIVE = 0,
-	AR5K_RFGAIN_READ_REQUESTED,
-	AR5K_RFGAIN_NEED_CHANGE,
-};
-
-#define AR5K_GAIN_CRN_FIX_BITS_5111		4
-#define AR5K_GAIN_CRN_FIX_BITS_5112		7
-#define AR5K_GAIN_CRN_MAX_FIX_BITS		AR5K_GAIN_CRN_FIX_BITS_5112
-#define AR5K_GAIN_DYN_ADJUST_HI_MARGIN		15
-#define AR5K_GAIN_DYN_ADJUST_LO_MARGIN		20
-#define AR5K_GAIN_CCK_PROBE_CORR		5
-#define AR5K_GAIN_CCK_OFDM_GAIN_DELTA		15
-#define AR5K_GAIN_STEP_COUNT			10
-#define AR5K_GAIN_PARAM_TX_CLIP			0
-#define AR5K_GAIN_PARAM_PD_90			1
-#define AR5K_GAIN_PARAM_PD_84			2
-#define AR5K_GAIN_PARAM_GAIN_SEL		3
-#define AR5K_GAIN_PARAM_MIX_ORN			0
-#define AR5K_GAIN_PARAM_PD_138			1
-#define AR5K_GAIN_PARAM_PD_137			2
-#define AR5K_GAIN_PARAM_PD_136			3
-#define AR5K_GAIN_PARAM_PD_132			4
-#define AR5K_GAIN_PARAM_PD_131			5
-#define AR5K_GAIN_PARAM_PD_130			6
-#define AR5K_GAIN_CHECK_ADJUST(_g) 		\
-	((_g)->g_current <= (_g)->g_low || (_g)->g_current >= (_g)->g_high)
-
-struct ath5k_gain_opt_step {
-	s16				gos_param[AR5K_GAIN_CRN_MAX_FIX_BITS];
-	s32				gos_gain;
-};
-
-struct ath5k_gain {
-	u32			g_step_idx;
-	u32			g_current;
-	u32			g_target;
-	u32			g_low;
-	u32			g_high;
-	u32			g_f_corr;
-	u32			g_active;
-	const struct ath5k_gain_opt_step	*g_step;
-};
-
-
-/*
- * HW SPECIFIC STRUCTS
- */
-
-/* Some EEPROM defines */
-#define AR5K_EEPROM_EEP_SCALE		100
-#define AR5K_EEPROM_EEP_DELTA		10
-#define AR5K_EEPROM_N_MODES		3
-#define AR5K_EEPROM_N_5GHZ_CHAN		10
-#define AR5K_EEPROM_N_2GHZ_CHAN		3
-#define AR5K_EEPROM_MAX_CHAN		10
-#define AR5K_EEPROM_N_PCDAC		11
-#define AR5K_EEPROM_N_TEST_FREQ		8
-#define AR5K_EEPROM_N_EDGES		8
-#define AR5K_EEPROM_N_INTERCEPTS	11
-#define AR5K_EEPROM_FREQ_M(_v)		AR5K_EEPROM_OFF(_v, 0x7f, 0xff)
-#define AR5K_EEPROM_PCDAC_M		0x3f
-#define AR5K_EEPROM_PCDAC_START		1
-#define AR5K_EEPROM_PCDAC_STOP		63
-#define AR5K_EEPROM_PCDAC_STEP		1
-#define AR5K_EEPROM_NON_EDGE_M		0x40
-#define AR5K_EEPROM_CHANNEL_POWER	8
-#define AR5K_EEPROM_N_OBDB		4
-#define AR5K_EEPROM_OBDB_DIS		0xffff
-#define AR5K_EEPROM_CHANNEL_DIS		0xff
-#define AR5K_EEPROM_SCALE_OC_DELTA(_x)	(((_x) * 2) / 10)
-#define AR5K_EEPROM_N_CTLS(_v)		AR5K_EEPROM_OFF(_v, 16, 32)
-#define AR5K_EEPROM_MAX_CTLS		32
-#define AR5K_EEPROM_N_XPD_PER_CHANNEL	4
-#define AR5K_EEPROM_N_XPD0_POINTS	4
-#define AR5K_EEPROM_N_XPD3_POINTS	3
-#define AR5K_EEPROM_N_INTERCEPT_10_2GHZ	35
-#define AR5K_EEPROM_N_INTERCEPT_10_5GHZ	55
-#define AR5K_EEPROM_POWER_M		0x3f
-#define AR5K_EEPROM_POWER_MIN		0
-#define AR5K_EEPROM_POWER_MAX		3150
-#define AR5K_EEPROM_POWER_STEP		50
-#define AR5K_EEPROM_POWER_TABLE_SIZE	64
-#define AR5K_EEPROM_N_POWER_LOC_11B	4
-#define AR5K_EEPROM_N_POWER_LOC_11G	6
-#define AR5K_EEPROM_I_GAIN		10
-#define AR5K_EEPROM_CCK_OFDM_DELTA	15
-#define AR5K_EEPROM_N_IQ_CAL		2
-
-/* Struct to hold EEPROM calibration data */
-struct ath5k_eeprom_info {
-	u16	ee_magic;
-	u16	ee_protect;
-	u16	ee_regdomain;
-	u16	ee_version;
-	u16	ee_header;
-	u16	ee_ant_gain;
-	u16	ee_misc0;
-	u16	ee_misc1;
-	u16	ee_cck_ofdm_gain_delta;
-	u16	ee_cck_ofdm_power_delta;
-	u16	ee_scaled_cck_delta;
-
-	/* Used for tx thermal adjustment (eeprom_init, rfregs) */
-	u16	ee_tx_clip;
-	u16	ee_pwd_84;
-	u16	ee_pwd_90;
-	u16	ee_gain_select;
-
-	/* RF Calibration settings (reset, rfregs) */
-	u16	ee_i_cal[AR5K_EEPROM_N_MODES];
-	u16	ee_q_cal[AR5K_EEPROM_N_MODES];
-	u16	ee_fixed_bias[AR5K_EEPROM_N_MODES];
-	u16	ee_turbo_max_power[AR5K_EEPROM_N_MODES];
-	u16	ee_xr_power[AR5K_EEPROM_N_MODES];
-	u16	ee_switch_settling[AR5K_EEPROM_N_MODES];
-	u16	ee_ant_tx_rx[AR5K_EEPROM_N_MODES];
-	u16	ee_ant_control[AR5K_EEPROM_N_MODES][AR5K_EEPROM_N_PCDAC];
-	u16	ee_ob[AR5K_EEPROM_N_MODES][AR5K_EEPROM_N_OBDB];
-	u16	ee_db[AR5K_EEPROM_N_MODES][AR5K_EEPROM_N_OBDB];
-	u16	ee_tx_end2xlna_enable[AR5K_EEPROM_N_MODES];
-	u16	ee_tx_end2xpa_disable[AR5K_EEPROM_N_MODES];
-	u16	ee_tx_frm2xpa_enable[AR5K_EEPROM_N_MODES];
-	u16	ee_thr_62[AR5K_EEPROM_N_MODES];
-	u16	ee_xlna_gain[AR5K_EEPROM_N_MODES];
-	u16	ee_xpd[AR5K_EEPROM_N_MODES];
-	u16	ee_x_gain[AR5K_EEPROM_N_MODES];
-	u16	ee_i_gain[AR5K_EEPROM_N_MODES];
-	u16	ee_margin_tx_rx[AR5K_EEPROM_N_MODES];
-
-	/* Unused */
-	u16	ee_false_detect[AR5K_EEPROM_N_MODES];
-	u16	ee_cal_pier[AR5K_EEPROM_N_MODES][AR5K_EEPROM_N_2GHZ_CHAN];
-	u16	ee_channel[AR5K_EEPROM_N_MODES][AR5K_EEPROM_MAX_CHAN]; /*empty*/
-
-	/* Conformance test limits (Unused) */
-	u16	ee_ctls;
-	u16	ee_ctl[AR5K_EEPROM_MAX_CTLS];
-
-	/* Noise Floor Calibration settings */
-	s16	ee_noise_floor_thr[AR5K_EEPROM_N_MODES];
-	s8	ee_adc_desired_size[AR5K_EEPROM_N_MODES];
-	s8	ee_pga_desired_size[AR5K_EEPROM_N_MODES];
-};
-
-/*
- * Internal RX/TX descriptor structures
- * (rX: reserved fields possibily used by future versions of the ar5k chipset)
- */
-
-/*
- * common hardware RX control descriptor
- */
-struct ath5k_hw_rx_ctl {
-	u32	rx_control_0; /* RX control word 0 */
-
-#define AR5K_DESC_RX_CTL0			0x00000000
-
-	u32	rx_control_1; /* RX control word 1 */
-
-#define AR5K_DESC_RX_CTL1_BUF_LEN		0x00000fff
-#define AR5K_DESC_RX_CTL1_INTREQ		0x00002000
-} __packed;
-
-/*
- * common hardware RX status descriptor
- * 5210/11 and 5212 differ only in the flags defined below
- */
-struct ath5k_hw_rx_status {
-	u32	rx_status_0; /* RX status word 0 */
-	u32	rx_status_1; /* RX status word 1 */
-} __packed;
-
-/* 5210/5211 */
-#define AR5K_5210_RX_DESC_STATUS0_DATA_LEN		0x00000fff
-#define AR5K_5210_RX_DESC_STATUS0_MORE			0x00001000
-#define AR5K_5210_RX_DESC_STATUS0_RECEIVE_RATE		0x00078000
-#define AR5K_5210_RX_DESC_STATUS0_RECEIVE_RATE_S	15
-#define AR5K_5210_RX_DESC_STATUS0_RECEIVE_SIGNAL	0x07f80000
-#define AR5K_5210_RX_DESC_STATUS0_RECEIVE_SIGNAL_S	19
-#define AR5K_5210_RX_DESC_STATUS0_RECEIVE_ANTENNA	0x38000000
-#define AR5K_5210_RX_DESC_STATUS0_RECEIVE_ANTENNA_S	27
-#define AR5K_5210_RX_DESC_STATUS1_DONE			0x00000001
-#define AR5K_5210_RX_DESC_STATUS1_FRAME_RECEIVE_OK	0x00000002
-#define AR5K_5210_RX_DESC_STATUS1_CRC_ERROR		0x00000004
-#define AR5K_5210_RX_DESC_STATUS1_FIFO_OVERRUN		0x00000008
-#define AR5K_5210_RX_DESC_STATUS1_DECRYPT_CRC_ERROR	0x00000010
-#define AR5K_5210_RX_DESC_STATUS1_PHY_ERROR		0x000000e0
-#define AR5K_5210_RX_DESC_STATUS1_PHY_ERROR_S		5
-#define AR5K_5210_RX_DESC_STATUS1_KEY_INDEX_VALID	0x00000100
-#define AR5K_5210_RX_DESC_STATUS1_KEY_INDEX		0x00007e00
-#define AR5K_5210_RX_DESC_STATUS1_KEY_INDEX_S		9
-#define AR5K_5210_RX_DESC_STATUS1_RECEIVE_TIMESTAMP	0x0fff8000
-#define AR5K_5210_RX_DESC_STATUS1_RECEIVE_TIMESTAMP_S	15
-#define AR5K_5210_RX_DESC_STATUS1_KEY_CACHE_MISS	0x10000000
-
-/* 5212 */
-#define AR5K_5212_RX_DESC_STATUS0_DATA_LEN		0x00000fff
-#define AR5K_5212_RX_DESC_STATUS0_MORE			0x00001000
-#define AR5K_5212_RX_DESC_STATUS0_DECOMP_CRC_ERROR	0x00002000
-#define AR5K_5212_RX_DESC_STATUS0_RECEIVE_RATE		0x000f8000
-#define AR5K_5212_RX_DESC_STATUS0_RECEIVE_RATE_S	15
-#define AR5K_5212_RX_DESC_STATUS0_RECEIVE_SIGNAL	0x0ff00000
-#define AR5K_5212_RX_DESC_STATUS0_RECEIVE_SIGNAL_S	20
-#define AR5K_5212_RX_DESC_STATUS0_RECEIVE_ANTENNA	0xf0000000
-#define AR5K_5212_RX_DESC_STATUS0_RECEIVE_ANTENNA_S	28
-#define AR5K_5212_RX_DESC_STATUS1_DONE			0x00000001
-#define AR5K_5212_RX_DESC_STATUS1_FRAME_RECEIVE_OK	0x00000002
-#define AR5K_5212_RX_DESC_STATUS1_CRC_ERROR		0x00000004
-#define AR5K_5212_RX_DESC_STATUS1_DECRYPT_CRC_ERROR	0x00000008
-#define AR5K_5212_RX_DESC_STATUS1_PHY_ERROR		0x00000010
-#define AR5K_5212_RX_DESC_STATUS1_MIC_ERROR		0x00000020
-#define AR5K_5212_RX_DESC_STATUS1_KEY_INDEX_VALID	0x00000100
-#define AR5K_5212_RX_DESC_STATUS1_KEY_INDEX		0x0000fe00
-#define AR5K_5212_RX_DESC_STATUS1_KEY_INDEX_S		9
-#define AR5K_5212_RX_DESC_STATUS1_RECEIVE_TIMESTAMP	0x7fff0000
-#define AR5K_5212_RX_DESC_STATUS1_RECEIVE_TIMESTAMP_S	16
-#define AR5K_5212_RX_DESC_STATUS1_KEY_CACHE_MISS	0x80000000
-
-/*
- * common hardware RX error descriptor
- */
-struct ath5k_hw_rx_error {
-	u32	rx_error_0; /* RX error word 0 */
-
-#define AR5K_RX_DESC_ERROR0			0x00000000
-
-	u32	rx_error_1; /* RX error word 1 */
-
-#define AR5K_RX_DESC_ERROR1_PHY_ERROR_CODE	0x0000ff00
-#define AR5K_RX_DESC_ERROR1_PHY_ERROR_CODE_S	8
-} __packed;
-
-#define AR5K_DESC_RX_PHY_ERROR_NONE		0x00
-#define AR5K_DESC_RX_PHY_ERROR_TIMING		0x20
-#define AR5K_DESC_RX_PHY_ERROR_PARITY		0x40
-#define AR5K_DESC_RX_PHY_ERROR_RATE		0x60
-#define AR5K_DESC_RX_PHY_ERROR_LENGTH		0x80
-#define AR5K_DESC_RX_PHY_ERROR_64QAM		0xa0
-#define AR5K_DESC_RX_PHY_ERROR_SERVICE		0xc0
-#define AR5K_DESC_RX_PHY_ERROR_TRANSMITOVR	0xe0
-
-/*
- * 5210/5211 hardware 2-word TX control descriptor
- */
-struct ath5k_hw_2w_tx_ctl {
-	u32	tx_control_0; /* TX control word 0 */
-
-#define AR5K_2W_TX_DESC_CTL0_FRAME_LEN		0x00000fff
-#define AR5K_2W_TX_DESC_CTL0_HEADER_LEN		0x0003f000 /*[5210 ?]*/
-#define AR5K_2W_TX_DESC_CTL0_HEADER_LEN_S	12
-#define AR5K_2W_TX_DESC_CTL0_XMIT_RATE		0x003c0000
-#define AR5K_2W_TX_DESC_CTL0_XMIT_RATE_S	18
-#define AR5K_2W_TX_DESC_CTL0_RTSENA		0x00400000
-#define AR5K_2W_TX_DESC_CTL0_CLRDMASK		0x01000000
-#define AR5K_2W_TX_DESC_CTL0_LONG_PACKET	0x00800000 /*[5210]*/
-#define AR5K_2W_TX_DESC_CTL0_VEOL		0x00800000 /*[5211]*/
-#define AR5K_2W_TX_DESC_CTL0_FRAME_TYPE		0x1c000000 /*[5210]*/
-#define AR5K_2W_TX_DESC_CTL0_FRAME_TYPE_S	26
-#define AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT_5210	0x02000000
-#define AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT_5211	0x1e000000
-#define AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT	(ah->ah_version == AR5K_AR5210 ? \
-						AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT_5210 : \
-						AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT_5211)
-#define AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT_S	25
-#define AR5K_2W_TX_DESC_CTL0_INTREQ		0x20000000
-#define AR5K_2W_TX_DESC_CTL0_ENCRYPT_KEY_VALID	0x40000000
-
-	u32	tx_control_1; /* TX control word 1 */
-
-#define AR5K_2W_TX_DESC_CTL1_BUF_LEN		0x00000fff
-#define AR5K_2W_TX_DESC_CTL1_MORE		0x00001000
-#define AR5K_2W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX_5210	0x0007e000
-#define AR5K_2W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX_5211	0x000fe000
-#define AR5K_2W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX	(ah->ah_version == AR5K_AR5210 ? \
-						AR5K_2W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX_5210 : \
-						AR5K_2W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX_5211)
-#define AR5K_2W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX_S	13
-#define AR5K_2W_TX_DESC_CTL1_FRAME_TYPE		0x00700000 /*[5211]*/
-#define AR5K_2W_TX_DESC_CTL1_FRAME_TYPE_S	20
-#define AR5K_2W_TX_DESC_CTL1_NOACK		0x00800000 /*[5211]*/
-#define AR5K_2W_TX_DESC_CTL1_RTS_DURATION	0xfff80000 /*[5210 ?]*/
-} __packed;
-
-#define AR5K_AR5210_TX_DESC_FRAME_TYPE_NORMAL   0x00
-#define AR5K_AR5210_TX_DESC_FRAME_TYPE_ATIM     0x04
-#define AR5K_AR5210_TX_DESC_FRAME_TYPE_PSPOLL   0x08
-#define AR5K_AR5210_TX_DESC_FRAME_TYPE_NO_DELAY 0x0c
-#define AR5K_AR5210_TX_DESC_FRAME_TYPE_PIFS     0x10
-
-/*
- * 5212 hardware 4-word TX control descriptor
- */
-struct ath5k_hw_4w_tx_ctl {
-	u32	tx_control_0; /* TX control word 0 */
-
-#define AR5K_4W_TX_DESC_CTL0_FRAME_LEN		0x00000fff
-#define AR5K_4W_TX_DESC_CTL0_XMIT_POWER		0x003f0000
-#define AR5K_4W_TX_DESC_CTL0_XMIT_POWER_S	16
-#define AR5K_4W_TX_DESC_CTL0_RTSENA		0x00400000
-#define AR5K_4W_TX_DESC_CTL0_VEOL		0x00800000
-#define AR5K_4W_TX_DESC_CTL0_CLRDMASK		0x01000000
-#define AR5K_4W_TX_DESC_CTL0_ANT_MODE_XMIT	0x1e000000
-#define AR5K_4W_TX_DESC_CTL0_ANT_MODE_XMIT_S	25
-#define AR5K_4W_TX_DESC_CTL0_INTREQ		0x20000000
-#define AR5K_4W_TX_DESC_CTL0_ENCRYPT_KEY_VALID	0x40000000
-#define AR5K_4W_TX_DESC_CTL0_CTSENA		0x80000000
-
-	u32	tx_control_1; /* TX control word 1 */
-
-#define AR5K_4W_TX_DESC_CTL1_BUF_LEN		0x00000fff
-#define AR5K_4W_TX_DESC_CTL1_MORE		0x00001000
-#define AR5K_4W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX	0x000fe000
-#define AR5K_4W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX_S	13
-#define AR5K_4W_TX_DESC_CTL1_FRAME_TYPE		0x00f00000
-#define AR5K_4W_TX_DESC_CTL1_FRAME_TYPE_S	20
-#define AR5K_4W_TX_DESC_CTL1_NOACK		0x01000000
-#define AR5K_4W_TX_DESC_CTL1_COMP_PROC		0x06000000
-#define AR5K_4W_TX_DESC_CTL1_COMP_PROC_S	25
-#define AR5K_4W_TX_DESC_CTL1_COMP_IV_LEN	0x18000000
-#define AR5K_4W_TX_DESC_CTL1_COMP_IV_LEN_S	27
-#define AR5K_4W_TX_DESC_CTL1_COMP_ICV_LEN	0x60000000
-#define AR5K_4W_TX_DESC_CTL1_COMP_ICV_LEN_S	29
-
-	u32	tx_control_2; /* TX control word 2 */
-
-#define AR5K_4W_TX_DESC_CTL2_RTS_DURATION		0x00007fff
-#define AR5K_4W_TX_DESC_CTL2_DURATION_UPDATE_ENABLE	0x00008000
-#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES0		0x000f0000
-#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES0_S		16
-#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES1		0x00f00000
-#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES1_S		20
-#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES2		0x0f000000
-#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES2_S		24
-#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES3		0xf0000000
-#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES3_S		28
-
-	u32	tx_control_3; /* TX control word 3 */
-
-#define AR5K_4W_TX_DESC_CTL3_XMIT_RATE0		0x0000001f
-#define AR5K_4W_TX_DESC_CTL3_XMIT_RATE1		0x000003e0
-#define AR5K_4W_TX_DESC_CTL3_XMIT_RATE1_S	5
-#define AR5K_4W_TX_DESC_CTL3_XMIT_RATE2		0x00007c00
-#define AR5K_4W_TX_DESC_CTL3_XMIT_RATE2_S	10
-#define AR5K_4W_TX_DESC_CTL3_XMIT_RATE3		0x000f8000
-#define AR5K_4W_TX_DESC_CTL3_XMIT_RATE3_S	15
-#define AR5K_4W_TX_DESC_CTL3_RTS_CTS_RATE	0x01f00000
-#define AR5K_4W_TX_DESC_CTL3_RTS_CTS_RATE_S	20
-} __packed;
-
-/*
- * Common TX status descriptor
- */
-struct ath5k_hw_tx_status {
-	u32	tx_status_0; /* TX status word 0 */
-
-#define AR5K_DESC_TX_STATUS0_FRAME_XMIT_OK	0x00000001
-#define AR5K_DESC_TX_STATUS0_EXCESSIVE_RETRIES	0x00000002
-#define AR5K_DESC_TX_STATUS0_FIFO_UNDERRUN	0x00000004
-#define AR5K_DESC_TX_STATUS0_FILTERED		0x00000008
-/*???
-#define AR5K_DESC_TX_STATUS0_RTS_FAIL_COUNT	0x000000f0
-#define AR5K_DESC_TX_STATUS0_RTS_FAIL_COUNT_S	4
-*/
-#define AR5K_DESC_TX_STATUS0_SHORT_RETRY_COUNT	0x000000f0
-#define AR5K_DESC_TX_STATUS0_SHORT_RETRY_COUNT_S	4
-/*???
-#define AR5K_DESC_TX_STATUS0_DATA_FAIL_COUNT	0x00000f00
-#define AR5K_DESC_TX_STATUS0_DATA_FAIL_COUNT_S	8
-*/
-#define AR5K_DESC_TX_STATUS0_LONG_RETRY_COUNT	0x00000f00
-#define AR5K_DESC_TX_STATUS0_LONG_RETRY_COUNT_S	8
-#define AR5K_DESC_TX_STATUS0_VIRT_COLL_COUNT	0x0000f000
-#define AR5K_DESC_TX_STATUS0_VIRT_COLL_COUNT_S	12
-#define AR5K_DESC_TX_STATUS0_SEND_TIMESTAMP	0xffff0000
-#define AR5K_DESC_TX_STATUS0_SEND_TIMESTAMP_S	16
-
-	u32	tx_status_1; /* TX status word 1 */
-
-#define AR5K_DESC_TX_STATUS1_DONE		0x00000001
-#define AR5K_DESC_TX_STATUS1_SEQ_NUM		0x00001ffe
-#define AR5K_DESC_TX_STATUS1_SEQ_NUM_S		1
-#define AR5K_DESC_TX_STATUS1_ACK_SIG_STRENGTH	0x001fe000
-#define AR5K_DESC_TX_STATUS1_ACK_SIG_STRENGTH_S	13
-#define AR5K_DESC_TX_STATUS1_FINAL_TS_INDEX	0x00600000
-#define AR5K_DESC_TX_STATUS1_FINAL_TS_INDEX_S	21
-#define AR5K_DESC_TX_STATUS1_COMP_SUCCESS	0x00800000
-#define AR5K_DESC_TX_STATUS1_XMIT_ANTENNA	0x01000000
-} __packed;
-
-
-/*
- * 5210/5211 hardware TX descriptor
- */
-struct ath5k_hw_5210_tx_desc {
-	struct ath5k_hw_2w_tx_ctl	tx_ctl;
-	struct ath5k_hw_tx_status	tx_stat;
-} __packed;
-
-/*
- * 5212 hardware TX descriptor
- */
-struct ath5k_hw_5212_tx_desc {
-	struct ath5k_hw_4w_tx_ctl	tx_ctl;
-	struct ath5k_hw_tx_status	tx_stat;
-} __packed;
-
-/*
- * common hardware RX descriptor
- */
-struct ath5k_hw_all_rx_desc {
-	struct ath5k_hw_rx_ctl			rx_ctl;
-	union {
-		struct ath5k_hw_rx_status	rx_stat;
-		struct ath5k_hw_rx_error	rx_err;
-	} u;
-} __packed;
-
-
-/*
- * AR5K REGISTER ACCESS
- */
-
-/*Swap RX/TX Descriptor for big endian archs*/
-#if defined(__BIG_ENDIAN)
-#define AR5K_INIT_CFG	(		\
-	AR5K_CFG_SWTD | AR5K_CFG_SWRD	\
-)
-#else
-#define AR5K_INIT_CFG	0x00000000
-#endif
-
-/*#define AR5K_REG_READ(_reg)	ath5k_hw_reg_read(ah, _reg)
-
-#define AR5K_REG_WRITE(_reg, _val)	ath5k_hw_reg_write(ah, _val, _reg)*/
-
-#define AR5K_REG_SM(_val, _flags)					\
-	(((_val) << _flags##_S) & (_flags))
-
-#define AR5K_REG_MS(_val, _flags)					\
-	(((_val) & (_flags)) >> _flags##_S)
-
-/* Some registers can hold multiple values of interest. For this
- * reason when we want to write to these registers we must first
- * retrieve the values which we do not want to clear (lets call this
- * old_data) and then set the register with this and our new_value:
- * ( old_data | new_value) */
-#define AR5K_REG_WRITE_BITS(ah, _reg, _flags, _val)			\
-	ath5k_hw_reg_write(ah, (ath5k_hw_reg_read(ah, _reg) & ~(_flags)) | \
-	    (((_val) << _flags##_S) & (_flags)), _reg)
-
-#define AR5K_REG_MASKED_BITS(ah, _reg, _flags, _mask)			\
-	ath5k_hw_reg_write(ah, (ath5k_hw_reg_read(ah, _reg) &		\
-			(_mask)) | (_flags), _reg)
-
-#define AR5K_REG_ENABLE_BITS(ah, _reg, _flags)				\
-	ath5k_hw_reg_write(ah, ath5k_hw_reg_read(ah, _reg) | (_flags), _reg)
-
-#define AR5K_REG_DISABLE_BITS(ah, _reg, _flags)			\
-	ath5k_hw_reg_write(ah, ath5k_hw_reg_read(ah, _reg) & ~(_flags), _reg)
-
-#define AR5K_PHY_WRITE(ah, _reg, _val)					\
-	ath5k_hw_reg_write(ah, _val, (ah)->ah_phy + ((_reg) << 2))
-
-#define AR5K_PHY_READ(ah, _reg)					\
-	ath5k_hw_reg_read(ah, (ah)->ah_phy + ((_reg) << 2))
-
-#define AR5K_REG_WAIT(_i) do {						\
-	if (_i % 64)							\
-		udelay(1);						\
-} while (0)
-
-#define AR5K_EEPROM_READ(_o, _v) do {					\
-	if ((ret = ath5k_hw_eeprom_read(ah, (_o), &(_v))) != 0)	\
-		return (ret);						\
-} while (0)
-
-#define AR5K_EEPROM_READ_HDR(_o, _v)					\
-	AR5K_EEPROM_READ(_o, ah->ah_capabilities.cap_eeprom._v);	\
-
-/* Read status of selected queue */
-#define AR5K_REG_READ_Q(ah, _reg, _queue)				\
-	(ath5k_hw_reg_read(ah, _reg) & (1 << _queue))			\
-
-#define AR5K_REG_WRITE_Q(ah, _reg, _queue)				\
-	ath5k_hw_reg_write(ah, (1 << _queue), _reg)
-
-#define AR5K_Q_ENABLE_BITS(_reg, _queue) do {				\
-	_reg |= 1 << _queue;						\
-} while (0)
-
-#define AR5K_Q_DISABLE_BITS(_reg, _queue) do {				\
-	_reg &= ~(1 << _queue);						\
-} while (0)
-
-#define AR5K_LOW_ID(_a)(				\
-(_a)[0] | (_a)[1] << 8 | (_a)[2] << 16 | (_a)[3] << 24	\
-)
-
-#define AR5K_HIGH_ID(_a)	((_a)[4] | (_a)[5] << 8)
-
-/*
- * Initial register values
- */
-
-/*
- * Common initial register values
- */
-#define AR5K_INIT_MODE				CHANNEL_B
-
-#define AR5K_INIT_TX_LATENCY			502
-#define AR5K_INIT_USEC				39
-#define AR5K_INIT_USEC_TURBO			79
-#define AR5K_INIT_USEC_32			31
-#define AR5K_INIT_CARR_SENSE_EN			1
-#define AR5K_INIT_PROG_IFS			920
-#define AR5K_INIT_PROG_IFS_TURBO		960
-#define AR5K_INIT_EIFS				3440
-#define AR5K_INIT_EIFS_TURBO			6880
-#define AR5K_INIT_SLOT_TIME			396
-#define AR5K_INIT_SLOT_TIME_TURBO		480
-#define AR5K_INIT_ACK_CTS_TIMEOUT		1024
-#define AR5K_INIT_ACK_CTS_TIMEOUT_TURBO		0x08000800
-#define AR5K_INIT_SIFS				560
-#define AR5K_INIT_SIFS_TURBO			480
-#define AR5K_INIT_SH_RETRY			10
-#define AR5K_INIT_LG_RETRY			AR5K_INIT_SH_RETRY
-#define AR5K_INIT_SSH_RETRY			32
-#define AR5K_INIT_SLG_RETRY			AR5K_INIT_SSH_RETRY
-#define AR5K_INIT_TX_RETRY			10
-#define AR5K_INIT_TOPS				8
-#define AR5K_INIT_RXNOFRM			8
-#define AR5K_INIT_RPGTO				0
-#define AR5K_INIT_TXNOFRM			0
-#define AR5K_INIT_BEACON_PERIOD			65535
-#define AR5K_INIT_TIM_OFFSET			0
-#define AR5K_INIT_BEACON_EN			0
-#define AR5K_INIT_RESET_TSF			0
-
-#define AR5K_INIT_TRANSMIT_LATENCY		(			\
-	(AR5K_INIT_TX_LATENCY << 14) | (AR5K_INIT_USEC_32 << 7) |	\
-	(AR5K_INIT_USEC)						\
-)
-#define AR5K_INIT_TRANSMIT_LATENCY_TURBO	(			\
-	(AR5K_INIT_TX_LATENCY << 14) | (AR5K_INIT_USEC_32 << 7) |	\
-	(AR5K_INIT_USEC_TURBO)						\
-)
-#define AR5K_INIT_PROTO_TIME_CNTRL		(			\
-	(AR5K_INIT_CARR_SENSE_EN << 26) | (AR5K_INIT_EIFS << 12) |	\
-	(AR5K_INIT_PROG_IFS)						\
-)
-#define AR5K_INIT_PROTO_TIME_CNTRL_TURBO	(			\
-	(AR5K_INIT_CARR_SENSE_EN << 26) | (AR5K_INIT_EIFS_TURBO << 12) | \
-	(AR5K_INIT_PROG_IFS_TURBO)					\
-)
-#define AR5K_INIT_BEACON_CONTROL		(			\
-	(AR5K_INIT_RESET_TSF << 24) | (AR5K_INIT_BEACON_EN << 23) |	\
-	(AR5K_INIT_TIM_OFFSET << 16) | (AR5K_INIT_BEACON_PERIOD)	\
-)
-
-/*
- * Non-common initial register values which have to be loaded into the
- * card at boot time and after each reset.
- */
-
-/* Register dumps are done per operation mode */
-#define AR5K_INI_RFGAIN_5GHZ		0
-#define AR5K_INI_RFGAIN_2GHZ		1
-
-#define AR5K_INI_VAL_11A		0
-#define AR5K_INI_VAL_11A_TURBO		1
-#define AR5K_INI_VAL_11B		2
-#define AR5K_INI_VAL_11G		3
-#define AR5K_INI_VAL_11G_TURBO		4
-#define AR5K_INI_VAL_XR			0
-#define AR5K_INI_VAL_MAX		5
-
-#define AR5K_RF5111_INI_RF_MAX_BANKS	AR5K_MAX_RF_BANKS
-#define AR5K_RF5112_INI_RF_MAX_BANKS	AR5K_MAX_RF_BANKS
-
-static inline u32 ath5k_hw_bitswap(u32 val, unsigned int bits)
-{
-	u32 retval = 0, bit, i;
-
-	for (i = 0; i < bits; i++) {
-		bit = (val >> i) & 1;
-		retval = (retval << 1) | bit;
-	}
-
-	return retval;
-}
diff --git a/drivers/net/wireless/ath5k/initvals.c b/drivers/net/wireless/ath5k/initvals.c
index 2806b21..ea2e1a2 100644
--- a/drivers/net/wireless/ath5k/initvals.c
+++ b/drivers/net/wireless/ath5k/initvals.c
@@ -1,9 +1,9 @@
 /*
  * Initial register settings functions
  *
- * Copyright (c) 2004, 2005, 2006, 2007 Reyk Floeter <reyk@openbsd.org>
- * Copyright (c) 2006, 2007 Nick Kossifidis <mickflemm@gmail.com>
- * Copyright (c) 2007 Jiri Slaby <jirislaby@gmail.com>
+ * Copyright (c) 2004-2007 Reyk Floeter <reyk@openbsd.org>
+ * Copyright (c) 2006-2007 Nick Kossifidis <mickflemm@gmail.com>
+ * Copyright (c) 2007-2008 Jiri Slaby <jirislaby@gmail.com>
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -20,13 +20,9 @@
  */
 
 #include "ath5k.h"
-#include "base.h"
 #include "reg.h"
-
-/*
- * MAC/PHY REGISTERS
- */
-
+#include "debug.h"
+#include "base.h"
 
 /*
  * Mode-independent initial register writes
@@ -65,10 +61,10 @@
 	{ AR5K_TXCFG,		AR5K_DMASIZE_128B },
 	{ AR5K_RXCFG,		AR5K_DMASIZE_128B },
 	{ AR5K_CFG,		AR5K_INIT_CFG },
-	{ AR5K_TOPS,		AR5K_INIT_TOPS },
-	{ AR5K_RXNOFRM,		AR5K_INIT_RXNOFRM },
-	{ AR5K_RPGTO,		AR5K_INIT_RPGTO },
-	{ AR5K_TXNOFRM,		AR5K_INIT_TXNOFRM },
+	{ AR5K_TOPS,		8 },
+	{ AR5K_RXNOFRM,		8 },
+	{ AR5K_RPGTO,		0 },
+	{ AR5K_TXNOFRM,		0 },
 	{ AR5K_SFR,		0 },
 	{ AR5K_MIBC,		0 },
 	{ AR5K_MISC,		0 },
diff --git a/drivers/net/wireless/ath5k/pcu.c b/drivers/net/wireless/ath5k/pcu.c
new file mode 100644
index 0000000..a47df9a
--- /dev/null
+++ b/drivers/net/wireless/ath5k/pcu.c
@@ -0,0 +1,1014 @@
+/*
+ * Copyright (c) 2004-2008 Reyk Floeter <reyk@openbsd.org>
+ * Copyright (c) 2006-2008 Nick Kossifidis <mickflemm@gmail.com>
+ * Copyright (c) 2007-2008 Matthew W. S. Bell  <mentor@madwifi.org>
+ * Copyright (c) 2007-2008 Luis Rodriguez <mcgrof@winlab.rutgers.edu>
+ * Copyright (c) 2007-2008 Pavel Roskin <proski@gnu.org>
+ * Copyright (c) 2007-2008 Jiri Slaby <jirislaby@gmail.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+/*********************************\
+* Protocol Control Unit Functions *
+\*********************************/
+
+#include "ath5k.h"
+#include "reg.h"
+#include "debug.h"
+#include "base.h"
+
+/*******************\
+* Generic functions *
+\*******************/
+
+/**
+ * ath5k_hw_set_opmode - Set PCU operating mode
+ *
+ * @ah: The &struct ath5k_hw
+ *
+ * Initialize PCU for the various operating modes (AP/STA etc)
+ *
+ * NOTE: ah->ah_op_mode must be set before calling this.
+ */
+int ath5k_hw_set_opmode(struct ath5k_hw *ah)
+{
+	u32 pcu_reg, beacon_reg, low_id, high_id;
+
+	pcu_reg = 0;
+	beacon_reg = 0;
+
+	ATH5K_TRACE(ah->ah_sc);
+
+	switch (ah->ah_op_mode) {
+	case NL80211_IFTYPE_ADHOC:
+		pcu_reg |= AR5K_STA_ID1_ADHOC | AR5K_STA_ID1_DESC_ANTENNA |
+			(ah->ah_version == AR5K_AR5210 ?
+				AR5K_STA_ID1_NO_PSPOLL : 0);
+		beacon_reg |= AR5K_BCR_ADHOC;
+		break;
+
+	case NL80211_IFTYPE_AP:
+	case NL80211_IFTYPE_MESH_POINT:
+		pcu_reg |= AR5K_STA_ID1_AP | AR5K_STA_ID1_RTS_DEF_ANTENNA |
+			(ah->ah_version == AR5K_AR5210 ?
+				AR5K_STA_ID1_NO_PSPOLL : 0);
+		beacon_reg |= AR5K_BCR_AP;
+		break;
+
+	case NL80211_IFTYPE_STATION:
+		pcu_reg |= AR5K_STA_ID1_DEFAULT_ANTENNA |
+			(ah->ah_version == AR5K_AR5210 ?
+				AR5K_STA_ID1_PWR_SV : 0);
+	case NL80211_IFTYPE_MONITOR:
+		pcu_reg |= AR5K_STA_ID1_DEFAULT_ANTENNA |
+			(ah->ah_version == AR5K_AR5210 ?
+				AR5K_STA_ID1_NO_PSPOLL : 0);
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	/*
+	 * Set PCU registers
+	 */
+	low_id = AR5K_LOW_ID(ah->ah_sta_id);
+	high_id = AR5K_HIGH_ID(ah->ah_sta_id);
+	ath5k_hw_reg_write(ah, low_id, AR5K_STA_ID0);
+	ath5k_hw_reg_write(ah, pcu_reg | high_id, AR5K_STA_ID1);
+
+	/*
+	 * Set Beacon Control Register on 5210
+	 */
+	if (ah->ah_version == AR5K_AR5210)
+		ath5k_hw_reg_write(ah, beacon_reg, AR5K_BCR);
+
+	return 0;
+}
+
+/**
+ * ath5k_hw_update - Update mib counters (mac layer statistics)
+ *
+ * @ah: The &struct ath5k_hw
+ * @stats: The &struct ieee80211_low_level_stats we use to track
+ * statistics on the driver
+ *
+ * Reads MIB counters from PCU and updates sw statistics. Must be
+ * called after a MIB interrupt.
+ */
+void ath5k_hw_update_mib_counters(struct ath5k_hw *ah,
+		struct ieee80211_low_level_stats  *stats)
+{
+	ATH5K_TRACE(ah->ah_sc);
+
+	/* Read-And-Clear */
+	stats->dot11ACKFailureCount += ath5k_hw_reg_read(ah, AR5K_ACK_FAIL);
+	stats->dot11RTSFailureCount += ath5k_hw_reg_read(ah, AR5K_RTS_FAIL);
+	stats->dot11RTSSuccessCount += ath5k_hw_reg_read(ah, AR5K_RTS_OK);
+	stats->dot11FCSErrorCount += ath5k_hw_reg_read(ah, AR5K_FCS_FAIL);
+
+	/* XXX: Should we use this to track beacon count ?
+	 * -we read it anyway to clear the register */
+	ath5k_hw_reg_read(ah, AR5K_BEACON_CNT);
+
+	/* Reset profile count registers on 5212*/
+	if (ah->ah_version == AR5K_AR5212) {
+		ath5k_hw_reg_write(ah, 0, AR5K_PROFCNT_TX);
+		ath5k_hw_reg_write(ah, 0, AR5K_PROFCNT_RX);
+		ath5k_hw_reg_write(ah, 0, AR5K_PROFCNT_RXCLR);
+		ath5k_hw_reg_write(ah, 0, AR5K_PROFCNT_CYCLE);
+	}
+}
+
+/**
+ * ath5k_hw_set_ack_bitrate - set bitrate for ACKs
+ *
+ * @ah: The &struct ath5k_hw
+ * @high: Flag to determine if we want to use high transmition rate
+ * for ACKs or not
+ *
+ * If high flag is set, we tell hw to use a set of control rates based on
+ * the current transmition rate (check out control_rates array inside reset.c).
+ * If not hw just uses the lowest rate available for the current modulation
+ * scheme being used (1Mbit for CCK and 6Mbits for OFDM).
+ */
+void ath5k_hw_set_ack_bitrate_high(struct ath5k_hw *ah, bool high)
+{
+	if (ah->ah_version != AR5K_AR5212)
+		return;
+	else {
+		u32 val = AR5K_STA_ID1_BASE_RATE_11B | AR5K_STA_ID1_ACKCTS_6MB;
+		if (high)
+			AR5K_REG_ENABLE_BITS(ah, AR5K_STA_ID1, val);
+		else
+			AR5K_REG_DISABLE_BITS(ah, AR5K_STA_ID1, val);
+	}
+}
+
+
+/******************\
+* ACK/CTS Timeouts *
+\******************/
+
+/**
+ * ath5k_hw_het_ack_timeout - Get ACK timeout from PCU in usec
+ *
+ * @ah: The &struct ath5k_hw
+ */
+unsigned int ath5k_hw_get_ack_timeout(struct ath5k_hw *ah)
+{
+	ATH5K_TRACE(ah->ah_sc);
+
+	return ath5k_hw_clocktoh(AR5K_REG_MS(ath5k_hw_reg_read(ah,
+			AR5K_TIME_OUT), AR5K_TIME_OUT_ACK), ah->ah_turbo);
+}
+
+/**
+ * ath5k_hw_set_ack_timeout - Set ACK timeout on PCU
+ *
+ * @ah: The &struct ath5k_hw
+ * @timeout: Timeout in usec
+ */
+int ath5k_hw_set_ack_timeout(struct ath5k_hw *ah, unsigned int timeout)
+{
+	ATH5K_TRACE(ah->ah_sc);
+	if (ath5k_hw_clocktoh(AR5K_REG_MS(0xffffffff, AR5K_TIME_OUT_ACK),
+			ah->ah_turbo) <= timeout)
+		return -EINVAL;
+
+	AR5K_REG_WRITE_BITS(ah, AR5K_TIME_OUT, AR5K_TIME_OUT_ACK,
+		ath5k_hw_htoclock(timeout, ah->ah_turbo));
+
+	return 0;
+}
+
+/**
+ * ath5k_hw_get_cts_timeout - Get CTS timeout from PCU in usec
+ *
+ * @ah: The &struct ath5k_hw
+ */
+unsigned int ath5k_hw_get_cts_timeout(struct ath5k_hw *ah)
+{
+	ATH5K_TRACE(ah->ah_sc);
+	return ath5k_hw_clocktoh(AR5K_REG_MS(ath5k_hw_reg_read(ah,
+			AR5K_TIME_OUT), AR5K_TIME_OUT_CTS), ah->ah_turbo);
+}
+
+/**
+ * ath5k_hw_set_cts_timeout - Set CTS timeout on PCU
+ *
+ * @ah: The &struct ath5k_hw
+ * @timeout: Timeout in usec
+ */
+int ath5k_hw_set_cts_timeout(struct ath5k_hw *ah, unsigned int timeout)
+{
+	ATH5K_TRACE(ah->ah_sc);
+	if (ath5k_hw_clocktoh(AR5K_REG_MS(0xffffffff, AR5K_TIME_OUT_CTS),
+			ah->ah_turbo) <= timeout)
+		return -EINVAL;
+
+	AR5K_REG_WRITE_BITS(ah, AR5K_TIME_OUT, AR5K_TIME_OUT_CTS,
+			ath5k_hw_htoclock(timeout, ah->ah_turbo));
+
+	return 0;
+}
+
+
+/****************\
+* BSSID handling *
+\****************/
+
+/**
+ * ath5k_hw_get_lladdr - Get station id
+ *
+ * @ah: The &struct ath5k_hw
+ * @mac: The card's mac address
+ *
+ * Initialize ah->ah_sta_id using the mac address provided
+ * (just a memcpy).
+ *
+ * TODO: Remove it once we merge ath5k_softc and ath5k_hw
+ */
+void ath5k_hw_get_lladdr(struct ath5k_hw *ah, u8 *mac)
+{
+	ATH5K_TRACE(ah->ah_sc);
+	memcpy(mac, ah->ah_sta_id, ETH_ALEN);
+}
+
+/**
+ * ath5k_hw_set_lladdr - Set station id
+ *
+ * @ah: The &struct ath5k_hw
+ * @mac: The card's mac address
+ *
+ * Set station id on hw using the provided mac address
+ */
+int ath5k_hw_set_lladdr(struct ath5k_hw *ah, const u8 *mac)
+{
+	u32 low_id, high_id;
+
+	ATH5K_TRACE(ah->ah_sc);
+	/* Set new station ID */
+	memcpy(ah->ah_sta_id, mac, ETH_ALEN);
+
+	low_id = AR5K_LOW_ID(mac);
+	high_id = AR5K_HIGH_ID(mac);
+
+	ath5k_hw_reg_write(ah, low_id, AR5K_STA_ID0);
+	ath5k_hw_reg_write(ah, high_id, AR5K_STA_ID1);
+
+	return 0;
+}
+
+/**
+ * ath5k_hw_set_associd - Set BSSID for association
+ *
+ * @ah: The &struct ath5k_hw
+ * @bssid: BSSID
+ * @assoc_id: Assoc id
+ *
+ * Sets the BSSID which trigers the "SME Join" operation
+ */
+void ath5k_hw_set_associd(struct ath5k_hw *ah, const u8 *bssid, u16 assoc_id)
+{
+	u32 low_id, high_id;
+	u16 tim_offset = 0;
+
+	/*
+	 * Set simple BSSID mask on 5212
+	 */
+	if (ah->ah_version == AR5K_AR5212) {
+		ath5k_hw_reg_write(ah, 0xffffffff, AR5K_BSS_IDM0);
+		ath5k_hw_reg_write(ah, 0xffffffff, AR5K_BSS_IDM1);
+	}
+
+	/*
+	 * Set BSSID which triggers the "SME Join" operation
+	 */
+	low_id = AR5K_LOW_ID(bssid);
+	high_id = AR5K_HIGH_ID(bssid);
+	ath5k_hw_reg_write(ah, low_id, AR5K_BSS_ID0);
+	ath5k_hw_reg_write(ah, high_id | ((assoc_id & 0x3fff) <<
+				AR5K_BSS_ID1_AID_S), AR5K_BSS_ID1);
+
+	if (assoc_id == 0) {
+		ath5k_hw_disable_pspoll(ah);
+		return;
+	}
+
+	AR5K_REG_WRITE_BITS(ah, AR5K_BEACON, AR5K_BEACON_TIM,
+			tim_offset ? tim_offset + 4 : 0);
+
+	ath5k_hw_enable_pspoll(ah, NULL, 0);
+}
+
+/**
+ * ath5k_hw_set_bssid_mask - filter out bssids we listen
+ *
+ * @ah: the &struct ath5k_hw
+ * @mask: the bssid_mask, a u8 array of size ETH_ALEN
+ *
+ * BSSID masking is a method used by AR5212 and newer hardware to inform PCU
+ * which bits of the interface's MAC address should be looked at when trying
+ * to decide which packets to ACK. In station mode and AP mode with a single
+ * BSS every bit matters since we lock to only one BSS. In AP mode with
+ * multiple BSSes (virtual interfaces) not every bit matters because hw must
+ * accept frames for all BSSes and so we tweak some bits of our mac address
+ * in order to have multiple BSSes.
+ *
+ * NOTE: This is a simple filter and does *not* filter out all
+ * relevant frames. Some frames that are not for us might get ACKed from us
+ * by PCU because they just match the mask.
+ *
+ * When handling multiple BSSes you can get the BSSID mask by computing the
+ * set of  ~ ( MAC XOR BSSID ) for all bssids we handle.
+ *
+ * When you do this you are essentially computing the common bits of all your
+ * BSSes. Later it is assumed the harware will "and" (&) the BSSID mask with
+ * the MAC address to obtain the relevant bits and compare the result with
+ * (frame's BSSID & mask) to see if they match.
+ */
+/*
+ * Simple example: on your card you have have two BSSes you have created with
+ * BSSID-01 and BSSID-02. Lets assume BSSID-01 will not use the MAC address.
+ * There is another BSSID-03 but you are not part of it. For simplicity's sake,
+ * assuming only 4 bits for a mac address and for BSSIDs you can then have:
+ *
+ *                  \
+ * MAC:                0001 |
+ * BSSID-01:   0100 | --> Belongs to us
+ * BSSID-02:   1001 |
+ *                  /
+ * -------------------
+ * BSSID-03:   0110  | --> External
+ * -------------------
+ *
+ * Our bssid_mask would then be:
+ *
+ *             On loop iteration for BSSID-01:
+ *             ~(0001 ^ 0100)  -> ~(0101)
+ *                             ->   1010
+ *             bssid_mask      =    1010
+ *
+ *             On loop iteration for BSSID-02:
+ *             bssid_mask &= ~(0001   ^   1001)
+ *             bssid_mask =   (1010)  & ~(0001 ^ 1001)
+ *             bssid_mask =   (1010)  & ~(1001)
+ *             bssid_mask =   (1010)  &  (0110)
+ *             bssid_mask =   0010
+ *
+ * A bssid_mask of 0010 means "only pay attention to the second least
+ * significant bit". This is because its the only bit common
+ * amongst the MAC and all BSSIDs we support. To findout what the real
+ * common bit is we can simply "&" the bssid_mask now with any BSSID we have
+ * or our MAC address (we assume the hardware uses the MAC address).
+ *
+ * Now, suppose there's an incoming frame for BSSID-03:
+ *
+ * IFRAME-01:  0110
+ *
+ * An easy eye-inspeciton of this already should tell you that this frame
+ * will not pass our check. This is beacuse the bssid_mask tells the
+ * hardware to only look at the second least significant bit and the
+ * common bit amongst the MAC and BSSIDs is 0, this frame has the 2nd LSB
+ * as 1, which does not match 0.
+ *
+ * So with IFRAME-01 we *assume* the hardware will do:
+ *
+ *     allow = (IFRAME-01 & bssid_mask) == (bssid_mask & MAC) ? 1 : 0;
+ *  --> allow = (0110 & 0010) == (0010 & 0001) ? 1 : 0;
+ *  --> allow = (0010) == 0000 ? 1 : 0;
+ *  --> allow = 0
+ *
+ *  Lets now test a frame that should work:
+ *
+ * IFRAME-02:  0001 (we should allow)
+ *
+ *     allow = (0001 & 1010) == 1010
+ *
+ *     allow = (IFRAME-02 & bssid_mask) == (bssid_mask & MAC) ? 1 : 0;
+ *  --> allow = (0001 & 0010) ==  (0010 & 0001) ? 1 :0;
+ *  --> allow = (0010) == (0010)
+ *  --> allow = 1
+ *
+ * Other examples:
+ *
+ * IFRAME-03:  0100 --> allowed
+ * IFRAME-04:  1001 --> allowed
+ * IFRAME-05:  1101 --> allowed but its not for us!!!
+ *
+ */
+int ath5k_hw_set_bssid_mask(struct ath5k_hw *ah, const u8 *mask)
+{
+	u32 low_id, high_id;
+	ATH5K_TRACE(ah->ah_sc);
+
+	if (ah->ah_version == AR5K_AR5212) {
+		low_id = AR5K_LOW_ID(mask);
+		high_id = AR5K_HIGH_ID(mask);
+
+		ath5k_hw_reg_write(ah, low_id, AR5K_BSS_IDM0);
+		ath5k_hw_reg_write(ah, high_id, AR5K_BSS_IDM1);
+
+		return 0;
+	}
+
+	return -EIO;
+}
+
+
+/************\
+* RX Control *
+\************/
+
+/**
+ * ath5k_hw_start_rx_pcu - Start RX engine
+ *
+ * @ah: The &struct ath5k_hw
+ *
+ * Starts RX engine on PCU so that hw can process RXed frames
+ * (ACK etc).
+ *
+ * NOTE: RX DMA should be already enabled using ath5k_hw_start_rx_dma
+ * TODO: Init ANI here
+ */
+void ath5k_hw_start_rx_pcu(struct ath5k_hw *ah)
+{
+	ATH5K_TRACE(ah->ah_sc);
+	AR5K_REG_DISABLE_BITS(ah, AR5K_DIAG_SW, AR5K_DIAG_SW_DIS_RX);
+}
+
+/**
+ * at5k_hw_stop_rx_pcu - Stop RX engine
+ *
+ * @ah: The &struct ath5k_hw
+ *
+ * Stops RX engine on PCU
+ *
+ * TODO: Detach ANI here
+ */
+void ath5k_hw_stop_rx_pcu(struct ath5k_hw *ah)
+{
+	ATH5K_TRACE(ah->ah_sc);
+	AR5K_REG_ENABLE_BITS(ah, AR5K_DIAG_SW, AR5K_DIAG_SW_DIS_RX);
+}
+
+/*
+ * Set multicast filter
+ */
+void ath5k_hw_set_mcast_filter(struct ath5k_hw *ah, u32 filter0, u32 filter1)
+{
+	ATH5K_TRACE(ah->ah_sc);
+	/* Set the multicat filter */
+	ath5k_hw_reg_write(ah, filter0, AR5K_MCAST_FILTER0);
+	ath5k_hw_reg_write(ah, filter1, AR5K_MCAST_FILTER1);
+}
+
+/*
+ * Set multicast filter by index
+ */
+int ath5k_hw_set_mcast_filter_idx(struct ath5k_hw *ah, u32 index)
+{
+
+	ATH5K_TRACE(ah->ah_sc);
+	if (index >= 64)
+		return -EINVAL;
+	else if (index >= 32)
+		AR5K_REG_ENABLE_BITS(ah, AR5K_MCAST_FILTER1,
+				(1 << (index - 32)));
+	else
+		AR5K_REG_ENABLE_BITS(ah, AR5K_MCAST_FILTER0, (1 << index));
+
+	return 0;
+}
+
+/*
+ * Clear Multicast filter by index
+ */
+int ath5k_hw_clear_mcast_filter_idx(struct ath5k_hw *ah, u32 index)
+{
+
+	ATH5K_TRACE(ah->ah_sc);
+	if (index >= 64)
+		return -EINVAL;
+	else if (index >= 32)
+		AR5K_REG_DISABLE_BITS(ah, AR5K_MCAST_FILTER1,
+				(1 << (index - 32)));
+	else
+		AR5K_REG_DISABLE_BITS(ah, AR5K_MCAST_FILTER0, (1 << index));
+
+	return 0;
+}
+
+/**
+ * ath5k_hw_get_rx_filter - Get current rx filter
+ *
+ * @ah: The &struct ath5k_hw
+ *
+ * Returns the RX filter by reading rx filter and
+ * phy error filter registers. RX filter is used
+ * to set the allowed frame types that PCU will accept
+ * and pass to the driver. For a list of frame types
+ * check out reg.h.
+ */
+u32 ath5k_hw_get_rx_filter(struct ath5k_hw *ah)
+{
+	u32 data, filter = 0;
+
+	ATH5K_TRACE(ah->ah_sc);
+	filter = ath5k_hw_reg_read(ah, AR5K_RX_FILTER);
+
+	/*Radar detection for 5212*/
+	if (ah->ah_version == AR5K_AR5212) {
+		data = ath5k_hw_reg_read(ah, AR5K_PHY_ERR_FIL);
+
+		if (data & AR5K_PHY_ERR_FIL_RADAR)
+			filter |= AR5K_RX_FILTER_RADARERR;
+		if (data & (AR5K_PHY_ERR_FIL_OFDM | AR5K_PHY_ERR_FIL_CCK))
+			filter |= AR5K_RX_FILTER_PHYERR;
+	}
+
+	return filter;
+}
+
+/**
+ * ath5k_hw_set_rx_filter - Set rx filter
+ *
+ * @ah: The &struct ath5k_hw
+ * @filter: RX filter mask (see reg.h)
+ *
+ * Sets RX filter register and also handles PHY error filter
+ * register on 5212 and newer chips so that we have proper PHY
+ * error reporting.
+ */
+void ath5k_hw_set_rx_filter(struct ath5k_hw *ah, u32 filter)
+{
+	u32 data = 0;
+
+	ATH5K_TRACE(ah->ah_sc);
+
+	/* Set PHY error filter register on 5212*/
+	if (ah->ah_version == AR5K_AR5212) {
+		if (filter & AR5K_RX_FILTER_RADARERR)
+			data |= AR5K_PHY_ERR_FIL_RADAR;
+		if (filter & AR5K_RX_FILTER_PHYERR)
+			data |= AR5K_PHY_ERR_FIL_OFDM | AR5K_PHY_ERR_FIL_CCK;
+	}
+
+	/*
+	 * The AR5210 uses promiscous mode to detect radar activity
+	 */
+	if (ah->ah_version == AR5K_AR5210 &&
+			(filter & AR5K_RX_FILTER_RADARERR)) {
+		filter &= ~AR5K_RX_FILTER_RADARERR;
+		filter |= AR5K_RX_FILTER_PROM;
+	}
+
+	/*Zero length DMA*/
+	if (data)
+		AR5K_REG_ENABLE_BITS(ah, AR5K_RXCFG, AR5K_RXCFG_ZLFDMA);
+	else
+		AR5K_REG_DISABLE_BITS(ah, AR5K_RXCFG, AR5K_RXCFG_ZLFDMA);
+
+	/*Write RX Filter register*/
+	ath5k_hw_reg_write(ah, filter & 0xff, AR5K_RX_FILTER);
+
+	/*Write PHY error filter register on 5212*/
+	if (ah->ah_version == AR5K_AR5212)
+		ath5k_hw_reg_write(ah, data, AR5K_PHY_ERR_FIL);
+
+}
+
+
+/****************\
+* Beacon control *
+\****************/
+
+/**
+ * ath5k_hw_get_tsf32 - Get a 32bit TSF
+ *
+ * @ah: The &struct ath5k_hw
+ *
+ * Returns lower 32 bits of current TSF
+ */
+u32 ath5k_hw_get_tsf32(struct ath5k_hw *ah)
+{
+	ATH5K_TRACE(ah->ah_sc);
+	return ath5k_hw_reg_read(ah, AR5K_TSF_L32);
+}
+
+/**
+ * ath5k_hw_get_tsf64 - Get the full 64bit TSF
+ *
+ * @ah: The &struct ath5k_hw
+ *
+ * Returns the current TSF
+ */
+u64 ath5k_hw_get_tsf64(struct ath5k_hw *ah)
+{
+	u64 tsf = ath5k_hw_reg_read(ah, AR5K_TSF_U32);
+	ATH5K_TRACE(ah->ah_sc);
+
+	return ath5k_hw_reg_read(ah, AR5K_TSF_L32) | (tsf << 32);
+}
+
+/**
+ * ath5k_hw_reset_tsf - Force a TSF reset
+ *
+ * @ah: The &struct ath5k_hw
+ *
+ * Forces a TSF reset on PCU
+ */
+void ath5k_hw_reset_tsf(struct ath5k_hw *ah)
+{
+	u32 val;
+
+	ATH5K_TRACE(ah->ah_sc);
+
+	val = ath5k_hw_reg_read(ah, AR5K_BEACON) | AR5K_BEACON_RESET_TSF;
+
+	/*
+	 * Each write to the RESET_TSF bit toggles a hardware internal
+	 * signal to reset TSF, but if left high it will cause a TSF reset
+	 * on the next chip reset as well.  Thus we always write the value
+	 * twice to clear the signal.
+	 */
+	ath5k_hw_reg_write(ah, val, AR5K_BEACON);
+	ath5k_hw_reg_write(ah, val, AR5K_BEACON);
+}
+
+/*
+ * Initialize beacon timers
+ */
+void ath5k_hw_init_beacon(struct ath5k_hw *ah, u32 next_beacon, u32 interval)
+{
+	u32 timer1, timer2, timer3;
+
+	ATH5K_TRACE(ah->ah_sc);
+	/*
+	 * Set the additional timers by mode
+	 */
+	switch (ah->ah_op_mode) {
+	case NL80211_IFTYPE_STATION:
+		if (ah->ah_version == AR5K_AR5210) {
+			timer1 = 0xffffffff;
+			timer2 = 0xffffffff;
+		} else {
+			timer1 = 0x0000ffff;
+			timer2 = 0x0007ffff;
+		}
+		break;
+
+	default:
+		timer1 = (next_beacon - AR5K_TUNE_DMA_BEACON_RESP) << 3;
+		timer2 = (next_beacon - AR5K_TUNE_SW_BEACON_RESP) << 3;
+	}
+
+	timer3 = next_beacon + (ah->ah_atim_window ? ah->ah_atim_window : 1);
+
+	/*
+	 * Set the beacon register and enable all timers.
+	 * (next beacon, DMA beacon, software beacon, ATIM window time)
+	 */
+	ath5k_hw_reg_write(ah, next_beacon, AR5K_TIMER0);
+	ath5k_hw_reg_write(ah, timer1, AR5K_TIMER1);
+	ath5k_hw_reg_write(ah, timer2, AR5K_TIMER2);
+	ath5k_hw_reg_write(ah, timer3, AR5K_TIMER3);
+
+	ath5k_hw_reg_write(ah, interval & (AR5K_BEACON_PERIOD |
+			AR5K_BEACON_RESET_TSF | AR5K_BEACON_ENABLE),
+		AR5K_BEACON);
+}
+
+#if 0
+/*
+ * Set beacon timers
+ */
+int ath5k_hw_set_beacon_timers(struct ath5k_hw *ah,
+		const struct ath5k_beacon_state *state)
+{
+	u32 cfp_period, next_cfp, dtim, interval, next_beacon;
+
+	/*
+	 * TODO: should be changed through *state
+	 * review struct ath5k_beacon_state struct
+	 *
+	 * XXX: These are used for cfp period bellow, are they
+	 * ok ? Is it O.K. for tsf here to be 0 or should we use
+	 * get_tsf ?
+	 */
+	u32 dtim_count = 0; /* XXX */
+	u32 cfp_count = 0; /* XXX */
+	u32 tsf = 0; /* XXX */
+
+	ATH5K_TRACE(ah->ah_sc);
+	/* Return on an invalid beacon state */
+	if (state->bs_interval < 1)
+		return -EINVAL;
+
+	interval = state->bs_interval;
+	dtim = state->bs_dtim_period;
+
+	/*
+	 * PCF support?
+	 */
+	if (state->bs_cfp_period > 0) {
+		/*
+		 * Enable PCF mode and set the CFP
+		 * (Contention Free Period) and timer registers
+		 */
+		cfp_period = state->bs_cfp_period * state->bs_dtim_period *
+			state->bs_interval;
+		next_cfp = (cfp_count * state->bs_dtim_period + dtim_count) *
+			state->bs_interval;
+
+		AR5K_REG_ENABLE_BITS(ah, AR5K_STA_ID1,
+				AR5K_STA_ID1_DEFAULT_ANTENNA |
+				AR5K_STA_ID1_PCF);
+		ath5k_hw_reg_write(ah, cfp_period, AR5K_CFP_PERIOD);
+		ath5k_hw_reg_write(ah, state->bs_cfp_max_duration,
+				AR5K_CFP_DUR);
+		ath5k_hw_reg_write(ah, (tsf + (next_cfp == 0 ? cfp_period :
+						next_cfp)) << 3, AR5K_TIMER2);
+	} else {
+		/* Disable PCF mode */
+		AR5K_REG_DISABLE_BITS(ah, AR5K_STA_ID1,
+				AR5K_STA_ID1_DEFAULT_ANTENNA |
+				AR5K_STA_ID1_PCF);
+	}
+
+	/*
+	 * Enable the beacon timer register
+	 */
+	ath5k_hw_reg_write(ah, state->bs_next_beacon, AR5K_TIMER0);
+
+	/*
+	 * Start the beacon timers
+	 */
+	ath5k_hw_reg_write(ah, (ath5k_hw_reg_read(ah, AR5K_BEACON) &
+		~(AR5K_BEACON_PERIOD | AR5K_BEACON_TIM)) |
+		AR5K_REG_SM(state->bs_tim_offset ? state->bs_tim_offset + 4 : 0,
+		AR5K_BEACON_TIM) | AR5K_REG_SM(state->bs_interval,
+		AR5K_BEACON_PERIOD), AR5K_BEACON);
+
+	/*
+	 * Write new beacon miss threshold, if it appears to be valid
+	 * XXX: Figure out right values for min <= bs_bmiss_threshold <= max
+	 * and return if its not in range. We can test this by reading value and
+	 * setting value to a largest value and seeing which values register.
+	 */
+
+	AR5K_REG_WRITE_BITS(ah, AR5K_RSSI_THR, AR5K_RSSI_THR_BMISS,
+			state->bs_bmiss_threshold);
+
+	/*
+	 * Set sleep control register
+	 * XXX: Didn't find this in 5210 code but since this register
+	 * exists also in ar5k's 5210 headers i leave it as common code.
+	 */
+	AR5K_REG_WRITE_BITS(ah, AR5K_SLEEP_CTL, AR5K_SLEEP_CTL_SLDUR,
+			(state->bs_sleep_duration - 3) << 3);
+
+	/*
+	 * Set enhanced sleep registers on 5212
+	 */
+	if (ah->ah_version == AR5K_AR5212) {
+		if (state->bs_sleep_duration > state->bs_interval &&
+				roundup(state->bs_sleep_duration, interval) ==
+				state->bs_sleep_duration)
+			interval = state->bs_sleep_duration;
+
+		if (state->bs_sleep_duration > dtim && (dtim == 0 ||
+				roundup(state->bs_sleep_duration, dtim) ==
+				state->bs_sleep_duration))
+			dtim = state->bs_sleep_duration;
+
+		if (interval > dtim)
+			return -EINVAL;
+
+		next_beacon = interval == dtim ? state->bs_next_dtim :
+			state->bs_next_beacon;
+
+		ath5k_hw_reg_write(ah,
+			AR5K_REG_SM((state->bs_next_dtim - 3) << 3,
+			AR5K_SLEEP0_NEXT_DTIM) |
+			AR5K_REG_SM(10, AR5K_SLEEP0_CABTO) |
+			AR5K_SLEEP0_ENH_SLEEP_EN |
+			AR5K_SLEEP0_ASSUME_DTIM, AR5K_SLEEP0);
+
+		ath5k_hw_reg_write(ah, AR5K_REG_SM((next_beacon - 3) << 3,
+			AR5K_SLEEP1_NEXT_TIM) |
+			AR5K_REG_SM(10, AR5K_SLEEP1_BEACON_TO), AR5K_SLEEP1);
+
+		ath5k_hw_reg_write(ah,
+			AR5K_REG_SM(interval, AR5K_SLEEP2_TIM_PER) |
+			AR5K_REG_SM(dtim, AR5K_SLEEP2_DTIM_PER), AR5K_SLEEP2);
+	}
+
+	return 0;
+}
+
+/*
+ * Reset beacon timers
+ */
+void ath5k_hw_reset_beacon(struct ath5k_hw *ah)
+{
+	ATH5K_TRACE(ah->ah_sc);
+	/*
+	 * Disable beacon timer
+	 */
+	ath5k_hw_reg_write(ah, 0, AR5K_TIMER0);
+
+	/*
+	 * Disable some beacon register values
+	 */
+	AR5K_REG_DISABLE_BITS(ah, AR5K_STA_ID1,
+			AR5K_STA_ID1_DEFAULT_ANTENNA | AR5K_STA_ID1_PCF);
+	ath5k_hw_reg_write(ah, AR5K_BEACON_PERIOD, AR5K_BEACON);
+}
+
+/*
+ * Wait for beacon queue to finish
+ */
+int ath5k_hw_beaconq_finish(struct ath5k_hw *ah, unsigned long phys_addr)
+{
+	unsigned int i;
+	int ret;
+
+	ATH5K_TRACE(ah->ah_sc);
+
+	/* 5210 doesn't have QCU*/
+	if (ah->ah_version == AR5K_AR5210) {
+		/*
+		 * Wait for beaconn queue to finish by checking
+		 * Control Register and Beacon Status Register.
+		 */
+		for (i = AR5K_TUNE_BEACON_INTERVAL / 2; i > 0; i--) {
+			if (!(ath5k_hw_reg_read(ah, AR5K_BSR) & AR5K_BSR_TXQ1F)
+					||
+			    !(ath5k_hw_reg_read(ah, AR5K_CR) & AR5K_BSR_TXQ1F))
+				break;
+			udelay(10);
+		}
+
+		/* Timeout... */
+		if (i <= 0) {
+			/*
+			 * Re-schedule the beacon queue
+			 */
+			ath5k_hw_reg_write(ah, phys_addr, AR5K_NOQCU_TXDP1);
+			ath5k_hw_reg_write(ah, AR5K_BCR_TQ1V | AR5K_BCR_BDMAE,
+					AR5K_BCR);
+
+			return -EIO;
+		}
+		ret = 0;
+	} else {
+	/*5211/5212*/
+		ret = ath5k_hw_register_timeout(ah,
+			AR5K_QUEUE_STATUS(AR5K_TX_QUEUE_ID_BEACON),
+			AR5K_QCU_STS_FRMPENDCNT, 0, false);
+
+		if (AR5K_REG_READ_Q(ah, AR5K_QCU_TXE, AR5K_TX_QUEUE_ID_BEACON))
+			return -EIO;
+	}
+
+	return ret;
+}
+#endif
+
+
+/*********************\
+* Key table functions *
+\*********************/
+
+/*
+ * Reset a key entry on the table
+ */
+int ath5k_hw_reset_key(struct ath5k_hw *ah, u16 entry)
+{
+	unsigned int i;
+
+	ATH5K_TRACE(ah->ah_sc);
+	AR5K_ASSERT_ENTRY(entry, AR5K_KEYTABLE_SIZE);
+
+	for (i = 0; i < AR5K_KEYCACHE_SIZE; i++)
+		ath5k_hw_reg_write(ah, 0, AR5K_KEYTABLE_OFF(entry, i));
+
+	/*
+	 * Set NULL encryption on AR5212+
+	 *
+	 * Note: AR5K_KEYTABLE_TYPE -> AR5K_KEYTABLE_OFF(entry, 5)
+	 *       AR5K_KEYTABLE_TYPE_NULL -> 0x00000007
+	 *
+	 * Note2: Windows driver (ndiswrapper) sets this to
+	 *        0x00000714 instead of 0x00000007
+	 */
+	if (ah->ah_version > AR5K_AR5211)
+		ath5k_hw_reg_write(ah, AR5K_KEYTABLE_TYPE_NULL,
+				AR5K_KEYTABLE_TYPE(entry));
+
+	return 0;
+}
+
+/*
+ * Check if a table entry is valid
+ */
+int ath5k_hw_is_key_valid(struct ath5k_hw *ah, u16 entry)
+{
+	ATH5K_TRACE(ah->ah_sc);
+	AR5K_ASSERT_ENTRY(entry, AR5K_KEYTABLE_SIZE);
+
+	/* Check the validation flag at the end of the entry */
+	return ath5k_hw_reg_read(ah, AR5K_KEYTABLE_MAC1(entry)) &
+		AR5K_KEYTABLE_VALID;
+}
+
+/*
+ * Set a key entry on the table
+ */
+int ath5k_hw_set_key(struct ath5k_hw *ah, u16 entry,
+		const struct ieee80211_key_conf *key, const u8 *mac)
+{
+	unsigned int i;
+	__le32 key_v[5] = {};
+	u32 keytype;
+
+	ATH5K_TRACE(ah->ah_sc);
+
+	/* key->keylen comes in from mac80211 in bytes */
+
+	if (key->keylen > AR5K_KEYTABLE_SIZE / 8)
+		return -EOPNOTSUPP;
+
+	switch (key->keylen) {
+	/* WEP 40-bit   = 40-bit  entered key + 24 bit IV = 64-bit */
+	case 40 / 8:
+		memcpy(&key_v[0], key->key, 5);
+		keytype = AR5K_KEYTABLE_TYPE_40;
+		break;
+
+	/* WEP 104-bit  = 104-bit entered key + 24-bit IV = 128-bit */
+	case 104 / 8:
+		memcpy(&key_v[0], &key->key[0], 6);
+		memcpy(&key_v[2], &key->key[6], 6);
+		memcpy(&key_v[4], &key->key[12], 1);
+		keytype = AR5K_KEYTABLE_TYPE_104;
+		break;
+	/* WEP 128-bit  = 128-bit entered key + 24 bit IV = 152-bit */
+	case 128 / 8:
+		memcpy(&key_v[0], &key->key[0], 6);
+		memcpy(&key_v[2], &key->key[6], 6);
+		memcpy(&key_v[4], &key->key[12], 4);
+		keytype = AR5K_KEYTABLE_TYPE_128;
+		break;
+
+	default:
+		return -EINVAL; /* shouldn't happen */
+	}
+
+	for (i = 0; i < ARRAY_SIZE(key_v); i++)
+		ath5k_hw_reg_write(ah, le32_to_cpu(key_v[i]),
+				AR5K_KEYTABLE_OFF(entry, i));
+
+	ath5k_hw_reg_write(ah, keytype, AR5K_KEYTABLE_TYPE(entry));
+
+	return ath5k_hw_set_key_lladdr(ah, entry, mac);
+}
+
+int ath5k_hw_set_key_lladdr(struct ath5k_hw *ah, u16 entry, const u8 *mac)
+{
+	u32 low_id, high_id;
+
+	ATH5K_TRACE(ah->ah_sc);
+	 /* Invalid entry (key table overflow) */
+	AR5K_ASSERT_ENTRY(entry, AR5K_KEYTABLE_SIZE);
+
+	/* MAC may be NULL if it's a broadcast key. In this case no need to
+	 * to compute AR5K_LOW_ID and AR5K_HIGH_ID as we already know it. */
+	if (unlikely(mac == NULL)) {
+		low_id = 0xffffffff;
+		high_id = 0xffff | AR5K_KEYTABLE_VALID;
+	} else {
+		low_id = AR5K_LOW_ID(mac);
+		high_id = AR5K_HIGH_ID(mac) | AR5K_KEYTABLE_VALID;
+	}
+
+	ath5k_hw_reg_write(ah, low_id, AR5K_KEYTABLE_MAC0(entry));
+	ath5k_hw_reg_write(ah, high_id, AR5K_KEYTABLE_MAC1(entry));
+
+	return 0;
+}
+
diff --git a/drivers/net/wireless/ath5k/phy.c b/drivers/net/wireless/ath5k/phy.c
index fa0d47f..e43f656 100644
--- a/drivers/net/wireless/ath5k/phy.c
+++ b/drivers/net/wireless/ath5k/phy.c
@@ -1,9 +1,9 @@
 /*
  * PHY functions
  *
- * Copyright (c) 2004, 2005, 2006, 2007 Reyk Floeter <reyk@openbsd.org>
- * Copyright (c) 2006, 2007 Nick Kossifidis <mickflemm@gmail.com>
- * Copyright (c) 2007 Jiri Slaby <jirislaby@gmail.com>
+ * Copyright (c) 2004-2007 Reyk Floeter <reyk@openbsd.org>
+ * Copyright (c) 2006-2007 Nick Kossifidis <mickflemm@gmail.com>
+ * Copyright (c) 2007-2008 Jiri Slaby <jirislaby@gmail.com>
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -19,6 +19,8 @@
  *
  */
 
+#define _ATH5K_PHY
+
 #include <linux/delay.h>
 
 #include "ath5k.h"
@@ -2122,7 +2124,7 @@
 	beacon = ath5k_hw_reg_read(ah, AR5K_BEACON_5210);
 	ath5k_hw_reg_write(ah, beacon & ~AR5K_BEACON_ENABLE, AR5K_BEACON_5210);
 
-	udelay(2300);
+	mdelay(2);
 
 	/*
 	 * Set the channel (with AGC turned off)
@@ -2501,3 +2503,5 @@
 
 	return ath5k_hw_txpower(ah, channel, power);
 }
+
+#undef _ATH5K_PHY
diff --git a/drivers/net/wireless/ath5k/qcu.c b/drivers/net/wireless/ath5k/qcu.c
new file mode 100644
index 0000000..01bf091
--- /dev/null
+++ b/drivers/net/wireless/ath5k/qcu.c
@@ -0,0 +1,488 @@
+/*
+ * Copyright (c) 2004-2008 Reyk Floeter <reyk@openbsd.org>
+ * Copyright (c) 2006-2008 Nick Kossifidis <mickflemm@gmail.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+/********************************************\
+Queue Control Unit, DFS Control Unit Functions
+\********************************************/
+
+#include "ath5k.h"
+#include "reg.h"
+#include "debug.h"
+#include "base.h"
+
+/*
+ * Get properties for a transmit queue
+ */
+int ath5k_hw_get_tx_queueprops(struct ath5k_hw *ah, int queue,
+		struct ath5k_txq_info *queue_info)
+{
+	ATH5K_TRACE(ah->ah_sc);
+	memcpy(queue_info, &ah->ah_txq[queue], sizeof(struct ath5k_txq_info));
+	return 0;
+}
+
+/*
+ * Set properties for a transmit queue
+ */
+int ath5k_hw_set_tx_queueprops(struct ath5k_hw *ah, int queue,
+				const struct ath5k_txq_info *queue_info)
+{
+	ATH5K_TRACE(ah->ah_sc);
+	AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num);
+
+	if (ah->ah_txq[queue].tqi_type == AR5K_TX_QUEUE_INACTIVE)
+		return -EIO;
+
+	memcpy(&ah->ah_txq[queue], queue_info, sizeof(struct ath5k_txq_info));
+
+	/*XXX: Is this supported on 5210 ?*/
+	if ((queue_info->tqi_type == AR5K_TX_QUEUE_DATA &&
+			((queue_info->tqi_subtype == AR5K_WME_AC_VI) ||
+			(queue_info->tqi_subtype == AR5K_WME_AC_VO))) ||
+			queue_info->tqi_type == AR5K_TX_QUEUE_UAPSD)
+		ah->ah_txq[queue].tqi_flags |= AR5K_TXQ_FLAG_POST_FR_BKOFF_DIS;
+
+	return 0;
+}
+
+/*
+ * Initialize a transmit queue
+ */
+int ath5k_hw_setup_tx_queue(struct ath5k_hw *ah, enum ath5k_tx_queue queue_type,
+		struct ath5k_txq_info *queue_info)
+{
+	unsigned int queue;
+	int ret;
+
+	ATH5K_TRACE(ah->ah_sc);
+
+	/*
+	 * Get queue by type
+	 */
+	/*5210 only has 2 queues*/
+	if (ah->ah_version == AR5K_AR5210) {
+		switch (queue_type) {
+		case AR5K_TX_QUEUE_DATA:
+			queue = AR5K_TX_QUEUE_ID_NOQCU_DATA;
+			break;
+		case AR5K_TX_QUEUE_BEACON:
+		case AR5K_TX_QUEUE_CAB:
+			queue = AR5K_TX_QUEUE_ID_NOQCU_BEACON;
+			break;
+		default:
+			return -EINVAL;
+		}
+	} else {
+		switch (queue_type) {
+		case AR5K_TX_QUEUE_DATA:
+			for (queue = AR5K_TX_QUEUE_ID_DATA_MIN;
+				ah->ah_txq[queue].tqi_type !=
+				AR5K_TX_QUEUE_INACTIVE; queue++) {
+
+				if (queue > AR5K_TX_QUEUE_ID_DATA_MAX)
+					return -EINVAL;
+			}
+			break;
+		case AR5K_TX_QUEUE_UAPSD:
+			queue = AR5K_TX_QUEUE_ID_UAPSD;
+			break;
+		case AR5K_TX_QUEUE_BEACON:
+			queue = AR5K_TX_QUEUE_ID_BEACON;
+			break;
+		case AR5K_TX_QUEUE_CAB:
+			queue = AR5K_TX_QUEUE_ID_CAB;
+			break;
+		case AR5K_TX_QUEUE_XR_DATA:
+			if (ah->ah_version != AR5K_AR5212)
+				ATH5K_ERR(ah->ah_sc,
+					"XR data queues only supported in"
+					" 5212!\n");
+			queue = AR5K_TX_QUEUE_ID_XR_DATA;
+			break;
+		default:
+			return -EINVAL;
+		}
+	}
+
+	/*
+	 * Setup internal queue structure
+	 */
+	memset(&ah->ah_txq[queue], 0, sizeof(struct ath5k_txq_info));
+	ah->ah_txq[queue].tqi_type = queue_type;
+
+	if (queue_info != NULL) {
+		queue_info->tqi_type = queue_type;
+		ret = ath5k_hw_set_tx_queueprops(ah, queue, queue_info);
+		if (ret)
+			return ret;
+	}
+
+	/*
+	 * We use ah_txq_status to hold a temp value for
+	 * the Secondary interrupt mask registers on 5211+
+	 * check out ath5k_hw_reset_tx_queue
+	 */
+	AR5K_Q_ENABLE_BITS(ah->ah_txq_status, queue);
+
+	return queue;
+}
+
+/*
+ * Get number of pending frames
+ * for a specific queue [5211+]
+ */
+u32 ath5k_hw_num_tx_pending(struct ath5k_hw *ah, unsigned int queue)
+{
+	ATH5K_TRACE(ah->ah_sc);
+	AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num);
+
+	/* Return if queue is declared inactive */
+	if (ah->ah_txq[queue].tqi_type == AR5K_TX_QUEUE_INACTIVE)
+		return false;
+
+	/* XXX: How about AR5K_CFG_TXCNT ? */
+	if (ah->ah_version == AR5K_AR5210)
+		return false;
+
+	return AR5K_QUEUE_STATUS(queue) & AR5K_QCU_STS_FRMPENDCNT;
+}
+
+/*
+ * Set a transmit queue inactive
+ */
+void ath5k_hw_release_tx_queue(struct ath5k_hw *ah, unsigned int queue)
+{
+	ATH5K_TRACE(ah->ah_sc);
+	if (WARN_ON(queue >= ah->ah_capabilities.cap_queues.q_tx_num))
+		return;
+
+	/* This queue will be skipped in further operations */
+	ah->ah_txq[queue].tqi_type = AR5K_TX_QUEUE_INACTIVE;
+	/*For SIMR setup*/
+	AR5K_Q_DISABLE_BITS(ah->ah_txq_status, queue);
+}
+
+/*
+ * Set DFS properties for a transmit queue on DCU
+ */
+int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue)
+{
+	u32 cw_min, cw_max, retry_lg, retry_sh;
+	struct ath5k_txq_info *tq = &ah->ah_txq[queue];
+
+	ATH5K_TRACE(ah->ah_sc);
+	AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num);
+
+	tq = &ah->ah_txq[queue];
+
+	if (tq->tqi_type == AR5K_TX_QUEUE_INACTIVE)
+		return 0;
+
+	if (ah->ah_version == AR5K_AR5210) {
+		/* Only handle data queues, others will be ignored */
+		if (tq->tqi_type != AR5K_TX_QUEUE_DATA)
+			return 0;
+
+		/* Set Slot time */
+		ath5k_hw_reg_write(ah, ah->ah_turbo ?
+			AR5K_INIT_SLOT_TIME_TURBO : AR5K_INIT_SLOT_TIME,
+			AR5K_SLOT_TIME);
+		/* Set ACK_CTS timeout */
+		ath5k_hw_reg_write(ah, ah->ah_turbo ?
+			AR5K_INIT_ACK_CTS_TIMEOUT_TURBO :
+			AR5K_INIT_ACK_CTS_TIMEOUT, AR5K_SLOT_TIME);
+		/* Set Transmit Latency */
+		ath5k_hw_reg_write(ah, ah->ah_turbo ?
+			AR5K_INIT_TRANSMIT_LATENCY_TURBO :
+			AR5K_INIT_TRANSMIT_LATENCY, AR5K_USEC_5210);
+
+		/* Set IFS0 */
+		if (ah->ah_turbo) {
+			 ath5k_hw_reg_write(ah, ((AR5K_INIT_SIFS_TURBO +
+				(ah->ah_aifs + tq->tqi_aifs) *
+				AR5K_INIT_SLOT_TIME_TURBO) <<
+				AR5K_IFS0_DIFS_S) | AR5K_INIT_SIFS_TURBO,
+				AR5K_IFS0);
+		} else {
+			ath5k_hw_reg_write(ah, ((AR5K_INIT_SIFS +
+				(ah->ah_aifs + tq->tqi_aifs) *
+				AR5K_INIT_SLOT_TIME) << AR5K_IFS0_DIFS_S) |
+				AR5K_INIT_SIFS, AR5K_IFS0);
+		}
+
+		/* Set IFS1 */
+		ath5k_hw_reg_write(ah, ah->ah_turbo ?
+			AR5K_INIT_PROTO_TIME_CNTRL_TURBO :
+			AR5K_INIT_PROTO_TIME_CNTRL, AR5K_IFS1);
+		/* Set AR5K_PHY_SETTLING */
+		ath5k_hw_reg_write(ah, ah->ah_turbo ?
+			(ath5k_hw_reg_read(ah, AR5K_PHY_SETTLING) & ~0x7F)
+			| 0x38 :
+			(ath5k_hw_reg_read(ah, AR5K_PHY_SETTLING) & ~0x7F)
+			| 0x1C,
+			AR5K_PHY_SETTLING);
+		/* Set Frame Control Register */
+		ath5k_hw_reg_write(ah, ah->ah_turbo ?
+			(AR5K_PHY_FRAME_CTL_INI | AR5K_PHY_TURBO_MODE |
+			AR5K_PHY_TURBO_SHORT | 0x2020) :
+			(AR5K_PHY_FRAME_CTL_INI | 0x1020),
+			AR5K_PHY_FRAME_CTL_5210);
+	}
+
+	/*
+	 * Calculate cwmin/max by channel mode
+	 */
+	cw_min = ah->ah_cw_min = AR5K_TUNE_CWMIN;
+	cw_max = ah->ah_cw_max = AR5K_TUNE_CWMAX;
+	ah->ah_aifs = AR5K_TUNE_AIFS;
+	/*XR is only supported on 5212*/
+	if (IS_CHAN_XR(ah->ah_current_channel) &&
+			ah->ah_version == AR5K_AR5212) {
+		cw_min = ah->ah_cw_min = AR5K_TUNE_CWMIN_XR;
+		cw_max = ah->ah_cw_max = AR5K_TUNE_CWMAX_XR;
+		ah->ah_aifs = AR5K_TUNE_AIFS_XR;
+	/*B mode is not supported on 5210*/
+	} else if (IS_CHAN_B(ah->ah_current_channel) &&
+			ah->ah_version != AR5K_AR5210) {
+		cw_min = ah->ah_cw_min = AR5K_TUNE_CWMIN_11B;
+		cw_max = ah->ah_cw_max = AR5K_TUNE_CWMAX_11B;
+		ah->ah_aifs = AR5K_TUNE_AIFS_11B;
+	}
+
+	cw_min = 1;
+	while (cw_min < ah->ah_cw_min)
+		cw_min = (cw_min << 1) | 1;
+
+	cw_min = tq->tqi_cw_min < 0 ? (cw_min >> (-tq->tqi_cw_min)) :
+		((cw_min << tq->tqi_cw_min) + (1 << tq->tqi_cw_min) - 1);
+	cw_max = tq->tqi_cw_max < 0 ? (cw_max >> (-tq->tqi_cw_max)) :
+		((cw_max << tq->tqi_cw_max) + (1 << tq->tqi_cw_max) - 1);
+
+	/*
+	 * Calculate and set retry limits
+	 */
+	if (ah->ah_software_retry) {
+		/* XXX Need to test this */
+		retry_lg = ah->ah_limit_tx_retries;
+		retry_sh = retry_lg = retry_lg > AR5K_DCU_RETRY_LMT_SH_RETRY ?
+			AR5K_DCU_RETRY_LMT_SH_RETRY : retry_lg;
+	} else {
+		retry_lg = AR5K_INIT_LG_RETRY;
+		retry_sh = AR5K_INIT_SH_RETRY;
+	}
+
+	/*No QCU/DCU [5210]*/
+	if (ah->ah_version == AR5K_AR5210) {
+		ath5k_hw_reg_write(ah,
+			(cw_min << AR5K_NODCU_RETRY_LMT_CW_MIN_S)
+			| AR5K_REG_SM(AR5K_INIT_SLG_RETRY,
+				AR5K_NODCU_RETRY_LMT_SLG_RETRY)
+			| AR5K_REG_SM(AR5K_INIT_SSH_RETRY,
+				AR5K_NODCU_RETRY_LMT_SSH_RETRY)
+			| AR5K_REG_SM(retry_lg, AR5K_NODCU_RETRY_LMT_LG_RETRY)
+			| AR5K_REG_SM(retry_sh, AR5K_NODCU_RETRY_LMT_SH_RETRY),
+			AR5K_NODCU_RETRY_LMT);
+	} else {
+		/*QCU/DCU [5211+]*/
+		ath5k_hw_reg_write(ah,
+			AR5K_REG_SM(AR5K_INIT_SLG_RETRY,
+				AR5K_DCU_RETRY_LMT_SLG_RETRY) |
+			AR5K_REG_SM(AR5K_INIT_SSH_RETRY,
+				AR5K_DCU_RETRY_LMT_SSH_RETRY) |
+			AR5K_REG_SM(retry_lg, AR5K_DCU_RETRY_LMT_LG_RETRY) |
+			AR5K_REG_SM(retry_sh, AR5K_DCU_RETRY_LMT_SH_RETRY),
+			AR5K_QUEUE_DFS_RETRY_LIMIT(queue));
+
+	/*===Rest is also for QCU/DCU only [5211+]===*/
+
+		/*
+		 * Set initial content window (cw_min/cw_max)
+		 * and arbitrated interframe space (aifs)...
+		 */
+		ath5k_hw_reg_write(ah,
+			AR5K_REG_SM(cw_min, AR5K_DCU_LCL_IFS_CW_MIN) |
+			AR5K_REG_SM(cw_max, AR5K_DCU_LCL_IFS_CW_MAX) |
+			AR5K_REG_SM(ah->ah_aifs + tq->tqi_aifs,
+				AR5K_DCU_LCL_IFS_AIFS),
+			AR5K_QUEUE_DFS_LOCAL_IFS(queue));
+
+		/*
+		 * Set misc registers
+		 */
+		ath5k_hw_reg_write(ah, AR5K_QCU_MISC_DCU_EARLY,
+			AR5K_QUEUE_MISC(queue));
+
+		if (tq->tqi_cbr_period) {
+			ath5k_hw_reg_write(ah, AR5K_REG_SM(tq->tqi_cbr_period,
+				AR5K_QCU_CBRCFG_INTVAL) |
+				AR5K_REG_SM(tq->tqi_cbr_overflow_limit,
+				AR5K_QCU_CBRCFG_ORN_THRES),
+				AR5K_QUEUE_CBRCFG(queue));
+			AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue),
+				AR5K_QCU_MISC_FRSHED_CBR);
+			if (tq->tqi_cbr_overflow_limit)
+				AR5K_REG_ENABLE_BITS(ah,
+					AR5K_QUEUE_MISC(queue),
+					AR5K_QCU_MISC_CBR_THRES_ENABLE);
+		}
+
+		if (tq->tqi_ready_time)
+			ath5k_hw_reg_write(ah, AR5K_REG_SM(tq->tqi_ready_time,
+				AR5K_QCU_RDYTIMECFG_INTVAL) |
+				AR5K_QCU_RDYTIMECFG_ENABLE,
+				AR5K_QUEUE_RDYTIMECFG(queue));
+
+		if (tq->tqi_burst_time) {
+			ath5k_hw_reg_write(ah, AR5K_REG_SM(tq->tqi_burst_time,
+				AR5K_DCU_CHAN_TIME_DUR) |
+				AR5K_DCU_CHAN_TIME_ENABLE,
+				AR5K_QUEUE_DFS_CHANNEL_TIME(queue));
+
+			if (tq->tqi_flags
+			& AR5K_TXQ_FLAG_RDYTIME_EXP_POLICY_ENABLE)
+				AR5K_REG_ENABLE_BITS(ah,
+					AR5K_QUEUE_MISC(queue),
+					AR5K_QCU_MISC_RDY_VEOL_POLICY);
+		}
+
+		if (tq->tqi_flags & AR5K_TXQ_FLAG_BACKOFF_DISABLE)
+			ath5k_hw_reg_write(ah, AR5K_DCU_MISC_POST_FR_BKOFF_DIS,
+				AR5K_QUEUE_DFS_MISC(queue));
+
+		if (tq->tqi_flags & AR5K_TXQ_FLAG_FRAG_BURST_BACKOFF_ENABLE)
+			ath5k_hw_reg_write(ah, AR5K_DCU_MISC_BACKOFF_FRAG,
+				AR5K_QUEUE_DFS_MISC(queue));
+
+		/*
+		 * Set registers by queue type
+		 */
+		switch (tq->tqi_type) {
+		case AR5K_TX_QUEUE_BEACON:
+			AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue),
+				AR5K_QCU_MISC_FRSHED_DBA_GT |
+				AR5K_QCU_MISC_CBREXP_BCN_DIS |
+				AR5K_QCU_MISC_BCN_ENABLE);
+
+			AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_DFS_MISC(queue),
+				(AR5K_DCU_MISC_ARBLOCK_CTL_GLOBAL <<
+				AR5K_DCU_MISC_ARBLOCK_CTL_S) |
+				AR5K_DCU_MISC_POST_FR_BKOFF_DIS |
+				AR5K_DCU_MISC_BCN_ENABLE);
+
+			ath5k_hw_reg_write(ah, ((AR5K_TUNE_BEACON_INTERVAL -
+				(AR5K_TUNE_SW_BEACON_RESP -
+				AR5K_TUNE_DMA_BEACON_RESP) -
+				AR5K_TUNE_ADDITIONAL_SWBA_BACKOFF) * 1024) |
+				AR5K_QCU_RDYTIMECFG_ENABLE,
+				AR5K_QUEUE_RDYTIMECFG(queue));
+			break;
+
+		case AR5K_TX_QUEUE_CAB:
+			AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue),
+				AR5K_QCU_MISC_FRSHED_DBA_GT |
+				AR5K_QCU_MISC_CBREXP_DIS |
+				AR5K_QCU_MISC_CBREXP_BCN_DIS);
+
+			AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_DFS_MISC(queue),
+				(AR5K_DCU_MISC_ARBLOCK_CTL_GLOBAL <<
+				AR5K_DCU_MISC_ARBLOCK_CTL_S));
+			break;
+
+		case AR5K_TX_QUEUE_UAPSD:
+			AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue),
+				AR5K_QCU_MISC_CBREXP_DIS);
+			break;
+
+		case AR5K_TX_QUEUE_DATA:
+		default:
+			break;
+		}
+
+		/*
+		 * Enable interrupts for this tx queue
+		 * in the secondary interrupt mask registers
+		 */
+		if (tq->tqi_flags & AR5K_TXQ_FLAG_TXOKINT_ENABLE)
+			AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txok, queue);
+
+		if (tq->tqi_flags & AR5K_TXQ_FLAG_TXERRINT_ENABLE)
+			AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txerr, queue);
+
+		if (tq->tqi_flags & AR5K_TXQ_FLAG_TXURNINT_ENABLE)
+			AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txurn, queue);
+
+		if (tq->tqi_flags & AR5K_TXQ_FLAG_TXDESCINT_ENABLE)
+			AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txdesc, queue);
+
+		if (tq->tqi_flags & AR5K_TXQ_FLAG_TXEOLINT_ENABLE)
+			AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txeol, queue);
+
+
+		/* Update secondary interrupt mask registers */
+		ah->ah_txq_imr_txok &= ah->ah_txq_status;
+		ah->ah_txq_imr_txerr &= ah->ah_txq_status;
+		ah->ah_txq_imr_txurn &= ah->ah_txq_status;
+		ah->ah_txq_imr_txdesc &= ah->ah_txq_status;
+		ah->ah_txq_imr_txeol &= ah->ah_txq_status;
+
+		ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_txok,
+			AR5K_SIMR0_QCU_TXOK) |
+			AR5K_REG_SM(ah->ah_txq_imr_txdesc,
+			AR5K_SIMR0_QCU_TXDESC), AR5K_SIMR0);
+		ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_txerr,
+			AR5K_SIMR1_QCU_TXERR) |
+			AR5K_REG_SM(ah->ah_txq_imr_txeol,
+			AR5K_SIMR1_QCU_TXEOL), AR5K_SIMR1);
+		ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_txurn,
+			AR5K_SIMR2_QCU_TXURN), AR5K_SIMR2);
+	}
+
+	return 0;
+}
+
+/*
+ * Get slot time from DCU
+ */
+unsigned int ath5k_hw_get_slot_time(struct ath5k_hw *ah)
+{
+	ATH5K_TRACE(ah->ah_sc);
+	if (ah->ah_version == AR5K_AR5210)
+		return ath5k_hw_clocktoh(ath5k_hw_reg_read(ah,
+				AR5K_SLOT_TIME) & 0xffff, ah->ah_turbo);
+	else
+		return ath5k_hw_reg_read(ah, AR5K_DCU_GBL_IFS_SLOT) & 0xffff;
+}
+
+/*
+ * Set slot time on DCU
+ */
+int ath5k_hw_set_slot_time(struct ath5k_hw *ah, unsigned int slot_time)
+{
+	ATH5K_TRACE(ah->ah_sc);
+	if (slot_time < AR5K_SLOT_TIME_9 || slot_time > AR5K_SLOT_TIME_MAX)
+		return -EINVAL;
+
+	if (ah->ah_version == AR5K_AR5210)
+		ath5k_hw_reg_write(ah, ath5k_hw_htoclock(slot_time,
+				ah->ah_turbo), AR5K_SLOT_TIME);
+	else
+		ath5k_hw_reg_write(ah, slot_time, AR5K_DCU_GBL_IFS_SLOT);
+
+	return 0;
+}
+
diff --git a/drivers/net/wireless/ath5k/reg.h b/drivers/net/wireless/ath5k/reg.h
index 7562bf1..e557fe1 100644
--- a/drivers/net/wireless/ath5k/reg.h
+++ b/drivers/net/wireless/ath5k/reg.h
@@ -1,7 +1,7 @@
 /*
- * Copyright (c) 2007 Nick Kossifidis <mickflemm@gmail.com>
- * Copyright (c) 2004, 2005, 2006, 2007 Reyk Floeter <reyk@openbsd.org>
- * Copyright (c) 2007 Michael Taylor <mike.taylor@apprion.com>
+ * Copyright (c) 2006-2008 Nick Kossifidis <mickflemm@gmail.com>
+ * Copyright (c) 2004-2008 Reyk Floeter <reyk@openbsd.org>
+ * Copyright (c) 2007-2008 Michael Taylor <mike.taylor@apprion.com>
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -29,6 +29,10 @@
  *        http://www.it.iitb.ac.in/~janak/wifire/01222734.pdf
  *
  * 5211 - http://www.hotchips.org/archives/hc14/3_Tue/16_mcfarland.pdf
+ *
+ * This file also contains register values found on a memory dump of
+ * Atheros's ART program (Atheros Radio Test), on ath9k, on legacy-hal
+ * released by Atheros and on various debug messages found on the net.
  */
 
 
@@ -295,7 +299,7 @@
 #define AR5K_ISR_RXPHY		0x00004000	/* PHY error */
 #define AR5K_ISR_RXKCM		0x00008000	/* RX Key cache miss */
 #define AR5K_ISR_SWBA		0x00010000	/* Software beacon alert */
-#define AR5K_ISR_BRSSI		0x00020000
+#define AR5K_ISR_BRSSI		0x00020000	/* Beacon rssi below threshold (?) */
 #define AR5K_ISR_BMISS		0x00040000	/* Beacon missed */
 #define AR5K_ISR_HIUERR		0x00080000	/* Host Interface Unit error [5211+] */
 #define AR5K_ISR_BNR		0x00100000 	/* Beacon not ready [5211+] */
@@ -303,46 +307,56 @@
 #define AR5K_ISR_RXCHIRP	0x00200000	/* CHIRP Received [5212+] */
 #define AR5K_ISR_SSERR		0x00200000	/* Signaled System Error [5210] */
 #define AR5K_ISR_DPERR		0x00400000	/* Det par Error (?) [5210] */
-#define AR5K_ISR_TIM		0x00800000	/* [5210] */
-#define AR5K_ISR_BCNMISC	0x00800000	/* [5212+] */
-#define AR5K_ISR_GPIO		0x01000000	/* GPIO (rf kill)*/
-#define AR5K_ISR_QCBRORN	0x02000000	/* CBR overrun (?)  [5211+] */
-#define AR5K_ISR_QCBRURN	0x04000000	/* CBR underrun (?) [5211+] */
-#define AR5K_ISR_QTRIG		0x08000000	/* [5211+] */
+#define AR5K_ISR_RXDOPPLER	0x00400000	/* Doppler chirp received [5212+] */
+#define AR5K_ISR_TIM		0x00800000	/* [5211+] */
+#define AR5K_ISR_BCNMISC	0x00800000	/* 'or' of TIM, CAB_END, DTIM_SYNC, BCN_TIMEOUT,
+						CAB_TIMEOUT and DTIM bits from SISR2 [5212+] */
+#define AR5K_ISR_GPIO		0x01000000	/* GPIO (rf kill) */
+#define AR5K_ISR_QCBRORN	0x02000000	/* QCU CBR overrun [5211+] */
+#define AR5K_ISR_QCBRURN	0x04000000	/* QCU CBR underrun [5211+] */
+#define AR5K_ISR_QTRIG		0x08000000	/* QCU scheduling trigger [5211+] */
 
 /*
  * Secondary status registers [5211+] (0 - 4)
  *
- * I guess from the names that these give the status for each
- * queue, that's why only masks are defined here, haven't got
- * any info about them (couldn't find them anywhere in ar5k code).
+ * These give the status for each QCU, only QCUs 0-9 are
+ * represented.
  */
 #define AR5K_SISR0		0x0084			/* Register Address [5211+] */
 #define AR5K_SISR0_QCU_TXOK	0x000003ff	/* Mask for QCU_TXOK */
+#define AR5K_SISR0_QCU_TXOK_S	0
 #define AR5K_SISR0_QCU_TXDESC	0x03ff0000	/* Mask for QCU_TXDESC */
+#define AR5K_SISR0_QCU_TXDESC_S	16
 
 #define AR5K_SISR1		0x0088			/* Register Address [5211+] */
 #define AR5K_SISR1_QCU_TXERR	0x000003ff	/* Mask for QCU_TXERR */
+#define AR5K_SISR1_QCU_TXERR_S	0
 #define AR5K_SISR1_QCU_TXEOL	0x03ff0000	/* Mask for QCU_TXEOL */
+#define AR5K_SISR1_QCU_TXEOL_S	16
 
 #define AR5K_SISR2		0x008c			/* Register Address [5211+] */
 #define AR5K_SISR2_QCU_TXURN	0x000003ff	/* Mask for QCU_TXURN */
+#define	AR5K_SISR2_QCU_TXURN_S	0
 #define	AR5K_SISR2_MCABT	0x00100000	/* Master Cycle Abort */
 #define	AR5K_SISR2_SSERR	0x00200000	/* Signaled System Error */
-#define	AR5K_SISR2_DPERR	0x00400000	/* Det par Error (?) */
+#define	AR5K_SISR2_DPERR	0x00400000	/* Bus parity error */
 #define	AR5K_SISR2_TIM		0x01000000	/* [5212+] */
 #define	AR5K_SISR2_CAB_END	0x02000000	/* [5212+] */
 #define	AR5K_SISR2_DTIM_SYNC	0x04000000	/* DTIM sync lost [5212+] */
 #define	AR5K_SISR2_BCN_TIMEOUT	0x08000000	/* Beacon Timeout [5212+] */
 #define	AR5K_SISR2_CAB_TIMEOUT	0x10000000	/* CAB Timeout [5212+] */
 #define	AR5K_SISR2_DTIM		0x20000000	/* [5212+] */
+#define	AR5K_SISR2_TSFOOR	0x80000000	/* TSF OOR (?) */
 
 #define AR5K_SISR3		0x0090			/* Register Address [5211+] */
 #define AR5K_SISR3_QCBRORN	0x000003ff	/* Mask for QCBRORN */
+#define AR5K_SISR3_QCBORN_S	0
 #define AR5K_SISR3_QCBRURN	0x03ff0000	/* Mask for QCBRURN */
+#define AR5K_SISR3_QCBRURN_S	16
 
 #define AR5K_SISR4		0x0094			/* Register Address [5211+] */
 #define AR5K_SISR4_QTRIG	0x000003ff	/* Mask for QTRIG */
+#define AR5K_SISR4_QTRIG_S	0
 
 /*
  * Shadow read-and-clear interrupt status registers [5211+]
@@ -379,7 +393,7 @@
 #define AR5K_IMR_RXPHY		0x00004000	/* PHY error*/
 #define AR5K_IMR_RXKCM		0x00008000	/* RX Key cache miss */
 #define AR5K_IMR_SWBA		0x00010000	/* Software beacon alert*/
-#define AR5K_IMR_BRSSI		0x00020000
+#define AR5K_IMR_BRSSI		0x00020000	/* Beacon rssi below threshold (?) */
 #define AR5K_IMR_BMISS		0x00040000	/* Beacon missed*/
 #define AR5K_IMR_HIUERR		0x00080000	/* Host Interface Unit error [5211+] */
 #define AR5K_IMR_BNR		0x00100000 	/* Beacon not ready [5211+] */
@@ -387,12 +401,14 @@
 #define AR5K_IMR_RXCHIRP	0x00200000	/* CHIRP Received [5212+]*/
 #define AR5K_IMR_SSERR		0x00200000	/* Signaled System Error [5210] */
 #define AR5K_IMR_DPERR		0x00400000	/* Det par Error (?) [5210] */
+#define AR5K_IMR_RXDOPPLER	0x00400000	/* Doppler chirp received [5212+] */
 #define AR5K_IMR_TIM		0x00800000	/* [5211+] */
-#define AR5K_IMR_BCNMISC	0x00800000	/* [5212+] */
+#define AR5K_IMR_BCNMISC	0x00800000	/* 'or' of TIM, CAB_END, DTIM_SYNC, BCN_TIMEOUT,
+						CAB_TIMEOUT and DTIM bits from SISR2 [5212+] */
 #define AR5K_IMR_GPIO		0x01000000	/* GPIO (rf kill)*/
-#define AR5K_IMR_QCBRORN	0x02000000	/* CBR overrun (?) [5211+] */
-#define AR5K_IMR_QCBRURN	0x04000000	/* CBR underrun (?) [5211+] */
-#define AR5K_IMR_QTRIG		0x08000000	/* [5211+] */
+#define AR5K_IMR_QCBRORN	0x02000000	/* QCU CBR overrun (?) [5211+] */
+#define AR5K_IMR_QCBRURN	0x04000000	/* QCU CBR underrun (?) [5211+] */
+#define AR5K_IMR_QTRIG		0x08000000	/* QCU scheduling trigger [5211+] */
 
 /*
  * Secondary interrupt mask registers [5211+] (0 - 4)
@@ -414,13 +430,14 @@
 #define AR5K_SIMR2_QCU_TXURN_S	0
 #define	AR5K_SIMR2_MCABT	0x00100000	/* Master Cycle Abort */
 #define	AR5K_SIMR2_SSERR	0x00200000	/* Signaled System Error */
-#define	AR5K_SIMR2_DPERR	0x00400000	/* Det par Error (?) */
+#define	AR5K_SIMR2_DPERR	0x00400000	/* Bus parity error */
 #define	AR5K_SIMR2_TIM		0x01000000	/* [5212+] */
 #define	AR5K_SIMR2_CAB_END	0x02000000	/* [5212+] */
 #define	AR5K_SIMR2_DTIM_SYNC	0x04000000	/* DTIM Sync lost [5212+] */
 #define	AR5K_SIMR2_BCN_TIMEOUT	0x08000000	/* Beacon Timeout [5212+] */
 #define	AR5K_SIMR2_CAB_TIMEOUT	0x10000000	/* CAB Timeout [5212+] */
 #define	AR5K_SIMR2_DTIM		0x20000000	/* [5212+] */
+#define	AR5K_SIMR2_TSFOOR	0x80000000	/* TSF OOR (?) */
 
 #define AR5K_SIMR3		0x00b0			/* Register Address [5211+] */
 #define AR5K_SIMR3_QCBRORN	0x000003ff	/* Mask for QCBRORN */
@@ -586,15 +603,15 @@
 #define	AR5K_QCU_MISC_FRSHED_M		0x0000000f	/* Frame sheduling mask */
 #define	AR5K_QCU_MISC_FRSHED_ASAP		0	/* ASAP */
 #define	AR5K_QCU_MISC_FRSHED_CBR		1	/* Constant Bit Rate */
-#define	AR5K_QCU_MISC_FRSHED_DBA_GT		2	/* DMA Beacon alert gated (?) */
-#define	AR5K_QCU_MISC_FRSHED_TIM_GT		3	/* Time gated (?) */
-#define	AR5K_QCU_MISC_FRSHED_BCN_SENT_GT	4	/* Beacon sent gated (?) */
+#define	AR5K_QCU_MISC_FRSHED_DBA_GT		2	/* DMA Beacon alert gated */
+#define	AR5K_QCU_MISC_FRSHED_TIM_GT		3	/* TIMT gated */
+#define	AR5K_QCU_MISC_FRSHED_BCN_SENT_GT	4	/* Beacon sent gated */
 #define	AR5K_QCU_MISC_ONESHOT_ENABLE	0x00000010	/* Oneshot enable */
-#define	AR5K_QCU_MISC_CBREXP		0x00000020	/* CBR expired (normal queue) */
-#define	AR5K_QCU_MISC_CBREXP_BCN	0x00000040	/* CBR expired (beacon queue) */
+#define	AR5K_QCU_MISC_CBREXP_DIS	0x00000020	/* Disable CBR expired counter (normal queue) */
+#define	AR5K_QCU_MISC_CBREXP_BCN_DIS	0x00000040	/* Disable CBR expired counter (beacon queue) */
 #define	AR5K_QCU_MISC_BCN_ENABLE	0x00000080	/* Enable Beacon use */
-#define	AR5K_QCU_MISC_CBR_THRES_ENABLE	0x00000100	/* CBR threshold enabled */
-#define	AR5K_QCU_MISC_RDY_VEOL_POLICY	0x00000200	/* TXE reset when RDYTIME enalbed */
+#define	AR5K_QCU_MISC_CBR_THRES_ENABLE	0x00000100	/* CBR expired threshold enabled */
+#define	AR5K_QCU_MISC_RDY_VEOL_POLICY	0x00000200	/* TXE reset when RDYTIME expired or VEOL */
 #define	AR5K_QCU_MISC_CBR_RESET_CNT	0x00000400	/* CBR threshold (counter) reset */
 #define	AR5K_QCU_MISC_DCU_EARLY		0x00000800	/* DCU early termination */
 #define AR5K_QCU_MISC_DCU_CMP_EN	0x00001000	/* Enable frame compression */
@@ -663,6 +680,7 @@
 #define	AR5K_DCU_LCL_IFS_CW_MAX_S	10
 #define	AR5K_DCU_LCL_IFS_AIFS		0x0ff00000	/* Arbitrated Interframe Space */
 #define	AR5K_DCU_LCL_IFS_AIFS_S		20
+#define	AR5K_DCU_LCL_IFS_AIFS_MAX	0xfc		/* Anything above that can cause DCU to hang */
 #define	AR5K_QUEUE_DFS_LOCAL_IFS(_q)	AR5K_QUEUE_REG(AR5K_DCU_LCL_IFS_BASE, _q)
 
 /*
@@ -691,11 +709,7 @@
 /*
  * DCU misc registers [5211+]
  *
- * For some of the registers i couldn't find in the code
- * (only backoff stuff is there realy) i tried to match the
- * names with 802.11e parameters etc, so i guess VIRTCOL here
- * means Virtual Collision and HCFPOLL means Hybrid Coordination
- * factor Poll (CF- Poll). Arbiter lockout control controls the
+ * Note: Arbiter lockout control controls the
  * behaviour on low priority queues when we have multiple queues
  * with pending frames. Intra-frame lockout means we wait until
  * the queue's current frame transmits (with post frame backoff and bursting)
@@ -705,15 +719,20 @@
  * No lockout means there is no special handling.
  */
 #define AR5K_DCU_MISC_BASE		0x1100			/* Register Address -Queue0 DCU_MISC */
-#define	AR5K_DCU_MISC_BACKOFF		0x000007ff	/* Mask for backoff threshold */
+#define	AR5K_DCU_MISC_BACKOFF		0x0000003f	/* Mask for backoff threshold */
+#define	AR5K_DCU_MISC_ETS_RTS_POL	0x00000040	/* End of transmission series
+							station RTS/data failure count
+							reset policy (?) */
+#define AR5K_DCU_MISC_ETS_CW_POL	0x00000080	/* End of transmission series
+							CW reset policy */
+#define	AR5K_DCU_MISC_FRAG_WAIT		0x00000100	/* Wait for next fragment */
 #define AR5K_DCU_MISC_BACKOFF_FRAG	0x00000200	/* Enable backoff while bursting */
 #define	AR5K_DCU_MISC_HCFPOLL_ENABLE	0x00000800	/* CF - Poll enable */
 #define	AR5K_DCU_MISC_BACKOFF_PERSIST	0x00001000	/* Persistent backoff */
 #define	AR5K_DCU_MISC_FRMPRFTCH_ENABLE	0x00002000	/* Enable frame pre-fetch */
 #define	AR5K_DCU_MISC_VIRTCOL		0x0000c000	/* Mask for Virtual Collision (?) */
-#define	AR5K_DCU_MISC_VIRTCOL_NORMAL		0
-#define	AR5K_DCU_MISC_VIRTCOL_MODIFIED		1
-#define	AR5K_DCU_MISC_VIRTCOL_IGNORE		2
+#define	AR5K_DCU_MISC_VIRTCOL_NORMAL	0
+#define	AR5K_DCU_MISC_VIRTCOL_IGNORE	1
 #define	AR5K_DCU_MISC_BCN_ENABLE	0x00010000	/* Enable Beacon use */
 #define	AR5K_DCU_MISC_ARBLOCK_CTL	0x00060000	/* Arbiter lockout control mask */
 #define	AR5K_DCU_MISC_ARBLOCK_CTL_S	17
@@ -768,8 +787,9 @@
 #define	AR5K_DCU_GBL_IFS_MISC_TURBO_MODE	0x00000008	/* Turbo mode */
 #define	AR5K_DCU_GBL_IFS_MISC_SIFS_DUR_USEC	0x000003f0	/* SIFS Duration mask */
 #define	AR5K_DCU_GBL_IFS_MISC_USEC_DUR		0x000ffc00	/* USEC Duration mask */
+#define	AR5K_DCU_GBL_IFS_MISC_USEC_DUR_S	10
 #define	AR5K_DCU_GBL_IFS_MISC_DCU_ARB_DELAY	0x00300000	/* DCU Arbiter delay mask */
-#define AR5K_DCU_GBL_IFS_MISC_SIFS_CNT_RST	0x00400000	/* SIFC cnt reset policy (?) */
+#define AR5K_DCU_GBL_IFS_MISC_SIFS_CNT_RST	0x00400000	/* SIFS cnt reset policy (?) */
 #define AR5K_DCU_GBL_IFS_MISC_AIFS_CNT_RST	0x00800000	/* AIFS cnt reset policy (?) */
 #define AR5K_DCU_GBL_IFS_MISC_RND_LFSR_SL_DIS	0x01000000	/* Disable random LFSR slice */
 
@@ -820,8 +840,6 @@
 #define AR5K_RESET_CTL_MAC	0x00000004	/* MAC reset (PCU+Baseband ?) [5210] */
 #define AR5K_RESET_CTL_PHY	0x00000008	/* PHY reset [5210] */
 #define AR5K_RESET_CTL_PCI	0x00000010	/* PCI Core reset (interrupts etc) */
-#define AR5K_RESET_CTL_CHIP	(AR5K_RESET_CTL_PCU | AR5K_RESET_CTL_DMA |	\
-				AR5K_RESET_CTL_MAC | AR5K_RESET_CTL_PHY)
 
 /*
  * Sleep control register
@@ -833,9 +851,11 @@
 #define AR5K_SLEEP_CTL_SLE_S		16
 #define AR5K_SLEEP_CTL_SLE_WAKE		0x00000000	/* Force chip awake */
 #define AR5K_SLEEP_CTL_SLE_SLP		0x00010000	/* Force chip sleep */
-#define AR5K_SLEEP_CTL_SLE_ALLOW	0x00020000
+#define AR5K_SLEEP_CTL_SLE_ALLOW	0x00020000	/* Normal sleep policy */
 #define AR5K_SLEEP_CTL_SLE_UNITS	0x00000008	/* [5211+] */
-/* more bits */
+#define AR5K_SLEEP_CTL_DUR_TIM_POL	0x00040000	/* Sleep duration timing policy */
+#define AR5K_SLEEP_CTL_DUR_WRITE_POL	0x00080000	/* Sleep duration write policy */
+#define AR5K_SLEEP_CTL_SLE_POL		0x00100000	/* Sleep policy mode */
 
 /*
  * Interrupt pending register
@@ -851,27 +871,28 @@
 
 /*
  * PCI configuration register
+ * TODO: Fix LED stuff
  */
 #define AR5K_PCICFG			0x4010			/* Register Address */
 #define AR5K_PCICFG_EEAE		0x00000001	/* Eeprom access enable [5210] */
-#define	AR5K_PCICFG_SLEEP_CLOCK_EN	0x00000002	/* Enable sleep clock (?) */
+#define AR5K_PCICFG_SLEEP_CLOCK_EN	0x00000002	/* Enable sleep clock */
 #define AR5K_PCICFG_CLKRUNEN		0x00000004	/* CLKRUN enable [5211+] */
 #define AR5K_PCICFG_EESIZE		0x00000018	/* Mask for EEPROM size [5211+] */
 #define AR5K_PCICFG_EESIZE_S		3
 #define AR5K_PCICFG_EESIZE_4K		0		/* 4K */
 #define AR5K_PCICFG_EESIZE_8K		1		/* 8K */
 #define AR5K_PCICFG_EESIZE_16K		2		/* 16K */
-#define AR5K_PCICFG_EESIZE_FAIL		3		/* Failed to get size (?) [5211+] */
+#define AR5K_PCICFG_EESIZE_FAIL		3		/* Failed to get size [5211+] */
 #define AR5K_PCICFG_LED			0x00000060	/* Led status [5211+] */
 #define AR5K_PCICFG_LED_NONE		0x00000000	/* Default [5211+] */
 #define AR5K_PCICFG_LED_PEND		0x00000020	/* Scan / Auth pending */
 #define AR5K_PCICFG_LED_ASSOC		0x00000040	/* Associated */
 #define	AR5K_PCICFG_BUS_SEL		0x00000380	/* Mask for "bus select" [5211+] (?) */
-#define	AR5K_PCICFG_CBEFIX_DIS		0x00000400	/* Disable CBE fix (?) */
-#define AR5K_PCICFG_SL_INTEN		0x00000800	/* Enable interrupts when asleep (?) */
+#define AR5K_PCICFG_CBEFIX_DIS		0x00000400	/* Disable CBE fix */
+#define AR5K_PCICFG_SL_INTEN		0x00000800	/* Enable interrupts when asleep */
 #define AR5K_PCICFG_LED_BCTL		0x00001000	/* Led blink (?) [5210] */
-#define	AR5K_PCICFG_UNK			0x00001000	/* Passed on some parts durring attach (?) */
-#define AR5K_PCICFG_SL_INPEN		0x00002000	/* Sleep even whith pending interrupts (?) */
+#define AR5K_PCICFG_RETRY_FIX		0x00001000	/* Enable pci core retry fix */
+#define AR5K_PCICFG_SL_INPEN		0x00002000	/* Sleep even whith pending interrupts*/
 #define AR5K_PCICFG_SPWR_DN		0x00010000	/* Mask for power status */
 #define AR5K_PCICFG_LEDMODE		0x000e0000	/* Ledmode [5211+] */
 #define AR5K_PCICFG_LEDMODE_PROP	0x00000000	/* Blink on standard traffic [5211+] */
@@ -884,7 +905,8 @@
 #define AR5K_PCICFG_LEDSTATE				\
 	(AR5K_PCICFG_LED | AR5K_PCICFG_LEDMODE |	\
 	AR5K_PCICFG_LEDBLINK | AR5K_PCICFG_LEDSLOW)
-#define	AR5K_PCICFG_SLEEP_CLOCK_RATE	0x03000000	/* Sleep clock rate (field) */
+#define	AR5K_PCICFG_SLEEP_CLOCK_RATE	0x03000000	/* Sleep clock rate */
+#define	AR5K_PCICFG_SLEEP_CLOCK_RATE_S	24
 
 /*
  * "General Purpose Input/Output" (GPIO) control register
@@ -906,8 +928,8 @@
 
 #define AR5K_GPIOCR		0x4014				/* Register Address */
 #define AR5K_GPIOCR_INT_ENA	0x00008000		/* Enable GPIO interrupt */
-#define AR5K_GPIOCR_INT_SELL	0x00000000		/* Generate interrupt when pin is off (?) */
-#define AR5K_GPIOCR_INT_SELH	0x00010000		/* Generate interrupt when pin is on */
+#define AR5K_GPIOCR_INT_SELL	0x00000000		/* Generate interrupt when pin is low */
+#define AR5K_GPIOCR_INT_SELH	0x00010000		/* Generate interrupt when pin is high */
 #define AR5K_GPIOCR_IN(n)	(0 << ((n) * 2))	/* Mode 0 for pin n */
 #define AR5K_GPIOCR_OUT0(n)	(1 << ((n) * 2))	/* Mode 1 for pin n */
 #define AR5K_GPIOCR_OUT1(n)	(2 << ((n) * 2))	/* Mode 2 for pin n */
@@ -925,7 +947,6 @@
 #define AR5K_GPIODI	0x401c
 #define AR5K_GPIODI_M	0x0000002f
 
-
 /*
  * Silicon revision register
  */
@@ -935,7 +956,59 @@
 #define AR5K_SREV_VER		0x000000ff	/* Mask for version */
 #define AR5K_SREV_VER_S		4
 
+/*
+ * TXE write posting register
+ */
+#define	AR5K_TXEPOST	0x4028
 
+/*
+ * QCU sleep mask
+ */
+#define	AR5K_QCU_SLEEP_MASK	0x402c
+
+/* 0x4068 is compression buffer configuration
+ * register on 5414 and pm configuration register
+ * on 5424 and newer pci-e chips. */
+
+/*
+ * Compression buffer configuration
+ * register (enable/disable) [5414]
+ */
+#define AR5K_5414_CBCFG		0x4068
+#define AR5K_5414_CBCFG_BUF_DIS	0x10	/* Disable buffer */
+
+/*
+ * PCI-E Power managment configuration
+ * and status register [5424+]
+ */
+#define	AR5K_PCIE_PM_CTL		0x4068			/* Register address */
+/* Only 5424 */
+#define	AR5K_PCIE_PM_CTL_L1_WHEN_D2	0x00000001	/* enable PCIe core enter L1
+							when d2_sleep_en is asserted */
+#define	AR5K_PCIE_PM_CTL_L0_L0S_CLEAR	0x00000002	/* Clear L0 and L0S counters */
+#define	AR5K_PCIE_PM_CTL_L0_L0S_EN	0x00000004	/* Start L0 nd L0S counters */
+#define	AR5K_PCIE_PM_CTL_LDRESET_EN	0x00000008	/* Enable reset when link goes
+							down */
+/* Wake On Wireless */
+#define	AR5K_PCIE_PM_CTL_PME_EN		0x00000010	/* PME Enable */
+#define	AR5K_PCIE_PM_CTL_AUX_PWR_DET	0x00000020	/* Aux power detect */
+#define	AR5K_PCIE_PM_CTL_PME_CLEAR	0x00000040	/* Clear PME */
+#define	AR5K_PCIE_PM_CTL_PSM_D0		0x00000080
+#define	AR5K_PCIE_PM_CTL_PSM_D1		0x00000100
+#define	AR5K_PCIE_PM_CTL_PSM_D2		0x00000200
+#define	AR5K_PCIE_PM_CTL_PSM_D3		0x00000400
+
+/*
+ * PCI-E Workaround enable register
+ */
+#define	AR5K_PCIE_WAEN	0x407c
+
+/*
+ * PCI-E Serializer/Desirializer
+ * registers
+ */
+#define	AR5K_PCIE_SERDES	0x4080
+#define	AR5K_PCIE_SERDES_RESET	0x4084
 
 /*====EEPROM REGISTERS====*/
 
@@ -977,98 +1050,6 @@
 #define AR5K_EEPROM_BASE	0x6000
 
 /*
- * Common ar5xxx EEPROM data offsets (set these on AR5K_EEPROM_BASE)
- */
-#define AR5K_EEPROM_MAGIC		0x003d	/* EEPROM Magic number */
-#define AR5K_EEPROM_MAGIC_VALUE		0x5aa5	/* Default - found on EEPROM */
-#define AR5K_EEPROM_MAGIC_5212		0x0000145c /* 5212 */
-#define AR5K_EEPROM_MAGIC_5211		0x0000145b /* 5211 */
-#define AR5K_EEPROM_MAGIC_5210		0x0000145a /* 5210 */
-
-#define AR5K_EEPROM_PROTECT		0x003f	/* EEPROM protect status */
-#define AR5K_EEPROM_PROTECT_RD_0_31	0x0001	/* Read protection bit for offsets 0x0 - 0x1f */
-#define AR5K_EEPROM_PROTECT_WR_0_31	0x0002	/* Write protection bit for offsets 0x0 - 0x1f */
-#define AR5K_EEPROM_PROTECT_RD_32_63	0x0004	/* 0x20 - 0x3f */
-#define AR5K_EEPROM_PROTECT_WR_32_63	0x0008
-#define AR5K_EEPROM_PROTECT_RD_64_127	0x0010	/* 0x40 - 0x7f */
-#define AR5K_EEPROM_PROTECT_WR_64_127	0x0020
-#define AR5K_EEPROM_PROTECT_RD_128_191	0x0040	/* 0x80 - 0xbf (regdom) */
-#define AR5K_EEPROM_PROTECT_WR_128_191	0x0080
-#define AR5K_EEPROM_PROTECT_RD_192_207	0x0100	/* 0xc0 - 0xcf */
-#define AR5K_EEPROM_PROTECT_WR_192_207	0x0200
-#define AR5K_EEPROM_PROTECT_RD_208_223	0x0400	/* 0xd0 - 0xdf */
-#define AR5K_EEPROM_PROTECT_WR_208_223	0x0800
-#define AR5K_EEPROM_PROTECT_RD_224_239	0x1000	/* 0xe0 - 0xef */
-#define AR5K_EEPROM_PROTECT_WR_224_239	0x2000
-#define AR5K_EEPROM_PROTECT_RD_240_255	0x4000	/* 0xf0 - 0xff */
-#define AR5K_EEPROM_PROTECT_WR_240_255	0x8000
-#define AR5K_EEPROM_REG_DOMAIN		0x00bf	/* EEPROM regdom */
-#define AR5K_EEPROM_INFO_BASE		0x00c0	/* EEPROM header */
-#define AR5K_EEPROM_INFO_MAX		(0x400 - AR5K_EEPROM_INFO_BASE)
-#define AR5K_EEPROM_INFO_CKSUM		0xffff
-#define AR5K_EEPROM_INFO(_n)		(AR5K_EEPROM_INFO_BASE + (_n))
-
-#define AR5K_EEPROM_VERSION		AR5K_EEPROM_INFO(1)	/* EEPROM Version */
-#define AR5K_EEPROM_VERSION_3_0		0x3000	/* No idea what's going on before this version */
-#define AR5K_EEPROM_VERSION_3_1		0x3001	/* ob/db values for 2Ghz (ar5211_rfregs) */
-#define AR5K_EEPROM_VERSION_3_2		0x3002	/* different frequency representation (eeprom_bin2freq) */
-#define AR5K_EEPROM_VERSION_3_3		0x3003	/* offsets changed, has 32 CTLs (see below) and ee_false_detect (eeprom_read_modes) */
-#define AR5K_EEPROM_VERSION_3_4		0x3004	/* has ee_i_gain ee_cck_ofdm_power_delta (eeprom_read_modes) */
-#define AR5K_EEPROM_VERSION_4_0		0x4000	/* has ee_misc*, ee_cal_pier, ee_turbo_max_power and ee_xr_power (eeprom_init) */
-#define AR5K_EEPROM_VERSION_4_1		0x4001	/* has ee_margin_tx_rx (eeprom_init) */
-#define AR5K_EEPROM_VERSION_4_2		0x4002	/* has ee_cck_ofdm_gain_delta (eeprom_init) */
-#define AR5K_EEPROM_VERSION_4_3		0x4003
-#define AR5K_EEPROM_VERSION_4_4		0x4004
-#define AR5K_EEPROM_VERSION_4_5		0x4005
-#define AR5K_EEPROM_VERSION_4_6		0x4006	/* has ee_scaled_cck_delta */
-#define AR5K_EEPROM_VERSION_4_7		0x4007
-
-#define AR5K_EEPROM_MODE_11A		0
-#define AR5K_EEPROM_MODE_11B		1
-#define AR5K_EEPROM_MODE_11G		2
-
-#define AR5K_EEPROM_HDR			AR5K_EEPROM_INFO(2)	/* Header that contains the device caps */
-#define AR5K_EEPROM_HDR_11A(_v)		(((_v) >> AR5K_EEPROM_MODE_11A) & 0x1)
-#define AR5K_EEPROM_HDR_11B(_v)		(((_v) >> AR5K_EEPROM_MODE_11B) & 0x1)
-#define AR5K_EEPROM_HDR_11G(_v)		(((_v) >> AR5K_EEPROM_MODE_11G) & 0x1)
-#define AR5K_EEPROM_HDR_T_2GHZ_DIS(_v)	(((_v) >> 3) & 0x1)	/* Disable turbo for 2Ghz (?) */
-#define AR5K_EEPROM_HDR_T_5GHZ_DBM(_v)	(((_v) >> 4) & 0x7f)	/* Max turbo power for a/XR mode (eeprom_init) */
-#define AR5K_EEPROM_HDR_DEVICE(_v)	(((_v) >> 11) & 0x7)
-#define AR5K_EEPROM_HDR_T_5GHZ_DIS(_v)	(((_v) >> 15) & 0x1)	/* Disable turbo for 5Ghz (?) */
-#define AR5K_EEPROM_HDR_RFKILL(_v)	(((_v) >> 14) & 0x1)	/* Device has RFKill support */
-
-#define AR5K_EEPROM_RFKILL_GPIO_SEL	0x0000001c
-#define AR5K_EEPROM_RFKILL_GPIO_SEL_S	2
-#define AR5K_EEPROM_RFKILL_POLARITY	0x00000002
-#define AR5K_EEPROM_RFKILL_POLARITY_S	1
-
-/* Newer EEPROMs are using a different offset */
-#define AR5K_EEPROM_OFF(_v, _v3_0, _v3_3) \
-	(((_v) >= AR5K_EEPROM_VERSION_3_3) ? _v3_3 : _v3_0)
-
-#define AR5K_EEPROM_ANT_GAIN(_v)	AR5K_EEPROM_OFF(_v, 0x00c4, 0x00c3)
-#define AR5K_EEPROM_ANT_GAIN_5GHZ(_v)	((int8_t)(((_v) >> 8) & 0xff))
-#define AR5K_EEPROM_ANT_GAIN_2GHZ(_v)	((int8_t)((_v) & 0xff))
-
-/* calibration settings */
-#define AR5K_EEPROM_MODES_11A(_v)	AR5K_EEPROM_OFF(_v, 0x00c5, 0x00d4)
-#define AR5K_EEPROM_MODES_11B(_v)	AR5K_EEPROM_OFF(_v, 0x00d0, 0x00f2)
-#define AR5K_EEPROM_MODES_11G(_v)	AR5K_EEPROM_OFF(_v, 0x00da, 0x010d)
-#define AR5K_EEPROM_CTL(_v)		AR5K_EEPROM_OFF(_v, 0x00e4, 0x0128)	/* Conformance test limits */
-
-/* [3.1 - 3.3] */
-#define AR5K_EEPROM_OBDB0_2GHZ		0x00ec
-#define AR5K_EEPROM_OBDB1_2GHZ		0x00ed
-
-/* Misc values available since EEPROM 4.0 */
-#define AR5K_EEPROM_MISC0		0x00c4
-#define AR5K_EEPROM_EARSTART(_v)	((_v) & 0xfff)
-#define AR5K_EEPROM_EEMAP(_v)		(((_v) >> 14) & 0x3)
-#define AR5K_EEPROM_MISC1		0x00c5
-#define AR5K_EEPROM_TARGET_PWRSTART(_v)	((_v) & 0xfff)
-#define AR5K_EEPROM_HAS32KHZCRYSTAL(_v)	(((_v) >> 14) & 0x1)
-
-/*
  * EEPROM data register
  */
 #define AR5K_EEPROM_DATA_5211	0x6004
@@ -1100,14 +1081,28 @@
  * EEPROM config register
  */
 #define AR5K_EEPROM_CFG			0x6010			/* Register Addres */
-#define AR5K_EEPROM_CFG_SIZE_OVR	0x00000001
+#define AR5K_EEPROM_CFG_SIZE		0x00000003		/* Size determination override */
+#define AR5K_EEPROM_CFG_SIZE_AUTO	0
+#define AR5K_EEPROM_CFG_SIZE_4KBIT	1
+#define AR5K_EEPROM_CFG_SIZE_8KBIT	2
+#define AR5K_EEPROM_CFG_SIZE_16KBIT	3
 #define AR5K_EEPROM_CFG_WR_WAIT_DIS	0x00000004	/* Disable write wait */
 #define AR5K_EEPROM_CFG_CLK_RATE	0x00000018	/* Clock rate */
-#define AR5K_EEPROM_CFG_PROT_KEY	0x00ffff00	/* Protectio key */
+#define AR5K_EEPROM_CFG_CLK_RATE_S		3
+#define AR5K_EEPROM_CFG_CLK_RATE_156KHZ	0
+#define AR5K_EEPROM_CFG_CLK_RATE_312KHZ	1
+#define AR5K_EEPROM_CFG_CLK_RATE_625KHZ	2
+#define AR5K_EEPROM_CFG_PROT_KEY	0x00ffff00      /* Protection key */
+#define AR5K_EEPROM_CFG_PROT_KEY_S	8
 #define AR5K_EEPROM_CFG_LIND_EN		0x01000000	/* Enable length indicator (?) */
 
 
 /*
+ * TODO: Wake On Wireless registers
+ * Range 0x7000 - 0x7ce0
+ */
+
+/*
  * Protocol Control Unit (PCU) registers
  */
 /*
@@ -1139,11 +1134,13 @@
 #define AR5K_STA_ID1_DESC_ANTENNA	0x00400000	/* Update antenna from descriptor */
 #define AR5K_STA_ID1_RTS_DEF_ANTENNA	0x00800000	/* Use default antenna for RTS */
 #define AR5K_STA_ID1_ACKCTS_6MB		0x01000000	/* Use 6Mbit/s for ACK/CTS */
-#define AR5K_STA_ID1_BASE_RATE_11B	0x02000000	/* Use 11b base rate (for ACK/CTS ?) [5211+] */
-#define AR5K_STA_ID1_SELF_GEN_SECTORE	0x04000000	/* Self generate sectore (?) */
+#define AR5K_STA_ID1_BASE_RATE_11B	0x02000000	/* Use 11b base rate for ACK/CTS [5211+] */
+#define AR5K_STA_ID1_SELFGEN_DEF_ANT	0x04000000	/* Use def. antenna for self generated frames */
 #define AR5K_STA_ID1_CRYPT_MIC_EN	0x08000000	/* Enable MIC */
-#define AR5K_STA_ID1_KEYSRCH_MODE	0x10000000	/* Keysearch mode (?) */
+#define AR5K_STA_ID1_KEYSRCH_MODE	0x10000000	/* Look up key when key id != 0 */
 #define AR5K_STA_ID1_PRESERVE_SEQ_NUM	0x20000000	/* Preserve sequence number */
+#define AR5K_STA_ID1_CBCIV_ENDIAN	0x40000000	/* ??? */
+#define AR5K_STA_ID1_KEYSRCH_MCAST	0x80000000	/* Do key cache search for mcast frames */
 
 /*
  * First BSSID register (MAC address, lower 32bits)
@@ -1402,16 +1399,16 @@
 #define AR5K_DIAG_SW_LOOP_BACK_5211	0x00000040
 #define AR5K_DIAG_SW_LOOP_BACK		(ah->ah_version == AR5K_AR5210 ? \
 					AR5K_DIAG_SW_LOOP_BACK_5210 : AR5K_DIAG_SW_LOOP_BACK_5211)
-#define AR5K_DIAG_SW_CORR_FCS_5210	0x00000100
+#define AR5K_DIAG_SW_CORR_FCS_5210	0x00000100	/* Corrupted FCS */
 #define AR5K_DIAG_SW_CORR_FCS_5211	0x00000080
 #define AR5K_DIAG_SW_CORR_FCS		(ah->ah_version == AR5K_AR5210 ? \
 					AR5K_DIAG_SW_CORR_FCS_5210 : AR5K_DIAG_SW_CORR_FCS_5211)
-#define AR5K_DIAG_SW_CHAN_INFO_5210	0x00000200
+#define AR5K_DIAG_SW_CHAN_INFO_5210	0x00000200	/* Dump channel info */
 #define AR5K_DIAG_SW_CHAN_INFO_5211	0x00000100
 #define AR5K_DIAG_SW_CHAN_INFO		(ah->ah_version == AR5K_AR5210 ? \
 					AR5K_DIAG_SW_CHAN_INFO_5210 : AR5K_DIAG_SW_CHAN_INFO_5211)
-#define AR5K_DIAG_SW_EN_SCRAM_SEED_5211	0x00000200	/* Enable scrambler seed */
-#define AR5K_DIAG_SW_EN_SCRAM_SEED_5210	0x00000400
+#define AR5K_DIAG_SW_EN_SCRAM_SEED_5210	0x00000400	/* Enable fixed scrambler seed */
+#define AR5K_DIAG_SW_EN_SCRAM_SEED_5211	0x00000200
 #define AR5K_DIAG_SW_EN_SCRAM_SEED	(ah->ah_version == AR5K_AR5210 ? \
 					AR5K_DIAG_SW_EN_SCRAM_SEED_5210 : AR5K_DIAG_SW_EN_SCRAM_SEED_5211)
 #define AR5K_DIAG_SW_ECO_ENABLE		0x00000400	/* [5211+] */
@@ -1420,12 +1417,15 @@
 #define AR5K_DIAG_SW_SCRAM_SEED_S	10
 #define AR5K_DIAG_SW_DIS_SEQ_INC	0x00040000	/* Disable seqnum increment (?)[5210] */
 #define AR5K_DIAG_SW_FRAME_NV0_5210	0x00080000
-#define AR5K_DIAG_SW_FRAME_NV0_5211	0x00020000
+#define AR5K_DIAG_SW_FRAME_NV0_5211	0x00020000	/* Accept frames of non-zero protocol number */
 #define	AR5K_DIAG_SW_FRAME_NV0		(ah->ah_version == AR5K_AR5210 ? \
 					AR5K_DIAG_SW_FRAME_NV0_5210 : AR5K_DIAG_SW_FRAME_NV0_5211)
-#define AR5K_DIAG_SW_OBSPT_M		0x000c0000
+#define AR5K_DIAG_SW_OBSPT_M		0x000c0000	/* Observation point select (?) */
 #define AR5K_DIAG_SW_OBSPT_S		18
-/* more bits */
+#define AR5K_DIAG_SW_RX_CLEAR_HIGH	0x0010000	/* Force RX Clear high */
+#define AR5K_DIAG_SW_IGNORE_CARR_SENSE	0x0020000	/* Ignore virtual carrier sense */
+#define AR5K_DIAG_SW_CHANEL_IDLE_HIGH	0x0040000	/* Force channel idle high */
+#define AR5K_DIAG_SW_PHEAR_ME		0x0080000	/* ??? */
 
 /*
  * TSF (clock) register (lower 32 bits)
@@ -1636,16 +1636,16 @@
  *
  * XXX: PCDAC steps (0.5dbm) or DBM ?
  *
- * XXX: Mask changes for newer chips to 7f
- *      like tx power table ?
  */
 #define AR5K_TXPC			0x80e8			/* Register Address */
-#define AR5K_TXPC_ACK_M			0x0000003f	/* Mask for ACK tx power */
+#define AR5K_TXPC_ACK_M			0x0000003f	/* ACK tx power */
 #define AR5K_TXPC_ACK_S			0
-#define AR5K_TXPC_CTS_M			0x00003f00	/* Mask for CTS tx power */
+#define AR5K_TXPC_CTS_M			0x00003f00	/* CTS tx power */
 #define AR5K_TXPC_CTS_S			8
-#define AR5K_TXPC_CHIRP_M		0x003f0000	/* Mask for CHIRP tx power */
-#define AR5K_TXPC_CHIRP_S		22
+#define AR5K_TXPC_CHIRP_M		0x003f0000	/* CHIRP tx power */
+#define AR5K_TXPC_CHIRP_S		16
+#define AR5K_TXPC_DOPPLER		0x0f000000	/* Doppler chirp span (?) */
+#define AR5K_TXPC_DOPPLER_S		24
 
 /*
  * Profile count registers
@@ -1656,14 +1656,19 @@
 #define AR5K_PROFCNT_CYCLE		0x80f8	/* Cycle count (?) */
 
 /*
- * Quiet (period) control registers (?)
+ * Quiet period control registers
  */
 #define AR5K_QUIET_CTL1			0x80fc			/* Register Address */
-#define AR5K_QUIET_CTL1_NEXT_QT		0x0000ffff	/* Mask for next quiet (period?) (?) */
-#define AR5K_QUIET_CTL1_QT_EN		0x00010000	/* Enable quiet (period?) */
+#define AR5K_QUIET_CTL1_NEXT_QT_TSF	0x0000ffff	/* Next quiet period TSF (TU) */
+#define AR5K_QUIET_CTL1_NEXT_QT_TSF_S	0
+#define AR5K_QUIET_CTL1_QT_EN		0x00010000	/* Enable quiet period */
+#define AR5K_QUIET_CTL1_ACK_CTS_EN	0x00020000	/* Send ACK/CTS during quiet period */
+
 #define AR5K_QUIET_CTL2			0x8100			/* Register Address */
-#define AR5K_QUIET_CTL2_QT_PER		0x0000ffff	/* Mask for quiet period (?) */
-#define AR5K_QUIET_CTL2_QT_DUR		0xffff0000	/* Mask for quiet duration (?) */
+#define AR5K_QUIET_CTL2_QT_PER		0x0000ffff	/* Mask for quiet period periodicity */
+#define AR5K_QUIET_CTL2_QT_PER_S	0
+#define AR5K_QUIET_CTL2_QT_DUR		0xffff0000	/* Mask for quiet period duration */
+#define AR5K_QUIET_CTL2_QT_DUR_S	16
 
 /*
  * TSF parameter register
@@ -1673,12 +1678,15 @@
 #define AR5K_TSF_PARM_INC_S		0
 
 /*
- * QoS register (?)
+ * QoS NOACK policy
  */
-#define AR5K_QOS			0x8108			/* Register Address */
-#define AR5K_QOS_NOACK_2BIT_VALUES	0x00000000	/* (field) */
-#define AR5K_QOS_NOACK_BIT_OFFSET	0x00000020	/* (field) */
-#define AR5K_QOS_NOACK_BYTE_OFFSET	0x00000080	/* (field) */
+#define AR5K_QOS_NOACK			0x8108			/* Register Address */
+#define AR5K_QOS_NOACK_2BIT_VALUES	0x0000000f	/* ??? */
+#define AR5K_QOS_NOACK_2BIT_VALUES_S	0
+#define AR5K_QOS_NOACK_BIT_OFFSET	0x00000070	/* ??? */
+#define AR5K_QOS_NOACK_BIT_OFFSET_S	4
+#define AR5K_QOS_NOACK_BYTE_OFFSET	0x00000180	/* ??? */
+#define AR5K_QOS_NOACK_BYTE_OFFSET_S	8
 
 /*
  * PHY error filter register
@@ -1702,29 +1710,15 @@
 /*
  * MIC QoS control register (?)
  */
-#define	AR5K_MIC_QOS_CTL	0x8118			/* Register Address */
-#define	AR5K_MIC_QOS_CTL_0	0x00000001	/* MIC QoS control 0 (?) */
-#define	AR5K_MIC_QOS_CTL_1	0x00000004	/* MIC QoS control 1 (?) */
-#define	AR5K_MIC_QOS_CTL_2	0x00000010	/* MIC QoS control 2 (?) */
-#define	AR5K_MIC_QOS_CTL_3	0x00000040	/* MIC QoS control 3 (?) */
-#define	AR5K_MIC_QOS_CTL_4	0x00000100	/* MIC QoS control 4 (?) */
-#define	AR5K_MIC_QOS_CTL_5	0x00000400	/* MIC QoS control 5 (?) */
-#define	AR5K_MIC_QOS_CTL_6	0x00001000	/* MIC QoS control 6 (?) */
-#define	AR5K_MIC_QOS_CTL_7	0x00004000	/* MIC QoS control 7 (?) */
-#define	AR5K_MIC_QOS_CTL_MQ_EN	0x00010000	/* Enable MIC QoS */
+#define	AR5K_MIC_QOS_CTL		0x8118			/* Register Address */
+#define	AR5K_MIC_QOS_CTL_OFF(_n)	(1 << (_n * 2))
+#define	AR5K_MIC_QOS_CTL_MQ_EN		0x00010000	/* Enable MIC QoS */
 
 /*
  * MIC QoS select register (?)
  */
-#define	AR5K_MIC_QOS_SEL	0x811c
-#define	AR5K_MIC_QOS_SEL_0	0x00000001
-#define	AR5K_MIC_QOS_SEL_1	0x00000010
-#define	AR5K_MIC_QOS_SEL_2	0x00000100
-#define	AR5K_MIC_QOS_SEL_3	0x00001000
-#define	AR5K_MIC_QOS_SEL_4	0x00010000
-#define	AR5K_MIC_QOS_SEL_5	0x00100000
-#define	AR5K_MIC_QOS_SEL_6	0x01000000
-#define	AR5K_MIC_QOS_SEL_7	0x10000000
+#define	AR5K_MIC_QOS_SEL		0x811c
+#define	AR5K_MIC_QOS_SEL_OFF(_n)	(1 << (_n * 4))
 
 /*
  * Misc mode control register (?)
@@ -1759,6 +1753,11 @@
 #define	AR5K_TSF_THRES			0x813c
 
 /*
+ * TODO: Wake On Wireless registers
+ * Range: 0x8147 - 0x818c
+ */
+
+/*
  * Rate -> ACK SIFS mapping table (32 entries)
  */
 #define	AR5K_RATE_ACKSIFS_BASE		0x8680			/* Register Address */
@@ -1873,7 +1872,8 @@
  */
 #define	AR5K_PHY_TURBO			0x9804			/* Register Address */
 #define	AR5K_PHY_TURBO_MODE		0x00000001	/* Enable turbo mode */
-#define	AR5K_PHY_TURBO_SHORT		0x00000002	/* Short mode (20Mhz channels) (?) */
+#define	AR5K_PHY_TURBO_SHORT		0x00000002	/* Set short symbols to turbo mode */
+#define	AR5K_PHY_TURBO_MIMO		0x00000004	/* Set turbo for mimo mimo */
 
 /*
  * PHY agility command register
@@ -1883,6 +1883,11 @@
 #define	AR5K_PHY_TST1			0x9808
 #define	AR5K_PHY_AGC_DISABLE		0x08000000	/* Disable AGC to A2 (?)*/
 #define	AR5K_PHY_TST1_TXHOLD		0x00003800	/* Set tx hold (?) */
+#define	AR5K_PHY_TST1_TXSRC_SRC		0x00000002	/* Used with bit 7 (?) */
+#define	AR5K_PHY_TST1_TXSRC_SRC_S	1
+#define	AR5K_PHY_TST1_TXSRC_ALT		0x00000080	/* Set input to tsdac (?) */
+#define	AR5K_PHY_TST1_TXSRC_ALT_S	7
+
 
 /*
  * PHY timing register 3 [5112+]
@@ -1907,15 +1912,23 @@
 
 /*
  * PHY RF control registers
- * (i think these are delay times,
- * these calibration values exist
- * in EEPROM)
  */
 #define AR5K_PHY_RF_CTL2		0x9824			/* Register Address */
-#define	AR5K_PHY_RF_CTL2_TXF2TXD_START	0x0000000f	/* Mask for TX frame to TX d(esc?) start */
+#define	AR5K_PHY_RF_CTL2_TXF2TXD_START	0x0000000f	/* TX frame to TX data start */
+#define	AR5K_PHY_RF_CTL2_TXF2TXD_START_S	0
 
 #define AR5K_PHY_RF_CTL3		0x9828			/* Register Address */
-#define AR5K_PHY_RF_CTL3_TXE2XLNA_ON	0x0000000f	/* Mask for TX end to XLNA on */
+#define AR5K_PHY_RF_CTL3_TXE2XLNA_ON	0x0000000f	/* TX end to XLNA on */
+#define	AR5K_PHY_RF_CTL3_TXE2XLNA_ON_S	0
+
+#define	AR5K_PHY_ADC_CTL			0x982c
+#define	AR5K_PHY_ADC_CTL_INBUFGAIN_OFF		0x00000003
+#define	AR5K_PHY_ADC_CTL_INBUFGAIN_OFF_S	0
+#define	AR5K_PHY_ADC_CTL_PWD_DAC_OFF		0x00002000
+#define	AR5K_PHY_ADC_CTL_PWD_BAND_GAP_OFF	0x00004000
+#define	AR5K_PHY_ADC_CTL_PWD_ADC_OFF		0x00008000
+#define	AR5K_PHY_ADC_CTL_INBUFGAIN_ON		0x00030000
+#define	AR5K_PHY_ADC_CTL_INBUFGAIN_ON_S		16
 
 #define AR5K_PHY_RF_CTL4		0x9834			/* Register Address */
 #define AR5K_PHY_RF_CTL4_TXF2XPA_A_ON	0x00000001	/* TX frame to XPA A on (field) */
@@ -1937,35 +1950,43 @@
  * PHY settling register
  */
 #define AR5K_PHY_SETTLING		0x9844			/* Register Address */
-#define	AR5K_PHY_SETTLING_AGC		0x0000007f	/* Mask for AGC settling time */
-#define	AR5K_PHY_SETTLING_SWITCH	0x00003f80	/* Mask for Switch settlig time */
+#define	AR5K_PHY_SETTLING_AGC		0x0000007f	/* AGC settling time */
+#define	AR5K_PHY_SETTLING_AGC_S		0
+#define	AR5K_PHY_SETTLING_SWITCH	0x00003f80	/* Switch settlig time */
+#define	AR5K_PHY_SETTLINK_SWITCH_S	7
 
 /*
  * PHY Gain registers
  */
 #define AR5K_PHY_GAIN			0x9848			/* Register Address */
-#define	AR5K_PHY_GAIN_TXRX_ATTEN	0x0003f000	/* Mask for TX-RX Attenuation */
+#define	AR5K_PHY_GAIN_TXRX_ATTEN	0x0003f000	/* TX-RX Attenuation */
+#define	AR5K_PHY_GAIN_TXRX_ATTEN_S	12
+#define	AR5K_PHY_GAIN_TXRX_RF_MAX	0x007c0000
+#define	AR5K_PHY_GAIN_TXRX_RF_MAX_S	18
 
 #define	AR5K_PHY_GAIN_OFFSET		0x984c			/* Register Address */
 #define	AR5K_PHY_GAIN_OFFSET_RXTX_FLAG	0x00020000	/* RX-TX flag (?) */
 
 /*
- * Desired size register
+ * Desired ADC/PGA size register
  * (for more infos read ANI patent)
  */
 #define AR5K_PHY_DESIRED_SIZE		0x9850			/* Register Address */
-#define	AR5K_PHY_DESIRED_SIZE_ADC	0x000000ff	/* Mask for ADC desired size */
-#define	AR5K_PHY_DESIRED_SIZE_PGA	0x0000ff00	/* Mask for PGA desired size */
-#define	AR5K_PHY_DESIRED_SIZE_TOT	0x0ff00000	/* Mask for Total desired size (?) */
+#define	AR5K_PHY_DESIRED_SIZE_ADC	0x000000ff	/* ADC desired size */
+#define	AR5K_PHY_DESIRED_SIZE_ADC_S	0
+#define	AR5K_PHY_DESIRED_SIZE_PGA	0x0000ff00	/* PGA desired size */
+#define	AR5K_PHY_DESIRED_SIZE_PGA_S	8
+#define	AR5K_PHY_DESIRED_SIZE_TOT	0x0ff00000	/* Total desired size */
+#define	AR5K_PHY_DESIRED_SIZE_TOT_S	20
 
 /*
  * PHY signal register
  * (for more infos read ANI patent)
  */
 #define	AR5K_PHY_SIG			0x9858			/* Register Address */
-#define	AR5K_PHY_SIG_FIRSTEP		0x0003f000	/* Mask for FIRSTEP */
+#define	AR5K_PHY_SIG_FIRSTEP		0x0003f000	/* FIRSTEP */
 #define	AR5K_PHY_SIG_FIRSTEP_S		12
-#define	AR5K_PHY_SIG_FIRPWR		0x03fc0000	/* Mask for FIPWR */
+#define	AR5K_PHY_SIG_FIRPWR		0x03fc0000	/* FIPWR */
 #define	AR5K_PHY_SIG_FIRPWR_S		18
 
 /*
@@ -1973,9 +1994,9 @@
  * (for more infos read ANI patent)
  */
 #define	AR5K_PHY_AGCCOARSE		0x985c			/* Register Address */
-#define	AR5K_PHY_AGCCOARSE_LO		0x00007f80	/* Mask for AGC Coarse low */
+#define	AR5K_PHY_AGCCOARSE_LO		0x00007f80	/* AGC Coarse low */
 #define	AR5K_PHY_AGCCOARSE_LO_S		7
-#define	AR5K_PHY_AGCCOARSE_HI		0x003f8000	/* Mask for AGC Coarse high */
+#define	AR5K_PHY_AGCCOARSE_HI		0x003f8000	/* AGC Coarse high */
 #define	AR5K_PHY_AGCCOARSE_HI_S		15
 
 /*
@@ -1984,6 +2005,8 @@
 #define	AR5K_PHY_AGCCTL			0x9860			/* Register address */
 #define	AR5K_PHY_AGCCTL_CAL		0x00000001	/* Enable PHY calibration */
 #define	AR5K_PHY_AGCCTL_NF		0x00000002	/* Enable Noise Floor calibration */
+#define	AR5K_PHY_AGCCTL_NF_EN		0x00008000	/* Enable nf calibration to happen (?) */
+#define	AR5K_PHY_AGCCTL_NF_NOUPDATE	0x00020000	/* Don't update nf automaticaly */
 
 /*
  * PHY noise floor status register
@@ -1994,7 +2017,10 @@
 #define AR5K_PHY_NF_RVAL(_n)		(((_n) >> 19) & AR5K_PHY_NF_M)
 #define AR5K_PHY_NF_AVAL(_n)		(-((_n) ^ AR5K_PHY_NF_M) + 1)
 #define AR5K_PHY_NF_SVAL(_n)		(((_n) & AR5K_PHY_NF_M) | (1 << 9))
-#define	AR5K_PHY_NF_THRESH62		0x00001000	/* Thresh62 -check ANI patent- (field) */
+#define	AR5K_PHY_NF_THRESH62		0x0007f000	/* Thresh62 -check ANI patent- (field) */
+#define	AR5K_PHY_NF_THRESH62_S		12
+#define	AR5K_PHY_NF_MINCCA_PWR		0x0ff80000	/* ??? */
+#define	AR5K_PHY_NF_MINCCA_PWR_S	19
 
 /*
  * PHY ADC saturation register [5110]
@@ -2034,24 +2060,31 @@
  */
 #define AR5K_PHY_SCR			0x9870
 #define AR5K_PHY_SCR_32MHZ		0x0000001f
+
 #define AR5K_PHY_SLMT			0x9874
 #define AR5K_PHY_SLMT_32MHZ		0x0000007f
+
 #define AR5K_PHY_SCAL			0x9878
 #define AR5K_PHY_SCAL_32MHZ		0x0000000e
 
+
 /*
  * PHY PLL (Phase Locked Loop) control register
  */
 #define	AR5K_PHY_PLL			0x987c
-#define	AR5K_PHY_PLL_20MHZ		0x13	/* For half rate (?) [5111+] */
-#define	AR5K_PHY_PLL_40MHZ_5211		0x18	/* For 802.11a */
+#define	AR5K_PHY_PLL_20MHZ		0x00000013	/* For half rate (?) */
+/* 40MHz -> 5GHz band */
+#define	AR5K_PHY_PLL_40MHZ_5211		0x00000018
 #define	AR5K_PHY_PLL_40MHZ_5212		0x000000aa
+#define	AR5K_PHY_PLL_40MHZ_5413		0x00000004
 #define	AR5K_PHY_PLL_40MHZ		(ah->ah_version == AR5K_AR5211 ? \
 					AR5K_PHY_PLL_40MHZ_5211 : AR5K_PHY_PLL_40MHZ_5212)
-#define	AR5K_PHY_PLL_44MHZ_5211		0x19	/* For 802.11b/g */
+/* 44MHz -> 2.4GHz band */
+#define	AR5K_PHY_PLL_44MHZ_5211		0x00000019
 #define	AR5K_PHY_PLL_44MHZ_5212		0x000000ab
 #define	AR5K_PHY_PLL_44MHZ		(ah->ah_version == AR5K_AR5211 ? \
 					AR5K_PHY_PLL_44MHZ_5211 : AR5K_PHY_PLL_44MHZ_5212)
+
 #define AR5K_PHY_PLL_RF5111		0x00000000
 #define AR5K_PHY_PLL_RF5112		0x00000040
 #define	AR5K_PHY_PLL_HALF_RATE		0x00000100
@@ -2118,6 +2151,19 @@
 #define AR5K_PHY_RFSTG_DISABLE		0x00000021
 
 /*
+ * BIN masks (?)
+ */
+#define	AR5K_PHY_BIN_MASK_1	0x9900
+#define	AR5K_PHY_BIN_MASK_2	0x9904
+#define	AR5K_PHY_BIN_MASK_3	0x9908
+
+#define	AR5K_PHY_BIN_MASK_CTL		0x990c
+#define	AR5K_PHY_BIN_MASK_CTL_MASK_4	0x00003fff
+#define	AR5K_PHY_BIN_MASK_CTL_MASK_4_S	0
+#define	AR5K_PHY_BIN_MASK_CTL_RATE	0xff000000
+#define	AR5K_PHY_BIN_MASK_CTL_RATE_S	24
+
+/*
  * PHY Antenna control register
  */
 #define AR5K_PHY_ANT_CTL		0x9910			/* Register Address */
@@ -2164,6 +2210,7 @@
 #define	AR5K_PHY_OFDM_SELFCORR			0x9924			/* Register Address */
 #define	AR5K_PHY_OFDM_SELFCORR_CYPWR_THR1_EN	0x00000001	/* Enable cyclic RSSI thr 1 */
 #define	AR5K_PHY_OFDM_SELFCORR_CYPWR_THR1	0x000000fe	/* Mask for Cyclic RSSI threshold 1 */
+#define	AR5K_PHY_OFDM_SELFCORR_CYPWR_THR1_S	0
 #define	AR5K_PHY_OFDM_SELFCORR_CYPWR_THR3	0x00000100	/* Cyclic RSSI threshold 3 (field) (?) */
 #define	AR5K_PHY_OFDM_SELFCORR_RSSI_1ATHR_EN	0x00008000	/* Enable 1A RSSI threshold (?) */
 #define	AR5K_PHY_OFDM_SELFCORR_RSSI_1ATHR	0x00010000	/* 1A RSSI threshold (field) (?) */
@@ -2210,7 +2257,6 @@
 #define	AR5K_PHY_PAPD_PROBE_INI_5111	0x00004883	/* [5212+] */
 #define	AR5K_PHY_PAPD_PROBE_INI_5112	0x00004882	/* [5212+] */
 
-
 /*
  * PHY TX rate power registers [5112+]
  */
@@ -2232,6 +2278,8 @@
 #define	AR5K_PHY_FRAME_CTL_TX_CLIP	0x00000038	/* Mask for tx clip (?) */
 #define	AR5K_PHY_FRAME_CTL_TX_CLIP_S	3
 #define	AR5K_PHY_FRAME_CTL_PREP_CHINFO	0x00010000	/* Prepend chan info */
+#define	AR5K_PHY_FRAME_CTL_EMU		0x80000000
+#define	AR5K_PHY_FRAME_CTL_EMU_S	31
 /*---[5110/5111]---*/
 #define	AR5K_PHY_FRAME_CTL_TIMING_ERR	0x01000000	/* PHY timing error */
 #define	AR5K_PHY_FRAME_CTL_PARITY_ERR	0x02000000	/* Parity error */
@@ -2250,48 +2298,36 @@
  * PHY radar detection register [5111+]
  */
 #define	AR5K_PHY_RADAR			0x9954
-
-/* Radar enable 			........ ........ ........ .......1 */
 #define	AR5K_PHY_RADAR_ENABLE		0x00000001
-#define	AR5K_PHY_RADAR_DISABLE          0x00000000
-#define	AR5K_PHY_RADAR_ENABLE_S		0
-
-/* This is the value found on the card  .1.111.1 .1.1.... 111....1 1...1...
-at power on. */
-#define	AR5K_PHY_RADAR_PWONDEF_AR5213	0x5d50e188
-
-/* This is the value found on the card 	.1.1.111 ..11...1 .1...1.1 1...11.1
-after DFS is enabled */
-#define	AR5K_PHY_RADAR_ENABLED_AR5213	0x5731458d
-
-/* Finite Impulse Response (FIR) filter .1111111 ........ ........ ........
- * power out threshold.
- * 7-bits, standard power range {0..127} in 1/2 dBm units. */
-#define AR5K_PHY_RADAR_FIRPWROUTTHR    	0x7f000000
-#define AR5K_PHY_RADAR_FIRPWROUTTHR_S	24
-
-/* Radar RSSI/SNR threshold.		........ 111111.. ........ ........
- * 6-bits, dBm range {0..63} in dBm units. */
-#define AR5K_PHY_RADAR_RADARRSSITHR    	0x00fc0000
-#define AR5K_PHY_RADAR_RADARRSSITHR_S	18
-
-/* Pulse height threshold 		........ ......11 1111.... ........
- * 6-bits, dBm range {0..63} in dBm units. */
-#define AR5K_PHY_RADAR_PULSEHEIGHTTHR   0x0003f000
-#define AR5K_PHY_RADAR_PULSEHEIGHTTHR_S	12
-
-/* Pulse RSSI/SNR threshold		........ ........ ....1111 11......
- * 6-bits, dBm range {0..63} in dBm units. */
-#define AR5K_PHY_RADAR_PULSERSSITHR    	0x00000fc0
-#define AR5K_PHY_RADAR_PULSERSSITHR_S	6
-
-/* Inband threshold  			........ ........ ........ ..11111.
- * 5-bits, units unknown {0..31} (? MHz ?) */
-#define AR5K_PHY_RADAR_INBANDTHR    	0x0000003e
+#define	AR5K_PHY_RADAR_DISABLE		0x00000000
+#define AR5K_PHY_RADAR_INBANDTHR    	0x0000003e	/* Inband threshold
+							5-bits, units unknown {0..31}
+							(? MHz ?) */
 #define AR5K_PHY_RADAR_INBANDTHR_S	1
 
+#define AR5K_PHY_RADAR_PRSSI_THR    	0x00000fc0	/* Pulse RSSI/SNR threshold
+							6-bits, dBm range {0..63}
+							in dBm units. */
+#define AR5K_PHY_RADAR_PRSSI_THR_S	6
+
+#define AR5K_PHY_RADAR_PHEIGHT_THR   	0x0003f000	/* Pulse height threshold
+							6-bits, dBm range {0..63}
+							in dBm units. */
+#define AR5K_PHY_RADAR_PHEIGHT_THR_S	12
+
+#define AR5K_PHY_RADAR_RSSI_THR    	0x00fc0000	/* Radar RSSI/SNR threshold.
+							6-bits, dBm range {0..63}
+							in dBm units. */
+#define AR5K_PHY_RADAR_RSSI_THR_S	18
+
+#define AR5K_PHY_RADAR_FIRPWR_THR	0x7f000000	/* Finite Impulse Response
+							filter power out threshold.
+							7-bits, standard power range
+							{0..127} in 1/2 dBm units. */
+#define AR5K_PHY_RADAR_FIRPWR_THRS	24
+
 /*
- * PHY antenna switch table registers [5110]
+ * PHY antenna switch table registers
  */
 #define AR5K_PHY_ANT_SWITCH_TABLE_0	0x9960
 #define AR5K_PHY_ANT_SWITCH_TABLE_1	0x9964
@@ -2302,25 +2338,65 @@
 #define AR5K_PHY_NFTHRES		0x9968
 
 /*
- * PHY clock sleep registers [5112+]
+ * Sigma Delta register (?) [5213]
  */
-#define AR5K_PHY_SCLOCK			0x99f0
-#define AR5K_PHY_SCLOCK_32MHZ		0x0000000c
-#define AR5K_PHY_SDELAY			0x99f4
-#define AR5K_PHY_SDELAY_32MHZ		0x000000ff
-#define AR5K_PHY_SPENDING		0x99f8
-#define	AR5K_PHY_SPENDING_14		0x00000014
-#define	AR5K_PHY_SPENDING_18		0x00000018
-#define AR5K_PHY_SPENDING_RF5111	0x00000018
-#define AR5K_PHY_SPENDING_RF5112	0x00000014
-/* #define AR5K_PHY_SPENDING_RF5112A	0x0000000e */
-/* #define AR5K_PHY_SPENDING_RF5424	0x00000012 */
-#define	AR5K_PHY_SPENDING_RF5413	0x00000014
-#define	AR5K_PHY_SPENDING_RF2413	0x00000014
-#define AR5K_PHY_SPENDING_RF2425	0x00000018
+#define AR5K_PHY_SIGMA_DELTA		0x996C
+#define AR5K_PHY_SIGMA_DELTA_ADC_SEL	0x00000003
+#define AR5K_PHY_SIGMA_DELTA_ADC_SEL_S	0
+#define AR5K_PHY_SIGMA_DELTA_FILT2	0x000000f8
+#define AR5K_PHY_SIGMA_DELTA_FILT2_S	3
+#define AR5K_PHY_SIGMA_DELTA_FILT1	0x00001f00
+#define AR5K_PHY_SIGMA_DELTA_FILT1_S	8
+#define AR5K_PHY_SIGMA_DELTA_ADC_CLIP	0x01ff3000
+#define AR5K_PHY_SIGMA_DELTA_ADC_CLIP_S	13
 
 /*
- * Misc PHY/radio registers [5110 - 5111]
+ * RF restart register [5112+] (?)
+ */
+#define AR5K_PHY_RESTART		0x9970		/* restart */
+#define AR5K_PHY_RESTART_DIV_GC		0x001c0000	/* Fast diversity gc_limit (?) */
+#define AR5K_PHY_RESTART_DIV_GC_S	18
+
+/*
+ * RF Bus access request register (for synth-oly channel switching)
+ */
+#define AR5K_PHY_RFBUS_REQ		0x997C
+#define AR5K_PHY_RFBUS_REQ_REQUEST	0x00000001
+
+/*
+ * Spur mitigation masks (?)
+ */
+#define AR5K_PHY_TIMING_7		0x9980
+#define AR5K_PHY_TIMING_8		0x9984
+#define AR5K_PHY_TIMING_8_PILOT_MASK_2		0x000fffff
+#define AR5K_PHY_TIMING_8_PILOT_MASK_2_S	0
+
+#define AR5K_PHY_BIN_MASK2_1		0x9988
+#define AR5K_PHY_BIN_MASK2_2		0x998c
+#define AR5K_PHY_BIN_MASK2_3		0x9990
+
+#define AR5K_PHY_BIN_MASK2_4		0x9994
+#define AR5K_PHY_BIN_MASK2_4_MASK_4	0x00003fff
+#define AR5K_PHY_BIN_MASK2_4_MASK_4_S	0
+
+#define AR_PHY_TIMING_9			0x9998
+#define AR_PHY_TIMING_10		0x999c
+#define AR_PHY_TIMING_10_PILOT_MASK_2	0x000fffff
+#define AR_PHY_TIMING_10_PILOT_MASK_2_S	0
+
+/*
+ * Spur mitigation control
+ */
+#define AR_PHY_TIMING_11			0x99a0		/* Register address */
+#define AR_PHY_TIMING_11_SPUR_DELTA_PHASE	0x000fffff	/* Spur delta phase */
+#define AR_PHY_TIMING_11_SPUR_DELTA_PHASE_S	0
+#define AR_PHY_TIMING_11_SPUR_FREQ_SD		0x3ff00000	/* Freq sigma delta */
+#define AR_PHY_TIMING_11_SPUR_FREQ_SD_S	20
+#define AR_PHY_TIMING_11_USE_SPUR_IN_AGC	0x40000000	/* Spur filter in AGC detector */
+#define AR_PHY_TIMING_11_USE_SPUR_IN_SELFCOR	0x80000000	/* Spur filter in OFDM self correlator */
+
+/*
+ * Gain tables
  */
 #define	AR5K_BB_GAIN_BASE		0x9b00	/* BaseBand Amplifier Gain table base address */
 #define AR5K_BB_GAIN(_n)		(AR5K_BB_GAIN_BASE + ((_n) << 2))
@@ -2340,9 +2416,10 @@
 #define	AR5K_PHY_CURRENT_RSSI	0x9c1c
 
 /*
- * PHY RF Bus grant register (?)
+ * PHY RF Bus grant register
  */
 #define	AR5K_PHY_RFBUS_GRANT	0x9c20
+#define	AR5K_PHY_RFBUS_GRANT_OK	0x00000001
 
 /*
  * PHY ADC test register
@@ -2386,6 +2463,31 @@
 #define	AR5K_PHY_CHAN_STATUS_RX_CLR_PAP	0x00000008
 
 /*
+ * Heavy clip enable register
+ */
+#define	AR5K_PHY_HEAVY_CLIP_ENABLE	0x99e0
+
+/*
+ * PHY clock sleep registers [5112+]
+ */
+#define AR5K_PHY_SCLOCK			0x99f0
+#define AR5K_PHY_SCLOCK_32MHZ		0x0000000c
+#define AR5K_PHY_SDELAY			0x99f4
+#define AR5K_PHY_SDELAY_32MHZ		0x000000ff
+#define AR5K_PHY_SPENDING		0x99f8
+#define AR5K_PHY_SPENDING_14		0x00000014
+#define AR5K_PHY_SPENDING_18		0x00000018
+#define AR5K_PHY_SPENDING_RF5111	0x00000018
+#define AR5K_PHY_SPENDING_RF5112	0x00000014
+/* #define AR5K_PHY_SPENDING_RF5112A	0x0000000e */
+/* #define AR5K_PHY_SPENDING_RF5424	0x00000012 */
+#define AR5K_PHY_SPENDING_RF5413	0x00000018
+#define AR5K_PHY_SPENDING_RF2413	0x00000018
+#define AR5K_PHY_SPENDING_RF2316	0x00000018
+#define AR5K_PHY_SPENDING_RF2317	0x00000018
+#define AR5K_PHY_SPENDING_RF2425	0x00000014
+
+/*
  * PHY PAPD I (power?) table (?)
  * (92! entries)
  */
@@ -2436,10 +2538,47 @@
 #define AR5K_PHY_CCK_CROSSCORR_WEAK_SIG_THR	0x0000000f
 #define AR5K_PHY_CCK_CROSSCORR_WEAK_SIG_THR_S	0
 
+/* Same address is used for antenna diversity activation */
+#define	AR5K_PHY_FAST_ANT_DIV		0xa208
+#define	AR5K_PHY_FAST_ANT_DIV_EN	0x00002000
+
 /*
  * PHY 2GHz gain register [5111+]
  */
-#define	AR5K_PHY_GAIN_2GHZ		0xa20c
-#define	AR5K_PHY_GAIN_2GHZ_MARGIN_TXRX	0x00fc0000
+#define	AR5K_PHY_GAIN_2GHZ			0xa20c
+#define	AR5K_PHY_GAIN_2GHZ_MARGIN_TXRX		0x00fc0000
 #define	AR5K_PHY_GAIN_2GHZ_MARGIN_TXRX_S	18
-#define	AR5K_PHY_GAIN_2GHZ_INI_5111	0x6480416c
+#define	AR5K_PHY_GAIN_2GHZ_INI_5111		0x6480416c
+
+#define	AR5K_PHY_CCK_RX_CTL_4			0xa21c
+#define	AR5K_PHY_CCK_RX_CTL_4_FREQ_EST_SHORT	0x01f80000
+#define	AR5K_PHY_CCK_RX_CTL_4_FREQ_EST_SHORT_S	19
+
+#define	AR5K_PHY_DAG_CCK_CTL			0xa228
+#define	AR5K_PHY_DAG_CCK_CTL_EN_RSSI_THR	0x00000200
+#define	AR5K_PHY_DAG_CCK_CTL_RSSI_THR		0x0001fc00
+#define	AR5K_PHY_DAG_CCK_CTL_RSSI_THR_S		10
+
+#define	AR5K_PHY_FAST_ADC	0xa24c
+
+#define	AR5K_PHY_BLUETOOTH	0xa254
+
+/*
+ * Transmit Power Control register
+ * [2413+]
+ */
+#define	AR5K_PHY_TPC_RG1		0xa258
+#define	AR5K_PHY_TPC_RG1_NUM_PD_GAIN	0x0000c000
+#define	AR5K_PHY_TPC_RG1_NUM_PD_GAIN_S	14
+
+#define	AR5K_PHY_TPC_RG5			0xa26C
+#define	AR5K_PHY_TPC_RG5_PD_GAIN_OVERLAP	0x0000000F
+#define	AR5K_PHY_TPC_RG5_PD_GAIN_OVERLAP_S	0
+#define	AR5K_PHY_TPC_RG5_PD_GAIN_BOUNDARY_1	0x000003F0
+#define	AR5K_PHY_TPC_RG5_PD_GAIN_BOUNDARY_1_S	4
+#define	AR5K_PHY_TPC_RG5_PD_GAIN_BOUNDARY_2	0x0000FC00
+#define	AR5K_PHY_TPC_RG5_PD_GAIN_BOUNDARY_2_S	10
+#define	AR5K_PHY_TPC_RG5_PD_GAIN_BOUNDARY_3	0x003F0000
+#define	AR5K_PHY_TPC_RG5_PD_GAIN_BOUNDARY_3_S	16
+#define	AR5K_PHY_TPC_RG5_PD_GAIN_BOUNDARY_4	0x0FC00000
+#define	AR5K_PHY_TPC_RG5_PD_GAIN_BOUNDARY_4_S	22
diff --git a/drivers/net/wireless/ath5k/reset.c b/drivers/net/wireless/ath5k/reset.c
new file mode 100644
index 0000000..8f18868
--- /dev/null
+++ b/drivers/net/wireless/ath5k/reset.c
@@ -0,0 +1,931 @@
+/*
+ * Copyright (c) 2004-2008 Reyk Floeter <reyk@openbsd.org>
+ * Copyright (c) 2006-2008 Nick Kossifidis <mickflemm@gmail.com>
+ * Copyright (c) 2007-2008 Luis Rodriguez <mcgrof@winlab.rutgers.edu>
+ * Copyright (c) 2007-2008 Pavel Roskin <proski@gnu.org>
+ * Copyright (c) 2007-2008 Jiri Slaby <jirislaby@gmail.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#define _ATH5K_RESET
+
+/*****************************\
+  Reset functions and helpers
+\*****************************/
+
+#include <linux/pci.h>
+#include "ath5k.h"
+#include "reg.h"
+#include "base.h"
+#include "debug.h"
+
+/**
+ * ath5k_hw_write_ofdm_timings - set OFDM timings on AR5212
+ *
+ * @ah: the &struct ath5k_hw
+ * @channel: the currently set channel upon reset
+ *
+ * Write the OFDM timings for the AR5212 upon reset. This is a helper for
+ * ath5k_hw_reset(). This seems to tune the PLL a specified frequency
+ * depending on the bandwidth of the channel.
+ *
+ */
+static inline int ath5k_hw_write_ofdm_timings(struct ath5k_hw *ah,
+	struct ieee80211_channel *channel)
+{
+	/* Get exponent and mantissa and set it */
+	u32 coef_scaled, coef_exp, coef_man,
+		ds_coef_exp, ds_coef_man, clock;
+
+	if (!(ah->ah_version == AR5K_AR5212) ||
+		!(channel->hw_value & CHANNEL_OFDM))
+		BUG();
+
+	/* Seems there are two PLLs, one for baseband sampling and one
+	 * for tuning. Tuning basebands are 40 MHz or 80MHz when in
+	 * turbo. */
+	clock = channel->hw_value & CHANNEL_TURBO ? 80 : 40;
+	coef_scaled = ((5 * (clock << 24)) / 2) /
+	channel->center_freq;
+
+	for (coef_exp = 31; coef_exp > 0; coef_exp--)
+		if ((coef_scaled >> coef_exp) & 0x1)
+			break;
+
+	if (!coef_exp)
+		return -EINVAL;
+
+	coef_exp = 14 - (coef_exp - 24);
+	coef_man = coef_scaled +
+		(1 << (24 - coef_exp - 1));
+	ds_coef_man = coef_man >> (24 - coef_exp);
+	ds_coef_exp = coef_exp - 16;
+
+	AR5K_REG_WRITE_BITS(ah, AR5K_PHY_TIMING_3,
+		AR5K_PHY_TIMING_3_DSC_MAN, ds_coef_man);
+	AR5K_REG_WRITE_BITS(ah, AR5K_PHY_TIMING_3,
+		AR5K_PHY_TIMING_3_DSC_EXP, ds_coef_exp);
+
+	return 0;
+}
+
+
+/*
+ * index into rates for control rates, we can set it up like this because
+ * this is only used for AR5212 and we know it supports G mode
+ */
+static int control_rates[] =
+	{ 0, 1, 1, 1, 4, 4, 6, 6, 8, 8, 8, 8 };
+
+/**
+ * ath5k_hw_write_rate_duration - set rate duration during hw resets
+ *
+ * @ah: the &struct ath5k_hw
+ * @mode: one of enum ath5k_driver_mode
+ *
+ * Write the rate duration table upon hw reset. This is a helper for
+ * ath5k_hw_reset(). It seems all this is doing is setting an ACK timeout for
+ * the hardware for the current mode for each rate. The rates which are capable
+ * of short preamble (802.11b rates 2Mbps, 5.5Mbps, and 11Mbps) have another
+ * register for the short preamble ACK timeout calculation.
+ */
+static inline void ath5k_hw_write_rate_duration(struct ath5k_hw *ah,
+       unsigned int mode)
+{
+	struct ath5k_softc *sc = ah->ah_sc;
+	struct ieee80211_rate *rate;
+	unsigned int i;
+
+	/* Write rate duration table */
+	for (i = 0; i < sc->sbands[IEEE80211_BAND_2GHZ].n_bitrates; i++) {
+		u32 reg;
+		u16 tx_time;
+
+		rate = &sc->sbands[IEEE80211_BAND_2GHZ].bitrates[control_rates[i]];
+
+		/* Set ACK timeout */
+		reg = AR5K_RATE_DUR(rate->hw_value);
+
+		/* An ACK frame consists of 10 bytes. If you add the FCS,
+		 * which ieee80211_generic_frame_duration() adds,
+		 * its 14 bytes. Note we use the control rate and not the
+		 * actual rate for this rate. See mac80211 tx.c
+		 * ieee80211_duration() for a brief description of
+		 * what rate we should choose to TX ACKs. */
+		tx_time = le16_to_cpu(ieee80211_generic_frame_duration(sc->hw,
+							sc->vif, 10, rate));
+
+		ath5k_hw_reg_write(ah, tx_time, reg);
+
+		if (!(rate->flags & IEEE80211_RATE_SHORT_PREAMBLE))
+			continue;
+
+		/*
+		 * We're not distinguishing short preamble here,
+		 * This is true, all we'll get is a longer value here
+		 * which is not necessarilly bad. We could use
+		 * export ieee80211_frame_duration() but that needs to be
+		 * fixed first to be properly used by mac802111 drivers:
+		 *
+		 *  - remove erp stuff and let the routine figure ofdm
+		 *    erp rates
+		 *  - remove passing argument ieee80211_local as
+		 *    drivers don't have access to it
+		 *  - move drivers using ieee80211_generic_frame_duration()
+		 *    to this
+		 */
+		ath5k_hw_reg_write(ah, tx_time,
+			reg + (AR5K_SET_SHORT_PREAMBLE << 2));
+	}
+}
+
+/*
+ * Reset chipset
+ */
+static int ath5k_hw_nic_reset(struct ath5k_hw *ah, u32 val)
+{
+	int ret;
+	u32 mask = val ? val : ~0U;
+
+	ATH5K_TRACE(ah->ah_sc);
+
+	/* Read-and-clear RX Descriptor Pointer*/
+	ath5k_hw_reg_read(ah, AR5K_RXDP);
+
+	/*
+	 * Reset the device and wait until success
+	 */
+	ath5k_hw_reg_write(ah, val, AR5K_RESET_CTL);
+
+	/* Wait at least 128 PCI clocks */
+	udelay(15);
+
+	if (ah->ah_version == AR5K_AR5210) {
+		val &= AR5K_RESET_CTL_PCU | AR5K_RESET_CTL_DMA
+			| AR5K_RESET_CTL_MAC | AR5K_RESET_CTL_PHY;
+		mask &= AR5K_RESET_CTL_PCU | AR5K_RESET_CTL_DMA
+			| AR5K_RESET_CTL_MAC | AR5K_RESET_CTL_PHY;
+	} else {
+		val &= AR5K_RESET_CTL_PCU | AR5K_RESET_CTL_BASEBAND;
+		mask &= AR5K_RESET_CTL_PCU | AR5K_RESET_CTL_BASEBAND;
+	}
+
+	ret = ath5k_hw_register_timeout(ah, AR5K_RESET_CTL, mask, val, false);
+
+	/*
+	 * Reset configuration register (for hw byte-swap). Note that this
+	 * is only set for big endian. We do the necessary magic in
+	 * AR5K_INIT_CFG.
+	 */
+	if ((val & AR5K_RESET_CTL_PCU) == 0)
+		ath5k_hw_reg_write(ah, AR5K_INIT_CFG, AR5K_CFG);
+
+	return ret;
+}
+
+/*
+ * Sleep control
+ */
+int ath5k_hw_set_power(struct ath5k_hw *ah, enum ath5k_power_mode mode,
+		bool set_chip, u16 sleep_duration)
+{
+	unsigned int i;
+	u32 staid, data;
+
+	ATH5K_TRACE(ah->ah_sc);
+	staid = ath5k_hw_reg_read(ah, AR5K_STA_ID1);
+
+	switch (mode) {
+	case AR5K_PM_AUTO:
+		staid &= ~AR5K_STA_ID1_DEFAULT_ANTENNA;
+		/* fallthrough */
+	case AR5K_PM_NETWORK_SLEEP:
+		if (set_chip)
+			ath5k_hw_reg_write(ah,
+				AR5K_SLEEP_CTL_SLE_ALLOW |
+				sleep_duration,
+				AR5K_SLEEP_CTL);
+
+		staid |= AR5K_STA_ID1_PWR_SV;
+		break;
+
+	case AR5K_PM_FULL_SLEEP:
+		if (set_chip)
+			ath5k_hw_reg_write(ah, AR5K_SLEEP_CTL_SLE_SLP,
+				AR5K_SLEEP_CTL);
+
+		staid |= AR5K_STA_ID1_PWR_SV;
+		break;
+
+	case AR5K_PM_AWAKE:
+
+		staid &= ~AR5K_STA_ID1_PWR_SV;
+
+		if (!set_chip)
+			goto commit;
+
+		/* Preserve sleep duration */
+		data = ath5k_hw_reg_read(ah, AR5K_SLEEP_CTL);
+		if (data & 0xffc00000)
+			data = 0;
+		else
+			data = data & 0xfffcffff;
+
+		ath5k_hw_reg_write(ah, data, AR5K_SLEEP_CTL);
+		udelay(15);
+
+		for (i = 50; i > 0; i--) {
+			/* Check if the chip did wake up */
+			if ((ath5k_hw_reg_read(ah, AR5K_PCICFG) &
+					AR5K_PCICFG_SPWR_DN) == 0)
+				break;
+
+			/* Wait a bit and retry */
+			udelay(200);
+			ath5k_hw_reg_write(ah, data, AR5K_SLEEP_CTL);
+		}
+
+		/* Fail if the chip didn't wake up */
+		if (i <= 0)
+			return -EIO;
+
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+commit:
+	ah->ah_power_mode = mode;
+	ath5k_hw_reg_write(ah, staid, AR5K_STA_ID1);
+
+	return 0;
+}
+
+/*
+ * Bring up MAC + PHY Chips
+ */
+int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial)
+{
+	struct pci_dev *pdev = ah->ah_sc->pdev;
+	u32 turbo, mode, clock, bus_flags;
+	int ret;
+
+	turbo = 0;
+	mode = 0;
+	clock = 0;
+
+	ATH5K_TRACE(ah->ah_sc);
+
+	/* Wakeup the device */
+	ret = ath5k_hw_set_power(ah, AR5K_PM_AWAKE, true, 0);
+	if (ret) {
+		ATH5K_ERR(ah->ah_sc, "failed to wakeup the MAC Chip\n");
+		return ret;
+	}
+
+	if (ah->ah_version != AR5K_AR5210) {
+		/*
+		 * Get channel mode flags
+		 */
+
+		if (ah->ah_radio >= AR5K_RF5112) {
+			mode = AR5K_PHY_MODE_RAD_RF5112;
+			clock = AR5K_PHY_PLL_RF5112;
+		} else {
+			mode = AR5K_PHY_MODE_RAD_RF5111;	/*Zero*/
+			clock = AR5K_PHY_PLL_RF5111;		/*Zero*/
+		}
+
+		if (flags & CHANNEL_2GHZ) {
+			mode |= AR5K_PHY_MODE_FREQ_2GHZ;
+			clock |= AR5K_PHY_PLL_44MHZ;
+
+			if (flags & CHANNEL_CCK) {
+				mode |= AR5K_PHY_MODE_MOD_CCK;
+			} else if (flags & CHANNEL_OFDM) {
+				/* XXX Dynamic OFDM/CCK is not supported by the
+				 * AR5211 so we set MOD_OFDM for plain g (no
+				 * CCK headers) operation. We need to test
+				 * this, 5211 might support ofdm-only g after
+				 * all, there are also initial register values
+				 * in the code for g mode (see initvals.c). */
+				if (ah->ah_version == AR5K_AR5211)
+					mode |= AR5K_PHY_MODE_MOD_OFDM;
+				else
+					mode |= AR5K_PHY_MODE_MOD_DYN;
+			} else {
+				ATH5K_ERR(ah->ah_sc,
+					"invalid radio modulation mode\n");
+				return -EINVAL;
+			}
+		} else if (flags & CHANNEL_5GHZ) {
+			mode |= AR5K_PHY_MODE_FREQ_5GHZ;
+			clock |= AR5K_PHY_PLL_40MHZ;
+
+			if (flags & CHANNEL_OFDM)
+				mode |= AR5K_PHY_MODE_MOD_OFDM;
+			else {
+				ATH5K_ERR(ah->ah_sc,
+					"invalid radio modulation mode\n");
+				return -EINVAL;
+			}
+		} else {
+			ATH5K_ERR(ah->ah_sc, "invalid radio frequency mode\n");
+			return -EINVAL;
+		}
+
+		if (flags & CHANNEL_TURBO)
+			turbo = AR5K_PHY_TURBO_MODE | AR5K_PHY_TURBO_SHORT;
+	} else { /* Reset the device */
+
+		/* ...enable Atheros turbo mode if requested */
+		if (flags & CHANNEL_TURBO)
+			ath5k_hw_reg_write(ah, AR5K_PHY_TURBO_MODE,
+					AR5K_PHY_TURBO);
+	}
+
+	/* reseting PCI on PCI-E cards results card to hang
+	 * and always return 0xffff... so we ingore that flag
+	 * for PCI-E cards */
+	bus_flags = (pdev->is_pcie) ? 0 : AR5K_RESET_CTL_PCI;
+
+	/* Reset chipset */
+	if (ah->ah_version == AR5K_AR5210) {
+		ret = ath5k_hw_nic_reset(ah, AR5K_RESET_CTL_PCU |
+			AR5K_RESET_CTL_MAC | AR5K_RESET_CTL_DMA |
+			AR5K_RESET_CTL_PHY | AR5K_RESET_CTL_PCI);
+			mdelay(2);
+	} else {
+		ret = ath5k_hw_nic_reset(ah, AR5K_RESET_CTL_PCU |
+			AR5K_RESET_CTL_BASEBAND | bus_flags);
+	}
+	if (ret) {
+		ATH5K_ERR(ah->ah_sc, "failed to reset the MAC Chip\n");
+		return -EIO;
+	}
+
+	/* ...wakeup again!*/
+	ret = ath5k_hw_set_power(ah, AR5K_PM_AWAKE, true, 0);
+	if (ret) {
+		ATH5K_ERR(ah->ah_sc, "failed to resume the MAC Chip\n");
+		return ret;
+	}
+
+	/* ...final warm reset */
+	if (ath5k_hw_nic_reset(ah, 0)) {
+		ATH5K_ERR(ah->ah_sc, "failed to warm reset the MAC Chip\n");
+		return -EIO;
+	}
+
+	if (ah->ah_version != AR5K_AR5210) {
+		/* ...set the PHY operating mode */
+		ath5k_hw_reg_write(ah, clock, AR5K_PHY_PLL);
+		udelay(300);
+
+		ath5k_hw_reg_write(ah, mode, AR5K_PHY_MODE);
+		ath5k_hw_reg_write(ah, turbo, AR5K_PHY_TURBO);
+	}
+
+	return 0;
+}
+
+/*
+ * Main reset function
+ */
+int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
+	struct ieee80211_channel *channel, bool change_channel)
+{
+	struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
+	struct pci_dev *pdev = ah->ah_sc->pdev;
+	u32 data, s_seq, s_ant, s_led[3], dma_size;
+	unsigned int i, mode, freq, ee_mode, ant[2];
+	int ret;
+
+	ATH5K_TRACE(ah->ah_sc);
+
+	s_seq = 0;
+	s_ant = 0;
+	ee_mode = 0;
+	freq = 0;
+	mode = 0;
+
+	/*
+	 * Save some registers before a reset
+	 */
+	/*DCU/Antenna selection not available on 5210*/
+	if (ah->ah_version != AR5K_AR5210) {
+		if (change_channel) {
+			/* Seq number for queue 0 -do this for all queues ? */
+			s_seq = ath5k_hw_reg_read(ah,
+					AR5K_QUEUE_DFS_SEQNUM(0));
+			/*Default antenna*/
+			s_ant = ath5k_hw_reg_read(ah, AR5K_DEFAULT_ANTENNA);
+		}
+	}
+
+	/*GPIOs*/
+	s_led[0] = ath5k_hw_reg_read(ah, AR5K_PCICFG) & AR5K_PCICFG_LEDSTATE;
+	s_led[1] = ath5k_hw_reg_read(ah, AR5K_GPIOCR);
+	s_led[2] = ath5k_hw_reg_read(ah, AR5K_GPIODO);
+
+	if (change_channel && ah->ah_rf_banks != NULL)
+		ath5k_hw_get_rf_gain(ah);
+
+
+	/*Wakeup the device*/
+	ret = ath5k_hw_nic_wakeup(ah, channel->hw_value, false);
+	if (ret)
+		return ret;
+
+	/*
+	 * Initialize operating mode
+	 */
+	ah->ah_op_mode = op_mode;
+
+	/*
+	 * 5111/5112 Settings
+	 * 5210 only comes with RF5110
+	 */
+	if (ah->ah_version != AR5K_AR5210) {
+		if (ah->ah_radio != AR5K_RF5111 &&
+			ah->ah_radio != AR5K_RF5112 &&
+			ah->ah_radio != AR5K_RF5413 &&
+			ah->ah_radio != AR5K_RF2413 &&
+			ah->ah_radio != AR5K_RF2425) {
+			ATH5K_ERR(ah->ah_sc,
+				"invalid phy radio: %u\n", ah->ah_radio);
+			return -EINVAL;
+		}
+
+		switch (channel->hw_value & CHANNEL_MODES) {
+		case CHANNEL_A:
+			mode = AR5K_MODE_11A;
+			freq = AR5K_INI_RFGAIN_5GHZ;
+			ee_mode = AR5K_EEPROM_MODE_11A;
+			break;
+		case CHANNEL_G:
+			mode = AR5K_MODE_11G;
+			freq = AR5K_INI_RFGAIN_2GHZ;
+			ee_mode = AR5K_EEPROM_MODE_11G;
+			break;
+		case CHANNEL_B:
+			mode = AR5K_MODE_11B;
+			freq = AR5K_INI_RFGAIN_2GHZ;
+			ee_mode = AR5K_EEPROM_MODE_11B;
+			break;
+		case CHANNEL_T:
+			mode = AR5K_MODE_11A_TURBO;
+			freq = AR5K_INI_RFGAIN_5GHZ;
+			ee_mode = AR5K_EEPROM_MODE_11A;
+			break;
+		/*Is this ok on 5211 too ?*/
+		case CHANNEL_TG:
+			mode = AR5K_MODE_11G_TURBO;
+			freq = AR5K_INI_RFGAIN_2GHZ;
+			ee_mode = AR5K_EEPROM_MODE_11G;
+			break;
+		case CHANNEL_XR:
+			if (ah->ah_version == AR5K_AR5211) {
+				ATH5K_ERR(ah->ah_sc,
+					"XR mode not available on 5211");
+				return -EINVAL;
+			}
+			mode = AR5K_MODE_XR;
+			freq = AR5K_INI_RFGAIN_5GHZ;
+			ee_mode = AR5K_EEPROM_MODE_11A;
+			break;
+		default:
+			ATH5K_ERR(ah->ah_sc,
+				"invalid channel: %d\n", channel->center_freq);
+			return -EINVAL;
+		}
+
+		/* PHY access enable */
+		ath5k_hw_reg_write(ah, AR5K_PHY_SHIFT_5GHZ, AR5K_PHY(0));
+
+	}
+
+	ret = ath5k_hw_write_initvals(ah, mode, change_channel);
+	if (ret)
+		return ret;
+
+	/*
+	 * 5211/5212 Specific
+	 */
+	if (ah->ah_version != AR5K_AR5210) {
+		/*
+		 * Write initial RF gain settings
+		 * This should work for both 5111/5112
+		 */
+		ret = ath5k_hw_rfgain(ah, freq);
+		if (ret)
+			return ret;
+
+		mdelay(1);
+
+		/*
+		 * Write some more initial register settings
+		 */
+		if (ah->ah_version == AR5K_AR5212) {
+			ath5k_hw_reg_write(ah, 0x0002a002, 0x982c);
+
+			if (channel->hw_value == CHANNEL_G)
+				if (ah->ah_mac_srev < AR5K_SREV_AR2413)
+					ath5k_hw_reg_write(ah, 0x00f80d80,
+								0x994c);
+				else if (ah->ah_mac_srev < AR5K_SREV_AR5424)
+					ath5k_hw_reg_write(ah, 0x00380140,
+								0x994c);
+				else if (ah->ah_mac_srev < AR5K_SREV_AR2425)
+					ath5k_hw_reg_write(ah, 0x00fc0ec0,
+								0x994c);
+				else /* 2425 */
+					ath5k_hw_reg_write(ah, 0x00fc0fc0,
+								0x994c);
+			else
+				ath5k_hw_reg_write(ah, 0x00000000, 0x994c);
+
+			/* Some bits are disabled here, we know nothing about
+			 * register 0xa228 yet, most of the times this ends up
+			 * with a value 0x9b5 -haven't seen any dump with
+			 * a different value- */
+			/* Got this from decompiling binary HAL */
+			data = ath5k_hw_reg_read(ah, 0xa228);
+			data &= 0xfffffdff;
+			ath5k_hw_reg_write(ah, data, 0xa228);
+
+			data = ath5k_hw_reg_read(ah, 0xa228);
+			data &= 0xfffe03ff;
+			ath5k_hw_reg_write(ah, data, 0xa228);
+			data = 0;
+
+			/* Just write 0x9b5 ? */
+			/* ath5k_hw_reg_write(ah, 0x000009b5, 0xa228); */
+			ath5k_hw_reg_write(ah, 0x0000000f, AR5K_SEQ_MASK);
+			ath5k_hw_reg_write(ah, 0x00000000, 0xa254);
+			ath5k_hw_reg_write(ah, 0x0000000e, AR5K_PHY_SCAL);
+		}
+
+		/* Fix for first revision of the RF5112 RF chipset */
+		if (ah->ah_radio >= AR5K_RF5112 &&
+				ah->ah_radio_5ghz_revision <
+				AR5K_SREV_RAD_5112A) {
+			ath5k_hw_reg_write(ah, AR5K_PHY_CCKTXCTL_WORLD,
+					AR5K_PHY_CCKTXCTL);
+			if (channel->hw_value & CHANNEL_5GHZ)
+				data = 0xffb81020;
+			else
+				data = 0xffb80d20;
+			ath5k_hw_reg_write(ah, data, AR5K_PHY_FRAME_CTL);
+			data = 0;
+		}
+
+		/*
+		 * Set TX power (FIXME)
+		 */
+		ret = ath5k_hw_txpower(ah, channel, AR5K_TUNE_DEFAULT_TXPOWER);
+		if (ret)
+			return ret;
+
+		/* Write rate duration table only on AR5212 and if
+		 * virtual interface has already been brought up
+		 * XXX: rethink this after new mode changes to
+		 * mac80211 are integrated */
+		if (ah->ah_version == AR5K_AR5212 &&
+			ah->ah_sc->vif != NULL)
+			ath5k_hw_write_rate_duration(ah, mode);
+
+		/*
+		 * Write RF registers
+		 */
+		ret = ath5k_hw_rfregs(ah, channel, mode);
+		if (ret)
+			return ret;
+
+		/*
+		 * Configure additional registers
+		 */
+
+		/* Write OFDM timings on 5212*/
+		if (ah->ah_version == AR5K_AR5212 &&
+			channel->hw_value & CHANNEL_OFDM) {
+			ret = ath5k_hw_write_ofdm_timings(ah, channel);
+			if (ret)
+				return ret;
+		}
+
+		/*Enable/disable 802.11b mode on 5111
+		(enable 2111 frequency converter + CCK)*/
+		if (ah->ah_radio == AR5K_RF5111) {
+			if (mode == AR5K_MODE_11B)
+				AR5K_REG_ENABLE_BITS(ah, AR5K_TXCFG,
+				    AR5K_TXCFG_B_MODE);
+			else
+				AR5K_REG_DISABLE_BITS(ah, AR5K_TXCFG,
+				    AR5K_TXCFG_B_MODE);
+		}
+
+		/*
+		 * Set channel and calibrate the PHY
+		 */
+		ret = ath5k_hw_channel(ah, channel);
+		if (ret)
+			return ret;
+
+		/* Set antenna mode */
+		AR5K_REG_MASKED_BITS(ah, AR5K_PHY_ANT_CTL,
+			ah->ah_antenna[ee_mode][0], 0xfffffc06);
+
+		/*
+		 * In case a fixed antenna was set as default
+		 * write the same settings on both AR5K_PHY_ANT_SWITCH_TABLE
+		 * registers.
+		 */
+		if (s_ant != 0) {
+			if (s_ant == AR5K_ANT_FIXED_A) /* 1 - Main */
+				ant[0] = ant[1] = AR5K_ANT_FIXED_A;
+			else	/* 2 - Aux */
+				ant[0] = ant[1] = AR5K_ANT_FIXED_B;
+		} else {
+			ant[0] = AR5K_ANT_FIXED_A;
+			ant[1] = AR5K_ANT_FIXED_B;
+		}
+
+		ath5k_hw_reg_write(ah, ah->ah_antenna[ee_mode][ant[0]],
+			AR5K_PHY_ANT_SWITCH_TABLE_0);
+		ath5k_hw_reg_write(ah, ah->ah_antenna[ee_mode][ant[1]],
+			AR5K_PHY_ANT_SWITCH_TABLE_1);
+
+		/* Commit values from EEPROM */
+		if (ah->ah_radio == AR5K_RF5111)
+			AR5K_REG_WRITE_BITS(ah, AR5K_PHY_FRAME_CTL,
+			    AR5K_PHY_FRAME_CTL_TX_CLIP, ee->ee_tx_clip);
+
+		ath5k_hw_reg_write(ah,
+			AR5K_PHY_NF_SVAL(ee->ee_noise_floor_thr[ee_mode]),
+			AR5K_PHY_NFTHRES);
+
+		AR5K_REG_MASKED_BITS(ah, AR5K_PHY_SETTLING,
+			(ee->ee_switch_settling[ee_mode] << 7) & 0x3f80,
+			0xffffc07f);
+		AR5K_REG_MASKED_BITS(ah, AR5K_PHY_GAIN,
+			(ee->ee_ant_tx_rx[ee_mode] << 12) & 0x3f000,
+			0xfffc0fff);
+		AR5K_REG_MASKED_BITS(ah, AR5K_PHY_DESIRED_SIZE,
+			(ee->ee_adc_desired_size[ee_mode] & 0x00ff) |
+			((ee->ee_pga_desired_size[ee_mode] << 8) & 0xff00),
+			0xffff0000);
+
+		ath5k_hw_reg_write(ah,
+			(ee->ee_tx_end2xpa_disable[ee_mode] << 24) |
+			(ee->ee_tx_end2xpa_disable[ee_mode] << 16) |
+			(ee->ee_tx_frm2xpa_enable[ee_mode] << 8) |
+			(ee->ee_tx_frm2xpa_enable[ee_mode]), AR5K_PHY_RF_CTL4);
+
+		AR5K_REG_MASKED_BITS(ah, AR5K_PHY_RF_CTL3,
+			ee->ee_tx_end2xlna_enable[ee_mode] << 8, 0xffff00ff);
+		AR5K_REG_MASKED_BITS(ah, AR5K_PHY_NF,
+			(ee->ee_thr_62[ee_mode] << 12) & 0x7f000, 0xfff80fff);
+		AR5K_REG_MASKED_BITS(ah, AR5K_PHY_OFDM_SELFCORR, 4, 0xffffff01);
+
+		AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_IQ,
+		    AR5K_PHY_IQ_CORR_ENABLE |
+		    (ee->ee_i_cal[ee_mode] << AR5K_PHY_IQ_CORR_Q_I_COFF_S) |
+		    ee->ee_q_cal[ee_mode]);
+
+		if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_1)
+			AR5K_REG_WRITE_BITS(ah, AR5K_PHY_GAIN_2GHZ,
+				AR5K_PHY_GAIN_2GHZ_MARGIN_TXRX,
+				ee->ee_margin_tx_rx[ee_mode]);
+
+	} else {
+		mdelay(1);
+		/* Disable phy and wait */
+		ath5k_hw_reg_write(ah, AR5K_PHY_ACT_DISABLE, AR5K_PHY_ACT);
+		mdelay(1);
+	}
+
+	/*
+	 * Restore saved values
+	 */
+	/*DCU/Antenna selection not available on 5210*/
+	if (ah->ah_version != AR5K_AR5210) {
+		ath5k_hw_reg_write(ah, s_seq, AR5K_QUEUE_DFS_SEQNUM(0));
+		ath5k_hw_reg_write(ah, s_ant, AR5K_DEFAULT_ANTENNA);
+	}
+	AR5K_REG_ENABLE_BITS(ah, AR5K_PCICFG, s_led[0]);
+	ath5k_hw_reg_write(ah, s_led[1], AR5K_GPIOCR);
+	ath5k_hw_reg_write(ah, s_led[2], AR5K_GPIODO);
+
+	/*
+	 * Misc
+	 */
+	/* XXX: add ah->aid once mac80211 gives this to us */
+	ath5k_hw_set_associd(ah, ah->ah_bssid, 0);
+
+	ath5k_hw_set_opmode(ah);
+	/*PISR/SISR Not available on 5210*/
+	if (ah->ah_version != AR5K_AR5210) {
+		ath5k_hw_reg_write(ah, 0xffffffff, AR5K_PISR);
+		/* If we later allow tuning for this, store into sc structure */
+		data = AR5K_TUNE_RSSI_THRES |
+			AR5K_TUNE_BMISS_THRES << AR5K_RSSI_THR_BMISS_S;
+		ath5k_hw_reg_write(ah, data, AR5K_RSSI_THR);
+	}
+
+	/*
+	 * Set Rx/Tx DMA Configuration
+	 *
+	 * Set maximum DMA size (512) except for PCI-E cards since
+	 * it causes rx overruns and tx errors (tested on 5424 but since
+	 * rx overruns also occur on 5416/5418 with madwifi we set 128
+	 * for all PCI-E cards to be safe).
+	 *
+	 * In dumps this is 128 for allchips.
+	 *
+	 * XXX: need to check 5210 for this
+	 * TODO: Check out tx triger level, it's always 64 on dumps but I
+	 * guess we can tweak it and see how it goes ;-)
+	 */
+	dma_size = (pdev->is_pcie) ? AR5K_DMASIZE_128B : AR5K_DMASIZE_512B;
+	if (ah->ah_version != AR5K_AR5210) {
+		AR5K_REG_WRITE_BITS(ah, AR5K_TXCFG,
+			AR5K_TXCFG_SDMAMR, dma_size);
+		AR5K_REG_WRITE_BITS(ah, AR5K_RXCFG,
+			AR5K_RXCFG_SDMAMW, dma_size);
+	}
+
+	/*
+	 * Enable the PHY and wait until completion
+	 */
+	ath5k_hw_reg_write(ah, AR5K_PHY_ACT_ENABLE, AR5K_PHY_ACT);
+
+	/*
+	 * On 5211+ read activation -> rx delay
+	 * and use it.
+	 */
+	if (ah->ah_version != AR5K_AR5210) {
+		data = ath5k_hw_reg_read(ah, AR5K_PHY_RX_DELAY) &
+			AR5K_PHY_RX_DELAY_M;
+		data = (channel->hw_value & CHANNEL_CCK) ?
+			((data << 2) / 22) : (data / 10);
+
+		udelay(100 + (2 * data));
+		data = 0;
+	} else {
+		mdelay(1);
+	}
+
+	/*
+	 * Perform ADC test (?)
+	 */
+	data = ath5k_hw_reg_read(ah, AR5K_PHY_TST1);
+	ath5k_hw_reg_write(ah, AR5K_PHY_TST1_TXHOLD, AR5K_PHY_TST1);
+	for (i = 0; i <= 20; i++) {
+		if (!(ath5k_hw_reg_read(ah, AR5K_PHY_ADC_TEST) & 0x10))
+			break;
+		udelay(200);
+	}
+	ath5k_hw_reg_write(ah, data, AR5K_PHY_TST1);
+	data = 0;
+
+	/*
+	 * Start automatic gain calibration
+	 *
+	 * During AGC calibration RX path is re-routed to
+	 * a signal detector so we don't receive anything.
+	 *
+	 * This method is used to calibrate some static offsets
+	 * used together with on-the fly I/Q calibration (the
+	 * one performed via ath5k_hw_phy_calibrate), that doesn't
+	 * interrupt rx path.
+	 *
+	 * If we are in a noisy environment AGC calibration may time
+	 * out.
+	 */
+	AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_AGCCTL,
+				AR5K_PHY_AGCCTL_CAL);
+
+	/* At the same time start I/Q calibration for QAM constellation
+	 * -no need for CCK- */
+	ah->ah_calibration = false;
+	if (!(mode == AR5K_MODE_11B)) {
+		ah->ah_calibration = true;
+		AR5K_REG_WRITE_BITS(ah, AR5K_PHY_IQ,
+				AR5K_PHY_IQ_CAL_NUM_LOG_MAX, 15);
+		AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_IQ,
+				AR5K_PHY_IQ_RUN);
+	}
+
+	/* Wait for gain calibration to finish (we check for I/Q calibration
+	 * during ath5k_phy_calibrate) */
+	if (ath5k_hw_register_timeout(ah, AR5K_PHY_AGCCTL,
+			AR5K_PHY_AGCCTL_CAL, 0, false)) {
+		ATH5K_ERR(ah->ah_sc, "gain calibration timeout (%uMHz)\n",
+			channel->center_freq);
+		return -EAGAIN;
+	}
+
+	/*
+	 * Start noise floor calibration
+	 *
+	 * If we run NF calibration before AGC, it always times out.
+	 * Binary HAL starts NF and AGC calibration at the same time
+	 * and only waits for AGC to finish. I believe that's wrong because
+	 * during NF calibration, rx path is also routed to a detector, so if
+	 * it doesn't finish we won't have RX.
+	 *
+	 * XXX: Find an interval that's OK for all cards...
+	 */
+	ret = ath5k_hw_noise_floor_calibration(ah, channel->center_freq);
+	if (ret)
+		return ret;
+
+	/*
+	 * Reset queues and start beacon timers at the end of the reset routine
+	 */
+	for (i = 0; i < ah->ah_capabilities.cap_queues.q_tx_num; i++) {
+		/*No QCU on 5210*/
+		if (ah->ah_version != AR5K_AR5210)
+			AR5K_REG_WRITE_Q(ah, AR5K_QUEUE_QCUMASK(i), i);
+
+		ret = ath5k_hw_reset_tx_queue(ah, i);
+		if (ret) {
+			ATH5K_ERR(ah->ah_sc,
+				"failed to reset TX queue #%d\n", i);
+			return ret;
+		}
+	}
+
+	/* Pre-enable interrupts on 5211/5212*/
+	if (ah->ah_version != AR5K_AR5210)
+		ath5k_hw_set_imr(ah, AR5K_INT_RX | AR5K_INT_TX |
+				AR5K_INT_FATAL);
+
+	/*
+	 * Set RF kill flags if supported by the device (read from the EEPROM)
+	 * Disable gpio_intr for now since it results system hang.
+	 * TODO: Handle this in ath5k_intr
+	 */
+#if 0
+	if (AR5K_EEPROM_HDR_RFKILL(ah->ah_capabilities.cap_eeprom.ee_header)) {
+		ath5k_hw_set_gpio_input(ah, 0);
+		ah->ah_gpio[0] = ath5k_hw_get_gpio(ah, 0);
+		if (ah->ah_gpio[0] == 0)
+			ath5k_hw_set_gpio_intr(ah, 0, 1);
+		else
+			ath5k_hw_set_gpio_intr(ah, 0, 0);
+	}
+#endif
+
+	/*
+	 * Set the 32MHz reference clock on 5212 phy clock sleep register
+	 *
+	 * TODO: Find out how to switch to external 32Khz clock to save power
+	 */
+	if (ah->ah_version == AR5K_AR5212) {
+		ath5k_hw_reg_write(ah, AR5K_PHY_SCR_32MHZ, AR5K_PHY_SCR);
+		ath5k_hw_reg_write(ah, AR5K_PHY_SLMT_32MHZ, AR5K_PHY_SLMT);
+		ath5k_hw_reg_write(ah, AR5K_PHY_SCAL_32MHZ, AR5K_PHY_SCAL);
+		ath5k_hw_reg_write(ah, AR5K_PHY_SCLOCK_32MHZ, AR5K_PHY_SCLOCK);
+		ath5k_hw_reg_write(ah, AR5K_PHY_SDELAY_32MHZ, AR5K_PHY_SDELAY);
+		ath5k_hw_reg_write(ah, ah->ah_phy_spending, AR5K_PHY_SPENDING);
+
+		data = ath5k_hw_reg_read(ah, AR5K_USEC_5211) & 0xffffc07f ;
+		data |= (ah->ah_phy_spending == AR5K_PHY_SPENDING_18) ?
+						0x00000f80 : 0x00001380 ;
+		ath5k_hw_reg_write(ah, data, AR5K_USEC_5211);
+		data = 0;
+	}
+
+	if (ah->ah_version == AR5K_AR5212) {
+		ath5k_hw_reg_write(ah, 0x000100aa, 0x8118);
+		ath5k_hw_reg_write(ah, 0x00003210, 0x811c);
+		ath5k_hw_reg_write(ah, 0x00000052, 0x8108);
+		if (ah->ah_mac_srev >= AR5K_SREV_AR2413)
+			ath5k_hw_reg_write(ah, 0x00000004, 0x8120);
+	}
+
+	/*
+	 * Disable beacons and reset the register
+	 */
+	AR5K_REG_DISABLE_BITS(ah, AR5K_BEACON, AR5K_BEACON_ENABLE |
+			AR5K_BEACON_RESET_TSF);
+
+	return 0;
+}
+
+#undef _ATH5K_RESET
diff --git a/drivers/net/wireless/ath9k/Kconfig b/drivers/net/wireless/ath9k/Kconfig
index 9e19dcc..80a6924 100644
--- a/drivers/net/wireless/ath9k/Kconfig
+++ b/drivers/net/wireless/ath9k/Kconfig
@@ -1,6 +1,9 @@
 config ATH9K
 	tristate "Atheros 802.11n wireless cards support"
 	depends on PCI && MAC80211 && WLAN_80211
+	select MAC80211_LEDS
+	select LEDS_CLASS
+	select NEW_LEDS
 	---help---
 	  This module adds support for wireless adapters based on
 	  Atheros IEEE 802.11n AR5008 and AR9001 family of chipsets.
diff --git a/drivers/net/wireless/ath9k/ath9k.h b/drivers/net/wireless/ath9k/ath9k.h
index d1b0fba..accace5 100644
--- a/drivers/net/wireless/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath9k/ath9k.h
@@ -144,6 +144,7 @@
 #define ATH9K_TXDESC_EXT_AND_CTL	0x0080
 #define ATH9K_TXDESC_VMF		0x0100
 #define ATH9K_TXDESC_FRAG_IS_ON 	0x0200
+#define ATH9K_TXDESC_CAB		0x0400
 
 #define ATH9K_RXDESC_INTREQ		0x0020
 
@@ -564,8 +565,6 @@
 #define CTL_5GHT40              8
 
 #define AR_EEPROM_MAC(i)        (0x1d+(i))
-#define EEP_SCALE       100
-#define EEP_DELTA       10
 
 #define AR_EEPROM_RFSILENT_GPIO_SEL     0x001c
 #define AR_EEPROM_RFSILENT_GPIO_SEL_S   2
@@ -606,9 +605,6 @@
 #define REG_CLR_BIT(_a, _r, _f) \
 	REG_WRITE(_a, _r, REG_READ(_a, _r) & ~_f)
 
-#define ATH9K_COMP_BUF_MAX_SIZE   9216
-#define ATH9K_COMP_BUF_ALIGN_SIZE 512
-
 #define ATH9K_TXQ_USE_LOCKOUT_BKOFF_DIS   0x00000001
 
 #define INIT_AIFS       2
@@ -632,12 +628,6 @@
 				 (IEEE80211_WEP_IVLEN +		\
 				  IEEE80211_WEP_KIDLEN +	\
 				  IEEE80211_WEP_CRCLEN))
-#define IEEE80211_MAX_LEN       (2300 + FCS_LEN +		\
-				 (IEEE80211_WEP_IVLEN +		\
-				  IEEE80211_WEP_KIDLEN +	\
-				  IEEE80211_WEP_CRCLEN))
-
-#define MAX_REG_ADD_COUNT   129
 #define MAX_RATE_POWER 63
 
 enum ath9k_power_mode {
@@ -707,13 +697,6 @@
 };
 #define PHY_CCK PHY_DS
 
-enum start_adhoc_option {
-	START_ADHOC_NO_11A,
-	START_ADHOC_PER_11D,
-	START_ADHOC_IN_11A,
-	START_ADHOC_IN_11B,
-};
-
 enum ath9k_tp_scale {
 	ATH9K_TP_SCALE_MAX = 0,
 	ATH9K_TP_SCALE_50,
@@ -769,14 +752,11 @@
 
 #define ATH9K_RSSI_EP_MULTIPLIER  (1<<7)
 
-enum ath9k_gpio_output_mux_type {
-	ATH9K_GPIO_OUTPUT_MUX_AS_OUTPUT,
-	ATH9K_GPIO_OUTPUT_MUX_AS_PCIE_ATTENTION_LED,
-	ATH9K_GPIO_OUTPUT_MUX_AS_PCIE_POWER_LED,
-	ATH9K_GPIO_OUTPUT_MUX_AS_MAC_NETWORK_LED,
-	ATH9K_GPIO_OUTPUT_MUX_AS_MAC_POWER_LED,
-	ATH9K_GPIO_OUTPUT_MUX_NUM_ENTRIES
-};
+#define AR_GPIO_OUTPUT_MUX_AS_OUTPUT             0
+#define AR_GPIO_OUTPUT_MUX_AS_PCIE_ATTENTION_LED 1
+#define AR_GPIO_OUTPUT_MUX_AS_PCIE_POWER_LED     2
+#define AR_GPIO_OUTPUT_MUX_AS_MAC_NETWORK_LED    5
+#define AR_GPIO_OUTPUT_MUX_AS_MAC_POWER_LED      6
 
 enum {
 	ATH9K_RESET_POWER_ON,
@@ -790,19 +770,20 @@
 	u32 ah_magic;
 	u16 ah_devid;
 	u16 ah_subvendorid;
-	struct ath_softc *ah_sc;
-	void __iomem *ah_sh;
-	u16 ah_countryCode;
 	u32 ah_macVersion;
 	u16 ah_macRev;
 	u16 ah_phyRev;
 	u16 ah_analog5GhzRev;
 	u16 ah_analog2GhzRev;
-	u8 ah_decompMask[ATH9K_DECOMP_MASK_SIZE];
-	u32 ah_flags;
+
+	void __iomem *ah_sh;
+	struct ath_softc *ah_sc;
 	enum ath9k_opmode ah_opmode;
 	struct ath9k_ops_config ah_config;
 	struct ath9k_hw_capabilities ah_caps;
+
+	u16 ah_countryCode;
+	u32 ah_flags;
 	int16_t ah_powerLimit;
 	u16 ah_maxPowerLevel;
 	u32 ah_tpScale;
@@ -812,15 +793,17 @@
 	u16 ah_currentRD5G;
 	u16 ah_currentRD2G;
 	char ah_iso[4];
-	enum start_adhoc_option ah_adHocMode;
-	bool ah_commonMode;
+
 	struct ath9k_channel ah_channels[150];
-	u32 ah_nchan;
 	struct ath9k_channel *ah_curchan;
-	u16 ah_rfsilent;
-	bool ah_rfkillEnabled;
+	u32 ah_nchan;
+
 	bool ah_isPciExpress;
 	u16 ah_txTrigLevel;
+	u16 ah_rfsilent;
+	u32 ah_rfkill_gpio;
+	u32 ah_rfkill_polarity;
+
 #ifndef ATH_NF_PER_CHAN
 	struct ath9k_nfcal_hist nfCalHist[NUM_NF_READINGS];
 #endif
@@ -853,7 +836,7 @@
 u32 ath9k_hw_mhz2ieee(struct ath_hal *ah, u32 freq, u32 flags);
 enum ath9k_int ath9k_hw_set_interrupts(struct ath_hal *ah,
 				     enum ath9k_int ints);
-bool ath9k_hw_reset(struct ath_hal *ah, enum ath9k_opmode opmode,
+bool ath9k_hw_reset(struct ath_hal *ah,
 		    struct ath9k_channel *chan,
 		    enum ath9k_ht_macmode macmode,
 		    u8 txchainmask, u8 rxchainmask,
@@ -871,7 +854,7 @@
 			u8 rxchainmask,
 			bool longcal,
 			bool *isCalDone);
-int16_t ath9k_hw_getchan_noise(struct ath_hal *ah,
+s16 ath9k_hw_getchan_noise(struct ath_hal *ah,
 			       struct ath9k_channel *chan);
 void ath9k_hw_write_associd(struct ath_hal *ah, const u8 *bssid,
 			    u16 assocId);
@@ -1018,4 +1001,9 @@
 bool ath9k_get_channel_edges(struct ath_hal *ah,
 			     u16 flags, u16 *low,
 			     u16 *high);
+void ath9k_hw_cfg_output(struct ath_hal *ah, u32 gpio,
+			u32 ah_signal_type);
+void ath9k_hw_set_gpio(struct ath_hal *ah, u32 gpio, u32 value);
+u32 ath9k_hw_gpio_get(struct ath_hal *ah, u32 gpio);
+void ath9k_hw_cfg_gpio_input(struct ath_hal *ah, u32 gpio);
 #endif
diff --git a/drivers/net/wireless/ath9k/beacon.c b/drivers/net/wireless/ath9k/beacon.c
index 00a0eaa..9e15c30 100644
--- a/drivers/net/wireless/ath9k/beacon.c
+++ b/drivers/net/wireless/ath9k/beacon.c
@@ -16,7 +16,6 @@
 
  /* Implementation of beacon processing. */
 
-#include <asm/unaligned.h>
 #include "core.h"
 
 /*
@@ -26,14 +25,13 @@
  *  the operating mode of the station (AP or AdHoc).  Parameters are AIFS
  *  settings and channel width min/max
 */
-
 static int ath_beaconq_config(struct ath_softc *sc)
 {
 	struct ath_hal *ah = sc->sc_ah;
 	struct ath9k_tx_queue_info qi;
 
 	ath9k_hw_get_txq_props(ah, sc->sc_bhalq, &qi);
-	if (sc->sc_opmode == ATH9K_M_HOSTAP) {
+	if (sc->sc_ah->ah_opmode == ATH9K_M_HOSTAP) {
 		/* Always burst out beacon and CAB traffic. */
 		qi.tqi_aifs = 1;
 		qi.tqi_cwmin = 0;
@@ -63,19 +61,18 @@
  *  up all required antenna switch parameters, rate codes, and channel flags.
  *  Beacons are always sent out at the lowest rate, and are not retried.
 */
-
 static void ath_beacon_setup(struct ath_softc *sc,
-	struct ath_vap *avp, struct ath_buf *bf)
+			     struct ath_vap *avp, struct ath_buf *bf)
 {
 	struct sk_buff *skb = (struct sk_buff *)bf->bf_mpdu;
 	struct ath_hal *ah = sc->sc_ah;
 	struct ath_desc *ds;
-	int flags, antenna;
+	struct ath9k_11n_rate_series series[4];
 	const struct ath9k_rate_table *rt;
+	int flags, antenna;
 	u8 rix, rate;
 	int ctsrate = 0;
 	int ctsduration = 0;
-	struct ath9k_11n_rate_series  series[4];
 
 	DPRINTF(sc, ATH_DBG_BEACON, "%s: m %p len %u\n",
 		__func__, skb, skb->len);
@@ -85,7 +82,7 @@
 
 	flags = ATH9K_TXDESC_NOACK;
 
-	if (sc->sc_opmode == ATH9K_M_IBSS &&
+	if (sc->sc_ah->ah_opmode == ATH9K_M_IBSS &&
 	    (ah->ah_caps.hw_caps & ATH9K_HW_CAP_VEOL)) {
 		ds->ds_link = bf->bf_daddr; /* self-linked */
 		flags |= ATH9K_TXDESC_VEOL;
@@ -111,27 +108,28 @@
 	rix = 0;
 	rt = sc->sc_currates;
 	rate = rt->info[rix].rateCode;
-	if (sc->sc_flags & ATH_PREAMBLE_SHORT)
+	if (sc->sc_flags & SC_OP_PREAMBLE_SHORT)
 		rate |= rt->info[rix].shortPreamble;
 
-	ath9k_hw_set11n_txdesc(ah, ds
-			      , skb->len + FCS_LEN /* frame length */
-			      , ATH9K_PKT_TYPE_BEACON /* Atheros packet type */
-			      , avp->av_btxctl.txpower /* txpower XXX */
-			      , ATH9K_TXKEYIX_INVALID /* no encryption */
-			      , ATH9K_KEY_TYPE_CLEAR /* no encryption */
-			      , flags /* no ack, veol for beacons */
+	ath9k_hw_set11n_txdesc(ah, ds,
+			       skb->len + FCS_LEN,     /* frame length */
+			       ATH9K_PKT_TYPE_BEACON,  /* Atheros packet type */
+			       avp->av_btxctl.txpower, /* txpower XXX */
+			       ATH9K_TXKEYIX_INVALID,  /* no encryption */
+			       ATH9K_KEY_TYPE_CLEAR,   /* no encryption */
+			       flags                   /* no ack,
+							  veol for beacons */
 		);
 
 	/* NB: beacon's BufLen must be a multiple of 4 bytes */
-	ath9k_hw_filltxdesc(ah, ds
-			   , roundup(skb->len, 4) /* buffer length */
-			   , true /* first segment */
-			   , true /* last segment */
-			   , ds /* first descriptor */
+	ath9k_hw_filltxdesc(ah, ds,
+			    roundup(skb->len, 4), /* buffer length */
+			    true,                 /* first segment */
+			    true,                 /* last segment */
+			    ds                    /* first descriptor */
 		);
 
-	memzero(series, sizeof(struct ath9k_11n_rate_series) * 4);
+	memset(series, 0, sizeof(struct ath9k_11n_rate_series) * 4);
 	series[0].Tries = 1;
 	series[0].Rate = rate;
 	series[0].ChSel = sc->sc_tx_chainmask;
@@ -140,55 +138,6 @@
 		ctsrate, ctsduration, series, 4, 0);
 }
 
-/* Move everything from the vap's mcast queue to the hardware cab queue.
- * Caller must hold mcasq lock and cabq lock
- * XXX MORE_DATA bit?
- */
-static void empty_mcastq_into_cabq(struct ath_hal *ah,
-	struct ath_txq *mcastq, struct ath_txq *cabq)
-{
-	struct ath_buf *bfmcast;
-
-	BUG_ON(list_empty(&mcastq->axq_q));
-
-	bfmcast = list_first_entry(&mcastq->axq_q, struct ath_buf, list);
-
-	/* link the descriptors */
-	if (!cabq->axq_link)
-		ath9k_hw_puttxbuf(ah, cabq->axq_qnum, bfmcast->bf_daddr);
-	else
-		*cabq->axq_link = bfmcast->bf_daddr;
-
-	/* append the private vap mcast list to  the cabq */
-
-	cabq->axq_depth	+= mcastq->axq_depth;
-	cabq->axq_totalqueued += mcastq->axq_totalqueued;
-	cabq->axq_linkbuf = mcastq->axq_linkbuf;
-	cabq->axq_link = mcastq->axq_link;
-	list_splice_tail_init(&mcastq->axq_q, &cabq->axq_q);
-	mcastq->axq_depth = 0;
-	mcastq->axq_totalqueued = 0;
-	mcastq->axq_linkbuf = NULL;
-	mcastq->axq_link = NULL;
-}
-
-/* This is only run at DTIM. We move everything from the vap's mcast queue
- * to the hardware cab queue. Caller must hold the mcastq lock. */
-static void trigger_mcastq(struct ath_hal *ah,
-	struct ath_txq *mcastq, struct ath_txq *cabq)
-{
-	spin_lock_bh(&cabq->axq_lock);
-
-	if (!list_empty(&mcastq->axq_q))
-		empty_mcastq_into_cabq(ah, mcastq, cabq);
-
-	/* cabq is gated by beacon so it is safe to start here */
-	if (!list_empty(&cabq->axq_q))
-		ath9k_hw_txstart(ah, cabq->axq_qnum);
-
-	spin_unlock_bh(&cabq->axq_lock);
-}
-
 /*
  *  Generate beacon frame and queue cab data for a vap.
  *
@@ -199,39 +148,36 @@
 */
 static struct ath_buf *ath_beacon_generate(struct ath_softc *sc, int if_id)
 {
-	struct ath_hal *ah = sc->sc_ah;
 	struct ath_buf *bf;
 	struct ath_vap *avp;
 	struct sk_buff *skb;
-	int cabq_depth;
-	int mcastq_depth;
-	int is_beacon_dtim = 0;
-	unsigned int curlen;
 	struct ath_txq *cabq;
-	struct ath_txq *mcastq;
 	struct ieee80211_tx_info *info;
+	int cabq_depth;
+
 	avp = sc->sc_vaps[if_id];
-
-	mcastq = &avp->av_mcastq;
-	cabq = sc->sc_cabq;
-
 	ASSERT(avp);
 
+	cabq = sc->sc_cabq;
+
 	if (avp->av_bcbuf == NULL) {
 		DPRINTF(sc, ATH_DBG_BEACON, "%s: avp=%p av_bcbuf=%p\n",
 			__func__, avp, avp->av_bcbuf);
 		return NULL;
 	}
-	bf = avp->av_bcbuf;
-	skb = (struct sk_buff *) bf->bf_mpdu;
 
-	/*
-	 * Update dynamic beacon contents.  If this returns
-	 * non-zero then we need to remap the memory because
-	 * the beacon frame changed size (probably because
-	 * of the TIM bitmap).
-	 */
-	curlen = skb->len;
+	bf = avp->av_bcbuf;
+	skb = (struct sk_buff *)bf->bf_mpdu;
+	if (skb) {
+		pci_unmap_single(sc->pdev, bf->bf_dmacontext,
+				 skb_end_pointer(skb) - skb->head,
+				 PCI_DMA_TODEVICE);
+	}
+
+	skb = ieee80211_beacon_get(sc->hw, avp->av_if_data);
+	bf->bf_mpdu = skb;
+	if (skb == NULL)
+		return NULL;
 
 	info = IEEE80211_SKB_CB(skb);
 	if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) {
@@ -239,29 +185,18 @@
 		 * TODO: make sure the seq# gets assigned properly (vs. other
 		 * TX frames)
 		 */
-		struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+		struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
 		sc->seq_no += 0x10;
 		hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG);
 		hdr->seq_ctrl |= cpu_to_le16(sc->seq_no);
 	}
 
-	/* XXX: spin_lock_bh should not be used here, but sparse bitches
-	 * otherwise. We should fix sparse :) */
-	spin_lock_bh(&mcastq->axq_lock);
-	mcastq_depth = avp->av_mcastq.axq_depth;
+	bf->bf_buf_addr = bf->bf_dmacontext =
+		pci_map_single(sc->pdev, skb->data,
+			       skb_end_pointer(skb) - skb->head,
+			       PCI_DMA_TODEVICE);
 
-	if (ath_update_beacon(sc, if_id, &avp->av_boff, skb, mcastq_depth) ==
-	    1) {
-		ath_skb_unmap_single(sc, skb, PCI_DMA_TODEVICE,
-				     get_dma_mem_context(bf, bf_dmacontext));
-		bf->bf_buf_addr = ath_skb_map_single(sc, skb, PCI_DMA_TODEVICE,
-			get_dma_mem_context(bf, bf_dmacontext));
-	} else {
-		pci_dma_sync_single_for_cpu(sc->pdev,
-					    bf->bf_buf_addr,
-					    skb_tailroom(skb),
-					    PCI_DMA_TODEVICE);
-	}
+	skb = ieee80211_get_buffered_bc(sc->hw, avp->av_if_data);
 
 	/*
 	 * if the CABQ traffic from previous DTIM is pending and the current
@@ -275,9 +210,7 @@
 	cabq_depth = cabq->axq_depth;
 	spin_unlock_bh(&cabq->axq_lock);
 
-	is_beacon_dtim = avp->av_boff.bo_tim[4] & 1;
-
-	if (mcastq_depth && is_beacon_dtim && cabq_depth) {
+	if (skb && cabq_depth) {
 		/*
 		 * Unlock the cabq lock as ath_tx_draintxq acquires
 		 * the lock again which is a common function and that
@@ -297,10 +230,11 @@
 	 * Enable the CAB queue before the beacon queue to
 	 * insure cab frames are triggered by this beacon.
 	 */
-	if (is_beacon_dtim)
-		trigger_mcastq(ah, mcastq, cabq);
+	while (skb) {
+		ath_tx_cabq(sc, skb);
+		skb = ieee80211_get_buffered_bc(sc->hw, avp->av_if_data);
+	}
 
-	spin_unlock_bh(&mcastq->axq_lock);
 	return bf;
 }
 
@@ -308,7 +242,6 @@
  * Startup beacon transmission for adhoc mode when they are sent entirely
  * by the hardware using the self-linked descriptor + veol trick.
 */
-
 static void ath_beacon_start_adhoc(struct ath_softc *sc, int if_id)
 {
 	struct ath_hal *ah = sc->sc_ah;
@@ -345,12 +278,11 @@
  *  min/max, and enable aifs). The info structure does not need to be
  *  persistant.
 */
-
 int ath_beaconq_setup(struct ath_hal *ah)
 {
 	struct ath9k_tx_queue_info qi;
 
-	memzero(&qi, sizeof(qi));
+	memset(&qi, 0, sizeof(qi));
 	qi.tqi_aifs = 1;
 	qi.tqi_cwmin = 0;
 	qi.tqi_cwmax = 0;
@@ -366,29 +298,27 @@
  *  the ATH interface.  This routine also calculates the beacon "slot" for
  *  staggared beacons in the mBSSID case.
 */
-
 int ath_beacon_alloc(struct ath_softc *sc, int if_id)
 {
 	struct ath_vap *avp;
-	struct ieee80211_hdr *wh;
+	struct ieee80211_hdr *hdr;
 	struct ath_buf *bf;
 	struct sk_buff *skb;
+	__le64 tstamp;
 
 	avp = sc->sc_vaps[if_id];
 	ASSERT(avp);
 
 	/* Allocate a beacon descriptor if we haven't done so. */
 	if (!avp->av_bcbuf) {
-		/*
-		 * Allocate beacon state for hostap/ibss.  We know
-		 * a buffer is available.
-		 */
+		/* Allocate beacon state for hostap/ibss.  We know
+		 * a buffer is available. */
 
 		avp->av_bcbuf = list_first_entry(&sc->sc_bbuf,
-				struct ath_buf, list);
+						 struct ath_buf, list);
 		list_del(&avp->av_bcbuf->list);
 
-		if (sc->sc_opmode == ATH9K_M_HOSTAP ||
+		if (sc->sc_ah->ah_opmode == ATH9K_M_HOSTAP ||
 		    !(sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_VEOL)) {
 			int slot;
 			/*
@@ -421,17 +351,16 @@
 	bf = avp->av_bcbuf;
 	if (bf->bf_mpdu != NULL) {
 		skb = (struct sk_buff *)bf->bf_mpdu;
-		ath_skb_unmap_single(sc, skb, PCI_DMA_TODEVICE,
-				     get_dma_mem_context(bf, bf_dmacontext));
+		pci_unmap_single(sc->pdev, bf->bf_dmacontext,
+				 skb_end_pointer(skb) - skb->head,
+				 PCI_DMA_TODEVICE);
 		dev_kfree_skb_any(skb);
 		bf->bf_mpdu = NULL;
 	}
 
 	/*
-	 * NB: the beacon data buffer must be 32-bit aligned;
-	 * we assume the wbuf routines will return us something
-	 * with this alignment (perhaps should assert).
-	 * FIXME: Fill avp->av_boff.bo_tim,avp->av_btxctl.txpower and
+	 * NB: the beacon data buffer must be 32-bit aligned.
+	 * FIXME: Fill avp->av_btxctl.txpower and
 	 * avp->av_btxctl.shortPreamble
 	 */
 	skb = ieee80211_beacon_get(sc->hw, avp->av_if_data);
@@ -441,6 +370,9 @@
 		return -ENOMEM;
 	}
 
+	tstamp = ((struct ieee80211_mgmt *)skb->data)->u.beacon.timestamp;
+	sc->bc_tstamp = le64_to_cpu(tstamp);
+
 	/*
 	 * Calculate a TSF adjustment factor required for
 	 * staggered beacons.  Note that we assume the format
@@ -452,9 +384,8 @@
 		__le64 val;
 		int intval;
 
-		/* FIXME: Use default value for now: Sujith */
-
-		intval = ATH_DEFAULT_BINTVAL;
+		intval = sc->hw->conf.beacon_int ?
+			sc->hw->conf.beacon_int : ATH_DEFAULT_BINTVAL;
 
 		/*
 		 * The beacon interval is in TU's; the TSF in usecs.
@@ -475,12 +406,14 @@
 			__func__, "stagger",
 			avp->av_bslot, intval, (unsigned long long)tsfadjust);
 
-		wh = (struct ieee80211_hdr *)skb->data;
-		memcpy(&wh[1], &val, sizeof(val));
+		hdr = (struct ieee80211_hdr *)skb->data;
+		memcpy(&hdr[1], &val, sizeof(val));
 	}
 
-	bf->bf_buf_addr = ath_skb_map_single(sc, skb, PCI_DMA_TODEVICE,
-		get_dma_mem_context(bf, bf_dmacontext));
+	bf->bf_buf_addr = bf->bf_dmacontext =
+		pci_map_single(sc->pdev, skb->data,
+			       skb_end_pointer(skb) - skb->head,
+			       PCI_DMA_TODEVICE);
 	bf->bf_mpdu = skb;
 
 	return 0;
@@ -490,9 +423,8 @@
  *  Reclaim beacon resources and return buffer to the pool.
  *
  *  Checks the VAP to put the beacon frame buffer back to the ATH object
- *  queue, and de-allocates any wbuf frames that were sent as CAB traffic.
+ *  queue, and de-allocates any skbs that were sent as CAB traffic.
 */
-
 void ath_beacon_return(struct ath_softc *sc, struct ath_vap *avp)
 {
 	if (avp->av_bcbuf != NULL) {
@@ -506,8 +438,9 @@
 		bf = avp->av_bcbuf;
 		if (bf->bf_mpdu != NULL) {
 			struct sk_buff *skb = (struct sk_buff *)bf->bf_mpdu;
-			ath_skb_unmap_single(sc, skb, PCI_DMA_TODEVICE,
-				get_dma_mem_context(bf, bf_dmacontext));
+			pci_unmap_single(sc->pdev, bf->bf_dmacontext,
+					 skb_end_pointer(skb) - skb->head,
+					 PCI_DMA_TODEVICE);
 			dev_kfree_skb_any(skb);
 			bf->bf_mpdu = NULL;
 		}
@@ -518,44 +451,14 @@
 }
 
 /*
- *  Reclaim beacon resources and return buffer to the pool.
- *
- *  This function will free any wbuf frames that are still attached to the
- *  beacon buffers in the ATH object.  Note that this does not de-allocate
- *  any wbuf objects that are in the transmit queue and have not yet returned
- *  to the ATH object.
-*/
-
-void ath_beacon_free(struct ath_softc *sc)
-{
-	struct ath_buf *bf;
-
-	list_for_each_entry(bf, &sc->sc_bbuf, list) {
-		if (bf->bf_mpdu != NULL) {
-			struct sk_buff *skb = (struct sk_buff *) bf->bf_mpdu;
-			ath_skb_unmap_single(sc, skb, PCI_DMA_TODEVICE,
-				get_dma_mem_context(bf, bf_dmacontext));
-			dev_kfree_skb_any(skb);
-			bf->bf_mpdu = NULL;
-		}
-	}
-}
-
-/*
  * Tasklet for Sending Beacons
  *
  * Transmit one or more beacon frames at SWBA.  Dynamic updates to the frame
  * contents are done as needed and the slot time is also adjusted based on
  * current state.
- *
- * This tasklet is not scheduled, it's called in ISR context.
 */
-
 void ath9k_beacon_tasklet(unsigned long data)
 {
-#define TSF_TO_TU(_h,_l)					\
-	((((u32)(_h)) << 22) | (((u32)(_l)) >> 10))
-
 	struct ath_softc *sc = (struct ath_softc *)data;
 	struct ath_hal *ah = sc->sc_ah;
 	struct ath_buf *bf = NULL;
@@ -568,7 +471,7 @@
 	u32 tsftu;
 	u16 intval;
 
-	if (sc->sc_noreset) {
+	if (sc->sc_flags & SC_OP_NO_RESET) {
 		show_cycles = ath9k_hw_GetMibCycleCountsPct(ah,
 							    &rx_clear,
 							    &rx_frame,
@@ -581,6 +484,8 @@
 	 * and wait for the next.  Missed beacons indicate
 	 * a problem and should not occur.  If we miss too
 	 * many consecutive beacons reset the device.
+	 *
+	 * FIXME: Clean up this mess !!
 	 */
 	if (ath9k_hw_numtxpending(ah, sc->sc_bhalq) != 0) {
 		sc->sc_bmisscount++;
@@ -590,25 +495,22 @@
 		 *      (in that layer).
 		 */
 		if (sc->sc_bmisscount < BSTUCK_THRESH) {
-			if (sc->sc_noreset) {
+			if (sc->sc_flags & SC_OP_NO_RESET) {
 				DPRINTF(sc, ATH_DBG_BEACON,
 					"%s: missed %u consecutive beacons\n",
 					__func__, sc->sc_bmisscount);
 				if (show_cycles) {
 					/*
-					 * Display cycle counter stats
-					 * from HW to aide in debug of
-					 * stickiness.
+					 * Display cycle counter stats from HW
+					 * to aide in debug of stickiness.
 					 */
-					DPRINTF(sc,
-						ATH_DBG_BEACON,
+					DPRINTF(sc, ATH_DBG_BEACON,
 						"%s: busy times: rx_clear=%d, "
 						"rx_frame=%d, tx_frame=%d\n",
 						__func__, rx_clear, rx_frame,
 						tx_frame);
 				} else {
-					DPRINTF(sc,
-						ATH_DBG_BEACON,
+					DPRINTF(sc, ATH_DBG_BEACON,
 						"%s: unable to obtain "
 						"busy times\n", __func__);
 				}
@@ -618,10 +520,9 @@
 					__func__, sc->sc_bmisscount);
 			}
 		} else if (sc->sc_bmisscount >= BSTUCK_THRESH) {
-			if (sc->sc_noreset) {
+			if (sc->sc_flags & SC_OP_NO_RESET) {
 				if (sc->sc_bmisscount == BSTUCK_THRESH) {
-					DPRINTF(sc,
-						ATH_DBG_BEACON,
+					DPRINTF(sc, ATH_DBG_BEACON,
 						"%s: beacon is officially "
 						"stuck\n", __func__);
 					ath9k_hw_dmaRegDump(ah);
@@ -633,13 +534,12 @@
 				ath_bstuck_process(sc);
 			}
 		}
-
 		return;
 	}
+
 	if (sc->sc_bmisscount != 0) {
-		if (sc->sc_noreset) {
-			DPRINTF(sc,
-				ATH_DBG_BEACON,
+		if (sc->sc_flags & SC_OP_NO_RESET) {
+			DPRINTF(sc, ATH_DBG_BEACON,
 				"%s: resume beacon xmit after %u misses\n",
 				__func__, sc->sc_bmisscount);
 		} else {
@@ -656,17 +556,19 @@
 	 * on the tsf to safeguard against missing an swba.
 	 */
 
-	/* FIXME: Use default value for now - Sujith */
-	intval = ATH_DEFAULT_BINTVAL;
+	intval = sc->hw->conf.beacon_int ?
+		sc->hw->conf.beacon_int : ATH_DEFAULT_BINTVAL;
 
 	tsf = ath9k_hw_gettsf64(ah);
 	tsftu = TSF_TO_TU(tsf>>32, tsf);
 	slot = ((tsftu % intval) * ATH_BCBUF) / intval;
 	if_id = sc->sc_bslot[(slot + 1) % ATH_BCBUF];
+
 	DPRINTF(sc, ATH_DBG_BEACON,
-			"%s: slot %d [tsf %llu tsftu %u intval %u] if_id %d\n",
-			__func__, slot, (unsigned long long) tsf, tsftu,
-			intval, if_id);
+		"%s: slot %d [tsf %llu tsftu %u intval %u] if_id %d\n",
+		__func__, slot, (unsigned long long)tsf, tsftu,
+		intval, if_id);
+
 	bfaddr = 0;
 	if (if_id != ATH_IF_ID_ANY) {
 		bf = ath_beacon_generate(sc, if_id);
@@ -717,22 +619,20 @@
 
 		sc->ast_be_xmit += bc;     /* XXX per-vap? */
 	}
-#undef TSF_TO_TU
 }
 
 /*
  *  Tasklet for Beacon Stuck processing
  *
  *  Processing for Beacon Stuck.
- *  Basically calls the ath_internal_reset function to reset the chip.
+ *  Basically resets the chip.
 */
-
 void ath_bstuck_process(struct ath_softc *sc)
 {
 	DPRINTF(sc, ATH_DBG_BEACON,
 		"%s: stuck beacon; resetting (bmiss count %u)\n",
 		__func__, sc->sc_bmisscount);
-	ath_internal_reset(sc);
+	ath_reset(sc, false);
 }
 
 /*
@@ -750,40 +650,32 @@
  * interrupt when we stop seeing beacons from the AP
  * we've associated with.
  */
-
 void ath_beacon_config(struct ath_softc *sc, int if_id)
 {
-#define TSF_TO_TU(_h,_l)					\
-	((((u32)(_h)) << 22) | (((u32)(_l)) >> 10))
 	struct ath_hal *ah = sc->sc_ah;
-	u32 nexttbtt, intval;
 	struct ath_beacon_config conf;
 	enum ath9k_opmode av_opmode;
+	u32 nexttbtt, intval;
 
 	if (if_id != ATH_IF_ID_ANY)
 		av_opmode = sc->sc_vaps[if_id]->av_opmode;
 	else
-		av_opmode = sc->sc_opmode;
+		av_opmode = sc->sc_ah->ah_opmode;
 
-	memzero(&conf, sizeof(struct ath_beacon_config));
+	memset(&conf, 0, sizeof(struct ath_beacon_config));
 
-	/* FIXME: Use default values for now - Sujith */
-	/* Query beacon configuration first */
-	/*
-	 * Protocol stack doesn't support dynamic beacon configuration,
-	 * use default configurations.
-	 */
-	conf.beacon_interval = ATH_DEFAULT_BINTVAL;
+	conf.beacon_interval = sc->hw->conf.beacon_int ?
+		sc->hw->conf.beacon_int : ATH_DEFAULT_BINTVAL;
 	conf.listen_interval = 1;
 	conf.dtim_period = conf.beacon_interval;
 	conf.dtim_count = 1;
 	conf.bmiss_timeout = ATH_DEFAULT_BMISS_LIMIT * conf.beacon_interval;
 
 	/* extract tstamp from last beacon and convert to TU */
-	nexttbtt = TSF_TO_TU(get_unaligned_le32(conf.u.last_tstamp + 4),
-			     get_unaligned_le32(conf.u.last_tstamp));
+	nexttbtt = TSF_TO_TU(sc->bc_tstamp >> 32, sc->bc_tstamp);
+
 	/* XXX conditionalize multi-bss support? */
-	if (sc->sc_opmode == ATH9K_M_HOSTAP) {
+	if (sc->sc_ah->ah_opmode == ATH9K_M_HOSTAP) {
 		/*
 		 * For multi-bss ap support beacons are either staggered
 		 * evenly over N slots or burst together.  For the former
@@ -797,14 +689,16 @@
 		intval = conf.beacon_interval & ATH9K_BEACON_PERIOD;
 	}
 
-	if (nexttbtt == 0)      /* e.g. for ap mode */
+	if (nexttbtt == 0)	/* e.g. for ap mode */
 		nexttbtt = intval;
-	else if (intval)        /* NB: can be 0 for monitor mode */
+	else if (intval)	/* NB: can be 0 for monitor mode */
 		nexttbtt = roundup(nexttbtt, intval);
+
 	DPRINTF(sc, ATH_DBG_BEACON, "%s: nexttbtt %u intval %u (%u)\n",
 		__func__, nexttbtt, intval, conf.beacon_interval);
+
 	/* Check for ATH9K_M_HOSTAP and sc_nostabeacons for WDS client */
-	if (sc->sc_opmode == ATH9K_M_STA) {
+	if (sc->sc_ah->ah_opmode == ATH9K_M_STA) {
 		struct ath9k_beacon_state bs;
 		u64 tsf;
 		u32 tsftu;
@@ -816,19 +710,19 @@
 		 * last beacon we received (which may be none).
 		 */
 		dtimperiod = conf.dtim_period;
-		if (dtimperiod <= 0)        /* NB: 0 if not known */
+		if (dtimperiod <= 0)		/* NB: 0 if not known */
 			dtimperiod = 1;
 		dtimcount = conf.dtim_count;
-		if (dtimcount >= dtimperiod)    /* NB: sanity check */
-			dtimcount = 0;      /* XXX? */
-		cfpperiod = 1;          /* NB: no PCF support yet */
+		if (dtimcount >= dtimperiod)	/* NB: sanity check */
+			dtimcount = 0;
+		cfpperiod = 1;			/* NB: no PCF support yet */
 		cfpcount = 0;
 
 		sleepduration = conf.listen_interval * intval;
 		if (sleepduration <= 0)
 			sleepduration = intval;
 
-#define FUDGE   2
+#define FUDGE 2
 		/*
 		 * Pull nexttbtt forward to reflect the current
 		 * TSF and calculate dtim+cfp state for the result.
@@ -844,7 +738,7 @@
 			}
 		} while (nexttbtt < tsftu);
 #undef FUDGE
-		memzero(&bs, sizeof(bs));
+		memset(&bs, 0, sizeof(bs));
 		bs.bs_intval = intval;
 		bs.bs_nexttbtt = nexttbtt;
 		bs.bs_dtimperiod = dtimperiod*intval;
@@ -852,6 +746,7 @@
 		bs.bs_cfpperiod = cfpperiod*bs.bs_dtimperiod;
 		bs.bs_cfpnext = bs.bs_nextdtim + cfpcount*bs.bs_dtimperiod;
 		bs.bs_cfpmaxduration = 0;
+
 		/*
 		 * Calculate the number of consecutive beacons to miss
 		 * before taking a BMISS interrupt.  The configuration
@@ -860,9 +755,8 @@
 		 * result to at most 15 beacons.
 		 */
 		if (sleepduration > intval) {
-			bs.bs_bmissthreshold =
-				conf.listen_interval *
-					ATH_DEFAULT_BMISS_LIMIT / 2;
+			bs.bs_bmissthreshold = conf.listen_interval *
+				ATH_DEFAULT_BMISS_LIMIT / 2;
 		} else {
 			bs.bs_bmissthreshold =
 				DIV_ROUND_UP(conf.bmiss_timeout, intval);
@@ -882,8 +776,8 @@
 		 * XXX fixed at 100ms
 		 */
 
-		bs.bs_sleepduration =
-			roundup(IEEE80211_MS_TO_TU(100), sleepduration);
+		bs.bs_sleepduration = roundup(IEEE80211_MS_TO_TU(100),
+					      sleepduration);
 		if (bs.bs_sleepduration > bs.bs_dtimperiod)
 			bs.bs_sleepduration = bs.bs_dtimperiod;
 
@@ -899,19 +793,19 @@
 			"cfp:period %u "
 			"maxdur %u "
 			"next %u "
-			"timoffset %u\n"
-			, __func__
-			, (unsigned long long)tsf, tsftu
-			, bs.bs_intval
-			, bs.bs_nexttbtt
-			, bs.bs_dtimperiod
-			, bs.bs_nextdtim
-			, bs.bs_bmissthreshold
-			, bs.bs_sleepduration
-			, bs.bs_cfpperiod
-			, bs.bs_cfpmaxduration
-			, bs.bs_cfpnext
-			, bs.bs_timoffset
+			"timoffset %u\n",
+			__func__,
+			(unsigned long long)tsf, tsftu,
+			bs.bs_intval,
+			bs.bs_nexttbtt,
+			bs.bs_dtimperiod,
+			bs.bs_nextdtim,
+			bs.bs_bmissthreshold,
+			bs.bs_sleepduration,
+			bs.bs_cfpperiod,
+			bs.bs_cfpmaxduration,
+			bs.bs_cfpnext,
+			bs.bs_timoffset
 			);
 
 		ath9k_hw_set_interrupts(ah, 0);
@@ -924,12 +818,12 @@
 		ath9k_hw_set_interrupts(ah, 0);
 		if (nexttbtt == intval)
 			intval |= ATH9K_BEACON_RESET_TSF;
-		if (sc->sc_opmode == ATH9K_M_IBSS) {
+		if (sc->sc_ah->ah_opmode == ATH9K_M_IBSS) {
 			/*
 			 * Pull nexttbtt forward to reflect the current
-			 * TSF .
+			 * TSF
 			 */
-#define FUDGE   2
+#define FUDGE 2
 			if (!(intval & ATH9K_BEACON_RESET_TSF)) {
 				tsf = ath9k_hw_gettsf64(ah);
 				tsftu = TSF_TO_TU((u32)(tsf>>32),
@@ -956,7 +850,7 @@
 			if (!(ah->ah_caps.hw_caps & ATH9K_HW_CAP_VEOL))
 				sc->sc_imask |= ATH9K_INT_SWBA;
 			ath_beaconq_config(sc);
-		} else if (sc->sc_opmode == ATH9K_M_HOSTAP) {
+		} else if (sc->sc_ah->ah_opmode == ATH9K_M_HOSTAP) {
 			/*
 			 * In AP mode we enable the beacon timers and
 			 * SWBA interrupts to prepare beacon frames.
@@ -972,11 +866,10 @@
 		 * When using a self-linked beacon descriptor in
 		 * ibss mode load it once here.
 		 */
-		if (sc->sc_opmode == ATH9K_M_IBSS &&
+		if (sc->sc_ah->ah_opmode == ATH9K_M_IBSS &&
 		    (ah->ah_caps.hw_caps & ATH9K_HW_CAP_VEOL))
 			ath_beacon_start_adhoc(sc, 0);
 	}
-#undef TSF_TO_TU
 }
 
 /* Function to collect beacon rssi data and resync beacon if necessary */
@@ -988,5 +881,5 @@
 	 * beacon frame we just received.
 	 */
 	ath_beacon_config(sc, if_id);
-	sc->sc_beacons = 1;
+	sc->sc_flags |= SC_OP_BEACONS;
 }
diff --git a/drivers/net/wireless/ath9k/core.c b/drivers/net/wireless/ath9k/core.c
index f6c4528..c5033f6 100644
--- a/drivers/net/wireless/ath9k/core.c
+++ b/drivers/net/wireless/ath9k/core.c
@@ -21,9 +21,6 @@
 
 static int ath_outdoor;		/* enable outdoor use */
 
-static const u8 ath_bcast_mac[ETH_ALEN] =
-    { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
-
 static u32 ath_chainmask_sel_up_rssi_thres =
 	ATH_CHAINMASK_SEL_UP_RSSI_THRES;
 static u32 ath_chainmask_sel_down_rssi_thres =
@@ -54,10 +51,8 @@
  *  Set current operating mode
  *
  *  This function initializes and fills the rate table in the ATH object based
- *  on the operating mode.  The blink rates are also set up here, although
- *  they have been superceeded by the ath_led module.
+ *  on the operating mode.
 */
-
 static void ath_setcurmode(struct ath_softc *sc, enum wireless_mode mode)
 {
 	const struct ath9k_rate_table *rt;
@@ -70,7 +65,7 @@
 	for (i = 0; i < rt->rateCount; i++)
 		sc->sc_rixmap[rt->info[i].rateCode] = (u8) i;
 
-	memzero(sc->sc_hwmap, sizeof(sc->sc_hwmap));
+	memset(sc->sc_hwmap, 0, sizeof(sc->sc_hwmap));
 	for (i = 0; i < 256; i++) {
 		u8 ix = rt->rateCodeToIndex[i];
 
@@ -235,7 +230,7 @@
  *  Determine mode from channel flags
  *
  *  This routine will provide the enumerated WIRELESSS_MODE value based
- *  on the settings of the channel flags.  If ho valid set of flags
+ *  on the settings of the channel flags.  If no valid set of flags
  *  exist, the lowest mode (11b) is selected.
 */
 
@@ -260,7 +255,8 @@
 	else if (chan->chanmode == CHANNEL_G_HT40MINUS)
 		return ATH9K_MODE_11NG_HT40MINUS;
 
-	/* NB: should not get here */
+	WARN_ON(1); /* should not get here */
+
 	return ATH9K_MODE_11B;
 }
 
@@ -275,14 +271,12 @@
 {
 	struct ath_hal *ah = sc->sc_ah;
 
-	DPRINTF(sc, ATH_DBG_CONFIG, "%s: invalid %u\n",
-		__func__, sc->sc_invalid);
+	DPRINTF(sc, ATH_DBG_CONFIG, "%s: invalid %ld\n",
+		__func__, sc->sc_flags & SC_OP_INVALID);
 
 	/*
 	 * Shutdown the hardware and driver:
 	 *    stop output from above
-	 *    reset 802.11 state machine
-	 *      (sends station deassoc/deauth frames)
 	 *    turn off timers
 	 *    disable interrupts
 	 *    clear transmit machinery
@@ -294,10 +288,8 @@
 	 * hardware is gone (invalid).
 	 */
 
-	if (!sc->sc_invalid)
-		ath9k_hw_set_interrupts(ah, 0);
 	ath_draintxq(sc, false);
-	if (!sc->sc_invalid) {
+	if (!(sc->sc_flags & SC_OP_INVALID)) {
 		ath_stoprecv(sc);
 		ath9k_hw_phy_disable(ah);
 	} else
@@ -307,56 +299,6 @@
 }
 
 /*
- *  Start Scan
- *
- *  This function is called when starting a channel scan.  It will perform
- *  power save wakeup processing, set the filter for the scan, and get the
- *  chip ready to send broadcast packets out during the scan.
-*/
-
-void ath_scan_start(struct ath_softc *sc)
-{
-	struct ath_hal *ah = sc->sc_ah;
-	u32 rfilt;
-	u32 now = (u32) jiffies_to_msecs(get_timestamp());
-
-	sc->sc_scanning = 1;
-	rfilt = ath_calcrxfilter(sc);
-	ath9k_hw_setrxfilter(ah, rfilt);
-	ath9k_hw_write_associd(ah, ath_bcast_mac, 0);
-
-	/* Restore previous power management state. */
-
-	DPRINTF(sc, ATH_DBG_CONFIG, "%d.%03d | %s: RX filter 0x%x aid 0\n",
-		now / 1000, now % 1000, __func__, rfilt);
-}
-
-/*
- *  Scan End
- *
- *  This routine is called by the upper layer when the scan is completed.  This
- *  will set the filters back to normal operating mode, set the BSSID to the
- *  correct value, and restore the power save state.
-*/
-
-void ath_scan_end(struct ath_softc *sc)
-{
-	struct ath_hal *ah = sc->sc_ah;
-	u32 rfilt;
-	u32 now = (u32) jiffies_to_msecs(get_timestamp());
-
-	sc->sc_scanning = 0;
-	/* Request for a full reset due to rx packet filter changes */
-	sc->sc_full_reset = 1;
-	rfilt = ath_calcrxfilter(sc);
-	ath9k_hw_setrxfilter(ah, rfilt);
-	ath9k_hw_write_associd(ah, sc->sc_curbssid, sc->sc_curaid);
-
-	DPRINTF(sc, ATH_DBG_CONFIG, "%d.%03d | %s: RX filter 0x%x aid 0x%x\n",
-		now / 1000, now % 1000, __func__, rfilt, sc->sc_curaid);
-}
-
-/*
  * Set the current channel
  *
  * Set/change channels.  If the channel is really being changed, it's done
@@ -367,25 +309,23 @@
 {
 	struct ath_hal *ah = sc->sc_ah;
 	bool fastcc = true, stopped;
-	enum ath9k_ht_macmode ht_macmode;
 
-	if (sc->sc_invalid)	/* if the device is invalid or removed */
+	if (sc->sc_flags & SC_OP_INVALID) /* the device is invalid or removed */
 		return -EIO;
 
 	DPRINTF(sc, ATH_DBG_CONFIG,
 		"%s: %u (%u MHz) -> %u (%u MHz), cflags:%x\n",
 		__func__,
-		ath9k_hw_mhz2ieee(ah, sc->sc_curchan.channel,
-				  sc->sc_curchan.channelFlags),
-		sc->sc_curchan.channel,
+		ath9k_hw_mhz2ieee(ah, sc->sc_ah->ah_curchan->channel,
+				  sc->sc_ah->ah_curchan->channelFlags),
+		sc->sc_ah->ah_curchan->channel,
 		ath9k_hw_mhz2ieee(ah, hchan->channel, hchan->channelFlags),
 		hchan->channel, hchan->channelFlags);
 
-	ht_macmode = ath_cwm_macmode(sc);
-
-	if (hchan->channel != sc->sc_curchan.channel ||
-	    hchan->channelFlags != sc->sc_curchan.channelFlags ||
-	    sc->sc_update_chainmask || sc->sc_full_reset) {
+	if (hchan->channel != sc->sc_ah->ah_curchan->channel ||
+	    hchan->channelFlags != sc->sc_ah->ah_curchan->channelFlags ||
+	    (sc->sc_flags & SC_OP_CHAINMASK_UPDATE) ||
+	    (sc->sc_flags & SC_OP_FULL_RESET)) {
 		int status;
 		/*
 		 * This is only performed if the channel settings have
@@ -404,15 +344,16 @@
 		 * to flush data frames already in queue because of
 		 * changing channel. */
 
-		if (!stopped || sc->sc_full_reset)
+		if (!stopped || (sc->sc_flags & SC_OP_FULL_RESET))
 			fastcc = false;
 
 		spin_lock_bh(&sc->sc_resetlock);
-		if (!ath9k_hw_reset(ah, sc->sc_opmode, hchan,
-					ht_macmode, sc->sc_tx_chainmask,
-					sc->sc_rx_chainmask,
-					sc->sc_ht_extprotspacing,
-					fastcc, &status)) {
+		if (!ath9k_hw_reset(ah, hchan,
+				    sc->sc_ht_info.tx_chan_width,
+				    sc->sc_tx_chainmask,
+				    sc->sc_rx_chainmask,
+				    sc->sc_ht_extprotspacing,
+				    fastcc, &status)) {
 			DPRINTF(sc, ATH_DBG_FATAL,
 				"%s: unable to reset channel %u (%uMhz) "
 				"flags 0x%x hal status %u\n", __func__,
@@ -424,9 +365,8 @@
 		}
 		spin_unlock_bh(&sc->sc_resetlock);
 
-		sc->sc_curchan = *hchan;
-		sc->sc_update_chainmask = 0;
-		sc->sc_full_reset = 0;
+		sc->sc_flags &= ~SC_OP_CHAINMASK_UPDATE;
+		sc->sc_flags &= ~SC_OP_FULL_RESET;
 
 		/* Re-enable rx framework */
 		if (ath_startrecv(sc) != 0) {
@@ -477,7 +417,7 @@
 {
 	struct ath_chainmask_sel *cm = &an->an_chainmask_sel;
 
-	memzero(cm, sizeof(struct ath_chainmask_sel));
+	memset(cm, 0, sizeof(struct ath_chainmask_sel));
 
 	cm->cur_tx_mask = sc->sc_tx_chainmask;
 	cm->cur_rx_mask = sc->sc_rx_chainmask;
@@ -537,7 +477,7 @@
 
 void ath_update_chainmask(struct ath_softc *sc, int is_ht)
 {
-	sc->sc_update_chainmask = 1;
+	sc->sc_flags |= SC_OP_CHAINMASK_UPDATE;
 	if (is_ht) {
 		sc->sc_tx_chainmask = sc->sc_ah->ah_caps.tx_chainmask;
 		sc->sc_rx_chainmask = sc->sc_ah->ah_caps.rx_chainmask;
@@ -550,66 +490,126 @@
 		__func__, sc->sc_tx_chainmask, sc->sc_rx_chainmask);
 }
 
+/*******/
+/* ANI */
+/*******/
+
+/*
+ *  This routine performs the periodic noise floor calibration function
+ *  that is used to adjust and optimize the chip performance.  This
+ *  takes environmental changes (location, temperature) into account.
+ *  When the task is complete, it reschedules itself depending on the
+ *  appropriate interval that was calculated.
+ */
+
+static void ath_ani_calibrate(unsigned long data)
+{
+	struct ath_softc *sc;
+	struct ath_hal *ah;
+	bool longcal = false;
+	bool shortcal = false;
+	bool aniflag = false;
+	unsigned int timestamp = jiffies_to_msecs(jiffies);
+	u32 cal_interval;
+
+	sc = (struct ath_softc *)data;
+	ah = sc->sc_ah;
+
+	/*
+	* don't calibrate when we're scanning.
+	* we are most likely not on our home channel.
+	*/
+	if (sc->rx_filter & FIF_BCN_PRBRESP_PROMISC)
+		return;
+
+	/* Long calibration runs independently of short calibration. */
+	if ((timestamp - sc->sc_ani.sc_longcal_timer) >= ATH_LONG_CALINTERVAL) {
+		longcal = true;
+		DPRINTF(sc, ATH_DBG_ANI, "%s: longcal @%lu\n",
+			__func__, jiffies);
+		sc->sc_ani.sc_longcal_timer = timestamp;
+	}
+
+	/* Short calibration applies only while sc_caldone is false */
+	if (!sc->sc_ani.sc_caldone) {
+		if ((timestamp - sc->sc_ani.sc_shortcal_timer) >=
+		    ATH_SHORT_CALINTERVAL) {
+			shortcal = true;
+			DPRINTF(sc, ATH_DBG_ANI, "%s: shortcal @%lu\n",
+			       __func__, jiffies);
+			sc->sc_ani.sc_shortcal_timer = timestamp;
+			sc->sc_ani.sc_resetcal_timer = timestamp;
+		}
+	} else {
+		if ((timestamp - sc->sc_ani.sc_resetcal_timer) >=
+		    ATH_RESTART_CALINTERVAL) {
+			ath9k_hw_reset_calvalid(ah, ah->ah_curchan,
+						&sc->sc_ani.sc_caldone);
+			if (sc->sc_ani.sc_caldone)
+				sc->sc_ani.sc_resetcal_timer = timestamp;
+		}
+	}
+
+	/* Verify whether we must check ANI */
+	if ((timestamp - sc->sc_ani.sc_checkani_timer) >=
+	   ATH_ANI_POLLINTERVAL) {
+		aniflag = true;
+		sc->sc_ani.sc_checkani_timer = timestamp;
+	}
+
+	/* Skip all processing if there's nothing to do. */
+	if (longcal || shortcal || aniflag) {
+		/* Call ANI routine if necessary */
+		if (aniflag)
+			ath9k_hw_ani_monitor(ah, &sc->sc_halstats,
+					     ah->ah_curchan);
+
+		/* Perform calibration if necessary */
+		if (longcal || shortcal) {
+			bool iscaldone = false;
+
+			if (ath9k_hw_calibrate(ah, ah->ah_curchan,
+					       sc->sc_rx_chainmask, longcal,
+					       &iscaldone)) {
+				if (longcal)
+					sc->sc_ani.sc_noise_floor =
+						ath9k_hw_getchan_noise(ah,
+							       ah->ah_curchan);
+
+				DPRINTF(sc, ATH_DBG_ANI,
+					"%s: calibrate chan %u/%x nf: %d\n",
+					 __func__,
+					ah->ah_curchan->channel,
+					ah->ah_curchan->channelFlags,
+					sc->sc_ani.sc_noise_floor);
+			} else {
+				DPRINTF(sc, ATH_DBG_ANY,
+					"%s: calibrate chan %u/%x failed\n",
+					 __func__,
+					ah->ah_curchan->channel,
+					ah->ah_curchan->channelFlags);
+			}
+			sc->sc_ani.sc_caldone = iscaldone;
+		}
+	}
+
+	/*
+	* Set timer interval based on previous results.
+	* The interval must be the shortest necessary to satisfy ANI,
+	* short calibration and long calibration.
+	*/
+
+	cal_interval = ATH_ANI_POLLINTERVAL;
+	if (!sc->sc_ani.sc_caldone)
+		cal_interval = min(cal_interval, (u32)ATH_SHORT_CALINTERVAL);
+
+	mod_timer(&sc->sc_ani.timer, jiffies + msecs_to_jiffies(cal_interval));
+}
+
 /******************/
 /* VAP management */
 /******************/
 
-/*
- *  VAP in Listen mode
- *
- *  This routine brings the VAP out of the down state into a "listen" state
- *  where it waits for association requests.  This is used in AP and AdHoc
- *  modes.
-*/
-
-int ath_vap_listen(struct ath_softc *sc, int if_id)
-{
-	struct ath_hal *ah = sc->sc_ah;
-	struct ath_vap *avp;
-	u32 rfilt = 0;
-	DECLARE_MAC_BUF(mac);
-
-	avp = sc->sc_vaps[if_id];
-	if (avp == NULL) {
-		DPRINTF(sc, ATH_DBG_FATAL, "%s: invalid interface id %u\n",
-			__func__, if_id);
-		return -EINVAL;
-	}
-
-#ifdef CONFIG_SLOW_ANT_DIV
-	ath_slow_ant_div_stop(&sc->sc_antdiv);
-#endif
-
-	/* update ratectrl about the new state */
-	ath_rate_newstate(sc, avp);
-
-	rfilt = ath_calcrxfilter(sc);
-	ath9k_hw_setrxfilter(ah, rfilt);
-
-	if (sc->sc_opmode == ATH9K_M_STA || sc->sc_opmode == ATH9K_M_IBSS) {
-		memcpy(sc->sc_curbssid, ath_bcast_mac, ETH_ALEN);
-		ath9k_hw_write_associd(ah, sc->sc_curbssid, sc->sc_curaid);
-	} else
-		sc->sc_curaid = 0;
-
-	DPRINTF(sc, ATH_DBG_CONFIG,
-		"%s: RX filter 0x%x bssid %s aid 0x%x\n",
-		__func__, rfilt, print_mac(mac,
-			sc->sc_curbssid), sc->sc_curaid);
-
-	/*
-	 * XXXX
-	 * Disable BMISS interrupt when we're not associated
-	 */
-	ath9k_hw_set_interrupts(ah,
-		sc->sc_imask & ~(ATH9K_INT_SWBA | ATH9K_INT_BMISS));
-	sc->sc_imask &= ~(ATH9K_INT_SWBA | ATH9K_INT_BMISS);
-	/* need to reconfigure the beacons when it moves to RUN */
-	sc->sc_beacons = 0;
-
-	return 0;
-}
-
 int ath_vap_attach(struct ath_softc *sc,
 		   int if_id,
 		   struct ieee80211_vif *if_data,
@@ -642,21 +642,19 @@
 	if (avp == NULL)
 		return -ENOMEM;
 
-	memzero(avp, sizeof(struct ath_vap));
+	memset(avp, 0, sizeof(struct ath_vap));
 	avp->av_if_data = if_data;
 	/* Set the VAP opmode */
 	avp->av_opmode = opmode;
 	avp->av_bslot = -1;
-	INIT_LIST_HEAD(&avp->av_mcastq.axq_q);
-	INIT_LIST_HEAD(&avp->av_mcastq.axq_acq);
-	spin_lock_init(&avp->av_mcastq.axq_lock);
 
-	ath9k_hw_set_tsfadjust(sc->sc_ah, 1);
+	if (opmode == ATH9K_M_HOSTAP)
+		ath9k_hw_set_tsfadjust(sc->sc_ah, 1);
 
 	sc->sc_vaps[if_id] = avp;
 	sc->sc_nvaps++;
 	/* Set the device opmode */
-	sc->sc_opmode = opmode;
+	sc->sc_ah->ah_opmode = opmode;
 
 	/* default VAP configuration */
 	avp->av_config.av_fixed_rateset = IEEE80211_FIXED_RATE_NONE;
@@ -689,9 +687,6 @@
 	ath_stoprecv(sc);	/* stop recv side */
 	ath_flushrecv(sc);	/* flush recv queue */
 
-	/* Reclaim any pending mcast bufs on the vap. */
-	ath_tx_draintxq(sc, &avp->av_mcastq, false);
-
 	kfree(avp);
 	sc->sc_vaps[if_id] = NULL;
 	sc->sc_nvaps--;
@@ -728,9 +723,9 @@
 	struct ath_hal *ah = sc->sc_ah;
 	int status;
 	int error = 0;
-	enum ath9k_ht_macmode ht_macmode = ath_cwm_macmode(sc);
 
-	DPRINTF(sc, ATH_DBG_CONFIG, "%s: mode %d\n", __func__, sc->sc_opmode);
+	DPRINTF(sc, ATH_DBG_CONFIG, "%s: mode %d\n",
+		__func__, sc->sc_ah->ah_opmode);
 
 	/*
 	 * Stop anything previously setup.  This is safe
@@ -752,16 +747,16 @@
 	 * be followed by initialization of the appropriate bits
 	 * and then setup of the interrupt mask.
 	 */
-	sc->sc_curchan = *initial_chan;
 
 	spin_lock_bh(&sc->sc_resetlock);
-	if (!ath9k_hw_reset(ah, sc->sc_opmode, &sc->sc_curchan, ht_macmode,
-			   sc->sc_tx_chainmask, sc->sc_rx_chainmask,
-			   sc->sc_ht_extprotspacing, false, &status)) {
+	if (!ath9k_hw_reset(ah, initial_chan,
+			    sc->sc_ht_info.tx_chan_width,
+			    sc->sc_tx_chainmask, sc->sc_rx_chainmask,
+			    sc->sc_ht_extprotspacing, false, &status)) {
 		DPRINTF(sc, ATH_DBG_FATAL,
 			"%s: unable to reset hardware; hal status %u "
 			"(freq %u flags 0x%x)\n", __func__, status,
-			sc->sc_curchan.channel, sc->sc_curchan.channelFlags);
+			initial_chan->channel, initial_chan->channelFlags);
 		error = -EIO;
 		spin_unlock_bh(&sc->sc_resetlock);
 		goto done;
@@ -802,7 +797,8 @@
 	 * Note we only do this (at the moment) for station mode.
 	 */
 	if (ath9k_hw_phycounters(ah) &&
-	    ((sc->sc_opmode == ATH9K_M_STA) || (sc->sc_opmode == ATH9K_M_IBSS)))
+	    ((sc->sc_ah->ah_opmode == ATH9K_M_STA) ||
+	     (sc->sc_ah->ah_opmode == ATH9K_M_IBSS)))
 		sc->sc_imask |= ATH9K_INT_MIB;
 	/*
 	 * Some hardware processes the TIM IE and fires an
@@ -811,7 +807,7 @@
 	 * enable the TIM interrupt when operating as station.
 	 */
 	if ((ah->ah_caps.hw_caps & ATH9K_HW_CAP_ENHANCEDPM) &&
-	    (sc->sc_opmode == ATH9K_M_STA) &&
+	    (sc->sc_ah->ah_opmode == ATH9K_M_STA) &&
 	    !sc->sc_config.swBeaconProcess)
 		sc->sc_imask |= ATH9K_INT_TIM;
 	/*
@@ -823,34 +819,34 @@
 
 	/* XXX: we must make sure h/w is ready and clear invalid flag
 	 * before turning on interrupt. */
-	sc->sc_invalid = 0;
+	sc->sc_flags &= ~SC_OP_INVALID;
 done:
 	return error;
 }
 
-/*
- * Reset the hardware w/o losing operational state.  This is
- * basically a more efficient way of doing ath_stop, ath_init,
- * followed by state transitions to the current 802.11
- * operational state.  Used to recover from errors rx overrun
- * and to reset the hardware when rf gain settings must be reset.
- */
-
-static int ath_reset_start(struct ath_softc *sc, u32 flag)
+int ath_reset(struct ath_softc *sc, bool retry_tx)
 {
 	struct ath_hal *ah = sc->sc_ah;
+	int status;
+	int error = 0;
 
 	ath9k_hw_set_interrupts(ah, 0);	/* disable interrupts */
-	ath_draintxq(sc, flag & RESET_RETRY_TXQ);	/* stop xmit side */
-	ath_stoprecv(sc);	/* stop recv side */
-	ath_flushrecv(sc);	/* flush recv queue */
+	ath_draintxq(sc, retry_tx);	/* stop xmit */
+	ath_stoprecv(sc);		/* stop recv */
+	ath_flushrecv(sc);		/* flush recv queue */
 
-	return 0;
-}
-
-static int ath_reset_end(struct ath_softc *sc, u32 flag)
-{
-	struct ath_hal *ah = sc->sc_ah;
+	/* Reset chip */
+	spin_lock_bh(&sc->sc_resetlock);
+	if (!ath9k_hw_reset(ah, sc->sc_ah->ah_curchan,
+			    sc->sc_ht_info.tx_chan_width,
+			    sc->sc_tx_chainmask, sc->sc_rx_chainmask,
+			    sc->sc_ht_extprotspacing, false, &status)) {
+		DPRINTF(sc, ATH_DBG_FATAL,
+			"%s: unable to reset hardware; hal status %u\n",
+			__func__, status);
+		error = -EIO;
+	}
+	spin_unlock_bh(&sc->sc_resetlock);
 
 	if (ath_startrecv(sc) != 0)	/* restart recv */
 		DPRINTF(sc, ATH_DBG_FATAL,
@@ -861,16 +857,17 @@
 	 * that changes the channel so update any state that
 	 * might change as a result.
 	 */
-	ath_setcurmode(sc, ath_chan2mode(&sc->sc_curchan));
+	ath_setcurmode(sc, ath_chan2mode(sc->sc_ah->ah_curchan));
 
-	ath_update_txpow(sc);	/* update tx power state */
+	ath_update_txpow(sc);
 
-	if (sc->sc_beacons)
+	if (sc->sc_flags & SC_OP_BEACONS)
 		ath_beacon_config(sc, ATH_IF_ID_ANY);	/* restart beacons */
+
 	ath9k_hw_set_interrupts(ah, sc->sc_imask);
 
 	/* Restart the txq */
-	if (flag & RESET_RETRY_TXQ) {
+	if (retry_tx) {
 		int i;
 		for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
 			if (ATH_TXQ_SETUP(sc, i)) {
@@ -880,28 +877,6 @@
 			}
 		}
 	}
-	return 0;
-}
-
-int ath_reset(struct ath_softc *sc)
-{
-	struct ath_hal *ah = sc->sc_ah;
-	int status;
-	int error = 0;
-	enum ath9k_ht_macmode ht_macmode = ath_cwm_macmode(sc);
-
-	/* NB: indicate channel change so we do a full reset */
-	spin_lock_bh(&sc->sc_resetlock);
-	if (!ath9k_hw_reset(ah, sc->sc_opmode, &sc->sc_curchan,
-			   ht_macmode,
-			   sc->sc_tx_chainmask, sc->sc_rx_chainmask,
-			   sc->sc_ht_extprotspacing, false, &status)) {
-		DPRINTF(sc, ATH_DBG_FATAL,
-			"%s: unable to reset hardware; hal status %u\n",
-			__func__, status);
-		error = -EIO;
-	}
-	spin_unlock_bh(&sc->sc_resetlock);
 
 	return error;
 }
@@ -911,7 +886,7 @@
 	struct ath_hal *ah = sc->sc_ah;
 
 	/* No I/O if device has been surprise removed */
-	if (sc->sc_invalid)
+	if (sc->sc_flags & SC_OP_INVALID)
 		return -EIO;
 
 	/* Shut off the interrupt before setting sc->sc_invalid to '1' */
@@ -919,7 +894,7 @@
 
 	/* XXX: we must make sure h/w will not generate any interrupt
 	 * before setting the invalid flag. */
-	sc->sc_invalid = 1;
+	sc->sc_flags |= SC_OP_INVALID;
 
 	/* disable HAL and put h/w to sleep */
 	ath9k_hw_disable(sc->sc_ah);
@@ -940,7 +915,7 @@
 	bool sched = false;
 
 	do {
-		if (sc->sc_invalid) {
+		if (sc->sc_flags & SC_OP_INVALID) {
 			/*
 			 * The hardware is not ready/present, don't
 			 * touch anything. Note this can happen early
@@ -1050,7 +1025,7 @@
 
 	if (status & ATH9K_INT_FATAL) {
 		/* need a chip reset */
-		ath_internal_reset(sc);
+		ath_reset(sc, false);
 		return;
 	} else {
 
@@ -1093,10 +1068,9 @@
 	int status;
 	int error = 0, i;
 	int csz = 0;
-	u32 rd;
 
 	/* XXX: hardware will not be ready until ath_open() being called */
-	sc->sc_invalid = 1;
+	sc->sc_flags |= SC_OP_INVALID;
 
 	sc->sc_debug = DBG_DEFAULT;
 	DPRINTF(sc, ATH_DBG_CONFIG, "%s: devid 0x%x\n", __func__, devid);
@@ -1126,8 +1100,9 @@
 	}
 	sc->sc_ah = ah;
 
-	/* Get the chipset-specific aggr limit. */
-	sc->sc_rtsaggrlimit = ah->ah_caps.rts_aggr_limit;
+	/* Initializes the noise floor to a reasonable default value.
+	 * Later on this will be updated during ANI processing. */
+	sc->sc_ani.sc_noise_floor = ATH_DEFAULT_NOISE_FLOOR;
 
 	/* Get the hardware key cache size. */
 	sc->sc_keymax = ah->ah_caps.keycache_size;
@@ -1162,14 +1137,12 @@
 	 * is resposible for filtering this list based on settings
 	 * like the phy mode.
 	 */
-	rd = ah->ah_currentRD;
-
 	error = ath_setup_channels(sc);
 	if (error)
 		goto bad;
 
 	/* default to STA mode */
-	sc->sc_opmode = ATH9K_M_MONITOR;
+	sc->sc_ah->ah_opmode = ATH9K_M_MONITOR;
 
 	/* Setup rate tables */
 
@@ -1238,9 +1211,11 @@
 		goto bad2;
 	}
 
+	setup_timer(&sc->sc_ani.timer, ath_ani_calibrate, (unsigned long)sc);
+
 	sc->sc_rc = ath_rate_attach(ah);
 	if (sc->sc_rc == NULL) {
-		error = EIO;
+		error = -EIO;
 		goto bad2;
 	}
 
@@ -1280,20 +1255,13 @@
 
 	/* 11n Capabilities */
 	if (ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT) {
-		sc->sc_txaggr = 1;
-		sc->sc_rxaggr = 1;
+		sc->sc_flags |= SC_OP_TXAGGR;
+		sc->sc_flags |= SC_OP_RXAGGR;
 	}
 
 	sc->sc_tx_chainmask = ah->ah_caps.tx_chainmask;
 	sc->sc_rx_chainmask = ah->ah_caps.rx_chainmask;
 
-	/* Configuration for rx chain detection */
-	sc->sc_rxchaindetect_ref = 0;
-	sc->sc_rxchaindetect_thresh5GHz = 35;
-	sc->sc_rxchaindetect_thresh2GHz = 35;
-	sc->sc_rxchaindetect_delta5GHz = 30;
-	sc->sc_rxchaindetect_delta2GHz = 30;
-
 	ath9k_hw_setcapability(ah, ATH9K_CAP_DIVERSITY, 1, true, NULL);
 	sc->sc_defant = ath9k_hw_getdefantenna(ah);
 
@@ -1336,8 +1304,10 @@
 
 	DPRINTF(sc, ATH_DBG_CONFIG, "%s\n", __func__);
 
+	tasklet_kill(&sc->intr_tq);
+	tasklet_kill(&sc->bcon_tasklet);
 	ath_stop(sc);
-	if (!sc->sc_invalid)
+	if (!(sc->sc_flags & SC_OP_INVALID))
 		ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_AWAKE);
 	ath_rate_detach(sc->sc_rc);
 	/* cleanup tx queues */
@@ -1364,7 +1334,7 @@
 	an = kmalloc(sizeof(struct ath_node), GFP_ATOMIC);
 	if (an == NULL)
 		return NULL;
-	memzero(an, sizeof(*an));
+	memset(an, 0, sizeof(*an));
 
 	an->an_sc = sc;
 	memcpy(an->an_addr, addr, ETH_ALEN);
@@ -1464,9 +1434,9 @@
 	/* if station reassociates, tear down the aggregation state. */
 	if (!isnew) {
 		for (tidno = 0; tidno < WME_NUM_TID; tidno++) {
-			if (sc->sc_txaggr)
+			if (sc->sc_flags & SC_OP_TXAGGR)
 				ath_tx_aggr_teardown(sc, an, tidno);
-			if (sc->sc_rxaggr)
+			if (sc->sc_flags & SC_OP_RXAGGR)
 				ath_rx_aggr_teardown(sc, an, tidno);
 		}
 	}
@@ -1751,7 +1721,7 @@
 		error = -ENOMEM;
 		goto fail2;
 	}
-	memzero(bf, bsize);
+	memset(bf, 0, bsize);
 	dd->dd_bufptr = bf;
 
 	INIT_LIST_HEAD(head);
@@ -1783,7 +1753,7 @@
 	pci_free_consistent(sc->pdev,
 		dd->dd_desc_len, dd->dd_desc, dd->dd_desc_paddr);
 fail:
-	memzero(dd, sizeof(*dd));
+	memset(dd, 0, sizeof(*dd));
 	return error;
 #undef ATH_DESC_4KB_BOUND_CHECK
 #undef ATH_DESC_4KB_BOUND_NUM_SKIPPED
@@ -1808,20 +1778,13 @@
 
 	INIT_LIST_HEAD(head);
 	kfree(dd->dd_bufptr);
-	memzero(dd, sizeof(*dd));
+	memset(dd, 0, sizeof(*dd));
 }
 
 /*************/
 /* Utilities */
 /*************/
 
-void ath_internal_reset(struct ath_softc *sc)
-{
-	ath_reset_start(sc, 0);
-	ath_reset(sc);
-	ath_reset_end(sc, 0);
-}
-
 int ath_get_hal_qnum(u16 queue, struct ath_softc *sc)
 {
 	int qnum;
diff --git a/drivers/net/wireless/ath9k/core.h b/drivers/net/wireless/ath9k/core.h
index 4ee695b..cb3e61e 100644
--- a/drivers/net/wireless/ath9k/core.h
+++ b/drivers/net/wireless/ath9k/core.h
@@ -39,6 +39,8 @@
 #include <linux/scatterlist.h>
 #include <asm/page.h>
 #include <net/mac80211.h>
+#include <linux/leds.h>
+#include <linux/rfkill.h>
 
 #include "ath9k.h"
 #include "rc.h"
@@ -79,11 +81,8 @@
 		}				\
 	} while (0)
 
-/* XXX: remove */
-#define memzero(_buf, _len) memset(_buf, 0, _len)
-
-#define get_dma_mem_context(var, field) (&((var)->field))
-#define copy_dma_mem_context(dst, src)  (*dst = *src)
+#define TSF_TO_TU(_h,_l) \
+	((((u32)(_h)) << 22) | (((u32)(_l)) >> 10))
 
 #define ATH9K_BH_STATUS_INTACT		0
 #define ATH9K_BH_STATUS_CHANGE		1
@@ -95,6 +94,8 @@
 	return ((jiffies / HZ) * 1000) + (jiffies % HZ) * (1000 / HZ);
 }
 
+static const u8 ath_bcast_mac[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+
 /*************/
 /* Debugging */
 /*************/
@@ -175,42 +176,38 @@
 /* Descriptor Management */
 /*************************/
 
-/* Number of descriptors per buffer. The only case where we see skbuff
-chains is due to FF aggregation in the driver. */
-#define	ATH_TXDESC	    1
-/* if there's more fragment for this MSDU */
-#define ATH_BF_MORE_MPDU    1
 #define ATH_TXBUF_RESET(_bf) do {				\
 		(_bf)->bf_status = 0;				\
 		(_bf)->bf_lastbf = NULL;			\
 		(_bf)->bf_lastfrm = NULL;			\
 		(_bf)->bf_next = NULL;				\
-		memzero(&((_bf)->bf_state),			\
+		memset(&((_bf)->bf_state), 0,			\
 			    sizeof(struct ath_buf_state));	\
 	} while (0)
 
+enum buffer_type {
+	BUF_DATA		= BIT(0),
+	BUF_AGGR		= BIT(1),
+	BUF_AMPDU		= BIT(2),
+	BUF_HT			= BIT(3),
+	BUF_RETRY		= BIT(4),
+	BUF_XRETRY		= BIT(5),
+	BUF_SHORT_PREAMBLE	= BIT(6),
+	BUF_BAR			= BIT(7),
+	BUF_PSPOLL		= BIT(8),
+	BUF_AGGR_BURST		= BIT(9),
+	BUF_CALC_AIRTIME	= BIT(10),
+};
+
 struct ath_buf_state {
-	int bfs_nframes;	/* # frames in aggregate */
-	u16 bfs_al;		/* length of aggregate */
-	u16 bfs_frmlen;		/* length of frame */
-	int bfs_seqno;		/* sequence number */
-	int bfs_tidno;		/* tid of this frame */
-	int bfs_retries;	/* current retries */
+	int bfs_nframes;			/* # frames in aggregate */
+	u16 bfs_al;				/* length of aggregate */
+	u16 bfs_frmlen;				/* length of frame */
+	int bfs_seqno;				/* sequence number */
+	int bfs_tidno;				/* tid of this frame */
+	int bfs_retries;			/* current retries */
 	struct ath_rc_series bfs_rcs[4];	/* rate series */
-	u8 bfs_isdata:1;	/* is a data frame/aggregate */
-	u8 bfs_isaggr:1;	/* is an aggregate */
-	u8 bfs_isampdu:1;	/* is an a-mpdu, aggregate or not */
-	u8 bfs_ht:1;		/* is an HT frame */
-	u8 bfs_isretried:1;	/* is retried */
-	u8 bfs_isxretried:1;	/* is excessive retried */
-	u8 bfs_shpreamble:1;	/* is short preamble */
-	u8 bfs_isbar:1;		/* is a BAR */
-	u8 bfs_ispspoll:1;	/* is a PS-Poll */
-	u8 bfs_aggrburst:1;	/* is a aggr burst */
-	u8 bfs_calcairtime:1;	/* requests airtime be calculated
-				when set for tx frame */
-	int bfs_rifsburst_elem;	/* RIFS burst/bar */
-	int bfs_nrifsubframes;	/* # of elements in burst */
+	u32 bf_type;				/* BUF_* (enum buffer_type) */
 	/* key type use to encrypt this frame */
 	enum ath9k_key_type bfs_keytype;
 };
@@ -222,26 +219,22 @@
 #define bf_seqno        	bf_state.bfs_seqno
 #define bf_tidno        	bf_state.bfs_tidno
 #define bf_rcs          	bf_state.bfs_rcs
-#define bf_isdata       	bf_state.bfs_isdata
-#define bf_isaggr       	bf_state.bfs_isaggr
-#define bf_isampdu      	bf_state.bfs_isampdu
-#define bf_ht           	bf_state.bfs_ht
-#define bf_isretried    	bf_state.bfs_isretried
-#define bf_isxretried   	bf_state.bfs_isxretried
-#define bf_shpreamble   	bf_state.bfs_shpreamble
-#define bf_rifsburst_elem  	bf_state.bfs_rifsburst_elem
-#define bf_nrifsubframes  	bf_state.bfs_nrifsubframes
 #define bf_keytype      	bf_state.bfs_keytype
-#define bf_isbar        	bf_state.bfs_isbar
-#define bf_ispspoll     	bf_state.bfs_ispspoll
-#define bf_aggrburst    	bf_state.bfs_aggrburst
-#define bf_calcairtime  	bf_state.bfs_calcairtime
+#define bf_isdata(bf)		(bf->bf_state.bf_type & BUF_DATA)
+#define bf_isaggr(bf)		(bf->bf_state.bf_type & BUF_AGGR)
+#define bf_isampdu(bf)		(bf->bf_state.bf_type & BUF_AMPDU)
+#define bf_isht(bf)		(bf->bf_state.bf_type & BUF_HT)
+#define bf_isretried(bf)	(bf->bf_state.bf_type & BUF_RETRY)
+#define bf_isxretried(bf)	(bf->bf_state.bf_type & BUF_XRETRY)
+#define bf_isshpreamble(bf)	(bf->bf_state.bf_type & BUF_SHORT_PREAMBLE)
+#define bf_isbar(bf)		(bf->bf_state.bf_type & BUF_BAR)
+#define bf_ispspoll(bf) 	(bf->bf_state.bf_type & BUF_PSPOLL)
+#define bf_isaggrburst(bf)	(bf->bf_state.bf_type & BUF_AGGR_BURST)
 
 /*
  * Abstraction of a contiguous buffer to transmit/receive.  There is only
  * a single hw descriptor encapsulated here.
  */
-
 struct ath_buf {
 	struct list_head list;
 	struct list_head *last;
@@ -316,7 +309,7 @@
 #define ATH_RX_TIMEOUT           40      /* 40 milliseconds */
 #define WME_NUM_TID              16
 #define IEEE80211_BAR_CTL_TID_M  0xF000  /* tid mask */
-#define IEEE80211_BAR_CTL_TID_S  2       /* tid shift */
+#define IEEE80211_BAR_CTL_TID_S  12      /* tid shift */
 
 enum ATH_RX_TYPE {
 	ATH_RX_NON_CONSUMED = 0,
@@ -391,10 +384,10 @@
 		 struct sk_buff *skb,
 		 struct ath_recv_status *rx_status,
 		 enum ATH_RX_TYPE *status);
-int ath__rx_indicate(struct ath_softc *sc,
-		    struct sk_buff *skb,
-		    struct ath_recv_status *status,
-		    u16 keyix);
+int _ath_rx_indicate(struct ath_softc *sc,
+		     struct sk_buff *skb,
+		     struct ath_recv_status *status,
+		     u16 keyix);
 int ath_rx_subframe(struct ath_node *an, struct sk_buff *skb,
 		    struct ath_recv_status *status);
 
@@ -402,8 +395,7 @@
 /* TX */
 /******/
 
-#define ATH_FRAG_PER_MSDU       1
-#define ATH_TXBUF               (512/ATH_FRAG_PER_MSDU)
+#define ATH_TXBUF               512
 /* max number of transmit attempts (tries) */
 #define ATH_TXMAXTRY            13
 /* max number of 11n transmit attempts (tries) */
@@ -522,7 +514,6 @@
 	u32 keyix;
 	int min_rate;
 	int mcast_rate;
-	u16 nextfraglen;
 	struct ath_softc *dev;
 	dma_addr_t dmacontext;
 };
@@ -557,10 +548,10 @@
 int ath_tx_setup(struct ath_softc *sc, int haltype);
 void ath_draintxq(struct ath_softc *sc, bool retry_tx);
 void ath_tx_draintxq(struct ath_softc *sc,
-	struct ath_txq *txq, bool retry_tx);
+		     struct ath_txq *txq, bool retry_tx);
 void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an);
 void ath_tx_node_cleanup(struct ath_softc *sc,
-	struct ath_node *an, bool bh_flag);
+			 struct ath_node *an, bool bh_flag);
 void ath_tx_node_free(struct ath_softc *sc, struct ath_node *an);
 void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq);
 int ath_tx_init(struct ath_softc *sc, int nbufs);
@@ -575,6 +566,7 @@
 void ath_notify_txq_status(struct ath_softc *sc, u16 queue_depth);
 void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
 		     struct ath_xmit_status *tx_status, struct ath_node *an);
+void ath_tx_cabq(struct ath_softc *sc, struct sk_buff *skb);
 
 /**********************/
 /* Node / Aggregation */
@@ -585,7 +577,6 @@
 /* indicates the node is 80211 power save */
 #define ATH_NODE_PWRSAVE        0x2
 
-#define ADDBA_TIMEOUT              200 /* 200 milliseconds */
 #define ADDBA_EXCHANGE_ATTEMPTS    10
 #define ATH_AGGR_DELIM_SZ          4   /* delimiter size   */
 #define ATH_AGGR_MINPLEN           256 /* in bytes, minimum packet length */
@@ -705,9 +696,6 @@
 #define	ATH_BCBUF               	4   /* number of beacon buffers */
 #define ATH_DEFAULT_BINTVAL     	100 /* default beacon interval in TU */
 #define ATH_DEFAULT_BMISS_LIMIT 	10
-#define	ATH_BEACON_AIFS_DEFAULT		0  /* Default aifs for ap beacon q */
-#define	ATH_BEACON_CWMIN_DEFAULT	0  /* Default cwmin for ap beacon q */
-#define	ATH_BEACON_CWMAX_DEFAULT	0  /* Default cwmax for ap beacon q */
 #define IEEE80211_MS_TO_TU(x)           (((x) * 1000) / 1024)
 
 /* beacon configuration */
@@ -724,30 +712,16 @@
 	} u; /* last received beacon/probe response timestamp of this BSS. */
 };
 
-/* offsets in a beacon frame for
- * quick acess of beacon content by low-level driver */
-struct ath_beacon_offset {
-	u8 *bo_tim;	/* start of atim/dtim */
-};
-
 void ath9k_beacon_tasklet(unsigned long data);
 void ath_beacon_config(struct ath_softc *sc, int if_id);
 int ath_beaconq_setup(struct ath_hal *ah);
 int ath_beacon_alloc(struct ath_softc *sc, int if_id);
 void ath_bstuck_process(struct ath_softc *sc);
-void ath_beacon_tasklet(struct ath_softc *sc, int *needmark);
-void ath_beacon_free(struct ath_softc *sc);
 void ath_beacon_return(struct ath_softc *sc, struct ath_vap *avp);
 void ath_beacon_sync(struct ath_softc *sc, int if_id);
-void ath_update_beacon_info(struct ath_softc *sc, int avgbrssi);
 void ath_get_beaconconfig(struct ath_softc *sc,
 			  int if_id,
 			  struct ath_beacon_config *conf);
-int ath_update_beacon(struct ath_softc *sc,
-		      int if_id,
-		      struct ath_beacon_offset *bo,
-		      struct sk_buff *skb,
-		      int mcast);
 /********/
 /* VAPs */
 /********/
@@ -774,10 +748,8 @@
 	struct ieee80211_vif *av_if_data;
 	enum ath9k_opmode av_opmode;	/* VAP operational mode */
 	struct ath_buf *av_bcbuf;	/* beacon buffer */
-	struct ath_beacon_offset av_boff; /* dynamic update state */
 	struct ath_tx_control av_btxctl;  /* txctl information for beacon */
 	int av_bslot;			/* beacon slot index */
-	struct ath_txq av_mcastq;	/* multicast transmit queue */
 	struct ath_vap_config av_config;/* vap configuration parameters*/
 	struct ath_rate_node *rc_node;
 };
@@ -788,8 +760,7 @@
 		   enum ath9k_opmode opmode);
 int ath_vap_detach(struct ath_softc *sc, int if_id);
 int ath_vap_config(struct ath_softc *sc,
-	int if_id, struct ath_vap_config *if_config);
-int ath_vap_listen(struct ath_softc *sc, int if_id);
+		   int if_id, struct ath_vap_config *if_config);
 
 /*********************/
 /* Antenna diversity */
@@ -829,6 +800,58 @@
 		      struct ath_rx_status *rx_stats);
 void ath_setdefantenna(void *sc, u32 antenna);
 
+/*******/
+/* ANI */
+/*******/
+
+/* ANI values for STA only.
+   FIXME: Add appropriate values for AP later */
+
+#define ATH_ANI_POLLINTERVAL    100     /* 100 milliseconds between ANI poll */
+#define ATH_SHORT_CALINTERVAL   1000    /* 1 second between calibrations */
+#define ATH_LONG_CALINTERVAL    30000   /* 30 seconds between calibrations */
+#define ATH_RESTART_CALINTERVAL 1200000 /* 20 minutes between calibrations */
+
+struct ath_ani {
+	bool sc_caldone;
+	int16_t sc_noise_floor;
+	unsigned int sc_longcal_timer;
+	unsigned int sc_shortcal_timer;
+	unsigned int sc_resetcal_timer;
+	unsigned int sc_checkani_timer;
+	struct timer_list timer;
+};
+
+/********************/
+/*   LED Control    */
+/********************/
+
+#define ATH_LED_PIN	1
+
+enum ath_led_type {
+	ATH_LED_RADIO,
+	ATH_LED_ASSOC,
+	ATH_LED_TX,
+	ATH_LED_RX
+};
+
+struct ath_led {
+	struct ath_softc *sc;
+	struct led_classdev led_cdev;
+	enum ath_led_type led_type;
+	char name[32];
+	bool registered;
+};
+
+/* Rfkill */
+#define ATH_RFKILL_POLL_INTERVAL	2000 /* msecs */
+
+struct ath_rfkill {
+	struct rfkill *rfkill;
+	struct delayed_work rfkill_poll;
+	char rfkill_name[32];
+};
+
 /********************/
 /* Main driver core */
 /********************/
@@ -841,11 +864,7 @@
 #define	ATH_DEFAULT_NOISE_FLOOR -95
 #define ATH_REGCLASSIDS_MAX     10
 #define ATH_CABQ_READY_TIME     80  /* % of beacon interval */
-#define ATH_PREAMBLE_SHORT	(1<<0)
-#define ATH_PROTECT_ENABLE	(1<<1)
 #define ATH_MAX_SW_RETRIES      10
-/* Num farmes difference in tx to flip default recv */
-#define	ATH_ANTENNA_DIFF	2
 #define ATH_CHAN_MAX            255
 #define IEEE80211_WEP_NKID      4       /* number of key ids */
 #define IEEE80211_RATE_VAL      0x7f
@@ -859,9 +878,7 @@
  */
 #define	ATH_KEYMAX	        128        /* max key cache size we handle */
 
-#define RESET_RETRY_TXQ         0x00000001
 #define ATH_IF_ID_ANY   	0xff
-
 #define ATH_TXPOWER_MAX         100     /* .5 dBm units */
 
 #define RSSI_LPF_THRESHOLD         -20
@@ -907,60 +924,64 @@
 	u8 ext_chan_offset;
 };
 
+#define SC_OP_INVALID		BIT(0)
+#define SC_OP_BEACONS		BIT(1)
+#define SC_OP_RXAGGR		BIT(2)
+#define SC_OP_TXAGGR		BIT(3)
+#define SC_OP_CHAINMASK_UPDATE	BIT(4)
+#define SC_OP_FULL_RESET	BIT(5)
+#define SC_OP_NO_RESET		BIT(6)
+#define SC_OP_PREAMBLE_SHORT	BIT(7)
+#define SC_OP_PROTECT_ENABLE	BIT(8)
+#define SC_OP_RXFLUSH		BIT(9)
+#define SC_OP_LED_ASSOCIATED	BIT(10)
+#define SC_OP_RFKILL_REGISTERED	BIT(11)
+#define SC_OP_RFKILL_SW_BLOCKED	BIT(12)
+#define SC_OP_RFKILL_HW_BLOCKED	BIT(13)
+
 struct ath_softc {
 	struct ieee80211_hw *hw;
 	struct pci_dev *pdev;
-	void __iomem *mem;
 	struct tasklet_struct intr_tq;
 	struct tasklet_struct bcon_tasklet;
-	struct ath_config sc_config;	/* load-time parameters */
-	int sc_debug;
+	struct ath_config sc_config;
 	struct ath_hal *sc_ah;
-	struct ath_rate_softc *sc_rc;	/* tx rate control support */
-	u32 sc_intrstatus;
-	enum ath9k_opmode sc_opmode;	/* current operating mode */
+	struct ath_rate_softc *sc_rc;
+	void __iomem *mem;
 
-	u8 sc_invalid;			/* being detached */
-	u8 sc_beacons;			/* beacons running */
-	u8 sc_scanning;			/* scanning active */
-	u8 sc_txaggr;			/* enable 11n tx aggregation */
-	u8 sc_rxaggr;			/* enable 11n rx aggregation */
-	u8 sc_update_chainmask;		/* change chain mask */
-	u8 sc_full_reset;		/* force full reset */
-	enum wireless_mode sc_curmode;	/* current phy mode */
-	u16 sc_curtxpow;
-	u16 sc_curaid;
 	u8 sc_curbssid[ETH_ALEN];
 	u8 sc_myaddr[ETH_ALEN];
-	enum PROT_MODE sc_protmode;
-	u8 sc_mcastantenna;
-	u8 sc_txantenna;		/* data tx antenna (fixed or auto) */
-	u8 sc_nbcnvaps;			/* # of vaps sending beacons */
-	u16 sc_nvaps;			/* # of active virtual ap's */
-	struct ath_vap *sc_vaps[ATH_BCBUF];
-	enum ath9k_int sc_imask;
 	u8 sc_bssidmask[ETH_ALEN];
-	u8 sc_defant;			/* current default antenna */
-	u8 sc_rxotherant;		/* rx's on non-default antenna */
+
+	int sc_debug;
+	u32 sc_intrstatus;
+	u32 sc_flags; /* SC_OP_* */
+	unsigned int rx_filter;
+	u16 sc_curtxpow;
+	u16 sc_curaid;
 	u16 sc_cachelsz;
 	int sc_slotupdate;		/* slot to next advance fsm */
 	int sc_slottime;
-	u8 sc_noreset;
 	int sc_bslot[ATH_BCBUF];
+	u8 sc_tx_chainmask;
+	u8 sc_rx_chainmask;
+	enum ath9k_int sc_imask;
+	enum wireless_mode sc_curmode;	/* current phy mode */
+	enum PROT_MODE sc_protmode;
+
+	u8 sc_nbcnvaps;			/* # of vaps sending beacons */
+	u16 sc_nvaps;			/* # of active virtual ap's */
+	struct ath_vap *sc_vaps[ATH_BCBUF];
+
+	u8 sc_mcastantenna;
+	u8 sc_defant;			/* current default antenna */
+	u8 sc_rxotherant;		/* rx's on non-default antenna */
+
 	struct ath9k_node_stats sc_halstats; /* station-mode rssi stats */
 	struct list_head node_list;
 	struct ath_ht_info sc_ht_info;
-	int16_t sc_noise_floor;		/* signal noise floor in dBm */
 	enum ath9k_ht_extprotspacing sc_ht_extprotspacing;
-	u8 sc_tx_chainmask;
-	u8 sc_rx_chainmask;
-	u8 sc_rxchaindetect_ref;
-	u8 sc_rxchaindetect_thresh5GHz;
-	u8 sc_rxchaindetect_thresh2GHz;
-	u8 sc_rxchaindetect_delta5GHz;
-	u8 sc_rxchaindetect_delta2GHz;
-	u32 sc_rtsaggrlimit;		/* Chipset specific aggr limit */
-	u32 sc_flags;
+
 #ifdef CONFIG_SLOW_ANT_DIV
 	struct ath_antdiv sc_antdiv;
 #endif
@@ -974,15 +995,12 @@
 	u32 sc_keymax;		/* size of key cache */
 	DECLARE_BITMAP(sc_keymap, ATH_KEYMAX);	/* key use bit map */
 	u8 sc_splitmic;		/* split TKIP MIC keys */
-	int sc_keytype;
 
 	/* RX */
 	struct list_head sc_rxbuf;
 	struct ath_descdma sc_rxdma;
 	int sc_rxbufsize;	/* rx size based on mtu */
 	u32 *sc_rxlink;		/* link ptr in last RX desc */
-	u32 sc_rxflush;		/* rx flush in progress */
-	u64 sc_lastrx;		/* tsf of last rx'd frame */
 
 	/* TX */
 	struct list_head sc_txbuf;
@@ -991,7 +1009,6 @@
 	u32 sc_txqsetup;
 	u32 sc_txintrperiod;	/* tx interrupt batching */
 	int sc_haltype2q[ATH9K_WME_AC_VO+1]; /* HAL WME	AC -> h/w qnum */
-	u32 sc_ant_tx[8];	/* recent tx frames/antenna */
 	u16 seq_no; /* TX sequence number */
 
 	/* Beacon */
@@ -1002,6 +1019,7 @@
 	u32 sc_bhalq;
 	u32 sc_bmisscount;
 	u32 ast_be_xmit;	/* beacons transmitted */
+	u64 bc_tstamp;
 
 	/* Rate */
 	struct ieee80211_rate rates[IEEE80211_NUM_BANDS][ATH_RATE_MAX];
@@ -1016,7 +1034,6 @@
 	/* Channel, Band */
 	struct ieee80211_channel channels[IEEE80211_NUM_BANDS][ATH_CHAN_MAX];
 	struct ieee80211_supported_band sbands[IEEE80211_NUM_BANDS];
-	struct ath9k_channel sc_curchan;
 
 	/* Locks */
 	spinlock_t sc_rxflushlock;
@@ -1024,6 +1041,18 @@
 	spinlock_t sc_txbuflock;
 	spinlock_t sc_resetlock;
 	spinlock_t node_lock;
+
+	/* LEDs */
+	struct ath_led radio_led;
+	struct ath_led assoc_led;
+	struct ath_led tx_led;
+	struct ath_led rx_led;
+
+	/* Rfkill */
+	struct ath_rfkill rf_kill;
+
+	/* ANI */
+	struct ath_ani sc_ani;
 };
 
 int ath_init(u16 devid, struct ath_softc *sc);
@@ -1031,14 +1060,8 @@
 int ath_open(struct ath_softc *sc, struct ath9k_channel *initial_chan);
 int ath_suspend(struct ath_softc *sc);
 irqreturn_t ath_isr(int irq, void *dev);
-int ath_reset(struct ath_softc *sc);
-void ath_scan_start(struct ath_softc *sc);
-void ath_scan_end(struct ath_softc *sc);
+int ath_reset(struct ath_softc *sc, bool retry_tx);
 int ath_set_channel(struct ath_softc *sc, struct ath9k_channel *hchan);
-void ath_setup_rate(struct ath_softc *sc,
-		    enum wireless_mode wMode,
-		    enum RATE_TYPE type,
-		    const struct ath9k_rate_table *rt);
 
 /*********************/
 /* Utility Functions */
@@ -1057,17 +1080,5 @@
 void ath_get_currentCountry(struct ath_softc *sc,
 	struct ath9k_country_entry *ctry);
 u64 ath_extend_tsf(struct ath_softc *sc, u32 rstamp);
-void ath_internal_reset(struct ath_softc *sc);
-u32 ath_chan2flags(struct ieee80211_channel *chan, struct ath_softc *sc);
-dma_addr_t ath_skb_map_single(struct ath_softc *sc,
-			      struct sk_buff *skb,
-			      int direction,
-			      dma_addr_t *pa);
-void ath_skb_unmap_single(struct ath_softc *sc,
-			  struct sk_buff *skb,
-			  int direction,
-			  dma_addr_t *pa);
-void ath_mcast_merge(struct ath_softc *sc, u32 mfilt[2]);
-enum ath9k_ht_macmode ath_cwm_macmode(struct ath_softc *sc);
 
 #endif /* CORE_H */
diff --git a/drivers/net/wireless/ath9k/hw.c b/drivers/net/wireless/ath9k/hw.c
index 6dbfed0..98bc25c 100644
--- a/drivers/net/wireless/ath9k/hw.c
+++ b/drivers/net/wireless/ath9k/hw.c
@@ -85,29 +85,6 @@
 	ath9k_hw_adc_dccal_calibrate
 };
 
-static const struct ath_hal ar5416hal = {
-	AR5416_MAGIC,
-	0,
-	0,
-	NULL,
-	NULL,
-	CTRY_DEFAULT,
-	0,
-	0,
-	0,
-	0,
-	0,
-	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-	 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-	 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-	 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-	 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-	 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-	 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-	 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-	},
-};
-
 static struct ath9k_rate_table ar5416_11a_table = {
 	8,
 	{0},
@@ -352,7 +329,7 @@
 	ah->ah_config.ofdm_trig_high = 500;
 	ah->ah_config.cck_trig_high = 200;
 	ah->ah_config.cck_trig_low = 100;
-	ah->ah_config.enable_ani = 0;
+	ah->ah_config.enable_ani = 1;
 	ah->ah_config.noise_immunity_level = 4;
 	ah->ah_config.ofdm_weaksignal_det = 1;
 	ah->ah_config.cck_weaksignal_thr = 0;
@@ -371,7 +348,7 @@
 	ah->ah_config.intr_mitigation = 0;
 }
 
-static inline void ath9k_hw_override_ini(struct ath_hal *ah,
+static void ath9k_hw_override_ini(struct ath_hal *ah,
 					 struct ath9k_channel *chan)
 {
 	if (!AR_SREV_5416_V20_OR_LATER(ah)
@@ -381,8 +358,8 @@
 	REG_WRITE(ah, 0x9800 + (651 << 2), 0x11);
 }
 
-static inline void ath9k_hw_init_bb(struct ath_hal *ah,
-				    struct ath9k_channel *chan)
+static void ath9k_hw_init_bb(struct ath_hal *ah,
+			     struct ath9k_channel *chan)
 {
 	u32 synthDelay;
 
@@ -397,8 +374,8 @@
 	udelay(synthDelay + BASE_ACTIVATE_DELAY);
 }
 
-static inline void ath9k_hw_init_interrupt_masks(struct ath_hal *ah,
-						 enum ath9k_opmode opmode)
+static void ath9k_hw_init_interrupt_masks(struct ath_hal *ah,
+					  enum ath9k_opmode opmode)
 {
 	struct ath_hal_5416 *ahp = AH5416(ah);
 
@@ -428,7 +405,7 @@
 	}
 }
 
-static inline void ath9k_hw_init_qos(struct ath_hal *ah)
+static void ath9k_hw_init_qos(struct ath_hal *ah)
 {
 	REG_WRITE(ah, AR_MIC_QOS_CONTROL, 0x100aa);
 	REG_WRITE(ah, AR_MIC_QOS_SELECT, 0x3210);
@@ -523,7 +500,7 @@
 		return ath9k_hw_eeprom_read(ah, off, data);
 }
 
-static inline bool ath9k_hw_fill_eeprom(struct ath_hal *ah)
+static bool ath9k_hw_fill_eeprom(struct ath_hal *ah)
 {
 	struct ath_hal_5416 *ahp = AH5416(ah);
 	struct ar5416_eeprom *eep = &ahp->ah_eeprom;
@@ -790,7 +767,7 @@
 	return true;
 }
 
-static inline int ath9k_hw_check_eeprom(struct ath_hal *ah)
+static int ath9k_hw_check_eeprom(struct ath_hal *ah)
 {
 	u32 sum = 0, el;
 	u16 *eepdata;
@@ -1196,11 +1173,12 @@
 
 	ah = &ahp->ah;
 
-	memcpy(&ahp->ah, &ar5416hal, sizeof(struct ath_hal));
-
 	ah->ah_sc = sc;
 	ah->ah_sh = mem;
 
+	ah->ah_magic = AR5416_MAGIC;
+	ah->ah_countryCode = CTRY_DEFAULT;
+
 	ah->ah_devid = devid;
 	ah->ah_subvendorid = 0;
 
@@ -1294,7 +1272,7 @@
 	}
 }
 
-static inline int ath9k_hw_get_radiorev(struct ath_hal *ah)
+static int ath9k_hw_get_radiorev(struct ath_hal *ah)
 {
 	u32 val;
 	int i;
@@ -1307,7 +1285,7 @@
 	return ath9k_hw_reverse_bits(val, 8);
 }
 
-static inline int ath9k_hw_init_macaddr(struct ath_hal *ah)
+static int ath9k_hw_init_macaddr(struct ath_hal *ah)
 {
 	u32 sum;
 	int i;
@@ -1389,7 +1367,7 @@
 	return spur_val;
 }
 
-static inline int ath9k_hw_rfattach(struct ath_hal *ah)
+static int ath9k_hw_rfattach(struct ath_hal *ah)
 {
 	bool rfStatus = false;
 	int ecode = 0;
@@ -1434,8 +1412,8 @@
 	return 0;
 }
 
-static inline void ath9k_hw_init_pll(struct ath_hal *ah,
-				     struct ath9k_channel *chan)
+static void ath9k_hw_init_pll(struct ath_hal *ah,
+			      struct ath9k_channel *chan)
 {
 	u32 pll;
 
@@ -1553,7 +1531,7 @@
 	}
 }
 
-static inline void
+static void
 ath9k_hw_set_rfmode(struct ath_hal *ah, struct ath9k_channel *chan)
 {
 	u32 rfMode = 0;
@@ -1623,7 +1601,7 @@
 	return true;
 }
 
-static inline bool ath9k_hw_set_reset_power_on(struct ath_hal *ah)
+static bool ath9k_hw_set_reset_power_on(struct ath_hal *ah)
 {
 	REG_WRITE(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN |
 		  AR_RTC_FORCE_WAKE_ON_INT);
@@ -1664,7 +1642,7 @@
 	}
 }
 
-static inline
+static
 struct ath9k_channel *ath9k_hw_check_chan(struct ath_hal *ah,
 					  struct ath9k_channel *chan)
 {
@@ -2098,7 +2076,7 @@
 		ahp->ah_procPhyErr |= HAL_PROCESS_ANI;
 }
 
-static inline void ath9k_hw_ani_setup(struct ath_hal *ah)
+static void ath9k_hw_ani_setup(struct ath_hal *ah)
 {
 	struct ath_hal_5416 *ahp = AH5416(ah);
 	int i;
@@ -2548,6 +2526,11 @@
 	}
 }
 
+/*
+ * Process a MIB interrupt.  We may potentially be invoked because
+ * any of the MIB counters overflow/trigger so don't assume we're
+ * here because a PHY error counter triggered.
+ */
 void ath9k_hw_procmibevent(struct ath_hal *ah,
 			   const struct ath9k_node_stats *stats)
 {
@@ -2555,18 +2538,20 @@
 	u32 phyCnt1, phyCnt2;
 
 	DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Processing Mib Intr\n");
-
+	/* Reset these counters regardless */
 	REG_WRITE(ah, AR_FILT_OFDM, 0);
 	REG_WRITE(ah, AR_FILT_CCK, 0);
 	if (!(REG_READ(ah, AR_SLP_MIB_CTRL) & AR_SLP_MIB_PENDING))
 		REG_WRITE(ah, AR_SLP_MIB_CTRL, AR_SLP_MIB_CLEAR);
 
+	/* Clear the mib counters and save them in the stats */
 	ath9k_hw_update_mibstats(ah, &ahp->ah_mibStats);
 	ahp->ah_stats.ast_nodestats = *stats;
 
 	if (!DO_ANI(ah))
 		return;
 
+	/* NB: these are not reset-on-read */
 	phyCnt1 = REG_READ(ah, AR_PHY_ERR_1);
 	phyCnt2 = REG_READ(ah, AR_PHY_ERR_2);
 	if (((phyCnt1 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK) ||
@@ -2574,6 +2559,7 @@
 		struct ar5416AniState *aniState = ahp->ah_curani;
 		u32 ofdmPhyErrCnt, cckPhyErrCnt;
 
+		/* NB: only use ast_ani_*errs with AH_PRIVATE_DIAG */
 		ofdmPhyErrCnt = phyCnt1 - aniState->ofdmPhyErrBase;
 		ahp->ah_stats.ast_ani_ofdmerrs +=
 			ofdmPhyErrCnt - aniState->ofdmPhyErrCount;
@@ -2584,11 +2570,17 @@
 			cckPhyErrCnt - aniState->cckPhyErrCount;
 		aniState->cckPhyErrCount = cckPhyErrCnt;
 
+		/*
+		 * NB: figure out which counter triggered.  If both
+		 * trigger we'll only deal with one as the processing
+		 * clobbers the error counter so the trigger threshold
+		 * check will never be true.
+		 */
 		if (aniState->ofdmPhyErrCount > aniState->ofdmTrigHigh)
 			ath9k_hw_ani_ofdm_err_trigger(ah);
 		if (aniState->cckPhyErrCount > aniState->cckTrigHigh)
 			ath9k_hw_ani_cck_err_trigger(ah);
-
+		/* NB: always restart to insure the h/w counters are reset */
 		ath9k_ani_restart(ah);
 	}
 }
@@ -2822,32 +2814,11 @@
 	}
 }
 
-static bool ath9k_hw_cfg_output(struct ath_hal *ah, u32 gpio,
-				enum ath9k_gpio_output_mux_type
-				halSignalType)
+void ath9k_hw_cfg_output(struct ath_hal *ah, u32 gpio,
+			 u32 ah_signal_type)
 {
-	u32 ah_signal_type;
 	u32 gpio_shift;
 
-	static u32 MuxSignalConversionTable[] = {
-
-		AR_GPIO_OUTPUT_MUX_AS_OUTPUT,
-
-		AR_GPIO_OUTPUT_MUX_AS_PCIE_ATTENTION_LED,
-
-		AR_GPIO_OUTPUT_MUX_AS_PCIE_POWER_LED,
-
-		AR_GPIO_OUTPUT_MUX_AS_MAC_NETWORK_LED,
-
-		AR_GPIO_OUTPUT_MUX_AS_MAC_POWER_LED,
-	};
-
-	if ((halSignalType >= 0)
-	    && (halSignalType < ARRAY_SIZE(MuxSignalConversionTable)))
-		ah_signal_type = MuxSignalConversionTable[halSignalType];
-	else
-		return false;
-
 	ath9k_hw_gpio_cfg_output_mux(ah, gpio, ah_signal_type);
 
 	gpio_shift = 2 * gpio;
@@ -2856,19 +2827,46 @@
 		AR_GPIO_OE_OUT,
 		(AR_GPIO_OE_OUT_DRV_ALL << gpio_shift),
 		(AR_GPIO_OE_OUT_DRV << gpio_shift));
-
-	return true;
 }
 
-static bool ath9k_hw_set_gpio(struct ath_hal *ah, u32 gpio,
-			      u32 val)
+void ath9k_hw_set_gpio(struct ath_hal *ah, u32 gpio, u32 val)
 {
 	REG_RMW(ah, AR_GPIO_IN_OUT, ((val & 1) << gpio),
 		AR_GPIO_BIT(gpio));
-	return true;
 }
 
-static u32 ath9k_hw_gpio_get(struct ath_hal *ah, u32 gpio)
+/*
+ * Configure GPIO Input lines
+ */
+void ath9k_hw_cfg_gpio_input(struct ath_hal *ah, u32 gpio)
+{
+	u32 gpio_shift;
+
+	ASSERT(gpio < ah->ah_caps.num_gpio_pins);
+
+	gpio_shift = gpio << 1;
+
+	REG_RMW(ah,
+		AR_GPIO_OE_OUT,
+		(AR_GPIO_OE_OUT_DRV_NO << gpio_shift),
+		(AR_GPIO_OE_OUT_DRV << gpio_shift));
+}
+
+#ifdef CONFIG_RFKILL
+static void ath9k_enable_rfkill(struct ath_hal *ah)
+{
+	REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL,
+		    AR_GPIO_INPUT_EN_VAL_RFSILENT_BB);
+
+	REG_CLR_BIT(ah, AR_GPIO_INPUT_MUX2,
+		    AR_GPIO_INPUT_MUX2_RFSILENT);
+
+	ath9k_hw_cfg_gpio_input(ah, ah->ah_rfkill_gpio);
+	REG_SET_BIT(ah, AR_PHY_TEST, RFSILENT_BB);
+}
+#endif
+
+u32 ath9k_hw_gpio_get(struct ath_hal *ah, u32 gpio)
 {
 	if (gpio >= ah->ah_caps.num_gpio_pins)
 		return 0xffffffff;
@@ -2883,7 +2881,7 @@
 	}
 }
 
-static inline int ath9k_hw_post_attach(struct ath_hal *ah)
+static int ath9k_hw_post_attach(struct ath_hal *ah)
 {
 	int ecode;
 
@@ -3081,17 +3079,17 @@
 
 	pCap->hw_caps |= ATH9K_HW_CAP_ENHANCEDPM;
 
+#ifdef CONFIG_RFKILL
 	ah->ah_rfsilent = ath9k_hw_get_eeprom(ahp, EEP_RF_SILENT);
 	if (ah->ah_rfsilent & EEP_RFSILENT_ENABLED) {
-		ahp->ah_gpioSelect =
+		ah->ah_rfkill_gpio =
 			MS(ah->ah_rfsilent, EEP_RFSILENT_GPIO_SEL);
-		ahp->ah_polarity =
+		ah->ah_rfkill_polarity =
 			MS(ah->ah_rfsilent, EEP_RFSILENT_POLARITY);
 
-		ath9k_hw_setcapability(ah, ATH9K_CAP_RFSILENT, 1, true,
-				       NULL);
 		pCap->hw_caps |= ATH9K_HW_CAP_RFSILENT;
 	}
+#endif
 
 	if ((ah->ah_macVersion == AR_SREV_VERSION_5416_PCI) ||
 	    (ah->ah_macVersion == AR_SREV_VERSION_5416_PCIE) ||
@@ -3595,7 +3593,7 @@
 	return true;
 }
 
-static inline void
+static void
 ath9k_hw_get_gain_boundaries_pdadcs(struct ath_hal *ah,
 				    struct ath9k_channel *chan,
 				    struct cal_data_per_freq *pRawDataSet,
@@ -3777,7 +3775,7 @@
 	return;
 }
 
-static inline bool
+static bool
 ath9k_hw_set_power_cal_table(struct ath_hal *ah,
 			     struct ar5416_eeprom *pEepData,
 			     struct ath9k_channel *chan,
@@ -3980,7 +3978,7 @@
 	}
 }
 
-static inline void
+static void
 ath9k_hw_get_legacy_target_powers(struct ath_hal *ah,
 				  struct ath9k_channel *chan,
 				  struct cal_target_power_leg *powInfo,
@@ -4046,7 +4044,7 @@
 	}
 }
 
-static inline void
+static void
 ath9k_hw_get_target_powers(struct ath_hal *ah,
 			   struct ath9k_channel *chan,
 			   struct cal_target_power_ht *powInfo,
@@ -4113,7 +4111,7 @@
 	}
 }
 
-static inline u16
+static u16
 ath9k_hw_get_max_edge_power(u16 freq,
 			    struct cal_ctl_edges *pRdEdgesPower,
 			    bool is2GHz)
@@ -4143,7 +4141,7 @@
 	return twiceMaxEdgePower;
 }
 
-static inline bool
+static bool
 ath9k_hw_set_power_per_rate_table(struct ath_hal *ah,
 				  struct ar5416_eeprom *pEepData,
 				  struct ath9k_channel *chan,
@@ -5122,7 +5120,7 @@
 	REG_WRITE(ah, AR_PHY_MASK2_P_61_45, tmp_mask);
 }
 
-static inline void ath9k_hw_init_chain_masks(struct ath_hal *ah)
+static void ath9k_hw_init_chain_masks(struct ath_hal *ah)
 {
 	struct ath_hal_5416 *ahp = AH5416(ah);
 	int rx_chainmask, tx_chainmask;
@@ -5326,7 +5324,7 @@
 	}
 }
 
-static inline void ath9k_hw_init_user_settings(struct ath_hal *ah)
+static void ath9k_hw_init_user_settings(struct ath_hal *ah)
 {
 	struct ath_hal_5416 *ahp = AH5416(ah);
 
@@ -5345,7 +5343,7 @@
 		ath9k_hw_set_global_txtimeout(ah, ahp->ah_globaltxtimeout);
 }
 
-static inline int
+static int
 ath9k_hw_process_ini(struct ath_hal *ah,
 		     struct ath9k_channel *chan,
 		     enum ath9k_ht_macmode macmode)
@@ -5476,7 +5474,7 @@
 	return 0;
 }
 
-static inline void ath9k_hw_setup_calibration(struct ath_hal *ah,
+static void ath9k_hw_setup_calibration(struct ath_hal *ah,
 					      struct hal_cal_list *currCal)
 {
 	REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(0),
@@ -5512,8 +5510,8 @@
 		    AR_PHY_TIMING_CTRL4_DO_CAL);
 }
 
-static inline void ath9k_hw_reset_calibration(struct ath_hal *ah,
-					      struct hal_cal_list *currCal)
+static void ath9k_hw_reset_calibration(struct ath_hal *ah,
+				       struct hal_cal_list *currCal)
 {
 	struct ath_hal_5416 *ahp = AH5416(ah);
 	int i;
@@ -5532,7 +5530,7 @@
 	ahp->ah_CalSamples = 0;
 }
 
-static inline void
+static void
 ath9k_hw_per_calibration(struct ath_hal *ah,
 			 struct ath9k_channel *ichan,
 			 u8 rxchainmask,
@@ -5622,7 +5620,7 @@
 	return true;
 }
 
-static inline bool
+static bool
 ath9k_hw_channel_change(struct ath_hal *ah,
 			struct ath9k_channel *chan,
 			enum ath9k_ht_macmode macmode)
@@ -5799,8 +5797,8 @@
 	return retval;
 }
 
-static inline bool ath9k_hw_init_cal(struct ath_hal *ah,
-				     struct ath9k_channel *chan)
+static bool ath9k_hw_init_cal(struct ath_hal *ah,
+			      struct ath9k_channel *chan)
 {
 	struct ath_hal_5416 *ahp = AH5416(ah);
 	struct ath9k_channel *ichan =
@@ -5861,7 +5859,7 @@
 }
 
 
-bool ath9k_hw_reset(struct ath_hal *ah, enum ath9k_opmode opmode,
+bool ath9k_hw_reset(struct ath_hal *ah,
 		    struct ath9k_channel *chan,
 		    enum ath9k_ht_macmode macmode,
 		    u8 txchainmask, u8 rxchainmask,
@@ -5869,7 +5867,6 @@
 		    bool bChannelChange,
 		    int *status)
 {
-#define FAIL(_code)     do { ecode = _code; goto bad; } while (0)
 	u32 saveLedState;
 	struct ath_hal_5416 *ahp = AH5416(ah);
 	struct ath9k_channel *curchan = ah->ah_curchan;
@@ -5891,11 +5888,14 @@
 		DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL,
 			 "%s: invalid channel %u/0x%x; no mapping\n",
 			 __func__, chan->channel, chan->channelFlags);
-		FAIL(-EINVAL);
+		ecode = -EINVAL;
+		goto bad;
 	}
 
-	if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE))
-		return false;
+	if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE)) {
+		ecode = -EIO;
+		goto bad;
+	}
 
 	if (curchan)
 		ath9k_hw_getnf(ah, curchan);
@@ -5932,7 +5932,8 @@
 	if (!ath9k_hw_chip_reset(ah, chan)) {
 		DPRINTF(ah->ah_sc, ATH_DBG_RESET, "%s: chip reset failed\n",
 			 __func__);
-		FAIL(-EIO);
+		ecode = -EINVAL;
+		goto bad;
 	}
 
 	if (AR_SREV_9280(ah)) {
@@ -5945,12 +5946,14 @@
 			else
 				ath9k_hw_set_gpio(ah, 9, 1);
 		}
-		ath9k_hw_cfg_output(ah, 9, ATH9K_GPIO_OUTPUT_MUX_AS_OUTPUT);
+		ath9k_hw_cfg_output(ah, 9, AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
 	}
 
 	ecode = ath9k_hw_process_ini(ah, chan, macmode);
-	if (ecode != 0)
+	if (ecode != 0) {
+		ecode = -EINVAL;
 		goto bad;
+	}
 
 	if (IS_CHAN_OFDM(chan) || IS_CHAN_HT(chan))
 		ath9k_hw_set_delta_slope(ah, chan);
@@ -5963,7 +5966,8 @@
 	if (!ath9k_hw_eeprom_set_board_values(ah, chan)) {
 		DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
 			 "%s: error setting board options\n", __func__);
-		FAIL(-EIO);
+		ecode = -EIO;
+		goto bad;
 	}
 
 	ath9k_hw_decrease_chain_power(ah, chan);
@@ -5975,7 +5979,7 @@
 		  | (ah->ah_config.
 		     ack_6mb ? AR_STA_ID1_ACKCTS_6MB : 0)
 		  | ahp->ah_staId1Defaults);
-	ath9k_hw_set_operating_mode(ah, opmode);
+	ath9k_hw_set_operating_mode(ah, ah->ah_opmode);
 
 	REG_WRITE(ah, AR_BSSMSKL, get_unaligned_le32(ahp->ah_bssidmask));
 	REG_WRITE(ah, AR_BSSMSKU, get_unaligned_le16(ahp->ah_bssidmask + 4));
@@ -5991,11 +5995,15 @@
 	REG_WRITE(ah, AR_RSSI_THR, INIT_RSSI_THR);
 
 	if (AR_SREV_9280_10_OR_LATER(ah)) {
-		if (!(ath9k_hw_ar9280_set_channel(ah, chan)))
-			FAIL(-EIO);
+		if (!(ath9k_hw_ar9280_set_channel(ah, chan))) {
+			ecode = -EIO;
+			goto bad;
+		}
 	} else {
-		if (!(ath9k_hw_set_channel(ah, chan)))
-			FAIL(-EIO);
+		if (!(ath9k_hw_set_channel(ah, chan))) {
+			ecode = -EIO;
+			goto bad;
+		}
 	}
 
 	for (i = 0; i < AR_NUM_DCU; i++)
@@ -6005,13 +6013,15 @@
 	for (i = 0; i < ah->ah_caps.total_queues; i++)
 		ath9k_hw_resettxqueue(ah, i);
 
-	ath9k_hw_init_interrupt_masks(ah, opmode);
+	ath9k_hw_init_interrupt_masks(ah, ah->ah_opmode);
 	ath9k_hw_init_qos(ah);
 
+#ifdef CONFIG_RFKILL
+	if (ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
+		ath9k_enable_rfkill(ah);
+#endif
 	ath9k_hw_init_user_settings(ah);
 
-	ah->ah_opmode = opmode;
-
 	REG_WRITE(ah, AR_STA_ID1,
 		  REG_READ(ah, AR_STA_ID1) | AR_STA_ID1_PRESERVE_SEQNUM);
 
@@ -6027,8 +6037,10 @@
 
 	ath9k_hw_init_bb(ah, chan);
 
-	if (!ath9k_hw_init_cal(ah, chan))
-		FAIL(-ENODEV);
+	if (!ath9k_hw_init_cal(ah, chan)){
+		ecode = -EIO;;
+		goto bad;
+	}
 
 	rx_chainmask = ahp->ah_rxchainmask;
 	if ((rx_chainmask == 0x5) || (rx_chainmask == 0x3)) {
@@ -6064,7 +6076,6 @@
 	if (status)
 		*status = ecode;
 	return false;
-#undef FAIL
 }
 
 bool ath9k_hw_phy_disable(struct ath_hal *ah)
@@ -6539,31 +6550,6 @@
 	return true;
 }
 
-#ifdef CONFIG_ATH9K_RFKILL
-static void ath9k_enable_rfkill(struct ath_hal *ah)
-{
-	struct ath_hal_5416 *ahp = AH5416(ah);
-
-	REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL,
-		    AR_GPIO_INPUT_EN_VAL_RFSILENT_BB);
-
-	REG_CLR_BIT(ah, AR_GPIO_INPUT_MUX2,
-		    AR_GPIO_INPUT_MUX2_RFSILENT);
-
-	ath9k_hw_cfg_gpio_input(ah, ahp->ah_gpioSelect);
-	REG_SET_BIT(ah, AR_PHY_TEST, RFSILENT_BB);
-
-	if (ahp->ah_gpioBit == ath9k_hw_gpio_get(ah, ahp->ah_gpioSelect)) {
-
-		ath9k_hw_set_gpio_intr(ah, ahp->ah_gpioSelect,
-				       !ahp->ah_gpioBit);
-	} else {
-		ath9k_hw_set_gpio_intr(ah, ahp->ah_gpioSelect,
-				       ahp->ah_gpioBit);
-	}
-}
-#endif
-
 void
 ath9k_hw_write_associd(struct ath_hal *ah, const u8 *bssid,
 		       u16 assocId)
@@ -7678,8 +7664,7 @@
 	REG_WRITE(ah, AR_DRETRY_LIMIT(q),
 		  SM(INIT_SSH_RETRY, AR_D_RETRY_LIMIT_STA_SH)
 		  | SM(INIT_SLG_RETRY, AR_D_RETRY_LIMIT_STA_LG)
-		  | SM(qi->tqi_shretry, AR_D_RETRY_LIMIT_FR_SH)
-		);
+		  | SM(qi->tqi_shretry, AR_D_RETRY_LIMIT_FR_SH));
 
 	REG_WRITE(ah, AR_QMISC(q), AR_Q_MISC_DCU_EARLY_TERM_REQ);
 	REG_WRITE(ah, AR_DMISC(q),
@@ -8324,15 +8309,7 @@
 		*error = -ENXIO;
 		break;
 	}
-	if (ah != NULL) {
-		ah->ah_devid = ah->ah_devid;
-		ah->ah_subvendorid = ah->ah_subvendorid;
-		ah->ah_macVersion = ah->ah_macVersion;
-		ah->ah_macRev = ah->ah_macRev;
-		ah->ah_phyRev = ah->ah_phyRev;
-		ah->ah_analog5GhzRev = ah->ah_analog5GhzRev;
-		ah->ah_analog2GhzRev = ah->ah_analog2GhzRev;
-	}
+
 	return ah;
 }
 
@@ -8439,23 +8416,48 @@
 	}
 }
 
-int16_t
+/* We can tune this as we go by monitoring really low values */
+#define ATH9K_NF_TOO_LOW	-60
+
+/* AR5416 may return very high value (like -31 dBm), in those cases the nf
+ * is incorrect and we should use the static NF value. Later we can try to
+ * find out why they are reporting these values */
+static bool ath9k_hw_nf_in_range(struct ath_hal *ah, s16 nf)
+{
+	if (nf > ATH9K_NF_TOO_LOW) {
+		DPRINTF(ah->ah_sc, ATH_DBG_NF_CAL,
+			 "%s: noise floor value detected (%d) is "
+			"lower than what we think is a "
+			"reasonable value (%d)\n",
+			 __func__, nf, ATH9K_NF_TOO_LOW);
+		return false;
+	}
+	return true;
+}
+
+s16
 ath9k_hw_getchan_noise(struct ath_hal *ah, struct ath9k_channel *chan)
 {
 	struct ath9k_channel *ichan;
+	s16 nf;
 
 	ichan = ath9k_regd_check_channel(ah, chan);
 	if (ichan == NULL) {
 		DPRINTF(ah->ah_sc, ATH_DBG_NF_CAL,
 			 "%s: invalid channel %u/0x%x; no mapping\n",
 			 __func__, chan->channel, chan->channelFlags);
-		return 0;
+		return ATH_DEFAULT_NOISE_FLOOR;
 	}
 	if (ichan->rawNoiseFloor == 0) {
 		enum wireless_mode mode = ath9k_hw_chan2wmode(ah, chan);
-		return NOISE_FLOOR[mode];
+		nf = NOISE_FLOOR[mode];
 	} else
-		return ichan->rawNoiseFloor;
+		nf = ichan->rawNoiseFloor;
+
+	if (!ath9k_hw_nf_in_range(ah, nf))
+		nf = ATH_DEFAULT_NOISE_FLOOR;
+
+	return nf;
 }
 
 bool ath9k_hw_set_tsfadjust(struct ath_hal *ah, u32 setting)
diff --git a/drivers/net/wireless/ath9k/hw.h b/drivers/net/wireless/ath9k/hw.h
index ae680f2..2113818 100644
--- a/drivers/net/wireless/ath9k/hw.h
+++ b/drivers/net/wireless/ath9k/hw.h
@@ -314,14 +314,11 @@
 #define RXSTATUS_RATE(ah, ads)  (AR_SREV_5416_V20_OR_LATER(ah) ?	\
 				 MS(ads->ds_rxstatus0, AR_RxRate) :	\
 				 (ads->ds_rxstatus3 >> 2) & 0xFF)
-#define RXSTATUS_DUPLICATE(ah, ads)  (AR_SREV_5416_V20_OR_LATER(ah) ?	\
-				      MS(ads->ds_rxstatus3, AR_Parallel40) : \
-				      (ads->ds_rxstatus3 >> 10) & 0x1)
 
-#define set11nTries(_series, _index)				\
+#define set11nTries(_series, _index) \
 	(SM((_series)[_index].Tries, AR_XmitDataTries##_index))
 
-#define set11nRate(_series, _index)				\
+#define set11nRate(_series, _index) \
 	(SM((_series)[_index].Rate, AR_XmitRate##_index))
 
 #define set11nPktDurRTSCTS(_series, _index)				\
@@ -330,11 +327,11 @@
 		AR_RTSCTSQual##_index : 0))
 
 #define set11nRateFlags(_series, _index)				\
-	(((_series)[_index].RateFlags & ATH9K_RATESERIES_2040 ? \
-		AR_2040_##_index : 0) \
-	|((_series)[_index].RateFlags & ATH9K_RATESERIES_HALFGI ? \
-		AR_GI##_index : 0) \
-	|SM((_series)[_index].ChSel, AR_ChainSel##_index))
+	(((_series)[_index].RateFlags & ATH9K_RATESERIES_2040 ?		\
+	  AR_2040_##_index : 0)						\
+	 |((_series)[_index].RateFlags & ATH9K_RATESERIES_HALFGI ?	\
+	   AR_GI##_index : 0)						\
+	 |SM((_series)[_index].ChSel, AR_ChainSel##_index))
 
 #define AR_SREV_9100(ah) ((ah->ah_macVersion) == AR_SREV_VERSION_9100)
 
@@ -346,9 +343,6 @@
 #define MAX_TX_FIFO_THRESHOLD   ((4096 / 64) - 1)
 #define INIT_TX_FIFO_THRESHOLD  MIN_TX_FIFO_THRESHOLD
 
-#define NUM_CORNER_FIX_BITS_2133    7
-#define CCK_OFDM_GAIN_DELTA         15
-
 struct ar5416AniState {
 	struct ath9k_channel c;
 	u8 noiseImmunityLevel;
@@ -377,11 +371,8 @@
 };
 
 #define HAL_PROCESS_ANI     0x00000001
-#define HAL_RADAR_EN        0x80000000
-#define HAL_AR_EN           0x40000000
-
 #define DO_ANI(ah) \
-    ((AH5416(ah)->ah_procPhyErr & HAL_PROCESS_ANI))
+	((AH5416(ah)->ah_procPhyErr & HAL_PROCESS_ANI))
 
 struct ar5416Stats {
 	u32 ast_ani_niup;
@@ -425,7 +416,6 @@
 #define AR5416_EEP_MINOR_VER_7       0x7
 #define AR5416_EEP_MINOR_VER_9       0x9
 
-#define AR5416_EEP_START_LOC            256
 #define AR5416_NUM_5G_CAL_PIERS         8
 #define AR5416_NUM_2G_CAL_PIERS         4
 #define AR5416_NUM_5G_20_TARGET_POWERS  8
@@ -441,25 +431,10 @@
 #define AR5416_EEPROM_MODAL_SPURS       5
 #define AR5416_MAX_RATE_POWER           63
 #define AR5416_NUM_PDADC_VALUES         128
-#define AR5416_NUM_RATES                16
 #define AR5416_BCHAN_UNUSED             0xFF
 #define AR5416_MAX_PWR_RANGE_IN_HALF_DB 64
-#define AR5416_EEPMISC_BIG_ENDIAN       0x01
 #define AR5416_MAX_CHAINS               3
-#define AR5416_ANT_16S                  25
-
-#define AR5416_NUM_ANT_CHAIN_FIELDS     7
-#define AR5416_NUM_ANT_COMMON_FIELDS    4
-#define AR5416_SIZE_ANT_CHAIN_FIELD     3
-#define AR5416_SIZE_ANT_COMMON_FIELD    4
-#define AR5416_ANT_CHAIN_MASK           0x7
-#define AR5416_ANT_COMMON_MASK          0xf
-#define AR5416_CHAIN_0_IDX              0
-#define AR5416_CHAIN_1_IDX              1
-#define AR5416_CHAIN_2_IDX              2
-
 #define AR5416_PWR_TABLE_OFFSET         -5
-#define AR5416_LEGACY_CHAINMASK         1
 
 enum eeprom_param {
 	EEP_NFTHRESH_5,
@@ -633,7 +608,7 @@
 };
 
 #define INIT_INI_ARRAY(iniarray, array, rows, columns) do {	\
-		(iniarray)->ia_array = (u32 *)(array);    \
+		(iniarray)->ia_array = (u32 *)(array);		\
 		(iniarray)->ia_rows = (rows);			\
 		(iniarray)->ia_columns = (columns);		\
 	} while (0)
@@ -641,16 +616,16 @@
 #define INI_RA(iniarray, row, column) \
 	(((iniarray)->ia_array)[(row) *	((iniarray)->ia_columns) + (column)])
 
-#define INIT_CAL(_perCal) do { \
-		(_perCal)->calState = CAL_WAITING; \
-		(_perCal)->calNext = NULL; \
+#define INIT_CAL(_perCal) do {				\
+		(_perCal)->calState = CAL_WAITING;	\
+		(_perCal)->calNext = NULL;		\
 	} while (0)
 
 #define INSERT_CAL(_ahp, _perCal)					\
 	do {								\
 		if ((_ahp)->ah_cal_list_last == NULL) {			\
-			(_ahp)->ah_cal_list = \
-				(_ahp)->ah_cal_list_last = (_perCal); \
+			(_ahp)->ah_cal_list =				\
+				(_ahp)->ah_cal_list_last = (_perCal);	\
 			((_ahp)->ah_cal_list_last)->calNext = (_perCal); \
 		} else {						\
 			((_ahp)->ah_cal_list_last)->calNext = (_perCal); \
@@ -696,25 +671,29 @@
 struct ath_hal_5416 {
 	struct ath_hal ah;
 	struct ar5416_eeprom ah_eeprom;
+	struct ar5416Stats ah_stats;
+	struct ath9k_tx_queue_info ah_txq[ATH9K_NUM_TX_QUEUES];
+	void __iomem *ah_cal_mem;
+
 	u8 ah_macaddr[ETH_ALEN];
 	u8 ah_bssid[ETH_ALEN];
 	u8 ah_bssidmask[ETH_ALEN];
 	u16 ah_assocId;
+
 	int16_t ah_curchanRadIndex;
 	u32 ah_maskReg;
-	struct ar5416Stats ah_stats;
-	u32 ah_txDescMask;
 	u32 ah_txOkInterruptMask;
 	u32 ah_txErrInterruptMask;
 	u32 ah_txDescInterruptMask;
 	u32 ah_txEolInterruptMask;
 	u32 ah_txUrnInterruptMask;
-	struct ath9k_tx_queue_info ah_txq[ATH9K_NUM_TX_QUEUES];
-	enum ath9k_power_mode ah_powerMode;
 	bool ah_chipFullSleep;
 	u32 ah_atimWindow;
-	enum ath9k_ant_setting ah_diversityControl;
 	u16 ah_antennaSwitchSwap;
+	enum ath9k_power_mode ah_powerMode;
+	enum ath9k_ant_setting ah_diversityControl;
+
+	/* Calibration */
 	enum hal_cal_types ah_suppCals;
 	struct hal_cal_list ah_iqCalData;
 	struct hal_cal_list ah_adcGainCalData;
@@ -751,16 +730,16 @@
 		int32_t sign[AR5416_MAX_CHAINS];
 	} ah_Meas3;
 	u16 ah_CalSamples;
-	u32 ah_tx6PowerInHalfDbm;
+
 	u32 ah_staId1Defaults;
 	u32 ah_miscMode;
-	bool ah_tpcEnabled;
-	u32 ah_beaconInterval;
 	enum {
 		AUTO_32KHZ,
 		USE_32KHZ,
 		DONT_USE_32KHZ,
 	} ah_enable32kHzClock;
+
+	/* RF */
 	u32 *ah_analogBank0Data;
 	u32 *ah_analogBank1Data;
 	u32 *ah_analogBank2Data;
@@ -770,8 +749,9 @@
 	u32 *ah_analogBank7Data;
 	u32 *ah_addac5416_21;
 	u32 *ah_bank6Temp;
-	u32 ah_ofdmTxPower;
+
 	int16_t ah_txPowerIndexOffset;
+	u32 ah_beaconInterval;
 	u32 ah_slottime;
 	u32 ah_acktimeout;
 	u32 ah_ctstimeout;
@@ -780,7 +760,8 @@
 	u32 ah_gpioSelect;
 	u32 ah_polarity;
 	u32 ah_gpioBit;
-	bool ah_eepEnabled;
+
+	/* ANI */
 	u32 ah_procPhyErr;
 	bool ah_hasHwPhyCounters;
 	u32 ah_aniPeriod;
@@ -790,18 +771,14 @@
 	int ah_coarseHigh[5];
 	int ah_coarseLow[5];
 	int ah_firpwr[5];
-	u16 ah_ratesArray[16];
+	enum ath9k_ani_cmd ah_ani_function;
+
 	u32 ah_intrTxqs;
 	bool ah_intrMitigation;
-	u32 ah_cycleCount;
-	u32 ah_ctlBusy;
-	u32 ah_extBusy;
 	enum ath9k_ht_extprotspacing ah_extprotspacing;
 	u8 ah_txchainmask;
 	u8 ah_rxchainmask;
-	int ah_hwp;
-	void __iomem *ah_cal_mem;
-	enum ath9k_ani_cmd ah_ani_function;
+
 	struct ar5416IniArray ah_iniModes;
 	struct ar5416IniArray ah_iniCommon;
 	struct ar5416IniArray ah_iniBank0;
@@ -820,10 +797,6 @@
 
 #define FREQ2FBIN(x, y) ((y) ? ((x) - 2300) : (((x) - 4800) / 5))
 
-#define IS_5416_EMU(ah)					\
-	((ah->ah_devid == AR5416_DEVID_EMU) ||		\
-	 (ah->ah_devid == AR5416_DEVID_EMU_PCIE))
-
 #define ar5416RfDetach(ah) do {					\
 		if (AH5416(ah)->ah_rfHal.rfDetach != NULL)	\
 			AH5416(ah)->ah_rfHal.rfDetach(ah);	\
@@ -841,8 +814,8 @@
 #define REG_WRITE_ARRAY(iniarray, column, regWr) do {                   \
 		int r;							\
 		for (r = 0; r < ((iniarray)->ia_rows); r++) {		\
-			REG_WRITE(ah, INI_RA((iniarray), (r), 0), \
-				INI_RA((iniarray), r, (column))); \
+			REG_WRITE(ah, INI_RA((iniarray), (r), 0),	\
+				  INI_RA((iniarray), r, (column)));	\
 			DO_DELAY(regWr);				\
 		}							\
 	} while (0)
@@ -852,30 +825,21 @@
 #define COEF_SCALE_S                24
 #define HT40_CHANNEL_CENTER_SHIFT   10
 
-#define ar5416CheckOpMode(_opmode)					\
-	((_opmode == ATH9K_M_STA) || (_opmode == ATH9K_M_IBSS) ||	\
-	 (_opmode == ATH9K_M_HOSTAP) || (_opmode == ATH9K_M_MONITOR))
-
 #define AR5416_EEPROM_MAGIC_OFFSET  0x0
 
 #define AR5416_EEPROM_S             2
 #define AR5416_EEPROM_OFFSET        0x2000
-#define AR5416_EEPROM_START_ADDR			\
+#define AR5416_EEPROM_START_ADDR \
 	(AR_SREV_9100(ah)) ? 0x1fff1000 : 0x503f1200
 #define AR5416_EEPROM_MAX           0xae0
-#define ar5416_get_eep_ver(_ahp)				\
+#define ar5416_get_eep_ver(_ahp) \
 	(((_ahp)->ah_eeprom.baseEepHeader.version >> 12) & 0xF)
-#define ar5416_get_eep_rev(_ahp)				\
+#define ar5416_get_eep_rev(_ahp) \
 	(((_ahp)->ah_eeprom.baseEepHeader.version) & 0xFFF)
-#define ar5416_get_ntxchains(_txchainmask)				\
+#define ar5416_get_ntxchains(_txchainmask) \
 	(((_txchainmask >> 2) & 1) + \
 		((_txchainmask >> 1) & 1) + (_txchainmask & 1))
 
-#define IS_EEP_MINOR_V3(_ahp) \
-	(ath9k_hw_get_eeprom((_ahp), EEP_MINOR_REV)  >= AR5416_EEP_MINOR_VER_3)
-
-#define FIXED_CCA_THRESHOLD 15
-
 #ifdef __BIG_ENDIAN
 #define AR5416_EEPROM_MAGIC 0x5aa5
 #else
@@ -910,8 +874,6 @@
 #define AR_GPIOD_MASK                   0x00001FFF
 #define AR_GPIO_BIT(_gpio)              (1 << (_gpio))
 
-#define MAX_ANALOG_START                319
-
 #define HAL_EP_RND(x, mul) \
 	((((x)%(mul)) >= ((mul)/2)) ? ((x) + ((mul) - 1)) / (mul) : (x)/(mul))
 #define BEACON_RSSI(ahp) \
@@ -923,8 +885,6 @@
 #define AH_TIMEOUT         100000
 #define AH_TIME_QUANTUM        10
 
-#define IS(_c, _f)       (((_c)->channelFlags & _f) || 0)
-
 #define AR_KEYTABLE_SIZE 128
 #define POWER_UP_TIME    200000
 
@@ -964,6 +924,6 @@
 #define OFDM_SYMBOL_TIME_QUARTER    16
 
 u32 ath9k_hw_get_eeprom(struct ath_hal_5416 *ahp,
-			      enum eeprom_param param);
+			enum eeprom_param param);
 
 #endif
diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c
index 99badf1..7472699 100644
--- a/drivers/net/wireless/ath9k/main.c
+++ b/drivers/net/wireless/ath9k/main.c
@@ -22,8 +22,6 @@
 #define ATH_PCI_VERSION "0.1"
 
 #define IEEE80211_HTCAP_MAXRXAMPDU_FACTOR	13
-#define IEEE80211_ACTION_CAT_HT			7
-#define IEEE80211_ACTION_HT_TXCHWIDTH		0
 
 static char *dev_info = "ath9k";
 
@@ -142,7 +140,7 @@
 	struct ath9k_keyval hk;
 	const u8 *mac = NULL;
 	int ret = 0;
-	enum ieee80211_if_types opmode;
+	enum nl80211_iftype opmode;
 
 	memset(&hk, 0, sizeof(hk));
 
@@ -181,14 +179,14 @@
 	 */
 	if (is_broadcast_ether_addr(addr)) {
 		switch (opmode) {
-		case IEEE80211_IF_TYPE_STA:
+		case NL80211_IFTYPE_STATION:
 			/* default key:  could be group WPA key
 			 * or could be static WEP key */
 			mac = NULL;
 			break;
-		case IEEE80211_IF_TYPE_IBSS:
+		case NL80211_IFTYPE_ADHOC:
 			break;
-		case IEEE80211_IF_TYPE_AP:
+		case NL80211_IFTYPE_AP:
 			break;
 		default:
 			ASSERT(0);
@@ -206,37 +204,30 @@
 	if (!ret)
 		return -EIO;
 
-	if (mac)
-		sc->sc_keytype = hk.kv_type;
 	return 0;
 }
 
 static void ath_key_delete(struct ath_softc *sc, struct ieee80211_key_conf *key)
 {
-#define ATH_MAX_NUM_KEYS 4
 	int freeslot;
 
-	freeslot = (key->keyidx >= ATH_MAX_NUM_KEYS) ? 1 : 0;
+	freeslot = (key->keyidx >= 4) ? 1 : 0;
 	ath_key_reset(sc, key->keyidx, freeslot);
-#undef ATH_MAX_NUM_KEYS
 }
 
 static void setup_ht_cap(struct ieee80211_ht_info *ht_info)
 {
-/* Until mac80211 includes these fields */
-
-#define IEEE80211_HT_CAP_DSSSCCK40 0x1000
-#define	IEEE80211_HT_CAP_MAXRXAMPDU_65536 0x3   /* 2 ^ 16 */
-#define	IEEE80211_HT_CAP_MPDUDENSITY_8 0x6     	/* 8 usec */
+#define	ATH9K_HT_CAP_MAXRXAMPDU_65536 0x3	/* 2 ^ 16 */
+#define	ATH9K_HT_CAP_MPDUDENSITY_8 0x6		/* 8 usec */
 
 	ht_info->ht_supported = 1;
 	ht_info->cap = (u16)IEEE80211_HT_CAP_SUP_WIDTH
-			|(u16)IEEE80211_HT_CAP_MIMO_PS
+			|(u16)IEEE80211_HT_CAP_SM_PS
 			|(u16)IEEE80211_HT_CAP_SGI_40
 			|(u16)IEEE80211_HT_CAP_DSSSCCK40;
 
-	ht_info->ampdu_factor = IEEE80211_HT_CAP_MAXRXAMPDU_65536;
-	ht_info->ampdu_density = IEEE80211_HT_CAP_MPDUDENSITY_8;
+	ht_info->ampdu_factor = ATH9K_HT_CAP_MAXRXAMPDU_65536;
+	ht_info->ampdu_density = ATH9K_HT_CAP_MPDUDENSITY_8;
 	/* setup supported mcs set */
 	memset(ht_info->supp_mcs_set, 0, 16);
 	ht_info->supp_mcs_set[0] = 0xff;
@@ -283,10 +274,12 @@
 	rx_status->mactime = status->tsf;
 	rx_status->band = curchan->band;
 	rx_status->freq =  curchan->center_freq;
-	rx_status->noise = ATH_DEFAULT_NOISE_FLOOR;
+	rx_status->noise = sc->sc_ani.sc_noise_floor;
 	rx_status->signal = rx_status->noise + status->rssi;
 	rx_status->rate_idx = ath_rate2idx(sc, (status->rateKbps / 100));
 	rx_status->antenna = status->antenna;
+
+	/* XXX Fix me, 64 cannot be the max rssi value, rigure it out */
 	rx_status->qual = status->rssi * 100 / 64;
 
 	if (status->flags & ATH_RX_MIC_ERROR)
@@ -332,461 +325,6 @@
 	}
 }
 
-static int ath9k_start(struct ieee80211_hw *hw)
-{
-	struct ath_softc *sc = hw->priv;
-	struct ieee80211_channel *curchan = hw->conf.channel;
-	int error = 0, pos;
-
-	DPRINTF(sc, ATH_DBG_CONFIG, "%s: Starting driver with "
-		"initial channel: %d MHz\n", __func__, curchan->center_freq);
-
-	/* setup initial channel */
-
-	pos = ath_get_channel(sc, curchan);
-	if (pos == -1) {
-		DPRINTF(sc, ATH_DBG_FATAL, "%s: Invalid channel\n", __func__);
-		return -EINVAL;
-	}
-
-	sc->sc_ah->ah_channels[pos].chanmode =
-		(curchan->band == IEEE80211_BAND_2GHZ) ? CHANNEL_G : CHANNEL_A;
-
-	/* open ath_dev */
-	error = ath_open(sc, &sc->sc_ah->ah_channels[pos]);
-	if (error) {
-		DPRINTF(sc, ATH_DBG_FATAL,
-			"%s: Unable to complete ath_open\n", __func__);
-		return error;
-	}
-
-	ieee80211_wake_queues(hw);
-	return 0;
-}
-
-static int ath9k_tx(struct ieee80211_hw *hw,
-		    struct sk_buff *skb)
-{
-	struct ath_softc *sc = hw->priv;
-	int hdrlen, padsize;
-	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
-
-	/*
-	 * As a temporary workaround, assign seq# here; this will likely need
-	 * to be cleaned up to work better with Beacon transmission and virtual
-	 * BSSes.
-	 */
-	if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) {
-		struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
-		if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT)
-			sc->seq_no += 0x10;
-		hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG);
-		hdr->seq_ctrl |= cpu_to_le16(sc->seq_no);
-	}
-
-	/* Add the padding after the header if this is not already done */
-	hdrlen = ieee80211_get_hdrlen_from_skb(skb);
-	if (hdrlen & 3) {
-		padsize = hdrlen % 4;
-		if (skb_headroom(skb) < padsize)
-			return -1;
-		skb_push(skb, padsize);
-		memmove(skb->data, skb->data + padsize, hdrlen);
-	}
-
-	DPRINTF(sc, ATH_DBG_XMIT, "%s: transmitting packet, skb: %p\n",
-		__func__,
-		skb);
-
-	if (ath_tx_start(sc, skb) != 0) {
-		DPRINTF(sc, ATH_DBG_XMIT, "%s: TX failed\n", __func__);
-		dev_kfree_skb_any(skb);
-		/* FIXME: Check for proper return value from ATH_DEV */
-		return 0;
-	}
-
-	return 0;
-}
-
-static void ath9k_stop(struct ieee80211_hw *hw)
-{
-	struct ath_softc *sc = hw->priv;
-	int error;
-
-	DPRINTF(sc, ATH_DBG_CONFIG, "%s: Driver halt\n", __func__);
-
-	error = ath_suspend(sc);
-	if (error)
-		DPRINTF(sc, ATH_DBG_CONFIG,
-			"%s: Device is no longer present\n", __func__);
-
-	ieee80211_stop_queues(hw);
-}
-
-static int ath9k_add_interface(struct ieee80211_hw *hw,
-			       struct ieee80211_if_init_conf *conf)
-{
-	struct ath_softc *sc = hw->priv;
-	int error, ic_opmode = 0;
-
-	/* Support only vap for now */
-
-	if (sc->sc_nvaps)
-		return -ENOBUFS;
-
-	switch (conf->type) {
-	case IEEE80211_IF_TYPE_STA:
-		ic_opmode = ATH9K_M_STA;
-		break;
-	case IEEE80211_IF_TYPE_IBSS:
-		ic_opmode = ATH9K_M_IBSS;
-		break;
-	default:
-		DPRINTF(sc, ATH_DBG_FATAL,
-			"%s: Only STA and IBSS are supported currently\n",
-			__func__);
-		return -EOPNOTSUPP;
-	}
-
-	DPRINTF(sc, ATH_DBG_CONFIG, "%s: Attach a VAP of type: %d\n",
-		__func__,
-		ic_opmode);
-
-	error = ath_vap_attach(sc, 0, conf->vif, ic_opmode);
-	if (error) {
-		DPRINTF(sc, ATH_DBG_FATAL,
-			"%s: Unable to attach vap, error: %d\n",
-			__func__, error);
-		return error;
-	}
-
-	return 0;
-}
-
-static void ath9k_remove_interface(struct ieee80211_hw *hw,
-				   struct ieee80211_if_init_conf *conf)
-{
-	struct ath_softc *sc = hw->priv;
-	struct ath_vap *avp;
-	int error;
-
-	DPRINTF(sc, ATH_DBG_CONFIG, "%s: Detach VAP\n", __func__);
-
-	avp = sc->sc_vaps[0];
-	if (avp == NULL) {
-		DPRINTF(sc, ATH_DBG_FATAL, "%s: Invalid interface\n",
-			__func__);
-		return;
-	}
-
-#ifdef CONFIG_SLOW_ANT_DIV
-	ath_slow_ant_div_stop(&sc->sc_antdiv);
-#endif
-
-	/* Update ratectrl */
-	ath_rate_newstate(sc, avp);
-
-	/* Reclaim beacon resources */
-	if (sc->sc_opmode == ATH9K_M_HOSTAP || sc->sc_opmode == ATH9K_M_IBSS) {
-		ath9k_hw_stoptxdma(sc->sc_ah, sc->sc_bhalq);
-		ath_beacon_return(sc, avp);
-	}
-
-	/* Set interrupt mask */
-	sc->sc_imask &= ~(ATH9K_INT_SWBA | ATH9K_INT_BMISS);
-	ath9k_hw_set_interrupts(sc->sc_ah, sc->sc_imask & ~ATH9K_INT_GLOBAL);
-	sc->sc_beacons = 0;
-
-	error = ath_vap_detach(sc, 0);
-	if (error)
-		DPRINTF(sc, ATH_DBG_FATAL,
-			"%s: Unable to detach vap, error: %d\n",
-			__func__, error);
-}
-
-static int ath9k_config(struct ieee80211_hw *hw,
-			struct ieee80211_conf *conf)
-{
-	struct ath_softc *sc = hw->priv;
-	struct ieee80211_channel *curchan = hw->conf.channel;
-	int pos;
-
-	DPRINTF(sc, ATH_DBG_CONFIG, "%s: Set channel: %d MHz\n",
-		__func__,
-		curchan->center_freq);
-
-	pos = ath_get_channel(sc, curchan);
-	if (pos == -1) {
-		DPRINTF(sc, ATH_DBG_FATAL, "%s: Invalid channel\n", __func__);
-		return -EINVAL;
-	}
-
-	sc->sc_ah->ah_channels[pos].chanmode =
-		(curchan->band == IEEE80211_BAND_2GHZ) ?
-		CHANNEL_G : CHANNEL_A;
-
-	if (sc->sc_curaid && hw->conf.ht_conf.ht_supported)
-		sc->sc_ah->ah_channels[pos].chanmode =
-			ath_get_extchanmode(sc, curchan);
-
-	sc->sc_config.txpowlimit = 2 * conf->power_level;
-
-	/* set h/w channel */
-	if (ath_set_channel(sc, &sc->sc_ah->ah_channels[pos]) < 0)
-		DPRINTF(sc, ATH_DBG_FATAL, "%s: Unable to set channel\n",
-			__func__);
-
-	return 0;
-}
-
-static int ath9k_config_interface(struct ieee80211_hw *hw,
-				  struct ieee80211_vif *vif,
-				  struct ieee80211_if_conf *conf)
-{
-	struct ath_softc *sc = hw->priv;
-	struct ath_vap *avp;
-	u32 rfilt = 0;
-	int error, i;
-	DECLARE_MAC_BUF(mac);
-
-	avp = sc->sc_vaps[0];
-	if (avp == NULL) {
-		DPRINTF(sc, ATH_DBG_FATAL, "%s: Invalid interface\n",
-			__func__);
-		return -EINVAL;
-	}
-
-	if ((conf->changed & IEEE80211_IFCC_BSSID) &&
-	    !is_zero_ether_addr(conf->bssid)) {
-		switch (vif->type) {
-		case IEEE80211_IF_TYPE_STA:
-		case IEEE80211_IF_TYPE_IBSS:
-			/* Update ratectrl about the new state */
-			ath_rate_newstate(sc, avp);
-
-			/* Set rx filter */
-			rfilt = ath_calcrxfilter(sc);
-			ath9k_hw_setrxfilter(sc->sc_ah, rfilt);
-
-			/* Set BSSID */
-			memcpy(sc->sc_curbssid, conf->bssid, ETH_ALEN);
-			sc->sc_curaid = 0;
-			ath9k_hw_write_associd(sc->sc_ah, sc->sc_curbssid,
-					       sc->sc_curaid);
-
-			/* Set aggregation protection mode parameters */
-			sc->sc_config.ath_aggr_prot = 0;
-
-			/*
-			 * Reset our TSF so that its value is lower than the
-			 * beacon that we are trying to catch.
-			 * Only then hw will update its TSF register with the
-			 * new beacon. Reset the TSF before setting the BSSID
-			 * to avoid allowing in any frames that would update
-			 * our TSF only to have us clear it
-			 * immediately thereafter.
-			 */
-			ath9k_hw_reset_tsf(sc->sc_ah);
-
-			/* Disable BMISS interrupt when we're not associated */
-			ath9k_hw_set_interrupts(sc->sc_ah,
-					sc->sc_imask &
-					~(ATH9K_INT_SWBA | ATH9K_INT_BMISS));
-			sc->sc_imask &= ~(ATH9K_INT_SWBA | ATH9K_INT_BMISS);
-
-			DPRINTF(sc, ATH_DBG_CONFIG,
-				"%s: RX filter 0x%x bssid %s aid 0x%x\n",
-				__func__, rfilt,
-				print_mac(mac, sc->sc_curbssid), sc->sc_curaid);
-
-			/* need to reconfigure the beacon */
-			sc->sc_beacons = 0;
-
-			break;
-		default:
-			break;
-		}
-	}
-
-	if ((conf->changed & IEEE80211_IFCC_BEACON) &&
-	    (vif->type == IEEE80211_IF_TYPE_IBSS)) {
-		/*
-		 * Allocate and setup the beacon frame.
-		 *
-		 * Stop any previous beacon DMA.  This may be
-		 * necessary, for example, when an ibss merge
-		 * causes reconfiguration; we may be called
-		 * with beacon transmission active.
-		 */
-		ath9k_hw_stoptxdma(sc->sc_ah, sc->sc_bhalq);
-
-		error = ath_beacon_alloc(sc, 0);
-		if (error != 0)
-			return error;
-
-		ath_beacon_sync(sc, 0);
-	}
-
-	/* Check for WLAN_CAPABILITY_PRIVACY ? */
-	if ((avp->av_opmode != IEEE80211_IF_TYPE_STA)) {
-		for (i = 0; i < IEEE80211_WEP_NKID; i++)
-			if (ath9k_hw_keyisvalid(sc->sc_ah, (u16)i))
-				ath9k_hw_keysetmac(sc->sc_ah,
-						   (u16)i,
-						   sc->sc_curbssid);
-	}
-
-	/* Only legacy IBSS for now */
-	if (vif->type == IEEE80211_IF_TYPE_IBSS)
-		ath_update_chainmask(sc, 0);
-
-	return 0;
-}
-
-#define SUPPORTED_FILTERS			\
-	(FIF_PROMISC_IN_BSS |			\
-	FIF_ALLMULTI |				\
-	FIF_CONTROL |				\
-	FIF_OTHER_BSS |				\
-	FIF_BCN_PRBRESP_PROMISC |		\
-	FIF_FCSFAIL)
-
-/* Accept unicast, bcast and mcast frames */
-
-static void ath9k_configure_filter(struct ieee80211_hw *hw,
-				   unsigned int changed_flags,
-				   unsigned int *total_flags,
-				   int mc_count,
-				   struct dev_mc_list *mclist)
-{
-	struct ath_softc *sc = hw->priv;
-
-	changed_flags &= SUPPORTED_FILTERS;
-	*total_flags &= SUPPORTED_FILTERS;
-
-	if (changed_flags & FIF_BCN_PRBRESP_PROMISC) {
-		if (*total_flags & FIF_BCN_PRBRESP_PROMISC)
-			ath_scan_start(sc);
-		else
-			ath_scan_end(sc);
-	}
-}
-
-static void ath9k_sta_notify(struct ieee80211_hw *hw,
-			     struct ieee80211_vif *vif,
-			     enum sta_notify_cmd cmd,
-			     const u8 *addr)
-{
-	struct ath_softc *sc = hw->priv;
-	struct ath_node *an;
-	unsigned long flags;
-	DECLARE_MAC_BUF(mac);
-
-	spin_lock_irqsave(&sc->node_lock, flags);
-	an = ath_node_find(sc, (u8 *) addr);
-	spin_unlock_irqrestore(&sc->node_lock, flags);
-
-	switch (cmd) {
-	case STA_NOTIFY_ADD:
-		spin_lock_irqsave(&sc->node_lock, flags);
-		if (!an) {
-			ath_node_attach(sc, (u8 *)addr, 0);
-			DPRINTF(sc, ATH_DBG_CONFIG, "%s: Attach a node: %s\n",
-				__func__,
-				print_mac(mac, addr));
-		} else {
-			ath_node_get(sc, (u8 *)addr);
-		}
-		spin_unlock_irqrestore(&sc->node_lock, flags);
-		break;
-	case STA_NOTIFY_REMOVE:
-		if (!an)
-			DPRINTF(sc, ATH_DBG_FATAL,
-				"%s: Removal of a non-existent node\n",
-				__func__);
-		else {
-			ath_node_put(sc, an, ATH9K_BH_STATUS_INTACT);
-			DPRINTF(sc, ATH_DBG_CONFIG, "%s: Put a node: %s\n",
-				__func__,
-				print_mac(mac, addr));
-		}
-		break;
-	default:
-		break;
-	}
-}
-
-static int ath9k_conf_tx(struct ieee80211_hw *hw,
-			 u16 queue,
-			 const struct ieee80211_tx_queue_params *params)
-{
-	struct ath_softc *sc = hw->priv;
-	struct ath9k_tx_queue_info qi;
-	int ret = 0, qnum;
-
-	if (queue >= WME_NUM_AC)
-		return 0;
-
-	qi.tqi_aifs = params->aifs;
-	qi.tqi_cwmin = params->cw_min;
-	qi.tqi_cwmax = params->cw_max;
-	qi.tqi_burstTime = params->txop;
-	qnum = ath_get_hal_qnum(queue, sc);
-
-	DPRINTF(sc, ATH_DBG_CONFIG,
-		"%s: Configure tx [queue/halq] [%d/%d],  "
-		"aifs: %d, cw_min: %d, cw_max: %d, txop: %d\n",
-		__func__,
-		queue,
-		qnum,
-		params->aifs,
-		params->cw_min,
-		params->cw_max,
-		params->txop);
-
-	ret = ath_txq_update(sc, qnum, &qi);
-	if (ret)
-		DPRINTF(sc, ATH_DBG_FATAL,
-			"%s: TXQ Update failed\n", __func__);
-
-	return ret;
-}
-
-static int ath9k_set_key(struct ieee80211_hw *hw,
-			 enum set_key_cmd cmd,
-			 const u8 *local_addr,
-			 const u8 *addr,
-			 struct ieee80211_key_conf *key)
-{
-	struct ath_softc *sc = hw->priv;
-	int ret = 0;
-
-	DPRINTF(sc, ATH_DBG_KEYCACHE, " %s: Set HW Key\n", __func__);
-
-	switch (cmd) {
-	case SET_KEY:
-		ret = ath_key_config(sc, addr, key);
-		if (!ret) {
-			set_bit(key->keyidx, sc->sc_keymap);
-			key->hw_key_idx = key->keyidx;
-			/* push IV and Michael MIC generation to stack */
-			key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
-			if (key->alg == ALG_TKIP)
-				key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC;
-		}
-		break;
-	case DISABLE_KEY:
-		ath_key_delete(sc, key);
-		clear_bit(key->keyidx, sc->sc_keymap);
-		sc->sc_keytype = ATH9K_CIPHER_CLR;
-		break;
-	default:
-		ret = -EINVAL;
-	}
-
-	return ret;
-}
-
 static void ath9k_ht_conf(struct ath_softc *sc,
 			  struct ieee80211_bss_conf *bss_conf)
 {
@@ -847,7 +385,7 @@
 
 		/* Configure the beacon */
 		ath_beacon_config(sc, 0);
-		sc->sc_beacons = 1;
+		sc->sc_flags |= SC_OP_BEACONS;
 
 		/* Reset rssi stats */
 		sc->sc_halstats.ns_avgbrssi = ATH_RSSI_DUMMY_MARKER;
@@ -891,6 +429,11 @@
 		ath_rate_newstate(sc, avp);
 		/* Update ratectrl about the new state */
 		ath_rc_node_update(hw, avp->rc_node);
+
+		/* Start ANI */
+		mod_timer(&sc->sc_ani.timer,
+			jiffies + msecs_to_jiffies(ATH_ANI_POLLINTERVAL));
+
 	} else {
 		DPRINTF(sc, ATH_DBG_CONFIG,
 		"%s: Bss Info DISSOC\n", __func__);
@@ -898,145 +441,6 @@
 	}
 }
 
-static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
-				   struct ieee80211_vif *vif,
-				   struct ieee80211_bss_conf *bss_conf,
-				   u32 changed)
-{
-	struct ath_softc *sc = hw->priv;
-
-	if (changed & BSS_CHANGED_ERP_PREAMBLE) {
-		DPRINTF(sc, ATH_DBG_CONFIG, "%s: BSS Changed PREAMBLE %d\n",
-			__func__,
-			bss_conf->use_short_preamble);
-		if (bss_conf->use_short_preamble)
-			sc->sc_flags |= ATH_PREAMBLE_SHORT;
-		else
-			sc->sc_flags &= ~ATH_PREAMBLE_SHORT;
-	}
-
-	if (changed & BSS_CHANGED_ERP_CTS_PROT) {
-		DPRINTF(sc, ATH_DBG_CONFIG, "%s: BSS Changed CTS PROT %d\n",
-			__func__,
-			bss_conf->use_cts_prot);
-		if (bss_conf->use_cts_prot &&
-		    hw->conf.channel->band != IEEE80211_BAND_5GHZ)
-			sc->sc_flags |= ATH_PROTECT_ENABLE;
-		else
-			sc->sc_flags &= ~ATH_PROTECT_ENABLE;
-	}
-
-	if (changed & BSS_CHANGED_HT) {
-		DPRINTF(sc, ATH_DBG_CONFIG, "%s: BSS Changed HT %d\n",
-			__func__,
-			bss_conf->assoc_ht);
-		ath9k_ht_conf(sc, bss_conf);
-	}
-
-	if (changed & BSS_CHANGED_ASSOC) {
-		DPRINTF(sc, ATH_DBG_CONFIG, "%s: BSS Changed ASSOC %d\n",
-			__func__,
-			bss_conf->assoc);
-		ath9k_bss_assoc_info(sc, bss_conf);
-	}
-}
-
-static u64 ath9k_get_tsf(struct ieee80211_hw *hw)
-{
-	u64 tsf;
-	struct ath_softc *sc = hw->priv;
-	struct ath_hal *ah = sc->sc_ah;
-
-	tsf = ath9k_hw_gettsf64(ah);
-
-	return tsf;
-}
-
-static void ath9k_reset_tsf(struct ieee80211_hw *hw)
-{
-	struct ath_softc *sc = hw->priv;
-	struct ath_hal *ah = sc->sc_ah;
-
-	ath9k_hw_reset_tsf(ah);
-}
-
-static int ath9k_ampdu_action(struct ieee80211_hw *hw,
-		       enum ieee80211_ampdu_mlme_action action,
-		       const u8 *addr,
-		       u16 tid,
-		       u16 *ssn)
-{
-	struct ath_softc *sc = hw->priv;
-	int ret = 0;
-
-	switch (action) {
-	case IEEE80211_AMPDU_RX_START:
-		ret = ath_rx_aggr_start(sc, addr, tid, ssn);
-		if (ret < 0)
-			DPRINTF(sc, ATH_DBG_FATAL,
-				"%s: Unable to start RX aggregation\n",
-				__func__);
-		break;
-	case IEEE80211_AMPDU_RX_STOP:
-		ret = ath_rx_aggr_stop(sc, addr, tid);
-		if (ret < 0)
-			DPRINTF(sc, ATH_DBG_FATAL,
-				"%s: Unable to stop RX aggregation\n",
-				__func__);
-		break;
-	case IEEE80211_AMPDU_TX_START:
-		ret = ath_tx_aggr_start(sc, addr, tid, ssn);
-		if (ret < 0)
-			DPRINTF(sc, ATH_DBG_FATAL,
-				"%s: Unable to start TX aggregation\n",
-				__func__);
-		else
-			ieee80211_start_tx_ba_cb_irqsafe(hw, (u8 *)addr, tid);
-		break;
-	case IEEE80211_AMPDU_TX_STOP:
-		ret = ath_tx_aggr_stop(sc, addr, tid);
-		if (ret < 0)
-			DPRINTF(sc, ATH_DBG_FATAL,
-				"%s: Unable to stop TX aggregation\n",
-				__func__);
-
-		ieee80211_stop_tx_ba_cb_irqsafe(hw, (u8 *)addr, tid);
-		break;
-	default:
-		DPRINTF(sc, ATH_DBG_FATAL,
-			"%s: Unknown AMPDU action\n", __func__);
-	}
-
-	return ret;
-}
-
-static struct ieee80211_ops ath9k_ops = {
-	.tx 		    = ath9k_tx,
-	.start 		    = ath9k_start,
-	.stop 		    = ath9k_stop,
-	.add_interface 	    = ath9k_add_interface,
-	.remove_interface   = ath9k_remove_interface,
-	.config 	    = ath9k_config,
-	.config_interface   = ath9k_config_interface,
-	.configure_filter   = ath9k_configure_filter,
-	.get_stats          = NULL,
-	.sta_notify         = ath9k_sta_notify,
-	.conf_tx 	    = ath9k_conf_tx,
-	.get_tx_stats 	    = NULL,
-	.bss_info_changed   = ath9k_bss_info_changed,
-	.set_tim            = NULL,
-	.set_key            = ath9k_set_key,
-	.hw_scan            = NULL,
-	.get_tkip_seq       = NULL,
-	.set_rts_threshold  = NULL,
-	.set_frag_threshold = NULL,
-	.set_retry_limit    = NULL,
-	.get_tsf 	    = ath9k_get_tsf,
-	.reset_tsf 	    = ath9k_reset_tsf,
-	.tx_last_beacon     = NULL,
-	.ampdu_action       = ath9k_ampdu_action
-};
-
 void ath_get_beaconconfig(struct ath_softc *sc,
 			  int if_id,
 			  struct ath_beacon_config *conf)
@@ -1051,15 +455,6 @@
 	conf->bmiss_timeout = ATH_DEFAULT_BMISS_LIMIT * conf->listen_interval;
 }
 
-int ath_update_beacon(struct ath_softc *sc,
-		      int if_id,
-		      struct ath_beacon_offset *bo,
-		      struct sk_buff *skb,
-		      int mcast)
-{
-	return 0;
-}
-
 void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
 		     struct ath_xmit_status *tx_status, struct ath_node *an)
 {
@@ -1099,7 +494,7 @@
 		ath_node_put(sc, an, ATH9K_BH_STATUS_CHANGE);
 }
 
-int ath__rx_indicate(struct ath_softc *sc,
+int _ath_rx_indicate(struct ath_softc *sc,
 		     struct sk_buff *skb,
 		     struct ath_recv_status *status,
 		     u16 keyix)
@@ -1119,9 +514,6 @@
 		skb_pull(skb, padsize);
 	}
 
-	/* remove FCS before passing up to protocol stack */
-	skb_trim(skb, (skb->len - FCS_LEN));
-
 	/* Prepare rx status */
 	ath9k_rx_prepare(sc, skb, status, &rx_status);
 
@@ -1170,17 +562,338 @@
 	return 0;
 }
 
-enum ath9k_ht_macmode ath_cwm_macmode(struct ath_softc *sc)
+/********************************/
+/*	 LED functions		*/
+/********************************/
+
+static void ath_led_brightness(struct led_classdev *led_cdev,
+			       enum led_brightness brightness)
 {
-	return sc->sc_ht_info.tx_chan_width;
+	struct ath_led *led = container_of(led_cdev, struct ath_led, led_cdev);
+	struct ath_softc *sc = led->sc;
+
+	switch (brightness) {
+	case LED_OFF:
+		if (led->led_type == ATH_LED_ASSOC ||
+		    led->led_type == ATH_LED_RADIO)
+			sc->sc_flags &= ~SC_OP_LED_ASSOCIATED;
+		ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN,
+				(led->led_type == ATH_LED_RADIO) ? 1 :
+				!!(sc->sc_flags & SC_OP_LED_ASSOCIATED));
+		break;
+	case LED_FULL:
+		if (led->led_type == ATH_LED_ASSOC)
+			sc->sc_flags |= SC_OP_LED_ASSOCIATED;
+		ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 0);
+		break;
+	default:
+		break;
+	}
 }
 
+static int ath_register_led(struct ath_softc *sc, struct ath_led *led,
+			    char *trigger)
+{
+	int ret;
+
+	led->sc = sc;
+	led->led_cdev.name = led->name;
+	led->led_cdev.default_trigger = trigger;
+	led->led_cdev.brightness_set = ath_led_brightness;
+
+	ret = led_classdev_register(wiphy_dev(sc->hw->wiphy), &led->led_cdev);
+	if (ret)
+		DPRINTF(sc, ATH_DBG_FATAL,
+			"Failed to register led:%s", led->name);
+	else
+		led->registered = 1;
+	return ret;
+}
+
+static void ath_unregister_led(struct ath_led *led)
+{
+	if (led->registered) {
+		led_classdev_unregister(&led->led_cdev);
+		led->registered = 0;
+	}
+}
+
+static void ath_deinit_leds(struct ath_softc *sc)
+{
+	ath_unregister_led(&sc->assoc_led);
+	sc->sc_flags &= ~SC_OP_LED_ASSOCIATED;
+	ath_unregister_led(&sc->tx_led);
+	ath_unregister_led(&sc->rx_led);
+	ath_unregister_led(&sc->radio_led);
+	ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1);
+}
+
+static void ath_init_leds(struct ath_softc *sc)
+{
+	char *trigger;
+	int ret;
+
+	/* Configure gpio 1 for output */
+	ath9k_hw_cfg_output(sc->sc_ah, ATH_LED_PIN,
+			    AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
+	/* LED off, active low */
+	ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1);
+
+	trigger = ieee80211_get_radio_led_name(sc->hw);
+	snprintf(sc->radio_led.name, sizeof(sc->radio_led.name),
+		"ath9k-%s:radio", wiphy_name(sc->hw->wiphy));
+	ret = ath_register_led(sc, &sc->radio_led, trigger);
+	sc->radio_led.led_type = ATH_LED_RADIO;
+	if (ret)
+		goto fail;
+
+	trigger = ieee80211_get_assoc_led_name(sc->hw);
+	snprintf(sc->assoc_led.name, sizeof(sc->assoc_led.name),
+		"ath9k-%s:assoc", wiphy_name(sc->hw->wiphy));
+	ret = ath_register_led(sc, &sc->assoc_led, trigger);
+	sc->assoc_led.led_type = ATH_LED_ASSOC;
+	if (ret)
+		goto fail;
+
+	trigger = ieee80211_get_tx_led_name(sc->hw);
+	snprintf(sc->tx_led.name, sizeof(sc->tx_led.name),
+		"ath9k-%s:tx", wiphy_name(sc->hw->wiphy));
+	ret = ath_register_led(sc, &sc->tx_led, trigger);
+	sc->tx_led.led_type = ATH_LED_TX;
+	if (ret)
+		goto fail;
+
+	trigger = ieee80211_get_rx_led_name(sc->hw);
+	snprintf(sc->rx_led.name, sizeof(sc->rx_led.name),
+		"ath9k-%s:rx", wiphy_name(sc->hw->wiphy));
+	ret = ath_register_led(sc, &sc->rx_led, trigger);
+	sc->rx_led.led_type = ATH_LED_RX;
+	if (ret)
+		goto fail;
+
+	return;
+
+fail:
+	ath_deinit_leds(sc);
+}
+
+#ifdef CONFIG_RFKILL
+/*******************/
+/*	Rfkill	   */
+/*******************/
+
+static void ath_radio_enable(struct ath_softc *sc)
+{
+	struct ath_hal *ah = sc->sc_ah;
+	int status;
+
+	spin_lock_bh(&sc->sc_resetlock);
+	if (!ath9k_hw_reset(ah, ah->ah_curchan,
+			    sc->sc_ht_info.tx_chan_width,
+			    sc->sc_tx_chainmask,
+			    sc->sc_rx_chainmask,
+			    sc->sc_ht_extprotspacing,
+			    false, &status)) {
+		DPRINTF(sc, ATH_DBG_FATAL,
+			"%s: unable to reset channel %u (%uMhz) "
+			"flags 0x%x hal status %u\n", __func__,
+			ath9k_hw_mhz2ieee(ah,
+					  ah->ah_curchan->channel,
+					  ah->ah_curchan->channelFlags),
+			ah->ah_curchan->channel,
+			ah->ah_curchan->channelFlags, status);
+	}
+	spin_unlock_bh(&sc->sc_resetlock);
+
+	ath_update_txpow(sc);
+	if (ath_startrecv(sc) != 0) {
+		DPRINTF(sc, ATH_DBG_FATAL,
+			"%s: unable to restart recv logic\n", __func__);
+		return;
+	}
+
+	if (sc->sc_flags & SC_OP_BEACONS)
+		ath_beacon_config(sc, ATH_IF_ID_ANY);	/* restart beacons */
+
+	/* Re-Enable  interrupts */
+	ath9k_hw_set_interrupts(ah, sc->sc_imask);
+
+	/* Enable LED */
+	ath9k_hw_cfg_output(ah, ATH_LED_PIN,
+			    AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
+	ath9k_hw_set_gpio(ah, ATH_LED_PIN, 0);
+
+	ieee80211_wake_queues(sc->hw);
+}
+
+static void ath_radio_disable(struct ath_softc *sc)
+{
+	struct ath_hal *ah = sc->sc_ah;
+	int status;
+
+
+	ieee80211_stop_queues(sc->hw);
+
+	/* Disable LED */
+	ath9k_hw_set_gpio(ah, ATH_LED_PIN, 1);
+	ath9k_hw_cfg_gpio_input(ah, ATH_LED_PIN);
+
+	/* Disable interrupts */
+	ath9k_hw_set_interrupts(ah, 0);
+
+	ath_draintxq(sc, false);	/* clear pending tx frames */
+	ath_stoprecv(sc);		/* turn off frame recv */
+	ath_flushrecv(sc);		/* flush recv queue */
+
+	spin_lock_bh(&sc->sc_resetlock);
+	if (!ath9k_hw_reset(ah, ah->ah_curchan,
+			    sc->sc_ht_info.tx_chan_width,
+			    sc->sc_tx_chainmask,
+			    sc->sc_rx_chainmask,
+			    sc->sc_ht_extprotspacing,
+			    false, &status)) {
+		DPRINTF(sc, ATH_DBG_FATAL,
+			"%s: unable to reset channel %u (%uMhz) "
+			"flags 0x%x hal status %u\n", __func__,
+			ath9k_hw_mhz2ieee(ah,
+				ah->ah_curchan->channel,
+				ah->ah_curchan->channelFlags),
+			ah->ah_curchan->channel,
+			ah->ah_curchan->channelFlags, status);
+	}
+	spin_unlock_bh(&sc->sc_resetlock);
+
+	ath9k_hw_phy_disable(ah);
+	ath9k_hw_setpower(ah, ATH9K_PM_FULL_SLEEP);
+}
+
+static bool ath_is_rfkill_set(struct ath_softc *sc)
+{
+	struct ath_hal *ah = sc->sc_ah;
+
+	return ath9k_hw_gpio_get(ah, ah->ah_rfkill_gpio) ==
+				  ah->ah_rfkill_polarity;
+}
+
+/* h/w rfkill poll function */
+static void ath_rfkill_poll(struct work_struct *work)
+{
+	struct ath_softc *sc = container_of(work, struct ath_softc,
+					    rf_kill.rfkill_poll.work);
+	bool radio_on;
+
+	if (sc->sc_flags & SC_OP_INVALID)
+		return;
+
+	radio_on = !ath_is_rfkill_set(sc);
+
+	/*
+	 * enable/disable radio only when there is a
+	 * state change in RF switch
+	 */
+	if (radio_on == !!(sc->sc_flags & SC_OP_RFKILL_HW_BLOCKED)) {
+		enum rfkill_state state;
+
+		if (sc->sc_flags & SC_OP_RFKILL_SW_BLOCKED) {
+			state = radio_on ? RFKILL_STATE_SOFT_BLOCKED
+				: RFKILL_STATE_HARD_BLOCKED;
+		} else if (radio_on) {
+			ath_radio_enable(sc);
+			state = RFKILL_STATE_UNBLOCKED;
+		} else {
+			ath_radio_disable(sc);
+			state = RFKILL_STATE_HARD_BLOCKED;
+		}
+
+		if (state == RFKILL_STATE_HARD_BLOCKED)
+			sc->sc_flags |= SC_OP_RFKILL_HW_BLOCKED;
+		else
+			sc->sc_flags &= ~SC_OP_RFKILL_HW_BLOCKED;
+
+		rfkill_force_state(sc->rf_kill.rfkill, state);
+	}
+
+	queue_delayed_work(sc->hw->workqueue, &sc->rf_kill.rfkill_poll,
+			   msecs_to_jiffies(ATH_RFKILL_POLL_INTERVAL));
+}
+
+/* s/w rfkill handler */
+static int ath_sw_toggle_radio(void *data, enum rfkill_state state)
+{
+	struct ath_softc *sc = data;
+
+	switch (state) {
+	case RFKILL_STATE_SOFT_BLOCKED:
+		if (!(sc->sc_flags & (SC_OP_RFKILL_HW_BLOCKED |
+		    SC_OP_RFKILL_SW_BLOCKED)))
+			ath_radio_disable(sc);
+		sc->sc_flags |= SC_OP_RFKILL_SW_BLOCKED;
+		return 0;
+	case RFKILL_STATE_UNBLOCKED:
+		if ((sc->sc_flags & SC_OP_RFKILL_SW_BLOCKED)) {
+			sc->sc_flags &= ~SC_OP_RFKILL_SW_BLOCKED;
+			if (sc->sc_flags & SC_OP_RFKILL_HW_BLOCKED) {
+				DPRINTF(sc, ATH_DBG_FATAL, "Can't turn on the"
+					"radio as it is disabled by h/w \n");
+				return -EPERM;
+			}
+			ath_radio_enable(sc);
+		}
+		return 0;
+	default:
+		return -EINVAL;
+	}
+}
+
+/* Init s/w rfkill */
+static int ath_init_sw_rfkill(struct ath_softc *sc)
+{
+	sc->rf_kill.rfkill = rfkill_allocate(wiphy_dev(sc->hw->wiphy),
+					     RFKILL_TYPE_WLAN);
+	if (!sc->rf_kill.rfkill) {
+		DPRINTF(sc, ATH_DBG_FATAL, "Failed to allocate rfkill\n");
+		return -ENOMEM;
+	}
+
+	snprintf(sc->rf_kill.rfkill_name, sizeof(sc->rf_kill.rfkill_name),
+		"ath9k-%s:rfkill", wiphy_name(sc->hw->wiphy));
+	sc->rf_kill.rfkill->name = sc->rf_kill.rfkill_name;
+	sc->rf_kill.rfkill->data = sc;
+	sc->rf_kill.rfkill->toggle_radio = ath_sw_toggle_radio;
+	sc->rf_kill.rfkill->state = RFKILL_STATE_UNBLOCKED;
+	sc->rf_kill.rfkill->user_claim_unsupported = 1;
+
+	return 0;
+}
+
+/* Deinitialize rfkill */
+static void ath_deinit_rfkill(struct ath_softc *sc)
+{
+	if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
+		cancel_delayed_work_sync(&sc->rf_kill.rfkill_poll);
+
+	if (sc->sc_flags & SC_OP_RFKILL_REGISTERED) {
+		rfkill_unregister(sc->rf_kill.rfkill);
+		sc->sc_flags &= ~SC_OP_RFKILL_REGISTERED;
+		sc->rf_kill.rfkill = NULL;
+	}
+}
+#endif /* CONFIG_RFKILL */
+
 static int ath_detach(struct ath_softc *sc)
 {
 	struct ieee80211_hw *hw = sc->hw;
 
 	DPRINTF(sc, ATH_DBG_CONFIG, "%s: Detach ATH hw\n", __func__);
 
+	/* Deinit LED control */
+	ath_deinit_leds(sc);
+
+#ifdef CONFIG_RFKILL
+	/* deinit rfkill */
+	ath_deinit_rfkill(sc);
+#endif
+
 	/* Unregister hw */
 
 	ieee80211_unregister_hw(hw);
@@ -1274,23 +987,686 @@
 		goto bad;
 	}
 
+	/* Initialize LED control */
+	ath_init_leds(sc);
+
+#ifdef CONFIG_RFKILL
+	/* Initialze h/w Rfkill */
+	if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
+		INIT_DELAYED_WORK(&sc->rf_kill.rfkill_poll, ath_rfkill_poll);
+
+	/* Initialize s/w rfkill */
+	if (ath_init_sw_rfkill(sc))
+		goto detach;
+#endif
+
 	/* initialize tx/rx engine */
 
 	error = ath_tx_init(sc, ATH_TXBUF);
 	if (error != 0)
-		goto bad1;
+		goto detach;
 
 	error = ath_rx_init(sc, ATH_RXBUF);
 	if (error != 0)
-		goto bad1;
+		goto detach;
 
 	return 0;
-bad1:
+detach:
 	ath_detach(sc);
 bad:
 	return error;
 }
 
+static int ath9k_start(struct ieee80211_hw *hw)
+{
+	struct ath_softc *sc = hw->priv;
+	struct ieee80211_channel *curchan = hw->conf.channel;
+	int error = 0, pos;
+
+	DPRINTF(sc, ATH_DBG_CONFIG, "%s: Starting driver with "
+		"initial channel: %d MHz\n", __func__, curchan->center_freq);
+
+	/* setup initial channel */
+
+	pos = ath_get_channel(sc, curchan);
+	if (pos == -1) {
+		DPRINTF(sc, ATH_DBG_FATAL, "%s: Invalid channel\n", __func__);
+		return -EINVAL;
+	}
+
+	sc->sc_ah->ah_channels[pos].chanmode =
+		(curchan->band == IEEE80211_BAND_2GHZ) ? CHANNEL_G : CHANNEL_A;
+
+	/* open ath_dev */
+	error = ath_open(sc, &sc->sc_ah->ah_channels[pos]);
+	if (error) {
+		DPRINTF(sc, ATH_DBG_FATAL,
+			"%s: Unable to complete ath_open\n", __func__);
+		return error;
+	}
+
+#ifdef CONFIG_RFKILL
+	/* Start rfkill polling */
+	if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
+		queue_delayed_work(sc->hw->workqueue,
+				   &sc->rf_kill.rfkill_poll, 0);
+
+	if (!(sc->sc_flags & SC_OP_RFKILL_REGISTERED)) {
+		if (rfkill_register(sc->rf_kill.rfkill)) {
+			DPRINTF(sc, ATH_DBG_FATAL,
+					"Unable to register rfkill\n");
+			rfkill_free(sc->rf_kill.rfkill);
+
+			/* Deinitialize the device */
+			if (sc->pdev->irq)
+				free_irq(sc->pdev->irq, sc);
+			ath_detach(sc);
+			pci_iounmap(sc->pdev, sc->mem);
+			pci_release_region(sc->pdev, 0);
+			pci_disable_device(sc->pdev);
+			ieee80211_free_hw(hw);
+			return -EIO;
+		} else {
+			sc->sc_flags |= SC_OP_RFKILL_REGISTERED;
+		}
+	}
+#endif
+
+	ieee80211_wake_queues(hw);
+	return 0;
+}
+
+static int ath9k_tx(struct ieee80211_hw *hw,
+		    struct sk_buff *skb)
+{
+	struct ath_softc *sc = hw->priv;
+	int hdrlen, padsize;
+	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+
+	/*
+	 * As a temporary workaround, assign seq# here; this will likely need
+	 * to be cleaned up to work better with Beacon transmission and virtual
+	 * BSSes.
+	 */
+	if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) {
+		struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+		if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT)
+			sc->seq_no += 0x10;
+		hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG);
+		hdr->seq_ctrl |= cpu_to_le16(sc->seq_no);
+	}
+
+	/* Add the padding after the header if this is not already done */
+	hdrlen = ieee80211_get_hdrlen_from_skb(skb);
+	if (hdrlen & 3) {
+		padsize = hdrlen % 4;
+		if (skb_headroom(skb) < padsize)
+			return -1;
+		skb_push(skb, padsize);
+		memmove(skb->data, skb->data + padsize, hdrlen);
+	}
+
+	DPRINTF(sc, ATH_DBG_XMIT, "%s: transmitting packet, skb: %p\n",
+		__func__,
+		skb);
+
+	if (ath_tx_start(sc, skb) != 0) {
+		DPRINTF(sc, ATH_DBG_XMIT, "%s: TX failed\n", __func__);
+		dev_kfree_skb_any(skb);
+		/* FIXME: Check for proper return value from ATH_DEV */
+		return 0;
+	}
+
+	return 0;
+}
+
+static void ath9k_stop(struct ieee80211_hw *hw)
+{
+	struct ath_softc *sc = hw->priv;
+	int error;
+
+	DPRINTF(sc, ATH_DBG_CONFIG, "%s: Driver halt\n", __func__);
+
+	error = ath_suspend(sc);
+	if (error)
+		DPRINTF(sc, ATH_DBG_CONFIG,
+			"%s: Device is no longer present\n", __func__);
+
+	ieee80211_stop_queues(hw);
+
+#ifdef CONFIG_RFKILL
+	if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
+		cancel_delayed_work_sync(&sc->rf_kill.rfkill_poll);
+#endif
+}
+
+static int ath9k_add_interface(struct ieee80211_hw *hw,
+			       struct ieee80211_if_init_conf *conf)
+{
+	struct ath_softc *sc = hw->priv;
+	int error, ic_opmode = 0;
+
+	/* Support only vap for now */
+
+	if (sc->sc_nvaps)
+		return -ENOBUFS;
+
+	switch (conf->type) {
+	case NL80211_IFTYPE_STATION:
+		ic_opmode = ATH9K_M_STA;
+		break;
+	case NL80211_IFTYPE_ADHOC:
+		ic_opmode = ATH9K_M_IBSS;
+		break;
+	case NL80211_IFTYPE_AP:
+		ic_opmode = ATH9K_M_HOSTAP;
+		break;
+	default:
+		DPRINTF(sc, ATH_DBG_FATAL,
+			"%s: Interface type %d not yet supported\n",
+			__func__, conf->type);
+		return -EOPNOTSUPP;
+	}
+
+	DPRINTF(sc, ATH_DBG_CONFIG, "%s: Attach a VAP of type: %d\n",
+		__func__,
+		ic_opmode);
+
+	error = ath_vap_attach(sc, 0, conf->vif, ic_opmode);
+	if (error) {
+		DPRINTF(sc, ATH_DBG_FATAL,
+			"%s: Unable to attach vap, error: %d\n",
+			__func__, error);
+		return error;
+	}
+
+	if (conf->type == NL80211_IFTYPE_AP) {
+		/* TODO: is this a suitable place to start ANI for AP mode? */
+		/* Start ANI */
+		mod_timer(&sc->sc_ani.timer,
+			  jiffies + msecs_to_jiffies(ATH_ANI_POLLINTERVAL));
+	}
+
+	return 0;
+}
+
+static void ath9k_remove_interface(struct ieee80211_hw *hw,
+				   struct ieee80211_if_init_conf *conf)
+{
+	struct ath_softc *sc = hw->priv;
+	struct ath_vap *avp;
+	int error;
+
+	DPRINTF(sc, ATH_DBG_CONFIG, "%s: Detach VAP\n", __func__);
+
+	avp = sc->sc_vaps[0];
+	if (avp == NULL) {
+		DPRINTF(sc, ATH_DBG_FATAL, "%s: Invalid interface\n",
+			__func__);
+		return;
+	}
+
+#ifdef CONFIG_SLOW_ANT_DIV
+	ath_slow_ant_div_stop(&sc->sc_antdiv);
+#endif
+	/* Stop ANI */
+	del_timer_sync(&sc->sc_ani.timer);
+
+	/* Update ratectrl */
+	ath_rate_newstate(sc, avp);
+
+	/* Reclaim beacon resources */
+	if (sc->sc_ah->ah_opmode == ATH9K_M_HOSTAP ||
+	    sc->sc_ah->ah_opmode == ATH9K_M_IBSS) {
+		ath9k_hw_stoptxdma(sc->sc_ah, sc->sc_bhalq);
+		ath_beacon_return(sc, avp);
+	}
+
+	/* Set interrupt mask */
+	sc->sc_imask &= ~(ATH9K_INT_SWBA | ATH9K_INT_BMISS);
+	ath9k_hw_set_interrupts(sc->sc_ah, sc->sc_imask & ~ATH9K_INT_GLOBAL);
+	sc->sc_flags &= ~SC_OP_BEACONS;
+
+	error = ath_vap_detach(sc, 0);
+	if (error)
+		DPRINTF(sc, ATH_DBG_FATAL,
+			"%s: Unable to detach vap, error: %d\n",
+			__func__, error);
+}
+
+static int ath9k_config(struct ieee80211_hw *hw,
+			struct ieee80211_conf *conf)
+{
+	struct ath_softc *sc = hw->priv;
+	struct ieee80211_channel *curchan = hw->conf.channel;
+	int pos;
+
+	DPRINTF(sc, ATH_DBG_CONFIG, "%s: Set channel: %d MHz\n",
+		__func__,
+		curchan->center_freq);
+
+	pos = ath_get_channel(sc, curchan);
+	if (pos == -1) {
+		DPRINTF(sc, ATH_DBG_FATAL, "%s: Invalid channel\n", __func__);
+		return -EINVAL;
+	}
+
+	sc->sc_ah->ah_channels[pos].chanmode =
+		(curchan->band == IEEE80211_BAND_2GHZ) ?
+		CHANNEL_G : CHANNEL_A;
+
+	if (sc->sc_curaid && hw->conf.ht_conf.ht_supported)
+		sc->sc_ah->ah_channels[pos].chanmode =
+			ath_get_extchanmode(sc, curchan);
+
+	sc->sc_config.txpowlimit = 2 * conf->power_level;
+
+	/* set h/w channel */
+	if (ath_set_channel(sc, &sc->sc_ah->ah_channels[pos]) < 0)
+		DPRINTF(sc, ATH_DBG_FATAL, "%s: Unable to set channel\n",
+			__func__);
+
+	return 0;
+}
+
+static int ath9k_config_interface(struct ieee80211_hw *hw,
+				  struct ieee80211_vif *vif,
+				  struct ieee80211_if_conf *conf)
+{
+	struct ath_softc *sc = hw->priv;
+	struct ath_hal *ah = sc->sc_ah;
+	struct ath_vap *avp;
+	u32 rfilt = 0;
+	int error, i;
+	DECLARE_MAC_BUF(mac);
+
+	avp = sc->sc_vaps[0];
+	if (avp == NULL) {
+		DPRINTF(sc, ATH_DBG_FATAL, "%s: Invalid interface\n",
+			__func__);
+		return -EINVAL;
+	}
+
+	/* TODO: Need to decide which hw opmode to use for multi-interface
+	 * cases */
+	if (vif->type == NL80211_IFTYPE_AP &&
+	    ah->ah_opmode != ATH9K_M_HOSTAP) {
+		ah->ah_opmode = ATH9K_M_HOSTAP;
+		ath9k_hw_setopmode(ah);
+		ath9k_hw_write_associd(ah, sc->sc_myaddr, 0);
+		/* Request full reset to get hw opmode changed properly */
+		sc->sc_flags |= SC_OP_FULL_RESET;
+	}
+
+	if ((conf->changed & IEEE80211_IFCC_BSSID) &&
+	    !is_zero_ether_addr(conf->bssid)) {
+		switch (vif->type) {
+		case NL80211_IFTYPE_STATION:
+		case NL80211_IFTYPE_ADHOC:
+			/* Update ratectrl about the new state */
+			ath_rate_newstate(sc, avp);
+
+			/* Set BSSID */
+			memcpy(sc->sc_curbssid, conf->bssid, ETH_ALEN);
+			sc->sc_curaid = 0;
+			ath9k_hw_write_associd(sc->sc_ah, sc->sc_curbssid,
+					       sc->sc_curaid);
+
+			/* Set aggregation protection mode parameters */
+			sc->sc_config.ath_aggr_prot = 0;
+
+			/*
+			 * Reset our TSF so that its value is lower than the
+			 * beacon that we are trying to catch.
+			 * Only then hw will update its TSF register with the
+			 * new beacon. Reset the TSF before setting the BSSID
+			 * to avoid allowing in any frames that would update
+			 * our TSF only to have us clear it
+			 * immediately thereafter.
+			 */
+			ath9k_hw_reset_tsf(sc->sc_ah);
+
+			/* Disable BMISS interrupt when we're not associated */
+			ath9k_hw_set_interrupts(sc->sc_ah,
+					sc->sc_imask &
+					~(ATH9K_INT_SWBA | ATH9K_INT_BMISS));
+			sc->sc_imask &= ~(ATH9K_INT_SWBA | ATH9K_INT_BMISS);
+
+			DPRINTF(sc, ATH_DBG_CONFIG,
+				"%s: RX filter 0x%x bssid %s aid 0x%x\n",
+				__func__, rfilt,
+				print_mac(mac, sc->sc_curbssid), sc->sc_curaid);
+
+			/* need to reconfigure the beacon */
+			sc->sc_flags &= ~SC_OP_BEACONS ;
+
+			break;
+		default:
+			break;
+		}
+	}
+
+	if ((conf->changed & IEEE80211_IFCC_BEACON) &&
+	    ((vif->type == NL80211_IFTYPE_ADHOC) ||
+	     (vif->type == NL80211_IFTYPE_AP))) {
+		/*
+		 * Allocate and setup the beacon frame.
+		 *
+		 * Stop any previous beacon DMA.  This may be
+		 * necessary, for example, when an ibss merge
+		 * causes reconfiguration; we may be called
+		 * with beacon transmission active.
+		 */
+		ath9k_hw_stoptxdma(sc->sc_ah, sc->sc_bhalq);
+
+		error = ath_beacon_alloc(sc, 0);
+		if (error != 0)
+			return error;
+
+		ath_beacon_sync(sc, 0);
+	}
+
+	/* Check for WLAN_CAPABILITY_PRIVACY ? */
+	if ((avp->av_opmode != NL80211_IFTYPE_STATION)) {
+		for (i = 0; i < IEEE80211_WEP_NKID; i++)
+			if (ath9k_hw_keyisvalid(sc->sc_ah, (u16)i))
+				ath9k_hw_keysetmac(sc->sc_ah,
+						   (u16)i,
+						   sc->sc_curbssid);
+	}
+
+	/* Only legacy IBSS for now */
+	if (vif->type == NL80211_IFTYPE_ADHOC)
+		ath_update_chainmask(sc, 0);
+
+	return 0;
+}
+
+#define SUPPORTED_FILTERS			\
+	(FIF_PROMISC_IN_BSS |			\
+	FIF_ALLMULTI |				\
+	FIF_CONTROL |				\
+	FIF_OTHER_BSS |				\
+	FIF_BCN_PRBRESP_PROMISC |		\
+	FIF_FCSFAIL)
+
+/* FIXME: sc->sc_full_reset ? */
+static void ath9k_configure_filter(struct ieee80211_hw *hw,
+				   unsigned int changed_flags,
+				   unsigned int *total_flags,
+				   int mc_count,
+				   struct dev_mc_list *mclist)
+{
+	struct ath_softc *sc = hw->priv;
+	u32 rfilt;
+
+	changed_flags &= SUPPORTED_FILTERS;
+	*total_flags &= SUPPORTED_FILTERS;
+
+	sc->rx_filter = *total_flags;
+	rfilt = ath_calcrxfilter(sc);
+	ath9k_hw_setrxfilter(sc->sc_ah, rfilt);
+
+	if (changed_flags & FIF_BCN_PRBRESP_PROMISC) {
+		if (*total_flags & FIF_BCN_PRBRESP_PROMISC)
+			ath9k_hw_write_associd(sc->sc_ah, ath_bcast_mac, 0);
+	}
+
+	DPRINTF(sc, ATH_DBG_CONFIG, "%s: Set HW RX filter: 0x%x\n",
+		__func__, sc->rx_filter);
+}
+
+static void ath9k_sta_notify(struct ieee80211_hw *hw,
+			     struct ieee80211_vif *vif,
+			     enum sta_notify_cmd cmd,
+			     struct ieee80211_sta *sta)
+{
+	struct ath_softc *sc = hw->priv;
+	struct ath_node *an;
+	unsigned long flags;
+	DECLARE_MAC_BUF(mac);
+
+	spin_lock_irqsave(&sc->node_lock, flags);
+	an = ath_node_find(sc, sta->addr);
+	spin_unlock_irqrestore(&sc->node_lock, flags);
+
+	switch (cmd) {
+	case STA_NOTIFY_ADD:
+		spin_lock_irqsave(&sc->node_lock, flags);
+		if (!an) {
+			ath_node_attach(sc, sta->addr, 0);
+			DPRINTF(sc, ATH_DBG_CONFIG, "%s: Attach a node: %s\n",
+				__func__, print_mac(mac, sta->addr));
+		} else {
+			ath_node_get(sc, sta->addr);
+		}
+		spin_unlock_irqrestore(&sc->node_lock, flags);
+		break;
+	case STA_NOTIFY_REMOVE:
+		if (!an)
+			DPRINTF(sc, ATH_DBG_FATAL,
+				"%s: Removal of a non-existent node\n",
+				__func__);
+		else {
+			ath_node_put(sc, an, ATH9K_BH_STATUS_INTACT);
+			DPRINTF(sc, ATH_DBG_CONFIG, "%s: Put a node: %s\n",
+				__func__,
+				print_mac(mac, sta->addr));
+		}
+		break;
+	default:
+		break;
+	}
+}
+
+static int ath9k_conf_tx(struct ieee80211_hw *hw,
+			 u16 queue,
+			 const struct ieee80211_tx_queue_params *params)
+{
+	struct ath_softc *sc = hw->priv;
+	struct ath9k_tx_queue_info qi;
+	int ret = 0, qnum;
+
+	if (queue >= WME_NUM_AC)
+		return 0;
+
+	qi.tqi_aifs = params->aifs;
+	qi.tqi_cwmin = params->cw_min;
+	qi.tqi_cwmax = params->cw_max;
+	qi.tqi_burstTime = params->txop;
+	qnum = ath_get_hal_qnum(queue, sc);
+
+	DPRINTF(sc, ATH_DBG_CONFIG,
+		"%s: Configure tx [queue/halq] [%d/%d],  "
+		"aifs: %d, cw_min: %d, cw_max: %d, txop: %d\n",
+		__func__,
+		queue,
+		qnum,
+		params->aifs,
+		params->cw_min,
+		params->cw_max,
+		params->txop);
+
+	ret = ath_txq_update(sc, qnum, &qi);
+	if (ret)
+		DPRINTF(sc, ATH_DBG_FATAL,
+			"%s: TXQ Update failed\n", __func__);
+
+	return ret;
+}
+
+static int ath9k_set_key(struct ieee80211_hw *hw,
+			 enum set_key_cmd cmd,
+			 const u8 *local_addr,
+			 const u8 *addr,
+			 struct ieee80211_key_conf *key)
+{
+	struct ath_softc *sc = hw->priv;
+	int ret = 0;
+
+	DPRINTF(sc, ATH_DBG_KEYCACHE, " %s: Set HW Key\n", __func__);
+
+	switch (cmd) {
+	case SET_KEY:
+		ret = ath_key_config(sc, addr, key);
+		if (!ret) {
+			set_bit(key->keyidx, sc->sc_keymap);
+			key->hw_key_idx = key->keyidx;
+			/* push IV and Michael MIC generation to stack */
+			key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
+			if (key->alg == ALG_TKIP)
+				key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC;
+		}
+		break;
+	case DISABLE_KEY:
+		ath_key_delete(sc, key);
+		clear_bit(key->keyidx, sc->sc_keymap);
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
+				   struct ieee80211_vif *vif,
+				   struct ieee80211_bss_conf *bss_conf,
+				   u32 changed)
+{
+	struct ath_softc *sc = hw->priv;
+
+	if (changed & BSS_CHANGED_ERP_PREAMBLE) {
+		DPRINTF(sc, ATH_DBG_CONFIG, "%s: BSS Changed PREAMBLE %d\n",
+			__func__,
+			bss_conf->use_short_preamble);
+		if (bss_conf->use_short_preamble)
+			sc->sc_flags |= SC_OP_PREAMBLE_SHORT;
+		else
+			sc->sc_flags &= ~SC_OP_PREAMBLE_SHORT;
+	}
+
+	if (changed & BSS_CHANGED_ERP_CTS_PROT) {
+		DPRINTF(sc, ATH_DBG_CONFIG, "%s: BSS Changed CTS PROT %d\n",
+			__func__,
+			bss_conf->use_cts_prot);
+		if (bss_conf->use_cts_prot &&
+		    hw->conf.channel->band != IEEE80211_BAND_5GHZ)
+			sc->sc_flags |= SC_OP_PROTECT_ENABLE;
+		else
+			sc->sc_flags &= ~SC_OP_PROTECT_ENABLE;
+	}
+
+	if (changed & BSS_CHANGED_HT) {
+		DPRINTF(sc, ATH_DBG_CONFIG, "%s: BSS Changed HT %d\n",
+			__func__,
+			bss_conf->assoc_ht);
+		ath9k_ht_conf(sc, bss_conf);
+	}
+
+	if (changed & BSS_CHANGED_ASSOC) {
+		DPRINTF(sc, ATH_DBG_CONFIG, "%s: BSS Changed ASSOC %d\n",
+			__func__,
+			bss_conf->assoc);
+		ath9k_bss_assoc_info(sc, bss_conf);
+	}
+}
+
+static u64 ath9k_get_tsf(struct ieee80211_hw *hw)
+{
+	u64 tsf;
+	struct ath_softc *sc = hw->priv;
+	struct ath_hal *ah = sc->sc_ah;
+
+	tsf = ath9k_hw_gettsf64(ah);
+
+	return tsf;
+}
+
+static void ath9k_reset_tsf(struct ieee80211_hw *hw)
+{
+	struct ath_softc *sc = hw->priv;
+	struct ath_hal *ah = sc->sc_ah;
+
+	ath9k_hw_reset_tsf(ah);
+}
+
+static int ath9k_ampdu_action(struct ieee80211_hw *hw,
+		       enum ieee80211_ampdu_mlme_action action,
+		       struct ieee80211_sta *sta,
+		       u16 tid, u16 *ssn)
+{
+	struct ath_softc *sc = hw->priv;
+	int ret = 0;
+
+	switch (action) {
+	case IEEE80211_AMPDU_RX_START:
+		ret = ath_rx_aggr_start(sc, sta->addr, tid, ssn);
+		if (ret < 0)
+			DPRINTF(sc, ATH_DBG_FATAL,
+				"%s: Unable to start RX aggregation\n",
+				__func__);
+		break;
+	case IEEE80211_AMPDU_RX_STOP:
+		ret = ath_rx_aggr_stop(sc, sta->addr, tid);
+		if (ret < 0)
+			DPRINTF(sc, ATH_DBG_FATAL,
+				"%s: Unable to stop RX aggregation\n",
+				__func__);
+		break;
+	case IEEE80211_AMPDU_TX_START:
+		ret = ath_tx_aggr_start(sc, sta->addr, tid, ssn);
+		if (ret < 0)
+			DPRINTF(sc, ATH_DBG_FATAL,
+				"%s: Unable to start TX aggregation\n",
+				__func__);
+		else
+			ieee80211_start_tx_ba_cb_irqsafe(hw, sta->addr, tid);
+		break;
+	case IEEE80211_AMPDU_TX_STOP:
+		ret = ath_tx_aggr_stop(sc, sta->addr, tid);
+		if (ret < 0)
+			DPRINTF(sc, ATH_DBG_FATAL,
+				"%s: Unable to stop TX aggregation\n",
+				__func__);
+
+		ieee80211_stop_tx_ba_cb_irqsafe(hw, sta->addr, tid);
+		break;
+	default:
+		DPRINTF(sc, ATH_DBG_FATAL,
+			"%s: Unknown AMPDU action\n", __func__);
+	}
+
+	return ret;
+}
+
+static struct ieee80211_ops ath9k_ops = {
+	.tx 		    = ath9k_tx,
+	.start 		    = ath9k_start,
+	.stop 		    = ath9k_stop,
+	.add_interface 	    = ath9k_add_interface,
+	.remove_interface   = ath9k_remove_interface,
+	.config 	    = ath9k_config,
+	.config_interface   = ath9k_config_interface,
+	.configure_filter   = ath9k_configure_filter,
+	.get_stats          = NULL,
+	.sta_notify         = ath9k_sta_notify,
+	.conf_tx 	    = ath9k_conf_tx,
+	.get_tx_stats 	    = NULL,
+	.bss_info_changed   = ath9k_bss_info_changed,
+	.set_tim            = NULL,
+	.set_key            = ath9k_set_key,
+	.hw_scan            = NULL,
+	.get_tkip_seq       = NULL,
+	.set_rts_threshold  = NULL,
+	.set_frag_threshold = NULL,
+	.set_retry_limit    = NULL,
+	.get_tsf 	    = ath9k_get_tsf,
+	.reset_tsf 	    = ath9k_reset_tsf,
+	.tx_last_beacon     = NULL,
+	.ampdu_action       = ath9k_ampdu_action
+};
+
 static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 {
 	void __iomem *mem;
@@ -1364,9 +1740,16 @@
 		goto bad2;
 	}
 
-	hw->flags = IEEE80211_HW_SIGNAL_DBM |
+	hw->flags = IEEE80211_HW_RX_INCLUDES_FCS |
+		IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
+		IEEE80211_HW_SIGNAL_DBM |
 		IEEE80211_HW_NOISE_DBM;
 
+	hw->wiphy->interface_modes =
+		BIT(NL80211_IFTYPE_AP) |
+		BIT(NL80211_IFTYPE_STATION) |
+		BIT(NL80211_IFTYPE_ADHOC);
+
 	SET_IEEE80211_DEV(hw, &pdev->dev);
 	pci_set_drvdata(pdev, hw);
 
@@ -1414,10 +1797,17 @@
 {
 	struct ieee80211_hw *hw = pci_get_drvdata(pdev);
 	struct ath_softc *sc = hw->priv;
+	enum ath9k_int status;
 
-	if (pdev->irq)
+	if (pdev->irq) {
+		ath9k_hw_set_interrupts(sc->sc_ah, 0);
+		/* clear the ISR */
+		ath9k_hw_getisr(sc->sc_ah, &status);
+		sc->sc_flags |= SC_OP_INVALID;
 		free_irq(pdev->irq, sc);
+	}
 	ath_detach(sc);
+
 	pci_iounmap(pdev, sc->mem);
 	pci_release_region(pdev, 0);
 	pci_disable_device(pdev);
@@ -1428,6 +1818,16 @@
 
 static int ath_pci_suspend(struct pci_dev *pdev, pm_message_t state)
 {
+	struct ieee80211_hw *hw = pci_get_drvdata(pdev);
+	struct ath_softc *sc = hw->priv;
+
+	ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1);
+
+#ifdef CONFIG_RFKILL
+	if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
+		cancel_delayed_work_sync(&sc->rf_kill.rfkill_poll);
+#endif
+
 	pci_save_state(pdev);
 	pci_disable_device(pdev);
 	pci_set_power_state(pdev, 3);
@@ -1437,6 +1837,8 @@
 
 static int ath_pci_resume(struct pci_dev *pdev)
 {
+	struct ieee80211_hw *hw = pci_get_drvdata(pdev);
+	struct ath_softc *sc = hw->priv;
 	u32 val;
 	int err;
 
@@ -1453,6 +1855,21 @@
 	if ((val & 0x0000ff00) != 0)
 		pci_write_config_dword(pdev, 0x40, val & 0xffff00ff);
 
+	/* Enable LED */
+	ath9k_hw_cfg_output(sc->sc_ah, ATH_LED_PIN,
+			    AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
+	ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1);
+
+#ifdef CONFIG_RFKILL
+	/*
+	 * check the h/w rfkill state on resume
+	 * and start the rfkill poll timer
+	 */
+	if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
+		queue_delayed_work(sc->hw->workqueue,
+				   &sc->rf_kill.rfkill_poll, 0);
+#endif
+
 	return 0;
 }
 
diff --git a/drivers/net/wireless/ath9k/phy.h b/drivers/net/wireless/ath9k/phy.h
index 0cd399a..1470234 100644
--- a/drivers/net/wireless/ath9k/phy.h
+++ b/drivers/net/wireless/ath9k/phy.h
@@ -18,19 +18,19 @@
 #define PHY_H
 
 bool ath9k_hw_ar9280_set_channel(struct ath_hal *ah,
-					  struct ath9k_channel
-					  *chan);
+				 struct ath9k_channel
+				 *chan);
 bool ath9k_hw_set_channel(struct ath_hal *ah,
-				   struct ath9k_channel *chan);
+			  struct ath9k_channel *chan);
 void ath9k_hw_write_regs(struct ath_hal *ah, u32 modesIndex,
 			 u32 freqIndex, int regWrites);
 bool ath9k_hw_set_rf_regs(struct ath_hal *ah,
-				   struct ath9k_channel *chan,
-				   u16 modesIndex);
+			  struct ath9k_channel *chan,
+			  u16 modesIndex);
 void ath9k_hw_decrease_chain_power(struct ath_hal *ah,
 				   struct ath9k_channel *chan);
 bool ath9k_hw_init_rf(struct ath_hal *ah,
-			       int *status);
+		      int *status);
 
 #define AR_PHY_BASE     0x9800
 #define AR_PHY(_n)      (AR_PHY_BASE + ((_n)<<2))
diff --git a/drivers/net/wireless/ath9k/rc.c b/drivers/net/wireless/ath9k/rc.c
index 73c460a..cca2fc5 100644
--- a/drivers/net/wireless/ath9k/rc.c
+++ b/drivers/net/wireless/ath9k/rc.c
@@ -20,6 +20,7 @@
  */
 
 #include "core.h"
+/* FIXME: remove this include! */
 #include "../net/mac80211/rate.h"
 
 static u32 tx_triglevel_max;
@@ -653,8 +654,8 @@
 	rate_ctrl = (struct ath_tx_ratectrl *)(ath_rc_priv);
 	for (i = 0; i < rate_table->rate_cnt; i++) {
 		valid = (ath_rc_priv->single_stream ?
-				rate_table->info[i].valid_single_stream :
-				rate_table->info[i].valid);
+			 rate_table->info[i].valid_single_stream :
+			 rate_table->info[i].valid);
 		if (valid == TRUE) {
 			u32 phy = rate_table->info[i].phy;
 			u8 valid_rate_count = 0;
@@ -740,14 +741,14 @@
 		for (j = 0; j < rate_table->rate_cnt; j++) {
 			u32 phy = rate_table->info[j].phy;
 			u32 valid = (ath_rc_priv->single_stream ?
-				rate_table->info[j].valid_single_stream :
-				rate_table->info[j].valid);
+				     rate_table->info[j].valid_single_stream :
+				     rate_table->info[j].valid);
 
 			if (((((struct ath_rateset *)
-				mcs_set)->rs_rates[i] & 0x7F) !=
-				(rate_table->info[j].dot11rate & 0x7F)) ||
-					!WLAN_RC_PHY_HT(phy) ||
-					!WLAN_RC_PHY_HT_VALID(valid, capflag))
+			       mcs_set)->rs_rates[i] & 0x7F) !=
+			     (rate_table->info[j].dot11rate & 0x7F)) ||
+			    !WLAN_RC_PHY_HT(phy) ||
+			    !WLAN_RC_PHY_HT_VALID(valid, capflag))
 				continue;
 
 			if (!ath_rc_valid_phyrate(phy, capflag, FALSE))
@@ -847,9 +848,9 @@
 	/* For half and quarter rate channles use different
 	 * rate tables
 	 */
-	if (sc->sc_curchan.channelFlags & CHANNEL_HALF)
+	if (sc->sc_ah->ah_curchan->channelFlags & CHANNEL_HALF)
 		ar5416_sethalf_ratetable(asc);
-	else if (sc->sc_curchan.channelFlags & CHANNEL_QUARTER)
+	else if (sc->sc_ah->ah_curchan->channelFlags & CHANNEL_QUARTER)
 		ar5416_setquarter_ratetable(asc);
 	else /* full rate */
 		ar5416_setfull_ratetable(asc);
@@ -866,10 +867,10 @@
 }
 
 static u8 ath_rc_ratefind_ht(struct ath_softc *sc,
-				   struct ath_rate_node *ath_rc_priv,
-				   const struct ath_rate_table *rate_table,
-				   int probe_allowed, int *is_probing,
-				   int is_retry)
+			     struct ath_rate_node *ath_rc_priv,
+			     const struct ath_rate_table *rate_table,
+			     int probe_allowed, int *is_probing,
+			     int is_retry)
 {
 	u32 dt, best_thruput, this_thruput, now_msec;
 	u8 rate, next_rate, best_rate, maxindex, minindex;
@@ -997,8 +998,8 @@
 		rate = rate_ctrl->rate_table_size - 1;
 
 	ASSERT((rate_table->info[rate].valid && !ath_rc_priv->single_stream) ||
-		(rate_table->info[rate].valid_single_stream &&
-			ath_rc_priv->single_stream));
+	       (rate_table->info[rate].valid_single_stream &&
+		ath_rc_priv->single_stream));
 
 	return rate;
 }
@@ -1023,10 +1024,10 @@
 }
 
 static u8 ath_rc_rate_getidx(struct ath_softc *sc,
-				   struct ath_rate_node *ath_rc_priv,
-				   const struct ath_rate_table *rate_table,
-				   u8 rix, u16 stepdown,
-				   u16 min_rate)
+			     struct ath_rate_node *ath_rc_priv,
+			     const struct ath_rate_table *rate_table,
+			     u8 rix, u16 stepdown,
+			     u16 min_rate)
 {
 	u32 j;
 	u8 nextindex;
@@ -1066,8 +1067,8 @@
 	rate_table =
 		(struct ath_rate_table *)asc->hw_rate_table[sc->sc_curmode];
 	rix = ath_rc_ratefind_ht(sc, ath_rc_priv, rate_table,
-				(rcflag & ATH_RC_PROBE_ALLOWED) ? 1 : 0,
-				is_probe, is_retry);
+				 (rcflag & ATH_RC_PROBE_ALLOWED) ? 1 : 0,
+				 is_probe, is_retry);
 	nrix = rix;
 
 	if ((rcflag & ATH_RC_PROBE_ALLOWED) && (*is_probe)) {
@@ -1099,13 +1100,13 @@
 		try_num = ((i + 1) == num_rates) ?
 			num_tries - (try_per_rate * i) : try_per_rate ;
 		min_rate = (((i + 1) == num_rates) &&
-			(rcflag & ATH_RC_MINRATE_LASTRATE)) ? 1 : 0;
+			    (rcflag & ATH_RC_MINRATE_LASTRATE)) ? 1 : 0;
 
 		nrix = ath_rc_rate_getidx(sc, ath_rc_priv,
-			rate_table, nrix, 1, min_rate);
+					  rate_table, nrix, 1, min_rate);
 		/* All other rates in the series have RTS enabled */
 		ath_rc_rate_set_series(rate_table,
-			&series[i], try_num, nrix, TRUE);
+				       &series[i], try_num, nrix, TRUE);
 	}
 
 	/*
@@ -1124,13 +1125,13 @@
 	 * above conditions.
 	 */
 	if ((sc->sc_curmode == ATH9K_MODE_11NG_HT20) ||
-			(sc->sc_curmode == ATH9K_MODE_11NG_HT40PLUS) ||
-			(sc->sc_curmode == ATH9K_MODE_11NG_HT40MINUS)) {
+	    (sc->sc_curmode == ATH9K_MODE_11NG_HT40PLUS) ||
+	    (sc->sc_curmode == ATH9K_MODE_11NG_HT40MINUS)) {
 		u8  dot11rate = rate_table->info[rix].dot11rate;
 		u8 phy = rate_table->info[rix].phy;
 		if (i == 4 &&
 		    ((dot11rate == 2 && phy == WLAN_RC_PHY_HT_40_SS) ||
-		    (dot11rate == 3 && phy == WLAN_RC_PHY_HT_20_SS))) {
+		     (dot11rate == 3 && phy == WLAN_RC_PHY_HT_20_SS))) {
 			series[3].rix = series[2].rix;
 			series[3].flags = series[2].flags;
 			series[3].max_4ms_framelen = series[2].max_4ms_framelen;
@@ -1141,18 +1142,19 @@
 /*
  * Return the Tx rate series.
  */
-void ath_rate_findrate(struct ath_softc *sc,
-		       struct ath_rate_node *ath_rc_priv,
-		       int num_tries,
-		       int num_rates,
-		       unsigned int rcflag,
-		       struct ath_rc_series series[],
-		       int *is_probe,
-		       int is_retry)
+static void ath_rate_findrate(struct ath_softc *sc,
+			      struct ath_rate_node *ath_rc_priv,
+			      int num_tries,
+			      int num_rates,
+			      unsigned int rcflag,
+			      struct ath_rc_series series[],
+			      int *is_probe,
+			      int is_retry)
 {
 	struct ath_vap *avp = ath_rc_priv->avp;
 
-	DPRINTF(sc, ATH_DBG_RATE, "%s", __func__);
+	DPRINTF(sc, ATH_DBG_RATE, "%s\n", __func__);
+
 	if (!num_rates || !num_tries)
 		return;
 
@@ -1174,9 +1176,8 @@
 			unsigned int    mcs;
 			u8 series_rix = 0;
 
-			series[idx].tries =
-				IEEE80211_RATE_IDX_ENTRY(
-					avp->av_config.av_fixed_retryset, idx);
+			series[idx].tries = IEEE80211_RATE_IDX_ENTRY(
+				avp->av_config.av_fixed_retryset, idx);
 
 			mcs = IEEE80211_RATE_IDX_ENTRY(
 				avp->av_config.av_fixed_rateset, idx);
@@ -1228,7 +1229,7 @@
 	u32 now_msec = jiffies_to_msecs(jiffies);
 	int state_change = FALSE, rate, count;
 	u8 last_per;
-	struct ath_rate_softc  *asc = (struct ath_rate_softc *)sc->sc_rc;
+	struct ath_rate_softc *asc = (struct ath_rate_softc *)sc->sc_rc;
 	struct ath_rate_table *rate_table =
 		(struct ath_rate_table *)asc->hw_rate_table[sc->sc_curmode];
 
@@ -1272,14 +1273,14 @@
 		} else {
 			/* xretries == 2 */
 			count = sizeof(nretry_to_per_lookup) /
-					sizeof(nretry_to_per_lookup[0]);
+				sizeof(nretry_to_per_lookup[0]);
 			if (retries >= count)
 				retries = count - 1;
 			/* new_PER = 7/8*old_PER + 1/8*(currentPER) */
 			rate_ctrl->state[tx_rate].per =
 				(u8)(rate_ctrl->state[tx_rate].per -
-				(rate_ctrl->state[tx_rate].per >> 3) +
-				((100) >> 3));
+				     (rate_ctrl->state[tx_rate].per >> 3) +
+				     ((100) >> 3));
 		}
 
 		/* xretries == 1 or 2 */
@@ -1295,8 +1296,7 @@
 		if (retries >= count)
 			retries = count - 1;
 		if (info_priv->n_bad_frames) {
-			/* new_PER = 7/8*old_PER + 1/8*(currentPER)  */
-			/*
+			/* new_PER = 7/8*old_PER + 1/8*(currentPER)
 			 * Assuming that n_frames is not 0.  The current PER
 			 * from the retries is 100 * retries / (retries+1),
 			 * since the first retries attempts failed, and the
@@ -1386,7 +1386,7 @@
 			 * rssi_ack values.
 			 */
 			if (tx_rate == rate_ctrl->rate_max_phy &&
-					rate_ctrl->hw_maxretry_pktcnt < 255) {
+			    rate_ctrl->hw_maxretry_pktcnt < 255) {
 				rate_ctrl->hw_maxretry_pktcnt++;
 			}
 
@@ -1418,7 +1418,7 @@
 					/* Now reduce the current
 					 * rssi threshold. */
 					if ((rssi_ackAvg < rssi_thres + 2) &&
-						(rssi_thres > rssi_ack_vmin)) {
+					    (rssi_thres > rssi_ack_vmin)) {
 						rate_ctrl->state[tx_rate].
 							rssi_thres--;
 					}
@@ -1436,10 +1436,10 @@
 	 * a while (except if we are probing).
 	 */
 	if (rate_ctrl->state[tx_rate].per >= 55 && tx_rate > 0 &&
-			rate_table->info[tx_rate].ratekbps <=
-			rate_table->info[rate_ctrl->rate_max_phy].ratekbps) {
+	    rate_table->info[tx_rate].ratekbps <=
+	    rate_table->info[rate_ctrl->rate_max_phy].ratekbps) {
 		ath_rc_get_nextlowervalid_txrate(rate_table, rate_ctrl,
-				(u8) tx_rate, &rate_ctrl->rate_max_phy);
+				 (u8) tx_rate, &rate_ctrl->rate_max_phy);
 
 		/* Don't probe for a little while. */
 		rate_ctrl->probe_time = now_msec;
@@ -1460,43 +1460,43 @@
 				break;
 
 			if (rate_ctrl->state[rate].rssi_thres +
-				rate_table->info[rate].rssi_ack_deltamin >
-					rate_ctrl->state[rate+1].rssi_thres) {
+			    rate_table->info[rate].rssi_ack_deltamin >
+			    rate_ctrl->state[rate+1].rssi_thres) {
 				rate_ctrl->state[rate+1].rssi_thres =
 					rate_ctrl->state[rate].
-						rssi_thres +
+					rssi_thres +
 					rate_table->info[rate].
-						rssi_ack_deltamin;
+					rssi_ack_deltamin;
 			}
 		}
 
 		/* Make sure the rates below this have lower rssi thresholds. */
 		for (rate = tx_rate - 1; rate >= 0; rate--) {
 			if (rate_table->info[rate].phy !=
-				rate_table->info[tx_rate].phy)
+			    rate_table->info[tx_rate].phy)
 				break;
 
 			if (rate_ctrl->state[rate].rssi_thres +
-				rate_table->info[rate].rssi_ack_deltamin >
-					rate_ctrl->state[rate+1].rssi_thres) {
+			    rate_table->info[rate].rssi_ack_deltamin >
+			    rate_ctrl->state[rate+1].rssi_thres) {
 				if (rate_ctrl->state[rate+1].rssi_thres <
-					rate_table->info[rate].
-					rssi_ack_deltamin)
+				    rate_table->info[rate].
+				    rssi_ack_deltamin)
 					rate_ctrl->state[rate].rssi_thres = 0;
 				else {
 					rate_ctrl->state[rate].rssi_thres =
 						rate_ctrl->state[rate+1].
-							rssi_thres -
-							rate_table->info[rate].
-							rssi_ack_deltamin;
+						rssi_thres -
+						rate_table->info[rate].
+						rssi_ack_deltamin;
 				}
 
 				if (rate_ctrl->state[rate].rssi_thres <
-					rate_table->info[rate].
-						rssi_ack_validmin) {
+				    rate_table->info[rate].
+				    rssi_ack_validmin) {
 					rate_ctrl->state[rate].rssi_thres =
 						rate_table->info[rate].
-							rssi_ack_validmin;
+						rssi_ack_validmin;
 				}
 			}
 		}
@@ -1507,11 +1507,11 @@
 	if (rate_ctrl->state[tx_rate].per < last_per) {
 		for (rate = tx_rate - 1; rate >= 0; rate--) {
 			if (rate_table->info[rate].phy !=
-				rate_table->info[tx_rate].phy)
+			    rate_table->info[tx_rate].phy)
 				break;
 
 			if (rate_ctrl->state[rate].per >
-					rate_ctrl->state[rate+1].per) {
+			    rate_ctrl->state[rate+1].per) {
 				rate_ctrl->state[rate].per =
 					rate_ctrl->state[rate+1].per;
 			}
@@ -1528,11 +1528,11 @@
 	/* Every so often, we reduce the thresholds and
 	 * PER (different for CCK and OFDM). */
 	if (now_msec - rate_ctrl->rssi_down_time >=
-		rate_table->rssi_reduce_interval) {
+	    rate_table->rssi_reduce_interval) {
 
 		for (rate = 0; rate < rate_ctrl->rate_table_size; rate++) {
 			if (rate_ctrl->state[rate].rssi_thres >
-				rate_table->info[rate].rssi_ack_validmin)
+			    rate_table->info[rate].rssi_ack_validmin)
 				rate_ctrl->state[rate].rssi_thres -= 1;
 		}
 		rate_ctrl->rssi_down_time = now_msec;
@@ -1541,7 +1541,7 @@
 	/* Every so often, we reduce the thresholds
 	 * and PER (different for CCK and OFDM). */
 	if (now_msec - rate_ctrl->per_down_time >=
-		rate_table->rssi_reduce_interval) {
+	    rate_table->rssi_reduce_interval) {
 		for (rate = 0; rate < rate_ctrl->rate_table_size; rate++) {
 			rate_ctrl->state[rate].per =
 				7 * rate_ctrl->state[rate].per / 8;
@@ -1560,7 +1560,7 @@
 			  struct ath_tx_info_priv *info_priv, int final_ts_idx,
 			  int xretries, int long_retry)
 {
-	struct ath_rate_softc  *asc = (struct ath_rate_softc *)sc->sc_rc;
+	struct ath_rate_softc *asc = (struct ath_rate_softc *)sc->sc_rc;
 	struct ath_rate_table *rate_table;
 	struct ath_tx_ratectrl *rate_ctrl;
 	struct ath_rc_series rcs[4];
@@ -1637,7 +1637,6 @@
 		xretries, long_retry);
 }
 
-
 /*
  * Process a tx descriptor for a completed transmit (success or failure).
  */
@@ -1651,13 +1650,13 @@
 	struct ath_vap *avp;
 
 	avp = rc_priv->avp;
-	if ((avp->av_config.av_fixed_rateset != IEEE80211_FIXED_RATE_NONE)
-			|| info_priv->tx.ts_status & ATH9K_TXERR_FILT)
+	if ((avp->av_config.av_fixed_rateset != IEEE80211_FIXED_RATE_NONE) ||
+	    (info_priv->tx.ts_status & ATH9K_TXERR_FILT))
 		return;
 
 	if (info_priv->tx.ts_rssi > 0) {
 		ATH_RSSI_LPF(an->an_chainmask_sel.tx_avgrssi,
-				info_priv->tx.ts_rssi);
+			     info_priv->tx.ts_rssi);
 	}
 
 	/*
@@ -1682,7 +1681,6 @@
 		      info_priv->tx.ts_longretry);
 }
 
-
 /*
  *  Update the SIB's rate control information
  *
@@ -1701,8 +1699,8 @@
 	struct ath_rate_softc *asc = (struct ath_rate_softc *)sc->sc_rc;
 	struct ath_rateset *rateset = negotiated_rates;
 	u8 *ht_mcs = (u8 *)negotiated_htrates;
-	struct ath_tx_ratectrl *rate_ctrl  = (struct ath_tx_ratectrl *)
-		(ath_rc_priv);
+	struct ath_tx_ratectrl *rate_ctrl =
+		(struct ath_tx_ratectrl *)ath_rc_priv;
 	u8 i, j, k, hi = 0, hthi = 0;
 
 	rate_table = (struct ath_rate_table *)
@@ -1815,19 +1813,18 @@
 }
 
 
-static void ath_setup_rates(struct ieee80211_local *local, struct sta_info *sta)
+static void ath_setup_rates(struct ath_softc *sc,
+			    struct ieee80211_supported_band *sband,
+			    struct ieee80211_sta *sta,
+			    struct ath_rate_node *rc_priv)
 
 {
-	struct ieee80211_supported_band *sband;
-	struct ieee80211_hw *hw = local_to_hw(local);
-	struct ath_softc *sc = hw->priv;
-	struct ath_rate_node *rc_priv = sta->rate_ctrl_priv;
 	int i, j = 0;
 
-	DPRINTF(sc, ATH_DBG_RATE, "%s", __func__);
-	sband =  local->hw.wiphy->bands[local->hw.conf.channel->band];
+	DPRINTF(sc, ATH_DBG_RATE, "%s\n", __func__);
+
 	for (i = 0; i < sband->n_bitrates; i++) {
-		if (sta->supp_rates[local->hw.conf.channel->band] & BIT(i)) {
+		if (sta->supp_rates[sband->band] & BIT(i)) {
 			rc_priv->neg_rates.rs_rates[j]
 				= (sband->bitrates[i].bitrate * 2) / 10;
 			j++;
@@ -1854,19 +1851,17 @@
 }
 
 /* Rate Control callbacks */
-static void ath_tx_status(void *priv, struct net_device *dev,
+static void ath_tx_status(void *priv, struct ieee80211_supported_band *sband,
+			  struct ieee80211_sta *sta, void *priv_sta,
 			  struct sk_buff *skb)
 {
 	struct ath_softc *sc = priv;
 	struct ath_tx_info_priv *tx_info_priv;
 	struct ath_node *an;
-	struct sta_info *sta;
-	struct ieee80211_local *local;
 	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
 	struct ieee80211_hdr *hdr;
 	__le16 fc;
 
-	local = hw_to_local(sc->hw);
 	hdr = (struct ieee80211_hdr *)skb->data;
 	fc = hdr->frame_control;
 	tx_info_priv = (struct ath_tx_info_priv *)tx_info->driver_data[0];
@@ -1875,8 +1870,7 @@
 	an = ath_node_find(sc, hdr->addr1);
 	spin_unlock_bh(&sc->node_lock);
 
-	sta = sta_info_get(local, hdr->addr1);
-	if (!an || !sta || !ieee80211_is_data(fc)) {
+	if (!an || !priv_sta || !ieee80211_is_data(fc)) {
 		if (tx_info->driver_data[0] != NULL) {
 			kfree(tx_info->driver_data[0]);
 			tx_info->driver_data[0] = NULL;
@@ -1884,37 +1878,40 @@
 		return;
 	}
 	if (tx_info->driver_data[0] != NULL) {
-		ath_rate_tx_complete(sc, an, sta->rate_ctrl_priv, tx_info_priv);
+		ath_rate_tx_complete(sc, an, priv_sta, tx_info_priv);
 		kfree(tx_info->driver_data[0]);
 		tx_info->driver_data[0] = NULL;
 	}
 }
 
 static void ath_tx_aggr_resp(struct ath_softc *sc,
-			     struct sta_info *sta,
+			     struct ieee80211_supported_band *sband,
+			     struct ieee80211_sta *sta,
 			     struct ath_node *an,
 			     u8 tidno)
 {
-	struct ieee80211_hw *hw = sc->hw;
-	struct ieee80211_local *local;
 	struct ath_atx_tid *txtid;
-	struct ieee80211_supported_band *sband;
 	u16 buffersize = 0;
 	int state;
-	DECLARE_MAC_BUF(mac);
+	struct sta_info *si;
 
-	if (!sc->sc_txaggr)
+	if (!(sc->sc_flags & SC_OP_TXAGGR))
 		return;
 
 	txtid = ATH_AN_2_TID(an, tidno);
 	if (!txtid->paused)
 		return;
 
-	local = hw_to_local(sc->hw);
-	sband = hw->wiphy->bands[hw->conf.channel->band];
+	/*
+	 * XXX: This is entirely busted, we aren't supposed to
+	 *	access the sta from here because it's internal
+	 *	to mac80211, and looking at the state without
+	 *	locking is wrong too.
+	 */
+	si = container_of(sta, struct sta_info, sta);
 	buffersize = IEEE80211_MIN_AMPDU_BUF <<
 		sband->ht_info.ampdu_factor; /* FIXME */
-	state = sta->ampdu_mlme.tid_state_tx[tidno];
+	state = si->ampdu_mlme.tid_state_tx[tidno];
 
 	if (state & HT_ADDBA_RECEIVED_MSK) {
 		txtid->addba_exchangecomplete = 1;
@@ -1930,21 +1927,18 @@
 	}
 }
 
-static void ath_get_rate(void *priv, struct net_device *dev,
-			 struct ieee80211_supported_band *sband,
-			 struct sk_buff *skb,
-			 struct rate_selection *sel)
+static void ath_get_rate(void *priv, struct ieee80211_supported_band *sband,
+			 struct ieee80211_sta *sta, void *priv_sta,
+			 struct sk_buff *skb, struct rate_selection *sel)
 {
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
-	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-	struct sta_info *sta;
-	struct ath_softc *sc = (struct ath_softc *)priv;
+	struct ath_softc *sc = priv;
 	struct ieee80211_hw *hw = sc->hw;
 	struct ath_tx_info_priv *tx_info_priv;
-	struct ath_rate_node *ath_rc_priv;
+	struct ath_rate_node *ath_rc_priv = priv_sta;
 	struct ath_node *an;
 	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
-	int is_probe, chk, ret;
+	int is_probe = FALSE, chk, ret;
 	s8 lowest_idx;
 	__le16 fc = hdr->frame_control;
 	u8 *qc, tid;
@@ -1957,18 +1951,15 @@
 	ASSERT(tx_info->driver_data[0] != NULL);
 	tx_info_priv = (struct ath_tx_info_priv *)tx_info->driver_data[0];
 
-	sta = sta_info_get(local, hdr->addr1);
-	lowest_idx = rate_lowest_index(local, sband, sta);
+	lowest_idx = rate_lowest_index(sband, sta);
 	tx_info_priv->min_rate = (sband->bitrates[lowest_idx].bitrate * 2) / 10;
 	/* lowest rate for management and multicast/broadcast frames */
 	if (!ieee80211_is_data(fc) ||
-			is_multicast_ether_addr(hdr->addr1) || !sta) {
+	    is_multicast_ether_addr(hdr->addr1) || !sta) {
 		sel->rate_idx = lowest_idx;
 		return;
 	}
 
-	ath_rc_priv = sta->rate_ctrl_priv;
-
 	/* Find tx rate for unicast frames */
 	ath_rate_findrate(sc, ath_rc_priv,
 			  ATH_11N_TXMAXTRY, 4,
@@ -1977,8 +1968,7 @@
 			  &is_probe,
 			  false);
 	if (is_probe)
-		sel->probe_idx = ((struct ath_tx_ratectrl *)
-			sta->rate_ctrl_priv)->probe_rate;
+		sel->probe_idx = ath_rc_priv->tx_ratectrl.probe_rate;
 
 	/* Ratecontrol sometimes returns invalid rate index */
 	if (tx_info_priv->rcs[0].rix != 0xff)
@@ -2022,38 +2012,31 @@
 						__func__,
 						print_mac(mac, hdr->addr1));
 			} else if (chk == AGGR_EXCHANGE_PROGRESS)
-				ath_tx_aggr_resp(sc, sta, an, tid);
+				ath_tx_aggr_resp(sc, sband, sta, an, tid);
 		}
 	}
 }
 
-static void ath_rate_init(void *priv, void *priv_sta,
-			  struct ieee80211_local *local,
-			  struct sta_info *sta)
+static void ath_rate_init(void *priv, struct ieee80211_supported_band *sband,
+                          struct ieee80211_sta *sta, void *priv_sta)
 {
-	struct ieee80211_supported_band *sband;
-	struct ieee80211_hw *hw = local_to_hw(local);
-	struct ieee80211_conf *conf = &local->hw.conf;
-	struct ath_softc *sc = hw->priv;
+	struct ath_softc *sc = priv;
+	struct ath_rate_node *ath_rc_priv = priv_sta;
 	int i, j = 0;
 
 	DPRINTF(sc, ATH_DBG_RATE, "%s\n", __func__);
 
-	sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
-	sta->txrate_idx = rate_lowest_index(local, sband, sta);
-
-	ath_setup_rates(local, sta);
-	if (conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) {
+	ath_setup_rates(sc, sband, sta, ath_rc_priv);
+	if (sc->hw->conf.flags & IEEE80211_CONF_SUPPORT_HT_MODE) {
 		for (i = 0; i < MCS_SET_SIZE; i++) {
-			if (conf->ht_conf.supp_mcs_set[i/8] & (1<<(i%8)))
-				((struct ath_rate_node *)
-				priv_sta)->neg_ht_rates.rs_rates[j++] = i;
+			if (sc->hw->conf.ht_conf.supp_mcs_set[i/8] & (1<<(i%8)))
+				ath_rc_priv->neg_ht_rates.rs_rates[j++] = i;
 			if (j == ATH_RATE_MAX)
 				break;
 		}
-		((struct ath_rate_node *)priv_sta)->neg_ht_rates.rs_nrates = j;
+		ath_rc_priv->neg_ht_rates.rs_nrates = j;
 	}
-	ath_rc_node_update(hw, priv_sta);
+	ath_rc_node_update(sc->hw, priv_sta);
 }
 
 static void ath_rate_clear(void *priv)
@@ -2061,13 +2044,12 @@
 	return;
 }
 
-static void *ath_rate_alloc(struct ieee80211_local *local)
+static void *ath_rate_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir)
 {
-	struct ieee80211_hw *hw = local_to_hw(local);
 	struct ath_softc *sc = hw->priv;
 
-	DPRINTF(sc, ATH_DBG_RATE, "%s", __func__);
-	return local->hw.priv;
+	DPRINTF(sc, ATH_DBG_RATE, "%s\n", __func__);
+	return hw->priv;
 }
 
 static void ath_rate_free(void *priv)
@@ -2075,24 +2057,28 @@
 	return;
 }
 
-static void *ath_rate_alloc_sta(void *priv, gfp_t gfp)
+static void *ath_rate_alloc_sta(void *priv, struct ieee80211_sta *sta, gfp_t gfp)
 {
 	struct ath_softc *sc = priv;
 	struct ath_vap *avp = sc->sc_vaps[0];
 	struct ath_rate_node *rate_priv;
 
-	DPRINTF(sc, ATH_DBG_RATE, "%s", __func__);
+	DPRINTF(sc, ATH_DBG_RATE, "%s\n", __func__);
+
 	rate_priv = ath_rate_node_alloc(avp, sc->sc_rc, gfp);
 	if (!rate_priv) {
-		DPRINTF(sc, ATH_DBG_FATAL, "%s:Unable to allocate"
-				"private rate control structure", __func__);
+		DPRINTF(sc, ATH_DBG_FATAL,
+			"%s: Unable to allocate private rc structure\n",
+			__func__);
 		return NULL;
 	}
 	ath_rc_sib_init(rate_priv);
+
 	return rate_priv;
 }
 
-static void ath_rate_free_sta(void *priv, void *priv_sta)
+static void ath_rate_free_sta(void *priv, struct ieee80211_sta *sta,
+			      void *priv_sta)
 {
 	struct ath_rate_node *rate_priv = priv_sta;
 	struct ath_softc *sc = priv;
@@ -2111,7 +2097,7 @@
 	.alloc = ath_rate_alloc,
 	.free = ath_rate_free,
 	.alloc_sta = ath_rate_alloc_sta,
-	.free_sta = ath_rate_free_sta
+	.free_sta = ath_rate_free_sta,
 };
 
 int ath_rate_control_register(void)
diff --git a/drivers/net/wireless/ath9k/rc.h b/drivers/net/wireless/ath9k/rc.h
index 71aef9c..b95b415 100644
--- a/drivers/net/wireless/ath9k/rc.h
+++ b/drivers/net/wireless/ath9k/rc.h
@@ -71,9 +71,6 @@
  */
 #define IEEE80211_RATE_IDX_ENTRY(val, idx) (((val&(0xff<<(idx*8)))>>(idx*8)))
 
-#define SHORT_PRE 1
-#define LONG_PRE 0
-
 #define WLAN_PHY_HT_20_SS       WLAN_RC_PHY_HT_20_SS
 #define WLAN_PHY_HT_20_DS       WLAN_RC_PHY_HT_20_DS
 #define WLAN_PHY_HT_20_DS_HGI   WLAN_RC_PHY_HT_20_DS_HGI
@@ -102,18 +99,18 @@
 	WLAN_RC_PHY_MAX
 };
 
-#define WLAN_RC_PHY_DS(_phy)   ((_phy == WLAN_RC_PHY_HT_20_DS)           \
-	|| (_phy == WLAN_RC_PHY_HT_40_DS)        \
-	|| (_phy == WLAN_RC_PHY_HT_20_DS_HGI)    \
-	|| (_phy == WLAN_RC_PHY_HT_40_DS_HGI))
-#define WLAN_RC_PHY_40(_phy)   ((_phy == WLAN_RC_PHY_HT_40_SS)           \
-	|| (_phy == WLAN_RC_PHY_HT_40_DS)        \
-	|| (_phy == WLAN_RC_PHY_HT_40_SS_HGI)    \
-	|| (_phy == WLAN_RC_PHY_HT_40_DS_HGI))
+#define WLAN_RC_PHY_DS(_phy)   ((_phy == WLAN_RC_PHY_HT_20_DS)		\
+				|| (_phy == WLAN_RC_PHY_HT_40_DS)	\
+				|| (_phy == WLAN_RC_PHY_HT_20_DS_HGI)	\
+				|| (_phy == WLAN_RC_PHY_HT_40_DS_HGI))
+#define WLAN_RC_PHY_40(_phy)   ((_phy == WLAN_RC_PHY_HT_40_SS)		\
+				|| (_phy == WLAN_RC_PHY_HT_40_DS)	\
+				|| (_phy == WLAN_RC_PHY_HT_40_SS_HGI)	\
+				|| (_phy == WLAN_RC_PHY_HT_40_DS_HGI))
 #define WLAN_RC_PHY_SGI(_phy)  ((_phy == WLAN_RC_PHY_HT_20_SS_HGI)      \
-	|| (_phy == WLAN_RC_PHY_HT_20_DS_HGI)   \
-	|| (_phy == WLAN_RC_PHY_HT_40_SS_HGI)   \
-	|| (_phy == WLAN_RC_PHY_HT_40_DS_HGI))
+				|| (_phy == WLAN_RC_PHY_HT_20_DS_HGI)   \
+				|| (_phy == WLAN_RC_PHY_HT_40_SS_HGI)   \
+				|| (_phy == WLAN_RC_PHY_HT_40_DS_HGI))
 
 #define WLAN_RC_PHY_HT(_phy)    (_phy >= WLAN_RC_PHY_HT_20_SS)
 
@@ -135,56 +132,59 @@
 #define WLAN_RC_SGI_FLAG        (0x04)
 #define WLAN_RC_HT_FLAG         (0x08)
 
-/* Index into the rate table */
-#define INIT_RATE_MAX_20	23
-#define INIT_RATE_MAX_40	40
-
 #define RATE_TABLE_SIZE		64
 
-/* XXX: Convert to kdoc */
+/**
+ * struct ath_rate_table - Rate Control table
+ * @valid: valid for use in rate control
+ * @valid_single_stream: valid for use in rate control for
+ * 	single stream operation
+ * @phy: CCK/OFDM
+ * @ratekbps: rate in Kbits per second
+ * @user_ratekbps: user rate in Kbits per second
+ * @ratecode: rate that goes into HW descriptors
+ * @short_preamble: Mask for enabling short preamble in ratecode for CCK
+ * @dot11rate: value that goes into supported
+ * 	rates info element of MLME
+ * @ctrl_rate: Index of next lower basic rate, used for duration computation
+ * @max_4ms_framelen: maximum frame length(bytes) for tx duration
+ * @probe_interval: interval for rate control to probe for other rates
+ * @rssi_reduce_interval: interval for rate control to reduce rssi
+ * @initial_ratemax: initial ratemax value used in ath_rc_sib_update()
+ */
 struct ath_rate_table {
 	int rate_cnt;
 	struct {
-		int valid;            /* Valid for use in rate control */
-		int valid_single_stream;/* Valid for use in rate control
-					for single stream operation */
-		u8 phy;              /* CCK/OFDM/TURBO/XR */
-		u32 ratekbps;         /* Rate in Kbits per second */
-		u32 user_ratekbps;     /* User rate in KBits per second */
-		u8 ratecode;         /* rate that goes into
-					hw descriptors */
-		u8 short_preamble;    /* Mask for enabling short preamble
-						in rate code for CCK */
-		u8 dot11rate;        /* Value that goes into supported
-					rates info element of MLME */
-		u8 ctrl_rate;      /* Index of next lower basic rate,
-					used for duration computation */
-		int8_t rssi_ack_validmin;  /* Rate control related */
-		int8_t rssi_ack_deltamin;  /* Rate control related */
-		u8 base_index;        /* base rate index */
-		u8 cw40index;        /* 40cap rate index */
-		u8 sgi_index;         /* shortgi rate index */
-		u8 ht_index;          /* shortgi rate index */
-		u32 max_4ms_framelen;   /* Maximum frame length(bytes)
-						for 4ms tx duration */
+		int valid;
+		int valid_single_stream;
+		u8 phy;
+		u32 ratekbps;
+		u32 user_ratekbps;
+		u8 ratecode;
+		u8 short_preamble;
+		u8 dot11rate;
+		u8 ctrl_rate;
+		int8_t rssi_ack_validmin;
+		int8_t rssi_ack_deltamin;
+		u8 base_index;
+		u8 cw40index;
+		u8 sgi_index;
+		u8 ht_index;
+		u32 max_4ms_framelen;
 	} info[RATE_TABLE_SIZE];
-	u32 probe_interval;        /* interval for ratectrl to
-					probe for other rates */
-	u32 rssi_reduce_interval;   /* interval for ratectrl
-						to reduce RSSI */
-	u8 initial_ratemax;   /* the initial ratemax value used
-					in ath_rc_sib_update() */
+	u32 probe_interval;
+	u32 rssi_reduce_interval;
+	u8 initial_ratemax;
 };
 
 #define ATH_RC_PROBE_ALLOWED            0x00000001
 #define ATH_RC_MINRATE_LASTRATE         0x00000002
-#define ATH_RC_SHORT_PREAMBLE           0x00000004
 
 struct ath_rc_series {
-	u8    rix;
-	u8    tries;
-	u8    flags;
-	u32   max_4ms_framelen;
+	u8 rix;
+	u8 tries;
+	u8 flags;
+	u32 max_4ms_framelen;
 };
 
 /* rcs_flags definition */
@@ -201,42 +201,56 @@
 #define MAX_TX_RATE_PHY         48
 
 struct ath_tx_ratectrl_state {
-	int8_t rssi_thres; /* required rssi for this rate (dB) */
-	u8 per; /* recent estimate of packet error rate (%) */
+	int8_t rssi_thres;	/* required rssi for this rate (dB) */
+	u8 per;			/* recent estimate of packet error rate (%) */
 };
 
+/**
+ * struct ath_tx_ratectrl - TX Rate control Information
+ * @state: RC state
+ * @rssi_last: last ACK rssi
+ * @rssi_last_lookup: last ACK rssi used for lookup
+ * @rssi_last_prev: previous last ACK rssi
+ * @rssi_last_prev2: 2nd previous last ACK rssi
+ * @rssi_sum_cnt: count of rssi_sum for averaging
+ * @rssi_sum_rate: rate that we are averaging
+ * @rssi_sum: running sum of rssi for averaging
+ * @probe_rate: rate we are probing at
+ * @rssi_time: msec timestamp for last ack rssi
+ * @rssi_down_time: msec timestamp for last down step
+ * @probe_time: msec timestamp for last probe
+ * @hw_maxretry_pktcnt: num of packets since we got HW max retry error
+ * @max_valid_rate: maximum number of valid rate
+ * @per_down_time: msec timestamp for last PER down step
+ * @valid_phy_ratecnt: valid rate count
+ * @rate_max_phy: phy index for the max rate
+ * @probe_interval: interval for ratectrl to probe for other rates
+ */
 struct ath_tx_ratectrl {
-	struct ath_tx_ratectrl_state state[MAX_TX_RATE_TBL]; /* state */
-	int8_t rssi_last;            /* last ack rssi */
-	int8_t rssi_last_lookup;	/* last ack rssi used for lookup */
-	int8_t rssi_last_prev;	/* previous last ack rssi */
-	int8_t rssi_last_prev2;	/* 2nd previous last ack rssi */
-	int32_t rssi_sum_cnt;        /* count of rssi_sum for averaging */
-	int32_t rssi_sum_rate;       /* rate that we are averaging */
-	int32_t rssi_sum;           /* running sum of rssi for averaging */
-	u32 valid_txrate_mask;   /* mask of valid rates */
-	u8 rate_table_size;      /* rate table size */
-	u8 rate_max;            /* max rate that has recently worked */
-	u8 probe_rate;          /* rate we are probing at */
-	u32 rssi_time;          /* msec timestamp for last ack rssi */
-	u32 rssi_down_time;      /* msec timestamp for last down step */
-	u32 probe_time;         /* msec timestamp for last probe */
-	u8 hw_maxretry_pktcnt;   /* num packets since we got
-					HW max retry error */
-	u8 max_valid_rate;       /* maximum number of valid rate */
-	u8 valid_rate_index[MAX_TX_RATE_TBL]; /* valid rate index */
-	u32 per_down_time;       /* msec timstamp for last
-					PER down step */
+	struct ath_tx_ratectrl_state state[MAX_TX_RATE_TBL];
+	int8_t rssi_last;
+	int8_t rssi_last_lookup;
+	int8_t rssi_last_prev;
+	int8_t rssi_last_prev2;
+	int32_t rssi_sum_cnt;
+	int32_t rssi_sum_rate;
+	int32_t rssi_sum;
+	u8 rate_table_size;
+	u8 probe_rate;
+	u32 rssi_time;
+	u32 rssi_down_time;
+	u32 probe_time;
+	u8 hw_maxretry_pktcnt;
+	u8 max_valid_rate;
+	u8 valid_rate_index[MAX_TX_RATE_TBL];
+	u32 per_down_time;
 
 	/* 11n state */
-	u8  valid_phy_ratecnt[WLAN_RC_PHY_MAX]; /* valid rate count */
-	u8  valid_phy_rateidx[WLAN_RC_PHY_MAX][MAX_TX_RATE_TBL];
-	u8  rc_phy_mode;
-	u8  rate_max_phy;        /* Phy index for the max rate */
-	u32 rate_max_lastused;   /* msec timstamp of when we
-					last used rateMaxPhy */
-	u32 probe_interval;     /* interval for ratectrl to probe
-					for other rates */
+	u8 valid_phy_ratecnt[WLAN_RC_PHY_MAX];
+	u8 valid_phy_rateidx[WLAN_RC_PHY_MAX][MAX_TX_RATE_TBL];
+	u8 rc_phy_mode;
+	u8 rate_max_phy;
+	u32 probe_interval;
 };
 
 struct ath_rateset {
@@ -248,29 +262,32 @@
 struct ath_rate_softc {
 	/* phy tables that contain rate control data */
 	const void *hw_rate_table[ATH9K_MODE_MAX];
-	int fixedrix;	/* -1 or index of fixed rate */
+
+	/* -1 or index of fixed rate */
+	int fixedrix;
 };
 
 /* per-node state */
 struct ath_rate_node {
-	struct ath_tx_ratectrl tx_ratectrl;	/* rate control state proper */
-	u32 prev_data_rix;	/* rate idx of last data frame */
+	struct ath_tx_ratectrl tx_ratectrl;
 
-	/* map of rate ix -> negotiated rate set ix */
-	u8 rixmap[MAX_TX_RATE_TBL];
+	/* rate idx of last data frame */
+	u32 prev_data_rix;
 
-	/* map of ht rate ix -> negotiated rate set ix */
-	u8 ht_rixmap[MAX_TX_RATE_TBL];
+	/* ht capabilities */
+	u8 ht_cap;
 
-	u8 ht_cap;		/* ht capabilities */
-	u8 ant_tx;		/* current transmit antenna */
+	/* When TRUE, only single stream Tx possible */
+	u8 single_stream;
 
-	u8 single_stream;   /* When TRUE, only single
-				stream Tx possible */
-	struct ath_rateset neg_rates;	/* Negotiated rates */
-	struct ath_rateset neg_ht_rates;	/* Negotiated HT rates */
-	struct ath_rate_softc *asc; /* back pointer to atheros softc */
-	struct ath_vap *avp;	/* back pointer to vap */
+	/* Negotiated rates */
+	struct ath_rateset neg_rates;
+
+	/* Negotiated HT rates */
+	struct ath_rateset neg_ht_rates;
+
+	struct ath_rate_softc *asc;
+	struct ath_vap *avp;
 };
 
 /* Driver data of ieee80211_tx_info */
@@ -297,17 +314,10 @@
 void ath_rate_newstate(struct ath_softc *sc, struct ath_vap *avp);
 
 /*
- * Return the tx rate series.
- */
-void ath_rate_findrate(struct ath_softc *sc, struct ath_rate_node *ath_rc_priv,
-		       int num_tries, int num_rates,
-		       unsigned int rcflag, struct ath_rc_series[],
-		       int *is_probe, int isretry);
-/*
  * Return rate index for given Dot11 Rate.
  */
 u8 ath_rate_findrateix(struct ath_softc *sc,
-			     u8 dot11_rate);
+		       u8 dot11_rate);
 
 /* Routines to register/unregister rate control algorithm */
 int ath_rate_control_register(void);
diff --git a/drivers/net/wireless/ath9k/recv.c b/drivers/net/wireless/ath9k/recv.c
index 20ddb7a..4983402 100644
--- a/drivers/net/wireless/ath9k/recv.c
+++ b/drivers/net/wireless/ath9k/recv.c
@@ -184,7 +184,7 @@
 		tid = qc[0] & 0xf;
 	}
 
-	if (sc->sc_opmode == ATH9K_M_STA) {
+	if (sc->sc_ah->ah_opmode == ATH9K_M_STA) {
 		/* Drop the frame not belonging to me. */
 		if (memcmp(hdr->addr1, sc->sc_myaddr, ETH_ALEN)) {
 			dev_kfree_skb(skb);
@@ -449,17 +449,16 @@
 	int type;
 
 	/* indicate frame to the stack, which will free the old skb. */
-	type = ath__rx_indicate(sc, skb, status, keyix);
+	type = _ath_rx_indicate(sc, skb, status, keyix);
 
 	/* allocate a new skb and queue it to for H/W processing */
 	nskb = ath_rxbuf_alloc(sc, sc->sc_rxbufsize);
 	if (nskb != NULL) {
 		bf->bf_mpdu = nskb;
-		bf->bf_buf_addr = ath_skb_map_single(sc,
-			nskb,
-			PCI_DMA_FROMDEVICE,
-			/* XXX: Remove get_dma_mem_context() */
-			get_dma_mem_context(bf, bf_dmacontext));
+		bf->bf_buf_addr = pci_map_single(sc->pdev, nskb->data,
+					 skb_end_pointer(nskb) - nskb->head,
+					 PCI_DMA_FROMDEVICE);
+		bf->bf_dmacontext = bf->bf_buf_addr;
 		ATH_RX_CONTEXT(nskb)->ctx_rxbuf = bf;
 
 		/* queue the new wbuf to H/W */
@@ -505,7 +504,7 @@
 
 	do {
 		spin_lock_init(&sc->sc_rxflushlock);
-		sc->sc_rxflush = 0;
+		sc->sc_flags &= ~SC_OP_RXFLUSH;
 		spin_lock_init(&sc->sc_rxbuflock);
 
 		/*
@@ -542,9 +541,10 @@
 			}
 
 			bf->bf_mpdu = skb;
-			bf->bf_buf_addr =
-				ath_skb_map_single(sc, skb, PCI_DMA_FROMDEVICE,
-				       get_dma_mem_context(bf, bf_dmacontext));
+			bf->bf_buf_addr = pci_map_single(sc->pdev, skb->data,
+					 skb_end_pointer(skb) - skb->head,
+					 PCI_DMA_FROMDEVICE);
+			bf->bf_dmacontext = bf->bf_buf_addr;
 			ATH_RX_CONTEXT(skb)->ctx_rxbuf = bf;
 		}
 		sc->sc_rxlink = NULL;
@@ -598,6 +598,7 @@
 u32 ath_calcrxfilter(struct ath_softc *sc)
 {
 #define	RX_FILTER_PRESERVE (ATH9K_RX_FILTER_PHYERR | ATH9K_RX_FILTER_PHYRADAR)
+
 	u32 rfilt;
 
 	rfilt = (ath9k_hw_getrxfilter(sc->sc_ah) & RX_FILTER_PRESERVE)
@@ -605,25 +606,29 @@
 		| ATH9K_RX_FILTER_MCAST;
 
 	/* If not a STA, enable processing of Probe Requests */
-	if (sc->sc_opmode != ATH9K_M_STA)
+	if (sc->sc_ah->ah_opmode != ATH9K_M_STA)
 		rfilt |= ATH9K_RX_FILTER_PROBEREQ;
 
 	/* Can't set HOSTAP into promiscous mode */
-	if (sc->sc_opmode == ATH9K_M_MONITOR) {
+	if (((sc->sc_ah->ah_opmode != ATH9K_M_HOSTAP) &&
+	     (sc->rx_filter & FIF_PROMISC_IN_BSS)) ||
+	    (sc->sc_ah->ah_opmode == ATH9K_M_MONITOR)) {
 		rfilt |= ATH9K_RX_FILTER_PROM;
 		/* ??? To prevent from sending ACK */
 		rfilt &= ~ATH9K_RX_FILTER_UCAST;
 	}
 
-	if (sc->sc_opmode == ATH9K_M_STA || sc->sc_opmode == ATH9K_M_IBSS ||
-	    sc->sc_scanning)
+	if (((sc->sc_ah->ah_opmode == ATH9K_M_STA) &&
+	     (sc->rx_filter & FIF_BCN_PRBRESP_PROMISC)) ||
+	    (sc->sc_ah->ah_opmode == ATH9K_M_IBSS))
 		rfilt |= ATH9K_RX_FILTER_BEACON;
 
 	/* If in HOSTAP mode, want to enable reception of PSPOLL frames
 	   & beacon frames */
-	if (sc->sc_opmode == ATH9K_M_HOSTAP)
+	if (sc->sc_ah->ah_opmode == ATH9K_M_HOSTAP)
 		rfilt |= (ATH9K_RX_FILTER_BEACON | ATH9K_RX_FILTER_PSPOLL);
 	return rfilt;
+
 #undef RX_FILTER_PRESERVE
 }
 
@@ -703,11 +708,11 @@
 	 * progress (see references to sc_rxflush)
 	 */
 	spin_lock_bh(&sc->sc_rxflushlock);
-	sc->sc_rxflush = 1;
+	sc->sc_flags |= SC_OP_RXFLUSH;
 
 	ath_rx_tasklet(sc, 1);
 
-	sc->sc_rxflush = 0;
+	sc->sc_flags &= ~SC_OP_RXFLUSH;
 	spin_unlock_bh(&sc->sc_rxflushlock);
 }
 
@@ -720,7 +725,7 @@
 		 struct ath_recv_status *rx_status,
 		 enum ATH_RX_TYPE *status)
 {
-	if (is_ampdu && sc->sc_rxaggr) {
+	if (is_ampdu && (sc->sc_flags & SC_OP_RXAGGR)) {
 		*status = ATH_RX_CONSUMED;
 		return ath_ampdu_input(sc, an, skb, rx_status);
 	} else {
@@ -751,7 +756,7 @@
 
 	do {
 		/* If handling rx interrupt and flush is in progress => exit */
-		if (sc->sc_rxflush && (flush == 0))
+		if ((sc->sc_flags & SC_OP_RXFLUSH) && (flush == 0))
 			break;
 
 		spin_lock_bh(&sc->sc_rxbuflock);
@@ -887,7 +892,7 @@
 
 		hdr = (struct ieee80211_hdr *)skb->data;
 		fc = hdr->frame_control;
-		memzero(&rx_status, sizeof(struct ath_recv_status));
+		memset(&rx_status, 0, sizeof(struct ath_recv_status));
 
 		if (ds->ds_rxstat.rs_more) {
 			/*
@@ -901,7 +906,7 @@
 			 * Enable this if you want to see
 			 * error frames in Monitor mode.
 			 */
-			if (sc->sc_opmode != ATH9K_M_MONITOR)
+			if (sc->sc_ah->ah_opmode != ATH9K_M_MONITOR)
 				goto rx_next;
 #endif
 			/* fall thru for monitor mode handling... */
@@ -946,7 +951,7 @@
 			 * decryption and MIC failures. For monitor mode,
 			 * we also ignore the CRC error.
 			 */
-			if (sc->sc_opmode == ATH9K_M_MONITOR) {
+			if (sc->sc_ah->ah_opmode == ATH9K_M_MONITOR) {
 				if (ds->ds_rxstat.rs_status &
 				    ~(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC |
 					ATH9K_RXERR_CRC))
@@ -994,20 +999,11 @@
 				rx_status.flags |= ATH_RX_SHORT_GI;
 		}
 
-		/* sc->sc_noise_floor is only available when the station
+		/* sc_noise_floor is only available when the station
 		   attaches to an AP, so we use a default value
 		   if we are not yet attached. */
-
-		/* XXX we should use either sc->sc_noise_floor or
-		 * ath_hal_getChanNoise(ah, &sc->sc_curchan)
-		 * to calculate the noise floor.
-		 * However, the value returned by ath_hal_getChanNoise
-		 * seems to be incorrect (-31dBm on the last test),
-		 * so we will use a hard-coded value until we
-		 * figure out what is going on.
-		 */
 		rx_status.abs_rssi =
-			ds->ds_rxstat.rs_rssi + ATH_DEFAULT_NOISE_FLOOR;
+			ds->ds_rxstat.rs_rssi + sc->sc_ani.sc_noise_floor;
 
 		pci_dma_sync_single_for_cpu(sc->pdev,
 					    bf->bf_buf_addr,
@@ -1090,7 +1086,7 @@
 			"%s: Reset rx chain mask. "
 			"Do internal reset\n", __func__);
 		ASSERT(flush == 0);
-		ath_internal_reset(sc);
+		ath_reset(sc, false);
 	}
 
 	return 0;
@@ -1128,7 +1124,7 @@
 	rxtid = &an->an_aggr.rx.tid[tid];
 
 	spin_lock_bh(&rxtid->tidlock);
-	if (sc->sc_rxaggr) {
+	if (sc->sc_flags & SC_OP_RXAGGR) {
 		/* Allow aggregation reception
 		 * Adjust rx BA window size. Peer might indicate a
 		 * zero buffer size for a _dont_care_ condition.
@@ -1161,7 +1157,7 @@
 		} else {
 			/* Ensure the memory is zeroed out (all internal
 			 * pointers are null) */
-			memzero(rxtid->rxbuf, ATH_TID_MAX_BUFS *
+			memset(rxtid->rxbuf, 0, ATH_TID_MAX_BUFS *
 				sizeof(struct ath_rxbuf));
 			DPRINTF(sc, ATH_DBG_AGGR,
 				"%s: Allocated @%p\n", __func__, rxtid->rxbuf);
@@ -1228,7 +1224,7 @@
 
 void ath_rx_node_init(struct ath_softc *sc, struct ath_node *an)
 {
-	if (sc->sc_rxaggr) {
+	if (sc->sc_flags & SC_OP_RXAGGR) {
 		struct ath_arx_tid *rxtid;
 		int tidno;
 
@@ -1260,7 +1256,7 @@
 
 void ath_rx_node_cleanup(struct ath_softc *sc, struct ath_node *an)
 {
-	if (sc->sc_rxaggr) {
+	if (sc->sc_flags & SC_OP_RXAGGR) {
 		struct ath_arx_tid *rxtid;
 		int tidno, i;
 
@@ -1293,27 +1289,3 @@
 {
 	ath_rx_node_cleanup(sc, an);
 }
-
-dma_addr_t ath_skb_map_single(struct ath_softc *sc,
-			      struct sk_buff *skb,
-			      int direction,
-			      dma_addr_t *pa)
-{
-	/*
-	 * NB: do NOT use skb->len, which is 0 on initialization.
-	 * Use skb's entire data area instead.
-	 */
-	*pa = pci_map_single(sc->pdev, skb->data,
-		skb_end_pointer(skb) - skb->head, direction);
-	return *pa;
-}
-
-void ath_skb_unmap_single(struct ath_softc *sc,
-			  struct sk_buff *skb,
-			  int direction,
-			  dma_addr_t *pa)
-{
-	/* Unmap skb's entire data area */
-	pci_unmap_single(sc->pdev, *pa,
-		skb_end_pointer(skb) - skb->head, direction);
-}
diff --git a/drivers/net/wireless/ath9k/reg.h b/drivers/net/wireless/ath9k/reg.h
index 42b0890..60617ae 100644
--- a/drivers/net/wireless/ath9k/reg.h
+++ b/drivers/net/wireless/ath9k/reg.h
@@ -899,12 +899,6 @@
 #define AR_GPIO_OUTPUT_MUX2                      0x4064
 #define AR_GPIO_OUTPUT_MUX3                      0x4068
 
-#define AR_GPIO_OUTPUT_MUX_AS_OUTPUT             0
-#define AR_GPIO_OUTPUT_MUX_AS_PCIE_ATTENTION_LED 1
-#define AR_GPIO_OUTPUT_MUX_AS_PCIE_POWER_LED     2
-#define AR_GPIO_OUTPUT_MUX_AS_MAC_NETWORK_LED    5
-#define AR_GPIO_OUTPUT_MUX_AS_MAC_POWER_LED      6
-
 #define AR_INPUT_STATE                           0x406c
 
 #define AR_EEPROM_STATUS_DATA                    0x407c
diff --git a/drivers/net/wireless/ath9k/xmit.c b/drivers/net/wireless/ath9k/xmit.c
index 550129f..3a47579 100644
--- a/drivers/net/wireless/ath9k/xmit.c
+++ b/drivers/net/wireless/ath9k/xmit.c
@@ -60,79 +60,6 @@
 #define IS_HT_RATE(_rate)     ((_rate) & 0x80)
 
 /*
- * Insert a chain of ath_buf (descriptors) on a multicast txq
- * but do NOT start tx DMA on this queue.
- * NB: must be called with txq lock held
- */
-
-static void ath_tx_mcastqaddbuf(struct ath_softc *sc,
-				struct ath_txq *txq,
-				struct list_head *head)
-{
-	struct ath_hal *ah = sc->sc_ah;
-	struct ath_buf *bf;
-
-	if (list_empty(head))
-		return;
-
-	/*
-	 * Insert the frame on the outbound list and
-	 * pass it on to the hardware.
-	 */
-	bf = list_first_entry(head, struct ath_buf, list);
-
-	/*
-	 * The CAB queue is started from the SWBA handler since
-	 * frames only go out on DTIM and to avoid possible races.
-	 */
-	ath9k_hw_set_interrupts(ah, 0);
-
-	/*
-	 * If there is anything in the mcastq, we want to set
-	 * the "more data" bit in the last item in the queue to
-	 * indicate that there is "more data". It makes sense to add
-	 * it here since you are *always* going to have
-	 * more data when adding to this queue, no matter where
-	 * you call from.
-	 */
-
-	if (txq->axq_depth) {
-		struct ath_buf *lbf;
-		struct ieee80211_hdr *hdr;
-
-		/*
-		 * Add the "more data flag" to the last frame
-		 */
-
-		lbf = list_entry(txq->axq_q.prev, struct ath_buf, list);
-		hdr = (struct ieee80211_hdr *)
-			((struct sk_buff *)(lbf->bf_mpdu))->data;
-		hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREDATA);
-	}
-
-	/*
-	 * Now, concat the frame onto the queue
-	 */
-	list_splice_tail_init(head, &txq->axq_q);
-	txq->axq_depth++;
-	txq->axq_totalqueued++;
-	txq->axq_linkbuf = list_entry(txq->axq_q.prev, struct ath_buf, list);
-
-	DPRINTF(sc, ATH_DBG_QUEUE,
-		"%s: txq depth = %d\n", __func__, txq->axq_depth);
-	if (txq->axq_link != NULL) {
-		*txq->axq_link = bf->bf_daddr;
-		DPRINTF(sc, ATH_DBG_XMIT,
-			"%s: link[%u](%p)=%llx (%p)\n",
-			__func__,
-			txq->axq_qnum, txq->axq_link,
-			ito64(bf->bf_daddr), bf->bf_desc);
-	}
-	txq->axq_link = &(bf->bf_lastbf->bf_desc->ds_link);
-	ath9k_hw_set_interrupts(ah, sc->sc_imask);
-}
-
-/*
  * Insert a chain of ath_buf (descriptors) on a txq and
  * assume the descriptors are already chained together by caller.
  * NB: must be called with txq lock held
@@ -277,8 +204,6 @@
 	__le16 fc;
 	u8 *qc;
 
-	memset(txctl, 0, sizeof(struct ath_tx_control));
-
 	txctl->dev = sc;
 	hdr = (struct ieee80211_hdr *)skb->data;
 	hdrlen = ieee80211_get_hdrlen_from_skb(skb);
@@ -302,7 +227,6 @@
 	}
 
 	txctl->if_id = 0;
-	txctl->nextfraglen = 0;
 	txctl->frmlen = skb->len + FCS_LEN - (hdrlen & 3);
 	txctl->txpower = MAX_RATE_POWER; /* FIXME */
 
@@ -313,13 +237,13 @@
 
 	if (tx_info->control.hw_key) {
 		txctl->keyix = tx_info->control.hw_key->hw_key_idx;
-		txctl->frmlen += tx_info->control.icv_len;
+		txctl->frmlen += tx_info->control.hw_key->icv_len;
 
-		if (sc->sc_keytype == ATH9K_CIPHER_WEP)
+		if (tx_info->control.hw_key->alg == ALG_WEP)
 			txctl->keytype = ATH9K_KEY_TYPE_WEP;
-		else if (sc->sc_keytype == ATH9K_CIPHER_TKIP)
+		else if (tx_info->control.hw_key->alg == ALG_TKIP)
 			txctl->keytype = ATH9K_KEY_TYPE_TKIP;
-		else if (sc->sc_keytype == ATH9K_CIPHER_AES_CCM)
+		else if (tx_info->control.hw_key->alg == ALG_CCMP)
 			txctl->keytype = ATH9K_KEY_TYPE_AES;
 	}
 
@@ -329,12 +253,18 @@
 
 	/* Fill qnum */
 
-	txctl->qnum = ath_get_hal_qnum(skb_get_queue_mapping(skb), sc);
-	txq = &sc->sc_txq[txctl->qnum];
+	if (unlikely(txctl->flags & ATH9K_TXDESC_CAB)) {
+		txctl->qnum = 0;
+		txq = sc->sc_cabq;
+	} else {
+		txctl->qnum = ath_get_hal_qnum(skb_get_queue_mapping(skb), sc);
+		txq = &sc->sc_txq[txctl->qnum];
+	}
 	spin_lock_bh(&txq->axq_lock);
 
 	/* Try to avoid running out of descriptors */
-	if (txq->axq_depth >= (ATH_TXBUF - 20)) {
+	if (txq->axq_depth >= (ATH_TXBUF - 20) &&
+	    !(txctl->flags & ATH9K_TXDESC_CAB)) {
 		DPRINTF(sc, ATH_DBG_FATAL,
 			"%s: TX queue: %d is full, depth: %d\n",
 			__func__,
@@ -354,7 +284,7 @@
 
 	/* Fill flags */
 
-	txctl->flags = ATH9K_TXDESC_CLRDMASK;    /* needed for crypto errors */
+	txctl->flags |= ATH9K_TXDESC_CLRDMASK; /* needed for crypto errors */
 
 	if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK)
 		txctl->flags |= ATH9K_TXDESC_NOACK;
@@ -392,7 +322,7 @@
 		 * incremented by the fragmentation routine.
 		 */
 		if (likely(!(txctl->flags & ATH9K_TXDESC_FRAG_IS_ON)) &&
-			txctl->ht && sc->sc_txaggr) {
+		    txctl->ht && (sc->sc_flags & SC_OP_TXAGGR)) {
 			struct ath_atx_tid *tid;
 
 			tid = ATH_AN_2_TID(txctl->an, txctl->tidno);
@@ -413,50 +343,18 @@
 	}
 	rix = rcs[0].rix;
 
-	/*
-	 * Calculate duration.  This logically belongs in the 802.11
-	 * layer but it lacks sufficient information to calculate it.
-	 */
-	if ((txctl->flags & ATH9K_TXDESC_NOACK) == 0 && !ieee80211_is_ctl(fc)) {
-		u16 dur;
+	if (ieee80211_has_morefrags(fc) ||
+	    (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG)) {
 		/*
-		 * XXX not right with fragmentation.
-		 */
-		if (sc->sc_flags & ATH_PREAMBLE_SHORT)
-			dur = rt->info[rix].spAckDuration;
-		else
-			dur = rt->info[rix].lpAckDuration;
-
-		if (le16_to_cpu(hdr->frame_control) &
-				IEEE80211_FCTL_MOREFRAGS) {
-			dur += dur;  /* Add additional 'SIFS + ACK' */
-
-			/*
-			** Compute size of next fragment in order to compute
-			** durations needed to update NAV.
-			** The last fragment uses the ACK duration only.
-			** Add time for next fragment.
-			*/
-			dur += ath9k_hw_computetxtime(sc->sc_ah, rt,
-					txctl->nextfraglen,
-					rix, sc->sc_flags & ATH_PREAMBLE_SHORT);
-		}
-
-		if (ieee80211_has_morefrags(fc) ||
-		     (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG)) {
-			/*
-			**  Force hardware to use computed duration for next
-			**  fragment by disabling multi-rate retry, which
-			**  updates duration based on the multi-rate
-			**  duration table.
-			*/
-			rcs[1].tries = rcs[2].tries = rcs[3].tries = 0;
-			rcs[1].rix = rcs[2].rix = rcs[3].rix = 0;
-			/* reset tries but keep rate index */
-			rcs[0].tries = ATH_TXMAXTRY;
-		}
-
-		hdr->duration_id = cpu_to_le16(dur);
+		**  Force hardware to use computed duration for next
+		**  fragment by disabling multi-rate retry, which
+		**  updates duration based on the multi-rate
+		**  duration table.
+		*/
+		rcs[1].tries = rcs[2].tries = rcs[3].tries = 0;
+		rcs[1].rix = rcs[2].rix = rcs[3].rix = 0;
+		/* reset tries but keep rate index */
+		rcs[0].tries = ATH_TXMAXTRY;
 	}
 
 	/*
@@ -484,12 +382,8 @@
 	if (is_multicast_ether_addr(hdr->addr1)) {
 		antenna = sc->sc_mcastantenna + 1;
 		sc->sc_mcastantenna = (sc->sc_mcastantenna + 1) & 0x1;
-	} else
-		antenna = sc->sc_txantenna;
+	}
 
-#ifdef USE_LEGACY_HAL
-	txctl->antenna = antenna;
-#endif
 	return 0;
 }
 
@@ -502,7 +396,6 @@
 {
 	struct sk_buff *skb = bf->bf_mpdu;
 	struct ath_xmit_status tx_status;
-	dma_addr_t *pa;
 
 	/*
 	 * Set retry information.
@@ -518,13 +411,12 @@
 	if (!txok) {
 		tx_status.flags |= ATH_TX_ERROR;
 
-		if (bf->bf_isxretried)
+		if (bf_isxretried(bf))
 			tx_status.flags |= ATH_TX_XRETRY;
 	}
 	/* Unmap this frame */
-	pa = get_dma_mem_context(bf, bf_dmacontext);
 	pci_unmap_single(sc->pdev,
-			 *pa,
+			 bf->bf_dmacontext,
 			 skb->len,
 			 PCI_DMA_TODEVICE);
 	/* complete this frame */
@@ -629,7 +521,7 @@
 	if (isnodegone || ds->ds_txstat.ts_flags == ATH9K_TX_SW_ABORTED)
 		return 0;
 
-	isaggr = bf->bf_isaggr;
+	isaggr = bf_isaggr(bf);
 	if (isaggr) {
 		seq_st = ATH_DS_BA_SEQ(ds);
 		memcpy(ba, ATH_DS_BA_BITMAP(ds), WME_BA_BMP_SIZE >> 3);
@@ -651,7 +543,7 @@
 	struct sk_buff *skb;
 	struct ieee80211_hdr *hdr;
 
-	bf->bf_isretried = 1;
+	bf->bf_state.bf_type |= BUF_RETRY;
 	bf->bf_retries++;
 
 	skb = bf->bf_mpdu;
@@ -698,7 +590,7 @@
 	u8 rc;
 	int streams, pktlen;
 
-	pktlen = bf->bf_isaggr ? bf->bf_al : bf->bf_frmlen;
+	pktlen = bf_isaggr(bf) ? bf->bf_al : bf->bf_frmlen;
 	rc = rt->info[rix].rateCode;
 
 	/*
@@ -742,7 +634,7 @@
 	int i, flags, rtsctsena = 0, dynamic_mimops = 0;
 	u32 ctsduration = 0;
 	u8 rix = 0, cix, ctsrate = 0;
-	u32 aggr_limit_with_rts = sc->sc_rtsaggrlimit;
+	u32 aggr_limit_with_rts = ah->ah_caps.rts_aggr_limit;
 	struct ath_node *an = (struct ath_node *) bf->bf_node;
 
 	/*
@@ -781,7 +673,7 @@
 	 * let rate series flags determine which rates will actually
 	 * use RTS.
 	 */
-	if ((ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT) && bf->bf_isdata) {
+	if ((ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT) && bf_isdata(bf)) {
 		BUG_ON(!an);
 		/*
 		 * 802.11g protection not needed, use our default behavior
@@ -793,7 +685,7 @@
 		 * and the second aggregate should have any protection at all.
 		 */
 		if (an->an_smmode == ATH_SM_PWRSAV_DYNAMIC) {
-			if (!bf->bf_aggrburst) {
+			if (!bf_isaggrburst(bf)) {
 				flags = ATH9K_TXDESC_RTSENA;
 				dynamic_mimops = 1;
 			} else {
@@ -806,7 +698,7 @@
 	 * Set protection if aggregate protection on
 	 */
 	if (sc->sc_config.ath_aggr_prot &&
-	    (!bf->bf_isaggr || (bf->bf_isaggr && bf->bf_al < 8192))) {
+	    (!bf_isaggr(bf) || (bf_isaggr(bf) && bf->bf_al < 8192))) {
 		flags = ATH9K_TXDESC_RTSENA;
 		cix = rt->info[sc->sc_protrix].controlRate;
 		rtsctsena = 1;
@@ -815,7 +707,7 @@
 	/*
 	 *  For AR5416 - RTS cannot be followed by a frame larger than 8K.
 	 */
-	if (bf->bf_isaggr && (bf->bf_al > aggr_limit_with_rts)) {
+	if (bf_isaggr(bf) && (bf->bf_al > aggr_limit_with_rts)) {
 		/*
 		 * Ensure that in the case of SM Dynamic power save
 		 * while we are bursting the second aggregate the
@@ -832,12 +724,12 @@
 	/* NB: cix is set above where RTS/CTS is enabled */
 	BUG_ON(cix == 0xff);
 	ctsrate = rt->info[cix].rateCode |
-		(bf->bf_shpreamble ? rt->info[cix].shortPreamble : 0);
+		(bf_isshpreamble(bf) ? rt->info[cix].shortPreamble : 0);
 
 	/*
 	 * Setup HAL rate series
 	 */
-	memzero(series, sizeof(struct ath9k_11n_rate_series) * 4);
+	memset(series, 0, sizeof(struct ath9k_11n_rate_series) * 4);
 
 	for (i = 0; i < 4; i++) {
 		if (!bf->bf_rcs[i].tries)
@@ -846,7 +738,7 @@
 		rix = bf->bf_rcs[i].rix;
 
 		series[i].Rate = rt->info[rix].rateCode |
-			(bf->bf_shpreamble ? rt->info[rix].shortPreamble : 0);
+			(bf_isshpreamble(bf) ? rt->info[rix].shortPreamble : 0);
 
 		series[i].Tries = bf->bf_rcs[i].tries;
 
@@ -862,7 +754,7 @@
 			sc, rix, bf,
 			(bf->bf_rcs[i].flags & ATH_RC_CW40_FLAG) != 0,
 			(bf->bf_rcs[i].flags & ATH_RC_SGI_FLAG),
-			bf->bf_shpreamble);
+			bf_isshpreamble(bf));
 
 		if ((an->an_smmode == ATH_SM_PWRSAV_STATIC) &&
 		    (bf->bf_rcs[i].flags & ATH_RC_DS_FLAG) == 0) {
@@ -875,7 +767,7 @@
 			 */
 			series[i].ChSel = sc->sc_tx_chainmask;
 		} else {
-			if (bf->bf_ht)
+			if (bf_isht(bf))
 				series[i].ChSel =
 					ath_chainmask_sel_logic(sc, an);
 			else
@@ -908,7 +800,7 @@
 		 *     use the precalculated ACK durations.
 		 */
 		if (flags & ATH9K_TXDESC_RTSENA) {    /* SIFS + CTS */
-			ctsduration += bf->bf_shpreamble ?
+			ctsduration += bf_isshpreamble(bf) ?
 				rt->info[cix].spAckDuration :
 				rt->info[cix].lpAckDuration;
 		}
@@ -916,7 +808,7 @@
 		ctsduration += series[0].PktDuration;
 
 		if ((bf->bf_flags & ATH9K_TXDESC_NOACK) == 0) { /* SIFS + ACK */
-			ctsduration += bf->bf_shpreamble ?
+			ctsduration += bf_isshpreamble(bf) ?
 				rt->info[rix].spAckDuration :
 				rt->info[rix].lpAckDuration;
 		}
@@ -925,17 +817,17 @@
 		 * Disable multi-rate retry when using RTS/CTS by clearing
 		 * series 1, 2 and 3.
 		 */
-		memzero(&series[1], sizeof(struct ath9k_11n_rate_series) * 3);
+		memset(&series[1], 0, sizeof(struct ath9k_11n_rate_series) * 3);
 	}
 
 	/*
 	 * set dur_update_en for l-sig computation except for PS-Poll frames
 	 */
 	ath9k_hw_set11n_ratescenario(ah, ds, lastds,
-				    !bf->bf_ispspoll,
-				    ctsrate,
-				    ctsduration,
-				    series, 4, flags);
+				     !bf_ispspoll(bf),
+				     ctsrate,
+				     ctsduration,
+				     series, 4, flags);
 	if (sc->sc_config.ath_aggr_prot && flags)
 		ath9k_hw_set11n_burstduration(ah, ds, 8192);
 }
@@ -958,7 +850,7 @@
 	BUG_ON(list_empty(bf_head));
 
 	bf = list_first_entry(bf_head, struct ath_buf, list);
-	bf->bf_isampdu = 0; /* regular HT frame */
+	bf->bf_state.bf_type &= ~BUF_AMPDU; /* regular HT frame */
 
 	skb = (struct sk_buff *)bf->bf_mpdu;
 	tx_info = IEEE80211_SKB_CB(skb);
@@ -998,7 +890,7 @@
 
 	while (!list_empty(&tid->buf_q)) {
 		bf = list_first_entry(&tid->buf_q, struct ath_buf, list);
-		ASSERT(!bf->bf_isretried);
+		ASSERT(!bf_isretried(bf));
 		list_cut_position(&bf_head, &tid->buf_q, &bf->bf_lastfrm->list);
 		ath_tx_send_normal(sc, txq, tid, &bf_head);
 	}
@@ -1025,7 +917,7 @@
 	int isaggr, txfail, txpending, sendbar = 0, needreset = 0;
 	int isnodegone = (an->an_flags & ATH_NODE_CLEAN);
 
-	isaggr = bf->bf_isaggr;
+	isaggr = bf_isaggr(bf);
 	if (isaggr) {
 		if (txok) {
 			if (ATH_DS_TX_BA(ds)) {
@@ -1038,7 +930,7 @@
 					ATH_DS_BA_BITMAP(ds),
 					WME_BA_BMP_SIZE >> 3);
 			} else {
-				memzero(ba, WME_BA_BMP_SIZE >> 3);
+				memset(ba, 0, WME_BA_BMP_SIZE >> 3);
 
 				/*
 				 * AR5416 can become deaf/mute when BA
@@ -1047,11 +939,11 @@
 				 * when perform internal reset in this routine.
 				 * Only enable reset in STA mode for now.
 				 */
-				if (sc->sc_opmode == ATH9K_M_STA)
+				if (sc->sc_ah->ah_opmode == ATH9K_M_STA)
 					needreset = 1;
 			}
 		} else {
-			memzero(ba, WME_BA_BMP_SIZE >> 3);
+			memset(ba, 0, WME_BA_BMP_SIZE >> 3);
 		}
 	}
 
@@ -1075,7 +967,7 @@
 					ath_tx_set_retry(sc, bf);
 					txpending = 1;
 				} else {
-					bf->bf_isxretried = 1;
+					bf->bf_state.bf_type |= BUF_XRETRY;
 					txfail = 1;
 					sendbar = 1;
 				}
@@ -1175,11 +1067,8 @@
 						tbf->bf_lastfrm->bf_desc);
 
 					/* copy the DMA context */
-					copy_dma_mem_context(
-						get_dma_mem_context(tbf,
-							bf_dmacontext),
-						get_dma_mem_context(bf_last,
-							bf_dmacontext));
+					tbf->bf_dmacontext =
+						bf_last->bf_dmacontext;
 				}
 				list_add_tail(&tbf->list, &bf_head);
 			} else {
@@ -1188,7 +1077,7 @@
 				 * software retry
 				 */
 				ath9k_hw_cleartxdesc(sc->sc_ah,
-					bf->bf_lastfrm->bf_desc);
+						     bf->bf_lastfrm->bf_desc);
 			}
 
 			/*
@@ -1242,7 +1131,7 @@
 	}
 
 	if (needreset)
-		ath_internal_reset(sc);
+		ath_reset(sc, false);
 
 	return;
 }
@@ -1331,7 +1220,7 @@
 
 		txq->axq_depth--;
 
-		if (bf->bf_isaggr)
+		if (bf_isaggr(bf))
 			txq->axq_aggr_depth--;
 
 		txok = (ds->ds_txstat.ts_status == 0);
@@ -1345,14 +1234,14 @@
 			spin_unlock_bh(&sc->sc_txbuflock);
 		}
 
-		if (!bf->bf_isampdu) {
+		if (!bf_isampdu(bf)) {
 			/*
 			 * This frame is sent out as a single frame.
 			 * Use hardware retry status for this frame.
 			 */
 			bf->bf_retries = ds->ds_txstat.ts_longretry;
 			if (ds->ds_txstat.ts_status & ATH9K_TXERR_XRETRY)
-				bf->bf_isxretried = 1;
+				bf->bf_state.bf_type |= BUF_XRETRY;
 			nbad = 0;
 		} else {
 			nbad = ath_tx_num_badfrms(sc, bf, txok);
@@ -1368,7 +1257,7 @@
 			if (ds->ds_txstat.ts_status == 0)
 				nacked++;
 
-			if (bf->bf_isdata) {
+			if (bf_isdata(bf)) {
 				if (isrifs)
 					tmp_ds = bf->bf_rifslast->bf_desc;
 				else
@@ -1384,7 +1273,7 @@
 		/*
 		 * Complete this transmit unit
 		 */
-		if (bf->bf_isampdu)
+		if (bf_isampdu(bf))
 			ath_tx_complete_aggr_rifs(sc, txq, bf, &bf_head, txok);
 		else
 			ath_tx_complete_buf(sc, bf, &bf_head, txok, 0);
@@ -1406,7 +1295,7 @@
 		/*
 		 * schedule any pending packets if aggregation is enabled
 		 */
-		if (sc->sc_txaggr)
+		if (sc->sc_flags & SC_OP_TXAGGR)
 			ath_txq_schedule(sc, txq);
 		spin_unlock_bh(&txq->axq_lock);
 	}
@@ -1430,10 +1319,9 @@
 	struct ath_hal *ah = sc->sc_ah;
 	int i;
 	int npend = 0;
-	enum ath9k_ht_macmode ht_macmode = ath_cwm_macmode(sc);
 
 	/* XXX return value */
-	if (!sc->sc_invalid) {
+	if (!(sc->sc_flags & SC_OP_INVALID)) {
 		for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
 			if (ATH_TXQ_SETUP(sc, i)) {
 				ath_tx_stopdma(sc, &sc->sc_txq[i]);
@@ -1454,10 +1342,11 @@
 			"%s: Unable to stop TxDMA. Reset HAL!\n", __func__);
 
 		spin_lock_bh(&sc->sc_resetlock);
-		if (!ath9k_hw_reset(ah, sc->sc_opmode,
-			&sc->sc_curchan, ht_macmode,
-			sc->sc_tx_chainmask, sc->sc_rx_chainmask,
-			sc->sc_ht_extprotspacing, true, &status)) {
+		if (!ath9k_hw_reset(ah,
+				    sc->sc_ah->ah_curchan,
+				    sc->sc_ht_info.tx_chan_width,
+				    sc->sc_tx_chainmask, sc->sc_rx_chainmask,
+				    sc->sc_ht_extprotspacing, true, &status)) {
 
 			DPRINTF(sc, ATH_DBG_FATAL,
 				"%s: unable to reset hardware; hal status %u\n",
@@ -1481,7 +1370,7 @@
 {
 	int index, cindex;
 
-	if (bf->bf_isretried)
+	if (bf_isretried(bf))
 		return;
 
 	index  = ATH_BA_INDEX(tid->seq_start, bf->bf_seqno);
@@ -1516,7 +1405,7 @@
 	BUG_ON(list_empty(bf_head));
 
 	bf = list_first_entry(bf_head, struct ath_buf, list);
-	bf->bf_isampdu = 1;
+	bf->bf_state.bf_type |= BUF_AMPDU;
 	bf->bf_seqno = txctl->seqno; /* save seqno and tidno in buffer */
 	bf->bf_tidno = txctl->tidno;
 
@@ -1860,7 +1749,7 @@
 		if (bf->bf_nframes == 1) {
 			ASSERT(bf->bf_lastfrm == bf_last);
 
-			bf->bf_isaggr = 0;
+			bf->bf_state.bf_type &= ~BUF_AGGR;
 			/*
 			 * clear aggr bits for every descriptor
 			 * XXX TODO: is there a way to optimize it?
@@ -1877,7 +1766,7 @@
 		/*
 		 * setup first desc with rate and aggr info
 		 */
-		bf->bf_isaggr  = 1;
+		bf->bf_state.bf_type |= BUF_AGGR;
 		ath_buf_set_rate(sc, bf);
 		ath9k_hw_set11n_aggr_first(sc->sc_ah, bf->bf_desc, bf->bf_al);
 
@@ -1925,7 +1814,7 @@
 		list_cut_position(&bf_head, &tid->buf_q, &bf->bf_lastfrm->list);
 
 		/* update baw for software retried frame */
-		if (bf->bf_isretried)
+		if (bf_isretried(bf))
 			ath_tx_update_baw(sc, tid, bf->bf_seqno);
 
 		/*
@@ -1990,13 +1879,18 @@
 	struct list_head bf_head;
 	struct ath_desc *ds;
 	struct ath_hal *ah = sc->sc_ah;
-	struct ath_txq *txq = &sc->sc_txq[txctl->qnum];
+	struct ath_txq *txq;
 	struct ath_tx_info_priv *tx_info_priv;
 	struct ath_rc_series *rcs;
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
 	struct ieee80211_tx_info *tx_info =  IEEE80211_SKB_CB(skb);
 	__le16 fc = hdr->frame_control;
 
+	if (unlikely(txctl->flags & ATH9K_TXDESC_CAB))
+		txq = sc->sc_cabq;
+	else
+		txq = &sc->sc_txq[txctl->qnum];
+
 	/* For each sglist entry, allocate an ath_buf for DMA */
 	INIT_LIST_HEAD(&bf_head);
 	spin_lock_bh(&sc->sc_txbuflock);
@@ -2014,11 +1908,21 @@
 	/* set up this buffer */
 	ATH_TXBUF_RESET(bf);
 	bf->bf_frmlen = txctl->frmlen;
-	bf->bf_isdata = ieee80211_is_data(fc);
-	bf->bf_isbar = ieee80211_is_back_req(fc);
-	bf->bf_ispspoll = ieee80211_is_pspoll(fc);
+
+	ieee80211_is_data(fc) ?
+		(bf->bf_state.bf_type |= BUF_DATA) :
+		(bf->bf_state.bf_type &= ~BUF_DATA);
+	ieee80211_is_back_req(fc) ?
+		(bf->bf_state.bf_type |= BUF_BAR) :
+		(bf->bf_state.bf_type &= ~BUF_BAR);
+	ieee80211_is_pspoll(fc) ?
+		(bf->bf_state.bf_type |= BUF_PSPOLL) :
+		(bf->bf_state.bf_type &= ~BUF_PSPOLL);
+	(sc->sc_flags & SC_OP_PREAMBLE_SHORT) ?
+		(bf->bf_state.bf_type |= BUF_SHORT_PREAMBLE) :
+		(bf->bf_state.bf_type &= ~BUF_SHORT_PREAMBLE);
+
 	bf->bf_flags = txctl->flags;
-	bf->bf_shpreamble = sc->sc_flags & ATH_PREAMBLE_SHORT;
 	bf->bf_keytype = txctl->keytype;
 	tx_info_priv = (struct ath_tx_info_priv *)tx_info->driver_data[0];
 	rcs = tx_info_priv->rcs;
@@ -2038,8 +1942,7 @@
 	/*
 	 * Save the DMA context in the first ath_buf
 	 */
-	copy_dma_mem_context(get_dma_mem_context(bf, bf_dmacontext),
-			     get_dma_mem_context(txctl, dmacontext));
+	bf->bf_dmacontext = txctl->dmacontext;
 
 	/*
 	 * Formulate first tx descriptor with tx controls.
@@ -2060,11 +1963,13 @@
 			    ds);                /* first descriptor */
 
 	bf->bf_lastfrm = bf;
-	bf->bf_ht = txctl->ht;
+	(txctl->ht) ?
+		(bf->bf_state.bf_type |= BUF_HT) :
+		(bf->bf_state.bf_type &= ~BUF_HT);
 
 	spin_lock_bh(&txq->axq_lock);
 
-	if (txctl->ht && sc->sc_txaggr) {
+	if (txctl->ht && (sc->sc_flags & SC_OP_TXAGGR)) {
 		struct ath_atx_tid *tid = ATH_AN_2_TID(an, txctl->tidno);
 		if (ath_aggr_query(sc, an, txctl->tidno)) {
 			/*
@@ -2090,27 +1995,7 @@
 			bf->bf_tidno = txctl->tidno;
 		}
 
-		if (is_multicast_ether_addr(hdr->addr1)) {
-			struct ath_vap *avp = sc->sc_vaps[txctl->if_id];
-
-			/*
-			 * When servicing one or more stations in power-save
-			 * mode (or) if there is some mcast data waiting on
-			 * mcast queue (to prevent out of order delivery of
-			 * mcast,bcast packets) multicast frames must be
-			 * buffered until after the beacon. We use the private
-			 * mcast queue for that.
-			 */
-			/* XXX? more bit in 802.11 frame header */
-			spin_lock_bh(&avp->av_mcastq.axq_lock);
-			if (txctl->ps || avp->av_mcastq.axq_depth)
-				ath_tx_mcastqaddbuf(sc,
-					&avp->av_mcastq, &bf_head);
-			else
-				ath_tx_txqaddbuf(sc, txq, &bf_head);
-			spin_unlock_bh(&avp->av_mcastq.axq_lock);
-		} else
-			ath_tx_txqaddbuf(sc, txq, &bf_head);
+		ath_tx_txqaddbuf(sc, txq, &bf_head);
 	}
 	spin_unlock_bh(&txq->axq_lock);
 	return 0;
@@ -2118,30 +2003,31 @@
 
 static void xmit_map_sg(struct ath_softc *sc,
 			struct sk_buff *skb,
-			dma_addr_t *pa,
 			struct ath_tx_control *txctl)
 {
 	struct ath_xmit_status tx_status;
 	struct ath_atx_tid *tid;
 	struct scatterlist sg;
 
-	*pa = pci_map_single(sc->pdev, skb->data, skb->len, PCI_DMA_TODEVICE);
+	txctl->dmacontext = pci_map_single(sc->pdev, skb->data,
+					   skb->len, PCI_DMA_TODEVICE);
 
 	/* setup S/G list */
 	memset(&sg, 0, sizeof(struct scatterlist));
-	sg_dma_address(&sg) = *pa;
+	sg_dma_address(&sg) = txctl->dmacontext;
 	sg_dma_len(&sg) = skb->len;
 
 	if (ath_tx_start_dma(sc, skb, &sg, 1, txctl) != 0) {
 		/*
 		 *  We have to do drop frame here.
 		 */
-		pci_unmap_single(sc->pdev, *pa, skb->len, PCI_DMA_TODEVICE);
+		pci_unmap_single(sc->pdev, txctl->dmacontext,
+				 skb->len, PCI_DMA_TODEVICE);
 
 		tx_status.retries = 0;
 		tx_status.flags = ATH_TX_ERROR;
 
-		if (txctl->ht && sc->sc_txaggr) {
+		if (txctl->ht && (sc->sc_flags & SC_OP_TXAGGR)) {
 			/* Reclaim the seqno. */
 			tid = ATH_AN_2_TID((struct ath_node *)
 				txctl->an, txctl->tidno);
@@ -2162,7 +2048,7 @@
 
 		/* Setup tx descriptors */
 		error = ath_descdma_setup(sc, &sc->sc_txdma, &sc->sc_txbuf,
-			"tx", nbufs * ATH_FRAG_PER_MSDU, ATH_TXDESC);
+			"tx", nbufs, 1);
 		if (error != 0) {
 			DPRINTF(sc, ATH_DBG_FATAL,
 				"%s: failed to allocate tx descriptors: %d\n",
@@ -2212,7 +2098,7 @@
 	struct ath9k_tx_queue_info qi;
 	int qnum;
 
-	memzero(&qi, sizeof(qi));
+	memset(&qi, 0, sizeof(qi));
 	qi.tqi_subtype = subtype;
 	qi.tqi_aifs = ATH9K_TXQ_USEDEFAULT;
 	qi.tqi_cwmin = ATH9K_TXQ_USEDEFAULT;
@@ -2403,6 +2289,7 @@
 	struct ath_tx_control txctl;
 	int error = 0;
 
+	memset(&txctl, 0, sizeof(struct ath_tx_control));
 	error = ath_tx_prepare(sc, skb, &txctl);
 	if (error == 0)
 		/*
@@ -2410,9 +2297,7 @@
 		 * ath_tx_start_dma() will be called either synchronously
 		 * or asynchrounsly once DMA is complete.
 		 */
-		xmit_map_sg(sc, skb,
-			    get_dma_mem_context(&txctl, dmacontext),
-			    &txctl);
+		xmit_map_sg(sc, skb, &txctl);
 	else
 		ath_node_put(sc, txctl.an, ATH9K_BH_STATUS_CHANGE);
 
@@ -2424,8 +2309,7 @@
 
 void ath_tx_tasklet(struct ath_softc *sc)
 {
-	u64 tsf = ath9k_hw_gettsf64(sc->sc_ah);
-	int i, nacked = 0;
+	int i;
 	u32 qcumask = ((1 << ATH9K_NUM_TX_QUEUES) - 1);
 
 	ath9k_hw_gettxintrtxqs(sc->sc_ah, &qcumask);
@@ -2435,10 +2319,8 @@
 	 */
 	for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
 		if (ATH_TXQ_SETUP(sc, i) && (qcumask & (1 << i)))
-			nacked += ath_tx_processq(sc, &sc->sc_txq[i]);
+			ath_tx_processq(sc, &sc->sc_txq[i]);
 	}
-	if (nacked)
-		sc->sc_lastrx = tsf;
 }
 
 void ath_tx_draintxq(struct ath_softc *sc,
@@ -2486,14 +2368,14 @@
 
 		spin_unlock_bh(&txq->axq_lock);
 
-		if (bf->bf_isampdu)
+		if (bf_isampdu(bf))
 			ath_tx_complete_aggr_rifs(sc, txq, bf, &bf_head, 0);
 		else
 			ath_tx_complete_buf(sc, bf, &bf_head, 0, 0);
 	}
 
 	/* flush any pending frames if aggregation is enabled */
-	if (sc->sc_txaggr) {
+	if (sc->sc_flags & SC_OP_TXAGGR) {
 		if (!retry_tx) {
 			spin_lock_bh(&txq->axq_lock);
 			ath_txq_drain_pending_buffers(sc, txq,
@@ -2509,7 +2391,7 @@
 {
 	/* stop beacon queue. The beacon will be freed when
 	 * we go to INIT state */
-	if (!sc->sc_invalid) {
+	if (!(sc->sc_flags & SC_OP_INVALID)) {
 		(void) ath9k_hw_stoptxdma(sc->sc_ah, sc->sc_bhalq);
 		DPRINTF(sc, ATH_DBG_XMIT, "%s: beacon queue %x\n", __func__,
 			ath9k_hw_gettxbuf(sc->sc_ah, sc->sc_bhalq));
@@ -2536,7 +2418,7 @@
 	struct ath_atx_tid *txtid;
 	DECLARE_MAC_BUF(mac);
 
-	if (!sc->sc_txaggr)
+	if (!(sc->sc_flags & SC_OP_TXAGGR))
 		return AGGR_NOT_REQUIRED;
 
 	/* ADDBA exchange must be completed before sending aggregates */
@@ -2583,7 +2465,7 @@
 		return -1;
 	}
 
-	if (sc->sc_txaggr) {
+	if (sc->sc_flags & SC_OP_TXAGGR) {
 		txtid = ATH_AN_2_TID(an, tid);
 		txtid->addba_exchangeinprogress = 1;
 		ath_tx_pause_tid(sc, txtid);
@@ -2647,7 +2529,7 @@
 	spin_lock_bh(&txq->axq_lock);
 	while (!list_empty(&txtid->buf_q)) {
 		bf = list_first_entry(&txtid->buf_q, struct ath_buf, list);
-		if (!bf->bf_isretried) {
+		if (!bf_isretried(bf)) {
 			/*
 			 * NB: it's based on the assumption that
 			 * software retried frame will always stay
@@ -2743,7 +2625,7 @@
 
 void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an)
 {
-	if (sc->sc_txaggr) {
+	if (sc->sc_flags & SC_OP_TXAGGR) {
 		struct ath_atx_tid *tid;
 		struct ath_atx_ac *ac;
 		int tidno, acno;
@@ -2855,7 +2737,7 @@
 
 void ath_tx_node_free(struct ath_softc *sc, struct ath_node *an)
 {
-	if (sc->sc_txaggr) {
+	if (sc->sc_flags & SC_OP_TXAGGR) {
 		struct ath_atx_tid *tid;
 		int tidno, i;
 
@@ -2869,3 +2751,57 @@
 		}
 	}
 }
+
+void ath_tx_cabq(struct ath_softc *sc, struct sk_buff *skb)
+{
+	int hdrlen, padsize;
+	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+	struct ath_tx_control txctl;
+
+	/*
+	 * As a temporary workaround, assign seq# here; this will likely need
+	 * to be cleaned up to work better with Beacon transmission and virtual
+	 * BSSes.
+	 */
+	if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) {
+		struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+		if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT)
+			sc->seq_no += 0x10;
+		hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG);
+		hdr->seq_ctrl |= cpu_to_le16(sc->seq_no);
+	}
+
+	/* Add the padding after the header if this is not already done */
+	hdrlen = ieee80211_get_hdrlen_from_skb(skb);
+	if (hdrlen & 3) {
+		padsize = hdrlen % 4;
+		if (skb_headroom(skb) < padsize) {
+			DPRINTF(sc, ATH_DBG_XMIT, "%s: TX CABQ padding "
+				"failed\n", __func__);
+			dev_kfree_skb_any(skb);
+			return;
+		}
+		skb_push(skb, padsize);
+		memmove(skb->data, skb->data + padsize, hdrlen);
+	}
+
+	DPRINTF(sc, ATH_DBG_XMIT, "%s: transmitting CABQ packet, skb: %p\n",
+		__func__,
+		skb);
+
+	memset(&txctl, 0, sizeof(struct ath_tx_control));
+	txctl.flags = ATH9K_TXDESC_CAB;
+	if (ath_tx_prepare(sc, skb, &txctl) == 0) {
+		/*
+		 * Start DMA mapping.
+		 * ath_tx_start_dma() will be called either synchronously
+		 * or asynchrounsly once DMA is complete.
+		 */
+		xmit_map_sg(sc, skb, &txctl);
+	} else {
+		ath_node_put(sc, txctl.an, ATH9K_BH_STATUS_CHANGE);
+		DPRINTF(sc, ATH_DBG_XMIT, "%s: TX CABQ failed\n", __func__);
+		dev_kfree_skb_any(skb);
+	}
+}
+
diff --git a/drivers/net/wireless/atmel.c b/drivers/net/wireless/atmel.c
index bd65c48..ecb02bd 100644
--- a/drivers/net/wireless/atmel.c
+++ b/drivers/net/wireless/atmel.c
@@ -2258,7 +2258,7 @@
 
 static int atmel_set_scan(struct net_device *dev,
 			  struct iw_request_info *info,
-			  struct iw_param *vwrq,
+			  struct iw_point *dwrq,
 			  char *extra)
 {
 	struct atmel_private *priv = netdev_priv(dev);
diff --git a/drivers/net/wireless/atmel_cs.c b/drivers/net/wireless/atmel_cs.c
index 12617cd..7740624 100644
--- a/drivers/net/wireless/atmel_cs.c
+++ b/drivers/net/wireless/atmel_cs.c
@@ -158,7 +158,7 @@
 	DEBUG(0, "atmel_attach()\n");
 
 	/* Interrupt setup */
-	p_dev->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
+	p_dev->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING;
 	p_dev->irq.IRQInfo1 = IRQ_LEVEL_ID;
 	p_dev->irq.Handler = NULL;
 
@@ -224,13 +224,58 @@
 	return 0;
 }
 
+static int atmel_config_check(struct pcmcia_device *p_dev,
+			      cistpl_cftable_entry_t *cfg,
+			      cistpl_cftable_entry_t *dflt,
+			      unsigned int vcc,
+			      void *priv_data)
+{
+	if (cfg->index == 0)
+		return -ENODEV;
+
+	/* Does this card need audio output? */
+	if (cfg->flags & CISTPL_CFTABLE_AUDIO) {
+		p_dev->conf.Attributes |= CONF_ENABLE_SPKR;
+		p_dev->conf.Status = CCSR_AUDIO_ENA;
+	}
+
+	/* Use power settings for Vcc and Vpp if present */
+	/*  Note that the CIS values need to be rescaled */
+	if (cfg->vpp1.present & (1<<CISTPL_POWER_VNOM))
+		p_dev->conf.Vpp = cfg->vpp1.param[CISTPL_POWER_VNOM]/10000;
+	else if (dflt->vpp1.present & (1<<CISTPL_POWER_VNOM))
+		p_dev->conf.Vpp = dflt->vpp1.param[CISTPL_POWER_VNOM]/10000;
+
+	/* Do we need to allocate an interrupt? */
+	if (cfg->irq.IRQInfo1 || dflt->irq.IRQInfo1)
+		p_dev->conf.Attributes |= CONF_ENABLE_IRQ;
+
+	/* IO window settings */
+	p_dev->io.NumPorts1 = p_dev->io.NumPorts2 = 0;
+	if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) {
+		cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io;
+		p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
+		if (!(io->flags & CISTPL_IO_8BIT))
+			p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_16;
+		if (!(io->flags & CISTPL_IO_16BIT))
+			p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
+		p_dev->io.BasePort1 = io->win[0].base;
+		p_dev->io.NumPorts1 = io->win[0].len;
+		if (io->nwin > 1) {
+			p_dev->io.Attributes2 = p_dev->io.Attributes1;
+			p_dev->io.BasePort2 = io->win[1].base;
+			p_dev->io.NumPorts2 = io->win[1].len;
+		}
+	}
+
+	/* This reserves IO space but doesn't actually enable it */
+	return pcmcia_request_io(p_dev, &p_dev->io);
+}
+
 static int atmel_config(struct pcmcia_device *link)
 {
-	tuple_t tuple;
-	cisparse_t parse;
 	local_info_t *dev;
 	int last_fn, last_ret;
-	u_char buf[64];
 	struct pcmcia_device_id *did;
 
 	dev = link->priv;
@@ -238,11 +283,6 @@
 
 	DEBUG(0, "atmel_config(0x%p)\n", link);
 
-	tuple.Attributes = 0;
-	tuple.TupleData = buf;
-	tuple.TupleDataMax = sizeof(buf);
-	tuple.TupleOffset = 0;
-
 	/*
 	  In this loop, we scan the CIS for configuration table entries,
 	  each of which describes a valid card configuration, including
@@ -255,66 +295,8 @@
 	  these things without consulting the CIS, and most client drivers
 	  will only use the CIS to fill in implementation-defined details.
 	*/
-	tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
-	CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple));
-	while (1) {
-		cistpl_cftable_entry_t dflt = { 0 };
-		cistpl_cftable_entry_t *cfg = &(parse.cftable_entry);
-		if (pcmcia_get_tuple_data(link, &tuple) != 0 ||
-				pcmcia_parse_tuple(link, &tuple, &parse) != 0)
-			goto next_entry;
-
-		if (cfg->flags & CISTPL_CFTABLE_DEFAULT) dflt = *cfg;
-		if (cfg->index == 0) goto next_entry;
-		link->conf.ConfigIndex = cfg->index;
-
-		/* Does this card need audio output? */
-		if (cfg->flags & CISTPL_CFTABLE_AUDIO) {
-			link->conf.Attributes |= CONF_ENABLE_SPKR;
-			link->conf.Status = CCSR_AUDIO_ENA;
-		}
-
-		/* Use power settings for Vcc and Vpp if present */
-		/*  Note that the CIS values need to be rescaled */
-		if (cfg->vpp1.present & (1<<CISTPL_POWER_VNOM))
-			link->conf.Vpp =
-				cfg->vpp1.param[CISTPL_POWER_VNOM]/10000;
-		else if (dflt.vpp1.present & (1<<CISTPL_POWER_VNOM))
-			link->conf.Vpp =
-				dflt.vpp1.param[CISTPL_POWER_VNOM]/10000;
-
-		/* Do we need to allocate an interrupt? */
-		if (cfg->irq.IRQInfo1 || dflt.irq.IRQInfo1)
-			link->conf.Attributes |= CONF_ENABLE_IRQ;
-
-		/* IO window settings */
-		link->io.NumPorts1 = link->io.NumPorts2 = 0;
-		if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) {
-			cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt.io;
-			link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
-			if (!(io->flags & CISTPL_IO_8BIT))
-				link->io.Attributes1 = IO_DATA_PATH_WIDTH_16;
-			if (!(io->flags & CISTPL_IO_16BIT))
-				link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
-			link->io.BasePort1 = io->win[0].base;
-			link->io.NumPorts1 = io->win[0].len;
-			if (io->nwin > 1) {
-				link->io.Attributes2 = link->io.Attributes1;
-				link->io.BasePort2 = io->win[1].base;
-				link->io.NumPorts2 = io->win[1].len;
-			}
-		}
-
-		/* This reserves IO space but doesn't actually enable it */
-		if (pcmcia_request_io(link, &link->io) != 0)
-			goto next_entry;
-
-		/* If we got this far, we're cool! */
-		break;
-
-	next_entry:
-		CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(link, &tuple));
-	}
+	if (pcmcia_loop_config(link, atmel_config_check, NULL))
+		goto failed;
 
 	/*
 	  Allocate an interrupt line.  Note that this does not assign a
@@ -360,6 +342,7 @@
 
  cs_failed:
 	cs_error(link, last_fn, last_ret);
+ failed:
 	atmel_release(link);
 	return -ENODEV;
 }
diff --git a/drivers/net/wireless/b43/Kconfig b/drivers/net/wireless/b43/Kconfig
index 1fa043d..1f81d36 100644
--- a/drivers/net/wireless/b43/Kconfig
+++ b/drivers/net/wireless/b43/Kconfig
@@ -80,6 +80,18 @@
 
 	  SAY N.
 
+config B43_PHY_LP
+	bool "IEEE 802.11g LP-PHY support (BROKEN)"
+	depends on B43 && EXPERIMENTAL && BROKEN
+	---help---
+	  Support for the LP-PHY.
+	  The LP-PHY is an IEEE 802.11g based PHY built into some notebooks
+	  and embedded devices.
+
+	  THIS IS BROKEN AND DOES NOT WORK YET.
+
+	  SAY N.
+
 # This config option automatically enables b43 LEDS support,
 # if it's possible.
 config B43_LEDS
diff --git a/drivers/net/wireless/b43/Makefile b/drivers/net/wireless/b43/Makefile
index 8c52b0b..14a02b3 100644
--- a/drivers/net/wireless/b43/Makefile
+++ b/drivers/net/wireless/b43/Makefile
@@ -1,8 +1,11 @@
 b43-y				+= main.o
 b43-y				+= tables.o
 b43-$(CONFIG_B43_NPHY)		+= tables_nphy.o
-b43-y				+= phy.o
-b43-$(CONFIG_B43_NPHY)		+= nphy.o
+b43-y				+= phy_common.o
+b43-y				+= phy_g.o
+b43-y				+= phy_a.o
+b43-$(CONFIG_B43_NPHY)		+= phy_n.o
+b43-$(CONFIG_B43_PHY_LP)	+= phy_lp.o
 b43-y				+= sysfs.o
 b43-y				+= xmit.o
 b43-y				+= lo.o
diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h
index edcdfa3..427b820 100644
--- a/drivers/net/wireless/b43/b43.h
+++ b/drivers/net/wireless/b43/b43.h
@@ -12,7 +12,7 @@
 #include "leds.h"
 #include "rfkill.h"
 #include "lo.h"
-#include "phy.h"
+#include "phy_common.h"
 
 
 /* The unique identifier of the firmware that's officially supported by
@@ -173,6 +173,11 @@
 #define B43_SHM_SH_CHAN			0x00A0	/* Current channel (low 8bit only) */
 #define  B43_SHM_SH_CHAN_5GHZ		0x0100	/* Bit set, if 5Ghz channel */
 #define B43_SHM_SH_BCMCFIFOID		0x0108	/* Last posted cookie to the bcast/mcast FIFO */
+/* TSSI information */
+#define B43_SHM_SH_TSSI_CCK		0x0058	/* TSSI for last 4 CCK frames (32bit) */
+#define B43_SHM_SH_TSSI_OFDM_A		0x0068	/* TSSI for last 4 OFDM frames (32bit) */
+#define B43_SHM_SH_TSSI_OFDM_G		0x0070	/* TSSI for last 4 OFDM frames (32bit) */
+#define  B43_TSSI_MAX			0x7F	/* Max value for one TSSI value */
 /* SHM_SHARED TX FIFO variables */
 #define B43_SHM_SH_SIZE01		0x0098	/* TX FIFO size for FIFO 0 (low) and 1 (high) */
 #define B43_SHM_SH_SIZE23		0x009A	/* TX FIFO size for FIFO 2 and 3 */
@@ -508,122 +513,6 @@
 } __attribute__((__packed__));
 
 
-struct b43_phy {
-	/* Band support flags. */
-	bool supports_2ghz;
-	bool supports_5ghz;
-
-	/* GMODE bit enabled? */
-	bool gmode;
-
-	/* Analog Type */
-	u8 analog;
-	/* B43_PHYTYPE_ */
-	u8 type;
-	/* PHY revision number. */
-	u8 rev;
-
-	/* Radio versioning */
-	u16 radio_manuf;	/* Radio manufacturer */
-	u16 radio_ver;		/* Radio version */
-	u8 radio_rev;		/* Radio revision */
-
-	bool dyn_tssi_tbl;	/* tssi2dbm is kmalloc()ed. */
-
-	/* ACI (adjacent channel interference) flags. */
-	bool aci_enable;
-	bool aci_wlan_automatic;
-	bool aci_hw_rssi;
-
-	/* Radio switched on/off */
-	bool radio_on;
-	struct {
-		/* Values saved when turning the radio off.
-		 * They are needed when turning it on again. */
-		bool valid;
-		u16 rfover;
-		u16 rfoverval;
-	} radio_off_context;
-
-	u16 minlowsig[2];
-	u16 minlowsigpos[2];
-
-	/* TSSI to dBm table in use */
-	const s8 *tssi2dbm;
-	/* Target idle TSSI */
-	int tgt_idle_tssi;
-	/* Current idle TSSI */
-	int cur_idle_tssi;
-
-	/* LocalOscillator control values. */
-	struct b43_txpower_lo_control *lo_control;
-	/* Values from b43_calc_loopback_gain() */
-	s16 max_lb_gain;	/* Maximum Loopback gain in hdB */
-	s16 trsw_rx_gain;	/* TRSW RX gain in hdB */
-	s16 lna_lod_gain;	/* LNA lod */
-	s16 lna_gain;		/* LNA */
-	s16 pga_gain;		/* PGA */
-
-	/* Desired TX power level (in dBm).
-	 * This is set by the user and adjusted in b43_phy_xmitpower(). */
-	u8 power_level;
-	/* A-PHY TX Power control value. */
-	u16 txpwr_offset;
-
-	/* Current TX power level attenuation control values */
-	struct b43_bbatt bbatt;
-	struct b43_rfatt rfatt;
-	u8 tx_control;		/* B43_TXCTL_XXX */
-
-	/* Hardware Power Control enabled? */
-	bool hardware_power_control;
-
-	/* Current Interference Mitigation mode */
-	int interfmode;
-	/* Stack of saved values from the Interference Mitigation code.
-	 * Each value in the stack is layed out as follows:
-	 * bit 0-11:  offset
-	 * bit 12-15: register ID
-	 * bit 16-32: value
-	 * register ID is: 0x1 PHY, 0x2 Radio, 0x3 ILT
-	 */
-#define B43_INTERFSTACK_SIZE	26
-	u32 interfstack[B43_INTERFSTACK_SIZE];	//FIXME: use a data structure
-
-	/* Saved values from the NRSSI Slope calculation */
-	s16 nrssi[2];
-	s32 nrssislope;
-	/* In memory nrssi lookup table. */
-	s8 nrssi_lt[64];
-
-	/* current channel */
-	u8 channel;
-
-	u16 lofcal;
-
-	u16 initval;		//FIXME rename?
-
-	/* PHY TX errors counter. */
-	atomic_t txerr_cnt;
-
-	/* The device does address auto increment for the OFDM tables.
-	 * We cache the previously used address here and omit the address
-	 * write on the next table access, if possible. */
-	u16 ofdmtab_addr; /* The address currently set in hardware. */
-	enum { /* The last data flow direction. */
-		B43_OFDMTAB_DIRECTION_UNKNOWN = 0,
-		B43_OFDMTAB_DIRECTION_READ,
-		B43_OFDMTAB_DIRECTION_WRITE,
-	} ofdmtab_addr_direction;
-
-#if B43_DEBUG
-	/* Manual TX-power control enabled? */
-	bool manual_txpower_control;
-	/* PHY registers locked by b43_phy_lock()? */
-	bool phy_locked;
-#endif /* B43_DEBUG */
-};
-
 /* Data structures for DMA transmission, per 80211 core. */
 struct b43_dma {
 	struct b43_dmaring *tx_ring_AC_BK; /* Background */
@@ -680,7 +569,7 @@
 #define B43_QOS_VOICE		B43_QOS_PARAMS(3)
 
 /* QOS parameter hardware data structure offsets. */
-#define B43_NR_QOSPARAMS	22
+#define B43_NR_QOSPARAMS	16
 enum {
 	B43_QOSPARAM_TXOP = 0,
 	B43_QOSPARAM_CWMIN,
@@ -696,8 +585,6 @@
 struct b43_qos_params {
 	/* The QOS parameters */
 	struct ieee80211_tx_queue_params p;
-	/* Does this need to get uploaded to hardware? */
-	bool need_hw_update;
 };
 
 struct b43_wldev;
@@ -759,11 +646,13 @@
 	bool beacon_templates_virgin; /* Never wrote the templates? */
 	struct work_struct beacon_update_trigger;
 
-	/* The current QOS parameters for the 4 queues.
-	 * This is protected by the irq_lock. */
+	/* The current QOS parameters for the 4 queues. */
 	struct b43_qos_params qos_params[4];
-	/* Workqueue for updating QOS parameters in hardware. */
-	struct work_struct qos_update_work;
+
+	/* Work for adjustment of the transmission power.
+	 * This is scheduled when we determine that the actual TX output
+	 * power doesn't match what we want. */
+	struct work_struct txpower_adjust_work;
 };
 
 /* In-memory representation of a cached microcode file. */
@@ -908,6 +797,15 @@
 	return (wl->operating && wl->if_type == type);
 }
 
+/**
+ * b43_current_band - Returns the currently used band.
+ * Returns one of IEEE80211_BAND_2GHZ and IEEE80211_BAND_5GHZ.
+ */
+static inline enum ieee80211_band b43_current_band(struct b43_wl *wl)
+{
+	return wl->hw->conf.channel->band;
+}
+
 static inline u16 b43_read16(struct b43_wldev *dev, u16 offset)
 {
 	return ssb_read16(dev->dev, offset);
diff --git a/drivers/net/wireless/b43/debugfs.c b/drivers/net/wireless/b43/debugfs.c
index 29851bc..06a01da 100644
--- a/drivers/net/wireless/b43/debugfs.c
+++ b/drivers/net/wireless/b43/debugfs.c
@@ -443,76 +443,6 @@
 	return count;
 }
 
-static ssize_t txpower_g_read_file(struct b43_wldev *dev,
-				   char *buf, size_t bufsize)
-{
-	ssize_t count = 0;
-
-	if (dev->phy.type != B43_PHYTYPE_G) {
-		fappend("Device is not a G-PHY\n");
-		goto out;
-	}
-	fappend("Control:               %s\n", dev->phy.manual_txpower_control ?
-		"MANUAL" : "AUTOMATIC");
-	fappend("Baseband attenuation:  %u\n", dev->phy.bbatt.att);
-	fappend("Radio attenuation:     %u\n", dev->phy.rfatt.att);
-	fappend("TX Mixer Gain:         %s\n",
-		(dev->phy.tx_control & B43_TXCTL_TXMIX) ? "ON" : "OFF");
-	fappend("PA Gain 2dB:           %s\n",
-		(dev->phy.tx_control & B43_TXCTL_PA2DB) ? "ON" : "OFF");
-	fappend("PA Gain 3dB:           %s\n",
-		(dev->phy.tx_control & B43_TXCTL_PA3DB) ? "ON" : "OFF");
-	fappend("\n\n");
-	fappend("You can write to this file:\n");
-	fappend("Writing \"auto\" enables automatic txpower control.\n");
-	fappend
-	    ("Writing the attenuation values as \"bbatt rfatt txmix pa2db pa3db\" "
-	     "enables manual txpower control.\n");
-	fappend("Example: 5 4 0 0 1\n");
-	fappend("Enables manual control with Baseband attenuation 5, "
-		"Radio attenuation 4, No TX Mixer Gain, "
-		"No PA Gain 2dB, With PA Gain 3dB.\n");
-out:
-	return count;
-}
-
-static int txpower_g_write_file(struct b43_wldev *dev,
-				const char *buf, size_t count)
-{
-	if (dev->phy.type != B43_PHYTYPE_G)
-		return -ENODEV;
-	if ((count >= 4) && (memcmp(buf, "auto", 4) == 0)) {
-		/* Automatic control */
-		dev->phy.manual_txpower_control = 0;
-		b43_phy_xmitpower(dev);
-	} else {
-		int bbatt = 0, rfatt = 0, txmix = 0, pa2db = 0, pa3db = 0;
-		/* Manual control */
-		if (sscanf(buf, "%d %d %d %d %d", &bbatt, &rfatt,
-			   &txmix, &pa2db, &pa3db) != 5)
-			return -EINVAL;
-		b43_put_attenuation_into_ranges(dev, &bbatt, &rfatt);
-		dev->phy.manual_txpower_control = 1;
-		dev->phy.bbatt.att = bbatt;
-		dev->phy.rfatt.att = rfatt;
-		dev->phy.tx_control = 0;
-		if (txmix)
-			dev->phy.tx_control |= B43_TXCTL_TXMIX;
-		if (pa2db)
-			dev->phy.tx_control |= B43_TXCTL_PA2DB;
-		if (pa3db)
-			dev->phy.tx_control |= B43_TXCTL_PA3DB;
-		b43_phy_lock(dev);
-		b43_radio_lock(dev);
-		b43_set_txpower_g(dev, &dev->phy.bbatt,
-				  &dev->phy.rfatt, dev->phy.tx_control);
-		b43_radio_unlock(dev);
-		b43_phy_unlock(dev);
-	}
-
-	return 0;
-}
-
 /* wl->irq_lock is locked */
 static int restart_write_file(struct b43_wldev *dev,
 			      const char *buf, size_t count)
@@ -560,7 +490,7 @@
 		err = -ENODEV;
 		goto out;
 	}
-	lo = phy->lo_control;
+	lo = phy->g->lo_control;
 	fappend("-- Local Oscillator calibration data --\n\n");
 	fappend("HW-power-control enabled: %d\n",
 		dev->phy.hardware_power_control);
@@ -578,8 +508,8 @@
 	list_for_each_entry(cal, &lo->calib_list, list) {
 		bool active;
 
-		active = (b43_compare_bbatt(&cal->bbatt, &phy->bbatt) &&
-			  b43_compare_rfatt(&cal->rfatt, &phy->rfatt));
+		active = (b43_compare_bbatt(&cal->bbatt, &phy->g->bbatt) &&
+			  b43_compare_rfatt(&cal->rfatt, &phy->g->rfatt));
 		fappend("BB(%d), RF(%d,%d)  ->  I=%d, Q=%d  "
 			"(expires in %lu sec)%s\n",
 			cal->bbatt.att,
@@ -763,7 +693,6 @@
 B43_DEBUGFS_FOPS(mmio32write, NULL, mmio32write__write_file, 1);
 B43_DEBUGFS_FOPS(tsf, tsf_read_file, tsf_write_file, 1);
 B43_DEBUGFS_FOPS(txstat, txstat_read_file, NULL, 0);
-B43_DEBUGFS_FOPS(txpower_g, txpower_g_read_file, txpower_g_write_file, 0);
 B43_DEBUGFS_FOPS(restart, NULL, restart_write_file, 1);
 B43_DEBUGFS_FOPS(loctls, loctls_read_file, NULL, 0);
 
@@ -877,7 +806,6 @@
 	ADD_FILE(mmio32write, 0200);
 	ADD_FILE(tsf, 0600);
 	ADD_FILE(txstat, 0400);
-	ADD_FILE(txpower_g, 0600);
 	ADD_FILE(restart, 0200);
 	ADD_FILE(loctls, 0400);
 
@@ -907,7 +835,6 @@
 	debugfs_remove(e->file_mmio32write.dentry);
 	debugfs_remove(e->file_tsf.dentry);
 	debugfs_remove(e->file_txstat.dentry);
-	debugfs_remove(e->file_txpower_g.dentry);
 	debugfs_remove(e->file_restart.dentry);
 	debugfs_remove(e->file_loctls.dentry);
 
diff --git a/drivers/net/wireless/b43/lo.c b/drivers/net/wireless/b43/lo.c
index 9c854d6..6a18a14 100644
--- a/drivers/net/wireless/b43/lo.c
+++ b/drivers/net/wireless/b43/lo.c
@@ -29,7 +29,7 @@
 
 #include "b43.h"
 #include "lo.h"
-#include "phy.h"
+#include "phy_g.h"
 #include "main.h"
 
 #include <linux/delay.h>
@@ -174,7 +174,8 @@
 static void lo_measure_txctl_values(struct b43_wldev *dev)
 {
 	struct b43_phy *phy = &dev->phy;
-	struct b43_txpower_lo_control *lo = phy->lo_control;
+	struct b43_phy_g *gphy = phy->g;
+	struct b43_txpower_lo_control *lo = gphy->lo_control;
 	u16 reg, mask;
 	u16 trsw_rx, pga;
 	u16 radio_pctl_reg;
@@ -195,7 +196,7 @@
 		int lb_gain;	/* Loopback gain (in dB) */
 
 		trsw_rx = 0;
-		lb_gain = phy->max_lb_gain / 2;
+		lb_gain = gphy->max_lb_gain / 2;
 		if (lb_gain > 10) {
 			radio_pctl_reg = 0;
 			pga = abs(10 - lb_gain) / 6;
@@ -226,7 +227,7 @@
 	}
 	b43_radio_write16(dev, 0x43, (b43_radio_read16(dev, 0x43)
 				      & 0xFFF0) | radio_pctl_reg);
-	b43_phy_set_baseband_attenuation(dev, 2);
+	b43_gphy_set_baseband_attenuation(dev, 2);
 
 	reg = lo_txctl_register_table(dev, &mask, NULL);
 	mask = ~mask;
@@ -277,7 +278,8 @@
 static void lo_read_power_vector(struct b43_wldev *dev)
 {
 	struct b43_phy *phy = &dev->phy;
-	struct b43_txpower_lo_control *lo = phy->lo_control;
+	struct b43_phy_g *gphy = phy->g;
+	struct b43_txpower_lo_control *lo = gphy->lo_control;
 	int i;
 	u64 tmp;
 	u64 power_vector = 0;
@@ -298,6 +300,7 @@
 				   s16 max_rx_gain, int use_trsw_rx)
 {
 	struct b43_phy *phy = &dev->phy;
+	struct b43_phy_g *gphy = phy->g;
 	u16 tmp;
 
 	if (max_rx_gain < 0)
@@ -308,7 +311,7 @@
 		int trsw_rx_gain;
 
 		if (use_trsw_rx) {
-			trsw_rx_gain = phy->trsw_rx_gain / 2;
+			trsw_rx_gain = gphy->trsw_rx_gain / 2;
 			if (max_rx_gain >= trsw_rx_gain) {
 				trsw_rx_gain = max_rx_gain - trsw_rx_gain;
 				trsw_rx = 0x20;
@@ -316,38 +319,38 @@
 		} else
 			trsw_rx_gain = max_rx_gain;
 		if (trsw_rx_gain < 9) {
-			phy->lna_lod_gain = 0;
+			gphy->lna_lod_gain = 0;
 		} else {
-			phy->lna_lod_gain = 1;
+			gphy->lna_lod_gain = 1;
 			trsw_rx_gain -= 8;
 		}
 		trsw_rx_gain = clamp_val(trsw_rx_gain, 0, 0x2D);
-		phy->pga_gain = trsw_rx_gain / 3;
-		if (phy->pga_gain >= 5) {
-			phy->pga_gain -= 5;
-			phy->lna_gain = 2;
+		gphy->pga_gain = trsw_rx_gain / 3;
+		if (gphy->pga_gain >= 5) {
+			gphy->pga_gain -= 5;
+			gphy->lna_gain = 2;
 		} else
-			phy->lna_gain = 0;
+			gphy->lna_gain = 0;
 	} else {
-		phy->lna_gain = 0;
-		phy->trsw_rx_gain = 0x20;
+		gphy->lna_gain = 0;
+		gphy->trsw_rx_gain = 0x20;
 		if (max_rx_gain >= 0x14) {
-			phy->lna_lod_gain = 1;
-			phy->pga_gain = 2;
+			gphy->lna_lod_gain = 1;
+			gphy->pga_gain = 2;
 		} else if (max_rx_gain >= 0x12) {
-			phy->lna_lod_gain = 1;
-			phy->pga_gain = 1;
+			gphy->lna_lod_gain = 1;
+			gphy->pga_gain = 1;
 		} else if (max_rx_gain >= 0xF) {
-			phy->lna_lod_gain = 1;
-			phy->pga_gain = 0;
+			gphy->lna_lod_gain = 1;
+			gphy->pga_gain = 0;
 		} else {
-			phy->lna_lod_gain = 0;
-			phy->pga_gain = 0;
+			gphy->lna_lod_gain = 0;
+			gphy->pga_gain = 0;
 		}
 	}
 
 	tmp = b43_radio_read16(dev, 0x7A);
-	if (phy->lna_lod_gain == 0)
+	if (gphy->lna_lod_gain == 0)
 		tmp &= ~0x0008;
 	else
 		tmp |= 0x0008;
@@ -392,10 +395,11 @@
 {
 	struct ssb_sprom *sprom = &dev->dev->bus->sprom;
 	struct b43_phy *phy = &dev->phy;
-	struct b43_txpower_lo_control *lo = phy->lo_control;
+	struct b43_phy_g *gphy = phy->g;
+	struct b43_txpower_lo_control *lo = gphy->lo_control;
 	u16 tmp;
 
-	if (b43_has_hardware_pctl(phy)) {
+	if (b43_has_hardware_pctl(dev)) {
 		sav->phy_lo_mask = b43_phy_read(dev, B43_PHY_LO_MASK);
 		sav->phy_extg_01 = b43_phy_read(dev, B43_PHY_EXTG(0x01));
 		sav->phy_dacctl_hwpctl = b43_phy_read(dev, B43_PHY_DACCTL);
@@ -496,7 +500,7 @@
 		b43_phy_write(dev, B43_PHY_CCK(0x2B), 0x0802);
 	if (phy->rev >= 2)
 		b43_dummy_transmission(dev);
-	b43_radio_selectchannel(dev, 6, 0);
+	b43_gphy_channel_switch(dev, 6, 0);
 	b43_radio_read16(dev, 0x51);	/* dummy read */
 	if (phy->type == B43_PHYTYPE_G)
 		b43_phy_write(dev, B43_PHY_CCK(0x2F), 0);
@@ -520,18 +524,19 @@
 			       struct lo_g_saved_values *sav)
 {
 	struct b43_phy *phy = &dev->phy;
+	struct b43_phy_g *gphy = phy->g;
 	u16 tmp;
 
 	if (phy->rev >= 2) {
 		b43_phy_write(dev, B43_PHY_PGACTL, 0xE300);
-		tmp = (phy->pga_gain << 8);
+		tmp = (gphy->pga_gain << 8);
 		b43_phy_write(dev, B43_PHY_RFOVERVAL, tmp | 0xA0);
 		udelay(5);
 		b43_phy_write(dev, B43_PHY_RFOVERVAL, tmp | 0xA2);
 		udelay(2);
 		b43_phy_write(dev, B43_PHY_RFOVERVAL, tmp | 0xA3);
 	} else {
-		tmp = (phy->pga_gain | 0xEFA0);
+		tmp = (gphy->pga_gain | 0xEFA0);
 		b43_phy_write(dev, B43_PHY_PGACTL, tmp);
 	}
 	if (phy->type == B43_PHYTYPE_G) {
@@ -572,7 +577,7 @@
 		b43_phy_write(dev, B43_PHY_CCK(0x3E), sav->phy_cck_3E);
 		b43_phy_write(dev, B43_PHY_CRS0, sav->phy_crs0);
 	}
-	if (b43_has_hardware_pctl(phy)) {
+	if (b43_has_hardware_pctl(dev)) {
 		tmp = (sav->phy_lo_mask & 0xBFFF);
 		b43_phy_write(dev, B43_PHY_LO_MASK, tmp);
 		b43_phy_write(dev, B43_PHY_EXTG(0x01), sav->phy_extg_01);
@@ -580,7 +585,7 @@
 		b43_phy_write(dev, B43_PHY_CCK(0x14), sav->phy_cck_14);
 		b43_phy_write(dev, B43_PHY_HPWR_TSSICTL, sav->phy_hpwr_tssictl);
 	}
-	b43_radio_selectchannel(dev, sav->old_channel, 1);
+	b43_gphy_channel_switch(dev, sav->old_channel, 1);
 }
 
 struct b43_lo_g_statemachine {
@@ -597,6 +602,7 @@
 				    struct b43_lo_g_statemachine *d)
 {
 	struct b43_phy *phy = &dev->phy;
+	struct b43_phy_g *gphy = phy->g;
 	struct b43_loctl test_loctl;
 	struct b43_loctl orig_loctl;
 	struct b43_loctl prev_loctl = {
@@ -646,9 +652,9 @@
 		     test_loctl.q != prev_loctl.q) &&
 		    (abs(test_loctl.i) <= 16 && abs(test_loctl.q) <= 16)) {
 			b43_lo_write(dev, &test_loctl);
-			feedth = lo_measure_feedthrough(dev, phy->lna_gain,
-							phy->pga_gain,
-							phy->trsw_rx_gain);
+			feedth = lo_measure_feedthrough(dev, gphy->lna_gain,
+							gphy->pga_gain,
+							gphy->trsw_rx_gain);
 			if (feedth < d->lowest_feedth) {
 				memcpy(probe_loctl, &test_loctl,
 				       sizeof(struct b43_loctl));
@@ -677,6 +683,7 @@
 					 int *max_rx_gain)
 {
 	struct b43_phy *phy = &dev->phy;
+	struct b43_phy_g *gphy = phy->g;
 	struct b43_lo_g_statemachine d;
 	u16 feedth;
 	int found_lower;
@@ -693,17 +700,17 @@
 		max_repeat = 4;
 	do {
 		b43_lo_write(dev, &d.min_loctl);
-		feedth = lo_measure_feedthrough(dev, phy->lna_gain,
-						phy->pga_gain,
-						phy->trsw_rx_gain);
+		feedth = lo_measure_feedthrough(dev, gphy->lna_gain,
+						gphy->pga_gain,
+						gphy->trsw_rx_gain);
 		if (feedth < 0x258) {
 			if (feedth >= 0x12C)
 				*max_rx_gain += 6;
 			else
 				*max_rx_gain += 3;
-			feedth = lo_measure_feedthrough(dev, phy->lna_gain,
-							phy->pga_gain,
-							phy->trsw_rx_gain);
+			feedth = lo_measure_feedthrough(dev, gphy->lna_gain,
+							gphy->pga_gain,
+							gphy->trsw_rx_gain);
 		}
 		d.lowest_feedth = feedth;
 
@@ -752,6 +759,7 @@
 					       const struct b43_rfatt *rfatt)
 {
 	struct b43_phy *phy = &dev->phy;
+	struct b43_phy_g *gphy = phy->g;
 	struct b43_loctl loctl = {
 		.i = 0,
 		.q = 0,
@@ -782,11 +790,11 @@
 	if (rfatt->with_padmix)
 		max_rx_gain -= pad_mix_gain;
 	if (has_loopback_gain(phy))
-		max_rx_gain += phy->max_lb_gain;
+		max_rx_gain += gphy->max_lb_gain;
 	lo_measure_gain_values(dev, max_rx_gain,
 			       has_loopback_gain(phy));
 
-	b43_phy_set_baseband_attenuation(dev, bbatt->att);
+	b43_gphy_set_baseband_attenuation(dev, bbatt->att);
 	lo_probe_loctls_statemachine(dev, &loctl, &max_rx_gain);
 
 	lo_measure_restore(dev, &saved_regs);
@@ -820,7 +828,7 @@
 						const struct b43_bbatt *bbatt,
 						const struct b43_rfatt *rfatt)
 {
-	struct b43_txpower_lo_control *lo = dev->phy.lo_control;
+	struct b43_txpower_lo_control *lo = dev->phy.g->lo_control;
 	struct b43_lo_calib *c;
 
 	c = b43_find_lo_calib(lo, bbatt, rfatt);
@@ -839,7 +847,8 @@
 void b43_gphy_dc_lt_init(struct b43_wldev *dev, bool update_all)
 {
 	struct b43_phy *phy = &dev->phy;
-	struct b43_txpower_lo_control *lo = phy->lo_control;
+	struct b43_phy_g *gphy = phy->g;
+	struct b43_txpower_lo_control *lo = gphy->lo_control;
 	int i;
 	int rf_offset, bb_offset;
 	const struct b43_rfatt *rfatt;
@@ -917,14 +926,14 @@
 
 void b43_lo_g_adjust(struct b43_wldev *dev)
 {
-	struct b43_phy *phy = &dev->phy;
+	struct b43_phy_g *gphy = dev->phy.g;
 	struct b43_lo_calib *cal;
 	struct b43_rfatt rf;
 
-	memcpy(&rf, &phy->rfatt, sizeof(rf));
+	memcpy(&rf, &gphy->rfatt, sizeof(rf));
 	b43_lo_fixup_rfatt(&rf);
 
-	cal = b43_get_calib_lo_settings(dev, &phy->bbatt, &rf);
+	cal = b43_get_calib_lo_settings(dev, &gphy->bbatt, &rf);
 	if (!cal)
 		return;
 	b43_lo_write(dev, &cal->ctl);
@@ -952,7 +961,8 @@
 void b43_lo_g_maintanance_work(struct b43_wldev *dev)
 {
 	struct b43_phy *phy = &dev->phy;
-	struct b43_txpower_lo_control *lo = phy->lo_control;
+	struct b43_phy_g *gphy = phy->g;
+	struct b43_txpower_lo_control *lo = gphy->lo_control;
 	unsigned long now;
 	unsigned long expire;
 	struct b43_lo_calib *cal, *tmp;
@@ -962,7 +972,7 @@
 	if (!lo)
 		return;
 	now = jiffies;
-	hwpctl = b43_has_hardware_pctl(phy);
+	hwpctl = b43_has_hardware_pctl(dev);
 
 	if (hwpctl) {
 		/* Read the power vector and update it, if needed. */
@@ -983,8 +993,8 @@
 		if (!time_before(cal->calib_time, expire))
 			continue;
 		/* This item expired. */
-		if (b43_compare_bbatt(&cal->bbatt, &phy->bbatt) &&
-		    b43_compare_rfatt(&cal->rfatt, &phy->rfatt)) {
+		if (b43_compare_bbatt(&cal->bbatt, &gphy->bbatt) &&
+		    b43_compare_rfatt(&cal->rfatt, &gphy->rfatt)) {
 			B43_WARN_ON(current_item_expired);
 			current_item_expired = 1;
 		}
@@ -1002,7 +1012,7 @@
 		/* Recalibrate currently used LO setting. */
 		if (b43_debug(dev, B43_DBG_LO))
 			b43dbg(dev->wl, "LO: Recalibrating current LO setting\n");
-		cal = b43_calibrate_lo_setting(dev, &phy->bbatt, &phy->rfatt);
+		cal = b43_calibrate_lo_setting(dev, &gphy->bbatt, &gphy->rfatt);
 		if (cal) {
 			list_add(&cal->list, &lo->calib_list);
 			b43_lo_write(dev, &cal->ctl);
@@ -1013,7 +1023,7 @@
 
 void b43_lo_g_cleanup(struct b43_wldev *dev)
 {
-	struct b43_txpower_lo_control *lo = dev->phy.lo_control;
+	struct b43_txpower_lo_control *lo = dev->phy.g->lo_control;
 	struct b43_lo_calib *cal, *tmp;
 
 	if (!lo)
@@ -1027,9 +1037,7 @@
 /* LO Initialization */
 void b43_lo_g_init(struct b43_wldev *dev)
 {
-	struct b43_phy *phy = &dev->phy;
-
-	if (b43_has_hardware_pctl(phy)) {
+	if (b43_has_hardware_pctl(dev)) {
 		lo_read_power_vector(dev);
 		b43_gphy_dc_lt_init(dev, 1);
 	}
diff --git a/drivers/net/wireless/b43/lo.h b/drivers/net/wireless/b43/lo.h
index 1da321c..3b27e20 100644
--- a/drivers/net/wireless/b43/lo.h
+++ b/drivers/net/wireless/b43/lo.h
@@ -1,7 +1,9 @@
 #ifndef B43_LO_H_
 #define B43_LO_H_
 
-#include "phy.h"
+/* G-PHY Local Oscillator */
+
+#include "phy_g.h"
 
 struct b43_wldev;
 
diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c
index 7205a93..14c44df 100644
--- a/drivers/net/wireless/b43/main.c
+++ b/drivers/net/wireless/b43/main.c
@@ -44,8 +44,9 @@
 #include "b43.h"
 #include "main.h"
 #include "debugfs.h"
-#include "phy.h"
-#include "nphy.h"
+#include "phy_common.h"
+#include "phy_g.h"
+#include "phy_n.h"
 #include "dma.h"
 #include "pio.h"
 #include "sysfs.h"
@@ -814,7 +815,7 @@
 			break;
 		udelay(10);
 	}
-	for (i = 0x00; i < 0x0A; i++) {
+	for (i = 0x00; i < 0x19; i++) {
 		value = b43_read16(dev, 0x0690);
 		if (!(value & 0x0100))
 			break;
@@ -1051,23 +1052,6 @@
 	}
 }
 
-/* Turn the Analog ON/OFF */
-static void b43_switch_analog(struct b43_wldev *dev, int on)
-{
-	switch (dev->phy.type) {
-	case B43_PHYTYPE_A:
-	case B43_PHYTYPE_G:
-		b43_write16(dev, B43_MMIO_PHY0, on ? 0 : 0xF4);
-		break;
-	case B43_PHYTYPE_N:
-		b43_phy_write(dev, B43_NPHY_AFECTL_OVER,
-			      on ? 0 : 0x7FFF);
-		break;
-	default:
-		B43_WARN_ON(1);
-	}
-}
-
 void b43_wireless_core_reset(struct b43_wldev *dev, u32 flags)
 {
 	u32 tmslow;
@@ -1090,8 +1074,12 @@
 	ssb_read32(dev->dev, SSB_TMSLOW);	/* flush */
 	msleep(1);
 
-	/* Turn Analog ON */
-	b43_switch_analog(dev, 1);
+	/* Turn Analog ON, but only if we already know the PHY-type.
+	 * This protects against very early setup where we don't know the
+	 * PHY-type, yet. wireless_core_reset will be called once again later,
+	 * when we know the PHY-type. */
+	if (dev->phy.ops)
+		dev->phy.ops->switch_analog(dev, 1);
 
 	macctl = b43_read32(dev, B43_MMIO_MACCTL);
 	macctl &= ~B43_MACCTL_GMODE;
@@ -1174,6 +1162,8 @@
 {
 	/* Top half of Link Quality calculation. */
 
+	if (dev->phy.type != B43_PHYTYPE_G)
+		return;
 	if (dev->noisecalc.calculation_running)
 		return;
 	dev->noisecalc.calculation_running = 1;
@@ -1184,7 +1174,7 @@
 
 static void handle_irq_noise(struct b43_wldev *dev)
 {
-	struct b43_phy *phy = &dev->phy;
+	struct b43_phy_g *phy = dev->phy.g;
 	u16 tmp;
 	u8 noise[4];
 	u8 i, j;
@@ -1192,6 +1182,9 @@
 
 	/* Bottom half of Link Quality calculation. */
 
+	if (dev->phy.type != B43_PHYTYPE_G)
+		return;
+
 	/* Possible race condition: It might be possible that the user
 	 * changed to a different channel in the meantime since we
 	 * started the calculation. We ignore that fact, since it's
@@ -1251,13 +1244,13 @@
 
 static void handle_irq_tbtt_indication(struct b43_wldev *dev)
 {
-	if (b43_is_mode(dev->wl, IEEE80211_IF_TYPE_AP)) {
+	if (b43_is_mode(dev->wl, NL80211_IFTYPE_AP)) {
 		///TODO: PS TBTT
 	} else {
 		if (1 /*FIXME: the last PSpoll frame was sent successfully */ )
 			b43_power_saving_ctl_bits(dev, 0);
 	}
-	if (b43_is_mode(dev->wl, IEEE80211_IF_TYPE_IBSS))
+	if (b43_is_mode(dev->wl, NL80211_IFTYPE_ADHOC))
 		dev->dfq_valid = 1;
 }
 
@@ -1606,8 +1599,8 @@
 	struct b43_wl *wl = dev->wl;
 	u32 cmd, beacon0_valid, beacon1_valid;
 
-	if (!b43_is_mode(wl, IEEE80211_IF_TYPE_AP) &&
-	    !b43_is_mode(wl, IEEE80211_IF_TYPE_MESH_POINT))
+	if (!b43_is_mode(wl, NL80211_IFTYPE_AP) &&
+	    !b43_is_mode(wl, NL80211_IFTYPE_MESH_POINT))
 		return;
 
 	/* This is the bottom half of the asynchronous beacon update. */
@@ -2575,10 +2568,10 @@
 	ctl &= ~B43_MACCTL_BEACPROMISC;
 	ctl |= B43_MACCTL_INFRA;
 
-	if (b43_is_mode(wl, IEEE80211_IF_TYPE_AP) ||
-	    b43_is_mode(wl, IEEE80211_IF_TYPE_MESH_POINT))
+	if (b43_is_mode(wl, NL80211_IFTYPE_AP) ||
+	    b43_is_mode(wl, NL80211_IFTYPE_MESH_POINT))
 		ctl |= B43_MACCTL_AP;
-	else if (b43_is_mode(wl, IEEE80211_IF_TYPE_IBSS))
+	else if (b43_is_mode(wl, NL80211_IFTYPE_ADHOC))
 		ctl &= ~B43_MACCTL_INFRA;
 
 	if (wl->filter_flags & FIF_CONTROL)
@@ -2688,9 +2681,8 @@
 /* This is the opposite of b43_chip_init() */
 static void b43_chip_exit(struct b43_wldev *dev)
 {
-	b43_radio_turn_off(dev, 1);
+	b43_phy_exit(dev);
 	b43_gpio_cleanup(dev);
-	b43_lo_g_cleanup(dev);
 	/* firmware is released later */
 }
 
@@ -2700,7 +2692,7 @@
 static int b43_chip_init(struct b43_wldev *dev)
 {
 	struct b43_phy *phy = &dev->phy;
-	int err, tmp;
+	int err;
 	u32 value32, macctl;
 	u16 value16;
 
@@ -2725,19 +2717,20 @@
 	err = b43_upload_initvals(dev);
 	if (err)
 		goto err_gpio_clean;
-	b43_radio_turn_on(dev);
 
-	b43_write16(dev, 0x03E6, 0x0000);
+	/* Turn the Analog on and initialize the PHY. */
+	phy->ops->switch_analog(dev, 1);
 	err = b43_phy_init(dev);
 	if (err)
-		goto err_radio_off;
+		goto err_gpio_clean;
 
-	/* Select initial Interference Mitigation. */
-	tmp = phy->interfmode;
-	phy->interfmode = B43_INTERFMODE_NONE;
-	b43_radio_set_interference_mitigation(dev, tmp);
+	/* Disable Interference Mitigation. */
+	if (phy->ops->interf_mitigation)
+		phy->ops->interf_mitigation(dev, B43_INTERFMODE_NONE);
 
-	b43_set_rx_antenna(dev, B43_ANTENNA_DEFAULT);
+	/* Select the antennae */
+	if (phy->ops->set_rx_antenna)
+		phy->ops->set_rx_antenna(dev, B43_ANTENNA_DEFAULT);
 	b43_mgmtframe_txantenna(dev, B43_ANTENNA_DEFAULT);
 
 	if (phy->type == B43_PHYTYPE_B) {
@@ -2790,8 +2783,6 @@
 out:
 	return err;
 
-err_radio_off:
-	b43_radio_turn_off(dev, 1);
 err_gpio_clean:
 	b43_gpio_cleanup(dev);
 	return err;
@@ -2799,25 +2790,13 @@
 
 static void b43_periodic_every60sec(struct b43_wldev *dev)
 {
-	struct b43_phy *phy = &dev->phy;
+	const struct b43_phy_operations *ops = dev->phy.ops;
 
-	if (phy->type != B43_PHYTYPE_G)
-		return;
-	if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_RSSI) {
-		b43_mac_suspend(dev);
-		b43_calc_nrssi_slope(dev);
-		if ((phy->radio_ver == 0x2050) && (phy->radio_rev == 8)) {
-			u8 old_chan = phy->channel;
+	if (ops->pwork_60sec)
+		ops->pwork_60sec(dev);
 
-			/* VCO Calibration */
-			if (old_chan >= 8)
-				b43_radio_selectchannel(dev, 1, 0);
-			else
-				b43_radio_selectchannel(dev, 13, 0);
-			b43_radio_selectchannel(dev, old_chan, 0);
-		}
-		b43_mac_enable(dev);
-	}
+	/* Force check the TX power emission now. */
+	b43_phy_txpower_check(dev, B43_TXPWR_IGNORE_TIME);
 }
 
 static void b43_periodic_every30sec(struct b43_wldev *dev)
@@ -2845,32 +2824,8 @@
 		}
 	}
 
-	if (phy->type == B43_PHYTYPE_G) {
-		//TODO: update_aci_moving_average
-		if (phy->aci_enable && phy->aci_wlan_automatic) {
-			b43_mac_suspend(dev);
-			if (!phy->aci_enable && 1 /*TODO: not scanning? */ ) {
-				if (0 /*TODO: bunch of conditions */ ) {
-					b43_radio_set_interference_mitigation
-					    (dev, B43_INTERFMODE_MANUALWLAN);
-				}
-			} else if (1 /*TODO*/) {
-				/*
-				   if ((aci_average > 1000) && !(b43_radio_aci_scan(dev))) {
-				   b43_radio_set_interference_mitigation(dev,
-				   B43_INTERFMODE_NONE);
-				   }
-				 */
-			}
-			b43_mac_enable(dev);
-		} else if (phy->interfmode == B43_INTERFMODE_NONWLAN &&
-			   phy->rev == 1) {
-			//TODO: implement rev1 workaround
-		}
-	}
-	b43_phy_xmitpower(dev);	//FIXME: unless scanning?
-	b43_lo_g_maintanance_work(dev);
-	//TODO for APHY (temperature?)
+	if (phy->ops->pwork_15sec)
+		phy->ops->pwork_15sec(dev);
 
 	atomic_set(&phy->txerr_cnt, B43_PHY_TX_BADNESS_LIMIT);
 	wmb();
@@ -3104,36 +3059,31 @@
 	}
 }
 
-/* Update the QOS parameters in hardware. */
-static void b43_qos_update(struct b43_wldev *dev)
+/* Mapping of mac80211 queue numbers to b43 QoS SHM offsets. */
+static const u16 b43_qos_shm_offsets[] = {
+	/* [mac80211-queue-nr] = SHM_OFFSET, */
+	[0] = B43_QOS_VOICE,
+	[1] = B43_QOS_VIDEO,
+	[2] = B43_QOS_BESTEFFORT,
+	[3] = B43_QOS_BACKGROUND,
+};
+
+/* Update all QOS parameters in hardware. */
+static void b43_qos_upload_all(struct b43_wldev *dev)
 {
 	struct b43_wl *wl = dev->wl;
 	struct b43_qos_params *params;
-	unsigned long flags;
 	unsigned int i;
 
-	/* Mapping of mac80211 queues to b43 SHM offsets. */
-	static const u16 qos_shm_offsets[] = {
-		[0] = B43_QOS_VOICE,
-		[1] = B43_QOS_VIDEO,
-		[2] = B43_QOS_BESTEFFORT,
-		[3] = B43_QOS_BACKGROUND,
-	};
-	BUILD_BUG_ON(ARRAY_SIZE(qos_shm_offsets) != ARRAY_SIZE(wl->qos_params));
+	BUILD_BUG_ON(ARRAY_SIZE(b43_qos_shm_offsets) !=
+		     ARRAY_SIZE(wl->qos_params));
 
 	b43_mac_suspend(dev);
-	spin_lock_irqsave(&wl->irq_lock, flags);
-
 	for (i = 0; i < ARRAY_SIZE(wl->qos_params); i++) {
 		params = &(wl->qos_params[i]);
-		if (params->need_hw_update) {
-			b43_qos_params_upload(dev, &(params->p),
-					      qos_shm_offsets[i]);
-			params->need_hw_update = 0;
-		}
+		b43_qos_params_upload(dev, &(params->p),
+				      b43_qos_shm_offsets[i]);
 	}
-
-	spin_unlock_irqrestore(&wl->irq_lock, flags);
 	b43_mac_enable(dev);
 }
 
@@ -3142,25 +3092,50 @@
 	struct b43_qos_params *params;
 	unsigned int i;
 
+	/* Initialize QoS parameters to sane defaults. */
+
+	BUILD_BUG_ON(ARRAY_SIZE(b43_qos_shm_offsets) !=
+		     ARRAY_SIZE(wl->qos_params));
+
 	for (i = 0; i < ARRAY_SIZE(wl->qos_params); i++) {
 		params = &(wl->qos_params[i]);
 
-		memset(&(params->p), 0, sizeof(params->p));
-		params->p.aifs = -1;
-		params->need_hw_update = 1;
+		switch (b43_qos_shm_offsets[i]) {
+		case B43_QOS_VOICE:
+			params->p.txop = 0;
+			params->p.aifs = 2;
+			params->p.cw_min = 0x0001;
+			params->p.cw_max = 0x0001;
+			break;
+		case B43_QOS_VIDEO:
+			params->p.txop = 0;
+			params->p.aifs = 2;
+			params->p.cw_min = 0x0001;
+			params->p.cw_max = 0x0001;
+			break;
+		case B43_QOS_BESTEFFORT:
+			params->p.txop = 0;
+			params->p.aifs = 3;
+			params->p.cw_min = 0x0001;
+			params->p.cw_max = 0x03FF;
+			break;
+		case B43_QOS_BACKGROUND:
+			params->p.txop = 0;
+			params->p.aifs = 7;
+			params->p.cw_min = 0x0001;
+			params->p.cw_max = 0x03FF;
+			break;
+		default:
+			B43_WARN_ON(1);
+		}
 	}
 }
 
 /* Initialize the core's QOS capabilities */
 static void b43_qos_init(struct b43_wldev *dev)
 {
-	struct b43_wl *wl = dev->wl;
-	unsigned int i;
-
 	/* Upload the current QOS parameters. */
-	for (i = 0; i < ARRAY_SIZE(wl->qos_params); i++)
-		wl->qos_params[i].need_hw_update = 1;
-	b43_qos_update(dev);
+	b43_qos_upload_all(dev);
 
 	/* Enable QOS support. */
 	b43_hf_write(dev, b43_hf_read(dev) | B43_HF_EDCF);
@@ -3169,25 +3144,13 @@
 		    | B43_MMIO_IFSCTL_USE_EDCF);
 }
 
-static void b43_qos_update_work(struct work_struct *work)
-{
-	struct b43_wl *wl = container_of(work, struct b43_wl, qos_update_work);
-	struct b43_wldev *dev;
-
-	mutex_lock(&wl->mutex);
-	dev = wl->current_dev;
-	if (likely(dev && (b43_status(dev) >= B43_STAT_INITIALIZED)))
-		b43_qos_update(dev);
-	mutex_unlock(&wl->mutex);
-}
-
 static int b43_op_conf_tx(struct ieee80211_hw *hw, u16 _queue,
 			  const struct ieee80211_tx_queue_params *params)
 {
 	struct b43_wl *wl = hw_to_b43_wl(hw);
-	unsigned long flags;
+	struct b43_wldev *dev;
 	unsigned int queue = (unsigned int)_queue;
-	struct b43_qos_params *p;
+	int err = -ENODEV;
 
 	if (queue >= ARRAY_SIZE(wl->qos_params)) {
 		/* Queue not available or don't support setting
@@ -3195,16 +3158,25 @@
 		 * confuse mac80211. */
 		return 0;
 	}
+	BUILD_BUG_ON(ARRAY_SIZE(b43_qos_shm_offsets) !=
+		     ARRAY_SIZE(wl->qos_params));
 
-	spin_lock_irqsave(&wl->irq_lock, flags);
-	p = &(wl->qos_params[queue]);
-	memcpy(&(p->p), params, sizeof(p->p));
-	p->need_hw_update = 1;
-	spin_unlock_irqrestore(&wl->irq_lock, flags);
+	mutex_lock(&wl->mutex);
+	dev = wl->current_dev;
+	if (unlikely(!dev || (b43_status(dev) < B43_STAT_INITIALIZED)))
+		goto out_unlock;
 
-	queue_work(hw->workqueue, &wl->qos_update_work);
+	memcpy(&(wl->qos_params[queue].p), params, sizeof(*params));
+	b43_mac_suspend(dev);
+	b43_qos_params_upload(dev, &(wl->qos_params[queue].p),
+			      b43_qos_shm_offsets[queue]);
+	b43_mac_enable(dev);
+	err = 0;
 
-	return 0;
+out_unlock:
+	mutex_unlock(&wl->mutex);
+
+	return err;
 }
 
 static int b43_op_get_tx_stats(struct ieee80211_hw *hw,
@@ -3401,7 +3373,7 @@
 	/* Switch to the requested channel.
 	 * The firmware takes care of races with the TX handler. */
 	if (conf->channel->hw_value != phy->channel)
-		b43_radio_selectchannel(dev, conf->channel->hw_value, 0);
+		b43_switch_channel(dev, conf->channel->hw_value);
 
 	/* Enable/Disable ShortSlot timing. */
 	if ((!!(conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME)) !=
@@ -3417,26 +3389,30 @@
 
 	/* Adjust the desired TX power level. */
 	if (conf->power_level != 0) {
-		if (conf->power_level != phy->power_level) {
-			phy->power_level = conf->power_level;
-			b43_phy_xmitpower(dev);
+		spin_lock_irqsave(&wl->irq_lock, flags);
+		if (conf->power_level != phy->desired_txpower) {
+			phy->desired_txpower = conf->power_level;
+			b43_phy_txpower_check(dev, B43_TXPWR_IGNORE_TIME |
+						   B43_TXPWR_IGNORE_TSSI);
 		}
+		spin_unlock_irqrestore(&wl->irq_lock, flags);
 	}
 
 	/* Antennas for RX and management frame TX. */
 	antenna = b43_antenna_from_ieee80211(dev, conf->antenna_sel_tx);
 	b43_mgmtframe_txantenna(dev, antenna);
 	antenna = b43_antenna_from_ieee80211(dev, conf->antenna_sel_rx);
-	b43_set_rx_antenna(dev, antenna);
+	if (phy->ops->set_rx_antenna)
+		phy->ops->set_rx_antenna(dev, antenna);
 
 	/* Update templates for AP/mesh mode. */
-	if (b43_is_mode(wl, IEEE80211_IF_TYPE_AP) ||
-	    b43_is_mode(wl, IEEE80211_IF_TYPE_MESH_POINT))
+	if (b43_is_mode(wl, NL80211_IFTYPE_AP) ||
+	    b43_is_mode(wl, NL80211_IFTYPE_MESH_POINT))
 		b43_set_beacon_int(dev, conf->beacon_int);
 
 	if (!!conf->radio_enabled != phy->radio_on) {
 		if (conf->radio_enabled) {
-			b43_radio_turn_on(dev);
+			b43_software_rfkill(dev, RFKILL_STATE_UNBLOCKED);
 			b43info(dev->wl, "Radio turned on by software\n");
 			if (!dev->radio_hw_enable) {
 				b43info(dev->wl, "The hardware RF-kill button "
@@ -3444,7 +3420,7 @@
 					"Press the button to turn it on.\n");
 			}
 		} else {
-			b43_radio_turn_off(dev, 0);
+			b43_software_rfkill(dev, RFKILL_STATE_SOFT_BLOCKED);
 			b43info(dev->wl, "Radio turned off by software\n");
 		}
 	}
@@ -3619,14 +3595,14 @@
 	else
 		memset(wl->bssid, 0, ETH_ALEN);
 	if (b43_status(dev) >= B43_STAT_INITIALIZED) {
-		if (b43_is_mode(wl, IEEE80211_IF_TYPE_AP) ||
-		    b43_is_mode(wl, IEEE80211_IF_TYPE_MESH_POINT)) {
+		if (b43_is_mode(wl, NL80211_IFTYPE_AP) ||
+		    b43_is_mode(wl, NL80211_IFTYPE_MESH_POINT)) {
 			B43_WARN_ON(vif->type != wl->if_type);
 			if (conf->changed & IEEE80211_IFCC_SSID)
 				b43_set_ssid(dev, conf->ssid, conf->ssid_len);
 			if (conf->changed & IEEE80211_IFCC_BEACON)
 				b43_update_templates(wl);
-		} else if (b43_is_mode(wl, IEEE80211_IF_TYPE_IBSS)) {
+		} else if (b43_is_mode(wl, NL80211_IFTYPE_ADHOC)) {
 			if (conf->changed & IEEE80211_IFCC_BEACON)
 				b43_update_templates(wl);
 		}
@@ -3818,48 +3794,10 @@
 static void setup_struct_phy_for_init(struct b43_wldev *dev,
 				      struct b43_phy *phy)
 {
-	struct b43_txpower_lo_control *lo;
-	int i;
-
-	memset(phy->minlowsig, 0xFF, sizeof(phy->minlowsig));
-	memset(phy->minlowsigpos, 0, sizeof(phy->minlowsigpos));
-
-	phy->aci_enable = 0;
-	phy->aci_wlan_automatic = 0;
-	phy->aci_hw_rssi = 0;
-
-	phy->radio_off_context.valid = 0;
-
-	lo = phy->lo_control;
-	if (lo) {
-		memset(lo, 0, sizeof(*(phy->lo_control)));
-		lo->tx_bias = 0xFF;
-		INIT_LIST_HEAD(&lo->calib_list);
-	}
-	phy->max_lb_gain = 0;
-	phy->trsw_rx_gain = 0;
-	phy->txpwr_offset = 0;
-
-	/* NRSSI */
-	phy->nrssislope = 0;
-	for (i = 0; i < ARRAY_SIZE(phy->nrssi); i++)
-		phy->nrssi[i] = -1000;
-	for (i = 0; i < ARRAY_SIZE(phy->nrssi_lt); i++)
-		phy->nrssi_lt[i] = i;
-
-	phy->lofcal = 0xFFFF;
-	phy->initval = 0xFFFF;
-
-	phy->interfmode = B43_INTERFMODE_NONE;
-	phy->channel = 0xFF;
-
 	phy->hardware_power_control = !!modparam_hwpctl;
-
+	phy->next_txpwr_check_time = jiffies;
 	/* PHY TX errors counter. */
 	atomic_set(&phy->txerr_cnt, B43_PHY_TX_BADNESS_LIMIT);
-
-	/* OFDM-table address caching. */
-	phy->ofdmtab_addr_direction = B43_OFDMTAB_DIRECTION_UNKNOWN;
 }
 
 static void setup_struct_wldev_for_init(struct b43_wldev *dev)
@@ -3965,7 +3903,7 @@
 		pu_delay = 3700;
 	else
 		pu_delay = 1050;
-	if (b43_is_mode(dev->wl, IEEE80211_IF_TYPE_IBSS) || idle)
+	if (b43_is_mode(dev->wl, NL80211_IFTYPE_ADHOC) || idle)
 		pu_delay = 500;
 	if ((dev->phy.radio_ver == 0x2050) && (dev->phy.radio_rev == 8))
 		pu_delay = max(pu_delay, (u16)2400);
@@ -3979,7 +3917,7 @@
 	u16 pretbtt;
 
 	/* The time value is in microseconds. */
-	if (b43_is_mode(dev->wl, IEEE80211_IF_TYPE_IBSS)) {
+	if (b43_is_mode(dev->wl, NL80211_IFTYPE_ADHOC)) {
 		pretbtt = 2;
 	} else {
 		if (dev->phy.type == B43_PHYTYPE_A)
@@ -3995,7 +3933,6 @@
 /* Locking: wl->mutex */
 static void b43_wireless_core_exit(struct b43_wldev *dev)
 {
-	struct b43_phy *phy = &dev->phy;
 	u32 macctl;
 
 	B43_WARN_ON(b43_status(dev) > B43_STAT_INITIALIZED);
@@ -4016,12 +3953,7 @@
 	b43_dma_free(dev);
 	b43_pio_free(dev);
 	b43_chip_exit(dev);
-	b43_radio_turn_off(dev, 1);
-	b43_switch_analog(dev, 0);
-	if (phy->dyn_tssi_tbl)
-		kfree(phy->tssi2dbm);
-	kfree(phy->lo_control);
-	phy->lo_control = NULL;
+	dev->phy.ops->switch_analog(dev, 0);
 	if (dev->wl->current_beacon) {
 		dev_kfree_skb_any(dev->wl->current_beacon);
 		dev->wl->current_beacon = NULL;
@@ -4052,29 +3984,23 @@
 		b43_wireless_core_reset(dev, tmp);
 	}
 
-	if ((phy->type == B43_PHYTYPE_B) || (phy->type == B43_PHYTYPE_G)) {
-		phy->lo_control =
-		    kzalloc(sizeof(*(phy->lo_control)), GFP_KERNEL);
-		if (!phy->lo_control) {
-			err = -ENOMEM;
-			goto err_busdown;
-		}
-	}
+	/* Reset all data structures. */
 	setup_struct_wldev_for_init(dev);
-
-	err = b43_phy_init_tssi2dbm_table(dev);
-	if (err)
-		goto err_kfree_lo_control;
+	phy->ops->prepare_structs(dev);
 
 	/* Enable IRQ routing to this device. */
 	ssb_pcicore_dev_irqvecs_enable(&bus->pcicore, dev->dev);
 
 	b43_imcfglo_timeouts_workaround(dev);
 	b43_bluetooth_coext_disable(dev);
-	b43_phy_early_init(dev);
+	if (phy->ops->prepare_hardware) {
+		err = phy->ops->prepare_hardware(dev);
+		if (err)
+			goto err_busdown;
+	}
 	err = b43_chip_init(dev);
 	if (err)
-		goto err_kfree_tssitbl;
+		goto err_busdown;
 	b43_shm_write16(dev, B43_SHM_SHARED,
 			B43_SHM_SH_WLCOREREV, dev->dev->id.revision);
 	hf = b43_hf_read(dev);
@@ -4140,15 +4066,9 @@
 out:
 	return err;
 
-      err_chip_exit:
+err_chip_exit:
 	b43_chip_exit(dev);
-      err_kfree_tssitbl:
-	if (phy->dyn_tssi_tbl)
-		kfree(phy->tssi2dbm);
-      err_kfree_lo_control:
-	kfree(phy->lo_control);
-	phy->lo_control = NULL;
-      err_busdown:
+err_busdown:
 	ssb_bus_may_powerdown(bus);
 	B43_WARN_ON(b43_status(dev) != B43_STAT_UNINIT);
 	return err;
@@ -4164,11 +4084,11 @@
 
 	/* TODO: allow WDS/AP devices to coexist */
 
-	if (conf->type != IEEE80211_IF_TYPE_AP &&
-	    conf->type != IEEE80211_IF_TYPE_MESH_POINT &&
-	    conf->type != IEEE80211_IF_TYPE_STA &&
-	    conf->type != IEEE80211_IF_TYPE_WDS &&
-	    conf->type != IEEE80211_IF_TYPE_IBSS)
+	if (conf->type != NL80211_IFTYPE_AP &&
+	    conf->type != NL80211_IFTYPE_MESH_POINT &&
+	    conf->type != NL80211_IFTYPE_STATION &&
+	    conf->type != NL80211_IFTYPE_WDS &&
+	    conf->type != NL80211_IFTYPE_ADHOC)
 		return -EOPNOTSUPP;
 
 	mutex_lock(&wl->mutex);
@@ -4283,7 +4203,6 @@
 	struct b43_wldev *dev = wl->current_dev;
 
 	b43_rfkill_exit(dev);
-	cancel_work_sync(&(wl->qos_update_work));
 	cancel_work_sync(&(wl->beacon_update_trigger));
 
 	mutex_lock(&wl->mutex);
@@ -4291,6 +4210,8 @@
 		b43_wireless_core_stop(dev);
 	b43_wireless_core_exit(dev);
 	mutex_unlock(&wl->mutex);
+
+	cancel_work_sync(&(wl->txpower_adjust_work));
 }
 
 static int b43_op_set_retry_limit(struct ieee80211_hw *hw,
@@ -4313,7 +4234,8 @@
 	return err;
 }
 
-static int b43_op_beacon_set_tim(struct ieee80211_hw *hw, int aid, int set)
+static int b43_op_beacon_set_tim(struct ieee80211_hw *hw,
+				 struct ieee80211_sta *sta, bool set)
 {
 	struct b43_wl *wl = hw_to_b43_wl(hw);
 	unsigned long flags;
@@ -4328,7 +4250,7 @@
 static void b43_op_sta_notify(struct ieee80211_hw *hw,
 			      struct ieee80211_vif *vif,
 			      enum sta_notify_cmd notify_cmd,
-			      const u8 *addr)
+			      struct ieee80211_sta *sta)
 {
 	struct b43_wl *wl = hw_to_b43_wl(hw);
 
@@ -4422,6 +4344,7 @@
 	/* We release firmware that late to not be required to re-request
 	 * is all the time when we reinit the core. */
 	b43_release_firmware(dev);
+	b43_phy_free(dev);
 }
 
 static int b43_wireless_core_attach(struct b43_wldev *dev)
@@ -4495,30 +4418,35 @@
 		}
 	}
 
+	err = b43_phy_allocate(dev);
+	if (err)
+		goto err_powerdown;
+
 	dev->phy.gmode = have_2ghz_phy;
 	tmp = dev->phy.gmode ? B43_TMSLOW_GMODE : 0;
 	b43_wireless_core_reset(dev, tmp);
 
 	err = b43_validate_chipaccess(dev);
 	if (err)
-		goto err_powerdown;
+		goto err_phy_free;
 	err = b43_setup_bands(dev, have_2ghz_phy, have_5ghz_phy);
 	if (err)
-		goto err_powerdown;
+		goto err_phy_free;
 
 	/* Now set some default "current_dev" */
 	if (!wl->current_dev)
 		wl->current_dev = dev;
 	INIT_WORK(&dev->restart_work, b43_chip_reset);
 
-	b43_radio_turn_off(dev, 1);
-	b43_switch_analog(dev, 0);
+	dev->phy.ops->switch_analog(dev, 0);
 	ssb_device_disable(dev->dev, 0);
 	ssb_bus_may_powerdown(bus);
 
 out:
 	return err;
 
+err_phy_free:
+	b43_phy_free(dev);
 err_powerdown:
 	ssb_bus_may_powerdown(bus);
 	return err;
@@ -4615,9 +4543,11 @@
 		pdev = bus->host_pci;
 		if (IS_PDEV(pdev, BROADCOM, 0x4318, ASUSTEK, 0x100F) ||
 		    IS_PDEV(pdev, BROADCOM, 0x4320,    DELL, 0x0003) ||
+		    IS_PDEV(pdev, BROADCOM, 0x4320,      HP, 0x12f8) ||
 		    IS_PDEV(pdev, BROADCOM, 0x4320, LINKSYS, 0x0015) ||
 		    IS_PDEV(pdev, BROADCOM, 0x4320, LINKSYS, 0x0014) ||
-		    IS_PDEV(pdev, BROADCOM, 0x4320, LINKSYS, 0x0013))
+		    IS_PDEV(pdev, BROADCOM, 0x4320, LINKSYS, 0x0013) ||
+		    IS_PDEV(pdev, BROADCOM, 0x4320, MOTOROLA, 0x7010))
 			bus->sprom.boardflags_lo &= ~B43_BFL_BTCOEXIST;
 	}
 }
@@ -4650,7 +4580,15 @@
 		    IEEE80211_HW_SIGNAL_DBM |
 		    IEEE80211_HW_NOISE_DBM;
 
+	hw->wiphy->interface_modes =
+		BIT(NL80211_IFTYPE_AP) |
+		BIT(NL80211_IFTYPE_MESH_POINT) |
+		BIT(NL80211_IFTYPE_STATION) |
+		BIT(NL80211_IFTYPE_WDS) |
+		BIT(NL80211_IFTYPE_ADHOC);
+
 	hw->queues = b43_modparam_qos ? 4 : 1;
+	hw->max_altrates = 1;
 	SET_IEEE80211_DEV(hw, dev->dev);
 	if (is_valid_ether_addr(sprom->et1mac))
 		SET_IEEE80211_PERM_ADDR(hw, sprom->et1mac);
@@ -4667,8 +4605,8 @@
 	spin_lock_init(&wl->shm_lock);
 	mutex_init(&wl->mutex);
 	INIT_LIST_HEAD(&wl->devlist);
-	INIT_WORK(&wl->qos_update_work, b43_qos_update_work);
 	INIT_WORK(&wl->beacon_update_trigger, b43_beacon_update_trigger_work);
+	INIT_WORK(&wl->txpower_adjust_work, b43_phy_txpower_adjust_work);
 
 	ssb_set_devtypedata(dev, wl);
 	b43info(wl, "Broadcom %04X WLAN found\n", dev->bus->chip_id);
diff --git a/drivers/net/wireless/b43/nphy.c b/drivers/net/wireless/b43/nphy.c
deleted file mode 100644
index 644eed9..0000000
--- a/drivers/net/wireless/b43/nphy.c
+++ /dev/null
@@ -1,486 +0,0 @@
-/*
-
-  Broadcom B43 wireless driver
-  IEEE 802.11n PHY support
-
-  Copyright (c) 2008 Michael Buesch <mb@bu3sch.de>
-
-  This program is free software; you can redistribute it and/or modify
-  it under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 of the License, or
-  (at your option) any later version.
-
-  This program is distributed in the hope that it will be useful,
-  but WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-  GNU General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with this program; see the file COPYING.  If not, write to
-  the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
-  Boston, MA 02110-1301, USA.
-
-*/
-
-#include <linux/delay.h>
-#include <linux/types.h>
-
-#include "b43.h"
-#include "nphy.h"
-#include "tables_nphy.h"
-
-
-void b43_nphy_set_rxantenna(struct b43_wldev *dev, int antenna)
-{//TODO
-}
-
-void b43_nphy_xmitpower(struct b43_wldev *dev)
-{//TODO
-}
-
-static void b43_chantab_radio_upload(struct b43_wldev *dev,
-				     const struct b43_nphy_channeltab_entry *e)
-{
-	b43_radio_write16(dev, B2055_PLL_REF, e->radio_pll_ref);
-	b43_radio_write16(dev, B2055_RF_PLLMOD0, e->radio_rf_pllmod0);
-	b43_radio_write16(dev, B2055_RF_PLLMOD1, e->radio_rf_pllmod1);
-	b43_radio_write16(dev, B2055_VCO_CAPTAIL, e->radio_vco_captail);
-	b43_radio_write16(dev, B2055_VCO_CAL1, e->radio_vco_cal1);
-	b43_radio_write16(dev, B2055_VCO_CAL2, e->radio_vco_cal2);
-	b43_radio_write16(dev, B2055_PLL_LFC1, e->radio_pll_lfc1);
-	b43_radio_write16(dev, B2055_PLL_LFR1, e->radio_pll_lfr1);
-	b43_radio_write16(dev, B2055_PLL_LFC2, e->radio_pll_lfc2);
-	b43_radio_write16(dev, B2055_LGBUF_CENBUF, e->radio_lgbuf_cenbuf);
-	b43_radio_write16(dev, B2055_LGEN_TUNE1, e->radio_lgen_tune1);
-	b43_radio_write16(dev, B2055_LGEN_TUNE2, e->radio_lgen_tune2);
-	b43_radio_write16(dev, B2055_C1_LGBUF_ATUNE, e->radio_c1_lgbuf_atune);
-	b43_radio_write16(dev, B2055_C1_LGBUF_GTUNE, e->radio_c1_lgbuf_gtune);
-	b43_radio_write16(dev, B2055_C1_RX_RFR1, e->radio_c1_rx_rfr1);
-	b43_radio_write16(dev, B2055_C1_TX_PGAPADTN, e->radio_c1_tx_pgapadtn);
-	b43_radio_write16(dev, B2055_C1_TX_MXBGTRIM, e->radio_c1_tx_mxbgtrim);
-	b43_radio_write16(dev, B2055_C2_LGBUF_ATUNE, e->radio_c2_lgbuf_atune);
-	b43_radio_write16(dev, B2055_C2_LGBUF_GTUNE, e->radio_c2_lgbuf_gtune);
-	b43_radio_write16(dev, B2055_C2_RX_RFR1, e->radio_c2_rx_rfr1);
-	b43_radio_write16(dev, B2055_C2_TX_PGAPADTN, e->radio_c2_tx_pgapadtn);
-	b43_radio_write16(dev, B2055_C2_TX_MXBGTRIM, e->radio_c2_tx_mxbgtrim);
-}
-
-static void b43_chantab_phy_upload(struct b43_wldev *dev,
-				   const struct b43_nphy_channeltab_entry *e)
-{
-	b43_phy_write(dev, B43_NPHY_BW1A, e->phy_bw1a);
-	b43_phy_write(dev, B43_NPHY_BW2, e->phy_bw2);
-	b43_phy_write(dev, B43_NPHY_BW3, e->phy_bw3);
-	b43_phy_write(dev, B43_NPHY_BW4, e->phy_bw4);
-	b43_phy_write(dev, B43_NPHY_BW5, e->phy_bw5);
-	b43_phy_write(dev, B43_NPHY_BW6, e->phy_bw6);
-}
-
-static void b43_nphy_tx_power_fix(struct b43_wldev *dev)
-{
-	//TODO
-}
-
-/* Tune the hardware to a new channel. Don't call this directly.
- * Use b43_radio_selectchannel() */
-int b43_nphy_selectchannel(struct b43_wldev *dev, u8 channel)
-{
-	const struct b43_nphy_channeltab_entry *tabent;
-
-	tabent = b43_nphy_get_chantabent(dev, channel);
-	if (!tabent)
-		return -ESRCH;
-
-	//FIXME enable/disable band select upper20 in RXCTL
-	if (0 /*FIXME 5Ghz*/)
-		b43_radio_maskset(dev, B2055_MASTER1, 0xFF8F, 0x20);
-	else
-		b43_radio_maskset(dev, B2055_MASTER1, 0xFF8F, 0x50);
-	b43_chantab_radio_upload(dev, tabent);
-	udelay(50);
-	b43_radio_write16(dev, B2055_VCO_CAL10, 5);
-	b43_radio_write16(dev, B2055_VCO_CAL10, 45);
-	b43_radio_write16(dev, B2055_VCO_CAL10, 65);
-	udelay(300);
-	if (0 /*FIXME 5Ghz*/)
-		b43_phy_set(dev, B43_NPHY_BANDCTL, B43_NPHY_BANDCTL_5GHZ);
-	else
-		b43_phy_mask(dev, B43_NPHY_BANDCTL, ~B43_NPHY_BANDCTL_5GHZ);
-	b43_chantab_phy_upload(dev, tabent);
-	b43_nphy_tx_power_fix(dev);
-
-	return 0;
-}
-
-static void b43_radio_init2055_pre(struct b43_wldev *dev)
-{
-	b43_phy_mask(dev, B43_NPHY_RFCTL_CMD,
-		     ~B43_NPHY_RFCTL_CMD_PORFORCE);
-	b43_phy_set(dev, B43_NPHY_RFCTL_CMD,
-		    B43_NPHY_RFCTL_CMD_CHIP0PU |
-		    B43_NPHY_RFCTL_CMD_OEPORFORCE);
-	b43_phy_set(dev, B43_NPHY_RFCTL_CMD,
-		    B43_NPHY_RFCTL_CMD_PORFORCE);
-}
-
-static void b43_radio_init2055_post(struct b43_wldev *dev)
-{
-	struct ssb_sprom *sprom = &(dev->dev->bus->sprom);
-	struct ssb_boardinfo *binfo = &(dev->dev->bus->boardinfo);
-	int i;
-	u16 val;
-
-	b43_radio_mask(dev, B2055_MASTER1, 0xFFF3);
-	msleep(1);
-	if ((sprom->revision != 4) || !(sprom->boardflags_hi & 0x0002)) {
-		if ((binfo->vendor != PCI_VENDOR_ID_BROADCOM) ||
-		    (binfo->type != 0x46D) ||
-		    (binfo->rev < 0x41)) {
-			b43_radio_mask(dev, B2055_C1_RX_BB_REG, 0x7F);
-			b43_radio_mask(dev, B2055_C1_RX_BB_REG, 0x7F);
-			msleep(1);
-		}
-	}
-	b43_radio_maskset(dev, B2055_RRCCAL_NOPTSEL, 0x3F, 0x2C);
-	msleep(1);
-	b43_radio_write16(dev, B2055_CAL_MISC, 0x3C);
-	msleep(1);
-	b43_radio_mask(dev, B2055_CAL_MISC, 0xFFBE);
-	msleep(1);
-	b43_radio_set(dev, B2055_CAL_LPOCTL, 0x80);
-	msleep(1);
-	b43_radio_set(dev, B2055_CAL_MISC, 0x1);
-	msleep(1);
-	b43_radio_set(dev, B2055_CAL_MISC, 0x40);
-	msleep(1);
-	for (i = 0; i < 100; i++) {
-		val = b43_radio_read16(dev, B2055_CAL_COUT2);
-		if (val & 0x80)
-			break;
-		udelay(10);
-	}
-	msleep(1);
-	b43_radio_mask(dev, B2055_CAL_LPOCTL, 0xFF7F);
-	msleep(1);
-	b43_radio_selectchannel(dev, dev->phy.channel, 0);
-	b43_radio_write16(dev, B2055_C1_RX_BB_LPF, 0x9);
-	b43_radio_write16(dev, B2055_C2_RX_BB_LPF, 0x9);
-	b43_radio_write16(dev, B2055_C1_RX_BB_MIDACHP, 0x83);
-	b43_radio_write16(dev, B2055_C2_RX_BB_MIDACHP, 0x83);
-}
-
-/* Initialize a Broadcom 2055 N-radio */
-static void b43_radio_init2055(struct b43_wldev *dev)
-{
-	b43_radio_init2055_pre(dev);
-	if (b43_status(dev) < B43_STAT_INITIALIZED)
-		b2055_upload_inittab(dev, 0, 1);
-	else
-		b2055_upload_inittab(dev, 0/*FIXME on 5ghz band*/, 0);
-	b43_radio_init2055_post(dev);
-}
-
-void b43_nphy_radio_turn_on(struct b43_wldev *dev)
-{
-	b43_radio_init2055(dev);
-}
-
-void b43_nphy_radio_turn_off(struct b43_wldev *dev)
-{
-	b43_phy_mask(dev, B43_NPHY_RFCTL_CMD,
-		     ~B43_NPHY_RFCTL_CMD_EN);
-}
-
-#define ntab_upload(dev, offset, data) do { \
-		unsigned int i;						\
-		for (i = 0; i < (offset##_SIZE); i++)			\
-			b43_ntab_write(dev, (offset) + i, (data)[i]);	\
-	} while (0)
-
-/* Upload the N-PHY tables. */
-static void b43_nphy_tables_init(struct b43_wldev *dev)
-{
-	/* Static tables */
-	ntab_upload(dev, B43_NTAB_FRAMESTRUCT, b43_ntab_framestruct);
-	ntab_upload(dev, B43_NTAB_FRAMELT, b43_ntab_framelookup);
-	ntab_upload(dev, B43_NTAB_TMAP, b43_ntab_tmap);
-	ntab_upload(dev, B43_NTAB_TDTRN, b43_ntab_tdtrn);
-	ntab_upload(dev, B43_NTAB_INTLEVEL, b43_ntab_intlevel);
-	ntab_upload(dev, B43_NTAB_PILOT, b43_ntab_pilot);
-	ntab_upload(dev, B43_NTAB_PILOTLT, b43_ntab_pilotlt);
-	ntab_upload(dev, B43_NTAB_TDI20A0, b43_ntab_tdi20a0);
-	ntab_upload(dev, B43_NTAB_TDI20A1, b43_ntab_tdi20a1);
-	ntab_upload(dev, B43_NTAB_TDI40A0, b43_ntab_tdi40a0);
-	ntab_upload(dev, B43_NTAB_TDI40A1, b43_ntab_tdi40a1);
-	ntab_upload(dev, B43_NTAB_BDI, b43_ntab_bdi);
-	ntab_upload(dev, B43_NTAB_CHANEST, b43_ntab_channelest);
-	ntab_upload(dev, B43_NTAB_MCS, b43_ntab_mcs);
-
-	/* Volatile tables */
-	ntab_upload(dev, B43_NTAB_NOISEVAR10, b43_ntab_noisevar10);
-	ntab_upload(dev, B43_NTAB_NOISEVAR11, b43_ntab_noisevar11);
-	ntab_upload(dev, B43_NTAB_C0_ESTPLT, b43_ntab_estimatepowerlt0);
-	ntab_upload(dev, B43_NTAB_C1_ESTPLT, b43_ntab_estimatepowerlt1);
-	ntab_upload(dev, B43_NTAB_C0_ADJPLT, b43_ntab_adjustpower0);
-	ntab_upload(dev, B43_NTAB_C1_ADJPLT, b43_ntab_adjustpower1);
-	ntab_upload(dev, B43_NTAB_C0_GAINCTL, b43_ntab_gainctl0);
-	ntab_upload(dev, B43_NTAB_C1_GAINCTL, b43_ntab_gainctl1);
-	ntab_upload(dev, B43_NTAB_C0_IQLT, b43_ntab_iqlt0);
-	ntab_upload(dev, B43_NTAB_C1_IQLT, b43_ntab_iqlt1);
-	ntab_upload(dev, B43_NTAB_C0_LOFEEDTH, b43_ntab_loftlt0);
-	ntab_upload(dev, B43_NTAB_C1_LOFEEDTH, b43_ntab_loftlt1);
-}
-
-static void b43_nphy_workarounds(struct b43_wldev *dev)
-{
-	struct b43_phy *phy = &dev->phy;
-	unsigned int i;
-
-	b43_phy_set(dev, B43_NPHY_IQFLIP,
-		    B43_NPHY_IQFLIP_ADC1 | B43_NPHY_IQFLIP_ADC2);
-	if (1 /* FIXME band is 2.4GHz */) {
-		b43_phy_set(dev, B43_NPHY_CLASSCTL,
-			    B43_NPHY_CLASSCTL_CCKEN);
-	} else {
-		b43_phy_mask(dev, B43_NPHY_CLASSCTL,
-			     ~B43_NPHY_CLASSCTL_CCKEN);
-	}
-	b43_radio_set(dev, B2055_C1_TX_RF_SPARE, 0x8);
-	b43_phy_write(dev, B43_NPHY_TXFRAMEDELAY, 8);
-
-	/* Fixup some tables */
-	b43_ntab_write(dev, B43_NTAB16(8, 0x00), 0xA);
-	b43_ntab_write(dev, B43_NTAB16(8, 0x10), 0xA);
-	b43_ntab_write(dev, B43_NTAB16(8, 0x02), 0xCDAA);
-	b43_ntab_write(dev, B43_NTAB16(8, 0x12), 0xCDAA);
-	b43_ntab_write(dev, B43_NTAB16(8, 0x08), 0);
-	b43_ntab_write(dev, B43_NTAB16(8, 0x18), 0);
-	b43_ntab_write(dev, B43_NTAB16(8, 0x07), 0x7AAB);
-	b43_ntab_write(dev, B43_NTAB16(8, 0x17), 0x7AAB);
-	b43_ntab_write(dev, B43_NTAB16(8, 0x06), 0x800);
-	b43_ntab_write(dev, B43_NTAB16(8, 0x16), 0x800);
-
-	b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_LO1, 0x2D8);
-	b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_UP1, 0x301);
-	b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_LO2, 0x2D8);
-	b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_UP2, 0x301);
-
-	//TODO set RF sequence
-
-	/* Set narrowband clip threshold */
-	b43_phy_write(dev, B43_NPHY_C1_NBCLIPTHRES, 66);
-	b43_phy_write(dev, B43_NPHY_C2_NBCLIPTHRES, 66);
-
-	/* Set wideband clip 2 threshold */
-	b43_phy_maskset(dev, B43_NPHY_C1_CLIPWBTHRES,
-			~B43_NPHY_C1_CLIPWBTHRES_CLIP2,
-			21 << B43_NPHY_C1_CLIPWBTHRES_CLIP2_SHIFT);
-	b43_phy_maskset(dev, B43_NPHY_C2_CLIPWBTHRES,
-			~B43_NPHY_C2_CLIPWBTHRES_CLIP2,
-			21 << B43_NPHY_C2_CLIPWBTHRES_CLIP2_SHIFT);
-
-	/* Set Clip 2 detect */
-	b43_phy_set(dev, B43_NPHY_C1_CGAINI,
-		    B43_NPHY_C1_CGAINI_CL2DETECT);
-	b43_phy_set(dev, B43_NPHY_C2_CGAINI,
-		    B43_NPHY_C2_CGAINI_CL2DETECT);
-
-	if (0 /*FIXME*/) {
-		/* Set dwell lengths */
-		b43_phy_write(dev, B43_NPHY_CLIP1_NBDWELL_LEN, 43);
-		b43_phy_write(dev, B43_NPHY_CLIP2_NBDWELL_LEN, 43);
-		b43_phy_write(dev, B43_NPHY_W1CLIP1_DWELL_LEN, 9);
-		b43_phy_write(dev, B43_NPHY_W1CLIP2_DWELL_LEN, 9);
-
-		/* Set gain backoff */
-		b43_phy_maskset(dev, B43_NPHY_C1_CGAINI,
-				~B43_NPHY_C1_CGAINI_GAINBKOFF,
-				1 << B43_NPHY_C1_CGAINI_GAINBKOFF_SHIFT);
-		b43_phy_maskset(dev, B43_NPHY_C2_CGAINI,
-				~B43_NPHY_C2_CGAINI_GAINBKOFF,
-				1 << B43_NPHY_C2_CGAINI_GAINBKOFF_SHIFT);
-
-		/* Set HPVGA2 index */
-		b43_phy_maskset(dev, B43_NPHY_C1_INITGAIN,
-				~B43_NPHY_C1_INITGAIN_HPVGA2,
-				6 << B43_NPHY_C1_INITGAIN_HPVGA2_SHIFT);
-		b43_phy_maskset(dev, B43_NPHY_C2_INITGAIN,
-				~B43_NPHY_C2_INITGAIN_HPVGA2,
-				6 << B43_NPHY_C2_INITGAIN_HPVGA2_SHIFT);
-
-		//FIXME verify that the specs really mean to use autoinc here.
-		for (i = 0; i < 3; i++)
-			b43_ntab_write(dev, B43_NTAB16(7, 0x106) + i, 0x673);
-	}
-
-	/* Set minimum gain value */
-	b43_phy_maskset(dev, B43_NPHY_C1_MINMAX_GAIN,
-			~B43_NPHY_C1_MINGAIN,
-			23 << B43_NPHY_C1_MINGAIN_SHIFT);
-	b43_phy_maskset(dev, B43_NPHY_C2_MINMAX_GAIN,
-			~B43_NPHY_C2_MINGAIN,
-			23 << B43_NPHY_C2_MINGAIN_SHIFT);
-
-	if (phy->rev < 2) {
-		b43_phy_mask(dev, B43_NPHY_SCRAM_SIGCTL,
-			     ~B43_NPHY_SCRAM_SIGCTL_SCM);
-	}
-
-	/* Set phase track alpha and beta */
-	b43_phy_write(dev, B43_NPHY_PHASETR_A0, 0x125);
-	b43_phy_write(dev, B43_NPHY_PHASETR_A1, 0x1B3);
-	b43_phy_write(dev, B43_NPHY_PHASETR_A2, 0x105);
-	b43_phy_write(dev, B43_NPHY_PHASETR_B0, 0x16E);
-	b43_phy_write(dev, B43_NPHY_PHASETR_B1, 0xCD);
-	b43_phy_write(dev, B43_NPHY_PHASETR_B2, 0x20);
-}
-
-static void b43_nphy_reset_cca(struct b43_wldev *dev)
-{
-	u16 bbcfg;
-
-	ssb_write32(dev->dev, SSB_TMSLOW,
-		    ssb_read32(dev->dev, SSB_TMSLOW) | SSB_TMSLOW_FGC);
-	bbcfg = b43_phy_read(dev, B43_NPHY_BBCFG);
-	b43_phy_set(dev, B43_NPHY_BBCFG, B43_NPHY_BBCFG_RSTCCA);
-	b43_phy_write(dev, B43_NPHY_BBCFG,
-		      bbcfg & ~B43_NPHY_BBCFG_RSTCCA);
-	ssb_write32(dev->dev, SSB_TMSLOW,
-		    ssb_read32(dev->dev, SSB_TMSLOW) & ~SSB_TMSLOW_FGC);
-}
-
-enum b43_nphy_rf_sequence {
-	B43_RFSEQ_RX2TX,
-	B43_RFSEQ_TX2RX,
-	B43_RFSEQ_RESET2RX,
-	B43_RFSEQ_UPDATE_GAINH,
-	B43_RFSEQ_UPDATE_GAINL,
-	B43_RFSEQ_UPDATE_GAINU,
-};
-
-static void b43_nphy_force_rf_sequence(struct b43_wldev *dev,
-				       enum b43_nphy_rf_sequence seq)
-{
-	static const u16 trigger[] = {
-		[B43_RFSEQ_RX2TX]		= B43_NPHY_RFSEQTR_RX2TX,
-		[B43_RFSEQ_TX2RX]		= B43_NPHY_RFSEQTR_TX2RX,
-		[B43_RFSEQ_RESET2RX]		= B43_NPHY_RFSEQTR_RST2RX,
-		[B43_RFSEQ_UPDATE_GAINH]	= B43_NPHY_RFSEQTR_UPGH,
-		[B43_RFSEQ_UPDATE_GAINL]	= B43_NPHY_RFSEQTR_UPGL,
-		[B43_RFSEQ_UPDATE_GAINU]	= B43_NPHY_RFSEQTR_UPGU,
-	};
-	int i;
-
-	B43_WARN_ON(seq >= ARRAY_SIZE(trigger));
-
-	b43_phy_set(dev, B43_NPHY_RFSEQMODE,
-		    B43_NPHY_RFSEQMODE_CAOVER | B43_NPHY_RFSEQMODE_TROVER);
-	b43_phy_set(dev, B43_NPHY_RFSEQTR, trigger[seq]);
-	for (i = 0; i < 200; i++) {
-		if (!(b43_phy_read(dev, B43_NPHY_RFSEQST) & trigger[seq]))
-			goto ok;
-		msleep(1);
-	}
-	b43err(dev->wl, "RF sequence status timeout\n");
-ok:
-	b43_phy_mask(dev, B43_NPHY_RFSEQMODE,
-		     ~(B43_NPHY_RFSEQMODE_CAOVER | B43_NPHY_RFSEQMODE_TROVER));
-}
-
-static void b43_nphy_bphy_init(struct b43_wldev *dev)
-{
-	unsigned int i;
-	u16 val;
-
-	val = 0x1E1F;
-	for (i = 0; i < 14; i++) {
-		b43_phy_write(dev, B43_PHY_N_BMODE(0x88 + i), val);
-		val -= 0x202;
-	}
-	val = 0x3E3F;
-	for (i = 0; i < 16; i++) {
-		b43_phy_write(dev, B43_PHY_N_BMODE(0x97 + i), val);
-		val -= 0x202;
-	}
-	b43_phy_write(dev, B43_PHY_N_BMODE(0x38), 0x668);
-}
-
-/* RSSI Calibration */
-static void b43_nphy_rssi_cal(struct b43_wldev *dev, u8 type)
-{
-	//TODO
-}
-
-int b43_phy_initn(struct b43_wldev *dev)
-{
-	struct b43_phy *phy = &dev->phy;
-	u16 tmp;
-
-	//TODO: Spectral management
-	b43_nphy_tables_init(dev);
-
-	/* Clear all overrides */
-	b43_phy_write(dev, B43_NPHY_RFCTL_OVER, 0);
-	b43_phy_write(dev, B43_NPHY_RFCTL_INTC1, 0);
-	b43_phy_write(dev, B43_NPHY_RFCTL_INTC2, 0);
-	b43_phy_write(dev, B43_NPHY_RFCTL_INTC3, 0);
-	b43_phy_write(dev, B43_NPHY_RFCTL_INTC4, 0);
-	b43_phy_mask(dev, B43_NPHY_RFSEQMODE,
-		     ~(B43_NPHY_RFSEQMODE_CAOVER |
-		       B43_NPHY_RFSEQMODE_TROVER));
-	b43_phy_write(dev, B43_NPHY_AFECTL_OVER, 0);
-
-	tmp = (phy->rev < 2) ? 64 : 59;
-	b43_phy_maskset(dev, B43_NPHY_BPHY_CTL3,
-			~B43_NPHY_BPHY_CTL3_SCALE,
-			tmp << B43_NPHY_BPHY_CTL3_SCALE_SHIFT);
-
-	b43_phy_write(dev, B43_NPHY_AFESEQ_TX2RX_PUD_20M, 0x20);
-	b43_phy_write(dev, B43_NPHY_AFESEQ_TX2RX_PUD_40M, 0x20);
-
-	b43_phy_write(dev, B43_NPHY_TXREALFD, 184);
-	b43_phy_write(dev, B43_NPHY_MIMO_CRSTXEXT, 200);
-	b43_phy_write(dev, B43_NPHY_PLOAD_CSENSE_EXTLEN, 80);
-	b43_phy_write(dev, B43_NPHY_C2_BCLIPBKOFF, 511);
-
-	//TODO MIMO-Config
-	//TODO Update TX/RX chain
-
-	if (phy->rev < 2) {
-		b43_phy_write(dev, B43_NPHY_DUP40_GFBL, 0xAA8);
-		b43_phy_write(dev, B43_NPHY_DUP40_BL, 0x9A4);
-	}
-	b43_nphy_workarounds(dev);
-	b43_nphy_reset_cca(dev);
-
-	ssb_write32(dev->dev, SSB_TMSLOW,
-		    ssb_read32(dev->dev, SSB_TMSLOW) | B43_TMSLOW_MACPHYCLKEN);
-	b43_nphy_force_rf_sequence(dev, B43_RFSEQ_RX2TX);
-	b43_nphy_force_rf_sequence(dev, B43_RFSEQ_RESET2RX);
-
-	b43_phy_read(dev, B43_NPHY_CLASSCTL); /* dummy read */
-	//TODO read core1/2 clip1 thres regs
-
-	if (1 /* FIXME Band is 2.4GHz */)
-		b43_nphy_bphy_init(dev);
-	//TODO disable TX power control
-	//TODO Fix the TX power settings
-	//TODO Init periodic calibration with reason 3
-	b43_nphy_rssi_cal(dev, 2);
-	b43_nphy_rssi_cal(dev, 0);
-	b43_nphy_rssi_cal(dev, 1);
-	//TODO get TX gain
-	//TODO init superswitch
-	//TODO calibrate LO
-	//TODO idle TSSI TX pctl
-	//TODO TX power control power setup
-	//TODO table writes
-	//TODO TX power control coefficients
-	//TODO enable TX power control
-	//TODO control antenna selection
-	//TODO init radar detection
-	//TODO reset channel if changed
-
-	b43err(dev->wl, "IEEE 802.11n devices are not supported, yet.\n");
-	return 0;
-}
diff --git a/drivers/net/wireless/b43/nphy.h b/drivers/net/wireless/b43/nphy.h
deleted file mode 100644
index faf46b9..0000000
--- a/drivers/net/wireless/b43/nphy.h
+++ /dev/null
@@ -1,972 +0,0 @@
-#ifndef B43_NPHY_H_
-#define B43_NPHY_H_
-
-#include "phy.h"
-
-
-/* N-PHY registers. */
-
-#define B43_NPHY_BBCFG				B43_PHY_N(0x001) /* BB config */
-#define  B43_NPHY_BBCFG_RSTCCA			0x4000 /* Reset CCA */
-#define  B43_NPHY_BBCFG_RSTRX			0x8000 /* Reset RX */
-#define B43_NPHY_CHANNEL			B43_PHY_N(0x005) /* Channel */
-#define B43_NPHY_TXERR				B43_PHY_N(0x007) /* TX error */
-#define B43_NPHY_BANDCTL			B43_PHY_N(0x009) /* Band control */
-#define  B43_NPHY_BANDCTL_5GHZ			0x0001 /* Use the 5GHz band */
-#define B43_NPHY_4WI_ADDR			B43_PHY_N(0x00B) /* Four-wire bus address */
-#define B43_NPHY_4WI_DATAHI			B43_PHY_N(0x00C) /* Four-wire bus data high */
-#define B43_NPHY_4WI_DATALO			B43_PHY_N(0x00D) /* Four-wire bus data low */
-#define B43_NPHY_BIST_STAT0			B43_PHY_N(0x00E) /* Built-in self test status 0 */
-#define B43_NPHY_BIST_STAT1			B43_PHY_N(0x00F) /* Built-in self test status 1 */
-
-#define B43_NPHY_C1_DESPWR			B43_PHY_N(0x018) /* Core 1 desired power */
-#define B43_NPHY_C1_CCK_DESPWR			B43_PHY_N(0x019) /* Core 1 CCK desired power */
-#define B43_NPHY_C1_BCLIPBKOFF			B43_PHY_N(0x01A) /* Core 1 barely clip backoff */
-#define B43_NPHY_C1_CCK_BCLIPBKOFF		B43_PHY_N(0x01B) /* Core 1 CCK barely clip backoff */
-#define B43_NPHY_C1_CGAINI			B43_PHY_N(0x01C) /* Core 1 compute gain info */
-#define  B43_NPHY_C1_CGAINI_GAINBKOFF		0x001F /* Gain backoff */
-#define  B43_NPHY_C1_CGAINI_GAINBKOFF_SHIFT	0
-#define  B43_NPHY_C1_CGAINI_CLIPGBKOFF		0x03E0 /* Clip gain backoff */
-#define  B43_NPHY_C1_CGAINI_CLIPGBKOFF_SHIFT	5
-#define  B43_NPHY_C1_CGAINI_GAINSTEP		0x1C00 /* Gain step */
-#define  B43_NPHY_C1_CGAINI_GAINSTEP_SHIFT	10
-#define  B43_NPHY_C1_CGAINI_CL2DETECT		0x2000 /* Clip 2 detect mask */
-#define B43_NPHY_C1_CCK_CGAINI			B43_PHY_N(0x01D) /* Core 1 CCK compute gain info */
-#define  B43_NPHY_C1_CCK_CGAINI_GAINBKOFF	0x001F /* Gain backoff */
-#define  B43_NPHY_C1_CCK_CGAINI_CLIPGBKOFF	0x01E0 /* CCK barely clip gain backoff */
-#define B43_NPHY_C1_MINMAX_GAIN			B43_PHY_N(0x01E) /* Core 1 min/max gain */
-#define  B43_NPHY_C1_MINGAIN			0x00FF /* Minimum gain */
-#define  B43_NPHY_C1_MINGAIN_SHIFT		0
-#define  B43_NPHY_C1_MAXGAIN			0xFF00 /* Maximum gain */
-#define  B43_NPHY_C1_MAXGAIN_SHIFT		8
-#define B43_NPHY_C1_CCK_MINMAX_GAIN		B43_PHY_N(0x01F) /* Core 1 CCK min/max gain */
-#define  B43_NPHY_C1_CCK_MINGAIN		0x00FF /* Minimum gain */
-#define  B43_NPHY_C1_CCK_MINGAIN_SHIFT		0
-#define  B43_NPHY_C1_CCK_MAXGAIN		0xFF00 /* Maximum gain */
-#define  B43_NPHY_C1_CCK_MAXGAIN_SHIFT		8
-#define B43_NPHY_C1_INITGAIN			B43_PHY_N(0x020) /* Core 1 initial gain code */
-#define  B43_NPHY_C1_INITGAIN_EXTLNA		0x0001 /* External LNA index */
-#define  B43_NPHY_C1_INITGAIN_LNA		0x0006 /* LNA index */
-#define  B43_NPHY_C1_INITGAIN_LNAIDX_SHIFT	1
-#define  B43_NPHY_C1_INITGAIN_HPVGA1		0x0078 /* HPVGA1 index */
-#define  B43_NPHY_C1_INITGAIN_HPVGA1_SHIFT	3
-#define  B43_NPHY_C1_INITGAIN_HPVGA2		0x0F80 /* HPVGA2 index */
-#define  B43_NPHY_C1_INITGAIN_HPVGA2_SHIFT	7
-#define  B43_NPHY_C1_INITGAIN_TRRX		0x1000 /* TR RX index */
-#define  B43_NPHY_C1_INITGAIN_TRTX		0x2000 /* TR TX index */
-#define B43_NPHY_C1_CLIP1_HIGAIN		B43_PHY_N(0x021) /* Core 1 clip1 high gain code */
-#define B43_NPHY_C1_CLIP1_MEDGAIN		B43_PHY_N(0x022) /* Core 1 clip1 medium gain code */
-#define B43_NPHY_C1_CLIP1_LOGAIN		B43_PHY_N(0x023) /* Core 1 clip1 low gain code */
-#define B43_NPHY_C1_CLIP2_GAIN			B43_PHY_N(0x024) /* Core 1 clip2 gain code */
-#define B43_NPHY_C1_FILTERGAIN			B43_PHY_N(0x025) /* Core 1 filter gain */
-#define B43_NPHY_C1_LPF_QHPF_BW			B43_PHY_N(0x026) /* Core 1 LPF Q HP F bandwidth */
-#define B43_NPHY_C1_CLIPWBTHRES			B43_PHY_N(0x027) /* Core 1 clip wideband threshold */
-#define  B43_NPHY_C1_CLIPWBTHRES_CLIP2		0x003F /* Clip 2 */
-#define  B43_NPHY_C1_CLIPWBTHRES_CLIP2_SHIFT	0
-#define  B43_NPHY_C1_CLIPWBTHRES_CLIP1		0x0FC0 /* Clip 1 */
-#define  B43_NPHY_C1_CLIPWBTHRES_CLIP1_SHIFT	6
-#define B43_NPHY_C1_W1THRES			B43_PHY_N(0x028) /* Core 1 W1 threshold */
-#define B43_NPHY_C1_EDTHRES			B43_PHY_N(0x029) /* Core 1 ED threshold */
-#define B43_NPHY_C1_SMSIGTHRES			B43_PHY_N(0x02A) /* Core 1 small sig threshold */
-#define B43_NPHY_C1_NBCLIPTHRES			B43_PHY_N(0x02B) /* Core 1 NB clip threshold */
-#define B43_NPHY_C1_CLIP1THRES			B43_PHY_N(0x02C) /* Core 1 clip1 threshold */
-#define B43_NPHY_C1_CLIP2THRES			B43_PHY_N(0x02D) /* Core 1 clip2 threshold */
-
-#define B43_NPHY_C2_DESPWR			B43_PHY_N(0x02E) /* Core 2 desired power */
-#define B43_NPHY_C2_CCK_DESPWR			B43_PHY_N(0x02F) /* Core 2 CCK desired power */
-#define B43_NPHY_C2_BCLIPBKOFF			B43_PHY_N(0x030) /* Core 2 barely clip backoff */
-#define B43_NPHY_C2_CCK_BCLIPBKOFF		B43_PHY_N(0x031) /* Core 2 CCK barely clip backoff */
-#define B43_NPHY_C2_CGAINI			B43_PHY_N(0x032) /* Core 2 compute gain info */
-#define  B43_NPHY_C2_CGAINI_GAINBKOFF		0x001F /* Gain backoff */
-#define  B43_NPHY_C2_CGAINI_GAINBKOFF_SHIFT	0
-#define  B43_NPHY_C2_CGAINI_CLIPGBKOFF		0x03E0 /* Clip gain backoff */
-#define  B43_NPHY_C2_CGAINI_CLIPGBKOFF_SHIFT	5
-#define  B43_NPHY_C2_CGAINI_GAINSTEP		0x1C00 /* Gain step */
-#define  B43_NPHY_C2_CGAINI_GAINSTEP_SHIFT	10
-#define  B43_NPHY_C2_CGAINI_CL2DETECT		0x2000 /* Clip 2 detect mask */
-#define B43_NPHY_C2_CCK_CGAINI			B43_PHY_N(0x033) /* Core 2 CCK compute gain info */
-#define  B43_NPHY_C2_CCK_CGAINI_GAINBKOFF	0x001F /* Gain backoff */
-#define  B43_NPHY_C2_CCK_CGAINI_CLIPGBKOFF	0x01E0 /* CCK barely clip gain backoff */
-#define B43_NPHY_C2_MINMAX_GAIN			B43_PHY_N(0x034) /* Core 2 min/max gain */
-#define  B43_NPHY_C2_MINGAIN			0x00FF /* Minimum gain */
-#define  B43_NPHY_C2_MINGAIN_SHIFT		0
-#define  B43_NPHY_C2_MAXGAIN			0xFF00 /* Maximum gain */
-#define  B43_NPHY_C2_MAXGAIN_SHIFT		8
-#define B43_NPHY_C2_CCK_MINMAX_GAIN		B43_PHY_N(0x035) /* Core 2 CCK min/max gain */
-#define  B43_NPHY_C2_CCK_MINGAIN		0x00FF /* Minimum gain */
-#define  B43_NPHY_C2_CCK_MINGAIN_SHIFT		0
-#define  B43_NPHY_C2_CCK_MAXGAIN		0xFF00 /* Maximum gain */
-#define  B43_NPHY_C2_CCK_MAXGAIN_SHIFT		8
-#define B43_NPHY_C2_INITGAIN			B43_PHY_N(0x036) /* Core 2 initial gain code */
-#define  B43_NPHY_C2_INITGAIN_EXTLNA		0x0001 /* External LNA index */
-#define  B43_NPHY_C2_INITGAIN_LNA		0x0006 /* LNA index */
-#define  B43_NPHY_C2_INITGAIN_LNAIDX_SHIFT	1
-#define  B43_NPHY_C2_INITGAIN_HPVGA1		0x0078 /* HPVGA1 index */
-#define  B43_NPHY_C2_INITGAIN_HPVGA1_SHIFT	3
-#define  B43_NPHY_C2_INITGAIN_HPVGA2		0x0F80 /* HPVGA2 index */
-#define  B43_NPHY_C2_INITGAIN_HPVGA2_SHIFT	7
-#define  B43_NPHY_C2_INITGAIN_TRRX		0x1000 /* TR RX index */
-#define  B43_NPHY_C2_INITGAIN_TRTX		0x2000 /* TR TX index */
-#define B43_NPHY_C2_CLIP1_HIGAIN		B43_PHY_N(0x037) /* Core 2 clip1 high gain code */
-#define B43_NPHY_C2_CLIP1_MEDGAIN		B43_PHY_N(0x038) /* Core 2 clip1 medium gain code */
-#define B43_NPHY_C2_CLIP1_LOGAIN		B43_PHY_N(0x039) /* Core 2 clip1 low gain code */
-#define B43_NPHY_C2_CLIP2_GAIN			B43_PHY_N(0x03A) /* Core 2 clip2 gain code */
-#define B43_NPHY_C2_FILTERGAIN			B43_PHY_N(0x03B) /* Core 2 filter gain */
-#define B43_NPHY_C2_LPF_QHPF_BW			B43_PHY_N(0x03C) /* Core 2 LPF Q HP F bandwidth */
-#define B43_NPHY_C2_CLIPWBTHRES			B43_PHY_N(0x03D) /* Core 2 clip wideband threshold */
-#define  B43_NPHY_C2_CLIPWBTHRES_CLIP2		0x003F /* Clip 2 */
-#define  B43_NPHY_C2_CLIPWBTHRES_CLIP2_SHIFT	0
-#define  B43_NPHY_C2_CLIPWBTHRES_CLIP1		0x0FC0 /* Clip 1 */
-#define  B43_NPHY_C2_CLIPWBTHRES_CLIP1_SHIFT	6
-#define B43_NPHY_C2_W1THRES			B43_PHY_N(0x03E) /* Core 2 W1 threshold */
-#define B43_NPHY_C2_EDTHRES			B43_PHY_N(0x03F) /* Core 2 ED threshold */
-#define B43_NPHY_C2_SMSIGTHRES			B43_PHY_N(0x040) /* Core 2 small sig threshold */
-#define B43_NPHY_C2_NBCLIPTHRES			B43_PHY_N(0x041) /* Core 2 NB clip threshold */
-#define B43_NPHY_C2_CLIP1THRES			B43_PHY_N(0x042) /* Core 2 clip1 threshold */
-#define B43_NPHY_C2_CLIP2THRES			B43_PHY_N(0x043) /* Core 2 clip2 threshold */
-
-#define B43_NPHY_CRS_THRES1			B43_PHY_N(0x044) /* CRS threshold 1 */
-#define B43_NPHY_CRS_THRES2			B43_PHY_N(0x045) /* CRS threshold 2 */
-#define B43_NPHY_CRS_THRES3			B43_PHY_N(0x046) /* CRS threshold 3 */
-#define B43_NPHY_CRSCTL				B43_PHY_N(0x047) /* CRS control */
-#define B43_NPHY_DCFADDR			B43_PHY_N(0x048) /* DC filter address */
-#define B43_NPHY_RXF20_NUM0			B43_PHY_N(0x049) /* RX filter 20 numerator 0 */
-#define B43_NPHY_RXF20_NUM1			B43_PHY_N(0x04A) /* RX filter 20 numerator 1 */
-#define B43_NPHY_RXF20_NUM2			B43_PHY_N(0x04B) /* RX filter 20 numerator 2 */
-#define B43_NPHY_RXF20_DENOM0			B43_PHY_N(0x04C) /* RX filter 20 denominator 0 */
-#define B43_NPHY_RXF20_DENOM1			B43_PHY_N(0x04D) /* RX filter 20 denominator 1 */
-#define B43_NPHY_RXF20_NUM10			B43_PHY_N(0x04E) /* RX filter 20 numerator 10 */
-#define B43_NPHY_RXF20_NUM11			B43_PHY_N(0x04F) /* RX filter 20 numerator 11 */
-#define B43_NPHY_RXF20_NUM12			B43_PHY_N(0x050) /* RX filter 20 numerator 12 */
-#define B43_NPHY_RXF20_DENOM10			B43_PHY_N(0x051) /* RX filter 20 denominator 10 */
-#define B43_NPHY_RXF20_DENOM11			B43_PHY_N(0x052) /* RX filter 20 denominator 11 */
-#define B43_NPHY_RXF40_NUM0			B43_PHY_N(0x053) /* RX filter 40 numerator 0 */
-#define B43_NPHY_RXF40_NUM1			B43_PHY_N(0x054) /* RX filter 40 numerator 1 */
-#define B43_NPHY_RXF40_NUM2			B43_PHY_N(0x055) /* RX filter 40 numerator 2 */
-#define B43_NPHY_RXF40_DENOM0			B43_PHY_N(0x056) /* RX filter 40 denominator 0 */
-#define B43_NPHY_RXF40_DENOM1			B43_PHY_N(0x057) /* RX filter 40 denominator 1 */
-#define B43_NPHY_RXF40_NUM10			B43_PHY_N(0x058) /* RX filter 40 numerator 10 */
-#define B43_NPHY_RXF40_NUM11			B43_PHY_N(0x059) /* RX filter 40 numerator 11 */
-#define B43_NPHY_RXF40_NUM12			B43_PHY_N(0x05A) /* RX filter 40 numerator 12 */
-#define B43_NPHY_RXF40_DENOM10			B43_PHY_N(0x05B) /* RX filter 40 denominator 10 */
-#define B43_NPHY_RXF40_DENOM11			B43_PHY_N(0x05C) /* RX filter 40 denominator 11 */
-#define B43_NPHY_PPROC_RSTLEN			B43_PHY_N(0x060) /* Packet processing reset length */
-#define B43_NPHY_INITCARR_DLEN			B43_PHY_N(0x061) /* Initial carrier detection length */
-#define B43_NPHY_CLIP1CARR_DLEN			B43_PHY_N(0x062) /* Clip1 carrier detection length */
-#define B43_NPHY_CLIP2CARR_DLEN			B43_PHY_N(0x063) /* Clip2 carrier detection length */
-#define B43_NPHY_INITGAIN_SLEN			B43_PHY_N(0x064) /* Initial gain settle length */
-#define B43_NPHY_CLIP1GAIN_SLEN			B43_PHY_N(0x065) /* Clip1 gain settle length */
-#define B43_NPHY_CLIP2GAIN_SLEN			B43_PHY_N(0x066) /* Clip2 gain settle length */
-#define B43_NPHY_PACKGAIN_SLEN			B43_PHY_N(0x067) /* Packet gain settle length */
-#define B43_NPHY_CARRSRC_TLEN			B43_PHY_N(0x068) /* Carrier search timeout length */
-#define B43_NPHY_TISRC_TLEN			B43_PHY_N(0x069) /* Timing search timeout length */
-#define B43_NPHY_ENDROP_TLEN			B43_PHY_N(0x06A) /* Energy drop timeout length */
-#define B43_NPHY_CLIP1_NBDWELL_LEN		B43_PHY_N(0x06B) /* Clip1 NB dwell length */
-#define B43_NPHY_CLIP2_NBDWELL_LEN		B43_PHY_N(0x06C) /* Clip2 NB dwell length */
-#define B43_NPHY_W1CLIP1_DWELL_LEN		B43_PHY_N(0x06D) /* W1 clip1 dwell length */
-#define B43_NPHY_W1CLIP2_DWELL_LEN		B43_PHY_N(0x06E) /* W1 clip2 dwell length */
-#define B43_NPHY_W2CLIP1_DWELL_LEN		B43_PHY_N(0x06F) /* W2 clip1 dwell length */
-#define B43_NPHY_PLOAD_CSENSE_EXTLEN		B43_PHY_N(0x070) /* Payload carrier sense extension length */
-#define B43_NPHY_EDROP_CSENSE_EXTLEN		B43_PHY_N(0x071) /* Energy drop carrier sense extension length */
-#define B43_NPHY_TABLE_ADDR			B43_PHY_N(0x072) /* Table address */
-#define B43_NPHY_TABLE_DATALO			B43_PHY_N(0x073) /* Table data low */
-#define B43_NPHY_TABLE_DATAHI			B43_PHY_N(0x074) /* Table data high */
-#define B43_NPHY_WWISE_LENIDX			B43_PHY_N(0x075) /* WWiSE length index */
-#define B43_NPHY_TGNSYNC_LENIDX			B43_PHY_N(0x076) /* TGNsync length index */
-#define B43_NPHY_TXMACIF_HOLDOFF		B43_PHY_N(0x077) /* TX MAC IF Hold off */
-#define B43_NPHY_RFCTL_CMD			B43_PHY_N(0x078) /* RF control (command) */
-#define  B43_NPHY_RFCTL_CMD_START		0x0001 /* Start sequence */
-#define  B43_NPHY_RFCTL_CMD_RXTX		0x0002 /* RX/TX */
-#define  B43_NPHY_RFCTL_CMD_CORESEL		0x0038 /* Core select */
-#define  B43_NPHY_RFCTL_CMD_CORESEL_SHIFT	3
-#define  B43_NPHY_RFCTL_CMD_PORFORCE		0x0040 /* POR force */
-#define  B43_NPHY_RFCTL_CMD_OEPORFORCE		0x0080 /* OE POR force */
-#define  B43_NPHY_RFCTL_CMD_RXEN		0x0100 /* RX enable */
-#define  B43_NPHY_RFCTL_CMD_TXEN		0x0200 /* TX enable */
-#define  B43_NPHY_RFCTL_CMD_CHIP0PU		0x0400 /* Chip0 PU */
-#define  B43_NPHY_RFCTL_CMD_EN			0x0800 /* Radio enabled */
-#define  B43_NPHY_RFCTL_CMD_SEQENCORE		0xF000 /* Seq en core */
-#define  B43_NPHY_RFCTL_CMD_SEQENCORE_SHIFT	12
-#define B43_NPHY_RFCTL_RSSIO1			B43_PHY_N(0x07A) /* RF control (RSSI others 1) */
-#define  B43_NPHY_RFCTL_RSSIO1_RXPD		0x0001 /* RX PD */
-#define  B43_NPHY_RFCTL_RSSIO1_TXPD		0x0002 /* TX PD */
-#define  B43_NPHY_RFCTL_RSSIO1_PAPD		0x0004 /* PA PD */
-#define  B43_NPHY_RFCTL_RSSIO1_RSSICTL		0x0030 /* RSSI control */
-#define  B43_NPHY_RFCTL_RSSIO1_LPFBW		0x00C0 /* LPF bandwidth */
-#define  B43_NPHY_RFCTL_RSSIO1_HPFBWHI		0x0100 /* HPF bandwidth high */
-#define  B43_NPHY_RFCTL_RSSIO1_HIQDISCO		0x0200 /* HIQ dis core */
-#define B43_NPHY_RFCTL_RXG1			B43_PHY_N(0x07B) /* RF control (RX gain 1) */
-#define B43_NPHY_RFCTL_TXG1			B43_PHY_N(0x07C) /* RF control (TX gain 1) */
-#define B43_NPHY_RFCTL_RSSIO2			B43_PHY_N(0x07D) /* RF control (RSSI others 2) */
-#define  B43_NPHY_RFCTL_RSSIO2_RXPD		0x0001 /* RX PD */
-#define  B43_NPHY_RFCTL_RSSIO2_TXPD		0x0002 /* TX PD */
-#define  B43_NPHY_RFCTL_RSSIO2_PAPD		0x0004 /* PA PD */
-#define  B43_NPHY_RFCTL_RSSIO2_RSSICTL		0x0030 /* RSSI control */
-#define  B43_NPHY_RFCTL_RSSIO2_LPFBW		0x00C0 /* LPF bandwidth */
-#define  B43_NPHY_RFCTL_RSSIO2_HPFBWHI		0x0100 /* HPF bandwidth high */
-#define  B43_NPHY_RFCTL_RSSIO2_HIQDISCO		0x0200 /* HIQ dis core */
-#define B43_NPHY_RFCTL_RXG2			B43_PHY_N(0x07E) /* RF control (RX gain 2) */
-#define B43_NPHY_RFCTL_TXG2			B43_PHY_N(0x07F) /* RF control (TX gain 2) */
-#define B43_NPHY_RFCTL_RSSIO3			B43_PHY_N(0x080) /* RF control (RSSI others 3) */
-#define  B43_NPHY_RFCTL_RSSIO3_RXPD		0x0001 /* RX PD */
-#define  B43_NPHY_RFCTL_RSSIO3_TXPD		0x0002 /* TX PD */
-#define  B43_NPHY_RFCTL_RSSIO3_PAPD		0x0004 /* PA PD */
-#define  B43_NPHY_RFCTL_RSSIO3_RSSICTL		0x0030 /* RSSI control */
-#define  B43_NPHY_RFCTL_RSSIO3_LPFBW		0x00C0 /* LPF bandwidth */
-#define  B43_NPHY_RFCTL_RSSIO3_HPFBWHI		0x0100 /* HPF bandwidth high */
-#define  B43_NPHY_RFCTL_RSSIO3_HIQDISCO		0x0200 /* HIQ dis core */
-#define B43_NPHY_RFCTL_RXG3			B43_PHY_N(0x081) /* RF control (RX gain 3) */
-#define B43_NPHY_RFCTL_TXG3			B43_PHY_N(0x082) /* RF control (TX gain 3) */
-#define B43_NPHY_RFCTL_RSSIO4			B43_PHY_N(0x083) /* RF control (RSSI others 4) */
-#define  B43_NPHY_RFCTL_RSSIO4_RXPD		0x0001 /* RX PD */
-#define  B43_NPHY_RFCTL_RSSIO4_TXPD		0x0002 /* TX PD */
-#define  B43_NPHY_RFCTL_RSSIO4_PAPD		0x0004 /* PA PD */
-#define  B43_NPHY_RFCTL_RSSIO4_RSSICTL		0x0030 /* RSSI control */
-#define  B43_NPHY_RFCTL_RSSIO4_LPFBW		0x00C0 /* LPF bandwidth */
-#define  B43_NPHY_RFCTL_RSSIO4_HPFBWHI		0x0100 /* HPF bandwidth high */
-#define  B43_NPHY_RFCTL_RSSIO4_HIQDISCO		0x0200 /* HIQ dis core */
-#define B43_NPHY_RFCTL_RXG4			B43_PHY_N(0x084) /* RF control (RX gain 4) */
-#define B43_NPHY_RFCTL_TXG4			B43_PHY_N(0x085) /* RF control (TX gain 4) */
-#define B43_NPHY_C1_TXIQ_COMP_OFF		B43_PHY_N(0x087) /* Core 1 TX I/Q comp offset */
-#define B43_NPHY_C2_TXIQ_COMP_OFF		B43_PHY_N(0x088) /* Core 2 TX I/Q comp offset */
-#define B43_NPHY_C1_TXCTL			B43_PHY_N(0x08B) /* Core 1 TX control */
-#define B43_NPHY_C2_TXCTL			B43_PHY_N(0x08C) /* Core 2 TX control */
-#define B43_NPHY_SCRAM_SIGCTL			B43_PHY_N(0x090) /* Scram signal control */
-#define  B43_NPHY_SCRAM_SIGCTL_INITST		0x007F /* Initial state value */
-#define  B43_NPHY_SCRAM_SIGCTL_INITST_SHIFT	0
-#define  B43_NPHY_SCRAM_SIGCTL_SCM		0x0080 /* Scram control mode */
-#define  B43_NPHY_SCRAM_SIGCTL_SICE		0x0100 /* Scram index control enable */
-#define  B43_NPHY_SCRAM_SIGCTL_START		0xFE00 /* Scram start bit */
-#define  B43_NPHY_SCRAM_SIGCTL_START_SHIFT	9
-#define B43_NPHY_RFCTL_INTC1			B43_PHY_N(0x091) /* RF control (intc 1) */
-#define B43_NPHY_RFCTL_INTC2			B43_PHY_N(0x092) /* RF control (intc 2) */
-#define B43_NPHY_RFCTL_INTC3			B43_PHY_N(0x093) /* RF control (intc 3) */
-#define B43_NPHY_RFCTL_INTC4			B43_PHY_N(0x094) /* RF control (intc 4) */
-#define B43_NPHY_NRDTO_WWISE			B43_PHY_N(0x095) /* # datatones WWiSE */
-#define B43_NPHY_NRDTO_TGNSYNC			B43_PHY_N(0x096) /* # datatones TGNsync */
-#define B43_NPHY_SIGFMOD_WWISE			B43_PHY_N(0x097) /* Signal field mod WWiSE */
-#define B43_NPHY_LEG_SIGFMOD_11N		B43_PHY_N(0x098) /* Legacy signal field mod 11n */
-#define B43_NPHY_HT_SIGFMOD_11N			B43_PHY_N(0x099) /* HT signal field mod 11n */
-#define B43_NPHY_C1_RXIQ_COMPA0			B43_PHY_N(0x09A) /* Core 1 RX I/Q comp A0 */
-#define B43_NPHY_C1_RXIQ_COMPB0			B43_PHY_N(0x09B) /* Core 1 RX I/Q comp B0 */
-#define B43_NPHY_C2_RXIQ_COMPA1			B43_PHY_N(0x09C) /* Core 2 RX I/Q comp A1 */
-#define B43_NPHY_C2_RXIQ_COMPB1			B43_PHY_N(0x09D) /* Core 2 RX I/Q comp B1 */
-#define B43_NPHY_RXCTL				B43_PHY_N(0x0A0) /* RX control */
-#define  B43_NPHY_RXCTL_BSELU20			0x0010 /* Band select upper 20 */
-#define  B43_NPHY_RXCTL_RIFSEN			0x0080 /* RIFS enable */
-#define B43_NPHY_RFSEQMODE			B43_PHY_N(0x0A1) /* RF seq mode */
-#define  B43_NPHY_RFSEQMODE_CAOVER		0x0001 /* Core active override */
-#define  B43_NPHY_RFSEQMODE_TROVER		0x0002 /* Trigger override */
-#define B43_NPHY_RFSEQCA			B43_PHY_N(0x0A2) /* RF seq core active */
-#define  B43_NPHY_RFSEQCA_TXEN			0x000F /* TX enable */
-#define  B43_NPHY_RFSEQCA_TXEN_SHIFT		0
-#define  B43_NPHY_RFSEQCA_RXEN			0x00F0 /* RX enable */
-#define  B43_NPHY_RFSEQCA_RXEN_SHIFT		4
-#define  B43_NPHY_RFSEQCA_TXDIS			0x0F00 /* TX disable */
-#define  B43_NPHY_RFSEQCA_TXDIS_SHIFT		8
-#define  B43_NPHY_RFSEQCA_RXDIS			0xF000 /* RX disable */
-#define  B43_NPHY_RFSEQCA_RXDIS_SHIFT		12
-#define B43_NPHY_RFSEQTR			B43_PHY_N(0x0A3) /* RF seq trigger */
-#define  B43_NPHY_RFSEQTR_RX2TX			0x0001 /* RX2TX */
-#define  B43_NPHY_RFSEQTR_TX2RX			0x0002 /* TX2RX */
-#define  B43_NPHY_RFSEQTR_UPGH			0x0004 /* Update gain H */
-#define  B43_NPHY_RFSEQTR_UPGL			0x0008 /* Update gain L */
-#define  B43_NPHY_RFSEQTR_UPGU			0x0010 /* Update gain U */
-#define  B43_NPHY_RFSEQTR_RST2RX		0x0020 /* Reset to RX */
-#define B43_NPHY_RFSEQST			B43_PHY_N(0x0A4) /* RF seq status. Values same as trigger. */
-#define B43_NPHY_AFECTL_OVER			B43_PHY_N(0x0A5) /* AFE control override */
-#define B43_NPHY_AFECTL_C1			B43_PHY_N(0x0A6) /* AFE control core 1 */
-#define B43_NPHY_AFECTL_C2			B43_PHY_N(0x0A7) /* AFE control core 2 */
-#define B43_NPHY_AFECTL_C3			B43_PHY_N(0x0A8) /* AFE control core 3 */
-#define B43_NPHY_AFECTL_C4			B43_PHY_N(0x0A9) /* AFE control core 4 */
-#define B43_NPHY_AFECTL_DACGAIN1		B43_PHY_N(0x0AA) /* AFE control DAC gain 1 */
-#define B43_NPHY_AFECTL_DACGAIN2		B43_PHY_N(0x0AB) /* AFE control DAC gain 2 */
-#define B43_NPHY_AFECTL_DACGAIN3		B43_PHY_N(0x0AC) /* AFE control DAC gain 3 */
-#define B43_NPHY_AFECTL_DACGAIN4		B43_PHY_N(0x0AD) /* AFE control DAC gain 4 */
-#define B43_NPHY_STR_ADDR1			B43_PHY_N(0x0AE) /* STR address 1 */
-#define B43_NPHY_STR_ADDR2			B43_PHY_N(0x0AF) /* STR address 2 */
-#define B43_NPHY_CLASSCTL			B43_PHY_N(0x0B0) /* Classifier control */
-#define  B43_NPHY_CLASSCTL_CCKEN		0x0001 /* CCK enable */
-#define  B43_NPHY_CLASSCTL_OFDMEN		0x0002 /* OFDM enable */
-#define  B43_NPHY_CLASSCTL_WAITEDEN		0x0004 /* Waited enable */
-#define B43_NPHY_IQFLIP				B43_PHY_N(0x0B1) /* I/Q flip */
-#define  B43_NPHY_IQFLIP_ADC1			0x0001 /* ADC1 */
-#define  B43_NPHY_IQFLIP_ADC2			0x0010 /* ADC2 */
-#define B43_NPHY_SISO_SNR_THRES			B43_PHY_N(0x0B2) /* SISO SNR threshold */
-#define B43_NPHY_SIGMA_N_MULT			B43_PHY_N(0x0B3) /* Sigma N multiplier */
-#define B43_NPHY_TXMACDELAY			B43_PHY_N(0x0B4) /* TX MAC delay */
-#define B43_NPHY_TXFRAMEDELAY			B43_PHY_N(0x0B5) /* TX frame delay */
-#define B43_NPHY_MLPARM				B43_PHY_N(0x0B6) /* ML parameters */
-#define B43_NPHY_MLCTL				B43_PHY_N(0x0B7) /* ML control */
-#define B43_NPHY_WWISE_20NCYCDAT		B43_PHY_N(0x0B8) /* WWiSE 20 N cyc data */
-#define B43_NPHY_WWISE_40NCYCDAT		B43_PHY_N(0x0B9) /* WWiSE 40 N cyc data */
-#define B43_NPHY_TGNSYNC_20NCYCDAT		B43_PHY_N(0x0BA) /* TGNsync 20 N cyc data */
-#define B43_NPHY_TGNSYNC_40NCYCDAT		B43_PHY_N(0x0BB) /* TGNsync 40 N cyc data */
-#define B43_NPHY_INITSWIZP			B43_PHY_N(0x0BC) /* Initial swizzle pattern */
-#define B43_NPHY_TXTAILCNT			B43_PHY_N(0x0BD) /* TX tail count value */
-#define B43_NPHY_BPHY_CTL1			B43_PHY_N(0x0BE) /* B PHY control 1 */
-#define B43_NPHY_BPHY_CTL2			B43_PHY_N(0x0BF) /* B PHY control 2 */
-#define  B43_NPHY_BPHY_CTL2_LUT			0x001F /* LUT index */
-#define  B43_NPHY_BPHY_CTL2_LUT_SHIFT		0
-#define  B43_NPHY_BPHY_CTL2_MACDEL		0x7FE0 /* MAC delay */
-#define  B43_NPHY_BPHY_CTL2_MACDEL_SHIFT	5
-#define B43_NPHY_IQLOCAL_CMD			B43_PHY_N(0x0C0) /* I/Q LO cal command */
-#define  B43_NPHY_IQLOCAL_CMD_EN		0x8000
-#define B43_NPHY_IQLOCAL_CMDNNUM		B43_PHY_N(0x0C1) /* I/Q LO cal command N num */
-#define B43_NPHY_IQLOCAL_CMDGCTL		B43_PHY_N(0x0C2) /* I/Q LO cal command G control */
-#define B43_NPHY_SAMP_CMD			B43_PHY_N(0x0C3) /* Sample command */
-#define  B43_NPHY_SAMP_CMD_STOP			0x0002 /* Stop */
-#define B43_NPHY_SAMP_LOOPCNT			B43_PHY_N(0x0C4) /* Sample loop count */
-#define B43_NPHY_SAMP_WAITCNT			B43_PHY_N(0x0C5) /* Sample wait count */
-#define B43_NPHY_SAMP_DEPCNT			B43_PHY_N(0x0C6) /* Sample depth count */
-#define B43_NPHY_SAMP_STAT			B43_PHY_N(0x0C7) /* Sample status */
-#define B43_NPHY_GPIO_LOOEN			B43_PHY_N(0x0C8) /* GPIO low out enable */
-#define B43_NPHY_GPIO_HIOEN			B43_PHY_N(0x0C9) /* GPIO high out enable */
-#define B43_NPHY_GPIO_SEL			B43_PHY_N(0x0CA) /* GPIO select */
-#define B43_NPHY_GPIO_CLKCTL			B43_PHY_N(0x0CB) /* GPIO clock control */
-#define B43_NPHY_TXF_20CO_AS0			B43_PHY_N(0x0CC) /* TX filter 20 coeff A stage 0 */
-#define B43_NPHY_TXF_20CO_AS1			B43_PHY_N(0x0CD) /* TX filter 20 coeff A stage 1 */
-#define B43_NPHY_TXF_20CO_AS2			B43_PHY_N(0x0CE) /* TX filter 20 coeff A stage 2 */
-#define B43_NPHY_TXF_20CO_B32S0			B43_PHY_N(0x0CF) /* TX filter 20 coeff B32 stage 0 */
-#define B43_NPHY_TXF_20CO_B1S0			B43_PHY_N(0x0D0) /* TX filter 20 coeff B1 stage 0 */
-#define B43_NPHY_TXF_20CO_B32S1			B43_PHY_N(0x0D1) /* TX filter 20 coeff B32 stage 1 */
-#define B43_NPHY_TXF_20CO_B1S1			B43_PHY_N(0x0D2) /* TX filter 20 coeff B1 stage 1 */
-#define B43_NPHY_TXF_20CO_B32S2			B43_PHY_N(0x0D3) /* TX filter 20 coeff B32 stage 2 */
-#define B43_NPHY_TXF_20CO_B1S2			B43_PHY_N(0x0D4) /* TX filter 20 coeff B1 stage 2 */
-#define B43_NPHY_SIGFLDTOL			B43_PHY_N(0x0D5) /* Signal fld tolerance */
-#define B43_NPHY_TXSERFLD			B43_PHY_N(0x0D6) /* TX service field */
-#define B43_NPHY_AFESEQ_RX2TX_PUD		B43_PHY_N(0x0D7) /* AFE seq RX2TX power up/down delay */
-#define B43_NPHY_AFESEQ_TX2RX_PUD		B43_PHY_N(0x0D8) /* AFE seq TX2RX power up/down delay */
-#define B43_NPHY_TGNSYNC_SCRAMI0		B43_PHY_N(0x0D9) /* TGNsync scram init 0 */
-#define B43_NPHY_TGNSYNC_SCRAMI1		B43_PHY_N(0x0DA) /* TGNsync scram init 1 */
-#define B43_NPHY_INITSWIZPATTLEG		B43_PHY_N(0x0DB) /* Initial swizzle pattern leg */
-#define B43_NPHY_BPHY_CTL3			B43_PHY_N(0x0DC) /* B PHY control 3 */
-#define  B43_NPHY_BPHY_CTL3_SCALE		0x00FF /* Scale */
-#define  B43_NPHY_BPHY_CTL3_SCALE_SHIFT		0
-#define  B43_NPHY_BPHY_CTL3_FSC			0xFF00 /* Frame start count value */
-#define  B43_NPHY_BPHY_CTL3_FSC_SHIFT		8
-#define B43_NPHY_BPHY_CTL4			B43_PHY_N(0x0DD) /* B PHY control 4 */
-#define B43_NPHY_C1_TXBBMULT			B43_PHY_N(0x0DE) /* Core 1 TX BB multiplier */
-#define B43_NPHY_C2_TXBBMULT			B43_PHY_N(0x0DF) /* Core 2 TX BB multiplier */
-#define B43_NPHY_TXF_40CO_AS0			B43_PHY_N(0x0E1) /* TX filter 40 coeff A stage 0 */
-#define B43_NPHY_TXF_40CO_AS1			B43_PHY_N(0x0E2) /* TX filter 40 coeff A stage 1 */
-#define B43_NPHY_TXF_40CO_AS2			B43_PHY_N(0x0E3) /* TX filter 40 coeff A stage 2 */
-#define B43_NPHY_TXF_40CO_B32S0			B43_PHY_N(0x0E4) /* TX filter 40 coeff B32 stage 0 */
-#define B43_NPHY_TXF_40CO_B1S0			B43_PHY_N(0x0E5) /* TX filter 40 coeff B1 stage 0 */
-#define B43_NPHY_TXF_40CO_B32S1			B43_PHY_N(0x0E6) /* TX filter 40 coeff B32 stage 1 */
-#define B43_NPHY_TXF_40CO_B1S1			B43_PHY_N(0x0E7) /* TX filter 40 coeff B1 stage 1 */
-#define B43_NPHY_TXF_40CO_B32S2			B43_PHY_N(0x0E8) /* TX filter 40 coeff B32 stage 2 */
-#define B43_NPHY_TXF_40CO_B1S2			B43_PHY_N(0x0E9) /* TX filter 40 coeff B1 stage 2 */
-#define B43_NPHY_BIST_STAT2			B43_PHY_N(0x0EA) /* BIST status 2 */
-#define B43_NPHY_BIST_STAT3			B43_PHY_N(0x0EB) /* BIST status 3 */
-#define B43_NPHY_RFCTL_OVER			B43_PHY_N(0x0EC) /* RF control override */
-#define B43_NPHY_MIMOCFG			B43_PHY_N(0x0ED) /* MIMO config */
-#define  B43_NPHY_MIMOCFG_GFMIX			0x0004 /* Greenfield or mixed mode */
-#define  B43_NPHY_MIMOCFG_AUTO			0x0100 /* Greenfield/mixed mode auto */
-#define B43_NPHY_RADAR_BLNKCTL			B43_PHY_N(0x0EE) /* Radar blank control */
-#define B43_NPHY_A0RADAR_FIFOCTL		B43_PHY_N(0x0EF) /* Antenna 0 radar FIFO control */
-#define B43_NPHY_A1RADAR_FIFOCTL		B43_PHY_N(0x0F0) /* Antenna 1 radar FIFO control */
-#define B43_NPHY_A0RADAR_FIFODAT		B43_PHY_N(0x0F1) /* Antenna 0 radar FIFO data */
-#define B43_NPHY_A1RADAR_FIFODAT		B43_PHY_N(0x0F2) /* Antenna 1 radar FIFO data */
-#define B43_NPHY_RADAR_THRES0			B43_PHY_N(0x0F3) /* Radar threshold 0 */
-#define B43_NPHY_RADAR_THRES1			B43_PHY_N(0x0F4) /* Radar threshold 1 */
-#define B43_NPHY_RADAR_THRES0R			B43_PHY_N(0x0F5) /* Radar threshold 0R */
-#define B43_NPHY_RADAR_THRES1R			B43_PHY_N(0x0F6) /* Radar threshold 1R */
-#define B43_NPHY_CSEN_20IN40_DLEN		B43_PHY_N(0x0F7) /* Carrier sense 20 in 40 dwell length */
-#define B43_NPHY_RFCTL_LUT_TRSW_LO1		B43_PHY_N(0x0F8) /* RF control LUT TRSW lower 1 */
-#define B43_NPHY_RFCTL_LUT_TRSW_UP1		B43_PHY_N(0x0F9) /* RF control LUT TRSW upper 1 */
-#define B43_NPHY_RFCTL_LUT_TRSW_LO2		B43_PHY_N(0x0FA) /* RF control LUT TRSW lower 2 */
-#define B43_NPHY_RFCTL_LUT_TRSW_UP2		B43_PHY_N(0x0FB) /* RF control LUT TRSW upper 2 */
-#define B43_NPHY_RFCTL_LUT_TRSW_LO3		B43_PHY_N(0x0FC) /* RF control LUT TRSW lower 3 */
-#define B43_NPHY_RFCTL_LUT_TRSW_UP3		B43_PHY_N(0x0FD) /* RF control LUT TRSW upper 3 */
-#define B43_NPHY_RFCTL_LUT_TRSW_LO4		B43_PHY_N(0x0FE) /* RF control LUT TRSW lower 4 */
-#define B43_NPHY_RFCTL_LUT_TRSW_UP4		B43_PHY_N(0x0FF) /* RF control LUT TRSW upper 4 */
-#define B43_NPHY_RFCTL_LUT_LNAPA1		B43_PHY_N(0x100) /* RF control LUT LNA PA 1 */
-#define B43_NPHY_RFCTL_LUT_LNAPA2		B43_PHY_N(0x101) /* RF control LUT LNA PA 2 */
-#define B43_NPHY_RFCTL_LUT_LNAPA3		B43_PHY_N(0x102) /* RF control LUT LNA PA 3 */
-#define B43_NPHY_RFCTL_LUT_LNAPA4		B43_PHY_N(0x103) /* RF control LUT LNA PA 4 */
-#define B43_NPHY_TGNSYNC_CRCM0			B43_PHY_N(0x104) /* TGNsync CRC mask 0 */
-#define B43_NPHY_TGNSYNC_CRCM1			B43_PHY_N(0x105) /* TGNsync CRC mask 1 */
-#define B43_NPHY_TGNSYNC_CRCM2			B43_PHY_N(0x106) /* TGNsync CRC mask 2 */
-#define B43_NPHY_TGNSYNC_CRCM3			B43_PHY_N(0x107) /* TGNsync CRC mask 3 */
-#define B43_NPHY_TGNSYNC_CRCM4			B43_PHY_N(0x108) /* TGNsync CRC mask 4 */
-#define B43_NPHY_CRCPOLY			B43_PHY_N(0x109) /* CRC polynomial */
-#define B43_NPHY_SIGCNT				B43_PHY_N(0x10A) /* # sig count */
-#define B43_NPHY_SIGSTARTBIT_CTL		B43_PHY_N(0x10B) /* Sig start bit control */
-#define B43_NPHY_CRCPOLY_ORDER			B43_PHY_N(0x10C) /* CRC polynomial order */
-#define B43_NPHY_RFCTL_CST0			B43_PHY_N(0x10D) /* RF control core swap table 0 */
-#define B43_NPHY_RFCTL_CST1			B43_PHY_N(0x10E) /* RF control core swap table 1 */
-#define B43_NPHY_RFCTL_CST2O			B43_PHY_N(0x10F) /* RF control core swap table 2 + others */
-#define B43_NPHY_BPHY_CTL5			B43_PHY_N(0x111) /* B PHY control 5 */
-#define B43_NPHY_RFSEQ_LPFBW			B43_PHY_N(0x112) /* RF seq LPF bandwidth */
-#define B43_NPHY_TSSIBIAS1			B43_PHY_N(0x114) /* TSSI bias val 1 */
-#define B43_NPHY_TSSIBIAS2			B43_PHY_N(0x115) /* TSSI bias val 2 */
-#define  B43_NPHY_TSSIBIAS_BIAS			0x00FF /* Bias */
-#define  B43_NPHY_TSSIBIAS_BIAS_SHIFT		0
-#define  B43_NPHY_TSSIBIAS_VAL			0xFF00 /* Value */
-#define  B43_NPHY_TSSIBIAS_VAL_SHIFT		8
-#define B43_NPHY_ESTPWR1			B43_PHY_N(0x118) /* Estimated power 1 */
-#define B43_NPHY_ESTPWR2			B43_PHY_N(0x119) /* Estimated power 2 */
-#define  B43_NPHY_ESTPWR_PWR			0x00FF /* Estimated power */
-#define  B43_NPHY_ESTPWR_PWR_SHIFT		0
-#define  B43_NPHY_ESTPWR_VALID			0x0100 /* Estimated power valid */
-#define B43_NPHY_TSSI_MAXTXFDT			B43_PHY_N(0x11C) /* TSSI max TX frame delay time */
-#define  B43_NPHY_TSSI_MAXTXFDT_VAL		0x00FF /* max TX frame delay time */
-#define  B43_NPHY_TSSI_MAXTXFDT_VAL_SHIFT	0
-#define B43_NPHY_TSSI_MAXTDT			B43_PHY_N(0x11D) /* TSSI max TSSI delay time */
-#define  B43_NPHY_TSSI_MAXTDT_VAL		0x00FF /* max TSSI delay time */
-#define  B43_NPHY_TSSI_MAXTDT_VAL_SHIFT		0
-#define B43_NPHY_ITSSI1				B43_PHY_N(0x11E) /* TSSI idle 1 */
-#define B43_NPHY_ITSSI2				B43_PHY_N(0x11F) /* TSSI idle 2 */
-#define  B43_NPHY_ITSSI_VAL			0x00FF /* Idle TSSI */
-#define  B43_NPHY_ITSSI_VAL_SHIFT		0
-#define B43_NPHY_TSSIMODE			B43_PHY_N(0x122) /* TSSI mode */
-#define  B43_NPHY_TSSIMODE_EN			0x0001 /* TSSI enable */
-#define  B43_NPHY_TSSIMODE_PDEN			0x0002 /* Power det enable */
-#define B43_NPHY_RXMACIFM			B43_PHY_N(0x123) /* RX Macif mode */
-#define B43_NPHY_CRSIT_COCNT_LO			B43_PHY_N(0x124) /* CRS idle time CRS-on count (low) */
-#define B43_NPHY_CRSIT_COCNT_HI			B43_PHY_N(0x125) /* CRS idle time CRS-on count (high) */
-#define B43_NPHY_CRSIT_MTCNT_LO			B43_PHY_N(0x126) /* CRS idle time measure time count (low) */
-#define B43_NPHY_CRSIT_MTCNT_HI			B43_PHY_N(0x127) /* CRS idle time measure time count (high) */
-#define B43_NPHY_SAMTWC				B43_PHY_N(0x128) /* Sample tail wait count */
-#define B43_NPHY_IQEST_CMD			B43_PHY_N(0x129) /* I/Q estimate command */
-#define  B43_NPHY_IQEST_CMD_START		0x0001 /* Start */
-#define  B43_NPHY_IQEST_CMD_MODE		0x0002 /* Mode */
-#define B43_NPHY_IQEST_WT			B43_PHY_N(0x12A) /* I/Q estimate wait time */
-#define  B43_NPHY_IQEST_WT_VAL			0x00FF /* Wait time */
-#define  B43_NPHY_IQEST_WT_VAL_SHIFT		0
-#define B43_NPHY_IQEST_SAMCNT			B43_PHY_N(0x12B) /* I/Q estimate sample count */
-#define B43_NPHY_IQEST_IQACC_LO0		B43_PHY_N(0x12C) /* I/Q estimate I/Q acc lo 0 */
-#define B43_NPHY_IQEST_IQACC_HI0		B43_PHY_N(0x12D) /* I/Q estimate I/Q acc hi 0 */
-#define B43_NPHY_IQEST_IPACC_LO0		B43_PHY_N(0x12E) /* I/Q estimate I power acc lo 0 */
-#define B43_NPHY_IQEST_IPACC_HI0		B43_PHY_N(0x12F) /* I/Q estimate I power acc hi 0 */
-#define B43_NPHY_IQEST_QPACC_LO0		B43_PHY_N(0x130) /* I/Q estimate Q power acc lo 0 */
-#define B43_NPHY_IQEST_QPACC_HI0		B43_PHY_N(0x131) /* I/Q estimate Q power acc hi 0 */
-#define B43_NPHY_IQEST_IQACC_LO1		B43_PHY_N(0x134) /* I/Q estimate I/Q acc lo 1 */
-#define B43_NPHY_IQEST_IQACC_HI1		B43_PHY_N(0x135) /* I/Q estimate I/Q acc hi 1 */
-#define B43_NPHY_IQEST_IPACC_LO1		B43_PHY_N(0x136) /* I/Q estimate I power acc lo 1 */
-#define B43_NPHY_IQEST_IPACC_HI1		B43_PHY_N(0x137) /* I/Q estimate I power acc hi 1 */
-#define B43_NPHY_IQEST_QPACC_LO1		B43_PHY_N(0x138) /* I/Q estimate Q power acc lo 1 */
-#define B43_NPHY_IQEST_QPACC_HI1		B43_PHY_N(0x139) /* I/Q estimate Q power acc hi 1 */
-#define B43_NPHY_MIMO_CRSTXEXT			B43_PHY_N(0x13A) /* MIMO PHY CRS TX extension */
-#define B43_NPHY_PWRDET1			B43_PHY_N(0x13B) /* Power det 1 */
-#define B43_NPHY_PWRDET2			B43_PHY_N(0x13C) /* Power det 2 */
-#define B43_NPHY_MAXRSSI_DTIME			B43_PHY_N(0x13F) /* RSSI max RSSI delay time */
-#define B43_NPHY_PIL_DW0			B43_PHY_N(0x141) /* Pilot data weight 0 */
-#define B43_NPHY_PIL_DW1			B43_PHY_N(0x142) /* Pilot data weight 1 */
-#define B43_NPHY_PIL_DW2			B43_PHY_N(0x143) /* Pilot data weight 2 */
-#define  B43_NPHY_PIL_DW_BPSK			0x000F /* BPSK */
-#define  B43_NPHY_PIL_DW_BPSK_SHIFT		0
-#define  B43_NPHY_PIL_DW_QPSK			0x00F0 /* QPSK */
-#define  B43_NPHY_PIL_DW_QPSK_SHIFT		4
-#define  B43_NPHY_PIL_DW_16QAM			0x0F00 /* 16-QAM */
-#define  B43_NPHY_PIL_DW_16QAM_SHIFT		8
-#define  B43_NPHY_PIL_DW_64QAM			0xF000 /* 64-QAM */
-#define  B43_NPHY_PIL_DW_64QAM_SHIFT		12
-#define B43_NPHY_FMDEM_CFG			B43_PHY_N(0x144) /* FM demodulation config */
-#define B43_NPHY_PHASETR_A0			B43_PHY_N(0x145) /* Phase track alpha 0 */
-#define B43_NPHY_PHASETR_A1			B43_PHY_N(0x146) /* Phase track alpha 1 */
-#define B43_NPHY_PHASETR_A2			B43_PHY_N(0x147) /* Phase track alpha 2 */
-#define B43_NPHY_PHASETR_B0			B43_PHY_N(0x148) /* Phase track beta 0 */
-#define B43_NPHY_PHASETR_B1			B43_PHY_N(0x149) /* Phase track beta 1 */
-#define B43_NPHY_PHASETR_B2			B43_PHY_N(0x14A) /* Phase track beta 2 */
-#define B43_NPHY_PHASETR_CHG0			B43_PHY_N(0x14B) /* Phase track change 0 */
-#define B43_NPHY_PHASETR_CHG1			B43_PHY_N(0x14C) /* Phase track change 1 */
-#define B43_NPHY_PHASETW_OFF			B43_PHY_N(0x14D) /* Phase track offset */
-#define B43_NPHY_RFCTL_DBG			B43_PHY_N(0x14E) /* RF control debug */
-#define B43_NPHY_CCK_SHIFTB_REF			B43_PHY_N(0x150) /* CCK shiftbits reference var */
-#define B43_NPHY_OVER_DGAIN0			B43_PHY_N(0x152) /* Override digital gain 0 */
-#define B43_NPHY_OVER_DGAIN1			B43_PHY_N(0x153) /* Override digital gain 1 */
-#define  B43_NPHY_OVER_DGAIN_FDGV		0x0007 /* Force digital gain value */
-#define  B43_NPHY_OVER_DGAIN_FDGV_SHIFT		0
-#define  B43_NPHY_OVER_DGAIN_FDGEN		0x0008 /* Force digital gain enable */
-#define  B43_NPHY_OVER_DGAIN_CCKDGECV		0xFF00 /* CCK digital gain enable count value */
-#define  B43_NPHY_OVER_DGAIN_CCKDGECV_SHIFT	8
-#define B43_NPHY_BIST_STAT4			B43_PHY_N(0x156) /* BIST status 4 */
-#define B43_NPHY_RADAR_MAL			B43_PHY_N(0x157) /* Radar MA length */
-#define B43_NPHY_RADAR_SRCCTL			B43_PHY_N(0x158) /* Radar search control */
-#define B43_NPHY_VLD_DTSIG			B43_PHY_N(0x159) /* VLD data tones sig */
-#define B43_NPHY_VLD_DTDAT			B43_PHY_N(0x15A) /* VLD data tones data */
-#define B43_NPHY_C1_BPHY_RXIQCA0		B43_PHY_N(0x15B) /* Core 1 B PHY RX I/Q comp A0 */
-#define B43_NPHY_C1_BPHY_RXIQCB0		B43_PHY_N(0x15C) /* Core 1 B PHY RX I/Q comp B0 */
-#define B43_NPHY_C2_BPHY_RXIQCA1		B43_PHY_N(0x15D) /* Core 2 B PHY RX I/Q comp A1 */
-#define B43_NPHY_C2_BPHY_RXIQCB1		B43_PHY_N(0x15E) /* Core 2 B PHY RX I/Q comp B1 */
-#define B43_NPHY_FREQGAIN0			B43_PHY_N(0x160) /* Frequency gain 0 */
-#define B43_NPHY_FREQGAIN1			B43_PHY_N(0x161) /* Frequency gain 1 */
-#define B43_NPHY_FREQGAIN2			B43_PHY_N(0x162) /* Frequency gain 2 */
-#define B43_NPHY_FREQGAIN3			B43_PHY_N(0x163) /* Frequency gain 3 */
-#define B43_NPHY_FREQGAIN4			B43_PHY_N(0x164) /* Frequency gain 4 */
-#define B43_NPHY_FREQGAIN5			B43_PHY_N(0x165) /* Frequency gain 5 */
-#define B43_NPHY_FREQGAIN6			B43_PHY_N(0x166) /* Frequency gain 6 */
-#define B43_NPHY_FREQGAIN7			B43_PHY_N(0x167) /* Frequency gain 7 */
-#define B43_NPHY_FREQGAIN_BYPASS		B43_PHY_N(0x168) /* Frequency gain bypass */
-#define B43_NPHY_TRLOSS				B43_PHY_N(0x169) /* TR loss value */
-#define B43_NPHY_C1_ADCCLIP			B43_PHY_N(0x16A) /* Core 1 ADC clip */
-#define B43_NPHY_C2_ADCCLIP			B43_PHY_N(0x16B) /* Core 2 ADC clip */
-#define B43_NPHY_LTRN_OFFGAIN			B43_PHY_N(0x16F) /* LTRN offset gain */
-#define B43_NPHY_LTRN_OFF			B43_PHY_N(0x170) /* LTRN offset */
-#define B43_NPHY_NRDATAT_WWISE20SIG		B43_PHY_N(0x171) /* # data tones WWiSE 20 sig */
-#define B43_NPHY_NRDATAT_WWISE40SIG		B43_PHY_N(0x172) /* # data tones WWiSE 40 sig */
-#define B43_NPHY_NRDATAT_TGNSYNC20SIG		B43_PHY_N(0x173) /* # data tones TGNsync 20 sig */
-#define B43_NPHY_NRDATAT_TGNSYNC40SIG		B43_PHY_N(0x174) /* # data tones TGNsync 40 sig */
-#define B43_NPHY_WWISE_CRCM0			B43_PHY_N(0x175) /* WWiSE CRC mask 0 */
-#define B43_NPHY_WWISE_CRCM1			B43_PHY_N(0x176) /* WWiSE CRC mask 1 */
-#define B43_NPHY_WWISE_CRCM2			B43_PHY_N(0x177) /* WWiSE CRC mask 2 */
-#define B43_NPHY_WWISE_CRCM3			B43_PHY_N(0x178) /* WWiSE CRC mask 3 */
-#define B43_NPHY_WWISE_CRCM4			B43_PHY_N(0x179) /* WWiSE CRC mask 4 */
-#define B43_NPHY_CHANEST_CDDSH			B43_PHY_N(0x17A) /* Channel estimate CDD shift */
-#define B43_NPHY_HTAGC_WCNT			B43_PHY_N(0x17B) /* HT ADC wait counters */
-#define B43_NPHY_SQPARM				B43_PHY_N(0x17C) /* SQ params */
-#define B43_NPHY_MCSDUP6M			B43_PHY_N(0x17D) /* MCS dup 6M */
-#define B43_NPHY_NDATAT_DUP40			B43_PHY_N(0x17E) /* # data tones dup 40 */
-#define B43_NPHY_DUP40_TGNSYNC_CYCD		B43_PHY_N(0x17F) /* Dup40 TGNsync cycle data */
-#define B43_NPHY_DUP40_GFBL			B43_PHY_N(0x180) /* Dup40 GF format BL address */
-#define B43_NPHY_DUP40_BL			B43_PHY_N(0x181) /* Dup40 format BL address */
-#define B43_NPHY_LEGDUP_FTA			B43_PHY_N(0x182) /* Legacy dup frm table address */
-#define B43_NPHY_PACPROC_DBG			B43_PHY_N(0x183) /* Packet processing debug */
-#define B43_NPHY_PIL_CYC1			B43_PHY_N(0x184) /* Pilot cycle counter 1 */
-#define B43_NPHY_PIL_CYC2			B43_PHY_N(0x185) /* Pilot cycle counter 2 */
-#define B43_NPHY_TXF_20CO_S0A1			B43_PHY_N(0x186) /* TX filter 20 coeff stage 0 A1 */
-#define B43_NPHY_TXF_20CO_S0A2			B43_PHY_N(0x187) /* TX filter 20 coeff stage 0 A2 */
-#define B43_NPHY_TXF_20CO_S1A1			B43_PHY_N(0x188) /* TX filter 20 coeff stage 1 A1 */
-#define B43_NPHY_TXF_20CO_S1A2			B43_PHY_N(0x189) /* TX filter 20 coeff stage 1 A2 */
-#define B43_NPHY_TXF_20CO_S2A1			B43_PHY_N(0x18A) /* TX filter 20 coeff stage 2 A1 */
-#define B43_NPHY_TXF_20CO_S2A2			B43_PHY_N(0x18B) /* TX filter 20 coeff stage 2 A2 */
-#define B43_NPHY_TXF_20CO_S0B1			B43_PHY_N(0x18C) /* TX filter 20 coeff stage 0 B1 */
-#define B43_NPHY_TXF_20CO_S0B2			B43_PHY_N(0x18D) /* TX filter 20 coeff stage 0 B2 */
-#define B43_NPHY_TXF_20CO_S0B3			B43_PHY_N(0x18E) /* TX filter 20 coeff stage 0 B3 */
-#define B43_NPHY_TXF_20CO_S1B1			B43_PHY_N(0x18F) /* TX filter 20 coeff stage 1 B1 */
-#define B43_NPHY_TXF_20CO_S1B2			B43_PHY_N(0x190) /* TX filter 20 coeff stage 1 B2 */
-#define B43_NPHY_TXF_20CO_S1B3			B43_PHY_N(0x191) /* TX filter 20 coeff stage 1 B3 */
-#define B43_NPHY_TXF_20CO_S2B1			B43_PHY_N(0x192) /* TX filter 20 coeff stage 2 B1 */
-#define B43_NPHY_TXF_20CO_S2B2			B43_PHY_N(0x193) /* TX filter 20 coeff stage 2 B2 */
-#define B43_NPHY_TXF_20CO_S2B3			B43_PHY_N(0x194) /* TX filter 20 coeff stage 2 B3 */
-#define B43_NPHY_TXF_40CO_S0A1			B43_PHY_N(0x195) /* TX filter 40 coeff stage 0 A1 */
-#define B43_NPHY_TXF_40CO_S0A2			B43_PHY_N(0x196) /* TX filter 40 coeff stage 0 A2 */
-#define B43_NPHY_TXF_40CO_S1A1			B43_PHY_N(0x197) /* TX filter 40 coeff stage 1 A1 */
-#define B43_NPHY_TXF_40CO_S1A2			B43_PHY_N(0x198) /* TX filter 40 coeff stage 1 A2 */
-#define B43_NPHY_TXF_40CO_S2A1			B43_PHY_N(0x199) /* TX filter 40 coeff stage 2 A1 */
-#define B43_NPHY_TXF_40CO_S2A2			B43_PHY_N(0x19A) /* TX filter 40 coeff stage 2 A2 */
-#define B43_NPHY_TXF_40CO_S0B1			B43_PHY_N(0x19B) /* TX filter 40 coeff stage 0 B1 */
-#define B43_NPHY_TXF_40CO_S0B2			B43_PHY_N(0x19C) /* TX filter 40 coeff stage 0 B2 */
-#define B43_NPHY_TXF_40CO_S0B3			B43_PHY_N(0x19D) /* TX filter 40 coeff stage 0 B3 */
-#define B43_NPHY_TXF_40CO_S1B1			B43_PHY_N(0x19E) /* TX filter 40 coeff stage 1 B1 */
-#define B43_NPHY_TXF_40CO_S1B2			B43_PHY_N(0x19F) /* TX filter 40 coeff stage 1 B2 */
-#define B43_NPHY_TXF_40CO_S1B3			B43_PHY_N(0x1A0) /* TX filter 40 coeff stage 1 B3 */
-#define B43_NPHY_TXF_40CO_S2B1			B43_PHY_N(0x1A1) /* TX filter 40 coeff stage 2 B1 */
-#define B43_NPHY_TXF_40CO_S2B2			B43_PHY_N(0x1A2) /* TX filter 40 coeff stage 2 B2 */
-#define B43_NPHY_TXF_40CO_S2B3			B43_PHY_N(0x1A3) /* TX filter 40 coeff stage 2 B3 */
-#define B43_NPHY_RSSIMC_0I_RSSI_X		B43_PHY_N(0x1A4) /* RSSI multiplication coefficient 0 I RSSI X */
-#define B43_NPHY_RSSIMC_0I_RSSI_Y		B43_PHY_N(0x1A5) /* RSSI multiplication coefficient 0 I RSSI Y */
-#define B43_NPHY_RSSIMC_0I_RSSI_Z		B43_PHY_N(0x1A6) /* RSSI multiplication coefficient 0 I RSSI Z */
-#define B43_NPHY_RSSIMC_0I_TBD			B43_PHY_N(0x1A7) /* RSSI multiplication coefficient 0 I TBD */
-#define B43_NPHY_RSSIMC_0I_PWRDET		B43_PHY_N(0x1A8) /* RSSI multiplication coefficient 0 I power det */
-#define B43_NPHY_RSSIMC_0I_TSSI			B43_PHY_N(0x1A9) /* RSSI multiplication coefficient 0 I TSSI */
-#define B43_NPHY_RSSIMC_0Q_RSSI_X		B43_PHY_N(0x1AA) /* RSSI multiplication coefficient 0 Q RSSI X */
-#define B43_NPHY_RSSIMC_0Q_RSSI_Y		B43_PHY_N(0x1AB) /* RSSI multiplication coefficient 0 Q RSSI Y */
-#define B43_NPHY_RSSIMC_0Q_RSSI_Z		B43_PHY_N(0x1AC) /* RSSI multiplication coefficient 0 Q RSSI Z */
-#define B43_NPHY_RSSIMC_0Q_TBD			B43_PHY_N(0x1AD) /* RSSI multiplication coefficient 0 Q TBD */
-#define B43_NPHY_RSSIMC_0Q_PWRDET		B43_PHY_N(0x1AE) /* RSSI multiplication coefficient 0 Q power det */
-#define B43_NPHY_RSSIMC_0Q_TSSI			B43_PHY_N(0x1AF) /* RSSI multiplication coefficient 0 Q TSSI */
-#define B43_NPHY_RSSIMC_1I_RSSI_X		B43_PHY_N(0x1B0) /* RSSI multiplication coefficient 1 I RSSI X */
-#define B43_NPHY_RSSIMC_1I_RSSI_Y		B43_PHY_N(0x1B1) /* RSSI multiplication coefficient 1 I RSSI Y */
-#define B43_NPHY_RSSIMC_1I_RSSI_Z		B43_PHY_N(0x1B2) /* RSSI multiplication coefficient 1 I RSSI Z */
-#define B43_NPHY_RSSIMC_1I_TBD			B43_PHY_N(0x1B3) /* RSSI multiplication coefficient 1 I TBD */
-#define B43_NPHY_RSSIMC_1I_PWRDET		B43_PHY_N(0x1B4) /* RSSI multiplication coefficient 1 I power det */
-#define B43_NPHY_RSSIMC_1I_TSSI			B43_PHY_N(0x1B5) /* RSSI multiplication coefficient 1 I TSSI */
-#define B43_NPHY_RSSIMC_1Q_RSSI_X		B43_PHY_N(0x1B6) /* RSSI multiplication coefficient 1 Q RSSI X */
-#define B43_NPHY_RSSIMC_1Q_RSSI_Y		B43_PHY_N(0x1B7) /* RSSI multiplication coefficient 1 Q RSSI Y */
-#define B43_NPHY_RSSIMC_1Q_RSSI_Z		B43_PHY_N(0x1B8) /* RSSI multiplication coefficient 1 Q RSSI Z */
-#define B43_NPHY_RSSIMC_1Q_TBD			B43_PHY_N(0x1B9) /* RSSI multiplication coefficient 1 Q TBD */
-#define B43_NPHY_RSSIMC_1Q_PWRDET		B43_PHY_N(0x1BA) /* RSSI multiplication coefficient 1 Q power det */
-#define B43_NPHY_RSSIMC_1Q_TSSI			B43_PHY_N(0x1BB) /* RSSI multiplication coefficient 1 Q TSSI */
-#define B43_NPHY_SAMC_WCNT			B43_PHY_N(0x1BC) /* Sample collect wait counter */
-#define B43_NPHY_PTHROUGH_CNT			B43_PHY_N(0x1BD) /* Pass-through counter */
-#define B43_NPHY_LTRN_OFF_G20L			B43_PHY_N(0x1C4) /* LTRN offset gain 20L */
-#define B43_NPHY_LTRN_OFF_20L			B43_PHY_N(0x1C5) /* LTRN offset 20L */
-#define B43_NPHY_LTRN_OFF_G20U			B43_PHY_N(0x1C6) /* LTRN offset gain 20U */
-#define B43_NPHY_LTRN_OFF_20U			B43_PHY_N(0x1C7) /* LTRN offset 20U */
-#define B43_NPHY_DSSSCCK_GAINSL			B43_PHY_N(0x1C8) /* DSSS/CCK gain settle length */
-#define B43_NPHY_GPIO_LOOUT			B43_PHY_N(0x1C9) /* GPIO low out */
-#define B43_NPHY_GPIO_HIOUT			B43_PHY_N(0x1CA) /* GPIO high out */
-#define B43_NPHY_CRS_CHECK			B43_PHY_N(0x1CB) /* CRS check */
-#define B43_NPHY_ML_LOGSS_RAT			B43_PHY_N(0x1CC) /* ML/logss ratio */
-#define B43_NPHY_DUPSCALE			B43_PHY_N(0x1CD) /* Dup scale */
-#define B43_NPHY_BW1A				B43_PHY_N(0x1CE) /* BW 1A */
-#define B43_NPHY_BW2				B43_PHY_N(0x1CF) /* BW 2 */
-#define B43_NPHY_BW3				B43_PHY_N(0x1D0) /* BW 3 */
-#define B43_NPHY_BW4				B43_PHY_N(0x1D1) /* BW 4 */
-#define B43_NPHY_BW5				B43_PHY_N(0x1D2) /* BW 5 */
-#define B43_NPHY_BW6				B43_PHY_N(0x1D3) /* BW 6 */
-#define B43_NPHY_COALEN0			B43_PHY_N(0x1D4) /* Coarse length 0 */
-#define B43_NPHY_COALEN1			B43_PHY_N(0x1D5) /* Coarse length 1 */
-#define B43_NPHY_CRSTHRES_1U			B43_PHY_N(0x1D6) /* CRS threshold 1 U */
-#define B43_NPHY_CRSTHRES_2U			B43_PHY_N(0x1D7) /* CRS threshold 2 U */
-#define B43_NPHY_CRSTHRES_3U			B43_PHY_N(0x1D8) /* CRS threshold 3 U */
-#define B43_NPHY_CRSCTL_U			B43_PHY_N(0x1D9) /* CRS control U */
-#define B43_NPHY_CRSTHRES_1L			B43_PHY_N(0x1DA) /* CRS threshold 1 L */
-#define B43_NPHY_CRSTHRES_2L			B43_PHY_N(0x1DB) /* CRS threshold 2 L */
-#define B43_NPHY_CRSTHRES_3L			B43_PHY_N(0x1DC) /* CRS threshold 3 L */
-#define B43_NPHY_CRSCTL_L			B43_PHY_N(0x1DD) /* CRS control L */
-#define B43_NPHY_STRA_1U			B43_PHY_N(0x1DE) /* STR address 1 U */
-#define B43_NPHY_STRA_2U			B43_PHY_N(0x1DF) /* STR address 2 U */
-#define B43_NPHY_STRA_1L			B43_PHY_N(0x1E0) /* STR address 1 L */
-#define B43_NPHY_STRA_2L			B43_PHY_N(0x1E1) /* STR address 2 L */
-#define B43_NPHY_CRSCHECK1			B43_PHY_N(0x1E2) /* CRS check 1 */
-#define B43_NPHY_CRSCHECK2			B43_PHY_N(0x1E3) /* CRS check 2 */
-#define B43_NPHY_CRSCHECK3			B43_PHY_N(0x1E4) /* CRS check 3 */
-#define B43_NPHY_JMPSTP0			B43_PHY_N(0x1E5) /* Jump step 0 */
-#define B43_NPHY_JMPSTP1			B43_PHY_N(0x1E6) /* Jump step 1 */
-#define B43_NPHY_TXPCTL_CMD			B43_PHY_N(0x1E7) /* TX power control command */
-#define  B43_NPHY_TXPCTL_CMD_INIT		0x007F /* Init */
-#define  B43_NPHY_TXPCTL_CMD_INIT_SHIFT		0
-#define  B43_NPHY_TXPCTL_CMD_COEFF		0x2000 /* Power control coefficients */
-#define  B43_NPHY_TXPCTL_CMD_HWPCTLEN		0x4000 /* Hardware TX power control enable */
-#define  B43_NPHY_TXPCTL_CMD_PCTLEN		0x8000 /* TX power control enable */
-#define B43_NPHY_TXPCTL_N			B43_PHY_N(0x1E8) /* TX power control N num */
-#define  B43_NPHY_TXPCTL_N_TSSID		0x00FF /* N TSSI delay */
-#define  B43_NPHY_TXPCTL_N_TSSID_SHIFT		0
-#define  B43_NPHY_TXPCTL_N_NPTIL2		0x0700 /* N PT integer log2 */
-#define  B43_NPHY_TXPCTL_N_NPTIL2_SHIFT		8
-#define B43_NPHY_TXPCTL_ITSSI			B43_PHY_N(0x1E9) /* TX power control idle TSSI */
-#define  B43_NPHY_TXPCTL_ITSSI_0		0x003F /* Idle TSSI 0 */
-#define  B43_NPHY_TXPCTL_ITSSI_0_SHIFT		0
-#define  B43_NPHY_TXPCTL_ITSSI_1		0x3F00 /* Idle TSSI 1 */
-#define  B43_NPHY_TXPCTL_ITSSI_1_SHIFT		8
-#define  B43_NPHY_TXPCTL_ITSSI_BINF		0x8000 /* Raw TSSI offset bin format */
-#define B43_NPHY_TXPCTL_TPWR			B43_PHY_N(0x1EA) /* TX power control target power */
-#define  B43_NPHY_TXPCTL_TPWR_0			0x00FF /* Power 0 */
-#define  B43_NPHY_TXPCTL_TPWR_0_SHIFT		0
-#define  B43_NPHY_TXPCTL_TPWR_1			0xFF00 /* Power 1 */
-#define  B43_NPHY_TXPCTL_TPWR_1_SHIFT		8
-#define B43_NPHY_TXPCTL_BIDX			B43_PHY_N(0x1EB) /* TX power control base index */
-#define  B43_NPHY_TXPCTL_BIDX_0			0x007F /* uC base index 0 */
-#define  B43_NPHY_TXPCTL_BIDX_0_SHIFT		0
-#define  B43_NPHY_TXPCTL_BIDX_1			0x7F00 /* uC base index 1 */
-#define  B43_NPHY_TXPCTL_BIDX_1_SHIFT		8
-#define  B43_NPHY_TXPCTL_BIDX_LOAD		0x8000 /* Load base index */
-#define B43_NPHY_TXPCTL_PIDX			B43_PHY_N(0x1EC) /* TX power control power index */
-#define  B43_NPHY_TXPCTL_PIDX_0			0x007F /* uC power index 0 */
-#define  B43_NPHY_TXPCTL_PIDX_0_SHIFT		0
-#define  B43_NPHY_TXPCTL_PIDX_1			0x7F00 /* uC power index 1 */
-#define  B43_NPHY_TXPCTL_PIDX_1_SHIFT		8
-#define B43_NPHY_C1_TXPCTL_STAT			B43_PHY_N(0x1ED) /* Core 1 TX power control status */
-#define B43_NPHY_C2_TXPCTL_STAT			B43_PHY_N(0x1EE) /* Core 2 TX power control status */
-#define  B43_NPHY_TXPCTL_STAT_EST		0x00FF /* Estimated power */
-#define  B43_NPHY_TXPCTL_STAT_EST_SHIFT		0
-#define  B43_NPHY_TXPCTL_STAT_BIDX		0x7F00 /* Base index */
-#define  B43_NPHY_TXPCTL_STAT_BIDX_SHIFT	8
-#define  B43_NPHY_TXPCTL_STAT_ESTVALID		0x8000 /* Estimated power valid */
-#define B43_NPHY_SMALLSGS_LEN			B43_PHY_N(0x1EF) /* Small sig gain settle length */
-#define B43_NPHY_PHYSTAT_GAIN0			B43_PHY_N(0x1F0) /* PHY stats gain info 0 */
-#define B43_NPHY_PHYSTAT_GAIN1			B43_PHY_N(0x1F1) /* PHY stats gain info 1 */
-#define B43_NPHY_PHYSTAT_FREQEST		B43_PHY_N(0x1F2) /* PHY stats frequency estimate */
-#define B43_NPHY_PHYSTAT_ADVRET			B43_PHY_N(0x1F3) /* PHY stats ADV retard */
-#define B43_NPHY_PHYLB_MODE			B43_PHY_N(0x1F4) /* PHY loopback mode */
-#define B43_NPHY_TONE_MIDX20_1			B43_PHY_N(0x1F5) /* Tone map index 20/1 */
-#define B43_NPHY_TONE_MIDX20_2			B43_PHY_N(0x1F6) /* Tone map index 20/2 */
-#define B43_NPHY_TONE_MIDX20_3			B43_PHY_N(0x1F7) /* Tone map index 20/3 */
-#define B43_NPHY_TONE_MIDX40_1			B43_PHY_N(0x1F8) /* Tone map index 40/1 */
-#define B43_NPHY_TONE_MIDX40_2			B43_PHY_N(0x1F9) /* Tone map index 40/2 */
-#define B43_NPHY_TONE_MIDX40_3			B43_PHY_N(0x1FA) /* Tone map index 40/3 */
-#define B43_NPHY_TONE_MIDX40_4			B43_PHY_N(0x1FB) /* Tone map index 40/4 */
-#define B43_NPHY_PILTONE_MIDX1			B43_PHY_N(0x1FC) /* Pilot tone map index 1 */
-#define B43_NPHY_PILTONE_MIDX2			B43_PHY_N(0x1FD) /* Pilot tone map index 2 */
-#define B43_NPHY_PILTONE_MIDX3			B43_PHY_N(0x1FE) /* Pilot tone map index 3 */
-#define B43_NPHY_TXRIFS_FRDEL			B43_PHY_N(0x1FF) /* TX RIFS frame delay */
-#define B43_NPHY_AFESEQ_RX2TX_PUD_40M		B43_PHY_N(0x200) /* AFE seq rx2tx power up/down delay 40M */
-#define B43_NPHY_AFESEQ_TX2RX_PUD_40M		B43_PHY_N(0x201) /* AFE seq tx2rx power up/down delay 40M */
-#define B43_NPHY_AFESEQ_RX2TX_PUD_20M		B43_PHY_N(0x202) /* AFE seq rx2tx power up/down delay 20M */
-#define B43_NPHY_AFESEQ_TX2RX_PUD_20M		B43_PHY_N(0x203) /* AFE seq tx2rx power up/down delay 20M */
-#define B43_NPHY_RX_SIGCTL			B43_PHY_N(0x204) /* RX signal control */
-#define B43_NPHY_RXPIL_CYCNT0			B43_PHY_N(0x205) /* RX pilot cycle counter 0 */
-#define B43_NPHY_RXPIL_CYCNT1			B43_PHY_N(0x206) /* RX pilot cycle counter 1 */
-#define B43_NPHY_RXPIL_CYCNT2			B43_PHY_N(0x207) /* RX pilot cycle counter 2 */
-#define B43_NPHY_AFESEQ_RX2TX_PUD_10M		B43_PHY_N(0x208) /* AFE seq rx2tx power up/down delay 10M */
-#define B43_NPHY_AFESEQ_TX2RX_PUD_10M		B43_PHY_N(0x209) /* AFE seq tx2rx power up/down delay 10M */
-#define B43_NPHY_DSSSCCK_CRSEXTL		B43_PHY_N(0x20A) /* DSSS/CCK CRS extension length */
-#define B43_NPHY_ML_LOGSS_RATSLOPE		B43_PHY_N(0x20B) /* ML/logss ratio slope */
-#define B43_NPHY_RIFS_SRCTL			B43_PHY_N(0x20C) /* RIFS search timeout length */
-#define B43_NPHY_TXREALFD			B43_PHY_N(0x20D) /* TX real frame delay */
-#define B43_NPHY_HPANT_SWTHRES			B43_PHY_N(0x20E) /* High power antenna switch threshold */
-#define B43_NPHY_EDCRS_ASSTHRES0		B43_PHY_N(0x210) /* ED CRS assert threshold 0 */
-#define B43_NPHY_EDCRS_ASSTHRES1		B43_PHY_N(0x211) /* ED CRS assert threshold 1 */
-#define B43_NPHY_EDCRS_DEASSTHRES0		B43_PHY_N(0x212) /* ED CRS deassert threshold 0 */
-#define B43_NPHY_EDCRS_DEASSTHRES1		B43_PHY_N(0x213) /* ED CRS deassert threshold 1 */
-#define B43_NPHY_STR_WTIME20U			B43_PHY_N(0x214) /* STR wait time 20U */
-#define B43_NPHY_STR_WTIME20L			B43_PHY_N(0x215) /* STR wait time 20L */
-#define B43_NPHY_TONE_MIDX657M			B43_PHY_N(0x216) /* Tone map index 657M */
-#define B43_NPHY_HTSIGTONES			B43_PHY_N(0x217) /* HT signal tones */
-#define B43_NPHY_RSSI1				B43_PHY_N(0x219) /* RSSI value 1 */
-#define B43_NPHY_RSSI2				B43_PHY_N(0x21A) /* RSSI value 2 */
-#define B43_NPHY_CHAN_ESTHANG			B43_PHY_N(0x21D) /* Channel estimate hang */
-#define B43_NPHY_FINERX2_CGC			B43_PHY_N(0x221) /* Fine RX 2 clock gate control */
-#define  B43_NPHY_FINERX2_CGC_DECGC		0x0008 /* Decode gated clocks */
-#define B43_NPHY_TXPCTL_INIT			B43_PHY_N(0x222) /* TX power controll init */
-#define  B43_NPHY_TXPCTL_INIT_PIDXI1		0x00FF /* Power index init 1 */
-#define  B43_NPHY_TXPCTL_INIT_PIDXI1_SHIFT	0
-
-
-
-/* Broadcom 2055 radio registers */
-
-#define B2055_GEN_SPARE			0x00 /* GEN spare */
-#define B2055_SP_PINPD			0x02 /* SP PIN PD */
-#define B2055_C1_SP_RSSI		0x03 /* SP RSSI Core 1 */
-#define B2055_C1_SP_PDMISC		0x04 /* SP PD MISC Core 1 */
-#define B2055_C2_SP_RSSI		0x05 /* SP RSSI Core 2 */
-#define B2055_C2_SP_PDMISC		0x06 /* SP PD MISC Core 2 */
-#define B2055_C1_SP_RXGC1		0x07 /* SP RX GC1 Core 1 */
-#define B2055_C1_SP_RXGC2		0x08 /* SP RX GC2 Core 1 */
-#define B2055_C2_SP_RXGC1		0x09 /* SP RX GC1 Core 2 */
-#define B2055_C2_SP_RXGC2		0x0A /* SP RX GC2 Core 2 */
-#define B2055_C1_SP_LPFBWSEL		0x0B /* SP LPF BW select Core 1 */
-#define B2055_C2_SP_LPFBWSEL		0x0C /* SP LPF BW select Core 2 */
-#define B2055_C1_SP_TXGC1		0x0D /* SP TX GC1 Core 1 */
-#define B2055_C1_SP_TXGC2		0x0E /* SP TX GC2 Core 1 */
-#define B2055_C2_SP_TXGC1		0x0F /* SP TX GC1 Core 2 */
-#define B2055_C2_SP_TXGC2		0x10 /* SP TX GC2 Core 2 */
-#define B2055_MASTER1			0x11 /* Master control 1 */
-#define B2055_MASTER2			0x12 /* Master control 2 */
-#define B2055_PD_LGEN			0x13 /* PD LGEN */
-#define B2055_PD_PLLTS			0x14 /* PD PLL TS */
-#define B2055_C1_PD_LGBUF		0x15 /* PD Core 1 LGBUF */
-#define B2055_C1_PD_TX			0x16 /* PD Core 1 TX */
-#define B2055_C1_PD_RXTX		0x17 /* PD Core 1 RXTX */
-#define B2055_C1_PD_RSSIMISC		0x18 /* PD Core 1 RSSI MISC */
-#define B2055_C2_PD_LGBUF		0x19 /* PD Core 2 LGBUF */
-#define B2055_C2_PD_TX			0x1A /* PD Core 2 TX */
-#define B2055_C2_PD_RXTX		0x1B /* PD Core 2 RXTX */
-#define B2055_C2_PD_RSSIMISC		0x1C /* PD Core 2 RSSI MISC */
-#define B2055_PWRDET_LGEN		0x1D /* PWRDET LGEN */
-#define B2055_C1_PWRDET_LGBUF		0x1E /* PWRDET LGBUF Core 1 */
-#define B2055_C1_PWRDET_RXTX		0x1F /* PWRDET RXTX Core 1 */
-#define B2055_C2_PWRDET_LGBUF		0x20 /* PWRDET LGBUF Core 2 */
-#define B2055_C2_PWRDET_RXTX		0x21 /* PWRDET RXTX Core 2 */
-#define B2055_RRCCAL_CS			0x22 /* RRCCAL Control spare */
-#define B2055_RRCCAL_NOPTSEL		0x23 /* RRCCAL N OPT SEL */
-#define B2055_CAL_MISC			0x24 /* CAL MISC */
-#define B2055_CAL_COUT			0x25 /* CAL Counter out */
-#define B2055_CAL_COUT2			0x26 /* CAL Counter out 2 */
-#define B2055_CAL_CVARCTL		0x27 /* CAL CVAR Control */
-#define B2055_CAL_RVARCTL		0x28 /* CAL RVAR Control */
-#define B2055_CAL_LPOCTL		0x29 /* CAL LPO Control */
-#define B2055_CAL_TS			0x2A /* CAL TS */
-#define B2055_CAL_RCCALRTS		0x2B /* CAL RCCAL READ TS */
-#define B2055_CAL_RCALRTS		0x2C /* CAL RCAL READ TS */
-#define B2055_PADDRV			0x2D /* PAD driver */
-#define B2055_XOCTL1			0x2E /* XO Control 1 */
-#define B2055_XOCTL2			0x2F /* XO Control 2 */
-#define B2055_XOREGUL			0x30 /* XO Regulator */
-#define B2055_XOMISC			0x31 /* XO misc */
-#define B2055_PLL_LFC1			0x32 /* PLL LF C1 */
-#define B2055_PLL_CALVTH		0x33 /* PLL CAL VTH */
-#define B2055_PLL_LFC2			0x34 /* PLL LF C2 */
-#define B2055_PLL_REF			0x35 /* PLL reference */
-#define B2055_PLL_LFR1			0x36 /* PLL LF R1 */
-#define B2055_PLL_PFDCP			0x37 /* PLL PFD CP */
-#define B2055_PLL_IDAC_CPOPAMP		0x38 /* PLL IDAC CPOPAMP */
-#define B2055_PLL_CPREG			0x39 /* PLL CP Regulator */
-#define B2055_PLL_RCAL			0x3A /* PLL RCAL */
-#define B2055_RF_PLLMOD0		0x3B /* RF PLL MOD0 */
-#define B2055_RF_PLLMOD1		0x3C /* RF PLL MOD1 */
-#define B2055_RF_MMDIDAC1		0x3D /* RF MMD IDAC 1 */
-#define B2055_RF_MMDIDAC0		0x3E /* RF MMD IDAC 0 */
-#define B2055_RF_MMDSP			0x3F /* RF MMD spare */
-#define B2055_VCO_CAL1			0x40 /* VCO cal 1 */
-#define B2055_VCO_CAL2			0x41 /* VCO cal 2 */
-#define B2055_VCO_CAL3			0x42 /* VCO cal 3 */
-#define B2055_VCO_CAL4			0x43 /* VCO cal 4 */
-#define B2055_VCO_CAL5			0x44 /* VCO cal 5 */
-#define B2055_VCO_CAL6			0x45 /* VCO cal 6 */
-#define B2055_VCO_CAL7			0x46 /* VCO cal 7 */
-#define B2055_VCO_CAL8			0x47 /* VCO cal 8 */
-#define B2055_VCO_CAL9			0x48 /* VCO cal 9 */
-#define B2055_VCO_CAL10			0x49 /* VCO cal 10 */
-#define B2055_VCO_CAL11			0x4A /* VCO cal 11 */
-#define B2055_VCO_CAL12			0x4B /* VCO cal 12 */
-#define B2055_VCO_CAL13			0x4C /* VCO cal 13 */
-#define B2055_VCO_CAL14			0x4D /* VCO cal 14 */
-#define B2055_VCO_CAL15			0x4E /* VCO cal 15 */
-#define B2055_VCO_CAL16			0x4F /* VCO cal 16 */
-#define B2055_VCO_KVCO			0x50 /* VCO KVCO */
-#define B2055_VCO_CAPTAIL		0x51 /* VCO CAP TAIL */
-#define B2055_VCO_IDACVCO		0x52 /* VCO IDAC VCO */
-#define B2055_VCO_REG			0x53 /* VCO Regulator */
-#define B2055_PLL_RFVTH			0x54 /* PLL RF VTH */
-#define B2055_LGBUF_CENBUF		0x55 /* LGBUF CEN BUF */
-#define B2055_LGEN_TUNE1		0x56 /* LGEN tune 1 */
-#define B2055_LGEN_TUNE2		0x57 /* LGEN tune 2 */
-#define B2055_LGEN_IDAC1		0x58 /* LGEN IDAC 1 */
-#define B2055_LGEN_IDAC2		0x59 /* LGEN IDAC 2 */
-#define B2055_LGEN_BIASC		0x5A /* LGEN BIAS counter */
-#define B2055_LGEN_BIASIDAC		0x5B /* LGEN BIAS IDAC */
-#define B2055_LGEN_RCAL			0x5C /* LGEN RCAL */
-#define B2055_LGEN_DIV			0x5D /* LGEN div */
-#define B2055_LGEN_SPARE2		0x5E /* LGEN spare 2 */
-#define B2055_C1_LGBUF_ATUNE		0x5F /* Core 1 LGBUF A tune */
-#define B2055_C1_LGBUF_GTUNE		0x60 /* Core 1 LGBUF G tune */
-#define B2055_C1_LGBUF_DIV		0x61 /* Core 1 LGBUF div */
-#define B2055_C1_LGBUF_AIDAC		0x62 /* Core 1 LGBUF A IDAC */
-#define B2055_C1_LGBUF_GIDAC		0x63 /* Core 1 LGBUF G IDAC */
-#define B2055_C1_LGBUF_IDACFO		0x64 /* Core 1 LGBUF IDAC filter override */
-#define B2055_C1_LGBUF_SPARE		0x65 /* Core 1 LGBUF spare */
-#define B2055_C1_RX_RFSPC1		0x66 /* Core 1 RX RF SPC1 */
-#define B2055_C1_RX_RFR1		0x67 /* Core 1 RX RF reg 1 */
-#define B2055_C1_RX_RFR2		0x68 /* Core 1 RX RF reg 2 */
-#define B2055_C1_RX_RFRCAL		0x69 /* Core 1 RX RF RCAL */
-#define B2055_C1_RX_BB_BLCMP		0x6A /* Core 1 RX Baseband BUFI LPF CMP */
-#define B2055_C1_RX_BB_LPF		0x6B /* Core 1 RX Baseband LPF */
-#define B2055_C1_RX_BB_MIDACHP		0x6C /* Core 1 RX Baseband MIDAC High-pass */
-#define B2055_C1_RX_BB_VGA1IDAC		0x6D /* Core 1 RX Baseband VGA1 IDAC */
-#define B2055_C1_RX_BB_VGA2IDAC		0x6E /* Core 1 RX Baseband VGA2 IDAC */
-#define B2055_C1_RX_BB_VGA3IDAC		0x6F /* Core 1 RX Baseband VGA3 IDAC */
-#define B2055_C1_RX_BB_BUFOCTL		0x70 /* Core 1 RX Baseband BUFO Control */
-#define B2055_C1_RX_BB_RCCALCTL		0x71 /* Core 1 RX Baseband RCCAL Control */
-#define B2055_C1_RX_BB_RSSICTL1		0x72 /* Core 1 RX Baseband RSSI Control 1 */
-#define B2055_C1_RX_BB_RSSICTL2		0x73 /* Core 1 RX Baseband RSSI Control 2 */
-#define B2055_C1_RX_BB_RSSICTL3		0x74 /* Core 1 RX Baseband RSSI Control 3 */
-#define B2055_C1_RX_BB_RSSICTL4		0x75 /* Core 1 RX Baseband RSSI Control 4 */
-#define B2055_C1_RX_BB_RSSICTL5		0x76 /* Core 1 RX Baseband RSSI Control 5 */
-#define B2055_C1_RX_BB_REG		0x77 /* Core 1 RX Baseband Regulator */
-#define B2055_C1_RX_BB_SPARE1		0x78 /* Core 1 RX Baseband spare 1 */
-#define B2055_C1_RX_TXBBRCAL		0x79 /* Core 1 RX TX BB RCAL */
-#define B2055_C1_TX_RF_SPGA		0x7A /* Core 1 TX RF SGM PGA */
-#define B2055_C1_TX_RF_SPAD		0x7B /* Core 1 TX RF SGM PAD */
-#define B2055_C1_TX_RF_CNTPGA1		0x7C /* Core 1 TX RF counter PGA 1 */
-#define B2055_C1_TX_RF_CNTPAD1		0x7D /* Core 1 TX RF counter PAD 1 */
-#define B2055_C1_TX_RF_PGAIDAC		0x7E /* Core 1 TX RF PGA IDAC */
-#define B2055_C1_TX_PGAPADTN		0x7F /* Core 1 TX PGA PAD TN */
-#define B2055_C1_TX_PADIDAC1		0x80 /* Core 1 TX PAD IDAC 1 */
-#define B2055_C1_TX_PADIDAC2		0x81 /* Core 1 TX PAD IDAC 2 */
-#define B2055_C1_TX_MXBGTRIM		0x82 /* Core 1 TX MX B/G TRIM */
-#define B2055_C1_TX_RF_RCAL		0x83 /* Core 1 TX RF RCAL */
-#define B2055_C1_TX_RF_PADTSSI1		0x84 /* Core 1 TX RF PAD TSSI1 */
-#define B2055_C1_TX_RF_PADTSSI2		0x85 /* Core 1 TX RF PAD TSSI2 */
-#define B2055_C1_TX_RF_SPARE		0x86 /* Core 1 TX RF spare */
-#define B2055_C1_TX_RF_IQCAL1		0x87 /* Core 1 TX RF I/Q CAL 1 */
-#define B2055_C1_TX_RF_IQCAL2		0x88 /* Core 1 TX RF I/Q CAL 2 */
-#define B2055_C1_TXBB_RCCAL		0x89 /* Core 1 TXBB RC CAL Control */
-#define B2055_C1_TXBB_LPF1		0x8A /* Core 1 TXBB LPF 1 */
-#define B2055_C1_TX_VOSCNCL		0x8B /* Core 1 TX VOS CNCL */
-#define B2055_C1_TX_LPF_MXGMIDAC	0x8C /* Core 1 TX LPF MXGM IDAC */
-#define B2055_C1_TX_BB_MXGM		0x8D /* Core 1 TX BB MXGM */
-#define B2055_C2_LGBUF_ATUNE		0x8E /* Core 2 LGBUF A tune */
-#define B2055_C2_LGBUF_GTUNE		0x8F /* Core 2 LGBUF G tune */
-#define B2055_C2_LGBUF_DIV		0x90 /* Core 2 LGBUF div */
-#define B2055_C2_LGBUF_AIDAC		0x91 /* Core 2 LGBUF A IDAC */
-#define B2055_C2_LGBUF_GIDAC		0x92 /* Core 2 LGBUF G IDAC */
-#define B2055_C2_LGBUF_IDACFO		0x93 /* Core 2 LGBUF IDAC filter override */
-#define B2055_C2_LGBUF_SPARE		0x94 /* Core 2 LGBUF spare */
-#define B2055_C2_RX_RFSPC1		0x95 /* Core 2 RX RF SPC1 */
-#define B2055_C2_RX_RFR1		0x96 /* Core 2 RX RF reg 1 */
-#define B2055_C2_RX_RFR2		0x97 /* Core 2 RX RF reg 2 */
-#define B2055_C2_RX_RFRCAL		0x98 /* Core 2 RX RF RCAL */
-#define B2055_C2_RX_BB_BLCMP		0x99 /* Core 2 RX Baseband BUFI LPF CMP */
-#define B2055_C2_RX_BB_LPF		0x9A /* Core 2 RX Baseband LPF */
-#define B2055_C2_RX_BB_MIDACHP		0x9B /* Core 2 RX Baseband MIDAC High-pass */
-#define B2055_C2_RX_BB_VGA1IDAC		0x9C /* Core 2 RX Baseband VGA1 IDAC */
-#define B2055_C2_RX_BB_VGA2IDAC		0x9D /* Core 2 RX Baseband VGA2 IDAC */
-#define B2055_C2_RX_BB_VGA3IDAC		0x9E /* Core 2 RX Baseband VGA3 IDAC */
-#define B2055_C2_RX_BB_BUFOCTL		0x9F /* Core 2 RX Baseband BUFO Control */
-#define B2055_C2_RX_BB_RCCALCTL		0xA0 /* Core 2 RX Baseband RCCAL Control */
-#define B2055_C2_RX_BB_RSSICTL1		0xA1 /* Core 2 RX Baseband RSSI Control 1 */
-#define B2055_C2_RX_BB_RSSICTL2		0xA2 /* Core 2 RX Baseband RSSI Control 2 */
-#define B2055_C2_RX_BB_RSSICTL3		0xA3 /* Core 2 RX Baseband RSSI Control 3 */
-#define B2055_C2_RX_BB_RSSICTL4		0xA4 /* Core 2 RX Baseband RSSI Control 4 */
-#define B2055_C2_RX_BB_RSSICTL5		0xA5 /* Core 2 RX Baseband RSSI Control 5 */
-#define B2055_C2_RX_BB_REG		0xA6 /* Core 2 RX Baseband Regulator */
-#define B2055_C2_RX_BB_SPARE1		0xA7 /* Core 2 RX Baseband spare 1 */
-#define B2055_C2_RX_TXBBRCAL		0xA8 /* Core 2 RX TX BB RCAL */
-#define B2055_C2_TX_RF_SPGA		0xA9 /* Core 2 TX RF SGM PGA */
-#define B2055_C2_TX_RF_SPAD		0xAA /* Core 2 TX RF SGM PAD */
-#define B2055_C2_TX_RF_CNTPGA1		0xAB /* Core 2 TX RF counter PGA 1 */
-#define B2055_C2_TX_RF_CNTPAD1		0xAC /* Core 2 TX RF counter PAD 1 */
-#define B2055_C2_TX_RF_PGAIDAC		0xAD /* Core 2 TX RF PGA IDAC */
-#define B2055_C2_TX_PGAPADTN		0xAE /* Core 2 TX PGA PAD TN */
-#define B2055_C2_TX_PADIDAC1		0xAF /* Core 2 TX PAD IDAC 1 */
-#define B2055_C2_TX_PADIDAC2		0xB0 /* Core 2 TX PAD IDAC 2 */
-#define B2055_C2_TX_MXBGTRIM		0xB1 /* Core 2 TX MX B/G TRIM */
-#define B2055_C2_TX_RF_RCAL		0xB2 /* Core 2 TX RF RCAL */
-#define B2055_C2_TX_RF_PADTSSI1		0xB3 /* Core 2 TX RF PAD TSSI1 */
-#define B2055_C2_TX_RF_PADTSSI2		0xB4 /* Core 2 TX RF PAD TSSI2 */
-#define B2055_C2_TX_RF_SPARE		0xB5 /* Core 2 TX RF spare */
-#define B2055_C2_TX_RF_IQCAL1		0xB6 /* Core 2 TX RF I/Q CAL 1 */
-#define B2055_C2_TX_RF_IQCAL2		0xB7 /* Core 2 TX RF I/Q CAL 2 */
-#define B2055_C2_TXBB_RCCAL		0xB8 /* Core 2 TXBB RC CAL Control */
-#define B2055_C2_TXBB_LPF1		0xB9 /* Core 2 TXBB LPF 1 */
-#define B2055_C2_TX_VOSCNCL		0xBA /* Core 2 TX VOS CNCL */
-#define B2055_C2_TX_LPF_MXGMIDAC	0xBB /* Core 2 TX LPF MXGM IDAC */
-#define B2055_C2_TX_BB_MXGM		0xBC /* Core 2 TX BB MXGM */
-#define B2055_PRG_GCHP21		0xBD /* PRG GC HPVGA23 21 */
-#define B2055_PRG_GCHP22		0xBE /* PRG GC HPVGA23 22 */
-#define B2055_PRG_GCHP23		0xBF /* PRG GC HPVGA23 23 */
-#define B2055_PRG_GCHP24		0xC0 /* PRG GC HPVGA23 24 */
-#define B2055_PRG_GCHP25		0xC1 /* PRG GC HPVGA23 25 */
-#define B2055_PRG_GCHP26		0xC2 /* PRG GC HPVGA23 26 */
-#define B2055_PRG_GCHP27		0xC3 /* PRG GC HPVGA23 27 */
-#define B2055_PRG_GCHP28		0xC4 /* PRG GC HPVGA23 28 */
-#define B2055_PRG_GCHP29		0xC5 /* PRG GC HPVGA23 29 */
-#define B2055_PRG_GCHP30		0xC6 /* PRG GC HPVGA23 30 */
-#define B2055_C1_LNA_GAINBST		0xCD /* Core 1 LNA GAINBST */
-#define B2055_C1_B0NB_RSSIVCM		0xD2 /* Core 1 B0 narrow-band RSSI VCM */
-#define B2055_C1_GENSPARE2		0xD6 /* Core 1 GEN spare 2 */
-#define B2055_C2_LNA_GAINBST		0xD9 /* Core 2 LNA GAINBST */
-#define B2055_C2_B0NB_RSSIVCM		0xDE /* Core 2 B0 narrow-band RSSI VCM */
-#define B2055_C2_GENSPARE2		0xE2 /* Core 2 GEN spare 2 */
-
-
-
-struct b43_wldev;
-
-
-#ifdef CONFIG_B43_NPHY
-/* N-PHY support enabled */
-
-int b43_phy_initn(struct b43_wldev *dev);
-
-void b43_nphy_radio_turn_on(struct b43_wldev *dev);
-void b43_nphy_radio_turn_off(struct b43_wldev *dev);
-
-int b43_nphy_selectchannel(struct b43_wldev *dev, u8 channel);
-
-void b43_nphy_xmitpower(struct b43_wldev *dev);
-void b43_nphy_set_rxantenna(struct b43_wldev *dev, int antenna);
-
-
-#else /* CONFIG_B43_NPHY */
-/* N-PHY support disabled */
-
-
-static inline
-int b43_phy_initn(struct b43_wldev *dev)
-{
-	return -EOPNOTSUPP;
-}
-
-static inline
-void b43_nphy_radio_turn_on(struct b43_wldev *dev)
-{
-}
-static inline
-void b43_nphy_radio_turn_off(struct b43_wldev *dev)
-{
-}
-
-static inline
-int b43_nphy_selectchannel(struct b43_wldev *dev, u8 channel)
-{
-	return -ENOSYS;
-}
-
-static inline
-void b43_nphy_xmitpower(struct b43_wldev *dev)
-{
-}
-static inline
-void b43_nphy_set_rxantenna(struct b43_wldev *dev, int antenna)
-{
-}
-
-#endif /* CONFIG_B43_NPHY */
-#endif /* B43_NPHY_H_ */
diff --git a/drivers/net/wireless/b43/pcmcia.c b/drivers/net/wireless/b43/pcmcia.c
index b8aa163..3cfc303 100644
--- a/drivers/net/wireless/b43/pcmcia.c
+++ b/drivers/net/wireless/b43/pcmcia.c
@@ -82,13 +82,13 @@
 	tuple.TupleOffset = 0;
 
 	res = pcmcia_get_first_tuple(dev, &tuple);
-	if (res != CS_SUCCESS)
+	if (res != 0)
 		goto err_kfree_ssb;
 	res = pcmcia_get_tuple_data(dev, &tuple);
-	if (res != CS_SUCCESS)
+	if (res != 0)
 		goto err_kfree_ssb;
-	res = pcmcia_parse_tuple(dev, &tuple, &parse);
-	if (res != CS_SUCCESS)
+	res = pcmcia_parse_tuple(&tuple, &parse);
+	if (res != 0)
 		goto err_kfree_ssb;
 
 	dev->conf.ConfigBase = parse.config.base;
@@ -107,13 +107,13 @@
 	win.Size = SSB_CORE_SIZE;
 	win.AccessSpeed = 250;
 	res = pcmcia_request_window(&dev, &win, &dev->win);
-	if (res != CS_SUCCESS)
+	if (res != 0)
 		goto err_kfree_ssb;
 
 	mem.CardOffset = 0;
 	mem.Page = 0;
 	res = pcmcia_map_mem_page(dev->win, &mem);
-	if (res != CS_SUCCESS)
+	if (res != 0)
 		goto err_disable;
 
 	dev->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING;
@@ -121,11 +121,11 @@
 	dev->irq.Handler = NULL; /* The handler is registered later. */
 	dev->irq.Instance = NULL;
 	res = pcmcia_request_irq(dev, &dev->irq);
-	if (res != CS_SUCCESS)
+	if (res != 0)
 		goto err_disable;
 
 	res = pcmcia_request_configuration(dev, &dev->conf);
-	if (res != CS_SUCCESS)
+	if (res != 0)
 		goto err_disable;
 
 	err = ssb_bus_pcmciabus_register(ssb, dev, win.Base);
diff --git a/drivers/net/wireless/b43/phy.c b/drivers/net/wireless/b43/phy.c
deleted file mode 100644
index 305d4cd..0000000
--- a/drivers/net/wireless/b43/phy.c
+++ /dev/null
@@ -1,3906 +0,0 @@
-/*
-
-  Broadcom B43 wireless driver
-
-  Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
-  Copyright (c) 2005-2007 Stefano Brivio <stefano.brivio@polimi.it>
-  Copyright (c) 2005, 2006 Michael Buesch <mb@bu3sch.de>
-  Copyright (c) 2005, 2006 Danny van Dyk <kugelfang@gentoo.org>
-  Copyright (c) 2005, 2006 Andreas Jaggi <andreas.jaggi@waterwave.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; see the file COPYING.  If not, write to
-  the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
-  Boston, MA 02110-1301, USA.
-
-*/
-
-#include <linux/delay.h>
-#include <linux/io.h>
-#include <linux/types.h>
-#include <linux/bitrev.h>
-
-#include "b43.h"
-#include "phy.h"
-#include "nphy.h"
-#include "main.h"
-#include "tables.h"
-#include "lo.h"
-#include "wa.h"
-
-
-static const s8 b43_tssi2dbm_b_table[] = {
-	0x4D, 0x4C, 0x4B, 0x4A,
-	0x4A, 0x49, 0x48, 0x47,
-	0x47, 0x46, 0x45, 0x45,
-	0x44, 0x43, 0x42, 0x42,
-	0x41, 0x40, 0x3F, 0x3E,
-	0x3D, 0x3C, 0x3B, 0x3A,
-	0x39, 0x38, 0x37, 0x36,
-	0x35, 0x34, 0x32, 0x31,
-	0x30, 0x2F, 0x2D, 0x2C,
-	0x2B, 0x29, 0x28, 0x26,
-	0x25, 0x23, 0x21, 0x1F,
-	0x1D, 0x1A, 0x17, 0x14,
-	0x10, 0x0C, 0x06, 0x00,
-	-7, -7, -7, -7,
-	-7, -7, -7, -7,
-	-7, -7, -7, -7,
-};
-
-static const s8 b43_tssi2dbm_g_table[] = {
-	77, 77, 77, 76,
-	76, 76, 75, 75,
-	74, 74, 73, 73,
-	73, 72, 72, 71,
-	71, 70, 70, 69,
-	68, 68, 67, 67,
-	66, 65, 65, 64,
-	63, 63, 62, 61,
-	60, 59, 58, 57,
-	56, 55, 54, 53,
-	52, 50, 49, 47,
-	45, 43, 40, 37,
-	33, 28, 22, 14,
-	5, -7, -20, -20,
-	-20, -20, -20, -20,
-	-20, -20, -20, -20,
-};
-
-const u8 b43_radio_channel_codes_bg[] = {
-	12, 17, 22, 27,
-	32, 37, 42, 47,
-	52, 57, 62, 67,
-	72, 84,
-};
-
-#define bitrev4(tmp) (bitrev8(tmp) >> 4)
-static void b43_phy_initg(struct b43_wldev *dev);
-
-static void generate_rfatt_list(struct b43_wldev *dev,
-				struct b43_rfatt_list *list)
-{
-	struct b43_phy *phy = &dev->phy;
-
-	/* APHY.rev < 5 || GPHY.rev < 6 */
-	static const struct b43_rfatt rfatt_0[] = {
-		{.att = 3,.with_padmix = 0,},
-		{.att = 1,.with_padmix = 0,},
-		{.att = 5,.with_padmix = 0,},
-		{.att = 7,.with_padmix = 0,},
-		{.att = 9,.with_padmix = 0,},
-		{.att = 2,.with_padmix = 0,},
-		{.att = 0,.with_padmix = 0,},
-		{.att = 4,.with_padmix = 0,},
-		{.att = 6,.with_padmix = 0,},
-		{.att = 8,.with_padmix = 0,},
-		{.att = 1,.with_padmix = 1,},
-		{.att = 2,.with_padmix = 1,},
-		{.att = 3,.with_padmix = 1,},
-		{.att = 4,.with_padmix = 1,},
-	};
-	/* Radio.rev == 8 && Radio.version == 0x2050 */
-	static const struct b43_rfatt rfatt_1[] = {
-		{.att = 2,.with_padmix = 1,},
-		{.att = 4,.with_padmix = 1,},
-		{.att = 6,.with_padmix = 1,},
-		{.att = 8,.with_padmix = 1,},
-		{.att = 10,.with_padmix = 1,},
-		{.att = 12,.with_padmix = 1,},
-		{.att = 14,.with_padmix = 1,},
-	};
-	/* Otherwise */
-	static const struct b43_rfatt rfatt_2[] = {
-		{.att = 0,.with_padmix = 1,},
-		{.att = 2,.with_padmix = 1,},
-		{.att = 4,.with_padmix = 1,},
-		{.att = 6,.with_padmix = 1,},
-		{.att = 8,.with_padmix = 1,},
-		{.att = 9,.with_padmix = 1,},
-		{.att = 9,.with_padmix = 1,},
-	};
-
-	if (!b43_has_hardware_pctl(phy)) {
-		/* Software pctl */
-		list->list = rfatt_0;
-		list->len = ARRAY_SIZE(rfatt_0);
-		list->min_val = 0;
-		list->max_val = 9;
-		return;
-	}
-	if (phy->radio_ver == 0x2050 && phy->radio_rev == 8) {
-		/* Hardware pctl */
-		list->list = rfatt_1;
-		list->len = ARRAY_SIZE(rfatt_1);
-		list->min_val = 0;
-		list->max_val = 14;
-		return;
-	}
-	/* Hardware pctl */
-	list->list = rfatt_2;
-	list->len = ARRAY_SIZE(rfatt_2);
-	list->min_val = 0;
-	list->max_val = 9;
-}
-
-static void generate_bbatt_list(struct b43_wldev *dev,
-				struct b43_bbatt_list *list)
-{
-	static const struct b43_bbatt bbatt_0[] = {
-		{.att = 0,},
-		{.att = 1,},
-		{.att = 2,},
-		{.att = 3,},
-		{.att = 4,},
-		{.att = 5,},
-		{.att = 6,},
-		{.att = 7,},
-		{.att = 8,},
-	};
-
-	list->list = bbatt_0;
-	list->len = ARRAY_SIZE(bbatt_0);
-	list->min_val = 0;
-	list->max_val = 8;
-}
-
-bool b43_has_hardware_pctl(struct b43_phy *phy)
-{
-	if (!phy->hardware_power_control)
-		return 0;
-	switch (phy->type) {
-	case B43_PHYTYPE_A:
-		if (phy->rev >= 5)
-			return 1;
-		break;
-	case B43_PHYTYPE_G:
-		if (phy->rev >= 6)
-			return 1;
-		break;
-	default:
-		B43_WARN_ON(1);
-	}
-	return 0;
-}
-
-static void b43_shm_clear_tssi(struct b43_wldev *dev)
-{
-	struct b43_phy *phy = &dev->phy;
-
-	switch (phy->type) {
-	case B43_PHYTYPE_A:
-		b43_shm_write16(dev, B43_SHM_SHARED, 0x0068, 0x7F7F);
-		b43_shm_write16(dev, B43_SHM_SHARED, 0x006a, 0x7F7F);
-		break;
-	case B43_PHYTYPE_B:
-	case B43_PHYTYPE_G:
-		b43_shm_write16(dev, B43_SHM_SHARED, 0x0058, 0x7F7F);
-		b43_shm_write16(dev, B43_SHM_SHARED, 0x005a, 0x7F7F);
-		b43_shm_write16(dev, B43_SHM_SHARED, 0x0070, 0x7F7F);
-		b43_shm_write16(dev, B43_SHM_SHARED, 0x0072, 0x7F7F);
-		break;
-	}
-}
-
-/* Lock the PHY registers against concurrent access from the microcode.
- * This lock is nonrecursive. */
-void b43_phy_lock(struct b43_wldev *dev)
-{
-#if B43_DEBUG
-	B43_WARN_ON(dev->phy.phy_locked);
-	dev->phy.phy_locked = 1;
-#endif
-	B43_WARN_ON(dev->dev->id.revision < 3);
-
-	if (!b43_is_mode(dev->wl, IEEE80211_IF_TYPE_AP))
-		b43_power_saving_ctl_bits(dev, B43_PS_AWAKE);
-}
-
-void b43_phy_unlock(struct b43_wldev *dev)
-{
-#if B43_DEBUG
-	B43_WARN_ON(!dev->phy.phy_locked);
-	dev->phy.phy_locked = 0;
-#endif
-	B43_WARN_ON(dev->dev->id.revision < 3);
-
-	if (!b43_is_mode(dev->wl, IEEE80211_IF_TYPE_AP))
-		b43_power_saving_ctl_bits(dev, 0);
-}
-
-/* Different PHYs require different register routing flags.
- * This adjusts (and does sanity checks on) the routing flags.
- */
-static inline u16 adjust_phyreg_for_phytype(struct b43_phy *phy,
-					    u16 offset, struct b43_wldev *dev)
-{
-	if (phy->type == B43_PHYTYPE_A) {
-		/* OFDM registers are base-registers for the A-PHY. */
-		if ((offset & B43_PHYROUTE) == B43_PHYROUTE_OFDM_GPHY) {
-			offset &= ~B43_PHYROUTE;
-			offset |= B43_PHYROUTE_BASE;
-		}
-	}
-
-#if B43_DEBUG
-	if ((offset & B43_PHYROUTE) == B43_PHYROUTE_EXT_GPHY) {
-		/* Ext-G registers are only available on G-PHYs */
-		if (phy->type != B43_PHYTYPE_G) {
-			b43err(dev->wl, "Invalid EXT-G PHY access at "
-			       "0x%04X on PHY type %u\n", offset, phy->type);
-			dump_stack();
-		}
-	}
-	if ((offset & B43_PHYROUTE) == B43_PHYROUTE_N_BMODE) {
-		/* N-BMODE registers are only available on N-PHYs */
-		if (phy->type != B43_PHYTYPE_N) {
-			b43err(dev->wl, "Invalid N-BMODE PHY access at "
-			       "0x%04X on PHY type %u\n", offset, phy->type);
-			dump_stack();
-		}
-	}
-#endif /* B43_DEBUG */
-
-	return offset;
-}
-
-u16 b43_phy_read(struct b43_wldev * dev, u16 offset)
-{
-	struct b43_phy *phy = &dev->phy;
-
-	offset = adjust_phyreg_for_phytype(phy, offset, dev);
-	b43_write16(dev, B43_MMIO_PHY_CONTROL, offset);
-	return b43_read16(dev, B43_MMIO_PHY_DATA);
-}
-
-void b43_phy_write(struct b43_wldev *dev, u16 offset, u16 val)
-{
-	struct b43_phy *phy = &dev->phy;
-
-	offset = adjust_phyreg_for_phytype(phy, offset, dev);
-	b43_write16(dev, B43_MMIO_PHY_CONTROL, offset);
-	b43_write16(dev, B43_MMIO_PHY_DATA, val);
-}
-
-void b43_phy_mask(struct b43_wldev *dev, u16 offset, u16 mask)
-{
-	b43_phy_write(dev, offset,
-		      b43_phy_read(dev, offset) & mask);
-}
-
-void b43_phy_set(struct b43_wldev *dev, u16 offset, u16 set)
-{
-	b43_phy_write(dev, offset,
-		      b43_phy_read(dev, offset) | set);
-}
-
-void b43_phy_maskset(struct b43_wldev *dev, u16 offset, u16 mask, u16 set)
-{
-	b43_phy_write(dev, offset,
-		      (b43_phy_read(dev, offset) & mask) | set);
-}
-
-/* Adjust the transmission power output (G-PHY) */
-void b43_set_txpower_g(struct b43_wldev *dev,
-		       const struct b43_bbatt *bbatt,
-		       const struct b43_rfatt *rfatt, u8 tx_control)
-{
-	struct b43_phy *phy = &dev->phy;
-	struct b43_txpower_lo_control *lo = phy->lo_control;
-	u16 bb, rf;
-	u16 tx_bias, tx_magn;
-
-	bb = bbatt->att;
-	rf = rfatt->att;
-	tx_bias = lo->tx_bias;
-	tx_magn = lo->tx_magn;
-	if (unlikely(tx_bias == 0xFF))
-		tx_bias = 0;
-
-	/* Save the values for later */
-	phy->tx_control = tx_control;
-	memcpy(&phy->rfatt, rfatt, sizeof(*rfatt));
-	phy->rfatt.with_padmix = !!(tx_control & B43_TXCTL_TXMIX);
-	memcpy(&phy->bbatt, bbatt, sizeof(*bbatt));
-
-	if (b43_debug(dev, B43_DBG_XMITPOWER)) {
-		b43dbg(dev->wl, "Tuning TX-power to bbatt(%u), "
-		       "rfatt(%u), tx_control(0x%02X), "
-		       "tx_bias(0x%02X), tx_magn(0x%02X)\n",
-		       bb, rf, tx_control, tx_bias, tx_magn);
-	}
-
-	b43_phy_set_baseband_attenuation(dev, bb);
-	b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_RFATT, rf);
-	if (phy->radio_ver == 0x2050 && phy->radio_rev == 8) {
-		b43_radio_write16(dev, 0x43,
-				  (rf & 0x000F) | (tx_control & 0x0070));
-	} else {
-		b43_radio_write16(dev, 0x43, (b43_radio_read16(dev, 0x43)
-					      & 0xFFF0) | (rf & 0x000F));
-		b43_radio_write16(dev, 0x52, (b43_radio_read16(dev, 0x52)
-					      & ~0x0070) | (tx_control &
-							    0x0070));
-	}
-	if (has_tx_magnification(phy)) {
-		b43_radio_write16(dev, 0x52, tx_magn | tx_bias);
-	} else {
-		b43_radio_write16(dev, 0x52, (b43_radio_read16(dev, 0x52)
-					      & 0xFFF0) | (tx_bias & 0x000F));
-	}
-	if (phy->type == B43_PHYTYPE_G)
-		b43_lo_g_adjust(dev);
-}
-
-static void default_baseband_attenuation(struct b43_wldev *dev,
-					 struct b43_bbatt *bb)
-{
-	struct b43_phy *phy = &dev->phy;
-
-	if (phy->radio_ver == 0x2050 && phy->radio_rev < 6)
-		bb->att = 0;
-	else
-		bb->att = 2;
-}
-
-static void default_radio_attenuation(struct b43_wldev *dev,
-				      struct b43_rfatt *rf)
-{
-	struct ssb_bus *bus = dev->dev->bus;
-	struct b43_phy *phy = &dev->phy;
-
-	rf->with_padmix = 0;
-
-	if (bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM &&
-	    bus->boardinfo.type == SSB_BOARD_BCM4309G) {
-		if (bus->boardinfo.rev < 0x43) {
-			rf->att = 2;
-			return;
-		} else if (bus->boardinfo.rev < 0x51) {
-			rf->att = 3;
-			return;
-		}
-	}
-
-	if (phy->type == B43_PHYTYPE_A) {
-		rf->att = 0x60;
-		return;
-	}
-
-	switch (phy->radio_ver) {
-	case 0x2053:
-		switch (phy->radio_rev) {
-		case 1:
-			rf->att = 6;
-			return;
-		}
-		break;
-	case 0x2050:
-		switch (phy->radio_rev) {
-		case 0:
-			rf->att = 5;
-			return;
-		case 1:
-			if (phy->type == B43_PHYTYPE_G) {
-				if (bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM
-				    && bus->boardinfo.type == SSB_BOARD_BCM4309G
-				    && bus->boardinfo.rev >= 30)
-					rf->att = 3;
-				else if (bus->boardinfo.vendor ==
-					 SSB_BOARDVENDOR_BCM
-					 && bus->boardinfo.type ==
-					 SSB_BOARD_BU4306)
-					rf->att = 3;
-				else
-					rf->att = 1;
-			} else {
-				if (bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM
-				    && bus->boardinfo.type == SSB_BOARD_BCM4309G
-				    && bus->boardinfo.rev >= 30)
-					rf->att = 7;
-				else
-					rf->att = 6;
-			}
-			return;
-		case 2:
-			if (phy->type == B43_PHYTYPE_G) {
-				if (bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM
-				    && bus->boardinfo.type == SSB_BOARD_BCM4309G
-				    && bus->boardinfo.rev >= 30)
-					rf->att = 3;
-				else if (bus->boardinfo.vendor ==
-					 SSB_BOARDVENDOR_BCM
-					 && bus->boardinfo.type ==
-					 SSB_BOARD_BU4306)
-					rf->att = 5;
-				else if (bus->chip_id == 0x4320)
-					rf->att = 4;
-				else
-					rf->att = 3;
-			} else
-				rf->att = 6;
-			return;
-		case 3:
-			rf->att = 5;
-			return;
-		case 4:
-		case 5:
-			rf->att = 1;
-			return;
-		case 6:
-		case 7:
-			rf->att = 5;
-			return;
-		case 8:
-			rf->att = 0xA;
-			rf->with_padmix = 1;
-			return;
-		case 9:
-		default:
-			rf->att = 5;
-			return;
-		}
-	}
-	rf->att = 5;
-}
-
-static u16 default_tx_control(struct b43_wldev *dev)
-{
-	struct b43_phy *phy = &dev->phy;
-
-	if (phy->radio_ver != 0x2050)
-		return 0;
-	if (phy->radio_rev == 1)
-		return B43_TXCTL_PA2DB | B43_TXCTL_TXMIX;
-	if (phy->radio_rev < 6)
-		return B43_TXCTL_PA2DB;
-	if (phy->radio_rev == 8)
-		return B43_TXCTL_TXMIX;
-	return 0;
-}
-
-/* This func is called "PHY calibrate" in the specs... */
-void b43_phy_early_init(struct b43_wldev *dev)
-{
-	struct b43_phy *phy = &dev->phy;
-	struct b43_txpower_lo_control *lo = phy->lo_control;
-
-	default_baseband_attenuation(dev, &phy->bbatt);
-	default_radio_attenuation(dev, &phy->rfatt);
-	phy->tx_control = (default_tx_control(dev) << 4);
-
-	/* Commit previous writes */
-	b43_read32(dev, B43_MMIO_MACCTL);
-
-	if (phy->type == B43_PHYTYPE_B || phy->type == B43_PHYTYPE_G) {
-		generate_rfatt_list(dev, &lo->rfatt_list);
-		generate_bbatt_list(dev, &lo->bbatt_list);
-	}
-	if (phy->type == B43_PHYTYPE_G && phy->rev == 1) {
-		/* Workaround: Temporarly disable gmode through the early init
-		 * phase, as the gmode stuff is not needed for phy rev 1 */
-		phy->gmode = 0;
-		b43_wireless_core_reset(dev, 0);
-		b43_phy_initg(dev);
-		phy->gmode = 1;
-		b43_wireless_core_reset(dev, B43_TMSLOW_GMODE);
-	}
-}
-
-/* GPHY_TSSI_Power_Lookup_Table_Init */
-static void b43_gphy_tssi_power_lt_init(struct b43_wldev *dev)
-{
-	struct b43_phy *phy = &dev->phy;
-	int i;
-	u16 value;
-
-	for (i = 0; i < 32; i++)
-		b43_ofdmtab_write16(dev, 0x3C20, i, phy->tssi2dbm[i]);
-	for (i = 32; i < 64; i++)
-		b43_ofdmtab_write16(dev, 0x3C00, i - 32, phy->tssi2dbm[i]);
-	for (i = 0; i < 64; i += 2) {
-		value = (u16) phy->tssi2dbm[i];
-		value |= ((u16) phy->tssi2dbm[i + 1]) << 8;
-		b43_phy_write(dev, 0x380 + (i / 2), value);
-	}
-}
-
-/* GPHY_Gain_Lookup_Table_Init */
-static void b43_gphy_gain_lt_init(struct b43_wldev *dev)
-{
-	struct b43_phy *phy = &dev->phy;
-	struct b43_txpower_lo_control *lo = phy->lo_control;
-	u16 nr_written = 0;
-	u16 tmp;
-	u8 rf, bb;
-
-	for (rf = 0; rf < lo->rfatt_list.len; rf++) {
-		for (bb = 0; bb < lo->bbatt_list.len; bb++) {
-			if (nr_written >= 0x40)
-				return;
-			tmp = lo->bbatt_list.list[bb].att;
-			tmp <<= 8;
-			if (phy->radio_rev == 8)
-				tmp |= 0x50;
-			else
-				tmp |= 0x40;
-			tmp |= lo->rfatt_list.list[rf].att;
-			b43_phy_write(dev, 0x3C0 + nr_written, tmp);
-			nr_written++;
-		}
-	}
-}
-
-static void hardware_pctl_init_aphy(struct b43_wldev *dev)
-{
-	//TODO
-}
-
-static void hardware_pctl_init_gphy(struct b43_wldev *dev)
-{
-	struct b43_phy *phy = &dev->phy;
-
-	b43_phy_write(dev, 0x0036, (b43_phy_read(dev, 0x0036) & 0xFFC0)
-		      | (phy->tgt_idle_tssi - phy->cur_idle_tssi));
-	b43_phy_write(dev, 0x0478, (b43_phy_read(dev, 0x0478) & 0xFF00)
-		      | (phy->tgt_idle_tssi - phy->cur_idle_tssi));
-	b43_gphy_tssi_power_lt_init(dev);
-	b43_gphy_gain_lt_init(dev);
-	b43_phy_write(dev, 0x0060, b43_phy_read(dev, 0x0060) & 0xFFBF);
-	b43_phy_write(dev, 0x0014, 0x0000);
-
-	B43_WARN_ON(phy->rev < 6);
-	b43_phy_write(dev, 0x0478, b43_phy_read(dev, 0x0478)
-		      | 0x0800);
-	b43_phy_write(dev, 0x0478, b43_phy_read(dev, 0x0478)
-		      & 0xFEFF);
-	b43_phy_write(dev, 0x0801, b43_phy_read(dev, 0x0801)
-		      & 0xFFBF);
-
-	b43_gphy_dc_lt_init(dev, 1);
-}
-
-/* HardwarePowerControl init for A and G PHY */
-static void b43_hardware_pctl_init(struct b43_wldev *dev)
-{
-	struct b43_phy *phy = &dev->phy;
-
-	if (!b43_has_hardware_pctl(phy)) {
-		/* No hardware power control */
-		b43_hf_write(dev, b43_hf_read(dev) & ~B43_HF_HWPCTL);
-		return;
-	}
-	/* Init the hwpctl related hardware */
-	switch (phy->type) {
-	case B43_PHYTYPE_A:
-		hardware_pctl_init_aphy(dev);
-		break;
-	case B43_PHYTYPE_G:
-		hardware_pctl_init_gphy(dev);
-		break;
-	default:
-		B43_WARN_ON(1);
-	}
-	/* Enable hardware pctl in firmware. */
-	b43_hf_write(dev, b43_hf_read(dev) | B43_HF_HWPCTL);
-}
-
-static void b43_hardware_pctl_early_init(struct b43_wldev *dev)
-{
-	struct b43_phy *phy = &dev->phy;
-
-	if (!b43_has_hardware_pctl(phy)) {
-		b43_phy_write(dev, 0x047A, 0xC111);
-		return;
-	}
-
-	b43_phy_write(dev, 0x0036, b43_phy_read(dev, 0x0036) & 0xFEFF);
-	b43_phy_write(dev, 0x002F, 0x0202);
-	b43_phy_write(dev, 0x047C, b43_phy_read(dev, 0x047C) | 0x0002);
-	b43_phy_write(dev, 0x047A, b43_phy_read(dev, 0x047A) | 0xF000);
-	if (phy->radio_ver == 0x2050 && phy->radio_rev == 8) {
-		b43_phy_write(dev, 0x047A, (b43_phy_read(dev, 0x047A)
-					    & 0xFF0F) | 0x0010);
-		b43_phy_write(dev, 0x005D, b43_phy_read(dev, 0x005D)
-			      | 0x8000);
-		b43_phy_write(dev, 0x004E, (b43_phy_read(dev, 0x004E)
-					    & 0xFFC0) | 0x0010);
-		b43_phy_write(dev, 0x002E, 0xC07F);
-		b43_phy_write(dev, 0x0036, b43_phy_read(dev, 0x0036)
-			      | 0x0400);
-	} else {
-		b43_phy_write(dev, 0x0036, b43_phy_read(dev, 0x0036)
-			      | 0x0200);
-		b43_phy_write(dev, 0x0036, b43_phy_read(dev, 0x0036)
-			      | 0x0400);
-		b43_phy_write(dev, 0x005D, b43_phy_read(dev, 0x005D)
-			      & 0x7FFF);
-		b43_phy_write(dev, 0x004F, b43_phy_read(dev, 0x004F)
-			      & 0xFFFE);
-		b43_phy_write(dev, 0x004E, (b43_phy_read(dev, 0x004E)
-					    & 0xFFC0) | 0x0010);
-		b43_phy_write(dev, 0x002E, 0xC07F);
-		b43_phy_write(dev, 0x047A, (b43_phy_read(dev, 0x047A)
-					    & 0xFF0F) | 0x0010);
-	}
-}
-
-/* Intialize B/G PHY power control
- * as described in http://bcm-specs.sipsolutions.net/InitPowerControl
- */
-static void b43_phy_init_pctl(struct b43_wldev *dev)
-{
-	struct ssb_bus *bus = dev->dev->bus;
-	struct b43_phy *phy = &dev->phy;
-	struct b43_rfatt old_rfatt;
-	struct b43_bbatt old_bbatt;
-	u8 old_tx_control = 0;
-
-	if ((bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM) &&
-	    (bus->boardinfo.type == SSB_BOARD_BU4306))
-		return;
-
-	b43_phy_write(dev, 0x0028, 0x8018);
-
-	/* This does something with the Analog... */
-	b43_write16(dev, B43_MMIO_PHY0, b43_read16(dev, B43_MMIO_PHY0)
-		    & 0xFFDF);
-
-	if (phy->type == B43_PHYTYPE_G && !phy->gmode)
-		return;
-	b43_hardware_pctl_early_init(dev);
-	if (phy->cur_idle_tssi == 0) {
-		if (phy->radio_ver == 0x2050 && phy->analog == 0) {
-			b43_radio_write16(dev, 0x0076,
-					  (b43_radio_read16(dev, 0x0076)
-					   & 0x00F7) | 0x0084);
-		} else {
-			struct b43_rfatt rfatt;
-			struct b43_bbatt bbatt;
-
-			memcpy(&old_rfatt, &phy->rfatt, sizeof(old_rfatt));
-			memcpy(&old_bbatt, &phy->bbatt, sizeof(old_bbatt));
-			old_tx_control = phy->tx_control;
-
-			bbatt.att = 11;
-			if (phy->radio_rev == 8) {
-				rfatt.att = 15;
-				rfatt.with_padmix = 1;
-			} else {
-				rfatt.att = 9;
-				rfatt.with_padmix = 0;
-			}
-			b43_set_txpower_g(dev, &bbatt, &rfatt, 0);
-		}
-		b43_dummy_transmission(dev);
-		phy->cur_idle_tssi = b43_phy_read(dev, B43_PHY_ITSSI);
-		if (B43_DEBUG) {
-			/* Current-Idle-TSSI sanity check. */
-			if (abs(phy->cur_idle_tssi - phy->tgt_idle_tssi) >= 20) {
-				b43dbg(dev->wl,
-				       "!WARNING! Idle-TSSI phy->cur_idle_tssi "
-				       "measuring failed. (cur=%d, tgt=%d). Disabling TX power "
-				       "adjustment.\n", phy->cur_idle_tssi,
-				       phy->tgt_idle_tssi);
-				phy->cur_idle_tssi = 0;
-			}
-		}
-		if (phy->radio_ver == 0x2050 && phy->analog == 0) {
-			b43_radio_write16(dev, 0x0076,
-					  b43_radio_read16(dev, 0x0076)
-					  & 0xFF7B);
-		} else {
-			b43_set_txpower_g(dev, &old_bbatt,
-					  &old_rfatt, old_tx_control);
-		}
-	}
-	b43_hardware_pctl_init(dev);
-	b43_shm_clear_tssi(dev);
-}
-
-static void b43_phy_rssiagc(struct b43_wldev *dev, u8 enable)
-{
-	int i;
-
-	if (dev->phy.rev < 3) {
-		if (enable)
-			for (i = 0; i < B43_TAB_RSSIAGC1_SIZE; i++) {
-				b43_ofdmtab_write16(dev,
-					B43_OFDMTAB_LNAHPFGAIN1, i, 0xFFF8);
-				b43_ofdmtab_write16(dev,
-					B43_OFDMTAB_WRSSI, i, 0xFFF8);
-			}
-		else
-			for (i = 0; i < B43_TAB_RSSIAGC1_SIZE; i++) {
-				b43_ofdmtab_write16(dev,
-					B43_OFDMTAB_LNAHPFGAIN1, i, b43_tab_rssiagc1[i]);
-				b43_ofdmtab_write16(dev,
-					B43_OFDMTAB_WRSSI, i, b43_tab_rssiagc1[i]);
-			}
-	} else {
-		if (enable)
-			for (i = 0; i < B43_TAB_RSSIAGC1_SIZE; i++)
-				b43_ofdmtab_write16(dev,
-					B43_OFDMTAB_WRSSI, i, 0x0820);
-		else
-			for (i = 0; i < B43_TAB_RSSIAGC2_SIZE; i++)
-				b43_ofdmtab_write16(dev,
-					B43_OFDMTAB_WRSSI, i, b43_tab_rssiagc2[i]);
-	}
-}
-
-static void b43_phy_ww(struct b43_wldev *dev)
-{
-	u16 b, curr_s, best_s = 0xFFFF;
-	int i;
-
-	b43_phy_write(dev, B43_PHY_CRS0,
-		b43_phy_read(dev, B43_PHY_CRS0) & ~B43_PHY_CRS0_EN);
-	b43_phy_write(dev, B43_PHY_OFDM(0x1B),
-		b43_phy_read(dev, B43_PHY_OFDM(0x1B)) | 0x1000);
-	b43_phy_write(dev, B43_PHY_OFDM(0x82),
-		(b43_phy_read(dev, B43_PHY_OFDM(0x82)) & 0xF0FF) | 0x0300);
-	b43_radio_write16(dev, 0x0009,
-		b43_radio_read16(dev, 0x0009) | 0x0080);
-	b43_radio_write16(dev, 0x0012,
-		(b43_radio_read16(dev, 0x0012) & 0xFFFC) | 0x0002);
-	b43_wa_initgains(dev);
-	b43_phy_write(dev, B43_PHY_OFDM(0xBA), 0x3ED5);
-	b = b43_phy_read(dev, B43_PHY_PWRDOWN);
-	b43_phy_write(dev, B43_PHY_PWRDOWN, (b & 0xFFF8) | 0x0005);
-	b43_radio_write16(dev, 0x0004,
-		b43_radio_read16(dev, 0x0004) | 0x0004);
-	for (i = 0x10; i <= 0x20; i++) {
-		b43_radio_write16(dev, 0x0013, i);
-		curr_s = b43_phy_read(dev, B43_PHY_OTABLEQ) & 0x00FF;
-		if (!curr_s) {
-			best_s = 0x0000;
-			break;
-		} else if (curr_s >= 0x0080)
-			curr_s = 0x0100 - curr_s;
-		if (curr_s < best_s)
-			best_s = curr_s;
-	}
-	b43_phy_write(dev, B43_PHY_PWRDOWN, b);
-	b43_radio_write16(dev, 0x0004,
-		b43_radio_read16(dev, 0x0004) & 0xFFFB);
-	b43_radio_write16(dev, 0x0013, best_s);
-	b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1_R1, 0, 0xFFEC);
-	b43_phy_write(dev, B43_PHY_OFDM(0xB7), 0x1E80);
-	b43_phy_write(dev, B43_PHY_OFDM(0xB6), 0x1C00);
-	b43_phy_write(dev, B43_PHY_OFDM(0xB5), 0x0EC0);
-	b43_phy_write(dev, B43_PHY_OFDM(0xB2), 0x00C0);
-	b43_phy_write(dev, B43_PHY_OFDM(0xB9), 0x1FFF);
-	b43_phy_write(dev, B43_PHY_OFDM(0xBB),
-		(b43_phy_read(dev, B43_PHY_OFDM(0xBB)) & 0xF000) | 0x0053);
-	b43_phy_write(dev, B43_PHY_OFDM61,
-		(b43_phy_read(dev, B43_PHY_OFDM61) & 0xFE1F) | 0x0120);
-	b43_phy_write(dev, B43_PHY_OFDM(0x13),
-		(b43_phy_read(dev, B43_PHY_OFDM(0x13)) & 0x0FFF) | 0x3000);
-	b43_phy_write(dev, B43_PHY_OFDM(0x14),
-		(b43_phy_read(dev, B43_PHY_OFDM(0x14)) & 0x0FFF) | 0x3000);
-	b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, 6, 0x0017);
-	for (i = 0; i < 6; i++)
-		b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, i, 0x000F);
-	b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, 0x0D, 0x000E);
-	b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, 0x0E, 0x0011);
-	b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, 0x0F, 0x0013);
-	b43_phy_write(dev, B43_PHY_OFDM(0x33), 0x5030);
-	b43_phy_write(dev, B43_PHY_CRS0,
-		b43_phy_read(dev, B43_PHY_CRS0) | B43_PHY_CRS0_EN);
-}
-
-/* Initialize APHY. This is also called for the GPHY in some cases. */
-static void b43_phy_inita(struct b43_wldev *dev)
-{
-	struct ssb_bus *bus = dev->dev->bus;
-	struct b43_phy *phy = &dev->phy;
-
-	might_sleep();
-
-	if (phy->rev >= 6) {
-		if (phy->type == B43_PHYTYPE_A)
-			b43_phy_write(dev, B43_PHY_OFDM(0x1B),
-				b43_phy_read(dev, B43_PHY_OFDM(0x1B)) & ~0x1000);
-		if (b43_phy_read(dev, B43_PHY_ENCORE) & B43_PHY_ENCORE_EN)
-			b43_phy_write(dev, B43_PHY_ENCORE,
-				b43_phy_read(dev, B43_PHY_ENCORE) | 0x0010);
-		else
-			b43_phy_write(dev, B43_PHY_ENCORE,
-				b43_phy_read(dev, B43_PHY_ENCORE) & ~0x1010);
-	}
-
-	b43_wa_all(dev);
-
-	if (phy->type == B43_PHYTYPE_A) {
-		if (phy->gmode && (phy->rev < 3))
-			b43_phy_write(dev, 0x0034,
-				b43_phy_read(dev, 0x0034) | 0x0001);
-		b43_phy_rssiagc(dev, 0);
-
-		b43_phy_write(dev, B43_PHY_CRS0,
-			b43_phy_read(dev, B43_PHY_CRS0) | B43_PHY_CRS0_EN);
-
-		b43_radio_init2060(dev);
-
-		if ((bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM) &&
-		    ((bus->boardinfo.type == SSB_BOARD_BU4306) ||
-		     (bus->boardinfo.type == SSB_BOARD_BU4309))) {
-			; //TODO: A PHY LO
-		}
-
-		if (phy->rev >= 3)
-			b43_phy_ww(dev);
-
-		hardware_pctl_init_aphy(dev);
-
-		//TODO: radar detection
-	}
-
-	if ((phy->type == B43_PHYTYPE_G) &&
-	    (dev->dev->bus->sprom.boardflags_lo & B43_BFL_PACTRL)) {
-		b43_phy_write(dev, B43_PHY_OFDM(0x6E),
-				  (b43_phy_read(dev, B43_PHY_OFDM(0x6E))
-				   & 0xE000) | 0x3CF);
-	}
-}
-
-static void b43_phy_initb5(struct b43_wldev *dev)
-{
-	struct ssb_bus *bus = dev->dev->bus;
-	struct b43_phy *phy = &dev->phy;
-	u16 offset, value;
-	u8 old_channel;
-
-	if (phy->analog == 1) {
-		b43_radio_write16(dev, 0x007A, b43_radio_read16(dev, 0x007A)
-				  | 0x0050);
-	}
-	if ((bus->boardinfo.vendor != SSB_BOARDVENDOR_BCM) &&
-	    (bus->boardinfo.type != SSB_BOARD_BU4306)) {
-		value = 0x2120;
-		for (offset = 0x00A8; offset < 0x00C7; offset++) {
-			b43_phy_write(dev, offset, value);
-			value += 0x202;
-		}
-	}
-	b43_phy_write(dev, 0x0035, (b43_phy_read(dev, 0x0035) & 0xF0FF)
-		      | 0x0700);
-	if (phy->radio_ver == 0x2050)
-		b43_phy_write(dev, 0x0038, 0x0667);
-
-	if (phy->gmode || phy->rev >= 2) {
-		if (phy->radio_ver == 0x2050) {
-			b43_radio_write16(dev, 0x007A,
-					  b43_radio_read16(dev, 0x007A)
-					  | 0x0020);
-			b43_radio_write16(dev, 0x0051,
-					  b43_radio_read16(dev, 0x0051)
-					  | 0x0004);
-		}
-		b43_write16(dev, B43_MMIO_PHY_RADIO, 0x0000);
-
-		b43_phy_write(dev, 0x0802, b43_phy_read(dev, 0x0802) | 0x0100);
-		b43_phy_write(dev, 0x042B, b43_phy_read(dev, 0x042B) | 0x2000);
-
-		b43_phy_write(dev, 0x001C, 0x186A);
-
-		b43_phy_write(dev, 0x0013,
-			      (b43_phy_read(dev, 0x0013) & 0x00FF) | 0x1900);
-		b43_phy_write(dev, 0x0035,
-			      (b43_phy_read(dev, 0x0035) & 0xFFC0) | 0x0064);
-		b43_phy_write(dev, 0x005D,
-			      (b43_phy_read(dev, 0x005D) & 0xFF80) | 0x000A);
-	}
-
-	if (dev->bad_frames_preempt) {
-		b43_phy_write(dev, B43_PHY_RADIO_BITFIELD,
-			      b43_phy_read(dev,
-					   B43_PHY_RADIO_BITFIELD) | (1 << 11));
-	}
-
-	if (phy->analog == 1) {
-		b43_phy_write(dev, 0x0026, 0xCE00);
-		b43_phy_write(dev, 0x0021, 0x3763);
-		b43_phy_write(dev, 0x0022, 0x1BC3);
-		b43_phy_write(dev, 0x0023, 0x06F9);
-		b43_phy_write(dev, 0x0024, 0x037E);
-	} else
-		b43_phy_write(dev, 0x0026, 0xCC00);
-	b43_phy_write(dev, 0x0030, 0x00C6);
-	b43_write16(dev, 0x03EC, 0x3F22);
-
-	if (phy->analog == 1)
-		b43_phy_write(dev, 0x0020, 0x3E1C);
-	else
-		b43_phy_write(dev, 0x0020, 0x301C);
-
-	if (phy->analog == 0)
-		b43_write16(dev, 0x03E4, 0x3000);
-
-	old_channel = phy->channel;
-	/* Force to channel 7, even if not supported. */
-	b43_radio_selectchannel(dev, 7, 0);
-
-	if (phy->radio_ver != 0x2050) {
-		b43_radio_write16(dev, 0x0075, 0x0080);
-		b43_radio_write16(dev, 0x0079, 0x0081);
-	}
-
-	b43_radio_write16(dev, 0x0050, 0x0020);
-	b43_radio_write16(dev, 0x0050, 0x0023);
-
-	if (phy->radio_ver == 0x2050) {
-		b43_radio_write16(dev, 0x0050, 0x0020);
-		b43_radio_write16(dev, 0x005A, 0x0070);
-	}
-
-	b43_radio_write16(dev, 0x005B, 0x007B);
-	b43_radio_write16(dev, 0x005C, 0x00B0);
-
-	b43_radio_write16(dev, 0x007A, b43_radio_read16(dev, 0x007A) | 0x0007);
-
-	b43_radio_selectchannel(dev, old_channel, 0);
-
-	b43_phy_write(dev, 0x0014, 0x0080);
-	b43_phy_write(dev, 0x0032, 0x00CA);
-	b43_phy_write(dev, 0x002A, 0x88A3);
-
-	b43_set_txpower_g(dev, &phy->bbatt, &phy->rfatt, phy->tx_control);
-
-	if (phy->radio_ver == 0x2050)
-		b43_radio_write16(dev, 0x005D, 0x000D);
-
-	b43_write16(dev, 0x03E4, (b43_read16(dev, 0x03E4) & 0xFFC0) | 0x0004);
-}
-
-static void b43_phy_initb6(struct b43_wldev *dev)
-{
-	struct b43_phy *phy = &dev->phy;
-	u16 offset, val;
-	u8 old_channel;
-
-	b43_phy_write(dev, 0x003E, 0x817A);
-	b43_radio_write16(dev, 0x007A,
-			  (b43_radio_read16(dev, 0x007A) | 0x0058));
-	if (phy->radio_rev == 4 || phy->radio_rev == 5) {
-		b43_radio_write16(dev, 0x51, 0x37);
-		b43_radio_write16(dev, 0x52, 0x70);
-		b43_radio_write16(dev, 0x53, 0xB3);
-		b43_radio_write16(dev, 0x54, 0x9B);
-		b43_radio_write16(dev, 0x5A, 0x88);
-		b43_radio_write16(dev, 0x5B, 0x88);
-		b43_radio_write16(dev, 0x5D, 0x88);
-		b43_radio_write16(dev, 0x5E, 0x88);
-		b43_radio_write16(dev, 0x7D, 0x88);
-		b43_hf_write(dev, b43_hf_read(dev)
-			     | B43_HF_TSSIRPSMW);
-	}
-	B43_WARN_ON(phy->radio_rev == 6 || phy->radio_rev == 7);	/* We had code for these revs here... */
-	if (phy->radio_rev == 8) {
-		b43_radio_write16(dev, 0x51, 0);
-		b43_radio_write16(dev, 0x52, 0x40);
-		b43_radio_write16(dev, 0x53, 0xB7);
-		b43_radio_write16(dev, 0x54, 0x98);
-		b43_radio_write16(dev, 0x5A, 0x88);
-		b43_radio_write16(dev, 0x5B, 0x6B);
-		b43_radio_write16(dev, 0x5C, 0x0F);
-		if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_ALTIQ) {
-			b43_radio_write16(dev, 0x5D, 0xFA);
-			b43_radio_write16(dev, 0x5E, 0xD8);
-		} else {
-			b43_radio_write16(dev, 0x5D, 0xF5);
-			b43_radio_write16(dev, 0x5E, 0xB8);
-		}
-		b43_radio_write16(dev, 0x0073, 0x0003);
-		b43_radio_write16(dev, 0x007D, 0x00A8);
-		b43_radio_write16(dev, 0x007C, 0x0001);
-		b43_radio_write16(dev, 0x007E, 0x0008);
-	}
-	val = 0x1E1F;
-	for (offset = 0x0088; offset < 0x0098; offset++) {
-		b43_phy_write(dev, offset, val);
-		val -= 0x0202;
-	}
-	val = 0x3E3F;
-	for (offset = 0x0098; offset < 0x00A8; offset++) {
-		b43_phy_write(dev, offset, val);
-		val -= 0x0202;
-	}
-	val = 0x2120;
-	for (offset = 0x00A8; offset < 0x00C8; offset++) {
-		b43_phy_write(dev, offset, (val & 0x3F3F));
-		val += 0x0202;
-	}
-	if (phy->type == B43_PHYTYPE_G) {
-		b43_radio_write16(dev, 0x007A,
-				  b43_radio_read16(dev, 0x007A) | 0x0020);
-		b43_radio_write16(dev, 0x0051,
-				  b43_radio_read16(dev, 0x0051) | 0x0004);
-		b43_phy_write(dev, 0x0802, b43_phy_read(dev, 0x0802) | 0x0100);
-		b43_phy_write(dev, 0x042B, b43_phy_read(dev, 0x042B) | 0x2000);
-		b43_phy_write(dev, 0x5B, 0);
-		b43_phy_write(dev, 0x5C, 0);
-	}
-
-	old_channel = phy->channel;
-	if (old_channel >= 8)
-		b43_radio_selectchannel(dev, 1, 0);
-	else
-		b43_radio_selectchannel(dev, 13, 0);
-
-	b43_radio_write16(dev, 0x0050, 0x0020);
-	b43_radio_write16(dev, 0x0050, 0x0023);
-	udelay(40);
-	if (phy->radio_rev < 6 || phy->radio_rev == 8) {
-		b43_radio_write16(dev, 0x7C, (b43_radio_read16(dev, 0x7C)
-					      | 0x0002));
-		b43_radio_write16(dev, 0x50, 0x20);
-	}
-	if (phy->radio_rev <= 2) {
-		b43_radio_write16(dev, 0x7C, 0x20);
-		b43_radio_write16(dev, 0x5A, 0x70);
-		b43_radio_write16(dev, 0x5B, 0x7B);
-		b43_radio_write16(dev, 0x5C, 0xB0);
-	}
-	b43_radio_write16(dev, 0x007A,
-			  (b43_radio_read16(dev, 0x007A) & 0x00F8) | 0x0007);
-
-	b43_radio_selectchannel(dev, old_channel, 0);
-
-	b43_phy_write(dev, 0x0014, 0x0200);
-	if (phy->radio_rev >= 6)
-		b43_phy_write(dev, 0x2A, 0x88C2);
-	else
-		b43_phy_write(dev, 0x2A, 0x8AC0);
-	b43_phy_write(dev, 0x0038, 0x0668);
-	b43_set_txpower_g(dev, &phy->bbatt, &phy->rfatt, phy->tx_control);
-	if (phy->radio_rev <= 5) {
-		b43_phy_write(dev, 0x5D, (b43_phy_read(dev, 0x5D)
-					  & 0xFF80) | 0x0003);
-	}
-	if (phy->radio_rev <= 2)
-		b43_radio_write16(dev, 0x005D, 0x000D);
-
-	if (phy->analog == 4) {
-		b43_write16(dev, 0x3E4, 9);
-		b43_phy_write(dev, 0x61, b43_phy_read(dev, 0x61)
-			      & 0x0FFF);
-	} else {
-		b43_phy_write(dev, 0x0002, (b43_phy_read(dev, 0x0002) & 0xFFC0)
-			      | 0x0004);
-	}
-	if (phy->type == B43_PHYTYPE_B)
-		B43_WARN_ON(1);
-	else if (phy->type == B43_PHYTYPE_G)
-		b43_write16(dev, 0x03E6, 0x0);
-}
-
-static void b43_calc_loopback_gain(struct b43_wldev *dev)
-{
-	struct b43_phy *phy = &dev->phy;
-	u16 backup_phy[16] = { 0 };
-	u16 backup_radio[3];
-	u16 backup_bband;
-	u16 i, j, loop_i_max;
-	u16 trsw_rx;
-	u16 loop1_outer_done, loop1_inner_done;
-
-	backup_phy[0] = b43_phy_read(dev, B43_PHY_CRS0);
-	backup_phy[1] = b43_phy_read(dev, B43_PHY_CCKBBANDCFG);
-	backup_phy[2] = b43_phy_read(dev, B43_PHY_RFOVER);
-	backup_phy[3] = b43_phy_read(dev, B43_PHY_RFOVERVAL);
-	if (phy->rev != 1) {	/* Not in specs, but needed to prevent PPC machine check */
-		backup_phy[4] = b43_phy_read(dev, B43_PHY_ANALOGOVER);
-		backup_phy[5] = b43_phy_read(dev, B43_PHY_ANALOGOVERVAL);
-	}
-	backup_phy[6] = b43_phy_read(dev, B43_PHY_CCK(0x5A));
-	backup_phy[7] = b43_phy_read(dev, B43_PHY_CCK(0x59));
-	backup_phy[8] = b43_phy_read(dev, B43_PHY_CCK(0x58));
-	backup_phy[9] = b43_phy_read(dev, B43_PHY_CCK(0x0A));
-	backup_phy[10] = b43_phy_read(dev, B43_PHY_CCK(0x03));
-	backup_phy[11] = b43_phy_read(dev, B43_PHY_LO_MASK);
-	backup_phy[12] = b43_phy_read(dev, B43_PHY_LO_CTL);
-	backup_phy[13] = b43_phy_read(dev, B43_PHY_CCK(0x2B));
-	backup_phy[14] = b43_phy_read(dev, B43_PHY_PGACTL);
-	backup_phy[15] = b43_phy_read(dev, B43_PHY_LO_LEAKAGE);
-	backup_bband = phy->bbatt.att;
-	backup_radio[0] = b43_radio_read16(dev, 0x52);
-	backup_radio[1] = b43_radio_read16(dev, 0x43);
-	backup_radio[2] = b43_radio_read16(dev, 0x7A);
-
-	b43_phy_write(dev, B43_PHY_CRS0,
-		      b43_phy_read(dev, B43_PHY_CRS0) & 0x3FFF);
-	b43_phy_write(dev, B43_PHY_CCKBBANDCFG,
-		      b43_phy_read(dev, B43_PHY_CCKBBANDCFG) | 0x8000);
-	b43_phy_write(dev, B43_PHY_RFOVER,
-		      b43_phy_read(dev, B43_PHY_RFOVER) | 0x0002);
-	b43_phy_write(dev, B43_PHY_RFOVERVAL,
-		      b43_phy_read(dev, B43_PHY_RFOVERVAL) & 0xFFFD);
-	b43_phy_write(dev, B43_PHY_RFOVER,
-		      b43_phy_read(dev, B43_PHY_RFOVER) | 0x0001);
-	b43_phy_write(dev, B43_PHY_RFOVERVAL,
-		      b43_phy_read(dev, B43_PHY_RFOVERVAL) & 0xFFFE);
-	if (phy->rev != 1) {	/* Not in specs, but needed to prevent PPC machine check */
-		b43_phy_write(dev, B43_PHY_ANALOGOVER,
-			      b43_phy_read(dev, B43_PHY_ANALOGOVER) | 0x0001);
-		b43_phy_write(dev, B43_PHY_ANALOGOVERVAL,
-			      b43_phy_read(dev,
-					   B43_PHY_ANALOGOVERVAL) & 0xFFFE);
-		b43_phy_write(dev, B43_PHY_ANALOGOVER,
-			      b43_phy_read(dev, B43_PHY_ANALOGOVER) | 0x0002);
-		b43_phy_write(dev, B43_PHY_ANALOGOVERVAL,
-			      b43_phy_read(dev,
-					   B43_PHY_ANALOGOVERVAL) & 0xFFFD);
-	}
-	b43_phy_write(dev, B43_PHY_RFOVER,
-		      b43_phy_read(dev, B43_PHY_RFOVER) | 0x000C);
-	b43_phy_write(dev, B43_PHY_RFOVERVAL,
-		      b43_phy_read(dev, B43_PHY_RFOVERVAL) | 0x000C);
-	b43_phy_write(dev, B43_PHY_RFOVER,
-		      b43_phy_read(dev, B43_PHY_RFOVER) | 0x0030);
-	b43_phy_write(dev, B43_PHY_RFOVERVAL,
-		      (b43_phy_read(dev, B43_PHY_RFOVERVAL)
-		       & 0xFFCF) | 0x10);
-
-	b43_phy_write(dev, B43_PHY_CCK(0x5A), 0x0780);
-	b43_phy_write(dev, B43_PHY_CCK(0x59), 0xC810);
-	b43_phy_write(dev, B43_PHY_CCK(0x58), 0x000D);
-
-	b43_phy_write(dev, B43_PHY_CCK(0x0A),
-		      b43_phy_read(dev, B43_PHY_CCK(0x0A)) | 0x2000);
-	if (phy->rev != 1) {	/* Not in specs, but needed to prevent PPC machine check */
-		b43_phy_write(dev, B43_PHY_ANALOGOVER,
-			      b43_phy_read(dev, B43_PHY_ANALOGOVER) | 0x0004);
-		b43_phy_write(dev, B43_PHY_ANALOGOVERVAL,
-			      b43_phy_read(dev,
-					   B43_PHY_ANALOGOVERVAL) & 0xFFFB);
-	}
-	b43_phy_write(dev, B43_PHY_CCK(0x03),
-		      (b43_phy_read(dev, B43_PHY_CCK(0x03))
-		       & 0xFF9F) | 0x40);
-
-	if (phy->radio_rev == 8) {
-		b43_radio_write16(dev, 0x43, 0x000F);
-	} else {
-		b43_radio_write16(dev, 0x52, 0);
-		b43_radio_write16(dev, 0x43, (b43_radio_read16(dev, 0x43)
-					      & 0xFFF0) | 0x9);
-	}
-	b43_phy_set_baseband_attenuation(dev, 11);
-
-	if (phy->rev >= 3)
-		b43_phy_write(dev, B43_PHY_LO_MASK, 0xC020);
-	else
-		b43_phy_write(dev, B43_PHY_LO_MASK, 0x8020);
-	b43_phy_write(dev, B43_PHY_LO_CTL, 0);
-
-	b43_phy_write(dev, B43_PHY_CCK(0x2B),
-		      (b43_phy_read(dev, B43_PHY_CCK(0x2B))
-		       & 0xFFC0) | 0x01);
-	b43_phy_write(dev, B43_PHY_CCK(0x2B),
-		      (b43_phy_read(dev, B43_PHY_CCK(0x2B))
-		       & 0xC0FF) | 0x800);
-
-	b43_phy_write(dev, B43_PHY_RFOVER,
-		      b43_phy_read(dev, B43_PHY_RFOVER) | 0x0100);
-	b43_phy_write(dev, B43_PHY_RFOVERVAL,
-		      b43_phy_read(dev, B43_PHY_RFOVERVAL) & 0xCFFF);
-
-	if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_EXTLNA) {
-		if (phy->rev >= 7) {
-			b43_phy_write(dev, B43_PHY_RFOVER,
-				      b43_phy_read(dev, B43_PHY_RFOVER)
-				      | 0x0800);
-			b43_phy_write(dev, B43_PHY_RFOVERVAL,
-				      b43_phy_read(dev, B43_PHY_RFOVERVAL)
-				      | 0x8000);
-		}
-	}
-	b43_radio_write16(dev, 0x7A, b43_radio_read16(dev, 0x7A)
-			  & 0x00F7);
-
-	j = 0;
-	loop_i_max = (phy->radio_rev == 8) ? 15 : 9;
-	for (i = 0; i < loop_i_max; i++) {
-		for (j = 0; j < 16; j++) {
-			b43_radio_write16(dev, 0x43, i);
-			b43_phy_write(dev, B43_PHY_RFOVERVAL,
-				      (b43_phy_read(dev, B43_PHY_RFOVERVAL)
-				       & 0xF0FF) | (j << 8));
-			b43_phy_write(dev, B43_PHY_PGACTL,
-				      (b43_phy_read(dev, B43_PHY_PGACTL)
-				       & 0x0FFF) | 0xA000);
-			b43_phy_write(dev, B43_PHY_PGACTL,
-				      b43_phy_read(dev, B43_PHY_PGACTL)
-				      | 0xF000);
-			udelay(20);
-			if (b43_phy_read(dev, B43_PHY_LO_LEAKAGE) >= 0xDFC)
-				goto exit_loop1;
-		}
-	}
-      exit_loop1:
-	loop1_outer_done = i;
-	loop1_inner_done = j;
-	if (j >= 8) {
-		b43_phy_write(dev, B43_PHY_RFOVERVAL,
-			      b43_phy_read(dev, B43_PHY_RFOVERVAL)
-			      | 0x30);
-		trsw_rx = 0x1B;
-		for (j = j - 8; j < 16; j++) {
-			b43_phy_write(dev, B43_PHY_RFOVERVAL,
-				      (b43_phy_read(dev, B43_PHY_RFOVERVAL)
-				       & 0xF0FF) | (j << 8));
-			b43_phy_write(dev, B43_PHY_PGACTL,
-				      (b43_phy_read(dev, B43_PHY_PGACTL)
-				       & 0x0FFF) | 0xA000);
-			b43_phy_write(dev, B43_PHY_PGACTL,
-				      b43_phy_read(dev, B43_PHY_PGACTL)
-				      | 0xF000);
-			udelay(20);
-			trsw_rx -= 3;
-			if (b43_phy_read(dev, B43_PHY_LO_LEAKAGE) >= 0xDFC)
-				goto exit_loop2;
-		}
-	} else
-		trsw_rx = 0x18;
-      exit_loop2:
-
-	if (phy->rev != 1) {	/* Not in specs, but needed to prevent PPC machine check */
-		b43_phy_write(dev, B43_PHY_ANALOGOVER, backup_phy[4]);
-		b43_phy_write(dev, B43_PHY_ANALOGOVERVAL, backup_phy[5]);
-	}
-	b43_phy_write(dev, B43_PHY_CCK(0x5A), backup_phy[6]);
-	b43_phy_write(dev, B43_PHY_CCK(0x59), backup_phy[7]);
-	b43_phy_write(dev, B43_PHY_CCK(0x58), backup_phy[8]);
-	b43_phy_write(dev, B43_PHY_CCK(0x0A), backup_phy[9]);
-	b43_phy_write(dev, B43_PHY_CCK(0x03), backup_phy[10]);
-	b43_phy_write(dev, B43_PHY_LO_MASK, backup_phy[11]);
-	b43_phy_write(dev, B43_PHY_LO_CTL, backup_phy[12]);
-	b43_phy_write(dev, B43_PHY_CCK(0x2B), backup_phy[13]);
-	b43_phy_write(dev, B43_PHY_PGACTL, backup_phy[14]);
-
-	b43_phy_set_baseband_attenuation(dev, backup_bband);
-
-	b43_radio_write16(dev, 0x52, backup_radio[0]);
-	b43_radio_write16(dev, 0x43, backup_radio[1]);
-	b43_radio_write16(dev, 0x7A, backup_radio[2]);
-
-	b43_phy_write(dev, B43_PHY_RFOVER, backup_phy[2] | 0x0003);
-	udelay(10);
-	b43_phy_write(dev, B43_PHY_RFOVER, backup_phy[2]);
-	b43_phy_write(dev, B43_PHY_RFOVERVAL, backup_phy[3]);
-	b43_phy_write(dev, B43_PHY_CRS0, backup_phy[0]);
-	b43_phy_write(dev, B43_PHY_CCKBBANDCFG, backup_phy[1]);
-
-	phy->max_lb_gain =
-	    ((loop1_inner_done * 6) - (loop1_outer_done * 4)) - 11;
-	phy->trsw_rx_gain = trsw_rx * 2;
-}
-
-static void b43_phy_initg(struct b43_wldev *dev)
-{
-	struct b43_phy *phy = &dev->phy;
-	u16 tmp;
-
-	if (phy->rev == 1)
-		b43_phy_initb5(dev);
-	else
-		b43_phy_initb6(dev);
-
-	if (phy->rev >= 2 || phy->gmode)
-		b43_phy_inita(dev);
-
-	if (phy->rev >= 2) {
-		b43_phy_write(dev, B43_PHY_ANALOGOVER, 0);
-		b43_phy_write(dev, B43_PHY_ANALOGOVERVAL, 0);
-	}
-	if (phy->rev == 2) {
-		b43_phy_write(dev, B43_PHY_RFOVER, 0);
-		b43_phy_write(dev, B43_PHY_PGACTL, 0xC0);
-	}
-	if (phy->rev > 5) {
-		b43_phy_write(dev, B43_PHY_RFOVER, 0x400);
-		b43_phy_write(dev, B43_PHY_PGACTL, 0xC0);
-	}
-	if (phy->gmode || phy->rev >= 2) {
-		tmp = b43_phy_read(dev, B43_PHY_VERSION_OFDM);
-		tmp &= B43_PHYVER_VERSION;
-		if (tmp == 3 || tmp == 5) {
-			b43_phy_write(dev, B43_PHY_OFDM(0xC2), 0x1816);
-			b43_phy_write(dev, B43_PHY_OFDM(0xC3), 0x8006);
-		}
-		if (tmp == 5) {
-			b43_phy_write(dev, B43_PHY_OFDM(0xCC),
-				      (b43_phy_read(dev, B43_PHY_OFDM(0xCC))
-				       & 0x00FF) | 0x1F00);
-		}
-	}
-	if ((phy->rev <= 2 && phy->gmode) || phy->rev >= 2)
-		b43_phy_write(dev, B43_PHY_OFDM(0x7E), 0x78);
-	if (phy->radio_rev == 8) {
-		b43_phy_write(dev, B43_PHY_EXTG(0x01),
-			      b43_phy_read(dev, B43_PHY_EXTG(0x01))
-			      | 0x80);
-		b43_phy_write(dev, B43_PHY_OFDM(0x3E),
-			      b43_phy_read(dev, B43_PHY_OFDM(0x3E))
-			      | 0x4);
-	}
-	if (has_loopback_gain(phy))
-		b43_calc_loopback_gain(dev);
-
-	if (phy->radio_rev != 8) {
-		if (phy->initval == 0xFFFF)
-			phy->initval = b43_radio_init2050(dev);
-		else
-			b43_radio_write16(dev, 0x0078, phy->initval);
-	}
-	b43_lo_g_init(dev);
-	if (has_tx_magnification(phy)) {
-		b43_radio_write16(dev, 0x52,
-				  (b43_radio_read16(dev, 0x52) & 0xFF00)
-				  | phy->lo_control->tx_bias | phy->
-				  lo_control->tx_magn);
-	} else {
-		b43_radio_write16(dev, 0x52,
-				  (b43_radio_read16(dev, 0x52) & 0xFFF0)
-				  | phy->lo_control->tx_bias);
-	}
-	if (phy->rev >= 6) {
-		b43_phy_write(dev, B43_PHY_CCK(0x36),
-			      (b43_phy_read(dev, B43_PHY_CCK(0x36))
-			       & 0x0FFF) | (phy->lo_control->
-					    tx_bias << 12));
-	}
-	if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_PACTRL)
-		b43_phy_write(dev, B43_PHY_CCK(0x2E), 0x8075);
-	else
-		b43_phy_write(dev, B43_PHY_CCK(0x2E), 0x807F);
-	if (phy->rev < 2)
-		b43_phy_write(dev, B43_PHY_CCK(0x2F), 0x101);
-	else
-		b43_phy_write(dev, B43_PHY_CCK(0x2F), 0x202);
-	if (phy->gmode || phy->rev >= 2) {
-		b43_lo_g_adjust(dev);
-		b43_phy_write(dev, B43_PHY_LO_MASK, 0x8078);
-	}
-
-	if (!(dev->dev->bus->sprom.boardflags_lo & B43_BFL_RSSI)) {
-		/* The specs state to update the NRSSI LT with
-		 * the value 0x7FFFFFFF here. I think that is some weird
-		 * compiler optimization in the original driver.
-		 * Essentially, what we do here is resetting all NRSSI LT
-		 * entries to -32 (see the clamp_val() in nrssi_hw_update())
-		 */
-		b43_nrssi_hw_update(dev, 0xFFFF);	//FIXME?
-		b43_calc_nrssi_threshold(dev);
-	} else if (phy->gmode || phy->rev >= 2) {
-		if (phy->nrssi[0] == -1000) {
-			B43_WARN_ON(phy->nrssi[1] != -1000);
-			b43_calc_nrssi_slope(dev);
-		} else
-			b43_calc_nrssi_threshold(dev);
-	}
-	if (phy->radio_rev == 8)
-		b43_phy_write(dev, B43_PHY_EXTG(0x05), 0x3230);
-	b43_phy_init_pctl(dev);
-	/* FIXME: The spec says in the following if, the 0 should be replaced
-	   'if OFDM may not be used in the current locale'
-	   but OFDM is legal everywhere */
-	if ((dev->dev->bus->chip_id == 0x4306
-	     && dev->dev->bus->chip_package == 2) || 0) {
-		b43_phy_write(dev, B43_PHY_CRS0, b43_phy_read(dev, B43_PHY_CRS0)
-			      & 0xBFFF);
-		b43_phy_write(dev, B43_PHY_OFDM(0xC3),
-			      b43_phy_read(dev, B43_PHY_OFDM(0xC3))
-			      & 0x7FFF);
-	}
-}
-
-/* Set the baseband attenuation value on chip. */
-void b43_phy_set_baseband_attenuation(struct b43_wldev *dev,
-				      u16 baseband_attenuation)
-{
-	struct b43_phy *phy = &dev->phy;
-
-	if (phy->analog == 0) {
-		b43_write16(dev, B43_MMIO_PHY0, (b43_read16(dev, B43_MMIO_PHY0)
-						 & 0xFFF0) |
-			    baseband_attenuation);
-	} else if (phy->analog > 1) {
-		b43_phy_write(dev, B43_PHY_DACCTL,
-			      (b43_phy_read(dev, B43_PHY_DACCTL)
-			       & 0xFFC3) | (baseband_attenuation << 2));
-	} else {
-		b43_phy_write(dev, B43_PHY_DACCTL,
-			      (b43_phy_read(dev, B43_PHY_DACCTL)
-			       & 0xFF87) | (baseband_attenuation << 3));
-	}
-}
-
-/* http://bcm-specs.sipsolutions.net/EstimatePowerOut
- * This function converts a TSSI value to dBm in Q5.2
- */
-static s8 b43_phy_estimate_power_out(struct b43_wldev *dev, s8 tssi)
-{
-	struct b43_phy *phy = &dev->phy;
-	s8 dbm = 0;
-	s32 tmp;
-
-	tmp = (phy->tgt_idle_tssi - phy->cur_idle_tssi + tssi);
-
-	switch (phy->type) {
-	case B43_PHYTYPE_A:
-		tmp += 0x80;
-		tmp = clamp_val(tmp, 0x00, 0xFF);
-		dbm = phy->tssi2dbm[tmp];
-		//TODO: There's a FIXME on the specs
-		break;
-	case B43_PHYTYPE_B:
-	case B43_PHYTYPE_G:
-		tmp = clamp_val(tmp, 0x00, 0x3F);
-		dbm = phy->tssi2dbm[tmp];
-		break;
-	default:
-		B43_WARN_ON(1);
-	}
-
-	return dbm;
-}
-
-void b43_put_attenuation_into_ranges(struct b43_wldev *dev,
-				     int *_bbatt, int *_rfatt)
-{
-	int rfatt = *_rfatt;
-	int bbatt = *_bbatt;
-	struct b43_txpower_lo_control *lo = dev->phy.lo_control;
-
-	/* Get baseband and radio attenuation values into their permitted ranges.
-	 * Radio attenuation affects power level 4 times as much as baseband. */
-
-	/* Range constants */
-	const int rf_min = lo->rfatt_list.min_val;
-	const int rf_max = lo->rfatt_list.max_val;
-	const int bb_min = lo->bbatt_list.min_val;
-	const int bb_max = lo->bbatt_list.max_val;
-
-	while (1) {
-		if (rfatt > rf_max && bbatt > bb_max - 4)
-			break;	/* Can not get it into ranges */
-		if (rfatt < rf_min && bbatt < bb_min + 4)
-			break;	/* Can not get it into ranges */
-		if (bbatt > bb_max && rfatt > rf_max - 1)
-			break;	/* Can not get it into ranges */
-		if (bbatt < bb_min && rfatt < rf_min + 1)
-			break;	/* Can not get it into ranges */
-
-		if (bbatt > bb_max) {
-			bbatt -= 4;
-			rfatt += 1;
-			continue;
-		}
-		if (bbatt < bb_min) {
-			bbatt += 4;
-			rfatt -= 1;
-			continue;
-		}
-		if (rfatt > rf_max) {
-			rfatt -= 1;
-			bbatt += 4;
-			continue;
-		}
-		if (rfatt < rf_min) {
-			rfatt += 1;
-			bbatt -= 4;
-			continue;
-		}
-		break;
-	}
-
-	*_rfatt = clamp_val(rfatt, rf_min, rf_max);
-	*_bbatt = clamp_val(bbatt, bb_min, bb_max);
-}
-
-/* http://bcm-specs.sipsolutions.net/RecalculateTransmissionPower */
-void b43_phy_xmitpower(struct b43_wldev *dev)
-{
-	struct ssb_bus *bus = dev->dev->bus;
-	struct b43_phy *phy = &dev->phy;
-
-	if (phy->cur_idle_tssi == 0)
-		return;
-	if ((bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM) &&
-	    (bus->boardinfo.type == SSB_BOARD_BU4306))
-		return;
-#ifdef CONFIG_B43_DEBUG
-	if (phy->manual_txpower_control)
-		return;
-#endif
-
-	switch (phy->type) {
-	case B43_PHYTYPE_A:{
-
-			//TODO: Nothing for A PHYs yet :-/
-
-			break;
-		}
-	case B43_PHYTYPE_B:
-	case B43_PHYTYPE_G:{
-			u16 tmp;
-			s8 v0, v1, v2, v3;
-			s8 average;
-			int max_pwr;
-			int desired_pwr, estimated_pwr, pwr_adjust;
-			int rfatt_delta, bbatt_delta;
-			int rfatt, bbatt;
-			u8 tx_control;
-
-			tmp = b43_shm_read16(dev, B43_SHM_SHARED, 0x0058);
-			v0 = (s8) (tmp & 0x00FF);
-			v1 = (s8) ((tmp & 0xFF00) >> 8);
-			tmp = b43_shm_read16(dev, B43_SHM_SHARED, 0x005A);
-			v2 = (s8) (tmp & 0x00FF);
-			v3 = (s8) ((tmp & 0xFF00) >> 8);
-			tmp = 0;
-
-			if (v0 == 0x7F || v1 == 0x7F || v2 == 0x7F
-			    || v3 == 0x7F) {
-				tmp =
-				    b43_shm_read16(dev, B43_SHM_SHARED, 0x0070);
-				v0 = (s8) (tmp & 0x00FF);
-				v1 = (s8) ((tmp & 0xFF00) >> 8);
-				tmp =
-				    b43_shm_read16(dev, B43_SHM_SHARED, 0x0072);
-				v2 = (s8) (tmp & 0x00FF);
-				v3 = (s8) ((tmp & 0xFF00) >> 8);
-				if (v0 == 0x7F || v1 == 0x7F || v2 == 0x7F
-				    || v3 == 0x7F)
-					return;
-				v0 = (v0 + 0x20) & 0x3F;
-				v1 = (v1 + 0x20) & 0x3F;
-				v2 = (v2 + 0x20) & 0x3F;
-				v3 = (v3 + 0x20) & 0x3F;
-				tmp = 1;
-			}
-			b43_shm_clear_tssi(dev);
-
-			average = (v0 + v1 + v2 + v3 + 2) / 4;
-
-			if (tmp
-			    && (b43_shm_read16(dev, B43_SHM_SHARED, 0x005E) &
-				0x8))
-				average -= 13;
-
-			estimated_pwr =
-			    b43_phy_estimate_power_out(dev, average);
-
-			max_pwr = dev->dev->bus->sprom.maxpwr_bg;
-			if ((dev->dev->bus->sprom.boardflags_lo
-			    & B43_BFL_PACTRL) && (phy->type == B43_PHYTYPE_G))
-				max_pwr -= 0x3;
-			if (unlikely(max_pwr <= 0)) {
-				b43warn(dev->wl,
-					"Invalid max-TX-power value in SPROM.\n");
-				max_pwr = 60;	/* fake it */
-				dev->dev->bus->sprom.maxpwr_bg = max_pwr;
-			}
-
-			/*TODO:
-			   max_pwr = min(REG - dev->dev->bus->sprom.antennagain_bgphy - 0x6, max_pwr)
-			   where REG is the max power as per the regulatory domain
-			 */
-
-			/* Get desired power (in Q5.2) */
-			desired_pwr = INT_TO_Q52(phy->power_level);
-			/* And limit it. max_pwr already is Q5.2 */
-			desired_pwr = clamp_val(desired_pwr, 0, max_pwr);
-			if (b43_debug(dev, B43_DBG_XMITPOWER)) {
-				b43dbg(dev->wl,
-				       "Current TX power output: " Q52_FMT
-				       " dBm, " "Desired TX power output: "
-				       Q52_FMT " dBm\n", Q52_ARG(estimated_pwr),
-				       Q52_ARG(desired_pwr));
-			}
-
-			/* Calculate the adjustment delta. */
-			pwr_adjust = desired_pwr - estimated_pwr;
-
-			/* RF attenuation delta. */
-			rfatt_delta = ((pwr_adjust + 7) / 8);
-			/* Lower attenuation => Bigger power output. Negate it. */
-			rfatt_delta = -rfatt_delta;
-
-			/* Baseband attenuation delta. */
-			bbatt_delta = pwr_adjust / 2;
-			/* Lower attenuation => Bigger power output. Negate it. */
-			bbatt_delta = -bbatt_delta;
-			/* RF att affects power level 4 times as much as
-			 * Baseband attennuation. Subtract it. */
-			bbatt_delta -= 4 * rfatt_delta;
-
-			/* So do we finally need to adjust something? */
-			if ((rfatt_delta == 0) && (bbatt_delta == 0))
-				return;
-
-			/* Calculate the new attenuation values. */
-			bbatt = phy->bbatt.att;
-			bbatt += bbatt_delta;
-			rfatt = phy->rfatt.att;
-			rfatt += rfatt_delta;
-
-			b43_put_attenuation_into_ranges(dev, &bbatt, &rfatt);
-			tx_control = phy->tx_control;
-			if ((phy->radio_ver == 0x2050) && (phy->radio_rev == 2)) {
-				if (rfatt <= 1) {
-					if (tx_control == 0) {
-						tx_control =
-						    B43_TXCTL_PA2DB |
-						    B43_TXCTL_TXMIX;
-						rfatt += 2;
-						bbatt += 2;
-					} else if (dev->dev->bus->sprom.
-						   boardflags_lo &
-						   B43_BFL_PACTRL) {
-						bbatt += 4 * (rfatt - 2);
-						rfatt = 2;
-					}
-				} else if (rfatt > 4 && tx_control) {
-					tx_control = 0;
-					if (bbatt < 3) {
-						rfatt -= 3;
-						bbatt += 2;
-					} else {
-						rfatt -= 2;
-						bbatt -= 2;
-					}
-				}
-			}
-			/* Save the control values */
-			phy->tx_control = tx_control;
-			b43_put_attenuation_into_ranges(dev, &bbatt, &rfatt);
-			phy->rfatt.att = rfatt;
-			phy->bbatt.att = bbatt;
-
-			/* Adjust the hardware */
-			b43_phy_lock(dev);
-			b43_radio_lock(dev);
-			b43_set_txpower_g(dev, &phy->bbatt, &phy->rfatt,
-					  phy->tx_control);
-			b43_radio_unlock(dev);
-			b43_phy_unlock(dev);
-			break;
-		}
-	case B43_PHYTYPE_N:
-		b43_nphy_xmitpower(dev);
-		break;
-	default:
-		B43_WARN_ON(1);
-	}
-}
-
-static inline s32 b43_tssi2dbm_ad(s32 num, s32 den)
-{
-	if (num < 0)
-		return num / den;
-	else
-		return (num + den / 2) / den;
-}
-
-static inline
-    s8 b43_tssi2dbm_entry(s8 entry[], u8 index, s16 pab0, s16 pab1, s16 pab2)
-{
-	s32 m1, m2, f = 256, q, delta;
-	s8 i = 0;
-
-	m1 = b43_tssi2dbm_ad(16 * pab0 + index * pab1, 32);
-	m2 = max(b43_tssi2dbm_ad(32768 + index * pab2, 256), 1);
-	do {
-		if (i > 15)
-			return -EINVAL;
-		q = b43_tssi2dbm_ad(f * 4096 -
-				    b43_tssi2dbm_ad(m2 * f, 16) * f, 2048);
-		delta = abs(q - f);
-		f = q;
-		i++;
-	} while (delta >= 2);
-	entry[index] = clamp_val(b43_tssi2dbm_ad(m1 * f, 8192), -127, 128);
-	return 0;
-}
-
-/* http://bcm-specs.sipsolutions.net/TSSI_to_DBM_Table */
-int b43_phy_init_tssi2dbm_table(struct b43_wldev *dev)
-{
-	struct b43_phy *phy = &dev->phy;
-	s16 pab0, pab1, pab2;
-	u8 idx;
-	s8 *dyn_tssi2dbm;
-
-	if (phy->type == B43_PHYTYPE_A) {
-		pab0 = (s16) (dev->dev->bus->sprom.pa1b0);
-		pab1 = (s16) (dev->dev->bus->sprom.pa1b1);
-		pab2 = (s16) (dev->dev->bus->sprom.pa1b2);
-	} else {
-		pab0 = (s16) (dev->dev->bus->sprom.pa0b0);
-		pab1 = (s16) (dev->dev->bus->sprom.pa0b1);
-		pab2 = (s16) (dev->dev->bus->sprom.pa0b2);
-	}
-
-	if ((dev->dev->bus->chip_id == 0x4301) && (phy->radio_ver != 0x2050)) {
-		phy->tgt_idle_tssi = 0x34;
-		phy->tssi2dbm = b43_tssi2dbm_b_table;
-		return 0;
-	}
-
-	if (pab0 != 0 && pab1 != 0 && pab2 != 0 &&
-	    pab0 != -1 && pab1 != -1 && pab2 != -1) {
-		/* The pabX values are set in SPROM. Use them. */
-		if (phy->type == B43_PHYTYPE_A) {
-			if ((s8) dev->dev->bus->sprom.itssi_a != 0 &&
-			    (s8) dev->dev->bus->sprom.itssi_a != -1)
-				phy->tgt_idle_tssi =
-				    (s8) (dev->dev->bus->sprom.itssi_a);
-			else
-				phy->tgt_idle_tssi = 62;
-		} else {
-			if ((s8) dev->dev->bus->sprom.itssi_bg != 0 &&
-			    (s8) dev->dev->bus->sprom.itssi_bg != -1)
-				phy->tgt_idle_tssi =
-				    (s8) (dev->dev->bus->sprom.itssi_bg);
-			else
-				phy->tgt_idle_tssi = 62;
-		}
-		dyn_tssi2dbm = kmalloc(64, GFP_KERNEL);
-		if (dyn_tssi2dbm == NULL) {
-			b43err(dev->wl, "Could not allocate memory "
-			       "for tssi2dbm table\n");
-			return -ENOMEM;
-		}
-		for (idx = 0; idx < 64; idx++)
-			if (b43_tssi2dbm_entry
-			    (dyn_tssi2dbm, idx, pab0, pab1, pab2)) {
-				phy->tssi2dbm = NULL;
-				b43err(dev->wl, "Could not generate "
-				       "tssi2dBm table\n");
-				kfree(dyn_tssi2dbm);
-				return -ENODEV;
-			}
-		phy->tssi2dbm = dyn_tssi2dbm;
-		phy->dyn_tssi_tbl = 1;
-	} else {
-		/* pabX values not set in SPROM. */
-		switch (phy->type) {
-		case B43_PHYTYPE_A:
-			/* APHY needs a generated table. */
-			phy->tssi2dbm = NULL;
-			b43err(dev->wl, "Could not generate tssi2dBm "
-			       "table (wrong SPROM info)!\n");
-			return -ENODEV;
-		case B43_PHYTYPE_B:
-			phy->tgt_idle_tssi = 0x34;
-			phy->tssi2dbm = b43_tssi2dbm_b_table;
-			break;
-		case B43_PHYTYPE_G:
-			phy->tgt_idle_tssi = 0x34;
-			phy->tssi2dbm = b43_tssi2dbm_g_table;
-			break;
-		}
-	}
-
-	return 0;
-}
-
-int b43_phy_init(struct b43_wldev *dev)
-{
-	struct b43_phy *phy = &dev->phy;
-	bool unsupported = 0;
-	int err = 0;
-
-	switch (phy->type) {
-	case B43_PHYTYPE_A:
-		if (phy->rev == 2 || phy->rev == 3)
-			b43_phy_inita(dev);
-		else
-			unsupported = 1;
-		break;
-	case B43_PHYTYPE_G:
-		b43_phy_initg(dev);
-		break;
-	case B43_PHYTYPE_N:
-		err = b43_phy_initn(dev);
-		break;
-	default:
-		unsupported = 1;
-	}
-	if (unsupported)
-		b43err(dev->wl, "Unknown PHYTYPE found\n");
-
-	return err;
-}
-
-void b43_set_rx_antenna(struct b43_wldev *dev, int antenna)
-{
-	struct b43_phy *phy = &dev->phy;
-	u64 hf;
-	u16 tmp;
-	int autodiv = 0;
-
-	if (antenna == B43_ANTENNA_AUTO0 || antenna == B43_ANTENNA_AUTO1)
-		autodiv = 1;
-
-	hf = b43_hf_read(dev);
-	hf &= ~B43_HF_ANTDIVHELP;
-	b43_hf_write(dev, hf);
-
-	switch (phy->type) {
-	case B43_PHYTYPE_A:
-	case B43_PHYTYPE_G:
-		tmp = b43_phy_read(dev, B43_PHY_BBANDCFG);
-		tmp &= ~B43_PHY_BBANDCFG_RXANT;
-		tmp |= (autodiv ? B43_ANTENNA_AUTO0 : antenna)
-		    << B43_PHY_BBANDCFG_RXANT_SHIFT;
-		b43_phy_write(dev, B43_PHY_BBANDCFG, tmp);
-
-		if (autodiv) {
-			tmp = b43_phy_read(dev, B43_PHY_ANTDWELL);
-			if (antenna == B43_ANTENNA_AUTO0)
-				tmp &= ~B43_PHY_ANTDWELL_AUTODIV1;
-			else
-				tmp |= B43_PHY_ANTDWELL_AUTODIV1;
-			b43_phy_write(dev, B43_PHY_ANTDWELL, tmp);
-		}
-		if (phy->type == B43_PHYTYPE_G) {
-			tmp = b43_phy_read(dev, B43_PHY_ANTWRSETT);
-			if (autodiv)
-				tmp |= B43_PHY_ANTWRSETT_ARXDIV;
-			else
-				tmp &= ~B43_PHY_ANTWRSETT_ARXDIV;
-			b43_phy_write(dev, B43_PHY_ANTWRSETT, tmp);
-			if (phy->rev >= 2) {
-				tmp = b43_phy_read(dev, B43_PHY_OFDM61);
-				tmp |= B43_PHY_OFDM61_10;
-				b43_phy_write(dev, B43_PHY_OFDM61, tmp);
-
-				tmp =
-				    b43_phy_read(dev, B43_PHY_DIVSRCHGAINBACK);
-				tmp = (tmp & 0xFF00) | 0x15;
-				b43_phy_write(dev, B43_PHY_DIVSRCHGAINBACK,
-					      tmp);
-
-				if (phy->rev == 2) {
-					b43_phy_write(dev, B43_PHY_ADIVRELATED,
-						      8);
-				} else {
-					tmp =
-					    b43_phy_read(dev,
-							 B43_PHY_ADIVRELATED);
-					tmp = (tmp & 0xFF00) | 8;
-					b43_phy_write(dev, B43_PHY_ADIVRELATED,
-						      tmp);
-				}
-			}
-			if (phy->rev >= 6)
-				b43_phy_write(dev, B43_PHY_OFDM9B, 0xDC);
-		} else {
-			if (phy->rev < 3) {
-				tmp = b43_phy_read(dev, B43_PHY_ANTDWELL);
-				tmp = (tmp & 0xFF00) | 0x24;
-				b43_phy_write(dev, B43_PHY_ANTDWELL, tmp);
-			} else {
-				tmp = b43_phy_read(dev, B43_PHY_OFDM61);
-				tmp |= 0x10;
-				b43_phy_write(dev, B43_PHY_OFDM61, tmp);
-				if (phy->analog == 3) {
-					b43_phy_write(dev, B43_PHY_CLIPPWRDOWNT,
-						      0x1D);
-					b43_phy_write(dev, B43_PHY_ADIVRELATED,
-						      8);
-				} else {
-					b43_phy_write(dev, B43_PHY_CLIPPWRDOWNT,
-						      0x3A);
-					tmp =
-					    b43_phy_read(dev,
-							 B43_PHY_ADIVRELATED);
-					tmp = (tmp & 0xFF00) | 8;
-					b43_phy_write(dev, B43_PHY_ADIVRELATED,
-						      tmp);
-				}
-			}
-		}
-		break;
-	case B43_PHYTYPE_B:
-		tmp = b43_phy_read(dev, B43_PHY_CCKBBANDCFG);
-		tmp &= ~B43_PHY_BBANDCFG_RXANT;
-		tmp |= (autodiv ? B43_ANTENNA_AUTO0 : antenna)
-		    << B43_PHY_BBANDCFG_RXANT_SHIFT;
-		b43_phy_write(dev, B43_PHY_CCKBBANDCFG, tmp);
-		break;
-	case B43_PHYTYPE_N:
-		b43_nphy_set_rxantenna(dev, antenna);
-		break;
-	default:
-		B43_WARN_ON(1);
-	}
-
-	hf |= B43_HF_ANTDIVHELP;
-	b43_hf_write(dev, hf);
-}
-
-/* Get the freq, as it has to be written to the device. */
-static inline u16 channel2freq_bg(u8 channel)
-{
-	B43_WARN_ON(!(channel >= 1 && channel <= 14));
-
-	return b43_radio_channel_codes_bg[channel - 1];
-}
-
-/* Get the freq, as it has to be written to the device. */
-static inline u16 channel2freq_a(u8 channel)
-{
-	B43_WARN_ON(channel > 200);
-
-	return (5000 + 5 * channel);
-}
-
-void b43_radio_lock(struct b43_wldev *dev)
-{
-	u32 macctl;
-
-	macctl = b43_read32(dev, B43_MMIO_MACCTL);
-	B43_WARN_ON(macctl & B43_MACCTL_RADIOLOCK);
-	macctl |= B43_MACCTL_RADIOLOCK;
-	b43_write32(dev, B43_MMIO_MACCTL, macctl);
-	/* Commit the write and wait for the device
-	 * to exit any radio register access. */
-	b43_read32(dev, B43_MMIO_MACCTL);
-	udelay(10);
-}
-
-void b43_radio_unlock(struct b43_wldev *dev)
-{
-	u32 macctl;
-
-	/* Commit any write */
-	b43_read16(dev, B43_MMIO_PHY_VER);
-	/* unlock */
-	macctl = b43_read32(dev, B43_MMIO_MACCTL);
-	B43_WARN_ON(!(macctl & B43_MACCTL_RADIOLOCK));
-	macctl &= ~B43_MACCTL_RADIOLOCK;
-	b43_write32(dev, B43_MMIO_MACCTL, macctl);
-}
-
-u16 b43_radio_read16(struct b43_wldev *dev, u16 offset)
-{
-	struct b43_phy *phy = &dev->phy;
-
-	/* Offset 1 is a 32-bit register. */
-	B43_WARN_ON(offset == 1);
-
-	switch (phy->type) {
-	case B43_PHYTYPE_A:
-		offset |= 0x40;
-		break;
-	case B43_PHYTYPE_B:
-		if (phy->radio_ver == 0x2053) {
-			if (offset < 0x70)
-				offset += 0x80;
-			else if (offset < 0x80)
-				offset += 0x70;
-		} else if (phy->radio_ver == 0x2050) {
-			offset |= 0x80;
-		} else
-			B43_WARN_ON(1);
-		break;
-	case B43_PHYTYPE_G:
-		offset |= 0x80;
-		break;
-	case B43_PHYTYPE_N:
-		offset |= 0x100;
-		break;
-	case B43_PHYTYPE_LP:
-		/* No adjustment required. */
-		break;
-	default:
-		B43_WARN_ON(1);
-	}
-
-	b43_write16(dev, B43_MMIO_RADIO_CONTROL, offset);
-	return b43_read16(dev, B43_MMIO_RADIO_DATA_LOW);
-}
-
-void b43_radio_write16(struct b43_wldev *dev, u16 offset, u16 val)
-{
-	/* Offset 1 is a 32-bit register. */
-	B43_WARN_ON(offset == 1);
-
-	b43_write16(dev, B43_MMIO_RADIO_CONTROL, offset);
-	b43_write16(dev, B43_MMIO_RADIO_DATA_LOW, val);
-}
-
-void b43_radio_mask(struct b43_wldev *dev, u16 offset, u16 mask)
-{
-	b43_radio_write16(dev, offset,
-			  b43_radio_read16(dev, offset) & mask);
-}
-
-void b43_radio_set(struct b43_wldev *dev, u16 offset, u16 set)
-{
-	b43_radio_write16(dev, offset,
-			  b43_radio_read16(dev, offset) | set);
-}
-
-void b43_radio_maskset(struct b43_wldev *dev, u16 offset, u16 mask, u16 set)
-{
-	b43_radio_write16(dev, offset,
-			  (b43_radio_read16(dev, offset) & mask) | set);
-}
-
-static void b43_set_all_gains(struct b43_wldev *dev,
-			      s16 first, s16 second, s16 third)
-{
-	struct b43_phy *phy = &dev->phy;
-	u16 i;
-	u16 start = 0x08, end = 0x18;
-	u16 tmp;
-	u16 table;
-
-	if (phy->rev <= 1) {
-		start = 0x10;
-		end = 0x20;
-	}
-
-	table = B43_OFDMTAB_GAINX;
-	if (phy->rev <= 1)
-		table = B43_OFDMTAB_GAINX_R1;
-	for (i = 0; i < 4; i++)
-		b43_ofdmtab_write16(dev, table, i, first);
-
-	for (i = start; i < end; i++)
-		b43_ofdmtab_write16(dev, table, i, second);
-
-	if (third != -1) {
-		tmp = ((u16) third << 14) | ((u16) third << 6);
-		b43_phy_write(dev, 0x04A0,
-			      (b43_phy_read(dev, 0x04A0) & 0xBFBF) | tmp);
-		b43_phy_write(dev, 0x04A1,
-			      (b43_phy_read(dev, 0x04A1) & 0xBFBF) | tmp);
-		b43_phy_write(dev, 0x04A2,
-			      (b43_phy_read(dev, 0x04A2) & 0xBFBF) | tmp);
-	}
-	b43_dummy_transmission(dev);
-}
-
-static void b43_set_original_gains(struct b43_wldev *dev)
-{
-	struct b43_phy *phy = &dev->phy;
-	u16 i, tmp;
-	u16 table;
-	u16 start = 0x0008, end = 0x0018;
-
-	if (phy->rev <= 1) {
-		start = 0x0010;
-		end = 0x0020;
-	}
-
-	table = B43_OFDMTAB_GAINX;
-	if (phy->rev <= 1)
-		table = B43_OFDMTAB_GAINX_R1;
-	for (i = 0; i < 4; i++) {
-		tmp = (i & 0xFFFC);
-		tmp |= (i & 0x0001) << 1;
-		tmp |= (i & 0x0002) >> 1;
-
-		b43_ofdmtab_write16(dev, table, i, tmp);
-	}
-
-	for (i = start; i < end; i++)
-		b43_ofdmtab_write16(dev, table, i, i - start);
-
-	b43_phy_write(dev, 0x04A0,
-		      (b43_phy_read(dev, 0x04A0) & 0xBFBF) | 0x4040);
-	b43_phy_write(dev, 0x04A1,
-		      (b43_phy_read(dev, 0x04A1) & 0xBFBF) | 0x4040);
-	b43_phy_write(dev, 0x04A2,
-		      (b43_phy_read(dev, 0x04A2) & 0xBFBF) | 0x4000);
-	b43_dummy_transmission(dev);
-}
-
-/* Synthetic PU workaround */
-static void b43_synth_pu_workaround(struct b43_wldev *dev, u8 channel)
-{
-	struct b43_phy *phy = &dev->phy;
-
-	might_sleep();
-
-	if (phy->radio_ver != 0x2050 || phy->radio_rev >= 6) {
-		/* We do not need the workaround. */
-		return;
-	}
-
-	if (channel <= 10) {
-		b43_write16(dev, B43_MMIO_CHANNEL,
-			    channel2freq_bg(channel + 4));
-	} else {
-		b43_write16(dev, B43_MMIO_CHANNEL, channel2freq_bg(1));
-	}
-	msleep(1);
-	b43_write16(dev, B43_MMIO_CHANNEL, channel2freq_bg(channel));
-}
-
-u8 b43_radio_aci_detect(struct b43_wldev *dev, u8 channel)
-{
-	struct b43_phy *phy = &dev->phy;
-	u8 ret = 0;
-	u16 saved, rssi, temp;
-	int i, j = 0;
-
-	saved = b43_phy_read(dev, 0x0403);
-	b43_radio_selectchannel(dev, channel, 0);
-	b43_phy_write(dev, 0x0403, (saved & 0xFFF8) | 5);
-	if (phy->aci_hw_rssi)
-		rssi = b43_phy_read(dev, 0x048A) & 0x3F;
-	else
-		rssi = saved & 0x3F;
-	/* clamp temp to signed 5bit */
-	if (rssi > 32)
-		rssi -= 64;
-	for (i = 0; i < 100; i++) {
-		temp = (b43_phy_read(dev, 0x047F) >> 8) & 0x3F;
-		if (temp > 32)
-			temp -= 64;
-		if (temp < rssi)
-			j++;
-		if (j >= 20)
-			ret = 1;
-	}
-	b43_phy_write(dev, 0x0403, saved);
-
-	return ret;
-}
-
-u8 b43_radio_aci_scan(struct b43_wldev * dev)
-{
-	struct b43_phy *phy = &dev->phy;
-	u8 ret[13];
-	unsigned int channel = phy->channel;
-	unsigned int i, j, start, end;
-
-	if (!((phy->type == B43_PHYTYPE_G) && (phy->rev > 0)))
-		return 0;
-
-	b43_phy_lock(dev);
-	b43_radio_lock(dev);
-	b43_phy_write(dev, 0x0802, b43_phy_read(dev, 0x0802) & 0xFFFC);
-	b43_phy_write(dev, B43_PHY_G_CRS,
-		      b43_phy_read(dev, B43_PHY_G_CRS) & 0x7FFF);
-	b43_set_all_gains(dev, 3, 8, 1);
-
-	start = (channel - 5 > 0) ? channel - 5 : 1;
-	end = (channel + 5 < 14) ? channel + 5 : 13;
-
-	for (i = start; i <= end; i++) {
-		if (abs(channel - i) > 2)
-			ret[i - 1] = b43_radio_aci_detect(dev, i);
-	}
-	b43_radio_selectchannel(dev, channel, 0);
-	b43_phy_write(dev, 0x0802,
-		      (b43_phy_read(dev, 0x0802) & 0xFFFC) | 0x0003);
-	b43_phy_write(dev, 0x0403, b43_phy_read(dev, 0x0403) & 0xFFF8);
-	b43_phy_write(dev, B43_PHY_G_CRS,
-		      b43_phy_read(dev, B43_PHY_G_CRS) | 0x8000);
-	b43_set_original_gains(dev);
-	for (i = 0; i < 13; i++) {
-		if (!ret[i])
-			continue;
-		end = (i + 5 < 13) ? i + 5 : 13;
-		for (j = i; j < end; j++)
-			ret[j] = 1;
-	}
-	b43_radio_unlock(dev);
-	b43_phy_unlock(dev);
-
-	return ret[channel - 1];
-}
-
-/* http://bcm-specs.sipsolutions.net/NRSSILookupTable */
-void b43_nrssi_hw_write(struct b43_wldev *dev, u16 offset, s16 val)
-{
-	b43_phy_write(dev, B43_PHY_NRSSILT_CTRL, offset);
-	mmiowb();
-	b43_phy_write(dev, B43_PHY_NRSSILT_DATA, (u16) val);
-}
-
-/* http://bcm-specs.sipsolutions.net/NRSSILookupTable */
-s16 b43_nrssi_hw_read(struct b43_wldev *dev, u16 offset)
-{
-	u16 val;
-
-	b43_phy_write(dev, B43_PHY_NRSSILT_CTRL, offset);
-	val = b43_phy_read(dev, B43_PHY_NRSSILT_DATA);
-
-	return (s16) val;
-}
-
-/* http://bcm-specs.sipsolutions.net/NRSSILookupTable */
-void b43_nrssi_hw_update(struct b43_wldev *dev, u16 val)
-{
-	u16 i;
-	s16 tmp;
-
-	for (i = 0; i < 64; i++) {
-		tmp = b43_nrssi_hw_read(dev, i);
-		tmp -= val;
-		tmp = clamp_val(tmp, -32, 31);
-		b43_nrssi_hw_write(dev, i, tmp);
-	}
-}
-
-/* http://bcm-specs.sipsolutions.net/NRSSILookupTable */
-void b43_nrssi_mem_update(struct b43_wldev *dev)
-{
-	struct b43_phy *phy = &dev->phy;
-	s16 i, delta;
-	s32 tmp;
-
-	delta = 0x1F - phy->nrssi[0];
-	for (i = 0; i < 64; i++) {
-		tmp = (i - delta) * phy->nrssislope;
-		tmp /= 0x10000;
-		tmp += 0x3A;
-		tmp = clamp_val(tmp, 0, 0x3F);
-		phy->nrssi_lt[i] = tmp;
-	}
-}
-
-static void b43_calc_nrssi_offset(struct b43_wldev *dev)
-{
-	struct b43_phy *phy = &dev->phy;
-	u16 backup[20] = { 0 };
-	s16 v47F;
-	u16 i;
-	u16 saved = 0xFFFF;
-
-	backup[0] = b43_phy_read(dev, 0x0001);
-	backup[1] = b43_phy_read(dev, 0x0811);
-	backup[2] = b43_phy_read(dev, 0x0812);
-	if (phy->rev != 1) {	/* Not in specs, but needed to prevent PPC machine check */
-		backup[3] = b43_phy_read(dev, 0x0814);
-		backup[4] = b43_phy_read(dev, 0x0815);
-	}
-	backup[5] = b43_phy_read(dev, 0x005A);
-	backup[6] = b43_phy_read(dev, 0x0059);
-	backup[7] = b43_phy_read(dev, 0x0058);
-	backup[8] = b43_phy_read(dev, 0x000A);
-	backup[9] = b43_phy_read(dev, 0x0003);
-	backup[10] = b43_radio_read16(dev, 0x007A);
-	backup[11] = b43_radio_read16(dev, 0x0043);
-
-	b43_phy_write(dev, 0x0429, b43_phy_read(dev, 0x0429) & 0x7FFF);
-	b43_phy_write(dev, 0x0001,
-		      (b43_phy_read(dev, 0x0001) & 0x3FFF) | 0x4000);
-	b43_phy_write(dev, 0x0811, b43_phy_read(dev, 0x0811) | 0x000C);
-	b43_phy_write(dev, 0x0812,
-		      (b43_phy_read(dev, 0x0812) & 0xFFF3) | 0x0004);
-	b43_phy_write(dev, 0x0802, b43_phy_read(dev, 0x0802) & ~(0x1 | 0x2));
-	if (phy->rev >= 6) {
-		backup[12] = b43_phy_read(dev, 0x002E);
-		backup[13] = b43_phy_read(dev, 0x002F);
-		backup[14] = b43_phy_read(dev, 0x080F);
-		backup[15] = b43_phy_read(dev, 0x0810);
-		backup[16] = b43_phy_read(dev, 0x0801);
-		backup[17] = b43_phy_read(dev, 0x0060);
-		backup[18] = b43_phy_read(dev, 0x0014);
-		backup[19] = b43_phy_read(dev, 0x0478);
-
-		b43_phy_write(dev, 0x002E, 0);
-		b43_phy_write(dev, 0x002F, 0);
-		b43_phy_write(dev, 0x080F, 0);
-		b43_phy_write(dev, 0x0810, 0);
-		b43_phy_write(dev, 0x0478, b43_phy_read(dev, 0x0478) | 0x0100);
-		b43_phy_write(dev, 0x0801, b43_phy_read(dev, 0x0801) | 0x0040);
-		b43_phy_write(dev, 0x0060, b43_phy_read(dev, 0x0060) | 0x0040);
-		b43_phy_write(dev, 0x0014, b43_phy_read(dev, 0x0014) | 0x0200);
-	}
-	b43_radio_write16(dev, 0x007A, b43_radio_read16(dev, 0x007A) | 0x0070);
-	b43_radio_write16(dev, 0x007A, b43_radio_read16(dev, 0x007A) | 0x0080);
-	udelay(30);
-
-	v47F = (s16) ((b43_phy_read(dev, 0x047F) >> 8) & 0x003F);
-	if (v47F >= 0x20)
-		v47F -= 0x40;
-	if (v47F == 31) {
-		for (i = 7; i >= 4; i--) {
-			b43_radio_write16(dev, 0x007B, i);
-			udelay(20);
-			v47F =
-			    (s16) ((b43_phy_read(dev, 0x047F) >> 8) & 0x003F);
-			if (v47F >= 0x20)
-				v47F -= 0x40;
-			if (v47F < 31 && saved == 0xFFFF)
-				saved = i;
-		}
-		if (saved == 0xFFFF)
-			saved = 4;
-	} else {
-		b43_radio_write16(dev, 0x007A,
-				  b43_radio_read16(dev, 0x007A) & 0x007F);
-		if (phy->rev != 1) {	/* Not in specs, but needed to prevent PPC machine check */
-			b43_phy_write(dev, 0x0814,
-				      b43_phy_read(dev, 0x0814) | 0x0001);
-			b43_phy_write(dev, 0x0815,
-				      b43_phy_read(dev, 0x0815) & 0xFFFE);
-		}
-		b43_phy_write(dev, 0x0811, b43_phy_read(dev, 0x0811) | 0x000C);
-		b43_phy_write(dev, 0x0812, b43_phy_read(dev, 0x0812) | 0x000C);
-		b43_phy_write(dev, 0x0811, b43_phy_read(dev, 0x0811) | 0x0030);
-		b43_phy_write(dev, 0x0812, b43_phy_read(dev, 0x0812) | 0x0030);
-		b43_phy_write(dev, 0x005A, 0x0480);
-		b43_phy_write(dev, 0x0059, 0x0810);
-		b43_phy_write(dev, 0x0058, 0x000D);
-		if (phy->rev == 0) {
-			b43_phy_write(dev, 0x0003, 0x0122);
-		} else {
-			b43_phy_write(dev, 0x000A, b43_phy_read(dev, 0x000A)
-				      | 0x2000);
-		}
-		if (phy->rev != 1) {	/* Not in specs, but needed to prevent PPC machine check */
-			b43_phy_write(dev, 0x0814,
-				      b43_phy_read(dev, 0x0814) | 0x0004);
-			b43_phy_write(dev, 0x0815,
-				      b43_phy_read(dev, 0x0815) & 0xFFFB);
-		}
-		b43_phy_write(dev, 0x0003, (b43_phy_read(dev, 0x0003) & 0xFF9F)
-			      | 0x0040);
-		b43_radio_write16(dev, 0x007A,
-				  b43_radio_read16(dev, 0x007A) | 0x000F);
-		b43_set_all_gains(dev, 3, 0, 1);
-		b43_radio_write16(dev, 0x0043, (b43_radio_read16(dev, 0x0043)
-						& 0x00F0) | 0x000F);
-		udelay(30);
-		v47F = (s16) ((b43_phy_read(dev, 0x047F) >> 8) & 0x003F);
-		if (v47F >= 0x20)
-			v47F -= 0x40;
-		if (v47F == -32) {
-			for (i = 0; i < 4; i++) {
-				b43_radio_write16(dev, 0x007B, i);
-				udelay(20);
-				v47F =
-				    (s16) ((b43_phy_read(dev, 0x047F) >> 8) &
-					   0x003F);
-				if (v47F >= 0x20)
-					v47F -= 0x40;
-				if (v47F > -31 && saved == 0xFFFF)
-					saved = i;
-			}
-			if (saved == 0xFFFF)
-				saved = 3;
-		} else
-			saved = 0;
-	}
-	b43_radio_write16(dev, 0x007B, saved);
-
-	if (phy->rev >= 6) {
-		b43_phy_write(dev, 0x002E, backup[12]);
-		b43_phy_write(dev, 0x002F, backup[13]);
-		b43_phy_write(dev, 0x080F, backup[14]);
-		b43_phy_write(dev, 0x0810, backup[15]);
-	}
-	if (phy->rev != 1) {	/* Not in specs, but needed to prevent PPC machine check */
-		b43_phy_write(dev, 0x0814, backup[3]);
-		b43_phy_write(dev, 0x0815, backup[4]);
-	}
-	b43_phy_write(dev, 0x005A, backup[5]);
-	b43_phy_write(dev, 0x0059, backup[6]);
-	b43_phy_write(dev, 0x0058, backup[7]);
-	b43_phy_write(dev, 0x000A, backup[8]);
-	b43_phy_write(dev, 0x0003, backup[9]);
-	b43_radio_write16(dev, 0x0043, backup[11]);
-	b43_radio_write16(dev, 0x007A, backup[10]);
-	b43_phy_write(dev, 0x0802, b43_phy_read(dev, 0x0802) | 0x1 | 0x2);
-	b43_phy_write(dev, 0x0429, b43_phy_read(dev, 0x0429) | 0x8000);
-	b43_set_original_gains(dev);
-	if (phy->rev >= 6) {
-		b43_phy_write(dev, 0x0801, backup[16]);
-		b43_phy_write(dev, 0x0060, backup[17]);
-		b43_phy_write(dev, 0x0014, backup[18]);
-		b43_phy_write(dev, 0x0478, backup[19]);
-	}
-	b43_phy_write(dev, 0x0001, backup[0]);
-	b43_phy_write(dev, 0x0812, backup[2]);
-	b43_phy_write(dev, 0x0811, backup[1]);
-}
-
-void b43_calc_nrssi_slope(struct b43_wldev *dev)
-{
-	struct b43_phy *phy = &dev->phy;
-	u16 backup[18] = { 0 };
-	u16 tmp;
-	s16 nrssi0, nrssi1;
-
-	switch (phy->type) {
-	case B43_PHYTYPE_B:
-		backup[0] = b43_radio_read16(dev, 0x007A);
-		backup[1] = b43_radio_read16(dev, 0x0052);
-		backup[2] = b43_radio_read16(dev, 0x0043);
-		backup[3] = b43_phy_read(dev, 0x0030);
-		backup[4] = b43_phy_read(dev, 0x0026);
-		backup[5] = b43_phy_read(dev, 0x0015);
-		backup[6] = b43_phy_read(dev, 0x002A);
-		backup[7] = b43_phy_read(dev, 0x0020);
-		backup[8] = b43_phy_read(dev, 0x005A);
-		backup[9] = b43_phy_read(dev, 0x0059);
-		backup[10] = b43_phy_read(dev, 0x0058);
-		backup[11] = b43_read16(dev, 0x03E2);
-		backup[12] = b43_read16(dev, 0x03E6);
-		backup[13] = b43_read16(dev, B43_MMIO_CHANNEL_EXT);
-
-		tmp = b43_radio_read16(dev, 0x007A);
-		tmp &= (phy->rev >= 5) ? 0x007F : 0x000F;
-		b43_radio_write16(dev, 0x007A, tmp);
-		b43_phy_write(dev, 0x0030, 0x00FF);
-		b43_write16(dev, 0x03EC, 0x7F7F);
-		b43_phy_write(dev, 0x0026, 0x0000);
-		b43_phy_write(dev, 0x0015, b43_phy_read(dev, 0x0015) | 0x0020);
-		b43_phy_write(dev, 0x002A, 0x08A3);
-		b43_radio_write16(dev, 0x007A,
-				  b43_radio_read16(dev, 0x007A) | 0x0080);
-
-		nrssi0 = (s16) b43_phy_read(dev, 0x0027);
-		b43_radio_write16(dev, 0x007A,
-				  b43_radio_read16(dev, 0x007A) & 0x007F);
-		if (phy->rev >= 2) {
-			b43_write16(dev, 0x03E6, 0x0040);
-		} else if (phy->rev == 0) {
-			b43_write16(dev, 0x03E6, 0x0122);
-		} else {
-			b43_write16(dev, B43_MMIO_CHANNEL_EXT,
-				    b43_read16(dev,
-					       B43_MMIO_CHANNEL_EXT) & 0x2000);
-		}
-		b43_phy_write(dev, 0x0020, 0x3F3F);
-		b43_phy_write(dev, 0x0015, 0xF330);
-		b43_radio_write16(dev, 0x005A, 0x0060);
-		b43_radio_write16(dev, 0x0043,
-				  b43_radio_read16(dev, 0x0043) & 0x00F0);
-		b43_phy_write(dev, 0x005A, 0x0480);
-		b43_phy_write(dev, 0x0059, 0x0810);
-		b43_phy_write(dev, 0x0058, 0x000D);
-		udelay(20);
-
-		nrssi1 = (s16) b43_phy_read(dev, 0x0027);
-		b43_phy_write(dev, 0x0030, backup[3]);
-		b43_radio_write16(dev, 0x007A, backup[0]);
-		b43_write16(dev, 0x03E2, backup[11]);
-		b43_phy_write(dev, 0x0026, backup[4]);
-		b43_phy_write(dev, 0x0015, backup[5]);
-		b43_phy_write(dev, 0x002A, backup[6]);
-		b43_synth_pu_workaround(dev, phy->channel);
-		if (phy->rev != 0)
-			b43_write16(dev, 0x03F4, backup[13]);
-
-		b43_phy_write(dev, 0x0020, backup[7]);
-		b43_phy_write(dev, 0x005A, backup[8]);
-		b43_phy_write(dev, 0x0059, backup[9]);
-		b43_phy_write(dev, 0x0058, backup[10]);
-		b43_radio_write16(dev, 0x0052, backup[1]);
-		b43_radio_write16(dev, 0x0043, backup[2]);
-
-		if (nrssi0 == nrssi1)
-			phy->nrssislope = 0x00010000;
-		else
-			phy->nrssislope = 0x00400000 / (nrssi0 - nrssi1);
-
-		if (nrssi0 <= -4) {
-			phy->nrssi[0] = nrssi0;
-			phy->nrssi[1] = nrssi1;
-		}
-		break;
-	case B43_PHYTYPE_G:
-		if (phy->radio_rev >= 9)
-			return;
-		if (phy->radio_rev == 8)
-			b43_calc_nrssi_offset(dev);
-
-		b43_phy_write(dev, B43_PHY_G_CRS,
-			      b43_phy_read(dev, B43_PHY_G_CRS) & 0x7FFF);
-		b43_phy_write(dev, 0x0802, b43_phy_read(dev, 0x0802) & 0xFFFC);
-		backup[7] = b43_read16(dev, 0x03E2);
-		b43_write16(dev, 0x03E2, b43_read16(dev, 0x03E2) | 0x8000);
-		backup[0] = b43_radio_read16(dev, 0x007A);
-		backup[1] = b43_radio_read16(dev, 0x0052);
-		backup[2] = b43_radio_read16(dev, 0x0043);
-		backup[3] = b43_phy_read(dev, 0x0015);
-		backup[4] = b43_phy_read(dev, 0x005A);
-		backup[5] = b43_phy_read(dev, 0x0059);
-		backup[6] = b43_phy_read(dev, 0x0058);
-		backup[8] = b43_read16(dev, 0x03E6);
-		backup[9] = b43_read16(dev, B43_MMIO_CHANNEL_EXT);
-		if (phy->rev >= 3) {
-			backup[10] = b43_phy_read(dev, 0x002E);
-			backup[11] = b43_phy_read(dev, 0x002F);
-			backup[12] = b43_phy_read(dev, 0x080F);
-			backup[13] = b43_phy_read(dev, B43_PHY_G_LO_CONTROL);
-			backup[14] = b43_phy_read(dev, 0x0801);
-			backup[15] = b43_phy_read(dev, 0x0060);
-			backup[16] = b43_phy_read(dev, 0x0014);
-			backup[17] = b43_phy_read(dev, 0x0478);
-			b43_phy_write(dev, 0x002E, 0);
-			b43_phy_write(dev, B43_PHY_G_LO_CONTROL, 0);
-			switch (phy->rev) {
-			case 4:
-			case 6:
-			case 7:
-				b43_phy_write(dev, 0x0478,
-					      b43_phy_read(dev, 0x0478)
-					      | 0x0100);
-				b43_phy_write(dev, 0x0801,
-					      b43_phy_read(dev, 0x0801)
-					      | 0x0040);
-				break;
-			case 3:
-			case 5:
-				b43_phy_write(dev, 0x0801,
-					      b43_phy_read(dev, 0x0801)
-					      & 0xFFBF);
-				break;
-			}
-			b43_phy_write(dev, 0x0060, b43_phy_read(dev, 0x0060)
-				      | 0x0040);
-			b43_phy_write(dev, 0x0014, b43_phy_read(dev, 0x0014)
-				      | 0x0200);
-		}
-		b43_radio_write16(dev, 0x007A,
-				  b43_radio_read16(dev, 0x007A) | 0x0070);
-		b43_set_all_gains(dev, 0, 8, 0);
-		b43_radio_write16(dev, 0x007A,
-				  b43_radio_read16(dev, 0x007A) & 0x00F7);
-		if (phy->rev >= 2) {
-			b43_phy_write(dev, 0x0811,
-				      (b43_phy_read(dev, 0x0811) & 0xFFCF) |
-				      0x0030);
-			b43_phy_write(dev, 0x0812,
-				      (b43_phy_read(dev, 0x0812) & 0xFFCF) |
-				      0x0010);
-		}
-		b43_radio_write16(dev, 0x007A,
-				  b43_radio_read16(dev, 0x007A) | 0x0080);
-		udelay(20);
-
-		nrssi0 = (s16) ((b43_phy_read(dev, 0x047F) >> 8) & 0x003F);
-		if (nrssi0 >= 0x0020)
-			nrssi0 -= 0x0040;
-
-		b43_radio_write16(dev, 0x007A,
-				  b43_radio_read16(dev, 0x007A) & 0x007F);
-		if (phy->rev >= 2) {
-			b43_phy_write(dev, 0x0003, (b43_phy_read(dev, 0x0003)
-						    & 0xFF9F) | 0x0040);
-		}
-
-		b43_write16(dev, B43_MMIO_CHANNEL_EXT,
-			    b43_read16(dev, B43_MMIO_CHANNEL_EXT)
-			    | 0x2000);
-		b43_radio_write16(dev, 0x007A,
-				  b43_radio_read16(dev, 0x007A) | 0x000F);
-		b43_phy_write(dev, 0x0015, 0xF330);
-		if (phy->rev >= 2) {
-			b43_phy_write(dev, 0x0812,
-				      (b43_phy_read(dev, 0x0812) & 0xFFCF) |
-				      0x0020);
-			b43_phy_write(dev, 0x0811,
-				      (b43_phy_read(dev, 0x0811) & 0xFFCF) |
-				      0x0020);
-		}
-
-		b43_set_all_gains(dev, 3, 0, 1);
-		if (phy->radio_rev == 8) {
-			b43_radio_write16(dev, 0x0043, 0x001F);
-		} else {
-			tmp = b43_radio_read16(dev, 0x0052) & 0xFF0F;
-			b43_radio_write16(dev, 0x0052, tmp | 0x0060);
-			tmp = b43_radio_read16(dev, 0x0043) & 0xFFF0;
-			b43_radio_write16(dev, 0x0043, tmp | 0x0009);
-		}
-		b43_phy_write(dev, 0x005A, 0x0480);
-		b43_phy_write(dev, 0x0059, 0x0810);
-		b43_phy_write(dev, 0x0058, 0x000D);
-		udelay(20);
-		nrssi1 = (s16) ((b43_phy_read(dev, 0x047F) >> 8) & 0x003F);
-		if (nrssi1 >= 0x0020)
-			nrssi1 -= 0x0040;
-		if (nrssi0 == nrssi1)
-			phy->nrssislope = 0x00010000;
-		else
-			phy->nrssislope = 0x00400000 / (nrssi0 - nrssi1);
-		if (nrssi0 >= -4) {
-			phy->nrssi[0] = nrssi1;
-			phy->nrssi[1] = nrssi0;
-		}
-		if (phy->rev >= 3) {
-			b43_phy_write(dev, 0x002E, backup[10]);
-			b43_phy_write(dev, 0x002F, backup[11]);
-			b43_phy_write(dev, 0x080F, backup[12]);
-			b43_phy_write(dev, B43_PHY_G_LO_CONTROL, backup[13]);
-		}
-		if (phy->rev >= 2) {
-			b43_phy_write(dev, 0x0812,
-				      b43_phy_read(dev, 0x0812) & 0xFFCF);
-			b43_phy_write(dev, 0x0811,
-				      b43_phy_read(dev, 0x0811) & 0xFFCF);
-		}
-
-		b43_radio_write16(dev, 0x007A, backup[0]);
-		b43_radio_write16(dev, 0x0052, backup[1]);
-		b43_radio_write16(dev, 0x0043, backup[2]);
-		b43_write16(dev, 0x03E2, backup[7]);
-		b43_write16(dev, 0x03E6, backup[8]);
-		b43_write16(dev, B43_MMIO_CHANNEL_EXT, backup[9]);
-		b43_phy_write(dev, 0x0015, backup[3]);
-		b43_phy_write(dev, 0x005A, backup[4]);
-		b43_phy_write(dev, 0x0059, backup[5]);
-		b43_phy_write(dev, 0x0058, backup[6]);
-		b43_synth_pu_workaround(dev, phy->channel);
-		b43_phy_write(dev, 0x0802,
-			      b43_phy_read(dev, 0x0802) | (0x0001 | 0x0002));
-		b43_set_original_gains(dev);
-		b43_phy_write(dev, B43_PHY_G_CRS,
-			      b43_phy_read(dev, B43_PHY_G_CRS) | 0x8000);
-		if (phy->rev >= 3) {
-			b43_phy_write(dev, 0x0801, backup[14]);
-			b43_phy_write(dev, 0x0060, backup[15]);
-			b43_phy_write(dev, 0x0014, backup[16]);
-			b43_phy_write(dev, 0x0478, backup[17]);
-		}
-		b43_nrssi_mem_update(dev);
-		b43_calc_nrssi_threshold(dev);
-		break;
-	default:
-		B43_WARN_ON(1);
-	}
-}
-
-void b43_calc_nrssi_threshold(struct b43_wldev *dev)
-{
-	struct b43_phy *phy = &dev->phy;
-	s32 threshold;
-	s32 a, b;
-	s16 tmp16;
-	u16 tmp_u16;
-
-	switch (phy->type) {
-	case B43_PHYTYPE_B:{
-			if (phy->radio_ver != 0x2050)
-				return;
-			if (!
-			    (dev->dev->bus->sprom.
-			     boardflags_lo & B43_BFL_RSSI))
-				return;
-
-			if (phy->radio_rev >= 6) {
-				threshold =
-				    (phy->nrssi[1] - phy->nrssi[0]) * 32;
-				threshold += 20 * (phy->nrssi[0] + 1);
-				threshold /= 40;
-			} else
-				threshold = phy->nrssi[1] - 5;
-
-			threshold = clamp_val(threshold, 0, 0x3E);
-			b43_phy_read(dev, 0x0020);	/* dummy read */
-			b43_phy_write(dev, 0x0020,
-				      (((u16) threshold) << 8) | 0x001C);
-
-			if (phy->radio_rev >= 6) {
-				b43_phy_write(dev, 0x0087, 0x0E0D);
-				b43_phy_write(dev, 0x0086, 0x0C0B);
-				b43_phy_write(dev, 0x0085, 0x0A09);
-				b43_phy_write(dev, 0x0084, 0x0808);
-				b43_phy_write(dev, 0x0083, 0x0808);
-				b43_phy_write(dev, 0x0082, 0x0604);
-				b43_phy_write(dev, 0x0081, 0x0302);
-				b43_phy_write(dev, 0x0080, 0x0100);
-			}
-			break;
-		}
-	case B43_PHYTYPE_G:
-		if (!phy->gmode ||
-		    !(dev->dev->bus->sprom.boardflags_lo & B43_BFL_RSSI)) {
-			tmp16 = b43_nrssi_hw_read(dev, 0x20);
-			if (tmp16 >= 0x20)
-				tmp16 -= 0x40;
-			if (tmp16 < 3) {
-				b43_phy_write(dev, 0x048A,
-					      (b43_phy_read(dev, 0x048A)
-					       & 0xF000) | 0x09EB);
-			} else {
-				b43_phy_write(dev, 0x048A,
-					      (b43_phy_read(dev, 0x048A)
-					       & 0xF000) | 0x0AED);
-			}
-		} else {
-			if (phy->interfmode == B43_INTERFMODE_NONWLAN) {
-				a = 0xE;
-				b = 0xA;
-			} else if (!phy->aci_wlan_automatic && phy->aci_enable) {
-				a = 0x13;
-				b = 0x12;
-			} else {
-				a = 0xE;
-				b = 0x11;
-			}
-
-			a = a * (phy->nrssi[1] - phy->nrssi[0]);
-			a += (phy->nrssi[0] << 6);
-			if (a < 32)
-				a += 31;
-			else
-				a += 32;
-			a = a >> 6;
-			a = clamp_val(a, -31, 31);
-
-			b = b * (phy->nrssi[1] - phy->nrssi[0]);
-			b += (phy->nrssi[0] << 6);
-			if (b < 32)
-				b += 31;
-			else
-				b += 32;
-			b = b >> 6;
-			b = clamp_val(b, -31, 31);
-
-			tmp_u16 = b43_phy_read(dev, 0x048A) & 0xF000;
-			tmp_u16 |= ((u32) b & 0x0000003F);
-			tmp_u16 |= (((u32) a & 0x0000003F) << 6);
-			b43_phy_write(dev, 0x048A, tmp_u16);
-		}
-		break;
-	default:
-		B43_WARN_ON(1);
-	}
-}
-
-/* Stack implementation to save/restore values from the
- * interference mitigation code.
- * It is save to restore values in random order.
- */
-static void _stack_save(u32 * _stackptr, size_t * stackidx,
-			u8 id, u16 offset, u16 value)
-{
-	u32 *stackptr = &(_stackptr[*stackidx]);
-
-	B43_WARN_ON(offset & 0xF000);
-	B43_WARN_ON(id & 0xF0);
-	*stackptr = offset;
-	*stackptr |= ((u32) id) << 12;
-	*stackptr |= ((u32) value) << 16;
-	(*stackidx)++;
-	B43_WARN_ON(*stackidx >= B43_INTERFSTACK_SIZE);
-}
-
-static u16 _stack_restore(u32 * stackptr, u8 id, u16 offset)
-{
-	size_t i;
-
-	B43_WARN_ON(offset & 0xF000);
-	B43_WARN_ON(id & 0xF0);
-	for (i = 0; i < B43_INTERFSTACK_SIZE; i++, stackptr++) {
-		if ((*stackptr & 0x00000FFF) != offset)
-			continue;
-		if (((*stackptr & 0x0000F000) >> 12) != id)
-			continue;
-		return ((*stackptr & 0xFFFF0000) >> 16);
-	}
-	B43_WARN_ON(1);
-
-	return 0;
-}
-
-#define phy_stacksave(offset)					\
-	do {							\
-		_stack_save(stack, &stackidx, 0x1, (offset),	\
-			    b43_phy_read(dev, (offset)));	\
-	} while (0)
-#define phy_stackrestore(offset)				\
-	do {							\
-		b43_phy_write(dev, (offset),		\
-				  _stack_restore(stack, 0x1,	\
-						 (offset)));	\
-	} while (0)
-#define radio_stacksave(offset)						\
-	do {								\
-		_stack_save(stack, &stackidx, 0x2, (offset),		\
-			    b43_radio_read16(dev, (offset)));	\
-	} while (0)
-#define radio_stackrestore(offset)					\
-	do {								\
-		b43_radio_write16(dev, (offset),			\
-				      _stack_restore(stack, 0x2,	\
-						     (offset)));	\
-	} while (0)
-#define ofdmtab_stacksave(table, offset)			\
-	do {							\
-		_stack_save(stack, &stackidx, 0x3, (offset)|(table),	\
-			    b43_ofdmtab_read16(dev, (table), (offset)));	\
-	} while (0)
-#define ofdmtab_stackrestore(table, offset)			\
-	do {							\
-		b43_ofdmtab_write16(dev, (table),	(offset),	\
-				  _stack_restore(stack, 0x3,	\
-						 (offset)|(table)));	\
-	} while (0)
-
-static void
-b43_radio_interference_mitigation_enable(struct b43_wldev *dev, int mode)
-{
-	struct b43_phy *phy = &dev->phy;
-	u16 tmp, flipped;
-	size_t stackidx = 0;
-	u32 *stack = phy->interfstack;
-
-	switch (mode) {
-	case B43_INTERFMODE_NONWLAN:
-		if (phy->rev != 1) {
-			b43_phy_write(dev, 0x042B,
-				      b43_phy_read(dev, 0x042B) | 0x0800);
-			b43_phy_write(dev, B43_PHY_G_CRS,
-				      b43_phy_read(dev,
-						   B43_PHY_G_CRS) & ~0x4000);
-			break;
-		}
-		radio_stacksave(0x0078);
-		tmp = (b43_radio_read16(dev, 0x0078) & 0x001E);
-		B43_WARN_ON(tmp > 15);
-		flipped = bitrev4(tmp);
-		if (flipped < 10 && flipped >= 8)
-			flipped = 7;
-		else if (flipped >= 10)
-			flipped -= 3;
-		flipped = (bitrev4(flipped) << 1) | 0x0020;
-		b43_radio_write16(dev, 0x0078, flipped);
-
-		b43_calc_nrssi_threshold(dev);
-
-		phy_stacksave(0x0406);
-		b43_phy_write(dev, 0x0406, 0x7E28);
-
-		b43_phy_write(dev, 0x042B, b43_phy_read(dev, 0x042B) | 0x0800);
-		b43_phy_write(dev, B43_PHY_RADIO_BITFIELD,
-			      b43_phy_read(dev,
-					   B43_PHY_RADIO_BITFIELD) | 0x1000);
-
-		phy_stacksave(0x04A0);
-		b43_phy_write(dev, 0x04A0,
-			      (b43_phy_read(dev, 0x04A0) & 0xC0C0) | 0x0008);
-		phy_stacksave(0x04A1);
-		b43_phy_write(dev, 0x04A1,
-			      (b43_phy_read(dev, 0x04A1) & 0xC0C0) | 0x0605);
-		phy_stacksave(0x04A2);
-		b43_phy_write(dev, 0x04A2,
-			      (b43_phy_read(dev, 0x04A2) & 0xC0C0) | 0x0204);
-		phy_stacksave(0x04A8);
-		b43_phy_write(dev, 0x04A8,
-			      (b43_phy_read(dev, 0x04A8) & 0xC0C0) | 0x0803);
-		phy_stacksave(0x04AB);
-		b43_phy_write(dev, 0x04AB,
-			      (b43_phy_read(dev, 0x04AB) & 0xC0C0) | 0x0605);
-
-		phy_stacksave(0x04A7);
-		b43_phy_write(dev, 0x04A7, 0x0002);
-		phy_stacksave(0x04A3);
-		b43_phy_write(dev, 0x04A3, 0x287A);
-		phy_stacksave(0x04A9);
-		b43_phy_write(dev, 0x04A9, 0x2027);
-		phy_stacksave(0x0493);
-		b43_phy_write(dev, 0x0493, 0x32F5);
-		phy_stacksave(0x04AA);
-		b43_phy_write(dev, 0x04AA, 0x2027);
-		phy_stacksave(0x04AC);
-		b43_phy_write(dev, 0x04AC, 0x32F5);
-		break;
-	case B43_INTERFMODE_MANUALWLAN:
-		if (b43_phy_read(dev, 0x0033) & 0x0800)
-			break;
-
-		phy->aci_enable = 1;
-
-		phy_stacksave(B43_PHY_RADIO_BITFIELD);
-		phy_stacksave(B43_PHY_G_CRS);
-		if (phy->rev < 2) {
-			phy_stacksave(0x0406);
-		} else {
-			phy_stacksave(0x04C0);
-			phy_stacksave(0x04C1);
-		}
-		phy_stacksave(0x0033);
-		phy_stacksave(0x04A7);
-		phy_stacksave(0x04A3);
-		phy_stacksave(0x04A9);
-		phy_stacksave(0x04AA);
-		phy_stacksave(0x04AC);
-		phy_stacksave(0x0493);
-		phy_stacksave(0x04A1);
-		phy_stacksave(0x04A0);
-		phy_stacksave(0x04A2);
-		phy_stacksave(0x048A);
-		phy_stacksave(0x04A8);
-		phy_stacksave(0x04AB);
-		if (phy->rev == 2) {
-			phy_stacksave(0x04AD);
-			phy_stacksave(0x04AE);
-		} else if (phy->rev >= 3) {
-			phy_stacksave(0x04AD);
-			phy_stacksave(0x0415);
-			phy_stacksave(0x0416);
-			phy_stacksave(0x0417);
-			ofdmtab_stacksave(0x1A00, 0x2);
-			ofdmtab_stacksave(0x1A00, 0x3);
-		}
-		phy_stacksave(0x042B);
-		phy_stacksave(0x048C);
-
-		b43_phy_write(dev, B43_PHY_RADIO_BITFIELD,
-			      b43_phy_read(dev, B43_PHY_RADIO_BITFIELD)
-			      & ~0x1000);
-		b43_phy_write(dev, B43_PHY_G_CRS,
-			      (b43_phy_read(dev, B43_PHY_G_CRS)
-			       & 0xFFFC) | 0x0002);
-
-		b43_phy_write(dev, 0x0033, 0x0800);
-		b43_phy_write(dev, 0x04A3, 0x2027);
-		b43_phy_write(dev, 0x04A9, 0x1CA8);
-		b43_phy_write(dev, 0x0493, 0x287A);
-		b43_phy_write(dev, 0x04AA, 0x1CA8);
-		b43_phy_write(dev, 0x04AC, 0x287A);
-
-		b43_phy_write(dev, 0x04A0, (b43_phy_read(dev, 0x04A0)
-					    & 0xFFC0) | 0x001A);
-		b43_phy_write(dev, 0x04A7, 0x000D);
-
-		if (phy->rev < 2) {
-			b43_phy_write(dev, 0x0406, 0xFF0D);
-		} else if (phy->rev == 2) {
-			b43_phy_write(dev, 0x04C0, 0xFFFF);
-			b43_phy_write(dev, 0x04C1, 0x00A9);
-		} else {
-			b43_phy_write(dev, 0x04C0, 0x00C1);
-			b43_phy_write(dev, 0x04C1, 0x0059);
-		}
-
-		b43_phy_write(dev, 0x04A1, (b43_phy_read(dev, 0x04A1)
-					    & 0xC0FF) | 0x1800);
-		b43_phy_write(dev, 0x04A1, (b43_phy_read(dev, 0x04A1)
-					    & 0xFFC0) | 0x0015);
-		b43_phy_write(dev, 0x04A8, (b43_phy_read(dev, 0x04A8)
-					    & 0xCFFF) | 0x1000);
-		b43_phy_write(dev, 0x04A8, (b43_phy_read(dev, 0x04A8)
-					    & 0xF0FF) | 0x0A00);
-		b43_phy_write(dev, 0x04AB, (b43_phy_read(dev, 0x04AB)
-					    & 0xCFFF) | 0x1000);
-		b43_phy_write(dev, 0x04AB, (b43_phy_read(dev, 0x04AB)
-					    & 0xF0FF) | 0x0800);
-		b43_phy_write(dev, 0x04AB, (b43_phy_read(dev, 0x04AB)
-					    & 0xFFCF) | 0x0010);
-		b43_phy_write(dev, 0x04AB, (b43_phy_read(dev, 0x04AB)
-					    & 0xFFF0) | 0x0005);
-		b43_phy_write(dev, 0x04A8, (b43_phy_read(dev, 0x04A8)
-					    & 0xFFCF) | 0x0010);
-		b43_phy_write(dev, 0x04A8, (b43_phy_read(dev, 0x04A8)
-					    & 0xFFF0) | 0x0006);
-		b43_phy_write(dev, 0x04A2, (b43_phy_read(dev, 0x04A2)
-					    & 0xF0FF) | 0x0800);
-		b43_phy_write(dev, 0x04A0, (b43_phy_read(dev, 0x04A0)
-					    & 0xF0FF) | 0x0500);
-		b43_phy_write(dev, 0x04A2, (b43_phy_read(dev, 0x04A2)
-					    & 0xFFF0) | 0x000B);
-
-		if (phy->rev >= 3) {
-			b43_phy_write(dev, 0x048A, b43_phy_read(dev, 0x048A)
-				      & ~0x8000);
-			b43_phy_write(dev, 0x0415, (b43_phy_read(dev, 0x0415)
-						    & 0x8000) | 0x36D8);
-			b43_phy_write(dev, 0x0416, (b43_phy_read(dev, 0x0416)
-						    & 0x8000) | 0x36D8);
-			b43_phy_write(dev, 0x0417, (b43_phy_read(dev, 0x0417)
-						    & 0xFE00) | 0x016D);
-		} else {
-			b43_phy_write(dev, 0x048A, b43_phy_read(dev, 0x048A)
-				      | 0x1000);
-			b43_phy_write(dev, 0x048A, (b43_phy_read(dev, 0x048A)
-						    & 0x9FFF) | 0x2000);
-			b43_hf_write(dev, b43_hf_read(dev) | B43_HF_ACIW);
-		}
-		if (phy->rev >= 2) {
-			b43_phy_write(dev, 0x042B, b43_phy_read(dev, 0x042B)
-				      | 0x0800);
-		}
-		b43_phy_write(dev, 0x048C, (b43_phy_read(dev, 0x048C)
-					    & 0xF0FF) | 0x0200);
-		if (phy->rev == 2) {
-			b43_phy_write(dev, 0x04AE, (b43_phy_read(dev, 0x04AE)
-						    & 0xFF00) | 0x007F);
-			b43_phy_write(dev, 0x04AD, (b43_phy_read(dev, 0x04AD)
-						    & 0x00FF) | 0x1300);
-		} else if (phy->rev >= 6) {
-			b43_ofdmtab_write16(dev, 0x1A00, 0x3, 0x007F);
-			b43_ofdmtab_write16(dev, 0x1A00, 0x2, 0x007F);
-			b43_phy_write(dev, 0x04AD, b43_phy_read(dev, 0x04AD)
-				      & 0x00FF);
-		}
-		b43_calc_nrssi_slope(dev);
-		break;
-	default:
-		B43_WARN_ON(1);
-	}
-}
-
-static void
-b43_radio_interference_mitigation_disable(struct b43_wldev *dev, int mode)
-{
-	struct b43_phy *phy = &dev->phy;
-	u32 *stack = phy->interfstack;
-
-	switch (mode) {
-	case B43_INTERFMODE_NONWLAN:
-		if (phy->rev != 1) {
-			b43_phy_write(dev, 0x042B,
-				      b43_phy_read(dev, 0x042B) & ~0x0800);
-			b43_phy_write(dev, B43_PHY_G_CRS,
-				      b43_phy_read(dev,
-						   B43_PHY_G_CRS) | 0x4000);
-			break;
-		}
-		radio_stackrestore(0x0078);
-		b43_calc_nrssi_threshold(dev);
-		phy_stackrestore(0x0406);
-		b43_phy_write(dev, 0x042B, b43_phy_read(dev, 0x042B) & ~0x0800);
-		if (!dev->bad_frames_preempt) {
-			b43_phy_write(dev, B43_PHY_RADIO_BITFIELD,
-				      b43_phy_read(dev, B43_PHY_RADIO_BITFIELD)
-				      & ~(1 << 11));
-		}
-		b43_phy_write(dev, B43_PHY_G_CRS,
-			      b43_phy_read(dev, B43_PHY_G_CRS) | 0x4000);
-		phy_stackrestore(0x04A0);
-		phy_stackrestore(0x04A1);
-		phy_stackrestore(0x04A2);
-		phy_stackrestore(0x04A8);
-		phy_stackrestore(0x04AB);
-		phy_stackrestore(0x04A7);
-		phy_stackrestore(0x04A3);
-		phy_stackrestore(0x04A9);
-		phy_stackrestore(0x0493);
-		phy_stackrestore(0x04AA);
-		phy_stackrestore(0x04AC);
-		break;
-	case B43_INTERFMODE_MANUALWLAN:
-		if (!(b43_phy_read(dev, 0x0033) & 0x0800))
-			break;
-
-		phy->aci_enable = 0;
-
-		phy_stackrestore(B43_PHY_RADIO_BITFIELD);
-		phy_stackrestore(B43_PHY_G_CRS);
-		phy_stackrestore(0x0033);
-		phy_stackrestore(0x04A3);
-		phy_stackrestore(0x04A9);
-		phy_stackrestore(0x0493);
-		phy_stackrestore(0x04AA);
-		phy_stackrestore(0x04AC);
-		phy_stackrestore(0x04A0);
-		phy_stackrestore(0x04A7);
-		if (phy->rev >= 2) {
-			phy_stackrestore(0x04C0);
-			phy_stackrestore(0x04C1);
-		} else
-			phy_stackrestore(0x0406);
-		phy_stackrestore(0x04A1);
-		phy_stackrestore(0x04AB);
-		phy_stackrestore(0x04A8);
-		if (phy->rev == 2) {
-			phy_stackrestore(0x04AD);
-			phy_stackrestore(0x04AE);
-		} else if (phy->rev >= 3) {
-			phy_stackrestore(0x04AD);
-			phy_stackrestore(0x0415);
-			phy_stackrestore(0x0416);
-			phy_stackrestore(0x0417);
-			ofdmtab_stackrestore(0x1A00, 0x2);
-			ofdmtab_stackrestore(0x1A00, 0x3);
-		}
-		phy_stackrestore(0x04A2);
-		phy_stackrestore(0x048A);
-		phy_stackrestore(0x042B);
-		phy_stackrestore(0x048C);
-		b43_hf_write(dev, b43_hf_read(dev) & ~B43_HF_ACIW);
-		b43_calc_nrssi_slope(dev);
-		break;
-	default:
-		B43_WARN_ON(1);
-	}
-}
-
-#undef phy_stacksave
-#undef phy_stackrestore
-#undef radio_stacksave
-#undef radio_stackrestore
-#undef ofdmtab_stacksave
-#undef ofdmtab_stackrestore
-
-int b43_radio_set_interference_mitigation(struct b43_wldev *dev, int mode)
-{
-	struct b43_phy *phy = &dev->phy;
-	int currentmode;
-
-	if ((phy->type != B43_PHYTYPE_G) || (phy->rev == 0) || (!phy->gmode))
-		return -ENODEV;
-
-	phy->aci_wlan_automatic = 0;
-	switch (mode) {
-	case B43_INTERFMODE_AUTOWLAN:
-		phy->aci_wlan_automatic = 1;
-		if (phy->aci_enable)
-			mode = B43_INTERFMODE_MANUALWLAN;
-		else
-			mode = B43_INTERFMODE_NONE;
-		break;
-	case B43_INTERFMODE_NONE:
-	case B43_INTERFMODE_NONWLAN:
-	case B43_INTERFMODE_MANUALWLAN:
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	currentmode = phy->interfmode;
-	if (currentmode == mode)
-		return 0;
-	if (currentmode != B43_INTERFMODE_NONE)
-		b43_radio_interference_mitigation_disable(dev, currentmode);
-
-	if (mode == B43_INTERFMODE_NONE) {
-		phy->aci_enable = 0;
-		phy->aci_hw_rssi = 0;
-	} else
-		b43_radio_interference_mitigation_enable(dev, mode);
-	phy->interfmode = mode;
-
-	return 0;
-}
-
-static u16 b43_radio_core_calibration_value(struct b43_wldev *dev)
-{
-	u16 reg, index, ret;
-
-	static const u8 rcc_table[] = {
-		0x02, 0x03, 0x01, 0x0F,
-		0x06, 0x07, 0x05, 0x0F,
-		0x0A, 0x0B, 0x09, 0x0F,
-		0x0E, 0x0F, 0x0D, 0x0F,
-	};
-
-	reg = b43_radio_read16(dev, 0x60);
-	index = (reg & 0x001E) >> 1;
-	ret = rcc_table[index] << 1;
-	ret |= (reg & 0x0001);
-	ret |= 0x0020;
-
-	return ret;
-}
-
-#define LPD(L, P, D)	(((L) << 2) | ((P) << 1) | ((D) << 0))
-static u16 radio2050_rfover_val(struct b43_wldev *dev,
-				u16 phy_register, unsigned int lpd)
-{
-	struct b43_phy *phy = &dev->phy;
-	struct ssb_sprom *sprom = &(dev->dev->bus->sprom);
-
-	if (!phy->gmode)
-		return 0;
-
-	if (has_loopback_gain(phy)) {
-		int max_lb_gain = phy->max_lb_gain;
-		u16 extlna;
-		u16 i;
-
-		if (phy->radio_rev == 8)
-			max_lb_gain += 0x3E;
-		else
-			max_lb_gain += 0x26;
-		if (max_lb_gain >= 0x46) {
-			extlna = 0x3000;
-			max_lb_gain -= 0x46;
-		} else if (max_lb_gain >= 0x3A) {
-			extlna = 0x1000;
-			max_lb_gain -= 0x3A;
-		} else if (max_lb_gain >= 0x2E) {
-			extlna = 0x2000;
-			max_lb_gain -= 0x2E;
-		} else {
-			extlna = 0;
-			max_lb_gain -= 0x10;
-		}
-
-		for (i = 0; i < 16; i++) {
-			max_lb_gain -= (i * 6);
-			if (max_lb_gain < 6)
-				break;
-		}
-
-		if ((phy->rev < 7) ||
-		    !(sprom->boardflags_lo & B43_BFL_EXTLNA)) {
-			if (phy_register == B43_PHY_RFOVER) {
-				return 0x1B3;
-			} else if (phy_register == B43_PHY_RFOVERVAL) {
-				extlna |= (i << 8);
-				switch (lpd) {
-				case LPD(0, 1, 1):
-					return 0x0F92;
-				case LPD(0, 0, 1):
-				case LPD(1, 0, 1):
-					return (0x0092 | extlna);
-				case LPD(1, 0, 0):
-					return (0x0093 | extlna);
-				}
-				B43_WARN_ON(1);
-			}
-			B43_WARN_ON(1);
-		} else {
-			if (phy_register == B43_PHY_RFOVER) {
-				return 0x9B3;
-			} else if (phy_register == B43_PHY_RFOVERVAL) {
-				if (extlna)
-					extlna |= 0x8000;
-				extlna |= (i << 8);
-				switch (lpd) {
-				case LPD(0, 1, 1):
-					return 0x8F92;
-				case LPD(0, 0, 1):
-					return (0x8092 | extlna);
-				case LPD(1, 0, 1):
-					return (0x2092 | extlna);
-				case LPD(1, 0, 0):
-					return (0x2093 | extlna);
-				}
-				B43_WARN_ON(1);
-			}
-			B43_WARN_ON(1);
-		}
-	} else {
-		if ((phy->rev < 7) ||
-		    !(sprom->boardflags_lo & B43_BFL_EXTLNA)) {
-			if (phy_register == B43_PHY_RFOVER) {
-				return 0x1B3;
-			} else if (phy_register == B43_PHY_RFOVERVAL) {
-				switch (lpd) {
-				case LPD(0, 1, 1):
-					return 0x0FB2;
-				case LPD(0, 0, 1):
-					return 0x00B2;
-				case LPD(1, 0, 1):
-					return 0x30B2;
-				case LPD(1, 0, 0):
-					return 0x30B3;
-				}
-				B43_WARN_ON(1);
-			}
-			B43_WARN_ON(1);
-		} else {
-			if (phy_register == B43_PHY_RFOVER) {
-				return 0x9B3;
-			} else if (phy_register == B43_PHY_RFOVERVAL) {
-				switch (lpd) {
-				case LPD(0, 1, 1):
-					return 0x8FB2;
-				case LPD(0, 0, 1):
-					return 0x80B2;
-				case LPD(1, 0, 1):
-					return 0x20B2;
-				case LPD(1, 0, 0):
-					return 0x20B3;
-				}
-				B43_WARN_ON(1);
-			}
-			B43_WARN_ON(1);
-		}
-	}
-	return 0;
-}
-
-struct init2050_saved_values {
-	/* Core registers */
-	u16 reg_3EC;
-	u16 reg_3E6;
-	u16 reg_3F4;
-	/* Radio registers */
-	u16 radio_43;
-	u16 radio_51;
-	u16 radio_52;
-	/* PHY registers */
-	u16 phy_pgactl;
-	u16 phy_cck_5A;
-	u16 phy_cck_59;
-	u16 phy_cck_58;
-	u16 phy_cck_30;
-	u16 phy_rfover;
-	u16 phy_rfoverval;
-	u16 phy_analogover;
-	u16 phy_analogoverval;
-	u16 phy_crs0;
-	u16 phy_classctl;
-	u16 phy_lo_mask;
-	u16 phy_lo_ctl;
-	u16 phy_syncctl;
-};
-
-u16 b43_radio_init2050(struct b43_wldev *dev)
-{
-	struct b43_phy *phy = &dev->phy;
-	struct init2050_saved_values sav;
-	u16 rcc;
-	u16 radio78;
-	u16 ret;
-	u16 i, j;
-	u32 tmp1 = 0, tmp2 = 0;
-
-	memset(&sav, 0, sizeof(sav));	/* get rid of "may be used uninitialized..." */
-
-	sav.radio_43 = b43_radio_read16(dev, 0x43);
-	sav.radio_51 = b43_radio_read16(dev, 0x51);
-	sav.radio_52 = b43_radio_read16(dev, 0x52);
-	sav.phy_pgactl = b43_phy_read(dev, B43_PHY_PGACTL);
-	sav.phy_cck_5A = b43_phy_read(dev, B43_PHY_CCK(0x5A));
-	sav.phy_cck_59 = b43_phy_read(dev, B43_PHY_CCK(0x59));
-	sav.phy_cck_58 = b43_phy_read(dev, B43_PHY_CCK(0x58));
-
-	if (phy->type == B43_PHYTYPE_B) {
-		sav.phy_cck_30 = b43_phy_read(dev, B43_PHY_CCK(0x30));
-		sav.reg_3EC = b43_read16(dev, 0x3EC);
-
-		b43_phy_write(dev, B43_PHY_CCK(0x30), 0xFF);
-		b43_write16(dev, 0x3EC, 0x3F3F);
-	} else if (phy->gmode || phy->rev >= 2) {
-		sav.phy_rfover = b43_phy_read(dev, B43_PHY_RFOVER);
-		sav.phy_rfoverval = b43_phy_read(dev, B43_PHY_RFOVERVAL);
-		sav.phy_analogover = b43_phy_read(dev, B43_PHY_ANALOGOVER);
-		sav.phy_analogoverval =
-		    b43_phy_read(dev, B43_PHY_ANALOGOVERVAL);
-		sav.phy_crs0 = b43_phy_read(dev, B43_PHY_CRS0);
-		sav.phy_classctl = b43_phy_read(dev, B43_PHY_CLASSCTL);
-
-		b43_phy_write(dev, B43_PHY_ANALOGOVER,
-			      b43_phy_read(dev, B43_PHY_ANALOGOVER)
-			      | 0x0003);
-		b43_phy_write(dev, B43_PHY_ANALOGOVERVAL,
-			      b43_phy_read(dev, B43_PHY_ANALOGOVERVAL)
-			      & 0xFFFC);
-		b43_phy_write(dev, B43_PHY_CRS0, b43_phy_read(dev, B43_PHY_CRS0)
-			      & 0x7FFF);
-		b43_phy_write(dev, B43_PHY_CLASSCTL,
-			      b43_phy_read(dev, B43_PHY_CLASSCTL)
-			      & 0xFFFC);
-		if (has_loopback_gain(phy)) {
-			sav.phy_lo_mask = b43_phy_read(dev, B43_PHY_LO_MASK);
-			sav.phy_lo_ctl = b43_phy_read(dev, B43_PHY_LO_CTL);
-
-			if (phy->rev >= 3)
-				b43_phy_write(dev, B43_PHY_LO_MASK, 0xC020);
-			else
-				b43_phy_write(dev, B43_PHY_LO_MASK, 0x8020);
-			b43_phy_write(dev, B43_PHY_LO_CTL, 0);
-		}
-
-		b43_phy_write(dev, B43_PHY_RFOVERVAL,
-			      radio2050_rfover_val(dev, B43_PHY_RFOVERVAL,
-						   LPD(0, 1, 1)));
-		b43_phy_write(dev, B43_PHY_RFOVER,
-			      radio2050_rfover_val(dev, B43_PHY_RFOVER, 0));
-	}
-	b43_write16(dev, 0x3E2, b43_read16(dev, 0x3E2) | 0x8000);
-
-	sav.phy_syncctl = b43_phy_read(dev, B43_PHY_SYNCCTL);
-	b43_phy_write(dev, B43_PHY_SYNCCTL, b43_phy_read(dev, B43_PHY_SYNCCTL)
-		      & 0xFF7F);
-	sav.reg_3E6 = b43_read16(dev, 0x3E6);
-	sav.reg_3F4 = b43_read16(dev, 0x3F4);
-
-	if (phy->analog == 0) {
-		b43_write16(dev, 0x03E6, 0x0122);
-	} else {
-		if (phy->analog >= 2) {
-			b43_phy_write(dev, B43_PHY_CCK(0x03),
-				      (b43_phy_read(dev, B43_PHY_CCK(0x03))
-				       & 0xFFBF) | 0x40);
-		}
-		b43_write16(dev, B43_MMIO_CHANNEL_EXT,
-			    (b43_read16(dev, B43_MMIO_CHANNEL_EXT) | 0x2000));
-	}
-
-	rcc = b43_radio_core_calibration_value(dev);
-
-	if (phy->type == B43_PHYTYPE_B)
-		b43_radio_write16(dev, 0x78, 0x26);
-	if (phy->gmode || phy->rev >= 2) {
-		b43_phy_write(dev, B43_PHY_RFOVERVAL,
-			      radio2050_rfover_val(dev, B43_PHY_RFOVERVAL,
-						   LPD(0, 1, 1)));
-	}
-	b43_phy_write(dev, B43_PHY_PGACTL, 0xBFAF);
-	b43_phy_write(dev, B43_PHY_CCK(0x2B), 0x1403);
-	if (phy->gmode || phy->rev >= 2) {
-		b43_phy_write(dev, B43_PHY_RFOVERVAL,
-			      radio2050_rfover_val(dev, B43_PHY_RFOVERVAL,
-						   LPD(0, 0, 1)));
-	}
-	b43_phy_write(dev, B43_PHY_PGACTL, 0xBFA0);
-	b43_radio_write16(dev, 0x51, b43_radio_read16(dev, 0x51)
-			  | 0x0004);
-	if (phy->radio_rev == 8) {
-		b43_radio_write16(dev, 0x43, 0x1F);
-	} else {
-		b43_radio_write16(dev, 0x52, 0);
-		b43_radio_write16(dev, 0x43, (b43_radio_read16(dev, 0x43)
-					      & 0xFFF0) | 0x0009);
-	}
-	b43_phy_write(dev, B43_PHY_CCK(0x58), 0);
-
-	for (i = 0; i < 16; i++) {
-		b43_phy_write(dev, B43_PHY_CCK(0x5A), 0x0480);
-		b43_phy_write(dev, B43_PHY_CCK(0x59), 0xC810);
-		b43_phy_write(dev, B43_PHY_CCK(0x58), 0x000D);
-		if (phy->gmode || phy->rev >= 2) {
-			b43_phy_write(dev, B43_PHY_RFOVERVAL,
-				      radio2050_rfover_val(dev,
-							   B43_PHY_RFOVERVAL,
-							   LPD(1, 0, 1)));
-		}
-		b43_phy_write(dev, B43_PHY_PGACTL, 0xAFB0);
-		udelay(10);
-		if (phy->gmode || phy->rev >= 2) {
-			b43_phy_write(dev, B43_PHY_RFOVERVAL,
-				      radio2050_rfover_val(dev,
-							   B43_PHY_RFOVERVAL,
-							   LPD(1, 0, 1)));
-		}
-		b43_phy_write(dev, B43_PHY_PGACTL, 0xEFB0);
-		udelay(10);
-		if (phy->gmode || phy->rev >= 2) {
-			b43_phy_write(dev, B43_PHY_RFOVERVAL,
-				      radio2050_rfover_val(dev,
-							   B43_PHY_RFOVERVAL,
-							   LPD(1, 0, 0)));
-		}
-		b43_phy_write(dev, B43_PHY_PGACTL, 0xFFF0);
-		udelay(20);
-		tmp1 += b43_phy_read(dev, B43_PHY_LO_LEAKAGE);
-		b43_phy_write(dev, B43_PHY_CCK(0x58), 0);
-		if (phy->gmode || phy->rev >= 2) {
-			b43_phy_write(dev, B43_PHY_RFOVERVAL,
-				      radio2050_rfover_val(dev,
-							   B43_PHY_RFOVERVAL,
-							   LPD(1, 0, 1)));
-		}
-		b43_phy_write(dev, B43_PHY_PGACTL, 0xAFB0);
-	}
-	udelay(10);
-
-	b43_phy_write(dev, B43_PHY_CCK(0x58), 0);
-	tmp1++;
-	tmp1 >>= 9;
-
-	for (i = 0; i < 16; i++) {
-		radio78 = (bitrev4(i) << 1) | 0x0020;
-		b43_radio_write16(dev, 0x78, radio78);
-		udelay(10);
-		for (j = 0; j < 16; j++) {
-			b43_phy_write(dev, B43_PHY_CCK(0x5A), 0x0D80);
-			b43_phy_write(dev, B43_PHY_CCK(0x59), 0xC810);
-			b43_phy_write(dev, B43_PHY_CCK(0x58), 0x000D);
-			if (phy->gmode || phy->rev >= 2) {
-				b43_phy_write(dev, B43_PHY_RFOVERVAL,
-					      radio2050_rfover_val(dev,
-								   B43_PHY_RFOVERVAL,
-								   LPD(1, 0,
-								       1)));
-			}
-			b43_phy_write(dev, B43_PHY_PGACTL, 0xAFB0);
-			udelay(10);
-			if (phy->gmode || phy->rev >= 2) {
-				b43_phy_write(dev, B43_PHY_RFOVERVAL,
-					      radio2050_rfover_val(dev,
-								   B43_PHY_RFOVERVAL,
-								   LPD(1, 0,
-								       1)));
-			}
-			b43_phy_write(dev, B43_PHY_PGACTL, 0xEFB0);
-			udelay(10);
-			if (phy->gmode || phy->rev >= 2) {
-				b43_phy_write(dev, B43_PHY_RFOVERVAL,
-					      radio2050_rfover_val(dev,
-								   B43_PHY_RFOVERVAL,
-								   LPD(1, 0,
-								       0)));
-			}
-			b43_phy_write(dev, B43_PHY_PGACTL, 0xFFF0);
-			udelay(10);
-			tmp2 += b43_phy_read(dev, B43_PHY_LO_LEAKAGE);
-			b43_phy_write(dev, B43_PHY_CCK(0x58), 0);
-			if (phy->gmode || phy->rev >= 2) {
-				b43_phy_write(dev, B43_PHY_RFOVERVAL,
-					      radio2050_rfover_val(dev,
-								   B43_PHY_RFOVERVAL,
-								   LPD(1, 0,
-								       1)));
-			}
-			b43_phy_write(dev, B43_PHY_PGACTL, 0xAFB0);
-		}
-		tmp2++;
-		tmp2 >>= 8;
-		if (tmp1 < tmp2)
-			break;
-	}
-
-	/* Restore the registers */
-	b43_phy_write(dev, B43_PHY_PGACTL, sav.phy_pgactl);
-	b43_radio_write16(dev, 0x51, sav.radio_51);
-	b43_radio_write16(dev, 0x52, sav.radio_52);
-	b43_radio_write16(dev, 0x43, sav.radio_43);
-	b43_phy_write(dev, B43_PHY_CCK(0x5A), sav.phy_cck_5A);
-	b43_phy_write(dev, B43_PHY_CCK(0x59), sav.phy_cck_59);
-	b43_phy_write(dev, B43_PHY_CCK(0x58), sav.phy_cck_58);
-	b43_write16(dev, 0x3E6, sav.reg_3E6);
-	if (phy->analog != 0)
-		b43_write16(dev, 0x3F4, sav.reg_3F4);
-	b43_phy_write(dev, B43_PHY_SYNCCTL, sav.phy_syncctl);
-	b43_synth_pu_workaround(dev, phy->channel);
-	if (phy->type == B43_PHYTYPE_B) {
-		b43_phy_write(dev, B43_PHY_CCK(0x30), sav.phy_cck_30);
-		b43_write16(dev, 0x3EC, sav.reg_3EC);
-	} else if (phy->gmode) {
-		b43_write16(dev, B43_MMIO_PHY_RADIO,
-			    b43_read16(dev, B43_MMIO_PHY_RADIO)
-			    & 0x7FFF);
-		b43_phy_write(dev, B43_PHY_RFOVER, sav.phy_rfover);
-		b43_phy_write(dev, B43_PHY_RFOVERVAL, sav.phy_rfoverval);
-		b43_phy_write(dev, B43_PHY_ANALOGOVER, sav.phy_analogover);
-		b43_phy_write(dev, B43_PHY_ANALOGOVERVAL,
-			      sav.phy_analogoverval);
-		b43_phy_write(dev, B43_PHY_CRS0, sav.phy_crs0);
-		b43_phy_write(dev, B43_PHY_CLASSCTL, sav.phy_classctl);
-		if (has_loopback_gain(phy)) {
-			b43_phy_write(dev, B43_PHY_LO_MASK, sav.phy_lo_mask);
-			b43_phy_write(dev, B43_PHY_LO_CTL, sav.phy_lo_ctl);
-		}
-	}
-	if (i > 15)
-		ret = radio78;
-	else
-		ret = rcc;
-
-	return ret;
-}
-
-void b43_radio_init2060(struct b43_wldev *dev)
-{
-	int err;
-
-	b43_radio_write16(dev, 0x0004, 0x00C0);
-	b43_radio_write16(dev, 0x0005, 0x0008);
-	b43_radio_write16(dev, 0x0009, 0x0040);
-	b43_radio_write16(dev, 0x0005, 0x00AA);
-	b43_radio_write16(dev, 0x0032, 0x008F);
-	b43_radio_write16(dev, 0x0006, 0x008F);
-	b43_radio_write16(dev, 0x0034, 0x008F);
-	b43_radio_write16(dev, 0x002C, 0x0007);
-	b43_radio_write16(dev, 0x0082, 0x0080);
-	b43_radio_write16(dev, 0x0080, 0x0000);
-	b43_radio_write16(dev, 0x003F, 0x00DA);
-	b43_radio_write16(dev, 0x0005, b43_radio_read16(dev, 0x0005) & ~0x0008);
-	b43_radio_write16(dev, 0x0081, b43_radio_read16(dev, 0x0081) & ~0x0010);
-	b43_radio_write16(dev, 0x0081, b43_radio_read16(dev, 0x0081) & ~0x0020);
-	b43_radio_write16(dev, 0x0081, b43_radio_read16(dev, 0x0081) & ~0x0020);
-	msleep(1);		/* delay 400usec */
-
-	b43_radio_write16(dev, 0x0081,
-			  (b43_radio_read16(dev, 0x0081) & ~0x0020) | 0x0010);
-	msleep(1);		/* delay 400usec */
-
-	b43_radio_write16(dev, 0x0005,
-			  (b43_radio_read16(dev, 0x0005) & ~0x0008) | 0x0008);
-	b43_radio_write16(dev, 0x0085, b43_radio_read16(dev, 0x0085) & ~0x0010);
-	b43_radio_write16(dev, 0x0005, b43_radio_read16(dev, 0x0005) & ~0x0008);
-	b43_radio_write16(dev, 0x0081, b43_radio_read16(dev, 0x0081) & ~0x0040);
-	b43_radio_write16(dev, 0x0081,
-			  (b43_radio_read16(dev, 0x0081) & ~0x0040) | 0x0040);
-	b43_radio_write16(dev, 0x0005,
-			  (b43_radio_read16(dev, 0x0081) & ~0x0008) | 0x0008);
-	b43_phy_write(dev, 0x0063, 0xDDC6);
-	b43_phy_write(dev, 0x0069, 0x07BE);
-	b43_phy_write(dev, 0x006A, 0x0000);
-
-	err = b43_radio_selectchannel(dev, B43_DEFAULT_CHANNEL_A, 0);
-	B43_WARN_ON(err);
-
-	msleep(1);
-}
-
-static inline u16 freq_r3A_value(u16 frequency)
-{
-	u16 value;
-
-	if (frequency < 5091)
-		value = 0x0040;
-	else if (frequency < 5321)
-		value = 0x0000;
-	else if (frequency < 5806)
-		value = 0x0080;
-	else
-		value = 0x0040;
-
-	return value;
-}
-
-void b43_radio_set_tx_iq(struct b43_wldev *dev)
-{
-	static const u8 data_high[5] = { 0x00, 0x40, 0x80, 0x90, 0xD0 };
-	static const u8 data_low[5] = { 0x00, 0x01, 0x05, 0x06, 0x0A };
-	u16 tmp = b43_radio_read16(dev, 0x001E);
-	int i, j;
-
-	for (i = 0; i < 5; i++) {
-		for (j = 0; j < 5; j++) {
-			if (tmp == (data_high[i] << 4 | data_low[j])) {
-				b43_phy_write(dev, 0x0069,
-					      (i - j) << 8 | 0x00C0);
-				return;
-			}
-		}
-	}
-}
-
-int b43_radio_selectchannel(struct b43_wldev *dev,
-			    u8 channel, int synthetic_pu_workaround)
-{
-	struct b43_phy *phy = &dev->phy;
-	u16 r8, tmp;
-	u16 freq;
-	u16 channelcookie, savedcookie;
-	int err = 0;
-
-	if (channel == 0xFF) {
-		switch (phy->type) {
-		case B43_PHYTYPE_A:
-			channel = B43_DEFAULT_CHANNEL_A;
-			break;
-		case B43_PHYTYPE_B:
-		case B43_PHYTYPE_G:
-			channel = B43_DEFAULT_CHANNEL_BG;
-			break;
-		case B43_PHYTYPE_N:
-			//FIXME check if we are on 2.4GHz or 5GHz and set a default channel.
-			channel = 1;
-			break;
-		default:
-			B43_WARN_ON(1);
-		}
-	}
-
-	/* First we set the channel radio code to prevent the
-	 * firmware from sending ghost packets.
-	 */
-	channelcookie = channel;
-	if (0 /*FIXME on 5Ghz */)
-		channelcookie |= 0x100;
-	//FIXME set 40Mhz flag if required
-	savedcookie = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_CHAN);
-	b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_CHAN, channelcookie);
-
-	switch (phy->type) {
-	case B43_PHYTYPE_A:
-		if (channel > 200) {
-			err = -EINVAL;
-			goto out;
-		}
-		freq = channel2freq_a(channel);
-
-		r8 = b43_radio_read16(dev, 0x0008);
-		b43_write16(dev, 0x03F0, freq);
-		b43_radio_write16(dev, 0x0008, r8);
-
-		//TODO: write max channel TX power? to Radio 0x2D
-		tmp = b43_radio_read16(dev, 0x002E);
-		tmp &= 0x0080;
-		//TODO: OR tmp with the Power out estimation for this channel?
-		b43_radio_write16(dev, 0x002E, tmp);
-
-		if (freq >= 4920 && freq <= 5500) {
-			/*
-			 * r8 = (((freq * 15 * 0xE1FC780F) >> 32) / 29) & 0x0F;
-			 *    = (freq * 0.025862069
-			 */
-			r8 = 3 * freq / 116;	/* is equal to r8 = freq * 0.025862 */
-		}
-		b43_radio_write16(dev, 0x0007, (r8 << 4) | r8);
-		b43_radio_write16(dev, 0x0020, (r8 << 4) | r8);
-		b43_radio_write16(dev, 0x0021, (r8 << 4) | r8);
-		b43_radio_write16(dev, 0x0022, (b43_radio_read16(dev, 0x0022)
-						& 0x000F) | (r8 << 4));
-		b43_radio_write16(dev, 0x002A, (r8 << 4));
-		b43_radio_write16(dev, 0x002B, (r8 << 4));
-		b43_radio_write16(dev, 0x0008, (b43_radio_read16(dev, 0x0008)
-						& 0x00F0) | (r8 << 4));
-		b43_radio_write16(dev, 0x0029, (b43_radio_read16(dev, 0x0029)
-						& 0xFF0F) | 0x00B0);
-		b43_radio_write16(dev, 0x0035, 0x00AA);
-		b43_radio_write16(dev, 0x0036, 0x0085);
-		b43_radio_write16(dev, 0x003A, (b43_radio_read16(dev, 0x003A)
-						& 0xFF20) |
-				  freq_r3A_value(freq));
-		b43_radio_write16(dev, 0x003D,
-				  b43_radio_read16(dev, 0x003D) & 0x00FF);
-		b43_radio_write16(dev, 0x0081, (b43_radio_read16(dev, 0x0081)
-						& 0xFF7F) | 0x0080);
-		b43_radio_write16(dev, 0x0035,
-				  b43_radio_read16(dev, 0x0035) & 0xFFEF);
-		b43_radio_write16(dev, 0x0035, (b43_radio_read16(dev, 0x0035)
-						& 0xFFEF) | 0x0010);
-		b43_radio_set_tx_iq(dev);
-		//TODO: TSSI2dbm workaround
-		b43_phy_xmitpower(dev);	//FIXME correct?
-		break;
-	case B43_PHYTYPE_G:
-		if ((channel < 1) || (channel > 14)) {
-			err = -EINVAL;
-			goto out;
-		}
-
-		if (synthetic_pu_workaround)
-			b43_synth_pu_workaround(dev, channel);
-
-		b43_write16(dev, B43_MMIO_CHANNEL, channel2freq_bg(channel));
-
-		if (channel == 14) {
-			if (dev->dev->bus->sprom.country_code ==
-			    SSB_SPROM1CCODE_JAPAN)
-				b43_hf_write(dev,
-					     b43_hf_read(dev) & ~B43_HF_ACPR);
-			else
-				b43_hf_write(dev,
-					     b43_hf_read(dev) | B43_HF_ACPR);
-			b43_write16(dev, B43_MMIO_CHANNEL_EXT,
-				    b43_read16(dev, B43_MMIO_CHANNEL_EXT)
-				    | (1 << 11));
-		} else {
-			b43_write16(dev, B43_MMIO_CHANNEL_EXT,
-				    b43_read16(dev, B43_MMIO_CHANNEL_EXT)
-				    & 0xF7BF);
-		}
-		break;
-	case B43_PHYTYPE_N:
-		err = b43_nphy_selectchannel(dev, channel);
-		if (err)
-			goto out;
-		break;
-	default:
-		B43_WARN_ON(1);
-	}
-
-	phy->channel = channel;
-	/* Wait for the radio to tune to the channel and stabilize. */
-	msleep(8);
-out:
-	if (err) {
-		b43_shm_write16(dev, B43_SHM_SHARED,
-				B43_SHM_SH_CHAN, savedcookie);
-	}
-	return err;
-}
-
-void b43_radio_turn_on(struct b43_wldev *dev)
-{
-	struct b43_phy *phy = &dev->phy;
-	int err;
-	u8 channel;
-
-	might_sleep();
-
-	if (phy->radio_on)
-		return;
-
-	switch (phy->type) {
-	case B43_PHYTYPE_A:
-		b43_radio_write16(dev, 0x0004, 0x00C0);
-		b43_radio_write16(dev, 0x0005, 0x0008);
-		b43_phy_write(dev, 0x0010, b43_phy_read(dev, 0x0010) & 0xFFF7);
-		b43_phy_write(dev, 0x0011, b43_phy_read(dev, 0x0011) & 0xFFF7);
-		b43_radio_init2060(dev);
-		break;
-	case B43_PHYTYPE_B:
-	case B43_PHYTYPE_G:
-		b43_phy_write(dev, 0x0015, 0x8000);
-		b43_phy_write(dev, 0x0015, 0xCC00);
-		b43_phy_write(dev, 0x0015, (phy->gmode ? 0x00C0 : 0x0000));
-		if (phy->radio_off_context.valid) {
-			/* Restore the RFover values. */
-			b43_phy_write(dev, B43_PHY_RFOVER,
-				      phy->radio_off_context.rfover);
-			b43_phy_write(dev, B43_PHY_RFOVERVAL,
-				      phy->radio_off_context.rfoverval);
-			phy->radio_off_context.valid = 0;
-		}
-		channel = phy->channel;
-		err = b43_radio_selectchannel(dev, B43_DEFAULT_CHANNEL_BG, 1);
-		err |= b43_radio_selectchannel(dev, channel, 0);
-		B43_WARN_ON(err);
-		break;
-	case B43_PHYTYPE_N:
-		b43_nphy_radio_turn_on(dev);
-		break;
-	default:
-		B43_WARN_ON(1);
-	}
-	phy->radio_on = 1;
-}
-
-void b43_radio_turn_off(struct b43_wldev *dev, bool force)
-{
-	struct b43_phy *phy = &dev->phy;
-
-	if (!phy->radio_on && !force)
-		return;
-
-	switch (phy->type) {
-	case B43_PHYTYPE_N:
-		b43_nphy_radio_turn_off(dev);
-		break;
-	case B43_PHYTYPE_A:
-		b43_radio_write16(dev, 0x0004, 0x00FF);
-		b43_radio_write16(dev, 0x0005, 0x00FB);
-		b43_phy_write(dev, 0x0010, b43_phy_read(dev, 0x0010) | 0x0008);
-		b43_phy_write(dev, 0x0011, b43_phy_read(dev, 0x0011) | 0x0008);
-		break;
-	case B43_PHYTYPE_G: {
-		u16 rfover, rfoverval;
-
-		rfover = b43_phy_read(dev, B43_PHY_RFOVER);
-		rfoverval = b43_phy_read(dev, B43_PHY_RFOVERVAL);
-		if (!force) {
-			phy->radio_off_context.rfover = rfover;
-			phy->radio_off_context.rfoverval = rfoverval;
-			phy->radio_off_context.valid = 1;
-		}
-		b43_phy_write(dev, B43_PHY_RFOVER, rfover | 0x008C);
-		b43_phy_write(dev, B43_PHY_RFOVERVAL, rfoverval & 0xFF73);
-		break;
-	}
-	default:
-		B43_WARN_ON(1);
-	}
-	phy->radio_on = 0;
-}
diff --git a/drivers/net/wireless/b43/phy.h b/drivers/net/wireless/b43/phy.h
deleted file mode 100644
index 4aab109..0000000
--- a/drivers/net/wireless/b43/phy.h
+++ /dev/null
@@ -1,340 +0,0 @@
-#ifndef B43_PHY_H_
-#define B43_PHY_H_
-
-#include <linux/types.h>
-
-struct b43_wldev;
-struct b43_phy;
-
-/*** PHY Registers ***/
-
-/* Routing */
-#define B43_PHYROUTE			0x0C00 /* PHY register routing bits mask */
-#define  B43_PHYROUTE_BASE		0x0000 /* Base registers */
-#define  B43_PHYROUTE_OFDM_GPHY		0x0400 /* OFDM register routing for G-PHYs */
-#define  B43_PHYROUTE_EXT_GPHY		0x0800 /* Extended G-PHY registers */
-#define  B43_PHYROUTE_N_BMODE		0x0C00 /* N-PHY BMODE registers */
-
-/* CCK (B-PHY) registers. */
-#define B43_PHY_CCK(reg)		((reg) | B43_PHYROUTE_BASE)
-/* N-PHY registers. */
-#define B43_PHY_N(reg)			((reg) | B43_PHYROUTE_BASE)
-/* N-PHY BMODE registers. */
-#define B43_PHY_N_BMODE(reg)		((reg) | B43_PHYROUTE_N_BMODE)
-/* OFDM (A-PHY) registers. */
-#define B43_PHY_OFDM(reg)		((reg) | B43_PHYROUTE_OFDM_GPHY)
-/* Extended G-PHY registers. */
-#define B43_PHY_EXTG(reg)		((reg) | B43_PHYROUTE_EXT_GPHY)
-
-/* OFDM (A) PHY Registers */
-#define B43_PHY_VERSION_OFDM		B43_PHY_OFDM(0x00)	/* Versioning register for A-PHY */
-#define B43_PHY_BBANDCFG		B43_PHY_OFDM(0x01)	/* Baseband config */
-#define  B43_PHY_BBANDCFG_RXANT		0x180	/* RX Antenna selection */
-#define  B43_PHY_BBANDCFG_RXANT_SHIFT	7
-#define B43_PHY_PWRDOWN			B43_PHY_OFDM(0x03)	/* Powerdown */
-#define B43_PHY_CRSTHRES1_R1		B43_PHY_OFDM(0x06)	/* CRS Threshold 1 (phy.rev 1 only) */
-#define B43_PHY_LNAHPFCTL		B43_PHY_OFDM(0x1C)	/* LNA/HPF control */
-#define B43_PHY_LPFGAINCTL		B43_PHY_OFDM(0x20)	/* LPF Gain control */
-#define B43_PHY_ADIVRELATED		B43_PHY_OFDM(0x27)	/* FIXME rename */
-#define B43_PHY_CRS0			B43_PHY_OFDM(0x29)
-#define  B43_PHY_CRS0_EN		0x4000
-#define B43_PHY_PEAK_COUNT		B43_PHY_OFDM(0x30)
-#define B43_PHY_ANTDWELL		B43_PHY_OFDM(0x2B)	/* Antenna dwell */
-#define  B43_PHY_ANTDWELL_AUTODIV1	0x0100	/* Automatic RX diversity start antenna */
-#define B43_PHY_ENCORE			B43_PHY_OFDM(0x49)	/* "Encore" (RangeMax / BroadRange) */
-#define  B43_PHY_ENCORE_EN		0x0200	/* Encore enable */
-#define B43_PHY_LMS			B43_PHY_OFDM(0x55)
-#define B43_PHY_OFDM61			B43_PHY_OFDM(0x61)	/* FIXME rename */
-#define  B43_PHY_OFDM61_10		0x0010	/* FIXME rename */
-#define B43_PHY_IQBAL			B43_PHY_OFDM(0x69)	/* I/Q balance */
-#define B43_PHY_BBTXDC_BIAS		B43_PHY_OFDM(0x6B)	/* Baseband TX DC bias */
-#define B43_PHY_OTABLECTL		B43_PHY_OFDM(0x72)	/* OFDM table control (see below) */
-#define  B43_PHY_OTABLEOFF		0x03FF	/* OFDM table offset (see below) */
-#define  B43_PHY_OTABLENR		0xFC00	/* OFDM table number (see below) */
-#define  B43_PHY_OTABLENR_SHIFT		10
-#define B43_PHY_OTABLEI			B43_PHY_OFDM(0x73)	/* OFDM table data I */
-#define B43_PHY_OTABLEQ			B43_PHY_OFDM(0x74)	/* OFDM table data Q */
-#define B43_PHY_HPWR_TSSICTL		B43_PHY_OFDM(0x78)	/* Hardware power TSSI control */
-#define B43_PHY_ADCCTL			B43_PHY_OFDM(0x7A)	/* ADC control */
-#define B43_PHY_IDLE_TSSI		B43_PHY_OFDM(0x7B)
-#define B43_PHY_A_TEMP_SENSE		B43_PHY_OFDM(0x7C)	/* A PHY temperature sense */
-#define B43_PHY_NRSSITHRES		B43_PHY_OFDM(0x8A)	/* NRSSI threshold */
-#define B43_PHY_ANTWRSETT		B43_PHY_OFDM(0x8C)	/* Antenna WR settle */
-#define  B43_PHY_ANTWRSETT_ARXDIV	0x2000	/* Automatic RX diversity enabled */
-#define B43_PHY_CLIPPWRDOWNT		B43_PHY_OFDM(0x93)	/* Clip powerdown threshold */
-#define B43_PHY_OFDM9B			B43_PHY_OFDM(0x9B)	/* FIXME rename */
-#define B43_PHY_N1P1GAIN		B43_PHY_OFDM(0xA0)
-#define B43_PHY_P1P2GAIN		B43_PHY_OFDM(0xA1)
-#define B43_PHY_N1N2GAIN		B43_PHY_OFDM(0xA2)
-#define B43_PHY_CLIPTHRES		B43_PHY_OFDM(0xA3)
-#define B43_PHY_CLIPN1P2THRES		B43_PHY_OFDM(0xA4)
-#define B43_PHY_CCKSHIFTBITS_WA		B43_PHY_OFDM(0xA5)	/* CCK shiftbits workaround, FIXME rename */
-#define B43_PHY_CCKSHIFTBITS		B43_PHY_OFDM(0xA7)	/* FIXME rename */
-#define B43_PHY_DIVSRCHIDX		B43_PHY_OFDM(0xA8)	/* Divider search gain/index */
-#define B43_PHY_CLIPP2THRES		B43_PHY_OFDM(0xA9)
-#define B43_PHY_CLIPP3THRES		B43_PHY_OFDM(0xAA)
-#define B43_PHY_DIVP1P2GAIN		B43_PHY_OFDM(0xAB)
-#define B43_PHY_DIVSRCHGAINBACK		B43_PHY_OFDM(0xAD)	/* Divider search gain back */
-#define B43_PHY_DIVSRCHGAINCHNG		B43_PHY_OFDM(0xAE)	/* Divider search gain change */
-#define B43_PHY_CRSTHRES1		B43_PHY_OFDM(0xC0)	/* CRS Threshold 1 (phy.rev >= 2 only) */
-#define B43_PHY_CRSTHRES2		B43_PHY_OFDM(0xC1)	/* CRS Threshold 2 (phy.rev >= 2 only) */
-#define B43_PHY_TSSIP_LTBASE		B43_PHY_OFDM(0x380)	/* TSSI power lookup table base */
-#define B43_PHY_DC_LTBASE		B43_PHY_OFDM(0x3A0)	/* DC lookup table base */
-#define B43_PHY_GAIN_LTBASE		B43_PHY_OFDM(0x3C0)	/* Gain lookup table base */
-
-/* CCK (B) PHY Registers */
-#define B43_PHY_VERSION_CCK		B43_PHY_CCK(0x00)	/* Versioning register for B-PHY */
-#define B43_PHY_CCKBBANDCFG		B43_PHY_CCK(0x01)	/* Contains antenna 0/1 control bit */
-#define B43_PHY_PGACTL			B43_PHY_CCK(0x15)	/* PGA control */
-#define  B43_PHY_PGACTL_LPF		0x1000	/* Low pass filter (?) */
-#define  B43_PHY_PGACTL_LOWBANDW	0x0040	/* Low bandwidth flag */
-#define  B43_PHY_PGACTL_UNKNOWN		0xEFA0
-#define B43_PHY_FBCTL1			B43_PHY_CCK(0x18)	/* Frequency bandwidth control 1 */
-#define B43_PHY_ITSSI			B43_PHY_CCK(0x29)	/* Idle TSSI */
-#define B43_PHY_LO_LEAKAGE		B43_PHY_CCK(0x2D)	/* Measured LO leakage */
-#define B43_PHY_ENERGY			B43_PHY_CCK(0x33)	/* Energy */
-#define B43_PHY_SYNCCTL			B43_PHY_CCK(0x35)
-#define B43_PHY_FBCTL2			B43_PHY_CCK(0x38)	/* Frequency bandwidth control 2 */
-#define B43_PHY_DACCTL			B43_PHY_CCK(0x60)	/* DAC control */
-#define B43_PHY_RCCALOVER		B43_PHY_CCK(0x78)	/* RC calibration override */
-
-/* Extended G-PHY Registers */
-#define B43_PHY_CLASSCTL		B43_PHY_EXTG(0x02)	/* Classify control */
-#define B43_PHY_GTABCTL			B43_PHY_EXTG(0x03)	/* G-PHY table control (see below) */
-#define  B43_PHY_GTABOFF		0x03FF	/* G-PHY table offset (see below) */
-#define  B43_PHY_GTABNR			0xFC00	/* G-PHY table number (see below) */
-#define  B43_PHY_GTABNR_SHIFT		10
-#define B43_PHY_GTABDATA		B43_PHY_EXTG(0x04)	/* G-PHY table data */
-#define B43_PHY_LO_MASK			B43_PHY_EXTG(0x0F)	/* Local Oscillator control mask */
-#define B43_PHY_LO_CTL			B43_PHY_EXTG(0x10)	/* Local Oscillator control */
-#define B43_PHY_RFOVER			B43_PHY_EXTG(0x11)	/* RF override */
-#define B43_PHY_RFOVERVAL		B43_PHY_EXTG(0x12)	/* RF override value */
-#define  B43_PHY_RFOVERVAL_EXTLNA	0x8000
-#define  B43_PHY_RFOVERVAL_LNA		0x7000
-#define  B43_PHY_RFOVERVAL_LNA_SHIFT	12
-#define  B43_PHY_RFOVERVAL_PGA		0x0F00
-#define  B43_PHY_RFOVERVAL_PGA_SHIFT	8
-#define  B43_PHY_RFOVERVAL_UNK		0x0010	/* Unknown, always set. */
-#define  B43_PHY_RFOVERVAL_TRSWRX	0x00E0
-#define  B43_PHY_RFOVERVAL_BW		0x0003	/* Bandwidth flags */
-#define   B43_PHY_RFOVERVAL_BW_LPF	0x0001	/* Low Pass Filter */
-#define   B43_PHY_RFOVERVAL_BW_LBW	0x0002	/* Low Bandwidth (when set), high when unset */
-#define B43_PHY_ANALOGOVER		B43_PHY_EXTG(0x14)	/* Analog override */
-#define B43_PHY_ANALOGOVERVAL		B43_PHY_EXTG(0x15)	/* Analog override value */
-
-/*** OFDM table numbers ***/
-#define B43_OFDMTAB(number, offset)	(((number) << B43_PHY_OTABLENR_SHIFT) | (offset))
-#define B43_OFDMTAB_AGC1		B43_OFDMTAB(0x00, 0)
-#define B43_OFDMTAB_GAIN0		B43_OFDMTAB(0x00, 0)
-#define B43_OFDMTAB_GAINX		B43_OFDMTAB(0x01, 0)	//TODO rename
-#define B43_OFDMTAB_GAIN1		B43_OFDMTAB(0x01, 4)
-#define B43_OFDMTAB_AGC3		B43_OFDMTAB(0x02, 0)
-#define B43_OFDMTAB_GAIN2		B43_OFDMTAB(0x02, 3)
-#define B43_OFDMTAB_LNAHPFGAIN1		B43_OFDMTAB(0x03, 0)
-#define B43_OFDMTAB_WRSSI		B43_OFDMTAB(0x04, 0)
-#define B43_OFDMTAB_LNAHPFGAIN2		B43_OFDMTAB(0x04, 0)
-#define B43_OFDMTAB_NOISESCALE		B43_OFDMTAB(0x05, 0)
-#define B43_OFDMTAB_AGC2		B43_OFDMTAB(0x06, 0)
-#define B43_OFDMTAB_ROTOR		B43_OFDMTAB(0x08, 0)
-#define B43_OFDMTAB_ADVRETARD		B43_OFDMTAB(0x09, 0)
-#define B43_OFDMTAB_DAC			B43_OFDMTAB(0x0C, 0)
-#define B43_OFDMTAB_DC			B43_OFDMTAB(0x0E, 7)
-#define B43_OFDMTAB_PWRDYN2		B43_OFDMTAB(0x0E, 12)
-#define B43_OFDMTAB_LNAGAIN		B43_OFDMTAB(0x0E, 13)
-#define B43_OFDMTAB_UNKNOWN_0F		B43_OFDMTAB(0x0F, 0)	//TODO rename
-#define B43_OFDMTAB_UNKNOWN_APHY	B43_OFDMTAB(0x0F, 7)	//TODO rename
-#define B43_OFDMTAB_LPFGAIN		B43_OFDMTAB(0x0F, 12)
-#define B43_OFDMTAB_RSSI		B43_OFDMTAB(0x10, 0)
-#define B43_OFDMTAB_UNKNOWN_11		B43_OFDMTAB(0x11, 4)	//TODO rename
-#define B43_OFDMTAB_AGC1_R1		B43_OFDMTAB(0x13, 0)
-#define B43_OFDMTAB_GAINX_R1		B43_OFDMTAB(0x14, 0)	//TODO remove!
-#define B43_OFDMTAB_MINSIGSQ		B43_OFDMTAB(0x14, 0)
-#define B43_OFDMTAB_AGC3_R1		B43_OFDMTAB(0x15, 0)
-#define B43_OFDMTAB_WRSSI_R1		B43_OFDMTAB(0x15, 4)
-#define B43_OFDMTAB_TSSI		B43_OFDMTAB(0x15, 0)
-#define B43_OFDMTAB_DACRFPABB		B43_OFDMTAB(0x16, 0)
-#define B43_OFDMTAB_DACOFF		B43_OFDMTAB(0x17, 0)
-#define B43_OFDMTAB_DCBIAS		B43_OFDMTAB(0x18, 0)
-
-u16 b43_ofdmtab_read16(struct b43_wldev *dev, u16 table, u16 offset);
-void b43_ofdmtab_write16(struct b43_wldev *dev, u16 table,
-			 u16 offset, u16 value);
-u32 b43_ofdmtab_read32(struct b43_wldev *dev, u16 table, u16 offset);
-void b43_ofdmtab_write32(struct b43_wldev *dev, u16 table,
-			 u16 offset, u32 value);
-
-/*** G-PHY table numbers */
-#define B43_GTAB(number, offset)	(((number) << B43_PHY_GTABNR_SHIFT) | (offset))
-#define B43_GTAB_NRSSI			B43_GTAB(0x00, 0)
-#define B43_GTAB_TRFEMW			B43_GTAB(0x0C, 0x120)
-#define B43_GTAB_ORIGTR			B43_GTAB(0x2E, 0x298)
-
-u16 b43_gtab_read(struct b43_wldev *dev, u16 table, u16 offset);	//TODO implement
-void b43_gtab_write(struct b43_wldev *dev, u16 table, u16 offset, u16 value);	//TODO implement
-
-#define B43_DEFAULT_CHANNEL_A	36
-#define B43_DEFAULT_CHANNEL_BG	6
-
-enum {
-	B43_ANTENNA0,		/* Antenna 0 */
-	B43_ANTENNA1,		/* Antenna 0 */
-	B43_ANTENNA_AUTO1,	/* Automatic, starting with antenna 1 */
-	B43_ANTENNA_AUTO0,	/* Automatic, starting with antenna 0 */
-	B43_ANTENNA2,
-	B43_ANTENNA3 = 8,
-
-	B43_ANTENNA_AUTO = B43_ANTENNA_AUTO0,
-	B43_ANTENNA_DEFAULT = B43_ANTENNA_AUTO,
-};
-
-enum {
-	B43_INTERFMODE_NONE,
-	B43_INTERFMODE_NONWLAN,
-	B43_INTERFMODE_MANUALWLAN,
-	B43_INTERFMODE_AUTOWLAN,
-};
-
-/* Masks for the different PHY versioning registers. */
-#define B43_PHYVER_ANALOG		0xF000
-#define B43_PHYVER_ANALOG_SHIFT		12
-#define B43_PHYVER_TYPE			0x0F00
-#define B43_PHYVER_TYPE_SHIFT		8
-#define B43_PHYVER_VERSION		0x00FF
-
-void b43_phy_lock(struct b43_wldev *dev);
-void b43_phy_unlock(struct b43_wldev *dev);
-
-
-/* Read a value from a PHY register */
-u16 b43_phy_read(struct b43_wldev *dev, u16 offset);
-/* Write a value to a PHY register */
-void b43_phy_write(struct b43_wldev *dev, u16 offset, u16 val);
-/* Mask a PHY register with a mask */
-void b43_phy_mask(struct b43_wldev *dev, u16 offset, u16 mask);
-/* OR a PHY register with a bitmap */
-void b43_phy_set(struct b43_wldev *dev, u16 offset, u16 set);
-/* Mask and OR a PHY register with a mask and bitmap */
-void b43_phy_maskset(struct b43_wldev *dev, u16 offset, u16 mask, u16 set);
-
-
-int b43_phy_init_tssi2dbm_table(struct b43_wldev *dev);
-
-void b43_phy_early_init(struct b43_wldev *dev);
-int b43_phy_init(struct b43_wldev *dev);
-
-void b43_set_rx_antenna(struct b43_wldev *dev, int antenna);
-
-void b43_phy_xmitpower(struct b43_wldev *dev);
-
-/* Returns the boolean whether the board has HardwarePowerControl */
-bool b43_has_hardware_pctl(struct b43_phy *phy);
-/* Returns the boolean whether "TX Magnification" is enabled. */
-#define has_tx_magnification(phy) \
-	(((phy)->rev >= 2) &&			\
-	 ((phy)->radio_ver == 0x2050) &&	\
-	 ((phy)->radio_rev == 8))
-/* Card uses the loopback gain stuff */
-#define has_loopback_gain(phy) \
-	(((phy)->rev > 1) || ((phy)->gmode))
-
-/* Radio Attenuation (RF Attenuation) */
-struct b43_rfatt {
-	u8 att;			/* Attenuation value */
-	bool with_padmix;	/* Flag, PAD Mixer enabled. */
-};
-struct b43_rfatt_list {
-	/* Attenuation values list */
-	const struct b43_rfatt *list;
-	u8 len;
-	/* Minimum/Maximum attenuation values */
-	u8 min_val;
-	u8 max_val;
-};
-
-/* Returns true, if the values are the same. */
-static inline bool b43_compare_rfatt(const struct b43_rfatt *a,
-				     const struct b43_rfatt *b)
-{
-	return ((a->att == b->att) &&
-		(a->with_padmix == b->with_padmix));
-}
-
-/* Baseband Attenuation */
-struct b43_bbatt {
-	u8 att;			/* Attenuation value */
-};
-struct b43_bbatt_list {
-	/* Attenuation values list */
-	const struct b43_bbatt *list;
-	u8 len;
-	/* Minimum/Maximum attenuation values */
-	u8 min_val;
-	u8 max_val;
-};
-
-/* Returns true, if the values are the same. */
-static inline bool b43_compare_bbatt(const struct b43_bbatt *a,
-				     const struct b43_bbatt *b)
-{
-	return (a->att == b->att);
-}
-
-/* tx_control bits. */
-#define B43_TXCTL_PA3DB		0x40	/* PA Gain 3dB */
-#define B43_TXCTL_PA2DB		0x20	/* PA Gain 2dB */
-#define B43_TXCTL_TXMIX		0x10	/* TX Mixer Gain */
-
-/* Write BasebandAttenuation value to the device. */
-void b43_phy_set_baseband_attenuation(struct b43_wldev *dev,
-				      u16 baseband_attenuation);
-
-extern const u8 b43_radio_channel_codes_bg[];
-
-void b43_radio_lock(struct b43_wldev *dev);
-void b43_radio_unlock(struct b43_wldev *dev);
-
-
-/* Read a value from a 16bit radio register */
-u16 b43_radio_read16(struct b43_wldev *dev, u16 offset);
-/* Write a value to a 16bit radio register */
-void b43_radio_write16(struct b43_wldev *dev, u16 offset, u16 val);
-/* Mask a 16bit radio register with a mask */
-void b43_radio_mask(struct b43_wldev *dev, u16 offset, u16 mask);
-/* OR a 16bit radio register with a bitmap */
-void b43_radio_set(struct b43_wldev *dev, u16 offset, u16 set);
-/* Mask and OR a PHY register with a mask and bitmap */
-void b43_radio_maskset(struct b43_wldev *dev, u16 offset, u16 mask, u16 set);
-
-
-u16 b43_radio_init2050(struct b43_wldev *dev);
-void b43_radio_init2060(struct b43_wldev *dev);
-
-void b43_radio_turn_on(struct b43_wldev *dev);
-void b43_radio_turn_off(struct b43_wldev *dev, bool force);
-
-int b43_radio_selectchannel(struct b43_wldev *dev, u8 channel,
-			    int synthetic_pu_workaround);
-
-u8 b43_radio_aci_detect(struct b43_wldev *dev, u8 channel);
-u8 b43_radio_aci_scan(struct b43_wldev *dev);
-
-int b43_radio_set_interference_mitigation(struct b43_wldev *dev, int mode);
-
-void b43_calc_nrssi_slope(struct b43_wldev *dev);
-void b43_calc_nrssi_threshold(struct b43_wldev *dev);
-s16 b43_nrssi_hw_read(struct b43_wldev *dev, u16 offset);
-void b43_nrssi_hw_write(struct b43_wldev *dev, u16 offset, s16 val);
-void b43_nrssi_hw_update(struct b43_wldev *dev, u16 val);
-void b43_nrssi_mem_update(struct b43_wldev *dev);
-
-void b43_radio_set_tx_iq(struct b43_wldev *dev);
-u16 b43_radio_calibrationvalue(struct b43_wldev *dev);
-
-void b43_put_attenuation_into_ranges(struct b43_wldev *dev,
-				     int *_bbatt, int *_rfatt);
-
-void b43_set_txpower_g(struct b43_wldev *dev,
-		       const struct b43_bbatt *bbatt,
-		       const struct b43_rfatt *rfatt, u8 tx_control);
-
-#endif /* B43_PHY_H_ */
diff --git a/drivers/net/wireless/b43/phy_a.c b/drivers/net/wireless/b43/phy_a.c
new file mode 100644
index 0000000..0f1a84c
--- /dev/null
+++ b/drivers/net/wireless/b43/phy_a.c
@@ -0,0 +1,643 @@
+/*
+
+  Broadcom B43 wireless driver
+  IEEE 802.11a PHY driver
+
+  Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
+  Copyright (c) 2005-2007 Stefano Brivio <stefano.brivio@polimi.it>
+  Copyright (c) 2005-2008 Michael Buesch <mb@bu3sch.de>
+  Copyright (c) 2005, 2006 Danny van Dyk <kugelfang@gentoo.org>
+  Copyright (c) 2005, 2006 Andreas Jaggi <andreas.jaggi@waterwave.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; see the file COPYING.  If not, write to
+  the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+
+*/
+
+#include "b43.h"
+#include "phy_a.h"
+#include "phy_common.h"
+#include "wa.h"
+#include "tables.h"
+#include "main.h"
+
+
+/* Get the freq, as it has to be written to the device. */
+static inline u16 channel2freq_a(u8 channel)
+{
+	B43_WARN_ON(channel > 200);
+
+	return (5000 + 5 * channel);
+}
+
+static inline u16 freq_r3A_value(u16 frequency)
+{
+	u16 value;
+
+	if (frequency < 5091)
+		value = 0x0040;
+	else if (frequency < 5321)
+		value = 0x0000;
+	else if (frequency < 5806)
+		value = 0x0080;
+	else
+		value = 0x0040;
+
+	return value;
+}
+
+#if 0
+/* This function converts a TSSI value to dBm in Q5.2 */
+static s8 b43_aphy_estimate_power_out(struct b43_wldev *dev, s8 tssi)
+{
+	struct b43_phy *phy = &dev->phy;
+	struct b43_phy_a *aphy = phy->a;
+	s8 dbm = 0;
+	s32 tmp;
+
+	tmp = (aphy->tgt_idle_tssi - aphy->cur_idle_tssi + tssi);
+	tmp += 0x80;
+	tmp = clamp_val(tmp, 0x00, 0xFF);
+	dbm = aphy->tssi2dbm[tmp];
+	//TODO: There's a FIXME on the specs
+
+	return dbm;
+}
+#endif
+
+void b43_radio_set_tx_iq(struct b43_wldev *dev)
+{
+	static const u8 data_high[5] = { 0x00, 0x40, 0x80, 0x90, 0xD0 };
+	static const u8 data_low[5] = { 0x00, 0x01, 0x05, 0x06, 0x0A };
+	u16 tmp = b43_radio_read16(dev, 0x001E);
+	int i, j;
+
+	for (i = 0; i < 5; i++) {
+		for (j = 0; j < 5; j++) {
+			if (tmp == (data_high[i] << 4 | data_low[j])) {
+				b43_phy_write(dev, 0x0069,
+					      (i - j) << 8 | 0x00C0);
+				return;
+			}
+		}
+	}
+}
+
+static void aphy_channel_switch(struct b43_wldev *dev, unsigned int channel)
+{
+	u16 freq, r8, tmp;
+
+	freq = channel2freq_a(channel);
+
+	r8 = b43_radio_read16(dev, 0x0008);
+	b43_write16(dev, 0x03F0, freq);
+	b43_radio_write16(dev, 0x0008, r8);
+
+	//TODO: write max channel TX power? to Radio 0x2D
+	tmp = b43_radio_read16(dev, 0x002E);
+	tmp &= 0x0080;
+	//TODO: OR tmp with the Power out estimation for this channel?
+	b43_radio_write16(dev, 0x002E, tmp);
+
+	if (freq >= 4920 && freq <= 5500) {
+		/*
+		 * r8 = (((freq * 15 * 0xE1FC780F) >> 32) / 29) & 0x0F;
+		 *    = (freq * 0.025862069
+		 */
+		r8 = 3 * freq / 116;	/* is equal to r8 = freq * 0.025862 */
+	}
+	b43_radio_write16(dev, 0x0007, (r8 << 4) | r8);
+	b43_radio_write16(dev, 0x0020, (r8 << 4) | r8);
+	b43_radio_write16(dev, 0x0021, (r8 << 4) | r8);
+	b43_radio_write16(dev, 0x0022, (b43_radio_read16(dev, 0x0022)
+					& 0x000F) | (r8 << 4));
+	b43_radio_write16(dev, 0x002A, (r8 << 4));
+	b43_radio_write16(dev, 0x002B, (r8 << 4));
+	b43_radio_write16(dev, 0x0008, (b43_radio_read16(dev, 0x0008)
+					& 0x00F0) | (r8 << 4));
+	b43_radio_write16(dev, 0x0029, (b43_radio_read16(dev, 0x0029)
+					& 0xFF0F) | 0x00B0);
+	b43_radio_write16(dev, 0x0035, 0x00AA);
+	b43_radio_write16(dev, 0x0036, 0x0085);
+	b43_radio_write16(dev, 0x003A, (b43_radio_read16(dev, 0x003A)
+					& 0xFF20) |
+			  freq_r3A_value(freq));
+	b43_radio_write16(dev, 0x003D,
+			  b43_radio_read16(dev, 0x003D) & 0x00FF);
+	b43_radio_write16(dev, 0x0081, (b43_radio_read16(dev, 0x0081)
+					& 0xFF7F) | 0x0080);
+	b43_radio_write16(dev, 0x0035,
+			  b43_radio_read16(dev, 0x0035) & 0xFFEF);
+	b43_radio_write16(dev, 0x0035, (b43_radio_read16(dev, 0x0035)
+					& 0xFFEF) | 0x0010);
+	b43_radio_set_tx_iq(dev);
+	//TODO: TSSI2dbm workaround
+//FIXME	b43_phy_xmitpower(dev);
+}
+
+void b43_radio_init2060(struct b43_wldev *dev)
+{
+	b43_radio_write16(dev, 0x0004, 0x00C0);
+	b43_radio_write16(dev, 0x0005, 0x0008);
+	b43_radio_write16(dev, 0x0009, 0x0040);
+	b43_radio_write16(dev, 0x0005, 0x00AA);
+	b43_radio_write16(dev, 0x0032, 0x008F);
+	b43_radio_write16(dev, 0x0006, 0x008F);
+	b43_radio_write16(dev, 0x0034, 0x008F);
+	b43_radio_write16(dev, 0x002C, 0x0007);
+	b43_radio_write16(dev, 0x0082, 0x0080);
+	b43_radio_write16(dev, 0x0080, 0x0000);
+	b43_radio_write16(dev, 0x003F, 0x00DA);
+	b43_radio_write16(dev, 0x0005, b43_radio_read16(dev, 0x0005) & ~0x0008);
+	b43_radio_write16(dev, 0x0081, b43_radio_read16(dev, 0x0081) & ~0x0010);
+	b43_radio_write16(dev, 0x0081, b43_radio_read16(dev, 0x0081) & ~0x0020);
+	b43_radio_write16(dev, 0x0081, b43_radio_read16(dev, 0x0081) & ~0x0020);
+	msleep(1);		/* delay 400usec */
+
+	b43_radio_write16(dev, 0x0081,
+			  (b43_radio_read16(dev, 0x0081) & ~0x0020) | 0x0010);
+	msleep(1);		/* delay 400usec */
+
+	b43_radio_write16(dev, 0x0005,
+			  (b43_radio_read16(dev, 0x0005) & ~0x0008) | 0x0008);
+	b43_radio_write16(dev, 0x0085, b43_radio_read16(dev, 0x0085) & ~0x0010);
+	b43_radio_write16(dev, 0x0005, b43_radio_read16(dev, 0x0005) & ~0x0008);
+	b43_radio_write16(dev, 0x0081, b43_radio_read16(dev, 0x0081) & ~0x0040);
+	b43_radio_write16(dev, 0x0081,
+			  (b43_radio_read16(dev, 0x0081) & ~0x0040) | 0x0040);
+	b43_radio_write16(dev, 0x0005,
+			  (b43_radio_read16(dev, 0x0081) & ~0x0008) | 0x0008);
+	b43_phy_write(dev, 0x0063, 0xDDC6);
+	b43_phy_write(dev, 0x0069, 0x07BE);
+	b43_phy_write(dev, 0x006A, 0x0000);
+
+	aphy_channel_switch(dev, dev->phy.ops->get_default_chan(dev));
+
+	msleep(1);
+}
+
+static void b43_phy_rssiagc(struct b43_wldev *dev, u8 enable)
+{
+	int i;
+
+	if (dev->phy.rev < 3) {
+		if (enable)
+			for (i = 0; i < B43_TAB_RSSIAGC1_SIZE; i++) {
+				b43_ofdmtab_write16(dev,
+					B43_OFDMTAB_LNAHPFGAIN1, i, 0xFFF8);
+				b43_ofdmtab_write16(dev,
+					B43_OFDMTAB_WRSSI, i, 0xFFF8);
+			}
+		else
+			for (i = 0; i < B43_TAB_RSSIAGC1_SIZE; i++) {
+				b43_ofdmtab_write16(dev,
+					B43_OFDMTAB_LNAHPFGAIN1, i, b43_tab_rssiagc1[i]);
+				b43_ofdmtab_write16(dev,
+					B43_OFDMTAB_WRSSI, i, b43_tab_rssiagc1[i]);
+			}
+	} else {
+		if (enable)
+			for (i = 0; i < B43_TAB_RSSIAGC1_SIZE; i++)
+				b43_ofdmtab_write16(dev,
+					B43_OFDMTAB_WRSSI, i, 0x0820);
+		else
+			for (i = 0; i < B43_TAB_RSSIAGC2_SIZE; i++)
+				b43_ofdmtab_write16(dev,
+					B43_OFDMTAB_WRSSI, i, b43_tab_rssiagc2[i]);
+	}
+}
+
+static void b43_phy_ww(struct b43_wldev *dev)
+{
+	u16 b, curr_s, best_s = 0xFFFF;
+	int i;
+
+	b43_phy_write(dev, B43_PHY_CRS0,
+		b43_phy_read(dev, B43_PHY_CRS0) & ~B43_PHY_CRS0_EN);
+	b43_phy_write(dev, B43_PHY_OFDM(0x1B),
+		b43_phy_read(dev, B43_PHY_OFDM(0x1B)) | 0x1000);
+	b43_phy_write(dev, B43_PHY_OFDM(0x82),
+		(b43_phy_read(dev, B43_PHY_OFDM(0x82)) & 0xF0FF) | 0x0300);
+	b43_radio_write16(dev, 0x0009,
+		b43_radio_read16(dev, 0x0009) | 0x0080);
+	b43_radio_write16(dev, 0x0012,
+		(b43_radio_read16(dev, 0x0012) & 0xFFFC) | 0x0002);
+	b43_wa_initgains(dev);
+	b43_phy_write(dev, B43_PHY_OFDM(0xBA), 0x3ED5);
+	b = b43_phy_read(dev, B43_PHY_PWRDOWN);
+	b43_phy_write(dev, B43_PHY_PWRDOWN, (b & 0xFFF8) | 0x0005);
+	b43_radio_write16(dev, 0x0004,
+		b43_radio_read16(dev, 0x0004) | 0x0004);
+	for (i = 0x10; i <= 0x20; i++) {
+		b43_radio_write16(dev, 0x0013, i);
+		curr_s = b43_phy_read(dev, B43_PHY_OTABLEQ) & 0x00FF;
+		if (!curr_s) {
+			best_s = 0x0000;
+			break;
+		} else if (curr_s >= 0x0080)
+			curr_s = 0x0100 - curr_s;
+		if (curr_s < best_s)
+			best_s = curr_s;
+	}
+	b43_phy_write(dev, B43_PHY_PWRDOWN, b);
+	b43_radio_write16(dev, 0x0004,
+		b43_radio_read16(dev, 0x0004) & 0xFFFB);
+	b43_radio_write16(dev, 0x0013, best_s);
+	b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1_R1, 0, 0xFFEC);
+	b43_phy_write(dev, B43_PHY_OFDM(0xB7), 0x1E80);
+	b43_phy_write(dev, B43_PHY_OFDM(0xB6), 0x1C00);
+	b43_phy_write(dev, B43_PHY_OFDM(0xB5), 0x0EC0);
+	b43_phy_write(dev, B43_PHY_OFDM(0xB2), 0x00C0);
+	b43_phy_write(dev, B43_PHY_OFDM(0xB9), 0x1FFF);
+	b43_phy_write(dev, B43_PHY_OFDM(0xBB),
+		(b43_phy_read(dev, B43_PHY_OFDM(0xBB)) & 0xF000) | 0x0053);
+	b43_phy_write(dev, B43_PHY_OFDM61,
+		(b43_phy_read(dev, B43_PHY_OFDM61) & 0xFE1F) | 0x0120);
+	b43_phy_write(dev, B43_PHY_OFDM(0x13),
+		(b43_phy_read(dev, B43_PHY_OFDM(0x13)) & 0x0FFF) | 0x3000);
+	b43_phy_write(dev, B43_PHY_OFDM(0x14),
+		(b43_phy_read(dev, B43_PHY_OFDM(0x14)) & 0x0FFF) | 0x3000);
+	b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, 6, 0x0017);
+	for (i = 0; i < 6; i++)
+		b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, i, 0x000F);
+	b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, 0x0D, 0x000E);
+	b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, 0x0E, 0x0011);
+	b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, 0x0F, 0x0013);
+	b43_phy_write(dev, B43_PHY_OFDM(0x33), 0x5030);
+	b43_phy_write(dev, B43_PHY_CRS0,
+		b43_phy_read(dev, B43_PHY_CRS0) | B43_PHY_CRS0_EN);
+}
+
+static void hardware_pctl_init_aphy(struct b43_wldev *dev)
+{
+	//TODO
+}
+
+void b43_phy_inita(struct b43_wldev *dev)
+{
+	struct ssb_bus *bus = dev->dev->bus;
+	struct b43_phy *phy = &dev->phy;
+
+	/* This lowlevel A-PHY init is also called from G-PHY init.
+	 * So we must not access phy->a, if called from G-PHY code.
+	 */
+	B43_WARN_ON((phy->type != B43_PHYTYPE_A) &&
+		    (phy->type != B43_PHYTYPE_G));
+
+	might_sleep();
+
+	if (phy->rev >= 6) {
+		if (phy->type == B43_PHYTYPE_A)
+			b43_phy_write(dev, B43_PHY_OFDM(0x1B),
+				b43_phy_read(dev, B43_PHY_OFDM(0x1B)) & ~0x1000);
+		if (b43_phy_read(dev, B43_PHY_ENCORE) & B43_PHY_ENCORE_EN)
+			b43_phy_write(dev, B43_PHY_ENCORE,
+				b43_phy_read(dev, B43_PHY_ENCORE) | 0x0010);
+		else
+			b43_phy_write(dev, B43_PHY_ENCORE,
+				b43_phy_read(dev, B43_PHY_ENCORE) & ~0x1010);
+	}
+
+	b43_wa_all(dev);
+
+	if (phy->type == B43_PHYTYPE_A) {
+		if (phy->gmode && (phy->rev < 3))
+			b43_phy_write(dev, 0x0034,
+				b43_phy_read(dev, 0x0034) | 0x0001);
+		b43_phy_rssiagc(dev, 0);
+
+		b43_phy_write(dev, B43_PHY_CRS0,
+			b43_phy_read(dev, B43_PHY_CRS0) | B43_PHY_CRS0_EN);
+
+		b43_radio_init2060(dev);
+
+		if ((bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM) &&
+		    ((bus->boardinfo.type == SSB_BOARD_BU4306) ||
+		     (bus->boardinfo.type == SSB_BOARD_BU4309))) {
+			; //TODO: A PHY LO
+		}
+
+		if (phy->rev >= 3)
+			b43_phy_ww(dev);
+
+		hardware_pctl_init_aphy(dev);
+
+		//TODO: radar detection
+	}
+
+	if ((phy->type == B43_PHYTYPE_G) &&
+	    (dev->dev->bus->sprom.boardflags_lo & B43_BFL_PACTRL)) {
+		b43_phy_write(dev, B43_PHY_OFDM(0x6E),
+				  (b43_phy_read(dev, B43_PHY_OFDM(0x6E))
+				   & 0xE000) | 0x3CF);
+	}
+}
+
+/* Initialise the TSSI->dBm lookup table */
+static int b43_aphy_init_tssi2dbm_table(struct b43_wldev *dev)
+{
+	struct b43_phy *phy = &dev->phy;
+	struct b43_phy_a *aphy = phy->a;
+	s16 pab0, pab1, pab2;
+
+	pab0 = (s16) (dev->dev->bus->sprom.pa1b0);
+	pab1 = (s16) (dev->dev->bus->sprom.pa1b1);
+	pab2 = (s16) (dev->dev->bus->sprom.pa1b2);
+
+	if (pab0 != 0 && pab1 != 0 && pab2 != 0 &&
+	    pab0 != -1 && pab1 != -1 && pab2 != -1) {
+		/* The pabX values are set in SPROM. Use them. */
+		if ((s8) dev->dev->bus->sprom.itssi_a != 0 &&
+		    (s8) dev->dev->bus->sprom.itssi_a != -1)
+			aphy->tgt_idle_tssi =
+			    (s8) (dev->dev->bus->sprom.itssi_a);
+		else
+			aphy->tgt_idle_tssi = 62;
+		aphy->tssi2dbm = b43_generate_dyn_tssi2dbm_tab(dev, pab0,
+							       pab1, pab2);
+		if (!aphy->tssi2dbm)
+			return -ENOMEM;
+	} else {
+		/* pabX values not set in SPROM,
+		 * but APHY needs a generated table. */
+		aphy->tssi2dbm = NULL;
+		b43err(dev->wl, "Could not generate tssi2dBm "
+		       "table (wrong SPROM info)!\n");
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+static int b43_aphy_op_allocate(struct b43_wldev *dev)
+{
+	struct b43_phy_a *aphy;
+	int err;
+
+	aphy = kzalloc(sizeof(*aphy), GFP_KERNEL);
+	if (!aphy)
+		return -ENOMEM;
+	dev->phy.a = aphy;
+
+	err = b43_aphy_init_tssi2dbm_table(dev);
+	if (err)
+		goto err_free_aphy;
+
+	return 0;
+
+err_free_aphy:
+	kfree(aphy);
+	dev->phy.a = NULL;
+
+	return err;
+}
+
+static void b43_aphy_op_prepare_structs(struct b43_wldev *dev)
+{
+	struct b43_phy *phy = &dev->phy;
+	struct b43_phy_a *aphy = phy->a;
+	const void *tssi2dbm;
+	int tgt_idle_tssi;
+
+	/* tssi2dbm table is constant, so it is initialized at alloc time.
+	 * Save a copy of the pointer. */
+	tssi2dbm = aphy->tssi2dbm;
+	tgt_idle_tssi = aphy->tgt_idle_tssi;
+
+	/* Zero out the whole PHY structure. */
+	memset(aphy, 0, sizeof(*aphy));
+
+	aphy->tssi2dbm = tssi2dbm;
+	aphy->tgt_idle_tssi = tgt_idle_tssi;
+
+	//TODO init struct b43_phy_a
+
+}
+
+static void b43_aphy_op_free(struct b43_wldev *dev)
+{
+	struct b43_phy *phy = &dev->phy;
+	struct b43_phy_a *aphy = phy->a;
+
+	kfree(aphy->tssi2dbm);
+	aphy->tssi2dbm = NULL;
+
+	kfree(aphy);
+	dev->phy.a = NULL;
+}
+
+static int b43_aphy_op_init(struct b43_wldev *dev)
+{
+	b43_phy_inita(dev);
+
+	return 0;
+}
+
+static inline u16 adjust_phyreg(struct b43_wldev *dev, u16 offset)
+{
+	/* OFDM registers are base-registers for the A-PHY. */
+	if ((offset & B43_PHYROUTE) == B43_PHYROUTE_OFDM_GPHY) {
+		offset &= ~B43_PHYROUTE;
+		offset |= B43_PHYROUTE_BASE;
+	}
+
+#if B43_DEBUG
+	if ((offset & B43_PHYROUTE) == B43_PHYROUTE_EXT_GPHY) {
+		/* Ext-G registers are only available on G-PHYs */
+		b43err(dev->wl, "Invalid EXT-G PHY access at "
+		       "0x%04X on A-PHY\n", offset);
+		dump_stack();
+	}
+	if ((offset & B43_PHYROUTE) == B43_PHYROUTE_N_BMODE) {
+		/* N-BMODE registers are only available on N-PHYs */
+		b43err(dev->wl, "Invalid N-BMODE PHY access at "
+		       "0x%04X on A-PHY\n", offset);
+		dump_stack();
+	}
+#endif /* B43_DEBUG */
+
+	return offset;
+}
+
+static u16 b43_aphy_op_read(struct b43_wldev *dev, u16 reg)
+{
+	reg = adjust_phyreg(dev, reg);
+	b43_write16(dev, B43_MMIO_PHY_CONTROL, reg);
+	return b43_read16(dev, B43_MMIO_PHY_DATA);
+}
+
+static void b43_aphy_op_write(struct b43_wldev *dev, u16 reg, u16 value)
+{
+	reg = adjust_phyreg(dev, reg);
+	b43_write16(dev, B43_MMIO_PHY_CONTROL, reg);
+	b43_write16(dev, B43_MMIO_PHY_DATA, value);
+}
+
+static u16 b43_aphy_op_radio_read(struct b43_wldev *dev, u16 reg)
+{
+	/* Register 1 is a 32-bit register. */
+	B43_WARN_ON(reg == 1);
+	/* A-PHY needs 0x40 for read access */
+	reg |= 0x40;
+
+	b43_write16(dev, B43_MMIO_RADIO_CONTROL, reg);
+	return b43_read16(dev, B43_MMIO_RADIO_DATA_LOW);
+}
+
+static void b43_aphy_op_radio_write(struct b43_wldev *dev, u16 reg, u16 value)
+{
+	/* Register 1 is a 32-bit register. */
+	B43_WARN_ON(reg == 1);
+
+	b43_write16(dev, B43_MMIO_RADIO_CONTROL, reg);
+	b43_write16(dev, B43_MMIO_RADIO_DATA_LOW, value);
+}
+
+static bool b43_aphy_op_supports_hwpctl(struct b43_wldev *dev)
+{
+	return (dev->phy.rev >= 5);
+}
+
+static void b43_aphy_op_software_rfkill(struct b43_wldev *dev,
+					enum rfkill_state state)
+{
+	struct b43_phy *phy = &dev->phy;
+
+	if (state == RFKILL_STATE_UNBLOCKED) {
+		if (phy->radio_on)
+			return;
+		b43_radio_write16(dev, 0x0004, 0x00C0);
+		b43_radio_write16(dev, 0x0005, 0x0008);
+		b43_phy_write(dev, 0x0010, b43_phy_read(dev, 0x0010) & 0xFFF7);
+		b43_phy_write(dev, 0x0011, b43_phy_read(dev, 0x0011) & 0xFFF7);
+		b43_radio_init2060(dev);
+	} else {
+		b43_radio_write16(dev, 0x0004, 0x00FF);
+		b43_radio_write16(dev, 0x0005, 0x00FB);
+		b43_phy_write(dev, 0x0010, b43_phy_read(dev, 0x0010) | 0x0008);
+		b43_phy_write(dev, 0x0011, b43_phy_read(dev, 0x0011) | 0x0008);
+	}
+}
+
+static int b43_aphy_op_switch_channel(struct b43_wldev *dev,
+				      unsigned int new_channel)
+{
+	if (new_channel > 200)
+		return -EINVAL;
+	aphy_channel_switch(dev, new_channel);
+
+	return 0;
+}
+
+static unsigned int b43_aphy_op_get_default_chan(struct b43_wldev *dev)
+{
+	return 36; /* Default to channel 36 */
+}
+
+static void b43_aphy_op_set_rx_antenna(struct b43_wldev *dev, int antenna)
+{//TODO
+	struct b43_phy *phy = &dev->phy;
+	u64 hf;
+	u16 tmp;
+	int autodiv = 0;
+
+	if (antenna == B43_ANTENNA_AUTO0 || antenna == B43_ANTENNA_AUTO1)
+		autodiv = 1;
+
+	hf = b43_hf_read(dev);
+	hf &= ~B43_HF_ANTDIVHELP;
+	b43_hf_write(dev, hf);
+
+	tmp = b43_phy_read(dev, B43_PHY_BBANDCFG);
+	tmp &= ~B43_PHY_BBANDCFG_RXANT;
+	tmp |= (autodiv ? B43_ANTENNA_AUTO0 : antenna)
+	    << B43_PHY_BBANDCFG_RXANT_SHIFT;
+	b43_phy_write(dev, B43_PHY_BBANDCFG, tmp);
+
+	if (autodiv) {
+		tmp = b43_phy_read(dev, B43_PHY_ANTDWELL);
+		if (antenna == B43_ANTENNA_AUTO0)
+			tmp &= ~B43_PHY_ANTDWELL_AUTODIV1;
+		else
+			tmp |= B43_PHY_ANTDWELL_AUTODIV1;
+		b43_phy_write(dev, B43_PHY_ANTDWELL, tmp);
+	}
+	if (phy->rev < 3) {
+		tmp = b43_phy_read(dev, B43_PHY_ANTDWELL);
+		tmp = (tmp & 0xFF00) | 0x24;
+		b43_phy_write(dev, B43_PHY_ANTDWELL, tmp);
+	} else {
+		tmp = b43_phy_read(dev, B43_PHY_OFDM61);
+		tmp |= 0x10;
+		b43_phy_write(dev, B43_PHY_OFDM61, tmp);
+		if (phy->analog == 3) {
+			b43_phy_write(dev, B43_PHY_CLIPPWRDOWNT,
+				      0x1D);
+			b43_phy_write(dev, B43_PHY_ADIVRELATED,
+				      8);
+		} else {
+			b43_phy_write(dev, B43_PHY_CLIPPWRDOWNT,
+				      0x3A);
+			tmp =
+			    b43_phy_read(dev,
+					 B43_PHY_ADIVRELATED);
+			tmp = (tmp & 0xFF00) | 8;
+			b43_phy_write(dev, B43_PHY_ADIVRELATED,
+				      tmp);
+		}
+	}
+
+	hf |= B43_HF_ANTDIVHELP;
+	b43_hf_write(dev, hf);
+}
+
+static void b43_aphy_op_adjust_txpower(struct b43_wldev *dev)
+{//TODO
+}
+
+static enum b43_txpwr_result b43_aphy_op_recalc_txpower(struct b43_wldev *dev,
+							bool ignore_tssi)
+{//TODO
+	return B43_TXPWR_RES_DONE;
+}
+
+static void b43_aphy_op_pwork_15sec(struct b43_wldev *dev)
+{//TODO
+}
+
+static void b43_aphy_op_pwork_60sec(struct b43_wldev *dev)
+{//TODO
+}
+
+const struct b43_phy_operations b43_phyops_a = {
+	.allocate		= b43_aphy_op_allocate,
+	.free			= b43_aphy_op_free,
+	.prepare_structs	= b43_aphy_op_prepare_structs,
+	.init			= b43_aphy_op_init,
+	.phy_read		= b43_aphy_op_read,
+	.phy_write		= b43_aphy_op_write,
+	.radio_read		= b43_aphy_op_radio_read,
+	.radio_write		= b43_aphy_op_radio_write,
+	.supports_hwpctl	= b43_aphy_op_supports_hwpctl,
+	.software_rfkill	= b43_aphy_op_software_rfkill,
+	.switch_analog		= b43_phyop_switch_analog_generic,
+	.switch_channel		= b43_aphy_op_switch_channel,
+	.get_default_chan	= b43_aphy_op_get_default_chan,
+	.set_rx_antenna		= b43_aphy_op_set_rx_antenna,
+	.recalc_txpower		= b43_aphy_op_recalc_txpower,
+	.adjust_txpower		= b43_aphy_op_adjust_txpower,
+	.pwork_15sec		= b43_aphy_op_pwork_15sec,
+	.pwork_60sec		= b43_aphy_op_pwork_60sec,
+};
diff --git a/drivers/net/wireless/b43/phy_a.h b/drivers/net/wireless/b43/phy_a.h
new file mode 100644
index 0000000..5cfaab7
--- /dev/null
+++ b/drivers/net/wireless/b43/phy_a.h
@@ -0,0 +1,130 @@
+#ifndef LINUX_B43_PHY_A_H_
+#define LINUX_B43_PHY_A_H_
+
+#include "phy_common.h"
+
+
+/* OFDM (A) PHY Registers */
+#define B43_PHY_VERSION_OFDM		B43_PHY_OFDM(0x00)	/* Versioning register for A-PHY */
+#define B43_PHY_BBANDCFG		B43_PHY_OFDM(0x01)	/* Baseband config */
+#define  B43_PHY_BBANDCFG_RXANT		0x180	/* RX Antenna selection */
+#define  B43_PHY_BBANDCFG_RXANT_SHIFT	7
+#define B43_PHY_PWRDOWN			B43_PHY_OFDM(0x03)	/* Powerdown */
+#define B43_PHY_CRSTHRES1_R1		B43_PHY_OFDM(0x06)	/* CRS Threshold 1 (phy.rev 1 only) */
+#define B43_PHY_LNAHPFCTL		B43_PHY_OFDM(0x1C)	/* LNA/HPF control */
+#define B43_PHY_LPFGAINCTL		B43_PHY_OFDM(0x20)	/* LPF Gain control */
+#define B43_PHY_ADIVRELATED		B43_PHY_OFDM(0x27)	/* FIXME rename */
+#define B43_PHY_CRS0			B43_PHY_OFDM(0x29)
+#define  B43_PHY_CRS0_EN		0x4000
+#define B43_PHY_PEAK_COUNT		B43_PHY_OFDM(0x30)
+#define B43_PHY_ANTDWELL		B43_PHY_OFDM(0x2B)	/* Antenna dwell */
+#define  B43_PHY_ANTDWELL_AUTODIV1	0x0100	/* Automatic RX diversity start antenna */
+#define B43_PHY_ENCORE			B43_PHY_OFDM(0x49)	/* "Encore" (RangeMax / BroadRange) */
+#define  B43_PHY_ENCORE_EN		0x0200	/* Encore enable */
+#define B43_PHY_LMS			B43_PHY_OFDM(0x55)
+#define B43_PHY_OFDM61			B43_PHY_OFDM(0x61)	/* FIXME rename */
+#define  B43_PHY_OFDM61_10		0x0010	/* FIXME rename */
+#define B43_PHY_IQBAL			B43_PHY_OFDM(0x69)	/* I/Q balance */
+#define B43_PHY_BBTXDC_BIAS		B43_PHY_OFDM(0x6B)	/* Baseband TX DC bias */
+#define B43_PHY_OTABLECTL		B43_PHY_OFDM(0x72)	/* OFDM table control (see below) */
+#define  B43_PHY_OTABLEOFF		0x03FF	/* OFDM table offset (see below) */
+#define  B43_PHY_OTABLENR		0xFC00	/* OFDM table number (see below) */
+#define  B43_PHY_OTABLENR_SHIFT		10
+#define B43_PHY_OTABLEI			B43_PHY_OFDM(0x73)	/* OFDM table data I */
+#define B43_PHY_OTABLEQ			B43_PHY_OFDM(0x74)	/* OFDM table data Q */
+#define B43_PHY_HPWR_TSSICTL		B43_PHY_OFDM(0x78)	/* Hardware power TSSI control */
+#define B43_PHY_ADCCTL			B43_PHY_OFDM(0x7A)	/* ADC control */
+#define B43_PHY_IDLE_TSSI		B43_PHY_OFDM(0x7B)
+#define B43_PHY_A_TEMP_SENSE		B43_PHY_OFDM(0x7C)	/* A PHY temperature sense */
+#define B43_PHY_NRSSITHRES		B43_PHY_OFDM(0x8A)	/* NRSSI threshold */
+#define B43_PHY_ANTWRSETT		B43_PHY_OFDM(0x8C)	/* Antenna WR settle */
+#define  B43_PHY_ANTWRSETT_ARXDIV	0x2000	/* Automatic RX diversity enabled */
+#define B43_PHY_CLIPPWRDOWNT		B43_PHY_OFDM(0x93)	/* Clip powerdown threshold */
+#define B43_PHY_OFDM9B			B43_PHY_OFDM(0x9B)	/* FIXME rename */
+#define B43_PHY_N1P1GAIN		B43_PHY_OFDM(0xA0)
+#define B43_PHY_P1P2GAIN		B43_PHY_OFDM(0xA1)
+#define B43_PHY_N1N2GAIN		B43_PHY_OFDM(0xA2)
+#define B43_PHY_CLIPTHRES		B43_PHY_OFDM(0xA3)
+#define B43_PHY_CLIPN1P2THRES		B43_PHY_OFDM(0xA4)
+#define B43_PHY_CCKSHIFTBITS_WA		B43_PHY_OFDM(0xA5)	/* CCK shiftbits workaround, FIXME rename */
+#define B43_PHY_CCKSHIFTBITS		B43_PHY_OFDM(0xA7)	/* FIXME rename */
+#define B43_PHY_DIVSRCHIDX		B43_PHY_OFDM(0xA8)	/* Divider search gain/index */
+#define B43_PHY_CLIPP2THRES		B43_PHY_OFDM(0xA9)
+#define B43_PHY_CLIPP3THRES		B43_PHY_OFDM(0xAA)
+#define B43_PHY_DIVP1P2GAIN		B43_PHY_OFDM(0xAB)
+#define B43_PHY_DIVSRCHGAINBACK		B43_PHY_OFDM(0xAD)	/* Divider search gain back */
+#define B43_PHY_DIVSRCHGAINCHNG		B43_PHY_OFDM(0xAE)	/* Divider search gain change */
+#define B43_PHY_CRSTHRES1		B43_PHY_OFDM(0xC0)	/* CRS Threshold 1 (phy.rev >= 2 only) */
+#define B43_PHY_CRSTHRES2		B43_PHY_OFDM(0xC1)	/* CRS Threshold 2 (phy.rev >= 2 only) */
+#define B43_PHY_TSSIP_LTBASE		B43_PHY_OFDM(0x380)	/* TSSI power lookup table base */
+#define B43_PHY_DC_LTBASE		B43_PHY_OFDM(0x3A0)	/* DC lookup table base */
+#define B43_PHY_GAIN_LTBASE		B43_PHY_OFDM(0x3C0)	/* Gain lookup table base */
+
+/*** OFDM table numbers ***/
+#define B43_OFDMTAB(number, offset)	(((number) << B43_PHY_OTABLENR_SHIFT) | (offset))
+#define B43_OFDMTAB_AGC1		B43_OFDMTAB(0x00, 0)
+#define B43_OFDMTAB_GAIN0		B43_OFDMTAB(0x00, 0)
+#define B43_OFDMTAB_GAINX		B43_OFDMTAB(0x01, 0)	//TODO rename
+#define B43_OFDMTAB_GAIN1		B43_OFDMTAB(0x01, 4)
+#define B43_OFDMTAB_AGC3		B43_OFDMTAB(0x02, 0)
+#define B43_OFDMTAB_GAIN2		B43_OFDMTAB(0x02, 3)
+#define B43_OFDMTAB_LNAHPFGAIN1		B43_OFDMTAB(0x03, 0)
+#define B43_OFDMTAB_WRSSI		B43_OFDMTAB(0x04, 0)
+#define B43_OFDMTAB_LNAHPFGAIN2		B43_OFDMTAB(0x04, 0)
+#define B43_OFDMTAB_NOISESCALE		B43_OFDMTAB(0x05, 0)
+#define B43_OFDMTAB_AGC2		B43_OFDMTAB(0x06, 0)
+#define B43_OFDMTAB_ROTOR		B43_OFDMTAB(0x08, 0)
+#define B43_OFDMTAB_ADVRETARD		B43_OFDMTAB(0x09, 0)
+#define B43_OFDMTAB_DAC			B43_OFDMTAB(0x0C, 0)
+#define B43_OFDMTAB_DC			B43_OFDMTAB(0x0E, 7)
+#define B43_OFDMTAB_PWRDYN2		B43_OFDMTAB(0x0E, 12)
+#define B43_OFDMTAB_LNAGAIN		B43_OFDMTAB(0x0E, 13)
+#define B43_OFDMTAB_UNKNOWN_0F		B43_OFDMTAB(0x0F, 0)	//TODO rename
+#define B43_OFDMTAB_UNKNOWN_APHY	B43_OFDMTAB(0x0F, 7)	//TODO rename
+#define B43_OFDMTAB_LPFGAIN		B43_OFDMTAB(0x0F, 12)
+#define B43_OFDMTAB_RSSI		B43_OFDMTAB(0x10, 0)
+#define B43_OFDMTAB_UNKNOWN_11		B43_OFDMTAB(0x11, 4)	//TODO rename
+#define B43_OFDMTAB_AGC1_R1		B43_OFDMTAB(0x13, 0)
+#define B43_OFDMTAB_GAINX_R1		B43_OFDMTAB(0x14, 0)	//TODO remove!
+#define B43_OFDMTAB_MINSIGSQ		B43_OFDMTAB(0x14, 0)
+#define B43_OFDMTAB_AGC3_R1		B43_OFDMTAB(0x15, 0)
+#define B43_OFDMTAB_WRSSI_R1		B43_OFDMTAB(0x15, 4)
+#define B43_OFDMTAB_TSSI		B43_OFDMTAB(0x15, 0)
+#define B43_OFDMTAB_DACRFPABB		B43_OFDMTAB(0x16, 0)
+#define B43_OFDMTAB_DACOFF		B43_OFDMTAB(0x17, 0)
+#define B43_OFDMTAB_DCBIAS		B43_OFDMTAB(0x18, 0)
+
+u16 b43_ofdmtab_read16(struct b43_wldev *dev, u16 table, u16 offset);
+void b43_ofdmtab_write16(struct b43_wldev *dev, u16 table,
+			 u16 offset, u16 value);
+u32 b43_ofdmtab_read32(struct b43_wldev *dev, u16 table, u16 offset);
+void b43_ofdmtab_write32(struct b43_wldev *dev, u16 table,
+			 u16 offset, u32 value);
+
+
+struct b43_phy_a {
+	/* Pointer to the table used to convert a
+	 * TSSI value to dBm-Q5.2 */
+	const s8 *tssi2dbm;
+	/* Target idle TSSI */
+	int tgt_idle_tssi;
+	/* Current idle TSSI */
+	int cur_idle_tssi;//FIXME value currently not set
+
+	/* A-PHY TX Power control value. */
+	u16 txpwr_offset;
+
+	//TODO lots of missing stuff
+};
+
+/**
+ * b43_phy_inita - Lowlevel A-PHY init routine.
+ * This is _only_ used by the G-PHY code.
+ */
+void b43_phy_inita(struct b43_wldev *dev);
+
+
+struct b43_phy_operations;
+extern const struct b43_phy_operations b43_phyops_a;
+
+#endif /* LINUX_B43_PHY_A_H_ */
diff --git a/drivers/net/wireless/b43/phy_common.c b/drivers/net/wireless/b43/phy_common.c
new file mode 100644
index 0000000..af37abc
--- /dev/null
+++ b/drivers/net/wireless/b43/phy_common.c
@@ -0,0 +1,381 @@
+/*
+
+  Broadcom B43 wireless driver
+  Common PHY routines
+
+  Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
+  Copyright (c) 2005-2007 Stefano Brivio <stefano.brivio@polimi.it>
+  Copyright (c) 2005-2008 Michael Buesch <mb@bu3sch.de>
+  Copyright (c) 2005, 2006 Danny van Dyk <kugelfang@gentoo.org>
+  Copyright (c) 2005, 2006 Andreas Jaggi <andreas.jaggi@waterwave.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; see the file COPYING.  If not, write to
+  the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+
+*/
+
+#include "phy_common.h"
+#include "phy_g.h"
+#include "phy_a.h"
+#include "phy_n.h"
+#include "phy_lp.h"
+#include "b43.h"
+#include "main.h"
+
+
+int b43_phy_allocate(struct b43_wldev *dev)
+{
+	struct b43_phy *phy = &(dev->phy);
+	int err;
+
+	phy->ops = NULL;
+
+	switch (phy->type) {
+	case B43_PHYTYPE_A:
+		phy->ops = &b43_phyops_a;
+		break;
+	case B43_PHYTYPE_G:
+		phy->ops = &b43_phyops_g;
+		break;
+	case B43_PHYTYPE_N:
+#ifdef CONFIG_B43_NPHY
+		phy->ops = &b43_phyops_n;
+#endif
+		break;
+	case B43_PHYTYPE_LP:
+#ifdef CONFIG_B43_PHY_LP
+		phy->ops = &b43_phyops_lp;
+#endif
+		break;
+	}
+	if (B43_WARN_ON(!phy->ops))
+		return -ENODEV;
+
+	err = phy->ops->allocate(dev);
+	if (err)
+		phy->ops = NULL;
+
+	return err;
+}
+
+void b43_phy_free(struct b43_wldev *dev)
+{
+	dev->phy.ops->free(dev);
+	dev->phy.ops = NULL;
+}
+
+int b43_phy_init(struct b43_wldev *dev)
+{
+	struct b43_phy *phy = &dev->phy;
+	const struct b43_phy_operations *ops = phy->ops;
+	int err;
+
+	phy->channel = ops->get_default_chan(dev);
+
+	ops->software_rfkill(dev, RFKILL_STATE_UNBLOCKED);
+	err = ops->init(dev);
+	if (err) {
+		b43err(dev->wl, "PHY init failed\n");
+		goto err_block_rf;
+	}
+	/* Make sure to switch hardware and firmware (SHM) to
+	 * the default channel. */
+	err = b43_switch_channel(dev, ops->get_default_chan(dev));
+	if (err) {
+		b43err(dev->wl, "PHY init: Channel switch to default failed\n");
+		goto err_phy_exit;
+	}
+
+	return 0;
+
+err_phy_exit:
+	if (ops->exit)
+		ops->exit(dev);
+err_block_rf:
+	ops->software_rfkill(dev, RFKILL_STATE_SOFT_BLOCKED);
+
+	return err;
+}
+
+void b43_phy_exit(struct b43_wldev *dev)
+{
+	const struct b43_phy_operations *ops = dev->phy.ops;
+
+	ops->software_rfkill(dev, RFKILL_STATE_SOFT_BLOCKED);
+	if (ops->exit)
+		ops->exit(dev);
+}
+
+bool b43_has_hardware_pctl(struct b43_wldev *dev)
+{
+	if (!dev->phy.hardware_power_control)
+		return 0;
+	if (!dev->phy.ops->supports_hwpctl)
+		return 0;
+	return dev->phy.ops->supports_hwpctl(dev);
+}
+
+void b43_radio_lock(struct b43_wldev *dev)
+{
+	u32 macctl;
+
+	macctl = b43_read32(dev, B43_MMIO_MACCTL);
+	B43_WARN_ON(macctl & B43_MACCTL_RADIOLOCK);
+	macctl |= B43_MACCTL_RADIOLOCK;
+	b43_write32(dev, B43_MMIO_MACCTL, macctl);
+	/* Commit the write and wait for the device
+	 * to exit any radio register access. */
+	b43_read32(dev, B43_MMIO_MACCTL);
+	udelay(10);
+}
+
+void b43_radio_unlock(struct b43_wldev *dev)
+{
+	u32 macctl;
+
+	/* Commit any write */
+	b43_read16(dev, B43_MMIO_PHY_VER);
+	/* unlock */
+	macctl = b43_read32(dev, B43_MMIO_MACCTL);
+	B43_WARN_ON(!(macctl & B43_MACCTL_RADIOLOCK));
+	macctl &= ~B43_MACCTL_RADIOLOCK;
+	b43_write32(dev, B43_MMIO_MACCTL, macctl);
+}
+
+void b43_phy_lock(struct b43_wldev *dev)
+{
+#if B43_DEBUG
+	B43_WARN_ON(dev->phy.phy_locked);
+	dev->phy.phy_locked = 1;
+#endif
+	B43_WARN_ON(dev->dev->id.revision < 3);
+
+	if (!b43_is_mode(dev->wl, NL80211_IFTYPE_AP))
+		b43_power_saving_ctl_bits(dev, B43_PS_AWAKE);
+}
+
+void b43_phy_unlock(struct b43_wldev *dev)
+{
+#if B43_DEBUG
+	B43_WARN_ON(!dev->phy.phy_locked);
+	dev->phy.phy_locked = 0;
+#endif
+	B43_WARN_ON(dev->dev->id.revision < 3);
+
+	if (!b43_is_mode(dev->wl, NL80211_IFTYPE_AP))
+		b43_power_saving_ctl_bits(dev, 0);
+}
+
+u16 b43_radio_read(struct b43_wldev *dev, u16 reg)
+{
+	return dev->phy.ops->radio_read(dev, reg);
+}
+
+void b43_radio_write(struct b43_wldev *dev, u16 reg, u16 value)
+{
+	dev->phy.ops->radio_write(dev, reg, value);
+}
+
+void b43_radio_mask(struct b43_wldev *dev, u16 offset, u16 mask)
+{
+	b43_radio_write16(dev, offset,
+			  b43_radio_read16(dev, offset) & mask);
+}
+
+void b43_radio_set(struct b43_wldev *dev, u16 offset, u16 set)
+{
+	b43_radio_write16(dev, offset,
+			  b43_radio_read16(dev, offset) | set);
+}
+
+void b43_radio_maskset(struct b43_wldev *dev, u16 offset, u16 mask, u16 set)
+{
+	b43_radio_write16(dev, offset,
+			  (b43_radio_read16(dev, offset) & mask) | set);
+}
+
+u16 b43_phy_read(struct b43_wldev *dev, u16 reg)
+{
+	return dev->phy.ops->phy_read(dev, reg);
+}
+
+void b43_phy_write(struct b43_wldev *dev, u16 reg, u16 value)
+{
+	dev->phy.ops->phy_write(dev, reg, value);
+}
+
+void b43_phy_mask(struct b43_wldev *dev, u16 offset, u16 mask)
+{
+	b43_phy_write(dev, offset,
+		      b43_phy_read(dev, offset) & mask);
+}
+
+void b43_phy_set(struct b43_wldev *dev, u16 offset, u16 set)
+{
+	b43_phy_write(dev, offset,
+		      b43_phy_read(dev, offset) | set);
+}
+
+void b43_phy_maskset(struct b43_wldev *dev, u16 offset, u16 mask, u16 set)
+{
+	b43_phy_write(dev, offset,
+		      (b43_phy_read(dev, offset) & mask) | set);
+}
+
+int b43_switch_channel(struct b43_wldev *dev, unsigned int new_channel)
+{
+	struct b43_phy *phy = &(dev->phy);
+	u16 channelcookie, savedcookie;
+	int err;
+
+	if (new_channel == B43_DEFAULT_CHANNEL)
+		new_channel = phy->ops->get_default_chan(dev);
+
+	/* First we set the channel radio code to prevent the
+	 * firmware from sending ghost packets.
+	 */
+	channelcookie = new_channel;
+	if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ)
+		channelcookie |= 0x100;
+	//FIXME set 40Mhz flag if required
+	savedcookie = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_CHAN);
+	b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_CHAN, channelcookie);
+
+	/* Now try to switch the PHY hardware channel. */
+	err = phy->ops->switch_channel(dev, new_channel);
+	if (err)
+		goto err_restore_cookie;
+
+	dev->phy.channel = new_channel;
+	/* Wait for the radio to tune to the channel and stabilize. */
+	msleep(8);
+
+	return 0;
+
+err_restore_cookie:
+	b43_shm_write16(dev, B43_SHM_SHARED,
+			B43_SHM_SH_CHAN, savedcookie);
+
+	return err;
+}
+
+void b43_software_rfkill(struct b43_wldev *dev, enum rfkill_state state)
+{
+	struct b43_phy *phy = &dev->phy;
+
+	if (state == RFKILL_STATE_HARD_BLOCKED) {
+		/* We cannot hardware-block the device */
+		state = RFKILL_STATE_SOFT_BLOCKED;
+	}
+
+	phy->ops->software_rfkill(dev, state);
+	phy->radio_on = (state == RFKILL_STATE_UNBLOCKED);
+}
+
+/**
+ * b43_phy_txpower_adjust_work - TX power workqueue.
+ *
+ * Workqueue for updating the TX power parameters in hardware.
+ */
+void b43_phy_txpower_adjust_work(struct work_struct *work)
+{
+	struct b43_wl *wl = container_of(work, struct b43_wl,
+					 txpower_adjust_work);
+	struct b43_wldev *dev;
+
+	mutex_lock(&wl->mutex);
+	dev = wl->current_dev;
+
+	if (likely(dev && (b43_status(dev) >= B43_STAT_STARTED)))
+		dev->phy.ops->adjust_txpower(dev);
+
+	mutex_unlock(&wl->mutex);
+}
+
+/* Called with wl->irq_lock locked */
+void b43_phy_txpower_check(struct b43_wldev *dev, unsigned int flags)
+{
+	struct b43_phy *phy = &dev->phy;
+	unsigned long now = jiffies;
+	enum b43_txpwr_result result;
+
+	if (!(flags & B43_TXPWR_IGNORE_TIME)) {
+		/* Check if it's time for a TXpower check. */
+		if (time_before(now, phy->next_txpwr_check_time))
+			return; /* Not yet */
+	}
+	/* The next check will be needed in two seconds, or later. */
+	phy->next_txpwr_check_time = round_jiffies(now + (HZ * 2));
+
+	if ((dev->dev->bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM) &&
+	    (dev->dev->bus->boardinfo.type == SSB_BOARD_BU4306))
+		return; /* No software txpower adjustment needed */
+
+	result = phy->ops->recalc_txpower(dev, !!(flags & B43_TXPWR_IGNORE_TSSI));
+	if (result == B43_TXPWR_RES_DONE)
+		return; /* We are done. */
+	B43_WARN_ON(result != B43_TXPWR_RES_NEED_ADJUST);
+	B43_WARN_ON(phy->ops->adjust_txpower == NULL);
+
+	/* We must adjust the transmission power in hardware.
+	 * Schedule b43_phy_txpower_adjust_work(). */
+	queue_work(dev->wl->hw->workqueue, &dev->wl->txpower_adjust_work);
+}
+
+int b43_phy_shm_tssi_read(struct b43_wldev *dev, u16 shm_offset)
+{
+	const bool is_ofdm = (shm_offset != B43_SHM_SH_TSSI_CCK);
+	unsigned int a, b, c, d;
+	unsigned int average;
+	u32 tmp;
+
+	tmp = b43_shm_read32(dev, B43_SHM_SHARED, shm_offset);
+	a = tmp & 0xFF;
+	b = (tmp >> 8) & 0xFF;
+	c = (tmp >> 16) & 0xFF;
+	d = (tmp >> 24) & 0xFF;
+	if (a == 0 || a == B43_TSSI_MAX ||
+	    b == 0 || b == B43_TSSI_MAX ||
+	    c == 0 || c == B43_TSSI_MAX ||
+	    d == 0 || d == B43_TSSI_MAX)
+		return -ENOENT;
+	/* The values are OK. Clear them. */
+	tmp = B43_TSSI_MAX | (B43_TSSI_MAX << 8) |
+	      (B43_TSSI_MAX << 16) | (B43_TSSI_MAX << 24);
+	b43_shm_write32(dev, B43_SHM_SHARED, shm_offset, tmp);
+
+	if (is_ofdm) {
+		a = (a + 32) & 0x3F;
+		b = (b + 32) & 0x3F;
+		c = (c + 32) & 0x3F;
+		d = (d + 32) & 0x3F;
+	}
+
+	/* Get the average of the values with 0.5 added to each value. */
+	average = (a + b + c + d + 2) / 4;
+	if (is_ofdm) {
+		/* Adjust for CCK-boost */
+		if (b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_HOSTFLO)
+		    & B43_HF_CCKBOOST)
+			average = (average >= 13) ? (average - 13) : 0;
+	}
+
+	return average;
+}
+
+void b43_phyop_switch_analog_generic(struct b43_wldev *dev, bool on)
+{
+	b43_write16(dev, B43_MMIO_PHY0, on ? 0 : 0xF4);
+}
diff --git a/drivers/net/wireless/b43/phy_common.h b/drivers/net/wireless/b43/phy_common.h
new file mode 100644
index 0000000..c9f5430
--- /dev/null
+++ b/drivers/net/wireless/b43/phy_common.h
@@ -0,0 +1,413 @@
+#ifndef LINUX_B43_PHY_COMMON_H_
+#define LINUX_B43_PHY_COMMON_H_
+
+#include <linux/rfkill.h>
+
+struct b43_wldev;
+
+
+/* PHY register routing bits */
+#define B43_PHYROUTE			0x0C00 /* PHY register routing bits mask */
+#define  B43_PHYROUTE_BASE		0x0000 /* Base registers */
+#define  B43_PHYROUTE_OFDM_GPHY		0x0400 /* OFDM register routing for G-PHYs */
+#define  B43_PHYROUTE_EXT_GPHY		0x0800 /* Extended G-PHY registers */
+#define  B43_PHYROUTE_N_BMODE		0x0C00 /* N-PHY BMODE registers */
+
+/* CCK (B-PHY) registers. */
+#define B43_PHY_CCK(reg)		((reg) | B43_PHYROUTE_BASE)
+/* N-PHY registers. */
+#define B43_PHY_N(reg)			((reg) | B43_PHYROUTE_BASE)
+/* N-PHY BMODE registers. */
+#define B43_PHY_N_BMODE(reg)		((reg) | B43_PHYROUTE_N_BMODE)
+/* OFDM (A-PHY) registers. */
+#define B43_PHY_OFDM(reg)		((reg) | B43_PHYROUTE_OFDM_GPHY)
+/* Extended G-PHY registers. */
+#define B43_PHY_EXTG(reg)		((reg) | B43_PHYROUTE_EXT_GPHY)
+
+
+/* Masks for the PHY versioning registers. */
+#define B43_PHYVER_ANALOG		0xF000
+#define B43_PHYVER_ANALOG_SHIFT		12
+#define B43_PHYVER_TYPE			0x0F00
+#define B43_PHYVER_TYPE_SHIFT		8
+#define B43_PHYVER_VERSION		0x00FF
+
+/**
+ * enum b43_interference_mitigation - Interference Mitigation mode
+ *
+ * @B43_INTERFMODE_NONE:	Disabled
+ * @B43_INTERFMODE_NONWLAN:	Non-WLAN Interference Mitigation
+ * @B43_INTERFMODE_MANUALWLAN:	WLAN Interference Mitigation
+ * @B43_INTERFMODE_AUTOWLAN:	Automatic WLAN Interference Mitigation
+ */
+enum b43_interference_mitigation {
+	B43_INTERFMODE_NONE,
+	B43_INTERFMODE_NONWLAN,
+	B43_INTERFMODE_MANUALWLAN,
+	B43_INTERFMODE_AUTOWLAN,
+};
+
+/* Antenna identifiers */
+enum {
+	B43_ANTENNA0,		/* Antenna 0 */
+	B43_ANTENNA1,		/* Antenna 0 */
+	B43_ANTENNA_AUTO1,	/* Automatic, starting with antenna 1 */
+	B43_ANTENNA_AUTO0,	/* Automatic, starting with antenna 0 */
+	B43_ANTENNA2,
+	B43_ANTENNA3 = 8,
+
+	B43_ANTENNA_AUTO = B43_ANTENNA_AUTO0,
+	B43_ANTENNA_DEFAULT = B43_ANTENNA_AUTO,
+};
+
+/**
+ * enum b43_txpwr_result - Return value for the recalc_txpower PHY op.
+ *
+ * @B43_TXPWR_RES_NEED_ADJUST:	Values changed. Hardware adjustment is needed.
+ * @B43_TXPWR_RES_DONE:		No more work to do. Everything is done.
+ */
+enum b43_txpwr_result {
+	B43_TXPWR_RES_NEED_ADJUST,
+	B43_TXPWR_RES_DONE,
+};
+
+/**
+ * struct b43_phy_operations - Function pointers for PHY ops.
+ *
+ * @allocate:		Allocate and initialise the PHY data structures.
+ * 			Must not be NULL.
+ * @free:		Destroy and free the PHY data structures.
+ * 			Must not be NULL.
+ *
+ * @prepare_structs:	Prepare the PHY data structures.
+ * 			The data structures allocated in @allocate are
+ * 			initialized here.
+ * 			Must not be NULL.
+ * @prepare_hardware:	Prepare the PHY. This is called before b43_chip_init to
+ * 			do some early early PHY hardware init.
+ * 			Can be NULL, if not required.
+ * @init:		Initialize the PHY.
+ * 			Must not be NULL.
+ * @exit:		Shutdown the PHY.
+ * 			Can be NULL, if not required.
+ *
+ * @phy_read:		Read from a PHY register.
+ * 			Must not be NULL.
+ * @phy_write:		Write to a PHY register.
+ * 			Must not be NULL.
+ * @radio_read:		Read from a Radio register.
+ * 			Must not be NULL.
+ * @radio_write:	Write to a Radio register.
+ * 			Must not be NULL.
+ *
+ * @supports_hwpctl:	Returns a boolean whether Hardware Power Control
+ * 			is supported or not.
+ * 			If NULL, hwpctl is assumed to be never supported.
+ * @software_rfkill:	Turn the radio ON or OFF.
+ * 			Possible state values are
+ * 			RFKILL_STATE_SOFT_BLOCKED or
+ * 			RFKILL_STATE_UNBLOCKED
+ * 			Must not be NULL.
+ * @switch_analog:	Turn the Analog on/off.
+ * 			Must not be NULL.
+ * @switch_channel:	Switch the radio to another channel.
+ * 			Must not be NULL.
+ * @get_default_chan:	Just returns the default channel number.
+ * 			Must not be NULL.
+ * @set_rx_antenna:	Set the antenna used for RX.
+ * 			Can be NULL, if not supported.
+ * @interf_mitigation:	Switch the Interference Mitigation mode.
+ * 			Can be NULL, if not supported.
+ *
+ * @recalc_txpower:	Recalculate the transmission power parameters.
+ * 			This callback has to recalculate the TX power settings,
+ * 			but does not need to write them to the hardware, yet.
+ * 			Returns enum b43_txpwr_result to indicate whether the hardware
+ * 			needs to be adjusted.
+ * 			If B43_TXPWR_NEED_ADJUST is returned, @adjust_txpower
+ * 			will be called later.
+ * 			If the parameter "ignore_tssi" is true, the TSSI values should
+ * 			be ignored and a recalculation of the power settings should be
+ * 			done even if the TSSI values did not change.
+ * 			This callback is called with wl->irq_lock held and must not sleep.
+ * 			Must not be NULL.
+ * @adjust_txpower:	Write the previously calculated TX power settings
+ * 			(from @recalc_txpower) to the hardware.
+ * 			This function may sleep.
+ * 			Can be NULL, if (and ONLY if) @recalc_txpower _always_
+ * 			returns B43_TXPWR_RES_DONE.
+ *
+ * @pwork_15sec:	Periodic work. Called every 15 seconds.
+ * 			Can be NULL, if not required.
+ * @pwork_60sec:	Periodic work. Called every 60 seconds.
+ * 			Can be NULL, if not required.
+ */
+struct b43_phy_operations {
+	/* Initialisation */
+	int (*allocate)(struct b43_wldev *dev);
+	void (*free)(struct b43_wldev *dev);
+	void (*prepare_structs)(struct b43_wldev *dev);
+	int (*prepare_hardware)(struct b43_wldev *dev);
+	int (*init)(struct b43_wldev *dev);
+	void (*exit)(struct b43_wldev *dev);
+
+	/* Register access */
+	u16 (*phy_read)(struct b43_wldev *dev, u16 reg);
+	void (*phy_write)(struct b43_wldev *dev, u16 reg, u16 value);
+	u16 (*radio_read)(struct b43_wldev *dev, u16 reg);
+	void (*radio_write)(struct b43_wldev *dev, u16 reg, u16 value);
+
+	/* Radio */
+	bool (*supports_hwpctl)(struct b43_wldev *dev);
+	void (*software_rfkill)(struct b43_wldev *dev, enum rfkill_state state);
+	void (*switch_analog)(struct b43_wldev *dev, bool on);
+	int (*switch_channel)(struct b43_wldev *dev, unsigned int new_channel);
+	unsigned int (*get_default_chan)(struct b43_wldev *dev);
+	void (*set_rx_antenna)(struct b43_wldev *dev, int antenna);
+	int (*interf_mitigation)(struct b43_wldev *dev,
+				 enum b43_interference_mitigation new_mode);
+
+	/* Transmission power adjustment */
+	enum b43_txpwr_result (*recalc_txpower)(struct b43_wldev *dev,
+						bool ignore_tssi);
+	void (*adjust_txpower)(struct b43_wldev *dev);
+
+	/* Misc */
+	void (*pwork_15sec)(struct b43_wldev *dev);
+	void (*pwork_60sec)(struct b43_wldev *dev);
+};
+
+struct b43_phy_a;
+struct b43_phy_g;
+struct b43_phy_n;
+struct b43_phy_lp;
+
+struct b43_phy {
+	/* Hardware operation callbacks. */
+	const struct b43_phy_operations *ops;
+
+	/* Most hardware context information is stored in the standard-
+	 * specific data structures pointed to by the pointers below.
+	 * Only one of them is valid (the currently enabled PHY). */
+#ifdef CONFIG_B43_DEBUG
+	/* No union for debug build to force NULL derefs in buggy code. */
+	struct {
+#else
+	union {
+#endif
+		/* A-PHY specific information */
+		struct b43_phy_a *a;
+		/* G-PHY specific information */
+		struct b43_phy_g *g;
+		/* N-PHY specific information */
+		struct b43_phy_n *n;
+		/* LP-PHY specific information */
+		struct b43_phy_lp *lp;
+	};
+
+	/* Band support flags. */
+	bool supports_2ghz;
+	bool supports_5ghz;
+
+	/* GMODE bit enabled? */
+	bool gmode;
+
+	/* Analog Type */
+	u8 analog;
+	/* B43_PHYTYPE_ */
+	u8 type;
+	/* PHY revision number. */
+	u8 rev;
+
+	/* Radio versioning */
+	u16 radio_manuf;	/* Radio manufacturer */
+	u16 radio_ver;		/* Radio version */
+	u8 radio_rev;		/* Radio revision */
+
+	/* Software state of the radio */
+	bool radio_on;
+
+	/* Desired TX power level (in dBm).
+	 * This is set by the user and adjusted in b43_phy_xmitpower(). */
+	int desired_txpower;
+
+	/* Hardware Power Control enabled? */
+	bool hardware_power_control;
+
+	/* The time (in absolute jiffies) when the next TX power output
+	 * check is needed. */
+	unsigned long next_txpwr_check_time;
+
+	/* current channel */
+	unsigned int channel;
+
+	/* PHY TX errors counter. */
+	atomic_t txerr_cnt;
+
+#ifdef CONFIG_B43_DEBUG
+	/* PHY registers locked by b43_phy_lock()? */
+	bool phy_locked;
+#endif /* B43_DEBUG */
+};
+
+
+/**
+ * b43_phy_allocate - Allocate PHY structs
+ * Allocate the PHY data structures, based on the current dev->phy.type
+ */
+int b43_phy_allocate(struct b43_wldev *dev);
+
+/**
+ * b43_phy_free - Free PHY structs
+ */
+void b43_phy_free(struct b43_wldev *dev);
+
+/**
+ * b43_phy_init - Initialise the PHY
+ */
+int b43_phy_init(struct b43_wldev *dev);
+
+/**
+ * b43_phy_exit - Cleanup PHY
+ */
+void b43_phy_exit(struct b43_wldev *dev);
+
+/**
+ * b43_has_hardware_pctl - Hardware Power Control supported?
+ * Returns a boolean, whether hardware power control is supported.
+ */
+bool b43_has_hardware_pctl(struct b43_wldev *dev);
+
+/**
+ * b43_phy_read - 16bit PHY register read access
+ */
+u16 b43_phy_read(struct b43_wldev *dev, u16 reg);
+
+/**
+ * b43_phy_write - 16bit PHY register write access
+ */
+void b43_phy_write(struct b43_wldev *dev, u16 reg, u16 value);
+
+/**
+ * b43_phy_mask - Mask a PHY register with a mask
+ */
+void b43_phy_mask(struct b43_wldev *dev, u16 offset, u16 mask);
+
+/**
+ * b43_phy_set - OR a PHY register with a bitmap
+ */
+void b43_phy_set(struct b43_wldev *dev, u16 offset, u16 set);
+
+/**
+ * b43_phy_maskset - Mask and OR a PHY register with a mask and bitmap
+ */
+void b43_phy_maskset(struct b43_wldev *dev, u16 offset, u16 mask, u16 set);
+
+/**
+ * b43_radio_read - 16bit Radio register read access
+ */
+u16 b43_radio_read(struct b43_wldev *dev, u16 reg);
+#define b43_radio_read16	b43_radio_read /* DEPRECATED */
+
+/**
+ * b43_radio_write - 16bit Radio register write access
+ */
+void b43_radio_write(struct b43_wldev *dev, u16 reg, u16 value);
+#define b43_radio_write16	b43_radio_write /* DEPRECATED */
+
+/**
+ * b43_radio_mask - Mask a 16bit radio register with a mask
+ */
+void b43_radio_mask(struct b43_wldev *dev, u16 offset, u16 mask);
+
+/**
+ * b43_radio_set - OR a 16bit radio register with a bitmap
+ */
+void b43_radio_set(struct b43_wldev *dev, u16 offset, u16 set);
+
+/**
+ * b43_radio_maskset - Mask and OR a radio register with a mask and bitmap
+ */
+void b43_radio_maskset(struct b43_wldev *dev, u16 offset, u16 mask, u16 set);
+
+/**
+ * b43_radio_lock - Lock firmware radio register access
+ */
+void b43_radio_lock(struct b43_wldev *dev);
+
+/**
+ * b43_radio_unlock - Unlock firmware radio register access
+ */
+void b43_radio_unlock(struct b43_wldev *dev);
+
+/**
+ * b43_phy_lock - Lock firmware PHY register access
+ */
+void b43_phy_lock(struct b43_wldev *dev);
+
+/**
+ * b43_phy_unlock - Unlock firmware PHY register access
+ */
+void b43_phy_unlock(struct b43_wldev *dev);
+
+/**
+ * b43_switch_channel - Switch to another channel
+ */
+int b43_switch_channel(struct b43_wldev *dev, unsigned int new_channel);
+/**
+ * B43_DEFAULT_CHANNEL - Switch to the default channel.
+ */
+#define B43_DEFAULT_CHANNEL	UINT_MAX
+
+/**
+ * b43_software_rfkill - Turn the radio ON or OFF in software.
+ */
+void b43_software_rfkill(struct b43_wldev *dev, enum rfkill_state state);
+
+/**
+ * b43_phy_txpower_check - Check TX power output.
+ *
+ * Compare the current TX power output to the desired power emission
+ * and schedule an adjustment in case it mismatches.
+ * Requires wl->irq_lock locked.
+ *
+ * @flags:	OR'ed enum b43_phy_txpower_check_flags flags.
+ * 		See the docs below.
+ */
+void b43_phy_txpower_check(struct b43_wldev *dev, unsigned int flags);
+/**
+ * enum b43_phy_txpower_check_flags - Flags for b43_phy_txpower_check()
+ *
+ * @B43_TXPWR_IGNORE_TIME: Ignore the schedule time and force-redo
+ *                         the check now.
+ * @B43_TXPWR_IGNORE_TSSI: Redo the recalculation, even if the average
+ *                         TSSI did not change.
+ */
+enum b43_phy_txpower_check_flags {
+	B43_TXPWR_IGNORE_TIME		= (1 << 0),
+	B43_TXPWR_IGNORE_TSSI		= (1 << 1),
+};
+
+struct work_struct;
+void b43_phy_txpower_adjust_work(struct work_struct *work);
+
+/**
+ * b43_phy_shm_tssi_read - Read the average of the last 4 TSSI from SHM.
+ *
+ * @shm_offset:		The SHM address to read the values from.
+ *
+ * Returns the average of the 4 TSSI values, or a negative error code.
+ */
+int b43_phy_shm_tssi_read(struct b43_wldev *dev, u16 shm_offset);
+
+/**
+ * b43_phy_switch_analog_generic - Generic PHY operation for switching the Analog.
+ *
+ * It does the switching based on the PHY0 core register.
+ * Do _not_ call this directly. Only use it as a switch_analog callback
+ * for struct b43_phy_operations.
+ */
+void b43_phyop_switch_analog_generic(struct b43_wldev *dev, bool on);
+
+
+#endif /* LINUX_B43_PHY_COMMON_H_ */
diff --git a/drivers/net/wireless/b43/phy_g.c b/drivers/net/wireless/b43/phy_g.c
new file mode 100644
index 0000000..232181f
--- /dev/null
+++ b/drivers/net/wireless/b43/phy_g.c
@@ -0,0 +1,3282 @@
+/*
+
+  Broadcom B43 wireless driver
+  IEEE 802.11g PHY driver
+
+  Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
+  Copyright (c) 2005-2007 Stefano Brivio <stefano.brivio@polimi.it>
+  Copyright (c) 2005-2008 Michael Buesch <mb@bu3sch.de>
+  Copyright (c) 2005, 2006 Danny van Dyk <kugelfang@gentoo.org>
+  Copyright (c) 2005, 2006 Andreas Jaggi <andreas.jaggi@waterwave.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; see the file COPYING.  If not, write to
+  the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+
+*/
+
+#include "b43.h"
+#include "phy_g.h"
+#include "phy_common.h"
+#include "lo.h"
+#include "main.h"
+
+#include <linux/bitrev.h>
+
+
+static const s8 b43_tssi2dbm_g_table[] = {
+	77, 77, 77, 76,
+	76, 76, 75, 75,
+	74, 74, 73, 73,
+	73, 72, 72, 71,
+	71, 70, 70, 69,
+	68, 68, 67, 67,
+	66, 65, 65, 64,
+	63, 63, 62, 61,
+	60, 59, 58, 57,
+	56, 55, 54, 53,
+	52, 50, 49, 47,
+	45, 43, 40, 37,
+	33, 28, 22, 14,
+	5, -7, -20, -20,
+	-20, -20, -20, -20,
+	-20, -20, -20, -20,
+};
+
+const u8 b43_radio_channel_codes_bg[] = {
+	12, 17, 22, 27,
+	32, 37, 42, 47,
+	52, 57, 62, 67,
+	72, 84,
+};
+
+
+static void b43_calc_nrssi_threshold(struct b43_wldev *dev);
+
+
+#define bitrev4(tmp) (bitrev8(tmp) >> 4)
+
+
+/* Get the freq, as it has to be written to the device. */
+static inline u16 channel2freq_bg(u8 channel)
+{
+	B43_WARN_ON(!(channel >= 1 && channel <= 14));
+
+	return b43_radio_channel_codes_bg[channel - 1];
+}
+
+static void generate_rfatt_list(struct b43_wldev *dev,
+				struct b43_rfatt_list *list)
+{
+	struct b43_phy *phy = &dev->phy;
+
+	/* APHY.rev < 5 || GPHY.rev < 6 */
+	static const struct b43_rfatt rfatt_0[] = {
+		{.att = 3,.with_padmix = 0,},
+		{.att = 1,.with_padmix = 0,},
+		{.att = 5,.with_padmix = 0,},
+		{.att = 7,.with_padmix = 0,},
+		{.att = 9,.with_padmix = 0,},
+		{.att = 2,.with_padmix = 0,},
+		{.att = 0,.with_padmix = 0,},
+		{.att = 4,.with_padmix = 0,},
+		{.att = 6,.with_padmix = 0,},
+		{.att = 8,.with_padmix = 0,},
+		{.att = 1,.with_padmix = 1,},
+		{.att = 2,.with_padmix = 1,},
+		{.att = 3,.with_padmix = 1,},
+		{.att = 4,.with_padmix = 1,},
+	};
+	/* Radio.rev == 8 && Radio.version == 0x2050 */
+	static const struct b43_rfatt rfatt_1[] = {
+		{.att = 2,.with_padmix = 1,},
+		{.att = 4,.with_padmix = 1,},
+		{.att = 6,.with_padmix = 1,},
+		{.att = 8,.with_padmix = 1,},
+		{.att = 10,.with_padmix = 1,},
+		{.att = 12,.with_padmix = 1,},
+		{.att = 14,.with_padmix = 1,},
+	};
+	/* Otherwise */
+	static const struct b43_rfatt rfatt_2[] = {
+		{.att = 0,.with_padmix = 1,},
+		{.att = 2,.with_padmix = 1,},
+		{.att = 4,.with_padmix = 1,},
+		{.att = 6,.with_padmix = 1,},
+		{.att = 8,.with_padmix = 1,},
+		{.att = 9,.with_padmix = 1,},
+		{.att = 9,.with_padmix = 1,},
+	};
+
+	if (!b43_has_hardware_pctl(dev)) {
+		/* Software pctl */
+		list->list = rfatt_0;
+		list->len = ARRAY_SIZE(rfatt_0);
+		list->min_val = 0;
+		list->max_val = 9;
+		return;
+	}
+	if (phy->radio_ver == 0x2050 && phy->radio_rev == 8) {
+		/* Hardware pctl */
+		list->list = rfatt_1;
+		list->len = ARRAY_SIZE(rfatt_1);
+		list->min_val = 0;
+		list->max_val = 14;
+		return;
+	}
+	/* Hardware pctl */
+	list->list = rfatt_2;
+	list->len = ARRAY_SIZE(rfatt_2);
+	list->min_val = 0;
+	list->max_val = 9;
+}
+
+static void generate_bbatt_list(struct b43_wldev *dev,
+				struct b43_bbatt_list *list)
+{
+	static const struct b43_bbatt bbatt_0[] = {
+		{.att = 0,},
+		{.att = 1,},
+		{.att = 2,},
+		{.att = 3,},
+		{.att = 4,},
+		{.att = 5,},
+		{.att = 6,},
+		{.att = 7,},
+		{.att = 8,},
+	};
+
+	list->list = bbatt_0;
+	list->len = ARRAY_SIZE(bbatt_0);
+	list->min_val = 0;
+	list->max_val = 8;
+}
+
+static void b43_shm_clear_tssi(struct b43_wldev *dev)
+{
+	b43_shm_write16(dev, B43_SHM_SHARED, 0x0058, 0x7F7F);
+	b43_shm_write16(dev, B43_SHM_SHARED, 0x005a, 0x7F7F);
+	b43_shm_write16(dev, B43_SHM_SHARED, 0x0070, 0x7F7F);
+	b43_shm_write16(dev, B43_SHM_SHARED, 0x0072, 0x7F7F);
+}
+
+/* Synthetic PU workaround */
+static void b43_synth_pu_workaround(struct b43_wldev *dev, u8 channel)
+{
+	struct b43_phy *phy = &dev->phy;
+
+	might_sleep();
+
+	if (phy->radio_ver != 0x2050 || phy->radio_rev >= 6) {
+		/* We do not need the workaround. */
+		return;
+	}
+
+	if (channel <= 10) {
+		b43_write16(dev, B43_MMIO_CHANNEL,
+			    channel2freq_bg(channel + 4));
+	} else {
+		b43_write16(dev, B43_MMIO_CHANNEL, channel2freq_bg(1));
+	}
+	msleep(1);
+	b43_write16(dev, B43_MMIO_CHANNEL, channel2freq_bg(channel));
+}
+
+/* Set the baseband attenuation value on chip. */
+void b43_gphy_set_baseband_attenuation(struct b43_wldev *dev,
+				       u16 baseband_attenuation)
+{
+	struct b43_phy *phy = &dev->phy;
+
+	if (phy->analog == 0) {
+		b43_write16(dev, B43_MMIO_PHY0, (b43_read16(dev, B43_MMIO_PHY0)
+						 & 0xFFF0) |
+			    baseband_attenuation);
+	} else if (phy->analog > 1) {
+		b43_phy_write(dev, B43_PHY_DACCTL,
+			      (b43_phy_read(dev, B43_PHY_DACCTL)
+			       & 0xFFC3) | (baseband_attenuation << 2));
+	} else {
+		b43_phy_write(dev, B43_PHY_DACCTL,
+			      (b43_phy_read(dev, B43_PHY_DACCTL)
+			       & 0xFF87) | (baseband_attenuation << 3));
+	}
+}
+
+/* Adjust the transmission power output (G-PHY) */
+void b43_set_txpower_g(struct b43_wldev *dev,
+		       const struct b43_bbatt *bbatt,
+		       const struct b43_rfatt *rfatt, u8 tx_control)
+{
+	struct b43_phy *phy = &dev->phy;
+	struct b43_phy_g *gphy = phy->g;
+	struct b43_txpower_lo_control *lo = gphy->lo_control;
+	u16 bb, rf;
+	u16 tx_bias, tx_magn;
+
+	bb = bbatt->att;
+	rf = rfatt->att;
+	tx_bias = lo->tx_bias;
+	tx_magn = lo->tx_magn;
+	if (unlikely(tx_bias == 0xFF))
+		tx_bias = 0;
+
+	/* Save the values for later. Use memmove, because it's valid
+	 * to pass &gphy->rfatt as rfatt pointer argument. Same for bbatt. */
+	gphy->tx_control = tx_control;
+	memmove(&gphy->rfatt, rfatt, sizeof(*rfatt));
+	gphy->rfatt.with_padmix = !!(tx_control & B43_TXCTL_TXMIX);
+	memmove(&gphy->bbatt, bbatt, sizeof(*bbatt));
+
+	if (b43_debug(dev, B43_DBG_XMITPOWER)) {
+		b43dbg(dev->wl, "Tuning TX-power to bbatt(%u), "
+		       "rfatt(%u), tx_control(0x%02X), "
+		       "tx_bias(0x%02X), tx_magn(0x%02X)\n",
+		       bb, rf, tx_control, tx_bias, tx_magn);
+	}
+
+	b43_gphy_set_baseband_attenuation(dev, bb);
+	b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_RFATT, rf);
+	if (phy->radio_ver == 0x2050 && phy->radio_rev == 8) {
+		b43_radio_write16(dev, 0x43,
+				  (rf & 0x000F) | (tx_control & 0x0070));
+	} else {
+		b43_radio_write16(dev, 0x43, (b43_radio_read16(dev, 0x43)
+					      & 0xFFF0) | (rf & 0x000F));
+		b43_radio_write16(dev, 0x52, (b43_radio_read16(dev, 0x52)
+					      & ~0x0070) | (tx_control &
+							    0x0070));
+	}
+	if (has_tx_magnification(phy)) {
+		b43_radio_write16(dev, 0x52, tx_magn | tx_bias);
+	} else {
+		b43_radio_write16(dev, 0x52, (b43_radio_read16(dev, 0x52)
+					      & 0xFFF0) | (tx_bias & 0x000F));
+	}
+	b43_lo_g_adjust(dev);
+}
+
+/* GPHY_TSSI_Power_Lookup_Table_Init */
+static void b43_gphy_tssi_power_lt_init(struct b43_wldev *dev)
+{
+	struct b43_phy_g *gphy = dev->phy.g;
+	int i;
+	u16 value;
+
+	for (i = 0; i < 32; i++)
+		b43_ofdmtab_write16(dev, 0x3C20, i, gphy->tssi2dbm[i]);
+	for (i = 32; i < 64; i++)
+		b43_ofdmtab_write16(dev, 0x3C00, i - 32, gphy->tssi2dbm[i]);
+	for (i = 0; i < 64; i += 2) {
+		value = (u16) gphy->tssi2dbm[i];
+		value |= ((u16) gphy->tssi2dbm[i + 1]) << 8;
+		b43_phy_write(dev, 0x380 + (i / 2), value);
+	}
+}
+
+/* GPHY_Gain_Lookup_Table_Init */
+static void b43_gphy_gain_lt_init(struct b43_wldev *dev)
+{
+	struct b43_phy *phy = &dev->phy;
+	struct b43_phy_g *gphy = phy->g;
+	struct b43_txpower_lo_control *lo = gphy->lo_control;
+	u16 nr_written = 0;
+	u16 tmp;
+	u8 rf, bb;
+
+	for (rf = 0; rf < lo->rfatt_list.len; rf++) {
+		for (bb = 0; bb < lo->bbatt_list.len; bb++) {
+			if (nr_written >= 0x40)
+				return;
+			tmp = lo->bbatt_list.list[bb].att;
+			tmp <<= 8;
+			if (phy->radio_rev == 8)
+				tmp |= 0x50;
+			else
+				tmp |= 0x40;
+			tmp |= lo->rfatt_list.list[rf].att;
+			b43_phy_write(dev, 0x3C0 + nr_written, tmp);
+			nr_written++;
+		}
+	}
+}
+
+static void b43_set_all_gains(struct b43_wldev *dev,
+			      s16 first, s16 second, s16 third)
+{
+	struct b43_phy *phy = &dev->phy;
+	u16 i;
+	u16 start = 0x08, end = 0x18;
+	u16 tmp;
+	u16 table;
+
+	if (phy->rev <= 1) {
+		start = 0x10;
+		end = 0x20;
+	}
+
+	table = B43_OFDMTAB_GAINX;
+	if (phy->rev <= 1)
+		table = B43_OFDMTAB_GAINX_R1;
+	for (i = 0; i < 4; i++)
+		b43_ofdmtab_write16(dev, table, i, first);
+
+	for (i = start; i < end; i++)
+		b43_ofdmtab_write16(dev, table, i, second);
+
+	if (third != -1) {
+		tmp = ((u16) third << 14) | ((u16) third << 6);
+		b43_phy_write(dev, 0x04A0,
+			      (b43_phy_read(dev, 0x04A0) & 0xBFBF) | tmp);
+		b43_phy_write(dev, 0x04A1,
+			      (b43_phy_read(dev, 0x04A1) & 0xBFBF) | tmp);
+		b43_phy_write(dev, 0x04A2,
+			      (b43_phy_read(dev, 0x04A2) & 0xBFBF) | tmp);
+	}
+	b43_dummy_transmission(dev);
+}
+
+static void b43_set_original_gains(struct b43_wldev *dev)
+{
+	struct b43_phy *phy = &dev->phy;
+	u16 i, tmp;
+	u16 table;
+	u16 start = 0x0008, end = 0x0018;
+
+	if (phy->rev <= 1) {
+		start = 0x0010;
+		end = 0x0020;
+	}
+
+	table = B43_OFDMTAB_GAINX;
+	if (phy->rev <= 1)
+		table = B43_OFDMTAB_GAINX_R1;
+	for (i = 0; i < 4; i++) {
+		tmp = (i & 0xFFFC);
+		tmp |= (i & 0x0001) << 1;
+		tmp |= (i & 0x0002) >> 1;
+
+		b43_ofdmtab_write16(dev, table, i, tmp);
+	}
+
+	for (i = start; i < end; i++)
+		b43_ofdmtab_write16(dev, table, i, i - start);
+
+	b43_phy_write(dev, 0x04A0,
+		      (b43_phy_read(dev, 0x04A0) & 0xBFBF) | 0x4040);
+	b43_phy_write(dev, 0x04A1,
+		      (b43_phy_read(dev, 0x04A1) & 0xBFBF) | 0x4040);
+	b43_phy_write(dev, 0x04A2,
+		      (b43_phy_read(dev, 0x04A2) & 0xBFBF) | 0x4000);
+	b43_dummy_transmission(dev);
+}
+
+/* http://bcm-specs.sipsolutions.net/NRSSILookupTable */
+void b43_nrssi_hw_write(struct b43_wldev *dev, u16 offset, s16 val)
+{
+	b43_phy_write(dev, B43_PHY_NRSSILT_CTRL, offset);
+	b43_phy_write(dev, B43_PHY_NRSSILT_DATA, (u16) val);
+}
+
+/* http://bcm-specs.sipsolutions.net/NRSSILookupTable */
+s16 b43_nrssi_hw_read(struct b43_wldev *dev, u16 offset)
+{
+	u16 val;
+
+	b43_phy_write(dev, B43_PHY_NRSSILT_CTRL, offset);
+	val = b43_phy_read(dev, B43_PHY_NRSSILT_DATA);
+
+	return (s16) val;
+}
+
+/* http://bcm-specs.sipsolutions.net/NRSSILookupTable */
+void b43_nrssi_hw_update(struct b43_wldev *dev, u16 val)
+{
+	u16 i;
+	s16 tmp;
+
+	for (i = 0; i < 64; i++) {
+		tmp = b43_nrssi_hw_read(dev, i);
+		tmp -= val;
+		tmp = clamp_val(tmp, -32, 31);
+		b43_nrssi_hw_write(dev, i, tmp);
+	}
+}
+
+/* http://bcm-specs.sipsolutions.net/NRSSILookupTable */
+void b43_nrssi_mem_update(struct b43_wldev *dev)
+{
+	struct b43_phy_g *gphy = dev->phy.g;
+	s16 i, delta;
+	s32 tmp;
+
+	delta = 0x1F - gphy->nrssi[0];
+	for (i = 0; i < 64; i++) {
+		tmp = (i - delta) * gphy->nrssislope;
+		tmp /= 0x10000;
+		tmp += 0x3A;
+		tmp = clamp_val(tmp, 0, 0x3F);
+		gphy->nrssi_lt[i] = tmp;
+	}
+}
+
+static void b43_calc_nrssi_offset(struct b43_wldev *dev)
+{
+	struct b43_phy *phy = &dev->phy;
+	u16 backup[20] = { 0 };
+	s16 v47F;
+	u16 i;
+	u16 saved = 0xFFFF;
+
+	backup[0] = b43_phy_read(dev, 0x0001);
+	backup[1] = b43_phy_read(dev, 0x0811);
+	backup[2] = b43_phy_read(dev, 0x0812);
+	if (phy->rev != 1) {	/* Not in specs, but needed to prevent PPC machine check */
+		backup[3] = b43_phy_read(dev, 0x0814);
+		backup[4] = b43_phy_read(dev, 0x0815);
+	}
+	backup[5] = b43_phy_read(dev, 0x005A);
+	backup[6] = b43_phy_read(dev, 0x0059);
+	backup[7] = b43_phy_read(dev, 0x0058);
+	backup[8] = b43_phy_read(dev, 0x000A);
+	backup[9] = b43_phy_read(dev, 0x0003);
+	backup[10] = b43_radio_read16(dev, 0x007A);
+	backup[11] = b43_radio_read16(dev, 0x0043);
+
+	b43_phy_write(dev, 0x0429, b43_phy_read(dev, 0x0429) & 0x7FFF);
+	b43_phy_write(dev, 0x0001,
+		      (b43_phy_read(dev, 0x0001) & 0x3FFF) | 0x4000);
+	b43_phy_write(dev, 0x0811, b43_phy_read(dev, 0x0811) | 0x000C);
+	b43_phy_write(dev, 0x0812,
+		      (b43_phy_read(dev, 0x0812) & 0xFFF3) | 0x0004);
+	b43_phy_write(dev, 0x0802, b43_phy_read(dev, 0x0802) & ~(0x1 | 0x2));
+	if (phy->rev >= 6) {
+		backup[12] = b43_phy_read(dev, 0x002E);
+		backup[13] = b43_phy_read(dev, 0x002F);
+		backup[14] = b43_phy_read(dev, 0x080F);
+		backup[15] = b43_phy_read(dev, 0x0810);
+		backup[16] = b43_phy_read(dev, 0x0801);
+		backup[17] = b43_phy_read(dev, 0x0060);
+		backup[18] = b43_phy_read(dev, 0x0014);
+		backup[19] = b43_phy_read(dev, 0x0478);
+
+		b43_phy_write(dev, 0x002E, 0);
+		b43_phy_write(dev, 0x002F, 0);
+		b43_phy_write(dev, 0x080F, 0);
+		b43_phy_write(dev, 0x0810, 0);
+		b43_phy_write(dev, 0x0478, b43_phy_read(dev, 0x0478) | 0x0100);
+		b43_phy_write(dev, 0x0801, b43_phy_read(dev, 0x0801) | 0x0040);
+		b43_phy_write(dev, 0x0060, b43_phy_read(dev, 0x0060) | 0x0040);
+		b43_phy_write(dev, 0x0014, b43_phy_read(dev, 0x0014) | 0x0200);
+	}
+	b43_radio_write16(dev, 0x007A, b43_radio_read16(dev, 0x007A) | 0x0070);
+	b43_radio_write16(dev, 0x007A, b43_radio_read16(dev, 0x007A) | 0x0080);
+	udelay(30);
+
+	v47F = (s16) ((b43_phy_read(dev, 0x047F) >> 8) & 0x003F);
+	if (v47F >= 0x20)
+		v47F -= 0x40;
+	if (v47F == 31) {
+		for (i = 7; i >= 4; i--) {
+			b43_radio_write16(dev, 0x007B, i);
+			udelay(20);
+			v47F =
+			    (s16) ((b43_phy_read(dev, 0x047F) >> 8) & 0x003F);
+			if (v47F >= 0x20)
+				v47F -= 0x40;
+			if (v47F < 31 && saved == 0xFFFF)
+				saved = i;
+		}
+		if (saved == 0xFFFF)
+			saved = 4;
+	} else {
+		b43_radio_write16(dev, 0x007A,
+				  b43_radio_read16(dev, 0x007A) & 0x007F);
+		if (phy->rev != 1) {	/* Not in specs, but needed to prevent PPC machine check */
+			b43_phy_write(dev, 0x0814,
+				      b43_phy_read(dev, 0x0814) | 0x0001);
+			b43_phy_write(dev, 0x0815,
+				      b43_phy_read(dev, 0x0815) & 0xFFFE);
+		}
+		b43_phy_write(dev, 0x0811, b43_phy_read(dev, 0x0811) | 0x000C);
+		b43_phy_write(dev, 0x0812, b43_phy_read(dev, 0x0812) | 0x000C);
+		b43_phy_write(dev, 0x0811, b43_phy_read(dev, 0x0811) | 0x0030);
+		b43_phy_write(dev, 0x0812, b43_phy_read(dev, 0x0812) | 0x0030);
+		b43_phy_write(dev, 0x005A, 0x0480);
+		b43_phy_write(dev, 0x0059, 0x0810);
+		b43_phy_write(dev, 0x0058, 0x000D);
+		if (phy->rev == 0) {
+			b43_phy_write(dev, 0x0003, 0x0122);
+		} else {
+			b43_phy_write(dev, 0x000A, b43_phy_read(dev, 0x000A)
+				      | 0x2000);
+		}
+		if (phy->rev != 1) {	/* Not in specs, but needed to prevent PPC machine check */
+			b43_phy_write(dev, 0x0814,
+				      b43_phy_read(dev, 0x0814) | 0x0004);
+			b43_phy_write(dev, 0x0815,
+				      b43_phy_read(dev, 0x0815) & 0xFFFB);
+		}
+		b43_phy_write(dev, 0x0003, (b43_phy_read(dev, 0x0003) & 0xFF9F)
+			      | 0x0040);
+		b43_radio_write16(dev, 0x007A,
+				  b43_radio_read16(dev, 0x007A) | 0x000F);
+		b43_set_all_gains(dev, 3, 0, 1);
+		b43_radio_write16(dev, 0x0043, (b43_radio_read16(dev, 0x0043)
+						& 0x00F0) | 0x000F);
+		udelay(30);
+		v47F = (s16) ((b43_phy_read(dev, 0x047F) >> 8) & 0x003F);
+		if (v47F >= 0x20)
+			v47F -= 0x40;
+		if (v47F == -32) {
+			for (i = 0; i < 4; i++) {
+				b43_radio_write16(dev, 0x007B, i);
+				udelay(20);
+				v47F =
+				    (s16) ((b43_phy_read(dev, 0x047F) >> 8) &
+					   0x003F);
+				if (v47F >= 0x20)
+					v47F -= 0x40;
+				if (v47F > -31 && saved == 0xFFFF)
+					saved = i;
+			}
+			if (saved == 0xFFFF)
+				saved = 3;
+		} else
+			saved = 0;
+	}
+	b43_radio_write16(dev, 0x007B, saved);
+
+	if (phy->rev >= 6) {
+		b43_phy_write(dev, 0x002E, backup[12]);
+		b43_phy_write(dev, 0x002F, backup[13]);
+		b43_phy_write(dev, 0x080F, backup[14]);
+		b43_phy_write(dev, 0x0810, backup[15]);
+	}
+	if (phy->rev != 1) {	/* Not in specs, but needed to prevent PPC machine check */
+		b43_phy_write(dev, 0x0814, backup[3]);
+		b43_phy_write(dev, 0x0815, backup[4]);
+	}
+	b43_phy_write(dev, 0x005A, backup[5]);
+	b43_phy_write(dev, 0x0059, backup[6]);
+	b43_phy_write(dev, 0x0058, backup[7]);
+	b43_phy_write(dev, 0x000A, backup[8]);
+	b43_phy_write(dev, 0x0003, backup[9]);
+	b43_radio_write16(dev, 0x0043, backup[11]);
+	b43_radio_write16(dev, 0x007A, backup[10]);
+	b43_phy_write(dev, 0x0802, b43_phy_read(dev, 0x0802) | 0x1 | 0x2);
+	b43_phy_write(dev, 0x0429, b43_phy_read(dev, 0x0429) | 0x8000);
+	b43_set_original_gains(dev);
+	if (phy->rev >= 6) {
+		b43_phy_write(dev, 0x0801, backup[16]);
+		b43_phy_write(dev, 0x0060, backup[17]);
+		b43_phy_write(dev, 0x0014, backup[18]);
+		b43_phy_write(dev, 0x0478, backup[19]);
+	}
+	b43_phy_write(dev, 0x0001, backup[0]);
+	b43_phy_write(dev, 0x0812, backup[2]);
+	b43_phy_write(dev, 0x0811, backup[1]);
+}
+
+void b43_calc_nrssi_slope(struct b43_wldev *dev)
+{
+	struct b43_phy *phy = &dev->phy;
+	struct b43_phy_g *gphy = phy->g;
+	u16 backup[18] = { 0 };
+	u16 tmp;
+	s16 nrssi0, nrssi1;
+
+	B43_WARN_ON(phy->type != B43_PHYTYPE_G);
+
+	if (phy->radio_rev >= 9)
+		return;
+	if (phy->radio_rev == 8)
+		b43_calc_nrssi_offset(dev);
+
+	b43_phy_write(dev, B43_PHY_G_CRS,
+		      b43_phy_read(dev, B43_PHY_G_CRS) & 0x7FFF);
+	b43_phy_write(dev, 0x0802, b43_phy_read(dev, 0x0802) & 0xFFFC);
+	backup[7] = b43_read16(dev, 0x03E2);
+	b43_write16(dev, 0x03E2, b43_read16(dev, 0x03E2) | 0x8000);
+	backup[0] = b43_radio_read16(dev, 0x007A);
+	backup[1] = b43_radio_read16(dev, 0x0052);
+	backup[2] = b43_radio_read16(dev, 0x0043);
+	backup[3] = b43_phy_read(dev, 0x0015);
+	backup[4] = b43_phy_read(dev, 0x005A);
+	backup[5] = b43_phy_read(dev, 0x0059);
+	backup[6] = b43_phy_read(dev, 0x0058);
+	backup[8] = b43_read16(dev, 0x03E6);
+	backup[9] = b43_read16(dev, B43_MMIO_CHANNEL_EXT);
+	if (phy->rev >= 3) {
+		backup[10] = b43_phy_read(dev, 0x002E);
+		backup[11] = b43_phy_read(dev, 0x002F);
+		backup[12] = b43_phy_read(dev, 0x080F);
+		backup[13] = b43_phy_read(dev, B43_PHY_G_LO_CONTROL);
+		backup[14] = b43_phy_read(dev, 0x0801);
+		backup[15] = b43_phy_read(dev, 0x0060);
+		backup[16] = b43_phy_read(dev, 0x0014);
+		backup[17] = b43_phy_read(dev, 0x0478);
+		b43_phy_write(dev, 0x002E, 0);
+		b43_phy_write(dev, B43_PHY_G_LO_CONTROL, 0);
+		switch (phy->rev) {
+		case 4:
+		case 6:
+		case 7:
+			b43_phy_write(dev, 0x0478,
+				      b43_phy_read(dev, 0x0478)
+				      | 0x0100);
+			b43_phy_write(dev, 0x0801,
+				      b43_phy_read(dev, 0x0801)
+				      | 0x0040);
+			break;
+		case 3:
+		case 5:
+			b43_phy_write(dev, 0x0801,
+				      b43_phy_read(dev, 0x0801)
+				      & 0xFFBF);
+			break;
+		}
+		b43_phy_write(dev, 0x0060, b43_phy_read(dev, 0x0060)
+			      | 0x0040);
+		b43_phy_write(dev, 0x0014, b43_phy_read(dev, 0x0014)
+			      | 0x0200);
+	}
+	b43_radio_write16(dev, 0x007A,
+			  b43_radio_read16(dev, 0x007A) | 0x0070);
+	b43_set_all_gains(dev, 0, 8, 0);
+	b43_radio_write16(dev, 0x007A,
+			  b43_radio_read16(dev, 0x007A) & 0x00F7);
+	if (phy->rev >= 2) {
+		b43_phy_write(dev, 0x0811,
+			      (b43_phy_read(dev, 0x0811) & 0xFFCF) |
+			      0x0030);
+		b43_phy_write(dev, 0x0812,
+			      (b43_phy_read(dev, 0x0812) & 0xFFCF) |
+			      0x0010);
+	}
+	b43_radio_write16(dev, 0x007A,
+			  b43_radio_read16(dev, 0x007A) | 0x0080);
+	udelay(20);
+
+	nrssi0 = (s16) ((b43_phy_read(dev, 0x047F) >> 8) & 0x003F);
+	if (nrssi0 >= 0x0020)
+		nrssi0 -= 0x0040;
+
+	b43_radio_write16(dev, 0x007A,
+			  b43_radio_read16(dev, 0x007A) & 0x007F);
+	if (phy->rev >= 2) {
+		b43_phy_write(dev, 0x0003, (b43_phy_read(dev, 0x0003)
+					    & 0xFF9F) | 0x0040);
+	}
+
+	b43_write16(dev, B43_MMIO_CHANNEL_EXT,
+		    b43_read16(dev, B43_MMIO_CHANNEL_EXT)
+		    | 0x2000);
+	b43_radio_write16(dev, 0x007A,
+			  b43_radio_read16(dev, 0x007A) | 0x000F);
+	b43_phy_write(dev, 0x0015, 0xF330);
+	if (phy->rev >= 2) {
+		b43_phy_write(dev, 0x0812,
+			      (b43_phy_read(dev, 0x0812) & 0xFFCF) |
+			      0x0020);
+		b43_phy_write(dev, 0x0811,
+			      (b43_phy_read(dev, 0x0811) & 0xFFCF) |
+			      0x0020);
+	}
+
+	b43_set_all_gains(dev, 3, 0, 1);
+	if (phy->radio_rev == 8) {
+		b43_radio_write16(dev, 0x0043, 0x001F);
+	} else {
+		tmp = b43_radio_read16(dev, 0x0052) & 0xFF0F;
+		b43_radio_write16(dev, 0x0052, tmp | 0x0060);
+		tmp = b43_radio_read16(dev, 0x0043) & 0xFFF0;
+		b43_radio_write16(dev, 0x0043, tmp | 0x0009);
+	}
+	b43_phy_write(dev, 0x005A, 0x0480);
+	b43_phy_write(dev, 0x0059, 0x0810);
+	b43_phy_write(dev, 0x0058, 0x000D);
+	udelay(20);
+	nrssi1 = (s16) ((b43_phy_read(dev, 0x047F) >> 8) & 0x003F);
+	if (nrssi1 >= 0x0020)
+		nrssi1 -= 0x0040;
+	if (nrssi0 == nrssi1)
+		gphy->nrssislope = 0x00010000;
+	else
+		gphy->nrssislope = 0x00400000 / (nrssi0 - nrssi1);
+	if (nrssi0 >= -4) {
+		gphy->nrssi[0] = nrssi1;
+		gphy->nrssi[1] = nrssi0;
+	}
+	if (phy->rev >= 3) {
+		b43_phy_write(dev, 0x002E, backup[10]);
+		b43_phy_write(dev, 0x002F, backup[11]);
+		b43_phy_write(dev, 0x080F, backup[12]);
+		b43_phy_write(dev, B43_PHY_G_LO_CONTROL, backup[13]);
+	}
+	if (phy->rev >= 2) {
+		b43_phy_write(dev, 0x0812,
+			      b43_phy_read(dev, 0x0812) & 0xFFCF);
+		b43_phy_write(dev, 0x0811,
+			      b43_phy_read(dev, 0x0811) & 0xFFCF);
+	}
+
+	b43_radio_write16(dev, 0x007A, backup[0]);
+	b43_radio_write16(dev, 0x0052, backup[1]);
+	b43_radio_write16(dev, 0x0043, backup[2]);
+	b43_write16(dev, 0x03E2, backup[7]);
+	b43_write16(dev, 0x03E6, backup[8]);
+	b43_write16(dev, B43_MMIO_CHANNEL_EXT, backup[9]);
+	b43_phy_write(dev, 0x0015, backup[3]);
+	b43_phy_write(dev, 0x005A, backup[4]);
+	b43_phy_write(dev, 0x0059, backup[5]);
+	b43_phy_write(dev, 0x0058, backup[6]);
+	b43_synth_pu_workaround(dev, phy->channel);
+	b43_phy_write(dev, 0x0802,
+		      b43_phy_read(dev, 0x0802) | (0x0001 | 0x0002));
+	b43_set_original_gains(dev);
+	b43_phy_write(dev, B43_PHY_G_CRS,
+		      b43_phy_read(dev, B43_PHY_G_CRS) | 0x8000);
+	if (phy->rev >= 3) {
+		b43_phy_write(dev, 0x0801, backup[14]);
+		b43_phy_write(dev, 0x0060, backup[15]);
+		b43_phy_write(dev, 0x0014, backup[16]);
+		b43_phy_write(dev, 0x0478, backup[17]);
+	}
+	b43_nrssi_mem_update(dev);
+	b43_calc_nrssi_threshold(dev);
+}
+
+static void b43_calc_nrssi_threshold(struct b43_wldev *dev)
+{
+	struct b43_phy *phy = &dev->phy;
+	struct b43_phy_g *gphy = phy->g;
+	s32 a, b;
+	s16 tmp16;
+	u16 tmp_u16;
+
+	B43_WARN_ON(phy->type != B43_PHYTYPE_G);
+
+	if (!phy->gmode ||
+	    !(dev->dev->bus->sprom.boardflags_lo & B43_BFL_RSSI)) {
+		tmp16 = b43_nrssi_hw_read(dev, 0x20);
+		if (tmp16 >= 0x20)
+			tmp16 -= 0x40;
+		if (tmp16 < 3) {
+			b43_phy_write(dev, 0x048A,
+				      (b43_phy_read(dev, 0x048A)
+				       & 0xF000) | 0x09EB);
+		} else {
+			b43_phy_write(dev, 0x048A,
+				      (b43_phy_read(dev, 0x048A)
+				       & 0xF000) | 0x0AED);
+		}
+	} else {
+		if (gphy->interfmode == B43_INTERFMODE_NONWLAN) {
+			a = 0xE;
+			b = 0xA;
+		} else if (!gphy->aci_wlan_automatic && gphy->aci_enable) {
+			a = 0x13;
+			b = 0x12;
+		} else {
+			a = 0xE;
+			b = 0x11;
+		}
+
+		a = a * (gphy->nrssi[1] - gphy->nrssi[0]);
+		a += (gphy->nrssi[0] << 6);
+		if (a < 32)
+			a += 31;
+		else
+			a += 32;
+		a = a >> 6;
+		a = clamp_val(a, -31, 31);
+
+		b = b * (gphy->nrssi[1] - gphy->nrssi[0]);
+		b += (gphy->nrssi[0] << 6);
+		if (b < 32)
+			b += 31;
+		else
+			b += 32;
+		b = b >> 6;
+		b = clamp_val(b, -31, 31);
+
+		tmp_u16 = b43_phy_read(dev, 0x048A) & 0xF000;
+		tmp_u16 |= ((u32) b & 0x0000003F);
+		tmp_u16 |= (((u32) a & 0x0000003F) << 6);
+		b43_phy_write(dev, 0x048A, tmp_u16);
+	}
+}
+
+/* Stack implementation to save/restore values from the
+ * interference mitigation code.
+ * It is save to restore values in random order.
+ */
+static void _stack_save(u32 * _stackptr, size_t * stackidx,
+			u8 id, u16 offset, u16 value)
+{
+	u32 *stackptr = &(_stackptr[*stackidx]);
+
+	B43_WARN_ON(offset & 0xF000);
+	B43_WARN_ON(id & 0xF0);
+	*stackptr = offset;
+	*stackptr |= ((u32) id) << 12;
+	*stackptr |= ((u32) value) << 16;
+	(*stackidx)++;
+	B43_WARN_ON(*stackidx >= B43_INTERFSTACK_SIZE);
+}
+
+static u16 _stack_restore(u32 * stackptr, u8 id, u16 offset)
+{
+	size_t i;
+
+	B43_WARN_ON(offset & 0xF000);
+	B43_WARN_ON(id & 0xF0);
+	for (i = 0; i < B43_INTERFSTACK_SIZE; i++, stackptr++) {
+		if ((*stackptr & 0x00000FFF) != offset)
+			continue;
+		if (((*stackptr & 0x0000F000) >> 12) != id)
+			continue;
+		return ((*stackptr & 0xFFFF0000) >> 16);
+	}
+	B43_WARN_ON(1);
+
+	return 0;
+}
+
+#define phy_stacksave(offset)					\
+	do {							\
+		_stack_save(stack, &stackidx, 0x1, (offset),	\
+			    b43_phy_read(dev, (offset)));	\
+	} while (0)
+#define phy_stackrestore(offset)				\
+	do {							\
+		b43_phy_write(dev, (offset),		\
+				  _stack_restore(stack, 0x1,	\
+						 (offset)));	\
+	} while (0)
+#define radio_stacksave(offset)						\
+	do {								\
+		_stack_save(stack, &stackidx, 0x2, (offset),		\
+			    b43_radio_read16(dev, (offset)));	\
+	} while (0)
+#define radio_stackrestore(offset)					\
+	do {								\
+		b43_radio_write16(dev, (offset),			\
+				      _stack_restore(stack, 0x2,	\
+						     (offset)));	\
+	} while (0)
+#define ofdmtab_stacksave(table, offset)			\
+	do {							\
+		_stack_save(stack, &stackidx, 0x3, (offset)|(table),	\
+			    b43_ofdmtab_read16(dev, (table), (offset)));	\
+	} while (0)
+#define ofdmtab_stackrestore(table, offset)			\
+	do {							\
+		b43_ofdmtab_write16(dev, (table),	(offset),	\
+				  _stack_restore(stack, 0x3,	\
+						 (offset)|(table)));	\
+	} while (0)
+
+static void
+b43_radio_interference_mitigation_enable(struct b43_wldev *dev, int mode)
+{
+	struct b43_phy *phy = &dev->phy;
+	struct b43_phy_g *gphy = phy->g;
+	u16 tmp, flipped;
+	size_t stackidx = 0;
+	u32 *stack = gphy->interfstack;
+
+	switch (mode) {
+	case B43_INTERFMODE_NONWLAN:
+		if (phy->rev != 1) {
+			b43_phy_write(dev, 0x042B,
+				      b43_phy_read(dev, 0x042B) | 0x0800);
+			b43_phy_write(dev, B43_PHY_G_CRS,
+				      b43_phy_read(dev,
+						   B43_PHY_G_CRS) & ~0x4000);
+			break;
+		}
+		radio_stacksave(0x0078);
+		tmp = (b43_radio_read16(dev, 0x0078) & 0x001E);
+		B43_WARN_ON(tmp > 15);
+		flipped = bitrev4(tmp);
+		if (flipped < 10 && flipped >= 8)
+			flipped = 7;
+		else if (flipped >= 10)
+			flipped -= 3;
+		flipped = (bitrev4(flipped) << 1) | 0x0020;
+		b43_radio_write16(dev, 0x0078, flipped);
+
+		b43_calc_nrssi_threshold(dev);
+
+		phy_stacksave(0x0406);
+		b43_phy_write(dev, 0x0406, 0x7E28);
+
+		b43_phy_write(dev, 0x042B, b43_phy_read(dev, 0x042B) | 0x0800);
+		b43_phy_write(dev, B43_PHY_RADIO_BITFIELD,
+			      b43_phy_read(dev,
+					   B43_PHY_RADIO_BITFIELD) | 0x1000);
+
+		phy_stacksave(0x04A0);
+		b43_phy_write(dev, 0x04A0,
+			      (b43_phy_read(dev, 0x04A0) & 0xC0C0) | 0x0008);
+		phy_stacksave(0x04A1);
+		b43_phy_write(dev, 0x04A1,
+			      (b43_phy_read(dev, 0x04A1) & 0xC0C0) | 0x0605);
+		phy_stacksave(0x04A2);
+		b43_phy_write(dev, 0x04A2,
+			      (b43_phy_read(dev, 0x04A2) & 0xC0C0) | 0x0204);
+		phy_stacksave(0x04A8);
+		b43_phy_write(dev, 0x04A8,
+			      (b43_phy_read(dev, 0x04A8) & 0xC0C0) | 0x0803);
+		phy_stacksave(0x04AB);
+		b43_phy_write(dev, 0x04AB,
+			      (b43_phy_read(dev, 0x04AB) & 0xC0C0) | 0x0605);
+
+		phy_stacksave(0x04A7);
+		b43_phy_write(dev, 0x04A7, 0x0002);
+		phy_stacksave(0x04A3);
+		b43_phy_write(dev, 0x04A3, 0x287A);
+		phy_stacksave(0x04A9);
+		b43_phy_write(dev, 0x04A9, 0x2027);
+		phy_stacksave(0x0493);
+		b43_phy_write(dev, 0x0493, 0x32F5);
+		phy_stacksave(0x04AA);
+		b43_phy_write(dev, 0x04AA, 0x2027);
+		phy_stacksave(0x04AC);
+		b43_phy_write(dev, 0x04AC, 0x32F5);
+		break;
+	case B43_INTERFMODE_MANUALWLAN:
+		if (b43_phy_read(dev, 0x0033) & 0x0800)
+			break;
+
+		gphy->aci_enable = 1;
+
+		phy_stacksave(B43_PHY_RADIO_BITFIELD);
+		phy_stacksave(B43_PHY_G_CRS);
+		if (phy->rev < 2) {
+			phy_stacksave(0x0406);
+		} else {
+			phy_stacksave(0x04C0);
+			phy_stacksave(0x04C1);
+		}
+		phy_stacksave(0x0033);
+		phy_stacksave(0x04A7);
+		phy_stacksave(0x04A3);
+		phy_stacksave(0x04A9);
+		phy_stacksave(0x04AA);
+		phy_stacksave(0x04AC);
+		phy_stacksave(0x0493);
+		phy_stacksave(0x04A1);
+		phy_stacksave(0x04A0);
+		phy_stacksave(0x04A2);
+		phy_stacksave(0x048A);
+		phy_stacksave(0x04A8);
+		phy_stacksave(0x04AB);
+		if (phy->rev == 2) {
+			phy_stacksave(0x04AD);
+			phy_stacksave(0x04AE);
+		} else if (phy->rev >= 3) {
+			phy_stacksave(0x04AD);
+			phy_stacksave(0x0415);
+			phy_stacksave(0x0416);
+			phy_stacksave(0x0417);
+			ofdmtab_stacksave(0x1A00, 0x2);
+			ofdmtab_stacksave(0x1A00, 0x3);
+		}
+		phy_stacksave(0x042B);
+		phy_stacksave(0x048C);
+
+		b43_phy_write(dev, B43_PHY_RADIO_BITFIELD,
+			      b43_phy_read(dev, B43_PHY_RADIO_BITFIELD)
+			      & ~0x1000);
+		b43_phy_write(dev, B43_PHY_G_CRS,
+			      (b43_phy_read(dev, B43_PHY_G_CRS)
+			       & 0xFFFC) | 0x0002);
+
+		b43_phy_write(dev, 0x0033, 0x0800);
+		b43_phy_write(dev, 0x04A3, 0x2027);
+		b43_phy_write(dev, 0x04A9, 0x1CA8);
+		b43_phy_write(dev, 0x0493, 0x287A);
+		b43_phy_write(dev, 0x04AA, 0x1CA8);
+		b43_phy_write(dev, 0x04AC, 0x287A);
+
+		b43_phy_write(dev, 0x04A0, (b43_phy_read(dev, 0x04A0)
+					    & 0xFFC0) | 0x001A);
+		b43_phy_write(dev, 0x04A7, 0x000D);
+
+		if (phy->rev < 2) {
+			b43_phy_write(dev, 0x0406, 0xFF0D);
+		} else if (phy->rev == 2) {
+			b43_phy_write(dev, 0x04C0, 0xFFFF);
+			b43_phy_write(dev, 0x04C1, 0x00A9);
+		} else {
+			b43_phy_write(dev, 0x04C0, 0x00C1);
+			b43_phy_write(dev, 0x04C1, 0x0059);
+		}
+
+		b43_phy_write(dev, 0x04A1, (b43_phy_read(dev, 0x04A1)
+					    & 0xC0FF) | 0x1800);
+		b43_phy_write(dev, 0x04A1, (b43_phy_read(dev, 0x04A1)
+					    & 0xFFC0) | 0x0015);
+		b43_phy_write(dev, 0x04A8, (b43_phy_read(dev, 0x04A8)
+					    & 0xCFFF) | 0x1000);
+		b43_phy_write(dev, 0x04A8, (b43_phy_read(dev, 0x04A8)
+					    & 0xF0FF) | 0x0A00);
+		b43_phy_write(dev, 0x04AB, (b43_phy_read(dev, 0x04AB)
+					    & 0xCFFF) | 0x1000);
+		b43_phy_write(dev, 0x04AB, (b43_phy_read(dev, 0x04AB)
+					    & 0xF0FF) | 0x0800);
+		b43_phy_write(dev, 0x04AB, (b43_phy_read(dev, 0x04AB)
+					    & 0xFFCF) | 0x0010);
+		b43_phy_write(dev, 0x04AB, (b43_phy_read(dev, 0x04AB)
+					    & 0xFFF0) | 0x0005);
+		b43_phy_write(dev, 0x04A8, (b43_phy_read(dev, 0x04A8)
+					    & 0xFFCF) | 0x0010);
+		b43_phy_write(dev, 0x04A8, (b43_phy_read(dev, 0x04A8)
+					    & 0xFFF0) | 0x0006);
+		b43_phy_write(dev, 0x04A2, (b43_phy_read(dev, 0x04A2)
+					    & 0xF0FF) | 0x0800);
+		b43_phy_write(dev, 0x04A0, (b43_phy_read(dev, 0x04A0)
+					    & 0xF0FF) | 0x0500);
+		b43_phy_write(dev, 0x04A2, (b43_phy_read(dev, 0x04A2)
+					    & 0xFFF0) | 0x000B);
+
+		if (phy->rev >= 3) {
+			b43_phy_write(dev, 0x048A, b43_phy_read(dev, 0x048A)
+				      & ~0x8000);
+			b43_phy_write(dev, 0x0415, (b43_phy_read(dev, 0x0415)
+						    & 0x8000) | 0x36D8);
+			b43_phy_write(dev, 0x0416, (b43_phy_read(dev, 0x0416)
+						    & 0x8000) | 0x36D8);
+			b43_phy_write(dev, 0x0417, (b43_phy_read(dev, 0x0417)
+						    & 0xFE00) | 0x016D);
+		} else {
+			b43_phy_write(dev, 0x048A, b43_phy_read(dev, 0x048A)
+				      | 0x1000);
+			b43_phy_write(dev, 0x048A, (b43_phy_read(dev, 0x048A)
+						    & 0x9FFF) | 0x2000);
+			b43_hf_write(dev, b43_hf_read(dev) | B43_HF_ACIW);
+		}
+		if (phy->rev >= 2) {
+			b43_phy_write(dev, 0x042B, b43_phy_read(dev, 0x042B)
+				      | 0x0800);
+		}
+		b43_phy_write(dev, 0x048C, (b43_phy_read(dev, 0x048C)
+					    & 0xF0FF) | 0x0200);
+		if (phy->rev == 2) {
+			b43_phy_write(dev, 0x04AE, (b43_phy_read(dev, 0x04AE)
+						    & 0xFF00) | 0x007F);
+			b43_phy_write(dev, 0x04AD, (b43_phy_read(dev, 0x04AD)
+						    & 0x00FF) | 0x1300);
+		} else if (phy->rev >= 6) {
+			b43_ofdmtab_write16(dev, 0x1A00, 0x3, 0x007F);
+			b43_ofdmtab_write16(dev, 0x1A00, 0x2, 0x007F);
+			b43_phy_write(dev, 0x04AD, b43_phy_read(dev, 0x04AD)
+				      & 0x00FF);
+		}
+		b43_calc_nrssi_slope(dev);
+		break;
+	default:
+		B43_WARN_ON(1);
+	}
+}
+
+static void
+b43_radio_interference_mitigation_disable(struct b43_wldev *dev, int mode)
+{
+	struct b43_phy *phy = &dev->phy;
+	struct b43_phy_g *gphy = phy->g;
+	u32 *stack = gphy->interfstack;
+
+	switch (mode) {
+	case B43_INTERFMODE_NONWLAN:
+		if (phy->rev != 1) {
+			b43_phy_write(dev, 0x042B,
+				      b43_phy_read(dev, 0x042B) & ~0x0800);
+			b43_phy_write(dev, B43_PHY_G_CRS,
+				      b43_phy_read(dev,
+						   B43_PHY_G_CRS) | 0x4000);
+			break;
+		}
+		radio_stackrestore(0x0078);
+		b43_calc_nrssi_threshold(dev);
+		phy_stackrestore(0x0406);
+		b43_phy_write(dev, 0x042B, b43_phy_read(dev, 0x042B) & ~0x0800);
+		if (!dev->bad_frames_preempt) {
+			b43_phy_write(dev, B43_PHY_RADIO_BITFIELD,
+				      b43_phy_read(dev, B43_PHY_RADIO_BITFIELD)
+				      & ~(1 << 11));
+		}
+		b43_phy_write(dev, B43_PHY_G_CRS,
+			      b43_phy_read(dev, B43_PHY_G_CRS) | 0x4000);
+		phy_stackrestore(0x04A0);
+		phy_stackrestore(0x04A1);
+		phy_stackrestore(0x04A2);
+		phy_stackrestore(0x04A8);
+		phy_stackrestore(0x04AB);
+		phy_stackrestore(0x04A7);
+		phy_stackrestore(0x04A3);
+		phy_stackrestore(0x04A9);
+		phy_stackrestore(0x0493);
+		phy_stackrestore(0x04AA);
+		phy_stackrestore(0x04AC);
+		break;
+	case B43_INTERFMODE_MANUALWLAN:
+		if (!(b43_phy_read(dev, 0x0033) & 0x0800))
+			break;
+
+		gphy->aci_enable = 0;
+
+		phy_stackrestore(B43_PHY_RADIO_BITFIELD);
+		phy_stackrestore(B43_PHY_G_CRS);
+		phy_stackrestore(0x0033);
+		phy_stackrestore(0x04A3);
+		phy_stackrestore(0x04A9);
+		phy_stackrestore(0x0493);
+		phy_stackrestore(0x04AA);
+		phy_stackrestore(0x04AC);
+		phy_stackrestore(0x04A0);
+		phy_stackrestore(0x04A7);
+		if (phy->rev >= 2) {
+			phy_stackrestore(0x04C0);
+			phy_stackrestore(0x04C1);
+		} else
+			phy_stackrestore(0x0406);
+		phy_stackrestore(0x04A1);
+		phy_stackrestore(0x04AB);
+		phy_stackrestore(0x04A8);
+		if (phy->rev == 2) {
+			phy_stackrestore(0x04AD);
+			phy_stackrestore(0x04AE);
+		} else if (phy->rev >= 3) {
+			phy_stackrestore(0x04AD);
+			phy_stackrestore(0x0415);
+			phy_stackrestore(0x0416);
+			phy_stackrestore(0x0417);
+			ofdmtab_stackrestore(0x1A00, 0x2);
+			ofdmtab_stackrestore(0x1A00, 0x3);
+		}
+		phy_stackrestore(0x04A2);
+		phy_stackrestore(0x048A);
+		phy_stackrestore(0x042B);
+		phy_stackrestore(0x048C);
+		b43_hf_write(dev, b43_hf_read(dev) & ~B43_HF_ACIW);
+		b43_calc_nrssi_slope(dev);
+		break;
+	default:
+		B43_WARN_ON(1);
+	}
+}
+
+#undef phy_stacksave
+#undef phy_stackrestore
+#undef radio_stacksave
+#undef radio_stackrestore
+#undef ofdmtab_stacksave
+#undef ofdmtab_stackrestore
+
+static u16 b43_radio_core_calibration_value(struct b43_wldev *dev)
+{
+	u16 reg, index, ret;
+
+	static const u8 rcc_table[] = {
+		0x02, 0x03, 0x01, 0x0F,
+		0x06, 0x07, 0x05, 0x0F,
+		0x0A, 0x0B, 0x09, 0x0F,
+		0x0E, 0x0F, 0x0D, 0x0F,
+	};
+
+	reg = b43_radio_read16(dev, 0x60);
+	index = (reg & 0x001E) >> 1;
+	ret = rcc_table[index] << 1;
+	ret |= (reg & 0x0001);
+	ret |= 0x0020;
+
+	return ret;
+}
+
+#define LPD(L, P, D)	(((L) << 2) | ((P) << 1) | ((D) << 0))
+static u16 radio2050_rfover_val(struct b43_wldev *dev,
+				u16 phy_register, unsigned int lpd)
+{
+	struct b43_phy *phy = &dev->phy;
+	struct b43_phy_g *gphy = phy->g;
+	struct ssb_sprom *sprom = &(dev->dev->bus->sprom);
+
+	if (!phy->gmode)
+		return 0;
+
+	if (has_loopback_gain(phy)) {
+		int max_lb_gain = gphy->max_lb_gain;
+		u16 extlna;
+		u16 i;
+
+		if (phy->radio_rev == 8)
+			max_lb_gain += 0x3E;
+		else
+			max_lb_gain += 0x26;
+		if (max_lb_gain >= 0x46) {
+			extlna = 0x3000;
+			max_lb_gain -= 0x46;
+		} else if (max_lb_gain >= 0x3A) {
+			extlna = 0x1000;
+			max_lb_gain -= 0x3A;
+		} else if (max_lb_gain >= 0x2E) {
+			extlna = 0x2000;
+			max_lb_gain -= 0x2E;
+		} else {
+			extlna = 0;
+			max_lb_gain -= 0x10;
+		}
+
+		for (i = 0; i < 16; i++) {
+			max_lb_gain -= (i * 6);
+			if (max_lb_gain < 6)
+				break;
+		}
+
+		if ((phy->rev < 7) ||
+		    !(sprom->boardflags_lo & B43_BFL_EXTLNA)) {
+			if (phy_register == B43_PHY_RFOVER) {
+				return 0x1B3;
+			} else if (phy_register == B43_PHY_RFOVERVAL) {
+				extlna |= (i << 8);
+				switch (lpd) {
+				case LPD(0, 1, 1):
+					return 0x0F92;
+				case LPD(0, 0, 1):
+				case LPD(1, 0, 1):
+					return (0x0092 | extlna);
+				case LPD(1, 0, 0):
+					return (0x0093 | extlna);
+				}
+				B43_WARN_ON(1);
+			}
+			B43_WARN_ON(1);
+		} else {
+			if (phy_register == B43_PHY_RFOVER) {
+				return 0x9B3;
+			} else if (phy_register == B43_PHY_RFOVERVAL) {
+				if (extlna)
+					extlna |= 0x8000;
+				extlna |= (i << 8);
+				switch (lpd) {
+				case LPD(0, 1, 1):
+					return 0x8F92;
+				case LPD(0, 0, 1):
+					return (0x8092 | extlna);
+				case LPD(1, 0, 1):
+					return (0x2092 | extlna);
+				case LPD(1, 0, 0):
+					return (0x2093 | extlna);
+				}
+				B43_WARN_ON(1);
+			}
+			B43_WARN_ON(1);
+		}
+	} else {
+		if ((phy->rev < 7) ||
+		    !(sprom->boardflags_lo & B43_BFL_EXTLNA)) {
+			if (phy_register == B43_PHY_RFOVER) {
+				return 0x1B3;
+			} else if (phy_register == B43_PHY_RFOVERVAL) {
+				switch (lpd) {
+				case LPD(0, 1, 1):
+					return 0x0FB2;
+				case LPD(0, 0, 1):
+					return 0x00B2;
+				case LPD(1, 0, 1):
+					return 0x30B2;
+				case LPD(1, 0, 0):
+					return 0x30B3;
+				}
+				B43_WARN_ON(1);
+			}
+			B43_WARN_ON(1);
+		} else {
+			if (phy_register == B43_PHY_RFOVER) {
+				return 0x9B3;
+			} else if (phy_register == B43_PHY_RFOVERVAL) {
+				switch (lpd) {
+				case LPD(0, 1, 1):
+					return 0x8FB2;
+				case LPD(0, 0, 1):
+					return 0x80B2;
+				case LPD(1, 0, 1):
+					return 0x20B2;
+				case LPD(1, 0, 0):
+					return 0x20B3;
+				}
+				B43_WARN_ON(1);
+			}
+			B43_WARN_ON(1);
+		}
+	}
+	return 0;
+}
+
+struct init2050_saved_values {
+	/* Core registers */
+	u16 reg_3EC;
+	u16 reg_3E6;
+	u16 reg_3F4;
+	/* Radio registers */
+	u16 radio_43;
+	u16 radio_51;
+	u16 radio_52;
+	/* PHY registers */
+	u16 phy_pgactl;
+	u16 phy_cck_5A;
+	u16 phy_cck_59;
+	u16 phy_cck_58;
+	u16 phy_cck_30;
+	u16 phy_rfover;
+	u16 phy_rfoverval;
+	u16 phy_analogover;
+	u16 phy_analogoverval;
+	u16 phy_crs0;
+	u16 phy_classctl;
+	u16 phy_lo_mask;
+	u16 phy_lo_ctl;
+	u16 phy_syncctl;
+};
+
+u16 b43_radio_init2050(struct b43_wldev *dev)
+{
+	struct b43_phy *phy = &dev->phy;
+	struct init2050_saved_values sav;
+	u16 rcc;
+	u16 radio78;
+	u16 ret;
+	u16 i, j;
+	u32 tmp1 = 0, tmp2 = 0;
+
+	memset(&sav, 0, sizeof(sav));	/* get rid of "may be used uninitialized..." */
+
+	sav.radio_43 = b43_radio_read16(dev, 0x43);
+	sav.radio_51 = b43_radio_read16(dev, 0x51);
+	sav.radio_52 = b43_radio_read16(dev, 0x52);
+	sav.phy_pgactl = b43_phy_read(dev, B43_PHY_PGACTL);
+	sav.phy_cck_5A = b43_phy_read(dev, B43_PHY_CCK(0x5A));
+	sav.phy_cck_59 = b43_phy_read(dev, B43_PHY_CCK(0x59));
+	sav.phy_cck_58 = b43_phy_read(dev, B43_PHY_CCK(0x58));
+
+	if (phy->type == B43_PHYTYPE_B) {
+		sav.phy_cck_30 = b43_phy_read(dev, B43_PHY_CCK(0x30));
+		sav.reg_3EC = b43_read16(dev, 0x3EC);
+
+		b43_phy_write(dev, B43_PHY_CCK(0x30), 0xFF);
+		b43_write16(dev, 0x3EC, 0x3F3F);
+	} else if (phy->gmode || phy->rev >= 2) {
+		sav.phy_rfover = b43_phy_read(dev, B43_PHY_RFOVER);
+		sav.phy_rfoverval = b43_phy_read(dev, B43_PHY_RFOVERVAL);
+		sav.phy_analogover = b43_phy_read(dev, B43_PHY_ANALOGOVER);
+		sav.phy_analogoverval =
+		    b43_phy_read(dev, B43_PHY_ANALOGOVERVAL);
+		sav.phy_crs0 = b43_phy_read(dev, B43_PHY_CRS0);
+		sav.phy_classctl = b43_phy_read(dev, B43_PHY_CLASSCTL);
+
+		b43_phy_write(dev, B43_PHY_ANALOGOVER,
+			      b43_phy_read(dev, B43_PHY_ANALOGOVER)
+			      | 0x0003);
+		b43_phy_write(dev, B43_PHY_ANALOGOVERVAL,
+			      b43_phy_read(dev, B43_PHY_ANALOGOVERVAL)
+			      & 0xFFFC);
+		b43_phy_write(dev, B43_PHY_CRS0, b43_phy_read(dev, B43_PHY_CRS0)
+			      & 0x7FFF);
+		b43_phy_write(dev, B43_PHY_CLASSCTL,
+			      b43_phy_read(dev, B43_PHY_CLASSCTL)
+			      & 0xFFFC);
+		if (has_loopback_gain(phy)) {
+			sav.phy_lo_mask = b43_phy_read(dev, B43_PHY_LO_MASK);
+			sav.phy_lo_ctl = b43_phy_read(dev, B43_PHY_LO_CTL);
+
+			if (phy->rev >= 3)
+				b43_phy_write(dev, B43_PHY_LO_MASK, 0xC020);
+			else
+				b43_phy_write(dev, B43_PHY_LO_MASK, 0x8020);
+			b43_phy_write(dev, B43_PHY_LO_CTL, 0);
+		}
+
+		b43_phy_write(dev, B43_PHY_RFOVERVAL,
+			      radio2050_rfover_val(dev, B43_PHY_RFOVERVAL,
+						   LPD(0, 1, 1)));
+		b43_phy_write(dev, B43_PHY_RFOVER,
+			      radio2050_rfover_val(dev, B43_PHY_RFOVER, 0));
+	}
+	b43_write16(dev, 0x3E2, b43_read16(dev, 0x3E2) | 0x8000);
+
+	sav.phy_syncctl = b43_phy_read(dev, B43_PHY_SYNCCTL);
+	b43_phy_write(dev, B43_PHY_SYNCCTL, b43_phy_read(dev, B43_PHY_SYNCCTL)
+		      & 0xFF7F);
+	sav.reg_3E6 = b43_read16(dev, 0x3E6);
+	sav.reg_3F4 = b43_read16(dev, 0x3F4);
+
+	if (phy->analog == 0) {
+		b43_write16(dev, 0x03E6, 0x0122);
+	} else {
+		if (phy->analog >= 2) {
+			b43_phy_write(dev, B43_PHY_CCK(0x03),
+				      (b43_phy_read(dev, B43_PHY_CCK(0x03))
+				       & 0xFFBF) | 0x40);
+		}
+		b43_write16(dev, B43_MMIO_CHANNEL_EXT,
+			    (b43_read16(dev, B43_MMIO_CHANNEL_EXT) | 0x2000));
+	}
+
+	rcc = b43_radio_core_calibration_value(dev);
+
+	if (phy->type == B43_PHYTYPE_B)
+		b43_radio_write16(dev, 0x78, 0x26);
+	if (phy->gmode || phy->rev >= 2) {
+		b43_phy_write(dev, B43_PHY_RFOVERVAL,
+			      radio2050_rfover_val(dev, B43_PHY_RFOVERVAL,
+						   LPD(0, 1, 1)));
+	}
+	b43_phy_write(dev, B43_PHY_PGACTL, 0xBFAF);
+	b43_phy_write(dev, B43_PHY_CCK(0x2B), 0x1403);
+	if (phy->gmode || phy->rev >= 2) {
+		b43_phy_write(dev, B43_PHY_RFOVERVAL,
+			      radio2050_rfover_val(dev, B43_PHY_RFOVERVAL,
+						   LPD(0, 0, 1)));
+	}
+	b43_phy_write(dev, B43_PHY_PGACTL, 0xBFA0);
+	b43_radio_write16(dev, 0x51, b43_radio_read16(dev, 0x51)
+			  | 0x0004);
+	if (phy->radio_rev == 8) {
+		b43_radio_write16(dev, 0x43, 0x1F);
+	} else {
+		b43_radio_write16(dev, 0x52, 0);
+		b43_radio_write16(dev, 0x43, (b43_radio_read16(dev, 0x43)
+					      & 0xFFF0) | 0x0009);
+	}
+	b43_phy_write(dev, B43_PHY_CCK(0x58), 0);
+
+	for (i = 0; i < 16; i++) {
+		b43_phy_write(dev, B43_PHY_CCK(0x5A), 0x0480);
+		b43_phy_write(dev, B43_PHY_CCK(0x59), 0xC810);
+		b43_phy_write(dev, B43_PHY_CCK(0x58), 0x000D);
+		if (phy->gmode || phy->rev >= 2) {
+			b43_phy_write(dev, B43_PHY_RFOVERVAL,
+				      radio2050_rfover_val(dev,
+							   B43_PHY_RFOVERVAL,
+							   LPD(1, 0, 1)));
+		}
+		b43_phy_write(dev, B43_PHY_PGACTL, 0xAFB0);
+		udelay(10);
+		if (phy->gmode || phy->rev >= 2) {
+			b43_phy_write(dev, B43_PHY_RFOVERVAL,
+				      radio2050_rfover_val(dev,
+							   B43_PHY_RFOVERVAL,
+							   LPD(1, 0, 1)));
+		}
+		b43_phy_write(dev, B43_PHY_PGACTL, 0xEFB0);
+		udelay(10);
+		if (phy->gmode || phy->rev >= 2) {
+			b43_phy_write(dev, B43_PHY_RFOVERVAL,
+				      radio2050_rfover_val(dev,
+							   B43_PHY_RFOVERVAL,
+							   LPD(1, 0, 0)));
+		}
+		b43_phy_write(dev, B43_PHY_PGACTL, 0xFFF0);
+		udelay(20);
+		tmp1 += b43_phy_read(dev, B43_PHY_LO_LEAKAGE);
+		b43_phy_write(dev, B43_PHY_CCK(0x58), 0);
+		if (phy->gmode || phy->rev >= 2) {
+			b43_phy_write(dev, B43_PHY_RFOVERVAL,
+				      radio2050_rfover_val(dev,
+							   B43_PHY_RFOVERVAL,
+							   LPD(1, 0, 1)));
+		}
+		b43_phy_write(dev, B43_PHY_PGACTL, 0xAFB0);
+	}
+	udelay(10);
+
+	b43_phy_write(dev, B43_PHY_CCK(0x58), 0);
+	tmp1++;
+	tmp1 >>= 9;
+
+	for (i = 0; i < 16; i++) {
+		radio78 = (bitrev4(i) << 1) | 0x0020;
+		b43_radio_write16(dev, 0x78, radio78);
+		udelay(10);
+		for (j = 0; j < 16; j++) {
+			b43_phy_write(dev, B43_PHY_CCK(0x5A), 0x0D80);
+			b43_phy_write(dev, B43_PHY_CCK(0x59), 0xC810);
+			b43_phy_write(dev, B43_PHY_CCK(0x58), 0x000D);
+			if (phy->gmode || phy->rev >= 2) {
+				b43_phy_write(dev, B43_PHY_RFOVERVAL,
+					      radio2050_rfover_val(dev,
+								   B43_PHY_RFOVERVAL,
+								   LPD(1, 0,
+								       1)));
+			}
+			b43_phy_write(dev, B43_PHY_PGACTL, 0xAFB0);
+			udelay(10);
+			if (phy->gmode || phy->rev >= 2) {
+				b43_phy_write(dev, B43_PHY_RFOVERVAL,
+					      radio2050_rfover_val(dev,
+								   B43_PHY_RFOVERVAL,
+								   LPD(1, 0,
+								       1)));
+			}
+			b43_phy_write(dev, B43_PHY_PGACTL, 0xEFB0);
+			udelay(10);
+			if (phy->gmode || phy->rev >= 2) {
+				b43_phy_write(dev, B43_PHY_RFOVERVAL,
+					      radio2050_rfover_val(dev,
+								   B43_PHY_RFOVERVAL,
+								   LPD(1, 0,
+								       0)));
+			}
+			b43_phy_write(dev, B43_PHY_PGACTL, 0xFFF0);
+			udelay(10);
+			tmp2 += b43_phy_read(dev, B43_PHY_LO_LEAKAGE);
+			b43_phy_write(dev, B43_PHY_CCK(0x58), 0);
+			if (phy->gmode || phy->rev >= 2) {
+				b43_phy_write(dev, B43_PHY_RFOVERVAL,
+					      radio2050_rfover_val(dev,
+								   B43_PHY_RFOVERVAL,
+								   LPD(1, 0,
+								       1)));
+			}
+			b43_phy_write(dev, B43_PHY_PGACTL, 0xAFB0);
+		}
+		tmp2++;
+		tmp2 >>= 8;
+		if (tmp1 < tmp2)
+			break;
+	}
+
+	/* Restore the registers */
+	b43_phy_write(dev, B43_PHY_PGACTL, sav.phy_pgactl);
+	b43_radio_write16(dev, 0x51, sav.radio_51);
+	b43_radio_write16(dev, 0x52, sav.radio_52);
+	b43_radio_write16(dev, 0x43, sav.radio_43);
+	b43_phy_write(dev, B43_PHY_CCK(0x5A), sav.phy_cck_5A);
+	b43_phy_write(dev, B43_PHY_CCK(0x59), sav.phy_cck_59);
+	b43_phy_write(dev, B43_PHY_CCK(0x58), sav.phy_cck_58);
+	b43_write16(dev, 0x3E6, sav.reg_3E6);
+	if (phy->analog != 0)
+		b43_write16(dev, 0x3F4, sav.reg_3F4);
+	b43_phy_write(dev, B43_PHY_SYNCCTL, sav.phy_syncctl);
+	b43_synth_pu_workaround(dev, phy->channel);
+	if (phy->type == B43_PHYTYPE_B) {
+		b43_phy_write(dev, B43_PHY_CCK(0x30), sav.phy_cck_30);
+		b43_write16(dev, 0x3EC, sav.reg_3EC);
+	} else if (phy->gmode) {
+		b43_write16(dev, B43_MMIO_PHY_RADIO,
+			    b43_read16(dev, B43_MMIO_PHY_RADIO)
+			    & 0x7FFF);
+		b43_phy_write(dev, B43_PHY_RFOVER, sav.phy_rfover);
+		b43_phy_write(dev, B43_PHY_RFOVERVAL, sav.phy_rfoverval);
+		b43_phy_write(dev, B43_PHY_ANALOGOVER, sav.phy_analogover);
+		b43_phy_write(dev, B43_PHY_ANALOGOVERVAL,
+			      sav.phy_analogoverval);
+		b43_phy_write(dev, B43_PHY_CRS0, sav.phy_crs0);
+		b43_phy_write(dev, B43_PHY_CLASSCTL, sav.phy_classctl);
+		if (has_loopback_gain(phy)) {
+			b43_phy_write(dev, B43_PHY_LO_MASK, sav.phy_lo_mask);
+			b43_phy_write(dev, B43_PHY_LO_CTL, sav.phy_lo_ctl);
+		}
+	}
+	if (i > 15)
+		ret = radio78;
+	else
+		ret = rcc;
+
+	return ret;
+}
+
+static void b43_phy_initb5(struct b43_wldev *dev)
+{
+	struct ssb_bus *bus = dev->dev->bus;
+	struct b43_phy *phy = &dev->phy;
+	struct b43_phy_g *gphy = phy->g;
+	u16 offset, value;
+	u8 old_channel;
+
+	if (phy->analog == 1) {
+		b43_radio_write16(dev, 0x007A, b43_radio_read16(dev, 0x007A)
+				  | 0x0050);
+	}
+	if ((bus->boardinfo.vendor != SSB_BOARDVENDOR_BCM) &&
+	    (bus->boardinfo.type != SSB_BOARD_BU4306)) {
+		value = 0x2120;
+		for (offset = 0x00A8; offset < 0x00C7; offset++) {
+			b43_phy_write(dev, offset, value);
+			value += 0x202;
+		}
+	}
+	b43_phy_write(dev, 0x0035, (b43_phy_read(dev, 0x0035) & 0xF0FF)
+		      | 0x0700);
+	if (phy->radio_ver == 0x2050)
+		b43_phy_write(dev, 0x0038, 0x0667);
+
+	if (phy->gmode || phy->rev >= 2) {
+		if (phy->radio_ver == 0x2050) {
+			b43_radio_write16(dev, 0x007A,
+					  b43_radio_read16(dev, 0x007A)
+					  | 0x0020);
+			b43_radio_write16(dev, 0x0051,
+					  b43_radio_read16(dev, 0x0051)
+					  | 0x0004);
+		}
+		b43_write16(dev, B43_MMIO_PHY_RADIO, 0x0000);
+
+		b43_phy_write(dev, 0x0802, b43_phy_read(dev, 0x0802) | 0x0100);
+		b43_phy_write(dev, 0x042B, b43_phy_read(dev, 0x042B) | 0x2000);
+
+		b43_phy_write(dev, 0x001C, 0x186A);
+
+		b43_phy_write(dev, 0x0013,
+			      (b43_phy_read(dev, 0x0013) & 0x00FF) | 0x1900);
+		b43_phy_write(dev, 0x0035,
+			      (b43_phy_read(dev, 0x0035) & 0xFFC0) | 0x0064);
+		b43_phy_write(dev, 0x005D,
+			      (b43_phy_read(dev, 0x005D) & 0xFF80) | 0x000A);
+	}
+
+	if (dev->bad_frames_preempt) {
+		b43_phy_write(dev, B43_PHY_RADIO_BITFIELD,
+			      b43_phy_read(dev,
+					   B43_PHY_RADIO_BITFIELD) | (1 << 11));
+	}
+
+	if (phy->analog == 1) {
+		b43_phy_write(dev, 0x0026, 0xCE00);
+		b43_phy_write(dev, 0x0021, 0x3763);
+		b43_phy_write(dev, 0x0022, 0x1BC3);
+		b43_phy_write(dev, 0x0023, 0x06F9);
+		b43_phy_write(dev, 0x0024, 0x037E);
+	} else
+		b43_phy_write(dev, 0x0026, 0xCC00);
+	b43_phy_write(dev, 0x0030, 0x00C6);
+	b43_write16(dev, 0x03EC, 0x3F22);
+
+	if (phy->analog == 1)
+		b43_phy_write(dev, 0x0020, 0x3E1C);
+	else
+		b43_phy_write(dev, 0x0020, 0x301C);
+
+	if (phy->analog == 0)
+		b43_write16(dev, 0x03E4, 0x3000);
+
+	old_channel = phy->channel;
+	/* Force to channel 7, even if not supported. */
+	b43_gphy_channel_switch(dev, 7, 0);
+
+	if (phy->radio_ver != 0x2050) {
+		b43_radio_write16(dev, 0x0075, 0x0080);
+		b43_radio_write16(dev, 0x0079, 0x0081);
+	}
+
+	b43_radio_write16(dev, 0x0050, 0x0020);
+	b43_radio_write16(dev, 0x0050, 0x0023);
+
+	if (phy->radio_ver == 0x2050) {
+		b43_radio_write16(dev, 0x0050, 0x0020);
+		b43_radio_write16(dev, 0x005A, 0x0070);
+	}
+
+	b43_radio_write16(dev, 0x005B, 0x007B);
+	b43_radio_write16(dev, 0x005C, 0x00B0);
+
+	b43_radio_write16(dev, 0x007A, b43_radio_read16(dev, 0x007A) | 0x0007);
+
+	b43_gphy_channel_switch(dev, old_channel, 0);
+
+	b43_phy_write(dev, 0x0014, 0x0080);
+	b43_phy_write(dev, 0x0032, 0x00CA);
+	b43_phy_write(dev, 0x002A, 0x88A3);
+
+	b43_set_txpower_g(dev, &gphy->bbatt, &gphy->rfatt, gphy->tx_control);
+
+	if (phy->radio_ver == 0x2050)
+		b43_radio_write16(dev, 0x005D, 0x000D);
+
+	b43_write16(dev, 0x03E4, (b43_read16(dev, 0x03E4) & 0xFFC0) | 0x0004);
+}
+
+static void b43_phy_initb6(struct b43_wldev *dev)
+{
+	struct b43_phy *phy = &dev->phy;
+	struct b43_phy_g *gphy = phy->g;
+	u16 offset, val;
+	u8 old_channel;
+
+	b43_phy_write(dev, 0x003E, 0x817A);
+	b43_radio_write16(dev, 0x007A,
+			  (b43_radio_read16(dev, 0x007A) | 0x0058));
+	if (phy->radio_rev == 4 || phy->radio_rev == 5) {
+		b43_radio_write16(dev, 0x51, 0x37);
+		b43_radio_write16(dev, 0x52, 0x70);
+		b43_radio_write16(dev, 0x53, 0xB3);
+		b43_radio_write16(dev, 0x54, 0x9B);
+		b43_radio_write16(dev, 0x5A, 0x88);
+		b43_radio_write16(dev, 0x5B, 0x88);
+		b43_radio_write16(dev, 0x5D, 0x88);
+		b43_radio_write16(dev, 0x5E, 0x88);
+		b43_radio_write16(dev, 0x7D, 0x88);
+		b43_hf_write(dev, b43_hf_read(dev)
+			     | B43_HF_TSSIRPSMW);
+	}
+	B43_WARN_ON(phy->radio_rev == 6 || phy->radio_rev == 7);	/* We had code for these revs here... */
+	if (phy->radio_rev == 8) {
+		b43_radio_write16(dev, 0x51, 0);
+		b43_radio_write16(dev, 0x52, 0x40);
+		b43_radio_write16(dev, 0x53, 0xB7);
+		b43_radio_write16(dev, 0x54, 0x98);
+		b43_radio_write16(dev, 0x5A, 0x88);
+		b43_radio_write16(dev, 0x5B, 0x6B);
+		b43_radio_write16(dev, 0x5C, 0x0F);
+		if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_ALTIQ) {
+			b43_radio_write16(dev, 0x5D, 0xFA);
+			b43_radio_write16(dev, 0x5E, 0xD8);
+		} else {
+			b43_radio_write16(dev, 0x5D, 0xF5);
+			b43_radio_write16(dev, 0x5E, 0xB8);
+		}
+		b43_radio_write16(dev, 0x0073, 0x0003);
+		b43_radio_write16(dev, 0x007D, 0x00A8);
+		b43_radio_write16(dev, 0x007C, 0x0001);
+		b43_radio_write16(dev, 0x007E, 0x0008);
+	}
+	val = 0x1E1F;
+	for (offset = 0x0088; offset < 0x0098; offset++) {
+		b43_phy_write(dev, offset, val);
+		val -= 0x0202;
+	}
+	val = 0x3E3F;
+	for (offset = 0x0098; offset < 0x00A8; offset++) {
+		b43_phy_write(dev, offset, val);
+		val -= 0x0202;
+	}
+	val = 0x2120;
+	for (offset = 0x00A8; offset < 0x00C8; offset++) {
+		b43_phy_write(dev, offset, (val & 0x3F3F));
+		val += 0x0202;
+	}
+	if (phy->type == B43_PHYTYPE_G) {
+		b43_radio_write16(dev, 0x007A,
+				  b43_radio_read16(dev, 0x007A) | 0x0020);
+		b43_radio_write16(dev, 0x0051,
+				  b43_radio_read16(dev, 0x0051) | 0x0004);
+		b43_phy_write(dev, 0x0802, b43_phy_read(dev, 0x0802) | 0x0100);
+		b43_phy_write(dev, 0x042B, b43_phy_read(dev, 0x042B) | 0x2000);
+		b43_phy_write(dev, 0x5B, 0);
+		b43_phy_write(dev, 0x5C, 0);
+	}
+
+	old_channel = phy->channel;
+	if (old_channel >= 8)
+		b43_gphy_channel_switch(dev, 1, 0);
+	else
+		b43_gphy_channel_switch(dev, 13, 0);
+
+	b43_radio_write16(dev, 0x0050, 0x0020);
+	b43_radio_write16(dev, 0x0050, 0x0023);
+	udelay(40);
+	if (phy->radio_rev < 6 || phy->radio_rev == 8) {
+		b43_radio_write16(dev, 0x7C, (b43_radio_read16(dev, 0x7C)
+					      | 0x0002));
+		b43_radio_write16(dev, 0x50, 0x20);
+	}
+	if (phy->radio_rev <= 2) {
+		b43_radio_write16(dev, 0x7C, 0x20);
+		b43_radio_write16(dev, 0x5A, 0x70);
+		b43_radio_write16(dev, 0x5B, 0x7B);
+		b43_radio_write16(dev, 0x5C, 0xB0);
+	}
+	b43_radio_write16(dev, 0x007A,
+			  (b43_radio_read16(dev, 0x007A) & 0x00F8) | 0x0007);
+
+	b43_gphy_channel_switch(dev, old_channel, 0);
+
+	b43_phy_write(dev, 0x0014, 0x0200);
+	if (phy->radio_rev >= 6)
+		b43_phy_write(dev, 0x2A, 0x88C2);
+	else
+		b43_phy_write(dev, 0x2A, 0x8AC0);
+	b43_phy_write(dev, 0x0038, 0x0668);
+	b43_set_txpower_g(dev, &gphy->bbatt, &gphy->rfatt, gphy->tx_control);
+	if (phy->radio_rev <= 5) {
+		b43_phy_write(dev, 0x5D, (b43_phy_read(dev, 0x5D)
+					  & 0xFF80) | 0x0003);
+	}
+	if (phy->radio_rev <= 2)
+		b43_radio_write16(dev, 0x005D, 0x000D);
+
+	if (phy->analog == 4) {
+		b43_write16(dev, 0x3E4, 9);
+		b43_phy_write(dev, 0x61, b43_phy_read(dev, 0x61)
+			      & 0x0FFF);
+	} else {
+		b43_phy_write(dev, 0x0002, (b43_phy_read(dev, 0x0002) & 0xFFC0)
+			      | 0x0004);
+	}
+	if (phy->type == B43_PHYTYPE_B)
+		B43_WARN_ON(1);
+	else if (phy->type == B43_PHYTYPE_G)
+		b43_write16(dev, 0x03E6, 0x0);
+}
+
+static void b43_calc_loopback_gain(struct b43_wldev *dev)
+{
+	struct b43_phy *phy = &dev->phy;
+	struct b43_phy_g *gphy = phy->g;
+	u16 backup_phy[16] = { 0 };
+	u16 backup_radio[3];
+	u16 backup_bband;
+	u16 i, j, loop_i_max;
+	u16 trsw_rx;
+	u16 loop1_outer_done, loop1_inner_done;
+
+	backup_phy[0] = b43_phy_read(dev, B43_PHY_CRS0);
+	backup_phy[1] = b43_phy_read(dev, B43_PHY_CCKBBANDCFG);
+	backup_phy[2] = b43_phy_read(dev, B43_PHY_RFOVER);
+	backup_phy[3] = b43_phy_read(dev, B43_PHY_RFOVERVAL);
+	if (phy->rev != 1) {	/* Not in specs, but needed to prevent PPC machine check */
+		backup_phy[4] = b43_phy_read(dev, B43_PHY_ANALOGOVER);
+		backup_phy[5] = b43_phy_read(dev, B43_PHY_ANALOGOVERVAL);
+	}
+	backup_phy[6] = b43_phy_read(dev, B43_PHY_CCK(0x5A));
+	backup_phy[7] = b43_phy_read(dev, B43_PHY_CCK(0x59));
+	backup_phy[8] = b43_phy_read(dev, B43_PHY_CCK(0x58));
+	backup_phy[9] = b43_phy_read(dev, B43_PHY_CCK(0x0A));
+	backup_phy[10] = b43_phy_read(dev, B43_PHY_CCK(0x03));
+	backup_phy[11] = b43_phy_read(dev, B43_PHY_LO_MASK);
+	backup_phy[12] = b43_phy_read(dev, B43_PHY_LO_CTL);
+	backup_phy[13] = b43_phy_read(dev, B43_PHY_CCK(0x2B));
+	backup_phy[14] = b43_phy_read(dev, B43_PHY_PGACTL);
+	backup_phy[15] = b43_phy_read(dev, B43_PHY_LO_LEAKAGE);
+	backup_bband = gphy->bbatt.att;
+	backup_radio[0] = b43_radio_read16(dev, 0x52);
+	backup_radio[1] = b43_radio_read16(dev, 0x43);
+	backup_radio[2] = b43_radio_read16(dev, 0x7A);
+
+	b43_phy_write(dev, B43_PHY_CRS0,
+		      b43_phy_read(dev, B43_PHY_CRS0) & 0x3FFF);
+	b43_phy_write(dev, B43_PHY_CCKBBANDCFG,
+		      b43_phy_read(dev, B43_PHY_CCKBBANDCFG) | 0x8000);
+	b43_phy_write(dev, B43_PHY_RFOVER,
+		      b43_phy_read(dev, B43_PHY_RFOVER) | 0x0002);
+	b43_phy_write(dev, B43_PHY_RFOVERVAL,
+		      b43_phy_read(dev, B43_PHY_RFOVERVAL) & 0xFFFD);
+	b43_phy_write(dev, B43_PHY_RFOVER,
+		      b43_phy_read(dev, B43_PHY_RFOVER) | 0x0001);
+	b43_phy_write(dev, B43_PHY_RFOVERVAL,
+		      b43_phy_read(dev, B43_PHY_RFOVERVAL) & 0xFFFE);
+	if (phy->rev != 1) {	/* Not in specs, but needed to prevent PPC machine check */
+		b43_phy_write(dev, B43_PHY_ANALOGOVER,
+			      b43_phy_read(dev, B43_PHY_ANALOGOVER) | 0x0001);
+		b43_phy_write(dev, B43_PHY_ANALOGOVERVAL,
+			      b43_phy_read(dev,
+					   B43_PHY_ANALOGOVERVAL) & 0xFFFE);
+		b43_phy_write(dev, B43_PHY_ANALOGOVER,
+			      b43_phy_read(dev, B43_PHY_ANALOGOVER) | 0x0002);
+		b43_phy_write(dev, B43_PHY_ANALOGOVERVAL,
+			      b43_phy_read(dev,
+					   B43_PHY_ANALOGOVERVAL) & 0xFFFD);
+	}
+	b43_phy_write(dev, B43_PHY_RFOVER,
+		      b43_phy_read(dev, B43_PHY_RFOVER) | 0x000C);
+	b43_phy_write(dev, B43_PHY_RFOVERVAL,
+		      b43_phy_read(dev, B43_PHY_RFOVERVAL) | 0x000C);
+	b43_phy_write(dev, B43_PHY_RFOVER,
+		      b43_phy_read(dev, B43_PHY_RFOVER) | 0x0030);
+	b43_phy_write(dev, B43_PHY_RFOVERVAL,
+		      (b43_phy_read(dev, B43_PHY_RFOVERVAL)
+		       & 0xFFCF) | 0x10);
+
+	b43_phy_write(dev, B43_PHY_CCK(0x5A), 0x0780);
+	b43_phy_write(dev, B43_PHY_CCK(0x59), 0xC810);
+	b43_phy_write(dev, B43_PHY_CCK(0x58), 0x000D);
+
+	b43_phy_write(dev, B43_PHY_CCK(0x0A),
+		      b43_phy_read(dev, B43_PHY_CCK(0x0A)) | 0x2000);
+	if (phy->rev != 1) {	/* Not in specs, but needed to prevent PPC machine check */
+		b43_phy_write(dev, B43_PHY_ANALOGOVER,
+			      b43_phy_read(dev, B43_PHY_ANALOGOVER) | 0x0004);
+		b43_phy_write(dev, B43_PHY_ANALOGOVERVAL,
+			      b43_phy_read(dev,
+					   B43_PHY_ANALOGOVERVAL) & 0xFFFB);
+	}
+	b43_phy_write(dev, B43_PHY_CCK(0x03),
+		      (b43_phy_read(dev, B43_PHY_CCK(0x03))
+		       & 0xFF9F) | 0x40);
+
+	if (phy->radio_rev == 8) {
+		b43_radio_write16(dev, 0x43, 0x000F);
+	} else {
+		b43_radio_write16(dev, 0x52, 0);
+		b43_radio_write16(dev, 0x43, (b43_radio_read16(dev, 0x43)
+					      & 0xFFF0) | 0x9);
+	}
+	b43_gphy_set_baseband_attenuation(dev, 11);
+
+	if (phy->rev >= 3)
+		b43_phy_write(dev, B43_PHY_LO_MASK, 0xC020);
+	else
+		b43_phy_write(dev, B43_PHY_LO_MASK, 0x8020);
+	b43_phy_write(dev, B43_PHY_LO_CTL, 0);
+
+	b43_phy_write(dev, B43_PHY_CCK(0x2B),
+		      (b43_phy_read(dev, B43_PHY_CCK(0x2B))
+		       & 0xFFC0) | 0x01);
+	b43_phy_write(dev, B43_PHY_CCK(0x2B),
+		      (b43_phy_read(dev, B43_PHY_CCK(0x2B))
+		       & 0xC0FF) | 0x800);
+
+	b43_phy_write(dev, B43_PHY_RFOVER,
+		      b43_phy_read(dev, B43_PHY_RFOVER) | 0x0100);
+	b43_phy_write(dev, B43_PHY_RFOVERVAL,
+		      b43_phy_read(dev, B43_PHY_RFOVERVAL) & 0xCFFF);
+
+	if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_EXTLNA) {
+		if (phy->rev >= 7) {
+			b43_phy_write(dev, B43_PHY_RFOVER,
+				      b43_phy_read(dev, B43_PHY_RFOVER)
+				      | 0x0800);
+			b43_phy_write(dev, B43_PHY_RFOVERVAL,
+				      b43_phy_read(dev, B43_PHY_RFOVERVAL)
+				      | 0x8000);
+		}
+	}
+	b43_radio_write16(dev, 0x7A, b43_radio_read16(dev, 0x7A)
+			  & 0x00F7);
+
+	j = 0;
+	loop_i_max = (phy->radio_rev == 8) ? 15 : 9;
+	for (i = 0; i < loop_i_max; i++) {
+		for (j = 0; j < 16; j++) {
+			b43_radio_write16(dev, 0x43, i);
+			b43_phy_write(dev, B43_PHY_RFOVERVAL,
+				      (b43_phy_read(dev, B43_PHY_RFOVERVAL)
+				       & 0xF0FF) | (j << 8));
+			b43_phy_write(dev, B43_PHY_PGACTL,
+				      (b43_phy_read(dev, B43_PHY_PGACTL)
+				       & 0x0FFF) | 0xA000);
+			b43_phy_write(dev, B43_PHY_PGACTL,
+				      b43_phy_read(dev, B43_PHY_PGACTL)
+				      | 0xF000);
+			udelay(20);
+			if (b43_phy_read(dev, B43_PHY_LO_LEAKAGE) >= 0xDFC)
+				goto exit_loop1;
+		}
+	}
+      exit_loop1:
+	loop1_outer_done = i;
+	loop1_inner_done = j;
+	if (j >= 8) {
+		b43_phy_write(dev, B43_PHY_RFOVERVAL,
+			      b43_phy_read(dev, B43_PHY_RFOVERVAL)
+			      | 0x30);
+		trsw_rx = 0x1B;
+		for (j = j - 8; j < 16; j++) {
+			b43_phy_write(dev, B43_PHY_RFOVERVAL,
+				      (b43_phy_read(dev, B43_PHY_RFOVERVAL)
+				       & 0xF0FF) | (j << 8));
+			b43_phy_write(dev, B43_PHY_PGACTL,
+				      (b43_phy_read(dev, B43_PHY_PGACTL)
+				       & 0x0FFF) | 0xA000);
+			b43_phy_write(dev, B43_PHY_PGACTL,
+				      b43_phy_read(dev, B43_PHY_PGACTL)
+				      | 0xF000);
+			udelay(20);
+			trsw_rx -= 3;
+			if (b43_phy_read(dev, B43_PHY_LO_LEAKAGE) >= 0xDFC)
+				goto exit_loop2;
+		}
+	} else
+		trsw_rx = 0x18;
+      exit_loop2:
+
+	if (phy->rev != 1) {	/* Not in specs, but needed to prevent PPC machine check */
+		b43_phy_write(dev, B43_PHY_ANALOGOVER, backup_phy[4]);
+		b43_phy_write(dev, B43_PHY_ANALOGOVERVAL, backup_phy[5]);
+	}
+	b43_phy_write(dev, B43_PHY_CCK(0x5A), backup_phy[6]);
+	b43_phy_write(dev, B43_PHY_CCK(0x59), backup_phy[7]);
+	b43_phy_write(dev, B43_PHY_CCK(0x58), backup_phy[8]);
+	b43_phy_write(dev, B43_PHY_CCK(0x0A), backup_phy[9]);
+	b43_phy_write(dev, B43_PHY_CCK(0x03), backup_phy[10]);
+	b43_phy_write(dev, B43_PHY_LO_MASK, backup_phy[11]);
+	b43_phy_write(dev, B43_PHY_LO_CTL, backup_phy[12]);
+	b43_phy_write(dev, B43_PHY_CCK(0x2B), backup_phy[13]);
+	b43_phy_write(dev, B43_PHY_PGACTL, backup_phy[14]);
+
+	b43_gphy_set_baseband_attenuation(dev, backup_bband);
+
+	b43_radio_write16(dev, 0x52, backup_radio[0]);
+	b43_radio_write16(dev, 0x43, backup_radio[1]);
+	b43_radio_write16(dev, 0x7A, backup_radio[2]);
+
+	b43_phy_write(dev, B43_PHY_RFOVER, backup_phy[2] | 0x0003);
+	udelay(10);
+	b43_phy_write(dev, B43_PHY_RFOVER, backup_phy[2]);
+	b43_phy_write(dev, B43_PHY_RFOVERVAL, backup_phy[3]);
+	b43_phy_write(dev, B43_PHY_CRS0, backup_phy[0]);
+	b43_phy_write(dev, B43_PHY_CCKBBANDCFG, backup_phy[1]);
+
+	gphy->max_lb_gain =
+	    ((loop1_inner_done * 6) - (loop1_outer_done * 4)) - 11;
+	gphy->trsw_rx_gain = trsw_rx * 2;
+}
+
+static void b43_hardware_pctl_early_init(struct b43_wldev *dev)
+{
+	struct b43_phy *phy = &dev->phy;
+
+	if (!b43_has_hardware_pctl(dev)) {
+		b43_phy_write(dev, 0x047A, 0xC111);
+		return;
+	}
+
+	b43_phy_write(dev, 0x0036, b43_phy_read(dev, 0x0036) & 0xFEFF);
+	b43_phy_write(dev, 0x002F, 0x0202);
+	b43_phy_write(dev, 0x047C, b43_phy_read(dev, 0x047C) | 0x0002);
+	b43_phy_write(dev, 0x047A, b43_phy_read(dev, 0x047A) | 0xF000);
+	if (phy->radio_ver == 0x2050 && phy->radio_rev == 8) {
+		b43_phy_write(dev, 0x047A, (b43_phy_read(dev, 0x047A)
+					    & 0xFF0F) | 0x0010);
+		b43_phy_write(dev, 0x005D, b43_phy_read(dev, 0x005D)
+			      | 0x8000);
+		b43_phy_write(dev, 0x004E, (b43_phy_read(dev, 0x004E)
+					    & 0xFFC0) | 0x0010);
+		b43_phy_write(dev, 0x002E, 0xC07F);
+		b43_phy_write(dev, 0x0036, b43_phy_read(dev, 0x0036)
+			      | 0x0400);
+	} else {
+		b43_phy_write(dev, 0x0036, b43_phy_read(dev, 0x0036)
+			      | 0x0200);
+		b43_phy_write(dev, 0x0036, b43_phy_read(dev, 0x0036)
+			      | 0x0400);
+		b43_phy_write(dev, 0x005D, b43_phy_read(dev, 0x005D)
+			      & 0x7FFF);
+		b43_phy_write(dev, 0x004F, b43_phy_read(dev, 0x004F)
+			      & 0xFFFE);
+		b43_phy_write(dev, 0x004E, (b43_phy_read(dev, 0x004E)
+					    & 0xFFC0) | 0x0010);
+		b43_phy_write(dev, 0x002E, 0xC07F);
+		b43_phy_write(dev, 0x047A, (b43_phy_read(dev, 0x047A)
+					    & 0xFF0F) | 0x0010);
+	}
+}
+
+/* Hardware power control for G-PHY */
+static void b43_hardware_pctl_init_gphy(struct b43_wldev *dev)
+{
+	struct b43_phy *phy = &dev->phy;
+	struct b43_phy_g *gphy = phy->g;
+
+	if (!b43_has_hardware_pctl(dev)) {
+		/* No hardware power control */
+		b43_hf_write(dev, b43_hf_read(dev) & ~B43_HF_HWPCTL);
+		return;
+	}
+
+	b43_phy_write(dev, 0x0036, (b43_phy_read(dev, 0x0036) & 0xFFC0)
+		      | (gphy->tgt_idle_tssi - gphy->cur_idle_tssi));
+	b43_phy_write(dev, 0x0478, (b43_phy_read(dev, 0x0478) & 0xFF00)
+		      | (gphy->tgt_idle_tssi - gphy->cur_idle_tssi));
+	b43_gphy_tssi_power_lt_init(dev);
+	b43_gphy_gain_lt_init(dev);
+	b43_phy_write(dev, 0x0060, b43_phy_read(dev, 0x0060) & 0xFFBF);
+	b43_phy_write(dev, 0x0014, 0x0000);
+
+	B43_WARN_ON(phy->rev < 6);
+	b43_phy_write(dev, 0x0478, b43_phy_read(dev, 0x0478)
+		      | 0x0800);
+	b43_phy_write(dev, 0x0478, b43_phy_read(dev, 0x0478)
+		      & 0xFEFF);
+	b43_phy_write(dev, 0x0801, b43_phy_read(dev, 0x0801)
+		      & 0xFFBF);
+
+	b43_gphy_dc_lt_init(dev, 1);
+
+	/* Enable hardware pctl in firmware. */
+	b43_hf_write(dev, b43_hf_read(dev) | B43_HF_HWPCTL);
+}
+
+/* Intialize B/G PHY power control */
+static void b43_phy_init_pctl(struct b43_wldev *dev)
+{
+	struct ssb_bus *bus = dev->dev->bus;
+	struct b43_phy *phy = &dev->phy;
+	struct b43_phy_g *gphy = phy->g;
+	struct b43_rfatt old_rfatt;
+	struct b43_bbatt old_bbatt;
+	u8 old_tx_control = 0;
+
+	B43_WARN_ON(phy->type != B43_PHYTYPE_G);
+
+	if ((bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM) &&
+	    (bus->boardinfo.type == SSB_BOARD_BU4306))
+		return;
+
+	b43_phy_write(dev, 0x0028, 0x8018);
+
+	/* This does something with the Analog... */
+	b43_write16(dev, B43_MMIO_PHY0, b43_read16(dev, B43_MMIO_PHY0)
+		    & 0xFFDF);
+
+	if (!phy->gmode)
+		return;
+	b43_hardware_pctl_early_init(dev);
+	if (gphy->cur_idle_tssi == 0) {
+		if (phy->radio_ver == 0x2050 && phy->analog == 0) {
+			b43_radio_write16(dev, 0x0076,
+					  (b43_radio_read16(dev, 0x0076)
+					   & 0x00F7) | 0x0084);
+		} else {
+			struct b43_rfatt rfatt;
+			struct b43_bbatt bbatt;
+
+			memcpy(&old_rfatt, &gphy->rfatt, sizeof(old_rfatt));
+			memcpy(&old_bbatt, &gphy->bbatt, sizeof(old_bbatt));
+			old_tx_control = gphy->tx_control;
+
+			bbatt.att = 11;
+			if (phy->radio_rev == 8) {
+				rfatt.att = 15;
+				rfatt.with_padmix = 1;
+			} else {
+				rfatt.att = 9;
+				rfatt.with_padmix = 0;
+			}
+			b43_set_txpower_g(dev, &bbatt, &rfatt, 0);
+		}
+		b43_dummy_transmission(dev);
+		gphy->cur_idle_tssi = b43_phy_read(dev, B43_PHY_ITSSI);
+		if (B43_DEBUG) {
+			/* Current-Idle-TSSI sanity check. */
+			if (abs(gphy->cur_idle_tssi - gphy->tgt_idle_tssi) >= 20) {
+				b43dbg(dev->wl,
+				       "!WARNING! Idle-TSSI phy->cur_idle_tssi "
+				       "measuring failed. (cur=%d, tgt=%d). Disabling TX power "
+				       "adjustment.\n", gphy->cur_idle_tssi,
+				       gphy->tgt_idle_tssi);
+				gphy->cur_idle_tssi = 0;
+			}
+		}
+		if (phy->radio_ver == 0x2050 && phy->analog == 0) {
+			b43_radio_write16(dev, 0x0076,
+					  b43_radio_read16(dev, 0x0076)
+					  & 0xFF7B);
+		} else {
+			b43_set_txpower_g(dev, &old_bbatt,
+					  &old_rfatt, old_tx_control);
+		}
+	}
+	b43_hardware_pctl_init_gphy(dev);
+	b43_shm_clear_tssi(dev);
+}
+
+static void b43_phy_initg(struct b43_wldev *dev)
+{
+	struct b43_phy *phy = &dev->phy;
+	struct b43_phy_g *gphy = phy->g;
+	u16 tmp;
+
+	if (phy->rev == 1)
+		b43_phy_initb5(dev);
+	else
+		b43_phy_initb6(dev);
+
+	if (phy->rev >= 2 || phy->gmode)
+		b43_phy_inita(dev);
+
+	if (phy->rev >= 2) {
+		b43_phy_write(dev, B43_PHY_ANALOGOVER, 0);
+		b43_phy_write(dev, B43_PHY_ANALOGOVERVAL, 0);
+	}
+	if (phy->rev == 2) {
+		b43_phy_write(dev, B43_PHY_RFOVER, 0);
+		b43_phy_write(dev, B43_PHY_PGACTL, 0xC0);
+	}
+	if (phy->rev > 5) {
+		b43_phy_write(dev, B43_PHY_RFOVER, 0x400);
+		b43_phy_write(dev, B43_PHY_PGACTL, 0xC0);
+	}
+	if (phy->gmode || phy->rev >= 2) {
+		tmp = b43_phy_read(dev, B43_PHY_VERSION_OFDM);
+		tmp &= B43_PHYVER_VERSION;
+		if (tmp == 3 || tmp == 5) {
+			b43_phy_write(dev, B43_PHY_OFDM(0xC2), 0x1816);
+			b43_phy_write(dev, B43_PHY_OFDM(0xC3), 0x8006);
+		}
+		if (tmp == 5) {
+			b43_phy_write(dev, B43_PHY_OFDM(0xCC),
+				      (b43_phy_read(dev, B43_PHY_OFDM(0xCC))
+				       & 0x00FF) | 0x1F00);
+		}
+	}
+	if ((phy->rev <= 2 && phy->gmode) || phy->rev >= 2)
+		b43_phy_write(dev, B43_PHY_OFDM(0x7E), 0x78);
+	if (phy->radio_rev == 8) {
+		b43_phy_write(dev, B43_PHY_EXTG(0x01),
+			      b43_phy_read(dev, B43_PHY_EXTG(0x01))
+			      | 0x80);
+		b43_phy_write(dev, B43_PHY_OFDM(0x3E),
+			      b43_phy_read(dev, B43_PHY_OFDM(0x3E))
+			      | 0x4);
+	}
+	if (has_loopback_gain(phy))
+		b43_calc_loopback_gain(dev);
+
+	if (phy->radio_rev != 8) {
+		if (gphy->initval == 0xFFFF)
+			gphy->initval = b43_radio_init2050(dev);
+		else
+			b43_radio_write16(dev, 0x0078, gphy->initval);
+	}
+	b43_lo_g_init(dev);
+	if (has_tx_magnification(phy)) {
+		b43_radio_write16(dev, 0x52,
+				  (b43_radio_read16(dev, 0x52) & 0xFF00)
+				  | gphy->lo_control->tx_bias | gphy->
+				  lo_control->tx_magn);
+	} else {
+		b43_radio_write16(dev, 0x52,
+				  (b43_radio_read16(dev, 0x52) & 0xFFF0)
+				  | gphy->lo_control->tx_bias);
+	}
+	if (phy->rev >= 6) {
+		b43_phy_write(dev, B43_PHY_CCK(0x36),
+			      (b43_phy_read(dev, B43_PHY_CCK(0x36))
+			       & 0x0FFF) | (gphy->lo_control->
+					    tx_bias << 12));
+	}
+	if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_PACTRL)
+		b43_phy_write(dev, B43_PHY_CCK(0x2E), 0x8075);
+	else
+		b43_phy_write(dev, B43_PHY_CCK(0x2E), 0x807F);
+	if (phy->rev < 2)
+		b43_phy_write(dev, B43_PHY_CCK(0x2F), 0x101);
+	else
+		b43_phy_write(dev, B43_PHY_CCK(0x2F), 0x202);
+	if (phy->gmode || phy->rev >= 2) {
+		b43_lo_g_adjust(dev);
+		b43_phy_write(dev, B43_PHY_LO_MASK, 0x8078);
+	}
+
+	if (!(dev->dev->bus->sprom.boardflags_lo & B43_BFL_RSSI)) {
+		/* The specs state to update the NRSSI LT with
+		 * the value 0x7FFFFFFF here. I think that is some weird
+		 * compiler optimization in the original driver.
+		 * Essentially, what we do here is resetting all NRSSI LT
+		 * entries to -32 (see the clamp_val() in nrssi_hw_update())
+		 */
+		b43_nrssi_hw_update(dev, 0xFFFF);	//FIXME?
+		b43_calc_nrssi_threshold(dev);
+	} else if (phy->gmode || phy->rev >= 2) {
+		if (gphy->nrssi[0] == -1000) {
+			B43_WARN_ON(gphy->nrssi[1] != -1000);
+			b43_calc_nrssi_slope(dev);
+		} else
+			b43_calc_nrssi_threshold(dev);
+	}
+	if (phy->radio_rev == 8)
+		b43_phy_write(dev, B43_PHY_EXTG(0x05), 0x3230);
+	b43_phy_init_pctl(dev);
+	/* FIXME: The spec says in the following if, the 0 should be replaced
+	   'if OFDM may not be used in the current locale'
+	   but OFDM is legal everywhere */
+	if ((dev->dev->bus->chip_id == 0x4306
+	     && dev->dev->bus->chip_package == 2) || 0) {
+		b43_phy_write(dev, B43_PHY_CRS0, b43_phy_read(dev, B43_PHY_CRS0)
+			      & 0xBFFF);
+		b43_phy_write(dev, B43_PHY_OFDM(0xC3),
+			      b43_phy_read(dev, B43_PHY_OFDM(0xC3))
+			      & 0x7FFF);
+	}
+}
+
+void b43_gphy_channel_switch(struct b43_wldev *dev,
+			     unsigned int channel,
+			     bool synthetic_pu_workaround)
+{
+	if (synthetic_pu_workaround)
+		b43_synth_pu_workaround(dev, channel);
+
+	b43_write16(dev, B43_MMIO_CHANNEL, channel2freq_bg(channel));
+
+	if (channel == 14) {
+		if (dev->dev->bus->sprom.country_code ==
+		    SSB_SPROM1CCODE_JAPAN)
+			b43_hf_write(dev,
+				     b43_hf_read(dev) & ~B43_HF_ACPR);
+		else
+			b43_hf_write(dev,
+				     b43_hf_read(dev) | B43_HF_ACPR);
+		b43_write16(dev, B43_MMIO_CHANNEL_EXT,
+			    b43_read16(dev, B43_MMIO_CHANNEL_EXT)
+			    | (1 << 11));
+	} else {
+		b43_write16(dev, B43_MMIO_CHANNEL_EXT,
+			    b43_read16(dev, B43_MMIO_CHANNEL_EXT)
+			    & 0xF7BF);
+	}
+}
+
+static void default_baseband_attenuation(struct b43_wldev *dev,
+					 struct b43_bbatt *bb)
+{
+	struct b43_phy *phy = &dev->phy;
+
+	if (phy->radio_ver == 0x2050 && phy->radio_rev < 6)
+		bb->att = 0;
+	else
+		bb->att = 2;
+}
+
+static void default_radio_attenuation(struct b43_wldev *dev,
+				      struct b43_rfatt *rf)
+{
+	struct ssb_bus *bus = dev->dev->bus;
+	struct b43_phy *phy = &dev->phy;
+
+	rf->with_padmix = 0;
+
+	if (bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM &&
+	    bus->boardinfo.type == SSB_BOARD_BCM4309G) {
+		if (bus->boardinfo.rev < 0x43) {
+			rf->att = 2;
+			return;
+		} else if (bus->boardinfo.rev < 0x51) {
+			rf->att = 3;
+			return;
+		}
+	}
+
+	if (phy->type == B43_PHYTYPE_A) {
+		rf->att = 0x60;
+		return;
+	}
+
+	switch (phy->radio_ver) {
+	case 0x2053:
+		switch (phy->radio_rev) {
+		case 1:
+			rf->att = 6;
+			return;
+		}
+		break;
+	case 0x2050:
+		switch (phy->radio_rev) {
+		case 0:
+			rf->att = 5;
+			return;
+		case 1:
+			if (phy->type == B43_PHYTYPE_G) {
+				if (bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM
+				    && bus->boardinfo.type == SSB_BOARD_BCM4309G
+				    && bus->boardinfo.rev >= 30)
+					rf->att = 3;
+				else if (bus->boardinfo.vendor ==
+					 SSB_BOARDVENDOR_BCM
+					 && bus->boardinfo.type ==
+					 SSB_BOARD_BU4306)
+					rf->att = 3;
+				else
+					rf->att = 1;
+			} else {
+				if (bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM
+				    && bus->boardinfo.type == SSB_BOARD_BCM4309G
+				    && bus->boardinfo.rev >= 30)
+					rf->att = 7;
+				else
+					rf->att = 6;
+			}
+			return;
+		case 2:
+			if (phy->type == B43_PHYTYPE_G) {
+				if (bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM
+				    && bus->boardinfo.type == SSB_BOARD_BCM4309G
+				    && bus->boardinfo.rev >= 30)
+					rf->att = 3;
+				else if (bus->boardinfo.vendor ==
+					 SSB_BOARDVENDOR_BCM
+					 && bus->boardinfo.type ==
+					 SSB_BOARD_BU4306)
+					rf->att = 5;
+				else if (bus->chip_id == 0x4320)
+					rf->att = 4;
+				else
+					rf->att = 3;
+			} else
+				rf->att = 6;
+			return;
+		case 3:
+			rf->att = 5;
+			return;
+		case 4:
+		case 5:
+			rf->att = 1;
+			return;
+		case 6:
+		case 7:
+			rf->att = 5;
+			return;
+		case 8:
+			rf->att = 0xA;
+			rf->with_padmix = 1;
+			return;
+		case 9:
+		default:
+			rf->att = 5;
+			return;
+		}
+	}
+	rf->att = 5;
+}
+
+static u16 default_tx_control(struct b43_wldev *dev)
+{
+	struct b43_phy *phy = &dev->phy;
+
+	if (phy->radio_ver != 0x2050)
+		return 0;
+	if (phy->radio_rev == 1)
+		return B43_TXCTL_PA2DB | B43_TXCTL_TXMIX;
+	if (phy->radio_rev < 6)
+		return B43_TXCTL_PA2DB;
+	if (phy->radio_rev == 8)
+		return B43_TXCTL_TXMIX;
+	return 0;
+}
+
+static u8 b43_gphy_aci_detect(struct b43_wldev *dev, u8 channel)
+{
+	struct b43_phy *phy = &dev->phy;
+	struct b43_phy_g *gphy = phy->g;
+	u8 ret = 0;
+	u16 saved, rssi, temp;
+	int i, j = 0;
+
+	saved = b43_phy_read(dev, 0x0403);
+	b43_switch_channel(dev, channel);
+	b43_phy_write(dev, 0x0403, (saved & 0xFFF8) | 5);
+	if (gphy->aci_hw_rssi)
+		rssi = b43_phy_read(dev, 0x048A) & 0x3F;
+	else
+		rssi = saved & 0x3F;
+	/* clamp temp to signed 5bit */
+	if (rssi > 32)
+		rssi -= 64;
+	for (i = 0; i < 100; i++) {
+		temp = (b43_phy_read(dev, 0x047F) >> 8) & 0x3F;
+		if (temp > 32)
+			temp -= 64;
+		if (temp < rssi)
+			j++;
+		if (j >= 20)
+			ret = 1;
+	}
+	b43_phy_write(dev, 0x0403, saved);
+
+	return ret;
+}
+
+static u8 b43_gphy_aci_scan(struct b43_wldev *dev)
+{
+	struct b43_phy *phy = &dev->phy;
+	u8 ret[13];
+	unsigned int channel = phy->channel;
+	unsigned int i, j, start, end;
+
+	if (!((phy->type == B43_PHYTYPE_G) && (phy->rev > 0)))
+		return 0;
+
+	b43_phy_lock(dev);
+	b43_radio_lock(dev);
+	b43_phy_write(dev, 0x0802, b43_phy_read(dev, 0x0802) & 0xFFFC);
+	b43_phy_write(dev, B43_PHY_G_CRS,
+		      b43_phy_read(dev, B43_PHY_G_CRS) & 0x7FFF);
+	b43_set_all_gains(dev, 3, 8, 1);
+
+	start = (channel - 5 > 0) ? channel - 5 : 1;
+	end = (channel + 5 < 14) ? channel + 5 : 13;
+
+	for (i = start; i <= end; i++) {
+		if (abs(channel - i) > 2)
+			ret[i - 1] = b43_gphy_aci_detect(dev, i);
+	}
+	b43_switch_channel(dev, channel);
+	b43_phy_write(dev, 0x0802,
+		      (b43_phy_read(dev, 0x0802) & 0xFFFC) | 0x0003);
+	b43_phy_write(dev, 0x0403, b43_phy_read(dev, 0x0403) & 0xFFF8);
+	b43_phy_write(dev, B43_PHY_G_CRS,
+		      b43_phy_read(dev, B43_PHY_G_CRS) | 0x8000);
+	b43_set_original_gains(dev);
+	for (i = 0; i < 13; i++) {
+		if (!ret[i])
+			continue;
+		end = (i + 5 < 13) ? i + 5 : 13;
+		for (j = i; j < end; j++)
+			ret[j] = 1;
+	}
+	b43_radio_unlock(dev);
+	b43_phy_unlock(dev);
+
+	return ret[channel - 1];
+}
+
+static s32 b43_tssi2dbm_ad(s32 num, s32 den)
+{
+	if (num < 0)
+		return num / den;
+	else
+		return (num + den / 2) / den;
+}
+
+static s8 b43_tssi2dbm_entry(s8 entry[], u8 index,
+			     s16 pab0, s16 pab1, s16 pab2)
+{
+	s32 m1, m2, f = 256, q, delta;
+	s8 i = 0;
+
+	m1 = b43_tssi2dbm_ad(16 * pab0 + index * pab1, 32);
+	m2 = max(b43_tssi2dbm_ad(32768 + index * pab2, 256), 1);
+	do {
+		if (i > 15)
+			return -EINVAL;
+		q = b43_tssi2dbm_ad(f * 4096 -
+				    b43_tssi2dbm_ad(m2 * f, 16) * f, 2048);
+		delta = abs(q - f);
+		f = q;
+		i++;
+	} while (delta >= 2);
+	entry[index] = clamp_val(b43_tssi2dbm_ad(m1 * f, 8192), -127, 128);
+	return 0;
+}
+
+u8 * b43_generate_dyn_tssi2dbm_tab(struct b43_wldev *dev,
+				   s16 pab0, s16 pab1, s16 pab2)
+{
+	unsigned int i;
+	u8 *tab;
+	int err;
+
+	tab = kmalloc(64, GFP_KERNEL);
+	if (!tab) {
+		b43err(dev->wl, "Could not allocate memory "
+		       "for tssi2dbm table\n");
+		return NULL;
+	}
+	for (i = 0; i < 64; i++) {
+		err = b43_tssi2dbm_entry(tab, i, pab0, pab1, pab2);
+		if (err) {
+			b43err(dev->wl, "Could not generate "
+			       "tssi2dBm table\n");
+			kfree(tab);
+			return NULL;
+		}
+	}
+
+	return tab;
+}
+
+/* Initialise the TSSI->dBm lookup table */
+static int b43_gphy_init_tssi2dbm_table(struct b43_wldev *dev)
+{
+	struct b43_phy *phy = &dev->phy;
+	struct b43_phy_g *gphy = phy->g;
+	s16 pab0, pab1, pab2;
+
+	pab0 = (s16) (dev->dev->bus->sprom.pa0b0);
+	pab1 = (s16) (dev->dev->bus->sprom.pa0b1);
+	pab2 = (s16) (dev->dev->bus->sprom.pa0b2);
+
+	B43_WARN_ON((dev->dev->bus->chip_id == 0x4301) &&
+		    (phy->radio_ver != 0x2050)); /* Not supported anymore */
+
+	gphy->dyn_tssi_tbl = 0;
+
+	if (pab0 != 0 && pab1 != 0 && pab2 != 0 &&
+	    pab0 != -1 && pab1 != -1 && pab2 != -1) {
+		/* The pabX values are set in SPROM. Use them. */
+		if ((s8) dev->dev->bus->sprom.itssi_bg != 0 &&
+		    (s8) dev->dev->bus->sprom.itssi_bg != -1) {
+			gphy->tgt_idle_tssi =
+				(s8) (dev->dev->bus->sprom.itssi_bg);
+		} else
+			gphy->tgt_idle_tssi = 62;
+		gphy->tssi2dbm = b43_generate_dyn_tssi2dbm_tab(dev, pab0,
+							       pab1, pab2);
+		if (!gphy->tssi2dbm)
+			return -ENOMEM;
+		gphy->dyn_tssi_tbl = 1;
+	} else {
+		/* pabX values not set in SPROM. */
+		gphy->tgt_idle_tssi = 52;
+		gphy->tssi2dbm = b43_tssi2dbm_g_table;
+	}
+
+	return 0;
+}
+
+static int b43_gphy_op_allocate(struct b43_wldev *dev)
+{
+	struct b43_phy_g *gphy;
+	struct b43_txpower_lo_control *lo;
+	int err;
+
+	gphy = kzalloc(sizeof(*gphy), GFP_KERNEL);
+	if (!gphy) {
+		err = -ENOMEM;
+		goto error;
+	}
+	dev->phy.g = gphy;
+
+	lo = kzalloc(sizeof(*lo), GFP_KERNEL);
+	if (!lo) {
+		err = -ENOMEM;
+		goto err_free_gphy;
+	}
+	gphy->lo_control = lo;
+
+	err = b43_gphy_init_tssi2dbm_table(dev);
+	if (err)
+		goto err_free_lo;
+
+	return 0;
+
+err_free_lo:
+	kfree(lo);
+err_free_gphy:
+	kfree(gphy);
+error:
+	return err;
+}
+
+static void b43_gphy_op_prepare_structs(struct b43_wldev *dev)
+{
+	struct b43_phy *phy = &dev->phy;
+	struct b43_phy_g *gphy = phy->g;
+	const void *tssi2dbm;
+	int tgt_idle_tssi;
+	struct b43_txpower_lo_control *lo;
+	unsigned int i;
+
+	/* tssi2dbm table is constant, so it is initialized at alloc time.
+	 * Save a copy of the pointer. */
+	tssi2dbm = gphy->tssi2dbm;
+	tgt_idle_tssi = gphy->tgt_idle_tssi;
+	/* Save the LO pointer. */
+	lo = gphy->lo_control;
+
+	/* Zero out the whole PHY structure. */
+	memset(gphy, 0, sizeof(*gphy));
+
+	/* Restore pointers. */
+	gphy->tssi2dbm = tssi2dbm;
+	gphy->tgt_idle_tssi = tgt_idle_tssi;
+	gphy->lo_control = lo;
+
+	memset(gphy->minlowsig, 0xFF, sizeof(gphy->minlowsig));
+
+	/* NRSSI */
+	for (i = 0; i < ARRAY_SIZE(gphy->nrssi); i++)
+		gphy->nrssi[i] = -1000;
+	for (i = 0; i < ARRAY_SIZE(gphy->nrssi_lt); i++)
+		gphy->nrssi_lt[i] = i;
+
+	gphy->lofcal = 0xFFFF;
+	gphy->initval = 0xFFFF;
+
+	gphy->interfmode = B43_INTERFMODE_NONE;
+
+	/* OFDM-table address caching. */
+	gphy->ofdmtab_addr_direction = B43_OFDMTAB_DIRECTION_UNKNOWN;
+
+	gphy->average_tssi = 0xFF;
+
+	/* Local Osciallator structure */
+	lo->tx_bias = 0xFF;
+	INIT_LIST_HEAD(&lo->calib_list);
+}
+
+static void b43_gphy_op_free(struct b43_wldev *dev)
+{
+	struct b43_phy *phy = &dev->phy;
+	struct b43_phy_g *gphy = phy->g;
+
+	kfree(gphy->lo_control);
+
+	if (gphy->dyn_tssi_tbl)
+		kfree(gphy->tssi2dbm);
+	gphy->dyn_tssi_tbl = 0;
+	gphy->tssi2dbm = NULL;
+
+	kfree(gphy);
+	dev->phy.g = NULL;
+}
+
+static int b43_gphy_op_prepare_hardware(struct b43_wldev *dev)
+{
+	struct b43_phy *phy = &dev->phy;
+	struct b43_phy_g *gphy = phy->g;
+	struct b43_txpower_lo_control *lo = gphy->lo_control;
+
+	B43_WARN_ON(phy->type != B43_PHYTYPE_G);
+
+	default_baseband_attenuation(dev, &gphy->bbatt);
+	default_radio_attenuation(dev, &gphy->rfatt);
+	gphy->tx_control = (default_tx_control(dev) << 4);
+	generate_rfatt_list(dev, &lo->rfatt_list);
+	generate_bbatt_list(dev, &lo->bbatt_list);
+
+	/* Commit previous writes */
+	b43_read32(dev, B43_MMIO_MACCTL);
+
+	if (phy->rev == 1) {
+		/* Workaround: Temporarly disable gmode through the early init
+		 * phase, as the gmode stuff is not needed for phy rev 1 */
+		phy->gmode = 0;
+		b43_wireless_core_reset(dev, 0);
+		b43_phy_initg(dev);
+		phy->gmode = 1;
+		b43_wireless_core_reset(dev, B43_TMSLOW_GMODE);
+	}
+
+	return 0;
+}
+
+static int b43_gphy_op_init(struct b43_wldev *dev)
+{
+	b43_phy_initg(dev);
+
+	return 0;
+}
+
+static void b43_gphy_op_exit(struct b43_wldev *dev)
+{
+	b43_lo_g_cleanup(dev);
+}
+
+static u16 b43_gphy_op_read(struct b43_wldev *dev, u16 reg)
+{
+	b43_write16(dev, B43_MMIO_PHY_CONTROL, reg);
+	return b43_read16(dev, B43_MMIO_PHY_DATA);
+}
+
+static void b43_gphy_op_write(struct b43_wldev *dev, u16 reg, u16 value)
+{
+	b43_write16(dev, B43_MMIO_PHY_CONTROL, reg);
+	b43_write16(dev, B43_MMIO_PHY_DATA, value);
+}
+
+static u16 b43_gphy_op_radio_read(struct b43_wldev *dev, u16 reg)
+{
+	/* Register 1 is a 32-bit register. */
+	B43_WARN_ON(reg == 1);
+	/* G-PHY needs 0x80 for read access. */
+	reg |= 0x80;
+
+	b43_write16(dev, B43_MMIO_RADIO_CONTROL, reg);
+	return b43_read16(dev, B43_MMIO_RADIO_DATA_LOW);
+}
+
+static void b43_gphy_op_radio_write(struct b43_wldev *dev, u16 reg, u16 value)
+{
+	/* Register 1 is a 32-bit register. */
+	B43_WARN_ON(reg == 1);
+
+	b43_write16(dev, B43_MMIO_RADIO_CONTROL, reg);
+	b43_write16(dev, B43_MMIO_RADIO_DATA_LOW, value);
+}
+
+static bool b43_gphy_op_supports_hwpctl(struct b43_wldev *dev)
+{
+	return (dev->phy.rev >= 6);
+}
+
+static void b43_gphy_op_software_rfkill(struct b43_wldev *dev,
+					enum rfkill_state state)
+{
+	struct b43_phy *phy = &dev->phy;
+	struct b43_phy_g *gphy = phy->g;
+	unsigned int channel;
+
+	might_sleep();
+
+	if (state == RFKILL_STATE_UNBLOCKED) {
+		/* Turn radio ON */
+		if (phy->radio_on)
+			return;
+
+		b43_phy_write(dev, 0x0015, 0x8000);
+		b43_phy_write(dev, 0x0015, 0xCC00);
+		b43_phy_write(dev, 0x0015, (phy->gmode ? 0x00C0 : 0x0000));
+		if (gphy->radio_off_context.valid) {
+			/* Restore the RFover values. */
+			b43_phy_write(dev, B43_PHY_RFOVER,
+				      gphy->radio_off_context.rfover);
+			b43_phy_write(dev, B43_PHY_RFOVERVAL,
+				      gphy->radio_off_context.rfoverval);
+			gphy->radio_off_context.valid = 0;
+		}
+		channel = phy->channel;
+		b43_gphy_channel_switch(dev, 6, 1);
+		b43_gphy_channel_switch(dev, channel, 0);
+	} else {
+		/* Turn radio OFF */
+		u16 rfover, rfoverval;
+
+		rfover = b43_phy_read(dev, B43_PHY_RFOVER);
+		rfoverval = b43_phy_read(dev, B43_PHY_RFOVERVAL);
+		gphy->radio_off_context.rfover = rfover;
+		gphy->radio_off_context.rfoverval = rfoverval;
+		gphy->radio_off_context.valid = 1;
+		b43_phy_write(dev, B43_PHY_RFOVER, rfover | 0x008C);
+		b43_phy_write(dev, B43_PHY_RFOVERVAL, rfoverval & 0xFF73);
+	}
+}
+
+static int b43_gphy_op_switch_channel(struct b43_wldev *dev,
+				      unsigned int new_channel)
+{
+	if ((new_channel < 1) || (new_channel > 14))
+		return -EINVAL;
+	b43_gphy_channel_switch(dev, new_channel, 0);
+
+	return 0;
+}
+
+static unsigned int b43_gphy_op_get_default_chan(struct b43_wldev *dev)
+{
+	return 1; /* Default to channel 1 */
+}
+
+static void b43_gphy_op_set_rx_antenna(struct b43_wldev *dev, int antenna)
+{
+	struct b43_phy *phy = &dev->phy;
+	u64 hf;
+	u16 tmp;
+	int autodiv = 0;
+
+	if (antenna == B43_ANTENNA_AUTO0 || antenna == B43_ANTENNA_AUTO1)
+		autodiv = 1;
+
+	hf = b43_hf_read(dev);
+	hf &= ~B43_HF_ANTDIVHELP;
+	b43_hf_write(dev, hf);
+
+	tmp = b43_phy_read(dev, B43_PHY_BBANDCFG);
+	tmp &= ~B43_PHY_BBANDCFG_RXANT;
+	tmp |= (autodiv ? B43_ANTENNA_AUTO0 : antenna)
+			<< B43_PHY_BBANDCFG_RXANT_SHIFT;
+	b43_phy_write(dev, B43_PHY_BBANDCFG, tmp);
+
+	if (autodiv) {
+		tmp = b43_phy_read(dev, B43_PHY_ANTDWELL);
+		if (antenna == B43_ANTENNA_AUTO0)
+			tmp &= ~B43_PHY_ANTDWELL_AUTODIV1;
+		else
+			tmp |= B43_PHY_ANTDWELL_AUTODIV1;
+		b43_phy_write(dev, B43_PHY_ANTDWELL, tmp);
+	}
+	tmp = b43_phy_read(dev, B43_PHY_ANTWRSETT);
+	if (autodiv)
+		tmp |= B43_PHY_ANTWRSETT_ARXDIV;
+	else
+		tmp &= ~B43_PHY_ANTWRSETT_ARXDIV;
+	b43_phy_write(dev, B43_PHY_ANTWRSETT, tmp);
+	if (phy->rev >= 2) {
+		tmp = b43_phy_read(dev, B43_PHY_OFDM61);
+		tmp |= B43_PHY_OFDM61_10;
+		b43_phy_write(dev, B43_PHY_OFDM61, tmp);
+
+		tmp =
+		    b43_phy_read(dev, B43_PHY_DIVSRCHGAINBACK);
+		tmp = (tmp & 0xFF00) | 0x15;
+		b43_phy_write(dev, B43_PHY_DIVSRCHGAINBACK,
+			      tmp);
+
+		if (phy->rev == 2) {
+			b43_phy_write(dev, B43_PHY_ADIVRELATED,
+				      8);
+		} else {
+			tmp =
+			    b43_phy_read(dev,
+					 B43_PHY_ADIVRELATED);
+			tmp = (tmp & 0xFF00) | 8;
+			b43_phy_write(dev, B43_PHY_ADIVRELATED,
+				      tmp);
+		}
+	}
+	if (phy->rev >= 6)
+		b43_phy_write(dev, B43_PHY_OFDM9B, 0xDC);
+
+	hf |= B43_HF_ANTDIVHELP;
+	b43_hf_write(dev, hf);
+}
+
+static int b43_gphy_op_interf_mitigation(struct b43_wldev *dev,
+					 enum b43_interference_mitigation mode)
+{
+	struct b43_phy *phy = &dev->phy;
+	struct b43_phy_g *gphy = phy->g;
+	int currentmode;
+
+	B43_WARN_ON(phy->type != B43_PHYTYPE_G);
+	if ((phy->rev == 0) || (!phy->gmode))
+		return -ENODEV;
+
+	gphy->aci_wlan_automatic = 0;
+	switch (mode) {
+	case B43_INTERFMODE_AUTOWLAN:
+		gphy->aci_wlan_automatic = 1;
+		if (gphy->aci_enable)
+			mode = B43_INTERFMODE_MANUALWLAN;
+		else
+			mode = B43_INTERFMODE_NONE;
+		break;
+	case B43_INTERFMODE_NONE:
+	case B43_INTERFMODE_NONWLAN:
+	case B43_INTERFMODE_MANUALWLAN:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	currentmode = gphy->interfmode;
+	if (currentmode == mode)
+		return 0;
+	if (currentmode != B43_INTERFMODE_NONE)
+		b43_radio_interference_mitigation_disable(dev, currentmode);
+
+	if (mode == B43_INTERFMODE_NONE) {
+		gphy->aci_enable = 0;
+		gphy->aci_hw_rssi = 0;
+	} else
+		b43_radio_interference_mitigation_enable(dev, mode);
+	gphy->interfmode = mode;
+
+	return 0;
+}
+
+/* http://bcm-specs.sipsolutions.net/EstimatePowerOut
+ * This function converts a TSSI value to dBm in Q5.2
+ */
+static s8 b43_gphy_estimate_power_out(struct b43_wldev *dev, s8 tssi)
+{
+	struct b43_phy_g *gphy = dev->phy.g;
+	s8 dbm;
+	s32 tmp;
+
+	tmp = (gphy->tgt_idle_tssi - gphy->cur_idle_tssi + tssi);
+	tmp = clamp_val(tmp, 0x00, 0x3F);
+	dbm = gphy->tssi2dbm[tmp];
+
+	return dbm;
+}
+
+static void b43_put_attenuation_into_ranges(struct b43_wldev *dev,
+					    int *_bbatt, int *_rfatt)
+{
+	int rfatt = *_rfatt;
+	int bbatt = *_bbatt;
+	struct b43_txpower_lo_control *lo = dev->phy.g->lo_control;
+
+	/* Get baseband and radio attenuation values into their permitted ranges.
+	 * Radio attenuation affects power level 4 times as much as baseband. */
+
+	/* Range constants */
+	const int rf_min = lo->rfatt_list.min_val;
+	const int rf_max = lo->rfatt_list.max_val;
+	const int bb_min = lo->bbatt_list.min_val;
+	const int bb_max = lo->bbatt_list.max_val;
+
+	while (1) {
+		if (rfatt > rf_max && bbatt > bb_max - 4)
+			break;	/* Can not get it into ranges */
+		if (rfatt < rf_min && bbatt < bb_min + 4)
+			break;	/* Can not get it into ranges */
+		if (bbatt > bb_max && rfatt > rf_max - 1)
+			break;	/* Can not get it into ranges */
+		if (bbatt < bb_min && rfatt < rf_min + 1)
+			break;	/* Can not get it into ranges */
+
+		if (bbatt > bb_max) {
+			bbatt -= 4;
+			rfatt += 1;
+			continue;
+		}
+		if (bbatt < bb_min) {
+			bbatt += 4;
+			rfatt -= 1;
+			continue;
+		}
+		if (rfatt > rf_max) {
+			rfatt -= 1;
+			bbatt += 4;
+			continue;
+		}
+		if (rfatt < rf_min) {
+			rfatt += 1;
+			bbatt -= 4;
+			continue;
+		}
+		break;
+	}
+
+	*_rfatt = clamp_val(rfatt, rf_min, rf_max);
+	*_bbatt = clamp_val(bbatt, bb_min, bb_max);
+}
+
+static void b43_gphy_op_adjust_txpower(struct b43_wldev *dev)
+{
+	struct b43_phy *phy = &dev->phy;
+	struct b43_phy_g *gphy = phy->g;
+	int rfatt, bbatt;
+	u8 tx_control;
+
+	spin_lock_irq(&dev->wl->irq_lock);
+
+	/* Calculate the new attenuation values. */
+	bbatt = gphy->bbatt.att;
+	bbatt += gphy->bbatt_delta;
+	rfatt = gphy->rfatt.att;
+	rfatt += gphy->rfatt_delta;
+
+	b43_put_attenuation_into_ranges(dev, &bbatt, &rfatt);
+	tx_control = gphy->tx_control;
+	if ((phy->radio_ver == 0x2050) && (phy->radio_rev == 2)) {
+		if (rfatt <= 1) {
+			if (tx_control == 0) {
+				tx_control =
+				    B43_TXCTL_PA2DB |
+				    B43_TXCTL_TXMIX;
+				rfatt += 2;
+				bbatt += 2;
+			} else if (dev->dev->bus->sprom.
+				   boardflags_lo &
+				   B43_BFL_PACTRL) {
+				bbatt += 4 * (rfatt - 2);
+				rfatt = 2;
+			}
+		} else if (rfatt > 4 && tx_control) {
+			tx_control = 0;
+			if (bbatt < 3) {
+				rfatt -= 3;
+				bbatt += 2;
+			} else {
+				rfatt -= 2;
+				bbatt -= 2;
+			}
+		}
+	}
+	/* Save the control values */
+	gphy->tx_control = tx_control;
+	b43_put_attenuation_into_ranges(dev, &bbatt, &rfatt);
+	gphy->rfatt.att = rfatt;
+	gphy->bbatt.att = bbatt;
+
+	/* We drop the lock early, so we can sleep during hardware
+	 * adjustment. Possible races with op_recalc_txpower are harmless,
+	 * as we will be called once again in case we raced. */
+	spin_unlock_irq(&dev->wl->irq_lock);
+
+	if (b43_debug(dev, B43_DBG_XMITPOWER))
+		b43dbg(dev->wl, "Adjusting TX power\n");
+
+	/* Adjust the hardware */
+	b43_phy_lock(dev);
+	b43_radio_lock(dev);
+	b43_set_txpower_g(dev, &gphy->bbatt, &gphy->rfatt,
+			  gphy->tx_control);
+	b43_radio_unlock(dev);
+	b43_phy_unlock(dev);
+}
+
+static enum b43_txpwr_result b43_gphy_op_recalc_txpower(struct b43_wldev *dev,
+							bool ignore_tssi)
+{
+	struct b43_phy *phy = &dev->phy;
+	struct b43_phy_g *gphy = phy->g;
+	unsigned int average_tssi;
+	int cck_result, ofdm_result;
+	int estimated_pwr, desired_pwr, pwr_adjust;
+	int rfatt_delta, bbatt_delta;
+	unsigned int max_pwr;
+
+	/* First get the average TSSI */
+	cck_result = b43_phy_shm_tssi_read(dev, B43_SHM_SH_TSSI_CCK);
+	ofdm_result = b43_phy_shm_tssi_read(dev, B43_SHM_SH_TSSI_OFDM_G);
+	if ((cck_result < 0) && (ofdm_result < 0)) {
+		/* No TSSI information available */
+		if (!ignore_tssi)
+			goto no_adjustment_needed;
+		cck_result = 0;
+		ofdm_result = 0;
+	}
+	if (cck_result < 0)
+		average_tssi = ofdm_result;
+	else if (ofdm_result < 0)
+		average_tssi = cck_result;
+	else
+		average_tssi = (cck_result + ofdm_result) / 2;
+	/* Merge the average with the stored value. */
+	if (likely(gphy->average_tssi != 0xFF))
+		average_tssi = (average_tssi + gphy->average_tssi) / 2;
+	gphy->average_tssi = average_tssi;
+	B43_WARN_ON(average_tssi >= B43_TSSI_MAX);
+
+	/* Estimate the TX power emission based on the TSSI */
+	estimated_pwr = b43_gphy_estimate_power_out(dev, average_tssi);
+
+	B43_WARN_ON(phy->type != B43_PHYTYPE_G);
+	max_pwr = dev->dev->bus->sprom.maxpwr_bg;
+	if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_PACTRL)
+		max_pwr -= 3; /* minus 0.75 */
+	if (unlikely(max_pwr >= INT_TO_Q52(30/*dBm*/))) {
+		b43warn(dev->wl,
+			"Invalid max-TX-power value in SPROM.\n");
+		max_pwr = INT_TO_Q52(20); /* fake it */
+		dev->dev->bus->sprom.maxpwr_bg = max_pwr;
+	}
+
+	/* Get desired power (in Q5.2) */
+	if (phy->desired_txpower < 0)
+		desired_pwr = INT_TO_Q52(0);
+	else
+		desired_pwr = INT_TO_Q52(phy->desired_txpower);
+	/* And limit it. max_pwr already is Q5.2 */
+	desired_pwr = clamp_val(desired_pwr, 0, max_pwr);
+	if (b43_debug(dev, B43_DBG_XMITPOWER)) {
+		b43dbg(dev->wl,
+		       "[TX power]  current = " Q52_FMT
+		       " dBm,  desired = " Q52_FMT
+		       " dBm,  max = " Q52_FMT "\n",
+		       Q52_ARG(estimated_pwr),
+		       Q52_ARG(desired_pwr),
+		       Q52_ARG(max_pwr));
+	}
+
+	/* Calculate the adjustment delta. */
+	pwr_adjust = desired_pwr - estimated_pwr;
+	if (pwr_adjust == 0)
+		goto no_adjustment_needed;
+
+	/* RF attenuation delta. */
+	rfatt_delta = ((pwr_adjust + 7) / 8);
+	/* Lower attenuation => Bigger power output. Negate it. */
+	rfatt_delta = -rfatt_delta;
+
+	/* Baseband attenuation delta. */
+	bbatt_delta = pwr_adjust / 2;
+	/* Lower attenuation => Bigger power output. Negate it. */
+	bbatt_delta = -bbatt_delta;
+	/* RF att affects power level 4 times as much as
+	 * Baseband attennuation. Subtract it. */
+	bbatt_delta -= 4 * rfatt_delta;
+
+	if (b43_debug(dev, B43_DBG_XMITPOWER)) {
+		int dbm = pwr_adjust < 0 ? -pwr_adjust : pwr_adjust;
+		b43dbg(dev->wl,
+		       "[TX power deltas]  %s" Q52_FMT " dBm   =>   "
+		       "bbatt-delta = %d,  rfatt-delta = %d\n",
+		       (pwr_adjust < 0 ? "-" : ""), Q52_ARG(dbm),
+		       bbatt_delta, rfatt_delta);
+	}
+	/* So do we finally need to adjust something in hardware? */
+	if ((rfatt_delta == 0) && (bbatt_delta == 0))
+		goto no_adjustment_needed;
+
+	/* Save the deltas for later when we adjust the power. */
+	gphy->bbatt_delta = bbatt_delta;
+	gphy->rfatt_delta = rfatt_delta;
+
+	/* We need to adjust the TX power on the device. */
+	return B43_TXPWR_RES_NEED_ADJUST;
+
+no_adjustment_needed:
+	return B43_TXPWR_RES_DONE;
+}
+
+static void b43_gphy_op_pwork_15sec(struct b43_wldev *dev)
+{
+	struct b43_phy *phy = &dev->phy;
+	struct b43_phy_g *gphy = phy->g;
+
+	//TODO: update_aci_moving_average
+	if (gphy->aci_enable && gphy->aci_wlan_automatic) {
+		b43_mac_suspend(dev);
+		if (!gphy->aci_enable && 1 /*TODO: not scanning? */ ) {
+			if (0 /*TODO: bunch of conditions */ ) {
+				phy->ops->interf_mitigation(dev,
+					B43_INTERFMODE_MANUALWLAN);
+			}
+		} else if (0 /*TODO*/) {
+			   if (/*(aci_average > 1000) &&*/ !b43_gphy_aci_scan(dev))
+				phy->ops->interf_mitigation(dev, B43_INTERFMODE_NONE);
+		}
+		b43_mac_enable(dev);
+	} else if (gphy->interfmode == B43_INTERFMODE_NONWLAN &&
+		   phy->rev == 1) {
+		//TODO: implement rev1 workaround
+	}
+	b43_lo_g_maintanance_work(dev);
+}
+
+static void b43_gphy_op_pwork_60sec(struct b43_wldev *dev)
+{
+	struct b43_phy *phy = &dev->phy;
+
+	if (!(dev->dev->bus->sprom.boardflags_lo & B43_BFL_RSSI))
+		return;
+
+	b43_mac_suspend(dev);
+	b43_calc_nrssi_slope(dev);
+	if ((phy->radio_ver == 0x2050) && (phy->radio_rev == 8)) {
+		u8 old_chan = phy->channel;
+
+		/* VCO Calibration */
+		if (old_chan >= 8)
+			b43_switch_channel(dev, 1);
+		else
+			b43_switch_channel(dev, 13);
+		b43_switch_channel(dev, old_chan);
+	}
+	b43_mac_enable(dev);
+}
+
+const struct b43_phy_operations b43_phyops_g = {
+	.allocate		= b43_gphy_op_allocate,
+	.free			= b43_gphy_op_free,
+	.prepare_structs	= b43_gphy_op_prepare_structs,
+	.prepare_hardware	= b43_gphy_op_prepare_hardware,
+	.init			= b43_gphy_op_init,
+	.exit			= b43_gphy_op_exit,
+	.phy_read		= b43_gphy_op_read,
+	.phy_write		= b43_gphy_op_write,
+	.radio_read		= b43_gphy_op_radio_read,
+	.radio_write		= b43_gphy_op_radio_write,
+	.supports_hwpctl	= b43_gphy_op_supports_hwpctl,
+	.software_rfkill	= b43_gphy_op_software_rfkill,
+	.switch_analog		= b43_phyop_switch_analog_generic,
+	.switch_channel		= b43_gphy_op_switch_channel,
+	.get_default_chan	= b43_gphy_op_get_default_chan,
+	.set_rx_antenna		= b43_gphy_op_set_rx_antenna,
+	.interf_mitigation	= b43_gphy_op_interf_mitigation,
+	.recalc_txpower		= b43_gphy_op_recalc_txpower,
+	.adjust_txpower		= b43_gphy_op_adjust_txpower,
+	.pwork_15sec		= b43_gphy_op_pwork_15sec,
+	.pwork_60sec		= b43_gphy_op_pwork_60sec,
+};
diff --git a/drivers/net/wireless/b43/phy_g.h b/drivers/net/wireless/b43/phy_g.h
new file mode 100644
index 0000000..718947f
--- /dev/null
+++ b/drivers/net/wireless/b43/phy_g.h
@@ -0,0 +1,209 @@
+#ifndef LINUX_B43_PHY_G_H_
+#define LINUX_B43_PHY_G_H_
+
+/* OFDM PHY registers are defined in the A-PHY header. */
+#include "phy_a.h"
+
+/* CCK (B) PHY Registers */
+#define B43_PHY_VERSION_CCK		B43_PHY_CCK(0x00)	/* Versioning register for B-PHY */
+#define B43_PHY_CCKBBANDCFG		B43_PHY_CCK(0x01)	/* Contains antenna 0/1 control bit */
+#define B43_PHY_PGACTL			B43_PHY_CCK(0x15)	/* PGA control */
+#define  B43_PHY_PGACTL_LPF		0x1000	/* Low pass filter (?) */
+#define  B43_PHY_PGACTL_LOWBANDW	0x0040	/* Low bandwidth flag */
+#define  B43_PHY_PGACTL_UNKNOWN		0xEFA0
+#define B43_PHY_FBCTL1			B43_PHY_CCK(0x18)	/* Frequency bandwidth control 1 */
+#define B43_PHY_ITSSI			B43_PHY_CCK(0x29)	/* Idle TSSI */
+#define B43_PHY_LO_LEAKAGE		B43_PHY_CCK(0x2D)	/* Measured LO leakage */
+#define B43_PHY_ENERGY			B43_PHY_CCK(0x33)	/* Energy */
+#define B43_PHY_SYNCCTL			B43_PHY_CCK(0x35)
+#define B43_PHY_FBCTL2			B43_PHY_CCK(0x38)	/* Frequency bandwidth control 2 */
+#define B43_PHY_DACCTL			B43_PHY_CCK(0x60)	/* DAC control */
+#define B43_PHY_RCCALOVER		B43_PHY_CCK(0x78)	/* RC calibration override */
+
+/* Extended G-PHY Registers */
+#define B43_PHY_CLASSCTL		B43_PHY_EXTG(0x02)	/* Classify control */
+#define B43_PHY_GTABCTL			B43_PHY_EXTG(0x03)	/* G-PHY table control (see below) */
+#define  B43_PHY_GTABOFF		0x03FF	/* G-PHY table offset (see below) */
+#define  B43_PHY_GTABNR			0xFC00	/* G-PHY table number (see below) */
+#define  B43_PHY_GTABNR_SHIFT		10
+#define B43_PHY_GTABDATA		B43_PHY_EXTG(0x04)	/* G-PHY table data */
+#define B43_PHY_LO_MASK			B43_PHY_EXTG(0x0F)	/* Local Oscillator control mask */
+#define B43_PHY_LO_CTL			B43_PHY_EXTG(0x10)	/* Local Oscillator control */
+#define B43_PHY_RFOVER			B43_PHY_EXTG(0x11)	/* RF override */
+#define B43_PHY_RFOVERVAL		B43_PHY_EXTG(0x12)	/* RF override value */
+#define  B43_PHY_RFOVERVAL_EXTLNA	0x8000
+#define  B43_PHY_RFOVERVAL_LNA		0x7000
+#define  B43_PHY_RFOVERVAL_LNA_SHIFT	12
+#define  B43_PHY_RFOVERVAL_PGA		0x0F00
+#define  B43_PHY_RFOVERVAL_PGA_SHIFT	8
+#define  B43_PHY_RFOVERVAL_UNK		0x0010	/* Unknown, always set. */
+#define  B43_PHY_RFOVERVAL_TRSWRX	0x00E0
+#define  B43_PHY_RFOVERVAL_BW		0x0003	/* Bandwidth flags */
+#define   B43_PHY_RFOVERVAL_BW_LPF	0x0001	/* Low Pass Filter */
+#define   B43_PHY_RFOVERVAL_BW_LBW	0x0002	/* Low Bandwidth (when set), high when unset */
+#define B43_PHY_ANALOGOVER		B43_PHY_EXTG(0x14)	/* Analog override */
+#define B43_PHY_ANALOGOVERVAL		B43_PHY_EXTG(0x15)	/* Analog override value */
+
+
+/*** G-PHY table numbers */
+#define B43_GTAB(number, offset)	(((number) << B43_PHY_GTABNR_SHIFT) | (offset))
+#define B43_GTAB_NRSSI			B43_GTAB(0x00, 0)
+#define B43_GTAB_TRFEMW			B43_GTAB(0x0C, 0x120)
+#define B43_GTAB_ORIGTR			B43_GTAB(0x2E, 0x298)
+
+u16 b43_gtab_read(struct b43_wldev *dev, u16 table, u16 offset);
+void b43_gtab_write(struct b43_wldev *dev, u16 table, u16 offset, u16 value);
+
+
+/* Returns the boolean whether "TX Magnification" is enabled. */
+#define has_tx_magnification(phy) \
+	(((phy)->rev >= 2) &&			\
+	 ((phy)->radio_ver == 0x2050) &&	\
+	 ((phy)->radio_rev == 8))
+/* Card uses the loopback gain stuff */
+#define has_loopback_gain(phy) \
+	(((phy)->rev > 1) || ((phy)->gmode))
+
+/* Radio Attenuation (RF Attenuation) */
+struct b43_rfatt {
+	u8 att;			/* Attenuation value */
+	bool with_padmix;	/* Flag, PAD Mixer enabled. */
+};
+struct b43_rfatt_list {
+	/* Attenuation values list */
+	const struct b43_rfatt *list;
+	u8 len;
+	/* Minimum/Maximum attenuation values */
+	u8 min_val;
+	u8 max_val;
+};
+
+/* Returns true, if the values are the same. */
+static inline bool b43_compare_rfatt(const struct b43_rfatt *a,
+				     const struct b43_rfatt *b)
+{
+	return ((a->att == b->att) &&
+		(a->with_padmix == b->with_padmix));
+}
+
+/* Baseband Attenuation */
+struct b43_bbatt {
+	u8 att;			/* Attenuation value */
+};
+struct b43_bbatt_list {
+	/* Attenuation values list */
+	const struct b43_bbatt *list;
+	u8 len;
+	/* Minimum/Maximum attenuation values */
+	u8 min_val;
+	u8 max_val;
+};
+
+/* Returns true, if the values are the same. */
+static inline bool b43_compare_bbatt(const struct b43_bbatt *a,
+				     const struct b43_bbatt *b)
+{
+	return (a->att == b->att);
+}
+
+/* tx_control bits. */
+#define B43_TXCTL_PA3DB		0x40	/* PA Gain 3dB */
+#define B43_TXCTL_PA2DB		0x20	/* PA Gain 2dB */
+#define B43_TXCTL_TXMIX		0x10	/* TX Mixer Gain */
+
+struct b43_txpower_lo_control;
+
+struct b43_phy_g {
+	/* ACI (adjacent channel interference) flags. */
+	bool aci_enable;
+	bool aci_wlan_automatic;
+	bool aci_hw_rssi;
+
+	/* Radio switched on/off */
+	bool radio_on;
+	struct {
+		/* Values saved when turning the radio off.
+		 * They are needed when turning it on again. */
+		bool valid;
+		u16 rfover;
+		u16 rfoverval;
+	} radio_off_context;
+
+	u16 minlowsig[2];
+	u16 minlowsigpos[2];
+
+	/* Pointer to the table used to convert a
+	 * TSSI value to dBm-Q5.2 */
+	const s8 *tssi2dbm;
+	/* tssi2dbm is kmalloc()ed. Only used for free()ing. */
+	bool dyn_tssi_tbl;
+	/* Target idle TSSI */
+	int tgt_idle_tssi;
+	/* Current idle TSSI */
+	int cur_idle_tssi;
+	/* The current average TSSI.
+	 * Needs irq_lock, as it's updated in the IRQ path. */
+	u8 average_tssi;
+	/* Current TX power level attenuation control values */
+	struct b43_bbatt bbatt;
+	struct b43_rfatt rfatt;
+	u8 tx_control;		/* B43_TXCTL_XXX */
+	/* The calculated attenuation deltas that are used later
+	 * when adjusting the actual power output. */
+	int bbatt_delta;
+	int rfatt_delta;
+
+	/* LocalOscillator control values. */
+	struct b43_txpower_lo_control *lo_control;
+	/* Values from b43_calc_loopback_gain() */
+	s16 max_lb_gain;	/* Maximum Loopback gain in hdB */
+	s16 trsw_rx_gain;	/* TRSW RX gain in hdB */
+	s16 lna_lod_gain;	/* LNA lod */
+	s16 lna_gain;		/* LNA */
+	s16 pga_gain;		/* PGA */
+
+	/* Current Interference Mitigation mode */
+	int interfmode;
+	/* Stack of saved values from the Interference Mitigation code.
+	 * Each value in the stack is layed out as follows:
+	 * bit 0-11:  offset
+	 * bit 12-15: register ID
+	 * bit 16-32: value
+	 * register ID is: 0x1 PHY, 0x2 Radio, 0x3 ILT
+	 */
+#define B43_INTERFSTACK_SIZE	26
+	u32 interfstack[B43_INTERFSTACK_SIZE];	//FIXME: use a data structure
+
+	/* Saved values from the NRSSI Slope calculation */
+	s16 nrssi[2];
+	s32 nrssislope;
+	/* In memory nrssi lookup table. */
+	s8 nrssi_lt[64];
+
+	u16 lofcal;
+
+	u16 initval;		//FIXME rename?
+
+	/* The device does address auto increment for the OFDM tables.
+	 * We cache the previously used address here and omit the address
+	 * write on the next table access, if possible. */
+	u16 ofdmtab_addr; /* The address currently set in hardware. */
+	enum { /* The last data flow direction. */
+		B43_OFDMTAB_DIRECTION_UNKNOWN = 0,
+		B43_OFDMTAB_DIRECTION_READ,
+		B43_OFDMTAB_DIRECTION_WRITE,
+	} ofdmtab_addr_direction;
+};
+
+void b43_gphy_set_baseband_attenuation(struct b43_wldev *dev,
+				       u16 baseband_attenuation);
+void b43_gphy_channel_switch(struct b43_wldev *dev,
+			     unsigned int channel,
+			     bool synthetic_pu_workaround);
+u8 * b43_generate_dyn_tssi2dbm_tab(struct b43_wldev *dev,
+				   s16 pab0, s16 pab1, s16 pab2);
+
+struct b43_phy_operations;
+extern const struct b43_phy_operations b43_phyops_g;
+
+#endif /* LINUX_B43_PHY_G_H_ */
diff --git a/drivers/net/wireless/b43/phy_lp.c b/drivers/net/wireless/b43/phy_lp.c
new file mode 100644
index 0000000..c5d9dc3
--- /dev/null
+++ b/drivers/net/wireless/b43/phy_lp.c
@@ -0,0 +1,155 @@
+/*
+
+  Broadcom B43 wireless driver
+  IEEE 802.11g LP-PHY driver
+
+  Copyright (c) 2008 Michael Buesch <mb@bu3sch.de>
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; see the file COPYING.  If not, write to
+  the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+
+*/
+
+#include "b43.h"
+#include "phy_lp.h"
+#include "phy_common.h"
+
+
+static int b43_lpphy_op_allocate(struct b43_wldev *dev)
+{
+	struct b43_phy_lp *lpphy;
+
+	lpphy = kzalloc(sizeof(*lpphy), GFP_KERNEL);
+	if (!lpphy)
+		return -ENOMEM;
+	dev->phy.lp = lpphy;
+
+	return 0;
+}
+
+static void b43_lpphy_op_prepare_structs(struct b43_wldev *dev)
+{
+	struct b43_phy *phy = &dev->phy;
+	struct b43_phy_lp *lpphy = phy->lp;
+
+	memset(lpphy, 0, sizeof(*lpphy));
+
+	//TODO
+}
+
+static void b43_lpphy_op_free(struct b43_wldev *dev)
+{
+	struct b43_phy_lp *lpphy = dev->phy.lp;
+
+	kfree(lpphy);
+	dev->phy.lp = NULL;
+}
+
+static int b43_lpphy_op_init(struct b43_wldev *dev)
+{
+	//TODO
+
+	return 0;
+}
+
+static u16 b43_lpphy_op_read(struct b43_wldev *dev, u16 reg)
+{
+	b43_write16(dev, B43_MMIO_PHY_CONTROL, reg);
+	return b43_read16(dev, B43_MMIO_PHY_DATA);
+}
+
+static void b43_lpphy_op_write(struct b43_wldev *dev, u16 reg, u16 value)
+{
+	b43_write16(dev, B43_MMIO_PHY_CONTROL, reg);
+	b43_write16(dev, B43_MMIO_PHY_DATA, value);
+}
+
+static u16 b43_lpphy_op_radio_read(struct b43_wldev *dev, u16 reg)
+{
+	/* Register 1 is a 32-bit register. */
+	B43_WARN_ON(reg == 1);
+	/* LP-PHY needs a special bit set for read access */
+	if (dev->phy.rev < 2) {
+		if (reg != 0x4001)
+			reg |= 0x100;
+	} else
+		reg |= 0x200;
+
+	b43_write16(dev, B43_MMIO_RADIO_CONTROL, reg);
+	return b43_read16(dev, B43_MMIO_RADIO_DATA_LOW);
+}
+
+static void b43_lpphy_op_radio_write(struct b43_wldev *dev, u16 reg, u16 value)
+{
+	/* Register 1 is a 32-bit register. */
+	B43_WARN_ON(reg == 1);
+
+	b43_write16(dev, B43_MMIO_RADIO_CONTROL, reg);
+	b43_write16(dev, B43_MMIO_RADIO_DATA_LOW, value);
+}
+
+static void b43_lpphy_op_software_rfkill(struct b43_wldev *dev,
+					 enum rfkill_state state)
+{
+	//TODO
+}
+
+static int b43_lpphy_op_switch_channel(struct b43_wldev *dev,
+				       unsigned int new_channel)
+{
+	//TODO
+	return 0;
+}
+
+static unsigned int b43_lpphy_op_get_default_chan(struct b43_wldev *dev)
+{
+	return 1; /* Default to channel 1 */
+}
+
+static void b43_lpphy_op_set_rx_antenna(struct b43_wldev *dev, int antenna)
+{
+	//TODO
+}
+
+static void b43_lpphy_op_adjust_txpower(struct b43_wldev *dev)
+{
+	//TODO
+}
+
+static enum b43_txpwr_result b43_lpphy_op_recalc_txpower(struct b43_wldev *dev,
+							 bool ignore_tssi)
+{
+	//TODO
+	return B43_TXPWR_RES_DONE;
+}
+
+
+const struct b43_phy_operations b43_phyops_lp = {
+	.allocate		= b43_lpphy_op_allocate,
+	.free			= b43_lpphy_op_free,
+	.prepare_structs	= b43_lpphy_op_prepare_structs,
+	.init			= b43_lpphy_op_init,
+	.phy_read		= b43_lpphy_op_read,
+	.phy_write		= b43_lpphy_op_write,
+	.radio_read		= b43_lpphy_op_radio_read,
+	.radio_write		= b43_lpphy_op_radio_write,
+	.software_rfkill	= b43_lpphy_op_software_rfkill,
+	.switch_analog		= b43_phyop_switch_analog_generic,
+	.switch_channel		= b43_lpphy_op_switch_channel,
+	.get_default_chan	= b43_lpphy_op_get_default_chan,
+	.set_rx_antenna		= b43_lpphy_op_set_rx_antenna,
+	.recalc_txpower		= b43_lpphy_op_recalc_txpower,
+	.adjust_txpower		= b43_lpphy_op_adjust_txpower,
+};
diff --git a/drivers/net/wireless/b43/phy_lp.h b/drivers/net/wireless/b43/phy_lp.h
new file mode 100644
index 0000000..b0b5357
--- /dev/null
+++ b/drivers/net/wireless/b43/phy_lp.h
@@ -0,0 +1,540 @@
+#ifndef LINUX_B43_PHY_LP_H_
+#define LINUX_B43_PHY_LP_H_
+
+/* Definitions for the LP-PHY */
+
+
+
+
+#define B43_LP_RADIO(radio_reg)			(radio_reg)
+#define B43_LP_NORTH(radio_reg)			B43_LP_RADIO(radio_reg)
+#define B43_LP_SOUTH(radio_reg)			B43_LP_RADIO((radio_reg) | 0x4000)
+
+
+/*** Broadcom 2062 NORTH radio registers ***/
+#define B2062_N_COMM1				B43_LP_NORTH(0x000) /* Common 01 (north) */
+#define B2062_N_COMM2				B43_LP_NORTH(0x002) /* Common 02 (north) */
+#define B2062_N_COMM3				B43_LP_NORTH(0x003) /* Common 03 (north) */
+#define B2062_N_COMM4				B43_LP_NORTH(0x004) /* Common 04 (north) */
+#define B2062_N_COMM5				B43_LP_NORTH(0x005) /* Common 05 (north) */
+#define B2062_N_COMM6				B43_LP_NORTH(0x006) /* Common 06 (north) */
+#define B2062_N_COMM7				B43_LP_NORTH(0x007) /* Common 07 (north) */
+#define B2062_N_COMM8				B43_LP_NORTH(0x008) /* Common 08 (north) */
+#define B2062_N_COMM9				B43_LP_NORTH(0x009) /* Common 09 (north) */
+#define B2062_N_COMM10				B43_LP_NORTH(0x00A) /* Common 10 (north) */
+#define B2062_N_COMM11				B43_LP_NORTH(0x00B) /* Common 11 (north) */
+#define B2062_N_COMM12				B43_LP_NORTH(0x00C) /* Common 12 (north) */
+#define B2062_N_COMM13				B43_LP_NORTH(0x00D) /* Common 13 (north) */
+#define B2062_N_COMM14				B43_LP_NORTH(0x00E) /* Common 14 (north) */
+#define B2062_N_COMM15				B43_LP_NORTH(0x00F) /* Common 15 (north) */
+#define B2062_N_PDN_CTL0			B43_LP_NORTH(0x010) /* PDN Control 0 (north) */
+#define B2062_N_PDN_CTL1			B43_LP_NORTH(0x011) /* PDN Control 1 (north) */
+#define B2062_N_PDN_CTL2			B43_LP_NORTH(0x012) /* PDN Control 2 (north) */
+#define B2062_N_PDN_CTL3			B43_LP_NORTH(0x013) /* PDN Control 3 (north) */
+#define B2062_N_PDN_CTL4			B43_LP_NORTH(0x014) /* PDN Control 4 (north) */
+#define B2062_N_GEN_CTL0			B43_LP_NORTH(0x015) /* GEN Control 0 (north) */
+#define B2062_N_IQ_CALIB			B43_LP_NORTH(0x016) /* IQ Calibration (north) */
+#define B2062_N_LGENC				B43_LP_NORTH(0x017) /* LGENC (north) */
+#define B2062_N_LGENA_LPF			B43_LP_NORTH(0x018) /* LGENA LPF (north) */
+#define B2062_N_LGENA_BIAS0			B43_LP_NORTH(0x019) /* LGENA Bias 0 (north) */
+#define B2062_N_LGNEA_BIAS1			B43_LP_NORTH(0x01A) /* LGNEA Bias 1 (north) */
+#define B2062_N_LGENA_CTL0			B43_LP_NORTH(0x01B) /* LGENA Control 0 (north) */
+#define B2062_N_LGENA_CTL1			B43_LP_NORTH(0x01C) /* LGENA Control 1 (north) */
+#define B2062_N_LGENA_CTL2			B43_LP_NORTH(0x01D) /* LGENA Control 2 (north) */
+#define B2062_N_LGENA_TUNE0			B43_LP_NORTH(0x01E) /* LGENA Tune 0 (north) */
+#define B2062_N_LGENA_TUNE1			B43_LP_NORTH(0x01F) /* LGENA Tune 1 (north) */
+#define B2062_N_LGENA_TUNE2			B43_LP_NORTH(0x020) /* LGENA Tune 2 (north) */
+#define B2062_N_LGENA_TUNE3			B43_LP_NORTH(0x021) /* LGENA Tune 3 (north) */
+#define B2062_N_LGENA_CTL3			B43_LP_NORTH(0x022) /* LGENA Control 3 (north) */
+#define B2062_N_LGENA_CTL4			B43_LP_NORTH(0x023) /* LGENA Control 4 (north) */
+#define B2062_N_LGENA_CTL5			B43_LP_NORTH(0x024) /* LGENA Control 5 (north) */
+#define B2062_N_LGENA_CTL6			B43_LP_NORTH(0x025) /* LGENA Control 6 (north) */
+#define B2062_N_LGENA_CTL7			B43_LP_NORTH(0x026) /* LGENA Control 7 (north) */
+#define B2062_N_RXA_CTL0			B43_LP_NORTH(0x027) /* RXA Control 0 (north) */
+#define B2062_N_RXA_CTL1			B43_LP_NORTH(0x028) /* RXA Control 1 (north) */
+#define B2062_N_RXA_CTL2			B43_LP_NORTH(0x029) /* RXA Control 2 (north) */
+#define B2062_N_RXA_CTL3			B43_LP_NORTH(0x02A) /* RXA Control 3 (north) */
+#define B2062_N_RXA_CTL4			B43_LP_NORTH(0x02B) /* RXA Control 4 (north) */
+#define B2062_N_RXA_CTL5			B43_LP_NORTH(0x02C) /* RXA Control 5 (north) */
+#define B2062_N_RXA_CTL6			B43_LP_NORTH(0x02D) /* RXA Control 6 (north) */
+#define B2062_N_RXA_CTL7			B43_LP_NORTH(0x02E) /* RXA Control 7 (north) */
+#define B2062_N_RXBB_CTL0			B43_LP_NORTH(0x02F) /* RXBB Control 0 (north) */
+#define B2062_N_RXBB_CTL1			B43_LP_NORTH(0x030) /* RXBB Control 1 (north) */
+#define B2062_N_RXBB_CTL2			B43_LP_NORTH(0x031) /* RXBB Control 2 (north) */
+#define B2062_N_RXBB_GAIN0			B43_LP_NORTH(0x032) /* RXBB Gain 0 (north) */
+#define B2062_N_RXBB_GAIN1			B43_LP_NORTH(0x033) /* RXBB Gain 1 (north) */
+#define B2062_N_RXBB_GAIN2			B43_LP_NORTH(0x034) /* RXBB Gain 2 (north) */
+#define B2062_N_RXBB_GAIN3			B43_LP_NORTH(0x035) /* RXBB Gain 3 (north) */
+#define B2062_N_RXBB_RSSI0			B43_LP_NORTH(0x036) /* RXBB RSSI 0 (north) */
+#define B2062_N_RXBB_RSSI1			B43_LP_NORTH(0x037) /* RXBB RSSI 1 (north) */
+#define B2062_N_RXBB_CALIB0			B43_LP_NORTH(0x038) /* RXBB Calibration0 (north) */
+#define B2062_N_RXBB_CALIB1			B43_LP_NORTH(0x039) /* RXBB Calibration1 (north) */
+#define B2062_N_RXBB_CALIB2			B43_LP_NORTH(0x03A) /* RXBB Calibration2 (north) */
+#define B2062_N_RXBB_BIAS0			B43_LP_NORTH(0x03B) /* RXBB Bias 0 (north) */
+#define B2062_N_RXBB_BIAS1			B43_LP_NORTH(0x03C) /* RXBB Bias 1 (north) */
+#define B2062_N_RXBB_BIAS2			B43_LP_NORTH(0x03D) /* RXBB Bias 2 (north) */
+#define B2062_N_RXBB_BIAS3			B43_LP_NORTH(0x03E) /* RXBB Bias 3 (north) */
+#define B2062_N_RXBB_BIAS4			B43_LP_NORTH(0x03F) /* RXBB Bias 4 (north) */
+#define B2062_N_RXBB_BIAS5			B43_LP_NORTH(0x040) /* RXBB Bias 5 (north) */
+#define B2062_N_RXBB_RSSI2			B43_LP_NORTH(0x041) /* RXBB RSSI 2 (north) */
+#define B2062_N_RXBB_RSSI3			B43_LP_NORTH(0x042) /* RXBB RSSI 3 (north) */
+#define B2062_N_RXBB_RSSI4			B43_LP_NORTH(0x043) /* RXBB RSSI 4 (north) */
+#define B2062_N_RXBB_RSSI5			B43_LP_NORTH(0x044) /* RXBB RSSI 5 (north) */
+#define B2062_N_TX_CTL0				B43_LP_NORTH(0x045) /* TX Control 0 (north) */
+#define B2062_N_TX_CTL1				B43_LP_NORTH(0x046) /* TX Control 1 (north) */
+#define B2062_N_TX_CTL2				B43_LP_NORTH(0x047) /* TX Control 2 (north) */
+#define B2062_N_TX_CTL3				B43_LP_NORTH(0x048) /* TX Control 3 (north) */
+#define B2062_N_TX_CTL4				B43_LP_NORTH(0x049) /* TX Control 4 (north) */
+#define B2062_N_TX_CTL5				B43_LP_NORTH(0x04A) /* TX Control 5 (north) */
+#define B2062_N_TX_CTL6				B43_LP_NORTH(0x04B) /* TX Control 6 (north) */
+#define B2062_N_TX_CTL7				B43_LP_NORTH(0x04C) /* TX Control 7 (north) */
+#define B2062_N_TX_CTL8				B43_LP_NORTH(0x04D) /* TX Control 8 (north) */
+#define B2062_N_TX_CTL9				B43_LP_NORTH(0x04E) /* TX Control 9 (north) */
+#define B2062_N_TX_CTL_A			B43_LP_NORTH(0x04F) /* TX Control A (north) */
+#define B2062_N_TX_GC2G				B43_LP_NORTH(0x050) /* TX GC2G (north) */
+#define B2062_N_TX_GC5G				B43_LP_NORTH(0x051) /* TX GC5G (north) */
+#define B2062_N_TX_TUNE				B43_LP_NORTH(0x052) /* TX Tune (north) */
+#define B2062_N_TX_PAD				B43_LP_NORTH(0x053) /* TX PAD (north) */
+#define B2062_N_TX_PGA				B43_LP_NORTH(0x054) /* TX PGA (north) */
+#define B2062_N_TX_PADAUX			B43_LP_NORTH(0x055) /* TX PADAUX (north) */
+#define B2062_N_TX_PGAAUX			B43_LP_NORTH(0x056) /* TX PGAAUX (north) */
+#define B2062_N_TSSI_CTL0			B43_LP_NORTH(0x057) /* TSSI Control 0 (north) */
+#define B2062_N_TSSI_CTL1			B43_LP_NORTH(0x058) /* TSSI Control 1 (north) */
+#define B2062_N_TSSI_CTL2			B43_LP_NORTH(0x059) /* TSSI Control 2 (north) */
+#define B2062_N_IQ_CALIB_CTL0			B43_LP_NORTH(0x05A) /* IQ Calibration Control 0 (north) */
+#define B2062_N_IQ_CALIB_CTL1			B43_LP_NORTH(0x05B) /* IQ Calibration Control 1 (north) */
+#define B2062_N_IQ_CALIB_CTL2			B43_LP_NORTH(0x05C) /* IQ Calibration Control 2 (north) */
+#define B2062_N_CALIB_TS			B43_LP_NORTH(0x05D) /* Calibration TS (north) */
+#define B2062_N_CALIB_CTL0			B43_LP_NORTH(0x05E) /* Calibration Control 0 (north) */
+#define B2062_N_CALIB_CTL1			B43_LP_NORTH(0x05F) /* Calibration Control 1 (north) */
+#define B2062_N_CALIB_CTL2			B43_LP_NORTH(0x060) /* Calibration Control 2 (north) */
+#define B2062_N_CALIB_CTL3			B43_LP_NORTH(0x061) /* Calibration Control 3 (north) */
+#define B2062_N_CALIB_CTL4			B43_LP_NORTH(0x062) /* Calibration Control 4 (north) */
+#define B2062_N_CALIB_DBG0			B43_LP_NORTH(0x063) /* Calibration Debug 0 (north) */
+#define B2062_N_CALIB_DBG1			B43_LP_NORTH(0x064) /* Calibration Debug 1 (north) */
+#define B2062_N_CALIB_DBG2			B43_LP_NORTH(0x065) /* Calibration Debug 2 (north) */
+#define B2062_N_CALIB_DBG3			B43_LP_NORTH(0x066) /* Calibration Debug 3 (north) */
+#define B2062_N_PSENSE_CTL0			B43_LP_NORTH(0x069) /* PSENSE Control 0 (north) */
+#define B2062_N_PSENSE_CTL1			B43_LP_NORTH(0x06A) /* PSENSE Control 1 (north) */
+#define B2062_N_PSENSE_CTL2			B43_LP_NORTH(0x06B) /* PSENSE Control 2 (north) */
+#define B2062_N_TEST_BUF0			B43_LP_NORTH(0x06C) /* TEST BUF0 (north) */
+
+/*** Broadcom 2062 SOUTH radio registers ***/
+#define B2062_S_COMM1				B43_LP_SOUTH(0x000) /* Common 01 (south) */
+#define B2062_S_RADIO_ID_CODE			B43_LP_SOUTH(0x001) /* Radio ID code (south) */
+#define B2062_S_COMM2				B43_LP_SOUTH(0x002) /* Common 02 (south) */
+#define B2062_S_COMM3				B43_LP_SOUTH(0x003) /* Common 03 (south) */
+#define B2062_S_COMM4				B43_LP_SOUTH(0x004) /* Common 04 (south) */
+#define B2062_S_COMM5				B43_LP_SOUTH(0x005) /* Common 05 (south) */
+#define B2062_S_COMM6				B43_LP_SOUTH(0x006) /* Common 06 (south) */
+#define B2062_S_COMM7				B43_LP_SOUTH(0x007) /* Common 07 (south) */
+#define B2062_S_COMM8				B43_LP_SOUTH(0x008) /* Common 08 (south) */
+#define B2062_S_COMM9				B43_LP_SOUTH(0x009) /* Common 09 (south) */
+#define B2062_S_COMM10				B43_LP_SOUTH(0x00A) /* Common 10 (south) */
+#define B2062_S_COMM11				B43_LP_SOUTH(0x00B) /* Common 11 (south) */
+#define B2062_S_COMM12				B43_LP_SOUTH(0x00C) /* Common 12 (south) */
+#define B2062_S_COMM13				B43_LP_SOUTH(0x00D) /* Common 13 (south) */
+#define B2062_S_COMM14				B43_LP_SOUTH(0x00E) /* Common 14 (south) */
+#define B2062_S_COMM15				B43_LP_SOUTH(0x00F) /* Common 15 (south) */
+#define B2062_S_PDS_CTL0			B43_LP_SOUTH(0x010) /* PDS Control 0 (south) */
+#define B2062_S_PDS_CTL1			B43_LP_SOUTH(0x011) /* PDS Control 1 (south) */
+#define B2062_S_PDS_CTL2			B43_LP_SOUTH(0x012) /* PDS Control 2 (south) */
+#define B2062_S_PDS_CTL3			B43_LP_SOUTH(0x013) /* PDS Control 3 (south) */
+#define B2062_S_BG_CTL0				B43_LP_SOUTH(0x014) /* BG Control 0 (south) */
+#define B2062_S_BG_CTL1				B43_LP_SOUTH(0x015) /* BG Control 1 (south) */
+#define B2062_S_BG_CTL2				B43_LP_SOUTH(0x016) /* BG Control 2 (south) */
+#define B2062_S_LGENG_CTL0			B43_LP_SOUTH(0x017) /* LGENG Control 00 (south) */
+#define B2062_S_LGENG_CTL1			B43_LP_SOUTH(0x018) /* LGENG Control 01 (south) */
+#define B2062_S_LGENG_CTL2			B43_LP_SOUTH(0x019) /* LGENG Control 02 (south) */
+#define B2062_S_LGENG_CTL3			B43_LP_SOUTH(0x01A) /* LGENG Control 03 (south) */
+#define B2062_S_LGENG_CTL4			B43_LP_SOUTH(0x01B) /* LGENG Control 04 (south) */
+#define B2062_S_LGENG_CTL5			B43_LP_SOUTH(0x01C) /* LGENG Control 05 (south) */
+#define B2062_S_LGENG_CTL6			B43_LP_SOUTH(0x01D) /* LGENG Control 06 (south) */
+#define B2062_S_LGENG_CTL7			B43_LP_SOUTH(0x01E) /* LGENG Control 07 (south) */
+#define B2062_S_LGENG_CTL8			B43_LP_SOUTH(0x01F) /* LGENG Control 08 (south) */
+#define B2062_S_LGENG_CTL9			B43_LP_SOUTH(0x020) /* LGENG Control 09 (south) */
+#define B2062_S_LGENG_CTL10			B43_LP_SOUTH(0x021) /* LGENG Control 10 (south) */
+#define B2062_S_LGENG_CTL11			B43_LP_SOUTH(0x022) /* LGENG Control 11 (south) */
+#define B2062_S_REFPLL_CTL0			B43_LP_SOUTH(0x023) /* REFPLL Control 00 (south) */
+#define B2062_S_REFPLL_CTL1			B43_LP_SOUTH(0x024) /* REFPLL Control 01 (south) */
+#define B2062_S_REFPLL_CTL2			B43_LP_SOUTH(0x025) /* REFPLL Control 02 (south) */
+#define B2062_S_REFPLL_CTL3			B43_LP_SOUTH(0x026) /* REFPLL Control 03 (south) */
+#define B2062_S_REFPLL_CTL4			B43_LP_SOUTH(0x027) /* REFPLL Control 04 (south) */
+#define B2062_S_REFPLL_CTL5			B43_LP_SOUTH(0x028) /* REFPLL Control 05 (south) */
+#define B2062_S_REFPLL_CTL6			B43_LP_SOUTH(0x029) /* REFPLL Control 06 (south) */
+#define B2062_S_REFPLL_CTL7			B43_LP_SOUTH(0x02A) /* REFPLL Control 07 (south) */
+#define B2062_S_REFPLL_CTL8			B43_LP_SOUTH(0x02B) /* REFPLL Control 08 (south) */
+#define B2062_S_REFPLL_CTL9			B43_LP_SOUTH(0x02C) /* REFPLL Control 09 (south) */
+#define B2062_S_REFPLL_CTL10			B43_LP_SOUTH(0x02D) /* REFPLL Control 10 (south) */
+#define B2062_S_REFPLL_CTL11			B43_LP_SOUTH(0x02E) /* REFPLL Control 11 (south) */
+#define B2062_S_REFPLL_CTL12			B43_LP_SOUTH(0x02F) /* REFPLL Control 12 (south) */
+#define B2062_S_REFPLL_CTL13			B43_LP_SOUTH(0x030) /* REFPLL Control 13 (south) */
+#define B2062_S_REFPLL_CTL14			B43_LP_SOUTH(0x031) /* REFPLL Control 14 (south) */
+#define B2062_S_REFPLL_CTL15			B43_LP_SOUTH(0x032) /* REFPLL Control 15 (south) */
+#define B2062_S_REFPLL_CTL16			B43_LP_SOUTH(0x033) /* REFPLL Control 16 (south) */
+#define B2062_S_RFPLL_CTL0			B43_LP_SOUTH(0x034) /* RFPLL Control 00 (south) */
+#define B2062_S_RFPLL_CTL1			B43_LP_SOUTH(0x035) /* RFPLL Control 01 (south) */
+#define B2062_S_RFPLL_CTL2			B43_LP_SOUTH(0x036) /* RFPLL Control 02 (south) */
+#define B2062_S_RFPLL_CTL3			B43_LP_SOUTH(0x037) /* RFPLL Control 03 (south) */
+#define B2062_S_RFPLL_CTL4			B43_LP_SOUTH(0x038) /* RFPLL Control 04 (south) */
+#define B2062_S_RFPLL_CTL5			B43_LP_SOUTH(0x039) /* RFPLL Control 05 (south) */
+#define B2062_S_RFPLL_CTL6			B43_LP_SOUTH(0x03A) /* RFPLL Control 06 (south) */
+#define B2062_S_RFPLL_CTL7			B43_LP_SOUTH(0x03B) /* RFPLL Control 07 (south) */
+#define B2062_S_RFPLL_CTL8			B43_LP_SOUTH(0x03C) /* RFPLL Control 08 (south) */
+#define B2062_S_RFPLL_CTL9			B43_LP_SOUTH(0x03D) /* RFPLL Control 09 (south) */
+#define B2062_S_RFPLL_CTL10			B43_LP_SOUTH(0x03E) /* RFPLL Control 10 (south) */
+#define B2062_S_RFPLL_CTL11			B43_LP_SOUTH(0x03F) /* RFPLL Control 11 (south) */
+#define B2062_S_RFPLL_CTL12			B43_LP_SOUTH(0x040) /* RFPLL Control 12 (south) */
+#define B2062_S_RFPLL_CTL13			B43_LP_SOUTH(0x041) /* RFPLL Control 13 (south) */
+#define B2062_S_RFPLL_CTL14			B43_LP_SOUTH(0x042) /* RFPLL Control 14 (south) */
+#define B2062_S_RFPLL_CTL15			B43_LP_SOUTH(0x043) /* RFPLL Control 15 (south) */
+#define B2062_S_RFPLL_CTL16			B43_LP_SOUTH(0x044) /* RFPLL Control 16 (south) */
+#define B2062_S_RFPLL_CTL17			B43_LP_SOUTH(0x045) /* RFPLL Control 17 (south) */
+#define B2062_S_RFPLL_CTL18			B43_LP_SOUTH(0x046) /* RFPLL Control 18 (south) */
+#define B2062_S_RFPLL_CTL19			B43_LP_SOUTH(0x047) /* RFPLL Control 19 (south) */
+#define B2062_S_RFPLL_CTL20			B43_LP_SOUTH(0x048) /* RFPLL Control 20 (south) */
+#define B2062_S_RFPLL_CTL21			B43_LP_SOUTH(0x049) /* RFPLL Control 21 (south) */
+#define B2062_S_RFPLL_CTL22			B43_LP_SOUTH(0x04A) /* RFPLL Control 22 (south) */
+#define B2062_S_RFPLL_CTL23			B43_LP_SOUTH(0x04B) /* RFPLL Control 23 (south) */
+#define B2062_S_RFPLL_CTL24			B43_LP_SOUTH(0x04C) /* RFPLL Control 24 (south) */
+#define B2062_S_RFPLL_CTL25			B43_LP_SOUTH(0x04D) /* RFPLL Control 25 (south) */
+#define B2062_S_RFPLL_CTL26			B43_LP_SOUTH(0x04E) /* RFPLL Control 26 (south) */
+#define B2062_S_RFPLL_CTL27			B43_LP_SOUTH(0x04F) /* RFPLL Control 27 (south) */
+#define B2062_S_RFPLL_CTL28			B43_LP_SOUTH(0x050) /* RFPLL Control 28 (south) */
+#define B2062_S_RFPLL_CTL29			B43_LP_SOUTH(0x051) /* RFPLL Control 29 (south) */
+#define B2062_S_RFPLL_CTL30			B43_LP_SOUTH(0x052) /* RFPLL Control 30 (south) */
+#define B2062_S_RFPLL_CTL31			B43_LP_SOUTH(0x053) /* RFPLL Control 31 (south) */
+#define B2062_S_RFPLL_CTL32			B43_LP_SOUTH(0x054) /* RFPLL Control 32 (south) */
+#define B2062_S_RFPLL_CTL33			B43_LP_SOUTH(0x055) /* RFPLL Control 33 (south) */
+#define B2062_S_RFPLL_CTL34			B43_LP_SOUTH(0x056) /* RFPLL Control 34 (south) */
+#define B2062_S_RXG_CNT0			B43_LP_SOUTH(0x057) /* RXG Counter 00 (south) */
+#define B2062_S_RXG_CNT1			B43_LP_SOUTH(0x058) /* RXG Counter 01 (south) */
+#define B2062_S_RXG_CNT2			B43_LP_SOUTH(0x059) /* RXG Counter 02 (south) */
+#define B2062_S_RXG_CNT3			B43_LP_SOUTH(0x05A) /* RXG Counter 03 (south) */
+#define B2062_S_RXG_CNT4			B43_LP_SOUTH(0x05B) /* RXG Counter 04 (south) */
+#define B2062_S_RXG_CNT5			B43_LP_SOUTH(0x05C) /* RXG Counter 05 (south) */
+#define B2062_S_RXG_CNT6			B43_LP_SOUTH(0x05D) /* RXG Counter 06 (south) */
+#define B2062_S_RXG_CNT7			B43_LP_SOUTH(0x05E) /* RXG Counter 07 (south) */
+#define B2062_S_RXG_CNT8			B43_LP_SOUTH(0x05F) /* RXG Counter 08 (south) */
+#define B2062_S_RXG_CNT9			B43_LP_SOUTH(0x060) /* RXG Counter 09 (south) */
+#define B2062_S_RXG_CNT10			B43_LP_SOUTH(0x061) /* RXG Counter 10 (south) */
+#define B2062_S_RXG_CNT11			B43_LP_SOUTH(0x062) /* RXG Counter 11 (south) */
+#define B2062_S_RXG_CNT12			B43_LP_SOUTH(0x063) /* RXG Counter 12 (south) */
+#define B2062_S_RXG_CNT13			B43_LP_SOUTH(0x064) /* RXG Counter 13 (south) */
+#define B2062_S_RXG_CNT14			B43_LP_SOUTH(0x065) /* RXG Counter 14 (south) */
+#define B2062_S_RXG_CNT15			B43_LP_SOUTH(0x066) /* RXG Counter 15 (south) */
+#define B2062_S_RXG_CNT16			B43_LP_SOUTH(0x067) /* RXG Counter 16 (south) */
+#define B2062_S_RXG_CNT17			B43_LP_SOUTH(0x068) /* RXG Counter 17 (south) */
+
+
+
+/*** Broadcom 2063 radio registers ***/
+#define B2063_RADIO_ID_CODE			B43_LP_RADIO(0x001) /* Radio ID code */
+#define B2063_COMM1				B43_LP_RADIO(0x000) /* Common 01 */
+#define B2063_COMM2				B43_LP_RADIO(0x002) /* Common 02 */
+#define B2063_COMM3				B43_LP_RADIO(0x003) /* Common 03 */
+#define B2063_COMM4				B43_LP_RADIO(0x004) /* Common 04 */
+#define B2063_COMM5				B43_LP_RADIO(0x005) /* Common 05 */
+#define B2063_COMM6				B43_LP_RADIO(0x006) /* Common 06 */
+#define B2063_COMM7				B43_LP_RADIO(0x007) /* Common 07 */
+#define B2063_COMM8				B43_LP_RADIO(0x008) /* Common 08 */
+#define B2063_COMM9				B43_LP_RADIO(0x009) /* Common 09 */
+#define B2063_COMM10				B43_LP_RADIO(0x00A) /* Common 10 */
+#define B2063_COMM11				B43_LP_RADIO(0x00B) /* Common 11 */
+#define B2063_COMM12				B43_LP_RADIO(0x00C) /* Common 12 */
+#define B2063_COMM13				B43_LP_RADIO(0x00D) /* Common 13 */
+#define B2063_COMM14				B43_LP_RADIO(0x00E) /* Common 14 */
+#define B2063_COMM15				B43_LP_RADIO(0x00F) /* Common 15 */
+#define B2063_COMM16				B43_LP_RADIO(0x010) /* Common 16 */
+#define B2063_COMM17				B43_LP_RADIO(0x011) /* Common 17 */
+#define B2063_COMM18				B43_LP_RADIO(0x012) /* Common 18 */
+#define B2063_COMM19				B43_LP_RADIO(0x013) /* Common 19 */
+#define B2063_COMM20				B43_LP_RADIO(0x014) /* Common 20 */
+#define B2063_COMM21				B43_LP_RADIO(0x015) /* Common 21 */
+#define B2063_COMM22				B43_LP_RADIO(0x016) /* Common 22 */
+#define B2063_COMM23				B43_LP_RADIO(0x017) /* Common 23 */
+#define B2063_COMM24				B43_LP_RADIO(0x018) /* Common 24 */
+#define B2063_PWR_SWITCH_CTL			B43_LP_RADIO(0x019) /* POWER SWITCH Control */
+#define B2063_PLL_SP1				B43_LP_RADIO(0x01A) /* PLL SP 1 */
+#define B2063_PLL_SP2				B43_LP_RADIO(0x01B) /* PLL SP 2 */
+#define B2063_LOGEN_SP1				B43_LP_RADIO(0x01C) /* LOGEN SP 1 */
+#define B2063_LOGEN_SP2				B43_LP_RADIO(0x01D) /* LOGEN SP 2 */
+#define B2063_LOGEN_SP3				B43_LP_RADIO(0x01E) /* LOGEN SP 3 */
+#define B2063_LOGEN_SP4				B43_LP_RADIO(0x01F) /* LOGEN SP 4 */
+#define B2063_LOGEN_SP5				B43_LP_RADIO(0x020) /* LOGEN SP 5 */
+#define B2063_G_RX_SP1				B43_LP_RADIO(0x021) /* G RX SP 1 */
+#define B2063_G_RX_SP2				B43_LP_RADIO(0x022) /* G RX SP 2 */
+#define B2063_G_RX_SP3				B43_LP_RADIO(0x023) /* G RX SP 3 */
+#define B2063_G_RX_SP4				B43_LP_RADIO(0x024) /* G RX SP 4 */
+#define B2063_G_RX_SP5				B43_LP_RADIO(0x025) /* G RX SP 5 */
+#define B2063_G_RX_SP6				B43_LP_RADIO(0x026) /* G RX SP 6 */
+#define B2063_G_RX_SP7				B43_LP_RADIO(0x027) /* G RX SP 7 */
+#define B2063_G_RX_SP8				B43_LP_RADIO(0x028) /* G RX SP 8 */
+#define B2063_G_RX_SP9				B43_LP_RADIO(0x029) /* G RX SP 9 */
+#define B2063_G_RX_SP10				B43_LP_RADIO(0x02A) /* G RX SP 10 */
+#define B2063_G_RX_SP11				B43_LP_RADIO(0x02B) /* G RX SP 11 */
+#define B2063_A_RX_SP1				B43_LP_RADIO(0x02C) /* A RX SP 1 */
+#define B2063_A_RX_SP2				B43_LP_RADIO(0x02D) /* A RX SP 2 */
+#define B2063_A_RX_SP3				B43_LP_RADIO(0x02E) /* A RX SP 3 */
+#define B2063_A_RX_SP4				B43_LP_RADIO(0x02F) /* A RX SP 4 */
+#define B2063_A_RX_SP5				B43_LP_RADIO(0x030) /* A RX SP 5 */
+#define B2063_A_RX_SP6				B43_LP_RADIO(0x031) /* A RX SP 6 */
+#define B2063_A_RX_SP7				B43_LP_RADIO(0x032) /* A RX SP 7 */
+#define B2063_RX_BB_SP1				B43_LP_RADIO(0x033) /* RX BB SP 1 */
+#define B2063_RX_BB_SP2				B43_LP_RADIO(0x034) /* RX BB SP 2 */
+#define B2063_RX_BB_SP3				B43_LP_RADIO(0x035) /* RX BB SP 3 */
+#define B2063_RX_BB_SP4				B43_LP_RADIO(0x036) /* RX BB SP 4 */
+#define B2063_RX_BB_SP5				B43_LP_RADIO(0x037) /* RX BB SP 5 */
+#define B2063_RX_BB_SP6				B43_LP_RADIO(0x038) /* RX BB SP 6 */
+#define B2063_RX_BB_SP7				B43_LP_RADIO(0x039) /* RX BB SP 7 */
+#define B2063_RX_BB_SP8				B43_LP_RADIO(0x03A) /* RX BB SP 8 */
+#define B2063_TX_RF_SP1				B43_LP_RADIO(0x03B) /* TX RF SP 1 */
+#define B2063_TX_RF_SP2				B43_LP_RADIO(0x03C) /* TX RF SP 2 */
+#define B2063_TX_RF_SP3				B43_LP_RADIO(0x03D) /* TX RF SP 3 */
+#define B2063_TX_RF_SP4				B43_LP_RADIO(0x03E) /* TX RF SP 4 */
+#define B2063_TX_RF_SP5				B43_LP_RADIO(0x03F) /* TX RF SP 5 */
+#define B2063_TX_RF_SP6				B43_LP_RADIO(0x040) /* TX RF SP 6 */
+#define B2063_TX_RF_SP7				B43_LP_RADIO(0x041) /* TX RF SP 7 */
+#define B2063_TX_RF_SP8				B43_LP_RADIO(0x042) /* TX RF SP 8 */
+#define B2063_TX_RF_SP9				B43_LP_RADIO(0x043) /* TX RF SP 9 */
+#define B2063_TX_RF_SP10			B43_LP_RADIO(0x044) /* TX RF SP 10 */
+#define B2063_TX_RF_SP11			B43_LP_RADIO(0x045) /* TX RF SP 11 */
+#define B2063_TX_RF_SP12			B43_LP_RADIO(0x046) /* TX RF SP 12 */
+#define B2063_TX_RF_SP13			B43_LP_RADIO(0x047) /* TX RF SP 13 */
+#define B2063_TX_RF_SP14			B43_LP_RADIO(0x048) /* TX RF SP 14 */
+#define B2063_TX_RF_SP15			B43_LP_RADIO(0x049) /* TX RF SP 15 */
+#define B2063_TX_RF_SP16			B43_LP_RADIO(0x04A) /* TX RF SP 16 */
+#define B2063_TX_RF_SP17			B43_LP_RADIO(0x04B) /* TX RF SP 17 */
+#define B2063_PA_SP1				B43_LP_RADIO(0x04C) /* PA SP 1 */
+#define B2063_PA_SP2				B43_LP_RADIO(0x04D) /* PA SP 2 */
+#define B2063_PA_SP3				B43_LP_RADIO(0x04E) /* PA SP 3 */
+#define B2063_PA_SP4				B43_LP_RADIO(0x04F) /* PA SP 4 */
+#define B2063_PA_SP5				B43_LP_RADIO(0x050) /* PA SP 5 */
+#define B2063_PA_SP6				B43_LP_RADIO(0x051) /* PA SP 6 */
+#define B2063_PA_SP7				B43_LP_RADIO(0x052) /* PA SP 7 */
+#define B2063_TX_BB_SP1				B43_LP_RADIO(0x053) /* TX BB SP 1 */
+#define B2063_TX_BB_SP2				B43_LP_RADIO(0x054) /* TX BB SP 2 */
+#define B2063_TX_BB_SP3				B43_LP_RADIO(0x055) /* TX BB SP 3 */
+#define B2063_REG_SP1				B43_LP_RADIO(0x056) /* REG SP 1 */
+#define B2063_BANDGAP_CTL1			B43_LP_RADIO(0x057) /* BANDGAP Control 1 */
+#define B2063_BANDGAP_CTL2			B43_LP_RADIO(0x058) /* BANDGAP Control 2 */
+#define B2063_LPO_CTL1				B43_LP_RADIO(0x059) /* LPO Control 1 */
+#define B2063_RC_CALIB_CTL1			B43_LP_RADIO(0x05A) /* RC Calibration Control 1 */
+#define B2063_RC_CALIB_CTL2			B43_LP_RADIO(0x05B) /* RC Calibration Control 2 */
+#define B2063_RC_CALIB_CTL3			B43_LP_RADIO(0x05C) /* RC Calibration Control 3 */
+#define B2063_RC_CALIB_CTL4			B43_LP_RADIO(0x05D) /* RC Calibration Control 4 */
+#define B2063_RC_CALIB_CTL5			B43_LP_RADIO(0x05E) /* RC Calibration Control 5 */
+#define B2063_RC_CALIB_CTL6			B43_LP_RADIO(0x05F) /* RC Calibration Control 6 */
+#define B2063_RC_CALIB_CTL7			B43_LP_RADIO(0x060) /* RC Calibration Control 7 */
+#define B2063_RC_CALIB_CTL8			B43_LP_RADIO(0x061) /* RC Calibration Control 8 */
+#define B2063_RC_CALIB_CTL9			B43_LP_RADIO(0x062) /* RC Calibration Control 9 */
+#define B2063_RC_CALIB_CTL10			B43_LP_RADIO(0x063) /* RC Calibration Control 10 */
+#define B2063_PLL_JTAG_CALNRST			B43_LP_RADIO(0x064) /* PLL JTAG CALNRST */
+#define B2063_PLL_JTAG_IN_PLL1			B43_LP_RADIO(0x065) /* PLL JTAG IN PLL 1 */
+#define B2063_PLL_JTAG_IN_PLL2			B43_LP_RADIO(0x066) /* PLL JTAG IN PLL 2 */
+#define B2063_PLL_JTAG_PLL_CP1			B43_LP_RADIO(0x067) /* PLL JTAG PLL CP 1 */
+#define B2063_PLL_JTAG_PLL_CP2			B43_LP_RADIO(0x068) /* PLL JTAG PLL CP 2 */
+#define B2063_PLL_JTAG_PLL_CP3			B43_LP_RADIO(0x069) /* PLL JTAG PLL CP 3 */
+#define B2063_PLL_JTAG_PLL_CP4			B43_LP_RADIO(0x06A) /* PLL JTAG PLL CP 4 */
+#define B2063_PLL_JTAG_PLL_CTL1			B43_LP_RADIO(0x06B) /* PLL JTAG PLL Control 1 */
+#define B2063_PLL_JTAG_PLL_LF1			B43_LP_RADIO(0x06C) /* PLL JTAG PLL LF 1 */
+#define B2063_PLL_JTAG_PLL_LF2			B43_LP_RADIO(0x06D) /* PLL JTAG PLL LF 2 */
+#define B2063_PLL_JTAG_PLL_LF3			B43_LP_RADIO(0x06E) /* PLL JTAG PLL LF 3 */
+#define B2063_PLL_JTAG_PLL_LF4			B43_LP_RADIO(0x06F) /* PLL JTAG PLL LF 4 */
+#define B2063_PLL_JTAG_PLL_SG1			B43_LP_RADIO(0x070) /* PLL JTAG PLL SG 1 */
+#define B2063_PLL_JTAG_PLL_SG2			B43_LP_RADIO(0x071) /* PLL JTAG PLL SG 2 */
+#define B2063_PLL_JTAG_PLL_SG3			B43_LP_RADIO(0x072) /* PLL JTAG PLL SG 3 */
+#define B2063_PLL_JTAG_PLL_SG4			B43_LP_RADIO(0x073) /* PLL JTAG PLL SG 4 */
+#define B2063_PLL_JTAG_PLL_SG5			B43_LP_RADIO(0x074) /* PLL JTAG PLL SG 5 */
+#define B2063_PLL_JTAG_PLL_VCO1			B43_LP_RADIO(0x075) /* PLL JTAG PLL VCO 1 */
+#define B2063_PLL_JTAG_PLL_VCO2			B43_LP_RADIO(0x076) /* PLL JTAG PLL VCO 2 */
+#define B2063_PLL_JTAG_PLL_VCO_CALIB1		B43_LP_RADIO(0x077) /* PLL JTAG PLL VCO Calibration 1 */
+#define B2063_PLL_JTAG_PLL_VCO_CALIB2		B43_LP_RADIO(0x078) /* PLL JTAG PLL VCO Calibration 2 */
+#define B2063_PLL_JTAG_PLL_VCO_CALIB3		B43_LP_RADIO(0x079) /* PLL JTAG PLL VCO Calibration 3 */
+#define B2063_PLL_JTAG_PLL_VCO_CALIB4		B43_LP_RADIO(0x07A) /* PLL JTAG PLL VCO Calibration 4 */
+#define B2063_PLL_JTAG_PLL_VCO_CALIB5		B43_LP_RADIO(0x07B) /* PLL JTAG PLL VCO Calibration 5 */
+#define B2063_PLL_JTAG_PLL_VCO_CALIB6		B43_LP_RADIO(0x07C) /* PLL JTAG PLL VCO Calibration 6 */
+#define B2063_PLL_JTAG_PLL_VCO_CALIB7		B43_LP_RADIO(0x07D) /* PLL JTAG PLL VCO Calibration 7 */
+#define B2063_PLL_JTAG_PLL_VCO_CALIB8		B43_LP_RADIO(0x07E) /* PLL JTAG PLL VCO Calibration 8 */
+#define B2063_PLL_JTAG_PLL_VCO_CALIB9		B43_LP_RADIO(0x07F) /* PLL JTAG PLL VCO Calibration 9 */
+#define B2063_PLL_JTAG_PLL_VCO_CALIB10		B43_LP_RADIO(0x080) /* PLL JTAG PLL VCO Calibration 10 */
+#define B2063_PLL_JTAG_PLL_XTAL_12		B43_LP_RADIO(0x081) /* PLL JTAG PLL XTAL 1 2 */
+#define B2063_PLL_JTAG_PLL_XTAL3		B43_LP_RADIO(0x082) /* PLL JTAG PLL XTAL 3 */
+#define B2063_LOGEN_ACL1			B43_LP_RADIO(0x083) /* LOGEN ACL 1 */
+#define B2063_LOGEN_ACL2			B43_LP_RADIO(0x084) /* LOGEN ACL 2 */
+#define B2063_LOGEN_ACL3			B43_LP_RADIO(0x085) /* LOGEN ACL 3 */
+#define B2063_LOGEN_ACL4			B43_LP_RADIO(0x086) /* LOGEN ACL 4 */
+#define B2063_LOGEN_ACL5			B43_LP_RADIO(0x087) /* LOGEN ACL 5 */
+#define B2063_LO_CALIB_INPUTS			B43_LP_RADIO(0x088) /* LO Calibration INPUTS */
+#define B2063_LO_CALIB_CTL1			B43_LP_RADIO(0x089) /* LO Calibration Control 1 */
+#define B2063_LO_CALIB_CTL2			B43_LP_RADIO(0x08A) /* LO Calibration Control 2 */
+#define B2063_LO_CALIB_CTL3			B43_LP_RADIO(0x08B) /* LO Calibration Control 3 */
+#define B2063_LO_CALIB_WAITCNT			B43_LP_RADIO(0x08C) /* LO Calibration WAITCNT */
+#define B2063_LO_CALIB_OVR1			B43_LP_RADIO(0x08D) /* LO Calibration OVR 1 */
+#define B2063_LO_CALIB_OVR2			B43_LP_RADIO(0x08E) /* LO Calibration OVR 2 */
+#define B2063_LO_CALIB_OVAL1			B43_LP_RADIO(0x08F) /* LO Calibration OVAL 1 */
+#define B2063_LO_CALIB_OVAL2			B43_LP_RADIO(0x090) /* LO Calibration OVAL 2 */
+#define B2063_LO_CALIB_OVAL3			B43_LP_RADIO(0x091) /* LO Calibration OVAL 3 */
+#define B2063_LO_CALIB_OVAL4			B43_LP_RADIO(0x092) /* LO Calibration OVAL 4 */
+#define B2063_LO_CALIB_OVAL5			B43_LP_RADIO(0x093) /* LO Calibration OVAL 5 */
+#define B2063_LO_CALIB_OVAL6			B43_LP_RADIO(0x094) /* LO Calibration OVAL 6 */
+#define B2063_LO_CALIB_OVAL7			B43_LP_RADIO(0x095) /* LO Calibration OVAL 7 */
+#define B2063_LO_CALIB_CALVLD1			B43_LP_RADIO(0x096) /* LO Calibration CALVLD 1 */
+#define B2063_LO_CALIB_CALVLD2			B43_LP_RADIO(0x097) /* LO Calibration CALVLD 2 */
+#define B2063_LO_CALIB_CVAL1			B43_LP_RADIO(0x098) /* LO Calibration CVAL 1 */
+#define B2063_LO_CALIB_CVAL2			B43_LP_RADIO(0x099) /* LO Calibration CVAL 2 */
+#define B2063_LO_CALIB_CVAL3			B43_LP_RADIO(0x09A) /* LO Calibration CVAL 3 */
+#define B2063_LO_CALIB_CVAL4			B43_LP_RADIO(0x09B) /* LO Calibration CVAL 4 */
+#define B2063_LO_CALIB_CVAL5			B43_LP_RADIO(0x09C) /* LO Calibration CVAL 5 */
+#define B2063_LO_CALIB_CVAL6			B43_LP_RADIO(0x09D) /* LO Calibration CVAL 6 */
+#define B2063_LO_CALIB_CVAL7			B43_LP_RADIO(0x09E) /* LO Calibration CVAL 7 */
+#define B2063_LOGEN_CALIB_EN			B43_LP_RADIO(0x09F) /* LOGEN Calibration EN */
+#define B2063_LOGEN_PEAKDET1			B43_LP_RADIO(0x0A0) /* LOGEN PEAKDET 1 */
+#define B2063_LOGEN_RCCR1			B43_LP_RADIO(0x0A1) /* LOGEN RCCR 1 */
+#define B2063_LOGEN_VCOBUF1			B43_LP_RADIO(0x0A2) /* LOGEN VCOBUF 1 */
+#define B2063_LOGEN_MIXER1			B43_LP_RADIO(0x0A3) /* LOGEN MIXER 1 */
+#define B2063_LOGEN_MIXER2			B43_LP_RADIO(0x0A4) /* LOGEN MIXER 2 */
+#define B2063_LOGEN_BUF1			B43_LP_RADIO(0x0A5) /* LOGEN BUF 1 */
+#define B2063_LOGEN_BUF2			B43_LP_RADIO(0x0A6) /* LOGEN BUF 2 */
+#define B2063_LOGEN_DIV1			B43_LP_RADIO(0x0A7) /* LOGEN DIV 1 */
+#define B2063_LOGEN_DIV2			B43_LP_RADIO(0x0A8) /* LOGEN DIV 2 */
+#define B2063_LOGEN_DIV3			B43_LP_RADIO(0x0A9) /* LOGEN DIV 3 */
+#define B2063_LOGEN_CBUFRX1			B43_LP_RADIO(0x0AA) /* LOGEN CBUFRX 1 */
+#define B2063_LOGEN_CBUFRX2			B43_LP_RADIO(0x0AB) /* LOGEN CBUFRX 2 */
+#define B2063_LOGEN_CBUFTX1			B43_LP_RADIO(0x0AC) /* LOGEN CBUFTX 1 */
+#define B2063_LOGEN_CBUFTX2			B43_LP_RADIO(0x0AD) /* LOGEN CBUFTX 2 */
+#define B2063_LOGEN_IDAC1			B43_LP_RADIO(0x0AE) /* LOGEN IDAC 1 */
+#define B2063_LOGEN_SPARE1			B43_LP_RADIO(0x0AF) /* LOGEN SPARE 1 */
+#define B2063_LOGEN_SPARE2			B43_LP_RADIO(0x0B0) /* LOGEN SPARE 2 */
+#define B2063_LOGEN_SPARE3			B43_LP_RADIO(0x0B1) /* LOGEN SPARE 3 */
+#define B2063_G_RX_1ST1				B43_LP_RADIO(0x0B2) /* G RX 1ST 1 */
+#define B2063_G_RX_1ST2				B43_LP_RADIO(0x0B3) /* G RX 1ST 2 */
+#define B2063_G_RX_1ST3				B43_LP_RADIO(0x0B4) /* G RX 1ST 3 */
+#define B2063_G_RX_2ND1				B43_LP_RADIO(0x0B5) /* G RX 2ND 1 */
+#define B2063_G_RX_2ND2				B43_LP_RADIO(0x0B6) /* G RX 2ND 2 */
+#define B2063_G_RX_2ND3				B43_LP_RADIO(0x0B7) /* G RX 2ND 3 */
+#define B2063_G_RX_2ND4				B43_LP_RADIO(0x0B8) /* G RX 2ND 4 */
+#define B2063_G_RX_2ND5				B43_LP_RADIO(0x0B9) /* G RX 2ND 5 */
+#define B2063_G_RX_2ND6				B43_LP_RADIO(0x0BA) /* G RX 2ND 6 */
+#define B2063_G_RX_2ND7				B43_LP_RADIO(0x0BB) /* G RX 2ND 7 */
+#define B2063_G_RX_2ND8				B43_LP_RADIO(0x0BC) /* G RX 2ND 8 */
+#define B2063_G_RX_PS1				B43_LP_RADIO(0x0BD) /* G RX PS 1 */
+#define B2063_G_RX_PS2				B43_LP_RADIO(0x0BE) /* G RX PS 2 */
+#define B2063_G_RX_PS3				B43_LP_RADIO(0x0BF) /* G RX PS 3 */
+#define B2063_G_RX_PS4				B43_LP_RADIO(0x0C0) /* G RX PS 4 */
+#define B2063_G_RX_PS5				B43_LP_RADIO(0x0C1) /* G RX PS 5 */
+#define B2063_G_RX_MIX1				B43_LP_RADIO(0x0C2) /* G RX MIX 1 */
+#define B2063_G_RX_MIX2				B43_LP_RADIO(0x0C3) /* G RX MIX 2 */
+#define B2063_G_RX_MIX3				B43_LP_RADIO(0x0C4) /* G RX MIX 3 */
+#define B2063_G_RX_MIX4				B43_LP_RADIO(0x0C5) /* G RX MIX 4 */
+#define B2063_G_RX_MIX5				B43_LP_RADIO(0x0C6) /* G RX MIX 5 */
+#define B2063_G_RX_MIX6				B43_LP_RADIO(0x0C7) /* G RX MIX 6 */
+#define B2063_G_RX_MIX7				B43_LP_RADIO(0x0C8) /* G RX MIX 7 */
+#define B2063_G_RX_MIX8				B43_LP_RADIO(0x0C9) /* G RX MIX 8 */
+#define B2063_G_RX_PDET1			B43_LP_RADIO(0x0CA) /* G RX PDET 1 */
+#define B2063_G_RX_SPARES1			B43_LP_RADIO(0x0CB) /* G RX SPARES 1 */
+#define B2063_G_RX_SPARES2			B43_LP_RADIO(0x0CC) /* G RX SPARES 2 */
+#define B2063_G_RX_SPARES3			B43_LP_RADIO(0x0CD) /* G RX SPARES 3 */
+#define B2063_A_RX_1ST1				B43_LP_RADIO(0x0CE) /* A RX 1ST 1 */
+#define B2063_A_RX_1ST2				B43_LP_RADIO(0x0CF) /* A RX 1ST 2 */
+#define B2063_A_RX_1ST3				B43_LP_RADIO(0x0D0) /* A RX 1ST 3 */
+#define B2063_A_RX_1ST4				B43_LP_RADIO(0x0D1) /* A RX 1ST 4 */
+#define B2063_A_RX_1ST5				B43_LP_RADIO(0x0D2) /* A RX 1ST 5 */
+#define B2063_A_RX_2ND1				B43_LP_RADIO(0x0D3) /* A RX 2ND 1 */
+#define B2063_A_RX_2ND2				B43_LP_RADIO(0x0D4) /* A RX 2ND 2 */
+#define B2063_A_RX_2ND3				B43_LP_RADIO(0x0D5) /* A RX 2ND 3 */
+#define B2063_A_RX_2ND4				B43_LP_RADIO(0x0D6) /* A RX 2ND 4 */
+#define B2063_A_RX_2ND5				B43_LP_RADIO(0x0D7) /* A RX 2ND 5 */
+#define B2063_A_RX_2ND6				B43_LP_RADIO(0x0D8) /* A RX 2ND 6 */
+#define B2063_A_RX_2ND7				B43_LP_RADIO(0x0D9) /* A RX 2ND 7 */
+#define B2063_A_RX_PS1				B43_LP_RADIO(0x0DA) /* A RX PS 1 */
+#define B2063_A_RX_PS2				B43_LP_RADIO(0x0DB) /* A RX PS 2 */
+#define B2063_A_RX_PS3				B43_LP_RADIO(0x0DC) /* A RX PS 3 */
+#define B2063_A_RX_PS4				B43_LP_RADIO(0x0DD) /* A RX PS 4 */
+#define B2063_A_RX_PS5				B43_LP_RADIO(0x0DE) /* A RX PS 5 */
+#define B2063_A_RX_PS6				B43_LP_RADIO(0x0DF) /* A RX PS 6 */
+#define B2063_A_RX_MIX1				B43_LP_RADIO(0x0E0) /* A RX MIX 1 */
+#define B2063_A_RX_MIX2				B43_LP_RADIO(0x0E1) /* A RX MIX 2 */
+#define B2063_A_RX_MIX3				B43_LP_RADIO(0x0E2) /* A RX MIX 3 */
+#define B2063_A_RX_MIX4				B43_LP_RADIO(0x0E3) /* A RX MIX 4 */
+#define B2063_A_RX_MIX5				B43_LP_RADIO(0x0E4) /* A RX MIX 5 */
+#define B2063_A_RX_MIX6				B43_LP_RADIO(0x0E5) /* A RX MIX 6 */
+#define B2063_A_RX_MIX7				B43_LP_RADIO(0x0E6) /* A RX MIX 7 */
+#define B2063_A_RX_MIX8				B43_LP_RADIO(0x0E7) /* A RX MIX 8 */
+#define B2063_A_RX_PWRDET1			B43_LP_RADIO(0x0E8) /* A RX PWRDET 1 */
+#define B2063_A_RX_SPARE1			B43_LP_RADIO(0x0E9) /* A RX SPARE 1 */
+#define B2063_A_RX_SPARE2			B43_LP_RADIO(0x0EA) /* A RX SPARE 2 */
+#define B2063_A_RX_SPARE3			B43_LP_RADIO(0x0EB) /* A RX SPARE 3 */
+#define B2063_RX_TIA_CTL1			B43_LP_RADIO(0x0EC) /* RX TIA Control 1 */
+#define B2063_RX_TIA_CTL2			B43_LP_RADIO(0x0ED) /* RX TIA Control 2 */
+#define B2063_RX_TIA_CTL3			B43_LP_RADIO(0x0EE) /* RX TIA Control 3 */
+#define B2063_RX_TIA_CTL4			B43_LP_RADIO(0x0EF) /* RX TIA Control 4 */
+#define B2063_RX_TIA_CTL5			B43_LP_RADIO(0x0F0) /* RX TIA Control 5 */
+#define B2063_RX_TIA_CTL6			B43_LP_RADIO(0x0F1) /* RX TIA Control 6 */
+#define B2063_RX_BB_CTL1			B43_LP_RADIO(0x0F2) /* RX BB Control 1 */
+#define B2063_RX_BB_CTL2			B43_LP_RADIO(0x0F3) /* RX BB Control 2 */
+#define B2063_RX_BB_CTL3			B43_LP_RADIO(0x0F4) /* RX BB Control 3 */
+#define B2063_RX_BB_CTL4			B43_LP_RADIO(0x0F5) /* RX BB Control 4 */
+#define B2063_RX_BB_CTL5			B43_LP_RADIO(0x0F6) /* RX BB Control 5 */
+#define B2063_RX_BB_CTL6			B43_LP_RADIO(0x0F7) /* RX BB Control 6 */
+#define B2063_RX_BB_CTL7			B43_LP_RADIO(0x0F8) /* RX BB Control 7 */
+#define B2063_RX_BB_CTL8			B43_LP_RADIO(0x0F9) /* RX BB Control 8 */
+#define B2063_RX_BB_CTL9			B43_LP_RADIO(0x0FA) /* RX BB Control 9 */
+#define B2063_TX_RF_CTL1			B43_LP_RADIO(0x0FB) /* TX RF Control 1 */
+#define B2063_TX_RF_IDAC_LO_RF_I		B43_LP_RADIO(0x0FC) /* TX RF IDAC LO RF I */
+#define B2063_TX_RF_IDAC_LO_RF_Q		B43_LP_RADIO(0x0FD) /* TX RF IDAC LO RF Q */
+#define B2063_TX_RF_IDAC_LO_BB_I		B43_LP_RADIO(0x0FE) /* TX RF IDAC LO BB I */
+#define B2063_TX_RF_IDAC_LO_BB_Q		B43_LP_RADIO(0x0FF) /* TX RF IDAC LO BB Q */
+#define B2063_TX_RF_CTL2			B43_LP_RADIO(0x100) /* TX RF Control 2 */
+#define B2063_TX_RF_CTL3			B43_LP_RADIO(0x101) /* TX RF Control 3 */
+#define B2063_TX_RF_CTL4			B43_LP_RADIO(0x102) /* TX RF Control 4 */
+#define B2063_TX_RF_CTL5			B43_LP_RADIO(0x103) /* TX RF Control 5 */
+#define B2063_TX_RF_CTL6			B43_LP_RADIO(0x104) /* TX RF Control 6 */
+#define B2063_TX_RF_CTL7			B43_LP_RADIO(0x105) /* TX RF Control 7 */
+#define B2063_TX_RF_CTL8			B43_LP_RADIO(0x106) /* TX RF Control 8 */
+#define B2063_TX_RF_CTL9			B43_LP_RADIO(0x107) /* TX RF Control 9 */
+#define B2063_TX_RF_CTL10			B43_LP_RADIO(0x108) /* TX RF Control 10 */
+#define B2063_TX_RF_CTL14			B43_LP_RADIO(0x109) /* TX RF Control 14 */
+#define B2063_TX_RF_CTL15			B43_LP_RADIO(0x10A) /* TX RF Control 15 */
+#define B2063_PA_CTL1				B43_LP_RADIO(0x10B) /* PA Control 1 */
+#define B2063_PA_CTL2				B43_LP_RADIO(0x10C) /* PA Control 2 */
+#define B2063_PA_CTL3				B43_LP_RADIO(0x10D) /* PA Control 3 */
+#define B2063_PA_CTL4				B43_LP_RADIO(0x10E) /* PA Control 4 */
+#define B2063_PA_CTL5				B43_LP_RADIO(0x10F) /* PA Control 5 */
+#define B2063_PA_CTL6				B43_LP_RADIO(0x110) /* PA Control 6 */
+#define B2063_PA_CTL7				B43_LP_RADIO(0x111) /* PA Control 7 */
+#define B2063_PA_CTL8				B43_LP_RADIO(0x112) /* PA Control 8 */
+#define B2063_PA_CTL9				B43_LP_RADIO(0x113) /* PA Control 9 */
+#define B2063_PA_CTL10				B43_LP_RADIO(0x114) /* PA Control 10 */
+#define B2063_PA_CTL11				B43_LP_RADIO(0x115) /* PA Control 11 */
+#define B2063_PA_CTL12				B43_LP_RADIO(0x116) /* PA Control 12 */
+#define B2063_PA_CTL13				B43_LP_RADIO(0x117) /* PA Control 13 */
+#define B2063_TX_BB_CTL1			B43_LP_RADIO(0x118) /* TX BB Control 1 */
+#define B2063_TX_BB_CTL2			B43_LP_RADIO(0x119) /* TX BB Control 2 */
+#define B2063_TX_BB_CTL3			B43_LP_RADIO(0x11A) /* TX BB Control 3 */
+#define B2063_TX_BB_CTL4			B43_LP_RADIO(0x11B) /* TX BB Control 4 */
+#define B2063_GPIO_CTL1				B43_LP_RADIO(0x11C) /* GPIO Control 1 */
+#define B2063_VREG_CTL1				B43_LP_RADIO(0x11D) /* VREG Control 1 */
+#define B2063_AMUX_CTL1				B43_LP_RADIO(0x11E) /* AMUX Control 1 */
+#define B2063_IQ_CALIB_GVAR			B43_LP_RADIO(0x11F) /* IQ Calibration GVAR */
+#define B2063_IQ_CALIB_CTL1			B43_LP_RADIO(0x120) /* IQ Calibration Control 1 */
+#define B2063_IQ_CALIB_CTL2			B43_LP_RADIO(0x121) /* IQ Calibration Control 2 */
+#define B2063_TEMPSENSE_CTL1			B43_LP_RADIO(0x122) /* TEMPSENSE Control 1 */
+#define B2063_TEMPSENSE_CTL2			B43_LP_RADIO(0x123) /* TEMPSENSE Control 2 */
+#define B2063_TX_RX_LOOPBACK1			B43_LP_RADIO(0x124) /* TX/RX LOOPBACK 1 */
+#define B2063_TX_RX_LOOPBACK2			B43_LP_RADIO(0x125) /* TX/RX LOOPBACK 2 */
+#define B2063_EXT_TSSI_CTL1			B43_LP_RADIO(0x126) /* EXT TSSI Control 1 */
+#define B2063_EXT_TSSI_CTL2			B43_LP_RADIO(0x127) /* EXT TSSI Control 2 */
+#define B2063_AFE_CTL				B43_LP_RADIO(0x128) /* AFE Control */
+
+
+
+struct b43_phy_lp {
+	//TODO
+};
+
+
+struct b43_phy_operations;
+extern const struct b43_phy_operations b43_phyops_lp;
+
+#endif /* LINUX_B43_PHY_LP_H_ */
diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c
new file mode 100644
index 0000000..8bcfda5
--- /dev/null
+++ b/drivers/net/wireless/b43/phy_n.c
@@ -0,0 +1,628 @@
+/*
+
+  Broadcom B43 wireless driver
+  IEEE 802.11n PHY support
+
+  Copyright (c) 2008 Michael Buesch <mb@bu3sch.de>
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; see the file COPYING.  If not, write to
+  the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+
+*/
+
+#include <linux/delay.h>
+#include <linux/types.h>
+
+#include "b43.h"
+#include "phy_n.h"
+#include "tables_nphy.h"
+
+
+void b43_nphy_set_rxantenna(struct b43_wldev *dev, int antenna)
+{//TODO
+}
+
+static void b43_nphy_op_adjust_txpower(struct b43_wldev *dev)
+{//TODO
+}
+
+static enum b43_txpwr_result b43_nphy_op_recalc_txpower(struct b43_wldev *dev,
+							bool ignore_tssi)
+{//TODO
+	return B43_TXPWR_RES_DONE;
+}
+
+static void b43_chantab_radio_upload(struct b43_wldev *dev,
+				     const struct b43_nphy_channeltab_entry *e)
+{
+	b43_radio_write16(dev, B2055_PLL_REF, e->radio_pll_ref);
+	b43_radio_write16(dev, B2055_RF_PLLMOD0, e->radio_rf_pllmod0);
+	b43_radio_write16(dev, B2055_RF_PLLMOD1, e->radio_rf_pllmod1);
+	b43_radio_write16(dev, B2055_VCO_CAPTAIL, e->radio_vco_captail);
+	b43_radio_write16(dev, B2055_VCO_CAL1, e->radio_vco_cal1);
+	b43_radio_write16(dev, B2055_VCO_CAL2, e->radio_vco_cal2);
+	b43_radio_write16(dev, B2055_PLL_LFC1, e->radio_pll_lfc1);
+	b43_radio_write16(dev, B2055_PLL_LFR1, e->radio_pll_lfr1);
+	b43_radio_write16(dev, B2055_PLL_LFC2, e->radio_pll_lfc2);
+	b43_radio_write16(dev, B2055_LGBUF_CENBUF, e->radio_lgbuf_cenbuf);
+	b43_radio_write16(dev, B2055_LGEN_TUNE1, e->radio_lgen_tune1);
+	b43_radio_write16(dev, B2055_LGEN_TUNE2, e->radio_lgen_tune2);
+	b43_radio_write16(dev, B2055_C1_LGBUF_ATUNE, e->radio_c1_lgbuf_atune);
+	b43_radio_write16(dev, B2055_C1_LGBUF_GTUNE, e->radio_c1_lgbuf_gtune);
+	b43_radio_write16(dev, B2055_C1_RX_RFR1, e->radio_c1_rx_rfr1);
+	b43_radio_write16(dev, B2055_C1_TX_PGAPADTN, e->radio_c1_tx_pgapadtn);
+	b43_radio_write16(dev, B2055_C1_TX_MXBGTRIM, e->radio_c1_tx_mxbgtrim);
+	b43_radio_write16(dev, B2055_C2_LGBUF_ATUNE, e->radio_c2_lgbuf_atune);
+	b43_radio_write16(dev, B2055_C2_LGBUF_GTUNE, e->radio_c2_lgbuf_gtune);
+	b43_radio_write16(dev, B2055_C2_RX_RFR1, e->radio_c2_rx_rfr1);
+	b43_radio_write16(dev, B2055_C2_TX_PGAPADTN, e->radio_c2_tx_pgapadtn);
+	b43_radio_write16(dev, B2055_C2_TX_MXBGTRIM, e->radio_c2_tx_mxbgtrim);
+}
+
+static void b43_chantab_phy_upload(struct b43_wldev *dev,
+				   const struct b43_nphy_channeltab_entry *e)
+{
+	b43_phy_write(dev, B43_NPHY_BW1A, e->phy_bw1a);
+	b43_phy_write(dev, B43_NPHY_BW2, e->phy_bw2);
+	b43_phy_write(dev, B43_NPHY_BW3, e->phy_bw3);
+	b43_phy_write(dev, B43_NPHY_BW4, e->phy_bw4);
+	b43_phy_write(dev, B43_NPHY_BW5, e->phy_bw5);
+	b43_phy_write(dev, B43_NPHY_BW6, e->phy_bw6);
+}
+
+static void b43_nphy_tx_power_fix(struct b43_wldev *dev)
+{
+	//TODO
+}
+
+/* Tune the hardware to a new channel. */
+static int nphy_channel_switch(struct b43_wldev *dev, unsigned int channel)
+{
+	const struct b43_nphy_channeltab_entry *tabent;
+
+	tabent = b43_nphy_get_chantabent(dev, channel);
+	if (!tabent)
+		return -ESRCH;
+
+	//FIXME enable/disable band select upper20 in RXCTL
+	if (0 /*FIXME 5Ghz*/)
+		b43_radio_maskset(dev, B2055_MASTER1, 0xFF8F, 0x20);
+	else
+		b43_radio_maskset(dev, B2055_MASTER1, 0xFF8F, 0x50);
+	b43_chantab_radio_upload(dev, tabent);
+	udelay(50);
+	b43_radio_write16(dev, B2055_VCO_CAL10, 5);
+	b43_radio_write16(dev, B2055_VCO_CAL10, 45);
+	b43_radio_write16(dev, B2055_VCO_CAL10, 65);
+	udelay(300);
+	if (0 /*FIXME 5Ghz*/)
+		b43_phy_set(dev, B43_NPHY_BANDCTL, B43_NPHY_BANDCTL_5GHZ);
+	else
+		b43_phy_mask(dev, B43_NPHY_BANDCTL, ~B43_NPHY_BANDCTL_5GHZ);
+	b43_chantab_phy_upload(dev, tabent);
+	b43_nphy_tx_power_fix(dev);
+
+	return 0;
+}
+
+static void b43_radio_init2055_pre(struct b43_wldev *dev)
+{
+	b43_phy_mask(dev, B43_NPHY_RFCTL_CMD,
+		     ~B43_NPHY_RFCTL_CMD_PORFORCE);
+	b43_phy_set(dev, B43_NPHY_RFCTL_CMD,
+		    B43_NPHY_RFCTL_CMD_CHIP0PU |
+		    B43_NPHY_RFCTL_CMD_OEPORFORCE);
+	b43_phy_set(dev, B43_NPHY_RFCTL_CMD,
+		    B43_NPHY_RFCTL_CMD_PORFORCE);
+}
+
+static void b43_radio_init2055_post(struct b43_wldev *dev)
+{
+	struct ssb_sprom *sprom = &(dev->dev->bus->sprom);
+	struct ssb_boardinfo *binfo = &(dev->dev->bus->boardinfo);
+	int i;
+	u16 val;
+
+	b43_radio_mask(dev, B2055_MASTER1, 0xFFF3);
+	msleep(1);
+	if ((sprom->revision != 4) || !(sprom->boardflags_hi & 0x0002)) {
+		if ((binfo->vendor != PCI_VENDOR_ID_BROADCOM) ||
+		    (binfo->type != 0x46D) ||
+		    (binfo->rev < 0x41)) {
+			b43_radio_mask(dev, B2055_C1_RX_BB_REG, 0x7F);
+			b43_radio_mask(dev, B2055_C1_RX_BB_REG, 0x7F);
+			msleep(1);
+		}
+	}
+	b43_radio_maskset(dev, B2055_RRCCAL_NOPTSEL, 0x3F, 0x2C);
+	msleep(1);
+	b43_radio_write16(dev, B2055_CAL_MISC, 0x3C);
+	msleep(1);
+	b43_radio_mask(dev, B2055_CAL_MISC, 0xFFBE);
+	msleep(1);
+	b43_radio_set(dev, B2055_CAL_LPOCTL, 0x80);
+	msleep(1);
+	b43_radio_set(dev, B2055_CAL_MISC, 0x1);
+	msleep(1);
+	b43_radio_set(dev, B2055_CAL_MISC, 0x40);
+	msleep(1);
+	for (i = 0; i < 100; i++) {
+		val = b43_radio_read16(dev, B2055_CAL_COUT2);
+		if (val & 0x80)
+			break;
+		udelay(10);
+	}
+	msleep(1);
+	b43_radio_mask(dev, B2055_CAL_LPOCTL, 0xFF7F);
+	msleep(1);
+	nphy_channel_switch(dev, dev->phy.channel);
+	b43_radio_write16(dev, B2055_C1_RX_BB_LPF, 0x9);
+	b43_radio_write16(dev, B2055_C2_RX_BB_LPF, 0x9);
+	b43_radio_write16(dev, B2055_C1_RX_BB_MIDACHP, 0x83);
+	b43_radio_write16(dev, B2055_C2_RX_BB_MIDACHP, 0x83);
+}
+
+/* Initialize a Broadcom 2055 N-radio */
+static void b43_radio_init2055(struct b43_wldev *dev)
+{
+	b43_radio_init2055_pre(dev);
+	if (b43_status(dev) < B43_STAT_INITIALIZED)
+		b2055_upload_inittab(dev, 0, 1);
+	else
+		b2055_upload_inittab(dev, 0/*FIXME on 5ghz band*/, 0);
+	b43_radio_init2055_post(dev);
+}
+
+void b43_nphy_radio_turn_on(struct b43_wldev *dev)
+{
+	b43_radio_init2055(dev);
+}
+
+void b43_nphy_radio_turn_off(struct b43_wldev *dev)
+{
+	b43_phy_mask(dev, B43_NPHY_RFCTL_CMD,
+		     ~B43_NPHY_RFCTL_CMD_EN);
+}
+
+#define ntab_upload(dev, offset, data) do { \
+		unsigned int i;						\
+		for (i = 0; i < (offset##_SIZE); i++)			\
+			b43_ntab_write(dev, (offset) + i, (data)[i]);	\
+	} while (0)
+
+/* Upload the N-PHY tables. */
+static void b43_nphy_tables_init(struct b43_wldev *dev)
+{
+	/* Static tables */
+	ntab_upload(dev, B43_NTAB_FRAMESTRUCT, b43_ntab_framestruct);
+	ntab_upload(dev, B43_NTAB_FRAMELT, b43_ntab_framelookup);
+	ntab_upload(dev, B43_NTAB_TMAP, b43_ntab_tmap);
+	ntab_upload(dev, B43_NTAB_TDTRN, b43_ntab_tdtrn);
+	ntab_upload(dev, B43_NTAB_INTLEVEL, b43_ntab_intlevel);
+	ntab_upload(dev, B43_NTAB_PILOT, b43_ntab_pilot);
+	ntab_upload(dev, B43_NTAB_PILOTLT, b43_ntab_pilotlt);
+	ntab_upload(dev, B43_NTAB_TDI20A0, b43_ntab_tdi20a0);
+	ntab_upload(dev, B43_NTAB_TDI20A1, b43_ntab_tdi20a1);
+	ntab_upload(dev, B43_NTAB_TDI40A0, b43_ntab_tdi40a0);
+	ntab_upload(dev, B43_NTAB_TDI40A1, b43_ntab_tdi40a1);
+	ntab_upload(dev, B43_NTAB_BDI, b43_ntab_bdi);
+	ntab_upload(dev, B43_NTAB_CHANEST, b43_ntab_channelest);
+	ntab_upload(dev, B43_NTAB_MCS, b43_ntab_mcs);
+
+	/* Volatile tables */
+	ntab_upload(dev, B43_NTAB_NOISEVAR10, b43_ntab_noisevar10);
+	ntab_upload(dev, B43_NTAB_NOISEVAR11, b43_ntab_noisevar11);
+	ntab_upload(dev, B43_NTAB_C0_ESTPLT, b43_ntab_estimatepowerlt0);
+	ntab_upload(dev, B43_NTAB_C1_ESTPLT, b43_ntab_estimatepowerlt1);
+	ntab_upload(dev, B43_NTAB_C0_ADJPLT, b43_ntab_adjustpower0);
+	ntab_upload(dev, B43_NTAB_C1_ADJPLT, b43_ntab_adjustpower1);
+	ntab_upload(dev, B43_NTAB_C0_GAINCTL, b43_ntab_gainctl0);
+	ntab_upload(dev, B43_NTAB_C1_GAINCTL, b43_ntab_gainctl1);
+	ntab_upload(dev, B43_NTAB_C0_IQLT, b43_ntab_iqlt0);
+	ntab_upload(dev, B43_NTAB_C1_IQLT, b43_ntab_iqlt1);
+	ntab_upload(dev, B43_NTAB_C0_LOFEEDTH, b43_ntab_loftlt0);
+	ntab_upload(dev, B43_NTAB_C1_LOFEEDTH, b43_ntab_loftlt1);
+}
+
+static void b43_nphy_workarounds(struct b43_wldev *dev)
+{
+	struct b43_phy *phy = &dev->phy;
+	unsigned int i;
+
+	b43_phy_set(dev, B43_NPHY_IQFLIP,
+		    B43_NPHY_IQFLIP_ADC1 | B43_NPHY_IQFLIP_ADC2);
+	if (1 /* FIXME band is 2.4GHz */) {
+		b43_phy_set(dev, B43_NPHY_CLASSCTL,
+			    B43_NPHY_CLASSCTL_CCKEN);
+	} else {
+		b43_phy_mask(dev, B43_NPHY_CLASSCTL,
+			     ~B43_NPHY_CLASSCTL_CCKEN);
+	}
+	b43_radio_set(dev, B2055_C1_TX_RF_SPARE, 0x8);
+	b43_phy_write(dev, B43_NPHY_TXFRAMEDELAY, 8);
+
+	/* Fixup some tables */
+	b43_ntab_write(dev, B43_NTAB16(8, 0x00), 0xA);
+	b43_ntab_write(dev, B43_NTAB16(8, 0x10), 0xA);
+	b43_ntab_write(dev, B43_NTAB16(8, 0x02), 0xCDAA);
+	b43_ntab_write(dev, B43_NTAB16(8, 0x12), 0xCDAA);
+	b43_ntab_write(dev, B43_NTAB16(8, 0x08), 0);
+	b43_ntab_write(dev, B43_NTAB16(8, 0x18), 0);
+	b43_ntab_write(dev, B43_NTAB16(8, 0x07), 0x7AAB);
+	b43_ntab_write(dev, B43_NTAB16(8, 0x17), 0x7AAB);
+	b43_ntab_write(dev, B43_NTAB16(8, 0x06), 0x800);
+	b43_ntab_write(dev, B43_NTAB16(8, 0x16), 0x800);
+
+	b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_LO1, 0x2D8);
+	b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_UP1, 0x301);
+	b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_LO2, 0x2D8);
+	b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_UP2, 0x301);
+
+	//TODO set RF sequence
+
+	/* Set narrowband clip threshold */
+	b43_phy_write(dev, B43_NPHY_C1_NBCLIPTHRES, 66);
+	b43_phy_write(dev, B43_NPHY_C2_NBCLIPTHRES, 66);
+
+	/* Set wideband clip 2 threshold */
+	b43_phy_maskset(dev, B43_NPHY_C1_CLIPWBTHRES,
+			~B43_NPHY_C1_CLIPWBTHRES_CLIP2,
+			21 << B43_NPHY_C1_CLIPWBTHRES_CLIP2_SHIFT);
+	b43_phy_maskset(dev, B43_NPHY_C2_CLIPWBTHRES,
+			~B43_NPHY_C2_CLIPWBTHRES_CLIP2,
+			21 << B43_NPHY_C2_CLIPWBTHRES_CLIP2_SHIFT);
+
+	/* Set Clip 2 detect */
+	b43_phy_set(dev, B43_NPHY_C1_CGAINI,
+		    B43_NPHY_C1_CGAINI_CL2DETECT);
+	b43_phy_set(dev, B43_NPHY_C2_CGAINI,
+		    B43_NPHY_C2_CGAINI_CL2DETECT);
+
+	if (0 /*FIXME*/) {
+		/* Set dwell lengths */
+		b43_phy_write(dev, B43_NPHY_CLIP1_NBDWELL_LEN, 43);
+		b43_phy_write(dev, B43_NPHY_CLIP2_NBDWELL_LEN, 43);
+		b43_phy_write(dev, B43_NPHY_W1CLIP1_DWELL_LEN, 9);
+		b43_phy_write(dev, B43_NPHY_W1CLIP2_DWELL_LEN, 9);
+
+		/* Set gain backoff */
+		b43_phy_maskset(dev, B43_NPHY_C1_CGAINI,
+				~B43_NPHY_C1_CGAINI_GAINBKOFF,
+				1 << B43_NPHY_C1_CGAINI_GAINBKOFF_SHIFT);
+		b43_phy_maskset(dev, B43_NPHY_C2_CGAINI,
+				~B43_NPHY_C2_CGAINI_GAINBKOFF,
+				1 << B43_NPHY_C2_CGAINI_GAINBKOFF_SHIFT);
+
+		/* Set HPVGA2 index */
+		b43_phy_maskset(dev, B43_NPHY_C1_INITGAIN,
+				~B43_NPHY_C1_INITGAIN_HPVGA2,
+				6 << B43_NPHY_C1_INITGAIN_HPVGA2_SHIFT);
+		b43_phy_maskset(dev, B43_NPHY_C2_INITGAIN,
+				~B43_NPHY_C2_INITGAIN_HPVGA2,
+				6 << B43_NPHY_C2_INITGAIN_HPVGA2_SHIFT);
+
+		//FIXME verify that the specs really mean to use autoinc here.
+		for (i = 0; i < 3; i++)
+			b43_ntab_write(dev, B43_NTAB16(7, 0x106) + i, 0x673);
+	}
+
+	/* Set minimum gain value */
+	b43_phy_maskset(dev, B43_NPHY_C1_MINMAX_GAIN,
+			~B43_NPHY_C1_MINGAIN,
+			23 << B43_NPHY_C1_MINGAIN_SHIFT);
+	b43_phy_maskset(dev, B43_NPHY_C2_MINMAX_GAIN,
+			~B43_NPHY_C2_MINGAIN,
+			23 << B43_NPHY_C2_MINGAIN_SHIFT);
+
+	if (phy->rev < 2) {
+		b43_phy_mask(dev, B43_NPHY_SCRAM_SIGCTL,
+			     ~B43_NPHY_SCRAM_SIGCTL_SCM);
+	}
+
+	/* Set phase track alpha and beta */
+	b43_phy_write(dev, B43_NPHY_PHASETR_A0, 0x125);
+	b43_phy_write(dev, B43_NPHY_PHASETR_A1, 0x1B3);
+	b43_phy_write(dev, B43_NPHY_PHASETR_A2, 0x105);
+	b43_phy_write(dev, B43_NPHY_PHASETR_B0, 0x16E);
+	b43_phy_write(dev, B43_NPHY_PHASETR_B1, 0xCD);
+	b43_phy_write(dev, B43_NPHY_PHASETR_B2, 0x20);
+}
+
+static void b43_nphy_reset_cca(struct b43_wldev *dev)
+{
+	u16 bbcfg;
+
+	ssb_write32(dev->dev, SSB_TMSLOW,
+		    ssb_read32(dev->dev, SSB_TMSLOW) | SSB_TMSLOW_FGC);
+	bbcfg = b43_phy_read(dev, B43_NPHY_BBCFG);
+	b43_phy_set(dev, B43_NPHY_BBCFG, B43_NPHY_BBCFG_RSTCCA);
+	b43_phy_write(dev, B43_NPHY_BBCFG,
+		      bbcfg & ~B43_NPHY_BBCFG_RSTCCA);
+	ssb_write32(dev->dev, SSB_TMSLOW,
+		    ssb_read32(dev->dev, SSB_TMSLOW) & ~SSB_TMSLOW_FGC);
+}
+
+enum b43_nphy_rf_sequence {
+	B43_RFSEQ_RX2TX,
+	B43_RFSEQ_TX2RX,
+	B43_RFSEQ_RESET2RX,
+	B43_RFSEQ_UPDATE_GAINH,
+	B43_RFSEQ_UPDATE_GAINL,
+	B43_RFSEQ_UPDATE_GAINU,
+};
+
+static void b43_nphy_force_rf_sequence(struct b43_wldev *dev,
+				       enum b43_nphy_rf_sequence seq)
+{
+	static const u16 trigger[] = {
+		[B43_RFSEQ_RX2TX]		= B43_NPHY_RFSEQTR_RX2TX,
+		[B43_RFSEQ_TX2RX]		= B43_NPHY_RFSEQTR_TX2RX,
+		[B43_RFSEQ_RESET2RX]		= B43_NPHY_RFSEQTR_RST2RX,
+		[B43_RFSEQ_UPDATE_GAINH]	= B43_NPHY_RFSEQTR_UPGH,
+		[B43_RFSEQ_UPDATE_GAINL]	= B43_NPHY_RFSEQTR_UPGL,
+		[B43_RFSEQ_UPDATE_GAINU]	= B43_NPHY_RFSEQTR_UPGU,
+	};
+	int i;
+
+	B43_WARN_ON(seq >= ARRAY_SIZE(trigger));
+
+	b43_phy_set(dev, B43_NPHY_RFSEQMODE,
+		    B43_NPHY_RFSEQMODE_CAOVER | B43_NPHY_RFSEQMODE_TROVER);
+	b43_phy_set(dev, B43_NPHY_RFSEQTR, trigger[seq]);
+	for (i = 0; i < 200; i++) {
+		if (!(b43_phy_read(dev, B43_NPHY_RFSEQST) & trigger[seq]))
+			goto ok;
+		msleep(1);
+	}
+	b43err(dev->wl, "RF sequence status timeout\n");
+ok:
+	b43_phy_mask(dev, B43_NPHY_RFSEQMODE,
+		     ~(B43_NPHY_RFSEQMODE_CAOVER | B43_NPHY_RFSEQMODE_TROVER));
+}
+
+static void b43_nphy_bphy_init(struct b43_wldev *dev)
+{
+	unsigned int i;
+	u16 val;
+
+	val = 0x1E1F;
+	for (i = 0; i < 14; i++) {
+		b43_phy_write(dev, B43_PHY_N_BMODE(0x88 + i), val);
+		val -= 0x202;
+	}
+	val = 0x3E3F;
+	for (i = 0; i < 16; i++) {
+		b43_phy_write(dev, B43_PHY_N_BMODE(0x97 + i), val);
+		val -= 0x202;
+	}
+	b43_phy_write(dev, B43_PHY_N_BMODE(0x38), 0x668);
+}
+
+/* RSSI Calibration */
+static void b43_nphy_rssi_cal(struct b43_wldev *dev, u8 type)
+{
+	//TODO
+}
+
+int b43_phy_initn(struct b43_wldev *dev)
+{
+	struct b43_phy *phy = &dev->phy;
+	u16 tmp;
+
+	//TODO: Spectral management
+	b43_nphy_tables_init(dev);
+
+	/* Clear all overrides */
+	b43_phy_write(dev, B43_NPHY_RFCTL_OVER, 0);
+	b43_phy_write(dev, B43_NPHY_RFCTL_INTC1, 0);
+	b43_phy_write(dev, B43_NPHY_RFCTL_INTC2, 0);
+	b43_phy_write(dev, B43_NPHY_RFCTL_INTC3, 0);
+	b43_phy_write(dev, B43_NPHY_RFCTL_INTC4, 0);
+	b43_phy_mask(dev, B43_NPHY_RFSEQMODE,
+		     ~(B43_NPHY_RFSEQMODE_CAOVER |
+		       B43_NPHY_RFSEQMODE_TROVER));
+	b43_phy_write(dev, B43_NPHY_AFECTL_OVER, 0);
+
+	tmp = (phy->rev < 2) ? 64 : 59;
+	b43_phy_maskset(dev, B43_NPHY_BPHY_CTL3,
+			~B43_NPHY_BPHY_CTL3_SCALE,
+			tmp << B43_NPHY_BPHY_CTL3_SCALE_SHIFT);
+
+	b43_phy_write(dev, B43_NPHY_AFESEQ_TX2RX_PUD_20M, 0x20);
+	b43_phy_write(dev, B43_NPHY_AFESEQ_TX2RX_PUD_40M, 0x20);
+
+	b43_phy_write(dev, B43_NPHY_TXREALFD, 184);
+	b43_phy_write(dev, B43_NPHY_MIMO_CRSTXEXT, 200);
+	b43_phy_write(dev, B43_NPHY_PLOAD_CSENSE_EXTLEN, 80);
+	b43_phy_write(dev, B43_NPHY_C2_BCLIPBKOFF, 511);
+
+	//TODO MIMO-Config
+	//TODO Update TX/RX chain
+
+	if (phy->rev < 2) {
+		b43_phy_write(dev, B43_NPHY_DUP40_GFBL, 0xAA8);
+		b43_phy_write(dev, B43_NPHY_DUP40_BL, 0x9A4);
+	}
+	b43_nphy_workarounds(dev);
+	b43_nphy_reset_cca(dev);
+
+	ssb_write32(dev->dev, SSB_TMSLOW,
+		    ssb_read32(dev->dev, SSB_TMSLOW) | B43_TMSLOW_MACPHYCLKEN);
+	b43_nphy_force_rf_sequence(dev, B43_RFSEQ_RX2TX);
+	b43_nphy_force_rf_sequence(dev, B43_RFSEQ_RESET2RX);
+
+	b43_phy_read(dev, B43_NPHY_CLASSCTL); /* dummy read */
+	//TODO read core1/2 clip1 thres regs
+
+	if (1 /* FIXME Band is 2.4GHz */)
+		b43_nphy_bphy_init(dev);
+	//TODO disable TX power control
+	//TODO Fix the TX power settings
+	//TODO Init periodic calibration with reason 3
+	b43_nphy_rssi_cal(dev, 2);
+	b43_nphy_rssi_cal(dev, 0);
+	b43_nphy_rssi_cal(dev, 1);
+	//TODO get TX gain
+	//TODO init superswitch
+	//TODO calibrate LO
+	//TODO idle TSSI TX pctl
+	//TODO TX power control power setup
+	//TODO table writes
+	//TODO TX power control coefficients
+	//TODO enable TX power control
+	//TODO control antenna selection
+	//TODO init radar detection
+	//TODO reset channel if changed
+
+	b43err(dev->wl, "IEEE 802.11n devices are not supported, yet.\n");
+	return 0;
+}
+
+static int b43_nphy_op_allocate(struct b43_wldev *dev)
+{
+	struct b43_phy_n *nphy;
+
+	nphy = kzalloc(sizeof(*nphy), GFP_KERNEL);
+	if (!nphy)
+		return -ENOMEM;
+	dev->phy.n = nphy;
+
+	return 0;
+}
+
+static void b43_nphy_op_prepare_structs(struct b43_wldev *dev)
+{
+	struct b43_phy *phy = &dev->phy;
+	struct b43_phy_n *nphy = phy->n;
+
+	memset(nphy, 0, sizeof(*nphy));
+
+	//TODO init struct b43_phy_n
+}
+
+static void b43_nphy_op_free(struct b43_wldev *dev)
+{
+	struct b43_phy *phy = &dev->phy;
+	struct b43_phy_n *nphy = phy->n;
+
+	kfree(nphy);
+	phy->n = NULL;
+}
+
+static int b43_nphy_op_init(struct b43_wldev *dev)
+{
+	return b43_phy_initn(dev);
+}
+
+static inline void check_phyreg(struct b43_wldev *dev, u16 offset)
+{
+#if B43_DEBUG
+	if ((offset & B43_PHYROUTE) == B43_PHYROUTE_OFDM_GPHY) {
+		/* OFDM registers are onnly available on A/G-PHYs */
+		b43err(dev->wl, "Invalid OFDM PHY access at "
+		       "0x%04X on N-PHY\n", offset);
+		dump_stack();
+	}
+	if ((offset & B43_PHYROUTE) == B43_PHYROUTE_EXT_GPHY) {
+		/* Ext-G registers are only available on G-PHYs */
+		b43err(dev->wl, "Invalid EXT-G PHY access at "
+		       "0x%04X on N-PHY\n", offset);
+		dump_stack();
+	}
+#endif /* B43_DEBUG */
+}
+
+static u16 b43_nphy_op_read(struct b43_wldev *dev, u16 reg)
+{
+	check_phyreg(dev, reg);
+	b43_write16(dev, B43_MMIO_PHY_CONTROL, reg);
+	return b43_read16(dev, B43_MMIO_PHY_DATA);
+}
+
+static void b43_nphy_op_write(struct b43_wldev *dev, u16 reg, u16 value)
+{
+	check_phyreg(dev, reg);
+	b43_write16(dev, B43_MMIO_PHY_CONTROL, reg);
+	b43_write16(dev, B43_MMIO_PHY_DATA, value);
+}
+
+static u16 b43_nphy_op_radio_read(struct b43_wldev *dev, u16 reg)
+{
+	/* Register 1 is a 32-bit register. */
+	B43_WARN_ON(reg == 1);
+	/* N-PHY needs 0x100 for read access */
+	reg |= 0x100;
+
+	b43_write16(dev, B43_MMIO_RADIO_CONTROL, reg);
+	return b43_read16(dev, B43_MMIO_RADIO_DATA_LOW);
+}
+
+static void b43_nphy_op_radio_write(struct b43_wldev *dev, u16 reg, u16 value)
+{
+	/* Register 1 is a 32-bit register. */
+	B43_WARN_ON(reg == 1);
+
+	b43_write16(dev, B43_MMIO_RADIO_CONTROL, reg);
+	b43_write16(dev, B43_MMIO_RADIO_DATA_LOW, value);
+}
+
+static void b43_nphy_op_software_rfkill(struct b43_wldev *dev,
+					enum rfkill_state state)
+{//TODO
+}
+
+static void b43_nphy_op_switch_analog(struct b43_wldev *dev, bool on)
+{
+	b43_phy_write(dev, B43_NPHY_AFECTL_OVER,
+		      on ? 0 : 0x7FFF);
+}
+
+static int b43_nphy_op_switch_channel(struct b43_wldev *dev,
+				      unsigned int new_channel)
+{
+	if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) {
+		if ((new_channel < 1) || (new_channel > 14))
+			return -EINVAL;
+	} else {
+		if (new_channel > 200)
+			return -EINVAL;
+	}
+
+	return nphy_channel_switch(dev, new_channel);
+}
+
+static unsigned int b43_nphy_op_get_default_chan(struct b43_wldev *dev)
+{
+	if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ)
+		return 1;
+	return 36;
+}
+
+const struct b43_phy_operations b43_phyops_n = {
+	.allocate		= b43_nphy_op_allocate,
+	.free			= b43_nphy_op_free,
+	.prepare_structs	= b43_nphy_op_prepare_structs,
+	.init			= b43_nphy_op_init,
+	.phy_read		= b43_nphy_op_read,
+	.phy_write		= b43_nphy_op_write,
+	.radio_read		= b43_nphy_op_radio_read,
+	.radio_write		= b43_nphy_op_radio_write,
+	.software_rfkill	= b43_nphy_op_software_rfkill,
+	.switch_analog		= b43_nphy_op_switch_analog,
+	.switch_channel		= b43_nphy_op_switch_channel,
+	.get_default_chan	= b43_nphy_op_get_default_chan,
+	.recalc_txpower		= b43_nphy_op_recalc_txpower,
+	.adjust_txpower		= b43_nphy_op_adjust_txpower,
+};
diff --git a/drivers/net/wireless/b43/phy_n.h b/drivers/net/wireless/b43/phy_n.h
new file mode 100644
index 0000000..1749aef
--- /dev/null
+++ b/drivers/net/wireless/b43/phy_n.h
@@ -0,0 +1,930 @@
+#ifndef B43_NPHY_H_
+#define B43_NPHY_H_
+
+#include "phy_common.h"
+
+
+/* N-PHY registers. */
+
+#define B43_NPHY_BBCFG				B43_PHY_N(0x001) /* BB config */
+#define  B43_NPHY_BBCFG_RSTCCA			0x4000 /* Reset CCA */
+#define  B43_NPHY_BBCFG_RSTRX			0x8000 /* Reset RX */
+#define B43_NPHY_CHANNEL			B43_PHY_N(0x005) /* Channel */
+#define B43_NPHY_TXERR				B43_PHY_N(0x007) /* TX error */
+#define B43_NPHY_BANDCTL			B43_PHY_N(0x009) /* Band control */
+#define  B43_NPHY_BANDCTL_5GHZ			0x0001 /* Use the 5GHz band */
+#define B43_NPHY_4WI_ADDR			B43_PHY_N(0x00B) /* Four-wire bus address */
+#define B43_NPHY_4WI_DATAHI			B43_PHY_N(0x00C) /* Four-wire bus data high */
+#define B43_NPHY_4WI_DATALO			B43_PHY_N(0x00D) /* Four-wire bus data low */
+#define B43_NPHY_BIST_STAT0			B43_PHY_N(0x00E) /* Built-in self test status 0 */
+#define B43_NPHY_BIST_STAT1			B43_PHY_N(0x00F) /* Built-in self test status 1 */
+
+#define B43_NPHY_C1_DESPWR			B43_PHY_N(0x018) /* Core 1 desired power */
+#define B43_NPHY_C1_CCK_DESPWR			B43_PHY_N(0x019) /* Core 1 CCK desired power */
+#define B43_NPHY_C1_BCLIPBKOFF			B43_PHY_N(0x01A) /* Core 1 barely clip backoff */
+#define B43_NPHY_C1_CCK_BCLIPBKOFF		B43_PHY_N(0x01B) /* Core 1 CCK barely clip backoff */
+#define B43_NPHY_C1_CGAINI			B43_PHY_N(0x01C) /* Core 1 compute gain info */
+#define  B43_NPHY_C1_CGAINI_GAINBKOFF		0x001F /* Gain backoff */
+#define  B43_NPHY_C1_CGAINI_GAINBKOFF_SHIFT	0
+#define  B43_NPHY_C1_CGAINI_CLIPGBKOFF		0x03E0 /* Clip gain backoff */
+#define  B43_NPHY_C1_CGAINI_CLIPGBKOFF_SHIFT	5
+#define  B43_NPHY_C1_CGAINI_GAINSTEP		0x1C00 /* Gain step */
+#define  B43_NPHY_C1_CGAINI_GAINSTEP_SHIFT	10
+#define  B43_NPHY_C1_CGAINI_CL2DETECT		0x2000 /* Clip 2 detect mask */
+#define B43_NPHY_C1_CCK_CGAINI			B43_PHY_N(0x01D) /* Core 1 CCK compute gain info */
+#define  B43_NPHY_C1_CCK_CGAINI_GAINBKOFF	0x001F /* Gain backoff */
+#define  B43_NPHY_C1_CCK_CGAINI_CLIPGBKOFF	0x01E0 /* CCK barely clip gain backoff */
+#define B43_NPHY_C1_MINMAX_GAIN			B43_PHY_N(0x01E) /* Core 1 min/max gain */
+#define  B43_NPHY_C1_MINGAIN			0x00FF /* Minimum gain */
+#define  B43_NPHY_C1_MINGAIN_SHIFT		0
+#define  B43_NPHY_C1_MAXGAIN			0xFF00 /* Maximum gain */
+#define  B43_NPHY_C1_MAXGAIN_SHIFT		8
+#define B43_NPHY_C1_CCK_MINMAX_GAIN		B43_PHY_N(0x01F) /* Core 1 CCK min/max gain */
+#define  B43_NPHY_C1_CCK_MINGAIN		0x00FF /* Minimum gain */
+#define  B43_NPHY_C1_CCK_MINGAIN_SHIFT		0
+#define  B43_NPHY_C1_CCK_MAXGAIN		0xFF00 /* Maximum gain */
+#define  B43_NPHY_C1_CCK_MAXGAIN_SHIFT		8
+#define B43_NPHY_C1_INITGAIN			B43_PHY_N(0x020) /* Core 1 initial gain code */
+#define  B43_NPHY_C1_INITGAIN_EXTLNA		0x0001 /* External LNA index */
+#define  B43_NPHY_C1_INITGAIN_LNA		0x0006 /* LNA index */
+#define  B43_NPHY_C1_INITGAIN_LNAIDX_SHIFT	1
+#define  B43_NPHY_C1_INITGAIN_HPVGA1		0x0078 /* HPVGA1 index */
+#define  B43_NPHY_C1_INITGAIN_HPVGA1_SHIFT	3
+#define  B43_NPHY_C1_INITGAIN_HPVGA2		0x0F80 /* HPVGA2 index */
+#define  B43_NPHY_C1_INITGAIN_HPVGA2_SHIFT	7
+#define  B43_NPHY_C1_INITGAIN_TRRX		0x1000 /* TR RX index */
+#define  B43_NPHY_C1_INITGAIN_TRTX		0x2000 /* TR TX index */
+#define B43_NPHY_C1_CLIP1_HIGAIN		B43_PHY_N(0x021) /* Core 1 clip1 high gain code */
+#define B43_NPHY_C1_CLIP1_MEDGAIN		B43_PHY_N(0x022) /* Core 1 clip1 medium gain code */
+#define B43_NPHY_C1_CLIP1_LOGAIN		B43_PHY_N(0x023) /* Core 1 clip1 low gain code */
+#define B43_NPHY_C1_CLIP2_GAIN			B43_PHY_N(0x024) /* Core 1 clip2 gain code */
+#define B43_NPHY_C1_FILTERGAIN			B43_PHY_N(0x025) /* Core 1 filter gain */
+#define B43_NPHY_C1_LPF_QHPF_BW			B43_PHY_N(0x026) /* Core 1 LPF Q HP F bandwidth */
+#define B43_NPHY_C1_CLIPWBTHRES			B43_PHY_N(0x027) /* Core 1 clip wideband threshold */
+#define  B43_NPHY_C1_CLIPWBTHRES_CLIP2		0x003F /* Clip 2 */
+#define  B43_NPHY_C1_CLIPWBTHRES_CLIP2_SHIFT	0
+#define  B43_NPHY_C1_CLIPWBTHRES_CLIP1		0x0FC0 /* Clip 1 */
+#define  B43_NPHY_C1_CLIPWBTHRES_CLIP1_SHIFT	6
+#define B43_NPHY_C1_W1THRES			B43_PHY_N(0x028) /* Core 1 W1 threshold */
+#define B43_NPHY_C1_EDTHRES			B43_PHY_N(0x029) /* Core 1 ED threshold */
+#define B43_NPHY_C1_SMSIGTHRES			B43_PHY_N(0x02A) /* Core 1 small sig threshold */
+#define B43_NPHY_C1_NBCLIPTHRES			B43_PHY_N(0x02B) /* Core 1 NB clip threshold */
+#define B43_NPHY_C1_CLIP1THRES			B43_PHY_N(0x02C) /* Core 1 clip1 threshold */
+#define B43_NPHY_C1_CLIP2THRES			B43_PHY_N(0x02D) /* Core 1 clip2 threshold */
+
+#define B43_NPHY_C2_DESPWR			B43_PHY_N(0x02E) /* Core 2 desired power */
+#define B43_NPHY_C2_CCK_DESPWR			B43_PHY_N(0x02F) /* Core 2 CCK desired power */
+#define B43_NPHY_C2_BCLIPBKOFF			B43_PHY_N(0x030) /* Core 2 barely clip backoff */
+#define B43_NPHY_C2_CCK_BCLIPBKOFF		B43_PHY_N(0x031) /* Core 2 CCK barely clip backoff */
+#define B43_NPHY_C2_CGAINI			B43_PHY_N(0x032) /* Core 2 compute gain info */
+#define  B43_NPHY_C2_CGAINI_GAINBKOFF		0x001F /* Gain backoff */
+#define  B43_NPHY_C2_CGAINI_GAINBKOFF_SHIFT	0
+#define  B43_NPHY_C2_CGAINI_CLIPGBKOFF		0x03E0 /* Clip gain backoff */
+#define  B43_NPHY_C2_CGAINI_CLIPGBKOFF_SHIFT	5
+#define  B43_NPHY_C2_CGAINI_GAINSTEP		0x1C00 /* Gain step */
+#define  B43_NPHY_C2_CGAINI_GAINSTEP_SHIFT	10
+#define  B43_NPHY_C2_CGAINI_CL2DETECT		0x2000 /* Clip 2 detect mask */
+#define B43_NPHY_C2_CCK_CGAINI			B43_PHY_N(0x033) /* Core 2 CCK compute gain info */
+#define  B43_NPHY_C2_CCK_CGAINI_GAINBKOFF	0x001F /* Gain backoff */
+#define  B43_NPHY_C2_CCK_CGAINI_CLIPGBKOFF	0x01E0 /* CCK barely clip gain backoff */
+#define B43_NPHY_C2_MINMAX_GAIN			B43_PHY_N(0x034) /* Core 2 min/max gain */
+#define  B43_NPHY_C2_MINGAIN			0x00FF /* Minimum gain */
+#define  B43_NPHY_C2_MINGAIN_SHIFT		0
+#define  B43_NPHY_C2_MAXGAIN			0xFF00 /* Maximum gain */
+#define  B43_NPHY_C2_MAXGAIN_SHIFT		8
+#define B43_NPHY_C2_CCK_MINMAX_GAIN		B43_PHY_N(0x035) /* Core 2 CCK min/max gain */
+#define  B43_NPHY_C2_CCK_MINGAIN		0x00FF /* Minimum gain */
+#define  B43_NPHY_C2_CCK_MINGAIN_SHIFT		0
+#define  B43_NPHY_C2_CCK_MAXGAIN		0xFF00 /* Maximum gain */
+#define  B43_NPHY_C2_CCK_MAXGAIN_SHIFT		8
+#define B43_NPHY_C2_INITGAIN			B43_PHY_N(0x036) /* Core 2 initial gain code */
+#define  B43_NPHY_C2_INITGAIN_EXTLNA		0x0001 /* External LNA index */
+#define  B43_NPHY_C2_INITGAIN_LNA		0x0006 /* LNA index */
+#define  B43_NPHY_C2_INITGAIN_LNAIDX_SHIFT	1
+#define  B43_NPHY_C2_INITGAIN_HPVGA1		0x0078 /* HPVGA1 index */
+#define  B43_NPHY_C2_INITGAIN_HPVGA1_SHIFT	3
+#define  B43_NPHY_C2_INITGAIN_HPVGA2		0x0F80 /* HPVGA2 index */
+#define  B43_NPHY_C2_INITGAIN_HPVGA2_SHIFT	7
+#define  B43_NPHY_C2_INITGAIN_TRRX		0x1000 /* TR RX index */
+#define  B43_NPHY_C2_INITGAIN_TRTX		0x2000 /* TR TX index */
+#define B43_NPHY_C2_CLIP1_HIGAIN		B43_PHY_N(0x037) /* Core 2 clip1 high gain code */
+#define B43_NPHY_C2_CLIP1_MEDGAIN		B43_PHY_N(0x038) /* Core 2 clip1 medium gain code */
+#define B43_NPHY_C2_CLIP1_LOGAIN		B43_PHY_N(0x039) /* Core 2 clip1 low gain code */
+#define B43_NPHY_C2_CLIP2_GAIN			B43_PHY_N(0x03A) /* Core 2 clip2 gain code */
+#define B43_NPHY_C2_FILTERGAIN			B43_PHY_N(0x03B) /* Core 2 filter gain */
+#define B43_NPHY_C2_LPF_QHPF_BW			B43_PHY_N(0x03C) /* Core 2 LPF Q HP F bandwidth */
+#define B43_NPHY_C2_CLIPWBTHRES			B43_PHY_N(0x03D) /* Core 2 clip wideband threshold */
+#define  B43_NPHY_C2_CLIPWBTHRES_CLIP2		0x003F /* Clip 2 */
+#define  B43_NPHY_C2_CLIPWBTHRES_CLIP2_SHIFT	0
+#define  B43_NPHY_C2_CLIPWBTHRES_CLIP1		0x0FC0 /* Clip 1 */
+#define  B43_NPHY_C2_CLIPWBTHRES_CLIP1_SHIFT	6
+#define B43_NPHY_C2_W1THRES			B43_PHY_N(0x03E) /* Core 2 W1 threshold */
+#define B43_NPHY_C2_EDTHRES			B43_PHY_N(0x03F) /* Core 2 ED threshold */
+#define B43_NPHY_C2_SMSIGTHRES			B43_PHY_N(0x040) /* Core 2 small sig threshold */
+#define B43_NPHY_C2_NBCLIPTHRES			B43_PHY_N(0x041) /* Core 2 NB clip threshold */
+#define B43_NPHY_C2_CLIP1THRES			B43_PHY_N(0x042) /* Core 2 clip1 threshold */
+#define B43_NPHY_C2_CLIP2THRES			B43_PHY_N(0x043) /* Core 2 clip2 threshold */
+
+#define B43_NPHY_CRS_THRES1			B43_PHY_N(0x044) /* CRS threshold 1 */
+#define B43_NPHY_CRS_THRES2			B43_PHY_N(0x045) /* CRS threshold 2 */
+#define B43_NPHY_CRS_THRES3			B43_PHY_N(0x046) /* CRS threshold 3 */
+#define B43_NPHY_CRSCTL				B43_PHY_N(0x047) /* CRS control */
+#define B43_NPHY_DCFADDR			B43_PHY_N(0x048) /* DC filter address */
+#define B43_NPHY_RXF20_NUM0			B43_PHY_N(0x049) /* RX filter 20 numerator 0 */
+#define B43_NPHY_RXF20_NUM1			B43_PHY_N(0x04A) /* RX filter 20 numerator 1 */
+#define B43_NPHY_RXF20_NUM2			B43_PHY_N(0x04B) /* RX filter 20 numerator 2 */
+#define B43_NPHY_RXF20_DENOM0			B43_PHY_N(0x04C) /* RX filter 20 denominator 0 */
+#define B43_NPHY_RXF20_DENOM1			B43_PHY_N(0x04D) /* RX filter 20 denominator 1 */
+#define B43_NPHY_RXF20_NUM10			B43_PHY_N(0x04E) /* RX filter 20 numerator 10 */
+#define B43_NPHY_RXF20_NUM11			B43_PHY_N(0x04F) /* RX filter 20 numerator 11 */
+#define B43_NPHY_RXF20_NUM12			B43_PHY_N(0x050) /* RX filter 20 numerator 12 */
+#define B43_NPHY_RXF20_DENOM10			B43_PHY_N(0x051) /* RX filter 20 denominator 10 */
+#define B43_NPHY_RXF20_DENOM11			B43_PHY_N(0x052) /* RX filter 20 denominator 11 */
+#define B43_NPHY_RXF40_NUM0			B43_PHY_N(0x053) /* RX filter 40 numerator 0 */
+#define B43_NPHY_RXF40_NUM1			B43_PHY_N(0x054) /* RX filter 40 numerator 1 */
+#define B43_NPHY_RXF40_NUM2			B43_PHY_N(0x055) /* RX filter 40 numerator 2 */
+#define B43_NPHY_RXF40_DENOM0			B43_PHY_N(0x056) /* RX filter 40 denominator 0 */
+#define B43_NPHY_RXF40_DENOM1			B43_PHY_N(0x057) /* RX filter 40 denominator 1 */
+#define B43_NPHY_RXF40_NUM10			B43_PHY_N(0x058) /* RX filter 40 numerator 10 */
+#define B43_NPHY_RXF40_NUM11			B43_PHY_N(0x059) /* RX filter 40 numerator 11 */
+#define B43_NPHY_RXF40_NUM12			B43_PHY_N(0x05A) /* RX filter 40 numerator 12 */
+#define B43_NPHY_RXF40_DENOM10			B43_PHY_N(0x05B) /* RX filter 40 denominator 10 */
+#define B43_NPHY_RXF40_DENOM11			B43_PHY_N(0x05C) /* RX filter 40 denominator 11 */
+#define B43_NPHY_PPROC_RSTLEN			B43_PHY_N(0x060) /* Packet processing reset length */
+#define B43_NPHY_INITCARR_DLEN			B43_PHY_N(0x061) /* Initial carrier detection length */
+#define B43_NPHY_CLIP1CARR_DLEN			B43_PHY_N(0x062) /* Clip1 carrier detection length */
+#define B43_NPHY_CLIP2CARR_DLEN			B43_PHY_N(0x063) /* Clip2 carrier detection length */
+#define B43_NPHY_INITGAIN_SLEN			B43_PHY_N(0x064) /* Initial gain settle length */
+#define B43_NPHY_CLIP1GAIN_SLEN			B43_PHY_N(0x065) /* Clip1 gain settle length */
+#define B43_NPHY_CLIP2GAIN_SLEN			B43_PHY_N(0x066) /* Clip2 gain settle length */
+#define B43_NPHY_PACKGAIN_SLEN			B43_PHY_N(0x067) /* Packet gain settle length */
+#define B43_NPHY_CARRSRC_TLEN			B43_PHY_N(0x068) /* Carrier search timeout length */
+#define B43_NPHY_TISRC_TLEN			B43_PHY_N(0x069) /* Timing search timeout length */
+#define B43_NPHY_ENDROP_TLEN			B43_PHY_N(0x06A) /* Energy drop timeout length */
+#define B43_NPHY_CLIP1_NBDWELL_LEN		B43_PHY_N(0x06B) /* Clip1 NB dwell length */
+#define B43_NPHY_CLIP2_NBDWELL_LEN		B43_PHY_N(0x06C) /* Clip2 NB dwell length */
+#define B43_NPHY_W1CLIP1_DWELL_LEN		B43_PHY_N(0x06D) /* W1 clip1 dwell length */
+#define B43_NPHY_W1CLIP2_DWELL_LEN		B43_PHY_N(0x06E) /* W1 clip2 dwell length */
+#define B43_NPHY_W2CLIP1_DWELL_LEN		B43_PHY_N(0x06F) /* W2 clip1 dwell length */
+#define B43_NPHY_PLOAD_CSENSE_EXTLEN		B43_PHY_N(0x070) /* Payload carrier sense extension length */
+#define B43_NPHY_EDROP_CSENSE_EXTLEN		B43_PHY_N(0x071) /* Energy drop carrier sense extension length */
+#define B43_NPHY_TABLE_ADDR			B43_PHY_N(0x072) /* Table address */
+#define B43_NPHY_TABLE_DATALO			B43_PHY_N(0x073) /* Table data low */
+#define B43_NPHY_TABLE_DATAHI			B43_PHY_N(0x074) /* Table data high */
+#define B43_NPHY_WWISE_LENIDX			B43_PHY_N(0x075) /* WWiSE length index */
+#define B43_NPHY_TGNSYNC_LENIDX			B43_PHY_N(0x076) /* TGNsync length index */
+#define B43_NPHY_TXMACIF_HOLDOFF		B43_PHY_N(0x077) /* TX MAC IF Hold off */
+#define B43_NPHY_RFCTL_CMD			B43_PHY_N(0x078) /* RF control (command) */
+#define  B43_NPHY_RFCTL_CMD_START		0x0001 /* Start sequence */
+#define  B43_NPHY_RFCTL_CMD_RXTX		0x0002 /* RX/TX */
+#define  B43_NPHY_RFCTL_CMD_CORESEL		0x0038 /* Core select */
+#define  B43_NPHY_RFCTL_CMD_CORESEL_SHIFT	3
+#define  B43_NPHY_RFCTL_CMD_PORFORCE		0x0040 /* POR force */
+#define  B43_NPHY_RFCTL_CMD_OEPORFORCE		0x0080 /* OE POR force */
+#define  B43_NPHY_RFCTL_CMD_RXEN		0x0100 /* RX enable */
+#define  B43_NPHY_RFCTL_CMD_TXEN		0x0200 /* TX enable */
+#define  B43_NPHY_RFCTL_CMD_CHIP0PU		0x0400 /* Chip0 PU */
+#define  B43_NPHY_RFCTL_CMD_EN			0x0800 /* Radio enabled */
+#define  B43_NPHY_RFCTL_CMD_SEQENCORE		0xF000 /* Seq en core */
+#define  B43_NPHY_RFCTL_CMD_SEQENCORE_SHIFT	12
+#define B43_NPHY_RFCTL_RSSIO1			B43_PHY_N(0x07A) /* RF control (RSSI others 1) */
+#define  B43_NPHY_RFCTL_RSSIO1_RXPD		0x0001 /* RX PD */
+#define  B43_NPHY_RFCTL_RSSIO1_TXPD		0x0002 /* TX PD */
+#define  B43_NPHY_RFCTL_RSSIO1_PAPD		0x0004 /* PA PD */
+#define  B43_NPHY_RFCTL_RSSIO1_RSSICTL		0x0030 /* RSSI control */
+#define  B43_NPHY_RFCTL_RSSIO1_LPFBW		0x00C0 /* LPF bandwidth */
+#define  B43_NPHY_RFCTL_RSSIO1_HPFBWHI		0x0100 /* HPF bandwidth high */
+#define  B43_NPHY_RFCTL_RSSIO1_HIQDISCO		0x0200 /* HIQ dis core */
+#define B43_NPHY_RFCTL_RXG1			B43_PHY_N(0x07B) /* RF control (RX gain 1) */
+#define B43_NPHY_RFCTL_TXG1			B43_PHY_N(0x07C) /* RF control (TX gain 1) */
+#define B43_NPHY_RFCTL_RSSIO2			B43_PHY_N(0x07D) /* RF control (RSSI others 2) */
+#define  B43_NPHY_RFCTL_RSSIO2_RXPD		0x0001 /* RX PD */
+#define  B43_NPHY_RFCTL_RSSIO2_TXPD		0x0002 /* TX PD */
+#define  B43_NPHY_RFCTL_RSSIO2_PAPD		0x0004 /* PA PD */
+#define  B43_NPHY_RFCTL_RSSIO2_RSSICTL		0x0030 /* RSSI control */
+#define  B43_NPHY_RFCTL_RSSIO2_LPFBW		0x00C0 /* LPF bandwidth */
+#define  B43_NPHY_RFCTL_RSSIO2_HPFBWHI		0x0100 /* HPF bandwidth high */
+#define  B43_NPHY_RFCTL_RSSIO2_HIQDISCO		0x0200 /* HIQ dis core */
+#define B43_NPHY_RFCTL_RXG2			B43_PHY_N(0x07E) /* RF control (RX gain 2) */
+#define B43_NPHY_RFCTL_TXG2			B43_PHY_N(0x07F) /* RF control (TX gain 2) */
+#define B43_NPHY_RFCTL_RSSIO3			B43_PHY_N(0x080) /* RF control (RSSI others 3) */
+#define  B43_NPHY_RFCTL_RSSIO3_RXPD		0x0001 /* RX PD */
+#define  B43_NPHY_RFCTL_RSSIO3_TXPD		0x0002 /* TX PD */
+#define  B43_NPHY_RFCTL_RSSIO3_PAPD		0x0004 /* PA PD */
+#define  B43_NPHY_RFCTL_RSSIO3_RSSICTL		0x0030 /* RSSI control */
+#define  B43_NPHY_RFCTL_RSSIO3_LPFBW		0x00C0 /* LPF bandwidth */
+#define  B43_NPHY_RFCTL_RSSIO3_HPFBWHI		0x0100 /* HPF bandwidth high */
+#define  B43_NPHY_RFCTL_RSSIO3_HIQDISCO		0x0200 /* HIQ dis core */
+#define B43_NPHY_RFCTL_RXG3			B43_PHY_N(0x081) /* RF control (RX gain 3) */
+#define B43_NPHY_RFCTL_TXG3			B43_PHY_N(0x082) /* RF control (TX gain 3) */
+#define B43_NPHY_RFCTL_RSSIO4			B43_PHY_N(0x083) /* RF control (RSSI others 4) */
+#define  B43_NPHY_RFCTL_RSSIO4_RXPD		0x0001 /* RX PD */
+#define  B43_NPHY_RFCTL_RSSIO4_TXPD		0x0002 /* TX PD */
+#define  B43_NPHY_RFCTL_RSSIO4_PAPD		0x0004 /* PA PD */
+#define  B43_NPHY_RFCTL_RSSIO4_RSSICTL		0x0030 /* RSSI control */
+#define  B43_NPHY_RFCTL_RSSIO4_LPFBW		0x00C0 /* LPF bandwidth */
+#define  B43_NPHY_RFCTL_RSSIO4_HPFBWHI		0x0100 /* HPF bandwidth high */
+#define  B43_NPHY_RFCTL_RSSIO4_HIQDISCO		0x0200 /* HIQ dis core */
+#define B43_NPHY_RFCTL_RXG4			B43_PHY_N(0x084) /* RF control (RX gain 4) */
+#define B43_NPHY_RFCTL_TXG4			B43_PHY_N(0x085) /* RF control (TX gain 4) */
+#define B43_NPHY_C1_TXIQ_COMP_OFF		B43_PHY_N(0x087) /* Core 1 TX I/Q comp offset */
+#define B43_NPHY_C2_TXIQ_COMP_OFF		B43_PHY_N(0x088) /* Core 2 TX I/Q comp offset */
+#define B43_NPHY_C1_TXCTL			B43_PHY_N(0x08B) /* Core 1 TX control */
+#define B43_NPHY_C2_TXCTL			B43_PHY_N(0x08C) /* Core 2 TX control */
+#define B43_NPHY_SCRAM_SIGCTL			B43_PHY_N(0x090) /* Scram signal control */
+#define  B43_NPHY_SCRAM_SIGCTL_INITST		0x007F /* Initial state value */
+#define  B43_NPHY_SCRAM_SIGCTL_INITST_SHIFT	0
+#define  B43_NPHY_SCRAM_SIGCTL_SCM		0x0080 /* Scram control mode */
+#define  B43_NPHY_SCRAM_SIGCTL_SICE		0x0100 /* Scram index control enable */
+#define  B43_NPHY_SCRAM_SIGCTL_START		0xFE00 /* Scram start bit */
+#define  B43_NPHY_SCRAM_SIGCTL_START_SHIFT	9
+#define B43_NPHY_RFCTL_INTC1			B43_PHY_N(0x091) /* RF control (intc 1) */
+#define B43_NPHY_RFCTL_INTC2			B43_PHY_N(0x092) /* RF control (intc 2) */
+#define B43_NPHY_RFCTL_INTC3			B43_PHY_N(0x093) /* RF control (intc 3) */
+#define B43_NPHY_RFCTL_INTC4			B43_PHY_N(0x094) /* RF control (intc 4) */
+#define B43_NPHY_NRDTO_WWISE			B43_PHY_N(0x095) /* # datatones WWiSE */
+#define B43_NPHY_NRDTO_TGNSYNC			B43_PHY_N(0x096) /* # datatones TGNsync */
+#define B43_NPHY_SIGFMOD_WWISE			B43_PHY_N(0x097) /* Signal field mod WWiSE */
+#define B43_NPHY_LEG_SIGFMOD_11N		B43_PHY_N(0x098) /* Legacy signal field mod 11n */
+#define B43_NPHY_HT_SIGFMOD_11N			B43_PHY_N(0x099) /* HT signal field mod 11n */
+#define B43_NPHY_C1_RXIQ_COMPA0			B43_PHY_N(0x09A) /* Core 1 RX I/Q comp A0 */
+#define B43_NPHY_C1_RXIQ_COMPB0			B43_PHY_N(0x09B) /* Core 1 RX I/Q comp B0 */
+#define B43_NPHY_C2_RXIQ_COMPA1			B43_PHY_N(0x09C) /* Core 2 RX I/Q comp A1 */
+#define B43_NPHY_C2_RXIQ_COMPB1			B43_PHY_N(0x09D) /* Core 2 RX I/Q comp B1 */
+#define B43_NPHY_RXCTL				B43_PHY_N(0x0A0) /* RX control */
+#define  B43_NPHY_RXCTL_BSELU20			0x0010 /* Band select upper 20 */
+#define  B43_NPHY_RXCTL_RIFSEN			0x0080 /* RIFS enable */
+#define B43_NPHY_RFSEQMODE			B43_PHY_N(0x0A1) /* RF seq mode */
+#define  B43_NPHY_RFSEQMODE_CAOVER		0x0001 /* Core active override */
+#define  B43_NPHY_RFSEQMODE_TROVER		0x0002 /* Trigger override */
+#define B43_NPHY_RFSEQCA			B43_PHY_N(0x0A2) /* RF seq core active */
+#define  B43_NPHY_RFSEQCA_TXEN			0x000F /* TX enable */
+#define  B43_NPHY_RFSEQCA_TXEN_SHIFT		0
+#define  B43_NPHY_RFSEQCA_RXEN			0x00F0 /* RX enable */
+#define  B43_NPHY_RFSEQCA_RXEN_SHIFT		4
+#define  B43_NPHY_RFSEQCA_TXDIS			0x0F00 /* TX disable */
+#define  B43_NPHY_RFSEQCA_TXDIS_SHIFT		8
+#define  B43_NPHY_RFSEQCA_RXDIS			0xF000 /* RX disable */
+#define  B43_NPHY_RFSEQCA_RXDIS_SHIFT		12
+#define B43_NPHY_RFSEQTR			B43_PHY_N(0x0A3) /* RF seq trigger */
+#define  B43_NPHY_RFSEQTR_RX2TX			0x0001 /* RX2TX */
+#define  B43_NPHY_RFSEQTR_TX2RX			0x0002 /* TX2RX */
+#define  B43_NPHY_RFSEQTR_UPGH			0x0004 /* Update gain H */
+#define  B43_NPHY_RFSEQTR_UPGL			0x0008 /* Update gain L */
+#define  B43_NPHY_RFSEQTR_UPGU			0x0010 /* Update gain U */
+#define  B43_NPHY_RFSEQTR_RST2RX		0x0020 /* Reset to RX */
+#define B43_NPHY_RFSEQST			B43_PHY_N(0x0A4) /* RF seq status. Values same as trigger. */
+#define B43_NPHY_AFECTL_OVER			B43_PHY_N(0x0A5) /* AFE control override */
+#define B43_NPHY_AFECTL_C1			B43_PHY_N(0x0A6) /* AFE control core 1 */
+#define B43_NPHY_AFECTL_C2			B43_PHY_N(0x0A7) /* AFE control core 2 */
+#define B43_NPHY_AFECTL_C3			B43_PHY_N(0x0A8) /* AFE control core 3 */
+#define B43_NPHY_AFECTL_C4			B43_PHY_N(0x0A9) /* AFE control core 4 */
+#define B43_NPHY_AFECTL_DACGAIN1		B43_PHY_N(0x0AA) /* AFE control DAC gain 1 */
+#define B43_NPHY_AFECTL_DACGAIN2		B43_PHY_N(0x0AB) /* AFE control DAC gain 2 */
+#define B43_NPHY_AFECTL_DACGAIN3		B43_PHY_N(0x0AC) /* AFE control DAC gain 3 */
+#define B43_NPHY_AFECTL_DACGAIN4		B43_PHY_N(0x0AD) /* AFE control DAC gain 4 */
+#define B43_NPHY_STR_ADDR1			B43_PHY_N(0x0AE) /* STR address 1 */
+#define B43_NPHY_STR_ADDR2			B43_PHY_N(0x0AF) /* STR address 2 */
+#define B43_NPHY_CLASSCTL			B43_PHY_N(0x0B0) /* Classifier control */
+#define  B43_NPHY_CLASSCTL_CCKEN		0x0001 /* CCK enable */
+#define  B43_NPHY_CLASSCTL_OFDMEN		0x0002 /* OFDM enable */
+#define  B43_NPHY_CLASSCTL_WAITEDEN		0x0004 /* Waited enable */
+#define B43_NPHY_IQFLIP				B43_PHY_N(0x0B1) /* I/Q flip */
+#define  B43_NPHY_IQFLIP_ADC1			0x0001 /* ADC1 */
+#define  B43_NPHY_IQFLIP_ADC2			0x0010 /* ADC2 */
+#define B43_NPHY_SISO_SNR_THRES			B43_PHY_N(0x0B2) /* SISO SNR threshold */
+#define B43_NPHY_SIGMA_N_MULT			B43_PHY_N(0x0B3) /* Sigma N multiplier */
+#define B43_NPHY_TXMACDELAY			B43_PHY_N(0x0B4) /* TX MAC delay */
+#define B43_NPHY_TXFRAMEDELAY			B43_PHY_N(0x0B5) /* TX frame delay */
+#define B43_NPHY_MLPARM				B43_PHY_N(0x0B6) /* ML parameters */
+#define B43_NPHY_MLCTL				B43_PHY_N(0x0B7) /* ML control */
+#define B43_NPHY_WWISE_20NCYCDAT		B43_PHY_N(0x0B8) /* WWiSE 20 N cyc data */
+#define B43_NPHY_WWISE_40NCYCDAT		B43_PHY_N(0x0B9) /* WWiSE 40 N cyc data */
+#define B43_NPHY_TGNSYNC_20NCYCDAT		B43_PHY_N(0x0BA) /* TGNsync 20 N cyc data */
+#define B43_NPHY_TGNSYNC_40NCYCDAT		B43_PHY_N(0x0BB) /* TGNsync 40 N cyc data */
+#define B43_NPHY_INITSWIZP			B43_PHY_N(0x0BC) /* Initial swizzle pattern */
+#define B43_NPHY_TXTAILCNT			B43_PHY_N(0x0BD) /* TX tail count value */
+#define B43_NPHY_BPHY_CTL1			B43_PHY_N(0x0BE) /* B PHY control 1 */
+#define B43_NPHY_BPHY_CTL2			B43_PHY_N(0x0BF) /* B PHY control 2 */
+#define  B43_NPHY_BPHY_CTL2_LUT			0x001F /* LUT index */
+#define  B43_NPHY_BPHY_CTL2_LUT_SHIFT		0
+#define  B43_NPHY_BPHY_CTL2_MACDEL		0x7FE0 /* MAC delay */
+#define  B43_NPHY_BPHY_CTL2_MACDEL_SHIFT	5
+#define B43_NPHY_IQLOCAL_CMD			B43_PHY_N(0x0C0) /* I/Q LO cal command */
+#define  B43_NPHY_IQLOCAL_CMD_EN		0x8000
+#define B43_NPHY_IQLOCAL_CMDNNUM		B43_PHY_N(0x0C1) /* I/Q LO cal command N num */
+#define B43_NPHY_IQLOCAL_CMDGCTL		B43_PHY_N(0x0C2) /* I/Q LO cal command G control */
+#define B43_NPHY_SAMP_CMD			B43_PHY_N(0x0C3) /* Sample command */
+#define  B43_NPHY_SAMP_CMD_STOP			0x0002 /* Stop */
+#define B43_NPHY_SAMP_LOOPCNT			B43_PHY_N(0x0C4) /* Sample loop count */
+#define B43_NPHY_SAMP_WAITCNT			B43_PHY_N(0x0C5) /* Sample wait count */
+#define B43_NPHY_SAMP_DEPCNT			B43_PHY_N(0x0C6) /* Sample depth count */
+#define B43_NPHY_SAMP_STAT			B43_PHY_N(0x0C7) /* Sample status */
+#define B43_NPHY_GPIO_LOOEN			B43_PHY_N(0x0C8) /* GPIO low out enable */
+#define B43_NPHY_GPIO_HIOEN			B43_PHY_N(0x0C9) /* GPIO high out enable */
+#define B43_NPHY_GPIO_SEL			B43_PHY_N(0x0CA) /* GPIO select */
+#define B43_NPHY_GPIO_CLKCTL			B43_PHY_N(0x0CB) /* GPIO clock control */
+#define B43_NPHY_TXF_20CO_AS0			B43_PHY_N(0x0CC) /* TX filter 20 coeff A stage 0 */
+#define B43_NPHY_TXF_20CO_AS1			B43_PHY_N(0x0CD) /* TX filter 20 coeff A stage 1 */
+#define B43_NPHY_TXF_20CO_AS2			B43_PHY_N(0x0CE) /* TX filter 20 coeff A stage 2 */
+#define B43_NPHY_TXF_20CO_B32S0			B43_PHY_N(0x0CF) /* TX filter 20 coeff B32 stage 0 */
+#define B43_NPHY_TXF_20CO_B1S0			B43_PHY_N(0x0D0) /* TX filter 20 coeff B1 stage 0 */
+#define B43_NPHY_TXF_20CO_B32S1			B43_PHY_N(0x0D1) /* TX filter 20 coeff B32 stage 1 */
+#define B43_NPHY_TXF_20CO_B1S1			B43_PHY_N(0x0D2) /* TX filter 20 coeff B1 stage 1 */
+#define B43_NPHY_TXF_20CO_B32S2			B43_PHY_N(0x0D3) /* TX filter 20 coeff B32 stage 2 */
+#define B43_NPHY_TXF_20CO_B1S2			B43_PHY_N(0x0D4) /* TX filter 20 coeff B1 stage 2 */
+#define B43_NPHY_SIGFLDTOL			B43_PHY_N(0x0D5) /* Signal fld tolerance */
+#define B43_NPHY_TXSERFLD			B43_PHY_N(0x0D6) /* TX service field */
+#define B43_NPHY_AFESEQ_RX2TX_PUD		B43_PHY_N(0x0D7) /* AFE seq RX2TX power up/down delay */
+#define B43_NPHY_AFESEQ_TX2RX_PUD		B43_PHY_N(0x0D8) /* AFE seq TX2RX power up/down delay */
+#define B43_NPHY_TGNSYNC_SCRAMI0		B43_PHY_N(0x0D9) /* TGNsync scram init 0 */
+#define B43_NPHY_TGNSYNC_SCRAMI1		B43_PHY_N(0x0DA) /* TGNsync scram init 1 */
+#define B43_NPHY_INITSWIZPATTLEG		B43_PHY_N(0x0DB) /* Initial swizzle pattern leg */
+#define B43_NPHY_BPHY_CTL3			B43_PHY_N(0x0DC) /* B PHY control 3 */
+#define  B43_NPHY_BPHY_CTL3_SCALE		0x00FF /* Scale */
+#define  B43_NPHY_BPHY_CTL3_SCALE_SHIFT		0
+#define  B43_NPHY_BPHY_CTL3_FSC			0xFF00 /* Frame start count value */
+#define  B43_NPHY_BPHY_CTL3_FSC_SHIFT		8
+#define B43_NPHY_BPHY_CTL4			B43_PHY_N(0x0DD) /* B PHY control 4 */
+#define B43_NPHY_C1_TXBBMULT			B43_PHY_N(0x0DE) /* Core 1 TX BB multiplier */
+#define B43_NPHY_C2_TXBBMULT			B43_PHY_N(0x0DF) /* Core 2 TX BB multiplier */
+#define B43_NPHY_TXF_40CO_AS0			B43_PHY_N(0x0E1) /* TX filter 40 coeff A stage 0 */
+#define B43_NPHY_TXF_40CO_AS1			B43_PHY_N(0x0E2) /* TX filter 40 coeff A stage 1 */
+#define B43_NPHY_TXF_40CO_AS2			B43_PHY_N(0x0E3) /* TX filter 40 coeff A stage 2 */
+#define B43_NPHY_TXF_40CO_B32S0			B43_PHY_N(0x0E4) /* TX filter 40 coeff B32 stage 0 */
+#define B43_NPHY_TXF_40CO_B1S0			B43_PHY_N(0x0E5) /* TX filter 40 coeff B1 stage 0 */
+#define B43_NPHY_TXF_40CO_B32S1			B43_PHY_N(0x0E6) /* TX filter 40 coeff B32 stage 1 */
+#define B43_NPHY_TXF_40CO_B1S1			B43_PHY_N(0x0E7) /* TX filter 40 coeff B1 stage 1 */
+#define B43_NPHY_TXF_40CO_B32S2			B43_PHY_N(0x0E8) /* TX filter 40 coeff B32 stage 2 */
+#define B43_NPHY_TXF_40CO_B1S2			B43_PHY_N(0x0E9) /* TX filter 40 coeff B1 stage 2 */
+#define B43_NPHY_BIST_STAT2			B43_PHY_N(0x0EA) /* BIST status 2 */
+#define B43_NPHY_BIST_STAT3			B43_PHY_N(0x0EB) /* BIST status 3 */
+#define B43_NPHY_RFCTL_OVER			B43_PHY_N(0x0EC) /* RF control override */
+#define B43_NPHY_MIMOCFG			B43_PHY_N(0x0ED) /* MIMO config */
+#define  B43_NPHY_MIMOCFG_GFMIX			0x0004 /* Greenfield or mixed mode */
+#define  B43_NPHY_MIMOCFG_AUTO			0x0100 /* Greenfield/mixed mode auto */
+#define B43_NPHY_RADAR_BLNKCTL			B43_PHY_N(0x0EE) /* Radar blank control */
+#define B43_NPHY_A0RADAR_FIFOCTL		B43_PHY_N(0x0EF) /* Antenna 0 radar FIFO control */
+#define B43_NPHY_A1RADAR_FIFOCTL		B43_PHY_N(0x0F0) /* Antenna 1 radar FIFO control */
+#define B43_NPHY_A0RADAR_FIFODAT		B43_PHY_N(0x0F1) /* Antenna 0 radar FIFO data */
+#define B43_NPHY_A1RADAR_FIFODAT		B43_PHY_N(0x0F2) /* Antenna 1 radar FIFO data */
+#define B43_NPHY_RADAR_THRES0			B43_PHY_N(0x0F3) /* Radar threshold 0 */
+#define B43_NPHY_RADAR_THRES1			B43_PHY_N(0x0F4) /* Radar threshold 1 */
+#define B43_NPHY_RADAR_THRES0R			B43_PHY_N(0x0F5) /* Radar threshold 0R */
+#define B43_NPHY_RADAR_THRES1R			B43_PHY_N(0x0F6) /* Radar threshold 1R */
+#define B43_NPHY_CSEN_20IN40_DLEN		B43_PHY_N(0x0F7) /* Carrier sense 20 in 40 dwell length */
+#define B43_NPHY_RFCTL_LUT_TRSW_LO1		B43_PHY_N(0x0F8) /* RF control LUT TRSW lower 1 */
+#define B43_NPHY_RFCTL_LUT_TRSW_UP1		B43_PHY_N(0x0F9) /* RF control LUT TRSW upper 1 */
+#define B43_NPHY_RFCTL_LUT_TRSW_LO2		B43_PHY_N(0x0FA) /* RF control LUT TRSW lower 2 */
+#define B43_NPHY_RFCTL_LUT_TRSW_UP2		B43_PHY_N(0x0FB) /* RF control LUT TRSW upper 2 */
+#define B43_NPHY_RFCTL_LUT_TRSW_LO3		B43_PHY_N(0x0FC) /* RF control LUT TRSW lower 3 */
+#define B43_NPHY_RFCTL_LUT_TRSW_UP3		B43_PHY_N(0x0FD) /* RF control LUT TRSW upper 3 */
+#define B43_NPHY_RFCTL_LUT_TRSW_LO4		B43_PHY_N(0x0FE) /* RF control LUT TRSW lower 4 */
+#define B43_NPHY_RFCTL_LUT_TRSW_UP4		B43_PHY_N(0x0FF) /* RF control LUT TRSW upper 4 */
+#define B43_NPHY_RFCTL_LUT_LNAPA1		B43_PHY_N(0x100) /* RF control LUT LNA PA 1 */
+#define B43_NPHY_RFCTL_LUT_LNAPA2		B43_PHY_N(0x101) /* RF control LUT LNA PA 2 */
+#define B43_NPHY_RFCTL_LUT_LNAPA3		B43_PHY_N(0x102) /* RF control LUT LNA PA 3 */
+#define B43_NPHY_RFCTL_LUT_LNAPA4		B43_PHY_N(0x103) /* RF control LUT LNA PA 4 */
+#define B43_NPHY_TGNSYNC_CRCM0			B43_PHY_N(0x104) /* TGNsync CRC mask 0 */
+#define B43_NPHY_TGNSYNC_CRCM1			B43_PHY_N(0x105) /* TGNsync CRC mask 1 */
+#define B43_NPHY_TGNSYNC_CRCM2			B43_PHY_N(0x106) /* TGNsync CRC mask 2 */
+#define B43_NPHY_TGNSYNC_CRCM3			B43_PHY_N(0x107) /* TGNsync CRC mask 3 */
+#define B43_NPHY_TGNSYNC_CRCM4			B43_PHY_N(0x108) /* TGNsync CRC mask 4 */
+#define B43_NPHY_CRCPOLY			B43_PHY_N(0x109) /* CRC polynomial */
+#define B43_NPHY_SIGCNT				B43_PHY_N(0x10A) /* # sig count */
+#define B43_NPHY_SIGSTARTBIT_CTL		B43_PHY_N(0x10B) /* Sig start bit control */
+#define B43_NPHY_CRCPOLY_ORDER			B43_PHY_N(0x10C) /* CRC polynomial order */
+#define B43_NPHY_RFCTL_CST0			B43_PHY_N(0x10D) /* RF control core swap table 0 */
+#define B43_NPHY_RFCTL_CST1			B43_PHY_N(0x10E) /* RF control core swap table 1 */
+#define B43_NPHY_RFCTL_CST2O			B43_PHY_N(0x10F) /* RF control core swap table 2 + others */
+#define B43_NPHY_BPHY_CTL5			B43_PHY_N(0x111) /* B PHY control 5 */
+#define B43_NPHY_RFSEQ_LPFBW			B43_PHY_N(0x112) /* RF seq LPF bandwidth */
+#define B43_NPHY_TSSIBIAS1			B43_PHY_N(0x114) /* TSSI bias val 1 */
+#define B43_NPHY_TSSIBIAS2			B43_PHY_N(0x115) /* TSSI bias val 2 */
+#define  B43_NPHY_TSSIBIAS_BIAS			0x00FF /* Bias */
+#define  B43_NPHY_TSSIBIAS_BIAS_SHIFT		0
+#define  B43_NPHY_TSSIBIAS_VAL			0xFF00 /* Value */
+#define  B43_NPHY_TSSIBIAS_VAL_SHIFT		8
+#define B43_NPHY_ESTPWR1			B43_PHY_N(0x118) /* Estimated power 1 */
+#define B43_NPHY_ESTPWR2			B43_PHY_N(0x119) /* Estimated power 2 */
+#define  B43_NPHY_ESTPWR_PWR			0x00FF /* Estimated power */
+#define  B43_NPHY_ESTPWR_PWR_SHIFT		0
+#define  B43_NPHY_ESTPWR_VALID			0x0100 /* Estimated power valid */
+#define B43_NPHY_TSSI_MAXTXFDT			B43_PHY_N(0x11C) /* TSSI max TX frame delay time */
+#define  B43_NPHY_TSSI_MAXTXFDT_VAL		0x00FF /* max TX frame delay time */
+#define  B43_NPHY_TSSI_MAXTXFDT_VAL_SHIFT	0
+#define B43_NPHY_TSSI_MAXTDT			B43_PHY_N(0x11D) /* TSSI max TSSI delay time */
+#define  B43_NPHY_TSSI_MAXTDT_VAL		0x00FF /* max TSSI delay time */
+#define  B43_NPHY_TSSI_MAXTDT_VAL_SHIFT		0
+#define B43_NPHY_ITSSI1				B43_PHY_N(0x11E) /* TSSI idle 1 */
+#define B43_NPHY_ITSSI2				B43_PHY_N(0x11F) /* TSSI idle 2 */
+#define  B43_NPHY_ITSSI_VAL			0x00FF /* Idle TSSI */
+#define  B43_NPHY_ITSSI_VAL_SHIFT		0
+#define B43_NPHY_TSSIMODE			B43_PHY_N(0x122) /* TSSI mode */
+#define  B43_NPHY_TSSIMODE_EN			0x0001 /* TSSI enable */
+#define  B43_NPHY_TSSIMODE_PDEN			0x0002 /* Power det enable */
+#define B43_NPHY_RXMACIFM			B43_PHY_N(0x123) /* RX Macif mode */
+#define B43_NPHY_CRSIT_COCNT_LO			B43_PHY_N(0x124) /* CRS idle time CRS-on count (low) */
+#define B43_NPHY_CRSIT_COCNT_HI			B43_PHY_N(0x125) /* CRS idle time CRS-on count (high) */
+#define B43_NPHY_CRSIT_MTCNT_LO			B43_PHY_N(0x126) /* CRS idle time measure time count (low) */
+#define B43_NPHY_CRSIT_MTCNT_HI			B43_PHY_N(0x127) /* CRS idle time measure time count (high) */
+#define B43_NPHY_SAMTWC				B43_PHY_N(0x128) /* Sample tail wait count */
+#define B43_NPHY_IQEST_CMD			B43_PHY_N(0x129) /* I/Q estimate command */
+#define  B43_NPHY_IQEST_CMD_START		0x0001 /* Start */
+#define  B43_NPHY_IQEST_CMD_MODE		0x0002 /* Mode */
+#define B43_NPHY_IQEST_WT			B43_PHY_N(0x12A) /* I/Q estimate wait time */
+#define  B43_NPHY_IQEST_WT_VAL			0x00FF /* Wait time */
+#define  B43_NPHY_IQEST_WT_VAL_SHIFT		0
+#define B43_NPHY_IQEST_SAMCNT			B43_PHY_N(0x12B) /* I/Q estimate sample count */
+#define B43_NPHY_IQEST_IQACC_LO0		B43_PHY_N(0x12C) /* I/Q estimate I/Q acc lo 0 */
+#define B43_NPHY_IQEST_IQACC_HI0		B43_PHY_N(0x12D) /* I/Q estimate I/Q acc hi 0 */
+#define B43_NPHY_IQEST_IPACC_LO0		B43_PHY_N(0x12E) /* I/Q estimate I power acc lo 0 */
+#define B43_NPHY_IQEST_IPACC_HI0		B43_PHY_N(0x12F) /* I/Q estimate I power acc hi 0 */
+#define B43_NPHY_IQEST_QPACC_LO0		B43_PHY_N(0x130) /* I/Q estimate Q power acc lo 0 */
+#define B43_NPHY_IQEST_QPACC_HI0		B43_PHY_N(0x131) /* I/Q estimate Q power acc hi 0 */
+#define B43_NPHY_IQEST_IQACC_LO1		B43_PHY_N(0x134) /* I/Q estimate I/Q acc lo 1 */
+#define B43_NPHY_IQEST_IQACC_HI1		B43_PHY_N(0x135) /* I/Q estimate I/Q acc hi 1 */
+#define B43_NPHY_IQEST_IPACC_LO1		B43_PHY_N(0x136) /* I/Q estimate I power acc lo 1 */
+#define B43_NPHY_IQEST_IPACC_HI1		B43_PHY_N(0x137) /* I/Q estimate I power acc hi 1 */
+#define B43_NPHY_IQEST_QPACC_LO1		B43_PHY_N(0x138) /* I/Q estimate Q power acc lo 1 */
+#define B43_NPHY_IQEST_QPACC_HI1		B43_PHY_N(0x139) /* I/Q estimate Q power acc hi 1 */
+#define B43_NPHY_MIMO_CRSTXEXT			B43_PHY_N(0x13A) /* MIMO PHY CRS TX extension */
+#define B43_NPHY_PWRDET1			B43_PHY_N(0x13B) /* Power det 1 */
+#define B43_NPHY_PWRDET2			B43_PHY_N(0x13C) /* Power det 2 */
+#define B43_NPHY_MAXRSSI_DTIME			B43_PHY_N(0x13F) /* RSSI max RSSI delay time */
+#define B43_NPHY_PIL_DW0			B43_PHY_N(0x141) /* Pilot data weight 0 */
+#define B43_NPHY_PIL_DW1			B43_PHY_N(0x142) /* Pilot data weight 1 */
+#define B43_NPHY_PIL_DW2			B43_PHY_N(0x143) /* Pilot data weight 2 */
+#define  B43_NPHY_PIL_DW_BPSK			0x000F /* BPSK */
+#define  B43_NPHY_PIL_DW_BPSK_SHIFT		0
+#define  B43_NPHY_PIL_DW_QPSK			0x00F0 /* QPSK */
+#define  B43_NPHY_PIL_DW_QPSK_SHIFT		4
+#define  B43_NPHY_PIL_DW_16QAM			0x0F00 /* 16-QAM */
+#define  B43_NPHY_PIL_DW_16QAM_SHIFT		8
+#define  B43_NPHY_PIL_DW_64QAM			0xF000 /* 64-QAM */
+#define  B43_NPHY_PIL_DW_64QAM_SHIFT		12
+#define B43_NPHY_FMDEM_CFG			B43_PHY_N(0x144) /* FM demodulation config */
+#define B43_NPHY_PHASETR_A0			B43_PHY_N(0x145) /* Phase track alpha 0 */
+#define B43_NPHY_PHASETR_A1			B43_PHY_N(0x146) /* Phase track alpha 1 */
+#define B43_NPHY_PHASETR_A2			B43_PHY_N(0x147) /* Phase track alpha 2 */
+#define B43_NPHY_PHASETR_B0			B43_PHY_N(0x148) /* Phase track beta 0 */
+#define B43_NPHY_PHASETR_B1			B43_PHY_N(0x149) /* Phase track beta 1 */
+#define B43_NPHY_PHASETR_B2			B43_PHY_N(0x14A) /* Phase track beta 2 */
+#define B43_NPHY_PHASETR_CHG0			B43_PHY_N(0x14B) /* Phase track change 0 */
+#define B43_NPHY_PHASETR_CHG1			B43_PHY_N(0x14C) /* Phase track change 1 */
+#define B43_NPHY_PHASETW_OFF			B43_PHY_N(0x14D) /* Phase track offset */
+#define B43_NPHY_RFCTL_DBG			B43_PHY_N(0x14E) /* RF control debug */
+#define B43_NPHY_CCK_SHIFTB_REF			B43_PHY_N(0x150) /* CCK shiftbits reference var */
+#define B43_NPHY_OVER_DGAIN0			B43_PHY_N(0x152) /* Override digital gain 0 */
+#define B43_NPHY_OVER_DGAIN1			B43_PHY_N(0x153) /* Override digital gain 1 */
+#define  B43_NPHY_OVER_DGAIN_FDGV		0x0007 /* Force digital gain value */
+#define  B43_NPHY_OVER_DGAIN_FDGV_SHIFT		0
+#define  B43_NPHY_OVER_DGAIN_FDGEN		0x0008 /* Force digital gain enable */
+#define  B43_NPHY_OVER_DGAIN_CCKDGECV		0xFF00 /* CCK digital gain enable count value */
+#define  B43_NPHY_OVER_DGAIN_CCKDGECV_SHIFT	8
+#define B43_NPHY_BIST_STAT4			B43_PHY_N(0x156) /* BIST status 4 */
+#define B43_NPHY_RADAR_MAL			B43_PHY_N(0x157) /* Radar MA length */
+#define B43_NPHY_RADAR_SRCCTL			B43_PHY_N(0x158) /* Radar search control */
+#define B43_NPHY_VLD_DTSIG			B43_PHY_N(0x159) /* VLD data tones sig */
+#define B43_NPHY_VLD_DTDAT			B43_PHY_N(0x15A) /* VLD data tones data */
+#define B43_NPHY_C1_BPHY_RXIQCA0		B43_PHY_N(0x15B) /* Core 1 B PHY RX I/Q comp A0 */
+#define B43_NPHY_C1_BPHY_RXIQCB0		B43_PHY_N(0x15C) /* Core 1 B PHY RX I/Q comp B0 */
+#define B43_NPHY_C2_BPHY_RXIQCA1		B43_PHY_N(0x15D) /* Core 2 B PHY RX I/Q comp A1 */
+#define B43_NPHY_C2_BPHY_RXIQCB1		B43_PHY_N(0x15E) /* Core 2 B PHY RX I/Q comp B1 */
+#define B43_NPHY_FREQGAIN0			B43_PHY_N(0x160) /* Frequency gain 0 */
+#define B43_NPHY_FREQGAIN1			B43_PHY_N(0x161) /* Frequency gain 1 */
+#define B43_NPHY_FREQGAIN2			B43_PHY_N(0x162) /* Frequency gain 2 */
+#define B43_NPHY_FREQGAIN3			B43_PHY_N(0x163) /* Frequency gain 3 */
+#define B43_NPHY_FREQGAIN4			B43_PHY_N(0x164) /* Frequency gain 4 */
+#define B43_NPHY_FREQGAIN5			B43_PHY_N(0x165) /* Frequency gain 5 */
+#define B43_NPHY_FREQGAIN6			B43_PHY_N(0x166) /* Frequency gain 6 */
+#define B43_NPHY_FREQGAIN7			B43_PHY_N(0x167) /* Frequency gain 7 */
+#define B43_NPHY_FREQGAIN_BYPASS		B43_PHY_N(0x168) /* Frequency gain bypass */
+#define B43_NPHY_TRLOSS				B43_PHY_N(0x169) /* TR loss value */
+#define B43_NPHY_C1_ADCCLIP			B43_PHY_N(0x16A) /* Core 1 ADC clip */
+#define B43_NPHY_C2_ADCCLIP			B43_PHY_N(0x16B) /* Core 2 ADC clip */
+#define B43_NPHY_LTRN_OFFGAIN			B43_PHY_N(0x16F) /* LTRN offset gain */
+#define B43_NPHY_LTRN_OFF			B43_PHY_N(0x170) /* LTRN offset */
+#define B43_NPHY_NRDATAT_WWISE20SIG		B43_PHY_N(0x171) /* # data tones WWiSE 20 sig */
+#define B43_NPHY_NRDATAT_WWISE40SIG		B43_PHY_N(0x172) /* # data tones WWiSE 40 sig */
+#define B43_NPHY_NRDATAT_TGNSYNC20SIG		B43_PHY_N(0x173) /* # data tones TGNsync 20 sig */
+#define B43_NPHY_NRDATAT_TGNSYNC40SIG		B43_PHY_N(0x174) /* # data tones TGNsync 40 sig */
+#define B43_NPHY_WWISE_CRCM0			B43_PHY_N(0x175) /* WWiSE CRC mask 0 */
+#define B43_NPHY_WWISE_CRCM1			B43_PHY_N(0x176) /* WWiSE CRC mask 1 */
+#define B43_NPHY_WWISE_CRCM2			B43_PHY_N(0x177) /* WWiSE CRC mask 2 */
+#define B43_NPHY_WWISE_CRCM3			B43_PHY_N(0x178) /* WWiSE CRC mask 3 */
+#define B43_NPHY_WWISE_CRCM4			B43_PHY_N(0x179) /* WWiSE CRC mask 4 */
+#define B43_NPHY_CHANEST_CDDSH			B43_PHY_N(0x17A) /* Channel estimate CDD shift */
+#define B43_NPHY_HTAGC_WCNT			B43_PHY_N(0x17B) /* HT ADC wait counters */
+#define B43_NPHY_SQPARM				B43_PHY_N(0x17C) /* SQ params */
+#define B43_NPHY_MCSDUP6M			B43_PHY_N(0x17D) /* MCS dup 6M */
+#define B43_NPHY_NDATAT_DUP40			B43_PHY_N(0x17E) /* # data tones dup 40 */
+#define B43_NPHY_DUP40_TGNSYNC_CYCD		B43_PHY_N(0x17F) /* Dup40 TGNsync cycle data */
+#define B43_NPHY_DUP40_GFBL			B43_PHY_N(0x180) /* Dup40 GF format BL address */
+#define B43_NPHY_DUP40_BL			B43_PHY_N(0x181) /* Dup40 format BL address */
+#define B43_NPHY_LEGDUP_FTA			B43_PHY_N(0x182) /* Legacy dup frm table address */
+#define B43_NPHY_PACPROC_DBG			B43_PHY_N(0x183) /* Packet processing debug */
+#define B43_NPHY_PIL_CYC1			B43_PHY_N(0x184) /* Pilot cycle counter 1 */
+#define B43_NPHY_PIL_CYC2			B43_PHY_N(0x185) /* Pilot cycle counter 2 */
+#define B43_NPHY_TXF_20CO_S0A1			B43_PHY_N(0x186) /* TX filter 20 coeff stage 0 A1 */
+#define B43_NPHY_TXF_20CO_S0A2			B43_PHY_N(0x187) /* TX filter 20 coeff stage 0 A2 */
+#define B43_NPHY_TXF_20CO_S1A1			B43_PHY_N(0x188) /* TX filter 20 coeff stage 1 A1 */
+#define B43_NPHY_TXF_20CO_S1A2			B43_PHY_N(0x189) /* TX filter 20 coeff stage 1 A2 */
+#define B43_NPHY_TXF_20CO_S2A1			B43_PHY_N(0x18A) /* TX filter 20 coeff stage 2 A1 */
+#define B43_NPHY_TXF_20CO_S2A2			B43_PHY_N(0x18B) /* TX filter 20 coeff stage 2 A2 */
+#define B43_NPHY_TXF_20CO_S0B1			B43_PHY_N(0x18C) /* TX filter 20 coeff stage 0 B1 */
+#define B43_NPHY_TXF_20CO_S0B2			B43_PHY_N(0x18D) /* TX filter 20 coeff stage 0 B2 */
+#define B43_NPHY_TXF_20CO_S0B3			B43_PHY_N(0x18E) /* TX filter 20 coeff stage 0 B3 */
+#define B43_NPHY_TXF_20CO_S1B1			B43_PHY_N(0x18F) /* TX filter 20 coeff stage 1 B1 */
+#define B43_NPHY_TXF_20CO_S1B2			B43_PHY_N(0x190) /* TX filter 20 coeff stage 1 B2 */
+#define B43_NPHY_TXF_20CO_S1B3			B43_PHY_N(0x191) /* TX filter 20 coeff stage 1 B3 */
+#define B43_NPHY_TXF_20CO_S2B1			B43_PHY_N(0x192) /* TX filter 20 coeff stage 2 B1 */
+#define B43_NPHY_TXF_20CO_S2B2			B43_PHY_N(0x193) /* TX filter 20 coeff stage 2 B2 */
+#define B43_NPHY_TXF_20CO_S2B3			B43_PHY_N(0x194) /* TX filter 20 coeff stage 2 B3 */
+#define B43_NPHY_TXF_40CO_S0A1			B43_PHY_N(0x195) /* TX filter 40 coeff stage 0 A1 */
+#define B43_NPHY_TXF_40CO_S0A2			B43_PHY_N(0x196) /* TX filter 40 coeff stage 0 A2 */
+#define B43_NPHY_TXF_40CO_S1A1			B43_PHY_N(0x197) /* TX filter 40 coeff stage 1 A1 */
+#define B43_NPHY_TXF_40CO_S1A2			B43_PHY_N(0x198) /* TX filter 40 coeff stage 1 A2 */
+#define B43_NPHY_TXF_40CO_S2A1			B43_PHY_N(0x199) /* TX filter 40 coeff stage 2 A1 */
+#define B43_NPHY_TXF_40CO_S2A2			B43_PHY_N(0x19A) /* TX filter 40 coeff stage 2 A2 */
+#define B43_NPHY_TXF_40CO_S0B1			B43_PHY_N(0x19B) /* TX filter 40 coeff stage 0 B1 */
+#define B43_NPHY_TXF_40CO_S0B2			B43_PHY_N(0x19C) /* TX filter 40 coeff stage 0 B2 */
+#define B43_NPHY_TXF_40CO_S0B3			B43_PHY_N(0x19D) /* TX filter 40 coeff stage 0 B3 */
+#define B43_NPHY_TXF_40CO_S1B1			B43_PHY_N(0x19E) /* TX filter 40 coeff stage 1 B1 */
+#define B43_NPHY_TXF_40CO_S1B2			B43_PHY_N(0x19F) /* TX filter 40 coeff stage 1 B2 */
+#define B43_NPHY_TXF_40CO_S1B3			B43_PHY_N(0x1A0) /* TX filter 40 coeff stage 1 B3 */
+#define B43_NPHY_TXF_40CO_S2B1			B43_PHY_N(0x1A1) /* TX filter 40 coeff stage 2 B1 */
+#define B43_NPHY_TXF_40CO_S2B2			B43_PHY_N(0x1A2) /* TX filter 40 coeff stage 2 B2 */
+#define B43_NPHY_TXF_40CO_S2B3			B43_PHY_N(0x1A3) /* TX filter 40 coeff stage 2 B3 */
+#define B43_NPHY_RSSIMC_0I_RSSI_X		B43_PHY_N(0x1A4) /* RSSI multiplication coefficient 0 I RSSI X */
+#define B43_NPHY_RSSIMC_0I_RSSI_Y		B43_PHY_N(0x1A5) /* RSSI multiplication coefficient 0 I RSSI Y */
+#define B43_NPHY_RSSIMC_0I_RSSI_Z		B43_PHY_N(0x1A6) /* RSSI multiplication coefficient 0 I RSSI Z */
+#define B43_NPHY_RSSIMC_0I_TBD			B43_PHY_N(0x1A7) /* RSSI multiplication coefficient 0 I TBD */
+#define B43_NPHY_RSSIMC_0I_PWRDET		B43_PHY_N(0x1A8) /* RSSI multiplication coefficient 0 I power det */
+#define B43_NPHY_RSSIMC_0I_TSSI			B43_PHY_N(0x1A9) /* RSSI multiplication coefficient 0 I TSSI */
+#define B43_NPHY_RSSIMC_0Q_RSSI_X		B43_PHY_N(0x1AA) /* RSSI multiplication coefficient 0 Q RSSI X */
+#define B43_NPHY_RSSIMC_0Q_RSSI_Y		B43_PHY_N(0x1AB) /* RSSI multiplication coefficient 0 Q RSSI Y */
+#define B43_NPHY_RSSIMC_0Q_RSSI_Z		B43_PHY_N(0x1AC) /* RSSI multiplication coefficient 0 Q RSSI Z */
+#define B43_NPHY_RSSIMC_0Q_TBD			B43_PHY_N(0x1AD) /* RSSI multiplication coefficient 0 Q TBD */
+#define B43_NPHY_RSSIMC_0Q_PWRDET		B43_PHY_N(0x1AE) /* RSSI multiplication coefficient 0 Q power det */
+#define B43_NPHY_RSSIMC_0Q_TSSI			B43_PHY_N(0x1AF) /* RSSI multiplication coefficient 0 Q TSSI */
+#define B43_NPHY_RSSIMC_1I_RSSI_X		B43_PHY_N(0x1B0) /* RSSI multiplication coefficient 1 I RSSI X */
+#define B43_NPHY_RSSIMC_1I_RSSI_Y		B43_PHY_N(0x1B1) /* RSSI multiplication coefficient 1 I RSSI Y */
+#define B43_NPHY_RSSIMC_1I_RSSI_Z		B43_PHY_N(0x1B2) /* RSSI multiplication coefficient 1 I RSSI Z */
+#define B43_NPHY_RSSIMC_1I_TBD			B43_PHY_N(0x1B3) /* RSSI multiplication coefficient 1 I TBD */
+#define B43_NPHY_RSSIMC_1I_PWRDET		B43_PHY_N(0x1B4) /* RSSI multiplication coefficient 1 I power det */
+#define B43_NPHY_RSSIMC_1I_TSSI			B43_PHY_N(0x1B5) /* RSSI multiplication coefficient 1 I TSSI */
+#define B43_NPHY_RSSIMC_1Q_RSSI_X		B43_PHY_N(0x1B6) /* RSSI multiplication coefficient 1 Q RSSI X */
+#define B43_NPHY_RSSIMC_1Q_RSSI_Y		B43_PHY_N(0x1B7) /* RSSI multiplication coefficient 1 Q RSSI Y */
+#define B43_NPHY_RSSIMC_1Q_RSSI_Z		B43_PHY_N(0x1B8) /* RSSI multiplication coefficient 1 Q RSSI Z */
+#define B43_NPHY_RSSIMC_1Q_TBD			B43_PHY_N(0x1B9) /* RSSI multiplication coefficient 1 Q TBD */
+#define B43_NPHY_RSSIMC_1Q_PWRDET		B43_PHY_N(0x1BA) /* RSSI multiplication coefficient 1 Q power det */
+#define B43_NPHY_RSSIMC_1Q_TSSI			B43_PHY_N(0x1BB) /* RSSI multiplication coefficient 1 Q TSSI */
+#define B43_NPHY_SAMC_WCNT			B43_PHY_N(0x1BC) /* Sample collect wait counter */
+#define B43_NPHY_PTHROUGH_CNT			B43_PHY_N(0x1BD) /* Pass-through counter */
+#define B43_NPHY_LTRN_OFF_G20L			B43_PHY_N(0x1C4) /* LTRN offset gain 20L */
+#define B43_NPHY_LTRN_OFF_20L			B43_PHY_N(0x1C5) /* LTRN offset 20L */
+#define B43_NPHY_LTRN_OFF_G20U			B43_PHY_N(0x1C6) /* LTRN offset gain 20U */
+#define B43_NPHY_LTRN_OFF_20U			B43_PHY_N(0x1C7) /* LTRN offset 20U */
+#define B43_NPHY_DSSSCCK_GAINSL			B43_PHY_N(0x1C8) /* DSSS/CCK gain settle length */
+#define B43_NPHY_GPIO_LOOUT			B43_PHY_N(0x1C9) /* GPIO low out */
+#define B43_NPHY_GPIO_HIOUT			B43_PHY_N(0x1CA) /* GPIO high out */
+#define B43_NPHY_CRS_CHECK			B43_PHY_N(0x1CB) /* CRS check */
+#define B43_NPHY_ML_LOGSS_RAT			B43_PHY_N(0x1CC) /* ML/logss ratio */
+#define B43_NPHY_DUPSCALE			B43_PHY_N(0x1CD) /* Dup scale */
+#define B43_NPHY_BW1A				B43_PHY_N(0x1CE) /* BW 1A */
+#define B43_NPHY_BW2				B43_PHY_N(0x1CF) /* BW 2 */
+#define B43_NPHY_BW3				B43_PHY_N(0x1D0) /* BW 3 */
+#define B43_NPHY_BW4				B43_PHY_N(0x1D1) /* BW 4 */
+#define B43_NPHY_BW5				B43_PHY_N(0x1D2) /* BW 5 */
+#define B43_NPHY_BW6				B43_PHY_N(0x1D3) /* BW 6 */
+#define B43_NPHY_COALEN0			B43_PHY_N(0x1D4) /* Coarse length 0 */
+#define B43_NPHY_COALEN1			B43_PHY_N(0x1D5) /* Coarse length 1 */
+#define B43_NPHY_CRSTHRES_1U			B43_PHY_N(0x1D6) /* CRS threshold 1 U */
+#define B43_NPHY_CRSTHRES_2U			B43_PHY_N(0x1D7) /* CRS threshold 2 U */
+#define B43_NPHY_CRSTHRES_3U			B43_PHY_N(0x1D8) /* CRS threshold 3 U */
+#define B43_NPHY_CRSCTL_U			B43_PHY_N(0x1D9) /* CRS control U */
+#define B43_NPHY_CRSTHRES_1L			B43_PHY_N(0x1DA) /* CRS threshold 1 L */
+#define B43_NPHY_CRSTHRES_2L			B43_PHY_N(0x1DB) /* CRS threshold 2 L */
+#define B43_NPHY_CRSTHRES_3L			B43_PHY_N(0x1DC) /* CRS threshold 3 L */
+#define B43_NPHY_CRSCTL_L			B43_PHY_N(0x1DD) /* CRS control L */
+#define B43_NPHY_STRA_1U			B43_PHY_N(0x1DE) /* STR address 1 U */
+#define B43_NPHY_STRA_2U			B43_PHY_N(0x1DF) /* STR address 2 U */
+#define B43_NPHY_STRA_1L			B43_PHY_N(0x1E0) /* STR address 1 L */
+#define B43_NPHY_STRA_2L			B43_PHY_N(0x1E1) /* STR address 2 L */
+#define B43_NPHY_CRSCHECK1			B43_PHY_N(0x1E2) /* CRS check 1 */
+#define B43_NPHY_CRSCHECK2			B43_PHY_N(0x1E3) /* CRS check 2 */
+#define B43_NPHY_CRSCHECK3			B43_PHY_N(0x1E4) /* CRS check 3 */
+#define B43_NPHY_JMPSTP0			B43_PHY_N(0x1E5) /* Jump step 0 */
+#define B43_NPHY_JMPSTP1			B43_PHY_N(0x1E6) /* Jump step 1 */
+#define B43_NPHY_TXPCTL_CMD			B43_PHY_N(0x1E7) /* TX power control command */
+#define  B43_NPHY_TXPCTL_CMD_INIT		0x007F /* Init */
+#define  B43_NPHY_TXPCTL_CMD_INIT_SHIFT		0
+#define  B43_NPHY_TXPCTL_CMD_COEFF		0x2000 /* Power control coefficients */
+#define  B43_NPHY_TXPCTL_CMD_HWPCTLEN		0x4000 /* Hardware TX power control enable */
+#define  B43_NPHY_TXPCTL_CMD_PCTLEN		0x8000 /* TX power control enable */
+#define B43_NPHY_TXPCTL_N			B43_PHY_N(0x1E8) /* TX power control N num */
+#define  B43_NPHY_TXPCTL_N_TSSID		0x00FF /* N TSSI delay */
+#define  B43_NPHY_TXPCTL_N_TSSID_SHIFT		0
+#define  B43_NPHY_TXPCTL_N_NPTIL2		0x0700 /* N PT integer log2 */
+#define  B43_NPHY_TXPCTL_N_NPTIL2_SHIFT		8
+#define B43_NPHY_TXPCTL_ITSSI			B43_PHY_N(0x1E9) /* TX power control idle TSSI */
+#define  B43_NPHY_TXPCTL_ITSSI_0		0x003F /* Idle TSSI 0 */
+#define  B43_NPHY_TXPCTL_ITSSI_0_SHIFT		0
+#define  B43_NPHY_TXPCTL_ITSSI_1		0x3F00 /* Idle TSSI 1 */
+#define  B43_NPHY_TXPCTL_ITSSI_1_SHIFT		8
+#define  B43_NPHY_TXPCTL_ITSSI_BINF		0x8000 /* Raw TSSI offset bin format */
+#define B43_NPHY_TXPCTL_TPWR			B43_PHY_N(0x1EA) /* TX power control target power */
+#define  B43_NPHY_TXPCTL_TPWR_0			0x00FF /* Power 0 */
+#define  B43_NPHY_TXPCTL_TPWR_0_SHIFT		0
+#define  B43_NPHY_TXPCTL_TPWR_1			0xFF00 /* Power 1 */
+#define  B43_NPHY_TXPCTL_TPWR_1_SHIFT		8
+#define B43_NPHY_TXPCTL_BIDX			B43_PHY_N(0x1EB) /* TX power control base index */
+#define  B43_NPHY_TXPCTL_BIDX_0			0x007F /* uC base index 0 */
+#define  B43_NPHY_TXPCTL_BIDX_0_SHIFT		0
+#define  B43_NPHY_TXPCTL_BIDX_1			0x7F00 /* uC base index 1 */
+#define  B43_NPHY_TXPCTL_BIDX_1_SHIFT		8
+#define  B43_NPHY_TXPCTL_BIDX_LOAD		0x8000 /* Load base index */
+#define B43_NPHY_TXPCTL_PIDX			B43_PHY_N(0x1EC) /* TX power control power index */
+#define  B43_NPHY_TXPCTL_PIDX_0			0x007F /* uC power index 0 */
+#define  B43_NPHY_TXPCTL_PIDX_0_SHIFT		0
+#define  B43_NPHY_TXPCTL_PIDX_1			0x7F00 /* uC power index 1 */
+#define  B43_NPHY_TXPCTL_PIDX_1_SHIFT		8
+#define B43_NPHY_C1_TXPCTL_STAT			B43_PHY_N(0x1ED) /* Core 1 TX power control status */
+#define B43_NPHY_C2_TXPCTL_STAT			B43_PHY_N(0x1EE) /* Core 2 TX power control status */
+#define  B43_NPHY_TXPCTL_STAT_EST		0x00FF /* Estimated power */
+#define  B43_NPHY_TXPCTL_STAT_EST_SHIFT		0
+#define  B43_NPHY_TXPCTL_STAT_BIDX		0x7F00 /* Base index */
+#define  B43_NPHY_TXPCTL_STAT_BIDX_SHIFT	8
+#define  B43_NPHY_TXPCTL_STAT_ESTVALID		0x8000 /* Estimated power valid */
+#define B43_NPHY_SMALLSGS_LEN			B43_PHY_N(0x1EF) /* Small sig gain settle length */
+#define B43_NPHY_PHYSTAT_GAIN0			B43_PHY_N(0x1F0) /* PHY stats gain info 0 */
+#define B43_NPHY_PHYSTAT_GAIN1			B43_PHY_N(0x1F1) /* PHY stats gain info 1 */
+#define B43_NPHY_PHYSTAT_FREQEST		B43_PHY_N(0x1F2) /* PHY stats frequency estimate */
+#define B43_NPHY_PHYSTAT_ADVRET			B43_PHY_N(0x1F3) /* PHY stats ADV retard */
+#define B43_NPHY_PHYLB_MODE			B43_PHY_N(0x1F4) /* PHY loopback mode */
+#define B43_NPHY_TONE_MIDX20_1			B43_PHY_N(0x1F5) /* Tone map index 20/1 */
+#define B43_NPHY_TONE_MIDX20_2			B43_PHY_N(0x1F6) /* Tone map index 20/2 */
+#define B43_NPHY_TONE_MIDX20_3			B43_PHY_N(0x1F7) /* Tone map index 20/3 */
+#define B43_NPHY_TONE_MIDX40_1			B43_PHY_N(0x1F8) /* Tone map index 40/1 */
+#define B43_NPHY_TONE_MIDX40_2			B43_PHY_N(0x1F9) /* Tone map index 40/2 */
+#define B43_NPHY_TONE_MIDX40_3			B43_PHY_N(0x1FA) /* Tone map index 40/3 */
+#define B43_NPHY_TONE_MIDX40_4			B43_PHY_N(0x1FB) /* Tone map index 40/4 */
+#define B43_NPHY_PILTONE_MIDX1			B43_PHY_N(0x1FC) /* Pilot tone map index 1 */
+#define B43_NPHY_PILTONE_MIDX2			B43_PHY_N(0x1FD) /* Pilot tone map index 2 */
+#define B43_NPHY_PILTONE_MIDX3			B43_PHY_N(0x1FE) /* Pilot tone map index 3 */
+#define B43_NPHY_TXRIFS_FRDEL			B43_PHY_N(0x1FF) /* TX RIFS frame delay */
+#define B43_NPHY_AFESEQ_RX2TX_PUD_40M		B43_PHY_N(0x200) /* AFE seq rx2tx power up/down delay 40M */
+#define B43_NPHY_AFESEQ_TX2RX_PUD_40M		B43_PHY_N(0x201) /* AFE seq tx2rx power up/down delay 40M */
+#define B43_NPHY_AFESEQ_RX2TX_PUD_20M		B43_PHY_N(0x202) /* AFE seq rx2tx power up/down delay 20M */
+#define B43_NPHY_AFESEQ_TX2RX_PUD_20M		B43_PHY_N(0x203) /* AFE seq tx2rx power up/down delay 20M */
+#define B43_NPHY_RX_SIGCTL			B43_PHY_N(0x204) /* RX signal control */
+#define B43_NPHY_RXPIL_CYCNT0			B43_PHY_N(0x205) /* RX pilot cycle counter 0 */
+#define B43_NPHY_RXPIL_CYCNT1			B43_PHY_N(0x206) /* RX pilot cycle counter 1 */
+#define B43_NPHY_RXPIL_CYCNT2			B43_PHY_N(0x207) /* RX pilot cycle counter 2 */
+#define B43_NPHY_AFESEQ_RX2TX_PUD_10M		B43_PHY_N(0x208) /* AFE seq rx2tx power up/down delay 10M */
+#define B43_NPHY_AFESEQ_TX2RX_PUD_10M		B43_PHY_N(0x209) /* AFE seq tx2rx power up/down delay 10M */
+#define B43_NPHY_DSSSCCK_CRSEXTL		B43_PHY_N(0x20A) /* DSSS/CCK CRS extension length */
+#define B43_NPHY_ML_LOGSS_RATSLOPE		B43_PHY_N(0x20B) /* ML/logss ratio slope */
+#define B43_NPHY_RIFS_SRCTL			B43_PHY_N(0x20C) /* RIFS search timeout length */
+#define B43_NPHY_TXREALFD			B43_PHY_N(0x20D) /* TX real frame delay */
+#define B43_NPHY_HPANT_SWTHRES			B43_PHY_N(0x20E) /* High power antenna switch threshold */
+#define B43_NPHY_EDCRS_ASSTHRES0		B43_PHY_N(0x210) /* ED CRS assert threshold 0 */
+#define B43_NPHY_EDCRS_ASSTHRES1		B43_PHY_N(0x211) /* ED CRS assert threshold 1 */
+#define B43_NPHY_EDCRS_DEASSTHRES0		B43_PHY_N(0x212) /* ED CRS deassert threshold 0 */
+#define B43_NPHY_EDCRS_DEASSTHRES1		B43_PHY_N(0x213) /* ED CRS deassert threshold 1 */
+#define B43_NPHY_STR_WTIME20U			B43_PHY_N(0x214) /* STR wait time 20U */
+#define B43_NPHY_STR_WTIME20L			B43_PHY_N(0x215) /* STR wait time 20L */
+#define B43_NPHY_TONE_MIDX657M			B43_PHY_N(0x216) /* Tone map index 657M */
+#define B43_NPHY_HTSIGTONES			B43_PHY_N(0x217) /* HT signal tones */
+#define B43_NPHY_RSSI1				B43_PHY_N(0x219) /* RSSI value 1 */
+#define B43_NPHY_RSSI2				B43_PHY_N(0x21A) /* RSSI value 2 */
+#define B43_NPHY_CHAN_ESTHANG			B43_PHY_N(0x21D) /* Channel estimate hang */
+#define B43_NPHY_FINERX2_CGC			B43_PHY_N(0x221) /* Fine RX 2 clock gate control */
+#define  B43_NPHY_FINERX2_CGC_DECGC		0x0008 /* Decode gated clocks */
+#define B43_NPHY_TXPCTL_INIT			B43_PHY_N(0x222) /* TX power controll init */
+#define  B43_NPHY_TXPCTL_INIT_PIDXI1		0x00FF /* Power index init 1 */
+#define  B43_NPHY_TXPCTL_INIT_PIDXI1_SHIFT	0
+
+
+
+/* Broadcom 2055 radio registers */
+
+#define B2055_GEN_SPARE			0x00 /* GEN spare */
+#define B2055_SP_PINPD			0x02 /* SP PIN PD */
+#define B2055_C1_SP_RSSI		0x03 /* SP RSSI Core 1 */
+#define B2055_C1_SP_PDMISC		0x04 /* SP PD MISC Core 1 */
+#define B2055_C2_SP_RSSI		0x05 /* SP RSSI Core 2 */
+#define B2055_C2_SP_PDMISC		0x06 /* SP PD MISC Core 2 */
+#define B2055_C1_SP_RXGC1		0x07 /* SP RX GC1 Core 1 */
+#define B2055_C1_SP_RXGC2		0x08 /* SP RX GC2 Core 1 */
+#define B2055_C2_SP_RXGC1		0x09 /* SP RX GC1 Core 2 */
+#define B2055_C2_SP_RXGC2		0x0A /* SP RX GC2 Core 2 */
+#define B2055_C1_SP_LPFBWSEL		0x0B /* SP LPF BW select Core 1 */
+#define B2055_C2_SP_LPFBWSEL		0x0C /* SP LPF BW select Core 2 */
+#define B2055_C1_SP_TXGC1		0x0D /* SP TX GC1 Core 1 */
+#define B2055_C1_SP_TXGC2		0x0E /* SP TX GC2 Core 1 */
+#define B2055_C2_SP_TXGC1		0x0F /* SP TX GC1 Core 2 */
+#define B2055_C2_SP_TXGC2		0x10 /* SP TX GC2 Core 2 */
+#define B2055_MASTER1			0x11 /* Master control 1 */
+#define B2055_MASTER2			0x12 /* Master control 2 */
+#define B2055_PD_LGEN			0x13 /* PD LGEN */
+#define B2055_PD_PLLTS			0x14 /* PD PLL TS */
+#define B2055_C1_PD_LGBUF		0x15 /* PD Core 1 LGBUF */
+#define B2055_C1_PD_TX			0x16 /* PD Core 1 TX */
+#define B2055_C1_PD_RXTX		0x17 /* PD Core 1 RXTX */
+#define B2055_C1_PD_RSSIMISC		0x18 /* PD Core 1 RSSI MISC */
+#define B2055_C2_PD_LGBUF		0x19 /* PD Core 2 LGBUF */
+#define B2055_C2_PD_TX			0x1A /* PD Core 2 TX */
+#define B2055_C2_PD_RXTX		0x1B /* PD Core 2 RXTX */
+#define B2055_C2_PD_RSSIMISC		0x1C /* PD Core 2 RSSI MISC */
+#define B2055_PWRDET_LGEN		0x1D /* PWRDET LGEN */
+#define B2055_C1_PWRDET_LGBUF		0x1E /* PWRDET LGBUF Core 1 */
+#define B2055_C1_PWRDET_RXTX		0x1F /* PWRDET RXTX Core 1 */
+#define B2055_C2_PWRDET_LGBUF		0x20 /* PWRDET LGBUF Core 2 */
+#define B2055_C2_PWRDET_RXTX		0x21 /* PWRDET RXTX Core 2 */
+#define B2055_RRCCAL_CS			0x22 /* RRCCAL Control spare */
+#define B2055_RRCCAL_NOPTSEL		0x23 /* RRCCAL N OPT SEL */
+#define B2055_CAL_MISC			0x24 /* CAL MISC */
+#define B2055_CAL_COUT			0x25 /* CAL Counter out */
+#define B2055_CAL_COUT2			0x26 /* CAL Counter out 2 */
+#define B2055_CAL_CVARCTL		0x27 /* CAL CVAR Control */
+#define B2055_CAL_RVARCTL		0x28 /* CAL RVAR Control */
+#define B2055_CAL_LPOCTL		0x29 /* CAL LPO Control */
+#define B2055_CAL_TS			0x2A /* CAL TS */
+#define B2055_CAL_RCCALRTS		0x2B /* CAL RCCAL READ TS */
+#define B2055_CAL_RCALRTS		0x2C /* CAL RCAL READ TS */
+#define B2055_PADDRV			0x2D /* PAD driver */
+#define B2055_XOCTL1			0x2E /* XO Control 1 */
+#define B2055_XOCTL2			0x2F /* XO Control 2 */
+#define B2055_XOREGUL			0x30 /* XO Regulator */
+#define B2055_XOMISC			0x31 /* XO misc */
+#define B2055_PLL_LFC1			0x32 /* PLL LF C1 */
+#define B2055_PLL_CALVTH		0x33 /* PLL CAL VTH */
+#define B2055_PLL_LFC2			0x34 /* PLL LF C2 */
+#define B2055_PLL_REF			0x35 /* PLL reference */
+#define B2055_PLL_LFR1			0x36 /* PLL LF R1 */
+#define B2055_PLL_PFDCP			0x37 /* PLL PFD CP */
+#define B2055_PLL_IDAC_CPOPAMP		0x38 /* PLL IDAC CPOPAMP */
+#define B2055_PLL_CPREG			0x39 /* PLL CP Regulator */
+#define B2055_PLL_RCAL			0x3A /* PLL RCAL */
+#define B2055_RF_PLLMOD0		0x3B /* RF PLL MOD0 */
+#define B2055_RF_PLLMOD1		0x3C /* RF PLL MOD1 */
+#define B2055_RF_MMDIDAC1		0x3D /* RF MMD IDAC 1 */
+#define B2055_RF_MMDIDAC0		0x3E /* RF MMD IDAC 0 */
+#define B2055_RF_MMDSP			0x3F /* RF MMD spare */
+#define B2055_VCO_CAL1			0x40 /* VCO cal 1 */
+#define B2055_VCO_CAL2			0x41 /* VCO cal 2 */
+#define B2055_VCO_CAL3			0x42 /* VCO cal 3 */
+#define B2055_VCO_CAL4			0x43 /* VCO cal 4 */
+#define B2055_VCO_CAL5			0x44 /* VCO cal 5 */
+#define B2055_VCO_CAL6			0x45 /* VCO cal 6 */
+#define B2055_VCO_CAL7			0x46 /* VCO cal 7 */
+#define B2055_VCO_CAL8			0x47 /* VCO cal 8 */
+#define B2055_VCO_CAL9			0x48 /* VCO cal 9 */
+#define B2055_VCO_CAL10			0x49 /* VCO cal 10 */
+#define B2055_VCO_CAL11			0x4A /* VCO cal 11 */
+#define B2055_VCO_CAL12			0x4B /* VCO cal 12 */
+#define B2055_VCO_CAL13			0x4C /* VCO cal 13 */
+#define B2055_VCO_CAL14			0x4D /* VCO cal 14 */
+#define B2055_VCO_CAL15			0x4E /* VCO cal 15 */
+#define B2055_VCO_CAL16			0x4F /* VCO cal 16 */
+#define B2055_VCO_KVCO			0x50 /* VCO KVCO */
+#define B2055_VCO_CAPTAIL		0x51 /* VCO CAP TAIL */
+#define B2055_VCO_IDACVCO		0x52 /* VCO IDAC VCO */
+#define B2055_VCO_REG			0x53 /* VCO Regulator */
+#define B2055_PLL_RFVTH			0x54 /* PLL RF VTH */
+#define B2055_LGBUF_CENBUF		0x55 /* LGBUF CEN BUF */
+#define B2055_LGEN_TUNE1		0x56 /* LGEN tune 1 */
+#define B2055_LGEN_TUNE2		0x57 /* LGEN tune 2 */
+#define B2055_LGEN_IDAC1		0x58 /* LGEN IDAC 1 */
+#define B2055_LGEN_IDAC2		0x59 /* LGEN IDAC 2 */
+#define B2055_LGEN_BIASC		0x5A /* LGEN BIAS counter */
+#define B2055_LGEN_BIASIDAC		0x5B /* LGEN BIAS IDAC */
+#define B2055_LGEN_RCAL			0x5C /* LGEN RCAL */
+#define B2055_LGEN_DIV			0x5D /* LGEN div */
+#define B2055_LGEN_SPARE2		0x5E /* LGEN spare 2 */
+#define B2055_C1_LGBUF_ATUNE		0x5F /* Core 1 LGBUF A tune */
+#define B2055_C1_LGBUF_GTUNE		0x60 /* Core 1 LGBUF G tune */
+#define B2055_C1_LGBUF_DIV		0x61 /* Core 1 LGBUF div */
+#define B2055_C1_LGBUF_AIDAC		0x62 /* Core 1 LGBUF A IDAC */
+#define B2055_C1_LGBUF_GIDAC		0x63 /* Core 1 LGBUF G IDAC */
+#define B2055_C1_LGBUF_IDACFO		0x64 /* Core 1 LGBUF IDAC filter override */
+#define B2055_C1_LGBUF_SPARE		0x65 /* Core 1 LGBUF spare */
+#define B2055_C1_RX_RFSPC1		0x66 /* Core 1 RX RF SPC1 */
+#define B2055_C1_RX_RFR1		0x67 /* Core 1 RX RF reg 1 */
+#define B2055_C1_RX_RFR2		0x68 /* Core 1 RX RF reg 2 */
+#define B2055_C1_RX_RFRCAL		0x69 /* Core 1 RX RF RCAL */
+#define B2055_C1_RX_BB_BLCMP		0x6A /* Core 1 RX Baseband BUFI LPF CMP */
+#define B2055_C1_RX_BB_LPF		0x6B /* Core 1 RX Baseband LPF */
+#define B2055_C1_RX_BB_MIDACHP		0x6C /* Core 1 RX Baseband MIDAC High-pass */
+#define B2055_C1_RX_BB_VGA1IDAC		0x6D /* Core 1 RX Baseband VGA1 IDAC */
+#define B2055_C1_RX_BB_VGA2IDAC		0x6E /* Core 1 RX Baseband VGA2 IDAC */
+#define B2055_C1_RX_BB_VGA3IDAC		0x6F /* Core 1 RX Baseband VGA3 IDAC */
+#define B2055_C1_RX_BB_BUFOCTL		0x70 /* Core 1 RX Baseband BUFO Control */
+#define B2055_C1_RX_BB_RCCALCTL		0x71 /* Core 1 RX Baseband RCCAL Control */
+#define B2055_C1_RX_BB_RSSICTL1		0x72 /* Core 1 RX Baseband RSSI Control 1 */
+#define B2055_C1_RX_BB_RSSICTL2		0x73 /* Core 1 RX Baseband RSSI Control 2 */
+#define B2055_C1_RX_BB_RSSICTL3		0x74 /* Core 1 RX Baseband RSSI Control 3 */
+#define B2055_C1_RX_BB_RSSICTL4		0x75 /* Core 1 RX Baseband RSSI Control 4 */
+#define B2055_C1_RX_BB_RSSICTL5		0x76 /* Core 1 RX Baseband RSSI Control 5 */
+#define B2055_C1_RX_BB_REG		0x77 /* Core 1 RX Baseband Regulator */
+#define B2055_C1_RX_BB_SPARE1		0x78 /* Core 1 RX Baseband spare 1 */
+#define B2055_C1_RX_TXBBRCAL		0x79 /* Core 1 RX TX BB RCAL */
+#define B2055_C1_TX_RF_SPGA		0x7A /* Core 1 TX RF SGM PGA */
+#define B2055_C1_TX_RF_SPAD		0x7B /* Core 1 TX RF SGM PAD */
+#define B2055_C1_TX_RF_CNTPGA1		0x7C /* Core 1 TX RF counter PGA 1 */
+#define B2055_C1_TX_RF_CNTPAD1		0x7D /* Core 1 TX RF counter PAD 1 */
+#define B2055_C1_TX_RF_PGAIDAC		0x7E /* Core 1 TX RF PGA IDAC */
+#define B2055_C1_TX_PGAPADTN		0x7F /* Core 1 TX PGA PAD TN */
+#define B2055_C1_TX_PADIDAC1		0x80 /* Core 1 TX PAD IDAC 1 */
+#define B2055_C1_TX_PADIDAC2		0x81 /* Core 1 TX PAD IDAC 2 */
+#define B2055_C1_TX_MXBGTRIM		0x82 /* Core 1 TX MX B/G TRIM */
+#define B2055_C1_TX_RF_RCAL		0x83 /* Core 1 TX RF RCAL */
+#define B2055_C1_TX_RF_PADTSSI1		0x84 /* Core 1 TX RF PAD TSSI1 */
+#define B2055_C1_TX_RF_PADTSSI2		0x85 /* Core 1 TX RF PAD TSSI2 */
+#define B2055_C1_TX_RF_SPARE		0x86 /* Core 1 TX RF spare */
+#define B2055_C1_TX_RF_IQCAL1		0x87 /* Core 1 TX RF I/Q CAL 1 */
+#define B2055_C1_TX_RF_IQCAL2		0x88 /* Core 1 TX RF I/Q CAL 2 */
+#define B2055_C1_TXBB_RCCAL		0x89 /* Core 1 TXBB RC CAL Control */
+#define B2055_C1_TXBB_LPF1		0x8A /* Core 1 TXBB LPF 1 */
+#define B2055_C1_TX_VOSCNCL		0x8B /* Core 1 TX VOS CNCL */
+#define B2055_C1_TX_LPF_MXGMIDAC	0x8C /* Core 1 TX LPF MXGM IDAC */
+#define B2055_C1_TX_BB_MXGM		0x8D /* Core 1 TX BB MXGM */
+#define B2055_C2_LGBUF_ATUNE		0x8E /* Core 2 LGBUF A tune */
+#define B2055_C2_LGBUF_GTUNE		0x8F /* Core 2 LGBUF G tune */
+#define B2055_C2_LGBUF_DIV		0x90 /* Core 2 LGBUF div */
+#define B2055_C2_LGBUF_AIDAC		0x91 /* Core 2 LGBUF A IDAC */
+#define B2055_C2_LGBUF_GIDAC		0x92 /* Core 2 LGBUF G IDAC */
+#define B2055_C2_LGBUF_IDACFO		0x93 /* Core 2 LGBUF IDAC filter override */
+#define B2055_C2_LGBUF_SPARE		0x94 /* Core 2 LGBUF spare */
+#define B2055_C2_RX_RFSPC1		0x95 /* Core 2 RX RF SPC1 */
+#define B2055_C2_RX_RFR1		0x96 /* Core 2 RX RF reg 1 */
+#define B2055_C2_RX_RFR2		0x97 /* Core 2 RX RF reg 2 */
+#define B2055_C2_RX_RFRCAL		0x98 /* Core 2 RX RF RCAL */
+#define B2055_C2_RX_BB_BLCMP		0x99 /* Core 2 RX Baseband BUFI LPF CMP */
+#define B2055_C2_RX_BB_LPF		0x9A /* Core 2 RX Baseband LPF */
+#define B2055_C2_RX_BB_MIDACHP		0x9B /* Core 2 RX Baseband MIDAC High-pass */
+#define B2055_C2_RX_BB_VGA1IDAC		0x9C /* Core 2 RX Baseband VGA1 IDAC */
+#define B2055_C2_RX_BB_VGA2IDAC		0x9D /* Core 2 RX Baseband VGA2 IDAC */
+#define B2055_C2_RX_BB_VGA3IDAC		0x9E /* Core 2 RX Baseband VGA3 IDAC */
+#define B2055_C2_RX_BB_BUFOCTL		0x9F /* Core 2 RX Baseband BUFO Control */
+#define B2055_C2_RX_BB_RCCALCTL		0xA0 /* Core 2 RX Baseband RCCAL Control */
+#define B2055_C2_RX_BB_RSSICTL1		0xA1 /* Core 2 RX Baseband RSSI Control 1 */
+#define B2055_C2_RX_BB_RSSICTL2		0xA2 /* Core 2 RX Baseband RSSI Control 2 */
+#define B2055_C2_RX_BB_RSSICTL3		0xA3 /* Core 2 RX Baseband RSSI Control 3 */
+#define B2055_C2_RX_BB_RSSICTL4		0xA4 /* Core 2 RX Baseband RSSI Control 4 */
+#define B2055_C2_RX_BB_RSSICTL5		0xA5 /* Core 2 RX Baseband RSSI Control 5 */
+#define B2055_C2_RX_BB_REG		0xA6 /* Core 2 RX Baseband Regulator */
+#define B2055_C2_RX_BB_SPARE1		0xA7 /* Core 2 RX Baseband spare 1 */
+#define B2055_C2_RX_TXBBRCAL		0xA8 /* Core 2 RX TX BB RCAL */
+#define B2055_C2_TX_RF_SPGA		0xA9 /* Core 2 TX RF SGM PGA */
+#define B2055_C2_TX_RF_SPAD		0xAA /* Core 2 TX RF SGM PAD */
+#define B2055_C2_TX_RF_CNTPGA1		0xAB /* Core 2 TX RF counter PGA 1 */
+#define B2055_C2_TX_RF_CNTPAD1		0xAC /* Core 2 TX RF counter PAD 1 */
+#define B2055_C2_TX_RF_PGAIDAC		0xAD /* Core 2 TX RF PGA IDAC */
+#define B2055_C2_TX_PGAPADTN		0xAE /* Core 2 TX PGA PAD TN */
+#define B2055_C2_TX_PADIDAC1		0xAF /* Core 2 TX PAD IDAC 1 */
+#define B2055_C2_TX_PADIDAC2		0xB0 /* Core 2 TX PAD IDAC 2 */
+#define B2055_C2_TX_MXBGTRIM		0xB1 /* Core 2 TX MX B/G TRIM */
+#define B2055_C2_TX_RF_RCAL		0xB2 /* Core 2 TX RF RCAL */
+#define B2055_C2_TX_RF_PADTSSI1		0xB3 /* Core 2 TX RF PAD TSSI1 */
+#define B2055_C2_TX_RF_PADTSSI2		0xB4 /* Core 2 TX RF PAD TSSI2 */
+#define B2055_C2_TX_RF_SPARE		0xB5 /* Core 2 TX RF spare */
+#define B2055_C2_TX_RF_IQCAL1		0xB6 /* Core 2 TX RF I/Q CAL 1 */
+#define B2055_C2_TX_RF_IQCAL2		0xB7 /* Core 2 TX RF I/Q CAL 2 */
+#define B2055_C2_TXBB_RCCAL		0xB8 /* Core 2 TXBB RC CAL Control */
+#define B2055_C2_TXBB_LPF1		0xB9 /* Core 2 TXBB LPF 1 */
+#define B2055_C2_TX_VOSCNCL		0xBA /* Core 2 TX VOS CNCL */
+#define B2055_C2_TX_LPF_MXGMIDAC	0xBB /* Core 2 TX LPF MXGM IDAC */
+#define B2055_C2_TX_BB_MXGM		0xBC /* Core 2 TX BB MXGM */
+#define B2055_PRG_GCHP21		0xBD /* PRG GC HPVGA23 21 */
+#define B2055_PRG_GCHP22		0xBE /* PRG GC HPVGA23 22 */
+#define B2055_PRG_GCHP23		0xBF /* PRG GC HPVGA23 23 */
+#define B2055_PRG_GCHP24		0xC0 /* PRG GC HPVGA23 24 */
+#define B2055_PRG_GCHP25		0xC1 /* PRG GC HPVGA23 25 */
+#define B2055_PRG_GCHP26		0xC2 /* PRG GC HPVGA23 26 */
+#define B2055_PRG_GCHP27		0xC3 /* PRG GC HPVGA23 27 */
+#define B2055_PRG_GCHP28		0xC4 /* PRG GC HPVGA23 28 */
+#define B2055_PRG_GCHP29		0xC5 /* PRG GC HPVGA23 29 */
+#define B2055_PRG_GCHP30		0xC6 /* PRG GC HPVGA23 30 */
+#define B2055_C1_LNA_GAINBST		0xCD /* Core 1 LNA GAINBST */
+#define B2055_C1_B0NB_RSSIVCM		0xD2 /* Core 1 B0 narrow-band RSSI VCM */
+#define B2055_C1_GENSPARE2		0xD6 /* Core 1 GEN spare 2 */
+#define B2055_C2_LNA_GAINBST		0xD9 /* Core 2 LNA GAINBST */
+#define B2055_C2_B0NB_RSSIVCM		0xDE /* Core 2 B0 narrow-band RSSI VCM */
+#define B2055_C2_GENSPARE2		0xE2 /* Core 2 GEN spare 2 */
+
+
+
+struct b43_wldev;
+
+struct b43_phy_n {
+	//TODO lots of missing stuff
+};
+
+
+struct b43_phy_operations;
+extern const struct b43_phy_operations b43_phyops_n;
+
+#endif /* B43_NPHY_H_ */
diff --git a/drivers/net/wireless/b43/rfkill.c b/drivers/net/wireless/b43/rfkill.c
index fec5645..7137537 100644
--- a/drivers/net/wireless/b43/rfkill.c
+++ b/drivers/net/wireless/b43/rfkill.c
@@ -24,6 +24,7 @@
 
 #include "rfkill.h"
 #include "b43.h"
+#include "phy_common.h"
 
 #include <linux/kmod.h>
 
@@ -43,23 +44,6 @@
 	return 0;
 }
 
-/* Update the rfkill state */
-static void b43_rfkill_update_state(struct b43_wldev *dev)
-{
-	struct b43_rfkill *rfk = &(dev->wl->rfkill);
-
-	if (!dev->radio_hw_enable) {
-		rfk->rfkill->state = RFKILL_STATE_HARD_BLOCKED;
-		return;
-	}
-
-	if (!dev->phy.radio_on)
-		rfk->rfkill->state = RFKILL_STATE_SOFT_BLOCKED;
-	else
-		rfk->rfkill->state = RFKILL_STATE_UNBLOCKED;
-
-}
-
 /* The poll callback for the hardware button. */
 static void b43_rfkill_poll(struct input_polled_dev *poll_dev)
 {
@@ -77,7 +61,6 @@
 	if (unlikely(enabled != dev->radio_hw_enable)) {
 		dev->radio_hw_enable = enabled;
 		report_change = 1;
-		b43_rfkill_update_state(dev);
 		b43info(wl, "Radio hardware status changed to %s\n",
 			enabled ? "ENABLED" : "DISABLED");
 	}
@@ -114,11 +97,11 @@
 			goto out_unlock;
 		}
 		if (!dev->phy.radio_on)
-			b43_radio_turn_on(dev);
+			b43_software_rfkill(dev, state);
 		break;
 	case RFKILL_STATE_SOFT_BLOCKED:
 		if (dev->phy.radio_on)
-			b43_radio_turn_off(dev, 0);
+			b43_software_rfkill(dev, state);
 		break;
 	default:
 		b43warn(wl, "Received unexpected rfkill state %d.\n", state);
@@ -187,6 +170,11 @@
 			"The built-in radio LED will not work.\n");
 #endif /* CONFIG_RFKILL_INPUT */
 
+#if !defined(CONFIG_RFKILL_INPUT) && !defined(CONFIG_RFKILL_INPUT_MODULE)
+	b43warn(wl, "The rfkill-input subsystem is not available. "
+		"The built-in radio LED will not work.\n");
+#endif
+
 	err = input_register_polled_device(rfk->poll_dev);
 	if (err)
 		goto err_unreg_rfk;
diff --git a/drivers/net/wireless/b43/sysfs.c b/drivers/net/wireless/b43/sysfs.c
index 275095b..5adaa36 100644
--- a/drivers/net/wireless/b43/sysfs.c
+++ b/drivers/net/wireless/b43/sysfs.c
@@ -29,7 +29,7 @@
 #include "b43.h"
 #include "sysfs.h"
 #include "main.h"
-#include "phy.h"
+#include "phy_common.h"
 
 #define GENERIC_FILESIZE	64
 
@@ -59,7 +59,12 @@
 
 	mutex_lock(&wldev->wl->mutex);
 
-	switch (wldev->phy.interfmode) {
+	if (wldev->phy.type != B43_PHYTYPE_G) {
+		mutex_unlock(&wldev->wl->mutex);
+		return -ENOSYS;
+	}
+
+	switch (wldev->phy.g->interfmode) {
 	case B43_INTERFMODE_NONE:
 		count =
 		    snprintf(buf, PAGE_SIZE,
@@ -117,11 +122,15 @@
 	mutex_lock(&wldev->wl->mutex);
 	spin_lock_irqsave(&wldev->wl->irq_lock, flags);
 
-	err = b43_radio_set_interference_mitigation(wldev, mode);
-	if (err) {
-		b43err(wldev->wl, "Interference Mitigation not "
-		       "supported by device\n");
-	}
+	if (wldev->phy.ops->interf_mitigation) {
+		err = wldev->phy.ops->interf_mitigation(wldev, mode);
+		if (err) {
+			b43err(wldev->wl, "Interference Mitigation not "
+			       "supported by device\n");
+		}
+	} else
+		err = -ENOSYS;
+
 	mmiowb();
 	spin_unlock_irqrestore(&wldev->wl->irq_lock, flags);
 	mutex_unlock(&wldev->wl->mutex);
diff --git a/drivers/net/wireless/b43/tables.c b/drivers/net/wireless/b43/tables.c
index 3f5ea06..1ef9a64 100644
--- a/drivers/net/wireless/b43/tables.c
+++ b/drivers/net/wireless/b43/tables.c
@@ -27,7 +27,8 @@
 
 #include "b43.h"
 #include "tables.h"
-#include "phy.h"
+#include "phy_g.h"
+
 
 const u32 b43_tab_rotor[] = {
 	0xFEB93FFD, 0xFEC63FFD,	/* 0 */
@@ -377,17 +378,17 @@
 
 u16 b43_ofdmtab_read16(struct b43_wldev *dev, u16 table, u16 offset)
 {
-	struct b43_phy *phy = &dev->phy;
+	struct b43_phy_g *gphy = dev->phy.g;
 	u16 addr;
 
 	addr = table + offset;
-	if ((phy->ofdmtab_addr_direction != B43_OFDMTAB_DIRECTION_READ) ||
-	    (addr - 1 != phy->ofdmtab_addr)) {
+	if ((gphy->ofdmtab_addr_direction != B43_OFDMTAB_DIRECTION_READ) ||
+	    (addr - 1 != gphy->ofdmtab_addr)) {
 		/* The hardware has a different address in memory. Update it. */
 		b43_phy_write(dev, B43_PHY_OTABLECTL, addr);
-		phy->ofdmtab_addr_direction = B43_OFDMTAB_DIRECTION_READ;
+		gphy->ofdmtab_addr_direction = B43_OFDMTAB_DIRECTION_READ;
 	}
-	phy->ofdmtab_addr = addr;
+	gphy->ofdmtab_addr = addr;
 
 	return b43_phy_read(dev, B43_PHY_OTABLEI);
 
@@ -398,34 +399,34 @@
 void b43_ofdmtab_write16(struct b43_wldev *dev, u16 table,
 			 u16 offset, u16 value)
 {
-	struct b43_phy *phy = &dev->phy;
+	struct b43_phy_g *gphy = dev->phy.g;
 	u16 addr;
 
 	addr = table + offset;
-	if ((phy->ofdmtab_addr_direction != B43_OFDMTAB_DIRECTION_WRITE) ||
-	    (addr - 1 != phy->ofdmtab_addr)) {
+	if ((gphy->ofdmtab_addr_direction != B43_OFDMTAB_DIRECTION_WRITE) ||
+	    (addr - 1 != gphy->ofdmtab_addr)) {
 		/* The hardware has a different address in memory. Update it. */
 		b43_phy_write(dev, B43_PHY_OTABLECTL, addr);
-		phy->ofdmtab_addr_direction = B43_OFDMTAB_DIRECTION_WRITE;
+		gphy->ofdmtab_addr_direction = B43_OFDMTAB_DIRECTION_WRITE;
 	}
-	phy->ofdmtab_addr = addr;
+	gphy->ofdmtab_addr = addr;
 	b43_phy_write(dev, B43_PHY_OTABLEI, value);
 }
 
 u32 b43_ofdmtab_read32(struct b43_wldev *dev, u16 table, u16 offset)
 {
-	struct b43_phy *phy = &dev->phy;
+	struct b43_phy_g *gphy = dev->phy.g;
 	u32 ret;
 	u16 addr;
 
 	addr = table + offset;
-	if ((phy->ofdmtab_addr_direction != B43_OFDMTAB_DIRECTION_READ) ||
-	    (addr - 1 != phy->ofdmtab_addr)) {
+	if ((gphy->ofdmtab_addr_direction != B43_OFDMTAB_DIRECTION_READ) ||
+	    (addr - 1 != gphy->ofdmtab_addr)) {
 		/* The hardware has a different address in memory. Update it. */
 		b43_phy_write(dev, B43_PHY_OTABLECTL, addr);
-		phy->ofdmtab_addr_direction = B43_OFDMTAB_DIRECTION_READ;
+		gphy->ofdmtab_addr_direction = B43_OFDMTAB_DIRECTION_READ;
 	}
-	phy->ofdmtab_addr = addr;
+	gphy->ofdmtab_addr = addr;
 	ret = b43_phy_read(dev, B43_PHY_OTABLEQ);
 	ret <<= 16;
 	ret |= b43_phy_read(dev, B43_PHY_OTABLEI);
@@ -436,17 +437,17 @@
 void b43_ofdmtab_write32(struct b43_wldev *dev, u16 table,
 			 u16 offset, u32 value)
 {
-	struct b43_phy *phy = &dev->phy;
+	struct b43_phy_g *gphy = dev->phy.g;
 	u16 addr;
 
 	addr = table + offset;
-	if ((phy->ofdmtab_addr_direction != B43_OFDMTAB_DIRECTION_WRITE) ||
-	    (addr - 1 != phy->ofdmtab_addr)) {
+	if ((gphy->ofdmtab_addr_direction != B43_OFDMTAB_DIRECTION_WRITE) ||
+	    (addr - 1 != gphy->ofdmtab_addr)) {
 		/* The hardware has a different address in memory. Update it. */
 		b43_phy_write(dev, B43_PHY_OTABLECTL, addr);
-		phy->ofdmtab_addr_direction = B43_OFDMTAB_DIRECTION_WRITE;
+		gphy->ofdmtab_addr_direction = B43_OFDMTAB_DIRECTION_WRITE;
 	}
-	phy->ofdmtab_addr = addr;
+	gphy->ofdmtab_addr = addr;
 
 	b43_phy_write(dev, B43_PHY_OTABLEI, value);
 	b43_phy_write(dev, B43_PHY_OTABLEQ, (value >> 16));
diff --git a/drivers/net/wireless/b43/tables_nphy.c b/drivers/net/wireless/b43/tables_nphy.c
index 2aa5755..4e23363 100644
--- a/drivers/net/wireless/b43/tables_nphy.c
+++ b/drivers/net/wireless/b43/tables_nphy.c
@@ -24,8 +24,8 @@
 
 #include "b43.h"
 #include "tables_nphy.h"
-#include "phy.h"
-#include "nphy.h"
+#include "phy_common.h"
+#include "phy_n.h"
 
 
 struct b2055_inittab_entry {
diff --git a/drivers/net/wireless/b43/wa.c b/drivers/net/wireless/b43/wa.c
index daa9421..0c0fb15 100644
--- a/drivers/net/wireless/b43/wa.c
+++ b/drivers/net/wireless/b43/wa.c
@@ -27,7 +27,7 @@
 #include "b43.h"
 #include "main.h"
 #include "tables.h"
-#include "phy.h"
+#include "phy_common.h"
 #include "wa.h"
 
 static void b43_wa_papd(struct b43_wldev *dev)
diff --git a/drivers/net/wireless/b43/xmit.c b/drivers/net/wireless/b43/xmit.c
index 9dda816..2fabcf8 100644
--- a/drivers/net/wireless/b43/xmit.c
+++ b/drivers/net/wireless/b43/xmit.c
@@ -28,7 +28,7 @@
 */
 
 #include "xmit.h"
-#include "phy.h"
+#include "phy_common.h"
 #include "dma.h"
 #include "pio.h"
 
@@ -208,7 +208,7 @@
 	txrate = ieee80211_get_tx_rate(dev->wl->hw, info);
 	rate = txrate ? txrate->hw_value : B43_CCK_RATE_1MB;
 	rate_ofdm = b43_is_ofdm_rate(rate);
-	fbrate = ieee80211_get_alt_retry_rate(dev->wl->hw, info) ? : txrate;
+	fbrate = ieee80211_get_alt_retry_rate(dev->wl->hw, info, 0) ? : txrate;
 	rate_fb = fbrate->hw_value;
 	rate_fb_ofdm = b43_is_ofdm_rate(rate_fb);
 
@@ -252,7 +252,7 @@
 		}
 
 		/* Hardware appends ICV. */
-		plcp_fragment_len += info->control.icv_len;
+		plcp_fragment_len += info->control.hw_key->icv_len;
 
 		key_idx = b43_kidx_to_fw(dev, key_idx);
 		mac_ctl |= (key_idx << B43_TXH_MAC_KEYIDX_SHIFT) &
@@ -260,7 +260,7 @@
 		mac_ctl |= (key->algorithm << B43_TXH_MAC_KEYALG_SHIFT) &
 			   B43_TXH_MAC_KEYALG;
 		wlhdr_len = ieee80211_hdrlen(fctl);
-		iv_len = min((size_t) info->control.iv_len,
+		iv_len = min((size_t) info->control.hw_key->iv_len,
 			     ARRAY_SIZE(txhdr->iv));
 		memcpy(txhdr->iv, ((u8 *) wlhdr) + wlhdr_len, iv_len);
 	}
@@ -431,6 +431,7 @@
 			       int adjust_2053, int adjust_2050)
 {
 	struct b43_phy *phy = &dev->phy;
+	struct b43_phy_g *gphy = phy->g;
 	s32 tmp;
 
 	switch (phy->radio_ver) {
@@ -450,7 +451,8 @@
 			    boardflags_lo & B43_BFL_RSSI) {
 				if (in_rssi > 63)
 					in_rssi = 63;
-				tmp = phy->nrssi_lt[in_rssi];
+				B43_WARN_ON(phy->type != B43_PHYTYPE_G);
+				tmp = gphy->nrssi_lt[in_rssi];
 				tmp = 31 - tmp;
 				tmp *= -131;
 				tmp /= 128;
@@ -678,6 +680,8 @@
 		b43_pio_handle_txstatus(dev, status);
 	else
 		b43_dma_handle_txstatus(dev, status);
+
+	b43_phy_txpower_check(dev, 0);
 }
 
 /* Fill out the mac80211 TXstatus report based on the b43-specific
diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c
index 1cb77db..c66d575 100644
--- a/drivers/net/wireless/b43legacy/main.c
+++ b/drivers/net/wireless/b43legacy/main.c
@@ -888,13 +888,13 @@
 
 static void handle_irq_tbtt_indication(struct b43legacy_wldev *dev)
 {
-	if (b43legacy_is_mode(dev->wl, IEEE80211_IF_TYPE_AP)) {
+	if (b43legacy_is_mode(dev->wl, NL80211_IFTYPE_AP)) {
 		/* TODO: PS TBTT */
 	} else {
 		if (1/*FIXME: the last PSpoll frame was sent successfully */)
 			b43legacy_power_saving_ctl_bits(dev, -1, -1);
 	}
-	if (b43legacy_is_mode(dev->wl, IEEE80211_IF_TYPE_IBSS))
+	if (b43legacy_is_mode(dev->wl, NL80211_IFTYPE_ADHOC))
 		dev->dfq_valid = 1;
 }
 
@@ -1201,7 +1201,7 @@
 	struct b43legacy_wl *wl = dev->wl;
 	u32 cmd;
 
-	if (!b43legacy_is_mode(wl, IEEE80211_IF_TYPE_AP))
+	if (!b43legacy_is_mode(wl, NL80211_IFTYPE_AP))
 		return;
 
 	/* This is the bottom half of the asynchronous beacon update. */
@@ -1936,9 +1936,9 @@
 	ctl &= ~B43legacy_MACCTL_BEACPROMISC;
 	ctl |= B43legacy_MACCTL_INFRA;
 
-	if (b43legacy_is_mode(wl, IEEE80211_IF_TYPE_AP))
+	if (b43legacy_is_mode(wl, NL80211_IFTYPE_AP))
 		ctl |= B43legacy_MACCTL_AP;
-	else if (b43legacy_is_mode(wl, IEEE80211_IF_TYPE_IBSS))
+	else if (b43legacy_is_mode(wl, NL80211_IFTYPE_ADHOC))
 		ctl &= ~B43legacy_MACCTL_INFRA;
 
 	if (wl->filter_flags & FIF_CONTROL)
@@ -2646,7 +2646,7 @@
 	b43legacy_mgmtframe_txantenna(dev, antenna_tx);
 
 	/* Update templates for AP mode. */
-	if (b43legacy_is_mode(wl, IEEE80211_IF_TYPE_AP))
+	if (b43legacy_is_mode(wl, NL80211_IFTYPE_AP))
 		b43legacy_set_beacon_int(dev, conf->beacon_int);
 
 
@@ -2733,12 +2733,12 @@
 	else
 		memset(wl->bssid, 0, ETH_ALEN);
 	if (b43legacy_status(dev) >= B43legacy_STAT_INITIALIZED) {
-		if (b43legacy_is_mode(wl, IEEE80211_IF_TYPE_AP)) {
-			B43legacy_WARN_ON(vif->type != IEEE80211_IF_TYPE_AP);
+		if (b43legacy_is_mode(wl, NL80211_IFTYPE_AP)) {
+			B43legacy_WARN_ON(vif->type != NL80211_IFTYPE_AP);
 			b43legacy_set_ssid(dev, conf->ssid, conf->ssid_len);
 			if (conf->changed & IEEE80211_IFCC_BEACON)
 				b43legacy_update_templates(wl);
-		} else if (b43legacy_is_mode(wl, IEEE80211_IF_TYPE_IBSS)) {
+		} else if (b43legacy_is_mode(wl, NL80211_IFTYPE_ADHOC)) {
 			if (conf->changed & IEEE80211_IFCC_BEACON)
 				b43legacy_update_templates(wl);
 		}
@@ -3020,7 +3020,7 @@
 					  bool idle) {
 	u16 pu_delay = 1050;
 
-	if (b43legacy_is_mode(dev->wl, IEEE80211_IF_TYPE_IBSS) || idle)
+	if (b43legacy_is_mode(dev->wl, NL80211_IFTYPE_ADHOC) || idle)
 		pu_delay = 500;
 	if ((dev->phy.radio_ver == 0x2050) && (dev->phy.radio_rev == 8))
 		pu_delay = max(pu_delay, (u16)2400);
@@ -3035,7 +3035,7 @@
 	u16 pretbtt;
 
 	/* The time value is in microseconds. */
-	if (b43legacy_is_mode(dev->wl, IEEE80211_IF_TYPE_IBSS))
+	if (b43legacy_is_mode(dev->wl, NL80211_IFTYPE_ADHOC))
 		pretbtt = 2;
 	else
 		pretbtt = 250;
@@ -3259,10 +3259,10 @@
 
 	/* TODO: allow WDS/AP devices to coexist */
 
-	if (conf->type != IEEE80211_IF_TYPE_AP &&
-	    conf->type != IEEE80211_IF_TYPE_STA &&
-	    conf->type != IEEE80211_IF_TYPE_WDS &&
-	    conf->type != IEEE80211_IF_TYPE_IBSS)
+	if (conf->type != NL80211_IFTYPE_AP &&
+	    conf->type != NL80211_IFTYPE_STATION &&
+	    conf->type != NL80211_IFTYPE_WDS &&
+	    conf->type != NL80211_IFTYPE_ADHOC)
 		return -EOPNOTSUPP;
 
 	mutex_lock(&wl->mutex);
@@ -3403,7 +3403,7 @@
 }
 
 static int b43legacy_op_beacon_set_tim(struct ieee80211_hw *hw,
-				       int aid, int set)
+				       struct ieee80211_sta *sta, bool set)
 {
 	struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw);
 	unsigned long flags;
@@ -3704,7 +3704,13 @@
 	hw->flags = IEEE80211_HW_RX_INCLUDES_FCS |
 		    IEEE80211_HW_SIGNAL_DBM |
 		    IEEE80211_HW_NOISE_DBM;
+	hw->wiphy->interface_modes =
+		BIT(NL80211_IFTYPE_AP) |
+		BIT(NL80211_IFTYPE_STATION) |
+		BIT(NL80211_IFTYPE_WDS) |
+		BIT(NL80211_IFTYPE_ADHOC);
 	hw->queues = 1; /* FIXME: hardware has more queues */
+	hw->max_altrates = 1;
 	SET_IEEE80211_DEV(hw, dev->dev);
 	if (is_valid_ether_addr(sprom->et1mac))
 		SET_IEEE80211_PERM_ADDR(hw, sprom->et1mac);
diff --git a/drivers/net/wireless/b43legacy/phy.c b/drivers/net/wireless/b43legacy/phy.c
index 768cccb..4c9442b 100644
--- a/drivers/net/wireless/b43legacy/phy.c
+++ b/drivers/net/wireless/b43legacy/phy.c
@@ -103,7 +103,7 @@
 	if (dev->dev->id.revision < 3) {
 		b43legacy_mac_suspend(dev);
 	} else {
-		if (!b43legacy_is_mode(dev->wl, IEEE80211_IF_TYPE_AP))
+		if (!b43legacy_is_mode(dev->wl, NL80211_IFTYPE_AP))
 			b43legacy_power_saving_ctl_bits(dev, -1, 1);
 	}
 }
@@ -118,7 +118,7 @@
 	if (dev->dev->id.revision < 3) {
 		b43legacy_mac_enable(dev);
 	} else {
-		if (!b43legacy_is_mode(dev->wl, IEEE80211_IF_TYPE_AP))
+		if (!b43legacy_is_mode(dev->wl, NL80211_IFTYPE_AP))
 			b43legacy_power_saving_ctl_bits(dev, -1, -1);
 	}
 }
@@ -595,12 +595,14 @@
 				    0x0035) & 0xFFC0) | 0x0064);
 		b43legacy_phy_write(dev, 0x005D, (b43legacy_phy_read(dev,
 				    0x005D) & 0xFF80) | 0x000A);
+		b43legacy_phy_write(dev, 0x5B, 0x0000);
+		b43legacy_phy_write(dev, 0x5C, 0x0000);
 	}
 
 	if (dev->bad_frames_preempt)
 		b43legacy_phy_write(dev, B43legacy_PHY_RADIO_BITFIELD,
 				    b43legacy_phy_read(dev,
-				    B43legacy_PHY_RADIO_BITFIELD) | (1 << 11));
+				    B43legacy_PHY_RADIO_BITFIELD) | (1 << 12));
 
 	if (phy->analog == 1) {
 		b43legacy_phy_write(dev, 0x0026, 0xCE00);
@@ -753,7 +755,7 @@
 		b43legacy_radio_write16(dev, 0x0050, 0x0020);
 	}
 	if (phy->radio_rev <= 2) {
-		b43legacy_radio_write16(dev, 0x007C, 0x0020);
+		b43legacy_radio_write16(dev, 0x0050, 0x0020);
 		b43legacy_radio_write16(dev, 0x005A, 0x0070);
 		b43legacy_radio_write16(dev, 0x005B, 0x007B);
 		b43legacy_radio_write16(dev, 0x005C, 0x00B0);
@@ -771,7 +773,7 @@
 		b43legacy_phy_write(dev, 0x002A, 0x8AC0);
 	b43legacy_phy_write(dev, 0x0038, 0x0668);
 	b43legacy_radio_set_txpower_bg(dev, 0xFFFF, 0xFFFF, 0xFFFF);
-	if (phy->radio_rev <= 5)
+	if (phy->radio_rev == 4 || phy->radio_rev == 5)
 		b43legacy_phy_write(dev, 0x005D, (b43legacy_phy_read(dev,
 				    0x005D) & 0xFF80) | 0x0003);
 	if (phy->radio_rev <= 2)
@@ -1010,7 +1012,7 @@
 		b43legacy_phy_initb5(dev);
 	else
 		b43legacy_phy_initb6(dev);
-	if (phy->rev >= 2 || phy->gmode)
+	if (phy->rev >= 2 && phy->gmode)
 		b43legacy_phy_inita(dev);
 
 	if (phy->rev >= 2) {
@@ -1025,18 +1027,22 @@
 		b43legacy_phy_write(dev, 0x0811, 0x0400);
 		b43legacy_phy_write(dev, 0x0015, 0x00C0);
 	}
-	if (phy->rev >= 2 || phy->gmode) {
+	if (phy->gmode) {
 		tmp = b43legacy_phy_read(dev, 0x0400) & 0xFF;
-		if (tmp == 3 || tmp == 5) {
+		if (tmp == 3) {
+			b43legacy_phy_write(dev, 0x04C2, 0x1816);
+			b43legacy_phy_write(dev, 0x04C3, 0x8606);
+		}
+		if (tmp == 4 || tmp == 5) {
 			b43legacy_phy_write(dev, 0x04C2, 0x1816);
 			b43legacy_phy_write(dev, 0x04C3, 0x8006);
-			if (tmp == 5)
-				b43legacy_phy_write(dev, 0x04CC,
-						    (b43legacy_phy_read(dev,
-						     0x04CC) & 0x00FF) |
-						     0x1F00);
+			b43legacy_phy_write(dev, 0x04CC,
+					    (b43legacy_phy_read(dev,
+					     0x04CC) & 0x00FF) |
+					     0x1F00);
 		}
-		b43legacy_phy_write(dev, 0x047E, 0x0078);
+		if (phy->rev >= 2)
+			b43legacy_phy_write(dev, 0x047E, 0x0078);
 	}
 	if (phy->radio_rev == 8) {
 		b43legacy_phy_write(dev, 0x0801, b43legacy_phy_read(dev, 0x0801)
@@ -1078,7 +1084,7 @@
 		else
 			b43legacy_phy_write(dev, 0x002F, 0x0202);
 	}
-	if (phy->gmode || phy->rev >= 2) {
+	if (phy->gmode) {
 		b43legacy_phy_lo_adjust(dev, 0);
 		b43legacy_phy_write(dev, 0x080F, 0x8078);
 	}
diff --git a/drivers/net/wireless/b43legacy/rfkill.c b/drivers/net/wireless/b43legacy/rfkill.c
index 476add9..b32bf6a 100644
--- a/drivers/net/wireless/b43legacy/rfkill.c
+++ b/drivers/net/wireless/b43legacy/rfkill.c
@@ -44,23 +44,6 @@
 	return 0;
 }
 
-/* Update the rfkill state */
-static void b43legacy_rfkill_update_state(struct b43legacy_wldev *dev)
-{
-	struct b43legacy_rfkill *rfk = &(dev->wl->rfkill);
-
-	if (!dev->radio_hw_enable) {
-		rfk->rfkill->state = RFKILL_STATE_HARD_BLOCKED;
-		return;
-	}
-
-	if (!dev->phy.radio_on)
-		rfk->rfkill->state = RFKILL_STATE_SOFT_BLOCKED;
-	else
-		rfk->rfkill->state = RFKILL_STATE_UNBLOCKED;
-
-}
-
 /* The poll callback for the hardware button. */
 static void b43legacy_rfkill_poll(struct input_polled_dev *poll_dev)
 {
@@ -78,7 +61,6 @@
 	if (unlikely(enabled != dev->radio_hw_enable)) {
 		dev->radio_hw_enable = enabled;
 		report_change = 1;
-		b43legacy_rfkill_update_state(dev);
 		b43legacyinfo(wl, "Radio hardware status changed to %s\n",
 			enabled ? "ENABLED" : "DISABLED");
 	}
diff --git a/drivers/net/wireless/b43legacy/xmit.c b/drivers/net/wireless/b43legacy/xmit.c
index 68e1f8c..65e8337 100644
--- a/drivers/net/wireless/b43legacy/xmit.c
+++ b/drivers/net/wireless/b43legacy/xmit.c
@@ -193,7 +193,6 @@
 {
 	const struct ieee80211_hdr *wlhdr;
 	int use_encryption = !!info->control.hw_key;
-	u16 fctl;
 	u8 rate;
 	struct ieee80211_rate *rate_fb;
 	int rate_ofdm;
@@ -204,7 +203,6 @@
 	struct ieee80211_rate *tx_rate;
 
 	wlhdr = (const struct ieee80211_hdr *)fragment_data;
-	fctl = le16_to_cpu(wlhdr->frame_control);
 
 	memset(txhdr, 0, sizeof(*txhdr));
 
@@ -212,7 +210,7 @@
 
 	rate = tx_rate->hw_value;
 	rate_ofdm = b43legacy_is_ofdm_rate(rate);
-	rate_fb = ieee80211_get_alt_retry_rate(dev->wl->hw, info) ? : tx_rate;
+	rate_fb = ieee80211_get_alt_retry_rate(dev->wl->hw, info, 0) ? : tx_rate;
 	rate_fb_ofdm = b43legacy_is_ofdm_rate(rate_fb->hw_value);
 
 	txhdr->mac_frame_ctl = wlhdr->frame_control;
@@ -245,7 +243,7 @@
 
 		if (key->enabled) {
 			/* Hardware appends ICV. */
-			plcp_fragment_len += info->control.icv_len;
+			plcp_fragment_len += info->control.hw_key->icv_len;
 
 			key_idx = b43legacy_kidx_to_fw(dev, key_idx);
 			mac_ctl |= (key_idx << B43legacy_TX4_MAC_KEYIDX_SHIFT) &
@@ -253,8 +251,8 @@
 			mac_ctl |= (key->algorithm <<
 				   B43legacy_TX4_MAC_KEYALG_SHIFT) &
 				   B43legacy_TX4_MAC_KEYALG;
-			wlhdr_len = ieee80211_get_hdrlen(fctl);
-			iv_len = min((size_t)info->control.iv_len,
+			wlhdr_len = ieee80211_hdrlen(wlhdr->frame_control);
+			iv_len = min((size_t)info->control.hw_key->iv_len,
 				     ARRAY_SIZE(txhdr->iv));
 			memcpy(txhdr->iv, ((u8 *)wlhdr) + wlhdr_len, iv_len);
 		} else {
@@ -626,7 +624,7 @@
 	tmp = hw->count;
 	status.frame_count = (tmp >> 4);
 	status.rts_count = (tmp & 0x0F);
-	tmp = hw->flags;
+	tmp = hw->flags << 1;
 	status.supp_reason = ((tmp & 0x1C) >> 2);
 	status.pm_indicated = !!(tmp & 0x80);
 	status.intermediate = !!(tmp & 0x40);
diff --git a/drivers/net/wireless/hermes.c b/drivers/net/wireless/hermes.c
index 29d3910..bfa3753 100644
--- a/drivers/net/wireless/hermes.c
+++ b/drivers/net/wireless/hermes.c
@@ -87,7 +87,8 @@
 
    Callable from any context.
 */
-static int hermes_issue_cmd(hermes_t *hw, u16 cmd, u16 param0)
+static int hermes_issue_cmd(hermes_t *hw, u16 cmd, u16 param0,
+			    u16 param1, u16 param2)
 {
 	int k = CMD_BUSY_TIMEOUT;
 	u16 reg;
@@ -103,8 +104,8 @@
 		return -EBUSY;
 	}
 
-	hermes_write_regn(hw, PARAM2, 0);
-	hermes_write_regn(hw, PARAM1, 0);
+	hermes_write_regn(hw, PARAM2, param2);
+	hermes_write_regn(hw, PARAM1, param1);
 	hermes_write_regn(hw, PARAM0, param0);
 	hermes_write_regn(hw, CMD, cmd);
 	
@@ -115,16 +116,72 @@
  * Function definitions
  */
 
+/* For doing cmds that wipe the magic constant in SWSUPPORT0 */
+int hermes_doicmd_wait(hermes_t *hw, u16 cmd,
+		       u16 parm0, u16 parm1, u16 parm2,
+		       struct hermes_response *resp)
+{
+	int err = 0;
+	int k;
+	u16 status, reg;
+
+	err = hermes_issue_cmd(hw, cmd, parm0, parm1, parm2);
+	if (err)
+		return err;
+
+	reg = hermes_read_regn(hw, EVSTAT);
+	k = CMD_INIT_TIMEOUT;
+	while ((!(reg & HERMES_EV_CMD)) && k) {
+		k--;
+		udelay(10);
+		reg = hermes_read_regn(hw, EVSTAT);
+	}
+
+	hermes_write_regn(hw, SWSUPPORT0, HERMES_MAGIC);
+
+	if (!hermes_present(hw)) {
+		DEBUG(0, "hermes @ 0x%x: Card removed during reset.\n",
+		       hw->iobase);
+		err = -ENODEV;
+		goto out;
+	}
+
+	if (!(reg & HERMES_EV_CMD)) {
+		printk(KERN_ERR "hermes @ %p: "
+		       "Timeout waiting for card to reset (reg=0x%04x)!\n",
+		       hw->iobase, reg);
+		err = -ETIMEDOUT;
+		goto out;
+	}
+
+	status = hermes_read_regn(hw, STATUS);
+	if (resp) {
+		resp->status = status;
+		resp->resp0 = hermes_read_regn(hw, RESP0);
+		resp->resp1 = hermes_read_regn(hw, RESP1);
+		resp->resp2 = hermes_read_regn(hw, RESP2);
+	}
+
+	hermes_write_regn(hw, EVACK, HERMES_EV_CMD);
+
+	if (status & HERMES_STATUS_RESULT)
+		err = -EIO;
+out:
+	return err;
+}
+EXPORT_SYMBOL(hermes_doicmd_wait);
+
 void hermes_struct_init(hermes_t *hw, void __iomem *address, int reg_spacing)
 {
 	hw->iobase = address;
 	hw->reg_spacing = reg_spacing;
 	hw->inten = 0x0;
 }
+EXPORT_SYMBOL(hermes_struct_init);
 
 int hermes_init(hermes_t *hw)
 {
-	u16 status, reg;
+	u16 reg;
 	int err = 0;
 	int k;
 
@@ -162,45 +219,11 @@
 
 	/* We don't use hermes_docmd_wait here, because the reset wipes
 	   the magic constant in SWSUPPORT0 away, and it gets confused */
-	err = hermes_issue_cmd(hw, HERMES_CMD_INIT, 0);
-	if (err)
-		return err;
+	err = hermes_doicmd_wait(hw, HERMES_CMD_INIT, 0, 0, 0, NULL);
 
-	reg = hermes_read_regn(hw, EVSTAT);
-	k = CMD_INIT_TIMEOUT;
-	while ( (! (reg & HERMES_EV_CMD)) && k) {
-		k--;
-		udelay(10);
-		reg = hermes_read_regn(hw, EVSTAT);
-	}
-
-	hermes_write_regn(hw, SWSUPPORT0, HERMES_MAGIC);
-
-	if (! hermes_present(hw)) {
-		DEBUG(0, "hermes @ 0x%x: Card removed during reset.\n",
-		       hw->iobase);
-		err = -ENODEV;
-		goto out;
-	}
-		
-	if (! (reg & HERMES_EV_CMD)) {
-		printk(KERN_ERR "hermes @ %p: " 
-		       "Timeout waiting for card to reset (reg=0x%04x)!\n",
-		       hw->iobase, reg);
-		err = -ETIMEDOUT;
-		goto out;
-	}
-
-	status = hermes_read_regn(hw, STATUS);
-
-	hermes_write_regn(hw, EVACK, HERMES_EV_CMD);
-
-	if (status & HERMES_STATUS_RESULT)
-		err = -EIO;
-
- out:
 	return err;
 }
+EXPORT_SYMBOL(hermes_init);
 
 /* Issue a command to the chip, and (busy!) wait for it to
  * complete.
@@ -216,7 +239,7 @@
 	u16 reg;
 	u16 status;
 
-	err = hermes_issue_cmd(hw, cmd, parm0);
+	err = hermes_issue_cmd(hw, cmd, parm0, 0, 0);
 	if (err) {
 		if (! hermes_present(hw)) {
 			if (net_ratelimit())
@@ -271,6 +294,7 @@
  out:
 	return err;
 }
+EXPORT_SYMBOL(hermes_docmd_wait);
 
 int hermes_allocate(hermes_t *hw, u16 size, u16 *fid)
 {
@@ -313,7 +337,7 @@
 	
 	return 0;
 }
-
+EXPORT_SYMBOL(hermes_allocate);
 
 /* Set up a BAP to read a particular chunk of data from card's internal buffer.
  *
@@ -397,6 +421,7 @@
  out:
 	return err;
 }
+EXPORT_SYMBOL(hermes_bap_pread);
 
 /* Write a block of data to the chip's buffer, via the
  * BAP. Synchronization/serialization is the caller's problem.
@@ -422,6 +447,7 @@
  out:	
 	return err;
 }
+EXPORT_SYMBOL(hermes_bap_pwrite);
 
 /* Read a Length-Type-Value record from the card.
  *
@@ -463,7 +489,7 @@
 	if (rtype != rid)
 		printk(KERN_WARNING "hermes @ %p: %s(): "
 		       "rid (0x%04x) does not match type (0x%04x)\n",
-		       hw->iobase, __FUNCTION__, rid, rtype);
+		       hw->iobase, __func__, rid, rtype);
 	if (HERMES_RECLEN_TO_BYTES(rlength) > bufsize)
 		printk(KERN_WARNING "hermes @ %p: "
 		       "Truncating LTV record from %d to %d bytes. "
@@ -475,6 +501,7 @@
 
 	return 0;
 }
+EXPORT_SYMBOL(hermes_read_ltv);
 
 int hermes_write_ltv(hermes_t *hw, int bap, u16 rid, 
 		     u16 length, const void *value)
@@ -497,20 +524,11 @@
 
 	hermes_write_bytes(hw, dreg, value, count << 1);
 
-	err = hermes_docmd_wait(hw, HERMES_CMD_ACCESS | HERMES_CMD_WRITE, 
+	err = hermes_docmd_wait(hw, HERMES_CMD_ACCESS | HERMES_CMD_WRITE,
 				rid, NULL);
 
 	return err;
 }
-
-EXPORT_SYMBOL(hermes_struct_init);
-EXPORT_SYMBOL(hermes_init);
-EXPORT_SYMBOL(hermes_docmd_wait);
-EXPORT_SYMBOL(hermes_allocate);
-
-EXPORT_SYMBOL(hermes_bap_pread);
-EXPORT_SYMBOL(hermes_bap_pwrite);
-EXPORT_SYMBOL(hermes_read_ltv);
 EXPORT_SYMBOL(hermes_write_ltv);
 
 static int __init init_hermes(void)
diff --git a/drivers/net/wireless/hermes.h b/drivers/net/wireless/hermes.h
index 8e3f0e3..8b13c8f 100644
--- a/drivers/net/wireless/hermes.h
+++ b/drivers/net/wireless/hermes.h
@@ -179,17 +179,23 @@
 #define HERMES_802_11_OFFSET		(14)
 #define HERMES_802_3_OFFSET		(14+32)
 #define HERMES_802_2_OFFSET		(14+32+14)
+#define HERMES_TXCNTL2_OFFSET		(HERMES_802_3_OFFSET - 2)
 
 #define HERMES_RXSTAT_ERR		(0x0003)
 #define	HERMES_RXSTAT_BADCRC		(0x0001)
 #define	HERMES_RXSTAT_UNDECRYPTABLE	(0x0002)
+#define	HERMES_RXSTAT_MIC		(0x0010)	/* Frame contains MIC */
 #define	HERMES_RXSTAT_MACPORT		(0x0700)
 #define HERMES_RXSTAT_PCF		(0x1000)	/* Frame was received in CF period */
+#define	HERMES_RXSTAT_MIC_KEY_ID	(0x1800)	/* MIC key used */
 #define	HERMES_RXSTAT_MSGTYPE		(0xE000)
 #define	HERMES_RXSTAT_1042		(0x2000)	/* RFC-1042 frame */
 #define	HERMES_RXSTAT_TUNNEL		(0x4000)	/* bridge-tunnel encoded frame */
 #define	HERMES_RXSTAT_WMP		(0x6000)	/* Wavelan-II Management Protocol frame */
 
+/* Shift amount for key ID in RXSTAT and TXCTRL */
+#define	HERMES_MIC_KEY_ID_SHIFT		11
+
 struct hermes_tx_descriptor {
 	__le16 status;
 	__le16 reserved1;
@@ -208,6 +214,8 @@
 #define HERMES_TXCTRL_TX_OK		(0x0002)	/* ?? interrupt on Tx complete */
 #define HERMES_TXCTRL_TX_EX		(0x0004)	/* ?? interrupt on Tx exception */
 #define HERMES_TXCTRL_802_11		(0x0008)	/* We supply 802.11 header */
+#define HERMES_TXCTRL_MIC		(0x0010)	/* 802.3 + TKIP */
+#define HERMES_TXCTRL_MIC_KEY_ID	(0x1800)	/* MIC Key ID mask */
 #define HERMES_TXCTRL_ALT_RTRY		(0x0020)
 
 /* Inquiry constants and data types */
@@ -302,6 +310,40 @@
 	struct symbol_scan_apinfo	s;
 };
 
+/* Extended scan struct for HERMES_INQ_CHANNELINFO.
+ * wl_lkm calls this an ACS scan (Automatic Channel Select).
+ * Keep out of union hermes_scan_info because it is much bigger than
+ * the older scan structures. */
+struct agere_ext_scan_info {
+	__le16	reserved0;
+
+	u8	noise;
+	u8	level;
+	u8	rx_flow;
+	u8	rate;
+	__le16	reserved1[2];
+
+	__le16	frame_control;
+	__le16	dur_id;
+	u8	addr1[ETH_ALEN];
+	u8	addr2[ETH_ALEN];
+	u8	bssid[ETH_ALEN];
+	__le16	sequence;
+	u8	addr4[ETH_ALEN];
+
+	__le16	data_length;
+
+	/* Next 3 fields do not get filled in. */
+	u8	daddr[ETH_ALEN];
+	u8	saddr[ETH_ALEN];
+	__le16	len_type;
+
+	__le64	timestamp;
+	__le16	beacon_interval;
+	__le16	capabilities;
+	u8	data[316];
+} __attribute__ ((packed));
+
 #define HERMES_LINKSTATUS_NOT_CONNECTED   (0x0000)  
 #define HERMES_LINKSTATUS_CONNECTED       (0x0001)
 #define HERMES_LINKSTATUS_DISCONNECTED    (0x0002)
@@ -353,6 +395,9 @@
 int hermes_init(hermes_t *hw);
 int hermes_docmd_wait(hermes_t *hw, u16 cmd, u16 parm0,
 		      struct hermes_response *resp);
+int hermes_doicmd_wait(hermes_t *hw, u16 cmd,
+		       u16 parm0, u16 parm1, u16 parm2,
+		       struct hermes_response *resp);
 int hermes_allocate(hermes_t *hw, u16 size, u16 *fid);
 
 int hermes_bap_pread(hermes_t *hw, int bap, void *buf, int len,
diff --git a/drivers/net/wireless/hermes_dld.c b/drivers/net/wireless/hermes_dld.c
new file mode 100644
index 0000000..d8c626e
--- /dev/null
+++ b/drivers/net/wireless/hermes_dld.c
@@ -0,0 +1,730 @@
+/*
+ * Hermes download helper driver.
+ *
+ * This could be entirely merged into hermes.c.
+ *
+ * I'm keeping it separate to minimise the amount of merging between
+ * kernel upgrades. It also means the memory overhead for drivers that
+ * don't need firmware download low.
+ *
+ * This driver:
+ *  - is capable of writing to the volatile area of the hermes device
+ *  - is currently not capable of writing to non-volatile areas
+ *  - provide helpers to identify and update plugin data
+ *  - is not capable of interpreting a fw image directly. That is up to
+ *    the main card driver.
+ *  - deals with Hermes I devices. It can probably be modified to deal
+ *    with Hermes II devices
+ *
+ * Copyright (C) 2007, David Kilroy
+ *
+ * Plug data code slightly modified from spectrum_cs driver
+ *    Copyright (C) 2002-2005 Pavel Roskin <proski@gnu.org>
+ * Portions based on information in wl_lkm_718 Agere driver
+ *    COPYRIGHT (C) 2001-2004 by Agere Systems Inc. All Rights Reserved
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License
+ * at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU General Public License version 2 (the "GPL"), 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 MPL, 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 MPL or the GPL.
+ */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include "hermes.h"
+#include "hermes_dld.h"
+
+MODULE_DESCRIPTION("Download helper for Lucent Hermes chipset");
+MODULE_AUTHOR("David Kilroy <kilroyd@gmail.com>");
+MODULE_LICENSE("Dual MPL/GPL");
+
+#define PFX "hermes_dld: "
+
+/*
+ * AUX port access.  To unlock the AUX port write the access keys to the
+ * PARAM0-2 registers, then write HERMES_AUX_ENABLE to the HERMES_CONTROL
+ * register.  Then read it and make sure it's HERMES_AUX_ENABLED.
+ */
+#define HERMES_AUX_ENABLE	0x8000	/* Enable auxiliary port access */
+#define HERMES_AUX_DISABLE	0x4000	/* Disable to auxiliary port access */
+#define HERMES_AUX_ENABLED	0xC000	/* Auxiliary port is open */
+#define HERMES_AUX_DISABLED	0x0000	/* Auxiliary port is closed */
+
+#define HERMES_AUX_PW0	0xFE01
+#define HERMES_AUX_PW1	0xDC23
+#define HERMES_AUX_PW2	0xBA45
+
+/* HERMES_CMD_DOWNLD */
+#define HERMES_PROGRAM_DISABLE             (0x0000 | HERMES_CMD_DOWNLD)
+#define HERMES_PROGRAM_ENABLE_VOLATILE     (0x0100 | HERMES_CMD_DOWNLD)
+#define HERMES_PROGRAM_ENABLE_NON_VOLATILE (0x0200 | HERMES_CMD_DOWNLD)
+#define HERMES_PROGRAM_NON_VOLATILE        (0x0300 | HERMES_CMD_DOWNLD)
+
+/* End markers used in dblocks */
+#define PDI_END		0x00000000	/* End of PDA */
+#define BLOCK_END	0xFFFFFFFF	/* Last image block */
+#define TEXT_END	0x1A		/* End of text header */
+
+/*
+ * PDA == Production Data Area
+ *
+ * In principle, the max. size of the PDA is is 4096 words. Currently,
+ * however, only about 500 bytes of this area are used.
+ *
+ * Some USB implementations can't handle sizes in excess of 1016. Note
+ * that PDA is not actually used in those USB environments, but may be
+ * retrieved by common code.
+ */
+#define MAX_PDA_SIZE	1000
+
+/* Limit the amout we try to download in a single shot.
+ * Size is in bytes.
+ */
+#define MAX_DL_SIZE 1024
+#define LIMIT_PROGRAM_SIZE 0
+
+/*
+ * The following structures have little-endian fields denoted by
+ * the leading underscore.  Don't access them directly - use inline
+ * functions defined below.
+ */
+
+/*
+ * The binary image to be downloaded consists of series of data blocks.
+ * Each block has the following structure.
+ */
+struct dblock {
+	__le32 addr;		/* adapter address where to write the block */
+	__le16 len;		/* length of the data only, in bytes */
+	char data[0];		/* data to be written */
+} __attribute__ ((packed));
+
+/*
+ * Plug Data References are located in in the image after the last data
+ * block.  They refer to areas in the adapter memory where the plug data
+ * items with matching ID should be written.
+ */
+struct pdr {
+	__le32 id;		/* record ID */
+	__le32 addr;		/* adapter address where to write the data */
+	__le32 len;		/* expected length of the data, in bytes */
+	char next[0];		/* next PDR starts here */
+} __attribute__ ((packed));
+
+/*
+ * Plug Data Items are located in the EEPROM read from the adapter by
+ * primary firmware.  They refer to the device-specific data that should
+ * be plugged into the secondary firmware.
+ */
+struct pdi {
+	__le16 len;		/* length of ID and data, in words */
+	__le16 id;		/* record ID */
+	char data[0];		/* plug data */
+} __attribute__ ((packed));
+
+/*** FW data block access functions ***/
+
+static inline u32
+dblock_addr(const struct dblock *blk)
+{
+	return le32_to_cpu(blk->addr);
+}
+
+static inline u32
+dblock_len(const struct dblock *blk)
+{
+	return le16_to_cpu(blk->len);
+}
+
+/*** PDR Access functions ***/
+
+static inline u32
+pdr_id(const struct pdr *pdr)
+{
+	return le32_to_cpu(pdr->id);
+}
+
+static inline u32
+pdr_addr(const struct pdr *pdr)
+{
+	return le32_to_cpu(pdr->addr);
+}
+
+static inline u32
+pdr_len(const struct pdr *pdr)
+{
+	return le32_to_cpu(pdr->len);
+}
+
+/*** PDI Access functions ***/
+
+static inline u32
+pdi_id(const struct pdi *pdi)
+{
+	return le16_to_cpu(pdi->id);
+}
+
+/* Return length of the data only, in bytes */
+static inline u32
+pdi_len(const struct pdi *pdi)
+{
+	return 2 * (le16_to_cpu(pdi->len) - 1);
+}
+
+/*** Hermes AUX control ***/
+
+static inline void
+hermes_aux_setaddr(hermes_t *hw, u32 addr)
+{
+	hermes_write_reg(hw, HERMES_AUXPAGE, (u16) (addr >> 7));
+	hermes_write_reg(hw, HERMES_AUXOFFSET, (u16) (addr & 0x7F));
+}
+
+static inline int
+hermes_aux_control(hermes_t *hw, int enabled)
+{
+	int desired_state = enabled ? HERMES_AUX_ENABLED : HERMES_AUX_DISABLED;
+	int action = enabled ? HERMES_AUX_ENABLE : HERMES_AUX_DISABLE;
+	int i;
+
+	/* Already open? */
+	if (hermes_read_reg(hw, HERMES_CONTROL) == desired_state)
+		return 0;
+
+	hermes_write_reg(hw, HERMES_PARAM0, HERMES_AUX_PW0);
+	hermes_write_reg(hw, HERMES_PARAM1, HERMES_AUX_PW1);
+	hermes_write_reg(hw, HERMES_PARAM2, HERMES_AUX_PW2);
+	hermes_write_reg(hw, HERMES_CONTROL, action);
+
+	for (i = 0; i < 20; i++) {
+		udelay(10);
+		if (hermes_read_reg(hw, HERMES_CONTROL) ==
+		    desired_state)
+			return 0;
+	}
+
+	return -EBUSY;
+}
+
+/*** Plug Data Functions ***/
+
+/*
+ * Scan PDR for the record with the specified RECORD_ID.
+ * If it's not found, return NULL.
+ */
+static struct pdr *
+hermes_find_pdr(struct pdr *first_pdr, u32 record_id)
+{
+	struct pdr *pdr = first_pdr;
+	void *end = (void *)first_pdr + MAX_PDA_SIZE;
+
+	while (((void *)pdr < end) &&
+	       (pdr_id(pdr) != PDI_END)) {
+		/*
+		 * PDR area is currently not terminated by PDI_END.
+		 * It's followed by CRC records, which have the type
+		 * field where PDR has length.  The type can be 0 or 1.
+		 */
+		if (pdr_len(pdr) < 2)
+			return NULL;
+
+		/* If the record ID matches, we are done */
+		if (pdr_id(pdr) == record_id)
+			return pdr;
+
+		pdr = (struct pdr *) pdr->next;
+	}
+	return NULL;
+}
+
+/* Scan production data items for a particular entry */
+static struct pdi *
+hermes_find_pdi(struct pdi *first_pdi, u32 record_id)
+{
+	struct pdi *pdi = first_pdi;
+
+	while (pdi_id(pdi) != PDI_END) {
+
+		/* If the record ID matches, we are done */
+		if (pdi_id(pdi) == record_id)
+			return pdi;
+
+		pdi = (struct pdi *) &pdi->data[pdi_len(pdi)];
+	}
+	return NULL;
+}
+
+/* Process one Plug Data Item - find corresponding PDR and plug it */
+static int
+hermes_plug_pdi(hermes_t *hw, struct pdr *first_pdr, const struct pdi *pdi)
+{
+	struct pdr *pdr;
+
+	/* Find the PDR corresponding to this PDI */
+	pdr = hermes_find_pdr(first_pdr, pdi_id(pdi));
+
+	/* No match is found, safe to ignore */
+	if (!pdr)
+		return 0;
+
+	/* Lengths of the data in PDI and PDR must match */
+	if (pdi_len(pdi) != pdr_len(pdr))
+		return -EINVAL;
+
+	/* do the actual plugging */
+	hermes_aux_setaddr(hw, pdr_addr(pdr));
+	hermes_write_bytes(hw, HERMES_AUXDATA, pdi->data, pdi_len(pdi));
+
+	return 0;
+}
+
+/* Read PDA from the adapter */
+int hermes_read_pda(hermes_t *hw,
+		    __le16 *pda,
+		    u32 pda_addr,
+		    u16 pda_len,
+		    int use_eeprom) /* can we get this into hw? */
+{
+	int ret;
+	u16 pda_size;
+	u16 data_len = pda_len;
+	__le16 *data = pda;
+
+	if (use_eeprom) {
+		/* PDA of spectrum symbol is in eeprom */
+
+		/* Issue command to read EEPROM */
+		ret = hermes_docmd_wait(hw, HERMES_CMD_READMIF, 0, NULL);
+		if (ret)
+			return ret;
+	} else {
+		/* wl_lkm does not include PDA size in the PDA area.
+		 * We will pad the information into pda, so other routines
+		 * don't have to be modified */
+		pda[0] = cpu_to_le16(pda_len - 2);
+			/* Includes CFG_PROD_DATA but not itself */
+		pda[1] = cpu_to_le16(0x0800); /* CFG_PROD_DATA */
+		data_len = pda_len - 4;
+		data = pda + 2;
+	}
+
+	/* Open auxiliary port */
+	ret = hermes_aux_control(hw, 1);
+	printk(KERN_DEBUG PFX "AUX enable returned %d\n", ret);
+	if (ret)
+		return ret;
+
+	/* read PDA from EEPROM */
+	hermes_aux_setaddr(hw, pda_addr);
+	hermes_read_words(hw, HERMES_AUXDATA, data, data_len / 2);
+
+	/* Close aux port */
+	ret = hermes_aux_control(hw, 0);
+	printk(KERN_DEBUG PFX "AUX disable returned %d\n", ret);
+
+	/* Check PDA length */
+	pda_size = le16_to_cpu(pda[0]);
+	printk(KERN_DEBUG PFX "Actual PDA length %d, Max allowed %d\n",
+	       pda_size, pda_len);
+	if (pda_size > pda_len)
+		return -EINVAL;
+
+	return 0;
+}
+EXPORT_SYMBOL(hermes_read_pda);
+
+/* Parse PDA and write the records into the adapter
+ *
+ * Attempt to write every records that is in the specified pda
+ * which also has a valid production data record for the firmware.
+ */
+int hermes_apply_pda(hermes_t *hw,
+		     const char *first_pdr,
+		     const __le16 *pda)
+{
+	int ret;
+	const struct pdi *pdi;
+	struct pdr *pdr;
+
+	pdr = (struct pdr *) first_pdr;
+
+	/* Go through every PDI and plug them into the adapter */
+	pdi = (const struct pdi *) (pda + 2);
+	while (pdi_id(pdi) != PDI_END) {
+		ret = hermes_plug_pdi(hw, pdr, pdi);
+		if (ret)
+			return ret;
+
+		/* Increment to the next PDI */
+		pdi = (const struct pdi *) &pdi->data[pdi_len(pdi)];
+	}
+	return 0;
+}
+EXPORT_SYMBOL(hermes_apply_pda);
+
+/* Identify the total number of bytes in all blocks
+ * including the header data.
+ */
+size_t
+hermes_blocks_length(const char *first_block)
+{
+	const struct dblock *blk = (const struct dblock *) first_block;
+	int total_len = 0;
+	int len;
+
+	/* Skip all blocks to locate Plug Data References
+	 * (Spectrum CS) */
+	while (dblock_addr(blk) != BLOCK_END) {
+		len = dblock_len(blk);
+		total_len += sizeof(*blk) + len;
+		blk = (struct dblock *) &blk->data[len];
+	}
+
+	return total_len;
+}
+EXPORT_SYMBOL(hermes_blocks_length);
+
+/*** Hermes programming ***/
+
+/* About to start programming data (Hermes I)
+ * offset is the entry point
+ *
+ * Spectrum_cs' Symbol fw does not require this
+ * wl_lkm Agere fw does
+ * Don't know about intersil
+ */
+int hermesi_program_init(hermes_t *hw, u32 offset)
+{
+	int err;
+
+	/* Disable interrupts?*/
+	/*hw->inten = 0x0;*/
+	/*hermes_write_regn(hw, INTEN, 0);*/
+	/*hermes_set_irqmask(hw, 0);*/
+
+	/* Acknowledge any outstanding command */
+	hermes_write_regn(hw, EVACK, 0xFFFF);
+
+	/* Using doicmd_wait rather than docmd_wait */
+	err = hermes_doicmd_wait(hw,
+				 0x0100 | HERMES_CMD_INIT,
+				 0, 0, 0, NULL);
+	if (err)
+		return err;
+
+	err = hermes_doicmd_wait(hw,
+				 0x0000 | HERMES_CMD_INIT,
+				 0, 0, 0, NULL);
+	if (err)
+		return err;
+
+	err = hermes_aux_control(hw, 1);
+	printk(KERN_DEBUG PFX "AUX enable returned %d\n", err);
+
+	if (err)
+		return err;
+
+	printk(KERN_DEBUG PFX "Enabling volatile, EP 0x%08x\n", offset);
+	err = hermes_doicmd_wait(hw,
+				 HERMES_PROGRAM_ENABLE_VOLATILE,
+				 offset & 0xFFFFu,
+				 offset >> 16,
+				 0,
+				 NULL);
+	printk(KERN_DEBUG PFX "PROGRAM_ENABLE returned %d\n",
+	       err);
+
+	return err;
+}
+EXPORT_SYMBOL(hermesi_program_init);
+
+/* Done programming data (Hermes I)
+ *
+ * Spectrum_cs' Symbol fw does not require this
+ * wl_lkm Agere fw does
+ * Don't know about intersil
+ */
+int hermesi_program_end(hermes_t *hw)
+{
+	struct hermes_response resp;
+	int rc = 0;
+	int err;
+
+	rc = hermes_docmd_wait(hw, HERMES_PROGRAM_DISABLE, 0, &resp);
+
+	printk(KERN_DEBUG PFX "PROGRAM_DISABLE returned %d, "
+	       "r0 0x%04x, r1 0x%04x, r2 0x%04x\n",
+	       rc, resp.resp0, resp.resp1, resp.resp2);
+
+	if ((rc == 0) &&
+	    ((resp.status & HERMES_STATUS_CMDCODE) != HERMES_CMD_DOWNLD))
+		rc = -EIO;
+
+	err = hermes_aux_control(hw, 0);
+	printk(KERN_DEBUG PFX "AUX disable returned %d\n", err);
+
+	/* Acknowledge any outstanding command */
+	hermes_write_regn(hw, EVACK, 0xFFFF);
+
+	/* Reinitialise, ignoring return */
+	(void) hermes_doicmd_wait(hw, 0x0000 | HERMES_CMD_INIT,
+				  0, 0, 0, NULL);
+
+	return rc ? rc : err;
+}
+EXPORT_SYMBOL(hermesi_program_end);
+
+/* Program the data blocks */
+int hermes_program(hermes_t *hw, const char *first_block, const char *end)
+{
+	const struct dblock *blk;
+	u32 blkaddr;
+	u32 blklen;
+#if LIMIT_PROGRAM_SIZE
+	u32 addr;
+	u32 len;
+#endif
+
+	blk = (const struct dblock *) first_block;
+
+	if ((const char *) blk > (end - sizeof(*blk)))
+		return -EIO;
+
+	blkaddr = dblock_addr(blk);
+	blklen = dblock_len(blk);
+
+	while ((blkaddr != BLOCK_END) &&
+	       (((const char *) blk + blklen) <= end)) {
+		printk(KERN_DEBUG PFX
+		       "Programming block of length %d to address 0x%08x\n",
+		       blklen, blkaddr);
+
+#if !LIMIT_PROGRAM_SIZE
+		/* wl_lkm driver splits this into writes of 2000 bytes */
+		hermes_aux_setaddr(hw, blkaddr);
+		hermes_write_bytes(hw, HERMES_AUXDATA, blk->data,
+				   blklen);
+#else
+		len = (blklen < MAX_DL_SIZE) ? blklen : MAX_DL_SIZE;
+		addr = blkaddr;
+
+		while (addr < (blkaddr + blklen)) {
+			printk(KERN_DEBUG PFX
+			       "Programming subblock of length %d "
+			       "to address 0x%08x. Data @ %p\n",
+			       len, addr, &blk->data[addr - blkaddr]);
+
+			hermes_aux_setaddr(hw, addr);
+			hermes_write_bytes(hw, HERMES_AUXDATA,
+					   &blk->data[addr - blkaddr],
+					   len);
+
+			addr += len;
+			len = ((blkaddr + blklen - addr) < MAX_DL_SIZE) ?
+				(blkaddr + blklen - addr) : MAX_DL_SIZE;
+		}
+#endif
+		blk = (const struct dblock *) &blk->data[blklen];
+
+		if ((const char *) blk > (end - sizeof(*blk)))
+			return -EIO;
+
+		blkaddr = dblock_addr(blk);
+		blklen = dblock_len(blk);
+	}
+	return 0;
+}
+EXPORT_SYMBOL(hermes_program);
+
+static int __init init_hermes_dld(void)
+{
+	return 0;
+}
+
+static void __exit exit_hermes_dld(void)
+{
+}
+
+module_init(init_hermes_dld);
+module_exit(exit_hermes_dld);
+
+/*** Default plugging data for Hermes I ***/
+/* Values from wl_lkm_718/hcf/dhf.c */
+
+#define DEFINE_DEFAULT_PDR(pid, length, data)				\
+static const struct {							\
+	__le16 len;							\
+	__le16 id;							\
+	u8 val[length];							\
+} __attribute__ ((packed)) default_pdr_data_##pid = {			\
+	__constant_cpu_to_le16((sizeof(default_pdr_data_##pid)/		\
+				sizeof(__le16)) - 1),			\
+	__constant_cpu_to_le16(pid),					\
+	data								\
+}
+
+#define DEFAULT_PDR(pid) default_pdr_data_##pid
+
+/*  HWIF Compatiblity */
+DEFINE_DEFAULT_PDR(0x0005, 10, "\x00\x00\x06\x00\x01\x00\x01\x00\x01\x00");
+
+/* PPPPSign */
+DEFINE_DEFAULT_PDR(0x0108, 4, "\x00\x00\x00\x00");
+
+/* PPPPProf */
+DEFINE_DEFAULT_PDR(0x0109, 10, "\x00\x00\x00\x00\x03\x00\x00\x00\x00\x00");
+
+/* Antenna diversity */
+DEFINE_DEFAULT_PDR(0x0150, 2, "\x00\x3F");
+
+/* Modem VCO band Set-up */
+DEFINE_DEFAULT_PDR(0x0160, 28,
+		   "\x00\x00\x00\x00\x00\x00\x00\x00"
+		   "\x00\x00\x00\x00\x00\x00\x00\x00"
+		   "\x00\x00\x00\x00\x00\x00\x00\x00"
+		   "\x00\x00\x00\x00");
+
+/* Modem Rx Gain Table Values */
+DEFINE_DEFAULT_PDR(0x0161, 256,
+		   "\x3F\x01\x3F\01\x3F\x01\x3F\x01"
+		   "\x3F\x01\x3F\01\x3F\x01\x3F\x01"
+		   "\x3F\x01\x3F\01\x3F\x01\x3F\x01"
+		   "\x3F\x01\x3F\01\x3F\x01\x3F\x01"
+		   "\x3F\x01\x3E\01\x3E\x01\x3D\x01"
+		   "\x3D\x01\x3C\01\x3C\x01\x3B\x01"
+		   "\x3B\x01\x3A\01\x3A\x01\x39\x01"
+		   "\x39\x01\x38\01\x38\x01\x37\x01"
+		   "\x37\x01\x36\01\x36\x01\x35\x01"
+		   "\x35\x01\x34\01\x34\x01\x33\x01"
+		   "\x33\x01\x32\x01\x32\x01\x31\x01"
+		   "\x31\x01\x30\x01\x30\x01\x7B\x01"
+		   "\x7B\x01\x7A\x01\x7A\x01\x79\x01"
+		   "\x79\x01\x78\x01\x78\x01\x77\x01"
+		   "\x77\x01\x76\x01\x76\x01\x75\x01"
+		   "\x75\x01\x74\x01\x74\x01\x73\x01"
+		   "\x73\x01\x72\x01\x72\x01\x71\x01"
+		   "\x71\x01\x70\x01\x70\x01\x68\x01"
+		   "\x68\x01\x67\x01\x67\x01\x66\x01"
+		   "\x66\x01\x65\x01\x65\x01\x57\x01"
+		   "\x57\x01\x56\x01\x56\x01\x55\x01"
+		   "\x55\x01\x54\x01\x54\x01\x53\x01"
+		   "\x53\x01\x52\x01\x52\x01\x51\x01"
+		   "\x51\x01\x50\x01\x50\x01\x48\x01"
+		   "\x48\x01\x47\x01\x47\x01\x46\x01"
+		   "\x46\x01\x45\x01\x45\x01\x44\x01"
+		   "\x44\x01\x43\x01\x43\x01\x42\x01"
+		   "\x42\x01\x41\x01\x41\x01\x40\x01"
+		   "\x40\x01\x40\x01\x40\x01\x40\x01"
+		   "\x40\x01\x40\x01\x40\x01\x40\x01"
+		   "\x40\x01\x40\x01\x40\x01\x40\x01"
+		   "\x40\x01\x40\x01\x40\x01\x40\x01");
+
+/* Write PDA according to certain rules.
+ *
+ * For every production data record, look for a previous setting in
+ * the pda, and use that.
+ *
+ * For certain records, use defaults if they are not found in pda.
+ */
+int hermes_apply_pda_with_defaults(hermes_t *hw,
+				   const char *first_pdr,
+				   const __le16 *pda)
+{
+	const struct pdr *pdr = (const struct pdr *) first_pdr;
+	struct pdi *first_pdi = (struct pdi *) &pda[2];
+	struct pdi *pdi;
+	struct pdi *default_pdi = NULL;
+	struct pdi *outdoor_pdi;
+	void *end = (void *)first_pdr + MAX_PDA_SIZE;
+	int record_id;
+
+	while (((void *)pdr < end) &&
+	       (pdr_id(pdr) != PDI_END)) {
+		/*
+		 * For spectrum_cs firmwares,
+		 * PDR area is currently not terminated by PDI_END.
+		 * It's followed by CRC records, which have the type
+		 * field where PDR has length.  The type can be 0 or 1.
+		 */
+		if (pdr_len(pdr) < 2)
+			break;
+		record_id = pdr_id(pdr);
+
+		pdi = hermes_find_pdi(first_pdi, record_id);
+		if (pdi)
+			printk(KERN_DEBUG PFX "Found record 0x%04x at %p\n",
+			       record_id, pdi);
+
+		switch (record_id) {
+		case 0x110: /* Modem REFDAC values */
+		case 0x120: /* Modem VGDAC values */
+			outdoor_pdi = hermes_find_pdi(first_pdi, record_id + 1);
+			default_pdi = NULL;
+			if (outdoor_pdi) {
+				pdi = outdoor_pdi;
+				printk(KERN_DEBUG PFX
+				       "Using outdoor record 0x%04x at %p\n",
+				       record_id + 1, pdi);
+			}
+			break;
+		case 0x5: /*  HWIF Compatiblity */
+			default_pdi = (struct pdi *) &DEFAULT_PDR(0x0005);
+			break;
+		case 0x108: /* PPPPSign */
+			default_pdi = (struct pdi *) &DEFAULT_PDR(0x0108);
+			break;
+		case 0x109: /* PPPPProf */
+			default_pdi = (struct pdi *) &DEFAULT_PDR(0x0109);
+			break;
+		case 0x150: /* Antenna diversity */
+			default_pdi = (struct pdi *) &DEFAULT_PDR(0x0150);
+			break;
+		case 0x160: /* Modem VCO band Set-up */
+			default_pdi = (struct pdi *) &DEFAULT_PDR(0x0160);
+			break;
+		case 0x161: /* Modem Rx Gain Table Values */
+			default_pdi = (struct pdi *) &DEFAULT_PDR(0x0161);
+			break;
+		default:
+			default_pdi = NULL;
+			break;
+		}
+		if (!pdi && default_pdi) {
+			/* Use default */
+			pdi = default_pdi;
+			printk(KERN_DEBUG PFX
+			       "Using default record 0x%04x at %p\n",
+			       record_id, pdi);
+		}
+
+		if (pdi) {
+			/* Lengths of the data in PDI and PDR must match */
+			if (pdi_len(pdi) == pdr_len(pdr)) {
+				/* do the actual plugging */
+				hermes_aux_setaddr(hw, pdr_addr(pdr));
+				hermes_write_bytes(hw, HERMES_AUXDATA,
+						   pdi->data, pdi_len(pdi));
+			}
+		}
+
+		pdr++;
+	}
+	return 0;
+}
+EXPORT_SYMBOL(hermes_apply_pda_with_defaults);
diff --git a/drivers/net/wireless/hermes_dld.h b/drivers/net/wireless/hermes_dld.h
new file mode 100644
index 0000000..6fcb262
--- /dev/null
+++ b/drivers/net/wireless/hermes_dld.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2007, David Kilroy
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License
+ * at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU General Public License version 2 (the "GPL"), 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 MPL, 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 MPL or the GPL.
+ */
+#ifndef _HERMES_DLD_H
+#define _HERMES_DLD_H
+
+#include "hermes.h"
+
+int hermesi_program_init(hermes_t *hw, u32 offset);
+int hermesi_program_end(hermes_t *hw);
+int hermes_program(hermes_t *hw, const char *first_block, const char *end);
+
+int hermes_read_pda(hermes_t *hw,
+		    __le16 *pda,
+		    u32 pda_addr,
+		    u16 pda_len,
+		    int use_eeprom);
+int hermes_apply_pda(hermes_t *hw,
+		     const char *first_pdr,
+		     const __le16 *pda);
+int hermes_apply_pda_with_defaults(hermes_t *hw,
+				   const char *first_pdr,
+				   const __le16 *pda);
+
+size_t hermes_blocks_length(const char *first_block);
+
+#endif /* _HERMES_DLD_H */
diff --git a/drivers/net/wireless/hermes_rid.h b/drivers/net/wireless/hermes_rid.h
index 4f46b48..42eb67d 100644
--- a/drivers/net/wireless/hermes_rid.h
+++ b/drivers/net/wireless/hermes_rid.h
@@ -30,6 +30,7 @@
 #define HERMES_RID_CNFWEPENABLED_AGERE		0xFC20
 #define HERMES_RID_CNFAUTHENTICATION_AGERE	0xFC21
 #define HERMES_RID_CNFMANDATORYBSSID_SYMBOL	0xFC21
+#define HERMES_RID_CNFDROPUNENCRYPTED		0xFC22
 #define HERMES_RID_CNFWEPDEFAULTKEYID		0xFC23
 #define HERMES_RID_CNFDEFAULTKEY0		0xFC24
 #define HERMES_RID_CNFDEFAULTKEY1		0xFC25
@@ -85,6 +86,16 @@
 #define HERMES_RID_CNFSCANSSID_AGERE		0xFCB2
 #define HERMES_RID_CNFBASICRATES		0xFCB3
 #define HERMES_RID_CNFSUPPORTEDRATES		0xFCB4
+#define HERMES_RID_CNFADDDEFAULTTKIPKEY_AGERE	0xFCB4
+#define HERMES_RID_CNFSETWPAAUTHMGMTSUITE_AGERE	0xFCB5
+#define HERMES_RID_CNFREMDEFAULTTKIPKEY_AGERE	0xFCB6
+#define HERMES_RID_CNFADDMAPPEDTKIPKEY_AGERE	0xFCB7
+#define HERMES_RID_CNFREMMAPPEDTKIPKEY_AGERE	0xFCB8
+#define HERMES_RID_CNFSETWPACAPABILITIES_AGERE	0xFCB9
+#define HERMES_RID_CNFCACHEDPMKADDRESS		0xFCBA
+#define HERMES_RID_CNFREMOVEPMKADDRESS		0xFCBB
+#define HERMES_RID_CNFSCANCHANNELS2GHZ		0xFCC2
+#define HERMES_RID_CNFDISASSOCIATE		0xFCC8
 #define HERMES_RID_CNFTICKTIME			0xFCE0
 #define HERMES_RID_CNFSCANREQUEST		0xFCE1
 #define HERMES_RID_CNFJOINREQUEST		0xFCE2
@@ -137,6 +148,12 @@
 #define HERMES_RID_CURRENTTXRATE6		0xFD85
 #define HERMES_RID_OWNMACADDR			0xFD86
 #define HERMES_RID_SCANRESULTSTABLE		0xFD88
+#define HERMES_RID_CURRENT_COUNTRY_INFO		0xFD89
+#define HERMES_RID_CURRENT_WPA_IE		0xFD8A
+#define HERMES_RID_CURRENT_TKIP_IV		0xFD8B
+#define HERMES_RID_CURRENT_ASSOC_REQ_INFO	0xFD8C
+#define HERMES_RID_CURRENT_ASSOC_RESP_INFO	0xFD8D
+#define HERMES_RID_TXQUEUEEMPTY			0xFD91
 #define HERMES_RID_PHYTYPE			0xFDC0
 #define HERMES_RID_CURRENTCHANNEL		0xFDC1
 #define HERMES_RID_CURRENTPOWERSTATE		0xFDC2
diff --git a/drivers/net/wireless/hostap/hostap_cs.c b/drivers/net/wireless/hostap/hostap_cs.c
index 3b4e55c..6337402 100644
--- a/drivers/net/wireless/hostap/hostap_cs.c
+++ b/drivers/net/wireless/hostap/hostap_cs.c
@@ -234,7 +234,7 @@
 	reg.Value = hw_priv->link->io.BasePort1 & 0x00ff;
 	res = pcmcia_access_configuration_register(hw_priv->link,
 						   &reg);
-	if (res != CS_SUCCESS) {
+	if (res != 0) {
 		printk(KERN_DEBUG "Prism3 SanDisk - failed to set I/O base 0 -"
 		       " res=%d\n", res);
 	}
@@ -246,7 +246,7 @@
 	reg.Value = (hw_priv->link->io.BasePort1 & 0xff00) >> 8;
 	res = pcmcia_access_configuration_register(hw_priv->link,
 						   &reg);
-	if (res != CS_SUCCESS) {
+	if (res != 0) {
 		printk(KERN_DEBUG "Prism3 SanDisk - failed to set I/O base 1 -"
 		       " res=%d\n", res);
 	}
@@ -305,7 +305,7 @@
 	tuple.DesiredTuple = CISTPL_LONGLINK_MFC;
 	if (pcmcia_get_first_tuple(hw_priv->link, &tuple) ||
 	    pcmcia_get_tuple_data(hw_priv->link, &tuple) ||
-	    pcmcia_parse_tuple(hw_priv->link, &tuple, parse) ||
+	    pcmcia_parse_tuple(&tuple, parse) ||
 		parse->longlink_mfc.nfn < 2) {
 		/* No multi-function links found */
 		ret = -ENODEV;
@@ -322,7 +322,7 @@
 	reg.Value = COR_SOFT_RESET;
 	res = pcmcia_access_configuration_register(hw_priv->link,
 						   &reg);
-	if (res != CS_SUCCESS) {
+	if (res != 0) {
 		printk(KERN_DEBUG "%s: SanDisk - COR sreset failed (%d)\n",
 		       dev->name, res);
 		goto done;
@@ -339,7 +339,7 @@
 	reg.Value = COR_LEVEL_REQ | 0x8 | COR_ADDR_DECODE | COR_FUNC_ENA;
 	res = pcmcia_access_configuration_register(hw_priv->link,
 						   &reg);
-	if (res != CS_SUCCESS) {
+	if (res != 0) {
 		printk(KERN_DEBUG "%s: SanDisk - COR sreset failed (%d)\n",
 		       dev->name, res);
 		goto done;
@@ -374,7 +374,7 @@
 	reg.Value = 0;
 	res = pcmcia_access_configuration_register(hw_priv->link,
 						   &reg);
-	if (res != CS_SUCCESS) {
+	if (res != 0) {
 		printk(KERN_DEBUG "prism2_pccard_cor_sreset failed 1 (%d)\n",
 		       res);
 		return;
@@ -386,7 +386,7 @@
 	reg.Value |= COR_SOFT_RESET;
 	res = pcmcia_access_configuration_register(hw_priv->link,
 						   &reg);
-	if (res != CS_SUCCESS) {
+	if (res != 0) {
 		printk(KERN_DEBUG "prism2_pccard_cor_sreset failed 2 (%d)\n",
 		       res);
 		return;
@@ -399,7 +399,7 @@
 		reg.Value |= COR_IREQ_ENA;
 	res = pcmcia_access_configuration_register(hw_priv->link,
 						   &reg);
-	if (res != CS_SUCCESS) {
+	if (res != 0) {
 		printk(KERN_DEBUG "prism2_pccard_cor_sreset failed 3 (%d)\n",
 		       res);
 		return;
@@ -433,7 +433,7 @@
 	reg.Value = 0;
 	res = pcmcia_access_configuration_register(hw_priv->link,
 						   &reg);
-	if (res != CS_SUCCESS) {
+	if (res != 0) {
 		printk(KERN_DEBUG "prism2_pccard_genesis_sreset failed 1 "
 		       "(%d)\n", res);
 		return;
@@ -446,7 +446,7 @@
 	reg.Value |= COR_SOFT_RESET;
 	res = pcmcia_access_configuration_register(hw_priv->link,
 						   &reg);
-	if (res != CS_SUCCESS) {
+	if (res != 0) {
 		printk(KERN_DEBUG "prism2_pccard_genesis_sreset failed 2 "
 		       "(%d)\n", res);
 		return;
@@ -460,7 +460,7 @@
 	reg.Offset = CISREG_CCSR;
 	res = pcmcia_access_configuration_register(hw_priv->link,
 						   &reg);
-	if (res != CS_SUCCESS) {
+	if (res != 0) {
 		printk(KERN_DEBUG "prism2_pccard_genesis_sreset failed 3 "
 		       "(%d)\n", res);
 		return;
@@ -472,7 +472,7 @@
 	reg.Value = old_cor & ~COR_SOFT_RESET;
 	res = pcmcia_access_configuration_register(hw_priv->link,
 						   &reg);
-	if (res != CS_SUCCESS) {
+	if (res != 0) {
 		printk(KERN_DEBUG "prism2_pccard_genesis_sreset failed 4 "
 		       "(%d)\n", res);
 		return;
@@ -532,145 +532,118 @@
 #define CS_CHECK(fn, ret) \
 do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)
 
-#define CFG_CHECK2(fn, retf) \
-do { int _ret = (retf); \
-if (_ret != 0) { \
-	PDEBUG(DEBUG_EXTRA, "CardServices(" #fn ") returned %d\n", _ret); \
-	cs_error(link, fn, _ret); \
-	goto next_entry; \
-} \
-} while (0)
-
 
 /* run after a CARD_INSERTION event is received to configure the PCMCIA
  * socket and make the device available to the system */
+
+static int prism2_config_check(struct pcmcia_device *p_dev,
+			       cistpl_cftable_entry_t *cfg,
+			       cistpl_cftable_entry_t *dflt,
+			       unsigned int vcc,
+			       void *priv_data)
+{
+	if (cfg->index == 0)
+		return -ENODEV;
+
+	PDEBUG(DEBUG_EXTRA, "Checking CFTABLE_ENTRY 0x%02X "
+	       "(default 0x%02X)\n", cfg->index, dflt->index);
+
+	/* Does this card need audio output? */
+	if (cfg->flags & CISTPL_CFTABLE_AUDIO) {
+		p_dev->conf.Attributes |= CONF_ENABLE_SPKR;
+		p_dev->conf.Status = CCSR_AUDIO_ENA;
+	}
+
+	/* Use power settings for Vcc and Vpp if present */
+	/*  Note that the CIS values need to be rescaled */
+	if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) {
+		if (vcc != cfg->vcc.param[CISTPL_POWER_VNOM] /
+		    10000 && !ignore_cis_vcc) {
+			PDEBUG(DEBUG_EXTRA, "  Vcc mismatch - skipping"
+			       " this entry\n");
+			return -ENODEV;
+		}
+	} else if (dflt->vcc.present & (1 << CISTPL_POWER_VNOM)) {
+		if (vcc != dflt->vcc.param[CISTPL_POWER_VNOM] /
+		    10000 && !ignore_cis_vcc) {
+			PDEBUG(DEBUG_EXTRA, "  Vcc (default) mismatch "
+			       "- skipping this entry\n");
+			return -ENODEV;
+		}
+	}
+
+	if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM))
+		p_dev->conf.Vpp = cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000;
+	else if (dflt->vpp1.present & (1 << CISTPL_POWER_VNOM))
+		p_dev->conf.Vpp = dflt->vpp1.param[CISTPL_POWER_VNOM] / 10000;
+
+	/* Do we need to allocate an interrupt? */
+	if (cfg->irq.IRQInfo1 || dflt->irq.IRQInfo1)
+		p_dev->conf.Attributes |= CONF_ENABLE_IRQ;
+	else if (!(p_dev->conf.Attributes & CONF_ENABLE_IRQ)) {
+		/* At least Compaq WL200 does not have IRQInfo1 set,
+		 * but it does not work without interrupts.. */
+		printk(KERN_WARNING "Config has no IRQ info, but trying to "
+		       "enable IRQ anyway..\n");
+		p_dev->conf.Attributes |= CONF_ENABLE_IRQ;
+	}
+
+	/* IO window settings */
+	PDEBUG(DEBUG_EXTRA, "IO window settings: cfg->io.nwin=%d "
+	       "dflt->io.nwin=%d\n",
+	       cfg->io.nwin, dflt->io.nwin);
+	p_dev->io.NumPorts1 = p_dev->io.NumPorts2 = 0;
+	if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) {
+		cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io;
+		p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
+		PDEBUG(DEBUG_EXTRA, "io->flags = 0x%04X, "
+		       "io.base=0x%04x, len=%d\n", io->flags,
+		       io->win[0].base, io->win[0].len);
+		if (!(io->flags & CISTPL_IO_8BIT))
+			p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_16;
+		if (!(io->flags & CISTPL_IO_16BIT))
+			p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
+		p_dev->io.IOAddrLines = io->flags &
+			CISTPL_IO_LINES_MASK;
+		p_dev->io.BasePort1 = io->win[0].base;
+		p_dev->io.NumPorts1 = io->win[0].len;
+		if (io->nwin > 1) {
+			p_dev->io.Attributes2 = p_dev->io.Attributes1;
+			p_dev->io.BasePort2 = io->win[1].base;
+			p_dev->io.NumPorts2 = io->win[1].len;
+		}
+	}
+
+	/* This reserves IO space but doesn't actually enable it */
+	return pcmcia_request_io(p_dev, &p_dev->io);
+}
+
 static int prism2_config(struct pcmcia_device *link)
 {
 	struct net_device *dev;
 	struct hostap_interface *iface;
 	local_info_t *local;
 	int ret = 1;
-	tuple_t tuple;
-	cisparse_t *parse;
 	int last_fn, last_ret;
-	u_char buf[64];
-	config_info_t conf;
-	cistpl_cftable_entry_t dflt = { 0 };
 	struct hostap_cs_priv *hw_priv;
 
 	PDEBUG(DEBUG_FLOW, "prism2_config()\n");
 
-	parse = kmalloc(sizeof(cisparse_t), GFP_KERNEL);
 	hw_priv = kzalloc(sizeof(*hw_priv), GFP_KERNEL);
-	if (parse == NULL || hw_priv == NULL) {
+	if (hw_priv == NULL) {
 		ret = -ENOMEM;
 		goto failed;
 	}
 
-	tuple.Attributes = 0;
-	tuple.TupleData = buf;
-	tuple.TupleDataMax = sizeof(buf);
-	tuple.TupleOffset = 0;
-
-	CS_CHECK(GetConfigurationInfo,
-		 pcmcia_get_configuration_info(link, &conf));
-
 	/* Look for an appropriate configuration table entry in the CIS */
-	tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
-	CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple));
-	for (;;) {
-		cistpl_cftable_entry_t *cfg = &(parse->cftable_entry);
-		CFG_CHECK2(GetTupleData,
-			   pcmcia_get_tuple_data(link, &tuple));
-		CFG_CHECK2(ParseTuple,
-			   pcmcia_parse_tuple(link, &tuple, parse));
-
-		if (cfg->flags & CISTPL_CFTABLE_DEFAULT)
-			dflt = *cfg;
-		if (cfg->index == 0)
-			goto next_entry;
-		link->conf.ConfigIndex = cfg->index;
-		PDEBUG(DEBUG_EXTRA, "Checking CFTABLE_ENTRY 0x%02X "
-		       "(default 0x%02X)\n", cfg->index, dflt.index);
-
-		/* Does this card need audio output? */
-		if (cfg->flags & CISTPL_CFTABLE_AUDIO) {
-			link->conf.Attributes |= CONF_ENABLE_SPKR;
-			link->conf.Status = CCSR_AUDIO_ENA;
-		}
-
-		/* Use power settings for Vcc and Vpp if present */
-		/*  Note that the CIS values need to be rescaled */
-		if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) {
-			if (conf.Vcc != cfg->vcc.param[CISTPL_POWER_VNOM] /
-			    10000 && !ignore_cis_vcc) {
-				PDEBUG(DEBUG_EXTRA, "  Vcc mismatch - skipping"
-				       " this entry\n");
-				goto next_entry;
-			}
-		} else if (dflt.vcc.present & (1 << CISTPL_POWER_VNOM)) {
-			if (conf.Vcc != dflt.vcc.param[CISTPL_POWER_VNOM] /
-			    10000 && !ignore_cis_vcc) {
-				PDEBUG(DEBUG_EXTRA, "  Vcc (default) mismatch "
-				       "- skipping this entry\n");
-				goto next_entry;
-			}
-		}
-
-		if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM))
-			link->conf.Vpp =
-				cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000;
-		else if (dflt.vpp1.present & (1 << CISTPL_POWER_VNOM))
-			link->conf.Vpp =
-				dflt.vpp1.param[CISTPL_POWER_VNOM] / 10000;
-
-		/* Do we need to allocate an interrupt? */
-		if (cfg->irq.IRQInfo1 || dflt.irq.IRQInfo1)
-			link->conf.Attributes |= CONF_ENABLE_IRQ;
-		else if (!(link->conf.Attributes & CONF_ENABLE_IRQ)) {
-			/* At least Compaq WL200 does not have IRQInfo1 set,
-			 * but it does not work without interrupts.. */
-			printk("Config has no IRQ info, but trying to enable "
-			       "IRQ anyway..\n");
-			link->conf.Attributes |= CONF_ENABLE_IRQ;
-		}
-
-		/* IO window settings */
-		PDEBUG(DEBUG_EXTRA, "IO window settings: cfg->io.nwin=%d "
-		       "dflt.io.nwin=%d\n",
-		       cfg->io.nwin, dflt.io.nwin);
-		link->io.NumPorts1 = link->io.NumPorts2 = 0;
-		if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) {
-			cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt.io;
-			link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
-			PDEBUG(DEBUG_EXTRA, "io->flags = 0x%04X, "
-			       "io.base=0x%04x, len=%d\n", io->flags,
-			       io->win[0].base, io->win[0].len);
-			if (!(io->flags & CISTPL_IO_8BIT))
-				link->io.Attributes1 = IO_DATA_PATH_WIDTH_16;
-			if (!(io->flags & CISTPL_IO_16BIT))
-				link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
-			link->io.IOAddrLines = io->flags &
-				CISTPL_IO_LINES_MASK;
-			link->io.BasePort1 = io->win[0].base;
-			link->io.NumPorts1 = io->win[0].len;
-			if (io->nwin > 1) {
-				link->io.Attributes2 = link->io.Attributes1;
-				link->io.BasePort2 = io->win[1].base;
-				link->io.NumPorts2 = io->win[1].len;
-			}
-		}
-
-		/* This reserves IO space but doesn't actually enable it */
-		CFG_CHECK2(RequestIO,
-			   pcmcia_request_io(link, &link->io));
-
-		/* This configuration table entry is OK */
-		break;
-
-	next_entry:
-		CS_CHECK(GetNextTuple,
-			 pcmcia_get_next_tuple(link, &tuple));
+	last_ret = pcmcia_loop_config(link, prism2_config_check, NULL);
+	if (last_ret) {
+		if (!ignore_cis_vcc)
+			printk(KERN_ERR "GetNextTuple(): No matching "
+			       "CIS configuration.  Maybe you need the "
+			       "ignore_cis_vcc=1 parameter.\n");
+		cs_error(link, RequestIO, last_ret);
+		goto failed;
 	}
 
 	/* Need to allocate net_device before requesting IRQ handler */
@@ -738,14 +711,12 @@
 		if (ret == 0 && local->ddev)
 			strcpy(hw_priv->node.dev_name, local->ddev->name);
 	}
-	kfree(parse);
 	return ret;
 
  cs_failed:
 	cs_error(link, last_fn, last_ret);
 
  failed:
-	kfree(parse);
 	kfree(hw_priv);
 	prism2_release((u_long)link);
 	return ret;
diff --git a/drivers/net/wireless/ipw2100.c b/drivers/net/wireless/ipw2100.c
index 19a401c..bca7481 100644
--- a/drivers/net/wireless/ipw2100.c
+++ b/drivers/net/wireless/ipw2100.c
@@ -211,7 +211,7 @@
 do { \
 	if (ipw2100_debug_level & (level)) { \
 		printk(KERN_DEBUG "ipw2100: %c %s ", \
-                       in_interrupt() ? 'I' : 'U',  __FUNCTION__); \
+                       in_interrupt() ? 'I' : 'U',  __func__); \
 		printk(message); \
 	} \
 } while (0)
diff --git a/drivers/net/wireless/ipw2200.h b/drivers/net/wireless/ipw2200.h
index d4ab28b..0bad1ec 100644
--- a/drivers/net/wireless/ipw2200.h
+++ b/drivers/net/wireless/ipw2200.h
@@ -1394,13 +1394,13 @@
 #define IPW_DEBUG(level, fmt, args...) \
 do { if (ipw_debug_level & (level)) \
   printk(KERN_DEBUG DRV_NAME": %c %s " fmt, \
-         in_interrupt() ? 'I' : 'U', __FUNCTION__ , ## args); } while (0)
+         in_interrupt() ? 'I' : 'U', __func__ , ## args); } while (0)
 
 #ifdef CONFIG_IPW2200_DEBUG
 #define IPW_LL_DEBUG(level, fmt, args...) \
 do { if (ipw_debug_level & (level)) \
   printk(KERN_DEBUG DRV_NAME": %c %s " fmt, \
-         in_interrupt() ? 'I' : 'U', __FUNCTION__ , ## args); } while (0)
+         in_interrupt() ? 'I' : 'U', __func__ , ## args); } while (0)
 #else
 #define IPW_LL_DEBUG(level, fmt, args...) do {} while (0)
 #endif				/* CONFIG_IPW2200_DEBUG */
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-debug.h b/drivers/net/wireless/iwlwifi/iwl-3945-debug.h
index f1d002f..33016fb 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945-debug.h
+++ b/drivers/net/wireless/iwlwifi/iwl-3945-debug.h
@@ -34,12 +34,12 @@
 #define IWL_DEBUG(level, fmt, args...) \
 do { if (iwl3945_debug_level & (level)) \
   printk(KERN_ERR DRV_NAME": %c %s " fmt, \
-	 in_interrupt() ? 'I' : 'U', __FUNCTION__ , ## args); } while (0)
+	 in_interrupt() ? 'I' : 'U', __func__ , ## args); } while (0)
 
 #define IWL_DEBUG_LIMIT(level, fmt, args...) \
 do { if ((iwl3945_debug_level & (level)) && net_ratelimit()) \
   printk(KERN_ERR DRV_NAME": %c %s " fmt, \
-	 in_interrupt() ? 'I' : 'U', __FUNCTION__ , ## args); } while (0)
+	 in_interrupt() ? 'I' : 'U', __func__ , ## args); } while (0)
 
 static inline void iwl3945_print_hex_dump(int level, void *p, u32 len)
 {
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-io.h b/drivers/net/wireless/iwlwifi/iwl-3945-io.h
index 0b94751..b3fe48d 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945-io.h
+++ b/drivers/net/wireless/iwlwifi/iwl-3945-io.h
@@ -59,7 +59,7 @@
  *
  */
 
-#define _iwl3945_write32(priv, ofs, val) writel((val), (priv)->hw_base + (ofs))
+#define _iwl3945_write32(priv, ofs, val) iowrite32((val), (priv)->hw_base + (ofs))
 #ifdef CONFIG_IWL3945_DEBUG
 static inline void __iwl3945_write32(const char *f, u32 l, struct iwl3945_priv *priv,
 				 u32 ofs, u32 val)
@@ -73,14 +73,14 @@
 #define iwl3945_write32(priv, ofs, val) _iwl3945_write32(priv, ofs, val)
 #endif
 
-#define _iwl3945_read32(priv, ofs) readl((priv)->hw_base + (ofs))
+#define _iwl3945_read32(priv, ofs) ioread32((priv)->hw_base + (ofs))
 #ifdef CONFIG_IWL3945_DEBUG
 static inline u32 __iwl3945_read32(char *f, u32 l, struct iwl3945_priv *priv, u32 ofs)
 {
 	IWL_DEBUG_IO("read_direct32(0x%08X) - %s %d\n", ofs, f, l);
 	return _iwl3945_read32(priv, ofs);
 }
-#define iwl3945_read32(priv, ofs) __iwl3945_read32(__FILE__, __LINE__, priv, ofs)
+#define iwl3945_read32(priv, ofs)__iwl3945_read32(__FILE__, __LINE__, priv, ofs)
 #else
 #define iwl3945_read32(p, o) _iwl3945_read32(p, o)
 #endif
@@ -153,28 +153,10 @@
 static inline int _iwl3945_grab_nic_access(struct iwl3945_priv *priv)
 {
 	int ret;
-	u32 gp_ctl;
-
 #ifdef CONFIG_IWL3945_DEBUG
 	if (atomic_read(&priv->restrict_refcnt))
 		return 0;
 #endif
-	if (test_bit(STATUS_RF_KILL_HW, &priv->status) ||
-	    test_bit(STATUS_RF_KILL_SW, &priv->status)) {
-		IWL_WARNING("WARNING: Requesting MAC access during RFKILL "
-			"wakes up NIC\n");
-
-		/* 10 msec allows time for NIC to complete its data save */
-		gp_ctl = _iwl3945_read32(priv, CSR_GP_CNTRL);
-		if (gp_ctl & CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY) {
-			IWL_DEBUG_RF_KILL("Wait for complete power-down, "
-				"gpctl = 0x%08x\n", gp_ctl);
-			mdelay(10);
-		} else
-			IWL_DEBUG_RF_KILL("power-down complete, "
-					  "gpctl = 0x%08x\n", gp_ctl);
-	}
-
 	/* this bit wakes up the NIC */
 	_iwl3945_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
 	ret = _iwl3945_poll_bit(priv, CSR_GP_CNTRL,
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c
index 10c64bd..6fc5e73 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c
+++ b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c
@@ -36,8 +36,6 @@
 
 #include <linux/workqueue.h>
 
-#include "../net/mac80211/rate.h"
-
 #include "iwl-3945.h"
 
 #define RS_NAME "iwl-3945-rs"
@@ -65,6 +63,9 @@
 	u8 ibss_sta_added;
 	struct timer_list rate_scale_flush;
 	struct iwl3945_rate_scale_data win[IWL_RATE_COUNT];
+
+	/* used to be in sta_info */
+	int last_txrate_idx;
 };
 
 static s32 iwl3945_expected_tpt_g[IWL_RATE_COUNT] = {
@@ -316,9 +317,10 @@
 	}
 }
 
-static void rs_rate_init(void *priv_rate, void *priv_sta,
-			 struct ieee80211_local *local, struct sta_info *sta)
+static void rs_rate_init(void *priv, struct ieee80211_supported_band *sband,
+			 struct ieee80211_sta *sta, void *priv_sta)
 {
+	struct iwl3945_rs_sta *rs_sta = priv_sta;
 	int i;
 
 	IWL_DEBUG_RATE("enter\n");
@@ -329,24 +331,22 @@
 	 * after assoc.. */
 
 	for (i = IWL_RATE_COUNT - 1; i >= 0; i--) {
-		if (sta->supp_rates[local->hw.conf.channel->band] & (1 << i)) {
-			sta->txrate_idx = i;
+		if (sta->supp_rates[sband->band] & (1 << i)) {
+			rs_sta->last_txrate_idx = i;
 			break;
 		}
 	}
 
-	sta->last_txrate_idx = sta->txrate_idx;
-
 	/* For 5 GHz band it start at IWL_FIRST_OFDM_RATE */
-	if (local->hw.conf.channel->band == IEEE80211_BAND_5GHZ)
-		sta->last_txrate_idx += IWL_FIRST_OFDM_RATE;
+	if (sband->band == IEEE80211_BAND_5GHZ)
+		rs_sta->last_txrate_idx += IWL_FIRST_OFDM_RATE;
 
 	IWL_DEBUG_RATE("leave\n");
 }
 
-static void *rs_alloc(struct ieee80211_local *local)
+static void *rs_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir)
 {
-	return local->hw.priv;
+	return hw->priv;
 }
 
 /* rate scale requires free function to be implemented */
@@ -354,17 +354,24 @@
 {
 	return;
 }
+
 static void rs_clear(void *priv)
 {
 	return;
 }
 
 
-static void *rs_alloc_sta(void *priv, gfp_t gfp)
+static void *rs_alloc_sta(void *priv, struct ieee80211_sta *sta, gfp_t gfp)
 {
 	struct iwl3945_rs_sta *rs_sta;
+	struct iwl3945_sta_priv *psta = (void *) sta->drv_priv;
 	int i;
 
+	/*
+	 * XXX: If it's using sta->drv_priv anyway, it might
+	 *	as well just put all the information there.
+	 */
+
 	IWL_DEBUG_RATE("enter\n");
 
 	rs_sta = kzalloc(sizeof(struct iwl3945_rs_sta), gfp);
@@ -373,6 +380,8 @@
 		return NULL;
 	}
 
+	psta->rs_sta = rs_sta;
+
 	spin_lock_init(&rs_sta->lock);
 
 	rs_sta->start_rate = IWL_RATE_INVALID;
@@ -398,10 +407,14 @@
 	return rs_sta;
 }
 
-static void rs_free_sta(void *priv, void *priv_sta)
+static void rs_free_sta(void *priv, struct ieee80211_sta *sta,
+			void *priv_sta)
 {
+	struct iwl3945_sta_priv *psta = (void *) sta->drv_priv;
 	struct iwl3945_rs_sta *rs_sta = priv_sta;
 
+	psta->rs_sta = NULL;
+
 	IWL_DEBUG_RATE("enter\n");
 	del_timer_sync(&rs_sta->rate_scale_flush);
 	kfree(rs_sta);
@@ -443,26 +456,19 @@
  * NOTE: Uses iwl3945_priv->retry_rate for the # of retries attempted by
  * the hardware for each rate.
  */
-static void rs_tx_status(void *priv_rate,
-			 struct net_device *dev,
+static void rs_tx_status(void *priv_rate, struct ieee80211_supported_band *sband,
+			 struct ieee80211_sta *sta, void *priv_sta,
 			 struct sk_buff *skb)
 {
 	u8 retries, current_count;
 	int scale_rate_index, first_index, last_index;
 	unsigned long flags;
-	struct sta_info *sta;
-	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
 	struct iwl3945_priv *priv = (struct iwl3945_priv *)priv_rate;
-	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-	struct iwl3945_rs_sta *rs_sta;
-	struct ieee80211_supported_band *sband;
+	struct iwl3945_rs_sta *rs_sta = priv_sta;
 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
 
 	IWL_DEBUG_RATE("enter\n");
 
-	sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
-
-
 	retries = info->status.retry_count;
 	first_index = sband->bitrates[info->tx_rate_idx].hw_value;
 	if ((first_index < 0) || (first_index >= IWL_RATE_COUNT)) {
@@ -470,17 +476,11 @@
 		return;
 	}
 
-	rcu_read_lock();
-
-	sta = sta_info_get(local, hdr->addr1);
-	if (!sta || !sta->rate_ctrl_priv) {
-		rcu_read_unlock();
+	if (!priv_sta) {
 		IWL_DEBUG_RATE("leave: No STA priv data to update!\n");
 		return;
 	}
 
-	rs_sta = (void *)sta->rate_ctrl_priv;
-
 	rs_sta->tx_packets++;
 
 	scale_rate_index = first_index;
@@ -547,8 +547,6 @@
 
 	spin_unlock_irqrestore(&rs_sta->lock, flags);
 
-	rcu_read_unlock();
-
 	IWL_DEBUG_RATE("leave\n");
 
 	return;
@@ -632,16 +630,15 @@
  * rate table and must reference the driver allocated rate table
  *
  */
-static void rs_get_rate(void *priv_rate, struct net_device *dev,
-			struct ieee80211_supported_band *sband,
-			struct sk_buff *skb,
-			struct rate_selection *sel)
+static void rs_get_rate(void *priv_r, struct ieee80211_supported_band *sband,
+			struct ieee80211_sta *sta, void *priv_sta,
+			struct sk_buff *skb, struct rate_selection *sel)
 {
 	u8 low = IWL_RATE_INVALID;
 	u8 high = IWL_RATE_INVALID;
 	u16 high_low;
 	int index;
-	struct iwl3945_rs_sta *rs_sta;
+	struct iwl3945_rs_sta *rs_sta = priv_sta;
 	struct iwl3945_rate_scale_data *window = NULL;
 	int current_tpt = IWL_INV_TPT;
 	int low_tpt = IWL_INV_TPT;
@@ -649,40 +646,31 @@
 	u32 fail_count;
 	s8 scale_action = 0;
 	unsigned long flags;
-	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
-	struct sta_info *sta;
 	u16 fc, rate_mask;
-	struct iwl3945_priv *priv = (struct iwl3945_priv *)priv_rate;
+	struct iwl3945_priv *priv = (struct iwl3945_priv *)priv_r;
 	DECLARE_MAC_BUF(mac);
 
 	IWL_DEBUG_RATE("enter\n");
 
-	rcu_read_lock();
-
-	sta = sta_info_get(local, hdr->addr1);
-
 	/* Send management frames and broadcast/multicast data using lowest
 	 * rate. */
 	fc = le16_to_cpu(hdr->frame_control);
 	if ((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA ||
 	    is_multicast_ether_addr(hdr->addr1) ||
-	    !sta || !sta->rate_ctrl_priv) {
+	    !sta || !priv_sta) {
 		IWL_DEBUG_RATE("leave: No STA priv data to update!\n");
-		sel->rate_idx = rate_lowest_index(local, sband, sta);
-		rcu_read_unlock();
+		sel->rate_idx = rate_lowest_index(sband, sta);
 		return;
 	}
 
 	rate_mask = sta->supp_rates[sband->band];
-	index = min(sta->last_txrate_idx & 0xffff, IWL_RATE_COUNT - 1);
+	index = min(rs_sta->last_txrate_idx & 0xffff, IWL_RATE_COUNT - 1);
 
 	if (sband->band == IEEE80211_BAND_5GHZ)
 		rate_mask = rate_mask << IWL_FIRST_OFDM_RATE;
 
-	rs_sta = (void *)sta->rate_ctrl_priv;
-
-	if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) &&
+	if ((priv->iw_mode == NL80211_IFTYPE_ADHOC) &&
 	    !rs_sta->ibss_sta_added) {
 		u8 sta_id = iwl3945_hw_find_station(priv, hdr->addr1);
 
@@ -803,17 +791,13 @@
 
  out:
 
-	sta->last_txrate_idx = index;
+	rs_sta->last_txrate_idx = index;
 	if (sband->band == IEEE80211_BAND_5GHZ)
-		sta->txrate_idx = sta->last_txrate_idx - IWL_FIRST_OFDM_RATE;
+		sel->rate_idx = rs_sta->last_txrate_idx - IWL_FIRST_OFDM_RATE;
 	else
-		sta->txrate_idx = sta->last_txrate_idx;
-
-	rcu_read_unlock();
+		sel->rate_idx = rs_sta->last_txrate_idx;
 
 	IWL_DEBUG_RATE("leave: %d\n", index);
-
-	sel->rate_idx = sta->txrate_idx;
 }
 
 static struct rate_control_ops rs_ops = {
@@ -829,114 +813,28 @@
 	.free_sta = rs_free_sta,
 };
 
-int iwl3945_fill_rs_info(struct ieee80211_hw *hw, char *buf, u8 sta_id)
-{
-	struct ieee80211_local *local = hw_to_local(hw);
-	struct iwl3945_priv *priv = hw->priv;
-	struct iwl3945_rs_sta *rs_sta;
-	struct sta_info *sta;
-	unsigned long flags;
-	int count = 0, i;
-	u32 samples = 0, success = 0, good = 0;
-	unsigned long now = jiffies;
-	u32 max_time = 0;
-
-	rcu_read_lock();
-
-	sta = sta_info_get(local, priv->stations[sta_id].sta.sta.addr);
-	if (!sta || !sta->rate_ctrl_priv) {
-		if (sta)
-			IWL_DEBUG_RATE("leave - no private rate data!\n");
-		else
-			IWL_DEBUG_RATE("leave - no station!\n");
-		rcu_read_unlock();
-		return sprintf(buf, "station %d not found\n", sta_id);
-	}
-
-	rs_sta = (void *)sta->rate_ctrl_priv;
-	spin_lock_irqsave(&rs_sta->lock, flags);
-	i = IWL_RATE_54M_INDEX;
-	while (1) {
-		u64 mask;
-		int j;
-
-		count +=
-		    sprintf(&buf[count], " %2dMbs: ", iwl3945_rates[i].ieee / 2);
-
-		mask = (1ULL << (IWL_RATE_MAX_WINDOW - 1));
-		for (j = 0; j < IWL_RATE_MAX_WINDOW; j++, mask >>= 1)
-			buf[count++] =
-			    (rs_sta->win[i].data & mask) ? '1' : '0';
-
-		samples += rs_sta->win[i].counter;
-		good += rs_sta->win[i].success_counter;
-		success += rs_sta->win[i].success_counter *
-						iwl3945_rates[i].ieee;
-
-		if (rs_sta->win[i].stamp) {
-			int delta =
-			    jiffies_to_msecs(now - rs_sta->win[i].stamp);
-
-			if (delta > max_time)
-				max_time = delta;
-
-			count += sprintf(&buf[count], "%5dms\n", delta);
-		} else
-			buf[count++] = '\n';
-
-		j = iwl3945_get_prev_ieee_rate(i);
-		if (j == i)
-			break;
-		i = j;
-	}
-	spin_unlock_irqrestore(&rs_sta->lock, flags);
-	rcu_read_unlock();
-
-	/* Display the average rate of all samples taken.
-	 *
-	 * NOTE:  We multiple # of samples by 2 since the IEEE measurement
-	 * added from iwl3945_rates is actually 2X the rate */
-	if (samples)
-		count += sprintf(
-			&buf[count],
-			"\nAverage rate is %3d.%02dMbs over last %4dms\n"
-			"%3d%% success (%d good packets over %d tries)\n",
-			success / (2 * samples), (success * 5 / samples) % 10,
-			max_time, good * 100 / samples, good, samples);
-	else
-		count += sprintf(&buf[count], "\nAverage rate: 0Mbs\n");
-
-	return count;
-}
-
 void iwl3945_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id)
 {
 	struct iwl3945_priv *priv = hw->priv;
 	s32 rssi = 0;
 	unsigned long flags;
-	struct ieee80211_local *local = hw_to_local(hw);
 	struct iwl3945_rs_sta *rs_sta;
-	struct sta_info *sta;
+	struct ieee80211_sta *sta;
+	struct iwl3945_sta_priv *psta;
 
 	IWL_DEBUG_RATE("enter\n");
 
-	if (!local->rate_ctrl->ops->name ||
-	    strcmp(local->rate_ctrl->ops->name, RS_NAME)) {
-		IWL_WARNING("iwl-3945-rs not selected as rate control algo!\n");
-		IWL_DEBUG_RATE("leave - mac80211 picked the wrong RC algo.\n");
-		return;
-	}
-
 	rcu_read_lock();
 
-	sta = sta_info_get(local, priv->stations[sta_id].sta.sta.addr);
-	if (!sta || !sta->rate_ctrl_priv) {
+	sta = ieee80211_find_sta(hw, priv->stations[sta_id].sta.sta.addr);
+	psta = (void *) sta->drv_priv;
+	if (!sta || !psta) {
 		IWL_DEBUG_RATE("leave - no private rate data!\n");
 		rcu_read_unlock();
 		return;
 	}
 
-	rs_sta = (void *)sta->rate_ctrl_priv;
+	rs_sta = psta->rs_sta;
 
 	spin_lock_irqsave(&rs_sta->lock, flags);
 
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-rs.h b/drivers/net/wireless/iwlwifi/iwl-3945-rs.h
index f085d33..98b17ae 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945-rs.h
+++ b/drivers/net/wireless/iwlwifi/iwl-3945-rs.h
@@ -176,15 +176,6 @@
 }
 
 /**
- * iwl3945_fill_rs_info - Fill an output text buffer with the rate representation
- *
- * NOTE:  This is provided as a quick mechanism for a user to visualize
- * the performance of the rate control algorithm and is not meant to be
- * parsed software.
- */
-extern int iwl3945_fill_rs_info(struct ieee80211_hw *, char *buf, u8 sta_id);
-
-/**
  * iwl3945_rate_scale_init - Initialize the rate scale table based on assoc info
  *
  * The specific throughput table used is based on the type of network
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c
index 3f51f36..7ca5627 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945.c
+++ b/drivers/net/wireless/iwlwifi/iwl-3945.c
@@ -520,10 +520,10 @@
 	/* Filter incoming packets to determine if they are targeted toward
 	 * this network, discarding packets coming from ourselves */
 	switch (priv->iw_mode) {
-	case IEEE80211_IF_TYPE_IBSS: /* Header: Dest. | Source    | BSSID */
+	case NL80211_IFTYPE_ADHOC: /* Header: Dest. | Source    | BSSID */
 		/* packets to our IBSS update information */
 		return !compare_ether_addr(header->addr3, priv->bssid);
-	case IEEE80211_IF_TYPE_STA: /* Header: Dest. | AP{BSSID} | Source */
+	case NL80211_IFTYPE_STATION: /* Header: Dest. | AP{BSSID} | Source */
 		/* packets to our IBSS update information */
 		return !compare_ether_addr(header->addr2, priv->bssid);
 	default:
@@ -531,99 +531,6 @@
 	}
 }
 
-static void iwl3945_add_radiotap(struct iwl3945_priv *priv,
-				 struct sk_buff *skb,
-				 struct iwl3945_rx_frame_hdr *rx_hdr,
-				 struct ieee80211_rx_status *stats)
-{
-	/* First cache any information we need before we overwrite
-	 * the information provided in the skb from the hardware */
-	s8 signal = stats->signal;
-	s8 noise = 0;
-	int rate = stats->rate_idx;
-	u64 tsf = stats->mactime;
-	__le16 phy_flags_hw = rx_hdr->phy_flags, antenna;
-
-	struct iwl3945_rt_rx_hdr {
-		struct ieee80211_radiotap_header rt_hdr;
-		__le64 rt_tsf;		/* TSF */
-		u8 rt_flags;		/* radiotap packet flags */
-		u8 rt_rate;		/* rate in 500kb/s */
-		__le16 rt_channelMHz;	/* channel in MHz */
-		__le16 rt_chbitmask;	/* channel bitfield */
-		s8 rt_dbmsignal;	/* signal in dBm, kluged to signed */
-		s8 rt_dbmnoise;
-		u8 rt_antenna;		/* antenna number */
-	} __attribute__ ((packed)) *iwl3945_rt;
-
-	if (skb_headroom(skb) < sizeof(*iwl3945_rt)) {
-		if (net_ratelimit())
-			printk(KERN_ERR "not enough headroom [%d] for "
-			       "radiotap head [%zd]\n",
-			       skb_headroom(skb), sizeof(*iwl3945_rt));
-		return;
-	}
-
-	/* put radiotap header in front of 802.11 header and data */
-	iwl3945_rt = (void *)skb_push(skb, sizeof(*iwl3945_rt));
-
-	/* initialise radiotap header */
-	iwl3945_rt->rt_hdr.it_version = PKTHDR_RADIOTAP_VERSION;
-	iwl3945_rt->rt_hdr.it_pad = 0;
-
-	/* total header + data */
-	put_unaligned_le16(sizeof(*iwl3945_rt), &iwl3945_rt->rt_hdr.it_len);
-
-	/* Indicate all the fields we add to the radiotap header */
-	put_unaligned_le32((1 << IEEE80211_RADIOTAP_TSFT) |
-			   (1 << IEEE80211_RADIOTAP_FLAGS) |
-			   (1 << IEEE80211_RADIOTAP_RATE) |
-			   (1 << IEEE80211_RADIOTAP_CHANNEL) |
-			   (1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL) |
-			   (1 << IEEE80211_RADIOTAP_DBM_ANTNOISE) |
-			   (1 << IEEE80211_RADIOTAP_ANTENNA),
-			&iwl3945_rt->rt_hdr.it_present);
-
-	/* Zero the flags, we'll add to them as we go */
-	iwl3945_rt->rt_flags = 0;
-
-	put_unaligned_le64(tsf, &iwl3945_rt->rt_tsf);
-
-	iwl3945_rt->rt_dbmsignal = signal;
-	iwl3945_rt->rt_dbmnoise = noise;
-
-	/* Convert the channel frequency and set the flags */
-	put_unaligned_le16(stats->freq, &iwl3945_rt->rt_channelMHz);
-	if (!(phy_flags_hw & RX_RES_PHY_FLAGS_BAND_24_MSK))
-		put_unaligned_le16(IEEE80211_CHAN_OFDM | IEEE80211_CHAN_5GHZ,
-			      &iwl3945_rt->rt_chbitmask);
-	else if (phy_flags_hw & RX_RES_PHY_FLAGS_MOD_CCK_MSK)
-		put_unaligned_le16(IEEE80211_CHAN_CCK | IEEE80211_CHAN_2GHZ,
-			      &iwl3945_rt->rt_chbitmask);
-	else	/* 802.11g */
-		put_unaligned_le16(IEEE80211_CHAN_OFDM | IEEE80211_CHAN_2GHZ,
-			      &iwl3945_rt->rt_chbitmask);
-
-	if (rate == -1)
-		iwl3945_rt->rt_rate = 0;
-	else {
-		if (stats->band == IEEE80211_BAND_5GHZ)
-			rate += IWL_FIRST_OFDM_RATE;
-
-		iwl3945_rt->rt_rate = iwl3945_rates[rate].ieee;
-	}
-
-	/* antenna number */
-	antenna = phy_flags_hw & RX_RES_PHY_FLAGS_ANTENNA_MSK;
-	iwl3945_rt->rt_antenna = le16_to_cpu(antenna) >> 4;
-
-	/* set the preamble flag if we have it */
-	if (phy_flags_hw & RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK)
-		iwl3945_rt->rt_flags |= IEEE80211_RADIOTAP_F_SHORTPRE;
-
-	stats->flag |= RX_FLAG_RADIOTAP;
-}
-
 static void iwl3945_pass_packet_to_mac80211(struct iwl3945_priv *priv,
 				   struct iwl3945_rx_mem_buffer *rxb,
 				   struct ieee80211_rx_status *stats)
@@ -657,9 +564,6 @@
 		iwl3945_set_decrypted_flag(priv, rxb->skb,
 				       le32_to_cpu(rx_end->status), stats);
 
-	if (priv->add_radiotap)
-		iwl3945_add_radiotap(priv, rxb->skb, rx_hdr, stats);
-
 #ifdef CONFIG_IWL3945_LEDS
 	if (ieee80211_is_data(hdr->frame_control))
 		priv->rxtxpackets += len;
@@ -684,7 +588,6 @@
 	u16 rx_stats_noise_diff = le16_to_cpu(rx_stats->noise_diff);
 	u8 network_packet;
 
-	rx_status.antenna = 0;
 	rx_status.flag = 0;
 	rx_status.mactime = le64_to_cpu(rx_end->timestamp);
 	rx_status.freq =
@@ -696,6 +599,13 @@
 	if (rx_status.band == IEEE80211_BAND_5GHZ)
 		rx_status.rate_idx -= IWL_FIRST_OFDM_RATE;
 
+	rx_status.antenna = le16_to_cpu(rx_hdr->phy_flags &
+					RX_RES_PHY_FLAGS_ANTENNA_MSK) >> 4;
+
+	/* set the preamble flag if appropriate */
+	if (rx_hdr->phy_flags & RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK)
+		rx_status.flag |= RX_FLAG_SHORTPRE;
+
 	if ((unlikely(rx_stats->phy_count > 20))) {
 		IWL_DEBUG_DROP
 		    ("dsp size out of range [0,20]: "
@@ -771,100 +681,7 @@
 		priv->last_rx_noise = rx_status.noise;
 	}
 
-	if (priv->iw_mode == IEEE80211_IF_TYPE_MNTR) {
-		iwl3945_pass_packet_to_mac80211(priv, rxb, &rx_status);
-		return;
-	}
-
-	switch (le16_to_cpu(header->frame_control) & IEEE80211_FCTL_FTYPE) {
-	case IEEE80211_FTYPE_MGMT:
-		switch (le16_to_cpu(header->frame_control) &
-			IEEE80211_FCTL_STYPE) {
-		case IEEE80211_STYPE_PROBE_RESP:
-		case IEEE80211_STYPE_BEACON:{
-				/* If this is a beacon or probe response for
-				 * our network then cache the beacon
-				 * timestamp */
-				if ((((priv->iw_mode == IEEE80211_IF_TYPE_STA)
-				      && !compare_ether_addr(header->addr2,
-							     priv->bssid)) ||
-				     ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS)
-				      && !compare_ether_addr(header->addr3,
-							     priv->bssid)))) {
-					struct ieee80211_mgmt *mgmt =
-					    (struct ieee80211_mgmt *)header;
-					__le32 *pos;
-					pos = (__le32 *)&mgmt->u.beacon.
-					    timestamp;
-					priv->timestamp0 = le32_to_cpu(pos[0]);
-					priv->timestamp1 = le32_to_cpu(pos[1]);
-					priv->beacon_int = le16_to_cpu(
-					    mgmt->u.beacon.beacon_int);
-					if (priv->call_post_assoc_from_beacon &&
-					    (priv->iw_mode ==
-						IEEE80211_IF_TYPE_STA))
-						queue_work(priv->workqueue,
-						    &priv->post_associate.work);
-
-					priv->call_post_assoc_from_beacon = 0;
-				}
-
-				break;
-			}
-
-		case IEEE80211_STYPE_ACTION:
-			/* TODO: Parse 802.11h frames for CSA... */
-			break;
-
-			/*
-			 * TODO: Use the new callback function from
-			 * mac80211 instead of sniffing these packets.
-			 */
-		case IEEE80211_STYPE_ASSOC_RESP:
-		case IEEE80211_STYPE_REASSOC_RESP:{
-				struct ieee80211_mgmt *mgnt =
-				    (struct ieee80211_mgmt *)header;
-
-				/* We have just associated, give some
-				 * time for the 4-way handshake if
-				 * any. Don't start scan too early. */
-				priv->next_scan_jiffies = jiffies +
-					IWL_DELAY_NEXT_SCAN_AFTER_ASSOC;
-
-				priv->assoc_id = (~((1 << 15) | (1 << 14)) &
-						  le16_to_cpu(mgnt->u.
-							      assoc_resp.aid));
-				priv->assoc_capability =
-				    le16_to_cpu(mgnt->u.assoc_resp.capab_info);
-				if (priv->beacon_int)
-					queue_work(priv->workqueue,
-					    &priv->post_associate.work);
-				else
-					priv->call_post_assoc_from_beacon = 1;
-				break;
-			}
-
-		case IEEE80211_STYPE_PROBE_REQ:{
-				DECLARE_MAC_BUF(mac1);
-				DECLARE_MAC_BUF(mac2);
-				DECLARE_MAC_BUF(mac3);
-				if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS)
-					IWL_DEBUG_DROP
-					    ("Dropping (non network): %s"
-					     ", %s, %s\n",
-					     print_mac(mac1, header->addr1),
-					     print_mac(mac2, header->addr2),
-					     print_mac(mac3, header->addr3));
-				return;
-			}
-		}
-
-	case IEEE80211_FTYPE_DATA:
-		/* fall through */
-	default:
-		iwl3945_pass_packet_to_mac80211(priv, rxb, &rx_status);
-		break;
-	}
+	iwl3945_pass_packet_to_mac80211(priv, rxb, &rx_status);
 }
 
 int iwl3945_hw_txq_attach_buf_to_tfd(struct iwl3945_priv *priv, void *ptr,
@@ -990,7 +807,7 @@
 
 	priv->stations[sta_id].current_rate.rate_n_flags = rate;
 
-	if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) &&
+	if ((priv->iw_mode == NL80211_IFTYPE_ADHOC) &&
 	    (sta_id != priv->hw_setting.bcast_sta_id) &&
 		(sta_id != IWL_MULTICAST_ID))
 		priv->stations[IWL_STA_ID].current_rate.rate_n_flags = rate;
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.h b/drivers/net/wireless/iwlwifi/iwl-3945.h
index fa81ba1..bdd3247 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945.h
+++ b/drivers/net/wireless/iwlwifi/iwl-3945.h
@@ -73,6 +73,10 @@
 extern int iwl3945_param_hwcrypto;
 extern int iwl3945_param_queues_num;
 
+struct iwl3945_sta_priv {
+	struct iwl3945_rs_sta *rs_sta;
+};
+
 enum iwl3945_antenna {
 	IWL_ANTENNA_DIVERSITY,
 	IWL_ANTENNA_MAIN,
@@ -707,7 +711,6 @@
 
 	enum ieee80211_band band;
 	int alloc_rxb_skb;
-	bool add_radiotap;
 
 	void (*rx_handlers[REPLY_MAX])(struct iwl3945_priv *priv,
 				       struct iwl3945_rx_mem_buffer *rxb);
@@ -852,7 +855,7 @@
 	/* eeprom */
 	struct iwl3945_eeprom eeprom;
 
-	enum ieee80211_if_types iw_mode;
+	enum nl80211_iftype iw_mode;
 
 	struct sk_buff *ibss_beacon;
 
@@ -895,7 +898,6 @@
 	struct delayed_work thermal_periodic;
 	struct delayed_work gather_stats;
 	struct delayed_work scan_check;
-	struct delayed_work post_associate;
 
 #define IWL_DEFAULT_TX_POWER 0x0F
 	s8 user_txpower_limit;
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-hw.h b/drivers/net/wireless/iwlwifi/iwl-4965-hw.h
index fce950f..f4793a6 100644
--- a/drivers/net/wireless/iwlwifi/iwl-4965-hw.h
+++ b/drivers/net/wireless/iwlwifi/iwl-4965-hw.h
@@ -98,16 +98,17 @@
 #define IWL_RSSI_OFFSET	44
 
 
-#include "iwl-commands.h"
 
 /* PCI registers */
-#define PCI_LINK_CTRL      0x0F0	/* 1 byte */
-#define PCI_POWER_SOURCE   0x0C8
-#define PCI_REG_WUM8       0x0E8
+#define PCI_CFG_RETRY_TIMEOUT	0x041
+#define PCI_CFG_POWER_SOURCE	0x0C8
+#define PCI_REG_WUM8		0x0E8
+#define PCI_CFG_LINK_CTRL	0x0F0
 
 /* PCI register values */
-#define PCI_LINK_VAL_L0S_EN	0x01
-#define PCI_LINK_VAL_L1_EN	0x02
+#define PCI_CFG_LINK_CTRL_VAL_L0S_EN	0x01
+#define PCI_CFG_LINK_CTRL_VAL_L1_EN	0x02
+#define PCI_CFG_CMD_REG_INT_DIS_MSK	0x04
 #define PCI_CFG_PMC_PME_FROM_D3COLD_SUPPORT         (0x80000000)
 
 #define TFD_QUEUE_SIZE_MAX      (256)
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c
index 23fed32..9838de5 100644
--- a/drivers/net/wireless/iwlwifi/iwl-4965.c
+++ b/drivers/net/wireless/iwlwifi/iwl-4965.c
@@ -399,7 +399,7 @@
 	unsigned long flags;
 	u32 val;
 	u16 radio_cfg;
-	u8 val_link;
+	u16 link;
 
 	spin_lock_irqsave(&priv->lock, flags);
 
@@ -410,10 +410,10 @@
 				       val & ~(1 << 11));
 	}
 
-	pci_read_config_byte(priv->pci_dev, PCI_LINK_CTRL, &val_link);
+	pci_read_config_word(priv->pci_dev, PCI_CFG_LINK_CTRL, &link);
 
 	/* L1 is enabled by BIOS */
-	if ((val_link & PCI_LINK_VAL_L1_EN) == PCI_LINK_VAL_L1_EN)
+	if ((link & PCI_CFG_LINK_CTRL_VAL_L1_EN) == PCI_CFG_LINK_CTRL_VAL_L1_EN)
 		/* diable L0S disabled L1A enabled */
 		iwl_set_bit(priv, CSR_GIO_REG, CSR_GIO_REG_VAL_L0S_ENABLED);
 	else
@@ -1607,8 +1607,8 @@
 	return ret;
 }
 
-
-int iwl4965_hw_channel_switch(struct iwl_priv *priv, u16 channel)
+#ifdef IEEE80211_CONF_CHANNEL_SWITCH
+static int iwl4965_hw_channel_switch(struct iwl_priv *priv, u16 channel)
 {
 	int rc;
 	u8 band = 0;
@@ -1648,6 +1648,7 @@
 	rc = iwl_send_cmd_pdu(priv, REPLY_CHANNEL_SWITCH, sizeof(cmd), &cmd);
 	return rc;
 }
+#endif
 
 static int iwl4965_shared_mem_rx_idx(struct iwl_priv *priv)
 {
diff --git a/drivers/net/wireless/iwlwifi/iwl-5000-hw.h b/drivers/net/wireless/iwlwifi/iwl-5000-hw.h
index 17d4f31..c479ee2 100644
--- a/drivers/net/wireless/iwlwifi/iwl-5000-hw.h
+++ b/drivers/net/wireless/iwlwifi/iwl-5000-hw.h
@@ -129,6 +129,13 @@
 	__le32 padding2;
 } __attribute__ ((packed));
 
+/* calibrations defined for 5000 */
+/* defines the order in which results should be sent to the runtime uCode */
+enum iwl5000_calib {
+	IWL5000_CALIB_LO,
+	IWL5000_CALIB_TX_IQ,
+	IWL5000_CALIB_TX_IQ_PERD,
+};
 
 #endif /* __iwl_5000_hw_h__ */
 
diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c
index b08036a..f6003e7 100644
--- a/drivers/net/wireless/iwlwifi/iwl-5000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-5000.c
@@ -209,14 +209,14 @@
 {
 	unsigned long flags;
 	u16 radio_cfg;
-	u8 val_link;
+	u16 link;
 
 	spin_lock_irqsave(&priv->lock, flags);
 
-	pci_read_config_byte(priv->pci_dev, PCI_LINK_CTRL, &val_link);
+	pci_read_config_word(priv->pci_dev, PCI_CFG_LINK_CTRL, &link);
 
 	/* L1 is enabled by BIOS */
-	if ((val_link & PCI_LINK_VAL_L1_EN) == PCI_LINK_VAL_L1_EN)
+	if ((link & PCI_CFG_LINK_CTRL_VAL_L1_EN) == PCI_CFG_LINK_CTRL_VAL_L1_EN)
 		/* diable L0S disabled L1A enabled */
 		iwl_set_bit(priv, CSR_GIO_REG, CSR_GIO_REG_VAL_L0S_ENABLED);
 	else
@@ -445,48 +445,6 @@
 				sizeof(cal_cmd), &cal_cmd);
 }
 
-static int iwl5000_send_calib_results(struct iwl_priv *priv)
-{
-	int ret = 0;
-
-	struct iwl_host_cmd hcmd = {
-		.id = REPLY_PHY_CALIBRATION_CMD,
-		.meta.flags = CMD_SIZE_HUGE,
-	};
-
-	if (priv->calib_results.lo_res) {
-		hcmd.len = priv->calib_results.lo_res_len;
-		hcmd.data = priv->calib_results.lo_res;
-		ret = iwl_send_cmd_sync(priv, &hcmd);
-
-		if (ret)
-			goto err;
-	}
-
-	if (priv->calib_results.tx_iq_res) {
-		hcmd.len = priv->calib_results.tx_iq_res_len;
-		hcmd.data = priv->calib_results.tx_iq_res;
-		ret = iwl_send_cmd_sync(priv, &hcmd);
-
-		if (ret)
-			goto err;
-	}
-
-	if (priv->calib_results.tx_iq_perd_res) {
-		hcmd.len = priv->calib_results.tx_iq_perd_res_len;
-		hcmd.data = priv->calib_results.tx_iq_perd_res;
-		ret = iwl_send_cmd_sync(priv, &hcmd);
-
-		if (ret)
-			goto err;
-	}
-
-	return 0;
-err:
-	IWL_ERROR("Error %d\n", ret);
-	return ret;
-}
-
 static int iwl5000_send_calib_cfg(struct iwl_priv *priv)
 {
 	struct iwl5000_calib_cfg_cmd calib_cfg_cmd;
@@ -511,33 +469,30 @@
 	struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
 	struct iwl5000_calib_hdr *hdr = (struct iwl5000_calib_hdr *)pkt->u.raw;
 	int len = le32_to_cpu(pkt->len) & FH_RSCSR_FRAME_SIZE_MSK;
-
-	iwl_free_calib_results(priv);
+	int index;
 
 	/* reduce the size of the length field itself */
 	len -= 4;
 
+	/* Define the order in which the results will be sent to the runtime
+	 * uCode. iwl_send_calib_results sends them in a row according to their
+	 * index. We sort them here */
 	switch (hdr->op_code) {
 	case IWL5000_PHY_CALIBRATE_LO_CMD:
-		priv->calib_results.lo_res = kzalloc(len, GFP_ATOMIC);
-		priv->calib_results.lo_res_len = len;
-		memcpy(priv->calib_results.lo_res, pkt->u.raw, len);
+		index = IWL5000_CALIB_LO;
 		break;
 	case IWL5000_PHY_CALIBRATE_TX_IQ_CMD:
-		priv->calib_results.tx_iq_res = kzalloc(len, GFP_ATOMIC);
-		priv->calib_results.tx_iq_res_len = len;
-		memcpy(priv->calib_results.tx_iq_res, pkt->u.raw, len);
+		index = IWL5000_CALIB_TX_IQ;
 		break;
 	case IWL5000_PHY_CALIBRATE_TX_IQ_PERD_CMD:
-		priv->calib_results.tx_iq_perd_res = kzalloc(len, GFP_ATOMIC);
-		priv->calib_results.tx_iq_perd_res_len = len;
-		memcpy(priv->calib_results.tx_iq_perd_res, pkt->u.raw, len);
+		index = IWL5000_CALIB_TX_IQ_PERD;
 		break;
 	default:
 		IWL_ERROR("Unknown calibration notification %d\n",
 			  hdr->op_code);
 		return;
 	}
+	iwl_calib_set(&priv->calib_results[index], pkt->u.raw, len);
 }
 
 static void iwl5000_rx_calib_complete(struct iwl_priv *priv,
@@ -832,7 +787,7 @@
 	iwl5000_send_Xtal_calib(priv);
 
 	if (priv->ucode_type == UCODE_RT)
-		iwl5000_send_calib_results(priv);
+		iwl_send_calib_results(priv);
 
 	return 0;
 }
@@ -1614,6 +1569,8 @@
 	.mod_params = &iwl50_mod_params,
 };
 
+MODULE_FIRMWARE("iwlwifi-5000" IWL5000_UCODE_API ".ucode");
+
 module_param_named(disable50, iwl50_mod_params.disable, int, 0444);
 MODULE_PARM_DESC(disable50,
 		  "manually disable the 50XX radio (default 0 [radio on])");
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c
index 90a2b6d..93944de 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c
@@ -35,8 +35,6 @@
 
 #include <linux/workqueue.h>
 
-#include "../net/mac80211/rate.h"
-
 #include "iwl-dev.h"
 #include "iwl-sta.h"
 #include "iwl-core.h"
@@ -163,12 +161,15 @@
 	u32 dbg_fixed_rate;
 #endif
 	struct iwl_priv *drv;
+
+	/* used to be in sta_info */
+	int last_txrate_idx;
 };
 
 static void rs_rate_scale_perform(struct iwl_priv *priv,
-				   struct net_device *dev,
 				   struct ieee80211_hdr *hdr,
-				   struct sta_info *sta);
+				   struct ieee80211_sta *sta,
+				   struct iwl_lq_sta *lq_sta);
 static void rs_fill_link_cmd(const struct iwl_priv *priv,
 			     struct iwl_lq_sta *lq_sta, u32 rate_n_flags);
 
@@ -354,17 +355,11 @@
 
 static void rs_tl_turn_on_agg_for_tid(struct iwl_priv *priv,
 				      struct iwl_lq_sta *lq_data, u8 tid,
-				      struct sta_info *sta)
+				      struct ieee80211_sta *sta)
 {
-	unsigned long state;
 	DECLARE_MAC_BUF(mac);
 
-	spin_lock_bh(&sta->lock);
-	state = sta->ampdu_mlme.tid_state_tx[tid];
-	spin_unlock_bh(&sta->lock);
-
-	if (state == HT_AGG_STATE_IDLE &&
-	    rs_tl_get_load(lq_data, tid) > IWL_AGG_LOAD_THRESHOLD) {
+	if (rs_tl_get_load(lq_data, tid) > IWL_AGG_LOAD_THRESHOLD) {
 		IWL_DEBUG_HT("Starting Tx agg: STA: %s tid: %d\n",
 				print_mac(mac, sta->addr), tid);
 		ieee80211_start_tx_ba_session(priv->hw, sta->addr, tid);
@@ -373,7 +368,7 @@
 
 static void rs_tl_turn_on_agg(struct iwl_priv *priv, u8 tid,
 			      struct iwl_lq_sta *lq_data,
-			      struct sta_info *sta)
+			      struct ieee80211_sta *sta)
 {
 	if ((tid < TID_MAX_LOAD_COUNT))
 		rs_tl_turn_on_agg_for_tid(priv, lq_data, tid, sta);
@@ -436,7 +431,7 @@
 		/* Shift bitmap by one frame (throw away oldest history),
 		 * OR in "1", and increment "success" if this
 		 * frame was successful. */
-		window->data <<= 1;;
+		window->data <<= 1;
 		if (successes > 0) {
 			window->success_counter++;
 			window->data |= 0x1;
@@ -773,7 +768,8 @@
 /*
  * mac80211 sends us Tx status
  */
-static void rs_tx_status(void *priv_rate, struct net_device *dev,
+static void rs_tx_status(void *priv_r, struct ieee80211_supported_band *sband,
+			 struct ieee80211_sta *sta, void *priv_sta,
 			 struct sk_buff *skb)
 {
 	int status;
@@ -781,11 +777,9 @@
 	int rs_index, index = 0;
 	struct iwl_lq_sta *lq_sta;
 	struct iwl_link_quality_cmd *table;
-	struct sta_info *sta;
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
-	struct iwl_priv *priv = (struct iwl_priv *)priv_rate;
-	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-	struct ieee80211_hw *hw = local_to_hw(local);
+	struct iwl_priv *priv = (struct iwl_priv *)priv_r;
+	struct ieee80211_hw *hw = priv->hw;
 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
 	struct iwl_rate_scale_data *window = NULL;
 	struct iwl_rate_scale_data *search_win = NULL;
@@ -811,17 +805,9 @@
 	if (retries > 15)
 		retries = 15;
 
-	rcu_read_lock();
+	lq_sta = (struct iwl_lq_sta *)priv_sta;
 
-	sta = sta_info_get(local, hdr->addr1);
-
-	if (!sta || !sta->rate_ctrl_priv)
-		goto out;
-
-
-	lq_sta = (struct iwl_lq_sta *)sta->rate_ctrl_priv;
-
-	if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) &&
+	if ((priv->iw_mode == NL80211_IFTYPE_ADHOC) &&
 	    !lq_sta->ibss_sta_added)
 		goto out;
 
@@ -965,9 +951,8 @@
 	}
 
 	/* See if there's a better rate or modulation mode to try. */
-	rs_rate_scale_perform(priv, dev, hdr, sta);
+	rs_rate_scale_perform(priv, hdr, sta, lq_sta);
 out:
-	rcu_read_unlock();
 	return;
 }
 
@@ -1128,6 +1113,7 @@
 
 			/* Higher rate not available, use the original */
 			} else {
+				new_rate = rate;
 				break;
 			}
 		}
@@ -1142,7 +1128,7 @@
 static int rs_switch_to_mimo2(struct iwl_priv *priv,
 			     struct iwl_lq_sta *lq_sta,
 			     struct ieee80211_conf *conf,
-			     struct sta_info *sta,
+			     struct ieee80211_sta *sta,
 			     struct iwl_scale_tbl_info *tbl, int index)
 {
 	u16 rate_mask;
@@ -1153,8 +1139,8 @@
 	    !sta->ht_info.ht_supported)
 		return -1;
 
-	if (((sta->ht_info.cap & IEEE80211_HT_CAP_MIMO_PS) >> 2)
-						== IWL_MIMO_PS_STATIC)
+	if (((sta->ht_info.cap & IEEE80211_HT_CAP_SM_PS) >> 2)
+						== WLAN_HT_CAP_SM_PS_STATIC)
 		return -1;
 
 	/* Need both Tx chains/antennas to support MIMO */
@@ -1210,7 +1196,7 @@
 static int rs_switch_to_siso(struct iwl_priv *priv,
 			     struct iwl_lq_sta *lq_sta,
 			     struct ieee80211_conf *conf,
-			     struct sta_info *sta,
+			     struct ieee80211_sta *sta,
 			     struct iwl_scale_tbl_info *tbl, int index)
 {
 	u16 rate_mask;
@@ -1270,7 +1256,7 @@
 static int rs_move_legacy_other(struct iwl_priv *priv,
 				struct iwl_lq_sta *lq_sta,
 				struct ieee80211_conf *conf,
-				struct sta_info *sta,
+				struct ieee80211_sta *sta,
 				int index)
 {
 	struct iwl_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);
@@ -1281,15 +1267,23 @@
 		  (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT));
 	u8 start_action = tbl->action;
 	u8 valid_tx_ant = priv->hw_params.valid_tx_ant;
+	u8 tx_chains_num = priv->hw_params.tx_chains_num;
 	int ret = 0;
 
 	for (; ;) {
 		switch (tbl->action) {
-		case IWL_LEGACY_SWITCH_ANTENNA:
+		case IWL_LEGACY_SWITCH_ANTENNA1:
+		case IWL_LEGACY_SWITCH_ANTENNA2:
 			IWL_DEBUG_RATE("LQ: Legacy toggle Antenna\n");
 
 			lq_sta->action_counter++;
 
+			if ((tbl->action == IWL_LEGACY_SWITCH_ANTENNA1 &&
+							tx_chains_num <= 1) ||
+			    (tbl->action == IWL_LEGACY_SWITCH_ANTENNA2 &&
+							tx_chains_num <= 2))
+				break;
+
 			/* Don't change antenna if success has been great */
 			if (window->success_ratio >= IWL_RS_GOOD_RATIO)
 				break;
@@ -1299,7 +1293,7 @@
 
 			if (rs_toggle_antenna(valid_tx_ant,
 				&search_tbl->current_rate, search_tbl)) {
-				lq_sta->search_better_tbl = 1;
+				rs_set_expected_tpt_table(lq_sta, search_tbl);
 				goto out;
 			}
 			break;
@@ -1312,43 +1306,54 @@
 			ret = rs_switch_to_siso(priv, lq_sta, conf, sta,
 						 search_tbl, index);
 			if (!ret) {
-				lq_sta->search_better_tbl = 1;
 				lq_sta->action_counter = 0;
 				goto out;
 			}
 
 			break;
-		case IWL_LEGACY_SWITCH_MIMO2:
+		case IWL_LEGACY_SWITCH_MIMO2_AB:
+		case IWL_LEGACY_SWITCH_MIMO2_AC:
+		case IWL_LEGACY_SWITCH_MIMO2_BC:
 			IWL_DEBUG_RATE("LQ: Legacy switch to MIMO2\n");
 
 			/* Set up search table to try MIMO */
 			memcpy(search_tbl, tbl, sz);
 			search_tbl->is_SGI = 0;
-			search_tbl->ant_type = ANT_AB;/*FIXME:RS*/
-				/*FIXME:RS:need to check ant validity*/
+
+			if (tbl->action == IWL_LEGACY_SWITCH_MIMO2_AB)
+				search_tbl->ant_type = ANT_AB;
+			else if (tbl->action == IWL_LEGACY_SWITCH_MIMO2_AC)
+				search_tbl->ant_type = ANT_AC;
+			else
+				search_tbl->ant_type = ANT_BC;
+
+			if (!rs_is_valid_ant(valid_tx_ant, search_tbl->ant_type))
+				break;
+
 			ret = rs_switch_to_mimo2(priv, lq_sta, conf, sta,
 						 search_tbl, index);
 			if (!ret) {
-				lq_sta->search_better_tbl = 1;
 				lq_sta->action_counter = 0;
 				goto out;
 			}
 			break;
 		}
 		tbl->action++;
-		if (tbl->action > IWL_LEGACY_SWITCH_MIMO2)
-			tbl->action = IWL_LEGACY_SWITCH_ANTENNA;
+		if (tbl->action > IWL_LEGACY_SWITCH_MIMO2_BC)
+			tbl->action = IWL_LEGACY_SWITCH_ANTENNA1;
 
 		if (tbl->action == start_action)
 			break;
 
 	}
+	search_tbl->lq_type = LQ_NONE;
 	return 0;
 
- out:
+out:
+	lq_sta->search_better_tbl = 1;
 	tbl->action++;
-	if (tbl->action > IWL_LEGACY_SWITCH_MIMO2)
-		tbl->action = IWL_LEGACY_SWITCH_ANTENNA;
+	if (tbl->action > IWL_LEGACY_SWITCH_MIMO2_BC)
+		tbl->action = IWL_LEGACY_SWITCH_ANTENNA1;
 	return 0;
 
 }
@@ -1359,7 +1364,7 @@
 static int rs_move_siso_to_other(struct iwl_priv *priv,
 				 struct iwl_lq_sta *lq_sta,
 				 struct ieee80211_conf *conf,
-				 struct sta_info *sta, int index)
+				 struct ieee80211_sta *sta, int index)
 {
 	u8 is_green = lq_sta->is_green;
 	struct iwl_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);
@@ -1370,34 +1375,51 @@
 		  (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT));
 	u8 start_action = tbl->action;
 	u8 valid_tx_ant = priv->hw_params.valid_tx_ant;
+	u8 tx_chains_num = priv->hw_params.tx_chains_num;
 	int ret;
 
 	for (;;) {
 		lq_sta->action_counter++;
 		switch (tbl->action) {
-		case IWL_SISO_SWITCH_ANTENNA:
+		case IWL_SISO_SWITCH_ANTENNA1:
+		case IWL_SISO_SWITCH_ANTENNA2:
 			IWL_DEBUG_RATE("LQ: SISO toggle Antenna\n");
+
+			if ((tbl->action == IWL_SISO_SWITCH_ANTENNA1 &&
+							tx_chains_num <= 1) ||
+			    (tbl->action == IWL_SISO_SWITCH_ANTENNA2 &&
+							tx_chains_num <= 2))
+				break;
+
 			if (window->success_ratio >= IWL_RS_GOOD_RATIO)
 				break;
 
 			memcpy(search_tbl, tbl, sz);
 			if (rs_toggle_antenna(valid_tx_ant,
-				       &search_tbl->current_rate, search_tbl)) {
-				lq_sta->search_better_tbl = 1;
+				       &search_tbl->current_rate, search_tbl))
 				goto out;
-			}
 			break;
-		case IWL_SISO_SWITCH_MIMO2:
+		case IWL_SISO_SWITCH_MIMO2_AB:
+		case IWL_SISO_SWITCH_MIMO2_AC:
+		case IWL_SISO_SWITCH_MIMO2_BC:
 			IWL_DEBUG_RATE("LQ: SISO switch to MIMO2\n");
 			memcpy(search_tbl, tbl, sz);
 			search_tbl->is_SGI = 0;
-			search_tbl->ant_type = ANT_AB; /*FIXME:RS*/
+
+			if (tbl->action == IWL_SISO_SWITCH_MIMO2_AB)
+				search_tbl->ant_type = ANT_AB;
+			else if (tbl->action == IWL_SISO_SWITCH_MIMO2_AC)
+				search_tbl->ant_type = ANT_AC;
+			else
+				search_tbl->ant_type = ANT_BC;
+
+			if (!rs_is_valid_ant(valid_tx_ant, search_tbl->ant_type))
+				break;
+
 			ret = rs_switch_to_mimo2(priv, lq_sta, conf, sta,
 						 search_tbl, index);
-			if (!ret) {
-				lq_sta->search_better_tbl = 1;
+			if (!ret)
 				goto out;
-			}
 			break;
 		case IWL_SISO_SWITCH_GI:
 			if (!tbl->is_fat &&
@@ -1427,22 +1449,23 @@
 			}
 			search_tbl->current_rate = rate_n_flags_from_tbl(
 						search_tbl, index, is_green);
-			lq_sta->search_better_tbl = 1;
 			goto out;
 		}
 		tbl->action++;
 		if (tbl->action > IWL_SISO_SWITCH_GI)
-			tbl->action = IWL_SISO_SWITCH_ANTENNA;
+			tbl->action = IWL_SISO_SWITCH_ANTENNA1;
 
 		if (tbl->action == start_action)
 			break;
 	}
+	search_tbl->lq_type = LQ_NONE;
 	return 0;
 
  out:
+	lq_sta->search_better_tbl = 1;
 	tbl->action++;
 	if (tbl->action > IWL_SISO_SWITCH_GI)
-		tbl->action = IWL_SISO_SWITCH_ANTENNA;
+		tbl->action = IWL_SISO_SWITCH_ANTENNA1;
 	return 0;
 }
 
@@ -1452,43 +1475,64 @@
 static int rs_move_mimo_to_other(struct iwl_priv *priv,
 				 struct iwl_lq_sta *lq_sta,
 				 struct ieee80211_conf *conf,
-				 struct sta_info *sta, int index)
+				 struct ieee80211_sta *sta, int index)
 {
 	s8 is_green = lq_sta->is_green;
 	struct iwl_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);
 	struct iwl_scale_tbl_info *search_tbl =
 				&(lq_sta->lq_info[(1 - lq_sta->active_tbl)]);
+	struct iwl_rate_scale_data *window = &(tbl->win[index]);
 	u32 sz = (sizeof(struct iwl_scale_tbl_info) -
 		  (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT));
 	u8 start_action = tbl->action;
-	/*u8 valid_tx_ant = priv->hw_params.valid_tx_ant;*/
+	u8 valid_tx_ant = priv->hw_params.valid_tx_ant;
+	u8 tx_chains_num = priv->hw_params.tx_chains_num;
 	int ret;
 
 	for (;;) {
 		lq_sta->action_counter++;
 		switch (tbl->action) {
-		case IWL_MIMO_SWITCH_ANTENNA_A:
-		case IWL_MIMO_SWITCH_ANTENNA_B:
+		case IWL_MIMO2_SWITCH_ANTENNA1:
+		case IWL_MIMO2_SWITCH_ANTENNA2:
+			IWL_DEBUG_RATE("LQ: MIMO toggle Antennas\n");
+
+			if (tx_chains_num <= 2)
+				break;
+
+			if (window->success_ratio >= IWL_RS_GOOD_RATIO)
+				break;
+
+			memcpy(search_tbl, tbl, sz);
+			if (rs_toggle_antenna(valid_tx_ant,
+				       &search_tbl->current_rate, search_tbl))
+				goto out;
+			break;
+		case IWL_MIMO2_SWITCH_SISO_A:
+		case IWL_MIMO2_SWITCH_SISO_B:
+		case IWL_MIMO2_SWITCH_SISO_C:
 			IWL_DEBUG_RATE("LQ: MIMO2 switch to SISO\n");
 
 			/* Set up new search table for SISO */
 			memcpy(search_tbl, tbl, sz);
 
-			/*FIXME:RS:need to check ant validity + C*/
-			if (tbl->action == IWL_MIMO_SWITCH_ANTENNA_A)
+			if (tbl->action == IWL_MIMO2_SWITCH_SISO_A)
 				search_tbl->ant_type = ANT_A;
-			else
+			else if (tbl->action == IWL_MIMO2_SWITCH_SISO_B)
 				search_tbl->ant_type = ANT_B;
+			else
+				search_tbl->ant_type = ANT_C;
+
+			if (!rs_is_valid_ant(valid_tx_ant, search_tbl->ant_type))
+				break;
 
 			ret = rs_switch_to_siso(priv, lq_sta, conf, sta,
 						 search_tbl, index);
-			if (!ret) {
-				lq_sta->search_better_tbl = 1;
+			if (!ret)
 				goto out;
-			}
+
 			break;
 
-		case IWL_MIMO_SWITCH_GI:
+		case IWL_MIMO2_SWITCH_GI:
 			if (!tbl->is_fat &&
 				!(priv->current_ht_config.sgf &
 						HT_SHORT_GI_20MHZ))
@@ -1517,23 +1561,23 @@
 			}
 			search_tbl->current_rate = rate_n_flags_from_tbl(
 						search_tbl, index, is_green);
-			lq_sta->search_better_tbl = 1;
 			goto out;
 
 		}
 		tbl->action++;
-		if (tbl->action > IWL_MIMO_SWITCH_GI)
-			tbl->action = IWL_MIMO_SWITCH_ANTENNA_A;
+		if (tbl->action > IWL_MIMO2_SWITCH_GI)
+			tbl->action = IWL_MIMO2_SWITCH_ANTENNA1;
 
 		if (tbl->action == start_action)
 			break;
 	}
-
+	search_tbl->lq_type = LQ_NONE;
 	return 0;
  out:
+	lq_sta->search_better_tbl = 1;
 	tbl->action++;
-	if (tbl->action > IWL_MIMO_SWITCH_GI)
-		tbl->action = IWL_MIMO_SWITCH_ANTENNA_A;
+	if (tbl->action > IWL_MIMO2_SWITCH_GI)
+		tbl->action = IWL_MIMO2_SWITCH_ANTENNA1;
 	return 0;
 
 }
@@ -1624,12 +1668,11 @@
  * Do rate scaling and search for new modulation mode.
  */
 static void rs_rate_scale_perform(struct iwl_priv *priv,
-				  struct net_device *dev,
 				  struct ieee80211_hdr *hdr,
-				  struct sta_info *sta)
+				  struct ieee80211_sta *sta,
+				  struct iwl_lq_sta *lq_sta)
 {
-	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-	struct ieee80211_hw *hw = local_to_hw(local);
+	struct ieee80211_hw *hw = priv->hw;
 	struct ieee80211_conf *conf = &hw->conf;
 	int low = IWL_RATE_INVALID;
 	int high = IWL_RATE_INVALID;
@@ -1644,7 +1687,6 @@
 	__le16 fc;
 	u16 rate_mask;
 	u8 update_lq = 0;
-	struct iwl_lq_sta *lq_sta;
 	struct iwl_scale_tbl_info *tbl, *tbl1;
 	u16 rate_scale_index_msk = 0;
 	u32 rate;
@@ -1665,10 +1707,10 @@
 		return;
 	}
 
-	if (!sta || !sta->rate_ctrl_priv)
+	if (!sta || !lq_sta)
 		return;
 
-	lq_sta = (struct iwl_lq_sta *)sta->rate_ctrl_priv;
+	lq_sta->supp_rates = sta->supp_rates[lq_sta->band];
 
 	tid = rs_tl_add_packet(lq_sta, hdr);
 
@@ -1686,7 +1728,7 @@
 	is_green = lq_sta->is_green;
 
 	/* current tx rate */
-	index = sta->last_txrate_idx;
+	index = lq_sta->last_txrate_idx;
 
 	IWL_DEBUG_RATE("Rate scale index %d for type %d\n", index,
 		       tbl->lq_type);
@@ -1747,19 +1789,13 @@
 		rs_stay_in_table(lq_sta);
 
 		goto out;
+	}
 
 	/* Else we have enough samples; calculate estimate of
 	 * actual average throughput */
-	} else {
-		/*FIXME:RS remove this else if we don't get this error*/
-		if (window->average_tpt != ((window->success_ratio *
-				tbl->expected_tpt[index] + 64) / 128)) {
-			IWL_ERROR("expected_tpt should have been calculated"
-								" by now\n");
-			window->average_tpt = ((window->success_ratio *
-					tbl->expected_tpt[index] + 64) / 128);
-		}
-	}
+
+	BUG_ON(window->average_tpt != ((window->success_ratio *
+			tbl->expected_tpt[index] + 64) / 128));
 
 	/* If we are searching for better modulation mode, check success. */
 	if (lq_sta->search_better_tbl) {
@@ -1769,7 +1805,7 @@
 		 * continuing to use the setup that we've been trying. */
 		if (window->average_tpt > lq_sta->last_tpt) {
 
-			IWL_DEBUG_RATE("LQ: SWITCHING TO CURRENT TABLE "
+			IWL_DEBUG_RATE("LQ: SWITCHING TO NEW TABLE "
 					"suc=%d cur-tpt=%d old-tpt=%d\n",
 					window->success_ratio,
 					window->average_tpt,
@@ -2005,15 +2041,7 @@
 out:
 	tbl->current_rate = rate_n_flags_from_tbl(tbl, index, is_green);
 	i = index;
-	sta->last_txrate_idx = i;
-
-	/* sta->txrate_idx is an index to A mode rates which start
-	 * at IWL_FIRST_OFDM_RATE
-	 */
-	if (lq_sta->band == IEEE80211_BAND_5GHZ)
-		sta->txrate_idx = i - IWL_FIRST_OFDM_RATE;
-	else
-		sta->txrate_idx = i;
+	lq_sta->last_txrate_idx = i;
 
 	return;
 }
@@ -2021,9 +2049,9 @@
 
 static void rs_initialize_lq(struct iwl_priv *priv,
 			     struct ieee80211_conf *conf,
-			     struct sta_info *sta)
+			     struct ieee80211_sta *sta,
+			     struct iwl_lq_sta *lq_sta)
 {
-	struct iwl_lq_sta *lq_sta;
 	struct iwl_scale_tbl_info *tbl;
 	int rate_idx;
 	int i;
@@ -2032,14 +2060,13 @@
 	u8 active_tbl = 0;
 	u8 valid_tx_ant;
 
-	if (!sta || !sta->rate_ctrl_priv)
+	if (!sta || !lq_sta)
 		goto out;
 
-	lq_sta = (struct iwl_lq_sta *)sta->rate_ctrl_priv;
-	i = sta->last_txrate_idx;
+	i = lq_sta->last_txrate_idx;
 
 	if ((lq_sta->lq.sta_id == 0xff) &&
-	    (priv->iw_mode == IEEE80211_IF_TYPE_IBSS))
+	    (priv->iw_mode == NL80211_IFTYPE_ADHOC))
 		goto out;
 
 	valid_tx_ant = priv->hw_params.valid_tx_ant;
@@ -2076,40 +2103,33 @@
 	return;
 }
 
-static void rs_get_rate(void *priv_rate, struct net_device *dev,
-			struct ieee80211_supported_band *sband,
-			struct sk_buff *skb,
-			struct rate_selection *sel)
+static void rs_get_rate(void *priv_r, struct ieee80211_supported_band *sband,
+			struct ieee80211_sta *sta, void *priv_sta,
+			struct sk_buff *skb, struct rate_selection *sel)
 {
 
 	int i;
-	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-	struct ieee80211_conf *conf = &local->hw.conf;
+	struct iwl_priv *priv = (struct iwl_priv *)priv_r;
+	struct ieee80211_conf *conf = &priv->hw->conf;
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
-	struct sta_info *sta;
 	__le16 fc;
-	struct iwl_priv *priv = (struct iwl_priv *)priv_rate;
 	struct iwl_lq_sta *lq_sta;
 
 	IWL_DEBUG_RATE_LIMIT("rate scale calculate new rate for skb\n");
 
-	rcu_read_lock();
-
-	sta = sta_info_get(local, hdr->addr1);
-
 	/* Send management frames and broadcast/multicast data using lowest
 	 * rate. */
 	fc = hdr->frame_control;
 	if (!ieee80211_is_data(fc) || is_multicast_ether_addr(hdr->addr1) ||
-	    !sta || !sta->rate_ctrl_priv) {
-		sel->rate_idx = rate_lowest_index(local, sband, sta);
-		goto out;
+	    !sta || !priv_sta) {
+		sel->rate_idx = rate_lowest_index(sband, sta);
+		return;
 	}
 
-	lq_sta = (struct iwl_lq_sta *)sta->rate_ctrl_priv;
-	i = sta->last_txrate_idx;
+	lq_sta = (struct iwl_lq_sta *)priv_sta;
+	i = lq_sta->last_txrate_idx;
 
-	if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) &&
+	if ((priv->iw_mode == NL80211_IFTYPE_ADHOC) &&
 	    !lq_sta->ibss_sta_added) {
 		u8 sta_id = iwl_find_station(priv, hdr->addr1);
 		DECLARE_MAC_BUF(mac);
@@ -2124,23 +2144,22 @@
 			lq_sta->lq.sta_id = sta_id;
 			lq_sta->lq.rs_table[0].rate_n_flags = 0;
 			lq_sta->ibss_sta_added = 1;
-			rs_initialize_lq(priv, conf, sta);
+			rs_initialize_lq(priv, conf, sta, lq_sta);
 		}
 	}
 
 	if ((i < 0) || (i > IWL_RATE_COUNT)) {
-		sel->rate_idx = rate_lowest_index(local, sband, sta);
-		goto out;
+		sel->rate_idx = rate_lowest_index(sband, sta);
+		return;
 	}
 
 	if (sband->band == IEEE80211_BAND_5GHZ)
 		i -= IWL_FIRST_OFDM_RATE;
 	sel->rate_idx = i;
-out:
-	rcu_read_unlock();
 }
 
-static void *rs_alloc_sta(void *priv_rate, gfp_t gfp)
+static void *rs_alloc_sta(void *priv_rate, struct ieee80211_sta *sta,
+			  gfp_t gfp)
 {
 	struct iwl_lq_sta *lq_sta;
 	struct iwl_priv *priv;
@@ -2163,33 +2182,28 @@
 	return lq_sta;
 }
 
-static void rs_rate_init(void *priv_rate, void *priv_sta,
-			 struct ieee80211_local *local,
-			 struct sta_info *sta)
+static void rs_rate_init(void *priv_r, struct ieee80211_supported_band *sband,
+			 struct ieee80211_sta *sta, void *priv_sta)
 {
 	int i, j;
-	struct ieee80211_conf *conf = &local->hw.conf;
-	struct ieee80211_supported_band *sband;
-	struct iwl_priv *priv = (struct iwl_priv *)priv_rate;
+	struct iwl_priv *priv = (struct iwl_priv *)priv_r;
+	struct ieee80211_conf *conf = &priv->hw->conf;
 	struct iwl_lq_sta *lq_sta = priv_sta;
 
-	sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
-
 	lq_sta->flush_timer = 0;
 	lq_sta->supp_rates = sta->supp_rates[sband->band];
-	sta->txrate_idx = 3;
 	for (j = 0; j < LQ_SIZE; j++)
 		for (i = 0; i < IWL_RATE_COUNT; i++)
 			rs_rate_scale_clear_window(&lq_sta->lq_info[j].win[i]);
 
-	IWL_DEBUG_RATE("LQ: *** rate scale global init ***\n");
+	IWL_DEBUG_RATE("LQ: *** rate scale station global init ***\n");
 	/* TODO: what is a good starting rate for STA? About middle? Maybe not
 	 * the lowest or the highest rate.. Could consider using RSSI from
 	 * previous packets? Need to have IEEE 802.1X auth succeed immediately
 	 * after assoc.. */
 
 	lq_sta->ibss_sta_added = 0;
-	if (priv->iw_mode == IEEE80211_IF_TYPE_AP) {
+	if (priv->iw_mode == NL80211_IFTYPE_AP) {
 		u8 sta_id = iwl_find_station(priv, sta->addr);
 		DECLARE_MAC_BUF(mac);
 
@@ -2212,15 +2226,14 @@
 	}
 
 	/* Find highest tx rate supported by hardware and destination station */
+	lq_sta->last_txrate_idx = 3;
 	for (i = 0; i < sband->n_bitrates; i++)
 		if (sta->supp_rates[sband->band] & BIT(i))
-			sta->txrate_idx = i;
+			lq_sta->last_txrate_idx = i;
 
-	sta->last_txrate_idx = sta->txrate_idx;
-	/* WTF is with this bogus comment? A doesn't have cck rates */
-	/* For MODE_IEEE80211A, cck rates are at end of rate table */
-	if (local->hw.conf.channel->band == IEEE80211_BAND_5GHZ)
-		sta->last_txrate_idx += IWL_FIRST_OFDM_RATE;
+	/* For MODE_IEEE80211A, skip over cck rates in global rate table */
+	if (sband->band == IEEE80211_BAND_5GHZ)
+		lq_sta->last_txrate_idx += IWL_FIRST_OFDM_RATE;
 
 	lq_sta->is_dup = 0;
 	lq_sta->is_green = rs_use_green(priv, conf);
@@ -2260,7 +2273,7 @@
 	lq_sta->tx_agg_tid_en = IWL_AGG_ALL_TID;
 	lq_sta->drv = priv;
 
-	rs_initialize_lq(priv, conf, sta);
+	rs_initialize_lq(priv, conf, sta, lq_sta);
 }
 
 static void rs_fill_link_cmd(const struct iwl_priv *priv,
@@ -2382,9 +2395,9 @@
 	lq_cmd->agg_params.agg_time_limit = cpu_to_le16(4000);
 }
 
-static void *rs_alloc(struct ieee80211_local *local)
+static void *rs_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir)
 {
-	return local->hw.priv;
+	return hw->priv;
 }
 /* rate scale requires free function to be implemented */
 static void rs_free(void *priv_rate)
@@ -2405,12 +2418,12 @@
 #endif /* CONFIG_IWLWIFI_DEBUG */
 }
 
-static void rs_free_sta(void *priv_rate, void *priv_sta)
+static void rs_free_sta(void *priv_r, struct ieee80211_sta *sta,
+			void *priv_sta)
 {
 	struct iwl_lq_sta *lq_sta = priv_sta;
-	struct iwl_priv *priv;
+	struct iwl_priv *priv = priv_r;
 
-	priv = (struct iwl_priv *)priv_rate;
 	IWL_DEBUG_RATE("enter\n");
 	kfree(lq_sta);
 	IWL_DEBUG_RATE("leave\n");
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.h b/drivers/net/wireless/iwlwifi/iwl-agn-rs.h
index 84d4d1e..d148d73 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.h
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.h
@@ -206,21 +206,28 @@
 #define IWL_RATE_DECREASE_TH		1920	/*  15% */
 
 /* possible actions when in legacy mode */
-#define IWL_LEGACY_SWITCH_ANTENNA	0
-#define IWL_LEGACY_SWITCH_SISO		1
-#define IWL_LEGACY_SWITCH_MIMO2		2
+#define IWL_LEGACY_SWITCH_ANTENNA1      0
+#define IWL_LEGACY_SWITCH_ANTENNA2      1
+#define IWL_LEGACY_SWITCH_SISO          2
+#define IWL_LEGACY_SWITCH_MIMO2_AB      3
+#define IWL_LEGACY_SWITCH_MIMO2_AC      4
+#define IWL_LEGACY_SWITCH_MIMO2_BC      5
 
 /* possible actions when in siso mode */
-#define IWL_SISO_SWITCH_ANTENNA		0
-#define IWL_SISO_SWITCH_MIMO2		1
-#define IWL_SISO_SWITCH_GI		2
+#define IWL_SISO_SWITCH_ANTENNA1        0
+#define IWL_SISO_SWITCH_ANTENNA2        1
+#define IWL_SISO_SWITCH_MIMO2_AB        2
+#define IWL_SISO_SWITCH_MIMO2_AC        3
+#define IWL_SISO_SWITCH_MIMO2_BC        4
+#define IWL_SISO_SWITCH_GI              5
 
 /* possible actions when in mimo mode */
-#define IWL_MIMO_SWITCH_ANTENNA_A	0
-#define IWL_MIMO_SWITCH_ANTENNA_B	1
-#define IWL_MIMO_SWITCH_GI		2
-
-/*FIXME:RS:separate MIMO2/3 transitions*/
+#define IWL_MIMO2_SWITCH_ANTENNA1       0
+#define IWL_MIMO2_SWITCH_ANTENNA2       1
+#define IWL_MIMO2_SWITCH_SISO_A         2
+#define IWL_MIMO2_SWITCH_SISO_B         3
+#define IWL_MIMO2_SWITCH_SISO_C         4
+#define IWL_MIMO2_SWITCH_GI             5
 
 /*FIXME:RS:add posible acctions for MIMO3*/
 
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c
index e01f048..24a1aeb 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.c
@@ -337,7 +337,7 @@
 	/* If we have set the ASSOC_MSK and we are in BSS mode then
 	 * add the IWL_AP_ID to the station rate table */
 	if (new_assoc) {
-		if (priv->iw_mode == IEEE80211_IF_TYPE_STA) {
+		if (priv->iw_mode == NL80211_IFTYPE_STATION) {
 			ret = iwl_rxon_add_station(priv,
 					   priv->active_rxon.bssid_addr, 1);
 			if (ret == IWL_INVALID_STATION) {
@@ -448,8 +448,8 @@
 					  const u8 *dest, int left)
 {
 	if (!iwl_is_associated(priv) || !priv->ibss_beacon ||
-	    ((priv->iw_mode != IEEE80211_IF_TYPE_IBSS) &&
-	     (priv->iw_mode != IEEE80211_IF_TYPE_AP)))
+	    ((priv->iw_mode != NL80211_IFTYPE_ADHOC) &&
+	     (priv->iw_mode != NL80211_IFTYPE_AP)))
 		return 0;
 
 	if (priv->ibss_beacon->len > left)
@@ -485,7 +485,7 @@
 		return IWL_RATE_6M_PLCP;
 }
 
-unsigned int iwl4965_hw_get_beacon_cmd(struct iwl_priv *priv,
+static unsigned int iwl4965_hw_get_beacon_cmd(struct iwl_priv *priv,
 				       struct iwl_frame *frame, u8 rate)
 {
 	struct iwl_tx_beacon_cmd *tx_beacon_cmd;
@@ -564,8 +564,6 @@
 	if (!iwl_conf->is_ht)
 		return;
 
-	priv->ps_mode = (u8)((ht_conf->cap & IEEE80211_HT_CAP_MIMO_PS) >> 2);
-
 	if (ht_conf->cap & IEEE80211_HT_CAP_SGI_20)
 		iwl_conf->sgf |= HT_SHORT_GI_20MHZ;
 	if (ht_conf->cap & IEEE80211_HT_CAP_SGI_40)
@@ -586,6 +584,8 @@
 		iwl_conf->supported_chan_width = 0;
 	}
 
+	iwl_conf->sm_ps = (u8)((ht_conf->cap & IEEE80211_HT_CAP_SM_PS) >> 2);
+
 	memcpy(iwl_conf->supp_mcs_set, ht_conf->supp_mcs_set, 16);
 
 	iwl_conf->control_channel = ht_bss_conf->primary_channel;
@@ -672,7 +672,7 @@
 	beacon_int = priv->beacon_int;
 	spin_unlock_irqrestore(&priv->lock, flags);
 
-	if (priv->iw_mode == IEEE80211_IF_TYPE_STA) {
+	if (priv->iw_mode == NL80211_IFTYPE_STATION) {
 		if (beacon_int == 0) {
 			priv->rxon_timing.beacon_interval = cpu_to_le16(100);
 			priv->rxon_timing.beacon_init_val = cpu_to_le32(102400);
@@ -721,7 +721,7 @@
 		else
 			priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK;
 
-		if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS)
+		if (priv->iw_mode == NL80211_IFTYPE_ADHOC)
 			priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK;
 
 		priv->staging_rxon.flags |= RXON_FLG_BAND_24G_MSK;
@@ -740,23 +740,23 @@
 	memset(&priv->staging_rxon, 0, sizeof(priv->staging_rxon));
 
 	switch (priv->iw_mode) {
-	case IEEE80211_IF_TYPE_AP:
+	case NL80211_IFTYPE_AP:
 		priv->staging_rxon.dev_type = RXON_DEV_TYPE_AP;
 		break;
 
-	case IEEE80211_IF_TYPE_STA:
+	case NL80211_IFTYPE_STATION:
 		priv->staging_rxon.dev_type = RXON_DEV_TYPE_ESS;
 		priv->staging_rxon.filter_flags = RXON_FILTER_ACCEPT_GRP_MSK;
 		break;
 
-	case IEEE80211_IF_TYPE_IBSS:
+	case NL80211_IFTYPE_ADHOC:
 		priv->staging_rxon.dev_type = RXON_DEV_TYPE_IBSS;
 		priv->staging_rxon.flags = RXON_FLG_SHORT_PREAMBLE_MSK;
 		priv->staging_rxon.filter_flags = RXON_FILTER_BCON_AWARE_MSK |
 						  RXON_FILTER_ACCEPT_GRP_MSK;
 		break;
 
-	case IEEE80211_IF_TYPE_MNTR:
+	case NL80211_IFTYPE_MONITOR:
 		priv->staging_rxon.dev_type = RXON_DEV_TYPE_SNIFFER;
 		priv->staging_rxon.filter_flags = RXON_FILTER_PROMISC_MSK |
 		    RXON_FILTER_CTL2HOST_MSK | RXON_FILTER_ACCEPT_GRP_MSK;
@@ -785,7 +785,7 @@
 	 * in some case A channels are all non IBSS
 	 * in this case force B/G channel
 	 */
-	if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) &&
+	if ((priv->iw_mode == NL80211_IFTYPE_ADHOC) &&
 	    !(is_channel_ibss(ch_info)))
 		ch_info = &priv->channel_info[0];
 
@@ -1182,7 +1182,7 @@
 		le32_to_cpu(beacon->low_tsf), rate);
 #endif
 
-	if ((priv->iw_mode == IEEE80211_IF_TYPE_AP) &&
+	if ((priv->iw_mode == NL80211_IFTYPE_AP) &&
 	    (!test_bit(STATUS_EXIT_PENDING, &priv->status)))
 		queue_work(priv->workqueue, &priv->beacon_update);
 }
@@ -1270,7 +1270,7 @@
 
 	if (src == IWL_PWR_SRC_VAUX) {
 		u32 val;
-		ret = pci_read_config_dword(priv->pci_dev, PCI_POWER_SOURCE,
+		ret = pci_read_config_dword(priv->pci_dev, PCI_CFG_POWER_SOURCE,
 					    &val);
 
 		if (val & PCI_CFG_PMC_PME_FROM_D3COLD_SUPPORT)
@@ -2388,7 +2388,7 @@
 
 	mutex_lock(&priv->mutex);
 
-	ret = iwl4965_set_mode(priv, IEEE80211_IF_TYPE_MNTR);
+	ret = iwl4965_set_mode(priv, NL80211_IFTYPE_MONITOR);
 
 	if (ret) {
 		if (ret == -EAGAIN)
@@ -2469,7 +2469,7 @@
 	DECLARE_MAC_BUF(mac);
 	unsigned long flags;
 
-	if (priv->iw_mode == IEEE80211_IF_TYPE_AP) {
+	if (priv->iw_mode == NL80211_IFTYPE_AP) {
 		IWL_ERROR("%s Should not be called in AP mode\n", __func__);
 		return;
 	}
@@ -2486,6 +2486,7 @@
 	if (!priv->vif || !priv->is_open)
 		return;
 
+	iwl_power_cancel_timeout(priv);
 	iwl_scan_cancel_timeout(priv, 200);
 
 	conf = ieee80211_get_hw_conf(priv->hw);
@@ -2503,8 +2504,7 @@
 
 	priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK;
 
-	if (priv->current_ht_config.is_ht)
-		iwl_set_rxon_ht(priv, &priv->current_ht_config);
+	iwl_set_rxon_ht(priv, &priv->current_ht_config);
 
 	iwl_set_rxon_chain(priv);
 	priv->staging_rxon.assoc_id = cpu_to_le16(priv->assoc_id);
@@ -2523,7 +2523,7 @@
 		else
 			priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK;
 
-		if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS)
+		if (priv->iw_mode == NL80211_IFTYPE_ADHOC)
 			priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK;
 
 	}
@@ -2531,10 +2531,10 @@
 	iwl4965_commit_rxon(priv);
 
 	switch (priv->iw_mode) {
-	case IEEE80211_IF_TYPE_STA:
+	case NL80211_IFTYPE_STATION:
 		break;
 
-	case IEEE80211_IF_TYPE_IBSS:
+	case NL80211_IFTYPE_ADHOC:
 
 		/* assume default assoc id */
 		priv->assoc_id = 1;
@@ -2550,44 +2550,23 @@
 		break;
 	}
 
-	/* Enable Rx differential gain and sensitivity calibrations */
-	iwl_chain_noise_reset(priv);
-	priv->start_calib = 1;
-
-	if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS)
+	if (priv->iw_mode == NL80211_IFTYPE_ADHOC)
 		priv->assoc_station_added = 1;
 
 	spin_lock_irqsave(&priv->lock, flags);
 	iwl_activate_qos(priv, 0);
 	spin_unlock_irqrestore(&priv->lock, flags);
 
-	iwl_power_update_mode(priv, 0);
-	/* we have just associated, don't start scan too early */
-	priv->next_scan_jiffies = jiffies + IWL_DELAY_NEXT_SCAN;
-}
+	/* the chain noise calibration will enabled PM upon completion
+	 * If chain noise has already been run, then we need to enable
+	 * power management here */
+	if (priv->chain_noise_data.state == IWL_CHAIN_NOISE_DONE)
+		iwl_power_enable_management(priv);
 
-static int iwl4965_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf);
+	/* Enable Rx differential gain and sensitivity calibrations */
+	iwl_chain_noise_reset(priv);
+	priv->start_calib = 1;
 
-static void iwl_bg_scan_completed(struct work_struct *work)
-{
-	struct iwl_priv *priv =
-	    container_of(work, struct iwl_priv, scan_completed);
-
-	IWL_DEBUG_SCAN("SCAN complete scan\n");
-
-	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
-		return;
-
-	if (test_bit(STATUS_CONF_PENDING, &priv->status))
-		iwl4965_mac_config(priv->hw, ieee80211_get_hw_conf(priv->hw));
-
-	ieee80211_scan_completed(priv->hw);
-
-	/* Since setting the TXPOWER may have been deferred while
-	 * performing the scan, fire one off */
-	mutex_lock(&priv->mutex);
-	iwl_set_tx_power(priv, priv->tx_power_user_lmt, true);
-	mutex_unlock(&priv->mutex);
 }
 
 /*****************************************************************************
@@ -2728,12 +2707,6 @@
 
 	IWL_DEBUG_MACDUMP("enter\n");
 
-	if (priv->iw_mode == IEEE80211_IF_TYPE_MNTR) {
-		IWL_DEBUG_MAC80211("leave - monitor\n");
-		dev_kfree_skb_any(skb);
-		return 0;
-	}
-
 	IWL_DEBUG_TX("dev->xmit(%d bytes) at rate 0x%02x\n", skb->len,
 		     ieee80211_get_tx_rate(hw, IEEE80211_SKB_CB(skb))->bitrate);
 
@@ -2798,8 +2771,6 @@
 	mutex_lock(&priv->mutex);
 	IWL_DEBUG_MAC80211("enter to channel %d\n", conf->channel->hw_value);
 
-	priv->add_radiotap = !!(conf->flags & IEEE80211_CONF_RADIOTAP);
-
 	if (conf->radio_enabled && iwl_radio_kill_sw_enable_radio(priv)) {
 		IWL_DEBUG_MAC80211("leave - RF-KILL - waiting for uCode\n");
 		goto out;
@@ -2817,7 +2788,6 @@
 	if (unlikely(!priv->cfg->mod_params->disable_hw_scan &&
 		     test_bit(STATUS_SCANNING, &priv->status))) {
 		IWL_DEBUG_MAC80211("leave - scanning\n");
-		set_bit(STATUS_CONF_PENDING, &priv->status);
 		mutex_unlock(&priv->mutex);
 		return 0;
 	}
@@ -2830,7 +2800,7 @@
 		goto out;
 	}
 
-	if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS &&
+	if (priv->iw_mode == NL80211_IFTYPE_ADHOC &&
 	    !is_channel_ibss(ch_info)) {
 		IWL_ERROR("channel %d in band %d not IBSS channel\n",
 			conf->channel->hw_value, conf->channel->band);
@@ -2851,7 +2821,7 @@
 	)
 		priv->staging_rxon.flags = 0;
 
-	iwl_set_rxon_channel(priv, conf->channel->band, channel);
+	iwl_set_rxon_channel(priv, conf->channel);
 
 	iwl_set_flags_for_band(priv, conf->channel->band);
 
@@ -2880,6 +2850,13 @@
 		goto out;
 	}
 
+	if (conf->flags & IEEE80211_CONF_PS)
+		ret = iwl_power_set_user_mode(priv, IWL_POWER_INDEX_3);
+	else
+		ret = iwl_power_set_user_mode(priv, IWL_POWER_MODE_CAM);
+	if (ret)
+		IWL_DEBUG_MAC80211("Error setting power level\n");
+
 	IWL_DEBUG_MAC80211("TX Power old=%d new=%d\n",
 			   priv->tx_power_user_lmt, conf->power_level);
 
@@ -2896,7 +2873,6 @@
 	IWL_DEBUG_MAC80211("leave\n");
 
 out:
-	clear_bit(STATUS_CONF_PENDING, &priv->status);
 	mutex_unlock(&priv->mutex);
 	return ret;
 }
@@ -2945,7 +2921,7 @@
 				priv->staging_rxon.flags &=
 					~RXON_FLG_SHORT_SLOT_MSK;
 
-			if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS)
+			if (priv->iw_mode == NL80211_IFTYPE_ADHOC)
 				priv->staging_rxon.flags &=
 					~RXON_FLG_SHORT_SLOT_MSK;
 		}
@@ -2984,7 +2960,7 @@
 		return 0;
 	}
 
-	if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS &&
+	if (priv->iw_mode == NL80211_IFTYPE_ADHOC &&
 	    conf->changed & IEEE80211_IFCC_BEACON) {
 		struct sk_buff *beacon = ieee80211_beacon_get(hw, vif);
 		if (!beacon)
@@ -2994,7 +2970,7 @@
 			return rc;
 	}
 
-	if ((priv->iw_mode == IEEE80211_IF_TYPE_AP) &&
+	if ((priv->iw_mode == NL80211_IFTYPE_AP) &&
 	    (!conf->ssid_len)) {
 		IWL_DEBUG_MAC80211
 		    ("Leaving in AP mode because HostAPD is not ready.\n");
@@ -3017,7 +2993,7 @@
 	    !(priv->hw->flags & IEEE80211_HW_NO_PROBE_FILTERING)) {
  */
 
-	if (priv->iw_mode == IEEE80211_IF_TYPE_AP) {
+	if (priv->iw_mode == NL80211_IFTYPE_AP) {
 		if (!conf->bssid) {
 			conf->bssid = priv->mac_addr;
 			memcpy(priv->bssid, priv->mac_addr, ETH_ALEN);
@@ -3052,11 +3028,11 @@
 		 * to verify) - jpk */
 		memcpy(priv->bssid, conf->bssid, ETH_ALEN);
 
-		if (priv->iw_mode == IEEE80211_IF_TYPE_AP)
+		if (priv->iw_mode == NL80211_IFTYPE_AP)
 			iwl4965_config_ap(priv);
 		else {
 			rc = iwl4965_commit_rxon(priv);
-			if ((priv->iw_mode == IEEE80211_IF_TYPE_STA) && rc)
+			if ((priv->iw_mode == NL80211_IFTYPE_STATION) && rc)
 				iwl_rxon_add_station(
 					priv, priv->active_rxon.bssid_addr, 1);
 		}
@@ -3092,7 +3068,7 @@
 
 	if (changed_flags & (*total_flags) & FIF_OTHER_BSS) {
 		IWL_DEBUG_MAC80211("Enter: type %d (0x%x, 0x%x)\n",
-				   IEEE80211_IF_TYPE_MNTR,
+				   NL80211_IFTYPE_MONITOR,
 				   changed_flags, *total_flags);
 		/* queue work 'cuz mac80211 is holding a lock which
 		 * prevents us from issuing (synchronous) f/w cmds */
@@ -3173,6 +3149,10 @@
 			priv->power_data.dtim_period = bss_conf->dtim_period;
 			priv->timestamp = bss_conf->timestamp;
 			priv->assoc_capability = bss_conf->assoc_capability;
+
+			/* we have just associated, don't start scan too early
+			 * leave time for EAPOL exchange to complete
+			 */
 			priv->next_scan_jiffies = jiffies +
 					IWL_DELAY_NEXT_SCAN_AFTER_ASSOC;
 			mutex_lock(&priv->mutex);
@@ -3189,11 +3169,11 @@
 
 }
 
-static int iwl4965_mac_hw_scan(struct ieee80211_hw *hw, u8 *ssid, size_t len)
+static int iwl_mac_hw_scan(struct ieee80211_hw *hw, u8 *ssid, size_t ssid_len)
 {
-	int rc = 0;
 	unsigned long flags;
 	struct iwl_priv *priv = hw->priv;
+	int ret;
 
 	IWL_DEBUG_MAC80211("enter\n");
 
@@ -3201,41 +3181,47 @@
 	spin_lock_irqsave(&priv->lock, flags);
 
 	if (!iwl_is_ready_rf(priv)) {
-		rc = -EIO;
+		ret = -EIO;
 		IWL_DEBUG_MAC80211("leave - not ready or exit pending\n");
 		goto out_unlock;
 	}
 
-	if (priv->iw_mode == IEEE80211_IF_TYPE_AP) {	/* APs don't scan */
-		rc = -EIO;
+	if (priv->iw_mode == NL80211_IFTYPE_AP) {	/* APs don't scan */
+		ret = -EIO;
 		IWL_ERROR("ERROR: APs don't scan\n");
 		goto out_unlock;
 	}
 
-	/* we don't schedule scan within next_scan_jiffies period */
+	/* We don't schedule scan within next_scan_jiffies period.
+	 * Avoid scanning during possible EAPOL exchange, return
+	 * success immediately.
+	 */
 	if (priv->next_scan_jiffies &&
-			time_after(priv->next_scan_jiffies, jiffies)) {
-		rc = -EAGAIN;
+	    time_after(priv->next_scan_jiffies, jiffies)) {
+		IWL_DEBUG_SCAN("scan rejected: within next scan period\n");
+		queue_work(priv->workqueue, &priv->scan_completed);
+		ret = 0;
 		goto out_unlock;
 	}
+
 	/* if we just finished scan ask for delay */
-	if (priv->last_scan_jiffies && time_after(priv->last_scan_jiffies +
-				IWL_DELAY_NEXT_SCAN, jiffies)) {
-		rc = -EAGAIN;
+	if (iwl_is_associated(priv) && priv->last_scan_jiffies &&
+	    time_after(priv->last_scan_jiffies + IWL_DELAY_NEXT_SCAN, jiffies)) {
+		IWL_DEBUG_SCAN("scan rejected: within previous scan period\n");
+		queue_work(priv->workqueue, &priv->scan_completed);
+		ret = 0;
 		goto out_unlock;
 	}
-	if (len) {
-		IWL_DEBUG_SCAN("direct scan for %s [%d]\n ",
-			       iwl_escape_essid(ssid, len), (int)len);
 
+	if (ssid_len) {
 		priv->one_direct_scan = 1;
-		priv->direct_ssid_len = (u8)
-		    min((u8) len, (u8) IW_ESSID_MAX_SIZE);
+		priv->direct_ssid_len =  min_t(u8, ssid_len, IW_ESSID_MAX_SIZE);
 		memcpy(priv->direct_ssid, ssid, priv->direct_ssid_len);
-	} else
+	} else {
 		priv->one_direct_scan = 0;
+	}
 
-	rc = iwl_scan_initiate(priv);
+	ret = iwl_scan_initiate(priv);
 
 	IWL_DEBUG_MAC80211("leave\n");
 
@@ -3243,7 +3229,7 @@
 	spin_unlock_irqrestore(&priv->lock, flags);
 	mutex_unlock(&priv->mutex);
 
-	return rc;
+	return ret;
 }
 
 static void iwl4965_mac_update_tkip_key(struct ieee80211_hw *hw,
@@ -3332,7 +3318,7 @@
 	 * in 1X mode.
 	 * In legacy wep mode, we use another host command to the uCode */
 	if (key->alg == ALG_WEP && sta_id == priv->hw_params.bcast_sta_id &&
-		priv->iw_mode != IEEE80211_IF_TYPE_AP) {
+		priv->iw_mode != NL80211_IFTYPE_AP) {
 		if (cmd == SET_KEY)
 			is_default_wep_key = !priv->key_mapping_key;
 		else
@@ -3403,7 +3389,7 @@
 	priv->qos_data.def_qos_parm.ac[q].reserved1 = 0;
 	priv->qos_data.qos_active = 1;
 
-	if (priv->iw_mode == IEEE80211_IF_TYPE_AP)
+	if (priv->iw_mode == NL80211_IFTYPE_AP)
 		iwl_activate_qos(priv, 1);
 	else if (priv->assoc_id && iwl_is_associated(priv))
 		iwl_activate_qos(priv, 0);
@@ -3416,13 +3402,13 @@
 
 static int iwl4965_mac_ampdu_action(struct ieee80211_hw *hw,
 			     enum ieee80211_ampdu_mlme_action action,
-			     const u8 *addr, u16 tid, u16 *ssn)
+			     struct ieee80211_sta *sta, u16 tid, u16 *ssn)
 {
 	struct iwl_priv *priv = hw->priv;
 	DECLARE_MAC_BUF(mac);
 
 	IWL_DEBUG_HT("A-MPDU action on addr %s tid %d\n",
-		     print_mac(mac, addr), tid);
+		     print_mac(mac, sta->addr), tid);
 
 	if (!(priv->cfg->sku & IWL_SKU_N))
 		return -EACCES;
@@ -3430,16 +3416,16 @@
 	switch (action) {
 	case IEEE80211_AMPDU_RX_START:
 		IWL_DEBUG_HT("start Rx\n");
-		return iwl_rx_agg_start(priv, addr, tid, *ssn);
+		return iwl_rx_agg_start(priv, sta->addr, tid, *ssn);
 	case IEEE80211_AMPDU_RX_STOP:
 		IWL_DEBUG_HT("stop Rx\n");
-		return iwl_rx_agg_stop(priv, addr, tid);
+		return iwl_rx_agg_stop(priv, sta->addr, tid);
 	case IEEE80211_AMPDU_TX_START:
 		IWL_DEBUG_HT("start Tx\n");
-		return iwl_tx_agg_start(priv, addr, tid, ssn);
+		return iwl_tx_agg_start(priv, sta->addr, tid, ssn);
 	case IEEE80211_AMPDU_TX_STOP:
 		IWL_DEBUG_HT("stop Tx\n");
-		return iwl_tx_agg_stop(priv, addr, tid);
+		return iwl_tx_agg_stop(priv, sta->addr, tid);
 	default:
 		IWL_DEBUG_HT("unknown\n");
 		return -EINVAL;
@@ -3521,7 +3507,7 @@
 
 	priv->beacon_int = priv->hw->conf.beacon_int;
 	priv->timestamp = 0;
-	if ((priv->iw_mode == IEEE80211_IF_TYPE_STA))
+	if ((priv->iw_mode == NL80211_IFTYPE_STATION))
 		priv->beacon_int = 0;
 
 	spin_unlock_irqrestore(&priv->lock, flags);
@@ -3535,7 +3521,7 @@
 	/* we are restarting association process
 	 * clear RXON_FILTER_ASSOC_MSK bit
 	 */
-	if (priv->iw_mode != IEEE80211_IF_TYPE_AP) {
+	if (priv->iw_mode != NL80211_IFTYPE_AP) {
 		iwl_scan_cancel_timeout(priv, 100);
 		priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
 		iwl4965_commit_rxon(priv);
@@ -3544,7 +3530,17 @@
 	iwl_power_update_mode(priv, 0);
 
 	/* Per mac80211.h: This is only used in IBSS mode... */
-	if (priv->iw_mode != IEEE80211_IF_TYPE_IBSS) {
+	if (priv->iw_mode != NL80211_IFTYPE_ADHOC) {
+
+		/* switch to CAM during association period.
+		 * the ucode will block any association/authentication
+		 * frome during assiciation period if it can not hear
+		 * the AP because of PM. the timer enable PM back is
+		 * association do not complete
+		 */
+		if (priv->hw->conf.channel->flags & (IEEE80211_CHAN_PASSIVE_SCAN |
+						     IEEE80211_CHAN_RADAR))
+				iwl_power_disable_management(priv, 3000);
 
 		IWL_DEBUG_MAC80211("leave - not in IBSS\n");
 		mutex_unlock(&priv->mutex);
@@ -3573,7 +3569,7 @@
 		return -EIO;
 	}
 
-	if (priv->iw_mode != IEEE80211_IF_TYPE_IBSS) {
+	if (priv->iw_mode != NL80211_IFTYPE_ADHOC) {
 		IWL_DEBUG_MAC80211("leave - not IBSS\n");
 		mutex_unlock(&priv->mutex);
 		return -EIO;
@@ -3630,11 +3626,11 @@
 				 const char *buf, size_t count)
 {
 	struct iwl_priv *priv = d->driver_data;
-	char *p = (char *)buf;
-	u32 val;
+	unsigned long val;
+	int ret;
 
-	val = simple_strtoul(p, &p, 0);
-	if (p == buf)
+	ret = strict_strtoul(buf, 0, &val);
+	if (ret)
 		printk(KERN_INFO DRV_NAME
 		       ": %s is not in hex or decimal form.\n", buf);
 	else
@@ -3706,11 +3702,11 @@
 			      const char *buf, size_t count)
 {
 	struct iwl_priv *priv = (struct iwl_priv *)d->driver_data;
-	char *p = (char *)buf;
-	u32 val;
+	unsigned long val;
+	int ret;
 
-	val = simple_strtoul(p, &p, 10);
-	if (p == buf)
+	ret = strict_strtoul(buf, 10, &val);
+	if (ret)
 		printk(KERN_INFO DRV_NAME
 		       ": %s is not in decimal form.\n", buf);
 	else
@@ -3734,7 +3730,12 @@
 			   const char *buf, size_t count)
 {
 	struct iwl_priv *priv = (struct iwl_priv *)d->driver_data;
-	u32 flags = simple_strtoul(buf, NULL, 0);
+	unsigned long val;
+	u32 flags;
+	int ret = strict_strtoul(buf, 0, &val);
+	if (ret)
+		return ret;
+	flags = (u32)val;
 
 	mutex_lock(&priv->mutex);
 	if (le32_to_cpu(priv->staging_rxon.flags) != flags) {
@@ -3742,8 +3743,7 @@
 		if (iwl_scan_cancel_timeout(priv, 100))
 			IWL_WARNING("Could not cancel scan.\n");
 		else {
-			IWL_DEBUG_INFO("Committing rxon.flags = 0x%04X\n",
-				       flags);
+			IWL_DEBUG_INFO("Commit rxon.flags = 0x%04X\n", flags);
 			priv->staging_rxon.flags = cpu_to_le32(flags);
 			iwl4965_commit_rxon(priv);
 		}
@@ -3769,7 +3769,12 @@
 				  const char *buf, size_t count)
 {
 	struct iwl_priv *priv = (struct iwl_priv *)d->driver_data;
-	u32 filter_flags = simple_strtoul(buf, NULL, 0);
+	unsigned long val;
+	u32 filter_flags;
+	int ret = strict_strtoul(buf, 0, &val);
+	if (ret)
+		return ret;
+	filter_flags = (u32)val;
 
 	mutex_lock(&priv->mutex);
 	if (le32_to_cpu(priv->staging_rxon.filter_flags) != filter_flags) {
@@ -3870,10 +3875,12 @@
 				const char *buf, size_t count)
 {
 	struct iwl_priv *priv = dev_get_drvdata(d);
+	long val;
+	int ret  = strict_strtol(buf, 10, &val);
+	if (!ret)
+		return ret;
 
-	priv->retry_rate = simple_strtoul(buf, NULL, 0);
-	if (priv->retry_rate <= 0)
-		priv->retry_rate = 1;
+	priv->retry_rate = (val > 0) ? val : 1;
 
 	return count;
 }
@@ -3894,9 +3901,9 @@
 {
 	struct iwl_priv *priv = dev_get_drvdata(d);
 	int ret;
-	int mode;
+	unsigned long mode;
 
-	mode = simple_strtoul(buf, NULL, 0);
+
 	mutex_lock(&priv->mutex);
 
 	if (!iwl_is_ready(priv)) {
@@ -3904,6 +3911,10 @@
 		goto out;
 	}
 
+	ret = strict_strtoul(buf, 10, &mode);
+	if (ret)
+		goto out;
+
 	ret = iwl_power_set_user_mode(priv, mode);
 	if (ret) {
 		IWL_DEBUG_MAC80211("failed setting power mode.\n");
@@ -4080,9 +4091,8 @@
 	INIT_DELAYED_WORK(&priv->init_alive_start, iwl_bg_init_alive_start);
 	INIT_DELAYED_WORK(&priv->alive_start, iwl_bg_alive_start);
 
-	/* FIXME : remove when resolved PENDING */
-	INIT_WORK(&priv->scan_completed, iwl_bg_scan_completed);
 	iwl_setup_scan_deferred_work(priv);
+	iwl_setup_power_deferred_work(priv);
 
 	if (priv->cfg->ops->lib->setup_deferred_work)
 		priv->cfg->ops->lib->setup_deferred_work(priv);
@@ -4102,6 +4112,7 @@
 
 	cancel_delayed_work_sync(&priv->init_alive_start);
 	cancel_delayed_work(&priv->scan_check);
+	cancel_delayed_work_sync(&priv->set_power_save);
 	cancel_delayed_work(&priv->alive_start);
 	cancel_work_sync(&priv->beacon_update);
 	del_timer_sync(&priv->statistics_periodic);
@@ -4150,7 +4161,7 @@
 	.reset_tsf = iwl4965_mac_reset_tsf,
 	.bss_info_changed = iwl4965_bss_info_changed,
 	.ampdu_action = iwl4965_mac_ampdu_action,
-	.hw_scan = iwl4965_mac_hw_scan
+	.hw_scan = iwl_mac_hw_scan
 };
 
 static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
@@ -4204,13 +4215,13 @@
 
 	pci_set_master(pdev);
 
-	err = pci_set_dma_mask(pdev, DMA_64BIT_MASK);
+	err = pci_set_dma_mask(pdev, DMA_BIT_MASK(36));
 	if (!err)
-		err = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK);
+		err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(36));
 	if (err) {
-		err = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
+		err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
 		if (!err)
-			err = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
+			err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
 		/* both attempts failed: */
 		if (err) {
 			printk(KERN_WARNING "%s: No suitable DMA available.\n",
@@ -4225,9 +4236,6 @@
 
 	pci_set_drvdata(pdev, priv);
 
-	/* We disable the RETRY_TIMEOUT register (0x41) to keep
-	 * PCI Tx retries from interfering with C3 CPU state */
-	pci_write_config_byte(pdev, 0x41, 0x00);
 
 	/***********************
 	 * 3. Read REV register
@@ -4247,6 +4255,10 @@
 		": Detected Intel Wireless WiFi Link %s REV=0x%X\n",
 		priv->cfg->name, priv->hw_rev);
 
+	/* We disable the RETRY_TIMEOUT register (0x41) to keep
+	 * PCI Tx retries from interfering with C3 CPU state */
+	pci_write_config_byte(pdev, PCI_CFG_RETRY_TIMEOUT, 0x00);
+
 	/* amp init */
 	err = priv->cfg->ops->lib->apm_ops.init(priv);
 	if (err < 0) {
@@ -4481,7 +4493,10 @@
 	{IWL_PCI_DEVICE(0x4235, PCI_ANY_ID, iwl5300_agn_cfg)},
 	{IWL_PCI_DEVICE(0x4236, PCI_ANY_ID, iwl5300_agn_cfg)},
 	{IWL_PCI_DEVICE(0x4237, PCI_ANY_ID, iwl5100_agn_cfg)},
-	{IWL_PCI_DEVICE(0x423A, PCI_ANY_ID, iwl5350_agn_cfg)},
+/* 5350 WiFi/WiMax */
+	{IWL_PCI_DEVICE(0x423A, 0x1001, iwl5350_agn_cfg)},
+	{IWL_PCI_DEVICE(0x423A, 0x1021, iwl5350_agn_cfg)},
+	{IWL_PCI_DEVICE(0x423B, 0x1011, iwl5350_agn_cfg)},
 #endif /* CONFIG_IWL5000 */
 	{0}
 };
diff --git a/drivers/net/wireless/iwlwifi/iwl-calib.c b/drivers/net/wireless/iwlwifi/iwl-calib.c
index ef49440..72fbf47 100644
--- a/drivers/net/wireless/iwlwifi/iwl-calib.c
+++ b/drivers/net/wireless/iwlwifi/iwl-calib.c
@@ -66,6 +66,66 @@
 #include "iwl-core.h"
 #include "iwl-calib.h"
 
+/*****************************************************************************
+ * INIT calibrations framework
+ *****************************************************************************/
+
+ int iwl_send_calib_results(struct iwl_priv *priv)
+{
+	int ret = 0;
+	int i = 0;
+
+	struct iwl_host_cmd hcmd = {
+		.id = REPLY_PHY_CALIBRATION_CMD,
+		.meta.flags = CMD_SIZE_HUGE,
+	};
+
+	for (i = 0; i < IWL_CALIB_MAX; i++)
+		if (priv->calib_results[i].buf) {
+			hcmd.len = priv->calib_results[i].buf_len;
+			hcmd.data = priv->calib_results[i].buf;
+			ret = iwl_send_cmd_sync(priv, &hcmd);
+			if (ret)
+				goto err;
+		}
+
+	return 0;
+err:
+	IWL_ERROR("Error %d iteration %d\n", ret, i);
+	return ret;
+}
+EXPORT_SYMBOL(iwl_send_calib_results);
+
+int iwl_calib_set(struct iwl_calib_result *res, const u8 *buf, int len)
+{
+	if (res->buf_len != len) {
+		kfree(res->buf);
+		res->buf = kzalloc(len, GFP_ATOMIC);
+	}
+	if (unlikely(res->buf == NULL))
+		return -ENOMEM;
+
+	res->buf_len = len;
+	memcpy(res->buf, buf, len);
+	return 0;
+}
+EXPORT_SYMBOL(iwl_calib_set);
+
+void iwl_calib_free_results(struct iwl_priv *priv)
+{
+	int i;
+
+	for (i = 0; i < IWL_CALIB_MAX; i++) {
+		kfree(priv->calib_results[i].buf);
+		priv->calib_results[i].buf = NULL;
+		priv->calib_results[i].buf_len = 0;
+	}
+}
+
+/*****************************************************************************
+ * RUNTIME calibrations framework
+ *****************************************************************************/
+
 /* "false alarms" are signals that our DSP tries to lock onto,
  *   but then determines that they are either noise, or transmissions
  *   from a distant wireless network (also "noise", really) that get
@@ -748,13 +808,11 @@
 		}
 	}
 
+	/* Save for use within RXON, TX, SCAN commands, etc. */
+	priv->chain_noise_data.active_chains = active_chains;
 	IWL_DEBUG_CALIB("active_chains (bitwise) = 0x%x\n",
 			active_chains);
 
-	/* Save for use within RXON, TX, SCAN commands, etc. */
-	/*priv->valid_antenna = active_chains;*/
-	/*FIXME: should be reflected in RX chains in RXON */
-
 	/* Analyze noise for rx balance */
 	average_noise[0] = ((data->chain_noise_a)/CAL_NUM_OF_BEACONS);
 	average_noise[1] = ((data->chain_noise_b)/CAL_NUM_OF_BEACONS);
@@ -779,6 +837,15 @@
 
 	priv->cfg->ops->utils->gain_computation(priv, average_noise,
 		min_average_noise_antenna_i, min_average_noise);
+
+	/* Some power changes may have been made during the calibration.
+	 * Update and commit the RXON
+	 */
+	if (priv->cfg->ops->lib->update_chain_flags)
+		priv->cfg->ops->lib->update_chain_flags(priv);
+
+	data->state = IWL_CHAIN_NOISE_DONE;
+	iwl_power_enable_management(priv);
 }
 EXPORT_SYMBOL(iwl_chain_noise_calibration);
 
diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h
index 28b5b09..8d04e96 100644
--- a/drivers/net/wireless/iwlwifi/iwl-commands.h
+++ b/drivers/net/wireless/iwlwifi/iwl-commands.h
@@ -163,6 +163,13 @@
 /* iwl_cmd_header flags value */
 #define IWL_CMD_FAILED_MSK 0x40
 
+#define SEQ_TO_QUEUE(s)	(((s) >> 8) & 0x1f)
+#define QUEUE_TO_SEQ(q)	(((q) & 0x1f) << 8)
+#define SEQ_TO_INDEX(s)	((s) & 0xff)
+#define INDEX_TO_SEQ(i)	((i) & 0xff)
+#define SEQ_HUGE_FRAME	__constant_cpu_to_le16(0x4000)
+#define SEQ_RX_FRAME	__constant_cpu_to_le16(0x8000)
+
 /**
  * struct iwl_cmd_header
  *
@@ -171,7 +178,7 @@
  */
 struct iwl_cmd_header {
 	u8 cmd;		/* Command ID:  REPLY_RXON, etc. */
-	u8 flags;	/* IWL_CMD_* */
+	u8 flags;	/* 0:5 reserved, 6 abort, 7 internal */
 	/*
 	 * The driver sets up the sequence number to values of its chosing.
 	 * uCode does not use this value, but passes it back to the driver
@@ -187,11 +194,12 @@
 	 *
 	 * The Linux driver uses the following format:
 	 *
-	 *  0:7    index/position within Tx queue
-	 *  8:13   Tx queue selection
-	 * 14:14   driver sets this to indicate command is in the 'huge'
-	 *         storage at the end of the command buffers, i.e. scan cmd
-	 * 15:15   uCode sets this in uCode-originated response/notification
+	 *  0:7		tfd index - position within TX queue
+	 *  8:12	TX queue id
+	 *  13		reserved
+	 *  14		huge - driver sets this to indicate command is in the
+	 *  		'huge' storage at the end of the command buffers
+	 *  15		unsolicited RX or uCode-originated notification
 	 */
 	__le16 sequence;
 
@@ -2026,8 +2034,8 @@
  *   bit 2 - '0' PM have to walk up every DTIM
  *           '1' PM could sleep over DTIM till listen Interval.
  * PCI power managed
- *   bit 3 - '0' (PCI_LINK_CTRL & 0x1)
- *           '1' !(PCI_LINK_CTRL & 0x1)
+ *   bit 3 - '0' (PCI_CFG_LINK_CTRL & 0x1)
+ *           '1' !(PCI_CFG_LINK_CTRL & 0x1)
  * Force sleep Modes
  *   bit 31/30- '00' use both mac/xtal sleeps
  *              '01' force Mac sleep
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c
index 80f2f84..4c312c5 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.c
+++ b/drivers/net/wireless/iwlwifi/iwl-core.c
@@ -306,14 +306,14 @@
 	spin_lock_irqsave(&priv->lock, flags);
 	priv->qos_data.qos_active = 0;
 
-	if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS) {
+	if (priv->iw_mode == NL80211_IFTYPE_ADHOC) {
 		if (priv->qos_data.qos_enable)
 			priv->qos_data.qos_active = 1;
 		if (!(priv->active_rate & 0xfff0)) {
 			cw_min = 31;
 			is_legacy = 1;
 		}
-	} else if (priv->iw_mode == IEEE80211_IF_TYPE_AP) {
+	} else if (priv->iw_mode == NL80211_IFTYPE_AP) {
 		if (priv->qos_data.qos_enable)
 			priv->qos_data.qos_active = 1;
 	} else if (!(priv->staging_rxon.flags & RXON_FLG_SHORT_SLOT_MSK)) {
@@ -399,8 +399,8 @@
 
 	ht_info->cap |= (u16)IEEE80211_HT_CAP_GRN_FLD;
 	ht_info->cap |= (u16)IEEE80211_HT_CAP_SGI_20;
-	ht_info->cap |= (u16)(IEEE80211_HT_CAP_MIMO_PS &
-			     (IWL_MIMO_PS_NONE << 2));
+	ht_info->cap |= (u16)(IEEE80211_HT_CAP_SM_PS &
+			     (WLAN_HT_CAP_SM_PS_DISABLED << 2));
 
 	max_bit_rate = MAX_BIT_RATE_20_MHZ;
 	if (priv->hw_params.fat_channel & BIT(band)) {
@@ -646,8 +646,14 @@
 	struct iwl_rxon_cmd *rxon = &priv->staging_rxon;
 	u32 val;
 
-	if (!ht_info->is_ht)
+	if (!ht_info->is_ht) {
+		rxon->flags &= ~(RXON_FLG_CHANNEL_MODE_MIXED_MSK |
+			RXON_FLG_CHANNEL_MODE_PURE_40_MSK |
+			RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK |
+			RXON_FLG_FAT_PROT_MSK |
+			RXON_FLG_HT_PROT_MSK);
 		return;
+	}
 
 	/* Set up channel bandwidth:  20 MHz only, or 20/40 mixed if fat ok */
 	if (iwl_is_fat_tx_allowed(priv, NULL))
@@ -697,8 +703,12 @@
 }
 EXPORT_SYMBOL(iwl_set_rxon_ht);
 
-/*
- * Determine how many receiver/antenna chains to use.
+#define IWL_NUM_RX_CHAINS_MULTIPLE	3
+#define IWL_NUM_RX_CHAINS_SINGLE	2
+#define IWL_NUM_IDLE_CHAINS_DUAL	2
+#define IWL_NUM_IDLE_CHAINS_SINGLE	1
+
+/* Determine how many receiver/antenna chains to use.
  * More provides better reception via diversity.  Fewer saves power.
  * MIMO (dual stream) requires at least 2, but works better with 3.
  * This does not determine *which* chains to use, just how many.
@@ -709,10 +719,11 @@
 	bool is_cam = !test_bit(STATUS_POWER_PMI, &priv->status);
 
 	/* # of Rx chains to use when expecting MIMO. */
-	if (is_single || (!is_cam && (priv->ps_mode == IWL_MIMO_PS_STATIC)))
-		return 2;
+	if (is_single || (!is_cam && (priv->current_ht_config.sm_ps ==
+						 WLAN_HT_CAP_SM_PS_STATIC)))
+		return IWL_NUM_RX_CHAINS_SINGLE;
 	else
-		return 3;
+		return IWL_NUM_RX_CHAINS_MULTIPLE;
 }
 
 static int iwl_get_idle_rx_chain_count(struct iwl_priv *priv, int active_cnt)
@@ -720,17 +731,19 @@
 	int idle_cnt;
 	bool is_cam = !test_bit(STATUS_POWER_PMI, &priv->status);
 	/* # Rx chains when idling and maybe trying to save power */
-	switch (priv->ps_mode) {
-	case IWL_MIMO_PS_STATIC:
-	case IWL_MIMO_PS_DYNAMIC:
-		idle_cnt = (is_cam) ? 2 : 1;
+	switch (priv->current_ht_config.sm_ps) {
+	case WLAN_HT_CAP_SM_PS_STATIC:
+	case WLAN_HT_CAP_SM_PS_DYNAMIC:
+		idle_cnt = (is_cam) ? IWL_NUM_IDLE_CHAINS_DUAL :
+					IWL_NUM_IDLE_CHAINS_SINGLE;
 		break;
-	case IWL_MIMO_PS_NONE:
-		idle_cnt = (is_cam) ? active_cnt : 1;
+	case WLAN_HT_CAP_SM_PS_DISABLED:
+		idle_cnt = (is_cam) ? active_cnt : IWL_NUM_IDLE_CHAINS_SINGLE;
 		break;
-	case IWL_MIMO_PS_INVALID:
+	case WLAN_HT_CAP_SM_PS_INVALID:
 	default:
-		IWL_ERROR("invalide mimo ps mode %d\n", priv->ps_mode);
+		IWL_ERROR("invalide mimo ps mode %d\n",
+			   priv->current_ht_config.sm_ps);
 		WARN_ON(1);
 		idle_cnt = -1;
 		break;
@@ -738,6 +751,17 @@
 	return idle_cnt;
 }
 
+/* up to 4 chains */
+static u8 iwl_count_chain_bitmap(u32 chain_bitmap)
+{
+	u8 res;
+	res = (chain_bitmap & BIT(0)) >> 0;
+	res += (chain_bitmap & BIT(1)) >> 1;
+	res += (chain_bitmap & BIT(2)) >> 2;
+	res += (chain_bitmap & BIT(4)) >> 4;
+	return res;
+}
+
 /**
  * iwl_set_rxon_chain - Set up Rx chain usage in "staging" RXON image
  *
@@ -748,37 +772,47 @@
 {
 	bool is_single = is_single_rx_stream(priv);
 	bool is_cam = !test_bit(STATUS_POWER_PMI, &priv->status);
-	u8 idle_rx_cnt, active_rx_cnt;
+	u8 idle_rx_cnt, active_rx_cnt, valid_rx_cnt;
+	u32 active_chains;
 	u16 rx_chain;
 
 	/* Tell uCode which antennas are actually connected.
 	 * Before first association, we assume all antennas are connected.
 	 * Just after first association, iwl_chain_noise_calibration()
 	 *    checks which antennas actually *are* connected. */
-	rx_chain = priv->hw_params.valid_rx_ant << RXON_RX_CHAIN_VALID_POS;
+	 if (priv->chain_noise_data.active_chains)
+		active_chains = priv->chain_noise_data.active_chains;
+	else
+		active_chains = priv->hw_params.valid_rx_ant;
+
+	rx_chain = active_chains << RXON_RX_CHAIN_VALID_POS;
 
 	/* How many receivers should we use? */
 	active_rx_cnt = iwl_get_active_rx_chain_count(priv);
 	idle_rx_cnt = iwl_get_idle_rx_chain_count(priv, active_rx_cnt);
 
-	/* correct rx chain count accoridng hw settings */
-	if (priv->hw_params.rx_chains_num < active_rx_cnt)
-		active_rx_cnt = priv->hw_params.rx_chains_num;
 
-	if (priv->hw_params.rx_chains_num < idle_rx_cnt)
-		idle_rx_cnt = priv->hw_params.rx_chains_num;
+	/* correct rx chain count according hw settings
+	 * and chain noise calibration
+	 */
+	valid_rx_cnt = iwl_count_chain_bitmap(active_chains);
+	if (valid_rx_cnt < active_rx_cnt)
+		active_rx_cnt = valid_rx_cnt;
+
+	if (valid_rx_cnt < idle_rx_cnt)
+		idle_rx_cnt = valid_rx_cnt;
 
 	rx_chain |= active_rx_cnt << RXON_RX_CHAIN_MIMO_CNT_POS;
 	rx_chain |= idle_rx_cnt  << RXON_RX_CHAIN_CNT_POS;
 
 	priv->staging_rxon.rx_chain = cpu_to_le16(rx_chain);
 
-	if (!is_single && (active_rx_cnt >= 2) && is_cam)
+	if (!is_single && (active_rx_cnt >= IWL_NUM_RX_CHAINS_SINGLE) && is_cam)
 		priv->staging_rxon.rx_chain |= RXON_RX_CHAIN_MIMO_FORCE_MSK;
 	else
 		priv->staging_rxon.rx_chain &= ~RXON_RX_CHAIN_MIMO_FORCE_MSK;
 
-	IWL_DEBUG_ASSOC("rx_chain=0x%Xi active=%d idle=%d\n",
+	IWL_DEBUG_ASSOC("rx_chain=0x%X active=%d idle=%d\n",
 			priv->staging_rxon.rx_chain,
 			active_rx_cnt, idle_rx_cnt);
 
@@ -788,7 +822,7 @@
 EXPORT_SYMBOL(iwl_set_rxon_chain);
 
 /**
- * iwlcore_set_rxon_channel - Set the phymode and channel values in staging RXON
+ * iwl_set_rxon_channel - Set the phymode and channel values in staging RXON
  * @phymode: MODE_IEEE80211A sets to 5.2GHz; all else set to 2.4GHz
  * @channel: Any channel valid for the requested phymode
 
@@ -797,10 +831,11 @@
  * NOTE:  Does not commit to the hardware; it sets appropriate bit fields
  * in the staging RXON flag structure based on the phymode
  */
-int iwl_set_rxon_channel(struct iwl_priv *priv,
-				enum ieee80211_band band,
-				u16 channel)
+int iwl_set_rxon_channel(struct iwl_priv *priv, struct ieee80211_channel *ch)
 {
+	enum ieee80211_band band = ch->band;
+	u16 channel = ieee80211_frequency_to_channel(ch->center_freq);
+
 	if (!iwl_get_channel_info(priv, band, channel)) {
 		IWL_DEBUG_INFO("Could not set channel to %d [%d]\n",
 			       channel, band);
@@ -834,6 +869,10 @@
 	/* Tell mac80211 our characteristics */
 	hw->flags = IEEE80211_HW_SIGNAL_DBM |
 		    IEEE80211_HW_NOISE_DBM;
+	hw->wiphy->interface_modes =
+		BIT(NL80211_IFTYPE_AP) |
+		BIT(NL80211_IFTYPE_STATION) |
+		BIT(NL80211_IFTYPE_ADHOC);
 	/* Default value; 4 EDCA QOS priorities */
 	hw->queues = 4;
 	/* queues to support 11n aggregation */
@@ -891,7 +930,6 @@
 	spin_lock_init(&priv->power_data.lock);
 	spin_lock_init(&priv->sta_lock);
 	spin_lock_init(&priv->hcmd_lock);
-	spin_lock_init(&priv->lq_mngr.lock);
 
 	INIT_LIST_HEAD(&priv->free_frames);
 
@@ -905,10 +943,10 @@
 	priv->ieee_rates = NULL;
 	priv->band = IEEE80211_BAND_2GHZ;
 
-	priv->iw_mode = IEEE80211_IF_TYPE_STA;
+	priv->iw_mode = NL80211_IFTYPE_STATION;
 
 	priv->use_ant_b_for_management_frame = 1; /* start with ant B */
-	priv->ps_mode = IWL_MIMO_PS_NONE;
+	priv->current_ht_config.sm_ps = WLAN_HT_CAP_SM_PS_DISABLED;
 
 	/* Choose which receivers/antennas to use */
 	iwl_set_rxon_chain(priv);
@@ -922,8 +960,6 @@
 	priv->qos_data.qos_active = 0;
 	priv->qos_data.qos_cap.val = 0;
 
-	iwl_set_rxon_channel(priv, IEEE80211_BAND_2GHZ, 6);
-
 	priv->rates_mask = IWL_RATES_MASK;
 	/* If power management is turned on, default to AC mode */
 	priv->power_mode = IWL_POWER_AC;
@@ -950,22 +986,6 @@
 }
 EXPORT_SYMBOL(iwl_init_drv);
 
-void iwl_free_calib_results(struct iwl_priv *priv)
-{
-	kfree(priv->calib_results.lo_res);
-	priv->calib_results.lo_res = NULL;
-	priv->calib_results.lo_res_len = 0;
-
-	kfree(priv->calib_results.tx_iq_res);
-	priv->calib_results.tx_iq_res = NULL;
-	priv->calib_results.tx_iq_res_len = 0;
-
-	kfree(priv->calib_results.tx_iq_perd_res);
-	priv->calib_results.tx_iq_perd_res = NULL;
-	priv->calib_results.tx_iq_perd_res_len = 0;
-}
-EXPORT_SYMBOL(iwl_free_calib_results);
-
 int iwl_set_tx_power(struct iwl_priv *priv, s8 tx_power, bool force)
 {
 	int ret = 0;
@@ -993,10 +1013,9 @@
 }
 EXPORT_SYMBOL(iwl_set_tx_power);
 
-
 void iwl_uninit_drv(struct iwl_priv *priv)
 {
-	iwl_free_calib_results(priv);
+	iwl_calib_free_results(priv);
 	iwlcore_free_geos(priv);
 	iwl_free_channel_map(priv);
 	kfree(priv->scan);
@@ -1150,7 +1169,6 @@
 }
 EXPORT_SYMBOL(iwl_verify_ucode);
 
-
 static const char *desc_lookup(int i)
 {
 	switch (i) {
@@ -1231,9 +1249,9 @@
 /**
  * iwl_print_event_log - Dump error event log to syslog
  *
- * NOTE: Must be called with iwl4965_grab_nic_access() already obtained!
+ * NOTE: Must be called with iwl_grab_nic_access() already obtained!
  */
-void iwl_print_event_log(struct iwl_priv *priv, u32 start_idx,
+static void iwl_print_event_log(struct iwl_priv *priv, u32 start_idx,
 				u32 num_events, u32 mode)
 {
 	u32 i;
@@ -1274,8 +1292,6 @@
 		}
 	}
 }
-EXPORT_SYMBOL(iwl_print_event_log);
-
 
 void iwl_dump_nic_event_log(struct iwl_priv *priv)
 {
@@ -1391,7 +1407,7 @@
 
 	iwl_scan_cancel(priv);
 	/* FIXME: This is a workaround for AP */
-	if (priv->iw_mode != IEEE80211_IF_TYPE_AP) {
+	if (priv->iw_mode != NL80211_IFTYPE_AP) {
 		spin_lock_irqsave(&priv->lock, flags);
 		iwl_write32(priv, CSR_UCODE_DRV_GP1_SET,
 			    CSR_UCODE_SW_BIT_RFKILL);
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h
index 64f139e..288b6a8 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.h
+++ b/drivers/net/wireless/iwlwifi/iwl-core.h
@@ -184,14 +184,10 @@
 struct ieee80211_hw *iwl_alloc_all(struct iwl_cfg *cfg,
 		struct ieee80211_ops *hw_ops);
 void iwl_hw_detect(struct iwl_priv *priv);
-
 void iwl_clear_stations_table(struct iwl_priv *priv);
-void iwl_free_calib_results(struct iwl_priv *priv);
 void iwl_reset_qos(struct iwl_priv *priv);
 void iwl_set_rxon_chain(struct iwl_priv *priv);
-int iwl_set_rxon_channel(struct iwl_priv *priv,
-				enum ieee80211_band band,
-				u16 channel);
+int iwl_set_rxon_channel(struct iwl_priv *priv, struct ieee80211_channel *ch);
 void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_info *ht_info);
 u8 iwl_is_fat_tx_allowed(struct iwl_priv *priv,
 			 struct ieee80211_ht_info *sta_ht_inf);
@@ -218,7 +214,6 @@
 int iwl_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq);
 int iwl_rx_agg_start(struct iwl_priv *priv, const u8 *addr, int tid, u16 ssn);
 int iwl_rx_agg_stop(struct iwl_priv *priv, const u8 *addr, int tid);
-/* FIXME: remove when TX is moved to iwl core */
 int iwl_rx_queue_restock(struct iwl_priv *priv);
 int iwl_rx_queue_space(const struct iwl_rx_queue *q);
 void iwl_rx_allocate(struct iwl_priv *priv);
@@ -237,11 +232,7 @@
 ******************************************************/
 int iwl_txq_ctx_reset(struct iwl_priv *priv);
 int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb);
-/* FIXME: remove when free Tx is fully merged into iwlcore */
-int iwl_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq);
 void iwl_hw_txq_ctx_free(struct iwl_priv *priv);
-int iwl_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv, void *tfd,
-					dma_addr_t addr, u16 len);
 int iwl_txq_update_write_ptr(struct iwl_priv *priv, struct iwl_tx_queue *txq);
 int iwl_tx_agg_start(struct iwl_priv *priv, const u8 *ra, u16 tid, u16 *ssn);
 int iwl_tx_agg_stop(struct iwl_priv *priv , const u8 *ra, u16 tid);
@@ -256,6 +247,7 @@
  * RF -Kill - here and not in iwl-rfkill.h to be available when
  * RF-kill subsystem is not compiled.
  ****************************************************/
+void iwl_rf_kill(struct iwl_priv *priv);
 void iwl_radio_kill_sw_disable_radio(struct iwl_priv *priv);
 int iwl_radio_kill_sw_enable_radio(struct iwl_priv *priv);
 
@@ -286,11 +278,17 @@
 void iwl_init_scan_params(struct iwl_priv *priv);
 int iwl_scan_cancel(struct iwl_priv *priv);
 int iwl_scan_cancel_timeout(struct iwl_priv *priv, unsigned long ms);
-const char *iwl_escape_essid(const char *essid, u8 essid_len);
 int iwl_scan_initiate(struct iwl_priv *priv);
 void iwl_setup_rx_scan_handlers(struct iwl_priv *priv);
 void iwl_setup_scan_deferred_work(struct iwl_priv *priv);
 
+/*******************************************************************************
+ * Calibrations - implemented in iwl-calib.c
+ ******************************************************************************/
+int iwl_send_calib_results(struct iwl_priv *priv);
+int iwl_calib_set(struct iwl_calib_result *res, const u8 *buf, int len);
+void iwl_calib_free_results(struct iwl_priv *priv);
+
 /*****************************************************
  *   S e n d i n g     H o s t     C o m m a n d s   *
  *****************************************************/
@@ -312,8 +310,6 @@
 /*****************************************************
 *  Error Handling Debugging
 ******************************************************/
-void iwl_print_event_log(struct iwl_priv *priv, u32 start_idx,
-			 u32 num_events, u32 mode);
 void iwl_dump_nic_error_log(struct iwl_priv *priv);
 void iwl_dump_nic_event_log(struct iwl_priv *priv);
 
@@ -337,8 +333,7 @@
 #define STATUS_SCAN_HW		15
 #define STATUS_POWER_PMI	16
 #define STATUS_FW_ERROR		17
-#define STATUS_CONF_PENDING	18
-#define STATUS_MODE_PENDING	19
+#define STATUS_MODE_PENDING	18
 
 
 static inline int iwl_is_ready(struct iwl_priv *priv)
diff --git a/drivers/net/wireless/iwlwifi/iwl-csr.h b/drivers/net/wireless/iwlwifi/iwl-csr.h
index 52629fb..662edf4 100644
--- a/drivers/net/wireless/iwlwifi/iwl-csr.h
+++ b/drivers/net/wireless/iwlwifi/iwl-csr.h
@@ -64,7 +64,7 @@
 #define CSR_BASE    (0x000)
 
 #define CSR_HW_IF_CONFIG_REG    (CSR_BASE+0x000) /* hardware interface config */
-#define CSR_INT_COALESCING      (CSR_BASE+0x004) /* accum ints, 32-usec units */
+#define CSR_INT_COALESCING     (CSR_BASE+0x004) /* accum ints, 32-usec units */
 #define CSR_INT                 (CSR_BASE+0x008) /* host interrupt status/ack */
 #define CSR_INT_MASK            (CSR_BASE+0x00c) /* host interrupt enable */
 #define CSR_FH_INT_STATUS       (CSR_BASE+0x010) /* busmaster int status/ack*/
diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h
index d2daa17..e548d67 100644
--- a/drivers/net/wireless/iwlwifi/iwl-debug.h
+++ b/drivers/net/wireless/iwlwifi/iwl-debug.h
@@ -110,11 +110,12 @@
  *
  */
 
-#define IWL_DL_INFO          (1 << 0)
-#define IWL_DL_MAC80211      (1 << 1)
-#define IWL_DL_HOST_COMMAND  (1 << 2)
-#define IWL_DL_STATE         (1 << 3)
+#define IWL_DL_INFO		(1 << 0)
+#define IWL_DL_MAC80211		(1 << 1)
+#define IWL_DL_HCMD		(1 << 2)
+#define IWL_DL_STATE		(1 << 3)
 #define IWL_DL_MACDUMP		(1 << 4)
+#define IWL_DL_HCMD_DUMP	(1 << 5)
 #define IWL_DL_RADIO         (1 << 7)
 #define IWL_DL_POWER         (1 << 8)
 #define IWL_DL_TEMP          (1 << 9)
@@ -162,7 +163,8 @@
 #define IWL_DEBUG_ISR(f, a...)    IWL_DEBUG(IWL_DL_ISR, f, ## a)
 #define IWL_DEBUG_LED(f, a...) IWL_DEBUG(IWL_DL_LED, f, ## a)
 #define IWL_DEBUG_WEP(f, a...)    IWL_DEBUG(IWL_DL_WEP, f, ## a)
-#define IWL_DEBUG_HC(f, a...) IWL_DEBUG(IWL_DL_HOST_COMMAND, f, ## a)
+#define IWL_DEBUG_HC(f, a...) IWL_DEBUG(IWL_DL_HCMD, f, ## a)
+#define IWL_DEBUG_HC_DUMP(f, a...) IWL_DEBUG(IWL_DL_HCMD_DUMP, f, ## a)
 #define IWL_DEBUG_CALIB(f, a...) IWL_DEBUG(IWL_DL_CALIB, f, ## a)
 #define IWL_DEBUG_FW(f, a...) IWL_DEBUG(IWL_DL_FW, f, ## a)
 #define IWL_DEBUG_RF_KILL(f, a...) IWL_DEBUG(IWL_DL_RF_KILL, f, ## a)
diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h
index cdfb343..c018121 100644
--- a/drivers/net/wireless/iwlwifi/iwl-dev.h
+++ b/drivers/net/wireless/iwlwifi/iwl-dev.h
@@ -225,12 +225,6 @@
 	struct list_head list;
 };
 
-#define SEQ_TO_QUEUE(x)  ((x >> 8) & 0xbf)
-#define QUEUE_TO_SEQ(x)  ((x & 0xbf) << 8)
-#define SEQ_TO_INDEX(x) ((u8)(x & 0xff))
-#define INDEX_TO_SEQ(x) ((u8)(x & 0xff))
-#define SEQ_HUGE_FRAME  (0x4000)
-#define SEQ_RX_FRAME    __constant_cpu_to_le16(0x8000)
 #define SEQ_TO_SN(seq) (((seq) & IEEE80211_SCTL_SEQ) >> 4)
 #define SN_TO_SEQ(ssn) (((ssn) << 4) & IEEE80211_SCTL_SEQ)
 #define MAX_SN ((IEEE80211_SCTL_SEQ) >> 4)
@@ -412,6 +406,7 @@
 	/* self configuration data */
 	u8 is_ht;
 	u8 supported_chan_width;
+	u8 sm_ps;
 	u8 is_green_field;
 	u8 sgf;			/* HT_SHORT_GI_* short guard interval */
 	u8 max_amsdu_size;
@@ -570,50 +565,31 @@
 #define IWL_RX_STATS(x) (&x->u.rx_frame.stats)
 #define IWL_RX_DATA(x) (IWL_RX_HDR(x)->payload)
 
-
 /******************************************************************************
  *
- * Functions implemented in iwl-base.c which are forward declared here
- * for use by iwl-*.c
+ * Functions implemented in core module which are forward declared here
+ * for use by iwl-[4-5].c
  *
- *****************************************************************************/
-struct iwl_addsta_cmd;
-extern int iwl_send_add_sta(struct iwl_priv *priv,
-			    struct iwl_addsta_cmd *sta, u8 flags);
-u8 iwl_add_station_flags(struct iwl_priv *priv, const u8 *addr, int is_ap,
-			 u8 flags, struct ieee80211_ht_info *ht_info);
-extern unsigned int iwl4965_fill_beacon_frame(struct iwl_priv *priv,
-					struct ieee80211_hdr *hdr,
-					const u8 *dest, int left);
-extern void iwl4965_update_chain_flags(struct iwl_priv *priv);
-int iwl4965_set_pwr_src(struct iwl_priv *priv, enum iwl_pwr_src src);
-extern int iwl4965_set_power(struct iwl_priv *priv, void *cmd);
-
-extern const u8 iwl_bcast_addr[ETH_ALEN];
-
-/******************************************************************************
- *
- * Functions implemented in iwl-[34]*.c which are forward declared here
- * for use by iwl-base.c
- *
- * NOTE:  The implementation of these functions are hardware specific
- * which is why they are in the hardware specific files (vs. iwl-base.c)
+ * NOTE:  The implementation of these functions are not hardware specific
+ * which is why they are in the core module files.
  *
  * Naming convention --
- * iwl4965_         <-- Its part of iwlwifi (should be changed to iwl4965_)
- * iwl4965_hw_      <-- Hardware specific (implemented in iwl-XXXX.c by all HW)
+ * iwl_         <-- Is part of iwlwifi
  * iwlXXXX_     <-- Hardware specific (implemented in iwl-XXXX.c for XXXX)
  * iwl4965_bg_      <-- Called from work queue context
  * iwl4965_mac_     <-- mac80211 callback
  *
  ****************************************************************************/
+struct iwl_addsta_cmd;
+extern int iwl_send_add_sta(struct iwl_priv *priv,
+			    struct iwl_addsta_cmd *sta, u8 flags);
+extern u8 iwl_add_station_flags(struct iwl_priv *priv, const u8 *addr,
+			int is_ap, u8 flags, struct ieee80211_ht_info *ht_info);
+extern void iwl4965_update_chain_flags(struct iwl_priv *priv);
+extern int iwl4965_set_pwr_src(struct iwl_priv *priv, enum iwl_pwr_src src);
+extern const u8 iwl_bcast_addr[ETH_ALEN];
 extern int iwl_rxq_stop(struct iwl_priv *priv);
 extern void iwl_txq_ctx_stop(struct iwl_priv *priv);
-extern unsigned int iwl4965_hw_get_beacon_cmd(struct iwl_priv *priv,
-				 struct iwl_frame *frame, u8 rate);
-extern void iwl4965_disable_events(struct iwl_priv *priv);
-
-extern int iwl4965_hw_channel_switch(struct iwl_priv *priv, u16 channel);
 extern int iwl_queue_space(const struct iwl_queue *q);
 static inline int iwl_queue_used(const struct iwl_queue *q, int i)
 {
@@ -636,12 +612,6 @@
 
 struct iwl_priv;
 
-/*
- * Forward declare iwl-4965.c functions for iwl-base.c
- */
-extern void iwl4965_rf_kill_ct_config(struct iwl_priv *priv);
-int iwl4965_check_empty_hw_queue(struct iwl_priv *priv, int sta_id,
-					u8 tid, int txq_id);
 
 /* Structures, enum, and defines specific to the 4965 */
 
@@ -656,11 +626,6 @@
 #define IWL_CHANNEL_WIDTH_20MHZ   0
 #define IWL_CHANNEL_WIDTH_40MHZ   1
 
-#define IWL_MIMO_PS_STATIC        0
-#define IWL_MIMO_PS_NONE          3
-#define IWL_MIMO_PS_DYNAMIC       1
-#define IWL_MIMO_PS_INVALID       2
-
 #define IWL_OPERATION_MODE_AUTO     0
 #define IWL_OPERATION_MODE_HT_ONLY  1
 #define IWL_OPERATION_MODE_MIXED    2
@@ -671,18 +636,6 @@
 
 #define TX_POWER_IWL_ILLEGAL_VOLTAGE -10000
 
-struct iwl4965_lq_mngr {
-	spinlock_t lock;
-	s32 max_window_size;
-	s32 *expected_tpt;
-	u8 *next_higher_rate;
-	u8 *next_lower_rate;
-	unsigned long stamp;
-	unsigned long stamp_last;
-	u32 flush_time;
-	u32 tx_packets;
-};
-
 /* Sensitivity and chain noise calibration */
 #define INTERFERENCE_DATA_AVAILABLE	__constant_cpu_to_le32(1)
 #define INITIALIZATION_VALUE		0xFFFF
@@ -727,8 +680,9 @@
 
 enum iwl4965_chain_noise_state {
 	IWL_CHAIN_NOISE_ALIVE = 0,  /* must be 0 */
-	IWL_CHAIN_NOISE_ACCUMULATE = 1,
-	IWL_CHAIN_NOISE_CALIBRATED = 2,
+	IWL_CHAIN_NOISE_ACCUMULATE,
+	IWL_CHAIN_NOISE_CALIBRATED,
+	IWL_CHAIN_NOISE_DONE,
 };
 
 enum iwl4965_calib_enabled_state {
@@ -745,13 +699,10 @@
 	u32 beacon_energy_c;
 };
 
-struct iwl_calib_results {
-	void *tx_iq_res;
-	void *tx_iq_perd_res;
-	void *lo_res;
-	u32 tx_iq_res_len;
-	u32 tx_iq_perd_res_len;
-	u32 lo_res_len;
+/* Opaque calibration results */
+struct iwl_calib_result {
+	void *buf;
+	size_t buf_len;
 };
 
 enum ucode_type {
@@ -789,17 +740,18 @@
 
 /* Chain noise (differential Rx gain) calib data */
 struct iwl_chain_noise_data {
-	u8 state;
-	u16 beacon_count;
+	u32 active_chains;
 	u32 chain_noise_a;
 	u32 chain_noise_b;
 	u32 chain_noise_c;
 	u32 chain_signal_a;
 	u32 chain_signal_b;
 	u32 chain_signal_c;
+	u16 beacon_count;
 	u8 disconn_array[NUM_RX_CHAINS];
 	u8 delta_gain_code[NUM_RX_CHAINS];
 	u8 radio_write;
+	u8 state;
 };
 
 #define	EEPROM_SEM_TIMEOUT 10		/* milliseconds */
@@ -813,6 +765,7 @@
 
 
 #define IWL_MAX_NUM_QUEUES	20 /* FIXME: do dynamic allocation */
+#define IWL_CALIB_MAX  3
 
 struct iwl_priv {
 
@@ -828,7 +781,6 @@
 
 	enum ieee80211_band band;
 	int alloc_rxb_skb;
-	bool add_radiotap;
 
 	void (*rx_handlers[REPLY_MAX])(struct iwl_priv *priv,
 				       struct iwl_rx_mem_buffer *rxb);
@@ -857,7 +809,7 @@
 	s32 last_temperature;
 
 	/* init calibration results */
-	struct iwl_calib_results calib_results;
+	struct iwl_calib_result calib_results[IWL_CALIB_MAX];
 
 	/* Scan related variables */
 	unsigned long last_scan_jiffies;
@@ -939,9 +891,6 @@
 	u8 last_phy_res[100];
 
 	/* Rate scaling data */
-	struct iwl4965_lq_mngr lq_mngr;
-
-	/* Rate scaling data */
 	s8 data_retry_limit;
 	u8 retry_rate;
 
@@ -1005,7 +954,7 @@
 	u8 *eeprom;
 	struct iwl_eeprom_calib_info *calib_info;
 
-	enum ieee80211_if_types iw_mode;
+	enum nl80211_iftype iw_mode;
 
 	struct sk_buff *ibss_beacon;
 
@@ -1025,7 +974,6 @@
 	 * hardware */
 	u16 assoc_id;
 	u16 assoc_capability;
-	u8 ps_mode;
 
 	struct iwl_qos_info qos_data;
 
@@ -1047,6 +995,7 @@
 
 	struct tasklet_struct irq_tasklet;
 
+	struct delayed_work set_power_save;
 	struct delayed_work init_alive_start;
 	struct delayed_work alive_start;
 	struct delayed_work scan_check;
diff --git a/drivers/net/wireless/iwlwifi/iwl-fh.h b/drivers/net/wireless/iwlwifi/iwl-fh.h
index cd11c0c..a72efdf 100644
--- a/drivers/net/wireless/iwlwifi/iwl-fh.h
+++ b/drivers/net/wireless/iwlwifi/iwl-fh.h
@@ -247,8 +247,8 @@
 #define FH_RCSR_CHNL0_RX_CONFIG_RBDBC_SIZE_MSK (0x00F00000) /* bits 20-23 */
 #define FH_RCSR_CHNL0_RX_CONFIG_DMA_CHNL_EN_MSK (0xC0000000) /* bits 30-31*/
 
-#define FH_RCSR_RX_CONFIG_RBDCB_SIZE_BITSHIFT	(20)
-#define FH_RCSR_RX_CONFIG_REG_IRQ_RBTH_BITSHIFT	(4)
+#define FH_RCSR_RX_CONFIG_RBDCB_SIZE_POS	(20)
+#define FH_RCSR_RX_CONFIG_REG_IRQ_RBTH_POS	(4)
 #define RX_RB_TIMEOUT	(0x10)
 
 #define FH_RCSR_RX_CONFIG_CHNL_EN_PAUSE_VAL         (0x00000000)
@@ -260,8 +260,9 @@
 #define FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_12K   (0x00020000)
 #define FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_16K   (0x00030000)
 
-#define FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_NO_INT_VAL       (0x00000000)
-#define FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_INT_HOST_VAL     (0x00001000)
+#define FH_RCSR_CHNL0_RX_IGNORE_RXF_EMPTY              (0x00000004)
+#define FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_NO_INT_VAL    (0x00000000)
+#define FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_INT_HOST_VAL  (0x00001000)
 
 
 /**
diff --git a/drivers/net/wireless/iwlwifi/iwl-hcmd.c b/drivers/net/wireless/iwlwifi/iwl-hcmd.c
index 2eb03ee..8300f3d 100644
--- a/drivers/net/wireless/iwlwifi/iwl-hcmd.c
+++ b/drivers/net/wireless/iwlwifi/iwl-hcmd.c
@@ -120,8 +120,18 @@
 		return 1;
 	}
 
-	IWL_DEBUG_HC("back from %s (0x%08X)\n",
-			get_cmd_string(cmd->hdr.cmd), pkt->hdr.flags);
+#ifdef CONFIG_IWLWIFI_DEBUG
+	switch (cmd->hdr.cmd) {
+	case REPLY_TX_LINK_QUALITY_CMD:
+	case SENSITIVITY_CMD:
+		IWL_DEBUG_HC_DUMP("back from %s (0x%08X)\n",
+				get_cmd_string(cmd->hdr.cmd), pkt->hdr.flags);
+				break;
+	default:
+		IWL_DEBUG_HC("back from %s (0x%08X)\n",
+				get_cmd_string(cmd->hdr.cmd), pkt->hdr.flags);
+	}
+#endif
 
 	/* Let iwl_tx_complete free the response skb */
 	return 1;
diff --git a/drivers/net/wireless/iwlwifi/iwl-io.h b/drivers/net/wireless/iwlwifi/iwl-io.h
index 5bc3df4..9740fcc 100644
--- a/drivers/net/wireless/iwlwifi/iwl-io.h
+++ b/drivers/net/wireless/iwlwifi/iwl-io.h
@@ -61,7 +61,7 @@
  *
  */
 
-#define _iwl_write32(priv, ofs, val) writel((val), (priv)->hw_base + (ofs))
+#define _iwl_write32(priv, ofs, val) iowrite32((val), (priv)->hw_base + (ofs))
 #ifdef CONFIG_IWLWIFI_DEBUG
 static inline void __iwl_write32(const char *f, u32 l, struct iwl_priv *priv,
 				 u32 ofs, u32 val)
@@ -75,7 +75,7 @@
 #define iwl_write32(priv, ofs, val) _iwl_write32(priv, ofs, val)
 #endif
 
-#define _iwl_read32(priv, ofs) readl((priv)->hw_base + (ofs))
+#define _iwl_read32(priv, ofs) ioread32((priv)->hw_base + (ofs))
 #ifdef CONFIG_IWLWIFI_DEBUG
 static inline u32 __iwl_read32(char *f, u32 l, struct iwl_priv *priv, u32 ofs)
 {
@@ -155,28 +155,10 @@
 static inline int _iwl_grab_nic_access(struct iwl_priv *priv)
 {
 	int ret;
-	u32 gp_ctl;
-
 #ifdef CONFIG_IWLWIFI_DEBUG
 	if (atomic_read(&priv->restrict_refcnt))
 		return 0;
 #endif
-	if (test_bit(STATUS_RF_KILL_HW, &priv->status) ||
-	    test_bit(STATUS_RF_KILL_SW, &priv->status)) {
-		IWL_WARNING("WARNING: Requesting MAC access during RFKILL "
-			"wakes up NIC\n");
-
-		/* 10 msec allows time for NIC to complete its data save */
-		gp_ctl = _iwl_read32(priv, CSR_GP_CNTRL);
-		if (gp_ctl & CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY) {
-			IWL_DEBUG_RF_KILL("Wait for complete power-down, "
-				"gpctl = 0x%08x\n", gp_ctl);
-			mdelay(10);
-		} else
-			IWL_DEBUG_RF_KILL("power-down complete, "
-					  "gpctl = 0x%08x\n", gp_ctl);
-	}
-
 	/* this bit wakes up the NIC */
 	_iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
 	ret = _iwl_poll_bit(priv, CSR_GP_CNTRL,
diff --git a/drivers/net/wireless/iwlwifi/iwl-power.c b/drivers/net/wireless/iwlwifi/iwl-power.c
index a099c9e..60a03d2 100644
--- a/drivers/net/wireless/iwlwifi/iwl-power.c
+++ b/drivers/net/wireless/iwlwifi/iwl-power.c
@@ -152,9 +152,10 @@
 /* initialize to default */
 static int iwl_power_init_handle(struct iwl_priv *priv)
 {
-	int ret = 0, i;
 	struct iwl_power_mgr *pow_data;
 	int size = sizeof(struct iwl_power_vec_entry) * IWL_POWER_MAX;
+	struct iwl_powertable_cmd *cmd;
+	int i;
 	u16 pci_pm;
 
 	IWL_DEBUG_POWER("Initialize power \n");
@@ -167,25 +168,19 @@
 	memcpy(&pow_data->pwr_range_1[0], &range_1[0], size);
 	memcpy(&pow_data->pwr_range_2[0], &range_2[0], size);
 
-	ret = pci_read_config_word(priv->pci_dev,
-				  PCI_LINK_CTRL, &pci_pm);
-	if (ret != 0)
-		return 0;
-	else {
-		struct iwl_powertable_cmd *cmd;
+	pci_read_config_word(priv->pci_dev, PCI_CFG_LINK_CTRL, &pci_pm);
 
-		IWL_DEBUG_POWER("adjust power command flags\n");
+	IWL_DEBUG_POWER("adjust power command flags\n");
 
-		for (i = 0; i < IWL_POWER_MAX; i++) {
-			cmd = &pow_data->pwr_range_0[i].cmd;
+	for (i = 0; i < IWL_POWER_MAX; i++) {
+		cmd = &pow_data->pwr_range_0[i].cmd;
 
-			if (pci_pm & 0x1)
-				cmd->flags &= ~IWL_POWER_PCI_PM_MSK;
-			else
-				cmd->flags |= IWL_POWER_PCI_PM_MSK;
-		}
+		if (pci_pm & PCI_CFG_LINK_CTRL_VAL_L0S_EN)
+			cmd->flags &= ~IWL_POWER_PCI_PM_MSK;
+		else
+			cmd->flags |= IWL_POWER_PCI_PM_MSK;
 	}
-	return ret;
+	return 0;
 }
 
 /* adjust power command according to dtim period and power level*/
@@ -255,17 +250,26 @@
 
 
 /*
- * calucaute the final power mode index
+ * compute the final power mode index
  */
-int iwl_power_update_mode(struct iwl_priv *priv, u8 refresh)
+int iwl_power_update_mode(struct iwl_priv *priv, bool force)
 {
 	struct iwl_power_mgr *setting = &(priv->power_data);
 	int ret = 0;
 	u16 uninitialized_var(final_mode);
 
-       /* If on battery, set to 3,
-	* if plugged into AC power, set to CAM ("continuously aware mode"),
-	* else user level */
+	/* Don't update the RX chain when chain noise calibration is running */
+	if (priv->chain_noise_data.state != IWL_CHAIN_NOISE_DONE &&
+	    priv->chain_noise_data.state != IWL_CHAIN_NOISE_ALIVE) {
+		IWL_DEBUG_POWER("Cannot update the power, chain noise "
+			"calibration running: %d\n",
+			priv->chain_noise_data.state);
+		return -EAGAIN;
+	}
+
+	/* If on battery, set to 3,
+	 * if plugged into AC power, set to CAM ("continuously aware mode"),
+	 * else user level */
 
 	switch (setting->system_power_setting) {
 	case IWL_POWER_SYS_AUTO:
@@ -286,11 +290,11 @@
 		final_mode = setting->critical_power_setting;
 
 	/* driver only support CAM for non STA network */
-	if (priv->iw_mode != IEEE80211_IF_TYPE_STA)
+	if (priv->iw_mode != NL80211_IFTYPE_STATION)
 		final_mode = IWL_POWER_MODE_CAM;
 
 	if (!iwl_is_rfkill(priv) && !setting->power_disabled &&
-	    ((setting->power_mode != final_mode) || refresh)) {
+	    ((setting->power_mode != final_mode) || force)) {
 		struct iwl_powertable_cmd cmd;
 
 		if (final_mode != IWL_POWER_MODE_CAM)
@@ -324,7 +328,7 @@
  * this will be usefull for rate scale to disable PM during heavy
  * Tx/Rx activities
  */
-int iwl_power_disable_management(struct iwl_priv *priv)
+int iwl_power_disable_management(struct iwl_priv *priv, u32 ms)
 {
 	u16 prev_mode;
 	int ret = 0;
@@ -337,6 +341,11 @@
 	ret = iwl_power_update_mode(priv, 0);
 	priv->power_data.power_disabled = 1;
 	priv->power_data.user_power_setting = prev_mode;
+	cancel_delayed_work(&priv->set_power_save);
+	if (ms)
+		queue_delayed_work(priv->workqueue, &priv->set_power_save,
+				   msecs_to_jiffies(ms));
+
 
 	return ret;
 }
@@ -359,35 +368,26 @@
 /* set user_power_setting */
 int iwl_power_set_user_mode(struct iwl_priv *priv, u16 mode)
 {
-	int ret = 0;
-
 	if (mode > IWL_POWER_LIMIT)
 		return -EINVAL;
 
 	priv->power_data.user_power_setting = mode;
 
-	ret = iwl_power_update_mode(priv, 0);
-
-	return ret;
+	return iwl_power_update_mode(priv, 0);
 }
 EXPORT_SYMBOL(iwl_power_set_user_mode);
 
-
 /* set system_power_setting. This should be set by over all
  * PM application.
  */
 int iwl_power_set_system_mode(struct iwl_priv *priv, u16 mode)
 {
-	int ret = 0;
-
 	if (mode > IWL_POWER_LIMIT)
 		return -EINVAL;
 
 	priv->power_data.system_power_setting = mode;
 
-	ret = iwl_power_update_mode(priv, 0);
-
-	return ret;
+	return iwl_power_update_mode(priv, 0);
 }
 EXPORT_SYMBOL(iwl_power_set_system_mode);
 
@@ -431,3 +431,35 @@
 	return ret;
 }
 EXPORT_SYMBOL(iwl_power_temperature_change);
+
+static void iwl_bg_set_power_save(struct work_struct *work)
+{
+	struct iwl_priv *priv = container_of(work,
+				struct iwl_priv, set_power_save.work);
+	IWL_DEBUG(IWL_DL_STATE, "update power\n");
+
+	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+		return;
+
+	mutex_lock(&priv->mutex);
+
+	/* on starting association we disable power managment
+	 * until association, if association failed then this
+	 * timer will expire and enable PM again.
+	 */
+	if (!iwl_is_associated(priv))
+		iwl_power_enable_management(priv);
+
+	mutex_unlock(&priv->mutex);
+}
+void iwl_setup_power_deferred_work(struct iwl_priv *priv)
+{
+	INIT_DELAYED_WORK(&priv->set_power_save, iwl_bg_set_power_save);
+}
+EXPORT_SYMBOL(iwl_setup_power_deferred_work);
+
+void iwl_power_cancel_timeout(struct iwl_priv *priv)
+{
+	cancel_delayed_work(&priv->set_power_save);
+}
+EXPORT_SYMBOL(iwl_power_cancel_timeout);
diff --git a/drivers/net/wireless/iwlwifi/iwl-power.h b/drivers/net/wireless/iwlwifi/iwl-power.h
index abcbbf9..df484a9 100644
--- a/drivers/net/wireless/iwlwifi/iwl-power.h
+++ b/drivers/net/wireless/iwlwifi/iwl-power.h
@@ -72,14 +72,16 @@
 	/* final power level that used to calculate final power command */
 	u8 power_mode;
 	u8 user_power_setting; /* set by user through mac80211 or sysfs */
-	u8 system_power_setting; /* set by kernel syatem tools */
+	u8 system_power_setting; /* set by kernel system tools */
 	u8 critical_power_setting; /* set if driver over heated */
 	u8 is_battery_active; /* DC/AC power */
 	u8 power_disabled; /* flag to disable using power saving level */
 };
 
-int iwl_power_update_mode(struct iwl_priv *priv, u8 refresh);
-int iwl_power_disable_management(struct iwl_priv *priv);
+void iwl_setup_power_deferred_work(struct iwl_priv *priv);
+void iwl_power_cancel_timeout(struct iwl_priv *priv);
+int iwl_power_update_mode(struct iwl_priv *priv, bool force);
+int iwl_power_disable_management(struct iwl_priv *priv, u32 ms);
 int iwl_power_enable_management(struct iwl_priv *priv);
 int iwl_power_set_user_mode(struct iwl_priv *priv, u16 mode);
 int iwl_power_set_system_mode(struct iwl_priv *priv, u16 mode);
diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c
index e81bfc4..7cde9d7 100644
--- a/drivers/net/wireless/iwlwifi/iwl-rx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-rx.c
@@ -376,7 +376,9 @@
 {
 	int ret;
 	unsigned long flags;
-	unsigned int rb_size;
+	u32 rb_size;
+	const u32 rfdnlog = RX_QUEUE_SIZE_LOG; /* 256 RBDs */
+	const u32 rb_timeout = 0; /* FIXME: RX_RB_TIMEOUT why this stalls RX */
 
 	spin_lock_irqsave(&priv->lock, flags);
 	ret = iwl_grab_nic_access(priv);
@@ -398,26 +400,32 @@
 
 	/* Tell device where to find RBD circular buffer in DRAM */
 	iwl_write_direct32(priv, FH_RSCSR_CHNL0_RBDCB_BASE_REG,
-			   rxq->dma_addr >> 8);
+			   (u32)(rxq->dma_addr >> 8));
 
 	/* Tell device where in DRAM to update its Rx status */
 	iwl_write_direct32(priv, FH_RSCSR_CHNL0_STTS_WPTR_REG,
 			   (priv->shared_phys + priv->rb_closed_offset) >> 4);
 
-	/* Enable Rx DMA, enable host interrupt, Rx buffer size 4k, 256 RBDs */
+	/* Enable Rx DMA
+	 * FH_RCSR_CHNL0_RX_IGNORE_RXF_EMPTY is set becuase of HW bug in
+	 *      the credit mechanism in 5000 HW RX FIFO
+	 * Direct rx interrupts to hosts
+	 * Rx buffer size 4 or 8k
+	 * RB timeout 0x10
+	 * 256 RBDs
+	 */
 	iwl_write_direct32(priv, FH_MEM_RCSR_CHNL0_CONFIG_REG,
 			   FH_RCSR_RX_CONFIG_CHNL_EN_ENABLE_VAL |
+			   FH_RCSR_CHNL0_RX_IGNORE_RXF_EMPTY |
 			   FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_INT_HOST_VAL |
-			   rb_size |
-			     /* 0x10 << 4 | */
-			   (RX_QUEUE_SIZE_LOG <<
-			      FH_RCSR_RX_CONFIG_RBDCB_SIZE_BITSHIFT));
-
-	/*
-	 * iwl_write32(priv,CSR_INT_COAL_REG,0);
-	 */
+			   rb_size|
+			   (rb_timeout << FH_RCSR_RX_CONFIG_REG_IRQ_RBTH_POS)|
+			   (rfdnlog << FH_RCSR_RX_CONFIG_RBDCB_SIZE_POS));
 
 	iwl_release_nic_access(priv);
+
+	iwl_write32(priv, CSR_INT_COALESCING, 0x40);
+
 	spin_unlock_irqrestore(&priv->lock, flags);
 
 	return 0;
@@ -789,107 +797,6 @@
 }
 #endif
 
-static void iwl_add_radiotap(struct iwl_priv *priv,
-				 struct sk_buff *skb,
-				 struct iwl_rx_phy_res *rx_start,
-				 struct ieee80211_rx_status *stats,
-				 u32 ampdu_status)
-{
-	s8 signal = stats->signal;
-	s8 noise = 0;
-	int rate = stats->rate_idx;
-	u64 tsf = stats->mactime;
-	__le16 antenna;
-	__le16 phy_flags_hw = rx_start->phy_flags;
-	struct iwl4965_rt_rx_hdr {
-		struct ieee80211_radiotap_header rt_hdr;
-		__le64 rt_tsf;		/* TSF */
-		u8 rt_flags;		/* radiotap packet flags */
-		u8 rt_rate;		/* rate in 500kb/s */
-		__le16 rt_channelMHz;	/* channel in MHz */
-		__le16 rt_chbitmask;	/* channel bitfield */
-		s8 rt_dbmsignal;	/* signal in dBm, kluged to signed */
-		s8 rt_dbmnoise;
-		u8 rt_antenna;		/* antenna number */
-	} __attribute__ ((packed)) *iwl4965_rt;
-
-	/* TODO: We won't have enough headroom for HT frames. Fix it later. */
-	if (skb_headroom(skb) < sizeof(*iwl4965_rt)) {
-		if (net_ratelimit())
-			printk(KERN_ERR "not enough headroom [%d] for "
-			       "radiotap head [%zd]\n",
-			       skb_headroom(skb), sizeof(*iwl4965_rt));
-		return;
-	}
-
-	/* put radiotap header in front of 802.11 header and data */
-	iwl4965_rt = (void *)skb_push(skb, sizeof(*iwl4965_rt));
-
-	/* initialise radiotap header */
-	iwl4965_rt->rt_hdr.it_version = PKTHDR_RADIOTAP_VERSION;
-	iwl4965_rt->rt_hdr.it_pad = 0;
-
-	/* total header + data */
-	put_unaligned_le16(sizeof(*iwl4965_rt), &iwl4965_rt->rt_hdr.it_len);
-
-	/* Indicate all the fields we add to the radiotap header */
-	put_unaligned_le32((1 << IEEE80211_RADIOTAP_TSFT) |
-			   (1 << IEEE80211_RADIOTAP_FLAGS) |
-			   (1 << IEEE80211_RADIOTAP_RATE) |
-			   (1 << IEEE80211_RADIOTAP_CHANNEL) |
-			   (1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL) |
-			   (1 << IEEE80211_RADIOTAP_DBM_ANTNOISE) |
-			   (1 << IEEE80211_RADIOTAP_ANTENNA),
-			   &(iwl4965_rt->rt_hdr.it_present));
-
-	/* Zero the flags, we'll add to them as we go */
-	iwl4965_rt->rt_flags = 0;
-
-	put_unaligned_le64(tsf, &iwl4965_rt->rt_tsf);
-
-	iwl4965_rt->rt_dbmsignal = signal;
-	iwl4965_rt->rt_dbmnoise = noise;
-
-	/* Convert the channel frequency and set the flags */
-	put_unaligned(cpu_to_le16(stats->freq), &iwl4965_rt->rt_channelMHz);
-	if (!(phy_flags_hw & RX_RES_PHY_FLAGS_BAND_24_MSK))
-		put_unaligned_le16(IEEE80211_CHAN_OFDM | IEEE80211_CHAN_5GHZ,
-				   &iwl4965_rt->rt_chbitmask);
-	else if (phy_flags_hw & RX_RES_PHY_FLAGS_MOD_CCK_MSK)
-		put_unaligned_le16(IEEE80211_CHAN_CCK | IEEE80211_CHAN_2GHZ,
-				   &iwl4965_rt->rt_chbitmask);
-	else	/* 802.11g */
-		put_unaligned_le16(IEEE80211_CHAN_OFDM | IEEE80211_CHAN_2GHZ,
-				   &iwl4965_rt->rt_chbitmask);
-
-	if (rate == -1)
-		iwl4965_rt->rt_rate = 0;
-	else
-		iwl4965_rt->rt_rate = iwl_rates[rate].ieee;
-
-	/*
-	 * "antenna number"
-	 *
-	 * It seems that the antenna field in the phy flags value
-	 * is actually a bitfield. This is undefined by radiotap,
-	 * it wants an actual antenna number but I always get "7"
-	 * for most legacy frames I receive indicating that the
-	 * same frame was received on all three RX chains.
-	 *
-	 * I think this field should be removed in favour of a
-	 * new 802.11n radiotap field "RX chains" that is defined
-	 * as a bitmask.
-	 */
-	antenna = phy_flags_hw & RX_RES_PHY_FLAGS_ANTENNA_MSK;
-	iwl4965_rt->rt_antenna = le16_to_cpu(antenna) >> 4;
-
-	/* set the preamble flag if appropriate */
-	if (phy_flags_hw & RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK)
-		iwl4965_rt->rt_flags |= IEEE80211_RADIOTAP_F_SHORTPRE;
-
-	stats->flag |= RX_FLAG_RADIOTAP;
-}
-
 static void iwl_update_rx_stats(struct iwl_priv *priv, u16 fc, u16 len)
 {
 	/* 0 - mgmt, 1 - cnt, 2 - data */
@@ -1074,9 +981,6 @@
 	    iwl_set_decrypted_flag(priv, hdr, ampdu_status, stats))
 		return;
 
-	if (priv->add_radiotap)
-		iwl_add_radiotap(priv, rxb->skb, rx_start, stats, ampdu_status);
-
 	iwl_update_rx_stats(priv, le16_to_cpu(hdr->frame_control), len);
 	ieee80211_rx_irqsafe(priv->hw, rxb->skb, stats);
 	priv->alloc_rxb_skb--;
@@ -1130,10 +1034,10 @@
 	/* Filter incoming packets to determine if they are targeted toward
 	 * this network, discarding packets coming from ourselves */
 	switch (priv->iw_mode) {
-	case IEEE80211_IF_TYPE_IBSS: /* Header: Dest. | Source    | BSSID */
+	case NL80211_IFTYPE_ADHOC: /* Header: Dest. | Source    | BSSID */
 		/* packets to our IBSS update information */
 		return !compare_ether_addr(header->addr3, priv->bssid);
-	case IEEE80211_IF_TYPE_STA: /* Header: Dest. | AP{BSSID} | Source */
+	case NL80211_IFTYPE_STATION: /* Header: Dest. | AP{BSSID} | Source */
 		/* packets to our IBSS update information */
 		return !compare_ether_addr(header->addr2, priv->bssid);
 	default:
@@ -1171,7 +1075,6 @@
 	if (rx_status.band == IEEE80211_BAND_5GHZ)
 		rx_status.rate_idx -= IWL_FIRST_OFDM_RATE;
 
-	rx_status.antenna = 0;
 	rx_status.flag = 0;
 
 	/* TSF isn't reliable. In order to allow smooth user experience,
@@ -1253,8 +1156,28 @@
 		rx_status.signal, rx_status.noise, rx_status.signal,
 		(unsigned long long)rx_status.mactime);
 
+	/*
+	 * "antenna number"
+	 *
+	 * It seems that the antenna field in the phy flags value
+	 * is actually a bitfield. This is undefined by radiotap,
+	 * it wants an actual antenna number but I always get "7"
+	 * for most legacy frames I receive indicating that the
+	 * same frame was received on all three RX chains.
+	 *
+	 * I think this field should be removed in favour of a
+	 * new 802.11n radiotap field "RX chains" that is defined
+	 * as a bitmask.
+	 */
+	rx_status.antenna = le16_to_cpu(rx_start->phy_flags &
+					RX_RES_PHY_FLAGS_ANTENNA_MSK) >> 4;
+
+	/* set the preamble flag if appropriate */
+	if (rx_start->phy_flags & RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK)
+		rx_status.flag |= RX_FLAG_SHORTPRE;
+
 	/* Take shortcut when only in monitor mode */
-	if (priv->iw_mode == IEEE80211_IF_TYPE_MNTR) {
+	if (priv->iw_mode == NL80211_IFTYPE_MONITOR) {
 		iwl_pass_packet_to_mac80211(priv, include_phy,
 						 rxb, &rx_status);
 		return;
@@ -1271,7 +1194,7 @@
 	switch (fc & IEEE80211_FCTL_FTYPE) {
 	case IEEE80211_FTYPE_MGMT:
 	case IEEE80211_FTYPE_DATA:
-		if (priv->iw_mode == IEEE80211_IF_TYPE_AP)
+		if (priv->iw_mode == NL80211_IFTYPE_AP)
 			iwl_update_ps_mode(priv, fc  & IEEE80211_FCTL_PM,
 						header->addr2);
 		/* fall through */
diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c
index 6c8ac3a..3b0bee3 100644
--- a/drivers/net/wireless/iwlwifi/iwl-scan.c
+++ b/drivers/net/wireless/iwlwifi/iwl-scan.c
@@ -88,7 +88,7 @@
 
 
 
-const char *iwl_escape_essid(const char *essid, u8 essid_len)
+static const char *iwl_escape_essid(const char *essid, u8 essid_len)
 {
 	static char escaped[IW_ESSID_MAX_SIZE * 2 + 1];
 	const char *s = essid;
@@ -111,7 +111,6 @@
 	*d = '\0';
 	return escaped;
 }
-EXPORT_SYMBOL(iwl_escape_essid);
 
 /**
  * iwl_scan_cancel - Cancel any currently executing HW scan
@@ -464,11 +463,6 @@
 
 int iwl_scan_initiate(struct iwl_priv *priv)
 {
-	if (priv->iw_mode == IEEE80211_IF_TYPE_AP) {
-		IWL_ERROR("APs don't scan.\n");
-		return 0;
-	}
-
 	if (!iwl_is_ready_rf(priv)) {
 		IWL_DEBUG_SCAN("Aborting scan due to not ready.\n");
 		return -EIO;
@@ -480,8 +474,7 @@
 	}
 
 	if (test_bit(STATUS_SCAN_ABORTING, &priv->status)) {
-		IWL_DEBUG_SCAN("Scan request while abort pending.  "
-			       "Queuing.\n");
+		IWL_DEBUG_SCAN("Scan request while abort pending\n");
 		return -EAGAIN;
 	}
 
@@ -710,7 +703,7 @@
 	u16 cmd_len;
 	enum ieee80211_band band;
 	u8 n_probes = 2;
-	u8 rx_chain = 0x7; /* bitmap: ABC chains */
+	u8 rx_chain = priv->hw_params.valid_rx_ant;
 
 	conf = ieee80211_get_hw_conf(priv->hw);
 
@@ -850,7 +843,7 @@
 
 		/* Force use of chains B and C (0x6) for scan Rx for 4965
 		 * Avoid A (0x1) because of its off-channel reception on A-band.
-		 * MIMO is not used here, but value is required */
+		 */
 		if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_4965)
 			rx_chain = 0x6;
 	} else {
@@ -858,6 +851,7 @@
 		goto done;
 	}
 
+	/* MIMO is not used here, but value is required */
 	scan->rx_chain = RXON_RX_CHAIN_DRIVER_FORCE_MSK |
 				cpu_to_le16((0x7 << RXON_RX_CHAIN_VALID_POS) |
 				(rx_chain << RXON_RX_CHAIN_FORCE_SEL_POS) |
@@ -869,7 +863,7 @@
 
 	scan->tx_cmd.len = cpu_to_le16(cmd_len);
 
-	if (priv->iw_mode == IEEE80211_IF_TYPE_MNTR)
+	if (priv->iw_mode == NL80211_IFTYPE_MONITOR)
 		scan->filter_flags = RXON_FILTER_PROMISC_MSK;
 
 	scan->filter_flags |= (RXON_FILTER_ACCEPT_GRP_MSK |
@@ -922,10 +916,29 @@
 	mutex_unlock(&priv->mutex);
 }
 
+static void iwl_bg_scan_completed(struct work_struct *work)
+{
+	struct iwl_priv *priv =
+	    container_of(work, struct iwl_priv, scan_completed);
+
+	IWL_DEBUG_SCAN("SCAN complete scan\n");
+
+	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+		return;
+
+	ieee80211_scan_completed(priv->hw);
+
+	/* Since setting the TXPOWER may have been deferred while
+	 * performing the scan, fire one off */
+	mutex_lock(&priv->mutex);
+	iwl_set_tx_power(priv, priv->tx_power_user_lmt, true);
+	mutex_unlock(&priv->mutex);
+}
+
+
 void iwl_setup_scan_deferred_work(struct iwl_priv *priv)
 {
-	/*  FIXME: move here when resolved PENDING
-	 *  INIT_WORK(&priv->scan_completed, iwl_bg_scan_completed); */
+	INIT_WORK(&priv->scan_completed, iwl_bg_scan_completed);
 	INIT_WORK(&priv->request_scan, iwl_bg_request_scan);
 	INIT_WORK(&priv->abort_scan, iwl_bg_abort_scan);
 	INIT_DELAYED_WORK(&priv->scan_check, iwl_bg_scan_check);
diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c
index 6283a3a..61797f3 100644
--- a/drivers/net/wireless/iwlwifi/iwl-sta.c
+++ b/drivers/net/wireless/iwlwifi/iwl-sta.c
@@ -47,8 +47,8 @@
 	unsigned long flags;
 	DECLARE_MAC_BUF(mac);
 
-	if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) ||
-	    (priv->iw_mode == IEEE80211_IF_TYPE_AP))
+	if ((priv->iw_mode == NL80211_IFTYPE_ADHOC) ||
+	    (priv->iw_mode == NL80211_IFTYPE_AP))
 		start = IWL_STA_ID;
 
 	if (is_broadcast_ether_addr(addr))
@@ -74,7 +74,7 @@
 
 int iwl_get_ra_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr)
 {
-	if (priv->iw_mode == IEEE80211_IF_TYPE_STA) {
+	if (priv->iw_mode == NL80211_IFTYPE_STATION) {
 		return IWL_AP_ID;
 	} else {
 		u8 *da = ieee80211_get_DA(hdr);
@@ -191,20 +191,20 @@
 	if (!sta_ht_inf || !sta_ht_inf->ht_supported)
 		goto done;
 
-	mimo_ps_mode = (sta_ht_inf->cap & IEEE80211_HT_CAP_MIMO_PS) >> 2;
+	mimo_ps_mode = (sta_ht_inf->cap & IEEE80211_HT_CAP_SM_PS) >> 2;
 
 	sta_flags = priv->stations[index].sta.station_flags;
 
 	sta_flags &= ~(STA_FLG_RTS_MIMO_PROT_MSK | STA_FLG_MIMO_DIS_MSK);
 
 	switch (mimo_ps_mode) {
-	case WLAN_HT_CAP_MIMO_PS_STATIC:
+	case WLAN_HT_CAP_SM_PS_STATIC:
 		sta_flags |= STA_FLG_MIMO_DIS_MSK;
 		break;
-	case WLAN_HT_CAP_MIMO_PS_DYNAMIC:
+	case WLAN_HT_CAP_SM_PS_DYNAMIC:
 		sta_flags |= STA_FLG_RTS_MIMO_PROT_MSK;
 		break;
-	case WLAN_HT_CAP_MIMO_PS_DISABLED:
+	case WLAN_HT_CAP_SM_PS_DISABLED:
 		break;
 	default:
 		IWL_WARNING("Invalid MIMO PS mode %d\n", mimo_ps_mode);
@@ -286,7 +286,7 @@
 
 	/* BCAST station and IBSS stations do not work in HT mode */
 	if (sta_id != priv->hw_params.bcast_sta_id &&
-	    priv->iw_mode != IEEE80211_IF_TYPE_IBSS)
+	    priv->iw_mode != NL80211_IFTYPE_ADHOC)
 		iwl_set_ht_add_station(priv, sta_id, ht_info);
 
 	spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
@@ -817,7 +817,7 @@
 	};
 
 	if ((lq->sta_id == 0xFF) &&
-	    (priv->iw_mode == IEEE80211_IF_TYPE_IBSS))
+	    (priv->iw_mode == NL80211_IFTYPE_ADHOC))
 		return -EINVAL;
 
 	if (lq->sta_id == 0xFF)
@@ -904,7 +904,7 @@
 
 	if ((is_ap) &&
 	    (conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) &&
-	    (priv->iw_mode == IEEE80211_IF_TYPE_STA))
+	    (priv->iw_mode == NL80211_IFTYPE_STATION))
 		sta_id = iwl_add_station_flags(priv, addr, is_ap,
 						   0, cur_ht_config);
 	else
@@ -938,11 +938,11 @@
 
 	/* If we are a client station in a BSS network, use the special
 	 * AP station entry (that's the only station we communicate with) */
-	case IEEE80211_IF_TYPE_STA:
+	case NL80211_IFTYPE_STATION:
 		return IWL_AP_ID;
 
 	/* If we are an AP, then find the station, or use BCAST */
-	case IEEE80211_IF_TYPE_AP:
+	case NL80211_IFTYPE_AP:
 		sta_id = iwl_find_station(priv, hdr->addr1);
 		if (sta_id != IWL_INVALID_STATION)
 			return sta_id;
@@ -950,7 +950,7 @@
 
 	/* If this frame is going out to an IBSS network, find the station,
 	 * or create a new station table entry */
-	case IEEE80211_IF_TYPE_IBSS:
+	case NL80211_IFTYPE_ADHOC:
 		sta_id = iwl_find_station(priv, hdr->addr1);
 		if (sta_id != IWL_INVALID_STATION)
 			return sta_id;
@@ -968,6 +968,11 @@
 		iwl_print_hex_dump(priv, IWL_DL_DROP, (u8 *) hdr, sizeof(*hdr));
 		return priv->hw_params.bcast_sta_id;
 
+	/* If we are in monitor mode, use BCAST. This is required for
+	 * packet injection. */
+	case NL80211_IFTYPE_MONITOR:
+		return priv->hw_params.bcast_sta_id;
+
 	default:
 		IWL_WARNING("Unknown mode of operation: %d\n", priv->iw_mode);
 		return priv->hw_params.bcast_sta_id;
diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c
index 78b1a7a..907a53e 100644
--- a/drivers/net/wireless/iwlwifi/iwl-tx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-tx.c
@@ -63,7 +63,7 @@
  * Does NOT advance any TFD circular buffer read/write indexes
  * Does NOT free the TFD itself (which is within circular buffer)
  */
-int iwl_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq)
+static int iwl_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq)
 {
 	struct iwl_tfd_frame *bd_tmp = (struct iwl_tfd_frame *)&txq->bd[0];
 	struct iwl_tfd_frame *bd = &bd_tmp[txq->q.read_ptr];
@@ -115,10 +115,8 @@
 	}
 	return 0;
 }
-EXPORT_SYMBOL(iwl_hw_txq_free_tfd);
 
-
-int iwl_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv, void *ptr,
+static int iwl_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv, void *ptr,
 				 dma_addr_t addr, u16 len)
 {
 	int index, is_odd;
@@ -126,7 +124,7 @@
 	u32 num_tbs = IWL_GET_BITS(*tfd, num_tbs);
 
 	/* Each TFD can point to a maximum 20 Tx buffers */
-	if ((num_tbs >= MAX_NUM_OF_TBS) || (num_tbs < 0)) {
+	if (num_tbs >= MAX_NUM_OF_TBS) {
 		IWL_ERROR("Error can not send more than %d chunks\n",
 			  MAX_NUM_OF_TBS);
 		return -EINVAL;
@@ -151,7 +149,6 @@
 
 	return 0;
 }
-EXPORT_SYMBOL(iwl_hw_txq_attach_buf_to_tfd);
 
 /**
  * iwl_txq_update_write_ptr - Send new write index to hardware
@@ -478,7 +475,6 @@
 }
 EXPORT_SYMBOL(iwl_hw_txq_ctx_free);
 
-
 /**
  * iwl_txq_ctx_reset - Reset TX queue context
  * Destroys all DMA structures and initialise them again
@@ -545,6 +541,7 @@
  error_kw:
 	return ret;
 }
+
 /**
  * iwl_txq_ctx_stop - Stop all Tx DMA channels, free Tx queue memory
  */
@@ -796,11 +793,6 @@
 		goto drop_unlock;
 	}
 
-	if (!priv->vif) {
-		IWL_DEBUG_DROP("Dropping - !priv->vif\n");
-		goto drop_unlock;
-	}
-
 	if ((ieee80211_get_tx_rate(priv->hw, info)->hw_value & 0xFF) ==
 	     IWL_INVALID_RATE) {
 		IWL_ERROR("ERROR: No TX rate available.\n");
@@ -822,16 +814,18 @@
 
 	/* drop all data frame if we are not associated */
 	if (ieee80211_is_data(fc) &&
-	   (!iwl_is_associated(priv) ||
-	    ((priv->iw_mode == IEEE80211_IF_TYPE_STA) && !priv->assoc_id) ||
-	    !priv->assoc_station_added)) {
+	    (priv->iw_mode != NL80211_IFTYPE_MONITOR ||
+	    !(info->flags & IEEE80211_TX_CTL_INJECTED)) && /* packet injection */
+	    (!iwl_is_associated(priv) ||
+	     ((priv->iw_mode == NL80211_IFTYPE_STATION) && !priv->assoc_id) ||
+	     !priv->assoc_station_added)) {
 		IWL_DEBUG_DROP("Dropping - !iwl_is_associated\n");
 		goto drop_unlock;
 	}
 
 	spin_unlock_irqrestore(&priv->lock, flags);
 
-	hdr_len = ieee80211_get_hdrlen(le16_to_cpu(fc));
+	hdr_len = ieee80211_hdrlen(fc);
 
 	/* Find (or create) index into station table for destination station */
 	sta_id = iwl_get_sta_id(priv, hdr);
@@ -849,7 +843,7 @@
 	txq_id = swq_id;
 	if (ieee80211_is_data_qos(fc)) {
 		qc = ieee80211_get_qos_ctl(hdr);
-		tid = qc[0] & 0xf;
+		tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK;
 		seq_number = priv->stations[sta_id].tid[tid].seq_number;
 		seq_number &= IEEE80211_SCTL_SEQ;
 		hdr->seq_ctrl = hdr->seq_ctrl &
@@ -1064,7 +1058,7 @@
 	out_cmd->hdr.sequence = cpu_to_le16(QUEUE_TO_SEQ(IWL_CMD_QUEUE_NUM) |
 			INDEX_TO_SEQ(q->write_ptr));
 	if (out_cmd->meta.flags & CMD_SIZE_HUGE)
-		out_cmd->hdr.sequence |= cpu_to_le16(SEQ_HUGE_FRAME);
+		out_cmd->hdr.sequence |= SEQ_HUGE_FRAME;
 	len = (idx == TFD_CMD_SLOTS) ?
 			IWL_MAX_SCAN_SIZE : sizeof(struct iwl_cmd);
 	phys_addr = pci_map_single(priv->pci_dev, out_cmd, len,
@@ -1072,12 +1066,26 @@
 	phys_addr += offsetof(struct iwl_cmd, hdr);
 	iwl_hw_txq_attach_buf_to_tfd(priv, tfd, phys_addr, fix_size);
 
-	IWL_DEBUG_HC("Sending command %s (#%x), seq: 0x%04X, "
-		     "%d bytes at %d[%d]:%d\n",
-		     get_cmd_string(out_cmd->hdr.cmd),
-		     out_cmd->hdr.cmd, le16_to_cpu(out_cmd->hdr.sequence),
-		     fix_size, q->write_ptr, idx, IWL_CMD_QUEUE_NUM);
-
+#ifdef CONFIG_IWLWIFI_DEBUG
+	switch (out_cmd->hdr.cmd) {
+	case REPLY_TX_LINK_QUALITY_CMD:
+	case SENSITIVITY_CMD:
+		IWL_DEBUG_HC_DUMP("Sending command %s (#%x), seq: 0x%04X, "
+				"%d bytes at %d[%d]:%d\n",
+				get_cmd_string(out_cmd->hdr.cmd),
+				out_cmd->hdr.cmd,
+				le16_to_cpu(out_cmd->hdr.sequence), fix_size,
+				q->write_ptr, idx, IWL_CMD_QUEUE_NUM);
+				break;
+	default:
+		IWL_DEBUG_HC("Sending command %s (#%x), seq: 0x%04X, "
+				"%d bytes at %d[%d]:%d\n",
+				get_cmd_string(out_cmd->hdr.cmd),
+				out_cmd->hdr.cmd,
+				le16_to_cpu(out_cmd->hdr.sequence), fix_size,
+				q->write_ptr, idx, IWL_CMD_QUEUE_NUM);
+	}
+#endif
 	txq->need_update = 1;
 
 	/* Set up entry in queue's byte count circular buffer */
@@ -1185,17 +1193,16 @@
 	u16 sequence = le16_to_cpu(pkt->hdr.sequence);
 	int txq_id = SEQ_TO_QUEUE(sequence);
 	int index = SEQ_TO_INDEX(sequence);
-	int huge = sequence & SEQ_HUGE_FRAME;
 	int cmd_index;
+	bool huge = !!(pkt->hdr.sequence & SEQ_HUGE_FRAME);
 	struct iwl_cmd *cmd;
 
 	/* If a Tx command is being handled and it isn't in the actual
 	 * command queue then there a command routing bug has been introduced
 	 * in the queue management code. */
-	if (txq_id != IWL_CMD_QUEUE_NUM)
-		IWL_ERROR("Error wrong command queue %d command id 0x%X\n",
-			  txq_id, pkt->hdr.cmd);
-	BUG_ON(txq_id != IWL_CMD_QUEUE_NUM);
+	if (WARN(txq_id != IWL_CMD_QUEUE_NUM,
+		 "wrong command queue %d, command id 0x%X\n", txq_id, pkt->hdr.cmd))
+		return;
 
 	cmd_index = get_cmd_index(&priv->txq[IWL_CMD_QUEUE_NUM].q, index, huge);
 	cmd = priv->txq[IWL_CMD_QUEUE_NUM].cmd[cmd_index];
diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c
index b775d5b..d15a2c9 100644
--- a/drivers/net/wireless/iwlwifi/iwl3945-base.c
+++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c
@@ -1160,7 +1160,7 @@
 	/* If we have set the ASSOC_MSK and we are in BSS mode then
 	 * add the IWL_AP_ID to the station rate table */
 	if (iwl3945_is_associated(priv) &&
-	    (priv->iw_mode == IEEE80211_IF_TYPE_STA))
+	    (priv->iw_mode == NL80211_IFTYPE_STATION))
 		if (iwl3945_add_station(priv, priv->active_rxon.bssid_addr, 1, 0)
 		    == IWL_INVALID_STATION) {
 			IWL_ERROR("Error adding AP address for transmit.\n");
@@ -1447,8 +1447,8 @@
 {
 
 	if (!iwl3945_is_associated(priv) || !priv->ibss_beacon ||
-	    ((priv->iw_mode != IEEE80211_IF_TYPE_IBSS) &&
-	     (priv->iw_mode != IEEE80211_IF_TYPE_AP)))
+	    ((priv->iw_mode != NL80211_IFTYPE_ADHOC) &&
+	     (priv->iw_mode != NL80211_IFTYPE_AP)))
 		return 0;
 
 	if (priv->ibss_beacon->len > left)
@@ -1746,14 +1746,14 @@
 	spin_lock_irqsave(&priv->lock, flags);
 	priv->qos_data.qos_active = 0;
 
-	if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS) {
+	if (priv->iw_mode == NL80211_IFTYPE_ADHOC) {
 		if (priv->qos_data.qos_enable)
 			priv->qos_data.qos_active = 1;
 		if (!(priv->active_rate & 0xfff0)) {
 			cw_min = 31;
 			is_legacy = 1;
 		}
-	} else if (priv->iw_mode == IEEE80211_IF_TYPE_AP) {
+	} else if (priv->iw_mode == NL80211_IFTYPE_AP) {
 		if (priv->qos_data.qos_enable)
 			priv->qos_data.qos_active = 1;
 	} else if (!(priv->staging_rxon.flags & RXON_FLG_SHORT_SLOT_MSK)) {
@@ -2120,7 +2120,7 @@
 	beacon_int = priv->beacon_int;
 	spin_unlock_irqrestore(&priv->lock, flags);
 
-	if (priv->iw_mode == IEEE80211_IF_TYPE_STA) {
+	if (priv->iw_mode == NL80211_IFTYPE_STATION) {
 		if (beacon_int == 0) {
 			priv->rxon_timing.beacon_interval = cpu_to_le16(100);
 			priv->rxon_timing.beacon_init_val = cpu_to_le32(102400);
@@ -2156,7 +2156,7 @@
 
 static int iwl3945_scan_initiate(struct iwl3945_priv *priv)
 {
-	if (priv->iw_mode == IEEE80211_IF_TYPE_AP) {
+	if (priv->iw_mode == NL80211_IFTYPE_AP) {
 		IWL_ERROR("APs don't scan.\n");
 		return 0;
 	}
@@ -2218,7 +2218,7 @@
 		else
 			priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK;
 
-		if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS)
+		if (priv->iw_mode == NL80211_IFTYPE_ADHOC)
 			priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK;
 
 		priv->staging_rxon.flags |= RXON_FLG_BAND_24G_MSK;
@@ -2237,23 +2237,23 @@
 	memset(&priv->staging_rxon, 0, sizeof(priv->staging_rxon));
 
 	switch (priv->iw_mode) {
-	case IEEE80211_IF_TYPE_AP:
+	case NL80211_IFTYPE_AP:
 		priv->staging_rxon.dev_type = RXON_DEV_TYPE_AP;
 		break;
 
-	case IEEE80211_IF_TYPE_STA:
+	case NL80211_IFTYPE_STATION:
 		priv->staging_rxon.dev_type = RXON_DEV_TYPE_ESS;
 		priv->staging_rxon.filter_flags = RXON_FILTER_ACCEPT_GRP_MSK;
 		break;
 
-	case IEEE80211_IF_TYPE_IBSS:
+	case NL80211_IFTYPE_ADHOC:
 		priv->staging_rxon.dev_type = RXON_DEV_TYPE_IBSS;
 		priv->staging_rxon.flags = RXON_FLG_SHORT_PREAMBLE_MSK;
 		priv->staging_rxon.filter_flags = RXON_FILTER_BCON_AWARE_MSK |
 						  RXON_FILTER_ACCEPT_GRP_MSK;
 		break;
 
-	case IEEE80211_IF_TYPE_MNTR:
+	case NL80211_IFTYPE_MONITOR:
 		priv->staging_rxon.dev_type = RXON_DEV_TYPE_SNIFFER;
 		priv->staging_rxon.filter_flags = RXON_FILTER_PROMISC_MSK |
 		    RXON_FILTER_CTL2HOST_MSK | RXON_FILTER_ACCEPT_GRP_MSK;
@@ -2282,7 +2282,7 @@
 	 * in some case A channels are all non IBSS
 	 * in this case force B/G channel
 	 */
-	if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) &&
+	if ((priv->iw_mode == NL80211_IFTYPE_ADHOC) &&
 	    !(is_channel_ibss(ch_info)))
 		ch_info = &priv->channel_info[0];
 
@@ -2302,7 +2302,7 @@
 
 static int iwl3945_set_mode(struct iwl3945_priv *priv, int mode)
 {
-	if (mode == IEEE80211_IF_TYPE_IBSS) {
+	if (mode == NL80211_IFTYPE_ADHOC) {
 		const struct iwl3945_channel_info *ch_info;
 
 		ch_info = iwl3945_get_channel_info(priv,
@@ -2469,11 +2469,11 @@
 
 	/* If we are a client station in a BSS network, use the special
 	 * AP station entry (that's the only station we communicate with) */
-	case IEEE80211_IF_TYPE_STA:
+	case NL80211_IFTYPE_STATION:
 		return IWL_AP_ID;
 
 	/* If we are an AP, then find the station, or use BCAST */
-	case IEEE80211_IF_TYPE_AP:
+	case NL80211_IFTYPE_AP:
 		sta_id = iwl3945_hw_find_station(priv, hdr->addr1);
 		if (sta_id != IWL_INVALID_STATION)
 			return sta_id;
@@ -2481,7 +2481,7 @@
 
 	/* If this frame is going out to an IBSS network, find the station,
 	 * or create a new station table entry */
-	case IEEE80211_IF_TYPE_IBSS: {
+	case NL80211_IFTYPE_ADHOC: {
 		DECLARE_MAC_BUF(mac);
 
 		/* Create new station table entry */
@@ -2502,7 +2502,7 @@
 	}
 	/* If we are in monitor mode, use BCAST. This is required for
 	 * packet injection. */
-	case IEEE80211_IF_TYPE_MNTR:
+	case NL80211_IFTYPE_MONITOR:
 		return priv->hw_setting.bcast_sta_id;
 
 	default:
@@ -2565,16 +2565,16 @@
 
 	/* drop all data frame if we are not associated */
 	if (ieee80211_is_data(fc) &&
-	    (priv->iw_mode != IEEE80211_IF_TYPE_MNTR) && /* packet injection */
+	    (priv->iw_mode != NL80211_IFTYPE_MONITOR) && /* packet injection */
 	    (!iwl3945_is_associated(priv) ||
-	     ((priv->iw_mode == IEEE80211_IF_TYPE_STA) && !priv->assoc_id))) {
+	     ((priv->iw_mode == NL80211_IFTYPE_STATION) && !priv->assoc_id))) {
 		IWL_DEBUG_DROP("Dropping - !iwl3945_is_associated\n");
 		goto drop_unlock;
 	}
 
 	spin_unlock_irqrestore(&priv->lock, flags);
 
-	hdr_len = ieee80211_get_hdrlen(le16_to_cpu(fc));
+	hdr_len = ieee80211_hdrlen(fc);
 
 	/* Find (or create) index into station table for destination station */
 	sta_id = iwl3945_get_sta_id(priv, hdr);
@@ -2590,7 +2590,7 @@
 
 	if (ieee80211_is_data_qos(fc)) {
 		qc = ieee80211_get_qos_ctl(hdr);
-		tid = qc[0] & 0xf;
+		tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK;
 		seq_number = priv->stations[sta_id].tid[tid].seq_number &
 				IEEE80211_SCTL_SEQ;
 		hdr->seq_ctrl = cpu_to_le16(seq_number) |
@@ -2709,7 +2709,7 @@
 			   sizeof(out_cmd->cmd.tx));
 
 	iwl3945_print_hex_dump(IWL_DL_TX, (u8 *)out_cmd->cmd.tx.hdr,
-			   ieee80211_get_hdrlen(le16_to_cpu(fc)));
+			   ieee80211_hdrlen(fc));
 
 	/* Tell device the write index *just past* this latest filled TFD */
 	q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd);
@@ -2806,7 +2806,7 @@
 	if (disable_radio) {
 		iwl3945_scan_cancel(priv);
 		/* FIXME: This is a workaround for AP */
-		if (priv->iw_mode != IEEE80211_IF_TYPE_AP) {
+		if (priv->iw_mode != NL80211_IFTYPE_AP) {
 			spin_lock_irqsave(&priv->lock, flags);
 			iwl3945_write32(priv, CSR_UCODE_DRV_GP1_SET,
 				    CSR_UCODE_SW_BIT_RFKILL);
@@ -3161,7 +3161,7 @@
 		le32_to_cpu(beacon->low_tsf), rate);
 #endif
 
-	if ((priv->iw_mode == IEEE80211_IF_TYPE_AP) &&
+	if ((priv->iw_mode == NL80211_IFTYPE_AP) &&
 	    (!test_bit(STATUS_EXIT_PENDING, &priv->status)))
 		queue_work(priv->workqueue, &priv->beacon_update);
 }
@@ -4782,8 +4782,11 @@
 /* For active scan, listen ACTIVE_DWELL_TIME (msec) on each channel after
  * sending probe req.  This should be set long enough to hear probe responses
  * from more than one AP.  */
-#define IWL_ACTIVE_DWELL_TIME_24    (20)	/* all times in msec */
-#define IWL_ACTIVE_DWELL_TIME_52    (10)
+#define IWL_ACTIVE_DWELL_TIME_24    (30)	/* all times in msec */
+#define IWL_ACTIVE_DWELL_TIME_52    (20)
+
+#define IWL_ACTIVE_DWELL_FACTOR_24GHZ (3)
+#define IWL_ACTIVE_DWELL_FACTOR_52GHZ (2)
 
 /* For faster active scanning, scan will move to the next channel if fewer than
  * PLCP_QUIET_THRESH packets are heard on this channel within
@@ -4792,7 +4795,7 @@
  * no other traffic).
  * Disable "quiet" feature by setting PLCP_QUIET_THRESH to 0. */
 #define IWL_PLCP_QUIET_THRESH       __constant_cpu_to_le16(1)	/* packets */
-#define IWL_ACTIVE_QUIET_TIME       __constant_cpu_to_le16(5)	/* msec */
+#define IWL_ACTIVE_QUIET_TIME       __constant_cpu_to_le16(10)	/* msec */
 
 /* For passive scan, listen PASSIVE_DWELL_TIME (msec) on each channel.
  * Must be set longer than active dwell time.
@@ -4802,19 +4805,23 @@
 #define IWL_PASSIVE_DWELL_BASE      (100)
 #define IWL_CHANNEL_TUNE_TIME       5
 
+#define IWL_SCAN_PROBE_MASK(n)	 cpu_to_le32((BIT(n) | (BIT(n) - BIT(1))))
+
 static inline u16 iwl3945_get_active_dwell_time(struct iwl3945_priv *priv,
-						enum ieee80211_band band)
+						enum ieee80211_band band,
+						u8 n_probes)
 {
 	if (band == IEEE80211_BAND_5GHZ)
-		return IWL_ACTIVE_DWELL_TIME_52;
+		return IWL_ACTIVE_DWELL_TIME_52 +
+			IWL_ACTIVE_DWELL_FACTOR_52GHZ * (n_probes + 1);
 	else
-		return IWL_ACTIVE_DWELL_TIME_24;
+		return IWL_ACTIVE_DWELL_TIME_24 +
+			IWL_ACTIVE_DWELL_FACTOR_24GHZ * (n_probes + 1);
 }
 
 static u16 iwl3945_get_passive_dwell_time(struct iwl3945_priv *priv,
 					  enum ieee80211_band band)
 {
-	u16 active = iwl3945_get_active_dwell_time(priv, band);
 	u16 passive = (band == IEEE80211_BAND_2GHZ) ?
 	    IWL_PASSIVE_DWELL_BASE + IWL_PASSIVE_DWELL_TIME_24 :
 	    IWL_PASSIVE_DWELL_BASE + IWL_PASSIVE_DWELL_TIME_52;
@@ -4829,15 +4836,12 @@
 		passive = (passive * 98) / 100 - IWL_CHANNEL_TUNE_TIME * 2;
 	}
 
-	if (passive <= active)
-		passive = active + 1;
-
 	return passive;
 }
 
 static int iwl3945_get_channels_for_scan(struct iwl3945_priv *priv,
 					 enum ieee80211_band band,
-				     u8 is_active, u8 direct_mask,
+				     u8 is_active, u8 n_probes,
 				     struct iwl3945_scan_channel *scan_ch)
 {
 	const struct ieee80211_channel *channels = NULL;
@@ -4853,9 +4857,12 @@
 
 	channels = sband->channels;
 
-	active_dwell = iwl3945_get_active_dwell_time(priv, band);
+	active_dwell = iwl3945_get_active_dwell_time(priv, band, n_probes);
 	passive_dwell = iwl3945_get_passive_dwell_time(priv, band);
 
+	if (passive_dwell <= active_dwell)
+		passive_dwell = active_dwell + 1;
+
 	for (i = 0, added = 0; i < sband->n_channels; i++) {
 		if (channels[i].flags & IEEE80211_CHAN_DISABLED)
 			continue;
@@ -4875,8 +4882,8 @@
 		else
 			scan_ch->type = 1;	/* active */
 
-		if (scan_ch->type & 1)
-			scan_ch->type |= (direct_mask << 1);
+		if ((scan_ch->type & 1) && n_probes)
+			scan_ch->type |= IWL_SCAN_PROBE_MASK(n_probes);
 
 		scan_ch->active_dwell = cpu_to_le16(active_dwell);
 		scan_ch->passive_dwell = cpu_to_le16(passive_dwell);
@@ -6052,7 +6059,7 @@
 	if (!iwl3945_is_ready(priv))
 		IWL_DEBUG(IWL_DL_STATE, "leave - not ready\n");
 	else
-		if (iwl3945_set_mode(priv, IEEE80211_IF_TYPE_MNTR) != 0)
+		if (iwl3945_set_mode(priv, NL80211_IFTYPE_MONITOR) != 0)
 			IWL_ERROR("iwl3945_set_mode() failed\n");
 
 	mutex_unlock(&priv->mutex);
@@ -6093,7 +6100,7 @@
 	int rc = 0;
 	struct iwl3945_scan_cmd *scan;
 	struct ieee80211_conf *conf = NULL;
-	u8 direct_mask;
+	u8 n_probes = 2;
 	enum ieee80211_band band;
 
 	conf = ieee80211_get_hw_conf(priv->hw);
@@ -6201,7 +6208,7 @@
 		scan->direct_scan[0].len = priv->direct_ssid_len;
 		memcpy(scan->direct_scan[0].ssid,
 		       priv->direct_ssid, priv->direct_ssid_len);
-		direct_mask = 1;
+		n_probes++;
 	} else if (!iwl3945_is_associated(priv) && priv->essid_len) {
 		IWL_DEBUG_SCAN
 		  ("Kicking off one direct scan for '%s' when not associated\n",
@@ -6209,11 +6216,9 @@
 		scan->direct_scan[0].id = WLAN_EID_SSID;
 		scan->direct_scan[0].len = priv->essid_len;
 		memcpy(scan->direct_scan[0].ssid, priv->essid, priv->essid_len);
-		direct_mask = 1;
-	} else {
+		n_probes++;
+	} else
 		IWL_DEBUG_SCAN("Kicking off one indirect scan.\n");
-		direct_mask = 0;
-	}
 
 	/* We don't build a direct scan probe request; the uCode will do
 	 * that based on the direct_mask added to each channel entry */
@@ -6243,21 +6248,13 @@
 	/* select Rx antennas */
 	scan->flags |= iwl3945_get_antenna_flags(priv);
 
-	if (priv->iw_mode == IEEE80211_IF_TYPE_MNTR)
+	if (priv->iw_mode == NL80211_IFTYPE_MONITOR)
 		scan->filter_flags = RXON_FILTER_PROMISC_MSK;
 
-	if (direct_mask)
-		scan->channel_count =
-			iwl3945_get_channels_for_scan(
-				priv, band, 1, /* active */
-				direct_mask,
-				(void *)&scan->data[le16_to_cpu(scan->tx_cmd.len)]);
-	else
-		scan->channel_count =
-			iwl3945_get_channels_for_scan(
-				priv, band, 0, /* passive */
-				direct_mask,
-				(void *)&scan->data[le16_to_cpu(scan->tx_cmd.len)]);
+	scan->channel_count =
+		iwl3945_get_channels_for_scan(priv, band, 1, /* active */
+					      n_probes,
+			(void *)&scan->data[le16_to_cpu(scan->tx_cmd.len)]);
 
 	cmd.len += le16_to_cpu(scan->tx_cmd.len) +
 	    scan->channel_count * sizeof(struct iwl3945_scan_channel);
@@ -6320,16 +6317,13 @@
 
 #define IWL_DELAY_NEXT_SCAN (HZ*2)
 
-static void iwl3945_bg_post_associate(struct work_struct *data)
+static void iwl3945_post_associate(struct iwl3945_priv *priv)
 {
-	struct iwl3945_priv *priv = container_of(data, struct iwl3945_priv,
-					     post_associate.work);
-
 	int rc = 0;
 	struct ieee80211_conf *conf = NULL;
 	DECLARE_MAC_BUF(mac);
 
-	if (priv->iw_mode == IEEE80211_IF_TYPE_AP) {
+	if (priv->iw_mode == NL80211_IFTYPE_AP) {
 		IWL_ERROR("%s Should not be called in AP mode\n", __func__);
 		return;
 	}
@@ -6342,12 +6336,9 @@
 	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
 		return;
 
-	mutex_lock(&priv->mutex);
-
-	if (!priv->vif || !priv->is_open) {
-		mutex_unlock(&priv->mutex);
+	if (!priv->vif || !priv->is_open)
 		return;
-	}
+
 	iwl3945_scan_cancel_timeout(priv, 200);
 
 	conf = ieee80211_get_hw_conf(priv->hw);
@@ -6381,7 +6372,7 @@
 		else
 			priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK;
 
-		if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS)
+		if (priv->iw_mode == NL80211_IFTYPE_ADHOC)
 			priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK;
 
 	}
@@ -6389,11 +6380,11 @@
 	iwl3945_commit_rxon(priv);
 
 	switch (priv->iw_mode) {
-	case IEEE80211_IF_TYPE_STA:
+	case NL80211_IFTYPE_STATION:
 		iwl3945_rate_scale_init(priv->hw, IWL_AP_ID);
 		break;
 
-	case IEEE80211_IF_TYPE_IBSS:
+	case NL80211_IFTYPE_ADHOC:
 
 		/* clear out the station table */
 		iwl3945_clear_stations_table(priv);
@@ -6419,7 +6410,6 @@
 
 	/* we have just associated, don't start scan too early */
 	priv->next_scan_jiffies = jiffies + IWL_DELAY_NEXT_SCAN;
-	mutex_unlock(&priv->mutex);
 }
 
 static void iwl3945_bg_abort_scan(struct work_struct *work)
@@ -6567,7 +6557,6 @@
 		 */
 		mutex_lock(&priv->mutex);
 		iwl3945_scan_cancel_timeout(priv, 100);
-		cancel_delayed_work(&priv->post_associate);
 		mutex_unlock(&priv->mutex);
 	}
 
@@ -6650,8 +6639,6 @@
 	mutex_lock(&priv->mutex);
 	IWL_DEBUG_MAC80211("enter to channel %d\n", conf->channel->hw_value);
 
-	priv->add_radiotap = !!(conf->flags & IEEE80211_CONF_RADIOTAP);
-
 	if (!iwl3945_is_ready(priv)) {
 		IWL_DEBUG_MAC80211("leave - not ready\n");
 		ret = -EIO;
@@ -6767,7 +6754,7 @@
 				priv->staging_rxon.flags &=
 					~RXON_FLG_SHORT_SLOT_MSK;
 
-			if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS)
+			if (priv->iw_mode == NL80211_IFTYPE_ADHOC)
 				priv->staging_rxon.flags &=
 					~RXON_FLG_SHORT_SLOT_MSK;
 		}
@@ -6804,7 +6791,7 @@
 	}
 
 	/* handle this temporarily here */
-	if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS &&
+	if (priv->iw_mode == NL80211_IFTYPE_ADHOC &&
 	    conf->changed & IEEE80211_IFCC_BEACON) {
 		struct sk_buff *beacon = ieee80211_beacon_get(hw, vif);
 		if (!beacon)
@@ -6816,7 +6803,7 @@
 
 	/* XXX: this MUST use conf->mac_addr */
 
-	if ((priv->iw_mode == IEEE80211_IF_TYPE_AP) &&
+	if ((priv->iw_mode == NL80211_IFTYPE_AP) &&
 	    (!conf->ssid_len)) {
 		IWL_DEBUG_MAC80211
 		    ("Leaving in AP mode because HostAPD is not ready.\n");
@@ -6839,7 +6826,7 @@
 	    !(priv->hw->flags & IEEE80211_HW_NO_PROBE_FILTERING)) {
  */
 
-	if (priv->iw_mode == IEEE80211_IF_TYPE_AP) {
+	if (priv->iw_mode == NL80211_IFTYPE_AP) {
 		if (!conf->bssid) {
 			conf->bssid = priv->mac_addr;
 			memcpy(priv->bssid, priv->mac_addr, ETH_ALEN);
@@ -6874,11 +6861,11 @@
 		 * to verify) - jpk */
 		memcpy(priv->bssid, conf->bssid, ETH_ALEN);
 
-		if (priv->iw_mode == IEEE80211_IF_TYPE_AP)
+		if (priv->iw_mode == NL80211_IFTYPE_AP)
 			iwl3945_config_ap(priv);
 		else {
 			rc = iwl3945_commit_rxon(priv);
-			if ((priv->iw_mode == IEEE80211_IF_TYPE_STA) && rc)
+			if ((priv->iw_mode == NL80211_IFTYPE_STATION) && rc)
 				iwl3945_add_station(priv,
 					priv->active_rxon.bssid_addr, 1, 0);
 		}
@@ -6914,7 +6901,7 @@
 
 	if (changed_flags & (*total_flags) & FIF_OTHER_BSS) {
 		IWL_DEBUG_MAC80211("Enter: type %d (0x%x, 0x%x)\n",
-				   IEEE80211_IF_TYPE_MNTR,
+				   NL80211_IFTYPE_MONITOR,
 				   changed_flags, *total_flags);
 		/* queue work 'cuz mac80211 is holding a lock which
 		 * prevents us from issuing (synchronous) f/w cmds */
@@ -6935,7 +6922,6 @@
 
 	if (iwl3945_is_ready_rf(priv)) {
 		iwl3945_scan_cancel_timeout(priv, 100);
-		cancel_delayed_work(&priv->post_associate);
 		priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
 		iwl3945_commit_rxon(priv);
 	}
@@ -6950,6 +6936,63 @@
 	IWL_DEBUG_MAC80211("leave\n");
 }
 
+#define IWL_DELAY_NEXT_SCAN_AFTER_ASSOC (HZ*6)
+
+static void iwl3945_bss_info_changed(struct ieee80211_hw *hw,
+				     struct ieee80211_vif *vif,
+				     struct ieee80211_bss_conf *bss_conf,
+				     u32 changes)
+{
+	struct iwl3945_priv *priv = hw->priv;
+
+	IWL_DEBUG_MAC80211("changes = 0x%X\n", changes);
+
+	if (changes & BSS_CHANGED_ERP_PREAMBLE) {
+		IWL_DEBUG_MAC80211("ERP_PREAMBLE %d\n",
+				   bss_conf->use_short_preamble);
+		if (bss_conf->use_short_preamble)
+			priv->staging_rxon.flags |= RXON_FLG_SHORT_PREAMBLE_MSK;
+		else
+			priv->staging_rxon.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK;
+	}
+
+	if (changes & BSS_CHANGED_ERP_CTS_PROT) {
+		IWL_DEBUG_MAC80211("ERP_CTS %d\n", bss_conf->use_cts_prot);
+		if (bss_conf->use_cts_prot && (priv->band != IEEE80211_BAND_5GHZ))
+			priv->staging_rxon.flags |= RXON_FLG_TGG_PROTECT_MSK;
+		else
+			priv->staging_rxon.flags &= ~RXON_FLG_TGG_PROTECT_MSK;
+	}
+
+	if (changes & BSS_CHANGED_ASSOC) {
+		IWL_DEBUG_MAC80211("ASSOC %d\n", bss_conf->assoc);
+		/* This should never happen as this function should
+		 * never be called from interrupt context. */
+		if (WARN_ON_ONCE(in_interrupt()))
+			return;
+		if (bss_conf->assoc) {
+			priv->assoc_id = bss_conf->aid;
+			priv->beacon_int = bss_conf->beacon_int;
+			priv->timestamp0 = bss_conf->timestamp & 0xFFFFFFFF;
+			priv->timestamp1 = (bss_conf->timestamp >> 32) &
+					     0xFFFFFFFF;
+			priv->assoc_capability = bss_conf->assoc_capability;
+			priv->next_scan_jiffies = jiffies +
+					IWL_DELAY_NEXT_SCAN_AFTER_ASSOC;
+			mutex_lock(&priv->mutex);
+			iwl3945_post_associate(priv);
+			mutex_unlock(&priv->mutex);
+		} else {
+			priv->assoc_id = 0;
+			IWL_DEBUG_MAC80211("DISASSOC %d\n", bss_conf->assoc);
+		}
+	} else if (changes && iwl3945_is_associated(priv) && priv->assoc_id) {
+			IWL_DEBUG_MAC80211("Associated Changes %d\n", changes);
+			iwl3945_send_rxon_assoc(priv);
+	}
+
+}
+
 static int iwl3945_mac_hw_scan(struct ieee80211_hw *hw, u8 *ssid, size_t len)
 {
 	int rc = 0;
@@ -6967,7 +7010,7 @@
 		goto out_unlock;
 	}
 
-	if (priv->iw_mode == IEEE80211_IF_TYPE_AP) {	/* APs don't scan */
+	if (priv->iw_mode == NL80211_IFTYPE_AP) {	/* APs don't scan */
 		rc = -EIO;
 		IWL_ERROR("ERROR: APs don't scan\n");
 		goto out_unlock;
@@ -7109,7 +7152,7 @@
 	spin_unlock_irqrestore(&priv->lock, flags);
 
 	mutex_lock(&priv->mutex);
-	if (priv->iw_mode == IEEE80211_IF_TYPE_AP)
+	if (priv->iw_mode == NL80211_IFTYPE_AP)
 		iwl3945_activate_qos(priv, 1);
 	else if (priv->assoc_id && iwl3945_is_associated(priv))
 		iwl3945_activate_qos(priv, 0);
@@ -7182,8 +7225,6 @@
 
 	iwl3945_reset_qos(priv);
 
-	cancel_delayed_work(&priv->post_associate);
-
 	spin_lock_irqsave(&priv->lock, flags);
 	priv->assoc_id = 0;
 	priv->assoc_capability = 0;
@@ -7198,7 +7239,7 @@
 	priv->beacon_int = priv->hw->conf.beacon_int;
 	priv->timestamp1 = 0;
 	priv->timestamp0 = 0;
-	if ((priv->iw_mode == IEEE80211_IF_TYPE_STA))
+	if ((priv->iw_mode == NL80211_IFTYPE_STATION))
 		priv->beacon_int = 0;
 
 	spin_unlock_irqrestore(&priv->lock, flags);
@@ -7212,14 +7253,14 @@
 	/* we are restarting association process
 	 * clear RXON_FILTER_ASSOC_MSK bit
 	*/
-	if (priv->iw_mode != IEEE80211_IF_TYPE_AP) {
+	if (priv->iw_mode != NL80211_IFTYPE_AP) {
 		iwl3945_scan_cancel_timeout(priv, 100);
 		priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
 		iwl3945_commit_rxon(priv);
 	}
 
 	/* Per mac80211.h: This is only used in IBSS mode... */
-	if (priv->iw_mode != IEEE80211_IF_TYPE_IBSS) {
+	if (priv->iw_mode != NL80211_IFTYPE_ADHOC) {
 
 		IWL_DEBUG_MAC80211("leave - not in IBSS\n");
 		mutex_unlock(&priv->mutex);
@@ -7248,7 +7289,7 @@
 		return -EIO;
 	}
 
-	if (priv->iw_mode != IEEE80211_IF_TYPE_IBSS) {
+	if (priv->iw_mode != NL80211_IFTYPE_ADHOC) {
 		IWL_DEBUG_MAC80211("leave - not IBSS\n");
 		mutex_unlock(&priv->mutex);
 		return -EIO;
@@ -7268,7 +7309,7 @@
 
 	iwl3945_reset_qos(priv);
 
-	queue_work(priv->workqueue, &priv->post_associate.work);
+	iwl3945_post_associate(priv);
 
 	mutex_unlock(&priv->mutex);
 
@@ -7329,15 +7370,6 @@
 
 static DEVICE_ATTR(temperature, S_IRUGO, show_temperature, NULL);
 
-static ssize_t show_rs_window(struct device *d,
-			      struct device_attribute *attr,
-			      char *buf)
-{
-	struct iwl3945_priv *priv = d->driver_data;
-	return iwl3945_fill_rs_info(priv->hw, buf, IWL_AP_ID);
-}
-static DEVICE_ATTR(rs_window, S_IRUGO, show_rs_window, NULL);
-
 static ssize_t show_tx_power(struct device *d,
 			     struct device_attribute *attr, char *buf)
 {
@@ -7767,7 +7799,6 @@
 	INIT_WORK(&priv->rf_kill, iwl3945_bg_rf_kill);
 	INIT_WORK(&priv->beacon_update, iwl3945_bg_beacon_update);
 	INIT_WORK(&priv->set_monitor, iwl3945_bg_set_monitor);
-	INIT_DELAYED_WORK(&priv->post_associate, iwl3945_bg_post_associate);
 	INIT_DELAYED_WORK(&priv->init_alive_start, iwl3945_bg_init_alive_start);
 	INIT_DELAYED_WORK(&priv->alive_start, iwl3945_bg_alive_start);
 	INIT_DELAYED_WORK(&priv->scan_check, iwl3945_bg_scan_check);
@@ -7785,7 +7816,6 @@
 	cancel_delayed_work_sync(&priv->init_alive_start);
 	cancel_delayed_work(&priv->scan_check);
 	cancel_delayed_work(&priv->alive_start);
-	cancel_delayed_work(&priv->post_associate);
 	cancel_work_sync(&priv->beacon_update);
 }
 
@@ -7801,7 +7831,6 @@
 #endif
 	&dev_attr_power_level.attr,
 	&dev_attr_retry_rate.attr,
-	&dev_attr_rs_window.attr,
 	&dev_attr_statistics.attr,
 	&dev_attr_status.attr,
 	&dev_attr_temperature.attr,
@@ -7830,6 +7859,7 @@
 	.conf_tx = iwl3945_mac_conf_tx,
 	.get_tsf = iwl3945_mac_get_tsf,
 	.reset_tsf = iwl3945_mac_reset_tsf,
+	.bss_info_changed = iwl3945_bss_info_changed,
 	.hw_scan = iwl3945_mac_hw_scan
 };
 
@@ -7868,6 +7898,7 @@
 	SET_IEEE80211_DEV(hw, &pdev->dev);
 
 	hw->rate_control_algorithm = "iwl-3945-rs";
+	hw->sta_data_size = sizeof(struct iwl3945_sta_priv);
 
 	IWL_DEBUG_INFO("*** LOAD DRIVER ***\n");
 	priv = hw->priv;
@@ -7890,6 +7921,11 @@
 	hw->flags = IEEE80211_HW_SIGNAL_DBM |
 		    IEEE80211_HW_NOISE_DBM;
 
+	hw->wiphy->interface_modes =
+		BIT(NL80211_IFTYPE_AP) |
+		BIT(NL80211_IFTYPE_STATION) |
+		BIT(NL80211_IFTYPE_ADHOC);
+
 	/* 4 EDCA QOS priorities */
 	hw->queues = 4;
 
@@ -7951,7 +7987,7 @@
 		IWL_DEBUG_INFO("Radio disabled.\n");
 	}
 
-	priv->iw_mode = IEEE80211_IF_TYPE_STA;
+	priv->iw_mode = NL80211_IFTYPE_STATION;
 
 	printk(KERN_INFO DRV_NAME
 		": Detected Intel Wireless WiFi Link %s\n", priv->cfg->name);
@@ -8331,6 +8367,8 @@
 	iwl3945_rate_control_unregister();
 }
 
+MODULE_FIRMWARE("iwlwifi-3945" IWL3945_UCODE_API ".ucode");
+
 module_param_named(antenna, iwl3945_param_antenna, int, 0444);
 MODULE_PARM_DESC(antenna, "select antenna (1=Main, 2=Aux, default 0 [both])");
 module_param_named(disable, iwl3945_param_disable, int, 0444);
diff --git a/drivers/net/wireless/libertas/assoc.c b/drivers/net/wireless/libertas/assoc.c
index a267d6e..92be604 100644
--- a/drivers/net/wireless/libertas/assoc.c
+++ b/drivers/net/wireless/libertas/assoc.c
@@ -8,6 +8,7 @@
 #include "scan.h"
 #include "cmd.h"
 
+static int lbs_adhoc_post(struct lbs_private *priv, struct cmd_header *resp);
 
 static const u8 bssid_any[ETH_ALEN]  __attribute__ ((aligned (2))) =
 	{ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
@@ -20,12 +21,88 @@
 #define CAPINFO_MASK	(~(0xda00))
 
 
+/**
+ *  @brief This function finds common rates between rates and card rates.
+ *
+ * It will fill common rates in rates as output if found.
+ *
+ * NOTE: Setting the MSB of the basic rates need to be taken
+ *   care, either before or after calling this function
+ *
+ *  @param priv     A pointer to struct lbs_private structure
+ *  @param rates       the buffer which keeps input and output
+ *  @param rates_size  the size of rate1 buffer; new size of buffer on return
+ *
+ *  @return            0 on success, or -1 on error
+ */
+static int get_common_rates(struct lbs_private *priv,
+	u8 *rates,
+	u16 *rates_size)
+{
+	u8 *card_rates = lbs_bg_rates;
+	size_t num_card_rates = sizeof(lbs_bg_rates);
+	int ret = 0, i, j;
+	u8 tmp[30];
+	size_t tmp_size = 0;
+
+	/* For each rate in card_rates that exists in rate1, copy to tmp */
+	for (i = 0; card_rates[i] && (i < num_card_rates); i++) {
+		for (j = 0; rates[j] && (j < *rates_size); j++) {
+			if (rates[j] == card_rates[i])
+				tmp[tmp_size++] = card_rates[i];
+		}
+	}
+
+	lbs_deb_hex(LBS_DEB_JOIN, "AP rates    ", rates, *rates_size);
+	lbs_deb_hex(LBS_DEB_JOIN, "card rates  ", card_rates, num_card_rates);
+	lbs_deb_hex(LBS_DEB_JOIN, "common rates", tmp, tmp_size);
+	lbs_deb_join("TX data rate 0x%02x\n", priv->cur_rate);
+
+	if (!priv->enablehwauto) {
+		for (i = 0; i < tmp_size; i++) {
+			if (tmp[i] == priv->cur_rate)
+				goto done;
+		}
+		lbs_pr_alert("Previously set fixed data rate %#x isn't "
+		       "compatible with the network.\n", priv->cur_rate);
+		ret = -1;
+		goto done;
+	}
+	ret = 0;
+
+done:
+	memset(rates, 0, *rates_size);
+	*rates_size = min_t(int, tmp_size, *rates_size);
+	memcpy(rates, tmp, *rates_size);
+	return ret;
+}
+
+
+/**
+ *  @brief Sets the MSB on basic rates as the firmware requires
+ *
+ * Scan through an array and set the MSB for basic data rates.
+ *
+ *  @param rates     buffer of data rates
+ *  @param len       size of buffer
+ */
+static void lbs_set_basic_rate_flags(u8 *rates, size_t len)
+{
+	int i;
+
+	for (i = 0; i < len; i++) {
+		if (rates[i] == 0x02 || rates[i] == 0x04 ||
+		    rates[i] == 0x0b || rates[i] == 0x16)
+			rates[i] |= 0x80;
+	}
+}
+
 
 /**
  *  @brief Associate to a specific BSS discovered in a scan
  *
  *  @param priv      A pointer to struct lbs_private structure
- *  @param pbssdesc  Pointer to the BSS descriptor to associate with.
+ *  @param assoc_req The association request describing the BSS to associate with
  *
  *  @return          0-success, otherwise fail
  */
@@ -33,29 +110,29 @@
 	struct assoc_request *assoc_req)
 {
 	int ret;
+	u8 preamble = RADIO_PREAMBLE_LONG;
 
 	lbs_deb_enter(LBS_DEB_ASSOC);
 
 	ret = lbs_prepare_and_send_command(priv, CMD_802_11_AUTHENTICATE,
 				    0, CMD_OPTION_WAITFORRSP,
 				    0, assoc_req->bss.bssid);
-
 	if (ret)
-		goto done;
+		goto out;
 
-	/* set preamble to firmware */
+	/* Use short preamble only when both the BSS and firmware support it */
 	if ((priv->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) &&
 	    (assoc_req->bss.capability & WLAN_CAPABILITY_SHORT_PREAMBLE))
-		priv->preamble = CMD_TYPE_SHORT_PREAMBLE;
-	else
-		priv->preamble = CMD_TYPE_LONG_PREAMBLE;
+		preamble = RADIO_PREAMBLE_SHORT;
 
-	lbs_set_radio_control(priv);
+	ret = lbs_set_radio(priv, preamble, 1);
+	if (ret)
+		goto out;
 
 	ret = lbs_prepare_and_send_command(priv, CMD_802_11_ASSOCIATE,
 				    0, CMD_OPTION_WAITFORRSP, 0, assoc_req);
 
-done:
+out:
 	lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
 	return ret;
 }
@@ -64,17 +141,22 @@
  *  @brief Join an adhoc network found in a previous scan
  *
  *  @param priv         A pointer to struct lbs_private structure
- *  @param pbssdesc     Pointer to a BSS descriptor found in a previous scan
- *                      to attempt to join
+ *  @param assoc_req    The association request describing the BSS to join
  *
- *  @return             0--success, -1--fail
+ *  @return             0 on success, error on failure
  */
-static int lbs_join_adhoc_network(struct lbs_private *priv,
+static int lbs_adhoc_join(struct lbs_private *priv,
 	struct assoc_request *assoc_req)
 {
+	struct cmd_ds_802_11_ad_hoc_join cmd;
 	struct bss_descriptor *bss = &assoc_req->bss;
+	u8 preamble = RADIO_PREAMBLE_LONG;
+	DECLARE_MAC_BUF(mac);
+	u16 ratesize = 0;
 	int ret = 0;
 
+	lbs_deb_enter(LBS_DEB_ASSOC);
+
 	lbs_deb_join("current SSID '%s', ssid length %u\n",
 		escape_essid(priv->curbssparams.ssid,
 		priv->curbssparams.ssid_len),
@@ -106,29 +188,106 @@
 		goto out;
 	}
 
-	/* Use shortpreamble only when both creator and card supports
-	   short preamble */
-	if (!(bss->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) ||
-	    !(priv->capability & WLAN_CAPABILITY_SHORT_PREAMBLE)) {
-		lbs_deb_join("AdhocJoin: Long preamble\n");
-		priv->preamble = CMD_TYPE_LONG_PREAMBLE;
-	} else {
+	/* Use short preamble only when both the BSS and firmware support it */
+	if ((priv->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) &&
+	    (bss->capability & WLAN_CAPABILITY_SHORT_PREAMBLE)) {
 		lbs_deb_join("AdhocJoin: Short preamble\n");
-		priv->preamble = CMD_TYPE_SHORT_PREAMBLE;
+		preamble = RADIO_PREAMBLE_SHORT;
 	}
 
-	lbs_set_radio_control(priv);
+	ret = lbs_set_radio(priv, preamble, 1);
+	if (ret)
+		goto out;
 
 	lbs_deb_join("AdhocJoin: channel = %d\n", assoc_req->channel);
 	lbs_deb_join("AdhocJoin: band = %c\n", assoc_req->band);
 
 	priv->adhoccreate = 0;
+	priv->curbssparams.channel = bss->channel;
 
-	ret = lbs_prepare_and_send_command(priv, CMD_802_11_AD_HOC_JOIN,
-				    0, CMD_OPTION_WAITFORRSP,
-				    OID_802_11_SSID, assoc_req);
+	/* Build the join command */
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+
+	cmd.bss.type = CMD_BSS_TYPE_IBSS;
+	cmd.bss.beaconperiod = cpu_to_le16(bss->beaconperiod);
+
+	memcpy(&cmd.bss.bssid, &bss->bssid, ETH_ALEN);
+	memcpy(&cmd.bss.ssid, &bss->ssid, bss->ssid_len);
+
+	memcpy(&cmd.bss.phyparamset, &bss->phyparamset,
+	       sizeof(union ieeetypes_phyparamset));
+
+	memcpy(&cmd.bss.ssparamset, &bss->ssparamset,
+	       sizeof(union IEEEtypes_ssparamset));
+
+	cmd.bss.capability = cpu_to_le16(bss->capability & CAPINFO_MASK);
+	lbs_deb_join("ADHOC_J_CMD: tmpcap=%4X CAPINFO_MASK=%4X\n",
+	       bss->capability, CAPINFO_MASK);
+
+	/* information on BSSID descriptor passed to FW */
+	lbs_deb_join("ADHOC_J_CMD: BSSID = %s, SSID = '%s'\n",
+			print_mac(mac, cmd.bss.bssid), cmd.bss.ssid);
+
+	/* Only v8 and below support setting these */
+	if (priv->fwrelease < 0x09000000) {
+		/* failtimeout */
+		cmd.failtimeout = cpu_to_le16(MRVDRV_ASSOCIATION_TIME_OUT);
+		/* probedelay */
+		cmd.probedelay = cpu_to_le16(CMD_SCAN_PROBE_DELAY_TIME);
+	}
+
+	/* Copy Data rates from the rates recorded in scan response */
+	memset(cmd.bss.rates, 0, sizeof(cmd.bss.rates));
+	ratesize = min_t(u16, sizeof(cmd.bss.rates), MAX_RATES);
+	memcpy(cmd.bss.rates, bss->rates, ratesize);
+	if (get_common_rates(priv, cmd.bss.rates, &ratesize)) {
+		lbs_deb_join("ADHOC_JOIN: get_common_rates returned error.\n");
+		ret = -1;
+		goto out;
+	}
+
+	/* Copy the ad-hoc creation rates into Current BSS state structure */
+	memset(&priv->curbssparams.rates, 0, sizeof(priv->curbssparams.rates));
+	memcpy(&priv->curbssparams.rates, cmd.bss.rates, ratesize);
+
+	/* Set MSB on basic rates as the firmware requires, but _after_
+	 * copying to current bss rates.
+	 */
+	lbs_set_basic_rate_flags(cmd.bss.rates, ratesize);
+
+	cmd.bss.ssparamset.ibssparamset.atimwindow = cpu_to_le16(bss->atimwindow);
+
+	if (assoc_req->secinfo.wep_enabled) {
+		u16 tmp = le16_to_cpu(cmd.bss.capability);
+		tmp |= WLAN_CAPABILITY_PRIVACY;
+		cmd.bss.capability = cpu_to_le16(tmp);
+	}
+
+	if (priv->psmode == LBS802_11POWERMODEMAX_PSP) {
+		__le32 local_ps_mode = cpu_to_le32(LBS802_11POWERMODECAM);
+
+		/* wake up first */
+		ret = lbs_prepare_and_send_command(priv, CMD_802_11_PS_MODE,
+						   CMD_ACT_SET, 0, 0,
+						   &local_ps_mode);
+		if (ret) {
+			ret = -1;
+			goto out;
+		}
+	}
+
+	if (lbs_parse_dnld_countryinfo_11d(priv, bss)) {
+		ret = -1;
+		goto out;
+	}
+
+	ret = lbs_cmd_with_response(priv, CMD_802_11_AD_HOC_JOIN, &cmd);
+	if (ret == 0)
+		ret = lbs_adhoc_post(priv, (struct cmd_header *) &cmd);
 
 out:
+	lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
 	return ret;
 }
 
@@ -136,39 +295,131 @@
  *  @brief Start an Adhoc Network
  *
  *  @param priv         A pointer to struct lbs_private structure
- *  @param adhocssid    The ssid of the Adhoc Network
- *  @return             0--success, -1--fail
+ *  @param assoc_req    The association request describing the BSS to start
+ *
+ *  @return             0 on success, error on failure
  */
-static int lbs_start_adhoc_network(struct lbs_private *priv,
+static int lbs_adhoc_start(struct lbs_private *priv,
 	struct assoc_request *assoc_req)
 {
+	struct cmd_ds_802_11_ad_hoc_start cmd;
+	u8 preamble = RADIO_PREAMBLE_LONG;
+	size_t ratesize = 0;
+	u16 tmpcap = 0;
 	int ret = 0;
 
-	priv->adhoccreate = 1;
+	lbs_deb_enter(LBS_DEB_ASSOC);
 
 	if (priv->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) {
-		lbs_deb_join("AdhocStart: Short preamble\n");
-		priv->preamble = CMD_TYPE_SHORT_PREAMBLE;
-	} else {
-		lbs_deb_join("AdhocStart: Long preamble\n");
-		priv->preamble = CMD_TYPE_LONG_PREAMBLE;
+		lbs_deb_join("ADHOC_START: Will use short preamble\n");
+		preamble = RADIO_PREAMBLE_SHORT;
 	}
 
-	lbs_set_radio_control(priv);
+	ret = lbs_set_radio(priv, preamble, 1);
+	if (ret)
+		goto out;
 
-	lbs_deb_join("AdhocStart: channel = %d\n", assoc_req->channel);
-	lbs_deb_join("AdhocStart: band = %d\n", assoc_req->band);
+	/* Build the start command */
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
 
-	ret = lbs_prepare_and_send_command(priv, CMD_802_11_AD_HOC_START,
-				    0, CMD_OPTION_WAITFORRSP, 0, assoc_req);
+	memcpy(cmd.ssid, assoc_req->ssid, assoc_req->ssid_len);
 
+	lbs_deb_join("ADHOC_START: SSID '%s', ssid length %u\n",
+		escape_essid(assoc_req->ssid, assoc_req->ssid_len),
+		assoc_req->ssid_len);
+
+	cmd.bsstype = CMD_BSS_TYPE_IBSS;
+
+	if (priv->beacon_period == 0)
+		priv->beacon_period = MRVDRV_BEACON_INTERVAL;
+	cmd.beaconperiod = cpu_to_le16(priv->beacon_period);
+
+	WARN_ON(!assoc_req->channel);
+
+	/* set Physical parameter set */
+	cmd.phyparamset.dsparamset.elementid = MFIE_TYPE_DS_SET;
+	cmd.phyparamset.dsparamset.len = 1;
+	cmd.phyparamset.dsparamset.currentchan = assoc_req->channel;
+
+	/* set IBSS parameter set */
+	cmd.ssparamset.ibssparamset.elementid = MFIE_TYPE_IBSS_SET;
+	cmd.ssparamset.ibssparamset.len = 2;
+	cmd.ssparamset.ibssparamset.atimwindow = 0;
+
+	/* set capability info */
+	tmpcap = WLAN_CAPABILITY_IBSS;
+	if (assoc_req->secinfo.wep_enabled) {
+		lbs_deb_join("ADHOC_START: WEP enabled, setting privacy on\n");
+		tmpcap |= WLAN_CAPABILITY_PRIVACY;
+	} else
+		lbs_deb_join("ADHOC_START: WEP disabled, setting privacy off\n");
+
+	cmd.capability = cpu_to_le16(tmpcap);
+
+	/* Only v8 and below support setting probe delay */
+	if (priv->fwrelease < 0x09000000)
+		cmd.probedelay = cpu_to_le16(CMD_SCAN_PROBE_DELAY_TIME);
+
+	ratesize = min(sizeof(cmd.rates), sizeof(lbs_bg_rates));
+	memcpy(cmd.rates, lbs_bg_rates, ratesize);
+
+	/* Copy the ad-hoc creating rates into Current BSS state structure */
+	memset(&priv->curbssparams.rates, 0, sizeof(priv->curbssparams.rates));
+	memcpy(&priv->curbssparams.rates, &cmd.rates, ratesize);
+
+	/* Set MSB on basic rates as the firmware requires, but _after_
+	 * copying to current bss rates.
+	 */
+	lbs_set_basic_rate_flags(cmd.rates, ratesize);
+
+	lbs_deb_join("ADHOC_START: rates=%02x %02x %02x %02x\n",
+	       cmd.rates[0], cmd.rates[1], cmd.rates[2], cmd.rates[3]);
+
+	if (lbs_create_dnld_countryinfo_11d(priv)) {
+		lbs_deb_join("ADHOC_START: dnld_countryinfo_11d failed\n");
+		ret = -1;
+		goto out;
+	}
+
+	lbs_deb_join("ADHOC_START: Starting Ad-Hoc BSS on channel %d, band %d\n",
+		     assoc_req->channel, assoc_req->band);
+
+	priv->adhoccreate = 1;
+	priv->mode = IW_MODE_ADHOC;
+
+	ret = lbs_cmd_with_response(priv, CMD_802_11_AD_HOC_START, &cmd);
+	if (ret == 0)
+		ret = lbs_adhoc_post(priv, (struct cmd_header *) &cmd);
+
+out:
+	lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
 	return ret;
 }
 
-int lbs_stop_adhoc_network(struct lbs_private *priv)
+/**
+ *  @brief Stop and Ad-Hoc network and exit Ad-Hoc mode
+ *
+ *  @param priv         A pointer to struct lbs_private structure
+ *  @return             0 on success, or an error
+ */
+int lbs_adhoc_stop(struct lbs_private *priv)
 {
-	return lbs_prepare_and_send_command(priv, CMD_802_11_AD_HOC_STOP,
-				     0, CMD_OPTION_WAITFORRSP, 0, NULL);
+	struct cmd_ds_802_11_ad_hoc_stop cmd;
+	int ret;
+
+	lbs_deb_enter(LBS_DEB_JOIN);
+
+	memset(&cmd, 0, sizeof (cmd));
+	cmd.hdr.size = cpu_to_le16 (sizeof (cmd));
+
+	ret = lbs_cmd_with_response(priv, CMD_802_11_AD_HOC_STOP, &cmd);
+
+	/* Clean up everything even if there was an error */
+	lbs_mac_event_disconnected(priv);
+
+	lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
+	return ret;
 }
 
 static inline int match_bss_no_security(struct lbs_802_11_security *secinfo,
@@ -480,14 +731,14 @@
 		if (bss != NULL) {
 			lbs_deb_assoc("SSID found, will join\n");
 			memcpy(&assoc_req->bss, bss, sizeof(struct bss_descriptor));
-			lbs_join_adhoc_network(priv, assoc_req);
+			lbs_adhoc_join(priv, assoc_req);
 		} else {
 			/* else send START command */
 			lbs_deb_assoc("SSID not found, creating adhoc network\n");
 			memcpy(&assoc_req->bss.ssid, &assoc_req->ssid,
 				IW_ESSID_MAX_SIZE);
 			assoc_req->bss.ssid_len = assoc_req->ssid_len;
-			lbs_start_adhoc_network(priv, assoc_req);
+			lbs_adhoc_start(priv, assoc_req);
 		}
 	}
 
@@ -520,7 +771,7 @@
 		ret = lbs_associate(priv, assoc_req);
 		lbs_deb_assoc("ASSOC: lbs_associate(bssid) returned %d\n", ret);
 	} else if (assoc_req->mode == IW_MODE_ADHOC) {
-		lbs_join_adhoc_network(priv, assoc_req);
+		lbs_adhoc_join(priv, assoc_req);
 	}
 
 out:
@@ -572,11 +823,7 @@
 	}
 
 	priv->mode = assoc_req->mode;
-	ret = lbs_prepare_and_send_command(priv,
-				    CMD_802_11_SNMP_MIB,
-				    0, CMD_OPTION_WAITFORRSP,
-				    OID_802_11_INFRASTRUCTURE_MODE,
-		/* Shoot me now */  (void *) (size_t) assoc_req->mode);
+	ret = lbs_set_snmp_mib(priv, SNMP_MIB_OID_BSS_TYPE, assoc_req->mode);
 
 done:
 	lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
@@ -1029,7 +1276,9 @@
 	 */
 	if (priv->mode == IW_MODE_INFRA) {
 		if (should_deauth_infrastructure(priv, assoc_req)) {
-			ret = lbs_send_deauthentication(priv);
+			ret = lbs_cmd_80211_deauthenticate(priv,
+							   priv->curbssparams.bssid,
+							   WLAN_REASON_DEAUTH_LEAVING);
 			if (ret) {
 				lbs_deb_assoc("Deauthentication due to new "
 					"configuration request failed: %d\n",
@@ -1038,7 +1287,7 @@
 		}
 	} else if (priv->mode == IW_MODE_ADHOC) {
 		if (should_stop_adhoc(priv, assoc_req)) {
-			ret = lbs_stop_adhoc_network(priv);
+			ret = lbs_adhoc_stop(priv);
 			if (ret) {
 				lbs_deb_assoc("Teardown of AdHoc network due to "
 					"new configuration request failed: %d\n",
@@ -1214,94 +1463,6 @@
 
 
 /**
- *  @brief This function finds common rates between rate1 and card rates.
- *
- * It will fill common rates in rate1 as output if found.
- *
- * NOTE: Setting the MSB of the basic rates need to be taken
- *   care, either before or after calling this function
- *
- *  @param priv     A pointer to struct lbs_private structure
- *  @param rate1       the buffer which keeps input and output
- *  @param rate1_size  the size of rate1 buffer; new size of buffer on return
- *
- *  @return            0 or -1
- */
-static int get_common_rates(struct lbs_private *priv,
-	u8 *rates,
-	u16 *rates_size)
-{
-	u8 *card_rates = lbs_bg_rates;
-	size_t num_card_rates = sizeof(lbs_bg_rates);
-	int ret = 0, i, j;
-	u8 tmp[30];
-	size_t tmp_size = 0;
-
-	/* For each rate in card_rates that exists in rate1, copy to tmp */
-	for (i = 0; card_rates[i] && (i < num_card_rates); i++) {
-		for (j = 0; rates[j] && (j < *rates_size); j++) {
-			if (rates[j] == card_rates[i])
-				tmp[tmp_size++] = card_rates[i];
-		}
-	}
-
-	lbs_deb_hex(LBS_DEB_JOIN, "AP rates    ", rates, *rates_size);
-	lbs_deb_hex(LBS_DEB_JOIN, "card rates  ", card_rates, num_card_rates);
-	lbs_deb_hex(LBS_DEB_JOIN, "common rates", tmp, tmp_size);
-	lbs_deb_join("TX data rate 0x%02x\n", priv->cur_rate);
-
-	if (!priv->enablehwauto) {
-		for (i = 0; i < tmp_size; i++) {
-			if (tmp[i] == priv->cur_rate)
-				goto done;
-		}
-		lbs_pr_alert("Previously set fixed data rate %#x isn't "
-		       "compatible with the network.\n", priv->cur_rate);
-		ret = -1;
-		goto done;
-	}
-	ret = 0;
-
-done:
-	memset(rates, 0, *rates_size);
-	*rates_size = min_t(int, tmp_size, *rates_size);
-	memcpy(rates, tmp, *rates_size);
-	return ret;
-}
-
-
-/**
- *  @brief Sets the MSB on basic rates as the firmware requires
- *
- * Scan through an array and set the MSB for basic data rates.
- *
- *  @param rates     buffer of data rates
- *  @param len       size of buffer
- */
-static void lbs_set_basic_rate_flags(u8 *rates, size_t len)
-{
-	int i;
-
-	for (i = 0; i < len; i++) {
-		if (rates[i] == 0x02 || rates[i] == 0x04 ||
-		    rates[i] == 0x0b || rates[i] == 0x16)
-			rates[i] |= 0x80;
-	}
-}
-
-/**
- *  @brief Send Deauthentication Request
- *
- *  @param priv      A pointer to struct lbs_private structure
- *  @return          0--success, -1--fail
- */
-int lbs_send_deauthentication(struct lbs_private *priv)
-{
-	return lbs_prepare_and_send_command(priv, CMD_802_11_DEAUTHENTICATE,
-				     0, CMD_OPTION_WAITFORRSP, 0, NULL);
-}
-
-/**
  *  @brief This function prepares command of authenticate.
  *
  *  @param priv      A pointer to struct lbs_private structure
@@ -1353,26 +1514,37 @@
 	return ret;
 }
 
-int lbs_cmd_80211_deauthenticate(struct lbs_private *priv,
-				   struct cmd_ds_command *cmd)
+/**
+ *  @brief Deauthenticate from a specific BSS
+ *
+ *  @param priv        A pointer to struct lbs_private structure
+ *  @param bssid       The specific BSS to deauthenticate from
+ *  @param reason      The 802.11 sec. 7.3.1.7 Reason Code for deauthenticating
+ *
+ *  @return            0 on success, error on failure
+ */
+int lbs_cmd_80211_deauthenticate(struct lbs_private *priv, u8 bssid[ETH_ALEN],
+				 u16 reason)
 {
-	struct cmd_ds_802_11_deauthenticate *dauth = &cmd->params.deauth;
+	struct cmd_ds_802_11_deauthenticate cmd;
+	int ret;
 
 	lbs_deb_enter(LBS_DEB_JOIN);
 
-	cmd->command = cpu_to_le16(CMD_802_11_DEAUTHENTICATE);
-	cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_deauthenticate) +
-			     S_DS_GEN);
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+	memcpy(cmd.macaddr, &bssid[0], ETH_ALEN);
+	cmd.reasoncode = cpu_to_le16(reason);
 
-	/* set AP MAC address */
-	memmove(dauth->macaddr, priv->curbssparams.bssid, ETH_ALEN);
+	ret = lbs_cmd_with_response(priv, CMD_802_11_DEAUTHENTICATE, &cmd);
 
-	/* Reason code 3 = Station is leaving */
-#define REASON_CODE_STA_LEAVING 3
-	dauth->reasoncode = cpu_to_le16(REASON_CODE_STA_LEAVING);
+	/* Clean up everything even if there was an error; can't assume that
+	 * we're still authenticated to the AP after trying to deauth.
+	 */
+	lbs_mac_event_disconnected(priv);
 
 	lbs_deb_leave(LBS_DEB_JOIN);
-	return 0;
+	return ret;
 }
 
 int lbs_cmd_80211_associate(struct lbs_private *priv,
@@ -1489,231 +1661,6 @@
 	return ret;
 }
 
-int lbs_cmd_80211_ad_hoc_start(struct lbs_private *priv,
-				 struct cmd_ds_command *cmd, void *pdata_buf)
-{
-	struct cmd_ds_802_11_ad_hoc_start *adhs = &cmd->params.ads;
-	int ret = 0;
-	int cmdappendsize = 0;
-	struct assoc_request *assoc_req = pdata_buf;
-	u16 tmpcap = 0;
-	size_t ratesize = 0;
-
-	lbs_deb_enter(LBS_DEB_JOIN);
-
-	if (!priv) {
-		ret = -1;
-		goto done;
-	}
-
-	cmd->command = cpu_to_le16(CMD_802_11_AD_HOC_START);
-
-	/*
-	 * Fill in the parameters for 2 data structures:
-	 *   1. cmd_ds_802_11_ad_hoc_start command
-	 *   2. priv->scantable[i]
-	 *
-	 * Driver will fill up SSID, bsstype,IBSS param, Physical Param,
-	 *   probe delay, and cap info.
-	 *
-	 * Firmware will fill up beacon period, DTIM, Basic rates
-	 *   and operational rates.
-	 */
-
-	memset(adhs->ssid, 0, IW_ESSID_MAX_SIZE);
-	memcpy(adhs->ssid, assoc_req->ssid, assoc_req->ssid_len);
-
-	lbs_deb_join("ADHOC_S_CMD: SSID '%s', ssid length %u\n",
-		escape_essid(assoc_req->ssid, assoc_req->ssid_len),
-		assoc_req->ssid_len);
-
-	/* set the BSS type */
-	adhs->bsstype = CMD_BSS_TYPE_IBSS;
-	priv->mode = IW_MODE_ADHOC;
-	if (priv->beacon_period == 0)
-		priv->beacon_period = MRVDRV_BEACON_INTERVAL;
-	adhs->beaconperiod = cpu_to_le16(priv->beacon_period);
-
-	/* set Physical param set */
-#define DS_PARA_IE_ID   3
-#define DS_PARA_IE_LEN  1
-
-	adhs->phyparamset.dsparamset.elementid = DS_PARA_IE_ID;
-	adhs->phyparamset.dsparamset.len = DS_PARA_IE_LEN;
-
-	WARN_ON(!assoc_req->channel);
-
-	lbs_deb_join("ADHOC_S_CMD: Creating ADHOC on channel %d\n",
-		     assoc_req->channel);
-
-	adhs->phyparamset.dsparamset.currentchan = assoc_req->channel;
-
-	/* set IBSS param set */
-#define IBSS_PARA_IE_ID   6
-#define IBSS_PARA_IE_LEN  2
-
-	adhs->ssparamset.ibssparamset.elementid = IBSS_PARA_IE_ID;
-	adhs->ssparamset.ibssparamset.len = IBSS_PARA_IE_LEN;
-	adhs->ssparamset.ibssparamset.atimwindow = 0;
-
-	/* set capability info */
-	tmpcap = WLAN_CAPABILITY_IBSS;
-	if (assoc_req->secinfo.wep_enabled) {
-		lbs_deb_join("ADHOC_S_CMD: WEP enabled, "
-			"setting privacy on\n");
-		tmpcap |= WLAN_CAPABILITY_PRIVACY;
-	} else {
-		lbs_deb_join("ADHOC_S_CMD: WEP disabled, "
-			"setting privacy off\n");
-	}
-	adhs->capability = cpu_to_le16(tmpcap);
-
-	/* probedelay */
-	adhs->probedelay = cpu_to_le16(CMD_SCAN_PROBE_DELAY_TIME);
-
-	memset(adhs->rates, 0, sizeof(adhs->rates));
-	ratesize = min(sizeof(adhs->rates), sizeof(lbs_bg_rates));
-	memcpy(adhs->rates, lbs_bg_rates, ratesize);
-
-	/* Copy the ad-hoc creating rates into Current BSS state structure */
-	memset(&priv->curbssparams.rates, 0, sizeof(priv->curbssparams.rates));
-	memcpy(&priv->curbssparams.rates, &adhs->rates, ratesize);
-
-	/* Set MSB on basic rates as the firmware requires, but _after_
-	 * copying to current bss rates.
-	 */
-	lbs_set_basic_rate_flags(adhs->rates, ratesize);
-
-	lbs_deb_join("ADHOC_S_CMD: rates=%02x %02x %02x %02x \n",
-	       adhs->rates[0], adhs->rates[1], adhs->rates[2], adhs->rates[3]);
-
-	lbs_deb_join("ADHOC_S_CMD: AD HOC Start command is ready\n");
-
-	if (lbs_create_dnld_countryinfo_11d(priv)) {
-		lbs_deb_join("ADHOC_S_CMD: dnld_countryinfo_11d failed\n");
-		ret = -1;
-		goto done;
-	}
-
-	cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_ad_hoc_start) +
-				S_DS_GEN + cmdappendsize);
-
-	ret = 0;
-done:
-	lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret);
-	return ret;
-}
-
-int lbs_cmd_80211_ad_hoc_stop(struct cmd_ds_command *cmd)
-{
-	cmd->command = cpu_to_le16(CMD_802_11_AD_HOC_STOP);
-	cmd->size = cpu_to_le16(S_DS_GEN);
-
-	return 0;
-}
-
-int lbs_cmd_80211_ad_hoc_join(struct lbs_private *priv,
-				struct cmd_ds_command *cmd, void *pdata_buf)
-{
-	struct cmd_ds_802_11_ad_hoc_join *join_cmd = &cmd->params.adj;
-	struct assoc_request *assoc_req = pdata_buf;
-	struct bss_descriptor *bss = &assoc_req->bss;
-	int cmdappendsize = 0;
-	int ret = 0;
-	u16 ratesize = 0;
-	DECLARE_MAC_BUF(mac);
-
-	lbs_deb_enter(LBS_DEB_JOIN);
-
-	cmd->command = cpu_to_le16(CMD_802_11_AD_HOC_JOIN);
-
-	join_cmd->bss.type = CMD_BSS_TYPE_IBSS;
-	join_cmd->bss.beaconperiod = cpu_to_le16(bss->beaconperiod);
-
-	memcpy(&join_cmd->bss.bssid, &bss->bssid, ETH_ALEN);
-	memcpy(&join_cmd->bss.ssid, &bss->ssid, bss->ssid_len);
-
-	memcpy(&join_cmd->bss.phyparamset, &bss->phyparamset,
-	       sizeof(union ieeetypes_phyparamset));
-
-	memcpy(&join_cmd->bss.ssparamset, &bss->ssparamset,
-	       sizeof(union IEEEtypes_ssparamset));
-
-	join_cmd->bss.capability = cpu_to_le16(bss->capability & CAPINFO_MASK);
-	lbs_deb_join("ADHOC_J_CMD: tmpcap=%4X CAPINFO_MASK=%4X\n",
-	       bss->capability, CAPINFO_MASK);
-
-	/* information on BSSID descriptor passed to FW */
-	lbs_deb_join(
-	       "ADHOC_J_CMD: BSSID = %s, SSID = '%s'\n",
-	       print_mac(mac, join_cmd->bss.bssid),
-	       join_cmd->bss.ssid);
-
-	/* failtimeout */
-	join_cmd->failtimeout = cpu_to_le16(MRVDRV_ASSOCIATION_TIME_OUT);
-
-	/* probedelay */
-	join_cmd->probedelay = cpu_to_le16(CMD_SCAN_PROBE_DELAY_TIME);
-
-	priv->curbssparams.channel = bss->channel;
-
-	/* Copy Data rates from the rates recorded in scan response */
-	memset(join_cmd->bss.rates, 0, sizeof(join_cmd->bss.rates));
-	ratesize = min_t(u16, sizeof(join_cmd->bss.rates), MAX_RATES);
-	memcpy(join_cmd->bss.rates, bss->rates, ratesize);
-	if (get_common_rates(priv, join_cmd->bss.rates, &ratesize)) {
-		lbs_deb_join("ADHOC_J_CMD: get_common_rates returns error.\n");
-		ret = -1;
-		goto done;
-	}
-
-	/* Copy the ad-hoc creating rates into Current BSS state structure */
-	memset(&priv->curbssparams.rates, 0, sizeof(priv->curbssparams.rates));
-	memcpy(&priv->curbssparams.rates, join_cmd->bss.rates, ratesize);
-
-	/* Set MSB on basic rates as the firmware requires, but _after_
-	 * copying to current bss rates.
-	 */
-	lbs_set_basic_rate_flags(join_cmd->bss.rates, ratesize);
-
-	join_cmd->bss.ssparamset.ibssparamset.atimwindow =
-	    cpu_to_le16(bss->atimwindow);
-
-	if (assoc_req->secinfo.wep_enabled) {
-		u16 tmp = le16_to_cpu(join_cmd->bss.capability);
-		tmp |= WLAN_CAPABILITY_PRIVACY;
-		join_cmd->bss.capability = cpu_to_le16(tmp);
-	}
-
-	if (priv->psmode == LBS802_11POWERMODEMAX_PSP) {
-		/* wake up first */
-		__le32 Localpsmode;
-
-		Localpsmode = cpu_to_le32(LBS802_11POWERMODECAM);
-		ret = lbs_prepare_and_send_command(priv,
-					    CMD_802_11_PS_MODE,
-					    CMD_ACT_SET,
-					    0, 0, &Localpsmode);
-
-		if (ret) {
-			ret = -1;
-			goto done;
-		}
-	}
-
-	if (lbs_parse_dnld_countryinfo_11d(priv, bss)) {
-		ret = -1;
-		goto done;
-	}
-
-	cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_ad_hoc_join) +
-				S_DS_GEN + cmdappendsize);
-
-done:
-	lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret);
-	return ret;
-}
-
 int lbs_ret_80211_associate(struct lbs_private *priv,
 			      struct cmd_ds_command *resp)
 {
@@ -1815,34 +1762,19 @@
 	return ret;
 }
 
-int lbs_ret_80211_disassociate(struct lbs_private *priv)
-{
-	lbs_deb_enter(LBS_DEB_JOIN);
-
-	lbs_mac_event_disconnected(priv);
-
-	lbs_deb_leave(LBS_DEB_JOIN);
-	return 0;
-}
-
-int lbs_ret_80211_ad_hoc_start(struct lbs_private *priv,
-				 struct cmd_ds_command *resp)
+static int lbs_adhoc_post(struct lbs_private *priv, struct cmd_header *resp)
 {
 	int ret = 0;
 	u16 command = le16_to_cpu(resp->command);
 	u16 result = le16_to_cpu(resp->result);
-	struct cmd_ds_802_11_ad_hoc_result *padhocresult;
+	struct cmd_ds_802_11_ad_hoc_result *adhoc_resp;
 	union iwreq_data wrqu;
 	struct bss_descriptor *bss;
 	DECLARE_MAC_BUF(mac);
 
 	lbs_deb_enter(LBS_DEB_JOIN);
 
-	padhocresult = &resp->params.result;
-
-	lbs_deb_join("ADHOC_RESP: size = %d\n", le16_to_cpu(resp->size));
-	lbs_deb_join("ADHOC_RESP: command = %x\n", command);
-	lbs_deb_join("ADHOC_RESP: result = %x\n", result);
+	adhoc_resp = (struct cmd_ds_802_11_ad_hoc_result *) resp;
 
 	if (!priv->in_progress_assoc_req) {
 		lbs_deb_join("ADHOC_RESP: no in-progress association "
@@ -1856,26 +1788,19 @@
 	 * Join result code 0 --> SUCCESS
 	 */
 	if (result) {
-		lbs_deb_join("ADHOC_RESP: failed\n");
+		lbs_deb_join("ADHOC_RESP: failed (result 0x%X)\n", result);
 		if (priv->connect_status == LBS_CONNECTED)
 			lbs_mac_event_disconnected(priv);
 		ret = -1;
 		goto done;
 	}
 
-	/*
-	 * Now the join cmd should be successful
-	 * If BSSID has changed use SSID to compare instead of BSSID
-	 */
-	lbs_deb_join("ADHOC_RESP: associated to '%s'\n",
-		escape_essid(bss->ssid, bss->ssid_len));
-
 	/* Send a Media Connected event, according to the Spec */
 	priv->connect_status = LBS_CONNECTED;
 
 	if (command == CMD_RET(CMD_802_11_AD_HOC_START)) {
 		/* Update the created network descriptor with the new BSSID */
-		memcpy(bss->bssid, padhocresult->bssid, ETH_ALEN);
+		memcpy(bss->bssid, adhoc_resp->bssid, ETH_ALEN);
 	}
 
 	/* Set the BSSID from the joined/started descriptor */
@@ -1894,22 +1819,13 @@
 	wrqu.ap_addr.sa_family = ARPHRD_ETHER;
 	wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL);
 
-	lbs_deb_join("ADHOC_RESP: - Joined/Started Ad Hoc\n");
-	lbs_deb_join("ADHOC_RESP: channel = %d\n", priv->curbssparams.channel);
-	lbs_deb_join("ADHOC_RESP: BSSID = %s\n",
-		     print_mac(mac, padhocresult->bssid));
+	lbs_deb_join("ADHOC_RESP: Joined/started '%s', BSSID %s, channel %d\n",
+		     escape_essid(bss->ssid, bss->ssid_len),
+		     print_mac(mac, priv->curbssparams.bssid),
+		     priv->curbssparams.channel);
 
 done:
 	lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret);
 	return ret;
 }
 
-int lbs_ret_80211_ad_hoc_stop(struct lbs_private *priv)
-{
-	lbs_deb_enter(LBS_DEB_JOIN);
-
-	lbs_mac_event_disconnected(priv);
-
-	lbs_deb_leave(LBS_DEB_JOIN);
-	return 0;
-}
diff --git a/drivers/net/wireless/libertas/assoc.h b/drivers/net/wireless/libertas/assoc.h
index c516fbe..8b7336d 100644
--- a/drivers/net/wireless/libertas/assoc.h
+++ b/drivers/net/wireless/libertas/assoc.h
@@ -12,28 +12,18 @@
 int lbs_cmd_80211_authenticate(struct lbs_private *priv,
 					struct cmd_ds_command *cmd,
 					void *pdata_buf);
-int lbs_cmd_80211_ad_hoc_join(struct lbs_private *priv,
-				       struct cmd_ds_command *cmd,
-				       void *pdata_buf);
-int lbs_cmd_80211_ad_hoc_stop(struct cmd_ds_command *cmd);
-int lbs_cmd_80211_ad_hoc_start(struct lbs_private *priv,
-					struct cmd_ds_command *cmd,
-					void *pdata_buf);
+
+int lbs_adhoc_stop(struct lbs_private *priv);
+
 int lbs_cmd_80211_deauthenticate(struct lbs_private *priv,
-					  struct cmd_ds_command *cmd);
+				 u8 bssid[ETH_ALEN], u16 reason);
 int lbs_cmd_80211_associate(struct lbs_private *priv,
 				     struct cmd_ds_command *cmd,
 				     void *pdata_buf);
 
 int lbs_ret_80211_ad_hoc_start(struct lbs_private *priv,
 					struct cmd_ds_command *resp);
-int lbs_ret_80211_ad_hoc_stop(struct lbs_private *priv);
-int lbs_ret_80211_disassociate(struct lbs_private *priv);
 int lbs_ret_80211_associate(struct lbs_private *priv,
 				     struct cmd_ds_command *resp);
 
-int lbs_stop_adhoc_network(struct lbs_private *priv);
-
-int lbs_send_deauthentication(struct lbs_private *priv);
-
 #endif /* _LBS_ASSOC_H */
diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c
index 75427e6..a912fb6 100644
--- a/drivers/net/wireless/libertas/cmd.c
+++ b/drivers/net/wireless/libertas/cmd.c
@@ -480,181 +480,166 @@
 	return ret;
 }
 
-static int lbs_cmd_802_11_reset(struct cmd_ds_command *cmd, int cmd_action)
+/**
+ *  @brief Set an SNMP MIB value
+ *
+ *  @param priv    	A pointer to struct lbs_private structure
+ *  @param oid  	The OID to set in the firmware
+ *  @param val  	Value to set the OID to
+ *
+ *  @return 	   	0 on success, error on failure
+ */
+int lbs_set_snmp_mib(struct lbs_private *priv, u32 oid, u16 val)
 {
-	struct cmd_ds_802_11_reset *reset = &cmd->params.reset;
+	struct cmd_ds_802_11_snmp_mib cmd;
+	int ret;
 
 	lbs_deb_enter(LBS_DEB_CMD);
 
-	cmd->command = cpu_to_le16(CMD_802_11_RESET);
-	cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_reset) + S_DS_GEN);
-	reset->action = cpu_to_le16(cmd_action);
+	memset(&cmd, 0, sizeof (cmd));
+	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+	cmd.action = cpu_to_le16(CMD_ACT_SET);
+	cmd.oid = cpu_to_le16((u16) oid);
 
-	lbs_deb_leave(LBS_DEB_CMD);
-	return 0;
-}
-
-static int lbs_cmd_802_11_snmp_mib(struct lbs_private *priv,
-				    struct cmd_ds_command *cmd,
-				    int cmd_action,
-				    int cmd_oid, void *pdata_buf)
-{
-	struct cmd_ds_802_11_snmp_mib *pSNMPMIB = &cmd->params.smib;
-	u8 ucTemp;
-
-	lbs_deb_enter(LBS_DEB_CMD);
-
-	lbs_deb_cmd("SNMP_CMD: cmd_oid = 0x%x\n", cmd_oid);
-
-	cmd->command = cpu_to_le16(CMD_802_11_SNMP_MIB);
-	cmd->size = cpu_to_le16(sizeof(*pSNMPMIB) + S_DS_GEN);
-
-	switch (cmd_oid) {
-	case OID_802_11_INFRASTRUCTURE_MODE:
-	{
-		u8 mode = (u8) (size_t) pdata_buf;
-		pSNMPMIB->querytype = cpu_to_le16(CMD_ACT_SET);
-		pSNMPMIB->oid = cpu_to_le16((u16) DESIRED_BSSTYPE_I);
-		pSNMPMIB->bufsize = cpu_to_le16(sizeof(u8));
-		if (mode == IW_MODE_ADHOC) {
-			ucTemp = SNMP_MIB_VALUE_ADHOC;
-		} else {
-			/* Infra and Auto modes */
-			ucTemp = SNMP_MIB_VALUE_INFRA;
-		}
-
-		memmove(pSNMPMIB->value, &ucTemp, sizeof(u8));
-
+	switch (oid) {
+	case SNMP_MIB_OID_BSS_TYPE:
+		cmd.bufsize = cpu_to_le16(sizeof(u8));
+		cmd.value[0] = (val == IW_MODE_ADHOC) ? 2 : 1;
 		break;
-	}
-
-	case OID_802_11D_ENABLE:
-		{
-			u32 ulTemp;
-
-			pSNMPMIB->oid = cpu_to_le16((u16) DOT11D_I);
-
-			if (cmd_action == CMD_ACT_SET) {
-				pSNMPMIB->querytype = cpu_to_le16(CMD_ACT_SET);
-				pSNMPMIB->bufsize = cpu_to_le16(sizeof(u16));
-				ulTemp = *(u32 *)pdata_buf;
-				*((__le16 *)(pSNMPMIB->value)) =
-				    cpu_to_le16((u16) ulTemp);
-			}
-			break;
-		}
-
-	case OID_802_11_FRAGMENTATION_THRESHOLD:
-		{
-			u32 ulTemp;
-
-			pSNMPMIB->oid = cpu_to_le16((u16) FRAGTHRESH_I);
-
-			if (cmd_action == CMD_ACT_GET) {
-				pSNMPMIB->querytype = cpu_to_le16(CMD_ACT_GET);
-			} else if (cmd_action == CMD_ACT_SET) {
-				pSNMPMIB->querytype = cpu_to_le16(CMD_ACT_SET);
-				pSNMPMIB->bufsize = cpu_to_le16(sizeof(u16));
-				ulTemp = *((u32 *) pdata_buf);
-				*((__le16 *)(pSNMPMIB->value)) =
-				    cpu_to_le16((u16) ulTemp);
-
-			}
-
-			break;
-		}
-
-	case OID_802_11_RTS_THRESHOLD:
-		{
-
-			u32 ulTemp;
-			pSNMPMIB->oid = cpu_to_le16(RTSTHRESH_I);
-
-			if (cmd_action == CMD_ACT_GET) {
-				pSNMPMIB->querytype = cpu_to_le16(CMD_ACT_GET);
-			} else if (cmd_action == CMD_ACT_SET) {
-				pSNMPMIB->querytype = cpu_to_le16(CMD_ACT_SET);
-				pSNMPMIB->bufsize = cpu_to_le16(sizeof(u16));
-				ulTemp = *((u32 *)pdata_buf);
-				*(__le16 *)(pSNMPMIB->value) =
-				    cpu_to_le16((u16) ulTemp);
-
-			}
-			break;
-		}
-	case OID_802_11_TX_RETRYCOUNT:
-		pSNMPMIB->oid = cpu_to_le16((u16) SHORT_RETRYLIM_I);
-
-		if (cmd_action == CMD_ACT_GET) {
-			pSNMPMIB->querytype = cpu_to_le16(CMD_ACT_GET);
-		} else if (cmd_action == CMD_ACT_SET) {
-			pSNMPMIB->querytype = cpu_to_le16(CMD_ACT_SET);
-			pSNMPMIB->bufsize = cpu_to_le16(sizeof(u16));
-			*((__le16 *)(pSNMPMIB->value)) =
-			    cpu_to_le16((u16) priv->txretrycount);
-		}
-
+	case SNMP_MIB_OID_11D_ENABLE:
+	case SNMP_MIB_OID_FRAG_THRESHOLD:
+	case SNMP_MIB_OID_RTS_THRESHOLD:
+	case SNMP_MIB_OID_SHORT_RETRY_LIMIT:
+	case SNMP_MIB_OID_LONG_RETRY_LIMIT:
+		cmd.bufsize = cpu_to_le16(sizeof(u16));
+		*((__le16 *)(&cmd.value)) = cpu_to_le16(val);
 		break;
 	default:
-		break;
+		lbs_deb_cmd("SNMP_CMD: (set) unhandled OID 0x%x\n", oid);
+		ret = -EINVAL;
+		goto out;
 	}
 
-	lbs_deb_cmd(
-	       "SNMP_CMD: command=0x%x, size=0x%x, seqnum=0x%x, result=0x%x\n",
-	       le16_to_cpu(cmd->command), le16_to_cpu(cmd->size),
-	       le16_to_cpu(cmd->seqnum), le16_to_cpu(cmd->result));
+	lbs_deb_cmd("SNMP_CMD: (set) oid 0x%x, oid size 0x%x, value 0x%x\n",
+		    le16_to_cpu(cmd.oid), le16_to_cpu(cmd.bufsize), val);
 
-	lbs_deb_cmd(
-	       "SNMP_CMD: action 0x%x, oid 0x%x, oidsize 0x%x, value 0x%x\n",
-	       le16_to_cpu(pSNMPMIB->querytype), le16_to_cpu(pSNMPMIB->oid),
-	       le16_to_cpu(pSNMPMIB->bufsize),
-	       le16_to_cpu(*(__le16 *) pSNMPMIB->value));
+	ret = lbs_cmd_with_response(priv, CMD_802_11_SNMP_MIB, &cmd);
 
-	lbs_deb_leave(LBS_DEB_CMD);
-	return 0;
+out:
+	lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
+	return ret;
 }
 
-static int lbs_cmd_802_11_rf_tx_power(struct cmd_ds_command *cmd,
-				       u16 cmd_action, void *pdata_buf)
+/**
+ *  @brief Get an SNMP MIB value
+ *
+ *  @param priv    	A pointer to struct lbs_private structure
+ *  @param oid  	The OID to retrieve from the firmware
+ *  @param out_val  	Location for the returned value
+ *
+ *  @return 	   	0 on success, error on failure
+ */
+int lbs_get_snmp_mib(struct lbs_private *priv, u32 oid, u16 *out_val)
 {
-
-	struct cmd_ds_802_11_rf_tx_power *prtp = &cmd->params.txp;
+	struct cmd_ds_802_11_snmp_mib cmd;
+	int ret;
 
 	lbs_deb_enter(LBS_DEB_CMD);
 
-	cmd->size =
-	    cpu_to_le16((sizeof(struct cmd_ds_802_11_rf_tx_power)) + S_DS_GEN);
-	cmd->command = cpu_to_le16(CMD_802_11_RF_TX_POWER);
-	prtp->action = cpu_to_le16(cmd_action);
+	memset(&cmd, 0, sizeof (cmd));
+	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+	cmd.action = cpu_to_le16(CMD_ACT_GET);
+	cmd.oid = cpu_to_le16(oid);
 
-	lbs_deb_cmd("RF_TX_POWER_CMD: size:%d cmd:0x%x Act:%d\n",
-		    le16_to_cpu(cmd->size), le16_to_cpu(cmd->command),
-		    le16_to_cpu(prtp->action));
+	ret = lbs_cmd_with_response(priv, CMD_802_11_SNMP_MIB, &cmd);
+	if (ret)
+		goto out;
 
-	switch (cmd_action) {
-	case CMD_ACT_TX_POWER_OPT_GET:
-		prtp->action = cpu_to_le16(CMD_ACT_GET);
-		prtp->currentlevel = 0;
+	switch (le16_to_cpu(cmd.bufsize)) {
+	case sizeof(u8):
+		if (oid == SNMP_MIB_OID_BSS_TYPE) {
+			if (cmd.value[0] == 2)
+				*out_val = IW_MODE_ADHOC;
+			else
+				*out_val = IW_MODE_INFRA;
+		} else
+			*out_val = cmd.value[0];
 		break;
-
-	case CMD_ACT_TX_POWER_OPT_SET_HIGH:
-		prtp->action = cpu_to_le16(CMD_ACT_SET);
-		prtp->currentlevel = cpu_to_le16(CMD_ACT_TX_POWER_INDEX_HIGH);
+	case sizeof(u16):
+		*out_val = le16_to_cpu(*((__le16 *)(&cmd.value)));
 		break;
-
-	case CMD_ACT_TX_POWER_OPT_SET_MID:
-		prtp->action = cpu_to_le16(CMD_ACT_SET);
-		prtp->currentlevel = cpu_to_le16(CMD_ACT_TX_POWER_INDEX_MID);
-		break;
-
-	case CMD_ACT_TX_POWER_OPT_SET_LOW:
-		prtp->action = cpu_to_le16(CMD_ACT_SET);
-		prtp->currentlevel = cpu_to_le16(*((u16 *) pdata_buf));
+	default:
+		lbs_deb_cmd("SNMP_CMD: (get) unhandled OID 0x%x size %d\n",
+		            oid, le16_to_cpu(cmd.bufsize));
 		break;
 	}
 
+out:
+	lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
+	return ret;
+}
+
+/**
+ *  @brief Get the min, max, and current TX power
+ *
+ *  @param priv    	A pointer to struct lbs_private structure
+ *  @param curlevel  	Current power level in dBm
+ *  @param minlevel  	Minimum supported power level in dBm (optional)
+ *  @param maxlevel  	Maximum supported power level in dBm (optional)
+ *
+ *  @return 	   	0 on success, error on failure
+ */
+int lbs_get_tx_power(struct lbs_private *priv, s16 *curlevel, s16 *minlevel,
+		     s16 *maxlevel)
+{
+	struct cmd_ds_802_11_rf_tx_power cmd;
+	int ret;
+
+	lbs_deb_enter(LBS_DEB_CMD);
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+	cmd.action = cpu_to_le16(CMD_ACT_GET);
+
+	ret = lbs_cmd_with_response(priv, CMD_802_11_RF_TX_POWER, &cmd);
+	if (ret == 0) {
+		*curlevel = le16_to_cpu(cmd.curlevel);
+		if (minlevel)
+			*minlevel = le16_to_cpu(cmd.minlevel);
+		if (maxlevel)
+			*maxlevel = le16_to_cpu(cmd.maxlevel);
+	}
+
 	lbs_deb_leave(LBS_DEB_CMD);
-	return 0;
+	return ret;
+}
+
+/**
+ *  @brief Set the TX power
+ *
+ *  @param priv    	A pointer to struct lbs_private structure
+ *  @param dbm  	The desired power level in dBm
+ *
+ *  @return 	   	0 on success, error on failure
+ */
+int lbs_set_tx_power(struct lbs_private *priv, s16 dbm)
+{
+	struct cmd_ds_802_11_rf_tx_power cmd;
+	int ret;
+
+	lbs_deb_enter(LBS_DEB_CMD);
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+	cmd.action = cpu_to_le16(CMD_ACT_SET);
+	cmd.curlevel = cpu_to_le16(dbm);
+
+	lbs_deb_cmd("SET_RF_TX_POWER: %d dBm\n", dbm);
+
+	ret = lbs_cmd_with_response(priv, CMD_802_11_RF_TX_POWER, &cmd);
+
+	lbs_deb_leave(LBS_DEB_CMD);
+	return ret;
 }
 
 static int lbs_cmd_802_11_monitor_mode(struct cmd_ds_command *cmd,
@@ -1033,9 +1018,9 @@
 	return ret;
 }
 
-int lbs_mesh_config_send(struct lbs_private *priv,
-			 struct cmd_ds_mesh_config *cmd,
-			 uint16_t action, uint16_t type)
+static int __lbs_mesh_config_send(struct lbs_private *priv,
+				  struct cmd_ds_mesh_config *cmd,
+				  uint16_t action, uint16_t type)
 {
 	int ret;
 
@@ -1054,6 +1039,19 @@
 	return ret;
 }
 
+int lbs_mesh_config_send(struct lbs_private *priv,
+			 struct cmd_ds_mesh_config *cmd,
+			 uint16_t action, uint16_t type)
+{
+	int ret;
+
+	if (!(priv->fwcapinfo & FW_CAPINFO_PERSISTENT_CONFIG))
+		return -EOPNOTSUPP;
+
+	ret = __lbs_mesh_config_send(priv, cmd, action, type);
+	return ret;
+}
+
 /* This function is the CMD_MESH_CONFIG legacy function.  It only handles the
  * START and STOP actions.  The extended actions supported by CMD_MESH_CONFIG
  * are all handled by preparing a struct cmd_ds_mesh_config and passing it to
@@ -1095,7 +1093,7 @@
 		    action, priv->mesh_tlv, chan,
 		    escape_essid(priv->mesh_ssid, priv->mesh_ssid_len));
 
-	return lbs_mesh_config_send(priv, &cmd, action, priv->mesh_tlv);
+	return __lbs_mesh_config_send(priv, &cmd, action, priv->mesh_tlv);
 }
 
 static int lbs_cmd_bcn_ctrl(struct lbs_private * priv,
@@ -1256,41 +1254,47 @@
 	priv->cur_cmd = NULL;
 }
 
-int lbs_set_radio_control(struct lbs_private *priv)
+int lbs_set_radio(struct lbs_private *priv, u8 preamble, u8 radio_on)
 {
-	int ret = 0;
 	struct cmd_ds_802_11_radio_control cmd;
+	int ret = -EINVAL;
 
 	lbs_deb_enter(LBS_DEB_CMD);
 
 	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
 	cmd.action = cpu_to_le16(CMD_ACT_SET);
 
-	switch (priv->preamble) {
-	case CMD_TYPE_SHORT_PREAMBLE:
-		cmd.control = cpu_to_le16(SET_SHORT_PREAMBLE);
-		break;
-
-	case CMD_TYPE_LONG_PREAMBLE:
-		cmd.control = cpu_to_le16(SET_LONG_PREAMBLE);
-		break;
-
-	case CMD_TYPE_AUTO_PREAMBLE:
-	default:
-		cmd.control = cpu_to_le16(SET_AUTO_PREAMBLE);
-		break;
+	/* Only v8 and below support setting the preamble */
+	if (priv->fwrelease < 0x09000000) {
+		switch (preamble) {
+		case RADIO_PREAMBLE_SHORT:
+			if (!(priv->capability & WLAN_CAPABILITY_SHORT_PREAMBLE))
+				goto out;
+			/* Fall through */
+		case RADIO_PREAMBLE_AUTO:
+		case RADIO_PREAMBLE_LONG:
+			cmd.control = cpu_to_le16(preamble);
+			break;
+		default:
+			goto out;
+		}
 	}
 
-	if (priv->radioon)
-		cmd.control |= cpu_to_le16(TURN_ON_RF);
-	else
-		cmd.control &= cpu_to_le16(~TURN_ON_RF);
+	if (radio_on)
+		cmd.control |= cpu_to_le16(0x1);
+	else {
+		cmd.control &= cpu_to_le16(~0x1);
+		priv->txpower_cur = 0;
+	}
 
-	lbs_deb_cmd("RADIO_SET: radio %d, preamble %d\n", priv->radioon,
-		    priv->preamble);
+	lbs_deb_cmd("RADIO_CONTROL: radio %s, preamble %d\n",
+		    radio_on ? "ON" : "OFF", preamble);
+
+	priv->radio_on = radio_on;
 
 	ret = lbs_cmd_with_response(priv, CMD_802_11_RADIO_CONTROL, &cmd);
 
+out:
 	lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
 	return ret;
 }
@@ -1380,55 +1384,25 @@
 		ret = lbs_cmd_80211_associate(priv, cmdptr, pdata_buf);
 		break;
 
-	case CMD_802_11_DEAUTHENTICATE:
-		ret = lbs_cmd_80211_deauthenticate(priv, cmdptr);
-		break;
-
-	case CMD_802_11_AD_HOC_START:
-		ret = lbs_cmd_80211_ad_hoc_start(priv, cmdptr, pdata_buf);
-		break;
-
-	case CMD_802_11_RESET:
-		ret = lbs_cmd_802_11_reset(cmdptr, cmd_action);
-		break;
-
 	case CMD_802_11_AUTHENTICATE:
 		ret = lbs_cmd_80211_authenticate(priv, cmdptr, pdata_buf);
 		break;
 
-	case CMD_802_11_SNMP_MIB:
-		ret = lbs_cmd_802_11_snmp_mib(priv, cmdptr,
-					       cmd_action, cmd_oid, pdata_buf);
-		break;
-
 	case CMD_MAC_REG_ACCESS:
 	case CMD_BBP_REG_ACCESS:
 	case CMD_RF_REG_ACCESS:
 		ret = lbs_cmd_reg_access(cmdptr, cmd_action, pdata_buf);
 		break;
 
-	case CMD_802_11_RF_TX_POWER:
-		ret = lbs_cmd_802_11_rf_tx_power(cmdptr,
-						 cmd_action, pdata_buf);
-		break;
-
 	case CMD_802_11_MONITOR_MODE:
 		ret = lbs_cmd_802_11_monitor_mode(cmdptr,
 				          cmd_action, pdata_buf);
 		break;
 
-	case CMD_802_11_AD_HOC_JOIN:
-		ret = lbs_cmd_80211_ad_hoc_join(priv, cmdptr, pdata_buf);
-		break;
-
 	case CMD_802_11_RSSI:
 		ret = lbs_cmd_802_11_rssi(priv, cmdptr);
 		break;
 
-	case CMD_802_11_AD_HOC_STOP:
-		ret = lbs_cmd_80211_ad_hoc_stop(cmdptr);
-		break;
-
 	case CMD_802_11_SET_AFC:
 	case CMD_802_11_GET_AFC:
 
@@ -1953,6 +1927,70 @@
 }
 
 
+/**
+ * @brief Configures the transmission power control functionality.
+ *
+ * @param priv		A pointer to struct lbs_private structure
+ * @param enable	Transmission power control enable
+ * @param p0		Power level when link quality is good (dBm).
+ * @param p1		Power level when link quality is fair (dBm).
+ * @param p2		Power level when link quality is poor (dBm).
+ * @param usesnr	Use Signal to Noise Ratio in TPC
+ *
+ * @return 0 on success
+ */
+int lbs_set_tpc_cfg(struct lbs_private *priv, int enable, int8_t p0, int8_t p1,
+		int8_t p2, int usesnr)
+{
+	struct cmd_ds_802_11_tpc_cfg cmd;
+	int ret;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+	cmd.action = cpu_to_le16(CMD_ACT_SET);
+	cmd.enable = !!enable;
+	cmd.usesnr = !!usesnr;
+	cmd.P0 = p0;
+	cmd.P1 = p1;
+	cmd.P2 = p2;
+
+	ret = lbs_cmd_with_response(priv, CMD_802_11_TPC_CFG, &cmd);
+
+	return ret;
+}
+
+/**
+ * @brief Configures the power adaptation settings.
+ *
+ * @param priv		A pointer to struct lbs_private structure
+ * @param enable	Power adaptation enable
+ * @param p0		Power level for 1, 2, 5.5 and 11 Mbps (dBm).
+ * @param p1		Power level for 6, 9, 12, 18, 22, 24 and 36 Mbps (dBm).
+ * @param p2		Power level for 48 and 54 Mbps (dBm).
+ *
+ * @return 0 on Success
+ */
+
+int lbs_set_power_adapt_cfg(struct lbs_private *priv, int enable, int8_t p0,
+		int8_t p1, int8_t p2)
+{
+	struct cmd_ds_802_11_pa_cfg cmd;
+	int ret;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+	cmd.action = cpu_to_le16(CMD_ACT_SET);
+	cmd.enable = !!enable;
+	cmd.P0 = p0;
+	cmd.P1 = p1;
+	cmd.P2 = p2;
+
+	ret = lbs_cmd_with_response(priv, CMD_802_11_PA_CFG , &cmd);
+
+	return ret;
+}
+
+
 static struct cmd_ctrl_node *__lbs_cmd_async(struct lbs_private *priv,
 	uint16_t command, struct cmd_header *in_cmd, int in_cmd_size,
 	int (*callback)(struct lbs_private *, unsigned long, struct cmd_header *),
diff --git a/drivers/net/wireless/libertas/cmd.h b/drivers/net/wireless/libertas/cmd.h
index a53b51f..36be4c9 100644
--- a/drivers/net/wireless/libertas/cmd.h
+++ b/drivers/net/wireless/libertas/cmd.h
@@ -26,6 +26,18 @@
 	      int (*callback)(struct lbs_private *, unsigned long, struct cmd_header *),
 	      unsigned long callback_arg);
 
+int lbs_set_power_adapt_cfg(struct lbs_private *priv, int enable, int8_t p0,
+		int8_t p1, int8_t p2);
+
+int lbs_set_tpc_cfg(struct lbs_private *priv, int enable, int8_t p0, int8_t p1,
+		int8_t p2, int usesnr);
+
+int lbs_set_power_adapt_cfg(struct lbs_private *priv, int enable, int8_t p0,
+		int8_t p1, int8_t p2);
+
+int lbs_set_tpc_cfg(struct lbs_private *priv, int enable, int8_t p0, int8_t p1,
+		int8_t p2, int usesnr);
+
 int lbs_cmd_copyback(struct lbs_private *priv, unsigned long extra,
 		     struct cmd_header *resp);
 
@@ -61,4 +73,14 @@
 int lbs_cmd_802_11_key_material(struct lbs_private *priv, uint16_t cmd_action,
 				struct assoc_request *assoc);
 
+int lbs_get_tx_power(struct lbs_private *priv, s16 *curlevel, s16 *minlevel,
+		     s16 *maxlevel);
+int lbs_set_tx_power(struct lbs_private *priv, s16 dbm);
+
+int lbs_set_radio(struct lbs_private *priv, u8 preamble, u8 radio_on);
+
+int lbs_set_snmp_mib(struct lbs_private *priv, u32 oid, u16 val);
+
+int lbs_get_snmp_mib(struct lbs_private *priv, u32 oid, u16 *out_val);
+
 #endif /* _LBS_CMD_H */
diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c
index 24de3c3..bcf2a97 100644
--- a/drivers/net/wireless/libertas/cmdresp.c
+++ b/drivers/net/wireless/libertas/cmdresp.c
@@ -146,63 +146,6 @@
 	return ret;
 }
 
-static int lbs_ret_802_11_snmp_mib(struct lbs_private *priv,
-				    struct cmd_ds_command *resp)
-{
-	struct cmd_ds_802_11_snmp_mib *smib = &resp->params.smib;
-	u16 oid = le16_to_cpu(smib->oid);
-	u16 querytype = le16_to_cpu(smib->querytype);
-
-	lbs_deb_enter(LBS_DEB_CMD);
-
-	lbs_deb_cmd("SNMP_RESP: oid 0x%x, querytype 0x%x\n", oid,
-	       querytype);
-	lbs_deb_cmd("SNMP_RESP: Buf size %d\n", le16_to_cpu(smib->bufsize));
-
-	if (querytype == CMD_ACT_GET) {
-		switch (oid) {
-		case FRAGTHRESH_I:
-			priv->fragthsd =
-				le16_to_cpu(*((__le16 *)(smib->value)));
-			lbs_deb_cmd("SNMP_RESP: frag threshold %u\n",
-				    priv->fragthsd);
-			break;
-		case RTSTHRESH_I:
-			priv->rtsthsd =
-				le16_to_cpu(*((__le16 *)(smib->value)));
-			lbs_deb_cmd("SNMP_RESP: rts threshold %u\n",
-				    priv->rtsthsd);
-			break;
-		case SHORT_RETRYLIM_I:
-			priv->txretrycount =
-				le16_to_cpu(*((__le16 *)(smib->value)));
-			lbs_deb_cmd("SNMP_RESP: tx retry count %u\n",
-				    priv->rtsthsd);
-			break;
-		default:
-			break;
-		}
-	}
-
-	lbs_deb_enter(LBS_DEB_CMD);
-	return 0;
-}
-
-static int lbs_ret_802_11_rf_tx_power(struct lbs_private *priv,
-				       struct cmd_ds_command *resp)
-{
-	struct cmd_ds_802_11_rf_tx_power *rtp = &resp->params.txp;
-
-	lbs_deb_enter(LBS_DEB_CMD);
-
-	priv->txpowerlevel = le16_to_cpu(rtp->currentlevel);
-
-	lbs_deb_cmd("TX power currently %d\n", priv->txpowerlevel);
-
-	lbs_deb_leave(LBS_DEB_CMD);
-	return 0;
-}
-
 static int lbs_ret_802_11_rssi(struct lbs_private *priv,
 				struct cmd_ds_command *resp)
 {
@@ -273,24 +216,6 @@
 		ret = lbs_ret_80211_associate(priv, resp);
 		break;
 
-	case CMD_RET(CMD_802_11_DISASSOCIATE):
-	case CMD_RET(CMD_802_11_DEAUTHENTICATE):
-		ret = lbs_ret_80211_disassociate(priv);
-		break;
-
-	case CMD_RET(CMD_802_11_AD_HOC_START):
-	case CMD_RET(CMD_802_11_AD_HOC_JOIN):
-		ret = lbs_ret_80211_ad_hoc_start(priv, resp);
-		break;
-
-	case CMD_RET(CMD_802_11_SNMP_MIB):
-		ret = lbs_ret_802_11_snmp_mib(priv, resp);
-		break;
-
-	case CMD_RET(CMD_802_11_RF_TX_POWER):
-		ret = lbs_ret_802_11_rf_tx_power(priv, resp);
-		break;
-
 	case CMD_RET(CMD_802_11_SET_AFC):
 	case CMD_RET(CMD_802_11_GET_AFC):
 		spin_lock_irqsave(&priv->driver_lock, flags);
@@ -300,7 +225,6 @@
 
 		break;
 
-	case CMD_RET(CMD_802_11_RESET):
 	case CMD_RET(CMD_802_11_AUTHENTICATE):
 	case CMD_RET(CMD_802_11_BEACON_STOP):
 		break;
@@ -309,10 +233,6 @@
 		ret = lbs_ret_802_11_rssi(priv, resp);
 		break;
 
-	case CMD_RET(CMD_802_11_AD_HOC_STOP):
-		ret = lbs_ret_80211_ad_hoc_stop(priv);
-		break;
-
 	case CMD_RET(CMD_802_11D_DOMAIN_INFO):
 		ret = lbs_ret_802_11d_domain_info(resp);
 		break;
diff --git a/drivers/net/wireless/libertas/decl.h b/drivers/net/wireless/libertas/decl.h
index a8ac974..1a8888c 100644
--- a/drivers/net/wireless/libertas/decl.h
+++ b/drivers/net/wireless/libertas/decl.h
@@ -34,7 +34,6 @@
 void lbs_queue_event(struct lbs_private *priv, u32 event);
 void lbs_notify_command_response(struct lbs_private *priv, u8 resp_idx);
 
-int lbs_set_radio_control(struct lbs_private *priv);
 u32 lbs_fw_index_to_data_rate(u8 index);
 u8 lbs_data_rate_to_fw_index(u32 rate);
 
diff --git a/drivers/net/wireless/libertas/defs.h b/drivers/net/wireless/libertas/defs.h
index 12e6875..076a636 100644
--- a/drivers/net/wireless/libertas/defs.h
+++ b/drivers/net/wireless/libertas/defs.h
@@ -189,6 +189,14 @@
 #define MRVDRV_CMD_UPLD_RDY		0x0008
 #define MRVDRV_CARDEVENT		0x0010
 
+/* Automatic TX control default levels */
+#define POW_ADAPT_DEFAULT_P0 13
+#define POW_ADAPT_DEFAULT_P1 15
+#define POW_ADAPT_DEFAULT_P2 18
+#define TPC_DEFAULT_P0 5
+#define TPC_DEFAULT_P1 10
+#define TPC_DEFAULT_P2 13
+
 /** TxPD status */
 
 /*	Station firmware use TxPD status field to report final Tx transmit
@@ -243,6 +251,9 @@
 
 #define	CMD_F_HOSTCMD		(1 << 0)
 #define FW_CAPINFO_WPA  	(1 << 0)
+#define FW_CAPINFO_FIRMWARE_UPGRADE	(1 << 13)
+#define FW_CAPINFO_BOOT2_UPGRADE	(1<<14)
+#define FW_CAPINFO_PERSISTENT_CONFIG	(1<<15)
 
 #define KEY_LEN_WPA_AES			16
 #define KEY_LEN_WPA_TKIP		32
@@ -316,7 +327,8 @@
 enum DNLD_STATE {
 	DNLD_RES_RECEIVED,
 	DNLD_DATA_SENT,
-	DNLD_CMD_SENT
+	DNLD_CMD_SENT,
+	DNLD_BOOTCMD_SENT,
 };
 
 /** LBS_MEDIA_STATE */
@@ -339,27 +351,6 @@
 	MVMS_EVENT
 };
 
-/** SNMP_MIB_INDEX_e */
-enum SNMP_MIB_INDEX_e {
-	DESIRED_BSSTYPE_I = 0,
-	OP_RATESET_I,
-	BCNPERIOD_I,
-	DTIMPERIOD_I,
-	ASSOCRSP_TIMEOUT_I,
-	RTSTHRESH_I,
-	SHORT_RETRYLIM_I,
-	LONG_RETRYLIM_I,
-	FRAGTHRESH_I,
-	DOT11D_I,
-	DOT11H_I,
-	MANUFID_I,
-	PRODID_I,
-	MANUF_OUI_I,
-	MANUF_NAME_I,
-	MANUF_PRODNAME_I,
-	MANUF_PRODVER_I,
-};
-
 /** KEY_TYPE_ID */
 enum KEY_TYPE_ID {
 	KEY_TYPE_ID_WEP = 0,
@@ -374,12 +365,6 @@
 	KEY_INFO_WPA_ENABLED = 0x04
 };
 
-/** SNMP_MIB_VALUE_e */
-enum SNMP_MIB_VALUE_e {
-	SNMP_MIB_VALUE_INFRA = 1,
-	SNMP_MIB_VALUE_ADHOC
-};
-
 /* Default values for fwt commands. */
 #define FWT_DEFAULT_METRIC 0
 #define FWT_DEFAULT_DIR 1
diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h
index f5bb40c..f6f3753 100644
--- a/drivers/net/wireless/libertas/dev.h
+++ b/drivers/net/wireless/libertas/dev.h
@@ -58,6 +58,7 @@
 	u8 WPA2enabled;
 	u8 wep_enabled;
 	u8 auth_mode;
+	u32 key_mgmt;
 };
 
 /** Current Basic Service Set State Structure */
@@ -240,9 +241,6 @@
 	uint16_t enablehwauto;
 	uint16_t ratebitmap;
 
-	u32 fragthsd;
-	u32 rtsthsd;
-
 	u8 txretrycount;
 
 	/** Tx-related variables (for single packet tx) */
@@ -253,7 +251,9 @@
 	u32 connect_status;
 	u32 mesh_connect_status;
 	u16 regioncode;
-	u16 txpowerlevel;
+	s16 txpower_cur;
+	s16 txpower_min;
+	s16 txpower_max;
 
 	/** POWER MANAGEMENT AND PnP SUPPORT */
 	u8 surpriseremoved;
@@ -291,8 +291,7 @@
 	u16 nextSNRNF;
 	u16 numSNRNF;
 
-	u8 radioon;
-	u32 preamble;
+	u8 radio_on;
 
 	/** data rate stuff */
 	u8 cur_rate;
diff --git a/drivers/net/wireless/libertas/host.h b/drivers/net/wireless/libertas/host.h
index c92e41b..5004d76 100644
--- a/drivers/net/wireless/libertas/host.h
+++ b/drivers/net/wireless/libertas/host.h
@@ -9,17 +9,6 @@
 #define DEFAULT_AD_HOC_CHANNEL			6
 #define	DEFAULT_AD_HOC_CHANNEL_A		36
 
-/** IEEE 802.11 oids */
-#define OID_802_11_SSID				0x00008002
-#define OID_802_11_INFRASTRUCTURE_MODE		0x00008008
-#define OID_802_11_FRAGMENTATION_THRESHOLD	0x00008009
-#define OID_802_11_RTS_THRESHOLD		0x0000800A
-#define OID_802_11_TX_ANTENNA_SELECTED		0x0000800D
-#define OID_802_11_SUPPORTED_RATES		0x0000800E
-#define OID_802_11_STATISTICS			0x00008012
-#define OID_802_11_TX_RETRYCOUNT		0x0000801D
-#define OID_802_11D_ENABLE			0x00008020
-
 #define CMD_OPTION_WAITFORRSP			0x0002
 
 /** Host command IDs */
@@ -61,7 +50,6 @@
 #define CMD_RF_REG_MAP				0x0023
 #define CMD_802_11_DEAUTHENTICATE		0x0024
 #define CMD_802_11_REASSOCIATE			0x0025
-#define CMD_802_11_DISASSOCIATE			0x0026
 #define CMD_MAC_CONTROL				0x0028
 #define CMD_802_11_AD_HOC_START			0x002b
 #define CMD_802_11_AD_HOC_JOIN			0x002c
@@ -84,6 +72,7 @@
 #define CMD_802_11_INACTIVITY_TIMEOUT		0x0067
 #define CMD_802_11_SLEEP_PERIOD			0x0068
 #define CMD_802_11_TPC_CFG			0x0072
+#define CMD_802_11_PA_CFG			0x0073
 #define CMD_802_11_FW_WAKE_METHOD		0x0074
 #define CMD_802_11_SUBSCRIBE_EVENT		0x0075
 #define CMD_802_11_RATE_ADAPT_RATESET		0x0076
@@ -153,11 +142,6 @@
 #define CMD_ACT_MAC_ALL_MULTICAST_ENABLE	0x0100
 #define CMD_ACT_MAC_STRICT_PROTECTION_ENABLE	0x0400
 
-/* Define action or option for CMD_802_11_RADIO_CONTROL */
-#define CMD_TYPE_AUTO_PREAMBLE		0x0001
-#define CMD_TYPE_SHORT_PREAMBLE		0x0002
-#define CMD_TYPE_LONG_PREAMBLE		0x0003
-
 /* Event flags for CMD_802_11_SUBSCRIBE_EVENT */
 #define CMD_SUBSCRIBE_RSSI_LOW		0x0001
 #define CMD_SUBSCRIBE_SNR_LOW		0x0002
@@ -166,28 +150,14 @@
 #define CMD_SUBSCRIBE_RSSI_HIGH		0x0010
 #define CMD_SUBSCRIBE_SNR_HIGH		0x0020
 
-#define TURN_ON_RF			0x01
-#define RADIO_ON			0x01
-#define RADIO_OFF			0x00
-
-#define SET_AUTO_PREAMBLE		0x05
-#define SET_SHORT_PREAMBLE		0x03
-#define SET_LONG_PREAMBLE		0x01
+#define RADIO_PREAMBLE_LONG	0x00
+#define RADIO_PREAMBLE_SHORT	0x02
+#define RADIO_PREAMBLE_AUTO	0x04
 
 /* Define action or option for CMD_802_11_RF_CHANNEL */
 #define CMD_OPT_802_11_RF_CHANNEL_GET	0x00
 #define CMD_OPT_802_11_RF_CHANNEL_SET	0x01
 
-/* Define action or option for CMD_802_11_RF_TX_POWER */
-#define CMD_ACT_TX_POWER_OPT_GET	0x0000
-#define CMD_ACT_TX_POWER_OPT_SET_HIGH	0x8007
-#define CMD_ACT_TX_POWER_OPT_SET_MID	0x8004
-#define CMD_ACT_TX_POWER_OPT_SET_LOW	0x8000
-
-#define CMD_ACT_TX_POWER_INDEX_HIGH	0x0007
-#define CMD_ACT_TX_POWER_INDEX_MID	0x0004
-#define CMD_ACT_TX_POWER_INDEX_LOW	0x0000
-
 /* Define action or option for CMD_802_11_DATA_RATE */
 #define CMD_ACT_SET_TX_AUTO		0x0000
 #define CMD_ACT_SET_TX_FIX_RATE		0x0001
@@ -210,6 +180,19 @@
 #define CMD_WAKE_METHOD_COMMAND_INT	0x0001
 #define CMD_WAKE_METHOD_GPIO		0x0002
 
+/* Object IDs for CMD_802_11_SNMP_MIB */
+#define SNMP_MIB_OID_BSS_TYPE		0x0000
+#define SNMP_MIB_OID_OP_RATE_SET	0x0001
+#define SNMP_MIB_OID_BEACON_PERIOD	0x0002  /* Reserved on v9+ */
+#define SNMP_MIB_OID_DTIM_PERIOD	0x0003  /* Reserved on v9+ */
+#define SNMP_MIB_OID_ASSOC_TIMEOUT	0x0004  /* Reserved on v9+ */
+#define SNMP_MIB_OID_RTS_THRESHOLD	0x0005
+#define SNMP_MIB_OID_SHORT_RETRY_LIMIT	0x0006
+#define SNMP_MIB_OID_LONG_RETRY_LIMIT	0x0007
+#define SNMP_MIB_OID_FRAG_THRESHOLD	0x0008
+#define SNMP_MIB_OID_11D_ENABLE		0x0009
+#define SNMP_MIB_OID_11H_ENABLE		0x000A
+
 /* Define action or option for CMD_BT_ACCESS */
 enum cmd_bt_access_opts {
 	/* The bt commands start at 5 instead of 1 because the old dft commands
diff --git a/drivers/net/wireless/libertas/hostcmd.h b/drivers/net/wireless/libertas/hostcmd.h
index 913b480..d9f9a12 100644
--- a/drivers/net/wireless/libertas/hostcmd.h
+++ b/drivers/net/wireless/libertas/hostcmd.h
@@ -151,10 +151,6 @@
 	__le32 fwcapinfo;
 } __attribute__ ((packed));
 
-struct cmd_ds_802_11_reset {
-	__le16 action;
-};
-
 struct cmd_ds_802_11_subscribe_event {
 	struct cmd_header hdr;
 
@@ -232,7 +228,9 @@
 };
 
 struct cmd_ds_802_11_deauthenticate {
-	u8 macaddr[6];
+	struct cmd_header hdr;
+
+	u8 macaddr[ETH_ALEN];
 	__le16 reasoncode;
 };
 
@@ -251,20 +249,10 @@
 #endif
 } __attribute__ ((packed));
 
-struct cmd_ds_802_11_disassociate {
-	u8 destmacaddr[6];
-	__le16 reasoncode;
-};
-
 struct cmd_ds_802_11_associate_rsp {
 	struct ieeetypes_assocrsp assocRsp;
 };
 
-struct cmd_ds_802_11_ad_hoc_result {
-	u8 pad[3];
-	u8 bssid[ETH_ALEN];
-};
-
 struct cmd_ds_802_11_set_wep {
 	struct cmd_header hdr;
 
@@ -309,7 +297,9 @@
 };
 
 struct cmd_ds_802_11_snmp_mib {
-	__le16 querytype;
+	struct cmd_header hdr;
+
+	__le16 action;
 	__le16 oid;
 	__le16 bufsize;
 	u8 value[128];
@@ -435,8 +425,12 @@
 };
 
 struct cmd_ds_802_11_rf_tx_power {
+	struct cmd_header hdr;
+
 	__le16 action;
-	__le16 currentlevel;
+	__le16 curlevel;
+	s8 maxlevel;
+	s8 minlevel;
 };
 
 struct cmd_ds_802_11_rf_antenna {
@@ -507,10 +501,12 @@
 };
 
 struct cmd_ds_802_11_ad_hoc_start {
+	struct cmd_header hdr;
+
 	u8 ssid[IW_ESSID_MAX_SIZE];
 	u8 bsstype;
 	__le16 beaconperiod;
-	u8 dtimperiod;
+	u8 dtimperiod;   /* Reserved on v9 and later */
 	union IEEEtypes_ssparamset ssparamset;
 	union ieeetypes_phyparamset phyparamset;
 	__le16 probedelay;
@@ -519,9 +515,16 @@
 	u8 tlv_memory_size_pad[100];
 } __attribute__ ((packed));
 
+struct cmd_ds_802_11_ad_hoc_result {
+	struct cmd_header hdr;
+
+	u8 pad[3];
+	u8 bssid[ETH_ALEN];
+};
+
 struct adhoc_bssdesc {
-	u8 bssid[6];
-	u8 ssid[32];
+	u8 bssid[ETH_ALEN];
+	u8 ssid[IW_ESSID_MAX_SIZE];
 	u8 type;
 	__le16 beaconperiod;
 	u8 dtimperiod;
@@ -539,10 +542,15 @@
 } __attribute__ ((packed));
 
 struct cmd_ds_802_11_ad_hoc_join {
-	struct adhoc_bssdesc bss;
-	__le16 failtimeout;
-	__le16 probedelay;
+	struct cmd_header hdr;
 
+	struct adhoc_bssdesc bss;
+	__le16 failtimeout;   /* Reserved on v9 and later */
+	__le16 probedelay;    /* Reserved on v9 and later */
+} __attribute__ ((packed));
+
+struct cmd_ds_802_11_ad_hoc_stop {
+	struct cmd_header hdr;
 } __attribute__ ((packed));
 
 struct cmd_ds_802_11_enable_rsn {
@@ -597,14 +605,28 @@
 } __attribute__ ((packed));
 
 struct cmd_ds_802_11_tpc_cfg {
+	struct cmd_header hdr;
+
 	__le16 action;
-	u8 enable;
-	s8 P0;
-	s8 P1;
-	s8 P2;
-	u8 usesnr;
+	uint8_t enable;
+	int8_t P0;
+	int8_t P1;
+	int8_t P2;
+	uint8_t usesnr;
 } __attribute__ ((packed));
 
+
+struct cmd_ds_802_11_pa_cfg {
+	struct cmd_header hdr;
+
+	__le16 action;
+	uint8_t enable;
+	int8_t P0;
+	int8_t P1;
+	int8_t P2;
+} __attribute__ ((packed));
+
+
 struct cmd_ds_802_11_led_ctrl {
 	__le16 action;
 	__le16 numled;
@@ -693,21 +715,13 @@
 	union {
 		struct cmd_ds_802_11_ps_mode psmode;
 		struct cmd_ds_802_11_associate associate;
-		struct cmd_ds_802_11_deauthenticate deauth;
-		struct cmd_ds_802_11_ad_hoc_start ads;
-		struct cmd_ds_802_11_reset reset;
-		struct cmd_ds_802_11_ad_hoc_result result;
 		struct cmd_ds_802_11_authenticate auth;
 		struct cmd_ds_802_11_get_stat gstat;
 		struct cmd_ds_802_3_get_stat gstat_8023;
-		struct cmd_ds_802_11_snmp_mib smib;
-		struct cmd_ds_802_11_rf_tx_power txp;
 		struct cmd_ds_802_11_rf_antenna rant;
 		struct cmd_ds_802_11_monitor_mode monitor;
-		struct cmd_ds_802_11_ad_hoc_join adj;
 		struct cmd_ds_802_11_rssi rssi;
 		struct cmd_ds_802_11_rssi_rsp rssirsp;
-		struct cmd_ds_802_11_disassociate dassociate;
 		struct cmd_ds_mac_reg_access macreg;
 		struct cmd_ds_bbp_reg_access bbpreg;
 		struct cmd_ds_rf_reg_access rfreg;
diff --git a/drivers/net/wireless/libertas/if_cs.c b/drivers/net/wireless/libertas/if_cs.c
index 8941919..842a08d 100644
--- a/drivers/net/wireless/libertas/if_cs.c
+++ b/drivers/net/wireless/libertas/if_cs.c
@@ -713,7 +713,7 @@
 		ret = if_cs_send_cmd(priv, buf, nb);
 		break;
 	default:
-		lbs_pr_err("%s: unsupported type %d\n", __FUNCTION__, type);
+		lbs_pr_err("%s: unsupported type %d\n", __func__, type);
 	}
 
 	lbs_deb_leave_args(LBS_DEB_CS, "ret %d", ret);
@@ -791,7 +791,7 @@
 	tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
 	if ((ret = pcmcia_get_first_tuple(p_dev, &tuple)) != 0 ||
 	    (ret = pcmcia_get_tuple_data(p_dev, &tuple)) != 0 ||
-	    (ret = pcmcia_parse_tuple(p_dev, &tuple, &parse)) != 0)
+	    (ret = pcmcia_parse_tuple(&tuple, &parse)) != 0)
 	{
 		lbs_pr_err("error in pcmcia_get_first_tuple etc\n");
 		goto out1;
diff --git a/drivers/net/wireless/libertas/if_usb.c b/drivers/net/wireless/libertas/if_usb.c
index 632c291..cafbccb 100644
--- a/drivers/net/wireless/libertas/if_usb.c
+++ b/drivers/net/wireless/libertas/if_usb.c
@@ -39,7 +39,10 @@
 
 static void if_usb_receive(struct urb *urb);
 static void if_usb_receive_fwload(struct urb *urb);
-static int if_usb_prog_firmware(struct if_usb_card *cardp);
+static int __if_usb_prog_firmware(struct if_usb_card *cardp,
+					const char *fwname, int cmd);
+static int if_usb_prog_firmware(struct if_usb_card *cardp,
+					const char *fwname, int cmd);
 static int if_usb_host_to_card(struct lbs_private *priv, uint8_t type,
 			       uint8_t *payload, uint16_t nb);
 static int usb_tx_block(struct if_usb_card *cardp, uint8_t *payload,
@@ -48,6 +51,62 @@
 static int if_usb_submit_rx_urb(struct if_usb_card *cardp);
 static int if_usb_reset_device(struct if_usb_card *cardp);
 
+/* sysfs hooks */
+
+/**
+ *  Set function to write firmware to device's persistent memory
+ */
+static ssize_t if_usb_firmware_set(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count)
+{
+	struct lbs_private *priv = to_net_dev(dev)->priv;
+	struct if_usb_card *cardp = priv->card;
+	char fwname[FIRMWARE_NAME_MAX];
+	int ret;
+
+	sscanf(buf, "%29s", fwname); /* FIRMWARE_NAME_MAX - 1 = 29 */
+	ret = if_usb_prog_firmware(cardp, fwname, BOOT_CMD_UPDATE_FW);
+	if (ret == 0)
+		return count;
+
+	return ret;
+}
+
+/**
+ * lbs_flash_fw attribute to be exported per ethX interface through sysfs
+ * (/sys/class/net/ethX/lbs_flash_fw).  Use this like so to write firmware to
+ * the device's persistent memory:
+ * echo usb8388-5.126.0.p5.bin > /sys/class/net/ethX/lbs_flash_fw
+ */
+static DEVICE_ATTR(lbs_flash_fw, 0200, NULL, if_usb_firmware_set);
+
+/**
+ *  Set function to write firmware to device's persistent memory
+ */
+static ssize_t if_usb_boot2_set(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count)
+{
+	struct lbs_private *priv = to_net_dev(dev)->priv;
+	struct if_usb_card *cardp = priv->card;
+	char fwname[FIRMWARE_NAME_MAX];
+	int ret;
+
+	sscanf(buf, "%29s", fwname); /* FIRMWARE_NAME_MAX - 1 = 29 */
+	ret = if_usb_prog_firmware(cardp, fwname, BOOT_CMD_UPDATE_BOOT2);
+	if (ret == 0)
+		return count;
+
+	return ret;
+}
+
+/**
+ * lbs_flash_boot2 attribute to be exported per ethX interface through sysfs
+ * (/sys/class/net/ethX/lbs_flash_boot2).  Use this like so to write firmware
+ * to the device's persistent memory:
+ * echo usb8388-5.126.0.p5.bin > /sys/class/net/ethX/lbs_flash_boot2
+ */
+static DEVICE_ATTR(lbs_flash_boot2, 0200, NULL, if_usb_boot2_set);
+
 /**
  *  @brief  call back function to handle the status of the URB
  *  @param urb 		pointer to urb structure
@@ -66,10 +125,10 @@
 		lbs_deb_usb2(&urb->dev->dev, "Actual length transmitted %d\n",
 			     urb->actual_length);
 
-		/* Used for both firmware TX and regular TX.  priv isn't
-		 * valid at firmware load time.
+		/* Boot commands such as UPDATE_FW and UPDATE_BOOT2 are not
+		 * passed up to the lbs level.
 		 */
-		if (priv)
+		if (priv && priv->dnld_sent != DNLD_BOOTCMD_SENT)
 			lbs_host_to_card_done(priv);
 	} else {
 		/* print the failure status number for debug */
@@ -231,7 +290,7 @@
 	}
 
 	/* Upload firmware */
-	if (if_usb_prog_firmware(cardp)) {
+	if (__if_usb_prog_firmware(cardp, lbs_fw_name, BOOT_CMD_FW_BY_USB)) {
 		lbs_deb_usbd(&udev->dev, "FW upload failed\n");
 		goto err_prog_firmware;
 	}
@@ -260,6 +319,12 @@
 	usb_get_dev(udev);
 	usb_set_intfdata(intf, cardp);
 
+	if (device_create_file(&priv->dev->dev, &dev_attr_lbs_flash_fw))
+		lbs_pr_err("cannot register lbs_flash_fw attribute\n");
+
+	if (device_create_file(&priv->dev->dev, &dev_attr_lbs_flash_boot2))
+		lbs_pr_err("cannot register lbs_flash_boot2 attribute\n");
+
 	return 0;
 
 err_start_card:
@@ -285,6 +350,9 @@
 
 	lbs_deb_enter(LBS_DEB_MAIN);
 
+	device_remove_file(&priv->dev->dev, &dev_attr_lbs_flash_boot2);
+	device_remove_file(&priv->dev->dev, &dev_attr_lbs_flash_fw);
+
 	cardp->surprise_removed = 1;
 
 	if (priv) {
@@ -371,11 +439,10 @@
 	*(__le32 *)cardp->ep_out_buf = cpu_to_le32(CMD_TYPE_REQUEST);
 
 	cmd->command = cpu_to_le16(CMD_802_11_RESET);
-	cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_reset) + S_DS_GEN);
+	cmd->size = cpu_to_le16(sizeof(struct cmd_header));
 	cmd->result = cpu_to_le16(0);
 	cmd->seqnum = cpu_to_le16(0x5a5a);
-	cmd->params.reset.action = cpu_to_le16(CMD_ACT_HALT);
-	usb_tx_block(cardp, cardp->ep_out_buf, 4 + S_DS_GEN + sizeof(struct cmd_ds_802_11_reset));
+	usb_tx_block(cardp, cardp->ep_out_buf, 4 + sizeof(struct cmd_header));
 
 	msleep(100);
 	ret = usb_reset_device(cardp->udev);
@@ -510,7 +577,7 @@
 		if (le16_to_cpu(cardp->udev->descriptor.bcdDevice) < 0x3106) {
 			kfree_skb(skb);
 			if_usb_submit_rx_urb_fwload(cardp);
-			cardp->bootcmdresp = 1;
+			cardp->bootcmdresp = BOOT_CMD_RESP_OK;
 			lbs_deb_usbd(&cardp->udev->dev,
 				     "Received valid boot command response\n");
 			return;
@@ -526,7 +593,9 @@
 				lbs_pr_info("boot cmd response wrong magic number (0x%x)\n",
 					    le32_to_cpu(bootcmdresp.magic));
 			}
-		} else if (bootcmdresp.cmd != BOOT_CMD_FW_BY_USB) {
+		} else if ((bootcmdresp.cmd != BOOT_CMD_FW_BY_USB) &&
+			   (bootcmdresp.cmd != BOOT_CMD_UPDATE_FW) &&
+			   (bootcmdresp.cmd != BOOT_CMD_UPDATE_BOOT2)) {
 			lbs_pr_info("boot cmd response cmd_tag error (%d)\n",
 				    bootcmdresp.cmd);
 		} else if (bootcmdresp.result != BOOT_CMD_RESP_OK) {
@@ -564,8 +633,8 @@
 
 	kfree_skb(skb);
 
-	/* reschedule timer for 200ms hence */
-	mod_timer(&cardp->fw_timeout, jiffies + (HZ/5));
+	/* Give device 5s to either write firmware to its RAM or eeprom */
+	mod_timer(&cardp->fw_timeout, jiffies + (HZ*5));
 
 	if (cardp->fwfinalblk) {
 		cardp->fwdnldover = 1;
@@ -809,7 +878,54 @@
 }
 
 
-static int if_usb_prog_firmware(struct if_usb_card *cardp)
+/**
+*  @brief This function programs the firmware subject to cmd
+*
+*  @param cardp             the if_usb_card descriptor
+*         fwname            firmware or boot2 image file name
+*         cmd               either BOOT_CMD_FW_BY_USB, BOOT_CMD_UPDATE_FW,
+*                           or BOOT_CMD_UPDATE_BOOT2.
+*  @return     0 or error code
+*/
+static int if_usb_prog_firmware(struct if_usb_card *cardp,
+				const char *fwname, int cmd)
+{
+	struct lbs_private *priv = cardp->priv;
+	unsigned long flags, caps;
+	int ret;
+
+	caps = priv->fwcapinfo;
+	if (((cmd == BOOT_CMD_UPDATE_FW) && !(caps & FW_CAPINFO_FIRMWARE_UPGRADE)) ||
+	    ((cmd == BOOT_CMD_UPDATE_BOOT2) && !(caps & FW_CAPINFO_BOOT2_UPGRADE)))
+		return -EOPNOTSUPP;
+
+	/* Ensure main thread is idle. */
+	spin_lock_irqsave(&priv->driver_lock, flags);
+	while (priv->cur_cmd != NULL || priv->dnld_sent != DNLD_RES_RECEIVED) {
+		spin_unlock_irqrestore(&priv->driver_lock, flags);
+		if (wait_event_interruptible(priv->waitq,
+				(priv->cur_cmd == NULL &&
+				priv->dnld_sent == DNLD_RES_RECEIVED))) {
+			return -ERESTARTSYS;
+		}
+		spin_lock_irqsave(&priv->driver_lock, flags);
+	}
+	priv->dnld_sent = DNLD_BOOTCMD_SENT;
+	spin_unlock_irqrestore(&priv->driver_lock, flags);
+
+	ret = __if_usb_prog_firmware(cardp, fwname, cmd);
+
+	spin_lock_irqsave(&priv->driver_lock, flags);
+	priv->dnld_sent = DNLD_RES_RECEIVED;
+	spin_unlock_irqrestore(&priv->driver_lock, flags);
+
+	wake_up_interruptible(&priv->waitq);
+
+	return ret;
+}
+
+static int __if_usb_prog_firmware(struct if_usb_card *cardp,
+					const char *fwname, int cmd)
 {
 	int i = 0;
 	static int reset_count = 10;
@@ -817,20 +933,32 @@
 
 	lbs_deb_enter(LBS_DEB_USB);
 
-	if ((ret = request_firmware(&cardp->fw, lbs_fw_name,
-				    &cardp->udev->dev)) < 0) {
+	ret = request_firmware(&cardp->fw, fwname, &cardp->udev->dev);
+	if (ret < 0) {
 		lbs_pr_err("request_firmware() failed with %#x\n", ret);
-		lbs_pr_err("firmware %s not found\n", lbs_fw_name);
+		lbs_pr_err("firmware %s not found\n", fwname);
 		goto done;
 	}
 
-	if (check_fwfile_format(cardp->fw->data, cardp->fw->size))
+	if (check_fwfile_format(cardp->fw->data, cardp->fw->size)) {
+		ret = -EINVAL;
 		goto release_fw;
+	}
+
+	/* Cancel any pending usb business */
+	usb_kill_urb(cardp->rx_urb);
+	usb_kill_urb(cardp->tx_urb);
+
+	cardp->fwlastblksent = 0;
+	cardp->fwdnldover = 0;
+	cardp->totalbytes = 0;
+	cardp->fwfinalblk = 0;
+	cardp->bootcmdresp = 0;
 
 restart:
 	if (if_usb_submit_rx_urb_fwload(cardp) < 0) {
 		lbs_deb_usbd(&cardp->udev->dev, "URB submission is failed\n");
-		ret = -1;
+		ret = -EIO;
 		goto release_fw;
 	}
 
@@ -838,8 +966,7 @@
 	do {
 		int j = 0;
 		i++;
-		/* Issue Boot command = 1, Boot from Download-FW */
-		if_usb_issue_boot_command(cardp, BOOT_CMD_FW_BY_USB);
+		if_usb_issue_boot_command(cardp, cmd);
 		/* wait for command response */
 		do {
 			j++;
@@ -847,12 +974,21 @@
 		} while (cardp->bootcmdresp == 0 && j < 10);
 	} while (cardp->bootcmdresp == 0 && i < 5);
 
-	if (cardp->bootcmdresp <= 0) {
+	if (cardp->bootcmdresp == BOOT_CMD_RESP_NOT_SUPPORTED) {
+		/* Return to normal operation */
+		ret = -EOPNOTSUPP;
+		usb_kill_urb(cardp->rx_urb);
+		usb_kill_urb(cardp->tx_urb);
+		if (if_usb_submit_rx_urb(cardp) < 0)
+			ret = -EIO;
+		goto release_fw;
+	} else if (cardp->bootcmdresp <= 0) {
 		if (--reset_count >= 0) {
 			if_usb_reset_device(cardp);
 			goto restart;
 		}
-		return -1;
+		ret = -EIO;
+		goto release_fw;
 	}
 
 	i = 0;
@@ -882,7 +1018,7 @@
 		}
 
 		lbs_pr_info("FW download failure, time = %d ms\n", i * 100);
-		ret = -1;
+		ret = -EIO;
 		goto release_fw;
 	}
 
diff --git a/drivers/net/wireless/libertas/if_usb.h b/drivers/net/wireless/libertas/if_usb.h
index 5771a83..5ba0aee 100644
--- a/drivers/net/wireless/libertas/if_usb.h
+++ b/drivers/net/wireless/libertas/if_usb.h
@@ -30,6 +30,7 @@
 
 #define BOOT_CMD_RESP_OK		0x0001
 #define BOOT_CMD_RESP_FAIL		0x0000
+#define BOOT_CMD_RESP_NOT_SUPPORTED	0x0002
 
 struct bootcmdresp
 {
@@ -50,6 +51,10 @@
 	uint8_t ep_in;
 	uint8_t ep_out;
 
+	/* bootcmdresp == 0 means command is pending
+	 * bootcmdresp < 0 means error
+	 * bootcmdresp > 0 is a BOOT_CMD_RESP_* from firmware
+	 */
 	int8_t bootcmdresp;
 
 	int ep_in_size;
diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c
index bd32ac0..73dc8c7 100644
--- a/drivers/net/wireless/libertas/main.c
+++ b/drivers/net/wireless/libertas/main.c
@@ -291,9 +291,11 @@
 			if (priv->infra_open || priv->mesh_open)
 				return -EBUSY;
 			if (priv->mode == IW_MODE_INFRA)
-				lbs_send_deauthentication(priv);
+				lbs_cmd_80211_deauthenticate(priv,
+							     priv->curbssparams.bssid,
+							     WLAN_REASON_DEAUTH_LEAVING);
 			else if (priv->mode == IW_MODE_ADHOC)
-				lbs_stop_adhoc_network(priv);
+				lbs_adhoc_stop(priv);
 			lbs_add_rtap(priv);
 		}
 		priv->monitormode = monitor_mode;
@@ -956,17 +958,24 @@
 static int lbs_setup_firmware(struct lbs_private *priv)
 {
 	int ret = -1;
+	s16 curlevel = 0, minlevel = 0, maxlevel = 0;
 
 	lbs_deb_enter(LBS_DEB_FW);
 
-	/*
-	 * Read MAC address from HW
-	 */
+	/* Read MAC address from firmware */
 	memset(priv->current_addr, 0xff, ETH_ALEN);
 	ret = lbs_update_hw_spec(priv);
 	if (ret)
 		goto done;
 
+	/* Read power levels if available */
+	ret = lbs_get_tx_power(priv, &curlevel, &minlevel, &maxlevel);
+	if (ret == 0) {
+		priv->txpower_cur = curlevel;
+		priv->txpower_min = minlevel;
+		priv->txpower_max = maxlevel;
+	}
+
 	lbs_set_mac_control(priv);
 done:
 	lbs_deb_leave_args(LBS_DEB_FW, "ret %d", ret);
@@ -1042,7 +1051,7 @@
 	priv->mode = IW_MODE_INFRA;
 	priv->curbssparams.channel = DEFAULT_AD_HOC_CHANNEL;
 	priv->mac_control = CMD_ACT_MAC_RX_ON | CMD_ACT_MAC_TX_ON;
-	priv->radioon = RADIO_ON;
+	priv->radio_on = 1;
 	priv->enablehwauto = 1;
 	priv->capability = WLAN_CAPABILITY_SHORT_PREAMBLE;
 	priv->psmode = LBS802_11POWERMODECAM;
@@ -1196,7 +1205,13 @@
 	cancel_delayed_work_sync(&priv->scan_work);
 	cancel_delayed_work_sync(&priv->assoc_work);
 	cancel_work_sync(&priv->mcast_work);
+
+	/* worker thread destruction blocks on the in-flight command which
+	 * should have been cleared already in lbs_stop_card().
+	 */
+	lbs_deb_main("destroying worker thread\n");
 	destroy_workqueue(priv->work_thread);
+	lbs_deb_main("done destroying worker thread\n");
 
 	if (priv->psmode == LBS802_11POWERMODEMAX_PSP) {
 		priv->psmode = LBS802_11POWERMODECAM;
@@ -1314,14 +1329,26 @@
 		device_remove_file(&dev->dev, &dev_attr_lbs_rtap);
 	}
 
-	/* Flush pending command nodes */
+	/* Delete the timeout of the currently processing command */
 	del_timer_sync(&priv->command_timer);
+
+	/* Flush pending command nodes */
 	spin_lock_irqsave(&priv->driver_lock, flags);
+	lbs_deb_main("clearing pending commands\n");
 	list_for_each_entry(cmdnode, &priv->cmdpendingq, list) {
 		cmdnode->result = -ENOENT;
 		cmdnode->cmdwaitqwoken = 1;
 		wake_up_interruptible(&cmdnode->cmdwait_q);
 	}
+
+	/* Flush the command the card is currently processing */
+	if (priv->cur_cmd) {
+		lbs_deb_main("clearing current command\n");
+		priv->cur_cmd->result = -ENOENT;
+		priv->cur_cmd->cmdwaitqwoken = 1;
+		wake_up_interruptible(&priv->cur_cmd->cmdwait_q);
+	}
+	lbs_deb_main("done clearing commands\n");
 	spin_unlock_irqrestore(&priv->driver_lock, flags);
 
 	unregister_netdev(dev);
diff --git a/drivers/net/wireless/libertas/scan.c b/drivers/net/wireless/libertas/scan.c
index 4b27456..8f66903 100644
--- a/drivers/net/wireless/libertas/scan.c
+++ b/drivers/net/wireless/libertas/scan.c
@@ -944,6 +944,11 @@
 
 	lbs_deb_enter(LBS_DEB_WEXT);
 
+	if (!priv->radio_on) {
+		ret = -EINVAL;
+		goto out;
+	}
+
 	if (!netif_running(dev)) {
 		ret = -ENETDOWN;
 		goto out;
diff --git a/drivers/net/wireless/libertas/wext.c b/drivers/net/wireless/libertas/wext.c
index 8b3ed77..82c3e5a5 100644
--- a/drivers/net/wireless/libertas/wext.c
+++ b/drivers/net/wireless/libertas/wext.c
@@ -30,6 +30,14 @@
 	queue_delayed_work(priv->work_thread, &priv->assoc_work, HZ / 2);
 }
 
+static inline void lbs_do_association_work(struct lbs_private *priv)
+{
+	if (priv->surpriseremoved)
+		return;
+	cancel_delayed_work(&priv->assoc_work);
+	queue_delayed_work(priv->work_thread, &priv->assoc_work, 0);
+}
+
 static inline void lbs_cancel_association_work(struct lbs_private *priv)
 {
 	cancel_delayed_work(&priv->assoc_work);
@@ -120,34 +128,6 @@
 	return cfp;
 }
 
-
-/**
- *  @brief Set Radio On/OFF
- *
- *  @param priv                 A pointer to struct lbs_private structure
- *  @option 			Radio Option
- *  @return 	   		0 --success, otherwise fail
- */
-static int lbs_radio_ioctl(struct lbs_private *priv, u8 option)
-{
-	int ret = 0;
-
-	lbs_deb_enter(LBS_DEB_WEXT);
-
-	if (priv->radioon != option) {
-		lbs_deb_wext("switching radio %s\n", option ? "on" : "off");
-		priv->radioon = option;
-
-		ret = lbs_prepare_and_send_command(priv,
-					    CMD_802_11_RADIO_CONTROL,
-					    CMD_ACT_SET,
-					    CMD_OPTION_WAITFORRSP, 0, NULL);
-	}
-
-	lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
-	return ret;
-}
-
 /**
  *  @brief Copy active data rates based on adapter mode and status
  *
@@ -294,21 +274,17 @@
 {
 	int ret = 0;
 	struct lbs_private *priv = dev->priv;
-	u32 rthr = vwrq->value;
+	u32 val = vwrq->value;
 
 	lbs_deb_enter(LBS_DEB_WEXT);
 
-	if (vwrq->disabled) {
-		priv->rtsthsd = rthr = MRVDRV_RTS_MAX_VALUE;
-	} else {
-		if (rthr < MRVDRV_RTS_MIN_VALUE || rthr > MRVDRV_RTS_MAX_VALUE)
-			return -EINVAL;
-		priv->rtsthsd = rthr;
-	}
+	if (vwrq->disabled)
+		val = MRVDRV_RTS_MAX_VALUE;
 
-	ret = lbs_prepare_and_send_command(priv, CMD_802_11_SNMP_MIB,
-				    CMD_ACT_SET, CMD_OPTION_WAITFORRSP,
-				    OID_802_11_RTS_THRESHOLD, &rthr);
+	if (val > MRVDRV_RTS_MAX_VALUE) /* min rts value is 0 */
+		return -EINVAL;
+
+	ret = lbs_set_snmp_mib(priv, SNMP_MIB_OID_RTS_THRESHOLD, (u16) val);
 
 	lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
 	return ret;
@@ -317,21 +293,18 @@
 static int lbs_get_rts(struct net_device *dev, struct iw_request_info *info,
 			struct iw_param *vwrq, char *extra)
 {
-	int ret = 0;
 	struct lbs_private *priv = dev->priv;
+	int ret = 0;
+	u16 val = 0;
 
 	lbs_deb_enter(LBS_DEB_WEXT);
 
-	priv->rtsthsd = 0;
-	ret = lbs_prepare_and_send_command(priv, CMD_802_11_SNMP_MIB,
-				    CMD_ACT_GET, CMD_OPTION_WAITFORRSP,
-				    OID_802_11_RTS_THRESHOLD, NULL);
+	ret = lbs_get_snmp_mib(priv, SNMP_MIB_OID_RTS_THRESHOLD, &val);
 	if (ret)
 		goto out;
 
-	vwrq->value = priv->rtsthsd;
-	vwrq->disabled = ((vwrq->value < MRVDRV_RTS_MIN_VALUE)
-			  || (vwrq->value > MRVDRV_RTS_MAX_VALUE));
+	vwrq->value = val;
+	vwrq->disabled = val > MRVDRV_RTS_MAX_VALUE; /* min rts value is 0 */
 	vwrq->fixed = 1;
 
 out:
@@ -342,24 +315,19 @@
 static int lbs_set_frag(struct net_device *dev, struct iw_request_info *info,
 			 struct iw_param *vwrq, char *extra)
 {
-	int ret = 0;
-	u32 fthr = vwrq->value;
 	struct lbs_private *priv = dev->priv;
+	int ret = 0;
+	u32 val = vwrq->value;
 
 	lbs_deb_enter(LBS_DEB_WEXT);
 
-	if (vwrq->disabled) {
-		priv->fragthsd = fthr = MRVDRV_FRAG_MAX_VALUE;
-	} else {
-		if (fthr < MRVDRV_FRAG_MIN_VALUE
-		    || fthr > MRVDRV_FRAG_MAX_VALUE)
-			return -EINVAL;
-		priv->fragthsd = fthr;
-	}
+	if (vwrq->disabled)
+		val = MRVDRV_FRAG_MAX_VALUE;
 
-	ret = lbs_prepare_and_send_command(priv, CMD_802_11_SNMP_MIB,
-				    CMD_ACT_SET, CMD_OPTION_WAITFORRSP,
-				    OID_802_11_FRAGMENTATION_THRESHOLD, &fthr);
+	if (val < MRVDRV_FRAG_MIN_VALUE || val > MRVDRV_FRAG_MAX_VALUE)
+		return -EINVAL;
+
+	ret = lbs_set_snmp_mib(priv, SNMP_MIB_OID_FRAG_THRESHOLD, (u16) val);
 
 	lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
 	return ret;
@@ -368,22 +336,19 @@
 static int lbs_get_frag(struct net_device *dev, struct iw_request_info *info,
 			 struct iw_param *vwrq, char *extra)
 {
-	int ret = 0;
 	struct lbs_private *priv = dev->priv;
+	int ret = 0;
+	u16 val = 0;
 
 	lbs_deb_enter(LBS_DEB_WEXT);
 
-	priv->fragthsd = 0;
-	ret = lbs_prepare_and_send_command(priv,
-				    CMD_802_11_SNMP_MIB,
-				    CMD_ACT_GET, CMD_OPTION_WAITFORRSP,
-				    OID_802_11_FRAGMENTATION_THRESHOLD, NULL);
+	ret = lbs_get_snmp_mib(priv, SNMP_MIB_OID_FRAG_THRESHOLD, &val);
 	if (ret)
 		goto out;
 
-	vwrq->value = priv->fragthsd;
-	vwrq->disabled = ((vwrq->value < MRVDRV_FRAG_MIN_VALUE)
-			  || (vwrq->value > MRVDRV_FRAG_MAX_VALUE));
+	vwrq->value = val;
+	vwrq->disabled = ((val < MRVDRV_FRAG_MIN_VALUE)
+			  || (val > MRVDRV_FRAG_MAX_VALUE));
 	vwrq->fixed = 1;
 
 out:
@@ -410,7 +375,7 @@
 {
 	lbs_deb_enter(LBS_DEB_WEXT);
 
-	*uwrq = IW_MODE_REPEAT ;
+	*uwrq = IW_MODE_REPEAT;
 
 	lbs_deb_leave(LBS_DEB_WEXT);
 	return 0;
@@ -420,28 +385,30 @@
 			  struct iw_request_info *info,
 			  struct iw_param *vwrq, char *extra)
 {
-	int ret = 0;
 	struct lbs_private *priv = dev->priv;
+	s16 curlevel = 0;
+	int ret = 0;
 
 	lbs_deb_enter(LBS_DEB_WEXT);
 
-	ret = lbs_prepare_and_send_command(priv,
-				    CMD_802_11_RF_TX_POWER,
-				    CMD_ACT_TX_POWER_OPT_GET,
-				    CMD_OPTION_WAITFORRSP, 0, NULL);
+	if (!priv->radio_on) {
+		lbs_deb_wext("tx power off\n");
+		vwrq->value = 0;
+		vwrq->disabled = 1;
+		goto out;
+	}
 
+	ret = lbs_get_tx_power(priv, &curlevel, NULL, NULL);
 	if (ret)
 		goto out;
 
-	lbs_deb_wext("tx power level %d dbm\n", priv->txpowerlevel);
-	vwrq->value = priv->txpowerlevel;
+	lbs_deb_wext("tx power level %d dbm\n", curlevel);
+	priv->txpower_cur = curlevel;
+
+	vwrq->value = curlevel;
 	vwrq->fixed = 1;
-	if (priv->radioon) {
-		vwrq->disabled = 0;
-		vwrq->flags = IW_TXPOW_DBM;
-	} else {
-		vwrq->disabled = 1;
-	}
+	vwrq->disabled = 0;
+	vwrq->flags = IW_TXPOW_DBM;
 
 out:
 	lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
@@ -451,31 +418,44 @@
 static int lbs_set_retry(struct net_device *dev, struct iw_request_info *info,
 			  struct iw_param *vwrq, char *extra)
 {
-	int ret = 0;
 	struct lbs_private *priv = dev->priv;
+	int ret = 0;
+	u16 slimit = 0, llimit = 0;
 
 	lbs_deb_enter(LBS_DEB_WEXT);
 
-	if (vwrq->flags == IW_RETRY_LIMIT) {
-		/* The MAC has a 4-bit Total_Tx_Count register
-		   Total_Tx_Count = 1 + Tx_Retry_Count */
+        if ((vwrq->flags & IW_RETRY_TYPE) != IW_RETRY_LIMIT)
+                return -EOPNOTSUPP;
+
+	/* The MAC has a 4-bit Total_Tx_Count register
+	   Total_Tx_Count = 1 + Tx_Retry_Count */
 #define TX_RETRY_MIN 0
 #define TX_RETRY_MAX 14
-		if (vwrq->value < TX_RETRY_MIN || vwrq->value > TX_RETRY_MAX)
-			return -EINVAL;
+	if (vwrq->value < TX_RETRY_MIN || vwrq->value > TX_RETRY_MAX)
+		return -EINVAL;
 
-		/* Adding 1 to convert retry count to try count */
-		priv->txretrycount = vwrq->value + 1;
+	/* Add 1 to convert retry count to try count */
+	if (vwrq->flags & IW_RETRY_SHORT)
+		slimit = (u16) (vwrq->value + 1);
+	else if (vwrq->flags & IW_RETRY_LONG)
+		llimit = (u16) (vwrq->value + 1);
+	else
+		slimit = llimit = (u16) (vwrq->value + 1); /* set both */
 
-		ret = lbs_prepare_and_send_command(priv, CMD_802_11_SNMP_MIB,
-					    CMD_ACT_SET,
-					    CMD_OPTION_WAITFORRSP,
-					    OID_802_11_TX_RETRYCOUNT, NULL);
-
+	if (llimit) {
+		ret = lbs_set_snmp_mib(priv, SNMP_MIB_OID_LONG_RETRY_LIMIT,
+				       llimit);
 		if (ret)
 			goto out;
-	} else {
-		return -EOPNOTSUPP;
+	}
+
+	if (slimit) {
+		/* txretrycount follows the short retry limit */
+		priv->txretrycount = slimit;
+		ret = lbs_set_snmp_mib(priv, SNMP_MIB_OID_SHORT_RETRY_LIMIT,
+				       slimit);
+		if (ret)
+			goto out;
 	}
 
 out:
@@ -488,22 +468,30 @@
 {
 	struct lbs_private *priv = dev->priv;
 	int ret = 0;
+	u16 val = 0;
 
 	lbs_deb_enter(LBS_DEB_WEXT);
 
-	priv->txretrycount = 0;
-	ret = lbs_prepare_and_send_command(priv,
-				    CMD_802_11_SNMP_MIB,
-				    CMD_ACT_GET, CMD_OPTION_WAITFORRSP,
-				    OID_802_11_TX_RETRYCOUNT, NULL);
-	if (ret)
-		goto out;
-
 	vwrq->disabled = 0;
-	if (!vwrq->flags) {
-		vwrq->flags = IW_RETRY_LIMIT;
+
+	if (vwrq->flags & IW_RETRY_LONG) {
+		ret = lbs_get_snmp_mib(priv, SNMP_MIB_OID_LONG_RETRY_LIMIT, &val);
+		if (ret)
+			goto out;
+
 		/* Subtract 1 to convert try count to retry count */
-		vwrq->value = priv->txretrycount - 1;
+		vwrq->value = val - 1;
+		vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_LONG;
+	} else {
+		ret = lbs_get_snmp_mib(priv, SNMP_MIB_OID_SHORT_RETRY_LIMIT, &val);
+		if (ret)
+			goto out;
+
+		/* txretry count follows the short retry limit */
+		priv->txretrycount = val;
+		/* Subtract 1 to convert try count to retry count */
+		vwrq->value = val - 1;
+		vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_SHORT;
 	}
 
 out:
@@ -693,22 +681,12 @@
 
 	range->sensitivity = 0;
 
-	/*
-	 * Setup the supported power level ranges
-	 */
+	/* Setup the supported power level ranges */
 	memset(range->txpower, 0, sizeof(range->txpower));
-	range->txpower[0] = 5;
-	range->txpower[1] = 7;
-	range->txpower[2] = 9;
-	range->txpower[3] = 11;
-	range->txpower[4] = 13;
-	range->txpower[5] = 15;
-	range->txpower[6] = 17;
-	range->txpower[7] = 19;
-
-	range->num_txpower = 8;
-	range->txpower_capa = IW_TXPOW_DBM;
-	range->txpower_capa |= IW_TXPOW_RANGE;
+	range->txpower_capa = IW_TXPOW_DBM | IW_TXPOW_RANGE;
+	range->txpower[0] = priv->txpower_min;
+	range->txpower[1] = priv->txpower_max;
+	range->num_txpower = 2;
 
 	range->event_capa[0] = (IW_EVENT_CAPA_K_0 |
 				IW_EVENT_CAPA_MASK(SIOCGIWAP) |
@@ -998,9 +976,11 @@
 	if (fwrq->m != priv->curbssparams.channel) {
 		lbs_deb_wext("mesh channel change forces eth disconnect\n");
 		if (priv->mode == IW_MODE_INFRA)
-			lbs_send_deauthentication(priv);
+			lbs_cmd_80211_deauthenticate(priv,
+						     priv->curbssparams.bssid,
+						     WLAN_REASON_DEAUTH_LEAVING);
 		else if (priv->mode == IW_MODE_ADHOC)
-			lbs_stop_adhoc_network(priv);
+			lbs_adhoc_stop(priv);
 	}
 	lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, fwrq->m);
 	lbs_update_channel(priv);
@@ -1045,6 +1025,18 @@
 				new_rate);
 			goto out;
 		}
+		if (priv->fwrelease < 0x09000000) {
+			ret = lbs_set_power_adapt_cfg(priv, 0,
+					POW_ADAPT_DEFAULT_P0,
+					POW_ADAPT_DEFAULT_P1,
+					POW_ADAPT_DEFAULT_P2);
+			if (ret)
+				goto out;
+		}
+		ret = lbs_set_tpc_cfg(priv, 0, TPC_DEFAULT_P0, TPC_DEFAULT_P1,
+				TPC_DEFAULT_P2, 1);
+		if (ret)
+			goto out;
 	}
 
 	/* Try the newer command first (Firmware Spec 5.1 and above) */
@@ -1612,12 +1604,26 @@
 			set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags);
 		}
 
-		disable_wep (assoc_req);
+		/* Only disable wep if necessary: can't waste time here. */
+		if (priv->mac_control & CMD_ACT_MAC_WEP_ENABLE)
+			disable_wep(assoc_req);
 	}
 
 out:
 	if (ret == 0) {
-		lbs_postpone_association_work(priv);
+		/* 802.1x and WPA rekeying must happen as quickly as possible,
+		 * especially during the 4-way handshake; thus if in
+		 * infrastructure mode, and either (a) 802.1x is enabled or
+		 * (b) WPA is being used, set the key right away.
+		 */
+		if (assoc_req->mode == IW_MODE_INFRA &&
+		    ((assoc_req->secinfo.key_mgmt & IW_AUTH_KEY_MGMT_802_1X) ||
+		     (assoc_req->secinfo.key_mgmt & IW_AUTH_KEY_MGMT_PSK) ||
+		      assoc_req->secinfo.WPAenabled ||
+		      assoc_req->secinfo.WPA2enabled)) {
+			lbs_do_association_work(priv);
+		} else
+			lbs_postpone_association_work(priv);
 	} else {
 		lbs_cancel_association_work(priv);
 	}
@@ -1725,13 +1731,17 @@
 	case IW_AUTH_TKIP_COUNTERMEASURES:
 	case IW_AUTH_CIPHER_PAIRWISE:
 	case IW_AUTH_CIPHER_GROUP:
-	case IW_AUTH_KEY_MGMT:
 	case IW_AUTH_DROP_UNENCRYPTED:
 		/*
 		 * libertas does not use these parameters
 		 */
 		break;
 
+	case IW_AUTH_KEY_MGMT:
+		assoc_req->secinfo.key_mgmt = dwrq->value;
+		updated = 1;
+		break;
+
 	case IW_AUTH_WPA_VERSION:
 		if (dwrq->value & IW_AUTH_WPA_VERSION_DISABLED) {
 			assoc_req->secinfo.WPAenabled = 0;
@@ -1811,6 +1821,10 @@
 	lbs_deb_enter(LBS_DEB_WEXT);
 
 	switch (dwrq->flags & IW_AUTH_INDEX) {
+	case IW_AUTH_KEY_MGMT:
+		dwrq->value = priv->secinfo.key_mgmt;
+		break;
+
 	case IW_AUTH_WPA_VERSION:
 		dwrq->value = 0;
 		if (priv->secinfo.WPAenabled)
@@ -1844,39 +1858,77 @@
 {
 	int ret = 0;
 	struct lbs_private *priv = dev->priv;
-
-	u16 dbm;
+	s16 dbm = (s16) vwrq->value;
 
 	lbs_deb_enter(LBS_DEB_WEXT);
 
 	if (vwrq->disabled) {
-		lbs_radio_ioctl(priv, RADIO_OFF);
-		return 0;
+		lbs_set_radio(priv, RADIO_PREAMBLE_AUTO, 0);
+		goto out;
 	}
 
-	priv->preamble = CMD_TYPE_AUTO_PREAMBLE;
+	if (vwrq->fixed == 0) {
+		/* User requests automatic tx power control, however there are
+		 * many auto tx settings.  For now use firmware defaults until
+		 * we come up with a good way to expose these to the user. */
+		if (priv->fwrelease < 0x09000000) {
+			ret = lbs_set_power_adapt_cfg(priv, 1,
+					POW_ADAPT_DEFAULT_P0,
+					POW_ADAPT_DEFAULT_P1,
+					POW_ADAPT_DEFAULT_P2);
+			if (ret)
+				goto out;
+		}
+		ret = lbs_set_tpc_cfg(priv, 0, TPC_DEFAULT_P0, TPC_DEFAULT_P1,
+				TPC_DEFAULT_P2, 1);
+		if (ret)
+			goto out;
+		dbm = priv->txpower_max;
+	} else {
+		/* Userspace check in iwrange if it should use dBm or mW,
+		 * therefore this should never happen... Jean II */
+		if ((vwrq->flags & IW_TXPOW_TYPE) != IW_TXPOW_DBM) {
+			ret = -EOPNOTSUPP;
+			goto out;
+		}
 
-	lbs_radio_ioctl(priv, RADIO_ON);
+		/* Validate requested power level against firmware allowed
+		 * levels */
+		if (priv->txpower_min && (dbm < priv->txpower_min)) {
+			ret = -EINVAL;
+			goto out;
+		}
 
-	/* Userspace check in iwrange if it should use dBm or mW,
-	 * therefore this should never happen... Jean II */
-	if ((vwrq->flags & IW_TXPOW_TYPE) == IW_TXPOW_MWATT) {
-		return -EOPNOTSUPP;
-	} else
-		dbm = (u16) vwrq->value;
+		if (priv->txpower_max && (dbm > priv->txpower_max)) {
+			ret = -EINVAL;
+			goto out;
+		}
+		if (priv->fwrelease < 0x09000000) {
+			ret = lbs_set_power_adapt_cfg(priv, 0,
+					POW_ADAPT_DEFAULT_P0,
+					POW_ADAPT_DEFAULT_P1,
+					POW_ADAPT_DEFAULT_P2);
+			if (ret)
+				goto out;
+		}
+		ret = lbs_set_tpc_cfg(priv, 0, TPC_DEFAULT_P0, TPC_DEFAULT_P1,
+				TPC_DEFAULT_P2, 1);
+		if (ret)
+			goto out;
+	}
 
-	/* auto tx power control */
+	/* If the radio was off, turn it on */
+	if (!priv->radio_on) {
+		ret = lbs_set_radio(priv, RADIO_PREAMBLE_AUTO, 1);
+		if (ret)
+			goto out;
+	}
 
-	if (vwrq->fixed == 0)
-		dbm = 0xffff;
+	lbs_deb_wext("txpower set %d dBm\n", dbm);
 
-	lbs_deb_wext("txpower set %d dbm\n", dbm);
+	ret = lbs_set_tx_power(priv, dbm);
 
-	ret = lbs_prepare_and_send_command(priv,
-				    CMD_802_11_RF_TX_POWER,
-				    CMD_ACT_TX_POWER_OPT_SET_LOW,
-				    CMD_OPTION_WAITFORRSP, 0, (void *)&dbm);
-
+out:
 	lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
 	return ret;
 }
@@ -1928,6 +1980,11 @@
 
 	lbs_deb_enter(LBS_DEB_WEXT);
 
+	if (!priv->radio_on) {
+		ret = -EINVAL;
+		goto out;
+	}
+
 	/* Check the size of the string */
 	if (in_ssid_len > IW_ESSID_MAX_SIZE) {
 		ret = -E2BIG;
@@ -2005,6 +2062,11 @@
 
 	lbs_deb_enter(LBS_DEB_WEXT);
 
+	if (!priv->radio_on) {
+		ret = -EINVAL;
+		goto out;
+	}
+
 	/* Check the size of the string */
 	if (dwrq->length > IW_ESSID_MAX_SIZE) {
 		ret = -E2BIG;
@@ -2046,6 +2108,9 @@
 
 	lbs_deb_enter(LBS_DEB_WEXT);
 
+	if (!priv->radio_on)
+		return -EINVAL;
+
 	if (awrq->sa_family != ARPHRD_ETHER)
 		return -EINVAL;
 
diff --git a/drivers/net/wireless/libertas_tf/Makefile b/drivers/net/wireless/libertas_tf/Makefile
new file mode 100644
index 0000000..ff5544d
--- /dev/null
+++ b/drivers/net/wireless/libertas_tf/Makefile
@@ -0,0 +1,6 @@
+libertas_tf-objs := main.o cmd.o
+
+libertas_tf_usb-objs += if_usb.o
+
+obj-$(CONFIG_LIBERTAS_THINFIRM) += libertas_tf.o
+obj-$(CONFIG_LIBERTAS_THINFIRM_USB) += libertas_tf_usb.o
diff --git a/drivers/net/wireless/libertas_tf/cmd.c b/drivers/net/wireless/libertas_tf/cmd.c
new file mode 100644
index 0000000..fdbcf8b
--- /dev/null
+++ b/drivers/net/wireless/libertas_tf/cmd.c
@@ -0,0 +1,669 @@
+/*
+ *  Copyright (C) 2008, cozybit Inc.
+ *  Copyright (C) 2003-2006, Marvell International Ltd.
+ *
+ *  This program is free software; you can redistribute it and/or 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 "libertas_tf.h"
+
+static const struct channel_range channel_ranges[] = {
+	{ LBTF_REGDOMAIN_US,		1, 12 },
+	{ LBTF_REGDOMAIN_CA,		1, 12 },
+	{ LBTF_REGDOMAIN_EU,		1, 14 },
+	{ LBTF_REGDOMAIN_JP,		1, 14 },
+	{ LBTF_REGDOMAIN_SP,		1, 14 },
+	{ LBTF_REGDOMAIN_FR,		1, 14 },
+};
+
+static u16 lbtf_region_code_to_index[MRVDRV_MAX_REGION_CODE] =
+{
+	LBTF_REGDOMAIN_US, LBTF_REGDOMAIN_CA, LBTF_REGDOMAIN_EU,
+	LBTF_REGDOMAIN_SP, LBTF_REGDOMAIN_FR, LBTF_REGDOMAIN_JP,
+};
+
+static struct cmd_ctrl_node *lbtf_get_cmd_ctrl_node(struct lbtf_private *priv);
+
+
+/**
+ *  lbtf_cmd_copyback - Simple callback that copies response back into command
+ *
+ *  @priv	A pointer to struct lbtf_private structure
+ *  @extra	A pointer to the original command structure for which
+ *		'resp' is a response
+ *  @resp	A pointer to the command response
+ *
+ *  Returns: 0 on success, error on failure
+ */
+int lbtf_cmd_copyback(struct lbtf_private *priv, unsigned long extra,
+		     struct cmd_header *resp)
+{
+	struct cmd_header *buf = (void *)extra;
+	uint16_t copy_len;
+
+	copy_len = min(le16_to_cpu(buf->size), le16_to_cpu(resp->size));
+	memcpy(buf, resp, copy_len);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(lbtf_cmd_copyback);
+
+#define CHAN_TO_IDX(chan) ((chan) - 1)
+
+static void lbtf_geo_init(struct lbtf_private *priv)
+{
+	const struct channel_range *range = channel_ranges;
+	u8 ch;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(channel_ranges); i++)
+		if (channel_ranges[i].regdomain == priv->regioncode) {
+			range = &channel_ranges[i];
+			break;
+		}
+
+	for (ch = priv->range.start; ch < priv->range.end; ch++)
+		priv->channels[CHAN_TO_IDX(ch)].flags = 0;
+}
+
+/**
+ *  lbtf_update_hw_spec: Updates the hardware details.
+ *
+ *  @priv    	A pointer to struct lbtf_private structure
+ *
+ *  Returns: 0 on success, error on failure
+ */
+int lbtf_update_hw_spec(struct lbtf_private *priv)
+{
+	struct cmd_ds_get_hw_spec cmd;
+	int ret = -1;
+	u32 i;
+	DECLARE_MAC_BUF(mac);
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+	memcpy(cmd.permanentaddr, priv->current_addr, ETH_ALEN);
+	ret = lbtf_cmd_with_response(priv, CMD_GET_HW_SPEC, &cmd);
+	if (ret)
+		goto out;
+
+	priv->fwcapinfo = le32_to_cpu(cmd.fwcapinfo);
+
+	/* The firmware release is in an interesting format: the patch
+	 * level is in the most significant nibble ... so fix that: */
+	priv->fwrelease = le32_to_cpu(cmd.fwrelease);
+	priv->fwrelease = (priv->fwrelease << 8) |
+		(priv->fwrelease >> 24 & 0xff);
+
+	printk(KERN_INFO "libertastf: %s, fw %u.%u.%up%u, cap 0x%08x\n",
+		print_mac(mac, cmd.permanentaddr),
+		priv->fwrelease >> 24 & 0xff,
+		priv->fwrelease >> 16 & 0xff,
+		priv->fwrelease >>  8 & 0xff,
+		priv->fwrelease       & 0xff,
+		priv->fwcapinfo);
+
+	/* Clamp region code to 8-bit since FW spec indicates that it should
+	 * only ever be 8-bit, even though the field size is 16-bit.  Some
+	 * firmware returns non-zero high 8 bits here.
+	 */
+	priv->regioncode = le16_to_cpu(cmd.regioncode) & 0xFF;
+
+	for (i = 0; i < MRVDRV_MAX_REGION_CODE; i++) {
+		/* use the region code to search for the index */
+		if (priv->regioncode == lbtf_region_code_to_index[i])
+			break;
+	}
+
+	/* if it's unidentified region code, use the default (USA) */
+	if (i >= MRVDRV_MAX_REGION_CODE)
+		priv->regioncode = 0x10;
+
+	if (priv->current_addr[0] == 0xff)
+		memmove(priv->current_addr, cmd.permanentaddr, ETH_ALEN);
+
+	SET_IEEE80211_PERM_ADDR(priv->hw, priv->current_addr);
+
+	lbtf_geo_init(priv);
+out:
+	return ret;
+}
+
+/**
+ *  lbtf_set_channel: Set the radio channel
+ *
+ *  @priv	A pointer to struct lbtf_private structure
+ *  @channel	The desired channel, or 0 to clear a locked channel
+ *
+ *  Returns: 0 on success, error on failure
+ */
+int lbtf_set_channel(struct lbtf_private *priv, u8 channel)
+{
+	struct cmd_ds_802_11_rf_channel cmd;
+
+	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+	cmd.action = cpu_to_le16(CMD_OPT_802_11_RF_CHANNEL_SET);
+	cmd.channel = cpu_to_le16(channel);
+
+	return lbtf_cmd_with_response(priv, CMD_802_11_RF_CHANNEL, &cmd);
+}
+
+int lbtf_beacon_set(struct lbtf_private *priv, struct sk_buff *beacon)
+{
+	struct cmd_ds_802_11_beacon_set cmd;
+	int size;
+
+	if (beacon->len > MRVL_MAX_BCN_SIZE)
+		return -1;
+	size =  sizeof(cmd) - sizeof(cmd.beacon) + beacon->len;
+	cmd.hdr.size = cpu_to_le16(size);
+	cmd.len = cpu_to_le16(beacon->len);
+	memcpy(cmd.beacon, (u8 *) beacon->data, beacon->len);
+
+	lbtf_cmd_async(priv, CMD_802_11_BEACON_SET, &cmd.hdr, size);
+	return 0;
+}
+
+int lbtf_beacon_ctrl(struct lbtf_private *priv, bool beacon_enable,
+		     int beacon_int) {
+	struct cmd_ds_802_11_beacon_control cmd;
+
+	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+	cmd.action = cpu_to_le16(CMD_ACT_SET);
+	cmd.beacon_enable = cpu_to_le16(beacon_enable);
+	cmd.beacon_period = cpu_to_le16(beacon_int);
+
+	lbtf_cmd_async(priv, CMD_802_11_BEACON_CTRL, &cmd.hdr, sizeof(cmd));
+	return 0;
+}
+
+static void lbtf_queue_cmd(struct lbtf_private *priv,
+			  struct cmd_ctrl_node *cmdnode)
+{
+	unsigned long flags;
+
+	if (!cmdnode)
+		return;
+
+	if (!cmdnode->cmdbuf->size)
+		return;
+
+	cmdnode->result = 0;
+	spin_lock_irqsave(&priv->driver_lock, flags);
+	list_add_tail(&cmdnode->list, &priv->cmdpendingq);
+	spin_unlock_irqrestore(&priv->driver_lock, flags);
+}
+
+static void lbtf_submit_command(struct lbtf_private *priv,
+			       struct cmd_ctrl_node *cmdnode)
+{
+	unsigned long flags;
+	struct cmd_header *cmd;
+	uint16_t cmdsize;
+	uint16_t command;
+	int timeo = 5 * HZ;
+	int ret;
+
+	cmd = cmdnode->cmdbuf;
+
+	spin_lock_irqsave(&priv->driver_lock, flags);
+	priv->cur_cmd = cmdnode;
+	cmdsize = le16_to_cpu(cmd->size);
+	command = le16_to_cpu(cmd->command);
+	ret = priv->hw_host_to_card(priv, MVMS_CMD, (u8 *) cmd, cmdsize);
+	spin_unlock_irqrestore(&priv->driver_lock, flags);
+
+	if (ret)
+		/* Let the timer kick in and retry, and potentially reset
+		   the whole thing if the condition persists */
+		timeo = HZ;
+
+	/* Setup the timer after transmit command */
+	mod_timer(&priv->command_timer, jiffies + timeo);
+}
+
+/**
+ *  This function inserts command node to cmdfreeq
+ *  after cleans it. Requires priv->driver_lock held.
+ */
+static void __lbtf_cleanup_and_insert_cmd(struct lbtf_private *priv,
+					 struct cmd_ctrl_node *cmdnode)
+{
+	if (!cmdnode)
+		return;
+
+	cmdnode->callback = NULL;
+	cmdnode->callback_arg = 0;
+
+	memset(cmdnode->cmdbuf, 0, LBS_CMD_BUFFER_SIZE);
+
+	list_add_tail(&cmdnode->list, &priv->cmdfreeq);
+}
+
+static void lbtf_cleanup_and_insert_cmd(struct lbtf_private *priv,
+	struct cmd_ctrl_node *ptempcmd)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&priv->driver_lock, flags);
+	__lbtf_cleanup_and_insert_cmd(priv, ptempcmd);
+	spin_unlock_irqrestore(&priv->driver_lock, flags);
+}
+
+void lbtf_complete_command(struct lbtf_private *priv, struct cmd_ctrl_node *cmd,
+			  int result)
+{
+	cmd->result = result;
+	cmd->cmdwaitqwoken = 1;
+	wake_up_interruptible(&cmd->cmdwait_q);
+
+	if (!cmd->callback)
+		__lbtf_cleanup_and_insert_cmd(priv, cmd);
+	priv->cur_cmd = NULL;
+}
+
+int lbtf_cmd_set_mac_multicast_addr(struct lbtf_private *priv)
+{
+	struct cmd_ds_mac_multicast_addr cmd;
+
+	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+	cmd.action = cpu_to_le16(CMD_ACT_SET);
+
+	cmd.nr_of_adrs = cpu_to_le16((u16) priv->nr_of_multicastmacaddr);
+	memcpy(cmd.maclist, priv->multicastlist,
+	       priv->nr_of_multicastmacaddr * ETH_ALEN);
+
+	lbtf_cmd_async(priv, CMD_MAC_MULTICAST_ADR, &cmd.hdr, sizeof(cmd));
+	return 0;
+}
+
+void lbtf_set_mode(struct lbtf_private *priv, enum lbtf_mode mode)
+{
+	struct cmd_ds_set_mode cmd;
+
+	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+	cmd.mode = cpu_to_le16(mode);
+	lbtf_cmd_async(priv, CMD_802_11_SET_MODE, &cmd.hdr, sizeof(cmd));
+}
+
+void lbtf_set_bssid(struct lbtf_private *priv, bool activate, u8 *bssid)
+{
+	struct cmd_ds_set_bssid cmd;
+
+	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+	cmd.activate = activate ? 1 : 0;
+	if (activate)
+		memcpy(cmd.bssid, bssid, ETH_ALEN);
+
+	lbtf_cmd_async(priv, CMD_802_11_SET_BSSID, &cmd.hdr, sizeof(cmd));
+}
+
+int lbtf_set_mac_address(struct lbtf_private *priv, uint8_t *mac_addr)
+{
+	struct cmd_ds_802_11_mac_address cmd;
+
+	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+	cmd.action = cpu_to_le16(CMD_ACT_SET);
+
+	memcpy(cmd.macadd, mac_addr, ETH_ALEN);
+
+	lbtf_cmd_async(priv, CMD_802_11_MAC_ADDRESS, &cmd.hdr, sizeof(cmd));
+	return 0;
+}
+
+int lbtf_set_radio_control(struct lbtf_private *priv)
+{
+	int ret = 0;
+	struct cmd_ds_802_11_radio_control cmd;
+
+	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+	cmd.action = cpu_to_le16(CMD_ACT_SET);
+
+	switch (priv->preamble) {
+	case CMD_TYPE_SHORT_PREAMBLE:
+		cmd.control = cpu_to_le16(SET_SHORT_PREAMBLE);
+		break;
+
+	case CMD_TYPE_LONG_PREAMBLE:
+		cmd.control = cpu_to_le16(SET_LONG_PREAMBLE);
+		break;
+
+	case CMD_TYPE_AUTO_PREAMBLE:
+	default:
+		cmd.control = cpu_to_le16(SET_AUTO_PREAMBLE);
+		break;
+	}
+
+	if (priv->radioon)
+		cmd.control |= cpu_to_le16(TURN_ON_RF);
+	else
+		cmd.control &= cpu_to_le16(~TURN_ON_RF);
+
+	ret = lbtf_cmd_with_response(priv, CMD_802_11_RADIO_CONTROL, &cmd);
+	return ret;
+}
+
+void lbtf_set_mac_control(struct lbtf_private *priv)
+{
+	struct cmd_ds_mac_control cmd;
+	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+	cmd.action = cpu_to_le16(priv->mac_control);
+	cmd.reserved = 0;
+
+	lbtf_cmd_async(priv, CMD_MAC_CONTROL,
+		&cmd.hdr, sizeof(cmd));
+}
+
+/**
+ *  lbtf_allocate_cmd_buffer - Allocates cmd buffer, links it to free cmd queue
+ *
+ *  @priv	A pointer to struct lbtf_private structure
+ *
+ *  Returns: 0 on success.
+ */
+int lbtf_allocate_cmd_buffer(struct lbtf_private *priv)
+{
+	u32 bufsize;
+	u32 i;
+	struct cmd_ctrl_node *cmdarray;
+
+	/* Allocate and initialize the command array */
+	bufsize = sizeof(struct cmd_ctrl_node) * LBS_NUM_CMD_BUFFERS;
+	cmdarray = kzalloc(bufsize, GFP_KERNEL);
+	if (!cmdarray)
+		return -1;
+	priv->cmd_array = cmdarray;
+
+	/* Allocate and initialize each command buffer in the command array */
+	for (i = 0; i < LBS_NUM_CMD_BUFFERS; i++) {
+		cmdarray[i].cmdbuf = kzalloc(LBS_CMD_BUFFER_SIZE, GFP_KERNEL);
+		if (!cmdarray[i].cmdbuf)
+			return -1;
+	}
+
+	for (i = 0; i < LBS_NUM_CMD_BUFFERS; i++) {
+		init_waitqueue_head(&cmdarray[i].cmdwait_q);
+		lbtf_cleanup_and_insert_cmd(priv, &cmdarray[i]);
+	}
+	return 0;
+}
+
+/**
+ *  lbtf_free_cmd_buffer - Frees the cmd buffer.
+ *
+ *  @priv	A pointer to struct lbtf_private structure
+ *
+ *  Returns: 0
+ */
+int lbtf_free_cmd_buffer(struct lbtf_private *priv)
+{
+	struct cmd_ctrl_node *cmdarray;
+	unsigned int i;
+
+	/* need to check if cmd array is allocated or not */
+	if (priv->cmd_array == NULL)
+		return 0;
+
+	cmdarray = priv->cmd_array;
+
+	/* Release shared memory buffers */
+	for (i = 0; i < LBS_NUM_CMD_BUFFERS; i++) {
+		kfree(cmdarray[i].cmdbuf);
+		cmdarray[i].cmdbuf = NULL;
+	}
+
+	/* Release cmd_ctrl_node */
+	kfree(priv->cmd_array);
+	priv->cmd_array = NULL;
+
+	return 0;
+}
+
+/**
+ *  lbtf_get_cmd_ctrl_node - Gets free cmd node from free cmd queue.
+ *
+ *  @priv		A pointer to struct lbtf_private structure
+ *
+ *  Returns: pointer to a struct cmd_ctrl_node or NULL if none available.
+ */
+static struct cmd_ctrl_node *lbtf_get_cmd_ctrl_node(struct lbtf_private *priv)
+{
+	struct cmd_ctrl_node *tempnode;
+	unsigned long flags;
+
+	if (!priv)
+		return NULL;
+
+	spin_lock_irqsave(&priv->driver_lock, flags);
+
+	if (!list_empty(&priv->cmdfreeq)) {
+		tempnode = list_first_entry(&priv->cmdfreeq,
+					    struct cmd_ctrl_node, list);
+		list_del(&tempnode->list);
+	} else
+		tempnode = NULL;
+
+	spin_unlock_irqrestore(&priv->driver_lock, flags);
+
+	return tempnode;
+}
+
+/**
+ *  lbtf_execute_next_command: execute next command in cmd pending queue.
+ *
+ *  @priv     A pointer to struct lbtf_private structure
+ *
+ *  Returns: 0 on success.
+ */
+int lbtf_execute_next_command(struct lbtf_private *priv)
+{
+	struct cmd_ctrl_node *cmdnode = NULL;
+	struct cmd_header *cmd;
+	unsigned long flags;
+
+	/* Debug group is LBS_DEB_THREAD and not LBS_DEB_HOST, because the
+	 * only caller to us is lbtf_thread() and we get even when a
+	 * data packet is received */
+
+	spin_lock_irqsave(&priv->driver_lock, flags);
+
+	if (priv->cur_cmd) {
+		spin_unlock_irqrestore(&priv->driver_lock, flags);
+		return -1;
+	}
+
+	if (!list_empty(&priv->cmdpendingq)) {
+		cmdnode = list_first_entry(&priv->cmdpendingq,
+					   struct cmd_ctrl_node, list);
+	}
+
+	if (cmdnode) {
+		cmd = cmdnode->cmdbuf;
+
+		list_del(&cmdnode->list);
+		spin_unlock_irqrestore(&priv->driver_lock, flags);
+		lbtf_submit_command(priv, cmdnode);
+	} else
+		spin_unlock_irqrestore(&priv->driver_lock, flags);
+	return 0;
+}
+
+static struct cmd_ctrl_node *__lbtf_cmd_async(struct lbtf_private *priv,
+	uint16_t command, struct cmd_header *in_cmd, int in_cmd_size,
+	int (*callback)(struct lbtf_private *, unsigned long,
+			struct cmd_header *),
+	unsigned long callback_arg)
+{
+	struct cmd_ctrl_node *cmdnode;
+
+	if (priv->surpriseremoved)
+		return ERR_PTR(-ENOENT);
+
+	cmdnode = lbtf_get_cmd_ctrl_node(priv);
+	if (cmdnode == NULL) {
+		/* Wake up main thread to execute next command */
+		queue_work(lbtf_wq, &priv->cmd_work);
+		return ERR_PTR(-ENOBUFS);
+	}
+
+	cmdnode->callback = callback;
+	cmdnode->callback_arg = callback_arg;
+
+	/* Copy the incoming command to the buffer */
+	memcpy(cmdnode->cmdbuf, in_cmd, in_cmd_size);
+
+	/* Set sequence number, clean result, move to buffer */
+	priv->seqnum++;
+	cmdnode->cmdbuf->command = cpu_to_le16(command);
+	cmdnode->cmdbuf->size    = cpu_to_le16(in_cmd_size);
+	cmdnode->cmdbuf->seqnum  = cpu_to_le16(priv->seqnum);
+	cmdnode->cmdbuf->result  = 0;
+	cmdnode->cmdwaitqwoken = 0;
+	lbtf_queue_cmd(priv, cmdnode);
+	queue_work(lbtf_wq, &priv->cmd_work);
+
+	return cmdnode;
+}
+
+void lbtf_cmd_async(struct lbtf_private *priv, uint16_t command,
+	struct cmd_header *in_cmd, int in_cmd_size)
+{
+	__lbtf_cmd_async(priv, command, in_cmd, in_cmd_size, NULL, 0);
+}
+
+int __lbtf_cmd(struct lbtf_private *priv, uint16_t command,
+	      struct cmd_header *in_cmd, int in_cmd_size,
+	      int (*callback)(struct lbtf_private *,
+			      unsigned long, struct cmd_header *),
+	      unsigned long callback_arg)
+{
+	struct cmd_ctrl_node *cmdnode;
+	unsigned long flags;
+	int ret = 0;
+
+	cmdnode = __lbtf_cmd_async(priv, command, in_cmd, in_cmd_size,
+				  callback, callback_arg);
+	if (IS_ERR(cmdnode))
+		return PTR_ERR(cmdnode);
+
+	might_sleep();
+	ret = wait_event_interruptible(cmdnode->cmdwait_q,
+				       cmdnode->cmdwaitqwoken);
+       if (ret)	{
+		printk(KERN_DEBUG
+		       "libertastf: command 0x%04x interrupted by signal",
+		       command);
+		return ret;
+	}
+
+	spin_lock_irqsave(&priv->driver_lock, flags);
+	ret = cmdnode->result;
+	if (ret)
+		printk(KERN_DEBUG "libertastf: command 0x%04x failed: %d\n",
+			    command, ret);
+
+	__lbtf_cleanup_and_insert_cmd(priv, cmdnode);
+	spin_unlock_irqrestore(&priv->driver_lock, flags);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(__lbtf_cmd);
+
+/* Call holding driver_lock */
+void lbtf_cmd_response_rx(struct lbtf_private *priv)
+{
+	priv->cmd_response_rxed = 1;
+	queue_work(lbtf_wq, &priv->cmd_work);
+}
+EXPORT_SYMBOL_GPL(lbtf_cmd_response_rx);
+
+int lbtf_process_rx_command(struct lbtf_private *priv)
+{
+	uint16_t respcmd, curcmd;
+	struct cmd_header *resp;
+	int ret = 0;
+	unsigned long flags;
+	uint16_t result;
+
+	mutex_lock(&priv->lock);
+	spin_lock_irqsave(&priv->driver_lock, flags);
+
+	if (!priv->cur_cmd) {
+		ret = -1;
+		spin_unlock_irqrestore(&priv->driver_lock, flags);
+		goto done;
+	}
+
+	resp = (void *)priv->cmd_resp_buff;
+	curcmd = le16_to_cpu(priv->cur_cmd->cmdbuf->command);
+	respcmd = le16_to_cpu(resp->command);
+	result = le16_to_cpu(resp->result);
+
+	if (net_ratelimit())
+		printk(KERN_DEBUG "libertastf: cmd response 0x%04x, seq %d, size %d\n",
+			respcmd, le16_to_cpu(resp->seqnum),
+			le16_to_cpu(resp->size));
+
+	if (resp->seqnum != priv->cur_cmd->cmdbuf->seqnum) {
+		spin_unlock_irqrestore(&priv->driver_lock, flags);
+		ret = -1;
+		goto done;
+	}
+	if (respcmd != CMD_RET(curcmd)) {
+		spin_unlock_irqrestore(&priv->driver_lock, flags);
+		ret = -1;
+		goto done;
+	}
+
+	if (resp->result == cpu_to_le16(0x0004)) {
+		/* 0x0004 means -EAGAIN. Drop the response, let it time out
+		   and be resubmitted */
+		spin_unlock_irqrestore(&priv->driver_lock, flags);
+		ret = -1;
+		goto done;
+	}
+
+	/* Now we got response from FW, cancel the command timer */
+	del_timer(&priv->command_timer);
+	priv->cmd_timed_out = 0;
+	if (priv->nr_retries)
+		priv->nr_retries = 0;
+
+	/* If the command is not successful, cleanup and return failure */
+	if ((result != 0 || !(respcmd & 0x8000))) {
+		/*
+		 * Handling errors here
+		 */
+		switch (respcmd) {
+		case CMD_RET(CMD_GET_HW_SPEC):
+		case CMD_RET(CMD_802_11_RESET):
+			printk(KERN_DEBUG "libertastf: reset failed\n");
+			break;
+
+		}
+		lbtf_complete_command(priv, priv->cur_cmd, result);
+		spin_unlock_irqrestore(&priv->driver_lock, flags);
+
+		ret = -1;
+		goto done;
+	}
+
+	spin_unlock_irqrestore(&priv->driver_lock, flags);
+
+	if (priv->cur_cmd && priv->cur_cmd->callback) {
+		ret = priv->cur_cmd->callback(priv, priv->cur_cmd->callback_arg,
+				resp);
+	}
+	spin_lock_irqsave(&priv->driver_lock, flags);
+
+	if (priv->cur_cmd) {
+		/* Clean up and Put current command back to cmdfreeq */
+		lbtf_complete_command(priv, priv->cur_cmd, result);
+	}
+	spin_unlock_irqrestore(&priv->driver_lock, flags);
+
+done:
+	mutex_unlock(&priv->lock);
+	return ret;
+}
diff --git a/drivers/net/wireless/libertas_tf/if_usb.c b/drivers/net/wireless/libertas_tf/if_usb.c
new file mode 100644
index 0000000..1cc03a8
--- /dev/null
+++ b/drivers/net/wireless/libertas_tf/if_usb.c
@@ -0,0 +1,766 @@
+/*
+ *  Copyright (C) 2008, cozybit Inc.
+ *  Copyright (C) 2003-2006, Marvell International Ltd.
+ *
+ *  This program is free software; you can redistribute it and/or 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/delay.h>
+#include <linux/moduleparam.h>
+#include <linux/firmware.h>
+#include <linux/netdevice.h>
+#include <linux/usb.h>
+
+#define DRV_NAME "lbtf_usb"
+
+#include "libertas_tf.h"
+#include "if_usb.h"
+
+#define MESSAGE_HEADER_LEN	4
+
+static char *lbtf_fw_name = "lbtf_usb.bin";
+module_param_named(fw_name, lbtf_fw_name, charp, 0644);
+
+static struct usb_device_id if_usb_table[] = {
+	/* Enter the device signature inside */
+	{ USB_DEVICE(0x1286, 0x2001) },
+	{ USB_DEVICE(0x05a3, 0x8388) },
+	{}	/* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE(usb, if_usb_table);
+
+static void if_usb_receive(struct urb *urb);
+static void if_usb_receive_fwload(struct urb *urb);
+static int if_usb_prog_firmware(struct if_usb_card *cardp);
+static int if_usb_host_to_card(struct lbtf_private *priv, uint8_t type,
+			       uint8_t *payload, uint16_t nb);
+static int usb_tx_block(struct if_usb_card *cardp, uint8_t *payload,
+			uint16_t nb, u8 data);
+static void if_usb_free(struct if_usb_card *cardp);
+static int if_usb_submit_rx_urb(struct if_usb_card *cardp);
+static int if_usb_reset_device(struct if_usb_card *cardp);
+
+/**
+ *  if_usb_wrike_bulk_callback -  call back to handle URB status
+ *
+ *  @param urb 		pointer to urb structure
+ */
+static void if_usb_write_bulk_callback(struct urb *urb)
+{
+	if (urb->status != 0)
+		printk(KERN_INFO "libertastf: URB in failure status: %d\n",
+		       urb->status);
+}
+
+/**
+ *  if_usb_free - free tx/rx urb, skb and rx buffer
+ *
+ *  @param cardp	pointer if_usb_card
+ */
+static void if_usb_free(struct if_usb_card *cardp)
+{
+	/* Unlink tx & rx urb */
+	usb_kill_urb(cardp->tx_urb);
+	usb_kill_urb(cardp->rx_urb);
+	usb_kill_urb(cardp->cmd_urb);
+
+	usb_free_urb(cardp->tx_urb);
+	cardp->tx_urb = NULL;
+
+	usb_free_urb(cardp->rx_urb);
+	cardp->rx_urb = NULL;
+
+	usb_free_urb(cardp->cmd_urb);
+	cardp->cmd_urb = NULL;
+
+	kfree(cardp->ep_out_buf);
+	cardp->ep_out_buf = NULL;
+}
+
+static void if_usb_setup_firmware(struct lbtf_private *priv)
+{
+	struct if_usb_card *cardp = priv->card;
+	struct cmd_ds_set_boot2_ver b2_cmd;
+
+	if_usb_submit_rx_urb(cardp);
+	b2_cmd.hdr.size = cpu_to_le16(sizeof(b2_cmd));
+	b2_cmd.action = 0;
+	b2_cmd.version = cardp->boot2_version;
+
+	if (lbtf_cmd_with_response(priv, CMD_SET_BOOT2_VER, &b2_cmd))
+		printk(KERN_INFO "libertastf: setting boot2 version failed\n");
+}
+
+static void if_usb_fw_timeo(unsigned long priv)
+{
+	struct if_usb_card *cardp = (void *)priv;
+
+	if (!cardp->fwdnldover)
+		/* Download timed out */
+		cardp->priv->surpriseremoved = 1;
+	wake_up(&cardp->fw_wq);
+}
+
+/**
+ *  if_usb_probe - sets the configuration values
+ *
+ *  @ifnum	interface number
+ *  @id		pointer to usb_device_id
+ *
+ *  Returns: 0 on success, error code on failure
+ */
+static int if_usb_probe(struct usb_interface *intf,
+			const struct usb_device_id *id)
+{
+	struct usb_device *udev;
+	struct usb_host_interface *iface_desc;
+	struct usb_endpoint_descriptor *endpoint;
+	struct lbtf_private *priv;
+	struct if_usb_card *cardp;
+	int i;
+
+	udev = interface_to_usbdev(intf);
+
+	cardp = kzalloc(sizeof(struct if_usb_card), GFP_KERNEL);
+	if (!cardp)
+		goto error;
+
+	setup_timer(&cardp->fw_timeout, if_usb_fw_timeo, (unsigned long)cardp);
+	init_waitqueue_head(&cardp->fw_wq);
+
+	cardp->udev = udev;
+	iface_desc = intf->cur_altsetting;
+
+	for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
+		endpoint = &iface_desc->endpoint[i].desc;
+		if (usb_endpoint_is_bulk_in(endpoint)) {
+			cardp->ep_in_size =
+				le16_to_cpu(endpoint->wMaxPacketSize);
+			cardp->ep_in = usb_endpoint_num(endpoint);
+		} else if (usb_endpoint_is_bulk_out(endpoint)) {
+			cardp->ep_out_size =
+				le16_to_cpu(endpoint->wMaxPacketSize);
+			cardp->ep_out = usb_endpoint_num(endpoint);
+		}
+	}
+	if (!cardp->ep_out_size || !cardp->ep_in_size)
+		/* Endpoints not found */
+		goto dealloc;
+
+	cardp->rx_urb = usb_alloc_urb(0, GFP_KERNEL);
+	if (!cardp->rx_urb)
+		goto dealloc;
+
+	cardp->tx_urb = usb_alloc_urb(0, GFP_KERNEL);
+	if (!cardp->tx_urb)
+		goto dealloc;
+
+	cardp->cmd_urb = usb_alloc_urb(0, GFP_KERNEL);
+	if (!cardp->cmd_urb)
+		goto dealloc;
+
+	cardp->ep_out_buf = kmalloc(MRVDRV_ETH_TX_PACKET_BUFFER_SIZE,
+				    GFP_KERNEL);
+	if (!cardp->ep_out_buf)
+		goto dealloc;
+
+	priv = lbtf_add_card(cardp, &udev->dev);
+	if (!priv)
+		goto dealloc;
+
+	cardp->priv = priv;
+
+	priv->hw_host_to_card = if_usb_host_to_card;
+	priv->hw_prog_firmware = if_usb_prog_firmware;
+	priv->hw_reset_device = if_usb_reset_device;
+	cardp->boot2_version = udev->descriptor.bcdDevice;
+
+	usb_get_dev(udev);
+	usb_set_intfdata(intf, cardp);
+
+	return 0;
+
+dealloc:
+	if_usb_free(cardp);
+error:
+	return -ENOMEM;
+}
+
+/**
+ *  if_usb_disconnect -  free resource and cleanup
+ *
+ *  @intf	USB interface structure
+ */
+static void if_usb_disconnect(struct usb_interface *intf)
+{
+	struct if_usb_card *cardp = usb_get_intfdata(intf);
+	struct lbtf_private *priv = (struct lbtf_private *) cardp->priv;
+
+	if_usb_reset_device(cardp);
+
+	if (priv)
+		lbtf_remove_card(priv);
+
+	/* Unlink and free urb */
+	if_usb_free(cardp);
+
+	usb_set_intfdata(intf, NULL);
+	usb_put_dev(interface_to_usbdev(intf));
+}
+
+/**
+ *  if_usb_send_fw_pkt -  This function downloads the FW
+ *
+ *  @priv	pointer to struct lbtf_private
+ *
+ *  Returns: 0
+ */
+static int if_usb_send_fw_pkt(struct if_usb_card *cardp)
+{
+	struct fwdata *fwdata = cardp->ep_out_buf;
+	u8 *firmware = (u8 *) cardp->fw->data;
+
+	/* If we got a CRC failure on the last block, back
+	   up and retry it */
+	if (!cardp->CRC_OK) {
+		cardp->totalbytes = cardp->fwlastblksent;
+		cardp->fwseqnum--;
+	}
+
+	/* struct fwdata (which we sent to the card) has an
+	   extra __le32 field in between the header and the data,
+	   which is not in the struct fwheader in the actual
+	   firmware binary. Insert the seqnum in the middle... */
+	memcpy(&fwdata->hdr, &firmware[cardp->totalbytes],
+	       sizeof(struct fwheader));
+
+	cardp->fwlastblksent = cardp->totalbytes;
+	cardp->totalbytes += sizeof(struct fwheader);
+
+	memcpy(fwdata->data, &firmware[cardp->totalbytes],
+	       le32_to_cpu(fwdata->hdr.datalength));
+
+	fwdata->seqnum = cpu_to_le32(++cardp->fwseqnum);
+	cardp->totalbytes += le32_to_cpu(fwdata->hdr.datalength);
+
+	usb_tx_block(cardp, cardp->ep_out_buf, sizeof(struct fwdata) +
+		     le32_to_cpu(fwdata->hdr.datalength), 0);
+
+	if (fwdata->hdr.dnldcmd == cpu_to_le32(FW_HAS_LAST_BLOCK))
+		/* Host has finished FW downloading
+		 * Donwloading FW JUMP BLOCK
+		 */
+		cardp->fwfinalblk = 1;
+
+	return 0;
+}
+
+static int if_usb_reset_device(struct if_usb_card *cardp)
+{
+	struct cmd_ds_802_11_reset *cmd = cardp->ep_out_buf + 4;
+	int ret;
+
+	*(__le32 *)cardp->ep_out_buf = cpu_to_le32(CMD_TYPE_REQUEST);
+
+	cmd->hdr.command = cpu_to_le16(CMD_802_11_RESET);
+	cmd->hdr.size = cpu_to_le16(sizeof(struct cmd_ds_802_11_reset));
+	cmd->hdr.result = cpu_to_le16(0);
+	cmd->hdr.seqnum = cpu_to_le16(0x5a5a);
+	cmd->action = cpu_to_le16(CMD_ACT_HALT);
+	usb_tx_block(cardp, cardp->ep_out_buf,
+		     4 + sizeof(struct cmd_ds_802_11_reset), 0);
+
+	msleep(100);
+	ret = usb_reset_device(cardp->udev);
+	msleep(100);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(if_usb_reset_device);
+
+/**
+ *  usb_tx_block - transfer data to the device
+ *
+ *  @priv 	pointer to struct lbtf_private
+ *  @payload	pointer to payload data
+ *  @nb		data length
+ *  @data	non-zero for data, zero for commands
+ *
+ *  Returns: 0 on success, nonzero otherwise.
+ */
+static int usb_tx_block(struct if_usb_card *cardp, uint8_t *payload,
+			uint16_t nb, u8 data)
+{
+	struct urb *urb;
+
+	/* check if device is removed */
+	if (cardp->priv->surpriseremoved)
+		return -1;
+
+	if (data)
+		urb = cardp->tx_urb;
+	else
+		urb = cardp->cmd_urb;
+
+	usb_fill_bulk_urb(urb, cardp->udev,
+			  usb_sndbulkpipe(cardp->udev,
+					  cardp->ep_out),
+			  payload, nb, if_usb_write_bulk_callback, cardp);
+
+	urb->transfer_flags |= URB_ZERO_PACKET;
+
+	if (usb_submit_urb(urb, GFP_ATOMIC))
+		return -1;
+	return 0;
+}
+
+static int __if_usb_submit_rx_urb(struct if_usb_card *cardp,
+				  void (*callbackfn)(struct urb *urb))
+{
+	struct sk_buff *skb;
+
+	skb = dev_alloc_skb(MRVDRV_ETH_RX_PACKET_BUFFER_SIZE);
+	if (!skb)
+		return -1;
+
+	cardp->rx_skb = skb;
+
+	/* Fill the receive configuration URB and initialise the Rx call back */
+	usb_fill_bulk_urb(cardp->rx_urb, cardp->udev,
+			  usb_rcvbulkpipe(cardp->udev, cardp->ep_in),
+			  (void *) (skb->tail),
+			  MRVDRV_ETH_RX_PACKET_BUFFER_SIZE, callbackfn, cardp);
+
+	cardp->rx_urb->transfer_flags |= URB_ZERO_PACKET;
+
+	if (usb_submit_urb(cardp->rx_urb, GFP_ATOMIC)) {
+		kfree_skb(skb);
+		cardp->rx_skb = NULL;
+		return -1;
+	} else
+		return 0;
+}
+
+static int if_usb_submit_rx_urb_fwload(struct if_usb_card *cardp)
+{
+	return __if_usb_submit_rx_urb(cardp, &if_usb_receive_fwload);
+}
+
+static int if_usb_submit_rx_urb(struct if_usb_card *cardp)
+{
+	return __if_usb_submit_rx_urb(cardp, &if_usb_receive);
+}
+
+static void if_usb_receive_fwload(struct urb *urb)
+{
+	struct if_usb_card *cardp = urb->context;
+	struct sk_buff *skb = cardp->rx_skb;
+	struct fwsyncheader *syncfwheader;
+	struct bootcmdresp bcmdresp;
+
+	if (urb->status) {
+		kfree_skb(skb);
+		return;
+	}
+
+	if (cardp->fwdnldover) {
+		__le32 *tmp = (__le32 *)(skb->data);
+
+		if (tmp[0] == cpu_to_le32(CMD_TYPE_INDICATION) &&
+		    tmp[1] == cpu_to_le32(MACREG_INT_CODE_FIRMWARE_READY))
+			/* Firmware ready event received */
+			wake_up(&cardp->fw_wq);
+		else
+			if_usb_submit_rx_urb_fwload(cardp);
+		kfree_skb(skb);
+		return;
+	}
+	if (cardp->bootcmdresp <= 0) {
+		memcpy(&bcmdresp, skb->data, sizeof(bcmdresp));
+
+		if (le16_to_cpu(cardp->udev->descriptor.bcdDevice) < 0x3106) {
+			kfree_skb(skb);
+			if_usb_submit_rx_urb_fwload(cardp);
+			cardp->bootcmdresp = 1;
+			/* Received valid boot command response */
+			return;
+		}
+		if (bcmdresp.magic != cpu_to_le32(BOOT_CMD_MAGIC_NUMBER)) {
+			if (bcmdresp.magic == cpu_to_le32(CMD_TYPE_REQUEST) ||
+			    bcmdresp.magic == cpu_to_le32(CMD_TYPE_DATA) ||
+			    bcmdresp.magic == cpu_to_le32(CMD_TYPE_INDICATION))
+				cardp->bootcmdresp = -1;
+		} else if (bcmdresp.cmd == BOOT_CMD_FW_BY_USB &&
+			   bcmdresp.result == BOOT_CMD_RESP_OK)
+			cardp->bootcmdresp = 1;
+
+		kfree_skb(skb);
+		if_usb_submit_rx_urb_fwload(cardp);
+		return;
+	}
+
+	syncfwheader = kmalloc(sizeof(struct fwsyncheader), GFP_ATOMIC);
+	if (!syncfwheader) {
+		kfree_skb(skb);
+		return;
+	}
+
+	memcpy(syncfwheader, skb->data, sizeof(struct fwsyncheader));
+
+	if (!syncfwheader->cmd)
+		cardp->CRC_OK = 1;
+	else
+		cardp->CRC_OK = 0;
+	kfree_skb(skb);
+
+	/* reschedule timer for 200ms hence */
+	mod_timer(&cardp->fw_timeout, jiffies + (HZ/5));
+
+	if (cardp->fwfinalblk) {
+		cardp->fwdnldover = 1;
+		goto exit;
+	}
+
+	if_usb_send_fw_pkt(cardp);
+
+ exit:
+	if_usb_submit_rx_urb_fwload(cardp);
+
+	kfree(syncfwheader);
+
+	return;
+}
+
+#define MRVDRV_MIN_PKT_LEN	30
+
+static inline void process_cmdtypedata(int recvlength, struct sk_buff *skb,
+				       struct if_usb_card *cardp,
+				       struct lbtf_private *priv)
+{
+	if (recvlength > MRVDRV_ETH_RX_PACKET_BUFFER_SIZE + MESSAGE_HEADER_LEN
+	    || recvlength < MRVDRV_MIN_PKT_LEN) {
+		kfree_skb(skb);
+		return;
+	}
+
+	skb_put(skb, recvlength);
+	skb_pull(skb, MESSAGE_HEADER_LEN);
+	lbtf_rx(priv, skb);
+}
+
+static inline void process_cmdrequest(int recvlength, uint8_t *recvbuff,
+				      struct sk_buff *skb,
+				      struct if_usb_card *cardp,
+				      struct lbtf_private *priv)
+{
+	if (recvlength > LBS_CMD_BUFFER_SIZE) {
+		kfree_skb(skb);
+		return;
+	}
+
+	if (!in_interrupt())
+		BUG();
+
+	spin_lock(&priv->driver_lock);
+	memcpy(priv->cmd_resp_buff, recvbuff + MESSAGE_HEADER_LEN,
+	       recvlength - MESSAGE_HEADER_LEN);
+	kfree_skb(skb);
+	lbtf_cmd_response_rx(priv);
+	spin_unlock(&priv->driver_lock);
+}
+
+/**
+ *  if_usb_receive - read data received from the device.
+ *
+ *  @urb		pointer to struct urb
+ */
+static void if_usb_receive(struct urb *urb)
+{
+	struct if_usb_card *cardp = urb->context;
+	struct sk_buff *skb = cardp->rx_skb;
+	struct lbtf_private *priv = cardp->priv;
+	int recvlength = urb->actual_length;
+	uint8_t *recvbuff = NULL;
+	uint32_t recvtype = 0;
+	__le32 *pkt = (__le32 *) skb->data;
+
+	if (recvlength) {
+		if (urb->status) {
+			kfree_skb(skb);
+			goto setup_for_next;
+		}
+
+		recvbuff = skb->data;
+		recvtype = le32_to_cpu(pkt[0]);
+	} else if (urb->status) {
+		kfree_skb(skb);
+		return;
+	}
+
+	switch (recvtype) {
+	case CMD_TYPE_DATA:
+		process_cmdtypedata(recvlength, skb, cardp, priv);
+		break;
+
+	case CMD_TYPE_REQUEST:
+		process_cmdrequest(recvlength, recvbuff, skb, cardp, priv);
+		break;
+
+	case CMD_TYPE_INDICATION:
+	{
+		/* Event cause handling */
+		u32 event_cause = le32_to_cpu(pkt[1]);
+
+		/* Icky undocumented magic special case */
+		if (event_cause & 0xffff0000) {
+			u16 tmp;
+			u8 retrycnt;
+			u8 failure;
+
+			tmp = event_cause >> 16;
+			retrycnt = tmp & 0x00ff;
+			failure = (tmp & 0xff00) >> 8;
+			lbtf_send_tx_feedback(priv, retrycnt, failure);
+		} else if (event_cause == LBTF_EVENT_BCN_SENT)
+			lbtf_bcn_sent(priv);
+		else
+			printk(KERN_DEBUG
+			       "Unsupported notification %d received\n",
+			       event_cause);
+		kfree_skb(skb);
+		break;
+	}
+	default:
+		printk(KERN_DEBUG "libertastf: unknown command type 0x%X\n",
+			     recvtype);
+		kfree_skb(skb);
+		break;
+	}
+
+setup_for_next:
+	if_usb_submit_rx_urb(cardp);
+}
+
+/**
+ *  if_usb_host_to_card -  Download data to the device
+ *
+ *  @priv		pointer to struct lbtf_private structure
+ *  @type		type of data
+ *  @buf		pointer to data buffer
+ *  @len		number of bytes
+ *
+ *  Returns: 0 on success, nonzero otherwise
+ */
+static int if_usb_host_to_card(struct lbtf_private *priv, uint8_t type,
+			       uint8_t *payload, uint16_t nb)
+{
+	struct if_usb_card *cardp = priv->card;
+	u8 data = 0;
+
+	if (type == MVMS_CMD) {
+		*(__le32 *)cardp->ep_out_buf = cpu_to_le32(CMD_TYPE_REQUEST);
+	} else {
+		*(__le32 *)cardp->ep_out_buf = cpu_to_le32(CMD_TYPE_DATA);
+		data = 1;
+	}
+
+	memcpy((cardp->ep_out_buf + MESSAGE_HEADER_LEN), payload, nb);
+
+	return usb_tx_block(cardp, cardp->ep_out_buf, nb + MESSAGE_HEADER_LEN,
+			    data);
+}
+
+/**
+ *  if_usb_issue_boot_command - Issue boot command to Boot2.
+ *
+ *  @ivalue   1 boots from FW by USB-Download, 2 boots from FW in EEPROM.
+ *
+ *  Returns: 0
+ */
+static int if_usb_issue_boot_command(struct if_usb_card *cardp, int ivalue)
+{
+	struct bootcmd *bootcmd = cardp->ep_out_buf;
+
+	/* Prepare command */
+	bootcmd->magic = cpu_to_le32(BOOT_CMD_MAGIC_NUMBER);
+	bootcmd->cmd = ivalue;
+	memset(bootcmd->pad, 0, sizeof(bootcmd->pad));
+
+	/* Issue command */
+	usb_tx_block(cardp, cardp->ep_out_buf, sizeof(*bootcmd), 0);
+
+	return 0;
+}
+
+
+/**
+ *  check_fwfile_format - Check the validity of Boot2/FW image.
+ *
+ *  @data	pointer to image
+ *  @totlen	image length
+ *
+ *  Returns: 0 if the image is valid, nonzero otherwise.
+ */
+static int check_fwfile_format(const u8 *data, u32 totlen)
+{
+	u32 bincmd, exit;
+	u32 blksize, offset, len;
+	int ret;
+
+	ret = 1;
+	exit = len = 0;
+
+	do {
+		struct fwheader *fwh = (void *) data;
+
+		bincmd = le32_to_cpu(fwh->dnldcmd);
+		blksize = le32_to_cpu(fwh->datalength);
+		switch (bincmd) {
+		case FW_HAS_DATA_TO_RECV:
+			offset = sizeof(struct fwheader) + blksize;
+			data += offset;
+			len += offset;
+			if (len >= totlen)
+				exit = 1;
+			break;
+		case FW_HAS_LAST_BLOCK:
+			exit = 1;
+			ret = 0;
+			break;
+		default:
+			exit = 1;
+			break;
+		}
+	} while (!exit);
+
+	if (ret)
+		printk(KERN_INFO
+		       "libertastf: firmware file format check failed\n");
+	return ret;
+}
+
+
+static int if_usb_prog_firmware(struct if_usb_card *cardp)
+{
+	int i = 0;
+	static int reset_count = 10;
+	int ret = 0;
+
+	ret = request_firmware(&cardp->fw, lbtf_fw_name, &cardp->udev->dev);
+	if (ret < 0) {
+		printk(KERN_INFO "libertastf: firmware %s not found\n",
+		       lbtf_fw_name);
+		goto done;
+	}
+
+	if (check_fwfile_format(cardp->fw->data, cardp->fw->size))
+		goto release_fw;
+
+restart:
+	if (if_usb_submit_rx_urb_fwload(cardp) < 0) {
+		ret = -1;
+		goto release_fw;
+	}
+
+	cardp->bootcmdresp = 0;
+	do {
+		int j = 0;
+		i++;
+		/* Issue Boot command = 1, Boot from Download-FW */
+		if_usb_issue_boot_command(cardp, BOOT_CMD_FW_BY_USB);
+		/* wait for command response */
+		do {
+			j++;
+			msleep_interruptible(100);
+		} while (cardp->bootcmdresp == 0 && j < 10);
+	} while (cardp->bootcmdresp == 0 && i < 5);
+
+	if (cardp->bootcmdresp <= 0) {
+		if (--reset_count >= 0) {
+			if_usb_reset_device(cardp);
+			goto restart;
+		}
+		return -1;
+	}
+
+	i = 0;
+
+	cardp->totalbytes = 0;
+	cardp->fwlastblksent = 0;
+	cardp->CRC_OK = 1;
+	cardp->fwdnldover = 0;
+	cardp->fwseqnum = -1;
+	cardp->totalbytes = 0;
+	cardp->fwfinalblk = 0;
+
+	/* Send the first firmware packet... */
+	if_usb_send_fw_pkt(cardp);
+
+	/* ... and wait for the process to complete */
+	wait_event_interruptible(cardp->fw_wq, cardp->priv->surpriseremoved ||
+					       cardp->fwdnldover);
+
+	del_timer_sync(&cardp->fw_timeout);
+	usb_kill_urb(cardp->rx_urb);
+
+	if (!cardp->fwdnldover) {
+		printk(KERN_INFO "libertastf: failed to load fw,"
+				 " resetting device!\n");
+		if (--reset_count >= 0) {
+			if_usb_reset_device(cardp);
+			goto restart;
+		}
+
+		printk(KERN_INFO "libertastf: fw download failure\n");
+		ret = -1;
+		goto release_fw;
+	}
+
+	cardp->priv->fw_ready = 1;
+
+ release_fw:
+	release_firmware(cardp->fw);
+	cardp->fw = NULL;
+
+	if_usb_setup_firmware(cardp->priv);
+
+ done:
+	return ret;
+}
+EXPORT_SYMBOL_GPL(if_usb_prog_firmware);
+
+
+#define if_usb_suspend NULL
+#define if_usb_resume NULL
+
+static struct usb_driver if_usb_driver = {
+	.name = DRV_NAME,
+	.probe = if_usb_probe,
+	.disconnect = if_usb_disconnect,
+	.id_table = if_usb_table,
+	.suspend = if_usb_suspend,
+	.resume = if_usb_resume,
+};
+
+static int __init if_usb_init_module(void)
+{
+	int ret = 0;
+
+	ret = usb_register(&if_usb_driver);
+	return ret;
+}
+
+static void __exit if_usb_exit_module(void)
+{
+	usb_deregister(&if_usb_driver);
+}
+
+module_init(if_usb_init_module);
+module_exit(if_usb_exit_module);
+
+MODULE_DESCRIPTION("8388 USB WLAN Thinfirm Driver");
+MODULE_AUTHOR("Cozybit Inc.");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/wireless/libertas_tf/if_usb.h b/drivers/net/wireless/libertas_tf/if_usb.h
new file mode 100644
index 0000000..6fa5b3f5
--- /dev/null
+++ b/drivers/net/wireless/libertas_tf/if_usb.h
@@ -0,0 +1,98 @@
+/*
+ *  Copyright (C) 2008, cozybit Inc.
+ *  Copyright (C) 2003-2006, Marvell International Ltd.
+ *
+ *  This program is free software; you can redistribute it and/or 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/wait.h>
+#include <linux/timer.h>
+
+struct lbtf_private;
+
+/**
+  * This file contains definition for USB interface.
+  */
+#define CMD_TYPE_REQUEST		0xF00DFACE
+#define CMD_TYPE_DATA			0xBEADC0DE
+#define CMD_TYPE_INDICATION		0xBEEFFACE
+
+#define BOOT_CMD_FW_BY_USB		0x01
+#define BOOT_CMD_FW_IN_EEPROM		0x02
+#define BOOT_CMD_UPDATE_BOOT2		0x03
+#define BOOT_CMD_UPDATE_FW		0x04
+#define BOOT_CMD_MAGIC_NUMBER		0x4C56524D   /* LVRM */
+
+struct bootcmd {
+	__le32	magic;
+	uint8_t	cmd;
+	uint8_t	pad[11];
+};
+
+#define BOOT_CMD_RESP_OK		0x0001
+#define BOOT_CMD_RESP_FAIL		0x0000
+
+struct bootcmdresp {
+	__le32	magic;
+	uint8_t	cmd;
+	uint8_t	result;
+	uint8_t	pad[2];
+};
+
+/** USB card description structure*/
+struct if_usb_card {
+	struct usb_device *udev;
+	struct urb *rx_urb, *tx_urb, *cmd_urb;
+	struct lbtf_private *priv;
+
+	struct sk_buff *rx_skb;
+
+	uint8_t ep_in;
+	uint8_t ep_out;
+
+	int8_t bootcmdresp;
+
+	int ep_in_size;
+
+	void *ep_out_buf;
+	int ep_out_size;
+
+	const struct firmware *fw;
+	struct timer_list fw_timeout;
+	wait_queue_head_t fw_wq;
+	uint32_t fwseqnum;
+	uint32_t totalbytes;
+	uint32_t fwlastblksent;
+	uint8_t CRC_OK;
+	uint8_t fwdnldover;
+	uint8_t fwfinalblk;
+
+	__le16 boot2_version;
+};
+
+/** fwheader */
+struct fwheader {
+	__le32 dnldcmd;
+	__le32 baseaddr;
+	__le32 datalength;
+	__le32 CRC;
+};
+
+#define FW_MAX_DATA_BLK_SIZE	600
+/** FWData */
+struct fwdata {
+	struct fwheader hdr;
+	__le32 seqnum;
+	uint8_t data[0];
+};
+
+/** fwsyncheader */
+struct fwsyncheader {
+	__le32 cmd;
+	__le32 seqnum;
+};
+
+#define FW_HAS_DATA_TO_RECV		0x00000001
+#define FW_HAS_LAST_BLOCK		0x00000004
diff --git a/drivers/net/wireless/libertas_tf/libertas_tf.h b/drivers/net/wireless/libertas_tf/libertas_tf.h
new file mode 100644
index 0000000..8995cd7
--- /dev/null
+++ b/drivers/net/wireless/libertas_tf/libertas_tf.h
@@ -0,0 +1,514 @@
+/*
+ *  Copyright (C) 2008, cozybit Inc.
+ *  Copyright (C) 2007, Red Hat, Inc.
+ *  Copyright (C) 2003-2006, Marvell International Ltd.
+ *
+ *  This program is free software; you can redistribute it and/or 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/spinlock.h>
+#include <linux/device.h>
+#include <linux/kthread.h>
+#include <net/mac80211.h>
+
+#ifndef DRV_NAME
+#define DRV_NAME "libertas_tf"
+#endif
+
+#define	MRVL_DEFAULT_RETRIES			9
+#define MRVL_PER_PACKET_RATE			0x10
+#define MRVL_MAX_BCN_SIZE			440
+#define CMD_OPTION_WAITFORRSP			0x0002
+
+/* Return command are almost always the same as the host command, but with
+ * bit 15 set high.  There are a few exceptions, though...
+ */
+#define CMD_RET(cmd)			(0x8000 | cmd)
+
+/* Command codes */
+#define CMD_GET_HW_SPEC				0x0003
+#define CMD_802_11_RESET			0x0005
+#define CMD_MAC_MULTICAST_ADR			0x0010
+#define CMD_802_11_RADIO_CONTROL		0x001c
+#define CMD_802_11_RF_CHANNEL			0x001d
+#define CMD_802_11_RF_TX_POWER			0x001e
+#define CMD_MAC_CONTROL				0x0028
+#define CMD_802_11_MAC_ADDRESS			0x004d
+#define	CMD_SET_BOOT2_VER			0x00a5
+#define CMD_802_11_BEACON_CTRL			0x00b0
+#define CMD_802_11_BEACON_SET			0x00cb
+#define CMD_802_11_SET_MODE			0x00cc
+#define CMD_802_11_SET_BSSID			0x00cd
+
+#define CMD_ACT_GET			0x0000
+#define CMD_ACT_SET			0x0001
+
+/* Define action or option for CMD_802_11_RESET */
+#define CMD_ACT_HALT			0x0003
+
+/* Define action or option for CMD_MAC_CONTROL */
+#define CMD_ACT_MAC_RX_ON			0x0001
+#define CMD_ACT_MAC_TX_ON			0x0002
+#define CMD_ACT_MAC_MULTICAST_ENABLE		0x0020
+#define CMD_ACT_MAC_BROADCAST_ENABLE		0x0040
+#define CMD_ACT_MAC_PROMISCUOUS_ENABLE		0x0080
+#define CMD_ACT_MAC_ALL_MULTICAST_ENABLE	0x0100
+
+/* Define action or option for CMD_802_11_RADIO_CONTROL */
+#define CMD_TYPE_AUTO_PREAMBLE		0x0001
+#define CMD_TYPE_SHORT_PREAMBLE		0x0002
+#define CMD_TYPE_LONG_PREAMBLE		0x0003
+
+#define TURN_ON_RF			0x01
+#define RADIO_ON			0x01
+#define RADIO_OFF			0x00
+
+#define SET_AUTO_PREAMBLE		0x05
+#define SET_SHORT_PREAMBLE		0x03
+#define SET_LONG_PREAMBLE		0x01
+
+/* Define action or option for CMD_802_11_RF_CHANNEL */
+#define CMD_OPT_802_11_RF_CHANNEL_GET	0x00
+#define CMD_OPT_802_11_RF_CHANNEL_SET	0x01
+
+/* Codes for CMD_802_11_SET_MODE */
+enum lbtf_mode {
+	LBTF_PASSIVE_MODE,
+	LBTF_STA_MODE,
+	LBTF_AP_MODE,
+};
+
+/** Card Event definition */
+#define MACREG_INT_CODE_FIRMWARE_READY		48
+/** Buffer Constants */
+
+/*	The size of SQ memory PPA, DPA are 8 DWORDs, that keep the physical
+*	addresses of TxPD buffers. Station has only 8 TxPD available, Whereas
+*	driver has more local TxPDs. Each TxPD on the host memory is associated
+*	with a Tx control node. The driver maintains 8 RxPD descriptors for
+*	station firmware to store Rx packet information.
+*
+*	Current version of MAC has a 32x6 multicast address buffer.
+*
+*	802.11b can have up to  14 channels, the driver keeps the
+*	BSSID(MAC address) of each APs or Ad hoc stations it has sensed.
+*/
+
+#define MRVDRV_MAX_MULTICAST_LIST_SIZE	32
+#define LBS_NUM_CMD_BUFFERS             10
+#define LBS_CMD_BUFFER_SIZE             (2 * 1024)
+#define MRVDRV_MAX_CHANNEL_SIZE		14
+#define MRVDRV_SNAP_HEADER_LEN          8
+
+#define	LBS_UPLD_SIZE			2312
+#define DEV_NAME_LEN			32
+
+/** Misc constants */
+/* This section defines 802.11 specific contants */
+
+#define MRVDRV_MAX_REGION_CODE			6
+/**
+ * the table to keep region code
+ */
+#define LBTF_REGDOMAIN_US	0x10
+#define LBTF_REGDOMAIN_CA	0x20
+#define LBTF_REGDOMAIN_EU	0x30
+#define LBTF_REGDOMAIN_SP	0x31
+#define LBTF_REGDOMAIN_FR	0x32
+#define LBTF_REGDOMAIN_JP	0x40
+
+#define SBI_EVENT_CAUSE_SHIFT		3
+
+/** RxPD status */
+
+#define MRVDRV_RXPD_STATUS_OK                0x0001
+
+
+/* This is for firmware specific length */
+#define EXTRA_LEN	36
+
+#define MRVDRV_ETH_TX_PACKET_BUFFER_SIZE \
+	(ETH_FRAME_LEN + sizeof(struct txpd) + EXTRA_LEN)
+
+#define MRVDRV_ETH_RX_PACKET_BUFFER_SIZE \
+	(ETH_FRAME_LEN + sizeof(struct rxpd) \
+	 + MRVDRV_SNAP_HEADER_LEN + EXTRA_LEN)
+
+#define	CMD_F_HOSTCMD		(1 << 0)
+#define FW_CAPINFO_WPA  	(1 << 0)
+
+#define RF_ANTENNA_1		0x1
+#define RF_ANTENNA_2		0x2
+#define RF_ANTENNA_AUTO		0xFFFF
+
+#define LBTF_EVENT_BCN_SENT	55
+
+/** Global Variable Declaration */
+/** mv_ms_type */
+enum mv_ms_type {
+	MVMS_DAT = 0,
+	MVMS_CMD = 1,
+	MVMS_TXDONE = 2,
+	MVMS_EVENT
+};
+
+extern struct workqueue_struct *lbtf_wq;
+
+struct lbtf_private;
+
+struct lbtf_offset_value {
+	u32 offset;
+	u32 value;
+};
+
+struct channel_range {
+	u8 regdomain;
+	u8 start;
+	u8 end; /* exclusive (channel must be less than end) */
+};
+
+struct if_usb_card;
+
+/** Private structure for the MV device */
+struct lbtf_private {
+	void *card;
+	struct ieee80211_hw *hw;
+
+	/* Command response buffer */
+	u8 cmd_resp_buff[LBS_UPLD_SIZE];
+	/* Download sent:
+	   bit0 1/0=data_sent/data_tx_done,
+	   bit1 1/0=cmd_sent/cmd_tx_done,
+	   all other bits reserved 0 */
+	struct ieee80211_vif *vif;
+
+	struct work_struct cmd_work;
+	struct work_struct tx_work;
+	/** Hardware access */
+	int (*hw_host_to_card) (struct lbtf_private *priv, u8 type, u8 *payload, u16 nb);
+	int (*hw_prog_firmware) (struct if_usb_card *cardp);
+	int (*hw_reset_device) (struct if_usb_card *cardp);
+
+
+	/** Wlan adapter data structure*/
+	/** STATUS variables */
+	u32 fwrelease;
+	u32 fwcapinfo;
+	/* protected with big lock */
+
+	struct mutex lock;
+
+	/** command-related variables */
+	u16 seqnum;
+	/* protected by big lock */
+
+	struct cmd_ctrl_node *cmd_array;
+	/** Current command */
+	struct cmd_ctrl_node *cur_cmd;
+	/** command Queues */
+	/** Free command buffers */
+	struct list_head cmdfreeq;
+	/** Pending command buffers */
+	struct list_head cmdpendingq;
+
+	/** spin locks */
+	spinlock_t driver_lock;
+
+	/** Timers */
+	struct timer_list command_timer;
+	int nr_retries;
+	int cmd_timed_out;
+
+	u8 cmd_response_rxed;
+
+	/** capability Info used in Association, start, join */
+	u16 capability;
+
+	/** MAC address information */
+	u8 current_addr[ETH_ALEN];
+	u8 multicastlist[MRVDRV_MAX_MULTICAST_LIST_SIZE][ETH_ALEN];
+	u32 nr_of_multicastmacaddr;
+	int cur_freq;
+
+	struct sk_buff *skb_to_tx;
+	struct sk_buff *tx_skb;
+
+	/** NIC Operation characteristics */
+	u16 mac_control;
+	u16 regioncode;
+	struct channel_range range;
+
+	u8 radioon;
+	u32 preamble;
+
+	struct ieee80211_channel channels[14];
+	struct ieee80211_rate rates[12];
+	struct ieee80211_supported_band band;
+	struct lbtf_offset_value offsetvalue;
+
+	u8 fw_ready;
+	u8 surpriseremoved;
+	struct sk_buff_head bc_ps_buf;
+};
+
+/* 802.11-related definitions */
+
+/* TxPD descriptor */
+struct txpd {
+	/* Current Tx packet status */
+	__le32 tx_status;
+	/* Tx control */
+	__le32 tx_control;
+	__le32 tx_packet_location;
+	/* Tx packet length */
+	__le16 tx_packet_length;
+	/* First 2 byte of destination MAC address */
+	u8 tx_dest_addr_high[2];
+	/* Last 4 byte of destination MAC address */
+	u8 tx_dest_addr_low[4];
+	/* Pkt Priority */
+	u8 priority;
+	/* Pkt Trasnit Power control */
+	u8 powermgmt;
+	/* Time the packet has been queued in the driver (units = 2ms) */
+	u8 pktdelay_2ms;
+	/* reserved */
+	u8 reserved1;
+};
+
+/* RxPD Descriptor */
+struct rxpd {
+	/* Current Rx packet status */
+	__le16 status;
+
+	/* SNR */
+	u8 snr;
+
+	/* Tx control */
+	u8 rx_control;
+
+	/* Pkt length */
+	__le16 pkt_len;
+
+	/* Noise Floor */
+	u8 nf;
+
+	/* Rx Packet Rate */
+	u8 rx_rate;
+
+	/* Pkt addr */
+	__le32 pkt_ptr;
+
+	/* Next Rx RxPD addr */
+	__le32 next_rxpd_ptr;
+
+	/* Pkt Priority */
+	u8 priority;
+	u8 reserved[3];
+};
+
+struct cmd_header {
+	__le16 command;
+	__le16 size;
+	__le16 seqnum;
+	__le16 result;
+} __attribute__ ((packed));
+
+struct cmd_ctrl_node {
+	struct list_head list;
+	int result;
+	/* command response */
+	int (*callback)(struct lbtf_private *,
+			unsigned long, struct cmd_header *);
+	unsigned long callback_arg;
+	/* command data */
+	struct cmd_header *cmdbuf;
+	/* wait queue */
+	u16 cmdwaitqwoken;
+	wait_queue_head_t cmdwait_q;
+};
+
+/*
+ * Define data structure for CMD_GET_HW_SPEC
+ * This structure defines the response for the GET_HW_SPEC command
+ */
+struct cmd_ds_get_hw_spec {
+	struct cmd_header hdr;
+
+	/* HW Interface version number */
+	__le16 hwifversion;
+	/* HW version number */
+	__le16 version;
+	/* Max number of TxPD FW can handle */
+	__le16 nr_txpd;
+	/* Max no of Multicast address */
+	__le16 nr_mcast_adr;
+	/* MAC address */
+	u8 permanentaddr[6];
+
+	/* region Code */
+	__le16 regioncode;
+
+	/* Number of antenna used */
+	__le16 nr_antenna;
+
+	/* FW release number, example 0x01030304 = 2.3.4p1 */
+	__le32 fwrelease;
+
+	/* Base Address of TxPD queue */
+	__le32 wcb_base;
+	/* Read Pointer of RxPd queue */
+	__le32 rxpd_rdptr;
+
+	/* Write Pointer of RxPd queue */
+	__le32 rxpd_wrptr;
+
+	/*FW/HW capability */
+	__le32 fwcapinfo;
+} __attribute__ ((packed));
+
+struct cmd_ds_mac_control {
+	struct cmd_header hdr;
+	__le16 action;
+	u16 reserved;
+};
+
+struct cmd_ds_802_11_mac_address {
+	struct cmd_header hdr;
+
+	__le16 action;
+	uint8_t macadd[ETH_ALEN];
+};
+
+struct cmd_ds_mac_multicast_addr {
+	struct cmd_header hdr;
+
+	__le16 action;
+	__le16 nr_of_adrs;
+	u8 maclist[ETH_ALEN * MRVDRV_MAX_MULTICAST_LIST_SIZE];
+};
+
+struct cmd_ds_set_mode {
+	struct cmd_header hdr;
+
+	__le16 mode;
+};
+
+struct cmd_ds_set_bssid {
+	struct cmd_header hdr;
+
+	u8 bssid[6];
+	u8 activate;
+};
+
+struct cmd_ds_802_11_radio_control {
+	struct cmd_header hdr;
+
+	__le16 action;
+	__le16 control;
+};
+
+
+struct cmd_ds_802_11_rf_channel {
+	struct cmd_header hdr;
+
+	__le16 action;
+	__le16 channel;
+	__le16 rftype;      /* unused */
+	__le16 reserved;    /* unused */
+	u8 channellist[32]; /* unused */
+};
+
+struct cmd_ds_set_boot2_ver {
+	struct cmd_header hdr;
+
+	__le16 action;
+	__le16 version;
+};
+
+struct cmd_ds_802_11_reset {
+	struct cmd_header hdr;
+
+	__le16 action;
+};
+
+struct cmd_ds_802_11_beacon_control {
+	struct cmd_header hdr;
+
+	__le16 action;
+	__le16 beacon_enable;
+	__le16 beacon_period;
+};
+
+struct cmd_ds_802_11_beacon_set {
+	struct cmd_header hdr;
+
+	__le16 len;
+	u8 beacon[MRVL_MAX_BCN_SIZE];
+};
+
+struct lbtf_private;
+struct cmd_ctrl_node;
+
+/** Function Prototype Declaration */
+void lbtf_set_mac_control(struct lbtf_private *priv);
+
+int lbtf_free_cmd_buffer(struct lbtf_private *priv);
+
+int lbtf_allocate_cmd_buffer(struct lbtf_private *priv);
+int lbtf_execute_next_command(struct lbtf_private *priv);
+int lbtf_set_radio_control(struct lbtf_private *priv);
+int lbtf_update_hw_spec(struct lbtf_private *priv);
+int lbtf_cmd_set_mac_multicast_addr(struct lbtf_private *priv);
+void lbtf_set_mode(struct lbtf_private *priv, enum lbtf_mode mode);
+void lbtf_set_bssid(struct lbtf_private *priv, bool activate, u8 *bssid);
+int lbtf_set_mac_address(struct lbtf_private *priv, uint8_t *mac_addr);
+
+int lbtf_set_channel(struct lbtf_private *priv, u8 channel);
+
+int lbtf_beacon_set(struct lbtf_private *priv, struct sk_buff *beacon);
+int lbtf_beacon_ctrl(struct lbtf_private *priv, bool beacon_enable,
+		     int beacon_int);
+
+
+int lbtf_process_rx_command(struct lbtf_private *priv);
+void lbtf_complete_command(struct lbtf_private *priv, struct cmd_ctrl_node *cmd,
+			  int result);
+void lbtf_cmd_response_rx(struct lbtf_private *priv);
+
+/* main.c */
+struct chan_freq_power *lbtf_get_region_cfp_table(u8 region,
+	int *cfp_no);
+struct lbtf_private *lbtf_add_card(void *card, struct device *dmdev);
+int lbtf_remove_card(struct lbtf_private *priv);
+int lbtf_start_card(struct lbtf_private *priv);
+int lbtf_rx(struct lbtf_private *priv, struct sk_buff *skb);
+void lbtf_send_tx_feedback(struct lbtf_private *priv, u8 retrycnt, u8 fail);
+void lbtf_bcn_sent(struct lbtf_private *priv);
+
+/* support functions for cmd.c */
+/* lbtf_cmd() infers the size of the buffer to copy data back into, from
+   the size of the target of the pointer. Since the command to be sent
+   may often be smaller, that size is set in cmd->size by the caller.*/
+#define lbtf_cmd(priv, cmdnr, cmd, cb, cb_arg)	({		\
+	uint16_t __sz = le16_to_cpu((cmd)->hdr.size);		\
+	(cmd)->hdr.size = cpu_to_le16(sizeof(*(cmd)));		\
+	__lbtf_cmd(priv, cmdnr, &(cmd)->hdr, __sz, cb, cb_arg);	\
+})
+
+#define lbtf_cmd_with_response(priv, cmdnr, cmd)	\
+	lbtf_cmd(priv, cmdnr, cmd, lbtf_cmd_copyback, (unsigned long) (cmd))
+
+void lbtf_cmd_async(struct lbtf_private *priv, uint16_t command,
+	struct cmd_header *in_cmd, int in_cmd_size);
+
+int __lbtf_cmd(struct lbtf_private *priv, uint16_t command,
+	      struct cmd_header *in_cmd, int in_cmd_size,
+	      int (*callback)(struct lbtf_private *, unsigned long,
+			      struct cmd_header *),
+	      unsigned long callback_arg);
+
+int lbtf_cmd_copyback(struct lbtf_private *priv, unsigned long extra,
+		     struct cmd_header *resp);
diff --git a/drivers/net/wireless/libertas_tf/main.c b/drivers/net/wireless/libertas_tf/main.c
new file mode 100644
index 0000000..feff945
--- /dev/null
+++ b/drivers/net/wireless/libertas_tf/main.c
@@ -0,0 +1,662 @@
+/*
+ *  Copyright (C) 2008, cozybit Inc.
+ *  Copyright (C) 2003-2006, Marvell International Ltd.
+ *
+ *  This program is free software; you can redistribute it and/or 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 "libertas_tf.h"
+#include "linux/etherdevice.h"
+
+#define DRIVER_RELEASE_VERSION "004.p0"
+/* thinfirm version: 5.132.X.pX */
+#define LBTF_FW_VER_MIN		0x05840300
+#define LBTF_FW_VER_MAX		0x0584ffff
+#define QOS_CONTROL_LEN		2
+
+static const char lbtf_driver_version[] = "THINFIRM-USB8388-" DRIVER_RELEASE_VERSION;
+struct workqueue_struct *lbtf_wq;
+
+static const struct ieee80211_channel lbtf_channels[] = {
+	{ .center_freq = 2412, .hw_value = 1 },
+	{ .center_freq = 2417, .hw_value = 2 },
+	{ .center_freq = 2422, .hw_value = 3 },
+	{ .center_freq = 2427, .hw_value = 4 },
+	{ .center_freq = 2432, .hw_value = 5 },
+	{ .center_freq = 2437, .hw_value = 6 },
+	{ .center_freq = 2442, .hw_value = 7 },
+	{ .center_freq = 2447, .hw_value = 8 },
+	{ .center_freq = 2452, .hw_value = 9 },
+	{ .center_freq = 2457, .hw_value = 10 },
+	{ .center_freq = 2462, .hw_value = 11 },
+	{ .center_freq = 2467, .hw_value = 12 },
+	{ .center_freq = 2472, .hw_value = 13 },
+	{ .center_freq = 2484, .hw_value = 14 },
+};
+
+/* This table contains the hardware specific values for the modulation rates. */
+static const struct ieee80211_rate lbtf_rates[] = {
+	{ .bitrate = 10,
+	  .hw_value = 0, },
+	{ .bitrate = 20,
+	  .hw_value = 1,
+	  .flags = IEEE80211_RATE_SHORT_PREAMBLE },
+	{ .bitrate = 55,
+	  .hw_value = 2,
+	  .flags = IEEE80211_RATE_SHORT_PREAMBLE },
+	{ .bitrate = 110,
+	  .hw_value = 3,
+	  .flags = IEEE80211_RATE_SHORT_PREAMBLE },
+	{ .bitrate = 60,
+	  .hw_value = 5,
+	  .flags = 0 },
+	{ .bitrate = 90,
+	  .hw_value = 6,
+	  .flags = 0 },
+	{ .bitrate = 120,
+	  .hw_value = 7,
+	  .flags = 0 },
+	{ .bitrate = 180,
+	  .hw_value = 8,
+	  .flags = 0 },
+	{ .bitrate = 240,
+	  .hw_value = 9,
+	  .flags = 0 },
+	{ .bitrate = 360,
+	  .hw_value = 10,
+	  .flags = 0 },
+	{ .bitrate = 480,
+	  .hw_value = 11,
+	  .flags = 0 },
+	{ .bitrate = 540,
+	  .hw_value = 12,
+	  .flags = 0 },
+};
+
+static void lbtf_cmd_work(struct work_struct *work)
+{
+	struct lbtf_private *priv = container_of(work, struct lbtf_private,
+					 cmd_work);
+	spin_lock_irq(&priv->driver_lock);
+	/* command response? */
+	if (priv->cmd_response_rxed) {
+		priv->cmd_response_rxed = 0;
+		spin_unlock_irq(&priv->driver_lock);
+		lbtf_process_rx_command(priv);
+		spin_lock_irq(&priv->driver_lock);
+	}
+
+	if (priv->cmd_timed_out && priv->cur_cmd) {
+		struct cmd_ctrl_node *cmdnode = priv->cur_cmd;
+
+		if (++priv->nr_retries > 10) {
+			lbtf_complete_command(priv, cmdnode,
+					      -ETIMEDOUT);
+			priv->nr_retries = 0;
+		} else {
+			priv->cur_cmd = NULL;
+
+			/* Stick it back at the _top_ of the pending
+			 * queue for immediate resubmission */
+			list_add(&cmdnode->list, &priv->cmdpendingq);
+		}
+	}
+	priv->cmd_timed_out = 0;
+	spin_unlock_irq(&priv->driver_lock);
+
+	if (!priv->fw_ready)
+		return;
+	/* Execute the next command */
+	if (!priv->cur_cmd)
+		lbtf_execute_next_command(priv);
+}
+
+/**
+ *  lbtf_setup_firmware: initialize firmware.
+ *
+ *  @priv    A pointer to struct lbtf_private structure
+ *
+ *  Returns: 0 on success.
+ */
+static int lbtf_setup_firmware(struct lbtf_private *priv)
+{
+	int ret = -1;
+
+	/*
+	 * Read priv address from HW
+	 */
+	memset(priv->current_addr, 0xff, ETH_ALEN);
+	ret = lbtf_update_hw_spec(priv);
+	if (ret) {
+		ret = -1;
+		goto done;
+	}
+
+	lbtf_set_mac_control(priv);
+	lbtf_set_radio_control(priv);
+
+	ret = 0;
+done:
+	return ret;
+}
+
+/**
+ *  This function handles the timeout of command sending.
+ *  It will re-send the same command again.
+ */
+static void command_timer_fn(unsigned long data)
+{
+	struct lbtf_private *priv = (struct lbtf_private *)data;
+	unsigned long flags;
+
+	spin_lock_irqsave(&priv->driver_lock, flags);
+
+	if (!priv->cur_cmd) {
+		printk(KERN_DEBUG "libertastf: command timer expired; "
+				  "no pending command\n");
+		goto out;
+	}
+
+	printk(KERN_DEBUG "libertas: command %x timed out\n",
+		le16_to_cpu(priv->cur_cmd->cmdbuf->command));
+
+	priv->cmd_timed_out = 1;
+	queue_work(lbtf_wq, &priv->cmd_work);
+out:
+	spin_unlock_irqrestore(&priv->driver_lock, flags);
+}
+
+static int lbtf_init_adapter(struct lbtf_private *priv)
+{
+	memset(priv->current_addr, 0xff, ETH_ALEN);
+	mutex_init(&priv->lock);
+
+	priv->vif = NULL;
+	setup_timer(&priv->command_timer, command_timer_fn,
+		(unsigned long)priv);
+
+	INIT_LIST_HEAD(&priv->cmdfreeq);
+	INIT_LIST_HEAD(&priv->cmdpendingq);
+
+	spin_lock_init(&priv->driver_lock);
+
+	/* Allocate the command buffers */
+	if (lbtf_allocate_cmd_buffer(priv))
+		return -1;
+
+	return 0;
+}
+
+static void lbtf_free_adapter(struct lbtf_private *priv)
+{
+	lbtf_free_cmd_buffer(priv);
+	del_timer(&priv->command_timer);
+}
+
+static int lbtf_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
+{
+	struct lbtf_private *priv = hw->priv;
+
+	priv->skb_to_tx = skb;
+	queue_work(lbtf_wq, &priv->tx_work);
+	/*
+	 * queue will be restarted when we receive transmission feedback if
+	 * there are no buffered multicast frames to send
+	 */
+	ieee80211_stop_queues(priv->hw);
+	return 0;
+}
+
+static void lbtf_tx_work(struct work_struct *work)
+{
+	struct lbtf_private *priv = container_of(work, struct lbtf_private,
+					 tx_work);
+	unsigned int len;
+	struct ieee80211_tx_info *info;
+	struct txpd *txpd;
+	struct sk_buff *skb = NULL;
+	int err;
+
+	if ((priv->vif->type == NL80211_IFTYPE_AP) &&
+	    (!skb_queue_empty(&priv->bc_ps_buf)))
+		skb = skb_dequeue(&priv->bc_ps_buf);
+	else if (priv->skb_to_tx) {
+		skb = priv->skb_to_tx;
+		priv->skb_to_tx = NULL;
+	} else
+		return;
+
+	len = skb->len;
+	info  = IEEE80211_SKB_CB(skb);
+	txpd = (struct txpd *)  skb_push(skb, sizeof(struct txpd));
+
+	if (priv->surpriseremoved) {
+		dev_kfree_skb_any(skb);
+		return;
+	}
+
+	memset(txpd, 0, sizeof(struct txpd));
+	/* Activate per-packet rate selection */
+	txpd->tx_control |= cpu_to_le32(MRVL_PER_PACKET_RATE |
+			     ieee80211_get_tx_rate(priv->hw, info)->hw_value);
+
+	/* copy destination address from 802.11 header */
+	memcpy(txpd->tx_dest_addr_high, skb->data + sizeof(struct txpd) + 4,
+		ETH_ALEN);
+	txpd->tx_packet_length = cpu_to_le16(len);
+	txpd->tx_packet_location = cpu_to_le32(sizeof(struct txpd));
+	BUG_ON(priv->tx_skb);
+	spin_lock_irq(&priv->driver_lock);
+	priv->tx_skb = skb;
+	err = priv->hw_host_to_card(priv, MVMS_DAT, skb->data, skb->len);
+	spin_unlock_irq(&priv->driver_lock);
+	if (err) {
+		dev_kfree_skb_any(skb);
+		priv->tx_skb = NULL;
+	}
+}
+
+static int lbtf_op_start(struct ieee80211_hw *hw)
+{
+	struct lbtf_private *priv = hw->priv;
+	void *card = priv->card;
+	int ret = -1;
+
+	if (!priv->fw_ready)
+		/* Upload firmware */
+		if (priv->hw_prog_firmware(card))
+			goto err_prog_firmware;
+
+	/* poke the firmware */
+	priv->capability = WLAN_CAPABILITY_SHORT_PREAMBLE;
+	priv->radioon = RADIO_ON;
+	priv->mac_control = CMD_ACT_MAC_RX_ON | CMD_ACT_MAC_TX_ON;
+	ret = lbtf_setup_firmware(priv);
+	if (ret)
+		goto err_prog_firmware;
+
+	if ((priv->fwrelease < LBTF_FW_VER_MIN) ||
+	    (priv->fwrelease > LBTF_FW_VER_MAX)) {
+		ret = -1;
+		goto err_prog_firmware;
+	}
+
+	printk(KERN_INFO "libertastf: Marvell WLAN 802.11 thinfirm adapter\n");
+	return 0;
+
+err_prog_firmware:
+	priv->hw_reset_device(card);
+	return ret;
+}
+
+static void lbtf_op_stop(struct ieee80211_hw *hw)
+{
+	struct lbtf_private *priv = hw->priv;
+	unsigned long flags;
+	struct sk_buff *skb;
+
+	struct cmd_ctrl_node *cmdnode;
+	/* Flush pending command nodes */
+	spin_lock_irqsave(&priv->driver_lock, flags);
+	list_for_each_entry(cmdnode, &priv->cmdpendingq, list) {
+		cmdnode->result = -ENOENT;
+		cmdnode->cmdwaitqwoken = 1;
+		wake_up_interruptible(&cmdnode->cmdwait_q);
+	}
+
+	spin_unlock_irqrestore(&priv->driver_lock, flags);
+	cancel_work_sync(&priv->cmd_work);
+	cancel_work_sync(&priv->tx_work);
+	while ((skb = skb_dequeue(&priv->bc_ps_buf)))
+		dev_kfree_skb_any(skb);
+	priv->radioon = RADIO_OFF;
+	lbtf_set_radio_control(priv);
+
+	return;
+}
+
+static int lbtf_op_add_interface(struct ieee80211_hw *hw,
+			struct ieee80211_if_init_conf *conf)
+{
+	struct lbtf_private *priv = hw->priv;
+	if (priv->vif != NULL)
+		return -EOPNOTSUPP;
+
+	priv->vif = conf->vif;
+	switch (conf->type) {
+	case NL80211_IFTYPE_MESH_POINT:
+	case NL80211_IFTYPE_AP:
+		lbtf_set_mode(priv, LBTF_AP_MODE);
+		break;
+	case NL80211_IFTYPE_STATION:
+		lbtf_set_mode(priv, LBTF_STA_MODE);
+		break;
+	default:
+		priv->vif = NULL;
+		return -EOPNOTSUPP;
+	}
+	lbtf_set_mac_address(priv, (u8 *) conf->mac_addr);
+	return 0;
+}
+
+static void lbtf_op_remove_interface(struct ieee80211_hw *hw,
+			struct ieee80211_if_init_conf *conf)
+{
+	struct lbtf_private *priv = hw->priv;
+
+	if (priv->vif->type == NL80211_IFTYPE_AP ||
+	    priv->vif->type == NL80211_IFTYPE_MESH_POINT)
+		lbtf_beacon_ctrl(priv, 0, 0);
+	lbtf_set_mode(priv, LBTF_PASSIVE_MODE);
+	lbtf_set_bssid(priv, 0, NULL);
+	priv->vif = NULL;
+}
+
+static int lbtf_op_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf)
+{
+	struct lbtf_private *priv = hw->priv;
+	if (conf->channel->center_freq != priv->cur_freq) {
+		priv->cur_freq = conf->channel->center_freq;
+		lbtf_set_channel(priv, conf->channel->hw_value);
+	}
+	return 0;
+}
+
+static int lbtf_op_config_interface(struct ieee80211_hw *hw,
+			struct ieee80211_vif *vif,
+			struct ieee80211_if_conf *conf)
+{
+	struct lbtf_private *priv = hw->priv;
+	struct sk_buff *beacon;
+
+	switch (priv->vif->type) {
+	case NL80211_IFTYPE_AP:
+	case NL80211_IFTYPE_MESH_POINT:
+		beacon = ieee80211_beacon_get(hw, vif);
+		if (beacon) {
+			lbtf_beacon_set(priv, beacon);
+			kfree_skb(beacon);
+			lbtf_beacon_ctrl(priv, 1, hw->conf.beacon_int);
+		}
+		break;
+	default:
+		break;
+	}
+
+	if (conf->bssid) {
+		u8 null_bssid[ETH_ALEN] = {0};
+		bool activate = compare_ether_addr(conf->bssid, null_bssid);
+		lbtf_set_bssid(priv, activate, conf->bssid);
+	}
+
+	return 0;
+}
+
+#define SUPPORTED_FIF_FLAGS  (FIF_PROMISC_IN_BSS | FIF_ALLMULTI)
+static void lbtf_op_configure_filter(struct ieee80211_hw *hw,
+			unsigned int changed_flags,
+			unsigned int *new_flags,
+			int mc_count, struct dev_mc_list *mclist)
+{
+	struct lbtf_private *priv = hw->priv;
+	int old_mac_control = priv->mac_control;
+	int i;
+	changed_flags &= SUPPORTED_FIF_FLAGS;
+	*new_flags &= SUPPORTED_FIF_FLAGS;
+
+	if (!changed_flags)
+		return;
+
+	if (*new_flags & (FIF_PROMISC_IN_BSS))
+		priv->mac_control |= CMD_ACT_MAC_PROMISCUOUS_ENABLE;
+	else
+		priv->mac_control &= ~CMD_ACT_MAC_PROMISCUOUS_ENABLE;
+	if (*new_flags & (FIF_ALLMULTI) ||
+	    mc_count > MRVDRV_MAX_MULTICAST_LIST_SIZE) {
+		priv->mac_control |= CMD_ACT_MAC_ALL_MULTICAST_ENABLE;
+		priv->mac_control &= ~CMD_ACT_MAC_MULTICAST_ENABLE;
+	} else if (mc_count) {
+		priv->mac_control |= CMD_ACT_MAC_MULTICAST_ENABLE;
+		priv->mac_control &= ~CMD_ACT_MAC_ALL_MULTICAST_ENABLE;
+		priv->nr_of_multicastmacaddr = mc_count;
+		for (i = 0; i < mc_count; i++) {
+			if (!mclist)
+				break;
+			memcpy(&priv->multicastlist[i], mclist->da_addr,
+					ETH_ALEN);
+			mclist = mclist->next;
+		}
+		lbtf_cmd_set_mac_multicast_addr(priv);
+	} else {
+		priv->mac_control &= ~(CMD_ACT_MAC_MULTICAST_ENABLE |
+				       CMD_ACT_MAC_ALL_MULTICAST_ENABLE);
+		if (priv->nr_of_multicastmacaddr) {
+			priv->nr_of_multicastmacaddr = 0;
+			lbtf_cmd_set_mac_multicast_addr(priv);
+		}
+	}
+
+
+	if (priv->mac_control != old_mac_control)
+		lbtf_set_mac_control(priv);
+}
+
+static void lbtf_op_bss_info_changed(struct ieee80211_hw *hw,
+			struct ieee80211_vif *vif,
+			struct ieee80211_bss_conf *bss_conf,
+			u32 changes)
+{
+	struct lbtf_private *priv = hw->priv;
+
+	if (changes & BSS_CHANGED_ERP_PREAMBLE) {
+		if (bss_conf->use_short_preamble)
+			priv->preamble = CMD_TYPE_SHORT_PREAMBLE;
+		else
+			priv->preamble = CMD_TYPE_LONG_PREAMBLE;
+		lbtf_set_radio_control(priv);
+	}
+
+	return;
+}
+
+static const struct ieee80211_ops lbtf_ops = {
+	.tx			= lbtf_op_tx,
+	.start			= lbtf_op_start,
+	.stop			= lbtf_op_stop,
+	.add_interface		= lbtf_op_add_interface,
+	.remove_interface	= lbtf_op_remove_interface,
+	.config			= lbtf_op_config,
+	.config_interface	= lbtf_op_config_interface,
+	.configure_filter	= lbtf_op_configure_filter,
+	.bss_info_changed	= lbtf_op_bss_info_changed,
+};
+
+int lbtf_rx(struct lbtf_private *priv, struct sk_buff *skb)
+{
+	struct ieee80211_rx_status stats;
+	struct rxpd *prxpd;
+	int need_padding;
+	unsigned int flags;
+	struct ieee80211_hdr *hdr;
+
+	prxpd = (struct rxpd *) skb->data;
+
+	stats.flag = 0;
+	if (!(prxpd->status & cpu_to_le16(MRVDRV_RXPD_STATUS_OK)))
+		stats.flag |= RX_FLAG_FAILED_FCS_CRC;
+	stats.freq = priv->cur_freq;
+	stats.band = IEEE80211_BAND_2GHZ;
+	stats.signal = prxpd->snr;
+	stats.noise = prxpd->nf;
+	stats.qual = prxpd->snr - prxpd->nf;
+	/* Marvell rate index has a hole at value 4 */
+	if (prxpd->rx_rate > 4)
+		--prxpd->rx_rate;
+	stats.rate_idx = prxpd->rx_rate;
+	skb_pull(skb, sizeof(struct rxpd));
+
+	hdr = (struct ieee80211_hdr *)skb->data;
+	flags = le32_to_cpu(*(__le32 *)(skb->data + 4));
+
+	need_padding = ieee80211_is_data_qos(hdr->frame_control);
+	need_padding ^= ieee80211_has_a4(hdr->frame_control);
+	need_padding ^= ieee80211_is_data_qos(hdr->frame_control) &&
+			(*ieee80211_get_qos_ctl(hdr) &
+			 IEEE80211_QOS_CONTROL_A_MSDU_PRESENT);
+
+	if (need_padding) {
+		memmove(skb->data + 2, skb->data, skb->len);
+		skb_reserve(skb, 2);
+	}
+
+	ieee80211_rx_irqsafe(priv->hw, skb, &stats);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(lbtf_rx);
+
+/**
+ * lbtf_add_card: Add and initialize the card, no fw upload yet.
+ *
+ *  @card    A pointer to card
+ *
+ *  Returns: pointer to struct lbtf_priv.
+ */
+struct lbtf_private *lbtf_add_card(void *card, struct device *dmdev)
+{
+	struct ieee80211_hw *hw;
+	struct lbtf_private *priv = NULL;
+
+	hw = ieee80211_alloc_hw(sizeof(struct lbtf_private), &lbtf_ops);
+	if (!hw)
+		goto done;
+
+	priv = hw->priv;
+	if (lbtf_init_adapter(priv))
+		goto err_init_adapter;
+
+	priv->hw = hw;
+	priv->card = card;
+	priv->tx_skb = NULL;
+
+	hw->queues = 1;
+	hw->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING;
+	hw->extra_tx_headroom = sizeof(struct txpd);
+	memcpy(priv->channels, lbtf_channels, sizeof(lbtf_channels));
+	memcpy(priv->rates, lbtf_rates, sizeof(lbtf_rates));
+	priv->band.n_bitrates = ARRAY_SIZE(lbtf_rates);
+	priv->band.bitrates = priv->rates;
+	priv->band.n_channels = ARRAY_SIZE(lbtf_channels);
+	priv->band.channels = priv->channels;
+	hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &priv->band;
+	skb_queue_head_init(&priv->bc_ps_buf);
+
+	SET_IEEE80211_DEV(hw, dmdev);
+
+	INIT_WORK(&priv->cmd_work, lbtf_cmd_work);
+	INIT_WORK(&priv->tx_work, lbtf_tx_work);
+	if (ieee80211_register_hw(hw))
+		goto err_init_adapter;
+
+	goto done;
+
+err_init_adapter:
+	lbtf_free_adapter(priv);
+	ieee80211_free_hw(hw);
+	priv = NULL;
+
+done:
+	return priv;
+}
+EXPORT_SYMBOL_GPL(lbtf_add_card);
+
+
+int lbtf_remove_card(struct lbtf_private *priv)
+{
+	struct ieee80211_hw *hw = priv->hw;
+
+	priv->surpriseremoved = 1;
+	del_timer(&priv->command_timer);
+	lbtf_free_adapter(priv);
+	priv->hw = NULL;
+	ieee80211_unregister_hw(hw);
+	ieee80211_free_hw(hw);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(lbtf_remove_card);
+
+void lbtf_send_tx_feedback(struct lbtf_private *priv, u8 retrycnt, u8 fail)
+{
+	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(priv->tx_skb);
+	memset(&info->status, 0, sizeof(info->status));
+	/*
+	 * Commented out, otherwise we never go beyond 1Mbit/s using mac80211
+	 * default pid rc algorithm.
+	 *
+	 * info->status.retry_count = MRVL_DEFAULT_RETRIES - retrycnt;
+	 */
+	info->status.excessive_retries = fail ? 1 : 0;
+	if (!(info->flags & IEEE80211_TX_CTL_NO_ACK) && !fail)
+		info->flags |= IEEE80211_TX_STAT_ACK;
+	skb_pull(priv->tx_skb, sizeof(struct txpd));
+	ieee80211_tx_status_irqsafe(priv->hw, priv->tx_skb);
+	priv->tx_skb = NULL;
+	if (!priv->skb_to_tx && skb_queue_empty(&priv->bc_ps_buf))
+		ieee80211_wake_queues(priv->hw);
+	else
+		queue_work(lbtf_wq, &priv->tx_work);
+}
+EXPORT_SYMBOL_GPL(lbtf_send_tx_feedback);
+
+void lbtf_bcn_sent(struct lbtf_private *priv)
+{
+	struct sk_buff *skb = NULL;
+
+	if (priv->vif->type != NL80211_IFTYPE_AP)
+		return;
+
+	if (skb_queue_empty(&priv->bc_ps_buf)) {
+		bool tx_buff_bc = 0;
+
+		while ((skb = ieee80211_get_buffered_bc(priv->hw, priv->vif))) {
+			skb_queue_tail(&priv->bc_ps_buf, skb);
+			tx_buff_bc = 1;
+		}
+		if (tx_buff_bc) {
+			ieee80211_stop_queues(priv->hw);
+			queue_work(lbtf_wq, &priv->tx_work);
+		}
+	}
+
+	skb = ieee80211_beacon_get(priv->hw, priv->vif);
+
+	if (skb) {
+		lbtf_beacon_set(priv, skb);
+		kfree_skb(skb);
+	}
+}
+EXPORT_SYMBOL_GPL(lbtf_bcn_sent);
+
+static int __init lbtf_init_module(void)
+{
+	lbtf_wq = create_workqueue("libertastf");
+	if (lbtf_wq == NULL) {
+		printk(KERN_ERR "libertastf: couldn't create workqueue\n");
+		return -ENOMEM;
+	}
+	return 0;
+}
+
+static void __exit lbtf_exit_module(void)
+{
+	destroy_workqueue(lbtf_wq);
+}
+
+module_init(lbtf_init_module);
+module_exit(lbtf_exit_module);
+
+MODULE_DESCRIPTION("Libertas WLAN Thinfirm Driver Library");
+MODULE_AUTHOR("Cozybit Inc.");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c
index 248d31a..c9e4a43 100644
--- a/drivers/net/wireless/mac80211_hwsim.c
+++ b/drivers/net/wireless/mac80211_hwsim.c
@@ -14,6 +14,8 @@
  * - RX filtering based on filter configuration (data->rx_filter)
  */
 
+#include <linux/list.h>
+#include <linux/spinlock.h>
 #include <net/mac80211.h>
 #include <net/ieee80211_radiotap.h>
 #include <linux/if_arp.h>
@@ -28,11 +30,56 @@
 module_param(radios, int, 0444);
 MODULE_PARM_DESC(radios, "Number of simulated radios");
 
+struct hwsim_vif_priv {
+	u32 magic;
+};
+
+#define HWSIM_VIF_MAGIC	0x69537748
+
+static inline void hwsim_check_magic(struct ieee80211_vif *vif)
+{
+	struct hwsim_vif_priv *vp = (void *)vif->drv_priv;
+	WARN_ON(vp->magic != HWSIM_VIF_MAGIC);
+}
+
+static inline void hwsim_set_magic(struct ieee80211_vif *vif)
+{
+	struct hwsim_vif_priv *vp = (void *)vif->drv_priv;
+	vp->magic = HWSIM_VIF_MAGIC;
+}
+
+static inline void hwsim_clear_magic(struct ieee80211_vif *vif)
+{
+	struct hwsim_vif_priv *vp = (void *)vif->drv_priv;
+	vp->magic = 0;
+}
+
+struct hwsim_sta_priv {
+	u32 magic;
+};
+
+#define HWSIM_STA_MAGIC	0x6d537748
+
+static inline void hwsim_check_sta_magic(struct ieee80211_sta *sta)
+{
+	struct hwsim_sta_priv *sp = (void *)sta->drv_priv;
+	WARN_ON(sp->magic != HWSIM_VIF_MAGIC);
+}
+
+static inline void hwsim_set_sta_magic(struct ieee80211_sta *sta)
+{
+	struct hwsim_sta_priv *sp = (void *)sta->drv_priv;
+	sp->magic = HWSIM_VIF_MAGIC;
+}
+
+static inline void hwsim_clear_sta_magic(struct ieee80211_sta *sta)
+{
+	struct hwsim_sta_priv *sp = (void *)sta->drv_priv;
+	sp->magic = 0;
+}
 
 static struct class *hwsim_class;
 
-static struct ieee80211_hw **hwsim_radios;
-static int hwsim_radio_count;
 static struct net_device *hwsim_mon; /* global monitor netdev */
 
 
@@ -68,7 +115,12 @@
 	{ .bitrate = 540 }
 };
 
+static spinlock_t hwsim_radio_lock;
+static struct list_head hwsim_radios;
+
 struct mac80211_hwsim_data {
+	struct list_head list;
+	struct ieee80211_hw *hw;
 	struct device *dev;
 	struct ieee80211_supported_band band;
 	struct ieee80211_channel channels[ARRAY_SIZE(hwsim_channels)];
@@ -144,11 +196,11 @@
 }
 
 
-static int mac80211_hwsim_tx_frame(struct ieee80211_hw *hw,
-				   struct sk_buff *skb)
+static bool mac80211_hwsim_tx_frame(struct ieee80211_hw *hw,
+				    struct sk_buff *skb)
 {
-	struct mac80211_hwsim_data *data = hw->priv;
-	int i, ack = 0;
+	struct mac80211_hwsim_data *data = hw->priv, *data2;
+	bool ack = false;
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
 	struct ieee80211_rx_status rx_status;
@@ -161,13 +213,13 @@
 	/* TODO: simulate signal strength (and optional packet drop) */
 
 	/* Copy skb to all enabled radios that are on the current frequency */
-	for (i = 0; i < hwsim_radio_count; i++) {
-		struct mac80211_hwsim_data *data2;
+	spin_lock(&hwsim_radio_lock);
+	list_for_each_entry(data2, &hwsim_radios, list) {
 		struct sk_buff *nskb;
 
-		if (hwsim_radios[i] == NULL || hwsim_radios[i] == hw)
+		if (data == data2)
 			continue;
-		data2 = hwsim_radios[i]->priv;
+
 		if (!data2->started || !data2->radio_enabled ||
 		    data->channel->center_freq != data2->channel->center_freq)
 			continue;
@@ -176,11 +228,12 @@
 		if (nskb == NULL)
 			continue;
 
-		if (memcmp(hdr->addr1, hwsim_radios[i]->wiphy->perm_addr,
+		if (memcmp(hdr->addr1, data2->hw->wiphy->perm_addr,
 			   ETH_ALEN) == 0)
-			ack = 1;
-		ieee80211_rx_irqsafe(hwsim_radios[i], nskb, &rx_status);
+			ack = true;
+		ieee80211_rx_irqsafe(data2->hw, nskb, &rx_status);
 	}
+	spin_unlock(&hwsim_radio_lock);
 
 	return ack;
 }
@@ -189,7 +242,7 @@
 static int mac80211_hwsim_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
 {
 	struct mac80211_hwsim_data *data = hw->priv;
-	int ack;
+	bool ack;
 	struct ieee80211_tx_info *txi;
 
 	mac80211_hwsim_monitor_rx(hw, skb);
@@ -210,6 +263,12 @@
 	ack = mac80211_hwsim_tx_frame(hw, skb);
 
 	txi = IEEE80211_SKB_CB(skb);
+
+	if (txi->control.vif)
+		hwsim_check_magic(txi->control.vif);
+	if (txi->control.sta)
+		hwsim_check_sta_magic(txi->control.sta);
+
 	memset(&txi->status, 0, sizeof(txi->status));
 	if (!(txi->flags & IEEE80211_TX_CTL_NO_ACK)) {
 		if (ack)
@@ -246,6 +305,7 @@
 	printk(KERN_DEBUG "%s:%s (type=%d mac_addr=%s)\n",
 	       wiphy_name(hw->wiphy), __func__, conf->type,
 	       print_mac(mac, conf->mac_addr));
+	hwsim_set_magic(conf->vif);
 	return 0;
 }
 
@@ -257,6 +317,8 @@
 	printk(KERN_DEBUG "%s:%s (type=%d mac_addr=%s)\n",
 	       wiphy_name(hw->wiphy), __func__, conf->type,
 	       print_mac(mac, conf->mac_addr));
+	hwsim_check_magic(conf->vif);
+	hwsim_clear_magic(conf->vif);
 }
 
 
@@ -267,7 +329,9 @@
 	struct sk_buff *skb;
 	struct ieee80211_tx_info *info;
 
-	if (vif->type != IEEE80211_IF_TYPE_AP)
+	hwsim_check_magic(vif);
+
+	if (vif->type != NL80211_IFTYPE_AP)
 		return;
 
 	skb = ieee80211_beacon_get(hw, vif);
@@ -341,7 +405,45 @@
 	*total_flags = data->rx_filter;
 }
 
+static int mac80211_hwsim_config_interface(struct ieee80211_hw *hw,
+					   struct ieee80211_vif *vif,
+					   struct ieee80211_if_conf *conf)
+{
+	hwsim_check_magic(vif);
+	return 0;
+}
 
+static void mac80211_hwsim_bss_info_changed(struct ieee80211_hw *hw,
+					    struct ieee80211_vif *vif,
+					    struct ieee80211_bss_conf *info,
+					    u32 changed)
+{
+	hwsim_check_magic(vif);
+}
+
+static void mac80211_hwsim_sta_notify(struct ieee80211_hw *hw,
+				      struct ieee80211_vif *vif,
+				      enum sta_notify_cmd cmd,
+				      struct ieee80211_sta *sta)
+{
+	hwsim_check_magic(vif);
+	switch (cmd) {
+	case STA_NOTIFY_ADD:
+		hwsim_set_sta_magic(sta);
+		break;
+	case STA_NOTIFY_REMOVE:
+		hwsim_clear_sta_magic(sta);
+		break;
+	}
+}
+
+static int mac80211_hwsim_set_tim(struct ieee80211_hw *hw,
+				  struct ieee80211_sta *sta,
+				  bool set)
+{
+	hwsim_check_sta_magic(sta);
+	return 0;
+}
 
 static const struct ieee80211_ops mac80211_hwsim_ops =
 {
@@ -352,23 +454,30 @@
 	.remove_interface = mac80211_hwsim_remove_interface,
 	.config = mac80211_hwsim_config,
 	.configure_filter = mac80211_hwsim_configure_filter,
+	.config_interface = mac80211_hwsim_config_interface,
+	.bss_info_changed = mac80211_hwsim_bss_info_changed,
+	.sta_notify = mac80211_hwsim_sta_notify,
+	.set_tim = mac80211_hwsim_set_tim,
 };
 
 
 static void mac80211_hwsim_free(void)
 {
-	int i;
+	struct list_head tmplist, *i, *tmp;
+	struct mac80211_hwsim_data *data;
 
-	for (i = 0; i < hwsim_radio_count; i++) {
-		if (hwsim_radios[i]) {
-			struct mac80211_hwsim_data *data;
-			data = hwsim_radios[i]->priv;
-			ieee80211_unregister_hw(hwsim_radios[i]);
-			device_unregister(data->dev);
-			ieee80211_free_hw(hwsim_radios[i]);
-		}
+	INIT_LIST_HEAD(&tmplist);
+
+	spin_lock_bh(&hwsim_radio_lock);
+	list_for_each_safe(i, tmp, &hwsim_radios)
+		list_move(i, &tmplist);
+	spin_unlock_bh(&hwsim_radio_lock);
+
+	list_for_each_entry(data, &tmplist, list) {
+		ieee80211_unregister_hw(data->hw);
+		device_unregister(data->dev);
+		ieee80211_free_hw(data->hw);
 	}
-	kfree(hwsim_radios);
 	class_destroy(hwsim_class);
 }
 
@@ -398,37 +507,32 @@
 	struct ieee80211_hw *hw;
 	DECLARE_MAC_BUF(mac);
 
-	if (radios < 1 || radios > 65535)
+	if (radios < 1 || radios > 100)
 		return -EINVAL;
 
-	hwsim_radio_count = radios;
-	hwsim_radios = kcalloc(hwsim_radio_count,
-			       sizeof(struct ieee80211_hw *), GFP_KERNEL);
-	if (hwsim_radios == NULL)
-		return -ENOMEM;
+	spin_lock_init(&hwsim_radio_lock);
+	INIT_LIST_HEAD(&hwsim_radios);
 
 	hwsim_class = class_create(THIS_MODULE, "mac80211_hwsim");
-	if (IS_ERR(hwsim_class)) {
-		kfree(hwsim_radios);
+	if (IS_ERR(hwsim_class))
 		return PTR_ERR(hwsim_class);
-	}
 
 	memset(addr, 0, ETH_ALEN);
 	addr[0] = 0x02;
 
-	for (i = 0; i < hwsim_radio_count; i++) {
+	for (i = 0; i < radios; i++) {
 		printk(KERN_DEBUG "mac80211_hwsim: Initializing radio %d\n",
 		       i);
 		hw = ieee80211_alloc_hw(sizeof(*data), &mac80211_hwsim_ops);
-		if (hw == NULL) {
+		if (!hw) {
 			printk(KERN_DEBUG "mac80211_hwsim: ieee80211_alloc_hw "
 			       "failed\n");
 			err = -ENOMEM;
 			goto failed;
 		}
-		hwsim_radios[i] = hw;
-
 		data = hw->priv;
+		data->hw = hw;
+
 		data->dev = device_create_drvdata(hwsim_class, NULL, 0, hw,
 						"hwsim%d", i);
 		if (IS_ERR(data->dev)) {
@@ -446,7 +550,15 @@
 		SET_IEEE80211_PERM_ADDR(hw, addr);
 
 		hw->channel_change_time = 1;
-		hw->queues = 1;
+		hw->queues = 4;
+		hw->wiphy->interface_modes =
+			BIT(NL80211_IFTYPE_STATION) |
+			BIT(NL80211_IFTYPE_AP);
+		hw->ampdu_queues = 1;
+
+		/* ask mac80211 to reserve space for magic */
+		hw->vif_data_size = sizeof(struct hwsim_vif_priv);
+		hw->sta_data_size = sizeof(struct hwsim_sta_priv);
 
 		memcpy(data->channels, hwsim_channels, sizeof(hwsim_channels));
 		memcpy(data->rates, hwsim_rates, sizeof(hwsim_rates));
@@ -454,6 +566,19 @@
 		data->band.n_channels = ARRAY_SIZE(hwsim_channels);
 		data->band.bitrates = data->rates;
 		data->band.n_bitrates = ARRAY_SIZE(hwsim_rates);
+		data->band.ht_info.ht_supported = 1;
+		data->band.ht_info.cap = IEEE80211_HT_CAP_SUP_WIDTH |
+			IEEE80211_HT_CAP_GRN_FLD |
+			IEEE80211_HT_CAP_SGI_40 |
+			IEEE80211_HT_CAP_DSSSCCK40;
+		data->band.ht_info.ampdu_factor = 0x3;
+		data->band.ht_info.ampdu_density = 0x6;
+		memset(data->band.ht_info.supp_mcs_set, 0,
+		       sizeof(data->band.ht_info.supp_mcs_set));
+		data->band.ht_info.supp_mcs_set[0] = 0xff;
+		data->band.ht_info.supp_mcs_set[1] = 0xff;
+		data->band.ht_info.supp_mcs_set[12] =
+			IEEE80211_HT_CAP_MCS_TX_DEFINED;
 		hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &data->band;
 
 		err = ieee80211_register_hw(hw);
@@ -469,6 +594,8 @@
 
 		setup_timer(&data->beacon_timer, mac80211_hwsim_beacon,
 			    (unsigned long) hw);
+
+		list_add_tail(&data->list, &hwsim_radios);
 	}
 
 	hwsim_mon = alloc_netdev(0, "hwsim%d", hwsim_mon_setup);
@@ -500,7 +627,6 @@
 	device_unregister(data->dev);
 failed_drvdata:
 	ieee80211_free_hw(hw);
-	hwsim_radios[i] = NULL;
 failed:
 	mac80211_hwsim_free();
 	return err;
@@ -509,8 +635,7 @@
 
 static void __exit exit_mac80211_hwsim(void)
 {
-	printk(KERN_DEBUG "mac80211_hwsim: unregister %d radios\n",
-	       hwsim_radio_count);
+	printk(KERN_DEBUG "mac80211_hwsim: unregister radios\n");
 
 	unregister_netdev(hwsim_mon);
 	mac80211_hwsim_free();
diff --git a/drivers/net/wireless/netwave_cs.c b/drivers/net/wireless/netwave_cs.c
index f479c1a..a670f36b 100644
--- a/drivers/net/wireless/netwave_cs.c
+++ b/drivers/net/wireless/netwave_cs.c
@@ -398,7 +398,7 @@
     link->io.IOAddrLines = 5;
     
     /* Interrupt setup */
-    link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT;
+    link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING | IRQ_HANDLE_PRESENT;
     link->irq.IRQInfo1 = IRQ_LEVEL_ID;
     link->irq.Handler = &netwave_interrupt;
     
@@ -749,9 +749,10 @@
     for (i = j = 0x0; j < 0x400; j += 0x20) {
 	link->io.BasePort1 = j ^ 0x300;
 	i = pcmcia_request_io(link, &link->io);
-	if (i == CS_SUCCESS) break;
+	if (i == 0)
+		break;
     }
-    if (i != CS_SUCCESS) {
+    if (i != 0) {
 	cs_error(link, RequestIO, i);
 	goto failed;
     }
diff --git a/drivers/net/wireless/orinoco.c b/drivers/net/wireless/orinoco.c
index 36c004e..5090477 100644
--- a/drivers/net/wireless/orinoco.c
+++ b/drivers/net/wireless/orinoco.c
@@ -79,15 +79,21 @@
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
+#include <linux/delay.h>
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/ethtool.h>
+#include <linux/firmware.h>
 #include <linux/if_arp.h>
 #include <linux/wireless.h>
 #include <net/iw_handler.h>
 #include <net/ieee80211.h>
 
+#include <linux/scatterlist.h>
+#include <linux/crypto.h>
+
 #include "hermes_rid.h"
+#include "hermes_dld.h"
 #include "orinoco.h"
 
 /********************************************************************/
@@ -241,6 +247,74 @@
 static void __orinoco_set_multicast_list(struct net_device *dev);
 
 /********************************************************************/
+/* Michael MIC crypto setup                                         */
+/********************************************************************/
+#define MICHAEL_MIC_LEN 8
+static int orinoco_mic_init(struct orinoco_private *priv)
+{
+	priv->tx_tfm_mic = crypto_alloc_hash("michael_mic", 0, 0);
+	if (IS_ERR(priv->tx_tfm_mic)) {
+		printk(KERN_DEBUG "orinoco_mic_init: could not allocate "
+		       "crypto API michael_mic\n");
+		priv->tx_tfm_mic = NULL;
+		return -ENOMEM;
+	}
+
+	priv->rx_tfm_mic = crypto_alloc_hash("michael_mic", 0, 0);
+	if (IS_ERR(priv->rx_tfm_mic)) {
+		printk(KERN_DEBUG "orinoco_mic_init: could not allocate "
+		       "crypto API michael_mic\n");
+		priv->rx_tfm_mic = NULL;
+		return -ENOMEM;
+	}
+
+	return 0;
+}
+
+static void orinoco_mic_free(struct orinoco_private *priv)
+{
+	if (priv->tx_tfm_mic)
+		crypto_free_hash(priv->tx_tfm_mic);
+	if (priv->rx_tfm_mic)
+		crypto_free_hash(priv->rx_tfm_mic);
+}
+
+static int michael_mic(struct crypto_hash *tfm_michael, u8 *key,
+		       u8 *da, u8 *sa, u8 priority,
+		       u8 *data, size_t data_len, u8 *mic)
+{
+	struct hash_desc desc;
+	struct scatterlist sg[2];
+	u8 hdr[ETH_HLEN + 2]; /* size of header + padding */
+
+	if (tfm_michael == NULL) {
+		printk(KERN_WARNING "michael_mic: tfm_michael == NULL\n");
+		return -1;
+	}
+
+	/* Copy header into buffer. We need the padding on the end zeroed */
+	memcpy(&hdr[0], da, ETH_ALEN);
+	memcpy(&hdr[ETH_ALEN], sa, ETH_ALEN);
+	hdr[ETH_ALEN*2] = priority;
+	hdr[ETH_ALEN*2+1] = 0;
+	hdr[ETH_ALEN*2+2] = 0;
+	hdr[ETH_ALEN*2+3] = 0;
+
+	/* Use scatter gather to MIC header and data in one go */
+	sg_init_table(sg, 2);
+	sg_set_buf(&sg[0], hdr, sizeof(hdr));
+	sg_set_buf(&sg[1], data, data_len);
+
+	if (crypto_hash_setkey(tfm_michael, key, MIC_KEYLEN))
+		return -1;
+
+	desc.tfm = tfm_michael;
+	desc.flags = 0;
+	return crypto_hash_digest(&desc, sg, data_len + sizeof(hdr),
+				  mic);
+}
+
+/********************************************************************/
 /* Internal helper functions                                        */
 /********************************************************************/
 
@@ -273,12 +347,19 @@
 #define ORINOCO_MAX_BSS_COUNT	64
 static int orinoco_bss_data_allocate(struct orinoco_private *priv)
 {
-	if (priv->bss_data)
+	if (priv->bss_xbss_data)
 		return 0;
 
-	priv->bss_data =
-	    kzalloc(ORINOCO_MAX_BSS_COUNT * sizeof(bss_element), GFP_KERNEL);
-	if (!priv->bss_data) {
+	if (priv->has_ext_scan)
+		priv->bss_xbss_data = kzalloc(ORINOCO_MAX_BSS_COUNT *
+					      sizeof(struct xbss_element),
+					      GFP_KERNEL);
+	else
+		priv->bss_xbss_data = kzalloc(ORINOCO_MAX_BSS_COUNT *
+					      sizeof(struct bss_element),
+					      GFP_KERNEL);
+
+	if (!priv->bss_xbss_data) {
 		printk(KERN_WARNING "Out of memory allocating beacons");
 		return -ENOMEM;
 	}
@@ -287,18 +368,319 @@
 
 static void orinoco_bss_data_free(struct orinoco_private *priv)
 {
-	kfree(priv->bss_data);
-	priv->bss_data = NULL;
+	kfree(priv->bss_xbss_data);
+	priv->bss_xbss_data = NULL;
 }
 
+#define PRIV_BSS	((struct bss_element *)priv->bss_xbss_data)
+#define PRIV_XBSS	((struct xbss_element *)priv->bss_xbss_data)
 static void orinoco_bss_data_init(struct orinoco_private *priv)
 {
 	int i;
 
 	INIT_LIST_HEAD(&priv->bss_free_list);
 	INIT_LIST_HEAD(&priv->bss_list);
-	for (i = 0; i < ORINOCO_MAX_BSS_COUNT; i++)
-		list_add_tail(&priv->bss_data[i].list, &priv->bss_free_list);
+	if (priv->has_ext_scan)
+		for (i = 0; i < ORINOCO_MAX_BSS_COUNT; i++)
+			list_add_tail(&(PRIV_XBSS[i].list),
+				      &priv->bss_free_list);
+	else
+		for (i = 0; i < ORINOCO_MAX_BSS_COUNT; i++)
+			list_add_tail(&(PRIV_BSS[i].list),
+				      &priv->bss_free_list);
+
+}
+
+static inline u8 *orinoco_get_ie(u8 *data, size_t len,
+				 enum ieee80211_mfie eid)
+{
+	u8 *p = data;
+	while ((p + 2) < (data + len)) {
+		if (p[0] == eid)
+			return p;
+		p += p[1] + 2;
+	}
+	return NULL;
+}
+
+#define WPA_OUI_TYPE	"\x00\x50\xF2\x01"
+#define WPA_SELECTOR_LEN 4
+static inline u8 *orinoco_get_wpa_ie(u8 *data, size_t len)
+{
+	u8 *p = data;
+	while ((p + 2 + WPA_SELECTOR_LEN) < (data + len)) {
+		if ((p[0] == MFIE_TYPE_GENERIC) &&
+		    (memcmp(&p[2], WPA_OUI_TYPE, WPA_SELECTOR_LEN) == 0))
+			return p;
+		p += p[1] + 2;
+	}
+	return NULL;
+}
+
+
+/********************************************************************/
+/* Download functionality                                           */
+/********************************************************************/
+
+struct fw_info {
+	char *pri_fw;
+	char *sta_fw;
+	char *ap_fw;
+	u32 pda_addr;
+	u16 pda_size;
+};
+
+const static struct fw_info orinoco_fw[] = {
+	{ "", "agere_sta_fw.bin", "agere_ap_fw.bin", 0x00390000, 1000 },
+	{ "", "prism_sta_fw.bin", "prism_ap_fw.bin", 0, 1024 },
+	{ "symbol_sp24t_prim_fw", "symbol_sp24t_sec_fw", "", 0x00003100, 0x100 }
+};
+
+/* Structure used to access fields in FW
+ * Make sure LE decoding macros are used
+ */
+struct orinoco_fw_header {
+	char hdr_vers[6];       /* ASCII string for header version */
+	__le16 headersize;      /* Total length of header */
+	__le32 entry_point;     /* NIC entry point */
+	__le32 blocks;          /* Number of blocks to program */
+	__le32 block_offset;    /* Offset of block data from eof header */
+	__le32 pdr_offset;      /* Offset to PDR data from eof header */
+	__le32 pri_offset;      /* Offset to primary plug data */
+	__le32 compat_offset;   /* Offset to compatibility data*/
+	char signature[0];      /* FW signature length headersize-20 */
+} __attribute__ ((packed));
+
+/* Download either STA or AP firmware into the card. */
+static int
+orinoco_dl_firmware(struct orinoco_private *priv,
+		    const struct fw_info *fw,
+		    int ap)
+{
+	/* Plug Data Area (PDA) */
+	__le16 pda[512] = { 0 };
+
+	hermes_t *hw = &priv->hw;
+	const struct firmware *fw_entry;
+	const struct orinoco_fw_header *hdr;
+	const unsigned char *first_block;
+	const unsigned char *end;
+	const char *firmware;
+	struct net_device *dev = priv->ndev;
+	int err;
+
+	if (ap)
+		firmware = fw->ap_fw;
+	else
+		firmware = fw->sta_fw;
+
+	printk(KERN_DEBUG "%s: Attempting to download firmware %s\n",
+	       dev->name, firmware);
+
+	/* Read current plug data */
+	err = hermes_read_pda(hw, pda, fw->pda_addr,
+			      min_t(u16, fw->pda_size, sizeof(pda)), 0);
+	printk(KERN_DEBUG "%s: Read PDA returned %d\n", dev->name, err);
+	if (err)
+		return err;
+
+	err = request_firmware(&fw_entry, firmware, priv->dev);
+	if (err) {
+		printk(KERN_ERR "%s: Cannot find firmware %s\n",
+		       dev->name, firmware);
+		return -ENOENT;
+	}
+
+	hdr = (const struct orinoco_fw_header *) fw_entry->data;
+
+	/* Enable aux port to allow programming */
+	err = hermesi_program_init(hw, le32_to_cpu(hdr->entry_point));
+	printk(KERN_DEBUG "%s: Program init returned %d\n", dev->name, err);
+	if (err != 0)
+		goto abort;
+
+	/* Program data */
+	first_block = (fw_entry->data +
+		       le16_to_cpu(hdr->headersize) +
+		       le32_to_cpu(hdr->block_offset));
+	end = fw_entry->data + fw_entry->size;
+
+	err = hermes_program(hw, first_block, end);
+	printk(KERN_DEBUG "%s: Program returned %d\n", dev->name, err);
+	if (err != 0)
+		goto abort;
+
+	/* Update production data */
+	first_block = (fw_entry->data +
+		       le16_to_cpu(hdr->headersize) +
+		       le32_to_cpu(hdr->pdr_offset));
+
+	err = hermes_apply_pda_with_defaults(hw, first_block, pda);
+	printk(KERN_DEBUG "%s: Apply PDA returned %d\n", dev->name, err);
+	if (err)
+		goto abort;
+
+	/* Tell card we've finished */
+	err = hermesi_program_end(hw);
+	printk(KERN_DEBUG "%s: Program end returned %d\n", dev->name, err);
+	if (err != 0)
+		goto abort;
+
+	/* Check if we're running */
+	printk(KERN_DEBUG "%s: hermes_present returned %d\n",
+	       dev->name, hermes_present(hw));
+
+abort:
+	release_firmware(fw_entry);
+	return err;
+}
+
+/* End markers */
+#define TEXT_END	0x1A		/* End of text header */
+
+/*
+ * Process a firmware image - stop the card, load the firmware, reset
+ * the card and make sure it responds.  For the secondary firmware take
+ * care of the PDA - read it and then write it on top of the firmware.
+ */
+static int
+symbol_dl_image(struct orinoco_private *priv, const struct fw_info *fw,
+		const unsigned char *image, const unsigned char *end,
+		int secondary)
+{
+	hermes_t *hw = &priv->hw;
+	int ret;
+	const unsigned char *ptr;
+	const unsigned char *first_block;
+
+	/* Plug Data Area (PDA) */
+	__le16 pda[256];
+
+	/* Binary block begins after the 0x1A marker */
+	ptr = image;
+	while (*ptr++ != TEXT_END);
+	first_block = ptr;
+
+	/* Read the PDA from EEPROM */
+	if (secondary) {
+		ret = hermes_read_pda(hw, pda, fw->pda_addr, sizeof(pda), 1);
+		if (ret)
+			return ret;
+	}
+
+	/* Stop the firmware, so that it can be safely rewritten */
+	if (priv->stop_fw) {
+		ret = priv->stop_fw(priv, 1);
+		if (ret)
+			return ret;
+	}
+
+	/* Program the adapter with new firmware */
+	ret = hermes_program(hw, first_block, end);
+	if (ret)
+		return ret;
+
+	/* Write the PDA to the adapter */
+	if (secondary) {
+		size_t len = hermes_blocks_length(first_block);
+		ptr = first_block + len;
+		ret = hermes_apply_pda(hw, ptr, pda);
+		if (ret)
+			return ret;
+	}
+
+	/* Run the firmware */
+	if (priv->stop_fw) {
+		ret = priv->stop_fw(priv, 0);
+		if (ret)
+			return ret;
+	}
+
+	/* Reset hermes chip and make sure it responds */
+	ret = hermes_init(hw);
+
+	/* hermes_reset() should return 0 with the secondary firmware */
+	if (secondary && ret != 0)
+		return -ENODEV;
+
+	/* And this should work with any firmware */
+	if (!hermes_present(hw))
+		return -ENODEV;
+
+	return 0;
+}
+
+
+/*
+ * Download the firmware into the card, this also does a PCMCIA soft
+ * reset on the card, to make sure it's in a sane state.
+ */
+static int
+symbol_dl_firmware(struct orinoco_private *priv,
+		   const struct fw_info *fw)
+{
+	struct net_device *dev = priv->ndev;
+	int ret;
+	const struct firmware *fw_entry;
+
+	if (request_firmware(&fw_entry, fw->pri_fw,
+			     priv->dev) != 0) {
+		printk(KERN_ERR "%s: Cannot find firmware: %s\n",
+		       dev->name, fw->pri_fw);
+		return -ENOENT;
+	}
+
+	/* Load primary firmware */
+	ret = symbol_dl_image(priv, fw, fw_entry->data,
+			      fw_entry->data + fw_entry->size, 0);
+	release_firmware(fw_entry);
+	if (ret) {
+		printk(KERN_ERR "%s: Primary firmware download failed\n",
+		       dev->name);
+		return ret;
+	}
+
+	if (request_firmware(&fw_entry, fw->sta_fw,
+			     priv->dev) != 0) {
+		printk(KERN_ERR "%s: Cannot find firmware: %s\n",
+		       dev->name, fw->sta_fw);
+		return -ENOENT;
+	}
+
+	/* Load secondary firmware */
+	ret = symbol_dl_image(priv, fw, fw_entry->data,
+			      fw_entry->data + fw_entry->size, 1);
+	release_firmware(fw_entry);
+	if (ret) {
+		printk(KERN_ERR "%s: Secondary firmware download failed\n",
+		       dev->name);
+	}
+
+	return ret;
+}
+
+static int orinoco_download(struct orinoco_private *priv)
+{
+	int err = 0;
+	/* Reload firmware */
+	switch (priv->firmware_type) {
+	case FIRMWARE_TYPE_AGERE:
+		/* case FIRMWARE_TYPE_INTERSIL: */
+		err = orinoco_dl_firmware(priv,
+					  &orinoco_fw[priv->firmware_type], 0);
+		break;
+
+	case FIRMWARE_TYPE_SYMBOL:
+		err = symbol_dl_firmware(priv,
+					 &orinoco_fw[priv->firmware_type]);
+		break;
+	case FIRMWARE_TYPE_INTERSIL:
+		break;
+	}
+	/* TODO: if we fail we probably need to reinitialise
+	 * the driver */
+
+	return err;
 }
 
 /********************************************************************/
@@ -453,8 +835,7 @@
 	int err = 0;
 	u16 txfid = priv->txfid;
 	struct ethhdr *eh;
-	int data_off;
-	struct hermes_tx_descriptor desc;
+	int tx_control;
 	unsigned long flags;
 
 	if (! netif_running(dev)) {
@@ -486,23 +867,54 @@
 	if (skb->len < ETH_HLEN)
 		goto drop;
 
-	eh = (struct ethhdr *)skb->data;
+	tx_control = HERMES_TXCTRL_TX_OK | HERMES_TXCTRL_TX_EX;
 
-	memset(&desc, 0, sizeof(desc));
- 	desc.tx_control = cpu_to_le16(HERMES_TXCTRL_TX_OK | HERMES_TXCTRL_TX_EX);
-	err = hermes_bap_pwrite(hw, USER_BAP, &desc, sizeof(desc), txfid, 0);
-	if (err) {
-		if (net_ratelimit())
-			printk(KERN_ERR "%s: Error %d writing Tx descriptor "
-			       "to BAP\n", dev->name, err);
-		goto busy;
+	if (priv->encode_alg == IW_ENCODE_ALG_TKIP)
+		tx_control |= (priv->tx_key << HERMES_MIC_KEY_ID_SHIFT) |
+			HERMES_TXCTRL_MIC;
+
+	if (priv->has_alt_txcntl) {
+		/* WPA enabled firmwares have tx_cntl at the end of
+		 * the 802.11 header.  So write zeroed descriptor and
+		 * 802.11 header at the same time
+		 */
+		char desc[HERMES_802_3_OFFSET];
+		__le16 *txcntl = (__le16 *) &desc[HERMES_TXCNTL2_OFFSET];
+
+		memset(&desc, 0, sizeof(desc));
+
+		*txcntl = cpu_to_le16(tx_control);
+		err = hermes_bap_pwrite(hw, USER_BAP, &desc, sizeof(desc),
+					txfid, 0);
+		if (err) {
+			if (net_ratelimit())
+				printk(KERN_ERR "%s: Error %d writing Tx "
+				       "descriptor to BAP\n", dev->name, err);
+			goto busy;
+		}
+	} else {
+		struct hermes_tx_descriptor desc;
+
+		memset(&desc, 0, sizeof(desc));
+
+		desc.tx_control = cpu_to_le16(tx_control);
+		err = hermes_bap_pwrite(hw, USER_BAP, &desc, sizeof(desc),
+					txfid, 0);
+		if (err) {
+			if (net_ratelimit())
+				printk(KERN_ERR "%s: Error %d writing Tx "
+				       "descriptor to BAP\n", dev->name, err);
+			goto busy;
+		}
+
+		/* Clear the 802.11 header and data length fields - some
+		 * firmwares (e.g. Lucent/Agere 8.xx) appear to get confused
+		 * if this isn't done. */
+		hermes_clear_words(hw, HERMES_DATA0,
+				   HERMES_802_3_OFFSET - HERMES_802_11_OFFSET);
 	}
 
-	/* Clear the 802.11 header and data length fields - some
-	 * firmwares (e.g. Lucent/Agere 8.xx) appear to get confused
-	 * if this isn't done. */
-	hermes_clear_words(hw, HERMES_DATA0,
-			   HERMES_802_3_OFFSET - HERMES_802_11_OFFSET);
+	eh = (struct ethhdr *)skb->data;
 
 	/* Encapsulate Ethernet-II frames */
 	if (ntohs(eh->h_proto) > ETH_DATA_LEN) { /* Ethernet-II frame */
@@ -513,33 +925,65 @@
 
 		/* Strip destination and source from the data */
 		skb_pull(skb, 2 * ETH_ALEN);
-		data_off = HERMES_802_2_OFFSET + sizeof(encaps_hdr);
 
 		/* And move them to a separate header */
 		memcpy(&hdr.eth, eh, 2 * ETH_ALEN);
 		hdr.eth.h_proto = htons(sizeof(encaps_hdr) + skb->len);
 		memcpy(hdr.encap, encaps_hdr, sizeof(encaps_hdr));
 
-		err = hermes_bap_pwrite(hw, USER_BAP, &hdr, sizeof(hdr),
-					txfid, HERMES_802_3_OFFSET);
-		if (err) {
-			if (net_ratelimit())
-				printk(KERN_ERR "%s: Error %d writing packet "
-				       "header to BAP\n", dev->name, err);
-			goto busy;
+		/* Insert the SNAP header */
+		if (skb_headroom(skb) < sizeof(hdr)) {
+			printk(KERN_ERR
+			       "%s: Not enough headroom for 802.2 headers %d\n",
+			       dev->name, skb_headroom(skb));
+			goto drop;
 		}
-	} else { /* IEEE 802.3 frame */
-		data_off = HERMES_802_3_OFFSET;
+		eh = (struct ethhdr *) skb_push(skb, sizeof(hdr));
+		memcpy(eh, &hdr, sizeof(hdr));
 	}
 
 	err = hermes_bap_pwrite(hw, USER_BAP, skb->data, skb->len,
-				txfid, data_off);
+				txfid, HERMES_802_3_OFFSET);
 	if (err) {
 		printk(KERN_ERR "%s: Error %d writing packet to BAP\n",
 		       dev->name, err);
 		goto busy;
 	}
 
+	/* Calculate Michael MIC */
+	if (priv->encode_alg == IW_ENCODE_ALG_TKIP) {
+		u8 mic_buf[MICHAEL_MIC_LEN + 1];
+		u8 *mic;
+		size_t offset;
+		size_t len;
+
+		if (skb->len % 2) {
+			/* MIC start is on an odd boundary */
+			mic_buf[0] = skb->data[skb->len - 1];
+			mic = &mic_buf[1];
+			offset = skb->len - 1;
+			len = MICHAEL_MIC_LEN + 1;
+		} else {
+			mic = &mic_buf[0];
+			offset = skb->len;
+			len = MICHAEL_MIC_LEN;
+		}
+
+		michael_mic(priv->tx_tfm_mic,
+			    priv->tkip_key[priv->tx_key].tx_mic,
+			    eh->h_dest, eh->h_source, 0 /* priority */,
+			    skb->data + ETH_HLEN, skb->len - ETH_HLEN, mic);
+
+		/* Write the MIC */
+		err = hermes_bap_pwrite(hw, USER_BAP, &mic_buf[0], len,
+					txfid, HERMES_802_3_OFFSET + offset);
+		if (err) {
+			printk(KERN_ERR "%s: Error %d writing MIC to BAP\n",
+			       dev->name, err);
+			goto busy;
+		}
+	}
+
 	/* Finally, we actually initiate the send */
 	netif_stop_queue(dev);
 
@@ -554,7 +998,7 @@
 	}
 
 	dev->trans_start = jiffies;
-	stats->tx_bytes += data_off + skb->len;
+	stats->tx_bytes += HERMES_802_3_OFFSET + skb->len;
 	goto ok;
 
  drop:
@@ -834,21 +1278,48 @@
 	stats->rx_dropped++;
 }
 
+/* Get tsc from the firmware */
+static int orinoco_hw_get_tkip_iv(struct orinoco_private *priv, int key,
+				  u8 *tsc)
+{
+	hermes_t *hw = &priv->hw;
+	int err = 0;
+	u8 tsc_arr[4][IW_ENCODE_SEQ_MAX_SIZE];
+
+	if ((key < 0) || (key > 4))
+		return -EINVAL;
+
+	err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENT_TKIP_IV,
+			      sizeof(tsc_arr), NULL, &tsc_arr);
+	if (!err)
+		memcpy(tsc, &tsc_arr[key][0], sizeof(tsc_arr[0]));
+
+	return err;
+}
+
 static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw)
 {
 	struct orinoco_private *priv = netdev_priv(dev);
 	struct net_device_stats *stats = &priv->stats;
 	struct iw_statistics *wstats = &priv->wstats;
 	struct sk_buff *skb = NULL;
-	u16 rxfid, status, fc;
+	u16 rxfid, status;
 	int length;
-	struct hermes_rx_descriptor desc;
-	struct ethhdr *hdr;
+	struct hermes_rx_descriptor *desc;
+	struct orinoco_rx_data *rx_data;
 	int err;
 
+	desc = kmalloc(sizeof(*desc), GFP_ATOMIC);
+	if (!desc) {
+		printk(KERN_WARNING
+		       "%s: Can't allocate space for RX descriptor\n",
+		       dev->name);
+		goto update_stats;
+	}
+
 	rxfid = hermes_read_regn(hw, RXFID);
 
-	err = hermes_bap_pread(hw, IRQ_BAP, &desc, sizeof(desc),
+	err = hermes_bap_pread(hw, IRQ_BAP, desc, sizeof(*desc),
 			       rxfid, 0);
 	if (err) {
 		printk(KERN_ERR "%s: error %d reading Rx descriptor. "
@@ -856,7 +1327,7 @@
 		goto update_stats;
 	}
 
-	status = le16_to_cpu(desc.status);
+	status = le16_to_cpu(desc->status);
 
 	if (status & HERMES_RXSTAT_BADCRC) {
 		DEBUG(1, "%s: Bad CRC on Rx. Frame dropped.\n",
@@ -867,8 +1338,8 @@
 
 	/* Handle frames in monitor mode */
 	if (priv->iw_mode == IW_MODE_MONITOR) {
-		orinoco_rx_monitor(dev, rxfid, &desc);
-		return;
+		orinoco_rx_monitor(dev, rxfid, desc);
+		goto out;
 	}
 
 	if (status & HERMES_RXSTAT_UNDECRYPTABLE) {
@@ -878,15 +1349,14 @@
 		goto update_stats;
 	}
 
-	length = le16_to_cpu(desc.data_len);
-	fc = le16_to_cpu(desc.frame_ctl);
+	length = le16_to_cpu(desc->data_len);
 
 	/* Sanity checks */
 	if (length < 3) { /* No for even an 802.2 LLC header */
 		/* At least on Symbol firmware with PCF we get quite a
                    lot of these legitimately - Poll frames with no
                    data. */
-		return;
+		goto out;
 	}
 	if (length > IEEE80211_DATA_LEN) {
 		printk(KERN_WARNING "%s: Oversized frame received (%d bytes)\n",
@@ -895,6 +1365,11 @@
 		goto update_stats;
 	}
 
+	/* Payload size does not include Michael MIC. Increase payload
+	 * size to read it together with the data. */
+	if (status & HERMES_RXSTAT_MIC)
+		length += MICHAEL_MIC_LEN;
+
 	/* We need space for the packet data itself, plus an ethernet
 	   header, plus 2 bytes so we can align the IP header on a
 	   32bit boundary, plus 1 byte so we can read in odd length
@@ -921,6 +1396,100 @@
 		goto drop;
 	}
 
+	/* Add desc and skb to rx queue */
+	rx_data = kzalloc(sizeof(*rx_data), GFP_ATOMIC);
+	if (!rx_data) {
+		printk(KERN_WARNING "%s: Can't allocate RX packet\n",
+			dev->name);
+		goto drop;
+	}
+	rx_data->desc = desc;
+	rx_data->skb = skb;
+	list_add_tail(&rx_data->list, &priv->rx_list);
+	tasklet_schedule(&priv->rx_tasklet);
+
+	return;
+
+drop:
+	dev_kfree_skb_irq(skb);
+update_stats:
+	stats->rx_errors++;
+	stats->rx_dropped++;
+out:
+	kfree(desc);
+}
+
+static void orinoco_rx(struct net_device *dev,
+		       struct hermes_rx_descriptor *desc,
+		       struct sk_buff *skb)
+{
+	struct orinoco_private *priv = netdev_priv(dev);
+	struct net_device_stats *stats = &priv->stats;
+	u16 status, fc;
+	int length;
+	struct ethhdr *hdr;
+
+	status = le16_to_cpu(desc->status);
+	length = le16_to_cpu(desc->data_len);
+	fc = le16_to_cpu(desc->frame_ctl);
+
+	/* Calculate and check MIC */
+	if (status & HERMES_RXSTAT_MIC) {
+		int key_id = ((status & HERMES_RXSTAT_MIC_KEY_ID) >>
+			      HERMES_MIC_KEY_ID_SHIFT);
+		u8 mic[MICHAEL_MIC_LEN];
+		u8 *rxmic;
+		u8 *src = (fc & IEEE80211_FCTL_FROMDS) ?
+			desc->addr3 : desc->addr2;
+
+		/* Extract Michael MIC from payload */
+		rxmic = skb->data + skb->len - MICHAEL_MIC_LEN;
+
+		skb_trim(skb, skb->len - MICHAEL_MIC_LEN);
+		length -= MICHAEL_MIC_LEN;
+
+		michael_mic(priv->rx_tfm_mic,
+			    priv->tkip_key[key_id].rx_mic,
+			    desc->addr1,
+			    src,
+			    0, /* priority or QoS? */
+			    skb->data,
+			    skb->len,
+			    &mic[0]);
+
+		if (memcmp(mic, rxmic,
+			   MICHAEL_MIC_LEN)) {
+			union iwreq_data wrqu;
+			struct iw_michaelmicfailure wxmic;
+			DECLARE_MAC_BUF(mac);
+
+			printk(KERN_WARNING "%s: "
+			       "Invalid Michael MIC in data frame from %s, "
+			       "using key %i\n",
+			       dev->name, print_mac(mac, src), key_id);
+
+			/* TODO: update stats */
+
+			/* Notify userspace */
+			memset(&wxmic, 0, sizeof(wxmic));
+			wxmic.flags = key_id & IW_MICFAILURE_KEY_ID;
+			wxmic.flags |= (desc->addr1[0] & 1) ?
+				IW_MICFAILURE_GROUP : IW_MICFAILURE_PAIRWISE;
+			wxmic.src_addr.sa_family = ARPHRD_ETHER;
+			memcpy(wxmic.src_addr.sa_data, src, ETH_ALEN);
+
+			(void) orinoco_hw_get_tkip_iv(priv, key_id,
+						      &wxmic.tsc[0]);
+
+			memset(&wrqu, 0, sizeof(wrqu));
+			wrqu.data.length = sizeof(wxmic);
+			wireless_send_event(dev, IWEVMICHAELMICFAILURE, &wrqu,
+					    (char *) &wxmic);
+
+			goto drop;
+		}
+	}
+
 	/* Handle decapsulation
 	 * In most cases, the firmware tell us about SNAP frames.
 	 * For some reason, the SNAP frames sent by LinkSys APs
@@ -939,11 +1508,11 @@
 		hdr = (struct ethhdr *)skb_push(skb, ETH_HLEN);
 		hdr->h_proto = htons(length);
 	}
-	memcpy(hdr->h_dest, desc.addr1, ETH_ALEN);
+	memcpy(hdr->h_dest, desc->addr1, ETH_ALEN);
 	if (fc & IEEE80211_FCTL_FROMDS)
-		memcpy(hdr->h_source, desc.addr3, ETH_ALEN);
+		memcpy(hdr->h_source, desc->addr3, ETH_ALEN);
 	else
-		memcpy(hdr->h_source, desc.addr2, ETH_ALEN);
+		memcpy(hdr->h_source, desc->addr2, ETH_ALEN);
 
 	dev->last_rx = jiffies;
 	skb->protocol = eth_type_trans(skb, dev);
@@ -952,7 +1521,7 @@
 		skb->pkt_type = PACKET_OTHERHOST;
 	
 	/* Process the wireless stats if needed */
-	orinoco_stat_gather(dev, skb, &desc);
+	orinoco_stat_gather(dev, skb, desc);
 
 	/* Pass the packet to the networking stack */
 	netif_rx(skb);
@@ -961,13 +1530,33 @@
 
 	return;
 
- drop:	
-	dev_kfree_skb_irq(skb);
- update_stats:
+ drop:
+	dev_kfree_skb(skb);
 	stats->rx_errors++;
 	stats->rx_dropped++;
 }
 
+static void orinoco_rx_isr_tasklet(unsigned long data)
+{
+	struct net_device *dev = (struct net_device *) data;
+	struct orinoco_private *priv = netdev_priv(dev);
+	struct orinoco_rx_data *rx_data, *temp;
+	struct hermes_rx_descriptor *desc;
+	struct sk_buff *skb;
+
+	/* extract desc and skb from queue */
+	list_for_each_entry_safe(rx_data, temp, &priv->rx_list, list) {
+		desc = rx_data->desc;
+		skb = rx_data->skb;
+		list_del(&rx_data->list);
+		kfree(rx_data);
+
+		orinoco_rx(dev, desc, skb);
+
+		kfree(desc);
+	}
+}
+
 /********************************************************************/
 /* Rx path (info frames)                                            */
 /********************************************************************/
@@ -1087,49 +1676,169 @@
 }
 
 /* Send new BSSID to userspace */
-static void orinoco_send_wevents(struct work_struct *work)
+static void orinoco_send_bssid_wevent(struct orinoco_private *priv)
 {
-	struct orinoco_private *priv =
-		container_of(work, struct orinoco_private, wevent_work);
 	struct net_device *dev = priv->ndev;
 	struct hermes *hw = &priv->hw;
 	union iwreq_data wrqu;
 	int err;
-	unsigned long flags;
-
-	if (orinoco_lock(priv, &flags) != 0)
-		return;
 
 	err = hermes_read_ltv(hw, IRQ_BAP, HERMES_RID_CURRENTBSSID,
 			      ETH_ALEN, NULL, wrqu.ap_addr.sa_data);
 	if (err != 0)
-		goto out;
+		return;
 
 	wrqu.ap_addr.sa_family = ARPHRD_ETHER;
 
 	/* Send event to user space */
 	wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL);
-
- out:
-	orinoco_unlock(priv, &flags);
 }
 
+static void orinoco_send_assocreqie_wevent(struct orinoco_private *priv)
+{
+	struct net_device *dev = priv->ndev;
+	struct hermes *hw = &priv->hw;
+	union iwreq_data wrqu;
+	int err;
+	u8 buf[88];
+	u8 *ie;
+
+	if (!priv->has_wpa)
+		return;
+
+	err = hermes_read_ltv(hw, IRQ_BAP, HERMES_RID_CURRENT_ASSOC_REQ_INFO,
+			      sizeof(buf), NULL, &buf);
+	if (err != 0)
+		return;
+
+	ie = orinoco_get_wpa_ie(buf, sizeof(buf));
+	if (ie) {
+		int rem = sizeof(buf) - (ie - &buf[0]);
+		wrqu.data.length = ie[1] + 2;
+		if (wrqu.data.length > rem)
+			wrqu.data.length = rem;
+
+		if (wrqu.data.length)
+			/* Send event to user space */
+			wireless_send_event(dev, IWEVASSOCREQIE, &wrqu, ie);
+	}
+}
+
+static void orinoco_send_assocrespie_wevent(struct orinoco_private *priv)
+{
+	struct net_device *dev = priv->ndev;
+	struct hermes *hw = &priv->hw;
+	union iwreq_data wrqu;
+	int err;
+	u8 buf[88]; /* TODO: verify max size or IW_GENERIC_IE_MAX */
+	u8 *ie;
+
+	if (!priv->has_wpa)
+		return;
+
+	err = hermes_read_ltv(hw, IRQ_BAP, HERMES_RID_CURRENT_ASSOC_RESP_INFO,
+			      sizeof(buf), NULL, &buf);
+	if (err != 0)
+		return;
+
+	ie = orinoco_get_wpa_ie(buf, sizeof(buf));
+	if (ie) {
+		int rem = sizeof(buf) - (ie - &buf[0]);
+		wrqu.data.length = ie[1] + 2;
+		if (wrqu.data.length > rem)
+			wrqu.data.length = rem;
+
+		if (wrqu.data.length)
+			/* Send event to user space */
+			wireless_send_event(dev, IWEVASSOCRESPIE, &wrqu, ie);
+	}
+}
+
+static void orinoco_send_wevents(struct work_struct *work)
+{
+	struct orinoco_private *priv =
+		container_of(work, struct orinoco_private, wevent_work);
+	unsigned long flags;
+
+	if (orinoco_lock(priv, &flags) != 0)
+		return;
+
+	orinoco_send_assocreqie_wevent(priv);
+	orinoco_send_assocrespie_wevent(priv);
+	orinoco_send_bssid_wevent(priv);
+
+	orinoco_unlock(priv, &flags);
+}
 
 static inline void orinoco_clear_scan_results(struct orinoco_private *priv,
 					      unsigned long scan_age)
 {
-	bss_element *bss;
-	bss_element *tmp_bss;
+	if (priv->has_ext_scan) {
+		struct xbss_element *bss;
+		struct xbss_element *tmp_bss;
 
-	/* Blow away current list of scan results */
-	list_for_each_entry_safe(bss, tmp_bss, &priv->bss_list, list) {
-		if (!scan_age ||
-		    time_after(jiffies, bss->last_scanned + scan_age)) {
-			list_move_tail(&bss->list, &priv->bss_free_list);
-			/* Don't blow away ->list, just BSS data */
-			memset(bss, 0, sizeof(bss->bss));
-			bss->last_scanned = 0;
+		/* Blow away current list of scan results */
+		list_for_each_entry_safe(bss, tmp_bss, &priv->bss_list, list) {
+			if (!scan_age ||
+			    time_after(jiffies, bss->last_scanned + scan_age)) {
+				list_move_tail(&bss->list,
+					       &priv->bss_free_list);
+				/* Don't blow away ->list, just BSS data */
+				memset(&bss->bss, 0, sizeof(bss->bss));
+				bss->last_scanned = 0;
+			}
 		}
+	} else {
+		struct bss_element *bss;
+		struct bss_element *tmp_bss;
+
+		/* Blow away current list of scan results */
+		list_for_each_entry_safe(bss, tmp_bss, &priv->bss_list, list) {
+			if (!scan_age ||
+			    time_after(jiffies, bss->last_scanned + scan_age)) {
+				list_move_tail(&bss->list,
+					       &priv->bss_free_list);
+				/* Don't blow away ->list, just BSS data */
+				memset(&bss->bss, 0, sizeof(bss->bss));
+				bss->last_scanned = 0;
+			}
+		}
+	}
+}
+
+static void orinoco_add_ext_scan_result(struct orinoco_private *priv,
+					struct agere_ext_scan_info *atom)
+{
+	struct xbss_element *bss = NULL;
+	int found = 0;
+
+	/* Try to update an existing bss first */
+	list_for_each_entry(bss, &priv->bss_list, list) {
+		if (compare_ether_addr(bss->bss.bssid, atom->bssid))
+			continue;
+		/* ESSID lengths */
+		if (bss->bss.data[1] != atom->data[1])
+			continue;
+		if (memcmp(&bss->bss.data[2], &atom->data[2],
+			   atom->data[1]))
+			continue;
+		found = 1;
+		break;
+	}
+
+	/* Grab a bss off the free list */
+	if (!found && !list_empty(&priv->bss_free_list)) {
+		bss = list_entry(priv->bss_free_list.next,
+				 struct xbss_element, list);
+		list_del(priv->bss_free_list.next);
+
+		list_add_tail(&bss->list, &priv->bss_list);
+	}
+
+	if (bss) {
+		/* Always update the BSS to get latest beacon info */
+		memcpy(&bss->bss, atom, sizeof(bss->bss));
+		bss->last_scanned = jiffies;
 	}
 }
 
@@ -1194,7 +1903,7 @@
 	/* Read the entries one by one */
 	for (; offset + atom_len <= len; offset += atom_len) {
 		int found = 0;
-		bss_element *bss = NULL;
+		struct bss_element *bss = NULL;
 
 		/* Get next atom */
 		atom = (union hermes_scan_info *) (buf + offset);
@@ -1216,7 +1925,7 @@
 		/* Grab a bss off the free list */
 		if (!found && !list_empty(&priv->bss_free_list)) {
 			bss = list_entry(priv->bss_free_list.next,
-					 bss_element, list);
+					 struct bss_element, list);
 			list_del(priv->bss_free_list.next);
 
 			list_add_tail(&bss->list, &priv->bss_list);
@@ -1404,6 +2113,63 @@
 		kfree(buf);
 	}
 	break;
+	case HERMES_INQ_CHANNELINFO:
+	{
+		struct agere_ext_scan_info *bss;
+
+		if (!priv->scan_inprogress) {
+			printk(KERN_DEBUG "%s: Got chaninfo without scan, "
+			       "len=%d\n", dev->name, len);
+			break;
+		}
+
+		/* An empty result indicates that the scan is complete */
+		if (len == 0) {
+			union iwreq_data	wrqu;
+
+			/* Scan is no longer in progress */
+			priv->scan_inprogress = 0;
+
+			wrqu.data.length = 0;
+			wrqu.data.flags = 0;
+			wireless_send_event(dev, SIOCGIWSCAN, &wrqu, NULL);
+			break;
+		}
+
+		/* Sanity check */
+		else if (len > sizeof(*bss)) {
+			printk(KERN_WARNING
+			       "%s: Ext scan results too large (%d bytes). "
+			       "Truncating results to %zd bytes.\n",
+			       dev->name, len, sizeof(*bss));
+			len = sizeof(*bss);
+		} else if (len < (offsetof(struct agere_ext_scan_info,
+					   data) + 2)) {
+			/* Drop this result now so we don't have to
+			 * keep checking later */
+			printk(KERN_WARNING
+			       "%s: Ext scan results too short (%d bytes)\n",
+			       dev->name, len);
+			break;
+		}
+
+		bss = kmalloc(sizeof(*bss), GFP_ATOMIC);
+		if (bss == NULL)
+			break;
+
+		/* Read scan data */
+		err = hermes_bap_pread(hw, IRQ_BAP, (void *) bss, len,
+				       infofid, sizeof(info));
+		if (err) {
+			kfree(bss);
+			break;
+		}
+
+		orinoco_add_ext_scan_result(priv, bss);
+
+		kfree(bss);
+		break;
+	}
 	case HERMES_INQ_SEC_STAT_AGERE:
 		/* Security status (Agere specific) */
 		/* Ignore this frame for now */
@@ -1586,7 +2352,7 @@
 }
 
 /* Change the WEP keys and/or the current keys.  Can be called
- * either from __orinoco_hw_setup_wep() or directly from
+ * either from __orinoco_hw_setup_enc() or directly from
  * orinoco_ioctl_setiwencode().  In the later case the association
  * with the AP is not broken (if the firmware can handle it),
  * which is needed for 802.1x implementations. */
@@ -1646,14 +2412,16 @@
 	return 0;
 }
 
-static int __orinoco_hw_setup_wep(struct orinoco_private *priv)
+static int __orinoco_hw_setup_enc(struct orinoco_private *priv)
 {
 	hermes_t *hw = &priv->hw;
 	int err = 0;
 	int master_wep_flag;
 	int auth_flag;
+	int enc_flag;
 
-	if (priv->wep_on)
+	/* Setup WEP keys for WEP and WPA */
+	if (priv->encode_alg)
 		__orinoco_hw_setup_wepkeys(priv);
 
 	if (priv->wep_restrict)
@@ -1661,9 +2429,16 @@
 	else
 		auth_flag = HERMES_AUTH_OPEN;
 
+	if (priv->wpa_enabled)
+		enc_flag = 2;
+	else if (priv->encode_alg == IW_ENCODE_ALG_WEP)
+		enc_flag = 1;
+	else
+		enc_flag = 0;
+
 	switch (priv->firmware_type) {
 	case FIRMWARE_TYPE_AGERE: /* Agere style WEP */
-		if (priv->wep_on) {
+		if (priv->encode_alg == IW_ENCODE_ALG_WEP) {
 			/* Enable the shared-key authentication. */
 			err = hermes_write_wordrec(hw, USER_BAP,
 						   HERMES_RID_CNFAUTHENTICATION_AGERE,
@@ -1671,14 +2446,24 @@
 		}
 		err = hermes_write_wordrec(hw, USER_BAP,
 					   HERMES_RID_CNFWEPENABLED_AGERE,
-					   priv->wep_on);
+					   enc_flag);
 		if (err)
 			return err;
+
+		if (priv->has_wpa) {
+			/* Set WPA key management */
+			err = hermes_write_wordrec(hw, USER_BAP,
+				  HERMES_RID_CNFSETWPAAUTHMGMTSUITE_AGERE,
+				  priv->key_mgmt);
+			if (err)
+				return err;
+		}
+
 		break;
 
 	case FIRMWARE_TYPE_INTERSIL: /* Intersil style WEP */
 	case FIRMWARE_TYPE_SYMBOL: /* Symbol style WEP */
-		if (priv->wep_on) {
+		if (priv->encode_alg == IW_ENCODE_ALG_WEP) {
 			if (priv->wep_restrict ||
 			    (priv->firmware_type == FIRMWARE_TYPE_SYMBOL))
 				master_wep_flag = HERMES_WEP_PRIVACY_INVOKED |
@@ -1710,6 +2495,84 @@
 	return 0;
 }
 
+/* key must be 32 bytes, including the tx and rx MIC keys.
+ * rsc must be 8 bytes
+ * tsc must be 8 bytes or NULL
+ */
+static int __orinoco_hw_set_tkip_key(hermes_t *hw, int key_idx, int set_tx,
+				     u8 *key, u8 *rsc, u8 *tsc)
+{
+	struct {
+		__le16 idx;
+		u8 rsc[IW_ENCODE_SEQ_MAX_SIZE];
+		u8 key[TKIP_KEYLEN];
+		u8 tx_mic[MIC_KEYLEN];
+		u8 rx_mic[MIC_KEYLEN];
+		u8 tsc[IW_ENCODE_SEQ_MAX_SIZE];
+	} __attribute__ ((packed)) buf;
+	int ret;
+	int err;
+	int k;
+	u16 xmitting;
+
+	key_idx &= 0x3;
+
+	if (set_tx)
+		key_idx |= 0x8000;
+
+	buf.idx = cpu_to_le16(key_idx);
+	memcpy(buf.key, key,
+	       sizeof(buf.key) + sizeof(buf.tx_mic) + sizeof(buf.rx_mic));
+
+	if (rsc == NULL)
+		memset(buf.rsc, 0, sizeof(buf.rsc));
+	else
+		memcpy(buf.rsc, rsc, sizeof(buf.rsc));
+
+	if (tsc == NULL) {
+		memset(buf.tsc, 0, sizeof(buf.tsc));
+		buf.tsc[4] = 0x10;
+	} else {
+		memcpy(buf.tsc, tsc, sizeof(buf.tsc));
+	}
+
+	/* Wait upto 100ms for tx queue to empty */
+	k = 100;
+	do {
+		k--;
+		udelay(1000);
+		ret = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_TXQUEUEEMPTY,
+					  &xmitting);
+		if (ret)
+			break;
+	} while ((k > 0) && xmitting);
+
+	if (k == 0)
+		ret = -ETIMEDOUT;
+
+	err = HERMES_WRITE_RECORD(hw, USER_BAP,
+				  HERMES_RID_CNFADDDEFAULTTKIPKEY_AGERE,
+				  &buf);
+
+	return ret ? ret : err;
+}
+
+static int orinoco_clear_tkip_key(struct orinoco_private *priv,
+				  int key_idx)
+{
+	hermes_t *hw = &priv->hw;
+	int err;
+
+	memset(&priv->tkip_key[key_idx], 0, sizeof(priv->tkip_key[key_idx]));
+	err = hermes_write_wordrec(hw, USER_BAP,
+				   HERMES_RID_CNFREMDEFAULTTKIPKEY_AGERE,
+				   key_idx);
+	if (err)
+		printk(KERN_WARNING "%s: Error %d clearing TKIP key %d\n",
+		       priv->ndev->name, err, key_idx);
+	return err;
+}
+
 static int __orinoco_program_rids(struct net_device *dev)
 {
 	struct orinoco_private *priv = netdev_priv(dev);
@@ -1906,10 +2769,10 @@
 	}
 
 	/* Set up encryption */
-	if (priv->has_wep) {
-		err = __orinoco_hw_setup_wep(priv);
+	if (priv->has_wep || priv->has_wpa) {
+		err = __orinoco_hw_setup_enc(priv);
 		if (err) {
-			printk(KERN_ERR "%s: Error %d activating WEP\n",
+			printk(KERN_ERR "%s: Error %d activating encryption\n",
 			       dev->name, err);
 			return err;
 		}
@@ -2047,6 +2910,12 @@
 		}
 	}
 
+	if (priv->do_fw_download) {
+		err = orinoco_download(priv);
+		if (err)
+			priv->do_fw_download = 0;
+	}
+
 	err = orinoco_reinit_firmware(dev);
 	if (err) {
 		printk(KERN_ERR "%s: orinoco_reset: Error %d re-initializing firmware\n",
@@ -2258,6 +3127,10 @@
 	priv->has_ibss = 1;
 	priv->has_wep = 0;
 	priv->has_big_wep = 0;
+	priv->has_alt_txcntl = 0;
+	priv->has_ext_scan = 0;
+	priv->has_wpa = 0;
+	priv->do_fw_download = 0;
 
 	/* Determine capabilities from the firmware version */
 	switch (priv->firmware_type) {
@@ -2277,8 +3150,11 @@
 		priv->has_pm = (firmver >= 0x40020); /* Don't work in 7.52 ? */
 		priv->ibss_port = 1;
 		priv->has_hostscan = (firmver >= 0x8000a);
+		priv->do_fw_download = 1;
 		priv->broken_monitor = (firmver >= 0x80000);
-
+		priv->has_alt_txcntl = (firmver >= 0x90000); /* All 9.x ? */
+		priv->has_ext_scan = (firmver >= 0x90000); /* All 9.x ? */
+		priv->has_wpa = (firmver >= 0x9002a);
 		/* Tested with Agere firmware :
 		 *	1.16 ; 4.08 ; 4.52 ; 6.04 ; 6.16 ; 7.28 => Jean II
 		 * Tested CableTron firmware : 4.32 => Anton */
@@ -2321,6 +3197,21 @@
 			       firmver >= 0x31000;
 		priv->has_preamble = (firmver >= 0x20000);
 		priv->ibss_port = 4;
+
+		/* Symbol firmware is found on various cards, but
+		 * there has been no attempt to check firmware
+		 * download on non-spectrum_cs based cards.
+		 *
+		 * Given that the Agere firmware download works
+		 * differently, we should avoid doing a firmware
+		 * download with the Symbol algorithm on non-spectrum
+		 * cards.
+		 *
+		 * For now we can identify a spectrum_cs based card
+		 * because it has a firmware reset function.
+		 */
+		priv->do_fw_download = (priv->stop_fw != NULL);
+
  		priv->broken_disableport = (firmver == 0x25013) ||
  					   (firmver >= 0x30000 && firmver <= 0x31000);
 		priv->has_hostscan = (firmver >= 0x31001) ||
@@ -2391,6 +3282,20 @@
 		goto out;
 	}
 
+	if (priv->do_fw_download) {
+		err = orinoco_download(priv);
+		if (err)
+			priv->do_fw_download = 0;
+
+		/* Check firmware version again */
+		err = determine_firmware(dev);
+		if (err != 0) {
+			printk(KERN_ERR "%s: Incompatible firmware, aborting\n",
+			       dev->name);
+			goto out;
+		}
+	}
+
 	if (priv->has_port3)
 		printk(KERN_DEBUG "%s: Ad-hoc demo mode supported\n", dev->name);
 	if (priv->has_ibss)
@@ -2403,6 +3308,20 @@
 		else
 			printk("40-bit key\n");
 	}
+	if (priv->has_wpa) {
+		printk(KERN_DEBUG "%s: WPA-PSK supported\n", dev->name);
+		if (orinoco_mic_init(priv)) {
+			printk(KERN_ERR "%s: Failed to setup MIC crypto "
+			       "algorithm. Disabling WPA support\n", dev->name);
+			priv->has_wpa = 0;
+		}
+	}
+
+	/* Now we have the firmware capabilities, allocate appropiate
+	 * sized scan buffers */
+	if (orinoco_bss_data_allocate(priv))
+		goto out;
+	orinoco_bss_data_init(priv);
 
 	/* Get the MAC address */
 	err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CNFOWNMACADDR,
@@ -2518,8 +3437,13 @@
 	priv->channel = 0; /* use firmware default */
 
 	priv->promiscuous = 0;
-	priv->wep_on = 0;
+	priv->encode_alg = IW_ENCODE_ALG_NONE;
 	priv->tx_key = 0;
+	priv->wpa_enabled = 0;
+	priv->tkip_cm_active = 0;
+	priv->key_mgmt = 0;
+	priv->wpa_ie_len = 0;
+	priv->wpa_ie = NULL;
 
 	/* Make the hardware available, as long as it hasn't been
 	 * removed elsewhere (e.g. by PCMCIA hot unplug) */
@@ -2533,8 +3457,11 @@
 	return err;
 }
 
-struct net_device *alloc_orinocodev(int sizeof_card,
-				    int (*hard_reset)(struct orinoco_private *))
+struct net_device
+*alloc_orinocodev(int sizeof_card,
+		  struct device *device,
+		  int (*hard_reset)(struct orinoco_private *),
+		  int (*stop_fw)(struct orinoco_private *, int))
 {
 	struct net_device *dev;
 	struct orinoco_private *priv;
@@ -2549,10 +3476,7 @@
 				      + sizeof(struct orinoco_private));
 	else
 		priv->card = NULL;
-
-	if (orinoco_bss_data_allocate(priv))
-		goto err_out_free;
-	orinoco_bss_data_init(priv);
+	priv->dev = device;
 
 	/* Setup / override net_device fields */
 	dev->init = orinoco_init;
@@ -2570,10 +3494,14 @@
 	dev->set_multicast_list = orinoco_set_multicast_list;
 	/* we use the default eth_mac_addr for setting the MAC addr */
 
+	/* Reserve space in skb for the SNAP header */
+	dev->hard_header_len += ENCAPS_OVERHEAD;
+
 	/* Set up default callbacks */
 	dev->open = orinoco_open;
 	dev->stop = orinoco_stop;
 	priv->hard_reset = hard_reset;
+	priv->stop_fw = stop_fw;
 
 	spin_lock_init(&priv->lock);
 	priv->open = 0;
@@ -2584,20 +3512,27 @@
 	INIT_WORK(&priv->join_work, orinoco_join_ap);
 	INIT_WORK(&priv->wevent_work, orinoco_send_wevents);
 
+	INIT_LIST_HEAD(&priv->rx_list);
+	tasklet_init(&priv->rx_tasklet, orinoco_rx_isr_tasklet,
+		     (unsigned long) dev);
+
 	netif_carrier_off(dev);
 	priv->last_linkstatus = 0xffff;
 
 	return dev;
-
-err_out_free:
-	free_netdev(dev);
-	return NULL;
 }
 
 void free_orinocodev(struct net_device *dev)
 {
 	struct orinoco_private *priv = netdev_priv(dev);
 
+	/* No need to empty priv->rx_list: if the tasklet is scheduled
+	 * when we call tasklet_kill it will run one final time,
+	 * emptying the list */
+	tasklet_kill(&priv->rx_tasklet);
+	priv->wpa_ie_len = 0;
+	kfree(priv->wpa_ie);
+	orinoco_mic_free(priv);
 	orinoco_bss_data_free(priv);
 	free_netdev(dev);
 }
@@ -2909,7 +3844,7 @@
 	memset(range, 0, sizeof(struct iw_range));
 
 	range->we_version_compiled = WIRELESS_EXT;
-	range->we_version_source = 14;
+	range->we_version_source = 22;
 
 	/* Set available channels/frequencies */
 	range->num_channels = NUM_CHANNELS;
@@ -2939,6 +3874,9 @@
 		}
 	}
 
+	if (priv->has_wpa)
+		range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_CIPHER_TKIP;
+
 	if ((priv->iw_mode == IW_MODE_ADHOC) && (!SPY_NUMBER(priv))){
 		/* Quality stats meaningless in ad-hoc mode */
 	} else {
@@ -2986,6 +3924,11 @@
 	range->min_r_time = 0;
 	range->max_r_time = 65535 * 1000;	/* ??? */
 
+	if (priv->firmware_type == FIRMWARE_TYPE_AGERE)
+		range->scan_capa = IW_SCAN_CAPA_ESSID;
+	else
+		range->scan_capa = IW_SCAN_CAPA_NONE;
+
 	/* Event capability (kernel) */
 	IW_EVENT_CAPA_SET_KERNEL(range->event_capa);
 	/* Event capability (driver) */
@@ -3005,7 +3948,7 @@
 	struct orinoco_private *priv = netdev_priv(dev);
 	int index = (erq->flags & IW_ENCODE_INDEX) - 1;
 	int setindex = priv->tx_key;
-	int enable = priv->wep_on;
+	int encode_alg = priv->encode_alg;
 	int restricted = priv->wep_restrict;
 	u16 xlen = 0;
 	int err = -EINPROGRESS;		/* Call commit handler */
@@ -3026,6 +3969,10 @@
 	if (orinoco_lock(priv, &flags) != 0)
 		return -EBUSY;
 
+	/* Clear any TKIP key we have */
+	if ((priv->has_wpa) && (priv->encode_alg == IW_ENCODE_ALG_TKIP))
+		(void) orinoco_clear_tkip_key(priv, setindex);
+
 	if (erq->length > 0) {
 		if ((index < 0) || (index >= ORINOCO_MAX_KEYS))
 			index = priv->tx_key;
@@ -3039,9 +3986,9 @@
 			xlen = 0;
 
 		/* Switch on WEP if off */
-		if ((!enable) && (xlen > 0)) {
+		if ((encode_alg != IW_ENCODE_ALG_WEP) && (xlen > 0)) {
 			setindex = index;
-			enable = 1;
+			encode_alg = IW_ENCODE_ALG_WEP;
 		}
 	} else {
 		/* Important note : if the user do "iwconfig eth0 enc off",
@@ -3063,7 +4010,7 @@
 	}
 
 	if (erq->flags & IW_ENCODE_DISABLED)
-		enable = 0;
+		encode_alg = IW_ENCODE_ALG_NONE;
 	if (erq->flags & IW_ENCODE_OPEN)
 		restricted = 0;
 	if (erq->flags & IW_ENCODE_RESTRICTED)
@@ -3078,14 +4025,15 @@
 	priv->tx_key = setindex;
 
 	/* Try fast key change if connected and only keys are changed */
-	if (priv->wep_on && enable && (priv->wep_restrict == restricted) &&
+	if ((priv->encode_alg == encode_alg) &&
+	    (priv->wep_restrict == restricted) &&
 	    netif_carrier_ok(dev)) {
 		err = __orinoco_hw_setup_wepkeys(priv);
 		/* No need to commit if successful */
 		goto out;
 	}
 
-	priv->wep_on = enable;
+	priv->encode_alg = encode_alg;
 	priv->wep_restrict = restricted;
 
  out:
@@ -3114,7 +4062,7 @@
 		index = priv->tx_key;
 
 	erq->flags = 0;
-	if (! priv->wep_on)
+	if (!priv->encode_alg)
 		erq->flags |= IW_ENCODE_DISABLED;
 	erq->flags |= index + 1;
 
@@ -3689,6 +4637,399 @@
 	return err;
 }
 
+static int orinoco_ioctl_set_encodeext(struct net_device *dev,
+				       struct iw_request_info *info,
+				       union iwreq_data *wrqu,
+				       char *extra)
+{
+	struct orinoco_private *priv = netdev_priv(dev);
+	struct iw_point *encoding = &wrqu->encoding;
+	struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
+	int idx, alg = ext->alg, set_key = 1;
+	unsigned long flags;
+	int err = -EINVAL;
+	u16 key_len;
+
+	if (orinoco_lock(priv, &flags) != 0)
+		return -EBUSY;
+
+	/* Determine and validate the key index */
+	idx = encoding->flags & IW_ENCODE_INDEX;
+	if (idx) {
+		if ((idx < 1) || (idx > WEP_KEYS))
+			goto out;
+		idx--;
+	} else
+		idx = priv->tx_key;
+
+	if (encoding->flags & IW_ENCODE_DISABLED)
+	    alg = IW_ENCODE_ALG_NONE;
+
+	if (priv->has_wpa && (alg != IW_ENCODE_ALG_TKIP)) {
+		/* Clear any TKIP TX key we had */
+		(void) orinoco_clear_tkip_key(priv, priv->tx_key);
+	}
+
+	if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
+		priv->tx_key = idx;
+		set_key = ((alg == IW_ENCODE_ALG_TKIP) ||
+			   (ext->key_len > 0)) ? 1 : 0;
+	}
+
+	if (set_key) {
+		/* Set the requested key first */
+		switch (alg) {
+		case IW_ENCODE_ALG_NONE:
+			priv->encode_alg = alg;
+			priv->keys[idx].len = 0;
+			break;
+
+		case IW_ENCODE_ALG_WEP:
+			if (ext->key_len > SMALL_KEY_SIZE)
+				key_len = LARGE_KEY_SIZE;
+			else if (ext->key_len > 0)
+				key_len = SMALL_KEY_SIZE;
+			else
+				goto out;
+
+			priv->encode_alg = alg;
+			priv->keys[idx].len = cpu_to_le16(key_len);
+
+			key_len = min(ext->key_len, key_len);
+
+			memset(priv->keys[idx].data, 0, ORINOCO_MAX_KEY_SIZE);
+			memcpy(priv->keys[idx].data, ext->key, key_len);
+			break;
+
+		case IW_ENCODE_ALG_TKIP:
+		{
+			hermes_t *hw = &priv->hw;
+			u8 *tkip_iv = NULL;
+
+			if (!priv->has_wpa ||
+			    (ext->key_len > sizeof(priv->tkip_key[0])))
+				goto out;
+
+			priv->encode_alg = alg;
+			memset(&priv->tkip_key[idx], 0,
+			       sizeof(priv->tkip_key[idx]));
+			memcpy(&priv->tkip_key[idx], ext->key, ext->key_len);
+
+			if (ext->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID)
+				tkip_iv = &ext->rx_seq[0];
+
+			err = __orinoco_hw_set_tkip_key(hw, idx,
+				 ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY,
+				 (u8 *) &priv->tkip_key[idx],
+				 tkip_iv, NULL);
+			if (err)
+				printk(KERN_ERR "%s: Error %d setting TKIP key"
+				       "\n", dev->name, err);
+
+			goto out;
+		}
+		default:
+			goto out;
+		}
+	}
+	err = -EINPROGRESS;
+ out:
+	orinoco_unlock(priv, &flags);
+
+	return err;
+}
+
+static int orinoco_ioctl_get_encodeext(struct net_device *dev,
+				       struct iw_request_info *info,
+				       union iwreq_data *wrqu,
+				       char *extra)
+{
+	struct orinoco_private *priv = netdev_priv(dev);
+	struct iw_point *encoding = &wrqu->encoding;
+	struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
+	int idx, max_key_len;
+	unsigned long flags;
+	int err;
+
+	if (orinoco_lock(priv, &flags) != 0)
+		return -EBUSY;
+
+	err = -EINVAL;
+	max_key_len = encoding->length - sizeof(*ext);
+	if (max_key_len < 0)
+		goto out;
+
+	idx = encoding->flags & IW_ENCODE_INDEX;
+	if (idx) {
+		if ((idx < 1) || (idx > WEP_KEYS))
+			goto out;
+		idx--;
+	} else
+		idx = priv->tx_key;
+
+	encoding->flags = idx + 1;
+	memset(ext, 0, sizeof(*ext));
+
+	ext->alg = priv->encode_alg;
+	switch (priv->encode_alg) {
+	case IW_ENCODE_ALG_NONE:
+		ext->key_len = 0;
+		encoding->flags |= IW_ENCODE_DISABLED;
+		break;
+	case IW_ENCODE_ALG_WEP:
+		ext->key_len = min_t(u16, le16_to_cpu(priv->keys[idx].len),
+				     max_key_len);
+		memcpy(ext->key, priv->keys[idx].data, ext->key_len);
+		encoding->flags |= IW_ENCODE_ENABLED;
+		break;
+	case IW_ENCODE_ALG_TKIP:
+		ext->key_len = min_t(u16, sizeof(struct orinoco_tkip_key),
+				     max_key_len);
+		memcpy(ext->key, &priv->tkip_key[idx], ext->key_len);
+		encoding->flags |= IW_ENCODE_ENABLED;
+		break;
+	}
+
+	err = 0;
+ out:
+	orinoco_unlock(priv, &flags);
+
+	return err;
+}
+
+static int orinoco_ioctl_set_auth(struct net_device *dev,
+				  struct iw_request_info *info,
+				  union iwreq_data *wrqu, char *extra)
+{
+	struct orinoco_private *priv = netdev_priv(dev);
+	hermes_t *hw = &priv->hw;
+	struct iw_param *param = &wrqu->param;
+	unsigned long flags;
+	int ret = -EINPROGRESS;
+
+	if (orinoco_lock(priv, &flags) != 0)
+		return -EBUSY;
+
+	switch (param->flags & IW_AUTH_INDEX) {
+	case IW_AUTH_WPA_VERSION:
+	case IW_AUTH_CIPHER_PAIRWISE:
+	case IW_AUTH_CIPHER_GROUP:
+	case IW_AUTH_RX_UNENCRYPTED_EAPOL:
+	case IW_AUTH_PRIVACY_INVOKED:
+	case IW_AUTH_DROP_UNENCRYPTED:
+		/*
+		 * orinoco does not use these parameters
+		 */
+		break;
+
+	case IW_AUTH_KEY_MGMT:
+		/* wl_lkm implies value 2 == PSK for Hermes I
+		 * which ties in with WEXT
+		 * no other hints tho :(
+		 */
+		priv->key_mgmt = param->value;
+		break;
+
+	case IW_AUTH_TKIP_COUNTERMEASURES:
+		/* When countermeasures are enabled, shut down the
+		 * card; when disabled, re-enable the card. This must
+		 * take effect immediately.
+		 *
+		 * TODO: Make sure that the EAPOL message is getting
+		 *       out before card disabled
+		 */
+		if (param->value) {
+			priv->tkip_cm_active = 1;
+			ret = hermes_enable_port(hw, 0);
+		} else {
+			priv->tkip_cm_active = 0;
+			ret = hermes_disable_port(hw, 0);
+		}
+		break;
+
+	case IW_AUTH_80211_AUTH_ALG:
+		if (param->value & IW_AUTH_ALG_SHARED_KEY)
+			priv->wep_restrict = 1;
+		else if (param->value & IW_AUTH_ALG_OPEN_SYSTEM)
+			priv->wep_restrict = 0;
+		else
+			ret = -EINVAL;
+		break;
+
+	case IW_AUTH_WPA_ENABLED:
+		if (priv->has_wpa) {
+			priv->wpa_enabled = param->value ? 1 : 0;
+		} else {
+			if (param->value)
+				ret = -EOPNOTSUPP;
+			/* else silently accept disable of WPA */
+			priv->wpa_enabled = 0;
+		}
+		break;
+
+	default:
+		ret = -EOPNOTSUPP;
+	}
+
+	orinoco_unlock(priv, &flags);
+	return ret;
+}
+
+static int orinoco_ioctl_get_auth(struct net_device *dev,
+				  struct iw_request_info *info,
+				  union iwreq_data *wrqu, char *extra)
+{
+	struct orinoco_private *priv = netdev_priv(dev);
+	struct iw_param *param = &wrqu->param;
+	unsigned long flags;
+	int ret = 0;
+
+	if (orinoco_lock(priv, &flags) != 0)
+		return -EBUSY;
+
+	switch (param->flags & IW_AUTH_INDEX) {
+	case IW_AUTH_KEY_MGMT:
+		param->value = priv->key_mgmt;
+		break;
+
+	case IW_AUTH_TKIP_COUNTERMEASURES:
+		param->value = priv->tkip_cm_active;
+		break;
+
+	case IW_AUTH_80211_AUTH_ALG:
+		if (priv->wep_restrict)
+			param->value = IW_AUTH_ALG_SHARED_KEY;
+		else
+			param->value = IW_AUTH_ALG_OPEN_SYSTEM;
+		break;
+
+	case IW_AUTH_WPA_ENABLED:
+		param->value = priv->wpa_enabled;
+		break;
+
+	default:
+		ret = -EOPNOTSUPP;
+	}
+
+	orinoco_unlock(priv, &flags);
+	return ret;
+}
+
+static int orinoco_ioctl_set_genie(struct net_device *dev,
+				   struct iw_request_info *info,
+				   union iwreq_data *wrqu, char *extra)
+{
+	struct orinoco_private *priv = netdev_priv(dev);
+	u8 *buf;
+	unsigned long flags;
+	int err = 0;
+
+	if ((wrqu->data.length > MAX_WPA_IE_LEN) ||
+	    (wrqu->data.length && (extra == NULL)))
+		return -EINVAL;
+
+	if (orinoco_lock(priv, &flags) != 0)
+		return -EBUSY;
+
+	if (wrqu->data.length) {
+		buf = kmalloc(wrqu->data.length, GFP_KERNEL);
+		if (buf == NULL) {
+			err = -ENOMEM;
+			goto out;
+		}
+
+		memcpy(buf, extra, wrqu->data.length);
+		kfree(priv->wpa_ie);
+		priv->wpa_ie = buf;
+		priv->wpa_ie_len = wrqu->data.length;
+	} else {
+		kfree(priv->wpa_ie);
+		priv->wpa_ie = NULL;
+		priv->wpa_ie_len = 0;
+	}
+
+	if (priv->wpa_ie) {
+		/* Looks like wl_lkm wants to check the auth alg, and
+		 * somehow pass it to the firmware.
+		 * Instead it just calls the key mgmt rid
+		 *   - we do this in set auth.
+		 */
+	}
+
+out:
+	orinoco_unlock(priv, &flags);
+	return err;
+}
+
+static int orinoco_ioctl_get_genie(struct net_device *dev,
+				   struct iw_request_info *info,
+				   union iwreq_data *wrqu, char *extra)
+{
+	struct orinoco_private *priv = netdev_priv(dev);
+	unsigned long flags;
+	int err = 0;
+
+	if (orinoco_lock(priv, &flags) != 0)
+		return -EBUSY;
+
+	if ((priv->wpa_ie_len == 0) || (priv->wpa_ie == NULL)) {
+		wrqu->data.length = 0;
+		goto out;
+	}
+
+	if (wrqu->data.length < priv->wpa_ie_len) {
+		err = -E2BIG;
+		goto out;
+	}
+
+	wrqu->data.length = priv->wpa_ie_len;
+	memcpy(extra, priv->wpa_ie, priv->wpa_ie_len);
+
+out:
+	orinoco_unlock(priv, &flags);
+	return err;
+}
+
+static int orinoco_ioctl_set_mlme(struct net_device *dev,
+				  struct iw_request_info *info,
+				  union iwreq_data *wrqu, char *extra)
+{
+	struct orinoco_private *priv = netdev_priv(dev);
+	hermes_t *hw = &priv->hw;
+	struct iw_mlme *mlme = (struct iw_mlme *)extra;
+	unsigned long flags;
+	int ret = 0;
+
+	if (orinoco_lock(priv, &flags) != 0)
+		return -EBUSY;
+
+	switch (mlme->cmd) {
+	case IW_MLME_DEAUTH:
+		/* silently ignore */
+		break;
+
+	case IW_MLME_DISASSOC:
+	{
+		struct {
+			u8 addr[ETH_ALEN];
+			__le16 reason_code;
+		} __attribute__ ((packed)) buf;
+
+		memcpy(buf.addr, mlme->addr.sa_data, ETH_ALEN);
+		buf.reason_code = cpu_to_le16(mlme->reason_code);
+		ret = HERMES_WRITE_RECORD(hw, USER_BAP,
+					  HERMES_RID_CNFDISASSOCIATE,
+					  &buf);
+		break;
+	}
+	default:
+		ret = -EOPNOTSUPP;
+	}
+
+	orinoco_unlock(priv, &flags);
+	return ret;
+}
+
 static int orinoco_ioctl_getretry(struct net_device *dev,
 				  struct iw_request_info *info,
 				  struct iw_param *rrq,
@@ -3947,14 +5288,15 @@
 	return err;
 }
 
-/* Trigger a scan (look for other cells in the vicinity */
+/* Trigger a scan (look for other cells in the vicinity) */
 static int orinoco_ioctl_setscan(struct net_device *dev,
 				 struct iw_request_info *info,
-				 struct iw_param *srq,
+				 struct iw_point *srq,
 				 char *extra)
 {
 	struct orinoco_private *priv = netdev_priv(dev);
 	hermes_t *hw = &priv->hw;
+	struct iw_scan_req *si = (struct iw_scan_req *) extra;
 	int err = 0;
 	unsigned long flags;
 
@@ -3986,7 +5328,6 @@
 	 * we access scan variables in priv is critical.
 	 *	o scan_inprogress : not touched by irq handler
 	 *	o scan_mode : not touched by irq handler
-	 *	o scan_len : synchronised with scan_result
 	 * Before modifying anything on those variables, please think hard !
 	 * Jean II */
 
@@ -4016,13 +5357,43 @@
 		}
 		break;
 		case FIRMWARE_TYPE_AGERE:
-			err = hermes_write_wordrec(hw, USER_BAP,
+			if (priv->scan_mode & IW_SCAN_THIS_ESSID) {
+				struct hermes_idstring idbuf;
+				size_t len = min(sizeof(idbuf.val),
+						 (size_t) si->essid_len);
+				idbuf.len = cpu_to_le16(len);
+				memcpy(idbuf.val, si->essid, len);
+
+				err = hermes_write_ltv(hw, USER_BAP,
+					       HERMES_RID_CNFSCANSSID_AGERE,
+					       HERMES_BYTES_TO_RECLEN(len + 2),
+					       &idbuf);
+			} else
+				err = hermes_write_wordrec(hw, USER_BAP,
 						   HERMES_RID_CNFSCANSSID_AGERE,
 						   0);	/* Any ESSID */
 			if (err)
 				break;
 
-			err = hermes_inquire(hw, HERMES_INQ_SCAN);
+			if (priv->has_ext_scan) {
+				/* Clear scan results at the start of
+				 * an extended scan */
+				orinoco_clear_scan_results(priv,
+						msecs_to_jiffies(15000));
+
+				/* TODO: Is this available on older firmware?
+				 *   Can we use it to scan specific channels
+				 *   for IW_SCAN_THIS_FREQ? */
+				err = hermes_write_wordrec(hw, USER_BAP,
+						HERMES_RID_CNFSCANCHANNELS2GHZ,
+						0x7FFF);
+				if (err)
+					goto out;
+
+				err = hermes_inquire(hw,
+						     HERMES_INQ_CHANNELINFO);
+			} else
+				err = hermes_inquire(hw, HERMES_INQ_SCAN);
 			break;
 		}
 	} else
@@ -4040,8 +5411,7 @@
 #define MAX_CUSTOM_LEN 64
 
 /* Translate scan data returned from the card to a card independant
- * format that the Wireless Tools will understand - Jean II
- * Return message length or -errno for fatal errors */
+ * format that the Wireless Tools will understand - Jean II */
 static inline char *orinoco_translate_scan(struct net_device *dev,
 					   struct iw_request_info *info,
 					   char *current_ev,
@@ -4053,9 +5423,10 @@
 	u16			capabilities;
 	u16			channel;
 	struct iw_event		iwe;		/* Temporary buffer */
-	char                   *p;
 	char custom[MAX_CUSTOM_LEN];
 
+	memset(&iwe, 0, sizeof(iwe));
+
 	/* First entry *MUST* be the AP MAC address */
 	iwe.cmd = SIOCGIWAP;
 	iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
@@ -4077,8 +5448,8 @@
 	/* Add mode */
 	iwe.cmd = SIOCGIWMODE;
 	capabilities = le16_to_cpu(bss->a.capabilities);
-	if (capabilities & 0x3) {
-		if (capabilities & 0x1)
+	if (capabilities & (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS)) {
+		if (capabilities & WLAN_CAPABILITY_ESS)
 			iwe.u.mode = IW_MODE_MASTER;
 		else
 			iwe.u.mode = IW_MODE_ADHOC;
@@ -4088,17 +5459,22 @@
 
 	channel = bss->s.channel;
 	if ((channel >= 1) && (channel <= NUM_CHANNELS)) {
-		/* Add frequency */
+		/* Add channel and frequency */
 		iwe.cmd = SIOCGIWFREQ;
+		iwe.u.freq.m = channel;
+		iwe.u.freq.e = 0;
+		current_ev = iwe_stream_add_event(info, current_ev, end_buf,
+						  &iwe, IW_EV_FREQ_LEN);
+
 		iwe.u.freq.m = channel_frequency[channel-1] * 100000;
 		iwe.u.freq.e = 1;
 		current_ev = iwe_stream_add_event(info, current_ev, end_buf,
 						  &iwe, IW_EV_FREQ_LEN);
 	}
 
-	/* Add quality statistics */
+	/* Add quality statistics. level and noise in dB. No link quality */
 	iwe.cmd = IWEVQUAL;
-	iwe.u.qual.updated = 0x10;	/* no link quality */
+	iwe.u.qual.updated = IW_QUAL_DBM | IW_QUAL_QUAL_INVALID;
 	iwe.u.qual.level = (__u8) le16_to_cpu(bss->a.level) - 0x95;
 	iwe.u.qual.noise = (__u8) le16_to_cpu(bss->a.noise) - 0x95;
 	/* Wireless tools prior to 27.pre22 will show link quality
@@ -4112,25 +5488,13 @@
 
 	/* Add encryption capability */
 	iwe.cmd = SIOCGIWENCODE;
-	if (capabilities & 0x10)
+	if (capabilities & WLAN_CAPABILITY_PRIVACY)
 		iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
 	else
 		iwe.u.data.flags = IW_ENCODE_DISABLED;
 	iwe.u.data.length = 0;
 	current_ev = iwe_stream_add_point(info, current_ev, end_buf,
-					  &iwe, bss->a.essid);
-
-	/* Add EXTRA: Age to display seconds since last beacon/probe response
-	 * for given network. */
-	iwe.cmd = IWEVCUSTOM;
-	p = custom;
-	p += snprintf(p, MAX_CUSTOM_LEN - (p - custom),
-		      " Last beacon: %dms ago",
-		      jiffies_to_msecs(jiffies - last_scanned));
-	iwe.u.data.length = p - custom;
-	if (iwe.u.data.length)
-		current_ev = iwe_stream_add_point(info, current_ev, end_buf,
-						  &iwe, custom);
+					  &iwe, NULL);
 
 	/* Bit rate is not available in Lucent/Agere firmwares */
 	if (priv->firmware_type != FIRMWARE_TYPE_AGERE) {
@@ -4152,7 +5516,8 @@
 			if (bss->p.rates[i] == 0x0)
 				break;
 			/* Bit rate given in 500 kb/s units (+ 0x80) */
-			iwe.u.bitrate.value = ((bss->p.rates[i] & 0x7f) * 500000);
+			iwe.u.bitrate.value =
+				((bss->p.rates[i] & 0x7f) * 500000);
 			current_val = iwe_stream_add_value(info, current_ev,
 							   current_val,
 							   end_buf, &iwe,
@@ -4163,6 +5528,199 @@
 			current_ev = current_val;
 	}
 
+	/* Beacon interval */
+	iwe.cmd = IWEVCUSTOM;
+	iwe.u.data.length = snprintf(custom, MAX_CUSTOM_LEN,
+				     "bcn_int=%d",
+				     le16_to_cpu(bss->a.beacon_interv));
+	if (iwe.u.data.length)
+		current_ev = iwe_stream_add_point(info, current_ev, end_buf,
+						  &iwe, custom);
+
+	/* Capabilites */
+	iwe.cmd = IWEVCUSTOM;
+	iwe.u.data.length = snprintf(custom, MAX_CUSTOM_LEN,
+				     "capab=0x%04x",
+				     capabilities);
+	if (iwe.u.data.length)
+		current_ev = iwe_stream_add_point(info, current_ev, end_buf,
+						  &iwe, custom);
+
+	/* Add EXTRA: Age to display seconds since last beacon/probe response
+	 * for given network. */
+	iwe.cmd = IWEVCUSTOM;
+	iwe.u.data.length = snprintf(custom, MAX_CUSTOM_LEN,
+				     " Last beacon: %dms ago",
+				     jiffies_to_msecs(jiffies - last_scanned));
+	if (iwe.u.data.length)
+		current_ev = iwe_stream_add_point(info, current_ev, end_buf,
+						  &iwe, custom);
+
+	return current_ev;
+}
+
+static inline char *orinoco_translate_ext_scan(struct net_device *dev,
+					       struct iw_request_info *info,
+					       char *current_ev,
+					       char *end_buf,
+					       struct agere_ext_scan_info *bss,
+					       unsigned int last_scanned)
+{
+	u16			capabilities;
+	u16			channel;
+	struct iw_event		iwe;		/* Temporary buffer */
+	char custom[MAX_CUSTOM_LEN];
+	u8 *ie;
+
+	memset(&iwe, 0, sizeof(iwe));
+
+	/* First entry *MUST* be the AP MAC address */
+	iwe.cmd = SIOCGIWAP;
+	iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
+	memcpy(iwe.u.ap_addr.sa_data, bss->bssid, ETH_ALEN);
+	current_ev = iwe_stream_add_event(info, current_ev, end_buf,
+					  &iwe, IW_EV_ADDR_LEN);
+
+	/* Other entries will be displayed in the order we give them */
+
+	/* Add the ESSID */
+	ie = bss->data;
+	iwe.u.data.length = ie[1];
+	if (iwe.u.data.length) {
+		if (iwe.u.data.length > 32)
+			iwe.u.data.length = 32;
+		iwe.cmd = SIOCGIWESSID;
+		iwe.u.data.flags = 1;
+		current_ev = iwe_stream_add_point(info, current_ev, end_buf,
+						  &iwe, &ie[2]);
+	}
+
+	/* Add mode */
+	capabilities = le16_to_cpu(bss->capabilities);
+	if (capabilities & (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS)) {
+		iwe.cmd = SIOCGIWMODE;
+		if (capabilities & WLAN_CAPABILITY_ESS)
+			iwe.u.mode = IW_MODE_MASTER;
+		else
+			iwe.u.mode = IW_MODE_ADHOC;
+		current_ev = iwe_stream_add_event(info, current_ev, end_buf,
+						  &iwe, IW_EV_UINT_LEN);
+	}
+
+	ie = orinoco_get_ie(bss->data, sizeof(bss->data), MFIE_TYPE_DS_SET);
+	channel = ie ? ie[2] : 0;
+	if ((channel >= 1) && (channel <= NUM_CHANNELS)) {
+		/* Add channel and frequency */
+		iwe.cmd = SIOCGIWFREQ;
+		iwe.u.freq.m = channel;
+		iwe.u.freq.e = 0;
+		current_ev = iwe_stream_add_event(info, current_ev, end_buf,
+						  &iwe, IW_EV_FREQ_LEN);
+
+		iwe.u.freq.m = channel_frequency[channel-1] * 100000;
+		iwe.u.freq.e = 1;
+		current_ev = iwe_stream_add_event(info, current_ev, end_buf,
+						  &iwe, IW_EV_FREQ_LEN);
+	}
+
+	/* Add quality statistics. level and noise in dB. No link quality */
+	iwe.cmd = IWEVQUAL;
+	iwe.u.qual.updated = IW_QUAL_DBM | IW_QUAL_QUAL_INVALID;
+	iwe.u.qual.level = bss->level - 0x95;
+	iwe.u.qual.noise = bss->noise - 0x95;
+	/* Wireless tools prior to 27.pre22 will show link quality
+	 * anyway, so we provide a reasonable value. */
+	if (iwe.u.qual.level > iwe.u.qual.noise)
+		iwe.u.qual.qual = iwe.u.qual.level - iwe.u.qual.noise;
+	else
+		iwe.u.qual.qual = 0;
+	current_ev = iwe_stream_add_event(info, current_ev, end_buf,
+					  &iwe, IW_EV_QUAL_LEN);
+
+	/* Add encryption capability */
+	iwe.cmd = SIOCGIWENCODE;
+	if (capabilities & WLAN_CAPABILITY_PRIVACY)
+		iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
+	else
+		iwe.u.data.flags = IW_ENCODE_DISABLED;
+	iwe.u.data.length = 0;
+	current_ev = iwe_stream_add_point(info, current_ev, end_buf,
+					  &iwe, NULL);
+
+	/* WPA IE */
+	ie = orinoco_get_wpa_ie(bss->data, sizeof(bss->data));
+	if (ie) {
+		iwe.cmd = IWEVGENIE;
+		iwe.u.data.length = ie[1] + 2;
+		current_ev = iwe_stream_add_point(info, current_ev, end_buf,
+						  &iwe, ie);
+	}
+
+	/* RSN IE */
+	ie = orinoco_get_ie(bss->data, sizeof(bss->data), MFIE_TYPE_RSN);
+	if (ie) {
+		iwe.cmd = IWEVGENIE;
+		iwe.u.data.length = ie[1] + 2;
+		current_ev = iwe_stream_add_point(info, current_ev, end_buf,
+						  &iwe, ie);
+	}
+
+	ie = orinoco_get_ie(bss->data, sizeof(bss->data), MFIE_TYPE_RATES);
+	if (ie) {
+		char *p = current_ev + iwe_stream_lcp_len(info);
+		int i;
+
+		iwe.cmd = SIOCGIWRATE;
+		/* Those two flags are ignored... */
+		iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
+
+		for (i = 2; i < (ie[1] + 2); i++) {
+			iwe.u.bitrate.value = ((ie[i] & 0x7F) * 500000);
+			p = iwe_stream_add_value(info, current_ev, p, end_buf,
+						 &iwe, IW_EV_PARAM_LEN);
+		}
+		/* Check if we added any event */
+		if (p > (current_ev + iwe_stream_lcp_len(info)))
+			current_ev = p;
+	}
+
+	/* Timestamp */
+	iwe.cmd = IWEVCUSTOM;
+	iwe.u.data.length =
+		snprintf(custom, MAX_CUSTOM_LEN, "tsf=%016llx",
+			 (unsigned long long) le64_to_cpu(bss->timestamp));
+	if (iwe.u.data.length)
+		current_ev = iwe_stream_add_point(info, current_ev, end_buf,
+						  &iwe, custom);
+
+	/* Beacon interval */
+	iwe.cmd = IWEVCUSTOM;
+	iwe.u.data.length = snprintf(custom, MAX_CUSTOM_LEN,
+				     "bcn_int=%d",
+				     le16_to_cpu(bss->beacon_interval));
+	if (iwe.u.data.length)
+		current_ev = iwe_stream_add_point(info, current_ev, end_buf,
+						  &iwe, custom);
+
+	/* Capabilites */
+	iwe.cmd = IWEVCUSTOM;
+	iwe.u.data.length = snprintf(custom, MAX_CUSTOM_LEN,
+				     "capab=0x%04x",
+				     capabilities);
+	if (iwe.u.data.length)
+		current_ev = iwe_stream_add_point(info, current_ev, end_buf,
+						  &iwe, custom);
+
+	/* Add EXTRA: Age to display seconds since last beacon/probe response
+	 * for given network. */
+	iwe.cmd = IWEVCUSTOM;
+	iwe.u.data.length = snprintf(custom, MAX_CUSTOM_LEN,
+				     " Last beacon: %dms ago",
+				     jiffies_to_msecs(jiffies - last_scanned));
+	if (iwe.u.data.length)
+		current_ev = iwe_stream_add_point(info, current_ev, end_buf,
+						  &iwe, custom);
+
 	return current_ev;
 }
 
@@ -4173,7 +5731,6 @@
 				 char *extra)
 {
 	struct orinoco_private *priv = netdev_priv(dev);
-	bss_element *bss;
 	int err = 0;
 	unsigned long flags;
 	char *current_ev = extra;
@@ -4193,18 +5750,47 @@
 		goto out;
 	}
 
-	list_for_each_entry(bss, &priv->bss_list, list) {
-		/* Translate to WE format this entry */
-		current_ev = orinoco_translate_scan(dev, info, current_ev,
-						    extra + srq->length,
-						    &bss->bss,
-						    bss->last_scanned);
+	if (priv->has_ext_scan) {
+		struct xbss_element *bss;
 
-		/* Check if there is space for one more entry */
-		if ((extra + srq->length - current_ev) <= IW_EV_ADDR_LEN) {
-			/* Ask user space to try again with a bigger buffer */
-			err = -E2BIG;
-			goto out;
+		list_for_each_entry(bss, &priv->bss_list, list) {
+			/* Translate this entry to WE format */
+			current_ev =
+				orinoco_translate_ext_scan(dev, info,
+							   current_ev,
+							   extra + srq->length,
+							   &bss->bss,
+							   bss->last_scanned);
+
+			/* Check if there is space for one more entry */
+			if ((extra + srq->length - current_ev)
+			    <= IW_EV_ADDR_LEN) {
+				/* Ask user space to try again with a
+				 * bigger buffer */
+				err = -E2BIG;
+				goto out;
+			}
+		}
+
+	} else {
+		struct bss_element *bss;
+
+		list_for_each_entry(bss, &priv->bss_list, list) {
+			/* Translate this entry to WE format */
+			current_ev = orinoco_translate_scan(dev, info,
+							    current_ev,
+							    extra + srq->length,
+							    &bss->bss,
+							    bss->last_scanned);
+
+			/* Check if there is space for one more entry */
+			if ((extra + srq->length - current_ev)
+			    <= IW_EV_ADDR_LEN) {
+				/* Ask user space to try again with a
+				 * bigger buffer */
+				err = -E2BIG;
+				goto out;
+			}
 		}
 	}
 
@@ -4295,39 +5881,48 @@
  * Structures to export the Wireless Handlers
  */
 
+#define STD_IW_HANDLER(id, func) \
+	[IW_IOCTL_IDX(id)] = (iw_handler) func
 static const iw_handler	orinoco_handler[] = {
-	[SIOCSIWCOMMIT-SIOCIWFIRST] = (iw_handler) orinoco_ioctl_commit,
-	[SIOCGIWNAME  -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_getname,
-	[SIOCSIWFREQ  -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_setfreq,
-	[SIOCGIWFREQ  -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_getfreq,
-	[SIOCSIWMODE  -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_setmode,
-	[SIOCGIWMODE  -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_getmode,
-	[SIOCSIWSENS  -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_setsens,
-	[SIOCGIWSENS  -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_getsens,
-	[SIOCGIWRANGE -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_getiwrange,
-	[SIOCSIWSPY   -SIOCIWFIRST] = (iw_handler) iw_handler_set_spy,
-	[SIOCGIWSPY   -SIOCIWFIRST] = (iw_handler) iw_handler_get_spy,
-	[SIOCSIWTHRSPY-SIOCIWFIRST] = (iw_handler) iw_handler_set_thrspy,
-	[SIOCGIWTHRSPY-SIOCIWFIRST] = (iw_handler) iw_handler_get_thrspy,
-	[SIOCSIWAP    -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_setwap,
-	[SIOCGIWAP    -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_getwap,
-	[SIOCSIWSCAN  -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_setscan,
-	[SIOCGIWSCAN  -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_getscan,
-	[SIOCSIWESSID -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_setessid,
-	[SIOCGIWESSID -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_getessid,
-	[SIOCSIWNICKN -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_setnick,
-	[SIOCGIWNICKN -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_getnick,
-	[SIOCSIWRATE  -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_setrate,
-	[SIOCGIWRATE  -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_getrate,
-	[SIOCSIWRTS   -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_setrts,
-	[SIOCGIWRTS   -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_getrts,
-	[SIOCSIWFRAG  -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_setfrag,
-	[SIOCGIWFRAG  -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_getfrag,
-	[SIOCGIWRETRY -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_getretry,
-	[SIOCSIWENCODE-SIOCIWFIRST] = (iw_handler) orinoco_ioctl_setiwencode,
-	[SIOCGIWENCODE-SIOCIWFIRST] = (iw_handler) orinoco_ioctl_getiwencode,
-	[SIOCSIWPOWER -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_setpower,
-	[SIOCGIWPOWER -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_getpower,
+	STD_IW_HANDLER(SIOCSIWCOMMIT,	orinoco_ioctl_commit),
+	STD_IW_HANDLER(SIOCGIWNAME,	orinoco_ioctl_getname),
+	STD_IW_HANDLER(SIOCSIWFREQ,	orinoco_ioctl_setfreq),
+	STD_IW_HANDLER(SIOCGIWFREQ,	orinoco_ioctl_getfreq),
+	STD_IW_HANDLER(SIOCSIWMODE,	orinoco_ioctl_setmode),
+	STD_IW_HANDLER(SIOCGIWMODE,	orinoco_ioctl_getmode),
+	STD_IW_HANDLER(SIOCSIWSENS,	orinoco_ioctl_setsens),
+	STD_IW_HANDLER(SIOCGIWSENS,	orinoco_ioctl_getsens),
+	STD_IW_HANDLER(SIOCGIWRANGE,	orinoco_ioctl_getiwrange),
+	STD_IW_HANDLER(SIOCSIWSPY,	iw_handler_set_spy),
+	STD_IW_HANDLER(SIOCGIWSPY,	iw_handler_get_spy),
+	STD_IW_HANDLER(SIOCSIWTHRSPY,	iw_handler_set_thrspy),
+	STD_IW_HANDLER(SIOCGIWTHRSPY,	iw_handler_get_thrspy),
+	STD_IW_HANDLER(SIOCSIWAP,	orinoco_ioctl_setwap),
+	STD_IW_HANDLER(SIOCGIWAP,	orinoco_ioctl_getwap),
+	STD_IW_HANDLER(SIOCSIWSCAN,	orinoco_ioctl_setscan),
+	STD_IW_HANDLER(SIOCGIWSCAN,	orinoco_ioctl_getscan),
+	STD_IW_HANDLER(SIOCSIWESSID,	orinoco_ioctl_setessid),
+	STD_IW_HANDLER(SIOCGIWESSID,	orinoco_ioctl_getessid),
+	STD_IW_HANDLER(SIOCSIWNICKN,	orinoco_ioctl_setnick),
+	STD_IW_HANDLER(SIOCGIWNICKN,	orinoco_ioctl_getnick),
+	STD_IW_HANDLER(SIOCSIWRATE,	orinoco_ioctl_setrate),
+	STD_IW_HANDLER(SIOCGIWRATE,	orinoco_ioctl_getrate),
+	STD_IW_HANDLER(SIOCSIWRTS,	orinoco_ioctl_setrts),
+	STD_IW_HANDLER(SIOCGIWRTS,	orinoco_ioctl_getrts),
+	STD_IW_HANDLER(SIOCSIWFRAG,	orinoco_ioctl_setfrag),
+	STD_IW_HANDLER(SIOCGIWFRAG,	orinoco_ioctl_getfrag),
+	STD_IW_HANDLER(SIOCGIWRETRY,	orinoco_ioctl_getretry),
+	STD_IW_HANDLER(SIOCSIWENCODE,	orinoco_ioctl_setiwencode),
+	STD_IW_HANDLER(SIOCGIWENCODE,	orinoco_ioctl_getiwencode),
+	STD_IW_HANDLER(SIOCSIWPOWER,	orinoco_ioctl_setpower),
+	STD_IW_HANDLER(SIOCGIWPOWER,	orinoco_ioctl_getpower),
+	STD_IW_HANDLER(SIOCSIWGENIE,	orinoco_ioctl_set_genie),
+	STD_IW_HANDLER(SIOCGIWGENIE,	orinoco_ioctl_get_genie),
+	STD_IW_HANDLER(SIOCSIWMLME,	orinoco_ioctl_set_mlme),
+	STD_IW_HANDLER(SIOCSIWAUTH,	orinoco_ioctl_set_auth),
+	STD_IW_HANDLER(SIOCGIWAUTH,	orinoco_ioctl_get_auth),
+	STD_IW_HANDLER(SIOCSIWENCODEEXT, orinoco_ioctl_set_encodeext),
+	STD_IW_HANDLER(SIOCGIWENCODEEXT, orinoco_ioctl_get_encodeext),
 };
 
 
diff --git a/drivers/net/wireless/orinoco.h b/drivers/net/wireless/orinoco.h
index c6b1858..981570b 100644
--- a/drivers/net/wireless/orinoco.h
+++ b/drivers/net/wireless/orinoco.h
@@ -9,6 +9,7 @@
 
 #define DRIVER_VERSION "0.15"
 
+#include <linux/interrupt.h>
 #include <linux/netdevice.h>
 #include <linux/wireless.h>
 #include <net/iw_handler.h>
@@ -30,27 +31,57 @@
 	char data[ORINOCO_MAX_KEY_SIZE];
 } __attribute__ ((packed));
 
+#define TKIP_KEYLEN	16
+#define MIC_KEYLEN	8
+
+struct orinoco_tkip_key {
+	u8 tkip[TKIP_KEYLEN];
+	u8 tx_mic[MIC_KEYLEN];
+	u8 rx_mic[MIC_KEYLEN];
+};
+
 typedef enum {
 	FIRMWARE_TYPE_AGERE,
 	FIRMWARE_TYPE_INTERSIL,
 	FIRMWARE_TYPE_SYMBOL
 } fwtype_t;
 
-typedef struct {
+struct bss_element {
 	union hermes_scan_info bss;
 	unsigned long last_scanned;
 	struct list_head list;
-} bss_element;
+};
+
+struct xbss_element {
+	struct agere_ext_scan_info bss;
+	unsigned long last_scanned;
+	struct list_head list;
+};
+
+struct hermes_rx_descriptor;
+
+struct orinoco_rx_data {
+	struct hermes_rx_descriptor *desc;
+	struct sk_buff *skb;
+	struct list_head list;
+};
 
 struct orinoco_private {
 	void *card;	/* Pointer to card dependent structure */
+	struct device *dev;
 	int (*hard_reset)(struct orinoco_private *);
+	int (*stop_fw)(struct orinoco_private *, int);
 
 	/* Synchronisation stuff */
 	spinlock_t lock;
 	int hw_unavailable;
 	struct work_struct reset_work;
 
+	/* Interrupt tasklets */
+	struct tasklet_struct rx_tasklet;
+	struct list_head rx_list;
+	struct orinoco_rx_data *rx_data;
+
 	/* driver state */
 	int open;
 	u16 last_linkstatus;
@@ -83,13 +114,17 @@
 	unsigned int has_preamble:1;
 	unsigned int has_sensitivity:1;
 	unsigned int has_hostscan:1;
+	unsigned int has_alt_txcntl:1;
+	unsigned int has_ext_scan:1;
+	unsigned int has_wpa:1;
+	unsigned int do_fw_download:1;
 	unsigned int broken_disableport:1;
 	unsigned int broken_monitor:1;
 
 	/* Configuration paramaters */
 	u32 iw_mode;
 	int prefer_port3;
-	u16 wep_on, wep_restrict, tx_key;
+	u16 encode_alg, wep_restrict, tx_key;
 	struct orinoco_key keys[ORINOCO_MAX_KEYS];
 	int bitratemode;
  	char nick[IW_ESSID_MAX_SIZE+1];
@@ -113,10 +148,22 @@
 	/* Scanning support */
 	struct list_head bss_list;
 	struct list_head bss_free_list;
-	bss_element *bss_data;
+	void *bss_xbss_data;
 
 	int	scan_inprogress;	/* Scan pending... */
 	u32	scan_mode;		/* Type of scan done */
+
+	/* WPA support */
+	u8 *wpa_ie;
+	int wpa_ie_len;
+
+	struct orinoco_tkip_key tkip_key[ORINOCO_MAX_KEYS];
+	struct crypto_hash *rx_tfm_mic;
+	struct crypto_hash *tx_tfm_mic;
+
+	unsigned int wpa_enabled:1;
+	unsigned int tkip_cm_active:1;
+	unsigned int key_mgmt:3;
 };
 
 #ifdef ORINOCO_DEBUG
@@ -130,8 +177,10 @@
 /* Exported prototypes                                              */
 /********************************************************************/
 
-extern struct net_device *alloc_orinocodev(int sizeof_card,
-					   int (*hard_reset)(struct orinoco_private *));
+extern struct net_device *alloc_orinocodev(
+	int sizeof_card, struct device *device,
+	int (*hard_reset)(struct orinoco_private *),
+	int (*stop_fw)(struct orinoco_private *, int));
 extern void free_orinocodev(struct net_device *dev);
 extern int __orinoco_up(struct net_device *dev);
 extern int __orinoco_down(struct net_device *dev);
diff --git a/drivers/net/wireless/orinoco_cs.c b/drivers/net/wireless/orinoco_cs.c
index 1c216e0..e585684 100644
--- a/drivers/net/wireless/orinoco_cs.c
+++ b/drivers/net/wireless/orinoco_cs.c
@@ -80,7 +80,7 @@
 	/* We need atomic ops here, because we're not holding the lock */
 	set_bit(0, &card->hard_reset_in_progress);
 
-	err = pcmcia_reset_card(link, NULL);
+	err = pcmcia_reset_card(link->socket);
 	if (err)
 		return err;
 
@@ -109,7 +109,8 @@
 	struct orinoco_private *priv;
 	struct orinoco_pccard *card;
 
-	dev = alloc_orinocodev(sizeof(*card), orinoco_cs_hard_reset);
+	dev = alloc_orinocodev(sizeof(*card), &handle_to_dev(link),
+			       orinoco_cs_hard_reset, NULL);
 	if (! dev)
 		return -ENOMEM;
 	priv = netdev_priv(dev);
@@ -120,7 +121,7 @@
 	link->priv = dev;
 
 	/* Interrupt setup */
-	link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT;
+	link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING | IRQ_HANDLE_PRESENT;
 	link->irq.IRQInfo1 = IRQ_LEVEL_ID;
 	link->irq.Handler = orinoco_interrupt;
 	link->irq.Instance = dev; 
@@ -164,6 +165,70 @@
 		last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; \
 	} while (0)
 
+static int orinoco_cs_config_check(struct pcmcia_device *p_dev,
+				   cistpl_cftable_entry_t *cfg,
+				   cistpl_cftable_entry_t *dflt,
+				   unsigned int vcc,
+				   void *priv_data)
+{
+	if (cfg->index == 0)
+		goto next_entry;
+
+	/* Use power settings for Vcc and Vpp if present */
+	/* Note that the CIS values need to be rescaled */
+	if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) {
+		if (vcc != cfg->vcc.param[CISTPL_POWER_VNOM] / 10000) {
+			DEBUG(2, "spectrum_cs_config: Vcc mismatch (vcc = %d, CIS = %d)\n",  vcc, cfg->vcc.param[CISTPL_POWER_VNOM] / 10000);
+			if (!ignore_cis_vcc)
+				goto next_entry;
+		}
+	} else if (dflt->vcc.present & (1 << CISTPL_POWER_VNOM)) {
+		if (vcc != dflt->vcc.param[CISTPL_POWER_VNOM] / 10000) {
+			DEBUG(2, "spectrum_cs_config: Vcc mismatch (vcc = %d, CIS = %d)\n",  vcc, dflt->vcc.param[CISTPL_POWER_VNOM] / 10000);
+			if (!ignore_cis_vcc)
+				goto next_entry;
+		}
+	}
+
+	if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM))
+		p_dev->conf.Vpp =
+			cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000;
+	else if (dflt->vpp1.present & (1 << CISTPL_POWER_VNOM))
+		p_dev->conf.Vpp =
+			dflt->vpp1.param[CISTPL_POWER_VNOM] / 10000;
+
+	/* Do we need to allocate an interrupt? */
+	p_dev->conf.Attributes |= CONF_ENABLE_IRQ;
+
+	/* IO window settings */
+	p_dev->io.NumPorts1 = p_dev->io.NumPorts2 = 0;
+	if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) {
+		cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io;
+		p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
+		if (!(io->flags & CISTPL_IO_8BIT))
+			p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_16;
+		if (!(io->flags & CISTPL_IO_16BIT))
+			p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
+		p_dev->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK;
+		p_dev->io.BasePort1 = io->win[0].base;
+		p_dev->io.NumPorts1 = io->win[0].len;
+		if (io->nwin > 1) {
+			p_dev->io.Attributes2 = p_dev->io.Attributes1;
+			p_dev->io.BasePort2 = io->win[1].base;
+			p_dev->io.NumPorts2 = io->win[1].len;
+		}
+
+		/* This reserves IO space but doesn't actually enable it */
+		if (pcmcia_request_io(p_dev, &p_dev->io) != 0)
+			goto next_entry;
+	}
+	return 0;
+
+next_entry:
+	pcmcia_disable_device(p_dev);
+	return -ENODEV;
+};
+
 static int
 orinoco_cs_config(struct pcmcia_device *link)
 {
@@ -172,16 +237,8 @@
 	struct orinoco_pccard *card = priv->card;
 	hermes_t *hw = &priv->hw;
 	int last_fn, last_ret;
-	u_char buf[64];
-	config_info_t conf;
-	tuple_t tuple;
-	cisparse_t parse;
 	void __iomem *mem;
 
-	/* Look up the current Vcc */
-	CS_CHECK(GetConfigurationInfo,
-		 pcmcia_get_configuration_info(link, &conf));
-
 	/*
 	 * In this loop, we scan the CIS for configuration table
 	 * entries, each of which describes a valid card
@@ -196,94 +253,14 @@
 	 * and most client drivers will only use the CIS to fill in
 	 * implementation-defined details.
 	 */
-	tuple.Attributes = 0;
-	tuple.TupleData = buf;
-	tuple.TupleDataMax = sizeof(buf);
-	tuple.TupleOffset = 0;
-	tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
-	CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple));
-	while (1) {
-		cistpl_cftable_entry_t *cfg = &(parse.cftable_entry);
-		cistpl_cftable_entry_t dflt = { .index = 0 };
-
-		if ( (pcmcia_get_tuple_data(link, &tuple) != 0)
-		    || (pcmcia_parse_tuple(link, &tuple, &parse) != 0))
-			goto next_entry;
-
-		if (cfg->flags & CISTPL_CFTABLE_DEFAULT)
-			dflt = *cfg;
-		if (cfg->index == 0)
-			goto next_entry;
-		link->conf.ConfigIndex = cfg->index;
-
-		/* Use power settings for Vcc and Vpp if present */
-		/* Note that the CIS values need to be rescaled */
-		if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) {
-			if (conf.Vcc != cfg->vcc.param[CISTPL_POWER_VNOM] / 10000) {
-				DEBUG(2, "orinoco_cs_config: Vcc mismatch (conf.Vcc = %d, cfg CIS = %d)\n",  conf.Vcc, cfg->vcc.param[CISTPL_POWER_VNOM] / 10000);
-				if (!ignore_cis_vcc)
-					goto next_entry;
-			}
-		} else if (dflt.vcc.present & (1 << CISTPL_POWER_VNOM)) {
-			if (conf.Vcc != dflt.vcc.param[CISTPL_POWER_VNOM] / 10000) {
-				DEBUG(2, "orinoco_cs_config: Vcc mismatch (conf.Vcc = %d, dflt CIS = %d)\n",  conf.Vcc, dflt.vcc.param[CISTPL_POWER_VNOM] / 10000);
-				if(!ignore_cis_vcc)
-					goto next_entry;
-			}
-		}
-
-		if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM))
-			link->conf.Vpp =
-			    cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000;
-		else if (dflt.vpp1.present & (1 << CISTPL_POWER_VNOM))
-			link->conf.Vpp =
-			    dflt.vpp1.param[CISTPL_POWER_VNOM] / 10000;
-		
-		/* Do we need to allocate an interrupt? */
-		link->conf.Attributes |= CONF_ENABLE_IRQ;
-
-		/* IO window settings */
-		link->io.NumPorts1 = link->io.NumPorts2 = 0;
-		if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) {
-			cistpl_io_t *io =
-			    (cfg->io.nwin) ? &cfg->io : &dflt.io;
-			link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
-			if (!(io->flags & CISTPL_IO_8BIT))
-				link->io.Attributes1 =
-				    IO_DATA_PATH_WIDTH_16;
-			if (!(io->flags & CISTPL_IO_16BIT))
-				link->io.Attributes1 =
-				    IO_DATA_PATH_WIDTH_8;
-			link->io.IOAddrLines =
-			    io->flags & CISTPL_IO_LINES_MASK;
-			link->io.BasePort1 = io->win[0].base;
-			link->io.NumPorts1 = io->win[0].len;
-			if (io->nwin > 1) {
-				link->io.Attributes2 =
-				    link->io.Attributes1;
-				link->io.BasePort2 = io->win[1].base;
-				link->io.NumPorts2 = io->win[1].len;
-			}
-
-			/* This reserves IO space but doesn't actually enable it */
-			if (pcmcia_request_io(link, &link->io) != 0)
-				goto next_entry;
-		}
-
-
-		/* If we got this far, we're cool! */
-
-		break;
-		
-	next_entry:
-		pcmcia_disable_device(link);
-		last_ret = pcmcia_get_next_tuple(link, &tuple);
-		if (last_ret  == CS_NO_MORE_ITEMS) {
+	last_ret = pcmcia_loop_config(link, orinoco_cs_config_check, NULL);
+	if (last_ret) {
+		if (!ignore_cis_vcc)
 			printk(KERN_ERR PFX "GetNextTuple(): No matching "
 			       "CIS configuration.  Maybe you need the "
 			       "ignore_cis_vcc=1 parameter.\n");
-			goto cs_failed;
-		}
+		cs_error(link, RequestIO, last_ret);
+		goto failed;
 	}
 
 	/*
@@ -334,7 +311,6 @@
 	       "0x%04x-0x%04x\n", dev->name, dev->dev.parent->bus_id,
 	       link->irq.AssignedIRQ, link->io.BasePort1,
 	       link->io.BasePort1 + link->io.NumPorts1 - 1);
-
 	return 0;
 
  cs_failed:
diff --git a/drivers/net/wireless/orinoco_nortel.c b/drivers/net/wireless/orinoco_nortel.c
index 35ec5fc..2fc8659 100644
--- a/drivers/net/wireless/orinoco_nortel.c
+++ b/drivers/net/wireless/orinoco_nortel.c
@@ -182,7 +182,8 @@
 	}
 
 	/* Allocate network device */
-	dev = alloc_orinocodev(sizeof(*card), orinoco_nortel_cor_reset);
+	dev = alloc_orinocodev(sizeof(*card), &pdev->dev,
+			       orinoco_nortel_cor_reset, NULL);
 	if (!dev) {
 		printk(KERN_ERR PFX "Cannot allocate network device\n");
 		err = -ENOMEM;
diff --git a/drivers/net/wireless/orinoco_pci.c b/drivers/net/wireless/orinoco_pci.c
index 2547d5d..4ebd638 100644
--- a/drivers/net/wireless/orinoco_pci.c
+++ b/drivers/net/wireless/orinoco_pci.c
@@ -139,7 +139,8 @@
 	}
 
 	/* Allocate network device */
-	dev = alloc_orinocodev(sizeof(*card), orinoco_pci_cor_reset);
+	dev = alloc_orinocodev(sizeof(*card), &pdev->dev,
+			       orinoco_pci_cor_reset, NULL);
 	if (!dev) {
 		printk(KERN_ERR PFX "Cannot allocate network device\n");
 		err = -ENOMEM;
diff --git a/drivers/net/wireless/orinoco_plx.c b/drivers/net/wireless/orinoco_plx.c
index 98fe165..ef76185 100644
--- a/drivers/net/wireless/orinoco_plx.c
+++ b/drivers/net/wireless/orinoco_plx.c
@@ -221,7 +221,8 @@
 	}
 
 	/* Allocate network device */
-	dev = alloc_orinocodev(sizeof(*card), orinoco_plx_cor_reset);
+	dev = alloc_orinocodev(sizeof(*card), &pdev->dev,
+			       orinoco_plx_cor_reset, NULL);
 	if (!dev) {
 		printk(KERN_ERR PFX "Cannot allocate network device\n");
 		err = -ENOMEM;
diff --git a/drivers/net/wireless/orinoco_tmd.c b/drivers/net/wireless/orinoco_tmd.c
index df49318..ede24ec 100644
--- a/drivers/net/wireless/orinoco_tmd.c
+++ b/drivers/net/wireless/orinoco_tmd.c
@@ -124,7 +124,8 @@
 	}
 
 	/* Allocate network device */
-	dev = alloc_orinocodev(sizeof(*card), orinoco_tmd_cor_reset);
+	dev = alloc_orinocodev(sizeof(*card), &pdev->dev,
+			       orinoco_tmd_cor_reset, NULL);
 	if (!dev) {
 		printk(KERN_ERR PFX "Cannot allocate network device\n");
 		err = -ENOMEM;
diff --git a/drivers/net/wireless/p54/p54.h b/drivers/net/wireless/p54/p54.h
index 4801a36..1d0704f 100644
--- a/drivers/net/wireless/p54/p54.h
+++ b/drivers/net/wireless/p54/p54.h
@@ -1,5 +1,5 @@
-#ifndef PRISM54_H
-#define PRISM54_H
+#ifndef P54_H
+#define P54_H
 
 /*
  * Shared defines for all mac80211 Prism54 code
@@ -19,13 +19,24 @@
 	P54_CONTROL_TYPE_CHANNEL_CHANGE,
 	P54_CONTROL_TYPE_FREQDONE,
 	P54_CONTROL_TYPE_DCFINIT,
-	P54_CONTROL_TYPE_FREEQUEUE = 7,
+	P54_CONTROL_TYPE_ENCRYPTION,
+	P54_CONTROL_TYPE_TIM,
+	P54_CONTROL_TYPE_POWERMGT,
+	P54_CONTROL_TYPE_FREEQUEUE,
 	P54_CONTROL_TYPE_TXDONE,
 	P54_CONTROL_TYPE_PING,
 	P54_CONTROL_TYPE_STAT_READBACK,
 	P54_CONTROL_TYPE_BBP,
 	P54_CONTROL_TYPE_EEPROM_READBACK,
-	P54_CONTROL_TYPE_LED
+	P54_CONTROL_TYPE_LED,
+	P54_CONTROL_TYPE_GPIO,
+	P54_CONTROL_TYPE_TIMER,
+	P54_CONTROL_TYPE_MODULATION,
+	P54_CONTROL_TYPE_SYNTH_CONFIG,
+	P54_CONTROL_TYPE_DETECTOR_VALUE,
+	P54_CONTROL_TYPE_XBOW_SYNTH_CFG,
+	P54_CONTROL_TYPE_CCE_QUIET,
+	P54_CONTROL_TYPE_PSM_STA_UNLOCK,
 };
 
 struct p54_control_hdr {
@@ -38,11 +49,15 @@
 	u8 data[0];
 } __attribute__ ((packed));
 
-#define EEPROM_READBACK_LEN (sizeof(struct p54_control_hdr) + 4 /* p54_eeprom_lm86 */)
-#define MAX_RX_SIZE (IEEE80211_MAX_RTS_THRESHOLD + sizeof(struct p54_control_hdr) + 20 /* length of struct p54_rx_hdr */ + 16 )
+#define EEPROM_READBACK_LEN 0x3fc
 
 #define ISL38XX_DEV_FIRMWARE_ADDR 0x20000
 
+#define FW_FMAC 0x464d4143
+#define FW_LM86 0x4c4d3836
+#define FW_LM87 0x4c4d3837
+#define FW_LM20 0x4c4d3230
+
 struct p54_common {
 	u32 rx_start;
 	u32 rx_end;
@@ -53,27 +68,43 @@
 	void (*stop)(struct ieee80211_hw *dev);
 	int mode;
 	u16 seqno;
+	u16 rx_mtu;
+	u8 headroom;
+	u8 tailroom;
 	struct mutex conf_mutex;
 	u8 mac_addr[ETH_ALEN];
 	u8 bssid[ETH_ALEN];
+	__le16 filter_type;
 	struct pda_iq_autocal_entry *iq_autocal;
 	unsigned int iq_autocal_len;
 	struct pda_channel_output_limit *output_limit;
 	unsigned int output_limit_len;
 	struct pda_pa_curve_data *curve_data;
-	__le16 rxhw;
+	unsigned int filter_flags;
+	u16 rxhw;
 	u8 version;
+	u8 rx_antenna;
 	unsigned int tx_hdr_len;
 	void *cached_vdcf;
 	unsigned int fw_var;
-	struct ieee80211_tx_queue_stats tx_stats[4];
+	unsigned int fw_interface;
+	unsigned int output_power;
+	u32 tsf_low32;
+	u32 tsf_high32;
+	struct ieee80211_tx_queue_stats tx_stats[8];
+	struct ieee80211_low_level_stats stats;
+	struct timer_list stats_timer;
+	struct completion stats_comp;
+	void *cached_stats;
+	int noise;
+	void *eeprom;
+	struct completion eeprom_comp;
 };
 
 int p54_rx(struct ieee80211_hw *dev, struct sk_buff *skb);
-void p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw);
-int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len);
-void p54_fill_eeprom_readback(struct p54_control_hdr *hdr);
+int p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw);
+int p54_read_eeprom(struct ieee80211_hw *dev);
 struct ieee80211_hw *p54_init_common(size_t priv_data_len);
 void p54_free_common(struct ieee80211_hw *dev);
 
-#endif /* PRISM54_H */
+#endif /* P54_H */
diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c
index 29be3dc..1994aa1 100644
--- a/drivers/net/wireless/p54/p54common.c
+++ b/drivers/net/wireless/p54/p54common.c
@@ -27,7 +27,7 @@
 MODULE_LICENSE("GPL");
 MODULE_ALIAS("prism54common");
 
-static struct ieee80211_rate p54_rates[] = {
+static struct ieee80211_rate p54_bgrates[] = {
 	{ .bitrate = 10, .hw_value = 0, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
 	{ .bitrate = 20, .hw_value = 1, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
 	{ .bitrate = 55, .hw_value = 2, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
@@ -42,7 +42,7 @@
 	{ .bitrate = 540, .hw_value = 11, },
 };
 
-static struct ieee80211_channel p54_channels[] = {
+static struct ieee80211_channel p54_bgchannels[] = {
 	{ .center_freq = 2412, .hw_value = 1, },
 	{ .center_freq = 2417, .hw_value = 2, },
 	{ .center_freq = 2422, .hw_value = 3, },
@@ -60,14 +60,69 @@
 };
 
 static struct ieee80211_supported_band band_2GHz = {
-	.channels = p54_channels,
-	.n_channels = ARRAY_SIZE(p54_channels),
-	.bitrates = p54_rates,
-	.n_bitrates = ARRAY_SIZE(p54_rates),
+	.channels = p54_bgchannels,
+	.n_channels = ARRAY_SIZE(p54_bgchannels),
+	.bitrates = p54_bgrates,
+	.n_bitrates = ARRAY_SIZE(p54_bgrates),
 };
 
+static struct ieee80211_rate p54_arates[] = {
+	{ .bitrate = 60, .hw_value = 4, },
+	{ .bitrate = 90, .hw_value = 5, },
+	{ .bitrate = 120, .hw_value = 6, },
+	{ .bitrate = 180, .hw_value = 7, },
+	{ .bitrate = 240, .hw_value = 8, },
+	{ .bitrate = 360, .hw_value = 9, },
+	{ .bitrate = 480, .hw_value = 10, },
+	{ .bitrate = 540, .hw_value = 11, },
+};
 
-void p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw)
+static struct ieee80211_channel p54_achannels[] = {
+	{ .center_freq = 4920 },
+	{ .center_freq = 4940 },
+	{ .center_freq = 4960 },
+	{ .center_freq = 4980 },
+	{ .center_freq = 5040 },
+	{ .center_freq = 5060 },
+	{ .center_freq = 5080 },
+	{ .center_freq = 5170 },
+	{ .center_freq = 5180 },
+	{ .center_freq = 5190 },
+	{ .center_freq = 5200 },
+	{ .center_freq = 5210 },
+	{ .center_freq = 5220 },
+	{ .center_freq = 5230 },
+	{ .center_freq = 5240 },
+	{ .center_freq = 5260 },
+	{ .center_freq = 5280 },
+	{ .center_freq = 5300 },
+	{ .center_freq = 5320 },
+	{ .center_freq = 5500 },
+	{ .center_freq = 5520 },
+	{ .center_freq = 5540 },
+	{ .center_freq = 5560 },
+	{ .center_freq = 5580 },
+	{ .center_freq = 5600 },
+	{ .center_freq = 5620 },
+	{ .center_freq = 5640 },
+	{ .center_freq = 5660 },
+	{ .center_freq = 5680 },
+	{ .center_freq = 5700 },
+	{ .center_freq = 5745 },
+	{ .center_freq = 5765 },
+	{ .center_freq = 5785 },
+	{ .center_freq = 5805 },
+	{ .center_freq = 5825 },
+};
+
+static struct ieee80211_supported_band band_5GHz = {
+	.channels = p54_achannels,
+	.n_channels = ARRAY_SIZE(p54_achannels),
+	.bitrates = p54_arates,
+	.n_bitrates = ARRAY_SIZE(p54_arates),
+};
+
+int p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw)
 {
 	struct p54_common *priv = dev->priv;
 	struct bootrec_exp_if *exp_if;
@@ -79,7 +134,7 @@
 	int i;
 
 	if (priv->rx_start)
-		return;
+		return 0;
 
 	while (data < end_data && *data)
 		data++;
@@ -94,7 +149,9 @@
 		u32 code = le32_to_cpu(bootrec->code);
 		switch (code) {
 		case BR_CODE_COMPONENT_ID:
-			switch (be32_to_cpu(*(__be32 *)bootrec->data)) {
+			priv->fw_interface = be32_to_cpup((__be32 *)
+					     bootrec->data);
+			switch (priv->fw_interface) {
 			case FW_FMAC:
 				printk(KERN_INFO "p54: FreeMAC firmware\n");
 				break;
@@ -105,7 +162,7 @@
 				printk(KERN_INFO "p54: LM86 firmware\n");
 				break;
 			case FW_LM87:
-				printk(KERN_INFO "p54: LM87 firmware - not supported yet!\n");
+				printk(KERN_INFO "p54: LM87 firmware\n");
 				break;
 			default:
 				printk(KERN_INFO "p54: unknown firmware\n");
@@ -117,11 +174,21 @@
 			if (strnlen((unsigned char*)bootrec->data, 24) < 24)
 				fw_version = (unsigned char*)bootrec->data;
 			break;
-		case BR_CODE_DESCR:
-			priv->rx_start = le32_to_cpu(((__le32 *)bootrec->data)[1]);
+		case BR_CODE_DESCR: {
+			struct bootrec_desc *desc =
+				(struct bootrec_desc *)bootrec->data;
+			priv->rx_start = le32_to_cpu(desc->rx_start);
 			/* FIXME add sanity checking */
-			priv->rx_end = le32_to_cpu(((__le32 *)bootrec->data)[2]) - 0x3500;
+			priv->rx_end = le32_to_cpu(desc->rx_end) - 0x3500;
+			priv->headroom = desc->headroom;
+			priv->tailroom = desc->tailroom;
+			if (le32_to_cpu(bootrec->len) == 11)
+				priv->rx_mtu = le16_to_cpu(bootrec->rx_mtu);
+			else
+				priv->rx_mtu = (size_t)
+					0x620 - priv->tx_hdr_len;
 			break;
+			}
 		case BR_CODE_EXPOSED_IF:
 			exp_if = (struct bootrec_exp_if *) bootrec->data;
 			for (i = 0; i < (len * sizeof(*exp_if) / 4); i++)
@@ -146,23 +213,25 @@
 
 	if (priv->fw_var >= 0x300) {
 		/* Firmware supports QoS, use it! */
-		priv->tx_stats[0].limit = 3;
-		priv->tx_stats[1].limit = 4;
-		priv->tx_stats[2].limit = 3;
-		priv->tx_stats[3].limit = 1;
+		priv->tx_stats[4].limit = 3;
+		priv->tx_stats[5].limit = 4;
+		priv->tx_stats[6].limit = 3;
+		priv->tx_stats[7].limit = 1;
 		dev->queues = 4;
 	}
+
+	return 0;
 }
 EXPORT_SYMBOL_GPL(p54_parse_firmware);
 
-static int p54_convert_rev0_to_rev1(struct ieee80211_hw *dev,
-				    struct pda_pa_curve_data *curve_data)
+static int p54_convert_rev0(struct ieee80211_hw *dev,
+			    struct pda_pa_curve_data *curve_data)
 {
 	struct p54_common *priv = dev->priv;
-	struct pda_pa_curve_data_sample_rev1 *rev1;
-	struct pda_pa_curve_data_sample_rev0 *rev0;
+	struct p54_pa_curve_data_sample *dst;
+	struct pda_pa_curve_data_sample_rev0 *src;
 	size_t cd_len = sizeof(*curve_data) +
-		(curve_data->points_per_channel*sizeof(*rev1) + 2) *
+		(curve_data->points_per_channel*sizeof(*dst) + 2) *
 		 curve_data->channels;
 	unsigned int i, j;
 	void *source, *target;
@@ -180,28 +249,68 @@
 		*((__le16 *)target) = *freq;
 		target += sizeof(__le16);
 		for (j = 0; j < curve_data->points_per_channel; j++) {
-			rev1 = target;
-			rev0 = source;
+			dst = target;
+			src = source;
 
-			rev1->rf_power = rev0->rf_power;
-			rev1->pa_detector = rev0->pa_detector;
-			rev1->data_64qam = rev0->pcv;
+			dst->rf_power = src->rf_power;
+			dst->pa_detector = src->pa_detector;
+			dst->data_64qam = src->pcv;
 			/* "invent" the points for the other modulations */
 #define SUB(x,y) (u8)((x) - (y)) > (x) ? 0 : (x) - (y)
-			rev1->data_16qam = SUB(rev0->pcv, 12);
-			rev1->data_qpsk  = SUB(rev1->data_16qam, 12);
-			rev1->data_bpsk  = SUB(rev1->data_qpsk, 12);
-			rev1->data_barker= SUB(rev1->data_bpsk, 14);
+			dst->data_16qam = SUB(src->pcv, 12);
+			dst->data_qpsk = SUB(dst->data_16qam, 12);
+			dst->data_bpsk = SUB(dst->data_qpsk, 12);
+			dst->data_barker = SUB(dst->data_bpsk, 14);
 #undef SUB
-			target += sizeof(*rev1);
-			source += sizeof(*rev0);
+			target += sizeof(*dst);
+			source += sizeof(*src);
 		}
 	}
 
 	return 0;
 }
 
-int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len)
+static int p54_convert_rev1(struct ieee80211_hw *dev,
+			    struct pda_pa_curve_data *curve_data)
+{
+	struct p54_common *priv = dev->priv;
+	struct p54_pa_curve_data_sample *dst;
+	struct pda_pa_curve_data_sample_rev1 *src;
+	size_t cd_len = sizeof(*curve_data) +
+		(curve_data->points_per_channel*sizeof(*dst) + 2) *
+		 curve_data->channels;
+	unsigned int i, j;
+	void *source, *target;
+
+	priv->curve_data = kmalloc(cd_len, GFP_KERNEL);
+	if (!priv->curve_data)
+		return -ENOMEM;
+
+	memcpy(priv->curve_data, curve_data, sizeof(*curve_data));
+	source = curve_data->data;
+	target = priv->curve_data->data;
+	for (i = 0; i < curve_data->channels; i++) {
+		__le16 *freq = source;
+		source += sizeof(__le16);
+		*((__le16 *)target) = *freq;
+		target += sizeof(__le16);
+		for (j = 0; j < curve_data->points_per_channel; j++) {
+			memcpy(target, source, sizeof(*src));
+
+			target += sizeof(*dst);
+			source += sizeof(*src);
+		}
+		source++;
+	}
+
+	return 0;
+}
+
+static const char *p54_rf_chips[] = { "NULL", "Indigo?", "Duette",
+                              "Frisbee", "Xbow", "Longbow" };
+static int p54_init_xbow_synth(struct ieee80211_hw *dev);
+
+static int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len)
 {
 	struct p54_common *priv = dev->priv;
 	struct eeprom_pda_wrap *wrap = NULL;
@@ -210,6 +319,7 @@
 	void *tmp;
 	int err;
 	u8 *end = (u8 *)eeprom + len;
+	DECLARE_MAC_BUF(mac);
 
 	wrap = (struct eeprom_pda_wrap *) eeprom;
 	entry = (void *)wrap->data + le16_to_cpu(wrap->len);
@@ -250,27 +360,32 @@
 			       entry->data[1]*sizeof(*priv->output_limit));
 			priv->output_limit_len = entry->data[1];
 			break;
-		case PDR_PRISM_PA_CAL_CURVE_DATA:
-			if (data_len < sizeof(struct pda_pa_curve_data)) {
+		case PDR_PRISM_PA_CAL_CURVE_DATA: {
+			struct pda_pa_curve_data *curve_data =
+				(struct pda_pa_curve_data *)entry->data;
+			if (data_len < sizeof(*curve_data)) {
 				err = -EINVAL;
 				goto err;
 			}
 
-			if (((struct pda_pa_curve_data *)entry->data)->cal_method_rev) {
-				priv->curve_data = kmalloc(data_len, GFP_KERNEL);
-				if (!priv->curve_data) {
-					err = -ENOMEM;
-					goto err;
-				}
-
-				memcpy(priv->curve_data, entry->data, data_len);
-			} else {
-				err = p54_convert_rev0_to_rev1(dev, (struct pda_pa_curve_data *)entry->data);
-				if (err)
-					goto err;
+			switch (curve_data->cal_method_rev) {
+			case 0:
+				err = p54_convert_rev0(dev, curve_data);
+				break;
+			case 1:
+				err = p54_convert_rev1(dev, curve_data);
+				break;
+			default:
+				printk(KERN_ERR "p54: unknown curve data "
+						"revision %d\n",
+						curve_data->cal_method_rev);
+				err = -ENODEV;
+				break;
 			}
+			if (err)
+				goto err;
 
-			break;
+		}
 		case PDR_PRISM_ZIF_TX_IQ_CALIBRATION:
 			priv->iq_autocal = kmalloc(data_len, GFP_KERNEL);
 			if (!priv->iq_autocal) {
@@ -286,7 +401,7 @@
 			while ((u8 *)tmp < entry->data + data_len) {
 				struct bootrec_exp_if *exp_if = tmp;
 				if (le16_to_cpu(exp_if->if_id) == 0xF)
-					priv->rxhw = exp_if->variant & cpu_to_le16(0x07);
+					priv->rxhw = le16_to_cpu(exp_if->variant) & 0x07;
 				tmp += sizeof(struct bootrec_exp_if);
 			}
 			break;
@@ -312,6 +427,37 @@
 		goto err;
 	}
 
+	switch (priv->rxhw) {
+	case 4: /* XBow */
+		p54_init_xbow_synth(dev);
+	case 1: /* Indigo? */
+	case 2: /* Duette */
+		dev->wiphy->bands[IEEE80211_BAND_5GHZ] = &band_5GHz;
+	case 3: /* Frisbee */
+	case 5: /* Longbow */
+		dev->wiphy->bands[IEEE80211_BAND_2GHZ] = &band_2GHz;
+		break;
+	default:
+		printk(KERN_ERR "%s: unsupported RF-Chip\n",
+			wiphy_name(dev->wiphy));
+		err = -EINVAL;
+		goto err;
+	}
+
+	if (!is_valid_ether_addr(dev->wiphy->perm_addr)) {
+		u8 perm_addr[ETH_ALEN];
+
+		printk(KERN_WARNING "%s: Invalid hwaddr! Using randomly generated MAC addr\n",
+			wiphy_name(dev->wiphy));
+		random_ether_addr(perm_addr);
+		SET_IEEE80211_PERM_ADDR(dev, perm_addr);
+	}
+
+	printk(KERN_INFO "%s: hwaddr %s, MAC:isl38%02x RF:%s\n",
+		wiphy_name(dev->wiphy),
+		print_mac(mac, dev->wiphy->perm_addr),
+		priv->version, p54_rf_chips[priv->rxhw]);
+
 	return 0;
 
   err:
@@ -335,40 +481,55 @@
 }
 EXPORT_SYMBOL_GPL(p54_parse_eeprom);
 
-void p54_fill_eeprom_readback(struct p54_control_hdr *hdr)
+static int p54_rssi_to_dbm(struct ieee80211_hw *dev, int rssi)
 {
-	struct p54_eeprom_lm86 *eeprom_hdr;
-
-	hdr->magic1 = cpu_to_le16(0x8000);
-	hdr->len = cpu_to_le16(sizeof(*eeprom_hdr) + 0x2000);
-	hdr->type = cpu_to_le16(P54_CONTROL_TYPE_EEPROM_READBACK);
-	hdr->retry1 = hdr->retry2 = 0;
-	eeprom_hdr = (struct p54_eeprom_lm86 *) hdr->data;
-	eeprom_hdr->offset = 0x0;
-	eeprom_hdr->len = cpu_to_le16(0x2000);
+	/* TODO: get the rssi_add & rssi_mul data from the eeprom */
+	return ((rssi * 0x83) / 64 - 400) / 4;
 }
-EXPORT_SYMBOL_GPL(p54_fill_eeprom_readback);
 
-static void p54_rx_data(struct ieee80211_hw *dev, struct sk_buff *skb)
+static int p54_rx_data(struct ieee80211_hw *dev, struct sk_buff *skb)
 {
+	struct p54_common *priv = dev->priv;
 	struct p54_rx_hdr *hdr = (struct p54_rx_hdr *) skb->data;
 	struct ieee80211_rx_status rx_status = {0};
 	u16 freq = le16_to_cpu(hdr->freq);
+	size_t header_len = sizeof(*hdr);
+	u32 tsf32;
 
-	rx_status.signal = hdr->rssi;
+	if (!(hdr->magic & cpu_to_le16(0x0001))) {
+		if (priv->filter_flags & FIF_FCSFAIL)
+			rx_status.flag |= RX_FLAG_FAILED_FCS_CRC;
+		else
+			return 0;
+	}
+
+	rx_status.signal = p54_rssi_to_dbm(dev, hdr->rssi);
+	rx_status.noise = priv->noise;
 	/* XX correct? */
 	rx_status.qual = (100 * hdr->rssi) / 127;
-	rx_status.rate_idx = hdr->rate & 0xf;
+	rx_status.rate_idx = (dev->conf.channel->band == IEEE80211_BAND_2GHZ ?
+			hdr->rate : (hdr->rate - 4)) & 0xf;
 	rx_status.freq = freq;
-	rx_status.band = IEEE80211_BAND_2GHZ;
+	rx_status.band =  dev->conf.channel->band;
 	rx_status.antenna = hdr->antenna;
-	rx_status.mactime = le64_to_cpu(hdr->timestamp);
+
+	tsf32 = le32_to_cpu(hdr->tsf32);
+	if (tsf32 < priv->tsf_low32)
+		priv->tsf_high32++;
+	rx_status.mactime = ((u64)priv->tsf_high32) << 32 | tsf32;
+	priv->tsf_low32 = tsf32;
+
 	rx_status.flag |= RX_FLAG_TSFT;
 
-	skb_pull(skb, sizeof(*hdr));
+	if (hdr->magic & cpu_to_le16(0x4000))
+		header_len += hdr->align[0];
+
+	skb_pull(skb, header_len);
 	skb_trim(skb, le16_to_cpu(hdr->len));
 
 	ieee80211_rx_irqsafe(dev, skb, &rx_status);
+
+	return -1;
 }
 
 static void inline p54_wake_free_queues(struct ieee80211_hw *dev)
@@ -377,7 +538,7 @@
 	int i;
 
 	for (i = 0; i < dev->queues; i++)
-		if (priv->tx_stats[i].len < priv->tx_stats[i].limit)
+		if (priv->tx_stats[i + 4].len < priv->tx_stats[i + 4].limit)
 			ieee80211_wake_queue(dev, i);
 }
 
@@ -387,11 +548,13 @@
 	struct p54_control_hdr *hdr = (struct p54_control_hdr *) skb->data;
 	struct p54_frame_sent_hdr *payload = (struct p54_frame_sent_hdr *) hdr->data;
 	struct sk_buff *entry = (struct sk_buff *) priv->tx_queue.next;
-	u32 addr = le32_to_cpu(hdr->req_id) - 0x70;
+	u32 addr = le32_to_cpu(hdr->req_id) - priv->headroom;
 	struct memrecord *range = NULL;
 	u32 freed = 0;
 	u32 last_addr = priv->rx_start;
+	unsigned long flags;
 
+	spin_lock_irqsave(&priv->tx_queue.lock, flags);
 	while (entry != (struct sk_buff *)&priv->tx_queue) {
 		struct ieee80211_tx_info *info = IEEE80211_SKB_CB(entry);
 		range = (void *)info->driver_data;
@@ -412,13 +575,15 @@
 
 			last_addr = range->end_addr;
 			__skb_unlink(entry, &priv->tx_queue);
+			spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
+
 			memset(&info->status, 0, sizeof(info->status));
 			entry_hdr = (struct p54_control_hdr *) entry->data;
 			entry_data = (struct p54_tx_control_allocdata *) entry_hdr->data;
 			if ((entry_hdr->magic1 & cpu_to_le16(0x4000)) != 0)
 				pad = entry_data->align[0];
 
-			priv->tx_stats[entry_data->hw_queue - 4].len--;
+			priv->tx_stats[entry_data->hw_queue].len--;
 			if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) {
 				if (!(payload->status & 0x01))
 					info->flags |= IEEE80211_TX_STAT_ACK;
@@ -426,21 +591,60 @@
 					info->status.excessive_retries = 1;
 			}
 			info->status.retry_count = payload->retries - 1;
-			info->status.ack_signal = le16_to_cpu(payload->ack_rssi);
+			info->status.ack_signal = p54_rssi_to_dbm(dev,
+					le16_to_cpu(payload->ack_rssi));
 			skb_pull(entry, sizeof(*hdr) + pad + sizeof(*entry_data));
 			ieee80211_tx_status_irqsafe(dev, entry);
-			break;
+			goto out;
 		} else
 			last_addr = range->end_addr;
 		entry = entry->next;
 	}
+	spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
 
+out:
 	if (freed >= IEEE80211_MAX_RTS_THRESHOLD + 0x170 +
 	    sizeof(struct p54_control_hdr))
 		p54_wake_free_queues(dev);
 }
 
-static void p54_rx_control(struct ieee80211_hw *dev, struct sk_buff *skb)
+static void p54_rx_eeprom_readback(struct ieee80211_hw *dev,
+				   struct sk_buff *skb)
+{
+	struct p54_control_hdr *hdr = (struct p54_control_hdr *) skb->data;
+	struct p54_eeprom_lm86 *eeprom = (struct p54_eeprom_lm86 *) hdr->data;
+	struct p54_common *priv = dev->priv;
+
+	if (!priv->eeprom)
+		return ;
+
+	memcpy(priv->eeprom, eeprom->data, le16_to_cpu(eeprom->len));
+
+	complete(&priv->eeprom_comp);
+}
+
+static void p54_rx_stats(struct ieee80211_hw *dev, struct sk_buff *skb)
+{
+	struct p54_common *priv = dev->priv;
+	struct p54_control_hdr *hdr = (struct p54_control_hdr *) skb->data;
+	struct p54_statistics *stats = (struct p54_statistics *) hdr->data;
+	u32 tsf32 = le32_to_cpu(stats->tsf32);
+
+	if (tsf32 < priv->tsf_low32)
+		priv->tsf_high32++;
+	priv->tsf_low32 = tsf32;
+
+	priv->stats.dot11RTSFailureCount = le32_to_cpu(stats->rts_fail);
+	priv->stats.dot11RTSSuccessCount = le32_to_cpu(stats->rts_success);
+	priv->stats.dot11FCSErrorCount = le32_to_cpu(stats->rx_bad_fcs);
+
+	priv->noise = p54_rssi_to_dbm(dev, le32_to_cpu(stats->noise));
+	complete(&priv->stats_comp);
+
+	mod_timer(&priv->stats_timer, jiffies + 5 * HZ);
+}
+
+static int p54_rx_control(struct ieee80211_hw *dev, struct sk_buff *skb)
 {
 	struct p54_control_hdr *hdr = (struct p54_control_hdr *) skb->data;
 
@@ -450,36 +654,30 @@
 		break;
 	case P54_CONTROL_TYPE_BBP:
 		break;
+	case P54_CONTROL_TYPE_STAT_READBACK:
+		p54_rx_stats(dev, skb);
+		break;
+	case P54_CONTROL_TYPE_EEPROM_READBACK:
+		p54_rx_eeprom_readback(dev, skb);
+		break;
 	default:
 		printk(KERN_DEBUG "%s: not handling 0x%02x type control frame\n",
 		       wiphy_name(dev->wiphy), le16_to_cpu(hdr->type));
 		break;
 	}
+
+	return 0;
 }
 
 /* returns zero if skb can be reused */
 int p54_rx(struct ieee80211_hw *dev, struct sk_buff *skb)
 {
 	u8 type = le16_to_cpu(*((__le16 *)skb->data)) >> 8;
-	switch (type) {
-	case 0x00:
-	case 0x01:
-		p54_rx_data(dev, skb);
-		return -1;
-	case 0x4d:
-		/* TODO: do something better... but then again, I've never seen this happen */
-		printk(KERN_ERR "%s: Received fault. Probably need to restart hardware now..\n",
-		       wiphy_name(dev->wiphy));
-		break;
-	case 0x80:
-		p54_rx_control(dev, skb);
-		break;
-	default:
-		printk(KERN_ERR "%s: unknown frame RXed (0x%02x)\n",
-		       wiphy_name(dev->wiphy), type);
-		break;
-	}
-	return 0;
+
+	if (type == 0x80)
+		return p54_rx_control(dev, skb);
+	else
+		return p54_rx_data(dev, skb);
 }
 EXPORT_SYMBOL_GPL(p54_rx);
 
@@ -503,7 +701,7 @@
 	u32 target_addr = priv->rx_start;
 	unsigned long flags;
 	unsigned int left;
-	len = (len + 0x170 + 3) & ~0x3; /* 0x70 headroom, 0x100 tailroom */
+	len = (len + priv->headroom + priv->tailroom + 3) & ~0x3;
 
 	spin_lock_irqsave(&priv->tx_queue.lock, flags);
 	left = skb_queue_len(&priv->tx_queue);
@@ -538,15 +736,75 @@
 		range->start_addr = target_addr;
 		range->end_addr = target_addr + len;
 		__skb_queue_after(&priv->tx_queue, target_skb, skb);
-		if (largest_hole < IEEE80211_MAX_RTS_THRESHOLD + 0x170 +
+		if (largest_hole < priv->rx_mtu + priv->headroom +
+				   priv->tailroom +
 				   sizeof(struct p54_control_hdr))
 			ieee80211_stop_queues(dev);
 	}
 	spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
 
-	data->req_id = cpu_to_le32(target_addr + 0x70);
+	data->req_id = cpu_to_le32(target_addr + priv->headroom);
 }
 
+int p54_read_eeprom(struct ieee80211_hw *dev)
+{
+	struct p54_common *priv = dev->priv;
+	struct p54_control_hdr *hdr = NULL;
+	struct p54_eeprom_lm86 *eeprom_hdr;
+	size_t eeprom_size = 0x2020, offset = 0, blocksize;
+	int ret = -ENOMEM;
+	void *eeprom = NULL;
+
+	hdr = (struct p54_control_hdr *)kzalloc(sizeof(*hdr) +
+		sizeof(*eeprom_hdr) + EEPROM_READBACK_LEN, GFP_KERNEL);
+	if (!hdr)
+		goto free;
+
+	priv->eeprom = kzalloc(EEPROM_READBACK_LEN, GFP_KERNEL);
+	if (!priv->eeprom)
+		goto free;
+
+	eeprom = kzalloc(eeprom_size, GFP_KERNEL);
+	if (!eeprom)
+		goto free;
+
+	hdr->magic1 = cpu_to_le16(0x8000);
+	hdr->type = cpu_to_le16(P54_CONTROL_TYPE_EEPROM_READBACK);
+	hdr->retry1 = hdr->retry2 = 0;
+	eeprom_hdr = (struct p54_eeprom_lm86 *) hdr->data;
+
+	while (eeprom_size) {
+		blocksize = min(eeprom_size, (size_t)EEPROM_READBACK_LEN);
+		hdr->len = cpu_to_le16(blocksize + sizeof(*eeprom_hdr));
+		eeprom_hdr->offset = cpu_to_le16(offset);
+		eeprom_hdr->len = cpu_to_le16(blocksize);
+		p54_assign_address(dev, NULL, hdr, le16_to_cpu(hdr->len) +
+				   sizeof(*hdr));
+		priv->tx(dev, hdr, le16_to_cpu(hdr->len) + sizeof(*hdr), 0);
+
+		if (!wait_for_completion_interruptible_timeout(&priv->eeprom_comp, HZ)) {
+			printk(KERN_ERR "%s: device does not respond!\n",
+				wiphy_name(dev->wiphy));
+			ret = -EBUSY;
+			goto free;
+	        }
+
+		memcpy(eeprom + offset, priv->eeprom, blocksize);
+		offset += blocksize;
+		eeprom_size -= blocksize;
+	}
+
+	ret = p54_parse_eeprom(dev, eeprom, offset);
+free:
+	kfree(priv->eeprom);
+	priv->eeprom = NULL;
+	kfree(hdr);
+	kfree(eeprom);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(p54_read_eeprom);
+
 static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
 {
 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
@@ -559,7 +817,7 @@
 	u8 rate;
 	u8 cts_rate = 0x20;
 
-	current_queue = &priv->tx_stats[skb_get_queue_mapping(skb)];
+	current_queue = &priv->tx_stats[skb_get_queue_mapping(skb) + 4];
 	if (unlikely(current_queue->len > current_queue->limit))
 		return NETDEV_TX_BUSY;
 	current_queue->len++;
@@ -601,7 +859,7 @@
 	txhdr->hw_queue = skb_get_queue_mapping(skb) + 4;
 	txhdr->tx_antenna = (info->antenna_sel_tx == 0) ?
 		2 : info->antenna_sel_tx - 1;
-	txhdr->output_power = 0x7f; // HW Maximum
+	txhdr->output_power = priv->output_power;
 	txhdr->cts_rate = (info->flags & IEEE80211_TX_CTL_NO_ACK) ?
 			  0 : cts_rate;
 	if (padding)
@@ -628,12 +886,12 @@
 }
 
 static int p54_set_filter(struct ieee80211_hw *dev, u16 filter_type,
-			  const u8 *dst, const u8 *src, u8 antenna,
-			  u32 magic3, u32 magic8, u32 magic9)
+			  const u8 *bssid)
 {
 	struct p54_common *priv = dev->priv;
 	struct p54_control_hdr *hdr;
 	struct p54_tx_control_filter *filter;
+	size_t data_len;
 
 	hdr = kzalloc(sizeof(*hdr) + sizeof(*filter) +
 		      priv->tx_hdr_len, GFP_ATOMIC);
@@ -644,25 +902,35 @@
 
 	filter = (struct p54_tx_control_filter *) hdr->data;
 	hdr->magic1 = cpu_to_le16(0x8001);
-	hdr->len = cpu_to_le16(sizeof(*filter));
-	p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + sizeof(*filter));
 	hdr->type = cpu_to_le16(P54_CONTROL_TYPE_FILTER_SET);
 
-	filter->filter_type = cpu_to_le16(filter_type);
-	memcpy(filter->dst, dst, ETH_ALEN);
-	if (!src)
-		memset(filter->src, ~0, ETH_ALEN);
+	priv->filter_type = filter->filter_type = cpu_to_le16(filter_type);
+	memcpy(filter->mac_addr, priv->mac_addr, ETH_ALEN);
+	if (!bssid)
+		memset(filter->bssid, ~0, ETH_ALEN);
 	else
-		memcpy(filter->src, src, ETH_ALEN);
-	filter->antenna = antenna;
-	filter->magic3 = cpu_to_le32(magic3);
-	filter->rx_addr = cpu_to_le32(priv->rx_end);
-	filter->max_rx = cpu_to_le16(0x0620);	/* FIXME: for usb ver 1.. maybe */
-	filter->rxhw = priv->rxhw;
-	filter->magic8 = cpu_to_le16(magic8);
-	filter->magic9 = cpu_to_le16(magic9);
+		memcpy(filter->bssid, bssid, ETH_ALEN);
 
-	priv->tx(dev, hdr, sizeof(*hdr) + sizeof(*filter), 1);
+	filter->rx_antenna = priv->rx_antenna;
+
+	if (priv->fw_var < 0x500) {
+		data_len = P54_TX_CONTROL_FILTER_V1_LEN;
+		filter->v1.basic_rate_mask = cpu_to_le32(0x15F);
+		filter->v1.rx_addr = cpu_to_le32(priv->rx_end);
+		filter->v1.max_rx = cpu_to_le16(priv->rx_mtu);
+		filter->v1.rxhw = cpu_to_le16(priv->rxhw);
+		filter->v1.wakeup_timer = cpu_to_le16(500);
+	} else {
+		data_len = P54_TX_CONTROL_FILTER_V2_LEN;
+		filter->v2.rx_addr = cpu_to_le32(priv->rx_end);
+		filter->v2.max_rx = cpu_to_le16(priv->rx_mtu);
+		filter->v2.rxhw = cpu_to_le16(priv->rxhw);
+		filter->v2.timer = cpu_to_le16(1000);
+	}
+
+	hdr->len = cpu_to_le16(data_len);
+	p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + data_len);
+	priv->tx(dev, hdr, sizeof(*hdr) + data_len, 1);
 	return 0;
 }
 
@@ -672,12 +940,10 @@
 	struct p54_control_hdr *hdr;
 	struct p54_tx_control_channel *chan;
 	unsigned int i;
-	size_t payload_len = sizeof(*chan) + sizeof(u32)*2 +
-			     sizeof(*chan->curve_data) *
-			     priv->curve_data->points_per_channel;
+	size_t data_len;
 	void *entry;
 
-	hdr = kzalloc(sizeof(*hdr) + payload_len +
+	hdr = kzalloc(sizeof(*hdr) + sizeof(*chan) +
 		      priv->tx_hdr_len, GFP_KERNEL);
 	if (!hdr)
 		return -ENOMEM;
@@ -687,12 +953,11 @@
 	chan = (struct p54_tx_control_channel *) hdr->data;
 
 	hdr->magic1 = cpu_to_le16(0x8001);
-	hdr->len = cpu_to_le16(sizeof(*chan));
-	hdr->type = cpu_to_le16(P54_CONTROL_TYPE_CHANNEL_CHANGE);
-	p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + payload_len);
 
-	chan->magic1 = cpu_to_le16(0x1);
-	chan->magic2 = cpu_to_le16(0x0);
+	hdr->type = cpu_to_le16(P54_CONTROL_TYPE_CHANNEL_CHANGE);
+
+	chan->flags = cpu_to_le16(0x1);
+	chan->dwell = cpu_to_le16(0x0);
 
 	for (i = 0; i < priv->iq_autocal_len; i++) {
 		if (priv->iq_autocal[i].freq != freq)
@@ -710,35 +975,51 @@
 			continue;
 
 		chan->val_barker = 0x38;
-		chan->val_bpsk = priv->output_limit[i].val_bpsk;
-		chan->val_qpsk = priv->output_limit[i].val_qpsk;
-		chan->val_16qam = priv->output_limit[i].val_16qam;
-		chan->val_64qam = priv->output_limit[i].val_64qam;
+		chan->val_bpsk = chan->dup_bpsk =
+			priv->output_limit[i].val_bpsk;
+		chan->val_qpsk = chan->dup_qpsk =
+			priv->output_limit[i].val_qpsk;
+		chan->val_16qam = chan->dup_16qam =
+			priv->output_limit[i].val_16qam;
+		chan->val_64qam = chan->dup_64qam =
+			priv->output_limit[i].val_64qam;
 		break;
 	}
 	if (i == priv->output_limit_len)
 		goto err;
 
-	chan->pa_points_per_curve = priv->curve_data->points_per_channel;
-
 	entry = priv->curve_data->data;
 	for (i = 0; i < priv->curve_data->channels; i++) {
 		if (*((__le16 *)entry) != freq) {
 			entry += sizeof(__le16);
-			entry += sizeof(struct pda_pa_curve_data_sample_rev1) *
-				 chan->pa_points_per_curve;
+			entry += sizeof(struct p54_pa_curve_data_sample) *
+				 priv->curve_data->points_per_channel;
 			continue;
 		}
 
 		entry += sizeof(__le16);
+		chan->pa_points_per_curve =
+			min(priv->curve_data->points_per_channel, (u8) 8);
+
 		memcpy(chan->curve_data, entry, sizeof(*chan->curve_data) *
 		       chan->pa_points_per_curve);
 		break;
 	}
 
-	memcpy(hdr->data + payload_len - 4, &chan->val_bpsk, 4);
+	if (priv->fw_var < 0x500) {
+		data_len = P54_TX_CONTROL_CHANNEL_V1_LEN;
+		chan->v1.rssical_mul = cpu_to_le16(130);
+		chan->v1.rssical_add = cpu_to_le16(0xfe70);
+	} else {
+		data_len = P54_TX_CONTROL_CHANNEL_V2_LEN;
+		chan->v2.rssical_mul = cpu_to_le16(130);
+		chan->v2.rssical_add = cpu_to_le16(0xfe70);
+		chan->v2.basic_rate_mask = cpu_to_le32(0x15f);
+	}
 
-	priv->tx(dev, hdr, sizeof(*hdr) + payload_len, 1);
+	hdr->len = cpu_to_le16(data_len);
+	p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + data_len);
+	priv->tx(dev, hdr, sizeof(*hdr) + data_len, 1);
 	return 0;
 
  err:
@@ -846,12 +1127,25 @@
 			return -ENOMEM;
 	}
 
+	if (!priv->cached_stats) {
+		priv->cached_stats = kzalloc(sizeof(struct p54_statistics) +
+			priv->tx_hdr_len + sizeof(struct p54_control_hdr),
+			GFP_KERNEL);
+
+		if (!priv->cached_stats) {
+			kfree(priv->cached_vdcf);
+			priv->cached_vdcf = NULL;
+			return -ENOMEM;
+		}
+	}
+
 	err = priv->open(dev);
 	if (!err)
-		priv->mode = IEEE80211_IF_TYPE_MNTR;
+		priv->mode = NL80211_IFTYPE_MONITOR;
 
 	p54_init_vdcf(dev);
 
+	mod_timer(&priv->stats_timer, jiffies + HZ);
 	return err;
 }
 
@@ -859,10 +1153,13 @@
 {
 	struct p54_common *priv = dev->priv;
 	struct sk_buff *skb;
+
+	del_timer(&priv->stats_timer);
 	while ((skb = skb_dequeue(&priv->tx_queue)))
 		kfree_skb(skb);
 	priv->stop(dev);
-	priv->mode = IEEE80211_IF_TYPE_INVALID;
+	priv->tsf_high32 = priv->tsf_low32 = 0;
+	priv->mode = NL80211_IFTYPE_UNSPECIFIED;
 }
 
 static int p54_add_interface(struct ieee80211_hw *dev,
@@ -870,11 +1167,11 @@
 {
 	struct p54_common *priv = dev->priv;
 
-	if (priv->mode != IEEE80211_IF_TYPE_MNTR)
+	if (priv->mode != NL80211_IFTYPE_MONITOR)
 		return -EOPNOTSUPP;
 
 	switch (conf->type) {
-	case IEEE80211_IF_TYPE_STA:
+	case NL80211_IFTYPE_STATION:
 		priv->mode = conf->type;
 		break;
 	default:
@@ -883,12 +1180,11 @@
 
 	memcpy(priv->mac_addr, conf->mac_addr, ETH_ALEN);
 
-	p54_set_filter(dev, 0, priv->mac_addr, NULL, 0, 1, 0, 0xF642);
-	p54_set_filter(dev, 0, priv->mac_addr, NULL, 1, 0, 0, 0xF642);
+	p54_set_filter(dev, 0, NULL);
 
 	switch (conf->type) {
-	case IEEE80211_IF_TYPE_STA:
-		p54_set_filter(dev, 1, priv->mac_addr, NULL, 0, 0x15F, 0x1F4, 0);
+	case NL80211_IFTYPE_STATION:
+		p54_set_filter(dev, 1, NULL);
 		break;
 	default:
 		BUG();	/* impossible */
@@ -904,9 +1200,9 @@
 				 struct ieee80211_if_init_conf *conf)
 {
 	struct p54_common *priv = dev->priv;
-	priv->mode = IEEE80211_IF_TYPE_MNTR;
+	priv->mode = NL80211_IFTYPE_MONITOR;
 	memset(priv->mac_addr, 0, ETH_ALEN);
-	p54_set_filter(dev, 0, priv->mac_addr, NULL, 2, 0, 0, 0);
+	p54_set_filter(dev, 0, NULL);
 }
 
 static int p54_config(struct ieee80211_hw *dev, struct ieee80211_conf *conf)
@@ -915,6 +1211,9 @@
 	struct p54_common *priv = dev->priv;
 
 	mutex_lock(&priv->conf_mutex);
+	priv->rx_antenna = (conf->antenna_sel_rx == 0) ?
+		2 : conf->antenna_sel_tx - 1;
+	priv->output_power = conf->power_level << 2;
 	ret = p54_set_freq(dev, cpu_to_le16(conf->channel->center_freq));
 	p54_set_vdcf(dev);
 	mutex_unlock(&priv->conf_mutex);
@@ -928,8 +1227,7 @@
 	struct p54_common *priv = dev->priv;
 
 	mutex_lock(&priv->conf_mutex);
-	p54_set_filter(dev, 0, priv->mac_addr, conf->bssid, 0, 1, 0, 0xF642);
-	p54_set_filter(dev, 0, priv->mac_addr, conf->bssid, 2, 0, 0, 0);
+	p54_set_filter(dev, 0, conf->bssid);
 	p54_set_leds(dev, 1, !is_multicast_ether_addr(conf->bssid), 0);
 	memcpy(priv->bssid, conf->bssid, ETH_ALEN);
 	mutex_unlock(&priv->conf_mutex);
@@ -943,15 +1241,28 @@
 {
 	struct p54_common *priv = dev->priv;
 
-	*total_flags &= FIF_BCN_PRBRESP_PROMISC;
+	*total_flags &= FIF_BCN_PRBRESP_PROMISC |
+			FIF_PROMISC_IN_BSS |
+			FIF_FCSFAIL;
+
+	priv->filter_flags = *total_flags;
 
 	if (changed_flags & FIF_BCN_PRBRESP_PROMISC) {
 		if (*total_flags & FIF_BCN_PRBRESP_PROMISC)
-			p54_set_filter(dev, 0, priv->mac_addr,
-				       NULL, 2, 0, 0, 0);
+			p54_set_filter(dev, le16_to_cpu(priv->filter_type),
+				 NULL);
 		else
-			p54_set_filter(dev, 0, priv->mac_addr,
-				       priv->bssid, 2, 0, 0, 0);
+			p54_set_filter(dev, le16_to_cpu(priv->filter_type),
+				 priv->bssid);
+	}
+
+	if (changed_flags & FIF_PROMISC_IN_BSS) {
+		if (*total_flags & FIF_PROMISC_IN_BSS)
+			p54_set_filter(dev, le16_to_cpu(priv->filter_type) |
+				0x8, NULL);
+		else
+			p54_set_filter(dev, le16_to_cpu(priv->filter_type) &
+				~0x8, priv->bssid);
 	}
 }
 
@@ -975,10 +1286,67 @@
 	return 0;
 }
 
+static int p54_init_xbow_synth(struct ieee80211_hw *dev)
+{
+	struct p54_common *priv = dev->priv;
+	struct p54_control_hdr *hdr;
+	struct p54_tx_control_xbow_synth *xbow;
+
+	hdr = kzalloc(sizeof(*hdr) + sizeof(*xbow) +
+		      priv->tx_hdr_len, GFP_KERNEL);
+	if (!hdr)
+		return -ENOMEM;
+
+	hdr = (void *)hdr + priv->tx_hdr_len;
+	hdr->magic1 = cpu_to_le16(0x8001);
+	hdr->len = cpu_to_le16(sizeof(*xbow));
+	hdr->type = cpu_to_le16(P54_CONTROL_TYPE_XBOW_SYNTH_CFG);
+	p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + sizeof(*xbow));
+
+	xbow = (struct p54_tx_control_xbow_synth *) hdr->data;
+	xbow->magic1 = cpu_to_le16(0x1);
+	xbow->magic2 = cpu_to_le16(0x2);
+	xbow->freq = cpu_to_le16(5390);
+
+	priv->tx(dev, hdr, sizeof(*hdr) + sizeof(*xbow), 1);
+
+	return 0;
+}
+
+static void p54_statistics_timer(unsigned long data)
+{
+	struct ieee80211_hw *dev = (struct ieee80211_hw *) data;
+	struct p54_common *priv = dev->priv;
+	struct p54_control_hdr *hdr;
+	struct p54_statistics *stats;
+
+	BUG_ON(!priv->cached_stats);
+
+	hdr = (void *)priv->cached_stats + priv->tx_hdr_len;
+	hdr->magic1 = cpu_to_le16(0x8000);
+	hdr->len = cpu_to_le16(sizeof(*stats));
+	hdr->type = cpu_to_le16(P54_CONTROL_TYPE_STAT_READBACK);
+	p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + sizeof(*stats));
+
+	priv->tx(dev, hdr, sizeof(*hdr) + sizeof(*stats), 0);
+}
+
 static int p54_get_stats(struct ieee80211_hw *dev,
 			 struct ieee80211_low_level_stats *stats)
 {
-	/* TODO */
+	struct p54_common *priv = dev->priv;
+
+	del_timer(&priv->stats_timer);
+	p54_statistics_timer((unsigned long)dev);
+
+	if (!wait_for_completion_interruptible_timeout(&priv->stats_comp, HZ)) {
+		printk(KERN_ERR "%s: device does not respond!\n",
+			wiphy_name(dev->wiphy));
+		return -EBUSY;
+	}
+
+	memcpy(stats, &priv->stats, sizeof(*stats));
+
 	return 0;
 }
 
@@ -987,7 +1355,7 @@
 {
 	struct p54_common *priv = dev->priv;
 
-	memcpy(stats, &priv->tx_stats, sizeof(stats[0]) * dev->queues);
+	memcpy(stats, &priv->tx_stats[4], sizeof(stats[0]) * dev->queues);
 
 	return 0;
 }
@@ -1016,22 +1384,32 @@
 		return NULL;
 
 	priv = dev->priv;
-	priv->mode = IEEE80211_IF_TYPE_INVALID;
+	priv->mode = NL80211_IFTYPE_UNSPECIFIED;
 	skb_queue_head_init(&priv->tx_queue);
-	dev->wiphy->bands[IEEE80211_BAND_2GHZ] = &band_2GHz;
 	dev->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | /* not sure */
 		     IEEE80211_HW_RX_INCLUDES_FCS |
-		     IEEE80211_HW_SIGNAL_UNSPEC;
+		     IEEE80211_HW_SIGNAL_DBM |
+		     IEEE80211_HW_NOISE_DBM;
+
+	dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
+
 	dev->channel_change_time = 1000;	/* TODO: find actual value */
-	dev->max_signal = 127;
 
-	priv->tx_stats[0].limit = 5;
+	priv->tx_stats[0].limit = 1;
+	priv->tx_stats[1].limit = 1;
+	priv->tx_stats[2].limit = 1;
+	priv->tx_stats[3].limit = 1;
+	priv->tx_stats[4].limit = 5;
 	dev->queues = 1;
-
+	priv->noise = -94;
 	dev->extra_tx_headroom = sizeof(struct p54_control_hdr) + 4 +
 				 sizeof(struct p54_tx_control_allocdata);
 
 	mutex_init(&priv->conf_mutex);
+	init_completion(&priv->eeprom_comp);
+	init_completion(&priv->stats_comp);
+	setup_timer(&priv->stats_timer, p54_statistics_timer,
+		(unsigned long)dev);
 
 	return dev;
 }
@@ -1040,6 +1418,7 @@
 void p54_free_common(struct ieee80211_hw *dev)
 {
 	struct p54_common *priv = dev->priv;
+	kfree(priv->cached_stats);
 	kfree(priv->iq_autocal);
 	kfree(priv->output_limit);
 	kfree(priv->curve_data);
diff --git a/drivers/net/wireless/p54/p54common.h b/drivers/net/wireless/p54/p54common.h
index 8db6c0e..2fa994c 100644
--- a/drivers/net/wireless/p54/p54common.h
+++ b/drivers/net/wireless/p54/p54common.h
@@ -1,5 +1,5 @@
-#ifndef PRISM54COMMON_H
-#define PRISM54COMMON_H
+#ifndef P54COMMON_H
+#define P54COMMON_H
 
 /*
  * Common code specific definitions for mac80211 Prism54 drivers
@@ -18,7 +18,8 @@
 struct bootrec {
 	__le32 code;
 	__le32 len;
-	u32 data[0];
+	u32 data[10];
+	__le16 rx_mtu;
 } __attribute__((packed));
 
 struct bootrec_exp_if {
@@ -29,6 +30,17 @@
 	__le16 top_compat;
 } __attribute__((packed));
 
+struct bootrec_desc {
+	__le16 modes;
+	__le16 flags;
+	__le32 rx_start;
+	__le32 rx_end;
+	u8 headroom;
+	u8 tailroom;
+	u8 unimportant[6];
+	u8 rates[16];
+} __attribute__((packed));
+
 #define BR_CODE_MIN			0x80000000
 #define BR_CODE_COMPONENT_ID		0x80000001
 #define BR_CODE_COMPONENT_VERSION	0x80000002
@@ -39,11 +51,6 @@
 #define BR_CODE_END_OF_BRA		0xFF0000FF
 #define LEGACY_BR_CODE_END_OF_BRA	0xFFFFFFFF
 
-#define FW_FMAC 0x464d4143
-#define FW_LM86 0x4c4d3836
-#define FW_LM87 0x4c4d3837
-#define FW_LM20 0x4c4d3230
-
 /* PDA defines are Copyright (C) 2005 Nokia Corporation (taken from islsm_pda.h) */
 
 struct pda_entry {
@@ -89,6 +96,16 @@
 	u8 data_qpsk;
 	u8 data_16qam;
 	u8 data_64qam;
+} __attribute__ ((packed));
+
+struct p54_pa_curve_data_sample {
+	u8 rf_power;
+	u8 pa_detector;
+	u8 data_barker;
+	u8 data_bpsk;
+	u8 data_qpsk;
+	u8 data_16qam;
+	u8 data_64qam;
 	u8 padding;
 } __attribute__ ((packed));
 
@@ -169,8 +186,9 @@
 	u8 rssi;
 	u8 quality;
 	u16 unknown2;
-	__le64 timestamp;
-	u8 data[0];
+	__le32 tsf32;
+	__le32 unalloc0;
+	u8 align[0];
 } __attribute__ ((packed));
 
 struct p54_frame_sent_hdr {
@@ -198,22 +216,37 @@
 
 struct p54_tx_control_filter {
 	__le16 filter_type;
-	u8 dst[ETH_ALEN];
-	u8 src[ETH_ALEN];
-	u8 antenna;
-	u8 debug;
-	__le32 magic3;
-	u8 rates[8];	// FIXME: what's this for?
-	__le32 rx_addr;
-	__le16 max_rx;
-	__le16 rxhw;
-	__le16 magic8;
-	__le16 magic9;
+	u8 mac_addr[ETH_ALEN];
+	u8 bssid[ETH_ALEN];
+	u8 rx_antenna;
+	u8 rx_align;
+	union {
+		struct {
+			__le32 basic_rate_mask;
+			u8 rts_rates[8];
+			__le32 rx_addr;
+			__le16 max_rx;
+			__le16 rxhw;
+			__le16 wakeup_timer;
+			__le16 unalloc0;
+		} v1 __attribute__ ((packed));
+		struct {
+			__le32 rx_addr;
+			__le16 max_rx;
+			__le16 rxhw;
+			__le16 timer;
+			__le16 unalloc0;
+			__le32 unalloc1;
+		} v2 __attribute__ ((packed));
+	} __attribute__ ((packed));
 } __attribute__ ((packed));
 
+#define P54_TX_CONTROL_FILTER_V1_LEN (sizeof(struct p54_tx_control_filter))
+#define P54_TX_CONTROL_FILTER_V2_LEN (sizeof(struct p54_tx_control_filter)-8)
+
 struct p54_tx_control_channel {
-	__le16 magic1;
-	__le16 magic2;
+	__le16 flags;
+	__le16 dwell;
 	u8 padding1[20];
 	struct pda_iq_autocal_entry iq_autocal;
 	u8 pa_points_per_curve;
@@ -222,10 +255,29 @@
 	u8 val_qpsk;
 	u8 val_16qam;
 	u8 val_64qam;
-	struct pda_pa_curve_data_sample_rev1 curve_data[0];
-	/* additional padding/data after curve_data */
+	struct p54_pa_curve_data_sample curve_data[8];
+	u8 dup_bpsk;
+	u8 dup_qpsk;
+	u8 dup_16qam;
+	u8 dup_64qam;
+	union {
+		struct {
+			__le16 rssical_mul;
+			__le16 rssical_add;
+		} v1 __attribute__ ((packed));
+
+		struct {
+			__le32 basic_rate_mask;
+			 u8 rts_rates[8];
+			__le16 rssical_mul;
+			__le16 rssical_add;
+		} v2 __attribute__ ((packed));
+	} __attribute__ ((packed));
 } __attribute__ ((packed));
 
+#define P54_TX_CONTROL_CHANNEL_V1_LEN (sizeof(struct p54_tx_control_channel)-12)
+#define P54_TX_CONTROL_CHANNEL_V2_LEN (sizeof(struct p54_tx_control_channel))
+
 struct p54_tx_control_led {
 	__le16 mode;
 	__le16 led_temporary;
@@ -250,4 +302,24 @@
 	__le16 frameburst;
 } __attribute__ ((packed));
 
-#endif /* PRISM54COMMON_H */
+struct p54_statistics {
+	__le32 rx_success;
+	__le32 rx_bad_fcs;
+	__le32 rx_abort;
+	__le32 rx_abort_phy;
+	__le32 rts_success;
+	__le32 rts_fail;
+	__le32 tsf32;
+	__le32 airtime;
+	__le32 noise;
+	__le32 unkn[10]; /* CCE / CCA / RADAR */
+} __attribute__ ((packed));
+
+struct p54_tx_control_xbow_synth {
+	__le16 magic1;
+	__le16 magic2;
+	__le16 freq;
+	u32 padding[5];
+} __attribute__ ((packed));
+
+#endif /* P54COMMON_H */
diff --git a/drivers/net/wireless/p54/p54pci.c b/drivers/net/wireless/p54/p54pci.c
index 7dd4add..1c2a02a 100644
--- a/drivers/net/wireless/p54/p54pci.c
+++ b/drivers/net/wireless/p54/p54pci.c
@@ -3,6 +3,7 @@
  * Linux device driver for PCI based Prism54
  *
  * Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net>
+ * Copyright (c) 2008, Christian Lamparter <chunkeey@web.de>
  *
  * Based on the islsm (softmac prism54) driver, which is:
  * Copyright 2004-2006 Jean-Baptiste Note <jean-baptiste.note@m4x.org>, et al.
@@ -71,16 +72,18 @@
 	P54P_WRITE(ctrl_stat, reg);
 	wmb();
 
-	mdelay(50);
-
 	err = request_firmware(&fw_entry, "isl3886", &priv->pdev->dev);
 	if (err) {
-		printk(KERN_ERR "%s (prism54pci): cannot find firmware "
+		printk(KERN_ERR "%s (p54pci): cannot find firmware "
 		       "(isl3886)\n", pci_name(priv->pdev));
 		return err;
 	}
 
-	p54_parse_firmware(dev, fw_entry);
+	err = p54_parse_firmware(dev, fw_entry);
+	if (err) {
+		release_firmware(fw_entry);
+		return err;
+	}
 
 	data = (__le32 *) fw_entry->data;
 	remains = fw_entry->size;
@@ -121,162 +124,147 @@
 	wmb();
 	udelay(10);
 
+	/* wait for the firmware to boot properly */
+	mdelay(100);
+
 	return 0;
 }
 
-static irqreturn_t p54p_simple_interrupt(int irq, void *dev_id)
-{
-	struct p54p_priv *priv = (struct p54p_priv *) dev_id;
-	__le32 reg;
-
-	reg = P54P_READ(int_ident);
-	P54P_WRITE(int_ack, reg);
-
-	if (reg & P54P_READ(int_enable))
-		complete(&priv->boot_comp);
-
-	return IRQ_HANDLED;
-}
-
-static int p54p_read_eeprom(struct ieee80211_hw *dev)
+static void p54p_refill_rx_ring(struct ieee80211_hw *dev,
+	int ring_index, struct p54p_desc *ring, u32 ring_limit,
+	struct sk_buff **rx_buf)
 {
 	struct p54p_priv *priv = dev->priv;
 	struct p54p_ring_control *ring_control = priv->ring_control;
-	int err;
-	struct p54_control_hdr *hdr;
-	void *eeprom;
-	dma_addr_t rx_mapping, tx_mapping;
-	u16 alen;
+	u32 limit, idx, i;
 
-	init_completion(&priv->boot_comp);
-	err = request_irq(priv->pdev->irq, &p54p_simple_interrupt,
-			  IRQF_SHARED, "prism54pci", priv);
-	if (err) {
-		printk(KERN_ERR "%s (prism54pci): failed to register IRQ handler\n",
-		       pci_name(priv->pdev));
-		return err;
-	}
+	idx = le32_to_cpu(ring_control->host_idx[ring_index]);
+	limit = idx;
+	limit -= le32_to_cpu(ring_control->device_idx[ring_index]);
+	limit = ring_limit - limit;
 
-	eeprom = kmalloc(0x2010 + EEPROM_READBACK_LEN, GFP_KERNEL);
-	if (!eeprom) {
-		printk(KERN_ERR "%s (prism54pci): no memory for eeprom!\n",
-		       pci_name(priv->pdev));
-		err = -ENOMEM;
-		goto out;
-	}
-
-	memset(ring_control, 0, sizeof(*ring_control));
-	P54P_WRITE(ring_control_base, cpu_to_le32(priv->ring_control_dma));
-	P54P_READ(ring_control_base);
-	udelay(10);
-
-	P54P_WRITE(int_enable, cpu_to_le32(ISL38XX_INT_IDENT_INIT));
-	P54P_READ(int_enable);
-	udelay(10);
-
-	P54P_WRITE(dev_int, cpu_to_le32(ISL38XX_DEV_INT_RESET));
-
-	if (!wait_for_completion_interruptible_timeout(&priv->boot_comp, HZ)) {
-		printk(KERN_ERR "%s (prism54pci): Cannot boot firmware!\n",
-		       pci_name(priv->pdev));
-		err = -EINVAL;
-		goto out;
-	}
-
-	P54P_WRITE(int_enable, cpu_to_le32(ISL38XX_INT_IDENT_UPDATE));
-	P54P_READ(int_enable);
-
-	hdr = eeprom + 0x2010;
-	p54_fill_eeprom_readback(hdr);
-	hdr->req_id = cpu_to_le32(priv->common.rx_start);
-
-	rx_mapping = pci_map_single(priv->pdev, eeprom,
-				    0x2010, PCI_DMA_FROMDEVICE);
-	tx_mapping = pci_map_single(priv->pdev, (void *)hdr,
-				    EEPROM_READBACK_LEN, PCI_DMA_TODEVICE);
-
-	ring_control->rx_mgmt[0].host_addr = cpu_to_le32(rx_mapping);
-	ring_control->rx_mgmt[0].len = cpu_to_le16(0x2010);
-	ring_control->tx_data[0].host_addr = cpu_to_le32(tx_mapping);
-	ring_control->tx_data[0].device_addr = hdr->req_id;
-	ring_control->tx_data[0].len = cpu_to_le16(EEPROM_READBACK_LEN);
-
-	ring_control->host_idx[2] = cpu_to_le32(1);
-	ring_control->host_idx[1] = cpu_to_le32(1);
-
-	wmb();
-	mdelay(100);
-	P54P_WRITE(dev_int, cpu_to_le32(ISL38XX_DEV_INT_UPDATE));
-
-	wait_for_completion_interruptible_timeout(&priv->boot_comp, HZ);
-	wait_for_completion_interruptible_timeout(&priv->boot_comp, HZ);
-
-	pci_unmap_single(priv->pdev, tx_mapping,
-			 EEPROM_READBACK_LEN, PCI_DMA_TODEVICE);
-	pci_unmap_single(priv->pdev, rx_mapping,
-			 0x2010, PCI_DMA_FROMDEVICE);
-
-	alen = le16_to_cpu(ring_control->rx_mgmt[0].len);
-	if (le32_to_cpu(ring_control->device_idx[2]) != 1 ||
-	    alen < 0x10) {
-		printk(KERN_ERR "%s (prism54pci): Cannot read eeprom!\n",
-		       pci_name(priv->pdev));
-		err = -EINVAL;
-		goto out;
-	}
-
-	p54_parse_eeprom(dev, (u8 *)eeprom + 0x10, alen - 0x10);
-
- out:
-	kfree(eeprom);
-	P54P_WRITE(int_enable, cpu_to_le32(0));
-	P54P_READ(int_enable);
-	udelay(10);
-	free_irq(priv->pdev->irq, priv);
-	P54P_WRITE(dev_int, cpu_to_le32(ISL38XX_DEV_INT_RESET));
-	return err;
-}
-
-static void p54p_refill_rx_ring(struct ieee80211_hw *dev)
-{
-	struct p54p_priv *priv = dev->priv;
-	struct p54p_ring_control *ring_control = priv->ring_control;
-	u32 limit, host_idx, idx;
-
-	host_idx = le32_to_cpu(ring_control->host_idx[0]);
-	limit = host_idx;
-	limit -= le32_to_cpu(ring_control->device_idx[0]);
-	limit = ARRAY_SIZE(ring_control->rx_data) - limit;
-
-	idx = host_idx % ARRAY_SIZE(ring_control->rx_data);
+	i = idx % ring_limit;
 	while (limit-- > 1) {
-		struct p54p_desc *desc = &ring_control->rx_data[idx];
+		struct p54p_desc *desc = &ring[i];
 
 		if (!desc->host_addr) {
 			struct sk_buff *skb;
 			dma_addr_t mapping;
-			skb = dev_alloc_skb(MAX_RX_SIZE);
+			skb = dev_alloc_skb(priv->common.rx_mtu + 32);
 			if (!skb)
 				break;
 
 			mapping = pci_map_single(priv->pdev,
 						 skb_tail_pointer(skb),
-						 MAX_RX_SIZE,
+						 priv->common.rx_mtu + 32,
 						 PCI_DMA_FROMDEVICE);
 			desc->host_addr = cpu_to_le32(mapping);
 			desc->device_addr = 0;	// FIXME: necessary?
-			desc->len = cpu_to_le16(MAX_RX_SIZE);
+			desc->len = cpu_to_le16(priv->common.rx_mtu + 32);
 			desc->flags = 0;
-			priv->rx_buf[idx] = skb;
+			rx_buf[i] = skb;
 		}
 
+		i++;
 		idx++;
-		host_idx++;
-		idx %= ARRAY_SIZE(ring_control->rx_data);
+		i %= ring_limit;
 	}
 
 	wmb();
-	ring_control->host_idx[0] = cpu_to_le32(host_idx);
+	ring_control->host_idx[ring_index] = cpu_to_le32(idx);
+}
+
+static void p54p_check_rx_ring(struct ieee80211_hw *dev, u32 *index,
+	int ring_index, struct p54p_desc *ring, u32 ring_limit,
+	struct sk_buff **rx_buf)
+{
+	struct p54p_priv *priv = dev->priv;
+	struct p54p_ring_control *ring_control = priv->ring_control;
+	struct p54p_desc *desc;
+	u32 idx, i;
+
+	i = (*index) % ring_limit;
+	(*index) = idx = le32_to_cpu(ring_control->device_idx[ring_index]);
+	idx %= ring_limit;
+	while (i != idx) {
+		u16 len;
+		struct sk_buff *skb;
+		desc = &ring[i];
+		len = le16_to_cpu(desc->len);
+		skb = rx_buf[i];
+
+		if (!skb) {
+			i++;
+			i %= ring_limit;
+			continue;
+		}
+		skb_put(skb, len);
+
+		if (p54_rx(dev, skb)) {
+			pci_unmap_single(priv->pdev,
+					 le32_to_cpu(desc->host_addr),
+					 priv->common.rx_mtu + 32,
+					 PCI_DMA_FROMDEVICE);
+			rx_buf[i] = NULL;
+			desc->host_addr = 0;
+		} else {
+			skb_trim(skb, 0);
+			desc->len = cpu_to_le16(priv->common.rx_mtu + 32);
+		}
+
+		i++;
+		i %= ring_limit;
+	}
+
+	p54p_refill_rx_ring(dev, ring_index, ring, ring_limit, rx_buf);
+}
+
+/* caller must hold priv->lock */
+static void p54p_check_tx_ring(struct ieee80211_hw *dev, u32 *index,
+	int ring_index, struct p54p_desc *ring, u32 ring_limit,
+	void **tx_buf)
+{
+	struct p54p_priv *priv = dev->priv;
+	struct p54p_ring_control *ring_control = priv->ring_control;
+	struct p54p_desc *desc;
+	u32 idx, i;
+
+	i = (*index) % ring_limit;
+	(*index) = idx = le32_to_cpu(ring_control->device_idx[1]);
+	idx %= ring_limit;
+
+	while (i != idx) {
+		desc = &ring[i];
+		kfree(tx_buf[i]);
+		tx_buf[i] = NULL;
+
+		pci_unmap_single(priv->pdev, le32_to_cpu(desc->host_addr),
+				 le16_to_cpu(desc->len), PCI_DMA_TODEVICE);
+
+		desc->host_addr = 0;
+		desc->device_addr = 0;
+		desc->len = 0;
+		desc->flags = 0;
+
+		i++;
+		i %= ring_limit;
+	}
+}
+
+static void p54p_rx_tasklet(unsigned long dev_id)
+{
+	struct ieee80211_hw *dev = (struct ieee80211_hw *)dev_id;
+	struct p54p_priv *priv = dev->priv;
+	struct p54p_ring_control *ring_control = priv->ring_control;
+
+	p54p_check_rx_ring(dev, &priv->rx_idx_mgmt, 2, ring_control->rx_mgmt,
+		ARRAY_SIZE(ring_control->rx_mgmt), priv->rx_buf_mgmt);
+
+	p54p_check_rx_ring(dev, &priv->rx_idx_data, 0, ring_control->rx_data,
+		ARRAY_SIZE(ring_control->rx_data), priv->rx_buf_data);
+
+	wmb();
+	P54P_WRITE(dev_int, cpu_to_le32(ISL38XX_DEV_INT_UPDATE));
 }
 
 static irqreturn_t p54p_interrupt(int irq, void *dev_id)
@@ -298,65 +286,18 @@
 	reg &= P54P_READ(int_enable);
 
 	if (reg & cpu_to_le32(ISL38XX_INT_IDENT_UPDATE)) {
-		struct p54p_desc *desc;
-		u32 idx, i;
-		i = priv->tx_idx;
-		i %= ARRAY_SIZE(ring_control->tx_data);
-		priv->tx_idx = idx = le32_to_cpu(ring_control->device_idx[1]);
-		idx %= ARRAY_SIZE(ring_control->tx_data);
+		p54p_check_tx_ring(dev, &priv->tx_idx_mgmt,
+				   3, ring_control->tx_mgmt,
+				   ARRAY_SIZE(ring_control->tx_mgmt),
+				   priv->tx_buf_mgmt);
 
-		while (i != idx) {
-			desc = &ring_control->tx_data[i];
-			if (priv->tx_buf[i]) {
-				kfree(priv->tx_buf[i]);
-				priv->tx_buf[i] = NULL;
-			}
+		p54p_check_tx_ring(dev, &priv->tx_idx_data,
+				   1, ring_control->tx_data,
+				   ARRAY_SIZE(ring_control->tx_data),
+				   priv->tx_buf_data);
 
-			pci_unmap_single(priv->pdev, le32_to_cpu(desc->host_addr),
-					 le16_to_cpu(desc->len), PCI_DMA_TODEVICE);
+		tasklet_schedule(&priv->rx_tasklet);
 
-			desc->host_addr = 0;
-			desc->device_addr = 0;
-			desc->len = 0;
-			desc->flags = 0;
-
-			i++;
-			i %= ARRAY_SIZE(ring_control->tx_data);
-		}
-
-		i = priv->rx_idx;
-		i %= ARRAY_SIZE(ring_control->rx_data);
-		priv->rx_idx = idx = le32_to_cpu(ring_control->device_idx[0]);
-		idx %= ARRAY_SIZE(ring_control->rx_data);
-		while (i != idx) {
-			u16 len;
-			struct sk_buff *skb;
-			desc = &ring_control->rx_data[i];
-			len = le16_to_cpu(desc->len);
-			skb = priv->rx_buf[i];
-
-			skb_put(skb, len);
-
-			if (p54_rx(dev, skb)) {
-				pci_unmap_single(priv->pdev,
-						 le32_to_cpu(desc->host_addr),
-						 MAX_RX_SIZE, PCI_DMA_FROMDEVICE);
-
-				priv->rx_buf[i] = NULL;
-				desc->host_addr = 0;
-			} else {
-				skb_trim(skb, 0);
-				desc->len = cpu_to_le16(MAX_RX_SIZE);
-			}
-
-			i++;
-			i %= ARRAY_SIZE(ring_control->rx_data);
-		}
-
-		p54p_refill_rx_ring(dev);
-
-		wmb();
-		P54P_WRITE(dev_int, cpu_to_le32(ISL38XX_DEV_INT_UPDATE));
 	} else if (reg & cpu_to_le32(ISL38XX_INT_IDENT_INIT))
 		complete(&priv->boot_comp);
 
@@ -392,7 +333,7 @@
 	ring_control->host_idx[1] = cpu_to_le32(idx + 1);
 
 	if (free_on_tx)
-		priv->tx_buf[i] = data;
+		priv->tx_buf_data[i] = data;
 
 	spin_unlock_irqrestore(&priv->lock, flags);
 
@@ -412,7 +353,7 @@
 
 	init_completion(&priv->boot_comp);
 	err = request_irq(priv->pdev->irq, &p54p_interrupt,
-			  IRQF_SHARED, "prism54pci", dev);
+			  IRQF_SHARED, "p54pci", dev);
 	if (err) {
 		printk(KERN_ERR "%s: failed to register IRQ handler\n",
 		       wiphy_name(dev->wiphy));
@@ -420,10 +361,19 @@
 	}
 
 	memset(priv->ring_control, 0, sizeof(*priv->ring_control));
-	priv->rx_idx = priv->tx_idx = 0;
-	p54p_refill_rx_ring(dev);
+	err = p54p_upload_firmware(dev);
+	if (err) {
+		free_irq(priv->pdev->irq, dev);
+		return err;
+	}
+	priv->rx_idx_data = priv->tx_idx_data = 0;
+	priv->rx_idx_mgmt = priv->tx_idx_mgmt = 0;
 
-	p54p_upload_firmware(dev);
+	p54p_refill_rx_ring(dev, 0, priv->ring_control->rx_data,
+		ARRAY_SIZE(priv->ring_control->rx_data), priv->rx_buf_data);
+
+	p54p_refill_rx_ring(dev, 2, priv->ring_control->rx_mgmt,
+		ARRAY_SIZE(priv->ring_control->rx_mgmt), priv->rx_buf_mgmt);
 
 	P54P_WRITE(ring_control_base, cpu_to_le32(priv->ring_control_dma));
 	P54P_READ(ring_control_base);
@@ -465,6 +415,8 @@
 	unsigned int i;
 	struct p54p_desc *desc;
 
+	tasklet_kill(&priv->rx_tasklet);
+
 	P54P_WRITE(int_enable, cpu_to_le32(0));
 	P54P_READ(int_enable);
 	udelay(10);
@@ -473,26 +425,53 @@
 
 	P54P_WRITE(dev_int, cpu_to_le32(ISL38XX_DEV_INT_RESET));
 
-	for (i = 0; i < ARRAY_SIZE(priv->rx_buf); i++) {
+	for (i = 0; i < ARRAY_SIZE(priv->rx_buf_data); i++) {
 		desc = &ring_control->rx_data[i];
 		if (desc->host_addr)
-			pci_unmap_single(priv->pdev, le32_to_cpu(desc->host_addr),
-					 MAX_RX_SIZE, PCI_DMA_FROMDEVICE);
-		kfree_skb(priv->rx_buf[i]);
-		priv->rx_buf[i] = NULL;
+			pci_unmap_single(priv->pdev,
+					 le32_to_cpu(desc->host_addr),
+					 priv->common.rx_mtu + 32,
+					 PCI_DMA_FROMDEVICE);
+		kfree_skb(priv->rx_buf_data[i]);
+		priv->rx_buf_data[i] = NULL;
 	}
 
-	for (i = 0; i < ARRAY_SIZE(priv->tx_buf); i++) {
+	for (i = 0; i < ARRAY_SIZE(priv->rx_buf_mgmt); i++) {
+		desc = &ring_control->rx_mgmt[i];
+		if (desc->host_addr)
+			pci_unmap_single(priv->pdev,
+					 le32_to_cpu(desc->host_addr),
+					 priv->common.rx_mtu + 32,
+					 PCI_DMA_FROMDEVICE);
+		kfree_skb(priv->rx_buf_mgmt[i]);
+		priv->rx_buf_mgmt[i] = NULL;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(priv->tx_buf_data); i++) {
 		desc = &ring_control->tx_data[i];
 		if (desc->host_addr)
-			pci_unmap_single(priv->pdev, le32_to_cpu(desc->host_addr),
-					 le16_to_cpu(desc->len), PCI_DMA_TODEVICE);
+			pci_unmap_single(priv->pdev,
+					 le32_to_cpu(desc->host_addr),
+					 le16_to_cpu(desc->len),
+					 PCI_DMA_TODEVICE);
 
-		kfree(priv->tx_buf[i]);
-		priv->tx_buf[i] = NULL;
+		kfree(priv->tx_buf_data[i]);
+		priv->tx_buf_data[i] = NULL;
 	}
 
-	memset(ring_control, 0, sizeof(ring_control));
+	for (i = 0; i < ARRAY_SIZE(priv->tx_buf_mgmt); i++) {
+		desc = &ring_control->tx_mgmt[i];
+		if (desc->host_addr)
+			pci_unmap_single(priv->pdev,
+					 le32_to_cpu(desc->host_addr),
+					 le16_to_cpu(desc->len),
+					 PCI_DMA_TODEVICE);
+
+		kfree(priv->tx_buf_mgmt[i]);
+		priv->tx_buf_mgmt[i] = NULL;
+	}
+
+	memset(ring_control, 0, sizeof(*ring_control));
 }
 
 static int __devinit p54p_probe(struct pci_dev *pdev,
@@ -506,7 +485,7 @@
 
 	err = pci_enable_device(pdev);
 	if (err) {
-		printk(KERN_ERR "%s (prism54pci): Cannot enable new PCI device\n",
+		printk(KERN_ERR "%s (p54pci): Cannot enable new PCI device\n",
 		       pci_name(pdev));
 		return err;
 	}
@@ -514,22 +493,22 @@
 	mem_addr = pci_resource_start(pdev, 0);
 	mem_len = pci_resource_len(pdev, 0);
 	if (mem_len < sizeof(struct p54p_csr)) {
-		printk(KERN_ERR "%s (prism54pci): Too short PCI resources\n",
+		printk(KERN_ERR "%s (p54pci): Too short PCI resources\n",
 		       pci_name(pdev));
 		pci_disable_device(pdev);
 		return err;
 	}
 
-	err = pci_request_regions(pdev, "prism54pci");
+	err = pci_request_regions(pdev, "p54pci");
 	if (err) {
-		printk(KERN_ERR "%s (prism54pci): Cannot obtain PCI resources\n",
+		printk(KERN_ERR "%s (p54pci): Cannot obtain PCI resources\n",
 		       pci_name(pdev));
 		return err;
 	}
 
 	if (pci_set_dma_mask(pdev, DMA_32BIT_MASK) ||
 	    pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK)) {
-		printk(KERN_ERR "%s (prism54pci): No suitable DMA available\n",
+		printk(KERN_ERR "%s (p54pci): No suitable DMA available\n",
 		       pci_name(pdev));
 		goto err_free_reg;
 	}
@@ -542,7 +521,7 @@
 
 	dev = p54_init_common(sizeof(*priv));
 	if (!dev) {
-		printk(KERN_ERR "%s (prism54pci): ieee80211 alloc failed\n",
+		printk(KERN_ERR "%s (p54pci): ieee80211 alloc failed\n",
 		       pci_name(pdev));
 		err = -ENOMEM;
 		goto err_free_reg;
@@ -556,7 +535,7 @@
 
 	priv->map = ioremap(mem_addr, mem_len);
 	if (!priv->map) {
-		printk(KERN_ERR "%s (prism54pci): Cannot map device memory\n",
+		printk(KERN_ERR "%s (p54pci): Cannot map device memory\n",
 		       pci_name(pdev));
 		err = -EINVAL;	// TODO: use a better error code?
 		goto err_free_dev;
@@ -565,39 +544,31 @@
 	priv->ring_control = pci_alloc_consistent(pdev, sizeof(*priv->ring_control),
 						  &priv->ring_control_dma);
 	if (!priv->ring_control) {
-		printk(KERN_ERR "%s (prism54pci): Cannot allocate rings\n",
+		printk(KERN_ERR "%s (p54pci): Cannot allocate rings\n",
 		       pci_name(pdev));
 		err = -ENOMEM;
 		goto err_iounmap;
 	}
-	memset(priv->ring_control, 0, sizeof(*priv->ring_control));
-
-	err = p54p_upload_firmware(dev);
-	if (err)
-		goto err_free_desc;
-
-	err = p54p_read_eeprom(dev);
-	if (err)
-		goto err_free_desc;
-
 	priv->common.open = p54p_open;
 	priv->common.stop = p54p_stop;
 	priv->common.tx = p54p_tx;
 
 	spin_lock_init(&priv->lock);
+	tasklet_init(&priv->rx_tasklet, p54p_rx_tasklet, (unsigned long)dev);
+
+	p54p_open(dev);
+	err = p54_read_eeprom(dev);
+	p54p_stop(dev);
+	if (err)
+		goto err_free_desc;
 
 	err = ieee80211_register_hw(dev);
 	if (err) {
-		printk(KERN_ERR "%s (prism54pci): Cannot register netdevice\n",
+		printk(KERN_ERR "%s (p54pci): Cannot register netdevice\n",
 		       pci_name(pdev));
 		goto err_free_common;
 	}
 
-	printk(KERN_INFO "%s: hwaddr %s, isl38%02x\n",
-	       wiphy_name(dev->wiphy),
-	       print_mac(mac, dev->wiphy->perm_addr),
-	       priv->common.version);
-
 	return 0;
 
  err_free_common:
@@ -645,7 +616,7 @@
 	struct ieee80211_hw *dev = pci_get_drvdata(pdev);
 	struct p54p_priv *priv = dev->priv;
 
-	if (priv->common.mode != IEEE80211_IF_TYPE_INVALID) {
+	if (priv->common.mode != NL80211_IFTYPE_UNSPECIFIED) {
 		ieee80211_stop_queues(dev);
 		p54p_stop(dev);
 	}
@@ -663,7 +634,7 @@
 	pci_set_power_state(pdev, PCI_D0);
 	pci_restore_state(pdev);
 
-	if (priv->common.mode != IEEE80211_IF_TYPE_INVALID) {
+	if (priv->common.mode != NL80211_IFTYPE_UNSPECIFIED) {
 		p54p_open(dev);
 		ieee80211_wake_queues(dev);
 	}
@@ -673,7 +644,7 @@
 #endif /* CONFIG_PM */
 
 static struct pci_driver p54p_driver = {
-	.name		= "prism54pci",
+	.name		= "p54pci",
 	.id_table	= p54p_table,
 	.probe		= p54p_probe,
 	.remove		= __devexit_p(p54p_remove),
diff --git a/drivers/net/wireless/p54/p54pci.h b/drivers/net/wireless/p54/p54pci.h
index 5bedd7a..4a67780 100644
--- a/drivers/net/wireless/p54/p54pci.h
+++ b/drivers/net/wireless/p54/p54pci.h
@@ -1,5 +1,5 @@
-#ifndef PRISM54PCI_H
-#define PRISM54PCI_H
+#ifndef P54PCI_H
+#define P54PCI_H
 
 /*
  * Defines for PCI based mac80211 Prism54 driver
@@ -68,7 +68,7 @@
 } __attribute__ ((packed));
 
 /* usb backend only needs the register defines above */
-#ifndef PRISM54USB_H
+#ifndef P54USB_H
 struct p54p_desc {
 	__le32 host_addr;
 	__le32 device_addr;
@@ -92,15 +92,19 @@
 	struct p54_common common;
 	struct pci_dev *pdev;
 	struct p54p_csr __iomem *map;
+	struct tasklet_struct rx_tasklet;
 
 	spinlock_t lock;
 	struct p54p_ring_control *ring_control;
 	dma_addr_t ring_control_dma;
-	u32 rx_idx, tx_idx;
-	struct sk_buff *rx_buf[8];
-	void *tx_buf[32];
+	u32 rx_idx_data, tx_idx_data;
+	u32 rx_idx_mgmt, tx_idx_mgmt;
+	struct sk_buff *rx_buf_data[8];
+	struct sk_buff *rx_buf_mgmt[4];
+	void *tx_buf_data[32];
+	void *tx_buf_mgmt[4];
 	struct completion boot_comp;
 };
 
-#endif /* PRISM54USB_H */
-#endif /* PRISM54PCI_H */
+#endif /* P54USB_H */
+#endif /* P54PCI_H */
diff --git a/drivers/net/wireless/p54/p54usb.c b/drivers/net/wireless/p54/p54usb.c
index cbaca23..1912f5e 100644
--- a/drivers/net/wireless/p54/p54usb.c
+++ b/drivers/net/wireless/p54/p54usb.c
@@ -91,11 +91,16 @@
 
 	skb_unlink(skb, &priv->rx_queue);
 	skb_put(skb, urb->actual_length);
-	if (!priv->hw_type)
-		skb_pull(skb, sizeof(struct net2280_tx_hdr));
+
+	if (priv->hw_type == P54U_NET2280)
+		skb_pull(skb, priv->common.tx_hdr_len);
+	if (priv->common.fw_interface == FW_LM87) {
+		skb_pull(skb, 4);
+		skb_put(skb, 4);
+	}
 
 	if (p54_rx(dev, skb)) {
-		skb = dev_alloc_skb(MAX_RX_SIZE);
+		skb = dev_alloc_skb(priv->common.rx_mtu + 32);
 		if (unlikely(!skb)) {
 			usb_free_urb(urb);
 			/* TODO check rx queue length and refill *somewhere* */
@@ -109,9 +114,12 @@
 		urb->context = skb;
 		skb_queue_tail(&priv->rx_queue, skb);
 	} else {
-		if (!priv->hw_type)
-			skb_push(skb, sizeof(struct net2280_tx_hdr));
-
+		if (priv->hw_type == P54U_NET2280)
+			skb_push(skb, priv->common.tx_hdr_len);
+		if (priv->common.fw_interface == FW_LM87) {
+			skb_push(skb, 4);
+			skb_put(skb, 4);
+		}
 		skb_reset_tail_pointer(skb);
 		skb_trim(skb, 0);
 		if (urb->transfer_buffer != skb_tail_pointer(skb)) {
@@ -145,7 +153,7 @@
 	struct p54u_rx_info *info;
 
 	while (skb_queue_len(&priv->rx_queue) < 32) {
-		skb = __dev_alloc_skb(MAX_RX_SIZE, GFP_KERNEL);
+		skb = __dev_alloc_skb(priv->common.rx_mtu + 32, GFP_KERNEL);
 		if (!skb)
 			break;
 		entry = usb_alloc_urb(0, GFP_KERNEL);
@@ -153,7 +161,10 @@
 			kfree_skb(skb);
 			break;
 		}
-		usb_fill_bulk_urb(entry, priv->udev, usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA), skb_tail_pointer(skb), MAX_RX_SIZE, p54u_rx_cb, skb);
+		usb_fill_bulk_urb(entry, priv->udev,
+				  usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA),
+				  skb_tail_pointer(skb),
+				  priv->common.rx_mtu + 32, p54u_rx_cb, skb);
 		info = (struct p54u_rx_info *) skb->cb;
 		info->urb = entry;
 		info->dev = dev;
@@ -207,6 +218,42 @@
 	usb_submit_urb(data_urb, GFP_ATOMIC);
 }
 
+static __le32 p54u_lm87_chksum(const u32 *data, size_t length)
+{
+	u32 chk = 0;
+
+	length >>= 2;
+	while (length--) {
+		chk ^= *data++;
+		chk = (chk >> 5) ^ (chk << 3);
+	}
+
+	return cpu_to_le32(chk);
+}
+
+static void p54u_tx_lm87(struct ieee80211_hw *dev,
+			 struct p54_control_hdr *data,
+			 size_t len, int free_on_tx)
+{
+	struct p54u_priv *priv = dev->priv;
+	struct urb *data_urb;
+	struct lm87_tx_hdr *hdr = (void *)data - sizeof(*hdr);
+
+	data_urb = usb_alloc_urb(0, GFP_ATOMIC);
+	if (!data_urb)
+		return;
+
+	hdr->chksum = p54u_lm87_chksum((u32 *)data, len);
+	hdr->device_addr = data->req_id;
+
+	usb_fill_bulk_urb(data_urb, priv->udev,
+		usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA), hdr,
+		len + sizeof(*hdr), free_on_tx ? p54u_tx_free_cb : p54u_tx_cb,
+		dev);
+
+	usb_submit_urb(data_urb, GFP_ATOMIC);
+}
+
 static void p54u_tx_net2280(struct ieee80211_hw *dev, struct p54_control_hdr *data,
 			    size_t len, int free_on_tx)
 {
@@ -312,73 +359,6 @@
 			    data, len, &alen, 2000);
 }
 
-static int p54u_read_eeprom(struct ieee80211_hw *dev)
-{
-	struct p54u_priv *priv = dev->priv;
-	void *buf;
-	struct p54_control_hdr *hdr;
-	int err, alen;
-	size_t offset = priv->hw_type ? 0x10 : 0x20;
-
-	buf = kmalloc(0x2020, GFP_KERNEL);
-	if (!buf) {
-		printk(KERN_ERR "prism54usb: cannot allocate memory for "
-		       "eeprom readback!\n");
-		return -ENOMEM;
-	}
-
-	if (priv->hw_type) {
-		*((u32 *) buf) = priv->common.rx_start;
-		err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, sizeof(u32));
-		if (err) {
-			printk(KERN_ERR "prism54usb: addr send failed\n");
-			goto fail;
-		}
-	} else {
-		struct net2280_reg_write *reg = buf;
-		reg->port = cpu_to_le16(NET2280_DEV_U32);
-		reg->addr = cpu_to_le32(P54U_DEV_BASE);
-		reg->val = cpu_to_le32(ISL38XX_DEV_INT_DATA);
-		err = p54u_bulk_msg(priv, P54U_PIPE_DEV, buf, sizeof(*reg));
-		if (err) {
-			printk(KERN_ERR "prism54usb: dev_int send failed\n");
-			goto fail;
-		}
-	}
-
-	hdr = buf + priv->common.tx_hdr_len;
-	p54_fill_eeprom_readback(hdr);
-	hdr->req_id = cpu_to_le32(priv->common.rx_start);
-	if (priv->common.tx_hdr_len) {
-		struct net2280_tx_hdr *tx_hdr = buf;
-		tx_hdr->device_addr = hdr->req_id;
-		tx_hdr->len = cpu_to_le16(EEPROM_READBACK_LEN);
-	}
-
-	/* we can just pretend to send 0x2000 bytes of nothing in the headers */
-	err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf,
-			    EEPROM_READBACK_LEN + priv->common.tx_hdr_len);
-	if (err) {
-		printk(KERN_ERR "prism54usb: eeprom req send failed\n");
-		goto fail;
-	}
-
-	err = usb_bulk_msg(priv->udev,
-			   usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA),
-			   buf, 0x2020, &alen, 1000);
-	if (!err && alen > offset) {
-		p54_parse_eeprom(dev, (u8 *)buf + offset, alen - offset);
-	} else {
-		printk(KERN_ERR "prism54usb: eeprom read failed!\n");
-		err = -EINVAL;
-		goto fail;
-	}
-
- fail:
-	kfree(buf);
-	return err;
-}
-
 static int p54u_upload_firmware_3887(struct ieee80211_hw *dev)
 {
 	static char start_string[] = "~~~~<\r";
@@ -412,7 +392,9 @@
 		goto err_req_fw_failed;
 	}
 
-	p54_parse_firmware(dev, fw_entry);
+	err = p54_parse_firmware(dev, fw_entry);
+	if (err)
+		goto err_upload_failed;
 
 	left = block_size = min((size_t)P54U_FW_BLOCK, fw_entry->size);
 	strcpy(buf, start_string);
@@ -458,7 +440,7 @@
 
 		err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, block_size);
 		if (err) {
-			printk(KERN_ERR "prism54usb: firmware upload failed!\n");
+			printk(KERN_ERR "p54usb: firmware upload failed!\n");
 			goto err_upload_failed;
 		}
 
@@ -469,7 +451,7 @@
 	*((__le32 *)buf) = cpu_to_le32(~crc32_le(~0, fw_entry->data, fw_entry->size));
 	err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, sizeof(u32));
 	if (err) {
-		printk(KERN_ERR "prism54usb: firmware upload failed!\n");
+		printk(KERN_ERR "p54usb: firmware upload failed!\n");
 		goto err_upload_failed;
 	}
 
@@ -480,13 +462,13 @@
 			break;
 
 		if (alen > 5 && !memcmp(buf, "ERROR", 5)) {
-			printk(KERN_INFO "prism54usb: firmware upload failed!\n");
+			printk(KERN_INFO "p54usb: firmware upload failed!\n");
 			err = -EINVAL;
 			break;
 		}
 
 		if (time_after(jiffies, timeout)) {
-			printk(KERN_ERR "prism54usb: firmware boot timed out!\n");
+			printk(KERN_ERR "p54usb: firmware boot timed out!\n");
 			err = -ETIMEDOUT;
 			break;
 		}
@@ -498,7 +480,7 @@
 	buf[1] = '\r';
 	err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, 2);
 	if (err) {
-		printk(KERN_ERR "prism54usb: firmware boot failed!\n");
+		printk(KERN_ERR "p54usb: firmware boot failed!\n");
 		goto err_upload_failed;
 	}
 
@@ -549,7 +531,12 @@
 		return err;
 	}
 
-	p54_parse_firmware(dev, fw_entry);
+	err = p54_parse_firmware(dev, fw_entry);
+	if (err) {
+		kfree(buf);
+		release_firmware(fw_entry);
+		return err;
+	}
 
 #define P54U_WRITE(type, addr, data) \
 	do {\
@@ -660,7 +647,7 @@
 
 		err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, block_len);
 		if (err) {
-			printk(KERN_ERR "prism54usb: firmware block upload "
+			printk(KERN_ERR "p54usb: firmware block upload "
 			       "failed\n");
 			goto fail;
 		}
@@ -694,7 +681,7 @@
 			  0x002C | (unsigned long)&devreg->direct_mem_win);
 		if (!(reg & cpu_to_le32(ISL38XX_DMA_STATUS_DONE)) ||
 		    !(reg & cpu_to_le32(ISL38XX_DMA_STATUS_READY))) {
-			printk(KERN_ERR "prism54usb: firmware DMA transfer "
+			printk(KERN_ERR "p54usb: firmware DMA transfer "
 			       "failed\n");
 			goto fail;
 		}
@@ -802,7 +789,7 @@
 
 	dev = p54_init_common(sizeof(*priv));
 	if (!dev) {
-		printk(KERN_ERR "prism54usb: ieee80211 alloc failed\n");
+		printk(KERN_ERR "p54usb: ieee80211 alloc failed\n");
 		return -ENOMEM;
 	}
 
@@ -833,49 +820,40 @@
 		}
 	}
 	priv->common.open = p54u_open;
-
+	priv->common.stop = p54u_stop;
 	if (recognized_pipes < P54U_PIPE_NUMBER) {
 		priv->hw_type = P54U_3887;
-		priv->common.tx = p54u_tx_3887;
+		err = p54u_upload_firmware_3887(dev);
+		if (priv->common.fw_interface == FW_LM87) {
+			dev->extra_tx_headroom += sizeof(struct lm87_tx_hdr);
+			priv->common.tx_hdr_len = sizeof(struct lm87_tx_hdr);
+			priv->common.tx = p54u_tx_lm87;
+		} else
+			priv->common.tx = p54u_tx_3887;
 	} else {
+		priv->hw_type = P54U_NET2280;
 		dev->extra_tx_headroom += sizeof(struct net2280_tx_hdr);
 		priv->common.tx_hdr_len = sizeof(struct net2280_tx_hdr);
 		priv->common.tx = p54u_tx_net2280;
-	}
-	priv->common.stop = p54u_stop;
-
-	if (priv->hw_type)
-		err = p54u_upload_firmware_3887(dev);
-	else
 		err = p54u_upload_firmware_net2280(dev);
-	if (err)
-		goto err_free_dev;
-
-	err = p54u_read_eeprom(dev);
-	if (err)
-		goto err_free_dev;
-
-	if (!is_valid_ether_addr(dev->wiphy->perm_addr)) {
-		u8 perm_addr[ETH_ALEN];
-
-		printk(KERN_WARNING "prism54usb: Invalid hwaddr! Using randomly generated MAC addr\n");
-		random_ether_addr(perm_addr);
-		SET_IEEE80211_PERM_ADDR(dev, perm_addr);
 	}
+	if (err)
+		goto err_free_dev;
 
 	skb_queue_head_init(&priv->rx_queue);
 
+	p54u_open(dev);
+	err = p54_read_eeprom(dev);
+	p54u_stop(dev);
+	if (err)
+		goto err_free_dev;
+
 	err = ieee80211_register_hw(dev);
 	if (err) {
-		printk(KERN_ERR "prism54usb: Cannot register netdevice\n");
+		printk(KERN_ERR "p54usb: Cannot register netdevice\n");
 		goto err_free_dev;
 	}
 
-	printk(KERN_INFO "%s: hwaddr %s, isl38%02x\n",
-	       wiphy_name(dev->wiphy),
-	       print_mac(mac, dev->wiphy->perm_addr),
-	       priv->common.version);
-
 	return 0;
 
  err_free_dev:
@@ -902,7 +880,7 @@
 }
 
 static struct usb_driver p54u_driver = {
-	.name	= "prism54usb",
+	.name	= "p54usb",
 	.id_table = p54u_table,
 	.probe = p54u_probe,
 	.disconnect = p54u_disconnect,
diff --git a/drivers/net/wireless/p54/p54usb.h b/drivers/net/wireless/p54/p54usb.h
index d1896b3..5b8fe91 100644
--- a/drivers/net/wireless/p54/p54usb.h
+++ b/drivers/net/wireless/p54/p54usb.h
@@ -1,5 +1,5 @@
-#ifndef PRISM54USB_H
-#define PRISM54USB_H
+#ifndef P54USB_H
+#define P54USB_H
 
 /*
  * Defines for USB based mac80211 Prism54 driver
@@ -72,6 +72,11 @@
 	u8 padding[8];
 } __attribute__((packed));
 
+struct lm87_tx_hdr {
+	__le32 device_addr;
+	__le32 chksum;
+} __attribute__((packed));
+
 /* Some flags for the isl hardware registers controlling DMA inside the
  * chip */
 #define ISL38XX_DMA_STATUS_DONE			0x00000001
@@ -130,4 +135,4 @@
 	struct sk_buff_head rx_queue;
 };
 
-#endif /* PRISM54USB_H */
+#endif /* P54USB_H */
diff --git a/drivers/net/wireless/prism54/isl_ioctl.c b/drivers/net/wireless/prism54/isl_ioctl.c
index 3d75a71..16e68f4 100644
--- a/drivers/net/wireless/prism54/isl_ioctl.c
+++ b/drivers/net/wireless/prism54/isl_ioctl.c
@@ -71,7 +71,7 @@
 	if (iw_mode == IW_MODE_REPEAT || iw_mode == IW_MODE_SECOND) {
 		printk(KERN_DEBUG
 		       "%s(): Sorry, Repeater mode and Secondary mode "
-		       "are not yet supported by this driver.\n", __FUNCTION__);
+		       "are not yet supported by this driver.\n", __func__);
 		return -EINVAL;
 	}
 
@@ -333,7 +333,7 @@
 	if (*uwrq > IW_MODE_MONITOR || *uwrq < IW_MODE_AUTO) {
 		printk(KERN_DEBUG
 		       "%s: %s() You passed a non-valid init_mode.\n",
-		       priv->ndev->name, __FUNCTION__);
+		       priv->ndev->name, __func__);
 		return -EINVAL;
 	}
 
@@ -1234,7 +1234,7 @@
 		/* don't know how to disable radio */
 		printk(KERN_DEBUG
 		       "%s: %s() disabling radio is not yet supported.\n",
-		       priv->ndev->name, __FUNCTION__);
+		       priv->ndev->name, __func__);
 		return -ENOTSUPP;
 	} else if (vwrq->fixed)
 		/* currently only fixed value is supported */
@@ -1242,7 +1242,7 @@
 	else {
 		printk(KERN_DEBUG
 		       "%s: %s() auto power will be implemented later.\n",
-		       priv->ndev->name, __FUNCTION__);
+		       priv->ndev->name, __func__);
 		return -ENOTSUPP;
 	}
 }
diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c
index 963960d..1404a57 100644
--- a/drivers/net/wireless/ray_cs.c
+++ b/drivers/net/wireless/ray_cs.c
@@ -325,7 +325,7 @@
     p_dev->io.IOAddrLines = 5;
 
     /* Interrupt setup. For PCMCIA, driver takes what's given */
-    p_dev->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT;
+    p_dev->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING | IRQ_HANDLE_PRESENT;
     p_dev->irq.IRQInfo1 = IRQ_LEVEL_ID;
     p_dev->irq.Handler = &ray_interrupt;
 
@@ -798,9 +798,9 @@
     iounmap(local->amem);
     /* Do bother checking to see if these succeed or not */
     i = pcmcia_release_window(local->amem_handle);
-    if ( i != CS_SUCCESS ) DEBUG(0,"ReleaseWindow(local->amem) ret = %x\n",i);
+    if ( i != 0 ) DEBUG(0,"ReleaseWindow(local->amem) ret = %x\n",i);
     i = pcmcia_release_window(local->rmem_handle);
-    if ( i != CS_SUCCESS ) DEBUG(0,"ReleaseWindow(local->rmem) ret = %x\n",i);
+    if ( i != 0 ) DEBUG(0,"ReleaseWindow(local->rmem) ret = %x\n",i);
     pcmcia_disable_device(link);
 
     DEBUG(2,"ray_release ending\n");
diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c
index 00e965b..2b41489 100644
--- a/drivers/net/wireless/rndis_wlan.c
+++ b/drivers/net/wireless/rndis_wlan.c
@@ -1627,7 +1627,6 @@
 static int rndis_iw_set_scan(struct net_device *dev,
     struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
 {
-	struct iw_param *param = &wrqu->param;
 	struct usbnet *usbdev = dev->priv;
 	union iwreq_data evt;
 	int ret = -EINVAL;
@@ -1635,7 +1634,7 @@
 
 	devdbg(usbdev, "SIOCSIWSCAN");
 
-	if (param->flags == 0) {
+	if (wrqu->data.flags == 0) {
 		tmp = ccpu2(1);
 		ret = rndis_set_oid(usbdev, OID_802_11_BSSID_LIST_SCAN, &tmp,
 								sizeof(tmp));
diff --git a/drivers/net/wireless/rt2x00/Kconfig b/drivers/net/wireless/rt2x00/Kconfig
index d485a86..f839ce0 100644
--- a/drivers/net/wireless/rt2x00/Kconfig
+++ b/drivers/net/wireless/rt2x00/Kconfig
@@ -1,5 +1,5 @@
-config RT2X00
-	tristate "Ralink driver support"
+menuconfig RT2X00
+	bool "Ralink driver support"
 	depends on MAC80211 && WLAN_80211 && EXPERIMENTAL
 	---help---
 	  This will enable the experimental support for the Ralink drivers,
@@ -17,31 +17,6 @@
 
 if RT2X00
 
-config RT2X00_LIB
-	tristate
-
-config RT2X00_LIB_PCI
-	tristate
-	select RT2X00_LIB
-
-config RT2X00_LIB_USB
-	tristate
-	select RT2X00_LIB
-
-config RT2X00_LIB_FIRMWARE
-	boolean
-	depends on RT2X00_LIB
-	select FW_LOADER
-
-config RT2X00_LIB_RFKILL
-	boolean
-	depends on RT2X00_LIB
-	select RFKILL
-
-config RT2X00_LIB_LEDS
-	boolean
-	depends on RT2X00_LIB && NEW_LEDS
-
 config RT2400PCI
 	tristate "Ralink rt2400 (PCI/PCMCIA) support"
 	depends on PCI
@@ -53,23 +28,6 @@
 
 	  When compiled as a module, this driver will be called "rt2400pci.ko".
 
-config RT2400PCI_RFKILL
-	bool "Ralink rt2400 rfkill support"
-	depends on RT2400PCI
-	select RT2X00_LIB_RFKILL
-	---help---
-	  This adds support for integrated rt2400 hardware that features a
-	  hardware button to control the radio state.
-	  This feature depends on the RF switch subsystem rfkill.
-
-config RT2400PCI_LEDS
-	bool "Ralink rt2400 leds support"
-	depends on RT2400PCI && NEW_LEDS
-	select LEDS_CLASS
-	select RT2X00_LIB_LEDS
-	---help---
-	  This adds support for led triggers provided my mac80211.
-
 config RT2500PCI
 	tristate "Ralink rt2500 (PCI/PCMCIA) support"
 	depends on PCI
@@ -81,28 +39,12 @@
 
 	  When compiled as a module, this driver will be called "rt2500pci.ko".
 
-config RT2500PCI_RFKILL
-	bool "Ralink rt2500 rfkill support"
-	depends on RT2500PCI
-	select RT2X00_LIB_RFKILL
-	---help---
-	  This adds support for integrated rt2500 hardware that features a
-	  hardware button to control the radio state.
-	  This feature depends on the RF switch subsystem rfkill.
-
-config RT2500PCI_LEDS
-	bool "Ralink rt2500 leds support"
-	depends on RT2500PCI && NEW_LEDS
-	select LEDS_CLASS
-	select RT2X00_LIB_LEDS
-	---help---
-	  This adds support for led triggers provided my mac80211.
-
 config RT61PCI
 	tristate "Ralink rt2501/rt61 (PCI/PCMCIA) support"
 	depends on PCI
 	select RT2X00_LIB_PCI
 	select RT2X00_LIB_FIRMWARE
+	select RT2X00_LIB_CRYPTO
 	select CRC_ITU_T
 	select EEPROM_93CX6
 	---help---
@@ -111,23 +53,6 @@
 
 	  When compiled as a module, this driver will be called "rt61pci.ko".
 
-config RT61PCI_RFKILL
-	bool "Ralink rt2501/rt61 rfkill support"
-	depends on RT61PCI
-	select RT2X00_LIB_RFKILL
-	---help---
-	  This adds support for integrated rt61 hardware that features a
-	  hardware button to control the radio state.
-	  This feature depends on the RF switch subsystem rfkill.
-
-config RT61PCI_LEDS
-	bool "Ralink rt2501/rt61 leds support"
-	depends on RT61PCI && NEW_LEDS
-	select LEDS_CLASS
-	select RT2X00_LIB_LEDS
-	---help---
-	  This adds support for led triggers provided my mac80211.
-
 config RT2500USB
 	tristate "Ralink rt2500 (USB) support"
 	depends on USB
@@ -138,19 +63,12 @@
 
 	  When compiled as a module, this driver will be called "rt2500usb.ko".
 
-config RT2500USB_LEDS
-	bool "Ralink rt2500 leds support"
-	depends on RT2500USB && NEW_LEDS
-	select LEDS_CLASS
-	select RT2X00_LIB_LEDS
-	---help---
-	  This adds support for led triggers provided my mac80211.
-
 config RT73USB
 	tristate "Ralink rt2501/rt73 (USB) support"
 	depends on USB
 	select RT2X00_LIB_USB
 	select RT2X00_LIB_FIRMWARE
+	select RT2X00_LIB_CRYPTO
 	select CRC_ITU_T
 	---help---
 	  This adds support for rt2501 wireless chipset family.
@@ -158,13 +76,37 @@
 
 	  When compiled as a module, this driver will be called "rt73usb.ko".
 
-config RT73USB_LEDS
-	bool "Ralink rt2501/rt73 leds support"
-	depends on RT73USB && NEW_LEDS
-	select LEDS_CLASS
-	select RT2X00_LIB_LEDS
-	---help---
-	  This adds support for led triggers provided my mac80211.
+config RT2X00_LIB_PCI
+	tristate
+	select RT2X00_LIB
+
+config RT2X00_LIB_USB
+	tristate
+	select RT2X00_LIB
+
+config RT2X00_LIB
+	tristate
+
+config RT2X00_LIB_FIRMWARE
+	boolean
+	select FW_LOADER
+
+config RT2X00_LIB_CRYPTO
+	boolean
+
+config RT2X00_LIB_RFKILL
+	boolean
+	default y if (RT2X00_LIB=y && RFKILL=y) || (RT2X00_LIB=m && RFKILL!=n)
+
+comment "rt2x00 rfkill support disabled due to modularized RFKILL and built-in rt2x00"
+	depends on RT2X00_LIB=y && RFKILL=m
+
+config RT2X00_LIB_LEDS
+	boolean
+	default y if (RT2X00_LIB=y && LEDS_CLASS=y) || (RT2X00_LIB=m && LEDS_CLASS!=n)
+
+comment "rt2x00 leds support disabled due to modularized LEDS_CLASS and built-in rt2x00"
+	depends on RT2X00_LIB=y && LEDS_CLASS=m
 
 config RT2X00_LIB_DEBUGFS
 	bool "Ralink debugfs support"
diff --git a/drivers/net/wireless/rt2x00/Makefile b/drivers/net/wireless/rt2x00/Makefile
index 1087dbc..917cb4f 100644
--- a/drivers/net/wireless/rt2x00/Makefile
+++ b/drivers/net/wireless/rt2x00/Makefile
@@ -3,6 +3,7 @@
 rt2x00lib-y				+= rt2x00config.o
 rt2x00lib-y				+= rt2x00queue.o
 rt2x00lib-$(CONFIG_RT2X00_LIB_DEBUGFS)	+= rt2x00debug.o
+rt2x00lib-$(CONFIG_RT2X00_LIB_CRYPTO)	+= rt2x00crypto.o
 rt2x00lib-$(CONFIG_RT2X00_LIB_RFKILL)	+= rt2x00rfkill.o
 rt2x00lib-$(CONFIG_RT2X00_LIB_FIRMWARE)	+= rt2x00firmware.o
 rt2x00lib-$(CONFIG_RT2X00_LIB_LEDS)	+= rt2x00leds.o
diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c
index 4c0538d..08cb9ee 100644
--- a/drivers/net/wireless/rt2x00/rt2400pci.c
+++ b/drivers/net/wireless/rt2x00/rt2400pci.c
@@ -231,7 +231,7 @@
 };
 #endif /* CONFIG_RT2X00_LIB_DEBUGFS */
 
-#ifdef CONFIG_RT2400PCI_RFKILL
+#ifdef CONFIG_RT2X00_LIB_RFKILL
 static int rt2400pci_rfkill_poll(struct rt2x00_dev *rt2x00dev)
 {
 	u32 reg;
@@ -241,9 +241,9 @@
 }
 #else
 #define rt2400pci_rfkill_poll	NULL
-#endif /* CONFIG_RT2400PCI_RFKILL */
+#endif /* CONFIG_RT2X00_LIB_RFKILL */
 
-#ifdef CONFIG_RT2400PCI_LEDS
+#ifdef CONFIG_RT2X00_LIB_LEDS
 static void rt2400pci_brightness_set(struct led_classdev *led_cdev,
 				     enum led_brightness brightness)
 {
@@ -288,7 +288,7 @@
 	led->led_dev.blink_set = rt2400pci_blink_set;
 	led->flags = LED_INITIALIZED;
 }
-#endif /* CONFIG_RT2400PCI_LEDS */
+#endif /* CONFIG_RT2X00_LIB_LEDS */
 
 /*
  * Configuration handlers.
@@ -1241,7 +1241,7 @@
 	if (!reg)
 		return IRQ_NONE;
 
-	if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags))
+	if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
 		return IRQ_HANDLED;
 
 	/*
@@ -1374,22 +1374,22 @@
 	/*
 	 * Store led mode, for correct led behaviour.
 	 */
-#ifdef CONFIG_RT2400PCI_LEDS
+#ifdef CONFIG_RT2X00_LIB_LEDS
 	value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_LED_MODE);
 
 	rt2400pci_init_led(rt2x00dev, &rt2x00dev->led_radio, LED_TYPE_RADIO);
 	if (value == LED_MODE_TXRX_ACTIVITY)
 		rt2400pci_init_led(rt2x00dev, &rt2x00dev->led_qual,
 				   LED_TYPE_ACTIVITY);
-#endif /* CONFIG_RT2400PCI_LEDS */
+#endif /* CONFIG_RT2X00_LIB_LEDS */
 
 	/*
 	 * Detect if this device has an hardware controlled radio.
 	 */
-#ifdef CONFIG_RT2400PCI_RFKILL
+#ifdef CONFIG_RT2X00_LIB_RFKILL
 	if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_HARDWARE_RADIO))
 		__set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags);
-#endif /* CONFIG_RT2400PCI_RFKILL */
+#endif /* CONFIG_RT2X00_LIB_RFKILL */
 
 	/*
 	 * Check if the BBP tuning should be enabled.
@@ -1404,7 +1404,7 @@
  * RF value list for RF2420 & RF2421
  * Supports: 2.4 GHz
  */
-static const struct rf_channel rf_vals_bg[] = {
+static const struct rf_channel rf_vals_b[] = {
 	{ 1,  0x00022058, 0x000c1fda, 0x00000101, 0 },
 	{ 2,  0x00022058, 0x000c1fee, 0x00000101, 0 },
 	{ 3,  0x00022058, 0x000c2002, 0x00000101, 0 },
@@ -1421,10 +1421,11 @@
 	{ 14, 0x00022058, 0x000c20fa, 0x00000101, 0 },
 };
 
-static void rt2400pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
+static int rt2400pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
 {
 	struct hw_mode_spec *spec = &rt2x00dev->spec;
-	u8 *txpower;
+	struct channel_info *info;
+	char *tx_power;
 	unsigned int i;
 
 	/*
@@ -1440,23 +1441,28 @@
 						   EEPROM_MAC_ADDR_0));
 
 	/*
-	 * Convert tx_power array in eeprom.
-	 */
-	txpower = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_START);
-	for (i = 0; i < 14; i++)
-		txpower[i] = TXPOWER_FROM_DEV(txpower[i]);
-
-	/*
 	 * Initialize hw_mode information.
 	 */
 	spec->supported_bands = SUPPORT_BAND_2GHZ;
 	spec->supported_rates = SUPPORT_RATE_CCK;
-	spec->tx_power_a = NULL;
-	spec->tx_power_bg = txpower;
-	spec->tx_power_default = DEFAULT_TXPOWER;
 
-	spec->num_channels = ARRAY_SIZE(rf_vals_bg);
-	spec->channels = rf_vals_bg;
+	spec->num_channels = ARRAY_SIZE(rf_vals_b);
+	spec->channels = rf_vals_b;
+
+	/*
+	 * Create channel information array
+	 */
+	info = kzalloc(spec->num_channels * sizeof(*info), GFP_KERNEL);
+	if (!info)
+		return -ENOMEM;
+
+	spec->channels_info = info;
+
+	tx_power = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_START);
+	for (i = 0; i < 14; i++)
+		info[i].tx_power1 = TXPOWER_FROM_DEV(tx_power[i]);
+
+	return 0;
 }
 
 static int rt2400pci_probe_hw(struct rt2x00_dev *rt2x00dev)
@@ -1477,7 +1483,9 @@
 	/*
 	 * Initialize hw specifications.
 	 */
-	rt2400pci_probe_hw_mode(rt2x00dev);
+	retval = rt2400pci_probe_hw_mode(rt2x00dev);
+	if (retval)
+		return retval;
 
 	/*
 	 * This device requires the atim queue and DMA-mapped skbs.
diff --git a/drivers/net/wireless/rt2x00/rt2400pci.h b/drivers/net/wireless/rt2x00/rt2400pci.h
index bc55642..bbff381 100644
--- a/drivers/net/wireless/rt2x00/rt2400pci.h
+++ b/drivers/net/wireless/rt2x00/rt2400pci.h
@@ -938,19 +938,13 @@
 #define MAX_TXPOWER	62
 #define DEFAULT_TXPOWER	39
 
-#define TXPOWER_FROM_DEV(__txpower)					\
-({									\
-	((__txpower) > MAX_TXPOWER) ? DEFAULT_TXPOWER - MIN_TXPOWER :	\
-	((__txpower) < MIN_TXPOWER) ? DEFAULT_TXPOWER - MIN_TXPOWER :	\
-	(((__txpower) - MAX_TXPOWER) + MIN_TXPOWER);			\
-})
+#define __CLAMP_TX(__txpower) \
+	clamp_t(char, (__txpower), MIN_TXPOWER, MAX_TXPOWER)
 
-#define TXPOWER_TO_DEV(__txpower)			\
-({							\
-	(__txpower) += MIN_TXPOWER;			\
-	((__txpower) <= MIN_TXPOWER) ? MAX_TXPOWER :	\
-	(((__txpower) >= MAX_TXPOWER) ? MIN_TXPOWER :	\
-	(MAX_TXPOWER - ((__txpower) - MIN_TXPOWER)));	\
-})
+#define TXPOWER_FROM_DEV(__txpower) \
+	((__CLAMP_TX(__txpower) - MAX_TXPOWER) + MIN_TXPOWER)
+
+#define TXPOWER_TO_DEV(__txpower) \
+	MAX_TXPOWER - (__CLAMP_TX(__txpower) - MIN_TXPOWER)
 
 #endif /* RT2400PCI_H */
diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c
index 181a146..ef42cc0 100644
--- a/drivers/net/wireless/rt2x00/rt2500pci.c
+++ b/drivers/net/wireless/rt2x00/rt2500pci.c
@@ -231,7 +231,7 @@
 };
 #endif /* CONFIG_RT2X00_LIB_DEBUGFS */
 
-#ifdef CONFIG_RT2500PCI_RFKILL
+#ifdef CONFIG_RT2X00_LIB_RFKILL
 static int rt2500pci_rfkill_poll(struct rt2x00_dev *rt2x00dev)
 {
 	u32 reg;
@@ -241,9 +241,9 @@
 }
 #else
 #define rt2500pci_rfkill_poll	NULL
-#endif /* CONFIG_RT2500PCI_RFKILL */
+#endif /* CONFIG_RT2X00_LIB_RFKILL */
 
-#ifdef CONFIG_RT2500PCI_LEDS
+#ifdef CONFIG_RT2X00_LIB_LEDS
 static void rt2500pci_brightness_set(struct led_classdev *led_cdev,
 				     enum led_brightness brightness)
 {
@@ -288,7 +288,7 @@
 	led->led_dev.blink_set = rt2500pci_blink_set;
 	led->flags = LED_INITIALIZED;
 }
-#endif /* CONFIG_RT2500PCI_LEDS */
+#endif /* CONFIG_RT2X00_LIB_LEDS */
 
 /*
  * Configuration handlers.
@@ -1316,6 +1316,8 @@
 
 	if (rt2x00_get_field32(word0, RXD_W0_OFDM))
 		rxdesc->dev_flags |= RXDONE_SIGNAL_PLCP;
+	else
+		rxdesc->dev_flags |= RXDONE_SIGNAL_BITRATE;
 	if (rt2x00_get_field32(word0, RXD_W0_MY_BSS))
 		rxdesc->dev_flags |= RXDONE_MY_BSS;
 }
@@ -1377,7 +1379,7 @@
 	if (!reg)
 		return IRQ_NONE;
 
-	if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags))
+	if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
 		return IRQ_HANDLED;
 
 	/*
@@ -1531,22 +1533,22 @@
 	/*
 	 * Store led mode, for correct led behaviour.
 	 */
-#ifdef CONFIG_RT2500PCI_LEDS
+#ifdef CONFIG_RT2X00_LIB_LEDS
 	value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_LED_MODE);
 
 	rt2500pci_init_led(rt2x00dev, &rt2x00dev->led_radio, LED_TYPE_RADIO);
 	if (value == LED_MODE_TXRX_ACTIVITY)
 		rt2500pci_init_led(rt2x00dev, &rt2x00dev->led_qual,
 				   LED_TYPE_ACTIVITY);
-#endif /* CONFIG_RT2500PCI_LEDS */
+#endif /* CONFIG_RT2X00_LIB_LEDS */
 
 	/*
 	 * Detect if this device has an hardware controlled radio.
 	 */
-#ifdef CONFIG_RT2500PCI_RFKILL
+#ifdef CONFIG_RT2X00_LIB_RFKILL
 	if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_HARDWARE_RADIO))
 		__set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags);
-#endif /* CONFIG_RT2500PCI_RFKILL */
+#endif /* CONFIG_RT2X00_LIB_RFKILL */
 
 	/*
 	 * Check if the BBP tuning should be enabled.
@@ -1721,10 +1723,11 @@
 	{ 161, 0x00022020, 0x000090be, 0x00000101, 0x00000a07 },
 };
 
-static void rt2500pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
+static int rt2500pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
 {
 	struct hw_mode_spec *spec = &rt2x00dev->spec;
-	u8 *txpower;
+	struct channel_info *info;
+	char *tx_power;
 	unsigned int i;
 
 	/*
@@ -1741,20 +1744,10 @@
 						   EEPROM_MAC_ADDR_0));
 
 	/*
-	 * Convert tx_power array in eeprom.
-	 */
-	txpower = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_START);
-	for (i = 0; i < 14; i++)
-		txpower[i] = TXPOWER_FROM_DEV(txpower[i]);
-
-	/*
 	 * Initialize hw_mode information.
 	 */
 	spec->supported_bands = SUPPORT_BAND_2GHZ;
 	spec->supported_rates = SUPPORT_RATE_CCK | SUPPORT_RATE_OFDM;
-	spec->tx_power_a = NULL;
-	spec->tx_power_bg = txpower;
-	spec->tx_power_default = DEFAULT_TXPOWER;
 
 	if (rt2x00_rf(&rt2x00dev->chip, RF2522)) {
 		spec->num_channels = ARRAY_SIZE(rf_vals_bg_2522);
@@ -1776,6 +1769,26 @@
 		spec->num_channels = ARRAY_SIZE(rf_vals_5222);
 		spec->channels = rf_vals_5222;
 	}
+
+	/*
+	 * Create channel information array
+	 */
+	info = kzalloc(spec->num_channels * sizeof(*info), GFP_KERNEL);
+	if (!info)
+		return -ENOMEM;
+
+	spec->channels_info = info;
+
+	tx_power = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_START);
+	for (i = 0; i < 14; i++)
+		info[i].tx_power1 = TXPOWER_FROM_DEV(tx_power[i]);
+
+	if (spec->num_channels > 14) {
+		for (i = 14; i < spec->num_channels; i++)
+			info[i].tx_power1 = DEFAULT_TXPOWER;
+	}
+
+	return 0;
 }
 
 static int rt2500pci_probe_hw(struct rt2x00_dev *rt2x00dev)
@@ -1796,7 +1809,9 @@
 	/*
 	 * Initialize hw specifications.
 	 */
-	rt2500pci_probe_hw_mode(rt2x00dev);
+	retval = rt2500pci_probe_hw_mode(rt2x00dev);
+	if (retval)
+		return retval;
 
 	/*
 	 * This device requires the atim queue and DMA-mapped skbs.
diff --git a/drivers/net/wireless/rt2x00/rt2500pci.h b/drivers/net/wireless/rt2x00/rt2500pci.h
index 42f3769..8c26bef 100644
--- a/drivers/net/wireless/rt2x00/rt2500pci.h
+++ b/drivers/net/wireless/rt2x00/rt2500pci.h
@@ -1223,17 +1223,10 @@
 #define MAX_TXPOWER	31
 #define DEFAULT_TXPOWER	24
 
-#define TXPOWER_FROM_DEV(__txpower)		\
-({						\
-	((__txpower) > MAX_TXPOWER) ?		\
-		DEFAULT_TXPOWER : (__txpower);	\
-})
+#define TXPOWER_FROM_DEV(__txpower) \
+	(((u8)(__txpower)) > MAX_TXPOWER) ? DEFAULT_TXPOWER : (__txpower)
 
-#define TXPOWER_TO_DEV(__txpower)			\
-({							\
-	((__txpower) <= MIN_TXPOWER) ? MIN_TXPOWER :	\
-	(((__txpower) >= MAX_TXPOWER) ? MAX_TXPOWER :	\
-	(__txpower));					\
-})
+#define TXPOWER_TO_DEV(__txpower) \
+	clamp_t(char, __txpower, MIN_TXPOWER, MAX_TXPOWER)
 
 #endif /* RT2500PCI_H */
diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c
index cd5af65..d3bf7bb 100644
--- a/drivers/net/wireless/rt2x00/rt2500usb.c
+++ b/drivers/net/wireless/rt2x00/rt2500usb.c
@@ -288,7 +288,7 @@
 };
 #endif /* CONFIG_RT2X00_LIB_DEBUGFS */
 
-#ifdef CONFIG_RT2500USB_LEDS
+#ifdef CONFIG_RT2X00_LIB_LEDS
 static void rt2500usb_brightness_set(struct led_classdev *led_cdev,
 				     enum led_brightness brightness)
 {
@@ -333,7 +333,7 @@
 	led->led_dev.blink_set = rt2500usb_blink_set;
 	led->flags = LED_INITIALIZED;
 }
-#endif /* CONFIG_RT2500USB_LEDS */
+#endif /* CONFIG_RT2X00_LIB_LEDS */
 
 /*
  * Configuration handlers.
@@ -384,7 +384,7 @@
 		rt2500usb_register_read(rt2x00dev, TXRX_CSR20, &reg);
 		rt2x00_set_field16(&reg, TXRX_CSR20_OFFSET, bcn_preload >> 6);
 		rt2x00_set_field16(&reg, TXRX_CSR20_BCN_EXPECT_WINDOW,
-				   2 * (conf->type != IEEE80211_IF_TYPE_STA));
+				   2 * (conf->type != NL80211_IFTYPE_STATION));
 		rt2500usb_register_write(rt2x00dev, TXRX_CSR20, reg);
 
 		/*
@@ -1114,8 +1114,7 @@
 	rt2x00_set_field32(&word, TXD_W0_NEW_SEQ,
 			   test_bit(ENTRY_TXD_FIRST_FRAGMENT, &txdesc->flags));
 	rt2x00_set_field32(&word, TXD_W0_IFS, txdesc->ifs);
-	rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT,
-			   skb->len - skbdesc->desc_len);
+	rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, skb->len);
 	rt2x00_set_field32(&word, TXD_W0_CIPHER, CIPHER_NONE);
 	rt2x00_desc_write(txd, 0, word);
 }
@@ -1134,7 +1133,6 @@
 	int pipe = usb_sndbulkpipe(usb_dev, 1);
 	int length;
 	u16 reg;
-	u32 word, len;
 
 	/*
 	 * Add the descriptor in front of the skb.
@@ -1144,17 +1142,6 @@
 	skbdesc->desc = entry->skb->data;
 
 	/*
-	 * Adjust the beacon databyte count. The current number is
-	 * calculated before this function gets called, but falsely
-	 * assumes that the descriptor was already present in the SKB.
-	 */
-	rt2x00_desc_read(skbdesc->desc, 0, &word);
-	len  = rt2x00_get_field32(word, TXD_W0_DATABYTE_COUNT);
-	len += skbdesc->desc_len;
-	rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, len);
-	rt2x00_desc_write(skbdesc->desc, 0, word);
-
-	/*
 	 * Disable beaconing while we are reloading the beacon data,
 	 * otherwise we might be sending out invalid data.
 	 */
@@ -1280,6 +1267,8 @@
 
 	if (rt2x00_get_field32(word0, RXD_W0_OFDM))
 		rxdesc->dev_flags |= RXDONE_SIGNAL_PLCP;
+	else
+		rxdesc->dev_flags |= RXDONE_SIGNAL_BITRATE;
 	if (rt2x00_get_field32(word0, RXD_W0_MY_BSS))
 		rxdesc->dev_flags |= RXDONE_MY_BSS;
 
@@ -1297,7 +1286,7 @@
 	struct queue_entry *entry = (struct queue_entry *)urb->context;
 	struct queue_entry_priv_usb_bcn *bcn_priv = entry->priv_data;
 
-	if (!test_bit(DEVICE_ENABLED_RADIO, &entry->queue->rt2x00dev->flags))
+	if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &entry->queue->rt2x00dev->flags))
 		return;
 
 	/*
@@ -1484,14 +1473,14 @@
 	/*
 	 * Store led mode, for correct led behaviour.
 	 */
-#ifdef CONFIG_RT2500USB_LEDS
+#ifdef CONFIG_RT2X00_LIB_LEDS
 	value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_LED_MODE);
 
 	rt2500usb_init_led(rt2x00dev, &rt2x00dev->led_radio, LED_TYPE_RADIO);
 	if (value == LED_MODE_TXRX_ACTIVITY)
 		rt2500usb_init_led(rt2x00dev, &rt2x00dev->led_qual,
 				   LED_TYPE_ACTIVITY);
-#endif /* CONFIG_RT2500USB_LEDS */
+#endif /* CONFIG_RT2X00_LIB_LEDS */
 
 	/*
 	 * Check if the BBP tuning should be disabled.
@@ -1665,10 +1654,11 @@
 	{ 161, 0x00022020, 0x000090be, 0x00000101, 0x00000a07 },
 };
 
-static void rt2500usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
+static int rt2500usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
 {
 	struct hw_mode_spec *spec = &rt2x00dev->spec;
-	u8 *txpower;
+	struct channel_info *info;
+	char *tx_power;
 	unsigned int i;
 
 	/*
@@ -1687,20 +1677,10 @@
 						   EEPROM_MAC_ADDR_0));
 
 	/*
-	 * Convert tx_power array in eeprom.
-	 */
-	txpower = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_START);
-	for (i = 0; i < 14; i++)
-		txpower[i] = TXPOWER_FROM_DEV(txpower[i]);
-
-	/*
 	 * Initialize hw_mode information.
 	 */
 	spec->supported_bands = SUPPORT_BAND_2GHZ;
 	spec->supported_rates = SUPPORT_RATE_CCK | SUPPORT_RATE_OFDM;
-	spec->tx_power_a = NULL;
-	spec->tx_power_bg = txpower;
-	spec->tx_power_default = DEFAULT_TXPOWER;
 
 	if (rt2x00_rf(&rt2x00dev->chip, RF2522)) {
 		spec->num_channels = ARRAY_SIZE(rf_vals_bg_2522);
@@ -1722,6 +1702,26 @@
 		spec->num_channels = ARRAY_SIZE(rf_vals_5222);
 		spec->channels = rf_vals_5222;
 	}
+
+	/*
+	 * Create channel information array
+	 */
+	info = kzalloc(spec->num_channels * sizeof(*info), GFP_KERNEL);
+	if (!info)
+		return -ENOMEM;
+
+	spec->channels_info = info;
+
+	tx_power = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_START);
+	for (i = 0; i < 14; i++)
+		info[i].tx_power1 = TXPOWER_FROM_DEV(tx_power[i]);
+
+	if (spec->num_channels > 14) {
+		for (i = 14; i < spec->num_channels; i++)
+			info[i].tx_power1 = DEFAULT_TXPOWER;
+	}
+
+	return 0;
 }
 
 static int rt2500usb_probe_hw(struct rt2x00_dev *rt2x00dev)
@@ -1742,7 +1742,9 @@
 	/*
 	 * Initialize hw specifications.
 	 */
-	rt2500usb_probe_hw_mode(rt2x00dev);
+	retval = rt2500usb_probe_hw_mode(rt2x00dev);
+	if (retval)
+		return retval;
 
 	/*
 	 * This device requires the atim queue
diff --git a/drivers/net/wireless/rt2x00/rt2500usb.h b/drivers/net/wireless/rt2x00/rt2500usb.h
index 4769ffe..89e5ed2 100644
--- a/drivers/net/wireless/rt2x00/rt2500usb.h
+++ b/drivers/net/wireless/rt2x00/rt2500usb.h
@@ -825,17 +825,10 @@
 #define MAX_TXPOWER	31
 #define DEFAULT_TXPOWER	24
 
-#define TXPOWER_FROM_DEV(__txpower)		\
-({						\
-	((__txpower) > MAX_TXPOWER) ?		\
-		DEFAULT_TXPOWER : (__txpower);	\
-})
+#define TXPOWER_FROM_DEV(__txpower) \
+	(((u8)(__txpower)) > MAX_TXPOWER) ? DEFAULT_TXPOWER : (__txpower)
 
-#define TXPOWER_TO_DEV(__txpower)			\
-({							\
-	((__txpower) <= MIN_TXPOWER) ? MIN_TXPOWER :	\
-	(((__txpower) >= MAX_TXPOWER) ? MAX_TXPOWER :	\
-	(__txpower));					\
-})
+#define TXPOWER_TO_DEV(__txpower) \
+	clamp_t(char, __txpower, MIN_TXPOWER, MAX_TXPOWER)
 
 #endif /* RT2500USB_H */
diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h
index 8b10ea4..1359a37 100644
--- a/drivers/net/wireless/rt2x00/rt2x00.h
+++ b/drivers/net/wireless/rt2x00/rt2x00.h
@@ -44,7 +44,7 @@
 /*
  * Module information.
  */
-#define DRV_VERSION	"2.1.8"
+#define DRV_VERSION	"2.2.1"
 #define DRV_PROJECT	"http://rt2x00.serialmonkey.com"
 
 /*
@@ -53,11 +53,11 @@
  */
 #define DEBUG_PRINTK_MSG(__dev, __kernlvl, __lvl, __msg, __args...)	\
 	printk(__kernlvl "%s -> %s: %s - " __msg,			\
-	       wiphy_name((__dev)->hw->wiphy), __FUNCTION__, __lvl, ##__args)
+	       wiphy_name((__dev)->hw->wiphy), __func__, __lvl, ##__args)
 
 #define DEBUG_PRINTK_PROBE(__kernlvl, __lvl, __msg, __args...)	\
 	printk(__kernlvl "%s -> %s: %s - " __msg,		\
-	       KBUILD_MODNAME, __FUNCTION__, __lvl, ##__args)
+	       KBUILD_MODNAME, __func__, __lvl, ##__args)
 
 #ifdef CONFIG_RT2X00_DEBUG
 #define DEBUG_PRINTK(__dev, __kernlvl, __lvl, __msg, __args...)	\
@@ -144,6 +144,17 @@
 };
 
 /*
+ * Channel information structure
+ */
+struct channel_info {
+	unsigned int flags;
+#define GEOGRAPHY_ALLOWED	0x00000001
+
+	short tx_power1;
+	short tx_power2;
+};
+
+/*
  * Antenna setup values.
  */
 struct antenna_setup {
@@ -394,10 +405,7 @@
  * @num_channels: Number of supported channels. This is used as array size
  *	for @tx_power_a, @tx_power_bg and @channels.
  * @channels: Device/chipset specific channel values (See &struct rf_channel).
- * @tx_power_a: TX power values for all 5.2GHz channels (may be NULL).
- * @tx_power_bg: TX power values for all 2.4GHz channels (may be NULL).
- * @tx_power_default: Default TX power value to use when either
- *	@tx_power_a or @tx_power_bg is missing.
+ * @channels_info: Additional information for channels (See &struct channel_info).
  */
 struct hw_mode_spec {
 	unsigned int supported_bands;
@@ -410,10 +418,7 @@
 
 	unsigned int num_channels;
 	const struct rf_channel *channels;
-
-	const u8 *tx_power_a;
-	const u8 *tx_power_bg;
-	u8 tx_power_default;
+	const struct channel_info *channels_info;
 };
 
 /*
@@ -425,7 +430,9 @@
  */
 struct rt2x00lib_conf {
 	struct ieee80211_conf *conf;
+
 	struct rf_channel rf;
+	struct channel_info channel;
 
 	struct antenna_setup ant;
 
@@ -452,6 +459,23 @@
 };
 
 /*
+ * Configuration structure for hardware encryption.
+ */
+struct rt2x00lib_crypto {
+	enum cipher cipher;
+
+	enum set_key_cmd cmd;
+	const u8 *address;
+
+	u32 bssidx;
+	u32 aid;
+
+	u8 key[16];
+	u8 tx_mic[8];
+	u8 rx_mic[8];
+};
+
+/*
  * Configuration structure wrapper around the
  * rt2x00 interface configuration handler.
  */
@@ -459,7 +483,7 @@
 	/*
 	 * Interface type
 	 */
-	enum ieee80211_if_types type;
+	enum nl80211_iftype type;
 
 	/*
 	 * TSF sync value, this is dependant on the operation type.
@@ -547,6 +571,12 @@
 	/*
 	 * Configuration handlers.
 	 */
+	int (*config_shared_key) (struct rt2x00_dev *rt2x00dev,
+				  struct rt2x00lib_crypto *crypto,
+				  struct ieee80211_key_conf *key);
+	int (*config_pairwise_key) (struct rt2x00_dev *rt2x00dev,
+				    struct rt2x00lib_crypto *crypto,
+				    struct ieee80211_key_conf *key);
 	void (*config_filter) (struct rt2x00_dev *rt2x00dev,
 			       const unsigned int filter_flags);
 	void (*config_intf) (struct rt2x00_dev *rt2x00dev,
@@ -599,17 +629,16 @@
 	/*
 	 * Device state flags
 	 */
-	DEVICE_PRESENT,
-	DEVICE_REGISTERED_HW,
-	DEVICE_INITIALIZED,
-	DEVICE_STARTED,
-	DEVICE_STARTED_SUSPEND,
-	DEVICE_ENABLED_RADIO,
-	DEVICE_DISABLED_RADIO_HW,
-	DEVICE_DIRTY_CONFIG,
+	DEVICE_STATE_PRESENT,
+	DEVICE_STATE_REGISTERED_HW,
+	DEVICE_STATE_INITIALIZED,
+	DEVICE_STATE_STARTED,
+	DEVICE_STATE_STARTED_SUSPEND,
+	DEVICE_STATE_ENABLED_RADIO,
+	DEVICE_STATE_DISABLED_RADIO_HW,
 
 	/*
-	 * Driver features
+	 * Driver requirements
 	 */
 	DRIVER_REQUIRE_FIRMWARE,
 	DRIVER_REQUIRE_BEACON_GUARD,
@@ -618,9 +647,14 @@
 	DRIVER_REQUIRE_DMA,
 
 	/*
-	 * Driver configuration
+	 * Driver features
 	 */
 	CONFIG_SUPPORT_HW_BUTTON,
+	CONFIG_SUPPORT_HW_CRYPTO,
+
+	/*
+	 * Driver configuration
+	 */
 	CONFIG_FRAME_TYPE,
 	CONFIG_RF_SEQUENCE,
 	CONFIG_EXTERNAL_LNA_A,
@@ -769,6 +803,11 @@
 	u32 *rf;
 
 	/*
+	 * LNA gain
+	 */
+	short lna_gain;
+
+	/*
 	 * USB Max frame size (for rt2500usb & rt73usb).
 	 */
 	u16 usb_maxpacket;
@@ -966,6 +1005,13 @@
 				unsigned int changed_flags,
 				unsigned int *total_flags,
 				int mc_count, struct dev_addr_list *mc_list);
+#ifdef CONFIG_RT2X00_LIB_CRYPTO
+int rt2x00mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
+		      const u8 *local_address, const u8 *address,
+		      struct ieee80211_key_conf *key);
+#else
+#define rt2x00mac_set_key	NULL
+#endif /* CONFIG_RT2X00_LIB_CRYPTO */
 int rt2x00mac_get_stats(struct ieee80211_hw *hw,
 			struct ieee80211_low_level_stats *stats);
 int rt2x00mac_get_tx_stats(struct ieee80211_hw *hw,
diff --git a/drivers/net/wireless/rt2x00/rt2x00config.c b/drivers/net/wireless/rt2x00/rt2x00config.c
index d134c3b..4d5e87b 100644
--- a/drivers/net/wireless/rt2x00/rt2x00config.c
+++ b/drivers/net/wireless/rt2x00/rt2x00config.c
@@ -31,7 +31,7 @@
 
 void rt2x00lib_config_intf(struct rt2x00_dev *rt2x00dev,
 			   struct rt2x00_intf *intf,
-			   enum ieee80211_if_types type,
+			   enum nl80211_iftype type,
 			   u8 *mac, u8 *bssid)
 {
 	struct rt2x00intf_conf conf;
@@ -40,11 +40,11 @@
 	conf.type = type;
 
 	switch (type) {
-	case IEEE80211_IF_TYPE_IBSS:
-	case IEEE80211_IF_TYPE_AP:
+	case NL80211_IFTYPE_ADHOC:
+	case NL80211_IFTYPE_AP:
 		conf.sync = TSF_SYNC_BEACON;
 		break;
-	case IEEE80211_IF_TYPE_STA:
+	case NL80211_IFTYPE_STATION:
 		conf.sync = TSF_SYNC_INFRA;
 		break;
 	default:
@@ -121,7 +121,7 @@
 	 * Antenna setup changes require the RX to be disabled,
 	 * else the changes will be ignored by the device.
 	 */
-	if (test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags))
+	if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
 		rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_OFF_LINK);
 
 	/*
@@ -136,7 +136,7 @@
 	rt2x00dev->link.ant.active.rx = libconf.ant.rx;
 	rt2x00dev->link.ant.active.tx = libconf.ant.tx;
 
-	if (test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags))
+	if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
 		rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_ON_LINK);
 }
 
@@ -245,6 +245,10 @@
 		memcpy(&libconf.rf,
 		       &rt2x00dev->spec.channels[conf->channel->hw_value],
 		       sizeof(libconf.rf));
+
+		memcpy(&libconf.channel,
+		       &rt2x00dev->spec.channels_info[conf->channel->hw_value],
+		       sizeof(libconf.channel));
 	}
 
 	if (flags & CONFIG_UPDATE_ANTENNA) {
diff --git a/drivers/net/wireless/rt2x00/rt2x00crypto.c b/drivers/net/wireless/rt2x00/rt2x00crypto.c
new file mode 100644
index 0000000..5a858e5
--- /dev/null
+++ b/drivers/net/wireless/rt2x00/rt2x00crypto.c
@@ -0,0 +1,215 @@
+/*
+	Copyright (C) 2004 - 2008 rt2x00 SourceForge Project
+	<http://rt2x00.serialmonkey.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.
+ */
+
+/*
+	Module: rt2x00lib
+	Abstract: rt2x00 crypto specific routines.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+#include "rt2x00.h"
+#include "rt2x00lib.h"
+
+enum cipher rt2x00crypto_key_to_cipher(struct ieee80211_key_conf *key)
+{
+	switch (key->alg) {
+	case ALG_WEP:
+		if (key->keylen == LEN_WEP40)
+			return CIPHER_WEP64;
+		else
+			return CIPHER_WEP128;
+	case ALG_TKIP:
+		return CIPHER_TKIP;
+	case ALG_CCMP:
+		return CIPHER_AES;
+	default:
+		return CIPHER_NONE;
+	}
+}
+
+unsigned int rt2x00crypto_tx_overhead(struct ieee80211_tx_info *tx_info)
+{
+	struct ieee80211_key_conf *key = tx_info->control.hw_key;
+	unsigned int overhead = 0;
+
+	/*
+	 * Extend frame length to include IV/EIV/ICV/MMIC,
+	 * note that these lengths should only be added when
+	 * mac80211 does not generate it.
+	 */
+	overhead += key->icv_len;
+
+	if (!(key->flags & IEEE80211_KEY_FLAG_GENERATE_IV))
+		overhead += key->iv_len;
+
+	if (!(key->flags & IEEE80211_KEY_FLAG_GENERATE_MMIC)) {
+		if (key->alg == ALG_TKIP)
+			overhead += 8;
+	}
+
+	return overhead;
+}
+
+void rt2x00crypto_tx_remove_iv(struct sk_buff *skb, unsigned int iv_len)
+{
+	struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
+	unsigned int header_length = ieee80211_get_hdrlen_from_skb(skb);
+
+	if (unlikely(!iv_len))
+		return;
+
+	/* Copy IV/EIV data */
+	if (iv_len >= 4)
+		memcpy(&skbdesc->iv, skb->data + header_length, 4);
+	if (iv_len >= 8)
+		memcpy(&skbdesc->eiv, skb->data + header_length + 4, 4);
+
+	/* Move ieee80211 header */
+	memmove(skb->data + iv_len, skb->data, header_length);
+
+	/* Pull buffer to correct size */
+	skb_pull(skb, iv_len);
+
+	/* IV/EIV data has officially be stripped */
+	skbdesc->flags |= FRAME_DESC_IV_STRIPPED;
+}
+
+void rt2x00crypto_tx_insert_iv(struct sk_buff *skb)
+{
+	struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
+	unsigned int header_length = ieee80211_get_hdrlen_from_skb(skb);
+	const unsigned int iv_len =
+	    ((!!(skbdesc->iv)) * 4) + ((!!(skbdesc->eiv)) * 4);
+
+	if (!(skbdesc->flags & FRAME_DESC_IV_STRIPPED))
+		return;
+
+	skb_push(skb, iv_len);
+
+	/* Move ieee80211 header */
+	memmove(skb->data, skb->data + iv_len, header_length);
+
+	/* Copy IV/EIV data */
+	if (iv_len >= 4)
+		memcpy(skb->data + header_length, &skbdesc->iv, 4);
+	if (iv_len >= 8)
+		memcpy(skb->data + header_length + 4, &skbdesc->eiv, 4);
+
+	/* IV/EIV data has returned into the frame */
+	skbdesc->flags &= ~FRAME_DESC_IV_STRIPPED;
+}
+
+void rt2x00crypto_rx_insert_iv(struct sk_buff *skb, unsigned int align,
+			       unsigned int header_length,
+			       struct rxdone_entry_desc *rxdesc)
+{
+	unsigned int payload_len = rxdesc->size - header_length;
+	unsigned int iv_len;
+	unsigned int icv_len;
+	unsigned int transfer = 0;
+
+	/*
+	 * WEP64/WEP128: Provides IV & ICV
+	 * TKIP: Provides IV/EIV & ICV
+	 * AES: Provies IV/EIV & ICV
+	 */
+	switch (rxdesc->cipher) {
+	case CIPHER_WEP64:
+	case CIPHER_WEP128:
+		iv_len = 4;
+		icv_len = 4;
+		break;
+	case CIPHER_TKIP:
+		iv_len = 8;
+		icv_len = 4;
+		break;
+	case CIPHER_AES:
+		iv_len = 8;
+		icv_len = 8;
+		break;
+	default:
+		/* Unsupport type */
+		return;
+	}
+
+	/*
+	 * Make room for new data, note that we increase both
+	 * headsize and tailsize when required. The tailsize is
+	 * only needed when ICV data needs to be inserted and
+	 * the padding is smaller then the ICV data.
+	 * When alignment requirements is greater then the
+	 * ICV data we must trim the skb to the correct size
+	 * because we need to remove the extra bytes.
+	 */
+	skb_push(skb, iv_len + align);
+	if (align < icv_len)
+		skb_put(skb, icv_len - align);
+	else if (align > icv_len)
+		skb_trim(skb, rxdesc->size + iv_len + icv_len);
+
+	/* Move ieee80211 header */
+	memmove(skb->data + transfer,
+		skb->data + transfer + iv_len + align,
+		header_length);
+	transfer += header_length;
+
+	/* Copy IV data */
+	if (iv_len >= 4) {
+		memcpy(skb->data + transfer, &rxdesc->iv, 4);
+		transfer += 4;
+	}
+
+	/* Copy EIV data */
+	if (iv_len >= 8) {
+		memcpy(skb->data + transfer, &rxdesc->eiv, 4);
+		transfer += 4;
+	}
+
+	/* Move payload */
+	if (align) {
+		memmove(skb->data + transfer,
+			skb->data + transfer + align,
+			payload_len);
+	}
+
+	/*
+	 * NOTE: Always count the payload as transfered,
+	 * even when alignment was set to zero. This is required
+	 * for determining the correct offset for the ICV data.
+	 */
+	transfer += payload_len;
+
+	/* Copy ICV data */
+	if (icv_len >= 4) {
+		memcpy(skb->data + transfer, &rxdesc->icv, 4);
+		/*
+		 * AES appends 8 bytes, we can't fill the upper
+		 * 4 bytes, but mac80211 doesn't care about what
+		 * we provide here anyway and strips it immediately.
+		 */
+		transfer += icv_len;
+	}
+
+	/* IV/EIV/ICV has been inserted into frame */
+	rxdesc->size = transfer;
+	rxdesc->flags &= ~RX_FLAG_IV_STRIPPED;
+}
diff --git a/drivers/net/wireless/rt2x00/rt2x00debug.c b/drivers/net/wireless/rt2x00/rt2x00debug.c
index 6bee1d6..5cf4c85 100644
--- a/drivers/net/wireless/rt2x00/rt2x00debug.c
+++ b/drivers/net/wireless/rt2x00/rt2x00debug.c
@@ -35,6 +35,13 @@
 
 #define MAX_LINE_LENGTH 64
 
+struct rt2x00debug_crypto {
+	unsigned long success;
+	unsigned long icv_error;
+	unsigned long mic_error;
+	unsigned long key_error;
+};
+
 struct rt2x00debug_intf {
 	/*
 	 * Pointer to driver structure where
@@ -63,6 +70,7 @@
 	 *   - queue folder
 	 *     - frame dump file
 	 *     - queue stats file
+	 *     - crypto stats file
 	 */
 	struct dentry *driver_folder;
 	struct dentry *driver_entry;
@@ -80,6 +88,7 @@
 	struct dentry *queue_folder;
 	struct dentry *queue_frame_dump_entry;
 	struct dentry *queue_stats_entry;
+	struct dentry *crypto_stats_entry;
 
 	/*
 	 * The frame dump file only allows a single reader,
@@ -98,6 +107,12 @@
 	wait_queue_head_t frame_dump_waitqueue;
 
 	/*
+	 * HW crypto statistics.
+	 * All statistics are stored seperately per cipher type.
+	 */
+	struct rt2x00debug_crypto crypto_stats[CIPHER_MAX];
+
+	/*
 	 * Driver and chipset files will use a data buffer
 	 * that has been created in advance. This will simplify
 	 * the code since we can use the debugfs functions.
@@ -114,6 +129,25 @@
 	unsigned int offset_rf;
 };
 
+void rt2x00debug_update_crypto(struct rt2x00_dev *rt2x00dev,
+			       enum cipher cipher, enum rx_crypto status)
+{
+	struct rt2x00debug_intf *intf = rt2x00dev->debugfs_intf;
+
+	if (cipher == CIPHER_TKIP_NO_MIC)
+		cipher = CIPHER_TKIP;
+	if (cipher == CIPHER_NONE || cipher > CIPHER_MAX)
+		return;
+
+	/* Remove CIPHER_NONE index */
+	cipher--;
+
+	intf->crypto_stats[cipher].success += (status == RX_CRYPTO_SUCCESS);
+	intf->crypto_stats[cipher].icv_error += (status == RX_CRYPTO_FAIL_ICV);
+	intf->crypto_stats[cipher].mic_error += (status == RX_CRYPTO_FAIL_MIC);
+	intf->crypto_stats[cipher].key_error += (status == RX_CRYPTO_FAIL_KEY);
+}
+
 void rt2x00debug_dump_frame(struct rt2x00_dev *rt2x00dev,
 			    enum rt2x00_dump_type type, struct sk_buff *skb)
 {
@@ -327,6 +361,59 @@
 	.release	= rt2x00debug_file_release,
 };
 
+#ifdef CONFIG_RT2X00_LIB_CRYPTO
+static ssize_t rt2x00debug_read_crypto_stats(struct file *file,
+					     char __user *buf,
+					     size_t length,
+					     loff_t *offset)
+{
+	struct rt2x00debug_intf *intf = file->private_data;
+	char *name[] = { "WEP64", "WEP128", "TKIP", "AES" };
+	char *data;
+	char *temp;
+	size_t size;
+	unsigned int i;
+
+	if (*offset)
+		return 0;
+
+	data = kzalloc((1 + CIPHER_MAX)* MAX_LINE_LENGTH, GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	temp = data;
+	temp += sprintf(data, "cipher\tsuccess\ticv err\tmic err\tkey err\n");
+
+	for (i = 0; i < CIPHER_MAX; i++) {
+		temp += sprintf(temp, "%s\t%lu\t%lu\t%lu\t%lu\n", name[i],
+				intf->crypto_stats[i].success,
+				intf->crypto_stats[i].icv_error,
+				intf->crypto_stats[i].mic_error,
+				intf->crypto_stats[i].key_error);
+	}
+
+	size = strlen(data);
+	size = min(size, length);
+
+	if (copy_to_user(buf, data, size)) {
+		kfree(data);
+		return -EFAULT;
+	}
+
+	kfree(data);
+
+	*offset += size;
+	return size;
+}
+
+static const struct file_operations rt2x00debug_fop_crypto_stats = {
+	.owner		= THIS_MODULE,
+	.read		= rt2x00debug_read_crypto_stats,
+	.open		= rt2x00debug_file_open,
+	.release	= rt2x00debug_file_release,
+};
+#endif
+
 #define RT2X00DEBUGFS_OPS_READ(__name, __format, __type)	\
 static ssize_t rt2x00debug_read_##__name(struct file *file,	\
 					 char __user *buf,	\
@@ -569,6 +656,13 @@
 	    debugfs_create_file("queue", S_IRUSR, intf->queue_folder,
 				intf, &rt2x00debug_fop_queue_stats);
 
+#ifdef CONFIG_RT2X00_LIB_CRYPTO
+	if (test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags))
+		intf->crypto_stats_entry =
+		    debugfs_create_file("crypto", S_IRUGO, intf->queue_folder,
+					intf, &rt2x00debug_fop_crypto_stats);
+#endif
+
 	return;
 
 exit:
@@ -587,6 +681,9 @@
 
 	skb_queue_purge(&intf->frame_dump_skbqueue);
 
+#ifdef CONFIG_RT2X00_LIB_CRYPTO
+	debugfs_remove(intf->crypto_stats_entry);
+#endif
 	debugfs_remove(intf->queue_stats_entry);
 	debugfs_remove(intf->queue_frame_dump_entry);
 	debugfs_remove(intf->queue_folder);
diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c
index f42283a..86840e3 100644
--- a/drivers/net/wireless/rt2x00/rt2x00dev.c
+++ b/drivers/net/wireless/rt2x00/rt2x00dev.c
@@ -34,7 +34,7 @@
  */
 void rt2x00lib_reset_link_tuner(struct rt2x00_dev *rt2x00dev)
 {
-	if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags))
+	if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
 		return;
 
 	/*
@@ -94,8 +94,8 @@
 	 * Don't enable the radio twice.
 	 * And check if the hardware button has been disabled.
 	 */
-	if (test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags) ||
-	    test_bit(DEVICE_DISABLED_RADIO_HW, &rt2x00dev->flags))
+	if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags) ||
+	    test_bit(DEVICE_STATE_DISABLED_RADIO_HW, &rt2x00dev->flags))
 		return 0;
 
 	/*
@@ -117,7 +117,7 @@
 	rt2x00leds_led_radio(rt2x00dev, true);
 	rt2x00led_led_activity(rt2x00dev, true);
 
-	__set_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags);
+	set_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags);
 
 	/*
 	 * Enable RX.
@@ -134,7 +134,7 @@
 
 void rt2x00lib_disable_radio(struct rt2x00_dev *rt2x00dev)
 {
-	if (!__test_and_clear_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags))
+	if (!test_and_clear_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
 		return;
 
 	/*
@@ -354,7 +354,7 @@
 	 * When the radio is shutting down we should
 	 * immediately cease all link tuning.
 	 */
-	if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags))
+	if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
 		return;
 
 	/*
@@ -431,7 +431,7 @@
 	 * note that in the spinlock protected area above the delayed_flags
 	 * have been cleared correctly.
 	 */
-	if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags))
+	if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
 		return;
 
 	if (delayed_flags & DELAYED_UPDATE_BEACON)
@@ -467,8 +467,8 @@
 	struct rt2x00_dev *rt2x00dev = data;
 	struct rt2x00_intf *intf = vif_to_intf(vif);
 
-	if (vif->type != IEEE80211_IF_TYPE_AP &&
-	    vif->type != IEEE80211_IF_TYPE_IBSS)
+	if (vif->type != NL80211_IFTYPE_AP &&
+	    vif->type != NL80211_IFTYPE_ADHOC)
 		return;
 
 	/*
@@ -484,7 +484,7 @@
 
 void rt2x00lib_beacondone(struct rt2x00_dev *rt2x00dev)
 {
-	if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags))
+	if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
 		return;
 
 	ieee80211_iterate_active_interfaces_atomic(rt2x00dev->hw,
@@ -508,6 +508,15 @@
 	rt2x00queue_unmap_skb(rt2x00dev, entry->skb);
 
 	/*
+	 * If the IV/EIV data was stripped from the frame before it was
+	 * passed to the hardware, we should now reinsert it again because
+	 * mac80211 will expect the the same data to be present it the
+	 * frame as it was passed to us.
+	 */
+	if (test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags))
+		rt2x00crypto_tx_insert_iv(entry->skb);
+
+	/*
 	 * Send frame to debugfs immediately, after this call is completed
 	 * we are going to overwrite the skb->cb array.
 	 */
@@ -563,7 +572,7 @@
 
 	rt2x00dev->ops->lib->init_txentry(rt2x00dev, entry);
 
-	__clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags);
+	clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags);
 	rt2x00queue_index_inc(entry->queue, Q_INDEX_DONE);
 
 	/*
@@ -585,7 +594,7 @@
 	struct ieee80211_supported_band *sband;
 	struct ieee80211_hdr *hdr;
 	const struct rt2x00_rate *rate;
-	unsigned int header_size;
+	unsigned int header_length;
 	unsigned int align;
 	unsigned int i;
 	int idx = -1;
@@ -613,10 +622,19 @@
 	 * The data behind the ieee80211 header must be
 	 * aligned on a 4 byte boundary.
 	 */
-	header_size = ieee80211_get_hdrlen_from_skb(entry->skb);
-	align = ((unsigned long)(entry->skb->data + header_size)) & 3;
+	header_length = ieee80211_get_hdrlen_from_skb(entry->skb);
+	align = ((unsigned long)(entry->skb->data + header_length)) & 3;
 
-	if (align) {
+	/*
+	 * Hardware might have stripped the IV/EIV/ICV data,
+	 * in that case it is possible that the data was
+	 * provided seperately (through hardware descriptor)
+	 * in which case we should reinsert the data into the frame.
+	 */
+	if ((rxdesc.flags & RX_FLAG_IV_STRIPPED)) {
+		rt2x00crypto_rx_insert_iv(entry->skb, align,
+					  header_length, &rxdesc);
+	} else if (align) {
 		skb_push(entry->skb, align);
 		/* Move entire frame in 1 command */
 		memmove(entry->skb->data, entry->skb->data + align,
@@ -635,7 +653,7 @@
 
 		if (((rxdesc.dev_flags & RXDONE_SIGNAL_PLCP) &&
 		     (rate->plcp == rxdesc.signal)) ||
-		    (!(rxdesc.dev_flags & RXDONE_SIGNAL_PLCP) &&
+		    ((rxdesc.dev_flags & RXDONE_SIGNAL_BITRATE) &&
 		      (rate->bitrate == rxdesc.signal))) {
 			idx = i;
 			break;
@@ -657,6 +675,10 @@
 	    (rxdesc.dev_flags & RXDONE_MY_BSS))
 		rt2x00lib_update_link_stats(&rt2x00dev->link, rxdesc.rssi);
 
+	rt2x00debug_update_crypto(rt2x00dev,
+				  rxdesc.cipher,
+				  rxdesc.cipher_status);
+
 	rt2x00dev->link.qual.rx_success++;
 
 	rx_status->mactime = rxdesc.timestamp;
@@ -796,7 +818,6 @@
 	struct ieee80211_rate *rates;
 	unsigned int num_rates;
 	unsigned int i;
-	unsigned char tx_power;
 
 	num_rates = 0;
 	if (spec->supported_rates & SUPPORT_RATE_CCK)
@@ -822,20 +843,9 @@
 	 * Initialize Channel list.
 	 */
 	for (i = 0; i < spec->num_channels; i++) {
-		if (spec->channels[i].channel <= 14) {
-			if (spec->tx_power_bg)
-				tx_power = spec->tx_power_bg[i];
-			else
-				tx_power = spec->tx_power_default;
-		} else {
-			if (spec->tx_power_a)
-				tx_power = spec->tx_power_a[i];
-			else
-				tx_power = spec->tx_power_default;
-		}
-
 		rt2x00lib_channel(&channels[i],
-				  spec->channels[i].channel, tx_power, i);
+				  spec->channels[i].channel,
+				  spec->channels_info[i].tx_power1, i);
 	}
 
 	/*
@@ -878,7 +888,7 @@
 
 static void rt2x00lib_remove_hw(struct rt2x00_dev *rt2x00dev)
 {
-	if (test_bit(DEVICE_REGISTERED_HW, &rt2x00dev->flags))
+	if (test_bit(DEVICE_STATE_REGISTERED_HW, &rt2x00dev->flags))
 		ieee80211_unregister_hw(rt2x00dev->hw);
 
 	if (likely(rt2x00dev->hw->wiphy->bands[IEEE80211_BAND_2GHZ])) {
@@ -887,6 +897,8 @@
 		rt2x00dev->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = NULL;
 		rt2x00dev->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = NULL;
 	}
+
+	kfree(rt2x00dev->spec.channels_info);
 }
 
 static int rt2x00lib_probe_hw(struct rt2x00_dev *rt2x00dev)
@@ -894,6 +906,9 @@
 	struct hw_mode_spec *spec = &rt2x00dev->spec;
 	int status;
 
+	if (test_bit(DEVICE_STATE_REGISTERED_HW, &rt2x00dev->flags))
+		return 0;
+
 	/*
 	 * Initialize HW modes.
 	 */
@@ -915,7 +930,7 @@
 		return status;
 	}
 
-	__set_bit(DEVICE_REGISTERED_HW, &rt2x00dev->flags);
+	set_bit(DEVICE_STATE_REGISTERED_HW, &rt2x00dev->flags);
 
 	return 0;
 }
@@ -925,7 +940,7 @@
  */
 static void rt2x00lib_uninitialize(struct rt2x00_dev *rt2x00dev)
 {
-	if (!__test_and_clear_bit(DEVICE_INITIALIZED, &rt2x00dev->flags))
+	if (!test_and_clear_bit(DEVICE_STATE_INITIALIZED, &rt2x00dev->flags))
 		return;
 
 	/*
@@ -948,7 +963,7 @@
 {
 	int status;
 
-	if (test_bit(DEVICE_INITIALIZED, &rt2x00dev->flags))
+	if (test_bit(DEVICE_STATE_INITIALIZED, &rt2x00dev->flags))
 		return 0;
 
 	/*
@@ -967,7 +982,7 @@
 		return status;
 	}
 
-	__set_bit(DEVICE_INITIALIZED, &rt2x00dev->flags);
+	set_bit(DEVICE_STATE_INITIALIZED, &rt2x00dev->flags);
 
 	/*
 	 * Register the extra components.
@@ -981,7 +996,7 @@
 {
 	int retval;
 
-	if (test_bit(DEVICE_STARTED, &rt2x00dev->flags))
+	if (test_bit(DEVICE_STATE_STARTED, &rt2x00dev->flags))
 		return 0;
 
 	/*
@@ -999,28 +1014,18 @@
 	if (retval)
 		return retval;
 
-	/*
-	 * Enable radio.
-	 */
-	retval = rt2x00lib_enable_radio(rt2x00dev);
-	if (retval) {
-		rt2x00lib_uninitialize(rt2x00dev);
-		return retval;
-	}
-
 	rt2x00dev->intf_ap_count = 0;
 	rt2x00dev->intf_sta_count = 0;
 	rt2x00dev->intf_associated = 0;
 
-	__set_bit(DEVICE_STARTED, &rt2x00dev->flags);
-	__set_bit(DEVICE_DIRTY_CONFIG, &rt2x00dev->flags);
+	set_bit(DEVICE_STATE_STARTED, &rt2x00dev->flags);
 
 	return 0;
 }
 
 void rt2x00lib_stop(struct rt2x00_dev *rt2x00dev)
 {
-	if (!test_bit(DEVICE_STARTED, &rt2x00dev->flags))
+	if (!test_and_clear_bit(DEVICE_STATE_STARTED, &rt2x00dev->flags))
 		return;
 
 	/*
@@ -1032,8 +1037,6 @@
 	rt2x00dev->intf_ap_count = 0;
 	rt2x00dev->intf_sta_count = 0;
 	rt2x00dev->intf_associated = 0;
-
-	__clear_bit(DEVICE_STARTED, &rt2x00dev->flags);
 }
 
 /*
@@ -1049,6 +1052,11 @@
 	 */
 	rt2x00dev->hw->vif_data_size = sizeof(struct rt2x00_intf);
 
+	rt2x00dev->hw->wiphy->interface_modes =
+	    BIT(NL80211_IFTYPE_AP) |
+	    BIT(NL80211_IFTYPE_STATION) |
+	    BIT(NL80211_IFTYPE_ADHOC);
+
 	/*
 	 * Let the driver probe the device to detect the capabilities.
 	 */
@@ -1088,7 +1096,7 @@
 	rt2x00rfkill_allocate(rt2x00dev);
 	rt2x00debug_register(rt2x00dev);
 
-	__set_bit(DEVICE_PRESENT, &rt2x00dev->flags);
+	set_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags);
 
 	return 0;
 
@@ -1101,7 +1109,7 @@
 
 void rt2x00lib_remove_dev(struct rt2x00_dev *rt2x00dev)
 {
-	__clear_bit(DEVICE_PRESENT, &rt2x00dev->flags);
+	clear_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags);
 
 	/*
 	 * Disable radio.
@@ -1146,14 +1154,15 @@
 	int retval;
 
 	NOTICE(rt2x00dev, "Going to sleep.\n");
-	__clear_bit(DEVICE_PRESENT, &rt2x00dev->flags);
 
 	/*
 	 * Only continue if mac80211 has open interfaces.
 	 */
-	if (!test_bit(DEVICE_STARTED, &rt2x00dev->flags))
+	if (!test_and_clear_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags) ||
+	    !test_bit(DEVICE_STATE_STARTED, &rt2x00dev->flags))
 		goto exit;
-	__set_bit(DEVICE_STARTED_SUSPEND, &rt2x00dev->flags);
+
+	set_bit(DEVICE_STATE_STARTED_SUSPEND, &rt2x00dev->flags);
 
 	/*
 	 * Disable radio.
@@ -1203,8 +1212,8 @@
 	/*
 	 * Master or Ad-hoc mode require a new beacon update.
 	 */
-	if (vif->type == IEEE80211_IF_TYPE_AP ||
-	    vif->type == IEEE80211_IF_TYPE_IBSS)
+	if (vif->type == NL80211_IFTYPE_AP ||
+	    vif->type == NL80211_IFTYPE_ADHOC)
 		intf->delayed_flags |= DELAYED_UPDATE_BEACON;
 
 	spin_unlock(&intf->lock);
@@ -1225,7 +1234,7 @@
 	/*
 	 * Only continue if mac80211 had open interfaces.
 	 */
-	if (!__test_and_clear_bit(DEVICE_STARTED_SUSPEND, &rt2x00dev->flags))
+	if (!test_and_clear_bit(DEVICE_STATE_STARTED_SUSPEND, &rt2x00dev->flags))
 		return 0;
 
 	/*
@@ -1252,7 +1261,7 @@
 	/*
 	 * We are ready again to receive requests from mac80211.
 	 */
-	__set_bit(DEVICE_PRESENT, &rt2x00dev->flags);
+	set_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags);
 
 	/*
 	 * It is possible that during that mac80211 has attempted
@@ -1272,7 +1281,7 @@
 	return 0;
 
 exit:
-	rt2x00lib_disable_radio(rt2x00dev);
+	rt2x00lib_stop(rt2x00dev);
 	rt2x00lib_uninitialize(rt2x00dev);
 	rt2x00debug_deregister(rt2x00dev);
 
diff --git a/drivers/net/wireless/rt2x00/rt2x00lib.h b/drivers/net/wireless/rt2x00/rt2x00lib.h
index c5fb3a72..797eb61 100644
--- a/drivers/net/wireless/rt2x00/rt2x00lib.h
+++ b/drivers/net/wireless/rt2x00/rt2x00lib.h
@@ -88,7 +88,7 @@
  */
 void rt2x00lib_config_intf(struct rt2x00_dev *rt2x00dev,
 			   struct rt2x00_intf *intf,
-			   enum ieee80211_if_types type,
+			   enum nl80211_iftype type,
 			   u8 *mac, u8 *bssid);
 void rt2x00lib_config_erp(struct rt2x00_dev *rt2x00dev,
 			  struct rt2x00_intf *intf,
@@ -181,6 +181,8 @@
 void rt2x00debug_deregister(struct rt2x00_dev *rt2x00dev);
 void rt2x00debug_dump_frame(struct rt2x00_dev *rt2x00dev,
 			    enum rt2x00_dump_type type, struct sk_buff *skb);
+void rt2x00debug_update_crypto(struct rt2x00_dev *rt2x00dev,
+			       enum cipher cipher, enum rx_crypto status);
 #else
 static inline void rt2x00debug_register(struct rt2x00_dev *rt2x00dev)
 {
@@ -195,9 +197,54 @@
 					  struct sk_buff *skb)
 {
 }
+
+static inline void rt2x00debug_update_crypto(struct rt2x00_dev *rt2x00dev,
+					     enum cipher cipher,
+					     enum rx_crypto status)
+{
+}
 #endif /* CONFIG_RT2X00_LIB_DEBUGFS */
 
 /*
+ * Crypto handlers.
+ */
+#ifdef CONFIG_RT2X00_LIB_CRYPTO
+enum cipher rt2x00crypto_key_to_cipher(struct ieee80211_key_conf *key);
+unsigned int rt2x00crypto_tx_overhead(struct ieee80211_tx_info *tx_info);
+void rt2x00crypto_tx_remove_iv(struct sk_buff *skb, unsigned int iv_len);
+void rt2x00crypto_tx_insert_iv(struct sk_buff *skb);
+void rt2x00crypto_rx_insert_iv(struct sk_buff *skb, unsigned int align,
+			       unsigned int header_length,
+			       struct rxdone_entry_desc *rxdesc);
+#else
+static inline enum cipher rt2x00crypto_key_to_cipher(struct ieee80211_key_conf *key)
+{
+	return CIPHER_NONE;
+}
+
+static inline unsigned int rt2x00crypto_tx_overhead(struct ieee80211_tx_info *tx_info)
+{
+	return 0;
+}
+
+static inline void rt2x00crypto_tx_remove_iv(struct sk_buff *skb,
+					     unsigned int iv_len)
+{
+}
+
+static inline void rt2x00crypto_tx_insert_iv(struct sk_buff *skb)
+{
+}
+
+static inline void rt2x00crypto_rx_insert_iv(struct sk_buff *skb,
+					     unsigned int align,
+					     unsigned int header_length,
+					     struct rxdone_entry_desc *rxdesc)
+{
+}
+#endif
+
+/*
  * RFkill handlers.
  */
 #ifdef CONFIG_RT2X00_LIB_RFKILL
diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c
index d065073..2c6cc5c 100644
--- a/drivers/net/wireless/rt2x00/rt2x00mac.c
+++ b/drivers/net/wireless/rt2x00/rt2x00mac.c
@@ -36,21 +36,22 @@
 	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(frag_skb);
 	struct ieee80211_tx_info *rts_info;
 	struct sk_buff *skb;
-	int size;
+	unsigned int data_length;
+	int retval = 0;
 
 	if (tx_info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT)
-		size = sizeof(struct ieee80211_cts);
+		data_length = sizeof(struct ieee80211_cts);
 	else
-		size = sizeof(struct ieee80211_rts);
+		data_length = sizeof(struct ieee80211_rts);
 
-	skb = dev_alloc_skb(size + rt2x00dev->hw->extra_tx_headroom);
-	if (!skb) {
+	skb = dev_alloc_skb(data_length + rt2x00dev->hw->extra_tx_headroom);
+	if (unlikely(!skb)) {
 		WARNING(rt2x00dev, "Failed to create RTS/CTS frame.\n");
-		return NETDEV_TX_BUSY;
+		return -ENOMEM;
 	}
 
 	skb_reserve(skb, rt2x00dev->hw->extra_tx_headroom);
-	skb_put(skb, size);
+	skb_put(skb, data_length);
 
 	/*
 	 * Copy TX information over from original frame to
@@ -63,7 +64,6 @@
 	 */
 	memcpy(skb->cb, frag_skb->cb, sizeof(skb->cb));
 	rts_info = IEEE80211_SKB_CB(skb);
-	rts_info->control.hw_key = NULL;
 	rts_info->flags &= ~IEEE80211_TX_CTL_USE_RTS_CTS;
 	rts_info->flags &= ~IEEE80211_TX_CTL_USE_CTS_PROTECT;
 	rts_info->flags &= ~IEEE80211_TX_CTL_REQ_TX_STATUS;
@@ -73,22 +73,33 @@
 	else
 		rts_info->flags &= ~IEEE80211_TX_CTL_NO_ACK;
 
+	skb->do_not_encrypt = 1;
+
+	/*
+	 * RTS/CTS frame should use the length of the frame plus any
+	 * encryption overhead that will be added by the hardware.
+	 */
+#ifdef CONFIG_RT2X00_LIB_CRYPTO
+	if (!frag_skb->do_not_encrypt)
+		data_length += rt2x00crypto_tx_overhead(tx_info);
+#endif /* CONFIG_RT2X00_LIB_CRYPTO */
+
 	if (tx_info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT)
 		ieee80211_ctstoself_get(rt2x00dev->hw, tx_info->control.vif,
-					frag_skb->data, size, tx_info,
+					frag_skb->data, data_length, tx_info,
 					(struct ieee80211_cts *)(skb->data));
 	else
 		ieee80211_rts_get(rt2x00dev->hw, tx_info->control.vif,
-				  frag_skb->data, size, tx_info,
+				  frag_skb->data, data_length, tx_info,
 				  (struct ieee80211_rts *)(skb->data));
 
-	if (rt2x00queue_write_tx_frame(queue, skb)) {
+	retval = rt2x00queue_write_tx_frame(queue, skb);
+	if (retval) {
 		dev_kfree_skb_any(skb);
 		WARNING(rt2x00dev, "Failed to send RTS/CTS frame.\n");
-		return NETDEV_TX_BUSY;
 	}
 
-	return NETDEV_TX_OK;
+	return retval;
 }
 
 int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
@@ -106,11 +117,8 @@
 	 * Note that we can only stop the TX queues inside the TX path
 	 * due to possible race conditions in mac80211.
 	 */
-	if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags)) {
-		ieee80211_stop_queues(hw);
-		dev_kfree_skb_any(skb);
-		return NETDEV_TX_OK;
-	}
+	if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags))
+		goto exit_fail;
 
 	/*
 	 * Determine which queue to put packet on.
@@ -141,26 +149,25 @@
 	if ((tx_info->flags & (IEEE80211_TX_CTL_USE_RTS_CTS |
 			       IEEE80211_TX_CTL_USE_CTS_PROTECT)) &&
 	    !rt2x00dev->ops->hw->set_rts_threshold) {
-		if (rt2x00queue_available(queue) <= 1) {
-			ieee80211_stop_queue(rt2x00dev->hw, qid);
-			return NETDEV_TX_BUSY;
-		}
+		if (rt2x00queue_available(queue) <= 1)
+			goto exit_fail;
 
-		if (rt2x00mac_tx_rts_cts(rt2x00dev, queue, skb)) {
-			ieee80211_stop_queue(rt2x00dev->hw, qid);
-			return NETDEV_TX_BUSY;
-		}
+		if (rt2x00mac_tx_rts_cts(rt2x00dev, queue, skb))
+			goto exit_fail;
 	}
 
-	if (rt2x00queue_write_tx_frame(queue, skb)) {
-		ieee80211_stop_queue(rt2x00dev->hw, qid);
-		return NETDEV_TX_BUSY;
-	}
+	if (rt2x00queue_write_tx_frame(queue, skb))
+		goto exit_fail;
 
 	if (rt2x00queue_threshold(queue))
 		ieee80211_stop_queue(rt2x00dev->hw, qid);
 
 	return NETDEV_TX_OK;
+
+ exit_fail:
+	ieee80211_stop_queue(rt2x00dev->hw, qid);
+	dev_kfree_skb_any(skb);
+	return NETDEV_TX_OK;
 }
 EXPORT_SYMBOL_GPL(rt2x00mac_tx);
 
@@ -168,7 +175,7 @@
 {
 	struct rt2x00_dev *rt2x00dev = hw->priv;
 
-	if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags))
+	if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags))
 		return 0;
 
 	return rt2x00lib_start(rt2x00dev);
@@ -179,7 +186,7 @@
 {
 	struct rt2x00_dev *rt2x00dev = hw->priv;
 
-	if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags))
+	if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags))
 		return;
 
 	rt2x00lib_stop(rt2x00dev);
@@ -199,12 +206,12 @@
 	 * Don't allow interfaces to be added
 	 * the device has disappeared.
 	 */
-	if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags) ||
-	    !test_bit(DEVICE_STARTED, &rt2x00dev->flags))
+	if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags) ||
+	    !test_bit(DEVICE_STATE_STARTED, &rt2x00dev->flags))
 		return -ENODEV;
 
 	switch (conf->type) {
-	case IEEE80211_IF_TYPE_AP:
+	case NL80211_IFTYPE_AP:
 		/*
 		 * We don't support mixed combinations of
 		 * sta and ap interfaces.
@@ -220,8 +227,8 @@
 			return -ENOBUFS;
 
 		break;
-	case IEEE80211_IF_TYPE_STA:
-	case IEEE80211_IF_TYPE_IBSS:
+	case NL80211_IFTYPE_STATION:
+	case NL80211_IFTYPE_ADHOC:
 		/*
 		 * We don't support mixed combinations of
 		 * sta and ap interfaces.
@@ -249,7 +256,7 @@
 	 */
 	for (i = 0; i < queue->limit; i++) {
 		entry = &queue->entries[i];
-		if (!__test_and_set_bit(ENTRY_BCN_ASSIGNED, &entry->flags))
+		if (!test_and_set_bit(ENTRY_BCN_ASSIGNED, &entry->flags))
 			break;
 	}
 
@@ -261,7 +268,7 @@
 	 * increase interface count and start initialization.
 	 */
 
-	if (conf->type == IEEE80211_IF_TYPE_AP)
+	if (conf->type == NL80211_IFTYPE_AP)
 		rt2x00dev->intf_ap_count++;
 	else
 		rt2x00dev->intf_sta_count++;
@@ -270,7 +277,7 @@
 	spin_lock_init(&intf->seqlock);
 	intf->beacon = entry;
 
-	if (conf->type == IEEE80211_IF_TYPE_AP)
+	if (conf->type == NL80211_IFTYPE_AP)
 		memcpy(&intf->bssid, conf->mac_addr, ETH_ALEN);
 	memcpy(&intf->mac, conf->mac_addr, ETH_ALEN);
 
@@ -303,12 +310,12 @@
 	 * either the device has disappeared or when
 	 * no interface is present.
 	 */
-	if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags) ||
-	    (conf->type == IEEE80211_IF_TYPE_AP && !rt2x00dev->intf_ap_count) ||
-	    (conf->type != IEEE80211_IF_TYPE_AP && !rt2x00dev->intf_sta_count))
+	if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags) ||
+	    (conf->type == NL80211_IFTYPE_AP && !rt2x00dev->intf_ap_count) ||
+	    (conf->type != NL80211_IFTYPE_AP && !rt2x00dev->intf_sta_count))
 		return;
 
-	if (conf->type == IEEE80211_IF_TYPE_AP)
+	if (conf->type == NL80211_IFTYPE_AP)
 		rt2x00dev->intf_ap_count--;
 	else
 		rt2x00dev->intf_sta_count--;
@@ -317,59 +324,59 @@
 	 * Release beacon entry so it is available for
 	 * new interfaces again.
 	 */
-	__clear_bit(ENTRY_BCN_ASSIGNED, &intf->beacon->flags);
+	clear_bit(ENTRY_BCN_ASSIGNED, &intf->beacon->flags);
 
 	/*
 	 * Make sure the bssid and mac address registers
 	 * are cleared to prevent false ACKing of frames.
 	 */
 	rt2x00lib_config_intf(rt2x00dev, intf,
-			      IEEE80211_IF_TYPE_INVALID, NULL, NULL);
+			      NL80211_IFTYPE_UNSPECIFIED, NULL, NULL);
 }
 EXPORT_SYMBOL_GPL(rt2x00mac_remove_interface);
 
 int rt2x00mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf)
 {
 	struct rt2x00_dev *rt2x00dev = hw->priv;
-	int force_reconfig;
+	int radio_on;
+	int status;
 
 	/*
 	 * Mac80211 might be calling this function while we are trying
 	 * to remove the device or perhaps suspending it.
 	 */
-	if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags))
+	if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags))
 		return 0;
 
 	/*
-	 * Check if we need to disable the radio,
-	 * if this is not the case, at least the RX must be disabled.
+	 * Only change device state when the radio is enabled. It does not
+	 * matter what parameters we have configured when the radio is disabled
+	 * because we won't be able to send or receive anyway. Also note that
+	 * some configuration parameters (e.g. channel and antenna values) can
+	 * only be set when the radio is enabled.
 	 */
-	if (test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags)) {
-		if (!conf->radio_enabled)
-			rt2x00lib_disable_radio(rt2x00dev);
-		else
-			rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_OFF);
-	}
+	radio_on = test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags);
+	if (conf->radio_enabled) {
+		/* For programming the values, we have to turn RX off */
+		rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_OFF);
 
-	/*
-	 * When the DEVICE_DIRTY_CONFIG flag is set, the device has recently
-	 * been started and the configuration must be forced upon the hardware.
-	 * Otherwise registers will not be intialized correctly and could
-	 * result in non-working hardware because essential registers aren't
-	 * initialized.
-	 */
-	force_reconfig =
-	    __test_and_clear_bit(DEVICE_DIRTY_CONFIG, &rt2x00dev->flags);
+		/* Enable the radio */
+		status = rt2x00lib_enable_radio(rt2x00dev);
+		if (unlikely(status))
+			return status;
 
-	rt2x00lib_config(rt2x00dev, conf, force_reconfig);
+		/*
+		 * When we've just turned on the radio, we want to reprogram
+		 * everything to ensure a consistent state
+		 */
+		rt2x00lib_config(rt2x00dev, conf, !radio_on);
 
-	/*
-	 * Reenable RX only if the radio should be on.
-	 */
-	if (test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags))
+		/* Turn RX back on */
 		rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_ON);
-	else if (conf->radio_enabled)
-		return rt2x00lib_enable_radio(rt2x00dev);
+	} else {
+		/* Disable the radio */
+		rt2x00lib_disable_radio(rt2x00dev);
+	}
 
 	return 0;
 }
@@ -388,7 +395,7 @@
 	 * Mac80211 might be calling this function while we are trying
 	 * to remove the device or perhaps suspending it.
 	 */
-	if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags))
+	if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags))
 		return 0;
 
 	spin_lock(&intf->lock);
@@ -467,6 +474,91 @@
 }
 EXPORT_SYMBOL_GPL(rt2x00mac_configure_filter);
 
+#ifdef CONFIG_RT2X00_LIB_CRYPTO
+int rt2x00mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
+		      const u8 *local_address, const u8 *address,
+		      struct ieee80211_key_conf *key)
+{
+	struct rt2x00_dev *rt2x00dev = hw->priv;
+	int (*set_key) (struct rt2x00_dev *rt2x00dev,
+			struct rt2x00lib_crypto *crypto,
+			struct ieee80211_key_conf *key);
+	struct rt2x00lib_crypto crypto;
+
+	if (!test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags))
+		return -EOPNOTSUPP;
+	else if (key->keylen > 32)
+		return -ENOSPC;
+
+	memset(&crypto, 0, sizeof(crypto));
+
+	/*
+	 * When in STA mode, bssidx is always 0 otherwise local_address[5]
+	 * contains the bss number, see BSS_ID_MASK comments for details.
+	 */
+	if (rt2x00dev->intf_sta_count)
+		crypto.bssidx = 0;
+	else
+		crypto.bssidx =
+		    local_address[5] & (rt2x00dev->ops->max_ap_intf - 1);
+
+	crypto.cipher = rt2x00crypto_key_to_cipher(key);
+	if (crypto.cipher == CIPHER_NONE)
+		return -EOPNOTSUPP;
+
+	crypto.cmd = cmd;
+	crypto.address = address;
+
+	if (crypto.cipher == CIPHER_TKIP) {
+		if (key->keylen > NL80211_TKIP_DATA_OFFSET_ENCR_KEY)
+			memcpy(&crypto.key,
+			       &key->key[NL80211_TKIP_DATA_OFFSET_ENCR_KEY],
+			       sizeof(crypto.key));
+
+		if (key->keylen > NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY)
+			memcpy(&crypto.tx_mic,
+			       &key->key[NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY],
+			       sizeof(crypto.tx_mic));
+
+		if (key->keylen > NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY)
+			memcpy(&crypto.rx_mic,
+			       &key->key[NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY],
+			       sizeof(crypto.rx_mic));
+	} else
+		memcpy(&crypto.key, &key->key[0], key->keylen);
+
+	/*
+	 * Each BSS has a maximum of 4 shared keys.
+	 * Shared key index values:
+	 *	0) BSS0 key0
+	 *	1) BSS0 key1
+	 *	...
+	 *	4) BSS1 key0
+	 *	...
+	 *	8) BSS2 key0
+	 *	...
+	 * Both pairwise as shared key indeces are determined by
+	 * driver. This is required because the hardware requires
+	 * keys to be assigned in correct order (When key 1 is
+	 * provided but key 0 is not, then the key is not found
+	 * by the hardware during RX).
+	 */
+	if (cmd == SET_KEY)
+		key->hw_key_idx = 0;
+
+	if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE)
+		set_key = rt2x00dev->ops->lib->config_pairwise_key;
+	else
+		set_key = rt2x00dev->ops->lib->config_shared_key;
+
+	if (!set_key)
+		return -EOPNOTSUPP;
+
+	return set_key(rt2x00dev, &crypto, key);
+}
+EXPORT_SYMBOL_GPL(rt2x00mac_set_key);
+#endif /* CONFIG_RT2X00_LIB_CRYPTO */
+
 int rt2x00mac_get_stats(struct ieee80211_hw *hw,
 			struct ieee80211_low_level_stats *stats)
 {
@@ -575,10 +667,11 @@
 		queue->cw_max = 10; /* cw_min: 2^10 = 1024. */
 
 	queue->aifs = params->aifs;
+	queue->txop = params->txop;
 
 	INFO(rt2x00dev,
-	     "Configured TX queue %d - CWmin: %d, CWmax: %d, Aifs: %d.\n",
-	     queue_idx, queue->cw_min, queue->cw_max, queue->aifs);
+	     "Configured TX queue %d - CWmin: %d, CWmax: %d, Aifs: %d, TXop: %d.\n",
+	     queue_idx, queue->cw_min, queue->cw_max, queue->aifs, queue->txop);
 
 	return 0;
 }
diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c
index 898cdd7..1676ac4 100644
--- a/drivers/net/wireless/rt2x00/rt2x00queue.c
+++ b/drivers/net/wireless/rt2x00/rt2x00queue.c
@@ -33,10 +33,11 @@
 struct sk_buff *rt2x00queue_alloc_rxskb(struct rt2x00_dev *rt2x00dev,
 					struct queue_entry *entry)
 {
-	unsigned int frame_size;
-	unsigned int reserved_size;
 	struct sk_buff *skb;
 	struct skb_frame_desc *skbdesc;
+	unsigned int frame_size;
+	unsigned int head_size = 0;
+	unsigned int tail_size = 0;
 
 	/*
 	 * The frame size includes descriptor size, because the
@@ -49,16 +50,32 @@
 	 * this means we need at least 3 bytes for moving the frame
 	 * into the correct offset.
 	 */
-	reserved_size = 4;
+	head_size = 4;
+
+	/*
+	 * For IV/EIV/ICV assembly we must make sure there is
+	 * at least 8 bytes bytes available in headroom for IV/EIV
+	 * and 4 bytes for ICV data as tailroon.
+	 */
+#ifdef CONFIG_RT2X00_LIB_CRYPTO
+	if (test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags)) {
+		head_size += 8;
+		tail_size += 4;
+	}
+#endif /* CONFIG_RT2X00_LIB_CRYPTO */
 
 	/*
 	 * Allocate skbuffer.
 	 */
-	skb = dev_alloc_skb(frame_size + reserved_size);
+	skb = dev_alloc_skb(frame_size + head_size + tail_size);
 	if (!skb)
 		return NULL;
 
-	skb_reserve(skb, reserved_size);
+	/*
+	 * Make sure we not have a frame with the requested bytes
+	 * available in the head and tail.
+	 */
+	skb_reserve(skb, head_size);
 	skb_put(skb, frame_size);
 
 	/*
@@ -83,8 +100,21 @@
 {
 	struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
 
-	skbdesc->skb_dma = dma_map_single(rt2x00dev->dev, skb->data, skb->len,
-					  DMA_TO_DEVICE);
+	/*
+	 * If device has requested headroom, we should make sure that
+	 * is also mapped to the DMA so it can be used for transfering
+	 * additional descriptor information to the hardware.
+	 */
+	skb_push(skb, rt2x00dev->hw->extra_tx_headroom);
+
+	skbdesc->skb_dma =
+	    dma_map_single(rt2x00dev->dev, skb->data, skb->len, DMA_TO_DEVICE);
+
+	/*
+	 * Restore data pointer to original location again.
+	 */
+	skb_pull(skb, rt2x00dev->hw->extra_tx_headroom);
+
 	skbdesc->flags |= SKBDESC_DMA_MAPPED_TX;
 }
 EXPORT_SYMBOL_GPL(rt2x00queue_map_txskb);
@@ -100,7 +130,12 @@
 	}
 
 	if (skbdesc->flags & SKBDESC_DMA_MAPPED_TX) {
-		dma_unmap_single(rt2x00dev->dev, skbdesc->skb_dma, skb->len,
+		/*
+		 * Add headroom to the skb length, it has been removed
+		 * by the driver, but it was actually mapped to DMA.
+		 */
+		dma_unmap_single(rt2x00dev->dev, skbdesc->skb_dma,
+				 skb->len + rt2x00dev->hw->extra_tx_headroom,
 				 DMA_TO_DEVICE);
 		skbdesc->flags &= ~SKBDESC_DMA_MAPPED_TX;
 	}
@@ -120,7 +155,6 @@
 {
 	struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
 	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(entry->skb);
-	struct rt2x00_intf *intf = vif_to_intf(tx_info->control.vif);
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)entry->skb->data;
 	struct ieee80211_rate *rate =
 	    ieee80211_get_tx_rate(rt2x00dev->hw, tx_info);
@@ -140,7 +174,7 @@
 	txdesc->cw_max = entry->queue->cw_max;
 	txdesc->aifs = entry->queue->aifs;
 
-	/* Data length should be extended with 4 bytes for CRC */
+	/* Data length + CRC + IV/EIV/ICV/MMIC (when using encryption) */
 	data_length = entry->skb->len + 4;
 
 	/*
@@ -149,6 +183,35 @@
 	if (!(tx_info->flags & IEEE80211_TX_CTL_NO_ACK))
 		__set_bit(ENTRY_TXD_ACK, &txdesc->flags);
 
+#ifdef CONFIG_RT2X00_LIB_CRYPTO
+	if (test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags) &&
+	    !entry->skb->do_not_encrypt) {
+		struct ieee80211_key_conf *hw_key = tx_info->control.hw_key;
+
+		__set_bit(ENTRY_TXD_ENCRYPT, &txdesc->flags);
+
+		txdesc->cipher = rt2x00crypto_key_to_cipher(hw_key);
+
+		if (hw_key->flags & IEEE80211_KEY_FLAG_PAIRWISE)
+			__set_bit(ENTRY_TXD_ENCRYPT_PAIRWISE, &txdesc->flags);
+
+		txdesc->key_idx = hw_key->hw_key_idx;
+		txdesc->iv_offset = ieee80211_get_hdrlen_from_skb(entry->skb);
+
+		/*
+		 * Extend frame length to include all encryption overhead
+		 * that will be added by the hardware.
+		 */
+		data_length += rt2x00crypto_tx_overhead(tx_info);
+
+		if (!(hw_key->flags & IEEE80211_KEY_FLAG_GENERATE_IV))
+			__set_bit(ENTRY_TXD_ENCRYPT_IV, &txdesc->flags);
+
+		if (!(hw_key->flags & IEEE80211_KEY_FLAG_GENERATE_MMIC))
+			__set_bit(ENTRY_TXD_ENCRYPT_MMIC, &txdesc->flags);
+	}
+#endif /* CONFIG_RT2X00_LIB_CRYPTO */
+
 	/*
 	 * Check if this is a RTS/CTS frame
 	 */
@@ -214,16 +277,22 @@
 	 * sequence counter given by mac80211.
 	 */
 	if (tx_info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) {
-		spin_lock_irqsave(&intf->seqlock, irqflags);
+		if (likely(tx_info->control.vif)) {
+			struct rt2x00_intf *intf;
 
-		if (test_bit(ENTRY_TXD_FIRST_FRAGMENT, &txdesc->flags))
-			intf->seqno += 0x10;
-		hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG);
-		hdr->seq_ctrl |= cpu_to_le16(intf->seqno);
+			intf = vif_to_intf(tx_info->control.vif);
 
-		spin_unlock_irqrestore(&intf->seqlock, irqflags);
+			spin_lock_irqsave(&intf->seqlock, irqflags);
 
-		__set_bit(ENTRY_TXD_GENERATE_SEQ, &txdesc->flags);
+			if (test_bit(ENTRY_TXD_FIRST_FRAGMENT, &txdesc->flags))
+				intf->seqno += 0x10;
+			hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG);
+			hdr->seq_ctrl |= cpu_to_le16(intf->seqno);
+
+			spin_unlock_irqrestore(&intf->seqlock, irqflags);
+
+			__set_bit(ENTRY_TXD_GENERATE_SEQ, &txdesc->flags);
+		}
 	}
 
 	/*
@@ -305,11 +374,12 @@
 	struct queue_entry *entry = rt2x00queue_get_entry(queue, Q_INDEX);
 	struct txentry_desc txdesc;
 	struct skb_frame_desc *skbdesc;
+	unsigned int iv_len;
 
 	if (unlikely(rt2x00queue_full(queue)))
 		return -EINVAL;
 
-	if (__test_and_set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags)) {
+	if (test_and_set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags)) {
 		ERROR(queue->rt2x00dev,
 		      "Arrived at non-free entry in the non-full queue %d.\n"
 		      "Please file bug report to %s.\n",
@@ -326,21 +396,42 @@
 	rt2x00queue_create_tx_descriptor(entry, &txdesc);
 
 	/*
-	 * skb->cb array is now ours and we are free to use it.
+	 * All information is retreived from the skb->cb array,
+	 * now we should claim ownership of the driver part of that
+	 * array.
 	 */
 	skbdesc = get_skb_frame_desc(entry->skb);
 	memset(skbdesc, 0, sizeof(*skbdesc));
 	skbdesc->entry = entry;
 
+	/*
+	 * When hardware encryption is supported, and this frame
+	 * is to be encrypted, we should strip the IV/EIV data from
+	 * the frame so we can provide it to the driver seperately.
+	 */
+	if (test_bit(ENTRY_TXD_ENCRYPT, &txdesc.flags) &&
+	    !test_bit(ENTRY_TXD_ENCRYPT_IV, &txdesc.flags) &&
+		(IEEE80211_SKB_CB(skb)->control.hw_key != NULL)) {
+		iv_len = IEEE80211_SKB_CB(skb)->control.hw_key->iv_len;
+		rt2x00crypto_tx_remove_iv(skb, iv_len);
+	}
+
+	/*
+	 * It could be possible that the queue was corrupted and this
+	 * call failed. Just drop the frame, we cannot rollback and pass
+	 * the frame to mac80211 because the skb->cb has now been tainted.
+	 */
 	if (unlikely(queue->rt2x00dev->ops->lib->write_tx_data(entry))) {
-		__clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags);
-		return -EIO;
+		clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags);
+		dev_kfree_skb_any(entry->skb);
+		entry->skb = NULL;
+		return 0;
 	}
 
 	if (test_bit(DRIVER_REQUIRE_DMA, &queue->rt2x00dev->flags))
 		rt2x00queue_map_txskb(queue->rt2x00dev, skb);
 
-	__set_bit(ENTRY_DATA_PENDING, &entry->flags);
+	set_bit(ENTRY_DATA_PENDING, &entry->flags);
 
 	rt2x00queue_index_inc(queue, Q_INDEX);
 	rt2x00queue_write_tx_descriptor(entry, &txdesc);
@@ -653,6 +744,7 @@
 
 	queue->rt2x00dev = rt2x00dev;
 	queue->qid = qid;
+	queue->txop = 0;
 	queue->aifs = 2;
 	queue->cw_min = 5;
 	queue->cw_max = 10;
diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.h b/drivers/net/wireless/rt2x00/rt2x00queue.h
index ff78e52..9dbf04f 100644
--- a/drivers/net/wireless/rt2x00/rt2x00queue.h
+++ b/drivers/net/wireless/rt2x00/rt2x00queue.h
@@ -87,10 +87,13 @@
  *
  * @SKBDESC_DMA_MAPPED_RX: &skb_dma field has been mapped for RX
  * @SKBDESC_DMA_MAPPED_TX: &skb_dma field has been mapped for TX
+ * @FRAME_DESC_IV_STRIPPED: Frame contained a IV/EIV provided by
+ *	mac80211 but was stripped for processing by the driver.
  */
 enum skb_frame_desc_flags {
-	SKBDESC_DMA_MAPPED_RX = (1 << 0),
-	SKBDESC_DMA_MAPPED_TX = (1 << 1),
+	SKBDESC_DMA_MAPPED_RX = 1 << 0,
+	SKBDESC_DMA_MAPPED_TX = 1 << 1,
+	FRAME_DESC_IV_STRIPPED = 1 << 2,
 };
 
 /**
@@ -104,6 +107,8 @@
  * @desc: Pointer to descriptor part of the frame.
  *	Note that this pointer could point to something outside
  *	of the scope of the skb->data pointer.
+ * @iv: IV data used during encryption/decryption.
+ * @eiv: EIV data used during encryption/decryption.
  * @skb_dma: (PCI-only) the DMA address associated with the sk buffer.
  * @entry: The entry to which this sk buffer belongs.
  */
@@ -113,6 +118,9 @@
 	unsigned int desc_len;
 	void *desc;
 
+	__le32 iv;
+	__le32 eiv;
+
 	dma_addr_t skb_dma;
 
 	struct queue_entry *entry;
@@ -132,13 +140,14 @@
 /**
  * enum rxdone_entry_desc_flags: Flags for &struct rxdone_entry_desc
  *
- * @RXDONE_SIGNAL_PLCP: Does the signal field contain the plcp value,
- *	or does it contain the bitrate itself.
+ * @RXDONE_SIGNAL_PLCP: Signal field contains the plcp value.
+ * @RXDONE_SIGNAL_BITRATE: Signal field contains the bitrate value.
  * @RXDONE_MY_BSS: Does this frame originate from device's BSS.
  */
 enum rxdone_entry_desc_flags {
 	RXDONE_SIGNAL_PLCP = 1 << 0,
-	RXDONE_MY_BSS = 1 << 1,
+	RXDONE_SIGNAL_BITRATE = 1 << 1,
+	RXDONE_MY_BSS = 1 << 2,
 };
 
 /**
@@ -152,7 +161,11 @@
  * @size: Data size of the received frame.
  * @flags: MAC80211 receive flags (See &enum mac80211_rx_flags).
  * @dev_flags: Ralink receive flags (See &enum rxdone_entry_desc_flags).
-
+ * @cipher: Cipher type used during decryption.
+ * @cipher_status: Decryption status.
+ * @iv: IV data used during decryption.
+ * @eiv: EIV data used during decryption.
+ * @icv: ICV data used during decryption.
  */
 struct rxdone_entry_desc {
 	u64 timestamp;
@@ -161,6 +174,12 @@
 	int size;
 	int flags;
 	int dev_flags;
+	u8 cipher;
+	u8 cipher_status;
+
+	__le32 iv;
+	__le32 eiv;
+	__le32 icv;
 };
 
 /**
@@ -206,6 +225,10 @@
  * @ENTRY_TXD_BURST: This frame belongs to the same burst event.
  * @ENTRY_TXD_ACK: An ACK is required for this frame.
  * @ENTRY_TXD_RETRY_MODE: When set, the long retry count is used.
+ * @ENTRY_TXD_ENCRYPT: This frame should be encrypted.
+ * @ENTRY_TXD_ENCRYPT_PAIRWISE: Use pairwise key table (instead of shared).
+ * @ENTRY_TXD_ENCRYPT_IV: Generate IV/EIV in hardware.
+ * @ENTRY_TXD_ENCRYPT_MMIC: Generate MIC in hardware.
  */
 enum txentry_desc_flags {
 	ENTRY_TXD_RTS_FRAME,
@@ -218,6 +241,10 @@
 	ENTRY_TXD_BURST,
 	ENTRY_TXD_ACK,
 	ENTRY_TXD_RETRY_MODE,
+	ENTRY_TXD_ENCRYPT,
+	ENTRY_TXD_ENCRYPT_PAIRWISE,
+	ENTRY_TXD_ENCRYPT_IV,
+	ENTRY_TXD_ENCRYPT_MMIC,
 };
 
 /**
@@ -236,6 +263,9 @@
  * @ifs: IFS value.
  * @cw_min: cwmin value.
  * @cw_max: cwmax value.
+ * @cipher: Cipher type used for encryption.
+ * @key_idx: Key index used for encryption.
+ * @iv_offset: Position where IV should be inserted by hardware.
  */
 struct txentry_desc {
 	unsigned long flags;
@@ -252,6 +282,10 @@
 	short ifs;
 	short cw_min;
 	short cw_max;
+
+	enum cipher cipher;
+	u16 key_idx;
+	u16 iv_offset;
 };
 
 /**
@@ -335,6 +369,7 @@
  * @length: Number of frames in queue.
  * @index: Index pointers to entry positions in the queue,
  *	use &enum queue_index to get a specific index field.
+ * @txop: maximum burst time.
  * @aifs: The aifs value for outgoing frames (field ignored in RX queue).
  * @cw_min: The cw min value for outgoing frames (field ignored in RX queue).
  * @cw_max: The cw max value for outgoing frames (field ignored in RX queue).
@@ -354,6 +389,7 @@
 	unsigned short length;
 	unsigned short index[Q_INDEX_MAX];
 
+	unsigned short txop;
 	unsigned short aifs;
 	unsigned short cw_min;
 	unsigned short cw_max;
@@ -484,25 +520,51 @@
 }
 
 /**
- * rt2x00_desc_read - Read a word from the hardware descriptor.
+ * _rt2x00_desc_read - Read a word from the hardware descriptor.
+ * @desc: Base descriptor address
+ * @word: Word index from where the descriptor should be read.
+ * @value: Address where the descriptor value should be written into.
+ */
+static inline void _rt2x00_desc_read(__le32 *desc, const u8 word, __le32 *value)
+{
+	*value = desc[word];
+}
+
+/**
+ * rt2x00_desc_read - Read a word from the hardware descriptor, this
+ * function will take care of the byte ordering.
  * @desc: Base descriptor address
  * @word: Word index from where the descriptor should be read.
  * @value: Address where the descriptor value should be written into.
  */
 static inline void rt2x00_desc_read(__le32 *desc, const u8 word, u32 *value)
 {
-	*value = le32_to_cpu(desc[word]);
+	__le32 tmp;
+	_rt2x00_desc_read(desc, word, &tmp);
+	*value = le32_to_cpu(tmp);
 }
 
 /**
- * rt2x00_desc_write - wrote a word to the hardware descriptor.
+ * rt2x00_desc_write - write a word to the hardware descriptor, this
+ * function will take care of the byte ordering.
+ * @desc: Base descriptor address
+ * @word: Word index from where the descriptor should be written.
+ * @value: Value that should be written into the descriptor.
+ */
+static inline void _rt2x00_desc_write(__le32 *desc, const u8 word, __le32 value)
+{
+	desc[word] = value;
+}
+
+/**
+ * rt2x00_desc_write - write a word to the hardware descriptor.
  * @desc: Base descriptor address
  * @word: Word index from where the descriptor should be written.
  * @value: Value that should be written into the descriptor.
  */
 static inline void rt2x00_desc_write(__le32 *desc, const u8 word, u32 value)
 {
-	desc[word] = cpu_to_le32(value);
+	_rt2x00_desc_write(desc, word, cpu_to_le32(value));
 }
 
 #endif /* RT2X00QUEUE_H */
diff --git a/drivers/net/wireless/rt2x00/rt2x00reg.h b/drivers/net/wireless/rt2x00/rt2x00reg.h
index 2ea7866..c2fba7c 100644
--- a/drivers/net/wireless/rt2x00/rt2x00reg.h
+++ b/drivers/net/wireless/rt2x00/rt2x00reg.h
@@ -27,6 +27,16 @@
 #define RT2X00REG_H
 
 /*
+ * RX crypto status
+ */
+enum rx_crypto {
+	RX_CRYPTO_SUCCESS = 0,
+	RX_CRYPTO_FAIL_ICV = 1,
+	RX_CRYPTO_FAIL_MIC = 2,
+	RX_CRYPTO_FAIL_KEY = 3,
+};
+
+/*
  * Antenna values
  */
 enum antenna {
@@ -104,7 +114,14 @@
  */
 	CIPHER_CKIP64 = 5,
 	CIPHER_CKIP128 = 6,
-	CIPHER_TKIP_NO_MIC = 7,
+	CIPHER_TKIP_NO_MIC = 7, /* Don't send to device */
+
+/*
+ * Max cipher type.
+ * Note that CIPHER_NONE isn't counted, and CKIP64 and CKIP128
+ * are excluded due to limitations in mac80211.
+ */
+	CIPHER_MAX = 4,
 };
 
 /*
diff --git a/drivers/net/wireless/rt2x00/rt2x00rfkill.c b/drivers/net/wireless/rt2x00/rt2x00rfkill.c
index 04b2971..c3f53a9 100644
--- a/drivers/net/wireless/rt2x00/rt2x00rfkill.c
+++ b/drivers/net/wireless/rt2x00/rt2x00rfkill.c
@@ -41,20 +41,19 @@
 	/*
 	 * Only continue if there are enabled interfaces.
 	 */
-	if (!test_bit(DEVICE_STARTED, &rt2x00dev->flags))
+	if (!test_bit(DEVICE_STATE_STARTED, &rt2x00dev->flags))
 		return 0;
 
 	if (state == RFKILL_STATE_UNBLOCKED) {
-		INFO(rt2x00dev, "Hardware button pressed, enabling radio.\n");
-		__clear_bit(DEVICE_DISABLED_RADIO_HW, &rt2x00dev->flags);
+		INFO(rt2x00dev, "RFKILL event: enabling radio.\n");
+		clear_bit(DEVICE_STATE_DISABLED_RADIO_HW, &rt2x00dev->flags);
 		retval = rt2x00lib_enable_radio(rt2x00dev);
 	} else if (state == RFKILL_STATE_SOFT_BLOCKED) {
-		INFO(rt2x00dev, "Hardware button pressed, disabling radio.\n");
-		__set_bit(DEVICE_DISABLED_RADIO_HW, &rt2x00dev->flags);
+		INFO(rt2x00dev, "RFKILL event: disabling radio.\n");
+		set_bit(DEVICE_STATE_DISABLED_RADIO_HW, &rt2x00dev->flags);
 		rt2x00lib_disable_radio(rt2x00dev);
 	} else {
-		WARNING(rt2x00dev, "Received unexpected rfkill state %d.\n",
-			state);
+		WARNING(rt2x00dev, "RFKILL event: unknown state %d.\n", state);
 	}
 
 	return retval;
@@ -64,7 +63,12 @@
 {
 	struct rt2x00_dev *rt2x00dev = data;
 
-	*state = rt2x00dev->rfkill->state;
+	/*
+	 * rfkill_poll reports 1 when the key has been pressed and the
+	 * radio should be blocked.
+	 */
+	*state = rt2x00dev->ops->lib->rfkill_poll(rt2x00dev) ?
+	    RFKILL_STATE_SOFT_BLOCKED : RFKILL_STATE_UNBLOCKED;
 
 	return 0;
 }
@@ -73,19 +77,18 @@
 {
 	struct rt2x00_dev *rt2x00dev =
 	    container_of(work, struct rt2x00_dev, rfkill_work.work);
-	int state;
+	enum rfkill_state state;
 
-	if (!test_bit(RFKILL_STATE_REGISTERED, &rt2x00dev->rfkill_state))
+	if (!test_bit(RFKILL_STATE_REGISTERED, &rt2x00dev->rfkill_state) ||
+	    !test_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags))
 		return;
 
 	/*
-	 * rfkill_poll reports 1 when the key has been pressed and the
-	 * radio should be blocked.
+	 * Poll latest state and report it to rfkill who should sort
+	 * out if the state should be toggled or not.
 	 */
-	state = !rt2x00dev->ops->lib->rfkill_poll(rt2x00dev) ?
-	    RFKILL_STATE_UNBLOCKED : RFKILL_STATE_SOFT_BLOCKED;
-
-	rfkill_force_state(rt2x00dev->rfkill, state);
+	if (!rt2x00rfkill_get_state(rt2x00dev, &state))
+		rfkill_force_state(rt2x00dev->rfkill, state);
 
 	queue_delayed_work(rt2x00dev->hw->workqueue,
 			   &rt2x00dev->rfkill_work, RFKILL_POLL_INTERVAL);
@@ -93,8 +96,8 @@
 
 void rt2x00rfkill_register(struct rt2x00_dev *rt2x00dev)
 {
-	if (!test_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags) ||
-	    !test_bit(RFKILL_STATE_ALLOCATED, &rt2x00dev->rfkill_state))
+	if (!test_bit(RFKILL_STATE_ALLOCATED, &rt2x00dev->rfkill_state) ||
+	    test_bit(RFKILL_STATE_REGISTERED, &rt2x00dev->rfkill_state))
 		return;
 
 	if (rfkill_register(rt2x00dev->rfkill)) {
@@ -114,7 +117,7 @@
 
 void rt2x00rfkill_unregister(struct rt2x00_dev *rt2x00dev)
 {
-	if (!test_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags) ||
+	if (!test_bit(RFKILL_STATE_ALLOCATED, &rt2x00dev->rfkill_state) ||
 	    !test_bit(RFKILL_STATE_REGISTERED, &rt2x00dev->rfkill_state))
 		return;
 
@@ -127,21 +130,30 @@
 
 void rt2x00rfkill_allocate(struct rt2x00_dev *rt2x00dev)
 {
-	if (!test_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags))
+	struct device *dev = wiphy_dev(rt2x00dev->hw->wiphy);
+
+	if (test_bit(RFKILL_STATE_ALLOCATED, &rt2x00dev->rfkill_state))
 		return;
 
-	rt2x00dev->rfkill =
-	    rfkill_allocate(wiphy_dev(rt2x00dev->hw->wiphy), RFKILL_TYPE_WLAN);
+	rt2x00dev->rfkill = rfkill_allocate(dev, RFKILL_TYPE_WLAN);
 	if (!rt2x00dev->rfkill) {
 		ERROR(rt2x00dev, "Failed to allocate rfkill handler.\n");
 		return;
 	}
 
+	__set_bit(RFKILL_STATE_ALLOCATED, &rt2x00dev->rfkill_state);
+
 	rt2x00dev->rfkill->name = rt2x00dev->ops->name;
 	rt2x00dev->rfkill->data = rt2x00dev;
-	rt2x00dev->rfkill->state = -1;
 	rt2x00dev->rfkill->toggle_radio = rt2x00rfkill_toggle_radio;
-	rt2x00dev->rfkill->get_state = rt2x00rfkill_get_state;
+	if (test_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags)) {
+		rt2x00dev->rfkill->get_state = rt2x00rfkill_get_state;
+		rt2x00dev->rfkill->state =
+			rt2x00dev->ops->lib->rfkill_poll(rt2x00dev) ?
+			    RFKILL_STATE_SOFT_BLOCKED : RFKILL_STATE_UNBLOCKED;
+	} else {
+		rt2x00dev->rfkill->state = RFKILL_STATE_UNBLOCKED;
+	}
 
 	INIT_DELAYED_WORK(&rt2x00dev->rfkill_work, rt2x00rfkill_poll);
 
@@ -150,8 +162,7 @@
 
 void rt2x00rfkill_free(struct rt2x00_dev *rt2x00dev)
 {
-	if (!test_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags) ||
-	    !test_bit(RFKILL_STATE_ALLOCATED, &rt2x00dev->rfkill_state))
+	if (!test_bit(RFKILL_STATE_ALLOCATED, &rt2x00dev->flags))
 		return;
 
 	cancel_delayed_work_sync(&rt2x00dev->rfkill_work);
diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c
index 2050227..b73a7e0 100644
--- a/drivers/net/wireless/rt2x00/rt2x00usb.c
+++ b/drivers/net/wireless/rt2x00/rt2x00usb.c
@@ -163,16 +163,11 @@
 	struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
 	struct txdone_entry_desc txdesc;
 
-	if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags) ||
+	if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags) ||
 	    !test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags))
 		return;
 
 	/*
-	 * Remove the descriptor data from the buffer.
-	 */
-	skb_pull(entry->skb, entry->queue->desc_size);
-
-	/*
 	 * Obtain the status about this packet.
 	 * Note that when the status is 0 it does not mean the
 	 * frame was send out correctly. It only means the frame
@@ -224,6 +219,12 @@
 			  entry->skb->data, length,
 			  rt2x00usb_interrupt_txdone, entry);
 
+	/*
+	 * Make sure the skb->data pointer points to the frame, not the
+	 * descriptor.
+	 */
+	skb_pull(entry->skb, entry->queue->desc_size);
+
 	return 0;
 }
 EXPORT_SYMBOL_GPL(rt2x00usb_write_tx_data);
@@ -232,7 +233,7 @@
 {
 	struct queue_entry_priv_usb *entry_priv = entry->priv_data;
 
-	if (__test_and_clear_bit(ENTRY_DATA_PENDING, &entry->flags))
+	if (test_and_clear_bit(ENTRY_DATA_PENDING, &entry->flags))
 		usb_submit_urb(entry_priv->urb, GFP_ATOMIC);
 }
 
@@ -283,7 +284,7 @@
 	struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
 	u8 rxd[32];
 
-	if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags) ||
+	if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags) ||
 	    !test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags))
 		return;
 
@@ -293,7 +294,7 @@
 	 * a problem.
 	 */
 	if (urb->actual_length < entry->queue->desc_size || urb->status) {
-		__set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags);
+		set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags);
 		usb_submit_urb(urb, GFP_ATOMIC);
 		return;
 	}
@@ -361,7 +362,7 @@
 			  entry->skb->data, entry->skb->len,
 			  rt2x00usb_interrupt_rxdone, entry);
 
-	__set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags);
+	set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags);
 	usb_submit_urb(entry_priv->urb, GFP_ATOMIC);
 }
 EXPORT_SYMBOL_GPL(rt2x00usb_init_rxentry);
diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c
index 087e90b..a461620 100644
--- a/drivers/net/wireless/rt2x00/rt61pci.c
+++ b/drivers/net/wireless/rt2x00/rt61pci.c
@@ -38,6 +38,13 @@
 #include "rt61pci.h"
 
 /*
+ * Allow hardware encryption to be disabled.
+ */
+static int modparam_nohwcrypt = 0;
+module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO);
+MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption.");
+
+/*
  * Register access.
  * BBP and RF register require indirect register access,
  * and use the CSR registers PHY_CSR3 and PHY_CSR4 to achieve this.
@@ -156,7 +163,7 @@
 	rt2x00_rf_write(rt2x00dev, word, value);
 }
 
-#ifdef CONFIG_RT61PCI_LEDS
+#ifdef CONFIG_RT2X00_LIB_LEDS
 /*
  * This function is only called from rt61pci_led_brightness()
  * make gcc happy by placing this function inside the
@@ -188,7 +195,7 @@
 	rt2x00_set_field32(&reg, HOST_CMD_CSR_INTERRUPT_MCU, 1);
 	rt2x00pci_register_write(rt2x00dev, HOST_CMD_CSR, reg);
 }
-#endif /* CONFIG_RT61PCI_LEDS */
+#endif /* CONFIG_RT2X00_LIB_LEDS */
 
 static void rt61pci_eepromregister_read(struct eeprom_93cx6 *eeprom)
 {
@@ -264,7 +271,7 @@
 };
 #endif /* CONFIG_RT2X00_LIB_DEBUGFS */
 
-#ifdef CONFIG_RT61PCI_RFKILL
+#ifdef CONFIG_RT2X00_LIB_RFKILL
 static int rt61pci_rfkill_poll(struct rt2x00_dev *rt2x00dev)
 {
 	u32 reg;
@@ -274,9 +281,9 @@
 }
 #else
 #define rt61pci_rfkill_poll	NULL
-#endif /* CONFIG_RT61PCI_RFKILL */
+#endif /* CONFIG_RT2X00_LIB_RFKILL */
 
-#ifdef CONFIG_RT61PCI_LEDS
+#ifdef CONFIG_RT2X00_LIB_LEDS
 static void rt61pci_brightness_set(struct led_classdev *led_cdev,
 				   enum led_brightness brightness)
 {
@@ -341,11 +348,209 @@
 	led->led_dev.blink_set = rt61pci_blink_set;
 	led->flags = LED_INITIALIZED;
 }
-#endif /* CONFIG_RT61PCI_LEDS */
+#endif /* CONFIG_RT2X00_LIB_LEDS */
 
 /*
  * Configuration handlers.
  */
+static int rt61pci_config_shared_key(struct rt2x00_dev *rt2x00dev,
+				     struct rt2x00lib_crypto *crypto,
+				     struct ieee80211_key_conf *key)
+{
+	struct hw_key_entry key_entry;
+	struct rt2x00_field32 field;
+	u32 mask;
+	u32 reg;
+
+	if (crypto->cmd == SET_KEY) {
+		/*
+		 * rt2x00lib can't determine the correct free
+		 * key_idx for shared keys. We have 1 register
+		 * with key valid bits. The goal is simple, read
+		 * the register, if that is full we have no slots
+		 * left.
+		 * Note that each BSS is allowed to have up to 4
+		 * shared keys, so put a mask over the allowed
+		 * entries.
+		 */
+		mask = (0xf << crypto->bssidx);
+
+		rt2x00pci_register_read(rt2x00dev, SEC_CSR0, &reg);
+		reg &= mask;
+
+		if (reg && reg == mask)
+			return -ENOSPC;
+
+		key->hw_key_idx += reg ? ffz(reg) : 0;
+
+		/*
+		 * Upload key to hardware
+		 */
+		memcpy(key_entry.key, crypto->key,
+		       sizeof(key_entry.key));
+		memcpy(key_entry.tx_mic, crypto->tx_mic,
+		       sizeof(key_entry.tx_mic));
+		memcpy(key_entry.rx_mic, crypto->rx_mic,
+		       sizeof(key_entry.rx_mic));
+
+		reg = SHARED_KEY_ENTRY(key->hw_key_idx);
+		rt2x00pci_register_multiwrite(rt2x00dev, reg,
+					      &key_entry, sizeof(key_entry));
+
+		/*
+		 * The cipher types are stored over 2 registers.
+		 * bssidx 0 and 1 keys are stored in SEC_CSR1 and
+		 * bssidx 1 and 2 keys are stored in SEC_CSR5.
+		 * Using the correct defines correctly will cause overhead,
+		 * so just calculate the correct offset.
+		 */
+		if (key->hw_key_idx < 8) {
+			field.bit_offset = (3 * key->hw_key_idx);
+			field.bit_mask = 0x7 << field.bit_offset;
+
+			rt2x00pci_register_read(rt2x00dev, SEC_CSR1, &reg);
+			rt2x00_set_field32(&reg, field, crypto->cipher);
+			rt2x00pci_register_write(rt2x00dev, SEC_CSR1, reg);
+		} else {
+			field.bit_offset = (3 * (key->hw_key_idx - 8));
+			field.bit_mask = 0x7 << field.bit_offset;
+
+			rt2x00pci_register_read(rt2x00dev, SEC_CSR5, &reg);
+			rt2x00_set_field32(&reg, field, crypto->cipher);
+			rt2x00pci_register_write(rt2x00dev, SEC_CSR5, reg);
+		}
+
+		/*
+		 * The driver does not support the IV/EIV generation
+		 * in hardware. However it doesn't support the IV/EIV
+		 * inside the ieee80211 frame either, but requires it
+		 * to be provided seperately for the descriptor.
+		 * rt2x00lib will cut the IV/EIV data out of all frames
+		 * given to us by mac80211, but we must tell mac80211
+		 * to generate the IV/EIV data.
+		 */
+		key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
+	}
+
+	/*
+	 * SEC_CSR0 contains only single-bit fields to indicate
+	 * a particular key is valid. Because using the FIELD32()
+	 * defines directly will cause a lot of overhead we use
+	 * a calculation to determine the correct bit directly.
+	 */
+	mask = 1 << key->hw_key_idx;
+
+	rt2x00pci_register_read(rt2x00dev, SEC_CSR0, &reg);
+	if (crypto->cmd == SET_KEY)
+		reg |= mask;
+	else if (crypto->cmd == DISABLE_KEY)
+		reg &= ~mask;
+	rt2x00pci_register_write(rt2x00dev, SEC_CSR0, reg);
+
+	return 0;
+}
+
+static int rt61pci_config_pairwise_key(struct rt2x00_dev *rt2x00dev,
+				       struct rt2x00lib_crypto *crypto,
+				       struct ieee80211_key_conf *key)
+{
+	struct hw_pairwise_ta_entry addr_entry;
+	struct hw_key_entry key_entry;
+	u32 mask;
+	u32 reg;
+
+	if (crypto->cmd == SET_KEY) {
+		/*
+		 * rt2x00lib can't determine the correct free
+		 * key_idx for pairwise keys. We have 2 registers
+		 * with key valid bits. The goal is simple, read
+		 * the first register, if that is full move to
+		 * the next register.
+		 * When both registers are full, we drop the key,
+		 * otherwise we use the first invalid entry.
+		 */
+		rt2x00pci_register_read(rt2x00dev, SEC_CSR2, &reg);
+		if (reg && reg == ~0) {
+			key->hw_key_idx = 32;
+			rt2x00pci_register_read(rt2x00dev, SEC_CSR3, &reg);
+			if (reg && reg == ~0)
+				return -ENOSPC;
+		}
+
+		key->hw_key_idx += reg ? ffz(reg) : 0;
+
+		/*
+		 * Upload key to hardware
+		 */
+		memcpy(key_entry.key, crypto->key,
+		       sizeof(key_entry.key));
+		memcpy(key_entry.tx_mic, crypto->tx_mic,
+		       sizeof(key_entry.tx_mic));
+		memcpy(key_entry.rx_mic, crypto->rx_mic,
+		       sizeof(key_entry.rx_mic));
+
+		memset(&addr_entry, 0, sizeof(addr_entry));
+		memcpy(&addr_entry, crypto->address, ETH_ALEN);
+		addr_entry.cipher = crypto->cipher;
+
+		reg = PAIRWISE_KEY_ENTRY(key->hw_key_idx);
+		rt2x00pci_register_multiwrite(rt2x00dev, reg,
+					      &key_entry, sizeof(key_entry));
+
+		reg = PAIRWISE_TA_ENTRY(key->hw_key_idx);
+		rt2x00pci_register_multiwrite(rt2x00dev, reg,
+					      &addr_entry, sizeof(addr_entry));
+
+		/*
+		 * Enable pairwise lookup table for given BSS idx,
+		 * without this received frames will not be decrypted
+		 * by the hardware.
+		 */
+		rt2x00pci_register_read(rt2x00dev, SEC_CSR4, &reg);
+		reg |= (1 << crypto->bssidx);
+		rt2x00pci_register_write(rt2x00dev, SEC_CSR4, reg);
+
+		/*
+		 * The driver does not support the IV/EIV generation
+		 * in hardware. However it doesn't support the IV/EIV
+		 * inside the ieee80211 frame either, but requires it
+		 * to be provided seperately for the descriptor.
+		 * rt2x00lib will cut the IV/EIV data out of all frames
+		 * given to us by mac80211, but we must tell mac80211
+		 * to generate the IV/EIV data.
+		 */
+		key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
+	}
+
+	/*
+	 * SEC_CSR2 and SEC_CSR3 contain only single-bit fields to indicate
+	 * a particular key is valid. Because using the FIELD32()
+	 * defines directly will cause a lot of overhead we use
+	 * a calculation to determine the correct bit directly.
+	 */
+	if (key->hw_key_idx < 32) {
+		mask = 1 << key->hw_key_idx;
+
+		rt2x00pci_register_read(rt2x00dev, SEC_CSR2, &reg);
+		if (crypto->cmd == SET_KEY)
+			reg |= mask;
+		else if (crypto->cmd == DISABLE_KEY)
+			reg &= ~mask;
+		rt2x00pci_register_write(rt2x00dev, SEC_CSR2, reg);
+	} else {
+		mask = 1 << (key->hw_key_idx - 32);
+
+		rt2x00pci_register_read(rt2x00dev, SEC_CSR3, &reg);
+		if (crypto->cmd == SET_KEY)
+			reg |= mask;
+		else if (crypto->cmd == DISABLE_KEY)
+			reg &= ~mask;
+		rt2x00pci_register_write(rt2x00dev, SEC_CSR3, reg);
+	}
+
+	return 0;
+}
+
 static void rt61pci_config_filter(struct rt2x00_dev *rt2x00dev,
 				  const unsigned int filter_flags)
 {
@@ -440,6 +645,30 @@
 	rt2x00pci_register_write(rt2x00dev, TXRX_CSR4, reg);
 }
 
+
+static void rt61pci_config_lna_gain(struct rt2x00_dev *rt2x00dev,
+				    struct rt2x00lib_conf *libconf)
+{
+	u16 eeprom;
+	short lna_gain = 0;
+
+	if (libconf->band == IEEE80211_BAND_2GHZ) {
+		if (test_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags))
+			lna_gain += 14;
+
+		rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_BG, &eeprom);
+		lna_gain -= rt2x00_get_field16(eeprom, EEPROM_RSSI_OFFSET_BG_1);
+	} else {
+		if (test_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags))
+			lna_gain += 14;
+
+		rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_A, &eeprom);
+		lna_gain -= rt2x00_get_field16(eeprom, EEPROM_RSSI_OFFSET_A_1);
+	}
+
+	rt2x00dev->lna_gain = lna_gain;
+}
+
 static void rt61pci_config_phymode(struct rt2x00_dev *rt2x00dev,
 				   const int basic_rate_mask)
 {
@@ -758,6 +987,9 @@
 			   struct rt2x00lib_conf *libconf,
 			   const unsigned int flags)
 {
+	/* Always recalculate LNA gain before changing configuration */
+	rt61pci_config_lna_gain(rt2x00dev, libconf);
+
 	if (flags & CONFIG_UPDATE_PHYMODE)
 		rt61pci_config_phymode(rt2x00dev, libconf->basic_rates);
 	if (flags & CONFIG_UPDATE_CHANNEL)
@@ -1246,16 +1478,6 @@
 
 	rt2x00pci_register_write(rt2x00dev, M2H_CMD_DONE_CSR, 0xffffffff);
 
-	rt2x00pci_register_read(rt2x00dev, AC_TXOP_CSR0, &reg);
-	rt2x00_set_field32(&reg, AC_TXOP_CSR0_AC0_TX_OP, 0);
-	rt2x00_set_field32(&reg, AC_TXOP_CSR0_AC1_TX_OP, 0);
-	rt2x00pci_register_write(rt2x00dev, AC_TXOP_CSR0, reg);
-
-	rt2x00pci_register_read(rt2x00dev, AC_TXOP_CSR1, &reg);
-	rt2x00_set_field32(&reg, AC_TXOP_CSR1_AC2_TX_OP, 192);
-	rt2x00_set_field32(&reg, AC_TXOP_CSR1_AC3_TX_OP, 48);
-	rt2x00pci_register_write(rt2x00dev, AC_TXOP_CSR1, reg);
-
 	/*
 	 * Clear all beacons
 	 * For the Beacon base registers we only need to clear
@@ -1533,8 +1755,8 @@
  * TX descriptor initialization
  */
 static void rt61pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
-				    struct sk_buff *skb,
-				    struct txentry_desc *txdesc)
+				  struct sk_buff *skb,
+				  struct txentry_desc *txdesc)
 {
 	struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
 	__le32 *txd = skbdesc->desc;
@@ -1548,7 +1770,7 @@
 	rt2x00_set_field32(&word, TXD_W1_AIFSN, txdesc->aifs);
 	rt2x00_set_field32(&word, TXD_W1_CWMIN, txdesc->cw_min);
 	rt2x00_set_field32(&word, TXD_W1_CWMAX, txdesc->cw_max);
-	rt2x00_set_field32(&word, TXD_W1_IV_OFFSET, IEEE80211_HEADER);
+	rt2x00_set_field32(&word, TXD_W1_IV_OFFSET, txdesc->iv_offset);
 	rt2x00_set_field32(&word, TXD_W1_HW_SEQUENCE,
 			   test_bit(ENTRY_TXD_GENERATE_SEQ, &txdesc->flags));
 	rt2x00_set_field32(&word, TXD_W1_BUFFER_COUNT, 1);
@@ -1561,6 +1783,11 @@
 	rt2x00_set_field32(&word, TXD_W2_PLCP_LENGTH_HIGH, txdesc->length_high);
 	rt2x00_desc_write(txd, 2, word);
 
+	if (test_bit(ENTRY_TXD_ENCRYPT, &txdesc->flags)) {
+		_rt2x00_desc_write(txd, 3, skbdesc->iv);
+		_rt2x00_desc_write(txd, 4, skbdesc->eiv);
+	}
+
 	rt2x00_desc_read(txd, 5, &word);
 	rt2x00_set_field32(&word, TXD_W5_PID_TYPE, skbdesc->entry->queue->qid);
 	rt2x00_set_field32(&word, TXD_W5_PID_SUBTYPE,
@@ -1595,11 +1822,15 @@
 	rt2x00_set_field32(&word, TXD_W0_IFS, txdesc->ifs);
 	rt2x00_set_field32(&word, TXD_W0_RETRY_MODE,
 			   test_bit(ENTRY_TXD_RETRY_MODE, &txdesc->flags));
-	rt2x00_set_field32(&word, TXD_W0_TKIP_MIC, 0);
+	rt2x00_set_field32(&word, TXD_W0_TKIP_MIC,
+			   test_bit(ENTRY_TXD_ENCRYPT_MMIC, &txdesc->flags));
+	rt2x00_set_field32(&word, TXD_W0_KEY_TABLE,
+			   test_bit(ENTRY_TXD_ENCRYPT_PAIRWISE, &txdesc->flags));
+	rt2x00_set_field32(&word, TXD_W0_KEY_INDEX, txdesc->key_idx);
 	rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, skb->len);
 	rt2x00_set_field32(&word, TXD_W0_BURST,
 			   test_bit(ENTRY_TXD_BURST, &txdesc->flags));
-	rt2x00_set_field32(&word, TXD_W0_CIPHER_ALG, CIPHER_NONE);
+	rt2x00_set_field32(&word, TXD_W0_CIPHER_ALG, txdesc->cipher);
 	rt2x00_desc_write(txd, 0, word);
 }
 
@@ -1676,40 +1907,27 @@
  */
 static int rt61pci_agc_to_rssi(struct rt2x00_dev *rt2x00dev, int rxd_w1)
 {
-	u16 eeprom;
-	u8 offset;
+	u8 offset = rt2x00dev->lna_gain;
 	u8 lna;
 
 	lna = rt2x00_get_field32(rxd_w1, RXD_W1_RSSI_LNA);
 	switch (lna) {
 	case 3:
-		offset = 90;
+		offset += 90;
 		break;
 	case 2:
-		offset = 74;
+		offset += 74;
 		break;
 	case 1:
-		offset = 64;
+		offset += 64;
 		break;
 	default:
 		return 0;
 	}
 
 	if (rt2x00dev->rx_status.band == IEEE80211_BAND_5GHZ) {
-		if (test_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags))
-			offset += 14;
-
 		if (lna == 3 || lna == 2)
 			offset += 10;
-
-		rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_A, &eeprom);
-		offset -= rt2x00_get_field16(eeprom, EEPROM_RSSI_OFFSET_A_1);
-	} else {
-		if (test_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags))
-			offset += 14;
-
-		rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_BG, &eeprom);
-		offset -= rt2x00_get_field16(eeprom, EEPROM_RSSI_OFFSET_BG_1);
 	}
 
 	return rt2x00_get_field32(rxd_w1, RXD_W1_RSSI_AGC) * 2 - offset;
@@ -1718,6 +1936,7 @@
 static void rt61pci_fill_rxdone(struct queue_entry *entry,
 			        struct rxdone_entry_desc *rxdesc)
 {
+	struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
 	struct queue_entry_priv_pci *entry_priv = entry->priv_data;
 	u32 word0;
 	u32 word1;
@@ -1728,6 +1947,38 @@
 	if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR))
 		rxdesc->flags |= RX_FLAG_FAILED_FCS_CRC;
 
+	if (test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags)) {
+		rxdesc->cipher =
+		    rt2x00_get_field32(word0, RXD_W0_CIPHER_ALG);
+		rxdesc->cipher_status =
+		    rt2x00_get_field32(word0, RXD_W0_CIPHER_ERROR);
+	}
+
+	if (rxdesc->cipher != CIPHER_NONE) {
+		_rt2x00_desc_read(entry_priv->desc, 2, &rxdesc->iv);
+		_rt2x00_desc_read(entry_priv->desc, 3, &rxdesc->eiv);
+		_rt2x00_desc_read(entry_priv->desc, 4, &rxdesc->icv);
+
+		/*
+		 * Hardware has stripped IV/EIV data from 802.11 frame during
+		 * decryption. It has provided the data seperately but rt2x00lib
+		 * should decide if it should be reinserted.
+		 */
+		rxdesc->flags |= RX_FLAG_IV_STRIPPED;
+
+		/*
+		 * FIXME: Legacy driver indicates that the frame does
+		 * contain the Michael Mic. Unfortunately, in rt2x00
+		 * the MIC seems to be missing completely...
+		 */
+		rxdesc->flags |= RX_FLAG_MMIC_STRIPPED;
+
+		if (rxdesc->cipher_status == RX_CRYPTO_SUCCESS)
+			rxdesc->flags |= RX_FLAG_DECRYPTED;
+		else if (rxdesc->cipher_status == RX_CRYPTO_FAIL_MIC)
+			rxdesc->flags |= RX_FLAG_MMIC_ERROR;
+	}
+
 	/*
 	 * Obtain the status about this packet.
 	 * When frame was received with an OFDM bitrate,
@@ -1735,11 +1986,13 @@
 	 * a CCK bitrate the signal is the rate in 100kbit/s.
 	 */
 	rxdesc->signal = rt2x00_get_field32(word1, RXD_W1_SIGNAL);
-	rxdesc->rssi = rt61pci_agc_to_rssi(entry->queue->rt2x00dev, word1);
+	rxdesc->rssi = rt61pci_agc_to_rssi(rt2x00dev, word1);
 	rxdesc->size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT);
 
 	if (rt2x00_get_field32(word0, RXD_W0_OFDM))
 		rxdesc->dev_flags |= RXDONE_SIGNAL_PLCP;
+	else
+		rxdesc->dev_flags |= RXDONE_SIGNAL_BITRATE;
 	if (rt2x00_get_field32(word0, RXD_W0_MY_BSS))
 		rxdesc->dev_flags |= RXDONE_MY_BSS;
 }
@@ -1860,7 +2113,7 @@
 	if (!reg && !reg_mcu)
 		return IRQ_NONE;
 
-	if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags))
+	if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
 		return IRQ_HANDLED;
 
 	/*
@@ -2060,10 +2313,10 @@
 	/*
 	 * Detect if this device has an hardware controlled radio.
 	 */
-#ifdef CONFIG_RT61PCI_RFKILL
+#ifdef CONFIG_RT2X00_LIB_RFKILL
 	if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_HARDWARE_RADIO))
 		__set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags);
-#endif /* CONFIG_RT61PCI_RFKILL */
+#endif /* CONFIG_RT2X00_LIB_RFKILL */
 
 	/*
 	 * Read frequency offset and RF programming sequence.
@@ -2121,7 +2374,7 @@
 	 * If the eeprom value is invalid,
 	 * switch to default led mode.
 	 */
-#ifdef CONFIG_RT61PCI_LEDS
+#ifdef CONFIG_RT2X00_LIB_LEDS
 	rt2x00_eeprom_read(rt2x00dev, EEPROM_LED, &eeprom);
 	value = rt2x00_get_field16(eeprom, EEPROM_LED_LED_MODE);
 
@@ -2155,7 +2408,7 @@
 	rt2x00_set_field16(&rt2x00dev->led_mcu_reg, MCU_LEDCS_POLARITY_READY_A,
 			   rt2x00_get_field16(eeprom,
 					      EEPROM_LED_POLARITY_RDY_A));
-#endif /* CONFIG_RT61PCI_LEDS */
+#endif /* CONFIG_RT2X00_LIB_LEDS */
 
 	return 0;
 }
@@ -2274,10 +2527,11 @@
 	{ 46, 0x00002ccc, 0x000049a6, 0x0009be55, 0x000c0a23 },
 };
 
-static void rt61pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
+static int rt61pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
 {
 	struct hw_mode_spec *spec = &rt2x00dev->spec;
-	u8 *txpower;
+	struct channel_info *info;
+	char *tx_power;
 	unsigned int i;
 
 	/*
@@ -2294,20 +2548,10 @@
 						   EEPROM_MAC_ADDR_0));
 
 	/*
-	 * Convert tx_power array in eeprom.
-	 */
-	txpower = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_G_START);
-	for (i = 0; i < 14; i++)
-		txpower[i] = TXPOWER_FROM_DEV(txpower[i]);
-
-	/*
 	 * Initialize hw_mode information.
 	 */
 	spec->supported_bands = SUPPORT_BAND_2GHZ;
 	spec->supported_rates = SUPPORT_RATE_CCK | SUPPORT_RATE_OFDM;
-	spec->tx_power_a = NULL;
-	spec->tx_power_bg = txpower;
-	spec->tx_power_default = DEFAULT_TXPOWER;
 
 	if (!test_bit(CONFIG_RF_SEQUENCE, &rt2x00dev->flags)) {
 		spec->num_channels = 14;
@@ -2321,13 +2565,28 @@
 	    rt2x00_rf(&rt2x00dev->chip, RF5325)) {
 		spec->supported_bands |= SUPPORT_BAND_5GHZ;
 		spec->num_channels = ARRAY_SIZE(rf_vals_seq);
-
-		txpower = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_A_START);
-		for (i = 0; i < 14; i++)
-			txpower[i] = TXPOWER_FROM_DEV(txpower[i]);
-
-		spec->tx_power_a = txpower;
 	}
+
+	/*
+	 * Create channel information array
+	 */
+	info = kzalloc(spec->num_channels * sizeof(*info), GFP_KERNEL);
+	if (!info)
+		return -ENOMEM;
+
+	spec->channels_info = info;
+
+	tx_power = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_G_START);
+	for (i = 0; i < 14; i++)
+		info[i].tx_power1 = TXPOWER_FROM_DEV(tx_power[i]);
+
+	if (spec->num_channels > 14) {
+		tx_power = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_A_START);
+		for (i = 14; i < spec->num_channels; i++)
+			info[i].tx_power1 = TXPOWER_FROM_DEV(tx_power[i]);
+	}
+
+	return 0;
 }
 
 static int rt61pci_probe_hw(struct rt2x00_dev *rt2x00dev)
@@ -2348,13 +2607,17 @@
 	/*
 	 * Initialize hw specifications.
 	 */
-	rt61pci_probe_hw_mode(rt2x00dev);
+	retval = rt61pci_probe_hw_mode(rt2x00dev);
+	if (retval)
+		return retval;
 
 	/*
 	 * This device requires firmware and DMA mapped skbs.
 	 */
 	__set_bit(DRIVER_REQUIRE_FIRMWARE, &rt2x00dev->flags);
 	__set_bit(DRIVER_REQUIRE_DMA, &rt2x00dev->flags);
+	if (!modparam_nohwcrypt)
+		__set_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags);
 
 	/*
 	 * Set the rssi offset.
@@ -2381,6 +2644,63 @@
 	return 0;
 }
 
+static int rt61pci_conf_tx(struct ieee80211_hw *hw, u16 queue_idx,
+			   const struct ieee80211_tx_queue_params *params)
+{
+	struct rt2x00_dev *rt2x00dev = hw->priv;
+	struct data_queue *queue;
+	struct rt2x00_field32 field;
+	int retval;
+	u32 reg;
+
+	/*
+	 * First pass the configuration through rt2x00lib, that will
+	 * update the queue settings and validate the input. After that
+	 * we are free to update the registers based on the value
+	 * in the queue parameter.
+	 */
+	retval = rt2x00mac_conf_tx(hw, queue_idx, params);
+	if (retval)
+		return retval;
+
+	queue = rt2x00queue_get_queue(rt2x00dev, queue_idx);
+
+	/* Update WMM TXOP register */
+	if (queue_idx < 2) {
+		field.bit_offset = queue_idx * 16;
+		field.bit_mask = 0xffff << field.bit_offset;
+
+		rt2x00pci_register_read(rt2x00dev, AC_TXOP_CSR0, &reg);
+		rt2x00_set_field32(&reg, field, queue->txop);
+		rt2x00pci_register_write(rt2x00dev, AC_TXOP_CSR0, reg);
+	} else if (queue_idx < 4) {
+		field.bit_offset = (queue_idx - 2) * 16;
+		field.bit_mask = 0xffff << field.bit_offset;
+
+		rt2x00pci_register_read(rt2x00dev, AC_TXOP_CSR1, &reg);
+		rt2x00_set_field32(&reg, field, queue->txop);
+		rt2x00pci_register_write(rt2x00dev, AC_TXOP_CSR1, reg);
+	}
+
+	/* Update WMM registers */
+	field.bit_offset = queue_idx * 4;
+	field.bit_mask = 0xf << field.bit_offset;
+
+	rt2x00pci_register_read(rt2x00dev, AIFSN_CSR, &reg);
+	rt2x00_set_field32(&reg, field, queue->aifs);
+	rt2x00pci_register_write(rt2x00dev, AIFSN_CSR, reg);
+
+	rt2x00pci_register_read(rt2x00dev, CWMIN_CSR, &reg);
+	rt2x00_set_field32(&reg, field, queue->cw_min);
+	rt2x00pci_register_write(rt2x00dev, CWMIN_CSR, reg);
+
+	rt2x00pci_register_read(rt2x00dev, CWMAX_CSR, &reg);
+	rt2x00_set_field32(&reg, field, queue->cw_max);
+	rt2x00pci_register_write(rt2x00dev, CWMAX_CSR, reg);
+
+	return 0;
+}
+
 static u64 rt61pci_get_tsf(struct ieee80211_hw *hw)
 {
 	struct rt2x00_dev *rt2x00dev = hw->priv;
@@ -2404,10 +2724,11 @@
 	.config			= rt2x00mac_config,
 	.config_interface	= rt2x00mac_config_interface,
 	.configure_filter	= rt2x00mac_configure_filter,
+	.set_key		= rt2x00mac_set_key,
 	.get_stats		= rt2x00mac_get_stats,
 	.set_retry_limit	= rt61pci_set_retry_limit,
 	.bss_info_changed	= rt2x00mac_bss_info_changed,
-	.conf_tx		= rt2x00mac_conf_tx,
+	.conf_tx		= rt61pci_conf_tx,
 	.get_tx_stats		= rt2x00mac_get_tx_stats,
 	.get_tsf		= rt61pci_get_tsf,
 };
@@ -2432,6 +2753,8 @@
 	.write_beacon		= rt61pci_write_beacon,
 	.kick_tx_queue		= rt61pci_kick_tx_queue,
 	.fill_rxdone		= rt61pci_fill_rxdone,
+	.config_shared_key	= rt61pci_config_shared_key,
+	.config_pairwise_key	= rt61pci_config_pairwise_key,
 	.config_filter		= rt61pci_config_filter,
 	.config_intf		= rt61pci_config_intf,
 	.config_erp		= rt61pci_config_erp,
diff --git a/drivers/net/wireless/rt2x00/rt61pci.h b/drivers/net/wireless/rt2x00/rt61pci.h
index 1004d5b899..8ec1451 100644
--- a/drivers/net/wireless/rt2x00/rt61pci.h
+++ b/drivers/net/wireless/rt2x00/rt61pci.h
@@ -134,6 +134,16 @@
 #define PAIRWISE_KEY_TABLE_BASE		0x1200
 #define PAIRWISE_TA_TABLE_BASE		0x1a00
 
+#define SHARED_KEY_ENTRY(__idx) \
+	( SHARED_KEY_TABLE_BASE + \
+		((__idx) * sizeof(struct hw_key_entry)) )
+#define PAIRWISE_KEY_ENTRY(__idx) \
+	( PAIRWISE_KEY_TABLE_BASE + \
+		((__idx) * sizeof(struct hw_key_entry)) )
+#define PAIRWISE_TA_ENTRY(__idx) \
+	( PAIRWISE_TA_TABLE_BASE + \
+		((__idx) * sizeof(struct hw_pairwise_ta_entry)) )
+
 struct hw_key_entry {
 	u8 key[16];
 	u8 tx_mic[8];
@@ -142,7 +152,8 @@
 
 struct hw_pairwise_ta_entry {
 	u8 address[6];
-	u8 reserved[2];
+	u8 cipher;
+	u8 reserved;
 } __attribute__ ((packed));
 
 /*
@@ -662,6 +673,10 @@
  * SEC_CSR4: Pairwise key table lookup control.
  */
 #define SEC_CSR4			0x30b0
+#define SEC_CSR4_ENABLE_BSS0		FIELD32(0x00000001)
+#define SEC_CSR4_ENABLE_BSS1		FIELD32(0x00000002)
+#define SEC_CSR4_ENABLE_BSS2		FIELD32(0x00000004)
+#define SEC_CSR4_ENABLE_BSS3		FIELD32(0x00000008)
 
 /*
  * SEC_CSR5: shared key table security mode register.
@@ -1428,8 +1443,10 @@
 
 /*
  * Word4
+ * ICV: Received ICV of originally encrypted.
+ * NOTE: This is a guess, the official definition is "reserved"
  */
-#define RXD_W4_RESERVED			FIELD32(0xffffffff)
+#define RXD_W4_ICV			FIELD32(0xffffffff)
 
 /*
  * the above 20-byte is called RXINFO and will be DMAed to MAC RX block
@@ -1465,17 +1482,10 @@
 #define MAX_TXPOWER	31
 #define DEFAULT_TXPOWER	24
 
-#define TXPOWER_FROM_DEV(__txpower)		\
-({						\
-	((__txpower) > MAX_TXPOWER) ?		\
-		DEFAULT_TXPOWER : (__txpower);	\
-})
+#define TXPOWER_FROM_DEV(__txpower) \
+	(((u8)(__txpower)) > MAX_TXPOWER) ? DEFAULT_TXPOWER : (__txpower)
 
-#define TXPOWER_TO_DEV(__txpower)			\
-({							\
-	((__txpower) <= MIN_TXPOWER) ? MIN_TXPOWER :	\
-	(((__txpower) >= MAX_TXPOWER) ? MAX_TXPOWER :	\
-	(__txpower));					\
-})
+#define TXPOWER_TO_DEV(__txpower) \
+	clamp_t(char, __txpower, MIN_TXPOWER, MAX_TXPOWER)
 
 #endif /* RT61PCI_H */
diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c
index 9761eaa..934f8e03 100644
--- a/drivers/net/wireless/rt2x00/rt73usb.c
+++ b/drivers/net/wireless/rt2x00/rt73usb.c
@@ -37,6 +37,13 @@
 #include "rt73usb.h"
 
 /*
+ * Allow hardware encryption to be disabled.
+ */
+static int modparam_nohwcrypt = 0;
+module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO);
+MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption.");
+
+/*
  * Register access.
  * All access to the CSR registers will go through the methods
  * rt73usb_register_read and rt73usb_register_write.
@@ -285,7 +292,7 @@
 };
 #endif /* CONFIG_RT2X00_LIB_DEBUGFS */
 
-#ifdef CONFIG_RT73USB_LEDS
+#ifdef CONFIG_RT2X00_LIB_LEDS
 static void rt73usb_brightness_set(struct led_classdev *led_cdev,
 				   enum led_brightness brightness)
 {
@@ -352,11 +359,224 @@
 	led->led_dev.blink_set = rt73usb_blink_set;
 	led->flags = LED_INITIALIZED;
 }
-#endif /* CONFIG_RT73USB_LEDS */
+#endif /* CONFIG_RT2X00_LIB_LEDS */
 
 /*
  * Configuration handlers.
  */
+static int rt73usb_config_shared_key(struct rt2x00_dev *rt2x00dev,
+				     struct rt2x00lib_crypto *crypto,
+				     struct ieee80211_key_conf *key)
+{
+	struct hw_key_entry key_entry;
+	struct rt2x00_field32 field;
+	int timeout;
+	u32 mask;
+	u32 reg;
+
+	if (crypto->cmd == SET_KEY) {
+		/*
+		 * rt2x00lib can't determine the correct free
+		 * key_idx for shared keys. We have 1 register
+		 * with key valid bits. The goal is simple, read
+		 * the register, if that is full we have no slots
+		 * left.
+		 * Note that each BSS is allowed to have up to 4
+		 * shared keys, so put a mask over the allowed
+		 * entries.
+		 */
+		mask = (0xf << crypto->bssidx);
+
+		rt73usb_register_read(rt2x00dev, SEC_CSR0, &reg);
+		reg &= mask;
+
+		if (reg && reg == mask)
+			return -ENOSPC;
+
+		key->hw_key_idx += reg ? ffz(reg) : 0;
+
+		/*
+		 * Upload key to hardware
+		 */
+		memcpy(key_entry.key, crypto->key,
+		       sizeof(key_entry.key));
+		memcpy(key_entry.tx_mic, crypto->tx_mic,
+		       sizeof(key_entry.tx_mic));
+		memcpy(key_entry.rx_mic, crypto->rx_mic,
+		       sizeof(key_entry.rx_mic));
+
+		reg = SHARED_KEY_ENTRY(key->hw_key_idx);
+		timeout = REGISTER_TIMEOUT32(sizeof(key_entry));
+		rt2x00usb_vendor_request_large_buff(rt2x00dev, USB_MULTI_WRITE,
+						    USB_VENDOR_REQUEST_OUT, reg,
+						    &key_entry,
+						    sizeof(key_entry),
+						    timeout);
+
+		/*
+		 * The cipher types are stored over 2 registers.
+		 * bssidx 0 and 1 keys are stored in SEC_CSR1 and
+		 * bssidx 1 and 2 keys are stored in SEC_CSR5.
+		 * Using the correct defines correctly will cause overhead,
+		 * so just calculate the correct offset.
+		 */
+		if (key->hw_key_idx < 8) {
+			field.bit_offset = (3 * key->hw_key_idx);
+			field.bit_mask = 0x7 << field.bit_offset;
+
+			rt73usb_register_read(rt2x00dev, SEC_CSR1, &reg);
+			rt2x00_set_field32(&reg, field, crypto->cipher);
+			rt73usb_register_write(rt2x00dev, SEC_CSR1, reg);
+		} else {
+			field.bit_offset = (3 * (key->hw_key_idx - 8));
+			field.bit_mask = 0x7 << field.bit_offset;
+
+			rt73usb_register_read(rt2x00dev, SEC_CSR5, &reg);
+			rt2x00_set_field32(&reg, field, crypto->cipher);
+			rt73usb_register_write(rt2x00dev, SEC_CSR5, reg);
+		}
+
+		/*
+		 * The driver does not support the IV/EIV generation
+		 * in hardware. However it doesn't support the IV/EIV
+		 * inside the ieee80211 frame either, but requires it
+		 * to be provided seperately for the descriptor.
+		 * rt2x00lib will cut the IV/EIV data out of all frames
+		 * given to us by mac80211, but we must tell mac80211
+		 * to generate the IV/EIV data.
+		 */
+		key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
+	}
+
+	/*
+	 * SEC_CSR0 contains only single-bit fields to indicate
+	 * a particular key is valid. Because using the FIELD32()
+	 * defines directly will cause a lot of overhead we use
+	 * a calculation to determine the correct bit directly.
+	 */
+	mask = 1 << key->hw_key_idx;
+
+	rt73usb_register_read(rt2x00dev, SEC_CSR0, &reg);
+	if (crypto->cmd == SET_KEY)
+		reg |= mask;
+	else if (crypto->cmd == DISABLE_KEY)
+		reg &= ~mask;
+	rt73usb_register_write(rt2x00dev, SEC_CSR0, reg);
+
+	return 0;
+}
+
+static int rt73usb_config_pairwise_key(struct rt2x00_dev *rt2x00dev,
+				       struct rt2x00lib_crypto *crypto,
+				       struct ieee80211_key_conf *key)
+{
+	struct hw_pairwise_ta_entry addr_entry;
+	struct hw_key_entry key_entry;
+	int timeout;
+	u32 mask;
+	u32 reg;
+
+	if (crypto->cmd == SET_KEY) {
+		/*
+		 * rt2x00lib can't determine the correct free
+		 * key_idx for pairwise keys. We have 2 registers
+		 * with key valid bits. The goal is simple, read
+		 * the first register, if that is full move to
+		 * the next register.
+		 * When both registers are full, we drop the key,
+		 * otherwise we use the first invalid entry.
+		 */
+		rt73usb_register_read(rt2x00dev, SEC_CSR2, &reg);
+		if (reg && reg == ~0) {
+			key->hw_key_idx = 32;
+			rt73usb_register_read(rt2x00dev, SEC_CSR3, &reg);
+			if (reg && reg == ~0)
+				return -ENOSPC;
+		}
+
+		key->hw_key_idx += reg ? ffz(reg) : 0;
+
+		/*
+		 * Upload key to hardware
+		 */
+		memcpy(key_entry.key, crypto->key,
+		       sizeof(key_entry.key));
+		memcpy(key_entry.tx_mic, crypto->tx_mic,
+		       sizeof(key_entry.tx_mic));
+		memcpy(key_entry.rx_mic, crypto->rx_mic,
+		       sizeof(key_entry.rx_mic));
+
+		reg = PAIRWISE_KEY_ENTRY(key->hw_key_idx);
+		timeout = REGISTER_TIMEOUT32(sizeof(key_entry));
+		rt2x00usb_vendor_request_large_buff(rt2x00dev, USB_MULTI_WRITE,
+						    USB_VENDOR_REQUEST_OUT, reg,
+						    &key_entry,
+						    sizeof(key_entry),
+						    timeout);
+
+		/*
+		 * Send the address and cipher type to the hardware register.
+		 * This data fits within the CSR cache size, so we can use
+		 * rt73usb_register_multiwrite() directly.
+		 */
+		memset(&addr_entry, 0, sizeof(addr_entry));
+		memcpy(&addr_entry, crypto->address, ETH_ALEN);
+		addr_entry.cipher = crypto->cipher;
+
+		reg = PAIRWISE_TA_ENTRY(key->hw_key_idx);
+		rt73usb_register_multiwrite(rt2x00dev, reg,
+					    &addr_entry, sizeof(addr_entry));
+
+		/*
+		 * Enable pairwise lookup table for given BSS idx,
+		 * without this received frames will not be decrypted
+		 * by the hardware.
+		 */
+		rt73usb_register_read(rt2x00dev, SEC_CSR4, &reg);
+		reg |= (1 << crypto->bssidx);
+		rt73usb_register_write(rt2x00dev, SEC_CSR4, reg);
+
+		/*
+		 * The driver does not support the IV/EIV generation
+		 * in hardware. However it doesn't support the IV/EIV
+		 * inside the ieee80211 frame either, but requires it
+		 * to be provided seperately for the descriptor.
+		 * rt2x00lib will cut the IV/EIV data out of all frames
+		 * given to us by mac80211, but we must tell mac80211
+		 * to generate the IV/EIV data.
+		 */
+		key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
+	}
+
+	/*
+	 * SEC_CSR2 and SEC_CSR3 contain only single-bit fields to indicate
+	 * a particular key is valid. Because using the FIELD32()
+	 * defines directly will cause a lot of overhead we use
+	 * a calculation to determine the correct bit directly.
+	 */
+	if (key->hw_key_idx < 32) {
+		mask = 1 << key->hw_key_idx;
+
+		rt73usb_register_read(rt2x00dev, SEC_CSR2, &reg);
+		if (crypto->cmd == SET_KEY)
+			reg |= mask;
+		else if (crypto->cmd == DISABLE_KEY)
+			reg &= ~mask;
+		rt73usb_register_write(rt2x00dev, SEC_CSR2, reg);
+	} else {
+		mask = 1 << (key->hw_key_idx - 32);
+
+		rt73usb_register_read(rt2x00dev, SEC_CSR3, &reg);
+		if (crypto->cmd == SET_KEY)
+			reg |= mask;
+		else if (crypto->cmd == DISABLE_KEY)
+			reg &= ~mask;
+		rt73usb_register_write(rt2x00dev, SEC_CSR3, reg);
+	}
+
+	return 0;
+}
+
 static void rt73usb_config_filter(struct rt2x00_dev *rt2x00dev,
 				  const unsigned int filter_flags)
 {
@@ -451,6 +671,26 @@
 	rt73usb_register_write(rt2x00dev, TXRX_CSR4, reg);
 }
 
+static void rt73usb_config_lna_gain(struct rt2x00_dev *rt2x00dev,
+				    struct rt2x00lib_conf *libconf)
+{
+	u16 eeprom;
+	short lna_gain = 0;
+
+	if (libconf->band == IEEE80211_BAND_2GHZ) {
+		if (test_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags))
+			lna_gain += 14;
+
+		rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_BG, &eeprom);
+		lna_gain -= rt2x00_get_field16(eeprom, EEPROM_RSSI_OFFSET_BG_1);
+	} else {
+		rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_A, &eeprom);
+		lna_gain -= rt2x00_get_field16(eeprom, EEPROM_RSSI_OFFSET_A_1);
+	}
+
+	rt2x00dev->lna_gain = lna_gain;
+}
+
 static void rt73usb_config_phymode(struct rt2x00_dev *rt2x00dev,
 				   const int basic_rate_mask)
 {
@@ -705,6 +945,9 @@
 			   struct rt2x00lib_conf *libconf,
 			   const unsigned int flags)
 {
+	/* Always recalculate LNA gain before changing configuration */
+	rt73usb_config_lna_gain(rt2x00dev, libconf);
+
 	if (flags & CONFIG_UPDATE_PHYMODE)
 		rt73usb_config_phymode(rt2x00dev, libconf->basic_rates);
 	if (flags & CONFIG_UPDATE_CHANNEL)
@@ -1034,16 +1277,6 @@
 	rt73usb_register_write(rt2x00dev, PHY_CSR6, 0x00080606);
 	rt73usb_register_write(rt2x00dev, PHY_CSR7, 0x00000408);
 
-	rt73usb_register_read(rt2x00dev, AC_TXOP_CSR0, &reg);
-	rt2x00_set_field32(&reg, AC_TXOP_CSR0_AC0_TX_OP, 0);
-	rt2x00_set_field32(&reg, AC_TXOP_CSR0_AC1_TX_OP, 0);
-	rt73usb_register_write(rt2x00dev, AC_TXOP_CSR0, reg);
-
-	rt73usb_register_read(rt2x00dev, AC_TXOP_CSR1, &reg);
-	rt2x00_set_field32(&reg, AC_TXOP_CSR1_AC2_TX_OP, 192);
-	rt2x00_set_field32(&reg, AC_TXOP_CSR1_AC3_TX_OP, 48);
-	rt73usb_register_write(rt2x00dev, AC_TXOP_CSR1, reg);
-
 	rt73usb_register_read(rt2x00dev, MAC_CSR9, &reg);
 	rt2x00_set_field32(&reg, MAC_CSR9_CW_SELECT, 0);
 	rt73usb_register_write(rt2x00dev, MAC_CSR9, reg);
@@ -1265,8 +1498,8 @@
  * TX descriptor initialization
  */
 static void rt73usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
-				    struct sk_buff *skb,
-				    struct txentry_desc *txdesc)
+				  struct sk_buff *skb,
+				  struct txentry_desc *txdesc)
 {
 	struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
 	__le32 *txd = skbdesc->desc;
@@ -1280,7 +1513,7 @@
 	rt2x00_set_field32(&word, TXD_W1_AIFSN, txdesc->aifs);
 	rt2x00_set_field32(&word, TXD_W1_CWMIN, txdesc->cw_min);
 	rt2x00_set_field32(&word, TXD_W1_CWMAX, txdesc->cw_max);
-	rt2x00_set_field32(&word, TXD_W1_IV_OFFSET, IEEE80211_HEADER);
+	rt2x00_set_field32(&word, TXD_W1_IV_OFFSET, txdesc->iv_offset);
 	rt2x00_set_field32(&word, TXD_W1_HW_SEQUENCE,
 			   test_bit(ENTRY_TXD_GENERATE_SEQ, &txdesc->flags));
 	rt2x00_desc_write(txd, 1, word);
@@ -1292,6 +1525,11 @@
 	rt2x00_set_field32(&word, TXD_W2_PLCP_LENGTH_HIGH, txdesc->length_high);
 	rt2x00_desc_write(txd, 2, word);
 
+	if (test_bit(ENTRY_TXD_ENCRYPT, &txdesc->flags)) {
+		_rt2x00_desc_write(txd, 3, skbdesc->iv);
+		_rt2x00_desc_write(txd, 4, skbdesc->eiv);
+	}
+
 	rt2x00_desc_read(txd, 5, &word);
 	rt2x00_set_field32(&word, TXD_W5_TX_POWER,
 			   TXPOWER_TO_DEV(rt2x00dev->tx_power));
@@ -1313,12 +1551,15 @@
 	rt2x00_set_field32(&word, TXD_W0_IFS, txdesc->ifs);
 	rt2x00_set_field32(&word, TXD_W0_RETRY_MODE,
 			   test_bit(ENTRY_TXD_RETRY_MODE, &txdesc->flags));
-	rt2x00_set_field32(&word, TXD_W0_TKIP_MIC, 0);
-	rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT,
-			   skb->len - skbdesc->desc_len);
+	rt2x00_set_field32(&word, TXD_W0_TKIP_MIC,
+			   test_bit(ENTRY_TXD_ENCRYPT_MMIC, &txdesc->flags));
+	rt2x00_set_field32(&word, TXD_W0_KEY_TABLE,
+			   test_bit(ENTRY_TXD_ENCRYPT_PAIRWISE, &txdesc->flags));
+	rt2x00_set_field32(&word, TXD_W0_KEY_INDEX, txdesc->key_idx);
+	rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, skb->len);
 	rt2x00_set_field32(&word, TXD_W0_BURST2,
 			   test_bit(ENTRY_TXD_BURST, &txdesc->flags));
-	rt2x00_set_field32(&word, TXD_W0_CIPHER_ALG, CIPHER_NONE);
+	rt2x00_set_field32(&word, TXD_W0_CIPHER_ALG, txdesc->cipher);
 	rt2x00_desc_write(txd, 0, word);
 }
 
@@ -1331,7 +1572,6 @@
 	struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
 	unsigned int beacon_base;
 	u32 reg;
-	u32 word, len;
 
 	/*
 	 * Add the descriptor in front of the skb.
@@ -1341,17 +1581,6 @@
 	skbdesc->desc = entry->skb->data;
 
 	/*
-	 * Adjust the beacon databyte count. The current number is
-	 * calculated before this function gets called, but falsely
-	 * assumes that the descriptor was already present in the SKB.
-	 */
-	rt2x00_desc_read(skbdesc->desc, 0, &word);
-	len  = rt2x00_get_field32(word, TXD_W0_DATABYTE_COUNT);
-	len += skbdesc->desc_len;
-	rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, len);
-	rt2x00_desc_write(skbdesc->desc, 0, word);
-
-	/*
 	 * Disable beaconing while we are reloading the beacon data,
 	 * otherwise we might be sending out invalid data.
 	 */
@@ -1422,20 +1651,19 @@
  */
 static int rt73usb_agc_to_rssi(struct rt2x00_dev *rt2x00dev, int rxd_w1)
 {
-	u16 eeprom;
-	u8 offset;
+	u8 offset = rt2x00dev->lna_gain;
 	u8 lna;
 
 	lna = rt2x00_get_field32(rxd_w1, RXD_W1_RSSI_LNA);
 	switch (lna) {
 	case 3:
-		offset = 90;
+		offset += 90;
 		break;
 	case 2:
-		offset = 74;
+		offset += 74;
 		break;
 	case 1:
-		offset = 64;
+		offset += 64;
 		break;
 	default:
 		return 0;
@@ -1451,15 +1679,6 @@
 			else if (lna == 2)
 				offset += 8;
 		}
-
-		rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_A, &eeprom);
-		offset -= rt2x00_get_field16(eeprom, EEPROM_RSSI_OFFSET_A_1);
-	} else {
-		if (test_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags))
-			offset += 14;
-
-		rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_BG, &eeprom);
-		offset -= rt2x00_get_field16(eeprom, EEPROM_RSSI_OFFSET_BG_1);
 	}
 
 	return rt2x00_get_field32(rxd_w1, RXD_W1_RSSI_AGC) * 2 - offset;
@@ -1468,6 +1687,7 @@
 static void rt73usb_fill_rxdone(struct queue_entry *entry,
 			        struct rxdone_entry_desc *rxdesc)
 {
+	struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
 	struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
 	__le32 *rxd = (__le32 *)entry->skb->data;
 	u32 word0;
@@ -1489,6 +1709,38 @@
 	if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR))
 		rxdesc->flags |= RX_FLAG_FAILED_FCS_CRC;
 
+	if (test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags)) {
+		rxdesc->cipher =
+		    rt2x00_get_field32(word0, RXD_W0_CIPHER_ALG);
+		rxdesc->cipher_status =
+		    rt2x00_get_field32(word0, RXD_W0_CIPHER_ERROR);
+	}
+
+	if (rxdesc->cipher != CIPHER_NONE) {
+		_rt2x00_desc_read(rxd, 2, &rxdesc->iv);
+		_rt2x00_desc_read(rxd, 3, &rxdesc->eiv);
+		_rt2x00_desc_read(rxd, 4, &rxdesc->icv);
+
+		/*
+		 * Hardware has stripped IV/EIV data from 802.11 frame during
+		 * decryption. It has provided the data seperately but rt2x00lib
+		 * should decide if it should be reinserted.
+		 */
+		rxdesc->flags |= RX_FLAG_IV_STRIPPED;
+
+		/*
+		 * FIXME: Legacy driver indicates that the frame does
+		 * contain the Michael Mic. Unfortunately, in rt2x00
+		 * the MIC seems to be missing completely...
+		 */
+		rxdesc->flags |= RX_FLAG_MMIC_STRIPPED;
+
+		if (rxdesc->cipher_status == RX_CRYPTO_SUCCESS)
+			rxdesc->flags |= RX_FLAG_DECRYPTED;
+		else if (rxdesc->cipher_status == RX_CRYPTO_FAIL_MIC)
+			rxdesc->flags |= RX_FLAG_MMIC_ERROR;
+	}
+
 	/*
 	 * Obtain the status about this packet.
 	 * When frame was received with an OFDM bitrate,
@@ -1496,11 +1748,13 @@
 	 * a CCK bitrate the signal is the rate in 100kbit/s.
 	 */
 	rxdesc->signal = rt2x00_get_field32(word1, RXD_W1_SIGNAL);
-	rxdesc->rssi = rt73usb_agc_to_rssi(entry->queue->rt2x00dev, word1);
+	rxdesc->rssi = rt73usb_agc_to_rssi(rt2x00dev, word1);
 	rxdesc->size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT);
 
 	if (rt2x00_get_field32(word0, RXD_W0_OFDM))
 		rxdesc->dev_flags |= RXDONE_SIGNAL_PLCP;
+	else
+		rxdesc->dev_flags |= RXDONE_SIGNAL_BITRATE;
 	if (rt2x00_get_field32(word0, RXD_W0_MY_BSS))
 		rxdesc->dev_flags |= RXDONE_MY_BSS;
 
@@ -1678,7 +1932,7 @@
 	/*
 	 * Store led settings, for correct led behaviour.
 	 */
-#ifdef CONFIG_RT73USB_LEDS
+#ifdef CONFIG_RT2X00_LIB_LEDS
 	rt2x00_eeprom_read(rt2x00dev, EEPROM_LED, &eeprom);
 
 	rt73usb_init_led(rt2x00dev, &rt2x00dev->led_radio, LED_TYPE_RADIO);
@@ -1711,7 +1965,7 @@
 	rt2x00_set_field16(&rt2x00dev->led_mcu_reg, MCU_LEDCS_POLARITY_READY_A,
 			   rt2x00_get_field16(eeprom,
 					      EEPROM_LED_POLARITY_RDY_A));
-#endif /* CONFIG_RT73USB_LEDS */
+#endif /* CONFIG_RT2X00_LIB_LEDS */
 
 	return 0;
 }
@@ -1852,10 +2106,11 @@
 };
 
 
-static void rt73usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
+static int rt73usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
 {
 	struct hw_mode_spec *spec = &rt2x00dev->spec;
-	u8 *txpower;
+	struct channel_info *info;
+	char *tx_power;
 	unsigned int i;
 
 	/*
@@ -1872,20 +2127,10 @@
 						   EEPROM_MAC_ADDR_0));
 
 	/*
-	 * Convert tx_power array in eeprom.
-	 */
-	txpower = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_G_START);
-	for (i = 0; i < 14; i++)
-		txpower[i] = TXPOWER_FROM_DEV(txpower[i]);
-
-	/*
 	 * Initialize hw_mode information.
 	 */
 	spec->supported_bands = SUPPORT_BAND_2GHZ;
 	spec->supported_rates = SUPPORT_RATE_CCK | SUPPORT_RATE_OFDM;
-	spec->tx_power_a = NULL;
-	spec->tx_power_bg = txpower;
-	spec->tx_power_default = DEFAULT_TXPOWER;
 
 	if (rt2x00_rf(&rt2x00dev->chip, RF2528)) {
 		spec->num_channels = ARRAY_SIZE(rf_vals_bg_2528);
@@ -1903,14 +2148,26 @@
 		spec->channels = rf_vals_5225_2527;
 	}
 
-	if (rt2x00_rf(&rt2x00dev->chip, RF5225) ||
-	    rt2x00_rf(&rt2x00dev->chip, RF5226)) {
-		txpower = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_A_START);
-		for (i = 0; i < 14; i++)
-			txpower[i] = TXPOWER_FROM_DEV(txpower[i]);
+	/*
+	 * Create channel information array
+	 */
+	info = kzalloc(spec->num_channels * sizeof(*info), GFP_KERNEL);
+	if (!info)
+		return -ENOMEM;
 
-		spec->tx_power_a = txpower;
+	spec->channels_info = info;
+
+	tx_power = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_G_START);
+	for (i = 0; i < 14; i++)
+		info[i].tx_power1 = TXPOWER_FROM_DEV(tx_power[i]);
+
+	if (spec->num_channels > 14) {
+		tx_power = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_A_START);
+		for (i = 14; i < spec->num_channels; i++)
+			info[i].tx_power1 = TXPOWER_FROM_DEV(tx_power[i]);
 	}
+
+	return 0;
 }
 
 static int rt73usb_probe_hw(struct rt2x00_dev *rt2x00dev)
@@ -1931,13 +2188,17 @@
 	/*
 	 * Initialize hw specifications.
 	 */
-	rt73usb_probe_hw_mode(rt2x00dev);
+	retval = rt73usb_probe_hw_mode(rt2x00dev);
+	if (retval)
+		return retval;
 
 	/*
 	 * This device requires firmware.
 	 */
 	__set_bit(DRIVER_REQUIRE_FIRMWARE, &rt2x00dev->flags);
 	__set_bit(DRIVER_REQUIRE_SCHEDULED, &rt2x00dev->flags);
+	if (!modparam_nohwcrypt)
+		__set_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags);
 
 	/*
 	 * Set the rssi offset.
@@ -1964,6 +2225,63 @@
 	return 0;
 }
 
+static int rt73usb_conf_tx(struct ieee80211_hw *hw, u16 queue_idx,
+			   const struct ieee80211_tx_queue_params *params)
+{
+	struct rt2x00_dev *rt2x00dev = hw->priv;
+	struct data_queue *queue;
+	struct rt2x00_field32 field;
+	int retval;
+	u32 reg;
+
+	/*
+	 * First pass the configuration through rt2x00lib, that will
+	 * update the queue settings and validate the input. After that
+	 * we are free to update the registers based on the value
+	 * in the queue parameter.
+	 */
+	retval = rt2x00mac_conf_tx(hw, queue_idx, params);
+	if (retval)
+		return retval;
+
+	queue = rt2x00queue_get_queue(rt2x00dev, queue_idx);
+
+	/* Update WMM TXOP register */
+	if (queue_idx < 2) {
+		field.bit_offset = queue_idx * 16;
+		field.bit_mask = 0xffff << field.bit_offset;
+
+		rt73usb_register_read(rt2x00dev, AC_TXOP_CSR0, &reg);
+		rt2x00_set_field32(&reg, field, queue->txop);
+		rt73usb_register_write(rt2x00dev, AC_TXOP_CSR0, reg);
+	} else if (queue_idx < 4) {
+		field.bit_offset = (queue_idx - 2) * 16;
+		field.bit_mask = 0xffff << field.bit_offset;
+
+		rt73usb_register_read(rt2x00dev, AC_TXOP_CSR1, &reg);
+		rt2x00_set_field32(&reg, field, queue->txop);
+		rt73usb_register_write(rt2x00dev, AC_TXOP_CSR1, reg);
+	}
+
+	/* Update WMM registers */
+	field.bit_offset = queue_idx * 4;
+	field.bit_mask = 0xf << field.bit_offset;
+
+	rt73usb_register_read(rt2x00dev, AIFSN_CSR, &reg);
+	rt2x00_set_field32(&reg, field, queue->aifs);
+	rt73usb_register_write(rt2x00dev, AIFSN_CSR, reg);
+
+	rt73usb_register_read(rt2x00dev, CWMIN_CSR, &reg);
+	rt2x00_set_field32(&reg, field, queue->cw_min);
+	rt73usb_register_write(rt2x00dev, CWMIN_CSR, reg);
+
+	rt73usb_register_read(rt2x00dev, CWMAX_CSR, &reg);
+	rt2x00_set_field32(&reg, field, queue->cw_max);
+	rt73usb_register_write(rt2x00dev, CWMAX_CSR, reg);
+
+	return 0;
+}
+
 #if 0
 /*
  * Mac80211 demands get_tsf must be atomic.
@@ -1997,10 +2315,11 @@
 	.config			= rt2x00mac_config,
 	.config_interface	= rt2x00mac_config_interface,
 	.configure_filter	= rt2x00mac_configure_filter,
+	.set_key		= rt2x00mac_set_key,
 	.get_stats		= rt2x00mac_get_stats,
 	.set_retry_limit	= rt73usb_set_retry_limit,
 	.bss_info_changed	= rt2x00mac_bss_info_changed,
-	.conf_tx		= rt2x00mac_conf_tx,
+	.conf_tx		= rt73usb_conf_tx,
 	.get_tx_stats		= rt2x00mac_get_tx_stats,
 	.get_tsf		= rt73usb_get_tsf,
 };
@@ -2024,6 +2343,8 @@
 	.get_tx_data_len	= rt73usb_get_tx_data_len,
 	.kick_tx_queue		= rt73usb_kick_tx_queue,
 	.fill_rxdone		= rt73usb_fill_rxdone,
+	.config_shared_key	= rt73usb_config_shared_key,
+	.config_pairwise_key	= rt73usb_config_pairwise_key,
 	.config_filter		= rt73usb_config_filter,
 	.config_intf		= rt73usb_config_intf,
 	.config_erp		= rt73usb_config_erp,
diff --git a/drivers/net/wireless/rt2x00/rt73usb.h b/drivers/net/wireless/rt2x00/rt73usb.h
index 1484935..868386c 100644
--- a/drivers/net/wireless/rt2x00/rt73usb.h
+++ b/drivers/net/wireless/rt2x00/rt73usb.h
@@ -92,6 +92,16 @@
 #define PAIRWISE_KEY_TABLE_BASE		0x1200
 #define PAIRWISE_TA_TABLE_BASE		0x1a00
 
+#define SHARED_KEY_ENTRY(__idx) \
+	( SHARED_KEY_TABLE_BASE + \
+		((__idx) * sizeof(struct hw_key_entry)) )
+#define PAIRWISE_KEY_ENTRY(__idx) \
+	( PAIRWISE_KEY_TABLE_BASE + \
+		((__idx) * sizeof(struct hw_key_entry)) )
+#define PAIRWISE_TA_ENTRY(__idx) \
+	( PAIRWISE_TA_TABLE_BASE + \
+		((__idx) * sizeof(struct hw_pairwise_ta_entry)) )
+
 struct hw_key_entry {
 	u8 key[16];
 	u8 tx_mic[8];
@@ -100,7 +110,8 @@
 
 struct hw_pairwise_ta_entry {
 	u8 address[6];
-	u8 reserved[2];
+	u8 cipher;
+	u8 reserved;
 } __attribute__ ((packed));
 
 /*
@@ -563,6 +574,10 @@
  * SEC_CSR4: Pairwise key table lookup control.
  */
 #define SEC_CSR4			0x30b0
+#define SEC_CSR4_ENABLE_BSS0		FIELD32(0x00000001)
+#define SEC_CSR4_ENABLE_BSS1		FIELD32(0x00000002)
+#define SEC_CSR4_ENABLE_BSS2		FIELD32(0x00000004)
+#define SEC_CSR4_ENABLE_BSS3		FIELD32(0x00000008)
 
 /*
  * SEC_CSR5: shared key table security mode register.
@@ -1010,8 +1025,10 @@
 
 /*
  * Word4
+ * ICV: Received ICV of originally encrypted.
+ * NOTE: This is a guess, the official definition is "reserved"
  */
-#define RXD_W4_RESERVED			FIELD32(0xffffffff)
+#define RXD_W4_ICV			FIELD32(0xffffffff)
 
 /*
  * the above 20-byte is called RXINFO and will be DMAed to MAC RX block
@@ -1033,17 +1050,10 @@
 #define MAX_TXPOWER	31
 #define DEFAULT_TXPOWER	24
 
-#define TXPOWER_FROM_DEV(__txpower)		\
-({						\
-	((__txpower) > MAX_TXPOWER) ?		\
-		DEFAULT_TXPOWER : (__txpower);	\
-})
+#define TXPOWER_FROM_DEV(__txpower) \
+	(((u8)(__txpower)) > MAX_TXPOWER) ? DEFAULT_TXPOWER : (__txpower)
 
-#define TXPOWER_TO_DEV(__txpower)			\
-({							\
-	((__txpower) <= MIN_TXPOWER) ? MIN_TXPOWER :	\
-	(((__txpower) >= MAX_TXPOWER) ? MAX_TXPOWER :	\
-	(__txpower));					\
-})
+#define TXPOWER_TO_DEV(__txpower) \
+	clamp_t(char, __txpower, MIN_TXPOWER, MAX_TXPOWER)
 
 #endif /* RT73USB_H */
diff --git a/drivers/net/wireless/rtl8180.h b/drivers/net/wireless/rtl8180.h
index 082a11f..8721282 100644
--- a/drivers/net/wireless/rtl8180.h
+++ b/drivers/net/wireless/rtl8180.h
@@ -24,20 +24,6 @@
 #define ANAPARAM_PWR1_SHIFT	20
 #define ANAPARAM_PWR1_MASK	(0x7F << ANAPARAM_PWR1_SHIFT)
 
-enum rtl8180_tx_desc_flags {
-	RTL8180_TX_DESC_FLAG_NO_ENC	= (1 << 15),
-	RTL8180_TX_DESC_FLAG_TX_OK	= (1 << 15),
-	RTL8180_TX_DESC_FLAG_SPLCP	= (1 << 16),
-	RTL8180_TX_DESC_FLAG_RX_UNDER	= (1 << 16),
-	RTL8180_TX_DESC_FLAG_MOREFRAG	= (1 << 17),
-	RTL8180_TX_DESC_FLAG_CTS	= (1 << 18),
-	RTL8180_TX_DESC_FLAG_RTS	= (1 << 23),
-	RTL8180_TX_DESC_FLAG_LS		= (1 << 28),
-	RTL8180_TX_DESC_FLAG_FS		= (1 << 29),
-	RTL8180_TX_DESC_FLAG_DMA	= (1 << 30),
-	RTL8180_TX_DESC_FLAG_OWN	= (1 << 31)
-};
-
 struct rtl8180_tx_desc {
 	__le32 flags;
 	__le16 rts_duration;
@@ -52,23 +38,6 @@
 	u32 reserved[2];
 } __attribute__ ((packed));
 
-enum rtl8180_rx_desc_flags {
-	RTL8180_RX_DESC_FLAG_ICV_ERR	= (1 << 12),
-	RTL8180_RX_DESC_FLAG_CRC32_ERR	= (1 << 13),
-	RTL8180_RX_DESC_FLAG_PM		= (1 << 14),
-	RTL8180_RX_DESC_FLAG_RX_ERR	= (1 << 15),
-	RTL8180_RX_DESC_FLAG_BCAST	= (1 << 16),
-	RTL8180_RX_DESC_FLAG_PAM	= (1 << 17),
-	RTL8180_RX_DESC_FLAG_MCAST	= (1 << 18),
-	RTL8180_RX_DESC_FLAG_SPLCP	= (1 << 25),
-	RTL8180_RX_DESC_FLAG_FOF	= (1 << 26),
-	RTL8180_RX_DESC_FLAG_DMA_FAIL	= (1 << 27),
-	RTL8180_RX_DESC_FLAG_LS		= (1 << 28),
-	RTL8180_RX_DESC_FLAG_FS		= (1 << 29),
-	RTL8180_RX_DESC_FLAG_EOR	= (1 << 30),
-	RTL8180_RX_DESC_FLAG_OWN	= (1 << 31)
-};
-
 struct rtl8180_rx_desc {
 	__le32 flags;
 	__le32 flags2;
diff --git a/drivers/net/wireless/rtl8180_dev.c b/drivers/net/wireless/rtl8180_dev.c
index b7172a1..df7e78e 100644
--- a/drivers/net/wireless/rtl8180_dev.c
+++ b/drivers/net/wireless/rtl8180_dev.c
@@ -110,12 +110,12 @@
 		struct sk_buff *skb = priv->rx_buf[priv->rx_idx];
 		u32 flags = le32_to_cpu(entry->flags);
 
-		if (flags & RTL8180_RX_DESC_FLAG_OWN)
+		if (flags & RTL818X_RX_DESC_FLAG_OWN)
 			return;
 
-		if (unlikely(flags & (RTL8180_RX_DESC_FLAG_DMA_FAIL |
-				      RTL8180_RX_DESC_FLAG_FOF |
-				      RTL8180_RX_DESC_FLAG_RX_ERR)))
+		if (unlikely(flags & (RTL818X_RX_DESC_FLAG_DMA_FAIL |
+				      RTL818X_RX_DESC_FLAG_FOF |
+				      RTL818X_RX_DESC_FLAG_RX_ERR)))
 			goto done;
 		else {
 			u32 flags2 = le32_to_cpu(entry->flags2);
@@ -140,7 +140,7 @@
 			rx_status.band = dev->conf.channel->band;
 			rx_status.mactime = le64_to_cpu(entry->tsft);
 			rx_status.flag |= RX_FLAG_TSFT;
-			if (flags & RTL8180_RX_DESC_FLAG_CRC32_ERR)
+			if (flags & RTL818X_RX_DESC_FLAG_CRC32_ERR)
 				rx_status.flag |= RX_FLAG_FAILED_FCS_CRC;
 
 			ieee80211_rx_irqsafe(dev, skb, &rx_status);
@@ -154,10 +154,10 @@
 
 	done:
 		entry->rx_buf = cpu_to_le32(*((dma_addr_t *)skb->cb));
-		entry->flags = cpu_to_le32(RTL8180_RX_DESC_FLAG_OWN |
+		entry->flags = cpu_to_le32(RTL818X_RX_DESC_FLAG_OWN |
 					   MAX_RX_SIZE);
 		if (priv->rx_idx == 31)
-			entry->flags |= cpu_to_le32(RTL8180_RX_DESC_FLAG_EOR);
+			entry->flags |= cpu_to_le32(RTL818X_RX_DESC_FLAG_EOR);
 		priv->rx_idx = (priv->rx_idx + 1) % 32;
 	}
 }
@@ -173,7 +173,7 @@
 		struct ieee80211_tx_info *info;
 		u32 flags = le32_to_cpu(entry->flags);
 
-		if (flags & RTL8180_TX_DESC_FLAG_OWN)
+		if (flags & RTL818X_TX_DESC_FLAG_OWN)
 			return;
 
 		ring->idx = (ring->idx + 1) % ring->entries;
@@ -185,7 +185,7 @@
 		memset(&info->status, 0, sizeof(info->status));
 
 		if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) {
-			if (flags & RTL8180_TX_DESC_FLAG_TX_OK)
+			if (flags & RTL818X_TX_DESC_FLAG_TX_OK)
 				info->flags |= IEEE80211_TX_STAT_ACK;
 			else
 				info->status.excessive_retries = 1;
@@ -252,20 +252,20 @@
 	mapping = pci_map_single(priv->pdev, skb->data,
 				 skb->len, PCI_DMA_TODEVICE);
 
-	tx_flags = RTL8180_TX_DESC_FLAG_OWN | RTL8180_TX_DESC_FLAG_FS |
-		   RTL8180_TX_DESC_FLAG_LS |
+	tx_flags = RTL818X_TX_DESC_FLAG_OWN | RTL818X_TX_DESC_FLAG_FS |
+		   RTL818X_TX_DESC_FLAG_LS |
 		   (ieee80211_get_tx_rate(dev, info)->hw_value << 24) |
 		   skb->len;
 
 	if (priv->r8185)
-		tx_flags |= RTL8180_TX_DESC_FLAG_DMA |
-			    RTL8180_TX_DESC_FLAG_NO_ENC;
+		tx_flags |= RTL818X_TX_DESC_FLAG_DMA |
+			    RTL818X_TX_DESC_FLAG_NO_ENC;
 
 	if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) {
-		tx_flags |= RTL8180_TX_DESC_FLAG_RTS;
+		tx_flags |= RTL818X_TX_DESC_FLAG_RTS;
 		tx_flags |= ieee80211_get_rts_cts_rate(dev, info)->hw_value << 19;
 	} else if (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) {
-		tx_flags |= RTL8180_TX_DESC_FLAG_CTS;
+		tx_flags |= RTL818X_TX_DESC_FLAG_CTS;
 		tx_flags |= ieee80211_get_rts_cts_rate(dev, info)->hw_value << 19;
 	}
 
@@ -292,8 +292,8 @@
 	entry->plcp_len = cpu_to_le16(plcp_len);
 	entry->tx_buf = cpu_to_le32(mapping);
 	entry->frame_len = cpu_to_le32(skb->len);
-	entry->flags2 = info->control.alt_retry_rate_idx >= 0 ?
-		ieee80211_get_alt_retry_rate(dev, info)->bitrate << 4 : 0;
+	entry->flags2 = info->control.retries[0].rate_idx >= 0 ?
+		ieee80211_get_alt_retry_rate(dev, info, 0)->bitrate << 4 : 0;
 	entry->retry_limit = info->control.retry_limit;
 	entry->flags = cpu_to_le32(tx_flags);
 	__skb_queue_tail(&ring->queue, skb);
@@ -446,10 +446,10 @@
 		*mapping = pci_map_single(priv->pdev, skb_tail_pointer(skb),
 					  MAX_RX_SIZE, PCI_DMA_FROMDEVICE);
 		entry->rx_buf = cpu_to_le32(*mapping);
-		entry->flags = cpu_to_le32(RTL8180_RX_DESC_FLAG_OWN |
+		entry->flags = cpu_to_le32(RTL818X_RX_DESC_FLAG_OWN |
 					   MAX_RX_SIZE);
 	}
-	entry->flags |= cpu_to_le32(RTL8180_RX_DESC_FLAG_EOR);
+	entry->flags |= cpu_to_le32(RTL818X_RX_DESC_FLAG_EOR);
 	return 0;
 }
 
@@ -615,7 +615,7 @@
 	reg |= RTL818X_CMD_TX_ENABLE;
 	rtl818x_iowrite8(priv, &priv->map->CMD, reg);
 
-	priv->mode = IEEE80211_IF_TYPE_MNTR;
+	priv->mode = NL80211_IFTYPE_MONITOR;
 	return 0;
 
  err_free_rings:
@@ -633,7 +633,7 @@
 	u8 reg;
 	int i;
 
-	priv->mode = IEEE80211_IF_TYPE_INVALID;
+	priv->mode = NL80211_IFTYPE_UNSPECIFIED;
 
 	rtl818x_iowrite16(priv, &priv->map->INT_MASK, 0);
 
@@ -661,11 +661,11 @@
 {
 	struct rtl8180_priv *priv = dev->priv;
 
-	if (priv->mode != IEEE80211_IF_TYPE_MNTR)
+	if (priv->mode != NL80211_IFTYPE_MONITOR)
 		return -EOPNOTSUPP;
 
 	switch (conf->type) {
-	case IEEE80211_IF_TYPE_STA:
+	case NL80211_IFTYPE_STATION:
 		priv->mode = conf->type;
 		break;
 	default:
@@ -688,7 +688,7 @@
 				     struct ieee80211_if_init_conf *conf)
 {
 	struct rtl8180_priv *priv = dev->priv;
-	priv->mode = IEEE80211_IF_TYPE_MNTR;
+	priv->mode = NL80211_IFTYPE_MONITOR;
 	priv->vif = NULL;
 }
 
@@ -855,6 +855,7 @@
 	priv = dev->priv;
 	priv->pdev = pdev;
 
+	dev->max_altrates = 1;
 	SET_IEEE80211_DEV(dev, &pdev->dev);
 	pci_set_drvdata(pdev, dev);
 
diff --git a/drivers/net/wireless/rtl8187.h b/drivers/net/wireless/rtl8187.h
index 5a9515c..e82bb4d 100644
--- a/drivers/net/wireless/rtl8187.h
+++ b/drivers/net/wireless/rtl8187.h
@@ -58,12 +58,6 @@
 
 /* {rtl8187,rtl8187b}_tx_info is in skb */
 
-/* Tx flags are common between rtl8187 and rtl8187b */
-#define RTL8187_TX_FLAG_NO_ENCRYPT	(1 << 15)
-#define RTL8187_TX_FLAG_MORE_FRAG	(1 << 17)
-#define RTL8187_TX_FLAG_CTS		(1 << 18)
-#define RTL8187_TX_FLAG_RTS		(1 << 23)
-
 struct rtl8187_tx_hdr {
 	__le32 flags;
 	__le16 rts_duration;
diff --git a/drivers/net/wireless/rtl8187_dev.c b/drivers/net/wireless/rtl8187_dev.c
index ca5deb6..e990261 100644
--- a/drivers/net/wireless/rtl8187_dev.c
+++ b/drivers/net/wireless/rtl8187_dev.c
@@ -187,18 +187,18 @@
 	}
 
 	flags = skb->len;
-	flags |= RTL8187_TX_FLAG_NO_ENCRYPT;
+	flags |= RTL818X_TX_DESC_FLAG_NO_ENC;
 
 	flags |= ieee80211_get_tx_rate(dev, info)->hw_value << 24;
 	if (ieee80211_has_morefrags(((struct ieee80211_hdr *)skb->data)->frame_control))
-		flags |= RTL8187_TX_FLAG_MORE_FRAG;
+		flags |= RTL818X_TX_DESC_FLAG_MOREFRAG;
 	if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) {
-		flags |= RTL8187_TX_FLAG_RTS;
+		flags |= RTL818X_TX_DESC_FLAG_RTS;
 		flags |= ieee80211_get_rts_cts_rate(dev, info)->hw_value << 19;
 		rts_dur = ieee80211_rts_duration(dev, priv->vif,
 						 skb->len, info);
 	} else if (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) {
-		flags |= RTL8187_TX_FLAG_CTS;
+		flags |= RTL818X_TX_DESC_FLAG_CTS;
 		flags |= ieee80211_get_rts_cts_rate(dev, info)->hw_value << 19;
 	}
 
@@ -354,7 +354,7 @@
 	rx_status.freq = dev->conf.channel->center_freq;
 	rx_status.band = dev->conf.channel->band;
 	rx_status.flag |= RX_FLAG_TSFT;
-	if (flags & (1 << 13))
+	if (flags & RTL818X_RX_DESC_FLAG_CRC32_ERR)
 		rx_status.flag |= RX_FLAG_FAILED_FCS_CRC;
 	ieee80211_rx_irqsafe(dev, skb, &rx_status);
 
@@ -836,11 +836,11 @@
 	struct rtl8187_priv *priv = dev->priv;
 	int i;
 
-	if (priv->mode != IEEE80211_IF_TYPE_MNTR)
+	if (priv->mode != NL80211_IFTYPE_MONITOR)
 		return -EOPNOTSUPP;
 
 	switch (conf->type) {
-	case IEEE80211_IF_TYPE_STA:
+	case NL80211_IFTYPE_STATION:
 		priv->mode = conf->type;
 		break;
 	default:
@@ -865,7 +865,7 @@
 {
 	struct rtl8187_priv *priv = dev->priv;
 	mutex_lock(&priv->conf_mutex);
-	priv->mode = IEEE80211_IF_TYPE_MNTR;
+	priv->mode = NL80211_IFTYPE_MONITOR;
 	priv->vif = NULL;
 	mutex_unlock(&priv->conf_mutex);
 }
@@ -1057,7 +1057,7 @@
 	dev->wiphy->bands[IEEE80211_BAND_2GHZ] = &priv->band;
 
 
-	priv->mode = IEEE80211_IF_TYPE_MNTR;
+	priv->mode = NL80211_IFTYPE_MONITOR;
 	dev->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
 		     IEEE80211_HW_RX_INCLUDES_FCS;
 
@@ -1184,6 +1184,8 @@
 		dev->max_signal = 65;
 	}
 
+	dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
+
 	if ((id->driver_info == DEVICE_RTL8187) && priv->is_rtl8187b)
 		printk(KERN_INFO "rtl8187: inconsistency between id with OEM"
 		       " info!\n");
diff --git a/drivers/net/wireless/rtl818x.h b/drivers/net/wireless/rtl818x.h
index 00900fe..3538b15 100644
--- a/drivers/net/wireless/rtl818x.h
+++ b/drivers/net/wireless/rtl818x.h
@@ -193,4 +193,39 @@
 	void (*set_chan)(struct ieee80211_hw *, struct ieee80211_conf *);
 };
 
+/* Tx/Rx flags are common between RTL818X chips */
+
+enum rtl818x_tx_desc_flags {
+	RTL818X_TX_DESC_FLAG_NO_ENC	= (1 << 15),
+	RTL818X_TX_DESC_FLAG_TX_OK	= (1 << 15),
+	RTL818X_TX_DESC_FLAG_SPLCP	= (1 << 16),
+	RTL818X_TX_DESC_FLAG_RX_UNDER	= (1 << 16),
+	RTL818X_TX_DESC_FLAG_MOREFRAG	= (1 << 17),
+	RTL818X_TX_DESC_FLAG_CTS	= (1 << 18),
+	RTL818X_TX_DESC_FLAG_RTS	= (1 << 23),
+	RTL818X_TX_DESC_FLAG_LS		= (1 << 28),
+	RTL818X_TX_DESC_FLAG_FS		= (1 << 29),
+	RTL818X_TX_DESC_FLAG_DMA	= (1 << 30),
+	RTL818X_TX_DESC_FLAG_OWN	= (1 << 31)
+};
+
+enum rtl818x_rx_desc_flags {
+	RTL818X_RX_DESC_FLAG_ICV_ERR	= (1 << 12),
+	RTL818X_RX_DESC_FLAG_CRC32_ERR	= (1 << 13),
+	RTL818X_RX_DESC_FLAG_PM		= (1 << 14),
+	RTL818X_RX_DESC_FLAG_RX_ERR	= (1 << 15),
+	RTL818X_RX_DESC_FLAG_BCAST	= (1 << 16),
+	RTL818X_RX_DESC_FLAG_PAM	= (1 << 17),
+	RTL818X_RX_DESC_FLAG_MCAST	= (1 << 18),
+	RTL818X_RX_DESC_FLAG_QOS	= (1 << 19), /* RTL8187(B) only */
+	RTL818X_RX_DESC_FLAG_TRSW	= (1 << 24), /* RTL8187(B) only */
+	RTL818X_RX_DESC_FLAG_SPLCP	= (1 << 25),
+	RTL818X_RX_DESC_FLAG_FOF	= (1 << 26),
+	RTL818X_RX_DESC_FLAG_DMA_FAIL	= (1 << 27),
+	RTL818X_RX_DESC_FLAG_LS		= (1 << 28),
+	RTL818X_RX_DESC_FLAG_FS		= (1 << 29),
+	RTL818X_RX_DESC_FLAG_EOR	= (1 << 30),
+	RTL818X_RX_DESC_FLAG_OWN	= (1 << 31)
+};
+
 #endif /* RTL818X_H */
diff --git a/drivers/net/wireless/spectrum_cs.c b/drivers/net/wireless/spectrum_cs.c
index 98df9bc..b0c71c3 100644
--- a/drivers/net/wireless/spectrum_cs.c
+++ b/drivers/net/wireless/spectrum_cs.c
@@ -25,7 +25,6 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/delay.h>
-#include <linux/firmware.h>
 #include <pcmcia/cs_types.h>
 #include <pcmcia/cs.h>
 #include <pcmcia/cistpl.h>
@@ -34,9 +33,6 @@
 
 #include "orinoco.h"
 
-static const char primary_fw_name[] = "symbol_sp24t_prim_fw";
-static const char secondary_fw_name[] = "symbol_sp24t_sec_fw";
-
 /********************************************************************/
 /* Module stuff							    */
 /********************************************************************/
@@ -71,161 +67,11 @@
 static int spectrum_cs_config(struct pcmcia_device *link);
 static void spectrum_cs_release(struct pcmcia_device *link);
 
-/********************************************************************/
-/* Firmware downloader						    */
-/********************************************************************/
-
-/* Position of PDA in the adapter memory */
-#define EEPROM_ADDR	0x3000
-#define EEPROM_LEN	0x200
-#define PDA_OFFSET	0x100
-
-#define PDA_ADDR	(EEPROM_ADDR + PDA_OFFSET)
-#define PDA_WORDS	((EEPROM_LEN - PDA_OFFSET) / 2)
-
 /* Constants for the CISREG_CCSR register */
 #define HCR_RUN		0x07	/* run firmware after reset */
 #define HCR_IDLE	0x0E	/* don't run firmware after reset */
 #define HCR_MEM16	0x10	/* memory width bit, should be preserved */
 
-/*
- * AUX port access.  To unlock the AUX port write the access keys to the
- * PARAM0-2 registers, then write HERMES_AUX_ENABLE to the HERMES_CONTROL
- * register.  Then read it and make sure it's HERMES_AUX_ENABLED.
- */
-#define HERMES_AUX_ENABLE	0x8000	/* Enable auxiliary port access */
-#define HERMES_AUX_DISABLE	0x4000	/* Disable to auxiliary port access */
-#define HERMES_AUX_ENABLED	0xC000	/* Auxiliary port is open */
-
-#define HERMES_AUX_PW0	0xFE01
-#define HERMES_AUX_PW1	0xDC23
-#define HERMES_AUX_PW2	0xBA45
-
-/* End markers */
-#define PDI_END		0x00000000	/* End of PDA */
-#define BLOCK_END	0xFFFFFFFF	/* Last image block */
-#define TEXT_END	0x1A		/* End of text header */
-
-/*
- * The following structures have little-endian fields denoted by
- * the leading underscore.  Don't access them directly - use inline
- * functions defined below.
- */
-
-/*
- * The binary image to be downloaded consists of series of data blocks.
- * Each block has the following structure.
- */
-struct dblock {
-	__le32 addr;		/* adapter address where to write the block */
-	__le16 len;		/* length of the data only, in bytes */
-	char data[0];		/* data to be written */
-} __attribute__ ((packed));
-
-/*
- * Plug Data References are located in in the image after the last data
- * block.  They refer to areas in the adapter memory where the plug data
- * items with matching ID should be written.
- */
-struct pdr {
-	__le32 id;		/* record ID */
-	__le32 addr;		/* adapter address where to write the data */
-	__le32 len;		/* expected length of the data, in bytes */
-	char next[0];		/* next PDR starts here */
-} __attribute__ ((packed));
-
-
-/*
- * Plug Data Items are located in the EEPROM read from the adapter by
- * primary firmware.  They refer to the device-specific data that should
- * be plugged into the secondary firmware.
- */
-struct pdi {
-	__le16 len;		/* length of ID and data, in words */
-	__le16 id;		/* record ID */
-	char data[0];		/* plug data */
-} __attribute__ ((packed));
-
-
-/* Functions for access to little-endian data */
-static inline u32
-dblock_addr(const struct dblock *blk)
-{
-	return le32_to_cpu(blk->addr);
-}
-
-static inline u32
-dblock_len(const struct dblock *blk)
-{
-	return le16_to_cpu(blk->len);
-}
-
-static inline u32
-pdr_id(const struct pdr *pdr)
-{
-	return le32_to_cpu(pdr->id);
-}
-
-static inline u32
-pdr_addr(const struct pdr *pdr)
-{
-	return le32_to_cpu(pdr->addr);
-}
-
-static inline u32
-pdr_len(const struct pdr *pdr)
-{
-	return le32_to_cpu(pdr->len);
-}
-
-static inline u32
-pdi_id(const struct pdi *pdi)
-{
-	return le16_to_cpu(pdi->id);
-}
-
-/* Return length of the data only, in bytes */
-static inline u32
-pdi_len(const struct pdi *pdi)
-{
-	return 2 * (le16_to_cpu(pdi->len) - 1);
-}
-
-
-/* Set address of the auxiliary port */
-static inline void
-spectrum_aux_setaddr(hermes_t *hw, u32 addr)
-{
-	hermes_write_reg(hw, HERMES_AUXPAGE, (u16) (addr >> 7));
-	hermes_write_reg(hw, HERMES_AUXOFFSET, (u16) (addr & 0x7F));
-}
-
-
-/* Open access to the auxiliary port */
-static int
-spectrum_aux_open(hermes_t *hw)
-{
-	int i;
-
-	/* Already open? */
-	if (hermes_read_reg(hw, HERMES_CONTROL) == HERMES_AUX_ENABLED)
-		return 0;
-
-	hermes_write_reg(hw, HERMES_PARAM0, HERMES_AUX_PW0);
-	hermes_write_reg(hw, HERMES_PARAM1, HERMES_AUX_PW1);
-	hermes_write_reg(hw, HERMES_PARAM2, HERMES_AUX_PW2);
-	hermes_write_reg(hw, HERMES_CONTROL, HERMES_AUX_ENABLE);
-
-	for (i = 0; i < 20; i++) {
-		udelay(10);
-		if (hermes_read_reg(hw, HERMES_CONTROL) ==
-		    HERMES_AUX_ENABLED)
-			return 0;
-	}
-
-	return -EBUSY;
-}
-
 
 #define CS_CHECK(fn, ret) \
   do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)
@@ -292,252 +138,6 @@
 	return -ENODEV;
 }
 
-
-/*
- * Scan PDR for the record with the specified RECORD_ID.
- * If it's not found, return NULL.
- */
-static struct pdr *
-spectrum_find_pdr(struct pdr *first_pdr, u32 record_id)
-{
-	struct pdr *pdr = first_pdr;
-
-	while (pdr_id(pdr) != PDI_END) {
-		/*
-		 * PDR area is currently not terminated by PDI_END.
-		 * It's followed by CRC records, which have the type
-		 * field where PDR has length.  The type can be 0 or 1.
-		 */
-		if (pdr_len(pdr) < 2)
-			return NULL;
-
-		/* If the record ID matches, we are done */
-		if (pdr_id(pdr) == record_id)
-			return pdr;
-
-		pdr = (struct pdr *) pdr->next;
-	}
-	return NULL;
-}
-
-
-/* Process one Plug Data Item - find corresponding PDR and plug it */
-static int
-spectrum_plug_pdi(hermes_t *hw, struct pdr *first_pdr, struct pdi *pdi)
-{
-	struct pdr *pdr;
-
-	/* Find the PDI corresponding to this PDR */
-	pdr = spectrum_find_pdr(first_pdr, pdi_id(pdi));
-
-	/* No match is found, safe to ignore */
-	if (!pdr)
-		return 0;
-
-	/* Lengths of the data in PDI and PDR must match */
-	if (pdi_len(pdi) != pdr_len(pdr))
-		return -EINVAL;
-
-	/* do the actual plugging */
-	spectrum_aux_setaddr(hw, pdr_addr(pdr));
-	hermes_write_bytes(hw, HERMES_AUXDATA, pdi->data, pdi_len(pdi));
-
-	return 0;
-}
-
-
-/* Read PDA from the adapter */
-static int
-spectrum_read_pda(hermes_t *hw, __le16 *pda, int pda_len)
-{
-	int ret;
-	int pda_size;
-
-	/* Issue command to read EEPROM */
-	ret = hermes_docmd_wait(hw, HERMES_CMD_READMIF, 0, NULL);
-	if (ret)
-		return ret;
-
-	/* Open auxiliary port */
-	ret = spectrum_aux_open(hw);
-	if (ret)
-		return ret;
-
-	/* read PDA from EEPROM */
-	spectrum_aux_setaddr(hw, PDA_ADDR);
-	hermes_read_words(hw, HERMES_AUXDATA, pda, pda_len / 2);
-
-	/* Check PDA length */
-	pda_size = le16_to_cpu(pda[0]);
-	if (pda_size > pda_len)
-		return -EINVAL;
-
-	return 0;
-}
-
-
-/* Parse PDA and write the records into the adapter */
-static int
-spectrum_apply_pda(hermes_t *hw, const struct dblock *first_block,
-		   __le16 *pda)
-{
-	int ret;
-	struct pdi *pdi;
-	struct pdr *first_pdr;
-	const struct dblock *blk = first_block;
-
-	/* Skip all blocks to locate Plug Data References */
-	while (dblock_addr(blk) != BLOCK_END)
-		blk = (struct dblock *) &blk->data[dblock_len(blk)];
-
-	first_pdr = (struct pdr *) blk;
-
-	/* Go through every PDI and plug them into the adapter */
-	pdi = (struct pdi *) (pda + 2);
-	while (pdi_id(pdi) != PDI_END) {
-		ret = spectrum_plug_pdi(hw, first_pdr, pdi);
-		if (ret)
-			return ret;
-
-		/* Increment to the next PDI */
-		pdi = (struct pdi *) &pdi->data[pdi_len(pdi)];
-	}
-	return 0;
-}
-
-
-/* Load firmware blocks into the adapter */
-static int
-spectrum_load_blocks(hermes_t *hw, const struct dblock *first_block)
-{
-	const struct dblock *blk;
-	u32 blkaddr;
-	u32 blklen;
-
-	blk = first_block;
-	blkaddr = dblock_addr(blk);
-	blklen = dblock_len(blk);
-
-	while (dblock_addr(blk) != BLOCK_END) {
-		spectrum_aux_setaddr(hw, blkaddr);
-		hermes_write_bytes(hw, HERMES_AUXDATA, blk->data,
-				   blklen);
-
-		blk = (struct dblock *) &blk->data[blklen];
-		blkaddr = dblock_addr(blk);
-		blklen = dblock_len(blk);
-	}
-	return 0;
-}
-
-
-/*
- * Process a firmware image - stop the card, load the firmware, reset
- * the card and make sure it responds.  For the secondary firmware take
- * care of the PDA - read it and then write it on top of the firmware.
- */
-static int
-spectrum_dl_image(hermes_t *hw, struct pcmcia_device *link,
-		  const unsigned char *image, int secondary)
-{
-	int ret;
-	const unsigned char *ptr;
-	const struct dblock *first_block;
-
-	/* Plug Data Area (PDA) */
-	__le16 pda[PDA_WORDS];
-
-	/* Binary block begins after the 0x1A marker */
-	ptr = image;
-	while (*ptr++ != TEXT_END);
-	first_block = (const struct dblock *) ptr;
-
-	/* Read the PDA */
-	if (secondary) {
-		ret = spectrum_read_pda(hw, pda, sizeof(pda));
-		if (ret)
-			return ret;
-	}
-
-	/* Stop the firmware, so that it can be safely rewritten */
-	ret = spectrum_reset(link, 1);
-	if (ret)
-		return ret;
-
-	/* Program the adapter with new firmware */
-	ret = spectrum_load_blocks(hw, first_block);
-	if (ret)
-		return ret;
-
-	/* Write the PDA to the adapter */
-	if (secondary) {
-		ret = spectrum_apply_pda(hw, first_block, pda);
-		if (ret)
-			return ret;
-	}
-
-	/* Run the firmware */
-	ret = spectrum_reset(link, 0);
-	if (ret)
-		return ret;
-
-	/* Reset hermes chip and make sure it responds */
-	ret = hermes_init(hw);
-
-	/* hermes_reset() should return 0 with the secondary firmware */
-	if (secondary && ret != 0)
-		return -ENODEV;
-
-	/* And this should work with any firmware */
-	if (!hermes_present(hw))
-		return -ENODEV;
-
-	return 0;
-}
-
-
-/*
- * Download the firmware into the card, this also does a PCMCIA soft
- * reset on the card, to make sure it's in a sane state.
- */
-static int
-spectrum_dl_firmware(hermes_t *hw, struct pcmcia_device *link)
-{
-	int ret;
-	const struct firmware *fw_entry;
-
-	if (request_firmware(&fw_entry, primary_fw_name,
-			     &handle_to_dev(link)) != 0) {
-		printk(KERN_ERR PFX "Cannot find firmware: %s\n",
-		       primary_fw_name);
-		return -ENOENT;
-	}
-
-	/* Load primary firmware */
-	ret = spectrum_dl_image(hw, link, fw_entry->data, 0);
-	release_firmware(fw_entry);
-	if (ret) {
-		printk(KERN_ERR PFX "Primary firmware download failed\n");
-		return ret;
-	}
-
-	if (request_firmware(&fw_entry, secondary_fw_name,
-			     &handle_to_dev(link)) != 0) {
-		printk(KERN_ERR PFX "Cannot find firmware: %s\n",
-		       secondary_fw_name);
-		return -ENOENT;
-	}
-
-	/* Load secondary firmware */
-	ret = spectrum_dl_image(hw, link, fw_entry->data, 1);
-	release_firmware(fw_entry);
-	if (ret) {
-		printk(KERN_ERR PFX "Secondary firmware download failed\n");
-	}
-
-	return ret;
-}
-
 /********************************************************************/
 /* Device methods     						    */
 /********************************************************************/
@@ -547,22 +147,22 @@
 {
 	struct orinoco_pccard *card = priv->card;
 	struct pcmcia_device *link = card->p_dev;
-	int err;
 
-	if (!hermes_present(&priv->hw)) {
-		/* The firmware needs to be reloaded */
-		if (spectrum_dl_firmware(&priv->hw, link) != 0) {
-			printk(KERN_ERR PFX "Firmware download failed\n");
-			err = -ENODEV;
-		}
-	} else {
-		/* Soft reset using COR and HCR */
-		spectrum_reset(link, 0);
-	}
+	/* Soft reset using COR and HCR */
+	spectrum_reset(link, 0);
 
 	return 0;
 }
 
+static int
+spectrum_cs_stop_firmware(struct orinoco_private *priv, int idle)
+{
+	struct orinoco_pccard *card = priv->card;
+	struct pcmcia_device *link = card->p_dev;
+
+	return spectrum_reset(link, idle);
+}
+
 /********************************************************************/
 /* PCMCIA stuff     						    */
 /********************************************************************/
@@ -582,7 +182,9 @@
 	struct orinoco_private *priv;
 	struct orinoco_pccard *card;
 
-	dev = alloc_orinocodev(sizeof(*card), spectrum_cs_hard_reset);
+	dev = alloc_orinocodev(sizeof(*card), &handle_to_dev(link),
+			       spectrum_cs_hard_reset,
+			       spectrum_cs_stop_firmware);
 	if (! dev)
 		return -ENOMEM;
 	priv = netdev_priv(dev);
@@ -593,7 +195,7 @@
 	link->priv = dev;
 
 	/* Interrupt setup */
-	link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT;
+	link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING | IRQ_HANDLE_PRESENT;
 	link->irq.IRQInfo1 = IRQ_LEVEL_ID;
 	link->irq.Handler = orinoco_interrupt;
 	link->irq.Instance = dev; 
@@ -633,6 +235,70 @@
  * device available to the system.
  */
 
+static int spectrum_cs_config_check(struct pcmcia_device *p_dev,
+				    cistpl_cftable_entry_t *cfg,
+				    cistpl_cftable_entry_t *dflt,
+				    unsigned int vcc,
+				    void *priv_data)
+{
+	if (cfg->index == 0)
+		goto next_entry;
+
+	/* Use power settings for Vcc and Vpp if present */
+	/* Note that the CIS values need to be rescaled */
+	if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) {
+		if (vcc != cfg->vcc.param[CISTPL_POWER_VNOM] / 10000) {
+			DEBUG(2, "spectrum_cs_config: Vcc mismatch (vcc = %d, CIS = %d)\n",  vcc, cfg->vcc.param[CISTPL_POWER_VNOM] / 10000);
+			if (!ignore_cis_vcc)
+				goto next_entry;
+		}
+	} else if (dflt->vcc.present & (1 << CISTPL_POWER_VNOM)) {
+		if (vcc != dflt->vcc.param[CISTPL_POWER_VNOM] / 10000) {
+			DEBUG(2, "spectrum_cs_config: Vcc mismatch (vcc = %d, CIS = %d)\n",  vcc, dflt->vcc.param[CISTPL_POWER_VNOM] / 10000);
+			if (!ignore_cis_vcc)
+				goto next_entry;
+		}
+	}
+
+	if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM))
+		p_dev->conf.Vpp =
+			cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000;
+	else if (dflt->vpp1.present & (1 << CISTPL_POWER_VNOM))
+		p_dev->conf.Vpp =
+			dflt->vpp1.param[CISTPL_POWER_VNOM] / 10000;
+
+	/* Do we need to allocate an interrupt? */
+	p_dev->conf.Attributes |= CONF_ENABLE_IRQ;
+
+	/* IO window settings */
+	p_dev->io.NumPorts1 = p_dev->io.NumPorts2 = 0;
+	if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) {
+		cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io;
+		p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
+		if (!(io->flags & CISTPL_IO_8BIT))
+			p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_16;
+		if (!(io->flags & CISTPL_IO_16BIT))
+			p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
+		p_dev->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK;
+		p_dev->io.BasePort1 = io->win[0].base;
+		p_dev->io.NumPorts1 = io->win[0].len;
+		if (io->nwin > 1) {
+			p_dev->io.Attributes2 = p_dev->io.Attributes1;
+			p_dev->io.BasePort2 = io->win[1].base;
+			p_dev->io.NumPorts2 = io->win[1].len;
+		}
+
+		/* This reserves IO space but doesn't actually enable it */
+		if (pcmcia_request_io(p_dev, &p_dev->io) != 0)
+			goto next_entry;
+	}
+	return 0;
+
+next_entry:
+	pcmcia_disable_device(p_dev);
+	return -ENODEV;
+};
+
 static int
 spectrum_cs_config(struct pcmcia_device *link)
 {
@@ -641,16 +307,8 @@
 	struct orinoco_pccard *card = priv->card;
 	hermes_t *hw = &priv->hw;
 	int last_fn, last_ret;
-	u_char buf[64];
-	config_info_t conf;
-	tuple_t tuple;
-	cisparse_t parse;
 	void __iomem *mem;
 
-	/* Look up the current Vcc */
-	CS_CHECK(GetConfigurationInfo,
-		 pcmcia_get_configuration_info(link, &conf));
-
 	/*
 	 * In this loop, we scan the CIS for configuration table
 	 * entries, each of which describes a valid card
@@ -665,94 +323,14 @@
 	 * and most client drivers will only use the CIS to fill in
 	 * implementation-defined details.
 	 */
-	tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
-	tuple.Attributes = 0;
-	tuple.TupleData = buf;
-	tuple.TupleDataMax = sizeof(buf);
-	tuple.TupleOffset = 0;
-	CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple));
-	while (1) {
-		cistpl_cftable_entry_t *cfg = &(parse.cftable_entry);
-		cistpl_cftable_entry_t dflt = { .index = 0 };
-
-		if ( (pcmcia_get_tuple_data(link, &tuple) != 0)
-		    || (pcmcia_parse_tuple(link, &tuple, &parse) != 0))
-			goto next_entry;
-
-		if (cfg->flags & CISTPL_CFTABLE_DEFAULT)
-			dflt = *cfg;
-		if (cfg->index == 0)
-			goto next_entry;
-		link->conf.ConfigIndex = cfg->index;
-
-		/* Use power settings for Vcc and Vpp if present */
-		/* Note that the CIS values need to be rescaled */
-		if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) {
-			if (conf.Vcc != cfg->vcc.param[CISTPL_POWER_VNOM] / 10000) {
-				DEBUG(2, "spectrum_cs_config: Vcc mismatch (conf.Vcc = %d, CIS = %d)\n",  conf.Vcc, cfg->vcc.param[CISTPL_POWER_VNOM] / 10000);
-				if (!ignore_cis_vcc)
-					goto next_entry;
-			}
-		} else if (dflt.vcc.present & (1 << CISTPL_POWER_VNOM)) {
-			if (conf.Vcc != dflt.vcc.param[CISTPL_POWER_VNOM] / 10000) {
-				DEBUG(2, "spectrum_cs_config: Vcc mismatch (conf.Vcc = %d, CIS = %d)\n",  conf.Vcc, dflt.vcc.param[CISTPL_POWER_VNOM] / 10000);
-				if(!ignore_cis_vcc)
-					goto next_entry;
-			}
-		}
-
-		if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM))
-			link->conf.Vpp =
-			    cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000;
-		else if (dflt.vpp1.present & (1 << CISTPL_POWER_VNOM))
-			link->conf.Vpp =
-			    dflt.vpp1.param[CISTPL_POWER_VNOM] / 10000;
-		
-		/* Do we need to allocate an interrupt? */
-		link->conf.Attributes |= CONF_ENABLE_IRQ;
-
-		/* IO window settings */
-		link->io.NumPorts1 = link->io.NumPorts2 = 0;
-		if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) {
-			cistpl_io_t *io =
-			    (cfg->io.nwin) ? &cfg->io : &dflt.io;
-			link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
-			if (!(io->flags & CISTPL_IO_8BIT))
-				link->io.Attributes1 =
-				    IO_DATA_PATH_WIDTH_16;
-			if (!(io->flags & CISTPL_IO_16BIT))
-				link->io.Attributes1 =
-				    IO_DATA_PATH_WIDTH_8;
-			link->io.IOAddrLines =
-			    io->flags & CISTPL_IO_LINES_MASK;
-			link->io.BasePort1 = io->win[0].base;
-			link->io.NumPorts1 = io->win[0].len;
-			if (io->nwin > 1) {
-				link->io.Attributes2 =
-				    link->io.Attributes1;
-				link->io.BasePort2 = io->win[1].base;
-				link->io.NumPorts2 = io->win[1].len;
-			}
-
-			/* This reserves IO space but doesn't actually enable it */
-			if (pcmcia_request_io(link, &link->io) != 0)
-				goto next_entry;
-		}
-
-
-		/* If we got this far, we're cool! */
-
-		break;
-		
-	next_entry:
-		pcmcia_disable_device(link);
-		last_ret = pcmcia_get_next_tuple(link, &tuple);
-		if (last_ret  == CS_NO_MORE_ITEMS) {
+	last_ret = pcmcia_loop_config(link, spectrum_cs_config_check, NULL);
+	if (last_ret) {
+		if (!ignore_cis_vcc)
 			printk(KERN_ERR PFX "GetNextTuple(): No matching "
 			       "CIS configuration.  Maybe you need the "
 			       "ignore_cis_vcc=1 parameter.\n");
-			goto cs_failed;
-		}
+		cs_error(link, RequestIO, last_ret);
+		goto failed;
 	}
 
 	/*
@@ -784,7 +362,7 @@
 	dev->irq = link->irq.AssignedIRQ;
 	card->node.major = card->node.minor = 0;
 
-	/* Reset card and download firmware */
+	/* Reset card */
 	if (spectrum_cs_hard_reset(priv) != 0) {
 		goto failed;
 	}
diff --git a/drivers/net/wireless/wavelan.c b/drivers/net/wireless/wavelan.c
index 136220b..e939a73 100644
--- a/drivers/net/wireless/wavelan.c
+++ b/drivers/net/wireless/wavelan.c
@@ -4387,7 +4387,7 @@
  *
  * Thanks go also to:
  *	James Ashton (jaa101@syseng.anu.edu.au),
- *	Alan Cox (alan@redhat.com),
+ *	Alan Cox (alan@lxorguk.ukuu.org.uk),
  *	Allan Creighton (allanc@cs.usyd.edu.au),
  *	Matthew Geier (matthew@cs.usyd.edu.au),
  *	Remo di Giovanni (remo@cs.usyd.edu.au),
diff --git a/drivers/net/wireless/wavelan.p.h b/drivers/net/wireless/wavelan.p.h
index b33ac47..44d31bb 100644
--- a/drivers/net/wireless/wavelan.p.h
+++ b/drivers/net/wireless/wavelan.p.h
@@ -186,7 +186,7 @@
  *
  * Thanks go also to:
  *	James Ashton <jaa101@syseng.anu.edu.au>,
- *	Alan Cox <alan@redhat.com>,
+ *	Alan Cox <alan@lxorguk.ukuu.org.uk>,
  *	Allan Creighton <allanc@cs.usyd.edu.au>,
  *	Matthew Geier <matthew@cs.usyd.edu.au>,
  *	Remo di Giovanni <remo@cs.usyd.edu.au>,
diff --git a/drivers/net/wireless/wavelan_cs.c b/drivers/net/wireless/wavelan_cs.c
index 00a3559..e124b1d 100644
--- a/drivers/net/wireless/wavelan_cs.c
+++ b/drivers/net/wireless/wavelan_cs.c
@@ -3702,7 +3702,7 @@
 #endif
 
   i = pcmcia_access_configuration_register(link, &reg);
-  if(i != CS_SUCCESS)
+  if (i != 0)
     {
       cs_error(link, AccessConfigurationRegister, i);
       return FALSE;
@@ -3716,7 +3716,7 @@
   reg.Action = CS_WRITE;
   reg.Value = reg.Value | COR_SW_RESET;
   i = pcmcia_access_configuration_register(link, &reg);
-  if(i != CS_SUCCESS)
+  if (i != 0)
     {
       cs_error(link, AccessConfigurationRegister, i);
       return FALSE;
@@ -3725,7 +3725,7 @@
   reg.Action = CS_WRITE;
   reg.Value = COR_LEVEL_IRQ | COR_CONFIG;
   i = pcmcia_access_configuration_register(link, &reg);
-  if(i != CS_SUCCESS)
+  if (i != 0)
     {
       cs_error(link, AccessConfigurationRegister, i);
       return FALSE;
@@ -3903,7 +3903,7 @@
   do
     {
       i = pcmcia_request_io(link, &link->io);
-      if(i != CS_SUCCESS)
+      if (i != 0)
 	{
 	  cs_error(link, RequestIO, i);
 	  break;
@@ -3914,7 +3914,7 @@
        * actually assign a handler to the interrupt.
        */
       i = pcmcia_request_irq(link, &link->irq);
-      if(i != CS_SUCCESS)
+      if (i != 0)
 	{
 	  cs_error(link, RequestIRQ, i);
 	  break;
@@ -3926,7 +3926,7 @@
        */
       link->conf.ConfigIndex = 1;
       i = pcmcia_request_configuration(link, &link->conf);
-      if(i != CS_SUCCESS)
+      if (i != 0)
 	{
 	  cs_error(link, RequestConfiguration, i);
 	  break;
@@ -3942,7 +3942,7 @@
       req.Base = req.Size = 0;
       req.AccessSpeed = mem_speed;
       i = pcmcia_request_window(&link, &req, &link->win);
-      if(i != CS_SUCCESS)
+      if (i != 0)
 	{
 	  cs_error(link, RequestWindow, i);
 	  break;
@@ -3954,7 +3954,7 @@
 
       mem.CardOffset = 0; mem.Page = 0;
       i = pcmcia_map_mem_page(link->win, &mem);
-      if(i != CS_SUCCESS)
+      if (i != 0)
 	{
 	  cs_error(link, MapMemPage, i);
 	  break;
@@ -4496,7 +4496,7 @@
   p_dev->io.IOAddrLines = 3;
 
   /* Interrupt setup */
-  p_dev->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT;
+  p_dev->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING | IRQ_HANDLE_PRESENT;
   p_dev->irq.IRQInfo1 = IRQ_LEVEL_ID;
   p_dev->irq.Handler = wavelan_interrupt;
 
diff --git a/drivers/net/wireless/wl3501_cs.c b/drivers/net/wireless/wl3501_cs.c
index 3771419..68789c6 100644
--- a/drivers/net/wireless/wl3501_cs.c
+++ b/drivers/net/wireless/wl3501_cs.c
@@ -79,7 +79,7 @@
 module_param(pc_debug, int, 0);
 #define dprintk(n, format, args...) \
 	{ if (pc_debug > (n)) \
-		printk(KERN_INFO "%s: " format "\n", __FUNCTION__ , ##args); }
+		printk(KERN_INFO "%s: " format "\n", __func__ , ##args); }
 #else
 #define dprintk(n, format, args...)
 #endif
@@ -470,7 +470,7 @@
 			spin_unlock_irqrestore(&this->lock, flags);
 			rc = wait_event_interruptible(this->wait,
 				this->sig_pwr_mgmt_confirm.status != 255);
-			printk(KERN_INFO "%s: %s status=%d\n", __FUNCTION__,
+			printk(KERN_INFO "%s: %s status=%d\n", __func__,
 			       suspend ? "suspend" : "resume",
 			       this->sig_pwr_mgmt_confirm.status);
 			goto out;
@@ -1199,7 +1199,7 @@
 		}
 		WL3501_NOPLOOP(10);
 	}
-	printk(KERN_WARNING "%s: failed to reset the board!\n", __FUNCTION__);
+	printk(KERN_WARNING "%s: failed to reset the board!\n", __func__);
 	rc = -ENODEV;
 out:
 	return rc;
@@ -1250,7 +1250,7 @@
 out:
 	return rc;
 fail:
-	printk(KERN_WARNING "%s: failed!\n", __FUNCTION__);
+	printk(KERN_WARNING "%s: failed!\n", __func__);
 	goto out;
 }
 
@@ -1917,7 +1917,7 @@
 	p_dev->io.IOAddrLines	= 5;
 
 	/* Interrupt setup */
-	p_dev->irq.Attributes	= IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT;
+	p_dev->irq.Attributes	= IRQ_TYPE_DYNAMIC_SHARING | IRQ_HANDLE_PRESENT;
 	p_dev->irq.IRQInfo1	= IRQ_LEVEL_ID;
 	p_dev->irq.Handler = wl3501_interrupt;
 
@@ -1977,10 +1977,10 @@
 		link->io.BasePort1 = j;
 		link->io.BasePort2 = link->io.BasePort1 + 0x10;
 		i = pcmcia_request_io(link, &link->io);
-		if (i == CS_SUCCESS)
+		if (i == 0)
 			break;
 	}
-	if (i != CS_SUCCESS) {
+	if (i != 0) {
 		cs_error(link, RequestIO, i);
 		goto failed;
 	}
diff --git a/drivers/net/wireless/zd1211rw/Makefile b/drivers/net/wireless/zd1211rw/Makefile
index cc36126..1907eaf 100644
--- a/drivers/net/wireless/zd1211rw/Makefile
+++ b/drivers/net/wireless/zd1211rw/Makefile
@@ -1,6 +1,6 @@
 obj-$(CONFIG_ZD1211RW) += zd1211rw.o
 
-zd1211rw-objs := zd_chip.o zd_ieee80211.o zd_mac.o \
+zd1211rw-objs := zd_chip.o zd_mac.o \
 		zd_rf_al2230.o zd_rf_rf2959.o \
 		zd_rf_al7230b.o zd_rf_uw2453.o \
 		zd_rf.o zd_usb.o
diff --git a/drivers/net/wireless/zd1211rw/zd_chip.c b/drivers/net/wireless/zd1211rw/zd_chip.c
index 0acb5c3..e0ac58b 100644
--- a/drivers/net/wireless/zd1211rw/zd_chip.c
+++ b/drivers/net/wireless/zd1211rw/zd_chip.c
@@ -28,7 +28,6 @@
 
 #include "zd_def.h"
 #include "zd_chip.h"
-#include "zd_ieee80211.h"
 #include "zd_mac.h"
 #include "zd_rf.h"
 
diff --git a/drivers/net/wireless/zd1211rw/zd_ieee80211.c b/drivers/net/wireless/zd1211rw/zd_ieee80211.c
deleted file mode 100644
index d8dc41e..0000000
--- a/drivers/net/wireless/zd1211rw/zd_ieee80211.c
+++ /dev/null
@@ -1,100 +0,0 @@
-/* ZD1211 USB-WLAN driver for Linux
- *
- * Copyright (C) 2005-2007 Ulrich Kunitz <kune@deine-taler.de>
- * Copyright (C) 2006-2007 Daniel Drake <dsd@gentoo.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-/*
- * In the long term, we'll probably find a better way of handling regulatory
- * requirements outside of the driver.
- */
-
-#include <linux/kernel.h>
-#include <net/mac80211.h>
-
-#include "zd_ieee80211.h"
-#include "zd_mac.h"
-
-struct channel_range {
-	u8 regdomain;
-	u8 start;
-	u8 end; /* exclusive (channel must be less than end) */
-};
-
-static const struct channel_range channel_ranges[] = {
-	{ ZD_REGDOMAIN_FCC,		1, 12 },
-	{ ZD_REGDOMAIN_IC,		1, 12 },
-	{ ZD_REGDOMAIN_ETSI,		1, 14 },
-	{ ZD_REGDOMAIN_JAPAN,		1, 14 },
-	{ ZD_REGDOMAIN_SPAIN,		1, 14 },
-	{ ZD_REGDOMAIN_FRANCE,		1, 14 },
-
-	/* Japan originally only had channel 14 available (see CHNL_ID 0x40 in
-	 * 802.11). However, in 2001 the range was extended to include channels
-	 * 1-13. The ZyDAS devices still use the old region code but are
-	 * designed to allow the extra channel access in Japan. */
-	{ ZD_REGDOMAIN_JAPAN_ADD,	1, 15 },
-};
-
-static const struct channel_range *zd_channel_range(u8 regdomain)
-{
-	int i;
-	for (i = 0; i < ARRAY_SIZE(channel_ranges); i++) {
-		const struct channel_range *range = &channel_ranges[i];
-		if (range->regdomain == regdomain)
-			return range;
-	}
-	return NULL;
-}
-
-#define CHAN_TO_IDX(chan) ((chan) - 1)
-
-static void unmask_bg_channels(struct ieee80211_hw *hw,
-	const struct channel_range *range,
-	struct ieee80211_supported_band *sband)
-{
-	u8 channel;
-
-	for (channel = range->start; channel < range->end; channel++) {
-		struct ieee80211_channel *chan =
-			&sband->channels[CHAN_TO_IDX(channel)];
-		chan->flags = 0;
-	}
-}
-
-void zd_geo_init(struct ieee80211_hw *hw, u8 regdomain)
-{
-	struct zd_mac *mac = zd_hw_mac(hw);
-	const struct channel_range *range;
-
-	dev_dbg(zd_mac_dev(mac), "regdomain %#02x\n", regdomain);
-
-	range = zd_channel_range(regdomain);
-	if (!range) {
-		/* The vendor driver overrides the regulatory domain and
-		 * allowed channel registers and unconditionally restricts
-		 * available channels to 1-11 everywhere. Match their
-		 * questionable behaviour only for regdomains which we don't
-		 * recognise. */
-		dev_warn(zd_mac_dev(mac), "Unrecognised regulatory domain: "
-			"%#02x. Defaulting to FCC.\n", regdomain);
-		range = zd_channel_range(ZD_REGDOMAIN_FCC);
-	}
-
-	unmask_bg_channels(hw, range, &mac->band);
-}
-
diff --git a/drivers/net/wireless/zd1211rw/zd_ieee80211.h b/drivers/net/wireless/zd1211rw/zd_ieee80211.h
deleted file mode 100644
index 26b79f1..0000000
--- a/drivers/net/wireless/zd1211rw/zd_ieee80211.h
+++ /dev/null
@@ -1,95 +0,0 @@
-/* ZD1211 USB-WLAN driver for Linux
- *
- * Copyright (C) 2005-2007 Ulrich Kunitz <kune@deine-taler.de>
- * Copyright (C) 2006-2007 Daniel Drake <dsd@gentoo.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifndef _ZD_IEEE80211_H
-#define _ZD_IEEE80211_H
-
-#include <net/mac80211.h>
-
-/* Additional definitions from the standards.
- */
-
-#define ZD_REGDOMAIN_FCC	0x10
-#define ZD_REGDOMAIN_IC		0x20
-#define ZD_REGDOMAIN_ETSI	0x30
-#define ZD_REGDOMAIN_SPAIN	0x31
-#define ZD_REGDOMAIN_FRANCE	0x32
-#define ZD_REGDOMAIN_JAPAN_ADD	0x40
-#define ZD_REGDOMAIN_JAPAN	0x41
-
-enum {
-	MIN_CHANNEL24 = 1,
-	MAX_CHANNEL24 = 14,
-};
-
-void zd_geo_init(struct ieee80211_hw *hw, u8 regdomain);
-
-#define ZD_PLCP_SERVICE_LENGTH_EXTENSION 0x80
-
-struct ofdm_plcp_header {
-	u8 prefix[3];
-	__le16 service;
-} __attribute__((packed));
-
-static inline u8 zd_ofdm_plcp_header_rate(const struct ofdm_plcp_header *header)
-{
-	return header->prefix[0] & 0xf;
-}
-
-/* The following defines give the encoding of the 4-bit rate field in the
- * OFDM (802.11a/802.11g) PLCP header. Notify that these values are used to
- * define the zd-rate values for OFDM.
- *
- * See the struct zd_ctrlset definition in zd_mac.h.
- */
-#define ZD_OFDM_PLCP_RATE_6M	0xb
-#define ZD_OFDM_PLCP_RATE_9M	0xf
-#define ZD_OFDM_PLCP_RATE_12M	0xa
-#define ZD_OFDM_PLCP_RATE_18M	0xe
-#define ZD_OFDM_PLCP_RATE_24M	0x9
-#define ZD_OFDM_PLCP_RATE_36M	0xd
-#define ZD_OFDM_PLCP_RATE_48M	0x8
-#define ZD_OFDM_PLCP_RATE_54M	0xc
-
-struct cck_plcp_header {
-	u8 signal;
-	u8 service;
-	__le16 length;
-	__le16 crc16;
-} __attribute__((packed));
-
-static inline u8 zd_cck_plcp_header_signal(const struct cck_plcp_header *header)
-{
-	return header->signal;
-}
-
-/* These defines give the encodings of the signal field in the 802.11b PLCP
- * header. The signal field gives the bit rate of the following packet. Even
- * if technically wrong we use CCK here also for the 1 MBit/s and 2 MBit/s
- * rate to stay consistent with Zydas and our use of the term.
- *
- * Notify that these values are *not* used in the zd-rates.
- */
-#define ZD_CCK_PLCP_SIGNAL_1M	0x0a
-#define ZD_CCK_PLCP_SIGNAL_2M	0x14
-#define ZD_CCK_PLCP_SIGNAL_5M5	0x37
-#define ZD_CCK_PLCP_SIGNAL_11M	0x6e
-
-#endif /* _ZD_IEEE80211_H */
diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c
index 4d7b98b..fe1867b 100644
--- a/drivers/net/wireless/zd1211rw/zd_mac.c
+++ b/drivers/net/wireless/zd1211rw/zd_mac.c
@@ -3,7 +3,7 @@
  * Copyright (C) 2005-2007 Ulrich Kunitz <kune@deine-taler.de>
  * Copyright (C) 2006-2007 Daniel Drake <dsd@gentoo.org>
  * Copyright (C) 2006-2007 Michael Wu <flamingice@sourmilk.net>
- * Copyright (c) 2007 Luis R. Rodriguez <mcgrof@winlab.rutgers.edu>
+ * Copyright (C) 2007-2008 Luis R. Rodriguez <mcgrof@winlab.rutgers.edu>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -29,9 +29,23 @@
 #include "zd_def.h"
 #include "zd_chip.h"
 #include "zd_mac.h"
-#include "zd_ieee80211.h"
 #include "zd_rf.h"
 
+struct zd_reg_alpha2_map {
+	u32 reg;
+	char alpha2[2];
+};
+
+static struct zd_reg_alpha2_map reg_alpha2_map[] = {
+	{ ZD_REGDOMAIN_FCC, "US" },
+	{ ZD_REGDOMAIN_IC, "CA" },
+	{ ZD_REGDOMAIN_ETSI, "DE" }, /* Generic ETSI, use most restrictive */
+	{ ZD_REGDOMAIN_JAPAN, "JP" },
+	{ ZD_REGDOMAIN_JAPAN_ADD, "JP" },
+	{ ZD_REGDOMAIN_SPAIN, "ES" },
+	{ ZD_REGDOMAIN_FRANCE, "FR" },
+};
+
 /* This table contains the hardware specific values for the modulation rates. */
 static const struct ieee80211_rate zd_rates[] = {
 	{ .bitrate = 10,
@@ -95,6 +109,21 @@
 static void housekeeping_enable(struct zd_mac *mac);
 static void housekeeping_disable(struct zd_mac *mac);
 
+static int zd_reg2alpha2(u8 regdomain, char *alpha2)
+{
+	unsigned int i;
+	struct zd_reg_alpha2_map *reg_map;
+	for (i = 0; i < ARRAY_SIZE(reg_alpha2_map); i++) {
+		reg_map = &reg_alpha2_map[i];
+		if (regdomain == reg_map->reg) {
+			alpha2[0] = reg_map->alpha2[0];
+			alpha2[1] = reg_map->alpha2[1];
+			return 0;
+		}
+	}
+	return 1;
+}
+
 int zd_mac_preinit_hw(struct ieee80211_hw *hw)
 {
 	int r;
@@ -115,6 +144,7 @@
 	int r;
 	struct zd_mac *mac = zd_hw_mac(hw);
 	struct zd_chip *chip = &mac->chip;
+	char alpha2[2];
 	u8 default_regdomain;
 
 	r = zd_chip_enable_int(chip);
@@ -139,7 +169,9 @@
 	if (r)
 		goto disable_int;
 
-	zd_geo_init(hw, mac->regdomain);
+	r = zd_reg2alpha2(mac->regdomain, alpha2);
+	if (!r)
+		regulatory_hint(hw->wiphy, alpha2, NULL);
 
 	r = 0;
 disable_int:
@@ -579,7 +611,7 @@
 
 	q = &zd_hw_mac(hw)->ack_wait_queue;
 	spin_lock_irqsave(&q->lock, flags);
-	for (skb = q->next; skb != (struct sk_buff *)q; skb = skb->next) {
+	skb_queue_walk(q, skb) {
 		struct ieee80211_hdr *tx_hdr;
 
 		tx_hdr = (struct ieee80211_hdr *)skb->data;
@@ -684,15 +716,15 @@
 {
 	struct zd_mac *mac = zd_hw_mac(hw);
 
-	/* using IEEE80211_IF_TYPE_INVALID to indicate no mode selected */
-	if (mac->type != IEEE80211_IF_TYPE_INVALID)
+	/* using NL80211_IFTYPE_UNSPECIFIED to indicate no mode selected */
+	if (mac->type != NL80211_IFTYPE_UNSPECIFIED)
 		return -EOPNOTSUPP;
 
 	switch (conf->type) {
-	case IEEE80211_IF_TYPE_MNTR:
-	case IEEE80211_IF_TYPE_MESH_POINT:
-	case IEEE80211_IF_TYPE_STA:
-	case IEEE80211_IF_TYPE_IBSS:
+	case NL80211_IFTYPE_MONITOR:
+	case NL80211_IFTYPE_MESH_POINT:
+	case NL80211_IFTYPE_STATION:
+	case NL80211_IFTYPE_ADHOC:
 		mac->type = conf->type;
 		break;
 	default:
@@ -706,7 +738,7 @@
 				    struct ieee80211_if_init_conf *conf)
 {
 	struct zd_mac *mac = zd_hw_mac(hw);
-	mac->type = IEEE80211_IF_TYPE_INVALID;
+	mac->type = NL80211_IFTYPE_UNSPECIFIED;
 	zd_set_beacon_interval(&mac->chip, 0);
 	zd_write_mac_addr(&mac->chip, NULL);
 }
@@ -725,8 +757,8 @@
 	int associated;
 	int r;
 
-	if (mac->type == IEEE80211_IF_TYPE_MESH_POINT ||
-	    mac->type == IEEE80211_IF_TYPE_IBSS) {
+	if (mac->type == NL80211_IFTYPE_MESH_POINT ||
+	    mac->type == NL80211_IFTYPE_ADHOC) {
 		associated = true;
 		if (conf->changed & IEEE80211_IFCC_BEACON) {
 			struct sk_buff *beacon = ieee80211_beacon_get(hw, vif);
@@ -753,7 +785,7 @@
 	return 0;
 }
 
-void zd_process_intr(struct work_struct *work)
+static void zd_process_intr(struct work_struct *work)
 {
 	u16 int_status;
 	struct zd_mac *mac = container_of(work, struct zd_mac, process_intr);
@@ -923,7 +955,7 @@
 	spin_lock_init(&mac->lock);
 	mac->hw = hw;
 
-	mac->type = IEEE80211_IF_TYPE_INVALID;
+	mac->type = NL80211_IFTYPE_UNSPECIFIED;
 
 	memcpy(mac->channels, zd_channels, sizeof(zd_channels));
 	memcpy(mac->rates, zd_rates, sizeof(zd_rates));
@@ -937,6 +969,11 @@
 	hw->flags = IEEE80211_HW_RX_INCLUDES_FCS |
 		    IEEE80211_HW_SIGNAL_DB;
 
+	hw->wiphy->interface_modes =
+		BIT(NL80211_IFTYPE_MESH_POINT) |
+		BIT(NL80211_IFTYPE_STATION) |
+		BIT(NL80211_IFTYPE_ADHOC);
+
 	hw->max_signal = 100;
 	hw->queues = 1;
 	hw->extra_tx_headroom = sizeof(struct zd_ctrlset);
diff --git a/drivers/net/wireless/zd1211rw/zd_mac.h b/drivers/net/wireless/zd1211rw/zd_mac.h
index 18c1d56..4c05d3e 100644
--- a/drivers/net/wireless/zd1211rw/zd_mac.h
+++ b/drivers/net/wireless/zd1211rw/zd_mac.h
@@ -25,7 +25,6 @@
 #include <net/mac80211.h>
 
 #include "zd_chip.h"
-#include "zd_ieee80211.h"
 
 struct zd_ctrlset {
 	u8     modulation;
@@ -187,6 +186,70 @@
 	unsigned int pass_ctrl:1;
 };
 
+#define ZD_REGDOMAIN_FCC	0x10
+#define ZD_REGDOMAIN_IC		0x20
+#define ZD_REGDOMAIN_ETSI	0x30
+#define ZD_REGDOMAIN_SPAIN	0x31
+#define ZD_REGDOMAIN_FRANCE	0x32
+#define ZD_REGDOMAIN_JAPAN_ADD	0x40
+#define ZD_REGDOMAIN_JAPAN	0x41
+
+enum {
+	MIN_CHANNEL24 = 1,
+	MAX_CHANNEL24 = 14,
+};
+
+#define ZD_PLCP_SERVICE_LENGTH_EXTENSION 0x80
+
+struct ofdm_plcp_header {
+	u8 prefix[3];
+	__le16 service;
+} __attribute__((packed));
+
+static inline u8 zd_ofdm_plcp_header_rate(const struct ofdm_plcp_header *header)
+{
+	return header->prefix[0] & 0xf;
+}
+
+/* The following defines give the encoding of the 4-bit rate field in the
+ * OFDM (802.11a/802.11g) PLCP header. Notify that these values are used to
+ * define the zd-rate values for OFDM.
+ *
+ * See the struct zd_ctrlset definition in zd_mac.h.
+ */
+#define ZD_OFDM_PLCP_RATE_6M	0xb
+#define ZD_OFDM_PLCP_RATE_9M	0xf
+#define ZD_OFDM_PLCP_RATE_12M	0xa
+#define ZD_OFDM_PLCP_RATE_18M	0xe
+#define ZD_OFDM_PLCP_RATE_24M	0x9
+#define ZD_OFDM_PLCP_RATE_36M	0xd
+#define ZD_OFDM_PLCP_RATE_48M	0x8
+#define ZD_OFDM_PLCP_RATE_54M	0xc
+
+struct cck_plcp_header {
+	u8 signal;
+	u8 service;
+	__le16 length;
+	__le16 crc16;
+} __attribute__((packed));
+
+static inline u8 zd_cck_plcp_header_signal(const struct cck_plcp_header *header)
+{
+	return header->signal;
+}
+
+/* These defines give the encodings of the signal field in the 802.11b PLCP
+ * header. The signal field gives the bit rate of the following packet. Even
+ * if technically wrong we use CCK here also for the 1 MBit/s and 2 MBit/s
+ * rate to stay consistent with Zydas and our use of the term.
+ *
+ * Notify that these values are *not* used in the zd-rates.
+ */
+#define ZD_CCK_PLCP_SIGNAL_1M	0x0a
+#define ZD_CCK_PLCP_SIGNAL_2M	0x14
+#define ZD_CCK_PLCP_SIGNAL_5M5	0x37
+#define ZD_CCK_PLCP_SIGNAL_11M	0x6e
+
 static inline struct zd_mac *zd_hw_mac(struct ieee80211_hw *hw)
 {
 	return hw->priv;
diff --git a/drivers/net/wireless/zd1211rw/zd_rf.c b/drivers/net/wireless/zd1211rw/zd_rf.c
index ec41293..7207bfd 100644
--- a/drivers/net/wireless/zd1211rw/zd_rf.c
+++ b/drivers/net/wireless/zd1211rw/zd_rf.c
@@ -23,7 +23,7 @@
 
 #include "zd_def.h"
 #include "zd_rf.h"
-#include "zd_ieee80211.h"
+#include "zd_mac.h"
 #include "zd_chip.h"
 
 static const char * const rfs[] = {
diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c
index da8b743..a60ae86 100644
--- a/drivers/net/wireless/zd1211rw/zd_usb.c
+++ b/drivers/net/wireless/zd1211rw/zd_usb.c
@@ -58,6 +58,7 @@
 	{ USB_DEVICE(0x0586, 0x3407), .driver_info = DEVICE_ZD1211 },
 	{ USB_DEVICE(0x129b, 0x1666), .driver_info = DEVICE_ZD1211 },
 	{ USB_DEVICE(0x157e, 0x300a), .driver_info = DEVICE_ZD1211 },
+	{ USB_DEVICE(0x0105, 0x145f), .driver_info = DEVICE_ZD1211 },
 	/* ZD1211B */
 	{ USB_DEVICE(0x0ace, 0x1215), .driver_info = DEVICE_ZD1211B },
 	{ USB_DEVICE(0x157e, 0x300d), .driver_info = DEVICE_ZD1211B },
diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c
index c749bdb..3c3dd40 100644
--- a/drivers/net/xen-netfront.c
+++ b/drivers/net/xen-netfront.c
@@ -1794,10 +1794,10 @@
 
 static int __init netif_init(void)
 {
-	if (!is_running_on_xen())
+	if (!xen_domain())
 		return -ENODEV;
 
-	if (is_initial_xendomain())
+	if (xen_initial_domain())
 		return 0;
 
 	printk(KERN_INFO "Initialising Xen virtual ethernet driver.\n");
@@ -1809,7 +1809,7 @@
 
 static void __exit netif_exit(void)
 {
-	if (is_initial_xendomain())
+	if (xen_initial_domain())
 		return;
 
 	xenbus_unregister_driver(&netfront);
diff --git a/drivers/oprofile/buffer_sync.c b/drivers/oprofile/buffer_sync.c
index 9304c45..ed98227 100644
--- a/drivers/oprofile/buffer_sync.c
+++ b/drivers/oprofile/buffer_sync.c
@@ -5,6 +5,7 @@
  * @remark Read the file COPYING
  *
  * @author John Levon <levon@movementarian.org>
+ * @author Barry Kasindorf
  *
  * This is the core of the buffer management. Each
  * CPU buffer is processed and entered into the
@@ -33,7 +34,7 @@
 #include "event_buffer.h"
 #include "cpu_buffer.h"
 #include "buffer_sync.h"
- 
+
 static LIST_HEAD(dying_tasks);
 static LIST_HEAD(dead_tasks);
 static cpumask_t marked_cpus = CPU_MASK_NONE;
@@ -48,10 +49,11 @@
  * Can be invoked from softirq via RCU callback due to
  * call_rcu() of the task struct, hence the _irqsave.
  */
-static int task_free_notify(struct notifier_block * self, unsigned long val, void * data)
+static int
+task_free_notify(struct notifier_block *self, unsigned long val, void *data)
 {
 	unsigned long flags;
-	struct task_struct * task = data;
+	struct task_struct *task = data;
 	spin_lock_irqsave(&task_mortuary, flags);
 	list_add(&task->tasks, &dying_tasks);
 	spin_unlock_irqrestore(&task_mortuary, flags);
@@ -62,13 +64,14 @@
 /* The task is on its way out. A sync of the buffer means we can catch
  * any remaining samples for this task.
  */
-static int task_exit_notify(struct notifier_block * self, unsigned long val, void * data)
+static int
+task_exit_notify(struct notifier_block *self, unsigned long val, void *data)
 {
 	/* To avoid latency problems, we only process the current CPU,
 	 * hoping that most samples for the task are on this CPU
 	 */
 	sync_buffer(raw_smp_processor_id());
-  	return 0;
+	return 0;
 }
 
 
@@ -77,11 +80,12 @@
  * we don't lose any. This does not have to be exact, it's a QoI issue
  * only.
  */
-static int munmap_notify(struct notifier_block * self, unsigned long val, void * data)
+static int
+munmap_notify(struct notifier_block *self, unsigned long val, void *data)
 {
 	unsigned long addr = (unsigned long)data;
-	struct mm_struct * mm = current->mm;
-	struct vm_area_struct * mpnt;
+	struct mm_struct *mm = current->mm;
+	struct vm_area_struct *mpnt;
 
 	down_read(&mm->mmap_sem);
 
@@ -99,11 +103,12 @@
 	return 0;
 }
 
- 
+
 /* We need to be told about new modules so we don't attribute to a previously
  * loaded module, or drop the samples on the floor.
  */
-static int module_load_notify(struct notifier_block * self, unsigned long val, void * data)
+static int
+module_load_notify(struct notifier_block *self, unsigned long val, void *data)
 {
 #ifdef CONFIG_MODULES
 	if (val != MODULE_STATE_COMING)
@@ -118,7 +123,7 @@
 	return 0;
 }
 
- 
+
 static struct notifier_block task_free_nb = {
 	.notifier_call	= task_free_notify,
 };
@@ -135,7 +140,7 @@
 	.notifier_call = module_load_notify,
 };
 
- 
+
 static void end_sync(void)
 {
 	end_cpu_work();
@@ -208,14 +213,14 @@
  * not strictly necessary but allows oprofile to associate
  * shared-library samples with particular applications
  */
-static unsigned long get_exec_dcookie(struct mm_struct * mm)
+static unsigned long get_exec_dcookie(struct mm_struct *mm)
 {
 	unsigned long cookie = NO_COOKIE;
-	struct vm_area_struct * vma;
- 
+	struct vm_area_struct *vma;
+
 	if (!mm)
 		goto out;
- 
+
 	for (vma = mm->mmap; vma; vma = vma->vm_next) {
 		if (!vma->vm_file)
 			continue;
@@ -235,13 +240,14 @@
  * sure to do this lookup before a mm->mmap modification happens so
  * we don't lose track.
  */
-static unsigned long lookup_dcookie(struct mm_struct * mm, unsigned long addr, off_t * offset)
+static unsigned long
+lookup_dcookie(struct mm_struct *mm, unsigned long addr, off_t *offset)
 {
 	unsigned long cookie = NO_COOKIE;
-	struct vm_area_struct * vma;
+	struct vm_area_struct *vma;
 
 	for (vma = find_vma(mm, addr); vma; vma = vma->vm_next) {
- 
+
 		if (addr < vma->vm_start || addr >= vma->vm_end)
 			continue;
 
@@ -263,9 +269,20 @@
 	return cookie;
 }
 
+static void increment_tail(struct oprofile_cpu_buffer *b)
+{
+	unsigned long new_tail = b->tail_pos + 1;
+
+	rmb();	/* be sure fifo pointers are synchromized */
+
+	if (new_tail < b->buffer_size)
+		b->tail_pos = new_tail;
+	else
+		b->tail_pos = 0;
+}
 
 static unsigned long last_cookie = INVALID_COOKIE;
- 
+
 static void add_cpu_switch(int i)
 {
 	add_event_entry(ESCAPE_CODE);
@@ -278,16 +295,16 @@
 {
 	add_event_entry(ESCAPE_CODE);
 	if (in_kernel)
-		add_event_entry(KERNEL_ENTER_SWITCH_CODE); 
+		add_event_entry(KERNEL_ENTER_SWITCH_CODE);
 	else
-		add_event_entry(KERNEL_EXIT_SWITCH_CODE); 
+		add_event_entry(KERNEL_EXIT_SWITCH_CODE);
 }
- 
+
 static void
-add_user_ctx_switch(struct task_struct const * task, unsigned long cookie)
+add_user_ctx_switch(struct task_struct const *task, unsigned long cookie)
 {
 	add_event_entry(ESCAPE_CODE);
-	add_event_entry(CTX_SWITCH_CODE); 
+	add_event_entry(CTX_SWITCH_CODE);
 	add_event_entry(task->pid);
 	add_event_entry(cookie);
 	/* Another code for daemon back-compat */
@@ -296,7 +313,7 @@
 	add_event_entry(task->tgid);
 }
 
- 
+
 static void add_cookie_switch(unsigned long cookie)
 {
 	add_event_entry(ESCAPE_CODE);
@@ -304,13 +321,78 @@
 	add_event_entry(cookie);
 }
 
- 
+
 static void add_trace_begin(void)
 {
 	add_event_entry(ESCAPE_CODE);
 	add_event_entry(TRACE_BEGIN_CODE);
 }
 
+#ifdef CONFIG_OPROFILE_IBS
+
+#define IBS_FETCH_CODE_SIZE	2
+#define IBS_OP_CODE_SIZE	5
+#define IBS_EIP(offset)				\
+	(((struct op_sample *)&cpu_buf->buffer[(offset)])->eip)
+#define IBS_EVENT(offset)				\
+	(((struct op_sample *)&cpu_buf->buffer[(offset)])->event)
+
+/*
+ * Add IBS fetch and op entries to event buffer
+ */
+static void add_ibs_begin(struct oprofile_cpu_buffer *cpu_buf, int code,
+	int in_kernel, struct mm_struct *mm)
+{
+	unsigned long rip;
+	int i, count;
+	unsigned long ibs_cookie = 0;
+	off_t offset;
+
+	increment_tail(cpu_buf);	/* move to RIP entry */
+
+	rip = IBS_EIP(cpu_buf->tail_pos);
+
+#ifdef __LP64__
+	rip += IBS_EVENT(cpu_buf->tail_pos) << 32;
+#endif
+
+	if (mm) {
+		ibs_cookie = lookup_dcookie(mm, rip, &offset);
+
+		if (ibs_cookie == NO_COOKIE)
+			offset = rip;
+		if (ibs_cookie == INVALID_COOKIE) {
+			atomic_inc(&oprofile_stats.sample_lost_no_mapping);
+			offset = rip;
+		}
+		if (ibs_cookie != last_cookie) {
+			add_cookie_switch(ibs_cookie);
+			last_cookie = ibs_cookie;
+		}
+	} else
+		offset = rip;
+
+	add_event_entry(ESCAPE_CODE);
+	add_event_entry(code);
+	add_event_entry(offset);	/* Offset from Dcookie */
+
+	/* we send the Dcookie offset, but send the raw Linear Add also*/
+	add_event_entry(IBS_EIP(cpu_buf->tail_pos));
+	add_event_entry(IBS_EVENT(cpu_buf->tail_pos));
+
+	if (code == IBS_FETCH_CODE)
+		count = IBS_FETCH_CODE_SIZE;	/*IBS FETCH is 2 int64s*/
+	else
+		count = IBS_OP_CODE_SIZE;	/*IBS OP is 5 int64s*/
+
+	for (i = 0; i < count; i++) {
+		increment_tail(cpu_buf);
+		add_event_entry(IBS_EIP(cpu_buf->tail_pos));
+		add_event_entry(IBS_EVENT(cpu_buf->tail_pos));
+	}
+}
+
+#endif
 
 static void add_sample_entry(unsigned long offset, unsigned long event)
 {
@@ -319,13 +401,13 @@
 }
 
 
-static int add_us_sample(struct mm_struct * mm, struct op_sample * s)
+static int add_us_sample(struct mm_struct *mm, struct op_sample *s)
 {
 	unsigned long cookie;
 	off_t offset;
- 
- 	cookie = lookup_dcookie(mm, s->eip, &offset);
- 
+
+	cookie = lookup_dcookie(mm, s->eip, &offset);
+
 	if (cookie == INVALID_COOKIE) {
 		atomic_inc(&oprofile_stats.sample_lost_no_mapping);
 		return 0;
@@ -341,13 +423,13 @@
 	return 1;
 }
 
- 
+
 /* Add a sample to the global event buffer. If possible the
  * sample is converted into a persistent dentry/offset pair
  * for later lookup from userspace.
  */
 static int
-add_sample(struct mm_struct * mm, struct op_sample * s, int in_kernel)
+add_sample(struct mm_struct *mm, struct op_sample *s, int in_kernel)
 {
 	if (in_kernel) {
 		add_sample_entry(s->eip, s->event);
@@ -359,9 +441,9 @@
 	}
 	return 0;
 }
- 
 
-static void release_mm(struct mm_struct * mm)
+
+static void release_mm(struct mm_struct *mm)
 {
 	if (!mm)
 		return;
@@ -370,9 +452,9 @@
 }
 
 
-static struct mm_struct * take_tasks_mm(struct task_struct * task)
+static struct mm_struct *take_tasks_mm(struct task_struct *task)
 {
-	struct mm_struct * mm = get_task_mm(task);
+	struct mm_struct *mm = get_task_mm(task);
 	if (mm)
 		down_read(&mm->mmap_sem);
 	return mm;
@@ -383,10 +465,10 @@
 {
 	return val == ESCAPE_CODE;
 }
- 
+
 
 /* "acquire" as many cpu buffer slots as we can */
-static unsigned long get_slots(struct oprofile_cpu_buffer * b)
+static unsigned long get_slots(struct oprofile_cpu_buffer *b)
 {
 	unsigned long head = b->head_pos;
 	unsigned long tail = b->tail_pos;
@@ -412,19 +494,6 @@
 }
 
 
-static void increment_tail(struct oprofile_cpu_buffer * b)
-{
-	unsigned long new_tail = b->tail_pos + 1;
-
-	rmb();
-
-	if (new_tail < b->buffer_size)
-		b->tail_pos = new_tail;
-	else
-		b->tail_pos = 0;
-}
-
-
 /* Move tasks along towards death. Any tasks on dead_tasks
  * will definitely have no remaining references in any
  * CPU buffers at this point, because we use two lists,
@@ -435,8 +504,8 @@
 {
 	unsigned long flags;
 	LIST_HEAD(local_dead_tasks);
-	struct task_struct * task;
-	struct task_struct * ttask;
+	struct task_struct *task;
+	struct task_struct *ttask;
 
 	spin_lock_irqsave(&task_mortuary, flags);
 
@@ -493,7 +562,7 @@
 {
 	struct oprofile_cpu_buffer *cpu_buf = &per_cpu(cpu_buffer, cpu);
 	struct mm_struct *mm = NULL;
-	struct task_struct * new;
+	struct task_struct *new;
 	unsigned long cookie = 0;
 	int in_kernel = 1;
 	unsigned int i;
@@ -501,7 +570,7 @@
 	unsigned long available;
 
 	mutex_lock(&buffer_mutex);
- 
+
 	add_cpu_switch(cpu);
 
 	/* Remember, only we can modify tail_pos */
@@ -509,8 +578,8 @@
 	available = get_slots(cpu_buf);
 
 	for (i = 0; i < available; ++i) {
-		struct op_sample * s = &cpu_buf->buffer[cpu_buf->tail_pos];
- 
+		struct op_sample *s = &cpu_buf->buffer[cpu_buf->tail_pos];
+
 		if (is_code(s->eip)) {
 			if (s->event <= CPU_IS_KERNEL) {
 				/* kernel/userspace switch */
@@ -521,8 +590,18 @@
 			} else if (s->event == CPU_TRACE_BEGIN) {
 				state = sb_bt_start;
 				add_trace_begin();
+#ifdef CONFIG_OPROFILE_IBS
+			} else if (s->event == IBS_FETCH_BEGIN) {
+				state = sb_bt_start;
+				add_ibs_begin(cpu_buf,
+					IBS_FETCH_CODE, in_kernel, mm);
+			} else if (s->event == IBS_OP_BEGIN) {
+				state = sb_bt_start;
+				add_ibs_begin(cpu_buf,
+					IBS_OP_CODE, in_kernel, mm);
+#endif
 			} else {
-				struct mm_struct * oldmm = mm;
+				struct mm_struct *oldmm = mm;
 
 				/* userspace context switch */
 				new = (struct task_struct *)s->event;
@@ -533,13 +612,11 @@
 					cookie = get_exec_dcookie(mm);
 				add_user_ctx_switch(new, cookie);
 			}
-		} else {
-			if (state >= sb_bt_start &&
-			    !add_sample(mm, s, in_kernel)) {
-				if (state == sb_bt_start) {
-					state = sb_bt_ignore;
-					atomic_inc(&oprofile_stats.bt_lost_no_mapping);
-				}
+		} else if (state >= sb_bt_start &&
+			   !add_sample(mm, s, in_kernel)) {
+			if (state == sb_bt_start) {
+				state = sb_bt_ignore;
+				atomic_inc(&oprofile_stats.bt_lost_no_mapping);
 			}
 		}
 
diff --git a/drivers/oprofile/cpu_buffer.c b/drivers/oprofile/cpu_buffer.c
index 7ba78e6..e1bd5a9 100644
--- a/drivers/oprofile/cpu_buffer.c
+++ b/drivers/oprofile/cpu_buffer.c
@@ -5,6 +5,7 @@
  * @remark Read the file COPYING
  *
  * @author John Levon <levon@movementarian.org>
+ * @author Barry Kasindorf <barry.kasindorf@amd.com>
  *
  * Each CPU has a local buffer that stores PC value/event
  * pairs. We also log context switches when we notice them.
@@ -209,7 +210,7 @@
 	return 1;
 }
 
-static int oprofile_begin_trace(struct oprofile_cpu_buffer * cpu_buf)
+static int oprofile_begin_trace(struct oprofile_cpu_buffer *cpu_buf)
 {
 	if (nr_available_slots(cpu_buf) < 4) {
 		cpu_buf->sample_lost_overflow++;
@@ -254,6 +255,75 @@
 	oprofile_add_ext_sample(pc, regs, event, is_kernel);
 }
 
+#ifdef CONFIG_OPROFILE_IBS
+
+#define MAX_IBS_SAMPLE_SIZE	14
+static int log_ibs_sample(struct oprofile_cpu_buffer *cpu_buf,
+	unsigned long pc, int is_kernel, unsigned  int *ibs, int ibs_code)
+{
+	struct task_struct *task;
+
+	cpu_buf->sample_received++;
+
+	if (nr_available_slots(cpu_buf) < MAX_IBS_SAMPLE_SIZE) {
+		cpu_buf->sample_lost_overflow++;
+		return 0;
+	}
+
+	is_kernel = !!is_kernel;
+
+	/* notice a switch from user->kernel or vice versa */
+	if (cpu_buf->last_is_kernel != is_kernel) {
+		cpu_buf->last_is_kernel = is_kernel;
+		add_code(cpu_buf, is_kernel);
+	}
+
+	/* notice a task switch */
+	if (!is_kernel) {
+		task = current;
+
+		if (cpu_buf->last_task != task) {
+			cpu_buf->last_task = task;
+			add_code(cpu_buf, (unsigned long)task);
+		}
+	}
+
+	add_code(cpu_buf, ibs_code);
+	add_sample(cpu_buf, ibs[0], ibs[1]);
+	add_sample(cpu_buf, ibs[2], ibs[3]);
+	add_sample(cpu_buf, ibs[4], ibs[5]);
+
+	if (ibs_code == IBS_OP_BEGIN) {
+	add_sample(cpu_buf, ibs[6], ibs[7]);
+	add_sample(cpu_buf, ibs[8], ibs[9]);
+	add_sample(cpu_buf, ibs[10], ibs[11]);
+	}
+
+	return 1;
+}
+
+void oprofile_add_ibs_sample(struct pt_regs *const regs,
+				unsigned int * const ibs_sample, u8 code)
+{
+	int is_kernel = !user_mode(regs);
+	unsigned long pc = profile_pc(regs);
+
+	struct oprofile_cpu_buffer *cpu_buf =
+			 &per_cpu(cpu_buffer, smp_processor_id());
+
+	if (!backtrace_depth) {
+		log_ibs_sample(cpu_buf, pc, is_kernel, ibs_sample, code);
+		return;
+	}
+
+	/* if log_sample() fails we can't backtrace since we lost the source
+	* of this event */
+	if (log_ibs_sample(cpu_buf, pc, is_kernel, ibs_sample, code))
+		oprofile_ops.backtrace(regs, backtrace_depth);
+}
+
+#endif
+
 void oprofile_add_pc(unsigned long pc, int is_kernel, unsigned long event)
 {
 	struct oprofile_cpu_buffer *cpu_buf = &__get_cpu_var(cpu_buffer);
@@ -296,7 +366,7 @@
 	struct oprofile_cpu_buffer * b =
 		container_of(work, struct oprofile_cpu_buffer, work.work);
 	if (b->cpu != smp_processor_id()) {
-		printk("WQ on CPU%d, prefer CPU%d\n",
+		printk(KERN_DEBUG "WQ on CPU%d, prefer CPU%d\n",
 		       smp_processor_id(), b->cpu);
 	}
 	sync_buffer(b->cpu);
diff --git a/drivers/oprofile/cpu_buffer.h b/drivers/oprofile/cpu_buffer.h
index c3e366b..9c44d00 100644
--- a/drivers/oprofile/cpu_buffer.h
+++ b/drivers/oprofile/cpu_buffer.h
@@ -55,5 +55,7 @@
 /* transient events for the CPU buffer -> event buffer */
 #define CPU_IS_KERNEL 1
 #define CPU_TRACE_BEGIN 2
+#define IBS_FETCH_BEGIN 3
+#define IBS_OP_BEGIN    4
 
 #endif /* OPROFILE_CPU_BUFFER_H */
diff --git a/drivers/parport/parport_cs.c b/drivers/parport/parport_cs.c
index 00e1d96..b1899e9 100644
--- a/drivers/parport/parport_cs.c
+++ b/drivers/parport/parport_cs.c
@@ -149,52 +149,44 @@
 #define CS_CHECK(fn, ret) \
 do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)
 
+static int parport_config_check(struct pcmcia_device *p_dev,
+				cistpl_cftable_entry_t *cfg,
+				cistpl_cftable_entry_t *dflt,
+				unsigned int vcc,
+				void *priv_data)
+{
+	if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) {
+		cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io;
+		if (epp_mode)
+			p_dev->conf.ConfigIndex |= FORCE_EPP_MODE;
+		p_dev->io.BasePort1 = io->win[0].base;
+		p_dev->io.NumPorts1 = io->win[0].len;
+		p_dev->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK;
+		if (io->nwin == 2) {
+			p_dev->io.BasePort2 = io->win[1].base;
+			p_dev->io.NumPorts2 = io->win[1].len;
+		}
+		if (pcmcia_request_io(p_dev, &p_dev->io) != 0)
+			return -ENODEV;
+		return 0;
+	}
+	return -ENODEV;
+}
+
 static int parport_config(struct pcmcia_device *link)
 {
     parport_info_t *info = link->priv;
-    tuple_t tuple;
-    u_short buf[128];
-    cisparse_t parse;
-    cistpl_cftable_entry_t *cfg = &parse.cftable_entry;
-    cistpl_cftable_entry_t dflt = { 0 };
     struct parport *p;
     int last_ret, last_fn;
-    
-    DEBUG(0, "parport_config(0x%p)\n", link);
-    
-    tuple.TupleData = (cisdata_t *)buf;
-    tuple.TupleOffset = 0; tuple.TupleDataMax = 255;
-    tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
-    tuple.Attributes = 0;
-    CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple));
-    while (1) {
-	if (pcmcia_get_tuple_data(link, &tuple) != 0 ||
-		pcmcia_parse_tuple(link, &tuple, &parse) != 0)
-	    goto next_entry;
 
-	if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) {
-	    cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt.io;
-	    link->conf.ConfigIndex = cfg->index;
-	    if (epp_mode)
-		link->conf.ConfigIndex |= FORCE_EPP_MODE;
-	    link->io.BasePort1 = io->win[0].base;
-	    link->io.NumPorts1 = io->win[0].len;
-	    link->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK;
-	    if (io->nwin == 2) {
-		link->io.BasePort2 = io->win[1].base;
-		link->io.NumPorts2 = io->win[1].len;
-	    }
-	    if (pcmcia_request_io(link, &link->io) != 0)
-		goto next_entry;
-	    /* If we've got this far, we're done */
-	    break;
-	}
-	
-    next_entry:
-	if (cfg->flags & CISTPL_CFTABLE_DEFAULT) dflt = *cfg;
-	CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(link, &tuple));
+    DEBUG(0, "parport_config(0x%p)\n", link);
+
+    last_ret = pcmcia_loop_config(link, parport_config_check, NULL);
+    if (last_ret) {
+	    cs_error(link, RequestIO, last_ret);
+	    goto failed;
     }
-    
+
     CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq));
     CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf));
 
diff --git a/drivers/parport/parport_sunbpp.c b/drivers/parport/parport_sunbpp.c
index 9d595aa..065f229 100644
--- a/drivers/parport/parport_sunbpp.c
+++ b/drivers/parport/parport_sunbpp.c
@@ -26,6 +26,8 @@
 #include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/init.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 
 #include <linux/parport.h>
 
@@ -34,7 +36,6 @@
 
 #include <asm/io.h>
 #include <asm/oplib.h>           /* OpenProm Library */
-#include <asm/sbus.h>
 #include <asm/dma.h>             /* BPP uses LSI 64854 for DMA */
 #include <asm/irq.h>
 #include <asm/sunbpp.h>
@@ -285,38 +286,37 @@
 	.owner		= THIS_MODULE,
 };
 
-static int __devinit init_one_port(struct sbus_dev *sdev)
+static int __devinit bpp_probe(struct of_device *op, const struct of_device_id *match)
 {
-	struct parport *p;
-	/* at least in theory there may be a "we don't dma" case */
 	struct parport_operations *ops;
-	void __iomem *base;
-	int irq, dma, err = 0, size;
 	struct bpp_regs __iomem *regs;
+	int irq, dma, err = 0, size;
 	unsigned char value_tcr;
+	void __iomem *base;
+	struct parport *p;
 
-	irq = sdev->irqs[0];
-	base = sbus_ioremap(&sdev->resource[0], 0,
-			    sdev->reg_addrs[0].reg_size, 
-			    "sunbpp");
+	irq = op->irqs[0];
+	base = of_ioremap(&op->resource[0], 0,
+			  resource_size(&op->resource[0]),
+			  "sunbpp");
 	if (!base)
 		return -ENODEV;
 
-	size = sdev->reg_addrs[0].reg_size;
+	size = resource_size(&op->resource[0]);
 	dma = PARPORT_DMA_NONE;
 
 	ops = kmalloc(sizeof(struct parport_operations), GFP_KERNEL);
         if (!ops)
 		goto out_unmap;
 
-        memcpy (ops, &parport_sunbpp_ops, sizeof (struct parport_operations));
+        memcpy (ops, &parport_sunbpp_ops, sizeof(struct parport_operations));
 
 	dprintk(("register_port\n"));
 	if (!(p = parport_register_port((unsigned long)base, irq, dma, ops)))
 		goto out_free_ops;
 
 	p->size = size;
-	p->dev = &sdev->ofdev.dev;
+	p->dev = &op->dev;
 
 	if ((err = request_irq(p->irq, parport_irq_handler,
 			       IRQF_SHARED, p->name, p)) != 0) {
@@ -333,7 +333,7 @@
 
 	printk(KERN_INFO "%s: sunbpp at 0x%lx\n", p->name, p->base);
 
-	dev_set_drvdata(&sdev->ofdev.dev, p);
+	dev_set_drvdata(&op->dev, p);
 
 	parport_announce_port(p);
 
@@ -346,21 +346,14 @@
 	kfree(ops);
 
 out_unmap:
-	sbus_iounmap(base, size);
+	of_iounmap(&op->resource[0], base, size);
 
 	return err;
 }
 
-static int __devinit bpp_probe(struct of_device *dev, const struct of_device_id *match)
+static int __devexit bpp_remove(struct of_device *op)
 {
-	struct sbus_dev *sdev = to_sbus_device(&dev->dev);
-
-	return init_one_port(sdev);
-}
-
-static int __devexit bpp_remove(struct of_device *dev)
-{
-	struct parport *p = dev_get_drvdata(&dev->dev);
+	struct parport *p = dev_get_drvdata(&op->dev);
 	struct parport_operations *ops = p->ops;
 
 	parport_remove_port(p);
@@ -370,16 +363,16 @@
 		free_irq(p->irq, p);
 	}
 
-	sbus_iounmap((void __iomem *) p->base, p->size);
+	of_iounmap(&op->resource[0], (void __iomem *) p->base, p->size);
 	parport_put_port(p);
 	kfree(ops);
 
-	dev_set_drvdata(&dev->dev, NULL);
+	dev_set_drvdata(&op->dev, NULL);
 
 	return 0;
 }
 
-static struct of_device_id bpp_match[] = {
+static const struct of_device_id bpp_match[] = {
 	{
 		.name = "SUNW,bpp",
 	},
@@ -397,7 +390,7 @@
 
 static int __init parport_sunbpp_init(void)
 {
-	return of_register_driver(&bpp_sbus_driver, &sbus_bus_type);
+	return of_register_driver(&bpp_sbus_driver, &of_bus_type);
 }
 
 static void __exit parport_sunbpp_exit(void)
diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile
index 7d63f8c..4b47f4e 100644
--- a/drivers/pci/Makefile
+++ b/drivers/pci/Makefile
@@ -26,6 +26,8 @@
 # Build Intel IOMMU support
 obj-$(CONFIG_DMAR) += dmar.o iova.o intel-iommu.o
 
+obj-$(CONFIG_INTR_REMAP) += dmar.o intr_remapping.o
+
 #
 # Some architectures use the generic PCI setup functions
 #
diff --git a/drivers/pci/dma_remapping.h b/drivers/pci/dma_remapping.h
new file mode 100644
index 0000000..bff5c65
--- /dev/null
+++ b/drivers/pci/dma_remapping.h
@@ -0,0 +1,157 @@
+#ifndef _DMA_REMAPPING_H
+#define _DMA_REMAPPING_H
+
+/*
+ * We need a fixed PAGE_SIZE of 4K irrespective of
+ * arch PAGE_SIZE for IOMMU page tables.
+ */
+#define PAGE_SHIFT_4K		(12)
+#define PAGE_SIZE_4K		(1UL << PAGE_SHIFT_4K)
+#define PAGE_MASK_4K		(((u64)-1) << PAGE_SHIFT_4K)
+#define PAGE_ALIGN_4K(addr)	(((addr) + PAGE_SIZE_4K - 1) & PAGE_MASK_4K)
+
+#define IOVA_PFN(addr)		((addr) >> PAGE_SHIFT_4K)
+#define DMA_32BIT_PFN		IOVA_PFN(DMA_32BIT_MASK)
+#define DMA_64BIT_PFN		IOVA_PFN(DMA_64BIT_MASK)
+
+
+/*
+ * 0: Present
+ * 1-11: Reserved
+ * 12-63: Context Ptr (12 - (haw-1))
+ * 64-127: Reserved
+ */
+struct root_entry {
+	u64	val;
+	u64	rsvd1;
+};
+#define ROOT_ENTRY_NR (PAGE_SIZE_4K/sizeof(struct root_entry))
+static inline bool root_present(struct root_entry *root)
+{
+	return (root->val & 1);
+}
+static inline void set_root_present(struct root_entry *root)
+{
+	root->val |= 1;
+}
+static inline void set_root_value(struct root_entry *root, unsigned long value)
+{
+	root->val |= value & PAGE_MASK_4K;
+}
+
+struct context_entry;
+static inline struct context_entry *
+get_context_addr_from_root(struct root_entry *root)
+{
+	return (struct context_entry *)
+		(root_present(root)?phys_to_virt(
+		root->val & PAGE_MASK_4K):
+		NULL);
+}
+
+/*
+ * low 64 bits:
+ * 0: present
+ * 1: fault processing disable
+ * 2-3: translation type
+ * 12-63: address space root
+ * high 64 bits:
+ * 0-2: address width
+ * 3-6: aval
+ * 8-23: domain id
+ */
+struct context_entry {
+	u64 lo;
+	u64 hi;
+};
+#define context_present(c) ((c).lo & 1)
+#define context_fault_disable(c) (((c).lo >> 1) & 1)
+#define context_translation_type(c) (((c).lo >> 2) & 3)
+#define context_address_root(c) ((c).lo & PAGE_MASK_4K)
+#define context_address_width(c) ((c).hi &  7)
+#define context_domain_id(c) (((c).hi >> 8) & ((1 << 16) - 1))
+
+#define context_set_present(c) do {(c).lo |= 1;} while (0)
+#define context_set_fault_enable(c) \
+	do {(c).lo &= (((u64)-1) << 2) | 1;} while (0)
+#define context_set_translation_type(c, val) \
+	do { \
+		(c).lo &= (((u64)-1) << 4) | 3; \
+		(c).lo |= ((val) & 3) << 2; \
+	} while (0)
+#define CONTEXT_TT_MULTI_LEVEL 0
+#define context_set_address_root(c, val) \
+	do {(c).lo |= (val) & PAGE_MASK_4K;} while (0)
+#define context_set_address_width(c, val) do {(c).hi |= (val) & 7;} while (0)
+#define context_set_domain_id(c, val) \
+	do {(c).hi |= ((val) & ((1 << 16) - 1)) << 8;} while (0)
+#define context_clear_entry(c) do {(c).lo = 0; (c).hi = 0;} while (0)
+
+/*
+ * 0: readable
+ * 1: writable
+ * 2-6: reserved
+ * 7: super page
+ * 8-11: available
+ * 12-63: Host physcial address
+ */
+struct dma_pte {
+	u64 val;
+};
+#define dma_clear_pte(p)	do {(p).val = 0;} while (0)
+
+#define DMA_PTE_READ (1)
+#define DMA_PTE_WRITE (2)
+
+#define dma_set_pte_readable(p) do {(p).val |= DMA_PTE_READ;} while (0)
+#define dma_set_pte_writable(p) do {(p).val |= DMA_PTE_WRITE;} while (0)
+#define dma_set_pte_prot(p, prot) \
+		do {(p).val = ((p).val & ~3) | ((prot) & 3); } while (0)
+#define dma_pte_addr(p) ((p).val & PAGE_MASK_4K)
+#define dma_set_pte_addr(p, addr) do {\
+		(p).val |= ((addr) & PAGE_MASK_4K); } while (0)
+#define dma_pte_present(p) (((p).val & 3) != 0)
+
+struct intel_iommu;
+
+struct dmar_domain {
+	int	id;			/* domain id */
+	struct intel_iommu *iommu;	/* back pointer to owning iommu */
+
+	struct list_head devices; 	/* all devices' list */
+	struct iova_domain iovad;	/* iova's that belong to this domain */
+
+	struct dma_pte	*pgd;		/* virtual address */
+	spinlock_t	mapping_lock;	/* page table lock */
+	int		gaw;		/* max guest address width */
+
+	/* adjusted guest address width, 0 is level 2 30-bit */
+	int		agaw;
+
+#define DOMAIN_FLAG_MULTIPLE_DEVICES 1
+	int		flags;
+};
+
+/* PCI domain-device relationship */
+struct device_domain_info {
+	struct list_head link;	/* link to domain siblings */
+	struct list_head global; /* link to global list */
+	u8 bus;			/* PCI bus numer */
+	u8 devfn;		/* PCI devfn number */
+	struct pci_dev *dev; /* it's NULL for PCIE-to-PCI bridge */
+	struct dmar_domain *domain; /* pointer to domain */
+};
+
+extern int init_dmars(void);
+extern void free_dmar_iommu(struct intel_iommu *iommu);
+
+extern int dmar_disabled;
+
+#ifndef CONFIG_DMAR_GFX_WA
+static inline void iommu_prepare_gfx_mapping(void)
+{
+	return;
+}
+#endif /* !CONFIG_DMAR_GFX_WA */
+
+#endif
diff --git a/drivers/pci/dmar.c b/drivers/pci/dmar.c
index 8bf86ae..bd2c016 100644
--- a/drivers/pci/dmar.c
+++ b/drivers/pci/dmar.c
@@ -19,13 +19,16 @@
  * Author: Shaohua Li <shaohua.li@intel.com>
  * Author: Anil S Keshavamurthy <anil.s.keshavamurthy@intel.com>
  *
- * This file implements early detection/parsing of DMA Remapping Devices
+ * This file implements early detection/parsing of Remapping Devices
  * reported to OS through BIOS via DMA remapping reporting (DMAR) ACPI
  * tables.
+ *
+ * These routines are used by both DMA-remapping and Interrupt-remapping
  */
 
 #include <linux/pci.h>
 #include <linux/dmar.h>
+#include <linux/timer.h>
 #include "iova.h"
 #include "intel-iommu.h"
 
@@ -37,7 +40,6 @@
  * these units are not supported by the architecture.
  */
 LIST_HEAD(dmar_drhd_units);
-LIST_HEAD(dmar_rmrr_units);
 
 static struct acpi_table_header * __initdata dmar_tbl;
 
@@ -53,11 +55,6 @@
 		list_add(&drhd->list, &dmar_drhd_units);
 }
 
-static void __init dmar_register_rmrr_unit(struct dmar_rmrr_unit *rmrr)
-{
-	list_add(&rmrr->list, &dmar_rmrr_units);
-}
-
 static int __init dmar_parse_one_dev_scope(struct acpi_dmar_device_scope *scope,
 					   struct pci_dev **dev, u16 segment)
 {
@@ -172,19 +169,37 @@
 	struct acpi_dmar_hardware_unit *drhd;
 	struct dmar_drhd_unit *dmaru;
 	int ret = 0;
-	static int include_all;
 
 	dmaru = kzalloc(sizeof(*dmaru), GFP_KERNEL);
 	if (!dmaru)
 		return -ENOMEM;
 
+	dmaru->hdr = header;
 	drhd = (struct acpi_dmar_hardware_unit *)header;
 	dmaru->reg_base_addr = drhd->address;
 	dmaru->include_all = drhd->flags & 0x1; /* BIT0: INCLUDE_ALL */
 
+	ret = alloc_iommu(dmaru);
+	if (ret) {
+		kfree(dmaru);
+		return ret;
+	}
+	dmar_register_drhd_unit(dmaru);
+	return 0;
+}
+
+static int __init
+dmar_parse_dev(struct dmar_drhd_unit *dmaru)
+{
+	struct acpi_dmar_hardware_unit *drhd;
+	static int include_all;
+	int ret;
+
+	drhd = (struct acpi_dmar_hardware_unit *) dmaru->hdr;
+
 	if (!dmaru->include_all)
 		ret = dmar_parse_dev_scope((void *)(drhd + 1),
-				((void *)drhd) + header->length,
+				((void *)drhd) + drhd->header.length,
 				&dmaru->devices_cnt, &dmaru->devices,
 				drhd->segment);
 	else {
@@ -197,37 +212,59 @@
 		include_all = 1;
 	}
 
-	if (ret || (dmaru->devices_cnt == 0 && !dmaru->include_all))
+	if (ret || (dmaru->devices_cnt == 0 && !dmaru->include_all)) {
+		list_del(&dmaru->list);
 		kfree(dmaru);
-	else
-		dmar_register_drhd_unit(dmaru);
+	}
 	return ret;
 }
 
+#ifdef CONFIG_DMAR
+LIST_HEAD(dmar_rmrr_units);
+
+static void __init dmar_register_rmrr_unit(struct dmar_rmrr_unit *rmrr)
+{
+	list_add(&rmrr->list, &dmar_rmrr_units);
+}
+
+
 static int __init
 dmar_parse_one_rmrr(struct acpi_dmar_header *header)
 {
 	struct acpi_dmar_reserved_memory *rmrr;
 	struct dmar_rmrr_unit *rmrru;
-	int ret = 0;
 
 	rmrru = kzalloc(sizeof(*rmrru), GFP_KERNEL);
 	if (!rmrru)
 		return -ENOMEM;
 
+	rmrru->hdr = header;
 	rmrr = (struct acpi_dmar_reserved_memory *)header;
 	rmrru->base_address = rmrr->base_address;
 	rmrru->end_address = rmrr->end_address;
+
+	dmar_register_rmrr_unit(rmrru);
+	return 0;
+}
+
+static int __init
+rmrr_parse_dev(struct dmar_rmrr_unit *rmrru)
+{
+	struct acpi_dmar_reserved_memory *rmrr;
+	int ret;
+
+	rmrr = (struct acpi_dmar_reserved_memory *) rmrru->hdr;
 	ret = dmar_parse_dev_scope((void *)(rmrr + 1),
-		((void *)rmrr) + header->length,
+		((void *)rmrr) + rmrr->header.length,
 		&rmrru->devices_cnt, &rmrru->devices, rmrr->segment);
 
-	if (ret || (rmrru->devices_cnt == 0))
+	if (ret || (rmrru->devices_cnt == 0)) {
+		list_del(&rmrru->list);
 		kfree(rmrru);
-	else
-		dmar_register_rmrr_unit(rmrru);
+	}
 	return ret;
 }
+#endif
 
 static void __init
 dmar_table_print_dmar_entry(struct acpi_dmar_header *header)
@@ -252,6 +289,7 @@
 	}
 }
 
+
 /**
  * parse_dmar_table - parses the DMA reporting table
  */
@@ -284,7 +322,9 @@
 			ret = dmar_parse_one_drhd(entry_header);
 			break;
 		case ACPI_DMAR_TYPE_RESERVED_MEMORY:
+#ifdef CONFIG_DMAR
 			ret = dmar_parse_one_rmrr(entry_header);
+#endif
 			break;
 		default:
 			printk(KERN_WARNING PREFIX
@@ -300,15 +340,77 @@
 	return ret;
 }
 
+int dmar_pci_device_match(struct pci_dev *devices[], int cnt,
+			  struct pci_dev *dev)
+{
+	int index;
+
+	while (dev) {
+		for (index = 0; index < cnt; index++)
+			if (dev == devices[index])
+				return 1;
+
+		/* Check our parent */
+		dev = dev->bus->self;
+	}
+
+	return 0;
+}
+
+struct dmar_drhd_unit *
+dmar_find_matched_drhd_unit(struct pci_dev *dev)
+{
+	struct dmar_drhd_unit *drhd = NULL;
+
+	list_for_each_entry(drhd, &dmar_drhd_units, list) {
+		if (drhd->include_all || dmar_pci_device_match(drhd->devices,
+						drhd->devices_cnt, dev))
+			return drhd;
+	}
+
+	return NULL;
+}
+
+int __init dmar_dev_scope_init(void)
+{
+	struct dmar_drhd_unit *drhd;
+	int ret = -ENODEV;
+
+	for_each_drhd_unit(drhd) {
+		ret = dmar_parse_dev(drhd);
+		if (ret)
+			return ret;
+	}
+
+#ifdef CONFIG_DMAR
+	{
+		struct dmar_rmrr_unit *rmrr;
+		for_each_rmrr_units(rmrr) {
+			ret = rmrr_parse_dev(rmrr);
+			if (ret)
+				return ret;
+		}
+	}
+#endif
+
+	return ret;
+}
+
 
 int __init dmar_table_init(void)
 {
-
+	static int dmar_table_initialized;
 	int ret;
 
+	if (dmar_table_initialized)
+		return 0;
+
+	dmar_table_initialized = 1;
+
 	ret = parse_dmar_table();
 	if (ret) {
-		printk(KERN_INFO PREFIX "parse DMAR table failure.\n");
+		if (ret != -ENODEV)
+			printk(KERN_INFO PREFIX "parse DMAR table failure.\n");
 		return ret;
 	}
 
@@ -317,9 +419,14 @@
 		return -ENODEV;
 	}
 
+#ifdef CONFIG_DMAR
 	if (list_empty(&dmar_rmrr_units))
 		printk(KERN_INFO PREFIX "No RMRR found\n");
+#endif
 
+#ifdef CONFIG_INTR_REMAP
+	parse_ioapics_under_ir();
+#endif
 	return 0;
 }
 
@@ -341,3 +448,255 @@
 
 	return (ACPI_SUCCESS(status) ? 1 : 0);
 }
+
+void __init detect_intel_iommu(void)
+{
+	int ret;
+
+	ret = early_dmar_detect();
+
+#ifdef CONFIG_DMAR
+	{
+		struct acpi_table_dmar *dmar;
+		/*
+		 * for now we will disable dma-remapping when interrupt
+		 * remapping is enabled.
+		 * When support for queued invalidation for IOTLB invalidation
+		 * is added, we will not need this any more.
+		 */
+		dmar = (struct acpi_table_dmar *) dmar_tbl;
+		if (ret && cpu_has_x2apic && dmar->flags & 0x1) {
+			printk(KERN_INFO
+			       "Queued invalidation will be enabled to support "
+			       "x2apic and Intr-remapping.\n");
+			printk(KERN_INFO
+			       "Disabling IOMMU detection, because of missing "
+			       "queued invalidation support for IOTLB "
+			       "invalidation\n");
+			printk(KERN_INFO
+			       "Use \"nox2apic\", if you want to use Intel "
+			       " IOMMU for DMA-remapping and don't care about "
+			       " x2apic support\n");
+
+			dmar_disabled = 1;
+			return;
+		}
+
+		if (ret && !no_iommu && !iommu_detected && !swiotlb &&
+		    !dmar_disabled)
+			iommu_detected = 1;
+	}
+#endif
+}
+
+
+int alloc_iommu(struct dmar_drhd_unit *drhd)
+{
+	struct intel_iommu *iommu;
+	int map_size;
+	u32 ver;
+	static int iommu_allocated = 0;
+
+	iommu = kzalloc(sizeof(*iommu), GFP_KERNEL);
+	if (!iommu)
+		return -ENOMEM;
+
+	iommu->seq_id = iommu_allocated++;
+
+	iommu->reg = ioremap(drhd->reg_base_addr, PAGE_SIZE_4K);
+	if (!iommu->reg) {
+		printk(KERN_ERR "IOMMU: can't map the region\n");
+		goto error;
+	}
+	iommu->cap = dmar_readq(iommu->reg + DMAR_CAP_REG);
+	iommu->ecap = dmar_readq(iommu->reg + DMAR_ECAP_REG);
+
+	/* the registers might be more than one page */
+	map_size = max_t(int, ecap_max_iotlb_offset(iommu->ecap),
+		cap_max_fault_reg_offset(iommu->cap));
+	map_size = PAGE_ALIGN_4K(map_size);
+	if (map_size > PAGE_SIZE_4K) {
+		iounmap(iommu->reg);
+		iommu->reg = ioremap(drhd->reg_base_addr, map_size);
+		if (!iommu->reg) {
+			printk(KERN_ERR "IOMMU: can't map the region\n");
+			goto error;
+		}
+	}
+
+	ver = readl(iommu->reg + DMAR_VER_REG);
+	pr_debug("IOMMU %llx: ver %d:%d cap %llx ecap %llx\n",
+		drhd->reg_base_addr, DMAR_VER_MAJOR(ver), DMAR_VER_MINOR(ver),
+		iommu->cap, iommu->ecap);
+
+	spin_lock_init(&iommu->register_lock);
+
+	drhd->iommu = iommu;
+	return 0;
+error:
+	kfree(iommu);
+	return -1;
+}
+
+void free_iommu(struct intel_iommu *iommu)
+{
+	if (!iommu)
+		return;
+
+#ifdef CONFIG_DMAR
+	free_dmar_iommu(iommu);
+#endif
+
+	if (iommu->reg)
+		iounmap(iommu->reg);
+	kfree(iommu);
+}
+
+/*
+ * Reclaim all the submitted descriptors which have completed its work.
+ */
+static inline void reclaim_free_desc(struct q_inval *qi)
+{
+	while (qi->desc_status[qi->free_tail] == QI_DONE) {
+		qi->desc_status[qi->free_tail] = QI_FREE;
+		qi->free_tail = (qi->free_tail + 1) % QI_LENGTH;
+		qi->free_cnt++;
+	}
+}
+
+/*
+ * Submit the queued invalidation descriptor to the remapping
+ * hardware unit and wait for its completion.
+ */
+void qi_submit_sync(struct qi_desc *desc, struct intel_iommu *iommu)
+{
+	struct q_inval *qi = iommu->qi;
+	struct qi_desc *hw, wait_desc;
+	int wait_index, index;
+	unsigned long flags;
+
+	if (!qi)
+		return;
+
+	hw = qi->desc;
+
+	spin_lock(&qi->q_lock);
+	while (qi->free_cnt < 3) {
+		spin_unlock(&qi->q_lock);
+		cpu_relax();
+		spin_lock(&qi->q_lock);
+	}
+
+	index = qi->free_head;
+	wait_index = (index + 1) % QI_LENGTH;
+
+	qi->desc_status[index] = qi->desc_status[wait_index] = QI_IN_USE;
+
+	hw[index] = *desc;
+
+	wait_desc.low = QI_IWD_STATUS_DATA(2) | QI_IWD_STATUS_WRITE | QI_IWD_TYPE;
+	wait_desc.high = virt_to_phys(&qi->desc_status[wait_index]);
+
+	hw[wait_index] = wait_desc;
+
+	__iommu_flush_cache(iommu, &hw[index], sizeof(struct qi_desc));
+	__iommu_flush_cache(iommu, &hw[wait_index], sizeof(struct qi_desc));
+
+	qi->free_head = (qi->free_head + 2) % QI_LENGTH;
+	qi->free_cnt -= 2;
+
+	spin_lock_irqsave(&iommu->register_lock, flags);
+	/*
+	 * update the HW tail register indicating the presence of
+	 * new descriptors.
+	 */
+	writel(qi->free_head << 4, iommu->reg + DMAR_IQT_REG);
+	spin_unlock_irqrestore(&iommu->register_lock, flags);
+
+	while (qi->desc_status[wait_index] != QI_DONE) {
+		spin_unlock(&qi->q_lock);
+		cpu_relax();
+		spin_lock(&qi->q_lock);
+	}
+
+	qi->desc_status[index] = QI_DONE;
+
+	reclaim_free_desc(qi);
+	spin_unlock(&qi->q_lock);
+}
+
+/*
+ * Flush the global interrupt entry cache.
+ */
+void qi_global_iec(struct intel_iommu *iommu)
+{
+	struct qi_desc desc;
+
+	desc.low = QI_IEC_TYPE;
+	desc.high = 0;
+
+	qi_submit_sync(&desc, iommu);
+}
+
+/*
+ * Enable Queued Invalidation interface. This is a must to support
+ * interrupt-remapping. Also used by DMA-remapping, which replaces
+ * register based IOTLB invalidation.
+ */
+int dmar_enable_qi(struct intel_iommu *iommu)
+{
+	u32 cmd, sts;
+	unsigned long flags;
+	struct q_inval *qi;
+
+	if (!ecap_qis(iommu->ecap))
+		return -ENOENT;
+
+	/*
+	 * queued invalidation is already setup and enabled.
+	 */
+	if (iommu->qi)
+		return 0;
+
+	iommu->qi = kmalloc(sizeof(*qi), GFP_KERNEL);
+	if (!iommu->qi)
+		return -ENOMEM;
+
+	qi = iommu->qi;
+
+	qi->desc = (void *)(get_zeroed_page(GFP_KERNEL));
+	if (!qi->desc) {
+		kfree(qi);
+		iommu->qi = 0;
+		return -ENOMEM;
+	}
+
+	qi->desc_status = kmalloc(QI_LENGTH * sizeof(int), GFP_KERNEL);
+	if (!qi->desc_status) {
+		free_page((unsigned long) qi->desc);
+		kfree(qi);
+		iommu->qi = 0;
+		return -ENOMEM;
+	}
+
+	qi->free_head = qi->free_tail = 0;
+	qi->free_cnt = QI_LENGTH;
+
+	spin_lock_init(&qi->q_lock);
+
+	spin_lock_irqsave(&iommu->register_lock, flags);
+	/* write zero to the tail reg */
+	writel(0, iommu->reg + DMAR_IQT_REG);
+
+	dmar_writeq(iommu->reg + DMAR_IQA_REG, virt_to_phys(qi->desc));
+
+	cmd = iommu->gcmd | DMA_GCMD_QIE;
+	iommu->gcmd |= DMA_GCMD_QIE;
+	writel(cmd, iommu->reg + DMAR_GCMD_REG);
+
+	/* Make sure hardware complete it */
+	IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG, readl, (sts & DMA_GSTS_QIES), sts);
+	spin_unlock_irqrestore(&iommu->register_lock, flags);
+
+	return 0;
+}
diff --git a/drivers/pci/hotplug/ibmphp_ebda.c b/drivers/pci/hotplug/ibmphp_ebda.c
index 8467d02..7d27631 100644
--- a/drivers/pci/hotplug/ibmphp_ebda.c
+++ b/drivers/pci/hotplug/ibmphp_ebda.c
@@ -276,7 +276,7 @@
 	iounmap (io_mem);
 	debug ("returned ebda segment: %x\n", ebda_seg);
 	
-	io_mem = ioremap (ebda_seg<<4, 65000);
+	io_mem = ioremap(ebda_seg<<4, 1024);
 	if (!io_mem )
 		return -ENOMEM;
 	next_offset = 0x180;
diff --git a/drivers/pci/intel-iommu.c b/drivers/pci/intel-iommu.c
index c3edcdc..389fdd6 100644
--- a/drivers/pci/intel-iommu.c
+++ b/drivers/pci/intel-iommu.c
@@ -49,8 +49,6 @@
 
 #define DEFAULT_DOMAIN_ADDRESS_WIDTH 48
 
-#define DMAR_OPERATION_TIMEOUT ((cycles_t) tsc_khz*10*1000) /* 10sec */
-
 #define DOMAIN_MAX_ADDR(gaw) ((((u64)1) << gaw) - 1)
 
 
@@ -58,8 +56,6 @@
 
 DEFINE_TIMER(unmap_timer,  flush_unmaps_timeout, 0, 0);
 
-static struct intel_iommu *g_iommus;
-
 #define HIGH_WATER_MARK 250
 struct deferred_flush_tables {
 	int next;
@@ -80,7 +76,7 @@
 
 static void domain_remove_dev_info(struct dmar_domain *domain);
 
-static int dmar_disabled;
+int dmar_disabled;
 static int __initdata dmar_map_gfx = 1;
 static int dmar_forcedac;
 static int intel_iommu_strict;
@@ -185,13 +181,6 @@
 	kmem_cache_free(iommu_iova_cache, iova);
 }
 
-static inline void __iommu_flush_cache(
-	struct intel_iommu *iommu, void *addr, int size)
-{
-	if (!ecap_coherent(iommu->ecap))
-		clflush_cache_range(addr, size);
-}
-
 /* Gets context entry for a given bus and devfn */
 static struct context_entry * device_to_context_entry(struct intel_iommu *iommu,
 		u8 bus, u8 devfn)
@@ -488,19 +477,6 @@
 	return 0;
 }
 
-#define IOMMU_WAIT_OP(iommu, offset, op, cond, sts) \
-{\
-	cycles_t start_time = get_cycles();\
-	while (1) {\
-		sts = op (iommu->reg + offset);\
-		if (cond)\
-			break;\
-		if (DMAR_OPERATION_TIMEOUT < (get_cycles() - start_time))\
-			panic("DMAR hardware is malfunctioning\n");\
-		cpu_relax();\
-	}\
-}
-
 static void iommu_set_root_entry(struct intel_iommu *iommu)
 {
 	void *addr;
@@ -990,6 +966,8 @@
 		return -ENOMEM;
 	}
 
+	spin_lock_init(&iommu->lock);
+
 	/*
 	 * if Caching mode is set, then invalid translations are tagged
 	 * with domainid 0. Hence we need to pre-allocate it.
@@ -998,62 +976,15 @@
 		set_bit(0, iommu->domain_ids);
 	return 0;
 }
-static struct intel_iommu *alloc_iommu(struct intel_iommu *iommu,
-					struct dmar_drhd_unit *drhd)
-{
-	int ret;
-	int map_size;
-	u32 ver;
 
-	iommu->reg = ioremap(drhd->reg_base_addr, PAGE_SIZE_4K);
-	if (!iommu->reg) {
-		printk(KERN_ERR "IOMMU: can't map the region\n");
-		goto error;
-	}
-	iommu->cap = dmar_readq(iommu->reg + DMAR_CAP_REG);
-	iommu->ecap = dmar_readq(iommu->reg + DMAR_ECAP_REG);
-
-	/* the registers might be more than one page */
-	map_size = max_t(int, ecap_max_iotlb_offset(iommu->ecap),
-		cap_max_fault_reg_offset(iommu->cap));
-	map_size = PAGE_ALIGN_4K(map_size);
-	if (map_size > PAGE_SIZE_4K) {
-		iounmap(iommu->reg);
-		iommu->reg = ioremap(drhd->reg_base_addr, map_size);
-		if (!iommu->reg) {
-			printk(KERN_ERR "IOMMU: can't map the region\n");
-			goto error;
-		}
-	}
-
-	ver = readl(iommu->reg + DMAR_VER_REG);
-	pr_debug("IOMMU %llx: ver %d:%d cap %llx ecap %llx\n",
-		drhd->reg_base_addr, DMAR_VER_MAJOR(ver), DMAR_VER_MINOR(ver),
-		iommu->cap, iommu->ecap);
-	ret = iommu_init_domains(iommu);
-	if (ret)
-		goto error_unmap;
-	spin_lock_init(&iommu->lock);
-	spin_lock_init(&iommu->register_lock);
-
-	drhd->iommu = iommu;
-	return iommu;
-error_unmap:
-	iounmap(iommu->reg);
-error:
-	kfree(iommu);
-	return NULL;
-}
 
 static void domain_exit(struct dmar_domain *domain);
-static void free_iommu(struct intel_iommu *iommu)
+
+void free_dmar_iommu(struct intel_iommu *iommu)
 {
 	struct dmar_domain *domain;
 	int i;
 
-	if (!iommu)
-		return;
-
 	i = find_first_bit(iommu->domain_ids, cap_ndoms(iommu->cap));
 	for (; i < cap_ndoms(iommu->cap); ) {
 		domain = iommu->domains[i];
@@ -1078,10 +1009,6 @@
 
 	/* free context mapping */
 	free_context_table(iommu);
-
-	if (iommu->reg)
-		iounmap(iommu->reg);
-	kfree(iommu);
 }
 
 static struct dmar_domain * iommu_alloc_domain(struct intel_iommu *iommu)
@@ -1426,37 +1353,6 @@
 	return NULL;
 }
 
-static int dmar_pci_device_match(struct pci_dev *devices[], int cnt,
-     struct pci_dev *dev)
-{
-	int index;
-
-	while (dev) {
-		for (index = 0; index < cnt; index++)
-			if (dev == devices[index])
-				return 1;
-
-		/* Check our parent */
-		dev = dev->bus->self;
-	}
-
-	return 0;
-}
-
-static struct dmar_drhd_unit *
-dmar_find_matched_drhd_unit(struct pci_dev *dev)
-{
-	struct dmar_drhd_unit *drhd = NULL;
-
-	list_for_each_entry(drhd, &dmar_drhd_units, list) {
-		if (drhd->include_all || dmar_pci_device_match(drhd->devices,
-						drhd->devices_cnt, dev))
-			return drhd;
-	}
-
-	return NULL;
-}
-
 /* domain is initialized */
 static struct dmar_domain *get_domain_for_dev(struct pci_dev *pdev, int gaw)
 {
@@ -1729,8 +1625,6 @@
 	 * endfor
 	 */
 	for_each_drhd_unit(drhd) {
-		if (drhd->ignored)
-			continue;
 		g_num_of_iommus++;
 		/*
 		 * lock not needed as this is only incremented in the single
@@ -1739,12 +1633,6 @@
 		 */
 	}
 
-	g_iommus = kzalloc(g_num_of_iommus * sizeof(*iommu), GFP_KERNEL);
-	if (!g_iommus) {
-		ret = -ENOMEM;
-		goto error;
-	}
-
 	deferred_flush = kzalloc(g_num_of_iommus *
 		sizeof(struct deferred_flush_tables), GFP_KERNEL);
 	if (!deferred_flush) {
@@ -1752,16 +1640,15 @@
 		goto error;
 	}
 
-	i = 0;
 	for_each_drhd_unit(drhd) {
 		if (drhd->ignored)
 			continue;
-		iommu = alloc_iommu(&g_iommus[i], drhd);
-		i++;
-		if (!iommu) {
-			ret = -ENOMEM;
+
+		iommu = drhd->iommu;
+
+		ret = iommu_init_domains(iommu);
+		if (ret)
 			goto error;
-		}
 
 		/*
 		 * TBD:
@@ -1845,7 +1732,6 @@
 		iommu = drhd->iommu;
 		free_iommu(iommu);
 	}
-	kfree(g_iommus);
 	return ret;
 }
 
@@ -2002,7 +1888,10 @@
 	/* just flush them all */
 	for (i = 0; i < g_num_of_iommus; i++) {
 		if (deferred_flush[i].next) {
-			iommu_flush_iotlb_global(&g_iommus[i], 0);
+			struct intel_iommu *iommu =
+				deferred_flush[i].domain[0]->iommu;
+
+			iommu_flush_iotlb_global(iommu, 0);
 			for (j = 0; j < deferred_flush[i].next; j++) {
 				__free_iova(&deferred_flush[i].domain[j]->iovad,
 						deferred_flush[i].iova[j]);
@@ -2032,7 +1921,8 @@
 	if (list_size == HIGH_WATER_MARK)
 		flush_unmaps();
 
-	iommu_id = dom->iommu - g_iommus;
+	iommu_id = dom->iommu->seq_id;
+
 	next = deferred_flush[iommu_id].next;
 	deferred_flush[iommu_id].domain[next] = dom;
 	deferred_flush[iommu_id].iova[next] = iova;
@@ -2348,38 +2238,6 @@
 
 }
 
-static int blacklist_iommu(const struct dmi_system_id *id)
-{
-	printk(KERN_INFO "%s detected; disabling IOMMU\n",
-	       id->ident);
-	dmar_disabled = 1;
-	return 0;
-}
-
-static struct dmi_system_id __initdata intel_iommu_dmi_table[] = {
-	{	/* Some DG33BU BIOS revisions advertised non-existent VT-d */
-		.callback = blacklist_iommu,
-		.ident = "Intel DG33BU",
-		{	DMI_MATCH(DMI_BOARD_VENDOR, "Intel Corporation"),
-			DMI_MATCH(DMI_BOARD_NAME, "DG33BU"),
-		}
-	},
-	{ }
-};
-
-
-void __init detect_intel_iommu(void)
-{
-	if (swiotlb || no_iommu || iommu_detected || dmar_disabled)
-		return;
-	if (early_dmar_detect()) {
-		dmi_check_system(intel_iommu_dmi_table);
-		if (dmar_disabled)
-			return;
-		iommu_detected = 1;
-	}
-}
-
 static void __init init_no_remapping_devices(void)
 {
 	struct dmar_drhd_unit *drhd;
@@ -2426,12 +2284,19 @@
 {
 	int ret = 0;
 
-	if (no_iommu || swiotlb || dmar_disabled)
-		return -ENODEV;
-
 	if (dmar_table_init())
 		return 	-ENODEV;
 
+	if (dmar_dev_scope_init())
+		return 	-ENODEV;
+
+	/*
+	 * Check the need for DMA-remapping initialization now.
+	 * Above initialization will also be used by Interrupt-remapping.
+	 */
+	if (no_iommu || swiotlb || dmar_disabled)
+		return -ENODEV;
+
 	iommu_init_mempool();
 	dmar_init_reserved_ranges();
 
diff --git a/drivers/pci/intel-iommu.h b/drivers/pci/intel-iommu.h
index afc0ad9..2142c01 100644
--- a/drivers/pci/intel-iommu.h
+++ b/drivers/pci/intel-iommu.h
@@ -27,19 +27,8 @@
 #include <linux/sysdev.h>
 #include "iova.h"
 #include <linux/io.h>
-
-/*
- * We need a fixed PAGE_SIZE of 4K irrespective of
- * arch PAGE_SIZE for IOMMU page tables.
- */
-#define PAGE_SHIFT_4K		(12)
-#define PAGE_SIZE_4K		(1UL << PAGE_SHIFT_4K)
-#define PAGE_MASK_4K		(((u64)-1) << PAGE_SHIFT_4K)
-#define PAGE_ALIGN_4K(addr)	(((addr) + PAGE_SIZE_4K - 1) & PAGE_MASK_4K)
-
-#define IOVA_PFN(addr)		((addr) >> PAGE_SHIFT_4K)
-#define DMA_32BIT_PFN		IOVA_PFN(DMA_32BIT_MASK)
-#define DMA_64BIT_PFN		IOVA_PFN(DMA_64BIT_MASK)
+#include <asm/cacheflush.h>
+#include "dma_remapping.h"
 
 /*
  * Intel IOMMU register specification per version 1.0 public spec.
@@ -63,6 +52,11 @@
 #define	DMAR_PLMLIMIT_REG 0x6c	/* PMRR low limit */
 #define	DMAR_PHMBASE_REG 0x70	/* pmrr high base addr */
 #define	DMAR_PHMLIMIT_REG 0x78	/* pmrr high limit */
+#define DMAR_IQH_REG	0x80	/* Invalidation queue head register */
+#define DMAR_IQT_REG	0x88	/* Invalidation queue tail register */
+#define DMAR_IQA_REG	0x90	/* Invalidation queue addr register */
+#define DMAR_ICS_REG	0x98	/* Invalidation complete status register */
+#define DMAR_IRTA_REG	0xb8    /* Interrupt remapping table addr register */
 
 #define OFFSET_STRIDE		(9)
 /*
@@ -126,6 +120,10 @@
 #define ecap_max_iotlb_offset(e) \
 	(ecap_iotlb_offset(e) + ecap_niotlb_iunits(e) * 16)
 #define ecap_coherent(e)	((e) & 0x1)
+#define ecap_qis(e)		((e) & 0x2)
+#define ecap_eim_support(e)	((e >> 4) & 0x1)
+#define ecap_ir_support(e)	((e >> 3) & 0x1)
+#define ecap_max_handle_mask(e) ((e >> 20) & 0xf)
 
 
 /* IOTLB_REG */
@@ -141,6 +139,17 @@
 #define DMA_TLB_IH_NONLEAF (((u64)1) << 6)
 #define DMA_TLB_MAX_SIZE (0x3f)
 
+/* INVALID_DESC */
+#define DMA_ID_TLB_GLOBAL_FLUSH	(((u64)1) << 3)
+#define DMA_ID_TLB_DSI_FLUSH	(((u64)2) << 3)
+#define DMA_ID_TLB_PSI_FLUSH	(((u64)3) << 3)
+#define DMA_ID_TLB_READ_DRAIN	(((u64)1) << 7)
+#define DMA_ID_TLB_WRITE_DRAIN	(((u64)1) << 6)
+#define DMA_ID_TLB_DID(id)	(((u64)((id & 0xffff) << 16)))
+#define DMA_ID_TLB_IH_NONLEAF	(((u64)1) << 6)
+#define DMA_ID_TLB_ADDR(addr)	(addr)
+#define DMA_ID_TLB_ADDR_MASK(mask)	(mask)
+
 /* PMEN_REG */
 #define DMA_PMEN_EPM (((u32)1)<<31)
 #define DMA_PMEN_PRS (((u32)1)<<0)
@@ -151,6 +160,9 @@
 #define DMA_GCMD_SFL (((u32)1) << 29)
 #define DMA_GCMD_EAFL (((u32)1) << 28)
 #define DMA_GCMD_WBF (((u32)1) << 27)
+#define DMA_GCMD_QIE (((u32)1) << 26)
+#define DMA_GCMD_SIRTP (((u32)1) << 24)
+#define DMA_GCMD_IRE (((u32) 1) << 25)
 
 /* GSTS_REG */
 #define DMA_GSTS_TES (((u32)1) << 31)
@@ -158,6 +170,9 @@
 #define DMA_GSTS_FLS (((u32)1) << 29)
 #define DMA_GSTS_AFLS (((u32)1) << 28)
 #define DMA_GSTS_WBFS (((u32)1) << 27)
+#define DMA_GSTS_QIES (((u32)1) << 26)
+#define DMA_GSTS_IRTPS (((u32)1) << 24)
+#define DMA_GSTS_IRES (((u32)1) << 25)
 
 /* CCMD_REG */
 #define DMA_CCMD_ICC (((u64)1) << 63)
@@ -187,158 +202,106 @@
 #define dma_frcd_source_id(c) (c & 0xffff)
 #define dma_frcd_page_addr(d) (d & (((u64)-1) << 12)) /* low 64 bit */
 
-/*
- * 0: Present
- * 1-11: Reserved
- * 12-63: Context Ptr (12 - (haw-1))
- * 64-127: Reserved
- */
-struct root_entry {
-	u64	val;
-	u64	rsvd1;
-};
-#define ROOT_ENTRY_NR (PAGE_SIZE_4K/sizeof(struct root_entry))
-static inline bool root_present(struct root_entry *root)
-{
-	return (root->val & 1);
-}
-static inline void set_root_present(struct root_entry *root)
-{
-	root->val |= 1;
-}
-static inline void set_root_value(struct root_entry *root, unsigned long value)
-{
-	root->val |= value & PAGE_MASK_4K;
+#define DMAR_OPERATION_TIMEOUT ((cycles_t) tsc_khz*10*1000) /* 10sec */
+
+#define IOMMU_WAIT_OP(iommu, offset, op, cond, sts) \
+{\
+	cycles_t start_time = get_cycles();\
+	while (1) {\
+		sts = op (iommu->reg + offset);\
+		if (cond)\
+			break;\
+		if (DMAR_OPERATION_TIMEOUT < (get_cycles() - start_time))\
+			panic("DMAR hardware is malfunctioning\n");\
+		cpu_relax();\
+	}\
 }
 
-struct context_entry;
-static inline struct context_entry *
-get_context_addr_from_root(struct root_entry *root)
-{
-	return (struct context_entry *)
-		(root_present(root)?phys_to_virt(
-		root->val & PAGE_MASK_4K):
-		NULL);
-}
+#define QI_LENGTH	256	/* queue length */
 
-/*
- * low 64 bits:
- * 0: present
- * 1: fault processing disable
- * 2-3: translation type
- * 12-63: address space root
- * high 64 bits:
- * 0-2: address width
- * 3-6: aval
- * 8-23: domain id
- */
-struct context_entry {
-	u64 lo;
-	u64 hi;
-};
-#define context_present(c) ((c).lo & 1)
-#define context_fault_disable(c) (((c).lo >> 1) & 1)
-#define context_translation_type(c) (((c).lo >> 2) & 3)
-#define context_address_root(c) ((c).lo & PAGE_MASK_4K)
-#define context_address_width(c) ((c).hi &  7)
-#define context_domain_id(c) (((c).hi >> 8) & ((1 << 16) - 1))
-
-#define context_set_present(c) do {(c).lo |= 1;} while (0)
-#define context_set_fault_enable(c) \
-	do {(c).lo &= (((u64)-1) << 2) | 1;} while (0)
-#define context_set_translation_type(c, val) \
-	do { \
-		(c).lo &= (((u64)-1) << 4) | 3; \
-		(c).lo |= ((val) & 3) << 2; \
-	} while (0)
-#define CONTEXT_TT_MULTI_LEVEL 0
-#define context_set_address_root(c, val) \
-	do {(c).lo |= (val) & PAGE_MASK_4K;} while (0)
-#define context_set_address_width(c, val) do {(c).hi |= (val) & 7;} while (0)
-#define context_set_domain_id(c, val) \
-	do {(c).hi |= ((val) & ((1 << 16) - 1)) << 8;} while (0)
-#define context_clear_entry(c) do {(c).lo = 0; (c).hi = 0;} while (0)
-
-/*
- * 0: readable
- * 1: writable
- * 2-6: reserved
- * 7: super page
- * 8-11: available
- * 12-63: Host physcial address
- */
-struct dma_pte {
-	u64 val;
-};
-#define dma_clear_pte(p)	do {(p).val = 0;} while (0)
-
-#define DMA_PTE_READ (1)
-#define DMA_PTE_WRITE (2)
-
-#define dma_set_pte_readable(p) do {(p).val |= DMA_PTE_READ;} while (0)
-#define dma_set_pte_writable(p) do {(p).val |= DMA_PTE_WRITE;} while (0)
-#define dma_set_pte_prot(p, prot) \
-		do {(p).val = ((p).val & ~3) | ((prot) & 3); } while (0)
-#define dma_pte_addr(p) ((p).val & PAGE_MASK_4K)
-#define dma_set_pte_addr(p, addr) do {\
-		(p).val |= ((addr) & PAGE_MASK_4K); } while (0)
-#define dma_pte_present(p) (((p).val & 3) != 0)
-
-struct intel_iommu;
-
-struct dmar_domain {
-	int	id;			/* domain id */
-	struct intel_iommu *iommu;	/* back pointer to owning iommu */
-
-	struct list_head devices; 	/* all devices' list */
-	struct iova_domain iovad;	/* iova's that belong to this domain */
-
-	struct dma_pte	*pgd;		/* virtual address */
-	spinlock_t	mapping_lock;	/* page table lock */
-	int		gaw;		/* max guest address width */
-
-	/* adjusted guest address width, 0 is level 2 30-bit */
-	int		agaw;
-
-#define DOMAIN_FLAG_MULTIPLE_DEVICES 1
-	int		flags;
+enum {
+	QI_FREE,
+	QI_IN_USE,
+	QI_DONE
 };
 
-/* PCI domain-device relationship */
-struct device_domain_info {
-	struct list_head link;	/* link to domain siblings */
-	struct list_head global; /* link to global list */
-	u8 bus;			/* PCI bus numer */
-	u8 devfn;		/* PCI devfn number */
-	struct pci_dev *dev; /* it's NULL for PCIE-to-PCI bridge */
-	struct dmar_domain *domain; /* pointer to domain */
+#define QI_CC_TYPE		0x1
+#define QI_IOTLB_TYPE		0x2
+#define QI_DIOTLB_TYPE		0x3
+#define QI_IEC_TYPE		0x4
+#define QI_IWD_TYPE		0x5
+
+#define QI_IEC_SELECTIVE	(((u64)1) << 4)
+#define QI_IEC_IIDEX(idx)	(((u64)(idx & 0xffff) << 32))
+#define QI_IEC_IM(m)		(((u64)(m & 0x1f) << 27))
+
+#define QI_IWD_STATUS_DATA(d)	(((u64)d) << 32)
+#define QI_IWD_STATUS_WRITE	(((u64)1) << 5)
+
+struct qi_desc {
+	u64 low, high;
 };
 
-extern int init_dmars(void);
+struct q_inval {
+	spinlock_t      q_lock;
+	struct qi_desc  *desc;          /* invalidation queue */
+	int             *desc_status;   /* desc status */
+	int             free_head;      /* first free entry */
+	int             free_tail;      /* last free entry */
+	int             free_cnt;
+};
+
+#ifdef CONFIG_INTR_REMAP
+/* 1MB - maximum possible interrupt remapping table size */
+#define INTR_REMAP_PAGE_ORDER	8
+#define INTR_REMAP_TABLE_REG_SIZE	0xf
+
+#define INTR_REMAP_TABLE_ENTRIES	65536
+
+struct ir_table {
+	struct irte *base;
+};
+#endif
 
 struct intel_iommu {
 	void __iomem	*reg; /* Pointer to hardware regs, virtual addr */
 	u64		cap;
 	u64		ecap;
-	unsigned long 	*domain_ids; /* bitmap of domains */
-	struct dmar_domain **domains; /* ptr to domains */
 	int		seg;
 	u32		gcmd; /* Holds TE, EAFL. Don't need SRTP, SFL, WBF */
-	spinlock_t	lock; /* protect context, domain ids */
 	spinlock_t	register_lock; /* protect register handling */
+	int		seq_id;	/* sequence id of the iommu */
+
+#ifdef CONFIG_DMAR
+	unsigned long 	*domain_ids; /* bitmap of domains */
+	struct dmar_domain **domains; /* ptr to domains */
+	spinlock_t	lock; /* protect context, domain ids */
 	struct root_entry *root_entry; /* virtual address */
 
 	unsigned int irq;
 	unsigned char name[7];    /* Device Name */
 	struct msi_msg saved_msg;
 	struct sys_device sysdev;
+#endif
+	struct q_inval  *qi;            /* Queued invalidation info */
+#ifdef CONFIG_INTR_REMAP
+	struct ir_table *ir_table;	/* Interrupt remapping info */
+#endif
 };
 
-#ifndef CONFIG_DMAR_GFX_WA
-static inline void iommu_prepare_gfx_mapping(void)
+static inline void __iommu_flush_cache(
+	struct intel_iommu *iommu, void *addr, int size)
 {
-	return;
+	if (!ecap_coherent(iommu->ecap))
+		clflush_cache_range(addr, size);
 }
-#endif /* !CONFIG_DMAR_GFX_WA */
 
+extern struct dmar_drhd_unit * dmar_find_matched_drhd_unit(struct pci_dev *dev);
+
+extern int alloc_iommu(struct dmar_drhd_unit *drhd);
+extern void free_iommu(struct intel_iommu *iommu);
+extern int dmar_enable_qi(struct intel_iommu *iommu);
+extern void qi_global_iec(struct intel_iommu *iommu);
+
+extern void qi_submit_sync(struct qi_desc *desc, struct intel_iommu *iommu);
 #endif
diff --git a/drivers/pci/intr_remapping.c b/drivers/pci/intr_remapping.c
new file mode 100644
index 0000000..bb642cc
--- /dev/null
+++ b/drivers/pci/intr_remapping.c
@@ -0,0 +1,471 @@
+#include <linux/dmar.h>
+#include <linux/spinlock.h>
+#include <linux/jiffies.h>
+#include <linux/pci.h>
+#include <linux/irq.h>
+#include <asm/io_apic.h>
+#include "intel-iommu.h"
+#include "intr_remapping.h"
+
+static struct ioapic_scope ir_ioapic[MAX_IO_APICS];
+static int ir_ioapic_num;
+int intr_remapping_enabled;
+
+static struct {
+	struct intel_iommu *iommu;
+	u16 irte_index;
+	u16 sub_handle;
+	u8  irte_mask;
+} irq_2_iommu[NR_IRQS];
+
+static DEFINE_SPINLOCK(irq_2_ir_lock);
+
+int irq_remapped(int irq)
+{
+	if (irq > NR_IRQS)
+		return 0;
+
+	if (!irq_2_iommu[irq].iommu)
+		return 0;
+
+	return 1;
+}
+
+int get_irte(int irq, struct irte *entry)
+{
+	int index;
+
+	if (!entry || irq > NR_IRQS)
+		return -1;
+
+	spin_lock(&irq_2_ir_lock);
+	if (!irq_2_iommu[irq].iommu) {
+		spin_unlock(&irq_2_ir_lock);
+		return -1;
+	}
+
+	index = irq_2_iommu[irq].irte_index + irq_2_iommu[irq].sub_handle;
+	*entry = *(irq_2_iommu[irq].iommu->ir_table->base + index);
+
+	spin_unlock(&irq_2_ir_lock);
+	return 0;
+}
+
+int alloc_irte(struct intel_iommu *iommu, int irq, u16 count)
+{
+	struct ir_table *table = iommu->ir_table;
+	u16 index, start_index;
+	unsigned int mask = 0;
+	int i;
+
+	if (!count)
+		return -1;
+
+	/*
+	 * start the IRTE search from index 0.
+	 */
+	index = start_index = 0;
+
+	if (count > 1) {
+		count = __roundup_pow_of_two(count);
+		mask = ilog2(count);
+	}
+
+	if (mask > ecap_max_handle_mask(iommu->ecap)) {
+		printk(KERN_ERR
+		       "Requested mask %x exceeds the max invalidation handle"
+		       " mask value %Lx\n", mask,
+		       ecap_max_handle_mask(iommu->ecap));
+		return -1;
+	}
+
+	spin_lock(&irq_2_ir_lock);
+	do {
+		for (i = index; i < index + count; i++)
+			if  (table->base[i].present)
+				break;
+		/* empty index found */
+		if (i == index + count)
+			break;
+
+		index = (index + count) % INTR_REMAP_TABLE_ENTRIES;
+
+		if (index == start_index) {
+			spin_unlock(&irq_2_ir_lock);
+			printk(KERN_ERR "can't allocate an IRTE\n");
+			return -1;
+		}
+	} while (1);
+
+	for (i = index; i < index + count; i++)
+		table->base[i].present = 1;
+
+	irq_2_iommu[irq].iommu = iommu;
+	irq_2_iommu[irq].irte_index =  index;
+	irq_2_iommu[irq].sub_handle = 0;
+	irq_2_iommu[irq].irte_mask = mask;
+
+	spin_unlock(&irq_2_ir_lock);
+
+	return index;
+}
+
+static void qi_flush_iec(struct intel_iommu *iommu, int index, int mask)
+{
+	struct qi_desc desc;
+
+	desc.low = QI_IEC_IIDEX(index) | QI_IEC_TYPE | QI_IEC_IM(mask)
+		   | QI_IEC_SELECTIVE;
+	desc.high = 0;
+
+	qi_submit_sync(&desc, iommu);
+}
+
+int map_irq_to_irte_handle(int irq, u16 *sub_handle)
+{
+	int index;
+
+	spin_lock(&irq_2_ir_lock);
+	if (irq >= NR_IRQS || !irq_2_iommu[irq].iommu) {
+		spin_unlock(&irq_2_ir_lock);
+		return -1;
+	}
+
+	*sub_handle = irq_2_iommu[irq].sub_handle;
+	index = irq_2_iommu[irq].irte_index;
+	spin_unlock(&irq_2_ir_lock);
+	return index;
+}
+
+int set_irte_irq(int irq, struct intel_iommu *iommu, u16 index, u16 subhandle)
+{
+	spin_lock(&irq_2_ir_lock);
+	if (irq >= NR_IRQS || irq_2_iommu[irq].iommu) {
+		spin_unlock(&irq_2_ir_lock);
+		return -1;
+	}
+
+	irq_2_iommu[irq].iommu = iommu;
+	irq_2_iommu[irq].irte_index = index;
+	irq_2_iommu[irq].sub_handle = subhandle;
+	irq_2_iommu[irq].irte_mask = 0;
+
+	spin_unlock(&irq_2_ir_lock);
+
+	return 0;
+}
+
+int clear_irte_irq(int irq, struct intel_iommu *iommu, u16 index)
+{
+	spin_lock(&irq_2_ir_lock);
+	if (irq >= NR_IRQS || !irq_2_iommu[irq].iommu) {
+		spin_unlock(&irq_2_ir_lock);
+		return -1;
+	}
+
+	irq_2_iommu[irq].iommu = NULL;
+	irq_2_iommu[irq].irte_index = 0;
+	irq_2_iommu[irq].sub_handle = 0;
+	irq_2_iommu[irq].irte_mask = 0;
+
+	spin_unlock(&irq_2_ir_lock);
+
+	return 0;
+}
+
+int modify_irte(int irq, struct irte *irte_modified)
+{
+	int index;
+	struct irte *irte;
+	struct intel_iommu *iommu;
+
+	spin_lock(&irq_2_ir_lock);
+	if (irq >= NR_IRQS || !irq_2_iommu[irq].iommu) {
+		spin_unlock(&irq_2_ir_lock);
+		return -1;
+	}
+
+	iommu = irq_2_iommu[irq].iommu;
+
+	index = irq_2_iommu[irq].irte_index + irq_2_iommu[irq].sub_handle;
+	irte = &iommu->ir_table->base[index];
+
+	set_64bit((unsigned long *)irte, irte_modified->low | (1 << 1));
+	__iommu_flush_cache(iommu, irte, sizeof(*irte));
+
+	qi_flush_iec(iommu, index, 0);
+
+	spin_unlock(&irq_2_ir_lock);
+	return 0;
+}
+
+int flush_irte(int irq)
+{
+	int index;
+	struct intel_iommu *iommu;
+
+	spin_lock(&irq_2_ir_lock);
+	if (irq >= NR_IRQS || !irq_2_iommu[irq].iommu) {
+		spin_unlock(&irq_2_ir_lock);
+		return -1;
+	}
+
+	iommu = irq_2_iommu[irq].iommu;
+
+	index = irq_2_iommu[irq].irte_index + irq_2_iommu[irq].sub_handle;
+
+	qi_flush_iec(iommu, index, irq_2_iommu[irq].irte_mask);
+	spin_unlock(&irq_2_ir_lock);
+
+	return 0;
+}
+
+struct intel_iommu *map_ioapic_to_ir(int apic)
+{
+	int i;
+
+	for (i = 0; i < MAX_IO_APICS; i++)
+		if (ir_ioapic[i].id == apic)
+			return ir_ioapic[i].iommu;
+	return NULL;
+}
+
+struct intel_iommu *map_dev_to_ir(struct pci_dev *dev)
+{
+	struct dmar_drhd_unit *drhd;
+
+	drhd = dmar_find_matched_drhd_unit(dev);
+	if (!drhd)
+		return NULL;
+
+	return drhd->iommu;
+}
+
+int free_irte(int irq)
+{
+	int index, i;
+	struct irte *irte;
+	struct intel_iommu *iommu;
+
+	spin_lock(&irq_2_ir_lock);
+	if (irq >= NR_IRQS || !irq_2_iommu[irq].iommu) {
+		spin_unlock(&irq_2_ir_lock);
+		return -1;
+	}
+
+	iommu = irq_2_iommu[irq].iommu;
+
+	index = irq_2_iommu[irq].irte_index + irq_2_iommu[irq].sub_handle;
+	irte = &iommu->ir_table->base[index];
+
+	if (!irq_2_iommu[irq].sub_handle) {
+		for (i = 0; i < (1 << irq_2_iommu[irq].irte_mask); i++)
+			set_64bit((unsigned long *)irte, 0);
+		qi_flush_iec(iommu, index, irq_2_iommu[irq].irte_mask);
+	}
+
+	irq_2_iommu[irq].iommu = NULL;
+	irq_2_iommu[irq].irte_index = 0;
+	irq_2_iommu[irq].sub_handle = 0;
+	irq_2_iommu[irq].irte_mask = 0;
+
+	spin_unlock(&irq_2_ir_lock);
+
+	return 0;
+}
+
+static void iommu_set_intr_remapping(struct intel_iommu *iommu, int mode)
+{
+	u64 addr;
+	u32 cmd, sts;
+	unsigned long flags;
+
+	addr = virt_to_phys((void *)iommu->ir_table->base);
+
+	spin_lock_irqsave(&iommu->register_lock, flags);
+
+	dmar_writeq(iommu->reg + DMAR_IRTA_REG,
+		    (addr) | IR_X2APIC_MODE(mode) | INTR_REMAP_TABLE_REG_SIZE);
+
+	/* Set interrupt-remapping table pointer */
+	cmd = iommu->gcmd | DMA_GCMD_SIRTP;
+	writel(cmd, iommu->reg + DMAR_GCMD_REG);
+
+	IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG,
+		      readl, (sts & DMA_GSTS_IRTPS), sts);
+	spin_unlock_irqrestore(&iommu->register_lock, flags);
+
+	/*
+	 * global invalidation of interrupt entry cache before enabling
+	 * interrupt-remapping.
+	 */
+	qi_global_iec(iommu);
+
+	spin_lock_irqsave(&iommu->register_lock, flags);
+
+	/* Enable interrupt-remapping */
+	cmd = iommu->gcmd | DMA_GCMD_IRE;
+	iommu->gcmd |= DMA_GCMD_IRE;
+	writel(cmd, iommu->reg + DMAR_GCMD_REG);
+
+	IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG,
+		      readl, (sts & DMA_GSTS_IRES), sts);
+
+	spin_unlock_irqrestore(&iommu->register_lock, flags);
+}
+
+
+static int setup_intr_remapping(struct intel_iommu *iommu, int mode)
+{
+	struct ir_table *ir_table;
+	struct page *pages;
+
+	ir_table = iommu->ir_table = kzalloc(sizeof(struct ir_table),
+					     GFP_KERNEL);
+
+	if (!iommu->ir_table)
+		return -ENOMEM;
+
+	pages = alloc_pages(GFP_KERNEL | __GFP_ZERO, INTR_REMAP_PAGE_ORDER);
+
+	if (!pages) {
+		printk(KERN_ERR "failed to allocate pages of order %d\n",
+		       INTR_REMAP_PAGE_ORDER);
+		kfree(iommu->ir_table);
+		return -ENOMEM;
+	}
+
+	ir_table->base = page_address(pages);
+
+	iommu_set_intr_remapping(iommu, mode);
+	return 0;
+}
+
+int __init enable_intr_remapping(int eim)
+{
+	struct dmar_drhd_unit *drhd;
+	int setup = 0;
+
+	/*
+	 * check for the Interrupt-remapping support
+	 */
+	for_each_drhd_unit(drhd) {
+		struct intel_iommu *iommu = drhd->iommu;
+
+		if (!ecap_ir_support(iommu->ecap))
+			continue;
+
+		if (eim && !ecap_eim_support(iommu->ecap)) {
+			printk(KERN_INFO "DRHD %Lx: EIM not supported by DRHD, "
+			       " ecap %Lx\n", drhd->reg_base_addr, iommu->ecap);
+			return -1;
+		}
+	}
+
+	/*
+	 * Enable queued invalidation for all the DRHD's.
+	 */
+	for_each_drhd_unit(drhd) {
+		int ret;
+		struct intel_iommu *iommu = drhd->iommu;
+		ret = dmar_enable_qi(iommu);
+
+		if (ret) {
+			printk(KERN_ERR "DRHD %Lx: failed to enable queued, "
+			       " invalidation, ecap %Lx, ret %d\n",
+			       drhd->reg_base_addr, iommu->ecap, ret);
+			return -1;
+		}
+	}
+
+	/*
+	 * Setup Interrupt-remapping for all the DRHD's now.
+	 */
+	for_each_drhd_unit(drhd) {
+		struct intel_iommu *iommu = drhd->iommu;
+
+		if (!ecap_ir_support(iommu->ecap))
+			continue;
+
+		if (setup_intr_remapping(iommu, eim))
+			goto error;
+
+		setup = 1;
+	}
+
+	if (!setup)
+		goto error;
+
+	intr_remapping_enabled = 1;
+
+	return 0;
+
+error:
+	/*
+	 * handle error condition gracefully here!
+	 */
+	return -1;
+}
+
+static int ir_parse_ioapic_scope(struct acpi_dmar_header *header,
+				 struct intel_iommu *iommu)
+{
+	struct acpi_dmar_hardware_unit *drhd;
+	struct acpi_dmar_device_scope *scope;
+	void *start, *end;
+
+	drhd = (struct acpi_dmar_hardware_unit *)header;
+
+	start = (void *)(drhd + 1);
+	end = ((void *)drhd) + header->length;
+
+	while (start < end) {
+		scope = start;
+		if (scope->entry_type == ACPI_DMAR_SCOPE_TYPE_IOAPIC) {
+			if (ir_ioapic_num == MAX_IO_APICS) {
+				printk(KERN_WARNING "Exceeded Max IO APICS\n");
+				return -1;
+			}
+
+			printk(KERN_INFO "IOAPIC id %d under DRHD base"
+			       " 0x%Lx\n", scope->enumeration_id,
+			       drhd->address);
+
+			ir_ioapic[ir_ioapic_num].iommu = iommu;
+			ir_ioapic[ir_ioapic_num].id = scope->enumeration_id;
+			ir_ioapic_num++;
+		}
+		start += scope->length;
+	}
+
+	return 0;
+}
+
+/*
+ * Finds the assocaition between IOAPIC's and its Interrupt-remapping
+ * hardware unit.
+ */
+int __init parse_ioapics_under_ir(void)
+{
+	struct dmar_drhd_unit *drhd;
+	int ir_supported = 0;
+
+	for_each_drhd_unit(drhd) {
+		struct intel_iommu *iommu = drhd->iommu;
+
+		if (ecap_ir_support(iommu->ecap)) {
+			if (ir_parse_ioapic_scope(drhd->hdr, iommu))
+				return -1;
+
+			ir_supported = 1;
+		}
+	}
+
+	if (ir_supported && ir_ioapic_num != nr_ioapics) {
+		printk(KERN_WARNING
+		       "Not all IO-APIC's listed under remapping hardware\n");
+		return -1;
+	}
+
+	return ir_supported;
+}
diff --git a/drivers/pci/intr_remapping.h b/drivers/pci/intr_remapping.h
new file mode 100644
index 0000000..05f2635
--- /dev/null
+++ b/drivers/pci/intr_remapping.h
@@ -0,0 +1,8 @@
+#include "intel-iommu.h"
+
+struct ioapic_scope {
+	struct intel_iommu *iommu;
+	unsigned int id;
+};
+
+#define IR_X2APIC_MODE(mode) (mode ? (1 << 11) : 0)
diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c
index 9c71858..77baff0 100644
--- a/drivers/pci/pci-sysfs.c
+++ b/drivers/pci/pci-sysfs.c
@@ -16,6 +16,7 @@
 
 
 #include <linux/kernel.h>
+#include <linux/sched.h>
 #include <linux/pci.h>
 #include <linux/stat.h>
 #include <linux/topology.h>
@@ -484,6 +485,21 @@
 #endif /* HAVE_PCI_LEGACY */
 
 #ifdef HAVE_PCI_MMAP
+
+static int pci_mmap_fits(struct pci_dev *pdev, int resno, struct vm_area_struct *vma)
+{
+	unsigned long nr, start, size;
+
+	nr = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
+	start = vma->vm_pgoff;
+	size = pci_resource_len(pdev, resno) >> PAGE_SHIFT;
+	if (start < size && size - start >= nr)
+		return 1;
+	WARN(1, "process \"%s\" tried to map 0x%08lx-0x%08lx on %s BAR %d (size 0x%08lx)\n",
+		current->comm, start, start+nr, pci_name(pdev), resno, size);
+	return 0;
+}
+
 /**
  * pci_mmap_resource - map a PCI resource into user memory space
  * @kobj: kobject for mapping
@@ -510,6 +526,9 @@
 	if (i >= PCI_ROM_RESOURCE)
 		return -ENODEV;
 
+	if (!pci_mmap_fits(pdev, i, vma))
+		return -EINVAL;
+
 	/* pci_mmap_page_range() expects the same kind of entry as coming
 	 * from /proc/bus/pci/ which is a "user visible" value. If this is
 	 * different from the resource itself, arch will do necessary fixup.
diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c
index 9a7c9e1..851f5b8 100644
--- a/drivers/pci/pcie/aspm.c
+++ b/drivers/pci/pcie/aspm.c
@@ -527,7 +527,7 @@
 		 */
 		pci_read_config_dword(child_dev, child_pos + PCI_EXP_DEVCAP,
 			&reg32);
-		if (!(reg32 & PCI_EXP_DEVCAP_RBER && !aspm_force)) {
+		if (!(reg32 & PCI_EXP_DEVCAP_RBER) && !aspm_force) {
 			printk("Pre-1.1 PCIe device detected, "
 				"disable ASPM for %s. It can be enabled forcedly"
 				" with 'pcie_aspm=force'\n", pci_name(pdev));
diff --git a/drivers/pci/search.c b/drivers/pci/search.c
index 3b3b5f1..4edfc47 100644
--- a/drivers/pci/search.c
+++ b/drivers/pci/search.c
@@ -162,7 +162,7 @@
  * time.
  */
 struct pci_dev *pci_find_device(unsigned int vendor, unsigned int device,
-				const struct pci_dev *from)
+				struct pci_dev *from)
 {
 	struct pci_dev *pdev;
 
@@ -263,7 +263,7 @@
  * this file.
  */
 static struct pci_dev *pci_get_dev_by_id(const struct pci_device_id *id,
-					 const struct pci_dev *from)
+					 struct pci_dev *from)
 {
 	struct device *dev;
 	struct device *dev_start = NULL;
@@ -303,7 +303,7 @@
  */
 struct pci_dev *pci_get_subsys(unsigned int vendor, unsigned int device,
 			       unsigned int ss_vendor, unsigned int ss_device,
-			       const struct pci_dev *from)
+			       struct pci_dev *from)
 {
 	struct pci_dev *pdev;
 	struct pci_device_id *id;
diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c
index 3abbfad..d5e2106 100644
--- a/drivers/pci/setup-bus.c
+++ b/drivers/pci/setup-bus.c
@@ -378,11 +378,10 @@
 	align = 0;
 	min_align = 0;
 	for (order = 0; order <= max_order; order++) {
-#ifdef CONFIG_RESOURCES_64BIT
-		resource_size_t align1 = 1ULL << (order + 20);
-#else
-		resource_size_t align1 = 1U << (order + 20);
-#endif
+		resource_size_t align1 = 1;
+
+		align1 <<= (order + 20);
+
 		if (!align)
 			min_align = align1;
 		else if (ALIGN(align + min_align, min_align) < align1)
diff --git a/drivers/pcmcia/Kconfig b/drivers/pcmcia/Kconfig
index e0f8840..f57eeae 100644
--- a/drivers/pcmcia/Kconfig
+++ b/drivers/pcmcia/Kconfig
@@ -220,7 +220,8 @@
 	tristate "PXA2xx support"
 	depends on ARM && ARCH_PXA && PCMCIA
 	depends on (ARCH_LUBBOCK || MACH_MAINSTONE || PXA_SHARPSL \
-		    || MACH_ARMCORE || ARCH_PXA_PALM)
+		    || MACH_ARMCORE || ARCH_PXA_PALM || TRIZEPS_PCMCIA \
+		    || ARCH_VIPER)
 	help
 	  Say Y here to include support for the PXA2xx PCMCIA controller
 
diff --git a/drivers/pcmcia/Makefile b/drivers/pcmcia/Makefile
index 269a9e9..74d1c90 100644
--- a/drivers/pcmcia/Makefile
+++ b/drivers/pcmcia/Makefile
@@ -2,10 +2,6 @@
 # Makefile for the kernel pcmcia subsystem (c/o David Hinds)
 #
 
-ifeq ($(CONFIG_PCMCIA_DEBUG),y)
-EXTRA_CFLAGS += -DDEBUG
-endif
-
 pcmcia_core-y					+= cs.o cistpl.o rsrc_mgr.o socket_sysfs.o
 pcmcia_core-$(CONFIG_CARDBUS)			+= cardbus.o
 obj-$(CONFIG_PCCARD)				+= pcmcia_core.o
@@ -29,7 +25,6 @@
 obj-$(CONFIG_HD64465_PCMCIA)			+= hd64465_ss.o
 obj-$(CONFIG_PCMCIA_SA1100)			+= sa11xx_core.o sa1100_cs.o
 obj-$(CONFIG_PCMCIA_SA1111)			+= sa11xx_core.o sa1111_cs.o
-obj-$(CONFIG_PCMCIA_PXA2XX)                     += pxa2xx_core.o pxa2xx_cs.o
 obj-$(CONFIG_M32R_PCC)				+= m32r_pcc.o
 obj-$(CONFIG_M32R_CFC)				+= m32r_cfc.o
 obj-$(CONFIG_PCMCIA_AU1X00)			+= au1x00_ss.o
@@ -68,9 +63,14 @@
 sa1100_cs-$(CONFIG_SA1100_SHANNON)		+= sa1100_shannon.o
 sa1100_cs-$(CONFIG_SA1100_SIMPAD)		+= sa1100_simpad.o
 
-pxa2xx_cs-$(CONFIG_ARCH_LUBBOCK)		+= pxa2xx_lubbock.o sa1111_generic.o
-pxa2xx_cs-$(CONFIG_MACH_MAINSTONE)		+= pxa2xx_mainstone.o
-pxa2xx_cs-$(CONFIG_PXA_SHARPSL)			+= pxa2xx_sharpsl.o
-pxa2xx_cs-$(CONFIG_MACH_ARMCORE)		+= pxa2xx_cm_x270.o
-pxa2xx_cs-$(CONFIG_MACH_PALMTX)		+= pxa2xx_palmtx.o
+pxa2xx_lubbock_cs-y				+= pxa2xx_lubbock.o sa1111_generic.o
+pxa2xx-obj-$(CONFIG_ARCH_LUBBOCK)		+= pxa2xx_lubbock_cs.o
+pxa2xx-obj-$(CONFIG_MACH_MAINSTONE)		+= pxa2xx_mainstone.o
+pxa2xx-obj-$(CONFIG_PXA_SHARPSL)		+= pxa2xx_sharpsl.o
+pxa2xx-obj-$(CONFIG_MACH_ARMCORE)		+= pxa2xx_cm_x2xx.o pxa2xx_cm_x255.o pxa2xx_cm_x270.o
+pxa2xx-obj-$(CONFIG_ARCH_VIPER)			+= pxa2xx_viper.o
+pxa2xx-obj-$(CONFIG_TRIZEPS_PCMCIA)		+= pxa2xx_trizeps.o
+pxa2xx-obj-$(CONFIG_MACH_PALMTX)		+= pxa2xx_palmtx.o
+pxa2xx-obj-$(CONFIG_MACH_PALMLD)		+= pxa2xx_palmld.o
 
+obj-$(CONFIG_PCMCIA_PXA2XX)			+= pxa2xx_core.o $(pxa2xx-obj-y)
diff --git a/drivers/pcmcia/au1000_generic.c b/drivers/pcmcia/au1000_generic.c
index 75e8f85..fc1de46 100644
--- a/drivers/pcmcia/au1000_generic.c
+++ b/drivers/pcmcia/au1000_generic.c
@@ -292,7 +292,7 @@
 		skt->spd_io[map->map] = speed;
 	}
 
-	map->start=(ioaddr_t)(u32)skt->virt_io;
+	map->start=(unsigned int)(u32)skt->virt_io;
 	map->stop=map->start+MAP_SIZE;
 	return 0;
 
diff --git a/drivers/pcmcia/au1000_generic.h b/drivers/pcmcia/au1000_generic.h
index a53ef59..13a4fbc 100644
--- a/drivers/pcmcia/au1000_generic.h
+++ b/drivers/pcmcia/au1000_generic.h
@@ -116,7 +116,7 @@
 	struct resource		res_attr;
 
 	void *                 	virt_io;
-	ioaddr_t              	phys_io;
+	unsigned int		phys_io;
 	unsigned int           	phys_attr;
 	unsigned int           	phys_mem;
 	unsigned short        	speed_io, speed_attr, speed_mem;
diff --git a/drivers/pcmcia/au1000_pb1x00.c b/drivers/pcmcia/au1000_pb1x00.c
index aa1cd4d..d6b4bd1 100644
--- a/drivers/pcmcia/au1000_pb1x00.c
+++ b/drivers/pcmcia/au1000_pb1x00.c
@@ -37,7 +37,6 @@
 #include <pcmcia/ss.h>
 #include <pcmcia/cistpl.h>
 #include <pcmcia/bus_ops.h>
-#include "cs_internal.h"
 
 #include <asm/io.h>
 #include <asm/irq.h>
diff --git a/drivers/pcmcia/au1000_xxs1500.c b/drivers/pcmcia/au1000_xxs1500.c
index 8a9b18c..9627390 100644
--- a/drivers/pcmcia/au1000_xxs1500.c
+++ b/drivers/pcmcia/au1000_xxs1500.c
@@ -41,7 +41,6 @@
 #include <pcmcia/ss.h>
 #include <pcmcia/cistpl.h>
 #include <pcmcia/bus_ops.h>
-#include "cs_internal.h"
 
 #include <asm/io.h>
 #include <asm/irq.h>
diff --git a/drivers/pcmcia/cardbus.c b/drivers/pcmcia/cardbus.c
index 911ca0e..db77e1f 100644
--- a/drivers/pcmcia/cardbus.c
+++ b/drivers/pcmcia/cardbus.c
@@ -238,7 +238,7 @@
 	pci_bus_add_devices(bus);
 
 	s->irq.AssignedIRQ = s->pci_irq;
-	return CS_SUCCESS;
+	return 0;
 }
 
 void cb_free(struct pcmcia_socket * s)
diff --git a/drivers/pcmcia/cistpl.c b/drivers/pcmcia/cistpl.c
index 65129b5..dcce9f5 100644
--- a/drivers/pcmcia/cistpl.c
+++ b/drivers/pcmcia/cistpl.c
@@ -92,7 +92,8 @@
 	if (!(s->features & SS_CAP_STATIC_MAP) && (mem->res == NULL)) {
 		mem->res = pcmcia_find_mem_region(0, s->map_size, s->map_size, 0, s);
 		if (mem->res == NULL) {
-			printk(KERN_NOTICE "cs: unable to map card memory!\n");
+			dev_printk(KERN_NOTICE, &s->dev,
+				   "cs: unable to map card memory!\n");
 			return NULL;
 		}
 		s->cis_virt = NULL;
@@ -265,13 +266,13 @@
 ======================================================================*/
 
 static void read_cis_cache(struct pcmcia_socket *s, int attr, u_int addr,
-			   u_int len, void *ptr)
+			   size_t len, void *ptr)
 {
     struct cis_cache_entry *cis;
     int ret;
 
     if (s->fake_cis) {
-	if (s->fake_cis_len > addr+len)
+	if (s->fake_cis_len >= addr+len)
 	    memcpy(ptr, s->fake_cis+addr, len);
 	else
 	    memset(ptr, 0xff, len);
@@ -351,7 +352,9 @@
 
 	buf = kmalloc(256, GFP_KERNEL);
 	if (buf == NULL)
-		return -1;
+		dev_printk(KERN_WARNING, &s->dev,
+			   "no memory for verifying CIS\n");
+		return -ENOMEM;
 	list_for_each_entry(cis, &s->cis_cache, node) {
 		int len = cis->len;
 
@@ -380,18 +383,22 @@
     
 ======================================================================*/
 
-int pcmcia_replace_cis(struct pcmcia_socket *s, cisdump_t *cis)
+int pcmcia_replace_cis(struct pcmcia_socket *s,
+		       const u8 *data, const size_t len)
 {
-    kfree(s->fake_cis);
-    s->fake_cis = NULL;
-    if (cis->Length > CISTPL_MAX_CIS_SIZE)
-	return CS_BAD_SIZE;
-    s->fake_cis = kmalloc(cis->Length, GFP_KERNEL);
-    if (s->fake_cis == NULL)
-	return CS_OUT_OF_RESOURCE;
-    s->fake_cis_len = cis->Length;
-    memcpy(s->fake_cis, cis->Data, cis->Length);
-    return CS_SUCCESS;
+	if (len > CISTPL_MAX_CIS_SIZE) {
+		dev_printk(KERN_WARNING, &s->dev, "replacement CIS too big\n");
+		return -EINVAL;
+	}
+	kfree(s->fake_cis);
+	s->fake_cis = kmalloc(len, GFP_KERNEL);
+	if (s->fake_cis == NULL) {
+		dev_printk(KERN_WARNING, &s->dev, "no memory to replace CIS\n");
+		return -ENOMEM;
+	}
+	s->fake_cis_len = len;
+	memcpy(s->fake_cis, data, len);
+	return 0;
 }
 EXPORT_SYMBOL(pcmcia_replace_cis);
 
@@ -418,9 +425,9 @@
 int pccard_get_first_tuple(struct pcmcia_socket *s, unsigned int function, tuple_t *tuple)
 {
     if (!s)
-	return CS_BAD_HANDLE;
+	return -EINVAL;
     if (!(s->state & SOCKET_PRESENT))
-	return CS_NO_CARD;
+	return -ENODEV;
     tuple->TupleLink = tuple->Flags = 0;
 #ifdef CONFIG_CARDBUS
     if (s->state & SOCKET_CARDBUS) {
@@ -440,10 +447,10 @@
 	!(tuple->Attributes & TUPLE_RETURN_COMMON)) {
 	cisdata_t req = tuple->DesiredTuple;
 	tuple->DesiredTuple = CISTPL_LONGLINK_MFC;
-	if (pccard_get_next_tuple(s, function, tuple) == CS_SUCCESS) {
+	if (pccard_get_next_tuple(s, function, tuple) == 0) {
 	    tuple->DesiredTuple = CISTPL_LINKTARGET;
-	    if (pccard_get_next_tuple(s, function, tuple) != CS_SUCCESS)
-		return CS_NO_MORE_ITEMS;
+	    if (pccard_get_next_tuple(s, function, tuple) != 0)
+		return -ENOSPC;
 	} else
 	    tuple->CISOffset = tuple->TupleLink = 0;
 	tuple->DesiredTuple = req;
@@ -498,9 +505,9 @@
     int ofs, i, attr;
 
     if (!s)
-	return CS_BAD_HANDLE;
+	return -EINVAL;
     if (!(s->state & SOCKET_PRESENT))
-	return CS_NO_CARD;
+	return -ENODEV;
 
     link[1] = tuple->TupleLink;
     ofs = tuple->CISOffset + tuple->TupleLink;
@@ -519,7 +526,7 @@
 	/* End of chain?  Follow long link if possible */
 	if (link[0] == CISTPL_END) {
 	    if ((ofs = follow_link(s, tuple)) < 0)
-		return CS_NO_MORE_ITEMS;
+		return -ENOSPC;
 	    attr = SPACE(tuple->Flags);
 	    read_cis_cache(s, attr, ofs, 2, link);
 	}
@@ -577,13 +584,13 @@
     }
     if (i == MAX_TUPLES) {
 	cs_dbg(s, 1, "cs: overrun in pcmcia_get_next_tuple\n");
-	return CS_NO_MORE_ITEMS;
+	return -ENOSPC;
     }
     
     tuple->TupleCode = link[0];
     tuple->TupleLink = link[1];
     tuple->CISOffset = ofs + 2;
-    return CS_SUCCESS;
+    return 0;
 }
 EXPORT_SYMBOL(pccard_get_next_tuple);
 
@@ -596,18 +603,18 @@
     u_int len;
 
     if (!s)
-	return CS_BAD_HANDLE;
+	return -EINVAL;
 
     if (tuple->TupleLink < tuple->TupleOffset)
-	return CS_NO_MORE_ITEMS;
+	return -ENOSPC;
     len = tuple->TupleLink - tuple->TupleOffset;
     tuple->TupleDataLen = tuple->TupleLink;
     if (len == 0)
-	return CS_SUCCESS;
+	return 0;
     read_cis_cache(s, SPACE(tuple->Flags),
 		   tuple->CISOffset + tuple->TupleOffset,
 		   _MIN(len, tuple->TupleDataMax), tuple->TupleData);
-    return CS_SUCCESS;
+    return 0;
 }
 EXPORT_SYMBOL(pccard_get_tuple_data);
 
@@ -640,25 +647,31 @@
 	case 3: device->dev[i].speed = 150; break;
 	case 4: device->dev[i].speed = 100; break;
 	case 7:
-	    if (++p == q) return CS_BAD_TUPLE;
+	    if (++p == q)
+		    return -EINVAL;
 	    device->dev[i].speed = SPEED_CVT(*p);
 	    while (*p & 0x80)
-		if (++p == q) return CS_BAD_TUPLE;
+		if (++p == q)
+			return -EINVAL;
 	    break;
 	default:
-	    return CS_BAD_TUPLE;
+	    return -EINVAL;
 	}
 
-	if (++p == q) return CS_BAD_TUPLE;
-	if (*p == 0xff) break;
+	if (++p == q)
+		return -EINVAL;
+	if (*p == 0xff)
+		break;
 	scale = *p & 7;
-	if (scale == 7) return CS_BAD_TUPLE;
+	if (scale == 7)
+		return -EINVAL;
 	device->dev[i].size = ((*p >> 3) + 1) * (512 << (scale*2));
 	device->ndev++;
-	if (++p == q) break;
+	if (++p == q)
+		break;
     }
     
-    return CS_SUCCESS;
+    return 0;
 }
 
 /*====================================================================*/
@@ -667,12 +680,12 @@
 {
     u_char *p;
     if (tuple->TupleDataLen < 5)
-	return CS_BAD_TUPLE;
+	return -EINVAL;
     p = (u_char *) tuple->TupleData;
     csum->addr = tuple->CISOffset + get_unaligned_le16(p) - 2;
     csum->len = get_unaligned_le16(p + 2);
     csum->sum = *(p + 4);
-    return CS_SUCCESS;
+    return 0;
 }
 
 /*====================================================================*/
@@ -680,9 +693,9 @@
 static int parse_longlink(tuple_t *tuple, cistpl_longlink_t *link)
 {
     if (tuple->TupleDataLen < 4)
-	return CS_BAD_TUPLE;
+	return -EINVAL;
     link->addr = get_unaligned_le32(tuple->TupleData);
-    return CS_SUCCESS;
+    return 0;
 }
 
 /*====================================================================*/
@@ -697,13 +710,13 @@
     
     link->nfn = *p; p++;
     if (tuple->TupleDataLen <= link->nfn*5)
-	return CS_BAD_TUPLE;
+	return -EINVAL;
     for (i = 0; i < link->nfn; i++) {
 	link->fn[i].space = *p; p++;
 	link->fn[i].addr = get_unaligned_le32(p);
 	p += 4;
     }
-    return CS_SUCCESS;
+    return 0;
 }
 
 /*====================================================================*/
@@ -713,24 +726,27 @@
 {
     int i, j, ns;
 
-    if (p == q) return CS_BAD_TUPLE;
+    if (p == q)
+	    return -EINVAL;
     ns = 0; j = 0;
     for (i = 0; i < max; i++) {
-	if (*p == 0xff) break;
+	if (*p == 0xff)
+		break;
 	ofs[i] = j;
 	ns++;
 	for (;;) {
 	    s[j++] = (*p == 0xff) ? '\0' : *p;
 	    if ((*p == '\0') || (*p == 0xff)) break;
-	    if (++p == q) return CS_BAD_TUPLE;
+	    if (++p == q)
+		    return -EINVAL;
 	}
 	if ((*p == 0xff) || (++p == q)) break;
     }
     if (found) {
 	*found = ns;
-	return CS_SUCCESS;
+	return 0;
     } else {
-	return (ns == max) ? CS_SUCCESS : CS_BAD_TUPLE;
+	return (ns == max) ? 0 : -EINVAL;
     }
 }
 
@@ -745,7 +761,8 @@
     
     vers_1->major = *p; p++;
     vers_1->minor = *p; p++;
-    if (p >= q) return CS_BAD_TUPLE;
+    if (p >= q)
+	    return -EINVAL;
 
     return parse_strings(p, q, CISTPL_VERS_1_MAX_PROD_STRINGS,
 			 vers_1->str, vers_1->ofs, &vers_1->ns);
@@ -781,7 +798,7 @@
 	p += 2;
     }
     jedec->nid = nid;
-    return CS_SUCCESS;
+    return 0;
 }
 
 /*====================================================================*/
@@ -789,10 +806,10 @@
 static int parse_manfid(tuple_t *tuple, cistpl_manfid_t *m)
 {
     if (tuple->TupleDataLen < 4)
-	return CS_BAD_TUPLE;
+	return -EINVAL;
     m->manf = get_unaligned_le16(tuple->TupleData);
     m->card = get_unaligned_le16(tuple->TupleData + 2);
-    return CS_SUCCESS;
+    return 0;
 }
 
 /*====================================================================*/
@@ -801,11 +818,11 @@
 {
     u_char *p;
     if (tuple->TupleDataLen < 2)
-	return CS_BAD_TUPLE;
+	return -EINVAL;
     p = (u_char *)tuple->TupleData;
     f->func = p[0];
     f->sysinit = p[1];
-    return CS_SUCCESS;
+    return 0;
 }
 
 /*====================================================================*/
@@ -815,12 +832,12 @@
     u_char *p;
     int i;
     if (tuple->TupleDataLen < 1)
-	return CS_BAD_TUPLE;
+	return -EINVAL;
     p = (u_char *)tuple->TupleData;
     f->type = p[0];
     for (i = 1; i < tuple->TupleDataLen; i++)
 	f->data[i-1] = p[i];
-    return CS_SUCCESS;
+    return 0;
 }
 
 /*====================================================================*/
@@ -834,7 +851,7 @@
     rasz = *p & 0x03;
     rmsz = (*p & 0x3c) >> 2;
     if (tuple->TupleDataLen < rasz+rmsz+4)
-	return CS_BAD_TUPLE;
+	return -EINVAL;
     config->last_idx = *(++p);
     p++;
     config->base = 0;
@@ -846,7 +863,7 @@
     for (i = 0; i <= rmsz; i++)
 	config->rmask[i>>2] += p[i] << (8*(i%4));
     config->subtuples = tuple->TupleDataLen - (rasz+rmsz+4);
-    return CS_SUCCESS;
+    return 0;
 }
 
 /*======================================================================
@@ -1002,10 +1019,12 @@
 
 static u_char *parse_irq(u_char *p, u_char *q, cistpl_irq_t *irq)
 {
-    if (p == q) return NULL;
+    if (p == q)
+	    return NULL;
     irq->IRQInfo1 = *p; p++;
     if (irq->IRQInfo1 & IRQ_INFO2_VALID) {
-	if (p+2 > q) return NULL;
+	if (p+2 > q)
+		return NULL;
 	irq->IRQInfo2 = (p[1]<<8) + p[0];
 	p += 2;
     }
@@ -1026,7 +1045,8 @@
     if (*p & 0x40)
 	entry->flags |= CISTPL_CFTABLE_DEFAULT;
     if (*p & 0x80) {
-	if (++p == q) return CS_BAD_TUPLE;
+	if (++p == q)
+		return -EINVAL;
 	if (*p & 0x10)
 	    entry->flags |= CISTPL_CFTABLE_BVDS;
 	if (*p & 0x20)
@@ -1040,30 +1060,35 @@
 	entry->interface = 0;
 
     /* Process optional features */
-    if (++p == q) return CS_BAD_TUPLE;
+    if (++p == q)
+	    return -EINVAL;
     features = *p; p++;
 
     /* Power options */
     if ((features & 3) > 0) {
 	p = parse_power(p, q, &entry->vcc);
-	if (p == NULL) return CS_BAD_TUPLE;
+	if (p == NULL)
+		return -EINVAL;
     } else
 	entry->vcc.present = 0;
     if ((features & 3) > 1) {
 	p = parse_power(p, q, &entry->vpp1);
-	if (p == NULL) return CS_BAD_TUPLE;
+	if (p == NULL)
+		return -EINVAL;
     } else
 	entry->vpp1.present = 0;
     if ((features & 3) > 2) {
 	p = parse_power(p, q, &entry->vpp2);
-	if (p == NULL) return CS_BAD_TUPLE;
+	if (p == NULL)
+		return -EINVAL;
     } else
 	entry->vpp2.present = 0;
 
     /* Timing options */
     if (features & 0x04) {
 	p = parse_timing(p, q, &entry->timing);
-	if (p == NULL) return CS_BAD_TUPLE;
+	if (p == NULL)
+		return -EINVAL;
     } else {
 	entry->timing.wait = 0;
 	entry->timing.ready = 0;
@@ -1073,14 +1098,16 @@
     /* I/O window options */
     if (features & 0x08) {
 	p = parse_io(p, q, &entry->io);
-	if (p == NULL) return CS_BAD_TUPLE;
+	if (p == NULL)
+		return -EINVAL;
     } else
 	entry->io.nwin = 0;
     
     /* Interrupt options */
     if (features & 0x10) {
 	p = parse_irq(p, q, &entry->irq);
-	if (p == NULL) return CS_BAD_TUPLE;
+	if (p == NULL)
+		return -EINVAL;
     } else
 	entry->irq.IRQInfo1 = 0;
 
@@ -1094,7 +1121,8 @@
 	entry->mem.win[0].card_addr = 0;
 	entry->mem.win[0].host_addr = 0;
 	p += 2;
-	if (p > q) return CS_BAD_TUPLE;
+	if (p > q)
+		return -EINVAL;
 	break;
     case 0x40:
 	entry->mem.nwin = 1;
@@ -1102,26 +1130,30 @@
 	entry->mem.win[0].card_addr = get_unaligned_le16(p + 2) << 8;
 	entry->mem.win[0].host_addr = 0;
 	p += 4;
-	if (p > q) return CS_BAD_TUPLE;
+	if (p > q)
+		return -EINVAL;
 	break;
     case 0x60:
 	p = parse_mem(p, q, &entry->mem);
-	if (p == NULL) return CS_BAD_TUPLE;
+	if (p == NULL)
+		return -EINVAL;
 	break;
     }
 
     /* Misc features */
     if (features & 0x80) {
-	if (p == q) return CS_BAD_TUPLE;
+	if (p == q)
+		return -EINVAL;
 	entry->flags |= (*p << 8);
 	while (*p & 0x80)
-	    if (++p == q) return CS_BAD_TUPLE;
+	    if (++p == q)
+		    return -EINVAL;
 	p++;
     }
 
     entry->subtuples = q-p;
     
-    return CS_SUCCESS;
+    return 0;
 }
 
 /*====================================================================*/
@@ -1132,12 +1164,12 @@
 {
     u_char *p;
     if (tuple->TupleDataLen < 6)
-	return CS_BAD_TUPLE;
+	return -EINVAL;
     p = (u_char *)tuple->TupleData;
     bar->attr = *p;
     p += 2;
     bar->size = get_unaligned_le32(p);
-    return CS_SUCCESS;
+    return 0;
 }
 
 static int parse_config_cb(tuple_t *tuple, cistpl_config_t *config)
@@ -1146,12 +1178,12 @@
     
     p = (u_char *)tuple->TupleData;
     if ((*p != 3) || (tuple->TupleDataLen < 6))
-	return CS_BAD_TUPLE;
+	return -EINVAL;
     config->last_idx = *(++p);
     p++;
     config->base = get_unaligned_le32(p);
     config->subtuples = tuple->TupleDataLen - 6;
-    return CS_SUCCESS;
+    return 0;
 }
 
 static int parse_cftable_entry_cb(tuple_t *tuple,
@@ -1167,29 +1199,34 @@
 	entry->flags |= CISTPL_CFTABLE_DEFAULT;
 
     /* Process optional features */
-    if (++p == q) return CS_BAD_TUPLE;
+    if (++p == q)
+	    return -EINVAL;
     features = *p; p++;
 
     /* Power options */
     if ((features & 3) > 0) {
 	p = parse_power(p, q, &entry->vcc);
-	if (p == NULL) return CS_BAD_TUPLE;
+	if (p == NULL)
+		return -EINVAL;
     } else
 	entry->vcc.present = 0;
     if ((features & 3) > 1) {
 	p = parse_power(p, q, &entry->vpp1);
-	if (p == NULL) return CS_BAD_TUPLE;
+	if (p == NULL)
+		return -EINVAL;
     } else
 	entry->vpp1.present = 0;
     if ((features & 3) > 2) {
 	p = parse_power(p, q, &entry->vpp2);
-	if (p == NULL) return CS_BAD_TUPLE;
+	if (p == NULL)
+		return -EINVAL;
     } else
 	entry->vpp2.present = 0;
 
     /* I/O window options */
     if (features & 0x08) {
-	if (p == q) return CS_BAD_TUPLE;
+	if (p == q)
+		return -EINVAL;
 	entry->io = *p; p++;
     } else
 	entry->io = 0;
@@ -1197,32 +1234,37 @@
     /* Interrupt options */
     if (features & 0x10) {
 	p = parse_irq(p, q, &entry->irq);
-	if (p == NULL) return CS_BAD_TUPLE;
+	if (p == NULL)
+		return -EINVAL;
     } else
 	entry->irq.IRQInfo1 = 0;
 
     if (features & 0x20) {
-	if (p == q) return CS_BAD_TUPLE;
+	if (p == q)
+		return -EINVAL;
 	entry->mem = *p; p++;
     } else
 	entry->mem = 0;
 
     /* Misc features */
     if (features & 0x80) {
-	if (p == q) return CS_BAD_TUPLE;
+	if (p == q)
+		return -EINVAL;
 	entry->flags |= (*p << 8);
 	if (*p & 0x80) {
-	    if (++p == q) return CS_BAD_TUPLE;
+	    if (++p == q)
+		    return -EINVAL;
 	    entry->flags |= (*p << 16);
 	}
 	while (*p & 0x80)
-	    if (++p == q) return CS_BAD_TUPLE;
+	    if (++p == q)
+		    return -EINVAL;
 	p++;
     }
 
     entry->subtuples = q-p;
     
-    return CS_SUCCESS;
+    return 0;
 }
 
 #endif
@@ -1248,7 +1290,7 @@
 	p += 6;
     }
     geo->ngeo = n;
-    return CS_SUCCESS;
+    return 0;
 }
 
 /*====================================================================*/
@@ -1258,7 +1300,7 @@
     u_char *p, *q;
 
     if (tuple->TupleDataLen < 10)
-	return CS_BAD_TUPLE;
+	return -EINVAL;
     
     p = tuple->TupleData;
     q = p + tuple->TupleDataLen;
@@ -1282,15 +1324,18 @@
     
     p = tuple->TupleData;
     q = p + tuple->TupleDataLen;
-    if (p == q) return CS_BAD_TUPLE;
+    if (p == q)
+	    return -EINVAL;
     org->data_org = *p;
-    if (++p == q) return CS_BAD_TUPLE;
+    if (++p == q)
+	    return -EINVAL;
     for (i = 0; i < 30; i++) {
 	org->desc[i] = *p;
 	if (*p == '\0') break;
-	if (++p == q) return CS_BAD_TUPLE;
+	if (++p == q)
+		return -EINVAL;
     }
-    return CS_SUCCESS;
+    return 0;
 }
 
 /*====================================================================*/
@@ -1300,7 +1345,7 @@
     u_char *p;
 
     if (tuple->TupleDataLen < 10)
-	return CS_BAD_TUPLE;
+	return -EINVAL;
 
     p = tuple->TupleData;
 
@@ -1309,17 +1354,17 @@
     fmt->offset = get_unaligned_le32(p + 2);
     fmt->length = get_unaligned_le32(p + 6);
 
-    return CS_SUCCESS;
+    return 0;
 }
 
 /*====================================================================*/
 
-int pccard_parse_tuple(tuple_t *tuple, cisparse_t *parse)
+int pcmcia_parse_tuple(tuple_t *tuple, cisparse_t *parse)
 {
-    int ret = CS_SUCCESS;
+    int ret = 0;
     
     if (tuple->TupleDataLen > tuple->TupleDataMax)
-	return CS_BAD_TUPLE;
+	return -EINVAL;
     switch (tuple->TupleCode) {
     case CISTPL_DEVICE:
     case CISTPL_DEVICE_A:
@@ -1387,15 +1432,17 @@
 	break;
     case CISTPL_NO_LINK:
     case CISTPL_LINKTARGET:
-	ret = CS_SUCCESS;
+	ret = 0;
 	break;
     default:
-	ret = CS_UNSUPPORTED_FUNCTION;
+	ret = -EINVAL;
 	break;
     }
+    if (ret)
+	    __cs_dbg(0, "parse_tuple failed %d\n", ret);
     return ret;
 }
-EXPORT_SYMBOL(pccard_parse_tuple);
+EXPORT_SYMBOL(pcmcia_parse_tuple);
 
 /*======================================================================
 
@@ -1410,18 +1457,22 @@
     int ret;
 
     buf = kmalloc(256, GFP_KERNEL);
-    if (buf == NULL)
-	return CS_OUT_OF_RESOURCE;
+    if (buf == NULL) {
+	    dev_printk(KERN_WARNING, &s->dev, "no memory to read tuple\n");
+	    return -ENOMEM;
+    }
     tuple.DesiredTuple = code;
     tuple.Attributes = TUPLE_RETURN_COMMON;
     ret = pccard_get_first_tuple(s, function, &tuple);
-    if (ret != CS_SUCCESS) goto done;
+    if (ret != 0)
+	    goto done;
     tuple.TupleData = buf;
     tuple.TupleOffset = 0;
     tuple.TupleDataMax = 255;
     ret = pccard_get_tuple_data(s, &tuple);
-    if (ret != CS_SUCCESS) goto done;
-    ret = pccard_parse_tuple(&tuple, parse);
+    if (ret != 0)
+	    goto done;
+    ret = pcmcia_parse_tuple(&tuple, parse);
 done:
     kfree(buf);
     return ret;
@@ -1446,37 +1497,40 @@
     int ret, reserved, dev_ok = 0, ident_ok = 0;
 
     if (!s)
-	return CS_BAD_HANDLE;
+	return -EINVAL;
 
     tuple = kmalloc(sizeof(*tuple), GFP_KERNEL);
-    if (tuple == NULL)
-	return CS_OUT_OF_RESOURCE;
+    if (tuple == NULL) {
+	    dev_printk(KERN_WARNING, &s->dev, "no memory to validate CIS\n");
+	    return -ENOMEM;
+    }
     p = kmalloc(sizeof(*p), GFP_KERNEL);
     if (p == NULL) {
-	kfree(tuple);
-	return CS_OUT_OF_RESOURCE;
+	    kfree(tuple);
+	    dev_printk(KERN_WARNING, &s->dev, "no memory to validate CIS\n");
+	    return -ENOMEM;
     }
 
     count = reserved = 0;
     tuple->DesiredTuple = RETURN_FIRST_TUPLE;
     tuple->Attributes = TUPLE_RETURN_COMMON;
     ret = pccard_get_first_tuple(s, function, tuple);
-    if (ret != CS_SUCCESS)
+    if (ret != 0)
 	goto done;
 
     /* First tuple should be DEVICE; we should really have either that
        or a CFTABLE_ENTRY of some sort */
     if ((tuple->TupleCode == CISTPL_DEVICE) ||
-	(pccard_read_tuple(s, function, CISTPL_CFTABLE_ENTRY, p) == CS_SUCCESS) ||
-	(pccard_read_tuple(s, function, CISTPL_CFTABLE_ENTRY_CB, p) == CS_SUCCESS))
+	(pccard_read_tuple(s, function, CISTPL_CFTABLE_ENTRY, p) == 0) ||
+	(pccard_read_tuple(s, function, CISTPL_CFTABLE_ENTRY_CB, p) == 0))
 	dev_ok++;
 
     /* All cards should have a MANFID tuple, and/or a VERS_1 or VERS_2
        tuple, for card identification.  Certain old D-Link and Linksys
        cards have only a broken VERS_2 tuple; hence the bogus test. */
-    if ((pccard_read_tuple(s, function, CISTPL_MANFID, p) == CS_SUCCESS) ||
-	(pccard_read_tuple(s, function, CISTPL_VERS_1, p) == CS_SUCCESS) ||
-	(pccard_read_tuple(s, function, CISTPL_VERS_2, p) != CS_NO_MORE_ITEMS))
+    if ((pccard_read_tuple(s, function, CISTPL_MANFID, p) == 0) ||
+	(pccard_read_tuple(s, function, CISTPL_VERS_1, p) == 0) ||
+	(pccard_read_tuple(s, function, CISTPL_VERS_2, p) != -ENOSPC))
 	ident_ok++;
 
     if (!dev_ok && !ident_ok)
@@ -1484,7 +1538,8 @@
 
     for (count = 1; count < MAX_TUPLES; count++) {
 	ret = pccard_get_next_tuple(s, function, tuple);
-	if (ret != CS_SUCCESS) break;
+	if (ret != 0)
+		break;
 	if (((tuple->TupleCode > 0x23) && (tuple->TupleCode < 0x40)) ||
 	    ((tuple->TupleCode > 0x47) && (tuple->TupleCode < 0x80)) ||
 	    ((tuple->TupleCode > 0x90) && (tuple->TupleCode < 0xff)))
@@ -1499,6 +1554,6 @@
 	    *info = count;
     kfree(tuple);
     kfree(p);
-    return CS_SUCCESS;
+    return 0;
 }
 EXPORT_SYMBOL(pccard_validate_cis);
diff --git a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c
index d120739..c68c5d3 100644
--- a/drivers/pcmcia/cs.c
+++ b/drivers/pcmcia/cs.c
@@ -61,7 +61,7 @@
 /* Access speed for attribute memory windows */
 INT_MODULE_PARM(cis_speed,	300);		/* ns */
 
-#ifdef DEBUG
+#ifdef CONFIG_PCMCIA_DEBUG
 static int pc_debug;
 
 module_param(pc_debug, int, 0644);
@@ -247,7 +247,8 @@
 
 	wait_for_completion(&socket->thread_done);
 	if (!socket->thread) {
-		printk(KERN_WARNING "PCMCIA: warning: socket thread for socket %p did not start\n", socket);
+		dev_printk(KERN_WARNING, &socket->dev,
+			   "PCMCIA: warning: socket thread did not start\n");
 		return -EIO;
 	}
 
@@ -366,16 +367,16 @@
 		skt->ops->get_status(skt, &status);
 
 		if (!(status & SS_DETECT))
-			return CS_NO_CARD;
+			return -ENODEV;
 
 		if (status & SS_READY)
-			return CS_SUCCESS;
+			return 0;
 
 		msleep(unreset_check * 10);
 	}
 
 	cs_err(skt, "time out after reset.\n");
-	return CS_GENERAL_FAILURE;
+	return -ETIMEDOUT;
 }
 
 /*
@@ -412,7 +413,8 @@
 
 	s->ops->get_status(s, &status);
 	if (status & SS_POWERON) {
-		printk(KERN_ERR "PCMCIA: socket %p: *** DANGER *** unable to remove socket power\n", s);
+		dev_printk(KERN_ERR, &s->dev,
+			   "*** DANGER *** unable to remove socket power\n");
 	}
 
 	cs_socket_put(s);
@@ -426,14 +428,14 @@
 
 	skt->ops->get_status(skt, &status);
 	if (!(status & SS_DETECT))
-		return CS_NO_CARD;
+		return -ENODEV;
 
 	msleep(initial_delay * 10);
 
 	for (i = 0; i < 100; i++) {
 		skt->ops->get_status(skt, &status);
 		if (!(status & SS_DETECT))
-			return CS_NO_CARD;
+			return -ENODEV;
 
 		if (!(status & SS_PENDING))
 			break;
@@ -443,13 +445,13 @@
 
 	if (status & SS_PENDING) {
 		cs_err(skt, "voltage interrogation timed out.\n");
-		return CS_GENERAL_FAILURE;
+		return -ETIMEDOUT;
 	}
 
 	if (status & SS_CARDBUS) {
 		if (!(skt->features & SS_CAP_CARDBUS)) {
 			cs_err(skt, "cardbus cards are not supported.\n");
-			return CS_BAD_TYPE;
+			return -EINVAL;
 		}
 		skt->state |= SOCKET_CARDBUS;
 	}
@@ -463,7 +465,7 @@
 		skt->socket.Vcc = skt->socket.Vpp = 50;
 	else {
 		cs_err(skt, "unsupported voltage key.\n");
-		return CS_BAD_TYPE;
+		return -EIO;
 	}
 
 	if (skt->power_hook)
@@ -480,7 +482,7 @@
 	skt->ops->get_status(skt, &status);
 	if (!(status & SS_POWERON)) {
 		cs_err(skt, "unable to apply power.\n");
-		return CS_BAD_TYPE;
+		return -EIO;
 	}
 
 	status = socket_reset(skt);
@@ -502,15 +504,16 @@
 	cs_dbg(skt, 4, "insert\n");
 
 	if (!cs_socket_get(skt))
-		return CS_NO_CARD;
+		return -ENODEV;
 
 	ret = socket_setup(skt, setup_delay);
-	if (ret == CS_SUCCESS) {
+	if (ret == 0) {
 		skt->state |= SOCKET_PRESENT;
 
-		printk(KERN_NOTICE "pccard: %s card inserted into slot %d\n",
-		       (skt->state & SOCKET_CARDBUS) ? "CardBus" : "PCMCIA",
-		       skt->sock);
+		dev_printk(KERN_NOTICE, &skt->dev,
+			   "pccard: %s card inserted into slot %d\n",
+			   (skt->state & SOCKET_CARDBUS) ? "CardBus" : "PCMCIA",
+			   skt->sock);
 
 #ifdef CONFIG_CARDBUS
 		if (skt->state & SOCKET_CARDBUS) {
@@ -531,7 +534,7 @@
 static int socket_suspend(struct pcmcia_socket *skt)
 {
 	if (skt->state & SOCKET_SUSPEND)
-		return CS_IN_USE;
+		return -EBUSY;
 
 	send_event(skt, CS_EVENT_PM_SUSPEND, CS_EVENT_PRI_LOW);
 	skt->socket = dead_socket;
@@ -540,7 +543,7 @@
 		skt->ops->suspend(skt);
 	skt->state |= SOCKET_SUSPEND;
 
-	return CS_SUCCESS;
+	return 0;
 }
 
 /*
@@ -553,7 +556,7 @@
 	int ret;
 
 	if (!(skt->state & SOCKET_SUSPEND))
-		return CS_IN_USE;
+		return -EBUSY;
 
 	skt->socket = dead_socket;
 	skt->ops->init(skt);
@@ -565,7 +568,7 @@
 	}
 
 	ret = socket_setup(skt, resume_delay);
-	if (ret == CS_SUCCESS) {
+	if (ret == 0) {
 		/*
 		 * FIXME: need a better check here for cardbus cards.
 		 */
@@ -590,12 +593,13 @@
 
 	skt->state &= ~SOCKET_SUSPEND;
 
-	return CS_SUCCESS;
+	return 0;
 }
 
 static void socket_remove(struct pcmcia_socket *skt)
 {
-	printk(KERN_NOTICE "pccard: card ejected from slot %d\n", skt->sock);
+	dev_printk(KERN_NOTICE, &skt->dev,
+		   "pccard: card ejected from slot %d\n", skt->sock);
 	socket_shutdown(skt);
 }
 
@@ -641,8 +645,8 @@
 	/* register with the device core */
 	ret = device_register(&skt->dev);
 	if (ret) {
-		printk(KERN_WARNING "PCMCIA: unable to register socket 0x%p\n",
-			skt);
+		dev_printk(KERN_WARNING, &skt->dev,
+			   "PCMCIA: unable to register socket\n");
 		skt->thread = NULL;
 		complete(&skt->thread_done);
 		return 0;
@@ -748,7 +752,7 @@
  * CIS register.
  */
 
-int pccard_reset_card(struct pcmcia_socket *skt)
+int pcmcia_reset_card(struct pcmcia_socket *skt)
 {
 	int ret;
 
@@ -757,15 +761,15 @@
 	mutex_lock(&skt->skt_mutex);
 	do {
 		if (!(skt->state & SOCKET_PRESENT)) {
-			ret = CS_NO_CARD;
+			ret = -ENODEV;
 			break;
 		}
 		if (skt->state & SOCKET_SUSPEND) {
-			ret = CS_IN_USE;
+			ret = -EBUSY;
 			break;
 		}
 		if (skt->state & SOCKET_CARDBUS) {
-			ret = CS_UNSUPPORTED_FUNCTION;
+			ret = -EPERM;
 			break;
 		}
 
@@ -774,20 +778,20 @@
 			send_event(skt, CS_EVENT_RESET_PHYSICAL, CS_EVENT_PRI_LOW);
 			if (skt->callback)
 				skt->callback->suspend(skt);
-			if (socket_reset(skt) == CS_SUCCESS) {
+			if (socket_reset(skt) == 0) {
 				send_event(skt, CS_EVENT_CARD_RESET, CS_EVENT_PRI_LOW);
 				if (skt->callback)
 					skt->callback->resume(skt);
 			}
 		}
 
-		ret = CS_SUCCESS;
+		ret = 0;
 	} while (0);
 	mutex_unlock(&skt->skt_mutex);
 
 	return ret;
 } /* reset_card */
-EXPORT_SYMBOL(pccard_reset_card);
+EXPORT_SYMBOL(pcmcia_reset_card);
 
 
 /* These shut down or wake up a socket.  They are sort of user
@@ -802,11 +806,11 @@
 	mutex_lock(&skt->skt_mutex);
 	do {
 		if (!(skt->state & SOCKET_PRESENT)) {
-			ret = CS_NO_CARD;
+			ret = -ENODEV;
 			break;
 		}
 		if (skt->state & SOCKET_CARDBUS) {
-			ret = CS_UNSUPPORTED_FUNCTION;
+			ret = -EPERM;
 			break;
 		}
 		if (skt->callback) {
@@ -832,11 +836,11 @@
 	mutex_lock(&skt->skt_mutex);
 	do {
 		if (!(skt->state & SOCKET_PRESENT)) {
-			ret = CS_NO_CARD;
+			ret = -ENODEV;
 			break;
 		}
 		if (skt->state & SOCKET_CARDBUS) {
-			ret = CS_UNSUPPORTED_FUNCTION;
+			ret = -EPERM;
 			break;
 		}
 		ret = socket_resume(skt);
@@ -892,7 +896,7 @@
 			ret = -EBUSY;
 			break;
 		}
-		if (socket_insert(skt) == CS_NO_CARD) {
+		if (socket_insert(skt) == -ENODEV) {
 			ret = -ENODEV;
 			break;
 		}
diff --git a/drivers/pcmcia/cs_internal.h b/drivers/pcmcia/cs_internal.h
index 63dc1a2..79615e6 100644
--- a/drivers/pcmcia/cs_internal.h
+++ b/drivers/pcmcia/cs_internal.h
@@ -1,5 +1,5 @@
 /*
- * cs_internal.h
+ * cs_internal.h -- definitions internal to the PCMCIA core modules
  *
  * 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
@@ -10,6 +10,12 @@
  * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
  *
  * (C) 1999		David A. Hinds
+ * (C) 2003 - 2008	Dominik Brodowski
+ *
+ *
+ * This file contains definitions _only_ needed by the PCMCIA core modules.
+ * It must not be included by PCMCIA socket drivers or by PCMCIA device
+ * drivers.
  */
 
 #ifndef _LINUX_CS_INTERNAL_H
@@ -18,29 +24,24 @@
 #include <linux/kref.h>
 
 /* Flags in client state */
-#define CLIENT_CONFIG_LOCKED	0x0001
-#define CLIENT_IRQ_REQ		0x0002
-#define CLIENT_IO_REQ		0x0004
-#define CLIENT_UNBOUND		0x0008
-#define CLIENT_STALE		0x0010
 #define CLIENT_WIN_REQ(i)	(0x1<<(i))
-#define CLIENT_CARDBUS		0x8000
 
 /* Each card function gets one of these guys */
 typedef struct config_t {
 	struct kref	ref;
-    u_int		state;
-    u_int		Attributes;
-    u_int		IntType;
-    u_int		ConfigBase;
-    u_char		Status, Pin, Copy, Option, ExtStatus;
-    u_int		CardValues;
-    io_req_t		io;
-    struct {
-	u_int		Attributes;
-    } irq;
+	unsigned int	state;
+	unsigned int	Attributes;
+	unsigned int	IntType;
+	unsigned int	ConfigBase;
+	unsigned char	Status, Pin, Copy, Option, ExtStatus;
+	unsigned int	CardValues;
+	io_req_t	io;
+	struct {
+		u_int	Attributes;
+	} irq;
 } config_t;
 
+
 struct cis_cache_entry {
 	struct list_head	node;
 	unsigned int		addr;
@@ -49,6 +50,30 @@
 	unsigned char		cache[0];
 };
 
+struct pccard_resource_ops {
+	int	(*validate_mem)		(struct pcmcia_socket *s);
+	int	(*adjust_io_region)	(struct resource *res,
+					 unsigned long r_start,
+					 unsigned long r_end,
+					 struct pcmcia_socket *s);
+	struct resource* (*find_io)	(unsigned long base, int num,
+					 unsigned long align,
+					 struct pcmcia_socket *s);
+	struct resource* (*find_mem)	(unsigned long base, unsigned long num,
+					 unsigned long align, int low,
+					 struct pcmcia_socket *s);
+	int	(*add_io)		(struct pcmcia_socket *s,
+					 unsigned int action,
+					 unsigned long r_start,
+					 unsigned long r_end);
+	int	(*add_mem)		(struct pcmcia_socket *s,
+					 unsigned int action,
+					 unsigned long r_start,
+					 unsigned long r_end);
+	int	(*init)			(struct pcmcia_socket *s);
+	void	(*exit)			(struct pcmcia_socket *s);
+};
+
 /* Flags in config state */
 #define CONFIG_LOCKED		0x01
 #define CONFIG_IRQ_REQ		0x02
@@ -59,7 +84,6 @@
 #define SOCKET_INUSE		0x0010
 #define SOCKET_SUSPEND		0x0080
 #define SOCKET_WIN_REQ(i)	(0x0100<<(i))
-#define SOCKET_REGION_INFO	0x4000
 #define SOCKET_CARDBUS		0x8000
 #define SOCKET_CARDBUS_CONFIG	0x10000
 
@@ -83,69 +107,153 @@
 	}
 }
 
-/* In cardbus.c */
-int cb_alloc(struct pcmcia_socket *s);
-void cb_free(struct pcmcia_socket *s);
-int read_cb_mem(struct pcmcia_socket *s, int space, u_int addr, u_int len, void *ptr);
+#ifdef CONFIG_PCMCIA_DEBUG
+extern int cs_debug_level(int);
 
-/* In cistpl.c */
-int pcmcia_read_cis_mem(struct pcmcia_socket *s, int attr,
-		 u_int addr, u_int len, void *ptr);
-void pcmcia_write_cis_mem(struct pcmcia_socket *s, int attr,
-		   u_int addr, u_int len, void *ptr);
-void release_cis_mem(struct pcmcia_socket *s);
-void destroy_cis_cache(struct pcmcia_socket *s);
+#define cs_dbg(skt, lvl, fmt, arg...) do {		\
+	if (cs_debug_level(lvl))			\
+		dev_printk(KERN_DEBUG, &skt->dev,	\
+		 "cs: " fmt, ## arg);			\
+} while (0)
+#define __cs_dbg(lvl, fmt, arg...) do {			\
+	if (cs_debug_level(lvl))			\
+		printk(KERN_DEBUG 			\
+		 "cs: " fmt, ## arg);			\
+} while (0)
+
+#else
+#define cs_dbg(skt, lvl, fmt, arg...) do { } while (0)
+#define __cs_dbg(lvl, fmt, arg...) do { } while (0)
+#endif
+
+#define cs_err(skt, fmt, arg...) \
+	dev_printk(KERN_ERR, &skt->dev, "cs: " fmt, ## arg)
+
+
+/*
+ * Stuff internal to module "pcmcia_core":
+ */
+
+/* cistpl.c */
 int verify_cis_cache(struct pcmcia_socket *s);
-int pccard_read_tuple(struct pcmcia_socket *s, unsigned int function, cisdata_t code, void *parse);
 
-/* In rsrc_mgr */
-int pcmcia_validate_mem(struct pcmcia_socket *s);
-struct resource *pcmcia_find_io_region(unsigned long base, int num, unsigned long align,
-		   struct pcmcia_socket *s);
-int pcmcia_adjust_io_region(struct resource *res, unsigned long r_start,
-		     unsigned long r_end, struct pcmcia_socket *s);
-struct resource *pcmcia_find_mem_region(u_long base, u_long num, u_long align,
-		    int low, struct pcmcia_socket *s);
+/* rsrc_mgr.c */
 void release_resource_db(struct pcmcia_socket *s);
 
-/* In socket_sysfs.c */
+/* socket_sysfs.c */
 extern int pccard_sysfs_add_socket(struct device *dev);
 extern void pccard_sysfs_remove_socket(struct device *dev);
 
-/* In cs.c */
-extern struct rw_semaphore pcmcia_socket_list_rwsem;
-extern struct list_head pcmcia_socket_list;
-int pcmcia_get_window(struct pcmcia_socket *s, window_handle_t *handle, int idx, win_req_t *req);
-int pccard_get_configuration_info(struct pcmcia_socket *s, struct pcmcia_device *p_dev, config_info_t *config);
-int pccard_reset_card(struct pcmcia_socket *skt);
+/* cardbus.c */
+int cb_alloc(struct pcmcia_socket *s);
+void cb_free(struct pcmcia_socket *s);
+int read_cb_mem(struct pcmcia_socket *s, int space, u_int addr, u_int len,
+		void *ptr);
 
 
+
+/*
+ * Stuff exported by module "pcmcia_core" to module "pcmcia"
+ */
+
 struct pcmcia_callback{
 	struct module	*owner;
-	int		(*event) (struct pcmcia_socket *s, event_t event, int priority);
+	int		(*event) (struct pcmcia_socket *s,
+				  event_t event, int priority);
 	void		(*requery) (struct pcmcia_socket *s, int new_cis);
 	int		(*suspend) (struct pcmcia_socket *s);
 	int		(*resume) (struct pcmcia_socket *s);
 };
 
+/* cs.c */
+extern struct rw_semaphore pcmcia_socket_list_rwsem;
+extern struct list_head pcmcia_socket_list;
+extern struct class pcmcia_socket_class;
+
+int pcmcia_get_window(struct pcmcia_socket *s,
+		      window_handle_t *handle,
+		      int idx,
+		      win_req_t *req);
 int pccard_register_pcmcia(struct pcmcia_socket *s, struct pcmcia_callback *c);
+struct pcmcia_socket *pcmcia_get_socket_by_nr(unsigned int nr);
 
-#define cs_socket_name(skt)	((skt)->dev.bus_id)
+int pcmcia_suspend_card(struct pcmcia_socket *skt);
+int pcmcia_resume_card(struct pcmcia_socket *skt);
 
-#ifdef DEBUG
-extern int cs_debug_level(int);
+int pcmcia_eject_card(struct pcmcia_socket *skt);
+int pcmcia_insert_card(struct pcmcia_socket *skt);
 
-#define cs_dbg(skt, lvl, fmt, arg...) do {		\
-	if (cs_debug_level(lvl))			\
-		printk(KERN_DEBUG "cs: %s: " fmt, 	\
-		       cs_socket_name(skt) , ## arg);	\
-} while (0)
+struct pcmcia_socket *pcmcia_get_socket(struct pcmcia_socket *skt);
+void pcmcia_put_socket(struct pcmcia_socket *skt);
 
-#else
-#define cs_dbg(skt, lvl, fmt, arg...) do { } while (0)
-#endif
+/* cistpl.c */
+int pcmcia_read_cis_mem(struct pcmcia_socket *s, int attr,
+			u_int addr, u_int len, void *ptr);
+void pcmcia_write_cis_mem(struct pcmcia_socket *s, int attr,
+			  u_int addr, u_int len, void *ptr);
+void release_cis_mem(struct pcmcia_socket *s);
+void destroy_cis_cache(struct pcmcia_socket *s);
+int pccard_read_tuple(struct pcmcia_socket *s, unsigned int function,
+		      cisdata_t code, void *parse);
+int pcmcia_replace_cis(struct pcmcia_socket *s,
+		       const u8 *data, const size_t len);
+int pccard_validate_cis(struct pcmcia_socket *s, unsigned int function,
+			unsigned int *count);
 
-#define cs_err(skt, fmt, arg...) \
-	printk(KERN_ERR "cs: %s: " fmt, (skt)->dev.bus_id , ## arg)
+/* rsrc_mgr.c */
+int pcmcia_validate_mem(struct pcmcia_socket *s);
+struct resource *pcmcia_find_io_region(unsigned long base,
+				       int num,
+				       unsigned long align,
+				       struct pcmcia_socket *s);
+int pcmcia_adjust_io_region(struct resource *res,
+			    unsigned long r_start,
+			    unsigned long r_end,
+			    struct pcmcia_socket *s);
+struct resource *pcmcia_find_mem_region(u_long base,
+					u_long num,
+					u_long align,
+					int low,
+					struct pcmcia_socket *s);
+
+/*
+ * Stuff internal to module "pcmcia".
+ */
+/* ds.c */
+extern struct bus_type pcmcia_bus_type;
+
+/* pcmcia_resource.c */
+extern int pcmcia_release_configuration(struct pcmcia_device *p_dev);
+
+#ifdef CONFIG_PCMCIA_IOCTL
+/* ds.c */
+extern spinlock_t pcmcia_dev_list_lock;
+
+extern struct pcmcia_device *pcmcia_get_dev(struct pcmcia_device *p_dev);
+extern void pcmcia_put_dev(struct pcmcia_device *p_dev);
+
+struct pcmcia_device *pcmcia_device_add(struct pcmcia_socket *s,
+					unsigned int function);
+
+/* pcmcia_ioctl.c */
+extern void __init pcmcia_setup_ioctl(void);
+extern void __exit pcmcia_cleanup_ioctl(void);
+extern void handle_event(struct pcmcia_socket *s, event_t event);
+extern int handle_request(struct pcmcia_socket *s, event_t event);
+
+#else /* CONFIG_PCMCIA_IOCTL */
+
+static inline void __init pcmcia_setup_ioctl(void) { return; }
+static inline void __exit pcmcia_cleanup_ioctl(void) { return; }
+static inline void handle_event(struct pcmcia_socket *s, event_t event)
+{
+	return;
+}
+static inline int handle_request(struct pcmcia_socket *s, event_t event)
+{
+	return 0;
+}
+
+#endif /* CONFIG_PCMCIA_IOCTL */
 
 #endif /* _LINUX_CS_INTERNAL_H */
diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c
index 4174d96..7956602 100644
--- a/drivers/pcmcia/ds.c
+++ b/drivers/pcmcia/ds.c
@@ -32,7 +32,6 @@
 #include <pcmcia/ss.h>
 
 #include "cs_internal.h"
-#include "ds_internal.h"
 
 /*====================================================================*/
 
@@ -42,17 +41,22 @@
 MODULE_DESCRIPTION("PCMCIA Driver Services");
 MODULE_LICENSE("GPL");
 
-#ifdef DEBUG
+#ifdef CONFIG_PCMCIA_DEBUG
 int ds_pc_debug;
 
 module_param_named(pc_debug, ds_pc_debug, int, 0644);
 
 #define ds_dbg(lvl, fmt, arg...) do {				\
-	if (ds_pc_debug > (lvl))					\
+	if (ds_pc_debug > (lvl))				\
 		printk(KERN_DEBUG "ds: " fmt , ## arg);		\
 } while (0)
+#define ds_dev_dbg(lvl, dev, fmt, arg...) do {				\
+	if (ds_pc_debug > (lvl))					\
+		dev_printk(KERN_DEBUG, dev, "ds: " fmt , ## arg);	\
+} while (0)
 #else
 #define ds_dbg(lvl, fmt, arg...) do { } while (0)
+#define ds_dev_dbg(lvl, dev, fmt, arg...) do { } while (0)
 #endif
 
 spinlock_t pcmcia_dev_list_lock;
@@ -64,42 +68,19 @@
 /* String tables for error messages */
 
 typedef struct lookup_t {
-    int key;
-    char *msg;
+    const int key;
+    const char *msg;
 } lookup_t;
 
 static const lookup_t error_table[] = {
-    { CS_SUCCESS,		"Operation succeeded" },
-    { CS_BAD_ADAPTER,		"Bad adapter" },
-    { CS_BAD_ATTRIBUTE, 	"Bad attribute", },
-    { CS_BAD_BASE,		"Bad base address" },
-    { CS_BAD_EDC,		"Bad EDC" },
-    { CS_BAD_IRQ,		"Bad IRQ" },
-    { CS_BAD_OFFSET,		"Bad offset" },
-    { CS_BAD_PAGE,		"Bad page number" },
-    { CS_READ_FAILURE,		"Read failure" },
-    { CS_BAD_SIZE,		"Bad size" },
-    { CS_BAD_SOCKET,		"Bad socket" },
-    { CS_BAD_TYPE,		"Bad type" },
-    { CS_BAD_VCC,		"Bad Vcc" },
-    { CS_BAD_VPP,		"Bad Vpp" },
-    { CS_BAD_WINDOW,		"Bad window" },
-    { CS_WRITE_FAILURE,		"Write failure" },
-    { CS_NO_CARD,		"No card present" },
-    { CS_UNSUPPORTED_FUNCTION,	"Usupported function" },
-    { CS_UNSUPPORTED_MODE,	"Unsupported mode" },
-    { CS_BAD_SPEED,		"Bad speed" },
-    { CS_BUSY,			"Resource busy" },
-    { CS_GENERAL_FAILURE,	"General failure" },
-    { CS_WRITE_PROTECTED,	"Write protected" },
-    { CS_BAD_ARG_LENGTH,	"Bad argument length" },
-    { CS_BAD_ARGS,		"Bad arguments" },
-    { CS_CONFIGURATION_LOCKED,	"Configuration locked" },
-    { CS_IN_USE,		"Resource in use" },
-    { CS_NO_MORE_ITEMS,		"No more items" },
-    { CS_OUT_OF_RESOURCE,	"Out of resource" },
-    { CS_BAD_HANDLE,		"Bad handle" },
-    { CS_BAD_TUPLE,		"Bad CIS tuple" }
+    { 0,			"Operation succeeded" },
+    { -EIO,			"Input/Output error" },
+    { -ENODEV,			"No card present" },
+    { -EINVAL,			"Bad parameter" },
+    { -EACCES,			"Configuration locked" },
+    { -EBUSY,			"Resource in use" },
+    { -ENOSPC,			"No more items" },
+    { -ENOMEM,			"Out of resource" },
 };
 
 
@@ -155,46 +136,32 @@
     { ReplaceCIS,			"ReplaceCIS" }
 };
 
-
-static int pcmcia_report_error(struct pcmcia_device *p_dev, error_info_t *err)
+const char *pcmcia_error_func(int func)
 {
 	int i;
-	char *serv;
-
-	if (!p_dev)
-		printk(KERN_NOTICE);
-	else
-		printk(KERN_NOTICE "%s: ", p_dev->dev.bus_id);
 
 	for (i = 0; i < ARRAY_SIZE(service_table); i++)
-		if (service_table[i].key == err->func)
-			break;
-	if (i < ARRAY_SIZE(service_table))
-		serv = service_table[i].msg;
-	else
-		serv = "Unknown service number";
+		if (service_table[i].key == func)
+			return service_table[i].msg;
+
+	return "Unknown service number";
+}
+EXPORT_SYMBOL(pcmcia_error_func);
+
+const char *pcmcia_error_ret(int ret)
+{
+	int i;
 
 	for (i = 0; i < ARRAY_SIZE(error_table); i++)
-		if (error_table[i].key == err->retcode)
-			break;
-	if (i < ARRAY_SIZE(error_table))
-		printk("%s: %s\n", serv, error_table[i].msg);
-	else
-		printk("%s: Unknown error code %#x\n", serv, err->retcode);
+		if (error_table[i].key == ret)
+			return error_table[i].msg;
 
-	return CS_SUCCESS;
-} /* report_error */
-
-/* end of code which was in cs.c before */
+	return "unknown";
+}
+EXPORT_SYMBOL(pcmcia_error_ret);
 
 /*======================================================================*/
 
-void cs_error(struct pcmcia_device *p_dev, int func, int ret)
-{
-	error_info_t err = { func, ret };
-	pcmcia_report_error(p_dev, &err);
-}
-EXPORT_SYMBOL(cs_error);
 
 
 static void pcmcia_check_driver(struct pcmcia_driver *p_drv)
@@ -391,7 +358,7 @@
 static void pcmcia_release_dev(struct device *dev)
 {
 	struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
-	ds_dbg(1, "releasing device %s\n", p_dev->dev.bus_id);
+	ds_dev_dbg(1, dev, "releasing device\n");
 	pcmcia_put_socket(p_dev->socket);
 	kfree(p_dev->devname);
 	kref_put(&p_dev->function_config->ref, pcmcia_release_function);
@@ -401,7 +368,7 @@
 static void pcmcia_add_device_later(struct pcmcia_socket *s, int mfc)
 {
 	if (!s->pcmcia_state.device_add_pending) {
-		ds_dbg(1, "scheduling to add %s secondary"
+		ds_dev_dbg(1, &s->dev, "scheduling to add %s secondary"
 		       " device to %d\n", mfc ? "mfc" : "pfc", s->sock);
 		s->pcmcia_state.device_add_pending = 1;
 		s->pcmcia_state.mfc_pfc = mfc;
@@ -427,8 +394,19 @@
 	p_drv = to_pcmcia_drv(dev->driver);
 	s = p_dev->socket;
 
-	ds_dbg(1, "trying to bind %s to %s\n", p_dev->dev.bus_id,
-	       p_drv->drv.name);
+	/* The PCMCIA code passes the match data in via dev->driver_data
+	 * which is an ugly hack. Once the driver probe is called it may
+	 * and often will overwrite the match data so we must save it first
+	 *
+	 * handle pseudo multifunction devices:
+	 * there are at most two pseudo multifunction devices.
+	 * if we're matching against the first, schedule a
+	 * call which will then check whether there are two
+	 * pseudo devices, and if not, add the second one.
+	 */
+	did = p_dev->dev.driver_data;
+
+	ds_dev_dbg(1, dev, "trying to bind to %s\n", p_drv->drv.name);
 
 	if ((!p_drv->probe) || (!p_dev->function_config) ||
 	    (!try_module_get(p_drv->owner))) {
@@ -443,33 +421,27 @@
 		p_dev->conf.ConfigBase = cis_config.base;
 		p_dev->conf.Present = cis_config.rmask[0];
 	} else {
-		printk(KERN_INFO "pcmcia: could not parse base and rmask0 of CIS\n");
+		dev_printk(KERN_INFO, dev,
+			   "pcmcia: could not parse base and rmask0 of CIS\n");
 		p_dev->conf.ConfigBase = 0;
 		p_dev->conf.Present = 0;
 	}
 
 	ret = p_drv->probe(p_dev);
 	if (ret) {
-		ds_dbg(1, "binding %s to %s failed with %d\n",
-		       p_dev->dev.bus_id, p_drv->drv.name, ret);
+		ds_dev_dbg(1, dev, "binding to %s failed with %d\n",
+			   p_drv->drv.name, ret);
 		goto put_module;
 	}
 
-	/* handle pseudo multifunction devices:
-	 * there are at most two pseudo multifunction devices.
-	 * if we're matching against the first, schedule a
-	 * call which will then check whether there are two
-	 * pseudo devices, and if not, add the second one.
-	 */
-	did = p_dev->dev.driver_data;
 	if (did && (did->match_flags & PCMCIA_DEV_ID_MATCH_DEVICE_NO) &&
 	    (p_dev->socket->device_count == 1) && (p_dev->device_no == 0))
 		pcmcia_add_device_later(p_dev->socket, 0);
 
- put_module:
+put_module:
 	if (ret)
 		module_put(p_drv->owner);
- put_dev:
+put_dev:
 	if (ret)
 		put_device(dev);
 	return (ret);
@@ -485,8 +457,9 @@
 	struct pcmcia_device	*tmp;
 	unsigned long		flags;
 
-	ds_dbg(2, "pcmcia_card_remove(%d) %s\n", s->sock,
-	       leftover ? leftover->devname : "");
+	ds_dev_dbg(2, leftover ? &leftover->dev : &s->dev,
+		   "pcmcia_card_remove(%d) %s\n", s->sock,
+		   leftover ? leftover->devname : "");
 
 	if (!leftover)
 		s->device_count = 0;
@@ -503,7 +476,7 @@
 		p_dev->_removed=1;
 		spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
 
-		ds_dbg(2, "unregistering device %s\n", p_dev->dev.bus_id);
+		ds_dev_dbg(2, &p_dev->dev, "unregistering device\n");
 		device_unregister(&p_dev->dev);
 	}
 
@@ -520,7 +493,7 @@
 	p_dev = to_pcmcia_dev(dev);
 	p_drv = to_pcmcia_drv(dev->driver);
 
-	ds_dbg(1, "removing device %s\n", p_dev->dev.bus_id);
+	ds_dev_dbg(1, dev, "removing device\n");
 
 	/* If we're removing the primary module driving a
 	 * pseudo multi-function card, we need to unbind
@@ -543,13 +516,15 @@
 
 	/* check for proper unloading */
 	if (p_dev->_irq || p_dev->_io || p_dev->_locked)
-		printk(KERN_INFO "pcmcia: driver %s did not release config properly\n",
-		       p_drv->drv.name);
+		dev_printk(KERN_INFO, dev,
+			"pcmcia: driver %s did not release config properly\n",
+			p_drv->drv.name);
 
 	for (i = 0; i < MAX_WIN; i++)
 		if (p_dev->_win & CLIENT_WIN_REQ(i))
-			printk(KERN_INFO "pcmcia: driver %s did not release windows properly\n",
-			       p_drv->drv.name);
+			dev_printk(KERN_INFO, dev,
+			  "pcmcia: driver %s did not release window properly\n",
+			   p_drv->drv.name);
 
 	/* references from pcmcia_probe_device */
 	pcmcia_put_dev(p_dev);
@@ -598,8 +573,9 @@
 		}
 		if (!pccard_read_tuple(p_dev->socket, p_dev->func,
 				      CISTPL_DEVICE_GEO, devgeo)) {
-			ds_dbg(0, "mem device geometry probably means "
-			       "FUNCID_MEMORY\n");
+			ds_dev_dbg(0, &p_dev->dev,
+				   "mem device geometry probably means "
+				   "FUNCID_MEMORY\n");
 			p_dev->func_id = CISTPL_FUNCID_MEMORY;
 			p_dev->has_func_id = 1;
 		}
@@ -680,7 +656,7 @@
 	if (!p_dev->devname)
 		goto err_free;
 	sprintf (p_dev->devname, "pcmcia%s", p_dev->dev.bus_id);
-	ds_dbg(3, "devname is %s\n", p_dev->devname);
+	ds_dev_dbg(3, &p_dev->dev, "devname is %s\n", p_dev->devname);
 
 	spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
 
@@ -701,7 +677,7 @@
 	spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
 
 	if (!p_dev->function_config) {
-		ds_dbg(3, "creating config_t for %s\n", p_dev->dev.bus_id);
+		ds_dev_dbg(3, &p_dev->dev, "creating config_t\n");
 		p_dev->function_config = kzalloc(sizeof(struct config_t),
 						 GFP_KERNEL);
 		if (!p_dev->function_config)
@@ -709,8 +685,9 @@
 		kref_init(&p_dev->function_config->ref);
 	}
 
-	printk(KERN_NOTICE "pcmcia: registering new device %s\n",
-	       p_dev->devname);
+	dev_printk(KERN_NOTICE, &p_dev->dev,
+		   "pcmcia: registering new device %s\n",
+		   p_dev->devname);
 
 	pcmcia_device_query(p_dev);
 
@@ -745,19 +722,20 @@
 	int ret = 0;
 
 	if (!(s->resource_setup_done)) {
-		ds_dbg(3, "no resources available, delaying card_add\n");
+		ds_dev_dbg(3, &s->dev,
+			   "no resources available, delaying card_add\n");
 		return -EAGAIN; /* try again, but later... */
 	}
 
 	if (pcmcia_validate_mem(s)) {
-		ds_dbg(3, "validating mem resources failed, "
+		ds_dev_dbg(3, &s->dev, "validating mem resources failed, "
 		       "delaying card_add\n");
 		return -EAGAIN; /* try again, but later... */
 	}
 
 	ret = pccard_validate_cis(s, BIND_FN_ALL, &no_chains);
 	if (ret || !no_chains) {
-		ds_dbg(0, "invalid CIS or invalid resources\n");
+		ds_dev_dbg(0, &s->dev, "invalid CIS or invalid resources\n");
 		return -ENODEV;
 	}
 
@@ -778,7 +756,7 @@
 {
 	struct pcmcia_socket *s =
 		container_of(work, struct pcmcia_socket, device_add);
-	ds_dbg(1, "adding additional device to %d\n", s->sock);
+	ds_dev_dbg(1, &s->dev, "adding additional device to %d\n", s->sock);
 	pcmcia_device_add(s, s->pcmcia_state.mfc_pfc);
 	s->pcmcia_state.device_add_pending = 0;
 	s->pcmcia_state.mfc_pfc = 0;
@@ -788,8 +766,7 @@
 {
 	struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
 	if (!p_dev->dev.driver) {
-		ds_dbg(1, "update device information for %s\n",
-		       p_dev->dev.bus_id);
+		ds_dev_dbg(1, dev, "update device information\n");
 		pcmcia_device_query(p_dev);
 	}
 
@@ -803,7 +780,7 @@
 	unsigned long flags;
 
 	/* must be called with skt_mutex held */
-	ds_dbg(0, "re-scanning socket %d\n", skt->sock);
+	ds_dev_dbg(0, &skt->dev, "re-scanning socket %d\n", skt->sock);
 
 	spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
 	if (list_empty(&skt->devices_list))
@@ -854,17 +831,17 @@
 	int ret = -ENOMEM;
 	int no_funcs;
 	int old_funcs;
-	cisdump_t *cis;
 	cistpl_longlink_mfc_t mfc;
 
 	if (!filename)
 		return -EINVAL;
 
-	ds_dbg(1, "trying to load CIS file %s\n", filename);
+	ds_dev_dbg(1, &dev->dev, "trying to load CIS file %s\n", filename);
 
 	if (strlen(filename) > (FIRMWARE_NAME_MAX - 1)) {
-		printk(KERN_WARNING "pcmcia: CIS filename is too long [%s]\n",
-			filename);
+		dev_printk(KERN_WARNING, &dev->dev,
+			   "pcmcia: CIS filename is too long [%s]\n",
+			   filename);
 		return -EINVAL;
 	}
 
@@ -873,23 +850,16 @@
 	if (request_firmware(&fw, path, &dev->dev) == 0) {
 		if (fw->size >= CISTPL_MAX_CIS_SIZE) {
 			ret = -EINVAL;
-			printk(KERN_ERR "pcmcia: CIS override is too big\n");
+			dev_printk(KERN_ERR, &dev->dev,
+				   "pcmcia: CIS override is too big\n");
 			goto release;
 		}
 
-		cis = kzalloc(sizeof(cisdump_t), GFP_KERNEL);
-		if (!cis) {
-			ret = -ENOMEM;
-			goto release;
-		}
-
-		cis->Length = fw->size + 1;
-		memcpy(cis->Data, fw->data, fw->size);
-
-		if (!pcmcia_replace_cis(s, cis))
+		if (!pcmcia_replace_cis(s, fw->data, fw->size))
 			ret = 0;
 		else {
-			printk(KERN_ERR "pcmcia: CIS override failed\n");
+			dev_printk(KERN_ERR, &dev->dev,
+				   "pcmcia: CIS override failed\n");
 			goto release;
 		}
 
@@ -993,14 +963,14 @@
 		 * after it has re-checked that there is no possible module
 		 * with a prod_id/manf_id/card_id match.
 		 */
-		ds_dbg(0, "skipping FUNC_ID match for %s until userspace "
-		       "interaction\n", dev->dev.bus_id);
+		ds_dev_dbg(0, &dev->dev,
+			"skipping FUNC_ID match until userspace interaction\n");
 		if (!dev->allow_func_id_match)
 			return 0;
 	}
 
 	if (did->match_flags & PCMCIA_DEV_ID_MATCH_FAKE_CIS) {
-		ds_dbg(0, "device %s needs a fake CIS\n", dev->dev.bus_id);
+		ds_dev_dbg(0, &dev->dev, "device needs a fake CIS\n");
 		if (!dev->socket->fake_cis)
 			pcmcia_load_firmware(dev, did->cisfile);
 
@@ -1032,11 +1002,9 @@
 	/* match dynamic devices first */
 	spin_lock(&p_drv->dynids.lock);
 	list_for_each_entry(dynid, &p_drv->dynids.list, node) {
-		ds_dbg(3, "trying to match %s to %s\n", dev->bus_id,
-		       drv->name);
+		ds_dev_dbg(3, dev, "trying to match to %s\n", drv->name);
 		if (pcmcia_devmatch(p_dev, &dynid->id)) {
-			ds_dbg(0, "matched %s to %s\n", dev->bus_id,
-			       drv->name);
+			ds_dev_dbg(0, dev, "matched to %s\n", drv->name);
 			spin_unlock(&p_drv->dynids.lock);
 			return 1;
 		}
@@ -1046,18 +1014,15 @@
 #ifdef CONFIG_PCMCIA_IOCTL
 	/* matching by cardmgr */
 	if (p_dev->cardmgr == p_drv) {
-		ds_dbg(0, "cardmgr matched %s to %s\n", dev->bus_id,
-		       drv->name);
+		ds_dev_dbg(0, dev, "cardmgr matched to %s\n", drv->name);
 		return 1;
 	}
 #endif
 
 	while (did && did->match_flags) {
-		ds_dbg(3, "trying to match %s to %s\n", dev->bus_id,
-		       drv->name);
+		ds_dev_dbg(3, dev, "trying to match to %s\n", drv->name);
 		if (pcmcia_devmatch(p_dev, did)) {
-			ds_dbg(0, "matched %s to %s\n", dev->bus_id,
-			       drv->name);
+			ds_dev_dbg(0, dev, "matched to %s\n", drv->name);
 			return 1;
 		}
 		did++;
@@ -1263,7 +1228,7 @@
 	if (p_dev->suspended)
 		return 0;
 
-	ds_dbg(2, "suspending %s\n", dev->bus_id);
+	ds_dev_dbg(2, dev, "suspending\n");
 
 	if (dev->driver)
 		p_drv = to_pcmcia_drv(dev->driver);
@@ -1274,15 +1239,16 @@
 	if (p_drv->suspend) {
 		ret = p_drv->suspend(p_dev);
 		if (ret) {
-			printk(KERN_ERR "pcmcia: device %s (driver %s) did "
-			       "not want to go to sleep (%d)\n",
-			       p_dev->devname, p_drv->drv.name, ret);
+			dev_printk(KERN_ERR, dev,
+				   "pcmcia: device %s (driver %s) did "
+				   "not want to go to sleep (%d)\n",
+				   p_dev->devname, p_drv->drv.name, ret);
 			goto out;
 		}
 	}
 
 	if (p_dev->device_no == p_dev->func) {
-		ds_dbg(2, "releasing configuration for %s\n", dev->bus_id);
+		ds_dev_dbg(2, dev, "releasing configuration\n");
 		pcmcia_release_configuration(p_dev);
 	}
 
@@ -1302,7 +1268,7 @@
 	if (!p_dev->suspended)
 		return 0;
 
-	ds_dbg(2, "resuming %s\n", dev->bus_id);
+	ds_dev_dbg(2, dev, "resuming\n");
 
 	if (dev->driver)
 		p_drv = to_pcmcia_drv(dev->driver);
@@ -1311,7 +1277,7 @@
 		goto out;
 
 	if (p_dev->device_no == p_dev->func) {
-		ds_dbg(2, "requesting configuration for %s\n", dev->bus_id);
+		ds_dev_dbg(2, dev, "requesting configuration\n");
 		ret = pcmcia_request_configuration(p_dev, &p_dev->conf);
 		if (ret)
 			goto out;
@@ -1353,14 +1319,14 @@
 
 static int pcmcia_bus_resume(struct pcmcia_socket *skt)
 {
-	ds_dbg(2, "resuming socket %d\n", skt->sock);
+	ds_dev_dbg(2, &skt->dev, "resuming socket %d\n", skt->sock);
 	bus_for_each_dev(&pcmcia_bus_type, NULL, skt, pcmcia_bus_resume_callback);
 	return 0;
 }
 
 static int pcmcia_bus_suspend(struct pcmcia_socket *skt)
 {
-	ds_dbg(2, "suspending socket %d\n", skt->sock);
+	ds_dev_dbg(2, &skt->dev, "suspending socket %d\n", skt->sock);
 	if (bus_for_each_dev(&pcmcia_bus_type, NULL, skt,
 			     pcmcia_bus_suspend_callback)) {
 		pcmcia_bus_resume(skt);
@@ -1386,13 +1352,14 @@
 	struct pcmcia_socket *s = pcmcia_get_socket(skt);
 
 	if (!s) {
-		printk(KERN_ERR "PCMCIA obtaining reference to socket %p " \
-			"failed, event 0x%x lost!\n", skt, event);
+		dev_printk(KERN_ERR, &skt->dev,
+			   "PCMCIA obtaining reference to socket "	\
+			   "failed, event 0x%x lost!\n", event);
 		return -ENODEV;
 	}
 
-	ds_dbg(1, "ds_event(0x%06x, %d, 0x%p)\n",
-	       event, priority, skt);
+	ds_dev_dbg(1, &skt->dev, "ds_event(0x%06x, %d, 0x%p)\n",
+		   event, priority, skt);
 
 	switch (event) {
 	case CS_EVENT_CARD_REMOVAL:
@@ -1467,7 +1434,8 @@
 
 	socket = pcmcia_get_socket(socket);
 	if (!socket) {
-		printk(KERN_ERR "PCMCIA obtaining reference to socket %p failed\n", socket);
+		dev_printk(KERN_ERR, dev,
+			   "PCMCIA obtaining reference to socket failed\n");
 		return -ENODEV;
 	}
 
@@ -1487,7 +1455,7 @@
 
 	ret = pccard_register_pcmcia(socket, &pcmcia_bus_callback);
 	if (ret) {
-		printk(KERN_ERR "PCMCIA registration PCCard core failed for socket %p\n", socket);
+		dev_printk(KERN_ERR, dev, "PCMCIA registration failed\n");
 		pcmcia_put_socket(socket);
 		return (ret);
 	}
diff --git a/drivers/pcmcia/ds_internal.h b/drivers/pcmcia/ds_internal.h
deleted file mode 100644
index 3a2b25e..0000000
--- a/drivers/pcmcia/ds_internal.h
+++ /dev/null
@@ -1,23 +0,0 @@
-/* ds_internal.h - internal header for 16-bit PCMCIA devices management */
-
-extern spinlock_t pcmcia_dev_list_lock;
-extern struct bus_type pcmcia_bus_type;
-
-extern struct pcmcia_device * pcmcia_get_dev(struct pcmcia_device *p_dev);
-extern void pcmcia_put_dev(struct pcmcia_device *p_dev);
-
-struct pcmcia_device * pcmcia_device_add(struct pcmcia_socket *s, unsigned int function);
-
-extern int pcmcia_release_configuration(struct pcmcia_device *p_dev);
-
-#ifdef CONFIG_PCMCIA_IOCTL
-extern void __init pcmcia_setup_ioctl(void);
-extern void __exit pcmcia_cleanup_ioctl(void);
-extern void handle_event(struct pcmcia_socket *s, event_t event);
-extern int handle_request(struct pcmcia_socket *s, event_t event);
-#else
-static inline void __init pcmcia_setup_ioctl(void) { return; }
-static inline void __exit pcmcia_cleanup_ioctl(void) { return; }
-static inline void handle_event(struct pcmcia_socket *s, event_t event) { return; }
-static inline int handle_request(struct pcmcia_socket *s, event_t event) { return CS_SUCCESS; }
-#endif
diff --git a/drivers/pcmcia/hd64465_ss.c b/drivers/pcmcia/hd64465_ss.c
index fb2bc1f..117dc12 100644
--- a/drivers/pcmcia/hd64465_ss.c
+++ b/drivers/pcmcia/hd64465_ss.c
@@ -46,7 +46,6 @@
 #include <pcmcia/cistpl.h>
 #include <pcmcia/ds.h>
 #include <pcmcia/ss.h>
-#include "cs_internal.h"
 
 #define MODNAME "hd64465_ss"
 
diff --git a/drivers/pcmcia/i82365.c b/drivers/pcmcia/i82365.c
index 68f6b27..71653ab 100644
--- a/drivers/pcmcia/i82365.c
+++ b/drivers/pcmcia/i82365.c
@@ -63,7 +63,7 @@
 #include "vg468.h"
 #include "ricoh.h"
 
-#ifdef DEBUG
+#ifdef CONFIG_PCMCIA_DEBUG
 static const char version[] =
 "i82365.c 1.265 1999/11/10 18:36:21 (David Hinds)";
 
diff --git a/drivers/pcmcia/m32r_cfc.c b/drivers/pcmcia/m32r_cfc.c
index 3616da2..2ab4f22 100644
--- a/drivers/pcmcia/m32r_cfc.c
+++ b/drivers/pcmcia/m32r_cfc.c
@@ -38,7 +38,7 @@
 
 #include "m32r_cfc.h"
 
-#ifdef DEBUG
+#ifdef CONFIG_PCMCIA_DEBUG
 static int m32r_cfc_debug;
 module_param(m32r_cfc_debug, int, 0644);
 #define debug(lvl, fmt, arg...) do {				\
@@ -505,7 +505,7 @@
 		pcc_set(sock,(unsigned int)PLD_CFBUFCR,1);
 	}
 
-#ifdef DEBUG
+#ifdef CONFIG_PCMCIA_DEBUG
 	if(state->flags & SS_IOCARD){
 		debug(3, ":IOCARD");
 	}
diff --git a/drivers/pcmcia/m32r_pcc.c b/drivers/pcmcia/m32r_pcc.c
index 2b42b71..2f108c2 100644
--- a/drivers/pcmcia/m32r_pcc.c
+++ b/drivers/pcmcia/m32r_pcc.c
@@ -45,7 +45,7 @@
 
 #define PCC_DEBUG_DBEX
 
-#ifdef DEBUG
+#ifdef CONFIG_PCMCIA_DEBUG
 static int m32r_pcc_debug;
 module_param(m32r_pcc_debug, int, 0644);
 #define debug(lvl, fmt, arg...) do {				\
@@ -460,7 +460,7 @@
 
 	pcc_set(sock,PCCSIGCR,reg);
 
-#ifdef DEBUG
+#ifdef CONFIG_PCMCIA_DEBUG
 	if(state->flags & SS_IOCARD){
 		debug(3, ":IOCARD");
 	}
diff --git a/drivers/pcmcia/m8xx_pcmcia.c b/drivers/pcmcia/m8xx_pcmcia.c
index ff66604..d1ad096 100644
--- a/drivers/pcmcia/m8xx_pcmcia.c
+++ b/drivers/pcmcia/m8xx_pcmcia.c
@@ -64,8 +64,8 @@
 #include <pcmcia/cs.h>
 #include <pcmcia/ss.h>
 
-#ifdef PCMCIA_DEBUG
-static int pc_debug = PCMCIA_DEBUG;
+#ifdef CONFIG_PCMCIA_DEBUG
+static int pc_debug;
 module_param(pc_debug, int, 0);
 #define dprintk(args...) printk(KERN_DEBUG "m8xx_pcmcia: " args);
 #else
diff --git a/drivers/pcmcia/o2micro.h b/drivers/pcmcia/o2micro.h
index a234ce1..5554015 100644
--- a/drivers/pcmcia/o2micro.h
+++ b/drivers/pcmcia/o2micro.h
@@ -140,7 +140,8 @@
 		a = config_readb(socket, O2_RESERVED1);
 		b = config_readb(socket, O2_RESERVED2);
 
-		printk(KERN_INFO "Yenta O2: res at 0x94/0xD4: %02x/%02x\n", a, b);
+		dev_printk(KERN_INFO, &socket->dev->dev,
+			   "O2: res at 0x94/0xD4: %02x/%02x\n", a, b);
 
 		switch (socket->dev->device) {
 		/*
@@ -153,7 +154,9 @@
 		case PCI_DEVICE_ID_O2_6812:
 		case PCI_DEVICE_ID_O2_6832:
 		case PCI_DEVICE_ID_O2_6836:
-			printk(KERN_INFO "Yenta O2: old bridge, disabling read prefetch/write burst\n");
+			dev_printk(KERN_INFO, &socket->dev->dev,
+				   "Yenta O2: old bridge, disabling read "
+				   "prefetch/write burst\n");
 			config_writeb(socket, O2_RESERVED1,
 			              a & ~(O2_RES_READ_PREFETCH | O2_RES_WRITE_BURST));
 			config_writeb(socket, O2_RESERVED2,
@@ -161,7 +164,8 @@
 			break;
 
 		default:
-			printk(KERN_INFO "Yenta O2: enabling read prefetch/write burst\n");
+			dev_printk(KERN_INFO , &socket->dev->dev,
+				   "O2: enabling read prefetch/write burst\n");
 			config_writeb(socket, O2_RESERVED1,
 			              a | O2_RES_READ_PREFETCH | O2_RES_WRITE_BURST);
 			config_writeb(socket, O2_RESERVED2,
diff --git a/drivers/pcmcia/pcmcia_ioctl.c b/drivers/pcmcia/pcmcia_ioctl.c
index 419f97f..1703b20 100644
--- a/drivers/pcmcia/pcmcia_ioctl.c
+++ b/drivers/pcmcia/pcmcia_ioctl.c
@@ -38,7 +38,6 @@
 #include <pcmcia/ss.h>
 
 #include "cs_internal.h"
-#include "ds_internal.h"
 
 static int major_dev = -1;
 
@@ -58,7 +57,7 @@
 } user_info_t;
 
 
-#ifdef DEBUG
+#ifdef CONFIG_PCMCIA_DEBUG
 extern int ds_pc_debug;
 
 #define ds_dbg(lvl, fmt, arg...) do {		\
@@ -149,7 +148,7 @@
 
 	irq = adj->resource.irq.IRQ;
 	if ((irq < 0) || (irq > 15))
-		return CS_BAD_IRQ;
+		return -EINVAL;
 
 	if (adj->Action != REMOVE_MANAGED_RESOURCE)
 		return 0;
@@ -167,7 +166,7 @@
 #else
 
 static inline int adjust_irq(struct pcmcia_socket *s, adjust_t *adj) {
-	return CS_SUCCESS;
+	return 0;
 }
 
 #endif
@@ -175,7 +174,7 @@
 static int pcmcia_adjust_resource_info(adjust_t *adj)
 {
 	struct pcmcia_socket *s;
-	int ret = CS_UNSUPPORTED_FUNCTION;
+	int ret = -ENOSYS;
 	unsigned long flags;
 
 	down_read(&pcmcia_socket_list_rwsem);
@@ -248,7 +247,7 @@
 	if (s->state & SOCKET_SUSPEND)
 		status->CardState |= CS_EVENT_PM_SUSPEND;
 	if (!(s->state & SOCKET_PRESENT))
-		return CS_NO_CARD;
+		return -ENODEV;
 
 	c = (p_dev) ? p_dev->function_config : NULL;
 
@@ -274,7 +273,7 @@
 			status->CardState |=
 				(reg & ESR_REQ_ATTN) ? CS_EVENT_REQUEST_ATTENTION : 0;
 		}
-		return CS_SUCCESS;
+		return 0;
 	}
 	status->CardState |=
 		(val & SS_WRPROT) ? CS_EVENT_WRITE_PROTECT : 0;
@@ -284,9 +283,81 @@
 		(val & SS_BATWARN) ? CS_EVENT_BATTERY_LOW : 0;
 	status->CardState |=
 		(val & SS_READY) ? CS_EVENT_READY_CHANGE : 0;
-	return CS_SUCCESS;
+	return 0;
 } /* pccard_get_status */
 
+int pccard_get_configuration_info(struct pcmcia_socket *s,
+				  struct pcmcia_device *p_dev,
+				  config_info_t *config)
+{
+	config_t *c;
+
+	if (!(s->state & SOCKET_PRESENT))
+		return -ENODEV;
+
+
+#ifdef CONFIG_CARDBUS
+	if (s->state & SOCKET_CARDBUS) {
+		memset(config, 0, sizeof(config_info_t));
+		config->Vcc = s->socket.Vcc;
+		config->Vpp1 = config->Vpp2 = s->socket.Vpp;
+		config->Option = s->cb_dev->subordinate->number;
+		if (s->state & SOCKET_CARDBUS_CONFIG) {
+			config->Attributes = CONF_VALID_CLIENT;
+			config->IntType = INT_CARDBUS;
+			config->AssignedIRQ = s->irq.AssignedIRQ;
+			if (config->AssignedIRQ)
+				config->Attributes |= CONF_ENABLE_IRQ;
+			if (s->io[0].res) {
+				config->BasePort1 = s->io[0].res->start;
+				config->NumPorts1 = s->io[0].res->end -
+					config->BasePort1 + 1;
+			}
+		}
+		return 0;
+	}
+#endif
+
+	if (p_dev) {
+		c = p_dev->function_config;
+		config->Function = p_dev->func;
+	} else {
+		c = NULL;
+		config->Function = 0;
+	}
+
+	if ((c == NULL) || !(c->state & CONFIG_LOCKED)) {
+		config->Attributes = 0;
+		config->Vcc = s->socket.Vcc;
+		config->Vpp1 = config->Vpp2 = s->socket.Vpp;
+		return 0;
+	}
+
+	config->Attributes = c->Attributes | CONF_VALID_CLIENT;
+	config->Vcc = s->socket.Vcc;
+	config->Vpp1 = config->Vpp2 = s->socket.Vpp;
+	config->IntType = c->IntType;
+	config->ConfigBase = c->ConfigBase;
+	config->Status = c->Status;
+	config->Pin = c->Pin;
+	config->Copy = c->Copy;
+	config->Option = c->Option;
+	config->ExtStatus = c->ExtStatus;
+	config->Present = config->CardValues = c->CardValues;
+	config->IRQAttributes = c->irq.Attributes;
+	config->AssignedIRQ = s->irq.AssignedIRQ;
+	config->BasePort1 = c->io.BasePort1;
+	config->NumPorts1 = c->io.NumPorts1;
+	config->Attributes1 = c->io.Attributes1;
+	config->BasePort2 = c->io.BasePort2;
+	config->NumPorts2 = c->io.NumPorts2;
+	config->Attributes2 = c->io.Attributes2;
+	config->IOAddrLines = c->io.IOAddrLines;
+
+	return 0;
+} /* pccard_get_configuration_info */
+
+
 /*======================================================================
 
     These manage a ring buffer of events pending for one user process
@@ -764,7 +835,7 @@
     case DS_GET_CONFIGURATION_INFO:
 	if (buf->config.Function &&
 	   (buf->config.Function >= s->functions))
-	    ret = CS_BAD_ARGS;
+	    ret = -EINVAL;
 	else {
 	    struct pcmcia_device *p_dev = get_pcmcia_device(s, buf->config.Function);
 	    ret = pccard_get_configuration_info(s, p_dev, &buf->config);
@@ -787,15 +858,15 @@
 	break;
     case DS_PARSE_TUPLE:
 	buf->tuple.TupleData = buf->tuple_parse.data;
-	ret = pccard_parse_tuple(&buf->tuple, &buf->tuple_parse.parse);
+	ret = pcmcia_parse_tuple(&buf->tuple, &buf->tuple_parse.parse);
 	break;
     case DS_RESET_CARD:
-	ret = pccard_reset_card(s);
+	ret = pcmcia_reset_card(s);
 	break;
     case DS_GET_STATUS:
 	    if (buf->status.Function &&
 		(buf->status.Function >= s->functions))
-		    ret = CS_BAD_ARGS;
+		    ret = -EINVAL;
 	    else {
 		    struct pcmcia_device *p_dev = get_pcmcia_device(s, buf->status.Function);
 		    ret = pccard_get_status(s, p_dev, &buf->status);
@@ -826,7 +897,7 @@
 	    goto free_out;
 	}
 
-	ret = CS_BAD_ARGS;
+	ret = -EINVAL;
 
 	if (!(buf->conf_reg.Function &&
 	     (buf->conf_reg.Function >= s->functions))) {
@@ -867,7 +938,7 @@
 			   &buf->win_info.map);
 	break;
     case DS_REPLACE_CIS:
-	ret = pcmcia_replace_cis(s, &buf->cisdump);
+	ret = pcmcia_replace_cis(s, buf->cisdump.Data, buf->cisdump.Length);
 	break;
     case DS_BIND_REQUEST:
 	if (!capable(CAP_SYS_ADMIN)) {
@@ -889,22 +960,19 @@
 	err = -EINVAL;
     }
 
-    if ((err == 0) && (ret != CS_SUCCESS)) {
+    if ((err == 0) && (ret != 0)) {
 	ds_dbg(2, "ds_ioctl: ret = %d\n", ret);
 	switch (ret) {
-	case CS_BAD_SOCKET: case CS_NO_CARD:
-	    err = -ENODEV; break;
-	case CS_BAD_ARGS: case CS_BAD_ATTRIBUTE: case CS_BAD_IRQ:
-	case CS_BAD_TUPLE:
-	    err = -EINVAL; break;
-	case CS_IN_USE:
-	    err = -EBUSY; break;
-	case CS_OUT_OF_RESOURCE:
+	case -ENODEV:
+	case -EINVAL:
+	case -EBUSY:
+	case -ENOSYS:
+	    err = ret;
+	    break;
+	case -ENOMEM:
 	    err = -ENOSPC; break;
-	case CS_NO_MORE_ITEMS:
+	case -ENOSPC:
 	    err = -ENODATA; break;
-	case CS_UNSUPPORTED_FUNCTION:
-	    err = -ENOSYS; break;
 	default:
 	    err = -EIO; break;
 	}
diff --git a/drivers/pcmcia/pcmcia_resource.c b/drivers/pcmcia/pcmcia_resource.c
index 4884a18..afea2b2 100644
--- a/drivers/pcmcia/pcmcia_resource.c
+++ b/drivers/pcmcia/pcmcia_resource.c
@@ -29,7 +29,6 @@
 #include <pcmcia/ds.h>
 
 #include "cs_internal.h"
-#include "ds_internal.h"
 
 
 /* Access speed for IO windows */
@@ -44,16 +43,17 @@
 #endif
 
 
-#ifdef DEBUG
+#ifdef CONFIG_PCMCIA_DEBUG
 extern int ds_pc_debug;
 
 #define ds_dbg(skt, lvl, fmt, arg...) do {			\
 	if (ds_pc_debug >= lvl)					\
-		printk(KERN_DEBUG "pcmcia_resource: %s: " fmt,	\
-			cs_socket_name(skt) , ## arg);		\
+		dev_printk(KERN_DEBUG, &skt->dev,		\
+			   "pcmcia_resource: " fmt,		\
+			   ## arg);				\
 } while (0)
 #else
-#define ds_dbg(lvl, fmt, arg...) do { } while (0)
+#define ds_dbg(skt, lvl, fmt, arg...) do { } while (0)
 #endif
 
 
@@ -168,13 +168,13 @@
 	u_char val;
 
 	if (!p_dev || !p_dev->function_config)
-		return CS_NO_CARD;
+		return -EINVAL;
 
 	s = p_dev->socket;
 	c = p_dev->function_config;
 
 	if (!(c->state & CONFIG_LOCKED))
-		return CS_CONFIGURATION_LOCKED;
+		return -EACCES;
 
 	addr = (c->ConfigBase + reg->Offset) >> 1;
 
@@ -188,93 +188,14 @@
 		pcmcia_write_cis_mem(s, 1, addr, 1, &val);
 		break;
 	default:
-		return CS_BAD_ARGS;
+		return -EINVAL;
 		break;
 	}
-	return CS_SUCCESS;
+	return 0;
 } /* pcmcia_access_configuration_register */
 EXPORT_SYMBOL(pcmcia_access_configuration_register);
 
 
-int pccard_get_configuration_info(struct pcmcia_socket *s,
-				  struct pcmcia_device *p_dev,
-				  config_info_t *config)
-{
-	config_t *c;
-
-	if (!(s->state & SOCKET_PRESENT))
-		return CS_NO_CARD;
-
-
-#ifdef CONFIG_CARDBUS
-	if (s->state & SOCKET_CARDBUS) {
-		memset(config, 0, sizeof(config_info_t));
-		config->Vcc = s->socket.Vcc;
-		config->Vpp1 = config->Vpp2 = s->socket.Vpp;
-		config->Option = s->cb_dev->subordinate->number;
-		if (s->state & SOCKET_CARDBUS_CONFIG) {
-			config->Attributes = CONF_VALID_CLIENT;
-			config->IntType = INT_CARDBUS;
-			config->AssignedIRQ = s->irq.AssignedIRQ;
-			if (config->AssignedIRQ)
-				config->Attributes |= CONF_ENABLE_IRQ;
-			if (s->io[0].res) {
-				config->BasePort1 = s->io[0].res->start;
-				config->NumPorts1 = s->io[0].res->end - config->BasePort1 + 1;
-			}
-		}
-		return CS_SUCCESS;
-	}
-#endif
-
-	if (p_dev) {
-		c = p_dev->function_config;
-		config->Function = p_dev->func;
-	} else {
-		c = NULL;
-		config->Function = 0;
-	}
-
-	if ((c == NULL) || !(c->state & CONFIG_LOCKED)) {
-		config->Attributes = 0;
-		config->Vcc = s->socket.Vcc;
-		config->Vpp1 = config->Vpp2 = s->socket.Vpp;
-		return CS_SUCCESS;
-	}
-
-	config->Attributes = c->Attributes | CONF_VALID_CLIENT;
-	config->Vcc = s->socket.Vcc;
-	config->Vpp1 = config->Vpp2 = s->socket.Vpp;
-	config->IntType = c->IntType;
-	config->ConfigBase = c->ConfigBase;
-	config->Status = c->Status;
-	config->Pin = c->Pin;
-	config->Copy = c->Copy;
-	config->Option = c->Option;
-	config->ExtStatus = c->ExtStatus;
-	config->Present = config->CardValues = c->CardValues;
-	config->IRQAttributes = c->irq.Attributes;
-	config->AssignedIRQ = s->irq.AssignedIRQ;
-	config->BasePort1 = c->io.BasePort1;
-	config->NumPorts1 = c->io.NumPorts1;
-	config->Attributes1 = c->io.Attributes1;
-	config->BasePort2 = c->io.BasePort2;
-	config->NumPorts2 = c->io.NumPorts2;
-	config->Attributes2 = c->io.Attributes2;
-	config->IOAddrLines = c->io.IOAddrLines;
-
-	return CS_SUCCESS;
-} /* pccard_get_configuration_info */
-
-int pcmcia_get_configuration_info(struct pcmcia_device *p_dev,
-				  config_info_t *config)
-{
-	return pccard_get_configuration_info(p_dev->socket, p_dev,
-					     config);
-}
-EXPORT_SYMBOL(pcmcia_get_configuration_info);
-
-
 /** pcmcia_get_window
  */
 int pcmcia_get_window(struct pcmcia_socket *s, window_handle_t *handle,
@@ -284,12 +205,12 @@
 	int w;
 
 	if (!s || !(s->state & SOCKET_PRESENT))
-		return CS_NO_CARD;
+		return -ENODEV;
 	for (w = idx; w < MAX_WIN; w++)
 		if (s->state & SOCKET_WIN_REQ(w))
 			break;
 	if (w == MAX_WIN)
-		return CS_NO_MORE_ITEMS;
+		return -EINVAL;
 	win = &s->win[w];
 	req->Base = win->ctl.res->start;
 	req->Size = win->ctl.res->end - win->ctl.res->start + 1;
@@ -304,7 +225,7 @@
 	if (win->ctl.flags & MAP_USE_WAIT)
 		req->Attributes |= WIN_USE_WAIT;
 	*handle = win;
-	return CS_SUCCESS;
+	return 0;
 } /* pcmcia_get_window */
 EXPORT_SYMBOL(pcmcia_get_window);
 
@@ -316,10 +237,10 @@
 int pcmcia_get_mem_page(window_handle_t win, memreq_t *req)
 {
 	if ((win == NULL) || (win->magic != WINDOW_MAGIC))
-		return CS_BAD_HANDLE;
+		return -EINVAL;
 	req->Page = 0;
 	req->CardOffset = win->ctl.card_start;
-	return CS_SUCCESS;
+	return 0;
 } /* pcmcia_get_mem_page */
 EXPORT_SYMBOL(pcmcia_get_mem_page);
 
@@ -328,14 +249,18 @@
 {
 	struct pcmcia_socket *s;
 	if ((win == NULL) || (win->magic != WINDOW_MAGIC))
-		return CS_BAD_HANDLE;
-	if (req->Page != 0)
-		return CS_BAD_PAGE;
+		return -EINVAL;
 	s = win->sock;
+	if (req->Page != 0) {
+		ds_dbg(s, 0, "failure: requested page is zero\n");
+		return -EINVAL;
+	}
 	win->ctl.card_start = req->CardOffset;
-	if (s->ops->set_mem_map(s, &win->ctl) != 0)
-		return CS_BAD_OFFSET;
-	return CS_SUCCESS;
+	if (s->ops->set_mem_map(s, &win->ctl) != 0) {
+		ds_dbg(s, 0, "failed to set_mem_map\n");
+		return -EIO;
+	}
+	return 0;
 } /* pcmcia_map_mem_page */
 EXPORT_SYMBOL(pcmcia_map_mem_page);
 
@@ -354,9 +279,9 @@
 	c = p_dev->function_config;
 
 	if (!(s->state & SOCKET_PRESENT))
-		return CS_NO_CARD;
+		return -ENODEV;
 	if (!(c->state & CONFIG_LOCKED))
-		return CS_CONFIGURATION_LOCKED;
+		return -EACCES;
 
 	if (mod->Attributes & CONF_IRQ_CHANGE_VALID) {
 		if (mod->Attributes & CONF_ENABLE_IRQ) {
@@ -369,20 +294,28 @@
 		s->ops->set_socket(s, &s->socket);
 	}
 
-	if (mod->Attributes & CONF_VCC_CHANGE_VALID)
-		return CS_BAD_VCC;
+	if (mod->Attributes & CONF_VCC_CHANGE_VALID) {
+		ds_dbg(s, 0, "changing Vcc is not allowed at this time\n");
+		return -EINVAL;
+	}
 
 	/* We only allow changing Vpp1 and Vpp2 to the same value */
 	if ((mod->Attributes & CONF_VPP1_CHANGE_VALID) &&
 	    (mod->Attributes & CONF_VPP2_CHANGE_VALID)) {
 		if (mod->Vpp1 != mod->Vpp2)
-			return CS_BAD_VPP;
+			ds_dbg(s, 0, "Vpp1 and Vpp2 must be the same\n");
+			return -EINVAL;
 		s->socket.Vpp = mod->Vpp1;
-		if (s->ops->set_socket(s, &s->socket))
-			return CS_BAD_VPP;
+		if (s->ops->set_socket(s, &s->socket)) {
+			dev_printk(KERN_WARNING, &s->dev,
+				   "Unable to set VPP\n");
+			return -EIO;
+		}
 	} else if ((mod->Attributes & CONF_VPP1_CHANGE_VALID) ||
-		   (mod->Attributes & CONF_VPP2_CHANGE_VALID))
-		return CS_BAD_VPP;
+		   (mod->Attributes & CONF_VPP2_CHANGE_VALID)) {
+		ds_dbg(s, 0, "changing Vcc is not allowed at this time\n");
+		return -EINVAL;
+	}
 
 	if (mod->Attributes & CONF_IO_CHANGE_WIDTH) {
 		pccard_io_map io_off = { 0, 0, 0, 0, 1 };
@@ -406,7 +339,7 @@
 		}
 	}
 
-	return CS_SUCCESS;
+	return 0;
 } /* modify_configuration */
 EXPORT_SYMBOL(pcmcia_modify_configuration);
 
@@ -441,7 +374,7 @@
 			}
 	}
 
-	return CS_SUCCESS;
+	return 0;
 } /* pcmcia_release_configuration */
 
 
@@ -459,7 +392,7 @@
 	config_t *c = p_dev->function_config;
 
 	if (!p_dev->_io )
-		return CS_BAD_HANDLE;
+		return -EINVAL;
 
 	p_dev->_io = 0;
 
@@ -467,7 +400,7 @@
 	    (c->io.NumPorts1 != req->NumPorts1) ||
 	    (c->io.BasePort2 != req->BasePort2) ||
 	    (c->io.NumPorts2 != req->NumPorts2))
-		return CS_BAD_ARGS;
+		return -EINVAL;
 
 	c->state &= ~CONFIG_IO_REQ;
 
@@ -475,7 +408,7 @@
 	if (req->NumPorts2)
 		release_io_space(s, req->BasePort2, req->NumPorts2);
 
-	return CS_SUCCESS;
+	return 0;
 } /* pcmcia_release_io */
 
 
@@ -485,15 +418,19 @@
 	config_t *c= p_dev->function_config;
 
 	if (!p_dev->_irq)
-		return CS_BAD_HANDLE;
+		return -EINVAL;
 	p_dev->_irq = 0;
 
 	if (c->state & CONFIG_LOCKED)
-		return CS_CONFIGURATION_LOCKED;
-	if (c->irq.Attributes != req->Attributes)
-		return CS_BAD_ATTRIBUTE;
-	if (s->irq.AssignedIRQ != req->AssignedIRQ)
-		return CS_BAD_IRQ;
+		return -EACCES;
+	if (c->irq.Attributes != req->Attributes) {
+		ds_dbg(s, 0, "IRQ attributes must match assigned ones\n");
+		return -EINVAL;
+	}
+	if (s->irq.AssignedIRQ != req->AssignedIRQ) {
+		ds_dbg(s, 0, "IRQ must match assigned one\n");
+		return -EINVAL;
+	}
 	if (--s->irq.Config == 0) {
 		c->state &= ~CONFIG_IRQ_REQ;
 		s->irq.AssignedIRQ = 0;
@@ -507,7 +444,7 @@
 	pcmcia_used_irq[req->AssignedIRQ]--;
 #endif
 
-	return CS_SUCCESS;
+	return 0;
 } /* pcmcia_release_irq */
 
 
@@ -516,10 +453,10 @@
 	struct pcmcia_socket *s;
 
 	if ((win == NULL) || (win->magic != WINDOW_MAGIC))
-		return CS_BAD_HANDLE;
+		return -EINVAL;
 	s = win->sock;
 	if (!(win->handle->_win & CLIENT_WIN_REQ(win->index)))
-		return CS_BAD_HANDLE;
+		return -EINVAL;
 
 	/* Shut down memory window */
 	win->ctl.flags &= ~MAP_ACTIVE;
@@ -536,7 +473,7 @@
 
 	win->magic = 0;
 
-	return CS_SUCCESS;
+	return 0;
 } /* pcmcia_release_window */
 EXPORT_SYMBOL(pcmcia_release_window);
 
@@ -551,18 +488,23 @@
 	pccard_io_map iomap;
 
 	if (!(s->state & SOCKET_PRESENT))
-		return CS_NO_CARD;
+		return -ENODEV;;
 
-	if (req->IntType & INT_CARDBUS)
-		return CS_UNSUPPORTED_MODE;
+	if (req->IntType & INT_CARDBUS) {
+		ds_dbg(p_dev->socket, 0, "IntType may not be INT_CARDBUS\n");
+		return -EINVAL;
+	}
 	c = p_dev->function_config;
 	if (c->state & CONFIG_LOCKED)
-		return CS_CONFIGURATION_LOCKED;
+		return -EACCES;
 
 	/* Do power control.  We don't allow changes in Vcc. */
 	s->socket.Vpp = req->Vpp;
-	if (s->ops->set_socket(s, &s->socket))
-		return CS_BAD_VPP;
+	if (s->ops->set_socket(s, &s->socket)) {
+		dev_printk(KERN_WARNING, &s->dev,
+			   "Unable to set socket state\n");
+		return -EINVAL;
+	}
 
 	/* Pick memory or I/O card, DMA mode, interrupt */
 	c->IntType = req->IntType;
@@ -651,7 +593,7 @@
 
 	c->state |= CONFIG_LOCKED;
 	p_dev->_locked = 1;
-	return CS_SUCCESS;
+	return 0;
 } /* pcmcia_request_configuration */
 EXPORT_SYMBOL(pcmcia_request_configuration);
 
@@ -667,37 +609,48 @@
 	config_t *c;
 
 	if (!(s->state & SOCKET_PRESENT))
-		return CS_NO_CARD;
+		return -ENODEV;
 
 	if (!req)
-		return CS_UNSUPPORTED_MODE;
+		return -EINVAL;
 	c = p_dev->function_config;
 	if (c->state & CONFIG_LOCKED)
-		return CS_CONFIGURATION_LOCKED;
-	if (c->state & CONFIG_IO_REQ)
-		return CS_IN_USE;
-	if (req->Attributes1 & (IO_SHARED | IO_FORCE_ALIAS_ACCESS))
-		return CS_BAD_ATTRIBUTE;
+		return -EACCES;
+	if (c->state & CONFIG_IO_REQ) {
+		ds_dbg(s, 0, "IO already configured\n");
+		return -EBUSY;
+	}
+	if (req->Attributes1 & (IO_SHARED | IO_FORCE_ALIAS_ACCESS)) {
+		ds_dbg(s, 0, "bad attribute setting for IO region 1\n");
+		return -EINVAL;
+	}
 	if ((req->NumPorts2 > 0) &&
-	    (req->Attributes2 & (IO_SHARED | IO_FORCE_ALIAS_ACCESS)))
-		return CS_BAD_ATTRIBUTE;
+	    (req->Attributes2 & (IO_SHARED | IO_FORCE_ALIAS_ACCESS))) {
+		ds_dbg(s, 0, "bad attribute setting for IO region 2\n");
+		return -EINVAL;
+	}
 
+	ds_dbg(s, 1, "trying to allocate resource 1\n");
 	if (alloc_io_space(s, req->Attributes1, &req->BasePort1,
-			   req->NumPorts1, req->IOAddrLines))
-		return CS_IN_USE;
+			   req->NumPorts1, req->IOAddrLines)) {
+		ds_dbg(s, 0, "allocation of resource 1 failed\n");
+		return -EBUSY;
+	}
 
 	if (req->NumPorts2) {
+		ds_dbg(s, 1, "trying to allocate resource 2\n");
 		if (alloc_io_space(s, req->Attributes2, &req->BasePort2,
 				   req->NumPorts2, req->IOAddrLines)) {
+			ds_dbg(s, 0, "allocation of resource 2 failed\n");
 			release_io_space(s, req->BasePort1, req->NumPorts1);
-			return CS_IN_USE;
+			return -EBUSY;
 		}
 	}
 
 	c->io = *req;
 	c->state |= CONFIG_IO_REQ;
 	p_dev->_io = 1;
-	return CS_SUCCESS;
+	return 0;
 } /* pcmcia_request_io */
 EXPORT_SYMBOL(pcmcia_request_io);
 
@@ -723,16 +676,18 @@
 {
 	struct pcmcia_socket *s = p_dev->socket;
 	config_t *c;
-	int ret = CS_IN_USE, irq = 0;
+	int ret = -EINVAL, irq = 0;
 	int type;
 
 	if (!(s->state & SOCKET_PRESENT))
-		return CS_NO_CARD;
+		return -ENODEV;
 	c = p_dev->function_config;
 	if (c->state & CONFIG_LOCKED)
-		return CS_CONFIGURATION_LOCKED;
-	if (c->state & CONFIG_IRQ_REQ)
-		return CS_IN_USE;
+		return -EACCES;
+	if (c->state & CONFIG_IRQ_REQ) {
+		ds_dbg(s, 0, "IRQ already configured\n");
+		return -EBUSY;
+	}
 
 	/* Decide what type of interrupt we are registering */
 	type = 0;
@@ -795,15 +750,19 @@
 	}
 
 	if (ret && (req->Attributes & IRQ_HANDLE_PRESENT)) {
-		if (request_irq(irq, req->Handler, type,  p_dev->devname, req->Instance))
-			return CS_IN_USE;
+		ret = request_irq(irq, req->Handler, type,
+				  p_dev->devname, req->Instance);
+		if (ret)
+			return ret;
 	}
 
 	/* Make sure the fact the request type was overridden is passed back */
 	if (type == IRQF_SHARED && !(req->Attributes & IRQ_TYPE_DYNAMIC_SHARING)) {
 		req->Attributes |= IRQ_TYPE_DYNAMIC_SHARING;
-		printk(KERN_WARNING "pcmcia: request for exclusive IRQ could not be fulfilled.\n");
-		printk(KERN_WARNING "pcmcia: the driver needs updating to supported shared IRQ lines.\n");
+		dev_printk(KERN_WARNING, &p_dev->dev, "pcmcia: "
+			"request for exclusive IRQ could not be fulfilled.\n");
+		dev_printk(KERN_WARNING, &p_dev->dev, "pcmcia: the driver "
+			"needs updating to supported shared IRQ lines.\n");
 	}
 	c->irq.Attributes = req->Attributes;
 	s->irq.AssignedIRQ = req->AssignedIRQ = irq;
@@ -816,7 +775,7 @@
 	pcmcia_used_irq[irq]++;
 #endif
 
-	return CS_SUCCESS;
+	return 0;
 } /* pcmcia_request_irq */
 EXPORT_SYMBOL(pcmcia_request_irq);
 
@@ -834,9 +793,11 @@
 	int w;
 
 	if (!(s->state & SOCKET_PRESENT))
-		return CS_NO_CARD;
-	if (req->Attributes & (WIN_PAGED | WIN_SHARED))
-		return CS_BAD_ATTRIBUTE;
+		return -ENODEV;
+	if (req->Attributes & (WIN_PAGED | WIN_SHARED)) {
+		ds_dbg(s, 0, "bad attribute setting for iomem region\n");
+		return -EINVAL;
+	}
 
 	/* Window size defaults to smallest available */
 	if (req->Size == 0)
@@ -844,19 +805,25 @@
 	align = (((s->features & SS_CAP_MEM_ALIGN) ||
 		  (req->Attributes & WIN_STRICT_ALIGN)) ?
 		 req->Size : s->map_size);
-	if (req->Size & (s->map_size-1))
-		return CS_BAD_SIZE;
+	if (req->Size & (s->map_size-1)) {
+		ds_dbg(s, 0, "invalid map size\n");
+		return -EINVAL;
+	}
 	if ((req->Base && (s->features & SS_CAP_STATIC_MAP)) ||
-	    (req->Base & (align-1)))
-		return CS_BAD_BASE;
+	    (req->Base & (align-1))) {
+		ds_dbg(s, 0, "invalid base address\n");
+		return -EINVAL;
+	}
 	if (req->Base)
 		align = 0;
 
 	/* Allocate system memory window */
 	for (w = 0; w < MAX_WIN; w++)
 		if (!(s->state & SOCKET_WIN_REQ(w))) break;
-	if (w == MAX_WIN)
-		return CS_OUT_OF_RESOURCE;
+	if (w == MAX_WIN) {
+		ds_dbg(s, 0, "all windows are used already\n");
+		return -EINVAL;
+	}
 
 	win = &s->win[w];
 	win->magic = WINDOW_MAGIC;
@@ -867,8 +834,10 @@
 	if (!(s->features & SS_CAP_STATIC_MAP)) {
 		win->ctl.res = pcmcia_find_mem_region(req->Base, req->Size, align,
 						      (req->Attributes & WIN_MAP_BELOW_1MB), s);
-		if (!win->ctl.res)
-			return CS_IN_USE;
+		if (!win->ctl.res) {
+			ds_dbg(s, 0, "allocating mem region failed\n");
+			return -EINVAL;
+		}
 	}
 	(*p_dev)->_win |= CLIENT_WIN_REQ(w);
 
@@ -885,8 +854,10 @@
 	if (req->Attributes & WIN_USE_WAIT)
 		win->ctl.flags |= MAP_USE_WAIT;
 	win->ctl.card_start = 0;
-	if (s->ops->set_mem_map(s, &win->ctl) != 0)
-		return CS_BAD_ARGS;
+	if (s->ops->set_mem_map(s, &win->ctl) != 0) {
+		ds_dbg(s, 0, "failed to set memory mapping\n");
+		return -EIO;
+	}
 	s->state |= SOCKET_WIN_REQ(w);
 
 	/* Return window handle */
@@ -897,7 +868,7 @@
 	}
 	*wh = win;
 
-	return CS_SUCCESS;
+	return 0;
 } /* pcmcia_request_window */
 EXPORT_SYMBOL(pcmcia_request_window);
 
@@ -909,3 +880,79 @@
 		pcmcia_release_window(p_dev->win);
 }
 EXPORT_SYMBOL(pcmcia_disable_device);
+
+
+struct pcmcia_cfg_mem {
+	tuple_t tuple;
+	cisparse_t parse;
+	u8 buf[256];
+	cistpl_cftable_entry_t dflt;
+};
+
+/**
+ * pcmcia_loop_config() - loop over configuration options
+ * @p_dev:	the struct pcmcia_device which we need to loop for.
+ * @conf_check:	function to call for each configuration option.
+ *		It gets passed the struct pcmcia_device, the CIS data
+ *		describing the configuration option, and private data
+ *		being passed to pcmcia_loop_config()
+ * @priv_data:	private data to be passed to the conf_check function.
+ *
+ * pcmcia_loop_config() loops over all configuration options, and calls
+ * the driver-specific conf_check() for each one, checking whether
+ * it is a valid one.
+ */
+int pcmcia_loop_config(struct pcmcia_device *p_dev,
+		       int	(*conf_check)	(struct pcmcia_device *p_dev,
+						 cistpl_cftable_entry_t *cfg,
+						 cistpl_cftable_entry_t *dflt,
+						 unsigned int vcc,
+						 void *priv_data),
+		       void *priv_data)
+{
+	struct pcmcia_cfg_mem *cfg_mem;
+
+	tuple_t *tuple;
+	int ret = -ENODEV;
+	unsigned int vcc;
+
+	cfg_mem = kzalloc(sizeof(struct pcmcia_cfg_mem), GFP_KERNEL);
+	if (cfg_mem == NULL)
+		return -ENOMEM;
+
+	/* get the current Vcc setting */
+	vcc = p_dev->socket->socket.Vcc;
+
+	tuple = &cfg_mem->tuple;
+	tuple->TupleData = cfg_mem->buf;
+	tuple->TupleDataMax = 255;
+	tuple->TupleOffset = 0;
+	tuple->DesiredTuple = CISTPL_CFTABLE_ENTRY;
+	tuple->Attributes = 0;
+
+	ret = pcmcia_get_first_tuple(p_dev, tuple);
+	while (!ret) {
+		cistpl_cftable_entry_t *cfg = &cfg_mem->parse.cftable_entry;
+
+		if (pcmcia_get_tuple_data(p_dev, tuple))
+			goto next_entry;
+
+		if (pcmcia_parse_tuple(tuple, &cfg_mem->parse))
+			goto next_entry;
+
+		/* default values */
+		p_dev->conf.ConfigIndex = cfg->index;
+		if (cfg->flags & CISTPL_CFTABLE_DEFAULT)
+			cfg_mem->dflt = *cfg;
+
+		ret = conf_check(p_dev, cfg, &cfg_mem->dflt, vcc, priv_data);
+		if (!ret)
+			break;
+
+next_entry:
+		ret = pcmcia_get_next_tuple(p_dev, tuple);
+	}
+
+	return ret;
+}
+EXPORT_SYMBOL(pcmcia_loop_config);
diff --git a/drivers/pcmcia/pxa2xx_base.c b/drivers/pcmcia/pxa2xx_base.c
index 1b07af5..bb9ddb9 100644
--- a/drivers/pcmcia/pxa2xx_base.c
+++ b/drivers/pcmcia/pxa2xx_base.c
@@ -30,12 +30,12 @@
 #include <asm/system.h>
 #include <mach/pxa-regs.h>
 #include <mach/pxa2xx-regs.h>
+#include <asm/mach-types.h>
 
 #include <pcmcia/cs_types.h>
 #include <pcmcia/ss.h>
 #include <pcmcia/cistpl.h>
 
-#include "cs_internal.h"
 #include "soc_common.h"
 #include "pxa2xx_base.h"
 
@@ -166,18 +166,32 @@
 }
 #endif
 
+static void pxa2xx_configure_sockets(struct device *dev)
+{
+	struct pcmcia_low_level *ops = dev->platform_data;
+
+	/*
+	 * We have at least one socket, so set MECR:CIT
+	 * (Card Is There)
+	 */
+	MECR |= MECR_CIT;
+
+	/* Set MECR:NOS (Number Of Sockets) */
+	if (ops->nr > 1 || machine_is_viper())
+		MECR |= MECR_NOS;
+	else
+		MECR &= ~MECR_NOS;
+}
+
 int __pxa2xx_drv_pcmcia_probe(struct device *dev)
 {
 	int ret;
 	struct pcmcia_low_level *ops;
-	int first, nr;
 
 	if (!dev || !dev->platform_data)
 		return -ENODEV;
 
 	ops = (struct pcmcia_low_level *)dev->platform_data;
-	first = ops->first;
-	nr = ops->nr;
 
 	/* Provide our PXA2xx specific timing routines. */
 	ops->set_timing  = pxa2xx_pcmcia_set_timing;
@@ -185,21 +199,10 @@
 	ops->frequency_change = pxa2xx_pcmcia_frequency_change;
 #endif
 
-	ret = soc_common_drv_pcmcia_probe(dev, ops, first, nr);
+	ret = soc_common_drv_pcmcia_probe(dev, ops, ops->first, ops->nr);
 
-	if (ret == 0) {
-		/*
-		 * We have at least one socket, so set MECR:CIT
-		 * (Card Is There)
-		 */
-		MECR |= MECR_CIT;
-
-		/* Set MECR:NOS (Number Of Sockets) */
-		if (nr > 1)
-			MECR |= MECR_NOS;
-		else
-			MECR &= ~MECR_NOS;
-	}
+	if (!ret)
+		pxa2xx_configure_sockets(dev);
 
 	return ret;
 }
@@ -223,11 +226,7 @@
 
 static int pxa2xx_drv_pcmcia_resume(struct platform_device *dev)
 {
-	struct pcmcia_low_level *ops = dev->dev.platform_data;
-	int nr = ops ? ops->nr : 0;
-
-	MECR = nr > 1 ? MECR_CIT | MECR_NOS : (nr > 0 ? MECR_CIT : 0);
-
+	pxa2xx_configure_sockets(&dev->dev);
 	return pcmcia_socket_dev_resume(&dev->dev);
 }
 
diff --git a/drivers/pcmcia/pxa2xx_cm_x255.c b/drivers/pcmcia/pxa2xx_cm_x255.c
new file mode 100644
index 0000000..7c8bcb4
--- /dev/null
+++ b/drivers/pcmcia/pxa2xx_cm_x255.c
@@ -0,0 +1,154 @@
+/*
+ * linux/drivers/pcmcia/pxa/pxa_cm_x255.c
+ *
+ * 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.
+ *
+ * Compulab Ltd., 2003, 2007, 2008
+ * Mike Rapoport <mike@compulab.co.il>
+ *
+ */
+
+#include <linux/platform_device.h>
+#include <linux/irq.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+
+#include <asm/mach-types.h>
+#include <mach/pxa-regs.h>
+
+#include "soc_common.h"
+
+#define GPIO_PCMCIA_SKTSEL	(54)
+#define GPIO_PCMCIA_S0_CD_VALID	(16)
+#define GPIO_PCMCIA_S1_CD_VALID	(17)
+#define GPIO_PCMCIA_S0_RDYINT	(6)
+#define GPIO_PCMCIA_S1_RDYINT	(8)
+#define GPIO_PCMCIA_RESET	(9)
+
+#define PCMCIA_S0_CD_VALID	IRQ_GPIO(GPIO_PCMCIA_S0_CD_VALID)
+#define PCMCIA_S1_CD_VALID	IRQ_GPIO(GPIO_PCMCIA_S1_CD_VALID)
+#define PCMCIA_S0_RDYINT	IRQ_GPIO(GPIO_PCMCIA_S0_RDYINT)
+#define PCMCIA_S1_RDYINT	IRQ_GPIO(GPIO_PCMCIA_S1_RDYINT)
+
+
+static struct pcmcia_irqs irqs[] = {
+	{ 0, PCMCIA_S0_CD_VALID, "PCMCIA0 CD" },
+	{ 1, PCMCIA_S1_CD_VALID, "PCMCIA1 CD" },
+};
+
+static int cmx255_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
+{
+	int ret = gpio_request(GPIO_PCMCIA_RESET, "PCCard reset");
+	if (ret)
+		return ret;
+	gpio_direction_output(GPIO_PCMCIA_RESET, 0);
+
+	skt->irq = skt->nr == 0 ? PCMCIA_S0_RDYINT : PCMCIA_S1_RDYINT;
+	ret = soc_pcmcia_request_irqs(skt, irqs, ARRAY_SIZE(irqs));
+	if (!ret)
+		gpio_free(GPIO_PCMCIA_RESET);
+
+	return ret;
+}
+
+static void cmx255_pcmcia_shutdown(struct soc_pcmcia_socket *skt)
+{
+	soc_pcmcia_free_irqs(skt, irqs, ARRAY_SIZE(irqs));
+	gpio_free(GPIO_PCMCIA_RESET);
+}
+
+
+static void cmx255_pcmcia_socket_state(struct soc_pcmcia_socket *skt,
+				       struct pcmcia_state *state)
+{
+	int cd = skt->nr ? GPIO_PCMCIA_S1_CD_VALID : GPIO_PCMCIA_S0_CD_VALID;
+	int rdy = skt->nr ? GPIO_PCMCIA_S0_RDYINT : GPIO_PCMCIA_S1_RDYINT;
+
+	state->detect = !gpio_get_value(cd);
+	state->ready  = !!gpio_get_value(rdy);
+	state->bvd1   = 1;
+	state->bvd2   = 1;
+	state->vs_3v  = 0;
+	state->vs_Xv  = 0;
+	state->wrprot = 0;  /* not available */
+}
+
+
+static int cmx255_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
+					  const socket_state_t *state)
+{
+	switch (skt->nr) {
+	case 0:
+		if (state->flags & SS_RESET) {
+			gpio_set_value(GPIO_PCMCIA_SKTSEL, 0);
+			udelay(1);
+			gpio_set_value(GPIO_PCMCIA_RESET, 1);
+			udelay(10);
+			gpio_set_value(GPIO_PCMCIA_RESET, 0);
+		}
+		break;
+	case 1:
+		if (state->flags & SS_RESET) {
+			gpio_set_value(GPIO_PCMCIA_SKTSEL, 1);
+			udelay(1);
+			gpio_set_value(GPIO_PCMCIA_RESET, 1);
+			udelay(10);
+			gpio_set_value(GPIO_PCMCIA_RESET, 0);
+		}
+		break;
+	}
+
+	return 0;
+}
+
+static void cmx255_pcmcia_socket_init(struct soc_pcmcia_socket *skt)
+{
+}
+
+static void cmx255_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt)
+{
+}
+
+
+static struct pcmcia_low_level cmx255_pcmcia_ops __initdata = {
+	.owner			= THIS_MODULE,
+	.hw_init		= cmx255_pcmcia_hw_init,
+	.hw_shutdown		= cmx255_pcmcia_shutdown,
+	.socket_state		= cmx255_pcmcia_socket_state,
+	.configure_socket	= cmx255_pcmcia_configure_socket,
+	.socket_init		= cmx255_pcmcia_socket_init,
+	.socket_suspend		= cmx255_pcmcia_socket_suspend,
+	.nr			= 1,
+};
+
+static struct platform_device *cmx255_pcmcia_device;
+
+int __init cmx255_pcmcia_init(void)
+{
+	int ret;
+
+	cmx255_pcmcia_device = platform_device_alloc("pxa2xx-pcmcia", -1);
+
+	if (!cmx255_pcmcia_device)
+		return -ENOMEM;
+
+	ret = platform_device_add_data(cmx255_pcmcia_device, &cmx255_pcmcia_ops,
+				       sizeof(cmx255_pcmcia_ops));
+
+	if (ret == 0) {
+		printk(KERN_INFO "Registering cm-x255 PCMCIA interface.\n");
+		ret = platform_device_add(cmx255_pcmcia_device);
+	}
+
+	if (ret)
+		platform_device_put(cmx255_pcmcia_device);
+
+	return ret;
+}
+
+void __exit cmx255_pcmcia_exit(void)
+{
+	platform_device_unregister(cmx255_pcmcia_device);
+}
diff --git a/drivers/pcmcia/pxa2xx_cm_x270.c b/drivers/pcmcia/pxa2xx_cm_x270.c
index bcff5cf..6c3aac3 100644
--- a/drivers/pcmcia/pxa2xx_cm_x270.c
+++ b/drivers/pcmcia/pxa2xx_cm_x270.c
@@ -105,13 +105,10 @@
 
 static struct platform_device *cmx270_pcmcia_device;
 
-static int __init cmx270_pcmcia_init(void)
+int __init cmx270_pcmcia_init(void)
 {
 	int ret;
 
-	if (!machine_is_armcore())
-		return -ENODEV;
-
 	cmx270_pcmcia_device = platform_device_alloc("pxa2xx-pcmcia", -1);
 
 	if (!cmx270_pcmcia_device)
@@ -131,14 +128,7 @@
 	return ret;
 }
 
-static void __exit cmx270_pcmcia_exit(void)
+void __exit cmx270_pcmcia_exit(void)
 {
 	platform_device_unregister(cmx270_pcmcia_device);
 }
-
-module_init(cmx270_pcmcia_init);
-module_exit(cmx270_pcmcia_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Mike Rapoport <mike@compulab.co.il>");
-MODULE_DESCRIPTION("CM-x270 PCMCIA driver");
diff --git a/drivers/pcmcia/pxa2xx_cm_x2xx.c b/drivers/pcmcia/pxa2xx_cm_x2xx.c
new file mode 100644
index 0000000..4f09506
--- /dev/null
+++ b/drivers/pcmcia/pxa2xx_cm_x2xx.c
@@ -0,0 +1,49 @@
+/*
+ * linux/drivers/pcmcia/pxa/pxa_cm_x2xx.c
+ *
+ * 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.
+ *
+ * Compulab Ltd., 2003, 2007, 2008
+ * Mike Rapoport <mike@compulab.co.il>
+ *
+ */
+
+#include <linux/module.h>
+
+#include <asm/system.h>
+#include <asm/mach-types.h>
+#include <mach/system.h>
+
+int cmx255_pcmcia_init(void);
+int cmx270_pcmcia_init(void);
+void cmx255_pcmcia_exit(void);
+void cmx270_pcmcia_exit(void);
+
+static int __init cmx2xx_pcmcia_init(void)
+{
+	int ret = -ENODEV;
+
+	if (machine_is_armcore() && cpu_is_pxa25x())
+		ret = cmx255_pcmcia_init();
+	else if (machine_is_armcore() && cpu_is_pxa27x())
+		ret = cmx270_pcmcia_init();
+
+	return ret;
+}
+
+static void __exit cmx2xx_pcmcia_exit(void)
+{
+	if (machine_is_armcore() && cpu_is_pxa25x())
+		cmx255_pcmcia_exit();
+	else if (machine_is_armcore() && cpu_is_pxa27x())
+		cmx270_pcmcia_exit();
+}
+
+module_init(cmx2xx_pcmcia_init);
+module_exit(cmx2xx_pcmcia_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mike Rapoport <mike@compulab.co.il>");
+MODULE_DESCRIPTION("CM-x2xx PCMCIA driver");
diff --git a/drivers/pcmcia/pxa2xx_palmld.c b/drivers/pcmcia/pxa2xx_palmld.c
new file mode 100644
index 0000000..1736c67
--- /dev/null
+++ b/drivers/pcmcia/pxa2xx_palmld.c
@@ -0,0 +1,151 @@
+/*
+ * linux/drivers/pcmcia/pxa2xx_palmld.c
+ *
+ * Driver for Palm LifeDrive PCMCIA
+ *
+ * Copyright (C) 2006 Alex Osborne <ato@meshy.org>
+ * Copyright (C) 2007-2008 Marek Vasut <marek.vasut@gmail.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/platform_device.h>
+#include <linux/gpio.h>
+
+#include <asm/mach-types.h>
+#include <mach/palmld.h>
+#include "soc_common.h"
+
+static int palmld_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
+{
+	int ret;
+
+	ret = gpio_request(GPIO_NR_PALMLD_PCMCIA_POWER, "PCMCIA PWR");
+	if (ret)
+		goto err1;
+	ret = gpio_direction_output(GPIO_NR_PALMLD_PCMCIA_POWER, 0);
+	if (ret)
+		goto err2;
+
+	ret = gpio_request(GPIO_NR_PALMLD_PCMCIA_RESET, "PCMCIA RST");
+	if (ret)
+		goto err2;
+	ret = gpio_direction_output(GPIO_NR_PALMLD_PCMCIA_RESET, 1);
+	if (ret)
+		goto err3;
+
+	ret = gpio_request(GPIO_NR_PALMLD_PCMCIA_READY, "PCMCIA RDY");
+	if (ret)
+		goto err3;
+	ret = gpio_direction_input(GPIO_NR_PALMLD_PCMCIA_READY);
+	if (ret)
+		goto err4;
+
+	skt->irq = IRQ_GPIO(GPIO_NR_PALMLD_PCMCIA_READY);
+	return 0;
+
+err4:
+	gpio_free(GPIO_NR_PALMLD_PCMCIA_READY);
+err3:
+	gpio_free(GPIO_NR_PALMLD_PCMCIA_RESET);
+err2:
+	gpio_free(GPIO_NR_PALMLD_PCMCIA_POWER);
+err1:
+	return ret;
+}
+
+static void palmld_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt)
+{
+	gpio_free(GPIO_NR_PALMLD_PCMCIA_READY);
+	gpio_free(GPIO_NR_PALMLD_PCMCIA_RESET);
+	gpio_free(GPIO_NR_PALMLD_PCMCIA_POWER);
+}
+
+static void palmld_pcmcia_socket_state(struct soc_pcmcia_socket *skt,
+					struct pcmcia_state *state)
+{
+	state->detect = 1; /* always inserted */
+	state->ready  = !!gpio_get_value(GPIO_NR_PALMLD_PCMCIA_READY);
+	state->bvd1   = 1;
+	state->bvd2   = 1;
+	state->wrprot = 0;
+	state->vs_3v  = 1;
+	state->vs_Xv  = 0;
+}
+
+static int palmld_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
+					const socket_state_t *state)
+{
+	gpio_set_value(GPIO_NR_PALMLD_PCMCIA_POWER, 1);
+	gpio_set_value(GPIO_NR_PALMLD_PCMCIA_RESET,
+			!!(state->flags & SS_RESET));
+
+	return 0;
+}
+
+static void palmld_pcmcia_socket_init(struct soc_pcmcia_socket *skt)
+{
+}
+
+static void palmld_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt)
+{
+}
+
+static struct pcmcia_low_level palmld_pcmcia_ops = {
+	.owner			= THIS_MODULE,
+
+	.first			= 0,
+	.nr			= 2,
+
+	.hw_init		= palmld_pcmcia_hw_init,
+	.hw_shutdown		= palmld_pcmcia_hw_shutdown,
+
+	.socket_state		= palmld_pcmcia_socket_state,
+	.configure_socket	= palmld_pcmcia_configure_socket,
+
+	.socket_init		= palmld_pcmcia_socket_init,
+	.socket_suspend		= palmld_pcmcia_socket_suspend,
+};
+
+static struct platform_device *palmld_pcmcia_device;
+
+static int __init palmld_pcmcia_init(void)
+{
+	int ret;
+
+	if (!machine_is_palmld())
+		return -ENODEV;
+
+	palmld_pcmcia_device = platform_device_alloc("pxa2xx-pcmcia", -1);
+	if (!palmld_pcmcia_device)
+		return -ENOMEM;
+
+	ret = platform_device_add_data(palmld_pcmcia_device, &palmld_pcmcia_ops,
+					sizeof(palmld_pcmcia_ops));
+
+	if (!ret)
+		ret = platform_device_add(palmld_pcmcia_device);
+
+	if (ret)
+		platform_device_put(palmld_pcmcia_device);
+
+	return ret;
+}
+
+static void __exit palmld_pcmcia_exit(void)
+{
+	platform_device_unregister(palmld_pcmcia_device);
+}
+
+module_init(palmld_pcmcia_init);
+module_exit(palmld_pcmcia_exit);
+
+MODULE_AUTHOR("Alex Osborne <ato@meshy.org>,"
+	    " Marek Vasut <marek.vasut@gmail.com>");
+MODULE_DESCRIPTION("PCMCIA support for Palm LifeDrive");
+MODULE_ALIAS("platform:pxa2xx-pcmcia");
+MODULE_LICENSE("GPL");
diff --git a/drivers/pcmcia/pxa2xx_trizeps4.c b/drivers/pcmcia/pxa2xx_trizeps4.c
new file mode 100644
index 0000000..36c7a0b
--- /dev/null
+++ b/drivers/pcmcia/pxa2xx_trizeps4.c
@@ -0,0 +1,256 @@
+/*
+ * linux/drivers/pcmcia/pxa2xx_trizeps4.c
+ *
+ * TRIZEPS PCMCIA specific routines.
+ *
+ * Author:	Jürgen Schindele
+ * Created:	20 02, 2006
+ * Copyright:	Jürgen Schindele
+ *
+ * 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/init.h>
+#include <linux/kernel.h>
+#include <linux/gpio.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+
+#include <asm/mach-types.h>
+#include <asm/irq.h>
+
+#include <mach/hardware.h>
+#include <mach/pxa-regs.h>
+#include <mach/trizeps4.h>
+
+#include "soc_common.h"
+
+extern void board_pcmcia_power(int power);
+
+static struct pcmcia_irqs irqs[] = {
+	{ 0, IRQ_GPIO(GPIO_PCD), "cs0_cd" }
+	/* on other baseboards we can have more inputs */
+};
+
+static int trizeps_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
+{
+	int ret, i;
+	/* we dont have voltage/card/ready detection
+	 * so we dont need interrupts for it
+	 */
+	switch (skt->nr) {
+	case 0:
+		if (gpio_request(GPIO_PRDY, "cf_irq") < 0) {
+			pr_err("%s: sock %d unable to request gpio %d\n", __func__,
+				skt->nr, GPIO_PRDY);
+			return -EBUSY;
+		}
+		if (gpio_direction_input(GPIO_PRDY) < 0) {
+			pr_err("%s: sock %d unable to set input gpio %d\n", __func__,
+				skt->nr, GPIO_PRDY);
+			gpio_free(GPIO_PRDY);
+			return -EINVAL;
+		}
+		skt->irq = IRQ_GPIO(GPIO_PRDY);
+		break;
+
+#ifndef CONFIG_MACH_TRIZEPS_CONXS
+	case 1:
+#endif
+	default:
+		break;
+	}
+	/* release the reset of this card */
+	pr_debug("%s: sock %d irq %d\n", __func__, skt->nr, skt->irq);
+
+	/* supplementory irqs for the socket */
+	for (i = 0; i < ARRAY_SIZE(irqs); i++) {
+		if (irqs[i].sock != skt->nr)
+			continue;
+		if (gpio_request(IRQ_TO_GPIO(irqs[i].irq), irqs[i].str) < 0) {
+			pr_err("%s: sock %d unable to request gpio %d\n",
+				__func__, skt->nr, IRQ_TO_GPIO(irqs[i].irq));
+			ret = -EBUSY;
+			goto error;
+		}
+		if (gpio_direction_input(IRQ_TO_GPIO(irqs[i].irq)) < 0) {
+			pr_err("%s: sock %d unable to set input gpio %d\n",
+				__func__, skt->nr, IRQ_TO_GPIO(irqs[i].irq));
+			ret = -EINVAL;
+			goto error;
+		}
+	}
+	return soc_pcmcia_request_irqs(skt, irqs, ARRAY_SIZE(irqs));
+
+error:
+	for (; i >= 0; i--) {
+		gpio_free(IRQ_TO_GPIO(irqs[i].irq));
+	}
+	return (ret);
+}
+
+static void trizeps_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt)
+{
+	int i;
+	/* free allocated gpio's */
+	gpio_free(GPIO_PRDY);
+	for (i = 0; i < ARRAY_SIZE(irqs); i++)
+		gpio_free(IRQ_TO_GPIO(irqs[i].irq));
+}
+
+static unsigned long trizeps_pcmcia_status[2];
+
+static void trizeps_pcmcia_socket_state(struct soc_pcmcia_socket *skt,
+				struct pcmcia_state *state)
+{
+	unsigned short status = 0, change;
+	status = CFSR_readw();
+	change = (status ^ trizeps_pcmcia_status[skt->nr]) &
+				ConXS_CFSR_BVD_MASK;
+	if (change) {
+		trizeps_pcmcia_status[skt->nr] = status;
+		if (status & ConXS_CFSR_BVD1) {
+			/* enable_irq empty */
+		} else {
+			/* disable_irq empty */
+		}
+	}
+
+	switch (skt->nr) {
+	case 0:
+		/* just fill in fix states */
+		state->detect = gpio_get_value(GPIO_PCD) ? 0 : 1;
+		state->ready  = gpio_get_value(GPIO_PRDY) ? 1 : 0;
+		state->bvd1   = (status & ConXS_CFSR_BVD1) ? 1 : 0;
+		state->bvd2   = (status & ConXS_CFSR_BVD2) ? 1 : 0;
+		state->vs_3v  = (status & ConXS_CFSR_VS1) ? 0 : 1;
+		state->vs_Xv  = (status & ConXS_CFSR_VS2) ? 0 : 1;
+		state->wrprot = 0;	/* not available */
+		break;
+
+#ifndef CONFIG_MACH_TRIZEPS_CONXS
+	/* on ConXS we only have one slot. Second is inactive */
+	case 1:
+		state->detect = 0;
+		state->ready  = 0;
+		state->bvd1   = 0;
+		state->bvd2   = 0;
+		state->vs_3v  = 0;
+		state->vs_Xv  = 0;
+		state->wrprot = 0;
+		break;
+
+#endif
+	}
+}
+
+static int trizeps_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
+				const socket_state_t *state)
+{
+	int ret = 0;
+	unsigned short power = 0;
+
+	/* we do nothing here just check a bit */
+	switch (state->Vcc) {
+	case 0:  power &= 0xfc; break;
+	case 33: power |= ConXS_BCR_S0_VCC_3V3; break;
+	case 50:
+		pr_err("%s(): Vcc 5V not supported in socket\n", __func__);
+		break;
+	default:
+		pr_err("%s(): bad Vcc %u\n", __func__, state->Vcc);
+		ret = -1;
+	}
+
+	switch (state->Vpp) {
+	case 0:  power &= 0xf3; break;
+	case 33: power |= ConXS_BCR_S0_VPP_3V3; break;
+	case 120:
+		pr_err("%s(): Vpp 12V not supported in socket\n", __func__);
+		break;
+	default:
+		if (state->Vpp != state->Vcc) {
+			pr_err("%s(): bad Vpp %u\n", __func__, state->Vpp);
+			ret = -1;
+		}
+	}
+
+	switch (skt->nr) {
+	case 0:			 /* we only have 3.3V */
+		board_pcmcia_power(power);
+		break;
+
+#ifndef CONFIG_MACH_TRIZEPS_CONXS
+	/* on ConXS we only have one slot. Second is inactive */
+	case 1:
+#endif
+	default:
+		break;
+	}
+
+	return ret;
+}
+
+static void trizeps_pcmcia_socket_init(struct soc_pcmcia_socket *skt)
+{
+	/* default is on */
+	board_pcmcia_power(0x9);
+}
+
+static void trizeps_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt)
+{
+	board_pcmcia_power(0x0);
+}
+
+static struct pcmcia_low_level trizeps_pcmcia_ops = {
+	.owner			= THIS_MODULE,
+	.hw_init		= trizeps_pcmcia_hw_init,
+	.hw_shutdown		= trizeps_pcmcia_hw_shutdown,
+	.socket_state		= trizeps_pcmcia_socket_state,
+	.configure_socket	= trizeps_pcmcia_configure_socket,
+	.socket_init		= trizeps_pcmcia_socket_init,
+	.socket_suspend		= trizeps_pcmcia_socket_suspend,
+#ifdef CONFIG_MACH_TRIZEPS_CONXS
+	.nr			= 1,
+#else
+	.nr			= 2,
+#endif
+	.first			= 0,
+};
+
+static struct platform_device *trizeps_pcmcia_device;
+
+static int __init trizeps_pcmcia_init(void)
+{
+	int ret;
+
+	trizeps_pcmcia_device = platform_device_alloc("pxa2xx-pcmcia", -1);
+	if (!trizeps_pcmcia_device)
+		return -ENOMEM;
+
+	ret = platform_device_add_data(trizeps_pcmcia_device,
+			&trizeps_pcmcia_ops, sizeof(trizeps_pcmcia_ops));
+
+	if (ret == 0)
+		ret = platform_device_add(trizeps_pcmcia_device);
+
+	if (ret)
+		platform_device_put(trizeps_pcmcia_device);
+
+	return ret;
+}
+
+static void __exit trizeps_pcmcia_exit(void)
+{
+	platform_device_unregister(trizeps_pcmcia_device);
+}
+
+fs_initcall(trizeps_pcmcia_init);
+module_exit(trizeps_pcmcia_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Juergen Schindele");
+MODULE_ALIAS("platform:pxa2xx-pcmcia");
diff --git a/drivers/pcmcia/pxa2xx_viper.c b/drivers/pcmcia/pxa2xx_viper.c
new file mode 100644
index 0000000..dd10481
--- /dev/null
+++ b/drivers/pcmcia/pxa2xx_viper.c
@@ -0,0 +1,179 @@
+/*
+ * VIPER PCMCIA support
+ *   Copyright 2004 Arcom Control Systems
+ *
+ * Maintained by Marc Zyngier <maz@misterjones.org>
+ * 			      <marc.zyngier@altran.com>
+ *
+ * Based on:
+ *   iPAQ h2200 PCMCIA support
+ *   Copyright 2004 Koen Kooi <koen@vestingbar.nl>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file COPYING in the main directory of this archive for
+ * more details.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+
+#include <pcmcia/ss.h>
+
+#include <asm/irq.h>
+
+#include <mach/pxa-regs.h>
+#include <mach/viper.h>
+#include <asm/mach-types.h>
+
+#include "soc_common.h"
+#include "pxa2xx_base.h"
+
+static struct pcmcia_irqs irqs[] = {
+	{ 0, gpio_to_irq(VIPER_CF_CD_GPIO),  "PCMCIA_CD" }
+};
+
+static int viper_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
+{
+	unsigned long flags;
+
+	skt->irq = gpio_to_irq(VIPER_CF_RDY_GPIO);
+
+	if (gpio_request(VIPER_CF_CD_GPIO, "CF detect"))
+		goto err_request_cd;
+
+	if (gpio_request(VIPER_CF_RDY_GPIO, "CF ready"))
+		goto err_request_rdy;
+
+	if (gpio_request(VIPER_CF_POWER_GPIO, "CF power"))
+		goto err_request_pwr;
+
+	local_irq_save(flags);
+
+	/* GPIO 82 is the CF power enable line. initially off */
+	if (gpio_direction_output(VIPER_CF_POWER_GPIO, 0) ||
+	    gpio_direction_input(VIPER_CF_CD_GPIO) ||
+	    gpio_direction_input(VIPER_CF_RDY_GPIO)) {
+		local_irq_restore(flags);
+		goto err_dir;
+	}
+
+	local_irq_restore(flags);
+
+	return soc_pcmcia_request_irqs(skt, irqs, ARRAY_SIZE(irqs));
+
+err_dir:
+	gpio_free(VIPER_CF_POWER_GPIO);
+err_request_pwr:
+	gpio_free(VIPER_CF_RDY_GPIO);
+err_request_rdy:
+	gpio_free(VIPER_CF_CD_GPIO);
+err_request_cd:
+	printk(KERN_ERR "viper: Failed to setup PCMCIA GPIOs\n");
+	return -1;
+}
+
+/*
+ * Release all resources.
+ */
+static void viper_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt)
+{
+	soc_pcmcia_free_irqs(skt, irqs, ARRAY_SIZE(irqs));
+	gpio_free(VIPER_CF_POWER_GPIO);
+	gpio_free(VIPER_CF_RDY_GPIO);
+	gpio_free(VIPER_CF_CD_GPIO);
+}
+
+static void viper_pcmcia_socket_state(struct soc_pcmcia_socket *skt,
+				      struct pcmcia_state *state)
+{
+	state->detect = gpio_get_value(VIPER_CF_CD_GPIO) ? 0 : 1;
+	state->ready  = gpio_get_value(VIPER_CF_RDY_GPIO) ? 1 : 0;
+	state->bvd1   = 1;
+	state->bvd2   = 1;
+	state->wrprot = 0;
+	state->vs_3v  = 1; /* Can only apply 3.3V */
+	state->vs_Xv  = 0;
+}
+
+static int viper_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
+					 const socket_state_t *state)
+{
+	/* Silently ignore Vpp, output enable, speaker enable. */
+	viper_cf_rst(state->flags & SS_RESET);
+
+	/* Apply socket voltage */
+	switch (state->Vcc) {
+	case 0:
+		gpio_set_value(VIPER_CF_POWER_GPIO, 0);
+		break;
+	case 33:
+		gpio_set_value(VIPER_CF_POWER_GPIO, 1);
+		break;
+	default:
+		printk(KERN_ERR "%s: Unsupported Vcc:%d\n",
+		       __func__, state->Vcc);
+		return -1;
+	}
+
+	return 0;
+}
+
+static void viper_pcmcia_socket_init(struct soc_pcmcia_socket *skt)
+{
+}
+
+static void viper_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt)
+{
+}
+
+static struct pcmcia_low_level viper_pcmcia_ops __initdata = {
+	.owner          	= THIS_MODULE,
+	.hw_init        	= viper_pcmcia_hw_init,
+	.hw_shutdown		= viper_pcmcia_hw_shutdown,
+	.socket_state		= viper_pcmcia_socket_state,
+	.configure_socket	= viper_pcmcia_configure_socket,
+	.socket_init		= viper_pcmcia_socket_init,
+	.socket_suspend		= viper_pcmcia_socket_suspend,
+	.nr         		= 1,
+};
+
+static struct platform_device *viper_pcmcia_device;
+
+static int __init viper_pcmcia_init(void)
+{
+	int ret;
+
+	if (!machine_is_viper())
+		return -ENODEV;
+
+	viper_pcmcia_device = platform_device_alloc("pxa2xx-pcmcia", -1);
+	if (!viper_pcmcia_device)
+		return -ENOMEM;
+
+	ret = platform_device_add_data(viper_pcmcia_device,
+				       &viper_pcmcia_ops,
+				       sizeof(viper_pcmcia_ops));
+
+	if (!ret)
+		ret = platform_device_add(viper_pcmcia_device);
+
+	if (ret)
+		platform_device_put(viper_pcmcia_device);
+
+	return ret;
+}
+
+static void __exit viper_pcmcia_exit(void)
+{
+	platform_device_unregister(viper_pcmcia_device);
+}
+
+module_init(viper_pcmcia_init);
+module_exit(viper_pcmcia_exit);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/pcmcia/rsrc_nonstatic.c b/drivers/pcmcia/rsrc_nonstatic.c
index 203e579..17f4ecf 100644
--- a/drivers/pcmcia/rsrc_nonstatic.c
+++ b/drivers/pcmcia/rsrc_nonstatic.c
@@ -122,19 +122,22 @@
 
 static int add_interval(struct resource_map *map, u_long base, u_long num)
 {
-    struct resource_map *p, *q;
+	struct resource_map *p, *q;
 
-    for (p = map; ; p = p->next) {
-	if ((p != map) && (p->base+p->num-1 >= base))
-	    return -1;
-	if ((p->next == map) || (p->next->base > base+num-1))
-	    break;
-    }
-    q = kmalloc(sizeof(struct resource_map), GFP_KERNEL);
-    if (!q) return CS_OUT_OF_RESOURCE;
-    q->base = base; q->num = num;
-    q->next = p->next; p->next = q;
-    return CS_SUCCESS;
+	for (p = map; ; p = p->next) {
+		if ((p != map) && (p->base+p->num-1 >= base))
+			return -1;
+		if ((p->next == map) || (p->next->base > base+num-1))
+			break;
+	}
+	q = kmalloc(sizeof(struct resource_map), GFP_KERNEL);
+	if (!q) {
+		printk(KERN_WARNING "out of memory to update resources\n");
+		return -ENOMEM;
+	}
+	q->base = base; q->num = num;
+	q->next = p->next; p->next = q;
+	return 0;
 }
 
 /*====================================================================*/
@@ -166,7 +169,10 @@
 	    } else {
 		/* Split the block into two pieces */
 		p = kmalloc(sizeof(struct resource_map), GFP_KERNEL);
-		if (!p) return CS_OUT_OF_RESOURCE;
+		if (!p) {
+		    printk(KERN_WARNING "out of memory to update resources\n");
+		    return -ENOMEM;
+		}
 		p->base = base+num;
 		p->num = q->base+q->num - p->base;
 		q->num = base - q->base;
@@ -174,7 +180,7 @@
 	    }
 	}
     }
-    return CS_SUCCESS;
+    return 0;
 }
 
 /*======================================================================
@@ -194,13 +200,14 @@
     int any;
     u_char *b, hole, most;
 
-    printk(KERN_INFO "cs: IO port probe %#x-%#x:",
-	   base, base+num-1);
+    dev_printk(KERN_INFO, &s->dev, "cs: IO port probe %#x-%#x:",
+	       base, base+num-1);
 
     /* First, what does a floating port look like? */
     b = kzalloc(256, GFP_KERNEL);
     if (!b) {
-            printk(KERN_ERR "do_io_probe: unable to kmalloc 256 bytes");
+	    dev_printk(KERN_ERR, &s->dev,
+		   "do_io_probe: unable to kmalloc 256 bytes");
             return;
     }
     for (i = base, most = 0; i < base+num; i += 8) {
@@ -366,8 +373,8 @@
     struct socket_data *s_data = s->resource_data;
     u_long i, j, bad, fail, step;
 
-    printk(KERN_INFO "cs: memory probe 0x%06lx-0x%06lx:",
-	   base, base+num-1);
+    dev_printk(KERN_INFO, &s->dev, "cs: memory probe 0x%06lx-0x%06lx:",
+	       base, base+num-1);
     bad = fail = 0;
     step = (num < 0x20000) ? 0x2000 : ((num>>4) & ~0x1fff);
     /* don't allow too large steps */
@@ -431,8 +438,8 @@
 	if (probe_mask & MEM_PROBE_HIGH) {
 		if (inv_probe(s_data->mem_db.next, s) > 0)
 			return 0;
-		printk(KERN_NOTICE "cs: warning: no high memory space "
-		       "available!\n");
+		dev_printk(KERN_NOTICE, &s->dev,
+			   "cs: warning: no high memory space available!\n");
 		return -ENODEV;
 	}
 
@@ -794,10 +801,11 @@
 		if (res->flags & IORESOURCE_IO) {
 			if (res == &ioport_resource)
 				continue;
-			printk(KERN_INFO "pcmcia: parent PCI bridge I/O "
-				"window: 0x%llx - 0x%llx\n",
-				(unsigned long long)res->start,
-				(unsigned long long)res->end);
+			dev_printk(KERN_INFO, &s->cb_dev->dev,
+				   "pcmcia: parent PCI bridge I/O "
+				   "window: 0x%llx - 0x%llx\n",
+				   (unsigned long long)res->start,
+				   (unsigned long long)res->end);
 			if (!adjust_io(s, ADD_MANAGED_RESOURCE, res->start, res->end))
 				done |= IORESOURCE_IO;
 
@@ -806,10 +814,11 @@
 		if (res->flags & IORESOURCE_MEM) {
 			if (res == &iomem_resource)
 				continue;
-			printk(KERN_INFO "pcmcia: parent PCI bridge Memory "
-				"window: 0x%llx - 0x%llx\n",
-				(unsigned long long)res->start,
-				(unsigned long long)res->end);
+			dev_printk(KERN_INFO, &s->cb_dev->dev,
+				   "pcmcia: parent PCI bridge Memory "
+				   "window: 0x%llx - 0x%llx\n",
+				   (unsigned long long)res->start,
+				   (unsigned long long)res->end);
 			if (!adjust_memory(s, ADD_MANAGED_RESOURCE, res->start, res->end))
 				done |= IORESOURCE_MEM;
 		}
diff --git a/drivers/pcmcia/soc_common.c b/drivers/pcmcia/soc_common.c
index da39721..f49ac66 100644
--- a/drivers/pcmcia/soc_common.c
+++ b/drivers/pcmcia/soc_common.c
@@ -54,7 +54,7 @@
 #include <mach/pxa-regs.h>
 #endif
 
-#ifdef DEBUG
+#ifdef CONFIG_PCMCIA_DEBUG
 
 static int pc_debug;
 module_param(pc_debug, int, 0644);
diff --git a/drivers/pcmcia/soc_common.h b/drivers/pcmcia/soc_common.h
index 91ef6a0..38c6737 100644
--- a/drivers/pcmcia/soc_common.h
+++ b/drivers/pcmcia/soc_common.h
@@ -15,7 +15,6 @@
 #include <pcmcia/cs.h>
 #include <pcmcia/ss.h>
 #include <pcmcia/cistpl.h>
-#include "cs_internal.h"
 
 
 struct device;
@@ -137,7 +136,7 @@
 extern int soc_common_drv_pcmcia_remove(struct device *dev);
 
 
-#ifdef DEBUG
+#ifdef CONFIG_PCMCIA_DEBUG
 
 extern void soc_pcmcia_debug(struct soc_pcmcia_socket *skt, const char *func,
 			     int lvl, const char *fmt, ...);
diff --git a/drivers/pcmcia/socket_sysfs.c b/drivers/pcmcia/socket_sysfs.c
index 006a29e..ff9a3bb 100644
--- a/drivers/pcmcia/socket_sysfs.c
+++ b/drivers/pcmcia/socket_sysfs.c
@@ -316,27 +316,18 @@
 				char *buf, loff_t off, size_t count)
 {
 	struct pcmcia_socket *s = to_socket(container_of(kobj, struct device, kobj));
-	cisdump_t *cis;
 	int error;
 
 	if (off)
 		return -EINVAL;
 
-	if (count >= 0x200)
+	if (count >= CISTPL_MAX_CIS_SIZE)
 		return -EINVAL;
 
 	if (!(s->state & SOCKET_PRESENT))
 		return -ENODEV;
 
-	cis = kzalloc(sizeof(cisdump_t), GFP_KERNEL);
-	if (!cis)
-		return -ENOMEM;
-
-	cis->Length = count + 1;
-	memcpy(cis->Data, buf, count);
-
-	error = pcmcia_replace_cis(s, cis);
-	kfree(cis);
+	error = pcmcia_replace_cis(s, buf, count);
 	if (error)
 		return -EIO;
 
diff --git a/drivers/pcmcia/tcic.c b/drivers/pcmcia/tcic.c
index 5792bd5..2a613e9 100644
--- a/drivers/pcmcia/tcic.c
+++ b/drivers/pcmcia/tcic.c
@@ -55,7 +55,7 @@
 #include <pcmcia/ss.h>
 #include "tcic.h"
 
-#ifdef DEBUG
+#ifdef CONFIG_PCMCIA_DEBUG
 static int pc_debug;
 
 module_param(pc_debug, int, 0644);
diff --git a/drivers/pcmcia/ti113x.h b/drivers/pcmcia/ti113x.h
index 129db7b..aaa7022 100644
--- a/drivers/pcmcia/ti113x.h
+++ b/drivers/pcmcia/ti113x.h
@@ -339,8 +339,8 @@
 
 	mfunc = mfunc_old = config_readl(socket, TI122X_MFUNC);
 	devctl = config_readb(socket, TI113X_DEVICE_CONTROL);
-	printk(KERN_INFO "Yenta TI: socket %s, mfunc 0x%08x, devctl 0x%02x\n",
-	       pci_name(socket->dev), mfunc, devctl);
+	dev_printk(KERN_INFO, &socket->dev->dev,
+		   "TI: mfunc 0x%08x, devctl 0x%02x\n", mfunc, devctl);
 
 	/* make sure PCI interrupts are enabled before probing */
 	ti_init(socket);
@@ -354,8 +354,8 @@
 	 * We're here which means PCI interrupts are _not_ delivered. try to
 	 * find the right setting (all serial or parallel)
 	 */
-	printk(KERN_INFO "Yenta TI: socket %s probing PCI interrupt failed, trying to fix\n",
-	       pci_name(socket->dev));
+	dev_printk(KERN_INFO, &socket->dev->dev,
+		   "TI: probing PCI interrupt failed, trying to fix\n");
 
 	/* for serial PCI make sure MFUNC3 is set to IRQSER */
 	if ((devctl & TI113X_DCR_IMODE_MASK) == TI12XX_DCR_IMODE_ALL_SERIAL) {
@@ -379,8 +379,8 @@
 
 				pci_irq_status = yenta_probe_cb_irq(socket);
 				if (pci_irq_status == 1) {
-					printk(KERN_INFO "Yenta TI: socket %s all-serial interrupts ok\n",
-					       pci_name(socket->dev));
+					dev_printk(KERN_INFO, &socket->dev->dev,
+					    "TI: all-serial interrupts ok\n");
 					mfunc_old = mfunc;
 					goto out;
 				}
@@ -395,8 +395,8 @@
 		}
 
 		/* serial PCI interrupts not working fall back to parallel */
-		printk(KERN_INFO "Yenta TI: socket %s falling back to parallel PCI interrupts\n",
-		       pci_name(socket->dev));
+		dev_printk(KERN_INFO, &socket->dev->dev,
+			   "TI: falling back to parallel PCI interrupts\n");
 		devctl &= ~TI113X_DCR_IMODE_MASK;
 		devctl |= TI113X_DCR_IMODE_SERIAL; /* serial ISA could be right */
 		config_writeb(socket, TI113X_DEVICE_CONTROL, devctl);
@@ -427,8 +427,8 @@
 	pci_irq_status = yenta_probe_cb_irq(socket);
 	if (pci_irq_status == 1) {
 		mfunc_old = mfunc;
-		printk(KERN_INFO "Yenta TI: socket %s parallel PCI interrupts ok\n",
-		       pci_name(socket->dev));
+		dev_printk(KERN_INFO, &socket->dev->dev,
+			   "TI: parallel PCI interrupts ok\n");
 	} else {
 		/* not working, back to old value */
 		mfunc = mfunc_old;
@@ -440,8 +440,9 @@
 out:
 	if (pci_irq_status < 1) {
 		socket->cb_irq = 0;
-		printk(KERN_INFO "Yenta TI: socket %s no PCI interrupts. Fish. Please report.\n",
-		       pci_name(socket->dev));
+		dev_printk(KERN_INFO, &socket->dev->dev,
+			   "Yenta TI: no PCI interrupts. Fish. "
+			   "Please report.\n");
 	}
 }
 
@@ -513,8 +514,9 @@
 
 	mfunc = mfunc_old = config_readl(socket, TI122X_MFUNC);
 	devctl = config_readb(socket, TI113X_DEVICE_CONTROL);
-	printk(KERN_INFO "Yenta TI: socket %s, mfunc 0x%08x, devctl 0x%02x\n",
-	       pci_name(socket->dev), mfunc, devctl);
+	dev_printk(KERN_INFO, &socket->dev->dev,
+		   "TI: mfunc 0x%08x, devctl 0x%02x\n",
+		   mfunc, devctl);
 
 	/* if IRQs are configured as tied, align irq of func1 with func0 */
 	sysctl = config_readl(socket, TI113X_SYSTEM_CONTROL);
@@ -533,9 +535,8 @@
 	 * We're here which means PCI interrupts are _not_ delivered. try to
 	 * find the right setting
 	 */
-	printk(KERN_INFO "Yenta TI: socket %s probing PCI interrupt failed, trying to fix\n",
-	       pci_name(socket->dev));
-
+	dev_printk(KERN_INFO, &socket->dev->dev,
+		   "TI: probing PCI interrupt failed, trying to fix\n");
 
 	/* if all serial: set INTRTIE, probe again */
 	if ((devctl & TI113X_DCR_IMODE_MASK) == TI12XX_DCR_IMODE_ALL_SERIAL) {
@@ -544,8 +545,8 @@
 		if (ti12xx_tie_interrupts(socket, &old_irq)) {
 			pci_irq_status = yenta_probe_cb_irq(socket);
 			if (pci_irq_status == 1) {
-				printk(KERN_INFO "Yenta TI: socket %s all-serial interrupts, tied ok\n",
-				       pci_name(socket->dev));
+				dev_printk(KERN_INFO, &socket->dev->dev,
+					"TI: all-serial interrupts, tied ok\n");
 				goto out;
 			}
 
@@ -582,8 +583,8 @@
 
 			pci_irq_status = yenta_probe_cb_irq(socket);
 			if (pci_irq_status == 1) {
-				printk(KERN_INFO "Yenta TI: socket %s parallel PCI interrupts ok\n",
-				       pci_name(socket->dev));
+				dev_printk(KERN_INFO, &socket->dev->dev,
+					   "TI: parallel PCI interrupts ok\n");
 				goto out;
 			}
 
@@ -593,13 +594,13 @@
 			if (pci_irq_status == -1)
 				goto out;
 		}
-		
+
 		/* still nothing: set INTRTIE */
 		if (ti12xx_tie_interrupts(socket, &old_irq)) {
 			pci_irq_status = yenta_probe_cb_irq(socket);
 			if (pci_irq_status == 1) {
-				printk(KERN_INFO "Yenta TI: socket %s parallel PCI interrupts, tied ok\n",
-				       pci_name(socket->dev));
+				dev_printk(KERN_INFO, &socket->dev->dev,
+				    "TI: parallel PCI interrupts, tied ok\n");
 				goto out;
 			}
 
@@ -610,8 +611,8 @@
 out:
 	if (pci_irq_status < 1) {
 		socket->cb_irq = 0;
-		printk(KERN_INFO "Yenta TI: socket %s no PCI interrupts. Fish. Please report.\n",
-		       pci_name(socket->dev));
+		dev_printk(KERN_INFO, &socket->dev->dev,
+			   "TI: no PCI interrupts. Fish. Please report.\n");
 	}
 }
 
@@ -815,11 +816,13 @@
 	/* make sure that memory burst is active */
 	val_orig = val = config_readl(socket, TI113X_SYSTEM_CONTROL);
 	if (disable_clkrun && PCI_FUNC(socket->dev->devfn) == 0) {
-		printk(KERN_INFO "Yenta: Disabling CLKRUN feature\n");
+		dev_printk(KERN_INFO, &socket->dev->dev,
+			   "Disabling CLKRUN feature\n");
 		val |= TI113X_SCR_KEEPCLK;
 	}
 	if (!(val & TI122X_SCR_MRBURSTUP)) {
-		printk(KERN_INFO "Yenta: Enabling burst memory read transactions\n");
+		dev_printk(KERN_INFO, &socket->dev->dev,
+			   "Enabling burst memory read transactions\n");
 		val |= TI122X_SCR_MRBURSTUP;
 	}
 	if (val_orig != val)
@@ -830,10 +833,12 @@
 	 * CSC interrupts to PCI rather than INTVAL.
 	 */
 	val = config_readb(socket, TI1250_DIAGNOSTIC);
-	printk(KERN_INFO "Yenta: Using %s to route CSC interrupts to PCI\n",
-		(val & TI1250_DIAG_PCI_CSC) ? "CSCINT" : "INTVAL");
-	printk(KERN_INFO "Yenta: Routing CardBus interrupts to %s\n",
-		(val & TI1250_DIAG_PCI_IREQ) ? "PCI" : "ISA");
+	dev_printk(KERN_INFO, &socket->dev->dev,
+		   "Using %s to route CSC interrupts to PCI\n",
+		   (val & TI1250_DIAG_PCI_CSC) ? "CSCINT" : "INTVAL");
+	dev_printk(KERN_INFO, &socket->dev->dev,
+		   "Routing CardBus interrupts to %s\n",
+		   (val & TI1250_DIAG_PCI_IREQ) ? "PCI" : "ISA");
 
 	/* do irqrouting, depending on function */
 	if (PCI_FUNC(socket->dev->devfn) == 0)
@@ -858,8 +863,9 @@
 		diag |= TI1250_DIAG_PCI_CSC | TI1250_DIAG_PCI_IREQ;
 
 	if (diag != old) {
-		printk(KERN_INFO "Yenta: adjusting diagnostic: %02x -> %02x\n",
-			old, diag);
+		dev_printk(KERN_INFO, &socket->dev->dev,
+			   "adjusting diagnostic: %02x -> %02x\n",
+			   old, diag);
 		config_writeb(socket, TI1250_DIAGNOSTIC, diag);
 	}
 
@@ -924,7 +930,9 @@
 		/* default to clear TLTEnable bit, old behaviour */
 		test_c9 &= ~ENE_TEST_C9_TLTENABLE;
 
-	printk(KERN_INFO "yenta EnE: chaning testregister 0xC9, %02x -> %02x\n", old_c9, test_c9);
+	dev_printk(KERN_INFO, &socket->dev->dev,
+		   "EnE: chaning testregister 0xC9, %02x -> %02x\n",
+		   old_c9, test_c9);
 	config_writeb(socket, ENE_TEST_C9, test_c9);
 }
 
diff --git a/drivers/pcmcia/yenta_socket.c b/drivers/pcmcia/yenta_socket.c
index 0ab1fb6..3ecd7c9 100644
--- a/drivers/pcmcia/yenta_socket.c
+++ b/drivers/pcmcia/yenta_socket.c
@@ -38,11 +38,7 @@
 module_param(pwr_irqs_off, bool, 0644);
 MODULE_PARM_DESC(pwr_irqs_off, "Force IRQs off during power-on of slot. Use only when seeing IRQ storms!");
 
-#if 0
-#define debug(x,args...) printk(KERN_DEBUG "%s: " x, __func__ , ##args)
-#else
-#define debug(x,args...)
-#endif
+#define debug(x, s, args...) dev_dbg(&s->dev->dev, x, ##args)
 
 /* Don't ask.. */
 #define to_cycles(ns)	((ns)/120)
@@ -69,13 +65,13 @@
 static inline u32 cb_readl(struct yenta_socket *socket, unsigned reg)
 {
 	u32 val = readl(socket->base + reg);
-	debug("%p %04x %08x\n", socket, reg, val);
+	debug("%04x %08x\n", socket, reg, val);
 	return val;
 }
 
 static inline void cb_writel(struct yenta_socket *socket, unsigned reg, u32 val)
 {
-	debug("%p %04x %08x\n", socket, reg, val);
+	debug("%04x %08x\n", socket, reg, val);
 	writel(val, socket->base + reg);
 	readl(socket->base + reg); /* avoid problems with PCI write posting */
 }
@@ -84,7 +80,7 @@
 {
 	u8 val;
 	pci_read_config_byte(socket->dev, offset, &val);
-	debug("%p %04x %02x\n", socket, offset, val);
+	debug("%04x %02x\n", socket, offset, val);
 	return val;
 }
 
@@ -92,7 +88,7 @@
 {
 	u16 val;
 	pci_read_config_word(socket->dev, offset, &val);
-	debug("%p %04x %04x\n", socket, offset, val);
+	debug("%04x %04x\n", socket, offset, val);
 	return val;
 }
 
@@ -100,32 +96,32 @@
 {
 	u32 val;
 	pci_read_config_dword(socket->dev, offset, &val);
-	debug("%p %04x %08x\n", socket, offset, val);
+	debug("%04x %08x\n", socket, offset, val);
 	return val;
 }
 
 static inline void config_writeb(struct yenta_socket *socket, unsigned offset, u8 val)
 {
-	debug("%p %04x %02x\n", socket, offset, val);
+	debug("%04x %02x\n", socket, offset, val);
 	pci_write_config_byte(socket->dev, offset, val);
 }
 
 static inline void config_writew(struct yenta_socket *socket, unsigned offset, u16 val)
 {
-	debug("%p %04x %04x\n", socket, offset, val);
+	debug("%04x %04x\n", socket, offset, val);
 	pci_write_config_word(socket->dev, offset, val);
 }
 
 static inline void config_writel(struct yenta_socket *socket, unsigned offset, u32 val)
 {
-	debug("%p %04x %08x\n", socket, offset, val);
+	debug("%04x %08x\n", socket, offset, val);
 	pci_write_config_dword(socket->dev, offset, val);
 }
 
 static inline u8 exca_readb(struct yenta_socket *socket, unsigned reg)
 {
 	u8 val = readb(socket->base + 0x800 + reg);
-	debug("%p %04x %02x\n", socket, reg, val);
+	debug("%04x %02x\n", socket, reg, val);
 	return val;
 }
 
@@ -134,20 +130,20 @@
 	u16 val;
 	val = readb(socket->base + 0x800 + reg);
 	val |= readb(socket->base + 0x800 + reg + 1) << 8;
-	debug("%p %04x %04x\n", socket, reg, val);
+	debug("%04x %04x\n", socket, reg, val);
 	return val;
 }
 
 static inline void exca_writeb(struct yenta_socket *socket, unsigned reg, u8 val)
 {
-	debug("%p %04x %02x\n", socket, reg, val);
+	debug("%04x %02x\n", socket, reg, val);
 	writeb(val, socket->base + 0x800 + reg);
 	readb(socket->base + 0x800 + reg); /* PCI write posting... */
 }
 
 static void exca_writew(struct yenta_socket *socket, unsigned reg, u16 val)
 {
-	debug("%p %04x %04x\n", socket, reg, val);
+	debug("%04x %04x\n", socket, reg, val);
 	writeb(val, socket->base + 0x800 + reg);
 	writeb(val >> 8, socket->base + 0x800 + reg + 1);
 
@@ -207,7 +203,7 @@
 
 
 	if (state & CB_CBCARD) {
-		val |= SS_CARDBUS;	
+		val |= SS_CARDBUS;
 		val |= (state & CB_CARDSTS) ? SS_STSCHG : 0;
 		val |= (state & (CB_CDETECT1 | CB_CDETECT2)) ? 0 : SS_DETECT;
 		val |= (state & CB_PWRCYCLE) ? SS_POWERON | SS_READY : 0;
@@ -650,8 +646,10 @@
 		root = pci_find_parent_resource(socket->dev, res);
 		if (root && (request_resource(root, res) == 0))
 			return 0;
-		printk(KERN_INFO "yenta %s: Preassigned resource %d busy or not available, reconfiguring...\n",
-				pci_name(socket->dev), nr);
+		dev_printk(KERN_INFO, &socket->dev->dev,
+			   "Preassigned resource %d busy or not available, "
+			   "reconfiguring...\n",
+			   nr);
 	}
 
 	if (type & IORESOURCE_IO) {
@@ -674,8 +672,9 @@
 			return 1;
 	}
 
-	printk(KERN_INFO "yenta %s: no resource of type %x available, trying to continue...\n",
-	       pci_name(socket->dev), type);
+	dev_printk(KERN_INFO, &socket->dev->dev,
+		   "no resource of type %x available, trying to continue...\n",
+		   type);
 	res->start = res->end = res->flags = 0;
 	return 0;
 }
@@ -923,7 +922,8 @@
 	socket->probe_status = 0;
 
 	if (request_irq(socket->cb_irq, yenta_probe_handler, IRQF_SHARED, "yenta", socket)) {
-		printk(KERN_WARNING "Yenta: request_irq() in yenta_probe_cb_irq() failed!\n");
+		dev_printk(KERN_WARNING, &socket->dev->dev,
+			   "request_irq() in yenta_probe_cb_irq() failed!\n");
 		return -1;
 	}
 
@@ -960,8 +960,9 @@
 	else
 		socket->socket.irq_mask = 0;
 
-	printk(KERN_INFO "Yenta: ISA IRQ mask 0x%04x, PCI irq %d\n",
-	       socket->socket.irq_mask, socket->cb_irq);
+	dev_printk(KERN_INFO, &socket->dev->dev,
+		   "ISA IRQ mask 0x%04x, PCI irq %d\n",
+		   socket->socket.irq_mask, socket->cb_irq);
 }
 
 /*
@@ -1051,8 +1052,9 @@
 
 	/* Show that the wanted subordinate number is not possible: */
 	if (cardbus_bridge->subordinate > upper_limit)
-		printk(KERN_WARNING "Yenta: Upper limit for fixing this "
-			"bridge's parent bridge: #%02x\n", upper_limit);
+		dev_printk(KERN_WARNING, &cardbus_bridge->dev,
+			   "Upper limit for fixing this "
+			   "bridge's parent bridge: #%02x\n", upper_limit);
 
 	/* If we have room to increase the bridge's subordinate number, */
 	if (bridge_to_fix->subordinate < upper_limit) {
@@ -1061,10 +1063,11 @@
 		unsigned char subordinate_to_assign =
 			min(cardbus_bridge->subordinate, upper_limit);
 
-		printk(KERN_INFO "Yenta: Raising subordinate bus# of parent "
-			"bus (#%02x) from #%02x to #%02x\n",
-			bridge_to_fix->number,
-			bridge_to_fix->subordinate, subordinate_to_assign);
+		dev_printk(KERN_INFO, &bridge_to_fix->dev,
+			   "Raising subordinate bus# of parent "
+			   "bus (#%02x) from #%02x to #%02x\n",
+			   bridge_to_fix->number,
+			   bridge_to_fix->subordinate, subordinate_to_assign);
 
 		/* Save the new subordinate in the bus struct of the bridge */
 		bridge_to_fix->subordinate = subordinate_to_assign;
@@ -1091,8 +1094,8 @@
 	 * Bail out if so.
 	 */
 	if (!dev->subordinate) {
-		printk(KERN_ERR "Yenta: no bus associated with %s! "
-			"(try 'pci=assign-busses')\n", pci_name(dev));
+		dev_printk(KERN_ERR, &dev->dev, "no bus associated! "
+			   "(try 'pci=assign-busses')\n");
 		return -ENODEV;
 	}
 
@@ -1127,7 +1130,7 @@
 		goto disable;
 
 	if (!pci_resource_start(dev, 0)) {
-		printk(KERN_ERR "No cardbus resource!\n");
+		dev_printk(KERN_ERR, &dev->dev, "No cardbus resource!\n");
 		ret = -ENODEV;
 		goto release;
 	}
@@ -1146,8 +1149,8 @@
 	 * report the subsystem vendor and device for help debugging
 	 * the irq stuff...
 	 */
-	printk(KERN_INFO "Yenta: CardBus bridge found at %s [%04x:%04x]\n",
-		pci_name(dev), dev->subsystem_vendor, dev->subsystem_device);
+	dev_printk(KERN_INFO, &dev->dev, "CardBus bridge found [%04x:%04x]\n",
+		   dev->subsystem_vendor, dev->subsystem_device);
 
 	yenta_config_init(socket);
 
@@ -1179,8 +1182,12 @@
 		socket->poll_timer.data = (unsigned long)socket;
 		socket->poll_timer.expires = jiffies + HZ;
 		add_timer(&socket->poll_timer);
-		printk(KERN_INFO "Yenta: no PCI IRQ, CardBus support disabled for this socket.\n"
-		       KERN_INFO "Yenta: check your BIOS CardBus, BIOS IRQ or ACPI settings.\n");
+		dev_printk(KERN_INFO, &dev->dev,
+			   "no PCI IRQ, CardBus support disabled for this "
+			   "socket.\n");
+		dev_printk(KERN_INFO, &dev->dev,
+			   "check your BIOS CardBus, BIOS IRQ or ACPI "
+			   "settings.\n");
 	} else {
 		socket->socket.features |= SS_CAP_CARDBUS;
 	}
@@ -1188,7 +1195,8 @@
 	/* Figure out what the dang thing can do for the PCMCIA layer... */
 	yenta_interrogate(socket);
 	yenta_get_socket_capabilities(socket, isa_interrupts);
-	printk(KERN_INFO "Socket status: %08x\n", cb_readl(socket, CB_SOCKET_STATE));
+	dev_printk(KERN_INFO, &dev->dev,
+		   "Socket status: %08x\n", cb_readl(socket, CB_SOCKET_STATE));
 
 	yenta_fixup_parent_bridge(dev->subordinate);
 
diff --git a/drivers/pnp/Makefile b/drivers/pnp/Makefile
index 26f5abc..e83f34f 100644
--- a/drivers/pnp/Makefile
+++ b/drivers/pnp/Makefile
@@ -2,12 +2,15 @@
 # Makefile for the Linux Plug-and-Play Support.
 #
 
-obj-y		:= core.o card.o driver.o resource.o manager.o support.o interface.o quirks.o system.o
+obj-y		:= core.o card.o driver.o resource.o manager.o support.o interface.o quirks.o
 
 obj-$(CONFIG_PNPACPI)		+= pnpacpi/
 obj-$(CONFIG_PNPBIOS)		+= pnpbios/
 obj-$(CONFIG_ISAPNP)		+= isapnp/
 
+# pnp_system_init goes after pnpacpi/pnpbios init
+obj-y				+= system.o
+
 ifeq ($(CONFIG_PNP_DEBUG),y)
 EXTRA_CFLAGS += -DDEBUG
 endif
diff --git a/drivers/pnp/pnpacpi/core.c b/drivers/pnp/pnpacpi/core.c
index c1b9ea3..53561d7 100644
--- a/drivers/pnp/pnpacpi/core.c
+++ b/drivers/pnp/pnpacpi/core.c
@@ -268,7 +268,7 @@
 	return 0;
 }
 
-subsys_initcall(pnpacpi_init);
+fs_initcall(pnpacpi_init);
 
 static int __init pnpacpi_setup(char *str)
 {
diff --git a/drivers/pnp/pnpbios/core.c b/drivers/pnp/pnpbios/core.c
index 19a4be1..662dfcdd 100644
--- a/drivers/pnp/pnpbios/core.c
+++ b/drivers/pnp/pnpbios/core.c
@@ -571,7 +571,7 @@
 	return 0;
 }
 
-subsys_initcall(pnpbios_init);
+fs_initcall(pnpbios_init);
 
 static int __init pnpbios_thread_init(void)
 {
diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig
index 9ce5585..63bb579 100644
--- a/drivers/power/Kconfig
+++ b/drivers/power/Kconfig
@@ -56,10 +56,10 @@
 	  Say Y to enable support for the battery on the Sharp Zaurus
 	  SL-6000 (tosa) models.
 
-config BATTERY_PALMTX
-	tristate "Palm T|X battery"
-	depends on MACH_PALMTX
+config BATTERY_WM97XX
+	bool "WM97xx generic battery driver"
+	depends on TOUCHSCREEN_WM97XX=y
 	help
-	  Say Y to enable support for the battery in Palm T|X.
+	  Say Y to enable support for battery measured by WM97xx aux port.
 
 endif # POWER_SUPPLY
diff --git a/drivers/power/Makefile b/drivers/power/Makefile
index 4706bf8..4e20026 100644
--- a/drivers/power/Makefile
+++ b/drivers/power/Makefile
@@ -21,4 +21,4 @@
 obj-$(CONFIG_BATTERY_PMU)	+= pmu_battery.o
 obj-$(CONFIG_BATTERY_OLPC)	+= olpc_battery.o
 obj-$(CONFIG_BATTERY_TOSA)	+= tosa_battery.o
-obj-$(CONFIG_BATTERY_PALMTX)	+= palmtx_battery.o
+obj-$(CONFIG_BATTERY_WM97XX)	+= wm97xx_battery.o
\ No newline at end of file
diff --git a/drivers/power/palmtx_battery.c b/drivers/power/palmtx_battery.c
deleted file mode 100644
index 7035bfa..0000000
--- a/drivers/power/palmtx_battery.c
+++ /dev/null
@@ -1,198 +0,0 @@
-/*
- * linux/drivers/power/palmtx_battery.c
- *
- * Battery measurement code for Palm T|X Handheld computer
- *
- * based on tosa_battery.c
- *
- * Copyright (C) 2008 Marek Vasut <marek.vasut@gmail.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/kernel.h>
-#include <linux/module.h>
-#include <linux/power_supply.h>
-#include <linux/wm97xx.h>
-#include <linux/delay.h>
-#include <linux/spinlock.h>
-#include <linux/interrupt.h>
-#include <linux/gpio.h>
-
-#include <asm/mach-types.h>
-#include <mach/palmtx.h>
-
-static DEFINE_MUTEX(bat_lock);
-static struct work_struct bat_work;
-struct mutex work_lock;
-int bat_status = POWER_SUPPLY_STATUS_DISCHARGING;
-
-static unsigned long palmtx_read_bat(struct power_supply *bat_ps)
-{
-	return wm97xx_read_aux_adc(bat_ps->dev->parent->driver_data,
-				    WM97XX_AUX_ID3) * 1000 / 414;
-}
-
-static unsigned long palmtx_read_temp(struct power_supply *bat_ps)
-{
-	return wm97xx_read_aux_adc(bat_ps->dev->parent->driver_data,
-				    WM97XX_AUX_ID2);
-}
-
-static int palmtx_bat_get_property(struct power_supply *bat_ps,
-			    enum power_supply_property psp,
-			    union power_supply_propval *val)
-{
-	switch (psp) {
-	case POWER_SUPPLY_PROP_STATUS:
-		val->intval = bat_status;
-		break;
-	case POWER_SUPPLY_PROP_TECHNOLOGY:
-		val->intval = POWER_SUPPLY_TECHNOLOGY_LIPO;
-		break;
-	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
-		val->intval = palmtx_read_bat(bat_ps);
-		break;
-	case POWER_SUPPLY_PROP_VOLTAGE_MAX:
-	case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
-		val->intval = PALMTX_BAT_MAX_VOLTAGE;
-		break;
-	case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
-		val->intval = PALMTX_BAT_MIN_VOLTAGE;
-		break;
-	case POWER_SUPPLY_PROP_TEMP:
-		val->intval = palmtx_read_temp(bat_ps);
-		break;
-	case POWER_SUPPLY_PROP_PRESENT:
-		val->intval = 1;
-		break;
-	default:
-		return -EINVAL;
-	}
-	return 0;
-}
-
-static void palmtx_bat_external_power_changed(struct power_supply *bat_ps)
-{
-	schedule_work(&bat_work);
-}
-
-static char *status_text[] = {
-	[POWER_SUPPLY_STATUS_UNKNOWN] =		"Unknown",
-	[POWER_SUPPLY_STATUS_CHARGING] =	"Charging",
-	[POWER_SUPPLY_STATUS_DISCHARGING] =	"Discharging",
-};
-
-static void palmtx_bat_update(struct power_supply *bat_ps)
-{
-	int old_status = bat_status;
-
-	mutex_lock(&work_lock);
-
-	bat_status = gpio_get_value(GPIO_NR_PALMTX_POWER_DETECT) ?
-				    POWER_SUPPLY_STATUS_CHARGING :
-				    POWER_SUPPLY_STATUS_DISCHARGING;
-
-	if (old_status != bat_status) {
-		pr_debug("%s %s -> %s\n", bat_ps->name,
-				status_text[old_status],
-				status_text[bat_status]);
-		power_supply_changed(bat_ps);
-	}
-
-	mutex_unlock(&work_lock);
-}
-
-static enum power_supply_property palmtx_bat_main_props[] = {
-	POWER_SUPPLY_PROP_STATUS,
-	POWER_SUPPLY_PROP_TECHNOLOGY,
-	POWER_SUPPLY_PROP_VOLTAGE_NOW,
-	POWER_SUPPLY_PROP_VOLTAGE_MAX,
-	POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
-	POWER_SUPPLY_PROP_TEMP,
-	POWER_SUPPLY_PROP_PRESENT,
-};
-
-struct power_supply bat_ps = {
-	.name			= "main-battery",
-	.type			= POWER_SUPPLY_TYPE_BATTERY,
-	.properties		= palmtx_bat_main_props,
-	.num_properties		= ARRAY_SIZE(palmtx_bat_main_props),
-	.get_property		= palmtx_bat_get_property,
-	.external_power_changed = palmtx_bat_external_power_changed,
-	.use_for_apm		= 1,
-};
-
-static void palmtx_bat_work(struct work_struct *work)
-{
-	palmtx_bat_update(&bat_ps);
-}
-
-#ifdef CONFIG_PM
-static int palmtx_bat_suspend(struct platform_device *dev, pm_message_t state)
-{
-	flush_scheduled_work();
-	return 0;
-}
-
-static int palmtx_bat_resume(struct platform_device *dev)
-{
-	schedule_work(&bat_work);
-	return 0;
-}
-#else
-#define palmtx_bat_suspend NULL
-#define palmtx_bat_resume NULL
-#endif
-
-static int __devinit palmtx_bat_probe(struct platform_device *dev)
-{
-	int ret = 0;
-
-	if (!machine_is_palmtx())
-		return -ENODEV;
-
-	mutex_init(&work_lock);
-
-	INIT_WORK(&bat_work, palmtx_bat_work);
-
-	ret = power_supply_register(&dev->dev, &bat_ps);
-	if (!ret)
-		schedule_work(&bat_work);
-
-	return ret;
-}
-
-static int __devexit palmtx_bat_remove(struct platform_device *dev)
-{
-	power_supply_unregister(&bat_ps);
-	return 0;
-}
-
-static struct platform_driver palmtx_bat_driver = {
-	.driver.name	= "wm97xx-battery",
-	.driver.owner	= THIS_MODULE,
-	.probe		= palmtx_bat_probe,
-	.remove		= __devexit_p(palmtx_bat_remove),
-	.suspend	= palmtx_bat_suspend,
-	.resume		= palmtx_bat_resume,
-};
-
-static int __init palmtx_bat_init(void)
-{
-	return platform_driver_register(&palmtx_bat_driver);
-}
-
-static void __exit palmtx_bat_exit(void)
-{
-	platform_driver_unregister(&palmtx_bat_driver);
-}
-
-module_init(palmtx_bat_init);
-module_exit(palmtx_bat_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Marek Vasut <marek.vasut@gmail.com>");
-MODULE_DESCRIPTION("Palm T|X battery driver");
diff --git a/drivers/power/wm97xx_battery.c b/drivers/power/wm97xx_battery.c
new file mode 100644
index 0000000..8bde921
--- /dev/null
+++ b/drivers/power/wm97xx_battery.c
@@ -0,0 +1,272 @@
+/*
+ * linux/drivers/power/wm97xx_battery.c
+ *
+ * Battery measurement code for WM97xx
+ *
+ * based on tosa_battery.c
+ *
+ * Copyright (C) 2008 Marek Vasut <marek.vasut@gmail.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/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/power_supply.h>
+#include <linux/wm97xx.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+#include <linux/gpio.h>
+#include <linux/wm97xx_batt.h>
+
+static DEFINE_MUTEX(bat_lock);
+static struct work_struct bat_work;
+struct mutex work_lock;
+static int bat_status = POWER_SUPPLY_STATUS_UNKNOWN;
+static struct wm97xx_batt_info *pdata;
+static enum power_supply_property *prop;
+
+static unsigned long wm97xx_read_bat(struct power_supply *bat_ps)
+{
+	return wm97xx_read_aux_adc(bat_ps->dev->parent->driver_data,
+					pdata->batt_aux) * pdata->batt_mult /
+					pdata->batt_div;
+}
+
+static unsigned long wm97xx_read_temp(struct power_supply *bat_ps)
+{
+	return wm97xx_read_aux_adc(bat_ps->dev->parent->driver_data,
+					pdata->temp_aux) * pdata->temp_mult /
+					pdata->temp_div;
+}
+
+static int wm97xx_bat_get_property(struct power_supply *bat_ps,
+			    enum power_supply_property psp,
+			    union power_supply_propval *val)
+{
+	switch (psp) {
+	case POWER_SUPPLY_PROP_STATUS:
+		val->intval = bat_status;
+		break;
+	case POWER_SUPPLY_PROP_TECHNOLOGY:
+		val->intval = pdata->batt_tech;
+		break;
+	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+		if (pdata->batt_aux >= 0)
+			val->intval = wm97xx_read_bat(bat_ps);
+		else
+			return -EINVAL;
+		break;
+	case POWER_SUPPLY_PROP_TEMP:
+		if (pdata->temp_aux >= 0)
+			val->intval = wm97xx_read_temp(bat_ps);
+		else
+			return -EINVAL;
+		break;
+	case POWER_SUPPLY_PROP_VOLTAGE_MAX:
+		if (pdata->max_voltage >= 0)
+			val->intval = pdata->max_voltage;
+		else
+			return -EINVAL;
+		break;
+	case POWER_SUPPLY_PROP_VOLTAGE_MIN:
+		if (pdata->min_voltage >= 0)
+			val->intval = pdata->min_voltage;
+		else
+			return -EINVAL;
+		break;
+	case POWER_SUPPLY_PROP_PRESENT:
+		val->intval = 1;
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static void wm97xx_bat_external_power_changed(struct power_supply *bat_ps)
+{
+	schedule_work(&bat_work);
+}
+
+static void wm97xx_bat_update(struct power_supply *bat_ps)
+{
+	int old_status = bat_status;
+
+	mutex_lock(&work_lock);
+
+	bat_status = (pdata->charge_gpio >= 0) ?
+			(gpio_get_value(pdata->charge_gpio) ?
+			POWER_SUPPLY_STATUS_DISCHARGING :
+			POWER_SUPPLY_STATUS_CHARGING) :
+			POWER_SUPPLY_STATUS_UNKNOWN;
+
+	if (old_status != bat_status) {
+		pr_debug("%s: %i -> %i\n", bat_ps->name, old_status,
+					bat_status);
+		power_supply_changed(bat_ps);
+	}
+
+	mutex_unlock(&work_lock);
+}
+
+static struct power_supply bat_ps = {
+	.type			= POWER_SUPPLY_TYPE_BATTERY,
+	.get_property		= wm97xx_bat_get_property,
+	.external_power_changed = wm97xx_bat_external_power_changed,
+	.use_for_apm		= 1,
+};
+
+static void wm97xx_bat_work(struct work_struct *work)
+{
+	wm97xx_bat_update(&bat_ps);
+}
+
+#ifdef CONFIG_PM
+static int wm97xx_bat_suspend(struct platform_device *dev, pm_message_t state)
+{
+	flush_scheduled_work();
+	return 0;
+}
+
+static int wm97xx_bat_resume(struct platform_device *dev)
+{
+	schedule_work(&bat_work);
+	return 0;
+}
+#else
+#define wm97xx_bat_suspend NULL
+#define wm97xx_bat_resume NULL
+#endif
+
+static int __devinit wm97xx_bat_probe(struct platform_device *dev)
+{
+	int ret = 0;
+	int props = 1;	/* POWER_SUPPLY_PROP_PRESENT */
+	int i = 0;
+
+	if (dev->id != -1)
+		return -EINVAL;
+
+	mutex_init(&work_lock);
+
+	if (!pdata) {
+		dev_err(&dev->dev, "Please use wm97xx_bat_set_pdata\n");
+		return -EINVAL;
+	}
+
+	if (pdata->charge_gpio >= 0 && gpio_is_valid(pdata->charge_gpio)) {
+		ret = gpio_request(pdata->charge_gpio, "BATT CHRG");
+		if (ret)
+			goto err;
+		ret = gpio_direction_input(pdata->charge_gpio);
+		if (ret)
+			goto err2;
+		props++;	/* POWER_SUPPLY_PROP_STATUS */
+	}
+
+	if (pdata->batt_tech >= 0)
+		props++;	/* POWER_SUPPLY_PROP_TECHNOLOGY */
+	if (pdata->temp_aux >= 0)
+		props++;	/* POWER_SUPPLY_PROP_TEMP */
+	if (pdata->batt_aux >= 0)
+		props++;	/* POWER_SUPPLY_PROP_VOLTAGE_NOW */
+	if (pdata->max_voltage >= 0)
+		props++;	/* POWER_SUPPLY_PROP_VOLTAGE_MAX */
+	if (pdata->min_voltage >= 0)
+		props++;	/* POWER_SUPPLY_PROP_VOLTAGE_MIN */
+
+	prop = kzalloc(props * sizeof(*prop), GFP_KERNEL);
+	if (!prop)
+		goto err2;
+
+	prop[i++] = POWER_SUPPLY_PROP_PRESENT;
+	if (pdata->charge_gpio >= 0)
+		prop[i++] = POWER_SUPPLY_PROP_STATUS;
+	if (pdata->batt_tech >= 0)
+		prop[i++] = POWER_SUPPLY_PROP_TECHNOLOGY;
+	if (pdata->temp_aux >= 0)
+		prop[i++] = POWER_SUPPLY_PROP_TEMP;
+	if (pdata->batt_aux >= 0)
+		prop[i++] = POWER_SUPPLY_PROP_VOLTAGE_NOW;
+	if (pdata->max_voltage >= 0)
+		prop[i++] = POWER_SUPPLY_PROP_VOLTAGE_MAX;
+	if (pdata->min_voltage >= 0)
+		prop[i++] = POWER_SUPPLY_PROP_VOLTAGE_MIN;
+
+	INIT_WORK(&bat_work, wm97xx_bat_work);
+
+	if (!pdata->batt_name) {
+		dev_info(&dev->dev, "Please consider setting proper battery "
+				"name in platform definition file, falling "
+				"back to name \"wm97xx-batt\"\n");
+		bat_ps.name = "wm97xx-batt";
+	} else
+		bat_ps.name = pdata->batt_name;
+
+	bat_ps.properties = prop;
+	bat_ps.num_properties = props;
+
+	ret = power_supply_register(&dev->dev, &bat_ps);
+	if (!ret)
+		schedule_work(&bat_work);
+	else
+		goto err3;
+
+	return 0;
+err3:
+	kfree(prop);
+err2:
+	gpio_free(pdata->charge_gpio);
+err:
+	return ret;
+}
+
+static int __devexit wm97xx_bat_remove(struct platform_device *dev)
+{
+	if (pdata && pdata->charge_gpio && pdata->charge_gpio >= 0)
+		gpio_free(pdata->charge_gpio);
+	flush_scheduled_work();
+	power_supply_unregister(&bat_ps);
+	kfree(prop);
+	return 0;
+}
+
+static struct platform_driver wm97xx_bat_driver = {
+	.driver	= {
+		.name	= "wm97xx-battery",
+		.owner	= THIS_MODULE,
+	},
+	.probe		= wm97xx_bat_probe,
+	.remove		= __devexit_p(wm97xx_bat_remove),
+	.suspend	= wm97xx_bat_suspend,
+	.resume		= wm97xx_bat_resume,
+};
+
+static int __init wm97xx_bat_init(void)
+{
+	return platform_driver_register(&wm97xx_bat_driver);
+}
+
+static void __exit wm97xx_bat_exit(void)
+{
+	platform_driver_unregister(&wm97xx_bat_driver);
+}
+
+void __init wm97xx_bat_set_pdata(struct wm97xx_batt_info *data)
+{
+	pdata = data;
+}
+EXPORT_SYMBOL_GPL(wm97xx_bat_set_pdata);
+
+module_init(wm97xx_bat_init);
+module_exit(wm97xx_bat_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Marek Vasut <marek.vasut@gmail.com>");
+MODULE_DESCRIPTION("WM97xx battery driver");
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index a656128..4dada6e 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -56,4 +56,28 @@
 	  charging select between 100 mA and 500 mA charging current
 	  limit.
 
+config REGULATOR_WM8350
+	tristate "Wolfson Microelectroncis WM8350 AudioPlus PMIC"
+	depends on MFD_WM8350
+	select REGULATOR
+	help
+	  This driver provides support for the voltage and current regulators
+          of the WM8350 AudioPlus PMIC.
+
+config REGULATOR_WM8400
+	tristate "Wolfson Microelectroncis WM8400 AudioPlus PMIC"
+	depends on MFD_WM8400
+	select REGULATOR
+	help
+	  This driver provides support for the voltage regulators of the
+	  WM8400 AudioPlus PMIC.
+
+config REGULATOR_DA903X
+	tristate "Support regulators on Dialog Semiconductor DA9030/DA9034 PMIC"
+	depends on PMIC_DA903X
+	select REGULATOR
+	help
+	  Say y here to support the BUCKs and LDOs regulators found on
+	  Dialog Semiconductor DA9030/DA9034 PMIC.
+
 endmenu
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index ac2c64e..254d40c 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -8,5 +8,8 @@
 obj-$(CONFIG_REGULATOR_VIRTUAL_CONSUMER) += virtual.o
 
 obj-$(CONFIG_REGULATOR_BQ24022) += bq24022.o
+obj-$(CONFIG_REGULATOR_WM8350) += wm8350-regulator.o
+obj-$(CONFIG_REGULATOR_WM8400) += wm8400-regulator.o
+obj-$(CONFIG_REGULATOR_DA903X)	+= da903x.o
 
 ccflags-$(CONFIG_REGULATOR_DEBUG) += -DDEBUG
diff --git a/drivers/regulator/bq24022.c b/drivers/regulator/bq24022.c
index 263699d..366565a 100644
--- a/drivers/regulator/bq24022.c
+++ b/drivers/regulator/bq24022.c
@@ -18,13 +18,13 @@
 #include <linux/regulator/bq24022.h>
 #include <linux/regulator/driver.h>
 
+
 static int bq24022_set_current_limit(struct regulator_dev *rdev,
 					int min_uA, int max_uA)
 {
-	struct platform_device *pdev = rdev_get_drvdata(rdev);
-	struct bq24022_mach_info *pdata = pdev->dev.platform_data;
+	struct bq24022_mach_info *pdata = rdev_get_drvdata(rdev);
 
-	dev_dbg(&pdev->dev, "setting current limit to %s mA\n",
+	dev_dbg(rdev_get_dev(rdev), "setting current limit to %s mA\n",
 		max_uA >= 500000 ? "500" : "100");
 
 	/* REVISIT: maybe return error if min_uA != 0 ? */
@@ -34,18 +34,16 @@
 
 static int bq24022_get_current_limit(struct regulator_dev *rdev)
 {
-	struct platform_device *pdev = rdev_get_drvdata(rdev);
-	struct bq24022_mach_info *pdata = pdev->dev.platform_data;
+	struct bq24022_mach_info *pdata = rdev_get_drvdata(rdev);
 
 	return gpio_get_value(pdata->gpio_iset2) ? 500000 : 100000;
 }
 
 static int bq24022_enable(struct regulator_dev *rdev)
 {
-	struct platform_device *pdev = rdev_get_drvdata(rdev);
-	struct bq24022_mach_info *pdata = pdev->dev.platform_data;
+	struct bq24022_mach_info *pdata = rdev_get_drvdata(rdev);
 
-	dev_dbg(&pdev->dev, "enabling charger\n");
+	dev_dbg(rdev_get_dev(rdev), "enabling charger\n");
 
 	gpio_set_value(pdata->gpio_nce, 0);
 	return 0;
@@ -53,10 +51,9 @@
 
 static int bq24022_disable(struct regulator_dev *rdev)
 {
-	struct platform_device *pdev = rdev_get_drvdata(rdev);
-	struct bq24022_mach_info *pdata = pdev->dev.platform_data;
+	struct bq24022_mach_info *pdata = rdev_get_drvdata(rdev);
 
-	dev_dbg(&pdev->dev, "disabling charger\n");
+	dev_dbg(rdev_get_dev(rdev), "disabling charger\n");
 
 	gpio_set_value(pdata->gpio_nce, 1);
 	return 0;
@@ -108,7 +105,7 @@
 	ret = gpio_direction_output(pdata->gpio_iset2, 0);
 	ret = gpio_direction_output(pdata->gpio_nce, 1);
 
-	bq24022 = regulator_register(&bq24022_desc, pdev);
+	bq24022 = regulator_register(&bq24022_desc, &pdev->dev, pdata);
 	if (IS_ERR(bq24022)) {
 		dev_dbg(&pdev->dev, "couldn't register regulator\n");
 		ret = PTR_ERR(bq24022);
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index 9c79862..02a7744 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -2,8 +2,9 @@
  * core.c  --  Voltage/Current Regulator framework.
  *
  * Copyright 2007, 2008 Wolfson Microelectronics PLC.
+ * Copyright 2008 SlimLogic Ltd.
  *
- * Author: Liam Girdwood <liam.girdwood@wolfsonmicro.com>
+ * Author: Liam Girdwood <lrg@slimlogic.co.uk>
  *
  *  This program is free software; you can redistribute  it and/or modify it
  *  under  the terms of  the GNU General  Public License as published by the
@@ -64,14 +65,9 @@
 	struct list_head list;
 	struct device *dev;
 	const char *supply;
-	const char *regulator;
+	struct regulator_dev *regulator;
 };
 
-static inline struct regulator_dev *to_rdev(struct device *d)
-{
-	return container_of(d, struct regulator_dev, dev);
-}
-
 /*
  * struct regulator
  *
@@ -227,7 +223,7 @@
 static ssize_t regulator_uV_show(struct device *dev,
 				struct device_attribute *attr, char *buf)
 {
-	struct regulator_dev *rdev = to_rdev(dev);
+	struct regulator_dev *rdev = dev_get_drvdata(dev);
 	ssize_t ret;
 
 	mutex_lock(&rdev->mutex);
@@ -240,15 +236,31 @@
 static ssize_t regulator_uA_show(struct device *dev,
 				struct device_attribute *attr, char *buf)
 {
-	struct regulator_dev *rdev = to_rdev(dev);
+	struct regulator_dev *rdev = dev_get_drvdata(dev);
 
 	return sprintf(buf, "%d\n", _regulator_get_current_limit(rdev));
 }
 
+static ssize_t regulator_name_show(struct device *dev,
+			     struct device_attribute *attr, char *buf)
+{
+	struct regulator_dev *rdev = dev_get_drvdata(dev);
+	const char *name;
+
+	if (rdev->constraints->name)
+		name = rdev->constraints->name;
+	else if (rdev->desc->name)
+		name = rdev->desc->name;
+	else
+		name = "";
+
+	return sprintf(buf, "%s\n", name);
+}
+
 static ssize_t regulator_opmode_show(struct device *dev,
 				    struct device_attribute *attr, char *buf)
 {
-	struct regulator_dev *rdev = to_rdev(dev);
+	struct regulator_dev *rdev = dev_get_drvdata(dev);
 	int mode = _regulator_get_mode(rdev);
 
 	switch (mode) {
@@ -267,7 +279,7 @@
 static ssize_t regulator_state_show(struct device *dev,
 				   struct device_attribute *attr, char *buf)
 {
-	struct regulator_dev *rdev = to_rdev(dev);
+	struct regulator_dev *rdev = dev_get_drvdata(dev);
 	int state = _regulator_is_enabled(rdev);
 
 	if (state > 0)
@@ -281,7 +293,7 @@
 static ssize_t regulator_min_uA_show(struct device *dev,
 				    struct device_attribute *attr, char *buf)
 {
-	struct regulator_dev *rdev = to_rdev(dev);
+	struct regulator_dev *rdev = dev_get_drvdata(dev);
 
 	if (!rdev->constraints)
 		return sprintf(buf, "constraint not defined\n");
@@ -292,7 +304,7 @@
 static ssize_t regulator_max_uA_show(struct device *dev,
 				    struct device_attribute *attr, char *buf)
 {
-	struct regulator_dev *rdev = to_rdev(dev);
+	struct regulator_dev *rdev = dev_get_drvdata(dev);
 
 	if (!rdev->constraints)
 		return sprintf(buf, "constraint not defined\n");
@@ -303,7 +315,7 @@
 static ssize_t regulator_min_uV_show(struct device *dev,
 				    struct device_attribute *attr, char *buf)
 {
-	struct regulator_dev *rdev = to_rdev(dev);
+	struct regulator_dev *rdev = dev_get_drvdata(dev);
 
 	if (!rdev->constraints)
 		return sprintf(buf, "constraint not defined\n");
@@ -314,7 +326,7 @@
 static ssize_t regulator_max_uV_show(struct device *dev,
 				    struct device_attribute *attr, char *buf)
 {
-	struct regulator_dev *rdev = to_rdev(dev);
+	struct regulator_dev *rdev = dev_get_drvdata(dev);
 
 	if (!rdev->constraints)
 		return sprintf(buf, "constraint not defined\n");
@@ -325,7 +337,7 @@
 static ssize_t regulator_total_uA_show(struct device *dev,
 				      struct device_attribute *attr, char *buf)
 {
-	struct regulator_dev *rdev = to_rdev(dev);
+	struct regulator_dev *rdev = dev_get_drvdata(dev);
 	struct regulator *regulator;
 	int uA = 0;
 
@@ -339,14 +351,14 @@
 static ssize_t regulator_num_users_show(struct device *dev,
 				      struct device_attribute *attr, char *buf)
 {
-	struct regulator_dev *rdev = to_rdev(dev);
+	struct regulator_dev *rdev = dev_get_drvdata(dev);
 	return sprintf(buf, "%d\n", rdev->use_count);
 }
 
 static ssize_t regulator_type_show(struct device *dev,
 				  struct device_attribute *attr, char *buf)
 {
-	struct regulator_dev *rdev = to_rdev(dev);
+	struct regulator_dev *rdev = dev_get_drvdata(dev);
 
 	switch (rdev->desc->type) {
 	case REGULATOR_VOLTAGE:
@@ -360,7 +372,7 @@
 static ssize_t regulator_suspend_mem_uV_show(struct device *dev,
 				struct device_attribute *attr, char *buf)
 {
-	struct regulator_dev *rdev = to_rdev(dev);
+	struct regulator_dev *rdev = dev_get_drvdata(dev);
 
 	if (!rdev->constraints)
 		return sprintf(buf, "not defined\n");
@@ -370,7 +382,7 @@
 static ssize_t regulator_suspend_disk_uV_show(struct device *dev,
 				struct device_attribute *attr, char *buf)
 {
-	struct regulator_dev *rdev = to_rdev(dev);
+	struct regulator_dev *rdev = dev_get_drvdata(dev);
 
 	if (!rdev->constraints)
 		return sprintf(buf, "not defined\n");
@@ -380,7 +392,7 @@
 static ssize_t regulator_suspend_standby_uV_show(struct device *dev,
 				struct device_attribute *attr, char *buf)
 {
-	struct regulator_dev *rdev = to_rdev(dev);
+	struct regulator_dev *rdev = dev_get_drvdata(dev);
 
 	if (!rdev->constraints)
 		return sprintf(buf, "not defined\n");
@@ -406,7 +418,7 @@
 static ssize_t regulator_suspend_mem_mode_show(struct device *dev,
 				struct device_attribute *attr, char *buf)
 {
-	struct regulator_dev *rdev = to_rdev(dev);
+	struct regulator_dev *rdev = dev_get_drvdata(dev);
 
 	if (!rdev->constraints)
 		return sprintf(buf, "not defined\n");
@@ -417,7 +429,7 @@
 static ssize_t regulator_suspend_disk_mode_show(struct device *dev,
 				struct device_attribute *attr, char *buf)
 {
-	struct regulator_dev *rdev = to_rdev(dev);
+	struct regulator_dev *rdev = dev_get_drvdata(dev);
 
 	if (!rdev->constraints)
 		return sprintf(buf, "not defined\n");
@@ -428,7 +440,7 @@
 static ssize_t regulator_suspend_standby_mode_show(struct device *dev,
 				struct device_attribute *attr, char *buf)
 {
-	struct regulator_dev *rdev = to_rdev(dev);
+	struct regulator_dev *rdev = dev_get_drvdata(dev);
 
 	if (!rdev->constraints)
 		return sprintf(buf, "not defined\n");
@@ -439,7 +451,7 @@
 static ssize_t regulator_suspend_mem_state_show(struct device *dev,
 				   struct device_attribute *attr, char *buf)
 {
-	struct regulator_dev *rdev = to_rdev(dev);
+	struct regulator_dev *rdev = dev_get_drvdata(dev);
 
 	if (!rdev->constraints)
 		return sprintf(buf, "not defined\n");
@@ -453,7 +465,7 @@
 static ssize_t regulator_suspend_disk_state_show(struct device *dev,
 				   struct device_attribute *attr, char *buf)
 {
-	struct regulator_dev *rdev = to_rdev(dev);
+	struct regulator_dev *rdev = dev_get_drvdata(dev);
 
 	if (!rdev->constraints)
 		return sprintf(buf, "not defined\n");
@@ -467,7 +479,7 @@
 static ssize_t regulator_suspend_standby_state_show(struct device *dev,
 				   struct device_attribute *attr, char *buf)
 {
-	struct regulator_dev *rdev = to_rdev(dev);
+	struct regulator_dev *rdev = dev_get_drvdata(dev);
 
 	if (!rdev->constraints)
 		return sprintf(buf, "not defined\n");
@@ -477,7 +489,9 @@
 	else
 		return sprintf(buf, "disabled\n");
 }
+
 static struct device_attribute regulator_dev_attrs[] = {
+	__ATTR(name, 0444, regulator_name_show, NULL),
 	__ATTR(microvolts, 0444, regulator_uV_show, NULL),
 	__ATTR(microamps, 0444, regulator_uA_show, NULL),
 	__ATTR(opmode, 0444, regulator_opmode_show, NULL),
@@ -512,7 +526,7 @@
 
 static void regulator_dev_release(struct device *dev)
 {
-	struct regulator_dev *rdev = to_rdev(dev);
+	struct regulator_dev *rdev = dev_get_drvdata(dev);
 	kfree(rdev);
 }
 
@@ -569,8 +583,11 @@
 
 	/* enable & disable are mandatory for suspend control */
 	if (!rdev->desc->ops->set_suspend_enable ||
-		!rdev->desc->ops->set_suspend_disable)
+		!rdev->desc->ops->set_suspend_disable) {
+		printk(KERN_ERR "%s: no way to set suspend state\n",
+			__func__);
 		return -EINVAL;
+	}
 
 	if (rstate->enabled)
 		ret = rdev->desc->ops->set_suspend_enable(rdev);
@@ -656,6 +673,155 @@
 	printk(KERN_INFO "regulator: %s: %s\n", rdev->desc->name, buf);
 }
 
+/**
+ * set_machine_constraints - sets regulator constraints
+ * @regulator: regulator source
+ *
+ * Allows platform initialisation code to define and constrain
+ * regulator circuits e.g. valid voltage/current ranges, etc.  NOTE:
+ * Constraints *must* be set by platform code in order for some
+ * regulator operations to proceed i.e. set_voltage, set_current_limit,
+ * set_mode.
+ */
+static int set_machine_constraints(struct regulator_dev *rdev,
+	struct regulation_constraints *constraints)
+{
+	int ret = 0;
+	const char *name;
+	struct regulator_ops *ops = rdev->desc->ops;
+
+	if (constraints->name)
+		name = constraints->name;
+	else if (rdev->desc->name)
+		name = rdev->desc->name;
+	else
+		name = "regulator";
+
+	rdev->constraints = constraints;
+
+	/* do we need to apply the constraint voltage */
+	if (rdev->constraints->apply_uV &&
+		rdev->constraints->min_uV == rdev->constraints->max_uV &&
+		ops->set_voltage) {
+		ret = ops->set_voltage(rdev,
+			rdev->constraints->min_uV, rdev->constraints->max_uV);
+			if (ret < 0) {
+				printk(KERN_ERR "%s: failed to apply %duV constraint to %s\n",
+				       __func__,
+				       rdev->constraints->min_uV, name);
+				rdev->constraints = NULL;
+				goto out;
+			}
+	}
+
+	/* are we enabled at boot time by firmware / bootloader */
+	if (rdev->constraints->boot_on)
+		rdev->use_count = 1;
+
+	/* do we need to setup our suspend state */
+	if (constraints->initial_state) {
+		ret = suspend_prepare(rdev, constraints->initial_state);
+		if (ret < 0) {
+			printk(KERN_ERR "%s: failed to set suspend state for %s\n",
+			       __func__, name);
+			rdev->constraints = NULL;
+			goto out;
+		}
+	}
+
+	/* if always_on is set then turn the regulator on if it's not
+	 * already on. */
+	if (constraints->always_on && ops->enable &&
+	    ((ops->is_enabled && !ops->is_enabled(rdev)) ||
+	     (!ops->is_enabled && !constraints->boot_on))) {
+		ret = ops->enable(rdev);
+		if (ret < 0) {
+			printk(KERN_ERR "%s: failed to enable %s\n",
+			       __func__, name);
+			rdev->constraints = NULL;
+			goto out;
+		}
+	}
+
+	print_constraints(rdev);
+out:
+	return ret;
+}
+
+/**
+ * set_supply - set regulator supply regulator
+ * @regulator: regulator name
+ * @supply: supply regulator name
+ *
+ * Called by platform initialisation code to set the supply regulator for this
+ * regulator. This ensures that a regulators supply will also be enabled by the
+ * core if it's child is enabled.
+ */
+static int set_supply(struct regulator_dev *rdev,
+	struct regulator_dev *supply_rdev)
+{
+	int err;
+
+	err = sysfs_create_link(&rdev->dev.kobj, &supply_rdev->dev.kobj,
+				"supply");
+	if (err) {
+		printk(KERN_ERR
+		       "%s: could not add device link %s err %d\n",
+		       __func__, supply_rdev->dev.kobj.name, err);
+		       goto out;
+	}
+	rdev->supply = supply_rdev;
+	list_add(&rdev->slist, &supply_rdev->supply_list);
+out:
+	return err;
+}
+
+/**
+ * set_consumer_device_supply: Bind a regulator to a symbolic supply
+ * @regulator: regulator source
+ * @dev:       device the supply applies to
+ * @supply:    symbolic name for supply
+ *
+ * Allows platform initialisation code to map physical regulator
+ * sources to symbolic names for supplies for use by devices.  Devices
+ * should use these symbolic names to request regulators, avoiding the
+ * need to provide board-specific regulator names as platform data.
+ */
+static int set_consumer_device_supply(struct regulator_dev *rdev,
+	struct device *consumer_dev, const char *supply)
+{
+	struct regulator_map *node;
+
+	if (supply == NULL)
+		return -EINVAL;
+
+	node = kmalloc(sizeof(struct regulator_map), GFP_KERNEL);
+	if (node == NULL)
+		return -ENOMEM;
+
+	node->regulator = rdev;
+	node->dev = consumer_dev;
+	node->supply = supply;
+
+	list_add(&node->list, &regulator_map_list);
+	return 0;
+}
+
+static void unset_consumer_device_supply(struct regulator_dev *rdev,
+	struct device *consumer_dev)
+{
+	struct regulator_map *node, *n;
+
+	list_for_each_entry_safe(node, n, &regulator_map_list, list) {
+		if (rdev == node->regulator &&
+			consumer_dev == node->dev) {
+			list_del(&node->list);
+			kfree(node);
+			return;
+		}
+	}
+}
+
 #define REG_STR_SIZE	32
 
 static struct regulator *create_regulator(struct regulator_dev *rdev,
@@ -746,7 +912,6 @@
 	struct regulator_dev *rdev;
 	struct regulator_map *map;
 	struct regulator *regulator = ERR_PTR(-ENODEV);
-	const char *supply = id;
 
 	if (id == NULL) {
 		printk(KERN_ERR "regulator: get() with no identifier\n");
@@ -758,15 +923,9 @@
 	list_for_each_entry(map, &regulator_map_list, list) {
 		if (dev == map->dev &&
 		    strcmp(map->supply, id) == 0) {
-			supply = map->regulator;
-			break;
-		}
-	}
-
-	list_for_each_entry(rdev, &regulator_list, list) {
-		if (strcmp(supply, rdev->desc->name) == 0 &&
-		    try_module_get(rdev->owner))
+			rdev = map->regulator;
 			goto found;
+		}
 	}
 	printk(KERN_ERR "regulator: Unable to get requested regulator: %s\n",
 	       id);
@@ -774,12 +933,16 @@
 	return regulator;
 
 found:
+	if (!try_module_get(rdev->owner))
+		goto out;
+
 	regulator = create_regulator(rdev, dev, id);
 	if (regulator == NULL) {
 		regulator = ERR_PTR(-ENOMEM);
 		module_put(rdev->owner);
 	}
 
+out:
 	mutex_unlock(&regulator_list_mutex);
 	return regulator;
 }
@@ -1559,11 +1722,12 @@
  * Returns 0 on success.
  */
 struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc,
-					  void *reg_data)
+	struct device *dev, void *driver_data)
 {
 	static atomic_t regulator_no = ATOMIC_INIT(0);
 	struct regulator_dev *rdev;
-	int ret;
+	struct regulator_init_data *init_data = dev->platform_data;
+	int ret, i;
 
 	if (regulator_desc == NULL)
 		return ERR_PTR(-EINVAL);
@@ -1575,6 +1739,9 @@
 	    !regulator_desc->type == REGULATOR_CURRENT)
 		return ERR_PTR(-EINVAL);
 
+	if (!init_data)
+		return ERR_PTR(-EINVAL);
+
 	rdev = kzalloc(sizeof(struct regulator_dev), GFP_KERNEL);
 	if (rdev == NULL)
 		return ERR_PTR(-ENOMEM);
@@ -1582,7 +1749,7 @@
 	mutex_lock(&regulator_list_mutex);
 
 	mutex_init(&rdev->mutex);
-	rdev->reg_data = reg_data;
+	rdev->reg_data = driver_data;
 	rdev->owner = regulator_desc->owner;
 	rdev->desc = regulator_desc;
 	INIT_LIST_HEAD(&rdev->consumer_list);
@@ -1591,20 +1758,68 @@
 	INIT_LIST_HEAD(&rdev->slist);
 	BLOCKING_INIT_NOTIFIER_HEAD(&rdev->notifier);
 
-	rdev->dev.class = &regulator_class;
-	device_initialize(&rdev->dev);
-	snprintf(rdev->dev.bus_id, sizeof(rdev->dev.bus_id),
-		 "regulator_%ld_%s",
-		 (unsigned long)atomic_inc_return(&regulator_no) - 1,
-		 regulator_desc->name);
+	/* preform any regulator specific init */
+	if (init_data->regulator_init) {
+		ret = init_data->regulator_init(rdev->reg_data);
+		if (ret < 0) {
+			kfree(rdev);
+			rdev = ERR_PTR(ret);
+			goto out;
+		}
+	}
 
-	ret = device_add(&rdev->dev);
-	if (ret == 0)
-		list_add(&rdev->list, &regulator_list);
-	else {
+	/* set regulator constraints */
+	ret = set_machine_constraints(rdev, &init_data->constraints);
+	if (ret < 0) {
 		kfree(rdev);
 		rdev = ERR_PTR(ret);
+		goto out;
 	}
+
+	/* register with sysfs */
+	rdev->dev.class = &regulator_class;
+	rdev->dev.parent = dev;
+	snprintf(rdev->dev.bus_id, sizeof(rdev->dev.bus_id),
+		 "regulator.%d", atomic_inc_return(&regulator_no) - 1);
+	ret = device_register(&rdev->dev);
+	if (ret != 0) {
+		kfree(rdev);
+		rdev = ERR_PTR(ret);
+		goto out;
+	}
+
+	dev_set_drvdata(&rdev->dev, rdev);
+
+	/* set supply regulator if it exists */
+	if (init_data->supply_regulator_dev) {
+		ret = set_supply(rdev,
+			dev_get_drvdata(init_data->supply_regulator_dev));
+		if (ret < 0) {
+			device_unregister(&rdev->dev);
+			kfree(rdev);
+			rdev = ERR_PTR(ret);
+			goto out;
+		}
+	}
+
+	/* add consumers devices */
+	for (i = 0; i < init_data->num_consumer_supplies; i++) {
+		ret = set_consumer_device_supply(rdev,
+			init_data->consumer_supplies[i].dev,
+			init_data->consumer_supplies[i].supply);
+		if (ret < 0) {
+			for (--i; i >= 0; i--)
+				unset_consumer_device_supply(rdev,
+					init_data->consumer_supplies[i].dev);
+			device_unregister(&rdev->dev);
+			kfree(rdev);
+			rdev = ERR_PTR(ret);
+			goto out;
+		}
+	}
+
+	list_add(&rdev->list, &regulator_list);
+out:
 	mutex_unlock(&regulator_list_mutex);
 	return rdev;
 }
@@ -1631,187 +1846,6 @@
 EXPORT_SYMBOL_GPL(regulator_unregister);
 
 /**
- * regulator_set_supply - set regulator supply regulator
- * @regulator: regulator name
- * @supply: supply regulator name
- *
- * Called by platform initialisation code to set the supply regulator for this
- * regulator. This ensures that a regulators supply will also be enabled by the
- * core if it's child is enabled.
- */
-int regulator_set_supply(const char *regulator, const char *supply)
-{
-	struct regulator_dev *rdev, *supply_rdev;
-	int err;
-
-	if (regulator == NULL || supply == NULL)
-		return -EINVAL;
-
-	mutex_lock(&regulator_list_mutex);
-
-	list_for_each_entry(rdev, &regulator_list, list) {
-		if (!strcmp(rdev->desc->name, regulator))
-			goto found_regulator;
-	}
-	mutex_unlock(&regulator_list_mutex);
-	return -ENODEV;
-
-found_regulator:
-	list_for_each_entry(supply_rdev, &regulator_list, list) {
-		if (!strcmp(supply_rdev->desc->name, supply))
-			goto found_supply;
-	}
-	mutex_unlock(&regulator_list_mutex);
-	return -ENODEV;
-
-found_supply:
-	err = sysfs_create_link(&rdev->dev.kobj, &supply_rdev->dev.kobj,
-				"supply");
-	if (err) {
-		printk(KERN_ERR
-		       "%s: could not add device link %s err %d\n",
-		       __func__, supply_rdev->dev.kobj.name, err);
-		       goto out;
-	}
-	rdev->supply = supply_rdev;
-	list_add(&rdev->slist, &supply_rdev->supply_list);
-out:
-	mutex_unlock(&regulator_list_mutex);
-	return err;
-}
-EXPORT_SYMBOL_GPL(regulator_set_supply);
-
-/**
- * regulator_get_supply - get regulator supply regulator
- * @regulator: regulator name
- *
- * Returns the supply supply regulator name or NULL if no supply regulator
- * exists (i.e the regulator is supplied directly from USB, Line, Battery, etc)
- */
-const char *regulator_get_supply(const char *regulator)
-{
-	struct regulator_dev *rdev;
-
-	if (regulator == NULL)
-		return NULL;
-
-	mutex_lock(&regulator_list_mutex);
-	list_for_each_entry(rdev, &regulator_list, list) {
-		if (!strcmp(rdev->desc->name, regulator))
-			goto found;
-	}
-	mutex_unlock(&regulator_list_mutex);
-	return NULL;
-
-found:
-	mutex_unlock(&regulator_list_mutex);
-	if (rdev->supply)
-		return rdev->supply->desc->name;
-	else
-		return NULL;
-}
-EXPORT_SYMBOL_GPL(regulator_get_supply);
-
-/**
- * regulator_set_machine_constraints - sets regulator constraints
- * @regulator: regulator source
- *
- * Allows platform initialisation code to define and constrain
- * regulator circuits e.g. valid voltage/current ranges, etc.  NOTE:
- * Constraints *must* be set by platform code in order for some
- * regulator operations to proceed i.e. set_voltage, set_current_limit,
- * set_mode.
- */
-int regulator_set_machine_constraints(const char *regulator_name,
-	struct regulation_constraints *constraints)
-{
-	struct regulator_dev *rdev;
-	int ret = 0;
-
-	if (regulator_name == NULL)
-		return -EINVAL;
-
-	mutex_lock(&regulator_list_mutex);
-
-	list_for_each_entry(rdev, &regulator_list, list) {
-		if (!strcmp(regulator_name, rdev->desc->name))
-			goto found;
-	}
-	ret = -ENODEV;
-	goto out;
-
-found:
-	mutex_lock(&rdev->mutex);
-	rdev->constraints = constraints;
-
-	/* do we need to apply the constraint voltage */
-	if (rdev->constraints->apply_uV &&
-		rdev->constraints->min_uV == rdev->constraints->max_uV &&
-		rdev->desc->ops->set_voltage) {
-		ret = rdev->desc->ops->set_voltage(rdev,
-			rdev->constraints->min_uV, rdev->constraints->max_uV);
-			if (ret < 0) {
-				printk(KERN_ERR "%s: failed to apply %duV"
-					" constraint\n", __func__,
-					rdev->constraints->min_uV);
-				rdev->constraints = NULL;
-				goto out;
-			}
-	}
-
-	/* are we enabled at boot time by firmware / bootloader */
-	if (rdev->constraints->boot_on)
-		rdev->use_count = 1;
-
-	/* do we need to setup our suspend state */
-	if (constraints->initial_state)
-		ret = suspend_prepare(rdev, constraints->initial_state);
-
-	print_constraints(rdev);
-	mutex_unlock(&rdev->mutex);
-
-out:
-	mutex_unlock(&regulator_list_mutex);
-	return ret;
-}
-EXPORT_SYMBOL_GPL(regulator_set_machine_constraints);
-
-
-/**
- * regulator_set_device_supply: Bind a regulator to a symbolic supply
- * @regulator: regulator source
- * @dev:       device the supply applies to
- * @supply:    symbolic name for supply
- *
- * Allows platform initialisation code to map physical regulator
- * sources to symbolic names for supplies for use by devices.  Devices
- * should use these symbolic names to request regulators, avoiding the
- * need to provide board-specific regulator names as platform data.
- */
-int regulator_set_device_supply(const char *regulator, struct device *dev,
-				const char *supply)
-{
-	struct regulator_map *node;
-
-	if (regulator == NULL || supply == NULL)
-		return -EINVAL;
-
-	node = kmalloc(sizeof(struct regulator_map), GFP_KERNEL);
-	if (node == NULL)
-		return -ENOMEM;
-
-	node->regulator = regulator;
-	node->dev = dev;
-	node->supply = supply;
-
-	mutex_lock(&regulator_list_mutex);
-	list_add(&node->list, &regulator_map_list);
-	mutex_unlock(&regulator_list_mutex);
-	return 0;
-}
-EXPORT_SYMBOL_GPL(regulator_set_device_supply);
-
-/**
  * regulator_suspend_prepare: prepare regulators for system wide suspend
  * @state: system suspend state
  *
@@ -1893,6 +1927,18 @@
 }
 EXPORT_SYMBOL_GPL(rdev_get_id);
 
+struct device *rdev_get_dev(struct regulator_dev *rdev)
+{
+	return &rdev->dev;
+}
+EXPORT_SYMBOL_GPL(rdev_get_dev);
+
+void *regulator_get_init_drvdata(struct regulator_init_data *reg_init_data)
+{
+	return reg_init_data->driver_data;
+}
+EXPORT_SYMBOL_GPL(regulator_get_init_drvdata);
+
 static int __init regulator_init(void)
 {
 	printk(KERN_INFO "regulator: core version %s\n", REGULATOR_VERSION);
diff --git a/drivers/regulator/da903x.c b/drivers/regulator/da903x.c
new file mode 100644
index 0000000..3688e33
--- /dev/null
+++ b/drivers/regulator/da903x.c
@@ -0,0 +1,513 @@
+/*
+ * Regulators driver for Dialog Semiconductor DA903x
+ *
+ * Copyright (C) 2006-2008 Marvell International Ltd.
+ * Copyright (C) 2008 Compulab Ltd.
+ *
+ * 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/kernel.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/mfd/da903x.h>
+
+/* DA9030 Registers */
+#define DA9030_INVAL		(-1)
+#define DA9030_LDO1011		(0x10)
+#define DA9030_LDO15		(0x11)
+#define DA9030_LDO1416		(0x12)
+#define DA9030_LDO1819		(0x13)
+#define DA9030_LDO17		(0x14)
+#define DA9030_BUCK2DVM1	(0x15)
+#define DA9030_BUCK2DVM2	(0x16)
+#define DA9030_RCTL11		(0x17)
+#define DA9030_RCTL21		(0x18)
+#define DA9030_LDO1		(0x90)
+#define DA9030_LDO23		(0x91)
+#define DA9030_LDO45		(0x92)
+#define DA9030_LDO6		(0x93)
+#define DA9030_LDO78		(0x94)
+#define DA9030_LDO912		(0x95)
+#define DA9030_BUCK		(0x96)
+#define DA9030_RCTL12		(0x97)
+#define DA9030_RCTL22		(0x98)
+#define DA9030_LDO_UNLOCK	(0xa0)
+#define DA9030_LDO_UNLOCK_MASK	(0xe0)
+#define DA9034_OVER1		(0x10)
+
+/* DA9034 Registers */
+#define DA9034_INVAL		(-1)
+#define DA9034_OVER2		(0x11)
+#define DA9034_OVER3		(0x12)
+#define DA9034_LDO643		(0x13)
+#define DA9034_LDO987		(0x14)
+#define DA9034_LDO1110		(0x15)
+#define DA9034_LDO1312		(0x16)
+#define DA9034_LDO1514		(0x17)
+#define DA9034_VCC1		(0x20)
+#define DA9034_ADTV1		(0x23)
+#define DA9034_ADTV2		(0x24)
+#define DA9034_AVRC		(0x25)
+#define DA9034_CDTV1		(0x26)
+#define DA9034_CDTV2		(0x27)
+#define DA9034_CVRC		(0x28)
+#define DA9034_SDTV1		(0x29)
+#define DA9034_SDTV2		(0x2a)
+#define DA9034_SVRC		(0x2b)
+#define DA9034_MDTV1		(0x32)
+#define DA9034_MDTV2		(0x33)
+#define DA9034_MVRC		(0x34)
+
+struct da903x_regulator_info {
+	struct regulator_desc desc;
+
+	int	min_uV;
+	int	max_uV;
+	int	step_uV;
+	int	vol_reg;
+	int	vol_shift;
+	int	vol_nbits;
+	int	update_reg;
+	int	update_bit;
+	int	enable_reg;
+	int	enable_bit;
+};
+
+static inline int check_range(struct da903x_regulator_info *info,
+				int min_uV, int max_uV)
+{
+	if (min_uV < info->min_uV || min_uV > info->max_uV)
+		return -EINVAL;
+
+	return 0;
+}
+
+/* DA9030/DA9034 common operations */
+static int da903x_set_ldo_voltage(struct regulator_dev *rdev,
+				  int min_uV, int max_uV)
+{
+	struct da903x_regulator_info *info = rdev_get_drvdata(rdev);
+	struct device *da9034_dev = rdev_get_dev(rdev)->parent;
+	uint8_t val, mask;
+
+	if (check_range(info, min_uV, max_uV)) {
+		pr_err("invalid voltage range (%d, %d) uV", min_uV, max_uV);
+		return -EINVAL;
+	}
+
+	val = (min_uV - info->min_uV + info->step_uV - 1) / info->step_uV;
+	val <<= info->vol_shift;
+	mask = ((1 << info->vol_nbits) - 1)  << info->vol_shift;
+
+	return da903x_update(da9034_dev, info->vol_reg, val, mask);
+}
+
+static int da903x_get_voltage(struct regulator_dev *rdev)
+{
+	struct da903x_regulator_info *info = rdev_get_drvdata(rdev);
+	struct device *da9034_dev = rdev_get_dev(rdev)->parent;
+	uint8_t val, mask;
+	int ret;
+
+	ret = da903x_read(da9034_dev, info->vol_reg, &val);
+	if (ret)
+		return ret;
+
+	mask = ((1 << info->vol_nbits) - 1)  << info->vol_shift;
+	val = (val & mask) >> info->vol_shift;
+
+	return info->min_uV + info->step_uV * val;
+}
+
+static int da903x_enable(struct regulator_dev *rdev)
+{
+	struct da903x_regulator_info *info = rdev_get_drvdata(rdev);
+	struct device *da9034_dev = rdev_get_dev(rdev)->parent;
+
+	return da903x_set_bits(da9034_dev, info->enable_reg,
+					1 << info->enable_bit);
+}
+
+static int da903x_disable(struct regulator_dev *rdev)
+{
+	struct da903x_regulator_info *info = rdev_get_drvdata(rdev);
+	struct device *da9034_dev = rdev_get_dev(rdev)->parent;
+
+	return da903x_clr_bits(da9034_dev, info->enable_reg,
+					1 << info->enable_bit);
+}
+
+static int da903x_is_enabled(struct regulator_dev *rdev)
+{
+	struct da903x_regulator_info *info = rdev_get_drvdata(rdev);
+	struct device *da9034_dev = rdev_get_dev(rdev)->parent;
+	uint8_t reg_val;
+	int ret;
+
+	ret = da903x_read(da9034_dev, info->enable_reg, &reg_val);
+	if (ret)
+		return ret;
+
+	return reg_val & (1 << info->enable_bit);
+}
+
+/* DA9030 specific operations */
+static int da9030_set_ldo1_15_voltage(struct regulator_dev *rdev,
+				       int min_uV, int max_uV)
+{
+	struct da903x_regulator_info *info = rdev_get_drvdata(rdev);
+	struct device *da903x_dev = rdev_get_dev(rdev)->parent;
+	uint8_t val, mask;
+	int ret;
+
+	if (check_range(info, min_uV, max_uV)) {
+		pr_err("invalid voltage range (%d, %d) uV", min_uV, max_uV);
+		return -EINVAL;
+	}
+
+	val = (min_uV - info->min_uV + info->step_uV - 1) / info->step_uV;
+	val <<= info->vol_shift;
+	mask = ((1 << info->vol_nbits) - 1)  << info->vol_shift;
+	val |= DA9030_LDO_UNLOCK; /* have to set UNLOCK bits */
+	mask |= DA9030_LDO_UNLOCK_MASK;
+
+	/* write twice */
+	ret = da903x_update(da903x_dev, info->vol_reg, val, mask);
+	if (ret)
+		return ret;
+
+	return da903x_update(da903x_dev, info->vol_reg, val, mask);
+}
+
+static int da9030_set_ldo14_voltage(struct regulator_dev *rdev,
+				  int min_uV, int max_uV)
+{
+	struct da903x_regulator_info *info = rdev_get_drvdata(rdev);
+	struct device *da903x_dev = rdev_get_dev(rdev)->parent;
+	uint8_t val, mask;
+	int thresh;
+
+	if (check_range(info, min_uV, max_uV)) {
+		pr_err("invalid voltage range (%d, %d) uV", min_uV, max_uV);
+		return -EINVAL;
+	}
+
+	thresh = (info->max_uV + info->min_uV) / 2;
+	if (min_uV < thresh) {
+		val = (thresh - min_uV + info->step_uV - 1) / info->step_uV;
+		val |= 0x4;
+	} else {
+		val = (min_uV - thresh + info->step_uV - 1) / info->step_uV;
+	}
+
+	val <<= info->vol_shift;
+	mask = ((1 << info->vol_nbits) - 1)  << info->vol_shift;
+
+	return da903x_update(da903x_dev, info->vol_reg, val, mask);
+}
+
+static int da9030_get_ldo14_voltage(struct regulator_dev *rdev)
+{
+	struct da903x_regulator_info *info = rdev_get_drvdata(rdev);
+	struct device *da903x_dev = rdev_get_dev(rdev)->parent;
+	uint8_t val, mask;
+	int ret;
+
+	ret = da903x_read(da903x_dev, info->vol_reg, &val);
+	if (ret)
+		return ret;
+
+	mask = ((1 << info->vol_nbits) - 1)  << info->vol_shift;
+	val = (val & mask) >> info->vol_shift;
+
+	if (val & 0x4)
+		return info->min_uV + info->step_uV * (3 - (val & ~0x4));
+	else
+		return (info->max_uV + info->min_uV) / 2 +
+			info->step_uV * (val & ~0x4);
+}
+
+/* DA9034 specific operations */
+static int da9034_set_dvc_voltage(struct regulator_dev *rdev,
+				  int min_uV, int max_uV)
+{
+	struct da903x_regulator_info *info = rdev_get_drvdata(rdev);
+	struct device *da9034_dev = rdev_get_dev(rdev)->parent;
+	uint8_t val, mask;
+	int ret;
+
+	if (check_range(info, min_uV, max_uV)) {
+		pr_err("invalid voltage range (%d, %d) uV", min_uV, max_uV);
+		return -EINVAL;
+	}
+
+	val = (min_uV - info->min_uV + info->step_uV - 1) / info->step_uV;
+	val <<= info->vol_shift;
+	mask = ((1 << info->vol_nbits) - 1)  << info->vol_shift;
+
+	ret = da903x_update(da9034_dev, info->vol_reg, val, mask);
+	if (ret)
+		return ret;
+
+	ret = da903x_set_bits(da9034_dev, info->update_reg,
+					1 << info->update_bit);
+	return ret;
+}
+
+static int da9034_set_ldo12_voltage(struct regulator_dev *rdev,
+				    int min_uV, int max_uV)
+{
+	struct da903x_regulator_info *info = rdev_get_drvdata(rdev);
+	struct device *da9034_dev = rdev_get_dev(rdev)->parent;
+	uint8_t val, mask;
+
+	if (check_range(info, min_uV, max_uV)) {
+		pr_err("invalid voltage range (%d, %d) uV", min_uV, max_uV);
+		return -EINVAL;
+	}
+
+	val = (min_uV - info->min_uV + info->step_uV - 1) / info->step_uV;
+	val = (val > 7 || val < 20) ? 8 : val - 12;
+	val <<= info->vol_shift;
+	mask = ((1 << info->vol_nbits) - 1)  << info->vol_shift;
+
+	return da903x_update(da9034_dev, info->vol_reg, val, mask);
+}
+
+static int da9034_get_ldo12_voltage(struct regulator_dev *rdev)
+{
+	struct da903x_regulator_info *info = rdev_get_drvdata(rdev);
+	struct device *da9034_dev = rdev_get_dev(rdev)->parent;
+	uint8_t val, mask;
+	int ret;
+
+	ret = da903x_read(da9034_dev, info->vol_reg, &val);
+	if (ret)
+		return ret;
+
+	mask = ((1 << info->vol_nbits) - 1)  << info->vol_shift;
+	val = (val & mask) >> info->vol_shift;
+
+	if (val >= 8)
+		return 2700000 + info->step_uV * (val - 8);
+
+	return info->min_uV + info->step_uV * val;
+}
+
+static struct regulator_ops da903x_regulator_ldo_ops = {
+	.set_voltage	= da903x_set_ldo_voltage,
+	.get_voltage	= da903x_get_voltage,
+	.enable		= da903x_enable,
+	.disable	= da903x_disable,
+	.is_enabled	= da903x_is_enabled,
+};
+
+/* NOTE: this is dedicated for the insane DA9030 LDO14 */
+static struct regulator_ops da9030_regulator_ldo14_ops = {
+	.set_voltage	= da9030_set_ldo14_voltage,
+	.get_voltage	= da9030_get_ldo14_voltage,
+	.enable		= da903x_enable,
+	.disable	= da903x_disable,
+	.is_enabled	= da903x_is_enabled,
+};
+
+/* NOTE: this is dedicated for the DA9030 LDO1 and LDO15 that have locks  */
+static struct regulator_ops da9030_regulator_ldo1_15_ops = {
+	.set_voltage	= da9030_set_ldo1_15_voltage,
+	.get_voltage	= da903x_get_voltage,
+	.enable		= da903x_enable,
+	.disable	= da903x_disable,
+	.is_enabled	= da903x_is_enabled,
+};
+
+static struct regulator_ops da9034_regulator_dvc_ops = {
+	.set_voltage	= da9034_set_dvc_voltage,
+	.get_voltage	= da903x_get_voltage,
+	.enable		= da903x_enable,
+	.disable	= da903x_disable,
+	.is_enabled	= da903x_is_enabled,
+};
+
+/* NOTE: this is dedicated for the insane LDO12 */
+static struct regulator_ops da9034_regulator_ldo12_ops = {
+	.set_voltage	= da9034_set_ldo12_voltage,
+	.get_voltage	= da9034_get_ldo12_voltage,
+	.enable		= da903x_enable,
+	.disable	= da903x_disable,
+	.is_enabled	= da903x_is_enabled,
+};
+
+#define DA903x_LDO(_pmic, _id, min, max, step, vreg, shift, nbits, ereg, ebit)	\
+{									\
+	.desc	= {							\
+		.name	= "LDO" #_id,					\
+		.ops	= &da903x_regulator_ldo_ops,			\
+		.type	= REGULATOR_VOLTAGE,				\
+		.id	= _pmic##_ID_LDO##_id,				\
+		.owner	= THIS_MODULE,					\
+	},								\
+	.min_uV		= (min) * 1000,					\
+	.max_uV		= (max) * 1000,					\
+	.step_uV	= (step) * 1000,				\
+	.vol_reg	= _pmic##_##vreg,				\
+	.vol_shift	= (shift),					\
+	.vol_nbits	= (nbits),					\
+	.enable_reg	= _pmic##_##ereg,				\
+	.enable_bit	= (ebit),					\
+}
+
+#define DA9034_DVC(_id, min, max, step, vreg, nbits, ureg, ubit, ereg, ebit) \
+{									\
+	.desc	= {							\
+		.name	= #_id,						\
+		.ops	= &da9034_regulator_dvc_ops,			\
+		.type	= REGULATOR_VOLTAGE,				\
+		.id	= DA9034_ID_##_id,				\
+		.owner	= THIS_MODULE,					\
+	},								\
+	.min_uV		= (min) * 1000,					\
+	.max_uV		= (max) * 1000,					\
+	.step_uV	= (step) * 1000,				\
+	.vol_reg	= DA9034_##vreg,				\
+	.vol_shift	= (0),						\
+	.vol_nbits	= (nbits),					\
+	.update_reg	= DA9034_##ureg,				\
+	.update_bit	= (ubit),					\
+	.enable_reg	= DA9034_##ereg,				\
+	.enable_bit	= (ebit),					\
+}
+
+#define DA9034_LDO(_id, min, max, step, vreg, shift, nbits, ereg, ebit)	\
+	DA903x_LDO(DA9034, _id, min, max, step, vreg, shift, nbits, ereg, ebit)
+
+#define DA9030_LDO(_id, min, max, step, vreg, shift, nbits, ereg, ebit)	\
+	DA903x_LDO(DA9030, _id, min, max, step, vreg, shift, nbits, ereg, ebit)
+
+static struct da903x_regulator_info da903x_regulator_info[] = {
+	/* DA9030 */
+	DA9030_LDO( 1, 1200, 3200, 100,    LDO1, 0, 5, RCTL12, 1),
+	DA9030_LDO( 2, 1800, 3200, 100,   LDO23, 0, 4, RCTL12, 2),
+	DA9030_LDO( 3, 1800, 3200, 100,   LDO23, 4, 4, RCTL12, 3),
+	DA9030_LDO( 4, 1800, 3200, 100,   LDO45, 0, 4, RCTL12, 4),
+	DA9030_LDO( 5, 1800, 3200, 100,   LDO45, 4, 4, RCTL12, 5),
+	DA9030_LDO( 6, 1800, 3200, 100,    LDO6, 0, 4, RCTL12, 6),
+	DA9030_LDO( 7, 1800, 3200, 100,   LDO78, 0, 4, RCTL12, 7),
+	DA9030_LDO( 8, 1800, 3200, 100,   LDO78, 4, 4, RCTL22, 0),
+	DA9030_LDO( 9, 1800, 3200, 100,  LDO912, 0, 4, RCTL22, 1),
+	DA9030_LDO(10, 1800, 3200, 100, LDO1011, 0, 4, RCTL22, 2),
+	DA9030_LDO(11, 1800, 3200, 100, LDO1011, 4, 4, RCTL22, 3),
+	DA9030_LDO(12, 1800, 3200, 100,  LDO912, 4, 4, RCTL22, 4),
+	DA9030_LDO(14, 2760, 2940,  30, LDO1416, 0, 3, RCTL11, 4),
+	DA9030_LDO(15, 1100, 2650,  50,	  LDO15, 0, 5, RCTL11, 5),
+	DA9030_LDO(16, 1100, 2650,  50, LDO1416, 3, 5, RCTL11, 6),
+	DA9030_LDO(17, 1800, 3200, 100,   LDO17, 0, 4, RCTL11, 7),
+	DA9030_LDO(18, 1800, 3200, 100, LDO1819, 0, 4, RCTL21, 2),
+	DA9030_LDO(19, 1800, 3200, 100, LDO1819, 4, 4, RCTL21, 1),
+	DA9030_LDO(13, 2100, 2100, 0, INVAL, 0, 0, RCTL11, 3), /* fixed @2.1V */
+
+	/* DA9034 */
+	DA9034_DVC(BUCK1, 725, 1500, 25, ADTV1, 5, VCC1, 0, OVER1, 0),
+	DA9034_DVC(BUCK2, 725, 1500, 25, CDTV1, 5, VCC1, 2, OVER1, 1),
+	DA9034_DVC(LDO2,  725, 1500, 25, SDTV1, 5, VCC1, 4, OVER1, 2),
+	DA9034_DVC(LDO1, 1700, 2075, 25, MDTV1, 4, VCC1, 6, OVER3, 4),
+
+	DA9034_LDO( 3, 1800, 3300, 100,  LDO643, 0, 4, OVER3, 5),
+	DA9034_LDO( 4, 1800, 2900,1100,  LDO643, 4, 1, OVER3, 6),
+	DA9034_LDO( 6, 2500, 2850,  50,  LDO643, 5, 3, OVER2, 0),
+	DA9034_LDO( 7, 2700, 3050,  50,  LDO987, 0, 3, OVER2, 1),
+	DA9034_LDO( 8, 2700, 2850,  50,  LDO987, 3, 2, OVER2, 2),
+	DA9034_LDO( 9, 2700, 3050,  50,  LDO987, 5, 3, OVER2, 3),
+	DA9034_LDO(10, 2700, 3050,  50, LDO1110, 0, 3, OVER2, 4),
+	DA9034_LDO(11, 1800, 3300, 100, LDO1110, 4, 4, OVER2, 5),
+	DA9034_LDO(12, 1700, 3050,  50, LDO1312, 0, 4, OVER3, 6),
+	DA9034_LDO(13, 1800, 3300, 100, LDO1312, 4, 4, OVER2, 7),
+	DA9034_LDO(14, 1800, 3300, 100, LDO1514, 0, 4, OVER3, 0),
+	DA9034_LDO(15, 1800, 3300, 100, LDO1514, 4, 4, OVER3, 1),
+	DA9034_LDO(5, 3100, 3100, 0, INVAL, 0, 0, OVER3, 7), /* fixed @3.1V */
+};
+
+static inline struct da903x_regulator_info *find_regulator_info(int id)
+{
+	struct da903x_regulator_info *ri;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(da903x_regulator_info); i++) {
+		ri = &da903x_regulator_info[i];
+		if (ri->desc.id == id)
+			return ri;
+	}
+	return NULL;
+}
+
+static int __devinit da903x_regulator_probe(struct platform_device *pdev)
+{
+	struct da903x_regulator_info *ri = NULL;
+	struct regulator_dev *rdev;
+
+	ri = find_regulator_info(pdev->id);
+	if (ri == NULL) {
+		dev_err(&pdev->dev, "invalid regulator ID specified\n");
+		return -EINVAL;
+	}
+
+	/* Workaround for the weird LDO12 voltage setting */
+	if (ri->desc.id == DA9034_ID_LDO12)
+		ri->desc.ops = &da9034_regulator_ldo12_ops;
+
+	if (ri->desc.id == DA9030_ID_LDO14)
+		ri->desc.ops = &da9030_regulator_ldo14_ops;
+
+	if (ri->desc.id == DA9030_ID_LDO1 || ri->desc.id == DA9030_ID_LDO15)
+		ri->desc.ops = &da9030_regulator_ldo1_15_ops;
+
+	rdev = regulator_register(&ri->desc, pdev->dev.parent, ri);
+	if (IS_ERR(rdev)) {
+		dev_err(&pdev->dev, "failed to register regulator %s\n",
+				ri->desc.name);
+		return PTR_ERR(rdev);
+	}
+
+	platform_set_drvdata(pdev, rdev);
+	return 0;
+}
+
+static int __devexit da903x_regulator_remove(struct platform_device *pdev)
+{
+	struct regulator_dev *rdev = platform_get_drvdata(pdev);
+
+	regulator_unregister(rdev);
+	return 0;
+}
+
+static struct platform_driver da903x_regulator_driver = {
+	.driver	= {
+		.name	= "da903x-regulator",
+		.owner	= THIS_MODULE,
+	},
+	.probe		= da903x_regulator_probe,
+	.remove		= da903x_regulator_remove,
+};
+
+static int __init da903x_regulator_init(void)
+{
+	return platform_driver_register(&da903x_regulator_driver);
+}
+module_init(da903x_regulator_init);
+
+static void __exit da903x_regulator_exit(void)
+{
+	platform_driver_unregister(&da903x_regulator_driver);
+}
+module_exit(da903x_regulator_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Eric Miao <eric.miao@marvell.com>"
+	      "Mike Rapoport <mike@compulab.co.il>");
+MODULE_DESCRIPTION("Regulator Driver for Dialog Semiconductor DA903X PMIC");
+MODULE_ALIAS("platform:da903x-regulator");
diff --git a/drivers/regulator/wm8350-regulator.c b/drivers/regulator/wm8350-regulator.c
new file mode 100644
index 0000000..1f44b17
--- /dev/null
+++ b/drivers/regulator/wm8350-regulator.c
@@ -0,0 +1,1431 @@
+/*
+ * wm8350.c  --  Voltage and current regulation for the Wolfson WM8350 PMIC
+ *
+ * Copyright 2007, 2008 Wolfson Microelectronics PLC.
+ *
+ * Author: Liam Girdwood
+ *         linux@wolfsonmicro.com
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/bitops.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/mfd/wm8350/core.h>
+#include <linux/mfd/wm8350/pmic.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+
+/* Microamps */
+static const int isink_cur[] = {
+	4,
+	5,
+	6,
+	7,
+	8,
+	10,
+	11,
+	14,
+	16,
+	19,
+	23,
+	27,
+	32,
+	39,
+	46,
+	54,
+	65,
+	77,
+	92,
+	109,
+	130,
+	154,
+	183,
+	218,
+	259,
+	308,
+	367,
+	436,
+	518,
+	616,
+	733,
+	872,
+	1037,
+	1233,
+	1466,
+	1744,
+	2073,
+	2466,
+	2933,
+	3487,
+	4147,
+	4932,
+	5865,
+	6975,
+	8294,
+	9864,
+	11730,
+	13949,
+	16589,
+	19728,
+	23460,
+	27899,
+	33178,
+	39455,
+	46920,
+	55798,
+	66355,
+	78910,
+	93840,
+	111596,
+	132710,
+	157820,
+	187681,
+	223191
+};
+
+static int get_isink_val(int min_uA, int max_uA, u16 *setting)
+{
+	int i;
+
+	for (i = ARRAY_SIZE(isink_cur) - 1; i >= 0; i--) {
+		if (min_uA <= isink_cur[i] && max_uA >= isink_cur[i]) {
+			*setting = i;
+			return 0;
+		}
+	}
+	return -EINVAL;
+}
+
+static inline int wm8350_ldo_val_to_mvolts(unsigned int val)
+{
+	if (val < 16)
+		return (val * 50) + 900;
+	else
+		return ((val - 16) * 100) + 1800;
+
+}
+
+static inline unsigned int wm8350_ldo_mvolts_to_val(int mV)
+{
+	if (mV < 1800)
+		return (mV - 900) / 50;
+	else
+		return ((mV - 1800) / 100) + 16;
+}
+
+static inline int wm8350_dcdc_val_to_mvolts(unsigned int val)
+{
+	return (val * 25) + 850;
+}
+
+static inline unsigned int wm8350_dcdc_mvolts_to_val(int mV)
+{
+	return (mV - 850) / 25;
+}
+
+static int wm8350_isink_set_current(struct regulator_dev *rdev, int min_uA,
+	int max_uA)
+{
+	struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+	int isink = rdev_get_id(rdev);
+	u16 val, setting;
+	int ret;
+
+	ret = get_isink_val(min_uA, max_uA, &setting);
+	if (ret != 0)
+		return ret;
+
+	switch (isink) {
+	case WM8350_ISINK_A:
+		val = wm8350_reg_read(wm8350, WM8350_CURRENT_SINK_DRIVER_A) &
+		    ~WM8350_CS1_ISEL_MASK;
+		wm8350_reg_write(wm8350, WM8350_CURRENT_SINK_DRIVER_A,
+				 val | setting);
+		break;
+	case WM8350_ISINK_B:
+		val = wm8350_reg_read(wm8350, WM8350_CURRENT_SINK_DRIVER_B) &
+		    ~WM8350_CS1_ISEL_MASK;
+		wm8350_reg_write(wm8350, WM8350_CURRENT_SINK_DRIVER_B,
+				 val | setting);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int wm8350_isink_get_current(struct regulator_dev *rdev)
+{
+	struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+	int isink = rdev_get_id(rdev);
+	u16 val;
+
+	switch (isink) {
+	case WM8350_ISINK_A:
+		val = wm8350_reg_read(wm8350, WM8350_CURRENT_SINK_DRIVER_A) &
+		    WM8350_CS1_ISEL_MASK;
+		break;
+	case WM8350_ISINK_B:
+		val = wm8350_reg_read(wm8350, WM8350_CURRENT_SINK_DRIVER_B) &
+		    WM8350_CS1_ISEL_MASK;
+		break;
+	default:
+		return 0;
+	}
+
+	return (isink_cur[val] + 50) / 100;
+}
+
+/* turn on ISINK followed by DCDC */
+static int wm8350_isink_enable(struct regulator_dev *rdev)
+{
+	struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+	int isink = rdev_get_id(rdev);
+
+	switch (isink) {
+	case WM8350_ISINK_A:
+		switch (wm8350->pmic.isink_A_dcdc) {
+		case WM8350_DCDC_2:
+		case WM8350_DCDC_5:
+			wm8350_set_bits(wm8350, WM8350_POWER_MGMT_7,
+					WM8350_CS1_ENA);
+			wm8350_set_bits(wm8350, WM8350_CSA_FLASH_CONTROL,
+					WM8350_CS1_DRIVE);
+			wm8350_set_bits(wm8350, WM8350_DCDC_LDO_REQUESTED,
+					1 << (wm8350->pmic.isink_A_dcdc -
+					      WM8350_DCDC_1));
+			break;
+		default:
+			return -EINVAL;
+		}
+		break;
+	case WM8350_ISINK_B:
+		switch (wm8350->pmic.isink_B_dcdc) {
+		case WM8350_DCDC_2:
+		case WM8350_DCDC_5:
+			wm8350_set_bits(wm8350, WM8350_POWER_MGMT_7,
+					WM8350_CS2_ENA);
+			wm8350_set_bits(wm8350, WM8350_CSB_FLASH_CONTROL,
+					WM8350_CS2_DRIVE);
+			wm8350_set_bits(wm8350, WM8350_DCDC_LDO_REQUESTED,
+					1 << (wm8350->pmic.isink_B_dcdc -
+					      WM8350_DCDC_1));
+			break;
+		default:
+			return -EINVAL;
+		}
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int wm8350_isink_disable(struct regulator_dev *rdev)
+{
+	struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+	int isink = rdev_get_id(rdev);
+
+	switch (isink) {
+	case WM8350_ISINK_A:
+		switch (wm8350->pmic.isink_A_dcdc) {
+		case WM8350_DCDC_2:
+		case WM8350_DCDC_5:
+			wm8350_clear_bits(wm8350, WM8350_DCDC_LDO_REQUESTED,
+					  1 << (wm8350->pmic.isink_A_dcdc -
+						WM8350_DCDC_1));
+			wm8350_clear_bits(wm8350, WM8350_POWER_MGMT_7,
+					  WM8350_CS1_ENA);
+			break;
+		default:
+			return -EINVAL;
+		}
+		break;
+	case WM8350_ISINK_B:
+		switch (wm8350->pmic.isink_B_dcdc) {
+		case WM8350_DCDC_2:
+		case WM8350_DCDC_5:
+			wm8350_clear_bits(wm8350, WM8350_DCDC_LDO_REQUESTED,
+					  1 << (wm8350->pmic.isink_B_dcdc -
+						WM8350_DCDC_1));
+			wm8350_clear_bits(wm8350, WM8350_POWER_MGMT_7,
+					  WM8350_CS2_ENA);
+			break;
+		default:
+			return -EINVAL;
+		}
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int wm8350_isink_is_enabled(struct regulator_dev *rdev)
+{
+	struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+	int isink = rdev_get_id(rdev);
+
+	switch (isink) {
+	case WM8350_ISINK_A:
+		return wm8350_reg_read(wm8350, WM8350_CURRENT_SINK_DRIVER_A) &
+		    0x8000;
+	case WM8350_ISINK_B:
+		return wm8350_reg_read(wm8350, WM8350_CURRENT_SINK_DRIVER_B) &
+		    0x8000;
+	}
+	return -EINVAL;
+}
+
+int wm8350_isink_set_flash(struct wm8350 *wm8350, int isink, u16 mode,
+			   u16 trigger, u16 duration, u16 on_ramp, u16 off_ramp,
+			   u16 drive)
+{
+	switch (isink) {
+	case WM8350_ISINK_A:
+		wm8350_reg_write(wm8350, WM8350_CSA_FLASH_CONTROL,
+				 (mode ? WM8350_CS1_FLASH_MODE : 0) |
+				 (trigger ? WM8350_CS1_TRIGSRC : 0) |
+				 duration | on_ramp | off_ramp | drive);
+		break;
+	case WM8350_ISINK_B:
+		wm8350_reg_write(wm8350, WM8350_CSB_FLASH_CONTROL,
+				 (mode ? WM8350_CS2_FLASH_MODE : 0) |
+				 (trigger ? WM8350_CS2_TRIGSRC : 0) |
+				 duration | on_ramp | off_ramp | drive);
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+EXPORT_SYMBOL_GPL(wm8350_isink_set_flash);
+
+static int wm8350_dcdc_set_voltage(struct regulator_dev *rdev, int min_uV,
+	int max_uV)
+{
+	struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+	int volt_reg, dcdc = rdev_get_id(rdev), mV,
+		min_mV = min_uV / 1000, max_mV = max_uV / 1000;
+	u16 val;
+
+	if (min_mV < 850 || min_mV > 4025)
+		return -EINVAL;
+	if (max_mV < 850 || max_mV > 4025)
+		return -EINVAL;
+
+	/* step size is 25mV */
+	mV = (min_mV - 826) / 25;
+	if (wm8350_dcdc_val_to_mvolts(mV) > max_mV)
+		return -EINVAL;
+	BUG_ON(wm8350_dcdc_val_to_mvolts(mV) < min_mV);
+
+	switch (dcdc) {
+	case WM8350_DCDC_1:
+		volt_reg = WM8350_DCDC1_CONTROL;
+		break;
+	case WM8350_DCDC_3:
+		volt_reg = WM8350_DCDC3_CONTROL;
+		break;
+	case WM8350_DCDC_4:
+		volt_reg = WM8350_DCDC4_CONTROL;
+		break;
+	case WM8350_DCDC_6:
+		volt_reg = WM8350_DCDC6_CONTROL;
+		break;
+	case WM8350_DCDC_2:
+	case WM8350_DCDC_5:
+	default:
+		return -EINVAL;
+	}
+
+	/* all DCDCs have same mV bits */
+	val = wm8350_reg_read(wm8350, volt_reg) & ~WM8350_DC1_VSEL_MASK;
+	wm8350_reg_write(wm8350, volt_reg, val | mV);
+	return 0;
+}
+
+static int wm8350_dcdc_get_voltage(struct regulator_dev *rdev)
+{
+	struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+	int volt_reg, dcdc = rdev_get_id(rdev);
+	u16 val;
+
+	switch (dcdc) {
+	case WM8350_DCDC_1:
+		volt_reg = WM8350_DCDC1_CONTROL;
+		break;
+	case WM8350_DCDC_3:
+		volt_reg = WM8350_DCDC3_CONTROL;
+		break;
+	case WM8350_DCDC_4:
+		volt_reg = WM8350_DCDC4_CONTROL;
+		break;
+	case WM8350_DCDC_6:
+		volt_reg = WM8350_DCDC6_CONTROL;
+		break;
+	case WM8350_DCDC_2:
+	case WM8350_DCDC_5:
+	default:
+		return -EINVAL;
+	}
+
+	/* all DCDCs have same mV bits */
+	val = wm8350_reg_read(wm8350, volt_reg) & WM8350_DC1_VSEL_MASK;
+	return wm8350_dcdc_val_to_mvolts(val) * 1000;
+}
+
+static int wm8350_dcdc_set_suspend_voltage(struct regulator_dev *rdev, int uV)
+{
+	struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+	int volt_reg, mV = uV / 1000, dcdc = rdev_get_id(rdev);
+	u16 val;
+
+	dev_dbg(wm8350->dev, "%s %d mV %d\n", __func__, dcdc, mV);
+
+	if (mV && (mV < 850 || mV > 4025)) {
+		dev_err(wm8350->dev,
+			"DCDC%d suspend voltage %d mV out of range\n",
+			dcdc, mV);
+		return -EINVAL;
+	}
+	if (mV == 0)
+		mV = 850;
+
+	switch (dcdc) {
+	case WM8350_DCDC_1:
+		volt_reg = WM8350_DCDC1_LOW_POWER;
+		break;
+	case WM8350_DCDC_3:
+		volt_reg = WM8350_DCDC3_LOW_POWER;
+		break;
+	case WM8350_DCDC_4:
+		volt_reg = WM8350_DCDC4_LOW_POWER;
+		break;
+	case WM8350_DCDC_6:
+		volt_reg = WM8350_DCDC6_LOW_POWER;
+		break;
+	case WM8350_DCDC_2:
+	case WM8350_DCDC_5:
+	default:
+		return -EINVAL;
+	}
+
+	/* all DCDCs have same mV bits */
+	val = wm8350_reg_read(wm8350, volt_reg) & ~WM8350_DC1_VSEL_MASK;
+	wm8350_reg_write(wm8350, volt_reg,
+			 val | wm8350_dcdc_mvolts_to_val(mV));
+	return 0;
+}
+
+static int wm8350_dcdc_set_suspend_enable(struct regulator_dev *rdev)
+{
+	struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+	int dcdc = rdev_get_id(rdev);
+	u16 val;
+
+	switch (dcdc) {
+	case WM8350_DCDC_1:
+		val = wm8350_reg_read(wm8350, WM8350_DCDC1_LOW_POWER)
+			& ~WM8350_DCDC_HIB_MODE_MASK;
+		wm8350_reg_write(wm8350, WM8350_DCDC1_LOW_POWER,
+			wm8350->pmic.dcdc1_hib_mode);
+		break;
+	case WM8350_DCDC_3:
+		val = wm8350_reg_read(wm8350, WM8350_DCDC3_LOW_POWER)
+			& ~WM8350_DCDC_HIB_MODE_MASK;
+		wm8350_reg_write(wm8350, WM8350_DCDC3_LOW_POWER,
+			wm8350->pmic.dcdc3_hib_mode);
+		break;
+	case WM8350_DCDC_4:
+		val = wm8350_reg_read(wm8350, WM8350_DCDC4_LOW_POWER)
+			& ~WM8350_DCDC_HIB_MODE_MASK;
+		wm8350_reg_write(wm8350, WM8350_DCDC4_LOW_POWER,
+			wm8350->pmic.dcdc4_hib_mode);
+		break;
+	case WM8350_DCDC_6:
+		val = wm8350_reg_read(wm8350, WM8350_DCDC6_LOW_POWER)
+			& ~WM8350_DCDC_HIB_MODE_MASK;
+		wm8350_reg_write(wm8350, WM8350_DCDC6_LOW_POWER,
+			wm8350->pmic.dcdc6_hib_mode);
+		break;
+	case WM8350_DCDC_2:
+	case WM8350_DCDC_5:
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int wm8350_dcdc_set_suspend_disable(struct regulator_dev *rdev)
+{
+	struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+	int dcdc = rdev_get_id(rdev);
+	u16 val;
+
+	switch (dcdc) {
+	case WM8350_DCDC_1:
+		val = wm8350_reg_read(wm8350, WM8350_DCDC1_LOW_POWER);
+		wm8350->pmic.dcdc1_hib_mode = val & WM8350_DCDC_HIB_MODE_MASK;
+		wm8350_reg_write(wm8350, WM8350_DCDC1_LOW_POWER,
+			WM8350_DCDC_HIB_MODE_DIS);
+		break;
+	case WM8350_DCDC_3:
+		val = wm8350_reg_read(wm8350, WM8350_DCDC3_LOW_POWER);
+		wm8350->pmic.dcdc3_hib_mode = val & WM8350_DCDC_HIB_MODE_MASK;
+		wm8350_reg_write(wm8350, WM8350_DCDC3_LOW_POWER,
+			WM8350_DCDC_HIB_MODE_DIS);
+		break;
+	case WM8350_DCDC_4:
+		val = wm8350_reg_read(wm8350, WM8350_DCDC4_LOW_POWER);
+		wm8350->pmic.dcdc4_hib_mode = val & WM8350_DCDC_HIB_MODE_MASK;
+		wm8350_reg_write(wm8350, WM8350_DCDC4_LOW_POWER,
+			WM8350_DCDC_HIB_MODE_DIS);
+		break;
+	case WM8350_DCDC_6:
+		val = wm8350_reg_read(wm8350, WM8350_DCDC6_LOW_POWER);
+		wm8350->pmic.dcdc6_hib_mode = val & WM8350_DCDC_HIB_MODE_MASK;
+		wm8350_reg_write(wm8350, WM8350_DCDC6_LOW_POWER,
+			WM8350_DCDC_HIB_MODE_DIS);
+		break;
+	case WM8350_DCDC_2:
+	case WM8350_DCDC_5:
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int wm8350_dcdc25_set_suspend_enable(struct regulator_dev *rdev)
+{
+	struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+	int dcdc = rdev_get_id(rdev);
+	u16 val;
+
+	switch (dcdc) {
+	case WM8350_DCDC_2:
+		val = wm8350_reg_read(wm8350, WM8350_DCDC2_CONTROL)
+		    & ~WM8350_DC2_HIB_MODE_MASK;
+		wm8350_reg_write(wm8350, WM8350_DCDC2_CONTROL, val |
+				 WM8350_DC2_HIB_MODE_ACTIVE);
+		break;
+	case WM8350_DCDC_5:
+		val = wm8350_reg_read(wm8350, WM8350_DCDC5_CONTROL)
+		    & ~WM8350_DC2_HIB_MODE_MASK;
+		wm8350_reg_write(wm8350, WM8350_DCDC5_CONTROL, val |
+				 WM8350_DC5_HIB_MODE_ACTIVE);
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int wm8350_dcdc25_set_suspend_disable(struct regulator_dev *rdev)
+{
+	struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+	int dcdc = rdev_get_id(rdev);
+	u16 val;
+
+	switch (dcdc) {
+	case WM8350_DCDC_2:
+		val = wm8350_reg_read(wm8350, WM8350_DCDC2_CONTROL)
+		    & ~WM8350_DC2_HIB_MODE_MASK;
+		wm8350_reg_write(wm8350, WM8350_DCDC2_CONTROL, val |
+				 WM8350_DC2_HIB_MODE_DISABLE);
+		break;
+	case WM8350_DCDC_5:
+		val = wm8350_reg_read(wm8350, WM8350_DCDC5_CONTROL)
+		    & ~WM8350_DC2_HIB_MODE_MASK;
+		wm8350_reg_write(wm8350, WM8350_DCDC5_CONTROL, val |
+				 WM8350_DC2_HIB_MODE_DISABLE);
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int wm8350_dcdc_set_suspend_mode(struct regulator_dev *rdev,
+	unsigned int mode)
+{
+	struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+	int dcdc = rdev_get_id(rdev);
+	u16 *hib_mode;
+
+	switch (dcdc) {
+	case WM8350_DCDC_1:
+		hib_mode = &wm8350->pmic.dcdc1_hib_mode;
+		break;
+	case WM8350_DCDC_3:
+		hib_mode = &wm8350->pmic.dcdc3_hib_mode;
+		break;
+	case WM8350_DCDC_4:
+		hib_mode = &wm8350->pmic.dcdc4_hib_mode;
+		break;
+	case WM8350_DCDC_6:
+		hib_mode = &wm8350->pmic.dcdc6_hib_mode;
+		break;
+	case WM8350_DCDC_2:
+	case WM8350_DCDC_5:
+	default:
+		return -EINVAL;
+	}
+
+	switch (mode) {
+	case REGULATOR_MODE_NORMAL:
+		*hib_mode = WM8350_DCDC_HIB_MODE_IMAGE;
+		break;
+	case REGULATOR_MODE_IDLE:
+		*hib_mode = WM8350_DCDC_HIB_MODE_STANDBY;
+		break;
+	case REGULATOR_MODE_STANDBY:
+		*hib_mode = WM8350_DCDC_HIB_MODE_LDO_IM;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int wm8350_ldo_set_suspend_voltage(struct regulator_dev *rdev, int uV)
+{
+	struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+	int volt_reg, mV = uV / 1000, ldo = rdev_get_id(rdev);
+	u16 val;
+
+	dev_dbg(wm8350->dev, "%s %d mV %d\n", __func__, ldo, mV);
+
+	if (mV < 900 || mV > 3300) {
+		dev_err(wm8350->dev, "LDO%d voltage %d mV out of range\n",
+			ldo, mV);
+		return -EINVAL;
+	}
+
+	switch (ldo) {
+	case WM8350_LDO_1:
+		volt_reg = WM8350_LDO1_LOW_POWER;
+		break;
+	case WM8350_LDO_2:
+		volt_reg = WM8350_LDO2_LOW_POWER;
+		break;
+	case WM8350_LDO_3:
+		volt_reg = WM8350_LDO3_LOW_POWER;
+		break;
+	case WM8350_LDO_4:
+		volt_reg = WM8350_LDO4_LOW_POWER;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* all LDOs have same mV bits */
+	val = wm8350_reg_read(wm8350, volt_reg) & ~WM8350_LDO1_VSEL_MASK;
+	wm8350_reg_write(wm8350, volt_reg,
+			 val | wm8350_ldo_mvolts_to_val(mV));
+	return 0;
+}
+
+static int wm8350_ldo_set_suspend_enable(struct regulator_dev *rdev)
+{
+	struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+	int volt_reg, ldo = rdev_get_id(rdev);
+	u16 val;
+
+	switch (ldo) {
+	case WM8350_LDO_1:
+		volt_reg = WM8350_LDO1_LOW_POWER;
+		break;
+	case WM8350_LDO_2:
+		volt_reg = WM8350_LDO2_LOW_POWER;
+		break;
+	case WM8350_LDO_3:
+		volt_reg = WM8350_LDO3_LOW_POWER;
+		break;
+	case WM8350_LDO_4:
+		volt_reg = WM8350_LDO4_LOW_POWER;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* all LDOs have same mV bits */
+	val = wm8350_reg_read(wm8350, volt_reg) & ~WM8350_LDO1_HIB_MODE_MASK;
+	wm8350_reg_write(wm8350, volt_reg, val);
+	return 0;
+}
+
+static int wm8350_ldo_set_suspend_disable(struct regulator_dev *rdev)
+{
+	struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+	int volt_reg, ldo = rdev_get_id(rdev);
+	u16 val;
+
+	switch (ldo) {
+	case WM8350_LDO_1:
+		volt_reg = WM8350_LDO1_LOW_POWER;
+		break;
+	case WM8350_LDO_2:
+		volt_reg = WM8350_LDO2_LOW_POWER;
+		break;
+	case WM8350_LDO_3:
+		volt_reg = WM8350_LDO3_LOW_POWER;
+		break;
+	case WM8350_LDO_4:
+		volt_reg = WM8350_LDO4_LOW_POWER;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* all LDOs have same mV bits */
+	val = wm8350_reg_read(wm8350, volt_reg) & ~WM8350_LDO1_HIB_MODE_MASK;
+	wm8350_reg_write(wm8350, volt_reg, WM8350_LDO1_HIB_MODE_DIS);
+	return 0;
+}
+
+static int wm8350_ldo_set_voltage(struct regulator_dev *rdev, int min_uV,
+	int max_uV)
+{
+	struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+	int volt_reg, ldo = rdev_get_id(rdev), mV, min_mV = min_uV / 1000,
+		max_mV = max_uV / 1000;
+	u16 val;
+
+	if (min_mV < 900 || min_mV > 3300)
+		return -EINVAL;
+	if (max_mV < 900 || max_mV > 3300)
+		return -EINVAL;
+
+	if (min_mV < 1800) {
+		/* step size is 50mV < 1800mV */
+		mV = (min_mV - 851) / 50;
+		if (wm8350_ldo_val_to_mvolts(mV) > max_mV)
+			return -EINVAL;
+		BUG_ON(wm8350_ldo_val_to_mvolts(mV) < min_mV);
+	} else {
+		/* step size is 100mV > 1800mV */
+		mV = ((min_mV - 1701) / 100) + 16;
+		if (wm8350_ldo_val_to_mvolts(mV) > max_mV)
+			return -EINVAL;
+		BUG_ON(wm8350_ldo_val_to_mvolts(mV) < min_mV);
+	}
+
+	switch (ldo) {
+	case WM8350_LDO_1:
+		volt_reg = WM8350_LDO1_CONTROL;
+		break;
+	case WM8350_LDO_2:
+		volt_reg = WM8350_LDO2_CONTROL;
+		break;
+	case WM8350_LDO_3:
+		volt_reg = WM8350_LDO3_CONTROL;
+		break;
+	case WM8350_LDO_4:
+		volt_reg = WM8350_LDO4_CONTROL;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* all LDOs have same mV bits */
+	val = wm8350_reg_read(wm8350, volt_reg) & ~WM8350_LDO1_VSEL_MASK;
+	wm8350_reg_write(wm8350, volt_reg, val | mV);
+	return 0;
+}
+
+static int wm8350_ldo_get_voltage(struct regulator_dev *rdev)
+{
+	struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+	int volt_reg, ldo = rdev_get_id(rdev);
+	u16 val;
+
+	switch (ldo) {
+	case WM8350_LDO_1:
+		volt_reg = WM8350_LDO1_CONTROL;
+		break;
+	case WM8350_LDO_2:
+		volt_reg = WM8350_LDO2_CONTROL;
+		break;
+	case WM8350_LDO_3:
+		volt_reg = WM8350_LDO3_CONTROL;
+		break;
+	case WM8350_LDO_4:
+		volt_reg = WM8350_LDO4_CONTROL;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* all LDOs have same mV bits */
+	val = wm8350_reg_read(wm8350, volt_reg) & WM8350_LDO1_VSEL_MASK;
+	return wm8350_ldo_val_to_mvolts(val) * 1000;
+}
+
+int wm8350_dcdc_set_slot(struct wm8350 *wm8350, int dcdc, u16 start,
+			 u16 stop, u16 fault)
+{
+	int slot_reg;
+	u16 val;
+
+	dev_dbg(wm8350->dev, "%s %d start %d stop %d\n",
+		__func__, dcdc, start, stop);
+
+	/* slot valid ? */
+	if (start > 15 || stop > 15)
+		return -EINVAL;
+
+	switch (dcdc) {
+	case WM8350_DCDC_1:
+		slot_reg = WM8350_DCDC1_TIMEOUTS;
+		break;
+	case WM8350_DCDC_2:
+		slot_reg = WM8350_DCDC2_TIMEOUTS;
+		break;
+	case WM8350_DCDC_3:
+		slot_reg = WM8350_DCDC3_TIMEOUTS;
+		break;
+	case WM8350_DCDC_4:
+		slot_reg = WM8350_DCDC4_TIMEOUTS;
+		break;
+	case WM8350_DCDC_5:
+		slot_reg = WM8350_DCDC5_TIMEOUTS;
+		break;
+	case WM8350_DCDC_6:
+		slot_reg = WM8350_DCDC6_TIMEOUTS;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	val = wm8350_reg_read(wm8350, slot_reg) &
+	    ~(WM8350_DC1_ENSLOT_MASK | WM8350_DC1_SDSLOT_MASK |
+	      WM8350_DC1_ERRACT_MASK);
+	wm8350_reg_write(wm8350, slot_reg,
+			 val | (start << WM8350_DC1_ENSLOT_SHIFT) |
+			 (stop << WM8350_DC1_SDSLOT_SHIFT) |
+			 (fault << WM8350_DC1_ERRACT_SHIFT));
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(wm8350_dcdc_set_slot);
+
+int wm8350_ldo_set_slot(struct wm8350 *wm8350, int ldo, u16 start, u16 stop)
+{
+	int slot_reg;
+	u16 val;
+
+	dev_dbg(wm8350->dev, "%s %d start %d stop %d\n",
+		__func__, ldo, start, stop);
+
+	/* slot valid ? */
+	if (start > 15 || stop > 15)
+		return -EINVAL;
+
+	switch (ldo) {
+	case WM8350_LDO_1:
+		slot_reg = WM8350_LDO1_TIMEOUTS;
+		break;
+	case WM8350_LDO_2:
+		slot_reg = WM8350_LDO2_TIMEOUTS;
+		break;
+	case WM8350_LDO_3:
+		slot_reg = WM8350_LDO3_TIMEOUTS;
+		break;
+	case WM8350_LDO_4:
+		slot_reg = WM8350_LDO4_TIMEOUTS;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	val = wm8350_reg_read(wm8350, slot_reg) & ~WM8350_LDO1_SDSLOT_MASK;
+	wm8350_reg_write(wm8350, slot_reg, val | ((start << 10) | (stop << 6)));
+	return 0;
+}
+EXPORT_SYMBOL_GPL(wm8350_ldo_set_slot);
+
+int wm8350_dcdc25_set_mode(struct wm8350 *wm8350, int dcdc, u16 mode,
+			   u16 ilim, u16 ramp, u16 feedback)
+{
+	u16 val;
+
+	dev_dbg(wm8350->dev, "%s %d mode: %s %s\n", __func__, dcdc,
+		mode ? "normal" : "boost", ilim ? "low" : "normal");
+
+	switch (dcdc) {
+	case WM8350_DCDC_2:
+		val = wm8350_reg_read(wm8350, WM8350_DCDC2_CONTROL)
+		    & ~(WM8350_DC2_MODE_MASK | WM8350_DC2_ILIM_MASK |
+			WM8350_DC2_RMP_MASK | WM8350_DC2_FBSRC_MASK);
+		wm8350_reg_write(wm8350, WM8350_DCDC2_CONTROL, val |
+				 (mode << WM8350_DC2_MODE_SHIFT) |
+				 (ilim << WM8350_DC2_ILIM_SHIFT) |
+				 (ramp << WM8350_DC2_RMP_SHIFT) |
+				 (feedback << WM8350_DC2_FBSRC_SHIFT));
+		break;
+	case WM8350_DCDC_5:
+		val = wm8350_reg_read(wm8350, WM8350_DCDC5_CONTROL)
+		    & ~(WM8350_DC5_MODE_MASK | WM8350_DC5_ILIM_MASK |
+			WM8350_DC5_RMP_MASK | WM8350_DC5_FBSRC_MASK);
+		wm8350_reg_write(wm8350, WM8350_DCDC5_CONTROL, val |
+				 (mode << WM8350_DC5_MODE_SHIFT) |
+				 (ilim << WM8350_DC5_ILIM_SHIFT) |
+				 (ramp << WM8350_DC5_RMP_SHIFT) |
+				 (feedback << WM8350_DC5_FBSRC_SHIFT));
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(wm8350_dcdc25_set_mode);
+
+static int wm8350_dcdc_enable(struct regulator_dev *rdev)
+{
+	struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+	int dcdc = rdev_get_id(rdev);
+	u16 shift;
+
+	if (dcdc < WM8350_DCDC_1 || dcdc > WM8350_DCDC_6)
+		return -EINVAL;
+
+	shift = dcdc - WM8350_DCDC_1;
+	wm8350_set_bits(wm8350, WM8350_DCDC_LDO_REQUESTED, 1 << shift);
+	return 0;
+}
+
+static int wm8350_dcdc_disable(struct regulator_dev *rdev)
+{
+	struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+	int dcdc = rdev_get_id(rdev);
+	u16 shift;
+
+	if (dcdc < WM8350_DCDC_1 || dcdc > WM8350_DCDC_6)
+		return -EINVAL;
+
+	shift = dcdc - WM8350_DCDC_1;
+	wm8350_clear_bits(wm8350, WM8350_DCDC_LDO_REQUESTED, 1 << shift);
+
+	return 0;
+}
+
+static int wm8350_ldo_enable(struct regulator_dev *rdev)
+{
+	struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+	int ldo = rdev_get_id(rdev);
+	u16 shift;
+
+	if (ldo < WM8350_LDO_1 || ldo > WM8350_LDO_4)
+		return -EINVAL;
+
+	shift = (ldo - WM8350_LDO_1) + 8;
+	wm8350_set_bits(wm8350, WM8350_DCDC_LDO_REQUESTED, 1 << shift);
+	return 0;
+}
+
+static int wm8350_ldo_disable(struct regulator_dev *rdev)
+{
+	struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+	int ldo = rdev_get_id(rdev);
+	u16 shift;
+
+	if (ldo < WM8350_LDO_1 || ldo > WM8350_LDO_4)
+		return -EINVAL;
+
+	shift = (ldo - WM8350_LDO_1) + 8;
+	wm8350_clear_bits(wm8350, WM8350_DCDC_LDO_REQUESTED, 1 << shift);
+	return 0;
+}
+
+static int force_continuous_enable(struct wm8350 *wm8350, int dcdc, int enable)
+{
+	int reg = 0, ret;
+
+	switch (dcdc) {
+	case WM8350_DCDC_1:
+		reg = WM8350_DCDC1_FORCE_PWM;
+		break;
+	case WM8350_DCDC_3:
+		reg = WM8350_DCDC3_FORCE_PWM;
+		break;
+	case WM8350_DCDC_4:
+		reg = WM8350_DCDC4_FORCE_PWM;
+		break;
+	case WM8350_DCDC_6:
+		reg = WM8350_DCDC6_FORCE_PWM;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (enable)
+		ret = wm8350_set_bits(wm8350, reg,
+			WM8350_DCDC1_FORCE_PWM_ENA);
+	else
+		ret = wm8350_clear_bits(wm8350, reg,
+			WM8350_DCDC1_FORCE_PWM_ENA);
+	return ret;
+}
+
+static int wm8350_dcdc_set_mode(struct regulator_dev *rdev, unsigned int mode)
+{
+	struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+	int dcdc = rdev_get_id(rdev);
+	u16 val;
+
+	if (dcdc < WM8350_DCDC_1 || dcdc > WM8350_DCDC_6)
+		return -EINVAL;
+
+	if (dcdc == WM8350_DCDC_2 || dcdc == WM8350_DCDC_5)
+		return -EINVAL;
+
+	val = 1 << (dcdc - WM8350_DCDC_1);
+
+	switch (mode) {
+	case REGULATOR_MODE_FAST:
+		/* force continuous mode */
+		wm8350_set_bits(wm8350, WM8350_DCDC_ACTIVE_OPTIONS, val);
+		wm8350_clear_bits(wm8350, WM8350_DCDC_SLEEP_OPTIONS, val);
+		force_continuous_enable(wm8350, dcdc, 1);
+		break;
+	case REGULATOR_MODE_NORMAL:
+		/* active / pulse skipping */
+		wm8350_set_bits(wm8350, WM8350_DCDC_ACTIVE_OPTIONS, val);
+		wm8350_clear_bits(wm8350, WM8350_DCDC_SLEEP_OPTIONS, val);
+		force_continuous_enable(wm8350, dcdc, 0);
+		break;
+	case REGULATOR_MODE_IDLE:
+		/* standby mode */
+		force_continuous_enable(wm8350, dcdc, 0);
+		wm8350_clear_bits(wm8350, WM8350_DCDC_SLEEP_OPTIONS, val);
+		wm8350_clear_bits(wm8350, WM8350_DCDC_ACTIVE_OPTIONS, val);
+		break;
+	case REGULATOR_MODE_STANDBY:
+		/* LDO mode */
+		force_continuous_enable(wm8350, dcdc, 0);
+		wm8350_set_bits(wm8350, WM8350_DCDC_SLEEP_OPTIONS, val);
+		break;
+	}
+
+	return 0;
+}
+
+static unsigned int wm8350_dcdc_get_mode(struct regulator_dev *rdev)
+{
+	struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+	int dcdc = rdev_get_id(rdev);
+	u16 mask, sleep, active, force;
+	int mode = REGULATOR_MODE_NORMAL;
+
+	if (dcdc < WM8350_DCDC_1 || dcdc > WM8350_DCDC_6)
+		return -EINVAL;
+
+	if (dcdc == WM8350_DCDC_2 || dcdc == WM8350_DCDC_5)
+		return -EINVAL;
+
+	mask = 1 << (dcdc - WM8350_DCDC_1);
+	active = wm8350_reg_read(wm8350, WM8350_DCDC_ACTIVE_OPTIONS) & mask;
+	sleep = wm8350_reg_read(wm8350, WM8350_DCDC_SLEEP_OPTIONS) & mask;
+	force = wm8350_reg_read(wm8350, WM8350_DCDC1_FORCE_PWM)
+	    & WM8350_DCDC1_FORCE_PWM_ENA;
+	dev_dbg(wm8350->dev, "mask %x active %x sleep %x force %x",
+		mask, active, sleep, force);
+
+	if (active && !sleep) {
+		if (force)
+			mode = REGULATOR_MODE_FAST;
+		else
+			mode = REGULATOR_MODE_NORMAL;
+	} else if (!active && !sleep)
+		mode = REGULATOR_MODE_IDLE;
+	else if (!sleep)
+		mode = REGULATOR_MODE_STANDBY;
+
+	return mode;
+}
+
+static unsigned int wm8350_ldo_get_mode(struct regulator_dev *rdev)
+{
+	return REGULATOR_MODE_NORMAL;
+}
+
+struct wm8350_dcdc_efficiency {
+	int uA_load_min;
+	int uA_load_max;
+	unsigned int mode;
+};
+
+static const struct wm8350_dcdc_efficiency dcdc1_6_efficiency[] = {
+	{0, 10000, REGULATOR_MODE_STANDBY},       /* 0 - 10mA - LDO */
+	{10000, 100000, REGULATOR_MODE_IDLE},     /* 10mA - 100mA - Standby */
+	{100000, 1000000, REGULATOR_MODE_NORMAL}, /* > 100mA - Active */
+	{-1, -1, REGULATOR_MODE_NORMAL},
+};
+
+static const struct wm8350_dcdc_efficiency dcdc3_4_efficiency[] = {
+	{0, 10000, REGULATOR_MODE_STANDBY},      /* 0 - 10mA - LDO */
+	{10000, 100000, REGULATOR_MODE_IDLE},    /* 10mA - 100mA - Standby */
+	{100000, 800000, REGULATOR_MODE_NORMAL}, /* > 100mA - Active */
+	{-1, -1, REGULATOR_MODE_NORMAL},
+};
+
+static unsigned int get_mode(int uA, const struct wm8350_dcdc_efficiency *eff)
+{
+	int i = 0;
+
+	while (eff[i].uA_load_min != -1) {
+		if (uA >= eff[i].uA_load_min && uA <= eff[i].uA_load_max)
+			return eff[i].mode;
+	}
+	return REGULATOR_MODE_NORMAL;
+}
+
+/* Query the regulator for it's most efficient mode @ uV,uA
+ * WM8350 regulator efficiency is pretty similar over
+ * different input and output uV.
+ */
+static unsigned int wm8350_dcdc_get_optimum_mode(struct regulator_dev *rdev,
+						 int input_uV, int output_uV,
+						 int output_uA)
+{
+	int dcdc = rdev_get_id(rdev), mode;
+
+	switch (dcdc) {
+	case WM8350_DCDC_1:
+	case WM8350_DCDC_6:
+		mode = get_mode(output_uA, dcdc1_6_efficiency);
+		break;
+	case WM8350_DCDC_3:
+	case WM8350_DCDC_4:
+		mode = get_mode(output_uA, dcdc3_4_efficiency);
+		break;
+	default:
+		mode = REGULATOR_MODE_NORMAL;
+		break;
+	}
+	return mode;
+}
+
+static int wm8350_dcdc_is_enabled(struct regulator_dev *rdev)
+{
+	struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+	int dcdc = rdev_get_id(rdev), shift;
+
+	if (dcdc < WM8350_DCDC_1 || dcdc > WM8350_DCDC_6)
+		return -EINVAL;
+
+	shift = dcdc - WM8350_DCDC_1;
+	return wm8350_reg_read(wm8350, WM8350_DCDC_LDO_REQUESTED)
+	    & (1 << shift);
+}
+
+static int wm8350_ldo_is_enabled(struct regulator_dev *rdev)
+{
+	struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+	int ldo = rdev_get_id(rdev), shift;
+
+	if (ldo < WM8350_LDO_1 || ldo > WM8350_LDO_4)
+		return -EINVAL;
+
+	shift = (ldo - WM8350_LDO_1) + 8;
+	return wm8350_reg_read(wm8350, WM8350_DCDC_LDO_REQUESTED)
+	    & (1 << shift);
+}
+
+static struct regulator_ops wm8350_dcdc_ops = {
+	.set_voltage = wm8350_dcdc_set_voltage,
+	.get_voltage = wm8350_dcdc_get_voltage,
+	.enable = wm8350_dcdc_enable,
+	.disable = wm8350_dcdc_disable,
+	.get_mode = wm8350_dcdc_get_mode,
+	.set_mode = wm8350_dcdc_set_mode,
+	.get_optimum_mode = wm8350_dcdc_get_optimum_mode,
+	.is_enabled = wm8350_dcdc_is_enabled,
+	.set_suspend_voltage = wm8350_dcdc_set_suspend_voltage,
+	.set_suspend_enable = wm8350_dcdc_set_suspend_enable,
+	.set_suspend_disable = wm8350_dcdc_set_suspend_disable,
+	.set_suspend_mode = wm8350_dcdc_set_suspend_mode,
+};
+
+static struct regulator_ops wm8350_dcdc2_5_ops = {
+	.enable = wm8350_dcdc_enable,
+	.disable = wm8350_dcdc_disable,
+	.is_enabled = wm8350_dcdc_is_enabled,
+	.set_suspend_enable = wm8350_dcdc25_set_suspend_enable,
+	.set_suspend_disable = wm8350_dcdc25_set_suspend_disable,
+};
+
+static struct regulator_ops wm8350_ldo_ops = {
+	.set_voltage = wm8350_ldo_set_voltage,
+	.get_voltage = wm8350_ldo_get_voltage,
+	.enable = wm8350_ldo_enable,
+	.disable = wm8350_ldo_disable,
+	.is_enabled = wm8350_ldo_is_enabled,
+	.get_mode = wm8350_ldo_get_mode,
+	.set_suspend_voltage = wm8350_ldo_set_suspend_voltage,
+	.set_suspend_enable = wm8350_ldo_set_suspend_enable,
+	.set_suspend_disable = wm8350_ldo_set_suspend_disable,
+};
+
+static struct regulator_ops wm8350_isink_ops = {
+	.set_current_limit = wm8350_isink_set_current,
+	.get_current_limit = wm8350_isink_get_current,
+	.enable = wm8350_isink_enable,
+	.disable = wm8350_isink_disable,
+	.is_enabled = wm8350_isink_is_enabled,
+};
+
+static struct regulator_desc wm8350_reg[NUM_WM8350_REGULATORS] = {
+	{
+		.name = "DCDC1",
+		.id = WM8350_DCDC_1,
+		.ops = &wm8350_dcdc_ops,
+		.irq = WM8350_IRQ_UV_DC1,
+		.type = REGULATOR_VOLTAGE,
+		.owner = THIS_MODULE,
+	},
+	{
+		.name = "DCDC2",
+		.id = WM8350_DCDC_2,
+		.ops = &wm8350_dcdc2_5_ops,
+		.irq = WM8350_IRQ_UV_DC2,
+		.type = REGULATOR_VOLTAGE,
+		.owner = THIS_MODULE,
+	},
+	{
+		.name = "DCDC3",
+		.id = WM8350_DCDC_3,
+		.ops = &wm8350_dcdc_ops,
+		.irq = WM8350_IRQ_UV_DC3,
+		.type = REGULATOR_VOLTAGE,
+		.owner = THIS_MODULE,
+	},
+	{
+		.name = "DCDC4",
+		.id = WM8350_DCDC_4,
+		.ops = &wm8350_dcdc_ops,
+		.irq = WM8350_IRQ_UV_DC4,
+		.type = REGULATOR_VOLTAGE,
+		.owner = THIS_MODULE,
+	},
+	{
+		.name = "DCDC5",
+		.id = WM8350_DCDC_5,
+		.ops = &wm8350_dcdc2_5_ops,
+		.irq = WM8350_IRQ_UV_DC5,
+		.type = REGULATOR_VOLTAGE,
+		.owner = THIS_MODULE,
+	 },
+	{
+		.name = "DCDC6",
+		.id = WM8350_DCDC_6,
+		.ops = &wm8350_dcdc_ops,
+		.irq = WM8350_IRQ_UV_DC6,
+		.type = REGULATOR_VOLTAGE,
+		.owner = THIS_MODULE,
+	},
+	{
+		.name = "LDO1",
+		.id = WM8350_LDO_1,
+		.ops = &wm8350_ldo_ops,
+		.irq = WM8350_IRQ_UV_LDO1,
+		.type = REGULATOR_VOLTAGE,
+		.owner = THIS_MODULE,
+	},
+	{
+		.name = "LDO2",
+		.id = WM8350_LDO_2,
+		.ops = &wm8350_ldo_ops,
+		.irq = WM8350_IRQ_UV_LDO2,
+		.type = REGULATOR_VOLTAGE,
+		.owner = THIS_MODULE,
+	},
+	{
+		.name = "LDO3",
+		.id = WM8350_LDO_3,
+		.ops = &wm8350_ldo_ops,
+		.irq = WM8350_IRQ_UV_LDO3,
+		.type = REGULATOR_VOLTAGE,
+		.owner = THIS_MODULE,
+	},
+	{
+		.name = "LDO4",
+		.id = WM8350_LDO_4,
+		.ops = &wm8350_ldo_ops,
+		.irq = WM8350_IRQ_UV_LDO4,
+		.type = REGULATOR_VOLTAGE,
+		.owner = THIS_MODULE,
+	},
+	{
+		.name = "ISINKA",
+		.id = WM8350_ISINK_A,
+		.ops = &wm8350_isink_ops,
+		.irq = WM8350_IRQ_CS1,
+		.type = REGULATOR_CURRENT,
+		.owner = THIS_MODULE,
+	 },
+	{
+		.name = "ISINKB",
+		.id = WM8350_ISINK_B,
+		.ops = &wm8350_isink_ops,
+		.irq = WM8350_IRQ_CS2,
+		.type = REGULATOR_CURRENT,
+		.owner = THIS_MODULE,
+	 },
+};
+
+static void pmic_uv_handler(struct wm8350 *wm8350, int irq, void *data)
+{
+	struct regulator_dev *rdev = (struct regulator_dev *)data;
+
+	if (irq == WM8350_IRQ_CS1 || irq == WM8350_IRQ_CS2)
+		regulator_notifier_call_chain(rdev,
+					      REGULATOR_EVENT_REGULATION_OUT,
+					      wm8350);
+	else
+		regulator_notifier_call_chain(rdev,
+					      REGULATOR_EVENT_UNDER_VOLTAGE,
+					      wm8350);
+}
+
+static int wm8350_regulator_probe(struct platform_device *pdev)
+{
+	struct wm8350 *wm8350 = dev_get_drvdata(&pdev->dev);
+	struct regulator_dev *rdev;
+	int ret;
+	u16 val;
+
+	if (pdev->id < WM8350_DCDC_1 || pdev->id > WM8350_ISINK_B)
+		return -ENODEV;
+
+	/* do any regulatior specific init */
+	switch (pdev->id) {
+	case WM8350_DCDC_1:
+		val = wm8350_reg_read(wm8350, WM8350_DCDC1_LOW_POWER);
+		wm8350->pmic.dcdc1_hib_mode = val & WM8350_DCDC_HIB_MODE_MASK;
+		break;
+	case WM8350_DCDC_3:
+		val = wm8350_reg_read(wm8350, WM8350_DCDC3_LOW_POWER);
+		wm8350->pmic.dcdc3_hib_mode = val & WM8350_DCDC_HIB_MODE_MASK;
+		break;
+	case WM8350_DCDC_4:
+		val = wm8350_reg_read(wm8350, WM8350_DCDC4_LOW_POWER);
+		wm8350->pmic.dcdc4_hib_mode = val & WM8350_DCDC_HIB_MODE_MASK;
+		break;
+	case WM8350_DCDC_6:
+		val = wm8350_reg_read(wm8350, WM8350_DCDC6_LOW_POWER);
+		wm8350->pmic.dcdc6_hib_mode = val & WM8350_DCDC_HIB_MODE_MASK;
+		break;
+	}
+
+
+	/* register regulator */
+	rdev = regulator_register(&wm8350_reg[pdev->id], &pdev->dev,
+				  dev_get_drvdata(&pdev->dev));
+	if (IS_ERR(rdev)) {
+		dev_err(&pdev->dev, "failed to register %s\n",
+			wm8350_reg[pdev->id].name);
+		return PTR_ERR(rdev);
+	}
+
+	/* register regulator IRQ */
+	ret = wm8350_register_irq(wm8350, wm8350_reg[pdev->id].irq,
+				  pmic_uv_handler, rdev);
+	if (ret < 0) {
+		regulator_unregister(rdev);
+		dev_err(&pdev->dev, "failed to register regulator %s IRQ\n",
+			wm8350_reg[pdev->id].name);
+		return ret;
+	}
+
+	wm8350_unmask_irq(wm8350, wm8350_reg[pdev->id].irq);
+
+	return 0;
+}
+
+static int wm8350_regulator_remove(struct platform_device *pdev)
+{
+	struct regulator_dev *rdev = platform_get_drvdata(pdev);
+	struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+
+	wm8350_mask_irq(wm8350, wm8350_reg[pdev->id].irq);
+	wm8350_free_irq(wm8350, wm8350_reg[pdev->id].irq);
+
+	regulator_unregister(rdev);
+
+	return 0;
+}
+
+int wm8350_register_regulator(struct wm8350 *wm8350, int reg,
+			      struct regulator_init_data *initdata)
+{
+	struct platform_device *pdev;
+	int ret;
+
+	if (wm8350->pmic.pdev[reg])
+		return -EBUSY;
+
+	pdev = platform_device_alloc("wm8350-regulator", reg);
+	if (!pdev)
+		return -ENOMEM;
+
+	wm8350->pmic.pdev[reg] = pdev;
+
+	initdata->driver_data = wm8350;
+
+	pdev->dev.platform_data = initdata;
+	pdev->dev.parent = wm8350->dev;
+	platform_set_drvdata(pdev, wm8350);
+
+	ret = platform_device_add(pdev);
+
+	if (ret != 0) {
+		dev_err(wm8350->dev, "Failed to register regulator %d: %d\n",
+			reg, ret);
+		platform_device_del(pdev);
+		wm8350->pmic.pdev[reg] = NULL;
+	}
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(wm8350_register_regulator);
+
+static struct platform_driver wm8350_regulator_driver = {
+	.probe = wm8350_regulator_probe,
+	.remove = wm8350_regulator_remove,
+	.driver		= {
+		.name	= "wm8350-regulator",
+	},
+};
+
+static int __init wm8350_regulator_init(void)
+{
+	return platform_driver_register(&wm8350_regulator_driver);
+}
+subsys_initcall(wm8350_regulator_init);
+
+static void __exit wm8350_regulator_exit(void)
+{
+	platform_driver_unregister(&wm8350_regulator_driver);
+}
+module_exit(wm8350_regulator_exit);
+
+/* Module information */
+MODULE_AUTHOR("Liam Girdwood");
+MODULE_DESCRIPTION("WM8350 voltage and current regulator driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/regulator/wm8400-regulator.c b/drivers/regulator/wm8400-regulator.c
new file mode 100644
index 0000000..48b372e
--- /dev/null
+++ b/drivers/regulator/wm8400-regulator.c
@@ -0,0 +1,368 @@
+/*
+ * Regulator support for WM8400
+ *
+ * Copyright 2008 Wolfson Microelectronics PLC.
+ *
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.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/bug.h>
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/regulator/driver.h>
+#include <linux/mfd/wm8400-private.h>
+
+static int wm8400_ldo_is_enabled(struct regulator_dev *dev)
+{
+	struct wm8400 *wm8400 = rdev_get_drvdata(dev);
+	u16 val;
+
+	val = wm8400_reg_read(wm8400, WM8400_LDO1_CONTROL + rdev_get_id(dev));
+	return (val & WM8400_LDO1_ENA) != 0;
+}
+
+static int wm8400_ldo_enable(struct regulator_dev *dev)
+{
+	struct wm8400 *wm8400 = rdev_get_drvdata(dev);
+
+	return wm8400_set_bits(wm8400, WM8400_LDO1_CONTROL + rdev_get_id(dev),
+			       WM8400_LDO1_ENA, WM8400_LDO1_ENA);
+}
+
+static int wm8400_ldo_disable(struct regulator_dev *dev)
+{
+	struct wm8400 *wm8400 = rdev_get_drvdata(dev);
+
+	return wm8400_set_bits(wm8400, WM8400_LDO1_CONTROL + rdev_get_id(dev),
+			       WM8400_LDO1_ENA, 0);
+}
+
+static int wm8400_ldo_get_voltage(struct regulator_dev *dev)
+{
+	struct wm8400 *wm8400 = rdev_get_drvdata(dev);
+	u16 val;
+
+	val = wm8400_reg_read(wm8400, WM8400_LDO1_CONTROL + rdev_get_id(dev));
+	val &= WM8400_LDO1_VSEL_MASK;
+
+	if (val < 15)
+		return 900000 + (val * 50000);
+	else
+		return 1600000 + ((val - 14) * 100000);
+}
+
+static int wm8400_ldo_set_voltage(struct regulator_dev *dev,
+				  int min_uV, int max_uV)
+{
+	struct wm8400 *wm8400 = rdev_get_drvdata(dev);
+	u16 val;
+
+	if (min_uV < 900000 || min_uV > 3300000)
+		return -EINVAL;
+
+	if (min_uV < 1700000) {
+		/* Steps of 50mV from 900mV;  */
+		val = (min_uV - 850001) / 50000;
+
+		if ((val * 50000) + 900000 > max_uV)
+			return -EINVAL;
+		BUG_ON((val * 50000) + 900000 < min_uV);
+	} else {
+		/* Steps of 100mV from 1700mV */
+		val = ((min_uV - 1600001) / 100000);
+
+		if ((val * 100000) + 1700000 > max_uV)
+			return -EINVAL;
+		BUG_ON((val * 100000) + 1700000 < min_uV);
+
+		val += 0xf;
+	}
+
+	return wm8400_set_bits(wm8400, WM8400_LDO1_CONTROL + rdev_get_id(dev),
+			       WM8400_LDO1_VSEL_MASK, val);
+}
+
+static struct regulator_ops wm8400_ldo_ops = {
+	.is_enabled = wm8400_ldo_is_enabled,
+	.enable = wm8400_ldo_enable,
+	.disable = wm8400_ldo_disable,
+	.get_voltage = wm8400_ldo_get_voltage,
+	.set_voltage = wm8400_ldo_set_voltage,
+};
+
+static int wm8400_dcdc_is_enabled(struct regulator_dev *dev)
+{
+	struct wm8400 *wm8400 = rdev_get_drvdata(dev);
+	int offset = (rdev_get_id(dev) - WM8400_DCDC1) * 2;
+	u16 val;
+
+	val = wm8400_reg_read(wm8400, WM8400_DCDC1_CONTROL_1 + offset);
+	return (val & WM8400_DC1_ENA) != 0;
+}
+
+static int wm8400_dcdc_enable(struct regulator_dev *dev)
+{
+	struct wm8400 *wm8400 = rdev_get_drvdata(dev);
+	int offset = (rdev_get_id(dev) - WM8400_DCDC1) * 2;
+
+	return wm8400_set_bits(wm8400, WM8400_DCDC1_CONTROL_1 + offset,
+			       WM8400_DC1_ENA, WM8400_DC1_ENA);
+}
+
+static int wm8400_dcdc_disable(struct regulator_dev *dev)
+{
+	struct wm8400 *wm8400 = rdev_get_drvdata(dev);
+	int offset = (rdev_get_id(dev) - WM8400_DCDC1) * 2;
+
+	return wm8400_set_bits(wm8400, WM8400_DCDC1_CONTROL_1 + offset,
+			       WM8400_DC1_ENA, 0);
+}
+
+static int wm8400_dcdc_get_voltage(struct regulator_dev *dev)
+{
+	struct wm8400 *wm8400 = rdev_get_drvdata(dev);
+	u16 val;
+	int offset = (rdev_get_id(dev) - WM8400_DCDC1) * 2;
+
+	val = wm8400_reg_read(wm8400, WM8400_DCDC1_CONTROL_1 + offset);
+	val &= WM8400_DC1_VSEL_MASK;
+
+	return 850000 + (25000 * val);
+}
+
+static int wm8400_dcdc_set_voltage(struct regulator_dev *dev,
+				  int min_uV, int max_uV)
+{
+	struct wm8400 *wm8400 = rdev_get_drvdata(dev);
+	u16 val;
+	int offset = (rdev_get_id(dev) - WM8400_DCDC1) * 2;
+
+	if (min_uV < 850000)
+		return -EINVAL;
+
+	val = (min_uV - 825001) / 25000;
+
+	if (850000 + (25000 * val) > max_uV)
+		return -EINVAL;
+	BUG_ON(850000 + (25000 * val) < min_uV);
+
+	return wm8400_set_bits(wm8400, WM8400_DCDC1_CONTROL_1 + offset,
+			       WM8400_DC1_VSEL_MASK, val);
+}
+
+static unsigned int wm8400_dcdc_get_mode(struct regulator_dev *dev)
+{
+	struct wm8400 *wm8400 = rdev_get_drvdata(dev);
+	int offset = (rdev_get_id(dev) - WM8400_DCDC1) * 2;
+	u16 data[2];
+	int ret;
+
+	ret = wm8400_block_read(wm8400, WM8400_DCDC1_CONTROL_1 + offset, 2,
+				data);
+	if (ret != 0)
+		return 0;
+
+	/* Datasheet: hibernate */
+	if (data[0] & WM8400_DC1_SLEEP)
+		return REGULATOR_MODE_STANDBY;
+
+	/* Datasheet: standby */
+	if (!(data[0] & WM8400_DC1_ACTIVE))
+		return REGULATOR_MODE_IDLE;
+
+	/* Datasheet: active with or without force PWM */
+	if (data[1] & WM8400_DC1_FRC_PWM)
+		return REGULATOR_MODE_FAST;
+	else
+		return REGULATOR_MODE_NORMAL;
+}
+
+static int wm8400_dcdc_set_mode(struct regulator_dev *dev, unsigned int mode)
+{
+	struct wm8400 *wm8400 = rdev_get_drvdata(dev);
+	int offset = (rdev_get_id(dev) - WM8400_DCDC1) * 2;
+	int ret;
+
+	switch (mode) {
+	case REGULATOR_MODE_FAST:
+		/* Datasheet: active with force PWM */
+		ret = wm8400_set_bits(wm8400, WM8400_DCDC1_CONTROL_2 + offset,
+				      WM8400_DC1_FRC_PWM, WM8400_DC1_FRC_PWM);
+		if (ret != 0)
+			return ret;
+
+		return wm8400_set_bits(wm8400, WM8400_DCDC1_CONTROL_1 + offset,
+				       WM8400_DC1_ACTIVE | WM8400_DC1_SLEEP,
+				       WM8400_DC1_ACTIVE);
+
+	case REGULATOR_MODE_NORMAL:
+		/* Datasheet: active */
+		ret = wm8400_set_bits(wm8400, WM8400_DCDC1_CONTROL_2 + offset,
+				      WM8400_DC1_FRC_PWM, 0);
+		if (ret != 0)
+			return ret;
+
+		return wm8400_set_bits(wm8400, WM8400_DCDC1_CONTROL_1 + offset,
+				       WM8400_DC1_ACTIVE | WM8400_DC1_SLEEP,
+				       WM8400_DC1_ACTIVE);
+
+	case REGULATOR_MODE_IDLE:
+		/* Datasheet: standby */
+		ret = wm8400_set_bits(wm8400, WM8400_DCDC1_CONTROL_1 + offset,
+				      WM8400_DC1_ACTIVE, 0);
+		if (ret != 0)
+			return ret;
+		return wm8400_set_bits(wm8400, WM8400_DCDC1_CONTROL_1 + offset,
+				       WM8400_DC1_SLEEP, 0);
+
+	default:
+		return -EINVAL;
+	}
+}
+
+static unsigned int wm8400_dcdc_get_optimum_mode(struct regulator_dev *dev,
+						 int input_uV, int output_uV,
+						 int load_uA)
+{
+	return REGULATOR_MODE_NORMAL;
+}
+
+static struct regulator_ops wm8400_dcdc_ops = {
+	.is_enabled = wm8400_dcdc_is_enabled,
+	.enable = wm8400_dcdc_enable,
+	.disable = wm8400_dcdc_disable,
+	.get_voltage = wm8400_dcdc_get_voltage,
+	.set_voltage = wm8400_dcdc_set_voltage,
+	.get_mode = wm8400_dcdc_get_mode,
+	.set_mode = wm8400_dcdc_set_mode,
+	.get_optimum_mode = wm8400_dcdc_get_optimum_mode,
+};
+
+static struct regulator_desc regulators[] = {
+	{
+		.name = "LDO1",
+		.id = WM8400_LDO1,
+		.ops = &wm8400_ldo_ops,
+		.type = REGULATOR_VOLTAGE,
+		.owner = THIS_MODULE,
+	},
+	{
+		.name = "LDO2",
+		.id = WM8400_LDO2,
+		.ops = &wm8400_ldo_ops,
+		.type = REGULATOR_VOLTAGE,
+		.owner = THIS_MODULE,
+	},
+	{
+		.name = "LDO3",
+		.id = WM8400_LDO3,
+		.ops = &wm8400_ldo_ops,
+		.type = REGULATOR_VOLTAGE,
+		.owner = THIS_MODULE,
+	},
+	{
+		.name = "LDO4",
+		.id = WM8400_LDO4,
+		.ops = &wm8400_ldo_ops,
+		.type = REGULATOR_VOLTAGE,
+		.owner = THIS_MODULE,
+	},
+	{
+		.name = "DCDC1",
+		.id = WM8400_DCDC1,
+		.ops = &wm8400_dcdc_ops,
+		.type = REGULATOR_VOLTAGE,
+		.owner = THIS_MODULE,
+	},
+	{
+		.name = "DCDC2",
+		.id = WM8400_DCDC2,
+		.ops = &wm8400_dcdc_ops,
+		.type = REGULATOR_VOLTAGE,
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init wm8400_regulator_probe(struct platform_device *pdev)
+{
+	struct regulator_dev *rdev;
+
+	rdev = regulator_register(&regulators[pdev->id], &pdev->dev,
+		pdev->dev.driver_data);
+
+	if (IS_ERR(rdev))
+		return PTR_ERR(rdev);
+
+	return 0;
+}
+
+static int __devexit wm8400_regulator_remove(struct platform_device *pdev)
+{
+	struct regulator_dev *rdev = platform_get_drvdata(pdev);
+
+	regulator_unregister(rdev);
+
+	return 0;
+}
+
+static struct platform_driver wm8400_regulator_driver = {
+	.driver = {
+		.name = "wm8400-regulator",
+	},
+	.probe = wm8400_regulator_probe,
+	.remove = __devexit_p(wm8400_regulator_remove),
+};
+
+/**
+ * wm8400_register_regulator - enable software control of a WM8400 regulator
+ *
+ * This function enables software control of a WM8400 regulator via
+ * the regulator API.  It is intended to be called from the
+ * platform_init() callback of the WM8400 MFD driver.
+ *
+ * @param dev      The WM8400 device to operate on.
+ * @param reg      The regulator to control.
+ * @param initdata Regulator initdata for the regulator.
+ */
+int wm8400_register_regulator(struct device *dev, int reg,
+			      struct regulator_init_data *initdata)
+{
+	struct wm8400 *wm8400 = dev->driver_data;
+
+	if (wm8400->regulators[reg].name)
+		return -EBUSY;
+
+	initdata->driver_data = wm8400;
+
+	wm8400->regulators[reg].name = "wm8400-regulator";
+	wm8400->regulators[reg].id = reg;
+	wm8400->regulators[reg].dev.parent = dev;
+	wm8400->regulators[reg].dev.driver_data = wm8400;
+	wm8400->regulators[reg].dev.platform_data = initdata;
+
+	return platform_device_register(&wm8400->regulators[reg]);
+}
+EXPORT_SYMBOL_GPL(wm8400_register_regulator);
+
+static int __init wm8400_regulator_init(void)
+{
+	return platform_driver_register(&wm8400_regulator_driver);
+}
+module_init(wm8400_regulator_init);
+
+static void __exit wm8400_regulator_exit(void)
+{
+	platform_driver_unregister(&wm8400_regulator_driver);
+}
+module_exit(wm8400_regulator_exit);
+
+MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
+MODULE_DESCRIPTION("WM8400 regulator driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:wm8400-regulator");
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 9a9755c..b57fba5 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -329,7 +329,7 @@
 
 config RTC_DRV_CMOS
 	tristate "PC-style 'CMOS'"
-	depends on X86 || ALPHA || ARM || M32R || ATARI || PPC || MIPS
+	depends on X86 || ALPHA || ARM || M32R || ATARI || PPC || MIPS || SPARC64
 	default y if X86
 	help
 	  Say "yes" here to get direct support for the real time clock
@@ -406,14 +406,26 @@
 	  will be called rtc-m48t86.
 
 config RTC_DRV_M48T59
-	tristate "ST M48T59"
+	tristate "ST M48T59/M48T08/M48T02"
 	help
 	  If you say Y here you will get support for the
-	  ST M48T59 RTC chip.
+	  ST M48T59 RTC chip and compatible ST M48T08 and M48T02.
+
+	  These chips are usually found in Sun SPARC and UltraSPARC
+	  workstations.
 
 	  This driver can also be built as a module, if so, the module
 	  will be called "rtc-m48t59".
 
+config RTC_DRV_BQ4802
+	tristate "TI BQ4802"
+	help
+	  If you say Y here you will get support for the TI
+	  BQ4802 RTC chip.
+
+	  This driver can also be built as a module. If so, the module
+	  will be called rtc-bq4802.
+
 config RTC_DRV_V3020
 	tristate "EM Microelectronic V3020"
 	help
@@ -583,4 +595,18 @@
 	 the RTC. This exposes that functionality through the generic RTC
 	 class.
 
+config RTC_DRV_SUN4V
+	bool "SUN4V Hypervisor RTC"
+	depends on SPARC64
+	help
+	  If you say Y here you will get support for the Hypervisor
+	  based RTC on SUN4V systems.
+
+config RTC_DRV_STARFIRE
+	bool "Starfire RTC"
+	depends on SPARC64
+	help
+	  If you say Y here you will get support for the RTC found on
+	  Starfire systems.
+
 endif # RTC_CLASS
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index 18622ef..10f41f8 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -38,6 +38,9 @@
 obj-$(CONFIG_RTC_DRV_M41T94)	+= rtc-m41t94.o
 obj-$(CONFIG_RTC_DRV_M48T59)	+= rtc-m48t59.o
 obj-$(CONFIG_RTC_DRV_M48T86)	+= rtc-m48t86.o
+obj-$(CONFIG_RTC_DRV_BQ4802)	+= rtc-bq4802.o
+obj-$(CONFIG_RTC_DRV_SUN4V)	+= rtc-sun4v.o
+obj-$(CONFIG_RTC_DRV_STARFIRE)	+= rtc-starfire.o
 obj-$(CONFIG_RTC_DRV_MAX6900)	+= rtc-max6900.o
 obj-$(CONFIG_RTC_DRV_MAX6902)	+= rtc-max6902.o
 obj-$(CONFIG_RTC_DRV_OMAP)	+= rtc-omap.o
diff --git a/drivers/rtc/rtc-bq4802.c b/drivers/rtc/rtc-bq4802.c
new file mode 100644
index 0000000..189a018
--- /dev/null
+++ b/drivers/rtc/rtc-bq4802.c
@@ -0,0 +1,230 @@
+/* rtc-bq4802.c: TI BQ4802 RTC driver.
+ *
+ * Copyright (C) 2008 David S. Miller <davem@davemloft.net>
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/rtc.h>
+#include <linux/bcd.h>
+
+MODULE_AUTHOR("David S. Miller <davem@davemloft.net>");
+MODULE_DESCRIPTION("TI BQ4802 RTC driver");
+MODULE_LICENSE("GPL");
+
+struct bq4802 {
+	void __iomem		*regs;
+	unsigned long		ioport;
+	struct rtc_device	*rtc;
+	spinlock_t		lock;
+	struct resource		*r;
+	u8 (*read)(struct bq4802 *, int);
+	void (*write)(struct bq4802 *, int, u8);
+};
+
+static u8 bq4802_read_io(struct bq4802 *p, int off)
+{
+	return inb(p->ioport + off);
+}
+
+static void bq4802_write_io(struct bq4802 *p, int off, u8 val)
+{
+	outb(val, p->ioport + off);
+}
+
+static u8 bq4802_read_mem(struct bq4802 *p, int off)
+{
+	return readb(p->regs + off);
+}
+
+static void bq4802_write_mem(struct bq4802 *p, int off, u8 val)
+{
+	writeb(val, p->regs + off);
+}
+
+static int bq4802_read_time(struct device *dev, struct rtc_time *tm)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct bq4802 *p = platform_get_drvdata(pdev);
+	unsigned long flags;
+	unsigned int century;
+	u8 val;
+
+	spin_lock_irqsave(&p->lock, flags);
+
+	val = p->read(p, 0x0e);
+	p->write(p, 0xe, val | 0x08);
+
+	tm->tm_sec = p->read(p, 0x00);
+	tm->tm_min = p->read(p, 0x02);
+	tm->tm_hour = p->read(p, 0x04);
+	tm->tm_mday = p->read(p, 0x06);
+	tm->tm_mon = p->read(p, 0x09);
+	tm->tm_year = p->read(p, 0x0a);
+	tm->tm_wday = p->read(p, 0x08);
+	century = p->read(p, 0x0f);
+
+	p->write(p, 0x0e, val);
+
+	spin_unlock_irqrestore(&p->lock, flags);
+
+	BCD_TO_BIN(tm->tm_sec);
+	BCD_TO_BIN(tm->tm_min);
+	BCD_TO_BIN(tm->tm_hour);
+	BCD_TO_BIN(tm->tm_mday);
+	BCD_TO_BIN(tm->tm_mon);
+	BCD_TO_BIN(tm->tm_year);
+	BCD_TO_BIN(tm->tm_wday);
+	BCD_TO_BIN(century);
+
+	tm->tm_year += (century * 100);
+	tm->tm_year -= 1900;
+
+	tm->tm_mon--;
+
+	return 0;
+}
+
+static int bq4802_set_time(struct device *dev, struct rtc_time *tm)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct bq4802 *p = platform_get_drvdata(pdev);
+	u8 sec, min, hrs, day, mon, yrs, century, val;
+	unsigned long flags;
+	unsigned int year;
+
+	year = tm->tm_year + 1900;
+	century = year / 100;
+	yrs = year % 100;
+
+	mon = tm->tm_mon + 1;   /* tm_mon starts at zero */
+	day = tm->tm_mday;
+	hrs = tm->tm_hour;
+	min = tm->tm_min;
+	sec = tm->tm_sec;
+
+	BIN_TO_BCD(sec);
+	BIN_TO_BCD(min);
+	BIN_TO_BCD(hrs);
+	BIN_TO_BCD(day);
+	BIN_TO_BCD(mon);
+	BIN_TO_BCD(yrs);
+	BIN_TO_BCD(century);
+
+	spin_lock_irqsave(&p->lock, flags);
+
+	val = p->read(p, 0x0e);
+	p->write(p, 0x0e, val | 0x08);
+
+	p->write(p, 0x00, sec);
+	p->write(p, 0x02, min);
+	p->write(p, 0x04, hrs);
+	p->write(p, 0x06, day);
+	p->write(p, 0x09, mon);
+	p->write(p, 0x0a, yrs);
+	p->write(p, 0x0f, century);
+
+	p->write(p, 0x0e, val);
+
+	spin_unlock_irqrestore(&p->lock, flags);
+
+	return 0;
+}
+
+static const struct rtc_class_ops bq4802_ops = {
+	.read_time	= bq4802_read_time,
+	.set_time	= bq4802_set_time,
+};
+
+static int __devinit bq4802_probe(struct platform_device *pdev)
+{
+	struct bq4802 *p = kzalloc(sizeof(*p), GFP_KERNEL);
+	int err = -ENOMEM;
+
+	if (!p)
+		goto out;
+
+	spin_lock_init(&p->lock);
+
+	p->r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!p->r) {
+		p->r = platform_get_resource(pdev, IORESOURCE_IO, 0);
+		err = -EINVAL;
+		if (!p->r)
+			goto out_free;
+	}
+	if (p->r->flags & IORESOURCE_IO) {
+		p->ioport = p->r->start;
+		p->read = bq4802_read_io;
+		p->write = bq4802_write_io;
+	} else if (p->r->flags & IORESOURCE_MEM) {
+		p->regs = ioremap(p->r->start, resource_size(p->r));
+		p->read = bq4802_read_mem;
+		p->write = bq4802_write_mem;
+	} else {
+		err = -EINVAL;
+		goto out_free;
+	}
+
+	p->rtc = rtc_device_register("bq4802", &pdev->dev,
+				     &bq4802_ops, THIS_MODULE);
+	if (IS_ERR(p->rtc)) {
+		err = PTR_ERR(p->rtc);
+		goto out_iounmap;
+	}
+
+	platform_set_drvdata(pdev, p);
+	err = 0;
+out:
+	return err;
+
+out_iounmap:
+	if (p->r->flags & IORESOURCE_MEM)
+		iounmap(p->regs);
+out_free:
+	kfree(p);
+	goto out;
+}
+
+static int __devexit bq4802_remove(struct platform_device *pdev)
+{
+	struct bq4802 *p = platform_get_drvdata(pdev);
+
+	rtc_device_unregister(p->rtc);
+	if (p->r->flags & IORESOURCE_MEM)
+		iounmap(p->regs);
+
+	platform_set_drvdata(pdev, NULL);
+
+	kfree(p);
+
+	return 0;
+}
+
+/* work with hotplug and coldplug */
+MODULE_ALIAS("platform:rtc-bq4802");
+
+static struct platform_driver bq4802_driver = {
+	.driver		= {
+		.name	= "rtc-bq4802",
+		.owner	= THIS_MODULE,
+	},
+	.probe		= bq4802_probe,
+	.remove		= __devexit_p(bq4802_remove),
+};
+
+static int __init bq4802_init(void)
+{
+	return platform_driver_register(&bq4802_driver);
+}
+
+static void __exit bq4802_exit(void)
+{
+	platform_driver_unregister(&bq4802_driver);
+}
+
+module_init(bq4802_init);
+module_exit(bq4802_exit);
diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c
index b184367..963ad0b 100644
--- a/drivers/rtc/rtc-cmos.c
+++ b/drivers/rtc/rtc-cmos.c
@@ -636,7 +636,7 @@
 	 */
 #if	defined(CONFIG_ATARI)
 	address_space = 64;
-#elif defined(__i386__) || defined(__x86_64__) || defined(__arm__)
+#elif defined(__i386__) || defined(__x86_64__) || defined(__arm__) || defined(__sparc__)
 	address_space = 128;
 #else
 #warning Assuming 128 bytes of RTC+NVRAM address space, not 64 bytes.
@@ -699,7 +699,8 @@
 	/* FIXME teach the alarm code how to handle binary mode;
 	 * <asm-generic/rtc.h> doesn't know 12-hour mode either.
 	 */
-	if (!(rtc_control & RTC_24H) || (rtc_control & (RTC_DM_BINARY))) {
+	if (is_valid_irq(rtc_irq) &&
+	    (!(rtc_control & RTC_24H) || (rtc_control & (RTC_DM_BINARY)))) {
 		dev_dbg(dev, "only 24-hr BCD mode supported\n");
 		retval = -ENXIO;
 		goto cleanup1;
@@ -912,6 +913,92 @@
  * predate even PNPBIOS should set up platform_bus devices.
  */
 
+#ifdef	CONFIG_ACPI
+
+#include <linux/acpi.h>
+
+#ifdef	CONFIG_PM
+static u32 rtc_handler(void *context)
+{
+	acpi_clear_event(ACPI_EVENT_RTC);
+	acpi_disable_event(ACPI_EVENT_RTC, 0);
+	return ACPI_INTERRUPT_HANDLED;
+}
+
+static inline void rtc_wake_setup(void)
+{
+	acpi_install_fixed_event_handler(ACPI_EVENT_RTC, rtc_handler, NULL);
+	/*
+	 * After the RTC handler is installed, the Fixed_RTC event should
+	 * be disabled. Only when the RTC alarm is set will it be enabled.
+	 */
+	acpi_clear_event(ACPI_EVENT_RTC);
+	acpi_disable_event(ACPI_EVENT_RTC, 0);
+}
+
+static void rtc_wake_on(struct device *dev)
+{
+	acpi_clear_event(ACPI_EVENT_RTC);
+	acpi_enable_event(ACPI_EVENT_RTC, 0);
+}
+
+static void rtc_wake_off(struct device *dev)
+{
+	acpi_disable_event(ACPI_EVENT_RTC, 0);
+}
+#else
+#define rtc_wake_setup()	do{}while(0)
+#define rtc_wake_on		NULL
+#define rtc_wake_off		NULL
+#endif
+
+/* Every ACPI platform has a mc146818 compatible "cmos rtc".  Here we find
+ * its device node and pass extra config data.  This helps its driver use
+ * capabilities that the now-obsolete mc146818 didn't have, and informs it
+ * that this board's RTC is wakeup-capable (per ACPI spec).
+ */
+static struct cmos_rtc_board_info acpi_rtc_info;
+
+static void __devinit
+cmos_wake_setup(struct device *dev)
+{
+	if (acpi_disabled)
+		return;
+
+	rtc_wake_setup();
+	acpi_rtc_info.wake_on = rtc_wake_on;
+	acpi_rtc_info.wake_off = rtc_wake_off;
+
+	/* workaround bug in some ACPI tables */
+	if (acpi_gbl_FADT.month_alarm && !acpi_gbl_FADT.day_alarm) {
+		dev_dbg(dev, "bogus FADT month_alarm (%d)\n",
+			acpi_gbl_FADT.month_alarm);
+		acpi_gbl_FADT.month_alarm = 0;
+	}
+
+	acpi_rtc_info.rtc_day_alarm = acpi_gbl_FADT.day_alarm;
+	acpi_rtc_info.rtc_mon_alarm = acpi_gbl_FADT.month_alarm;
+	acpi_rtc_info.rtc_century = acpi_gbl_FADT.century;
+
+	/* NOTE:  S4_RTC_WAKE is NOT currently useful to Linux */
+	if (acpi_gbl_FADT.flags & ACPI_FADT_S4_RTC_WAKE)
+		dev_info(dev, "RTC can wake from S4\n");
+
+	dev->platform_data = &acpi_rtc_info;
+
+	/* RTC always wakes from S1/S2/S3, and often S4/STD */
+	device_init_wakeup(dev, 1);
+}
+
+#else
+
+static void __devinit
+cmos_wake_setup(struct device *dev)
+{
+}
+
+#endif
+
 #ifdef	CONFIG_PNP
 
 #include <linux/pnp.h>
@@ -919,6 +1006,8 @@
 static int __devinit
 cmos_pnp_probe(struct pnp_dev *pnp, const struct pnp_device_id *id)
 {
+	cmos_wake_setup(&pnp->dev);
+
 	if (pnp_port_start(pnp,0) == 0x70 && !pnp_irq_valid(pnp,0))
 		/* Some machines contain a PNP entry for the RTC, but
 		 * don't define the IRQ. It should always be safe to
@@ -996,6 +1085,7 @@
 
 static int __init cmos_platform_probe(struct platform_device *pdev)
 {
+	cmos_wake_setup(&pdev->dev);
 	return cmos_do_probe(&pdev->dev,
 			platform_get_resource(pdev, IORESOURCE_IO, 0),
 			platform_get_irq(pdev, 0));
@@ -1030,29 +1120,32 @@
 
 static int __init cmos_init(void)
 {
+	int retval = 0;
+
 #ifdef	CONFIG_PNP
-	if (pnp_platform_devices)
-		return pnp_register_driver(&cmos_pnp_driver);
-	else
-		return platform_driver_probe(&cmos_platform_driver,
-			cmos_platform_probe);
-#else
-	return platform_driver_probe(&cmos_platform_driver,
-			cmos_platform_probe);
-#endif /* CONFIG_PNP */
+	pnp_register_driver(&cmos_pnp_driver);
+#endif
+
+	if (!cmos_rtc.dev)
+		retval = platform_driver_probe(&cmos_platform_driver,
+					       cmos_platform_probe);
+
+	if (retval == 0)
+		return 0;
+
+#ifdef	CONFIG_PNP
+	pnp_unregister_driver(&cmos_pnp_driver);
+#endif
+	return retval;
 }
 module_init(cmos_init);
 
 static void __exit cmos_exit(void)
 {
 #ifdef	CONFIG_PNP
-	if (pnp_platform_devices)
-		pnp_unregister_driver(&cmos_pnp_driver);
-	else
-		platform_driver_unregister(&cmos_platform_driver);
-#else
+	pnp_unregister_driver(&cmos_pnp_driver);
+#endif
 	platform_driver_unregister(&cmos_platform_driver);
-#endif /* CONFIG_PNP */
 }
 module_exit(cmos_exit);
 
diff --git a/drivers/rtc/rtc-dev.c b/drivers/rtc/rtc-dev.c
index f118252..52e2743 100644
--- a/drivers/rtc/rtc-dev.c
+++ b/drivers/rtc/rtc-dev.c
@@ -422,6 +422,12 @@
 	return err;
 }
 
+static int rtc_dev_fasync(int fd, struct file *file, int on)
+{
+	struct rtc_device *rtc = file->private_data;
+	return fasync_helper(fd, file, on, &rtc->async_queue);
+}
+
 static int rtc_dev_release(struct inode *inode, struct file *file)
 {
 	struct rtc_device *rtc = file->private_data;
@@ -434,16 +440,13 @@
 	if (rtc->ops->release)
 		rtc->ops->release(rtc->dev.parent);
 
+	if (file->f_flags & FASYNC)
+		rtc_dev_fasync(-1, file, 0);
+
 	clear_bit_unlock(RTC_DEV_BUSY, &rtc->flags);
 	return 0;
 }
 
-static int rtc_dev_fasync(int fd, struct file *file, int on)
-{
-	struct rtc_device *rtc = file->private_data;
-	return fasync_helper(fd, file, on, &rtc->async_queue);
-}
-
 static const struct file_operations rtc_dev_fops = {
 	.owner		= THIS_MODULE,
 	.llseek		= no_llseek,
diff --git a/drivers/rtc/rtc-m48t59.c b/drivers/rtc/rtc-m48t59.c
index 013e6c1..ce4eff6 100644
--- a/drivers/rtc/rtc-m48t59.c
+++ b/drivers/rtc/rtc-m48t59.c
@@ -24,8 +24,9 @@
 #define NO_IRQ	(-1)
 #endif
 
-#define M48T59_READ(reg)	pdata->read_byte(dev, reg)
-#define M48T59_WRITE(val, reg)	pdata->write_byte(dev, reg, val)
+#define M48T59_READ(reg) (pdata->read_byte(dev, pdata->offset + reg))
+#define M48T59_WRITE(val, reg) \
+	(pdata->write_byte(dev, pdata->offset + reg, val))
 
 #define M48T59_SET_BITS(mask, reg)	\
 	M48T59_WRITE((M48T59_READ(reg) | (mask)), (reg))
@@ -34,7 +35,6 @@
 
 struct m48t59_private {
 	void __iomem *ioaddr;
-	unsigned int size; /* iomem size */
 	int irq;
 	struct rtc_device *rtc;
 	spinlock_t lock; /* serialize the NVRAM and RTC access */
@@ -82,7 +82,8 @@
 	tm->tm_mday	= BCD2BIN(M48T59_READ(M48T59_MDAY));
 
 	val = M48T59_READ(M48T59_WDAY);
-	if ((val & M48T59_WDAY_CEB) && (val & M48T59_WDAY_CB)) {
+	if ((pdata->type == M48T59RTC_TYPE_M48T59) &&
+	    (val & M48T59_WDAY_CEB) && (val & M48T59_WDAY_CB)) {
 		dev_dbg(dev, "Century bit is enabled\n");
 		tm->tm_year += 100;	/* one century */
 	}
@@ -126,7 +127,7 @@
 	M48T59_WRITE((BIN2BCD(tm->tm_mon + 1) & 0x1F), M48T59_MONTH);
 	M48T59_WRITE(BIN2BCD(tm->tm_year % 100), M48T59_YEAR);
 
-	if (tm->tm_year/100)
+	if (pdata->type == M48T59RTC_TYPE_M48T59 && (tm->tm_year / 100))
 		val = (M48T59_WDAY_CEB | M48T59_WDAY_CB);
 	val |= (BIN2BCD(tm->tm_wday) & 0x07);
 	M48T59_WRITE(val, M48T59_WDAY);
@@ -310,6 +311,11 @@
 	.proc		= m48t59_rtc_proc,
 };
 
+static const struct rtc_class_ops m48t02_rtc_ops = {
+	.read_time	= m48t59_rtc_read_time,
+	.set_time	= m48t59_rtc_set_time,
+};
+
 static ssize_t m48t59_nvram_read(struct kobject *kobj,
 				struct bin_attribute *bin_attr,
 				char *buf, loff_t pos, size_t size)
@@ -321,7 +327,7 @@
 	ssize_t cnt = 0;
 	unsigned long flags;
 
-	for (; size > 0 && pos < M48T59_NVRAM_SIZE; cnt++, size--) {
+	for (; size > 0 && pos < pdata->offset; cnt++, size--) {
 		spin_lock_irqsave(&m48t59->lock, flags);
 		*buf++ = M48T59_READ(cnt);
 		spin_unlock_irqrestore(&m48t59->lock, flags);
@@ -341,7 +347,7 @@
 	ssize_t cnt = 0;
 	unsigned long flags;
 
-	for (; size > 0 && pos < M48T59_NVRAM_SIZE; cnt++, size--) {
+	for (; size > 0 && pos < pdata->offset; cnt++, size--) {
 		spin_lock_irqsave(&m48t59->lock, flags);
 		M48T59_WRITE(*buf++, cnt);
 		spin_unlock_irqrestore(&m48t59->lock, flags);
@@ -358,7 +364,6 @@
 	},
 	.read = m48t59_nvram_read,
 	.write = m48t59_nvram_write,
-	.size = M48T59_NVRAM_SIZE,
 };
 
 static int __devinit m48t59_rtc_probe(struct platform_device *pdev)
@@ -367,6 +372,8 @@
 	struct m48t59_private *m48t59 = NULL;
 	struct resource *res;
 	int ret = -ENOMEM;
+	char *name;
+	const struct rtc_class_ops *ops;
 
 	/* This chip could be memory-mapped or I/O-mapped */
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -391,6 +398,8 @@
 			/* Ensure we only kmalloc platform data once */
 			pdev->dev.platform_data = pdata;
 		}
+		if (!pdata->type)
+			pdata->type = M48T59RTC_TYPE_M48T59;
 
 		/* Try to use the generic memory read/write ops */
 		if (!pdata->write_byte)
@@ -403,10 +412,14 @@
 	if (!m48t59)
 		return -ENOMEM;
 
-	m48t59->size = res->end - res->start + 1;
-	m48t59->ioaddr = ioremap(res->start, m48t59->size);
-	if (!m48t59->ioaddr)
-		goto out;
+	m48t59->ioaddr = pdata->ioaddr;
+
+	if (!m48t59->ioaddr) {
+		/* ioaddr not mapped externally */
+		m48t59->ioaddr = ioremap(res->start, res->end - res->start + 1);
+		if (!m48t59->ioaddr)
+			goto out;
+	}
 
 	/* Try to get irq number. We also can work in
 	 * the mode without IRQ.
@@ -421,14 +434,36 @@
 		if (ret)
 			goto out;
 	}
+	switch (pdata->type) {
+	case M48T59RTC_TYPE_M48T59:
+		name = "m48t59";
+		ops = &m48t59_rtc_ops;
+		pdata->offset = 0x1ff0;
+		break;
+	case M48T59RTC_TYPE_M48T02:
+		name = "m48t02";
+		ops = &m48t02_rtc_ops;
+		pdata->offset = 0x7f0;
+		break;
+	case M48T59RTC_TYPE_M48T08:
+		name = "m48t08";
+		ops = &m48t02_rtc_ops;
+		pdata->offset = 0x1ff0;
+		break;
+	default:
+		dev_err(&pdev->dev, "Unknown RTC type\n");
+		ret = -ENODEV;
+		goto out;
+	}
 
-	m48t59->rtc = rtc_device_register("m48t59", &pdev->dev,
-				&m48t59_rtc_ops, THIS_MODULE);
+	m48t59->rtc = rtc_device_register(name, &pdev->dev, ops, THIS_MODULE);
 	if (IS_ERR(m48t59->rtc)) {
 		ret = PTR_ERR(m48t59->rtc);
 		goto out;
 	}
 
+	m48t59_nvram_attr.size = pdata->offset;
+
 	ret = sysfs_create_bin_file(&pdev->dev.kobj, &m48t59_nvram_attr);
 	if (ret)
 		goto out;
@@ -452,11 +487,12 @@
 static int __devexit m48t59_rtc_remove(struct platform_device *pdev)
 {
 	struct m48t59_private *m48t59 = platform_get_drvdata(pdev);
+	struct m48t59_plat_data *pdata = pdev->dev.platform_data;
 
 	sysfs_remove_bin_file(&pdev->dev.kobj, &m48t59_nvram_attr);
 	if (!IS_ERR(m48t59->rtc))
 		rtc_device_unregister(m48t59->rtc);
-	if (m48t59->ioaddr)
+	if (m48t59->ioaddr && !pdata->ioaddr)
 		iounmap(m48t59->ioaddr);
 	if (m48t59->irq != NO_IRQ)
 		free_irq(m48t59->irq, &pdev->dev);
@@ -491,5 +527,5 @@
 module_exit(m48t59_rtc_exit);
 
 MODULE_AUTHOR("Mark Zhan <rongkai.zhan@windriver.com>");
-MODULE_DESCRIPTION("M48T59 RTC driver");
+MODULE_DESCRIPTION("M48T59/M48T02/M48T08 RTC driver");
 MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/rtc-starfire.c b/drivers/rtc/rtc-starfire.c
new file mode 100644
index 0000000..7ccb0dd
--- /dev/null
+++ b/drivers/rtc/rtc-starfire.c
@@ -0,0 +1,120 @@
+/* rtc-starfire.c: Starfire platform RTC driver.
+ *
+ * Copyright (C) 2008 David S. Miller <davem@davemloft.net>
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/time.h>
+#include <linux/rtc.h>
+#include <linux/platform_device.h>
+
+#include <asm/oplib.h>
+
+MODULE_AUTHOR("David S. Miller <davem@davemloft.net>");
+MODULE_DESCRIPTION("Starfire RTC driver");
+MODULE_LICENSE("GPL");
+
+struct starfire_rtc {
+	struct rtc_device	*rtc;
+	spinlock_t		lock;
+};
+
+static u32 starfire_get_time(void)
+{
+	static char obp_gettod[32];
+	static u32 unix_tod;
+
+	sprintf(obp_gettod, "h# %08x unix-gettod",
+		(unsigned int) (long) &unix_tod);
+	prom_feval(obp_gettod);
+
+	return unix_tod;
+}
+
+static int starfire_read_time(struct device *dev, struct rtc_time *tm)
+{
+	struct starfire_rtc *p = dev_get_drvdata(dev);
+	unsigned long flags, secs;
+
+	spin_lock_irqsave(&p->lock, flags);
+	secs = starfire_get_time();
+	spin_unlock_irqrestore(&p->lock, flags);
+
+	rtc_time_to_tm(secs, tm);
+
+	return 0;
+}
+
+static int starfire_set_time(struct device *dev, struct rtc_time *tm)
+{
+	unsigned long secs;
+	int err;
+
+	err = rtc_tm_to_time(tm, &secs);
+	if (err)
+		return err;
+
+	/* Do nothing, time is set using the service processor
+	 * console on this platform.
+	 */
+	return 0;
+}
+
+static const struct rtc_class_ops starfire_rtc_ops = {
+	.read_time	= starfire_read_time,
+	.set_time	= starfire_set_time,
+};
+
+static int __devinit starfire_rtc_probe(struct platform_device *pdev)
+{
+	struct starfire_rtc *p = kzalloc(sizeof(*p), GFP_KERNEL);
+
+	if (!p)
+		return -ENOMEM;
+
+	spin_lock_init(&p->lock);
+
+	p->rtc = rtc_device_register("starfire", &pdev->dev,
+				     &starfire_rtc_ops, THIS_MODULE);
+	if (IS_ERR(p->rtc)) {
+		int err = PTR_ERR(p->rtc);
+		kfree(p);
+		return err;
+	}
+	platform_set_drvdata(pdev, p);
+	return 0;
+}
+
+static int __devexit starfire_rtc_remove(struct platform_device *pdev)
+{
+	struct starfire_rtc *p = platform_get_drvdata(pdev);
+
+	rtc_device_unregister(p->rtc);
+	kfree(p);
+
+	return 0;
+}
+
+static struct platform_driver starfire_rtc_driver = {
+	.driver		= {
+		.name	= "rtc-starfire",
+		.owner	= THIS_MODULE,
+	},
+	.probe		= starfire_rtc_probe,
+	.remove		= __devexit_p(starfire_rtc_remove),
+};
+
+static int __init starfire_rtc_init(void)
+{
+	return platform_driver_register(&starfire_rtc_driver);
+}
+
+static void __exit starfire_rtc_exit(void)
+{
+	platform_driver_unregister(&starfire_rtc_driver);
+}
+
+module_init(starfire_rtc_init);
+module_exit(starfire_rtc_exit);
diff --git a/drivers/rtc/rtc-sun4v.c b/drivers/rtc/rtc-sun4v.c
new file mode 100644
index 0000000..2012ccb
--- /dev/null
+++ b/drivers/rtc/rtc-sun4v.c
@@ -0,0 +1,153 @@
+/* rtc-sun4c.c: Hypervisor based RTC for SUN4V systems.
+ *
+ * Copyright (C) 2008 David S. Miller <davem@davemloft.net>
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/time.h>
+#include <linux/rtc.h>
+#include <linux/platform_device.h>
+
+#include <asm/hypervisor.h>
+
+MODULE_AUTHOR("David S. Miller <davem@davemloft.net>");
+MODULE_DESCRIPTION("SUN4V RTC driver");
+MODULE_LICENSE("GPL");
+
+struct sun4v_rtc {
+	struct rtc_device	*rtc;
+	spinlock_t		lock;
+};
+
+static unsigned long hypervisor_get_time(void)
+{
+	unsigned long ret, time;
+	int retries = 10000;
+
+retry:
+	ret = sun4v_tod_get(&time);
+	if (ret == HV_EOK)
+		return time;
+	if (ret == HV_EWOULDBLOCK) {
+		if (--retries > 0) {
+			udelay(100);
+			goto retry;
+		}
+		printk(KERN_WARNING "SUN4V: tod_get() timed out.\n");
+		return 0;
+	}
+	printk(KERN_WARNING "SUN4V: tod_get() not supported.\n");
+	return 0;
+}
+
+static int sun4v_read_time(struct device *dev, struct rtc_time *tm)
+{
+	struct sun4v_rtc *p = dev_get_drvdata(dev);
+	unsigned long flags, secs;
+
+	spin_lock_irqsave(&p->lock, flags);
+	secs = hypervisor_get_time();
+	spin_unlock_irqrestore(&p->lock, flags);
+
+	rtc_time_to_tm(secs, tm);
+
+	return 0;
+}
+
+static int hypervisor_set_time(unsigned long secs)
+{
+	unsigned long ret;
+	int retries = 10000;
+
+retry:
+	ret = sun4v_tod_set(secs);
+	if (ret == HV_EOK)
+		return 0;
+	if (ret == HV_EWOULDBLOCK) {
+		if (--retries > 0) {
+			udelay(100);
+			goto retry;
+		}
+		printk(KERN_WARNING "SUN4V: tod_set() timed out.\n");
+		return -EAGAIN;
+	}
+	printk(KERN_WARNING "SUN4V: tod_set() not supported.\n");
+	return -EOPNOTSUPP;
+}
+
+static int sun4v_set_time(struct device *dev, struct rtc_time *tm)
+{
+	struct sun4v_rtc *p = dev_get_drvdata(dev);
+	unsigned long flags, secs;
+	int err;
+
+	err = rtc_tm_to_time(tm, &secs);
+	if (err)
+		return err;
+
+	spin_lock_irqsave(&p->lock, flags);
+	err = hypervisor_set_time(secs);
+	spin_unlock_irqrestore(&p->lock, flags);
+
+	return err;
+}
+
+static const struct rtc_class_ops sun4v_rtc_ops = {
+	.read_time	= sun4v_read_time,
+	.set_time	= sun4v_set_time,
+};
+
+static int __devinit sun4v_rtc_probe(struct platform_device *pdev)
+{
+	struct sun4v_rtc *p = kzalloc(sizeof(*p), GFP_KERNEL);
+
+	if (!p)
+		return -ENOMEM;
+
+	spin_lock_init(&p->lock);
+
+	p->rtc = rtc_device_register("sun4v", &pdev->dev,
+				     &sun4v_rtc_ops, THIS_MODULE);
+	if (IS_ERR(p->rtc)) {
+		int err = PTR_ERR(p->rtc);
+		kfree(p);
+		return err;
+	}
+	platform_set_drvdata(pdev, p);
+	return 0;
+}
+
+static int __devexit sun4v_rtc_remove(struct platform_device *pdev)
+{
+	struct sun4v_rtc *p = platform_get_drvdata(pdev);
+
+	rtc_device_unregister(p->rtc);
+	kfree(p);
+
+	return 0;
+}
+
+static struct platform_driver sun4v_rtc_driver = {
+	.driver		= {
+		.name	= "rtc-sun4v",
+		.owner	= THIS_MODULE,
+	},
+	.probe		= sun4v_rtc_probe,
+	.remove		= __devexit_p(sun4v_rtc_remove),
+};
+
+static int __init sun4v_rtc_init(void)
+{
+	return platform_driver_register(&sun4v_rtc_driver);
+}
+
+static void __exit sun4v_rtc_exit(void)
+{
+	platform_driver_unregister(&sun4v_rtc_driver);
+}
+
+module_init(sun4v_rtc_init);
+module_exit(sun4v_rtc_exit);
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c
index acb7801..0a225cc 100644
--- a/drivers/s390/block/dasd.c
+++ b/drivers/s390/block/dasd.c
@@ -215,7 +215,7 @@
 			return rc;
 	}
 	/* register 'device' debug area, used for all DBF_DEV_XXX calls */
-	device->debug_area = debug_register(device->cdev->dev.bus_id, 1, 1,
+	device->debug_area = debug_register(dev_name(&device->cdev->dev), 1, 1,
 					    8 * sizeof(long));
 	debug_register_view(device->debug_area, &debug_sprintf_view);
 	debug_set_level(device->debug_area, DBF_WARNING);
@@ -933,7 +933,7 @@
 		MESSAGE(KERN_DEBUG,
 			"invalid status in handle_killed_request: "
 			"bus_id %s, status %02x",
-			cdev->dev.bus_id, cqr->status);
+			dev_name(&cdev->dev), cqr->status);
 		return;
 	}
 
@@ -942,7 +942,7 @@
 	    device != dasd_device_from_cdev_locked(cdev) ||
 	    strncmp(device->discipline->ebcname, (char *) &cqr->magic, 4)) {
 		MESSAGE(KERN_DEBUG, "invalid device in request: bus_id %s",
-			cdev->dev.bus_id);
+			dev_name(&cdev->dev));
 		return;
 	}
 
@@ -982,11 +982,11 @@
 			break;
 		case -ETIMEDOUT:
 			printk(KERN_WARNING"%s(%s): request timed out\n",
-			       __func__, cdev->dev.bus_id);
+			       __func__, dev_name(&cdev->dev));
 			break;
 		default:
 			printk(KERN_WARNING"%s(%s): unknown error %ld\n",
-			       __func__, cdev->dev.bus_id, PTR_ERR(irb));
+			       __func__, dev_name(&cdev->dev), PTR_ERR(irb));
 		}
 		dasd_handle_killed_request(cdev, intparm);
 		return;
@@ -995,7 +995,7 @@
 	now = get_clock();
 
 	DBF_EVENT(DBF_ERR, "Interrupt: bus_id %s CS/DS %04x ip %08x",
-		  cdev->dev.bus_id, ((irb->scsw.cmd.cstat << 8) |
+		  dev_name(&cdev->dev), ((irb->scsw.cmd.cstat << 8) |
 		  irb->scsw.cmd.dstat), (unsigned int) intparm);
 
 	/* check for unsolicited interrupts */
@@ -1019,7 +1019,7 @@
 	if (!device ||
 	    strncmp(device->discipline->ebcname, (char *) &cqr->magic, 4)) {
 		MESSAGE(KERN_DEBUG, "invalid device in request: bus_id %s",
-			cdev->dev.bus_id);
+			dev_name(&cdev->dev));
 		return;
 	}
 
@@ -1037,7 +1037,7 @@
 	if (cqr->status != DASD_CQR_IN_IO) {
 		MESSAGE(KERN_DEBUG,
 			"invalid status: bus_id %s, status %02x",
-			cdev->dev.bus_id, cqr->status);
+			dev_name(&cdev->dev), cqr->status);
 		return;
 	}
 	DBF_DEV_EVENT(DBF_DEBUG, device, "Int: CS/DS 0x%04x for cqr %p",
@@ -2134,14 +2134,14 @@
 	if (ret) {
 		printk(KERN_WARNING
 		       "dasd_generic_probe: could not set ccw-device options "
-		       "for %s\n", cdev->dev.bus_id);
+		       "for %s\n", dev_name(&cdev->dev));
 		return ret;
 	}
 	ret = dasd_add_sysfs_files(cdev);
 	if (ret) {
 		printk(KERN_WARNING
 		       "dasd_generic_probe: could not add sysfs entries "
-		       "for %s\n", cdev->dev.bus_id);
+		       "for %s\n", dev_name(&cdev->dev));
 		return ret;
 	}
 	cdev->handler = &dasd_int_handler;
@@ -2152,13 +2152,13 @@
 	 * initial probe.
 	 */
 	if ((dasd_get_feature(cdev, DASD_FEATURE_INITIAL_ONLINE) > 0 ) ||
-	    (dasd_autodetect && dasd_busid_known(cdev->dev.bus_id) != 0))
+	    (dasd_autodetect && dasd_busid_known(dev_name(&cdev->dev)) != 0))
 		ret = ccw_device_set_online(cdev);
 	if (ret)
 		printk(KERN_WARNING
 		       "dasd_generic_probe: could not initially "
 		       "online ccw-device %s; return code: %d\n",
-		       cdev->dev.bus_id, ret);
+		       dev_name(&cdev->dev), ret);
 	return 0;
 }
 
@@ -2224,7 +2224,7 @@
 		        printk (KERN_WARNING
 				"dasd_generic couldn't online device %s "
 				"- discipline DIAG not available\n",
-				cdev->dev.bus_id);
+				dev_name(&cdev->dev));
 			dasd_delete_device(device);
 			return -ENODEV;
 		}
@@ -2248,7 +2248,7 @@
 		printk (KERN_WARNING
 			"dasd_generic couldn't online device %s "
 			"with discipline %s rc=%i\n",
-			cdev->dev.bus_id, discipline->name, rc);
+			dev_name(&cdev->dev), discipline->name, rc);
 		module_put(discipline->owner);
 		module_put(base_discipline->owner);
 		dasd_delete_device(device);
@@ -2259,7 +2259,7 @@
 	if (device->state <= DASD_STATE_KNOWN) {
 		printk (KERN_WARNING
 			"dasd_generic discipline not found for %s\n",
-			cdev->dev.bus_id);
+			dev_name(&cdev->dev));
 		rc = -ENODEV;
 		dasd_set_target_state(device, DASD_STATE_NEW);
 		if (device->block)
@@ -2267,7 +2267,7 @@
 		dasd_delete_device(device);
 	} else
 		pr_debug("dasd_generic device %s found\n",
-				cdev->dev.bus_id);
+				dev_name(&cdev->dev));
 
 	/* FIXME: we have to wait for the root device but we don't want
 	 * to wait for each single device but for all at once. */
diff --git a/drivers/s390/block/dasd_3990_erp.c b/drivers/s390/block/dasd_3990_erp.c
index 5c6e6f3..b8f9c00 100644
--- a/drivers/s390/block/dasd_3990_erp.c
+++ b/drivers/s390/block/dasd_3990_erp.c
@@ -1397,7 +1397,7 @@
 			DEV_MESSAGE(KERN_ERR, cqr->startdev,
 				    "ERP on alias device for request %p,"
 				    " recover on base device %s", cqr,
-				    cqr->block->base->cdev->dev.bus_id);
+				    dev_name(&cqr->block->base->cdev->dev));
 		}
 		dasd_eckd_reset_ccw_to_base_io(cqr);
 		erp->startdev = cqr->block->base;
diff --git a/drivers/s390/block/dasd_devmap.c b/drivers/s390/block/dasd_devmap.c
index cd3335c..921443b 100644
--- a/drivers/s390/block/dasd_devmap.c
+++ b/drivers/s390/block/dasd_devmap.c
@@ -515,9 +515,9 @@
 {
 	struct dasd_devmap *devmap;
 
-	devmap = dasd_find_busid(cdev->dev.bus_id);
+	devmap = dasd_find_busid(dev_name(&cdev->dev));
 	if (IS_ERR(devmap))
-		devmap = dasd_add_busid(cdev->dev.bus_id,
+		devmap = dasd_add_busid(dev_name(&cdev->dev),
 					DASD_FEATURE_DEFAULT);
 	return devmap;
 }
@@ -584,7 +584,7 @@
 	unsigned long flags;
 
 	/* First remove device pointer from devmap. */
-	devmap = dasd_find_busid(device->cdev->dev.bus_id);
+	devmap = dasd_find_busid(dev_name(&device->cdev->dev));
 	BUG_ON(IS_ERR(devmap));
 	spin_lock(&dasd_devmap_lock);
 	if (devmap->device != device) {
@@ -674,7 +674,7 @@
 	struct dasd_devmap *devmap;
 	int ro_flag;
 
-	devmap = dasd_find_busid(dev->bus_id);
+	devmap = dasd_find_busid(dev_name(dev));
 	if (!IS_ERR(devmap))
 		ro_flag = (devmap->features & DASD_FEATURE_READONLY) != 0;
 	else
@@ -723,7 +723,7 @@
 	struct dasd_devmap *devmap;
 	int erplog;
 
-	devmap = dasd_find_busid(dev->bus_id);
+	devmap = dasd_find_busid(dev_name(dev));
 	if (!IS_ERR(devmap))
 		erplog = (devmap->features & DASD_FEATURE_ERPLOG) != 0;
 	else
@@ -770,7 +770,7 @@
 	struct dasd_devmap *devmap;
 	int use_diag;
 
-	devmap = dasd_find_busid(dev->bus_id);
+	devmap = dasd_find_busid(dev_name(dev));
 	if (!IS_ERR(devmap))
 		use_diag = (devmap->features & DASD_FEATURE_USEDIAG) != 0;
 	else
@@ -876,7 +876,7 @@
 	struct dasd_devmap *devmap;
 	int alias;
 
-	devmap = dasd_find_busid(dev->bus_id);
+	devmap = dasd_find_busid(dev_name(dev));
 	spin_lock(&dasd_devmap_lock);
 	if (IS_ERR(devmap) || strlen(devmap->uid.vendor) == 0) {
 		spin_unlock(&dasd_devmap_lock);
@@ -899,7 +899,7 @@
 	struct dasd_devmap *devmap;
 	char *vendor;
 
-	devmap = dasd_find_busid(dev->bus_id);
+	devmap = dasd_find_busid(dev_name(dev));
 	spin_lock(&dasd_devmap_lock);
 	if (!IS_ERR(devmap) && strlen(devmap->uid.vendor) > 0)
 		vendor = devmap->uid.vendor;
@@ -924,7 +924,7 @@
 	char ua_string[3];
 	struct dasd_uid *uid;
 
-	devmap = dasd_find_busid(dev->bus_id);
+	devmap = dasd_find_busid(dev_name(dev));
 	spin_lock(&dasd_devmap_lock);
 	if (IS_ERR(devmap) || strlen(devmap->uid.vendor) == 0) {
 		spin_unlock(&dasd_devmap_lock);
@@ -972,7 +972,7 @@
 	struct dasd_devmap *devmap;
 	int eer_flag;
 
-	devmap = dasd_find_busid(dev->bus_id);
+	devmap = dasd_find_busid(dev_name(dev));
 	if (!IS_ERR(devmap) && devmap->device)
 		eer_flag = dasd_eer_enabled(devmap->device);
 	else
@@ -1034,7 +1034,7 @@
 {
 	struct dasd_devmap *devmap;
 
-	devmap = dasd_find_busid(cdev->dev.bus_id);
+	devmap = dasd_find_busid(dev_name(&cdev->dev));
 	if (IS_ERR(devmap))
 		return PTR_ERR(devmap);
 	spin_lock(&dasd_devmap_lock);
@@ -1057,7 +1057,7 @@
 {
 	struct dasd_devmap *devmap;
 
-	devmap = dasd_find_busid(cdev->dev.bus_id);
+	devmap = dasd_find_busid(dev_name(&cdev->dev));
 	if (IS_ERR(devmap))
 		return PTR_ERR(devmap);
 
@@ -1077,7 +1077,7 @@
 {
 	struct dasd_devmap *devmap;
 
-	devmap = dasd_find_busid(cdev->dev.bus_id);
+	devmap = dasd_find_busid(dev_name(&cdev->dev));
 	if (IS_ERR(devmap))
 		return PTR_ERR(devmap);
 
@@ -1093,7 +1093,7 @@
 {
 	struct dasd_devmap *devmap;
 
-	devmap = dasd_find_busid(cdev->dev.bus_id);
+	devmap = dasd_find_busid(dev_name(&cdev->dev));
 	if (IS_ERR(devmap))
 		return PTR_ERR(devmap);
 
diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c
index 773b3fe..49f9d22 100644
--- a/drivers/s390/block/dasd_eckd.c
+++ b/drivers/s390/block/dasd_eckd.c
@@ -6,6 +6,8 @@
  *		    Martin Schwidefsky <schwidefsky@de.ibm.com>
  * Bugreports.to..: <Linux390@de.ibm.com>
  * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
+ * EMC Symmetrix ioctl Copyright EMC Corporation, 2008
+ * Author.........: Nigel Hislop <hislop_nigel@emc.com>
  *
  */
 
@@ -84,7 +86,7 @@
 	if (ret) {
 		printk(KERN_WARNING
 		       "dasd_eckd_probe: could not set ccw-device options "
-		       "for %s\n", cdev->dev.bus_id);
+		       "for %s\n", dev_name(&cdev->dev));
 		return ret;
 	}
 	ret = dasd_generic_probe(cdev, &dasd_eckd_discipline);
@@ -1501,12 +1503,27 @@
 		return;
 	}
 
-	/* just report other unsolicited interrupts */
-	DEV_MESSAGE(KERN_DEBUG, device, "%s",
-		    "unsolicited interrupt received");
-	device->discipline->dump_sense(device, NULL, irb);
-	dasd_schedule_device_bh(device);
+	if ((irb->scsw.cmd.cc == 1) &&
+	    (irb->scsw.cmd.fctl & SCSW_FCTL_START_FUNC) &&
+	    (irb->scsw.cmd.actl & SCSW_ACTL_START_PEND) &&
+	    (irb->scsw.cmd.stctl & SCSW_STCTL_STATUS_PEND)) {
+		/* fake irb do nothing, they are handled elsewhere */
+		dasd_schedule_device_bh(device);
+		return;
+	}
 
+	if (!(irb->esw.esw0.erw.cons)) {
+		/* just report other unsolicited interrupts */
+		DEV_MESSAGE(KERN_ERR, device, "%s",
+			    "unsolicited interrupt received");
+	} else {
+		DEV_MESSAGE(KERN_ERR, device, "%s",
+			    "unsolicited interrupt received "
+			    "(sense available)");
+		device->discipline->dump_sense(device, NULL, irb);
+	}
+
+	dasd_schedule_device_bh(device);
 	return;
 };
 
@@ -2068,6 +2085,103 @@
 	return 0;
 }
 
+/*
+ * Issue syscall I/O to EMC Symmetrix array.
+ * CCWs are PSF and RSSD
+ */
+static int dasd_symm_io(struct dasd_device *device, void __user *argp)
+{
+	struct dasd_symmio_parms usrparm;
+	char *psf_data, *rssd_result;
+	struct dasd_ccw_req *cqr;
+	struct ccw1 *ccw;
+	int rc;
+
+	/* Copy parms from caller */
+	rc = -EFAULT;
+	if (copy_from_user(&usrparm, argp, sizeof(usrparm)))
+		goto out;
+#ifndef CONFIG_64BIT
+	/* Make sure pointers are sane even on 31 bit. */
+	if ((usrparm.psf_data >> 32) != 0 || (usrparm.rssd_result >> 32) != 0) {
+		rc = -EINVAL;
+		goto out;
+	}
+#endif
+	/* alloc I/O data area */
+	psf_data = kzalloc(usrparm.psf_data_len, GFP_KERNEL | GFP_DMA);
+	rssd_result = kzalloc(usrparm.rssd_result_len, GFP_KERNEL | GFP_DMA);
+	if (!psf_data || !rssd_result) {
+		rc = -ENOMEM;
+		goto out_free;
+	}
+
+	/* get syscall header from user space */
+	rc = -EFAULT;
+	if (copy_from_user(psf_data,
+			   (void __user *)(unsigned long) usrparm.psf_data,
+			   usrparm.psf_data_len))
+		goto out_free;
+
+	/* sanity check on syscall header */
+	if (psf_data[0] != 0x17 && psf_data[1] != 0xce) {
+		rc = -EINVAL;
+		goto out_free;
+	}
+
+	/* setup CCWs for PSF + RSSD */
+	cqr = dasd_smalloc_request("ECKD", 2 , 0, device);
+	if (IS_ERR(cqr)) {
+		DEV_MESSAGE(KERN_WARNING, device, "%s",
+			"Could not allocate initialization request");
+		rc = PTR_ERR(cqr);
+		goto out_free;
+	}
+
+	cqr->startdev = device;
+	cqr->memdev = device;
+	cqr->retries = 3;
+	cqr->expires = 10 * HZ;
+	cqr->buildclk = get_clock();
+	cqr->status = DASD_CQR_FILLED;
+
+	/* Build the ccws */
+	ccw = cqr->cpaddr;
+
+	/* PSF ccw */
+	ccw->cmd_code = DASD_ECKD_CCW_PSF;
+	ccw->count = usrparm.psf_data_len;
+	ccw->flags |= CCW_FLAG_CC;
+	ccw->cda = (__u32)(addr_t) psf_data;
+
+	ccw++;
+
+	/* RSSD ccw  */
+	ccw->cmd_code = DASD_ECKD_CCW_RSSD;
+	ccw->count = usrparm.rssd_result_len;
+	ccw->flags = CCW_FLAG_SLI ;
+	ccw->cda = (__u32)(addr_t) rssd_result;
+
+	rc = dasd_sleep_on(cqr);
+	if (rc)
+		goto out_sfree;
+
+	rc = -EFAULT;
+	if (copy_to_user((void __user *)(unsigned long) usrparm.rssd_result,
+			   rssd_result, usrparm.rssd_result_len))
+		goto out_sfree;
+	rc = 0;
+
+out_sfree:
+	dasd_sfree_request(cqr, cqr->memdev);
+out_free:
+	kfree(rssd_result);
+	kfree(psf_data);
+out:
+	DBF_DEV_EVENT(DBF_WARNING, device, "Symmetrix ioctl: rc=%d", rc);
+	return rc;
+}
+
 static int
 dasd_eckd_ioctl(struct dasd_block *block, unsigned int cmd, void __user *argp)
 {
@@ -2086,6 +2200,8 @@
 		return dasd_eckd_reserve(device);
 	case BIODASDSLCK:
 		return dasd_eckd_steal_lock(device);
+	case BIODASDSYMMIO:
+		return dasd_symm_io(device, argp);
 	default:
 		return -ENOIOCTLCMD;
 	}
@@ -2145,13 +2261,13 @@
 	/* dump the sense data */
 	len = sprintf(page,  KERN_ERR PRINTK_HEADER
 		      " I/O status report for device %s:\n",
-		      device->cdev->dev.bus_id);
+		      dev_name(&device->cdev->dev));
 	len += sprintf(page + len, KERN_ERR PRINTK_HEADER
 		       " in req: %p CS: 0x%02X DS: 0x%02X\n", req,
 		       irb->scsw.cmd.cstat, irb->scsw.cmd.dstat);
 	len += sprintf(page + len, KERN_ERR PRINTK_HEADER
 		       " device %s: Failing CCW: %p\n",
-		       device->cdev->dev.bus_id,
+		       dev_name(&device->cdev->dev),
 		       (void *) (addr_t) irb->scsw.cmd.cpa);
 	if (irb->esw.esw0.erw.cons) {
 		for (sl = 0; sl < 4; sl++) {
diff --git a/drivers/s390/block/dasd_eer.c b/drivers/s390/block/dasd_eer.c
index bf512ac..892e287 100644
--- a/drivers/s390/block/dasd_eer.c
+++ b/drivers/s390/block/dasd_eer.c
@@ -309,7 +309,8 @@
 	do_gettimeofday(&tv);
 	header.tv_sec = tv.tv_sec;
 	header.tv_usec = tv.tv_usec;
-	strncpy(header.busid, device->cdev->dev.bus_id, DASD_EER_BUSID_SIZE);
+	strncpy(header.busid, dev_name(&device->cdev->dev),
+		DASD_EER_BUSID_SIZE);
 
 	spin_lock_irqsave(&bufferlock, flags);
 	list_for_each_entry(eerb, &bufferlist, list) {
@@ -349,7 +350,8 @@
 	do_gettimeofday(&tv);
 	header.tv_sec = tv.tv_sec;
 	header.tv_usec = tv.tv_usec;
-	strncpy(header.busid, device->cdev->dev.bus_id, DASD_EER_BUSID_SIZE);
+	strncpy(header.busid, dev_name(&device->cdev->dev),
+		DASD_EER_BUSID_SIZE);
 
 	spin_lock_irqsave(&bufferlock, flags);
 	list_for_each_entry(eerb, &bufferlist, list) {
diff --git a/drivers/s390/block/dasd_fba.c b/drivers/s390/block/dasd_fba.c
index aa0c533..93d9b64 100644
--- a/drivers/s390/block/dasd_fba.c
+++ b/drivers/s390/block/dasd_fba.c
@@ -451,13 +451,13 @@
 	}
 	len = sprintf(page, KERN_ERR PRINTK_HEADER
 		      " I/O status report for device %s:\n",
-		      device->cdev->dev.bus_id);
+		      dev_name(&device->cdev->dev));
 	len += sprintf(page + len, KERN_ERR PRINTK_HEADER
 		       " in req: %p CS: 0x%02X DS: 0x%02X\n", req,
 		       irb->scsw.cmd.cstat, irb->scsw.cmd.dstat);
 	len += sprintf(page + len, KERN_ERR PRINTK_HEADER
 		       " device %s: Failing CCW: %p\n",
-		       device->cdev->dev.bus_id,
+		       dev_name(&device->cdev->dev),
 		       (void *) (addr_t) irb->scsw.cmd.cpa);
 	if (irb->esw.esw0.erw.cons) {
 		for (sl = 0; sl < 4; sl++) {
diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h
index 31ecaa4..489d5fe 100644
--- a/drivers/s390/block/dasd_int.h
+++ b/drivers/s390/block/dasd_int.h
@@ -126,7 +126,7 @@
 #define DEV_MESSAGE(d_loglevel,d_device,d_string,d_args...)\
 do { \
 	printk(d_loglevel PRINTK_HEADER " %s: " d_string "\n", \
-	       d_device->cdev->dev.bus_id, d_args); \
+	       dev_name(&d_device->cdev->dev), d_args); \
 	DBF_DEV_EVENT(DBF_ALERT, d_device, d_string, d_args); \
 } while(0)
 
@@ -140,7 +140,7 @@
 #define DEV_MESSAGE_LOG(d_loglevel,d_device,d_string,d_args...)\
 do { \
 	printk(d_loglevel PRINTK_HEADER " %s: " d_string "\n", \
-	       d_device->cdev->dev.bus_id, d_args); \
+	       dev_name(&d_device->cdev->dev), d_args); \
 } while(0)
 
 #define MESSAGE_LOG(d_loglevel,d_string,d_args...)\
diff --git a/drivers/s390/block/dasd_proc.c b/drivers/s390/block/dasd_proc.c
index 03c0e40..9088de8 100644
--- a/drivers/s390/block/dasd_proc.c
+++ b/drivers/s390/block/dasd_proc.c
@@ -67,7 +67,7 @@
 		return 0;
 	}
 	/* Print device number. */
-	seq_printf(m, "%s", device->cdev->dev.bus_id);
+	seq_printf(m, "%s", dev_name(&device->cdev->dev));
 	/* Print discipline string. */
 	if (device != NULL && device->discipline != NULL)
 		seq_printf(m, "(%s)", device->discipline->name);
@@ -76,7 +76,8 @@
 	/* Print kdev. */
 	if (block->gdp)
 		seq_printf(m, " at (%3d:%6d)",
-			   block->gdp->major, block->gdp->first_minor);
+			   MAJOR(disk_devt(block->gdp)),
+			   MINOR(disk_devt(block->gdp)));
 	else
 		seq_printf(m, "  at (???:??????)");
 	/* Print device name. */
diff --git a/drivers/s390/block/dcssblk.c b/drivers/s390/block/dcssblk.c
index 711b300..a7ff167 100644
--- a/drivers/s390/block/dcssblk.c
+++ b/drivers/s390/block/dcssblk.c
@@ -31,7 +31,6 @@
 #define PRINT_WARN(x...)  printk(KERN_WARNING DCSSBLK_NAME " warning: " x)
 #define PRINT_ERR(x...)	  printk(KERN_ERR DCSSBLK_NAME " error: " x)
 
-
 static int dcssblk_open(struct inode *inode, struct file *filp);
 static int dcssblk_release(struct inode *inode, struct file *filp);
 static int dcssblk_make_request(struct request_queue *q, struct bio *bio);
@@ -48,26 +47,6 @@
 	.direct_access 	= dcssblk_direct_access,
 };
 
-static ssize_t dcssblk_add_store(struct device * dev, struct device_attribute *attr, const char * buf,
-				  size_t count);
-static ssize_t dcssblk_remove_store(struct device * dev, struct device_attribute *attr, const char * buf,
-				  size_t count);
-static ssize_t dcssblk_save_store(struct device * dev, struct device_attribute *attr, const char * buf,
-				  size_t count);
-static ssize_t dcssblk_save_show(struct device *dev, struct device_attribute *attr, char *buf);
-static ssize_t dcssblk_shared_store(struct device * dev, struct device_attribute *attr, const char * buf,
-				  size_t count);
-static ssize_t dcssblk_shared_show(struct device *dev, struct device_attribute *attr, char *buf);
-
-static DEVICE_ATTR(add, S_IWUSR, NULL, dcssblk_add_store);
-static DEVICE_ATTR(remove, S_IWUSR, NULL, dcssblk_remove_store);
-static DEVICE_ATTR(save, S_IWUSR | S_IRUGO, dcssblk_save_show,
-		   dcssblk_save_store);
-static DEVICE_ATTR(shared, S_IWUSR | S_IRUGO, dcssblk_shared_show,
-		   dcssblk_shared_store);
-
-static struct device *dcssblk_root_dev;
-
 struct dcssblk_dev_info {
 	struct list_head lh;
 	struct device dev;
@@ -80,8 +59,42 @@
 	unsigned char save_pending;
 	unsigned char is_shared;
 	struct request_queue *dcssblk_queue;
+	int num_of_segments;
+	struct list_head seg_list;
 };
 
+struct segment_info {
+	struct list_head lh;
+	char segment_name[BUS_ID_SIZE];
+	unsigned long start;
+	unsigned long end;
+	int segment_type;
+};
+
+static ssize_t dcssblk_add_store(struct device * dev, struct device_attribute *attr, const char * buf,
+				  size_t count);
+static ssize_t dcssblk_remove_store(struct device * dev, struct device_attribute *attr, const char * buf,
+				  size_t count);
+static ssize_t dcssblk_save_store(struct device * dev, struct device_attribute *attr, const char * buf,
+				  size_t count);
+static ssize_t dcssblk_save_show(struct device *dev, struct device_attribute *attr, char *buf);
+static ssize_t dcssblk_shared_store(struct device * dev, struct device_attribute *attr, const char * buf,
+				  size_t count);
+static ssize_t dcssblk_shared_show(struct device *dev, struct device_attribute *attr, char *buf);
+static ssize_t dcssblk_seglist_show(struct device *dev,
+				struct device_attribute *attr,
+				char *buf);
+
+static DEVICE_ATTR(add, S_IWUSR, NULL, dcssblk_add_store);
+static DEVICE_ATTR(remove, S_IWUSR, NULL, dcssblk_remove_store);
+static DEVICE_ATTR(save, S_IWUSR | S_IRUSR, dcssblk_save_show,
+		   dcssblk_save_store);
+static DEVICE_ATTR(shared, S_IWUSR | S_IRUSR, dcssblk_shared_show,
+		   dcssblk_shared_store);
+static DEVICE_ATTR(seglist, S_IRUSR, dcssblk_seglist_show, NULL);
+
+static struct device *dcssblk_root_dev;
+
 static LIST_HEAD(dcssblk_devices);
 static struct rw_semaphore dcssblk_devices_sem;
 
@@ -91,8 +104,15 @@
 static void
 dcssblk_release_segment(struct device *dev)
 {
-	PRINT_DEBUG("segment release fn called for %s\n", dev->bus_id);
-	kfree(container_of(dev, struct dcssblk_dev_info, dev));
+	struct dcssblk_dev_info *dev_info;
+	struct segment_info *entry, *temp;
+
+	dev_info = container_of(dev, struct dcssblk_dev_info, dev);
+	list_for_each_entry_safe(entry, temp, &dev_info->seg_list, lh) {
+		list_del(&entry->lh);
+		kfree(entry);
+	}
+	kfree(dev_info);
 	module_put(THIS_MODULE);
 }
 
@@ -114,7 +134,7 @@
 		found = 0;
 		// test if minor available
 		list_for_each_entry(entry, &dcssblk_devices, lh)
-			if (minor == entry->gd->first_minor)
+			if (minor == MINOR(disk_devt(entry->gd)))
 				found++;
 		if (!found) break; // got unused minor
 	}
@@ -142,6 +162,169 @@
 	return NULL;
 }
 
+/*
+ * get the struct segment_info from seg_list
+ * for the given name.
+ * down_read(&dcssblk_devices_sem) must be held.
+ */
+static struct segment_info *
+dcssblk_get_segment_by_name(char *name)
+{
+	struct dcssblk_dev_info *dev_info;
+	struct segment_info *entry;
+
+	list_for_each_entry(dev_info, &dcssblk_devices, lh) {
+		list_for_each_entry(entry, &dev_info->seg_list, lh) {
+			if (!strcmp(name, entry->segment_name))
+				return entry;
+		}
+	}
+	return NULL;
+}
+
+/*
+ * get the highest address of the multi-segment block.
+ */
+static unsigned long
+dcssblk_find_highest_addr(struct dcssblk_dev_info *dev_info)
+{
+	unsigned long highest_addr;
+	struct segment_info *entry;
+
+	highest_addr = 0;
+	list_for_each_entry(entry, &dev_info->seg_list, lh) {
+		if (highest_addr < entry->end)
+			highest_addr = entry->end;
+	}
+	return highest_addr;
+}
+
+/*
+ * get the lowest address of the multi-segment block.
+ */
+static unsigned long
+dcssblk_find_lowest_addr(struct dcssblk_dev_info *dev_info)
+{
+	int set_first;
+	unsigned long lowest_addr;
+	struct segment_info *entry;
+
+	set_first = 0;
+	lowest_addr = 0;
+	list_for_each_entry(entry, &dev_info->seg_list, lh) {
+		if (set_first == 0) {
+			lowest_addr = entry->start;
+			set_first = 1;
+		} else {
+			if (lowest_addr > entry->start)
+				lowest_addr = entry->start;
+		}
+	}
+	return lowest_addr;
+}
+
+/*
+ * Check continuity of segments.
+ */
+static int
+dcssblk_is_continuous(struct dcssblk_dev_info *dev_info)
+{
+	int i, j, rc;
+	struct segment_info *sort_list, *entry, temp;
+
+	if (dev_info->num_of_segments <= 1)
+		return 0;
+
+	sort_list = kzalloc(
+			sizeof(struct segment_info) * dev_info->num_of_segments,
+			GFP_KERNEL);
+	if (sort_list == NULL)
+		return -ENOMEM;
+	i = 0;
+	list_for_each_entry(entry, &dev_info->seg_list, lh) {
+		memcpy(&sort_list[i], entry, sizeof(struct segment_info));
+		i++;
+	}
+
+	/* sort segments */
+	for (i = 0; i < dev_info->num_of_segments; i++)
+		for (j = 0; j < dev_info->num_of_segments; j++)
+			if (sort_list[j].start > sort_list[i].start) {
+				memcpy(&temp, &sort_list[i],
+					sizeof(struct segment_info));
+				memcpy(&sort_list[i], &sort_list[j],
+					sizeof(struct segment_info));
+				memcpy(&sort_list[j], &temp,
+					sizeof(struct segment_info));
+			}
+
+	/* check continuity */
+	for (i = 0; i < dev_info->num_of_segments - 1; i++) {
+		if ((sort_list[i].end + 1) != sort_list[i+1].start) {
+			PRINT_ERR("Segment %s is not contiguous with "
+				"segment %s\n",
+				sort_list[i].segment_name,
+				sort_list[i+1].segment_name);
+			rc = -EINVAL;
+			goto out;
+		}
+		/* EN and EW are allowed in a block device */
+		if (sort_list[i].segment_type != sort_list[i+1].segment_type) {
+			if (!(sort_list[i].segment_type & SEGMENT_EXCLUSIVE) ||
+				(sort_list[i].segment_type == SEG_TYPE_ER) ||
+				!(sort_list[i+1].segment_type &
+				SEGMENT_EXCLUSIVE) ||
+				(sort_list[i+1].segment_type == SEG_TYPE_ER)) {
+				PRINT_ERR("Segment %s has different type from "
+					"segment %s\n",
+					sort_list[i].segment_name,
+					sort_list[i+1].segment_name);
+				rc = -EINVAL;
+				goto out;
+			}
+		}
+	}
+	rc = 0;
+out:
+	kfree(sort_list);
+	return rc;
+}
+
+/*
+ * Load a segment
+ */
+static int
+dcssblk_load_segment(char *name, struct segment_info **seg_info)
+{
+	int rc;
+
+	/* already loaded? */
+	down_read(&dcssblk_devices_sem);
+	*seg_info = dcssblk_get_segment_by_name(name);
+	up_read(&dcssblk_devices_sem);
+	if (*seg_info != NULL)
+		return -EEXIST;
+
+	/* get a struct segment_info */
+	*seg_info = kzalloc(sizeof(struct segment_info), GFP_KERNEL);
+	if (*seg_info == NULL)
+		return -ENOMEM;
+
+	strcpy((*seg_info)->segment_name, name);
+
+	/* load the segment */
+	rc = segment_load(name, SEGMENT_SHARED,
+			&(*seg_info)->start, &(*seg_info)->end);
+	if (rc < 0) {
+		segment_warning(rc, (*seg_info)->segment_name);
+		kfree(*seg_info);
+	} else {
+		INIT_LIST_HEAD(&(*seg_info)->lh);
+		(*seg_info)->segment_type = rc;
+	}
+	return rc;
+}
+
 static void dcssblk_unregister_callback(struct device *dev)
 {
 	device_unregister(dev);
@@ -165,6 +348,7 @@
 dcssblk_shared_store(struct device *dev, struct device_attribute *attr, const char *inbuf, size_t count)
 {
 	struct dcssblk_dev_info *dev_info;
+	struct segment_info *entry, *temp;
 	int rc;
 
 	if ((count > 1) && (inbuf[1] != '\n') && (inbuf[1] != '\0'))
@@ -172,46 +356,46 @@
 	down_write(&dcssblk_devices_sem);
 	dev_info = container_of(dev, struct dcssblk_dev_info, dev);
 	if (atomic_read(&dev_info->use_count)) {
-		PRINT_ERR("share: segment %s is busy!\n",
-			  dev_info->segment_name);
 		rc = -EBUSY;
 		goto out;
 	}
 	if (inbuf[0] == '1') {
-		// reload segment in shared mode
-		rc = segment_modify_shared(dev_info->segment_name,
-					   SEGMENT_SHARED);
-		if (rc < 0) {
-			BUG_ON(rc == -EINVAL);
-			if (rc != -EAGAIN)
-				goto removeseg;
-		} else {
-			dev_info->is_shared = 1;
-			switch (dev_info->segment_type) {
-				case SEG_TYPE_SR:
-				case SEG_TYPE_ER:
-				case SEG_TYPE_SC:
-					set_disk_ro(dev_info->gd,1);
+		/* reload segments in shared mode */
+		list_for_each_entry(entry, &dev_info->seg_list, lh) {
+			rc = segment_modify_shared(entry->segment_name,
+						SEGMENT_SHARED);
+			if (rc < 0) {
+				BUG_ON(rc == -EINVAL);
+				if (rc != -EAGAIN)
+					goto removeseg;
 			}
 		}
+		dev_info->is_shared = 1;
+		switch (dev_info->segment_type) {
+		case SEG_TYPE_SR:
+		case SEG_TYPE_ER:
+		case SEG_TYPE_SC:
+			set_disk_ro(dev_info->gd, 1);
+		}
 	} else if (inbuf[0] == '0') {
-		// reload segment in exclusive mode
+		/* reload segments in exclusive mode */
 		if (dev_info->segment_type == SEG_TYPE_SC) {
 			PRINT_ERR("Segment type SC (%s) cannot be loaded in "
-				  "non-shared mode\n", dev_info->segment_name);
+				"non-shared mode\n", dev_info->segment_name);
 			rc = -EINVAL;
 			goto out;
 		}
-		rc = segment_modify_shared(dev_info->segment_name,
-					   SEGMENT_EXCLUSIVE);
-		if (rc < 0) {
-			BUG_ON(rc == -EINVAL);
-			if (rc != -EAGAIN)
-				goto removeseg;
-		} else {
-			dev_info->is_shared = 0;
-			set_disk_ro(dev_info->gd, 0);
+		list_for_each_entry(entry, &dev_info->seg_list, lh) {
+			rc = segment_modify_shared(entry->segment_name,
+						   SEGMENT_EXCLUSIVE);
+			if (rc < 0) {
+				BUG_ON(rc == -EINVAL);
+				if (rc != -EAGAIN)
+					goto removeseg;
+			}
 		}
+		dev_info->is_shared = 0;
+		set_disk_ro(dev_info->gd, 0);
 	} else {
 		rc = -EINVAL;
 		goto out;
@@ -220,8 +404,14 @@
 	goto out;
 
 removeseg:
-	PRINT_ERR("Could not reload segment %s, removing it now!\n",
-			dev_info->segment_name);
+	PRINT_ERR("Could not reload segment(s) of the device %s, removing "
+		"segment(s) now!\n",
+		dev_info->segment_name);
+	temp = entry;
+	list_for_each_entry(entry, &dev_info->seg_list, lh) {
+		if (entry != temp)
+			segment_unload(entry->segment_name);
+	}
 	list_del(&dev_info->lh);
 
 	del_gendisk(dev_info->gd);
@@ -254,6 +444,7 @@
 dcssblk_save_store(struct device *dev, struct device_attribute *attr, const char *inbuf, size_t count)
 {
 	struct dcssblk_dev_info *dev_info;
+	struct segment_info *entry;
 
 	if ((count > 1) && (inbuf[1] != '\n') && (inbuf[1] != '\0'))
 		return -EINVAL;
@@ -263,14 +454,16 @@
 	if (inbuf[0] == '1') {
 		if (atomic_read(&dev_info->use_count) == 0) {
 			// device is idle => we save immediately
-			PRINT_INFO("Saving segment %s\n",
+			PRINT_INFO("Saving segment(s) of the device %s\n",
 				   dev_info->segment_name);
-			segment_save(dev_info->segment_name);
+			list_for_each_entry(entry, &dev_info->seg_list, lh) {
+				segment_save(entry->segment_name);
+			}
 		}  else {
 			// device is busy => we save it when it becomes
 			// idle in dcssblk_release
-			PRINT_INFO("Segment %s is currently busy, it will "
-				   "be saved when it becomes idle...\n",
+			PRINT_INFO("Device %s is currently busy, segment(s) "
+				   "will be saved when it becomes idle...\n",
 				   dev_info->segment_name);
 			dev_info->save_pending = 1;
 		}
@@ -279,7 +472,8 @@
 			// device is busy & the user wants to undo his save
 			// request
 			dev_info->save_pending = 0;
-			PRINT_INFO("Pending save for segment %s deactivated\n",
+			PRINT_INFO("Pending save for segment(s) of the device "
+					"%s deactivated\n",
 					dev_info->segment_name);
 		}
 	} else {
@@ -291,66 +485,123 @@
 }
 
 /*
+ * device attribute for showing all segments in a device
+ */
+static ssize_t
+dcssblk_seglist_show(struct device *dev, struct device_attribute *attr,
+		char *buf)
+{
+	int i;
+
+	struct dcssblk_dev_info *dev_info;
+	struct segment_info *entry;
+
+	down_read(&dcssblk_devices_sem);
+	dev_info = container_of(dev, struct dcssblk_dev_info, dev);
+	i = 0;
+	buf[0] = '\0';
+	list_for_each_entry(entry, &dev_info->seg_list, lh) {
+		strcpy(&buf[i], entry->segment_name);
+		i += strlen(entry->segment_name);
+		buf[i] = '\n';
+		i++;
+	}
+	up_read(&dcssblk_devices_sem);
+	return i;
+}
+
+/*
  * device attribute for adding devices
  */
 static ssize_t
 dcssblk_add_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
 {
-	int rc, i;
+	int rc, i, j, num_of_segments;
 	struct dcssblk_dev_info *dev_info;
+	struct segment_info *seg_info, *temp;
 	char *local_buf;
 	unsigned long seg_byte_size;
 
 	dev_info = NULL;
+	seg_info = NULL;
 	if (dev != dcssblk_root_dev) {
 		rc = -EINVAL;
 		goto out_nobuf;
 	}
+	if ((count < 1) || (buf[0] == '\0') || (buf[0] == '\n')) {
+		rc = -ENAMETOOLONG;
+		goto out_nobuf;
+	}
+
 	local_buf = kmalloc(count + 1, GFP_KERNEL);
 	if (local_buf == NULL) {
 		rc = -ENOMEM;
 		goto out_nobuf;
 	}
+
 	/*
 	 * parse input
 	 */
+	num_of_segments = 0;
 	for (i = 0; ((buf[i] != '\0') && (buf[i] != '\n') && i < count); i++) {
-		local_buf[i] = toupper(buf[i]);
-	}
-	local_buf[i] = '\0';
-	if ((i == 0) || (i > 8)) {
-		rc = -ENAMETOOLONG;
-		goto out;
-	}
-	/*
-	 * already loaded?
-	 */
-	down_read(&dcssblk_devices_sem);
-	dev_info = dcssblk_get_device_by_name(local_buf);
-	up_read(&dcssblk_devices_sem);
-	if (dev_info != NULL) {
-		PRINT_WARN("Segment %s already loaded!\n", local_buf);
-		rc = -EEXIST;
-		goto out;
-	}
-	/*
-	 * get a struct dcssblk_dev_info
-	 */
-	dev_info = kzalloc(sizeof(struct dcssblk_dev_info), GFP_KERNEL);
-	if (dev_info == NULL) {
-		rc = -ENOMEM;
-		goto out;
+		for (j = i; (buf[j] != ':') &&
+			(buf[j] != '\0') &&
+			(buf[j] != '\n') &&
+			j < count; j++) {
+			local_buf[j-i] = toupper(buf[j]);
+		}
+		local_buf[j-i] = '\0';
+		if (((j - i) == 0) || ((j - i) > 8)) {
+			rc = -ENAMETOOLONG;
+			goto seg_list_del;
+		}
+
+		rc = dcssblk_load_segment(local_buf, &seg_info);
+		if (rc < 0)
+			goto seg_list_del;
+		/*
+		 * get a struct dcssblk_dev_info
+		 */
+		if (num_of_segments == 0) {
+			dev_info = kzalloc(sizeof(struct dcssblk_dev_info),
+					GFP_KERNEL);
+			if (dev_info == NULL) {
+				rc = -ENOMEM;
+				goto out;
+			}
+			strcpy(dev_info->segment_name, local_buf);
+			dev_info->segment_type = seg_info->segment_type;
+			INIT_LIST_HEAD(&dev_info->seg_list);
+		}
+		list_add_tail(&seg_info->lh, &dev_info->seg_list);
+		num_of_segments++;
+		i = j;
+
+		if ((buf[j] == '\0') || (buf[j] == '\n'))
+			break;
 	}
 
-	strcpy(dev_info->segment_name, local_buf);
-	strlcpy(dev_info->dev.bus_id, local_buf, BUS_ID_SIZE);
+	/* no trailing colon at the end of the input */
+	if ((i > 0) && (buf[i-1] == ':')) {
+		rc = -ENAMETOOLONG;
+		goto seg_list_del;
+	}
+	strlcpy(local_buf, buf, i + 1);
+	dev_info->num_of_segments = num_of_segments;
+	rc = dcssblk_is_continuous(dev_info);
+	if (rc < 0)
+		goto seg_list_del;
+
+	dev_info->start = dcssblk_find_lowest_addr(dev_info);
+	dev_info->end = dcssblk_find_highest_addr(dev_info);
+
+	dev_set_name(&dev_info->dev, dev_info->segment_name);
 	dev_info->dev.release = dcssblk_release_segment;
 	INIT_LIST_HEAD(&dev_info->lh);
-
 	dev_info->gd = alloc_disk(DCSSBLK_MINORS_PER_DISK);
 	if (dev_info->gd == NULL) {
 		rc = -ENOMEM;
-		goto free_dev_info;
+		goto seg_list_del;
 	}
 	dev_info->gd->major = dcssblk_major;
 	dev_info->gd->fops = &dcssblk_devops;
@@ -360,59 +611,43 @@
 	dev_info->gd->driverfs_dev = &dev_info->dev;
 	blk_queue_make_request(dev_info->dcssblk_queue, dcssblk_make_request);
 	blk_queue_hardsect_size(dev_info->dcssblk_queue, 4096);
-	/*
-	 * load the segment
-	 */
-	rc = segment_load(local_buf, SEGMENT_SHARED,
-				&dev_info->start, &dev_info->end);
-	if (rc < 0) {
-		segment_warning(rc, dev_info->segment_name);
-		goto dealloc_gendisk;
-	}
+
 	seg_byte_size = (dev_info->end - dev_info->start + 1);
 	set_capacity(dev_info->gd, seg_byte_size >> 9); // size in sectors
-	PRINT_INFO("Loaded segment %s, size = %lu Byte, "
+	PRINT_INFO("Loaded segment(s) %s, size = %lu Byte, "
 		   "capacity = %lu (512 Byte) sectors\n", local_buf,
 		   seg_byte_size, seg_byte_size >> 9);
 
-	dev_info->segment_type = rc;
 	dev_info->save_pending = 0;
 	dev_info->is_shared = 1;
 	dev_info->dev.parent = dcssblk_root_dev;
 
 	/*
-	 * get minor, add to list
+	 *get minor, add to list
 	 */
 	down_write(&dcssblk_devices_sem);
-	if (dcssblk_get_device_by_name(local_buf)) {
-		up_write(&dcssblk_devices_sem);
+	if (dcssblk_get_segment_by_name(local_buf)) {
 		rc = -EEXIST;
-		goto unload_seg;
+		goto release_gd;
 	}
 	rc = dcssblk_assign_free_minor(dev_info);
-	if (rc) {
-		up_write(&dcssblk_devices_sem);
-		PRINT_ERR("No free minor number available! "
-			  "Unloading segment...\n");
-		goto unload_seg;
-	}
+	if (rc)
+		goto release_gd;
 	sprintf(dev_info->gd->disk_name, "dcssblk%d",
-		dev_info->gd->first_minor);
+		MINOR(disk_devt(dev_info->gd)));
 	list_add_tail(&dev_info->lh, &dcssblk_devices);
 
 	if (!try_module_get(THIS_MODULE)) {
 		rc = -ENODEV;
-		goto list_del;
+		goto dev_list_del;
 	}
 	/*
 	 * register the device
 	 */
 	rc = device_register(&dev_info->dev);
 	if (rc) {
-		PRINT_ERR("Segment %s could not be registered RC=%d\n",
-				local_buf, rc);
 		module_put(THIS_MODULE);
-		goto list_del;
+		goto dev_list_del;
 	}
 	get_device(&dev_info->dev);
 	rc = device_create_file(&dev_info->dev, &dev_attr_shared);
@@ -421,6 +656,9 @@
 	rc = device_create_file(&dev_info->dev, &dev_attr_save);
 	if (rc)
 		goto unregister_dev;
+	rc = device_create_file(&dev_info->dev, &dev_attr_seglist);
+	if (rc)
+		goto unregister_dev;
 
 	add_disk(dev_info->gd);
 
@@ -434,7 +672,6 @@
 			set_disk_ro(dev_info->gd,0);
 			break;
 	}
-	PRINT_DEBUG("Segment %s loaded successfully\n", local_buf);
 	up_write(&dcssblk_devices_sem);
 	rc = count;
 	goto out;
@@ -445,20 +682,27 @@
 	dev_info->gd->queue = NULL;
 	put_disk(dev_info->gd);
 	device_unregister(&dev_info->dev);
-	segment_unload(dev_info->segment_name);
+	list_for_each_entry(seg_info, &dev_info->seg_list, lh) {
+		segment_unload(seg_info->segment_name);
+	}
 	put_device(&dev_info->dev);
 	up_write(&dcssblk_devices_sem);
 	goto out;
-list_del:
+dev_list_del:
 	list_del(&dev_info->lh);
-	up_write(&dcssblk_devices_sem);
-unload_seg:
-	segment_unload(local_buf);
-dealloc_gendisk:
+release_gd:
 	blk_cleanup_queue(dev_info->dcssblk_queue);
 	dev_info->gd->queue = NULL;
 	put_disk(dev_info->gd);
-free_dev_info:
+	up_write(&dcssblk_devices_sem);
+seg_list_del:
+	if (dev_info == NULL)
+		goto out;
+	list_for_each_entry_safe(seg_info, temp, &dev_info->seg_list, lh) {
+		list_del(&seg_info->lh);
+		segment_unload(seg_info->segment_name);
+		kfree(seg_info);
+	}
 	kfree(dev_info);
 out:
 	kfree(local_buf);
@@ -473,6 +717,7 @@
 dcssblk_remove_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
 {
 	struct dcssblk_dev_info *dev_info;
+	struct segment_info *entry;
 	int rc, i;
 	char *local_buf;
 
@@ -499,26 +744,28 @@
 	dev_info = dcssblk_get_device_by_name(local_buf);
 	if (dev_info == NULL) {
 		up_write(&dcssblk_devices_sem);
-		PRINT_WARN("Segment %s is not loaded!\n", local_buf);
+		PRINT_WARN("Device %s is not loaded!\n", local_buf);
 		rc = -ENODEV;
 		goto out_buf;
 	}
 	if (atomic_read(&dev_info->use_count) != 0) {
 		up_write(&dcssblk_devices_sem);
-		PRINT_WARN("Segment %s is in use!\n", local_buf);
+		PRINT_WARN("Device %s is in use!\n", local_buf);
 		rc = -EBUSY;
 		goto out_buf;
 	}
-	list_del(&dev_info->lh);
 
+	list_del(&dev_info->lh);
 	del_gendisk(dev_info->gd);
 	blk_cleanup_queue(dev_info->dcssblk_queue);
 	dev_info->gd->queue = NULL;
 	put_disk(dev_info->gd);
 	device_unregister(&dev_info->dev);
-	segment_unload(dev_info->segment_name);
-	PRINT_DEBUG("Segment %s unloaded successfully\n",
-			dev_info->segment_name);
+
+	/* unload all related segments */
+	list_for_each_entry(entry, &dev_info->seg_list, lh)
+		segment_unload(entry->segment_name);
+
 	put_device(&dev_info->dev);
 	up_write(&dcssblk_devices_sem);
 
@@ -550,6 +797,7 @@
 dcssblk_release(struct inode *inode, struct file *filp)
 {
 	struct dcssblk_dev_info *dev_info;
+	struct segment_info *entry;
 	int rc;
 
 	dev_info = inode->i_bdev->bd_disk->private_data;
@@ -560,9 +808,11 @@
 	down_write(&dcssblk_devices_sem);
 	if (atomic_dec_and_test(&dev_info->use_count)
 	    && (dev_info->save_pending)) {
-		PRINT_INFO("Segment %s became idle and is being saved now\n",
+		PRINT_INFO("Device %s became idle and is being saved now\n",
 			    dev_info->segment_name);
-		segment_save(dev_info->segment_name);
+		list_for_each_entry(entry, &dev_info->seg_list, lh) {
+			segment_save(entry->segment_name);
+		}
 		dev_info->save_pending = 0;
 	}
 	up_write(&dcssblk_devices_sem);
@@ -602,7 +852,8 @@
 		case SEG_TYPE_SC:
 			/* cannot write to these segments */
 			if (bio_data_dir(bio) == WRITE) {
-				PRINT_WARN("rejecting write to ro segment %s\n", dev_info->dev.bus_id);
+				PRINT_WARN("rejecting write to ro device %s\n",
+					   dev_name(&dev_info->dev));
 				goto fail;
 			}
 		}
@@ -657,7 +908,7 @@
 dcssblk_check_params(void)
 {
 	int rc, i, j, k;
-	char buf[9];
+	char buf[DCSSBLK_PARM_LEN + 1];
 	struct dcssblk_dev_info *dev_info;
 
 	for (i = 0; (i < DCSSBLK_PARM_LEN) && (dcssblk_segments[i] != '\0');
@@ -665,15 +916,16 @@
 		for (j = i; (dcssblk_segments[j] != ',')  &&
 			    (dcssblk_segments[j] != '\0') &&
 			    (dcssblk_segments[j] != '(')  &&
-			    (j - i) < 8; j++)
+			    (j < DCSSBLK_PARM_LEN); j++)
 		{
 			buf[j-i] = dcssblk_segments[j];
 		}
 		buf[j-i] = '\0';
 		rc = dcssblk_add_store(dcssblk_root_dev, NULL, buf, j-i);
 		if ((rc >= 0) && (dcssblk_segments[j] == '(')) {
-			for (k = 0; buf[k] != '\0'; k++)
+			for (k = 0; (buf[k] != ':') && (buf[k] != '\0'); k++)
 				buf[k] = toupper(buf[k]);
+			buf[k] = '\0';
 			if (!strncmp(&dcssblk_segments[j], "(local)", 7)) {
 				down_read(&dcssblk_devices_sem);
 				dev_info = dcssblk_get_device_by_name(buf);
@@ -740,10 +992,12 @@
 
 module_param_string(segments, dcssblk_segments, DCSSBLK_PARM_LEN, 0444);
 MODULE_PARM_DESC(segments, "Name of DCSS segment(s) to be loaded, "
-		 "comma-separated list, each name max. 8 chars.\n"
-		 "Adding \"(local)\" to segment name equals echoing 0 to "
-		 "/sys/devices/dcssblk/<segment name>/shared after loading "
-		 "the segment - \n"
-		 "e.g. segments=\"mydcss1,mydcss2,mydcss3(local)\"");
+		 "comma-separated list, names in each set separated "
+		 "by commas are separated by colons, each set contains "
+		 "names of contiguous segments and each name max. 8 chars.\n"
+		 "Adding \"(local)\" to the end of each set equals echoing 0 "
+		 "to /sys/devices/dcssblk/<device name>/shared after loading "
+		 "the contiguous segments - \n"
+		 "e.g. segments=\"mydcss1,mydcss2:mydcss3,mydcss4(local)\"");
 
 MODULE_LICENSE("GPL");
diff --git a/drivers/s390/block/xpram.c b/drivers/s390/block/xpram.c
index dd9b986..0391698 100644
--- a/drivers/s390/block/xpram.c
+++ b/drivers/s390/block/xpram.c
@@ -56,6 +56,7 @@
 static xpram_device_t xpram_devices[XPRAM_MAX_DEVS];
 static unsigned int xpram_sizes[XPRAM_MAX_DEVS];
 static struct gendisk *xpram_disks[XPRAM_MAX_DEVS];
+static struct request_queue *xpram_queues[XPRAM_MAX_DEVS];
 static unsigned int xpram_pages;
 static int xpram_devs;
 
@@ -330,18 +331,22 @@
 	return 0;
 }
 
-static struct request_queue *xpram_queue;
-
 static int __init xpram_setup_blkdev(void)
 {
 	unsigned long offset;
 	int i, rc = -ENOMEM;
 
 	for (i = 0; i < xpram_devs; i++) {
-		struct gendisk *disk = alloc_disk(1);
-		if (!disk)
+		xpram_disks[i] = alloc_disk(1);
+		if (!xpram_disks[i])
 			goto out;
-		xpram_disks[i] = disk;
+		xpram_queues[i] = blk_alloc_queue(GFP_KERNEL);
+		if (!xpram_queues[i]) {
+			put_disk(xpram_disks[i]);
+			goto out;
+		}
+		blk_queue_make_request(xpram_queues[i], xpram_make_request);
+		blk_queue_hardsect_size(xpram_queues[i], 4096);
 	}
 
 	/*
@@ -352,18 +357,6 @@
 		goto out;
 
 	/*
-	 * Assign the other needed values: make request function, sizes and
-	 * hardsect size. All the minor devices feature the same value.
-	 */
-	xpram_queue = blk_alloc_queue(GFP_KERNEL);
-	if (!xpram_queue) {
-		rc = -ENOMEM;
-		goto out_unreg;
-	}
-	blk_queue_make_request(xpram_queue, xpram_make_request);
-	blk_queue_hardsect_size(xpram_queue, 4096);
-
-	/*
 	 * Setup device structures.
 	 */
 	offset = 0;
@@ -377,18 +370,18 @@
 		disk->first_minor = i;
 		disk->fops = &xpram_devops;
 		disk->private_data = &xpram_devices[i];
-		disk->queue = xpram_queue;
+		disk->queue = xpram_queues[i];
 		sprintf(disk->disk_name, "slram%d", i);
 		set_capacity(disk, xpram_sizes[i] << 1);
 		add_disk(disk);
 	}
 
 	return 0;
-out_unreg:
-	unregister_blkdev(XPRAM_MAJOR, XPRAM_NAME);
 out:
-	while (i--)
+	while (i--) {
+		blk_cleanup_queue(xpram_queues[i]);
 		put_disk(xpram_disks[i]);
+	}
 	return rc;
 }
 
@@ -400,10 +393,10 @@
 	int i;
 	for (i = 0; i < xpram_devs; i++) {
 		del_gendisk(xpram_disks[i]);
+		blk_cleanup_queue(xpram_queues[i]);
 		put_disk(xpram_disks[i]);
 	}
 	unregister_blkdev(XPRAM_MAJOR, XPRAM_NAME);
-	blk_cleanup_queue(xpram_queue);
 }
 
 static int __init xpram_init(void)
diff --git a/drivers/s390/char/con3215.c b/drivers/s390/char/con3215.c
index d3ec9b5..9ab06e0 100644
--- a/drivers/s390/char/con3215.c
+++ b/drivers/s390/char/con3215.c
@@ -21,6 +21,7 @@
 #include <linux/console.h>
 #include <linux/interrupt.h>
 #include <linux/err.h>
+#include <linux/reboot.h>
 
 #include <linux/slab.h>
 #include <linux/bootmem.h>
@@ -88,7 +89,6 @@
 	int count;		      /* number of bytes in output buffer */
 	int written;		      /* number of bytes in write requests */
 	struct tty_struct *tty;	      /* pointer to tty structure if present */
-	struct tasklet_struct tasklet;
 	struct raw3215_req *queued_read; /* pointer to queued read requests */
 	struct raw3215_req *queued_write;/* pointer to queued write requests */
 	wait_queue_head_t empty_wait; /* wait queue for flushing */
@@ -341,21 +341,14 @@
 }
 
 /*
- * The bottom half handler routine for 3215 devices. It tries to start
- * the next IO and wakes up processes waiting on the tty.
+ * Try to start the next IO and wake up processes waiting on the tty.
  */
-static void
-raw3215_tasklet(void *data)
+static void raw3215_next_io(struct raw3215_info *raw)
 {
-	struct raw3215_info *raw;
 	struct tty_struct *tty;
-	unsigned long flags;
 
-	raw = (struct raw3215_info *) data;
-	spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags);
 	raw3215_mk_write_req(raw);
 	raw3215_try_io(raw);
-	spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags);
 	tty = raw->tty;
 	if (tty != NULL &&
 	    RAW3215_BUFFER_SIZE - raw->count >= RAW3215_MIN_SPACE) {
@@ -380,7 +373,7 @@
 	cstat = irb->scsw.cmd.cstat;
 	dstat = irb->scsw.cmd.dstat;
 	if (cstat != 0)
-		tasklet_schedule(&raw->tasklet);
+		raw3215_next_io(raw);
 	if (dstat & 0x01) { /* we got a unit exception */
 		dstat &= ~0x01;	 /* we can ignore it */
 	}
@@ -390,7 +383,7 @@
 			break;
 		/* Attention interrupt, someone hit the enter key */
 		raw3215_mk_read_req(raw);
-		tasklet_schedule(&raw->tasklet);
+		raw3215_next_io(raw);
 		break;
 	case 0x08:
 	case 0x0C:
@@ -448,7 +441,7 @@
 		    raw->queued_read == NULL) {
 			wake_up_interruptible(&raw->empty_wait);
 		}
-		tasklet_schedule(&raw->tasklet);
+		raw3215_next_io(raw);
 		break;
 	default:
 		/* Strange interrupt, I'll do my best to clean up */
@@ -460,7 +453,7 @@
 			raw->flags &= ~RAW3215_WORKING;
 			raw3215_free_req(req);
 		}
-		tasklet_schedule(&raw->tasklet);
+		raw3215_next_io(raw);
 	}
 	return;
 }
@@ -674,9 +667,6 @@
 		kfree(raw);
 		return -ENOMEM;
 	}
-	tasklet_init(&raw->tasklet,
-		     (void (*)(unsigned long)) raw3215_tasklet,
-		     (unsigned long) raw);
 	init_waitqueue_head(&raw->empty_wait);
 
 	cdev->dev.driver_data = raw;
@@ -775,11 +765,11 @@
 }
 
 /*
- * panic() calls console_unblank before the system enters a
- * disabled, endless loop.
+ * panic() calls con3215_flush through a panic_notifier
+ * before the system enters a disabled, endless loop.
  */
 static void
-con3215_unblank(void)
+con3215_flush(void)
 {
 	struct raw3215_info *raw;
 	unsigned long flags;
@@ -790,6 +780,23 @@
 	spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags);
 }
 
+static int con3215_notify(struct notifier_block *self,
+			  unsigned long event, void *data)
+{
+	con3215_flush();
+	return NOTIFY_OK;
+}
+
+static struct notifier_block on_panic_nb = {
+	.notifier_call = con3215_notify,
+	.priority = 0,
+};
+
+static struct notifier_block on_reboot_nb = {
+	.notifier_call = con3215_notify,
+	.priority = 0,
+};
+
 /*
  *  The console structure for the 3215 console
  */
@@ -797,7 +804,6 @@
 	.name	 = "ttyS",
 	.write	 = con3215_write,
 	.device	 = con3215_device,
-	.unblank = con3215_unblank,
 	.flags	 = CON_PRINTBUFFER,
 };
 
@@ -846,9 +852,6 @@
 	cdev->handler = raw3215_irq;
 
 	raw->flags |= RAW3215_FIXED;
-	tasklet_init(&raw->tasklet,
-		     (void (*)(unsigned long)) raw3215_tasklet,
-		     (unsigned long) raw);
 	init_waitqueue_head(&raw->empty_wait);
 
 	/* Request the console irq */
@@ -859,6 +862,8 @@
 		raw3215[0] = NULL;
 		return -ENODEV;
 	}
+	atomic_notifier_chain_register(&panic_notifier_list, &on_panic_nb);
+	register_reboot_notifier(&on_reboot_nb);
 	register_console(&con3215);
 	return 0;
 }
diff --git a/drivers/s390/char/con3270.c b/drivers/s390/char/con3270.c
index 3c07974..d028d2e 100644
--- a/drivers/s390/char/con3270.c
+++ b/drivers/s390/char/con3270.c
@@ -15,6 +15,7 @@
 #include <linux/list.h>
 #include <linux/types.h>
 #include <linux/err.h>
+#include <linux/reboot.h>
 
 #include <asm/ccwdev.h>
 #include <asm/cio.h>
@@ -528,11 +529,11 @@
 }
 
 /*
- * panic() calls console_unblank before the system enters a
- * disabled, endless loop.
+ * panic() calls con3270_flush through a panic_notifier
+ * before the system enters a disabled, endless loop.
  */
 static void
-con3270_unblank(void)
+con3270_flush(void)
 {
 	struct con3270 *cp;
 	unsigned long flags;
@@ -554,6 +555,23 @@
 	spin_unlock_irqrestore(&cp->view.lock, flags);
 }
 
+static int con3270_notify(struct notifier_block *self,
+			  unsigned long event, void *data)
+{
+	con3270_flush();
+	return NOTIFY_OK;
+}
+
+static struct notifier_block on_panic_nb = {
+	.notifier_call = con3270_notify,
+	.priority = 0,
+};
+
+static struct notifier_block on_reboot_nb = {
+	.notifier_call = con3270_notify,
+	.priority = 0,
+};
+
 /*
  *  The console structure for the 3270 console
  */
@@ -561,7 +579,6 @@
 	.name	 = "tty3270",
 	.write	 = con3270_write,
 	.device	 = con3270_device,
-	.unblank = con3270_unblank,
 	.flags	 = CON_PRINTBUFFER,
 };
 
@@ -623,6 +640,8 @@
 	condev->cline->len = 0;
 	con3270_create_status(condev);
 	condev->input = alloc_string(&condev->freemem, 80);
+	atomic_notifier_chain_register(&panic_notifier_list, &on_panic_nb);
+	register_reboot_notifier(&on_reboot_nb);
 	register_console(&con3270);
 	return 0;
 }
diff --git a/drivers/s390/char/fs3270.c b/drivers/s390/char/fs3270.c
index d18e6d2..40759c3 100644
--- a/drivers/s390/char/fs3270.c
+++ b/drivers/s390/char/fs3270.c
@@ -418,25 +418,22 @@
 {
 	struct fs3270 *fp;
 	struct idal_buffer *ib;
-	int minor, rc;
+	int minor, rc = 0;
 
 	if (imajor(filp->f_path.dentry->d_inode) != IBM_FS3270_MAJOR)
 		return -ENODEV;
-	lock_kernel();
 	minor = iminor(filp->f_path.dentry->d_inode);
 	/* Check for minor 0 multiplexer. */
 	if (minor == 0) {
-		struct tty_struct *tty;
-		mutex_lock(&tty_mutex);
-		tty = get_current_tty();
+		struct tty_struct *tty = get_current_tty();
 		if (!tty || tty->driver->major != IBM_TTY3270_MAJOR) {
-			mutex_unlock(&tty_mutex);
-			rc = -ENODEV;
-			goto out;
+			tty_kref_put(tty);
+			return -ENODEV;
 		}
 		minor = tty->index + RAW3270_FIRSTMINOR;
-		mutex_unlock(&tty_mutex);
+		tty_kref_put(tty);
 	}
+	lock_kernel();
 	/* Check if some other program is already using fullscreen mode. */
 	fp = (struct fs3270 *) raw3270_find_view(&fs3270_fn, minor);
 	if (!IS_ERR(fp)) {
@@ -478,7 +475,7 @@
 	filp->private_data = fp;
 out:
 	unlock_kernel();
-	return 0;
+	return rc;
 }
 
 /*
diff --git a/drivers/s390/char/raw3270.c b/drivers/s390/char/raw3270.c
index c3dee90..1792b2c 100644
--- a/drivers/s390/char/raw3270.c
+++ b/drivers/s390/char/raw3270.c
@@ -1171,7 +1171,7 @@
 	rp->clttydev = device_create_drvdata(class3270, &rp->cdev->dev,
 					     MKDEV(IBM_TTY3270_MAJOR, rp->minor),
 					     NULL,
-					     "tty%s", rp->cdev->dev.bus_id);
+					     "tty%s", dev_name(&rp->cdev->dev));
 	if (IS_ERR(rp->clttydev)) {
 		rc = PTR_ERR(rp->clttydev);
 		goto out_ttydev;
@@ -1180,7 +1180,7 @@
 	rp->cltubdev = device_create_drvdata(class3270, &rp->cdev->dev,
 					     MKDEV(IBM_FS3270_MAJOR, rp->minor),
 					     NULL,
-					     "tub%s", rp->cdev->dev.bus_id);
+					     "tub%s", dev_name(&rp->cdev->dev));
 	if (!IS_ERR(rp->cltubdev))
 		goto out;
 
diff --git a/drivers/s390/char/sclp_con.c b/drivers/s390/char/sclp_con.c
index 7e619c5..9a25c4b 100644
--- a/drivers/s390/char/sclp_con.c
+++ b/drivers/s390/char/sclp_con.c
@@ -16,6 +16,7 @@
 #include <linux/bootmem.h>
 #include <linux/termios.h>
 #include <linux/err.h>
+#include <linux/reboot.h>
 
 #include "sclp.h"
 #include "sclp_rw.h"
@@ -172,7 +173,7 @@
  * will be flushed to the SCLP.
  */
 static void
-sclp_console_unblank(void)
+sclp_console_flush(void)
 {
 	unsigned long flags;
 
@@ -188,6 +189,24 @@
 	spin_unlock_irqrestore(&sclp_con_lock, flags);
 }
 
+static int
+sclp_console_notify(struct notifier_block *self,
+			  unsigned long event, void *data)
+{
+	sclp_console_flush();
+	return NOTIFY_OK;
+}
+
+static struct notifier_block on_panic_nb = {
+	.notifier_call = sclp_console_notify,
+	.priority = 1,
+};
+
+static struct notifier_block on_reboot_nb = {
+	.notifier_call = sclp_console_notify,
+	.priority = 1,
+};
+
 /*
  * used to register the SCLP console to the kernel and to
  * give printk necessary information
@@ -197,7 +216,6 @@
 	.name = sclp_console_name,
 	.write = sclp_console_write,
 	.device = sclp_console_device,
-	.unblank = sclp_console_unblank,
 	.flags = CON_PRINTBUFFER,
 	.index = 0 /* ttyS0 */
 };
@@ -241,6 +259,8 @@
 	sclp_con_width_htab = 8;
 
 	/* enable printk-access to this driver */
+	atomic_notifier_chain_register(&panic_notifier_list, &on_panic_nb);
+	register_reboot_notifier(&on_reboot_nb);
 	register_console(&sclp_console);
 	return 0;
 }
diff --git a/drivers/s390/char/sclp_vt220.c b/drivers/s390/char/sclp_vt220.c
index ad51738..9854f19 100644
--- a/drivers/s390/char/sclp_vt220.c
+++ b/drivers/s390/char/sclp_vt220.c
@@ -24,6 +24,8 @@
 #include <linux/bootmem.h>
 #include <linux/interrupt.h>
 #include <linux/init.h>
+#include <linux/reboot.h>
+
 #include <asm/uaccess.h>
 #include "sclp.h"
 
@@ -743,24 +745,30 @@
 	return sclp_vt220_driver;
 }
 
-/*
- * This routine is called from panic when the kernel is going to give up.
- * We have to make sure that all buffers will be flushed to the SCLP.
- * Note that this function may be called from within an interrupt context.
- */
-static void
-sclp_vt220_con_unblank(void)
+static int
+sclp_vt220_notify(struct notifier_block *self,
+			  unsigned long event, void *data)
 {
 	__sclp_vt220_flush_buffer();
+	return NOTIFY_OK;
 }
 
+static struct notifier_block on_panic_nb = {
+	.notifier_call = sclp_vt220_notify,
+	.priority = 1,
+};
+
+static struct notifier_block on_reboot_nb = {
+	.notifier_call = sclp_vt220_notify,
+	.priority = 1,
+};
+
 /* Structure needed to register with printk */
 static struct console sclp_vt220_console =
 {
 	.name = SCLP_VT220_CONSOLE_NAME,
 	.write = sclp_vt220_con_write,
 	.device = sclp_vt220_con_device,
-	.unblank = sclp_vt220_con_unblank,
 	.flags = CON_PRINTBUFFER,
 	.index = SCLP_VT220_CONSOLE_INDEX
 };
@@ -776,6 +784,8 @@
 	if (rc)
 		return rc;
 	/* Attach linux console */
+	atomic_notifier_chain_register(&panic_notifier_list, &on_panic_nb);
+	register_reboot_notifier(&on_reboot_nb);
 	register_console(&sclp_vt220_console);
 	return 0;
 }
diff --git a/drivers/s390/char/tape_3590.c b/drivers/s390/char/tape_3590.c
index 8399876..4005c44 100644
--- a/drivers/s390/char/tape_3590.c
+++ b/drivers/s390/char/tape_3590.c
@@ -910,7 +910,7 @@
 	 * should proceed with the new tape... this
 	 * should probably be done in user space!
 	 */
-	PRINT_WARN("(%s): Swap Tape Device!\n", device->cdev->dev.bus_id);
+	PRINT_WARN("(%s): Swap Tape Device!\n", dev_name(&device->cdev->dev));
 	return tape_3590_erp_basic(device, request, irb, -EIO);
 }
 
@@ -1003,40 +1003,43 @@
 	/* Exception Message */
 	switch (sense->fmt.f70.emc) {
 	case 0x02:
-		PRINT_WARN("(%s): Data degraded\n", device->cdev->dev.bus_id);
+		PRINT_WARN("(%s): Data degraded\n",
+			   dev_name(&device->cdev->dev));
 		break;
 	case 0x03:
 		PRINT_WARN("(%s): Data degraded in partion %i\n",
-			   device->cdev->dev.bus_id, sense->fmt.f70.mp);
+			   dev_name(&device->cdev->dev), sense->fmt.f70.mp);
 		break;
 	case 0x04:
-		PRINT_WARN("(%s): Medium degraded\n", device->cdev->dev.bus_id);
+		PRINT_WARN("(%s): Medium degraded\n",
+			   dev_name(&device->cdev->dev));
 		break;
 	case 0x05:
 		PRINT_WARN("(%s): Medium degraded in partition %i\n",
-			   device->cdev->dev.bus_id, sense->fmt.f70.mp);
+			   dev_name(&device->cdev->dev), sense->fmt.f70.mp);
 		break;
 	case 0x06:
-		PRINT_WARN("(%s): Block 0 Error\n", device->cdev->dev.bus_id);
+		PRINT_WARN("(%s): Block 0 Error\n",
+			   dev_name(&device->cdev->dev));
 		break;
 	case 0x07:
 		PRINT_WARN("(%s): Medium Exception 0x%02x\n",
-			   device->cdev->dev.bus_id, sense->fmt.f70.md);
+			   dev_name(&device->cdev->dev), sense->fmt.f70.md);
 		break;
 	default:
 		PRINT_WARN("(%s): MIM ExMsg: 0x%02x\n",
-			   device->cdev->dev.bus_id, sense->fmt.f70.emc);
+			   dev_name(&device->cdev->dev), sense->fmt.f70.emc);
 		break;
 	}
 	/* Service Message */
 	switch (sense->fmt.f70.smc) {
 	case 0x02:
 		PRINT_WARN("(%s): Reference Media maintenance procedure %i\n",
-			   device->cdev->dev.bus_id, sense->fmt.f70.md);
+			   dev_name(&device->cdev->dev), sense->fmt.f70.md);
 		break;
 	default:
 		PRINT_WARN("(%s): MIM ServiceMsg: 0x%02x\n",
-			   device->cdev->dev.bus_id, sense->fmt.f70.smc);
+			   dev_name(&device->cdev->dev), sense->fmt.f70.smc);
 		break;
 	}
 }
@@ -1054,101 +1057,101 @@
 	switch (sense->fmt.f71.emc) {
 	case 0x01:
 		PRINT_WARN("(%s): Effect of failure is unknown\n",
-			   device->cdev->dev.bus_id);
+			   dev_name(&device->cdev->dev));
 		break;
 	case 0x02:
 		PRINT_WARN("(%s): CU Exception - no performance impact\n",
-			   device->cdev->dev.bus_id);
+			   dev_name(&device->cdev->dev));
 		break;
 	case 0x03:
 		PRINT_WARN("(%s): CU Exception on channel interface 0x%02x\n",
-			   device->cdev->dev.bus_id, sense->fmt.f71.md[0]);
+			   dev_name(&device->cdev->dev), sense->fmt.f71.md[0]);
 		break;
 	case 0x04:
 		PRINT_WARN("(%s): CU Exception on device path 0x%02x\n",
-			   device->cdev->dev.bus_id, sense->fmt.f71.md[0]);
+			   dev_name(&device->cdev->dev), sense->fmt.f71.md[0]);
 		break;
 	case 0x05:
 		PRINT_WARN("(%s): CU Exception on library path 0x%02x\n",
-			   device->cdev->dev.bus_id, sense->fmt.f71.md[0]);
+			   dev_name(&device->cdev->dev), sense->fmt.f71.md[0]);
 		break;
 	case 0x06:
 		PRINT_WARN("(%s): CU Exception on node 0x%02x\n",
-			   device->cdev->dev.bus_id, sense->fmt.f71.md[0]);
+			   dev_name(&device->cdev->dev), sense->fmt.f71.md[0]);
 		break;
 	case 0x07:
 		PRINT_WARN("(%s): CU Exception on partition 0x%02x\n",
-			   device->cdev->dev.bus_id, sense->fmt.f71.md[0]);
+			   dev_name(&device->cdev->dev), sense->fmt.f71.md[0]);
 		break;
 	default:
 		PRINT_WARN("(%s): SIM ExMsg: 0x%02x\n",
-			   device->cdev->dev.bus_id, sense->fmt.f71.emc);
+			   dev_name(&device->cdev->dev), sense->fmt.f71.emc);
 	}
 	/* Service Message */
 	switch (sense->fmt.f71.smc) {
 	case 0x01:
 		PRINT_WARN("(%s): Repair impact is unknown\n",
-			   device->cdev->dev.bus_id);
+			   dev_name(&device->cdev->dev));
 		break;
 	case 0x02:
 		PRINT_WARN("(%s): Repair will not impact cu performance\n",
-			   device->cdev->dev.bus_id);
+			   dev_name(&device->cdev->dev));
 		break;
 	case 0x03:
 		if (sense->fmt.f71.mdf == 0)
 			PRINT_WARN("(%s): Repair will disable node "
 				   "0x%x on CU\n",
-				   device->cdev->dev.bus_id,
+				   dev_name(&device->cdev->dev),
 				   sense->fmt.f71.md[1]);
 		else
 			PRINT_WARN("(%s): Repair will disable nodes "
 				   "(0x%x-0x%x) on CU\n",
-				   device->cdev->dev.bus_id,
+				   dev_name(&device->cdev->dev),
 				   sense->fmt.f71.md[1], sense->fmt.f71.md[2]);
 		break;
 	case 0x04:
 		if (sense->fmt.f71.mdf == 0)
 			PRINT_WARN("(%s): Repair will disable cannel path "
 				   "0x%x on CU\n",
-				   device->cdev->dev.bus_id,
+				   dev_name(&device->cdev->dev),
 				   sense->fmt.f71.md[1]);
 		else
 			PRINT_WARN("(%s): Repair will disable cannel paths "
 				   "(0x%x-0x%x) on CU\n",
-				   device->cdev->dev.bus_id,
+				   dev_name(&device->cdev->dev),
 				   sense->fmt.f71.md[1], sense->fmt.f71.md[2]);
 		break;
 	case 0x05:
 		if (sense->fmt.f71.mdf == 0)
 			PRINT_WARN("(%s): Repair will disable device path "
 				   "0x%x on CU\n",
-				   device->cdev->dev.bus_id,
+				   dev_name(&device->cdev->dev),
 				   sense->fmt.f71.md[1]);
 		else
 			PRINT_WARN("(%s): Repair will disable device paths "
 				   "(0x%x-0x%x) on CU\n",
-				   device->cdev->dev.bus_id,
+				   dev_name(&device->cdev->dev),
 				   sense->fmt.f71.md[1], sense->fmt.f71.md[2]);
 		break;
 	case 0x06:
 		if (sense->fmt.f71.mdf == 0)
 			PRINT_WARN("(%s): Repair will disable library path "
 				   "0x%x on CU\n",
-				   device->cdev->dev.bus_id,
+				   dev_name(&device->cdev->dev),
 				   sense->fmt.f71.md[1]);
 		else
 			PRINT_WARN("(%s): Repair will disable library paths "
 				   "(0x%x-0x%x) on CU\n",
-				   device->cdev->dev.bus_id,
+				   dev_name(&device->cdev->dev),
 				   sense->fmt.f71.md[1], sense->fmt.f71.md[2]);
 		break;
 	case 0x07:
 		PRINT_WARN("(%s): Repair will disable access to CU\n",
-			   device->cdev->dev.bus_id);
+			   dev_name(&device->cdev->dev));
 		break;
 	default:
 		PRINT_WARN("(%s): SIM ServiceMsg: 0x%02x\n",
-			   device->cdev->dev.bus_id, sense->fmt.f71.smc);
+			   dev_name(&device->cdev->dev), sense->fmt.f71.smc);
 	}
 }
 
@@ -1165,104 +1168,104 @@
 	switch (sense->fmt.f71.emc) {
 	case 0x01:
 		PRINT_WARN("(%s): Effect of failure is unknown\n",
-			   device->cdev->dev.bus_id);
+			   dev_name(&device->cdev->dev));
 		break;
 	case 0x02:
 		PRINT_WARN("(%s): DV Exception - no performance impact\n",
-			   device->cdev->dev.bus_id);
+			   dev_name(&device->cdev->dev));
 		break;
 	case 0x03:
 		PRINT_WARN("(%s): DV Exception on channel interface 0x%02x\n",
-			   device->cdev->dev.bus_id, sense->fmt.f71.md[0]);
+			   dev_name(&device->cdev->dev), sense->fmt.f71.md[0]);
 		break;
 	case 0x04:
 		PRINT_WARN("(%s): DV Exception on loader 0x%02x\n",
-			   device->cdev->dev.bus_id, sense->fmt.f71.md[0]);
+			   dev_name(&device->cdev->dev), sense->fmt.f71.md[0]);
 		break;
 	case 0x05:
 		PRINT_WARN("(%s): DV Exception on message display 0x%02x\n",
-			   device->cdev->dev.bus_id, sense->fmt.f71.md[0]);
+			   dev_name(&device->cdev->dev), sense->fmt.f71.md[0]);
 		break;
 	case 0x06:
 		PRINT_WARN("(%s): DV Exception in tape path\n",
-			   device->cdev->dev.bus_id);
+			   dev_name(&device->cdev->dev));
 		break;
 	case 0x07:
 		PRINT_WARN("(%s): DV Exception in drive\n",
-			   device->cdev->dev.bus_id);
+			   dev_name(&device->cdev->dev));
 		break;
 	default:
 		PRINT_WARN("(%s): DSIM ExMsg: 0x%02x\n",
-			   device->cdev->dev.bus_id, sense->fmt.f71.emc);
+			   dev_name(&device->cdev->dev), sense->fmt.f71.emc);
 	}
 	/* Service Message */
 	switch (sense->fmt.f71.smc) {
 	case 0x01:
 		PRINT_WARN("(%s): Repair impact is unknown\n",
-			   device->cdev->dev.bus_id);
+			   dev_name(&device->cdev->dev));
 		break;
 	case 0x02:
 		PRINT_WARN("(%s): Repair will not impact device performance\n",
-			   device->cdev->dev.bus_id);
+			   dev_name(&device->cdev->dev));
 		break;
 	case 0x03:
 		if (sense->fmt.f71.mdf == 0)
 			PRINT_WARN("(%s): Repair will disable channel path "
 				   "0x%x on DV\n",
-				   device->cdev->dev.bus_id,
+				   dev_name(&device->cdev->dev),
 				   sense->fmt.f71.md[1]);
 		else
 			PRINT_WARN("(%s): Repair will disable channel path "
 				   "(0x%x-0x%x) on DV\n",
-				   device->cdev->dev.bus_id,
+				   dev_name(&device->cdev->dev),
 				   sense->fmt.f71.md[1], sense->fmt.f71.md[2]);
 		break;
 	case 0x04:
 		if (sense->fmt.f71.mdf == 0)
 			PRINT_WARN("(%s): Repair will disable interface 0x%x "
 				   "on DV\n",
-				   device->cdev->dev.bus_id,
+				   dev_name(&device->cdev->dev),
 				   sense->fmt.f71.md[1]);
 		else
 			PRINT_WARN("(%s): Repair will disable interfaces "
 				   "(0x%x-0x%x) on DV\n",
-				   device->cdev->dev.bus_id,
+				   dev_name(&device->cdev->dev),
 				   sense->fmt.f71.md[1], sense->fmt.f71.md[2]);
 		break;
 	case 0x05:
 		if (sense->fmt.f71.mdf == 0)
 			PRINT_WARN("(%s): Repair will disable loader 0x%x "
 				   "on DV\n",
-				   device->cdev->dev.bus_id,
+				   dev_name(&device->cdev->dev),
 				   sense->fmt.f71.md[1]);
 		else
 			PRINT_WARN("(%s): Repair will disable loader "
 				   "(0x%x-0x%x) on DV\n",
-				   device->cdev->dev.bus_id,
+				   dev_name(&device->cdev->dev),
 				   sense->fmt.f71.md[1], sense->fmt.f71.md[2]);
 		break;
 	case 0x07:
 		PRINT_WARN("(%s): Repair will disable access to DV\n",
-			   device->cdev->dev.bus_id);
+			   dev_name(&device->cdev->dev));
 		break;
 	case 0x08:
 		if (sense->fmt.f71.mdf == 0)
 			PRINT_WARN("(%s): Repair will disable message "
 				   "display 0x%x on DV\n",
-				   device->cdev->dev.bus_id,
+				   dev_name(&device->cdev->dev),
 				   sense->fmt.f71.md[1]);
 		else
 			PRINT_WARN("(%s): Repair will disable message "
 				   "displays (0x%x-0x%x) on DV\n",
-				   device->cdev->dev.bus_id,
+				   dev_name(&device->cdev->dev),
 				   sense->fmt.f71.md[1], sense->fmt.f71.md[2]);
 		break;
 	case 0x09:
-		PRINT_WARN("(%s): Clean DV\n", device->cdev->dev.bus_id);
+		PRINT_WARN("(%s): Clean DV\n", dev_name(&device->cdev->dev));
 		break;
 	default:
 		PRINT_WARN("(%s): DSIM ServiceMsg: 0x%02x\n",
-			   device->cdev->dev.bus_id, sense->fmt.f71.smc);
+			   dev_name(&device->cdev->dev), sense->fmt.f71.smc);
 	}
 }
 
@@ -1279,18 +1282,18 @@
 		return;
 	if ((sense->mc > 0) && (sense->mc < TAPE_3590_MAX_MSG)) {
 		if (tape_3590_msg[sense->mc] != NULL)
-			PRINT_WARN("(%s): %s\n", device->cdev->dev.bus_id,
+			PRINT_WARN("(%s): %s\n", dev_name(&device->cdev->dev),
 				   tape_3590_msg[sense->mc]);
 		else {
 			PRINT_WARN("(%s): Message Code 0x%x\n",
-				   device->cdev->dev.bus_id, sense->mc);
+				   dev_name(&device->cdev->dev), sense->mc);
 		}
 		return;
 	}
 	if (sense->mc == 0xf0) {
 		/* Standard Media Information Message */
 		PRINT_WARN("(%s): MIM SEV=%i, MC=%02x, ES=%x/%x, "
-			   "RC=%02x-%04x-%02x\n", device->cdev->dev.bus_id,
+			   "RC=%02x-%04x-%02x\n", dev_name(&device->cdev->dev),
 			   sense->fmt.f70.sev, sense->mc,
 			   sense->fmt.f70.emc, sense->fmt.f70.smc,
 			   sense->fmt.f70.refcode, sense->fmt.f70.mid,
@@ -1302,7 +1305,7 @@
 		/* Standard I/O Subsystem Service Information Message */
 		PRINT_WARN("(%s): IOSIM SEV=%i, DEVTYPE=3590/%02x, "
 			   "MC=%02x, ES=%x/%x, REF=0x%04x-0x%04x-0x%04x\n",
-			   device->cdev->dev.bus_id, sense->fmt.f71.sev,
+			   dev_name(&device->cdev->dev), sense->fmt.f71.sev,
 			   device->cdev->id.dev_model,
 			   sense->mc, sense->fmt.f71.emc,
 			   sense->fmt.f71.smc, sense->fmt.f71.refcode1,
@@ -1314,7 +1317,7 @@
 		/* Standard Device Service Information Message */
 		PRINT_WARN("(%s): DEVSIM SEV=%i, DEVTYPE=3590/%02x, "
 			   "MC=%02x, ES=%x/%x, REF=0x%04x-0x%04x-0x%04x\n",
-			   device->cdev->dev.bus_id, sense->fmt.f71.sev,
+			   dev_name(&device->cdev->dev), sense->fmt.f71.sev,
 			   device->cdev->id.dev_model,
 			   sense->mc, sense->fmt.f71.emc,
 			   sense->fmt.f71.smc, sense->fmt.f71.refcode1,
@@ -1327,7 +1330,7 @@
 		return;
 	}
 	PRINT_WARN("(%s): Device Message(%x)\n",
-		   device->cdev->dev.bus_id, sense->mc);
+		   dev_name(&device->cdev->dev), sense->mc);
 }
 
 static int tape_3590_crypt_error(struct tape_device *device,
@@ -1336,10 +1339,11 @@
 	u8 cu_rc, ekm_rc1;
 	u16 ekm_rc2;
 	u32 drv_rc;
-	char *bus_id, *sense;
+	const char *bus_id;
+	char *sense;
 
 	sense = ((struct tape_3590_sense *) irb->ecw)->fmt.data;
-	bus_id = device->cdev->dev.bus_id;
+	bus_id = dev_name(&device->cdev->dev);
 	cu_rc = sense[0];
 	drv_rc = *((u32*) &sense[5]) & 0xffffff;
 	ekm_rc1 = sense[9];
@@ -1440,7 +1444,7 @@
 		 * "device intervention" is not very meaningfull
 		 */
 		PRINT_WARN("(%s): Tape operation when medium not loaded\n",
-			   device->cdev->dev.bus_id);
+			   dev_name(&device->cdev->dev));
 		tape_med_state_set(device, MS_UNLOADED);
 		tape_3590_schedule_work(device, TO_CRYPT_OFF);
 		return tape_3590_erp_basic(device, request, irb, -ENOMEDIUM);
@@ -1487,18 +1491,18 @@
 
 	case 0x6020:
 		PRINT_WARN("(%s): Cartridge of wrong type ?\n",
-			   device->cdev->dev.bus_id);
+			   dev_name(&device->cdev->dev));
 		return tape_3590_erp_basic(device, request, irb, -EMEDIUMTYPE);
 
 	case 0x8011:
 		PRINT_WARN("(%s): Another host has reserved the tape device\n",
-			   device->cdev->dev.bus_id);
+			   dev_name(&device->cdev->dev));
 		return tape_3590_erp_basic(device, request, irb, -EPERM);
 	case 0x8013:
 		PRINT_WARN("(%s): Another host has privileged access to the "
-			   "tape device\n", device->cdev->dev.bus_id);
+			   "tape device\n", dev_name(&device->cdev->dev));
 		PRINT_WARN("(%s): To solve the problem unload the current "
-			   "cartridge!\n", device->cdev->dev.bus_id);
+			   "cartridge!\n", dev_name(&device->cdev->dev));
 		return tape_3590_erp_basic(device, request, irb, -EPERM);
 	default:
 		return tape_3590_erp_basic(device, request, irb, -EIO);
diff --git a/drivers/s390/char/tape_block.c b/drivers/s390/char/tape_block.c
index 95da72b..a25b8bf 100644
--- a/drivers/s390/char/tape_block.c
+++ b/drivers/s390/char/tape_block.c
@@ -278,7 +278,7 @@
 
 	if (!device->blk_data.disk) {
 		PRINT_ERR("(%s): No gendisk to clean up!\n",
-			device->cdev->dev.bus_id);
+			dev_name(&device->cdev->dev));
 		goto cleanup_queue;
 	}
 
diff --git a/drivers/s390/char/tape_core.c b/drivers/s390/char/tape_core.c
index 181a544..d7073db 100644
--- a/drivers/s390/char/tape_core.c
+++ b/drivers/s390/char/tape_core.c
@@ -215,12 +215,12 @@
 	case MS_UNLOADED:
 		device->tape_generic_status |= GMT_DR_OPEN(~0);
 		PRINT_INFO("(%s): Tape is unloaded\n",
-			   device->cdev->dev.bus_id);
+			   dev_name(&device->cdev->dev));
 		break;
 	case MS_LOADED:
 		device->tape_generic_status &= ~GMT_DR_OPEN(~0);
 		PRINT_INFO("(%s): Tape has been mounted\n",
-			   device->cdev->dev.bus_id);
+			   dev_name(&device->cdev->dev));
 		break;
 	default:
 		// print nothing
@@ -415,7 +415,7 @@
 				device->cdev_id);
 			PRINT_WARN("(%s): Set offline failed "
 				"- drive in use.\n",
-				device->cdev->dev.bus_id);
+				dev_name(&device->cdev->dev));
 			spin_unlock_irq(get_ccwdev_lock(device->cdev));
 			return -EBUSY;
 	}
@@ -538,7 +538,8 @@
 	ret = sysfs_create_group(&cdev->dev.kobj, &tape_attr_group);
 	if (ret) {
 		tape_put_device(device);
-		PRINT_ERR("probe failed for tape device %s\n", cdev->dev.bus_id);
+		PRINT_ERR("probe failed for tape device %s\n",
+			  dev_name(&cdev->dev));
 		return ret;
 	}
 	cdev->dev.driver_data = device;
@@ -546,7 +547,7 @@
 	device->cdev = cdev;
 	ccw_device_get_id(cdev, &dev_id);
 	device->cdev_id = devid_to_int(&dev_id);
-	PRINT_INFO("tape device %s found\n", cdev->dev.bus_id);
+	PRINT_INFO("tape device %s found\n", dev_name(&cdev->dev));
 	return ret;
 }
 
@@ -616,7 +617,7 @@
 				device->cdev_id);
 			PRINT_WARN("(%s): Drive in use vanished - "
 				"expect trouble!\n",
-				device->cdev->dev.bus_id);
+				dev_name(&device->cdev->dev));
 			PRINT_WARN("State was %i\n", device->tape_state);
 			tape_state_set(device, TS_NOT_OPER);
 			__tape_discard_requests(device);
@@ -840,7 +841,7 @@
 	PRINT_INFO("-------------------------------------------------\n");
 	PRINT_INFO("DSTAT : %02x  CSTAT: %02x	CPA: %04x\n",
 		   irb->scsw.cmd.dstat, irb->scsw.cmd.cstat, irb->scsw.cmd.cpa);
-	PRINT_INFO("DEVICE: %s\n", device->cdev->dev.bus_id);
+	PRINT_INFO("DEVICE: %s\n", dev_name(&device->cdev->dev));
 	if (request != NULL)
 		PRINT_INFO("OP	  : %s\n", tape_op_verbose[request->op]);
 
@@ -1051,7 +1052,7 @@
 	device = (struct tape_device *) cdev->dev.driver_data;
 	if (device == NULL) {
 		PRINT_ERR("could not get device structure for %s "
-			  "in interrupt\n", cdev->dev.bus_id);
+			  "in interrupt\n", dev_name(&cdev->dev));
 		return;
 	}
 	request = (struct tape_request *) intparm;
@@ -1064,13 +1065,13 @@
 		switch (PTR_ERR(irb)) {
 			case -ETIMEDOUT:
 				PRINT_WARN("(%s): Request timed out\n",
-					cdev->dev.bus_id);
+					dev_name(&cdev->dev));
 			case -EIO:
 				__tape_end_request(device, request, -EIO);
 				break;
 			default:
 				PRINT_ERR("(%s): Unexpected i/o error %li\n",
-					cdev->dev.bus_id,
+					dev_name(&cdev->dev),
 					PTR_ERR(irb));
 		}
 		return;
diff --git a/drivers/s390/char/tape_proc.c b/drivers/s390/char/tape_proc.c
index e7c888c..8a376af 100644
--- a/drivers/s390/char/tape_proc.c
+++ b/drivers/s390/char/tape_proc.c
@@ -52,7 +52,7 @@
 		return 0;
 	spin_lock_irq(get_ccwdev_lock(device->cdev));
 	seq_printf(m, "%d\t", (int) n);
-	seq_printf(m, "%-10.10s ", device->cdev->dev.bus_id);
+	seq_printf(m, "%-10.10s ", dev_name(&device->cdev->dev));
 	seq_printf(m, "%04X/", device->cdev->id.cu_type);
 	seq_printf(m, "%02X\t", device->cdev->id.cu_model);
 	seq_printf(m, "%04X/", device->cdev->id.dev_type);
diff --git a/drivers/s390/char/tape_std.c b/drivers/s390/char/tape_std.c
index cc8fd781..5bd573d 100644
--- a/drivers/s390/char/tape_std.c
+++ b/drivers/s390/char/tape_std.c
@@ -47,7 +47,7 @@
 	rc = tape_cancel_io(device, request);
 	if(rc)
 		PRINT_ERR("(%s): Assign timeout: Cancel failed with rc = %i\n",
-			device->cdev->dev.bus_id, rc);
+			dev_name(&device->cdev->dev), rc);
 
 }
 
@@ -83,7 +83,7 @@
 
 	if (rc != 0) {
 		PRINT_WARN("%s: assign failed - device might be busy\n",
-			device->cdev->dev.bus_id);
+			dev_name(&device->cdev->dev));
 		DBF_EVENT(3, "%08x: assign failed - device might be busy\n",
 			device->cdev_id);
 	} else {
@@ -106,7 +106,7 @@
 		DBF_EVENT(3, "(%08x): Can't unassign device\n",
 			device->cdev_id);
 		PRINT_WARN("(%s): Can't unassign device - device gone\n",
-			device->cdev->dev.bus_id);
+			dev_name(&device->cdev->dev));
 		return -EIO;
 	}
 
@@ -120,7 +120,8 @@
 
 	if ((rc = tape_do_io(device, request)) != 0) {
 		DBF_EVENT(3, "%08x: Unassign failed\n", device->cdev_id);
-		PRINT_WARN("%s: Unassign failed\n", device->cdev->dev.bus_id);
+		PRINT_WARN("%s: Unassign failed\n",
+			   dev_name(&device->cdev->dev));
 	} else {
 		DBF_EVENT(3, "%08x: Tape unassigned\n", device->cdev_id);
 	}
@@ -634,10 +635,10 @@
 		DBF_EXCEPTION(6, "xcom parm\n");
 		if (*device->modeset_byte & 0x08)
 			PRINT_INFO("(%s) Compression is currently on\n",
-				   device->cdev->dev.bus_id);
+				   dev_name(&device->cdev->dev));
 		else
 			PRINT_INFO("(%s) Compression is currently off\n",
-				   device->cdev->dev.bus_id);
+				   dev_name(&device->cdev->dev));
 		PRINT_INFO("Use 1 to switch compression on, 0 to "
 			   "switch it off\n");
 		return -EINVAL;
diff --git a/drivers/s390/char/vmlogrdr.c b/drivers/s390/char/vmlogrdr.c
index c31faef..42173cc 100644
--- a/drivers/s390/char/vmlogrdr.c
+++ b/drivers/s390/char/vmlogrdr.c
@@ -724,8 +724,7 @@
 
 	dev = kzalloc(sizeof(struct device), GFP_KERNEL);
 	if (dev) {
-		snprintf(dev->bus_id, BUS_ID_SIZE, "%s",
-			 priv->internal_name);
+		dev_set_name(dev, priv->internal_name);
 		dev->bus = &iucv_bus;
 		dev->parent = iucv_root;
 		dev->driver = &vmlogrdr_driver;
@@ -751,7 +750,7 @@
 	priv->class_device = device_create_drvdata(vmlogrdr_class, dev,
 						   MKDEV(vmlogrdr_major,
 							 priv->minor_num),
-						   priv, "%s", dev->bus_id);
+						   priv, "%s", dev_name(dev));
 	if (IS_ERR(priv->class_device)) {
 		ret = PTR_ERR(priv->class_device);
 		priv->class_device=NULL;
diff --git a/drivers/s390/char/vmur.c b/drivers/s390/char/vmur.c
index c1f352b..6fdfa5d 100644
--- a/drivers/s390/char/vmur.c
+++ b/drivers/s390/char/vmur.c
@@ -886,11 +886,11 @@
 		goto fail_free_cdev;
 	if (urd->cdev->id.cu_type == READER_PUNCH_DEVTYPE) {
 		if (urd->class == DEV_CLASS_UR_I)
-			sprintf(node_id, "vmrdr-%s", cdev->dev.bus_id);
+			sprintf(node_id, "vmrdr-%s", dev_name(&cdev->dev));
 		if (urd->class == DEV_CLASS_UR_O)
-			sprintf(node_id, "vmpun-%s", cdev->dev.bus_id);
+			sprintf(node_id, "vmpun-%s", dev_name(&cdev->dev));
 	} else if (urd->cdev->id.cu_type == PRINTER_DEVTYPE) {
-		sprintf(node_id, "vmprt-%s", cdev->dev.bus_id);
+		sprintf(node_id, "vmprt-%s", dev_name(&cdev->dev));
 	} else {
 		rc = -EOPNOTSUPP;
 		goto fail_free_cdev;
diff --git a/drivers/s390/cio/blacklist.c b/drivers/s390/cio/blacklist.c
index 0bfcbbe..2f547b8 100644
--- a/drivers/s390/cio/blacklist.c
+++ b/drivers/s390/cio/blacklist.c
@@ -24,6 +24,7 @@
 #include "cio.h"
 #include "cio_debug.h"
 #include "css.h"
+#include "device.h"
 
 /*
  * "Blacklisting" of certain devices:
@@ -191,9 +192,9 @@
 			rc = blacklist_range(ra, from_ssid, to_ssid, from, to,
 					     msgtrigger);
 			if (rc)
-				totalrc = 1;
+				totalrc = -EINVAL;
 		} else
-			totalrc = 1;
+			totalrc = -EINVAL;
 	}
 
 	return totalrc;
@@ -240,8 +241,10 @@
 		rc = blacklist_parse_parameters(buf, free, 0);
 	else if (strcmp("add", parm) == 0)
 		rc = blacklist_parse_parameters(buf, add, 0);
+	else if (strcmp("purge", parm) == 0)
+		return ccw_purge_blacklisted();
 	else
-		return 1;
+		return -EINVAL;
 
 	css_schedule_reprobe();
 
@@ -353,7 +356,7 @@
 	}
 	ret = blacklist_parse_proc_parameters(buf);
 	if (ret)
-		rc = -EINVAL;
+		rc = ret;
 	else
 		rc = user_len;
 
diff --git a/drivers/s390/cio/ccwgroup.c b/drivers/s390/cio/ccwgroup.c
index e0ce65f..3ac2c20 100644
--- a/drivers/s390/cio/ccwgroup.c
+++ b/drivers/s390/cio/ccwgroup.c
@@ -113,7 +113,8 @@
 
 	for (i = 0; i < gdev->count; i++) {
 		if (gdev->cdev[i]) {
-			dev_set_drvdata(&gdev->cdev[i]->dev, NULL);
+			if (dev_get_drvdata(&gdev->cdev[i]->dev) == gdev)
+				dev_set_drvdata(&gdev->cdev[i]->dev, NULL);
 			put_device(&gdev->cdev[i]->dev);
 		}
 	}
@@ -268,8 +269,7 @@
 		goto error;
 	}
 
-	snprintf (gdev->dev.bus_id, BUS_ID_SIZE, "%s",
-			gdev->cdev[0]->dev.bus_id);
+	dev_set_name(&gdev->dev, "%s", dev_name(&gdev->cdev[0]->dev));
 
 	rc = device_add(&gdev->dev);
 	if (rc)
@@ -296,6 +296,7 @@
 			if (dev_get_drvdata(&gdev->cdev[i]->dev) == gdev)
 				dev_set_drvdata(&gdev->cdev[i]->dev, NULL);
 			put_device(&gdev->cdev[i]->dev);
+			gdev->cdev[i] = NULL;
 		}
 	mutex_unlock(&gdev->reg_mutex);
 	put_device(&gdev->dev);
diff --git a/drivers/s390/cio/chp.c b/drivers/s390/cio/chp.c
index f1216cf..1246f61 100644
--- a/drivers/s390/cio/chp.c
+++ b/drivers/s390/cio/chp.c
@@ -393,8 +393,7 @@
 	chp->state = 1;
 	chp->dev.parent = &channel_subsystems[chpid.cssid]->device;
 	chp->dev.release = chp_release;
-	snprintf(chp->dev.bus_id, BUS_ID_SIZE, "chp%x.%02x", chpid.cssid,
-		 chpid.id);
+	dev_set_name(&chp->dev, "chp%x.%02x", chpid.cssid, chpid.id);
 
 	/* Obtain channel path description and fill it in. */
 	ret = chsc_determine_base_channel_path_desc(chpid, &chp->desc);
diff --git a/drivers/s390/cio/chsc_sch.c b/drivers/s390/cio/chsc_sch.c
index 91ca87a..f49f0e5 100644
--- a/drivers/s390/cio/chsc_sch.c
+++ b/drivers/s390/cio/chsc_sch.c
@@ -261,7 +261,7 @@
 {
 	int backed_up;
 
-	if (!scsw_stctl(&request->irb.scsw) & SCSW_STCTL_STATUS_PEND)
+	if (!(scsw_stctl(&request->irb.scsw) & SCSW_STCTL_STATUS_PEND))
 		return -EIO;
 	backed_up = scsw_cstat(&request->irb.scsw) & SCHN_STAT_CHAIN_CHECK;
 	request->irb.scsw.cmd.cstat &= ~SCHN_STAT_CHAIN_CHECK;
diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c
index 5954b90..3db2c38 100644
--- a/drivers/s390/cio/cio.c
+++ b/drivers/s390/cio/cio.c
@@ -114,6 +114,7 @@
 	struct tpi_info *tpi_info;
 	struct subchannel *sch;
 	struct irb *irb;
+	int irq_context;
 
 	tpi_info = (struct tpi_info *) __LC_SUBCHANNEL_ID;
 	if (tpi (NULL) != 1)
@@ -126,7 +127,9 @@
 	sch = (struct subchannel *)(unsigned long)tpi_info->intparm;
 	if (!sch)
 		return 1;
-	local_bh_disable();
+	irq_context = in_interrupt();
+	if (!irq_context)
+		local_bh_disable();
 	irq_enter ();
 	spin_lock(sch->lock);
 	memcpy(&sch->schib.scsw, &irb->scsw, sizeof(union scsw));
@@ -134,7 +137,8 @@
 		sch->driver->irq(sch);
 	spin_unlock(sch->lock);
 	irq_exit ();
-	_local_bh_enable();
+	if (!irq_context)
+		_local_bh_enable();
 	return 1;
 }
 
@@ -153,7 +157,7 @@
 	CIO_MSG_EVENT(2, "cio_start: 'not oper' status for "
 		      "subchannel 0.%x.%04x!\n", sch->schid.ssid,
 		      sch->schid.sch_no);
-	sprintf(dbf_text, "no%s", sch->dev.bus_id);
+	sprintf(dbf_text, "no%s", dev_name(&sch->dev));
 	CIO_TRACE_EVENT(0, dbf_text);
 	CIO_HEX_EVENT(0, &sch->schib, sizeof (struct schib));
 
@@ -171,9 +175,10 @@
 	union orb *orb;
 
 	CIO_TRACE_EVENT(4, "stIO");
-	CIO_TRACE_EVENT(4, sch->dev.bus_id);
+	CIO_TRACE_EVENT(4, dev_name(&sch->dev));
 
 	orb = &to_io_private(sch)->orb;
+	memset(orb, 0, sizeof(union orb));
 	/* sch is always under 2G. */
 	orb->cmd.intparm = (u32)(addr_t)sch;
 	orb->cmd.fmt = 1;
@@ -231,7 +236,7 @@
 	int ccode;
 
 	CIO_TRACE_EVENT (4, "resIO");
-	CIO_TRACE_EVENT (4, sch->dev.bus_id);
+	CIO_TRACE_EVENT(4, dev_name(&sch->dev));
 
 	ccode = rsch (sch->schid);
 
@@ -268,7 +273,7 @@
 		return -ENODEV;
 
 	CIO_TRACE_EVENT (2, "haltIO");
-	CIO_TRACE_EVENT (2, sch->dev.bus_id);
+	CIO_TRACE_EVENT(2, dev_name(&sch->dev));
 
 	/*
 	 * Issue "Halt subchannel" and process condition code
@@ -303,7 +308,7 @@
 		return -ENODEV;
 
 	CIO_TRACE_EVENT (2, "clearIO");
-	CIO_TRACE_EVENT (2, sch->dev.bus_id);
+	CIO_TRACE_EVENT(2, dev_name(&sch->dev));
 
 	/*
 	 * Issue "Clear subchannel" and process condition code
@@ -339,7 +344,7 @@
 		return -ENODEV;
 
 	CIO_TRACE_EVENT (2, "cancelIO");
-	CIO_TRACE_EVENT (2, sch->dev.bus_id);
+	CIO_TRACE_EVENT(2, dev_name(&sch->dev));
 
 	ccode = xsch (sch->schid);
 
@@ -403,7 +408,7 @@
 	int ret;
 
 	CIO_TRACE_EVENT (2, "ensch");
-	CIO_TRACE_EVENT (2, sch->dev.bus_id);
+	CIO_TRACE_EVENT(2, dev_name(&sch->dev));
 
 	if (sch_is_pseudo_sch(sch))
 		return -EINVAL;
@@ -453,7 +458,7 @@
 	int ret;
 
 	CIO_TRACE_EVENT (2, "dissch");
-	CIO_TRACE_EVENT (2, sch->dev.bus_id);
+	CIO_TRACE_EVENT(2, dev_name(&sch->dev));
 
 	if (sch_is_pseudo_sch(sch))
 		return 0;
@@ -570,8 +575,10 @@
 	}
 	mutex_init(&sch->reg_mutex);
 	/* Set a name for the subchannel */
-	snprintf (sch->dev.bus_id, BUS_ID_SIZE, "0.%x.%04x", schid.ssid,
-		  schid.sch_no);
+	if (cio_is_console(schid))
+		sch->dev.init_name = cio_get_console_sch_name(schid);
+	else
+		dev_set_name(&sch->dev, "0.%x.%04x", schid.ssid, schid.sch_no);
 
 	/*
 	 * The first subchannel that is not-operational (ccode==3)
@@ -676,6 +683,7 @@
 
 #ifdef CONFIG_CCW_CONSOLE
 static struct subchannel console_subchannel;
+static char console_sch_name[10] = "0.x.xxxx";
 static struct io_subchannel_private console_priv;
 static int console_subchannel_in_use;
 
@@ -826,6 +834,12 @@
 	return &console_subchannel;
 }
 
+const char *cio_get_console_sch_name(struct subchannel_id schid)
+{
+	snprintf(console_sch_name, 10, "0.%x.%04x", schid.ssid, schid.sch_no);
+	return (const char *)console_sch_name;
+}
+
 #endif
 static int
 __disable_subchannel_easy(struct subchannel_id schid, struct schib *schib)
@@ -845,19 +859,6 @@
 	return -EBUSY; /* uhm... */
 }
 
-/* we can't use the normal udelay here, since it enables external interrupts */
-
-static void udelay_reset(unsigned long usecs)
-{
-	uint64_t start_cc, end_cc;
-
-	asm volatile ("STCK %0" : "=m" (start_cc));
-	do {
-		cpu_relax();
-		asm volatile ("STCK %0" : "=m" (end_cc));
-	} while (((end_cc - start_cc)/4096) < usecs);
-}
-
 static int
 __clear_io_subchannel_easy(struct subchannel_id schid)
 {
@@ -873,7 +874,7 @@
 			if (schid_equal(&ti.schid, &schid))
 				return 0;
 		}
-		udelay_reset(100);
+		udelay_simple(100);
 	}
 	return -EBUSY;
 }
@@ -881,7 +882,7 @@
 static void __clear_chsc_subchannel_easy(void)
 {
 	/* It seems we can only wait for a bit here :/ */
-	udelay_reset(100);
+	udelay_simple(100);
 }
 
 static int pgm_check_occured;
@@ -891,7 +892,7 @@
 	pgm_check_occured = 1;
 }
 
-static int stsch_reset(struct subchannel_id schid, volatile struct schib *addr)
+static int stsch_reset(struct subchannel_id schid, struct schib *addr)
 {
 	int rc;
 
diff --git a/drivers/s390/cio/cio.h b/drivers/s390/cio/cio.h
index 3b236d2..0fb2478 100644
--- a/drivers/s390/cio/cio.h
+++ b/drivers/s390/cio/cio.h
@@ -117,11 +117,15 @@
 extern struct subchannel *cio_get_console_subchannel(void);
 extern spinlock_t * cio_get_console_lock(void);
 extern void *cio_get_console_priv(void);
+extern const char *cio_get_console_sch_name(struct subchannel_id schid);
+extern const char *cio_get_console_cdev_name(struct subchannel *sch);
 #else
 #define cio_is_console(schid) 0
 #define cio_get_console_subchannel() NULL
 #define cio_get_console_lock() NULL
 #define cio_get_console_priv() NULL
+#define cio_get_console_sch_name(schid) NULL
+#define cio_get_console_cdev_name(sch) NULL
 #endif
 
 #endif
diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c
index 1261e1a..76bbb1e 100644
--- a/drivers/s390/cio/css.c
+++ b/drivers/s390/cio/css.c
@@ -698,7 +698,7 @@
 		return -ENOMEM;
 	css->pseudo_subchannel->dev.parent = &css->device;
 	css->pseudo_subchannel->dev.release = css_subchannel_release;
-	sprintf(css->pseudo_subchannel->dev.bus_id, "defunct");
+	dev_set_name(&css->pseudo_subchannel->dev, "defunct");
 	ret = cio_create_sch_lock(css->pseudo_subchannel);
 	if (ret) {
 		kfree(css->pseudo_subchannel);
@@ -707,7 +707,7 @@
 	mutex_init(&css->mutex);
 	css->valid = 1;
 	css->cssid = nr;
-	sprintf(css->device.bus_id, "css%x", nr);
+	dev_set_name(&css->device, "css%x", nr);
 	css->device.release = channel_subsystem_release;
 	tod_high = (u32) (get_clock() >> 32);
 	css_generate_pgid(css, tod_high);
diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c
index 2822103..4e78c82 100644
--- a/drivers/s390/cio/device.c
+++ b/drivers/s390/cio/device.c
@@ -31,6 +31,7 @@
 #include "device.h"
 #include "ioasm.h"
 #include "io_sch.h"
+#include "blacklist.h"
 
 static struct timer_list recovery_timer;
 static DEFINE_SPINLOCK(recovery_lock);
@@ -296,36 +297,33 @@
 		device_del(&cdev->dev);
 }
 
-static void ccw_device_remove_orphan_cb(struct device *dev)
+static void ccw_device_remove_orphan_cb(struct work_struct *work)
 {
-	struct ccw_device *cdev = to_ccwdev(dev);
+	struct ccw_device_private *priv;
+	struct ccw_device *cdev;
 
+	priv = container_of(work, struct ccw_device_private, kick_work);
+	cdev = priv->cdev;
 	ccw_device_unregister(cdev);
 	put_device(&cdev->dev);
+	/* Release cdev reference for workqueue processing. */
+	put_device(&cdev->dev);
 }
 
-static void ccw_device_remove_sch_cb(struct device *dev)
-{
-	struct subchannel *sch;
-
-	sch = to_subchannel(dev);
-	css_sch_device_unregister(sch);
-	/* Reset intparm to zeroes. */
-	sch->schib.pmcw.intparm = 0;
-	cio_modify(sch);
-	put_device(&sch->dev);
-}
+static void ccw_device_call_sch_unregister(struct work_struct *work);
 
 static void
 ccw_device_remove_disconnected(struct ccw_device *cdev)
 {
 	unsigned long flags;
-	int rc;
 
 	/*
 	 * Forced offline in disconnected state means
 	 * 'throw away device'.
 	 */
+	/* Get cdev reference for workqueue processing. */
+	if (!get_device(&cdev->dev))
+		return;
 	if (ccw_device_is_orphan(cdev)) {
 		/*
 		 * Deregister ccw device.
@@ -335,23 +333,13 @@
 		spin_lock_irqsave(cdev->ccwlock, flags);
 		cdev->private->state = DEV_STATE_NOT_OPER;
 		spin_unlock_irqrestore(cdev->ccwlock, flags);
-		rc = device_schedule_callback(&cdev->dev,
-					      ccw_device_remove_orphan_cb);
-		if (rc)
-			CIO_MSG_EVENT(0, "Couldn't unregister orphan "
-				      "0.%x.%04x\n",
-				      cdev->private->dev_id.ssid,
-				      cdev->private->dev_id.devno);
-		return;
-	}
-	/* Deregister subchannel, which will kill the ccw device. */
-	rc = device_schedule_callback(cdev->dev.parent,
-				      ccw_device_remove_sch_cb);
-	if (rc)
-		CIO_MSG_EVENT(0, "Couldn't unregister disconnected device "
-			      "0.%x.%04x\n",
-			      cdev->private->dev_id.ssid,
-			      cdev->private->dev_id.devno);
+		PREPARE_WORK(&cdev->private->kick_work,
+				ccw_device_remove_orphan_cb);
+	} else
+		/* Deregister subchannel, which will kill the ccw device. */
+		PREPARE_WORK(&cdev->private->kick_work,
+				ccw_device_call_sch_unregister);
+	queue_work(slow_path_wq, &cdev->private->kick_work);
 }
 
 /**
@@ -970,12 +958,17 @@
 
 	priv = container_of(work, struct ccw_device_private, kick_work);
 	cdev = priv->cdev;
+	/* Get subchannel reference for local processing. */
+	if (!get_device(cdev->dev.parent))
+		return;
 	sch = to_subchannel(cdev->dev.parent);
 	css_sch_device_unregister(sch);
 	/* Reset intparm to zeroes. */
 	sch->schib.pmcw.intparm = 0;
 	cio_modify(sch);
+	/* Release cdev reference for workqueue processing.*/
 	put_device(&cdev->dev);
+	/* Release subchannel reference for local processing. */
 	put_device(&sch->dev);
 }
 
@@ -1001,6 +994,8 @@
 		PREPARE_WORK(&cdev->private->kick_work,
 			     ccw_device_call_sch_unregister);
 		queue_work(slow_path_wq, &cdev->private->kick_work);
+		/* Release subchannel reference for asynchronous recognition. */
+		put_device(&sch->dev);
 		if (atomic_dec_and_test(&ccw_device_init_count))
 			wake_up(&ccw_device_init_wq);
 		break;
@@ -1040,8 +1035,11 @@
 	init_timer(&priv->timer);
 
 	/* Set an initial name for the device. */
-	snprintf (cdev->dev.bus_id, BUS_ID_SIZE, "0.%x.%04x",
-		  sch->schid.ssid, sch->schib.pmcw.dev);
+	if (cio_is_console(sch->schid))
+		cdev->dev.init_name = cio_get_console_cdev_name(sch);
+	else
+		dev_set_name(&cdev->dev, "0.%x.%04x",
+			     sch->schid.ssid, sch->schib.pmcw.dev);
 
 	/* Increase counter of devices currently in recognition. */
 	atomic_inc(&ccw_device_init_count);
@@ -1106,7 +1104,7 @@
 	cdev = sch_get_cdev(sch);
 
 	CIO_TRACE_EVENT(3, "IRQ");
-	CIO_TRACE_EVENT(3, sch->dev.bus_id);
+	CIO_TRACE_EVENT(3, dev_name(&sch->dev));
 	if (cdev)
 		dev_fsm_event(cdev, DEV_EVENT_INTERRUPT);
 }
@@ -1476,6 +1474,45 @@
 	spin_unlock_irqrestore(&recovery_lock, flags);
 }
 
+static int purge_fn(struct device *dev, void *data)
+{
+	struct ccw_device *cdev = to_ccwdev(dev);
+	struct ccw_device_private *priv = cdev->private;
+	int unreg;
+
+	spin_lock_irq(cdev->ccwlock);
+	unreg = is_blacklisted(priv->dev_id.ssid, priv->dev_id.devno) &&
+		(priv->state == DEV_STATE_OFFLINE);
+	spin_unlock_irq(cdev->ccwlock);
+	if (!unreg)
+		goto out;
+	if (!get_device(&cdev->dev))
+		goto out;
+	CIO_MSG_EVENT(3, "ccw: purging 0.%x.%04x\n", priv->dev_id.ssid,
+		      priv->dev_id.devno);
+	PREPARE_WORK(&cdev->private->kick_work, ccw_device_call_sch_unregister);
+	queue_work(slow_path_wq, &cdev->private->kick_work);
+
+out:
+	/* Abort loop in case of pending signal. */
+	if (signal_pending(current))
+		return -EINTR;
+
+	return 0;
+}
+
+/**
+ * ccw_purge_blacklisted - purge unused, blacklisted devices
+ *
+ * Unregister all ccw devices that are offline and on the blacklist.
+ */
+int ccw_purge_blacklisted(void)
+{
+	CIO_MSG_EVENT(2, "ccw: purging blacklisted devices\n");
+	bus_for_each_dev(&ccw_bus_type, NULL, NULL, purge_fn);
+	return 0;
+}
+
 static void device_set_disconnected(struct ccw_device *cdev)
 {
 	if (!cdev)
@@ -1492,7 +1529,7 @@
 	struct subchannel *sch = to_subchannel(cdev->dev.parent);
 
 	CIO_TRACE_EVENT(2, "notoper");
-	CIO_TRACE_EVENT(2, sch->dev.bus_id);
+	CIO_TRACE_EVENT(2, dev_name(&sch->dev));
 	ccw_device_set_timeout(cdev, 0);
 	cio_disable_subchannel(sch);
 	cdev->private->state = DEV_STATE_NOT_OPER;
@@ -1591,6 +1628,7 @@
 
 #ifdef CONFIG_CCW_CONSOLE
 static struct ccw_device console_cdev;
+static char console_cdev_name[10] = "0.x.xxxx";
 static struct ccw_device_private console_private;
 static int console_cdev_in_use;
 
@@ -1661,6 +1699,14 @@
 	console_cdev.online = 1;
 	return &console_cdev;
 }
+
+
+const char *cio_get_console_cdev_name(struct subchannel *sch)
+{
+	snprintf(console_cdev_name, 10, "0.%x.%04x",
+		 sch->schid.ssid, sch->schib.pmcw.dev);
+	return (const char *)console_cdev_name;
+}
 #endif
 
 /*
@@ -1673,7 +1719,7 @@
 
 	bus_id = id;
 
-	return (strncmp(bus_id, dev->bus_id, BUS_ID_SIZE) == 0);
+	return (strncmp(bus_id, dev_name(dev), BUS_ID_SIZE) == 0);
 }
 
 
diff --git a/drivers/s390/cio/device.h b/drivers/s390/cio/device.h
index 6f5c3f2..104ed66 100644
--- a/drivers/s390/cio/device.h
+++ b/drivers/s390/cio/device.h
@@ -86,6 +86,7 @@
 int ccw_device_recognition(struct ccw_device *);
 int ccw_device_online(struct ccw_device *);
 int ccw_device_offline(struct ccw_device *);
+int ccw_purge_blacklisted(void);
 
 /* Function prototypes for device status and basic sense stuff. */
 void ccw_device_accumulate_irb(struct ccw_device *, struct irb *);
diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c
index 84cc9ea..10bc039 100644
--- a/drivers/s390/cio/device_fsm.c
+++ b/drivers/s390/cio/device_fsm.c
@@ -52,8 +52,10 @@
 	printk(KERN_WARNING "cio: orb:\n");
 	print_hex_dump(KERN_WARNING, "cio:  ", DUMP_PREFIX_NONE, 16, 1,
 		       orb, sizeof(*orb), 0);
-	printk(KERN_WARNING "cio: ccw device bus id: %s\n", cdev->dev.bus_id);
-	printk(KERN_WARNING "cio: subchannel bus id: %s\n", sch->dev.bus_id);
+	printk(KERN_WARNING "cio: ccw device bus id: %s\n",
+	       dev_name(&cdev->dev));
+	printk(KERN_WARNING "cio: subchannel bus id: %s\n",
+	       dev_name(&sch->dev));
 	printk(KERN_WARNING "cio: subchannel lpm: %02x, opm: %02x, "
 	       "vpm: %02x\n", sch->lpm, sch->opm, sch->vpm);
 
diff --git a/drivers/s390/cio/device_ops.c b/drivers/s390/cio/device_ops.c
index ee1a283..eabcc42 100644
--- a/drivers/s390/cio/device_ops.c
+++ b/drivers/s390/cio/device_ops.c
@@ -498,7 +498,7 @@
 	sch = to_subchannel(cdev->dev.parent);
 	
 	CIO_TRACE_EVENT(2, "stl lock");
-	CIO_TRACE_EVENT(2, cdev->dev.bus_id);
+	CIO_TRACE_EVENT(2, dev_name(&cdev->dev));
 
 	buf = kmalloc(32*sizeof(char), GFP_DMA|GFP_KERNEL);
 	if (!buf)
diff --git a/drivers/s390/cio/io_sch.h b/drivers/s390/cio/io_sch.h
index 3f8f1cf..c4f3e7c 100644
--- a/drivers/s390/cio/io_sch.h
+++ b/drivers/s390/cio/io_sch.h
@@ -123,7 +123,7 @@
 	void *cmb_wait;			/* deferred cmb enable/disable */
 };
 
-static inline int ssch(struct subchannel_id schid, volatile union orb *addr)
+static inline int ssch(struct subchannel_id schid, union orb *addr)
 {
 	register struct subchannel_id reg1 asm("1") = schid;
 	int ccode = -EIO;
@@ -134,7 +134,9 @@
 		"	srl	%0,28\n"
 		"1:\n"
 		EX_TABLE(0b, 1b)
-		: "+d" (ccode) : "d" (reg1), "a" (addr), "m" (*addr) : "cc");
+		: "+d" (ccode)
+		: "d" (reg1), "a" (addr), "m" (*addr)
+		: "cc", "memory");
 	return ccode;
 }
 
@@ -147,7 +149,9 @@
 		"	rsch\n"
 		"	ipm	%0\n"
 		"	srl	%0,28"
-		: "=d" (ccode) : "d" (reg1) : "cc");
+		: "=d" (ccode)
+		: "d" (reg1)
+		: "cc", "memory");
 	return ccode;
 }
 
@@ -160,7 +164,9 @@
 		"	csch\n"
 		"	ipm	%0\n"
 		"	srl	%0,28"
-		: "=d" (ccode) : "d" (reg1) : "cc");
+		: "=d" (ccode)
+		: "d" (reg1)
+		: "cc");
 	return ccode;
 }
 
@@ -173,7 +179,9 @@
 		"	hsch\n"
 		"	ipm	%0\n"
 		"	srl	%0,28"
-		: "=d" (ccode) : "d" (reg1) : "cc");
+		: "=d" (ccode)
+		: "d" (reg1)
+		: "cc");
 	return ccode;
 }
 
@@ -186,7 +194,9 @@
 		"	.insn	rre,0xb2760000,%1,0\n"
 		"	ipm	%0\n"
 		"	srl	%0,28"
-		: "=d" (ccode) : "d" (reg1) : "cc");
+		: "=d" (ccode)
+		: "d" (reg1)
+		: "cc");
 	return ccode;
 }
 
diff --git a/drivers/s390/cio/ioasm.h b/drivers/s390/cio/ioasm.h
index 9fa2ac1..7592627 100644
--- a/drivers/s390/cio/ioasm.h
+++ b/drivers/s390/cio/ioasm.h
@@ -23,38 +23,39 @@
  * Some S390 specific IO instructions as inline
  */
 
-static inline int stsch(struct subchannel_id schid,
-			    volatile struct schib *addr)
+static inline int stsch(struct subchannel_id schid, struct schib *addr)
 {
 	register struct subchannel_id reg1 asm ("1") = schid;
 	int ccode;
 
 	asm volatile(
-		"	stsch	0(%2)\n"
+		"	stsch	0(%3)\n"
 		"	ipm	%0\n"
 		"	srl	%0,28"
-		: "=d" (ccode) : "d" (reg1), "a" (addr), "m" (*addr) : "cc");
+		: "=d" (ccode), "=m" (*addr)
+		: "d" (reg1), "a" (addr)
+		: "cc");
 	return ccode;
 }
 
-static inline int stsch_err(struct subchannel_id schid,
-				volatile struct schib *addr)
+static inline int stsch_err(struct subchannel_id schid, struct schib *addr)
 {
 	register struct subchannel_id reg1 asm ("1") = schid;
 	int ccode = -EIO;
 
 	asm volatile(
-		"	stsch	0(%2)\n"
+		"	stsch	0(%3)\n"
 		"0:	ipm	%0\n"
 		"	srl	%0,28\n"
 		"1:\n"
 		EX_TABLE(0b,1b)
-		: "+d" (ccode) : "d" (reg1), "a" (addr), "m" (*addr) : "cc");
+		: "+d" (ccode), "=m" (*addr)
+		: "d" (reg1), "a" (addr)
+		: "cc");
 	return ccode;
 }
 
-static inline int msch(struct subchannel_id schid,
-			   volatile struct schib *addr)
+static inline int msch(struct subchannel_id schid, struct schib *addr)
 {
 	register struct subchannel_id reg1 asm ("1") = schid;
 	int ccode;
@@ -63,12 +64,13 @@
 		"	msch	0(%2)\n"
 		"	ipm	%0\n"
 		"	srl	%0,28"
-		: "=d" (ccode) : "d" (reg1), "a" (addr), "m" (*addr) : "cc");
+		: "=d" (ccode)
+		: "d" (reg1), "a" (addr), "m" (*addr)
+		: "cc");
 	return ccode;
 }
 
-static inline int msch_err(struct subchannel_id schid,
-			       volatile struct schib *addr)
+static inline int msch_err(struct subchannel_id schid, struct schib *addr)
 {
 	register struct subchannel_id reg1 asm ("1") = schid;
 	int ccode = -EIO;
@@ -79,33 +81,38 @@
 		"	srl	%0,28\n"
 		"1:\n"
 		EX_TABLE(0b,1b)
-		: "+d" (ccode) : "d" (reg1), "a" (addr), "m" (*addr) : "cc");
+		: "+d" (ccode)
+		: "d" (reg1), "a" (addr), "m" (*addr)
+		: "cc");
 	return ccode;
 }
 
-static inline int tsch(struct subchannel_id schid,
-			   volatile struct irb *addr)
+static inline int tsch(struct subchannel_id schid, struct irb *addr)
 {
 	register struct subchannel_id reg1 asm ("1") = schid;
 	int ccode;
 
 	asm volatile(
-		"	tsch	0(%2)\n"
+		"	tsch	0(%3)\n"
 		"	ipm	%0\n"
 		"	srl	%0,28"
-		: "=d" (ccode) : "d" (reg1), "a" (addr), "m" (*addr) : "cc");
+		: "=d" (ccode), "=m" (*addr)
+		: "d" (reg1), "a" (addr)
+		: "cc");
 	return ccode;
 }
 
-static inline int tpi( volatile struct tpi_info *addr)
+static inline int tpi(struct tpi_info *addr)
 {
 	int ccode;
 
 	asm volatile(
-		"	tpi	0(%1)\n"
+		"	tpi	0(%2)\n"
 		"	ipm	%0\n"
 		"	srl	%0,28"
-		: "=d" (ccode) : "a" (addr), "m" (*addr) : "cc");
+		: "=d" (ccode), "=m" (*addr)
+		: "a" (addr)
+		: "cc");
 	return ccode;
 }
 
diff --git a/drivers/s390/cio/qdio.h b/drivers/s390/cio/qdio.h
index c1a7098..e3ea1d5 100644
--- a/drivers/s390/cio/qdio.h
+++ b/drivers/s390/cio/qdio.h
@@ -16,6 +16,14 @@
 #define QDIO_BUSY_BIT_GIVE_UP		2000000	/* 2 seconds = eternity */
 #define QDIO_INPUT_THRESHOLD		500	/* 500 microseconds */
 
+/*
+ * if an asynchronous HiperSockets queue runs full, the 10 seconds timer wait
+ * till next initiative to give transmitted skbs back to the stack is too long.
+ * Therefore polling is started in case of multicast queue is filled more
+ * than 50 percent.
+ */
+#define QDIO_IQDIO_POLL_LVL		65	/* HS multicast queue */
+
 enum qdio_irq_states {
 	QDIO_IRQ_STATE_INACTIVE,
 	QDIO_IRQ_STATE_ESTABLISHED,
@@ -195,6 +203,9 @@
 	/* PCIs are enabled for the queue */
 	int pci_out_enabled;
 
+	/* IQDIO: output multiple buffers (enhanced SIGA) */
+	int use_enh_siga;
+
 	/* timer to check for more outbound work */
 	struct timer_list timer;
 };
diff --git a/drivers/s390/cio/qdio_debug.c b/drivers/s390/cio/qdio_debug.c
index 337aa30..b539082 100644
--- a/drivers/s390/cio/qdio_debug.c
+++ b/drivers/s390/cio/qdio_debug.c
@@ -155,7 +155,7 @@
 static void get_queue_name(struct qdio_q *q, struct ccw_device *cdev, char *name)
 {
 	memset(name, 0, sizeof(name));
-	sprintf(name, "%s", cdev->dev.bus_id);
+	sprintf(name, "%s", dev_name(&cdev->dev));
 	if (q->is_input_q)
 		sprintf(name + strlen(name), "_input");
 	else
diff --git a/drivers/s390/cio/qdio_main.c b/drivers/s390/cio/qdio_main.c
index e6eabc8..a50682d 100644
--- a/drivers/s390/cio/qdio_main.c
+++ b/drivers/s390/cio/qdio_main.c
@@ -316,6 +316,9 @@
 	unsigned int fc = 0;
 	unsigned long schid;
 
+	if (q->u.out.use_enh_siga) {
+		fc = 3;
+	}
 	if (!is_qebsm(q))
 		schid = *((u32 *)&q->irq_ptr->schid);
 	else {
@@ -851,6 +854,12 @@
 	if (queue_type(q) == QDIO_IQDIO_QFMT && !multicast_outbound(q))
 		return;
 
+	if ((queue_type(q) == QDIO_IQDIO_QFMT) &&
+	    (atomic_read(&q->nr_buf_used)) > QDIO_IQDIO_POLL_LVL) {
+		tasklet_schedule(&q->tasklet);
+		return;
+	}
+
 	if (q->u.out.pci_out_enabled)
 		return;
 
@@ -956,7 +965,7 @@
 	char dbf_text[15];
 
 	QDIO_DBF_TEXT2(1, trace, "ick2");
-	sprintf(dbf_text, "%s", cdev->dev.bus_id);
+	sprintf(dbf_text, "%s", dev_name(&cdev->dev));
 	QDIO_DBF_TEXT2(1, trace, dbf_text);
 	QDIO_DBF_HEX2(0, trace, &intparm, sizeof(int));
 	QDIO_DBF_HEX2(0, trace, &dstat, sizeof(int));
@@ -1443,6 +1452,8 @@
 	}
 
 	qdio_setup_ssqd_info(irq_ptr);
+	sprintf(dbf_text, "qDmmwc%2x", irq_ptr->ssqd_desc.mmwc);
+	QDIO_DBF_TEXT2(0, setup, dbf_text);
 	sprintf(dbf_text, "qib ac%2x", irq_ptr->qib.ac);
 	QDIO_DBF_TEXT2(0, setup, dbf_text);
 
@@ -1615,12 +1626,21 @@
 		if (multicast_outbound(q))
 			qdio_kick_outbound_q(q);
 		else
-			/*
-			 * One siga-w per buffer required for unicast
-			 * HiperSockets.
-			 */
-			while (count--)
+			if ((q->irq_ptr->ssqd_desc.mmwc > 1) &&
+			    (count > 1) &&
+			    (count <= q->irq_ptr->ssqd_desc.mmwc)) {
+				/* exploit enhanced SIGA */
+				q->u.out.use_enh_siga = 1;
 				qdio_kick_outbound_q(q);
+			} else {
+				/*
+				* One siga-w per buffer required for unicast
+				* HiperSockets.
+				*/
+				q->u.out.use_enh_siga = 0;
+				while (count--)
+					qdio_kick_outbound_q(q);
+			}
 		goto out;
 	}
 
diff --git a/drivers/s390/cio/qdio_setup.c b/drivers/s390/cio/qdio_setup.c
index 1679e2f..a0b6b46 100644
--- a/drivers/s390/cio/qdio_setup.c
+++ b/drivers/s390/cio/qdio_setup.c
@@ -447,51 +447,36 @@
 {
 	char s[80];
 
-	sprintf(s, "%s sc:%x ", cdev->dev.bus_id, irq_ptr->schid.sch_no);
-
+	sprintf(s, "qdio: %s ", dev_name(&cdev->dev));
 	switch (irq_ptr->qib.qfmt) {
 	case QDIO_QETH_QFMT:
-		sprintf(s + strlen(s), "OSADE ");
+		sprintf(s + strlen(s), "OSA ");
 		break;
 	case QDIO_ZFCP_QFMT:
 		sprintf(s + strlen(s), "ZFCP ");
 		break;
 	case QDIO_IQDIO_QFMT:
-		sprintf(s + strlen(s), "HiperSockets ");
+		sprintf(s + strlen(s), "HS ");
 		break;
 	}
-	sprintf(s + strlen(s), "using: ");
-
-	if (!is_thinint_irq(irq_ptr))
-		sprintf(s + strlen(s), "no");
-	sprintf(s + strlen(s), "AdapterInterrupts ");
-	if (!(irq_ptr->sch_token != 0))
-		sprintf(s + strlen(s), "no");
-	sprintf(s + strlen(s), "QEBSM ");
-	if (!(irq_ptr->qib.ac & QIB_AC_OUTBOUND_PCI_SUPPORTED))
-		sprintf(s + strlen(s), "no");
-	sprintf(s + strlen(s), "OutboundPCI ");
-	if (!css_general_characteristics.aif_tdd)
-		sprintf(s + strlen(s), "no");
-	sprintf(s + strlen(s), "TDD\n");
-	printk(KERN_INFO "qdio: %s", s);
-
-	memset(s, 0, sizeof(s));
-	sprintf(s, "%s SIGA required: ", cdev->dev.bus_id);
-	if (irq_ptr->siga_flag.input)
-		sprintf(s + strlen(s), "Read ");
-	if (irq_ptr->siga_flag.output)
-		sprintf(s + strlen(s), "Write ");
-	if (irq_ptr->siga_flag.sync)
-		sprintf(s + strlen(s), "Sync ");
-	if (!irq_ptr->siga_flag.no_sync_ti)
-		sprintf(s + strlen(s), "SyncAI ");
-	if (!irq_ptr->siga_flag.no_sync_out_ti)
-		sprintf(s + strlen(s), "SyncOutAI ");
-	if (!irq_ptr->siga_flag.no_sync_out_pci)
-		sprintf(s + strlen(s), "SyncOutPCI");
+	sprintf(s + strlen(s), "on SC %x using ", irq_ptr->schid.sch_no);
+	sprintf(s + strlen(s), "AI:%d ", is_thinint_irq(irq_ptr));
+	sprintf(s + strlen(s), "QEBSM:%d ", (irq_ptr->sch_token) ? 1 : 0);
+	sprintf(s + strlen(s), "PCI:%d ",
+		(irq_ptr->qib.ac & QIB_AC_OUTBOUND_PCI_SUPPORTED) ? 1 : 0);
+	sprintf(s + strlen(s), "TDD:%d ", css_general_characteristics.aif_tdd);
+	sprintf(s + strlen(s), "SIGA:");
+	sprintf(s + strlen(s), "%s", (irq_ptr->siga_flag.input) ? "R" : " ");
+	sprintf(s + strlen(s), "%s", (irq_ptr->siga_flag.output) ? "W" : " ");
+	sprintf(s + strlen(s), "%s", (irq_ptr->siga_flag.sync) ? "S" : " ");
+	sprintf(s + strlen(s), "%s",
+		(!irq_ptr->siga_flag.no_sync_ti) ? "A" : " ");
+	sprintf(s + strlen(s), "%s",
+		(!irq_ptr->siga_flag.no_sync_out_ti) ? "O" : " ");
+	sprintf(s + strlen(s), "%s",
+		(!irq_ptr->siga_flag.no_sync_out_pci) ? "P" : " ");
 	sprintf(s + strlen(s), "\n");
-	printk(KERN_INFO "qdio: %s", s);
+	printk(KERN_INFO "%s", s);
 }
 
 int __init qdio_setup_init(void)
diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c
index 62b6b55..326db1e 100644
--- a/drivers/s390/crypto/ap_bus.c
+++ b/drivers/s390/crypto/ap_bus.c
@@ -892,8 +892,8 @@
 
 		ap_dev->device.bus = &ap_bus_type;
 		ap_dev->device.parent = ap_root_device;
-		snprintf(ap_dev->device.bus_id, BUS_ID_SIZE, "card%02x",
-			 AP_QID_DEVICE(ap_dev->qid));
+		dev_set_name(&ap_dev->device, "card%02x",
+			     AP_QID_DEVICE(ap_dev->qid));
 		ap_dev->device.release = ap_device_release;
 		rc = device_register(&ap_dev->device);
 		if (rc) {
diff --git a/drivers/s390/kvm/kvm_virtio.c b/drivers/s390/kvm/kvm_virtio.c
index 292b60d..ff4a693 100644
--- a/drivers/s390/kvm/kvm_virtio.c
+++ b/drivers/s390/kvm/kvm_virtio.c
@@ -24,6 +24,7 @@
 #include <asm/kvm_virtio.h>
 #include <asm/setup.h>
 #include <asm/s390_ext.h>
+#include <asm/s390_rdev.h>
 
 #define VIRTIO_SUBCODE_64 0x0D00
 
@@ -241,10 +242,7 @@
  * The root device for the kvm virtio devices.
  * This makes them appear as /sys/devices/kvm_s390/0,1,2 not /sys/devices/0,1,2.
  */
-static struct device kvm_root = {
-	.parent = NULL,
-	.bus_id = "kvm_s390",
-};
+static struct device *kvm_root;
 
 /*
  * adds a new device and register it with virtio
@@ -261,7 +259,7 @@
 		return;
 	}
 
-	kdev->vdev.dev.parent = &kvm_root;
+	kdev->vdev.dev.parent = kvm_root;
 	kdev->vdev.id.device = d->type;
 	kdev->vdev.config = &kvm_vq_configspace_ops;
 	kdev->desc = d;
@@ -317,15 +315,16 @@
 	if (!MACHINE_IS_KVM)
 		return -ENODEV;
 
-	rc = device_register(&kvm_root);
-	if (rc) {
+	kvm_root = s390_root_dev_register("kvm_s390");
+	if (IS_ERR(kvm_root)) {
+		rc = PTR_ERR(kvm_root);
 		printk(KERN_ERR "Could not register kvm_s390 root device");
 		return rc;
 	}
 
 	rc = vmem_add_mapping(PFN_PHYS(max_pfn), PAGE_SIZE);
 	if (rc) {
-		device_unregister(&kvm_root);
+		s390_root_dev_unregister(kvm_root);
 		return rc;
 	}
 
diff --git a/drivers/s390/net/claw.c b/drivers/s390/net/claw.c
index e10ac9a..f5e6185 100644
--- a/drivers/s390/net/claw.c
+++ b/drivers/s390/net/claw.c
@@ -299,7 +299,7 @@
 		probe_error(cgdev);
 		put_device(&cgdev->dev);
 		printk(KERN_WARNING "add_files failed %s %s Exit Line %d \n",
-			cgdev->cdev[0]->dev.bus_id,__func__,__LINE__);
+			dev_name(&cgdev->cdev[0]->dev), __func__, __LINE__);
 		CLAW_DBF_TEXT_(2, setup, "probex%d", rc);
 		return rc;
 	}
@@ -584,7 +584,7 @@
 	if (!cdev->dev.driver_data) {
                 printk(KERN_WARNING "claw: unsolicited interrupt for device:"
 		 	"%s received c-%02x d-%02x\n",
-		       cdev->dev.bus_id, irb->scsw.cmd.cstat,
+		       dev_name(&cdev->dev), irb->scsw.cmd.cstat,
 		       irb->scsw.cmd.dstat);
 		CLAW_DBF_TEXT(2, trace, "badirq");
                 return;
@@ -598,7 +598,7 @@
 		p_ch = &privptr->channel[WRITE];
 	else {
 		printk(KERN_WARNING "claw: Can't determine channel for "
-			"interrupt, device %s\n", cdev->dev.bus_id);
+			"interrupt, device %s\n", dev_name(&cdev->dev));
 		CLAW_DBF_TEXT(2, trace, "badchan");
 		return;
 	}
@@ -662,7 +662,7 @@
 			printk(KERN_WARNING "claw: unsolicited "
 				"interrupt for device:"
 				"%s received c-%02x d-%02x\n",
-				cdev->dev.bus_id,
+				dev_name(&cdev->dev),
 				irb->scsw.cmd.cstat,
 				irb->scsw.cmd.dstat);
 			return;
@@ -1136,19 +1136,20 @@
 			break;
 		case -ENODEV:
 			printk(KERN_EMERG "%s: Missing device called "
-				"for IO ENODEV\n", cdev->dev.bus_id);
+				"for IO ENODEV\n", dev_name(&cdev->dev));
 			break;
 		case -EIO:
 			printk(KERN_EMERG "%s: Status pending... EIO \n",
-				cdev->dev.bus_id);
+				dev_name(&cdev->dev));
 			break;
 		case -EINVAL:
 			printk(KERN_EMERG "%s: Invalid Dev State EINVAL \n",
-				cdev->dev.bus_id);
+				dev_name(&cdev->dev));
 			break;
 		default:
 			printk(KERN_EMERG "%s: Unknown error in "
-				 "Do_IO %d\n",cdev->dev.bus_id, return_code);
+				 "Do_IO %d\n", dev_name(&cdev->dev),
+			       return_code);
 		}
 	}
 	CLAW_DBF_TEXT(4, trace, "ccwret");
@@ -2848,11 +2849,11 @@
 	struct chbk *p_ch;
 	struct ccw_dev_id dev_id;
 
-	CLAW_DBF_TEXT_(2, setup, "%s", cdev->dev.bus_id);
+	CLAW_DBF_TEXT_(2, setup, "%s", dev_name(&cdev->dev));
 	privptr->channel[i].flag  = i+1;   /* Read is 1 Write is 2 */
 	p_ch = &privptr->channel[i];
 	p_ch->cdev = cdev;
-	snprintf(p_ch->id, CLAW_ID_SIZE, "cl-%s", cdev->dev.bus_id);
+	snprintf(p_ch->id, CLAW_ID_SIZE, "cl-%s", dev_name(&cdev->dev));
 	ccw_device_get_id(cdev, &dev_id);
 	p_ch->devno = dev_id.devno;
 	if ((p_ch->irb = kzalloc(sizeof (struct irb),GFP_KERNEL)) == NULL) {
@@ -2879,7 +2880,8 @@
 	int ret;
 	struct ccw_dev_id dev_id;
 
-	printk(KERN_INFO "claw: add for %s\n",cgdev->cdev[READ]->dev.bus_id);
+	printk(KERN_INFO "claw: add for %s\n",
+	       dev_name(&cgdev->cdev[READ]->dev));
 	CLAW_DBF_TEXT(2, setup, "new_dev");
 	privptr = cgdev->dev.driver_data;
 	cgdev->cdev[READ]->dev.driver_data = privptr;
@@ -2903,14 +2905,16 @@
 	if (ret != 0) {
 		printk(KERN_WARNING
 			"claw: ccw_device_set_online %s READ failed "
-			"with ret = %d\n",cgdev->cdev[READ]->dev.bus_id,ret);
+		       "with ret = %d\n", dev_name(&cgdev->cdev[READ]->dev),
+		       ret);
 		goto out;
 	}
 	ret = ccw_device_set_online(cgdev->cdev[WRITE]);
 	if (ret != 0) {
 		printk(KERN_WARNING
 			"claw: ccw_device_set_online %s WRITE failed "
-			"with ret = %d\n",cgdev->cdev[WRITE]->dev.bus_id, ret);
+		       "with ret = %d\n", dev_name(&cgdev->cdev[WRITE]->dev),
+		       ret);
 		goto out;
 	}
 	dev = alloc_netdev(0,"claw%d",claw_init_netdevice);
@@ -2986,7 +2990,7 @@
 	struct net_device *ndev;
 	int	ret;
 
-	CLAW_DBF_TEXT_(2, setup, "%s", cgdev->dev.bus_id);
+	CLAW_DBF_TEXT_(2, setup, "%s", dev_name(&cgdev->dev));
 	priv = cgdev->dev.driver_data;
 	if (!priv)
 		return -ENODEV;
@@ -3016,11 +3020,11 @@
 	struct claw_privbk *priv;
 
 	BUG_ON(!cgdev);
-	CLAW_DBF_TEXT_(2, setup, "%s", cgdev->dev.bus_id);
+	CLAW_DBF_TEXT_(2, setup, "%s", dev_name(&cgdev->dev));
 	priv = cgdev->dev.driver_data;
 	BUG_ON(!priv);
 	printk(KERN_INFO "claw: %s() called %s will be removed.\n",
-			__func__,cgdev->cdev[0]->dev.bus_id);
+			__func__, dev_name(&cgdev->cdev[0]->dev));
 	if (cgdev->state == CCWGROUP_ONLINE)
 		claw_shutdown_device(cgdev);
 	claw_remove_files(&cgdev->dev);
diff --git a/drivers/s390/net/claw.h b/drivers/s390/net/claw.h
index 1a89d98..005072c 100644
--- a/drivers/s390/net/claw.h
+++ b/drivers/s390/net/claw.h
@@ -85,7 +85,7 @@
 #define CLAW_MAX_DEV            256        /*      max claw devices          */
 #define MAX_NAME_LEN            8          /* host name, adapter name length */
 #define CLAW_FRAME_SIZE         4096
-#define CLAW_ID_SIZE            BUS_ID_SIZE+3
+#define CLAW_ID_SIZE		20+3
 
 /* state machine codes used in claw_irq_handler */
 
diff --git a/drivers/s390/net/ctcm_main.c b/drivers/s390/net/ctcm_main.c
index b11fec2..a4e29836 100644
--- a/drivers/s390/net/ctcm_main.c
+++ b/drivers/s390/net/ctcm_main.c
@@ -277,18 +277,18 @@
 
 	CTCM_DBF_TEXT_(ERROR, CTC_DBF_WARN,
 			"irb error %ld on device %s\n",
-				PTR_ERR(irb), cdev->dev.bus_id);
+				PTR_ERR(irb), dev_name(&cdev->dev));
 
 	switch (PTR_ERR(irb)) {
 	case -EIO:
-		ctcm_pr_warn("i/o-error on device %s\n", cdev->dev.bus_id);
+		ctcm_pr_warn("i/o-error on device %s\n", dev_name(&cdev->dev));
 		break;
 	case -ETIMEDOUT:
-		ctcm_pr_warn("timeout on device %s\n", cdev->dev.bus_id);
+		ctcm_pr_warn("timeout on device %s\n", dev_name(&cdev->dev));
 		break;
 	default:
 		ctcm_pr_warn("unknown error %ld on device %s\n",
-				PTR_ERR(irb), cdev->dev.bus_id);
+				PTR_ERR(irb), dev_name(&cdev->dev));
 	}
 	return PTR_ERR(irb);
 }
@@ -1182,7 +1182,7 @@
 	int dstat;
 
 	CTCM_DBF_TEXT_(TRACE, CTC_DBF_DEBUG,
-		"Enter %s(%s)", CTCM_FUNTAIL, &cdev->dev.bus_id);
+		"Enter %s(%s)", CTCM_FUNTAIL, dev_name(&cdev->dev));
 
 	if (ctcm_check_irb_error(cdev, irb))
 		return;
@@ -1208,14 +1208,14 @@
 		ch = priv->channel[WRITE];
 	else {
 		ctcm_pr_err("ctcm: Can't determine channel for interrupt, "
-			   "device %s\n", cdev->dev.bus_id);
+			   "device %s\n", dev_name(&cdev->dev));
 		return;
 	}
 
 	dev = ch->netdev;
 	if (dev == NULL) {
 		ctcm_pr_crit("ctcm: %s dev=NULL bus_id=%s, ch=0x%p\n",
-				__func__, cdev->dev.bus_id, ch);
+				__func__, dev_name(&cdev->dev), ch);
 		return;
 	}
 
@@ -1329,7 +1329,7 @@
 
 	CTCM_DBF_TEXT_(SETUP, CTC_DBF_INFO,
 		"%s(%s), type %d, proto %d",
-			__func__, cdev->dev.bus_id,	type, priv->protocol);
+			__func__, dev_name(&cdev->dev),	type, priv->protocol);
 
 	ch = kzalloc(sizeof(struct channel), GFP_KERNEL);
 	if (ch == NULL)
@@ -1358,7 +1358,7 @@
 					goto nomem_return;
 
 	ch->cdev = cdev;
-	snprintf(ch->id, CTCM_ID_SIZE, "ch-%s", cdev->dev.bus_id);
+	snprintf(ch->id, CTCM_ID_SIZE, "ch-%s", dev_name(&cdev->dev));
 	ch->type = type;
 
 	/**
@@ -1518,8 +1518,8 @@
 
 	type = get_channel_type(&cdev0->id);
 
-	snprintf(read_id, CTCM_ID_SIZE, "ch-%s", cdev0->dev.bus_id);
-	snprintf(write_id, CTCM_ID_SIZE, "ch-%s", cdev1->dev.bus_id);
+	snprintf(read_id, CTCM_ID_SIZE, "ch-%s", dev_name(&cdev0->dev));
+	snprintf(write_id, CTCM_ID_SIZE, "ch-%s", dev_name(&cdev1->dev));
 
 	ret = add_channel(cdev0, type, priv);
 	if (ret)
diff --git a/drivers/s390/net/ctcm_main.h b/drivers/s390/net/ctcm_main.h
index 8e10ee8..d77cce3 100644
--- a/drivers/s390/net/ctcm_main.h
+++ b/drivers/s390/net/ctcm_main.h
@@ -104,7 +104,7 @@
 #define READ			0
 #define WRITE			1
 
-#define CTCM_ID_SIZE		BUS_ID_SIZE+3
+#define CTCM_ID_SIZE		20+3
 
 struct ctcm_profile {
 	unsigned long maxmulti;
diff --git a/drivers/s390/net/lcs.c b/drivers/s390/net/lcs.c
index 9bcfa04..0825be8 100644
--- a/drivers/s390/net/lcs.c
+++ b/drivers/s390/net/lcs.c
@@ -492,7 +492,7 @@
 	unsigned long flags;
 	int rc;
 
-	LCS_DBF_TEXT_(4,trace,"ssch%s", channel->ccwdev->dev.bus_id);
+	LCS_DBF_TEXT_(4, trace,"ssch%s", dev_name(&channel->ccwdev->dev));
 	spin_lock_irqsave(get_ccwdev_lock(channel->ccwdev), flags);
 	rc = ccw_device_start(channel->ccwdev,
 			      channel->ccws + channel->io_idx, 0, 0,
@@ -501,7 +501,8 @@
 		channel->state = LCS_CH_STATE_RUNNING;
 	spin_unlock_irqrestore(get_ccwdev_lock(channel->ccwdev), flags);
 	if (rc) {
-		LCS_DBF_TEXT_(4,trace,"essh%s", channel->ccwdev->dev.bus_id);
+		LCS_DBF_TEXT_(4,trace,"essh%s",
+			      dev_name(&channel->ccwdev->dev));
 		PRINT_ERR("Error in starting channel, rc=%d!\n", rc);
 	}
 	return rc;
@@ -514,12 +515,13 @@
 	int rc;
 
 	LCS_DBF_TEXT(4,trace,"clearch");
-	LCS_DBF_TEXT_(4,trace,"%s", channel->ccwdev->dev.bus_id);
+	LCS_DBF_TEXT_(4, trace, "%s", dev_name(&channel->ccwdev->dev));
 	spin_lock_irqsave(get_ccwdev_lock(channel->ccwdev), flags);
 	rc = ccw_device_clear(channel->ccwdev, (addr_t) channel);
 	spin_unlock_irqrestore(get_ccwdev_lock(channel->ccwdev), flags);
 	if (rc) {
-		LCS_DBF_TEXT_(4,trace,"ecsc%s", channel->ccwdev->dev.bus_id);
+		LCS_DBF_TEXT_(4, trace, "ecsc%s",
+			      dev_name(&channel->ccwdev->dev));
 		return rc;
 	}
 	wait_event(channel->wait_q, (channel->state == LCS_CH_STATE_CLEARED));
@@ -540,13 +542,14 @@
 	if (channel->state == LCS_CH_STATE_STOPPED)
 		return 0;
 	LCS_DBF_TEXT(4,trace,"haltsch");
-	LCS_DBF_TEXT_(4,trace,"%s", channel->ccwdev->dev.bus_id);
+	LCS_DBF_TEXT_(4, trace, "%s", dev_name(&channel->ccwdev->dev));
 	channel->state = LCS_CH_STATE_INIT;
 	spin_lock_irqsave(get_ccwdev_lock(channel->ccwdev), flags);
 	rc = ccw_device_halt(channel->ccwdev, (addr_t) channel);
 	spin_unlock_irqrestore(get_ccwdev_lock(channel->ccwdev), flags);
 	if (rc) {
-		LCS_DBF_TEXT_(4,trace,"ehsc%s", channel->ccwdev->dev.bus_id);
+		LCS_DBF_TEXT_(4, trace, "ehsc%s",
+			      dev_name(&channel->ccwdev->dev));
 		return rc;
 	}
 	/* Asynchronous halt initialted. Wait for its completion. */
@@ -632,10 +635,11 @@
 		return 0;
 	if (channel->ccws[channel->io_idx].flags & CCW_FLAG_SUSPEND)
 		return 0;
-	LCS_DBF_TEXT_(5, trace, "rsch%s", channel->ccwdev->dev.bus_id);
+	LCS_DBF_TEXT_(5, trace, "rsch%s", dev_name(&channel->ccwdev->dev));
 	rc = ccw_device_resume(channel->ccwdev);
 	if (rc) {
-		LCS_DBF_TEXT_(4, trace, "ersc%s", channel->ccwdev->dev.bus_id);
+		LCS_DBF_TEXT_(4, trace, "ersc%s",
+			      dev_name(&channel->ccwdev->dev));
 		PRINT_ERR("Error in lcs_resume_channel: rc=%d\n",rc);
 	} else
 		channel->state = LCS_CH_STATE_RUNNING;
@@ -1302,18 +1306,18 @@
 
 	switch (PTR_ERR(irb)) {
 	case -EIO:
-		PRINT_WARN("i/o-error on device %s\n", cdev->dev.bus_id);
+		PRINT_WARN("i/o-error on device %s\n", dev_name(&cdev->dev));
 		LCS_DBF_TEXT(2, trace, "ckirberr");
 		LCS_DBF_TEXT_(2, trace, "  rc%d", -EIO);
 		break;
 	case -ETIMEDOUT:
-		PRINT_WARN("timeout on device %s\n", cdev->dev.bus_id);
+		PRINT_WARN("timeout on device %s\n", dev_name(&cdev->dev));
 		LCS_DBF_TEXT(2, trace, "ckirberr");
 		LCS_DBF_TEXT_(2, trace, "  rc%d", -ETIMEDOUT);
 		break;
 	default:
 		PRINT_WARN("unknown error %ld on device %s\n", PTR_ERR(irb),
-			   cdev->dev.bus_id);
+			   dev_name(&cdev->dev));
 		LCS_DBF_TEXT(2, trace, "ckirberr");
 		LCS_DBF_TEXT(2, trace, "  rc???");
 	}
@@ -1390,7 +1394,7 @@
 
 	cstat = irb->scsw.cmd.cstat;
 	dstat = irb->scsw.cmd.dstat;
-	LCS_DBF_TEXT_(5, trace, "Rint%s",cdev->dev.bus_id);
+	LCS_DBF_TEXT_(5, trace, "Rint%s", dev_name(&cdev->dev));
 	LCS_DBF_TEXT_(5, trace, "%4x%4x", irb->scsw.cmd.cstat,
 		      irb->scsw.cmd.dstat);
 	LCS_DBF_TEXT_(5, trace, "%4x%4x", irb->scsw.cmd.fctl,
@@ -1400,7 +1404,7 @@
 	rc = lcs_get_problem(cdev, irb);
 	if (rc || (dstat & DEV_STAT_UNIT_EXCEP)) {
 		PRINT_WARN("check on device %s, dstat=0x%X, cstat=0x%X \n",
-			    cdev->dev.bus_id, dstat, cstat);
+			    dev_name(&cdev->dev), dstat, cstat);
 		if (rc) {
 			channel->state = LCS_CH_STATE_ERROR;
 		}
@@ -1463,7 +1467,7 @@
 	int rc;
 
 	channel = (struct lcs_channel *) data;
-	LCS_DBF_TEXT_(5, trace, "tlet%s",channel->ccwdev->dev.bus_id);
+	LCS_DBF_TEXT_(5, trace, "tlet%s", dev_name(&channel->ccwdev->dev));
 
 	/* Check for processed buffers. */
 	iob = channel->iob;
@@ -2244,7 +2248,7 @@
 		return 0;
 	LCS_DBF_TEXT(4, trace, "recover2");
 	gdev = card->gdev;
-	PRINT_WARN("Recovery of device %s started...\n", gdev->dev.bus_id);
+	PRINT_WARN("Recovery of device %s started...\n", dev_name(&gdev->dev));
 	rc = __lcs_shutdown_device(gdev, 1);
 	rc = lcs_new_device(gdev);
 	if (!rc)
diff --git a/drivers/s390/net/netiucv.c b/drivers/s390/net/netiucv.c
index 9242b5a..0fea51e 100644
--- a/drivers/s390/net/netiucv.c
+++ b/drivers/s390/net/netiucv.c
@@ -1724,7 +1724,7 @@
 	IUCV_DBF_TEXT(trace, 3, __func__);
 
 	if (dev) {
-		snprintf(dev->bus_id, BUS_ID_SIZE, "net%s", ndev->name);
+		dev_set_name(dev, "net%s", ndev->name);
 		dev->bus = &iucv_bus;
 		dev->parent = iucv_root;
 		/*
diff --git a/drivers/s390/net/qeth_core.h b/drivers/s390/net/qeth_core.h
index bf8a75c..af6d604 100644
--- a/drivers/s390/net/qeth_core.h
+++ b/drivers/s390/net/qeth_core.h
@@ -90,11 +90,11 @@
 #define CARD_RDEV(card) card->read.ccwdev
 #define CARD_WDEV(card) card->write.ccwdev
 #define CARD_DDEV(card) card->data.ccwdev
-#define CARD_BUS_ID(card) card->gdev->dev.bus_id
-#define CARD_RDEV_ID(card) card->read.ccwdev->dev.bus_id
-#define CARD_WDEV_ID(card) card->write.ccwdev->dev.bus_id
-#define CARD_DDEV_ID(card) card->data.ccwdev->dev.bus_id
-#define CHANNEL_ID(channel) channel->ccwdev->dev.bus_id
+#define CARD_BUS_ID(card) dev_name(&card->gdev->dev)
+#define CARD_RDEV_ID(card) dev_name(&card->read.ccwdev->dev)
+#define CARD_WDEV_ID(card) dev_name(&card->write.ccwdev->dev)
+#define CARD_DDEV_ID(card) dev_name(&card->data.ccwdev->dev)
+#define CHANNEL_ID(channel) dev_name(&channel->ccwdev->dev)
 
 /**
  * card stuff
diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c
index c7ab1b8..7de410d 100644
--- a/drivers/s390/net/qeth_core_main.c
+++ b/drivers/s390/net/qeth_core_main.c
@@ -745,7 +745,7 @@
 		     SCHN_STAT_PROT_CHECK | SCHN_STAT_PROG_CHECK)) {
 		QETH_DBF_TEXT(TRACE, 2, "CGENCHK");
 		PRINT_WARN("check on device %s, dstat=x%x, cstat=x%x ",
-			   cdev->dev.bus_id, dstat, cstat);
+			   dev_name(&cdev->dev), dstat, cstat);
 		print_hex_dump(KERN_WARNING, "qeth: irb ", DUMP_PREFIX_OFFSET,
 				16, 1, irb, 64, 1);
 		return 1;
@@ -760,7 +760,7 @@
 		if (sense[SENSE_COMMAND_REJECT_BYTE] &
 		    SENSE_COMMAND_REJECT_FLAG) {
 			QETH_DBF_TEXT(TRACE, 2, "CMDREJi");
-			return 0;
+			return 1;
 		}
 		if ((sense[2] == 0xaf) && (sense[3] == 0xfe)) {
 			QETH_DBF_TEXT(TRACE, 2, "AFFE");
@@ -784,12 +784,12 @@
 
 	switch (PTR_ERR(irb)) {
 	case -EIO:
-		PRINT_WARN("i/o-error on device %s\n", cdev->dev.bus_id);
+		PRINT_WARN("i/o-error on device %s\n", dev_name(&cdev->dev));
 		QETH_DBF_TEXT(TRACE, 2, "ckirberr");
 		QETH_DBF_TEXT_(TRACE, 2, "  rc%d", -EIO);
 		break;
 	case -ETIMEDOUT:
-		PRINT_WARN("timeout on device %s\n", cdev->dev.bus_id);
+		PRINT_WARN("timeout on device %s\n", dev_name(&cdev->dev));
 		QETH_DBF_TEXT(TRACE, 2, "ckirberr");
 		QETH_DBF_TEXT_(TRACE, 2, "  rc%d", -ETIMEDOUT);
 		if (intparm == QETH_RCD_PARM) {
@@ -803,7 +803,7 @@
 		break;
 	default:
 		PRINT_WARN("unknown error %ld on device %s\n", PTR_ERR(irb),
-			   cdev->dev.bus_id);
+			   dev_name(&cdev->dev));
 		QETH_DBF_TEXT(TRACE, 2, "ckirberr");
 		QETH_DBF_TEXT(TRACE, 2, "  rc???");
 	}
@@ -884,6 +884,7 @@
 		}
 		rc = qeth_get_problem(cdev, irb);
 		if (rc) {
+			qeth_clear_ipacmd_list(card);
 			qeth_schedule_recovery(card);
 			goto out;
 		}
@@ -4081,7 +4082,7 @@
 	if (!get_device(dev))
 		return -ENODEV;
 
-	QETH_DBF_TEXT_(SETUP, 2, "%s", gdev->dev.bus_id);
+	QETH_DBF_TEXT_(SETUP, 2, "%s", dev_name(&gdev->dev));
 
 	card = qeth_alloc_card();
 	if (!card) {
@@ -4147,6 +4148,7 @@
 	unsigned long flags;
 	struct qeth_card *card = dev_get_drvdata(&gdev->dev);
 
+	QETH_DBF_TEXT(SETUP, 2, "removedv");
 	if (card->discipline.ccwgdriver) {
 		card->discipline.ccwgdriver->remove(gdev);
 		qeth_core_free_discipline(card);
diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c
index 3ac3cc1..955ba7a 100644
--- a/drivers/s390/net/qeth_l2_main.c
+++ b/drivers/s390/net/qeth_l2_main.c
@@ -395,7 +395,8 @@
 	}
 	if (card->state == CARD_STATE_SOFTSETUP) {
 		qeth_l2_process_vlans(card, 1);
-		qeth_l2_del_all_mc(card);
+		if (!card->use_hard_stop)
+			qeth_l2_del_all_mc(card);
 		qeth_clear_ipacmd_list(card);
 		card->state = CARD_STATE_HARDSETUP;
 	}
@@ -559,7 +560,8 @@
 			"device %s: x%x\n", CARD_BUS_ID(card), rc);
 	}
 
-	if (card->info.guestlan) {
+	if ((card->info.type == QETH_CARD_TYPE_IQD) || 
+	    (card->info.guestlan)) {
 		rc = qeth_setadpparms_change_macaddr(card);
 		if (rc) {
 			QETH_DBF_MESSAGE(2, "couldn't get MAC address on "
@@ -825,7 +827,6 @@
 	}
 	card->data.state = CH_STATE_UP;
 	card->state = CARD_STATE_UP;
-	card->dev->flags |= IFF_UP;
 	netif_start_queue(dev);
 
 	if (!card->lan_online && netif_carrier_ok(dev))
@@ -840,7 +841,6 @@
 
 	QETH_DBF_TEXT(TRACE, 4, "qethstop");
 	netif_tx_disable(dev);
-	card->dev->flags &= ~IFF_UP;
 	if (card->state == CARD_STATE_UP)
 		card->state = CARD_STATE_SOFTSETUP;
 	return 0;
@@ -1137,9 +1137,13 @@
 	if (!rc)
 		PRINT_INFO("Device %s successfully recovered!\n",
 			   CARD_BUS_ID(card));
-	else
+	else {
+		rtnl_lock();
+		dev_close(card->dev);
+		rtnl_unlock();
 		PRINT_INFO("Device %s could not be recovered!\n",
 			   CARD_BUS_ID(card));
+	}
 	return 0;
 }
 
diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c
index dd72c3c..99547de 100644
--- a/drivers/s390/net/qeth_l3_main.c
+++ b/drivers/s390/net/qeth_l3_main.c
@@ -2795,7 +2795,6 @@
 		return -ENODEV;
 	card->data.state = CH_STATE_UP;
 	card->state = CARD_STATE_UP;
-	card->dev->flags |= IFF_UP;
 	netif_start_queue(dev);
 
 	if (!card->lan_online && netif_carrier_ok(dev))
@@ -2809,7 +2808,6 @@
 
 	QETH_DBF_TEXT(TRACE, 4, "qethstop");
 	netif_tx_disable(dev);
-	card->dev->flags &= ~IFF_UP;
 	if (card->state == CARD_STATE_UP)
 		card->state = CARD_STATE_SOFTSETUP;
 	return 0;
@@ -3218,9 +3216,13 @@
 	if (!rc)
 		PRINT_INFO("Device %s successfully recovered!\n",
 			   CARD_BUS_ID(card));
-	else
+	else {
+		rtnl_lock();
+		dev_close(card->dev);
+		rtnl_unlock();
 		PRINT_INFO("Device %s could not be recovered!\n",
 			   CARD_BUS_ID(card));
+	}
 	return 0;
 }
 
diff --git a/drivers/s390/s390_rdev.c b/drivers/s390/s390_rdev.c
index 3c7145d..64371c0 100644
--- a/drivers/s390/s390_rdev.c
+++ b/drivers/s390/s390_rdev.c
@@ -30,7 +30,7 @@
 	dev = kzalloc(sizeof(struct device), GFP_KERNEL);
 	if (!dev)
 		return ERR_PTR(-ENOMEM);
-	strncpy(dev->bus_id, name, min(strlen(name), (size_t)BUS_ID_SIZE));
+	dev_set_name(dev, name);
 	dev->release = s390_root_dev_release;
 	ret = device_register(dev);
 	if (ret) {
diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c
index 90abfd0..3b56220 100644
--- a/drivers/s390/scsi/zfcp_aux.c
+++ b/drivers/s390/scsi/zfcp_aux.c
@@ -88,11 +88,13 @@
 	strncpy(zfcp_data.init_busid, token, BUS_ID_SIZE);
 
 	token = strsep(&str, ",");
-	if (!token || strict_strtoull(token, 0, &zfcp_data.init_wwpn))
+	if (!token || strict_strtoull(token, 0,
+				(unsigned long long *) &zfcp_data.init_wwpn))
 		goto err_out;
 
 	token = strsep(&str, ",");
-	if (!token || strict_strtoull(token, 0, &zfcp_data.init_fcp_lun))
+	if (!token || strict_strtoull(token, 0,
+				(unsigned long long *) &zfcp_data.init_fcp_lun))
 		goto err_out;
 
 	kfree(str);
@@ -100,24 +102,10 @@
 
  err_out:
 	kfree(str);
-	pr_err("zfcp: Parse error for device parameter string %s, "
-	       "device not attached.\n", devstr);
+	pr_err("zfcp: %s is not a valid SCSI device\n", devstr);
 	return 0;
 }
 
-static struct zfcp_adapter *zfcp_get_adapter_by_busid(char *bus_id)
-{
-	struct zfcp_adapter *adapter;
-
-	list_for_each_entry(adapter, &zfcp_data.adapter_list_head, list)
-		if ((strncmp(bus_id, adapter->ccw_device->dev.bus_id,
-			     BUS_ID_SIZE) == 0) &&
-		    !(atomic_read(&adapter->status) &
-		      ZFCP_STATUS_COMMON_REMOVE))
-		    return adapter;
-	return NULL;
-}
-
 static void __init zfcp_init_device_configure(void)
 {
 	struct zfcp_adapter *adapter;
@@ -141,7 +129,12 @@
 		goto out_unit;
 	up(&zfcp_data.config_sema);
 	ccw_device_set_online(adapter->ccw_device);
+
 	zfcp_erp_wait(adapter);
+	wait_event(adapter->erp_done_wqh,
+		   !(atomic_read(&unit->status) &
+				ZFCP_STATUS_UNIT_SCSI_WORK_PENDING));
+
 	down(&zfcp_data.config_sema);
 	zfcp_unit_put(unit);
 out_unit:
@@ -180,9 +173,9 @@
 	if (!zfcp_data.gid_pn_cache)
 		goto out_gid_cache;
 
-	INIT_LIST_HEAD(&zfcp_data.adapter_list_head);
-	INIT_LIST_HEAD(&zfcp_data.adapter_remove_lh);
+	zfcp_data.work_queue = create_singlethread_workqueue("zfcp_wq");
 
+	INIT_LIST_HEAD(&zfcp_data.adapter_list_head);
 	sema_init(&zfcp_data.config_sema, 1);
 	rwlock_init(&zfcp_data.config_lock);
 
@@ -193,13 +186,14 @@
 
 	retval = misc_register(&zfcp_cfdc_misc);
 	if (retval) {
-		pr_err("zfcp: registration of misc device zfcp_cfdc failed\n");
+		pr_err("zfcp: Registering the misc device zfcp_cfdc failed\n");
 		goto out_misc;
 	}
 
 	retval = zfcp_ccw_register();
 	if (retval) {
-		pr_err("zfcp: Registration with common I/O layer failed.\n");
+		pr_err("zfcp: The zfcp device driver could not register with "
+		       "the common I/O layer\n");
 		goto out_ccw_register;
 	}
 
@@ -231,8 +225,7 @@
  *
  * Returns: pointer to zfcp_unit or NULL
  */
-struct zfcp_unit *zfcp_get_unit_by_lun(struct zfcp_port *port,
-				       fcp_lun_t fcp_lun)
+struct zfcp_unit *zfcp_get_unit_by_lun(struct zfcp_port *port, u64 fcp_lun)
 {
 	struct zfcp_unit *unit;
 
@@ -251,7 +244,7 @@
  * Returns: pointer to zfcp_port or NULL
  */
 struct zfcp_port *zfcp_get_port_by_wwpn(struct zfcp_adapter *adapter,
-					wwn_t wwpn)
+					u64 wwpn)
 {
 	struct zfcp_port *port;
 
@@ -276,7 +269,7 @@
  *
  * Sets up some unit internal structures and creates sysfs entry.
  */
-struct zfcp_unit *zfcp_unit_enqueue(struct zfcp_port *port, fcp_lun_t fcp_lun)
+struct zfcp_unit *zfcp_unit_enqueue(struct zfcp_port *port, u64 fcp_lun)
 {
 	struct zfcp_unit *unit;
 
@@ -290,7 +283,8 @@
 	unit->port = port;
 	unit->fcp_lun = fcp_lun;
 
-	snprintf(unit->sysfs_device.bus_id, BUS_ID_SIZE, "0x%016llx", fcp_lun);
+	dev_set_name(&unit->sysfs_device, "0x%016llx",
+		     (unsigned long long) fcp_lun);
 	unit->sysfs_device.parent = &port->sysfs_device;
 	unit->sysfs_device.release = zfcp_sysfs_unit_release;
 	dev_set_drvdata(&unit->sysfs_device, unit);
@@ -323,7 +317,6 @@
 	}
 
 	zfcp_unit_get(unit);
-	unit->scsi_lun = scsilun_to_int((struct scsi_lun *)&unit->fcp_lun);
 
 	write_lock_irq(&zfcp_data.config_lock);
 	list_add_tail(&unit->list, &port->unit_list_head);
@@ -332,7 +325,6 @@
 
 	write_unlock_irq(&zfcp_data.config_lock);
 
-	port->units++;
 	zfcp_port_get(port);
 
 	return unit;
@@ -351,11 +343,10 @@
  */
 void zfcp_unit_dequeue(struct zfcp_unit *unit)
 {
-	zfcp_unit_wait(unit);
+	wait_event(unit->remove_wq, atomic_read(&unit->refcount) == 0);
 	write_lock_irq(&zfcp_data.config_lock);
 	list_del(&unit->list);
 	write_unlock_irq(&zfcp_data.config_lock);
-	unit->port->units--;
 	zfcp_port_put(unit->port);
 	sysfs_remove_group(&unit->sysfs_device.kobj, &zfcp_sysfs_unit_attrs);
 	device_unregister(&unit->sysfs_device);
@@ -416,11 +407,6 @@
 		mempool_destroy(adapter->pool.data_gid_pn);
 }
 
-static void zfcp_dummy_release(struct device *dev)
-{
-	return;
-}
-
 /**
  * zfcp_status_read_refill - refill the long running status_read_requests
  * @adapter: ptr to struct zfcp_adapter for which the buffers should be refilled
@@ -450,19 +436,6 @@
 					     stat_work));
 }
 
-static int zfcp_nameserver_enqueue(struct zfcp_adapter *adapter)
-{
-	struct zfcp_port *port;
-
-	port = zfcp_port_enqueue(adapter, 0, ZFCP_STATUS_PORT_WKA,
-				 ZFCP_DID_DIRECTORY_SERVICE);
-	if (IS_ERR(port))
-		return PTR_ERR(port);
-	zfcp_port_put(port);
-
-	return 0;
-}
-
 /**
  * zfcp_adapter_enqueue - enqueue a new adapter to the list
  * @ccw_device: pointer to the struct cc_device
@@ -508,7 +481,6 @@
 	init_waitqueue_head(&adapter->erp_done_wqh);
 
 	INIT_LIST_HEAD(&adapter->port_list_head);
-	INIT_LIST_HEAD(&adapter->port_remove_lh);
 	INIT_LIST_HEAD(&adapter->erp_ready_head);
 	INIT_LIST_HEAD(&adapter->erp_running_head);
 
@@ -518,7 +490,7 @@
 	spin_lock_init(&adapter->san_dbf_lock);
 	spin_lock_init(&adapter->scsi_dbf_lock);
 	spin_lock_init(&adapter->rec_dbf_lock);
-	spin_lock_init(&adapter->req_q.lock);
+	spin_lock_init(&adapter->req_q_lock);
 
 	rwlock_init(&adapter->erp_lock);
 	rwlock_init(&adapter->abort_lock);
@@ -537,28 +509,15 @@
 			       &zfcp_sysfs_adapter_attrs))
 		goto sysfs_failed;
 
-	adapter->generic_services.parent = &adapter->ccw_device->dev;
-	adapter->generic_services.release = zfcp_dummy_release;
-	snprintf(adapter->generic_services.bus_id, BUS_ID_SIZE,
-		 "generic_services");
-
-	if (device_register(&adapter->generic_services))
-		goto generic_services_failed;
-
 	write_lock_irq(&zfcp_data.config_lock);
 	atomic_clear_mask(ZFCP_STATUS_COMMON_REMOVE, &adapter->status);
 	list_add_tail(&adapter->list, &zfcp_data.adapter_list_head);
 	write_unlock_irq(&zfcp_data.config_lock);
 
-	zfcp_data.adapters++;
-
-	zfcp_nameserver_enqueue(adapter);
+	zfcp_fc_nameserver_init(adapter);
 
 	return 0;
 
-generic_services_failed:
-	sysfs_remove_group(&ccw_device->dev.kobj,
-			   &zfcp_sysfs_adapter_attrs);
 sysfs_failed:
 	zfcp_adapter_debug_unregister(adapter);
 debug_register_failed:
@@ -585,7 +544,6 @@
 	cancel_work_sync(&adapter->scan_work);
 	cancel_work_sync(&adapter->stat_work);
 	zfcp_adapter_scsi_unregister(adapter);
-	device_unregister(&adapter->generic_services);
 	sysfs_remove_group(&adapter->ccw_device->dev.kobj,
 			   &zfcp_sysfs_adapter_attrs);
 	dev_set_drvdata(&adapter->ccw_device->dev, NULL);
@@ -603,9 +561,6 @@
 	list_del(&adapter->list);
 	write_unlock_irq(&zfcp_data.config_lock);
 
-	/* decrease number of adapters in list */
-	zfcp_data.adapters--;
-
 	zfcp_qdio_free(adapter);
 
 	zfcp_free_low_mem_buffers(adapter);
@@ -633,21 +588,19 @@
  * d_id is used to enqueue ports with a well known address like the Directory
  * Service for nameserver lookup.
  */
-struct zfcp_port *zfcp_port_enqueue(struct zfcp_adapter *adapter, wwn_t wwpn,
+struct zfcp_port *zfcp_port_enqueue(struct zfcp_adapter *adapter, u64 wwpn,
 				     u32 status, u32 d_id)
 {
 	struct zfcp_port *port;
 	int retval;
-	char *bus_id;
 
 	port = kzalloc(sizeof(struct zfcp_port), GFP_KERNEL);
 	if (!port)
 		return ERR_PTR(-ENOMEM);
 
 	init_waitqueue_head(&port->remove_wq);
-
 	INIT_LIST_HEAD(&port->unit_list_head);
-	INIT_LIST_HEAD(&port->unit_remove_lh);
+	INIT_WORK(&port->gid_pn_work, zfcp_erp_port_strategy_open_lookup);
 
 	port->adapter = adapter;
 	port->d_id = d_id;
@@ -657,34 +610,8 @@
 	atomic_set_mask(status | ZFCP_STATUS_COMMON_REMOVE, &port->status);
 	atomic_set(&port->refcount, 0);
 
-	if (status & ZFCP_STATUS_PORT_WKA) {
-		switch (d_id) {
-		case ZFCP_DID_DIRECTORY_SERVICE:
-			bus_id = "directory";
-			break;
-		case ZFCP_DID_MANAGEMENT_SERVICE:
-			bus_id = "management";
-			break;
-		case ZFCP_DID_KEY_DISTRIBUTION_SERVICE:
-			bus_id = "key_distribution";
-			break;
-		case ZFCP_DID_ALIAS_SERVICE:
-			bus_id = "alias";
-			break;
-		case ZFCP_DID_TIME_SERVICE:
-			bus_id = "time";
-			break;
-		default:
-			kfree(port);
-			return ERR_PTR(-EINVAL);
-		}
-		snprintf(port->sysfs_device.bus_id, BUS_ID_SIZE, "%s", bus_id);
-		port->sysfs_device.parent = &adapter->generic_services;
-	} else {
-		snprintf(port->sysfs_device.bus_id,
-			 BUS_ID_SIZE, "0x%016llx", wwpn);
-		port->sysfs_device.parent = &adapter->ccw_device->dev;
-	}
+	dev_set_name(&port->sysfs_device, "0x%016llx", wwpn);
+	port->sysfs_device.parent = &adapter->ccw_device->dev;
 
 	port->sysfs_device.release = zfcp_sysfs_port_release;
 	dev_set_drvdata(&port->sysfs_device, port);
@@ -700,12 +627,8 @@
 	if (device_register(&port->sysfs_device))
 		goto err_out_free;
 
-	if (status & ZFCP_STATUS_PORT_WKA)
-		retval = sysfs_create_group(&port->sysfs_device.kobj,
-					    &zfcp_sysfs_ns_port_attrs);
-	else
-		retval = sysfs_create_group(&port->sysfs_device.kobj,
-					    &zfcp_sysfs_port_attrs);
+	retval = sysfs_create_group(&port->sysfs_device.kobj,
+				    &zfcp_sysfs_port_attrs);
 
 	if (retval) {
 		device_unregister(&port->sysfs_device);
@@ -718,10 +641,6 @@
 	list_add_tail(&port->list, &adapter->port_list_head);
 	atomic_clear_mask(ZFCP_STATUS_COMMON_REMOVE, &port->status);
 	atomic_set_mask(ZFCP_STATUS_COMMON_RUNNING, &port->status);
-	if (d_id == ZFCP_DID_DIRECTORY_SERVICE)
-		if (!adapter->nameserver_port)
-			adapter->nameserver_port = port;
-	adapter->ports++;
 
 	write_unlock_irq(&zfcp_data.config_lock);
 
@@ -740,21 +659,15 @@
  */
 void zfcp_port_dequeue(struct zfcp_port *port)
 {
-	zfcp_port_wait(port);
+	wait_event(port->remove_wq, atomic_read(&port->refcount) == 0);
 	write_lock_irq(&zfcp_data.config_lock);
 	list_del(&port->list);
-	port->adapter->ports--;
 	write_unlock_irq(&zfcp_data.config_lock);
 	if (port->rport)
 		fc_remote_port_delete(port->rport);
 	port->rport = NULL;
 	zfcp_adapter_put(port->adapter);
-	if (atomic_read(&port->status) & ZFCP_STATUS_PORT_WKA)
-		sysfs_remove_group(&port->sysfs_device.kobj,
-				   &zfcp_sysfs_ns_port_attrs);
-	else
-		sysfs_remove_group(&port->sysfs_device.kobj,
-				   &zfcp_sysfs_port_attrs);
+	sysfs_remove_group(&port->sysfs_device.kobj, &zfcp_sysfs_port_attrs);
 	device_unregister(&port->sysfs_device);
 }
 
diff --git a/drivers/s390/scsi/zfcp_ccw.c b/drivers/s390/scsi/zfcp_ccw.c
index 51b6a05..b04038c 100644
--- a/drivers/s390/scsi/zfcp_ccw.c
+++ b/drivers/s390/scsi/zfcp_ccw.c
@@ -25,7 +25,8 @@
 	down(&zfcp_data.config_sema);
 	if (zfcp_adapter_enqueue(ccw_device)) {
 		dev_err(&ccw_device->dev,
-			"Setup of data structures failed.\n");
+			"Setting up data structures for the "
+			"FCP adapter failed\n");
 		retval = -EINVAL;
 	}
 	up(&zfcp_data.config_sema);
@@ -46,6 +47,8 @@
 	struct zfcp_adapter *adapter;
 	struct zfcp_port *port, *p;
 	struct zfcp_unit *unit, *u;
+	LIST_HEAD(unit_remove_lh);
+	LIST_HEAD(port_remove_lh);
 
 	ccw_device_set_offline(ccw_device);
 	down(&zfcp_data.config_sema);
@@ -54,26 +57,26 @@
 	write_lock_irq(&zfcp_data.config_lock);
 	list_for_each_entry_safe(port, p, &adapter->port_list_head, list) {
 		list_for_each_entry_safe(unit, u, &port->unit_list_head, list) {
-			list_move(&unit->list, &port->unit_remove_lh);
+			list_move(&unit->list, &unit_remove_lh);
 			atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE,
 					&unit->status);
 		}
-		list_move(&port->list, &adapter->port_remove_lh);
+		list_move(&port->list, &port_remove_lh);
 		atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &port->status);
 	}
 	atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &adapter->status);
 	write_unlock_irq(&zfcp_data.config_lock);
 
-	list_for_each_entry_safe(port, p, &adapter->port_remove_lh, list) {
-		list_for_each_entry_safe(unit, u, &port->unit_remove_lh, list) {
-			if (atomic_test_mask(ZFCP_STATUS_UNIT_REGISTERED,
-				&unit->status))
+	list_for_each_entry_safe(port, p, &port_remove_lh, list) {
+		list_for_each_entry_safe(unit, u, &unit_remove_lh, list) {
+			if (atomic_read(&unit->status) &
+			    ZFCP_STATUS_UNIT_REGISTERED)
 				scsi_remove_device(unit->device);
 			zfcp_unit_dequeue(unit);
 		}
 		zfcp_port_dequeue(port);
 	}
-	zfcp_adapter_wait(adapter);
+	wait_event(adapter->remove_wq, atomic_read(&adapter->refcount) == 0);
 	zfcp_adapter_dequeue(adapter);
 
 	up(&zfcp_data.config_sema);
@@ -156,15 +159,18 @@
 
 	switch (event) {
 	case CIO_GONE:
-		dev_warn(&adapter->ccw_device->dev, "device gone\n");
+		dev_warn(&adapter->ccw_device->dev,
+			 "The FCP device has been detached\n");
 		zfcp_erp_adapter_shutdown(adapter, 0, 87, NULL);
 		break;
 	case CIO_NO_PATH:
-		dev_warn(&adapter->ccw_device->dev, "no path\n");
+		dev_warn(&adapter->ccw_device->dev,
+			 "The CHPID for the FCP device is offline\n");
 		zfcp_erp_adapter_shutdown(adapter, 0, 88, NULL);
 		break;
 	case CIO_OPER:
-		dev_info(&adapter->ccw_device->dev, "operational again\n");
+		dev_info(&adapter->ccw_device->dev,
+			 "The FCP device is operational again\n");
 		zfcp_erp_modify_adapter_status(adapter, 11, NULL,
 					       ZFCP_STATUS_COMMON_RUNNING,
 					       ZFCP_SET);
@@ -220,3 +226,20 @@
 {
 	return ccw_driver_register(&zfcp_ccw_driver);
 }
+
+/**
+ * zfcp_get_adapter_by_busid - find zfcp_adapter struct
+ * @busid: bus id string of zfcp adapter to find
+ */
+struct zfcp_adapter *zfcp_get_adapter_by_busid(char *busid)
+{
+	struct ccw_device *ccw_device;
+	struct zfcp_adapter *adapter = NULL;
+
+	ccw_device = get_ccwdev_by_busid(&zfcp_ccw_driver, busid);
+	if (ccw_device) {
+		adapter = dev_get_drvdata(&ccw_device->dev);
+		put_device(&ccw_device->dev);
+	}
+	return adapter;
+}
diff --git a/drivers/s390/scsi/zfcp_dbf.c b/drivers/s390/scsi/zfcp_dbf.c
index fca48b8..060f5f2 100644
--- a/drivers/s390/scsi/zfcp_dbf.c
+++ b/drivers/s390/scsi/zfcp_dbf.c
@@ -318,6 +318,26 @@
 	spin_unlock_irqrestore(&adapter->hba_dbf_lock, flags);
 }
 
+/**
+ * zfcp_hba_dbf_event_berr - trace event for bit error threshold
+ * @adapter: adapter affected by this QDIO related event
+ * @req: fsf request
+ */
+void zfcp_hba_dbf_event_berr(struct zfcp_adapter *adapter,
+			     struct zfcp_fsf_req *req)
+{
+	struct zfcp_hba_dbf_record *r = &adapter->hba_dbf_buf;
+	struct fsf_status_read_buffer *sr_buf = req->data;
+	struct fsf_bit_error_payload *err = &sr_buf->payload.bit_error;
+	unsigned long flags;
+
+	spin_lock_irqsave(&adapter->hba_dbf_lock, flags);
+	memset(r, 0, sizeof(*r));
+	strncpy(r->tag, "berr", ZFCP_DBF_TAG_SIZE);
+	memcpy(&r->u.berr, err, sizeof(struct fsf_bit_error_payload));
+	debug_event(adapter->hba_dbf, 0, r, sizeof(*r));
+	spin_unlock_irqrestore(&adapter->hba_dbf_lock, flags);
+}
 static void zfcp_hba_dbf_view_response(char **p,
 				       struct zfcp_hba_dbf_record_response *r)
 {
@@ -399,6 +419,30 @@
 	zfcp_dbf_out(p, "sbal_count", "0x%02x", r->sbal_count);
 }
 
+static void zfcp_hba_dbf_view_berr(char **p, struct fsf_bit_error_payload *r)
+{
+	zfcp_dbf_out(p, "link_failures", "%d", r->link_failure_error_count);
+	zfcp_dbf_out(p, "loss_of_sync_err", "%d", r->loss_of_sync_error_count);
+	zfcp_dbf_out(p, "loss_of_sig_err", "%d", r->loss_of_signal_error_count);
+	zfcp_dbf_out(p, "prim_seq_err", "%d",
+		     r->primitive_sequence_error_count);
+	zfcp_dbf_out(p, "inval_trans_word_err", "%d",
+		     r->invalid_transmission_word_error_count);
+	zfcp_dbf_out(p, "CRC_errors", "%d", r->crc_error_count);
+	zfcp_dbf_out(p, "prim_seq_event_to", "%d",
+		     r->primitive_sequence_event_timeout_count);
+	zfcp_dbf_out(p, "elast_buf_overrun_err", "%d",
+		     r->elastic_buffer_overrun_error_count);
+	zfcp_dbf_out(p, "adv_rec_buf2buf_cred", "%d",
+		     r->advertised_receive_b2b_credit);
+	zfcp_dbf_out(p, "curr_rec_buf2buf_cred", "%d",
+		     r->current_receive_b2b_credit);
+	zfcp_dbf_out(p, "adv_trans_buf2buf_cred", "%d",
+		     r->advertised_transmit_b2b_credit);
+	zfcp_dbf_out(p, "curr_trans_buf2buf_cred", "%d",
+		     r->current_transmit_b2b_credit);
+}
+
 static int zfcp_hba_dbf_view_format(debug_info_t *id, struct debug_view *view,
 				    char *out_buf, const char *in_buf)
 {
@@ -418,6 +462,8 @@
 		zfcp_hba_dbf_view_status(&p, &r->u.status);
 	else if (strncmp(r->tag, "qdio", ZFCP_DBF_TAG_SIZE) == 0)
 		zfcp_hba_dbf_view_qdio(&p, &r->u.qdio);
+	else if (strncmp(r->tag, "berr", ZFCP_DBF_TAG_SIZE) == 0)
+		zfcp_hba_dbf_view_berr(&p, &r->u.berr);
 
 	p += sprintf(p, "\n");
 	return p - out_buf;
@@ -519,14 +565,14 @@
 	[75]	= "physical port recovery escalation after failed port "
 		  "recovery",
 	[76]	= "port recovery escalation after failed unit recovery",
-	[77]	= "recovery opening nameserver port",
+	[77]	= "",
 	[78]	= "duplicate request id",
 	[79]	= "link down",
 	[80]	= "exclusive read-only unit access unsupported",
 	[81]	= "shared read-write unit access unsupported",
 	[82]	= "incoming rscn",
 	[83]	= "incoming wwpn",
-	[84]	= "",
+	[84]	= "wka port handle not valid close port",
 	[85]	= "online",
 	[86]	= "offline",
 	[87]	= "ccw device gone",
@@ -570,7 +616,7 @@
 	[125]	= "need newer zfcp",
 	[126]	= "need newer microcode",
 	[127]	= "arbitrated loop not supported",
-	[128]	= "unknown topology",
+	[128]	= "",
 	[129]	= "qtcb size mismatch",
 	[130]	= "unknown fsf status ecd",
 	[131]	= "fcp request too big",
@@ -829,9 +875,9 @@
 void zfcp_san_dbf_event_ct_request(struct zfcp_fsf_req *fsf_req)
 {
 	struct zfcp_send_ct *ct = (struct zfcp_send_ct *)fsf_req->data;
-	struct zfcp_port *port = ct->port;
-	struct zfcp_adapter *adapter = port->adapter;
-	struct ct_hdr *hdr = zfcp_sg_to_address(ct->req);
+	struct zfcp_wka_port *wka_port = ct->wka_port;
+	struct zfcp_adapter *adapter = wka_port->adapter;
+	struct ct_hdr *hdr = sg_virt(ct->req);
 	struct zfcp_san_dbf_record *r = &adapter->san_dbf_buf;
 	struct zfcp_san_dbf_record_ct_request *oct = &r->u.ct_req;
 	unsigned long flags;
@@ -842,7 +888,7 @@
 	r->fsf_reqid = (unsigned long)fsf_req;
 	r->fsf_seqno = fsf_req->seq_no;
 	r->s_id = fc_host_port_id(adapter->scsi_host);
-	r->d_id = port->d_id;
+	r->d_id = wka_port->d_id;
 	oct->cmd_req_code = hdr->cmd_rsp_code;
 	oct->revision = hdr->revision;
 	oct->gs_type = hdr->gs_type;
@@ -863,9 +909,9 @@
 void zfcp_san_dbf_event_ct_response(struct zfcp_fsf_req *fsf_req)
 {
 	struct zfcp_send_ct *ct = (struct zfcp_send_ct *)fsf_req->data;
-	struct zfcp_port *port = ct->port;
-	struct zfcp_adapter *adapter = port->adapter;
-	struct ct_hdr *hdr = zfcp_sg_to_address(ct->resp);
+	struct zfcp_wka_port *wka_port = ct->wka_port;
+	struct zfcp_adapter *adapter = wka_port->adapter;
+	struct ct_hdr *hdr = sg_virt(ct->resp);
 	struct zfcp_san_dbf_record *r = &adapter->san_dbf_buf;
 	struct zfcp_san_dbf_record_ct_response *rct = &r->u.ct_resp;
 	unsigned long flags;
@@ -875,7 +921,7 @@
 	strncpy(r->tag, "rctc", ZFCP_DBF_TAG_SIZE);
 	r->fsf_reqid = (unsigned long)fsf_req;
 	r->fsf_seqno = fsf_req->seq_no;
-	r->s_id = port->d_id;
+	r->s_id = wka_port->d_id;
 	r->d_id = fc_host_port_id(adapter->scsi_host);
 	rct->cmd_rsp_code = hdr->cmd_rsp_code;
 	rct->revision = hdr->revision;
@@ -922,8 +968,8 @@
 
 	zfcp_san_dbf_event_els("oels", 2, fsf_req,
 			       fc_host_port_id(els->adapter->scsi_host),
-			       els->d_id, *(u8 *) zfcp_sg_to_address(els->req),
-			       zfcp_sg_to_address(els->req), els->req->length);
+			       els->d_id, *(u8 *) sg_virt(els->req),
+			       sg_virt(els->req), els->req->length);
 }
 
 /**
@@ -936,8 +982,7 @@
 
 	zfcp_san_dbf_event_els("rels", 2, fsf_req, els->d_id,
 			       fc_host_port_id(els->adapter->scsi_host),
-			       *(u8 *)zfcp_sg_to_address(els->req),
-			       zfcp_sg_to_address(els->resp),
+			       *(u8 *)sg_virt(els->req), sg_virt(els->resp),
 			       els->resp->length);
 }
 
diff --git a/drivers/s390/scsi/zfcp_dbf.h b/drivers/s390/scsi/zfcp_dbf.h
index 0ddb184..e8f4508 100644
--- a/drivers/s390/scsi/zfcp_dbf.h
+++ b/drivers/s390/scsi/zfcp_dbf.h
@@ -151,6 +151,7 @@
 		struct zfcp_hba_dbf_record_response response;
 		struct zfcp_hba_dbf_record_status status;
 		struct zfcp_hba_dbf_record_qdio qdio;
+		struct fsf_bit_error_payload berr;
 	} u;
 } __attribute__ ((packed));
 
diff --git a/drivers/s390/scsi/zfcp_def.h b/drivers/s390/scsi/zfcp_def.h
index 67f45fc..8a13071 100644
--- a/drivers/s390/scsi/zfcp_def.h
+++ b/drivers/s390/scsi/zfcp_def.h
@@ -39,29 +39,6 @@
 
 /********************* GENERAL DEFINES *********************************/
 
-/**
- * zfcp_sg_to_address - determine kernel address from struct scatterlist
- * @list: struct scatterlist
- * Return: kernel address
- */
-static inline void *
-zfcp_sg_to_address(struct scatterlist *list)
-{
-	return sg_virt(list);
-}
-
-/**
- * zfcp_address_to_sg - set up struct scatterlist from kernel address
- * @address: kernel address
- * @list: struct scatterlist
- * @size: buffer size
- */
-static inline void
-zfcp_address_to_sg(void *address, struct scatterlist *list, unsigned int size)
-{
-	sg_set_buf(list, address, size);
-}
-
 #define REQUEST_LIST_SIZE 128
 
 /********************* SCSI SPECIFIC DEFINES *********************************/
@@ -101,11 +78,6 @@
 
 /*************** FIBRE CHANNEL PROTOCOL SPECIFIC DEFINES ********************/
 
-typedef unsigned long long wwn_t;
-typedef unsigned long long fcp_lun_t;
-/* data length field may be at variable position in FCP-2 FCP_CMND IU */
-typedef unsigned int       fcp_dl_t;
-
 /* timeout for name-server lookup (in seconds) */
 #define ZFCP_NS_GID_PN_TIMEOUT		10
 
@@ -129,7 +101,7 @@
 
 /* FCP(-2) FCP_CMND IU */
 struct fcp_cmnd_iu {
-	fcp_lun_t fcp_lun;	   /* FCP logical unit number */
+	u64 fcp_lun;	   /* FCP logical unit number */
 	u8  crn;	           /* command reference number */
 	u8  reserved0:5;	   /* reserved */
 	u8  task_attribute:3;	   /* task attribute */
@@ -204,7 +176,7 @@
 struct fcp_logo {
         u32 command;
         u32 nport_did;
-        wwn_t nport_wwpn;
+	u64 nport_wwpn;
 } __attribute__((packed));
 
 /*
@@ -218,13 +190,6 @@
 #define ZFCP_LS_RSCN			0x61
 #define ZFCP_LS_RNID			0x78
 
-struct zfcp_ls_rjt_par {
-	u8 action;
- 	u8 reason_code;
- 	u8 reason_expl;
- 	u8 vendor_unique;
-} __attribute__ ((packed));
-
 struct zfcp_ls_adisc {
 	u8		code;
 	u8		field[3];
@@ -234,20 +199,6 @@
 	u32		nport_id;
 } __attribute__ ((packed));
 
-struct zfcp_ls_adisc_acc {
-	u8		code;
-	u8		field[3];
-	u32		hard_nport_id;
-	u64		wwpn;
-	u64		wwnn;
-	u32		nport_id;
-} __attribute__ ((packed));
-
-struct zfcp_rc_entry {
-	u8 code;
-	const char *description;
-};
-
 /*
  * FC-GS-2 stuff
  */
@@ -281,9 +232,7 @@
 #define ZFCP_STATUS_COMMON_RUNNING		0x40000000
 #define ZFCP_STATUS_COMMON_ERP_FAILED		0x20000000
 #define ZFCP_STATUS_COMMON_UNBLOCKED		0x10000000
-#define ZFCP_STATUS_COMMON_OPENING              0x08000000
 #define ZFCP_STATUS_COMMON_OPEN                 0x04000000
-#define ZFCP_STATUS_COMMON_CLOSING              0x02000000
 #define ZFCP_STATUS_COMMON_ERP_INUSE		0x01000000
 #define ZFCP_STATUS_COMMON_ACCESS_DENIED	0x00800000
 #define ZFCP_STATUS_COMMON_ACCESS_BOXED		0x00400000
@@ -291,16 +240,15 @@
 
 /* adapter status */
 #define ZFCP_STATUS_ADAPTER_QDIOUP		0x00000002
-#define ZFCP_STATUS_ADAPTER_REGISTERED		0x00000004
 #define ZFCP_STATUS_ADAPTER_XCONFIG_OK		0x00000008
 #define ZFCP_STATUS_ADAPTER_HOST_CON_INIT	0x00000010
 #define ZFCP_STATUS_ADAPTER_ERP_THREAD_UP	0x00000020
 #define ZFCP_STATUS_ADAPTER_ERP_THREAD_KILL	0x00000080
 #define ZFCP_STATUS_ADAPTER_ERP_PENDING		0x00000100
 #define ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED	0x00000200
-#define ZFCP_STATUS_ADAPTER_XPORT_OK		0x00000800
 
 /* FC-PH/FC-GS well-known address identifiers for generic services */
+#define ZFCP_DID_WKA				0xFFFFF0
 #define ZFCP_DID_MANAGEMENT_SERVICE		0xFFFFFA
 #define ZFCP_DID_TIME_SERVICE			0xFFFFFB
 #define ZFCP_DID_DIRECTORY_SERVICE		0xFFFFFC
@@ -312,29 +260,27 @@
 #define ZFCP_STATUS_PORT_DID_DID		0x00000002
 #define ZFCP_STATUS_PORT_PHYS_CLOSING		0x00000004
 #define ZFCP_STATUS_PORT_NO_WWPN		0x00000008
-#define ZFCP_STATUS_PORT_NO_SCSI_ID		0x00000010
 #define ZFCP_STATUS_PORT_INVALID_WWPN		0x00000020
 
-/* for ports with well known addresses */
-#define ZFCP_STATUS_PORT_WKA \
-		(ZFCP_STATUS_PORT_NO_WWPN | \
-		 ZFCP_STATUS_PORT_NO_SCSI_ID)
+/* well known address (WKA) port status*/
+enum zfcp_wka_status {
+	ZFCP_WKA_PORT_OFFLINE,
+	ZFCP_WKA_PORT_CLOSING,
+	ZFCP_WKA_PORT_OPENING,
+	ZFCP_WKA_PORT_ONLINE,
+};
 
 /* logical unit status */
-#define ZFCP_STATUS_UNIT_TEMPORARY		0x00000002
 #define ZFCP_STATUS_UNIT_SHARED			0x00000004
 #define ZFCP_STATUS_UNIT_READONLY		0x00000008
 #define ZFCP_STATUS_UNIT_REGISTERED		0x00000010
 #define ZFCP_STATUS_UNIT_SCSI_WORK_PENDING	0x00000020
 
 /* FSF request status (this does not have a common part) */
-#define ZFCP_STATUS_FSFREQ_NOT_INIT		0x00000000
-#define ZFCP_STATUS_FSFREQ_POOL  		0x00000001
 #define ZFCP_STATUS_FSFREQ_TASK_MANAGEMENT	0x00000002
 #define ZFCP_STATUS_FSFREQ_COMPLETED		0x00000004
 #define ZFCP_STATUS_FSFREQ_ERROR		0x00000008
 #define ZFCP_STATUS_FSFREQ_CLEANUP		0x00000010
-#define ZFCP_STATUS_FSFREQ_ABORTING		0x00000020
 #define ZFCP_STATUS_FSFREQ_ABORTSUCCEEDED	0x00000040
 #define ZFCP_STATUS_FSFREQ_ABORTNOTNEEDED       0x00000080
 #define ZFCP_STATUS_FSFREQ_ABORTED              0x00000100
@@ -379,7 +325,7 @@
  * a port name is required */
 struct ct_iu_gid_pn_req {
 	struct ct_hdr header;
-	wwn_t wwpn;
+	u64 wwpn;
 } __attribute__ ((packed));
 
 /* FS_ACC IU and data unit for GID_PN nameserver request */
@@ -388,11 +334,9 @@
 	u32 d_id;
 } __attribute__ ((packed));
 
-typedef void (*zfcp_send_ct_handler_t)(unsigned long);
-
 /**
  * struct zfcp_send_ct - used to pass parameters to function zfcp_fsf_send_ct
- * @port: port where the request is sent to
+ * @wka_port: port where the request is sent to
  * @req: scatter-gather list for request
  * @resp: scatter-gather list for response
  * @req_count: number of elements in request scatter-gather list
@@ -404,12 +348,12 @@
  * @status: used to pass error status to calling function
  */
 struct zfcp_send_ct {
-	struct zfcp_port *port;
+	struct zfcp_wka_port *wka_port;
 	struct scatterlist *req;
 	struct scatterlist *resp;
 	unsigned int req_count;
 	unsigned int resp_count;
-	zfcp_send_ct_handler_t handler;
+	void (*handler)(unsigned long);
 	unsigned long handler_data;
 	int timeout;
 	struct completion *completion;
@@ -426,8 +370,6 @@
         struct zfcp_port *port;
 };
 
-typedef void (*zfcp_send_els_handler_t)(unsigned long);
-
 /**
  * struct zfcp_send_els - used to pass parameters to function zfcp_fsf_send_els
  * @adapter: adapter where request is sent from
@@ -451,22 +393,28 @@
 	struct scatterlist *resp;
 	unsigned int req_count;
 	unsigned int resp_count;
-	zfcp_send_els_handler_t handler;
+	void (*handler)(unsigned long);
 	unsigned long handler_data;
 	struct completion *completion;
 	int ls_code;
 	int status;
 };
 
+struct zfcp_wka_port {
+	struct zfcp_adapter	*adapter;
+	wait_queue_head_t	completion_wq;
+	enum zfcp_wka_status	status;
+	atomic_t		refcount;
+	u32			d_id;
+	u32			handle;
+	struct mutex		mutex;
+	struct delayed_work	work;
+};
+
 struct zfcp_qdio_queue {
-	struct qdio_buffer *sbal[QDIO_MAX_BUFFERS_PER_Q]; /* SBALs */
-	u8		   first;	      /* index of next free bfr
-						 in queue (free_count>0) */
-	atomic_t           count;	      /* number of free buffers
-						 in queue */
-	spinlock_t	   lock;	      /* lock for operations on queue */
-	int                pci_batch;	      /* SBALs since PCI indication
-						 was last set */
+	struct qdio_buffer *sbal[QDIO_MAX_BUFFERS_PER_Q];
+	u8		   first;	/* index of next free bfr in queue */
+	atomic_t           count;	/* number of free buffers in queue */
 };
 
 struct zfcp_erp_action {
@@ -475,7 +423,7 @@
 	struct zfcp_adapter *adapter; /* device which should be recovered */
 	struct zfcp_port *port;
 	struct zfcp_unit *unit;
-	volatile u32 status;	      /* recovery status */
+	u32		status;	      /* recovery status */
 	u32 step;	              /* active step of this erp action */
 	struct zfcp_fsf_req *fsf_req; /* fsf request currently pending
 					 for this action */
@@ -506,8 +454,8 @@
 	atomic_t                refcount;          /* reference count */
 	wait_queue_head_t	remove_wq;         /* can be used to wait for
 						      refcount drop to zero */
-	wwn_t			peer_wwnn;	   /* P2P peer WWNN */
-	wwn_t			peer_wwpn;	   /* P2P peer WWPN */
+	u64			peer_wwnn;	   /* P2P peer WWNN */
+	u64			peer_wwpn;	   /* P2P peer WWPN */
 	u32			peer_d_id;	   /* P2P peer D_ID */
 	struct ccw_device       *ccw_device;	   /* S/390 ccw device */
 	u32			hydra_version;	   /* Hydra version */
@@ -518,13 +466,13 @@
 	u16			timer_ticks;       /* time int for a tick */
 	struct Scsi_Host	*scsi_host;	   /* Pointer to mid-layer */
 	struct list_head	port_list_head;	   /* remote port list */
-	struct list_head        port_remove_lh;    /* head of ports to be
-						      removed */
-	u32			ports;	           /* number of remote ports */
 	unsigned long		req_no;		   /* unique FSF req number */
 	struct list_head	*req_list;	   /* list of pending reqs */
 	spinlock_t		req_list_lock;	   /* request list lock */
 	struct zfcp_qdio_queue	req_q;		   /* request queue */
+	spinlock_t		req_q_lock;	   /* for operations on queue */
+	int			req_q_pci_batch;   /* SBALs since PCI indication
+						      was last set */
 	u32			fsf_req_seq_no;	   /* FSF cmnd seq number */
 	wait_queue_head_t	request_wq;	   /* can be used to wait for
 						      more avaliable SBALs */
@@ -548,7 +496,7 @@
 						      actions */
 	u32			erp_low_mem_count; /* nr of erp actions waiting
 						      for memory */
-	struct zfcp_port	*nameserver_port;  /* adapter's nameserver */
+	struct zfcp_wka_port	nsp;		   /* adapter's nameserver */
 	debug_info_t		*rec_dbf;
 	debug_info_t		*hba_dbf;
 	debug_info_t		*san_dbf;          /* debug feature areas */
@@ -563,11 +511,11 @@
 	struct zfcp_scsi_dbf_record	scsi_dbf_buf;
 	struct zfcp_adapter_mempool	pool;      /* Adapter memory pools */
 	struct qdio_initialize  qdio_init_data;    /* for qdio_establish */
-	struct device           generic_services;  /* directory for WKA ports */
 	struct fc_host_statistics *fc_stats;
 	struct fsf_qtcb_bottom_port *stats_reset_data;
 	unsigned long		stats_reset;
 	struct work_struct	scan_work;
+	atomic_t		qdio_outb_full;	   /* queue full incidents */
 };
 
 struct zfcp_port {
@@ -579,18 +527,16 @@
 						  refcount drop to zero */
 	struct zfcp_adapter    *adapter;       /* adapter used to access port */
 	struct list_head       unit_list_head; /* head of logical unit list */
-	struct list_head       unit_remove_lh; /* head of luns to be removed
-						  list */
-	u32		       units;	       /* # of logical units in list */
 	atomic_t	       status;	       /* status of this remote port */
-	wwn_t		       wwnn;	       /* WWNN if known */
-	wwn_t		       wwpn;	       /* WWPN */
+	u64		       wwnn;	       /* WWNN if known */
+	u64		       wwpn;	       /* WWPN */
 	u32		       d_id;	       /* D_ID */
 	u32		       handle;	       /* handle assigned by FSF */
 	struct zfcp_erp_action erp_action;     /* pending error recovery */
         atomic_t               erp_counter;
 	u32                    maxframe_size;
 	u32                    supported_classes;
+	struct work_struct     gid_pn_work;
 };
 
 struct zfcp_unit {
@@ -601,8 +547,7 @@
 						  refcount drop to zero */
 	struct zfcp_port       *port;	       /* remote port of unit */
 	atomic_t	       status;	       /* status of this logical unit */
-	unsigned int	       scsi_lun;       /* own SCSI LUN */
-	fcp_lun_t	       fcp_lun;	       /* own FCP_LUN */
+	u64		       fcp_lun;	       /* own FCP_LUN */
 	u32		       handle;	       /* handle assigned by FSF */
         struct scsi_device     *device;        /* scsi device struct pointer */
 	struct zfcp_erp_action erp_action;     /* pending error recovery */
@@ -625,7 +570,7 @@
 	u8			sbal_response;	/* SBAL used in interrupt */
 	wait_queue_head_t      completion_wq;  /* can be used by a routine
 						  to wait for completion */
-	volatile u32	       status;	       /* status of this request */
+	u32			status;	       /* status of this request */
 	u32		       fsf_command;    /* FSF Command copy */
 	struct fsf_qtcb	       *qtcb;	       /* address of associated QTCB */
 	u32		       seq_no;         /* Sequence number of request */
@@ -644,23 +589,20 @@
 struct zfcp_data {
 	struct scsi_host_template scsi_host_template;
 	struct scsi_transport_template *scsi_transport_template;
-        atomic_t                status;             /* Module status flags */
 	struct list_head	adapter_list_head;  /* head of adapter list */
-	struct list_head	adapter_remove_lh;  /* head of adapters to be
-						       removed */
-	u32			adapters;	    /* # of adapters in list */
 	rwlock_t                config_lock;        /* serialises changes
 						       to adapter/port/unit
 						       lists */
 	struct semaphore        config_sema;        /* serialises configuration
 						       changes */
 	atomic_t		loglevel;            /* current loglevel */
-	char                    init_busid[BUS_ID_SIZE];
-	wwn_t                   init_wwpn;
-	fcp_lun_t               init_fcp_lun;
-	struct kmem_cache		*fsf_req_qtcb_cache;
-	struct kmem_cache		*sr_buffer_cache;
-	struct kmem_cache		*gid_pn_cache;
+	char			init_busid[20];
+	u64			init_wwpn;
+	u64			init_fcp_lun;
+	struct kmem_cache	*fsf_req_qtcb_cache;
+	struct kmem_cache	*sr_buffer_cache;
+	struct kmem_cache	*gid_pn_cache;
+	struct workqueue_struct	*work_queue;
 };
 
 /* struct used by memory pools for fsf_requests */
@@ -677,14 +619,7 @@
 #define ZFCP_SET                0x00000100
 #define ZFCP_CLEAR              0x00000200
 
-#ifndef atomic_test_mask
-#define atomic_test_mask(mask, target) \
-           ((atomic_read(target) & mask) == mask)
-#endif
-
-#define zfcp_get_busid_by_adapter(adapter) (adapter->ccw_device->dev.bus_id)
-#define zfcp_get_busid_by_port(port) (zfcp_get_busid_by_adapter(port->adapter))
-#define zfcp_get_busid_by_unit(unit) (zfcp_get_busid_by_port(unit->port))
+#define zfcp_get_busid_by_adapter(adapter) (dev_name(&adapter->ccw_device->dev))
 
 /*
  * Helper functions for request ID management.
@@ -745,12 +680,6 @@
 }
 
 static inline void
-zfcp_unit_wait(struct zfcp_unit *unit)
-{
-	wait_event(unit->remove_wq, atomic_read(&unit->refcount) == 0);
-}
-
-static inline void
 zfcp_port_get(struct zfcp_port *port)
 {
 	atomic_inc(&port->refcount);
@@ -764,12 +693,6 @@
 }
 
 static inline void
-zfcp_port_wait(struct zfcp_port *port)
-{
-	wait_event(port->remove_wq, atomic_read(&port->refcount) == 0);
-}
-
-static inline void
 zfcp_adapter_get(struct zfcp_adapter *adapter)
 {
 	atomic_inc(&adapter->refcount);
@@ -782,10 +705,4 @@
 		wake_up(&adapter->remove_wq);
 }
 
-static inline void
-zfcp_adapter_wait(struct zfcp_adapter *adapter)
-{
-	wait_event(adapter->remove_wq, atomic_read(&adapter->refcount) == 0);
-}
-
 #endif /* ZFCP_DEF_H */
diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c
index 643ac4b..9040f73 100644
--- a/drivers/s390/scsi/zfcp_erp.c
+++ b/drivers/s390/scsi/zfcp_erp.c
@@ -23,7 +23,6 @@
 	ZFCP_ERP_STEP_FSF_XCONFIG	= 0x0001,
 	ZFCP_ERP_STEP_PHYS_PORT_CLOSING	= 0x0010,
 	ZFCP_ERP_STEP_PORT_CLOSING	= 0x0100,
-	ZFCP_ERP_STEP_NAMESERVER_OPEN	= 0x0200,
 	ZFCP_ERP_STEP_NAMESERVER_LOOKUP	= 0x0400,
 	ZFCP_ERP_STEP_PORT_OPENING	= 0x0800,
 	ZFCP_ERP_STEP_UNIT_CLOSING	= 0x1000,
@@ -532,8 +531,7 @@
 	struct zfcp_port *port;
 
 	list_for_each_entry(port, &adapter->port_list_head, list)
-		if (!(atomic_read(&port->status) & ZFCP_STATUS_PORT_WKA))
-			_zfcp_erp_port_reopen(port, clear, id, ref);
+		_zfcp_erp_port_reopen(port, clear, id, ref);
 }
 
 static void _zfcp_erp_unit_reopen_all(struct zfcp_port *port, int clear, u8 id,
@@ -669,8 +667,6 @@
 	int ret;
 	struct zfcp_adapter *adapter = act->adapter;
 
-	atomic_clear_mask(ZFCP_STATUS_ADAPTER_XPORT_OK, &adapter->status);
-
 	write_lock_irq(&adapter->erp_lock);
 	zfcp_erp_action_to_running(act);
 	write_unlock_irq(&adapter->erp_lock);
@@ -741,8 +737,7 @@
 				       ZFCP_STATUS_COMMON_OPEN, ZFCP_CLEAR);
  failed_qdio:
 	atomic_clear_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK |
-			  ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED |
-			  ZFCP_STATUS_ADAPTER_XPORT_OK,
+			  ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED,
 			  &act->adapter->status);
 	return retval;
 }
@@ -751,15 +746,11 @@
 {
 	int retval;
 
-	atomic_set_mask(ZFCP_STATUS_COMMON_CLOSING, &act->adapter->status);
 	zfcp_erp_adapter_strategy_generic(act, 1); /* close */
-	atomic_clear_mask(ZFCP_STATUS_COMMON_CLOSING, &act->adapter->status);
 	if (act->status & ZFCP_STATUS_ERP_CLOSE_ONLY)
 		return ZFCP_ERP_EXIT;
 
-	atomic_set_mask(ZFCP_STATUS_COMMON_OPENING, &act->adapter->status);
 	retval = zfcp_erp_adapter_strategy_generic(act, 0); /* open */
-	atomic_clear_mask(ZFCP_STATUS_COMMON_OPENING, &act->adapter->status);
 
 	if (retval == ZFCP_ERP_FAILED)
 		ssleep(8);
@@ -783,10 +774,7 @@
 
 static void zfcp_erp_port_strategy_clearstati(struct zfcp_port *port)
 {
-	atomic_clear_mask(ZFCP_STATUS_COMMON_OPENING |
-			  ZFCP_STATUS_COMMON_CLOSING |
-			  ZFCP_STATUS_COMMON_ACCESS_DENIED |
-			  ZFCP_STATUS_PORT_DID_DID |
+	atomic_clear_mask(ZFCP_STATUS_COMMON_ACCESS_DENIED |
 			  ZFCP_STATUS_PORT_PHYS_CLOSING |
 			  ZFCP_STATUS_PORT_INVALID_WWPN,
 			  &port->status);
@@ -839,73 +827,12 @@
 	return ZFCP_ERP_CONTINUES;
 }
 
-static void zfcp_erp_port_strategy_open_ns_wake(struct zfcp_erp_action *ns_act)
-{
-	unsigned long flags;
-	struct zfcp_adapter *adapter = ns_act->adapter;
-	struct zfcp_erp_action *act, *tmp;
-	int status;
-
-	read_lock_irqsave(&adapter->erp_lock, flags);
-	list_for_each_entry_safe(act, tmp, &adapter->erp_running_head, list) {
-		if (act->step == ZFCP_ERP_STEP_NAMESERVER_OPEN) {
-			status = atomic_read(&adapter->nameserver_port->status);
-			if (status & ZFCP_STATUS_COMMON_ERP_FAILED)
-				zfcp_erp_port_failed(act->port, 27, NULL);
-			zfcp_erp_action_ready(act);
-		}
-	}
-	read_unlock_irqrestore(&adapter->erp_lock, flags);
-}
-
-static int zfcp_erp_port_strategy_open_nameserver(struct zfcp_erp_action *act)
-{
-	int retval;
-
-	switch (act->step) {
-	case ZFCP_ERP_STEP_UNINITIALIZED:
-	case ZFCP_ERP_STEP_PHYS_PORT_CLOSING:
-	case ZFCP_ERP_STEP_PORT_CLOSING:
-		return zfcp_erp_port_strategy_open_port(act);
-
-	case ZFCP_ERP_STEP_PORT_OPENING:
-		if (atomic_read(&act->port->status) & ZFCP_STATUS_COMMON_OPEN)
-			retval = ZFCP_ERP_SUCCEEDED;
-		else
-			retval = ZFCP_ERP_FAILED;
-		/* this is needed anyway  */
-		zfcp_erp_port_strategy_open_ns_wake(act);
-		return retval;
-
-	default:
-		return ZFCP_ERP_FAILED;
-	}
-}
-
-static int zfcp_erp_port_strategy_open_lookup(struct zfcp_erp_action *act)
-{
-	int retval;
-
-	retval = zfcp_fc_ns_gid_pn_request(act);
-	if (retval == -ENOMEM)
-		return ZFCP_ERP_NOMEM;
-	act->step = ZFCP_ERP_STEP_NAMESERVER_LOOKUP;
-	if (retval)
-		return ZFCP_ERP_FAILED;
-	return ZFCP_ERP_CONTINUES;
-}
-
 static int zfcp_erp_open_ptp_port(struct zfcp_erp_action *act)
 {
 	struct zfcp_adapter *adapter = act->adapter;
 	struct zfcp_port *port = act->port;
 
 	if (port->wwpn != adapter->peer_wwpn) {
-		dev_err(&adapter->ccw_device->dev,
-			"Failed to open port 0x%016Lx, "
-			"Peer WWPN 0x%016Lx does not "
-			"match.\n", port->wwpn,
-			adapter->peer_wwpn);
 		zfcp_erp_port_failed(port, 25, NULL);
 		return ZFCP_ERP_FAILED;
 	}
@@ -914,11 +841,25 @@
 	return zfcp_erp_port_strategy_open_port(act);
 }
 
+void zfcp_erp_port_strategy_open_lookup(struct work_struct *work)
+{
+	int retval;
+	struct zfcp_port *port = container_of(work, struct zfcp_port,
+					      gid_pn_work);
+
+	retval = zfcp_fc_ns_gid_pn(&port->erp_action);
+	if (retval == -ENOMEM)
+		zfcp_erp_notify(&port->erp_action, ZFCP_ERP_NOMEM);
+	port->erp_action.step = ZFCP_ERP_STEP_NAMESERVER_LOOKUP;
+	if (retval)
+		zfcp_erp_notify(&port->erp_action, ZFCP_ERP_FAILED);
+
+}
+
 static int zfcp_erp_port_strategy_open_common(struct zfcp_erp_action *act)
 {
 	struct zfcp_adapter *adapter = act->adapter;
 	struct zfcp_port *port = act->port;
-	struct zfcp_port *ns_port = adapter->nameserver_port;
 	int p_status = atomic_read(&port->status);
 
 	switch (act->step) {
@@ -927,28 +868,10 @@
 	case ZFCP_ERP_STEP_PORT_CLOSING:
 		if (fc_host_port_type(adapter->scsi_host) == FC_PORTTYPE_PTP)
 			return zfcp_erp_open_ptp_port(act);
-		if (!ns_port) {
-			dev_err(&adapter->ccw_device->dev,
-				"Nameserver port unavailable.\n");
-			return ZFCP_ERP_FAILED;
+		if (!(p_status & ZFCP_STATUS_PORT_DID_DID)) {
+			queue_work(zfcp_data.work_queue, &port->gid_pn_work);
+			return ZFCP_ERP_CONTINUES;
 		}
-		if (!(atomic_read(&ns_port->status) &
-		      ZFCP_STATUS_COMMON_UNBLOCKED)) {
-			/* nameserver port may live again */
-			atomic_set_mask(ZFCP_STATUS_COMMON_RUNNING,
-					&ns_port->status);
-			if (zfcp_erp_port_reopen(ns_port, 0, 77, act) >= 0) {
-				act->step = ZFCP_ERP_STEP_NAMESERVER_OPEN;
-				return ZFCP_ERP_CONTINUES;
-			}
-			return ZFCP_ERP_FAILED;
-		}
-		/* else nameserver port is already open, fall through */
-	case ZFCP_ERP_STEP_NAMESERVER_OPEN:
-		if (!(atomic_read(&ns_port->status) & ZFCP_STATUS_COMMON_OPEN))
-			return ZFCP_ERP_FAILED;
-		return zfcp_erp_port_strategy_open_lookup(act);
-
 	case ZFCP_ERP_STEP_NAMESERVER_LOOKUP:
 		if (!(p_status & ZFCP_STATUS_PORT_DID_DID)) {
 			if (p_status & (ZFCP_STATUS_PORT_INVALID_WWPN)) {
@@ -961,25 +884,26 @@
 
 	case ZFCP_ERP_STEP_PORT_OPENING:
 		/* D_ID might have changed during open */
-		if ((p_status & ZFCP_STATUS_COMMON_OPEN) &&
-		    (p_status & ZFCP_STATUS_PORT_DID_DID))
-			return ZFCP_ERP_SUCCEEDED;
+		if (p_status & ZFCP_STATUS_COMMON_OPEN) {
+			if (p_status & ZFCP_STATUS_PORT_DID_DID)
+				return ZFCP_ERP_SUCCEEDED;
+			else {
+				act->step = ZFCP_ERP_STEP_PORT_CLOSING;
+				return ZFCP_ERP_CONTINUES;
+			}
 		/* fall through otherwise */
+		}
 	}
 	return ZFCP_ERP_FAILED;
 }
 
-static int zfcp_erp_port_strategy_open(struct zfcp_erp_action *act)
-{
-	if (atomic_read(&act->port->status) & (ZFCP_STATUS_PORT_WKA))
-		return zfcp_erp_port_strategy_open_nameserver(act);
-	return zfcp_erp_port_strategy_open_common(act);
-}
-
 static int zfcp_erp_port_strategy(struct zfcp_erp_action *erp_action)
 {
 	struct zfcp_port *port = erp_action->port;
 
+	if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_NOESC)
+		goto close_init_done;
+
 	switch (erp_action->step) {
 	case ZFCP_ERP_STEP_UNINITIALIZED:
 		zfcp_erp_port_strategy_clearstati(port);
@@ -992,19 +916,17 @@
 			return ZFCP_ERP_FAILED;
 		break;
 	}
+
+close_init_done:
 	if (erp_action->status & ZFCP_STATUS_ERP_CLOSE_ONLY)
 		return ZFCP_ERP_EXIT;
-	else
-		return zfcp_erp_port_strategy_open(erp_action);
 
-	return ZFCP_ERP_FAILED;
+	return zfcp_erp_port_strategy_open_common(erp_action);
 }
 
 static void zfcp_erp_unit_strategy_clearstati(struct zfcp_unit *unit)
 {
-	atomic_clear_mask(ZFCP_STATUS_COMMON_OPENING |
-			  ZFCP_STATUS_COMMON_CLOSING |
-			  ZFCP_STATUS_COMMON_ACCESS_DENIED |
+	atomic_clear_mask(ZFCP_STATUS_COMMON_ACCESS_DENIED |
 			  ZFCP_STATUS_UNIT_SHARED |
 			  ZFCP_STATUS_UNIT_READONLY,
 			  &unit->status);
@@ -1065,8 +987,14 @@
 		break;
 	case ZFCP_ERP_FAILED :
 		atomic_inc(&unit->erp_counter);
-		if (atomic_read(&unit->erp_counter) > ZFCP_MAX_ERPS)
+		if (atomic_read(&unit->erp_counter) > ZFCP_MAX_ERPS) {
+			dev_err(&unit->port->adapter->ccw_device->dev,
+				"ERP failed for unit 0x%016Lx on "
+				"port 0x%016Lx\n",
+				(unsigned long long)unit->fcp_lun,
+				(unsigned long long)unit->port->wwpn);
 			zfcp_erp_unit_failed(unit, 21, NULL);
+		}
 		break;
 	}
 
@@ -1091,8 +1019,12 @@
 			result = ZFCP_ERP_EXIT;
 		}
 		atomic_inc(&port->erp_counter);
-		if (atomic_read(&port->erp_counter) > ZFCP_MAX_ERPS)
+		if (atomic_read(&port->erp_counter) > ZFCP_MAX_ERPS) {
+			dev_err(&port->adapter->ccw_device->dev,
+				"ERP failed for remote port 0x%016Lx\n",
+				(unsigned long long)port->wwpn);
 			zfcp_erp_port_failed(port, 22, NULL);
+		}
 		break;
 	}
 
@@ -1114,8 +1046,12 @@
 
 	case ZFCP_ERP_FAILED :
 		atomic_inc(&adapter->erp_counter);
-		if (atomic_read(&adapter->erp_counter) > ZFCP_MAX_ERPS)
+		if (atomic_read(&adapter->erp_counter) > ZFCP_MAX_ERPS) {
+			dev_err(&adapter->ccw_device->dev,
+				"ERP cannot recover an error "
+				"on the FCP device\n");
 			zfcp_erp_adapter_failed(adapter, 23, NULL);
+		}
 		break;
 	}
 
@@ -1250,9 +1186,10 @@
 	struct zfcp_unit *unit = p->unit;
 	struct fc_rport *rport = unit->port->rport;
 	scsi_scan_target(&rport->dev, 0, rport->scsi_target_id,
-			 unit->scsi_lun, 0);
+			 scsilun_to_int((struct scsi_lun *)&unit->fcp_lun), 0);
 	atomic_clear_mask(ZFCP_STATUS_UNIT_SCSI_WORK_PENDING, &unit->status);
 	zfcp_unit_put(unit);
+	wake_up(&unit->port->adapter->erp_done_wqh);
 	kfree(p);
 }
 
@@ -1263,9 +1200,9 @@
 	p = kzalloc(sizeof(*p), GFP_KERNEL);
 	if (!p) {
 		dev_err(&unit->port->adapter->ccw_device->dev,
-			"Out of resources. Could not register unit "
-			"0x%016Lx on port 0x%016Lx with SCSI stack.\n",
-			unit->fcp_lun, unit->port->wwpn);
+			"Registering unit 0x%016Lx on port 0x%016Lx failed\n",
+			(unsigned long long)unit->fcp_lun,
+			(unsigned long long)unit->port->wwpn);
 		return;
 	}
 
@@ -1273,7 +1210,7 @@
 	atomic_set_mask(ZFCP_STATUS_UNIT_SCSI_WORK_PENDING, &unit->status);
 	INIT_WORK(&p->work, zfcp_erp_scsi_scan);
 	p->unit = unit;
-	schedule_work(&p->work);
+	queue_work(zfcp_data.work_queue, &p->work);
 }
 
 static void zfcp_erp_rport_register(struct zfcp_port *port)
@@ -1286,8 +1223,8 @@
 	port->rport = fc_remote_port_add(port->adapter->scsi_host, 0, &ids);
 	if (!port->rport) {
 		dev_err(&port->adapter->ccw_device->dev,
-			"Failed registration of rport "
-			"0x%016Lx.\n", port->wwpn);
+			"Registering port 0x%016Lx failed\n",
+			(unsigned long long)port->wwpn);
 		return;
 	}
 
@@ -1299,12 +1236,12 @@
 static void zfcp_erp_rports_del(struct zfcp_adapter *adapter)
 {
 	struct zfcp_port *port;
-	list_for_each_entry(port, &adapter->port_list_head, list)
-		if (port->rport && !(atomic_read(&port->status) &
-					ZFCP_STATUS_PORT_WKA)) {
-			fc_remote_port_delete(port->rport);
-			port->rport = NULL;
-		}
+	list_for_each_entry(port, &adapter->port_list_head, list) {
+		if (!port->rport)
+			continue;
+		fc_remote_port_delete(port->rport);
+		port->rport = NULL;
+	}
 }
 
 static void zfcp_erp_action_cleanup(struct zfcp_erp_action *act, int result)
@@ -1439,7 +1376,7 @@
 	struct zfcp_erp_action *act;
 	unsigned long flags;
 
-	daemonize("zfcperp%s", adapter->ccw_device->dev.bus_id);
+	daemonize("zfcperp%s", dev_name(&adapter->ccw_device->dev));
 	/* Block all signals */
 	siginitsetinv(&current->blocked, 0);
 	atomic_set_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_UP, &adapter->status);
@@ -1459,9 +1396,9 @@
 				zfcp_erp_wakeup(adapter);
 		}
 
-		zfcp_rec_dbf_event_thread(4, adapter);
+		zfcp_rec_dbf_event_thread_lock(4, adapter);
 		down_interruptible(&adapter->erp_ready_sem);
-		zfcp_rec_dbf_event_thread(5, adapter);
+		zfcp_rec_dbf_event_thread_lock(5, adapter);
 	}
 
 	atomic_clear_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_UP, &adapter->status);
@@ -1484,7 +1421,7 @@
 	retval = kernel_thread(zfcp_erp_thread, adapter, SIGCHLD);
 	if (retval < 0) {
 		dev_err(&adapter->ccw_device->dev,
-			"Creation of ERP thread failed.\n");
+			"Creating an ERP thread for the FCP device failed.\n");
 		return retval;
 	}
 	wait_event(adapter->erp_thread_wqh,
@@ -1506,7 +1443,7 @@
 {
 	atomic_set_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_KILL, &adapter->status);
 	up(&adapter->erp_ready_sem);
-	zfcp_rec_dbf_event_thread_lock(2, adapter);
+	zfcp_rec_dbf_event_thread_lock(3, adapter);
 
 	wait_event(adapter->erp_thread_wqh,
 		   !(atomic_read(&adapter->status) &
@@ -1526,7 +1463,6 @@
 {
 	zfcp_erp_modify_adapter_status(adapter, id, ref,
 				       ZFCP_STATUS_COMMON_ERP_FAILED, ZFCP_SET);
-	dev_err(&adapter->ccw_device->dev, "Adapter ERP failed.\n");
 }
 
 /**
@@ -1539,15 +1475,6 @@
 {
 	zfcp_erp_modify_port_status(port, id, ref,
 				    ZFCP_STATUS_COMMON_ERP_FAILED, ZFCP_SET);
-
-	if (atomic_read(&port->status) & ZFCP_STATUS_PORT_WKA)
-		dev_err(&port->adapter->ccw_device->dev,
-			"Port ERP failed for WKA port d_id=0x%06x.\n",
-			port->d_id);
-	else
-		dev_err(&port->adapter->ccw_device->dev,
-			"Port ERP failed for port wwpn=0x%016Lx.\n",
-			port->wwpn);
 }
 
 /**
@@ -1560,10 +1487,6 @@
 {
 	zfcp_erp_modify_unit_status(unit, id, ref,
 				    ZFCP_STATUS_COMMON_ERP_FAILED, ZFCP_SET);
-
-	dev_err(&unit->port->adapter->ccw_device->dev,
-		"Unit ERP failed for unit 0x%016Lx on port 0x%016Lx.\n",
-		unit->fcp_lun, unit->port->wwpn);
 }
 
 /**
@@ -1754,9 +1677,8 @@
 
 	if (!(status & (ZFCP_STATUS_COMMON_ACCESS_DENIED |
 			ZFCP_STATUS_COMMON_ACCESS_BOXED))) {
-		if (!(status & ZFCP_STATUS_PORT_WKA))
-			list_for_each_entry(unit, &port->unit_list_head, list)
-				zfcp_erp_unit_access_changed(unit, id, ref);
+		list_for_each_entry(unit, &port->unit_list_head, list)
+				    zfcp_erp_unit_access_changed(unit, id, ref);
 		return;
 	}
 
@@ -1779,10 +1701,7 @@
 		return;
 
 	read_lock_irqsave(&zfcp_data.config_lock, flags);
-	if (adapter->nameserver_port)
-		zfcp_erp_port_access_changed(adapter->nameserver_port, id, ref);
 	list_for_each_entry(port, &adapter->port_list_head, list)
-		if (port != adapter->nameserver_port)
-			zfcp_erp_port_access_changed(port, id, ref);
+		zfcp_erp_port_access_changed(port, id, ref);
 	read_unlock_irqrestore(&zfcp_data.config_lock, flags);
 }
diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h
index edfdb21..b5adeda 100644
--- a/drivers/s390/scsi/zfcp_ext.h
+++ b/drivers/s390/scsi/zfcp_ext.h
@@ -12,16 +12,14 @@
 #include "zfcp_def.h"
 
 /* zfcp_aux.c */
-extern struct zfcp_unit *zfcp_get_unit_by_lun(struct zfcp_port *,
-					      fcp_lun_t);
-extern struct zfcp_port *zfcp_get_port_by_wwpn(struct zfcp_adapter *,
-					       wwn_t);
+extern struct zfcp_unit *zfcp_get_unit_by_lun(struct zfcp_port *, u64);
+extern struct zfcp_port *zfcp_get_port_by_wwpn(struct zfcp_adapter *, u64);
 extern int zfcp_adapter_enqueue(struct ccw_device *);
 extern void zfcp_adapter_dequeue(struct zfcp_adapter *);
-extern struct zfcp_port *zfcp_port_enqueue(struct zfcp_adapter *, wwn_t, u32,
+extern struct zfcp_port *zfcp_port_enqueue(struct zfcp_adapter *, u64, u32,
 					   u32);
 extern void zfcp_port_dequeue(struct zfcp_port *);
-extern struct zfcp_unit *zfcp_unit_enqueue(struct zfcp_port *, fcp_lun_t);
+extern struct zfcp_unit *zfcp_unit_enqueue(struct zfcp_port *, u64);
 extern void zfcp_unit_dequeue(struct zfcp_unit *);
 extern int zfcp_reqlist_isempty(struct zfcp_adapter *);
 extern void zfcp_sg_free_table(struct scatterlist *, int);
@@ -29,6 +27,7 @@
 
 /* zfcp_ccw.c */
 extern int zfcp_ccw_register(void);
+extern struct zfcp_adapter *zfcp_get_adapter_by_busid(char *);
 
 /* zfcp_cfdc.c */
 extern struct miscdevice zfcp_cfdc_misc;
@@ -50,6 +49,8 @@
 					 struct fsf_status_read_buffer *);
 extern void zfcp_hba_dbf_event_qdio(struct zfcp_adapter *, unsigned int, int,
 				    int);
+extern void zfcp_hba_dbf_event_berr(struct zfcp_adapter *,
+				    struct zfcp_fsf_req *);
 extern void zfcp_san_dbf_event_ct_request(struct zfcp_fsf_req *);
 extern void zfcp_san_dbf_event_ct_response(struct zfcp_fsf_req *);
 extern void zfcp_san_dbf_event_els_request(struct zfcp_fsf_req *);
@@ -91,17 +92,21 @@
 extern void zfcp_erp_unit_access_denied(struct zfcp_unit *, u8, void *);
 extern void zfcp_erp_adapter_access_changed(struct zfcp_adapter *, u8, void *);
 extern void zfcp_erp_timeout_handler(unsigned long);
+extern void zfcp_erp_port_strategy_open_lookup(struct work_struct *);
 
 /* zfcp_fc.c */
 extern int zfcp_scan_ports(struct zfcp_adapter *);
 extern void _zfcp_scan_ports_later(struct work_struct *);
 extern void zfcp_fc_incoming_els(struct zfcp_fsf_req *);
-extern int zfcp_fc_ns_gid_pn_request(struct zfcp_erp_action *);
+extern int zfcp_fc_ns_gid_pn(struct zfcp_erp_action *);
 extern void zfcp_fc_plogi_evaluate(struct zfcp_port *, struct fsf_plogi *);
 extern void zfcp_test_link(struct zfcp_port *);
+extern void zfcp_fc_nameserver_init(struct zfcp_adapter *);
 
 /* zfcp_fsf.c */
 extern int zfcp_fsf_open_port(struct zfcp_erp_action *);
+extern int zfcp_fsf_open_wka_port(struct zfcp_wka_port *);
+extern int zfcp_fsf_close_wka_port(struct zfcp_wka_port *);
 extern int zfcp_fsf_close_port(struct zfcp_erp_action *);
 extern int zfcp_fsf_close_physical_port(struct zfcp_erp_action *);
 extern int zfcp_fsf_open_unit(struct zfcp_erp_action *);
@@ -135,10 +140,8 @@
 extern int zfcp_qdio_allocate(struct zfcp_adapter *);
 extern void zfcp_qdio_free(struct zfcp_adapter *);
 extern int zfcp_qdio_send(struct zfcp_fsf_req *);
-extern volatile struct qdio_buffer_element *zfcp_qdio_sbale_req(
-						struct zfcp_fsf_req *);
-extern volatile struct qdio_buffer_element *zfcp_qdio_sbale_curr(
-						struct zfcp_fsf_req *);
+extern struct qdio_buffer_element *zfcp_qdio_sbale_req(struct zfcp_fsf_req *);
+extern struct qdio_buffer_element *zfcp_qdio_sbale_curr(struct zfcp_fsf_req *);
 extern int zfcp_qdio_sbals_from_sg(struct zfcp_fsf_req *, unsigned long,
 				   struct scatterlist *, int);
 extern int zfcp_qdio_open(struct zfcp_adapter *);
@@ -148,14 +151,12 @@
 extern struct zfcp_data zfcp_data;
 extern int zfcp_adapter_scsi_register(struct zfcp_adapter *);
 extern void zfcp_adapter_scsi_unregister(struct zfcp_adapter *);
-extern void zfcp_set_fcp_dl(struct fcp_cmnd_iu *, fcp_dl_t);
 extern char *zfcp_get_fcp_sns_info_ptr(struct fcp_rsp_iu *);
 extern struct fc_function_template zfcp_transport_functions;
 
 /* zfcp_sysfs.c */
 extern struct attribute_group zfcp_sysfs_unit_attrs;
 extern struct attribute_group zfcp_sysfs_adapter_attrs;
-extern struct attribute_group zfcp_sysfs_ns_port_attrs;
 extern struct attribute_group zfcp_sysfs_port_attrs;
 extern struct device_attribute *zfcp_sysfs_sdev_attrs[];
 extern struct device_attribute *zfcp_sysfs_shost_attrs[];
diff --git a/drivers/s390/scsi/zfcp_fc.c b/drivers/s390/scsi/zfcp_fc.c
index 56196c9..1a7c80a 100644
--- a/drivers/s390/scsi/zfcp_fc.c
+++ b/drivers/s390/scsi/zfcp_fc.c
@@ -39,6 +39,84 @@
 	struct scatterlist sg_resp[ZFCP_GPN_FT_BUFFERS];
 };
 
+struct zfcp_fc_ns_handler_data {
+	struct completion done;
+	void (*handler)(unsigned long);
+	unsigned long handler_data;
+};
+
+static int zfcp_wka_port_get(struct zfcp_wka_port *wka_port)
+{
+	if (mutex_lock_interruptible(&wka_port->mutex))
+		return -ERESTARTSYS;
+
+	if (wka_port->status != ZFCP_WKA_PORT_ONLINE) {
+		wka_port->status = ZFCP_WKA_PORT_OPENING;
+		if (zfcp_fsf_open_wka_port(wka_port))
+			wka_port->status = ZFCP_WKA_PORT_OFFLINE;
+	}
+
+	mutex_unlock(&wka_port->mutex);
+
+	wait_event_timeout(
+		wka_port->completion_wq,
+		wka_port->status == ZFCP_WKA_PORT_ONLINE ||
+		wka_port->status == ZFCP_WKA_PORT_OFFLINE,
+		HZ >> 1);
+
+	if (wka_port->status == ZFCP_WKA_PORT_ONLINE) {
+		atomic_inc(&wka_port->refcount);
+		return 0;
+	}
+	return -EIO;
+}
+
+static void zfcp_wka_port_offline(struct work_struct *work)
+{
+	struct delayed_work *dw = container_of(work, struct delayed_work, work);
+	struct zfcp_wka_port *wka_port =
+			container_of(dw, struct zfcp_wka_port, work);
+
+	wait_event(wka_port->completion_wq,
+			atomic_read(&wka_port->refcount) == 0);
+
+	mutex_lock(&wka_port->mutex);
+	if ((atomic_read(&wka_port->refcount) != 0) ||
+	    (wka_port->status != ZFCP_WKA_PORT_ONLINE))
+		goto out;
+
+	wka_port->status = ZFCP_WKA_PORT_CLOSING;
+	if (zfcp_fsf_close_wka_port(wka_port)) {
+		wka_port->status = ZFCP_WKA_PORT_OFFLINE;
+		wake_up(&wka_port->completion_wq);
+	}
+out:
+	mutex_unlock(&wka_port->mutex);
+}
+
+static void zfcp_wka_port_put(struct zfcp_wka_port *wka_port)
+{
+	if (atomic_dec_return(&wka_port->refcount) != 0)
+		return;
+	/* wait 10 miliseconds, other reqs might pop in */
+	schedule_delayed_work(&wka_port->work, HZ / 100);
+}
+
+void zfcp_fc_nameserver_init(struct zfcp_adapter *adapter)
+{
+	struct zfcp_wka_port *wka_port = &adapter->nsp;
+
+	init_waitqueue_head(&wka_port->completion_wq);
+
+	wka_port->adapter = adapter;
+	wka_port->d_id = ZFCP_DID_DIRECTORY_SERVICE;
+
+	wka_port->status = ZFCP_WKA_PORT_OFFLINE;
+	atomic_set(&wka_port->refcount, 0);
+	mutex_init(&wka_port->mutex);
+	INIT_DELAYED_WORK(&wka_port->work, zfcp_wka_port_offline);
+}
+
 static void _zfcp_fc_incoming_rscn(struct zfcp_fsf_req *fsf_req, u32 range,
 				   struct fcp_rscn_element *elem)
 {
@@ -47,10 +125,8 @@
 
 	read_lock_irqsave(&zfcp_data.config_lock, flags);
 	list_for_each_entry(port, &fsf_req->adapter->port_list_head, list) {
-		if (atomic_test_mask(ZFCP_STATUS_PORT_WKA, &port->status))
-			continue;
 		/* FIXME: ZFCP_STATUS_PORT_DID_DID check is racy */
-		if (!atomic_test_mask(ZFCP_STATUS_PORT_DID_DID, &port->status))
+		if (!(atomic_read(&port->status) & ZFCP_STATUS_PORT_DID_DID))
 			/* Try to connect to unused ports anyway. */
 			zfcp_erp_port_reopen(port,
 					     ZFCP_STATUS_COMMON_ERP_FAILED,
@@ -102,7 +178,7 @@
 	schedule_work(&fsf_req->adapter->scan_work);
 }
 
-static void zfcp_fc_incoming_wwpn(struct zfcp_fsf_req *req, wwn_t wwpn)
+static void zfcp_fc_incoming_wwpn(struct zfcp_fsf_req *req, u64 wwpn)
 {
 	struct zfcp_adapter *adapter = req->adapter;
 	struct zfcp_port *port;
@@ -157,7 +233,18 @@
 		zfcp_fc_incoming_rscn(fsf_req);
 }
 
-static void zfcp_ns_gid_pn_handler(unsigned long data)
+static void zfcp_fc_ns_handler(unsigned long data)
+{
+	struct zfcp_fc_ns_handler_data *compl_rec =
+			(struct zfcp_fc_ns_handler_data *) data;
+
+	if (compl_rec->handler)
+		compl_rec->handler(compl_rec->handler_data);
+
+	complete(&compl_rec->done);
+}
+
+static void zfcp_fc_ns_gid_pn_eval(unsigned long data)
 {
 	struct zfcp_gid_pn_data *gid_pn = (struct zfcp_gid_pn_data *) data;
 	struct zfcp_send_ct *ct = &gid_pn->ct;
@@ -166,43 +253,31 @@
 	struct zfcp_port *port = gid_pn->port;
 
 	if (ct->status)
-		goto out;
+		return;
 	if (ct_iu_resp->header.cmd_rsp_code != ZFCP_CT_ACCEPT) {
 		atomic_set_mask(ZFCP_STATUS_PORT_INVALID_WWPN, &port->status);
-		goto out;
+		return;
 	}
 	/* paranoia */
 	if (ct_iu_req->wwpn != port->wwpn)
-		goto out;
+		return;
 	/* looks like a valid d_id */
 	port->d_id = ct_iu_resp->d_id & ZFCP_DID_MASK;
 	atomic_set_mask(ZFCP_STATUS_PORT_DID_DID, &port->status);
-out:
-	mempool_free(gid_pn, port->adapter->pool.data_gid_pn);
 }
 
-/**
- * zfcp_fc_ns_gid_pn_request - initiate GID_PN nameserver request
- * @erp_action: pointer to zfcp_erp_action where GID_PN request is needed
- * return: -ENOMEM on error, 0 otherwise
- */
-int zfcp_fc_ns_gid_pn_request(struct zfcp_erp_action *erp_action)
+int static zfcp_fc_ns_gid_pn_request(struct zfcp_erp_action *erp_action,
+				     struct zfcp_gid_pn_data *gid_pn)
 {
-	int ret;
-	struct zfcp_gid_pn_data *gid_pn;
 	struct zfcp_adapter *adapter = erp_action->adapter;
-
-	gid_pn = mempool_alloc(adapter->pool.data_gid_pn, GFP_ATOMIC);
-	if (!gid_pn)
-		return -ENOMEM;
-
-	memset(gid_pn, 0, sizeof(*gid_pn));
+	struct zfcp_fc_ns_handler_data compl_rec;
+	int ret;
 
 	/* setup parameters for send generic command */
 	gid_pn->port = erp_action->port;
-	gid_pn->ct.port = adapter->nameserver_port;
-	gid_pn->ct.handler = zfcp_ns_gid_pn_handler;
-	gid_pn->ct.handler_data = (unsigned long) gid_pn;
+	gid_pn->ct.wka_port = &adapter->nsp;
+	gid_pn->ct.handler = zfcp_fc_ns_handler;
+	gid_pn->ct.handler_data = (unsigned long) &compl_rec;
 	gid_pn->ct.timeout = ZFCP_NS_GID_PN_TIMEOUT;
 	gid_pn->ct.req = &gid_pn->req;
 	gid_pn->ct.resp = &gid_pn->resp;
@@ -222,10 +297,42 @@
 	gid_pn->ct_iu_req.header.max_res_size = ZFCP_CT_MAX_SIZE;
 	gid_pn->ct_iu_req.wwpn = erp_action->port->wwpn;
 
+	init_completion(&compl_rec.done);
+	compl_rec.handler = zfcp_fc_ns_gid_pn_eval;
+	compl_rec.handler_data = (unsigned long) gid_pn;
 	ret = zfcp_fsf_send_ct(&gid_pn->ct, adapter->pool.fsf_req_erp,
 			       erp_action);
+	if (!ret)
+		wait_for_completion(&compl_rec.done);
+	return ret;
+}
+
+/**
+ * zfcp_fc_ns_gid_pn_request - initiate GID_PN nameserver request
+ * @erp_action: pointer to zfcp_erp_action where GID_PN request is needed
+ * return: -ENOMEM on error, 0 otherwise
+ */
+int zfcp_fc_ns_gid_pn(struct zfcp_erp_action *erp_action)
+{
+	int ret;
+	struct zfcp_gid_pn_data *gid_pn;
+	struct zfcp_adapter *adapter = erp_action->adapter;
+
+	gid_pn = mempool_alloc(adapter->pool.data_gid_pn, GFP_ATOMIC);
+	if (!gid_pn)
+		return -ENOMEM;
+
+	memset(gid_pn, 0, sizeof(*gid_pn));
+
+	ret = zfcp_wka_port_get(&adapter->nsp);
 	if (ret)
-		mempool_free(gid_pn, adapter->pool.data_gid_pn);
+		goto out;
+
+	ret = zfcp_fc_ns_gid_pn_request(erp_action, gid_pn);
+
+	zfcp_wka_port_put(&adapter->nsp);
+out:
+	mempool_free(gid_pn, adapter->pool.data_gid_pn);
 	return ret;
 }
 
@@ -255,14 +362,14 @@
 	struct scatterlist req;
 	struct scatterlist resp;
 	struct zfcp_ls_adisc ls_adisc;
-	struct zfcp_ls_adisc_acc ls_adisc_acc;
+	struct zfcp_ls_adisc ls_adisc_acc;
 };
 
 static void zfcp_fc_adisc_handler(unsigned long data)
 {
 	struct zfcp_els_adisc *adisc = (struct zfcp_els_adisc *) data;
 	struct zfcp_port *port = adisc->els.port;
-	struct zfcp_ls_adisc_acc *ls_adisc = &adisc->ls_adisc_acc;
+	struct zfcp_ls_adisc *ls_adisc = &adisc->ls_adisc_acc;
 
 	if (adisc->els.status) {
 		/* request rejected or timed out */
@@ -295,7 +402,7 @@
 	sg_init_one(adisc->els.req, &adisc->ls_adisc,
 		    sizeof(struct zfcp_ls_adisc));
 	sg_init_one(adisc->els.resp, &adisc->ls_adisc_acc,
-		    sizeof(struct zfcp_ls_adisc_acc));
+		    sizeof(struct zfcp_ls_adisc));
 
 	adisc->els.req_count = 1;
 	adisc->els.resp_count = 1;
@@ -338,30 +445,6 @@
 		zfcp_erp_port_forced_reopen(port, 0, 65, NULL);
 }
 
-static int zfcp_scan_get_nameserver(struct zfcp_adapter *adapter)
-{
-	int ret;
-
-	if (!adapter->nameserver_port)
-		return -EINTR;
-
-	if (!atomic_test_mask(ZFCP_STATUS_COMMON_UNBLOCKED,
-			       &adapter->nameserver_port->status)) {
-		ret = zfcp_erp_port_reopen(adapter->nameserver_port, 0, 148,
-					   NULL);
-		if (ret)
-			return ret;
-		zfcp_erp_wait(adapter);
-	}
-	return !atomic_test_mask(ZFCP_STATUS_COMMON_UNBLOCKED,
-				  &adapter->nameserver_port->status);
-}
-
-static void zfcp_gpn_ft_handler(unsigned long _done)
-{
-	complete((struct completion *)_done);
-}
-
 static void zfcp_free_sg_env(struct zfcp_gpn_ft *gpn_ft)
 {
 	struct scatterlist *sg = &gpn_ft->sg_req;
@@ -403,7 +486,7 @@
 {
 	struct zfcp_send_ct *ct = &gpn_ft->ct;
 	struct ct_iu_gpn_ft_req *req = sg_virt(&gpn_ft->sg_req);
-	struct completion done;
+	struct zfcp_fc_ns_handler_data compl_rec;
 	int ret;
 
 	/* prepare CT IU for GPN_FT */
@@ -420,19 +503,20 @@
 	req->fc4_type = ZFCP_CT_SCSI_FCP;
 
 	/* prepare zfcp_send_ct */
-	ct->port = adapter->nameserver_port;
-	ct->handler = zfcp_gpn_ft_handler;
-	ct->handler_data = (unsigned long)&done;
+	ct->wka_port = &adapter->nsp;
+	ct->handler = zfcp_fc_ns_handler;
+	ct->handler_data = (unsigned long)&compl_rec;
 	ct->timeout = 10;
 	ct->req = &gpn_ft->sg_req;
 	ct->resp = gpn_ft->sg_resp;
 	ct->req_count = 1;
 	ct->resp_count = ZFCP_GPN_FT_BUFFERS;
 
-	init_completion(&done);
+	init_completion(&compl_rec.done);
+	compl_rec.handler = NULL;
 	ret = zfcp_fsf_send_ct(ct, NULL, NULL);
 	if (!ret)
-		wait_for_completion(&done);
+		wait_for_completion(&compl_rec.done);
 	return ret;
 }
 
@@ -442,9 +526,8 @@
 
 	atomic_clear_mask(ZFCP_STATUS_COMMON_NOESC, &port->status);
 
-	if (port == adapter->nameserver_port)
-		return;
-	if ((port->supported_classes != 0) || (port->units != 0)) {
+	if ((port->supported_classes != 0) ||
+	    !list_empty(&port->unit_list_head)) {
 		zfcp_port_put(port);
 		return;
 	}
@@ -460,7 +543,7 @@
 	struct scatterlist *sg = gpn_ft->sg_resp;
 	struct ct_hdr *hdr = sg_virt(sg);
 	struct gpn_ft_resp_acc *acc = sg_virt(sg);
-	struct zfcp_adapter *adapter = ct->port->adapter;
+	struct zfcp_adapter *adapter = ct->wka_port->adapter;
 	struct zfcp_port *port, *tmp;
 	u32 d_id;
 	int ret = 0, x, last = 0;
@@ -490,6 +573,9 @@
 		d_id = acc->port_id[0] << 16 | acc->port_id[1] << 8 |
 		       acc->port_id[2];
 
+		/* don't attach ports with a well known address */
+		if ((d_id & ZFCP_DID_WKA) == ZFCP_DID_WKA)
+			continue;
 		/* skip the adapter's port and known remote ports */
 		if (acc->wwpn == fc_host_port_name(adapter->scsi_host))
 			continue;
@@ -528,13 +614,15 @@
 	if (fc_host_port_type(adapter->scsi_host) != FC_PORTTYPE_NPORT)
 		return 0;
 
-	ret = zfcp_scan_get_nameserver(adapter);
+	ret = zfcp_wka_port_get(&adapter->nsp);
 	if (ret)
 		return ret;
 
 	gpn_ft = zfcp_alloc_sg_env();
-	if (!gpn_ft)
-		return -ENOMEM;
+	if (!gpn_ft) {
+		ret = -ENOMEM;
+		goto out;
+	}
 
 	for (i = 0; i < 3; i++) {
 		ret = zfcp_scan_issue_gpn_ft(gpn_ft, adapter);
@@ -547,7 +635,8 @@
 		}
 	}
 	zfcp_free_sg_env(gpn_ft);
-
+out:
+	zfcp_wka_port_put(&adapter->nsp);
 	return ret;
 }
 
diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c
index 49dbeb7..739356a 100644
--- a/drivers/s390/scsi/zfcp_fsf.c
+++ b/drivers/s390/scsi/zfcp_fsf.c
@@ -50,19 +50,16 @@
 	[FSF_QTCB_UPLOAD_CONTROL_FILE] =  FSF_SUPPORT_COMMAND
 };
 
-static const char *zfcp_act_subtable_type[] = {
-	"unknown", "OS", "WWPN", "DID", "LUN"
-};
-
 static void zfcp_act_eval_err(struct zfcp_adapter *adapter, u32 table)
 {
 	u16 subtable = table >> 16;
 	u16 rule = table & 0xffff;
+	const char *act_type[] = { "unknown", "OS", "WWPN", "DID", "LUN" };
 
-	if (subtable && subtable < ARRAY_SIZE(zfcp_act_subtable_type))
+	if (subtable && subtable < ARRAY_SIZE(act_type))
 		dev_warn(&adapter->ccw_device->dev,
-			 "Access denied in subtable %s, rule %d.\n",
-			 zfcp_act_subtable_type[subtable], rule);
+			 "Access denied according to ACT rule type %s, "
+			 "rule %d\n", act_type[subtable], rule);
 }
 
 static void zfcp_fsf_access_denied_port(struct zfcp_fsf_req *req,
@@ -70,8 +67,8 @@
 {
 	struct fsf_qtcb_header *header = &req->qtcb->header;
 	dev_warn(&req->adapter->ccw_device->dev,
-		 "Access denied, cannot send command to port 0x%016Lx.\n",
-		 port->wwpn);
+		 "Access denied to port 0x%016Lx\n",
+		 (unsigned long long)port->wwpn);
 	zfcp_act_eval_err(req->adapter, header->fsf_status_qual.halfword[0]);
 	zfcp_act_eval_err(req->adapter, header->fsf_status_qual.halfword[1]);
 	zfcp_erp_port_access_denied(port, 55, req);
@@ -83,8 +80,9 @@
 {
 	struct fsf_qtcb_header *header = &req->qtcb->header;
 	dev_warn(&req->adapter->ccw_device->dev,
-		 "Access denied for unit 0x%016Lx on port 0x%016Lx.\n",
-		 unit->fcp_lun, unit->port->wwpn);
+		 "Access denied to unit 0x%016Lx on port 0x%016Lx\n",
+		 (unsigned long long)unit->fcp_lun,
+		 (unsigned long long)unit->port->wwpn);
 	zfcp_act_eval_err(req->adapter, header->fsf_status_qual.halfword[0]);
 	zfcp_act_eval_err(req->adapter, header->fsf_status_qual.halfword[1]);
 	zfcp_erp_unit_access_denied(unit, 59, req);
@@ -93,9 +91,8 @@
 
 static void zfcp_fsf_class_not_supp(struct zfcp_fsf_req *req)
 {
-	dev_err(&req->adapter->ccw_device->dev,
-		"Required FC class not supported by adapter, "
-		"shutting down adapter.\n");
+	dev_err(&req->adapter->ccw_device->dev, "FCP device not "
+		"operational because of an unsupported FC class\n");
 	zfcp_erp_adapter_shutdown(req->adapter, 0, 123, req);
 	req->status |= ZFCP_STATUS_FSFREQ_ERROR;
 }
@@ -171,42 +168,6 @@
 	read_unlock_irqrestore(&zfcp_data.config_lock, flags);
 }
 
-static void zfcp_fsf_bit_error_threshold(struct zfcp_fsf_req *req)
-{
-	struct zfcp_adapter *adapter = req->adapter;
-	struct fsf_status_read_buffer *sr_buf = req->data;
-	struct fsf_bit_error_payload *err = &sr_buf->payload.bit_error;
-
-	dev_warn(&adapter->ccw_device->dev,
-		 "Warning: bit error threshold data "
-		 "received for the adapter: "
-		 "link failures = %i, loss of sync errors = %i, "
-		 "loss of signal errors = %i, "
-		 "primitive sequence errors = %i, "
-		 "invalid transmission word errors = %i, "
-		 "CRC errors = %i).\n",
-		 err->link_failure_error_count,
-		 err->loss_of_sync_error_count,
-		 err->loss_of_signal_error_count,
-		 err->primitive_sequence_error_count,
-		 err->invalid_transmission_word_error_count,
-		 err->crc_error_count);
-	dev_warn(&adapter->ccw_device->dev,
-		 "Additional bit error threshold data of the adapter: "
-		 "primitive sequence event time-outs = %i, "
-		 "elastic buffer overrun errors = %i, "
-		 "advertised receive buffer-to-buffer credit = %i, "
-		 "current receice buffer-to-buffer credit = %i, "
-		 "advertised transmit buffer-to-buffer credit = %i, "
-		 "current transmit buffer-to-buffer credit = %i).\n",
-		 err->primitive_sequence_event_timeout_count,
-		 err->elastic_buffer_overrun_error_count,
-		 err->advertised_receive_b2b_credit,
-		 err->current_receive_b2b_credit,
-		 err->advertised_transmit_b2b_credit,
-		 err->current_transmit_b2b_credit);
-}
-
 static void zfcp_fsf_link_down_info_eval(struct zfcp_fsf_req *req, u8 id,
 					 struct fsf_link_down_info *link_down)
 {
@@ -223,62 +184,66 @@
 	switch (link_down->error_code) {
 	case FSF_PSQ_LINK_NO_LIGHT:
 		dev_warn(&req->adapter->ccw_device->dev,
-			 "The local link is down: no light detected.\n");
+			 "There is no light signal from the local "
+			 "fibre channel cable\n");
 		break;
 	case FSF_PSQ_LINK_WRAP_PLUG:
 		dev_warn(&req->adapter->ccw_device->dev,
-			 "The local link is down: wrap plug detected.\n");
+			 "There is a wrap plug instead of a fibre "
+			 "channel cable\n");
 		break;
 	case FSF_PSQ_LINK_NO_FCP:
 		dev_warn(&req->adapter->ccw_device->dev,
-			 "The local link is down: "
-			 "adjacent node on link does not support FCP.\n");
+			 "The adjacent fibre channel node does not "
+			 "support FCP\n");
 		break;
 	case FSF_PSQ_LINK_FIRMWARE_UPDATE:
 		dev_warn(&req->adapter->ccw_device->dev,
-			 "The local link is down: "
-			 "firmware update in progress.\n");
+			 "The FCP device is suspended because of a "
+			 "firmware update\n");
 		break;
 	case FSF_PSQ_LINK_INVALID_WWPN:
 		dev_warn(&req->adapter->ccw_device->dev,
-			 "The local link is down: "
-			 "duplicate or invalid WWPN detected.\n");
+			 "The FCP device detected a WWPN that is "
+			 "duplicate or not valid\n");
 		break;
 	case FSF_PSQ_LINK_NO_NPIV_SUPPORT:
 		dev_warn(&req->adapter->ccw_device->dev,
-			 "The local link is down: "
-			 "no support for NPIV by Fabric.\n");
+			 "The fibre channel fabric does not support NPIV\n");
 		break;
 	case FSF_PSQ_LINK_NO_FCP_RESOURCES:
 		dev_warn(&req->adapter->ccw_device->dev,
-			 "The local link is down: "
-			 "out of resource in FCP daughtercard.\n");
+			 "The FCP adapter cannot support more NPIV ports\n");
 		break;
 	case FSF_PSQ_LINK_NO_FABRIC_RESOURCES:
 		dev_warn(&req->adapter->ccw_device->dev,
-			 "The local link is down: "
-			 "out of resource in Fabric.\n");
+			 "The adjacent switch cannot support "
+			 "more NPIV ports\n");
 		break;
 	case FSF_PSQ_LINK_FABRIC_LOGIN_UNABLE:
 		dev_warn(&req->adapter->ccw_device->dev,
-			 "The local link is down: "
-			 "unable to login to Fabric.\n");
+			 "The FCP adapter could not log in to the "
+			 "fibre channel fabric\n");
 		break;
 	case FSF_PSQ_LINK_WWPN_ASSIGNMENT_CORRUPTED:
 		dev_warn(&req->adapter->ccw_device->dev,
-			 "WWPN assignment file corrupted on adapter.\n");
+			 "The WWPN assignment file on the FCP adapter "
+			 "has been damaged\n");
 		break;
 	case FSF_PSQ_LINK_MODE_TABLE_CURRUPTED:
 		dev_warn(&req->adapter->ccw_device->dev,
-			 "Mode table corrupted on adapter.\n");
+			 "The mode table on the FCP adapter "
+			 "has been damaged\n");
 		break;
 	case FSF_PSQ_LINK_NO_WWPN_ASSIGNMENT:
 		dev_warn(&req->adapter->ccw_device->dev,
-			 "No WWPN for assignment table on adapter.\n");
+			 "All NPIV ports on the FCP adapter have "
+			 "been assigned\n");
 		break;
 	default:
 		dev_warn(&req->adapter->ccw_device->dev,
-			 "The local link to adapter is down.\n");
+			 "The link between the FCP adapter and "
+			 "the FC fabric is down\n");
 	}
 out:
 	zfcp_erp_adapter_failed(adapter, id, req);
@@ -286,27 +251,18 @@
 
 static void zfcp_fsf_status_read_link_down(struct zfcp_fsf_req *req)
 {
-	struct zfcp_adapter *adapter = req->adapter;
 	struct fsf_status_read_buffer *sr_buf = req->data;
 	struct fsf_link_down_info *ldi =
 		(struct fsf_link_down_info *) &sr_buf->payload;
 
 	switch (sr_buf->status_subtype) {
 	case FSF_STATUS_READ_SUB_NO_PHYSICAL_LINK:
-		dev_warn(&adapter->ccw_device->dev,
-			 "Physical link is down.\n");
 		zfcp_fsf_link_down_info_eval(req, 38, ldi);
 		break;
 	case FSF_STATUS_READ_SUB_FDISC_FAILED:
-		dev_warn(&adapter->ccw_device->dev,
-			 "Local link is down "
-			 "due to failed FDISC login.\n");
 		zfcp_fsf_link_down_info_eval(req, 39, ldi);
 		break;
 	case FSF_STATUS_READ_SUB_FIRMWARE_UPDATE:
-		dev_warn(&adapter->ccw_device->dev,
-			 "Local link is down "
-			 "due to firmware update on adapter.\n");
 		zfcp_fsf_link_down_info_eval(req, 40, NULL);
 	};
 }
@@ -335,14 +291,17 @@
 	case FSF_STATUS_READ_SENSE_DATA_AVAIL:
 		break;
 	case FSF_STATUS_READ_BIT_ERROR_THRESHOLD:
-		zfcp_fsf_bit_error_threshold(req);
+		dev_warn(&adapter->ccw_device->dev,
+			 "The error threshold for checksum statistics "
+			 "has been exceeded\n");
+		zfcp_hba_dbf_event_berr(adapter, req);
 		break;
 	case FSF_STATUS_READ_LINK_DOWN:
 		zfcp_fsf_status_read_link_down(req);
 		break;
 	case FSF_STATUS_READ_LINK_UP:
 		dev_info(&adapter->ccw_device->dev,
-			 "Local link was replugged.\n");
+			 "The local link has been restored\n");
 		/* All ports should be marked as ready to run again */
 		zfcp_erp_modify_adapter_status(adapter, 30, NULL,
 					       ZFCP_STATUS_COMMON_RUNNING,
@@ -370,7 +329,7 @@
 	zfcp_fsf_req_free(req);
 
 	atomic_inc(&adapter->stat_miss);
-	schedule_work(&adapter->stat_work);
+	queue_work(zfcp_data.work_queue, &adapter->stat_work);
 }
 
 static void zfcp_fsf_fsfstatus_qual_eval(struct zfcp_fsf_req *req)
@@ -386,8 +345,8 @@
 		break;
 	case FSF_SQ_NO_RECOM:
 		dev_err(&req->adapter->ccw_device->dev,
-			"No recommendation could be given for a "
-			"problem on the adapter.\n");
+			"The FCP adapter reported a problem "
+			"that cannot be recovered\n");
 		zfcp_erp_adapter_shutdown(req->adapter, 0, 121, req);
 		break;
 	}
@@ -403,8 +362,7 @@
 	switch (req->qtcb->header.fsf_status) {
 	case FSF_UNKNOWN_COMMAND:
 		dev_err(&req->adapter->ccw_device->dev,
-			"Command issued by the device driver (0x%x) is "
-			"not known by the adapter.\n",
+			"The FCP adapter does not recognize the command 0x%x\n",
 			req->qtcb->header.fsf_command);
 		zfcp_erp_adapter_shutdown(req->adapter, 0, 120, req);
 		req->status |= ZFCP_STATUS_FSFREQ_ERROR;
@@ -435,11 +393,9 @@
 		return;
 	case FSF_PROT_QTCB_VERSION_ERROR:
 		dev_err(&adapter->ccw_device->dev,
-			"The QTCB version requested by zfcp (0x%x) is not "
-			"supported by the FCP adapter (lowest supported "
-			"0x%x, highest supported 0x%x).\n",
-			FSF_QTCB_CURRENT_VERSION, psq->word[0],
-			psq->word[1]);
+			"QTCB version 0x%x not supported by FCP adapter "
+			"(0x%x to 0x%x)\n", FSF_QTCB_CURRENT_VERSION,
+			psq->word[0], psq->word[1]);
 		zfcp_erp_adapter_shutdown(adapter, 0, 117, req);
 		break;
 	case FSF_PROT_ERROR_STATE:
@@ -449,8 +405,7 @@
 		break;
 	case FSF_PROT_UNSUPP_QTCB_TYPE:
 		dev_err(&adapter->ccw_device->dev,
-			"Packet header type used by the device driver is "
-			"incompatible with that used on the adapter.\n");
+			"The QTCB type is not supported by the FCP adapter\n");
 		zfcp_erp_adapter_shutdown(adapter, 0, 118, req);
 		break;
 	case FSF_PROT_HOST_CONNECTION_INITIALIZING:
@@ -459,7 +414,7 @@
 		break;
 	case FSF_PROT_DUPLICATE_REQUEST_ID:
 		dev_err(&adapter->ccw_device->dev,
-			"The request identifier 0x%Lx is ambiguous.\n",
+			"0x%Lx is an ambiguous request identifier\n",
 			(unsigned long long)qtcb->bottom.support.req_handle);
 		zfcp_erp_adapter_shutdown(adapter, 0, 78, req);
 		break;
@@ -479,9 +434,7 @@
 		break;
 	default:
 		dev_err(&adapter->ccw_device->dev,
-			"Transfer protocol status information"
-			"provided by the adapter (0x%x) "
-			"is not compatible with the device driver.\n",
+			"0x%x is not a valid transfer protocol status\n",
 			qtcb->prefix.prot_status);
 		zfcp_erp_adapter_shutdown(adapter, 0, 119, req);
 	}
@@ -559,33 +512,17 @@
 		adapter->peer_wwpn = bottom->plogi_payload.wwpn;
 		adapter->peer_wwnn = bottom->plogi_payload.wwnn;
 		fc_host_port_type(shost) = FC_PORTTYPE_PTP;
-		if (req->erp_action)
-			dev_info(&adapter->ccw_device->dev,
-				 "Point-to-Point fibrechannel "
-				 "configuration detected.\n");
 		break;
 	case FSF_TOPO_FABRIC:
 		fc_host_port_type(shost) = FC_PORTTYPE_NPORT;
-		if (req->erp_action)
-			dev_info(&adapter->ccw_device->dev,
-				 "Switched fabric fibrechannel "
-				 "network detected.\n");
 		break;
 	case FSF_TOPO_AL:
 		fc_host_port_type(shost) = FC_PORTTYPE_NLPORT;
-		dev_err(&adapter->ccw_device->dev,
-			"Unsupported arbitrated loop fibrechannel "
-			"topology detected, shutting down "
-			"adapter.\n");
-		zfcp_erp_adapter_shutdown(adapter, 0, 127, req);
-		return -EIO;
 	default:
-		fc_host_port_type(shost) = FC_PORTTYPE_UNKNOWN;
 		dev_err(&adapter->ccw_device->dev,
-			"The fibrechannel topology reported by the"
-			" adapter is not known by the zfcp driver,"
-			" shutting down adapter.\n");
-		zfcp_erp_adapter_shutdown(adapter, 0, 128, req);
+			"Unknown or unsupported arbitrated loop "
+			"fibre channel topology detected\n");
+		zfcp_erp_adapter_shutdown(adapter, 0, 127, req);
 		return -EIO;
 	}
 
@@ -616,11 +553,9 @@
 
 		if (bottom->max_qtcb_size < sizeof(struct fsf_qtcb)) {
 			dev_err(&adapter->ccw_device->dev,
-				"Maximum QTCB size (%d bytes) allowed by "
-				"the adapter is lower than the minimum "
-				"required by the driver (%ld bytes).\n",
-				bottom->max_qtcb_size,
-				sizeof(struct fsf_qtcb));
+				"FCP adapter maximum QTCB size (%d bytes) "
+				"is too small\n",
+				bottom->max_qtcb_size);
 			zfcp_erp_adapter_shutdown(adapter, 0, 129, req);
 			return;
 		}
@@ -656,15 +591,15 @@
 
 	if (FSF_QTCB_CURRENT_VERSION < bottom->low_qtcb_version) {
 		dev_err(&adapter->ccw_device->dev,
-			"The adapter only supports newer control block "
-			"versions, try updated device driver.\n");
+			"The FCP adapter only supports newer "
+			"control block versions\n");
 		zfcp_erp_adapter_shutdown(adapter, 0, 125, req);
 		return;
 	}
 	if (FSF_QTCB_CURRENT_VERSION > bottom->high_qtcb_version) {
 		dev_err(&adapter->ccw_device->dev,
-			"The adapter only supports older control block "
-			"versions, consider a microcode upgrade.\n");
+			"The FCP adapter only supports older "
+			"control block versions\n");
 		zfcp_erp_adapter_shutdown(adapter, 0, 126, req);
 	}
 }
@@ -688,7 +623,6 @@
 
 static void zfcp_fsf_exchange_port_data_handler(struct zfcp_fsf_req *req)
 {
-	struct zfcp_adapter *adapter = req->adapter;
 	struct fsf_qtcb *qtcb = req->qtcb;
 
 	if (req->status & ZFCP_STATUS_FSFREQ_ERROR)
@@ -697,38 +631,47 @@
 	switch (qtcb->header.fsf_status) {
 	case FSF_GOOD:
 		zfcp_fsf_exchange_port_evaluate(req);
-		atomic_set_mask(ZFCP_STATUS_ADAPTER_XPORT_OK, &adapter->status);
 		break;
 	case FSF_EXCHANGE_CONFIG_DATA_INCOMPLETE:
 		zfcp_fsf_exchange_port_evaluate(req);
-		atomic_set_mask(ZFCP_STATUS_ADAPTER_XPORT_OK, &adapter->status);
 		zfcp_fsf_link_down_info_eval(req, 43,
 			&qtcb->header.fsf_status_qual.link_down_info);
 		break;
 	}
 }
 
-static int zfcp_fsf_sbal_check(struct zfcp_qdio_queue *queue)
+static int zfcp_fsf_sbal_check(struct zfcp_adapter *adapter)
 {
-	spin_lock_bh(&queue->lock);
-	if (atomic_read(&queue->count))
+	struct zfcp_qdio_queue *req_q = &adapter->req_q;
+
+	spin_lock_bh(&adapter->req_q_lock);
+	if (atomic_read(&req_q->count))
 		return 1;
-	spin_unlock_bh(&queue->lock);
+	spin_unlock_bh(&adapter->req_q_lock);
 	return 0;
 }
 
+static int zfcp_fsf_sbal_available(struct zfcp_adapter *adapter)
+{
+	unsigned int count = atomic_read(&adapter->req_q.count);
+	if (!count)
+		atomic_inc(&adapter->qdio_outb_full);
+	return count > 0;
+}
+
 static int zfcp_fsf_req_sbal_get(struct zfcp_adapter *adapter)
 {
 	long ret;
-	struct zfcp_qdio_queue *req_q = &adapter->req_q;
 
-	spin_unlock_bh(&req_q->lock);
+	spin_unlock_bh(&adapter->req_q_lock);
 	ret = wait_event_interruptible_timeout(adapter->request_wq,
-					zfcp_fsf_sbal_check(req_q), 5 * HZ);
+					zfcp_fsf_sbal_check(adapter), 5 * HZ);
 	if (ret > 0)
 		return 0;
+	if (!ret)
+		atomic_inc(&adapter->qdio_outb_full);
 
-	spin_lock_bh(&req_q->lock);
+	spin_lock_bh(&adapter->req_q_lock);
 	return -EIO;
 }
 
@@ -765,7 +708,7 @@
 						u32 fsf_cmd, int req_flags,
 						mempool_t *pool)
 {
-	volatile struct qdio_buffer_element *sbale;
+	struct qdio_buffer_element *sbale;
 
 	struct zfcp_fsf_req *req;
 	struct zfcp_qdio_queue *req_q = &adapter->req_q;
@@ -867,10 +810,10 @@
 {
 	struct zfcp_fsf_req *req;
 	struct fsf_status_read_buffer *sr_buf;
-	volatile struct qdio_buffer_element *sbale;
+	struct qdio_buffer_element *sbale;
 	int retval = -EIO;
 
-	spin_lock_bh(&adapter->req_q.lock);
+	spin_lock_bh(&adapter->req_q_lock);
 	if (zfcp_fsf_req_sbal_get(adapter))
 		goto out;
 
@@ -910,7 +853,7 @@
 	zfcp_fsf_req_free(req);
 	zfcp_hba_dbf_event_fsf_unsol("fail", adapter, NULL);
 out:
-	spin_unlock_bh(&adapter->req_q.lock);
+	spin_unlock_bh(&adapter->req_q_lock);
 	return retval;
 }
 
@@ -980,11 +923,11 @@
 						struct zfcp_unit *unit,
 						int req_flags)
 {
-	volatile struct qdio_buffer_element *sbale;
+	struct qdio_buffer_element *sbale;
 	struct zfcp_fsf_req *req = NULL;
 
-	spin_lock(&adapter->req_q.lock);
-	if (!atomic_read(&adapter->req_q.count))
+	spin_lock(&adapter->req_q_lock);
+	if (!zfcp_fsf_sbal_available(adapter))
 		goto out;
 	req = zfcp_fsf_req_create(adapter, FSF_QTCB_ABORT_FCP_CMND,
 				  req_flags, adapter->pool.fsf_req_abort);
@@ -1013,7 +956,7 @@
 	zfcp_fsf_req_free(req);
 	req = NULL;
 out:
-	spin_unlock(&adapter->req_q.lock);
+	spin_unlock(&adapter->req_q_lock);
 	return req;
 }
 
@@ -1021,7 +964,6 @@
 {
 	struct zfcp_adapter *adapter = req->adapter;
 	struct zfcp_send_ct *send_ct = req->data;
-	struct zfcp_port *port = send_ct->port;
 	struct fsf_qtcb_header *header = &req->qtcb->header;
 
 	send_ct->status = -EINVAL;
@@ -1040,17 +982,14 @@
         case FSF_ADAPTER_STATUS_AVAILABLE:
                 switch (header->fsf_status_qual.word[0]){
                 case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE:
-			zfcp_test_link(port);
                 case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED:
 			req->status |= ZFCP_STATUS_FSFREQ_ERROR;
 			break;
                 }
                 break;
 	case FSF_ACCESS_DENIED:
-		zfcp_fsf_access_denied_port(req, port);
 		break;
         case FSF_PORT_BOXED:
-		zfcp_erp_port_boxed(port, 49, req);
 		req->status |= ZFCP_STATUS_FSFREQ_ERROR |
 			       ZFCP_STATUS_FSFREQ_RETRY;
 		break;
@@ -1101,12 +1040,12 @@
 int zfcp_fsf_send_ct(struct zfcp_send_ct *ct, mempool_t *pool,
 		     struct zfcp_erp_action *erp_action)
 {
-	struct zfcp_port *port = ct->port;
-	struct zfcp_adapter *adapter = port->adapter;
+	struct zfcp_wka_port *wka_port = ct->wka_port;
+	struct zfcp_adapter *adapter = wka_port->adapter;
 	struct zfcp_fsf_req *req;
 	int ret = -EIO;
 
-	spin_lock_bh(&adapter->req_q.lock);
+	spin_lock_bh(&adapter->req_q_lock);
 	if (zfcp_fsf_req_sbal_get(adapter))
 		goto out;
 
@@ -1123,7 +1062,7 @@
 		goto failed_send;
 
 	req->handler = zfcp_fsf_send_ct_handler;
-	req->qtcb->header.port_handle = port->handle;
+	req->qtcb->header.port_handle = wka_port->handle;
 	req->qtcb->bottom.support.service_class = FSF_CLASS_3;
 	req->qtcb->bottom.support.timeout = ct->timeout;
 	req->data = ct;
@@ -1148,7 +1087,7 @@
 	if (erp_action)
 		erp_action->fsf_req = NULL;
 out:
-	spin_unlock_bh(&adapter->req_q.lock);
+	spin_unlock_bh(&adapter->req_q_lock);
 	return ret;
 }
 
@@ -1218,8 +1157,8 @@
 		       ZFCP_STATUS_COMMON_UNBLOCKED)))
 		return -EBUSY;
 
-	spin_lock(&adapter->req_q.lock);
-	if (!atomic_read(&adapter->req_q.count))
+	spin_lock(&adapter->req_q_lock);
+	if (!zfcp_fsf_sbal_available(adapter))
 		goto out;
 	req = zfcp_fsf_req_create(adapter, FSF_QTCB_SEND_ELS,
 				  ZFCP_REQ_AUTO_CLEANUP, NULL);
@@ -1228,8 +1167,8 @@
 		goto out;
 	}
 
-	ret = zfcp_fsf_setup_sbals(req, els->req, els->resp,
-				   FSF_MAX_SBALS_PER_ELS_REQ);
+	ret = zfcp_fsf_setup_sbals(req, els->req, els->resp, 2);
+
 	if (ret)
 		goto failed_send;
 
@@ -1252,19 +1191,19 @@
 failed_send:
 	zfcp_fsf_req_free(req);
 out:
-	spin_unlock(&adapter->req_q.lock);
+	spin_unlock(&adapter->req_q_lock);
 	return ret;
 }
 
 int zfcp_fsf_exchange_config_data(struct zfcp_erp_action *erp_action)
 {
-	volatile struct qdio_buffer_element *sbale;
+	struct qdio_buffer_element *sbale;
 	struct zfcp_fsf_req *req;
 	struct zfcp_adapter *adapter = erp_action->adapter;
 	int retval = -EIO;
 
-	spin_lock_bh(&adapter->req_q.lock);
-	if (!atomic_read(&adapter->req_q.count))
+	spin_lock_bh(&adapter->req_q_lock);
+	if (!zfcp_fsf_sbal_available(adapter))
 		goto out;
 	req = zfcp_fsf_req_create(adapter,
 				  FSF_QTCB_EXCHANGE_CONFIG_DATA,
@@ -1295,18 +1234,18 @@
 		erp_action->fsf_req = NULL;
 	}
 out:
-	spin_unlock_bh(&adapter->req_q.lock);
+	spin_unlock_bh(&adapter->req_q_lock);
 	return retval;
 }
 
 int zfcp_fsf_exchange_config_data_sync(struct zfcp_adapter *adapter,
 				       struct fsf_qtcb_bottom_config *data)
 {
-	volatile struct qdio_buffer_element *sbale;
+	struct qdio_buffer_element *sbale;
 	struct zfcp_fsf_req *req = NULL;
 	int retval = -EIO;
 
-	spin_lock_bh(&adapter->req_q.lock);
+	spin_lock_bh(&adapter->req_q_lock);
 	if (zfcp_fsf_req_sbal_get(adapter))
 		goto out;
 
@@ -1334,7 +1273,7 @@
 	zfcp_fsf_start_timer(req, ZFCP_FSF_REQUEST_TIMEOUT);
 	retval = zfcp_fsf_req_send(req);
 out:
-	spin_unlock_bh(&adapter->req_q.lock);
+	spin_unlock_bh(&adapter->req_q_lock);
 	if (!retval)
 		wait_event(req->completion_wq,
 			   req->status & ZFCP_STATUS_FSFREQ_COMPLETED);
@@ -1351,7 +1290,7 @@
  */
 int zfcp_fsf_exchange_port_data(struct zfcp_erp_action *erp_action)
 {
-	volatile struct qdio_buffer_element *sbale;
+	struct qdio_buffer_element *sbale;
 	struct zfcp_fsf_req *req;
 	struct zfcp_adapter *adapter = erp_action->adapter;
 	int retval = -EIO;
@@ -1359,8 +1298,8 @@
 	if (!(adapter->adapter_features & FSF_FEATURE_HBAAPI_MANAGEMENT))
 		return -EOPNOTSUPP;
 
-	spin_lock_bh(&adapter->req_q.lock);
-	if (!atomic_read(&adapter->req_q.count))
+	spin_lock_bh(&adapter->req_q_lock);
+	if (!zfcp_fsf_sbal_available(adapter))
 		goto out;
 	req = zfcp_fsf_req_create(adapter, FSF_QTCB_EXCHANGE_PORT_DATA,
 				  ZFCP_REQ_AUTO_CLEANUP,
@@ -1385,7 +1324,7 @@
 		erp_action->fsf_req = NULL;
 	}
 out:
-	spin_unlock_bh(&adapter->req_q.lock);
+	spin_unlock_bh(&adapter->req_q_lock);
 	return retval;
 }
 
@@ -1398,15 +1337,15 @@
 int zfcp_fsf_exchange_port_data_sync(struct zfcp_adapter *adapter,
 				     struct fsf_qtcb_bottom_port *data)
 {
-	volatile struct qdio_buffer_element *sbale;
+	struct qdio_buffer_element *sbale;
 	struct zfcp_fsf_req *req = NULL;
 	int retval = -EIO;
 
 	if (!(adapter->adapter_features & FSF_FEATURE_HBAAPI_MANAGEMENT))
 		return -EOPNOTSUPP;
 
-	spin_lock_bh(&adapter->req_q.lock);
-	if (!atomic_read(&adapter->req_q.count))
+	spin_lock_bh(&adapter->req_q_lock);
+	if (!zfcp_fsf_sbal_available(adapter))
 		goto out;
 
 	req = zfcp_fsf_req_create(adapter, FSF_QTCB_EXCHANGE_PORT_DATA, 0,
@@ -1427,7 +1366,7 @@
 	zfcp_fsf_start_timer(req, ZFCP_FSF_REQUEST_TIMEOUT);
 	retval = zfcp_fsf_req_send(req);
 out:
-	spin_unlock_bh(&adapter->req_q.lock);
+	spin_unlock_bh(&adapter->req_q_lock);
 	if (!retval)
 		wait_event(req->completion_wq,
 			   req->status & ZFCP_STATUS_FSFREQ_COMPLETED);
@@ -1443,7 +1382,7 @@
 	struct fsf_plogi *plogi;
 
 	if (req->status & ZFCP_STATUS_FSFREQ_ERROR)
-		goto skip_fsfstatus;
+		return;
 
 	switch (header->fsf_status) {
 	case FSF_PORT_ALREADY_OPEN:
@@ -1453,9 +1392,9 @@
 		break;
 	case FSF_MAXIMUM_NUMBER_OF_PORTS_EXCEEDED:
 		dev_warn(&req->adapter->ccw_device->dev,
-			 "The adapter is out of resources. The remote port "
-			 "0x%016Lx could not be opened, disabling it.\n",
-			 port->wwpn);
+			 "Not enough FCP adapter resources to open "
+			 "remote port 0x%016Lx\n",
+			 (unsigned long long)port->wwpn);
 		zfcp_erp_port_failed(port, 31, req);
 		req->status |= ZFCP_STATUS_FSFREQ_ERROR;
 		break;
@@ -1467,8 +1406,8 @@
 			break;
 		case FSF_SQ_NO_RETRY_POSSIBLE:
 			dev_warn(&req->adapter->ccw_device->dev,
-				 "The remote port 0x%016Lx could not be "
-				 "opened. Disabling it.\n", port->wwpn);
+				 "Remote port 0x%016Lx could not be opened\n",
+				 (unsigned long long)port->wwpn);
 			zfcp_erp_port_failed(port, 32, req);
 			req->status |= ZFCP_STATUS_FSFREQ_ERROR;
 			break;
@@ -1496,9 +1435,6 @@
 		 * another GID_PN straight after a port has been opened.
 		 * Alternately, an ADISC/PDISC ELS should suffice, as well.
 		 */
-		if (atomic_read(&port->status) & ZFCP_STATUS_PORT_NO_WWPN)
-			break;
-
 		plogi = (struct fsf_plogi *) req->qtcb->bottom.support.els;
 		if (req->qtcb->bottom.support.els1_length >= sizeof(*plogi)) {
 			if (plogi->serv_param.wwpn != port->wwpn)
@@ -1514,9 +1450,6 @@
 		req->status |= ZFCP_STATUS_FSFREQ_ERROR;
 		break;
 	}
-
-skip_fsfstatus:
-	atomic_clear_mask(ZFCP_STATUS_COMMON_OPENING, &port->status);
 }
 
 /**
@@ -1526,12 +1459,12 @@
  */
 int zfcp_fsf_open_port(struct zfcp_erp_action *erp_action)
 {
-	volatile struct qdio_buffer_element *sbale;
+	struct qdio_buffer_element *sbale;
 	struct zfcp_adapter *adapter = erp_action->adapter;
 	struct zfcp_fsf_req *req;
 	int retval = -EIO;
 
-	spin_lock_bh(&adapter->req_q.lock);
+	spin_lock_bh(&adapter->req_q_lock);
 	if (zfcp_fsf_req_sbal_get(adapter))
 		goto out;
 
@@ -1553,7 +1486,6 @@
 	req->data = erp_action->port;
 	req->erp_action = erp_action;
 	erp_action->fsf_req = req;
-	atomic_set_mask(ZFCP_STATUS_COMMON_OPENING, &erp_action->port->status);
 
 	zfcp_fsf_start_erp_timer(req);
 	retval = zfcp_fsf_req_send(req);
@@ -1562,7 +1494,7 @@
 		erp_action->fsf_req = NULL;
 	}
 out:
-	spin_unlock_bh(&adapter->req_q.lock);
+	spin_unlock_bh(&adapter->req_q_lock);
 	return retval;
 }
 
@@ -1571,7 +1503,7 @@
 	struct zfcp_port *port = req->data;
 
 	if (req->status & ZFCP_STATUS_FSFREQ_ERROR)
-		goto skip_fsfstatus;
+		return;
 
 	switch (req->qtcb->header.fsf_status) {
 	case FSF_PORT_HANDLE_NOT_VALID:
@@ -1586,9 +1518,6 @@
 					    ZFCP_CLEAR);
 		break;
 	}
-
-skip_fsfstatus:
-	atomic_clear_mask(ZFCP_STATUS_COMMON_CLOSING, &port->status);
 }
 
 /**
@@ -1598,12 +1527,12 @@
  */
 int zfcp_fsf_close_port(struct zfcp_erp_action *erp_action)
 {
-	volatile struct qdio_buffer_element *sbale;
+	struct qdio_buffer_element *sbale;
 	struct zfcp_adapter *adapter = erp_action->adapter;
 	struct zfcp_fsf_req *req;
 	int retval = -EIO;
 
-	spin_lock_bh(&adapter->req_q.lock);
+	spin_lock_bh(&adapter->req_q_lock);
 	if (zfcp_fsf_req_sbal_get(adapter))
 		goto out;
 
@@ -1624,7 +1553,6 @@
 	req->erp_action = erp_action;
 	req->qtcb->header.port_handle = erp_action->port->handle;
 	erp_action->fsf_req = req;
-	atomic_set_mask(ZFCP_STATUS_COMMON_CLOSING, &erp_action->port->status);
 
 	zfcp_fsf_start_erp_timer(req);
 	retval = zfcp_fsf_req_send(req);
@@ -1633,7 +1561,131 @@
 		erp_action->fsf_req = NULL;
 	}
 out:
-	spin_unlock_bh(&adapter->req_q.lock);
+	spin_unlock_bh(&adapter->req_q_lock);
+	return retval;
+}
+
+static void zfcp_fsf_open_wka_port_handler(struct zfcp_fsf_req *req)
+{
+	struct zfcp_wka_port *wka_port = req->data;
+	struct fsf_qtcb_header *header = &req->qtcb->header;
+
+	if (req->status & ZFCP_STATUS_FSFREQ_ERROR) {
+		wka_port->status = ZFCP_WKA_PORT_OFFLINE;
+		goto out;
+	}
+
+	switch (header->fsf_status) {
+	case FSF_MAXIMUM_NUMBER_OF_PORTS_EXCEEDED:
+		dev_warn(&req->adapter->ccw_device->dev,
+			 "Opening WKA port 0x%x failed\n", wka_port->d_id);
+	case FSF_ADAPTER_STATUS_AVAILABLE:
+		req->status |= ZFCP_STATUS_FSFREQ_ERROR;
+	case FSF_ACCESS_DENIED:
+		wka_port->status = ZFCP_WKA_PORT_OFFLINE;
+		break;
+	case FSF_PORT_ALREADY_OPEN:
+	case FSF_GOOD:
+		wka_port->handle = header->port_handle;
+		wka_port->status = ZFCP_WKA_PORT_ONLINE;
+	}
+out:
+	wake_up(&wka_port->completion_wq);
+}
+
+/**
+ * zfcp_fsf_open_wka_port - create and send open wka-port request
+ * @wka_port: pointer to struct zfcp_wka_port
+ * Returns: 0 on success, error otherwise
+ */
+int zfcp_fsf_open_wka_port(struct zfcp_wka_port *wka_port)
+{
+	struct qdio_buffer_element *sbale;
+	struct zfcp_adapter *adapter = wka_port->adapter;
+	struct zfcp_fsf_req *req;
+	int retval = -EIO;
+
+	spin_lock_bh(&adapter->req_q_lock);
+	if (zfcp_fsf_req_sbal_get(adapter))
+		goto out;
+
+	req = zfcp_fsf_req_create(adapter,
+				  FSF_QTCB_OPEN_PORT_WITH_DID,
+				  ZFCP_REQ_AUTO_CLEANUP,
+				  adapter->pool.fsf_req_erp);
+	if (unlikely(IS_ERR(req))) {
+		retval = PTR_ERR(req);
+		goto out;
+	}
+
+	sbale = zfcp_qdio_sbale_req(req);
+	sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
+	sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
+
+	req->handler = zfcp_fsf_open_wka_port_handler;
+	req->qtcb->bottom.support.d_id = wka_port->d_id;
+	req->data = wka_port;
+
+	zfcp_fsf_start_timer(req, ZFCP_FSF_REQUEST_TIMEOUT);
+	retval = zfcp_fsf_req_send(req);
+	if (retval)
+		zfcp_fsf_req_free(req);
+out:
+	spin_unlock_bh(&adapter->req_q_lock);
+	return retval;
+}
+
+static void zfcp_fsf_close_wka_port_handler(struct zfcp_fsf_req *req)
+{
+	struct zfcp_wka_port *wka_port = req->data;
+
+	if (req->qtcb->header.fsf_status == FSF_PORT_HANDLE_NOT_VALID) {
+		req->status |= ZFCP_STATUS_FSFREQ_ERROR;
+		zfcp_erp_adapter_reopen(wka_port->adapter, 0, 84, req);
+	}
+
+	wka_port->status = ZFCP_WKA_PORT_OFFLINE;
+	wake_up(&wka_port->completion_wq);
+}
+
+/**
+ * zfcp_fsf_close_wka_port - create and send close wka port request
+ * @erp_action: pointer to struct zfcp_erp_action
+ * Returns: 0 on success, error otherwise
+ */
+int zfcp_fsf_close_wka_port(struct zfcp_wka_port *wka_port)
+{
+	struct qdio_buffer_element *sbale;
+	struct zfcp_adapter *adapter = wka_port->adapter;
+	struct zfcp_fsf_req *req;
+	int retval = -EIO;
+
+	spin_lock_bh(&adapter->req_q_lock);
+	if (zfcp_fsf_req_sbal_get(adapter))
+		goto out;
+
+	req = zfcp_fsf_req_create(adapter, FSF_QTCB_CLOSE_PORT,
+				  ZFCP_REQ_AUTO_CLEANUP,
+				  adapter->pool.fsf_req_erp);
+	if (unlikely(IS_ERR(req))) {
+		retval = PTR_ERR(req);
+		goto out;
+	}
+
+	sbale = zfcp_qdio_sbale_req(req);
+	sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
+	sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
+
+	req->handler = zfcp_fsf_close_wka_port_handler;
+	req->data = wka_port;
+	req->qtcb->header.port_handle = wka_port->handle;
+
+	zfcp_fsf_start_timer(req, ZFCP_FSF_REQUEST_TIMEOUT);
+	retval = zfcp_fsf_req_send(req);
+	if (retval)
+		zfcp_fsf_req_free(req);
+out:
+	spin_unlock_bh(&adapter->req_q_lock);
 	return retval;
 }
 
@@ -1695,12 +1747,12 @@
  */
 int zfcp_fsf_close_physical_port(struct zfcp_erp_action *erp_action)
 {
-	volatile struct qdio_buffer_element *sbale;
+	struct qdio_buffer_element *sbale;
 	struct zfcp_adapter *adapter = erp_action->adapter;
 	struct zfcp_fsf_req *req;
 	int retval = -EIO;
 
-	spin_lock_bh(&adapter->req_q.lock);
+	spin_lock_bh(&adapter->req_q_lock);
 	if (zfcp_fsf_req_sbal_get(adapter))
 		goto out;
 
@@ -1731,7 +1783,7 @@
 		erp_action->fsf_req = NULL;
 	}
 out:
-	spin_unlock_bh(&adapter->req_q.lock);
+	spin_unlock_bh(&adapter->req_q_lock);
 	return retval;
 }
 
@@ -1746,7 +1798,7 @@
 	int exclusive, readwrite;
 
 	if (req->status & ZFCP_STATUS_FSFREQ_ERROR)
-		goto skip_fsfstatus;
+		return;
 
 	atomic_clear_mask(ZFCP_STATUS_COMMON_ACCESS_DENIED |
 			  ZFCP_STATUS_COMMON_ACCESS_BOXED |
@@ -1774,14 +1826,12 @@
 	case FSF_LUN_SHARING_VIOLATION:
 		if (header->fsf_status_qual.word[0])
 			dev_warn(&adapter->ccw_device->dev,
-				 "FCP-LUN 0x%Lx at the remote port "
-				 "with WWPN 0x%Lx "
-				 "connected to the adapter "
-				 "is already in use in LPAR%d, CSS%d.\n",
-				 unit->fcp_lun,
-				 unit->port->wwpn,
-				 queue_designator->hla,
-				 queue_designator->cssid);
+				 "LUN 0x%Lx on port 0x%Lx is already in "
+				 "use by CSS%d, MIF Image ID %x\n",
+				 (unsigned long long)unit->fcp_lun,
+				 (unsigned long long)unit->port->wwpn,
+				 queue_designator->cssid,
+				 queue_designator->hla);
 		else
 			zfcp_act_eval_err(adapter,
 					  header->fsf_status_qual.word[2]);
@@ -1792,9 +1842,10 @@
 		break;
 	case FSF_MAXIMUM_NUMBER_OF_LUNS_EXCEEDED:
 		dev_warn(&adapter->ccw_device->dev,
-			 "The adapter ran out of resources. There is no "
-			 "handle available for unit 0x%016Lx on port 0x%016Lx.",
-			 unit->fcp_lun, unit->port->wwpn);
+			 "No handle is available for LUN "
+			 "0x%016Lx on port 0x%016Lx\n",
+			 (unsigned long long)unit->fcp_lun,
+			 (unsigned long long)unit->port->wwpn);
 		zfcp_erp_unit_failed(unit, 34, req);
 		/* fall through */
 	case FSF_INVALID_COMMAND_OPTION:
@@ -1831,26 +1882,29 @@
                 		atomic_set_mask(ZFCP_STATUS_UNIT_READONLY,
 						&unit->status);
 				dev_info(&adapter->ccw_device->dev,
-					 "Read-only access for unit 0x%016Lx "
-					 "on port 0x%016Lx.\n",
-					 unit->fcp_lun, unit->port->wwpn);
+					 "SCSI device at LUN 0x%016Lx on port "
+					 "0x%016Lx opened read-only\n",
+					 (unsigned long long)unit->fcp_lun,
+					 (unsigned long long)unit->port->wwpn);
         		}
 
         		if (exclusive && !readwrite) {
 				dev_err(&adapter->ccw_device->dev,
-					"Exclusive access of read-only unit "
-					"0x%016Lx on port 0x%016Lx not "
-					"supported, disabling unit.\n",
-					unit->fcp_lun, unit->port->wwpn);
+					"Exclusive read-only access not "
+					"supported (unit 0x%016Lx, "
+					"port 0x%016Lx)\n",
+					(unsigned long long)unit->fcp_lun,
+					(unsigned long long)unit->port->wwpn);
 				zfcp_erp_unit_failed(unit, 35, req);
 				req->status |= ZFCP_STATUS_FSFREQ_ERROR;
 				zfcp_erp_unit_shutdown(unit, 0, 80, req);
         		} else if (!exclusive && readwrite) {
 				dev_err(&adapter->ccw_device->dev,
-					"Shared access of read-write unit "
-					"0x%016Lx on port 0x%016Lx not "
-					"supported, disabling unit.\n",
-					unit->fcp_lun, unit->port->wwpn);
+					"Shared read-write access not "
+					"supported (unit 0x%016Lx, port "
+					"0x%016Lx\n)",
+					(unsigned long long)unit->fcp_lun,
+					(unsigned long long)unit->port->wwpn);
 				zfcp_erp_unit_failed(unit, 36, req);
 				req->status |= ZFCP_STATUS_FSFREQ_ERROR;
 				zfcp_erp_unit_shutdown(unit, 0, 81, req);
@@ -1858,9 +1912,6 @@
 		}
 		break;
 	}
-
-skip_fsfstatus:
-	atomic_clear_mask(ZFCP_STATUS_COMMON_OPENING, &unit->status);
 }
 
 /**
@@ -1870,12 +1921,12 @@
  */
 int zfcp_fsf_open_unit(struct zfcp_erp_action *erp_action)
 {
-	volatile struct qdio_buffer_element *sbale;
+	struct qdio_buffer_element *sbale;
 	struct zfcp_adapter *adapter = erp_action->adapter;
 	struct zfcp_fsf_req *req;
 	int retval = -EIO;
 
-	spin_lock_bh(&adapter->req_q.lock);
+	spin_lock_bh(&adapter->req_q_lock);
 	if (zfcp_fsf_req_sbal_get(adapter))
 		goto out;
 
@@ -1901,8 +1952,6 @@
 	if (!(adapter->connection_features & FSF_FEATURE_NPIV_MODE))
 		req->qtcb->bottom.support.option = FSF_OPEN_LUN_SUPPRESS_BOXING;
 
-	atomic_set_mask(ZFCP_STATUS_COMMON_OPENING, &erp_action->unit->status);
-
 	zfcp_fsf_start_erp_timer(req);
 	retval = zfcp_fsf_req_send(req);
 	if (retval) {
@@ -1910,7 +1959,7 @@
 		erp_action->fsf_req = NULL;
 	}
 out:
-	spin_unlock_bh(&adapter->req_q.lock);
+	spin_unlock_bh(&adapter->req_q_lock);
 	return retval;
 }
 
@@ -1919,7 +1968,7 @@
 	struct zfcp_unit *unit = req->data;
 
 	if (req->status & ZFCP_STATUS_FSFREQ_ERROR)
-		goto skip_fsfstatus;
+		return;
 
 	switch (req->qtcb->header.fsf_status) {
 	case FSF_PORT_HANDLE_NOT_VALID:
@@ -1949,8 +1998,6 @@
 		atomic_clear_mask(ZFCP_STATUS_COMMON_OPEN, &unit->status);
 		break;
 	}
-skip_fsfstatus:
-	atomic_clear_mask(ZFCP_STATUS_COMMON_CLOSING, &unit->status);
 }
 
 /**
@@ -1960,12 +2007,12 @@
  */
 int zfcp_fsf_close_unit(struct zfcp_erp_action *erp_action)
 {
-	volatile struct qdio_buffer_element *sbale;
+	struct qdio_buffer_element *sbale;
 	struct zfcp_adapter *adapter = erp_action->adapter;
 	struct zfcp_fsf_req *req;
 	int retval = -EIO;
 
-	spin_lock_bh(&adapter->req_q.lock);
+	spin_lock_bh(&adapter->req_q_lock);
 	if (zfcp_fsf_req_sbal_get(adapter))
 		goto out;
 	req = zfcp_fsf_req_create(adapter, FSF_QTCB_CLOSE_LUN,
@@ -1986,7 +2033,6 @@
 	req->data = erp_action->unit;
 	req->erp_action = erp_action;
 	erp_action->fsf_req = req;
-	atomic_set_mask(ZFCP_STATUS_COMMON_CLOSING, &erp_action->unit->status);
 
 	zfcp_fsf_start_erp_timer(req);
 	retval = zfcp_fsf_req_send(req);
@@ -1995,7 +2041,7 @@
 		erp_action->fsf_req = NULL;
 	}
 out:
-	spin_unlock_bh(&adapter->req_q.lock);
+	spin_unlock_bh(&adapter->req_q_lock);
 	return retval;
 }
 
@@ -2156,21 +2202,21 @@
 		break;
 	case FSF_DIRECTION_INDICATOR_NOT_VALID:
 		dev_err(&req->adapter->ccw_device->dev,
-			"Invalid data direction (%d) given for unit "
-			"0x%016Lx on port 0x%016Lx, shutting down "
-			"adapter.\n",
+			"Incorrect direction %d, unit 0x%016Lx on port "
+			"0x%016Lx closed\n",
 			req->qtcb->bottom.io.data_direction,
-			unit->fcp_lun, unit->port->wwpn);
+			(unsigned long long)unit->fcp_lun,
+			(unsigned long long)unit->port->wwpn);
 		zfcp_erp_adapter_shutdown(unit->port->adapter, 0, 133, req);
 		req->status |= ZFCP_STATUS_FSFREQ_ERROR;
 		break;
 	case FSF_CMND_LENGTH_NOT_VALID:
 		dev_err(&req->adapter->ccw_device->dev,
-			"An invalid control-data-block length field (%d) "
-			"was found in a command for unit 0x%016Lx on port "
-			"0x%016Lx. Shutting down adapter.\n",
+			"Incorrect CDB length %d, unit 0x%016Lx on "
+			"port 0x%016Lx closed\n",
 			req->qtcb->bottom.io.fcp_cmnd_length,
-			unit->fcp_lun, unit->port->wwpn);
+			(unsigned long long)unit->fcp_lun,
+			(unsigned long long)unit->port->wwpn);
 		zfcp_erp_adapter_shutdown(unit->port->adapter, 0, 134, req);
 		req->status |= ZFCP_STATUS_FSFREQ_ERROR;
 		break;
@@ -2201,6 +2247,20 @@
 	}
 }
 
+static void zfcp_set_fcp_dl(struct fcp_cmnd_iu *fcp_cmd, u32 fcp_dl)
+{
+	u32 *fcp_dl_ptr;
+
+	/*
+	 * fcp_dl_addr = start address of fcp_cmnd structure +
+	 * size of fixed part + size of dynamically sized add_dcp_cdb field
+	 * SEE FCP-2 documentation
+	 */
+	fcp_dl_ptr = (u32 *) ((unsigned char *) &fcp_cmd[1] +
+			(fcp_cmd->add_fcp_cdb_length << 2));
+	*fcp_dl_ptr = fcp_dl;
+}
+
 /**
  * zfcp_fsf_send_fcp_command_task - initiate an FCP command (for a SCSI command)
  * @adapter: adapter where scsi command is issued
@@ -2223,8 +2283,8 @@
 		       ZFCP_STATUS_COMMON_UNBLOCKED)))
 		return -EBUSY;
 
-	spin_lock(&adapter->req_q.lock);
-	if (!atomic_read(&adapter->req_q.count))
+	spin_lock(&adapter->req_q_lock);
+	if (!zfcp_fsf_sbal_available(adapter))
 		goto out;
 	req = zfcp_fsf_req_create(adapter, FSF_QTCB_FCP_CMND, req_flags,
 				  adapter->pool.fsf_req_scsi);
@@ -2286,7 +2346,7 @@
 	memcpy(fcp_cmnd_iu->fcp_cdb, scsi_cmnd->cmnd, scsi_cmnd->cmd_len);
 
 	req->qtcb->bottom.io.fcp_cmnd_length = sizeof(struct fcp_cmnd_iu) +
-		fcp_cmnd_iu->add_fcp_cdb_length + sizeof(fcp_dl_t);
+		fcp_cmnd_iu->add_fcp_cdb_length + sizeof(u32);
 
 	real_bytes = zfcp_qdio_sbals_from_sg(req, sbtype,
 					     scsi_sglist(scsi_cmnd),
@@ -2296,10 +2356,10 @@
 			retval = -EIO;
 		else {
 			dev_err(&adapter->ccw_device->dev,
-				"SCSI request too large. "
-				"Shutting down unit 0x%016Lx on port "
-				"0x%016Lx.\n", unit->fcp_lun,
-				unit->port->wwpn);
+				"Oversize data package, unit 0x%016Lx "
+				"on port 0x%016Lx closed\n",
+				(unsigned long long)unit->fcp_lun,
+				(unsigned long long)unit->port->wwpn);
 			zfcp_erp_unit_shutdown(unit, 0, 131, req);
 			retval = -EINVAL;
 		}
@@ -2322,7 +2382,7 @@
 	zfcp_fsf_req_free(req);
 	scsi_cmnd->host_scribble = NULL;
 out:
-	spin_unlock(&adapter->req_q.lock);
+	spin_unlock(&adapter->req_q_lock);
 	return retval;
 }
 
@@ -2338,7 +2398,7 @@
 					   struct zfcp_unit *unit,
 					   u8 tm_flags, int req_flags)
 {
-	volatile struct qdio_buffer_element *sbale;
+	struct qdio_buffer_element *sbale;
 	struct zfcp_fsf_req *req = NULL;
 	struct fcp_cmnd_iu *fcp_cmnd_iu;
 
@@ -2346,8 +2406,8 @@
 		       ZFCP_STATUS_COMMON_UNBLOCKED)))
 		return NULL;
 
-	spin_lock(&adapter->req_q.lock);
-	if (!atomic_read(&adapter->req_q.count))
+	spin_lock(&adapter->req_q_lock);
+	if (!zfcp_fsf_sbal_available(adapter))
 		goto out;
 	req = zfcp_fsf_req_create(adapter, FSF_QTCB_FCP_CMND, req_flags,
 				  adapter->pool.fsf_req_scsi);
@@ -2362,7 +2422,7 @@
 	req->qtcb->bottom.io.data_direction = FSF_DATADIR_CMND;
 	req->qtcb->bottom.io.service_class = FSF_CLASS_3;
 	req->qtcb->bottom.io.fcp_cmnd_length = 	sizeof(struct fcp_cmnd_iu) +
-						sizeof(fcp_dl_t);
+						sizeof(u32);
 
 	sbale = zfcp_qdio_sbale_req(req);
 	sbale[0].flags |= SBAL_FLAGS0_TYPE_WRITE;
@@ -2379,7 +2439,7 @@
 	zfcp_fsf_req_free(req);
 	req = NULL;
 out:
-	spin_unlock(&adapter->req_q.lock);
+	spin_unlock(&adapter->req_q_lock);
 	return req;
 }
 
@@ -2398,7 +2458,7 @@
 struct zfcp_fsf_req *zfcp_fsf_control_file(struct zfcp_adapter *adapter,
 					   struct zfcp_fsf_cfdc *fsf_cfdc)
 {
-	volatile struct qdio_buffer_element *sbale;
+	struct qdio_buffer_element *sbale;
 	struct zfcp_fsf_req *req = NULL;
 	struct fsf_qtcb_bottom_support *bottom;
 	int direction, retval = -EIO, bytes;
@@ -2417,7 +2477,7 @@
 		return ERR_PTR(-EINVAL);
 	}
 
-	spin_lock_bh(&adapter->req_q.lock);
+	spin_lock_bh(&adapter->req_q_lock);
 	if (zfcp_fsf_req_sbal_get(adapter))
 		goto out;
 
@@ -2447,7 +2507,7 @@
 	zfcp_fsf_start_timer(req, ZFCP_FSF_REQUEST_TIMEOUT);
 	retval = zfcp_fsf_req_send(req);
 out:
-	spin_unlock_bh(&adapter->req_q.lock);
+	spin_unlock_bh(&adapter->req_q_lock);
 
 	if (!retval) {
 		wait_event(req->completion_wq,
diff --git a/drivers/s390/scsi/zfcp_fsf.h b/drivers/s390/scsi/zfcp_fsf.h
index bf94b4d..fd3a887 100644
--- a/drivers/s390/scsi/zfcp_fsf.h
+++ b/drivers/s390/scsi/zfcp_fsf.h
@@ -71,13 +71,6 @@
 #define FSF_MAXIMUM_NUMBER_OF_LUNS_EXCEEDED	0x00000041
 #define FSF_ELS_COMMAND_REJECTED		0x00000050
 #define FSF_GENERIC_COMMAND_REJECTED		0x00000051
-#define FSF_OPERATION_PARTIALLY_SUCCESSFUL	0x00000052
-#define FSF_AUTHORIZATION_FAILURE		0x00000053
-#define FSF_CFDC_ERROR_DETECTED			0x00000054
-#define FSF_CONTROL_FILE_UPDATE_ERROR		0x00000055
-#define FSF_CONTROL_FILE_TOO_LARGE		0x00000056
-#define FSF_ACCESS_CONFLICT_DETECTED		0x00000057
-#define FSF_CONFLICTS_OVERRULED			0x00000058
 #define FSF_PORT_BOXED				0x00000059
 #define FSF_LUN_BOXED				0x0000005A
 #define FSF_EXCHANGE_CONFIG_DATA_INCOMPLETE	0x0000005B
@@ -85,9 +78,7 @@
 #define FSF_REQUEST_SIZE_TOO_LARGE		0x00000061
 #define FSF_RESPONSE_SIZE_TOO_LARGE		0x00000062
 #define FSF_SBAL_MISMATCH			0x00000063
-#define FSF_OPEN_PORT_WITHOUT_PRLI		0x00000064
 #define FSF_ADAPTER_STATUS_AVAILABLE		0x000000AD
-#define FSF_FCP_RSP_AVAILABLE			0x000000AF
 #define FSF_UNKNOWN_COMMAND			0x000000E2
 #define FSF_UNKNOWN_OP_SUBTYPE                  0x000000E3
 #define FSF_INVALID_COMMAND_OPTION              0x000000E5
@@ -102,20 +93,9 @@
 #define FSF_SQ_RETRY_IF_POSSIBLE		0x02
 #define FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED	0x03
 #define FSF_SQ_INVOKE_LINK_TEST_PROCEDURE	0x04
-#define FSF_SQ_ULP_PROGRAMMING_ERROR		0x05
 #define FSF_SQ_COMMAND_ABORTED			0x06
 #define FSF_SQ_NO_RETRY_POSSIBLE		0x07
 
-/* FSF status qualifier for CFDC commands */
-#define FSF_SQ_CFDC_HARDENED_ON_SE		0x00000000
-#define FSF_SQ_CFDC_COULD_NOT_HARDEN_ON_SE	0x00000001
-#define FSF_SQ_CFDC_COULD_NOT_HARDEN_ON_SE2	0x00000002
-/* CFDC subtable codes */
-#define FSF_SQ_CFDC_SUBTABLE_OS			0x0001
-#define FSF_SQ_CFDC_SUBTABLE_PORT_WWPN		0x0002
-#define FSF_SQ_CFDC_SUBTABLE_PORT_DID		0x0003
-#define FSF_SQ_CFDC_SUBTABLE_LUN		0x0004
-
 /* FSF status qualifier (most significant 4 bytes), local link down */
 #define FSF_PSQ_LINK_NO_LIGHT			0x00000004
 #define FSF_PSQ_LINK_WRAP_PLUG			0x00000008
@@ -145,7 +125,6 @@
 #define FSF_STATUS_READ_LINK_UP          	0x00000006
 #define FSF_STATUS_READ_NOTIFICATION_LOST	0x00000009
 #define FSF_STATUS_READ_CFDC_UPDATED		0x0000000A
-#define FSF_STATUS_READ_CFDC_HARDENED		0x0000000B
 #define FSF_STATUS_READ_FEATURE_UPDATE_ALERT	0x0000000C
 
 /* status subtypes in status read buffer */
@@ -159,20 +138,9 @@
 
 /* status subtypes for unsolicited status notification lost */
 #define FSF_STATUS_READ_SUB_INCOMING_ELS	0x00000001
-#define FSF_STATUS_READ_SUB_SENSE_DATA		0x00000002
-#define FSF_STATUS_READ_SUB_LINK_STATUS		0x00000004
-#define FSF_STATUS_READ_SUB_PORT_CLOSED		0x00000008
-#define FSF_STATUS_READ_SUB_BIT_ERROR_THRESHOLD	0x00000010
 #define FSF_STATUS_READ_SUB_ACT_UPDATED		0x00000020
-#define FSF_STATUS_READ_SUB_ACT_HARDENED	0x00000040
-#define FSF_STATUS_READ_SUB_FEATURE_UPDATE_ALERT 0x00000080
-
-/* status subtypes for CFDC */
-#define FSF_STATUS_READ_SUB_CFDC_HARDENED_ON_SE	0x00000002
-#define FSF_STATUS_READ_SUB_CFDC_HARDENED_ON_SE2 0x0000000F
 
 /* topologie that is detected by the adapter */
-#define FSF_TOPO_ERROR				0x00000000
 #define FSF_TOPO_P2P				0x00000001
 #define FSF_TOPO_FABRIC				0x00000002
 #define FSF_TOPO_AL				0x00000003
@@ -180,17 +148,13 @@
 /* data direction for FCP commands */
 #define FSF_DATADIR_WRITE			0x00000001
 #define FSF_DATADIR_READ			0x00000002
-#define FSF_DATADIR_READ_WRITE			0x00000003
 #define FSF_DATADIR_CMND			0x00000004
 
 /* fc service class */
-#define FSF_CLASS_1				0x00000001
-#define FSF_CLASS_2				0x00000002
 #define FSF_CLASS_3				0x00000003
 
 /* SBAL chaining */
 #define FSF_MAX_SBALS_PER_REQ			36
-#define FSF_MAX_SBALS_PER_ELS_REQ		2
 
 /* logging space behind QTCB */
 #define FSF_QTCB_LOG_SIZE			1024
@@ -200,50 +164,16 @@
 #define FSF_FEATURE_LUN_SHARING			0x00000004
 #define FSF_FEATURE_NOTIFICATION_LOST		0x00000008
 #define FSF_FEATURE_HBAAPI_MANAGEMENT           0x00000010
-#define FSF_FEATURE_ELS_CT_CHAINED_SBALS        0x00000020
 #define FSF_FEATURE_UPDATE_ALERT		0x00000100
 #define FSF_FEATURE_MEASUREMENT_DATA		0x00000200
 
 /* host connection features */
 #define FSF_FEATURE_NPIV_MODE			0x00000001
-#define FSF_FEATURE_VM_ASSIGNED_WWPN		0x00000002
 
 /* option */
 #define FSF_OPEN_LUN_SUPPRESS_BOXING		0x00000001
-#define FSF_OPEN_LUN_REPLICATE_SENSE		0x00000002
-
-/* adapter types */
-#define FSF_ADAPTER_TYPE_FICON                  0x00000001
-#define FSF_ADAPTER_TYPE_FICON_EXPRESS          0x00000002
-
-/* port types */
-#define FSF_HBA_PORTTYPE_UNKNOWN		0x00000001
-#define FSF_HBA_PORTTYPE_NOTPRESENT		0x00000003
-#define FSF_HBA_PORTTYPE_NPORT			0x00000005
-#define FSF_HBA_PORTTYPE_PTP			0x00000021
-/* following are not defined and used by FSF Spec
-   but are additionally defined by FC-HBA */
-#define FSF_HBA_PORTTYPE_OTHER			0x00000002
-#define FSF_HBA_PORTTYPE_NOTPRESENT		0x00000003
-#define FSF_HBA_PORTTYPE_NLPORT			0x00000006
-#define FSF_HBA_PORTTYPE_FLPORT			0x00000007
-#define FSF_HBA_PORTTYPE_FPORT			0x00000008
-#define FSF_HBA_PORTTYPE_LPORT			0x00000020
-
-/* port states */
-#define FSF_HBA_PORTSTATE_UNKNOWN		0x00000001
-#define FSF_HBA_PORTSTATE_ONLINE		0x00000002
-#define FSF_HBA_PORTSTATE_OFFLINE		0x00000003
-#define FSF_HBA_PORTSTATE_LINKDOWN		0x00000006
-#define FSF_HBA_PORTSTATE_ERROR			0x00000007
-
-/* IO states of adapter */
-#define FSF_IOSTAT_NPORT_RJT			0x00000004
-#define FSF_IOSTAT_FABRIC_RJT			0x00000005
-#define FSF_IOSTAT_LS_RJT			0x00000009
 
 /* open LUN access flags*/
-#define FSF_UNIT_ACCESS_OPEN_LUN_ALLOWED	0x01000000
 #define FSF_UNIT_ACCESS_EXCLUSIVE		0x02000000
 #define FSF_UNIT_ACCESS_OUTBOUND_TRANSFER	0x10000000
 
@@ -265,11 +195,6 @@
 	u32 res1;
 } __attribute__ ((packed));
 
-struct fsf_port_closed_payload {
-	struct fsf_queue_designator queue_designator;
-	u32                         port_handle;
-} __attribute__ ((packed));
-
 struct fsf_bit_error_payload {
 	u32 res1;
 	u32 link_failure_error_count;
diff --git a/drivers/s390/scsi/zfcp_qdio.c b/drivers/s390/scsi/zfcp_qdio.c
index 69d632d..3e05080 100644
--- a/drivers/s390/scsi/zfcp_qdio.c
+++ b/drivers/s390/scsi/zfcp_qdio.c
@@ -28,7 +28,7 @@
 	return 0;
 }
 
-static volatile struct qdio_buffer_element *
+static struct qdio_buffer_element *
 zfcp_qdio_sbale(struct zfcp_qdio_queue *q, int sbal_idx, int sbale_idx)
 {
 	return &q->sbal[sbal_idx]->element[sbale_idx];
@@ -57,7 +57,7 @@
 
 static void zfcp_qdio_handler_error(struct zfcp_adapter *adapter, u8 id)
 {
-	dev_warn(&adapter->ccw_device->dev, "QDIO problem occurred.\n");
+	dev_warn(&adapter->ccw_device->dev, "A QDIO problem occurred\n");
 
 	zfcp_erp_adapter_reopen(adapter,
 				ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED |
@@ -145,7 +145,7 @@
 {
 	struct zfcp_adapter *adapter = (struct zfcp_adapter *) parm;
 	struct zfcp_qdio_queue *queue = &adapter->resp_q;
-	volatile struct qdio_buffer_element *sbale;
+	struct qdio_buffer_element *sbale;
 	int sbal_idx, sbale_idx, sbal_no;
 
 	if (unlikely(qdio_err)) {
@@ -174,8 +174,8 @@
 
 		if (unlikely(!(sbale->flags & SBAL_FLAGS_LAST_ENTRY)))
 			dev_warn(&adapter->ccw_device->dev,
-				 "Protocol violation by adapter. "
-				 "Continuing operations.\n");
+				 "A QDIO protocol error occurred, "
+				 "operations continue\n");
 	}
 
 	/*
@@ -190,8 +190,7 @@
  * @fsf_req: pointer to struct fsf_req
  * Returns: pointer to qdio_buffer_element (SBALE) structure
  */
-volatile struct qdio_buffer_element *
-zfcp_qdio_sbale_req(struct zfcp_fsf_req *req)
+struct qdio_buffer_element *zfcp_qdio_sbale_req(struct zfcp_fsf_req *req)
 {
 	return zfcp_qdio_sbale(&req->adapter->req_q, req->sbal_last, 0);
 }
@@ -201,8 +200,7 @@
  * @fsf_req: pointer to struct fsf_req
  * Returns: pointer to qdio_buffer_element (SBALE) structure
  */
-volatile struct qdio_buffer_element *
-zfcp_qdio_sbale_curr(struct zfcp_fsf_req *req)
+struct qdio_buffer_element *zfcp_qdio_sbale_curr(struct zfcp_fsf_req *req)
 {
 	return zfcp_qdio_sbale(&req->adapter->req_q, req->sbal_last,
 			       req->sbale_curr);
@@ -216,10 +214,10 @@
 					% QDIO_MAX_BUFFERS_PER_Q;
 }
 
-static volatile struct qdio_buffer_element *
+static struct qdio_buffer_element *
 zfcp_qdio_sbal_chain(struct zfcp_fsf_req *fsf_req, unsigned long sbtype)
 {
-	volatile struct qdio_buffer_element *sbale;
+	struct qdio_buffer_element *sbale;
 
 	/* set last entry flag in current SBALE of current SBAL */
 	sbale = zfcp_qdio_sbale_curr(fsf_req);
@@ -250,7 +248,7 @@
 	return sbale;
 }
 
-static volatile struct qdio_buffer_element *
+static struct qdio_buffer_element *
 zfcp_qdio_sbale_next(struct zfcp_fsf_req *fsf_req, unsigned long sbtype)
 {
 	if (fsf_req->sbale_curr == ZFCP_LAST_SBALE_PER_SBAL)
@@ -273,7 +271,7 @@
 				unsigned int sbtype, void *start_addr,
 				unsigned int total_length)
 {
-	volatile struct qdio_buffer_element *sbale;
+	struct qdio_buffer_element *sbale;
 	unsigned long remaining, length;
 	void *addr;
 
@@ -282,6 +280,7 @@
 	     addr += length, remaining -= length) {
 		sbale = zfcp_qdio_sbale_next(fsf_req, sbtype);
 		if (!sbale) {
+			atomic_inc(&fsf_req->adapter->qdio_outb_full);
 			zfcp_qdio_undo_sbals(fsf_req);
 			return -EINVAL;
 		}
@@ -307,7 +306,7 @@
 int zfcp_qdio_sbals_from_sg(struct zfcp_fsf_req *fsf_req, unsigned long sbtype,
 			    struct scatterlist *sg, int max_sbals)
 {
-	volatile struct qdio_buffer_element *sbale;
+	struct qdio_buffer_element *sbale;
 	int retval, bytes = 0;
 
 	/* figure out last allowed SBAL */
@@ -344,10 +343,10 @@
 	int first = fsf_req->sbal_first;
 	int count = fsf_req->sbal_number;
 	int retval, pci, pci_batch;
-	volatile struct qdio_buffer_element *sbale;
+	struct qdio_buffer_element *sbale;
 
 	/* acknowledgements for transferred buffers */
-	pci_batch = req_q->pci_batch + count;
+	pci_batch = adapter->req_q_pci_batch + count;
 	if (unlikely(pci_batch >= ZFCP_QDIO_PCI_INTERVAL)) {
 		pci_batch %= ZFCP_QDIO_PCI_INTERVAL;
 		pci = first + count - (pci_batch + 1);
@@ -367,7 +366,7 @@
 	atomic_sub(count, &req_q->count);
 	req_q->first += count;
 	req_q->first %= QDIO_MAX_BUFFERS_PER_Q;
-	req_q->pci_batch = pci_batch;
+	adapter->req_q_pci_batch = pci_batch;
 	return 0;
 }
 
@@ -418,14 +417,14 @@
 	struct zfcp_qdio_queue *req_q;
 	int first, count;
 
-	if (!atomic_test_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &adapter->status))
+	if (!(atomic_read(&adapter->status) & ZFCP_STATUS_ADAPTER_QDIOUP))
 		return;
 
 	/* clear QDIOUP flag, thus do_QDIO is not called during qdio_shutdown */
 	req_q = &adapter->req_q;
-	spin_lock_bh(&req_q->lock);
+	spin_lock_bh(&adapter->req_q_lock);
 	atomic_clear_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &adapter->status);
-	spin_unlock_bh(&req_q->lock);
+	spin_unlock_bh(&adapter->req_q_lock);
 
 	qdio_shutdown(adapter->ccw_device, QDIO_FLAG_CLEANUP_USING_CLEAR);
 
@@ -438,7 +437,7 @@
 	}
 	req_q->first = 0;
 	atomic_set(&req_q->count, 0);
-	req_q->pci_batch = 0;
+	adapter->req_q_pci_batch = 0;
 	adapter->resp_q.first = 0;
 	atomic_set(&adapter->resp_q.count, 0);
 }
@@ -450,23 +449,17 @@
  */
 int zfcp_qdio_open(struct zfcp_adapter *adapter)
 {
-	volatile struct qdio_buffer_element *sbale;
+	struct qdio_buffer_element *sbale;
 	int cc;
 
-	if (atomic_test_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &adapter->status))
+	if (atomic_read(&adapter->status) & ZFCP_STATUS_ADAPTER_QDIOUP)
 		return -EIO;
 
-	if (qdio_establish(&adapter->qdio_init_data)) {
-		dev_err(&adapter->ccw_device->dev,
-			 "Establish of QDIO queues failed.\n");
-		return -EIO;
-	}
+	if (qdio_establish(&adapter->qdio_init_data))
+		goto failed_establish;
 
-	if (qdio_activate(adapter->ccw_device)) {
-		dev_err(&adapter->ccw_device->dev,
-			 "Activate of QDIO queues failed.\n");
+	if (qdio_activate(adapter->ccw_device))
 		goto failed_qdio;
-	}
 
 	for (cc = 0; cc < QDIO_MAX_BUFFERS_PER_Q; cc++) {
 		sbale = &(adapter->resp_q.sbal[cc]->element[0]);
@@ -476,20 +469,20 @@
 	}
 
 	if (do_QDIO(adapter->ccw_device, QDIO_FLAG_SYNC_INPUT, 0, 0,
-		     QDIO_MAX_BUFFERS_PER_Q)) {
-		dev_err(&adapter->ccw_device->dev,
-			 "Init of QDIO response queue failed.\n");
+		     QDIO_MAX_BUFFERS_PER_Q))
 		goto failed_qdio;
-	}
 
 	/* set index of first avalable SBALS / number of available SBALS */
 	adapter->req_q.first = 0;
 	atomic_set(&adapter->req_q.count, QDIO_MAX_BUFFERS_PER_Q);
-	adapter->req_q.pci_batch = 0;
+	adapter->req_q_pci_batch = 0;
 
 	return 0;
 
 failed_qdio:
 	qdio_shutdown(adapter->ccw_device, QDIO_FLAG_CLEANUP_USING_CLEAR);
+failed_establish:
+	dev_err(&adapter->ccw_device->dev,
+		"Setting up the QDIO connection to the FCP adapter failed\n");
 	return -EIO;
 }
diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c
index aeae56b..ca8f85f 100644
--- a/drivers/s390/scsi/zfcp_scsi.c
+++ b/drivers/s390/scsi/zfcp_scsi.c
@@ -21,20 +21,6 @@
 	return fcp_sns_info_ptr;
 }
 
-void zfcp_set_fcp_dl(struct fcp_cmnd_iu *fcp_cmd, fcp_dl_t fcp_dl)
-{
-	fcp_dl_t *fcp_dl_ptr;
-
-	/*
-	 * fcp_dl_addr = start address of fcp_cmnd structure +
-	 * size of fixed part + size of dynamically sized add_dcp_cdb field
-	 * SEE FCP-2 documentation
-	 */
-	fcp_dl_ptr = (fcp_dl_t *) ((unsigned char *) &fcp_cmd[1] +
-				   (fcp_cmd->add_fcp_cdb_length << 2));
-	*fcp_dl_ptr = fcp_dl;
-}
-
 static void zfcp_scsi_slave_destroy(struct scsi_device *sdpnt)
 {
 	struct zfcp_unit *unit = (struct zfcp_unit *) sdpnt->hostdata;
@@ -119,13 +105,17 @@
 {
 	struct zfcp_port *port;
 	struct zfcp_unit *unit;
+	int scsi_lun;
 
 	list_for_each_entry(port, &adapter->port_list_head, list) {
 		if (!port->rport || (id != port->rport->scsi_target_id))
 			continue;
-		list_for_each_entry(unit, &port->unit_list_head, list)
-			if (lun == unit->scsi_lun)
+		list_for_each_entry(unit, &port->unit_list_head, list) {
+			scsi_lun = scsilun_to_int(
+				(struct scsi_lun *)&unit->fcp_lun);
+			if (lun == scsi_lun)
 				return unit;
+		}
 	}
 
 	return NULL;
@@ -183,7 +173,6 @@
 		return retval;
 	}
 	fsf_req->data = NULL;
-	fsf_req->status |= ZFCP_STATUS_FSFREQ_ABORTING;
 
 	/* don't access old fsf_req after releasing the abort_lock */
 	write_unlock_irqrestore(&adapter->abort_lock, flags);
@@ -294,7 +283,8 @@
 					     sizeof (struct zfcp_adapter *));
 	if (!adapter->scsi_host) {
 		dev_err(&adapter->ccw_device->dev,
-			"registration with SCSI stack failed.");
+			"Registering the FCP device with the "
+			"SCSI stack failed\n");
 		return -EIO;
 	}
 
@@ -312,7 +302,6 @@
 		scsi_host_put(adapter->scsi_host);
 		return -EIO;
 	}
-	atomic_set_mask(ZFCP_STATUS_ADAPTER_REGISTERED, &adapter->status);
 
 	return 0;
 }
@@ -336,7 +325,6 @@
 	scsi_remove_host(shost);
 	scsi_host_put(shost);
 	adapter->scsi_host = NULL;
-	atomic_clear_mask(ZFCP_STATUS_ADAPTER_REGISTERED, &adapter->status);
 
 	return;
 }
diff --git a/drivers/s390/scsi/zfcp_sysfs.c b/drivers/s390/scsi/zfcp_sysfs.c
index 2e85c6c..ca9293b 100644
--- a/drivers/s390/scsi/zfcp_sysfs.c
+++ b/drivers/s390/scsi/zfcp_sysfs.c
@@ -26,9 +26,9 @@
 ZFCP_DEFINE_ATTR(zfcp_adapter, adapter, status, "0x%08x\n",
 		 atomic_read(&adapter->status));
 ZFCP_DEFINE_ATTR(zfcp_adapter, adapter, peer_wwnn, "0x%016llx\n",
-		 adapter->peer_wwnn);
+		 (unsigned long long) adapter->peer_wwnn);
 ZFCP_DEFINE_ATTR(zfcp_adapter, adapter, peer_wwpn, "0x%016llx\n",
-		 adapter->peer_wwpn);
+		 (unsigned long long) adapter->peer_wwpn);
 ZFCP_DEFINE_ATTR(zfcp_adapter, adapter, peer_d_id, "0x%06x\n",
 		 adapter->peer_d_id);
 ZFCP_DEFINE_ATTR(zfcp_adapter, adapter, card_version, "0x%04x\n",
@@ -135,8 +135,9 @@
 {
 	struct zfcp_adapter *adapter = dev_get_drvdata(dev);
 	struct zfcp_port *port;
-	wwn_t wwpn;
+	u64 wwpn;
 	int retval = 0;
+	LIST_HEAD(port_remove_lh);
 
 	down(&zfcp_data.config_sema);
 	if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_REMOVE) {
@@ -144,7 +145,7 @@
 		goto out;
 	}
 
-	if (strict_strtoull(buf, 0, &wwpn)) {
+	if (strict_strtoull(buf, 0, (unsigned long long *) &wwpn)) {
 		retval = -EINVAL;
 		goto out;
 	}
@@ -154,7 +155,7 @@
 	if (port && (atomic_read(&port->refcount) == 0)) {
 		zfcp_port_get(port);
 		atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &port->status);
-		list_move(&port->list, &adapter->port_remove_lh);
+		list_move(&port->list, &port_remove_lh);
 	} else
 		port = NULL;
 	write_unlock_irq(&zfcp_data.config_lock);
@@ -200,7 +201,7 @@
 {
 	struct zfcp_port *port = dev_get_drvdata(dev);
 	struct zfcp_unit *unit;
-	fcp_lun_t fcp_lun;
+	u64 fcp_lun;
 	int retval = -EINVAL;
 
 	down(&zfcp_data.config_sema);
@@ -209,7 +210,7 @@
 		goto out;
 	}
 
-	if (strict_strtoull(buf, 0, &fcp_lun))
+	if (strict_strtoull(buf, 0, (unsigned long long *) &fcp_lun))
 		goto out;
 
 	unit = zfcp_unit_enqueue(port, fcp_lun);
@@ -233,8 +234,9 @@
 {
 	struct zfcp_port *port = dev_get_drvdata(dev);
 	struct zfcp_unit *unit;
-	fcp_lun_t fcp_lun;
+	u64 fcp_lun;
 	int retval = 0;
+	LIST_HEAD(unit_remove_lh);
 
 	down(&zfcp_data.config_sema);
 	if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_REMOVE) {
@@ -242,7 +244,7 @@
 		goto out;
 	}
 
-	if (strict_strtoull(buf, 0, &fcp_lun)) {
+	if (strict_strtoull(buf, 0, (unsigned long long *) &fcp_lun)) {
 		retval = -EINVAL;
 		goto out;
 	}
@@ -252,7 +254,7 @@
 	if (unit && (atomic_read(&unit->refcount) == 0)) {
 		zfcp_unit_get(unit);
 		atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &unit->status);
-		list_move(&unit->list, &port->unit_remove_lh);
+		list_move(&unit->list, &unit_remove_lh);
 	} else
 		unit = NULL;
 
@@ -273,22 +275,7 @@
 }
 static DEVICE_ATTR(unit_remove, S_IWUSR, NULL, zfcp_sysfs_unit_remove_store);
 
-static struct attribute *zfcp_port_ns_attrs[] = {
-	&dev_attr_port_failed.attr,
-	&dev_attr_port_in_recovery.attr,
-	&dev_attr_port_status.attr,
-	&dev_attr_port_access_denied.attr,
-	NULL
-};
-
-/**
- * zfcp_sysfs_ns_port_attrs - sysfs attributes for nameserver
- */
-struct attribute_group zfcp_sysfs_ns_port_attrs = {
-	.attrs = zfcp_port_ns_attrs,
-};
-
-static struct attribute *zfcp_port_no_ns_attrs[] = {
+static struct attribute *zfcp_port_attrs[] = {
 	&dev_attr_unit_add.attr,
 	&dev_attr_unit_remove.attr,
 	&dev_attr_port_failed.attr,
@@ -302,7 +289,7 @@
  * zfcp_sysfs_port_attrs - sysfs attributes for all other ports
  */
 struct attribute_group zfcp_sysfs_port_attrs = {
-	.attrs = zfcp_port_no_ns_attrs,
+	.attrs = zfcp_port_attrs,
 };
 
 static struct attribute *zfcp_unit_attrs[] = {
@@ -394,9 +381,11 @@
 static DEVICE_ATTR(_name, S_IRUGO, zfcp_sysfs_scsi_##_name##_show, NULL);
 
 ZFCP_DEFINE_SCSI_ATTR(hba_id, "%s\n",
-	unit->port->adapter->ccw_device->dev.bus_id);
-ZFCP_DEFINE_SCSI_ATTR(wwpn, "0x%016llx\n", unit->port->wwpn);
-ZFCP_DEFINE_SCSI_ATTR(fcp_lun, "0x%016llx\n", unit->fcp_lun);
+		      dev_name(&unit->port->adapter->ccw_device->dev));
+ZFCP_DEFINE_SCSI_ATTR(wwpn, "0x%016llx\n",
+		      (unsigned long long) unit->port->wwpn);
+ZFCP_DEFINE_SCSI_ATTR(fcp_lun, "0x%016llx\n",
+		      (unsigned long long) unit->fcp_lun);
 
 struct device_attribute *zfcp_sysfs_sdev_attrs[] = {
 	&dev_attr_fcp_lun,
@@ -487,10 +476,23 @@
 ZFCP_SHOST_ATTR(seconds_active, "%llu\n",
 		(unsigned long long) stat_info.seconds_act);
 
+static ssize_t zfcp_sysfs_adapter_q_full_show(struct device *dev,
+					      struct device_attribute *attr,
+					      char *buf)
+{
+	struct Scsi_Host *scsi_host = class_to_shost(dev);
+	struct zfcp_adapter *adapter =
+		(struct zfcp_adapter *) scsi_host->hostdata[0];
+
+	return sprintf(buf, "%d\n", atomic_read(&adapter->qdio_outb_full));
+}
+static DEVICE_ATTR(queue_full, S_IRUGO, zfcp_sysfs_adapter_q_full_show, NULL);
+
 struct device_attribute *zfcp_sysfs_shost_attrs[] = {
 	&dev_attr_utilization,
 	&dev_attr_requests,
 	&dev_attr_megabytes,
 	&dev_attr_seconds_active,
+	&dev_attr_queue_full,
 	NULL
 };
diff --git a/drivers/sbus/Makefile b/drivers/sbus/Makefile
index 7b1d24d9..e94dc25 100644
--- a/drivers/sbus/Makefile
+++ b/drivers/sbus/Makefile
@@ -2,8 +2,4 @@
 # Makefile for the linux kernel.
 #
 
-ifneq ($(ARCH),m68k)
-obj-y    := sbus.o dvma.o
-endif
-
 obj-$(CONFIG_SBUSCHAR) += char/
diff --git a/drivers/sbus/char/Kconfig b/drivers/sbus/char/Kconfig
index 400c65b..73cde85 100644
--- a/drivers/sbus/char/Kconfig
+++ b/drivers/sbus/char/Kconfig
@@ -13,16 +13,6 @@
 
 	  If unsure, say Y.
 
-config SUN_MOSTEK_RTC
-	tristate "Mostek real time clock support"
-	depends on SPARC32
-	help
-	  The Mostek RTC chip is used on all known Sun computers except
-	  some JavaStations. For a JavaStation you need to say Y both here
-	  and to "Enhanced Real Time Clock Support".
-
-	  Say Y here unless you are building a special purpose kernel.
-
 config OBP_FLASH
 	tristate "OBP Flash Device support"
 	depends on SPARC64
@@ -30,26 +20,9 @@
 	  The OpenBoot PROM on Ultra systems is flashable. If you want to be
 	  able to upgrade the OBP firmware, say Y here.
 
-config SUN_BPP
-	tristate "Bidirectional parallel port support (OBSOLETE)"
-	depends on EXPERIMENTAL
-	help
-	  Say Y here to support Sun's obsolete variant of IEEE1284
-	  bidirectional parallel port protocol as /dev/bppX.  Can be built on
-	  x86 machines.
-
-config SUN_VIDEOPIX
-	tristate "Videopix Frame Grabber (EXPERIMENTAL)"
-	depends on EXPERIMENTAL && (BROKEN || !64BIT)
-	help
-	  Say Y here to support the Videopix Frame Grabber from Sun
-	  Microsystems, commonly found on SPARCstations.  This card, which is
-	  based on the Phillips SAA9051, can handle NTSC and PAL/SECAM and
-	  SVIDEO signals.
-
 config TADPOLE_TS102_UCTRL
 	tristate "Tadpole TS102 Microcontroller support (EXPERIMENTAL)"
-	depends on EXPERIMENTAL && SPARC32
+	depends on EXPERIMENTAL
 	help
 	  Say Y here to directly support the TS102 Microcontroller interface
 	  on the Tadpole Sparcbook 3.  This device handles power-management
diff --git a/drivers/sbus/char/Makefile b/drivers/sbus/char/Makefile
index 7ab060e..78b6183 100644
--- a/drivers/sbus/char/Makefile
+++ b/drivers/sbus/char/Makefile
@@ -7,18 +7,12 @@
 # Rewritten to use lists instead of if-statements.
 #
 
-vfc-objs := vfc_dev.o vfc_i2c.o
 bbc-objs := bbc_i2c.o bbc_envctrl.o
 
 obj-$(CONFIG_ENVCTRL)			+= envctrl.o
 obj-$(CONFIG_DISPLAY7SEG)		+= display7seg.o
-obj-$(CONFIG_WATCHDOG_CP1XXX)		+= cpwatchdog.o
-obj-$(CONFIG_WATCHDOG_RIO)		+= riowatchdog.o
 obj-$(CONFIG_OBP_FLASH)			+= flash.o
 obj-$(CONFIG_SUN_OPENPROMIO)		+= openprom.o
-obj-$(CONFIG_SUN_MOSTEK_RTC)		+= rtc.o
-obj-$(CONFIG_SUN_BPP)			+= bpp.o
-obj-$(CONFIG_SUN_VIDEOPIX)		+= vfc.o
 obj-$(CONFIG_TADPOLE_TS102_UCTRL)	+= uctrl.o
 obj-$(CONFIG_SUN_JSFLASH)		+= jsflash.o
 obj-$(CONFIG_BBC_I2C)			+= bbc.o
diff --git a/drivers/sbus/char/bbc_envctrl.c b/drivers/sbus/char/bbc_envctrl.c
index 0bde269..15dab96 100644
--- a/drivers/sbus/char/bbc_envctrl.c
+++ b/drivers/sbus/char/bbc_envctrl.c
@@ -1,15 +1,15 @@
-/* $Id: bbc_envctrl.c,v 1.4 2001/04/06 16:48:08 davem Exp $
- * bbc_envctrl.c: UltraSPARC-III environment control driver.
+/* bbc_envctrl.c: UltraSPARC-III environment control driver.
  *
- * Copyright (C) 2001 David S. Miller (davem@redhat.com)
+ * Copyright (C) 2001, 2008 David S. Miller (davem@davemloft.net)
  */
 
 #include <linux/kthread.h>
 #include <linux/delay.h>
 #include <linux/kmod.h>
 #include <linux/reboot.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 #include <asm/oplib.h>
-#include <asm/ebus.h>
 
 #include "bbc_i2c.h"
 #include "max1617.h"
@@ -75,43 +75,8 @@
 	{ 65, 55, 40, 5, -5, -10 },
 };
 
-enum fan_action { FAN_SLOWER, FAN_SAME, FAN_FASTER, FAN_FULLBLAST, FAN_STATE_MAX };
-
-struct bbc_cpu_temperature {
-	struct bbc_cpu_temperature	*next;
-
-	struct bbc_i2c_client		*client;
-	int				index;
-
-	/* Current readings, and history. */
-	s8				curr_cpu_temp;
-	s8				curr_amb_temp;
-	s8				prev_cpu_temp;
-	s8				prev_amb_temp;
-	s8				avg_cpu_temp;
-	s8				avg_amb_temp;
-
-	int				sample_tick;
-
-	enum fan_action			fan_todo[2];
-#define FAN_AMBIENT	0
-#define FAN_CPU		1
-};
-
-struct bbc_cpu_temperature *all_bbc_temps;
-
-struct bbc_fan_control {
-	struct bbc_fan_control 	*next;
-
-	struct bbc_i2c_client 	*client;
-	int 			index;
-
-	int			psupply_fan_on;
-	int			cpu_fan_speed;
-	int			system_fan_speed;
-};
-
-struct bbc_fan_control *all_bbc_fans;
+static LIST_HEAD(all_temps);
+static LIST_HEAD(all_fans);
 
 #define CPU_FAN_REG	0xf0
 #define SYS_FAN_REG	0xf2
@@ -330,7 +295,7 @@
 	 * recommend we do, and perform that action on all the
 	 * fans.
 	 */
-	for (tp = all_bbc_temps; tp; tp = tp->next) {
+	list_for_each_entry(tp, &all_temps, glob_list) {
 		if (tp->fan_todo[which_fan] == FAN_FULLBLAST) {
 			decision = FAN_FULLBLAST;
 			break;
@@ -439,7 +404,7 @@
 	/* Since we will not be monitoring things anymore, put
 	 * the fans on full blast.
 	 */
-	for (fp = all_bbc_fans; fp; fp = fp->next) {
+	list_for_each_entry(fp, &all_fans, glob_list) {
 		fp->cpu_fan_speed = FAN_SPEED_MAX;
 		fp->system_fan_speed = FAN_SPEED_MAX;
 		fp->psupply_fan_on = 1;
@@ -463,11 +428,11 @@
 		if (kthread_should_stop())
 			break;
 
-		for (tp = all_bbc_temps; tp; tp = tp->next) {
+		list_for_each_entry(tp, &all_temps, glob_list) {
 			get_current_temps(tp);
 			analyze_temps(tp, &last_warning_jiffies);
 		}
-		for (fp = all_bbc_fans; fp; fp = fp->next)
+		list_for_each_entry(fp, &all_fans, glob_list)
 			maybe_new_fan_speeds(fp);
 	}
 	printk(KERN_INFO "bbc_envctrl: kenvctrld exiting...\n");
@@ -477,7 +442,8 @@
 	return 0;
 }
 
-static void attach_one_temp(struct linux_ebus_child *echild, int temp_idx)
+static void attach_one_temp(struct bbc_i2c_bus *bp, struct of_device *op,
+			    int temp_idx)
 {
 	struct bbc_cpu_temperature *tp;
 
@@ -485,20 +451,17 @@
 	if (!tp)
 		return;
 
-	tp->client = bbc_i2c_attach(echild);
+	tp->client = bbc_i2c_attach(bp, op);
 	if (!tp->client) {
 		kfree(tp);
 		return;
 	}
 
+
 	tp->index = temp_idx;
-	{
-		struct bbc_cpu_temperature **tpp = &all_bbc_temps;
-		while (*tpp)
-			tpp = &((*tpp)->next);
-		tp->next = NULL;
-		*tpp = tp;
-	}
+
+	list_add(&tp->glob_list, &all_temps);
+	list_add(&tp->bp_list, &bp->temps);
 
 	/* Tell it to convert once every 5 seconds, clear all cfg
 	 * bits.
@@ -524,7 +487,8 @@
 	tp->fan_todo[FAN_CPU] = FAN_SAME;
 }
 
-static void attach_one_fan(struct linux_ebus_child *echild, int fan_idx)
+static void attach_one_fan(struct bbc_i2c_bus *bp, struct of_device *op,
+			   int fan_idx)
 {
 	struct bbc_fan_control *fp;
 
@@ -532,7 +496,7 @@
 	if (!fp)
 		return;
 
-	fp->client = bbc_i2c_attach(echild);
+	fp->client = bbc_i2c_attach(bp, op);
 	if (!fp->client) {
 		kfree(fp);
 		return;
@@ -540,13 +504,8 @@
 
 	fp->index = fan_idx;
 
-	{
-		struct bbc_fan_control **fpp = &all_bbc_fans;
-		while (*fpp)
-			fpp = &((*fpp)->next);
-		fp->next = NULL;
-		*fpp = fp;
-	}
+	list_add(&fp->glob_list, &all_fans);
+	list_add(&fp->bp_list, &bp->fans);
 
 	/* The i2c device controlling the fans is write-only.
 	 * So the only way to keep track of the current power
@@ -563,18 +522,18 @@
 	set_fan_speeds(fp);
 }
 
-int bbc_envctrl_init(void)
+int bbc_envctrl_init(struct bbc_i2c_bus *bp)
 {
-	struct linux_ebus_child *echild;
+	struct of_device *op;
 	int temp_index = 0;
 	int fan_index = 0;
 	int devidx = 0;
 
-	while ((echild = bbc_i2c_getdev(devidx++)) != NULL) {
-		if (!strcmp(echild->prom_node->name, "temperature"))
-			attach_one_temp(echild, temp_index++);
-		if (!strcmp(echild->prom_node->name, "fan-control"))
-			attach_one_fan(echild, fan_index++);
+	while ((op = bbc_i2c_getdev(bp, devidx++)) != NULL) {
+		if (!strcmp(op->node->name, "temperature"))
+			attach_one_temp(bp, op, temp_index++);
+		if (!strcmp(op->node->name, "fan-control"))
+			attach_one_fan(bp, op, fan_index++);
 	}
 	if (temp_index != 0 && fan_index != 0) {
 		kenvctrld_task = kthread_run(kenvctrld, NULL, "kenvctrld");
@@ -597,26 +556,22 @@
 	kfree(fp);
 }
 
-void bbc_envctrl_cleanup(void)
+void bbc_envctrl_cleanup(struct bbc_i2c_bus *bp)
 {
-	struct bbc_cpu_temperature *tp;
-	struct bbc_fan_control *fp;
+	struct bbc_cpu_temperature *tp, *tpos;
+	struct bbc_fan_control *fp, *fpos;
 
 	kthread_stop(kenvctrld_task);
 
-	tp = all_bbc_temps;
-	while (tp != NULL) {
-		struct bbc_cpu_temperature *next = tp->next;
+	list_for_each_entry_safe(tp, tpos, &bp->temps, bp_list) {
+		list_del(&tp->bp_list);
+		list_del(&tp->glob_list);
 		destroy_one_temp(tp);
-		tp = next;
 	}
-	all_bbc_temps = NULL;
 
-	fp = all_bbc_fans;
-	while (fp != NULL) {
-		struct bbc_fan_control *next = fp->next;
+	list_for_each_entry_safe(fp, fpos, &bp->fans, bp_list) {
+		list_del(&fp->bp_list);
+		list_del(&fp->glob_list);
 		destroy_one_fan(fp);
-		fp = next;
 	}
-	all_bbc_fans = NULL;
 }
diff --git a/drivers/sbus/char/bbc_i2c.c b/drivers/sbus/char/bbc_i2c.c
index ac8ef2c..f08e169 100644
--- a/drivers/sbus/char/bbc_i2c.c
+++ b/drivers/sbus/char/bbc_i2c.c
@@ -1,8 +1,7 @@
-/* $Id: bbc_i2c.c,v 1.2 2001/04/02 09:59:08 davem Exp $
- * bbc_i2c.c: I2C low-level driver for BBC device on UltraSPARC-III
+/* bbc_i2c.c: I2C low-level driver for BBC device on UltraSPARC-III
  *            platforms.
  *
- * Copyright (C) 2001 David S. Miller (davem@redhat.com)
+ * Copyright (C) 2001, 2008 David S. Miller (davem@davemloft.net)
  */
 
 #include <linux/module.h>
@@ -14,9 +13,8 @@
 #include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
-#include <asm/oplib.h>
-#include <asm/ebus.h>
-#include <asm/spitfire.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 #include <asm/bbc.h>
 #include <asm/io.h>
 
@@ -53,54 +51,12 @@
  * The second controller also connects to the smartcard reader, if present.
  */
 
-#define NUM_CHILDREN	8
-struct bbc_i2c_bus {
-	struct bbc_i2c_bus		*next;
-	int				index;
-	spinlock_t			lock;
-	void				__iomem *i2c_bussel_reg;
-	void				__iomem *i2c_control_regs;
-	unsigned char			own, clock;
-
-	wait_queue_head_t		wq;
-	volatile int			waiting;
-
-	struct linux_ebus_device	*bus_edev;
-	struct {
-		struct linux_ebus_child	*device;
-		int			client_claimed;
-	} devs[NUM_CHILDREN];
-};
-
-static struct bbc_i2c_bus *all_bbc_i2c;
-
-struct bbc_i2c_client {
-	struct bbc_i2c_bus	*bp;
-	struct linux_ebus_child	*echild;
-	int			bus;
-	int			address;
-};
-
-static int find_device(struct bbc_i2c_bus *bp, struct linux_ebus_child *echild)
+static void set_device_claimage(struct bbc_i2c_bus *bp, struct of_device *op, int val)
 {
 	int i;
 
 	for (i = 0; i < NUM_CHILDREN; i++) {
-		if (bp->devs[i].device == echild) {
-			if (bp->devs[i].client_claimed)
-				return 0;
-			return 1;
-		}
-	}
-	return 0;
-}
-
-static void set_device_claimage(struct bbc_i2c_bus *bp, struct linux_ebus_child *echild, int val)
-{
-	int i;
-
-	for (i = 0; i < NUM_CHILDREN; i++) {
-		if (bp->devs[i].device == echild) {
+		if (bp->devs[i].device == op) {
 			bp->devs[i].client_claimed = val;
 			return;
 		}
@@ -110,61 +66,47 @@
 #define claim_device(BP,ECHILD)		set_device_claimage(BP,ECHILD,1)
 #define release_device(BP,ECHILD)	set_device_claimage(BP,ECHILD,0)
 
-static struct bbc_i2c_bus *find_bus_for_device(struct linux_ebus_child *echild)
+struct of_device *bbc_i2c_getdev(struct bbc_i2c_bus *bp, int index)
 {
-	struct bbc_i2c_bus *bp = all_bbc_i2c;
+	struct of_device *op = NULL;
+	int curidx = 0, i;
 
-	while (bp != NULL) {
-		if (find_device(bp, echild) != 0)
+	for (i = 0; i < NUM_CHILDREN; i++) {
+		if (!(op = bp->devs[i].device))
 			break;
-		bp = bp->next;
+		if (curidx == index)
+			goto out;
+		op = NULL;
+		curidx++;
 	}
 
-	return bp;
-}
-
-struct linux_ebus_child *bbc_i2c_getdev(int index)
-{
-	struct bbc_i2c_bus *bp = all_bbc_i2c;
-	struct linux_ebus_child *echild = NULL;
-	int curidx = 0;
-
-	while (bp != NULL) {
-		struct bbc_i2c_bus *next = bp->next;
-		int i;
-
-		for (i = 0; i < NUM_CHILDREN; i++) {
-			if (!(echild = bp->devs[i].device))
-				break;
-			if (curidx == index)
-				goto out;
-			echild = NULL;
-			curidx++;
-		}
-		bp = next;
-	}
 out:
 	if (curidx == index)
-		return echild;
+		return op;
 	return NULL;
 }
 
-struct bbc_i2c_client *bbc_i2c_attach(struct linux_ebus_child *echild)
+struct bbc_i2c_client *bbc_i2c_attach(struct bbc_i2c_bus *bp, struct of_device *op)
 {
-	struct bbc_i2c_bus *bp = find_bus_for_device(echild);
 	struct bbc_i2c_client *client;
+	const u32 *reg;
 
-	if (!bp)
-		return NULL;
 	client = kzalloc(sizeof(*client), GFP_KERNEL);
 	if (!client)
 		return NULL;
 	client->bp = bp;
-	client->echild = echild;
-	client->bus = echild->resource[0].start;
-	client->address = echild->resource[1].start;
+	client->op = op;
 
-	claim_device(bp, echild);
+	reg = of_get_property(op->node, "reg", NULL);
+	if (!reg) {
+		kfree(client);
+		return NULL;
+	}
+
+	client->bus = reg[0];
+	client->address = reg[1];
+
+	claim_device(bp, op);
 
 	return client;
 }
@@ -172,9 +114,9 @@
 void bbc_i2c_detach(struct bbc_i2c_client *client)
 {
 	struct bbc_i2c_bus *bp = client->bp;
-	struct linux_ebus_child *echild = client->echild;
+	struct of_device *op = client->op;
 
-	release_device(bp, echild);
+	release_device(bp, op);
 	kfree(client);
 }
 
@@ -355,44 +297,43 @@
 	writeb(I2C_PCF_IDLE, bp->i2c_control_regs + 0x0);
 }
 
-static int __init attach_one_i2c(struct linux_ebus_device *edev, int index)
+static struct bbc_i2c_bus * __init attach_one_i2c(struct of_device *op, int index)
 {
 	struct bbc_i2c_bus *bp;
-	struct linux_ebus_child *echild;
+	struct device_node *dp;
 	int entry;
 
 	bp = kzalloc(sizeof(*bp), GFP_KERNEL);
 	if (!bp)
-		return -ENOMEM;
+		return NULL;
 
-	bp->i2c_control_regs = ioremap(edev->resource[0].start, 0x2);
+	bp->i2c_control_regs = of_ioremap(&op->resource[0], 0, 0x2, "bbc_i2c_regs");
 	if (!bp->i2c_control_regs)
 		goto fail;
 
-	if (edev->num_addrs == 2) {
-		bp->i2c_bussel_reg = ioremap(edev->resource[1].start, 0x1);
-		if (!bp->i2c_bussel_reg)
-			goto fail;
-	}
+	bp->i2c_bussel_reg = of_ioremap(&op->resource[1], 0, 0x1, "bbc_i2c_bussel");
+	if (!bp->i2c_bussel_reg)
+		goto fail;
 
 	bp->waiting = 0;
 	init_waitqueue_head(&bp->wq);
-	if (request_irq(edev->irqs[0], bbc_i2c_interrupt,
+	if (request_irq(op->irqs[0], bbc_i2c_interrupt,
 			IRQF_SHARED, "bbc_i2c", bp))
 		goto fail;
 
 	bp->index = index;
-	bp->bus_edev = edev;
+	bp->op = op;
 
 	spin_lock_init(&bp->lock);
-	bp->next = all_bbc_i2c;
-	all_bbc_i2c = bp;
 
 	entry = 0;
-	for (echild = edev->children;
-	     echild && entry < 8;
-	     echild = echild->next, entry++) {
-		bp->devs[entry].device = echild;
+	for (dp = op->node->child;
+	     dp && entry < 8;
+	     dp = dp->sibling, entry++) {
+		struct of_device *child_op;
+
+		child_op = of_find_device_by_node(dp);
+		bp->devs[entry].device = child_op;
 		bp->devs[entry].client_claimed = 0;
 	}
 
@@ -406,86 +347,90 @@
 
 	reset_one_i2c(bp);
 
-	return 0;
+	return bp;
 
 fail:
 	if (bp->i2c_bussel_reg)
-		iounmap(bp->i2c_bussel_reg);
+		of_iounmap(&op->resource[1], bp->i2c_bussel_reg, 1);
 	if (bp->i2c_control_regs)
-		iounmap(bp->i2c_control_regs);
+		of_iounmap(&op->resource[0], bp->i2c_control_regs, 2);
 	kfree(bp);
-	return -EINVAL;
+	return NULL;
 }
 
-static int __init bbc_present(void)
+extern int bbc_envctrl_init(struct bbc_i2c_bus *bp);
+extern void bbc_envctrl_cleanup(struct bbc_i2c_bus *bp);
+
+static int __devinit bbc_i2c_probe(struct of_device *op,
+				   const struct of_device_id *match)
 {
-	struct linux_ebus *ebus = NULL;
-	struct linux_ebus_device *edev = NULL;
-
-	for_each_ebus(ebus) {
-		for_each_ebusdev(edev, ebus) {
-			if (!strcmp(edev->prom_node->name, "bbc"))
-				return 1;
-		}
-	}
-	return 0;
-}
-
-extern int bbc_envctrl_init(void);
-extern void bbc_envctrl_cleanup(void);
-static void bbc_i2c_cleanup(void);
-
-static int __init bbc_i2c_init(void)
-{
-	struct linux_ebus *ebus = NULL;
-	struct linux_ebus_device *edev = NULL;
+	struct bbc_i2c_bus *bp;
 	int err, index = 0;
 
-	if ((tlb_type != cheetah && tlb_type != cheetah_plus) ||
-	    !bbc_present())
-		return -ENODEV;
+	bp = attach_one_i2c(op, index);
+	if (!bp)
+		return -EINVAL;
 
-	for_each_ebus(ebus) {
-		for_each_ebusdev(edev, ebus) {
-			if (!strcmp(edev->prom_node->name, "i2c")) {
-				if (!attach_one_i2c(edev, index))
-					index++;
-			}
-		}
+	err = bbc_envctrl_init(bp);
+	if (err) {
+		free_irq(op->irqs[0], bp);
+		if (bp->i2c_bussel_reg)
+			of_iounmap(&op->resource[0], bp->i2c_bussel_reg, 1);
+		if (bp->i2c_control_regs)
+			of_iounmap(&op->resource[1], bp->i2c_control_regs, 2);
+		kfree(bp);
+	} else {
+		dev_set_drvdata(&op->dev, bp);
 	}
 
-	if (!index)
-		return -ENODEV;
-
-	err = bbc_envctrl_init();
-	if (err)
-		bbc_i2c_cleanup();
 	return err;
 }
 
-static void bbc_i2c_cleanup(void)
+static int __devexit bbc_i2c_remove(struct of_device *op)
 {
-	struct bbc_i2c_bus *bp = all_bbc_i2c;
+	struct bbc_i2c_bus *bp = dev_get_drvdata(&op->dev);
 
-	bbc_envctrl_cleanup();
+	bbc_envctrl_cleanup(bp);
 
-	while (bp != NULL) {
-		struct bbc_i2c_bus *next = bp->next;
+	free_irq(op->irqs[0], bp);
 
-		free_irq(bp->bus_edev->irqs[0], bp);
+	if (bp->i2c_bussel_reg)
+		of_iounmap(&op->resource[0], bp->i2c_bussel_reg, 1);
+	if (bp->i2c_control_regs)
+		of_iounmap(&op->resource[1], bp->i2c_control_regs, 2);
 
-		if (bp->i2c_bussel_reg)
-			iounmap(bp->i2c_bussel_reg);
-		if (bp->i2c_control_regs)
-			iounmap(bp->i2c_control_regs);
+	kfree(bp);
 
-		kfree(bp);
+	return 0;
+}
 
-		bp = next;
-	}
-	all_bbc_i2c = NULL;
+static const struct of_device_id bbc_i2c_match[] = {
+	{
+		.name = "i2c",
+		.compatible = "SUNW,bbc-i2c",
+	},
+	{},
+};
+MODULE_DEVICE_TABLE(of, bbc_i2c_match);
+
+static struct of_platform_driver bbc_i2c_driver = {
+	.name		= "bbc_i2c",
+	.match_table	= bbc_i2c_match,
+	.probe		= bbc_i2c_probe,
+	.remove		= __devexit_p(bbc_i2c_remove),
+};
+
+static int __init bbc_i2c_init(void)
+{
+	return of_register_driver(&bbc_i2c_driver, &of_bus_type);
+}
+
+static void __exit bbc_i2c_exit(void)
+{
+	of_unregister_driver(&bbc_i2c_driver);
 }
 
 module_init(bbc_i2c_init);
-module_exit(bbc_i2c_cleanup);
+module_exit(bbc_i2c_exit);
+
 MODULE_LICENSE("GPL");
diff --git a/drivers/sbus/char/bbc_i2c.h b/drivers/sbus/char/bbc_i2c.h
index fb01bd1..83c4811 100644
--- a/drivers/sbus/char/bbc_i2c.h
+++ b/drivers/sbus/char/bbc_i2c.h
@@ -1,14 +1,79 @@
-/* $Id: bbc_i2c.h,v 1.2 2001/04/02 09:59:25 davem Exp $ */
 #ifndef _BBC_I2C_H
 #define _BBC_I2C_H
 
-#include <asm/ebus.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/list.h>
 
-struct bbc_i2c_client;
+struct bbc_i2c_client {
+	struct bbc_i2c_bus		*bp;
+	struct of_device		*op;
+	int				bus;
+	int				address;
+};
+
+enum fan_action { FAN_SLOWER, FAN_SAME, FAN_FASTER, FAN_FULLBLAST, FAN_STATE_MAX };
+
+struct bbc_cpu_temperature {
+	struct list_head		bp_list;
+	struct list_head		glob_list;
+
+	struct bbc_i2c_client		*client;
+	int				index;
+
+	/* Current readings, and history. */
+	s8				curr_cpu_temp;
+	s8				curr_amb_temp;
+	s8				prev_cpu_temp;
+	s8				prev_amb_temp;
+	s8				avg_cpu_temp;
+	s8				avg_amb_temp;
+
+	int				sample_tick;
+
+	enum fan_action			fan_todo[2];
+#define FAN_AMBIENT	0
+#define FAN_CPU		1
+};
+
+struct bbc_fan_control {
+	struct list_head		bp_list;
+	struct list_head		glob_list;
+
+	struct bbc_i2c_client 		*client;
+	int 				index;
+
+	int				psupply_fan_on;
+	int				cpu_fan_speed;
+	int				system_fan_speed;
+};
+
+#define NUM_CHILDREN	8
+
+struct bbc_i2c_bus {
+	struct bbc_i2c_bus		*next;
+	int				index;
+	spinlock_t			lock;
+	void				__iomem *i2c_bussel_reg;
+	void				__iomem *i2c_control_regs;
+	unsigned char			own, clock;
+
+	wait_queue_head_t		wq;
+	volatile int			waiting;
+
+	struct list_head		temps;
+	struct list_head		fans;
+
+	struct of_device		*op;
+	struct {
+		struct of_device	*device;
+		int			client_claimed;
+	} devs[NUM_CHILDREN];
+};
 
 /* Probing and attachment. */
-extern struct linux_ebus_child *bbc_i2c_getdev(int);
-extern struct bbc_i2c_client *bbc_i2c_attach(struct linux_ebus_child *);
+extern struct of_device *bbc_i2c_getdev(struct bbc_i2c_bus *, int);
+extern struct bbc_i2c_client *bbc_i2c_attach(struct bbc_i2c_bus *bp, struct of_device *);
 extern void bbc_i2c_detach(struct bbc_i2c_client *);
 
 /* Register read/write.  NOTE: Blocking! */
diff --git a/drivers/sbus/char/bpp.c b/drivers/sbus/char/bpp.c
deleted file mode 100644
index bba21e05..0000000
--- a/drivers/sbus/char/bpp.c
+++ /dev/null
@@ -1,1055 +0,0 @@
-/*
- * drivers/sbus/char/bpp.c
- *
- * Copyright (c) 1995 Picture Elements
- *      Stephen Williams (steve@icarus.com)
- *      Gus Baldauf (gbaldauf@ix.netcom.com)
- *
- * Linux/SPARC port by Peter Zaitcev.
- * Integration into SPARC tree by Tom Dyas.
- */
-
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/fs.h>
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/spinlock.h>
-#include <linux/timer.h>
-#include <linux/ioport.h>
-#include <linux/major.h>
-#include <linux/smp_lock.h>
-
-#include <asm/uaccess.h>
-#include <asm/io.h>
-
-#if defined(__i386__)
-# include <asm/system.h>
-#endif
-
-#if defined(__sparc__)
-# include <linux/init.h>
-# include <linux/delay.h>         /* udelay() */
-
-# include <asm/oplib.h>           /* OpenProm Library */
-# include <asm/sbus.h>
-#endif
-
-#include <asm/bpp.h>
-
-#define BPP_PROBE_CODE 0x55
-#define BPP_DELAY 100
-
-static const unsigned  BPP_MAJOR = LP_MAJOR;
-static const char *bpp_dev_name = "bpp";
-
-/* When switching from compatibility to a mode where I can read, try
-   the following mode first. */
-
-/* const unsigned char DEFAULT_ECP = 0x10; */
-static const unsigned char DEFAULT_ECP = 0x30;
-static const unsigned char DEFAULT_NIBBLE = 0x00;
-
-/*
- * These are 1284 time constraints, in units of jiffies.
- */
-
-static const unsigned long TIME_PSetup = 1;
-static const unsigned long TIME_PResponse = 6;
-static const unsigned long TIME_IDLE_LIMIT = 2000;
-
-/*
- * One instance per supported subdevice...
- */
-# define BPP_NO 3
-
-enum IEEE_Mode { COMPATIBILITY, NIBBLE, ECP, ECP_RLE, EPP };
-
-struct inst {
-      unsigned present  : 1; /* True if the hardware exists */
-      unsigned enhanced : 1; /* True if the hardware in "enhanced" */
-      unsigned opened   : 1; /* True if the device is opened already */
-      unsigned run_flag : 1; /* True if waiting for a repeate byte */
-
-      unsigned char direction; /* 0 --> out, 0x20 --> IN */
-      unsigned char pp_state; /* State of host controlled pins. */
-      enum IEEE_Mode mode;
-
-      unsigned char run_length;
-      unsigned char repeat_byte;
-};
-
-static struct inst instances[BPP_NO];
-
-#if defined(__i386__)
-
-static const unsigned short base_addrs[BPP_NO] = { 0x278, 0x378, 0x3bc };
-
-/*
- * These are for data access.
- * Control lines accesses are hidden in set_bits() and get_bits().
- * The exception is the probe procedure, which is system-dependent.
- */
-#define bpp_outb_p(data, base)  outb_p((data), (base))
-#define bpp_inb(base)  inb(base)
-#define bpp_inb_p(base)  inb_p(base)
-
-/*
- * This method takes the pin values mask and sets the hardware pins to
- * the requested value: 1 == high voltage, 0 == low voltage. This
- * burries the annoying PC bit inversion and preserves the direction
- * flag.
- */
-static void set_pins(unsigned short pins, unsigned minor)
-{
-      unsigned char bits = instances[minor].direction;  /* == 0x20 */
-
-      if (! (pins & BPP_PP_nStrobe))   bits |= 1;
-      if (! (pins & BPP_PP_nAutoFd))   bits |= 2;
-      if (   pins & BPP_PP_nInit)      bits |= 4;
-      if (! (pins & BPP_PP_nSelectIn)) bits |= 8;
-
-      instances[minor].pp_state = bits;
-
-      outb_p(bits, base_addrs[minor]+2);
-}
-
-static unsigned short get_pins(unsigned minor)
-{
-      unsigned short bits = 0;
-
-      unsigned value = instances[minor].pp_state;
-      if (! (value & 0x01)) bits |= BPP_PP_nStrobe;
-      if (! (value & 0x02)) bits |= BPP_PP_nAutoFd;
-      if (value & 0x04)     bits |= BPP_PP_nInit;
-      if (! (value & 0x08)) bits |= BPP_PP_nSelectIn;
-
-      value = inb_p(base_addrs[minor]+1);
-      if (value & 0x08)     bits |= BPP_GP_nFault;
-      if (value & 0x10)     bits |= BPP_GP_Select;
-      if (value & 0x20)     bits |= BPP_GP_PError;
-      if (value & 0x40)     bits |= BPP_GP_nAck;
-      if (! (value & 0x80)) bits |= BPP_GP_Busy;
-
-      return bits;
-}
-
-#endif /* __i386__ */
-
-#if defined(__sparc__)
-
-/*
- * Register block
- */
-      /* DMA registers */
-#define BPP_CSR      0x00
-#define BPP_ADDR     0x04
-#define BPP_BCNT     0x08
-#define BPP_TST_CSR  0x0C
-      /* Parallel Port registers */
-#define BPP_HCR      0x10
-#define BPP_OCR      0x12
-#define BPP_DR       0x14
-#define BPP_TCR      0x15
-#define BPP_OR       0x16
-#define BPP_IR       0x17
-#define BPP_ICR      0x18
-#define BPP_SIZE     0x1A
-
-/* BPP_CSR.  Bits of type RW1 are cleared with writing '1'. */
-#define P_DEV_ID_MASK   0xf0000000      /* R   */
-#define P_DEV_ID_ZEBRA  0x40000000
-#define P_DEV_ID_L64854 0xa0000000      /*      == NCR 89C100+89C105. Pity. */
-#define P_NA_LOADED     0x08000000      /* R    NA wirtten but was not used */
-#define P_A_LOADED      0x04000000      /* R    */
-#define P_DMA_ON        0x02000000      /* R    DMA is not disabled */
-#define P_EN_NEXT       0x01000000      /* RW   */
-#define P_TCI_DIS       0x00800000      /* RW   TCI forbidden from interrupts */
-#define P_DIAG          0x00100000      /* RW   Disables draining and resetting
-                                                of P-FIFO on loading of P_ADDR*/
-#define P_BURST_SIZE    0x000c0000      /* RW   SBus burst size */
-#define P_BURST_8       0x00000000
-#define P_BURST_4       0x00040000
-#define P_BURST_1       0x00080000      /*      "No burst" write */
-#define P_TC            0x00004000      /* RW1  Term Count, can be cleared when
-                                           P_EN_NEXT=1 */
-#define P_EN_CNT        0x00002000      /* RW   */
-#define P_EN_DMA        0x00000200      /* RW   */
-#define P_WRITE         0x00000100      /* R    DMA dir, 1=to ram, 0=to port */
-#define P_RESET         0x00000080      /* RW   */
-#define P_SLAVE_ERR     0x00000040      /* RW1  Access size error */
-#define P_INVALIDATE    0x00000020      /* W    Drop P-FIFO */
-#define P_INT_EN        0x00000010      /* RW   OK to P_INT_PEND||P_ERR_PEND */
-#define P_DRAINING      0x0000000c      /* R    P-FIFO is draining to memory */
-#define P_ERR_PEND      0x00000002      /* R    */
-#define P_INT_PEND      0x00000001      /* R    */
-
-/* BPP_HCR. Time is in increments of SBus clock. */
-#define P_HCR_TEST      0x8000      /* Allows buried counters to be read */
-#define P_HCR_DSW       0x7f00      /* Data strobe width (in ticks) */
-#define P_HCR_DDS       0x007f      /* Data setup before strobe (in ticks) */
-
-/* BPP_OCR. */
-#define P_OCR_MEM_CLR   0x8000
-#define P_OCR_DATA_SRC  0x4000      /* )                  */
-#define P_OCR_DS_DSEL   0x2000      /* )  Bidirectional      */
-#define P_OCR_BUSY_DSEL 0x1000      /* )    selects            */
-#define P_OCR_ACK_DSEL  0x0800      /* )                  */
-#define P_OCR_EN_DIAG   0x0400
-#define P_OCR_BUSY_OP   0x0200      /* Busy operation */
-#define P_OCR_ACK_OP    0x0100      /* Ack operation */
-#define P_OCR_SRST      0x0080      /* Reset state machines. Not selfcleaning. */
-#define P_OCR_IDLE      0x0008      /* PP data transfer state machine is idle */
-#define P_OCR_V_ILCK    0x0002      /* Versatec faded. Zebra only. */
-#define P_OCR_EN_VER    0x0001      /* Enable Versatec (0 - enable). Zebra only. */
-
-/* BPP_TCR */
-#define P_TCR_DIR       0x08
-#define P_TCR_BUSY      0x04
-#define P_TCR_ACK       0x02
-#define P_TCR_DS        0x01        /* Strobe */
-
-/* BPP_OR */
-#define P_OR_V3         0x20        /* )                 */
-#define P_OR_V2         0x10        /* ) on Zebra only   */
-#define P_OR_V1         0x08        /* )                 */
-#define P_OR_INIT       0x04
-#define P_OR_AFXN       0x02        /* Auto Feed */
-#define P_OR_SLCT_IN    0x01
-
-/* BPP_IR */
-#define P_IR_PE         0x04
-#define P_IR_SLCT       0x02
-#define P_IR_ERR        0x01
-
-/* BPP_ICR */
-#define P_DS_IRQ        0x8000      /* RW1  */
-#define P_ACK_IRQ       0x4000      /* RW1  */
-#define P_BUSY_IRQ      0x2000      /* RW1  */
-#define P_PE_IRQ        0x1000      /* RW1  */
-#define P_SLCT_IRQ      0x0800      /* RW1  */
-#define P_ERR_IRQ       0x0400      /* RW1  */
-#define P_DS_IRQ_EN     0x0200      /* RW   Always on rising edge */
-#define P_ACK_IRQ_EN    0x0100      /* RW   Always on rising edge */
-#define P_BUSY_IRP      0x0080      /* RW   1= rising edge */
-#define P_BUSY_IRQ_EN   0x0040      /* RW   */
-#define P_PE_IRP        0x0020      /* RW   1= rising edge */
-#define P_PE_IRQ_EN     0x0010      /* RW   */
-#define P_SLCT_IRP      0x0008      /* RW   1= rising edge */
-#define P_SLCT_IRQ_EN   0x0004      /* RW   */
-#define P_ERR_IRP       0x0002      /* RW1  1= rising edge */
-#define P_ERR_IRQ_EN    0x0001      /* RW   */
-
-static void __iomem *base_addrs[BPP_NO];
-
-#define bpp_outb_p(data, base)	sbus_writeb(data, (base) + BPP_DR)
-#define bpp_inb_p(base)		sbus_readb((base) + BPP_DR)
-#define bpp_inb(base)		sbus_readb((base) + BPP_DR)
-
-static void set_pins(unsigned short pins, unsigned minor)
-{
-      void __iomem *base = base_addrs[minor];
-      unsigned char bits_tcr = 0, bits_or = 0;
-
-      if (instances[minor].direction & 0x20) bits_tcr |= P_TCR_DIR;
-      if (   pins & BPP_PP_nStrobe)          bits_tcr |= P_TCR_DS;
-
-      if (   pins & BPP_PP_nAutoFd)          bits_or |= P_OR_AFXN;
-      if (! (pins & BPP_PP_nInit))           bits_or |= P_OR_INIT;
-      if (! (pins & BPP_PP_nSelectIn))       bits_or |= P_OR_SLCT_IN;
-
-      sbus_writeb(bits_or, base + BPP_OR);
-      sbus_writeb(bits_tcr, base + BPP_TCR);
-}
-
-/*
- * i386 people read output pins from a software image.
- * We may get them back from hardware.
- * Again, inversion of pins must he buried here.
- */
-static unsigned short get_pins(unsigned minor)
-{
-      void __iomem *base = base_addrs[minor];
-      unsigned short bits = 0;
-      unsigned value_tcr = sbus_readb(base + BPP_TCR);
-      unsigned value_ir = sbus_readb(base + BPP_IR);
-      unsigned value_or = sbus_readb(base + BPP_OR);
-
-      if (value_tcr & P_TCR_DS)         bits |= BPP_PP_nStrobe;
-      if (value_or & P_OR_AFXN)         bits |= BPP_PP_nAutoFd;
-      if (! (value_or & P_OR_INIT))     bits |= BPP_PP_nInit;
-      if (! (value_or & P_OR_SLCT_IN))  bits |= BPP_PP_nSelectIn;
-
-      if (value_ir & P_IR_ERR)          bits |= BPP_GP_nFault;
-      if (! (value_ir & P_IR_SLCT))     bits |= BPP_GP_Select;
-      if (! (value_ir & P_IR_PE))       bits |= BPP_GP_PError;
-      if (! (value_tcr & P_TCR_ACK))    bits |= BPP_GP_nAck;
-      if (value_tcr & P_TCR_BUSY)       bits |= BPP_GP_Busy;
-
-      return bits;
-}
-
-#endif /* __sparc__ */
-
-static void snooze(unsigned long snooze_time, unsigned minor)
-{
-	schedule_timeout_uninterruptible(snooze_time + 1);
-}
-
-static int wait_for(unsigned short set, unsigned short clr,
-               unsigned long delay, unsigned minor)
-{
-      unsigned short pins = get_pins(minor);
-
-      unsigned long extime = 0;
-
-      /*
-       * Try a real fast scan for the first jiffy, in case the device
-       * responds real good. The first while loop guesses an expire
-       * time accounting for possible wraparound of jiffies.
-       */
-      while (time_after_eq(jiffies, extime)) extime = jiffies + 1;
-      while ( (time_before(jiffies, extime))
-              && (((pins & set) != set) || ((pins & clr) != 0)) ) {
-            pins = get_pins(minor);
-      }
-
-      delay -= 1;
-
-      /*
-       * If my delay expired or the pins are still not where I want
-       * them, then resort to using the timer and greatly reduce my
-       * sample rate. If the peripheral is going to be slow, this will
-       * give the CPU up to some more worthy process.
-       */
-      while ( delay && (((pins & set) != set) || ((pins & clr) != 0)) ) {
-
-            snooze(1, minor);
-            pins = get_pins(minor);
-            delay -= 1;
-      }
-
-      if (delay == 0) return -1;
-      else return pins;
-}
-
-/*
- * Return ZERO(0) If the negotiation succeeds, an errno otherwise. An
- * errno means something broke, and I do not yet know how to fix it.
- */
-static int negotiate(unsigned char mode, unsigned minor)
-{
-      int rc;
-      unsigned short pins = get_pins(minor);
-      if (pins & BPP_PP_nSelectIn) return -EIO;
-
-
-        /* Event 0: Write the mode to the data lines */
-      bpp_outb_p(mode, base_addrs[minor]);
-
-      snooze(TIME_PSetup, minor);
-
-        /* Event 1: Strobe the mode code into the peripheral */
-      set_pins(BPP_PP_nSelectIn|BPP_PP_nStrobe|BPP_PP_nInit, minor);
-
-        /* Wait for Event 2: Peripheral responds as a 1284 device. */
-      rc = wait_for(BPP_GP_PError|BPP_GP_Select|BPP_GP_nFault,
-                BPP_GP_nAck,
-                TIME_PResponse,
-                minor);
-
-      if (rc == -1) return -ETIMEDOUT;
-
-        /* Event 3: latch extensibility request */
-      set_pins(BPP_PP_nSelectIn|BPP_PP_nInit, minor);
-
-        /* ... quick nap while peripheral ponders the byte i'm sending...*/
-      snooze(1, minor);
-
-        /* Event 4: restore strobe, to ACK peripheral's response. */
-      set_pins(BPP_PP_nSelectIn|BPP_PP_nAutoFd|BPP_PP_nStrobe|BPP_PP_nInit, minor);
-
-        /* Wait for Event 6: Peripheral latches response bits */
-      rc = wait_for(BPP_GP_nAck, 0, TIME_PSetup+TIME_PResponse, minor);
-      if (rc == -1) return -EIO;
-
-        /* A 1284 device cannot refuse nibble mode */
-      if (mode == DEFAULT_NIBBLE) return 0;
-
-      if (pins & BPP_GP_Select) return 0;
-
-      return -EPROTONOSUPPORT;
-}
-
-static int terminate(unsigned minor)
-{
-      int rc;
-
-        /* Event 22: Request termination of 1284 mode */
-      set_pins(BPP_PP_nAutoFd|BPP_PP_nStrobe|BPP_PP_nInit, minor);
-
-        /* Wait for Events 23 and 24: ACK termination request. */
-      rc = wait_for(BPP_GP_Busy|BPP_GP_nFault,
-                BPP_GP_nAck,
-                TIME_PSetup+TIME_PResponse,
-                minor);
-
-      instances[minor].direction = 0;
-      instances[minor].mode = COMPATIBILITY;
-
-      if (rc == -1) {
-          return -EIO;
-      }
-
-        /* Event 25: Handshake by lowering nAutoFd */
-      set_pins(BPP_PP_nStrobe|BPP_PP_nInit, minor);
-
-        /* Event 26: Peripheral wiggles lines... */
-
-        /* Event 27: Peripheral sets nAck HIGH to ack handshake */
-      rc = wait_for(BPP_GP_nAck, 0, TIME_PResponse, minor);
-      if (rc == -1) {
-          set_pins(BPP_PP_nAutoFd|BPP_PP_nStrobe|BPP_PP_nInit, minor);
-          return -EIO;
-      }
-
-        /* Event 28: Finish phase by raising nAutoFd */
-      set_pins(BPP_PP_nAutoFd|BPP_PP_nStrobe|BPP_PP_nInit, minor);
-
-      return 0;
-}
-
-static DEFINE_SPINLOCK(bpp_open_lock);
-
-/*
- * Allow only one process to open the device at a time.
- */
-static int bpp_open(struct inode *inode, struct file *f)
-{
-      unsigned minor = iminor(inode);
-      int ret;
-
-      lock_kernel();
-      spin_lock(&bpp_open_lock);
-      ret = 0;
-      if (minor >= BPP_NO) {
-	      ret = -ENODEV;
-      } else {
-	      if (! instances[minor].present) {
-		      ret = -ENODEV;
-	      } else {
-		      if (instances[minor].opened) 
-			      ret = -EBUSY;
-		      else
-			      instances[minor].opened = 1;
-	      }
-      }
-      spin_unlock(&bpp_open_lock);
-      unlock_kernel();
-
-      return ret;
-}
-
-/*
- * When the process closes the device, this method is called to clean
- * up and reset the hardware. Always leave the device in compatibility
- * mode as this is a reasonable place to clean up from messes made by
- * ioctls, or other mayhem.
- */
-static int bpp_release(struct inode *inode, struct file *f)
-{
-      unsigned minor = iminor(inode);
-
-      spin_lock(&bpp_open_lock);
-      instances[minor].opened = 0;
-
-      if (instances[minor].mode != COMPATIBILITY)
-	      terminate(minor);
-
-      spin_unlock(&bpp_open_lock);
-
-      return 0;
-}
-
-static long read_nibble(unsigned minor, char __user *c, unsigned long cnt)
-{
-      unsigned long remaining = cnt;
-      long rc;
-
-      while (remaining > 0) {
-          unsigned char byte = 0;
-          int pins;
-
-          /* Event 7: request nibble */
-          set_pins(BPP_PP_nSelectIn|BPP_PP_nStrobe, minor);
-
-          /* Wait for event 9: Peripher strobes first nibble */
-          pins = wait_for(0, BPP_GP_nAck, TIME_IDLE_LIMIT, minor);
-          if (pins == -1) return -ETIMEDOUT;
-
-          /* Event 10: I handshake nibble */
-          set_pins(BPP_PP_nSelectIn|BPP_PP_nStrobe|BPP_PP_nAutoFd, minor);
-          if (pins & BPP_GP_nFault) byte |= 0x01;
-          if (pins & BPP_GP_Select) byte |= 0x02;
-          if (pins & BPP_GP_PError) byte |= 0x04;
-          if (pins & BPP_GP_Busy)   byte |= 0x08;
-
-          /* Wait for event 11: Peripheral handshakes nibble */
-          rc = wait_for(BPP_GP_nAck, 0, TIME_PResponse, minor);
-
-          /* Event 7: request nibble */
-          set_pins(BPP_PP_nSelectIn|BPP_PP_nStrobe, minor);
-
-          /* Wait for event 9: Peripher strobes first nibble */
-          pins = wait_for(0, BPP_GP_nAck, TIME_PResponse, minor);
-          if (rc == -1) return -ETIMEDOUT;
-
-          /* Event 10: I handshake nibble */
-          set_pins(BPP_PP_nSelectIn|BPP_PP_nStrobe|BPP_PP_nAutoFd, minor);
-          if (pins & BPP_GP_nFault) byte |= 0x10;
-          if (pins & BPP_GP_Select) byte |= 0x20;
-          if (pins & BPP_GP_PError) byte |= 0x40;
-          if (pins & BPP_GP_Busy)   byte |= 0x80;
-
-          if (put_user(byte, c))
-		  return -EFAULT;
-          c += 1;
-          remaining -= 1;
-
-          /* Wait for event 11: Peripheral handshakes nibble */
-          rc = wait_for(BPP_GP_nAck, 0, TIME_PResponse, minor);
-          if (rc == -1) return -EIO;
-      }
-
-      return cnt - remaining;
-}
-
-static long read_ecp(unsigned minor, char __user *c, unsigned long cnt)
-{
-      unsigned long remaining;
-      long rc;
-
-        /* Turn ECP mode from forward to reverse if needed. */
-      if (! instances[minor].direction) {
-          unsigned short pins = get_pins(minor);
-
-            /* Event 38: Turn the bus around */
-          instances[minor].direction = 0x20;
-          pins &= ~BPP_PP_nAutoFd;
-          set_pins(pins, minor);
-
-            /* Event 39: Set pins for reverse mode. */
-          snooze(TIME_PSetup, minor);
-          set_pins(BPP_PP_nStrobe|BPP_PP_nSelectIn, minor);
-
-            /* Wait for event 40: Peripheral ready to be strobed */
-          rc = wait_for(0, BPP_GP_PError, TIME_PResponse, minor);
-          if (rc == -1) return -ETIMEDOUT;
-      }
-
-      remaining = cnt;
-
-      while (remaining > 0) {
-
-            /* If there is a run length for a repeated byte, repeat */
-            /* that byte a few times. */
-          if (instances[minor].run_length && !instances[minor].run_flag) {
-
-              char buffer[128];
-              unsigned idx;
-              unsigned repeat = remaining < instances[minor].run_length
-                                     ? remaining
-                               : instances[minor].run_length;
-
-              for (idx = 0 ;  idx < repeat ;  idx += 1)
-                buffer[idx] = instances[minor].repeat_byte;
-
-              if (copy_to_user(c, buffer, repeat))
-		      return -EFAULT;
-              remaining -= repeat;
-              c += repeat;
-              instances[minor].run_length -= repeat;
-          }
-
-          if (remaining == 0) break;
-
-
-            /* Wait for Event 43: Data active on the bus. */
-          rc = wait_for(0, BPP_GP_nAck, TIME_IDLE_LIMIT, minor);
-          if (rc == -1) break;
-
-          if (rc & BPP_GP_Busy) {
-                /* OK, this is data. read it in. */
-              unsigned char byte = bpp_inb(base_addrs[minor]);
-              if (put_user(byte, c))
-		      return -EFAULT;
-              c += 1;
-              remaining -= 1;
-
-              if (instances[minor].run_flag) {
-                  instances[minor].repeat_byte = byte;
-                  instances[minor].run_flag = 0;
-              }
-
-          } else {
-              unsigned char byte = bpp_inb(base_addrs[minor]);
-              if (byte & 0x80) {
-                  printk("bpp%d: "
-                         "Ignoring ECP channel %u from device.\n",
-                         minor, byte & 0x7f);
-              } else {
-                  instances[minor].run_length = byte;
-                  instances[minor].run_flag = 1;
-              }
-          }
-
-            /* Event 44: I got it. */
-          set_pins(BPP_PP_nStrobe|BPP_PP_nAutoFd|BPP_PP_nSelectIn, minor);
-
-            /* Wait for event 45: peripheral handshake */
-          rc = wait_for(BPP_GP_nAck, 0, TIME_PResponse, minor);
-          if (rc == -1) return -ETIMEDOUT;
-
-             /* Event 46: Finish handshake */
-          set_pins(BPP_PP_nStrobe|BPP_PP_nSelectIn, minor);
-
-      }
-
-
-      return cnt - remaining;
-}
-
-static ssize_t bpp_read(struct file *f, char __user *c, size_t cnt, loff_t * ppos)
-{
-      long rc;
-      unsigned minor = iminor(f->f_path.dentry->d_inode);
-      if (minor >= BPP_NO) return -ENODEV;
-      if (!instances[minor].present) return -ENODEV;
-
-      switch (instances[minor].mode) {
-
-        default:
-          if (instances[minor].mode != COMPATIBILITY)
-            terminate(minor);
-
-          if (instances[minor].enhanced) {
-              /* For now, do all reads with ECP-RLE mode */
-              unsigned short pins;
-
-              rc = negotiate(DEFAULT_ECP, minor);
-              if (rc < 0) break;
-
-              instances[minor].mode = ECP_RLE;
-
-              /* Event 30: set nAutoFd low to setup for ECP mode */
-              pins = get_pins(minor);
-              pins &= ~BPP_PP_nAutoFd;
-              set_pins(pins, minor);
-
-              /* Wait for Event 31: peripheral ready */
-              rc = wait_for(BPP_GP_PError, 0, TIME_PResponse, minor);
-              if (rc == -1) return -ETIMEDOUT;
-
-              rc = read_ecp(minor, c, cnt);
-
-          } else {
-              rc = negotiate(DEFAULT_NIBBLE, minor);
-              if (rc < 0) break;
-
-              instances[minor].mode = NIBBLE;
-
-              rc = read_nibble(minor, c, cnt);
-          }
-          break;
-
-        case NIBBLE:
-          rc = read_nibble(minor, c, cnt);
-          break;
-
-        case ECP:
-        case ECP_RLE:
-          rc = read_ecp(minor, c, cnt);
-          break;
-
-      }
-
-
-      return rc;
-}
-
-/*
- * Compatibility mode handshaking is a matter of writing data,
- * strobing it, and waiting for the printer to stop being busy.
- */
-static long write_compat(unsigned minor, const char __user *c, unsigned long cnt)
-{
-      long rc;
-      unsigned short pins = get_pins(minor);
-
-      unsigned long remaining = cnt;
-
-
-      while (remaining > 0) {
-            unsigned char byte;
-
-            if (get_user(byte, c))
-		    return -EFAULT;
-            c += 1;
-
-            rc = wait_for(BPP_GP_nAck, BPP_GP_Busy, TIME_IDLE_LIMIT, minor);
-            if (rc == -1) return -ETIMEDOUT;
-
-            bpp_outb_p(byte, base_addrs[minor]);
-            remaining -= 1;
-          /* snooze(1, minor); */
-
-          pins &= ~BPP_PP_nStrobe;
-          set_pins(pins, minor);
-
-          rc = wait_for(BPP_GP_Busy, 0, TIME_PResponse, minor);
-
-          pins |= BPP_PP_nStrobe;
-          set_pins(pins, minor);
-      }
-
-      return cnt - remaining;
-}
-
-/*
- * Write data using ECP mode. Watch out that the port may be set up
- * for reading. If so, turn the port around.
- */
-static long write_ecp(unsigned minor, const char __user *c, unsigned long cnt)
-{
-      unsigned short pins = get_pins(minor);
-      unsigned long remaining = cnt;
-
-      if (instances[minor].direction) {
-          int rc;
-
-            /* Event 47 Request bus be turned around */
-          pins |= BPP_PP_nInit;
-          set_pins(pins, minor);
-
-            /* Wait for Event 49: Peripheral relinquished bus */
-          rc = wait_for(BPP_GP_PError, 0, TIME_PResponse, minor);
-
-          pins |= BPP_PP_nAutoFd;
-          instances[minor].direction = 0;
-          set_pins(pins, minor);
-      }
-
-      while (remaining > 0) {
-          unsigned char byte;
-          int rc;
-
-          if (get_user(byte, c))
-		  return -EFAULT;
-
-          rc = wait_for(0, BPP_GP_Busy, TIME_PResponse, minor);
-          if (rc == -1) return -ETIMEDOUT;
-
-          c += 1;
-
-          bpp_outb_p(byte, base_addrs[minor]);
-
-          pins &= ~BPP_PP_nStrobe;
-          set_pins(pins, minor);
-
-          pins |= BPP_PP_nStrobe;
-          rc = wait_for(BPP_GP_Busy, 0, TIME_PResponse, minor);
-          if (rc == -1) return -EIO;
-
-          set_pins(pins, minor);
-      }
-
-      return cnt - remaining;
-}
-
-/*
- * Write to the peripheral. Be sensitive of the current mode. If I'm
- * in a mode that can be turned around (ECP) then just do
- * that. Otherwise, terminate and do my writing in compat mode. This
- * is the safest course as any device can handle it.
- */
-static ssize_t bpp_write(struct file *f, const char __user *c, size_t cnt, loff_t * ppos)
-{
-      long errno = 0;
-      unsigned minor = iminor(f->f_path.dentry->d_inode);
-      if (minor >= BPP_NO) return -ENODEV;
-      if (!instances[minor].present) return -ENODEV;
-
-      switch (instances[minor].mode) {
-
-        case ECP:
-        case ECP_RLE:
-          errno = write_ecp(minor, c, cnt);
-          break;
-        case COMPATIBILITY:
-          errno = write_compat(minor, c, cnt);
-          break;
-        default:
-          terminate(minor);
-          errno = write_compat(minor, c, cnt);
-      }
-
-      return errno;
-}
-
-static int bpp_ioctl(struct inode *inode, struct file *f, unsigned int cmd,
-		 unsigned long arg)
-{
-      int errno = 0;
-
-      unsigned minor = iminor(inode);
-      if (minor >= BPP_NO) return -ENODEV;
-      if (!instances[minor].present) return -ENODEV;
-
-
-      switch (cmd) {
-
-        case BPP_PUT_PINS:
-          set_pins(arg, minor);
-          break;
-
-        case BPP_GET_PINS:
-          errno = get_pins(minor);
-          break;
-
-        case BPP_PUT_DATA:
-          bpp_outb_p(arg, base_addrs[minor]);
-          break;
-
-        case BPP_GET_DATA:
-          errno = bpp_inb_p(base_addrs[minor]);
-          break;
-
-        case BPP_SET_INPUT:
-          if (arg)
-            if (instances[minor].enhanced) {
-                unsigned short bits = get_pins(minor);
-                instances[minor].direction = 0x20;
-                set_pins(bits, minor);
-            } else {
-                errno = -ENOTTY;
-            }
-          else {
-              unsigned short bits = get_pins(minor);
-              instances[minor].direction = 0x00;
-              set_pins(bits, minor);
-          }
-          break;
-
-        default:
-            errno = -EINVAL;
-      }
-
-      return errno;
-}
-
-static const struct file_operations bpp_fops = {
-	.owner =	THIS_MODULE,
-	.read =		bpp_read,
-	.write =	bpp_write,
-	.ioctl =	bpp_ioctl,
-	.open =		bpp_open,
-	.release =	bpp_release,
-};
-
-#if defined(__i386__)
-
-#define collectLptPorts()  {}
-
-static void probeLptPort(unsigned idx)
-{
-      unsigned int testvalue;
-      const unsigned short lpAddr = base_addrs[idx];
-
-      instances[idx].present = 0;
-      instances[idx].enhanced = 0;
-      instances[idx].direction = 0;
-      instances[idx].mode = COMPATIBILITY;
-      instances[idx].run_length = 0;
-      instances[idx].run_flag = 0;
-      if (!request_region(lpAddr,3, bpp_dev_name)) return;
-
-      /*
-       * First, make sure the instance exists. Do this by writing to
-       * the data latch and reading the value back. If the port *is*
-       * present, test to see if it supports extended-mode
-       * operation. This will be required for IEEE1284 reverse
-       * transfers.
-       */
-
-      outb_p(BPP_PROBE_CODE, lpAddr);
-      for (testvalue=0; testvalue<BPP_DELAY; testvalue++)
-            ;
-      testvalue = inb_p(lpAddr);
-      if (testvalue == BPP_PROBE_CODE) {
-            unsigned save;
-            instances[idx].present = 1;
-
-            save = inb_p(lpAddr+2);
-            for (testvalue=0; testvalue<BPP_DELAY; testvalue++)
-                  ;
-            outb_p(save|0x20, lpAddr+2);
-            for (testvalue=0; testvalue<BPP_DELAY; testvalue++)
-                  ;
-            outb_p(~BPP_PROBE_CODE, lpAddr);
-            for (testvalue=0; testvalue<BPP_DELAY; testvalue++)
-                  ;
-            testvalue = inb_p(lpAddr);
-            if ((testvalue&0xff) == (0xff&~BPP_PROBE_CODE))
-                  instances[idx].enhanced = 0;
-            else
-                  instances[idx].enhanced = 1;
-            outb_p(save, lpAddr+2);
-      }
-      else {
-            release_region(lpAddr,3);
-      }
-      /*
-       * Leave the port in compat idle mode.
-       */
-      set_pins(BPP_PP_nAutoFd|BPP_PP_nStrobe|BPP_PP_nInit, idx);
-
-      printk("bpp%d: Port at 0x%03x: Enhanced mode %s\n", idx, base_addrs[idx],
-            instances[idx].enhanced? "SUPPORTED" : "UNAVAILABLE");
-}
-
-static inline void freeLptPort(int idx)
-{
-      release_region(base_addrs[idx], 3);
-}
-
-#endif
-
-#if defined(__sparc__)
-
-static void __iomem *map_bpp(struct sbus_dev *dev, int idx)
-{
-      return sbus_ioremap(&dev->resource[0], 0, BPP_SIZE, "bpp");
-}
-
-static int collectLptPorts(void)
-{
-	struct sbus_bus *bus;
-	struct sbus_dev *dev;
-	int count;
-
-	count = 0;
-	for_all_sbusdev(dev, bus) {
-		if (strcmp(dev->prom_name, "SUNW,bpp") == 0) {
-			if (count >= BPP_NO) {
-				printk(KERN_NOTICE
-				       "bpp: More than %d bpp ports,"
-				       " rest is ignored\n", BPP_NO);
-				return count;
-			}
-			base_addrs[count] = map_bpp(dev, count);
-			count++;
-		}
-	}
-	return count;
-}
-
-static void probeLptPort(unsigned idx)
-{
-      void __iomem *rp = base_addrs[idx];
-      __u32 csr;
-      char *brand;
-
-      instances[idx].present = 0;
-      instances[idx].enhanced = 0;
-      instances[idx].direction = 0;
-      instances[idx].mode = COMPATIBILITY;
-      instances[idx].run_length = 0;
-      instances[idx].run_flag = 0;
-
-      if (!rp) return;
-
-      instances[idx].present = 1;
-      instances[idx].enhanced = 1;   /* Sure */
-
-      csr = sbus_readl(rp + BPP_CSR);
-      if ((csr & P_DRAINING) != 0 && (csr & P_ERR_PEND) == 0) {
-            udelay(20);
-            csr = sbus_readl(rp + BPP_CSR);
-            if ((csr & P_DRAINING) != 0 && (csr & P_ERR_PEND) == 0) {
-                  printk("bpp%d: DRAINING still active (0x%08x)\n", idx, csr);
-            }
-      }
-      printk("bpp%d: reset with 0x%08x ..", idx, csr);
-      sbus_writel((csr | P_RESET) & ~P_INT_EN, rp + BPP_CSR);
-      udelay(500);
-      sbus_writel(sbus_readl(rp + BPP_CSR) & ~P_RESET, rp + BPP_CSR);
-      csr = sbus_readl(rp + BPP_CSR);
-      printk(" done with csr=0x%08x ocr=0x%04x\n",
-         csr, sbus_readw(rp + BPP_OCR));
-
-      switch (csr & P_DEV_ID_MASK) {
-      case P_DEV_ID_ZEBRA:
-            brand = "Zebra";
-            break;
-      case P_DEV_ID_L64854:
-            brand = "DMA2";
-            break;
-      default:
-            brand = "Unknown";
-      }
-      printk("bpp%d: %s at %p\n", idx, brand, rp);
-
-      /*
-       * Leave the port in compat idle mode.
-       */
-      set_pins(BPP_PP_nAutoFd|BPP_PP_nStrobe|BPP_PP_nInit, idx);
-
-      return;
-}
-
-static inline void freeLptPort(int idx)
-{
-      sbus_iounmap(base_addrs[idx], BPP_SIZE);
-}
-
-#endif
-
-static int __init bpp_init(void)
-{
-	int rc;
-	unsigned idx;
-
-	rc = collectLptPorts();
-	if (rc == 0)
-		return -ENODEV;
-
-	rc = register_chrdev(BPP_MAJOR, bpp_dev_name, &bpp_fops);
-	if (rc < 0)
-		return rc;
-
-	for (idx = 0; idx < BPP_NO; idx++) {
-		instances[idx].opened = 0;
-		probeLptPort(idx);
-	}
-
-	return 0;
-}
-
-static void __exit bpp_cleanup(void)
-{
-	unsigned idx;
-
-	unregister_chrdev(BPP_MAJOR, bpp_dev_name);
-
-	for (idx = 0;  idx < BPP_NO; idx++) {
-		if (instances[idx].present)
-			freeLptPort(idx);
-	}
-}
-
-module_init(bpp_init);
-module_exit(bpp_cleanup);
-
-MODULE_LICENSE("GPL");
-
diff --git a/drivers/sbus/char/cpwatchdog.c b/drivers/sbus/char/cpwatchdog.c
deleted file mode 100644
index 23abfdf..0000000
--- a/drivers/sbus/char/cpwatchdog.c
+++ /dev/null
@@ -1,858 +0,0 @@
-/* cpwatchdog.c - driver implementation for hardware watchdog
- * timers found on Sun Microsystems CP1400 and CP1500 boards.
- *
- * This device supports both the generic Linux watchdog 
- * interface and Solaris-compatible ioctls as best it is
- * able.
- *
- * NOTE: 	CP1400 systems appear to have a defective intr_mask
- * 			register on the PLD, preventing the disabling of
- * 			timer interrupts.  We use a timer to periodically 
- * 			reset 'stopped' watchdogs on affected platforms.
- *
- * Copyright (c) 2000 Eric Brower (ebrower@usa.net)
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/fs.h>
-#include <linux/errno.h>
-#include <linux/major.h>
-#include <linux/init.h>
-#include <linux/miscdevice.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/timer.h>
-#include <linux/smp_lock.h>
-#include <linux/io.h>
-#include <asm/irq.h>
-#include <asm/ebus.h>
-#include <asm/oplib.h>
-#include <asm/uaccess.h>
-
-#include <asm/watchdog.h>
-
-#define WD_OBPNAME	"watchdog"
-#define WD_BADMODEL "SUNW,501-5336"
-#define WD_BTIMEOUT	(jiffies + (HZ * 1000))
-#define WD_BLIMIT	0xFFFF
-
-#define WD0_DEVNAME "watchdog0"
-#define WD1_DEVNAME "watchdog1"
-#define WD2_DEVNAME "watchdog2"
-
-#define WD0_MINOR	212
-#define WD1_MINOR	213	
-#define WD2_MINOR	214	
-
-
-/* Internal driver definitions
- */
-#define WD0_ID			0		/* Watchdog0						*/
-#define WD1_ID			1		/* Watchdog1						*/
-#define WD2_ID			2		/* Watchdog2						*/
-#define WD_NUMDEVS		3		/* Device contains 3 timers			*/
-
-#define WD_INTR_OFF		0		/* Interrupt disable value			*/
-#define WD_INTR_ON		1		/* Interrupt enable value			*/
-
-#define WD_STAT_INIT	0x01	/* Watchdog timer is initialized	*/
-#define WD_STAT_BSTOP	0x02	/* Watchdog timer is brokenstopped	*/
-#define WD_STAT_SVCD	0x04	/* Watchdog interrupt occurred		*/
-
-/* Register value definitions
- */
-#define WD0_INTR_MASK	0x01	/* Watchdog device interrupt masks	*/
-#define WD1_INTR_MASK	0x02
-#define WD2_INTR_MASK	0x04
-
-#define WD_S_RUNNING	0x01	/* Watchdog device status running	*/
-#define WD_S_EXPIRED	0x02	/* Watchdog device status expired	*/
-
-/* Sun uses Altera PLD EPF8820ATC144-4 
- * providing three hardware watchdogs:
- *
- * 	1) RIC - sends an interrupt when triggered
- * 	2) XIR - asserts XIR_B_RESET when triggered, resets CPU
- * 	3) POR - asserts POR_B_RESET when triggered, resets CPU, backplane, board
- *
- *** Timer register block definition (struct wd_timer_regblk)
- *
- * dcntr and limit registers (halfword access):      
- * -------------------
- * | 15 | ...| 1 | 0 |
- * -------------------
- * |-  counter val  -|
- * -------------------
- * dcntr - 	Current 16-bit downcounter value.
- * 			When downcounter reaches '0' watchdog expires.
- * 			Reading this register resets downcounter with 'limit' value.
- * limit - 	16-bit countdown value in 1/10th second increments.
- * 			Writing this register begins countdown with input value.
- * 			Reading from this register does not affect counter.
- * NOTES:	After watchdog reset, dcntr and limit contain '1'
- *
- * status register (byte access):
- * ---------------------------
- * | 7 | ... | 2 |  1  |  0  |
- * --------------+------------
- * |-   UNUSED  -| EXP | RUN |
- * ---------------------------
- * status-	Bit 0 - Watchdog is running
- * 			Bit 1 - Watchdog has expired
- *
- *** PLD register block definition (struct wd_pld_regblk)
- *
- * intr_mask register (byte access):
- * ---------------------------------
- * | 7 | ... | 3 |  2  |  1  |  0  |
- * +-------------+------------------
- * |-   UNUSED  -| WD3 | WD2 | WD1 |
- * ---------------------------------
- * WD3 -  1 == Interrupt disabled for watchdog 3
- * WD2 -  1 == Interrupt disabled for watchdog 2
- * WD1 -  1 == Interrupt disabled for watchdog 1
- *
- * pld_status register (byte access):
- * UNKNOWN, MAGICAL MYSTERY REGISTER
- *
- */
-#define WD_TIMER_REGSZ	16
-#define WD0_OFF		0
-#define WD1_OFF		(WD_TIMER_REGSZ * 1)
-#define WD2_OFF		(WD_TIMER_REGSZ * 2)
-#define PLD_OFF		(WD_TIMER_REGSZ * 3)
-
-#define WD_DCNTR	0x00
-#define WD_LIMIT	0x04
-#define WD_STATUS	0x08
-
-#define PLD_IMASK	(PLD_OFF + 0x00)
-#define PLD_STATUS	(PLD_OFF + 0x04)
-
-/* Individual timer structure 
- */
-struct wd_timer {
-	__u16			timeout;
-	__u8			intr_mask;
-	unsigned char		runstatus;
-	void __iomem		*regs;
-};
-
-/* Device structure
- */
-struct wd_device {
-	int				irq;
-	spinlock_t		lock;
-	unsigned char	isbaddoggie;	/* defective PLD */
-	unsigned char	opt_enable;
-	unsigned char	opt_reboot;
-	unsigned short	opt_timeout;
-	unsigned char	initialized;
-	struct wd_timer	watchdog[WD_NUMDEVS];
-	void __iomem	*regs;
-};
-
-static struct wd_device wd_dev = { 
-		0, __SPIN_LOCK_UNLOCKED(wd_dev.lock), 0, 0, 0, 0,
-};
-
-static struct timer_list wd_timer;
-
-static int wd0_timeout = 0;
-static int wd1_timeout = 0;
-static int wd2_timeout = 0;
-
-#ifdef MODULE
-module_param	(wd0_timeout, int, 0);
-MODULE_PARM_DESC(wd0_timeout, "Default watchdog0 timeout in 1/10secs");
-module_param 	(wd1_timeout, int, 0);
-MODULE_PARM_DESC(wd1_timeout, "Default watchdog1 timeout in 1/10secs");
-module_param 	(wd2_timeout, int, 0);
-MODULE_PARM_DESC(wd2_timeout, "Default watchdog2 timeout in 1/10secs");
-
-MODULE_AUTHOR
-	("Eric Brower <ebrower@usa.net>");
-MODULE_DESCRIPTION
-	("Hardware watchdog driver for Sun Microsystems CP1400/1500");
-MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE
-	("watchdog");
-#endif /* ifdef MODULE */
-
-/* Forward declarations of internal methods
- */
-#ifdef WD_DEBUG
-static void wd_dumpregs(void);
-#endif
-static irqreturn_t wd_interrupt(int irq, void *dev_id);
-static void wd_toggleintr(struct wd_timer* pTimer, int enable);
-static void wd_pingtimer(struct wd_timer* pTimer);
-static void wd_starttimer(struct wd_timer* pTimer);
-static void wd_resetbrokentimer(struct wd_timer* pTimer);
-static void wd_stoptimer(struct wd_timer* pTimer);
-static void wd_brokentimer(unsigned long data);
-static int  wd_getstatus(struct wd_timer* pTimer);
-
-/* PLD expects words to be written in LSB format,
- * so we must flip all words prior to writing them to regs
- */
-static inline unsigned short flip_word(unsigned short word)
-{
-	return ((word & 0xff) << 8) | ((word >> 8) & 0xff);
-}
-
-#define wd_writew(val, addr) 	(writew(flip_word(val), addr))
-#define wd_readw(addr) 			(flip_word(readw(addr)))
-#define wd_writeb(val, addr) 	(writeb(val, addr))
-#define wd_readb(addr) 			(readb(addr))
-
-
-/* CP1400s seem to have broken PLD implementations--
- * the interrupt_mask register cannot be written, so
- * no timer interrupts can be masked within the PLD.
- */
-static inline int wd_isbroken(void)
-{
-	/* we could test this by read/write/read/restore
-	 * on the interrupt mask register only if OBP
-	 * 'watchdog-enable?' == FALSE, but it seems 
-	 * ubiquitous on CP1400s
-	 */
-	char val[32];
-	prom_getproperty(prom_root_node, "model", val, sizeof(val));
-	return((!strcmp(val, WD_BADMODEL)) ? 1 : 0);
-}
-		
-/* Retrieve watchdog-enable? option from OBP
- * Returns 0 if false, 1 if true
- */
-static inline int wd_opt_enable(void)
-{
-	int opt_node;
-
-	opt_node = prom_getchild(prom_root_node);
-	opt_node = prom_searchsiblings(opt_node, "options");
-	return((-1 == prom_getint(opt_node, "watchdog-enable?")) ? 0 : 1);
-}
-
-/* Retrieve watchdog-reboot? option from OBP
- * Returns 0 if false, 1 if true
- */
-static inline int wd_opt_reboot(void)
-{
-	int opt_node;
-
-	opt_node = prom_getchild(prom_root_node);
-	opt_node = prom_searchsiblings(opt_node, "options");
-	return((-1 == prom_getint(opt_node, "watchdog-reboot?")) ? 0 : 1);
-}
-
-/* Retrieve watchdog-timeout option from OBP
- * Returns OBP value, or 0 if not located
- */
-static inline int wd_opt_timeout(void)
-{
-	int opt_node;
-	char value[32];
-	char *p = value;
-
-	opt_node = prom_getchild(prom_root_node);
-	opt_node = prom_searchsiblings(opt_node, "options");
-	opt_node = prom_getproperty(opt_node, 
-								"watchdog-timeout", 
-								value, 
-								sizeof(value));
-	if(-1 != opt_node) {
-		/* atoi implementation */
-		for(opt_node = 0; /* nop */; p++) {
-			if(*p >= '0' && *p <= '9') {
-				opt_node = (10*opt_node)+(*p-'0');
-			}
-			else {
-				break;
-			}
-		}
-	}
-	return((-1 == opt_node) ? (0) : (opt_node)); 
-}
-
-static int wd_open(struct inode *inode, struct file *f)
-{
-	lock_kernel();
-	switch(iminor(inode))
-	{
-		case WD0_MINOR:
-			f->private_data = &wd_dev.watchdog[WD0_ID];
-			break;
-		case WD1_MINOR:
-			f->private_data = &wd_dev.watchdog[WD1_ID];
-			break;
-		case WD2_MINOR:
-			f->private_data = &wd_dev.watchdog[WD2_ID];
-			break;
-		default:
-			unlock_kernel();
-			return(-ENODEV);
-	}
-
-	/* Register IRQ on first open of device */
-	if(0 == wd_dev.initialized)
-	{	
-		if (request_irq(wd_dev.irq, 
-						&wd_interrupt, 
-						IRQF_SHARED,
-						WD_OBPNAME,
-						(void *)wd_dev.regs)) {
-			printk("%s: Cannot register IRQ %d\n", 
-				WD_OBPNAME, wd_dev.irq);
-			unlock_kernel();
-			return(-EBUSY);
-		}
-		wd_dev.initialized = 1;
-	}
-
-	unlock_kernel();
-	return(nonseekable_open(inode, f));
-}
-
-static int wd_release(struct inode *inode, struct file *file)
-{
-	return 0;
-}
-
-static int wd_ioctl(struct inode *inode, struct file *file, 
-		     unsigned int cmd, unsigned long arg)
-{
-	int 	setopt 				= 0;
-	struct 	wd_timer* pTimer 	= (struct wd_timer*)file->private_data;
-	void __user *argp = (void __user *)arg;
-	struct 	watchdog_info info 	= {
-		0,
-		0,
-		"Altera EPF8820ATC144-4"
-	};
-
-	if(NULL == pTimer) {
-		return(-EINVAL);
-	}
-
-	switch(cmd)
-	{
-		/* Generic Linux IOCTLs */
-		case WDIOC_GETSUPPORT:
-			if(copy_to_user(argp, &info, sizeof(struct watchdog_info))) {
-				return(-EFAULT);
-			}
-			break;
-		case WDIOC_GETSTATUS:
-		case WDIOC_GETBOOTSTATUS:
-			if (put_user(0, (int __user *)argp))
-				return -EFAULT;
-			break;
-		case WDIOC_KEEPALIVE:
-			wd_pingtimer(pTimer);
-			break;
-		case WDIOC_SETOPTIONS:
-			if(copy_from_user(&setopt, argp, sizeof(unsigned int))) {
-				return -EFAULT;
-			}
-			if(setopt & WDIOS_DISABLECARD) {
-				if(wd_dev.opt_enable) {
-					printk(
-						"%s: cannot disable watchdog in ENABLED mode\n",
-						WD_OBPNAME);
-					return(-EINVAL);
-				}
-				wd_stoptimer(pTimer);
-			}
-			else if(setopt & WDIOS_ENABLECARD) {
-				wd_starttimer(pTimer);
-			}
-			else {
-				return(-EINVAL);
-			}	
-			break;
-		/* Solaris-compatible IOCTLs */
-		case WIOCGSTAT:
-			setopt = wd_getstatus(pTimer);
-			if(copy_to_user(argp, &setopt, sizeof(unsigned int))) {
-				return(-EFAULT);
-			}
-			break;
-		case WIOCSTART:
-			wd_starttimer(pTimer);
-			break;
-		case WIOCSTOP:
-			if(wd_dev.opt_enable) {
-				printk("%s: cannot disable watchdog in ENABLED mode\n",
-					WD_OBPNAME);
-				return(-EINVAL);
-			}
-			wd_stoptimer(pTimer);
-			break;
-		default:
-			return(-EINVAL);
-	}
-	return(0);
-}
-
-static long wd_compat_ioctl(struct file *file, unsigned int cmd,
-		unsigned long arg)
-{
-	int rval = -ENOIOCTLCMD;
-
-	switch (cmd) {
-	/* solaris ioctls are specific to this driver */
-	case WIOCSTART:
-	case WIOCSTOP:
-	case WIOCGSTAT:
-		lock_kernel();
-		rval = wd_ioctl(file->f_path.dentry->d_inode, file, cmd, arg);
-		unlock_kernel();
-		break;
-	/* everything else is handled by the generic compat layer */
-	default:
-		break;
-	}
-
-	return rval;
-}
-
-static ssize_t wd_write(struct file 	*file, 
-			const char	__user *buf, 
-			size_t 		count, 
-			loff_t 		*ppos)
-{
-	struct wd_timer* pTimer = (struct wd_timer*)file->private_data;
-
-	if(NULL == pTimer) {
-		return(-EINVAL);
-	}
-
-	if (count) {
-		wd_pingtimer(pTimer);
-		return 1;
-	}
-	return 0;
-}
-
-static ssize_t wd_read(struct file * file, char __user *buffer,
-		        size_t count, loff_t *ppos)
-{
-#ifdef WD_DEBUG
-	wd_dumpregs();
-	return(0);
-#else
-	return(-EINVAL);
-#endif /* ifdef WD_DEBUG */
-}
-
-static irqreturn_t wd_interrupt(int irq, void *dev_id)
-{
-	/* Only WD0 will interrupt-- others are NMI and we won't
-	 * see them here....
-	 */
-	spin_lock_irq(&wd_dev.lock);
-	if((unsigned long)wd_dev.regs == (unsigned long)dev_id)
-	{
-		wd_stoptimer(&wd_dev.watchdog[WD0_ID]);
-		wd_dev.watchdog[WD0_ID].runstatus |=  WD_STAT_SVCD;
-	}
-	spin_unlock_irq(&wd_dev.lock);
-	return IRQ_HANDLED;
-}
-
-static const struct file_operations wd_fops = {
-	.owner =	THIS_MODULE,
-	.ioctl =	wd_ioctl,
-	.compat_ioctl =	wd_compat_ioctl,
-	.open =		wd_open,
-	.write =	wd_write,
-	.read =		wd_read,
-	.release =	wd_release,
-};
-
-static struct miscdevice wd0_miscdev = { WD0_MINOR, WD0_DEVNAME, &wd_fops };
-static struct miscdevice wd1_miscdev = { WD1_MINOR, WD1_DEVNAME, &wd_fops };
-static struct miscdevice wd2_miscdev = { WD2_MINOR, WD2_DEVNAME, &wd_fops };
-
-#ifdef WD_DEBUG
-static void wd_dumpregs(void)
-{
-	/* Reading from downcounters initiates watchdog countdown--
-	 * Example is included below for illustration purposes.
-	 */
-	int i;
-	printk("%s: dumping register values\n", WD_OBPNAME);
-	for(i = WD0_ID; i < WD_NUMDEVS; ++i) {
-			/* printk("\t%s%i: dcntr  at 0x%lx: 0x%x\n", 
-			 * 	WD_OBPNAME,
-		 	 *	i,
-			 *	(unsigned long)(&wd_dev.watchdog[i].regs->dcntr), 
-			 *	readw(&wd_dev.watchdog[i].regs->dcntr));
-			 */
-			printk("\t%s%i: limit  at 0x%lx: 0x%x\n", 
-				WD_OBPNAME,
-				i,
-				(unsigned long)(&wd_dev.watchdog[i].regs->limit), 
-				readw(&wd_dev.watchdog[i].regs->limit));
-			printk("\t%s%i: status at 0x%lx: 0x%x\n", 
-				WD_OBPNAME,
-				i,
-				(unsigned long)(&wd_dev.watchdog[i].regs->status), 
-				readb(&wd_dev.watchdog[i].regs->status));
-			printk("\t%s%i: driver status: 0x%x\n",
-				WD_OBPNAME,
-				i,
-				wd_getstatus(&wd_dev.watchdog[i]));
-	}
-	printk("\tintr_mask  at %p: 0x%x\n", 
-		wd_dev.regs + PLD_IMASK,
-		readb(wd_dev.regs + PLD_IMASK));
-	printk("\tpld_status at %p: 0x%x\n", 
-		wd_dev.regs + PLD_STATUS, 
-		readb(wd_dev.regs + PLD_STATUS));
-}
-#endif
-
-/* Enable or disable watchdog interrupts
- * Because of the CP1400 defect this should only be
- * called during initialzation or by wd_[start|stop]timer()
- *
- * pTimer 	- pointer to timer device, or NULL to indicate all timers 
- * enable	- non-zero to enable interrupts, zero to disable
- */
-static void wd_toggleintr(struct wd_timer* pTimer, int enable)
-{
-	unsigned char curregs = wd_readb(wd_dev.regs + PLD_IMASK);
-	unsigned char setregs = 
-		(NULL == pTimer) ? 
-			(WD0_INTR_MASK | WD1_INTR_MASK | WD2_INTR_MASK) : 
-			(pTimer->intr_mask);
-
-	(WD_INTR_ON == enable) ?
-		(curregs &= ~setregs):
-		(curregs |=  setregs);
-
-	wd_writeb(curregs, wd_dev.regs + PLD_IMASK);
-	return;
-}
-
-/* Reset countdown timer with 'limit' value and continue countdown.
- * This will not start a stopped timer.
- *
- * pTimer	- pointer to timer device
- */
-static void wd_pingtimer(struct wd_timer* pTimer)
-{
-	if (wd_readb(pTimer->regs + WD_STATUS) & WD_S_RUNNING) {
-		wd_readw(pTimer->regs + WD_DCNTR);
-	}
-}
-
-/* Stop a running watchdog timer-- the timer actually keeps
- * running, but the interrupt is masked so that no action is
- * taken upon expiration.
- *
- * pTimer	- pointer to timer device
- */
-static void wd_stoptimer(struct wd_timer* pTimer)
-{
-	if(wd_readb(pTimer->regs + WD_STATUS) & WD_S_RUNNING) {
-		wd_toggleintr(pTimer, WD_INTR_OFF);
-
-		if(wd_dev.isbaddoggie) {
-			pTimer->runstatus |= WD_STAT_BSTOP;
-			wd_brokentimer((unsigned long)&wd_dev);
-		}
-	}
-}
-
-/* Start a watchdog timer with the specified limit value
- * If the watchdog is running, it will be restarted with
- * the provided limit value.
- *
- * This function will enable interrupts on the specified
- * watchdog.
- *
- * pTimer	- pointer to timer device
- * limit	- limit (countdown) value in 1/10th seconds
- */
-static void wd_starttimer(struct wd_timer* pTimer)
-{
-	if(wd_dev.isbaddoggie) {
-		pTimer->runstatus &= ~WD_STAT_BSTOP;
-	}
-	pTimer->runstatus &= ~WD_STAT_SVCD;
-
-	wd_writew(pTimer->timeout, pTimer->regs + WD_LIMIT);
-	wd_toggleintr(pTimer, WD_INTR_ON);
-}
-
-/* Restarts timer with maximum limit value and
- * does not unset 'brokenstop' value.
- */
-static void wd_resetbrokentimer(struct wd_timer* pTimer)
-{
-	wd_toggleintr(pTimer, WD_INTR_ON);
-	wd_writew(WD_BLIMIT, pTimer->regs + WD_LIMIT);
-}
-
-/* Timer device initialization helper.
- * Returns 0 on success, other on failure
- */
-static int wd_inittimer(int whichdog)
-{
-	struct miscdevice 				*whichmisc;
-	void __iomem *whichregs;
-	char 							whichident[8];
-	int								whichmask;
-	__u16							whichlimit;
-
-	switch(whichdog)
-	{
-		case WD0_ID:
-			whichmisc = &wd0_miscdev;
-			strcpy(whichident, "RIC");
-			whichregs = wd_dev.regs + WD0_OFF;
-			whichmask = WD0_INTR_MASK;
-			whichlimit= (0 == wd0_timeout) 	? 
-						(wd_dev.opt_timeout): 
-						(wd0_timeout);
-			break;
-		case WD1_ID:
-			whichmisc = &wd1_miscdev;
-			strcpy(whichident, "XIR");
-			whichregs = wd_dev.regs + WD1_OFF;
-			whichmask = WD1_INTR_MASK;
-			whichlimit= (0 == wd1_timeout) 	? 
-						(wd_dev.opt_timeout): 
-						(wd1_timeout);
-			break;
-		case WD2_ID:
-			whichmisc = &wd2_miscdev;
-			strcpy(whichident, "POR");
-			whichregs = wd_dev.regs + WD2_OFF;
-			whichmask = WD2_INTR_MASK;
-			whichlimit= (0 == wd2_timeout) 	? 
-						(wd_dev.opt_timeout): 
-						(wd2_timeout);
-			break;
-		default:
-			printk("%s: %s: invalid watchdog id: %i\n",
-				WD_OBPNAME, __func__, whichdog);
-			return(1);
-	}
-	if(0 != misc_register(whichmisc))
-	{
-		return(1);
-	}
-	wd_dev.watchdog[whichdog].regs			= whichregs;
-	wd_dev.watchdog[whichdog].timeout 		= whichlimit;
-	wd_dev.watchdog[whichdog].intr_mask		= whichmask;
-	wd_dev.watchdog[whichdog].runstatus 	&= ~WD_STAT_BSTOP;
-	wd_dev.watchdog[whichdog].runstatus 	|= WD_STAT_INIT;
-
-	printk("%s%i: %s hardware watchdog [%01i.%i sec] %s\n", 
-		WD_OBPNAME, 
-		whichdog, 
-		whichident, 
-		wd_dev.watchdog[whichdog].timeout / 10,
-		wd_dev.watchdog[whichdog].timeout % 10,
-		(0 != wd_dev.opt_enable) ? "in ENABLED mode" : "");
-	return(0);
-}
-
-/* Timer method called to reset stopped watchdogs--
- * because of the PLD bug on CP1400, we cannot mask
- * interrupts within the PLD so me must continually
- * reset the timers ad infinitum.
- */
-static void wd_brokentimer(unsigned long data)
-{
-	struct wd_device* pDev = (struct wd_device*)data;
-	int id, tripped = 0;
-
-	/* kill a running timer instance, in case we
-	 * were called directly instead of by kernel timer
-	 */
-	if(timer_pending(&wd_timer)) {
-		del_timer(&wd_timer);
-	}
-
-	for(id = WD0_ID; id < WD_NUMDEVS; ++id) {
-		if(pDev->watchdog[id].runstatus & WD_STAT_BSTOP) {
-			++tripped;
-			wd_resetbrokentimer(&pDev->watchdog[id]);
-		}
-	}
-
-	if(tripped) {
-		/* there is at least one timer brokenstopped-- reschedule */
-		init_timer(&wd_timer);
-		wd_timer.expires = WD_BTIMEOUT;
-		add_timer(&wd_timer);
-	}
-}
-
-static int wd_getstatus(struct wd_timer* pTimer)
-{
-	unsigned char stat = wd_readb(pTimer->regs + WD_STATUS);
-	unsigned char intr = wd_readb(wd_dev.regs + PLD_IMASK);
-	unsigned char ret  = WD_STOPPED;
-
-	/* determine STOPPED */
-	if(0 == stat ) { 
-		return(ret);
-	}
-	/* determine EXPIRED vs FREERUN vs RUNNING */
-	else if(WD_S_EXPIRED & stat) {
-		ret = WD_EXPIRED;
-	}
-	else if(WD_S_RUNNING & stat) {
-		if(intr & pTimer->intr_mask) {
-			ret = WD_FREERUN;
-		}
-		else {
-			/* Fudge WD_EXPIRED status for defective CP1400--
-			 * IF timer is running 
-			 * 	AND brokenstop is set 
-			 * 	AND an interrupt has been serviced
-			 * we are WD_EXPIRED.
-			 *
-			 * IF timer is running 
-			 * 	AND brokenstop is set 
-			 * 	AND no interrupt has been serviced
-			 * we are WD_FREERUN.
-			 */
-			if(wd_dev.isbaddoggie && (pTimer->runstatus & WD_STAT_BSTOP)) {
-				if(pTimer->runstatus & WD_STAT_SVCD) {
-					ret = WD_EXPIRED;
-				}
-				else {
-					/* we could as well pretend we are expired */
-					ret = WD_FREERUN;
-				}
-			}
-			else {
-				ret = WD_RUNNING;
-			}
-		}
-	}
-
-	/* determine SERVICED */
-	if(pTimer->runstatus & WD_STAT_SVCD) {
-		ret |= WD_SERVICED;
-	}
-
-	return(ret);
-}
-
-static int __init wd_init(void)
-{
-	int 	id;
-	struct 	linux_ebus *ebus = NULL;
-	struct 	linux_ebus_device *edev = NULL;
-
-	for_each_ebus(ebus) {
-		for_each_ebusdev(edev, ebus) {
-			if (!strcmp(edev->ofdev.node->name, WD_OBPNAME))
-				goto ebus_done;
-		}
-	}
-
-ebus_done:
-	if(!edev) {
-		printk("%s: unable to locate device\n", WD_OBPNAME);
-		return -ENODEV;
-	}
-
-	wd_dev.regs = 
-		ioremap(edev->resource[0].start, 4 * WD_TIMER_REGSZ); /* ? */
-
-	if(NULL == wd_dev.regs) {
-		printk("%s: unable to map registers\n", WD_OBPNAME);
-		return(-ENODEV);
-	}
-
-	/* initialize device structure from OBP parameters */
-	wd_dev.irq 			= edev->irqs[0];
-	wd_dev.opt_enable	= wd_opt_enable();
-	wd_dev.opt_reboot	= wd_opt_reboot();
-	wd_dev.opt_timeout	= wd_opt_timeout();
-	wd_dev.isbaddoggie	= wd_isbroken();
-
-	/* disable all interrupts unless watchdog-enabled? == true */
-	if(! wd_dev.opt_enable) {
-		wd_toggleintr(NULL, WD_INTR_OFF);
-	}
-
-	/* register miscellaneous devices */
-	for(id = WD0_ID; id < WD_NUMDEVS; ++id) {
-		if(0 != wd_inittimer(id)) {
-			printk("%s%i: unable to initialize\n", WD_OBPNAME, id);
-		}
-	}
-
-	/* warn about possible defective PLD */
-	if(wd_dev.isbaddoggie) {
-		init_timer(&wd_timer);
-		wd_timer.function 	= wd_brokentimer;
-		wd_timer.data		= (unsigned long)&wd_dev;
-		wd_timer.expires	= WD_BTIMEOUT;
-
-		printk("%s: PLD defect workaround enabled for model %s\n",
-			WD_OBPNAME, WD_BADMODEL);
-	}
-	return(0);
-}
-
-static void __exit wd_cleanup(void)
-{
-	int id;
-
-	/* if 'watchdog-enable?' == TRUE, timers are not stopped 
-	 * when module is unloaded.  All brokenstopped timers will
-	 * also now eventually trip. 
-	 */
-	for(id = WD0_ID; id < WD_NUMDEVS; ++id) {
-		if(WD_S_RUNNING == wd_readb(wd_dev.watchdog[id].regs + WD_STATUS)) {
-			if(wd_dev.opt_enable) {
-				printk(KERN_WARNING "%s%i: timer not stopped at release\n",
-					WD_OBPNAME, id);
-			}
-			else {
-				wd_stoptimer(&wd_dev.watchdog[id]);
-				if(wd_dev.watchdog[id].runstatus & WD_STAT_BSTOP) {
-					wd_resetbrokentimer(&wd_dev.watchdog[id]);
-					printk(KERN_WARNING 
-							"%s%i: defect workaround disabled at release, "\
-							"timer expires in ~%01i sec\n",
-							WD_OBPNAME, id, 
-							wd_readw(wd_dev.watchdog[id].regs + WD_LIMIT) / 10);
-				}
-			}
-		}
-	}
-
-	if(wd_dev.isbaddoggie && timer_pending(&wd_timer)) {
-		del_timer(&wd_timer);
-	}
-	if(0 != (wd_dev.watchdog[WD0_ID].runstatus & WD_STAT_INIT)) {
-		misc_deregister(&wd0_miscdev);
-	}
-	if(0 != (wd_dev.watchdog[WD1_ID].runstatus & WD_STAT_INIT)) {
-		misc_deregister(&wd1_miscdev);
-	}
-	if(0 != (wd_dev.watchdog[WD2_ID].runstatus & WD_STAT_INIT)) {
-		misc_deregister(&wd2_miscdev);
-	}
-	if(0 != wd_dev.initialized) {
-		free_irq(wd_dev.irq, (void *)wd_dev.regs);
-	}
-	iounmap(wd_dev.regs);
-}
-
-module_init(wd_init);
-module_exit(wd_cleanup);
diff --git a/drivers/sbus/char/display7seg.c b/drivers/sbus/char/display7seg.c
index d8f5c0c..2550af4 100644
--- a/drivers/sbus/char/display7seg.c
+++ b/drivers/sbus/char/display7seg.c
@@ -1,10 +1,7 @@
-/* $Id: display7seg.c,v 1.6 2002/01/08 16:00:16 davem Exp $
- *
- * display7seg - Driver implementation for the 7-segment display
- * present on Sun Microsystems CP1400 and CP1500
+/* display7seg.c - Driver implementation for the 7-segment display
+ *                 present on Sun Microsystems CP1400 and CP1500
  *
  * Copyright (c) 2000 Eric Brower (ebrower@usa.net)
- *
  */
 
 #include <linux/kernel.h>
@@ -16,22 +13,20 @@
 #include <linux/miscdevice.h>
 #include <linux/ioport.h>		/* request_region */
 #include <linux/smp_lock.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 #include <asm/atomic.h>
-#include <asm/ebus.h>			/* EBus device					*/
-#include <asm/oplib.h>			/* OpenProm Library 			*/
 #include <asm/uaccess.h>		/* put_/get_user			*/
 #include <asm/io.h>
 
 #include <asm/display7seg.h>
 
 #define D7S_MINOR	193
-#define D7S_OBPNAME	"display7seg"
-#define D7S_DEVNAME "d7s"
+#define DRIVER_NAME	"d7s"
+#define PFX		DRIVER_NAME ": "
 
 static int sol_compat = 0;		/* Solaris compatibility mode	*/
 
-#ifdef MODULE
-
 /* Solaris compatibility flag -
  * The Solaris implementation omits support for several
  * documented driver features (ref Sun doc 806-0180-03).  
@@ -46,20 +41,20 @@
  * If you wish the device to operate as under Solaris,
  * omitting above features, set this parameter to non-zero.
  */
-module_param
-	(sol_compat, int, 0);
-MODULE_PARM_DESC
-	(sol_compat, 
-	 "Disables documented functionality omitted from Solaris driver");
+module_param(sol_compat, int, 0);
+MODULE_PARM_DESC(sol_compat, 
+		 "Disables documented functionality omitted from Solaris driver");
 
-MODULE_AUTHOR
-	("Eric Brower <ebrower@usa.net>");
-MODULE_DESCRIPTION
-	("7-Segment Display driver for Sun Microsystems CP1400/1500");
+MODULE_AUTHOR("Eric Brower <ebrower@usa.net>");
+MODULE_DESCRIPTION("7-Segment Display driver for Sun Microsystems CP1400/1500");
 MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE
-	("d7s");
-#endif /* ifdef MODULE */
+MODULE_SUPPORTED_DEVICE("d7s");
+
+struct d7s {
+	void __iomem	*regs;
+	bool		flipped;
+};
+struct d7s *d7s_device;
 
 /*
  * Register block address- see header for details
@@ -72,22 +67,6 @@
  * FLIP		- Inverts display for upside-down mounted board
  * bits 0-4	- 7-segment display contents
  */
-static void __iomem* d7s_regs;
-
-static inline void d7s_free(void)
-{
-	iounmap(d7s_regs);
-}
-
-static inline int d7s_obpflipped(void)
-{
-	int opt_node;
-
-	opt_node = prom_getchild(prom_root_node);
-	opt_node = prom_searchsiblings(opt_node, "options");
-	return ((-1 != prom_getintdefault(opt_node, "d7s-flipped?", -1)) ? 0 : 1);
-}
-
 static atomic_t d7s_users = ATOMIC_INIT(0);
 
 static int d7s_open(struct inode *inode, struct file *f)
@@ -106,12 +85,15 @@
 	 * are not operating in solaris-compat mode
 	 */
 	if (atomic_dec_and_test(&d7s_users) && !sol_compat) {
-		int regval = 0;
+		struct d7s *p = d7s_device;
+		u8 regval = 0;
 
-		regval = readb(d7s_regs);
-		(0 == d7s_obpflipped())	? 
-			writeb(regval |= D7S_FLIP,  d7s_regs): 
-			writeb(regval &= ~D7S_FLIP, d7s_regs);
+		regval = readb(p->regs);
+		if (p->flipped)
+			regval |= D7S_FLIP;
+		else
+			regval &= ~D7S_FLIP;
+		writeb(regval, p->regs);
 	}
 
 	return 0;
@@ -119,9 +101,10 @@
 
 static long d7s_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 {
-	__u8 regs = readb(d7s_regs);
-	__u8 ireg = 0;
+	struct d7s *p = d7s_device;
+	u8 regs = readb(p->regs);
 	int error = 0;
+	u8 ireg = 0;
 
 	if (D7S_MINOR != iminor(file->f_path.dentry->d_inode))
 		return -ENODEV;
@@ -129,18 +112,20 @@
 	lock_kernel();
 	switch (cmd) {
 	case D7SIOCWR:
-		/* assign device register values
-		 * we mask-out D7S_FLIP if in sol_compat mode
+		/* assign device register values we mask-out D7S_FLIP
+		 * if in sol_compat mode
 		 */
 		if (get_user(ireg, (int __user *) arg)) {
 			error = -EFAULT;
 			break;
 		}
-		if (0 != sol_compat) {
-			(regs & D7S_FLIP) ? 
-				(ireg |= D7S_FLIP) : (ireg &= ~D7S_FLIP);
+		if (sol_compat) {
+			if (regs & D7S_FLIP)
+				ireg |= D7S_FLIP;
+			else
+				ireg &= ~D7S_FLIP;
 		}
-		writeb(ireg, d7s_regs);
+		writeb(ireg, p->regs);
 		break;
 
 	case D7SIOCRD:
@@ -158,9 +143,11 @@
 
 	case D7SIOCTM:
 		/* toggle device mode-- flip display orientation */
-		(regs & D7S_FLIP) ? 
-			(regs &= ~D7S_FLIP) : (regs |= D7S_FLIP);
-		writeb(regs, d7s_regs);
+		if (regs & D7S_FLIP)
+			regs &= ~D7S_FLIP;
+		else
+			regs |= D7S_FLIP;
+		writeb(regs, p->regs);
 		break;
 	};
 	unlock_kernel();
@@ -176,69 +163,123 @@
 	.release =		d7s_release,
 };
 
-static struct miscdevice d7s_miscdev = { D7S_MINOR, D7S_DEVNAME, &d7s_fops };
+static struct miscdevice d7s_miscdev = {
+	.minor		= D7S_MINOR,
+	.name		= DRIVER_NAME,
+	.fops		= &d7s_fops
+};
 
-static int __init d7s_init(void)
+static int __devinit d7s_probe(struct of_device *op,
+			       const struct of_device_id *match)
 {
-	struct linux_ebus *ebus = NULL;
-	struct linux_ebus_device *edev = NULL;
-	int iTmp = 0, regs = 0;
+	struct device_node *opts;
+	int err = -EINVAL;
+	struct d7s *p;
+	u8 regs;
 
-	for_each_ebus(ebus) {
-		for_each_ebusdev(edev, ebus) {
-			if (!strcmp(edev->prom_node->name, D7S_OBPNAME))
-				goto ebus_done;
-		}
+	if (d7s_device)
+		goto out;
+
+	p = kzalloc(sizeof(*p), GFP_KERNEL);
+	err = -ENOMEM;
+	if (!p)
+		goto out;
+
+	p->regs = of_ioremap(&op->resource[0], 0, sizeof(u8), "d7s");
+	if (!p->regs) {
+		printk(KERN_ERR PFX "Cannot map chip registers\n");
+		goto out_free;
 	}
 
-ebus_done:
-	if(!edev) {
-		printk("%s: unable to locate device\n", D7S_DEVNAME);
-		return -ENODEV;
+	err = misc_register(&d7s_miscdev);
+	if (err) {
+		printk(KERN_ERR PFX "Unable to acquire miscdevice minor %i\n",
+		       D7S_MINOR);
+		goto out_iounmap;
 	}
 
-	d7s_regs = ioremap(edev->resource[0].start, sizeof(__u8));
-
-	iTmp = misc_register(&d7s_miscdev);
-	if (0 != iTmp) {
-		printk("%s: unable to acquire miscdevice minor %i\n",
-		       D7S_DEVNAME, D7S_MINOR);
-		iounmap(d7s_regs);
-		return iTmp;
-	}
-
-	/* OBP option "d7s-flipped?" is honored as default
-	 * for the device, and reset default when detached
+	/* OBP option "d7s-flipped?" is honored as default for the
+	 * device, and reset default when detached
 	 */
-	regs = readb(d7s_regs);
-	iTmp = d7s_obpflipped();
-	(0 == iTmp) ? 
-		writeb(regs |= D7S_FLIP,  d7s_regs): 
-		writeb(regs &= ~D7S_FLIP, d7s_regs);
+	regs = readb(p->regs);
+	opts = of_find_node_by_path("/options");
+	if (opts &&
+	    of_get_property(opts, "d7s-flipped?", NULL))
+		p->flipped = true;
 
-	printk("%s: 7-Segment Display%s at 0x%lx %s\n", 
-	       D7S_DEVNAME,
-	       (0 == iTmp) ? (" (FLIPPED)") : (""),
-	       edev->resource[0].start,
-	       (0 != sol_compat) ? ("in sol_compat mode") : (""));
+	if (p->flipped)
+		regs |= D7S_FLIP;
+	else
+		regs &= ~D7S_FLIP;
+
+	writeb(regs,  p->regs);
+
+	printk(KERN_INFO PFX "7-Segment Display%s at [%s:0x%lx] %s\n", 
+	       op->node->full_name,
+	       (regs & D7S_FLIP) ? " (FLIPPED)" : "",
+	       op->resource[0].start,
+	       sol_compat ? "in sol_compat mode" : "");
+
+	dev_set_drvdata(&op->dev, p);
+	d7s_device = p;
+	err = 0;
+
+out:
+	return err;
+
+out_iounmap:
+	of_iounmap(&op->resource[0], p->regs, sizeof(u8));
+
+out_free:
+	kfree(p);
+	goto out;
+}
+
+static int __devexit d7s_remove(struct of_device *op)
+{
+	struct d7s *p = dev_get_drvdata(&op->dev);
+	u8 regs = readb(p->regs);
+
+	/* Honor OBP d7s-flipped? unless operating in solaris-compat mode */
+	if (sol_compat) {
+		if (p->flipped)
+			regs |= D7S_FLIP;
+		else
+			regs &= ~D7S_FLIP;
+		writeb(regs, p->regs);
+	}
+
+	misc_deregister(&d7s_miscdev);
+	of_iounmap(&op->resource[0], p->regs, sizeof(u8));
+	kfree(p);
 
 	return 0;
 }
 
-static void __exit d7s_cleanup(void)
+static const struct of_device_id d7s_match[] = {
+	{
+		.name = "display7seg",
+	},
+	{},
+};
+MODULE_DEVICE_TABLE(of, d7s_match);
+
+static struct of_platform_driver d7s_driver = {
+	.name		= DRIVER_NAME,
+	.match_table	= d7s_match,
+	.probe		= d7s_probe,
+	.remove		= __devexit_p(d7s_remove),
+};
+
+static int __init d7s_init(void)
 {
-	int regs = readb(d7s_regs);
+	return of_register_driver(&d7s_driver, &of_bus_type);
+}
 
-	/* Honor OBP d7s-flipped? unless operating in solaris-compat mode */
-	if (0 == sol_compat) {
-		(0 == d7s_obpflipped())	? 
-			writeb(regs |= D7S_FLIP,  d7s_regs):
-			writeb(regs &= ~D7S_FLIP, d7s_regs);
-	}
-
-	misc_deregister(&d7s_miscdev);
-	d7s_free();
+static void __exit d7s_exit(void)
+{
+	of_unregister_driver(&d7s_driver);
 }
 
 module_init(d7s_init);
-module_exit(d7s_cleanup);
+module_exit(d7s_exit);
diff --git a/drivers/sbus/char/envctrl.c b/drivers/sbus/char/envctrl.c
index a408402..58e583b 100644
--- a/drivers/sbus/char/envctrl.c
+++ b/drivers/sbus/char/envctrl.c
@@ -1,5 +1,4 @@
-/* $Id: envctrl.c,v 1.25 2002/01/15 09:01:26 davem Exp $
- * envctrl.c: Temperature and Fan monitoring on Machines providing it.
+/* envctrl.c: Temperature and Fan monitoring on Machines providing it.
  *
  * Copyright (C) 1998  Eddie C. Dost  (ecd@skynet.be)
  * Copyright (C) 2000  Vinh Truong    (vinh.truong@eng.sun.com)
@@ -28,12 +27,16 @@
 #include <linux/kmod.h>
 #include <linux/reboot.h>
 #include <linux/smp_lock.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 
-#include <asm/ebus.h>
 #include <asm/uaccess.h>
 #include <asm/envctrl.h>
 #include <asm/io.h>
 
+#define DRIVER_NAME	"envctrl"
+#define PFX		DRIVER_NAME ": "
+
 #define ENVCTRL_MINOR	162
 
 #define PCF8584_ADDRESS	0x55
@@ -193,7 +196,7 @@
 	} 
 
 	if (limit <= 0)
-		printk(KERN_INFO "envctrl: Pin status will not clear.\n");
+		printk(KERN_INFO PFX "Pin status will not clear.\n");
 }
 
 /* Function Description: Test busy bit.
@@ -211,7 +214,7 @@
 	} 
 
 	if (limit <= 0)
-		printk(KERN_INFO "envctrl: Busy bit will not clear.\n");
+		printk(KERN_INFO PFX "Busy bit will not clear.\n");
 }
 
 /* Function Description: Send the address for a read access.
@@ -858,11 +861,10 @@
 /* Function Description: Initialize i2c child device.
  * Return: None.
  */
-static void envctrl_init_i2c_child(struct linux_ebus_child *edev_child,
+static void envctrl_init_i2c_child(struct device_node *dp,
 				   struct i2c_child_t *pchild)
 {
 	int len, i, tbls_size = 0;
-	struct device_node *dp = edev_child->prom_node;
 	const void *pval;
 
 	/* Get device address. */
@@ -882,12 +884,12 @@
 
                 pchild->tables = kmalloc(tbls_size, GFP_KERNEL);
 		if (pchild->tables == NULL){
-			printk("envctrl: Failed to allocate table.\n");
+			printk(KERN_ERR PFX "Failed to allocate table.\n");
 			return;
 		}
 		pval = of_get_property(dp, "tables", &len);
                 if (!pval || len <= 0) {
-			printk("envctrl: Failed to get table.\n");
+			printk(KERN_ERR PFX "Failed to get table.\n");
 			return;
 		}
 		memcpy(pchild->tables, pval, len);
@@ -993,14 +995,14 @@
 	struct i2c_child_t *cputemp;
 
 	if (NULL == (cputemp = envctrl_get_i2c_child(ENVCTRL_CPUTEMP_MON))) {
-		printk(KERN_ERR 
-		       "envctrl: kenvctrld unable to monitor CPU temp-- exiting\n");
+		printk(KERN_ERR  PFX
+		       "kenvctrld unable to monitor CPU temp-- exiting\n");
 		return -ENODEV;
 	}
 
 	poll_interval = 5000; /* TODO env_mon_interval */
 
-	printk(KERN_INFO "envctrl: %s starting...\n", current->comm);
+	printk(KERN_INFO PFX "%s starting...\n", current->comm);
 	for (;;) {
 		msleep_interruptible(poll_interval);
 
@@ -1022,54 +1024,35 @@
 			}
 		}
 	}
-	printk(KERN_INFO "envctrl: %s exiting...\n", current->comm);
+	printk(KERN_INFO PFX "%s exiting...\n", current->comm);
 	return 0;
 }
 
-static int __init envctrl_init(void)
+static int __devinit envctrl_probe(struct of_device *op,
+				   const struct of_device_id *match)
 {
-	struct linux_ebus *ebus = NULL;
-	struct linux_ebus_device *edev = NULL;
-	struct linux_ebus_child *edev_child = NULL;
-	int err, i = 0;
+	struct device_node *dp;
+	int index, err;
 
-	for_each_ebus(ebus) {
-		for_each_ebusdev(edev, ebus) {
-			if (!strcmp(edev->prom_node->name, "bbc")) {
-				/* If we find a boot-bus controller node,
-				 * then this envctrl driver is not for us.
-				 */
-				return -ENODEV;
-			}
+	if (i2c)
+		return -EINVAL;
+
+	i2c = of_ioremap(&op->resource[0], 0, 0x2, DRIVER_NAME);
+	if (!i2c)
+		return -ENOMEM;
+
+	index = 0;
+	dp = op->node->child;
+	while (dp) {
+		if (!strcmp(dp->name, "gpio")) {
+			i2c_childlist[index].i2ctype = I2C_GPIO;
+			envctrl_init_i2c_child(dp, &(i2c_childlist[index++]));
+		} else if (!strcmp(dp->name, "adc")) {
+			i2c_childlist[index].i2ctype = I2C_ADC;
+			envctrl_init_i2c_child(dp, &(i2c_childlist[index++]));
 		}
-	}
 
-	/* Traverse through ebus and ebus device list for i2c device and
-	 * adc and gpio nodes.
-	 */
-	for_each_ebus(ebus) {
-		for_each_ebusdev(edev, ebus) {
-			if (!strcmp(edev->prom_node->name, "i2c")) {
-				i2c = ioremap(edev->resource[0].start, 0x2);
-				for_each_edevchild(edev, edev_child) {
-					if (!strcmp("gpio", edev_child->prom_node->name)) {
-						i2c_childlist[i].i2ctype = I2C_GPIO;
-						envctrl_init_i2c_child(edev_child, &(i2c_childlist[i++]));
-					}
-					if (!strcmp("adc", edev_child->prom_node->name)) {
-						i2c_childlist[i].i2ctype = I2C_ADC;
-						envctrl_init_i2c_child(edev_child, &(i2c_childlist[i++]));
-					}
-				}
-				goto done;
-			}
-		}
-	}
-
-done:
-	if (!edev) {
-		printk("envctrl: I2C device not found.\n");
-		return -ENODEV;
+		dp = dp->sibling;
 	}
 
 	/* Set device address. */
@@ -1087,7 +1070,7 @@
 	/* Register the device as a minor miscellaneous device. */
 	err = misc_register(&envctrl_dev);
 	if (err) {
-		printk("envctrl: Unable to get misc minor %d\n",
+		printk(KERN_ERR PFX "Unable to get misc minor %d\n",
 		       envctrl_dev.minor);
 		goto out_iounmap;
 	}
@@ -1096,12 +1079,12 @@
 	 * a next child device, so we decrement before reverse-traversal of
 	 * child devices.
 	 */
-	printk("envctrl: initialized ");
-	for (--i; i >= 0; --i) {
+	printk(KERN_INFO PFX "Initialized ");
+	for (--index; index >= 0; --index) {
 		printk("[%s 0x%lx]%s", 
-			(I2C_ADC == i2c_childlist[i].i2ctype) ? ("adc") : 
-			((I2C_GPIO == i2c_childlist[i].i2ctype) ? ("gpio") : ("unknown")), 
-			i2c_childlist[i].addr, (0 == i) ? ("\n") : (" "));
+			(I2C_ADC == i2c_childlist[index].i2ctype) ? "adc" : 
+			((I2C_GPIO == i2c_childlist[index].i2ctype) ? "gpio" : "unknown"), 
+			i2c_childlist[index].addr, (0 == index) ? "\n" : " ");
 	}
 
 	kenvctrld_task = kthread_run(kenvctrld, NULL, "kenvctrld");
@@ -1115,26 +1098,54 @@
 out_deregister:
 	misc_deregister(&envctrl_dev);
 out_iounmap:
-	iounmap(i2c);
-	for (i = 0; i < ENVCTRL_MAX_CPU * 2; i++)
-		kfree(i2c_childlist[i].tables);
+	of_iounmap(&op->resource[0], i2c, 0x2);
+	for (index = 0; index < ENVCTRL_MAX_CPU * 2; index++)
+		kfree(i2c_childlist[index].tables);
 
 	return err;
 }
 
-static void __exit envctrl_cleanup(void)
+static int __devexit envctrl_remove(struct of_device *op)
 {
-	int i;
+	int index;
 
 	kthread_stop(kenvctrld_task);
 
-	iounmap(i2c);
+	of_iounmap(&op->resource[0], i2c, 0x2);
 	misc_deregister(&envctrl_dev);
 
-	for (i = 0; i < ENVCTRL_MAX_CPU * 2; i++)
-		kfree(i2c_childlist[i].tables);
+	for (index = 0; index < ENVCTRL_MAX_CPU * 2; index++)
+		kfree(i2c_childlist[index].tables);
+
+	return 0;
+}
+
+static const struct of_device_id envctrl_match[] = {
+	{
+		.name = "i2c",
+		.compatible = "i2cpcf,8584",
+	},
+	{},
+};
+MODULE_DEVICE_TABLE(of, envctrl_match);
+
+static struct of_platform_driver envctrl_driver = {
+	.name		= DRIVER_NAME,
+	.match_table	= envctrl_match,
+	.probe		= envctrl_probe,
+	.remove		= __devexit_p(envctrl_remove),
+};
+
+static int __init envctrl_init(void)
+{
+	return of_register_driver(&envctrl_driver, &of_bus_type);
+}
+
+static void __exit envctrl_exit(void)
+{
+	of_unregister_driver(&envctrl_driver);
 }
 
 module_init(envctrl_init);
-module_exit(envctrl_cleanup);
+module_exit(envctrl_exit);
 MODULE_LICENSE("GPL");
diff --git a/drivers/sbus/char/flash.c b/drivers/sbus/char/flash.c
index 7d95e15..4108347 100644
--- a/drivers/sbus/char/flash.c
+++ b/drivers/sbus/char/flash.c
@@ -1,5 +1,4 @@
-/* $Id: flash.c,v 1.25 2001/12/21 04:56:16 davem Exp $
- * flash.c: Allow mmap access to the OBP Flash, for OBP updates.
+/* flash.c: Allow mmap access to the OBP Flash, for OBP updates.
  *
  * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
  */
@@ -15,13 +14,13 @@
 #include <linux/smp_lock.h>
 #include <linux/spinlock.h>
 #include <linux/mm.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 
 #include <asm/system.h>
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
 #include <asm/io.h>
-#include <asm/sbus.h>
-#include <asm/ebus.h>
 #include <asm/upa.h>
 
 static DEFINE_SPINLOCK(flash_lock);
@@ -161,97 +160,68 @@
 
 static struct miscdevice flash_dev = { FLASH_MINOR, "flash", &flash_fops };
 
-static int __init flash_init(void)
+static int __devinit flash_probe(struct of_device *op,
+				 const struct of_device_id *match)
 {
-	struct sbus_bus *sbus;
-	struct sbus_dev *sdev = NULL;
-#ifdef CONFIG_PCI
-	struct linux_ebus *ebus;
-	struct linux_ebus_device *edev = NULL;
-	struct linux_prom_registers regs[2];
-	int len, nregs;
-#endif
-	int err;
+	struct device_node *dp = op->node;
+	struct device_node *parent;
 
-	for_all_sbusdev(sdev, sbus) {
-		if (!strcmp(sdev->prom_name, "flashprom")) {
-			if (sdev->reg_addrs[0].phys_addr == sdev->reg_addrs[1].phys_addr) {
-				flash.read_base = ((unsigned long)sdev->reg_addrs[0].phys_addr) |
-					(((unsigned long)sdev->reg_addrs[0].which_io)<<32UL);
-				flash.read_size = sdev->reg_addrs[0].reg_size;
-				flash.write_base = flash.read_base;
-				flash.write_size = flash.read_size;
-			} else {
-				flash.read_base = ((unsigned long)sdev->reg_addrs[0].phys_addr) |
-					(((unsigned long)sdev->reg_addrs[0].which_io)<<32UL);
-				flash.read_size = sdev->reg_addrs[0].reg_size;
-				flash.write_base = ((unsigned long)sdev->reg_addrs[1].phys_addr) |
-					(((unsigned long)sdev->reg_addrs[1].which_io)<<32UL);
-				flash.write_size = sdev->reg_addrs[1].reg_size;
-			}
-			flash.busy = 0;
-			break;
-		}
-	}
-	if (!sdev) {
-#ifdef CONFIG_PCI
-		const struct linux_prom_registers *ebus_regs;
+	parent = dp->parent;
 
-		for_each_ebus(ebus) {
-			for_each_ebusdev(edev, ebus) {
-				if (!strcmp(edev->prom_node->name, "flashprom"))
-					goto ebus_done;
-			}
-		}
-	ebus_done:
-		if (!edev)
-			return -ENODEV;
-
-		ebus_regs = of_get_property(edev->prom_node, "reg", &len);
-		if (!ebus_regs || (len % sizeof(regs[0])) != 0) {
-			printk("flash: Strange reg property size %d\n", len);
-			return -ENODEV;
-		}
-
-		nregs = len / sizeof(ebus_regs[0]);
-
-		flash.read_base = edev->resource[0].start;
-		flash.read_size = ebus_regs[0].reg_size;
-
-		if (nregs == 1) {
-			flash.write_base = edev->resource[0].start;
-			flash.write_size = ebus_regs[0].reg_size;
-		} else if (nregs == 2) {
-			flash.write_base = edev->resource[1].start;
-			flash.write_size = ebus_regs[1].reg_size;
-		} else {
-			printk("flash: Strange number of regs %d\n", nregs);
-			return -ENODEV;
-		}
-
-		flash.busy = 0;
-
-#else
+	if (strcmp(parent->name, "sbus") &&
+	    strcmp(parent->name, "sbi") &&
+	    strcmp(parent->name, "ebus"))
 		return -ENODEV;
-#endif
-	}
 
-	printk("OBP Flash: RD %lx[%lx] WR %lx[%lx]\n",
+	flash.read_base = op->resource[0].start;
+	flash.read_size = resource_size(&op->resource[0]);
+	if (op->resource[1].flags) {
+		flash.write_base = op->resource[1].start;
+		flash.write_size = resource_size(&op->resource[1]);
+	} else {
+		flash.write_base = op->resource[0].start;
+		flash.write_size = resource_size(&op->resource[0]);
+	}
+	flash.busy = 0;
+
+	printk(KERN_INFO "%s: OBP Flash, RD %lx[%lx] WR %lx[%lx]\n",
+	       op->node->full_name,
 	       flash.read_base, flash.read_size,
 	       flash.write_base, flash.write_size);
 
-	err = misc_register(&flash_dev);
-	if (err) {
-		printk(KERN_ERR "flash: unable to get misc minor\n");
-		return err;
-	}
+	return misc_register(&flash_dev);
+}
+
+static int __devexit flash_remove(struct of_device *op)
+{
+	misc_deregister(&flash_dev);
 
 	return 0;
 }
 
+static const struct of_device_id flash_match[] = {
+	{
+		.name = "flashprom",
+	},
+	{},
+};
+MODULE_DEVICE_TABLE(of, flash_match);
+
+static struct of_platform_driver flash_driver = {
+	.name		= "flash",
+	.match_table	= flash_match,
+	.probe		= flash_probe,
+	.remove		= __devexit_p(flash_remove),
+};
+
+static int __init flash_init(void)
+{
+	return of_register_driver(&flash_driver, &of_bus_type);
+}
+
 static void __exit flash_cleanup(void)
 {
-	misc_deregister(&flash_dev);
+	of_unregister_driver(&flash_driver);
 }
 
 module_init(flash_init);
diff --git a/drivers/sbus/char/riowatchdog.c b/drivers/sbus/char/riowatchdog.c
deleted file mode 100644
index 88c0fc6..0000000
--- a/drivers/sbus/char/riowatchdog.c
+++ /dev/null
@@ -1,295 +0,0 @@
-/* $Id: riowatchdog.c,v 1.3.2.2 2002/01/23 18:48:02 davem Exp $
- * riowatchdog.c - driver for hw watchdog inside Super I/O of RIO
- *
- * Copyright (C) 2001 David S. Miller (davem@redhat.com)
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/fs.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/miscdevice.h>
-#include <linux/smp_lock.h>
-
-#include <asm/io.h>
-#include <asm/ebus.h>
-#include <asm/bbc.h>
-#include <asm/oplib.h>
-#include <asm/uaccess.h>
-
-#include <asm/watchdog.h>
-
-/* RIO uses the NatSemi Super I/O power management logical device
- * as its' watchdog.
- *
- * When the watchdog triggers, it asserts a line to the BBC (Boot Bus
- * Controller) of the machine.  The BBC can only be configured to
- * trigger a power-on reset when the signal is asserted.  The BBC
- * can be configured to ignore the signal entirely as well.
- *
- * The only Super I/O device register we care about is at index
- * 0x05 (WDTO_INDEX) which is the watchdog time-out in minutes (1-255).
- * If set to zero, this disables the watchdog.  When set, the system
- * must periodically (before watchdog expires) clear (set to zero) and
- * re-set the watchdog else it will trigger.
- *
- * There are two other indexed watchdog registers inside this Super I/O
- * logical device, but they are unused.  The first, at index 0x06 is
- * the watchdog control and can be used to make the watchdog timer re-set
- * when the PS/2 mouse or serial lines show activity.  The second, at
- * index 0x07 is merely a sampling of the line from the watchdog to the
- * BBC.
- *
- * The watchdog device generates no interrupts.
- */
-
-MODULE_AUTHOR("David S. Miller <davem@redhat.com>");
-MODULE_DESCRIPTION("Hardware watchdog driver for Sun RIO");
-MODULE_SUPPORTED_DEVICE("watchdog");
-MODULE_LICENSE("GPL");
-
-#define RIOWD_NAME	"pmc"
-#define RIOWD_MINOR	215
-
-static DEFINE_SPINLOCK(riowd_lock);
-
-static void __iomem *bbc_regs;
-static void __iomem *riowd_regs;
-#define WDTO_INDEX	0x05
-
-static int riowd_timeout = 1;		/* in minutes */
-module_param(riowd_timeout, int, 0);
-MODULE_PARM_DESC(riowd_timeout, "Watchdog timeout in minutes");
-
-#if 0 /* Currently unused. */
-static u8 riowd_readreg(int index)
-{
-	unsigned long flags;
-	u8 ret;
-
-	spin_lock_irqsave(&riowd_lock, flags);
-	writeb(index, riowd_regs + 0);
-	ret = readb(riowd_regs + 1);
-	spin_unlock_irqrestore(&riowd_lock, flags);
-
-	return ret;
-}
-#endif
-
-static void riowd_writereg(u8 val, int index)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&riowd_lock, flags);
-	writeb(index, riowd_regs + 0);
-	writeb(val, riowd_regs + 1);
-	spin_unlock_irqrestore(&riowd_lock, flags);
-}
-
-static void riowd_pingtimer(void)
-{
-	riowd_writereg(riowd_timeout, WDTO_INDEX);
-}
-
-static void riowd_stoptimer(void)
-{
-	u8 val;
-
-	riowd_writereg(0, WDTO_INDEX);
-
-	val = readb(bbc_regs + BBC_WDACTION);
-	val &= ~BBC_WDACTION_RST;
-	writeb(val, bbc_regs + BBC_WDACTION);
-}
-
-static void riowd_starttimer(void)
-{
-	u8 val;
-
-	riowd_writereg(riowd_timeout, WDTO_INDEX);
-
-	val = readb(bbc_regs + BBC_WDACTION);
-	val |= BBC_WDACTION_RST;
-	writeb(val, bbc_regs + BBC_WDACTION);
-}
-
-static int riowd_open(struct inode *inode, struct file *filp)
-{
-	cycle_kernel_lock();
-	nonseekable_open(inode, filp);
-	return 0;
-}
-
-static int riowd_release(struct inode *inode, struct file *filp)
-{
-	return 0;
-}
-
-static int riowd_ioctl(struct inode *inode, struct file *filp,
-		       unsigned int cmd, unsigned long arg)
-{
-	static struct watchdog_info info = {
-	       	WDIOF_SETTIMEOUT, 0, "Natl. Semiconductor PC97317"
-	};
-	void __user *argp = (void __user *)arg;
-	unsigned int options;
-	int new_margin;
-
-	switch (cmd) {
-	case WDIOC_GETSUPPORT:
-		if (copy_to_user(argp, &info, sizeof(info)))
-			return -EFAULT;
-		break;
-
-	case WDIOC_GETSTATUS:
-	case WDIOC_GETBOOTSTATUS:
-		if (put_user(0, (int __user *)argp))
-			return -EFAULT;
-		break;
-
-	case WDIOC_KEEPALIVE:
-		riowd_pingtimer();
-		break;
-
-	case WDIOC_SETOPTIONS:
-		if (copy_from_user(&options, argp, sizeof(options)))
-			return -EFAULT;
-
-		if (options & WDIOS_DISABLECARD)
-			riowd_stoptimer();
-		else if (options & WDIOS_ENABLECARD)
-			riowd_starttimer();
-		else
-			return -EINVAL;
-
-		break;
-
-	case WDIOC_SETTIMEOUT:
-		if (get_user(new_margin, (int __user *)argp))
-			return -EFAULT;
-		if ((new_margin < 60) || (new_margin > (255 * 60)))
-		    return -EINVAL;
-		riowd_timeout = (new_margin + 59) / 60;
-		riowd_pingtimer();
-		/* Fall */
-
-	case WDIOC_GETTIMEOUT:
-		return put_user(riowd_timeout * 60, (int __user *)argp);
-
-	default:
-		return -EINVAL;
-	};
-
-	return 0;
-}
-
-static ssize_t riowd_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
-{
-	if (count) {
-		riowd_pingtimer();
-		return 1;
-	}
-
-	return 0;
-}
-
-static const struct file_operations riowd_fops = {
-	.owner =	THIS_MODULE,
-	.ioctl =	riowd_ioctl,
-	.open =		riowd_open,
-	.write =	riowd_write,
-	.release =	riowd_release,
-};
-
-static struct miscdevice riowd_miscdev = { RIOWD_MINOR, RIOWD_NAME, &riowd_fops };
-
-static int __init riowd_bbc_init(void)
-{
-	struct 	linux_ebus *ebus = NULL;
-	struct 	linux_ebus_device *edev = NULL;
-	u8 val;
-
-	for_each_ebus(ebus) {
-		for_each_ebusdev(edev, ebus) {
-			if (!strcmp(edev->ofdev.node->name, "bbc"))
-				goto found_bbc;
-		}
-	}
-
-found_bbc:
-	if (!edev)
-		return -ENODEV;
-	bbc_regs = ioremap(edev->resource[0].start, BBC_REGS_SIZE);
-	if (!bbc_regs)
-		return -ENODEV;
-
-	/* Turn it off. */
-	val = readb(bbc_regs + BBC_WDACTION);
-	val &= ~BBC_WDACTION_RST;
-	writeb(val, bbc_regs + BBC_WDACTION);
-
-	return 0;
-}
-
-static int __init riowd_init(void)
-{
-	struct 	linux_ebus *ebus = NULL;
-	struct 	linux_ebus_device *edev = NULL;
-
-	for_each_ebus(ebus) {
-		for_each_ebusdev(edev, ebus) {
-			if (!strcmp(edev->ofdev.node->name, RIOWD_NAME))
-				goto ebus_done;
-		}
-	}
-
-ebus_done:
-	if (!edev)
-		goto fail;
-
-	riowd_regs = ioremap(edev->resource[0].start, 2);
-	if (riowd_regs == NULL) {
-		printk(KERN_ERR "pmc: Cannot map registers.\n");
-		return -ENODEV;
-	}
-
-	if (riowd_bbc_init()) {
-		printk(KERN_ERR "pmc: Failure initializing BBC config.\n");
-		goto fail;
-	}
-
-	if (misc_register(&riowd_miscdev)) {
-		printk(KERN_ERR "pmc: Cannot register watchdog misc device.\n");
-		goto fail;
-	}
-
-	printk(KERN_INFO "pmc: Hardware watchdog [%i minutes], "
-	       "regs at %p\n", riowd_timeout, riowd_regs);
-
-	return 0;
-
-fail:
-	if (riowd_regs) {
-		iounmap(riowd_regs);
-		riowd_regs = NULL;
-	}
-	if (bbc_regs) {
-		iounmap(bbc_regs);
-		bbc_regs = NULL;
-	}
-	return -ENODEV;
-}
-
-static void __exit riowd_cleanup(void)
-{
-	misc_deregister(&riowd_miscdev);
-	iounmap(riowd_regs);
-	riowd_regs = NULL;
-	iounmap(bbc_regs);
-	bbc_regs = NULL;
-}
-
-module_init(riowd_init);
-module_exit(riowd_cleanup);
diff --git a/drivers/sbus/char/rtc.c b/drivers/sbus/char/rtc.c
deleted file mode 100644
index b042991..0000000
--- a/drivers/sbus/char/rtc.c
+++ /dev/null
@@ -1,275 +0,0 @@
-/* $Id: rtc.c,v 1.28 2001/10/08 22:19:51 davem Exp $
- *
- * Linux/SPARC Real Time Clock Driver
- * Copyright (C) 1996 Thomas K. Dyas (tdyas@eden.rutgers.edu)
- *
- * This is a little driver that lets a user-level program access
- * the SPARC Mostek real time clock chip. It is no use unless you
- * use the modified clock utility.
- *
- * Get the modified clock utility from:
- *   ftp://vger.kernel.org/pub/linux/Sparc/userland/clock.c
- */
-
-#include <linux/module.h>
-#include <linux/smp_lock.h>
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/miscdevice.h>
-#include <linux/slab.h>
-#include <linux/fcntl.h>
-#include <linux/poll.h>
-#include <linux/init.h>
-#include <asm/io.h>
-#include <asm/mostek.h>
-#include <asm/system.h>
-#include <asm/uaccess.h>
-#include <asm/rtc.h>
-
-static int rtc_busy = 0;
-
-/* This is the structure layout used by drivers/char/rtc.c, we
- * support that driver's ioctls so that things are less messy in
- * userspace.
- */
-struct rtc_time_generic {
-	int tm_sec;
-	int tm_min;
-	int tm_hour;
-	int tm_mday;
-	int tm_mon;
-	int tm_year;
-	int tm_wday;
-	int tm_yday;
-	int tm_isdst;
-};
-#define RTC_AIE_ON	_IO('p', 0x01)	/* Alarm int. enable on		*/
-#define RTC_AIE_OFF	_IO('p', 0x02)	/* ... off			*/
-#define RTC_UIE_ON	_IO('p', 0x03)	/* Update int. enable on	*/
-#define RTC_UIE_OFF	_IO('p', 0x04)	/* ... off			*/
-#define RTC_PIE_ON	_IO('p', 0x05)	/* Periodic int. enable on	*/
-#define RTC_PIE_OFF	_IO('p', 0x06)	/* ... off			*/
-#define RTC_WIE_ON	_IO('p', 0x0f)  /* Watchdog int. enable on	*/
-#define RTC_WIE_OFF	_IO('p', 0x10)  /* ... off			*/
-#define RTC_RD_TIME	_IOR('p', 0x09, struct rtc_time_generic) /* Read RTC time   */
-#define RTC_SET_TIME	_IOW('p', 0x0a, struct rtc_time_generic) /* Set RTC time    */
-#define RTC_ALM_SET	_IOW('p', 0x07, struct rtc_time) /* Set alarm time  */
-#define RTC_ALM_READ	_IOR('p', 0x08, struct rtc_time) /* Read alarm time */
-#define RTC_IRQP_READ	_IOR('p', 0x0b, unsigned long)	 /* Read IRQ rate   */
-#define RTC_IRQP_SET	_IOW('p', 0x0c, unsigned long)	 /* Set IRQ rate    */
-#define RTC_EPOCH_READ	_IOR('p', 0x0d, unsigned long)	 /* Read epoch      */
-#define RTC_EPOCH_SET	_IOW('p', 0x0e, unsigned long)	 /* Set epoch       */
-#define RTC_WKALM_SET	_IOW('p', 0x0f, struct rtc_wkalrm)/* Set wakeup alarm*/
-#define RTC_WKALM_RD	_IOR('p', 0x10, struct rtc_wkalrm)/* Get wakeup alarm*/
-#define RTC_PLL_GET	_IOR('p', 0x11, struct rtc_pll_info)  /* Get PLL correction */
-#define RTC_PLL_SET	_IOW('p', 0x12, struct rtc_pll_info)  /* Set PLL correction */
-
-/* Retrieve the current date and time from the real time clock. */
-static void get_rtc_time(struct rtc_time *t)
-{
-	void __iomem *regs = mstk48t02_regs;
-	u8 tmp;
-
-	spin_lock_irq(&mostek_lock);
-
-	tmp = mostek_read(regs + MOSTEK_CREG);
-	tmp |= MSTK_CREG_READ;
-	mostek_write(regs + MOSTEK_CREG, tmp);
-
-	t->sec = MSTK_REG_SEC(regs);
-	t->min = MSTK_REG_MIN(regs);
-	t->hour = MSTK_REG_HOUR(regs);
-	t->dow = MSTK_REG_DOW(regs);
-	t->dom = MSTK_REG_DOM(regs);
-	t->month = MSTK_REG_MONTH(regs);
-	t->year = MSTK_CVT_YEAR( MSTK_REG_YEAR(regs) );
-
-	tmp = mostek_read(regs + MOSTEK_CREG);
-	tmp &= ~MSTK_CREG_READ;
-	mostek_write(regs + MOSTEK_CREG, tmp);
-
-	spin_unlock_irq(&mostek_lock);
-}
-
-/* Set the current date and time inthe real time clock. */
-void set_rtc_time(struct rtc_time *t)
-{
-	void __iomem *regs = mstk48t02_regs;
-	u8 tmp;
-
-	spin_lock_irq(&mostek_lock);
-
-	tmp = mostek_read(regs + MOSTEK_CREG);
-	tmp |= MSTK_CREG_WRITE;
-	mostek_write(regs + MOSTEK_CREG, tmp);
-
-	MSTK_SET_REG_SEC(regs,t->sec);
-	MSTK_SET_REG_MIN(regs,t->min);
-	MSTK_SET_REG_HOUR(regs,t->hour);
-	MSTK_SET_REG_DOW(regs,t->dow);
-	MSTK_SET_REG_DOM(regs,t->dom);
-	MSTK_SET_REG_MONTH(regs,t->month);
-	MSTK_SET_REG_YEAR(regs,t->year - MSTK_YEAR_ZERO);
-
-	tmp = mostek_read(regs + MOSTEK_CREG);
-	tmp &= ~MSTK_CREG_WRITE;
-	mostek_write(regs + MOSTEK_CREG, tmp);
-
-	spin_unlock_irq(&mostek_lock);
-}
-
-static int put_rtc_time_generic(void __user *argp, struct rtc_time *tm)
-{
-	struct rtc_time_generic __user *utm = argp;
-
-	if (__put_user(tm->sec, &utm->tm_sec) ||
-	    __put_user(tm->min, &utm->tm_min) ||
-	    __put_user(tm->hour, &utm->tm_hour) ||
-	    __put_user(tm->dom, &utm->tm_mday) ||
-	    __put_user(tm->month, &utm->tm_mon) ||
-	    __put_user(tm->year, &utm->tm_year) ||
-	    __put_user(tm->dow, &utm->tm_wday) ||
-	    __put_user(0, &utm->tm_yday) ||
-	    __put_user(0, &utm->tm_isdst))
-		return -EFAULT;
-
-	return 0;
-}
-
-static int get_rtc_time_generic(struct rtc_time *tm, void __user *argp)
-{
-	struct rtc_time_generic __user *utm = argp;
-
-	if (__get_user(tm->sec, &utm->tm_sec) ||
-	    __get_user(tm->min, &utm->tm_min) ||
-	    __get_user(tm->hour, &utm->tm_hour) ||
-	    __get_user(tm->dom, &utm->tm_mday) ||
-	    __get_user(tm->month, &utm->tm_mon) ||
-	    __get_user(tm->year, &utm->tm_year) ||
-	    __get_user(tm->dow, &utm->tm_wday))
-		return -EFAULT;
-
-	return 0;
-}
-
-static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
-	unsigned long arg)
-{
-	struct rtc_time rtc_tm;
-	void __user *argp = (void __user *)arg;
-
-	switch (cmd) {
-	/* No interrupt support, return an error
-	 * compatible with drivers/char/rtc.c
-	 */
-	case RTC_AIE_OFF:
-	case RTC_AIE_ON:
-	case RTC_PIE_OFF:
-	case RTC_PIE_ON:
-	case RTC_UIE_OFF:
-	case RTC_UIE_ON:
-	case RTC_IRQP_READ:
-	case RTC_IRQP_SET:
-	case RTC_EPOCH_SET:
-	case RTC_EPOCH_READ:
-		return -EINVAL;
-
-	case RTCGET:
-	case RTC_RD_TIME:
-		memset(&rtc_tm, 0, sizeof(struct rtc_time));
-		get_rtc_time(&rtc_tm);
-
-		if (cmd == RTCGET) {
-			if (copy_to_user(argp, &rtc_tm,
-					 sizeof(struct rtc_time)))
-				return -EFAULT;
-		} else if (put_rtc_time_generic(argp, &rtc_tm))
-			return -EFAULT;
-
-		return 0;
-
-
-	case RTCSET:
-	case RTC_SET_TIME:
-		if (!capable(CAP_SYS_TIME))
-			return -EPERM;
-
-		if (cmd == RTCSET) {
-			if (copy_from_user(&rtc_tm, argp,
-					   sizeof(struct rtc_time)))
-				return -EFAULT;
-		} else if (get_rtc_time_generic(&rtc_tm, argp))
-			return -EFAULT;
-
-		set_rtc_time(&rtc_tm);
-
-		return 0;
-
-	default:
-		return -EINVAL;
-	}
-}
-
-static int rtc_open(struct inode *inode, struct file *file)
-{
-	int ret;
-
-	lock_kernel();
-	spin_lock_irq(&mostek_lock);
-	if (rtc_busy) {
-		ret = -EBUSY;
-	} else {
-		rtc_busy = 1;
-		ret = 0;
-	}
-	spin_unlock_irq(&mostek_lock);
-	unlock_kernel();
-
-	return ret;
-}
-
-static int rtc_release(struct inode *inode, struct file *file)
-{
-	rtc_busy = 0;
-
-	return 0;
-}
-
-static const struct file_operations rtc_fops = {
-	.owner =	THIS_MODULE,
-	.llseek =	no_llseek,
-	.ioctl =	rtc_ioctl,
-	.open =		rtc_open,
-	.release =	rtc_release,
-};
-
-static struct miscdevice rtc_dev = { RTC_MINOR, "rtc", &rtc_fops };
-
-static int __init rtc_sun_init(void)
-{
-	int error;
-
-	/* It is possible we are being driven by some other RTC chip
-	 * and thus another RTC driver is handling things.
-	 */
-	if (!mstk48t02_regs)
-		return -ENODEV;
-
-	error = misc_register(&rtc_dev);
-	if (error) {
-		printk(KERN_ERR "rtc: unable to get misc minor for Mostek\n");
-		return error;
-	}
-	printk("rtc_sun_init: Registered Mostek RTC driver.\n");
-
-	return 0;
-}
-
-static void __exit rtc_sun_cleanup(void)
-{
-	misc_deregister(&rtc_dev);
-}
-
-module_init(rtc_sun_init);
-module_exit(rtc_sun_cleanup);
-MODULE_LICENSE("GPL");
diff --git a/drivers/sbus/char/uctrl.c b/drivers/sbus/char/uctrl.c
index 7776375..27993c3 100644
--- a/drivers/sbus/char/uctrl.c
+++ b/drivers/sbus/char/uctrl.c
@@ -1,7 +1,7 @@
-/* $Id: uctrl.c,v 1.12 2001/10/08 22:19:51 davem Exp $
- * uctrl.c: TS102 Microcontroller interface on Tadpole Sparcbook 3
+/* uctrl.c: TS102 Microcontroller interface on Tadpole Sparcbook 3
  *
  * Copyright 1999 Derrick J Brashear (shadow@dementia.org)
+ * Copyright 2008 David S. Miller (davem@davemloft.net)
  */
 
 #include <linux/module.h>
@@ -14,6 +14,8 @@
 #include <linux/init.h>
 #include <linux/miscdevice.h>
 #include <linux/mm.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 
 #include <asm/openprom.h>
 #include <asm/oplib.h>
@@ -21,7 +23,6 @@
 #include <asm/irq.h>
 #include <asm/io.h>
 #include <asm/pgtable.h>
-#include <asm/sbus.h>
 
 #define UCTRL_MINOR	174
 
@@ -33,26 +34,26 @@
 #endif
 
 struct uctrl_regs {
-	volatile u32 uctrl_intr;
-	volatile u32 uctrl_data;
-	volatile u32 uctrl_stat;
-	volatile u32 uctrl_xxx[5];
+	u32 uctrl_intr;
+	u32 uctrl_data;
+	u32 uctrl_stat;
+	u32 uctrl_xxx[5];
 };
 
 struct ts102_regs {
-	volatile u32 card_a_intr;
-	volatile u32 card_a_stat;
-	volatile u32 card_a_ctrl;
-	volatile u32 card_a_xxx;
-	volatile u32 card_b_intr;
-	volatile u32 card_b_stat;
-	volatile u32 card_b_ctrl;
-	volatile u32 card_b_xxx;
-	volatile u32 uctrl_intr;
-	volatile u32 uctrl_data;
-	volatile u32 uctrl_stat;
-	volatile u32 uctrl_xxx;
-	volatile u32 ts102_xxx[4];
+	u32 card_a_intr;
+	u32 card_a_stat;
+	u32 card_a_ctrl;
+	u32 card_a_xxx;
+	u32 card_b_intr;
+	u32 card_b_stat;
+	u32 card_b_ctrl;
+	u32 card_b_xxx;
+	u32 uctrl_intr;
+	u32 uctrl_data;
+	u32 uctrl_stat;
+	u32 uctrl_xxx;
+	u32 ts102_xxx[4];
 };
 
 /* Bits for uctrl_intr register */
@@ -186,17 +187,15 @@
   POWER_RESTART=0x83,
 };
 
-struct uctrl_driver {
-	struct uctrl_regs *regs;
+static struct uctrl_driver {
+	struct uctrl_regs __iomem *regs;
 	int irq;
 	int pending;
 	struct uctrl_status status;
-};
+} *global_driver;
 
-static struct uctrl_driver drv;
-
-static void uctrl_get_event_status(void);
-static void uctrl_get_external_status(void);
+static void uctrl_get_event_status(struct uctrl_driver *);
+static void uctrl_get_external_status(struct uctrl_driver *);
 
 static int
 uctrl_ioctl(struct inode *inode, struct file *file,
@@ -213,16 +212,14 @@
 uctrl_open(struct inode *inode, struct file *file)
 {
 	lock_kernel();
-	uctrl_get_event_status();
-	uctrl_get_external_status();
+	uctrl_get_event_status(global_driver);
+	uctrl_get_external_status(global_driver);
 	unlock_kernel();
 	return 0;
 }
 
 static irqreturn_t uctrl_interrupt(int irq, void *dev_id)
 {
-	struct uctrl_driver *driver = (struct uctrl_driver *)dev_id;
-	printk("in uctrl_interrupt\n");
 	return IRQ_HANDLED;
 }
 
@@ -244,11 +241,11 @@
 { \
   unsigned int i; \
   for (i = 0; i < 10000; i++) { \
-    if (UCTRL_STAT_TXNF_STA & driver->regs->uctrl_stat) \
+      if (UCTRL_STAT_TXNF_STA & sbus_readl(&driver->regs->uctrl_stat)) \
       break; \
   } \
   dprintk(("write data 0x%02x\n", value)); \
-  driver->regs->uctrl_data = value; \
+  sbus_writel(value, &driver->regs->uctrl_data); \
 }
 
 /* Wait for something to read, read it, then clear the bit */
@@ -257,24 +254,23 @@
   unsigned int i; \
   value = 0; \
   for (i = 0; i < 10000; i++) { \
-    if ((UCTRL_STAT_RXNE_STA & driver->regs->uctrl_stat) == 0) \
+      if ((UCTRL_STAT_RXNE_STA & sbus_readl(&driver->regs->uctrl_stat)) == 0) \
       break; \
     udelay(1); \
   } \
-  value = driver->regs->uctrl_data; \
+  value = sbus_readl(&driver->regs->uctrl_data); \
   dprintk(("read data 0x%02x\n", value)); \
-  driver->regs->uctrl_stat = UCTRL_STAT_RXNE_STA; \
+  sbus_writel(UCTRL_STAT_RXNE_STA, &driver->regs->uctrl_stat); \
 }
 
-static void uctrl_do_txn(struct uctrl_txn *txn)
+static void uctrl_do_txn(struct uctrl_driver *driver, struct uctrl_txn *txn)
 {
-	struct uctrl_driver *driver = &drv;
 	int stat, incnt, outcnt, bytecnt, intr;
 	u32 byte;
 
-	stat = driver->regs->uctrl_stat;
-	intr = driver->regs->uctrl_intr;
-	driver->regs->uctrl_stat = stat;
+	stat = sbus_readl(&driver->regs->uctrl_stat);
+	intr = sbus_readl(&driver->regs->uctrl_intr);
+	sbus_writel(stat, &driver->regs->uctrl_stat);
 
 	dprintk(("interrupt stat 0x%x int 0x%x\n", stat, intr));
 
@@ -305,9 +301,8 @@
 	}
 }
 
-static void uctrl_get_event_status(void)
+static void uctrl_get_event_status(struct uctrl_driver *driver)
 {
-	struct uctrl_driver *driver = &drv;
 	struct uctrl_txn txn;
 	u8 outbits[2];
 
@@ -317,7 +312,7 @@
 	txn.inbuf = NULL;
 	txn.outbuf = outbits;
 
-	uctrl_do_txn(&txn);
+	uctrl_do_txn(driver, &txn);
 
 	dprintk(("bytes %x %x\n", (outbits[0] & 0xff), (outbits[1] & 0xff)));
 	driver->status.event_status = 
@@ -325,9 +320,8 @@
 	dprintk(("ev is %x\n", driver->status.event_status));
 }
 
-static void uctrl_get_external_status(void)
+static void uctrl_get_external_status(struct uctrl_driver *driver)
 {
-	struct uctrl_driver *driver = &drv;
 	struct uctrl_txn txn;
 	u8 outbits[2];
 	int i, v;
@@ -338,7 +332,7 @@
 	txn.inbuf = NULL;
 	txn.outbuf = outbits;
 
-	uctrl_do_txn(&txn);
+	uctrl_do_txn(driver, &txn);
 
 	dprintk(("bytes %x %x\n", (outbits[0] & 0xff), (outbits[1] & 0xff)));
 	driver->status.external_status = 
@@ -354,71 +348,101 @@
 	
 }
 
-static int __init ts102_uctrl_init(void)
+static int __devinit uctrl_probe(struct of_device *op,
+				 const struct of_device_id *match)
 {
-	struct uctrl_driver *driver = &drv;
-	int len;
-	struct linux_prom_irqs tmp_irq[2];
-        unsigned int vaddr[2] = { 0, 0 };
-	int tmpnode, uctrlnode = prom_getchild(prom_root_node);
-	int err;
+	struct uctrl_driver *p;
+	int err = -ENOMEM;
 
-	tmpnode = prom_searchsiblings(uctrlnode, "obio");
+	p = kzalloc(sizeof(*p), GFP_KERNEL);
+	if (!p) {
+		printk(KERN_ERR "uctrl: Unable to allocate device struct.\n");
+		goto out;
+	}
 
-	if (tmpnode)
-	  uctrlnode = prom_getchild(tmpnode);
+	p->regs = of_ioremap(&op->resource[0], 0,
+			     resource_size(&op->resource[0]),
+			     "uctrl");
+	if (!p->regs) {
+		printk(KERN_ERR "uctrl: Unable to map registers.\n");
+		goto out_free;
+	}
 
-	uctrlnode = prom_searchsiblings(uctrlnode, "uctrl");
-
-	if (!uctrlnode)
-		return -ENODEV;
-
-	/* the prom mapped it for us */
-	len = prom_getproperty(uctrlnode, "address", (void *) vaddr,
-			       sizeof(vaddr));
-	driver->regs = (struct uctrl_regs *)vaddr[0];
-
-	len = prom_getproperty(uctrlnode, "intr", (char *) tmp_irq,
-			       sizeof(tmp_irq));
-
-	/* Flush device */
-	READUCTLDATA(len);
-
-	if(!driver->irq) 
-		driver->irq = tmp_irq[0].pri;
-
-	err = request_irq(driver->irq, uctrl_interrupt, 0, "uctrl", driver);
+	p->irq = op->irqs[0];
+	err = request_irq(p->irq, uctrl_interrupt, 0, "uctrl", p);
 	if (err) {
-		printk("%s: unable to register irq %d\n",
-		       __func__, driver->irq);
-		return err;
+		printk(KERN_ERR "uctrl: Unable to register irq.\n");
+		goto out_iounmap;
 	}
 
-	if (misc_register(&uctrl_dev)) {
-		printk("%s: unable to get misc minor %d\n",
-		       __func__, uctrl_dev.minor);
-		free_irq(driver->irq, driver);
-		return -ENODEV;
+	err = misc_register(&uctrl_dev);
+	if (err) {
+		printk(KERN_ERR "uctrl: Unable to register misc device.\n");
+		goto out_free_irq;
 	}
 
-	driver->regs->uctrl_intr = UCTRL_INTR_RXNE_REQ|UCTRL_INTR_RXNE_MSK;
-	printk("uctrl: 0x%p (irq %d)\n", driver->regs, driver->irq);
-	uctrl_get_event_status();
-	uctrl_get_external_status();
-        return 0;
+	sbus_writel(UCTRL_INTR_RXNE_REQ|UCTRL_INTR_RXNE_MSK, &p->regs->uctrl_intr);
+	printk(KERN_INFO "%s: uctrl regs[0x%p] (irq %d)\n",
+	       op->node->full_name, p->regs, p->irq);
+	uctrl_get_event_status(p);
+	uctrl_get_external_status(p);
+
+	dev_set_drvdata(&op->dev, p);
+	global_driver = p;
+
+out:
+	return err;
+
+out_free_irq:
+	free_irq(p->irq, p);
+
+out_iounmap:
+	of_iounmap(&op->resource[0], p->regs, resource_size(&op->resource[0]));
+
+out_free:
+	kfree(p);
+	goto out;
 }
 
-static void __exit ts102_uctrl_cleanup(void)
+static int __devexit uctrl_remove(struct of_device *op)
 {
-	struct uctrl_driver *driver = &drv;
+	struct uctrl_driver *p = dev_get_drvdata(&op->dev);
 
-	misc_deregister(&uctrl_dev);
-	if (driver->irq)
-		free_irq(driver->irq, driver);
-	if (driver->regs)
-		driver->regs = NULL;
+	if (p) {
+		misc_deregister(&uctrl_dev);
+		free_irq(p->irq, p);
+		of_iounmap(&op->resource[0], p->regs, resource_size(&op->resource[0]));
+		kfree(p);
+	}
+	return 0;
 }
 
-module_init(ts102_uctrl_init);
-module_exit(ts102_uctrl_cleanup);
+static const struct of_device_id uctrl_match[] = {
+	{
+		.name = "uctrl",
+	},
+	{},
+};
+MODULE_DEVICE_TABLE(of, uctrl_match);
+
+static struct of_platform_driver uctrl_driver = {
+	.name		= "uctrl",
+	.match_table	= uctrl_match,
+	.probe		= uctrl_probe,
+	.remove		= __devexit_p(uctrl_remove),
+};
+
+
+static int __init uctrl_init(void)
+{
+	return of_register_driver(&uctrl_driver, &of_bus_type);
+}
+
+static void __exit uctrl_exit(void)
+{
+	of_unregister_driver(&uctrl_driver);
+}
+
+module_init(uctrl_init);
+module_exit(uctrl_exit);
 MODULE_LICENSE("GPL");
diff --git a/drivers/sbus/char/vfc.h b/drivers/sbus/char/vfc.h
deleted file mode 100644
index a5240c5..0000000
--- a/drivers/sbus/char/vfc.h
+++ /dev/null
@@ -1,171 +0,0 @@
-#ifndef _LINUX_VFC_H_
-#define _LINUX_VFC_H_
-
-/*
- * The control register for the vfc is at offset 0x4000
- * The first field ram bank is located at offset 0x5000
- * The second field ram bank is at offset 0x7000
- * i2c_reg address the Phillips PCF8584(see notes in vfc_i2c.c) 
- *    data and transmit register.
- * i2c_s1 controls register s1 of the PCF8584
- * i2c_write seems to be similar to i2c_write but I am not 
- *    quite sure why sun uses it
- * 
- * I am also not sure whether or not you can read the fram bank as a
- * whole or whether you must read each word individually from offset
- * 0x5000 as soon as I figure it out I will update this file */
-
-struct vfc_regs {
-	char pad1[0x4000];
-	unsigned int control;  /* Offset 0x4000 */
-	char pad2[0xffb];      /* from offset 0x4004 to 0x5000 */
-	unsigned int fram_bank1; /* Offset 0x5000 */
-	char pad3[0xffb];        /* from offset 0x5004 to 0x6000 */
-	unsigned int i2c_reg; /* Offset 0x6000 */
-	unsigned int i2c_magic2; /* Offset 0x6004 */
-	unsigned int i2c_s1;  /* Offset 0x6008 */
-	unsigned int i2c_write; /* Offset 0x600c */
-	char pad4[0xff0];     /* from offset 0x6010 to 0x7000 */
-	unsigned int fram_bank2; /* Offset 0x7000 */
-	char pad5[0x1000];
-};
-
-#define VFC_SAA9051_NR (13)
-#define VFC_SAA9051_ADDR (0x8a)
-	/* The saa9051 returns the following for its status 
-	 * bit 0 - 0
-	 * bit 1 - SECAM color detected (1=found,0=not found)
-	 * bit 2 - COLOR detected (1=found,0=not found)
-	 * bit 3 - 0
-	 * bit 4 - Field frequency bit (1=60Hz (NTSC), 0=50Hz (PAL))
-	 * bit 5 - 1
-	 * bit 6 - horizontal frequency lock (1=transmitter found,
-	 *                                    0=no transmitter)
-	 * bit 7 - Power on reset bit (1=reset,0=at least one successful 
-	 *                                       read of the status byte)
-	 */
-
-#define VFC_SAA9051_PONRES (0x80)
-#define VFC_SAA9051_HLOCK (0x40)
-#define VFC_SAA9051_FD (0x10)
-#define VFC_SAA9051_CD (0x04)
-#define VFC_SAA9051_CS (0x02)
-
-
-/* The various saa9051 sub addresses */
-
-#define VFC_SAA9051_IDEL (0) 
-#define VFC_SAA9051_HSY_START (1)
-#define VFC_SAA9051_HSY_STOP (2)
-#define VFC_SAA9051_HC_START (3)
-#define VFC_SAA9051_HC_STOP (4)
-#define VFC_SAA9051_HS_START (5)
-#define VFC_SAA9051_HORIZ_PEAK (6)
-#define VFC_SAA9051_HUE (7)
-#define VFC_SAA9051_C1 (8)
-#define VFC_SAA9051_C2 (9)
-#define VFC_SAA9051_C3 (0xa)
-#define VFC_SAA9051_SECAM_DELAY (0xb)
-
-
-/* Bit settings for saa9051 sub address 0x06 */
-
-#define VFC_SAA9051_AP1 (0x01)
-#define VFC_SAA9051_AP2 (0x02)
-#define VFC_SAA9051_COR1 (0x04)
-#define VFC_SAA9051_COR2 (0x08)
-#define VFC_SAA9051_BP1 (0x10)
-#define VFC_SAA9051_BP2 (0x20)
-#define VFC_SAA9051_PF (0x40)
-#define VFC_SAA9051_BY (0x80)
-
-
-/* Bit settings for saa9051 sub address 0x08 */
-
-#define VFC_SAA9051_CCFR0 (0x01)
-#define VFC_SAA9051_CCFR1 (0x02)
-#define VFC_SAA9051_YPN (0x04)
-#define VFC_SAA9051_ALT (0x08)
-#define VFC_SAA9051_CO (0x10)
-#define VFC_SAA9051_VTR (0x20)
-#define VFC_SAA9051_FS (0x40)
-#define VFC_SAA9051_HPLL (0x80)
-
-
-/* Bit settings for saa9051 sub address 9 */
-
-#define VFC_SAA9051_SS0 (0x01)
-#define VFC_SAA9051_SS1 (0x02)
-#define VFC_SAA9051_AFCC (0x04)
-#define VFC_SAA9051_CI (0x08)
-#define VFC_SAA9051_SA9D4 (0x10) /* Don't care bit */
-#define VFC_SAA9051_OEC (0x20)
-#define VFC_SAA9051_OEY (0x40)
-#define VFC_SAA9051_VNL (0x80)
-
-
-/* Bit settings for saa9051 sub address 0x0A */
-
-#define VFC_SAA9051_YDL0 (0x01)
-#define VFC_SAA9051_YDL1 (0x02)
-#define VFC_SAA9051_YDL2 (0x04)
-#define VFC_SAA9051_SS2 (0x08)
-#define VFC_SAA9051_SS3 (0x10)
-#define VFC_SAA9051_YC (0x20)
-#define VFC_SAA9051_CT (0x40)
-#define VFC_SAA9051_SYC (0x80)
-
-
-#define VFC_SAA9051_SA(a,b) ((a)->saa9051_state_array[(b)+1])
-#define vfc_update_saa9051(a) (vfc_i2c_sendbuf((a),VFC_SAA9051_ADDR,\
-					    (a)->saa9051_state_array,\
-					    VFC_SAA9051_NR))
-
-
-struct vfc_dev {
-	volatile struct vfc_regs __iomem *regs;
-	struct vfc_regs *phys_regs;
-	unsigned int control_reg;
-	struct mutex device_lock_mtx;
-	int instance;
-	int busy;
-	unsigned long which_io;
-	unsigned char saa9051_state_array[VFC_SAA9051_NR];
-};
-
-void captstat_reset(struct vfc_dev *);
-void memptr_reset(struct vfc_dev *);
-
-int vfc_pcf8584_init(struct vfc_dev *);
-void vfc_i2c_delay_no_busy(struct vfc_dev *, unsigned long);
-void vfc_i2c_delay(struct vfc_dev *);
-int vfc_i2c_sendbuf(struct vfc_dev *, unsigned char, char *, int) ;
-int vfc_i2c_recvbuf(struct vfc_dev *, unsigned char, char *, int) ;
-int vfc_i2c_reset_bus(struct vfc_dev *);
-int vfc_init_i2c_bus(struct vfc_dev *);
-
-#define VFC_CONTROL_DIAGMODE  0x10000000
-#define VFC_CONTROL_MEMPTR    0x20000000
-#define VFC_CONTROL_CAPTURE   0x02000000
-#define VFC_CONTROL_CAPTRESET 0x04000000
-
-#define VFC_STATUS_CAPTURE    0x08000000
-
-#ifdef VFC_IOCTL_DEBUG
-#define VFC_IOCTL_DEBUG_PRINTK(a) printk a
-#else
-#define VFC_IOCTL_DEBUG_PRINTK(a)
-#endif
-
-#ifdef VFC_I2C_DEBUG
-#define VFC_I2C_DEBUG_PRINTK(a) printk a
-#else
-#define VFC_I2C_DEBUG_PRINTK(a)
-#endif
-
-#endif /* _LINUX_VFC_H_ */
-
-
-
-
-
diff --git a/drivers/sbus/char/vfc_dev.c b/drivers/sbus/char/vfc_dev.c
deleted file mode 100644
index 25181bb..0000000
--- a/drivers/sbus/char/vfc_dev.c
+++ /dev/null
@@ -1,736 +0,0 @@
-/*
- * drivers/sbus/char/vfc_dev.c
- *
- * Driver for the Videopix Frame Grabber.
- * 
- * In order to use the VFC you need to program the video controller
- * chip. This chip is the Phillips SAA9051.  You need to call their
- * documentation ordering line to get the docs.
- *
- * There is very little documentation on the VFC itself.  There is
- * some useful info that can be found in the manuals that come with
- * the card.  I will hopefully write some better docs at a later date.
- *
- * Copyright (C) 1996 Manish Vachharajani (mvachhar@noc.rutgers.edu)
- * */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <linux/errno.h>
-#include <linux/fs.h>
-#include <linux/delay.h>
-#include <linux/spinlock.h>
-#include <linux/mutex.h>
-#include <linux/mm.h>
-#include <linux/smp_lock.h>
-
-#include <asm/openprom.h>
-#include <asm/oplib.h>
-#include <asm/io.h>
-#include <asm/system.h>
-#include <asm/sbus.h>
-#include <asm/page.h>
-#include <asm/pgtable.h>
-#include <asm/uaccess.h>
-
-#define VFC_MAJOR (60)
-
-#if 0
-#define VFC_IOCTL_DEBUG
-#endif
-
-#include "vfc.h"
-#include <asm/vfc_ioctls.h>
-
-static const struct file_operations vfc_fops;
-static struct vfc_dev **vfc_dev_lst;
-static char vfcstr[]="vfc";
-static unsigned char saa9051_init_array[VFC_SAA9051_NR] = {
-	0x00, 0x64, 0x72, 0x52,
-	0x36, 0x18, 0xff, 0x20,
-	0xfc, 0x77, 0xe3, 0x50,
-	0x3e
-};
-
-static void vfc_lock_device(struct vfc_dev *dev)
-{
-	mutex_lock(&dev->device_lock_mtx);
-}
-
-static void vfc_unlock_device(struct vfc_dev *dev)
-{
-	mutex_unlock(&dev->device_lock_mtx);
-}
-
-
-static void vfc_captstat_reset(struct vfc_dev *dev)
-{
-	dev->control_reg |= VFC_CONTROL_CAPTRESET;
-	sbus_writel(dev->control_reg, &dev->regs->control);
-	dev->control_reg &= ~VFC_CONTROL_CAPTRESET;
-	sbus_writel(dev->control_reg, &dev->regs->control);
-	dev->control_reg |= VFC_CONTROL_CAPTRESET;
-	sbus_writel(dev->control_reg, &dev->regs->control);
-}
-
-static void vfc_memptr_reset(struct vfc_dev *dev)
-{
-	dev->control_reg |= VFC_CONTROL_MEMPTR;
-	sbus_writel(dev->control_reg, &dev->regs->control);
-	dev->control_reg &= ~VFC_CONTROL_MEMPTR;
-	sbus_writel(dev->control_reg, &dev->regs->control);
-	dev->control_reg |= VFC_CONTROL_MEMPTR; 
-	sbus_writel(dev->control_reg, &dev->regs->control);
-}
-
-static int vfc_csr_init(struct vfc_dev *dev)
-{
-	dev->control_reg = 0x80000000;
-	sbus_writel(dev->control_reg, &dev->regs->control);
-	udelay(200); 
-	dev->control_reg &= ~0x80000000;
-	sbus_writel(dev->control_reg, &dev->regs->control);
-	udelay(100); 
-	sbus_writel(0x0f000000, &dev->regs->i2c_magic2);
-
-	vfc_memptr_reset(dev);
-
-	dev->control_reg &= ~VFC_CONTROL_DIAGMODE;
-	dev->control_reg &= ~VFC_CONTROL_CAPTURE;
-	dev->control_reg |= 0x40000000;
-	sbus_writel(dev->control_reg, &dev->regs->control);
-
-	vfc_captstat_reset(dev);
-
-	return 0;
-}
-
-static int vfc_saa9051_init(struct vfc_dev *dev)
-{
-	int i;
-
-	for (i = 0; i < VFC_SAA9051_NR; i++)
-		dev->saa9051_state_array[i] = saa9051_init_array[i];
-
-	vfc_i2c_sendbuf(dev,VFC_SAA9051_ADDR,
-			dev->saa9051_state_array, VFC_SAA9051_NR);
-	return 0;
-}
-
-static int init_vfc_hw(struct vfc_dev *dev)
-{
-	vfc_lock_device(dev);
-	vfc_csr_init(dev);
-
-	vfc_pcf8584_init(dev);
-	vfc_init_i2c_bus(dev); /* hopefully this doesn't undo the magic
-				  sun code above*/
-	vfc_saa9051_init(dev);
-	vfc_unlock_device(dev);
-	return 0; 
-}
-
-static int init_vfc_devstruct(struct vfc_dev *dev, int instance)
-{
-	dev->instance=instance;
-	mutex_init(&dev->device_lock_mtx);
-	dev->control_reg=0;
-	dev->busy=0;
-	return 0;
-}
-
-static int init_vfc_device(struct sbus_dev *sdev,struct vfc_dev *dev,
-			   int instance)
-{
-	if(dev == NULL) {
-		printk(KERN_ERR "VFC: Bogus pointer passed\n");
-		return -ENOMEM;
-	}
-	printk("Initializing vfc%d\n",instance);
-	dev->regs = NULL;
-	dev->regs = (volatile struct vfc_regs __iomem *)
-		sbus_ioremap(&sdev->resource[0], 0,
-			     sizeof(struct vfc_regs), vfcstr);
-	dev->which_io = sdev->reg_addrs[0].which_io;
-	dev->phys_regs = (struct vfc_regs *) sdev->reg_addrs[0].phys_addr;
-	if (dev->regs == NULL)
-		return -EIO;
-
-	printk("vfc%d: registers mapped at phys_addr: 0x%lx\n    virt_addr: 0x%lx\n",
-	       instance,(unsigned long)sdev->reg_addrs[0].phys_addr,(unsigned long)dev->regs);
-
-	if (init_vfc_devstruct(dev, instance))
-		return -EINVAL;
-	if (init_vfc_hw(dev))
-		return -EIO;
-	return 0;
-}
-
-
-static struct vfc_dev *vfc_get_dev_ptr(int instance)
-{
-	return vfc_dev_lst[instance];
-}
-
-static DEFINE_SPINLOCK(vfc_dev_lock);
-
-static int vfc_open(struct inode *inode, struct file *file) 
-{
-	struct vfc_dev *dev;
-
-	lock_kernel();
-	spin_lock(&vfc_dev_lock);
-	dev = vfc_get_dev_ptr(iminor(inode));
-	if (dev == NULL) {
-		spin_unlock(&vfc_dev_lock);
-		unlock_kernel();
-		return -ENODEV;
-	}
-	if (dev->busy) {
-		spin_unlock(&vfc_dev_lock);
-		unlock_kernel();
-		return -EBUSY;
-	}
-
-	dev->busy = 1;
-	spin_unlock(&vfc_dev_lock);
-
-	vfc_lock_device(dev);
-	
-	vfc_csr_init(dev);
-	vfc_pcf8584_init(dev);
-	vfc_init_i2c_bus(dev);
-	vfc_saa9051_init(dev);
-	vfc_memptr_reset(dev);
-	vfc_captstat_reset(dev);
-	
-	vfc_unlock_device(dev);
-	unlock_kernel();
-	return 0;
-}
-
-static int vfc_release(struct inode *inode,struct file *file) 
-{
-	struct vfc_dev *dev;
-
-	spin_lock(&vfc_dev_lock);
-	dev = vfc_get_dev_ptr(iminor(inode));
-	if (!dev || !dev->busy) {
-		spin_unlock(&vfc_dev_lock);
-		return -EINVAL;
-	}
-	dev->busy = 0;
-	spin_unlock(&vfc_dev_lock);
-	return 0;
-}
-
-static int vfc_debug(struct vfc_dev *dev, int cmd, void __user *argp)
-{
-	struct vfc_debug_inout inout;
-	unsigned char *buffer;
-
-	if (!capable(CAP_SYS_ADMIN))
-		return -EPERM;
-
-	switch(cmd) {
-	case VFC_I2C_SEND:
-		if(copy_from_user(&inout, argp, sizeof(inout)))
-			return -EFAULT;
-
-		buffer = kmalloc(inout.len, GFP_KERNEL);
-		if (buffer == NULL)
-			return -ENOMEM;
-
-		if(copy_from_user(buffer, inout.buffer, inout.len)) {
-			kfree(buffer);
-			return -EFAULT;
-		}
-		
-
-		vfc_lock_device(dev);
-		inout.ret=
-			vfc_i2c_sendbuf(dev,inout.addr & 0xff,
-					buffer,inout.len);
-
-		if (copy_to_user(argp,&inout,sizeof(inout))) {
-			vfc_unlock_device(dev);
-			kfree(buffer);
-			return -EFAULT;
-		}
-		vfc_unlock_device(dev);
-
-		break;
-	case VFC_I2C_RECV:
-		if (copy_from_user(&inout, argp, sizeof(inout)))
-			return -EFAULT;
-
-		buffer = kzalloc(inout.len, GFP_KERNEL);
-		if (buffer == NULL)
-			return -ENOMEM;
-
-		vfc_lock_device(dev);
-		inout.ret=
-			vfc_i2c_recvbuf(dev,inout.addr & 0xff
-					,buffer,inout.len);
-		vfc_unlock_device(dev);
-		
-		if (copy_to_user(inout.buffer, buffer, inout.len)) {
-			kfree(buffer);
-			return -EFAULT;
-		}
-		if (copy_to_user(argp,&inout,sizeof(inout))) {
-			kfree(buffer);
-			return -EFAULT;
-		}
-		kfree(buffer);
-		break;
-	default:
-		return -EINVAL;
-	};
-
-	return 0;
-}
-
-static int vfc_capture_start(struct vfc_dev *dev)
-{
-	vfc_captstat_reset(dev);
-	dev->control_reg = sbus_readl(&dev->regs->control);
-	if((dev->control_reg & VFC_STATUS_CAPTURE)) {
-		printk(KERN_ERR "vfc%d: vfc capture status not reset\n",
-		       dev->instance);
-		return -EIO;
-	}
-
-	vfc_lock_device(dev);
-	dev->control_reg &= ~VFC_CONTROL_CAPTURE;
-	sbus_writel(dev->control_reg, &dev->regs->control);
-	dev->control_reg |= VFC_CONTROL_CAPTURE;
-	sbus_writel(dev->control_reg, &dev->regs->control);
-	dev->control_reg &= ~VFC_CONTROL_CAPTURE;
-	sbus_writel(dev->control_reg, &dev->regs->control);
-	vfc_unlock_device(dev);
-
-	return 0;
-}
-
-static int vfc_capture_poll(struct vfc_dev *dev)
-{
-	int timeout = 1000;
-
-	while (!timeout--) {
-		if (sbus_readl(&dev->regs->control) & VFC_STATUS_CAPTURE)
-			break;
-		vfc_i2c_delay_no_busy(dev, 100);
-	}
-	if(!timeout) {
-		printk(KERN_WARNING "vfc%d: capture timed out\n",
-		       dev->instance);
-		return -ETIMEDOUT;
-	}
-	return 0;
-}
-
-
-
-static int vfc_set_control_ioctl(struct inode *inode, struct file *file, 
-			  struct vfc_dev *dev, unsigned long arg) 
-{
-	int setcmd, ret = 0;
-
-	if (copy_from_user(&setcmd,(void __user *)arg,sizeof(unsigned int)))
-		return -EFAULT;
-
-	VFC_IOCTL_DEBUG_PRINTK(("vfc%d: IOCTL(VFCSCTRL) arg=0x%x\n",
-				dev->instance,setcmd));
-
-	switch(setcmd) {
-	case MEMPRST:
-		vfc_lock_device(dev);
-		vfc_memptr_reset(dev);
-		vfc_unlock_device(dev);
-		ret=0;
-		break;
-	case CAPTRCMD:
-		vfc_capture_start(dev);
-		vfc_capture_poll(dev);
-		break;
-	case DIAGMODE:
-		if(capable(CAP_SYS_ADMIN)) {
-			vfc_lock_device(dev);
-			dev->control_reg |= VFC_CONTROL_DIAGMODE;
-			sbus_writel(dev->control_reg, &dev->regs->control);
-			vfc_unlock_device(dev);
-			ret = 0;
-		} else {
-			ret = -EPERM; 
-		}
-		break;
-	case NORMMODE:
-		vfc_lock_device(dev);
-		dev->control_reg &= ~VFC_CONTROL_DIAGMODE;
-		sbus_writel(dev->control_reg, &dev->regs->control);
-		vfc_unlock_device(dev);
-		ret = 0;
-		break;
-	case CAPTRSTR:
-		vfc_capture_start(dev);
-		ret = 0;
-		break;
-	case CAPTRWAIT:
-		vfc_capture_poll(dev);
-		ret = 0;
-		break;
-	default:
-		ret = -EINVAL;
-		break;
-	};
-
-	return ret;
-}
-
-
-static int vfc_port_change_ioctl(struct inode *inode, struct file *file,
-				 struct vfc_dev *dev, unsigned long arg)
-{
-	int ret = 0;
-	int cmd;
-
-	if(copy_from_user(&cmd, (void __user *)arg, sizeof(unsigned int))) {
-		VFC_IOCTL_DEBUG_PRINTK(("vfc%d: User passed bogus pointer to "
-					"vfc_port_change_ioctl\n",
-					dev->instance));
-		return -EFAULT;
-	}
-	
-	VFC_IOCTL_DEBUG_PRINTK(("vfc%d: IOCTL(VFCPORTCHG) arg=0x%x\n",
-				dev->instance, cmd));
-
-	switch(cmd) {
-	case 1:
-	case 2:
-		VFC_SAA9051_SA(dev,VFC_SAA9051_HSY_START) = 0x72; 
-		VFC_SAA9051_SA(dev,VFC_SAA9051_HSY_STOP) = 0x52;
-		VFC_SAA9051_SA(dev,VFC_SAA9051_HC_START) = 0x36;
-		VFC_SAA9051_SA(dev,VFC_SAA9051_HC_STOP) = 0x18;
-		VFC_SAA9051_SA(dev,VFC_SAA9051_HORIZ_PEAK) = VFC_SAA9051_BP2;
-		VFC_SAA9051_SA(dev,VFC_SAA9051_C3) = VFC_SAA9051_CT | VFC_SAA9051_SS3;
-		VFC_SAA9051_SA(dev,VFC_SAA9051_SECAM_DELAY) = 0x3e;
-		break;
-	case 3:
-		VFC_SAA9051_SA(dev,VFC_SAA9051_HSY_START) = 0x3a;
-		VFC_SAA9051_SA(dev,VFC_SAA9051_HSY_STOP) = 0x17;
-		VFC_SAA9051_SA(dev,VFC_SAA9051_HC_START) = 0xfa;
-		VFC_SAA9051_SA(dev,VFC_SAA9051_HC_STOP) = 0xde;
-		VFC_SAA9051_SA(dev,VFC_SAA9051_HORIZ_PEAK) =
-			VFC_SAA9051_BY | VFC_SAA9051_PF | VFC_SAA9051_BP2;
-		VFC_SAA9051_SA(dev,VFC_SAA9051_C3) = VFC_SAA9051_YC;
-		VFC_SAA9051_SA(dev,VFC_SAA9051_SECAM_DELAY) = 0;
-		VFC_SAA9051_SA(dev,VFC_SAA9051_C2) &=
-			~(VFC_SAA9051_SS0 | VFC_SAA9051_SS1);
-		break;
-	default:
-		ret = -EINVAL;
-		return ret;
-		break;
-	}
-
-	switch(cmd) {
-	case 1:
-		VFC_SAA9051_SA(dev,VFC_SAA9051_C2) |=
-			(VFC_SAA9051_SS0 | VFC_SAA9051_SS1);
-		break;
-	case 2:
-		VFC_SAA9051_SA(dev,VFC_SAA9051_C2) &=
-			~(VFC_SAA9051_SS0 | VFC_SAA9051_SS1);
-		VFC_SAA9051_SA(dev,VFC_SAA9051_C2) |= VFC_SAA9051_SS0; 
-		break;
-	case 3:
-		break;
-	default:
-		ret = -EINVAL;
-		return ret;
-		break;
-	}
-	VFC_SAA9051_SA(dev,VFC_SAA9051_C3) &= ~(VFC_SAA9051_SS2);
-	ret=vfc_update_saa9051(dev);
-	udelay(500);
-	VFC_SAA9051_SA(dev,VFC_SAA9051_C3) |= (VFC_SAA9051_SS2);
-	ret=vfc_update_saa9051(dev);
-	return ret;
-}
-
-static int vfc_set_video_ioctl(struct inode *inode, struct file *file,
-			       struct vfc_dev *dev, unsigned long arg)
-{
-	int ret = 0;
-	int cmd;
-
-	if(copy_from_user(&cmd, (void __user *)arg, sizeof(unsigned int))) {
-		VFC_IOCTL_DEBUG_PRINTK(("vfc%d: User passed bogus pointer to "
-					"vfc_set_video_ioctl\n",
-					dev->instance));
-		return ret;
-	}
-	
-	VFC_IOCTL_DEBUG_PRINTK(("vfc%d: IOCTL(VFCSVID) arg=0x%x\n",
-				dev->instance, cmd));
-	switch(cmd) {
-	case STD_NTSC:
-		VFC_SAA9051_SA(dev,VFC_SAA9051_C1) &= ~VFC_SAA9051_ALT;
-		VFC_SAA9051_SA(dev,VFC_SAA9051_C1) |= VFC_SAA9051_YPN | 
-			VFC_SAA9051_CCFR0 | VFC_SAA9051_CCFR1 | VFC_SAA9051_FS;
-		ret = vfc_update_saa9051(dev);
-		break;
-	case STD_PAL:
-		VFC_SAA9051_SA(dev,VFC_SAA9051_C1) &= ~(VFC_SAA9051_YPN | 
-							VFC_SAA9051_CCFR1 | 
-							VFC_SAA9051_CCFR0 |
-							VFC_SAA9051_FS);
-		VFC_SAA9051_SA(dev,VFC_SAA9051_C1) |= VFC_SAA9051_ALT;
-		ret = vfc_update_saa9051(dev);
-		break;
-
-	case COLOR_ON:
-		VFC_SAA9051_SA(dev,VFC_SAA9051_C1) |= VFC_SAA9051_CO;
-		VFC_SAA9051_SA(dev,VFC_SAA9051_HORIZ_PEAK) &=
-			~(VFC_SAA9051_BY | VFC_SAA9051_PF);
-		ret = vfc_update_saa9051(dev);
-		break;
-	case MONO:
-		VFC_SAA9051_SA(dev,VFC_SAA9051_C1) &= ~(VFC_SAA9051_CO);
-		VFC_SAA9051_SA(dev,VFC_SAA9051_HORIZ_PEAK) |=
-			(VFC_SAA9051_BY | VFC_SAA9051_PF);
-		ret = vfc_update_saa9051(dev);
-		break;
-	default:
-		ret = -EINVAL;
-		break;
-	};
-
-	return ret;
-}
-
-static int vfc_get_video_ioctl(struct inode *inode, struct file *file,
-			       struct vfc_dev *dev, unsigned long arg)
-{
-	int ret = 0;
-	unsigned int status = NO_LOCK;
-	unsigned char buf[1];
-
-	if(vfc_i2c_recvbuf(dev, VFC_SAA9051_ADDR, buf, 1)) {
-		printk(KERN_ERR "vfc%d: Unable to get status\n",
-		       dev->instance);
-		return -EIO;
-	}
-
-	if(buf[0] & VFC_SAA9051_HLOCK) {
-		status = NO_LOCK;
-	} else if(buf[0] & VFC_SAA9051_FD) {
-		if(buf[0] & VFC_SAA9051_CD)
-			status = NTSC_COLOR;
-		else
-			status = NTSC_NOCOLOR;
-	} else {
-		if(buf[0] & VFC_SAA9051_CD)
-			status = PAL_COLOR;
-		else
-			status = PAL_NOCOLOR;
-	}
-	VFC_IOCTL_DEBUG_PRINTK(("vfc%d: IOCTL(VFCGVID) returning status 0x%x; "
-				"buf[0]=%x\n", dev->instance, status, buf[0]));
-
-	if (copy_to_user((void __user *)arg,&status,sizeof(unsigned int))) {
-		VFC_IOCTL_DEBUG_PRINTK(("vfc%d: User passed bogus pointer to "
-					"vfc_get_video_ioctl\n",
-					dev->instance));
-		return ret;
-	}
-	return ret;
-}
-
-static int vfc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
-	      unsigned long arg) 
-{
-	int ret = 0;
-	unsigned int tmp;
-	struct vfc_dev *dev;
-	void __user *argp = (void __user *)arg;
-
-	dev = vfc_get_dev_ptr(iminor(inode));
-	if(dev == NULL)
-		return -ENODEV;
-	
-	switch(cmd & 0x0000ffff) {
-	case VFCGCTRL:
-#if 0
-		VFC_IOCTL_DEBUG_PRINTK(("vfc%d: IOCTL(VFCGCTRL)\n", dev->instance));
-#endif
-		tmp = sbus_readl(&dev->regs->control);
-		if(copy_to_user(argp, &tmp, sizeof(unsigned int))) {
-			ret = -EFAULT;
-			break;
-		}
-		ret = 0;
-		break;
-	case VFCSCTRL:
-		ret = vfc_set_control_ioctl(inode, file, dev, arg);
-		break;
-	case VFCGVID:
-		ret = vfc_get_video_ioctl(inode, file, dev, arg);
-		break;
-	case VFCSVID:
-		ret = vfc_set_video_ioctl(inode, file, dev, arg);
-		break;
-	case VFCHUE:
-		VFC_IOCTL_DEBUG_PRINTK(("vfc%d: IOCTL(VFCHUE)\n", dev->instance));
-		if(copy_from_user(&tmp,argp,sizeof(unsigned int))) {
-			VFC_IOCTL_DEBUG_PRINTK(("vfc%d: User passed bogus pointer "
-						"to IOCTL(VFCHUE)", dev->instance));
-			ret = -EFAULT;
-		} else {
-			VFC_SAA9051_SA(dev,VFC_SAA9051_HUE) = tmp;
-			vfc_update_saa9051(dev);
-			ret = 0;
-		}
-		break;
-	case VFCPORTCHG:
-		ret = vfc_port_change_ioctl(inode, file, dev, arg);
-		break;
-	case VFCRDINFO:
-		ret = -EINVAL;
-		VFC_IOCTL_DEBUG_PRINTK(("vfc%d: IOCTL(VFCRDINFO)\n", dev->instance));
-		break;
-	default:
-		ret = vfc_debug(vfc_get_dev_ptr(iminor(inode)), cmd, argp);
-		break;
-	};
-
-	return ret;
-}
-
-static int vfc_mmap(struct file *file, struct vm_area_struct *vma) 
-{
-	unsigned int map_size, ret, map_offset;
-	struct vfc_dev *dev;
-	
-	dev = vfc_get_dev_ptr(iminor(file->f_path.dentry->d_inode));
-	if(dev == NULL)
-		return -ENODEV;
-
-	map_size = vma->vm_end - vma->vm_start;
-	if(map_size > sizeof(struct vfc_regs)) 
-		map_size = sizeof(struct vfc_regs);
-
-	vma->vm_flags |=
-		(VM_MAYREAD | VM_MAYWRITE | VM_MAYSHARE);
-	map_offset = (unsigned int) (long)dev->phys_regs;
-	ret = io_remap_pfn_range(vma, vma->vm_start,
-				  MK_IOSPACE_PFN(dev->which_io,
-					map_offset >> PAGE_SHIFT),
-				  map_size, vma->vm_page_prot);
-
-	if(ret)
-		return -EAGAIN;
-
-	return 0;
-}
-
-
-static const struct file_operations vfc_fops = {
-	.owner =	THIS_MODULE,
-	.llseek =	no_llseek,
-	.ioctl =	vfc_ioctl,
-	.mmap =		vfc_mmap,
-	.open =		vfc_open,
-	.release =	vfc_release,
-};
-
-static int vfc_probe(void)
-{
-	struct sbus_bus *sbus;
-	struct sbus_dev *sdev = NULL;
-	int ret;
-	int instance = 0, cards = 0;
-
-	for_all_sbusdev(sdev, sbus) {
-		if (strcmp(sdev->prom_name, "vfc") == 0) {
-			cards++;
-			continue;
-		}
-	}
-
-	if (!cards)
-		return -ENODEV;
-
-	vfc_dev_lst = kcalloc(cards + 1, sizeof(struct vfc_dev*), GFP_KERNEL);
-	if (vfc_dev_lst == NULL)
-		return -ENOMEM;
-	vfc_dev_lst[cards] = NULL;
-
-	ret = register_chrdev(VFC_MAJOR, vfcstr, &vfc_fops);
-	if(ret) {
-		printk(KERN_ERR "Unable to get major number %d\n", VFC_MAJOR);
-		kfree(vfc_dev_lst);
-		return -EIO;
-	}
-	instance = 0;
-	for_all_sbusdev(sdev, sbus) {
-		if (strcmp(sdev->prom_name, "vfc") == 0) {
-			vfc_dev_lst[instance]=(struct vfc_dev *)
-				kmalloc(sizeof(struct vfc_dev), GFP_KERNEL);
-			if (vfc_dev_lst[instance] == NULL)
-				return -ENOMEM;
-			ret = init_vfc_device(sdev,
-					      vfc_dev_lst[instance],
-					      instance);
-			if(ret) {
-				printk(KERN_ERR "Unable to initialize"
-				       " vfc%d device\n",
-				       instance);
-			} else {
-			}
-		
-			instance++;
-			continue;
-		}
-	}
-
-	return 0;
-}
-
-#ifdef MODULE
-int init_module(void)
-#else 
-int vfc_init(void)
-#endif
-{
-	return vfc_probe();
-}
-
-#ifdef MODULE
-static void deinit_vfc_device(struct vfc_dev *dev)
-{
-	if(dev == NULL)
-		return;
-	sbus_iounmap(dev->regs, sizeof(struct vfc_regs));
-	kfree(dev);
-}
-
-void cleanup_module(void)
-{
-	struct vfc_dev **devp;
-
-	unregister_chrdev(VFC_MAJOR,vfcstr);
-
-	for (devp = vfc_dev_lst; *devp; devp++)
-		deinit_vfc_device(*devp);
-
-	kfree(vfc_dev_lst);
-	return;
-}
-#endif
-
-MODULE_LICENSE("GPL");
-
diff --git a/drivers/sbus/char/vfc_i2c.c b/drivers/sbus/char/vfc_i2c.c
deleted file mode 100644
index 32b986e..0000000
--- a/drivers/sbus/char/vfc_i2c.c
+++ /dev/null
@@ -1,335 +0,0 @@
-/*
- * drivers/sbus/char/vfc_i2c.c
- *
- * Driver for the Videopix Frame Grabber.
- * 
- * Functions that support the Phillips i2c(I squared C) bus on the vfc
- *  Documentation for the Phillips I2C bus can be found on the 
- *  phillips home page
- *
- * Copyright (C) 1996 Manish Vachharajani (mvachhar@noc.rutgers.edu)
- *
- */
-
-/* NOTE: It seems to me that the documentation regarding the
-pcd8584t/pcf8584 does not show the correct way to address the i2c bus.
-Based on the information on the I2C bus itself and the remainder of
-the Phillips docs the following algorithms appear to be correct.  I am
-fairly certain that the flowcharts in the phillips docs are wrong. */
-
-
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/wait.h>
-#include <linux/delay.h>
-#include <asm/openprom.h>
-#include <asm/oplib.h>
-#include <asm/io.h>
-#include <asm/system.h>
-#include <asm/sbus.h>
-
-#if 0 
-#define VFC_I2C_DEBUG
-#endif
-
-#include "vfc.h"
-#include "vfc_i2c.h"
-
-#define WRITE_S1(__val) \
-	sbus_writel(__val, &dev->regs->i2c_s1)
-#define WRITE_REG(__val) \
-	sbus_writel(__val, &dev->regs->i2c_reg)
-
-#define VFC_I2C_READ (0x1)
-#define VFC_I2C_WRITE (0x0)
-     
-/****** 
-  The i2c bus controller chip on the VFC is a pcd8584t, but
-  phillips claims it doesn't exist.  As far as I can tell it is
-  identical to the PCF8584 so I treat it like it is the pcf8584.
-  
-  NOTE: The pcf8584 only cares
-  about the msb of the word you feed it 
-*****/
-
-int vfc_pcf8584_init(struct vfc_dev *dev) 
-{
-	/* This will also choose register S0_OWN so we can set it. */
-	WRITE_S1(RESET);
-
-	/* The pcf8584 shifts this value left one bit and uses
-	 * it as its i2c bus address.
-	 */
-	WRITE_REG(0x55000000);
-
-	/* This will set the i2c bus at the same speed sun uses,
-	 * and set another magic bit.
-	 */
-	WRITE_S1(SELECT(S2));
-	WRITE_REG(0x14000000);
-	
-	/* Enable the serial port, idle the i2c bus and set
-	 * the data reg to s0.
-	 */
-	WRITE_S1(CLEAR_I2C_BUS);
-	udelay(100);
-	return 0;
-}
-
-void vfc_i2c_delay_no_busy(struct vfc_dev *dev, unsigned long usecs) 
-{
-	schedule_timeout_uninterruptible(usecs_to_jiffies(usecs));
-}
-
-void inline vfc_i2c_delay(struct vfc_dev *dev) 
-{ 
-	vfc_i2c_delay_no_busy(dev, 100);
-}
-
-int vfc_init_i2c_bus(struct vfc_dev *dev)
-{
-	WRITE_S1(ENABLE_SERIAL | SELECT(S0) | ACK);
-	vfc_i2c_reset_bus(dev);
-	return 0;
-}
-
-int vfc_i2c_reset_bus(struct vfc_dev *dev) 
-{
-	VFC_I2C_DEBUG_PRINTK((KERN_DEBUG "vfc%d: Resetting the i2c bus\n",
-			      dev->instance));
-	if(dev == NULL)
-		return -EINVAL;
-	if(dev->regs == NULL)
-		return -EINVAL;
-	WRITE_S1(SEND_I2C_STOP);
-	WRITE_S1(SEND_I2C_STOP | ACK);
-	vfc_i2c_delay(dev);
-	WRITE_S1(CLEAR_I2C_BUS);
-	VFC_I2C_DEBUG_PRINTK((KERN_DEBUG "vfc%d: I2C status %x\n",
-			      dev->instance,
-			      sbus_readl(&dev->regs->i2c_s1)));
-	return 0;
-}
-
-static int vfc_i2c_wait_for_bus(struct vfc_dev *dev)
-{
-	int timeout = 1000; 
-
-	while(!(sbus_readl(&dev->regs->i2c_s1) & BB)) {
-		if(!(timeout--))
-			return -ETIMEDOUT;
-		vfc_i2c_delay(dev);
-	}
-	return 0;
-}
-
-static int vfc_i2c_wait_for_pin(struct vfc_dev *dev, int ack)
-{
-	int timeout = 1000; 
-	int s1;
-
-	while ((s1 = sbus_readl(&dev->regs->i2c_s1)) & PIN) {
-		if (!(timeout--))
-			return -ETIMEDOUT;
-		vfc_i2c_delay(dev);
-	}
-	if (ack == VFC_I2C_ACK_CHECK) {
-		if(s1 & LRB)
-			return -EIO; 
-	}
-	return 0;
-}
-
-#define SHIFT(a) ((a) << 24)
-static int vfc_i2c_xmit_addr(struct vfc_dev *dev, unsigned char addr,
-			     char mode)
-{ 
-	int ret, raddr;
-#if 1
-	WRITE_S1(SEND_I2C_STOP | ACK);
-	WRITE_S1(SELECT(S0) | ENABLE_SERIAL);
-	vfc_i2c_delay(dev);
-#endif
-
-	switch(mode) {
-	case VFC_I2C_READ:
-		raddr = SHIFT(((unsigned int)addr | 0x1));
-		WRITE_REG(raddr);
-		VFC_I2C_DEBUG_PRINTK(("vfc%d: receiving from i2c addr 0x%x\n",
-				      dev->instance, addr | 0x1));
-		break;
-	case VFC_I2C_WRITE:
-		raddr = SHIFT((unsigned int)addr & ~0x1);
-		WRITE_REG(raddr);
-		VFC_I2C_DEBUG_PRINTK(("vfc%d: sending to i2c addr 0x%x\n",
-				      dev->instance, addr & ~0x1));
-		break;
-	default:
-		return -EINVAL;
-	};
-
-	WRITE_S1(SEND_I2C_START);
-	vfc_i2c_delay(dev);
-	ret = vfc_i2c_wait_for_pin(dev,VFC_I2C_ACK_CHECK); /* We wait
-							      for the
-							      i2c send
-							      to finish
-							      here but
-							      Sun
-							      doesn't,
-							      hmm */
-	if (ret) {
-		printk(KERN_ERR "vfc%d: VFC xmit addr timed out or no ack\n",
-		       dev->instance);
-		return ret;
-	} else if (mode == VFC_I2C_READ) {
-		if ((ret = sbus_readl(&dev->regs->i2c_reg) & 0xff000000) != raddr) {
-			printk(KERN_WARNING 
-			       "vfc%d: returned slave address "
-			       "mismatch(%x,%x)\n",
-			       dev->instance, raddr, ret);
-		}
-	}	
-	return 0;
-}
-
-static int vfc_i2c_xmit_byte(struct vfc_dev *dev,unsigned char *byte)
-{
-	int ret;
-	u32 val = SHIFT((unsigned int)*byte);
-
-	WRITE_REG(val);
-
-	ret = vfc_i2c_wait_for_pin(dev, VFC_I2C_ACK_CHECK); 
-	switch(ret) {
-	case -ETIMEDOUT: 
-		printk(KERN_ERR "vfc%d: VFC xmit byte timed out or no ack\n",
-		       dev->instance);
-		break;
-	case -EIO:
-		ret = XMIT_LAST_BYTE;
-		break;
-	default:
-		break;
-	};
-
-	return ret;
-}
-
-static int vfc_i2c_recv_byte(struct vfc_dev *dev, unsigned char *byte,
-			     int last)
-{
-	int ret;
-
-	if (last) {
-		WRITE_REG(NEGATIVE_ACK);
-		VFC_I2C_DEBUG_PRINTK(("vfc%d: sending negative ack\n",
-				      dev->instance));
-	} else {
-		WRITE_S1(ACK);
-	}
-
-	ret = vfc_i2c_wait_for_pin(dev, VFC_I2C_NO_ACK_CHECK);
-	if(ret) {
-		printk(KERN_ERR "vfc%d: "
-		       "VFC recv byte timed out\n",
-		       dev->instance);
-	}
-	*byte = (sbus_readl(&dev->regs->i2c_reg)) >> 24;
-	return ret;
-}
-
-int vfc_i2c_recvbuf(struct vfc_dev *dev, unsigned char addr,
-		    char *buf, int count)
-{
-	int ret, last;
-
-	if(!(count && buf && dev && dev->regs) )
-		return -EINVAL;
-
-	if ((ret = vfc_i2c_wait_for_bus(dev))) {
-		printk(KERN_ERR "vfc%d: VFC I2C bus busy\n", dev->instance);
-		return ret;
-	}
-
-	if ((ret = vfc_i2c_xmit_addr(dev, addr, VFC_I2C_READ))) {
-		WRITE_S1(SEND_I2C_STOP);
-		vfc_i2c_delay(dev);
-		return ret;
-	}
-	
-	last = 0;
-	while (count--) {
-		if (!count)
-			last = 1;
-		if ((ret = vfc_i2c_recv_byte(dev, buf, last))) {
-			printk(KERN_ERR "vfc%d: "
-			       "VFC error while receiving byte\n",
-			       dev->instance);
-			WRITE_S1(SEND_I2C_STOP);
-			ret = -EINVAL;
-		}
-		buf++;
-	}
-	WRITE_S1(SEND_I2C_STOP | ACK);
-	vfc_i2c_delay(dev);
-	return ret;
-}
-
-int vfc_i2c_sendbuf(struct vfc_dev *dev, unsigned char addr, 
-		    char *buf, int count) 
-{
-	int ret;
-	
-	if (!(buf && dev && dev->regs))
-		return -EINVAL;
-	
-	if ((ret = vfc_i2c_wait_for_bus(dev))) {
-		printk(KERN_ERR "vfc%d: VFC I2C bus busy\n", dev->instance);
-		return ret;
-	}
-	
-	if ((ret = vfc_i2c_xmit_addr(dev, addr, VFC_I2C_WRITE))) {
-		WRITE_S1(SEND_I2C_STOP);
-		vfc_i2c_delay(dev);
-		return ret;
-	}
-	
-	while(count--) {
-		ret = vfc_i2c_xmit_byte(dev, buf);
-		switch(ret) {
-		case XMIT_LAST_BYTE:
-			VFC_I2C_DEBUG_PRINTK(("vfc%d: "
-					      "Receiver ended transmission with "
-					      " %d bytes remaining\n",
-					      dev->instance, count));
-			ret = 0;
-			goto done;
-			break;
-		case 0:
-			break;
-		default:
-			printk(KERN_ERR "vfc%d: "
-			       "VFC error while sending byte\n", dev->instance);
-			break;
-		};
-
-		buf++;
-	}
-done:
-	WRITE_S1(SEND_I2C_STOP | ACK);
-	vfc_i2c_delay(dev);
-	return ret;
-}
-
-
-
-
-
-
-
-
-
diff --git a/drivers/sbus/char/vfc_i2c.h b/drivers/sbus/char/vfc_i2c.h
deleted file mode 100644
index a2e6973..0000000
--- a/drivers/sbus/char/vfc_i2c.h
+++ /dev/null
@@ -1,44 +0,0 @@
-#ifndef _LINUX_VFC_I2C_H_
-#define _LINUX_VFC_I2C_H_
-
-/* control bits */
-#define PIN  (0x80000000)
-#define ESO  (0x40000000)
-#define ES1  (0x20000000)
-#define ES2  (0x10000000)
-#define ENI  (0x08000000)
-#define STA  (0x04000000)
-#define STO  (0x02000000)
-#define ACK  (0x01000000)
-
-/* status bits */
-#define STS  (0x20000000)
-#define BER  (0x10000000)
-#define LRB  (0x08000000)
-#define AAS  (0x04000000)
-#define LAB  (0x02000000)
-#define BB   (0x01000000)
-
-#define SEND_I2C_START (PIN | ESO | STA)
-#define SEND_I2C_STOP (PIN | ESO | STO)
-#define CLEAR_I2C_BUS (PIN | ESO | ACK)
-#define NEGATIVE_ACK ((ESO) & ~ACK)
-
-#define SELECT(a) (a)
-#define S0 (PIN | ESO | ES1)
-#define S0_OWN (PIN)
-#define S2 (PIN | ES1)
-#define S3 (PIN | ES2)
-
-#define ENABLE_SERIAL (PIN | ESO)
-#define DISABLE_SERIAL (PIN)
-#define RESET (PIN)
-
-#define XMIT_LAST_BYTE (1)
-#define VFC_I2C_ACK_CHECK (1)
-#define VFC_I2C_NO_ACK_CHECK (0)
-
-#endif /* _LINUX_VFC_I2C_H_ */
-
-
-
diff --git a/drivers/sbus/dvma.c b/drivers/sbus/dvma.c
deleted file mode 100644
index ab0d2de..0000000
--- a/drivers/sbus/dvma.c
+++ /dev/null
@@ -1,136 +0,0 @@
-/* dvma.c:  Routines that are used to access DMA on the Sparc SBus.
- *
- * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
- */
-
-#include <linux/string.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-
-#include <asm/oplib.h>
-#include <asm/io.h>
-#include <asm/dma.h>
-#include <asm/sbus.h>
-
-struct sbus_dma *dma_chain;
-
-static void __init init_one_dvma(struct sbus_dma *dma, int num_dma)
-{
-	printk("dma%d: ", num_dma);
-	
-	dma->next = NULL;
-	dma->running = 0;      /* No transfers going on as of yet */
-	dma->allocated = 0;    /* No one has allocated us yet */
-	switch(sbus_readl(dma->regs + DMA_CSR)&DMA_DEVICE_ID) {
-	case DMA_VERS0:
-		dma->revision = dvmarev0;
-		printk("Revision 0 ");
-		break;
-	case DMA_ESCV1:
-		dma->revision = dvmaesc1;
-		printk("ESC Revision 1 ");
-		break;
-	case DMA_VERS1:
-		dma->revision = dvmarev1;
-		printk("Revision 1 ");
-		break;
-	case DMA_VERS2:
-		dma->revision = dvmarev2;
-		printk("Revision 2 ");
-		break;
-	case DMA_VERHME:
-		dma->revision = dvmahme;
-		printk("HME DVMA gate array ");
-		break;
-	case DMA_VERSPLUS:
-		dma->revision = dvmarevplus;
-		printk("Revision 1 PLUS ");
-		break;
-	default:
-		printk("unknown dma version %08x",
-		       sbus_readl(dma->regs + DMA_CSR) & DMA_DEVICE_ID);
-		dma->allocated = 1;
-		break;
-	}
-	printk("\n");
-}
-
-/* Probe this SBus DMA module(s) */
-void __init dvma_init(struct sbus_bus *sbus)
-{
-	struct sbus_dev *this_dev;
-	struct sbus_dma *dma;
-	struct sbus_dma *dchain;
-	static int num_dma = 0;
-
-	for_each_sbusdev(this_dev, sbus) {
-		char *name = this_dev->prom_name;
-		int hme = 0;
-
-		if(!strcmp(name, "SUNW,fas"))
-			hme = 1;
-		else if(strcmp(name, "dma") &&
-			strcmp(name, "ledma") &&
-			strcmp(name, "espdma"))
-			continue;
-
-		/* Found one... */
-		dma = kmalloc(sizeof(struct sbus_dma), GFP_ATOMIC);
-
-		dma->sdev = this_dev;
-
-		/* Put at end of dma chain */
-		dchain = dma_chain;
-		if(dchain) {
-			while(dchain->next)
-				dchain = dchain->next;
-			dchain->next = dma;
-		} else {
-			/* We're the first in line */
-			dma_chain = dma;
-		}
-
-		dma->regs = sbus_ioremap(&dma->sdev->resource[0], 0,
-					 dma->sdev->resource[0].end - dma->sdev->resource[0].start + 1,
-					 "dma");
-
-		dma->node = dma->sdev->prom_node;
-		
-		init_one_dvma(dma, num_dma++);
-	}
-}
-
-#ifdef CONFIG_SUN4
-
-#include <asm/sun4paddr.h>
-
-void __init sun4_dvma_init(void)
-{
-	struct sbus_dma *dma;
-	struct resource r;
-
-	if(sun4_dma_physaddr) {
-		dma = kmalloc(sizeof(struct sbus_dma), GFP_ATOMIC);
-
-		/* No SBUS */
-		dma->sdev = NULL;
-
-		/* Only one DMA device */
-		dma_chain = dma;
-
-		memset(&r, 0, sizeof(r));
-		r.start = sun4_dma_physaddr;
-		dma->regs = sbus_ioremap(&r, 0, PAGE_SIZE, "dma");
-
-		/* No prom node */
-		dma->node = 0x0;
-
-		init_one_dvma(dma, 0);
-	} else {
-	  	dma_chain = NULL;
-	}
-}
-
-#endif
diff --git a/drivers/sbus/sbus.c b/drivers/sbus/sbus.c
deleted file mode 100644
index 9c12924..0000000
--- a/drivers/sbus/sbus.c
+++ /dev/null
@@ -1,316 +0,0 @@
-/* sbus.c: SBus support routines.
- *
- * Copyright (C) 1995, 2006 David S. Miller (davem@davemloft.net)
- */
-
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-#include <linux/device.h>
-#include <linux/of_device.h>
-
-#include <asm/system.h>
-#include <asm/sbus.h>
-#include <asm/dma.h>
-#include <asm/oplib.h>
-#include <asm/prom.h>
-#include <asm/bpp.h>
-#include <asm/irq.h>
-
-static ssize_t
-show_sbusobppath_attr(struct device * dev, struct device_attribute * attr, char * buf)
-{
-	struct sbus_dev *sbus;
-
-	sbus = to_sbus_device(dev);
-
-	return snprintf (buf, PAGE_SIZE, "%s\n", sbus->ofdev.node->full_name);
-}
-
-static DEVICE_ATTR(obppath, S_IRUSR | S_IRGRP | S_IROTH, show_sbusobppath_attr, NULL);
-
-struct sbus_bus *sbus_root;
-
-static void __init fill_sbus_device(struct device_node *dp, struct sbus_dev *sdev)
-{
-	struct dev_archdata *sd;
-	unsigned long base;
-	const void *pval;
-	int len, err;
-
-	sdev->prom_node = dp->node;
-	strcpy(sdev->prom_name, dp->name);
-
-	pval = of_get_property(dp, "reg", &len);
-	sdev->num_registers = 0;
-	if (pval) {
-		memcpy(sdev->reg_addrs, pval, len);
-
-		sdev->num_registers =
-			len / sizeof(struct linux_prom_registers);
-
-		base = (unsigned long) sdev->reg_addrs[0].phys_addr;
-
-		/* Compute the slot number. */
-		if (base >= SUN_SBUS_BVADDR && sparc_cpu_model == sun4m)
-			sdev->slot = sbus_dev_slot(base);
-		else
-			sdev->slot = sdev->reg_addrs[0].which_io;
-	}
-
-	pval = of_get_property(dp, "ranges", &len);
-	sdev->num_device_ranges = 0;
-	if (pval) {
-		memcpy(sdev->device_ranges, pval, len);
-		sdev->num_device_ranges =
-			len / sizeof(struct linux_prom_ranges);
-	}
-
-	sbus_fill_device_irq(sdev);
-
-	sd = &sdev->ofdev.dev.archdata;
-	sd->prom_node = dp;
-	sd->op = &sdev->ofdev;
-
-	sdev->ofdev.node = dp;
-	if (sdev->parent)
-		sdev->ofdev.dev.parent = &sdev->parent->ofdev.dev;
-	else
-		sdev->ofdev.dev.parent = &sdev->bus->ofdev.dev;
-	sdev->ofdev.dev.bus = &sbus_bus_type;
-	dev_set_name(&sdev->ofdev.dev, "sbus[%08x]", dp->node);
-
-	if (of_device_register(&sdev->ofdev) != 0)
-		printk(KERN_DEBUG "sbus: device registration error for %s!\n",
-		       dp->path_component_name);
-
-	/* WE HAVE BEEN INVADED BY ALIENS! */
-	err = sysfs_create_file(&sdev->ofdev.dev.kobj, &dev_attr_obppath.attr);
-}
-
-static void __init sbus_bus_ranges_init(struct device_node *dp, struct sbus_bus *sbus)
-{
-	const void *pval;
-	int len;
-
-	pval = of_get_property(dp, "ranges", &len);
-	sbus->num_sbus_ranges = 0;
-	if (pval) {
-		memcpy(sbus->sbus_ranges, pval, len);
-		sbus->num_sbus_ranges =
-			len / sizeof(struct linux_prom_ranges);
-
-		sbus_arch_bus_ranges_init(dp->parent, sbus);
-	}
-}
-
-static void __init __apply_ranges_to_regs(struct linux_prom_ranges *ranges,
-					  int num_ranges,
-					  struct linux_prom_registers *regs,
-					  int num_regs)
-{
-	if (num_ranges) {
-		int regnum;
-
-		for (regnum = 0; regnum < num_regs; regnum++) {
-			int rngnum;
-
-			for (rngnum = 0; rngnum < num_ranges; rngnum++) {
-				if (regs[regnum].which_io == ranges[rngnum].ot_child_space)
-					break;
-			}
-			if (rngnum == num_ranges) {
-				/* We used to flag this as an error.  Actually
-				 * some devices do not report the regs as we expect.
-				 * For example, see SUNW,pln device.  In that case
-				 * the reg property is in a format internal to that
-				 * node, ie. it is not in the SBUS register space
-				 * per se. -DaveM
-				 */
-				return;
-			}
-			regs[regnum].which_io = ranges[rngnum].ot_parent_space;
-			regs[regnum].phys_addr -= ranges[rngnum].ot_child_base;
-			regs[regnum].phys_addr += ranges[rngnum].ot_parent_base;
-		}
-	}
-}
-
-static void __init __fixup_regs_sdev(struct sbus_dev *sdev)
-{
-	if (sdev->num_registers != 0) {
-		struct sbus_dev *parent = sdev->parent;
-		int i;
-
-		while (parent != NULL) {
-			__apply_ranges_to_regs(parent->device_ranges,
-					       parent->num_device_ranges,
-					       sdev->reg_addrs,
-					       sdev->num_registers);
-
-			parent = parent->parent;
-		}
-
-		__apply_ranges_to_regs(sdev->bus->sbus_ranges,
-				       sdev->bus->num_sbus_ranges,
-				       sdev->reg_addrs,
-				       sdev->num_registers);
-
-		for (i = 0; i < sdev->num_registers; i++) {
-			struct resource *res = &sdev->resource[i];
-
-			res->start = sdev->reg_addrs[i].phys_addr;
-			res->end = (res->start +
-				    (unsigned long)sdev->reg_addrs[i].reg_size - 1UL);
-			res->flags = IORESOURCE_IO |
-				(sdev->reg_addrs[i].which_io & 0xff);
-		}
-	}
-}
-
-static void __init sbus_fixup_all_regs(struct sbus_dev *first_sdev)
-{
-	struct sbus_dev *sdev;
-
-	for (sdev = first_sdev; sdev; sdev = sdev->next) {
-		if (sdev->child)
-			sbus_fixup_all_regs(sdev->child);
-		__fixup_regs_sdev(sdev);
-	}
-}
-
-/* We preserve the "probe order" of these bus and device lists to give
- * the same ordering as the old code.
- */
-static void __init sbus_insert(struct sbus_bus *sbus, struct sbus_bus **root)
-{
-	while (*root)
-		root = &(*root)->next;
-	*root = sbus;
-	sbus->next = NULL;
-}
-
-static void __init sdev_insert(struct sbus_dev *sdev, struct sbus_dev **root)
-{
-	while (*root)
-		root = &(*root)->next;
-	*root = sdev;
-	sdev->next = NULL;
-}
-
-static void __init walk_children(struct device_node *dp, struct sbus_dev *parent, struct sbus_bus *sbus)
-{
-	dp = dp->child;
-	while (dp) {
-		struct sbus_dev *sdev;
-
-		sdev = kzalloc(sizeof(struct sbus_dev), GFP_ATOMIC);
-		if (sdev) {
-			sdev_insert(sdev, &parent->child);
-
-			sdev->bus = sbus;
-			sdev->parent = parent;
-			sdev->ofdev.dev.archdata.iommu =
-				sbus->ofdev.dev.archdata.iommu;
-			sdev->ofdev.dev.archdata.stc =
-				sbus->ofdev.dev.archdata.stc;
-
-			fill_sbus_device(dp, sdev);
-
-			walk_children(dp, sdev, sbus);
-		}
-		dp = dp->sibling;
-	}
-}
-
-static void __init build_one_sbus(struct device_node *dp, int num_sbus)
-{
-	struct sbus_bus *sbus;
-	unsigned int sbus_clock;
-	struct device_node *dev_dp;
-
-	sbus = kzalloc(sizeof(struct sbus_bus), GFP_ATOMIC);
-	if (!sbus)
-		return;
-
-	sbus_insert(sbus, &sbus_root);
-	sbus->prom_node = dp->node;
-
-	sbus_setup_iommu(sbus, dp);
-
-	printk("sbus%d: ", num_sbus);
-
-	sbus_clock = of_getintprop_default(dp, "clock-frequency",
-					   (25*1000*1000));
-	sbus->clock_freq = sbus_clock;
-
-	printk("Clock %d.%d MHz\n", (int) ((sbus_clock/1000)/1000),
-	       (int) (((sbus_clock/1000)%1000 != 0) ? 
-		      (((sbus_clock/1000)%1000) + 1000) : 0));
-
-	strcpy(sbus->prom_name, dp->name);
-
-	sbus_setup_arch_props(sbus, dp);
-
-	sbus_bus_ranges_init(dp, sbus);
-
-	sbus->ofdev.node = dp;
-	sbus->ofdev.dev.parent = NULL;
-	sbus->ofdev.dev.bus = &sbus_bus_type;
-	dev_set_name(&sbus->ofdev.dev, "sbus%d", num_sbus);
-
-	if (of_device_register(&sbus->ofdev) != 0)
-		printk(KERN_DEBUG "sbus: device registration error for %s!\n",
-		       dev_name(&sbus->ofdev.dev));
-
-	dev_dp = dp->child;
-	while (dev_dp) {
-		struct sbus_dev *sdev;
-
-		sdev = kzalloc(sizeof(struct sbus_dev), GFP_ATOMIC);
-		if (sdev) {
-			sdev_insert(sdev, &sbus->devices);
-
-			sdev->bus = sbus;
-			sdev->parent = NULL;
-			sdev->ofdev.dev.archdata.iommu =
-				sbus->ofdev.dev.archdata.iommu;
-			sdev->ofdev.dev.archdata.stc =
-				sbus->ofdev.dev.archdata.stc;
-
-			fill_sbus_device(dev_dp, sdev);
-
-			walk_children(dev_dp, sdev, sbus);
-		}
-		dev_dp = dev_dp->sibling;
-	}
-
-	sbus_fixup_all_regs(sbus->devices);
-
-	dvma_init(sbus);
-}
-
-static int __init sbus_init(void)
-{
-	struct device_node *dp;
-	const char *sbus_name = "sbus";
-	int num_sbus = 0;
-
-	if (sbus_arch_preinit())
-		return 0;
-
-	if (sparc_cpu_model == sun4d)
-		sbus_name = "sbi";
-
-	for_each_node_by_name(dp, sbus_name) {
-		build_one_sbus(dp, num_sbus);
-		num_sbus++;
-
-	}
-
-	sbus_arch_postinit();
-
-	return 0;
-}
-
-subsys_initcall(sbus_init);
diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig
index 4e0322b..403ecad 100644
--- a/drivers/scsi/Kconfig
+++ b/drivers/scsi/Kconfig
@@ -1325,14 +1325,6 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called qlogicfas.
 
-config SCSI_QLOGIC_FC_FIRMWARE
-	bool "Include loadable firmware in driver"
-	depends on SCSI_QLOGIC_FC
-  	help
-	  Say Y to include ISP2X00 Fabric Initiator/Target Firmware, with
-	  expanded LUN addressing and FcTape (FCP-2) support, in the
-	  qlogicfc driver. This is required on some platforms.
-
 config SCSI_QLOGIC_1280
 	tristate "Qlogic QLA 1240/1x80/1x160 SCSI support"
 	depends on PCI && SCSI
@@ -1648,6 +1640,7 @@
 	tristate "Atari native SCSI support"
 	depends on ATARI && SCSI
 	select SCSI_SPI_ATTRS
+	select NVRAM
 	---help---
 	  If you have an Atari with built-in NCR5380 SCSI controller (TT,
 	  Falcon, ...) say Y to get it supported. Of course also, if you have
@@ -1678,14 +1671,6 @@
 	  boot process fractionally longer but may assist recovery from errors
 	  that leave the devices with SCSI operations partway completed.
 
-config TT_DMA_EMUL
-	bool "Hades SCSI DMA emulator"
-	depends on ATARI_SCSI && HADES
-	help
-	  This option enables code which emulates the TT SCSI DMA chip on the
-	  Hades. This increases the SCSI transfer rates at least ten times
-	  compared to PIO transfers.
-
 config MAC_SCSI
 	bool "Macintosh NCR5380 SCSI"
 	depends on MAC && SCSI=y
diff --git a/drivers/scsi/aacraid/aachba.c b/drivers/scsi/aacraid/aachba.c
index aa4e77c..8abfd06 100644
--- a/drivers/scsi/aacraid/aachba.c
+++ b/drivers/scsi/aacraid/aachba.c
@@ -1139,7 +1139,7 @@
 	srbcmd->id       = cpu_to_le32(scmd_id(cmd));
 	srbcmd->lun      = cpu_to_le32(cmd->device->lun);
 	srbcmd->flags    = cpu_to_le32(flag);
-	timeout = cmd->timeout_per_command/HZ;
+	timeout = cmd->request->timeout/HZ;
 	if (timeout == 0)
 		timeout = 1;
 	srbcmd->timeout  = cpu_to_le32(timeout);  // timeout in seconds
diff --git a/drivers/scsi/atari_dma_emul.c b/drivers/scsi/atari_dma_emul.c
deleted file mode 100644
index cdc710e..0000000
--- a/drivers/scsi/atari_dma_emul.c
+++ /dev/null
@@ -1,468 +0,0 @@
-/*
- * atari_dma_emul.c -- TT SCSI DMA emulator for the Hades.
- *
- * Copyright 1997 Wout Klaren <W.Klaren@inter.nl.net>
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file COPYING in the main directory of this archive
- * for more details.
- *
- * This code was written using the Hades TOS source code as a
- * reference. This source code can be found on the home page
- * of Medusa Computer Systems.
- *
- * Version 0.1, 1997-09-24.
- * 
- * This code should be considered experimental. It has only been
- * tested on a Hades with a 68060. It might not work on a Hades
- * with a 68040. Make backups of your hard drives before using
- * this code.
- */
-
-#include <linux/compiler.h>
-#include <asm/thread_info.h>
-#include <asm/uaccess.h>
-
-#define hades_dma_ctrl		(*(unsigned char *) 0xffff8717)
-#define hades_psdm_reg		(*(unsigned char *) 0xffff8741)
-
-#define TRANSFER_SIZE		16
-
-struct m68040_frame {
-	unsigned long  effaddr;  /* effective address */
-	unsigned short ssw;      /* special status word */
-	unsigned short wb3s;     /* write back 3 status */
-	unsigned short wb2s;     /* write back 2 status */
-	unsigned short wb1s;     /* write back 1 status */
-	unsigned long  faddr;    /* fault address */
-	unsigned long  wb3a;     /* write back 3 address */
-	unsigned long  wb3d;     /* write back 3 data */
-	unsigned long  wb2a;     /* write back 2 address */
-	unsigned long  wb2d;     /* write back 2 data */
-	unsigned long  wb1a;     /* write back 1 address */
-	unsigned long  wb1dpd0;  /* write back 1 data/push data 0*/
-	unsigned long  pd1;      /* push data 1*/
-	unsigned long  pd2;      /* push data 2*/
-	unsigned long  pd3;      /* push data 3*/
-};
-
-static void writeback (unsigned short wbs, unsigned long wba,
-		       unsigned long wbd, void *old_buserr)
-{
-	mm_segment_t fs = get_fs();
-	static void *save_buserr;
-
-	__asm__ __volatile__ ("movec.l	%%vbr,%%a0\n\t"
-			      "move.l	%0,8(%%a0)\n\t"
-			      :
-			      : "r" (&&bus_error)
-			      : "a0" );
-
-	save_buserr = old_buserr;
-
-	set_fs (MAKE_MM_SEG(wbs & WBTM_040));
-
-	switch (wbs & WBSIZ_040) {
-	    case BA_SIZE_BYTE:
-		put_user (wbd & 0xff, (char *)wba);
-		break;
-	    case BA_SIZE_WORD:
-		put_user (wbd & 0xffff, (short *)wba);
-		break;
-	    case BA_SIZE_LONG:
-		put_user (wbd, (int *)wba);
-		break;
-	}
-
-	set_fs (fs);
-	return;
-
-bus_error:
-	__asm__ __volatile__ ("cmp.l	%0,2(%%sp)\n\t"
-			      "bcs.s	.jump_old\n\t"
-			      "cmp.l	%1,2(%%sp)\n\t"
-			      "bls.s	.restore_old\n"
-			".jump_old:\n\t"
-			      "move.l	%2,-(%%sp)\n\t"
-			      "rts\n"
-			".restore_old:\n\t"
-			      "move.l	%%a0,-(%%sp)\n\t"
-			      "movec.l	%%vbr,%%a0\n\t"
-			      "move.l	%2,8(%%a0)\n\t"
-			      "move.l	(%%sp)+,%%a0\n\t"
-			      "rte\n\t"
-			      :
-			      : "i" (writeback), "i" (&&bus_error),
-			        "m" (save_buserr) );
-}
-
-/*
- * static inline void set_restdata_reg(unsigned char *cur_addr)
- *
- * Set the rest data register if necessary.
- */
-
-static inline void set_restdata_reg(unsigned char *cur_addr)
-{
-	if (((long) cur_addr & ~3) != 0)
-		tt_scsi_dma.dma_restdata =
-			*((unsigned long *) ((long) cur_addr & ~3));
-}
-
-/*
- * void hades_dma_emulator(int irq, void *dummy)
- * 
- * This code emulates TT SCSI DMA on the Hades.
- * 
- * Note the following:
- * 
- * 1. When there is no byte available to read from the SCSI bus, or
- *    when a byte cannot yet bet written to the SCSI bus, a bus
- *    error occurs when reading or writing the pseudo DMA data
- *    register (hades_psdm_reg). We have to catch this bus error
- *    and try again to read or write the byte. If after several tries
- *    we still get a bus error, the interrupt handler is left. When
- *    the byte can be read or written, the interrupt handler is
- *    called again.
- * 
- * 2. The SCSI interrupt must be disabled in this interrupt handler.
- * 
- * 3. If we set the EOP signal, the SCSI controller still expects one
- *    byte to be read or written. Therefore the last byte is transferred
- *    separately, after setting the EOP signal.
- * 
- * 4. When this function is left, the address pointer (start_addr) is
- *    converted to a physical address. Because it points one byte
- *    further than the last transferred byte, it can point outside the
- *    current page. If virt_to_phys() is called with this address we
- *    might get an access error. Therefore virt_to_phys() is called with
- *    start_addr - 1 if the count has reached zero. The result is
- *    increased with one.
- */
-
-static irqreturn_t hades_dma_emulator(int irq, void *dummy)
-{
-	unsigned long dma_base;
-	register unsigned long dma_cnt asm ("d3");
-	static long save_buserr;
-	register unsigned long save_sp asm ("d4");
-	register int tries asm ("d5");
-	register unsigned char *start_addr asm ("a3"), *end_addr asm ("a4");
-	register unsigned char *eff_addr;
-	register unsigned char *psdm_reg;
-	unsigned long rem;
-
-	atari_disable_irq(IRQ_TT_MFP_SCSI);
-
-	/*
-	 * Read the dma address and count registers.
-	 */
-
-	dma_base = SCSI_DMA_READ_P(dma_addr);
-	dma_cnt = SCSI_DMA_READ_P(dma_cnt);
-
-	/*
-	 * Check if DMA is still enabled.
-	 */
-
-	if ((tt_scsi_dma.dma_ctrl & 2) == 0)
-	{
-		atari_enable_irq(IRQ_TT_MFP_SCSI);
-		return IRQ_HANDLED;
-	}
-
-	if (dma_cnt == 0)
-	{
-		printk(KERN_NOTICE "DMA emulation: count is zero.\n");
-		tt_scsi_dma.dma_ctrl &= 0xfd;	/* DMA ready. */
-		atari_enable_irq(IRQ_TT_MFP_SCSI);
-		return IRQ_HANDLED;
-	}
-
-	/*
-	 * Install new bus error routine.
-	 */
-
-	__asm__ __volatile__ ("movec.l	%%vbr,%%a0\n\t"
-			      "move.l	8(%%a0),%0\n\t"
-			      "move.l	%1,8(%%a0)\n\t"
-			      : "=&r" (save_buserr)
-			      : "r" (&&scsi_bus_error)
-			      : "a0" );
-
-	hades_dma_ctrl &= 0xfc;		/* Bus error and EOP off. */
-
-	/*
-	 * Save the stack pointer.
-	 */
-
-	__asm__ __volatile__ ("move.l	%%sp,%0\n\t"
-			      : "=&r" (save_sp) );
-
-	tries = 100;			/* Maximum number of bus errors. */
-	start_addr = phys_to_virt(dma_base);
-	end_addr = start_addr + dma_cnt;
-
-scsi_loop:
-	dma_cnt--;
-	rem = dma_cnt & (TRANSFER_SIZE - 1);
-	dma_cnt &= ~(TRANSFER_SIZE - 1);
-	psdm_reg = &hades_psdm_reg;
-
-	if (tt_scsi_dma.dma_ctrl & 1)	/* Read or write? */
-	{
-		/*
-		 * SCSI write. Abort when count is zero.
-		 */
-
-		switch (rem)
-		{
-		case 0:
-			while (dma_cnt > 0)
-			{
-				dma_cnt -= TRANSFER_SIZE;
-
-				*psdm_reg = *start_addr++;
-		case 15:
-				*psdm_reg = *start_addr++;
-		case 14:
-				*psdm_reg = *start_addr++;
-		case 13:
-				*psdm_reg = *start_addr++;
-		case 12:
-				*psdm_reg = *start_addr++;
-		case 11:
-				*psdm_reg = *start_addr++;
-		case 10:
-				*psdm_reg = *start_addr++;
-		case 9:
-				*psdm_reg = *start_addr++;
-		case 8:
-				*psdm_reg = *start_addr++;
-		case 7:
-				*psdm_reg = *start_addr++;
-		case 6:
-				*psdm_reg = *start_addr++;
-		case 5:
-				*psdm_reg = *start_addr++;
-		case 4:
-				*psdm_reg = *start_addr++;
-		case 3:
-				*psdm_reg = *start_addr++;
-		case 2:
-				*psdm_reg = *start_addr++;
-		case 1:
-				*psdm_reg = *start_addr++;
-			}
-		}
-
-		hades_dma_ctrl |= 1;	/* Set EOP. */
-		udelay(10);
-		*psdm_reg = *start_addr++;	/* Dummy byte. */
-		tt_scsi_dma.dma_ctrl &= 0xfd;	/* DMA ready. */
-	}
-	else
-	{
-		/*
-		 * SCSI read. Abort when count is zero.
-		 */
-
-		switch (rem)
-		{
-		case 0:
-			while (dma_cnt > 0)
-			{
-				dma_cnt -= TRANSFER_SIZE;
-
-				*start_addr++ = *psdm_reg;
-		case 15:
-				*start_addr++ = *psdm_reg;
-		case 14:
-				*start_addr++ = *psdm_reg;
-		case 13:
-				*start_addr++ = *psdm_reg;
-		case 12:
-				*start_addr++ = *psdm_reg;
-		case 11:
-				*start_addr++ = *psdm_reg;
-		case 10:
-				*start_addr++ = *psdm_reg;
-		case 9:
-				*start_addr++ = *psdm_reg;
-		case 8:
-				*start_addr++ = *psdm_reg;
-		case 7:
-				*start_addr++ = *psdm_reg;
-		case 6:
-				*start_addr++ = *psdm_reg;
-		case 5:
-				*start_addr++ = *psdm_reg;
-		case 4:
-				*start_addr++ = *psdm_reg;
-		case 3:
-				*start_addr++ = *psdm_reg;
-		case 2:
-				*start_addr++ = *psdm_reg;
-		case 1:
-				*start_addr++ = *psdm_reg;
-			}
-		}
-
-		hades_dma_ctrl |= 1;	/* Set EOP. */
-		udelay(10);
-		*start_addr++ = *psdm_reg;
-		tt_scsi_dma.dma_ctrl &= 0xfd;	/* DMA ready. */
-
-		set_restdata_reg(start_addr);
-	}
-
-	if (start_addr != end_addr)
-		printk(KERN_CRIT "DMA emulation: FATAL: Count is not zero at end of transfer.\n");
-
-	dma_cnt = end_addr - start_addr;
-
-scsi_end:
-	dma_base = (dma_cnt == 0) ? virt_to_phys(start_addr - 1) + 1 :  
-				    virt_to_phys(start_addr);
-
-	SCSI_DMA_WRITE_P(dma_addr, dma_base);
-	SCSI_DMA_WRITE_P(dma_cnt, dma_cnt);
-
-	/*
-	 * Restore old bus error routine.
-	 */
-
-	__asm__ __volatile__ ("movec.l	%%vbr,%%a0\n\t"
-			      "move.l	%0,8(%%a0)\n\t"
-			      :
-			      : "r" (save_buserr)
-			      : "a0" );
-
-	atari_enable_irq(IRQ_TT_MFP_SCSI);
-
-	return IRQ_HANDLED;
-
-scsi_bus_error:
-	/*
-	 * First check if the bus error is caused by our code.
-	 * If not, call the original handler.
-	 */
-
-	__asm__ __volatile__ ("cmp.l	%0,2(%%sp)\n\t"
-			      "bcs.s	.old_vector\n\t"
-			      "cmp.l	%1,2(%%sp)\n\t"
-			      "bls.s	.scsi_buserr\n"
-			".old_vector:\n\t"
-			      "move.l	%2,-(%%sp)\n\t"
-			      "rts\n"
-			".scsi_buserr:\n\t"
-			      :
-			      : "i" (&&scsi_loop), "i" (&&scsi_end),
-			        "m" (save_buserr) );
-
-	if (CPU_IS_060)
-	{
-		/*
-		 * Get effective address and restore the stack.
-		 */
-
-		__asm__ __volatile__ ("move.l	8(%%sp),%0\n\t"
-				      "move.l	%1,%%sp\n\t"
-				      : "=a&" (eff_addr)
-				      : "r" (save_sp) );
-	}
-	else
-	{
-		register struct m68040_frame *frame;
-
-		__asm__ __volatile__ ("lea	8(%%sp),%0\n\t"
-				      : "=a&" (frame) );
-
-		if (tt_scsi_dma.dma_ctrl & 1)
-		{
-			/*
-			 * Bus error while writing.
-			 */
-
-			if (frame->wb3s & WBV_040)
-			{
-				if (frame->wb3a == (long) &hades_psdm_reg)
-					start_addr--;
-				else
-					writeback(frame->wb3s, frame->wb3a,
-						  frame->wb3d, &&scsi_bus_error);
-			}
-
-			if (frame->wb2s & WBV_040)
-			{
-				if (frame->wb2a == (long) &hades_psdm_reg)
-					start_addr--;
-				else
-					writeback(frame->wb2s, frame->wb2a,
-						  frame->wb2d, &&scsi_bus_error);
-			}
-
-			if (frame->wb1s & WBV_040)
-			{
-				if (frame->wb1a == (long) &hades_psdm_reg)
-					start_addr--;
-			}
-		}
-		else
-		{
-			/*
-			 * Bus error while reading.
-			 */
-
-			if (frame->wb3s & WBV_040)
-				writeback(frame->wb3s, frame->wb3a,
-					  frame->wb3d, &&scsi_bus_error);
-		}
-
-		eff_addr = (unsigned char *) frame->faddr;
-
-		__asm__ __volatile__ ("move.l	%0,%%sp\n\t"
-				      :
-				      : "r" (save_sp) );
-	}
-
-	dma_cnt = end_addr - start_addr;
-
-	if (eff_addr == &hades_psdm_reg)
-	{
-		/*
-		 * Bus error occurred while reading the pseudo
-		 * DMA register. Time out.
-		 */
-
-		tries--;
-
-		if (tries <= 0)
-		{
-			if ((tt_scsi_dma.dma_ctrl & 1) == 0)	/* Read or write? */
-				set_restdata_reg(start_addr);
-
-			if (dma_cnt <= 1)
-				printk(KERN_CRIT "DMA emulation: Fatal "
-				       "error while %s the last byte.\n",
-				       (tt_scsi_dma.dma_ctrl & 1)
-				       ? "writing" : "reading");
-
-			goto scsi_end;
-		}
-		else
-			goto scsi_loop;
-	}
-	else
-	{
-		/*
-		 * Bus error during pseudo DMA transfer.
-		 * Terminate the DMA transfer.
-		 */
-
-		hades_dma_ctrl |= 3;	/* Set EOP and bus error. */
-		if ((tt_scsi_dma.dma_ctrl & 1) == 0)	/* Read or write? */
-			set_restdata_reg(start_addr);
-		goto scsi_end;
-	}
-}
diff --git a/drivers/scsi/atari_scsi.c b/drivers/scsi/atari_scsi.c
index f5732d8..21fe07f 100644
--- a/drivers/scsi/atari_scsi.c
+++ b/drivers/scsi/atari_scsi.c
@@ -249,10 +249,6 @@
 module_param(setup_hostid, int, 0);
 
 
-#if defined(CONFIG_TT_DMA_EMUL)
-#include "atari_dma_emul.c"
-#endif
-
 #if defined(REAL_DMA)
 
 static int scsi_dma_is_ignored_buserr(unsigned char dma_stat)
@@ -695,21 +691,8 @@
 #ifdef REAL_DMA
 		tt_scsi_dma.dma_ctrl = 0;
 		atari_dma_residual = 0;
-#ifdef CONFIG_TT_DMA_EMUL
-		if (MACH_IS_HADES) {
-			if (request_irq(IRQ_AUTO_2, hades_dma_emulator,
-					 IRQ_TYPE_PRIO, "Hades DMA emulator",
-					 hades_dma_emulator)) {
-				printk(KERN_ERR "atari_scsi_detect: cannot allocate irq %d, aborting (MACH_IS_HADES)",IRQ_AUTO_2);
-				free_irq(IRQ_TT_MFP_SCSI, instance);
-				scsi_unregister(atari_scsi_host);
-				atari_stram_free(atari_dma_buffer);
-				atari_dma_buffer = 0;
-				return 0;
-			}
-		}
-#endif
-		if (MACH_IS_MEDUSA || MACH_IS_HADES) {
+
+		if (MACH_IS_MEDUSA) {
 			/* While the read overruns (described by Drew Eckhardt in
 			 * NCR5380.c) never happened on TTs, they do in fact on the Medusa
 			 * (This was the cause why SCSI didn't work right for so long
@@ -1007,11 +990,7 @@
 					Scsi_Cmnd *cmd, int write_flag)
 {
 	unsigned long	possible_len, limit;
-#ifndef CONFIG_TT_DMA_EMUL
-	if (MACH_IS_HADES)
-		/* Hades has no SCSI DMA at all :-( Always force use of PIO */
-		return 0;
-#endif
+
 	if (IS_A_TT())
 		/* TT SCSI DMA can transfer arbitrary #bytes */
 		return wanted_len;
diff --git a/drivers/scsi/device_handler/scsi_dh_emc.c b/drivers/scsi/device_handler/scsi_dh_emc.c
index ef693e84..8f45570 100644
--- a/drivers/scsi/device_handler/scsi_dh_emc.c
+++ b/drivers/scsi/device_handler/scsi_dh_emc.c
@@ -84,7 +84,7 @@
 	/*
 	 * I/O buffer for both MODE_SELECT and INQUIRY commands.
 	 */
-	char buffer[CLARIION_BUFFER_SIZE];
+	unsigned char buffer[CLARIION_BUFFER_SIZE];
 	/*
 	 * SCSI sense buffer for commands -- assumes serial issuance
 	 * and completion sequence of all commands for same multipath.
@@ -176,7 +176,7 @@
 		err = SCSI_DH_DEV_TEMP_BUSY;
 		goto out;
 	}
-	if (csdev->buffer[4] < 0 || csdev->buffer[4] > 2) {
+	if (csdev->buffer[4] > 2) {
 		/* Invalid buffer format */
 		sdev_printk(KERN_NOTICE, sdev,
 			    "%s: invalid VPD page 0xC0 format\n",
@@ -278,7 +278,6 @@
 		return NULL;
 	}
 
-	memset(rq->cmd, 0, BLK_MAX_CDB);
 	rq->cmd_len = COMMAND_SIZE(cmd);
 	rq->cmd[0] = cmd;
 
diff --git a/drivers/scsi/device_handler/scsi_dh_hp_sw.c b/drivers/scsi/device_handler/scsi_dh_hp_sw.c
index a6a4ef3..5e93c88 100644
--- a/drivers/scsi/device_handler/scsi_dh_hp_sw.c
+++ b/drivers/scsi/device_handler/scsi_dh_hp_sw.c
@@ -114,7 +114,6 @@
 	req->cmd_type = REQ_TYPE_BLOCK_PC;
 	req->cmd_flags |= REQ_FAILFAST;
 	req->cmd_len = COMMAND_SIZE(TEST_UNIT_READY);
-	memset(req->cmd, 0, MAX_COMMAND_SIZE);
 	req->cmd[0] = TEST_UNIT_READY;
 	req->timeout = HP_SW_TIMEOUT;
 	req->sense = h->sense;
@@ -207,7 +206,6 @@
 	req->cmd_type = REQ_TYPE_BLOCK_PC;
 	req->cmd_flags |= REQ_FAILFAST;
 	req->cmd_len = COMMAND_SIZE(START_STOP);
-	memset(req->cmd, 0, MAX_COMMAND_SIZE);
 	req->cmd[0] = START_STOP;
 	req->cmd[4] = 1;	/* Start spin cycle */
 	req->timeout = HP_SW_TIMEOUT;
diff --git a/drivers/scsi/device_handler/scsi_dh_rdac.c b/drivers/scsi/device_handler/scsi_dh_rdac.c
index 6e2f130..50bf95f 100644
--- a/drivers/scsi/device_handler/scsi_dh_rdac.c
+++ b/drivers/scsi/device_handler/scsi_dh_rdac.c
@@ -225,8 +225,6 @@
 		return NULL;
 	}
 
-	memset(rq->cmd, 0, BLK_MAX_CDB);
-
 	rq->cmd_type = REQ_TYPE_BLOCK_PC;
 	rq->cmd_flags |= REQ_FAILFAST | REQ_NOMERGE;
 	rq->retries = RDAC_RETRIES;
@@ -590,6 +588,8 @@
 	{"STK", "OPENstorage D280"},
 	{"SUN", "CSM200_R"},
 	{"SUN", "LCSM100_F"},
+	{"DELL", "MD3000"},
+	{"DELL", "MD3000i"},
 	{NULL, NULL},
 };
 
diff --git a/drivers/scsi/esp_scsi.h b/drivers/scsi/esp_scsi.h
index bb43a13..28e22ac 100644
--- a/drivers/scsi/esp_scsi.h
+++ b/drivers/scsi/esp_scsi.h
@@ -521,7 +521,8 @@
 
 	struct completion	*eh_reset;
 
-	struct sbus_dma		*dma;
+	void			*dma;
+	int			dmarev;
 };
 
 /* A front-end driver for the ESP chip should do the following in
diff --git a/drivers/scsi/gdth.c b/drivers/scsi/gdth.c
index 822d521..c387c15 100644
--- a/drivers/scsi/gdth.c
+++ b/drivers/scsi/gdth.c
@@ -464,7 +464,6 @@
 
     /* use request field to save the ptr. to completion struct. */
     scp->request = (struct request *)&wait;
-    scp->timeout_per_command = timeout*HZ;
     scp->cmd_len = 12;
     scp->cmnd = cmnd;
     cmndinfo.priority = IOCTL_PRI;
@@ -1995,23 +1994,12 @@
     register Scsi_Cmnd *pscp;
     register Scsi_Cmnd *nscp;
     ulong flags;
-    unchar b, t;
 
     TRACE(("gdth_putq() priority %d\n",priority));
     spin_lock_irqsave(&ha->smp_lock, flags);
 
-    if (!cmndinfo->internal_command) {
+    if (!cmndinfo->internal_command)
         cmndinfo->priority = priority;
-        b = scp->device->channel;
-        t = scp->device->id;
-        if (priority >= DEFAULT_PRI) {
-            if ((b != ha->virt_bus && ha->raw[BUS_L2P(ha,b)].lock) ||
-                (b==ha->virt_bus && t<MAX_HDRIVES && ha->hdr[t].lock)) {
-                TRACE2(("gdth_putq(): locked IO ->update_timeout()\n"));
-                cmndinfo->timeout = gdth_update_timeout(scp, 0);
-            }
-        }
-    }
 
     if (ha->req_first==NULL) {
         ha->req_first = scp;                    /* queue was empty */
@@ -3899,6 +3887,39 @@
     return ((const char *)ha->binfo.type_string);
 }
 
+static enum blk_eh_timer_return gdth_timed_out(struct scsi_cmnd *scp)
+{
+	gdth_ha_str *ha = shost_priv(scp->device->host);
+	struct gdth_cmndinfo *cmndinfo = gdth_cmnd_priv(scp);
+	unchar b, t;
+	ulong flags;
+	enum blk_eh_timer_return retval = BLK_EH_NOT_HANDLED;
+
+	TRACE(("%s() cmd 0x%x\n", scp->cmnd[0], __func__));
+	b = scp->device->channel;
+	t = scp->device->id;
+
+	/*
+	 * We don't really honor the command timeout, but we try to
+	 * honor 6 times of the actual command timeout! So reset the
+	 * timer if this is less than 6th timeout on this command!
+	 */
+	if (++cmndinfo->timeout_count < 6)
+		retval = BLK_EH_RESET_TIMER;
+
+	/* Reset the timeout if it is locked IO */
+	spin_lock_irqsave(&ha->smp_lock, flags);
+	if ((b != ha->virt_bus && ha->raw[BUS_L2P(ha, b)].lock) ||
+	    (b == ha->virt_bus && t < MAX_HDRIVES && ha->hdr[t].lock)) {
+		TRACE2(("%s(): locked IO, reset timeout\n", __func__));
+		retval = BLK_EH_RESET_TIMER;
+	}
+	spin_unlock_irqrestore(&ha->smp_lock, flags);
+
+	return retval;
+}
+
+
 static int gdth_eh_bus_reset(Scsi_Cmnd *scp)
 {
     gdth_ha_str *ha = shost_priv(scp->device->host);
@@ -3992,7 +4013,7 @@
     BUG_ON(!cmndinfo);
 
     scp->scsi_done = done;
-    gdth_update_timeout(scp, scp->timeout_per_command * 6);
+    cmndinfo->timeout_count = 0;
     cmndinfo->priority = DEFAULT_PRI;
 
     return __gdth_queuecommand(ha, scp, cmndinfo);
@@ -4096,12 +4117,10 @@
             ha->hdr[j].lock = 1;
             spin_unlock_irqrestore(&ha->smp_lock, flags);
             gdth_wait_completion(ha, ha->bus_cnt, j);
-            gdth_stop_timeout(ha, ha->bus_cnt, j);
         } else {
             spin_lock_irqsave(&ha->smp_lock, flags);
             ha->hdr[j].lock = 0;
             spin_unlock_irqrestore(&ha->smp_lock, flags);
-            gdth_start_timeout(ha, ha->bus_cnt, j);
             gdth_next(ha);
         }
     } 
@@ -4539,18 +4558,14 @@
                 spin_lock_irqsave(&ha->smp_lock, flags);
                 ha->raw[i].lock = 1;
                 spin_unlock_irqrestore(&ha->smp_lock, flags);
-                for (j = 0; j < ha->tid_cnt; ++j) {
+		for (j = 0; j < ha->tid_cnt; ++j)
                     gdth_wait_completion(ha, i, j);
-                    gdth_stop_timeout(ha, i, j);
-                }
             } else {
                 spin_lock_irqsave(&ha->smp_lock, flags);
                 ha->raw[i].lock = 0;
                 spin_unlock_irqrestore(&ha->smp_lock, flags);
-                for (j = 0; j < ha->tid_cnt; ++j) {
-                    gdth_start_timeout(ha, i, j);
+		for (j = 0; j < ha->tid_cnt; ++j)
                     gdth_next(ha);
-                }
             }
         } 
         break;
@@ -4644,6 +4659,7 @@
         .slave_configure        = gdth_slave_configure,
         .bios_param             = gdth_bios_param,
         .proc_info              = gdth_proc_info,
+	.eh_timed_out		= gdth_timed_out,
         .proc_name              = "gdth",
         .can_queue              = GDTH_MAXCMDS,
         .this_id                = -1,
diff --git a/drivers/scsi/gdth.h b/drivers/scsi/gdth.h
index ca92476..1646444 100644
--- a/drivers/scsi/gdth.h
+++ b/drivers/scsi/gdth.h
@@ -916,7 +916,7 @@
         gdth_cmd_str *internal_cmd_str;         /* crier for internal messages*/
         dma_addr_t sense_paddr;                 /* sense dma-addr */
         unchar priority;
-        int timeout;
+	int timeout_count;			/* # of timeout calls */
         volatile int wait_for_completion;
         ushort status;
         ulong32 info;
diff --git a/drivers/scsi/gdth_proc.c b/drivers/scsi/gdth_proc.c
index ce0228e..59349a3 100644
--- a/drivers/scsi/gdth_proc.c
+++ b/drivers/scsi/gdth_proc.c
@@ -748,69 +748,3 @@
     }
     spin_unlock_irqrestore(&ha->smp_lock, flags);
 }
-
-static void gdth_stop_timeout(gdth_ha_str *ha, int busnum, int id)
-{
-    ulong flags;
-    Scsi_Cmnd *scp;
-    unchar b, t;
-
-    spin_lock_irqsave(&ha->smp_lock, flags);
-
-    for (scp = ha->req_first; scp; scp = (Scsi_Cmnd *)scp->SCp.ptr) {
-        struct gdth_cmndinfo *cmndinfo = gdth_cmnd_priv(scp);
-        if (!cmndinfo->internal_command) {
-            b = scp->device->channel;
-            t = scp->device->id;
-            if (t == (unchar)id && b == (unchar)busnum) {
-                TRACE2(("gdth_stop_timeout(): update_timeout()\n"));
-                cmndinfo->timeout = gdth_update_timeout(scp, 0);
-            }
-        }
-    }
-    spin_unlock_irqrestore(&ha->smp_lock, flags);
-}
-
-static void gdth_start_timeout(gdth_ha_str *ha, int busnum, int id)
-{
-    ulong flags;
-    Scsi_Cmnd *scp;
-    unchar b, t;
-
-    spin_lock_irqsave(&ha->smp_lock, flags);
-
-    for (scp = ha->req_first; scp; scp = (Scsi_Cmnd *)scp->SCp.ptr) {
-        struct gdth_cmndinfo *cmndinfo = gdth_cmnd_priv(scp);
-        if (!cmndinfo->internal_command) {
-            b = scp->device->channel;
-            t = scp->device->id;
-            if (t == (unchar)id && b == (unchar)busnum) {
-                TRACE2(("gdth_start_timeout(): update_timeout()\n"));
-                gdth_update_timeout(scp, cmndinfo->timeout);
-            }
-        }
-    }
-    spin_unlock_irqrestore(&ha->smp_lock, flags);
-}
-
-static int gdth_update_timeout(Scsi_Cmnd *scp, int timeout)
-{
-    int oldto;
-
-    oldto = scp->timeout_per_command;
-    scp->timeout_per_command = timeout;
-
-    if (timeout == 0) {
-        del_timer(&scp->eh_timeout);
-        scp->eh_timeout.data = (unsigned long) NULL;
-        scp->eh_timeout.expires = 0;
-    } else {
-        if (scp->eh_timeout.data != (unsigned long) NULL) 
-            del_timer(&scp->eh_timeout);
-        scp->eh_timeout.data = (unsigned long) scp;
-        scp->eh_timeout.expires = jiffies + timeout;
-        add_timer(&scp->eh_timeout);
-    }
-
-    return oldto;
-}
diff --git a/drivers/scsi/gdth_proc.h b/drivers/scsi/gdth_proc.h
index 45e6fda..9b900cc 100644
--- a/drivers/scsi/gdth_proc.h
+++ b/drivers/scsi/gdth_proc.h
@@ -20,9 +20,6 @@
                               ulong64 *paddr);
 static void gdth_ioctl_free(gdth_ha_str *ha, int size, char *buf, ulong64 paddr);
 static void gdth_wait_completion(gdth_ha_str *ha, int busnum, int id);
-static void gdth_stop_timeout(gdth_ha_str *ha, int busnum, int id);
-static void gdth_start_timeout(gdth_ha_str *ha, int busnum, int id);
-static int gdth_update_timeout(Scsi_Cmnd *scp, int timeout);
 
 #endif
 
diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c
index fed0b02..3fdbb13 100644
--- a/drivers/scsi/hosts.c
+++ b/drivers/scsi/hosts.c
@@ -464,7 +464,7 @@
 struct Scsi_Host *scsi_host_lookup(unsigned short hostnum)
 {
 	struct device *cdev;
-	struct Scsi_Host *shost = ERR_PTR(-ENXIO);
+	struct Scsi_Host *shost = NULL;
 
 	cdev = class_find_device(&shost_class, NULL, &hostnum,
 				 __scsi_host_match);
diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.c b/drivers/scsi/ibmvscsi/ibmvscsi.c
index 7b1502c..87e09f3 100644
--- a/drivers/scsi/ibmvscsi/ibmvscsi.c
+++ b/drivers/scsi/ibmvscsi/ibmvscsi.c
@@ -756,7 +756,7 @@
 	init_event_struct(evt_struct,
 			  handle_cmd_rsp,
 			  VIOSRP_SRP_FORMAT,
-			  cmnd->timeout_per_command/HZ);
+			  cmnd->request->timeout/HZ);
 
 	evt_struct->cmnd = cmnd;
 	evt_struct->cmnd_done = done;
diff --git a/drivers/scsi/ide-scsi.c b/drivers/scsi/ide-scsi.c
index 461331d..740bad4 100644
--- a/drivers/scsi/ide-scsi.c
+++ b/drivers/scsi/ide-scsi.c
@@ -40,7 +40,6 @@
 #include <linux/ioport.h>
 #include <linux/blkdev.h>
 #include <linux/errno.h>
-#include <linux/hdreg.h>
 #include <linux/slab.h>
 #include <linux/ide.h>
 #include <linux/scatterlist.h>
@@ -83,7 +82,6 @@
 	struct gendisk		*disk;
 	struct Scsi_Host	*host;
 
-	struct ide_atapi_pc *pc;		/* Current packet command */
 	unsigned long transform;		/* SCSI cmd translation layer */
 	unsigned long log;			/* log flags */
 } idescsi_scsi_t;
@@ -131,50 +129,6 @@
 	return scsihost_to_idescsi(ide_drive->driver_data);
 }
 
-/*
- *	PIO data transfer routine using the scatter gather table.
- */
-static void ide_scsi_io_buffers(ide_drive_t *drive, struct ide_atapi_pc *pc,
-				unsigned int bcount, int write)
-{
-	ide_hwif_t *hwif = drive->hwif;
-	const struct ide_tp_ops *tp_ops = hwif->tp_ops;
-	xfer_func_t *xf = write ? tp_ops->output_data : tp_ops->input_data;
-	char *buf;
-	int count;
-
-	while (bcount) {
-		count = min(pc->sg->length - pc->b_count, bcount);
-		if (PageHighMem(sg_page(pc->sg))) {
-			unsigned long flags;
-
-			local_irq_save(flags);
-			buf = kmap_atomic(sg_page(pc->sg), KM_IRQ0) +
-					  pc->sg->offset;
-			xf(drive, NULL, buf + pc->b_count, count);
-			kunmap_atomic(buf - pc->sg->offset, KM_IRQ0);
-			local_irq_restore(flags);
-		} else {
-			buf = sg_virt(pc->sg);
-			xf(drive, NULL, buf + pc->b_count, count);
-		}
-		bcount -= count; pc->b_count += count;
-		if (pc->b_count == pc->sg->length) {
-			if (!--pc->sg_cnt)
-				break;
-			pc->sg = sg_next(pc->sg);
-			pc->b_count = 0;
-		}
-	}
-
-	if (bcount) {
-		printk(KERN_ERR "%s: scatter gather table too small, %s\n",
-				drive->name, write ? "padding with zeros"
-						   : "discarding data");
-		ide_pad_transfer(drive, write, bcount);
-	}
-}
-
 static void ide_scsi_hex_dump(u8 *data, int len)
 {
 	print_hex_dump(KERN_CONT, "", DUMP_PREFIX_NONE, 16, 1, data, len, 0);
@@ -182,10 +136,10 @@
 
 static int idescsi_end_request(ide_drive_t *, int, int);
 
-static void ide_scsi_callback(ide_drive_t *drive)
+static void ide_scsi_callback(ide_drive_t *drive, int dsc)
 {
 	idescsi_scsi_t *scsi = drive_to_idescsi(drive);
-	struct ide_atapi_pc *pc = scsi->pc;
+	struct ide_atapi_pc *pc = drive->pc;
 
 	if (pc->flags & PC_FLAG_TIMEDOUT)
 		debug_log("%s: got timed out packet %lu at %lu\n", __func__,
@@ -244,9 +198,9 @@
 {
 	ide_hwif_t *hwif = drive->hwif;
 
-	if (hwif->tp_ops->read_status(hwif) & (BUSY_STAT | DRQ_STAT))
+	if (hwif->tp_ops->read_status(hwif) & (ATA_BUSY | ATA_DRQ))
 		/* force an abort */
-		hwif->tp_ops->exec_command(hwif, WIN_IDLEIMMEDIATE);
+		hwif->tp_ops->exec_command(hwif, ATA_CMD_IDLEIMMEDIATE);
 
 	rq->errors++;
 
@@ -312,49 +266,10 @@
 	spin_unlock_irqrestore(host->host_lock, flags);
 	kfree(pc);
 	blk_put_request(rq);
-	scsi->pc = NULL;
+	drive->pc = NULL;
 	return 0;
 }
 
-static inline unsigned long get_timeout(struct ide_atapi_pc *pc)
-{
-	return max_t(unsigned long, WAIT_CMD, pc->timeout - jiffies);
-}
-
-static int idescsi_expiry(ide_drive_t *drive)
-{
-	idescsi_scsi_t *scsi = drive_to_idescsi(drive);
-	struct ide_atapi_pc   *pc   = scsi->pc;
-
-	debug_log("%s called for %lu at %lu\n", __func__,
-		  pc->scsi_cmd->serial_number, jiffies);
-
-	pc->flags |= PC_FLAG_TIMEDOUT;
-
-	return 0;					/* we do not want the ide subsystem to retry */
-}
-
-/*
- *	Our interrupt handler.
- */
-static ide_startstop_t idescsi_pc_intr (ide_drive_t *drive)
-{
-	idescsi_scsi_t *scsi = drive_to_idescsi(drive);
-	struct ide_atapi_pc *pc = scsi->pc;
-
-	return ide_pc_intr(drive, pc, idescsi_pc_intr, get_timeout(pc),
-			   idescsi_expiry, NULL, NULL, NULL,
-			   ide_scsi_io_buffers);
-}
-
-static ide_startstop_t idescsi_transfer_pc(ide_drive_t *drive)
-{
-	idescsi_scsi_t *scsi = drive_to_idescsi(drive);
-
-	return ide_transfer_pc(drive, scsi->pc, idescsi_pc_intr,
-			       get_timeout(scsi->pc), idescsi_expiry);
-}
-
 static inline int idescsi_set_direction(struct ide_atapi_pc *pc)
 {
 	switch (pc->c[0]) {
@@ -397,13 +312,10 @@
 static ide_startstop_t idescsi_issue_pc(ide_drive_t *drive,
 		struct ide_atapi_pc *pc)
 {
-	idescsi_scsi_t *scsi = drive_to_idescsi(drive);
-
 	/* Set the current packet command */
-	scsi->pc = pc;
+	drive->pc = pc;
 
-	return ide_issue_pc(drive, pc, idescsi_transfer_pc,
-			    get_timeout(pc), idescsi_expiry);
+	return ide_issue_pc(drive, ide_scsi_get_timeout(pc), ide_scsi_expiry);
 }
 
 /*
@@ -419,7 +331,8 @@
 	if (blk_sense_request(rq) || blk_special_request(rq)) {
 		struct ide_atapi_pc *pc = (struct ide_atapi_pc *)rq->special;
 
-		if (drive->using_dma && !idescsi_map_sg(drive, pc))
+		if ((drive->dev_flags & IDE_DFLAG_USING_DMA) &&
+		    idescsi_map_sg(drive, pc) == 0)
 			pc->flags |= PC_FLAG_DMA_OK;
 
 		return idescsi_issue_pc(drive, pc);
@@ -430,21 +343,41 @@
 }
 
 #ifdef CONFIG_IDE_PROC_FS
-static void idescsi_add_settings(ide_drive_t *drive)
-{
-	idescsi_scsi_t *scsi = drive_to_idescsi(drive);
-
-/*
- *			drive	setting name	read/write	data type	min	max	mul_factor	div_factor	data pointer		set function
- */
-	ide_add_setting(drive,	"bios_cyl",	SETTING_RW,	TYPE_INT,	0,	1023,	1,		1,		&drive->bios_cyl,	NULL);
-	ide_add_setting(drive,	"bios_head",	SETTING_RW,	TYPE_BYTE,	0,	255,	1,		1,		&drive->bios_head,	NULL);
-	ide_add_setting(drive,	"bios_sect",	SETTING_RW,	TYPE_BYTE,	0,	63,	1,		1,		&drive->bios_sect,	NULL);
-	ide_add_setting(drive,	"transform",	SETTING_RW,	TYPE_INT,	0,	3,	1,		1,		&scsi->transform,	NULL);
-	ide_add_setting(drive,	"log",		SETTING_RW,	TYPE_INT,	0,	1,	1,		1,		&scsi->log,		NULL);
+#define ide_scsi_devset_get(name, field) \
+static int get_##name(ide_drive_t *drive) \
+{ \
+	idescsi_scsi_t *scsi = drive_to_idescsi(drive); \
+	return scsi->field; \
 }
-#else
-static inline void idescsi_add_settings(ide_drive_t *drive) { ; }
+
+#define ide_scsi_devset_set(name, field) \
+static int set_##name(ide_drive_t *drive, int arg) \
+{ \
+	idescsi_scsi_t *scsi = drive_to_idescsi(drive); \
+	scsi->field = arg; \
+	return 0; \
+}
+
+#define ide_scsi_devset_rw_field(_name, _field) \
+ide_scsi_devset_get(_name, _field); \
+ide_scsi_devset_set(_name, _field); \
+IDE_DEVSET(_name, DS_SYNC, get_##_name, set_##_name);
+
+ide_devset_rw_field(bios_cyl, bios_cyl);
+ide_devset_rw_field(bios_head, bios_head);
+ide_devset_rw_field(bios_sect, bios_sect);
+
+ide_scsi_devset_rw_field(transform, transform);
+ide_scsi_devset_rw_field(log, log);
+
+static const struct ide_proc_devset idescsi_settings[] = {
+	IDE_PROC_DEVSET(bios_cyl,  0, 1023),
+	IDE_PROC_DEVSET(bios_head, 0,  255),
+	IDE_PROC_DEVSET(bios_sect, 0,	63),
+	IDE_PROC_DEVSET(log,	   0,	 1),
+	IDE_PROC_DEVSET(transform, 0,	 3),
+	{ 0 },
+};
 #endif
 
 /*
@@ -452,16 +385,16 @@
  */
 static void idescsi_setup (ide_drive_t *drive, idescsi_scsi_t *scsi)
 {
-	if (drive->id && (drive->id->config & 0x0060) == 0x20)
-		set_bit(IDE_AFLAG_DRQ_INTERRUPT, &drive->atapi_flags);
 	clear_bit(IDESCSI_SG_TRANSFORM, &scsi->transform);
 #if IDESCSI_DEBUG_LOG
 	set_bit(IDESCSI_LOG_CMD, &scsi->log);
 #endif /* IDESCSI_DEBUG_LOG */
 
-	drive->pc_callback = ide_scsi_callback;
+	drive->pc_callback	 = ide_scsi_callback;
+	drive->pc_update_buffers = NULL;
+	drive->pc_io_buffers	 = ide_io_buffers;
 
-	idescsi_add_settings(drive);
+	ide_proc_register_driver(drive, scsi->driver);
 }
 
 static void ide_scsi_remove(ide_drive_t *drive)
@@ -481,7 +414,7 @@
 
 	ide_scsi_put(scsi);
 
-	drive->scsi = 0;
+	drive->dev_flags &= ~IDE_DFLAG_SCSI;
 }
 
 static int ide_scsi_probe(ide_drive_t *);
@@ -502,13 +435,12 @@
 	.probe			= ide_scsi_probe,
 	.remove			= ide_scsi_remove,
 	.version		= IDESCSI_VERSION,
-	.media			= ide_scsi,
-	.supports_dsc_overlap	= 0,
 	.do_request		= idescsi_do_request,
 	.end_request		= idescsi_end_request,
 	.error                  = idescsi_atapi_error,
 #ifdef CONFIG_IDE_PROC_FS
 	.proc			= idescsi_proc,
+	.settings		= idescsi_settings,
 #endif
 };
 
@@ -612,7 +544,7 @@
 	pc->req_xfer = pc->buf_size = scsi_bufflen(cmd);
 	pc->scsi_cmd = cmd;
 	pc->done = done;
-	pc->timeout = jiffies + cmd->timeout_per_command;
+	pc->timeout = jiffies + cmd->request->timeout;
 
 	if (test_bit(IDESCSI_LOG_CMD, &scsi->log)) {
 		printk ("ide-scsi: %s: que %lu, cmd = ", drive->name, cmd->serial_number);
@@ -647,6 +579,8 @@
 	int		busy;
 	int             ret   = FAILED;
 
+	struct ide_atapi_pc *pc;
+
 	/* In idescsi_eh_abort we try to gently pry our command from the ide subsystem */
 
 	if (test_bit(IDESCSI_LOG_CMD, &scsi->log))
@@ -667,26 +601,27 @@
 	spin_lock_irq(&ide_lock);
 
 	/* If there is no pc running we're done (our interrupt took care of it) */
-	if (!scsi->pc) {
+	pc = drive->pc;
+	if (pc == NULL) {
 		ret = SUCCESS;
 		goto ide_unlock;
 	}
 
 	/* It's somewhere in flight. Does ide subsystem agree? */
-	if (scsi->pc->scsi_cmd->serial_number == cmd->serial_number && !busy &&
-	    elv_queue_empty(drive->queue) && HWGROUP(drive)->rq != scsi->pc->rq) {
+	if (pc->scsi_cmd->serial_number == cmd->serial_number && !busy &&
+	    elv_queue_empty(drive->queue) && HWGROUP(drive)->rq != pc->rq) {
 		/*
 		 * FIXME - not sure this condition can ever occur
 		 */
 		printk (KERN_ERR "ide-scsi: cmd aborted!\n");
 
-		if (blk_sense_request(scsi->pc->rq))
-			kfree(scsi->pc->buf);
+		if (blk_sense_request(pc->rq))
+			kfree(pc->buf);
 		/* we need to call blk_put_request twice. */
-		blk_put_request(scsi->pc->rq);
-		blk_put_request(scsi->pc->rq);
-		kfree(scsi->pc);
-		scsi->pc = NULL;
+		blk_put_request(pc->rq);
+		blk_put_request(pc->rq);
+		kfree(pc);
+		drive->pc = NULL;
 
 		ret = SUCCESS;
 	}
@@ -708,6 +643,8 @@
 	int             ready = 0;
 	int             ret   = SUCCESS;
 
+	struct ide_atapi_pc *pc;
+
 	/* In idescsi_eh_reset we forcefully remove the command from the ide subsystem and reset the device. */
 
 	if (test_bit(IDESCSI_LOG_CMD, &scsi->log))
@@ -722,7 +659,9 @@
 	spin_lock_irq(cmd->device->host->host_lock);
 	spin_lock(&ide_lock);
 
-	if (!scsi->pc || (req = scsi->pc->rq) != HWGROUP(drive)->rq || !HWGROUP(drive)->handler) {
+	pc = drive->pc;
+
+	if (pc == NULL || (req = pc->rq) != HWGROUP(drive)->rq || !HWGROUP(drive)->handler) {
 		printk (KERN_WARNING "ide-scsi: No active request in idescsi_eh_reset\n");
 		spin_unlock(&ide_lock);
 		spin_unlock_irq(cmd->device->host->host_lock);
@@ -733,9 +672,9 @@
 	if (__blk_end_request(req, -EIO, 0))
 		BUG();
 	if (blk_sense_request(req))
-		kfree(scsi->pc->buf);
-	kfree(scsi->pc);
-	scsi->pc = NULL;
+		kfree(pc->buf);
+	kfree(pc);
+	drive->pc = NULL;
 	blk_put_request(req);
 
 	/* now nuke the drive queue */
@@ -811,6 +750,7 @@
 	struct gendisk *g;
 	static int warned;
 	int err = -ENOMEM;
+	u16 last_lun;
 
 	if (!warned && drive->media == ide_cdrom) {
 		printk(KERN_WARNING "ide-scsi is deprecated for cd burning! Use ide-cd and give dev=/dev/hdX as device\n");
@@ -821,12 +761,11 @@
 		return -ENODEV;
 
 	if (!strstr("ide-scsi", drive->driver_req) ||
-	    !drive->present ||
 	    drive->media == ide_disk ||
 	    !(host = scsi_host_alloc(&idescsi_template,sizeof(idescsi_scsi_t))))
 		return -ENODEV;
 
-	drive->scsi = 1;
+	drive->dev_flags |= IDE_DFLAG_SCSI;
 
 	g = alloc_disk(1 << PARTN_BITS);
 	if (!g)
@@ -836,12 +775,12 @@
 
 	host->max_id = 1;
 
-	if (drive->id->last_lun)
-		debug_log("%s: id->last_lun=%u\n", drive->name,
-			  drive->id->last_lun);
+	last_lun = drive->id[ATA_ID_LAST_LUN];
+	if (last_lun)
+		debug_log("%s: last_lun=%u\n", drive->name, last_lun);
 
-	if ((drive->id->last_lun & 0x7) != 7)
-		host->max_lun = (drive->id->last_lun & 0x7) + 1;
+	if ((last_lun & 7) != 7)
+		host->max_lun = (last_lun & 7) + 1;
 	else
 		host->max_lun = 1;
 
@@ -852,7 +791,6 @@
 	idescsi->host = host;
 	idescsi->disk = g;
 	g->private_data = &idescsi->driver;
-	ide_proc_register_driver(drive, &idescsi_driver);
 	err = 0;
 	idescsi_setup(drive, idescsi);
 	g->fops = &idescsi_ops;
@@ -868,7 +806,7 @@
 
 	put_disk(g);
 out_host_put:
-	drive->scsi = 0;
+	drive->dev_flags &= ~IDE_DFLAG_SCSI;
 	scsi_host_put(host);
 	return err;
 }
diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c
index e7a3a65..d30eb7b 100644
--- a/drivers/scsi/ipr.c
+++ b/drivers/scsi/ipr.c
@@ -3670,7 +3670,8 @@
 			sdev->no_uld_attach = 1;
 		}
 		if (ipr_is_vset_device(res)) {
-			sdev->timeout = IPR_VSET_RW_TIMEOUT;
+			blk_queue_rq_timeout(sdev->request_queue,
+					     IPR_VSET_RW_TIMEOUT);
 			blk_queue_max_sectors(sdev->request_queue, IPR_VSET_MAX_SECTORS);
 		}
 		if (ipr_is_vset_device(res) || ipr_is_scsi_disk(res))
diff --git a/drivers/scsi/ips.c b/drivers/scsi/ips.c
index bc9e6dd..ef683f0 100644
--- a/drivers/scsi/ips.c
+++ b/drivers/scsi/ips.c
@@ -3818,7 +3818,7 @@
 		scb->cmd.dcdb.segment_4G = 0;
 		scb->cmd.dcdb.enhanced_sg = 0;
 
-		TimeOut = scb->scsi_cmd->timeout_per_command;
+		TimeOut = scb->scsi_cmd->request->timeout;
 
 		if (ha->subsys->param[4] & 0x00100000) {	/* If NEW Tape DCDB is Supported */
 			if (!scb->sg_len) {
diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
index 299e075..da7b67d 100644
--- a/drivers/scsi/libiscsi.c
+++ b/drivers/scsi/libiscsi.c
@@ -1456,7 +1456,7 @@
 		if (lun == task->sc->device->lun || lun == -1) {
 			debug_scsi("failing in progress sc %p itt 0x%x\n",
 				   task->sc, task->itt);
-			fail_command(conn, task, DID_BUS_BUSY << 16);
+			fail_command(conn, task, error << 16);
 		}
 	}
 }
@@ -1476,12 +1476,12 @@
 		scsi_queue_work(conn->session->host, &conn->xmitwork);
 }
 
-static enum scsi_eh_timer_return iscsi_eh_cmd_timed_out(struct scsi_cmnd *scmd)
+static enum blk_eh_timer_return iscsi_eh_cmd_timed_out(struct scsi_cmnd *scmd)
 {
 	struct iscsi_cls_session *cls_session;
 	struct iscsi_session *session;
 	struct iscsi_conn *conn;
-	enum scsi_eh_timer_return rc = EH_NOT_HANDLED;
+	enum blk_eh_timer_return rc = BLK_EH_NOT_HANDLED;
 
 	cls_session = starget_to_session(scsi_target(scmd->device));
 	session = cls_session->dd_data;
@@ -1494,14 +1494,14 @@
 		 * We are probably in the middle of iscsi recovery so let
 		 * that complete and handle the error.
 		 */
-		rc = EH_RESET_TIMER;
+		rc = BLK_EH_RESET_TIMER;
 		goto done;
 	}
 
 	conn = session->leadconn;
 	if (!conn) {
 		/* In the middle of shuting down */
-		rc = EH_RESET_TIMER;
+		rc = BLK_EH_RESET_TIMER;
 		goto done;
 	}
 
@@ -1513,20 +1513,21 @@
 	 */
 	if (time_before_eq(conn->last_recv + (conn->recv_timeout * HZ) +
 			    (conn->ping_timeout * HZ), jiffies))
-		rc = EH_RESET_TIMER;
+		rc = BLK_EH_RESET_TIMER;
 	/*
 	 * if we are about to check the transport then give the command
 	 * more time
 	 */
 	if (time_before_eq(conn->last_recv + (conn->recv_timeout * HZ),
 			   jiffies))
-		rc = EH_RESET_TIMER;
+		rc = BLK_EH_RESET_TIMER;
 	/* if in the middle of checking the transport then give us more time */
 	if (conn->ping_task)
-		rc = EH_RESET_TIMER;
+		rc = BLK_EH_RESET_TIMER;
 done:
 	spin_unlock(&session->lock);
-	debug_scsi("return %s\n", rc == EH_RESET_TIMER ? "timer reset" : "nh");
+	debug_scsi("return %s\n", rc == BLK_EH_RESET_TIMER ?
+					"timer reset" : "nh");
 	return rc;
 }
 
diff --git a/drivers/scsi/libsas/sas_ata.c b/drivers/scsi/libsas/sas_ata.c
index 48ee8c7..e155011 100644
--- a/drivers/scsi/libsas/sas_ata.c
+++ b/drivers/scsi/libsas/sas_ata.c
@@ -294,10 +294,10 @@
 	}
 }
 
-static int sas_ata_scr_write(struct ata_port *ap, unsigned int sc_reg_in,
+static int sas_ata_scr_write(struct ata_link *link, unsigned int sc_reg_in,
 			      u32 val)
 {
-	struct domain_device *dev = ap->private_data;
+	struct domain_device *dev = link->ap->private_data;
 
 	SAS_DPRINTK("STUB %s\n", __func__);
 	switch (sc_reg_in) {
@@ -319,10 +319,10 @@
 	return 0;
 }
 
-static int sas_ata_scr_read(struct ata_port *ap, unsigned int sc_reg_in,
+static int sas_ata_scr_read(struct ata_link *link, unsigned int sc_reg_in,
 			    u32 *val)
 {
-	struct domain_device *dev = ap->private_data;
+	struct domain_device *dev = link->ap->private_data;
 
 	SAS_DPRINTK("STUB %s\n", __func__);
 	switch (sc_reg_in) {
@@ -398,7 +398,7 @@
 
 	/* Bounce SCSI-initiated commands to the SCSI EH */
 	if (qc->scsicmd) {
-		scsi_req_abort_cmd(qc->scsicmd);
+		blk_abort_request(qc->scsicmd->request);
 		scsi_schedule_eh(qc->scsicmd->device->host);
 		return;
 	}
diff --git a/drivers/scsi/libsas/sas_internal.h b/drivers/scsi/libsas/sas_internal.h
index b4f9368..0001374 100644
--- a/drivers/scsi/libsas/sas_internal.h
+++ b/drivers/scsi/libsas/sas_internal.h
@@ -55,7 +55,7 @@
 int  sas_register_ports(struct sas_ha_struct *sas_ha);
 void sas_unregister_ports(struct sas_ha_struct *sas_ha);
 
-enum scsi_eh_timer_return sas_scsi_timed_out(struct scsi_cmnd *);
+enum blk_eh_timer_return sas_scsi_timed_out(struct scsi_cmnd *);
 
 int  sas_init_queue(struct sas_ha_struct *sas_ha);
 int  sas_init_events(struct sas_ha_struct *sas_ha);
diff --git a/drivers/scsi/libsas/sas_scsi_host.c b/drivers/scsi/libsas/sas_scsi_host.c
index a8e3ef3..7448387 100644
--- a/drivers/scsi/libsas/sas_scsi_host.c
+++ b/drivers/scsi/libsas/sas_scsi_host.c
@@ -673,43 +673,43 @@
 	return;
 }
 
-enum scsi_eh_timer_return sas_scsi_timed_out(struct scsi_cmnd *cmd)
+enum blk_eh_timer_return sas_scsi_timed_out(struct scsi_cmnd *cmd)
 {
 	struct sas_task *task = TO_SAS_TASK(cmd);
 	unsigned long flags;
 
 	if (!task) {
-		cmd->timeout_per_command /= 2;
+		cmd->request->timeout /= 2;
 		SAS_DPRINTK("command 0x%p, task 0x%p, gone: %s\n",
-			    cmd, task, (cmd->timeout_per_command ?
-			    "EH_RESET_TIMER" : "EH_NOT_HANDLED"));
-		if (!cmd->timeout_per_command)
-			return EH_NOT_HANDLED;
-		return EH_RESET_TIMER;
+			    cmd, task, (cmd->request->timeout ?
+			    "BLK_EH_RESET_TIMER" : "BLK_EH_NOT_HANDLED"));
+		if (!cmd->request->timeout)
+			return BLK_EH_NOT_HANDLED;
+		return BLK_EH_RESET_TIMER;
 	}
 
 	spin_lock_irqsave(&task->task_state_lock, flags);
 	BUG_ON(task->task_state_flags & SAS_TASK_STATE_ABORTED);
 	if (task->task_state_flags & SAS_TASK_STATE_DONE) {
 		spin_unlock_irqrestore(&task->task_state_lock, flags);
-		SAS_DPRINTK("command 0x%p, task 0x%p, timed out: EH_HANDLED\n",
-			    cmd, task);
-		return EH_HANDLED;
+		SAS_DPRINTK("command 0x%p, task 0x%p, timed out: "
+			    "BLK_EH_HANDLED\n", cmd, task);
+		return BLK_EH_HANDLED;
 	}
 	if (!(task->task_state_flags & SAS_TASK_AT_INITIATOR)) {
 		spin_unlock_irqrestore(&task->task_state_lock, flags);
 		SAS_DPRINTK("command 0x%p, task 0x%p, not at initiator: "
-			    "EH_RESET_TIMER\n",
+			    "BLK_EH_RESET_TIMER\n",
 			    cmd, task);
-		return EH_RESET_TIMER;
+		return BLK_EH_RESET_TIMER;
 	}
 	task->task_state_flags |= SAS_TASK_STATE_ABORTED;
 	spin_unlock_irqrestore(&task->task_state_lock, flags);
 
-	SAS_DPRINTK("command 0x%p, task 0x%p, timed out: EH_NOT_HANDLED\n",
+	SAS_DPRINTK("command 0x%p, task 0x%p, timed out: BLK_EH_NOT_HANDLED\n",
 		    cmd, task);
 
-	return EH_NOT_HANDLED;
+	return BLK_EH_NOT_HANDLED;
 }
 
 int sas_ioctl(struct scsi_device *sdev, int cmd, void __user *arg)
@@ -1039,7 +1039,7 @@
 		return;
 	}
 
-	scsi_req_abort_cmd(sc);
+	blk_abort_request(sc->request);
 	scsi_schedule_eh(sc->device->host);
 }
 
diff --git a/drivers/scsi/megaraid/megaraid_sas.c b/drivers/scsi/megaraid/megaraid_sas.c
index 97b7633..afe1de9 100644
--- a/drivers/scsi/megaraid/megaraid_sas.c
+++ b/drivers/scsi/megaraid/megaraid_sas.c
@@ -1167,7 +1167,7 @@
  * cmd has not been completed within the timeout period.
  */
 static enum
-scsi_eh_timer_return megasas_reset_timer(struct scsi_cmnd *scmd)
+blk_eh_timer_return megasas_reset_timer(struct scsi_cmnd *scmd)
 {
 	struct megasas_cmd *cmd = (struct megasas_cmd *)scmd->SCp.ptr;
 	struct megasas_instance *instance;
@@ -1175,7 +1175,7 @@
 
 	if (time_after(jiffies, scmd->jiffies_at_alloc +
 				(MEGASAS_DEFAULT_CMD_TIMEOUT * 2) * HZ)) {
-		return EH_NOT_HANDLED;
+		return BLK_EH_NOT_HANDLED;
 	}
 
 	instance = cmd->instance;
@@ -1189,7 +1189,7 @@
 
 		spin_unlock_irqrestore(instance->host->host_lock, flags);
 	}
-	return EH_RESET_TIMER;
+	return BLK_EH_RESET_TIMER;
 }
 
 /**
diff --git a/drivers/scsi/ncr53c8xx.c b/drivers/scsi/ncr53c8xx.c
index c57c94c..3b7240e 100644
--- a/drivers/scsi/ncr53c8xx.c
+++ b/drivers/scsi/ncr53c8xx.c
@@ -4170,8 +4170,8 @@
 	**
 	**----------------------------------------------------
 	*/
-	if (np->settle_time && cmd->timeout_per_command >= HZ) {
-		u_long tlimit = jiffies + cmd->timeout_per_command - HZ;
+	if (np->settle_time && cmd->request->timeout >= HZ) {
+		u_long tlimit = jiffies + cmd->request->timeout - HZ;
 		if (time_after(np->settle_time, tlimit))
 			np->settle_time = tlimit;
 	}
diff --git a/drivers/scsi/pcmcia/aha152x_stub.c b/drivers/scsi/pcmcia/aha152x_stub.c
index 2dd0dc9..165ff88 100644
--- a/drivers/scsi/pcmcia/aha152x_stub.c
+++ b/drivers/scsi/pcmcia/aha152x_stub.c
@@ -140,44 +140,41 @@
 #define CS_CHECK(fn, ret) \
 do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)
 
+static int aha152x_config_check(struct pcmcia_device *p_dev,
+				cistpl_cftable_entry_t *cfg,
+				cistpl_cftable_entry_t *dflt,
+				unsigned int vcc,
+				void *priv_data)
+{
+	/* For New Media T&J, look for a SCSI window */
+	if (cfg->io.win[0].len >= 0x20)
+		p_dev->io.BasePort1 = cfg->io.win[0].base;
+	else if ((cfg->io.nwin > 1) &&
+		 (cfg->io.win[1].len >= 0x20))
+		p_dev->io.BasePort1 = cfg->io.win[1].base;
+	if ((cfg->io.nwin > 0) &&
+	    (p_dev->io.BasePort1 < 0xffff)) {
+		if (!pcmcia_request_io(p_dev, &p_dev->io))
+			return 0;
+	}
+	return -EINVAL;
+}
+
 static int aha152x_config_cs(struct pcmcia_device *link)
 {
     scsi_info_t *info = link->priv;
     struct aha152x_setup s;
-    tuple_t tuple;
-    cisparse_t parse;
-    int i, last_ret, last_fn;
-    u_char tuple_data[64];
+    int last_ret, last_fn;
     struct Scsi_Host *host;
-    
+
     DEBUG(0, "aha152x_config(0x%p)\n", link);
 
-    tuple.TupleData = tuple_data;
-    tuple.TupleDataMax = 64;
-    tuple.TupleOffset = 0;
-    tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
-    tuple.Attributes = 0;
-    CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple));
-    while (1) {
-	if (pcmcia_get_tuple_data(link, &tuple) != 0 ||
-		pcmcia_parse_tuple(link, &tuple, &parse) != 0)
-	    goto next_entry;
-	/* For New Media T&J, look for a SCSI window */
-	if (parse.cftable_entry.io.win[0].len >= 0x20)
-	    link->io.BasePort1 = parse.cftable_entry.io.win[0].base;
-	else if ((parse.cftable_entry.io.nwin > 1) &&
-		 (parse.cftable_entry.io.win[1].len >= 0x20))
-	    link->io.BasePort1 = parse.cftable_entry.io.win[1].base;
-	if ((parse.cftable_entry.io.nwin > 0) &&
-	    (link->io.BasePort1 < 0xffff)) {
-	    link->conf.ConfigIndex = parse.cftable_entry.index;
-	    i = pcmcia_request_io(link, &link->io);
-	    if (i == CS_SUCCESS) break;
-	}
-    next_entry:
-	CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(link, &tuple));
+    last_ret = pcmcia_loop_config(link, aha152x_config_check, NULL);
+    if (last_ret) {
+	cs_error(link, RequestIO, last_ret);
+	goto failed;
     }
-    
+
     CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq));
     CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf));
     
@@ -208,6 +205,7 @@
 
 cs_failed:
     cs_error(link, last_fn, last_ret);
+failed:
     aha152x_release_cs(link);
     return -ENODEV;
 }
diff --git a/drivers/scsi/pcmcia/fdomain_stub.c b/drivers/scsi/pcmcia/fdomain_stub.c
index d8b9935..06254f4 100644
--- a/drivers/scsi/pcmcia/fdomain_stub.c
+++ b/drivers/scsi/pcmcia/fdomain_stub.c
@@ -123,34 +123,30 @@
 #define CS_CHECK(fn, ret) \
 do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)
 
+static int fdomain_config_check(struct pcmcia_device *p_dev,
+				cistpl_cftable_entry_t *cfg,
+				cistpl_cftable_entry_t *dflt,
+				unsigned int vcc,
+				void *priv_data)
+{
+	p_dev->io.BasePort1 = cfg->io.win[0].base;
+	return pcmcia_request_io(p_dev, &p_dev->io);
+}
+
+
 static int fdomain_config(struct pcmcia_device *link)
 {
     scsi_info_t *info = link->priv;
-    tuple_t tuple;
-    cisparse_t parse;
-    int i, last_ret, last_fn;
-    u_char tuple_data[64];
+    int last_ret, last_fn;
     char str[22];
     struct Scsi_Host *host;
 
     DEBUG(0, "fdomain_config(0x%p)\n", link);
 
-    tuple.TupleData = tuple_data;
-    tuple.TupleDataMax = 64;
-    tuple.TupleOffset = 0;
-
-    tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
-    CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple));
-    while (1) {
-	if (pcmcia_get_tuple_data(link, &tuple) != 0 ||
-		pcmcia_parse_tuple(link, &tuple, &parse) != 0)
-	    goto next_entry;
-	link->conf.ConfigIndex = parse.cftable_entry.index;
-	link->io.BasePort1 = parse.cftable_entry.io.win[0].base;
-	i = pcmcia_request_io(link, &link->io);
-	if (i == CS_SUCCESS) break;
-    next_entry:
-	CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(link, &tuple));
+    last_ret = pcmcia_loop_config(link, fdomain_config_check, NULL);
+    if (last_ret) {
+	    cs_error(link, RequestIO, last_ret);
+	    goto failed;
     }
 
     CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq));
@@ -181,6 +177,7 @@
 
 cs_failed:
     cs_error(link, last_fn, last_ret);
+failed:
     fdomain_release(link);
     return -ENODEV;
 } /* fdomain_config */
diff --git a/drivers/scsi/pcmcia/nsp_cs.c b/drivers/scsi/pcmcia/nsp_cs.c
index 24e6cb83..11a61ea 100644
--- a/drivers/scsi/pcmcia/nsp_cs.c
+++ b/drivers/scsi/pcmcia/nsp_cs.c
@@ -1606,133 +1606,129 @@
     is received, to configure the PCMCIA socket, and to make the
     ethernet device available to the system.
 ======================================================================*/
-#define CS_CHECK(fn, ret) \
-do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)
-/*====================================================================*/
+
+struct nsp_cs_configdata {
+	nsp_hw_data		*data;
+	win_req_t		req;
+};
+
+static int nsp_cs_config_check(struct pcmcia_device *p_dev,
+			       cistpl_cftable_entry_t *cfg,
+			       cistpl_cftable_entry_t *dflt,
+			       unsigned int vcc,
+			       void *priv_data)
+{
+	struct nsp_cs_configdata *cfg_mem = priv_data;
+
+	if (cfg->index == 0)
+		return -ENODEV;
+
+	/* Does this card need audio output? */
+	if (cfg->flags & CISTPL_CFTABLE_AUDIO) {
+		p_dev->conf.Attributes |= CONF_ENABLE_SPKR;
+		p_dev->conf.Status = CCSR_AUDIO_ENA;
+	}
+
+	/* Use power settings for Vcc and Vpp if present */
+	/*  Note that the CIS values need to be rescaled */
+	if (cfg->vcc.present & (1<<CISTPL_POWER_VNOM)) {
+		if (vcc != cfg->vcc.param[CISTPL_POWER_VNOM]/10000)
+			return -ENODEV;
+		else if (dflt->vcc.present & (1<<CISTPL_POWER_VNOM)) {
+			if (vcc != dflt->vcc.param[CISTPL_POWER_VNOM]/10000)
+				return -ENODEV;
+		}
+
+		if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM)) {
+			p_dev->conf.Vpp =
+				cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000;
+		} else if (dflt->vpp1.present & (1 << CISTPL_POWER_VNOM)) {
+			p_dev->conf.Vpp =
+				dflt->vpp1.param[CISTPL_POWER_VNOM] / 10000;
+		}
+
+		/* Do we need to allocate an interrupt? */
+		if (cfg->irq.IRQInfo1 || dflt->irq.IRQInfo1)
+			p_dev->conf.Attributes |= CONF_ENABLE_IRQ;
+
+		/* IO window settings */
+		p_dev->io.NumPorts1 = p_dev->io.NumPorts2 = 0;
+		if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) {
+			cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io;
+			p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
+			if (!(io->flags & CISTPL_IO_8BIT))
+				p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_16;
+			if (!(io->flags & CISTPL_IO_16BIT))
+				p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
+			p_dev->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK;
+			p_dev->io.BasePort1 = io->win[0].base;
+			p_dev->io.NumPorts1 = io->win[0].len;
+			if (io->nwin > 1) {
+				p_dev->io.Attributes2 = p_dev->io.Attributes1;
+				p_dev->io.BasePort2 = io->win[1].base;
+				p_dev->io.NumPorts2 = io->win[1].len;
+			}
+			/* This reserves IO space but doesn't actually enable it */
+			if (pcmcia_request_io(p_dev, &p_dev->io) != 0)
+				goto next_entry;
+		}
+
+		if ((cfg->mem.nwin > 0) || (dflt->mem.nwin > 0)) {
+			memreq_t	map;
+			cistpl_mem_t	*mem =
+				(cfg->mem.nwin) ? &cfg->mem : &dflt->mem;
+			cfg_mem->req.Attributes = WIN_DATA_WIDTH_16|WIN_MEMORY_TYPE_CM;
+			cfg_mem->req.Attributes |= WIN_ENABLE;
+			cfg_mem->req.Base = mem->win[0].host_addr;
+			cfg_mem->req.Size = mem->win[0].len;
+			if (cfg_mem->req.Size < 0x1000)
+				cfg_mem->req.Size = 0x1000;
+			cfg_mem->req.AccessSpeed = 0;
+			if (pcmcia_request_window(&p_dev, &cfg_mem->req, &p_dev->win) != 0)
+				goto next_entry;
+			map.Page = 0; map.CardOffset = mem->win[0].card_addr;
+			if (pcmcia_map_mem_page(p_dev->win, &map) != 0)
+				goto next_entry;
+
+			cfg_mem->data->MmioAddress = (unsigned long) ioremap_nocache(cfg_mem->req.Base, cfg_mem->req.Size);
+			cfg_mem->data->MmioLength  = cfg_mem->req.Size;
+		}
+		/* If we got this far, we're cool! */
+		return 0;
+	}
+
+next_entry:
+	nsp_dbg(NSP_DEBUG_INIT, "next");
+	pcmcia_disable_device(p_dev);
+	return -ENODEV;
+}
+
 static int nsp_cs_config(struct pcmcia_device *link)
 {
 	int		  ret;
 	scsi_info_t	 *info	 = link->priv;
-	tuple_t		  tuple;
-	cisparse_t	  parse;
-	int		  last_ret, last_fn;
-	unsigned char	  tuple_data[64];
-	config_info_t	  conf;
-	win_req_t         req;
-	memreq_t          map;
-	cistpl_cftable_entry_t dflt = { 0 };
+	struct nsp_cs_configdata *cfg_mem;
 	struct Scsi_Host *host;
 	nsp_hw_data      *data = &nsp_data_base;
 
 	nsp_dbg(NSP_DEBUG_INIT, "in");
 
-	tuple.Attributes      = 0;
-	tuple.TupleData	      = tuple_data;
-	tuple.TupleDataMax    = sizeof(tuple_data);
-	tuple.TupleOffset     = 0;
+	cfg_mem = kzalloc(sizeof(cfg_mem), GFP_KERNEL);
+	if (!cfg_mem)
+		return -ENOMEM;
+	cfg_mem->data = data;
 
-	/* Look up the current Vcc */
-	CS_CHECK(GetConfigurationInfo, pcmcia_get_configuration_info(link, &conf));
-
-	tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
-	CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple));
-	while (1) {
-		cistpl_cftable_entry_t *cfg = &(parse.cftable_entry);
-
-		if (pcmcia_get_tuple_data(link, &tuple) != 0 ||
-				pcmcia_parse_tuple(link, &tuple, &parse) != 0)
-			goto next_entry;
-
-		if (cfg->flags & CISTPL_CFTABLE_DEFAULT) { dflt = *cfg; }
-		if (cfg->index == 0) { goto next_entry; }
-		link->conf.ConfigIndex = cfg->index;
-
-		/* Does this card need audio output? */
-		if (cfg->flags & CISTPL_CFTABLE_AUDIO) {
-			link->conf.Attributes |= CONF_ENABLE_SPKR;
-			link->conf.Status = CCSR_AUDIO_ENA;
-		}
-
-		/* Use power settings for Vcc and Vpp if present */
-		/*  Note that the CIS values need to be rescaled */
-		if (cfg->vcc.present & (1<<CISTPL_POWER_VNOM)) {
-			if (conf.Vcc != cfg->vcc.param[CISTPL_POWER_VNOM]/10000) {
-				goto next_entry;
-			}
-		} else if (dflt.vcc.present & (1<<CISTPL_POWER_VNOM)) {
-			if (conf.Vcc != dflt.vcc.param[CISTPL_POWER_VNOM]/10000) {
-				goto next_entry;
-			}
-		}
-
-		if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM)) {
-			link->conf.Vpp =
-				cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000;
-		} else if (dflt.vpp1.present & (1 << CISTPL_POWER_VNOM)) {
-			link->conf.Vpp =
-				dflt.vpp1.param[CISTPL_POWER_VNOM] / 10000;
-		}
-
-		/* Do we need to allocate an interrupt? */
-		if (cfg->irq.IRQInfo1 || dflt.irq.IRQInfo1) {
-			link->conf.Attributes |= CONF_ENABLE_IRQ;
-		}
-
-		/* IO window settings */
-		link->io.NumPorts1 = link->io.NumPorts2 = 0;
-		if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) {
-			cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt.io;
-			link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
-			if (!(io->flags & CISTPL_IO_8BIT))
-				link->io.Attributes1 = IO_DATA_PATH_WIDTH_16;
-			if (!(io->flags & CISTPL_IO_16BIT))
-				link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
-			link->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK;
-			link->io.BasePort1 = io->win[0].base;
-			link->io.NumPorts1 = io->win[0].len;
-			if (io->nwin > 1) {
-				link->io.Attributes2 = link->io.Attributes1;
-				link->io.BasePort2 = io->win[1].base;
-				link->io.NumPorts2 = io->win[1].len;
-			}
-			/* This reserves IO space but doesn't actually enable it */
-			if (pcmcia_request_io(link, &link->io) != 0)
-				goto next_entry;
-		}
-
-		if ((cfg->mem.nwin > 0) || (dflt.mem.nwin > 0)) {
-			cistpl_mem_t *mem =
-				(cfg->mem.nwin) ? &cfg->mem : &dflt.mem;
-			req.Attributes = WIN_DATA_WIDTH_16|WIN_MEMORY_TYPE_CM;
-			req.Attributes |= WIN_ENABLE;
-			req.Base = mem->win[0].host_addr;
-			req.Size = mem->win[0].len;
-			if (req.Size < 0x1000) {
-				req.Size = 0x1000;
-			}
-			req.AccessSpeed = 0;
-			if (pcmcia_request_window(&link, &req, &link->win) != 0)
-				goto next_entry;
-			map.Page = 0; map.CardOffset = mem->win[0].card_addr;
-			if (pcmcia_map_mem_page(link->win, &map) != 0)
-				goto next_entry;
-
-			data->MmioAddress = (unsigned long)ioremap_nocache(req.Base, req.Size);
-			data->MmioLength  = req.Size;
-		}
-		/* If we got this far, we're cool! */
-		break;
-
-	next_entry:
-		nsp_dbg(NSP_DEBUG_INIT, "next");
-		pcmcia_disable_device(link);
-		CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(link, &tuple));
-	}
+	ret = pcmcia_loop_config(link, nsp_cs_config_check, cfg_mem);
+		goto cs_failed;
 
 	if (link->conf.Attributes & CONF_ENABLE_IRQ) {
-		CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq));
+		if (pcmcia_request_irq(link, &link->irq))
+			goto cs_failed;
 	}
-	CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf));
+
+	ret = pcmcia_request_configuration(link, &link->conf);
+	if (ret)
+		goto cs_failed;
 
 	if (free_ports) {
 		if (link->io.BasePort1) {
@@ -1790,20 +1786,20 @@
 		printk(" & 0x%04x-0x%04x", link->io.BasePort2,
 		       link->io.BasePort2+link->io.NumPorts2-1);
 	if (link->win)
-		printk(", mem 0x%06lx-0x%06lx", req.Base,
-		       req.Base+req.Size-1);
+		printk(", mem 0x%06lx-0x%06lx", cfg_mem->req.Base,
+		       cfg_mem->req.Base+cfg_mem->req.Size-1);
 	printk("\n");
 
+	kfree(cfg_mem);
 	return 0;
 
  cs_failed:
 	nsp_dbg(NSP_DEBUG_INIT, "config fail");
-	cs_error(link, last_fn, last_ret);
 	nsp_cs_release(link);
+	kfree(cfg_mem);
 
 	return -ENODEV;
 } /* nsp_cs_config */
-#undef CS_CHECK
 
 
 /*======================================================================
diff --git a/drivers/scsi/pcmcia/qlogic_stub.c b/drivers/scsi/pcmcia/qlogic_stub.c
index 67c5a58..20c3e5e 100644
--- a/drivers/scsi/pcmcia/qlogic_stub.c
+++ b/drivers/scsi/pcmcia/qlogic_stub.c
@@ -195,39 +195,33 @@
 #define CS_CHECK(fn, ret) \
 do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)
 
+static int qlogic_config_check(struct pcmcia_device *p_dev,
+			       cistpl_cftable_entry_t *cfg,
+			       cistpl_cftable_entry_t *dflt,
+			       unsigned int vcc,
+			       void *priv_data)
+{
+	p_dev->io.BasePort1 = cfg->io.win[0].base;
+	p_dev->io.NumPorts1 = cfg->io.win[0].len;
+
+	if (p_dev->io.BasePort1 == 0)
+		return -ENODEV;
+
+	return pcmcia_request_io(p_dev, &p_dev->io);
+}
+
 static int qlogic_config(struct pcmcia_device * link)
 {
 	scsi_info_t *info = link->priv;
-	tuple_t tuple;
-	cisparse_t parse;
-	int i, last_ret, last_fn;
-	unsigned short tuple_data[32];
+	int last_ret, last_fn;
 	struct Scsi_Host *host;
 
 	DEBUG(0, "qlogic_config(0x%p)\n", link);
 
-	info->manf_id = link->manf_id;
-
-	tuple.TupleData = (cisdata_t *) tuple_data;
-	tuple.TupleDataMax = 64;
-	tuple.TupleOffset = 0;
-
-	tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
-	CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple));
-	while (1) {
-		if (pcmcia_get_tuple_data(link, &tuple) != 0 ||
-				pcmcia_parse_tuple(link, &tuple, &parse) != 0)
-			goto next_entry;
-		link->conf.ConfigIndex = parse.cftable_entry.index;
-		link->io.BasePort1 = parse.cftable_entry.io.win[0].base;
-		link->io.NumPorts1 = parse.cftable_entry.io.win[0].len;
-		if (link->io.BasePort1 != 0) {
-			i = pcmcia_request_io(link, &link->io);
-			if (i == CS_SUCCESS)
-				break;
-		}
-	      next_entry:
-		CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(link, &tuple));
+	last_ret = pcmcia_loop_config(link, qlogic_config_check, NULL);
+	if (last_ret) {
+		cs_error(link, RequestIO, last_ret);
+		goto failed;
 	}
 
 	CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq));
@@ -262,6 +256,7 @@
 cs_failed:
 	cs_error(link, last_fn, last_ret);
 	pcmcia_disable_device(link);
+failed:
 	return -ENODEV;
 
 }				/* qlogic_config */
diff --git a/drivers/scsi/pcmcia/sym53c500_cs.c b/drivers/scsi/pcmcia/sym53c500_cs.c
index 0be232b..b330c11 100644
--- a/drivers/scsi/pcmcia/sym53c500_cs.c
+++ b/drivers/scsi/pcmcia/sym53c500_cs.c
@@ -700,15 +700,27 @@
 #define CS_CHECK(fn, ret) \
 do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)
 
+static int SYM53C500_config_check(struct pcmcia_device *p_dev,
+				  cistpl_cftable_entry_t *cfg,
+				  cistpl_cftable_entry_t *dflt,
+				  unsigned int vcc,
+				  void *priv_data)
+{
+	p_dev->io.BasePort1 = cfg->io.win[0].base;
+	p_dev->io.NumPorts1 = cfg->io.win[0].len;
+
+	if (p_dev->io.BasePort1 == 0)
+		return -ENODEV;
+
+	return pcmcia_request_io(p_dev, &p_dev->io);
+}
+
 static int
 SYM53C500_config(struct pcmcia_device *link)
 {
 	struct scsi_info_t *info = link->priv;
-	tuple_t tuple;
-	cisparse_t parse;
-	int i, last_ret, last_fn;
+	int last_ret, last_fn;
 	int irq_level, port_base;
-	unsigned short tuple_data[32];
 	struct Scsi_Host *host;
 	struct scsi_host_template *tpnt = &sym53c500_driver_template;
 	struct sym53c500_data *data;
@@ -717,27 +729,10 @@
 
 	info->manf_id = link->manf_id;
 
-	tuple.TupleData = (cisdata_t *)tuple_data;
-	tuple.TupleDataMax = 64;
-	tuple.TupleOffset = 0;
-
-	tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
-	CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple));
-	while (1) {
-		if (pcmcia_get_tuple_data(link, &tuple) != 0 ||
-		    pcmcia_parse_tuple(link, &tuple, &parse) != 0)
-			goto next_entry;
-		link->conf.ConfigIndex = parse.cftable_entry.index;
-		link->io.BasePort1 = parse.cftable_entry.io.win[0].base;
-		link->io.NumPorts1 = parse.cftable_entry.io.win[0].len;
-
-		if (link->io.BasePort1 != 0) {
-			i = pcmcia_request_io(link, &link->io);
-			if (i == CS_SUCCESS)
-				break;
-		}
-next_entry:
-		CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(link, &tuple));
+	last_ret = pcmcia_loop_config(link, SYM53C500_config_check, NULL);
+	if (last_ret) {
+		cs_error(link, RequestIO, last_ret);
+		goto failed;
 	}
 
 	CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq));
@@ -831,6 +826,7 @@
 
 cs_failed:
 	cs_error(link, last_fn, last_ret);
+failed:
 	SYM53C500_release(link);
 	return -ENODEV;
 } /* SYM53C500_config */
diff --git a/drivers/scsi/qla1280.c b/drivers/scsi/qla1280.c
index 37f9ba0..b6cd12b 100644
--- a/drivers/scsi/qla1280.c
+++ b/drivers/scsi/qla1280.c
@@ -2845,7 +2845,7 @@
 	memset(((char *)pkt + 8), 0, (REQUEST_ENTRY_SIZE - 8));
 
 	/* Set ISP command timeout. */
-	pkt->timeout = cpu_to_le16(cmd->timeout_per_command/HZ);
+	pkt->timeout = cpu_to_le16(cmd->request->timeout/HZ);
 
 	/* Set device target ID and LUN */
 	pkt->lun = SCSI_LUN_32(cmd);
@@ -3114,7 +3114,7 @@
 	memset(((char *)pkt + 8), 0, (REQUEST_ENTRY_SIZE - 8));
 
 	/* Set ISP command timeout. */
-	pkt->timeout = cpu_to_le16(cmd->timeout_per_command/HZ);
+	pkt->timeout = cpu_to_le16(cmd->request->timeout/HZ);
 
 	/* Set device target ID and LUN */
 	pkt->lun = SCSI_LUN_32(cmd);
diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c
index 45e7dcb..0ddfe71 100644
--- a/drivers/scsi/qla2xxx/qla_attr.c
+++ b/drivers/scsi/qla2xxx/qla_attr.c
@@ -292,10 +292,11 @@
 		valid = 0;
 		if (ha->optrom_size == OPTROM_SIZE_2300 && start == 0)
 			valid = 1;
-		else if (start == (FA_BOOT_CODE_ADDR*4) ||
-		    start == (FA_RISC_CODE_ADDR*4))
+		else if (start == (ha->flt_region_boot * 4) ||
+		    start == (ha->flt_region_fw * 4))
 			valid = 1;
-		else if (IS_QLA25XX(ha) && start == (FA_VPD_NVRAM_ADDR*4))
+		else if (IS_QLA25XX(ha) &&
+		    start == (ha->flt_region_vpd_nvram * 4))
 		    valid = 1;
 		if (!valid) {
 			qla_printk(KERN_WARNING, ha,
@@ -1065,6 +1066,8 @@
 		pfc_host_stat->dumped_frames = stats->dumped_frames;
 		pfc_host_stat->nos_count = stats->nos_rcvd;
 	}
+	pfc_host_stat->fcp_input_megabytes = ha->qla_stats.input_bytes >> 20;
+	pfc_host_stat->fcp_output_megabytes = ha->qla_stats.output_bytes >> 20;
 
 done_free:
         dma_pool_free(ha->s_dma_pool, stats, stats_dma);
diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
index 94a720e..83c8192 100644
--- a/drivers/scsi/qla2xxx/qla_def.h
+++ b/drivers/scsi/qla2xxx/qla_def.h
@@ -25,7 +25,6 @@
 #include <linux/firmware.h>
 #include <linux/aer.h>
 #include <linux/mutex.h>
-#include <linux/semaphore.h>
 
 #include <scsi/scsi.h>
 #include <scsi/scsi_host.h>
@@ -2157,6 +2156,8 @@
 
 struct qla_statistics {
 	uint32_t total_isp_aborts;
+	uint64_t input_bytes;
+	uint64_t output_bytes;
 };
 
 /*
@@ -2238,6 +2239,7 @@
 #define FCPORT_UPDATE_NEEDED	27
 #define VP_DPC_NEEDED		28	/* wake up for VP dpc handling */
 #define UNLOADING		29
+#define NPIV_CONFIG_NEEDED	30
 
 	uint32_t	device_flags;
 #define DFLG_LOCAL_DEVICES		BIT_0
@@ -2507,7 +2509,6 @@
 	uint64_t	fce_wr, fce_rd;
 	struct mutex	fce_mutex;
 
-	uint32_t	hw_event_start;
 	uint32_t	hw_event_ptr;
 	uint32_t	hw_event_pause_errors;
 
@@ -2553,6 +2554,14 @@
 	uint32_t	fdt_unprotect_sec_cmd;
 	uint32_t	fdt_protect_sec_cmd;
 
+	uint32_t	flt_region_flt;
+	uint32_t	flt_region_fdt;
+	uint32_t	flt_region_boot;
+	uint32_t	flt_region_fw;
+	uint32_t	flt_region_vpd_nvram;
+	uint32_t	flt_region_hw_event;
+	uint32_t	flt_region_npiv_conf;
+
 	/* Needed for BEACON */
 	uint16_t	beacon_blink_led;
 	uint8_t		beacon_color_state;
diff --git a/drivers/scsi/qla2xxx/qla_fw.h b/drivers/scsi/qla2xxx/qla_fw.h
index cf19451..d1d1420 100644
--- a/drivers/scsi/qla2xxx/qla_fw.h
+++ b/drivers/scsi/qla2xxx/qla_fw.h
@@ -789,14 +789,23 @@
 #define FA_RISC_CODE_ADDR	0x20000
 #define FA_RISC_CODE_SEGMENTS	2
 
+#define FA_FLASH_DESCR_ADDR_24	0x11000
+#define FA_FLASH_LAYOUT_ADDR_24	0x11400
+#define FA_NPIV_CONF0_ADDR_24	0x16000
+#define FA_NPIV_CONF1_ADDR_24	0x17000
+
 #define FA_FW_AREA_ADDR		0x40000
 #define FA_VPD_NVRAM_ADDR	0x48000
 #define FA_FEATURE_ADDR		0x4C000
 #define FA_FLASH_DESCR_ADDR	0x50000
+#define FA_FLASH_LAYOUT_ADDR	0x50400
 #define FA_HW_EVENT0_ADDR	0x54000
-#define FA_HW_EVENT1_ADDR	0x54200
+#define FA_HW_EVENT1_ADDR	0x54400
 #define FA_HW_EVENT_SIZE	0x200
 #define FA_HW_EVENT_ENTRY_SIZE	4
+#define FA_NPIV_CONF0_ADDR	0x5C000
+#define FA_NPIV_CONF1_ADDR	0x5D000
+
 /*
  * Flash Error Log Event Codes.
  */
@@ -806,10 +815,6 @@
 #define HW_EVENT_NVRAM_CHKSUM_ERR	0xF023
 #define HW_EVENT_FLASH_FW_ERR	0xF024
 
-#define FA_BOOT_LOG_ADDR	0x58000
-#define FA_FW_DUMP0_ADDR	0x60000
-#define FA_FW_DUMP1_ADDR	0x70000
-
 	uint32_t flash_data;		/* Flash/NVRAM BIOS data. */
 
 	uint32_t ctrl_status;		/* Control/Status. */
@@ -1203,6 +1208,62 @@
 	uint8_t unused2[65];
 };
 
+/* Flash Layout Table ********************************************************/
+
+struct qla_flt_location {
+	uint8_t sig[4];
+	uint32_t start_lo;
+	uint32_t start_hi;
+	uint16_t unused;
+	uint16_t checksum;
+};
+
+struct qla_flt_header {
+	uint16_t version;
+	uint16_t length;
+	uint16_t checksum;
+	uint16_t unused;
+};
+
+#define FLT_REG_FW		0x01
+#define FLT_REG_BOOT_CODE	0x07
+#define FLT_REG_VPD_0		0x14
+#define FLT_REG_NVRAM_0		0x15
+#define FLT_REG_VPD_1		0x16
+#define FLT_REG_NVRAM_1		0x17
+#define FLT_REG_FDT		0x1a
+#define FLT_REG_FLT		0x1c
+#define FLT_REG_HW_EVENT_0	0x1d
+#define FLT_REG_HW_EVENT_1	0x1f
+#define FLT_REG_NPIV_CONF_0	0x29
+#define FLT_REG_NPIV_CONF_1	0x2a
+
+struct qla_flt_region {
+	uint32_t code;
+	uint32_t size;
+	uint32_t start;
+	uint32_t end;
+};
+
+/* Flash NPIV Configuration Table ********************************************/
+
+struct qla_npiv_header {
+	uint8_t sig[2];
+	uint16_t version;
+	uint16_t entries;
+	uint16_t unused[4];
+	uint16_t checksum;
+};
+
+struct qla_npiv_entry {
+	uint16_t flags;
+	uint16_t vf_id;
+	uint16_t qos;
+	uint16_t unused1;
+	uint8_t port_name[WWN_SIZE];
+	uint8_t node_name[WWN_SIZE];
+};
+
 /* 84XX Support **************************************************************/
 
 #define MBA_ISP84XX_ALERT	0x800f  /* Alert Notification. */
diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h
index 0b15673..753dbe6 100644
--- a/drivers/scsi/qla2xxx/qla_gbl.h
+++ b/drivers/scsi/qla2xxx/qla_gbl.h
@@ -313,9 +313,11 @@
 extern int qla2xxx_hw_event_log(scsi_qla_host_t *, uint16_t , uint16_t,
     uint16_t, uint16_t);
 
-extern void qla2xxx_get_flash_info(scsi_qla_host_t *);
+extern int qla2xxx_get_flash_info(scsi_qla_host_t *);
 extern int qla2xxx_get_vpd_field(scsi_qla_host_t *, char *, char *, size_t);
 
+extern void qla2xxx_flash_npiv_conf(scsi_qla_host_t *);
+
 /*
  * Global Function Prototypes in qla_dbg.c source file.
  */
diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c
index ee89ddd..a470f2d 100644
--- a/drivers/scsi/qla2xxx/qla_init.c
+++ b/drivers/scsi/qla2xxx/qla_init.c
@@ -83,6 +83,13 @@
 
 	ha->isp_ops->reset_chip(ha);
 
+	rval = qla2xxx_get_flash_info(ha);
+	if (rval) {
+		DEBUG2(printk("scsi(%ld): Unable to validate FLASH data.\n",
+		    ha->host_no));
+		return (rval);
+	}
+
 	ha->isp_ops->get_flash_version(ha, ha->request_ring);
 
 	qla_printk(KERN_INFO, ha, "Configure NVRAM parameters...\n");
@@ -109,7 +116,6 @@
 		rval = qla2x00_setup_chip(ha);
 		if (rval)
 			return (rval);
-		qla2xxx_get_flash_info(ha);
 	}
 	if (IS_QLA84XX(ha)) {
 		ha->cs84xx = qla84xx_get_chip(ha);
@@ -2016,7 +2022,7 @@
 		DEBUG3(printk("%s: exiting normally\n", __func__));
 	}
 
-	/* Restore state if a resync event occured during processing */
+	/* Restore state if a resync event occurred during processing */
 	if (test_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags)) {
 		if (test_bit(LOCAL_LOOP_UPDATE, &save_flags))
 			set_bit(LOCAL_LOOP_UPDATE, &ha->dpc_flags);
@@ -2561,7 +2567,7 @@
 	rval = QLA_SUCCESS;
 
 	/* Try GID_PT to get device list, else GAN. */
-	swl = kcalloc(MAX_FIBRE_DEVICES, sizeof(sw_info_t), GFP_ATOMIC);
+	swl = kcalloc(MAX_FIBRE_DEVICES, sizeof(sw_info_t), GFP_KERNEL);
 	if (!swl) {
 		/*EMPTY*/
 		DEBUG2(printk("scsi(%ld): GID_PT allocations failed, fallback "
@@ -3751,7 +3757,7 @@
 	rval = QLA_SUCCESS;
 
 	segments = FA_RISC_CODE_SEGMENTS;
-	faddr = FA_RISC_CODE_ADDR;
+	faddr = ha->flt_region_fw;
 	dcode = (uint32_t *)ha->request_ring;
 	*srisc_addr = 0;
 
diff --git a/drivers/scsi/qla2xxx/qla_inline.h b/drivers/scsi/qla2xxx/qla_inline.h
index 92fafbd..e90afad 100644
--- a/drivers/scsi/qla2xxx/qla_inline.h
+++ b/drivers/scsi/qla2xxx/qla_inline.h
@@ -52,7 +52,7 @@
  * @ha: HA context
  * @ha_locked: is function called with the hardware lock
  *
- * Returns non-zero if a failure occured, else zero.
+ * Returns non-zero if a failure occurred, else zero.
  */
 static inline int
 qla2x00_issue_marker(scsi_qla_host_t *ha, int ha_locked)
diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c
index d57669a..85bc0a4 100644
--- a/drivers/scsi/qla2xxx/qla_iocb.c
+++ b/drivers/scsi/qla2xxx/qla_iocb.c
@@ -21,17 +21,22 @@
  * Returns the proper CF_* direction based on CDB.
  */
 static inline uint16_t
-qla2x00_get_cmd_direction(struct scsi_cmnd *cmd)
+qla2x00_get_cmd_direction(srb_t *sp)
 {
 	uint16_t cflags;
 
 	cflags = 0;
 
 	/* Set transfer direction */
-	if (cmd->sc_data_direction == DMA_TO_DEVICE)
+	if (sp->cmd->sc_data_direction == DMA_TO_DEVICE) {
 		cflags = CF_WRITE;
-	else if (cmd->sc_data_direction == DMA_FROM_DEVICE)
+		sp->fcport->ha->qla_stats.output_bytes +=
+		    scsi_bufflen(sp->cmd);
+	} else if (sp->cmd->sc_data_direction == DMA_FROM_DEVICE) {
 		cflags = CF_READ;
+		sp->fcport->ha->qla_stats.input_bytes +=
+		    scsi_bufflen(sp->cmd);
+	}
 	return (cflags);
 }
 
@@ -169,7 +174,7 @@
 
 	ha = sp->ha;
 
-	cmd_pkt->control_flags |= cpu_to_le16(qla2x00_get_cmd_direction(cmd));
+	cmd_pkt->control_flags |= cpu_to_le16(qla2x00_get_cmd_direction(sp));
 
 	/* Three DSDs are available in the Command Type 2 IOCB */
 	avail_dsds = 3;
@@ -228,7 +233,7 @@
 
 	ha = sp->ha;
 
-	cmd_pkt->control_flags |= cpu_to_le16(qla2x00_get_cmd_direction(cmd));
+	cmd_pkt->control_flags |= cpu_to_le16(qla2x00_get_cmd_direction(sp));
 
 	/* Two DSDs are available in the Command Type 3 IOCB */
 	avail_dsds = 2;
@@ -262,7 +267,7 @@
  * qla2x00_start_scsi() - Send a SCSI command to the ISP
  * @sp: command to send to the ISP
  *
- * Returns non-zero if a failure occured, else zero.
+ * Returns non-zero if a failure occurred, else zero.
  */
 int
 qla2x00_start_scsi(srb_t *sp)
@@ -407,7 +412,7 @@
  *
  * Can be called from both normal and interrupt context.
  *
- * Returns non-zero if a failure occured, else zero.
+ * Returns non-zero if a failure occurred, else zero.
  */
 int
 __qla2x00_marker(scsi_qla_host_t *ha, uint16_t loop_id, uint16_t lun,
@@ -625,12 +630,17 @@
 	ha = sp->ha;
 
 	/* Set transfer direction */
-	if (cmd->sc_data_direction == DMA_TO_DEVICE)
+	if (cmd->sc_data_direction == DMA_TO_DEVICE) {
 		cmd_pkt->task_mgmt_flags =
 		    __constant_cpu_to_le16(TMF_WRITE_DATA);
-	else if (cmd->sc_data_direction == DMA_FROM_DEVICE)
+		sp->fcport->ha->qla_stats.output_bytes +=
+		    scsi_bufflen(sp->cmd);
+	} else if (cmd->sc_data_direction == DMA_FROM_DEVICE) {
 		cmd_pkt->task_mgmt_flags =
 		    __constant_cpu_to_le16(TMF_READ_DATA);
+		sp->fcport->ha->qla_stats.input_bytes +=
+		    scsi_bufflen(sp->cmd);
+	}
 
 	/* One DSD is available in the Command Type 3 IOCB */
 	avail_dsds = 1;
@@ -666,7 +676,7 @@
  * qla24xx_start_scsi() - Send a SCSI command to the ISP
  * @sp: command to send to the ISP
  *
- * Returns non-zero if a failure occured, else zero.
+ * Returns non-zero if a failure occurred, else zero.
  */
 int
 qla24xx_start_scsi(srb_t *sp)
diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c
index 45a3b93..fc4bfa7 100644
--- a/drivers/scsi/qla2xxx/qla_isr.c
+++ b/drivers/scsi/qla2xxx/qla_isr.c
@@ -391,9 +391,9 @@
 		break;
 
 	case MBA_LIP_OCCURRED:		/* Loop Initialization Procedure */
-		DEBUG2(printk("scsi(%ld): LIP occured (%x).\n", ha->host_no,
+		DEBUG2(printk("scsi(%ld): LIP occurred (%x).\n", ha->host_no,
 		    mb[1]));
-		qla_printk(KERN_INFO, ha, "LIP occured (%x).\n", mb[1]);
+		qla_printk(KERN_INFO, ha, "LIP occurred (%x).\n", mb[1]);
 
 		if (atomic_read(&ha->loop_state) != LOOP_DOWN) {
 			atomic_set(&ha->loop_state, LOOP_DOWN);
@@ -460,7 +460,7 @@
 		DEBUG2(printk("scsi(%ld): Asynchronous LIP RESET (%x).\n",
 		    ha->host_no, mb[1]));
 		qla_printk(KERN_INFO, ha,
-		    "LIP reset occured (%x).\n", mb[1]);
+		    "LIP reset occurred (%x).\n", mb[1]);
 
 		if (atomic_read(&ha->loop_state) != LOOP_DOWN) {
 			atomic_set(&ha->loop_state, LOOP_DOWN);
@@ -543,7 +543,7 @@
 
 	case MBA_PORT_UPDATE:		/* Port database update */
 		/*
-		 * If PORT UPDATE is global (recieved LIP_OCCURED/LIP_RESET
+		 * If PORT UPDATE is global (received LIP_OCCURRED/LIP_RESET
 		 * event etc. earlier indicating loop is down) then process
 		 * it.  Otherwise ignore it and Wait for RSCN to come in.
 		 */
@@ -589,7 +589,7 @@
 		    "scsi(%ld): RSCN database changed -- %04x %04x %04x.\n",
 		    ha->host_no, mb[1], mb[2], mb[3]));
 
-		rscn_entry = (mb[1] << 16) | mb[2];
+		rscn_entry = ((mb[1] & 0xff) << 16) | mb[2];
 		host_pid = (ha->d_id.b.domain << 16) | (ha->d_id.b.area << 8) |
 		    ha->d_id.b.al_pa;
 		if (rscn_entry == host_pid) {
@@ -600,6 +600,8 @@
 			break;
 		}
 
+		/* Ignore reserved bits from RSCN-payload. */
+		rscn_entry = ((mb[1] & 0x3ff) << 16) | mb[2];
 		rscn_queue_index = ha->rscn_in_ptr + 1;
 		if (rscn_queue_index == MAX_RSCN_COUNT)
 			rscn_queue_index = 0;
@@ -1060,8 +1062,9 @@
 		resid = resid_len;
 		/* Use F/W calculated residual length. */
 		if (IS_FWI2_CAPABLE(ha)) {
-			if (scsi_status & SS_RESIDUAL_UNDER &&
-			    resid != fw_resid_len) {
+			if (!(scsi_status & SS_RESIDUAL_UNDER)) {
+				lscsi_status = 0;
+			} else if (resid != fw_resid_len) {
 				scsi_status &= ~SS_RESIDUAL_UNDER;
 				lscsi_status = 0;
 			}
@@ -1834,7 +1837,6 @@
 		WRT_REG_WORD(&reg->isp.hccr, HCCR_CLR_HOST_INT);
 	}
 	spin_unlock_irq(&ha->hardware_lock);
-	ha->isp_ops->enable_intrs(ha);
 
 fail:
 	return ret;
diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c
index 813bc77..36bc685 100644
--- a/drivers/scsi/qla2xxx/qla_mbx.c
+++ b/drivers/scsi/qla2xxx/qla_mbx.c
@@ -233,7 +233,7 @@
 			DEBUG2_3_11(printk("%s(%ld): timeout schedule "
 			    "isp_abort_needed.\n", __func__, ha->host_no));
 			qla_printk(KERN_WARNING, ha,
-			    "Mailbox command timeout occured. Scheduling ISP "
+			    "Mailbox command timeout occurred. Scheduling ISP "
 			    "abort.\n");
 			set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags);
 			qla2xxx_wake_dpc(ha);
@@ -244,7 +244,7 @@
 			DEBUG2_3_11(printk("%s(%ld): timeout calling "
 			    "abort_isp\n", __func__, ha->host_no));
 			qla_printk(KERN_WARNING, ha,
-			    "Mailbox command timeout occured. Issuing ISP "
+			    "Mailbox command timeout occurred. Issuing ISP "
 			    "abort.\n");
 
 			set_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags);
@@ -1995,7 +1995,7 @@
 	char *pmap;
 	dma_addr_t pmap_dma;
 
-	pmap = dma_pool_alloc(ha->s_dma_pool, GFP_ATOMIC, &pmap_dma);
+	pmap = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &pmap_dma);
 	if (pmap  == NULL) {
 		DEBUG2_3_11(printk("%s(%ld): **** Mem Alloc Failed ****",
 		    __func__, ha->host_no));
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index 26afe44..3433441 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -1517,6 +1517,7 @@
 	set_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags);
 	set_bit(LOCAL_LOOP_UPDATE, &ha->dpc_flags);
 	set_bit(RSCN_UPDATE, &ha->dpc_flags);
+	set_bit(NPIV_CONFIG_NEEDED, &ha->dpc_flags);
 }
 
 static int
@@ -1663,8 +1664,6 @@
 		ha->gid_list_info_size = 8;
 		ha->optrom_size = OPTROM_SIZE_25XX;
 		ha->isp_ops = &qla25xx_isp_ops;
-		ha->hw_event_start = PCI_FUNC(pdev->devfn) ?
-		    FA_HW_EVENT1_ADDR: FA_HW_EVENT0_ADDR;
 	}
 	host->can_queue = ha->request_q_length + 128;
 
@@ -1740,6 +1739,8 @@
 	if (ret)
 		goto probe_failed;
 
+	ha->isp_ops->enable_intrs(ha);
+
 	scsi_scan_host(host);
 
 	qla2x00_alloc_sysfs_attr(ha);
@@ -2431,6 +2432,12 @@
 			    ha->host_no));
 		}
 
+		if (test_bit(NPIV_CONFIG_NEEDED, &ha->dpc_flags) &&
+		    atomic_read(&ha->loop_state) == LOOP_READY) {
+			clear_bit(NPIV_CONFIG_NEEDED, &ha->dpc_flags);
+			qla2xxx_flash_npiv_conf(ha);
+		}
+
 		if (!ha->interrupts_on)
 			ha->isp_ops->enable_intrs(ha);
 
diff --git a/drivers/scsi/qla2xxx/qla_sup.c b/drivers/scsi/qla2xxx/qla_sup.c
index 1bca744..90a1321 100644
--- a/drivers/scsi/qla2xxx/qla_sup.c
+++ b/drivers/scsi/qla2xxx/qla_sup.c
@@ -543,23 +543,198 @@
 	}
 }
 
-void
-qla2xxx_get_flash_info(scsi_qla_host_t *ha)
+static int
+qla2xxx_find_flt_start(scsi_qla_host_t *ha, uint32_t *start)
+{
+	const char *loc, *locations[] = { "DEF", "PCI" };
+	uint32_t pcihdr, pcids;
+	uint32_t *dcode;
+	uint8_t *buf, *bcode, last_image;
+	uint16_t cnt, chksum, *wptr;
+	struct qla_flt_location *fltl;
+
+	/*
+	 * FLT-location structure resides after the last PCI region.
+	 */
+
+	/* Begin with sane defaults. */
+	loc = locations[0];
+	*start = IS_QLA24XX_TYPE(ha) ? FA_FLASH_LAYOUT_ADDR_24:
+	    FA_FLASH_LAYOUT_ADDR;
+
+	/* Begin with first PCI expansion ROM header. */
+	buf = (uint8_t *)ha->request_ring;
+	dcode = (uint32_t *)ha->request_ring;
+	pcihdr = 0;
+	last_image = 1;
+	do {
+		/* Verify PCI expansion ROM header. */
+		qla24xx_read_flash_data(ha, dcode, pcihdr >> 2, 0x20);
+		bcode = buf + (pcihdr % 4);
+		if (bcode[0x0] != 0x55 || bcode[0x1] != 0xaa)
+			goto end;
+
+		/* Locate PCI data structure. */
+		pcids = pcihdr + ((bcode[0x19] << 8) | bcode[0x18]);
+		qla24xx_read_flash_data(ha, dcode, pcids >> 2, 0x20);
+		bcode = buf + (pcihdr % 4);
+
+		/* Validate signature of PCI data structure. */
+		if (bcode[0x0] != 'P' || bcode[0x1] != 'C' ||
+		    bcode[0x2] != 'I' || bcode[0x3] != 'R')
+			goto end;
+
+		last_image = bcode[0x15] & BIT_7;
+
+		/* Locate next PCI expansion ROM. */
+		pcihdr += ((bcode[0x11] << 8) | bcode[0x10]) * 512;
+	} while (!last_image);
+
+	/* Now verify FLT-location structure. */
+	fltl = (struct qla_flt_location *)ha->request_ring;
+	qla24xx_read_flash_data(ha, dcode, pcihdr >> 2,
+	    sizeof(struct qla_flt_location) >> 2);
+	if (fltl->sig[0] != 'Q' || fltl->sig[1] != 'F' ||
+	    fltl->sig[2] != 'L' || fltl->sig[3] != 'T')
+		goto end;
+
+	wptr = (uint16_t *)ha->request_ring;
+	cnt = sizeof(struct qla_flt_location) >> 1;
+	for (chksum = 0; cnt; cnt--)
+		chksum += le16_to_cpu(*wptr++);
+	if (chksum) {
+		qla_printk(KERN_ERR, ha,
+		    "Inconsistent FLTL detected: checksum=0x%x.\n", chksum);
+		qla2x00_dump_buffer(buf, sizeof(struct qla_flt_location));
+		return QLA_FUNCTION_FAILED;
+	}
+
+	/* Good data.  Use specified location. */
+	loc = locations[1];
+	*start = le16_to_cpu(fltl->start_hi) << 16 |
+	    le16_to_cpu(fltl->start_lo);
+end:
+	DEBUG2(qla_printk(KERN_DEBUG, ha, "FLTL[%s] = 0x%x.\n", loc, *start));
+	return QLA_SUCCESS;
+}
+
+static void
+qla2xxx_get_flt_info(scsi_qla_host_t *ha, uint32_t flt_addr)
+{
+	const char *loc, *locations[] = { "DEF", "FLT" };
+	uint16_t *wptr;
+	uint16_t cnt, chksum;
+	uint32_t start;
+	struct qla_flt_header *flt;
+	struct qla_flt_region *region;
+
+	ha->flt_region_flt = flt_addr;
+	wptr = (uint16_t *)ha->request_ring;
+	flt = (struct qla_flt_header *)ha->request_ring;
+	region = (struct qla_flt_region *)&flt[1];
+	ha->isp_ops->read_optrom(ha, (uint8_t *)ha->request_ring,
+	    flt_addr << 2, OPTROM_BURST_SIZE);
+	if (*wptr == __constant_cpu_to_le16(0xffff))
+		goto no_flash_data;
+	if (flt->version != __constant_cpu_to_le16(1)) {
+		DEBUG2(qla_printk(KERN_INFO, ha, "Unsupported FLT detected: "
+		    "version=0x%x length=0x%x checksum=0x%x.\n",
+		    le16_to_cpu(flt->version), le16_to_cpu(flt->length),
+		    le16_to_cpu(flt->checksum)));
+		goto no_flash_data;
+	}
+
+	cnt = (sizeof(struct qla_flt_header) + le16_to_cpu(flt->length)) >> 1;
+	for (chksum = 0; cnt; cnt--)
+		chksum += le16_to_cpu(*wptr++);
+	if (chksum) {
+		DEBUG2(qla_printk(KERN_INFO, ha, "Inconsistent FLT detected: "
+		    "version=0x%x length=0x%x checksum=0x%x.\n",
+		    le16_to_cpu(flt->version), le16_to_cpu(flt->length),
+		    chksum));
+		goto no_flash_data;
+	}
+
+	loc = locations[1];
+	cnt = le16_to_cpu(flt->length) / sizeof(struct qla_flt_region);
+	for ( ; cnt; cnt--, region++) {
+		/* Store addresses as DWORD offsets. */
+		start = le32_to_cpu(region->start) >> 2;
+
+		DEBUG3(qla_printk(KERN_DEBUG, ha, "FLT[%02x]: start=0x%x "
+		    "end=0x%x size=0x%x.\n", le32_to_cpu(region->code), start,
+		    le32_to_cpu(region->end) >> 2, le32_to_cpu(region->size)));
+
+		switch (le32_to_cpu(region->code)) {
+		case FLT_REG_FW:
+			ha->flt_region_fw = start;
+			break;
+		case FLT_REG_BOOT_CODE:
+			ha->flt_region_boot = start;
+			break;
+		case FLT_REG_VPD_0:
+			ha->flt_region_vpd_nvram = start;
+			break;
+		case FLT_REG_FDT:
+			ha->flt_region_fdt = start;
+			break;
+		case FLT_REG_HW_EVENT_0:
+			if (!PCI_FUNC(ha->pdev->devfn))
+				ha->flt_region_hw_event = start;
+			break;
+		case FLT_REG_HW_EVENT_1:
+			if (PCI_FUNC(ha->pdev->devfn))
+				ha->flt_region_hw_event = start;
+			break;
+		case FLT_REG_NPIV_CONF_0:
+			if (!PCI_FUNC(ha->pdev->devfn))
+				ha->flt_region_npiv_conf = start;
+			break;
+		case FLT_REG_NPIV_CONF_1:
+			if (PCI_FUNC(ha->pdev->devfn))
+				ha->flt_region_npiv_conf = start;
+			break;
+		}
+	}
+	goto done;
+
+no_flash_data:
+	/* Use hardcoded defaults. */
+	loc = locations[0];
+	ha->flt_region_fw = FA_RISC_CODE_ADDR;
+	ha->flt_region_boot = FA_BOOT_CODE_ADDR;
+	ha->flt_region_vpd_nvram = FA_VPD_NVRAM_ADDR;
+	ha->flt_region_fdt = IS_QLA24XX_TYPE(ha) ? FA_FLASH_DESCR_ADDR_24:
+	    FA_FLASH_DESCR_ADDR;
+	ha->flt_region_hw_event = !PCI_FUNC(ha->pdev->devfn) ?
+	    FA_HW_EVENT0_ADDR: FA_HW_EVENT1_ADDR;
+	ha->flt_region_npiv_conf = !PCI_FUNC(ha->pdev->devfn) ?
+	    (IS_QLA24XX_TYPE(ha) ? FA_NPIV_CONF0_ADDR_24: FA_NPIV_CONF0_ADDR):
+	    (IS_QLA24XX_TYPE(ha) ? FA_NPIV_CONF1_ADDR_24: FA_NPIV_CONF1_ADDR);
+done:
+	DEBUG2(qla_printk(KERN_DEBUG, ha, "FLT[%s]: boot=0x%x fw=0x%x "
+	    "vpd_nvram=0x%x fdt=0x%x flt=0x%x hwe=0x%x npiv=0x%x.\n", loc,
+	    ha->flt_region_boot, ha->flt_region_fw, ha->flt_region_vpd_nvram,
+	    ha->flt_region_fdt, ha->flt_region_flt, ha->flt_region_hw_event,
+	    ha->flt_region_npiv_conf));
+}
+
+static void
+qla2xxx_get_fdt_info(scsi_qla_host_t *ha)
 {
 #define FLASH_BLK_SIZE_32K	0x8000
 #define FLASH_BLK_SIZE_64K	0x10000
+	const char *loc, *locations[] = { "MID", "FDT" };
 	uint16_t cnt, chksum;
 	uint16_t *wptr;
 	struct qla_fdt_layout *fdt;
 	uint8_t	man_id, flash_id;
-
-	if (!IS_QLA24XX_TYPE(ha) && !IS_QLA25XX(ha))
-		return;
+	uint16_t mid, fid;
 
 	wptr = (uint16_t *)ha->request_ring;
 	fdt = (struct qla_fdt_layout *)ha->request_ring;
 	ha->isp_ops->read_optrom(ha, (uint8_t *)ha->request_ring,
-	    FA_FLASH_DESCR_ADDR << 2, OPTROM_BURST_SIZE);
+	    ha->flt_region_fdt << 2, OPTROM_BURST_SIZE);
 	if (*wptr == __constant_cpu_to_le16(0xffff))
 		goto no_flash_data;
 	if (fdt->sig[0] != 'Q' || fdt->sig[1] != 'L' || fdt->sig[2] != 'I' ||
@@ -577,7 +752,10 @@
 		goto no_flash_data;
 	}
 
-	ha->fdt_odd_index = le16_to_cpu(fdt->man_id) == 0x1f;
+	loc = locations[1];
+	mid = le16_to_cpu(fdt->man_id);
+	fid = le16_to_cpu(fdt->id);
+	ha->fdt_odd_index = mid == 0x1f;
 	ha->fdt_wrt_disable = fdt->wrt_disable_bits;
 	ha->fdt_erase_cmd = flash_conf_to_access_addr(0x0300 | fdt->erase_cmd);
 	ha->fdt_block_size = le32_to_cpu(fdt->block_size);
@@ -588,16 +766,12 @@
 		    flash_conf_to_access_addr(0x0300 | fdt->protect_sec_cmd):
 		    flash_conf_to_access_addr(0x0336);
 	}
-
-	DEBUG2(qla_printk(KERN_DEBUG, ha, "Flash[FDT]: (0x%x/0x%x) erase=0x%x "
-	    "pro=%x upro=%x idx=%d wrtd=0x%x blk=0x%x.\n",
-	    le16_to_cpu(fdt->man_id), le16_to_cpu(fdt->id), ha->fdt_erase_cmd,
-	    ha->fdt_protect_sec_cmd, ha->fdt_unprotect_sec_cmd,
-	    ha->fdt_odd_index, ha->fdt_wrt_disable, ha->fdt_block_size));
-	return;
-
+	goto done;
 no_flash_data:
+	loc = locations[0];
 	qla24xx_get_flash_manufacturer(ha, &man_id, &flash_id);
+	mid = man_id;
+	fid = flash_id;
 	ha->fdt_wrt_disable = 0x9c;
 	ha->fdt_erase_cmd = flash_conf_to_access_addr(0x03d8);
 	switch (man_id) {
@@ -625,14 +799,117 @@
 		ha->fdt_block_size = FLASH_BLK_SIZE_64K;
 		break;
 	}
-
-	DEBUG2(qla_printk(KERN_DEBUG, ha, "Flash[MID]: (0x%x/0x%x) erase=0x%x "
-	    "pro=%x upro=%x idx=%d wrtd=0x%x blk=0x%x.\n", man_id, flash_id,
+done:
+	DEBUG2(qla_printk(KERN_DEBUG, ha, "FDT[%s]: (0x%x/0x%x) erase=0x%x "
+	    "pro=%x upro=%x idx=%d wrtd=0x%x blk=0x%x.\n", loc, mid, fid,
 	    ha->fdt_erase_cmd, ha->fdt_protect_sec_cmd,
 	    ha->fdt_unprotect_sec_cmd, ha->fdt_odd_index, ha->fdt_wrt_disable,
 	    ha->fdt_block_size));
 }
 
+int
+qla2xxx_get_flash_info(scsi_qla_host_t *ha)
+{
+	int ret;
+	uint32_t flt_addr;
+
+	if (!IS_QLA24XX_TYPE(ha) && !IS_QLA25XX(ha))
+		return QLA_SUCCESS;
+
+	ret = qla2xxx_find_flt_start(ha, &flt_addr);
+	if (ret != QLA_SUCCESS)
+		return ret;
+
+	qla2xxx_get_flt_info(ha, flt_addr);
+	qla2xxx_get_fdt_info(ha);
+
+	return QLA_SUCCESS;
+}
+
+void
+qla2xxx_flash_npiv_conf(scsi_qla_host_t *ha)
+{
+#define NPIV_CONFIG_SIZE	(16*1024)
+	void *data;
+	uint16_t *wptr;
+	uint16_t cnt, chksum;
+	struct qla_npiv_header hdr;
+	struct qla_npiv_entry *entry;
+
+	if (!IS_QLA24XX_TYPE(ha) && !IS_QLA25XX(ha))
+		return;
+
+	ha->isp_ops->read_optrom(ha, (uint8_t *)&hdr,
+	    ha->flt_region_npiv_conf << 2, sizeof(struct qla_npiv_header));
+	if (hdr.version == __constant_cpu_to_le16(0xffff))
+		return;
+	if (hdr.version != __constant_cpu_to_le16(1)) {
+		DEBUG2(qla_printk(KERN_INFO, ha, "Unsupported NPIV-Config "
+		    "detected: version=0x%x entries=0x%x checksum=0x%x.\n",
+		    le16_to_cpu(hdr.version), le16_to_cpu(hdr.entries),
+		    le16_to_cpu(hdr.checksum)));
+		return;
+	}
+
+	data = kmalloc(NPIV_CONFIG_SIZE, GFP_KERNEL);
+	if (!data) {
+		DEBUG2(qla_printk(KERN_INFO, ha, "NPIV-Config: Unable to "
+		    "allocate memory.\n"));
+		return;
+	}
+
+	ha->isp_ops->read_optrom(ha, (uint8_t *)data,
+	    ha->flt_region_npiv_conf << 2, NPIV_CONFIG_SIZE);
+
+	cnt = (sizeof(struct qla_npiv_header) + le16_to_cpu(hdr.entries) *
+	    sizeof(struct qla_npiv_entry)) >> 1;
+	for (wptr = data, chksum = 0; cnt; cnt--)
+		chksum += le16_to_cpu(*wptr++);
+	if (chksum) {
+		DEBUG2(qla_printk(KERN_INFO, ha, "Inconsistent NPIV-Config "
+		    "detected: version=0x%x entries=0x%x checksum=0x%x.\n",
+		    le16_to_cpu(hdr.version), le16_to_cpu(hdr.entries),
+		    chksum));
+		goto done;
+	}
+
+	entry = data + sizeof(struct qla_npiv_header);
+	cnt = le16_to_cpu(hdr.entries);
+	for ( ; cnt; cnt--, entry++) {
+		uint16_t flags;
+		struct fc_vport_identifiers vid;
+		struct fc_vport *vport;
+
+		flags = le16_to_cpu(entry->flags);
+		if (flags == 0xffff)
+			continue;
+		if ((flags & BIT_0) == 0)
+			continue;
+
+		memset(&vid, 0, sizeof(vid));
+		vid.roles = FC_PORT_ROLE_FCP_INITIATOR;
+		vid.vport_type = FC_PORTTYPE_NPIV;
+		vid.disable = false;
+		vid.port_name = wwn_to_u64(entry->port_name);
+		vid.node_name = wwn_to_u64(entry->node_name);
+
+		DEBUG2(qla_printk(KERN_DEBUG, ha, "NPIV[%02x]: wwpn=%llx "
+		    "wwnn=%llx vf_id=0x%x qos=0x%x.\n", cnt,
+		    (unsigned long long)vid.port_name,
+		    (unsigned long long)vid.node_name,
+		    le16_to_cpu(entry->vf_id), le16_to_cpu(entry->qos)));
+
+		vport = fc_vport_create(ha->host, 0, &vid);
+		if (!vport)
+			qla_printk(KERN_INFO, ha, "NPIV-Config: Failed to "
+			    "create vport [%02x]: wwpn=%llx wwnn=%llx.\n", cnt,
+			    (unsigned long long)vid.port_name,
+			    (unsigned long long)vid.node_name);
+	}
+done:
+	kfree(data);
+}
+
 static void
 qla24xx_unprotect_flash(scsi_qla_host_t *ha)
 {
@@ -920,7 +1197,8 @@
 	dwptr = (uint32_t *)buf;
 	for (i = 0; i < bytes >> 2; i++, naddr++)
 		dwptr[i] = cpu_to_le32(qla24xx_read_flash_dword(ha,
-		    flash_data_to_access_addr(FA_VPD_NVRAM_ADDR | naddr)));
+		    flash_data_to_access_addr(ha->flt_region_vpd_nvram |
+		    naddr)));
 
 	return buf;
 }
@@ -935,10 +1213,10 @@
 	dbuf = vmalloc(RMW_BUFFER_SIZE);
 	if (!dbuf)
 		return QLA_MEMORY_ALLOC_FAILED;
-	ha->isp_ops->read_optrom(ha, dbuf, FA_VPD_NVRAM_ADDR << 2,
+	ha->isp_ops->read_optrom(ha, dbuf, ha->flt_region_vpd_nvram << 2,
 	    RMW_BUFFER_SIZE);
 	memcpy(dbuf + (naddr << 2), buf, bytes);
-	ha->isp_ops->write_optrom(ha, dbuf, FA_VPD_NVRAM_ADDR << 2,
+	ha->isp_ops->write_optrom(ha, dbuf, ha->flt_region_vpd_nvram << 2,
 	    RMW_BUFFER_SIZE);
 	vfree(dbuf);
 
@@ -2166,7 +2444,7 @@
 		memset(dbyte, 0, 8);
 		dcode = (uint16_t *)dbyte;
 
-		qla2x00_read_flash_data(ha, dbyte, FA_RISC_CODE_ADDR * 4 + 10,
+		qla2x00_read_flash_data(ha, dbyte, ha->flt_region_fw * 4 + 10,
 		    8);
 		DEBUG3(printk("%s(%ld): dumping fw ver from flash:\n",
 		    __func__, ha->host_no));
@@ -2177,7 +2455,7 @@
 		    (dcode[0] == 0 && dcode[1] == 0 && dcode[2] == 0 &&
 		    dcode[3] == 0)) {
 			DEBUG2(printk("%s(): Unrecognized fw revision at "
-			    "%x.\n", __func__, FA_RISC_CODE_ADDR * 4));
+			    "%x.\n", __func__, ha->flt_region_fw * 4));
 		} else {
 			/* values are in big endian */
 			ha->fw_revision[0] = dbyte[0] << 16 | dbyte[1];
@@ -2212,7 +2490,7 @@
 	dcode = mbuf;
 
 	/* Begin with first PCI expansion ROM header. */
-	pcihdr = 0;
+	pcihdr = ha->flt_region_boot;
 	last_image = 1;
 	do {
 		/* Verify PCI expansion ROM header. */
@@ -2282,7 +2560,7 @@
 	memset(ha->fw_revision, 0, sizeof(ha->fw_revision));
 	dcode = mbuf;
 
-	qla24xx_read_flash_data(ha, dcode, FA_RISC_CODE_ADDR + 4, 4);
+	qla24xx_read_flash_data(ha, dcode, ha->flt_region_fw + 4, 4);
 	for (i = 0; i < 4; i++)
 		dcode[i] = be32_to_cpu(dcode[i]);
 
@@ -2291,7 +2569,7 @@
 	    (dcode[0] == 0 && dcode[1] == 0 && dcode[2] == 0 &&
 	    dcode[3] == 0)) {
 		DEBUG2(printk("%s(): Unrecognized fw version at %x.\n",
-		    __func__, FA_RISC_CODE_ADDR));
+		    __func__, ha->flt_region_fw));
 	} else {
 		ha->fw_revision[0] = dcode[0];
 		ha->fw_revision[1] = dcode[1];
@@ -2355,7 +2633,7 @@
 	/* Locate first empty entry. */
 	for (;;) {
 		if (ha->hw_event_ptr >=
-		    ha->hw_event_start + FA_HW_EVENT_SIZE) {
+		    ha->flt_region_hw_event + FA_HW_EVENT_SIZE) {
 			DEBUG2(qla_printk(KERN_WARNING, ha,
 			    "HW event -- Log Full!\n"));
 			return QLA_MEMORY_ALLOC_FAILED;
@@ -2391,7 +2669,7 @@
 	int rval;
 	uint32_t marker[2], fdata[4];
 
-	if (ha->hw_event_start == 0)
+	if (ha->flt_region_hw_event == 0)
 		return QLA_FUNCTION_FAILED;
 
 	DEBUG2(qla_printk(KERN_WARNING, ha,
@@ -2406,7 +2684,7 @@
 		    QLA_DRIVER_PATCH_VER, QLA_DRIVER_BETA_VER);
 
 		/* Locate marker. */
-		ha->hw_event_ptr = ha->hw_event_start;
+		ha->hw_event_ptr = ha->flt_region_hw_event;
 		for (;;) {
 			qla24xx_read_flash_data(ha, fdata, ha->hw_event_ptr,
 			    4);
@@ -2415,7 +2693,7 @@
 				break;
 			ha->hw_event_ptr += FA_HW_EVENT_ENTRY_SIZE;
 			if (ha->hw_event_ptr >=
-			    ha->hw_event_start + FA_HW_EVENT_SIZE) {
+			    ha->flt_region_hw_event + FA_HW_EVENT_SIZE) {
 				DEBUG2(qla_printk(KERN_WARNING, ha,
 				    "HW event -- Log Full!\n"));
 				return QLA_MEMORY_ALLOC_FAILED;
diff --git a/drivers/scsi/qla2xxx/qla_version.h b/drivers/scsi/qla2xxx/qla_version.h
index 4160e4c..be5e299 100644
--- a/drivers/scsi/qla2xxx/qla_version.h
+++ b/drivers/scsi/qla2xxx/qla_version.h
@@ -7,7 +7,7 @@
 /*
  * Driver version
  */
-#define QLA2XXX_VERSION      "8.02.01-k7"
+#define QLA2XXX_VERSION      "8.02.01-k8"
 
 #define QLA_DRIVER_MAJOR_VER	8
 #define QLA_DRIVER_MINOR_VER	2
diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c
index 88bebb1..de8279a 100644
--- a/drivers/scsi/qla4xxx/ql4_os.c
+++ b/drivers/scsi/qla4xxx/ql4_os.c
@@ -1542,7 +1542,7 @@
 	DEBUG2(printk(KERN_INFO
 		      "scsi%ld: DEVICE_RESET cmd=%p jiffies = 0x%lx, to=%x,"
 		      "dpc_flags=%lx, status=%x allowed=%d\n", ha->host_no,
-		      cmd, jiffies, cmd->timeout_per_command / HZ,
+		      cmd, jiffies, cmd->request->timeout / HZ,
 		      ha->dpc_flags, cmd->result, cmd->allowed));
 
 	/* FIXME: wait for hba to go online */
@@ -1598,7 +1598,7 @@
 	DEBUG2(printk(KERN_INFO
 		      "scsi%ld: TARGET_DEVICE_RESET cmd=%p jiffies = 0x%lx, "
 		      "to=%x,dpc_flags=%lx, status=%x allowed=%d\n",
-		      ha->host_no, cmd, jiffies, cmd->timeout_per_command / HZ,
+		      ha->host_no, cmd, jiffies, cmd->request->timeout / HZ,
 		      ha->dpc_flags, cmd->result, cmd->allowed));
 
 	stat = qla4xxx_reset_target(ha, ddb_entry);
diff --git a/drivers/scsi/qlogicpti.c b/drivers/scsi/qlogicpti.c
index 4a1cf63..69d6ad8 100644
--- a/drivers/scsi/qlogicpti.c
+++ b/drivers/scsi/qlogicpti.c
@@ -1,6 +1,6 @@
 /* qlogicpti.c: Performance Technologies QlogicISP sbus card driver.
  *
- * Copyright (C) 1996, 2006 David S. Miller (davem@davemloft.net)
+ * Copyright (C) 1996, 2006, 2008 David S. Miller (davem@davemloft.net)
  *
  * A lot of this driver was directly stolen from Erik H. Moe's PCI
  * Qlogic ISP driver.  Mucho kudos to him for this code.
@@ -25,12 +25,14 @@
 #include <linux/interrupt.h>
 #include <linux/module.h>
 #include <linux/jiffies.h>
+#include <linux/dma-mapping.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 
 #include <asm/byteorder.h>
 
 #include "qlogicpti.h"
 
-#include <asm/sbus.h>
 #include <asm/dma.h>
 #include <asm/system.h>
 #include <asm/ptrace.h>
@@ -157,7 +159,7 @@
 	 * is a nop and the chip ends up using the smallest burst
 	 * size. -DaveM
 	 */
-	if (sbus_can_burst64(qpti->sdev) && (bursts & DMA_BURST64)) {
+	if (sbus_can_burst64() && (bursts & DMA_BURST64)) {
 		val = (SBUS_CFG1_BENAB | SBUS_CFG1_B64);
 	} else
 #endif
@@ -684,19 +686,19 @@
 
 static int __devinit qpti_map_regs(struct qlogicpti *qpti)
 {
-	struct sbus_dev *sdev = qpti->sdev;
+	struct of_device *op = qpti->op;
 
-	qpti->qregs = sbus_ioremap(&sdev->resource[0], 0,
-				   sdev->reg_addrs[0].reg_size,
-				   "PTI Qlogic/ISP");
+	qpti->qregs = of_ioremap(&op->resource[0], 0,
+				 resource_size(&op->resource[0]),
+				 "PTI Qlogic/ISP");
 	if (!qpti->qregs) {
 		printk("PTI: Qlogic/ISP registers are unmappable\n");
 		return -1;
 	}
 	if (qpti->is_pti) {
-		qpti->sreg = sbus_ioremap(&sdev->resource[0], (16 * 4096),
-					  sizeof(unsigned char),
-					  "PTI Qlogic/ISP statreg");
+		qpti->sreg = of_ioremap(&op->resource[0], (16 * 4096),
+					sizeof(unsigned char),
+					"PTI Qlogic/ISP statreg");
 		if (!qpti->sreg) {
 			printk("PTI: Qlogic/ISP status register is unmappable\n");
 			return -1;
@@ -707,9 +709,9 @@
 
 static int __devinit qpti_register_irq(struct qlogicpti *qpti)
 {
-	struct sbus_dev *sdev = qpti->sdev;
+	struct of_device *op = qpti->op;
 
-	qpti->qhost->irq = qpti->irq = sdev->irqs[0];
+	qpti->qhost->irq = qpti->irq = op->irqs[0];
 
 	/* We used to try various overly-clever things to
 	 * reduce the interrupt processing overhead on
@@ -732,17 +734,19 @@
 
 static void __devinit qpti_get_scsi_id(struct qlogicpti *qpti)
 {
-	qpti->scsi_id = prom_getintdefault(qpti->prom_node,
-					   "initiator-id",
-					   -1);
+	struct of_device *op = qpti->op;
+	struct device_node *dp;
+
+	dp = op->node;
+
+	qpti->scsi_id = of_getintprop_default(dp, "initiator-id", -1);
 	if (qpti->scsi_id == -1)
-		qpti->scsi_id = prom_getintdefault(qpti->prom_node,
-						   "scsi-initiator-id",
-						   -1);
+		qpti->scsi_id = of_getintprop_default(dp, "scsi-initiator-id",
+						      -1);
 	if (qpti->scsi_id == -1)
 		qpti->scsi_id =
-			prom_getintdefault(qpti->sdev->bus->prom_node,
-					   "scsi-initiator-id", 7);
+			of_getintprop_default(dp->parent,
+					      "scsi-initiator-id", 7);
 	qpti->qhost->this_id = qpti->scsi_id;
 	qpti->qhost->max_sectors = 64;
 
@@ -751,12 +755,11 @@
 
 static void qpti_get_bursts(struct qlogicpti *qpti)
 {
-	struct sbus_dev *sdev = qpti->sdev;
+	struct of_device *op = qpti->op;
 	u8 bursts, bmask;
 
-	bursts = prom_getintdefault(qpti->prom_node, "burst-sizes", 0xff);
-	bmask = prom_getintdefault(sdev->bus->prom_node,
-				   "burst-sizes", 0xff);
+	bursts = of_getintprop_default(op->node, "burst-sizes", 0xff);
+	bmask = of_getintprop_default(op->node->parent, "burst-sizes", 0xff);
 	if (bmask != 0xff)
 		bursts &= bmask;
 	if (bursts == 0xff ||
@@ -785,25 +788,25 @@
  */
 static int __devinit qpti_map_queues(struct qlogicpti *qpti)
 {
-	struct sbus_dev *sdev = qpti->sdev;
+	struct of_device *op = qpti->op;
 
 #define QSIZE(entries)	(((entries) + 1) * QUEUE_ENTRY_LEN)
-	qpti->res_cpu = sbus_alloc_consistent(sdev,
-					      QSIZE(RES_QUEUE_LEN),
-					      &qpti->res_dvma);
+	qpti->res_cpu = dma_alloc_coherent(&op->dev,
+					   QSIZE(RES_QUEUE_LEN),
+					   &qpti->res_dvma, GFP_ATOMIC);
 	if (qpti->res_cpu == NULL ||
 	    qpti->res_dvma == 0) {
 		printk("QPTI: Cannot map response queue.\n");
 		return -1;
 	}
 
-	qpti->req_cpu = sbus_alloc_consistent(sdev,
-					      QSIZE(QLOGICPTI_REQ_QUEUE_LEN),
-					      &qpti->req_dvma);
+	qpti->req_cpu = dma_alloc_coherent(&op->dev,
+					   QSIZE(QLOGICPTI_REQ_QUEUE_LEN),
+					   &qpti->req_dvma, GFP_ATOMIC);
 	if (qpti->req_cpu == NULL ||
 	    qpti->req_dvma == 0) {
-		sbus_free_consistent(sdev, QSIZE(RES_QUEUE_LEN),
-				     qpti->res_cpu, qpti->res_dvma);
+		dma_free_coherent(&op->dev, QSIZE(RES_QUEUE_LEN),
+				  qpti->res_cpu, qpti->res_dvma);
 		printk("QPTI: Cannot map request queue.\n");
 		return -1;
 	}
@@ -875,8 +878,9 @@
 		int sg_count;
 
 		sg = scsi_sglist(Cmnd);
-		sg_count = sbus_map_sg(qpti->sdev, sg, scsi_sg_count(Cmnd),
-		                                      Cmnd->sc_data_direction);
+		sg_count = dma_map_sg(&qpti->op->dev, sg,
+				      scsi_sg_count(Cmnd),
+				      Cmnd->sc_data_direction);
 
 		ds = cmd->dataseg;
 		cmd->segment_cnt = sg_count;
@@ -914,6 +918,7 @@
 				ds[i].d_count = sg_dma_len(s);
 			}
 			sg_count -= n;
+			sg = s;
 		}
 	} else {
 		cmd->dataseg[0].d_base = 0;
@@ -1151,9 +1156,9 @@
 			Cmnd->result = DID_ERROR << 16;
 
 		if (scsi_bufflen(Cmnd))
-			sbus_unmap_sg(qpti->sdev,
-				      scsi_sglist(Cmnd), scsi_sg_count(Cmnd),
-				      Cmnd->sc_data_direction);
+			dma_unmap_sg(&qpti->op->dev,
+				     scsi_sglist(Cmnd), scsi_sg_count(Cmnd),
+				     Cmnd->sc_data_direction);
 
 		qpti->cmd_count[Cmnd->device->id]--;
 		sbus_writew(out_ptr, qpti->qregs + MBOX5);
@@ -1267,34 +1272,32 @@
 	.use_clustering		= ENABLE_CLUSTERING,
 };
 
-static int __devinit qpti_sbus_probe(struct of_device *dev, const struct of_device_id *match)
+static int __devinit qpti_sbus_probe(struct of_device *op, const struct of_device_id *match)
 {
-	static int nqptis;
-	struct sbus_dev *sdev = to_sbus_device(&dev->dev);
-	struct device_node *dp = dev->node;
 	struct scsi_host_template *tpnt = match->data;
+	struct device_node *dp = op->node;
 	struct Scsi_Host *host;
 	struct qlogicpti *qpti;
+	static int nqptis;
 	const char *fcode;
 
 	/* Sometimes Antares cards come up not completely
 	 * setup, and we get a report of a zero IRQ.
 	 */
-	if (sdev->irqs[0] == 0)
+	if (op->irqs[0] == 0)
 		return -ENODEV;
 
 	host = scsi_host_alloc(tpnt, sizeof(struct qlogicpti));
 	if (!host)
 		return -ENOMEM;
 
-	qpti = (struct qlogicpti *) host->hostdata;
+	qpti = shost_priv(host);
 
 	host->max_id = MAX_TARGETS;
 	qpti->qhost = host;
-	qpti->sdev = sdev;
+	qpti->op = op;
 	qpti->qpti_id = nqptis;
-	qpti->prom_node = sdev->prom_node;
-	strcpy(qpti->prom_name, sdev->ofdev.node->name);
+	strcpy(qpti->prom_name, op->node->name);
 	qpti->is_pti = strcmp(qpti->prom_name, "QLGC,isp");
 
 	if (qpti_map_regs(qpti) < 0)
@@ -1340,12 +1343,12 @@
 		(qpti->ultra ? "Ultra" : "Fast"),
 		(qpti->differential ? "differential" : "single ended"));
 
-	if (scsi_add_host(host, &dev->dev)) {
+	if (scsi_add_host(host, &op->dev)) {
 		printk("qlogicpti%d: Failed scsi_add_host\n", qpti->qpti_id);
 		goto fail_unmap_queues;
 	}
 
-	dev_set_drvdata(&sdev->ofdev.dev, qpti);
+	dev_set_drvdata(&op->dev, qpti);
 
 	qpti_chain_add(qpti);
 
@@ -1356,19 +1359,20 @@
 
 fail_unmap_queues:
 #define QSIZE(entries)	(((entries) + 1) * QUEUE_ENTRY_LEN)
-	sbus_free_consistent(qpti->sdev,
-			     QSIZE(RES_QUEUE_LEN),
-			     qpti->res_cpu, qpti->res_dvma);
-	sbus_free_consistent(qpti->sdev,
-			     QSIZE(QLOGICPTI_REQ_QUEUE_LEN),
-			     qpti->req_cpu, qpti->req_dvma);
+	dma_free_coherent(&op->dev,
+			  QSIZE(RES_QUEUE_LEN),
+			  qpti->res_cpu, qpti->res_dvma);
+	dma_free_coherent(&op->dev,
+			  QSIZE(QLOGICPTI_REQ_QUEUE_LEN),
+			  qpti->req_cpu, qpti->req_dvma);
 #undef QSIZE
 
 fail_unmap_regs:
-	sbus_iounmap(qpti->qregs,
-		     qpti->sdev->reg_addrs[0].reg_size);
+	of_iounmap(&op->resource[0], qpti->qregs,
+		   resource_size(&op->resource[0]));
 	if (qpti->is_pti)
-		sbus_iounmap(qpti->sreg, sizeof(unsigned char));
+		of_iounmap(&op->resource[0], qpti->sreg,
+			   sizeof(unsigned char));
 
 fail_free_irq:
 	free_irq(qpti->irq, qpti);
@@ -1379,9 +1383,9 @@
 	return -ENODEV;
 }
 
-static int __devexit qpti_sbus_remove(struct of_device *dev)
+static int __devexit qpti_sbus_remove(struct of_device *op)
 {
-	struct qlogicpti *qpti = dev_get_drvdata(&dev->dev);
+	struct qlogicpti *qpti = dev_get_drvdata(&op->dev);
 
 	qpti_chain_del(qpti);
 
@@ -1394,24 +1398,25 @@
 	free_irq(qpti->irq, qpti);
 
 #define QSIZE(entries)	(((entries) + 1) * QUEUE_ENTRY_LEN)
-	sbus_free_consistent(qpti->sdev,
-			     QSIZE(RES_QUEUE_LEN),
-			     qpti->res_cpu, qpti->res_dvma);
-	sbus_free_consistent(qpti->sdev,
-			     QSIZE(QLOGICPTI_REQ_QUEUE_LEN),
-			     qpti->req_cpu, qpti->req_dvma);
+	dma_free_coherent(&op->dev,
+			  QSIZE(RES_QUEUE_LEN),
+			  qpti->res_cpu, qpti->res_dvma);
+	dma_free_coherent(&op->dev,
+			  QSIZE(QLOGICPTI_REQ_QUEUE_LEN),
+			  qpti->req_cpu, qpti->req_dvma);
 #undef QSIZE
 
-	sbus_iounmap(qpti->qregs, qpti->sdev->reg_addrs[0].reg_size);
+	of_iounmap(&op->resource[0], qpti->qregs,
+		   resource_size(&op->resource[0]));
 	if (qpti->is_pti)
-		sbus_iounmap(qpti->sreg, sizeof(unsigned char));
+		of_iounmap(&op->resource[0], qpti->sreg, sizeof(unsigned char));
 
 	scsi_host_put(qpti->qhost);
 
 	return 0;
 }
 
-static struct of_device_id qpti_match[] = {
+static const struct of_device_id qpti_match[] = {
 	{
 		.name = "ptisp",
 		.data = &qpti_template,
@@ -1441,7 +1446,7 @@
 
 static int __init qpti_init(void)
 {
-	return of_register_driver(&qpti_sbus_driver, &sbus_bus_type);
+	return of_register_driver(&qpti_sbus_driver, &of_bus_type);
 }
 
 static void __exit qpti_exit(void)
@@ -1452,7 +1457,7 @@
 MODULE_DESCRIPTION("QlogicISP SBUS driver");
 MODULE_AUTHOR("David S. Miller (davem@davemloft.net)");
 MODULE_LICENSE("GPL");
-MODULE_VERSION("2.0");
+MODULE_VERSION("2.1");
 
 module_init(qpti_init);
 module_exit(qpti_exit);
diff --git a/drivers/scsi/qlogicpti.h b/drivers/scsi/qlogicpti.h
index ef6da2d..9c053bb 100644
--- a/drivers/scsi/qlogicpti.h
+++ b/drivers/scsi/qlogicpti.h
@@ -342,7 +342,7 @@
 	u_int	                  req_in_ptr;		/* index of next request slot */
 	u_int	                  res_out_ptr;		/* index of next result slot  */
 	long	                  send_marker;		/* must we send a marker?     */
-	struct sbus_dev		 *sdev;
+	struct of_device	 *op;
 	unsigned long		  __pad;
 
 	int                       cmd_count[MAX_TARGETS];
diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c
index ee6be59..2ac3cb2 100644
--- a/drivers/scsi/scsi.c
+++ b/drivers/scsi/scsi.c
@@ -291,7 +291,6 @@
 		unsigned long flags;
 
 		cmd->device = dev;
-		init_timer(&cmd->eh_timeout);
 		INIT_LIST_HEAD(&cmd->list);
 		spin_lock_irqsave(&dev->list_lock, flags);
 		list_add_tail(&cmd->list, &dev->cmd_list);
@@ -652,26 +651,33 @@
 	unsigned long timeout;
 	int rtn = 0;
 
+	/*
+	 * We will use a queued command if possible, otherwise we will
+	 * emulate the queuing and calling of completion function ourselves.
+	 */
+	atomic_inc(&cmd->device->iorequest_cnt);
+
 	/* check if the device is still usable */
 	if (unlikely(cmd->device->sdev_state == SDEV_DEL)) {
 		/* in SDEV_DEL we error all commands. DID_NO_CONNECT
 		 * returns an immediate error upwards, and signals
 		 * that the device is no longer present */
 		cmd->result = DID_NO_CONNECT << 16;
-		atomic_inc(&cmd->device->iorequest_cnt);
-		__scsi_done(cmd);
+		scsi_done(cmd);
 		/* return 0 (because the command has been processed) */
 		goto out;
 	}
 
-	/* Check to see if the scsi lld put this device into state SDEV_BLOCK. */
-	if (unlikely(cmd->device->sdev_state == SDEV_BLOCK)) {
+	/* Check to see if the scsi lld made this device blocked. */
+	if (unlikely(scsi_device_blocked(cmd->device))) {
 		/* 
-		 * in SDEV_BLOCK, the command is just put back on the device
-		 * queue.  The suspend state has already blocked the queue so
-		 * future requests should not occur until the device 
-		 * transitions out of the suspend state.
+		 * in blocked state, the command is just put back on
+		 * the device queue.  The suspend state has already
+		 * blocked the queue so future requests should not
+		 * occur until the device transitions out of the
+		 * suspend state.
 		 */
+
 		scsi_queue_insert(cmd, SCSI_MLQUEUE_DEVICE_BUSY);
 
 		SCSI_LOG_MLQUEUE(3, printk("queuecommand : device blocked \n"));
@@ -714,21 +720,9 @@
 		host->resetting = 0;
 	}
 
-	/* 
-	 * AK: unlikely race here: for some reason the timer could
-	 * expire before the serial number is set up below.
-	 */
-	scsi_add_timer(cmd, cmd->timeout_per_command, scsi_times_out);
-
 	scsi_log_send(cmd);
 
 	/*
-	 * We will use a queued command if possible, otherwise we will
-	 * emulate the queuing and calling of completion function ourselves.
-	 */
-	atomic_inc(&cmd->device->iorequest_cnt);
-
-	/*
 	 * Before we queue this command, check if the command
 	 * length exceeds what the host adapter can handle.
 	 */
@@ -744,6 +738,12 @@
 	}
 
 	spin_lock_irqsave(host->host_lock, flags);
+	/*
+	 * AK: unlikely race here: for some reason the timer could
+	 * expire before the serial number is set up below.
+	 *
+	 * TODO: kill serial or move to blk layer
+	 */
 	scsi_cmd_get_serial(host, cmd); 
 
 	if (unlikely(host->shost_state == SHOST_DEL)) {
@@ -754,12 +754,8 @@
 	}
 	spin_unlock_irqrestore(host->host_lock, flags);
 	if (rtn) {
-		if (scsi_delete_timer(cmd)) {
-			atomic_inc(&cmd->device->iodone_cnt);
-			scsi_queue_insert(cmd,
-					  (rtn == SCSI_MLQUEUE_DEVICE_BUSY) ?
-					  rtn : SCSI_MLQUEUE_HOST_BUSY);
-		}
+		scsi_queue_insert(cmd, (rtn == SCSI_MLQUEUE_DEVICE_BUSY) ?
+						rtn : SCSI_MLQUEUE_HOST_BUSY);
 		SCSI_LOG_MLQUEUE(3,
 		    printk("queuecommand : request rejected\n"));
 	}
@@ -770,24 +766,6 @@
 }
 
 /**
- * scsi_req_abort_cmd -- Request command recovery for the specified command
- * @cmd: pointer to the SCSI command of interest
- *
- * This function requests that SCSI Core start recovery for the
- * command by deleting the timer and adding the command to the eh
- * queue.  It can be called by either LLDDs or SCSI Core.  LLDDs who
- * implement their own error recovery MAY ignore the timeout event if
- * they generated scsi_req_abort_cmd.
- */
-void scsi_req_abort_cmd(struct scsi_cmnd *cmd)
-{
-	if (!scsi_delete_timer(cmd))
-		return;
-	scsi_times_out(cmd);
-}
-EXPORT_SYMBOL(scsi_req_abort_cmd);
-
-/**
  * scsi_done - Enqueue the finished SCSI command into the done queue.
  * @cmd: The SCSI Command for which a low-level device driver (LLDD) gives
  * ownership back to SCSI Core -- i.e. the LLDD has finished with it.
@@ -802,42 +780,7 @@
  */
 static void scsi_done(struct scsi_cmnd *cmd)
 {
-	/*
-	 * We don't have to worry about this one timing out anymore.
-	 * If we are unable to remove the timer, then the command
-	 * has already timed out.  In which case, we have no choice but to
-	 * let the timeout function run, as we have no idea where in fact
-	 * that function could really be.  It might be on another processor,
-	 * etc, etc.
-	 */
-	if (!scsi_delete_timer(cmd))
-		return;
-	__scsi_done(cmd);
-}
-
-/* Private entry to scsi_done() to complete a command when the timer
- * isn't running --- used by scsi_times_out */
-void __scsi_done(struct scsi_cmnd *cmd)
-{
-	struct request *rq = cmd->request;
-
-	/*
-	 * Set the serial numbers back to zero
-	 */
-	cmd->serial_number = 0;
-
-	atomic_inc(&cmd->device->iodone_cnt);
-	if (cmd->result)
-		atomic_inc(&cmd->device->ioerr_cnt);
-
-	BUG_ON(!rq);
-
-	/*
-	 * The uptodate/nbytes values don't matter, as we allow partial
-	 * completes and thus will check this in the softirq callback
-	 */
-	rq->completion_data = cmd;
-	blk_complete_request(rq);
+	blk_complete_request(cmd->request);
 }
 
 /* Move this to a header if it becomes more generally useful */
diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
index 39ce3ab..fecefa0 100644
--- a/drivers/scsi/scsi_error.c
+++ b/drivers/scsi/scsi_error.c
@@ -112,69 +112,8 @@
 }
 
 /**
- * scsi_add_timer - Start timeout timer for a single scsi command.
- * @scmd:	scsi command that is about to start running.
- * @timeout:	amount of time to allow this command to run.
- * @complete:	timeout function to call if timer isn't canceled.
- *
- * Notes:
- *    This should be turned into an inline function.  Each scsi command
- *    has its own timer, and as it is added to the queue, we set up the
- *    timer.  When the command completes, we cancel the timer.
- */
-void scsi_add_timer(struct scsi_cmnd *scmd, int timeout,
-		    void (*complete)(struct scsi_cmnd *))
-{
-
-	/*
-	 * If the clock was already running for this command, then
-	 * first delete the timer.  The timer handling code gets rather
-	 * confused if we don't do this.
-	 */
-	if (scmd->eh_timeout.function)
-		del_timer(&scmd->eh_timeout);
-
-	scmd->eh_timeout.data = (unsigned long)scmd;
-	scmd->eh_timeout.expires = jiffies + timeout;
-	scmd->eh_timeout.function = (void (*)(unsigned long)) complete;
-
-	SCSI_LOG_ERROR_RECOVERY(5, printk("%s: scmd: %p, time:"
-					  " %d, (%p)\n", __func__,
-					  scmd, timeout, complete));
-
-	add_timer(&scmd->eh_timeout);
-}
-
-/**
- * scsi_delete_timer - Delete/cancel timer for a given function.
- * @scmd:	Cmd that we are canceling timer for
- *
- * Notes:
- *     This should be turned into an inline function.
- *
- * Return value:
- *     1 if we were able to detach the timer.  0 if we blew it, and the
- *     timer function has already started to run.
- */
-int scsi_delete_timer(struct scsi_cmnd *scmd)
-{
-	int rtn;
-
-	rtn = del_timer(&scmd->eh_timeout);
-
-	SCSI_LOG_ERROR_RECOVERY(5, printk("%s: scmd: %p,"
-					 " rtn: %d\n", __func__,
-					 scmd, rtn));
-
-	scmd->eh_timeout.data = (unsigned long)NULL;
-	scmd->eh_timeout.function = NULL;
-
-	return rtn;
-}
-
-/**
  * scsi_times_out - Timeout function for normal scsi commands.
- * @scmd:	Cmd that is timing out.
+ * @req:	request that is timing out.
  *
  * Notes:
  *     We do not need to lock this.  There is the potential for a race
@@ -182,9 +121,11 @@
  *     normal completion function determines that the timer has already
  *     fired, then it mustn't do anything.
  */
-void scsi_times_out(struct scsi_cmnd *scmd)
+enum blk_eh_timer_return scsi_times_out(struct request *req)
 {
-	enum scsi_eh_timer_return (* eh_timed_out)(struct scsi_cmnd *);
+	struct scsi_cmnd *scmd = req->special;
+	enum blk_eh_timer_return (*eh_timed_out)(struct scsi_cmnd *);
+	enum blk_eh_timer_return rtn = BLK_EH_NOT_HANDLED;
 
 	scsi_log_completion(scmd, TIMEOUT_ERROR);
 
@@ -196,22 +137,20 @@
 		eh_timed_out = NULL;
 
 	if (eh_timed_out)
-		switch (eh_timed_out(scmd)) {
-		case EH_HANDLED:
-			__scsi_done(scmd);
-			return;
-		case EH_RESET_TIMER:
-			scsi_add_timer(scmd, scmd->timeout_per_command,
-				       scsi_times_out);
-			return;
-		case EH_NOT_HANDLED:
+		rtn = eh_timed_out(scmd);
+		switch (rtn) {
+		case BLK_EH_NOT_HANDLED:
 			break;
+		default:
+			return rtn;
 		}
 
 	if (unlikely(!scsi_eh_scmd_add(scmd, SCSI_EH_CANCEL_CMD))) {
 		scmd->result |= DID_TIME_OUT << 16;
-		__scsi_done(scmd);
+		return BLK_EH_HANDLED;
 	}
+
+	return BLK_EH_NOT_HANDLED;
 }
 
 /**
@@ -1793,7 +1732,6 @@
 
 	blk_rq_init(NULL, &req);
 	scmd->request = &req;
-	memset(&scmd->eh_timeout, 0, sizeof(scmd->eh_timeout));
 
 	scmd->cmnd = req.cmd;
 
@@ -1804,8 +1742,6 @@
 
 	scmd->sc_data_direction		= DMA_BIDIRECTIONAL;
 
-	init_timer(&scmd->eh_timeout);
-
 	spin_lock_irqsave(shost->host_lock, flags);
 	shost->tmf_in_progress = 1;
 	spin_unlock_irqrestore(shost->host_lock, flags);
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index ff5d56b..98ee55c 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -852,7 +852,7 @@
 void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes)
 {
 	int result = cmd->result;
-	int this_count = scsi_bufflen(cmd);
+	int this_count;
 	struct request_queue *q = cmd->device->request_queue;
 	struct request *req = cmd->request;
 	int error = 0;
@@ -908,6 +908,7 @@
 	 */
 	if (scsi_end_request(cmd, error, good_bytes, result == 0) == NULL)
 		return;
+	this_count = blk_rq_bytes(req);
 
 	/* good_bytes = 0, or (inclusive) there were leftovers and
 	 * result = 0, so scsi_end_request couldn't retry.
@@ -1180,7 +1181,6 @@
 	
 	cmd->transfersize = req->data_len;
 	cmd->allowed = req->retries;
-	cmd->timeout_per_command = req->timeout;
 	return BLKPREP_OK;
 }
 EXPORT_SYMBOL(scsi_setup_blk_pc_cmnd);
@@ -1250,6 +1250,7 @@
 			break;
 		case SDEV_QUIESCE:
 		case SDEV_BLOCK:
+		case SDEV_CREATED_BLOCK:
 			/*
 			 * If the devices is blocked we defer normal commands.
 			 */
@@ -1415,17 +1416,26 @@
 	spin_unlock(shost->host_lock);
 	spin_lock(sdev->request_queue->queue_lock);
 
-	__scsi_done(cmd);
+	blk_complete_request(req);
 }
 
 static void scsi_softirq_done(struct request *rq)
 {
-	struct scsi_cmnd *cmd = rq->completion_data;
-	unsigned long wait_for = (cmd->allowed + 1) * cmd->timeout_per_command;
+	struct scsi_cmnd *cmd = rq->special;
+	unsigned long wait_for = (cmd->allowed + 1) * rq->timeout;
 	int disposition;
 
 	INIT_LIST_HEAD(&cmd->eh_entry);
 
+	/*
+	 * Set the serial numbers back to zero
+	 */
+	cmd->serial_number = 0;
+
+	atomic_inc(&cmd->device->iodone_cnt);
+	if (cmd->result)
+		atomic_inc(&cmd->device->ioerr_cnt);
+
 	disposition = scsi_decide_disposition(cmd);
 	if (disposition != SUCCESS &&
 	    time_before(cmd->jiffies_at_alloc + wait_for, jiffies)) {
@@ -1674,6 +1684,7 @@
 
 	blk_queue_prep_rq(q, scsi_prep_fn);
 	blk_queue_softirq_done(q, scsi_softirq_done);
+	blk_queue_rq_timed_out(q, scsi_times_out);
 	return q;
 }
 
@@ -2063,10 +2074,13 @@
 
 	switch (state) {
 	case SDEV_CREATED:
-		/* There are no legal states that come back to
-		 * created.  This is the manually initialised start
-		 * state */
-		goto illegal;
+		switch (oldstate) {
+		case SDEV_CREATED_BLOCK:
+			break;
+		default:
+			goto illegal;
+		}
+		break;
 			
 	case SDEV_RUNNING:
 		switch (oldstate) {
@@ -2104,8 +2118,17 @@
 
 	case SDEV_BLOCK:
 		switch (oldstate) {
-		case SDEV_CREATED:
 		case SDEV_RUNNING:
+		case SDEV_CREATED_BLOCK:
+			break;
+		default:
+			goto illegal;
+		}
+		break;
+
+	case SDEV_CREATED_BLOCK:
+		switch (oldstate) {
+		case SDEV_CREATED:
 			break;
 		default:
 			goto illegal;
@@ -2393,8 +2416,12 @@
 	int err = 0;
 
 	err = scsi_device_set_state(sdev, SDEV_BLOCK);
-	if (err)
-		return err;
+	if (err) {
+		err = scsi_device_set_state(sdev, SDEV_CREATED_BLOCK);
+
+		if (err)
+			return err;
+	}
 
 	/* 
 	 * The device has transitioned to SDEV_BLOCK.  Stop the
@@ -2437,8 +2464,12 @@
 	 * and goose the device queue if successful.  
 	 */
 	err = scsi_device_set_state(sdev, SDEV_RUNNING);
-	if (err)
-		return err;
+	if (err) {
+		err = scsi_device_set_state(sdev, SDEV_CREATED);
+
+		if (err)
+			return err;
+	}
 
 	spin_lock_irqsave(q->queue_lock, flags);
 	blk_start_queue(q);
diff --git a/drivers/scsi/scsi_netlink.c b/drivers/scsi/scsi_netlink.c
index ae7ed9a..b37e133 100644
--- a/drivers/scsi/scsi_netlink.c
+++ b/drivers/scsi/scsi_netlink.c
@@ -21,6 +21,7 @@
 #include <linux/time.h>
 #include <linux/jiffies.h>
 #include <linux/security.h>
+#include <linux/delay.h>
 #include <net/sock.h>
 #include <net/netlink.h>
 
@@ -30,6 +31,39 @@
 struct sock *scsi_nl_sock = NULL;
 EXPORT_SYMBOL_GPL(scsi_nl_sock);
 
+static DEFINE_SPINLOCK(scsi_nl_lock);
+static struct list_head scsi_nl_drivers;
+
+static u32	scsi_nl_state;
+#define STATE_EHANDLER_BSY		0x00000001
+
+struct scsi_nl_transport {
+	int (*msg_handler)(struct sk_buff *);
+	void (*event_handler)(struct notifier_block *, unsigned long, void *);
+	unsigned int refcnt;
+	int flags;
+};
+
+/* flags values (bit flags) */
+#define HANDLER_DELETING		0x1
+
+static struct scsi_nl_transport transports[SCSI_NL_MAX_TRANSPORTS] =
+	{ {NULL, }, };
+
+
+struct scsi_nl_drvr {
+	struct list_head next;
+	int (*dmsg_handler)(struct Scsi_Host *shost, void *payload,
+				 u32 len, u32 pid);
+	void (*devt_handler)(struct notifier_block *nb,
+				 unsigned long event, void *notify_ptr);
+	struct scsi_host_template *hostt;
+	u64 vendor_id;
+	unsigned int refcnt;
+	int flags;
+};
+
+
 
 /**
  * scsi_nl_rcv_msg - Receive message handler.
@@ -45,8 +79,9 @@
 {
 	struct nlmsghdr *nlh;
 	struct scsi_nl_hdr *hdr;
-	uint32_t rlen;
-	int err;
+	unsigned long flags;
+	u32 rlen;
+	int err, tport;
 
 	while (skb->len >= NLMSG_SPACE(0)) {
 		err = 0;
@@ -65,7 +100,7 @@
 
 		if (nlh->nlmsg_type != SCSI_TRANSPORT_MSG) {
 			err = -EBADMSG;
-			return;
+			goto next_msg;
 		}
 
 		hdr = NLMSG_DATA(nlh);
@@ -83,12 +118,27 @@
 		if (nlh->nlmsg_len < (sizeof(*nlh) + hdr->msglen)) {
 			printk(KERN_WARNING "%s: discarding partial message\n",
 				 __func__);
-			return;
+			goto next_msg;
 		}
 
 		/*
-		 * We currently don't support anyone sending us a message
+		 * Deliver message to the appropriate transport
 		 */
+		spin_lock_irqsave(&scsi_nl_lock, flags);
+
+		tport = hdr->transport;
+		if ((tport < SCSI_NL_MAX_TRANSPORTS) &&
+		    !(transports[tport].flags & HANDLER_DELETING) &&
+		    (transports[tport].msg_handler)) {
+			transports[tport].refcnt++;
+			spin_unlock_irqrestore(&scsi_nl_lock, flags);
+			err = transports[tport].msg_handler(skb);
+			spin_lock_irqsave(&scsi_nl_lock, flags);
+			transports[tport].refcnt--;
+		} else
+			err = -ENOENT;
+
+		spin_unlock_irqrestore(&scsi_nl_lock, flags);
 
 next_msg:
 		if ((err) || (nlh->nlmsg_flags & NLM_F_ACK))
@@ -110,14 +160,42 @@
 scsi_nl_rcv_event(struct notifier_block *this, unsigned long event, void *ptr)
 {
 	struct netlink_notify *n = ptr;
+	struct scsi_nl_drvr *driver;
+	unsigned long flags;
+	int tport;
 
 	if (n->protocol != NETLINK_SCSITRANSPORT)
 		return NOTIFY_DONE;
 
+	spin_lock_irqsave(&scsi_nl_lock, flags);
+	scsi_nl_state |= STATE_EHANDLER_BSY;
+
 	/*
-	 * Currently, we are not tracking PID's, etc. There is nothing
-	 * to handle.
+	 * Pass event on to any transports that may be listening
 	 */
+	for (tport = 0; tport < SCSI_NL_MAX_TRANSPORTS; tport++) {
+		if (!(transports[tport].flags & HANDLER_DELETING) &&
+		    (transports[tport].event_handler)) {
+			spin_unlock_irqrestore(&scsi_nl_lock, flags);
+			transports[tport].event_handler(this, event, ptr);
+			spin_lock_irqsave(&scsi_nl_lock, flags);
+		}
+	}
+
+	/*
+	 * Pass event on to any drivers that may be listening
+	 */
+	list_for_each_entry(driver, &scsi_nl_drivers, next) {
+		if (!(driver->flags & HANDLER_DELETING) &&
+		    (driver->devt_handler)) {
+			spin_unlock_irqrestore(&scsi_nl_lock, flags);
+			driver->devt_handler(this, event, ptr);
+			spin_lock_irqsave(&scsi_nl_lock, flags);
+		}
+	}
+
+	scsi_nl_state &= ~STATE_EHANDLER_BSY;
+	spin_unlock_irqrestore(&scsi_nl_lock, flags);
 
 	return NOTIFY_DONE;
 }
@@ -128,7 +206,281 @@
 
 
 /**
- * scsi_netlink_init - Called by SCSI subsystem to intialize the SCSI transport netlink interface
+ * GENERIC SCSI transport receive and event handlers
+ **/
+
+/**
+ * scsi_generic_msg_handler - receive message handler for GENERIC transport
+ * 			 messages
+ *
+ * @skb:		socket receive buffer
+ *
+ **/
+static int
+scsi_generic_msg_handler(struct sk_buff *skb)
+{
+	struct nlmsghdr *nlh = nlmsg_hdr(skb);
+	struct scsi_nl_hdr *snlh = NLMSG_DATA(nlh);
+	struct scsi_nl_drvr *driver;
+	struct Scsi_Host *shost;
+	unsigned long flags;
+	int err = 0, match, pid;
+
+	pid = NETLINK_CREDS(skb)->pid;
+
+	switch (snlh->msgtype) {
+	case SCSI_NL_SHOST_VENDOR:
+		{
+		struct scsi_nl_host_vendor_msg *msg = NLMSG_DATA(nlh);
+
+		/* Locate the driver that corresponds to the message */
+		spin_lock_irqsave(&scsi_nl_lock, flags);
+		match = 0;
+		list_for_each_entry(driver, &scsi_nl_drivers, next) {
+			if (driver->vendor_id == msg->vendor_id) {
+				match = 1;
+				break;
+			}
+		}
+
+		if ((!match) || (!driver->dmsg_handler)) {
+			spin_unlock_irqrestore(&scsi_nl_lock, flags);
+			err = -ESRCH;
+			goto rcv_exit;
+		}
+
+		if (driver->flags & HANDLER_DELETING) {
+			spin_unlock_irqrestore(&scsi_nl_lock, flags);
+			err = -ESHUTDOWN;
+			goto rcv_exit;
+		}
+
+		driver->refcnt++;
+		spin_unlock_irqrestore(&scsi_nl_lock, flags);
+
+
+		/* if successful, scsi_host_lookup takes a shost reference */
+		shost = scsi_host_lookup(msg->host_no);
+		if (!shost) {
+			err = -ENODEV;
+			goto driver_exit;
+		}
+
+		/* is this host owned by the vendor ? */
+		if (shost->hostt != driver->hostt) {
+			err = -EINVAL;
+			goto vendormsg_put;
+		}
+
+		/* pass message on to the driver */
+		err = driver->dmsg_handler(shost, (void *)&msg[1],
+					 msg->vmsg_datalen, pid);
+
+vendormsg_put:
+		/* release reference by scsi_host_lookup */
+		scsi_host_put(shost);
+
+driver_exit:
+		/* release our own reference on the registration object */
+		spin_lock_irqsave(&scsi_nl_lock, flags);
+		driver->refcnt--;
+		spin_unlock_irqrestore(&scsi_nl_lock, flags);
+		break;
+		}
+
+	default:
+		err = -EBADR;
+		break;
+	}
+
+rcv_exit:
+	if (err)
+		printk(KERN_WARNING "%s: Msgtype %d failed - err %d\n",
+			 __func__, snlh->msgtype, err);
+	return err;
+}
+
+
+/**
+ * scsi_nl_add_transport -
+ *    Registers message and event handlers for a transport. Enables
+ *    receipt of netlink messages and events to a transport.
+ *
+ * @tport:		transport registering handlers
+ * @msg_handler:	receive message handler callback
+ * @event_handler:	receive event handler callback
+ **/
+int
+scsi_nl_add_transport(u8 tport,
+	int (*msg_handler)(struct sk_buff *),
+	void (*event_handler)(struct notifier_block *, unsigned long, void *))
+{
+	unsigned long flags;
+	int err = 0;
+
+	if (tport >= SCSI_NL_MAX_TRANSPORTS)
+		return -EINVAL;
+
+	spin_lock_irqsave(&scsi_nl_lock, flags);
+
+	if (scsi_nl_state & STATE_EHANDLER_BSY) {
+		spin_unlock_irqrestore(&scsi_nl_lock, flags);
+		msleep(1);
+		spin_lock_irqsave(&scsi_nl_lock, flags);
+	}
+
+	if (transports[tport].msg_handler || transports[tport].event_handler) {
+		err = -EALREADY;
+		goto register_out;
+	}
+
+	transports[tport].msg_handler = msg_handler;
+	transports[tport].event_handler = event_handler;
+	transports[tport].flags = 0;
+	transports[tport].refcnt = 0;
+
+register_out:
+	spin_unlock_irqrestore(&scsi_nl_lock, flags);
+
+	return err;
+}
+EXPORT_SYMBOL_GPL(scsi_nl_add_transport);
+
+
+/**
+ * scsi_nl_remove_transport -
+ *    Disable transport receiption of messages and events
+ *
+ * @tport:		transport deregistering handlers
+ *
+ **/
+void
+scsi_nl_remove_transport(u8 tport)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&scsi_nl_lock, flags);
+	if (scsi_nl_state & STATE_EHANDLER_BSY) {
+		spin_unlock_irqrestore(&scsi_nl_lock, flags);
+		msleep(1);
+		spin_lock_irqsave(&scsi_nl_lock, flags);
+	}
+
+	if (tport < SCSI_NL_MAX_TRANSPORTS) {
+		transports[tport].flags |= HANDLER_DELETING;
+
+		while (transports[tport].refcnt != 0) {
+			spin_unlock_irqrestore(&scsi_nl_lock, flags);
+			schedule_timeout_uninterruptible(HZ/4);
+			spin_lock_irqsave(&scsi_nl_lock, flags);
+		}
+		transports[tport].msg_handler = NULL;
+		transports[tport].event_handler = NULL;
+		transports[tport].flags = 0;
+	}
+
+	spin_unlock_irqrestore(&scsi_nl_lock, flags);
+
+	return;
+}
+EXPORT_SYMBOL_GPL(scsi_nl_remove_transport);
+
+
+/**
+ * scsi_nl_add_driver -
+ *    A driver is registering its interfaces for SCSI netlink messages
+ *
+ * @vendor_id:          A unique identification value for the driver.
+ * @hostt:		address of the driver's host template. Used
+ *			to verify an shost is bound to the driver
+ * @nlmsg_handler:	receive message handler callback
+ * @nlevt_handler:	receive event handler callback
+ *
+ * Returns:
+ *   0 on Success
+ *   error result otherwise
+ **/
+int
+scsi_nl_add_driver(u64 vendor_id, struct scsi_host_template *hostt,
+	int (*nlmsg_handler)(struct Scsi_Host *shost, void *payload,
+				 u32 len, u32 pid),
+	void (*nlevt_handler)(struct notifier_block *nb,
+				 unsigned long event, void *notify_ptr))
+{
+	struct scsi_nl_drvr *driver;
+	unsigned long flags;
+
+	driver = kzalloc(sizeof(*driver), GFP_KERNEL);
+	if (unlikely(!driver)) {
+		printk(KERN_ERR "%s: allocation failure\n", __func__);
+		return -ENOMEM;
+	}
+
+	driver->dmsg_handler = nlmsg_handler;
+	driver->devt_handler = nlevt_handler;
+	driver->hostt = hostt;
+	driver->vendor_id = vendor_id;
+
+	spin_lock_irqsave(&scsi_nl_lock, flags);
+	if (scsi_nl_state & STATE_EHANDLER_BSY) {
+		spin_unlock_irqrestore(&scsi_nl_lock, flags);
+		msleep(1);
+		spin_lock_irqsave(&scsi_nl_lock, flags);
+	}
+	list_add_tail(&driver->next, &scsi_nl_drivers);
+	spin_unlock_irqrestore(&scsi_nl_lock, flags);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(scsi_nl_add_driver);
+
+
+/**
+ * scsi_nl_remove_driver -
+ *    An driver is unregistering with the SCSI netlink messages
+ *
+ * @vendor_id:          The unique identification value for the driver.
+ **/
+void
+scsi_nl_remove_driver(u64 vendor_id)
+{
+	struct scsi_nl_drvr *driver;
+	unsigned long flags;
+
+	spin_lock_irqsave(&scsi_nl_lock, flags);
+	if (scsi_nl_state & STATE_EHANDLER_BSY) {
+		spin_unlock_irqrestore(&scsi_nl_lock, flags);
+		msleep(1);
+		spin_lock_irqsave(&scsi_nl_lock, flags);
+	}
+
+	list_for_each_entry(driver, &scsi_nl_drivers, next) {
+		if (driver->vendor_id == vendor_id) {
+			driver->flags |= HANDLER_DELETING;
+			while (driver->refcnt != 0) {
+				spin_unlock_irqrestore(&scsi_nl_lock, flags);
+				schedule_timeout_uninterruptible(HZ/4);
+				spin_lock_irqsave(&scsi_nl_lock, flags);
+			}
+			list_del(&driver->next);
+			kfree(driver);
+			spin_unlock_irqrestore(&scsi_nl_lock, flags);
+			return;
+		}
+	}
+
+	spin_unlock_irqrestore(&scsi_nl_lock, flags);
+
+	printk(KERN_ERR "%s: removal of driver failed - vendor_id 0x%llx\n",
+	       __func__, (unsigned long long)vendor_id);
+	return;
+}
+EXPORT_SYMBOL_GPL(scsi_nl_remove_driver);
+
+
+/**
+ * scsi_netlink_init - Called by SCSI subsystem to intialize
+ * 	the SCSI transport netlink interface
  *
  **/
 void
@@ -136,6 +488,8 @@
 {
 	int error;
 
+	INIT_LIST_HEAD(&scsi_nl_drivers);
+
 	error = netlink_register_notifier(&scsi_netlink_notifier);
 	if (error) {
 		printk(KERN_ERR "%s: register of event handler failed - %d\n",
@@ -150,8 +504,15 @@
 		printk(KERN_ERR "%s: register of recieve handler failed\n",
 				__func__);
 		netlink_unregister_notifier(&scsi_netlink_notifier);
+		return;
 	}
 
+	/* Register the entry points for the generic SCSI transport */
+	error = scsi_nl_add_transport(SCSI_NL_TRANSPORT,
+				scsi_generic_msg_handler, NULL);
+	if (error)
+		printk(KERN_ERR "%s: register of GENERIC transport handler"
+				"  failed - %d\n", __func__, error);
 	return;
 }
 
@@ -163,6 +524,8 @@
 void
 scsi_netlink_exit(void)
 {
+	scsi_nl_remove_transport(SCSI_NL_TRANSPORT);
+
 	if (scsi_nl_sock) {
 		netlink_kernel_release(scsi_nl_sock);
 		netlink_unregister_notifier(&scsi_netlink_notifier);
@@ -172,3 +535,147 @@
 }
 
 
+/*
+ * Exported Interfaces
+ */
+
+/**
+ * scsi_nl_send_transport_msg -
+ *    Generic function to send a single message from a SCSI transport to
+ *    a single process
+ *
+ * @pid:		receiving pid
+ * @hdr:		message payload
+ *
+ **/
+void
+scsi_nl_send_transport_msg(u32 pid, struct scsi_nl_hdr *hdr)
+{
+	struct sk_buff *skb;
+	struct nlmsghdr	*nlh;
+	const char *fn;
+	char *datab;
+	u32 len, skblen;
+	int err;
+
+	if (!scsi_nl_sock) {
+		err = -ENOENT;
+		fn = "netlink socket";
+		goto msg_fail;
+	}
+
+	len = NLMSG_SPACE(hdr->msglen);
+	skblen = NLMSG_SPACE(len);
+
+	skb = alloc_skb(skblen, GFP_KERNEL);
+	if (!skb) {
+		err = -ENOBUFS;
+		fn = "alloc_skb";
+		goto msg_fail;
+	}
+
+	nlh = nlmsg_put(skb, pid, 0, SCSI_TRANSPORT_MSG, len - sizeof(*nlh), 0);
+	if (!nlh) {
+		err = -ENOBUFS;
+		fn = "nlmsg_put";
+		goto msg_fail_skb;
+	}
+	datab = NLMSG_DATA(nlh);
+	memcpy(datab, hdr, hdr->msglen);
+
+	err = nlmsg_unicast(scsi_nl_sock, skb, pid);
+	if (err < 0) {
+		fn = "nlmsg_unicast";
+		/* nlmsg_unicast already kfree_skb'd */
+		goto msg_fail;
+	}
+
+	return;
+
+msg_fail_skb:
+	kfree_skb(skb);
+msg_fail:
+	printk(KERN_WARNING
+		"%s: Dropped Message : pid %d Transport %d, msgtype x%x, "
+		"msglen %d: %s : err %d\n",
+		__func__, pid, hdr->transport, hdr->msgtype, hdr->msglen,
+		fn, err);
+	return;
+}
+EXPORT_SYMBOL_GPL(scsi_nl_send_transport_msg);
+
+
+/**
+ * scsi_nl_send_vendor_msg - called to send a shost vendor unique message
+ *                      to a specific process id.
+ *
+ * @pid:		process id of the receiver
+ * @host_no:		host # sending the message
+ * @vendor_id:		unique identifier for the driver's vendor
+ * @data_len:		amount, in bytes, of vendor unique payload data
+ * @data_buf:		pointer to vendor unique data buffer
+ *
+ * Returns:
+ *   0 on succesful return
+ *   otherwise, failing error code
+ *
+ * Notes:
+ *	This routine assumes no locks are held on entry.
+ */
+int
+scsi_nl_send_vendor_msg(u32 pid, unsigned short host_no, u64 vendor_id,
+			 char *data_buf, u32 data_len)
+{
+	struct sk_buff *skb;
+	struct nlmsghdr	*nlh;
+	struct scsi_nl_host_vendor_msg *msg;
+	u32 len, skblen;
+	int err;
+
+	if (!scsi_nl_sock) {
+		err = -ENOENT;
+		goto send_vendor_fail;
+	}
+
+	len = SCSI_NL_MSGALIGN(sizeof(*msg) + data_len);
+	skblen = NLMSG_SPACE(len);
+
+	skb = alloc_skb(skblen, GFP_KERNEL);
+	if (!skb) {
+		err = -ENOBUFS;
+		goto send_vendor_fail;
+	}
+
+	nlh = nlmsg_put(skb, 0, 0, SCSI_TRANSPORT_MSG,
+				skblen - sizeof(*nlh), 0);
+	if (!nlh) {
+		err = -ENOBUFS;
+		goto send_vendor_fail_skb;
+	}
+	msg = NLMSG_DATA(nlh);
+
+	INIT_SCSI_NL_HDR(&msg->snlh, SCSI_NL_TRANSPORT,
+				SCSI_NL_SHOST_VENDOR, len);
+	msg->vendor_id = vendor_id;
+	msg->host_no = host_no;
+	msg->vmsg_datalen = data_len;	/* bytes */
+	memcpy(&msg[1], data_buf, data_len);
+
+	err = nlmsg_unicast(scsi_nl_sock, skb, pid);
+	if (err)
+		/* nlmsg_multicast already kfree_skb'd */
+		goto send_vendor_fail;
+
+	return 0;
+
+send_vendor_fail_skb:
+	kfree_skb(skb);
+send_vendor_fail:
+	printk(KERN_WARNING
+		"%s: Dropped SCSI Msg : host %d vendor_unique - err %d\n",
+		__func__, host_no, err);
+	return err;
+}
+EXPORT_SYMBOL(scsi_nl_send_vendor_msg);
+
+
diff --git a/drivers/scsi/scsi_priv.h b/drivers/scsi/scsi_priv.h
index 79f0f75..6cddd5d 100644
--- a/drivers/scsi/scsi_priv.h
+++ b/drivers/scsi/scsi_priv.h
@@ -4,6 +4,7 @@
 #include <linux/device.h>
 
 struct request_queue;
+struct request;
 struct scsi_cmnd;
 struct scsi_device;
 struct scsi_host_template;
@@ -27,7 +28,6 @@
 extern int scsi_dispatch_cmd(struct scsi_cmnd *cmd);
 extern int scsi_setup_command_freelist(struct Scsi_Host *shost);
 extern void scsi_destroy_command_freelist(struct Scsi_Host *shost);
-extern void __scsi_done(struct scsi_cmnd *cmd);
 #ifdef CONFIG_SCSI_LOGGING
 void scsi_log_send(struct scsi_cmnd *cmd);
 void scsi_log_completion(struct scsi_cmnd *cmd, int disposition);
@@ -49,10 +49,7 @@
 extern void scsi_exit_devinfo(void);
 
 /* scsi_error.c */
-extern void scsi_add_timer(struct scsi_cmnd *, int,
-		void (*)(struct scsi_cmnd *));
-extern int scsi_delete_timer(struct scsi_cmnd *);
-extern void scsi_times_out(struct scsi_cmnd *cmd);
+extern enum blk_eh_timer_return scsi_times_out(struct request *req);
 extern int scsi_error_handler(void *host);
 extern int scsi_decide_disposition(struct scsi_cmnd *cmd);
 extern void scsi_eh_wakeup(struct Scsi_Host *shost);
diff --git a/drivers/scsi/scsi_proc.c b/drivers/scsi/scsi_proc.c
index c6a904a..82f7b2d 100644
--- a/drivers/scsi/scsi_proc.c
+++ b/drivers/scsi/scsi_proc.c
@@ -259,8 +259,8 @@
 	int error = -ENXIO;
 
 	shost = scsi_host_lookup(host);
-	if (IS_ERR(shost))
-		return PTR_ERR(shost);
+	if (!shost)
+		return error;
 
 	if (shost->transportt->user_scan)
 		error = shost->transportt->user_scan(shost, channel, id, lun);
@@ -287,8 +287,8 @@
 	int error = -ENXIO;
 
 	shost = scsi_host_lookup(host);
-	if (IS_ERR(shost))
-		return PTR_ERR(shost);
+	if (!shost)
+		return error;
 	sdev = scsi_device_lookup(shost, channel, id, lun);
 	if (sdev) {
 		scsi_remove_device(sdev);
diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c
index 34d0de6..334862e 100644
--- a/drivers/scsi/scsi_scan.c
+++ b/drivers/scsi/scsi_scan.c
@@ -730,6 +730,8 @@
 static int scsi_add_lun(struct scsi_device *sdev, unsigned char *inq_result,
 		int *bflags, int async)
 {
+	int ret;
+
 	/*
 	 * XXX do not save the inquiry, since it can change underneath us,
 	 * save just vendor/model/rev.
@@ -885,7 +887,17 @@
 
 	/* set the device running here so that slave configure
 	 * may do I/O */
-	scsi_device_set_state(sdev, SDEV_RUNNING);
+	ret = scsi_device_set_state(sdev, SDEV_RUNNING);
+	if (ret) {
+		ret = scsi_device_set_state(sdev, SDEV_BLOCK);
+
+		if (ret) {
+			sdev_printk(KERN_ERR, sdev,
+				    "in wrong state %s to complete scan\n",
+				    scsi_device_state_name(sdev->sdev_state));
+			return SCSI_SCAN_NO_RESPONSE;
+		}
+	}
 
 	if (*bflags & BLIST_MS_192_BYTES_FOR_3F)
 		sdev->use_192_bytes_for_3f = 1;
@@ -899,7 +911,7 @@
 	transport_configure_device(&sdev->sdev_gendev);
 
 	if (sdev->host->hostt->slave_configure) {
-		int ret = sdev->host->hostt->slave_configure(sdev);
+		ret = sdev->host->hostt->slave_configure(sdev);
 		if (ret) {
 			/*
 			 * if LLDD reports slave not present, don't clutter
@@ -994,7 +1006,7 @@
 	 */
 	sdev = scsi_device_lookup_by_target(starget, lun);
 	if (sdev) {
-		if (rescan || sdev->sdev_state != SDEV_CREATED) {
+		if (rescan || !scsi_device_created(sdev)) {
 			SCSI_LOG_SCAN_BUS(3, printk(KERN_INFO
 				"scsi scan: device exists on %s\n",
 				sdev->sdev_gendev.bus_id));
@@ -1467,7 +1479,7 @@
 	kfree(lun_data);
  out:
 	scsi_device_put(sdev);
-	if (sdev->sdev_state == SDEV_CREATED)
+	if (scsi_device_created(sdev))
 		/*
 		 * the sdev we used didn't appear in the report luns scan
 		 */
diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c
index ab3c718..93c28f3 100644
--- a/drivers/scsi/scsi_sysfs.c
+++ b/drivers/scsi/scsi_sysfs.c
@@ -34,6 +34,7 @@
 	{ SDEV_QUIESCE, "quiesce" },
 	{ SDEV_OFFLINE,	"offline" },
 	{ SDEV_BLOCK,	"blocked" },
+	{ SDEV_CREATED_BLOCK, "created-blocked" },
 };
 
 const char *scsi_device_state_name(enum scsi_device_state state)
@@ -560,12 +561,15 @@
 sdev_rd_attr (model, "%.16s\n");
 sdev_rd_attr (rev, "%.4s\n");
 
+/*
+ * TODO: can we make these symlinks to the block layer ones?
+ */
 static ssize_t
 sdev_show_timeout (struct device *dev, struct device_attribute *attr, char *buf)
 {
 	struct scsi_device *sdev;
 	sdev = to_scsi_device(dev);
-	return snprintf (buf, 20, "%d\n", sdev->timeout / HZ);
+	return snprintf(buf, 20, "%d\n", sdev->request_queue->rq_timeout / HZ);
 }
 
 static ssize_t
@@ -576,7 +580,7 @@
 	int timeout;
 	sdev = to_scsi_device(dev);
 	sscanf (buf, "%d\n", &timeout);
-	sdev->timeout = timeout * HZ;
+	blk_queue_rq_timeout(sdev->request_queue, timeout * HZ);
 	return count;
 }
 static DEVICE_ATTR(timeout, S_IRUGO | S_IWUSR, sdev_show_timeout, sdev_store_timeout);
diff --git a/drivers/scsi/scsi_tgt_lib.c b/drivers/scsi/scsi_tgt_lib.c
index 257e097..48ba413 100644
--- a/drivers/scsi/scsi_tgt_lib.c
+++ b/drivers/scsi/scsi_tgt_lib.c
@@ -362,7 +362,7 @@
 	int err;
 
 	dprintk("%lx %u\n", uaddr, len);
-	err = blk_rq_map_user(q, rq, (void *)uaddr, len);
+	err = blk_rq_map_user(q, rq, NULL, (void *)uaddr, len, GFP_KERNEL);
 	if (err) {
 		/*
 		 * TODO: need to fixup sg_tablesize, max_segment_size,
@@ -460,7 +460,7 @@
 
 	/* TODO: replace with a O(1) alg */
 	shost = scsi_host_lookup(host_no);
-	if (IS_ERR(shost)) {
+	if (!shost) {
 		printk(KERN_ERR "Could not find host no %d\n", host_no);
 		return -EINVAL;
 	}
@@ -550,7 +550,7 @@
 	dprintk("%d %d %llx\n", host_no, result, (unsigned long long) mid);
 
 	shost = scsi_host_lookup(host_no);
-	if (IS_ERR(shost)) {
+	if (!shost) {
 		printk(KERN_ERR "Could not find host no %d\n", host_no);
 		return err;
 	}
@@ -603,7 +603,7 @@
 	dprintk("%d %d%llx\n", host_no, result, (unsigned long long)itn_id);
 
 	shost = scsi_host_lookup(host_no);
-	if (IS_ERR(shost)) {
+	if (!shost) {
 		printk(KERN_ERR "Could not find host no %d\n", host_no);
 		return err;
 	}
diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c
index 56823fd..d5f7653 100644
--- a/drivers/scsi/scsi_transport_fc.c
+++ b/drivers/scsi/scsi_transport_fc.c
@@ -40,31 +40,7 @@
 
 static int fc_queue_work(struct Scsi_Host *, struct work_struct *);
 static void fc_vport_sched_delete(struct work_struct *work);
-
-/*
- * This is a temporary carrier for creating a vport. It will eventually
- * be replaced  by a real message definition for sgio or netlink.
- *
- * fc_vport_identifiers: This set of data contains all elements
- * to uniquely identify and instantiate a FC virtual port.
- *
- * Notes:
- *   symbolic_name: The driver is to append the symbolic_name string data
- *      to the symbolic_node_name data that it generates by default.
- *      the resulting combination should then be registered with the switch.
- *      It is expected that things like Xen may stuff a VM title into
- *      this field.
- */
-struct fc_vport_identifiers {
-	u64 node_name;
-	u64 port_name;
-	u32 roles;
-	bool disable;
-	enum fc_port_type vport_type;	/* only FC_PORTTYPE_NPIV allowed */
-	char symbolic_name[FC_VPORT_SYMBOLIC_NAMELEN];
-};
-
-static int fc_vport_create(struct Scsi_Host *shost, int channel,
+static int fc_vport_setup(struct Scsi_Host *shost, int channel,
 	struct device *pdev, struct fc_vport_identifiers  *ids,
 	struct fc_vport **vport);
 
@@ -1760,7 +1736,7 @@
 	vid.disable = false;		/* always enabled */
 
 	/* we only allow support on Channel 0 !!! */
-	stat = fc_vport_create(shost, 0, &shost->shost_gendev, &vid, &vport);
+	stat = fc_vport_setup(shost, 0, &shost->shost_gendev, &vid, &vport);
 	return stat ? stat : count;
 }
 static FC_DEVICE_ATTR(host, vport_create, S_IWUSR, NULL,
@@ -1950,15 +1926,15 @@
  * Notes:
  *	This routine assumes no locks are held on entry.
  */
-static enum scsi_eh_timer_return
+static enum blk_eh_timer_return
 fc_timed_out(struct scsi_cmnd *scmd)
 {
 	struct fc_rport *rport = starget_to_rport(scsi_target(scmd->device));
 
 	if (rport->port_state == FC_PORTSTATE_BLOCKED)
-		return EH_RESET_TIMER;
+		return BLK_EH_RESET_TIMER;
 
-	return EH_NOT_HANDLED;
+	return BLK_EH_NOT_HANDLED;
 }
 
 /*
@@ -3103,7 +3079,7 @@
 
 
 /**
- * fc_vport_create - allocates and creates a FC virtual port.
+ * fc_vport_setup - allocates and creates a FC virtual port.
  * @shost:	scsi host the virtual port is connected to.
  * @channel:	Channel on shost port connected to.
  * @pdev:	parent device for vport
@@ -3118,7 +3094,7 @@
  *	This routine assumes no locks are held on entry.
  */
 static int
-fc_vport_create(struct Scsi_Host *shost, int channel, struct device *pdev,
+fc_vport_setup(struct Scsi_Host *shost, int channel, struct device *pdev,
 	struct fc_vport_identifiers  *ids, struct fc_vport **ret_vport)
 {
 	struct fc_host_attrs *fc_host = shost_to_fc_host(shost);
@@ -3231,6 +3207,28 @@
 	return error;
 }
 
+/**
+ * fc_vport_create - Admin App or LLDD requests creation of a vport
+ * @shost:	scsi host the virtual port is connected to.
+ * @channel:	channel on shost port connected to.
+ * @ids:	The world wide names, FC4 port roles, etc for
+ *              the virtual port.
+ *
+ * Notes:
+ *	This routine assumes no locks are held on entry.
+ */
+struct fc_vport *
+fc_vport_create(struct Scsi_Host *shost, int channel,
+	struct fc_vport_identifiers *ids)
+{
+	int stat;
+	struct fc_vport *vport;
+
+	stat = fc_vport_setup(shost, channel, &shost->shost_gendev,
+		 ids, &vport);
+	return stat ? NULL : vport;
+}
+EXPORT_SYMBOL(fc_vport_create);
 
 /**
  * fc_vport_terminate - Admin App or LLDD requests termination of a vport
diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c
index 043c392..0ce5f7c 100644
--- a/drivers/scsi/scsi_transport_iscsi.c
+++ b/drivers/scsi/scsi_transport_iscsi.c
@@ -1361,7 +1361,7 @@
 		return -EINVAL;
 
 	shost = scsi_host_lookup(ev->u.tgt_dscvr.host_no);
-	if (IS_ERR(shost)) {
+	if (!shost) {
 		printk(KERN_ERR "target discovery could not find host no %u\n",
 		       ev->u.tgt_dscvr.host_no);
 		return -ENODEV;
@@ -1387,7 +1387,7 @@
 		return -ENOSYS;
 
 	shost = scsi_host_lookup(ev->u.set_host_param.host_no);
-	if (IS_ERR(shost)) {
+	if (!shost) {
 		printk(KERN_ERR "set_host_param could not find host no %u\n",
 		       ev->u.set_host_param.host_no);
 		return -ENODEV;
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index e5e7d78..a7b53be 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -47,6 +47,7 @@
 #include <linux/blkpg.h>
 #include <linux/delay.h>
 #include <linux/mutex.h>
+#include <linux/string_helpers.h>
 #include <asm/uaccess.h>
 
 #include <scsi/scsi.h>
@@ -86,6 +87,12 @@
 MODULE_ALIAS_SCSI_DEVICE(TYPE_MOD);
 MODULE_ALIAS_SCSI_DEVICE(TYPE_RBC);
 
+#if !defined(CONFIG_DEBUG_BLOCK_EXT_DEVT)
+#define SD_MINORS	16
+#else
+#define SD_MINORS	0
+#endif
+
 static int  sd_revalidate_disk(struct gendisk *);
 static int  sd_probe(struct device *);
 static int  sd_remove(struct device *);
@@ -159,7 +166,7 @@
 			sd_print_sense_hdr(sdkp, &sshdr);
 		return -EINVAL;
 	}
-	sd_revalidate_disk(sdkp->disk);
+	revalidate_disk(sdkp->disk);
 	return count;
 }
 
@@ -377,7 +384,6 @@
 	sector_t block = rq->sector;
 	sector_t threshold;
 	unsigned int this_count = rq->nr_sectors;
-	unsigned int timeout = sdp->timeout;
 	int ret;
 
 	if (rq->cmd_type == REQ_TYPE_BLOCK_PC) {
@@ -578,7 +584,6 @@
 	SCpnt->transfersize = sdp->sector_size;
 	SCpnt->underflow = this_count << 9;
 	SCpnt->allowed = SD_MAX_RETRIES;
-	SCpnt->timeout_per_command = timeout;
 
 	/*
 	 * This indicates that the command is ready from our end to be
@@ -910,7 +915,7 @@
 	struct scsi_disk *sdkp = scsi_disk_get_from_dev(dev);
 
 	if (sdkp) {
-		sd_revalidate_disk(sdkp->disk);
+		revalidate_disk(sdkp->disk);
 		scsi_disk_put(sdkp);
 	}
 }
@@ -1429,27 +1434,21 @@
 		 */
 		sector_size = 512;
 	}
-	{
-		/*
-		 * The msdos fs needs to know the hardware sector size
-		 * So I have created this table. See ll_rw_blk.c
-		 * Jacques Gelinas (Jacques@solucorp.qc.ca)
-		 */
-		int hard_sector = sector_size;
-		sector_t sz = (sdkp->capacity/2) * (hard_sector/256);
-		struct request_queue *queue = sdp->request_queue;
-		sector_t mb = sz;
+	blk_queue_hardsect_size(sdp->request_queue, sector_size);
 
-		blk_queue_hardsect_size(queue, hard_sector);
-		/* avoid 64-bit division on 32-bit platforms */
-		sector_div(sz, 625);
-		mb -= sz - 974;
-		sector_div(mb, 1950);
+	{
+		char cap_str_2[10], cap_str_10[10];
+		u64 sz = sdkp->capacity << ffz(~sector_size);
+
+		string_get_size(sz, STRING_UNITS_2, cap_str_2,
+				sizeof(cap_str_2));
+		string_get_size(sz, STRING_UNITS_10, cap_str_10,
+				sizeof(cap_str_10));
 
 		sd_printk(KERN_NOTICE, sdkp,
-			  "%llu %d-byte hardware sectors (%llu MB)\n",
+			  "%llu %d-byte hardware sectors: (%s/%s)\n",
 			  (unsigned long long)sdkp->capacity,
-			  hard_sector, (unsigned long long)mb);
+			  sector_size, cap_str_10, cap_str_2);
 	}
 
 	/* Rescale capacity to 512-byte units */
@@ -1764,6 +1763,52 @@
 }
 
 /**
+ *	sd_format_disk_name - format disk name
+ *	@prefix: name prefix - ie. "sd" for SCSI disks
+ *	@index: index of the disk to format name for
+ *	@buf: output buffer
+ *	@buflen: length of the output buffer
+ *
+ *	SCSI disk names starts at sda.  The 26th device is sdz and the
+ *	27th is sdaa.  The last one for two lettered suffix is sdzz
+ *	which is followed by sdaaa.
+ *
+ *	This is basically 26 base counting with one extra 'nil' entry
+ *	at the beggining from the second digit on and can be
+ *	determined using similar method as 26 base conversion with the
+ *	index shifted -1 after each digit is computed.
+ *
+ *	CONTEXT:
+ *	Don't care.
+ *
+ *	RETURNS:
+ *	0 on success, -errno on failure.
+ */
+static int sd_format_disk_name(char *prefix, int index, char *buf, int buflen)
+{
+	const int base = 'z' - 'a' + 1;
+	char *begin = buf + strlen(prefix);
+	char *end = buf + buflen;
+	char *p;
+	int unit;
+
+	p = end - 1;
+	*p = '\0';
+	unit = base;
+	do {
+		if (p == begin)
+			return -EINVAL;
+		*--p = 'a' + (index % unit);
+		index = (index / unit) - 1;
+	} while (index >= 0);
+
+	memmove(begin, p, end - p);
+	memcpy(buf, prefix, strlen(prefix));
+
+	return 0;
+}
+
+/**
  *	sd_probe - called during driver initialization and whenever a
  *	new scsi device is attached to the system. It is called once
  *	for each scsi device (not just disks) present.
@@ -1801,7 +1846,7 @@
 	if (!sdkp)
 		goto out;
 
-	gd = alloc_disk(16);
+	gd = alloc_disk(SD_MINORS);
 	if (!gd)
 		goto out_free;
 
@@ -1815,8 +1860,8 @@
 	if (error)
 		goto out_put;
 
-	error = -EBUSY;
-	if (index >= SD_MAX_DISKS)
+	error = sd_format_disk_name("sd", index, gd->disk_name, DISK_NAME_LEN);
+	if (error)
 		goto out_free_index;
 
 	sdkp->device = sdp;
@@ -1826,11 +1871,12 @@
 	sdkp->openers = 0;
 	sdkp->previous_state = 1;
 
-	if (!sdp->timeout) {
+	if (!sdp->request_queue->rq_timeout) {
 		if (sdp->type != TYPE_MOD)
-			sdp->timeout = SD_TIMEOUT;
+			blk_queue_rq_timeout(sdp->request_queue, SD_TIMEOUT);
 		else
-			sdp->timeout = SD_MOD_TIMEOUT;
+			blk_queue_rq_timeout(sdp->request_queue,
+					     SD_MOD_TIMEOUT);
 	}
 
 	device_initialize(&sdkp->dev);
@@ -1843,24 +1889,12 @@
 
 	get_device(&sdp->sdev_gendev);
 
-	gd->major = sd_major((index & 0xf0) >> 4);
-	gd->first_minor = ((index & 0xf) << 4) | (index & 0xfff00);
-	gd->minors = 16;
-	gd->fops = &sd_fops;
-
-	if (index < 26) {
-		sprintf(gd->disk_name, "sd%c", 'a' + index % 26);
-	} else if (index < (26 + 1) * 26) {
-		sprintf(gd->disk_name, "sd%c%c",
-			'a' + index / 26 - 1,'a' + index % 26);
-	} else {
-		const unsigned int m1 = (index / 26 - 1) / 26 - 1;
-		const unsigned int m2 = (index / 26 - 1) % 26;
-		const unsigned int m3 =  index % 26;
-		sprintf(gd->disk_name, "sd%c%c%c",
-			'a' + m1, 'a' + m2, 'a' + m3);
+	if (index < SD_MAX_DISKS) {
+		gd->major = sd_major((index & 0xf0) >> 4);
+		gd->first_minor = ((index & 0xf) << 4) | (index & 0xfff00);
+		gd->minors = SD_MINORS;
 	}
-
+	gd->fops = &sd_fops;
 	gd->private_data = &sdkp->driver;
 	gd->queue = sdkp->device->request_queue;
 
@@ -1869,7 +1903,7 @@
 	blk_queue_prep_rq(sdp->request_queue, sd_prep_fn);
 
 	gd->driverfs_dev = &sdp->sdev_gendev;
-	gd->flags = GENHD_FL_DRIVERFS;
+	gd->flags = GENHD_FL_EXT_DEVT | GENHD_FL_DRIVERFS;
 	if (sdp->removable)
 		gd->flags |= GENHD_FL_REMOVABLE;
 
diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c
index 661f9f2..ba9b9bb 100644
--- a/drivers/scsi/sg.c
+++ b/drivers/scsi/sg.c
@@ -47,7 +47,6 @@
 #include <linux/seq_file.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
-#include <linux/scatterlist.h>
 #include <linux/blktrace_api.h>
 #include <linux/smp_lock.h>
 
@@ -69,7 +68,6 @@
 #endif
 
 #define SG_ALLOW_DIO_DEF 0
-#define SG_ALLOW_DIO_CODE /* compile out by commenting this define */
 
 #define SG_MAX_DEVS 32768
 
@@ -118,8 +116,8 @@
 	unsigned short k_use_sg; /* Count of kernel scatter-gather pieces */
 	unsigned sglist_len; /* size of malloc'd scatter-gather list ++ */
 	unsigned bufflen;	/* Size of (aggregate) data buffer */
-	unsigned b_malloc_len;	/* actual len malloc'ed in buffer */
-	struct scatterlist *buffer;/* scatter list */
+	struct page **pages;
+	int page_order;
 	char dio_in_use;	/* 0->indirect IO (or mmap), 1->dio */
 	unsigned char cmd_opcode; /* first byte of command */
 } Sg_scatter_hold;
@@ -137,6 +135,8 @@
 	char orphan;		/* 1 -> drop on sight, 0 -> normal */
 	char sg_io_owned;	/* 1 -> packet belongs to SG_IO */
 	volatile char done;	/* 0->before bh, 1->before read, 2->read */
+	struct request *rq;
+	struct bio *bio;
 } Sg_request;
 
 typedef struct sg_fd {		/* holds the state of a file descriptor */
@@ -175,8 +175,8 @@
 
 static int sg_fasync(int fd, struct file *filp, int mode);
 /* tasklet or soft irq callback */
-static void sg_cmd_done(void *data, char *sense, int result, int resid);
-static int sg_start_req(Sg_request * srp);
+static void sg_rq_end_io(struct request *rq, int uptodate);
+static int sg_start_req(Sg_request *srp, unsigned char *cmd);
 static void sg_finish_rem_req(Sg_request * srp);
 static int sg_build_indirect(Sg_scatter_hold * schp, Sg_fd * sfp, int buff_size);
 static int sg_build_sgat(Sg_scatter_hold * schp, const Sg_fd * sfp,
@@ -188,17 +188,11 @@
 			int read_only, Sg_request **o_srp);
 static int sg_common_write(Sg_fd * sfp, Sg_request * srp,
 			   unsigned char *cmnd, int timeout, int blocking);
-static int sg_u_iovec(sg_io_hdr_t * hp, int sg_num, int ind,
-		      int wr_xf, int *countp, unsigned char __user **up);
-static int sg_write_xfer(Sg_request * srp);
-static int sg_read_xfer(Sg_request * srp);
 static int sg_read_oxfer(Sg_request * srp, char __user *outp, int num_read_xfer);
 static void sg_remove_scat(Sg_scatter_hold * schp);
 static void sg_build_reserve(Sg_fd * sfp, int req_size);
 static void sg_link_reserve(Sg_fd * sfp, Sg_request * srp, int size);
 static void sg_unlink_reserve(Sg_fd * sfp, Sg_request * srp);
-static struct page *sg_page_malloc(int rqSz, int lowDma, int *retSzp);
-static void sg_page_free(struct page *page, int size);
 static Sg_fd *sg_add_sfp(Sg_device * sdp, int dev);
 static int sg_remove_sfp(Sg_device * sdp, Sg_fd * sfp);
 static void __sg_remove_sfp(Sg_device * sdp, Sg_fd * sfp);
@@ -206,7 +200,6 @@
 static Sg_request *sg_add_request(Sg_fd * sfp);
 static int sg_remove_request(Sg_fd * sfp, Sg_request * srp);
 static int sg_res_in_use(Sg_fd * sfp);
-static int sg_build_direct(Sg_request * srp, Sg_fd * sfp, int dxfer_len);
 static Sg_device *sg_get_dev(int dev);
 #ifdef CONFIG_SCSI_PROC_FS
 static int sg_last_dev(void);
@@ -529,8 +522,7 @@
 		err = -EFAULT;
 		goto err_out;
 	}
-	err = sg_read_xfer(srp);
-      err_out:
+err_out:
 	sg_finish_rem_req(srp);
 	return (0 == err) ? count : err;
 }
@@ -612,7 +604,10 @@
 	else
 		hp->dxfer_direction = (mxsize > 0) ? SG_DXFER_FROM_DEV : SG_DXFER_NONE;
 	hp->dxfer_len = mxsize;
-	hp->dxferp = (char __user *)buf + cmd_size;
+	if (hp->dxfer_direction == SG_DXFER_TO_DEV)
+		hp->dxferp = (char __user *)buf + cmd_size;
+	else
+		hp->dxferp = NULL;
 	hp->sbp = NULL;
 	hp->timeout = old_hdr.reply_len;	/* structure abuse ... */
 	hp->flags = input_size;	/* structure abuse ... */
@@ -732,16 +727,12 @@
 	SCSI_LOG_TIMEOUT(4, printk("sg_common_write:  scsi opcode=0x%02x, cmd_size=%d\n",
 			  (int) cmnd[0], (int) hp->cmd_len));
 
-	if ((k = sg_start_req(srp))) {
+	k = sg_start_req(srp, cmnd);
+	if (k) {
 		SCSI_LOG_TIMEOUT(1, printk("sg_common_write: start_req err=%d\n", k));
 		sg_finish_rem_req(srp);
 		return k;	/* probably out of space --> ENOMEM */
 	}
-	if ((k = sg_write_xfer(srp))) {
-		SCSI_LOG_TIMEOUT(1, printk("sg_common_write: write_xfer, bad address\n"));
-		sg_finish_rem_req(srp);
-		return k;
-	}
 	if (sdp->detached) {
 		sg_finish_rem_req(srp);
 		return -ENODEV;
@@ -763,20 +754,11 @@
 		break;
 	}
 	hp->duration = jiffies_to_msecs(jiffies);
-/* Now send everything of to mid-level. The next time we hear about this
-   packet is when sg_cmd_done() is called (i.e. a callback). */
-	if (scsi_execute_async(sdp->device, cmnd, hp->cmd_len, data_dir, srp->data.buffer,
-				hp->dxfer_len, srp->data.k_use_sg, timeout,
-				SG_DEFAULT_RETRIES, srp, sg_cmd_done,
-				GFP_ATOMIC)) {
-		SCSI_LOG_TIMEOUT(1, printk("sg_common_write: scsi_execute_async failed\n"));
-		/*
-		 * most likely out of mem, but could also be a bad map
-		 */
-		sg_finish_rem_req(srp);
-		return -ENOMEM;
-	} else
-		return 0;
+
+	srp->rq->timeout = timeout;
+	blk_execute_rq_nowait(sdp->device->request_queue, sdp->disk,
+			      srp->rq, 1, sg_rq_end_io);
+	return 0;
 }
 
 static int
@@ -1192,8 +1174,7 @@
 	Sg_fd *sfp;
 	unsigned long offset, len, sa;
 	Sg_scatter_hold *rsv_schp;
-	struct scatterlist *sg;
-	int k;
+	int k, length;
 
 	if ((NULL == vma) || (!(sfp = (Sg_fd *) vma->vm_private_data)))
 		return VM_FAULT_SIGBUS;
@@ -1203,15 +1184,14 @@
 		return VM_FAULT_SIGBUS;
 	SCSI_LOG_TIMEOUT(3, printk("sg_vma_fault: offset=%lu, scatg=%d\n",
 				   offset, rsv_schp->k_use_sg));
-	sg = rsv_schp->buffer;
 	sa = vma->vm_start;
-	for (k = 0; (k < rsv_schp->k_use_sg) && (sa < vma->vm_end);
-	     ++k, sg = sg_next(sg)) {
+	length = 1 << (PAGE_SHIFT + rsv_schp->page_order);
+	for (k = 0; k < rsv_schp->k_use_sg && sa < vma->vm_end; k++) {
 		len = vma->vm_end - sa;
-		len = (len < sg->length) ? len : sg->length;
+		len = (len < length) ? len : length;
 		if (offset < len) {
-			struct page *page;
-			page = virt_to_page(page_address(sg_page(sg)) + offset);
+			struct page *page = nth_page(rsv_schp->pages[k],
+						     offset >> PAGE_SHIFT);
 			get_page(page);	/* increment page count */
 			vmf->page = page;
 			return 0; /* success */
@@ -1233,8 +1213,7 @@
 	Sg_fd *sfp;
 	unsigned long req_sz, len, sa;
 	Sg_scatter_hold *rsv_schp;
-	int k;
-	struct scatterlist *sg;
+	int k, length;
 
 	if ((!filp) || (!vma) || (!(sfp = (Sg_fd *) filp->private_data)))
 		return -ENXIO;
@@ -1248,11 +1227,10 @@
 		return -ENOMEM;	/* cannot map more than reserved buffer */
 
 	sa = vma->vm_start;
-	sg = rsv_schp->buffer;
-	for (k = 0; (k < rsv_schp->k_use_sg) && (sa < vma->vm_end);
-	     ++k, sg = sg_next(sg)) {
+	length = 1 << (PAGE_SHIFT + rsv_schp->page_order);
+	for (k = 0; k < rsv_schp->k_use_sg && sa < vma->vm_end; k++) {
 		len = vma->vm_end - sa;
-		len = (len < sg->length) ? len : sg->length;
+		len = (len < length) ? len : length;
 		sa += len;
 	}
 
@@ -1263,16 +1241,19 @@
 	return 0;
 }
 
-/* This function is a "bottom half" handler that is called by the
- * mid level when a command is completed (or has failed). */
-static void
-sg_cmd_done(void *data, char *sense, int result, int resid)
+/*
+ * This function is a "bottom half" handler that is called by the mid
+ * level when a command is completed (or has failed).
+ */
+static void sg_rq_end_io(struct request *rq, int uptodate)
 {
-	Sg_request *srp = data;
+	struct sg_request *srp = rq->end_io_data;
 	Sg_device *sdp = NULL;
 	Sg_fd *sfp;
 	unsigned long iflags;
 	unsigned int ms;
+	char *sense;
+	int result, resid;
 
 	if (NULL == srp) {
 		printk(KERN_ERR "sg_cmd_done: NULL request\n");
@@ -1286,6 +1267,9 @@
 		return;
 	}
 
+	sense = rq->sense;
+	result = rq->errors;
+	resid = rq->data_len;
 
 	SCSI_LOG_TIMEOUT(4, printk("sg_cmd_done: %s, pack_id=%d, res=0x%x\n",
 		sdp->disk->disk_name, srp->header.pack_id, result));
@@ -1296,7 +1280,6 @@
 	if (0 != result) {
 		struct scsi_sense_hdr sshdr;
 
-		memcpy(srp->sense_b, sense, sizeof (srp->sense_b));
 		srp->header.status = 0xff & result;
 		srp->header.masked_status = status_byte(result);
 		srp->header.msg_status = msg_byte(result);
@@ -1634,37 +1617,79 @@
 	idr_destroy(&sg_index_idr);
 }
 
-static int
-sg_start_req(Sg_request * srp)
+static int sg_start_req(Sg_request *srp, unsigned char *cmd)
 {
 	int res;
+	struct request *rq;
 	Sg_fd *sfp = srp->parentfp;
 	sg_io_hdr_t *hp = &srp->header;
 	int dxfer_len = (int) hp->dxfer_len;
 	int dxfer_dir = hp->dxfer_direction;
+	unsigned int iov_count = hp->iovec_count;
 	Sg_scatter_hold *req_schp = &srp->data;
 	Sg_scatter_hold *rsv_schp = &sfp->reserve;
+	struct request_queue *q = sfp->parentdp->device->request_queue;
+	struct rq_map_data *md, map_data;
+	int rw = hp->dxfer_direction == SG_DXFER_TO_DEV ? WRITE : READ;
 
-	SCSI_LOG_TIMEOUT(4, printk("sg_start_req: dxfer_len=%d\n", dxfer_len));
+	SCSI_LOG_TIMEOUT(4, printk(KERN_INFO "sg_start_req: dxfer_len=%d\n",
+				   dxfer_len));
+
+	rq = blk_get_request(q, rw, GFP_ATOMIC);
+	if (!rq)
+		return -ENOMEM;
+
+	memcpy(rq->cmd, cmd, hp->cmd_len);
+
+	rq->cmd_len = hp->cmd_len;
+	rq->cmd_type = REQ_TYPE_BLOCK_PC;
+
+	srp->rq = rq;
+	rq->end_io_data = srp;
+	rq->sense = srp->sense_b;
+	rq->retries = SG_DEFAULT_RETRIES;
+
 	if ((dxfer_len <= 0) || (dxfer_dir == SG_DXFER_NONE))
 		return 0;
-	if (sg_allow_dio && (hp->flags & SG_FLAG_DIRECT_IO) &&
-	    (dxfer_dir != SG_DXFER_UNKNOWN) && (0 == hp->iovec_count) &&
-	    (!sfp->parentdp->device->host->unchecked_isa_dma)) {
-		res = sg_build_direct(srp, sfp, dxfer_len);
-		if (res <= 0)	/* -ve -> error, 0 -> done, 1 -> try indirect */
-			return res;
+
+	if (sg_allow_dio && hp->flags & SG_FLAG_DIRECT_IO &&
+	    dxfer_dir != SG_DXFER_UNKNOWN && !iov_count &&
+	    !sfp->parentdp->device->host->unchecked_isa_dma &&
+	    blk_rq_aligned(q, hp->dxferp, dxfer_len))
+		md = NULL;
+	else
+		md = &map_data;
+
+	if (md) {
+		if (!sg_res_in_use(sfp) && dxfer_len <= rsv_schp->bufflen)
+			sg_link_reserve(sfp, srp, dxfer_len);
+		else {
+			res = sg_build_indirect(req_schp, sfp, dxfer_len);
+			if (res)
+				return res;
+		}
+
+		md->pages = req_schp->pages;
+		md->page_order = req_schp->page_order;
+		md->nr_entries = req_schp->k_use_sg;
 	}
-	if ((!sg_res_in_use(sfp)) && (dxfer_len <= rsv_schp->bufflen))
-		sg_link_reserve(sfp, srp, dxfer_len);
-	else {
-		res = sg_build_indirect(req_schp, sfp, dxfer_len);
-		if (res) {
-			sg_remove_scat(req_schp);
-			return res;
+
+	if (iov_count)
+		res = blk_rq_map_user_iov(q, rq, md, hp->dxferp, iov_count,
+					  hp->dxfer_len, GFP_ATOMIC);
+	else
+		res = blk_rq_map_user(q, rq, md, hp->dxferp,
+				      hp->dxfer_len, GFP_ATOMIC);
+
+	if (!res) {
+		srp->bio = rq->bio;
+
+		if (!md) {
+			req_schp->dio_in_use = 1;
+			hp->info |= SG_INFO_DIRECT_IO;
 		}
 	}
-	return 0;
+	return res;
 }
 
 static void
@@ -1678,186 +1703,37 @@
 		sg_unlink_reserve(sfp, srp);
 	else
 		sg_remove_scat(req_schp);
+
+	if (srp->rq) {
+		if (srp->bio)
+			blk_rq_unmap_user(srp->bio);
+
+		blk_put_request(srp->rq);
+	}
+
 	sg_remove_request(sfp, srp);
 }
 
 static int
 sg_build_sgat(Sg_scatter_hold * schp, const Sg_fd * sfp, int tablesize)
 {
-	int sg_bufflen = tablesize * sizeof(struct scatterlist);
+	int sg_bufflen = tablesize * sizeof(struct page *);
 	gfp_t gfp_flags = GFP_ATOMIC | __GFP_NOWARN;
 
-	/*
-	 * TODO: test without low_dma, we should not need it since
-	 * the block layer will bounce the buffer for us
-	 *
-	 * XXX(hch): we shouldn't need GFP_DMA for the actual S/G list.
-	 */
-	if (sfp->low_dma)
-		 gfp_flags |= GFP_DMA;
-	schp->buffer = kzalloc(sg_bufflen, gfp_flags);
-	if (!schp->buffer)
+	schp->pages = kzalloc(sg_bufflen, gfp_flags);
+	if (!schp->pages)
 		return -ENOMEM;
-	sg_init_table(schp->buffer, tablesize);
 	schp->sglist_len = sg_bufflen;
 	return tablesize;	/* number of scat_gath elements allocated */
 }
 
-#ifdef SG_ALLOW_DIO_CODE
-/* vvvvvvvv  following code borrowed from st driver's direct IO vvvvvvvvv */
-	/* TODO: hopefully we can use the generic block layer code */
-
-/* Pin down user pages and put them into a scatter gather list. Returns <= 0 if
-   - mapping of all pages not successful
-   (i.e., either completely successful or fails)
-*/
-static int 
-st_map_user_pages(struct scatterlist *sgl, const unsigned int max_pages, 
-	          unsigned long uaddr, size_t count, int rw)
-{
-	unsigned long end = (uaddr + count + PAGE_SIZE - 1) >> PAGE_SHIFT;
-	unsigned long start = uaddr >> PAGE_SHIFT;
-	const int nr_pages = end - start;
-	int res, i, j;
-	struct page **pages;
-
-	/* User attempted Overflow! */
-	if ((uaddr + count) < uaddr)
-		return -EINVAL;
-
-	/* Too big */
-        if (nr_pages > max_pages)
-		return -ENOMEM;
-
-	/* Hmm? */
-	if (count == 0)
-		return 0;
-
-	if ((pages = kmalloc(max_pages * sizeof(*pages), GFP_ATOMIC)) == NULL)
-		return -ENOMEM;
-
-        /* Try to fault in all of the necessary pages */
-	down_read(&current->mm->mmap_sem);
-        /* rw==READ means read from drive, write into memory area */
-	res = get_user_pages(
-		current,
-		current->mm,
-		uaddr,
-		nr_pages,
-		rw == READ,
-		0, /* don't force */
-		pages,
-		NULL);
-	up_read(&current->mm->mmap_sem);
-
-	/* Errors and no page mapped should return here */
-	if (res < nr_pages)
-		goto out_unmap;
-
-        for (i=0; i < nr_pages; i++) {
-                /* FIXME: flush superflous for rw==READ,
-                 * probably wrong function for rw==WRITE
-                 */
-		flush_dcache_page(pages[i]);
-		/* ?? Is locking needed? I don't think so */
-		/* if (!trylock_page(pages[i]))
-		   goto out_unlock; */
-        }
-
-	sg_set_page(sgl, pages[0], 0, uaddr & ~PAGE_MASK);
-	if (nr_pages > 1) {
-		sgl[0].length = PAGE_SIZE - sgl[0].offset;
-		count -= sgl[0].length;
-		for (i=1; i < nr_pages ; i++)
-			sg_set_page(&sgl[i], pages[i], count < PAGE_SIZE ? count : PAGE_SIZE, 0);
-	}
-	else {
-		sgl[0].length = count;
-	}
-
-	kfree(pages);
-	return nr_pages;
-
- out_unmap:
-	if (res > 0) {
-		for (j=0; j < res; j++)
-			page_cache_release(pages[j]);
-		res = 0;
-	}
-	kfree(pages);
-	return res;
-}
-
-
-/* And unmap them... */
-static int 
-st_unmap_user_pages(struct scatterlist *sgl, const unsigned int nr_pages,
-		    int dirtied)
-{
-	int i;
-
-	for (i=0; i < nr_pages; i++) {
-		struct page *page = sg_page(&sgl[i]);
-
-		if (dirtied)
-			SetPageDirty(page);
-		/* unlock_page(page); */
-		/* FIXME: cache flush missing for rw==READ
-		 * FIXME: call the correct reference counting function
-		 */
-		page_cache_release(page);
-	}
-
-	return 0;
-}
-
-/* ^^^^^^^^  above code borrowed from st driver's direct IO ^^^^^^^^^ */
-#endif
-
-
-/* Returns: -ve -> error, 0 -> done, 1 -> try indirect */
-static int
-sg_build_direct(Sg_request * srp, Sg_fd * sfp, int dxfer_len)
-{
-#ifdef SG_ALLOW_DIO_CODE
-	sg_io_hdr_t *hp = &srp->header;
-	Sg_scatter_hold *schp = &srp->data;
-	int sg_tablesize = sfp->parentdp->sg_tablesize;
-	int mx_sc_elems, res;
-	struct scsi_device *sdev = sfp->parentdp->device;
-
-	if (((unsigned long)hp->dxferp &
-			queue_dma_alignment(sdev->request_queue)) != 0)
-		return 1;
-
-	mx_sc_elems = sg_build_sgat(schp, sfp, sg_tablesize);
-        if (mx_sc_elems <= 0) {
-                return 1;
-        }
-	res = st_map_user_pages(schp->buffer, mx_sc_elems,
-				(unsigned long)hp->dxferp, dxfer_len, 
-				(SG_DXFER_TO_DEV == hp->dxfer_direction) ? 1 : 0);
-	if (res <= 0) {
-		sg_remove_scat(schp);
-		return 1;
-	}
-	schp->k_use_sg = res;
-	schp->dio_in_use = 1;
-	hp->info |= SG_INFO_DIRECT_IO;
-	return 0;
-#else
-	return 1;
-#endif
-}
-
 static int
 sg_build_indirect(Sg_scatter_hold * schp, Sg_fd * sfp, int buff_size)
 {
-	struct scatterlist *sg;
-	int ret_sz = 0, k, rem_sz, num, mx_sc_elems;
+	int ret_sz = 0, i, k, rem_sz, num, mx_sc_elems;
 	int sg_tablesize = sfp->parentdp->sg_tablesize;
-	int blk_size = buff_size;
-	struct page *p = NULL;
+	int blk_size = buff_size, order;
+	gfp_t gfp_mask = GFP_ATOMIC | __GFP_COMP | __GFP_NOWARN;
 
 	if (blk_size < 0)
 		return -EFAULT;
@@ -1881,15 +1757,26 @@
 		} else
 			scatter_elem_sz_prev = num;
 	}
-	for (k = 0, sg = schp->buffer, rem_sz = blk_size;
-	     (rem_sz > 0) && (k < mx_sc_elems);
-	     ++k, rem_sz -= ret_sz, sg = sg_next(sg)) {
-		
+
+	if (sfp->low_dma)
+		gfp_mask |= GFP_DMA;
+
+	if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
+		gfp_mask |= __GFP_ZERO;
+
+	order = get_order(num);
+retry:
+	ret_sz = 1 << (PAGE_SHIFT + order);
+
+	for (k = 0, rem_sz = blk_size; rem_sz > 0 && k < mx_sc_elems;
+	     k++, rem_sz -= ret_sz) {
+
 		num = (rem_sz > scatter_elem_sz_prev) ?
-		      scatter_elem_sz_prev : rem_sz;
-		p = sg_page_malloc(num, sfp->low_dma, &ret_sz);
-		if (!p)
-			return -ENOMEM;
+			scatter_elem_sz_prev : rem_sz;
+
+		schp->pages[k] = alloc_pages(gfp_mask, order);
+		if (!schp->pages[k])
+			goto out;
 
 		if (num == scatter_elem_sz_prev) {
 			if (unlikely(ret_sz > scatter_elem_sz_prev)) {
@@ -1897,12 +1784,12 @@
 				scatter_elem_sz_prev = ret_sz;
 			}
 		}
-		sg_set_page(sg, p, (ret_sz > num) ? num : ret_sz, 0);
 
 		SCSI_LOG_TIMEOUT(5, printk("sg_build_indirect: k=%d, num=%d, "
 				 "ret_sz=%d\n", k, num, ret_sz));
 	}		/* end of for loop */
 
+	schp->page_order = order;
 	schp->k_use_sg = k;
 	SCSI_LOG_TIMEOUT(5, printk("sg_build_indirect: k_use_sg=%d, "
 			 "rem_sz=%d\n", k, rem_sz));
@@ -1910,223 +1797,42 @@
 	schp->bufflen = blk_size;
 	if (rem_sz > 0)	/* must have failed */
 		return -ENOMEM;
-
 	return 0;
-}
+out:
+	for (i = 0; i < k; i++)
+		__free_pages(schp->pages[k], order);
 
-static int
-sg_write_xfer(Sg_request * srp)
-{
-	sg_io_hdr_t *hp = &srp->header;
-	Sg_scatter_hold *schp = &srp->data;
-	struct scatterlist *sg = schp->buffer;
-	int num_xfer = 0;
-	int j, k, onum, usglen, ksglen, res;
-	int iovec_count = (int) hp->iovec_count;
-	int dxfer_dir = hp->dxfer_direction;
-	unsigned char *p;
-	unsigned char __user *up;
-	int new_interface = ('\0' == hp->interface_id) ? 0 : 1;
+	if (--order >= 0)
+		goto retry;
 
-	if ((SG_DXFER_UNKNOWN == dxfer_dir) || (SG_DXFER_TO_DEV == dxfer_dir) ||
-	    (SG_DXFER_TO_FROM_DEV == dxfer_dir)) {
-		num_xfer = (int) (new_interface ? hp->dxfer_len : hp->flags);
-		if (schp->bufflen < num_xfer)
-			num_xfer = schp->bufflen;
-	}
-	if ((num_xfer <= 0) || (schp->dio_in_use) ||
-	    (new_interface
-	     && ((SG_FLAG_NO_DXFER | SG_FLAG_MMAP_IO) & hp->flags)))
-		return 0;
-
-	SCSI_LOG_TIMEOUT(4, printk("sg_write_xfer: num_xfer=%d, iovec_count=%d, k_use_sg=%d\n",
-			  num_xfer, iovec_count, schp->k_use_sg));
-	if (iovec_count) {
-		onum = iovec_count;
-		if (!access_ok(VERIFY_READ, hp->dxferp, SZ_SG_IOVEC * onum))
-			return -EFAULT;
-	} else
-		onum = 1;
-
-	ksglen = sg->length;
-	p = page_address(sg_page(sg));
-	for (j = 0, k = 0; j < onum; ++j) {
-		res = sg_u_iovec(hp, iovec_count, j, 1, &usglen, &up);
-		if (res)
-			return res;
-
-		for (; p; sg = sg_next(sg), ksglen = sg->length,
-		     p = page_address(sg_page(sg))) {
-			if (usglen <= 0)
-				break;
-			if (ksglen > usglen) {
-				if (usglen >= num_xfer) {
-					if (__copy_from_user(p, up, num_xfer))
-						return -EFAULT;
-					return 0;
-				}
-				if (__copy_from_user(p, up, usglen))
-					return -EFAULT;
-				p += usglen;
-				ksglen -= usglen;
-				break;
-			} else {
-				if (ksglen >= num_xfer) {
-					if (__copy_from_user(p, up, num_xfer))
-						return -EFAULT;
-					return 0;
-				}
-				if (__copy_from_user(p, up, ksglen))
-					return -EFAULT;
-				up += ksglen;
-				usglen -= ksglen;
-			}
-			++k;
-			if (k >= schp->k_use_sg)
-				return 0;
-		}
-	}
-
-	return 0;
-}
-
-static int
-sg_u_iovec(sg_io_hdr_t * hp, int sg_num, int ind,
-	   int wr_xf, int *countp, unsigned char __user **up)
-{
-	int num_xfer = (int) hp->dxfer_len;
-	unsigned char __user *p = hp->dxferp;
-	int count;
-
-	if (0 == sg_num) {
-		if (wr_xf && ('\0' == hp->interface_id))
-			count = (int) hp->flags;	/* holds "old" input_size */
-		else
-			count = num_xfer;
-	} else {
-		sg_iovec_t iovec;
-		if (__copy_from_user(&iovec, p + ind*SZ_SG_IOVEC, SZ_SG_IOVEC))
-			return -EFAULT;
-		p = iovec.iov_base;
-		count = (int) iovec.iov_len;
-	}
-	if (!access_ok(wr_xf ? VERIFY_READ : VERIFY_WRITE, p, count))
-		return -EFAULT;
-	if (up)
-		*up = p;
-	if (countp)
-		*countp = count;
-	return 0;
+	return -ENOMEM;
 }
 
 static void
 sg_remove_scat(Sg_scatter_hold * schp)
 {
 	SCSI_LOG_TIMEOUT(4, printk("sg_remove_scat: k_use_sg=%d\n", schp->k_use_sg));
-	if (schp->buffer && (schp->sglist_len > 0)) {
-		struct scatterlist *sg = schp->buffer;
-
-		if (schp->dio_in_use) {
-#ifdef SG_ALLOW_DIO_CODE
-			st_unmap_user_pages(sg, schp->k_use_sg, TRUE);
-#endif
-		} else {
+	if (schp->pages && schp->sglist_len > 0) {
+		if (!schp->dio_in_use) {
 			int k;
 
-			for (k = 0; (k < schp->k_use_sg) && sg_page(sg);
-			     ++k, sg = sg_next(sg)) {
+			for (k = 0; k < schp->k_use_sg && schp->pages[k]; k++) {
 				SCSI_LOG_TIMEOUT(5, printk(
-				    "sg_remove_scat: k=%d, pg=0x%p, len=%d\n",
-				    k, sg_page(sg), sg->length));
-				sg_page_free(sg_page(sg), sg->length);
+				    "sg_remove_scat: k=%d, pg=0x%p\n",
+				    k, schp->pages[k]));
+				__free_pages(schp->pages[k], schp->page_order);
 			}
+
+			kfree(schp->pages);
 		}
-		kfree(schp->buffer);
 	}
 	memset(schp, 0, sizeof (*schp));
 }
 
 static int
-sg_read_xfer(Sg_request * srp)
-{
-	sg_io_hdr_t *hp = &srp->header;
-	Sg_scatter_hold *schp = &srp->data;
-	struct scatterlist *sg = schp->buffer;
-	int num_xfer = 0;
-	int j, k, onum, usglen, ksglen, res;
-	int iovec_count = (int) hp->iovec_count;
-	int dxfer_dir = hp->dxfer_direction;
-	unsigned char *p;
-	unsigned char __user *up;
-	int new_interface = ('\0' == hp->interface_id) ? 0 : 1;
-
-	if ((SG_DXFER_UNKNOWN == dxfer_dir) || (SG_DXFER_FROM_DEV == dxfer_dir)
-	    || (SG_DXFER_TO_FROM_DEV == dxfer_dir)) {
-		num_xfer = hp->dxfer_len;
-		if (schp->bufflen < num_xfer)
-			num_xfer = schp->bufflen;
-	}
-	if ((num_xfer <= 0) || (schp->dio_in_use) ||
-	    (new_interface
-	     && ((SG_FLAG_NO_DXFER | SG_FLAG_MMAP_IO) & hp->flags)))
-		return 0;
-
-	SCSI_LOG_TIMEOUT(4, printk("sg_read_xfer: num_xfer=%d, iovec_count=%d, k_use_sg=%d\n",
-			  num_xfer, iovec_count, schp->k_use_sg));
-	if (iovec_count) {
-		onum = iovec_count;
-		if (!access_ok(VERIFY_READ, hp->dxferp, SZ_SG_IOVEC * onum))
-			return -EFAULT;
-	} else
-		onum = 1;
-
-	p = page_address(sg_page(sg));
-	ksglen = sg->length;
-	for (j = 0, k = 0; j < onum; ++j) {
-		res = sg_u_iovec(hp, iovec_count, j, 0, &usglen, &up);
-		if (res)
-			return res;
-
-		for (; p; sg = sg_next(sg), ksglen = sg->length,
-		     p = page_address(sg_page(sg))) {
-			if (usglen <= 0)
-				break;
-			if (ksglen > usglen) {
-				if (usglen >= num_xfer) {
-					if (__copy_to_user(up, p, num_xfer))
-						return -EFAULT;
-					return 0;
-				}
-				if (__copy_to_user(up, p, usglen))
-					return -EFAULT;
-				p += usglen;
-				ksglen -= usglen;
-				break;
-			} else {
-				if (ksglen >= num_xfer) {
-					if (__copy_to_user(up, p, num_xfer))
-						return -EFAULT;
-					return 0;
-				}
-				if (__copy_to_user(up, p, ksglen))
-					return -EFAULT;
-				up += ksglen;
-				usglen -= ksglen;
-			}
-			++k;
-			if (k >= schp->k_use_sg)
-				return 0;
-		}
-	}
-
-	return 0;
-}
-
-static int
 sg_read_oxfer(Sg_request * srp, char __user *outp, int num_read_xfer)
 {
 	Sg_scatter_hold *schp = &srp->data;
-	struct scatterlist *sg = schp->buffer;
 	int k, num;
 
 	SCSI_LOG_TIMEOUT(4, printk("sg_read_oxfer: num_read_xfer=%d\n",
@@ -2134,15 +1840,15 @@
 	if ((!outp) || (num_read_xfer <= 0))
 		return 0;
 
-	for (k = 0; (k < schp->k_use_sg) && sg_page(sg); ++k, sg = sg_next(sg)) {
-		num = sg->length;
+	num = 1 << (PAGE_SHIFT + schp->page_order);
+	for (k = 0; k < schp->k_use_sg && schp->pages[k]; k++) {
 		if (num > num_read_xfer) {
-			if (__copy_to_user(outp, page_address(sg_page(sg)),
+			if (__copy_to_user(outp, page_address(schp->pages[k]),
 					   num_read_xfer))
 				return -EFAULT;
 			break;
 		} else {
-			if (__copy_to_user(outp, page_address(sg_page(sg)),
+			if (__copy_to_user(outp, page_address(schp->pages[k]),
 					   num))
 				return -EFAULT;
 			num_read_xfer -= num;
@@ -2177,24 +1883,21 @@
 {
 	Sg_scatter_hold *req_schp = &srp->data;
 	Sg_scatter_hold *rsv_schp = &sfp->reserve;
-	struct scatterlist *sg = rsv_schp->buffer;
 	int k, num, rem;
 
 	srp->res_used = 1;
 	SCSI_LOG_TIMEOUT(4, printk("sg_link_reserve: size=%d\n", size));
 	rem = size;
 
-	for (k = 0; k < rsv_schp->k_use_sg; ++k, sg = sg_next(sg)) {
-		num = sg->length;
+	num = 1 << (PAGE_SHIFT + rsv_schp->page_order);
+	for (k = 0; k < rsv_schp->k_use_sg; k++) {
 		if (rem <= num) {
-			sfp->save_scat_len = num;
-			sg->length = rem;
 			req_schp->k_use_sg = k + 1;
 			req_schp->sglist_len = rsv_schp->sglist_len;
-			req_schp->buffer = rsv_schp->buffer;
+			req_schp->pages = rsv_schp->pages;
 
 			req_schp->bufflen = size;
-			req_schp->b_malloc_len = rsv_schp->b_malloc_len;
+			req_schp->page_order = rsv_schp->page_order;
 			break;
 		} else
 			rem -= num;
@@ -2208,22 +1911,13 @@
 sg_unlink_reserve(Sg_fd * sfp, Sg_request * srp)
 {
 	Sg_scatter_hold *req_schp = &srp->data;
-	Sg_scatter_hold *rsv_schp = &sfp->reserve;
 
 	SCSI_LOG_TIMEOUT(4, printk("sg_unlink_reserve: req->k_use_sg=%d\n",
 				   (int) req_schp->k_use_sg));
-	if ((rsv_schp->k_use_sg > 0) && (req_schp->k_use_sg > 0)) {
-		struct scatterlist *sg = rsv_schp->buffer;
-
-		if (sfp->save_scat_len > 0)
-			(sg + (req_schp->k_use_sg - 1))->length =
-			    (unsigned) sfp->save_scat_len;
-		else
-			SCSI_LOG_TIMEOUT(1, printk ("sg_unlink_reserve: BAD save_scat_len\n"));
-	}
 	req_schp->k_use_sg = 0;
 	req_schp->bufflen = 0;
-	req_schp->buffer = NULL;
+	req_schp->pages = NULL;
+	req_schp->page_order = 0;
 	req_schp->sglist_len = 0;
 	sfp->save_scat_len = 0;
 	srp->res_used = 0;
@@ -2481,53 +2175,6 @@
 	return srp ? 1 : 0;
 }
 
-/* The size fetched (value output via retSzp) set when non-NULL return */
-static struct page *
-sg_page_malloc(int rqSz, int lowDma, int *retSzp)
-{
-	struct page *resp = NULL;
-	gfp_t page_mask;
-	int order, a_size;
-	int resSz;
-
-	if ((rqSz <= 0) || (NULL == retSzp))
-		return resp;
-
-	if (lowDma)
-		page_mask = GFP_ATOMIC | GFP_DMA | __GFP_COMP | __GFP_NOWARN;
-	else
-		page_mask = GFP_ATOMIC | __GFP_COMP | __GFP_NOWARN;
-
-	for (order = 0, a_size = PAGE_SIZE; a_size < rqSz;
-	     order++, a_size <<= 1) ;
-	resSz = a_size;		/* rounded up if necessary */
-	resp = alloc_pages(page_mask, order);
-	while ((!resp) && order) {
-		--order;
-		a_size >>= 1;	/* divide by 2, until PAGE_SIZE */
-		resp =  alloc_pages(page_mask, order);	/* try half */
-		resSz = a_size;
-	}
-	if (resp) {
-		if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
-			memset(page_address(resp), 0, resSz);
-		*retSzp = resSz;
-	}
-	return resp;
-}
-
-static void
-sg_page_free(struct page *page, int size)
-{
-	int order, a_size;
-
-	if (!page)
-		return;
-	for (order = 0, a_size = PAGE_SIZE; a_size < size;
-	     order++, a_size <<= 1) ;
-	__free_pages(page, order);
-}
-
 #ifdef CONFIG_SCSI_PROC_FS
 static int
 sg_idr_max_id(int id, void *p, void *data)
diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c
index 27f5bfd..0f17009 100644
--- a/drivers/scsi/sr.c
+++ b/drivers/scsi/sr.c
@@ -331,7 +331,7 @@
 
 static int sr_prep_fn(struct request_queue *q, struct request *rq)
 {
-	int block=0, this_count, s_size, timeout = SR_TIMEOUT;
+	int block = 0, this_count, s_size;
 	struct scsi_cd *cd;
 	struct scsi_cmnd *SCpnt;
 	struct scsi_device *sdp = q->queuedata;
@@ -461,7 +461,6 @@
 	SCpnt->transfersize = cd->device->sector_size;
 	SCpnt->underflow = this_count << 9;
 	SCpnt->allowed = MAX_RETRIES;
-	SCpnt->timeout_per_command = timeout;
 
 	/*
 	 * This indicates that the command is ready from our end to be
@@ -620,6 +619,8 @@
 	disk->fops = &sr_bdops;
 	disk->flags = GENHD_FL_CD;
 
+	blk_queue_rq_timeout(sdev->request_queue, SR_TIMEOUT);
+
 	cd->device = sdev;
 	cd->disk = disk;
 	cd->driver = &sr_template;
@@ -878,7 +879,7 @@
 	struct gendisk *disk = cd->disk;
 
 	spin_lock(&sr_index_lock);
-	clear_bit(disk->first_minor, sr_index_bits);
+	clear_bit(MINOR(disk_devt(disk)), sr_index_bits);
 	spin_unlock(&sr_index_lock);
 
 	unregister_cdrom(&cd->cdi);
diff --git a/drivers/scsi/sun_esp.c b/drivers/scsi/sun_esp.c
index f9cf701..3d73aad 100644
--- a/drivers/scsi/sun_esp.c
+++ b/drivers/scsi/sun_esp.c
@@ -1,6 +1,6 @@
 /* sun_esp.c: ESP front-end for Sparc SBUS systems.
  *
- * Copyright (C) 2007 David S. Miller (davem@davemloft.net)
+ * Copyright (C) 2007, 2008 David S. Miller (davem@davemloft.net)
  */
 
 #include <linux/kernel.h>
@@ -9,79 +9,89 @@
 #include <linux/module.h>
 #include <linux/mm.h>
 #include <linux/init.h>
+#include <linux/dma-mapping.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 
 #include <asm/irq.h>
 #include <asm/io.h>
 #include <asm/dma.h>
 
-#include <asm/sbus.h>
-
 #include <scsi/scsi_host.h>
 
 #include "esp_scsi.h"
 
 #define DRV_MODULE_NAME		"sun_esp"
 #define PFX DRV_MODULE_NAME	": "
-#define DRV_VERSION		"1.000"
-#define DRV_MODULE_RELDATE	"April 19, 2007"
+#define DRV_VERSION		"1.100"
+#define DRV_MODULE_RELDATE	"August 27, 2008"
 
 #define dma_read32(REG) \
 	sbus_readl(esp->dma_regs + (REG))
 #define dma_write32(VAL, REG) \
 	sbus_writel((VAL), esp->dma_regs + (REG))
 
-static int __devinit esp_sbus_find_dma(struct esp *esp, struct sbus_dev *dma_sdev)
+/* DVMA chip revisions */
+enum dvma_rev {
+	dvmarev0,
+	dvmaesc1,
+	dvmarev1,
+	dvmarev2,
+	dvmarev3,
+	dvmarevplus,
+	dvmahme
+};
+
+static int __devinit esp_sbus_setup_dma(struct esp *esp,
+					struct of_device *dma_of)
 {
-	struct sbus_dev *sdev = esp->dev;
-	struct sbus_dma *dma;
+	esp->dma = dma_of;
 
-	if (dma_sdev != NULL) {
-		for_each_dvma(dma) {
-			if (dma->sdev == dma_sdev)
-				break;
-		}
-	} else {
-		for_each_dvma(dma) {
-			if (dma->sdev == NULL)
-				break;
+	esp->dma_regs = of_ioremap(&dma_of->resource[0], 0,
+				   resource_size(&dma_of->resource[0]),
+				   "espdma");
+	if (!esp->dma_regs)
+		return -ENOMEM;
 
-			/* If bus + slot are the same and it has the
-			 * correct OBP name, it's ours.
-			 */
-			if (sdev->bus == dma->sdev->bus &&
-			    sdev->slot == dma->sdev->slot &&
-			    (!strcmp(dma->sdev->prom_name, "dma") ||
-			     !strcmp(dma->sdev->prom_name, "espdma")))
-				break;
-		}
+	switch (dma_read32(DMA_CSR) & DMA_DEVICE_ID) {
+	case DMA_VERS0:
+		esp->dmarev = dvmarev0;
+		break;
+	case DMA_ESCV1:
+		esp->dmarev = dvmaesc1;
+		break;
+	case DMA_VERS1:
+		esp->dmarev = dvmarev1;
+		break;
+	case DMA_VERS2:
+		esp->dmarev = dvmarev2;
+		break;
+	case DMA_VERHME:
+		esp->dmarev = dvmahme;
+		break;
+	case DMA_VERSPLUS:
+		esp->dmarev = dvmarevplus;
+		break;
 	}
 
-	if (dma == NULL) {
-		printk(KERN_ERR PFX "[%s] Cannot find dma.\n",
-		       sdev->ofdev.node->full_name);
-		return -ENODEV;
-	}
-	esp->dma = dma;
-	esp->dma_regs = dma->regs;
-
 	return 0;
 
 }
 
 static int __devinit esp_sbus_map_regs(struct esp *esp, int hme)
 {
-	struct sbus_dev *sdev = esp->dev;
+	struct of_device *op = esp->dev;
 	struct resource *res;
 
 	/* On HME, two reg sets exist, first is DVMA,
 	 * second is ESP registers.
 	 */
 	if (hme)
-		res = &sdev->resource[1];
+		res = &op->resource[1];
 	else
-		res = &sdev->resource[0];
+		res = &op->resource[0];
 
-	esp->regs = sbus_ioremap(res, 0, SBUS_ESP_REG_SIZE, "ESP");
+	esp->regs = of_ioremap(res, 0, SBUS_ESP_REG_SIZE, "ESP");
 	if (!esp->regs)
 		return -ENOMEM;
 
@@ -90,10 +100,11 @@
 
 static int __devinit esp_sbus_map_command_block(struct esp *esp)
 {
-	struct sbus_dev *sdev = esp->dev;
+	struct of_device *op = esp->dev;
 
-	esp->command_block = sbus_alloc_consistent(sdev, 16,
-						   &esp->command_block_dma);
+	esp->command_block = dma_alloc_coherent(&op->dev, 16,
+						&esp->command_block_dma,
+						GFP_ATOMIC);
 	if (!esp->command_block)
 		return -ENOMEM;
 	return 0;
@@ -102,17 +113,18 @@
 static int __devinit esp_sbus_register_irq(struct esp *esp)
 {
 	struct Scsi_Host *host = esp->host;
-	struct sbus_dev *sdev = esp->dev;
+	struct of_device *op = esp->dev;
 
-	host->irq = sdev->irqs[0];
+	host->irq = op->irqs[0];
 	return request_irq(host->irq, scsi_esp_intr, IRQF_SHARED, "ESP", esp);
 }
 
-static void __devinit esp_get_scsi_id(struct esp *esp)
+static void __devinit esp_get_scsi_id(struct esp *esp, struct of_device *espdma)
 {
-	struct sbus_dev *sdev = esp->dev;
-	struct device_node *dp = sdev->ofdev.node;
+	struct of_device *op = esp->dev;
+	struct device_node *dp;
 
+	dp = op->node;
 	esp->scsi_id = of_getintprop_default(dp, "initiator-id", 0xff);
 	if (esp->scsi_id != 0xff)
 		goto done;
@@ -121,13 +133,7 @@
 	if (esp->scsi_id != 0xff)
 		goto done;
 
-	if (!sdev->bus) {
-		/* SUN4 */
-		esp->scsi_id = 7;
-		goto done;
-	}
-
-	esp->scsi_id = of_getintprop_default(sdev->bus->ofdev.node,
+	esp->scsi_id = of_getintprop_default(espdma->node,
 					     "scsi-initiator-id", 7);
 
 done:
@@ -137,9 +143,10 @@
 
 static void __devinit esp_get_differential(struct esp *esp)
 {
-	struct sbus_dev *sdev = esp->dev;
-	struct device_node *dp = sdev->ofdev.node;
+	struct of_device *op = esp->dev;
+	struct device_node *dp;
 
+	dp = op->node;
 	if (of_find_property(dp, "differential", NULL))
 		esp->flags |= ESP_FLAG_DIFFERENTIAL;
 	else
@@ -148,43 +155,36 @@
 
 static void __devinit esp_get_clock_params(struct esp *esp)
 {
-	struct sbus_dev *sdev = esp->dev;
-	struct device_node *dp = sdev->ofdev.node;
-	struct device_node *bus_dp;
+	struct of_device *op = esp->dev;
+	struct device_node *bus_dp, *dp;
 	int fmhz;
 
-	bus_dp = NULL;
-	if (sdev != NULL && sdev->bus != NULL)
-		bus_dp = sdev->bus->ofdev.node;
+	dp = op->node;
+	bus_dp = dp->parent;
 
 	fmhz = of_getintprop_default(dp, "clock-frequency", 0);
 	if (fmhz == 0)
-		fmhz = (!bus_dp) ? 0 :
-			of_getintprop_default(bus_dp, "clock-frequency", 0);
+		fmhz = of_getintprop_default(bus_dp, "clock-frequency", 0);
 
 	esp->cfreq = fmhz;
 }
 
-static void __devinit esp_get_bursts(struct esp *esp, struct sbus_dev *dma)
+static void __devinit esp_get_bursts(struct esp *esp, struct of_device *dma_of)
 {
-	struct sbus_dev *sdev = esp->dev;
-	struct device_node *dp = sdev->ofdev.node;
-	u8 bursts;
+	struct device_node *dma_dp = dma_of->node;
+	struct of_device *op = esp->dev;
+	struct device_node *dp;
+	u8 bursts, val;
 
+	dp = op->node;
 	bursts = of_getintprop_default(dp, "burst-sizes", 0xff);
-	if (dma) {
-		struct device_node *dma_dp = dma->ofdev.node;
-		u8 val = of_getintprop_default(dma_dp, "burst-sizes", 0xff);
-		if (val != 0xff)
-			bursts &= val;
-	}
+	val = of_getintprop_default(dma_dp, "burst-sizes", 0xff);
+	if (val != 0xff)
+		bursts &= val;
 
-	if (sdev->bus) {
-		u8 val = of_getintprop_default(sdev->bus->ofdev.node,
-					       "burst-sizes", 0xff);
-		if (val != 0xff)
-			bursts &= val;
-	}
+	val = of_getintprop_default(dma_dp->parent, "burst-sizes", 0xff);
+	if (val != 0xff)
+		bursts &= val;
 
 	if (bursts == 0xff ||
 	    (bursts & DMA_BURST16) == 0 ||
@@ -194,9 +194,9 @@
 	esp->bursts = bursts;
 }
 
-static void __devinit esp_sbus_get_props(struct esp *esp, struct sbus_dev *espdma)
+static void __devinit esp_sbus_get_props(struct esp *esp, struct of_device *espdma)
 {
-	esp_get_scsi_id(esp);
+	esp_get_scsi_id(esp, espdma);
 	esp_get_differential(esp);
 	esp_get_clock_params(esp);
 	esp_get_bursts(esp, espdma);
@@ -215,25 +215,33 @@
 static dma_addr_t sbus_esp_map_single(struct esp *esp, void *buf,
 				      size_t sz, int dir)
 {
-	return sbus_map_single(esp->dev, buf, sz, dir);
+	struct of_device *op = esp->dev;
+
+	return dma_map_single(&op->dev, buf, sz, dir);
 }
 
 static int sbus_esp_map_sg(struct esp *esp, struct scatterlist *sg,
 				  int num_sg, int dir)
 {
-	return sbus_map_sg(esp->dev, sg, num_sg, dir);
+	struct of_device *op = esp->dev;
+
+	return dma_map_sg(&op->dev, sg, num_sg, dir);
 }
 
 static void sbus_esp_unmap_single(struct esp *esp, dma_addr_t addr,
 				  size_t sz, int dir)
 {
-	sbus_unmap_single(esp->dev, addr, sz, dir);
+	struct of_device *op = esp->dev;
+
+	dma_unmap_single(&op->dev, addr, sz, dir);
 }
 
 static void sbus_esp_unmap_sg(struct esp *esp, struct scatterlist *sg,
 			      int num_sg, int dir)
 {
-	sbus_unmap_sg(esp->dev, sg, num_sg, dir);
+	struct of_device *op = esp->dev;
+
+	dma_unmap_sg(&op->dev, sg, num_sg, dir);
 }
 
 static int sbus_esp_irq_pending(struct esp *esp)
@@ -247,24 +255,26 @@
 {
 	int can_do_burst16, can_do_burst32, can_do_burst64;
 	int can_do_sbus64, lim;
+	struct of_device *op;
 	u32 val;
 
 	can_do_burst16 = (esp->bursts & DMA_BURST16) != 0;
 	can_do_burst32 = (esp->bursts & DMA_BURST32) != 0;
 	can_do_burst64 = 0;
 	can_do_sbus64 = 0;
-	if (sbus_can_dma_64bit(esp->dev))
+	op = esp->dev;
+	if (sbus_can_dma_64bit())
 		can_do_sbus64 = 1;
-	if (sbus_can_burst64(esp->sdev))
+	if (sbus_can_burst64())
 		can_do_burst64 = (esp->bursts & DMA_BURST64) != 0;
 
 	/* Put the DVMA into a known state. */
-	if (esp->dma->revision != dvmahme) {
+	if (esp->dmarev != dvmahme) {
 		val = dma_read32(DMA_CSR);
 		dma_write32(val | DMA_RST_SCSI, DMA_CSR);
 		dma_write32(val & ~DMA_RST_SCSI, DMA_CSR);
 	}
-	switch (esp->dma->revision) {
+	switch (esp->dmarev) {
 	case dvmahme:
 		dma_write32(DMA_RESET_FAS366, DMA_CSR);
 		dma_write32(DMA_RST_SCSI, DMA_CSR);
@@ -282,7 +292,7 @@
 
 		if (can_do_sbus64) {
 			esp->prev_hme_dmacsr |= DMA_SCSI_SBUS64;
-			sbus_set_sbus64(esp->dev, esp->bursts);
+			sbus_set_sbus64(&op->dev, esp->bursts);
 		}
 
 		lim = 1000;
@@ -346,14 +356,14 @@
 	u32 csr;
 	int lim;
 
-	if (esp->dma->revision == dvmahme)
+	if (esp->dmarev == dvmahme)
 		return;
 
 	csr = dma_read32(DMA_CSR);
 	if (!(csr & DMA_FIFO_ISDRAIN))
 		return;
 
-	if (esp->dma->revision != dvmarev3 && esp->dma->revision != dvmaesc1)
+	if (esp->dmarev != dvmarev3 && esp->dmarev != dvmaesc1)
 		dma_write32(csr | DMA_FIFO_STDRAIN, DMA_CSR);
 
 	lim = 1000;
@@ -369,7 +379,7 @@
 
 static void sbus_esp_dma_invalidate(struct esp *esp)
 {
-	if (esp->dma->revision == dvmahme) {
+	if (esp->dmarev == dvmahme) {
 		dma_write32(DMA_RST_SCSI, DMA_CSR);
 
 		esp->prev_hme_dmacsr = ((esp->prev_hme_dmacsr |
@@ -440,7 +450,7 @@
 		else
 			csr &= ~DMA_ST_WRITE;
 		dma_write32(csr, DMA_CSR);
-		if (esp->dma->revision == dvmaesc1) {
+		if (esp->dmarev == dvmaesc1) {
 			u32 end = PAGE_ALIGN(addr + dma_count + 16U);
 			dma_write32(end - addr, DMA_COUNT);
 		}
@@ -476,10 +486,8 @@
 	.dma_error	=	sbus_esp_dma_error,
 };
 
-static int __devinit esp_sbus_probe_one(struct device *dev,
-					struct sbus_dev *esp_dev,
-					struct sbus_dev *espdma,
-					struct sbus_bus *sbus,
+static int __devinit esp_sbus_probe_one(struct of_device *op,
+					struct of_device *espdma,
 					int hme)
 {
 	struct scsi_host_template *tpnt = &scsi_esp_template;
@@ -497,13 +505,13 @@
 	esp = shost_priv(host);
 
 	esp->host = host;
-	esp->dev = esp_dev;
+	esp->dev = op;
 	esp->ops = &sbus_esp_ops;
 
 	if (hme)
 		esp->flags |= ESP_FLAG_WIDE_CAPABLE;
 
-	err = esp_sbus_find_dma(esp, espdma);
+	err = esp_sbus_setup_dma(esp, espdma);
 	if (err < 0)
 		goto fail_unlink;
 
@@ -525,15 +533,15 @@
 	 * come up with the reset bit set, so make sure that
 	 * is clear first.
 	 */
-	if (esp->dma->revision == dvmaesc1) {
+	if (esp->dmarev == dvmaesc1) {
 		u32 val = dma_read32(DMA_CSR);
 
 		dma_write32(val & ~DMA_RST_SCSI, DMA_CSR);
 	}
 
-	dev_set_drvdata(&esp_dev->ofdev.dev, esp);
+	dev_set_drvdata(&op->dev, esp);
 
-	err = scsi_esp_register(esp, dev);
+	err = scsi_esp_register(esp, &op->dev);
 	if (err)
 		goto fail_free_irq;
 
@@ -542,41 +550,46 @@
 fail_free_irq:
 	free_irq(host->irq, esp);
 fail_unmap_command_block:
-	sbus_free_consistent(esp->dev, 16,
-			     esp->command_block,
-			     esp->command_block_dma);
+	dma_free_coherent(&op->dev, 16,
+			  esp->command_block,
+			  esp->command_block_dma);
 fail_unmap_regs:
-	sbus_iounmap(esp->regs, SBUS_ESP_REG_SIZE);
+	of_iounmap(&op->resource[(hme ? 1 : 0)], esp->regs, SBUS_ESP_REG_SIZE);
 fail_unlink:
 	scsi_host_put(host);
 fail:
 	return err;
 }
 
-static int __devinit esp_sbus_probe(struct of_device *dev, const struct of_device_id *match)
+static int __devinit esp_sbus_probe(struct of_device *op, const struct of_device_id *match)
 {
-	struct sbus_dev *sdev = to_sbus_device(&dev->dev);
-	struct device_node *dp = dev->node;
-	struct sbus_dev *dma_sdev = NULL;
+	struct device_node *dma_node = NULL;
+	struct device_node *dp = op->node;
+	struct of_device *dma_of = NULL;
 	int hme = 0;
 
 	if (dp->parent &&
 	    (!strcmp(dp->parent->name, "espdma") ||
 	     !strcmp(dp->parent->name, "dma")))
-		dma_sdev = sdev->parent;
+		dma_node = dp->parent;
 	else if (!strcmp(dp->name, "SUNW,fas")) {
-		dma_sdev = sdev;
+		dma_node = op->node;
 		hme = 1;
 	}
+	if (dma_node)
+		dma_of = of_find_device_by_node(dma_node);
+	if (!dma_of)
+		return -ENODEV;
 
-	return esp_sbus_probe_one(&dev->dev, sdev, dma_sdev,
-				  sdev->bus, hme);
+	return esp_sbus_probe_one(op, dma_of, hme);
 }
 
-static int __devexit esp_sbus_remove(struct of_device *dev)
+static int __devexit esp_sbus_remove(struct of_device *op)
 {
-	struct esp *esp = dev_get_drvdata(&dev->dev);
+	struct esp *esp = dev_get_drvdata(&op->dev);
+	struct of_device *dma_of = esp->dma;
 	unsigned int irq = esp->host->irq;
+	bool is_hme;
 	u32 val;
 
 	scsi_esp_unregister(esp);
@@ -586,17 +599,25 @@
 	dma_write32(val & ~DMA_INT_ENAB, DMA_CSR);
 
 	free_irq(irq, esp);
-	sbus_free_consistent(esp->dev, 16,
-			     esp->command_block,
-			     esp->command_block_dma);
-	sbus_iounmap(esp->regs, SBUS_ESP_REG_SIZE);
+
+	is_hme = (esp->dmarev == dvmahme);
+
+	dma_free_coherent(&op->dev, 16,
+			  esp->command_block,
+			  esp->command_block_dma);
+	of_iounmap(&op->resource[(is_hme ? 1 : 0)], esp->regs,
+		   SBUS_ESP_REG_SIZE);
+	of_iounmap(&dma_of->resource[0], esp->dma_regs,
+		   resource_size(&dma_of->resource[0]));
 
 	scsi_host_put(esp->host);
 
+	dev_set_drvdata(&op->dev, NULL);
+
 	return 0;
 }
 
-static struct of_device_id esp_match[] = {
+static const struct of_device_id esp_match[] = {
 	{
 		.name = "SUNW,esp",
 	},
@@ -619,7 +640,7 @@
 
 static int __init sunesp_init(void)
 {
-	return of_register_driver(&esp_sbus_driver, &sbus_bus_type);
+	return of_register_driver(&esp_sbus_driver, &of_bus_type);
 }
 
 static void __exit sunesp_exit(void)
diff --git a/drivers/scsi/sym53c8xx_2/sym_glue.c b/drivers/scsi/sym53c8xx_2/sym_glue.c
index d39107b..f4e6cde 100644
--- a/drivers/scsi/sym53c8xx_2/sym_glue.c
+++ b/drivers/scsi/sym53c8xx_2/sym_glue.c
@@ -519,8 +519,8 @@
 	 *  Shorten our settle_time if needed for 
 	 *  this command not to time out.
 	 */
-	if (np->s.settle_time_valid && cmd->timeout_per_command) {
-		unsigned long tlimit = jiffies + cmd->timeout_per_command;
+	if (np->s.settle_time_valid && cmd->request->timeout) {
+		unsigned long tlimit = jiffies + cmd->request->timeout;
 		tlimit -= SYM_CONF_TIMER_INTERVAL*2;
 		if (time_after(np->s.settle_time, tlimit)) {
 			np->s.settle_time = tlimit;
diff --git a/drivers/scsi/tmscsim.c b/drivers/scsi/tmscsim.c
index 1723d71..69ac6e5 100644
--- a/drivers/scsi/tmscsim.c
+++ b/drivers/scsi/tmscsim.c
@@ -2573,8 +2573,8 @@
 static int __init dc390_module_init(void)
 {
 	if (!disable_clustering)
-		printk(KERN_INFO "DC390: clustering now enabled by default. If you get problems load\n"
-		       "\twith \"disable_clustering=1\" and report to maintainers\n");
+		printk(KERN_INFO "DC390: clustering now enabled by default. If you get problems load\n");
+		printk(KERN_INFO "       with \"disable_clustering=1\" and report to maintainers\n");
 
 	if (tmscsim[0] == -1 || tmscsim[0] > 15) {
 		tmscsim[0] = 7;
diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c
index 9ccc563..d3ca7d3 100644
--- a/drivers/serial/8250.c
+++ b/drivers/serial/8250.c
@@ -44,6 +44,10 @@
 
 #include "8250.h"
 
+#ifdef CONFIG_SPARC
+#include "suncore.h"
+#endif
+
 /*
  * Configuration:
  *   share_irqs - whether we pass IRQF_SHARED to request_irq().  This option
@@ -53,6 +57,13 @@
 
 static unsigned int nr_uarts = CONFIG_SERIAL_8250_RUNTIME_UARTS;
 
+static struct uart_driver serial8250_reg;
+
+static int serial_index(struct uart_port *port)
+{
+	return (serial8250_reg.minor - 64) + port->line;
+}
+
 /*
  * Debugging.
  */
@@ -536,7 +547,7 @@
 /*
  * FIFO support.
  */
-static inline void serial8250_clear_fifos(struct uart_8250_port *p)
+static void serial8250_clear_fifos(struct uart_8250_port *p)
 {
 	if (p->capabilities & UART_CAP_FIFO) {
 		serial_outp(p, UART_FCR, UART_FCR_ENABLE_FIFO);
@@ -551,7 +562,7 @@
  * capability" bit enabled.  Note that on XR16C850s, we need to
  * reset LCR to write to IER.
  */
-static inline void serial8250_set_sleep(struct uart_8250_port *p, int sleep)
+static void serial8250_set_sleep(struct uart_8250_port *p, int sleep)
 {
 	if (p->capabilities & UART_CAP_SLEEP) {
 		if (p->capabilities & UART_CAP_EFR) {
@@ -993,7 +1004,7 @@
 		return;
 
 	DEBUG_AUTOCONF("ttyS%d: autoconf (0x%04x, 0x%p): ",
-			up->port.line, up->port.iobase, up->port.membase);
+		       serial_index(&up->port), up->port.iobase, up->port.membase);
 
 	/*
 	 * We really do need global IRQs disabled here - we're going to
@@ -1128,8 +1139,8 @@
 	if (up->capabilities != uart_config[up->port.type].flags) {
 		printk(KERN_WARNING
 		       "ttyS%d: detected caps %08x should be %08x\n",
-			up->port.line, up->capabilities,
-			uart_config[up->port.type].flags);
+		       serial_index(&up->port), up->capabilities,
+		       uart_config[up->port.type].flags);
 	}
 
 	up->port.fifosize = uart_config[up->port.type].fifo_size;
@@ -1424,8 +1435,7 @@
 /*
  * This handles the interrupt from one port.
  */
-static inline void
-serial8250_handle_port(struct uart_8250_port *up)
+static void serial8250_handle_port(struct uart_8250_port *up)
 {
 	unsigned int status;
 	unsigned long flags;
@@ -1719,7 +1729,7 @@
 /*
  *	Wait for transmitter & holding register to empty
  */
-static inline void wait_for_xmitr(struct uart_8250_port *up, int bits)
+static void wait_for_xmitr(struct uart_8250_port *up, int bits)
 {
 	unsigned int status, tmout = 10000;
 
@@ -1854,7 +1864,8 @@
 	 */
 	if (!(up->port.flags & UPF_BUGGY_UART) &&
 	    (serial_inp(up, UART_LSR) == 0xff)) {
-		printk("ttyS%d: LSR safety check engaged!\n", up->port.line);
+		printk(KERN_INFO "ttyS%d: LSR safety check engaged!\n",
+		       serial_index(&up->port));
 		return -ENODEV;
 	}
 
@@ -1909,7 +1920,8 @@
 		 */
 		if (!(iir1 & UART_IIR_NO_INT) && (iir & UART_IIR_NO_INT)) {
 			up->bugs |= UART_BUG_THRE;
-			pr_debug("ttyS%d - using backup timer\n", port->line);
+			pr_debug("ttyS%d - using backup timer\n",
+				 serial_index(port));
 		}
 	}
 
@@ -1969,7 +1981,7 @@
 		if (!(up->bugs & UART_BUG_TXEN)) {
 			up->bugs |= UART_BUG_TXEN;
 			pr_debug("ttyS%d - enabling bad tx status workarounds\n",
-				 port->line);
+				 serial_index(port));
 		}
 	} else {
 		up->bugs &= ~UART_BUG_TXEN;
@@ -2630,7 +2642,6 @@
 	return serial8250_find_port_for_earlycon();
 }
 
-static struct uart_driver serial8250_reg;
 static struct console serial8250_console = {
 	.name		= "ttyS",
 	.write		= serial8250_console_write,
@@ -2677,7 +2688,6 @@
 	.dev_name		= "ttyS",
 	.major			= TTY_MAJOR,
 	.minor			= 64,
-	.nr			= UART_NR,
 	.cons			= SERIAL8250_CONSOLE,
 };
 
@@ -2962,7 +2972,12 @@
 	for (i = 0; i < NR_IRQS; i++)
 		spin_lock_init(&irq_lists[i].lock);
 
+#ifdef CONFIG_SPARC
+	ret = sunserial_register_minors(&serial8250_reg, UART_NR);
+#else
+	serial8250_reg.nr = UART_NR;
 	ret = uart_register_driver(&serial8250_reg);
+#endif
 	if (ret)
 		goto out;
 
@@ -2987,7 +3002,11 @@
  put_dev:
 	platform_device_put(serial8250_isa_devs);
  unreg_uart_drv:
+#ifdef CONFIG_SPARC
+	sunserial_unregister_minors(&serial8250_reg, UART_NR);
+#else
 	uart_unregister_driver(&serial8250_reg);
+#endif
  out:
 	return ret;
 }
@@ -3006,7 +3025,11 @@
 	platform_driver_unregister(&serial8250_isa_driver);
 	platform_device_unregister(isa_dev);
 
+#ifdef CONFIG_SPARC
+	sunserial_unregister_minors(&serial8250_reg, UART_NR);
+#else
 	uart_unregister_driver(&serial8250_reg);
+#endif
 }
 
 module_init(serial8250_init);
diff --git a/drivers/serial/8250_pci.c b/drivers/serial/8250_pci.c
index c2f2393..c014ffb1 100644
--- a/drivers/serial/8250_pci.c
+++ b/drivers/serial/8250_pci.c
@@ -2041,9 +2041,9 @@
 		 * The device may have been disabled.  Re-enable it.
 		 */
 		err = pci_enable_device(dev);
+		/* FIXME: We cannot simply error out here */
 		if (err)
-			return err;
-
+			printk(KERN_ERR "pciserial: Unable to re-enable ports, trying to continue.\n");
 		pciserial_resume_ports(priv);
 	}
 	return 0;
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index 77cb342..31786b3 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -9,7 +9,6 @@
 # The new 8250/16550 serial drivers
 config SERIAL_8250
 	tristate "8250/16550 and compatible serial support"
-	depends on (BROKEN || !SPARC)
 	select SERIAL_CORE
 	---help---
 	  This selects whether you want to include the driver for the standard
@@ -994,24 +993,12 @@
 	bool "Support RTS/CTS on 68328 serial port"
 	depends on SERIAL_68328
 
-config SERIAL_COLDFIRE
-	bool "ColdFire serial support (DEPRECATED)"
-	depends on COLDFIRE
-	help
-	  This driver supports the built-in serial ports of the Motorola ColdFire
-	  family of CPUs.
-	  This driver is deprecated because it supports only the old interface
-	  for serial drivers and features like magic keys are not working.
-	  Please switch to the new style driver because this driver will be
-	  removed soon.
-
 config SERIAL_MCF
-	bool "Coldfire serial support (new style driver)"
+	bool "Coldfire serial support"
 	depends on COLDFIRE
 	select SERIAL_CORE
 	help
-	  This new serial driver supports the Freescale Coldfire serial ports
-	  using the new serial driver subsystem.
+	  This serial driver supports the Freescale Coldfire serial ports.
 
 config SERIAL_MCF_BAUDRATE
 	int "Default baudrate for Coldfire serial ports"
diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile
index 7e7383e..0c17c8d 100644
--- a/drivers/serial/Makefile
+++ b/drivers/serial/Makefile
@@ -4,6 +4,16 @@
 
 obj-$(CONFIG_SERIAL_CORE) += serial_core.o
 obj-$(CONFIG_SERIAL_21285) += 21285.o
+
+# These Sparc drivers have to appear before others such as 8250
+# which share ttySx minor node space.  Otherwise console device
+# names change and other unplesantries.
+obj-$(CONFIG_SERIAL_SUNCORE) += suncore.o
+obj-$(CONFIG_SERIAL_SUNHV) += sunhv.o
+obj-$(CONFIG_SERIAL_SUNZILOG) += sunzilog.o
+obj-$(CONFIG_SERIAL_SUNSU) += sunsu.o
+obj-$(CONFIG_SERIAL_SUNSAB) += sunsab.o
+
 obj-$(CONFIG_SERIAL_8250) += 8250.o
 obj-$(CONFIG_SERIAL_8250_PNP) += 8250_pnp.o
 obj-$(CONFIG_SERIAL_8250_GSC) += 8250_gsc.o
@@ -31,16 +41,10 @@
 obj-$(CONFIG_SERIAL_S3C2410) += s3c2410.o
 obj-$(CONFIG_SERIAL_S3C2412) += s3c2412.o
 obj-$(CONFIG_SERIAL_S3C2440) += s3c2440.o
-obj-$(CONFIG_SERIAL_SUNCORE) += suncore.o
-obj-$(CONFIG_SERIAL_SUNHV) += sunhv.o
-obj-$(CONFIG_SERIAL_SUNZILOG) += sunzilog.o
 obj-$(CONFIG_SERIAL_IP22_ZILOG) += ip22zilog.o
-obj-$(CONFIG_SERIAL_SUNSU) += sunsu.o
-obj-$(CONFIG_SERIAL_SUNSAB) += sunsab.o
 obj-$(CONFIG_SERIAL_MUX) += mux.o
 obj-$(CONFIG_SERIAL_68328) += 68328serial.o
 obj-$(CONFIG_SERIAL_68360) += 68360serial.o
-obj-$(CONFIG_SERIAL_COLDFIRE) += mcfserial.o
 obj-$(CONFIG_SERIAL_MCF) += mcf.o
 obj-$(CONFIG_SERIAL_PMACZILOG) += pmac_zilog.o
 obj-$(CONFIG_SERIAL_LH7A40X) += serial_lh7a40x.o
diff --git a/drivers/serial/atmel_serial.c b/drivers/serial/atmel_serial.c
index 3a6da80..61fb8b6 100644
--- a/drivers/serial/atmel_serial.c
+++ b/drivers/serial/atmel_serial.c
@@ -131,7 +131,8 @@
 struct atmel_uart_port {
 	struct uart_port	uart;		/* uart */
 	struct clk		*clk;		/* uart clock */
-	unsigned short		suspended;	/* is port suspended? */
+	int			may_wakeup;	/* cached value of device_may_wakeup for times we need to disable it */
+	u32			backup_imr;	/* IMR saved during suspend */
 	int			break_active;	/* break being received */
 
 	short			use_dma_rx;	/* enable PDC receiver */
@@ -984,8 +985,15 @@
 		 * This is called on uart_open() or a resume event.
 		 */
 		clk_enable(atmel_port->clk);
+
+		/* re-enable interrupts if we disabled some on suspend */
+		UART_PUT_IER(port, atmel_port->backup_imr);
 		break;
 	case 3:
+		/* Back up the interrupt mask and disable all interrupts */
+		atmel_port->backup_imr = UART_GET_IMR(port);
+		UART_PUT_IDR(port, -1);
+
 		/*
 		 * Disable the peripheral clock for this serial port.
 		 * This is called on uart_close() or a suspend event.
@@ -1475,13 +1483,12 @@
 			cpu_relax();
 	}
 
-	if (device_may_wakeup(&pdev->dev)
-	    && !atmel_serial_clk_will_stop())
-		enable_irq_wake(port->irq);
-	else {
-		uart_suspend_port(&atmel_uart, port);
-		atmel_port->suspended = 1;
-	}
+	/* we can not wake up if we're running on slow clock */
+	atmel_port->may_wakeup = device_may_wakeup(&pdev->dev);
+	if (atmel_serial_clk_will_stop())
+		device_set_wakeup_enable(&pdev->dev, 0);
+
+	uart_suspend_port(&atmel_uart, port);
 
 	return 0;
 }
@@ -1491,11 +1498,8 @@
 	struct uart_port *port = platform_get_drvdata(pdev);
 	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
 
-	if (atmel_port->suspended) {
-		uart_resume_port(&atmel_uart, port);
-		atmel_port->suspended = 0;
-	} else
-		disable_irq_wake(port->irq);
+	uart_resume_port(&atmel_uart, port);
+	device_set_wakeup_enable(&pdev->dev, atmel_port->may_wakeup);
 
 	return 0;
 }
@@ -1513,6 +1517,8 @@
 	BUILD_BUG_ON(!is_power_of_2(ATMEL_SERIAL_RINGSIZE));
 
 	port = &atmel_ports[pdev->id];
+	port->backup_imr = 0;
+
 	atmel_init_port(port, pdev);
 
 	if (!atmel_use_dma_rx(&port->uart)) {
diff --git a/drivers/serial/bfin_5xx.c b/drivers/serial/bfin_5xx.c
index 4a0d30b..569f0e2 100644
--- a/drivers/serial/bfin_5xx.c
+++ b/drivers/serial/bfin_5xx.c
@@ -1,7 +1,7 @@
 /*
  * Blackfin On-Chip Serial Driver
  *
- * Copyright 2006-2007 Analog Devices Inc.
+ * Copyright 2006-2008 Analog Devices Inc.
  *
  * Enter bugs at http://blackfin.uclinux.org/
  *
@@ -42,6 +42,9 @@
 #define BFIN_SERIAL_MAJOR	204
 #define BFIN_SERIAL_MINOR	64
 
+static struct bfin_serial_port bfin_serial_ports[BFIN_UART_NR_PORTS];
+static int nr_active_ports = ARRAY_SIZE(bfin_serial_resource);
+
 /*
  * Setup for console. Argument comes from the menuconfig
  */
@@ -126,13 +129,13 @@
 void kgdb_put_debug_char(int chr)
 {
 	struct bfin_serial_port *uart;
-	
+
 	if (CONFIG_KGDB_UART_PORT < 0
 		|| CONFIG_KGDB_UART_PORT >= BFIN_UART_NR_PORTS)
 		uart = &bfin_serial_ports[0];
 	else
 		uart = &bfin_serial_ports[CONFIG_KGDB_UART_PORT];
-	
+
 	while (!(UART_GET_LSR(uart) & THRE)) {
 		SSYNC();
 	}
@@ -152,7 +155,7 @@
 		uart = &bfin_serial_ports[0];
 	else
 		uart = &bfin_serial_ports[CONFIG_KGDB_UART_PORT];
-	
+
 	while(!(UART_GET_LSR(uart) & DR)) {
 		SSYNC();
 	}
@@ -298,7 +301,11 @@
 	bfin_serial_mctrl_check(uart);
 
 	if (uart_circ_empty(xmit) || uart_tx_stopped(&uart->port)) {
-		bfin_serial_stop_tx(&uart->port);
+#ifdef CONFIG_BF54x
+		/* Clear TFI bit */
+		UART_PUT_LSR(uart, TFI);
+#endif
+		UART_CLEAR_IER(uart, ETBEI);
 		return;
 	}
 
@@ -317,9 +324,6 @@
 
 	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
 		uart_write_wakeup(&uart->port);
-
-	if (uart_circ_empty(xmit))
-		bfin_serial_stop_tx(&uart->port);
 }
 
 static irqreturn_t bfin_serial_rx_int(int irq, void *dev_id)
@@ -645,6 +649,42 @@
 		free_irq(uart->port.irq, uart);
 		return -EBUSY;
 	}
+
+# ifdef CONFIG_BF54x
+	{
+		unsigned uart_dma_ch_rx, uart_dma_ch_tx;
+
+		switch (uart->port.irq) {
+		case IRQ_UART3_RX:
+			uart_dma_ch_rx = CH_UART3_RX;
+			uart_dma_ch_tx = CH_UART3_TX;
+			break;
+		case IRQ_UART2_RX:
+			uart_dma_ch_rx = CH_UART2_RX;
+			uart_dma_ch_tx = CH_UART2_TX;
+			break;
+		default:
+			uart_dma_ch_rx = uart_dma_ch_tx = 0;
+			break;
+		};
+
+		if (uart_dma_ch_rx &&
+			request_dma(uart_dma_ch_rx, "BFIN_UART_RX") < 0) {
+			printk(KERN_NOTICE"Fail to attach UART interrupt\n");
+			free_irq(uart->port.irq, uart);
+			free_irq(uart->port.irq + 1, uart);
+			return -EBUSY;
+		}
+		if (uart_dma_ch_tx &&
+			request_dma(uart_dma_ch_tx, "BFIN_UART_TX") < 0) {
+			printk(KERN_NOTICE "Fail to attach UART interrupt\n");
+			free_dma(uart_dma_ch_rx);
+			free_irq(uart->port.irq, uart);
+			free_irq(uart->port.irq + 1, uart);
+			return -EBUSY;
+		}
+	}
+# endif
 #endif
 	UART_SET_IER(uart, ERBFI);
 	return 0;
@@ -662,6 +702,20 @@
 	del_timer(&(uart->rx_dma_timer));
 	dma_free_coherent(NULL, PAGE_SIZE, uart->rx_dma_buf.buf, 0);
 #else
+#ifdef CONFIG_BF54x
+	switch (uart->port.irq) {
+	case IRQ_UART3_RX:
+		free_dma(CH_UART3_RX);
+		free_dma(CH_UART3_TX);
+		break;
+	case IRQ_UART2_RX:
+		free_dma(CH_UART2_RX);
+		free_dma(CH_UART2_TX);
+		break;
+	default:
+		break;
+	};
+#endif
 #ifdef	CONFIG_KGDB_UART
 	if (uart->port.line != CONFIG_KGDB_UART_PORT)
 #endif
@@ -757,6 +811,9 @@
 	val |= UCEN;
 	UART_PUT_GCTL(uart, val);
 
+	/* Port speed changed, update the per-port timeout. */
+	uart_update_timeout(port, termios->c_cflag, baud);
+
 	spin_unlock_irqrestore(&uart->port.lock, flags);
 }
 
@@ -859,8 +916,9 @@
 		return;
 	first = 0;
 
-	for (i = 0; i < nr_ports; i++) {
+	for (i = 0; i < nr_active_ports; i++) {
 		bfin_serial_ports[i].port.uartclk   = get_sclk();
+		bfin_serial_ports[i].port.fifosize  = BFIN_UART_TX_FIFO_SIZE;
 		bfin_serial_ports[i].port.ops       = &bfin_serial_pops;
 		bfin_serial_ports[i].port.line      = i;
 		bfin_serial_ports[i].port.iotype    = UPIO_MEM;
@@ -961,7 +1019,7 @@
 	 * if so, search for the first available port that does have
 	 * console support.
 	 */
-	if (co->index == -1 || co->index >= nr_ports)
+	if (co->index == -1 || co->index >= nr_active_ports)
 		co->index = 0;
 	uart = &bfin_serial_ports[co->index];
 
@@ -1056,7 +1114,7 @@
 	}
 }
 
-static struct __init console bfin_early_serial_console = {
+static struct __initdata console bfin_early_serial_console = {
 	.name = "early_BFuart",
 	.write = early_serial_write,
 	.device = uart_console_device,
@@ -1072,7 +1130,7 @@
 	struct bfin_serial_port *uart;
 	struct ktermios t;
 
-	if (port == -1 || port >= nr_ports)
+	if (port == -1 || port >= nr_active_ports)
 		port = 0;
 	bfin_serial_init_ports();
 	bfin_early_serial_console.index = port;
@@ -1100,20 +1158,26 @@
 
 static int bfin_serial_suspend(struct platform_device *dev, pm_message_t state)
 {
-	struct bfin_serial_port *uart = platform_get_drvdata(dev);
+	int i;
 
-	if (uart)
-		uart_suspend_port(&bfin_serial_reg, &uart->port);
+	for (i = 0; i < nr_active_ports; i++) {
+		if (bfin_serial_ports[i].port.dev != &dev->dev)
+			continue;
+		uart_suspend_port(&bfin_serial_reg, &bfin_serial_ports[i].port);
+	}
 
 	return 0;
 }
 
 static int bfin_serial_resume(struct platform_device *dev)
 {
-	struct bfin_serial_port *uart = platform_get_drvdata(dev);
+	int i;
 
-	if (uart)
-		uart_resume_port(&bfin_serial_reg, &uart->port);
+	for (i = 0; i < nr_active_ports; i++) {
+		if (bfin_serial_ports[i].port.dev != &dev->dev)
+			continue;
+		uart_resume_port(&bfin_serial_reg, &bfin_serial_ports[i].port);
+	}
 
 	return 0;
 }
@@ -1128,32 +1192,31 @@
 			break;
 
 	if (i < dev->num_resources) {
-		for (i = 0; i < nr_ports; i++, res++) {
+		for (i = 0; i < nr_active_ports; i++, res++) {
 			if (bfin_serial_ports[i].port.mapbase != res->start)
 				continue;
 			bfin_serial_ports[i].port.dev = &dev->dev;
 			uart_add_one_port(&bfin_serial_reg, &bfin_serial_ports[i].port);
-			platform_set_drvdata(dev, &bfin_serial_ports[i]);
 		}
 	}
 
 	return 0;
 }
 
-static int bfin_serial_remove(struct platform_device *pdev)
+static int bfin_serial_remove(struct platform_device *dev)
 {
-	struct bfin_serial_port *uart = platform_get_drvdata(pdev);
+	int i;
 
-
+	for (i = 0; i < nr_active_ports; i++) {
+		if (bfin_serial_ports[i].port.dev != &dev->dev)
+			continue;
+		uart_remove_one_port(&bfin_serial_reg, &bfin_serial_ports[i].port);
+		bfin_serial_ports[i].port.dev = NULL;
 #ifdef CONFIG_SERIAL_BFIN_CTSRTS
-	gpio_free(uart->cts_pin);
-	gpio_free(uart->rts_pin);
+		gpio_free(bfin_serial_ports[i].cts_pin);
+		gpio_free(bfin_serial_ports[i].rts_pin);
 #endif
-
-	platform_set_drvdata(pdev, NULL);
-
-	if (uart)
-		uart_remove_one_port(&bfin_serial_reg, &uart->port);
+	}
 
 	return 0;
 }
diff --git a/drivers/serial/crisv10.c b/drivers/serial/crisv10.c
index bf94a77..211c217 100644
--- a/drivers/serial/crisv10.c
+++ b/drivers/serial/crisv10.c
@@ -457,7 +457,6 @@
 #define NR_PORTS (sizeof(rs_table)/sizeof(struct e100_serial))
 
 static struct ktermios *serial_termios[NR_PORTS];
-static struct ktermios *serial_termios_locked[NR_PORTS];
 #ifdef CONFIG_ETRAX_SERIAL_FAST_TIMER
 static struct fast_timer fast_timers[NR_PORTS];
 #endif
@@ -4419,6 +4418,7 @@
 			rs485_pa_bit)) {
 		printk(KERN_CRIT "ETRAX100LX serial: Could not allocate "
 			"RS485 pin\n");
+		put_tty_driver(driver);
 		return -EBUSY;
 	}
 #endif
@@ -4427,6 +4427,7 @@
 			rs485_port_g_bit)) {
 		printk(KERN_CRIT "ETRAX100LX serial: Could not allocate "
 			"RS485 pin\n");
+		put_tty_driver(driver);
 		return -EBUSY;
 	}
 #endif
@@ -4446,8 +4447,6 @@
 	driver->init_termios.c_ispeed = 115200;
 	driver->init_termios.c_ospeed = 115200;
 	driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
-	driver->termios = serial_termios;
-	driver->termios_locked = serial_termios_locked;
 
 	tty_set_operations(driver, &rs_ops);
         serial_driver = driver;
diff --git a/drivers/serial/mcfserial.c b/drivers/serial/mcfserial.c
deleted file mode 100644
index fbe3835..0000000
--- a/drivers/serial/mcfserial.c
+++ /dev/null
@@ -1,1965 +0,0 @@
-#warning This driver is deprecated. Check Kconfig for details.
-/*
- * mcfserial.c -- serial driver for ColdFire internal UARTS.
- *
- * Copyright (C) 1999-2003 Greg Ungerer <gerg@snapgear.com>
- * Copyright (c) 2000-2001 Lineo, Inc. <www.lineo.com> 
- * Copyright (C) 2001-2002 SnapGear Inc. <www.snapgear.com> 
- *
- * Based on code from 68332serial.c which was:
- *
- * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
- * Copyright (C) 1998 TSHG
- * Copyright (c) 1999 Rt-Control Inc. <jeff@uclinux.org>
- *
- * Changes:
- * 08/07/2003    Daniele Bellucci <bellucda@tiscali.it>
- *               some cleanups in mcfrs_write.
- *
- */
- 
-#include <linux/module.h>
-#include <linux/errno.h>
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/timer.h>
-#include <linux/wait.h>
-#include <linux/interrupt.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/string.h>
-#include <linux/fcntl.h>
-#include <linux/mm.h>
-#include <linux/kernel.h>
-#include <linux/serial.h>
-#include <linux/serialP.h>
-#include <linux/console.h>
-#include <linux/init.h>
-#include <linux/bitops.h>
-#include <linux/delay.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/system.h>
-#include <asm/delay.h>
-#include <asm/coldfire.h>
-#include <asm/mcfsim.h>
-#include <asm/mcfuart.h>
-#include <asm/nettel.h>
-#include <asm/uaccess.h>
-#include "mcfserial.h"
-
-struct timer_list mcfrs_timer_struct;
-
-/*
- *	Default console baud rate,  we use this as the default
- *	for all ports so init can just open /dev/console and
- *	keep going.  Perhaps one day the cflag settings for the
- *	console can be used instead.
- */
-#if defined(CONFIG_HW_FEITH)
-#define	CONSOLE_BAUD_RATE	38400
-#define	DEFAULT_CBAUD		B38400
-#elif defined(CONFIG_MOD5272) || defined(CONFIG_M5208EVB) || \
-      defined(CONFIG_M5329EVB) || defined(CONFIG_GILBARCO)
-#define CONSOLE_BAUD_RATE 	115200
-#define DEFAULT_CBAUD		B115200
-#elif defined(CONFIG_ARNEWSH) || defined(CONFIG_FREESCALE) || \
-      defined(CONFIG_senTec) || defined(CONFIG_SNEHA) || defined(CONFIG_AVNET)
-#define	CONSOLE_BAUD_RATE	19200
-#define	DEFAULT_CBAUD		B19200
-#endif
-
-#ifndef CONSOLE_BAUD_RATE
-#define	CONSOLE_BAUD_RATE	9600
-#define	DEFAULT_CBAUD		B9600
-#endif
-
-int mcfrs_console_inited = 0;
-int mcfrs_console_port = -1;
-int mcfrs_console_baud = CONSOLE_BAUD_RATE;
-int mcfrs_console_cbaud = DEFAULT_CBAUD;
-
-/*
- *	Driver data structures.
- */
-static struct tty_driver *mcfrs_serial_driver;
-
-/* number of characters left in xmit buffer before we ask for more */
-#define WAKEUP_CHARS 256
-
-/* Debugging...
- */
-#undef SERIAL_DEBUG_OPEN
-#undef SERIAL_DEBUG_FLOW
-
-#if defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x) || \
-    defined(CONFIG_M520x) || defined(CONFIG_M532x)
-#define	IRQBASE	(MCFINT_VECBASE+MCFINT_UART0)
-#else
-#define	IRQBASE	73
-#endif
-
-/*
- *	Configuration table, UARTs to look for at startup.
- */
-static struct mcf_serial mcfrs_table[] = {
-	{  /* ttyS0 */
-		.magic = 0,
-		.addr = (volatile unsigned char *) (MCF_MBAR+MCFUART_BASE1),
-		.irq = IRQBASE,
-		.flags = ASYNC_BOOT_AUTOCONF,
-	},
-#ifdef MCFUART_BASE2
-	{  /* ttyS1 */
-		.magic = 0,
-		.addr = (volatile unsigned char *) (MCF_MBAR+MCFUART_BASE2),
-		.irq = IRQBASE+1,
-		.flags = ASYNC_BOOT_AUTOCONF,
-	},
-#endif
-#ifdef MCFUART_BASE3
-	{  /* ttyS2 */
-		.magic = 0,
-		.addr = (volatile unsigned char *) (MCF_MBAR+MCFUART_BASE3),
-		.irq = IRQBASE+2,
-		.flags = ASYNC_BOOT_AUTOCONF,
-	},
-#endif
-#ifdef MCFUART_BASE4
-	{  /* ttyS3 */
-		.magic = 0,
-		.addr = (volatile unsigned char *) (MCF_MBAR+MCFUART_BASE4),
-		.irq = IRQBASE+3,
-		.flags = ASYNC_BOOT_AUTOCONF,
-	},
-#endif
-};
-
-
-#define	NR_PORTS	(sizeof(mcfrs_table) / sizeof(struct mcf_serial))
-
-/*
- * This is used to figure out the divisor speeds and the timeouts.
- */
-static int mcfrs_baud_table[] = {
-	0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
-	9600, 19200, 38400, 57600, 115200, 230400, 460800, 0
-};
-#define MCFRS_BAUD_TABLE_SIZE \
-			(sizeof(mcfrs_baud_table)/sizeof(mcfrs_baud_table[0]))
-
-
-#ifdef CONFIG_MAGIC_SYSRQ
-/*
- *	Magic system request keys. Used for debugging...
- */
-extern int	magic_sysrq_key(int ch);
-#endif
-
-
-/*
- *	Forware declarations...
- */
-static void	mcfrs_change_speed(struct mcf_serial *info);
-static void	mcfrs_wait_until_sent(struct tty_struct *tty, int timeout);
-
-
-static inline int serial_paranoia_check(struct mcf_serial *info,
-					char *name, const char *routine)
-{
-#ifdef SERIAL_PARANOIA_CHECK
-	static const char badmagic[] =
-		"MCFRS(warning): bad magic number for serial struct %s in %s\n";
-	static const char badinfo[] =
-		"MCFRS(warning): null mcf_serial for %s in %s\n";
-
-	if (!info) {
-		printk(badinfo, name, routine);
-		return 1;
-	}
-	if (info->magic != SERIAL_MAGIC) {
-		printk(badmagic, name, routine);
-		return 1;
-	}
-#endif
-	return 0;
-}
-
-/*
- *	Sets or clears DTR and RTS on the requested line.
- */
-static void mcfrs_setsignals(struct mcf_serial *info, int dtr, int rts)
-{
-	volatile unsigned char	*uartp;
-	unsigned long		flags;
-	
-#if 0
-	printk("%s(%d): mcfrs_setsignals(info=%x,dtr=%d,rts=%d)\n",
-		__FILE__, __LINE__, info, dtr, rts);
-#endif
-
-	local_irq_save(flags);
-	if (dtr >= 0) {
-#ifdef MCFPP_DTR0
-		if (info->line)
-			mcf_setppdata(MCFPP_DTR1, (dtr ? 0 : MCFPP_DTR1));
-		else
-			mcf_setppdata(MCFPP_DTR0, (dtr ? 0 : MCFPP_DTR0));
-#endif
-	}
-	if (rts >= 0) {
-		uartp = info->addr;
-		if (rts) {
-			info->sigs |= TIOCM_RTS;
-			uartp[MCFUART_UOP1] = MCFUART_UOP_RTS;
-		} else {
-			info->sigs &= ~TIOCM_RTS;
-			uartp[MCFUART_UOP0] = MCFUART_UOP_RTS;
-		}
-	}
-	local_irq_restore(flags);
-	return;
-}
-
-/*
- *	Gets values of serial signals.
- */
-static int mcfrs_getsignals(struct mcf_serial *info)
-{
-	volatile unsigned char	*uartp;
-	unsigned long		flags;
-	int			sigs;
-#if defined(CONFIG_NETtel) && defined(CONFIG_M5307)
-	unsigned short		ppdata;
-#endif
-
-#if 0
-	printk("%s(%d): mcfrs_getsignals(info=%x)\n", __FILE__, __LINE__);
-#endif
-
-	local_irq_save(flags);
-	uartp = info->addr;
-	sigs = (uartp[MCFUART_UIPR] & MCFUART_UIPR_CTS) ? 0 : TIOCM_CTS;
-	sigs |= (info->sigs & TIOCM_RTS);
-
-#ifdef MCFPP_DCD0
-{
-	unsigned int ppdata;
-	ppdata = mcf_getppdata();
-	if (info->line == 0) {
-		sigs |= (ppdata & MCFPP_DCD0) ? 0 : TIOCM_CD;
-		sigs |= (ppdata & MCFPP_DTR0) ? 0 : TIOCM_DTR;
-	} else if (info->line == 1) {
-		sigs |= (ppdata & MCFPP_DCD1) ? 0 : TIOCM_CD;
-		sigs |= (ppdata & MCFPP_DTR1) ? 0 : TIOCM_DTR;
-	}
-}
-#endif
-
-	local_irq_restore(flags);
-	return(sigs);
-}
-
-/*
- * ------------------------------------------------------------
- * mcfrs_stop() and mcfrs_start()
- *
- * This routines are called before setting or resetting tty->stopped.
- * They enable or disable transmitter interrupts, as necessary.
- * ------------------------------------------------------------
- */
-static void mcfrs_stop(struct tty_struct *tty)
-{
-	volatile unsigned char	*uartp;
-	struct mcf_serial	*info = (struct mcf_serial *)tty->driver_data;
-	unsigned long		flags;
-
-	if (serial_paranoia_check(info, tty->name, "mcfrs_stop"))
-		return;
-	
-	local_irq_save(flags);
-	uartp = info->addr;
-	info->imr &= ~MCFUART_UIR_TXREADY;
-	uartp[MCFUART_UIMR] = info->imr;
-	local_irq_restore(flags);
-}
-
-static void mcfrs_start(struct tty_struct *tty)
-{
-	volatile unsigned char	*uartp;
-	struct mcf_serial	*info = (struct mcf_serial *)tty->driver_data;
-	unsigned long		flags;
-	
-	if (serial_paranoia_check(info, tty->name, "mcfrs_start"))
-		return;
-
-	local_irq_save(flags);
-	if (info->xmit_cnt && info->xmit_buf) {
-		uartp = info->addr;
-		info->imr |= MCFUART_UIR_TXREADY;
-		uartp[MCFUART_UIMR] = info->imr;
-	}
-	local_irq_restore(flags);
-}
-
-/*
- * ----------------------------------------------------------------------
- *
- * Here starts the interrupt handling routines.  All of the following
- * subroutines are declared as inline and are folded into
- * mcfrs_interrupt().  They were separated out for readability's sake.
- *
- * Note: mcfrs_interrupt() is a "fast" interrupt, which means that it
- * runs with interrupts turned off.  People who may want to modify
- * mcfrs_interrupt() should try to keep the interrupt handler as fast as
- * possible.  After you are done making modifications, it is not a bad
- * idea to do:
- * 
- * gcc -S -DKERNEL -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer serial.c
- *
- * and look at the resulting assemble code in serial.s.
- *
- * 				- Ted Ts'o (tytso@mit.edu), 7-Mar-93
- * -----------------------------------------------------------------------
- */
-
-static inline void receive_chars(struct mcf_serial *info)
-{
-	volatile unsigned char	*uartp;
-	struct tty_struct	*tty = info->port.tty;
-	unsigned char		status, ch, flag;
-
-	if (!tty)
-		return;
-
-	uartp = info->addr;
-
-	while ((status = uartp[MCFUART_USR]) & MCFUART_USR_RXREADY) {
-		ch = uartp[MCFUART_URB];
-		info->stats.rx++;
-
-#ifdef CONFIG_MAGIC_SYSRQ
-		if (mcfrs_console_inited && (info->line == mcfrs_console_port)) {
-			if (magic_sysrq_key(ch))
-				continue;
-		}
-#endif
-
-		flag = TTY_NORMAL;
-		if (status & MCFUART_USR_RXERR) {
-			uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETERR;
-			if (status & MCFUART_USR_RXBREAK) {
-				info->stats.rxbreak++;
-				flag = TTY_BREAK;
-			} else if (status & MCFUART_USR_RXPARITY) {
-				info->stats.rxparity++;
-				flag = TTY_PARITY;
-			} else if (status & MCFUART_USR_RXOVERRUN) {
-				info->stats.rxoverrun++;
-				flag = TTY_OVERRUN;
-			} else if (status & MCFUART_USR_RXFRAMING) {
-				info->stats.rxframing++;
-				flag = TTY_FRAME;
-			}
-		}
-		tty_insert_flip_char(tty, ch, flag);
-	}
-	tty_schedule_flip(tty);
-	return;
-}
-
-static inline void transmit_chars(struct mcf_serial *info)
-{
-	volatile unsigned char	*uartp;
-
-	uartp = info->addr;
-
-	if (info->x_char) {
-		/* Send special char - probably flow control */
-		uartp[MCFUART_UTB] = info->x_char;
-		info->x_char = 0;
-		info->stats.tx++;
-	}
-
-	if ((info->xmit_cnt <= 0) || info->port.tty->stopped) {
-		info->imr &= ~MCFUART_UIR_TXREADY;
-		uartp[MCFUART_UIMR] = info->imr;
-		return;
-	}
-
-	while (uartp[MCFUART_USR] & MCFUART_USR_TXREADY) {
-		uartp[MCFUART_UTB] = info->xmit_buf[info->xmit_tail++];
-		info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1);
-		info->stats.tx++;
-		if (--info->xmit_cnt <= 0)
-			break;
-	}
-
-	if (info->xmit_cnt < WAKEUP_CHARS)
-		schedule_work(&info->tqueue);
-	return;
-}
-
-/*
- * This is the serial driver's generic interrupt routine
- */
-irqreturn_t mcfrs_interrupt(int irq, void *dev_id)
-{
-	struct mcf_serial	*info;
-	unsigned char		isr;
-
-	info = &mcfrs_table[(irq - IRQBASE)];
-	isr = info->addr[MCFUART_UISR] & info->imr;
-
-	if (isr & MCFUART_UIR_RXREADY)
-		receive_chars(info);
-	if (isr & MCFUART_UIR_TXREADY)
-		transmit_chars(info);
-	return IRQ_HANDLED;
-}
-
-/*
- * -------------------------------------------------------------------
- * Here ends the serial interrupt routines.
- * -------------------------------------------------------------------
- */
-
-static void mcfrs_offintr(struct work_struct *work)
-{
-	struct mcf_serial *info = container_of(work, struct mcf_serial, tqueue);
-	struct tty_struct *tty = info->port.tty;
-	
-	if (tty)
-		tty_wakeup(tty);
-}
-
-
-/*
- *	Change of state on a DCD line.
- */
-void mcfrs_modem_change(struct mcf_serial *info, int dcd)
-{
-	if (info->count == 0)
-		return;
-
-	if (info->flags & ASYNC_CHECK_CD) {
-		if (dcd)
-			wake_up_interruptible(&info->open_wait);
-		else 
-			schedule_work(&info->tqueue_hangup);
-	}
-}
-
-
-#ifdef MCFPP_DCD0
-
-unsigned short	mcfrs_ppstatus;
-
-/*
- * This subroutine is called when the RS_TIMER goes off. It is used
- * to monitor the state of the DCD lines - since they have no edge
- * sensors and interrupt generators.
- */
-static void mcfrs_timer(void)
-{
-	unsigned int	ppstatus, dcdval, i;
-
-	ppstatus = mcf_getppdata() & (MCFPP_DCD0 | MCFPP_DCD1);
-
-	if (ppstatus != mcfrs_ppstatus) {
-		for (i = 0; (i < 2); i++) {
-			dcdval = (i ? MCFPP_DCD1 : MCFPP_DCD0);
-			if ((ppstatus & dcdval) != (mcfrs_ppstatus & dcdval)) {
-				mcfrs_modem_change(&mcfrs_table[i],
-					((ppstatus & dcdval) ? 0 : 1));
-			}
-		}
-	}
-	mcfrs_ppstatus = ppstatus;
-
-	/* Re-arm timer */
-	mcfrs_timer_struct.expires = jiffies + HZ/25;
-	add_timer(&mcfrs_timer_struct);
-}
-
-#endif	/* MCFPP_DCD0 */
-
-
-/*
- * This routine is called from the scheduler tqueue when the interrupt
- * routine has signalled that a hangup has occurred. The path of
- * hangup processing is:
- *
- * 	serial interrupt routine -> (scheduler tqueue) ->
- * 	do_serial_hangup() -> tty->hangup() -> mcfrs_hangup()
- * 
- */
-static void do_serial_hangup(struct work_struct *work)
-{
-	struct mcf_serial *info = container_of(work, struct mcf_serial, tqueue_hangup);
-	struct tty_struct *tty = info->port.tty;
-	
-	if (tty)
-		tty_hangup(tty);
-}
-
-static int startup(struct mcf_serial * info)
-{
-	volatile unsigned char	*uartp;
-	unsigned long		flags;
-	
-	if (info->flags & ASYNC_INITIALIZED)
-		return 0;
-
-	if (!info->xmit_buf) {
-		info->xmit_buf = (unsigned char *) __get_free_page(GFP_KERNEL);
-		if (!info->xmit_buf)
-			return -ENOMEM;
-	}
-
-	local_irq_save(flags);
-
-#ifdef SERIAL_DEBUG_OPEN
-	printk("starting up ttyS%d (irq %d)...\n", info->line, info->irq);
-#endif
-
-	/*
-	 *	Reset UART, get it into known state...
-	 */
-	uartp = info->addr;
-	uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETRX;  /* reset RX */
-	uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETTX;  /* reset TX */
-	mcfrs_setsignals(info, 1, 1);
-
-	if (info->port.tty)
-		clear_bit(TTY_IO_ERROR, &info->port.tty->flags);
-	info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
-
-	/*
-	 * and set the speed of the serial port
-	 */
-	mcfrs_change_speed(info);
-
-	/*
-	 * Lastly enable the UART transmitter and receiver, and
-	 * interrupt enables.
-	 */
-	info->imr = MCFUART_UIR_RXREADY;
-	uartp[MCFUART_UCR] = MCFUART_UCR_RXENABLE | MCFUART_UCR_TXENABLE;
-	uartp[MCFUART_UIMR] = info->imr;
-
-	info->flags |= ASYNC_INITIALIZED;
-	local_irq_restore(flags);
-	return 0;
-}
-
-/*
- * This routine will shutdown a serial port; interrupts are disabled, and
- * DTR is dropped if the hangup on close termio flag is on.
- */
-static void shutdown(struct mcf_serial * info)
-{
-	volatile unsigned char	*uartp;
-	unsigned long		flags;
-
-	if (!(info->flags & ASYNC_INITIALIZED))
-		return;
-
-#ifdef SERIAL_DEBUG_OPEN
-	printk("Shutting down serial port %d (irq %d)....\n", info->line,
-	       info->irq);
-#endif
-	
-	local_irq_save(flags);
-
-	uartp = info->addr;
-	uartp[MCFUART_UIMR] = 0;  /* mask all interrupts */
-	uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETRX;  /* reset RX */
-	uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETTX;  /* reset TX */
-
-	if (!info->port.tty || (info->port.tty->termios->c_cflag & HUPCL))
-		mcfrs_setsignals(info, 0, 0);
-
-	if (info->xmit_buf) {
-		free_page((unsigned long) info->xmit_buf);
-		info->xmit_buf = 0;
-	}
-
-	if (info->port.tty)
-		set_bit(TTY_IO_ERROR, &info->port.tty->flags);
-	
-	info->flags &= ~ASYNC_INITIALIZED;
-	local_irq_restore(flags);
-}
-
-
-/*
- * This routine is called to set the UART divisor registers to match
- * the specified baud rate for a serial port.
- */
-static void mcfrs_change_speed(struct mcf_serial *info)
-{
-	volatile unsigned char	*uartp;
-	unsigned int		baudclk, cflag;
-	unsigned long		flags;
-	unsigned char		mr1, mr2;
-	int			i;
-#ifdef	CONFIG_M5272
-	unsigned int		fraction;
-#endif
-
-	if (!info->port.tty || !info->port.tty->termios)
-		return;
-	cflag = info->port.tty->termios->c_cflag;
-	if (info->addr == 0)
-		return;
-
-#if 0
-	printk("%s(%d): mcfrs_change_speed()\n", __FILE__, __LINE__);
-#endif
-
-	i = cflag & CBAUD;
-	if (i & CBAUDEX) {
-		i &= ~CBAUDEX;
-		if (i < 1 || i > 4)
-			info->port.tty->termios->c_cflag &= ~CBAUDEX;
-		else
-			i += 15;
-	}
-	if (i == 0) {
-		mcfrs_setsignals(info, 0, -1);
-		return;
-	}
-
-	/* compute the baudrate clock */
-#ifdef	CONFIG_M5272
-	/*
-	 * For the MCF5272, also compute the baudrate fraction.
-	 */
-	baudclk = (MCF_BUSCLK / mcfrs_baud_table[i]) / 32;
-	fraction = MCF_BUSCLK - (baudclk * 32 * mcfrs_baud_table[i]);
-	fraction *= 16;
-	fraction /= (32 * mcfrs_baud_table[i]);
-#else
-	baudclk = ((MCF_BUSCLK / mcfrs_baud_table[i]) + 16) / 32;
-#endif
-
-	info->baud = mcfrs_baud_table[i];
-
-	mr1 = MCFUART_MR1_RXIRQRDY | MCFUART_MR1_RXERRCHAR;
-	mr2 = 0;
-
-	switch (cflag & CSIZE) {
-	case CS5:	mr1 |= MCFUART_MR1_CS5; break;
-	case CS6:	mr1 |= MCFUART_MR1_CS6; break;
-	case CS7:	mr1 |= MCFUART_MR1_CS7; break;
-	case CS8:
-	default:	mr1 |= MCFUART_MR1_CS8; break;
-	}
-
-	if (cflag & PARENB) {
-		if (cflag & CMSPAR) {
-			if (cflag & PARODD)
-				mr1 |= MCFUART_MR1_PARITYMARK;
-			else
-				mr1 |= MCFUART_MR1_PARITYSPACE;
-		} else {
-			if (cflag & PARODD)
-				mr1 |= MCFUART_MR1_PARITYODD;
-			else
-				mr1 |= MCFUART_MR1_PARITYEVEN;
-		}
-	} else {
-		mr1 |= MCFUART_MR1_PARITYNONE;
-	}
-
-	if (cflag & CSTOPB)
-		mr2 |= MCFUART_MR2_STOP2;
-	else
-		mr2 |= MCFUART_MR2_STOP1;
-
-	if (cflag & CRTSCTS) {
-		mr1 |= MCFUART_MR1_RXRTS;
-		mr2 |= MCFUART_MR2_TXCTS;
-	}
-
-	if (cflag & CLOCAL)
-		info->flags &= ~ASYNC_CHECK_CD;
-	else
-		info->flags |= ASYNC_CHECK_CD;
-
-	uartp = info->addr;
-
-	local_irq_save(flags);
-#if 0
-	printk("%s(%d): mr1=%x mr2=%x baudclk=%x\n", __FILE__, __LINE__,
-		mr1, mr2, baudclk);
-#endif
-	/*
-	  Note: pg 12-16 of MCF5206e User's Manual states that a
-	  software reset should be performed prior to changing
-	  UMR1,2, UCSR, UACR, bit 7
-	*/
-	uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETRX;    /* reset RX */
-	uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETTX;    /* reset TX */
-	uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETMRPTR;	/* reset MR pointer */
-	uartp[MCFUART_UMR] = mr1;
-	uartp[MCFUART_UMR] = mr2;
-	uartp[MCFUART_UBG1] = (baudclk & 0xff00) >> 8;	/* set msb byte */
-	uartp[MCFUART_UBG2] = (baudclk & 0xff);		/* set lsb byte */
-#ifdef	CONFIG_M5272
-	uartp[MCFUART_UFPD] = (fraction & 0xf);		/* set fraction */
-#endif
-	uartp[MCFUART_UCSR] = MCFUART_UCSR_RXCLKTIMER | MCFUART_UCSR_TXCLKTIMER;
-	uartp[MCFUART_UCR] = MCFUART_UCR_RXENABLE | MCFUART_UCR_TXENABLE;
-	mcfrs_setsignals(info, 1, -1);
-	local_irq_restore(flags);
-	return;
-}
-
-static void mcfrs_flush_chars(struct tty_struct *tty)
-{
-	volatile unsigned char	*uartp;
-	struct mcf_serial	*info = (struct mcf_serial *)tty->driver_data;
-	unsigned long		flags;
-
-	if (serial_paranoia_check(info, tty->name, "mcfrs_flush_chars"))
-		return;
-
-	uartp = (volatile unsigned char *) info->addr;
-
-	/*
-	 * re-enable receiver interrupt
-	 */
-	local_irq_save(flags);
-	if ((!(info->imr & MCFUART_UIR_RXREADY)) &&
-	    (info->flags & ASYNC_INITIALIZED) ) {
-		info->imr |= MCFUART_UIR_RXREADY;
-		uartp[MCFUART_UIMR] = info->imr;
-	}
-	local_irq_restore(flags);
-
-	if (info->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped ||
-	    !info->xmit_buf)
-		return;
-
-	/* Enable transmitter */
-	local_irq_save(flags);
-	info->imr |= MCFUART_UIR_TXREADY;
-	uartp[MCFUART_UIMR] = info->imr;
-	local_irq_restore(flags);
-}
-
-static int mcfrs_write(struct tty_struct * tty,
-		    const unsigned char *buf, int count)
-{
-	volatile unsigned char	*uartp;
-	struct mcf_serial	*info = (struct mcf_serial *)tty->driver_data;
-	unsigned long		flags;
-	int			c, total = 0;
-
-#if 0
-	printk("%s(%d): mcfrs_write(tty=%x,buf=%x,count=%d)\n",
-		__FILE__, __LINE__, (int)tty, (int)buf, count);
-#endif
-
-	if (serial_paranoia_check(info, tty->name, "mcfrs_write"))
-		return 0;
-
-	if (!tty || !info->xmit_buf)
-		return 0;
-	
-	local_save_flags(flags);
-	while (1) {
-		local_irq_disable();		
-		c = min(count, (int) min(((int)SERIAL_XMIT_SIZE) - info->xmit_cnt - 1,
-			((int)SERIAL_XMIT_SIZE) - info->xmit_head));
-		local_irq_restore(flags);
-
-		if (c <= 0)
-			break;
-
-		memcpy(info->xmit_buf + info->xmit_head, buf, c);
-
-		local_irq_disable();
-		info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE-1);
-		info->xmit_cnt += c;
-		local_irq_restore(flags);
-
-		buf += c;
-		count -= c;
-		total += c;
-	}
-
-	local_irq_disable();
-	uartp = info->addr;
-	info->imr |= MCFUART_UIR_TXREADY;
-	uartp[MCFUART_UIMR] = info->imr;
-	local_irq_restore(flags);
-
-	return total;
-}
-
-static int mcfrs_write_room(struct tty_struct *tty)
-{
-	struct mcf_serial *info = (struct mcf_serial *)tty->driver_data;
-	int	ret;
-
-	if (serial_paranoia_check(info, tty->name, "mcfrs_write_room"))
-		return 0;
-	ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1;
-	if (ret < 0)
-		ret = 0;
-	return ret;
-}
-
-static int mcfrs_chars_in_buffer(struct tty_struct *tty)
-{
-	struct mcf_serial *info = (struct mcf_serial *)tty->driver_data;
-
-	if (serial_paranoia_check(info, tty->name, "mcfrs_chars_in_buffer"))
-		return 0;
-	return info->xmit_cnt;
-}
-
-static void mcfrs_flush_buffer(struct tty_struct *tty)
-{
-	struct mcf_serial	*info = (struct mcf_serial *)tty->driver_data;
-	unsigned long		flags;
-
-	if (serial_paranoia_check(info, tty->name, "mcfrs_flush_buffer"))
-		return;
-
-	local_irq_save(flags);
-	info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
-	local_irq_restore(flags);
-
-	tty_wakeup(tty);
-}
-
-/*
- * ------------------------------------------------------------
- * mcfrs_throttle()
- * 
- * This routine is called by the upper-layer tty layer to signal that
- * incoming characters should be throttled.
- * ------------------------------------------------------------
- */
-static void mcfrs_throttle(struct tty_struct * tty)
-{
-	struct mcf_serial *info = (struct mcf_serial *)tty->driver_data;
-#ifdef SERIAL_DEBUG_THROTTLE
-	char	buf[64];
-	
-	printk("throttle %s: %d....\n", tty_name(tty, buf),
-	       tty->ldisc.chars_in_buffer(tty));
-#endif
-
-	if (serial_paranoia_check(info, tty->name, "mcfrs_throttle"))
-		return;
-	
-	if (I_IXOFF(tty))
-		info->x_char = STOP_CHAR(tty);
-
-	/* Turn off RTS line (do this atomic) */
-}
-
-static void mcfrs_unthrottle(struct tty_struct * tty)
-{
-	struct mcf_serial *info = (struct mcf_serial *)tty->driver_data;
-#ifdef SERIAL_DEBUG_THROTTLE
-	char	buf[64];
-	
-	printk("unthrottle %s: %d....\n", tty_name(tty, buf),
-	       tty->ldisc.chars_in_buffer(tty));
-#endif
-
-	if (serial_paranoia_check(info, tty->name, "mcfrs_unthrottle"))
-		return;
-	
-	if (I_IXOFF(tty)) {
-		if (info->x_char)
-			info->x_char = 0;
-		else
-			info->x_char = START_CHAR(tty);
-	}
-
-	/* Assert RTS line (do this atomic) */
-}
-
-/*
- * ------------------------------------------------------------
- * mcfrs_ioctl() and friends
- * ------------------------------------------------------------
- */
-
-static int get_serial_info(struct mcf_serial * info,
-			   struct serial_struct * retinfo)
-{
-	struct serial_struct tmp;
-  
-	if (!retinfo)
-		return -EFAULT;
-	memset(&tmp, 0, sizeof(tmp));
-	tmp.type = info->type;
-	tmp.line = info->line;
-	tmp.port = (unsigned int) info->addr;
-	tmp.irq = info->irq;
-	tmp.flags = info->flags;
-	tmp.baud_base = info->baud_base;
-	tmp.close_delay = info->close_delay;
-	tmp.closing_wait = info->closing_wait;
-	tmp.custom_divisor = info->custom_divisor;
-	return copy_to_user(retinfo,&tmp,sizeof(*retinfo)) ? -EFAULT : 0;
-}
-
-static int set_serial_info(struct mcf_serial * info,
-			   struct serial_struct * new_info)
-{
-	struct serial_struct new_serial;
-	struct mcf_serial old_info;
-	int 	retval = 0;
-
-	if (!new_info)
-		return -EFAULT;
-	if (copy_from_user(&new_serial,new_info,sizeof(new_serial)))
-		return -EFAULT;
-	old_info = *info;
-
-	if (!capable(CAP_SYS_ADMIN)) {
-		if ((new_serial.baud_base != info->baud_base) ||
-		    (new_serial.type != info->type) ||
-		    (new_serial.close_delay != info->close_delay) ||
-		    ((new_serial.flags & ~ASYNC_USR_MASK) !=
-		     (info->flags & ~ASYNC_USR_MASK)))
-			return -EPERM;
-		info->flags = ((info->flags & ~ASYNC_USR_MASK) |
-			       (new_serial.flags & ASYNC_USR_MASK));
-		info->custom_divisor = new_serial.custom_divisor;
-		goto check_and_exit;
-	}
-
-	if (info->count > 1)
-		return -EBUSY;
-
-	/*
-	 * OK, past this point, all the error checking has been done.
-	 * At this point, we start making changes.....
-	 */
-
-	info->baud_base = new_serial.baud_base;
-	info->flags = ((info->flags & ~ASYNC_FLAGS) |
-			(new_serial.flags & ASYNC_FLAGS));
-	info->type = new_serial.type;
-	info->close_delay = new_serial.close_delay;
-	info->closing_wait = new_serial.closing_wait;
-
-check_and_exit:
-	retval = startup(info);
-	return retval;
-}
-
-/*
- * get_lsr_info - get line status register info
- *
- * Purpose: Let user call ioctl() to get info when the UART physically
- * 	    is emptied.  On bus types like RS485, the transmitter must
- * 	    release the bus after transmitting. This must be done when
- * 	    the transmit shift register is empty, not be done when the
- * 	    transmit holding register is empty.  This functionality
- * 	    allows an RS485 driver to be written in user space. 
- */
-static int get_lsr_info(struct mcf_serial * info, unsigned int *value)
-{
-	volatile unsigned char	*uartp;
-	unsigned long		flags;
-	unsigned char		status;
-
-	local_irq_save(flags);
-	uartp = info->addr;
-	status = (uartp[MCFUART_USR] & MCFUART_USR_TXEMPTY) ? TIOCSER_TEMT : 0;
-	local_irq_restore(flags);
-
-	return put_user(status,value);
-}
-
-/*
- * This routine sends a break character out the serial port.
- */
-static void send_break(	struct mcf_serial * info, int duration)
-{
-	volatile unsigned char	*uartp;
-	unsigned long		flags;
-
-	if (!info->addr)
-		return;
-	set_current_state(TASK_INTERRUPTIBLE);
-	uartp = info->addr;
-
-	local_irq_save(flags);
-	uartp[MCFUART_UCR] = MCFUART_UCR_CMDBREAKSTART;
-	schedule_timeout(duration);
-	uartp[MCFUART_UCR] = MCFUART_UCR_CMDBREAKSTOP;
-	local_irq_restore(flags);
-}
-
-static int mcfrs_tiocmget(struct tty_struct *tty, struct file *file)
-{
-	struct mcf_serial * info = (struct mcf_serial *)tty->driver_data;
-
-	if (serial_paranoia_check(info, tty->name, "mcfrs_ioctl"))
-		return -ENODEV;
-	if (tty->flags & (1 << TTY_IO_ERROR))
-		return -EIO;
-
-	return mcfrs_getsignals(info);
-}
-
-static int mcfrs_tiocmset(struct tty_struct *tty, struct file *file,
-			  unsigned int set, unsigned int clear)
-{
-	struct mcf_serial * info = (struct mcf_serial *)tty->driver_data;
-	int rts = -1, dtr = -1;
-
-	if (serial_paranoia_check(info, tty->name, "mcfrs_ioctl"))
-		return -ENODEV;
-	if (tty->flags & (1 << TTY_IO_ERROR))
-		return -EIO;
-
-	if (set & TIOCM_RTS)
-		rts = 1;
-	if (set & TIOCM_DTR)
-		dtr = 1;
-	if (clear & TIOCM_RTS)
-		rts = 0;
-	if (clear & TIOCM_DTR)
-		dtr = 0;
-
-	mcfrs_setsignals(info, dtr, rts);
-
-	return 0;
-}
-
-static int mcfrs_ioctl(struct tty_struct *tty, struct file * file,
-		    unsigned int cmd, unsigned long arg)
-{
-	struct mcf_serial * info = (struct mcf_serial *)tty->driver_data;
-	int retval, error;
-
-	if (serial_paranoia_check(info, tty->name, "mcfrs_ioctl"))
-		return -ENODEV;
-
-	if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
-	    (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGWILD)  &&
-	    (cmd != TIOCSERSWILD) && (cmd != TIOCSERGSTRUCT)) {
-		if (tty->flags & (1 << TTY_IO_ERROR))
-		    return -EIO;
-	}
-	
-	switch (cmd) {
-		case TCSBRK:	/* SVID version: non-zero arg --> no break */
-			retval = tty_check_change(tty);
-			if (retval)
-				return retval;
-			tty_wait_until_sent(tty, 0);
-			if (!arg)
-				send_break(info, HZ/4);	/* 1/4 second */
-			return 0;
-		case TCSBRKP:	/* support for POSIX tcsendbreak() */
-			retval = tty_check_change(tty);
-			if (retval)
-				return retval;
-			tty_wait_until_sent(tty, 0);
-			send_break(info, arg ? arg*(HZ/10) : HZ/4);
-			return 0;
-		case TIOCGSERIAL:
-			if (access_ok(VERIFY_WRITE, (void *) arg,
-						sizeof(struct serial_struct)))
-				return get_serial_info(info,
-					       (struct serial_struct *) arg);
-			return -EFAULT;
-		case TIOCSSERIAL:
-			return set_serial_info(info,
-					       (struct serial_struct *) arg);
-		case TIOCSERGETLSR: /* Get line status register */
-			if (access_ok(VERIFY_WRITE, (void *) arg,
-						sizeof(unsigned int)))
-				return get_lsr_info(info, (unsigned int *) arg);
-			return -EFAULT;
-		case TIOCSERGSTRUCT:
-			error = copy_to_user((struct mcf_serial *) arg,
-				    info, sizeof(struct mcf_serial));
-			if (error)
-				return -EFAULT;
-			return 0;
-			
-#ifdef TIOCSET422
-		case TIOCSET422: {
-			unsigned int val;
-			get_user(val, (unsigned int *) arg);
-			mcf_setpa(MCFPP_PA11, (val ? 0 : MCFPP_PA11));
-			break;
-		}
-		case TIOCGET422: {
-			unsigned int val;
-			val = (mcf_getpa() & MCFPP_PA11) ? 0 : 1;
-			put_user(val, (unsigned int *) arg);
-			break;
-		}
-#endif
-
-		default:
-			return -ENOIOCTLCMD;
-		}
-	return 0;
-}
-
-static void mcfrs_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
-{
-	struct mcf_serial *info = (struct mcf_serial *)tty->driver_data;
-
-	if (tty->termios->c_cflag == old_termios->c_cflag)
-		return;
-
-	mcfrs_change_speed(info);
-
-	if ((old_termios->c_cflag & CRTSCTS) &&
-	    !(tty->termios->c_cflag & CRTSCTS)) {
-		tty->hw_stopped = 0;
-		mcfrs_setsignals(info, -1, 1);
-#if 0
-		mcfrs_start(tty);
-#endif
-	}
-}
-
-/*
- * ------------------------------------------------------------
- * mcfrs_close()
- * 
- * This routine is called when the serial port gets closed.  First, we
- * wait for the last remaining data to be sent.  Then, we unlink its
- * S structure from the interrupt chain if necessary, and we free
- * that IRQ if nothing is left in the chain.
- * ------------------------------------------------------------
- */
-static void mcfrs_close(struct tty_struct *tty, struct file * filp)
-{
-	volatile unsigned char	*uartp;
-	struct mcf_serial	*info = (struct mcf_serial *)tty->driver_data;
-	unsigned long		flags;
-
-	if (!info || serial_paranoia_check(info, tty->name, "mcfrs_close"))
-		return;
-	
-	local_irq_save(flags);
-	
-	if (tty_hung_up_p(filp)) {
-		local_irq_restore(flags);
-		return;
-	}
-	
-#ifdef SERIAL_DEBUG_OPEN
-	printk("mcfrs_close ttyS%d, count = %d\n", info->line, info->count);
-#endif
-	if ((tty->count == 1) && (info->count != 1)) {
-		/*
-		 * Uh, oh.  tty->count is 1, which means that the tty
-		 * structure will be freed.  Info->count should always
-		 * be one in these conditions.  If it's greater than
-		 * one, we've got real problems, since it means the
-		 * serial port won't be shutdown.
-		 */
-		printk("MCFRS: bad serial port count; tty->count is 1, "
-		       "info->count is %d\n", info->count);
-		info->count = 1;
-	}
-	if (--info->count < 0) {
-		printk("MCFRS: bad serial port count for ttyS%d: %d\n",
-		       info->line, info->count);
-		info->count = 0;
-	}
-	if (info->count) {
-		local_irq_restore(flags);
-		return;
-	}
-	info->flags |= ASYNC_CLOSING;
-
-	/*
-	 * Now we wait for the transmit buffer to clear; and we notify 
-	 * the line discipline to only process XON/XOFF characters.
-	 */
-	tty->closing = 1;
-	if (info->closing_wait != ASYNC_CLOSING_WAIT_NONE)
-		tty_wait_until_sent(tty, info->closing_wait);
-
-	/*
-	 * At this point we stop accepting input.  To do this, we
-	 * disable the receive line status interrupts, and tell the
-	 * interrupt driver to stop checking the data ready bit in the
-	 * line status register.
-	 */
-	info->imr &= ~MCFUART_UIR_RXREADY;
-	uartp = info->addr;
-	uartp[MCFUART_UIMR] = info->imr;
-
-#if 0
-	/* FIXME: do we need to keep this enabled for console?? */
-	if (mcfrs_console_inited && (mcfrs_console_port == info->line)) {
-		/* Do not disable the UART */ ;
-	} else
-#endif
-	shutdown(info);
-	mcfrs_flush_buffer(tty);
-	tty_ldisc_flush(tty);
-	
-	tty->closing = 0;
-	info->event = 0;
-	info->port.tty = NULL;
-#if 0	
-	if (tty->ldisc.num != ldiscs[N_TTY].num) {
-		if (tty->ldisc.close)
-			(tty->ldisc.close)(tty);
-		tty->ldisc = ldiscs[N_TTY];
-		tty->termios->c_line = N_TTY;
-		if (tty->ldisc.open)
-			(tty->ldisc.open)(tty);
-	}
-#endif	
-	if (info->blocked_open) {
-		if (info->close_delay) {
-			msleep_interruptible(jiffies_to_msecs(info->close_delay));
-		}
-		wake_up_interruptible(&info->open_wait);
-	}
-	info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
-	wake_up_interruptible(&info->close_wait);
-	local_irq_restore(flags);
-}
-
-/*
- * mcfrs_wait_until_sent() --- wait until the transmitter is empty
- */
-static void
-mcfrs_wait_until_sent(struct tty_struct *tty, int timeout)
-{
-#ifdef	CONFIG_M5272
-#define	MCF5272_FIFO_SIZE	25		/* fifo size + shift reg */
-
-	struct mcf_serial * info = (struct mcf_serial *)tty->driver_data;
-	volatile unsigned char *uartp;
-	unsigned long orig_jiffies, fifo_time, char_time, fifo_cnt;
-
-	if (serial_paranoia_check(info, tty->name, "mcfrs_wait_until_sent"))
-		return;
-
-	orig_jiffies = jiffies;
-
-	/*
-	 * Set the check interval to be 1/5 of the approximate time
-	 * to send the entire fifo, and make it at least 1.  The check
-	 * interval should also be less than the timeout.
-	 *
-	 * Note: we have to use pretty tight timings here to satisfy
-	 * the NIST-PCTS.
-	 */
-	lock_kernel();
-
-	fifo_time = (MCF5272_FIFO_SIZE * HZ * 10) / info->baud;
-	char_time = fifo_time / 5;
-	if (char_time == 0)
-		char_time = 1;
-	if (timeout && timeout < char_time)
-		char_time = timeout;
-
-	/*
-	 * Clamp the timeout period at 2 * the time to empty the
-	 * fifo.  Just to be safe, set the minimum at .5 seconds.
-	 */
-	fifo_time *= 2;
-	if (fifo_time < (HZ/2))
-		fifo_time = HZ/2;
-	if (!timeout || timeout > fifo_time)
-		timeout = fifo_time;
-
-	/*
-	 * Account for the number of bytes in the UART
-	 * transmitter FIFO plus any byte being shifted out.
-	 */
-	uartp = (volatile unsigned char *) info->addr;
-	for (;;) {
-		fifo_cnt = (uartp[MCFUART_UTF] & MCFUART_UTF_TXB);
-		if ((uartp[MCFUART_USR] & (MCFUART_USR_TXREADY|
-				MCFUART_USR_TXEMPTY)) ==
-			MCFUART_USR_TXREADY)
-			fifo_cnt++;
-		if (fifo_cnt == 0)
-			break;
-		msleep_interruptible(jiffies_to_msecs(char_time));
-		if (signal_pending(current))
-			break;
-		if (timeout && time_after(jiffies, orig_jiffies + timeout))
-			break;
-	}
-	unlock_kernel();
-#else
-	/*
-	 * For the other coldfire models, assume all data has been sent
-	 */
-#endif
-}
-
-/*
- * mcfrs_hangup() --- called by tty_hangup() when a hangup is signaled.
- */
-void mcfrs_hangup(struct tty_struct *tty)
-{
-	struct mcf_serial * info = (struct mcf_serial *)tty->driver_data;
-	
-	if (serial_paranoia_check(info, tty->name, "mcfrs_hangup"))
-		return;
-	
-	mcfrs_flush_buffer(tty);
-	shutdown(info);
-	info->event = 0;
-	info->count = 0;
-	info->flags &= ~ASYNC_NORMAL_ACTIVE;
-	info->port.tty = NULL;
-	wake_up_interruptible(&info->open_wait);
-}
-
-/*
- * ------------------------------------------------------------
- * mcfrs_open() and friends
- * ------------------------------------------------------------
- */
-static int block_til_ready(struct tty_struct *tty, struct file * filp,
-			   struct mcf_serial *info)
-{
-	DECLARE_WAITQUEUE(wait, current);
-	int	retval;
-	int	do_clocal = 0;
-
-	/*
-	 * If the device is in the middle of being closed, then block
-	 * until it's done, and then try again.
-	 */
-	if (info->flags & ASYNC_CLOSING) {
-		interruptible_sleep_on(&info->close_wait);
-#ifdef SERIAL_DO_RESTART
-		if (info->flags & ASYNC_HUP_NOTIFY)
-			return -EAGAIN;
-		else
-			return -ERESTARTSYS;
-#else
-		return -EAGAIN;
-#endif
-	}
-	
-	/*
-	 * If non-blocking mode is set, or the port is not enabled,
-	 * then make the check up front and then exit.
-	 */
-	if ((filp->f_flags & O_NONBLOCK) ||
-	    (tty->flags & (1 << TTY_IO_ERROR))) {
-		info->flags |= ASYNC_NORMAL_ACTIVE;
-		return 0;
-	}
-
-	if (tty->termios->c_cflag & CLOCAL)
-		do_clocal = 1;
-
-	/*
-	 * Block waiting for the carrier detect and the line to become
-	 * free (i.e., not in use by the callout).  While we are in
-	 * this loop, info->count is dropped by one, so that
-	 * mcfrs_close() knows when to free things.  We restore it upon
-	 * exit, either normal or abnormal.
-	 */
-	retval = 0;
-	add_wait_queue(&info->open_wait, &wait);
-#ifdef SERIAL_DEBUG_OPEN
-	printk("block_til_ready before block: ttyS%d, count = %d\n",
-	       info->line, info->count);
-#endif
-	info->count--;
-	info->blocked_open++;
-	while (1) {
-		local_irq_disable();
-		mcfrs_setsignals(info, 1, 1);
-		local_irq_enable();
-		current->state = TASK_INTERRUPTIBLE;
-		if (tty_hung_up_p(filp) ||
-		    !(info->flags & ASYNC_INITIALIZED)) {
-#ifdef SERIAL_DO_RESTART
-			if (info->flags & ASYNC_HUP_NOTIFY)
-				retval = -EAGAIN;
-			else
-				retval = -ERESTARTSYS;	
-#else
-			retval = -EAGAIN;
-#endif
-			break;
-		}
-		if (!(info->flags & ASYNC_CLOSING) &&
-		    (do_clocal || (mcfrs_getsignals(info) & TIOCM_CD)))
-			break;
-		if (signal_pending(current)) {
-			retval = -ERESTARTSYS;
-			break;
-		}
-#ifdef SERIAL_DEBUG_OPEN
-		printk("block_til_ready blocking: ttyS%d, count = %d\n",
-		       info->line, info->count);
-#endif
-		schedule();
-	}
-	current->state = TASK_RUNNING;
-	remove_wait_queue(&info->open_wait, &wait);
-	if (!tty_hung_up_p(filp))
-		info->count++;
-	info->blocked_open--;
-#ifdef SERIAL_DEBUG_OPEN
-	printk("block_til_ready after blocking: ttyS%d, count = %d\n",
-	       info->line, info->count);
-#endif
-	if (retval)
-		return retval;
-	info->flags |= ASYNC_NORMAL_ACTIVE;
-	return 0;
-}	
-
-/*
- * This routine is called whenever a serial port is opened. It
- * enables interrupts for a serial port, linking in its structure into
- * the IRQ chain.   It also performs the serial-specific
- * initialization for the tty structure.
- */
-int mcfrs_open(struct tty_struct *tty, struct file * filp)
-{
-	struct mcf_serial	*info;
-	int 			retval, line;
-
-	line = tty->index;
-	if ((line < 0) || (line >= NR_PORTS))
-		return -ENODEV;
-	info = mcfrs_table + line;
-	if (serial_paranoia_check(info, tty->name, "mcfrs_open"))
-		return -ENODEV;
-#ifdef SERIAL_DEBUG_OPEN
-	printk("mcfrs_open %s, count = %d\n", tty->name, info->count);
-#endif
-	info->count++;
-	tty->driver_data = info;
-	info->port.tty = tty;
-
-	/*
-	 * Start up serial port
-	 */
-	retval = startup(info);
-	if (retval)
-		return retval;
-
-	retval = block_til_ready(tty, filp, info);
-	if (retval) {
-#ifdef SERIAL_DEBUG_OPEN
-		printk("mcfrs_open returning after block_til_ready with %d\n",
-		       retval);
-#endif
-		return retval;
-	}
-
-#ifdef SERIAL_DEBUG_OPEN
-	printk("mcfrs_open %s successful...\n", tty->name);
-#endif
-	return 0;
-}
-
-/*
- *	Based on the line number set up the internal interrupt stuff.
- */
-static void mcfrs_irqinit(struct mcf_serial *info)
-{
-#if defined(CONFIG_M5272)
-	volatile unsigned long	*icrp;
-	volatile unsigned long	*portp;
-	volatile unsigned char	*uartp;
-
-	uartp = info->addr;
-	icrp = (volatile unsigned long *) (MCF_MBAR + MCFSIM_ICR2);
-
-	switch (info->line) {
-	case 0:
-		*icrp = 0xe0000000;
-		break;
-	case 1:
-		*icrp = 0x0e000000;
-		break;
-	default:
-		printk("MCFRS: don't know how to handle UART %d interrupt?\n",
-			info->line);
-		return;
-	}
-
-	/* Enable the output lines for the serial ports */
-	portp = (volatile unsigned long *) (MCF_MBAR + MCFSIM_PBCNT);
-	*portp = (*portp & ~0x000000ff) | 0x00000055;
-	portp = (volatile unsigned long *) (MCF_MBAR + MCFSIM_PDCNT);
-	*portp = (*portp & ~0x000003fc) | 0x000002a8;
-#elif defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x)
-	volatile unsigned char *icrp, *uartp;
-	volatile unsigned long *imrp;
-
-	uartp = info->addr;
-
-	icrp = (volatile unsigned char *) (MCF_MBAR + MCFICM_INTC0 +
-		MCFINTC_ICR0 + MCFINT_UART0 + info->line);
-	*icrp = 0x30 + info->line; /* level 6, line based priority */
-
-	imrp = (volatile unsigned long *) (MCF_MBAR + MCFICM_INTC0 +
-		MCFINTC_IMRL);
-	*imrp &= ~((1 << (info->irq - MCFINT_VECBASE)) | 1);
-#if defined(CONFIG_M527x)
-	{
-		/*
-		 * External Pin Mask Setting & Enable External Pin for Interface
-		 * mrcbis@aliceposta.it
-        	 */
-		u16 *serpin_enable_mask;
-		serpin_enable_mask = (u16 *) (MCF_IPSBAR + MCF_GPIO_PAR_UART);
-		if (info->line == 0)
-			*serpin_enable_mask |= UART0_ENABLE_MASK;
-		else if (info->line == 1)
-			*serpin_enable_mask |= UART1_ENABLE_MASK;
-		else if (info->line == 2)
-			*serpin_enable_mask |= UART2_ENABLE_MASK;
-	}
-#endif
-#if defined(CONFIG_M528x)
-	/* make sure PUAPAR is set for UART0 and UART1 */
-	if (info->line < 2) {
-		volatile unsigned char *portp = (volatile unsigned char *) (MCF_MBAR + MCF5282_GPIO_PUAPAR);
-		*portp |= (0x03 << (info->line * 2));
-	}
-#endif
-#elif defined(CONFIG_M520x)
-	volatile unsigned char *icrp, *uartp;
-	volatile unsigned long *imrp;
-
-	uartp = info->addr;
-
-	icrp = (volatile unsigned char *) (MCF_MBAR + MCFICM_INTC0 +
-		MCFINTC_ICR0 + MCFINT_UART0 + info->line);
-	*icrp = 0x03;
-
-	imrp = (volatile unsigned long *) (MCF_MBAR + MCFICM_INTC0 +
-		MCFINTC_IMRL);
-	*imrp &= ~((1 << (info->irq - MCFINT_VECBASE)) | 1);
-	if (info->line < 2) {
-		unsigned short *uart_par;
-		uart_par = (unsigned short *)(MCF_IPSBAR + MCF_GPIO_PAR_UART);
-		if (info->line == 0)
-			*uart_par |=  MCF_GPIO_PAR_UART_PAR_UTXD0
-				  | MCF_GPIO_PAR_UART_PAR_URXD0;
-		else if (info->line == 1)
-			*uart_par |=  MCF_GPIO_PAR_UART_PAR_UTXD1
-				  | MCF_GPIO_PAR_UART_PAR_URXD1;
-		} else if (info->line == 2) {
-			unsigned char *feci2c_par;
-			feci2c_par = (unsigned char *)(MCF_IPSBAR +  MCF_GPIO_PAR_FECI2C);
-			*feci2c_par &= ~0x0F;
-			*feci2c_par |=  MCF_GPIO_PAR_FECI2C_PAR_SCL_UTXD2
-				    | MCF_GPIO_PAR_FECI2C_PAR_SDA_URXD2;
-		}
-#elif defined(CONFIG_M532x)
-	volatile unsigned char *uartp;
-	uartp = info->addr;
-	switch (info->line) {
-	case 0:
-		MCF_INTC0_ICR26 = 0x3;
-		MCF_INTC0_CIMR = 26;
-		/* GPIO initialization */
-		MCF_GPIO_PAR_UART |= 0x000F;
-		break;
-	case 1:
-		MCF_INTC0_ICR27 = 0x3;
-		MCF_INTC0_CIMR = 27;
-		/* GPIO initialization */
-		MCF_GPIO_PAR_UART |= 0x0FF0;
-		break;
-	case 2:
-		MCF_INTC0_ICR28 = 0x3;
-		MCF_INTC0_CIMR = 28;
-		/* GPIOs also must be initalized, depends on board */
-		break;
-	}
-#else
-	volatile unsigned char	*icrp, *uartp;
-
-	switch (info->line) {
-	case 0:
-		icrp = (volatile unsigned char *) (MCF_MBAR + MCFSIM_UART1ICR);
-		*icrp = /*MCFSIM_ICR_AUTOVEC |*/ MCFSIM_ICR_LEVEL6 |
-			MCFSIM_ICR_PRI1;
-		mcf_setimr(mcf_getimr() & ~MCFSIM_IMR_UART1);
-		break;
-	case 1:
-		icrp = (volatile unsigned char *) (MCF_MBAR + MCFSIM_UART2ICR);
-		*icrp = /*MCFSIM_ICR_AUTOVEC |*/ MCFSIM_ICR_LEVEL6 |
-			MCFSIM_ICR_PRI2;
-		mcf_setimr(mcf_getimr() & ~MCFSIM_IMR_UART2);
-		break;
-	default:
-		printk("MCFRS: don't know how to handle UART %d interrupt?\n",
-			info->line);
-		return;
-	}
-
-	uartp = info->addr;
-	uartp[MCFUART_UIVR] = info->irq;
-#endif
-
-	/* Clear mask, so no surprise interrupts. */
-	uartp[MCFUART_UIMR] = 0;
-
-	if (request_irq(info->irq, mcfrs_interrupt, IRQF_DISABLED,
-	    "ColdFire UART", NULL)) {
-		printk("MCFRS: Unable to attach ColdFire UART %d interrupt "
-			"vector=%d\n", info->line, info->irq);
-	}
-
-	return;
-}
-
-
-char *mcfrs_drivername = "ColdFire internal UART serial driver version 1.00\n";
-
-
-/*
- * Serial stats reporting...
- */
-int mcfrs_readproc(char *page, char **start, off_t off, int count,
-		         int *eof, void *data)
-{
-	struct mcf_serial	*info;
-	char			str[20];
-	int			len, sigs, i;
-
-	len = sprintf(page, mcfrs_drivername);
-	for (i = 0; (i < NR_PORTS); i++) {
-		info = &mcfrs_table[i];
-		len += sprintf((page + len), "%d: port:%x irq=%d baud:%d ",
-			i, (unsigned int) info->addr, info->irq, info->baud);
-		if (info->stats.rx || info->stats.tx)
-			len += sprintf((page + len), "tx:%d rx:%d ",
-			info->stats.tx, info->stats.rx);
-		if (info->stats.rxframing)
-			len += sprintf((page + len), "fe:%d ",
-			info->stats.rxframing);
-		if (info->stats.rxparity)
-			len += sprintf((page + len), "pe:%d ",
-			info->stats.rxparity);
-		if (info->stats.rxbreak)
-			len += sprintf((page + len), "brk:%d ",
-			info->stats.rxbreak);
-		if (info->stats.rxoverrun)
-			len += sprintf((page + len), "oe:%d ",
-			info->stats.rxoverrun);
-
-		str[0] = str[1] = 0;
-		if ((sigs = mcfrs_getsignals(info))) {
-			if (sigs & TIOCM_RTS)
-				strcat(str, "|RTS");
-			if (sigs & TIOCM_CTS)
-				strcat(str, "|CTS");
-			if (sigs & TIOCM_DTR)
-				strcat(str, "|DTR");
-			if (sigs & TIOCM_CD)
-				strcat(str, "|CD");
-		}
-
-		len += sprintf((page + len), "%s\n", &str[1]);
-	}
-
-	return(len);
-}
-
-
-/* Finally, routines used to initialize the serial driver. */
-
-static void show_serial_version(void)
-{
-	printk(mcfrs_drivername);
-}
-
-static const struct tty_operations mcfrs_ops = {
-	.open = mcfrs_open,
-	.close = mcfrs_close,
-	.write = mcfrs_write,
-	.flush_chars = mcfrs_flush_chars,
-	.write_room = mcfrs_write_room,
-	.chars_in_buffer = mcfrs_chars_in_buffer,
-	.flush_buffer = mcfrs_flush_buffer,
-	.ioctl = mcfrs_ioctl,
-	.throttle = mcfrs_throttle,
-	.unthrottle = mcfrs_unthrottle,
-	.set_termios = mcfrs_set_termios,
-	.stop = mcfrs_stop,
-	.start = mcfrs_start,
-	.hangup = mcfrs_hangup,
-	.read_proc = mcfrs_readproc,
-	.wait_until_sent = mcfrs_wait_until_sent,
- 	.tiocmget = mcfrs_tiocmget,
-	.tiocmset = mcfrs_tiocmset,
-};
-
-/* mcfrs_init inits the driver */
-static int __init
-mcfrs_init(void)
-{
-	struct mcf_serial	*info;
-	unsigned long		flags;
-	int			i;
-
-	/* Setup base handler, and timer table. */
-#ifdef MCFPP_DCD0
-	init_timer(&mcfrs_timer_struct);
-	mcfrs_timer_struct.function = mcfrs_timer;
-	mcfrs_timer_struct.data = 0;
-	mcfrs_timer_struct.expires = jiffies + HZ/25;
-	add_timer(&mcfrs_timer_struct);
-	mcfrs_ppstatus = mcf_getppdata() & (MCFPP_DCD0 | MCFPP_DCD1);
-#endif
-	mcfrs_serial_driver = alloc_tty_driver(NR_PORTS);
-	if (!mcfrs_serial_driver)
-		return -ENOMEM;
-
-	show_serial_version();
-
-	/* Initialize the tty_driver structure */
-	mcfrs_serial_driver->owner = THIS_MODULE;
-	mcfrs_serial_driver->name = "ttyS";
-	mcfrs_serial_driver->driver_name = "mcfserial";
-	mcfrs_serial_driver->major = TTY_MAJOR;
-	mcfrs_serial_driver->minor_start = 64;
-	mcfrs_serial_driver->type = TTY_DRIVER_TYPE_SERIAL;
-	mcfrs_serial_driver->subtype = SERIAL_TYPE_NORMAL;
-	mcfrs_serial_driver->init_termios = tty_std_termios;
-
-	mcfrs_serial_driver->init_termios.c_cflag =
-		mcfrs_console_cbaud | CS8 | CREAD | HUPCL | CLOCAL;
-	mcfrs_serial_driver->flags = TTY_DRIVER_REAL_RAW;
-
-	tty_set_operations(mcfrs_serial_driver, &mcfrs_ops);
-
-	if (tty_register_driver(mcfrs_serial_driver)) {
-		printk("MCFRS: Couldn't register serial driver\n");
-		put_tty_driver(mcfrs_serial_driver);
-		return(-EBUSY);
-	}
-
-	local_irq_save(flags);
-
-	/*
-	 *	Configure all the attached serial ports.
-	 */
-	for (i = 0, info = mcfrs_table; (i < NR_PORTS); i++, info++) {
-		info->magic = SERIAL_MAGIC;
-		info->line = i;
-		info->port.tty = NULL;
-		info->custom_divisor = 16;
-		info->close_delay = 50;
-		info->closing_wait = 3000;
-		info->x_char = 0;
-		info->event = 0;
-		info->count = 0;
-		info->blocked_open = 0;
-		INIT_WORK(&info->tqueue, mcfrs_offintr);
-		INIT_WORK(&info->tqueue_hangup, do_serial_hangup);
-		init_waitqueue_head(&info->open_wait);
-		init_waitqueue_head(&info->close_wait);
-
-		info->imr = 0;
-		mcfrs_setsignals(info, 0, 0);
-		mcfrs_irqinit(info);
-
-		printk("ttyS%d at 0x%04x (irq = %d)", info->line,
-			(unsigned int) info->addr, info->irq);
-		printk(" is a builtin ColdFire UART\n");
-	}
-
-	local_irq_restore(flags);
-	return 0;
-}
-
-module_init(mcfrs_init);
-
-/****************************************************************************/
-/*                          Serial Console                                  */
-/****************************************************************************/
-
-/*
- *	Quick and dirty UART initialization, for console output.
- */
-
-void mcfrs_init_console(void)
-{
-	volatile unsigned char	*uartp;
-	unsigned int		clk;
-
-	/*
-	 *	Reset UART, get it into known state...
-	 */
-	uartp = (volatile unsigned char *) (MCF_MBAR +
-		(mcfrs_console_port ? MCFUART_BASE2 : MCFUART_BASE1));
-
-	uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETRX;  /* reset RX */
-	uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETTX;  /* reset TX */
-	uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETMRPTR;  /* reset MR pointer */
-
-	/*
-	 * Set port for defined baud , 8 data bits, 1 stop bit, no parity.
-	 */
-	uartp[MCFUART_UMR] = MCFUART_MR1_PARITYNONE | MCFUART_MR1_CS8;
-	uartp[MCFUART_UMR] = MCFUART_MR2_STOP1;
-
-#ifdef	CONFIG_M5272
-{
-	/*
-	 * For the MCF5272, also compute the baudrate fraction.
-	 */
-	int fraction = MCF_BUSCLK - (clk * 32 * mcfrs_console_baud);
-	fraction *= 16;
-	fraction /= (32 * mcfrs_console_baud);
-	uartp[MCFUART_UFPD] = (fraction & 0xf);		/* set fraction */
-	clk = (MCF_BUSCLK / mcfrs_console_baud) / 32;
-}
-#else
-	clk = ((MCF_BUSCLK / mcfrs_console_baud) + 16) / 32; /* set baud */
-#endif
-
-	uartp[MCFUART_UBG1] = (clk & 0xff00) >> 8;  /* set msb baud */
-	uartp[MCFUART_UBG2] = (clk & 0xff);  /* set lsb baud */
-	uartp[MCFUART_UCSR] = MCFUART_UCSR_RXCLKTIMER | MCFUART_UCSR_TXCLKTIMER;
-	uartp[MCFUART_UCR] = MCFUART_UCR_RXENABLE | MCFUART_UCR_TXENABLE;
-
-	mcfrs_console_inited++;
-	return;
-}
-
-
-/*
- *	Setup for console. Argument comes from the boot command line.
- */
-
-int mcfrs_console_setup(struct console *cp, char *arg)
-{
-	int		i, n = CONSOLE_BAUD_RATE;
-
-	if (!cp)
-		return(-1);
-
-	if (!strncmp(cp->name, "ttyS", 4))
-		mcfrs_console_port = cp->index;
-	else if (!strncmp(cp->name, "cua", 3))
-		mcfrs_console_port = cp->index;
-	else
-		return(-1);
-
-	if (arg)
-		n = simple_strtoul(arg,NULL,0);
-	for (i = 0; i < MCFRS_BAUD_TABLE_SIZE; i++)
-		if (mcfrs_baud_table[i] == n)
-			break;
-	if (i < MCFRS_BAUD_TABLE_SIZE) {
-		mcfrs_console_baud = n;
-		mcfrs_console_cbaud = 0;
-		if (i > 15) {
-			mcfrs_console_cbaud |= CBAUDEX;
-			i -= 15;
-		}
-		mcfrs_console_cbaud |= i;
-	}
-	mcfrs_init_console(); /* make sure baud rate changes */
-	return(0);
-}
-
-
-static struct tty_driver *mcfrs_console_device(struct console *c, int *index)
-{
-	*index = c->index;
-	return mcfrs_serial_driver;
-}
-
-
-/*
- *	Output a single character, using UART polled mode.
- *	This is used for console output.
- */
-
-int mcfrs_put_char(char ch)
-{
-	volatile unsigned char	*uartp;
-	unsigned long		flags;
-	int			i;
-
-	uartp = (volatile unsigned char *) (MCF_MBAR +
-		(mcfrs_console_port ? MCFUART_BASE2 : MCFUART_BASE1));
-
-	local_irq_save(flags);
-	for (i = 0; (i < 0x10000); i++) {
-		if (uartp[MCFUART_USR] & MCFUART_USR_TXREADY)
-			break;
-	}
-	if (i < 0x10000) {
-		uartp[MCFUART_UTB] = ch;
-		for (i = 0; (i < 0x10000); i++)
-			if (uartp[MCFUART_USR] & MCFUART_USR_TXEMPTY)
-				break;
-	}
-	if (i >= 0x10000)
-		mcfrs_init_console(); /* try and get it back */
-	local_irq_restore(flags);
-
-	return 1;
-}
-
-
-/*
- * rs_console_write is registered for printk output.
- */
-
-void mcfrs_console_write(struct console *cp, const char *p, unsigned len)
-{
-	if (!mcfrs_console_inited)
-		mcfrs_init_console();
-	while (len-- > 0) {
-		if (*p == '\n')
-			mcfrs_put_char('\r');
-		mcfrs_put_char(*p++);
-	}
-}
-
-/*
- * declare our consoles
- */
-
-struct console mcfrs_console = {
-	.name		= "ttyS",
-	.write		= mcfrs_console_write,
-	.device		= mcfrs_console_device,
-	.setup		= mcfrs_console_setup,
-	.flags		= CON_PRINTBUFFER,
-	.index		= -1,
-};
-
-static int __init mcfrs_console_init(void)
-{
-	register_console(&mcfrs_console);
-	return 0;
-}
-
-console_initcall(mcfrs_console_init);
-
-/****************************************************************************/
diff --git a/drivers/serial/mcfserial.h b/drivers/serial/mcfserial.h
deleted file mode 100644
index 56420e2..0000000
--- a/drivers/serial/mcfserial.h
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * mcfserial.c -- serial driver for ColdFire internal UARTS.
- *
- * Copyright (c) 1999 Greg Ungerer <gerg@snapgear.com>
- * Copyright (c) 2000-2001 Lineo, Inc. <www.lineo.com>
- * Copyright (c) 2002 SnapGear Inc., <www.snapgear.com>
- *
- * Based on code from 68332serial.c which was:
- *
- * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
- * Copyright (C) 1998 TSHG
- * Copyright (c) 1999 Rt-Control Inc. <jeff@uclinux.org>
- */ 
-#ifndef _MCF_SERIAL_H
-#define _MCF_SERIAL_H
-
-#include <linux/serial.h>
-
-#ifdef __KERNEL__
-
-/*
- *	Define a local serial stats structure.
- */
-
-struct mcf_stats {
-	unsigned int	rx;
-	unsigned int	tx;
-	unsigned int	rxbreak;
-	unsigned int	rxframing;
-	unsigned int	rxparity;
-	unsigned int	rxoverrun;
-};
-
-
-/*
- * This is our internal structure for each serial port's state.
- * Each serial port has one of these structures associated with it.
- */
-
-struct mcf_serial {
-	int			magic;
-	volatile unsigned char	*addr;		/* UART memory address */
-	int			irq;
-	int			flags; 		/* defined in tty.h */
-	int			type; 		/* UART type */
-	struct tty_struct 	*tty;
-	unsigned char		imr;		/* Software imr register */
-	unsigned int		baud;
-	int			sigs;
-	int			custom_divisor;
-	int			x_char;	/* xon/xoff character */
-	int			baud_base;
-	int			close_delay;
-	unsigned short		closing_wait;
-	unsigned short		closing_wait2;
-	unsigned long		event;
-	int			line;
-	int			count;	    /* # of fd on device */
-	int			blocked_open; /* # of blocked opens */
-	unsigned char 		*xmit_buf;
-	int			xmit_head;
-	int			xmit_tail;
-	int			xmit_cnt;
-	struct mcf_stats	stats;
-	struct work_struct	tqueue;
-	struct work_struct	tqueue_hangup;
-	wait_queue_head_t	open_wait;
-	wait_queue_head_t	close_wait;
-
-};
-
-#endif /* __KERNEL__ */
-
-#endif /* _MCF_SERIAL_H */
diff --git a/drivers/serial/pxa.c b/drivers/serial/pxa.c
index f7a0d37..abc00be 100644
--- a/drivers/serial/pxa.c
+++ b/drivers/serial/pxa.c
@@ -534,6 +534,11 @@
 
 	serial_out(up, UART_IER, up->ier);
 
+	if (termios->c_cflag & CRTSCTS)
+		up->mcr |= UART_MCR_AFE;
+	else
+		up->mcr &= ~UART_MCR_AFE;
+
 	serial_out(up, UART_LCR, cval | UART_LCR_DLAB);/* set DLAB */
 	serial_out(up, UART_DLL, quot & 0xff);		/* LS of divisor */
 	serial_out(up, UART_DLM, quot >> 8);		/* MS of divisor */
diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c
index f977c98..6bdf336 100644
--- a/drivers/serial/serial_core.c
+++ b/drivers/serial/serial_core.c
@@ -2051,7 +2051,8 @@
 					"transmitter\n",
 			       port->dev ? port->dev->bus_id : "",
 			       port->dev ? ": " : "",
-			       drv->dev_name, port->line);
+			       drv->dev_name,
+			       drv->tty_driver->name_base + port->line);
 
 		ops->shutdown(port);
 	}
@@ -2154,12 +2155,11 @@
 
 	switch (port->iotype) {
 	case UPIO_PORT:
-		snprintf(address, sizeof(address),
-			 "I/O 0x%x", port->iobase);
+		snprintf(address, sizeof(address), "I/O 0x%lx", port->iobase);
 		break;
 	case UPIO_HUB6:
 		snprintf(address, sizeof(address),
-			 "I/O 0x%x offset 0x%x", port->iobase, port->hub6);
+			 "I/O 0x%lx offset 0x%x", port->iobase, port->hub6);
 		break;
 	case UPIO_MEM:
 	case UPIO_MEM32:
@@ -2177,7 +2177,9 @@
 	printk(KERN_INFO "%s%s%s%d at %s (irq = %d) is a %s\n",
 	       port->dev ? port->dev->bus_id : "",
 	       port->dev ? ": " : "",
-	       drv->dev_name, port->line, address, port->irq, uart_type(port));
+	       drv->dev_name,
+	       drv->tty_driver->name_base + port->line,
+	       address, port->irq, uart_type(port));
 }
 
 static void
diff --git a/drivers/serial/serial_cs.c b/drivers/serial/serial_cs.c
index 164d2a4..7546aa8 100644
--- a/drivers/serial/serial_cs.c
+++ b/drivers/serial/serial_cs.c
@@ -431,131 +431,103 @@
 {
 	int i;
 	i = pcmcia_get_first_tuple(handle, tuple);
-	if (i != CS_SUCCESS)
-		return CS_NO_MORE_ITEMS;
-	i = pcmcia_get_tuple_data(handle, tuple);
-	if (i != CS_SUCCESS)
+	if (i != 0)
 		return i;
-	return pcmcia_parse_tuple(handle, tuple, parse);
-}
-
-static int
-next_tuple(struct pcmcia_device *handle, tuple_t * tuple, cisparse_t * parse)
-{
-	int i;
-	i = pcmcia_get_next_tuple(handle, tuple);
-	if (i != CS_SUCCESS)
-		return CS_NO_MORE_ITEMS;
 	i = pcmcia_get_tuple_data(handle, tuple);
-	if (i != CS_SUCCESS)
+	if (i != 0)
 		return i;
-	return pcmcia_parse_tuple(handle, tuple, parse);
+	return pcmcia_parse_tuple(tuple, parse);
 }
 
 /*====================================================================*/
 
-static int simple_config(struct pcmcia_device *link)
+static int simple_config_check(struct pcmcia_device *p_dev,
+			       cistpl_cftable_entry_t *cf,
+			       cistpl_cftable_entry_t *dflt,
+			       unsigned int vcc,
+			       void *priv_data)
+{
+	static const int size_table[2] = { 8, 16 };
+	int *try = priv_data;
+
+	if (cf->vpp1.present & (1 << CISTPL_POWER_VNOM))
+		p_dev->conf.Vpp =
+			cf->vpp1.param[CISTPL_POWER_VNOM] / 10000;
+
+	if ((cf->io.nwin > 0) && (cf->io.win[0].len == size_table[(*try >> 1)])
+	    && (cf->io.win[0].base != 0)) {
+		p_dev->io.BasePort1 = cf->io.win[0].base;
+		p_dev->io.IOAddrLines = ((*try & 0x1) == 0) ?
+			16 : cf->io.flags & CISTPL_IO_LINES_MASK;
+		if (!pcmcia_request_io(p_dev, &p_dev->io))
+			return 0;
+	}
+	return -EINVAL;
+}
+
+static int simple_config_check_notpicky(struct pcmcia_device *p_dev,
+					cistpl_cftable_entry_t *cf,
+					cistpl_cftable_entry_t *dflt,
+					unsigned int vcc,
+					void *priv_data)
 {
 	static const unsigned int base[5] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x0 };
-	static const int size_table[2] = { 8, 16 };
+	int j;
+
+	if ((cf->io.nwin > 0) && ((cf->io.flags & CISTPL_IO_LINES_MASK) <= 3)) {
+		for (j = 0; j < 5; j++) {
+			p_dev->io.BasePort1 = base[j];
+			p_dev->io.IOAddrLines = base[j] ? 16 : 3;
+			if (!pcmcia_request_io(p_dev, &p_dev->io))
+				return 0;
+		}
+	}
+	return -ENODEV;
+}
+
+static int simple_config(struct pcmcia_device *link)
+{
 	struct serial_info *info = link->priv;
-	struct serial_cfg_mem *cfg_mem;
-	tuple_t *tuple;
-	u_char *buf;
-	cisparse_t *parse;
-	cistpl_cftable_entry_t *cf;
-	config_info_t config;
-	int i, j, try;
-	int s;
-
-	cfg_mem = kmalloc(sizeof(struct serial_cfg_mem), GFP_KERNEL);
-	if (!cfg_mem)
-		return -1;
-
-	tuple = &cfg_mem->tuple;
-	parse = &cfg_mem->parse;
-	cf = &parse->cftable_entry;
-	buf = cfg_mem->buf;
+	int i = -ENODEV, try;
 
 	/* If the card is already configured, look up the port and irq */
-	i = pcmcia_get_configuration_info(link, &config);
-	if ((i == CS_SUCCESS) && (config.Attributes & CONF_VALID_CLIENT)) {
+	if (link->function_config) {
 		unsigned int port = 0;
-		if ((config.BasePort2 != 0) && (config.NumPorts2 == 8)) {
-			port = config.BasePort2;
+		if ((link->io.BasePort2 != 0) &&
+		    (link->io.NumPorts2 == 8)) {
+			port = link->io.BasePort2;
 			info->slave = 1;
 		} else if ((info->manfid == MANFID_OSITECH) &&
-			   (config.NumPorts1 == 0x40)) {
-			port = config.BasePort1 + 0x28;
+			   (link->io.NumPorts1 == 0x40)) {
+			port = link->io.BasePort1 + 0x28;
 			info->slave = 1;
 		}
 		if (info->slave) {
-			kfree(cfg_mem);
-			return setup_serial(link, info, port, config.AssignedIRQ);
+			return setup_serial(link, info, port,
+					    link->irq.AssignedIRQ);
 		}
 	}
 
-	/* First pass: look for a config entry that looks normal. */
-	tuple->TupleData = (cisdata_t *) buf;
-	tuple->TupleOffset = 0;
-	tuple->TupleDataMax = 255;
-	tuple->Attributes = 0;
-	tuple->DesiredTuple = CISTPL_CFTABLE_ENTRY;
-	/* Two tries: without IO aliases, then with aliases */
-	for (s = 0; s < 2; s++) {
-		for (try = 0; try < 2; try++) {
-			i = first_tuple(link, tuple, parse);
-			while (i != CS_NO_MORE_ITEMS) {
-				if (i != CS_SUCCESS)
-					goto next_entry;
-				if (cf->vpp1.present & (1 << CISTPL_POWER_VNOM))
-					link->conf.Vpp =
-					    cf->vpp1.param[CISTPL_POWER_VNOM] / 10000;
-				if ((cf->io.nwin > 0) && (cf->io.win[0].len == size_table[s]) &&
-					    (cf->io.win[0].base != 0)) {
-					link->conf.ConfigIndex = cf->index;
-					link->io.BasePort1 = cf->io.win[0].base;
-					link->io.IOAddrLines = (try == 0) ?
-					    16 : cf->io.flags & CISTPL_IO_LINES_MASK;
-					i = pcmcia_request_io(link, &link->io);
-					if (i == CS_SUCCESS)
-						goto found_port;
-				}
-next_entry:
-				i = next_tuple(link, tuple, parse);
-			}
-		}
-	}
+	/* First pass: look for a config entry that looks normal.
+	 * Two tries: without IO aliases, then with aliases */
+	for (try = 0; try < 4; try++)
+		if (!pcmcia_loop_config(link, simple_config_check, &try))
+			goto found_port;
+
 	/* Second pass: try to find an entry that isn't picky about
 	   its base address, then try to grab any standard serial port
 	   address, and finally try to get any free port. */
-	i = first_tuple(link, tuple, parse);
-	while (i != CS_NO_MORE_ITEMS) {
-		if ((i == CS_SUCCESS) && (cf->io.nwin > 0) &&
-		    ((cf->io.flags & CISTPL_IO_LINES_MASK) <= 3)) {
-			link->conf.ConfigIndex = cf->index;
-			for (j = 0; j < 5; j++) {
-				link->io.BasePort1 = base[j];
-				link->io.IOAddrLines = base[j] ? 16 : 3;
-				i = pcmcia_request_io(link, &link->io);
-				if (i == CS_SUCCESS)
-					goto found_port;
-			}
-		}
-		i = next_tuple(link, tuple, parse);
-	}
+	if (!pcmcia_loop_config(link, simple_config_check_notpicky, NULL))
+		goto found_port;
 
-      found_port:
-	if (i != CS_SUCCESS) {
-		printk(KERN_NOTICE
-		       "serial_cs: no usable port range found, giving up\n");
-		cs_error(link, RequestIO, i);
-		kfree(cfg_mem);
-		return -1;
-	}
+	printk(KERN_NOTICE
+	       "serial_cs: no usable port range found, giving up\n");
+	cs_error(link, RequestIO, i);
+	return -1;
 
+found_port:
 	i = pcmcia_request_irq(link, &link->irq);
-	if (i != CS_SUCCESS) {
+	if (i != 0) {
 		cs_error(link, RequestIRQ, i);
 		link->irq.AssignedIRQ = 0;
 	}
@@ -569,88 +541,76 @@
 		info->quirk->config(link);
 
 	i = pcmcia_request_configuration(link, &link->conf);
-	if (i != CS_SUCCESS) {
+	if (i != 0) {
 		cs_error(link, RequestConfiguration, i);
-		kfree(cfg_mem);
 		return -1;
 	}
-	kfree(cfg_mem);
 	return setup_serial(link, info, link->io.BasePort1, link->irq.AssignedIRQ);
 }
 
-static int multi_config(struct pcmcia_device * link)
+static int multi_config_check(struct pcmcia_device *p_dev,
+			      cistpl_cftable_entry_t *cf,
+			      cistpl_cftable_entry_t *dflt,
+			      unsigned int vcc,
+			      void *priv_data)
+{
+	int *base2 = priv_data;
+
+	/* The quad port cards have bad CIS's, so just look for a
+	   window larger than 8 ports and assume it will be right */
+	if ((cf->io.nwin == 1) && (cf->io.win[0].len > 8)) {
+		p_dev->io.BasePort1 = cf->io.win[0].base;
+		p_dev->io.IOAddrLines = cf->io.flags & CISTPL_IO_LINES_MASK;
+		if (!pcmcia_request_io(p_dev, &p_dev->io)) {
+			*base2 = p_dev->io.BasePort1 + 8;
+			return 0;
+		}
+	}
+	return -ENODEV;
+}
+
+static int multi_config_check_notpicky(struct pcmcia_device *p_dev,
+				       cistpl_cftable_entry_t *cf,
+				       cistpl_cftable_entry_t *dflt,
+				       unsigned int vcc,
+				       void *priv_data)
+{
+	int *base2 = priv_data;
+
+	if (cf->io.nwin == 2) {
+		p_dev->io.BasePort1 = cf->io.win[0].base;
+		p_dev->io.BasePort2 = cf->io.win[1].base;
+		p_dev->io.IOAddrLines = cf->io.flags & CISTPL_IO_LINES_MASK;
+		if (!pcmcia_request_io(p_dev, &p_dev->io)) {
+			*base2 = p_dev->io.BasePort2;
+			return 0;
+		}
+	}
+	return -ENODEV;
+}
+
+static int multi_config(struct pcmcia_device *link)
 {
 	struct serial_info *info = link->priv;
-	struct serial_cfg_mem *cfg_mem;
-	tuple_t *tuple;
-	u_char *buf;
-	cisparse_t *parse;
-	cistpl_cftable_entry_t *cf;
-	int i, rc, base2 = 0;
-
-	cfg_mem = kmalloc(sizeof(struct serial_cfg_mem), GFP_KERNEL);
-	if (!cfg_mem)
-		return -1;
-	tuple = &cfg_mem->tuple;
-	parse = &cfg_mem->parse;
-	cf = &parse->cftable_entry;
-	buf = cfg_mem->buf;
-
-	tuple->TupleData = (cisdata_t *) buf;
-	tuple->TupleOffset = 0;
-	tuple->TupleDataMax = 255;
-	tuple->Attributes = 0;
-	tuple->DesiredTuple = CISTPL_CFTABLE_ENTRY;
+	int i, base2 = 0;
 
 	/* First, look for a generic full-sized window */
 	link->io.NumPorts1 = info->multi * 8;
-	i = first_tuple(link, tuple, parse);
-	while (i != CS_NO_MORE_ITEMS) {
-		/* The quad port cards have bad CIS's, so just look for a
-		   window larger than 8 ports and assume it will be right */
-		if ((i == CS_SUCCESS) && (cf->io.nwin == 1) &&
-		    (cf->io.win[0].len > 8)) {
-			link->conf.ConfigIndex = cf->index;
-			link->io.BasePort1 = cf->io.win[0].base;
-			link->io.IOAddrLines =
-			    cf->io.flags & CISTPL_IO_LINES_MASK;
-			i = pcmcia_request_io(link, &link->io);
-			base2 = link->io.BasePort1 + 8;
-			if (i == CS_SUCCESS)
-				break;
-		}
-		i = next_tuple(link, tuple, parse);
-	}
-
-	/* If that didn't work, look for two windows */
-	if (i != CS_SUCCESS) {
+	if (pcmcia_loop_config(link, multi_config_check, &base2)) {
+		/* If that didn't work, look for two windows */
 		link->io.NumPorts1 = link->io.NumPorts2 = 8;
 		info->multi = 2;
-		i = first_tuple(link, tuple, parse);
-		while (i != CS_NO_MORE_ITEMS) {
-			if ((i == CS_SUCCESS) && (cf->io.nwin == 2)) {
-				link->conf.ConfigIndex = cf->index;
-				link->io.BasePort1 = cf->io.win[0].base;
-				link->io.BasePort2 = cf->io.win[1].base;
-				link->io.IOAddrLines =
-				    cf->io.flags & CISTPL_IO_LINES_MASK;
-				i = pcmcia_request_io(link, &link->io);
-				base2 = link->io.BasePort2;
-				if (i == CS_SUCCESS)
-					break;
-			}
-			i = next_tuple(link, tuple, parse);
+		if (pcmcia_loop_config(link, multi_config_check_notpicky,
+				       &base2)) {
+			printk(KERN_NOTICE "serial_cs: no usable port range"
+			       "found, giving up\n");
+			return -ENODEV;
 		}
 	}
 
-	if (i != CS_SUCCESS) {
-		cs_error(link, RequestIO, i);
-		rc = -1;
-		goto free_cfg_mem;
-	}
-
 	i = pcmcia_request_irq(link, &link->irq);
-	if (i != CS_SUCCESS) {
+	if (i != 0) {
+		/* FIXME: comment does not fit, error handling does not fit */
 		printk(KERN_NOTICE
 		       "serial_cs: no usable port range found, giving up\n");
 		cs_error(link, RequestIRQ, i);
@@ -664,10 +624,9 @@
 		info->quirk->config(link);
 
 	i = pcmcia_request_configuration(link, &link->conf);
-	if (i != CS_SUCCESS) {
+	if (i != 0) {
 		cs_error(link, RequestConfiguration, i);
-		rc = -1;
-		goto free_cfg_mem;
+		return -ENODEV;
 	}
 
 	/* The Oxford Semiconductor OXCF950 cards are in fact single-port:
@@ -678,7 +637,8 @@
 				info->prodid == PRODID_POSSIO_GCC)) {
 		int err;
 
-		if (cf->index == 1 || cf->index == 3) {
+		if (link->conf.ConfigIndex == 1 ||
+		    link->conf.ConfigIndex == 3) {
 			err = setup_serial(link, info, base2,
 					link->irq.AssignedIRQ);
 			base2 = link->io.BasePort1;
@@ -695,18 +655,14 @@
 		if (info->quirk && info->quirk->wakeup)
 			info->quirk->wakeup(link);
 
-		rc = 0;
-		goto free_cfg_mem;
+		return 0;
 	}
 
 	setup_serial(link, info, link->io.BasePort1, link->irq.AssignedIRQ);
 	for (i = 0; i < info->multi - 1; i++)
 		setup_serial(link, info, base2 + (8 * i),
 				link->irq.AssignedIRQ);
-	rc = 0;
-free_cfg_mem:
-	kfree(cfg_mem);
-	return rc;
+	return 0;
 }
 
 /*======================================================================
@@ -746,7 +702,7 @@
 	/* Is this a compliant multifunction card? */
 	tuple->DesiredTuple = CISTPL_LONGLINK_MFC;
 	tuple->Attributes = TUPLE_RETURN_COMMON | TUPLE_RETURN_LINK;
-	info->multi = (first_tuple(link, tuple, parse) == CS_SUCCESS);
+	info->multi = (first_tuple(link, tuple, parse) == 0);
 
 	/* Is this a multiport card? */
 	tuple->DesiredTuple = CISTPL_MANFID;
@@ -770,7 +726,7 @@
 	    ((link->func_id == CISTPL_FUNCID_MULTI) ||
 	     (link->func_id == CISTPL_FUNCID_SERIAL))) {
 		tuple->DesiredTuple = CISTPL_CFTABLE_ENTRY;
-		if (first_tuple(link, tuple, parse) == CS_SUCCESS) {
+		if (first_tuple(link, tuple, parse) == 0) {
 			if ((cf->io.nwin == 1) && (cf->io.win[0].len % 8 == 0))
 				info->multi = cf->io.win[0].len >> 3;
 			if ((cf->io.nwin == 2) && (cf->io.win[0].len == 8) &&
diff --git a/drivers/serial/serial_ks8695.c b/drivers/serial/serial_ks8695.c
index b9cbfc8..998e89d 100644
--- a/drivers/serial/serial_ks8695.c
+++ b/drivers/serial/serial_ks8695.c
@@ -63,8 +63,44 @@
 #define UART_DUMMY_LSR_RX	0x100
 #define UART_PORT_SIZE		(KS8695_USR - KS8695_URRB + 4)
 
-#define tx_enabled(port) ((port)->unused[0])
-#define rx_enabled(port) ((port)->unused[1])
+static inline int tx_enabled(struct uart_port *port)
+{
+	return port->unused[0] & 1;
+}
+
+static inline int rx_enabled(struct uart_port *port)
+{
+	return port->unused[0] & 2;
+}
+
+static inline int ms_enabled(struct uart_port *port)
+{
+	return port->unused[0] & 4;
+}
+
+static inline void ms_enable(struct uart_port *port, int enabled)
+{
+	if(enabled)
+		port->unused[0] |= 4;
+	else
+		port->unused[0] &= ~4;
+}
+
+static inline void rx_enable(struct uart_port *port, int enabled)
+{
+	if(enabled)
+		port->unused[0] |= 2;
+	else
+		port->unused[0] &= ~2;
+}
+
+static inline void tx_enable(struct uart_port *port, int enabled)
+{
+	if(enabled)
+		port->unused[0] |= 1;
+	else
+		port->unused[0] &= ~1;
+}
 
 
 #ifdef SUPPORT_SYSRQ
@@ -75,7 +111,7 @@
 {
 	if (tx_enabled(port)) {
 		disable_irq(KS8695_IRQ_UART_TX);
-		tx_enabled(port) = 0;
+		tx_enable(port, 0);
 	}
 }
 
@@ -83,7 +119,7 @@
 {
 	if (!tx_enabled(port)) {
 		enable_irq(KS8695_IRQ_UART_TX);
-		tx_enabled(port) = 1;
+		tx_enable(port, 1);
 	}
 }
 
@@ -91,18 +127,24 @@
 {
 	if (rx_enabled(port)) {
 		disable_irq(KS8695_IRQ_UART_RX);
-		rx_enabled(port) = 0;
+		rx_enable(port, 0);
 	}
 }
 
 static void ks8695uart_enable_ms(struct uart_port *port)
 {
-	enable_irq(KS8695_IRQ_UART_MODEM_STATUS);
+	if (!ms_enabled(port)) {
+		enable_irq(KS8695_IRQ_UART_MODEM_STATUS);
+		ms_enable(port,1);
+	}
 }
 
 static void ks8695uart_disable_ms(struct uart_port *port)
 {
-	disable_irq(KS8695_IRQ_UART_MODEM_STATUS);
+	if (ms_enabled(port)) {
+		disable_irq(KS8695_IRQ_UART_MODEM_STATUS);
+		ms_enable(port,0);
+	}
 }
 
 static irqreturn_t ks8695uart_rx_chars(int irq, void *dev_id)
@@ -285,8 +327,9 @@
 	int retval;
 
 	set_irq_flags(KS8695_IRQ_UART_TX, IRQF_VALID | IRQF_NOAUTOEN);
-	tx_enabled(port) = 0;
-	rx_enabled(port) = 1;
+	tx_enable(port, 0);
+	rx_enable(port, 1);
+	ms_enable(port, 1);
 
 	/*
 	 * Allocate the IRQ
diff --git a/drivers/serial/sunhv.c b/drivers/serial/sunhv.c
index e41766d..a94a2ab 100644
--- a/drivers/serial/sunhv.c
+++ b/drivers/serial/sunhv.c
@@ -616,7 +616,7 @@
 	return 0;
 }
 
-static struct of_device_id hv_match[] = {
+static const struct of_device_id hv_match[] = {
 	{
 		.name = "console",
 		.compatible = "qcn",
diff --git a/drivers/serial/sunsab.c b/drivers/serial/sunsab.c
index 29b4458..0355efe 100644
--- a/drivers/serial/sunsab.c
+++ b/drivers/serial/sunsab.c
@@ -1078,7 +1078,7 @@
 	return 0;
 }
 
-static struct of_device_id sab_match[] = {
+static const struct of_device_id sab_match[] = {
 	{
 		.name = "se",
 	},
diff --git a/drivers/serial/sunsu.c b/drivers/serial/sunsu.c
index a378464..a4dc79b1 100644
--- a/drivers/serial/sunsu.c
+++ b/drivers/serial/sunsu.c
@@ -1506,7 +1506,7 @@
 	return 0;
 }
 
-static struct of_device_id su_match[] = {
+static const struct of_device_id su_match[] = {
 	{
 		.name = "su",
 	},
diff --git a/drivers/serial/sunzilog.c b/drivers/serial/sunzilog.c
index 3cb4c8a..45a299f 100644
--- a/drivers/serial/sunzilog.c
+++ b/drivers/serial/sunzilog.c
@@ -1480,7 +1480,7 @@
 	return 0;
 }
 
-static struct of_device_id zs_match[] = {
+static const struct of_device_id zs_match[] = {
 	{
 		.name = "zs",
 	},
diff --git a/drivers/spi/orion_spi.c b/drivers/spi/orion_spi.c
index c4eaacd..b872bfa 100644
--- a/drivers/spi/orion_spi.c
+++ b/drivers/spi/orion_spi.c
@@ -427,7 +427,7 @@
 			goto msg_rejected;
 		}
 
-		if (t->speed_hz < orion_spi->min_speed) {
+		if (t->speed_hz && t->speed_hz < orion_spi->min_speed) {
 			dev_err(&spi->dev,
 				"message rejected : "
 				"device min speed (%d Hz) exceeds "
diff --git a/drivers/spi/pxa2xx_spi.c b/drivers/spi/pxa2xx_spi.c
index 0e53354..d47d363 100644
--- a/drivers/spi/pxa2xx_spi.c
+++ b/drivers/spi/pxa2xx_spi.c
@@ -49,7 +49,7 @@
 
 #define DMA_INT_MASK		(DCSR_ENDINTR | DCSR_STARTINTR | DCSR_BUSERR)
 #define RESET_DMA_CHANNEL	(DCSR_NODESC | DMA_INT_MASK)
-#define IS_DMA_ALIGNED(x)	(((x) & 0x07) == 0)
+#define IS_DMA_ALIGNED(x)	((((u32)(x)) & 0x07) == 0)
 #define MAX_DMA_LEN		8191
 
 /*
@@ -896,7 +896,7 @@
 				|| transfer->rx_dma || transfer->tx_dma) {
 			dev_err(&drv_data->pdev->dev,
 				"pump_transfers: mapped transfer length "
-				"of %lu is greater than %d\n",
+				"of %u is greater than %d\n",
 				transfer->len, MAX_DMA_LEN);
 			message->status = -EINVAL;
 			giveback(drv_data);
diff --git a/drivers/ssb/main.c b/drivers/ssb/main.c
index 87ab244..0ffabf5 100644
--- a/drivers/ssb/main.c
+++ b/drivers/ssb/main.c
@@ -471,6 +471,7 @@
 #endif
 			break;
 		case SSB_BUSTYPE_SSB:
+			dev->dma_mask = &dev->coherent_dma_mask;
 			break;
 		}
 
diff --git a/drivers/ssb/pci.c b/drivers/ssb/pci.c
index f883dcf..d5cde05 100644
--- a/drivers/ssb/pci.c
+++ b/drivers/ssb/pci.c
@@ -327,11 +327,9 @@
 	s8 gain;
 	u16 loc[3];
 
-	if (out->revision == 3) {			/* rev 3 moved MAC */
+	if (out->revision == 3)			/* rev 3 moved MAC */
 		loc[0] = SSB_SPROM3_IL0MAC;
-		loc[1] = SSB_SPROM3_ET0MAC;
-		loc[2] = SSB_SPROM3_ET1MAC;
-	} else {
+	else {
 		loc[0] = SSB_SPROM1_IL0MAC;
 		loc[1] = SSB_SPROM1_ET0MAC;
 		loc[2] = SSB_SPROM1_ET1MAC;
@@ -340,13 +338,15 @@
 		v = in[SPOFF(loc[0]) + i];
 		*(((__be16 *)out->il0mac) + i) = cpu_to_be16(v);
 	}
-	for (i = 0; i < 3; i++) {
-		v = in[SPOFF(loc[1]) + i];
-		*(((__be16 *)out->et0mac) + i) = cpu_to_be16(v);
-	}
-	for (i = 0; i < 3; i++) {
-		v = in[SPOFF(loc[2]) + i];
-		*(((__be16 *)out->et1mac) + i) = cpu_to_be16(v);
+	if (out->revision < 3) { 	/* only rev 1-2 have et0, et1 */
+		for (i = 0; i < 3; i++) {
+			v = in[SPOFF(loc[1]) + i];
+			*(((__be16 *)out->et0mac) + i) = cpu_to_be16(v);
+		}
+		for (i = 0; i < 3; i++) {
+			v = in[SPOFF(loc[2]) + i];
+			*(((__be16 *)out->et1mac) + i) = cpu_to_be16(v);
+		}
 	}
 	SPEX(et0phyaddr, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET0A, 0);
 	SPEX(et1phyaddr, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET1A,
@@ -399,30 +399,33 @@
 	out->antenna_gain.ghz5.a3 = gain;
 }
 
-static void sprom_extract_r4(struct ssb_sprom *out, const u16 *in)
+static void sprom_extract_r45(struct ssb_sprom *out, const u16 *in)
 {
 	int i;
 	u16 v;
+	u16 il0mac_offset;
 
-	/* extract the equivalent of the r1 variables */
+	if (out->revision == 4)
+		il0mac_offset = SSB_SPROM4_IL0MAC;
+	else
+		il0mac_offset = SSB_SPROM5_IL0MAC;
+	/* extract the MAC address */
 	for (i = 0; i < 3; i++) {
-		v = in[SPOFF(SSB_SPROM4_IL0MAC) + i];
+		v = in[SPOFF(il0mac_offset) + i];
 		*(((__be16 *)out->il0mac) + i) = cpu_to_be16(v);
 	}
-	for (i = 0; i < 3; i++) {
-		v = in[SPOFF(SSB_SPROM4_ET0MAC) + i];
-		*(((__be16 *)out->et0mac) + i) = cpu_to_be16(v);
-	}
-	for (i = 0; i < 3; i++) {
-		v = in[SPOFF(SSB_SPROM4_ET1MAC) + i];
-		*(((__be16 *)out->et1mac) + i) = cpu_to_be16(v);
-	}
 	SPEX(et0phyaddr, SSB_SPROM4_ETHPHY, SSB_SPROM4_ETHPHY_ET0A, 0);
 	SPEX(et1phyaddr, SSB_SPROM4_ETHPHY, SSB_SPROM4_ETHPHY_ET1A,
 	     SSB_SPROM4_ETHPHY_ET1A_SHIFT);
-	SPEX(country_code, SSB_SPROM4_CCODE, 0xFFFF, 0);
-	SPEX(boardflags_lo, SSB_SPROM4_BFLLO, 0xFFFF, 0);
-	SPEX(boardflags_hi, SSB_SPROM4_BFLHI, 0xFFFF, 0);
+	if (out->revision == 4) {
+		SPEX(country_code, SSB_SPROM4_CCODE, 0xFFFF, 0);
+		SPEX(boardflags_lo, SSB_SPROM4_BFLLO, 0xFFFF, 0);
+		SPEX(boardflags_hi, SSB_SPROM4_BFLHI, 0xFFFF, 0);
+	} else {
+		SPEX(country_code, SSB_SPROM5_CCODE, 0xFFFF, 0);
+		SPEX(boardflags_lo, SSB_SPROM5_BFLLO, 0xFFFF, 0);
+		SPEX(boardflags_hi, SSB_SPROM5_BFLHI, 0xFFFF, 0);
+	}
 	SPEX(ant_available_a, SSB_SPROM4_ANTAVAIL, SSB_SPROM4_ANTAVAIL_A,
 	     SSB_SPROM4_ANTAVAIL_A_SHIFT);
 	SPEX(ant_available_bg, SSB_SPROM4_ANTAVAIL, SSB_SPROM4_ANTAVAIL_BG,
@@ -433,12 +436,21 @@
 	SPEX(maxpwr_a, SSB_SPROM4_MAXP_A, SSB_SPROM4_MAXP_A_MASK, 0);
 	SPEX(itssi_a, SSB_SPROM4_MAXP_A, SSB_SPROM4_ITSSI_A,
 	     SSB_SPROM4_ITSSI_A_SHIFT);
-	SPEX(gpio0, SSB_SPROM4_GPIOA, SSB_SPROM4_GPIOA_P0, 0);
-	SPEX(gpio1, SSB_SPROM4_GPIOA, SSB_SPROM4_GPIOA_P1,
-	     SSB_SPROM4_GPIOA_P1_SHIFT);
-	SPEX(gpio2, SSB_SPROM4_GPIOB, SSB_SPROM4_GPIOB_P2, 0);
-	SPEX(gpio3, SSB_SPROM4_GPIOB, SSB_SPROM4_GPIOB_P3,
-	     SSB_SPROM4_GPIOB_P3_SHIFT);
+	if (out->revision == 4) {
+		SPEX(gpio0, SSB_SPROM4_GPIOA, SSB_SPROM4_GPIOA_P0, 0);
+		SPEX(gpio1, SSB_SPROM4_GPIOA, SSB_SPROM4_GPIOA_P1,
+		     SSB_SPROM4_GPIOA_P1_SHIFT);
+		SPEX(gpio2, SSB_SPROM4_GPIOB, SSB_SPROM4_GPIOB_P2, 0);
+		SPEX(gpio3, SSB_SPROM4_GPIOB, SSB_SPROM4_GPIOB_P3,
+		     SSB_SPROM4_GPIOB_P3_SHIFT);
+	} else {
+		SPEX(gpio0, SSB_SPROM5_GPIOA, SSB_SPROM5_GPIOA_P0, 0);
+		SPEX(gpio1, SSB_SPROM5_GPIOA, SSB_SPROM5_GPIOA_P1,
+		     SSB_SPROM5_GPIOA_P1_SHIFT);
+		SPEX(gpio2, SSB_SPROM5_GPIOB, SSB_SPROM5_GPIOB_P2, 0);
+		SPEX(gpio3, SSB_SPROM5_GPIOB, SSB_SPROM5_GPIOB_P3,
+		     SSB_SPROM5_GPIOB_P3_SHIFT);
+	}
 
 	/* Extract the antenna gain values. */
 	SPEX(antenna_gain.ghz24.a0, SSB_SPROM4_AGAIN01,
@@ -462,6 +474,8 @@
 
 	out->revision = in[size - 1] & 0x00FF;
 	ssb_dprintk(KERN_DEBUG PFX "SPROM revision %d detected.\n", out->revision);
+	memset(out->et0mac, 0xFF, 6);		/* preset et0 and et1 mac */
+	memset(out->et1mac, 0xFF, 6);
 	if ((bus->chip_id & 0xFF00) == 0x4400) {
 		/* Workaround: The BCM44XX chip has a stupid revision
 		 * number stored in the SPROM.
@@ -471,16 +485,16 @@
 	} else if (bus->chip_id == 0x4321) {
 		/* the BCM4328 has a chipid == 0x4321 and a rev 4 SPROM */
 		out->revision = 4;
-		sprom_extract_r4(out, in);
+		sprom_extract_r45(out, in);
 	} else {
 		if (out->revision == 0)
 			goto unsupported;
 		if (out->revision >= 1 && out->revision <= 3) {
 			sprom_extract_r123(out, in);
 		}
-		if (out->revision == 4)
-			sprom_extract_r4(out, in);
-		if (out->revision >= 5)
+		if (out->revision == 4 || out->revision == 5)
+			sprom_extract_r45(out, in);
+		if (out->revision > 5)
 			goto unsupported;
 	}
 
diff --git a/drivers/ssb/pcmcia.c b/drivers/ssb/pcmcia.c
index 24c2a46..fbfadba 100644
--- a/drivers/ssb/pcmcia.c
+++ b/drivers/ssb/pcmcia.c
@@ -80,7 +80,7 @@
 	reg.Action = CS_WRITE;
 	reg.Value = value;
 	res = pcmcia_access_configuration_register(bus->host_pcmcia, &reg);
-	if (unlikely(res != CS_SUCCESS))
+	if (unlikely(res != 0))
 		return -EBUSY;
 
 	return 0;
@@ -96,7 +96,7 @@
 	reg.Offset = offset;
 	reg.Action = CS_READ;
 	res = pcmcia_access_configuration_register(bus->host_pcmcia, &reg);
-	if (unlikely(res != CS_SUCCESS))
+	if (unlikely(res != 0))
 		return -EBUSY;
 	*value = reg.Value;
 
@@ -638,17 +638,17 @@
 	tuple.TupleData = buf;
 	tuple.TupleDataMax = sizeof(buf);
 	res = pcmcia_get_first_tuple(bus->host_pcmcia, &tuple);
-	GOTO_ERROR_ON(res != CS_SUCCESS, "MAC first tpl");
+	GOTO_ERROR_ON(res != 0, "MAC first tpl");
 	res = pcmcia_get_tuple_data(bus->host_pcmcia, &tuple);
-	GOTO_ERROR_ON(res != CS_SUCCESS, "MAC first tpl data");
+	GOTO_ERROR_ON(res != 0, "MAC first tpl data");
 	while (1) {
 		GOTO_ERROR_ON(tuple.TupleDataLen < 1, "MAC tpl < 1");
 		if (tuple.TupleData[0] == CISTPL_FUNCE_LAN_NODE_ID)
 			break;
 		res = pcmcia_get_next_tuple(bus->host_pcmcia, &tuple);
-		GOTO_ERROR_ON(res != CS_SUCCESS, "MAC next tpl");
+		GOTO_ERROR_ON(res != 0, "MAC next tpl");
 		res = pcmcia_get_tuple_data(bus->host_pcmcia, &tuple);
-		GOTO_ERROR_ON(res != CS_SUCCESS, "MAC next tpl data");
+		GOTO_ERROR_ON(res != 0, "MAC next tpl data");
 	}
 	GOTO_ERROR_ON(tuple.TupleDataLen != ETH_ALEN + 2, "MAC tpl size");
 	memcpy(sprom->il0mac, &tuple.TupleData[2], ETH_ALEN);
@@ -659,9 +659,9 @@
 	tuple.TupleData = buf;
 	tuple.TupleDataMax = sizeof(buf);
 	res = pcmcia_get_first_tuple(bus->host_pcmcia, &tuple);
-	GOTO_ERROR_ON(res != CS_SUCCESS, "VEN first tpl");
+	GOTO_ERROR_ON(res != 0, "VEN first tpl");
 	res = pcmcia_get_tuple_data(bus->host_pcmcia, &tuple);
-	GOTO_ERROR_ON(res != CS_SUCCESS, "VEN first tpl data");
+	GOTO_ERROR_ON(res != 0, "VEN first tpl data");
 	while (1) {
 		GOTO_ERROR_ON(tuple.TupleDataLen < 1, "VEN tpl < 1");
 		switch (tuple.TupleData[0]) {
@@ -733,11 +733,11 @@
 			break;
 		}
 		res = pcmcia_get_next_tuple(bus->host_pcmcia, &tuple);
-		if (res == CS_NO_MORE_ITEMS)
+		if (res == -ENOSPC)
 			break;
-		GOTO_ERROR_ON(res != CS_SUCCESS, "VEN next tpl");
+		GOTO_ERROR_ON(res != 0, "VEN next tpl");
 		res = pcmcia_get_tuple_data(bus->host_pcmcia, &tuple);
-		GOTO_ERROR_ON(res != CS_SUCCESS, "VEN next tpl data");
+		GOTO_ERROR_ON(res != 0, "VEN next tpl data");
 	}
 
 	return 0;
diff --git a/drivers/telephony/ixj_pcmcia.c b/drivers/telephony/ixj_pcmcia.c
index ff9a29b..347c3ed 100644
--- a/drivers/telephony/ixj_pcmcia.c
+++ b/drivers/telephony/ixj_pcmcia.c
@@ -124,65 +124,53 @@
 	return;
 }
 
+static int ixj_config_check(struct pcmcia_device *p_dev,
+			    cistpl_cftable_entry_t *cfg,
+			    cistpl_cftable_entry_t *dflt,
+			    unsigned int vcc,
+			    void *priv_data)
+{
+	if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) {
+		cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io;
+		p_dev->io.BasePort1 = io->win[0].base;
+		p_dev->io.NumPorts1 = io->win[0].len;
+		if (io->nwin == 2) {
+			p_dev->io.BasePort2 = io->win[1].base;
+			p_dev->io.NumPorts2 = io->win[1].len;
+		}
+		if (!pcmcia_request_io(p_dev, &p_dev->io))
+			return 0;
+	}
+	return -ENODEV;
+}
+
 static int ixj_config(struct pcmcia_device * link)
 {
 	IXJ *j;
 	ixj_info_t *info;
-	tuple_t tuple;
-	u_short buf[128];
-	cisparse_t parse;
-	cistpl_cftable_entry_t *cfg = &parse.cftable_entry;
-	cistpl_cftable_entry_t dflt =
-	{
-		0
-	};
-	int last_ret, last_fn;
+	cistpl_cftable_entry_t dflt = { 0 };
+
 	info = link->priv;
 	DEBUG(0, "ixj_config(0x%p)\n", link);
-	tuple.TupleData = (cisdata_t *) buf;
-	tuple.TupleOffset = 0;
-	tuple.TupleDataMax = 255;
-	tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
-	tuple.Attributes = 0;
-	CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple));
-	while (1) {
-		if (pcmcia_get_tuple_data(link, &tuple) != 0 ||
-				pcmcia_parse_tuple(link, &tuple, &parse) != 0)
-			goto next_entry;
-		if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) {
-			cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt.io;
-			link->conf.ConfigIndex = cfg->index;
-			link->io.BasePort1 = io->win[0].base;
-			link->io.NumPorts1 = io->win[0].len;
-			if (io->nwin == 2) {
-				link->io.BasePort2 = io->win[1].base;
-				link->io.NumPorts2 = io->win[1].len;
-			}
-			if (pcmcia_request_io(link, &link->io) != 0)
-				goto next_entry;
-			/* If we've got this far, we're done */
-			break;
-		}
-	      next_entry:
-		if (cfg->flags & CISTPL_CFTABLE_DEFAULT)
-			dflt = *cfg;
-		CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(link, &tuple));
-	}
 
-	CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf));
+	if (pcmcia_loop_config(link, ixj_config_check, &dflt))
+		goto cs_failed;
+
+	if (pcmcia_request_configuration(link, &link->conf))
+		goto cs_failed;
 
 	/*
  	 *	Register the card with the core.
- 	 */	
-	j=ixj_pcmcia_probe(link->io.BasePort1,link->io.BasePort1 + 0x10);
+	 */
+	j = ixj_pcmcia_probe(link->io.BasePort1, link->io.BasePort1 + 0x10);
 
 	info->ndev = 1;
 	info->node.major = PHONE_MAJOR;
 	link->dev_node = &info->node;
 	ixj_get_serial(link, j);
 	return 0;
+
       cs_failed:
-	cs_error(link, last_fn, last_ret);
 	ixj_cs_release(link);
 	return -ENODEV;
 }
diff --git a/drivers/usb/atm/usbatm.c b/drivers/usb/atm/usbatm.c
index 0722872..0da2c25 100644
--- a/drivers/usb/atm/usbatm.c
+++ b/drivers/usb/atm/usbatm.c
@@ -640,14 +640,13 @@
 
 	atm_dbg(instance, "%s entered\n", __func__);
 	spin_lock_irq(&instance->sndqueue.lock);
-	for (skb = instance->sndqueue.next, n = skb->next;
-	     skb != (struct sk_buff *)&instance->sndqueue;
-	     skb = n, n = skb->next)
+	skb_queue_walk_safe(&instance->sndqueue, skb, n) {
 		if (UDSL_SKB(skb)->atm.vcc == vcc) {
 			atm_dbg(instance, "%s: popping skb 0x%p\n", __func__, skb);
 			__skb_unlink(skb, &instance->sndqueue);
 			usbatm_pop(vcc, skb);
 		}
+	}
 	spin_unlock_irq(&instance->sndqueue.lock);
 
 	tasklet_disable(&instance->tx_channel.tasklet);
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
index 8abd4e5..8ab389d 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -1876,7 +1876,8 @@
 		 * with IRQF_SHARED. As usb_hcd_irq() will always disable
 		 * interrupts we can remove it here.
 		 */
-		irqflags &= ~IRQF_DISABLED;
+		if (irqflags & IRQF_SHARED)
+			irqflags &= ~IRQF_DISABLED;
 
 		snprintf(hcd->irq_descr, sizeof(hcd->irq_descr), "%s:usb%d",
 				hcd->driver->description, hcd->self.busnum);
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 6a5cb01..d999638 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -2683,35 +2683,17 @@
 				USB_PORT_STAT_C_ENABLE);
 #endif
 
-	/* Try to use the debounce delay for protection against
-	 * port-enable changes caused, for example, by EMI.
-	 */
-	if (portchange & (USB_PORT_STAT_C_CONNECTION |
-				USB_PORT_STAT_C_ENABLE)) {
-		status = hub_port_debounce(hub, port1);
-		if (status < 0) {
-			if (printk_ratelimit())
-				dev_err (hub_dev, "connect-debounce failed, "
-						"port %d disabled\n", port1);
-			portstatus &= ~USB_PORT_STAT_CONNECTION;
-		} else {
-			portstatus = status;
-		}
-	}
-
 	/* Try to resuscitate an existing device */
 	udev = hdev->children[port1-1];
 	if ((portstatus & USB_PORT_STAT_CONNECTION) && udev &&
 			udev->state != USB_STATE_NOTATTACHED) {
-
 		usb_lock_device(udev);
 		if (portstatus & USB_PORT_STAT_ENABLE) {
 			status = 0;		/* Nothing to do */
-		} else if (!udev->persist_enabled) {
-			status = -ENODEV;	/* Mustn't resuscitate */
 
 #ifdef CONFIG_USB_SUSPEND
-		} else if (udev->state == USB_STATE_SUSPENDED) {
+		} else if (udev->state == USB_STATE_SUSPENDED &&
+				udev->persist_enabled) {
 			/* For a suspended device, treat this as a
 			 * remote wakeup event.
 			 */
@@ -2726,7 +2708,7 @@
 #endif
 
 		} else {
-			status = usb_reset_device(udev);
+			status = -ENODEV;	/* Don't resuscitate */
 		}
 		usb_unlock_device(udev);
 
@@ -2741,6 +2723,19 @@
 		usb_disconnect(&hdev->children[port1-1]);
 	clear_bit(port1, hub->change_bits);
 
+	if (portchange & (USB_PORT_STAT_C_CONNECTION |
+				USB_PORT_STAT_C_ENABLE)) {
+		status = hub_port_debounce(hub, port1);
+		if (status < 0) {
+			if (printk_ratelimit())
+				dev_err(hub_dev, "connect-debounce failed, "
+						"port %d disabled\n", port1);
+			portstatus &= ~USB_PORT_STAT_CONNECTION;
+		} else {
+			portstatus = status;
+		}
+	}
+
 	/* Return now if debouncing failed or nothing is connected */
 	if (!(portstatus & USB_PORT_STAT_CONNECTION)) {
 
@@ -2748,7 +2743,7 @@
 		if ((wHubCharacteristics & HUB_CHAR_LPSM) < 2
 				&& !(portstatus & (1 << USB_PORT_FEAT_POWER)))
 			set_port_feature(hdev, port1, USB_PORT_FEAT_POWER);
- 
+
 		if (portstatus & USB_PORT_STAT_ENABLE)
   			goto done;
 		return;
diff --git a/drivers/usb/core/inode.c b/drivers/usb/core/inode.c
index db410e9..77fa7a0 100644
--- a/drivers/usb/core/inode.c
+++ b/drivers/usb/core/inode.c
@@ -97,7 +97,7 @@
 	Opt_err,
 };
 
-static match_table_t tokens = {
+static const match_table_t tokens = {
 	{Opt_devuid, "devuid=%u"},
 	{Opt_devgid, "devgid=%u"},
 	{Opt_devmode, "devmode=%o"},
diff --git a/drivers/usb/gadget/fsl_usb2_udc.c b/drivers/usb/gadget/fsl_usb2_udc.c
index 1cfccf1..45ad556 100644
--- a/drivers/usb/gadget/fsl_usb2_udc.c
+++ b/drivers/usb/gadget/fsl_usb2_udc.c
@@ -223,7 +223,7 @@
 	fsl_writel(tmp, &dr_regs->endpointlistaddr);
 
 	VDBG("vir[qh_base] is %p phy[qh_base] is 0x%8x reg is 0x%8x",
-		(int)udc->ep_qh, (int)tmp,
+		udc->ep_qh, (int)tmp,
 		fsl_readl(&dr_regs->endpointlistaddr));
 
 	/* Config PHY interface */
diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c
index 574c538..bb54cca 100644
--- a/drivers/usb/gadget/omap_udc.c
+++ b/drivers/usb/gadget/omap_udc.c
@@ -787,7 +787,7 @@
 			omap_set_dma_dest_params(ep->lch,
 				OMAP_DMA_PORT_TIPB,
 				OMAP_DMA_AMODE_CONSTANT,
-				(unsigned long) io_v2p(UDC_DATA_DMA),
+				UDC_DATA_DMA,
 				0, 0);
 		}
 	} else {
@@ -804,7 +804,7 @@
 			omap_set_dma_src_params(ep->lch,
 				OMAP_DMA_PORT_TIPB,
 				OMAP_DMA_AMODE_CONSTANT,
-				(unsigned long) io_v2p(UDC_DATA_DMA),
+				UDC_DATA_DMA,
 				0, 0);
 			/* EMIFF or SDRC */
 			omap_set_dma_dest_burst_mode(ep->lch,
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index d9d53f2..8409e07 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -145,16 +145,6 @@
 	return -ETIMEDOUT;
 }
 
-static int handshake_on_error_set_halt(struct ehci_hcd *ehci, void __iomem *ptr,
-				       u32 mask, u32 done, int usec)
-{
-	int error = handshake(ehci, ptr, mask, done, usec);
-	if (error)
-		ehci_to_hcd(ehci)->state = HC_STATE_HALT;
-
-	return error;
-}
-
 /* force HC to halt state from unknown (EHCI spec section 2.3) */
 static int ehci_halt (struct ehci_hcd *ehci)
 {
@@ -173,6 +163,22 @@
 			  STS_HALT, STS_HALT, 16 * 125);
 }
 
+static int handshake_on_error_set_halt(struct ehci_hcd *ehci, void __iomem *ptr,
+				       u32 mask, u32 done, int usec)
+{
+	int error;
+
+	error = handshake(ehci, ptr, mask, done, usec);
+	if (error) {
+		ehci_halt(ehci);
+		ehci_to_hcd(ehci)->state = HC_STATE_HALT;
+		ehci_err(ehci, "force halt; handhake %p %08x %08x -> %d\n",
+			ptr, mask, done, error);
+	}
+
+	return error;
+}
+
 /* put TDI/ARC silicon into EHCI mode */
 static void tdi_reset (struct ehci_hcd *ehci)
 {
diff --git a/drivers/usb/host/ehci-ixp4xx.c b/drivers/usb/host/ehci-ixp4xx.c
index f9575c4..9c32063 100644
--- a/drivers/usb/host/ehci-ixp4xx.c
+++ b/drivers/usb/host/ehci-ixp4xx.c
@@ -1,7 +1,7 @@
 /*
  * IXP4XX EHCI Host Controller Driver
  *
- * Author: Vladimir Barinov <vbarinov@ru.mvista.com>
+ * Author: Vladimir Barinov <vbarinov@embeddedalley.com>
  *
  * Based on "ehci-fsl.c" by Randy Vinson <rvinson@mvista.com>
  *
diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c
index b7853c8..4a0c5a7 100644
--- a/drivers/usb/host/ehci-sched.c
+++ b/drivers/usb/host/ehci-sched.c
@@ -437,6 +437,9 @@
 	u32	cmd;
 	int	status;
 
+	if (ehci->periodic_sched++)
+		return 0;
+
 	/* did clearing PSE did take effect yet?
 	 * takes effect only at frame boundaries...
 	 */
@@ -461,6 +464,9 @@
 	u32	cmd;
 	int	status;
 
+	if (--ehci->periodic_sched)
+		return 0;
+
 	/* did setting PSE not take effect yet?
 	 * takes effect only at frame boundaries...
 	 */
@@ -544,13 +550,10 @@
 		: (qh->usecs * 8);
 
 	/* maybe enable periodic schedule processing */
-	if (!ehci->periodic_sched++)
-		return enable_periodic (ehci);
-
-	return 0;
+	return enable_periodic(ehci);
 }
 
-static void qh_unlink_periodic (struct ehci_hcd *ehci, struct ehci_qh *qh)
+static int qh_unlink_periodic(struct ehci_hcd *ehci, struct ehci_qh *qh)
 {
 	unsigned	i;
 	unsigned	period;
@@ -586,9 +589,7 @@
 	qh_put (qh);
 
 	/* maybe turn off periodic schedule */
-	ehci->periodic_sched--;
-	if (!ehci->periodic_sched)
-		(void) disable_periodic (ehci);
+	return disable_periodic(ehci);
 }
 
 static void intr_deschedule (struct ehci_hcd *ehci, struct ehci_qh *qh)
@@ -1562,9 +1563,7 @@
 	urb->hcpriv = NULL;
 
 	timer_action (ehci, TIMER_IO_WATCHDOG);
-	if (unlikely (!ehci->periodic_sched++))
-		return enable_periodic (ehci);
-	return 0;
+	return enable_periodic(ehci);
 }
 
 #define	ISO_ERRS (EHCI_ISOC_BUF_ERR | EHCI_ISOC_BABBLE | EHCI_ISOC_XACTERR)
@@ -1642,7 +1641,7 @@
 	ehci_urb_done(ehci, urb, 0);
 	retval = true;
 	urb = NULL;
-	ehci->periodic_sched--;
+	(void) disable_periodic(ehci);
 	ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs--;
 
 	if (unlikely (list_empty (&stream->td_list))) {
@@ -1951,9 +1950,7 @@
 	urb->hcpriv = NULL;
 
 	timer_action (ehci, TIMER_IO_WATCHDOG);
-	if (!ehci->periodic_sched++)
-		return enable_periodic (ehci);
-	return 0;
+	return enable_periodic(ehci);
 }
 
 /*-------------------------------------------------------------------------*/
@@ -2019,7 +2016,7 @@
 	ehci_urb_done(ehci, urb, 0);
 	retval = true;
 	urb = NULL;
-	ehci->periodic_sched--;
+	(void) disable_periodic(ehci);
 	ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs--;
 
 	if (list_empty (&stream->td_list)) {
@@ -2243,8 +2240,7 @@
 			if (unlikely (modified)) {
 				if (likely(ehci->periodic_sched > 0))
 					goto restart;
-				/* maybe we can short-circuit this scan! */
-				disable_periodic(ehci);
+				/* short-circuit this scan */
 				now_uframe = clock;
 				break;
 			}
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
index 5799298..b697a13 100644
--- a/drivers/usb/host/ehci.h
+++ b/drivers/usb/host/ehci.h
@@ -210,143 +210,7 @@
 
 /*-------------------------------------------------------------------------*/
 
-/* EHCI register interface, corresponds to EHCI Revision 0.95 specification */
-
-/* Section 2.2 Host Controller Capability Registers */
-struct ehci_caps {
-	/* these fields are specified as 8 and 16 bit registers,
-	 * but some hosts can't perform 8 or 16 bit PCI accesses.
-	 */
-	u32		hc_capbase;
-#define HC_LENGTH(p)		(((p)>>00)&0x00ff)	/* bits 7:0 */
-#define HC_VERSION(p)		(((p)>>16)&0xffff)	/* bits 31:16 */
-	u32		hcs_params;     /* HCSPARAMS - offset 0x4 */
-#define HCS_DEBUG_PORT(p)	(((p)>>20)&0xf)	/* bits 23:20, debug port? */
-#define HCS_INDICATOR(p)	((p)&(1 << 16))	/* true: has port indicators */
-#define HCS_N_CC(p)		(((p)>>12)&0xf)	/* bits 15:12, #companion HCs */
-#define HCS_N_PCC(p)		(((p)>>8)&0xf)	/* bits 11:8, ports per CC */
-#define HCS_PORTROUTED(p)	((p)&(1 << 7))	/* true: port routing */
-#define HCS_PPC(p)		((p)&(1 << 4))	/* true: port power control */
-#define HCS_N_PORTS(p)		(((p)>>0)&0xf)	/* bits 3:0, ports on HC */
-
-	u32		hcc_params;      /* HCCPARAMS - offset 0x8 */
-#define HCC_EXT_CAPS(p)		(((p)>>8)&0xff)	/* for pci extended caps */
-#define HCC_ISOC_CACHE(p)       ((p)&(1 << 7))  /* true: can cache isoc frame */
-#define HCC_ISOC_THRES(p)       (((p)>>4)&0x7)  /* bits 6:4, uframes cached */
-#define HCC_CANPARK(p)		((p)&(1 << 2))  /* true: can park on async qh */
-#define HCC_PGM_FRAMELISTLEN(p) ((p)&(1 << 1))  /* true: periodic_size changes*/
-#define HCC_64BIT_ADDR(p)       ((p)&(1))       /* true: can use 64-bit addr */
-	u8		portroute [8];	 /* nibbles for routing - offset 0xC */
-} __attribute__ ((packed));
-
-
-/* Section 2.3 Host Controller Operational Registers */
-struct ehci_regs {
-
-	/* USBCMD: offset 0x00 */
-	u32		command;
-/* 23:16 is r/w intr rate, in microframes; default "8" == 1/msec */
-#define CMD_PARK	(1<<11)		/* enable "park" on async qh */
-#define CMD_PARK_CNT(c)	(((c)>>8)&3)	/* how many transfers to park for */
-#define CMD_LRESET	(1<<7)		/* partial reset (no ports, etc) */
-#define CMD_IAAD	(1<<6)		/* "doorbell" interrupt async advance */
-#define CMD_ASE		(1<<5)		/* async schedule enable */
-#define CMD_PSE		(1<<4)		/* periodic schedule enable */
-/* 3:2 is periodic frame list size */
-#define CMD_RESET	(1<<1)		/* reset HC not bus */
-#define CMD_RUN		(1<<0)		/* start/stop HC */
-
-	/* USBSTS: offset 0x04 */
-	u32		status;
-#define STS_ASS		(1<<15)		/* Async Schedule Status */
-#define STS_PSS		(1<<14)		/* Periodic Schedule Status */
-#define STS_RECL	(1<<13)		/* Reclamation */
-#define STS_HALT	(1<<12)		/* Not running (any reason) */
-/* some bits reserved */
-	/* these STS_* flags are also intr_enable bits (USBINTR) */
-#define STS_IAA		(1<<5)		/* Interrupted on async advance */
-#define STS_FATAL	(1<<4)		/* such as some PCI access errors */
-#define STS_FLR		(1<<3)		/* frame list rolled over */
-#define STS_PCD		(1<<2)		/* port change detect */
-#define STS_ERR		(1<<1)		/* "error" completion (overflow, ...) */
-#define STS_INT		(1<<0)		/* "normal" completion (short, ...) */
-
-	/* USBINTR: offset 0x08 */
-	u32		intr_enable;
-
-	/* FRINDEX: offset 0x0C */
-	u32		frame_index;	/* current microframe number */
-	/* CTRLDSSEGMENT: offset 0x10 */
-	u32		segment;	/* address bits 63:32 if needed */
-	/* PERIODICLISTBASE: offset 0x14 */
-	u32		frame_list;	/* points to periodic list */
-	/* ASYNCLISTADDR: offset 0x18 */
-	u32		async_next;	/* address of next async queue head */
-
-	u32		reserved [9];
-
-	/* CONFIGFLAG: offset 0x40 */
-	u32		configured_flag;
-#define FLAG_CF		(1<<0)		/* true: we'll support "high speed" */
-
-	/* PORTSC: offset 0x44 */
-	u32		port_status [0];	/* up to N_PORTS */
-/* 31:23 reserved */
-#define PORT_WKOC_E	(1<<22)		/* wake on overcurrent (enable) */
-#define PORT_WKDISC_E	(1<<21)		/* wake on disconnect (enable) */
-#define PORT_WKCONN_E	(1<<20)		/* wake on connect (enable) */
-/* 19:16 for port testing */
-#define PORT_LED_OFF	(0<<14)
-#define PORT_LED_AMBER	(1<<14)
-#define PORT_LED_GREEN	(2<<14)
-#define PORT_LED_MASK	(3<<14)
-#define PORT_OWNER	(1<<13)		/* true: companion hc owns this port */
-#define PORT_POWER	(1<<12)		/* true: has power (see PPC) */
-#define PORT_USB11(x) (((x)&(3<<10))==(1<<10))	/* USB 1.1 device */
-/* 11:10 for detecting lowspeed devices (reset vs release ownership) */
-/* 9 reserved */
-#define PORT_RESET	(1<<8)		/* reset port */
-#define PORT_SUSPEND	(1<<7)		/* suspend port */
-#define PORT_RESUME	(1<<6)		/* resume it */
-#define PORT_OCC	(1<<5)		/* over current change */
-#define PORT_OC		(1<<4)		/* over current active */
-#define PORT_PEC	(1<<3)		/* port enable change */
-#define PORT_PE		(1<<2)		/* port enable */
-#define PORT_CSC	(1<<1)		/* connect status change */
-#define PORT_CONNECT	(1<<0)		/* device connected */
-#define PORT_RWC_BITS   (PORT_CSC | PORT_PEC | PORT_OCC)
-} __attribute__ ((packed));
-
-#define USBMODE		0x68		/* USB Device mode */
-#define USBMODE_SDIS	(1<<3)		/* Stream disable */
-#define USBMODE_BE	(1<<2)		/* BE/LE endianness select */
-#define USBMODE_CM_HC	(3<<0)		/* host controller mode */
-#define USBMODE_CM_IDLE	(0<<0)		/* idle state */
-
-/* Appendix C, Debug port ... intended for use with special "debug devices"
- * that can help if there's no serial console.  (nonstandard enumeration.)
- */
-struct ehci_dbg_port {
-	u32	control;
-#define DBGP_OWNER	(1<<30)
-#define DBGP_ENABLED	(1<<28)
-#define DBGP_DONE	(1<<16)
-#define DBGP_INUSE	(1<<10)
-#define DBGP_ERRCODE(x)	(((x)>>7)&0x07)
-#	define DBGP_ERR_BAD	1
-#	define DBGP_ERR_SIGNAL	2
-#define DBGP_ERROR	(1<<6)
-#define DBGP_GO		(1<<5)
-#define DBGP_OUT	(1<<4)
-#define DBGP_LEN(x)	(((x)>>0)&0x0f)
-	u32	pids;
-#define DBGP_PID_GET(x)		(((x)>>16)&0xff)
-#define DBGP_PID_SET(data,tok)	(((data)<<8)|(tok))
-	u32	data03;
-	u32	data47;
-	u32	address;
-#define DBGP_EPADDR(dev,ep)	(((dev)<<8)|(ep))
-} __attribute__ ((packed));
+#include <linux/usb/ehci_def.h>
 
 /*-------------------------------------------------------------------------*/
 
diff --git a/drivers/usb/host/ohci-pxa27x.c b/drivers/usb/host/ohci-pxa27x.c
index 7f0f35c..e294d43 100644
--- a/drivers/usb/host/ohci-pxa27x.c
+++ b/drivers/usb/host/ohci-pxa27x.c
@@ -23,17 +23,90 @@
 #include <linux/signal.h>
 #include <linux/platform_device.h>
 #include <linux/clk.h>
-
-#include <mach/hardware.h>
-#include <mach/pxa-regs.h>
-#include <mach/pxa2xx-regs.h> /* FIXME: for PSSR */
 #include <mach/ohci.h>
 
+/*
+ * UHC: USB Host Controller (OHCI-like) register definitions
+ */
+#define UHCREV		(0x0000) /* UHC HCI Spec Revision */
+#define UHCHCON		(0x0004) /* UHC Host Control Register */
+#define UHCCOMS		(0x0008) /* UHC Command Status Register */
+#define UHCINTS		(0x000C) /* UHC Interrupt Status Register */
+#define UHCINTE		(0x0010) /* UHC Interrupt Enable */
+#define UHCINTD		(0x0014) /* UHC Interrupt Disable */
+#define UHCHCCA		(0x0018) /* UHC Host Controller Comm. Area */
+#define UHCPCED		(0x001C) /* UHC Period Current Endpt Descr */
+#define UHCCHED		(0x0020) /* UHC Control Head Endpt Descr */
+#define UHCCCED		(0x0024) /* UHC Control Current Endpt Descr */
+#define UHCBHED		(0x0028) /* UHC Bulk Head Endpt Descr */
+#define UHCBCED		(0x002C) /* UHC Bulk Current Endpt Descr */
+#define UHCDHEAD	(0x0030) /* UHC Done Head */
+#define UHCFMI		(0x0034) /* UHC Frame Interval */
+#define UHCFMR		(0x0038) /* UHC Frame Remaining */
+#define UHCFMN		(0x003C) /* UHC Frame Number */
+#define UHCPERS		(0x0040) /* UHC Periodic Start */
+#define UHCLS		(0x0044) /* UHC Low Speed Threshold */
+
+#define UHCRHDA		(0x0048) /* UHC Root Hub Descriptor A */
+#define UHCRHDA_NOCP	(1 << 12)	/* No over current protection */
+#define UHCRHDA_OCPM	(1 << 11)	/* Over Current Protection Mode */
+#define UHCRHDA_POTPGT(x) \
+			(((x) & 0xff) << 24) /* Power On To Power Good Time */
+
+#define UHCRHDB		(0x004C) /* UHC Root Hub Descriptor B */
+#define UHCRHS		(0x0050) /* UHC Root Hub Status */
+#define UHCRHPS1	(0x0054) /* UHC Root Hub Port 1 Status */
+#define UHCRHPS2	(0x0058) /* UHC Root Hub Port 2 Status */
+#define UHCRHPS3	(0x005C) /* UHC Root Hub Port 3 Status */
+
+#define UHCSTAT		(0x0060) /* UHC Status Register */
+#define UHCSTAT_UPS3	(1 << 16)	/* USB Power Sense Port3 */
+#define UHCSTAT_SBMAI	(1 << 15)	/* System Bus Master Abort Interrupt*/
+#define UHCSTAT_SBTAI	(1 << 14)	/* System Bus Target Abort Interrupt*/
+#define UHCSTAT_UPRI	(1 << 13)	/* USB Port Resume Interrupt */
+#define UHCSTAT_UPS2	(1 << 12)	/* USB Power Sense Port 2 */
+#define UHCSTAT_UPS1	(1 << 11)	/* USB Power Sense Port 1 */
+#define UHCSTAT_HTA	(1 << 10)	/* HCI Target Abort */
+#define UHCSTAT_HBA	(1 << 8)	/* HCI Buffer Active */
+#define UHCSTAT_RWUE	(1 << 7)	/* HCI Remote Wake Up Event */
+
+#define UHCHR           (0x0064) /* UHC Reset Register */
+#define UHCHR_SSEP3	(1 << 11)	/* Sleep Standby Enable for Port3 */
+#define UHCHR_SSEP2	(1 << 10)	/* Sleep Standby Enable for Port2 */
+#define UHCHR_SSEP1	(1 << 9)	/* Sleep Standby Enable for Port1 */
+#define UHCHR_PCPL	(1 << 7)	/* Power control polarity low */
+#define UHCHR_PSPL	(1 << 6)	/* Power sense polarity low */
+#define UHCHR_SSE	(1 << 5)	/* Sleep Standby Enable */
+#define UHCHR_UIT	(1 << 4)	/* USB Interrupt Test */
+#define UHCHR_SSDC	(1 << 3)	/* Simulation Scale Down Clock */
+#define UHCHR_CGR	(1 << 2)	/* Clock Generation Reset */
+#define UHCHR_FHR	(1 << 1)	/* Force Host Controller Reset */
+#define UHCHR_FSBIR	(1 << 0)	/* Force System Bus Iface Reset */
+
+#define UHCHIE          (0x0068) /* UHC Interrupt Enable Register*/
+#define UHCHIE_UPS3IE	(1 << 14)	/* Power Sense Port3 IntEn */
+#define UHCHIE_UPRIE	(1 << 13)	/* Port Resume IntEn */
+#define UHCHIE_UPS2IE	(1 << 12)	/* Power Sense Port2 IntEn */
+#define UHCHIE_UPS1IE	(1 << 11)	/* Power Sense Port1 IntEn */
+#define UHCHIE_TAIE	(1 << 10)	/* HCI Interface Transfer Abort
+					   Interrupt Enable*/
+#define UHCHIE_HBAIE	(1 << 8)	/* HCI Buffer Active IntEn */
+#define UHCHIE_RWIE	(1 << 7)	/* Remote Wake-up IntEn */
+
+#define UHCHIT          (0x006C) /* UHC Interrupt Test register */
+
 #define PXA_UHC_MAX_PORTNUM    3
 
-#define UHCRHPS(x)              __REG2( 0x4C000050, (x)<<2 )
+struct pxa27x_ohci {
+	/* must be 1st member here for hcd_to_ohci() to work */
+	struct ohci_hcd ohci;
 
-static struct clk *usb_clk;
+	struct device	*dev;
+	struct clk	*clk;
+	void __iomem	*mmio_base;
+};
+
+#define to_pxa27x_ohci(hcd)	(struct pxa27x_ohci *)hcd_to_ohci(hcd)
 
 /*
   PMM_NPS_MODE -- PMM Non-power switching mode
@@ -45,30 +118,35 @@
   PMM_PERPORT_MODE -- PMM per port switching mode
       Ports are powered individually.
  */
-static int pxa27x_ohci_select_pmm( int mode )
+static int pxa27x_ohci_select_pmm(struct pxa27x_ohci *ohci, int mode)
 {
-	switch ( mode ) {
+	uint32_t uhcrhda = __raw_readl(ohci->mmio_base + UHCRHDA);
+	uint32_t uhcrhdb = __raw_readl(ohci->mmio_base + UHCRHDB);
+
+	switch (mode) {
 	case PMM_NPS_MODE:
-		UHCRHDA |= RH_A_NPS;
+		uhcrhda |= RH_A_NPS;
 		break;
 	case PMM_GLOBAL_MODE:
-		UHCRHDA &= ~(RH_A_NPS & RH_A_PSM);
+		uhcrhda &= ~(RH_A_NPS & RH_A_PSM);
 		break;
 	case PMM_PERPORT_MODE:
-		UHCRHDA &= ~(RH_A_NPS);
-		UHCRHDA |= RH_A_PSM;
+		uhcrhda &= ~(RH_A_NPS);
+		uhcrhda |= RH_A_PSM;
 
 		/* Set port power control mask bits, only 3 ports. */
-		UHCRHDB |= (0x7<<17);
+		uhcrhdb |= (0x7<<17);
 		break;
 	default:
 		printk( KERN_ERR
 			"Invalid mode %d, set to non-power switch mode.\n",
 			mode );
 
-		UHCRHDA |= RH_A_NPS;
+		uhcrhda |= RH_A_NPS;
 	}
 
+	__raw_writel(uhcrhda, ohci->mmio_base + UHCRHDA);
+	__raw_writel(uhcrhdb, ohci->mmio_base + UHCRHDB);
 	return 0;
 }
 
@@ -76,57 +154,110 @@
 
 /*-------------------------------------------------------------------------*/
 
-static int pxa27x_start_hc(struct device *dev)
+static inline void pxa27x_setup_hc(struct pxa27x_ohci *ohci,
+				   struct pxaohci_platform_data *inf)
+{
+	uint32_t uhchr = __raw_readl(ohci->mmio_base + UHCHR);
+	uint32_t uhcrhda = __raw_readl(ohci->mmio_base + UHCRHDA);
+
+	if (inf->flags & ENABLE_PORT1)
+		uhchr &= ~UHCHR_SSEP1;
+
+	if (inf->flags & ENABLE_PORT2)
+		uhchr &= ~UHCHR_SSEP2;
+
+	if (inf->flags & ENABLE_PORT3)
+		uhchr &= ~UHCHR_SSEP3;
+
+	if (inf->flags & POWER_CONTROL_LOW)
+		uhchr |= UHCHR_PCPL;
+
+	if (inf->flags & POWER_SENSE_LOW)
+		uhchr |= UHCHR_PSPL;
+
+	if (inf->flags & NO_OC_PROTECTION)
+		uhcrhda |= UHCRHDA_NOCP;
+
+	if (inf->flags & OC_MODE_PERPORT)
+		uhcrhda |= UHCRHDA_OCPM;
+
+	if (inf->power_on_delay) {
+		uhcrhda &= ~UHCRHDA_POTPGT(0xff);
+		uhcrhda |= UHCRHDA_POTPGT(inf->power_on_delay / 2);
+	}
+
+	__raw_writel(uhchr, ohci->mmio_base + UHCHR);
+	__raw_writel(uhcrhda, ohci->mmio_base + UHCRHDA);
+}
+
+static inline void pxa27x_reset_hc(struct pxa27x_ohci *ohci)
+{
+	uint32_t uhchr = __raw_readl(ohci->mmio_base + UHCHR);
+
+	__raw_writel(uhchr | UHCHR_FHR, ohci->mmio_base + UHCHR);
+	udelay(11);
+	__raw_writel(uhchr & ~UHCHR_FHR, ohci->mmio_base + UHCHR);
+}
+
+#ifdef CONFIG_CPU_PXA27x
+extern void pxa27x_clear_otgph(void);
+#else
+#define pxa27x_clear_otgph()	do {} while (0)
+#endif
+
+static int pxa27x_start_hc(struct pxa27x_ohci *ohci, struct device *dev)
 {
 	int retval = 0;
 	struct pxaohci_platform_data *inf;
+	uint32_t uhchr;
 
 	inf = dev->platform_data;
 
-	clk_enable(usb_clk);
+	clk_enable(ohci->clk);
 
-	UHCHR |= UHCHR_FHR;
-	udelay(11);
-	UHCHR &= ~UHCHR_FHR;
+	pxa27x_reset_hc(ohci);
 
-	UHCHR |= UHCHR_FSBIR;
-	while (UHCHR & UHCHR_FSBIR)
+	uhchr = __raw_readl(ohci->mmio_base + UHCHR) | UHCHR_FSBIR;
+	__raw_writel(uhchr, ohci->mmio_base + UHCHR);
+
+	while (__raw_readl(ohci->mmio_base + UHCHR) & UHCHR_FSBIR)
 		cpu_relax();
 
+	pxa27x_setup_hc(ohci, inf);
+
 	if (inf->init)
 		retval = inf->init(dev);
 
 	if (retval < 0)
 		return retval;
 
-	UHCHR &= ~UHCHR_SSE;
-
-	UHCHIE = (UHCHIE_UPRIE | UHCHIE_RWIE);
+	uhchr = __raw_readl(ohci->mmio_base + UHCHR) & ~UHCHR_SSE;
+	__raw_writel(uhchr, ohci->mmio_base + UHCHR);
+	__raw_writel(UHCHIE_UPRIE | UHCHIE_RWIE, ohci->mmio_base + UHCHIE);
 
 	/* Clear any OTG Pin Hold */
-	if (cpu_is_pxa27x() && (PSSR & PSSR_OTGPH))
-		PSSR |= PSSR_OTGPH;
-
+	pxa27x_clear_otgph();
 	return 0;
 }
 
-static void pxa27x_stop_hc(struct device *dev)
+static void pxa27x_stop_hc(struct pxa27x_ohci *ohci, struct device *dev)
 {
 	struct pxaohci_platform_data *inf;
+	uint32_t uhccoms;
 
 	inf = dev->platform_data;
 
 	if (inf->exit)
 		inf->exit(dev);
 
-	UHCHR |= UHCHR_FHR;
-	udelay(11);
-	UHCHR &= ~UHCHR_FHR;
+	pxa27x_reset_hc(ohci);
 
-	UHCCOMS |= 1;
+	/* Host Controller Reset */
+	uhccoms = __raw_readl(ohci->mmio_base + UHCCOMS) | 0x01;
+	__raw_writel(uhccoms, ohci->mmio_base + UHCCOMS);
 	udelay(10);
 
-	clk_disable(usb_clk);
+	clk_disable(ohci->clk);
 }
 
 
@@ -147,18 +278,22 @@
  */
 int usb_hcd_pxa27x_probe (const struct hc_driver *driver, struct platform_device *pdev)
 {
-	int retval;
+	int retval, irq;
 	struct usb_hcd *hcd;
 	struct pxaohci_platform_data *inf;
+	struct pxa27x_ohci *ohci;
+	struct resource *r;
+	struct clk *usb_clk;
 
 	inf = pdev->dev.platform_data;
 
 	if (!inf)
 		return -ENODEV;
 
-	if (pdev->resource[1].flags != IORESOURCE_IRQ) {
-		pr_debug ("resource[1] is not IORESOURCE_IRQ");
-		return -ENOMEM;
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0) {
+		pr_err("no resource of IORESOURCE_IRQ");
+		return -ENXIO;
 	}
 
 	usb_clk = clk_get(&pdev->dev, "USBCLK");
@@ -168,8 +303,16 @@
 	hcd = usb_create_hcd (driver, &pdev->dev, "pxa27x");
 	if (!hcd)
 		return -ENOMEM;
-	hcd->rsrc_start = pdev->resource[0].start;
-	hcd->rsrc_len = pdev->resource[0].end - pdev->resource[0].start + 1;
+
+	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!r) {
+		pr_err("no resource of IORESOURCE_MEM");
+		retval = -ENXIO;
+		goto err1;
+	}
+
+	hcd->rsrc_start = r->start;
+	hcd->rsrc_len = resource_size(r);
 
 	if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
 		pr_debug("request_mem_region failed");
@@ -184,24 +327,30 @@
 		goto err2;
 	}
 
-	if ((retval = pxa27x_start_hc(&pdev->dev)) < 0) {
+	/* initialize "struct pxa27x_ohci" */
+	ohci = (struct pxa27x_ohci *)hcd_to_ohci(hcd);
+	ohci->dev = &pdev->dev;
+	ohci->clk = usb_clk;
+	ohci->mmio_base = (void __iomem *)hcd->regs;
+
+	if ((retval = pxa27x_start_hc(ohci, &pdev->dev)) < 0) {
 		pr_debug("pxa27x_start_hc failed");
 		goto err3;
 	}
 
 	/* Select Power Management Mode */
-	pxa27x_ohci_select_pmm(inf->port_mode);
+	pxa27x_ohci_select_pmm(ohci, inf->port_mode);
 
 	if (inf->power_budget)
 		hcd->power_budget = inf->power_budget;
 
 	ohci_hcd_init(hcd_to_ohci(hcd));
 
-	retval = usb_add_hcd(hcd, pdev->resource[1].start, IRQF_DISABLED);
+	retval = usb_add_hcd(hcd, irq, IRQF_DISABLED);
 	if (retval == 0)
 		return retval;
 
-	pxa27x_stop_hc(&pdev->dev);
+	pxa27x_stop_hc(ohci, &pdev->dev);
  err3:
 	iounmap(hcd->regs);
  err2:
@@ -228,12 +377,14 @@
  */
 void usb_hcd_pxa27x_remove (struct usb_hcd *hcd, struct platform_device *pdev)
 {
+	struct pxa27x_ohci *ohci = to_pxa27x_ohci(hcd);
+
 	usb_remove_hcd(hcd);
-	pxa27x_stop_hc(&pdev->dev);
+	pxa27x_stop_hc(ohci, &pdev->dev);
 	iounmap(hcd->regs);
 	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
 	usb_put_hcd(hcd);
-	clk_put(usb_clk);
+	clk_put(ohci->clk);
 }
 
 /*-------------------------------------------------------------------------*/
@@ -266,7 +417,7 @@
 static const struct hc_driver ohci_pxa27x_hc_driver = {
 	.description =		hcd_name,
 	.product_desc =		"PXA27x OHCI",
-	.hcd_priv_size =	sizeof(struct ohci_hcd),
+	.hcd_priv_size =	sizeof(struct pxa27x_ohci),
 
 	/*
 	 * generic hardware linkage
@@ -330,13 +481,13 @@
 static int ohci_hcd_pxa27x_drv_suspend(struct platform_device *pdev, pm_message_t state)
 {
 	struct usb_hcd *hcd = platform_get_drvdata(pdev);
-	struct ohci_hcd *ohci = hcd_to_ohci(hcd);
+	struct pxa27x_ohci *ohci = to_pxa27x_ohci(hcd);
 
-	if (time_before(jiffies, ohci->next_statechange))
+	if (time_before(jiffies, ohci->ohci.next_statechange))
 		msleep(5);
-	ohci->next_statechange = jiffies;
+	ohci->ohci.next_statechange = jiffies;
 
-	pxa27x_stop_hc(&pdev->dev);
+	pxa27x_stop_hc(ohci, &pdev->dev);
 	hcd->state = HC_STATE_SUSPENDED;
 
 	return 0;
@@ -345,14 +496,14 @@
 static int ohci_hcd_pxa27x_drv_resume(struct platform_device *pdev)
 {
 	struct usb_hcd *hcd = platform_get_drvdata(pdev);
-	struct ohci_hcd *ohci = hcd_to_ohci(hcd);
+	struct pxa27x_ohci *ohci = to_pxa27x_ohci(hcd);
 	int status;
 
-	if (time_before(jiffies, ohci->next_statechange))
+	if (time_before(jiffies, ohci->ohci.next_statechange))
 		msleep(5);
-	ohci->next_statechange = jiffies;
+	ohci->ohci.next_statechange = jiffies;
 
-	if ((status = pxa27x_start_hc(&pdev->dev)) < 0)
+	if ((status = pxa27x_start_hc(ohci, &pdev->dev)) < 0)
 		return status;
 
 	ohci_finish_controller_resume(hcd);
diff --git a/drivers/usb/host/sl811_cs.c b/drivers/usb/host/sl811_cs.c
index 5da63f5..516848d 100644
--- a/drivers/usb/host/sl811_cs.c
+++ b/drivers/usb/host/sl811_cs.c
@@ -112,7 +112,8 @@
 	.num_resources		= ARRAY_SIZE(resources),
 };
 
-static int sl811_hc_init(struct device *parent, ioaddr_t base_addr, int irq)
+static int sl811_hc_init(struct device *parent, resource_size_t base_addr,
+			 int irq)
 {
 	if (platform_dev.dev.parent)
 		return -EBUSY;
@@ -155,97 +156,72 @@
 	platform_device_unregister(&platform_dev);
 }
 
+static int sl811_cs_config_check(struct pcmcia_device *p_dev,
+				 cistpl_cftable_entry_t *cfg,
+				 cistpl_cftable_entry_t *dflt,
+				 unsigned int vcc,
+				 void *priv_data)
+{
+	if (cfg->index == 0)
+		return -ENODEV;
+
+	/* Use power settings for Vcc and Vpp if present */
+	/*  Note that the CIS values need to be rescaled */
+	if (cfg->vcc.present & (1<<CISTPL_POWER_VNOM)) {
+		if (cfg->vcc.param[CISTPL_POWER_VNOM]/10000 != vcc)
+			return -ENODEV;
+	} else if (dflt->vcc.present & (1<<CISTPL_POWER_VNOM)) {
+		if (dflt->vcc.param[CISTPL_POWER_VNOM]/10000 != vcc)
+			return -ENODEV;
+		}
+
+	if (cfg->vpp1.present & (1<<CISTPL_POWER_VNOM))
+		p_dev->conf.Vpp =
+			cfg->vpp1.param[CISTPL_POWER_VNOM]/10000;
+	else if (dflt->vpp1.present & (1<<CISTPL_POWER_VNOM))
+		p_dev->conf.Vpp =
+			dflt->vpp1.param[CISTPL_POWER_VNOM]/10000;
+
+	/* we need an interrupt */
+	if (cfg->irq.IRQInfo1 || dflt->irq.IRQInfo1)
+		p_dev->conf.Attributes |= CONF_ENABLE_IRQ;
+
+	/* IO window settings */
+	p_dev->io.NumPorts1 = p_dev->io.NumPorts2 = 0;
+	if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) {
+		cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io;
+
+		p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
+		p_dev->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK;
+		p_dev->io.BasePort1 = io->win[0].base;
+		p_dev->io.NumPorts1 = io->win[0].len;
+
+		return pcmcia_request_io(p_dev, &p_dev->io);
+	}
+	pcmcia_disable_device(p_dev);
+	return -ENODEV;
+}
+
+
 static int sl811_cs_config(struct pcmcia_device *link)
 {
 	struct device		*parent = &handle_to_dev(link);
 	local_info_t		*dev = link->priv;
-	tuple_t			tuple;
-	cisparse_t		parse;
 	int			last_fn, last_ret;
-	u_char			buf[64];
-	config_info_t		conf;
-	cistpl_cftable_entry_t	dflt = { 0 };
 
 	DBG(0, "sl811_cs_config(0x%p)\n", link);
 
-	/* Look up the current Vcc */
-	CS_CHECK(GetConfigurationInfo,
-			pcmcia_get_configuration_info(link, &conf));
-
-	tuple.Attributes = 0;
-	tuple.TupleData = buf;
-	tuple.TupleDataMax = sizeof(buf);
-	tuple.TupleOffset = 0;
-	tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
-	CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple));
-	while (1) {
-		cistpl_cftable_entry_t	*cfg = &(parse.cftable_entry);
-
-		if (pcmcia_get_tuple_data(link, &tuple) != 0
-				|| pcmcia_parse_tuple(link, &tuple, &parse)
-						!= 0)
-			goto next_entry;
-
-		if (cfg->flags & CISTPL_CFTABLE_DEFAULT) {
-			dflt = *cfg;
-		}
-
-		if (cfg->index == 0)
-			goto next_entry;
-
-		link->conf.ConfigIndex = cfg->index;
-
-		/* Use power settings for Vcc and Vpp if present */
-		/*  Note that the CIS values need to be rescaled */
-		if (cfg->vcc.present & (1<<CISTPL_POWER_VNOM)) {
-			if (cfg->vcc.param[CISTPL_POWER_VNOM]/10000
-					!= conf.Vcc)
-				goto next_entry;
-		} else if (dflt.vcc.present & (1<<CISTPL_POWER_VNOM)) {
-			if (dflt.vcc.param[CISTPL_POWER_VNOM]/10000
-					!= conf.Vcc)
-				goto next_entry;
-		}
-
-		if (cfg->vpp1.present & (1<<CISTPL_POWER_VNOM))
-			link->conf.Vpp =
-				cfg->vpp1.param[CISTPL_POWER_VNOM]/10000;
-		else if (dflt.vpp1.present & (1<<CISTPL_POWER_VNOM))
-			link->conf.Vpp =
-				dflt.vpp1.param[CISTPL_POWER_VNOM]/10000;
-
-		/* we need an interrupt */
-		if (cfg->irq.IRQInfo1 || dflt.irq.IRQInfo1)
-			link->conf.Attributes |= CONF_ENABLE_IRQ;
-
-		/* IO window settings */
-		link->io.NumPorts1 = link->io.NumPorts2 = 0;
-		if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) {
-			cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt.io;
-
-			link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
-			link->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK;
-			link->io.BasePort1 = io->win[0].base;
-			link->io.NumPorts1 = io->win[0].len;
-
-			if (pcmcia_request_io(link, &link->io) != 0)
-				goto next_entry;
-		}
-		break;
-
-next_entry:
-		pcmcia_disable_device(link);
-		last_ret = pcmcia_get_next_tuple(link, &tuple);
-	}
+	if (pcmcia_loop_config(link, sl811_cs_config_check, NULL))
+		goto failed;
 
 	/* require an IRQ and two registers */
 	if (!link->io.NumPorts1 || link->io.NumPorts1 < 2)
-		goto cs_failed;
+		goto failed;
 	if (link->conf.Attributes & CONF_ENABLE_IRQ)
 		CS_CHECK(RequestIRQ,
 			pcmcia_request_irq(link, &link->irq));
 	else
-		goto cs_failed;
+		goto failed;
 
 	CS_CHECK(RequestConfiguration,
 		pcmcia_request_configuration(link, &link->conf));
@@ -266,8 +242,9 @@
 	if (sl811_hc_init(parent, link->io.BasePort1, link->irq.AssignedIRQ)
 			< 0) {
 cs_failed:
-		printk("sl811_cs_config failed\n");
 		cs_error(link, last_fn, last_ret);
+failed:
+		printk(KERN_WARNING "sl811_cs_config failed\n");
 		sl811_cs_release(link);
 		return  -ENODEV;
 	}
diff --git a/drivers/usb/musb/Kconfig b/drivers/usb/musb/Kconfig
index a001748..58b2b8f 100644
--- a/drivers/usb/musb/Kconfig
+++ b/drivers/usb/musb/Kconfig
@@ -9,6 +9,7 @@
 # (M)HDRC = (Multipoint) Highspeed Dual-Role Controller
 config USB_MUSB_HDRC
 	depends on (USB || USB_GADGET) && HAVE_CLK
+	depends on !SUPERH
 	select TWL4030_USB if MACH_OMAP_3430SDP
 	tristate 'Inventra Highspeed Dual Role Controller (TI, ...)'
 	help
diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c
index c5b8f02..128e949 100644
--- a/drivers/usb/musb/musb_core.c
+++ b/drivers/usb/musb/musb_core.c
@@ -100,8 +100,8 @@
 #include <linux/io.h>
 
 #ifdef	CONFIG_ARM
-#include <asm/arch/hardware.h>
-#include <asm/arch/memory.h>
+#include <mach/hardware.h>
+#include <mach/memory.h>
 #include <asm/mach-types.h>
 #endif
 
diff --git a/drivers/usb/musb/omap2430.c b/drivers/usb/musb/omap2430.c
index 298b22e..9d2dcb1 100644
--- a/drivers/usb/musb/omap2430.c
+++ b/drivers/usb/musb/omap2430.c
@@ -35,8 +35,8 @@
 #include <linux/io.h>
 
 #include <asm/mach-types.h>
-#include <asm/arch/hardware.h>
-#include <asm/arch/mux.h>
+#include <mach/hardware.h>
+#include <mach/mux.h>
 
 #include "musb_core.h"
 #include "omap2430.h"
diff --git a/drivers/usb/musb/omap2430.h b/drivers/usb/musb/omap2430.h
index 786a620..dc76707 100644
--- a/drivers/usb/musb/omap2430.h
+++ b/drivers/usb/musb/omap2430.h
@@ -11,8 +11,8 @@
 #define __MUSB_OMAP243X_H__
 
 #if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3430)
-#include <asm/arch/hardware.h>
-#include <asm/arch/usb.h>
+#include <mach/hardware.h>
+#include <mach/usb.h>
 
 /*
  * OMAP2430-specific definitions
diff --git a/drivers/usb/serial/aircable.c b/drivers/usb/serial/aircable.c
index 79ea98c..99fb7dc 100644
--- a/drivers/usb/serial/aircable.c
+++ b/drivers/usb/serial/aircable.c
@@ -272,7 +272,7 @@
 	 * 64 bytes, to ensure I do not get throttled.
 	 * Ask USB mailing list for better aproach.
 	 */
-	tty = port->port.tty;
+	tty = tty_port_tty_get(&port->port);
 
 	if (!tty) {
 		schedule_work(&priv->rx_work);
@@ -283,12 +283,13 @@
 	count = min(64, serial_buf_data_avail(priv->rx_buf));
 
 	if (count <= 0)
-		return; /* We have finished sending everything. */
+		goto out; /* We have finished sending everything. */
 
 	tty_prepare_flip_string(tty, &data, count);
 	if (!data) {
-		err("%s- kzalloc(%d) failed.", __func__, count);
-		return;
+		dev_err(&port->dev, "%s- kzalloc(%d) failed.",
+							__func__, count);
+		goto out;
 	}
 
 	serial_buf_get(priv->rx_buf, data, count);
@@ -297,7 +298,8 @@
 
 	if (serial_buf_data_avail(priv->rx_buf))
 		schedule_work(&priv->rx_work);
-
+out:		
+	tty_kref_put(tty);
 	return;
 }
 /* End of private methods */
@@ -495,7 +497,7 @@
 	usb_serial_debug_data(debug, &port->dev, __func__,
 				urb->actual_length, urb->transfer_buffer);
 
-	tty = port->port.tty;
+	tty = tty_port_tty_get(&port->port);
 	if (tty && urb->actual_length) {
 		if (urb->actual_length <= 2) {
 			/* This is an incomplete package */
@@ -527,6 +529,7 @@
 		}
 		aircable_read(&priv->rx_work);
 	}
+	tty_kref_put(tty);
 
 	/* Schedule the next read _if_ we are still open */
 	if (port->port.count) {
diff --git a/drivers/usb/serial/belkin_sa.c b/drivers/usb/serial/belkin_sa.c
index 2ebe06c..1913bc7 100644
--- a/drivers/usb/serial/belkin_sa.c
+++ b/drivers/usb/serial/belkin_sa.c
@@ -322,7 +322,7 @@
 	 * to look in to this before committing any code.
 	 */
 	if (priv->last_lsr & BELKIN_SA_LSR_ERR) {
-		tty = port->port.tty;
+		tty = tty_port_tty_get(&port->port);
 		/* Overrun Error */
 		if (priv->last_lsr & BELKIN_SA_LSR_OE) {
 		}
@@ -335,6 +335,7 @@
 		/* Break Indicator */
 		if (priv->last_lsr & BELKIN_SA_LSR_BI) {
 		}
+		tty_kref_put(tty);
 	}
 #endif
 	spin_unlock_irqrestore(&priv->lock, flags);
diff --git a/drivers/usb/serial/console.c b/drivers/usb/serial/console.c
index e980766..5b20de1 100644
--- a/drivers/usb/serial/console.c
+++ b/drivers/usb/serial/console.c
@@ -117,7 +117,7 @@
 	}
 
 	port = serial->port[0];
-	port->port.tty = NULL;
+	tty_port_tty_set(&port->port, NULL);
 
 	info->port = port;
 
@@ -143,7 +143,7 @@
 			}
 			memset(&dummy, 0, sizeof(struct ktermios));
 			tty->termios = termios;
-			port->port.tty = tty;
+			tty_port_tty_set(&port->port, tty);
 		}
 
 		/* only call the device specific open if this
@@ -163,7 +163,7 @@
 			tty_termios_encode_baud_rate(termios, baud, baud);
 			serial->type->set_termios(tty, port, &dummy);
 
-			port->port.tty = NULL;
+			tty_port_tty_set(&port->port, NULL);
 			kfree(termios);
 			kfree(tty);
 		}
@@ -176,7 +176,7 @@
 	return retval;
 free_termios:
 	kfree(termios);
-	port->port.tty = NULL;
+	tty_port_tty_set(&port->port, NULL);
 free_tty:
 	kfree(tty);
 reset_open_count:
diff --git a/drivers/usb/serial/cp2101.c b/drivers/usb/serial/cp2101.c
index 442cba6..1279553 100644
--- a/drivers/usb/serial/cp2101.c
+++ b/drivers/usb/serial/cp2101.c
@@ -72,6 +72,7 @@
 	{ USB_DEVICE(0x10C4, 0x80CA) }, /* Degree Controls Inc */
 	{ USB_DEVICE(0x10C4, 0x80DD) }, /* Tracient RFID */
 	{ USB_DEVICE(0x10C4, 0x80F6) }, /* Suunto sports instrument */
+	{ USB_DEVICE(0x10C4, 0x8115) }, /* Arygon NFC/Mifare Reader */
 	{ USB_DEVICE(0x10C4, 0x813D) }, /* Burnside Telecom Deskmobile */
 	{ USB_DEVICE(0x10C4, 0x814A) }, /* West Mountain Radio RIGblaster P&P */
 	{ USB_DEVICE(0x10C4, 0x814B) }, /* West Mountain Radio RIGtalk */
@@ -83,6 +84,7 @@
 	{ USB_DEVICE(0x10C4, 0x81E7) }, /* Aerocomm Radio */
 	{ USB_DEVICE(0x10C4, 0x8218) }, /* Lipowsky Industrie Elektronik GmbH, HARP-1 */
 	{ USB_DEVICE(0x10c4, 0x8293) }, /* Telegesys ETRX2USB */
+	{ USB_DEVICE(0x10C4, 0x8341) }, /* Siemens MC35PU GPRS Modem */
 	{ USB_DEVICE(0x10C4, 0xEA60) }, /* Silicon Labs factory default */
 	{ USB_DEVICE(0x10C4, 0xEA61) }, /* Silicon Labs factory default */
 	{ USB_DEVICE(0x10C4, 0xF001) }, /* Elan Digital Systems USBscope50 */
@@ -93,6 +95,7 @@
 	{ USB_DEVICE(0x13AD, 0x9999) }, /* Baltech card reader */
 	{ USB_DEVICE(0x166A, 0x0303) }, /* Clipsal 5500PCU C-Bus USB interface */
 	{ USB_DEVICE(0x16D6, 0x0001) }, /* Jablotron serial interface */
+	{ USB_DEVICE(0x18EF, 0xE00F) }, /* ELV USB-I2C-Interface */
 	{ } /* Terminating Entry */
 };
 
diff --git a/drivers/usb/serial/cyberjack.c b/drivers/usb/serial/cyberjack.c
index b4d7235..94ef36c 100644
--- a/drivers/usb/serial/cyberjack.c
+++ b/drivers/usb/serial/cyberjack.c
@@ -384,7 +384,7 @@
 		return;
 	}
 
-	tty = port->port.tty;
+	tty = tty_port_tty_get(&port->port);
 	if (!tty) {
 		dbg("%s - ignoring since device not open\n", __func__);
 		return;
@@ -394,6 +394,7 @@
 		tty_insert_flip_string(tty, data, urb->actual_length);
 		tty_flip_buffer_push(tty);
 	}
+	tty_kref_put(tty);
 
 	spin_lock(&priv->lock);
 
diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c
index 22837a3..f3514a9 100644
--- a/drivers/usb/serial/cypress_m8.c
+++ b/drivers/usb/serial/cypress_m8.c
@@ -1286,7 +1286,7 @@
 	}
 	spin_unlock_irqrestore(&priv->lock, flags);
 
-	tty = port->port.tty;
+	tty = tty_port_tty_get(&port->port);
 	if (!tty) {
 		dbg("%s - bad tty pointer - exiting", __func__);
 		return;
@@ -1362,7 +1362,7 @@
 					data[i]);
 			tty_insert_flip_char(tty, data[i], tty_flag);
 		}
-		tty_flip_buffer_push(port->port.tty);
+		tty_flip_buffer_push(tty);
 	}
 
 	spin_lock_irqsave(&priv->lock, flags);
@@ -1371,6 +1371,7 @@
 	spin_unlock_irqrestore(&priv->lock, flags);
 
 continue_read:
+	tty_kref_put(tty);
 
 	/* Continue trying to always read... unless the port has closed. */
 
diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c
index 240aad1..5756ac6 100644
--- a/drivers/usb/serial/digi_acceleport.c
+++ b/drivers/usb/serial/digi_acceleport.c
@@ -604,7 +604,9 @@
 
 static void digi_wakeup_write(struct usb_serial_port *port)
 {
-	tty_wakeup(port->port.tty);
+	struct tty_struct *tty = tty_port_tty_get(&port->port);
+	tty_wakeup(tty);
+	tty_kref_put(tty);
 }
 
 
@@ -1668,7 +1670,7 @@
 {
 
 	struct usb_serial_port *port = urb->context;
-	struct tty_struct *tty = port->port.tty;
+	struct tty_struct *tty;
 	struct digi_port *priv = usb_get_serial_port_data(port);
 	int opcode = ((unsigned char *)urb->transfer_buffer)[0];
 	int len = ((unsigned char *)urb->transfer_buffer)[1];
@@ -1692,6 +1694,7 @@
 		return -1;
 	}
 
+	tty = tty_port_tty_get(&port->port);
 	spin_lock(&priv->dp_port_lock);
 
 	/* check for throttle; if set, do not resubmit read urb */
@@ -1735,6 +1738,7 @@
 		}
 	}
 	spin_unlock(&priv->dp_port_lock);
+	tty_kref_put(tty);
 
 	if (opcode == DIGI_CMD_RECEIVE_DISABLE)
 		dbg("%s: got RECEIVE_DISABLE", __func__);
@@ -1760,6 +1764,7 @@
 
 	struct usb_serial_port *port = urb->context;
 	struct usb_serial *serial = port->serial;
+	struct tty_struct *tty;
 	struct digi_port *priv = usb_get_serial_port_data(port);
 	int opcode, line, status, val;
 	int i;
@@ -1787,10 +1792,11 @@
 		if (priv == NULL)
 			return -1;
 
+		tty = tty_port_tty_get(&port->port);
 		rts = 0;
 		if (port->port.count)
-			rts = port->port.tty->termios->c_cflag & CRTSCTS;
-
+			rts = tty->termios->c_cflag & CRTSCTS;
+		
 		if (opcode == DIGI_CMD_READ_INPUT_SIGNALS) {
 			spin_lock(&priv->dp_port_lock);
 			/* convert from digi flags to termiox flags */
@@ -1798,14 +1804,14 @@
 				priv->dp_modem_signals |= TIOCM_CTS;
 				/* port must be open to use tty struct */
 				if (rts) {
-					port->port.tty->hw_stopped = 0;
+					tty->hw_stopped = 0;
 					digi_wakeup_write(port);
 				}
 			} else {
 				priv->dp_modem_signals &= ~TIOCM_CTS;
 				/* port must be open to use tty struct */
 				if (rts)
-					port->port.tty->hw_stopped = 1;
+					tty->hw_stopped = 1;
 			}
 			if (val & DIGI_READ_INPUT_SIGNALS_DSR)
 				priv->dp_modem_signals |= TIOCM_DSR;
@@ -1830,6 +1836,7 @@
 		} else if (opcode == DIGI_CMD_IFLUSH_FIFO) {
 			wake_up_interruptible(&priv->dp_flush_wait);
 		}
+		tty_kref_put(tty);
 	}
 	return 0;
 
diff --git a/drivers/usb/serial/empeg.c b/drivers/usb/serial/empeg.c
index a6ab5b5..1072e84 100644
--- a/drivers/usb/serial/empeg.c
+++ b/drivers/usb/serial/empeg.c
@@ -33,9 +33,8 @@
  *	Moved MOD_DEC_USE_COUNT to end of empeg_close().
  *
  * (12/03/2000) gb
- *	Added port->port.tty->ldisc.set_termios(port->port.tty, NULL) to
- *	empeg_open(). This notifies the tty driver that the termios have
- *	changed.
+ *	Added tty->ldisc.set_termios(port, tty, NULL) to empeg_open().
+ *	This notifies the tty driver that the termios have changed.
  *
  * (11/13/2000) gb
  *	Moved tty->low_latency = 1 from empeg_read_bulk_callback() to
@@ -354,7 +353,7 @@
 
 	usb_serial_debug_data(debug, &port->dev, __func__,
 						urb->actual_length, data);
-	tty = port->port.tty;
+	tty = tty_port_tty_get(&port->port);
 
 	if (urb->actual_length) {
 		tty_buffer_request_room(tty, urb->actual_length);
@@ -362,6 +361,7 @@
 		tty_flip_buffer_push(tty);
 		bytes_in += urb->actual_length;
 	}
+	tty_kref_put(tty);
 
 	/* Continue trying to always read  */
 	usb_fill_bulk_urb(
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
index 984f6ef..c2ac129 100644
--- a/drivers/usb/serial/ftdi_sio.c
+++ b/drivers/usb/serial/ftdi_sio.c
@@ -654,6 +654,9 @@
 		.driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
 	{ USB_DEVICE(RATOC_VENDOR_ID, RATOC_PRODUCT_ID_USB60F) },
 	{ USB_DEVICE(FTDI_VID, FTDI_REU_TINY_PID) },
+	{ USB_DEVICE(PAPOUCH_VID, PAPOUCH_QUIDO4x4_PID) },
+	{ USB_DEVICE(FTDI_VID, FTDI_DOMINTELL_DGQG_PID) },
+	{ USB_DEVICE(FTDI_VID, FTDI_DOMINTELL_DUSB_PID) },
 	{ },					/* Optional parameter entry */
 	{ }					/* Terminating entry */
 };
@@ -857,7 +860,7 @@
 
 	kfree(buf);
 	if (rv < 0) {
-		err("%s Error from MODEM_CTRL urb: DTR %s, RTS %s",
+		dbg("%s Error from MODEM_CTRL urb: DTR %s, RTS %s",
 				__func__,
 				(set & TIOCM_DTR) ? "HIGH" :
 				(clear & TIOCM_DTR) ? "LOW" : "unchanged",
@@ -1805,7 +1808,7 @@
 	if (port->port.count <= 0)
 		return;
 
-	tty = port->port.tty;
+	tty = tty_port_tty_get(&port->port);
 	if (!tty) {
 		dbg("%s - bad tty pointer - exiting", __func__);
 		return;
@@ -1814,7 +1817,7 @@
 	priv = usb_get_serial_port_data(port);
 	if (!priv) {
 		dbg("%s - bad port private data pointer - exiting", __func__);
-		return;
+		goto out;
 	}
 
 	if (urb != port->read_urb)
@@ -1824,7 +1827,7 @@
 		/* This will happen at close every time so it is a dbg not an
 		   err */
 		dbg("(this is ok on close) nonzero read bulk status received: %d", status);
-		return;
+		goto out;
 	}
 
 	/* count data bytes, but not status bytes */
@@ -1835,7 +1838,8 @@
 	spin_unlock_irqrestore(&priv->rx_lock, flags);
 
 	ftdi_process_read(&priv->rx_work.work);
-
+out:
+	tty_kref_put(tty);
 } /* ftdi_read_bulk_callback */
 
 
@@ -1860,7 +1864,7 @@
 	if (port->port.count <= 0)
 		return;
 
-	tty = port->port.tty;
+	tty = tty_port_tty_get(&port->port);
 	if (!tty) {
 		dbg("%s - bad tty pointer - exiting", __func__);
 		return;
@@ -1869,13 +1873,13 @@
 	priv = usb_get_serial_port_data(port);
 	if (!priv) {
 		dbg("%s - bad port private data pointer - exiting", __func__);
-		return;
+		goto out;
 	}
 
 	urb = port->read_urb;
 	if (!urb) {
 		dbg("%s - bad read_urb pointer - exiting", __func__);
-		return;
+		goto out;
 	}
 
 	data = urb->transfer_buffer;
@@ -2017,7 +2021,7 @@
 			schedule_delayed_work(&priv->rx_work, 1);
 		else
 			dbg("%s - port is closed", __func__);
-		return;
+		goto out;
 	}
 
 	/* urb is completely processed */
@@ -2038,6 +2042,8 @@
 			err("%s - failed resubmitting read urb, error %d",
 							__func__, result);
 	}
+out:
+	tty_kref_put(tty);
 } /* ftdi_process_read */
 
 
@@ -2253,7 +2259,7 @@
 			   0, 0,
 			   buf, 1, WDR_TIMEOUT);
 		if (ret < 0) {
-			err("%s Could not get modem status of device - err: %d", __func__,
+			dbg("%s Could not get modem status of device - err: %d", __func__,
 			    ret);
 			return ret;
 		}
@@ -2272,7 +2278,7 @@
 				   0, priv->interface,
 				   buf, 2, WDR_TIMEOUT);
 		if (ret < 0) {
-			err("%s Could not get modem status of device - err: %d", __func__,
+			dbg("%s Could not get modem status of device - err: %d", __func__,
 			    ret);
 			return ret;
 		}
diff --git a/drivers/usb/serial/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h
index 382265b..8a5b6df 100644
--- a/drivers/usb/serial/ftdi_sio.h
+++ b/drivers/usb/serial/ftdi_sio.h
@@ -750,6 +750,7 @@
 
 #define PAPOUCH_VID			0x5050	/* Vendor ID */
 #define PAPOUCH_TMU_PID			0x0400	/* TMU USB Thermometer */
+#define PAPOUCH_QUIDO4x4_PID		0x0900	/* Quido 4/4 Module */
 
 /*
  * ACG Identification Technologies GmbH products (http://www.acg.de/).
@@ -838,6 +839,10 @@
 /* Rig Expert Ukraine devices */
 #define FTDI_REU_TINY_PID		0xED22	/* RigExpert Tiny */
 
+/* Domintell products  http://www.domintell.com */
+#define FTDI_DOMINTELL_DGQG_PID	0xEF50	/* Master */
+#define FTDI_DOMINTELL_DUSB_PID	0xEF51	/* DUSB01 module */
+
 /* Commands */
 #define FTDI_SIO_RESET 		0 /* Reset the port */
 #define FTDI_SIO_MODEM_CTRL 	1 /* Set the modem control register */
diff --git a/drivers/usb/serial/garmin_gps.c b/drivers/usb/serial/garmin_gps.c
index d953820..2ad0569 100644
--- a/drivers/usb/serial/garmin_gps.c
+++ b/drivers/usb/serial/garmin_gps.c
@@ -276,7 +276,7 @@
 static void send_to_tty(struct usb_serial_port *port,
 			char *data, unsigned int actual_length)
 {
-	struct tty_struct *tty = port->port.tty;
+	struct tty_struct *tty = tty_port_tty_get(&port->port);
 
 	if (tty && actual_length) {
 
@@ -287,6 +287,7 @@
 		tty_insert_flip_string(tty, data, actual_length);
 		tty_flip_buffer_push(tty);
 	}
+	tty_kref_put(tty);
 }
 
 
diff --git a/drivers/usb/serial/generic.c b/drivers/usb/serial/generic.c
index fe84c88..814909f 100644
--- a/drivers/usb/serial/generic.c
+++ b/drivers/usb/serial/generic.c
@@ -330,7 +330,7 @@
 static void flush_and_resubmit_read_urb(struct usb_serial_port *port)
 {
 	struct urb *urb = port->read_urb;
-	struct tty_struct *tty = port->port.tty;
+	struct tty_struct *tty = tty_port_tty_get(&port->port);
 	int room;
 
 	/* Push data to tty */
@@ -341,6 +341,7 @@
 			tty_flip_buffer_push(tty);
 		}
 	}
+	tty_kref_put(tty);
 
 	resubmit_read_urb(port, GFP_ATOMIC);
 }
diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c
index bfa508d..611f97f 100644
--- a/drivers/usb/serial/io_edgeport.c
+++ b/drivers/usb/serial/io_edgeport.c
@@ -600,6 +600,7 @@
 	struct edgeport_serial	*edge_serial = urb->context;
 	struct edgeport_port *edge_port;
 	struct usb_serial_port *port;
+	struct tty_struct *tty;
 	unsigned char *data = urb->transfer_buffer;
 	int length = urb->actual_length;
 	int bytes_avail;
@@ -675,9 +676,12 @@
 
 					/* tell the tty driver that something
 					   has changed */
-					if (edge_port->port->port.tty)
-						tty_wakeup(edge_port->port->port.tty);
-
+					tty = tty_port_tty_get(
+						&edge_port->port->port);
+					if (tty) {
+						tty_wakeup(tty);
+						tty_kref_put(tty);
+					}
 					/* Since we have more credit, check
 					   if more data can be sent */
 					send_more_port_data(edge_serial,
@@ -778,13 +782,14 @@
 		    __func__, status);
 	}
 
-	tty = edge_port->port->port.tty;
+	tty = tty_port_tty_get(&edge_port->port->port);
 
 	if (tty && edge_port->open) {
 		/* let the tty driver wakeup if it has a special
 		   write_wakeup function */
 		tty_wakeup(tty);
 	}
+	tty_kref_put(tty);
 
 	/* Release the Write URB */
 	edge_port->write_in_progress = false;
@@ -826,11 +831,12 @@
 	}
 
 	/* Get pointer to tty */
-	tty = edge_port->port->port.tty;
+	tty = tty_port_tty_get(&edge_port->port->port);
 
 	/* tell the tty driver that something has changed */
 	if (tty && edge_port->open)
 		tty_wakeup(tty);
+	tty_kref_put(tty);
 
 	/* we have completed the command */
 	edge_port->commandPending = false;
@@ -1932,11 +1938,13 @@
 							edge_serial->rxPort];
 				edge_port = usb_get_serial_port_data(port);
 				if (edge_port->open) {
-					tty = edge_port->port->port.tty;
+					tty = tty_port_tty_get(
+						&edge_port->port->port);
 					if (tty) {
 						dbg("%s - Sending %d bytes to TTY for port %d",
 							__func__, rxLen, edge_serial->rxPort);
 						edge_tty_recv(&edge_serial->serial->dev->dev, tty, buffer, rxLen);
+						tty_kref_put(tty);
 					}
 					edge_port->icount.rx += rxLen;
 				}
@@ -1971,6 +1979,7 @@
 {
 	struct usb_serial_port *port;
 	struct edgeport_port *edge_port;
+	struct tty_struct *tty;
 	__u8 code = edge_serial->rxStatusCode;
 
 	/* switch the port pointer to the one being currently talked about */
@@ -2020,10 +2029,12 @@
 
 		/* send the current line settings to the port so we are
 		   in sync with any further termios calls */
-		/* FIXME: locking on tty */
-		if (edge_port->port->port.tty)
-			change_port_settings(edge_port->port->port.tty,
-				edge_port, edge_port->port->port.tty->termios);
+		tty = tty_port_tty_get(&edge_port->port->port);
+		if (tty) {
+			change_port_settings(tty,
+				edge_port, tty->termios);
+			tty_kref_put(tty);
+		}
 
 		/* we have completed the open */
 		edge_port->openPending = false;
@@ -2163,10 +2174,14 @@
 	}
 
 	/* Place LSR data byte into Rx buffer */
-	if (lsrData && edge_port->port->port.tty)
-		edge_tty_recv(&edge_port->port->dev,
-					edge_port->port->port.tty, &data, 1);
-
+	if (lsrData) {
+		struct tty_struct *tty =
+				tty_port_tty_get(&edge_port->port->port);
+		if (tty) {
+			edge_tty_recv(&edge_port->port->dev, tty, &data, 1);
+			tty_kref_put(tty);
+		}
+	}
 	/* update input line counters */
 	icount = &edge_port->icount;
 	if (newLsr & LSR_BREAK)
diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c
index cb4c543..541dd8e 100644
--- a/drivers/usb/serial/io_ti.c
+++ b/drivers/usb/serial/io_ti.c
@@ -572,7 +572,7 @@
 								int flush)
 {
 	int baud_rate;
-	struct tty_struct *tty = port->port->port.tty;
+	struct tty_struct *tty = tty_port_tty_get(&port->port->port);
 	wait_queue_t wait;
 	unsigned long flags;
 
@@ -599,6 +599,7 @@
 	if (flush)
 		edge_buf_clear(port->ep_out_buf);
 	spin_unlock_irqrestore(&port->ep_lock, flags);
+	tty_kref_put(tty);
 
 	/* wait for data to drain from the device */
 	timeout += jiffies;
@@ -1554,7 +1555,7 @@
 	/* Save the new modem status */
 	edge_port->shadow_msr = msr & 0xf0;
 
-	tty = edge_port->port->port.tty;
+	tty = tty_port_tty_get(&edge_port->port->port);
 	/* handle CTS flow control */
 	if (tty && C_CRTSCTS(tty)) {
 		if (msr & EDGEPORT_MSR_CTS) {
@@ -1564,6 +1565,7 @@
 			tty->hw_stopped = 1;
 		}
 	}
+	tty_kref_put(tty);
 
 	return;
 }
@@ -1574,6 +1576,7 @@
 	struct async_icount *icount;
 	__u8 new_lsr = (__u8)(lsr & (__u8)(LSR_OVER_ERR | LSR_PAR_ERR |
 						LSR_FRM_ERR | LSR_BREAK));
+	struct tty_struct *tty;
 
 	dbg("%s - %02x", __func__, new_lsr);
 
@@ -1587,8 +1590,13 @@
 		new_lsr &= (__u8)(LSR_OVER_ERR | LSR_BREAK);
 
 	/* Place LSR data byte into Rx buffer */
-	if (lsr_data && edge_port->port->port.tty)
-		edge_tty_recv(&edge_port->port->dev, edge_port->port->port.tty, &data, 1);
+	if (lsr_data) {
+		tty = tty_port_tty_get(&edge_port->port->port);
+		if (tty) {
+			edge_tty_recv(&edge_port->port->dev, tty, &data, 1);
+			tty_kref_put(tty);
+		}
+	}
 
 	/* update input line counters */
 	icount = &edge_port->icount;
@@ -1749,7 +1757,7 @@
 		++data;
 	}
 
-	tty = edge_port->port->port.tty;
+	tty = tty_port_tty_get(&edge_port->port->port);
 	if (tty && urb->actual_length) {
 		usb_serial_debug_data(debug, &edge_port->port->dev,
 					__func__, urb->actual_length, data);
@@ -1761,6 +1769,7 @@
 							urb->actual_length);
 		edge_port->icount.rx += urb->actual_length;
 	}
+	tty_kref_put(tty);
 
 exit:
 	/* continue read unless stopped */
@@ -1796,6 +1805,7 @@
 	struct usb_serial_port *port = urb->context;
 	struct edgeport_port *edge_port = usb_get_serial_port_data(port);
 	int status = urb->status;
+	struct tty_struct *tty;
 
 	dbg("%s - port %d", __func__, port->number);
 
@@ -1818,7 +1828,9 @@
 	}
 
 	/* send any buffered data */
-	edge_send(port->port.tty);
+	tty = tty_port_tty_get(&port->port);
+	edge_send(tty);
+	tty_kref_put(tty);
 }
 
 static int edge_open(struct tty_struct *tty,
@@ -1876,7 +1888,7 @@
 
 	/* set up the port settings */
 	if (tty)
-		edge_set_termios(tty, port, port->port.tty->termios);
+		edge_set_termios(tty, port, tty->termios);
 
 	/* open up the port */
 
diff --git a/drivers/usb/serial/ipaq.c b/drivers/usb/serial/ipaq.c
index cd9a2e13..2affa9c 100644
--- a/drivers/usb/serial/ipaq.c
+++ b/drivers/usb/serial/ipaq.c
@@ -764,13 +764,14 @@
 	usb_serial_debug_data(debug, &port->dev, __func__,
 						urb->actual_length, data);
 
-	tty = port->port.tty;
+	tty = tty_port_tty_get(&port->port);
 	if (tty && urb->actual_length) {
 		tty_buffer_request_room(tty, urb->actual_length);
 		tty_insert_flip_string(tty, data, urb->actual_length);
 		tty_flip_buffer_push(tty);
 		bytes_in += urb->actual_length;
 	}
+	tty_kref_put(tty);
 
 	/* Continue trying to always read  */
 	usb_fill_bulk_urb(port->read_urb, port->serial->dev,
diff --git a/drivers/usb/serial/ipw.c b/drivers/usb/serial/ipw.c
index a842025..480cac2 100644
--- a/drivers/usb/serial/ipw.c
+++ b/drivers/usb/serial/ipw.c
@@ -170,12 +170,13 @@
 	usb_serial_debug_data(debug, &port->dev, __func__,
 					urb->actual_length, data);
 
-	tty = port->port.tty;
+	tty = tty_port_tty_get(&port->port);
 	if (tty && urb->actual_length) {
 		tty_buffer_request_room(tty, urb->actual_length);
 		tty_insert_flip_string(tty, data, urb->actual_length);
 		tty_flip_buffer_push(tty);
 	}
+	tty_kref_put(tty);
 
 	/* Continue trying to always read  */
 	usb_fill_bulk_urb(port->read_urb, port->serial->dev,
diff --git a/drivers/usb/serial/ir-usb.c b/drivers/usb/serial/ir-usb.c
index e59155c..45d4043 100644
--- a/drivers/usb/serial/ir-usb.c
+++ b/drivers/usb/serial/ir-usb.c
@@ -465,11 +465,12 @@
 			ir_baud = *data & 0x0f;
 		usb_serial_debug_data(debug, &port->dev, __func__,
 						urb->actual_length, data);
- 		tty = port->port.tty;
+		tty = tty_port_tty_get(&port->port);
 		if (tty_buffer_request_room(tty, urb->actual_length - 1)) {
 			tty_insert_flip_string(tty, data+1, urb->actual_length - 1);
 			tty_flip_buffer_push(tty);
 		}
+		tty_kref_put(tty);
 
 		/*
 		 * No break here.
diff --git a/drivers/usb/serial/iuu_phoenix.c b/drivers/usb/serial/iuu_phoenix.c
index ddff37f..53710aa7 100644
--- a/drivers/usb/serial/iuu_phoenix.c
+++ b/drivers/usb/serial/iuu_phoenix.c
@@ -629,13 +629,14 @@
 	}
 
 	dbg("%s - %i chars to write", __func__, urb->actual_length);
-	tty = port->port.tty;
+	tty = tty_port_tty_get(&port->port);
 	if (data == NULL)
 		dbg("%s - data is NULL !!!", __func__);
 	if (tty && urb->actual_length && data) {
 		tty_insert_flip_string(tty, data, urb->actual_length);
 		tty_flip_buffer_push(tty);
 	}
+	tty_kref_put(tty);
 	iuu_led_activity_on(urb);
 }
 
diff --git a/drivers/usb/serial/keyspan.c b/drivers/usb/serial/keyspan.c
index 704716f..15447af 100644
--- a/drivers/usb/serial/keyspan.c
+++ b/drivers/usb/serial/keyspan.c
@@ -430,7 +430,7 @@
 	}
 
 	port =  urb->context;
-	tty = port->port.tty;
+	tty = tty_port_tty_get(&port->port);
 	if (tty && urb->actual_length) {
 		/* 0x80 bit is error flag */
 		if ((data[0] & 0x80) == 0) {
@@ -459,6 +459,7 @@
 		}
 		tty_flip_buffer_push(tty);
 	}
+	tty_kref_put(tty);
 
 	/* Resubmit urb so we continue receiving */
 	urb->dev = port->serial->dev;
@@ -513,6 +514,7 @@
 	struct usb_serial			*serial;
 	struct usb_serial_port			*port;
 	struct keyspan_port_private	 	*p_priv;
+	struct tty_struct			*tty;
 	int old_dcd_state, err;
 	int status = urb->status;
 
@@ -553,12 +555,11 @@
 	p_priv->dcd_state = ((msg->gpia_dcd) ? 1 : 0);
 	p_priv->ri_state = ((msg->ri) ? 1 : 0);
 
-	if (port->port.tty && !C_CLOCAL(port->port.tty)
-	    && old_dcd_state != p_priv->dcd_state) {
-		if (old_dcd_state)
-			tty_hangup(port->port.tty);
-		/*  else */
-		/*	wake_up_interruptible(&p_priv->open_wait); */
+	if (old_dcd_state != p_priv->dcd_state) {
+		tty = tty_port_tty_get(&port->port);
+		if (tty && !C_CLOCAL(tty))
+			tty_hangup(tty);
+		tty_kref_put(tty);
 	}
 
 	/* Resubmit urb so we continue receiving */
@@ -604,11 +605,12 @@
 		p_priv = usb_get_serial_port_data(port);
 		data = urb->transfer_buffer;
 
-		tty = port->port.tty;
-		if (urb->actual_length) {
+		tty =tty_port_tty_get(&port->port);
+		if (tty && urb->actual_length) {
 			tty_insert_flip_string(tty, data, urb->actual_length);
 			tty_flip_buffer_push(tty);
 		}
+		tty_kref_put(tty);
 
 		/* Resubmit urb so we continue receiving */
 		urb->dev = port->serial->dev;
@@ -652,6 +654,7 @@
 	struct usb_serial			*serial;
 	struct usb_serial_port			*port;
 	struct keyspan_port_private	 	*p_priv;
+	struct tty_struct			*tty;
 	int old_dcd_state;
 	int status = urb->status;
 
@@ -689,12 +692,11 @@
 	p_priv->dcd_state = ((msg->dcd) ? 1 : 0);
 	p_priv->ri_state = ((msg->ri) ? 1 : 0);
 
-	if (port->port.tty && !C_CLOCAL(port->port.tty)
-	    && old_dcd_state != p_priv->dcd_state) {
-		if (old_dcd_state)
-			tty_hangup(port->port.tty);
-		/*  else */
-		/*	wake_up_interruptible(&p_priv->open_wait); */
+	if( old_dcd_state != p_priv->dcd_state && old_dcd_state) {
+		tty = tty_port_tty_get(&port->port);
+		if (tty && !C_CLOCAL(tty)) 
+			tty_hangup(tty);
+		tty_kref_put(tty);
 	}
 
 		/* Resubmit urb so we continue receiving */
@@ -785,12 +787,11 @@
 	p_priv->dcd_state = ((msg->dcd) ? 1 : 0);
 	p_priv->ri_state = ((msg->ri) ? 1 : 0);
 
-	if (port->port.tty && !C_CLOCAL(port->port.tty)
-	    && old_dcd_state != p_priv->dcd_state) {
-		if (old_dcd_state)
-			tty_hangup(port->port.tty);
-		/*  else */
-		/*	wake_up_interruptible(&p_priv->open_wait); */
+	if (old_dcd_state != p_priv->dcd_state && old_dcd_state) {
+		struct tty_struct *tty = tty_port_tty_get(&port->port);
+		if (tty && !C_CLOCAL(tty))
+			tty_hangup(tty);
+		tty_kref_put(tty);
 	}
 
 	/* Resubmit urb so we continue receiving */
@@ -827,7 +828,7 @@
 	}
 
 	port =  urb->context;
-	tty = port->port.tty;
+	tty = tty_port_tty_get(&port->port);
 	if (tty && urb->actual_length) {
 		/* 0x80 bit is error flag */
 		if ((data[0] & 0x80) == 0) {
@@ -850,6 +851,7 @@
 		}
 		tty_flip_buffer_push(tty);
 	}
+	tty_kref_put(tty);
 
 	/* Resubmit urb so we continue receiving */
 	urb->dev = port->serial->dev;
@@ -893,7 +895,7 @@
 				return;
 			}
 			port = serial->port[data[i++]];
-			tty = port->port.tty;
+			tty = tty_port_tty_get(&port->port);
 			len = data[i++];
 
 			/* 0x80 bit is error flag */
@@ -927,6 +929,7 @@
 			}
 			if (port->port.count)
 				tty_flip_buffer_push(tty);
+			tty_kref_put(tty);
 		}
 	}
 
@@ -967,8 +970,8 @@
 	port =  urb->context;
 	p_priv = usb_get_serial_port_data(port);
 
-	tty = port->port.tty;
 	if (urb->actual_length) {
+		tty = tty_port_tty_get(&port->port);
 		/* if current mode is DMA, looks like usa28 format
 		   otherwise looks like usa26 data format */
 
@@ -1004,6 +1007,7 @@
 			}
 		}
 		tty_flip_buffer_push(tty);
+		tty_kref_put(tty);
 	}
 
 	/* Resubmit urb so we continue receiving */
@@ -1025,6 +1029,7 @@
 	struct usb_serial			*serial;
 	struct usb_serial_port			*port;
 	struct keyspan_port_private	 	*p_priv;
+	struct tty_struct			*tty;
 	int old_dcd_state, err;
 	int status = urb->status;
 
@@ -1053,12 +1058,11 @@
 	p_priv->dcd_state = ((msg->dcd) ? 1 : 0);
 	p_priv->ri_state = ((msg->ri) ? 1 : 0);
 
-	if (port->port.tty && !C_CLOCAL(port->port.tty)
-	    && old_dcd_state != p_priv->dcd_state) {
-		if (old_dcd_state)
-			tty_hangup(port->port.tty);
-		/*  else */
-		/*	wake_up_interruptible(&p_priv->open_wait); */
+	if (old_dcd_state != p_priv->dcd_state && old_dcd_state) {
+		tty = tty_port_tty_get(&port->port);
+		if (tty && !C_CLOCAL(tty))
+			tty_hangup(tty);
+		tty_kref_put(tty);
 	}
 
 	/* Resubmit urb so we continue receiving */
@@ -1130,12 +1134,11 @@
 	p_priv->cts_state = ((msg->hskia_cts) ? 1 : 0);
 	p_priv->dcd_state = ((msg->gpia_dcd) ? 1 : 0);
 
-	if (port->port.tty && !C_CLOCAL(port->port.tty)
-	    && old_dcd_state != p_priv->dcd_state) {
-		if (old_dcd_state)
-			tty_hangup(port->port.tty);
-		/*  else */
-		/*	wake_up_interruptible(&p_priv->open_wait); */
+	if (old_dcd_state != p_priv->dcd_state && old_dcd_state) {
+		struct tty_struct *tty = tty_port_tty_get(&port->port);
+		if (tty && !C_CLOCAL(tty))
+			tty_hangup(tty);
+		tty_kref_put(tty);
 	}
 
 	/* Resubmit urb so we continue receiving */
@@ -1332,7 +1335,7 @@
 			stop_urb(p_priv->out_urbs[i]);
 		}
 	}
-	port->port.tty = NULL;
+	tty_port_tty_set(&port->port, NULL);
 }
 
 /* download the firmware to a pre-renumeration device */
diff --git a/drivers/usb/serial/keyspan_pda.c b/drivers/usb/serial/keyspan_pda.c
index 040040a..99e9a14 100644
--- a/drivers/usb/serial/keyspan_pda.c
+++ b/drivers/usb/serial/keyspan_pda.c
@@ -172,8 +172,9 @@
 	struct keyspan_pda_private *priv =
 		container_of(work, struct keyspan_pda_private, wakeup_work);
 	struct usb_serial_port *port = priv->port;
-
-	tty_wakeup(port->port.tty);
+	struct tty_struct *tty = tty_port_tty_get(&port->port);
+	tty_wakeup(tty);
+	tty_kref_put(tty);
 }
 
 static void keyspan_pda_request_unthrottle(struct work_struct *work)
@@ -205,7 +206,7 @@
 static void keyspan_pda_rx_interrupt(struct urb *urb)
 {
 	struct usb_serial_port *port = urb->context;
-	struct tty_struct *tty = port->port.tty;
+	struct tty_struct *tty = tty_port_tty_get(&port->port);
 	unsigned char *data = urb->transfer_buffer;
 	int retval;
 	int status = urb->status;
@@ -222,7 +223,7 @@
 		/* this urb is terminated, clean up */
 		dbg("%s - urb shutting down with status: %d",
 		    __func__, status);
-		return;
+		goto out;
 	default:
 		dbg("%s - nonzero urb status received: %d",
 		    __func__, status);
@@ -261,8 +262,11 @@
 exit:
 	retval = usb_submit_urb(urb, GFP_ATOMIC);
 	if (retval)
-		err("%s - usb_submit_urb failed with result %d",
-		     __func__, retval);
+		dev_err(&port->dev,
+			"%s - usb_submit_urb failed with result %d",
+			__func__, retval);
+out:
+	tty_kref_put(tty);		     
 }
 
 
diff --git a/drivers/usb/serial/kl5kusb105.c b/drivers/usb/serial/kl5kusb105.c
index b84dddc..ff3a07f 100644
--- a/drivers/usb/serial/kl5kusb105.c
+++ b/drivers/usb/serial/kl5kusb105.c
@@ -658,7 +658,7 @@
 	} else {
 		int bytes_sent = ((__u8 *) data)[0] +
 				 ((unsigned int) ((__u8 *) data)[1] << 8);
-		tty = port->port.tty;
+		tty = tty_port_tty_get(&port->port);
 		/* we should immediately resubmit the URB, before attempting
 		 * to pass the data on to the tty layer. But that needs locking
 		 * against re-entry an then mixed-up data because of
@@ -679,6 +679,7 @@
 		tty_buffer_request_room(tty, bytes_sent);
 		tty_insert_flip_string(tty, data + 2, bytes_sent);
 		tty_flip_buffer_push(tty);
+		tty_kref_put(tty);
 
 		/* again lockless, but debug info only */
 		priv->bytes_in += bytes_sent;
diff --git a/drivers/usb/serial/kobil_sct.c b/drivers/usb/serial/kobil_sct.c
index deba28ec..cfcf37c 100644
--- a/drivers/usb/serial/kobil_sct.c
+++ b/drivers/usb/serial/kobil_sct.c
@@ -383,7 +383,7 @@
 		return;
 	}
 
-	tty = port->port.tty;
+	tty = tty_port_tty_get(&port->port);
 	if (urb->actual_length) {
 
 		/* BEGIN DEBUG */
@@ -405,6 +405,7 @@
 		tty_insert_flip_string(tty, data, urb->actual_length);
 		tty_flip_buffer_push(tty);
 	}
+	tty_kref_put(tty);
 	/* someone sets the dev to 0 if the close method has been called */
 	port->interrupt_in_urb->dev = port->serial->dev;
 
diff --git a/drivers/usb/serial/mct_u232.c b/drivers/usb/serial/mct_u232.c
index 0ded8bd..9b2cef8 100644
--- a/drivers/usb/serial/mct_u232.c
+++ b/drivers/usb/serial/mct_u232.c
@@ -563,10 +563,11 @@
 	 * Work-a-round: handle the 'usual' bulk-in pipe here
 	 */
 	if (urb->transfer_buffer_length > 2) {
-		tty = port->port.tty;
+		tty = tty_port_tty_get(&port->port);
 		if (urb->actual_length) {
 			tty_insert_flip_string(tty, data, urb->actual_length);
 			tty_flip_buffer_push(tty);
+			tty_kref_put(tty);
 		}
 		goto exit;
 	}
@@ -591,7 +592,7 @@
 	 * to look in to this before committing any code.
 	 */
 	if (priv->last_lsr & MCT_U232_LSR_ERR) {
-		tty = port->port.tty;
+		tty = tty_port_tty_get(&port->port);
 		/* Overrun Error */
 		if (priv->last_lsr & MCT_U232_LSR_OE) {
 		}
@@ -604,6 +605,7 @@
 		/* Break Indicator */
 		if (priv->last_lsr & MCT_U232_LSR_BI) {
 		}
+		tty_kref_put(tty);
 	}
 #endif
 	spin_unlock_irqrestore(&priv->lock, flags);
diff --git a/drivers/usb/serial/mos7720.c b/drivers/usb/serial/mos7720.c
index 7c4917d..7b538ca 100644
--- a/drivers/usb/serial/mos7720.c
+++ b/drivers/usb/serial/mos7720.c
@@ -216,12 +216,13 @@
 
 	data = urb->transfer_buffer;
 
-	tty = port->port.tty;
+	tty = tty_port_tty_get(&port->port);
 	if (tty && urb->actual_length) {
 		tty_buffer_request_room(tty, urb->actual_length);
 		tty_insert_flip_string(tty, data, urb->actual_length);
 		tty_flip_buffer_push(tty);
 	}
+	tty_kref_put(tty);
 
 	if (!port->read_urb) {
 		dbg("URB KILLED !!!");
@@ -262,10 +263,11 @@
 
 	dbg("Entering .........");
 
-	tty = mos7720_port->port->port.tty;
+	tty = tty_port_tty_get(&mos7720_port->port->port);
 
 	if (tty && mos7720_port->open)
 		tty_wakeup(tty);
+	tty_kref_put(tty);
 }
 
 /*
@@ -1267,29 +1269,6 @@
 	return 0;
 }
 
-/*
- * get_number_bytes_avail - get number of bytes available
- *
- * Purpose: Let user call ioctl to get the count of number of bytes available.
- */
-static int get_number_bytes_avail(struct moschip_port *mos7720_port,
-				  unsigned int __user *value)
-{
-	unsigned int result = 0;
-	struct tty_struct *tty = mos7720_port->port->port.tty;
-
-	if (!tty)
-		return -ENOIOCTLCMD;
-
-	result = tty->read_cnt;
-
-	dbg("%s(%d) = %d", __func__,  mos7720_port->port->number, result);
-	if (copy_to_user(value, &result, sizeof(int)))
-		return -EFAULT;
-
-	return -ENOIOCTLCMD;
-}
-
 static int set_modem_info(struct moschip_port *mos7720_port, unsigned int cmd,
 			  unsigned int __user *value)
 {
@@ -1409,13 +1388,6 @@
 	dbg("%s - port %d, cmd = 0x%x", __func__, port->number, cmd);
 
 	switch (cmd) {
-	case TIOCINQ:
-		/* return number of bytes available */
-		dbg("%s (%d) TIOCINQ", __func__,  port->number);
-		return get_number_bytes_avail(mos7720_port,
-					      (unsigned int __user *)arg);
-		break;
-
 	case TIOCSERGETLSR:
 		dbg("%s (%d) TIOCSERGETLSR", __func__,  port->number);
 		return get_lsr_info(tty, mos7720_port,
diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c
index 09d8206..60543d7 100644
--- a/drivers/usb/serial/mos7840.c
+++ b/drivers/usb/serial/mos7840.c
@@ -709,12 +709,13 @@
 	dbg("%s", "Entering ........... \n");
 
 	if (urb->actual_length) {
-		tty = mos7840_port->port->port.tty;
+		tty = tty_port_tty_get(&mos7840_port->port->port);
 		if (tty) {
 			tty_buffer_request_room(tty, urb->actual_length);
 			tty_insert_flip_string(tty, data, urb->actual_length);
 			dbg(" %s \n", data);
 			tty_flip_buffer_push(tty);
+			tty_kref_put(tty);
 		}
 		mos7840_port->icount.rx += urb->actual_length;
 		smp_wmb();
@@ -773,10 +774,10 @@
 
 	dbg("%s \n", "Entering .........");
 
-	tty = mos7840_port->port->port.tty;
-
+	tty = tty_port_tty_get(&mos7840_port->port->port);
 	if (tty && mos7840_port->open)
 		tty_wakeup(tty);
+	tty_kref_put(tty);
 
 }
 
diff --git a/drivers/usb/serial/navman.c b/drivers/usb/serial/navman.c
index d673653..bcdcbb8 100644
--- a/drivers/usb/serial/navman.c
+++ b/drivers/usb/serial/navman.c
@@ -64,12 +64,13 @@
 	usb_serial_debug_data(debug, &port->dev, __func__,
 			      urb->actual_length, data);
 
-	tty = port->port.tty;
+	tty = tty_port_tty_get(&port->port);
 	if (tty && urb->actual_length) {
 		tty_buffer_request_room(tty, urb->actual_length);
 		tty_insert_flip_string(tty, data, urb->actual_length);
 		tty_flip_buffer_push(tty);
 	}
+	tty_kref_put(tty);
 
 exit:
 	result = usb_submit_urb(urb, GFP_ATOMIC);
diff --git a/drivers/usb/serial/omninet.c b/drivers/usb/serial/omninet.c
index ae8e227..c4d70b0 100644
--- a/drivers/usb/serial/omninet.c
+++ b/drivers/usb/serial/omninet.c
@@ -172,7 +172,7 @@
 	dbg("%s - port %d", __func__, port->number);
 
 	wport = serial->port[1];
-	wport->port.tty = tty;		/* FIXME */
+	tty_port_tty_set(&wport->port, tty);
 
 	/* Start reading from the device */
 	usb_fill_bulk_urb(port->read_urb, serial->dev,
@@ -229,9 +229,11 @@
 	}
 
 	if (urb->actual_length && header->oh_len) {
-		tty_insert_flip_string(port->port.tty,
-			data + OMNINET_DATAOFFSET, header->oh_len);
-		tty_flip_buffer_push(port->port.tty);
+		struct tty_struct *tty = tty_port_tty_get(&port->port);
+		tty_insert_flip_string(tty, data + OMNINET_DATAOFFSET,
+							header->oh_len);
+		tty_flip_buffer_push(tty);
+		tty_kref_put(tty);
 	}
 
 	/* Continue trying to always read  */
diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c
index 9f9cd36..6b1727e 100644
--- a/drivers/usb/serial/option.c
+++ b/drivers/usb/serial/option.c
@@ -218,6 +218,7 @@
 /* ZTE PRODUCTS */
 #define ZTE_VENDOR_ID				0x19d2
 #define ZTE_PRODUCT_MF628			0x0015
+#define ZTE_PRODUCT_CDMA_TECH			0xfffe
 
 static struct usb_device_id option_ids[] = {
 	{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COLT) },
@@ -347,6 +348,7 @@
 	{ USB_DEVICE(MAXON_VENDOR_ID, 0x6280) }, /* BP3-USB & BP3-EXT HSDPA */
 	{ USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_UC864E) },
 	{ USB_DEVICE(ZTE_VENDOR_ID, ZTE_PRODUCT_MF628) },
+	{ USB_DEVICE(ZTE_VENDOR_ID, ZTE_PRODUCT_CDMA_TECH) },
 	{ } /* Terminating entry */
 };
 MODULE_DEVICE_TABLE(usb, option_ids);
@@ -569,14 +571,14 @@
 		dbg("%s: nonzero status: %d on endpoint %02x.",
 		    __func__, status, endpoint);
 	} else {
-		tty = port->port.tty;
+		tty = tty_port_tty_get(&port->port);
 		if (urb->actual_length) {
 			tty_buffer_request_room(tty, urb->actual_length);
 			tty_insert_flip_string(tty, data, urb->actual_length);
 			tty_flip_buffer_push(tty);
-		} else {
+		} else 
 			dbg("%s: empty read urb received", __func__);
-		}
+		tty_kref_put(tty);
 
 		/* Resubmit urb so we continue receiving */
 		if (port->port.count && status != -ESHUTDOWN) {
@@ -645,9 +647,13 @@
 			portdata->dsr_state = ((signals & 0x02) ? 1 : 0);
 			portdata->ri_state = ((signals & 0x08) ? 1 : 0);
 
-			if (port->port.tty && !C_CLOCAL(port->port.tty) &&
-					old_dcd_state && !portdata->dcd_state)
-				tty_hangup(port->port.tty);
+			if (old_dcd_state && !portdata->dcd_state) {
+				struct tty_struct *tty =
+						tty_port_tty_get(&port->port);
+				if (tty && !C_CLOCAL(tty))
+					tty_hangup(tty);
+				tty_kref_put(tty);
+			}
 		} else {
 			dbg("%s: type %x req %x", __func__,
 				req_pkt->bRequestType, req_pkt->bRequest);
@@ -791,7 +797,7 @@
 		for (i = 0; i < N_OUT_URB; i++)
 			usb_kill_urb(portdata->out_urbs[i]);
 	}
-	port->port.tty = NULL;	/* FIXME */
+	tty_port_tty_set(&port->port, NULL);
 }
 
 /* Helper functions used by option_setup_urbs */
diff --git a/drivers/usb/serial/oti6858.c b/drivers/usb/serial/oti6858.c
index 81db571..ba551f0 100644
--- a/drivers/usb/serial/oti6858.c
+++ b/drivers/usb/serial/oti6858.c
@@ -224,10 +224,6 @@
 	struct usb_serial_port *port;   /* USB port with which associated */
 };
 
-#undef dbg
-/* #define dbg(format, arg...) printk(KERN_INFO "%s: " format "\n", __FILE__, ## arg) */
-#define dbg(format, arg...) printk(KERN_INFO "" format "\n", ## arg)
-
 static void setup_line(struct work_struct *work)
 {
 	struct oti6858_private *priv = container_of(work,
@@ -1002,11 +998,12 @@
 		return;
 	}
 
-	tty = port->port.tty;
+	tty = tty_port_tty_get(&port->port);
 	if (tty != NULL && urb->actual_length > 0) {
 		tty_insert_flip_string(tty, data, urb->actual_length);
 		tty_flip_buffer_push(tty);
 	}
+	tty_kref_put(tty);
 
 	/* schedule the interrupt urb if we are still open */
 	if (port->port.count != 0) {
diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c
index 1ede144..9084378 100644
--- a/drivers/usb/serial/pl2303.c
+++ b/drivers/usb/serial/pl2303.c
@@ -154,7 +154,6 @@
 	wait_queue_head_t delta_msr_wait;
 	u8 line_control;
 	u8 line_status;
-	u8 termios_initialized;
 	enum pl2303_type type;
 };
 
@@ -526,16 +525,6 @@
 
 	dbg("%s -  port %d", __func__, port->number);
 
-	spin_lock_irqsave(&priv->lock, flags);
-	if (!priv->termios_initialized) {
-		*(tty->termios) = tty_std_termios;
-		tty->termios->c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
-		tty->termios->c_ispeed = 9600;
-		tty->termios->c_ospeed = 9600;
-		priv->termios_initialized = 1;
-	}
-	spin_unlock_irqrestore(&priv->lock, flags);
-
 	/* The PL2303 is reported to lose bytes if you change
 	   serial settings even to the same values as before. Thus
 	   we actually need to filter in this specific case */
@@ -1057,7 +1046,7 @@
 		tty_flag = TTY_FRAME;
 	dbg("%s - tty_flag = %d", __func__, tty_flag);
 
-	tty = port->port.tty;
+	tty = tty_port_tty_get(&port->port);
 	if (tty && urb->actual_length) {
 		tty_buffer_request_room(tty, urb->actual_length + 1);
 		/* overrun is special, not associated with a char */
@@ -1067,7 +1056,7 @@
 			tty_insert_flip_char(tty, data[i], tty_flag);
 		tty_flip_buffer_push(tty);
 	}
-
+	tty_kref_put(tty);
 	/* Schedule the next read _if_ we are still open */
 	if (port->port.count) {
 		urb->dev = port->serial->dev;
diff --git a/drivers/usb/serial/safe_serial.c b/drivers/usb/serial/safe_serial.c
index def52d0..72903ac 100644
--- a/drivers/usb/serial/safe_serial.c
+++ b/drivers/usb/serial/safe_serial.c
@@ -217,6 +217,7 @@
 	struct usb_serial_port *port =  urb->context;
 	unsigned char *data = urb->transfer_buffer;
 	unsigned char length = urb->actual_length;
+	struct tty_struct *tty;
 	int result;
 	int status = urb->status;
 
@@ -242,6 +243,7 @@
 		printk("\n");
 	}
 #endif
+	tty = tty_port_tty_get(&port->port);
 	if (safe) {
 		__u16 fcs;
 		fcs = fcs_compute10(data, length, CRC10_INITFCS);
@@ -250,9 +252,9 @@
 			if (actual_length <= (length - 2)) {
 				info("%s - actual: %d", __func__,
 							actual_length);
-				tty_insert_flip_string(port->port.tty,
+				tty_insert_flip_string(tty,
 							data, actual_length);
-				tty_flip_buffer_push(port->port.tty);
+				tty_flip_buffer_push(tty);
 			} else {
 				err("%s - inconsistent lengths %d:%d",
 					__func__, actual_length, length);
@@ -261,9 +263,10 @@
 			err("%s - bad CRC %x", __func__, fcs);
 		}
 	} else {
-		tty_insert_flip_string(port->port.tty, data, length);
-		tty_flip_buffer_push(port->port.tty);
+		tty_insert_flip_string(tty, data, length);
+		tty_flip_buffer_push(tty);
 	}
+	tty_kref_put(tty);
 
 	/* Continue trying to always read  */
 	usb_fill_bulk_urb(urb, port->serial->dev,
diff --git a/drivers/usb/serial/sierra.c b/drivers/usb/serial/sierra.c
index 7060337..8b9eaf3 100644
--- a/drivers/usb/serial/sierra.c
+++ b/drivers/usb/serial/sierra.c
@@ -14,7 +14,7 @@
   Whom based his on the Keyspan driver by Hugh Blemings <hugh@blemings.org>
 */
 
-#define DRIVER_VERSION "v.1.2.13a"
+#define DRIVER_VERSION "v.1.3.2"
 #define DRIVER_AUTHOR "Kevin Lloyd <klloyd@sierrawireless.com>"
 #define DRIVER_DESC "USB Driver for Sierra Wireless USB modems"
 
@@ -30,9 +30,6 @@
 
 #define SWIMS_USB_REQUEST_SetPower	0x00
 #define SWIMS_USB_REQUEST_SetNmea	0x07
-#define SWIMS_USB_REQUEST_SetMode	0x0B
-#define SWIMS_USB_REQUEST_GetSwocInfo	0x0A
-#define SWIMS_SET_MODE_Modem		0x0001
 
 /* per port private data */
 #define N_IN_URB	4
@@ -163,7 +160,7 @@
 	{ USB_DEVICE(0x1199, 0x0017) },	/* Sierra Wireless EM5625 */
 	{ USB_DEVICE(0x1199, 0x0018) },	/* Sierra Wireless MC5720 */
 	{ USB_DEVICE(0x1199, 0x0218) },	/* Sierra Wireless MC5720 */
-	{ USB_DEVICE(0x0f30, 0x1b1d) },	/* Sierra Wireless MC5720 */
+	{ USB_DEVICE(0x03f0, 0x1b1d) }, /* HP ev2200 a.k.a MC5720 */
 	{ USB_DEVICE(0x1199, 0x0020) },	/* Sierra Wireless MC5725 */
 	{ USB_DEVICE(0x1199, 0x0024) },	/* Sierra Wireless MC5727 */
 	{ USB_DEVICE(0x1199, 0x0220) },	/* Sierra Wireless MC5725 */
@@ -175,6 +172,8 @@
 	 /* Sierra Wireless Device */
 	{ USB_DEVICE_AND_INTERFACE_INFO(0x1199, 0x0025, 0xFF, 0xFF, 0xFF) },
 	{ USB_DEVICE(0x1199, 0x0026) }, /* Sierra Wireless Device */
+	{ USB_DEVICE(0x1199, 0x0027) }, /* Sierra Wireless Device */
+	{ USB_DEVICE(0x1199, 0x0028) }, /* Sierra Wireless Device */
 
 	{ USB_DEVICE(0x1199, 0x6802) },	/* Sierra Wireless MC8755 */
 	{ USB_DEVICE(0x1199, 0x6804) },	/* Sierra Wireless MC8755 */
@@ -187,6 +186,7 @@
 	{ USB_DEVICE(0x1199, 0x6821) },	/* Sierra Wireless AirCard 875U */
 	{ USB_DEVICE(0x1199, 0x6832) },	/* Sierra Wireless MC8780 */
 	{ USB_DEVICE(0x1199, 0x6833) },	/* Sierra Wireless MC8781 */
+	{ USB_DEVICE(0x1199, 0x683A) },	/* Sierra Wireless MC8785 */
 	{ USB_DEVICE(0x1199, 0x683B) },	/* Sierra Wireless MC8785 Composite */
 	{ USB_DEVICE(0x1199, 0x683C) },	/* Sierra Wireless MC8790 */
 	{ USB_DEVICE(0x1199, 0x683D) },	/* Sierra Wireless MC8790 */
@@ -204,6 +204,8 @@
 	/* Sierra Wireless Device */
 	{ USB_DEVICE_AND_INTERFACE_INFO(0x1199, 0x6890, 0xFF, 0xFF, 0xFF)},
 	/* Sierra Wireless Device */
+	{ USB_DEVICE_AND_INTERFACE_INFO(0x1199, 0x6891, 0xFF, 0xFF, 0xFF)},
+	/* Sierra Wireless Device */
 	{ USB_DEVICE_AND_INTERFACE_INFO(0x1199, 0x6892, 0xFF, 0xFF, 0xFF)},
 
 	{ USB_DEVICE(0x1199, 0x0112) }, /* Sierra Wireless AirCard 580 */
@@ -438,14 +440,14 @@
 		dbg("%s: nonzero status: %d on endpoint %02x.",
 		    __func__, status, endpoint);
 	} else {
-		tty = port->port.tty;
 		if (urb->actual_length) {
+		tty = tty_port_tty_get(&port->port);
 			tty_buffer_request_room(tty, urb->actual_length);
 			tty_insert_flip_string(tty, data, urb->actual_length);
 			tty_flip_buffer_push(tty);
-		} else {
+			tty_kref_put(tty);
+		} else
 			dbg("%s: empty read urb received", __func__);
-		}
 
 		/* Resubmit urb so we continue receiving */
 		if (port->port.count && status != -ESHUTDOWN) {
@@ -483,6 +485,7 @@
 			unsigned char signals = *((unsigned char *)
 					urb->transfer_buffer +
 					sizeof(struct usb_ctrlrequest));
+			struct tty_struct *tty;
 
 			dbg("%s: signal x%x", __func__, signals);
 
@@ -492,9 +495,11 @@
 			portdata->dsr_state = ((signals & 0x02) ? 1 : 0);
 			portdata->ri_state = ((signals & 0x08) ? 1 : 0);
 
-			if (port->port.tty && !C_CLOCAL(port->port.tty) &&
+			tty = tty_port_tty_get(&port->port);
+			if (tty && !C_CLOCAL(tty) &&
 					old_dcd_state && !portdata->dcd_state)
-				tty_hangup(port->port.tty);
+				tty_hangup(tty);
+			tty_kref_put(tty);
 		} else {
 			dbg("%s: type %x req %x", __func__,
 				req_pkt->bRequestType, req_pkt->bRequest);
@@ -614,8 +619,7 @@
 	}
 
 	usb_kill_urb(port->interrupt_in_urb);
-
-	port->port.tty = NULL;	/* FIXME */
+	tty_port_tty_set(&port->port, NULL);
 }
 
 static int sierra_startup(struct usb_serial *serial)
diff --git a/drivers/usb/serial/spcp8x5.c b/drivers/usb/serial/spcp8x5.c
index 283cf6b..1533d6e 100644
--- a/drivers/usb/serial/spcp8x5.c
+++ b/drivers/usb/serial/spcp8x5.c
@@ -755,7 +755,7 @@
 		tty_flag = TTY_FRAME;
 	dev_dbg(&port->dev, "tty_flag = %d\n", tty_flag);
 
-	tty = port->port.tty;
+	tty = tty_port_tty_get(&port->port);
 	if (tty && urb->actual_length) {
 		tty_buffer_request_room(tty, urb->actual_length + 1);
 		/* overrun is special, not associated with a char */
@@ -765,6 +765,7 @@
 			tty_insert_flip_char(tty, data[i], tty_flag);
 		tty_flip_buffer_push(tty);
 	}
+	tty_kref_put(tty);
 
 	/* Schedule the next read _if_ we are still open */
 	if (port->port.count) {
diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c
index e39c779..c90237d 100644
--- a/drivers/usb/serial/ti_usb_3410_5052.c
+++ b/drivers/usb/serial/ti_usb_3410_5052.c
@@ -179,7 +179,7 @@
 static int ti_get_lsr(struct ti_port *tport);
 static int ti_get_serial_info(struct ti_port *tport,
 	struct serial_struct __user *ret_arg);
-static int ti_set_serial_info(struct ti_port *tport,
+static int ti_set_serial_info(struct tty_struct *tty, struct ti_port *tport,
 	struct serial_struct __user *new_arg);
 static void ti_handle_new_msr(struct ti_port *tport, __u8 msr);
 
@@ -857,8 +857,8 @@
 				(struct serial_struct __user *)arg);
 	case TIOCSSERIAL:
 		dbg("%s - (%d) TIOCSSERIAL", __func__, port->number);
-		return ti_set_serial_info(tport,
-					(struct serial_struct __user *)arg);
+		return ti_set_serial_info(tty, tport,
+				(struct serial_struct __user *)arg);
 	case TIOCMIWAIT:
 		dbg("%s - (%d) TIOCMIWAIT", __func__, port->number);
 		cprev = tport->tp_icount;
@@ -1211,6 +1211,7 @@
 	struct device *dev = &urb->dev->dev;
 	int status = urb->status;
 	int retval = 0;
+	struct tty_struct *tty;
 
 	dbg("%s", __func__);
 
@@ -1239,20 +1240,22 @@
 		return;
 	}
 
-	if (port->port.tty && urb->actual_length) {
+	tty = tty_port_tty_get(&port->port);
+	if (tty && urb->actual_length) {
 		usb_serial_debug_data(debug, dev, __func__,
 			urb->actual_length, urb->transfer_buffer);
 
 		if (!tport->tp_is_open)
 			dbg("%s - port closed, dropping data", __func__);
 		else
-			ti_recv(&urb->dev->dev, port->port.tty,
+			ti_recv(&urb->dev->dev, tty,
 						urb->transfer_buffer,
 						urb->actual_length);
 
 		spin_lock(&tport->tp_lock);
 		tport->tp_icount.rx += urb->actual_length;
 		spin_unlock(&tport->tp_lock);
+		tty_kref_put(tty);
 	}
 
 exit:
@@ -1330,7 +1333,7 @@
 {
 	int count, result;
 	struct usb_serial_port *port = tport->tp_port;
-	struct tty_struct *tty = port->port.tty;	/* FIXME */
+	struct tty_struct *tty = tty_port_tty_get(&port->port);	/* FIXME */
 	unsigned long flags;
 
 
@@ -1338,19 +1341,15 @@
 
 	spin_lock_irqsave(&tport->tp_lock, flags);
 
-	if (tport->tp_write_urb_in_use) {
-		spin_unlock_irqrestore(&tport->tp_lock, flags);
-		return;
-	}
+	if (tport->tp_write_urb_in_use)
+		goto unlock;
 
 	count = ti_buf_get(tport->tp_write_buf,
 				port->write_urb->transfer_buffer,
 				port->bulk_out_size);
 
-	if (count == 0) {
-		spin_unlock_irqrestore(&tport->tp_lock, flags);
-		return;
-	}
+	if (count == 0)
+		goto unlock;
 
 	tport->tp_write_urb_in_use = 1;
 
@@ -1380,7 +1379,13 @@
 	/* more room in the buffer for new writes, wakeup */
 	if (tty)
 		tty_wakeup(tty);
+	tty_kref_put(tty);
 	wake_up_interruptible(&tport->tp_write_wait);
+	return;
+unlock:
+	spin_unlock_irqrestore(&tport->tp_lock, flags);
+	tty_kref_put(tty);
+	return;
 }
 
 
@@ -1464,20 +1469,16 @@
 }
 
 
-static int ti_set_serial_info(struct ti_port *tport,
+static int ti_set_serial_info(struct tty_struct *tty, struct ti_port *tport,
 	struct serial_struct __user *new_arg)
 {
-	struct usb_serial_port *port = tport->tp_port;
 	struct serial_struct new_serial;
 
 	if (copy_from_user(&new_serial, new_arg, sizeof(new_serial)))
 		return -EFAULT;
 
 	tport->tp_flags = new_serial.flags & TI_SET_SERIAL_FLAGS;
-	/* FIXME */
-	if (port->port.tty)
-		port->port.tty->low_latency =
-			(tport->tp_flags & ASYNC_LOW_LATENCY) ? 1 : 0;
+	tty->low_latency = (tport->tp_flags & ASYNC_LOW_LATENCY) ? 1 : 0;
 	tport->tp_closing_wait = new_serial.closing_wait;
 
 	return 0;
@@ -1510,7 +1511,7 @@
 	tport->tp_msr = msr & TI_MSR_MASK;
 
 	/* handle CTS flow control */
-	tty = tport->tp_port->port.tty;
+	tty = tty_port_tty_get(&tport->tp_port->port);
 	if (tty && C_CRTSCTS(tty)) {
 		if (msr & TI_MSR_CTS) {
 			tty->hw_stopped = 0;
@@ -1519,6 +1520,7 @@
 			tty->hw_stopped = 1;
 		}
 	}
+	tty_kref_put(tty);
 }
 
 
@@ -1744,7 +1746,7 @@
 	if (buffer) {
 		memcpy(buffer, fw_p->data, fw_p->size);
 		memset(buffer + fw_p->size, 0xff, buffer_size - fw_p->size);
-		ti_do_download(dev, pipe, buffer, fw_p->size);
+		status = ti_do_download(dev, pipe, buffer, fw_p->size);
 		kfree(buffer);
 	}
 	release_firmware(fw_p);
diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c
index b157c48..e7d4246 100644
--- a/drivers/usb/serial/usb-serial.c
+++ b/drivers/usb/serial/usb-serial.c
@@ -214,7 +214,7 @@
 	/* set up our port structure making the tty driver
 	 * remember our port object, and us it */
 	tty->driver_data = port;
-	port->port.tty = tty;
+	tty_port_tty_set(&port->port, tty);
 
 	if (port->port.count == 1) {
 
@@ -246,7 +246,7 @@
 bailout_mutex_unlock:
 	port->port.count = 0;
 	tty->driver_data = NULL;
-	port->port.tty = NULL;
+	tty_port_tty_set(&port->port, NULL);
 	mutex_unlock(&port->mutex);
 bailout_kref_put:
 	usb_serial_put(serial);
@@ -276,10 +276,11 @@
 		port->serial->type->close(tty, port, filp);
 
 	if (port->port.count == (port->console? 1 : 0)) {
-		if (port->port.tty) {
-			if (port->port.tty->driver_data)
-				port->port.tty->driver_data = NULL;
-			port->port.tty = NULL;
+		struct tty_struct *tty = tty_port_tty_get(&port->port);
+		if (tty) {
+			if (tty->driver_data)
+				tty->driver_data = NULL;
+			tty_port_tty_set(&port->port, NULL);
 		}
 	}
 
@@ -508,11 +509,12 @@
 	if (!port)
 		return;
 
-	tty = port->port.tty;
+	tty = tty_port_tty_get(&port->port);
 	if (!tty)
 		return;
 
 	tty_wakeup(tty);
+	tty_kref_put(tty);
 }
 
 static void port_release(struct device *dev)
@@ -733,7 +735,9 @@
 	    ((le16_to_cpu(dev->descriptor.idVendor) == ATEN_VENDOR_ID) &&
 	     (le16_to_cpu(dev->descriptor.idProduct) == ATEN_PRODUCT_ID)) ||
 	    ((le16_to_cpu(dev->descriptor.idVendor) == ALCOR_VENDOR_ID) &&
-	     (le16_to_cpu(dev->descriptor.idProduct) == ALCOR_PRODUCT_ID))) {
+	     (le16_to_cpu(dev->descriptor.idProduct) == ALCOR_PRODUCT_ID)) ||
+	    ((le16_to_cpu(dev->descriptor.idVendor) == SIEMENS_VENDOR_ID) &&
+	     (le16_to_cpu(dev->descriptor.idProduct) == SIEMENS_PRODUCT_ID_EF81))) {
 		if (interface != dev->actconfig->interface[0]) {
 			/* check out the endpoints of the other interface*/
 			iface_desc = dev->actconfig->interface[0]->cur_altsetting;
@@ -817,6 +821,7 @@
 		port = kzalloc(sizeof(struct usb_serial_port), GFP_KERNEL);
 		if (!port)
 			goto probe_error;
+		tty_port_init(&port->port);
 		port->serial = serial;
 		spin_lock_init(&port->lock);
 		mutex_init(&port->mutex);
@@ -1038,8 +1043,11 @@
 	for (i = 0; i < serial->num_ports; ++i) {
 		port = serial->port[i];
 		if (port) {
-			if (port->port.tty)
-				tty_hangup(port->port.tty);
+			struct tty_struct *tty = tty_port_tty_get(&port->port);
+			if (tty) {
+				tty_hangup(tty);
+				tty_kref_put(tty);
+			}
 			kill_traffic(port);
 		}
 	}
diff --git a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c
index cf8924f..a6d1c75 100644
--- a/drivers/usb/serial/visor.c
+++ b/drivers/usb/serial/visor.c
@@ -499,7 +499,7 @@
 	int status = urb->status;
 	struct tty_struct *tty;
 	int result;
-	int available_room;
+	int available_room = 0;
 
 	dbg("%s - port %d", __func__, port->number);
 
@@ -512,13 +512,17 @@
 	usb_serial_debug_data(debug, &port->dev, __func__,
 						urb->actual_length, data);
 
-	tty = port->port.tty;
-	if (tty && urb->actual_length) {
-		available_room = tty_buffer_request_room(tty,
+	if (urb->actual_length) {
+		tty = tty_port_tty_get(&port->port);
+		if (tty) {
+			available_room = tty_buffer_request_room(tty,
 							urb->actual_length);
-		if (available_room) {
-			tty_insert_flip_string(tty, data, available_room);
-			tty_flip_buffer_push(tty);
+			if (available_room) {
+				tty_insert_flip_string(tty, data,
+							available_room);
+				tty_flip_buffer_push(tty);
+			}
+			tty_kref_put(tty);
 		}
 		spin_lock(&priv->lock);
 		priv->bytes_in += available_room;
diff --git a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c
index 3a9d143..11c8b97 100644
--- a/drivers/usb/serial/whiteheat.c
+++ b/drivers/usb/serial/whiteheat.c
@@ -1481,7 +1481,7 @@
 	struct whiteheat_private *info =
 		container_of(work, struct whiteheat_private, rx_work);
 	struct usb_serial_port *port = info->port;
-	struct tty_struct *tty = port->port.tty;
+	struct tty_struct *tty = tty_port_tty_get(&port->port);
 	struct whiteheat_urb_wrap *wrap;
 	struct urb *urb;
 	unsigned long flags;
@@ -1493,7 +1493,7 @@
 	spin_lock_irqsave(&info->lock, flags);
 	if (info->flags & THROTTLED) {
 		spin_unlock_irqrestore(&info->lock, flags);
-		return;
+		goto out;
 	}
 
 	list_for_each_safe(tmp, tmp2, &info->rx_urb_q) {
@@ -1513,7 +1513,7 @@
 				spin_unlock_irqrestore(&info->lock, flags);
 				tty_flip_buffer_push(tty);
 				schedule_work(&info->rx_work);
-				return;
+				goto out;
 			}
 			tty_insert_flip_string(tty, urb->transfer_buffer, len);
 			sent += len;
@@ -1536,6 +1536,8 @@
 
 	if (sent)
 		tty_flip_buffer_push(tty);
+out:
+	tty_kref_put(tty);
 }
 
 
diff --git a/drivers/usb/storage/Kconfig b/drivers/usb/storage/Kconfig
index c760346..3d92496 100644
--- a/drivers/usb/storage/Kconfig
+++ b/drivers/usb/storage/Kconfig
@@ -146,18 +146,6 @@
 	  on the resulting scsi device node returns the Karma to normal
 	  operation.
 
-config USB_STORAGE_SIERRA
-	bool "Sierra Wireless TRU-Install Feature Support"
-	depends on USB_STORAGE
-	help
-	  Say Y here to include additional code to support Sierra Wireless
-	  products with the TRU-Install feature (e.g., AC597E, AC881U).
-
-	  This code switches the Sierra Wireless device from being in
-	  Mass Storage mode to Modem mode. It also has the ability to
-	  support host software upgrades should full Linux support be added
-	  to TRU-Install.
-
 config USB_STORAGE_CYPRESS_ATACB
 	bool "SAT emulation on Cypress USB/ATA Bridge with ATACB"
 	depends on USB_STORAGE
diff --git a/drivers/usb/storage/Makefile b/drivers/usb/storage/Makefile
index bc3415b..7f8beb5 100644
--- a/drivers/usb/storage/Makefile
+++ b/drivers/usb/storage/Makefile
@@ -21,11 +21,10 @@
 usb-storage-obj-$(CONFIG_USB_STORAGE_ALAUDA)	+= alauda.o
 usb-storage-obj-$(CONFIG_USB_STORAGE_ONETOUCH)	+= onetouch.o
 usb-storage-obj-$(CONFIG_USB_STORAGE_KARMA)	+= karma.o
-usb-storage-obj-$(CONFIG_USB_STORAGE_SIERRA)	+= sierra_ms.o
 usb-storage-obj-$(CONFIG_USB_STORAGE_CYPRESS_ATACB) += cypress_atacb.o
 
 usb-storage-objs :=	scsiglue.o protocol.o transport.o usb.o \
-			initializers.o $(usb-storage-obj-y)
+			initializers.o sierra_ms.o $(usb-storage-obj-y)
 
 ifneq ($(CONFIG_USB_LIBUSUAL),)
 	obj-$(CONFIG_USB)	+= libusual.o
diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h
index ba412e6..cd15547 100644
--- a/drivers/usb/storage/unusual_devs.h
+++ b/drivers/usb/storage/unusual_devs.h
@@ -160,6 +160,13 @@
 		US_SC_DEVICE, US_PR_DEVICE, NULL,
 		US_FL_MAX_SECTORS_64 ),
 
+/* Reported by Filip Joelsson <filip@blueturtle.nu> */
+UNUSUAL_DEV(  0x0421, 0x005d, 0x0001, 0x0600,
+		"Nokia",
+		"Nokia 3110c",
+		US_SC_DEVICE, US_PR_DEVICE, NULL,
+		US_FL_FIX_CAPACITY ),
+
 /* Reported by Mario Rettig <mariorettig@web.de> */
 UNUSUAL_DEV(  0x0421, 0x042e, 0x0100, 0x0100,
 		"Nokia",
@@ -232,6 +239,20 @@
 		US_SC_DEVICE, US_PR_DEVICE, NULL,
 		US_FL_FIX_CAPACITY ),
 
+/* Reported by Richard Nauber <RichardNauber@web.de> */
+UNUSUAL_DEV(  0x0421, 0x04fa, 0x0601, 0x0601,
+		"Nokia",
+		"6300",
+		US_SC_DEVICE, US_PR_DEVICE, NULL,
+		US_FL_FIX_CAPACITY ),
+
+/* Patch for Nokia 5310 capacity */
+UNUSUAL_DEV(  0x0421, 0x006a, 0x0000, 0x0591,
+	"Nokia",
+	"5310",
+	US_SC_DEVICE, US_PR_DEVICE, NULL,
+	US_FL_FIX_CAPACITY ),
+
 /* Reported by Olaf Hering <olh@suse.de> from novell bug #105878 */
 UNUSUAL_DEV(  0x0424, 0x0fdc, 0x0210, 0x0210,
 		"SMSC",
@@ -987,6 +1008,13 @@
 		US_SC_DEVICE, US_PR_DEVICE, NULL,
 		US_FL_FIX_CAPACITY ),
 
+/* Reported by Adrian Pilchowiec <adi1981@epf.pl> */
+UNUSUAL_DEV(  0x071b, 0x3203, 0x0000, 0x0000,
+		"RockChip",
+		"MP3",
+		US_SC_DEVICE, US_PR_DEVICE, NULL,
+		US_FL_NO_WP_DETECT | US_FL_MAX_SECTORS_64),
+
 /* Reported by Massimiliano Ghilardi <massimiliano.ghilardi@gmail.com>
  * This USB MP3/AVI player device fails and disconnects if more than 128
  * sectors (64kB) are read/written in a single command, and may be present
@@ -1576,7 +1604,6 @@
 		US_SC_DEVICE, US_PR_DEVICE, NULL,
 		0),
 
-#ifdef CONFIG_USB_STORAGE_SIERRA
 /* Reported by Kevin Lloyd <linux@sierrawireless.com>
  * Entry is needed for the initializer function override,
  * which instructs the device to load as a modem
@@ -1587,7 +1614,6 @@
 		"USB MMC Storage",
 		US_SC_DEVICE, US_PR_DEVICE, sierra_ms_init,
 		0),
-#endif
 
 /* Reported by Jaco Kroon <jaco@kroon.co.za>
  * The usb-storage module found on the Digitech GNX4 (and supposedly other
diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c
index 73679aa..27016fd 100644
--- a/drivers/usb/storage/usb.c
+++ b/drivers/usb/storage/usb.c
@@ -102,9 +102,7 @@
 #ifdef CONFIG_USB_STORAGE_CYPRESS_ATACB
 #include "cypress_atacb.h"
 #endif
-#ifdef CONFIG_USB_STORAGE_SIERRA
 #include "sierra_ms.h"
-#endif
 
 /* Some informational data */
 MODULE_AUTHOR("Matthew Dharm <mdharm-usb@one-eyed-alien.net>");
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 70d135e..f79c204 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -172,11 +172,6 @@
 	bool
 	depends on FB
 
-config FB_METRONOME
-	tristate
-	depends on FB
-	depends on FB_DEFERRED_IO
-
 config FB_HECUBA
 	tristate
 	depends on FB
@@ -678,7 +673,6 @@
 	select FB_CFB_FILLRECT
 	select FB_CFB_COPYAREA
 	select FB_CFB_IMAGEBLIT
-	select VIDEO_SELECT
 	help
 	  This is the frame buffer device driver for generic VESA 2.0
 	  compliant graphic cards. The older VESA 1.2 cards are not supported.
@@ -1583,7 +1577,6 @@
 	tristate "Cyberblade/i1 support"
 	depends on FB && PCI && X86_32 && !64BIT
 	select FB_CFB_IMAGEBLIT
-	select VIDEO_SELECT
 	---help---
 	  This driver is supposed to support the Trident Cyberblade/i1
 	  graphics core integrated in the VIA VT8601A North Bridge,
@@ -1974,19 +1967,6 @@
 	  framebuffer. ML300 carries a 640*480 LCD display on the board,
 	  ML403 uses a standard DB15 VGA connector.
 
-config FB_AM200EPD
-       tristate "AM-200 E-Ink EPD devkit support"
-       depends on FB && ARCH_PXA && MMU
-       select FB_SYS_FILLRECT
-       select FB_SYS_COPYAREA
-       select FB_SYS_IMAGEBLIT
-       select FB_SYS_FOPS
-       select FB_DEFERRED_IO
-       select FB_METRONOME
-       help
-         This enables support for the Metronome display controller used on
-         the E-Ink AM-200 EPD devkit.
-
 config FB_COBALT
 	tristate "Cobalt server LCD frame buffer support"
 	depends on FB && MIPS_COBALT
@@ -2041,6 +2021,19 @@
 	  frame buffer driver.  It communicates with a back-end
 	  in another domain.
 
+config FB_METRONOME
+	tristate "E-Ink Metronome/8track controller support"
+	depends on FB
+	select FB_SYS_FILLRECT
+	select FB_SYS_COPYAREA
+	select FB_SYS_IMAGEBLIT
+	select FB_SYS_FOPS
+	select FB_DEFERRED_IO
+	help
+	  This driver implements support for the E-Ink Metronome
+	  controller. The pre-release name for this device was 8track
+	  and could also have been called by some vendors as PVI-nnnn.
+
 source "drivers/video/omap/Kconfig"
 
 source "drivers/video/backlight/Kconfig"
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index a6b5529..ad0330b 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -29,7 +29,6 @@
 
 # Hardware specific drivers go first
 obj-$(CONFIG_FB_AMIGA)            += amifb.o c2p.o
-obj-$(CONFIG_FB_AM200EPD)         += am200epd.o
 obj-$(CONFIG_FB_ARC)              += arcfb.o
 obj-$(CONFIG_FB_CLPS711X)         += clps711xfb.o
 obj-$(CONFIG_FB_CYBER2000)        += cyber2000fb.o
diff --git a/drivers/video/am200epd.c b/drivers/video/am200epd.c
deleted file mode 100644
index 0c35b8b..0000000
--- a/drivers/video/am200epd.c
+++ /dev/null
@@ -1,295 +0,0 @@
-/*
- * linux/drivers/video/am200epd.c -- Platform device for AM200 EPD kit
- *
- * Copyright (C) 2008, Jaya Kumar
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file COPYING in the main directory of this archive for
- * more details.
- *
- * Layout is based on skeletonfb.c by James Simmons and Geert Uytterhoeven.
- *
- * This work was made possible by help and equipment support from E-Ink
- * Corporation. http://support.eink.com/community
- *
- * This driver is written to be used with the Metronome display controller.
- * on the AM200 EPD prototype kit/development kit with an E-Ink 800x600
- * Vizplex EPD on a Gumstix board using the Lyre interface board.
- *
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/delay.h>
-#include <linux/interrupt.h>
-#include <linux/fb.h>
-#include <linux/init.h>
-#include <linux/platform_device.h>
-#include <linux/list.h>
-#include <linux/uaccess.h>
-#include <linux/irq.h>
-
-#include <video/metronomefb.h>
-
-#include <mach/pxa-regs.h>
-
-/* register offsets for gpio control */
-#define LED_GPIO_PIN 51
-#define STDBY_GPIO_PIN 48
-#define RST_GPIO_PIN 49
-#define RDY_GPIO_PIN 32
-#define ERR_GPIO_PIN 17
-#define PCBPWR_GPIO_PIN 16
-
-#define AF_SEL_GPIO_N 0x3
-#define GAFR0_U_OFFSET(pin) ((pin - 16) * 2)
-#define GAFR1_L_OFFSET(pin) ((pin - 32) * 2)
-#define GAFR1_U_OFFSET(pin) ((pin - 48) * 2)
-#define GPDR1_OFFSET(pin) (pin - 32)
-#define GPCR1_OFFSET(pin) (pin - 32)
-#define GPSR1_OFFSET(pin) (pin - 32)
-#define GPCR0_OFFSET(pin) (pin)
-#define GPSR0_OFFSET(pin) (pin)
-
-static void am200_set_gpio_output(int pin, int val)
-{
-	u8 index;
-
-	index = pin >> 4;
-
-	switch (index) {
-	case 1:
-		if (val)
-			GPSR0 |= (1 << GPSR0_OFFSET(pin));
-		else
-			GPCR0 |= (1 << GPCR0_OFFSET(pin));
-		break;
-	case 2:
-		break;
-	case 3:
-		if (val)
-			GPSR1 |= (1 << GPSR1_OFFSET(pin));
-		else
-			GPCR1 |= (1 << GPCR1_OFFSET(pin));
-		break;
-	default:
-		printk(KERN_ERR "unimplemented\n");
-	}
-}
-
-static void __devinit am200_init_gpio_pin(int pin, int dir)
-{
-	u8 index;
-	/* dir 0 is output, 1 is input
-	- do 2 things here:
-	- set gpio alternate function to standard gpio
-	- set gpio direction to input or output  */
-
-	index = pin >> 4;
-	switch (index) {
-	case 1:
-		GAFR0_U &= ~(AF_SEL_GPIO_N << GAFR0_U_OFFSET(pin));
-
-		if (dir)
-			GPDR0 &= ~(1 << pin);
-		else
-			GPDR0 |= (1 << pin);
-		break;
-	case 2:
-		GAFR1_L &= ~(AF_SEL_GPIO_N << GAFR1_L_OFFSET(pin));
-
-		if (dir)
-			GPDR1 &= ~(1 << GPDR1_OFFSET(pin));
-		else
-			GPDR1 |= (1 << GPDR1_OFFSET(pin));
-		break;
-	case 3:
-		GAFR1_U &= ~(AF_SEL_GPIO_N << GAFR1_U_OFFSET(pin));
-
-		if (dir)
-			GPDR1 &= ~(1 << GPDR1_OFFSET(pin));
-		else
-			GPDR1 |= (1 << GPDR1_OFFSET(pin));
-		break;
-	default:
-		printk(KERN_ERR "unimplemented\n");
-	}
-}
-
-static void am200_init_gpio_regs(struct metronomefb_par *par)
-{
-	am200_init_gpio_pin(LED_GPIO_PIN, 0);
-	am200_set_gpio_output(LED_GPIO_PIN, 0);
-
-	am200_init_gpio_pin(STDBY_GPIO_PIN, 0);
-	am200_set_gpio_output(STDBY_GPIO_PIN, 0);
-
-	am200_init_gpio_pin(RST_GPIO_PIN, 0);
-	am200_set_gpio_output(RST_GPIO_PIN, 0);
-
-	am200_init_gpio_pin(RDY_GPIO_PIN, 1);
-
-	am200_init_gpio_pin(ERR_GPIO_PIN, 1);
-
-	am200_init_gpio_pin(PCBPWR_GPIO_PIN, 0);
-	am200_set_gpio_output(PCBPWR_GPIO_PIN, 0);
-}
-
-static void am200_disable_lcd_controller(struct metronomefb_par *par)
-{
-	LCSR = 0xffffffff;	/* Clear LCD Status Register */
-	LCCR0 |= LCCR0_DIS;	/* Disable LCD Controller */
-
-	/* we reset and just wait for things to settle */
-	msleep(200);
-}
-
-static void am200_enable_lcd_controller(struct metronomefb_par *par)
-{
-	LCSR = 0xffffffff;
-	FDADR0 = par->metromem_desc_dma;
-	LCCR0 |= LCCR0_ENB;
-}
-
-static void am200_init_lcdc_regs(struct metronomefb_par *par)
-{
-	/* here we do:
-	- disable the lcd controller
-	- setup lcd control registers
-	- setup dma descriptor
-	- reenable lcd controller
-	*/
-
-	/* disable the lcd controller */
-	am200_disable_lcd_controller(par);
-
-	/* setup lcd control registers */
-	LCCR0 = LCCR0_LDM | LCCR0_SFM | LCCR0_IUM | LCCR0_EFM | LCCR0_PAS
-		| LCCR0_QDM | LCCR0_BM | LCCR0_OUM;
-
-	LCCR1 = (par->info->var.xres/2 - 1) /* pixels per line */
-		| (27 << 10) /* hsync pulse width - 1 */
-		| (33 << 16) /* eol pixel count */
-		| (33 << 24); /* bol pixel count */
-
-	LCCR2 = (par->info->var.yres - 1) /* lines per panel */
-		| (24 << 10) /* vsync pulse width - 1 */
-		| (2 << 16) /* eof pixel count */
-		| (0 << 24); /* bof pixel count */
-
-	LCCR3 = 2 /* pixel clock divisor */
-		| (24 << 8) /* AC Bias pin freq */
-		| LCCR3_16BPP /* BPP */
-		| LCCR3_PCP;  /* PCP falling edge */
-
-}
-
-static void am200_post_dma_setup(struct metronomefb_par *par)
-{
-	par->metromem_desc->mFDADR0 = par->metromem_desc_dma;
-	par->metromem_desc->mFSADR0 = par->metromem_dma;
-	par->metromem_desc->mFIDR0 = 0;
-	par->metromem_desc->mLDCMD0 = par->info->var.xres
-					* par->info->var.yres;
-	am200_enable_lcd_controller(par);
-}
-
-static void am200_free_irq(struct fb_info *info)
-{
-	free_irq(IRQ_GPIO(RDY_GPIO_PIN), info);
-}
-
-static irqreturn_t am200_handle_irq(int irq, void *dev_id)
-{
-	struct fb_info *info = dev_id;
-	struct metronomefb_par *par = info->par;
-
-	wake_up_interruptible(&par->waitq);
-	return IRQ_HANDLED;
-}
-
-static int am200_setup_irq(struct fb_info *info)
-{
-	int retval;
-
-	retval = request_irq(IRQ_GPIO(RDY_GPIO_PIN), am200_handle_irq,
-				IRQF_DISABLED, "AM200", info);
-	if (retval) {
-		printk(KERN_ERR "am200epd: request_irq failed: %d\n", retval);
-		return retval;
-	}
-
-	return set_irq_type(IRQ_GPIO(RDY_GPIO_PIN), IRQ_TYPE_EDGE_FALLING);
-}
-
-static void am200_set_rst(struct metronomefb_par *par, int state)
-{
-	am200_set_gpio_output(RST_GPIO_PIN, state);
-}
-
-static void am200_set_stdby(struct metronomefb_par *par, int state)
-{
-	am200_set_gpio_output(STDBY_GPIO_PIN, state);
-}
-
-static int am200_wait_event(struct metronomefb_par *par)
-{
-	return wait_event_timeout(par->waitq, (GPLR1 & 0x01), HZ);
-}
-
-static int am200_wait_event_intr(struct metronomefb_par *par)
-{
-	return wait_event_interruptible_timeout(par->waitq, (GPLR1 & 0x01), HZ);
-}
-
-static struct metronome_board am200_board = {
-	.owner			= THIS_MODULE,
-	.free_irq		= am200_free_irq,
-	.setup_irq		= am200_setup_irq,
-	.init_gpio_regs		= am200_init_gpio_regs,
-	.init_lcdc_regs		= am200_init_lcdc_regs,
-	.post_dma_setup		= am200_post_dma_setup,
-	.set_rst		= am200_set_rst,
-	.set_stdby		= am200_set_stdby,
-	.met_wait_event		= am200_wait_event,
-	.met_wait_event_intr	= am200_wait_event_intr,
-};
-
-static struct platform_device *am200_device;
-
-static int __init am200_init(void)
-{
-	int ret;
-
-	/* request our platform independent driver */
-	request_module("metronomefb");
-
-	am200_device = platform_device_alloc("metronomefb", -1);
-	if (!am200_device)
-		return -ENOMEM;
-
-	platform_device_add_data(am200_device, &am200_board,
-					sizeof(am200_board));
-
-	/* this _add binds metronomefb to am200. metronomefb refcounts am200 */
-	ret = platform_device_add(am200_device);
-
-	if (ret)
-		platform_device_put(am200_device);
-
-	return ret;
-}
-
-static void __exit am200_exit(void)
-{
-	platform_device_unregister(am200_device);
-}
-
-module_init(am200_init);
-module_exit(am200_exit);
-
-MODULE_DESCRIPTION("board driver for am200 metronome epd kit");
-MODULE_AUTHOR("Jaya Kumar");
-MODULE_LICENSE("GPL");
diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c
index 75dac57..d38fd52 100644
--- a/drivers/video/atmel_lcdfb.c
+++ b/drivers/video/atmel_lcdfb.c
@@ -408,6 +408,10 @@
 			var->red.offset = 11;
 			var->blue.offset = 0;
 			var->green.length = 6;
+		} else if (sinfo->lcd_wiring_mode == ATMEL_LCDC_WIRING_RGB555) {
+			var->red.offset = 10;
+			var->blue.offset = 0;
+			var->green.length = 5;
 		} else {
 			/* BGR:555 mode */
 			var->red.offset = 0;
diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig
index 452b770..c72a135 100644
--- a/drivers/video/backlight/Kconfig
+++ b/drivers/video/backlight/Kconfig
@@ -24,6 +24,13 @@
 	  To have support for your specific LCD panel you will have to
 	  select the proper drivers which depend on this option.
 
+config LCD_CORGI
+	tristate "LCD Panel support for SHARP corgi/spitz model"
+	depends on LCD_CLASS_DEVICE && SPI_MASTER && PXA_SHARPSL
+	help
+	  Say y here to support the LCD panels usually found on SHARP
+	  corgi (C7x0) and spitz (Cxx00) models.
+
 config LCD_LTV350QV
 	tristate "Samsung LTV350QV LCD Panel"
 	depends on LCD_CLASS_DEVICE && SPI_MASTER
@@ -44,6 +51,14 @@
 	  If you have a panel based on the ILI9320 controller chip
 	  then say y to include a power driver for it.
 
+config LCD_TDO24M
+	tristate "Toppoly TDO24M LCD Panels support"
+	depends on LCD_CLASS_DEVICE && SPI_MASTER
+	default n
+	help
+	  If you have a Toppoly TDO24M series LCD panel, say y here to
+	  include the support for it.
+
 config LCD_VGG2432A4
 	tristate "VGG2432A4 LCM device support"
 	depends on BACKLIGHT_LCD_SUPPORT && LCD_CLASS_DEVICE && SPI_MASTER
diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile
index b405aac..3ec551e 100644
--- a/drivers/video/backlight/Makefile
+++ b/drivers/video/backlight/Makefile
@@ -1,10 +1,12 @@
 # Backlight & LCD drivers
 
 obj-$(CONFIG_LCD_CLASS_DEVICE)     += lcd.o
+obj-$(CONFIG_LCD_CORGI)		   += corgi_lcd.o
 obj-$(CONFIG_LCD_LTV350QV)	   += ltv350qv.o
 obj-$(CONFIG_LCD_ILI9320)	   += ili9320.o
 obj-$(CONFIG_LCD_PLATFORM)	   += platform_lcd.o
 obj-$(CONFIG_LCD_VGG2432A4)	   += vgg2432a4.o
+obj-$(CONFIG_LCD_TDO24M)	   += tdo24m.o
 
 obj-$(CONFIG_BACKLIGHT_CLASS_DEVICE) += backlight.o
 obj-$(CONFIG_BACKLIGHT_ATMEL_PWM)    += atmel-pwm-bl.o
diff --git a/drivers/video/backlight/corgi_lcd.c b/drivers/video/backlight/corgi_lcd.c
new file mode 100644
index 0000000..2afd47e
--- /dev/null
+++ b/drivers/video/backlight/corgi_lcd.c
@@ -0,0 +1,641 @@
+/*
+ *  LCD/Backlight Driver for Sharp Zaurus Handhelds (various models)
+ *
+ *  Copyright (c) 2004-2006 Richard Purdie
+ *
+ *  Based on Sharp's 2.4 Backlight Driver
+ *
+ *  Copyright (c) 2008 Marvell International Ltd.
+ *  	Converted to SPI device based LCD/Backlight device driver
+ *  	by Eric Miao <eric.miao@marvell.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/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/fb.h>
+#include <linux/lcd.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/corgi_lcd.h>
+#include <asm/mach/sharpsl_param.h>
+
+#define POWER_IS_ON(pwr)	((pwr) <= FB_BLANK_NORMAL)
+
+/* Register Addresses */
+#define RESCTL_ADRS     0x00
+#define PHACTRL_ADRS    0x01
+#define DUTYCTRL_ADRS   0x02
+#define POWERREG0_ADRS  0x03
+#define POWERREG1_ADRS  0x04
+#define GPOR3_ADRS      0x05
+#define PICTRL_ADRS     0x06
+#define POLCTRL_ADRS    0x07
+
+/* Register Bit Definitions */
+#define RESCTL_QVGA     0x01
+#define RESCTL_VGA      0x00
+
+#define POWER1_VW_ON    0x01  /* VW Supply FET ON */
+#define POWER1_GVSS_ON  0x02  /* GVSS(-8V) Power Supply ON */
+#define POWER1_VDD_ON   0x04  /* VDD(8V),SVSS(-4V) Power Supply ON */
+
+#define POWER1_VW_OFF   0x00  /* VW Supply FET OFF */
+#define POWER1_GVSS_OFF 0x00  /* GVSS(-8V) Power Supply OFF */
+#define POWER1_VDD_OFF  0x00  /* VDD(8V),SVSS(-4V) Power Supply OFF */
+
+#define POWER0_COM_DCLK 0x01  /* COM Voltage DC Bias DAC Serial Data Clock */
+#define POWER0_COM_DOUT 0x02  /* COM Voltage DC Bias DAC Serial Data Out */
+#define POWER0_DAC_ON   0x04  /* DAC Power Supply ON */
+#define POWER0_COM_ON   0x08  /* COM Power Supply ON */
+#define POWER0_VCC5_ON  0x10  /* VCC5 Power Supply ON */
+
+#define POWER0_DAC_OFF  0x00  /* DAC Power Supply OFF */
+#define POWER0_COM_OFF  0x00  /* COM Power Supply OFF */
+#define POWER0_VCC5_OFF 0x00  /* VCC5 Power Supply OFF */
+
+#define PICTRL_INIT_STATE      0x01
+#define PICTRL_INIOFF          0x02
+#define PICTRL_POWER_DOWN      0x04
+#define PICTRL_COM_SIGNAL_OFF  0x08
+#define PICTRL_DAC_SIGNAL_OFF  0x10
+
+#define POLCTRL_SYNC_POL_FALL  0x01
+#define POLCTRL_EN_POL_FALL    0x02
+#define POLCTRL_DATA_POL_FALL  0x04
+#define POLCTRL_SYNC_ACT_H     0x08
+#define POLCTRL_EN_ACT_L       0x10
+
+#define POLCTRL_SYNC_POL_RISE  0x00
+#define POLCTRL_EN_POL_RISE    0x00
+#define POLCTRL_DATA_POL_RISE  0x00
+#define POLCTRL_SYNC_ACT_L     0x00
+#define POLCTRL_EN_ACT_H       0x00
+
+#define PHACTRL_PHASE_MANUAL   0x01
+#define DEFAULT_PHAD_QVGA     (9)
+#define DEFAULT_COMADJ        (125)
+
+struct corgi_lcd {
+	struct spi_device	*spi_dev;
+	struct lcd_device	*lcd_dev;
+	struct backlight_device	*bl_dev;
+
+	int	limit_mask;
+	int	intensity;
+	int	power;
+	int	mode;
+	char	buf[2];
+
+	int	gpio_backlight_on;
+	int	gpio_backlight_cont;
+	int	gpio_backlight_cont_inverted;
+
+	void (*kick_battery)(void);
+};
+
+static int corgi_ssp_lcdtg_send(struct corgi_lcd *lcd, int reg, uint8_t val);
+
+static struct corgi_lcd *the_corgi_lcd;
+static unsigned long corgibl_flags;
+#define CORGIBL_SUSPENDED     0x01
+#define CORGIBL_BATTLOW       0x02
+
+/*
+ * This is only a psuedo I2C interface. We can't use the standard kernel
+ * routines as the interface is write only. We just assume the data is acked...
+ */
+static void lcdtg_ssp_i2c_send(struct corgi_lcd *lcd, uint8_t data)
+{
+	corgi_ssp_lcdtg_send(lcd, POWERREG0_ADRS, data);
+	udelay(10);
+}
+
+static void lcdtg_i2c_send_bit(struct corgi_lcd *lcd, uint8_t data)
+{
+	lcdtg_ssp_i2c_send(lcd, data);
+	lcdtg_ssp_i2c_send(lcd, data | POWER0_COM_DCLK);
+	lcdtg_ssp_i2c_send(lcd, data);
+}
+
+static void lcdtg_i2c_send_start(struct corgi_lcd *lcd, uint8_t base)
+{
+	lcdtg_ssp_i2c_send(lcd, base | POWER0_COM_DCLK | POWER0_COM_DOUT);
+	lcdtg_ssp_i2c_send(lcd, base | POWER0_COM_DCLK);
+	lcdtg_ssp_i2c_send(lcd, base);
+}
+
+static void lcdtg_i2c_send_stop(struct corgi_lcd *lcd, uint8_t base)
+{
+	lcdtg_ssp_i2c_send(lcd, base);
+	lcdtg_ssp_i2c_send(lcd, base | POWER0_COM_DCLK);
+	lcdtg_ssp_i2c_send(lcd, base | POWER0_COM_DCLK | POWER0_COM_DOUT);
+}
+
+static void lcdtg_i2c_send_byte(struct corgi_lcd *lcd,
+				uint8_t base, uint8_t data)
+{
+	int i;
+	for (i = 0; i < 8; i++) {
+		if (data & 0x80)
+			lcdtg_i2c_send_bit(lcd, base | POWER0_COM_DOUT);
+		else
+			lcdtg_i2c_send_bit(lcd, base);
+		data <<= 1;
+	}
+}
+
+static void lcdtg_i2c_wait_ack(struct corgi_lcd *lcd, uint8_t base)
+{
+	lcdtg_i2c_send_bit(lcd, base);
+}
+
+static void lcdtg_set_common_voltage(struct corgi_lcd *lcd,
+				     uint8_t base_data, uint8_t data)
+{
+	/* Set Common Voltage to M62332FP via I2C */
+	lcdtg_i2c_send_start(lcd, base_data);
+	lcdtg_i2c_send_byte(lcd, base_data, 0x9c);
+	lcdtg_i2c_wait_ack(lcd, base_data);
+	lcdtg_i2c_send_byte(lcd, base_data, 0x00);
+	lcdtg_i2c_wait_ack(lcd, base_data);
+	lcdtg_i2c_send_byte(lcd, base_data, data);
+	lcdtg_i2c_wait_ack(lcd, base_data);
+	lcdtg_i2c_send_stop(lcd, base_data);
+}
+
+static int corgi_ssp_lcdtg_send(struct corgi_lcd *lcd, int adrs, uint8_t data)
+{
+	struct spi_message msg;
+	struct spi_transfer xfer = {
+		.len		= 1,
+		.cs_change	= 1,
+		.tx_buf		= lcd->buf,
+	};
+
+	lcd->buf[0] = ((adrs & 0x07) << 5) | (data & 0x1f);
+	spi_message_init(&msg);
+	spi_message_add_tail(&xfer, &msg);
+
+	return spi_sync(lcd->spi_dev, &msg);
+}
+
+/* Set Phase Adjust */
+static void lcdtg_set_phadadj(struct corgi_lcd *lcd, int mode)
+{
+	int adj;
+
+	switch(mode) {
+	case CORGI_LCD_MODE_VGA:
+		/* Setting for VGA */
+		adj = sharpsl_param.phadadj;
+		adj = (adj < 0) ? PHACTRL_PHASE_MANUAL :
+				  PHACTRL_PHASE_MANUAL | ((adj & 0xf) << 1);
+		break;
+	case CORGI_LCD_MODE_QVGA:
+	default:
+		/* Setting for QVGA */
+		adj = (DEFAULT_PHAD_QVGA << 1) | PHACTRL_PHASE_MANUAL;
+		break;
+	}
+
+	corgi_ssp_lcdtg_send(lcd, PHACTRL_ADRS, adj);
+}
+
+static void corgi_lcd_power_on(struct corgi_lcd *lcd)
+{
+	int comadj;
+
+	/* Initialize Internal Logic & Port */
+	corgi_ssp_lcdtg_send(lcd, PICTRL_ADRS,
+			PICTRL_POWER_DOWN | PICTRL_INIOFF |
+			PICTRL_INIT_STATE | PICTRL_COM_SIGNAL_OFF |
+			PICTRL_DAC_SIGNAL_OFF);
+
+	corgi_ssp_lcdtg_send(lcd, POWERREG0_ADRS,
+			POWER0_COM_DCLK | POWER0_COM_DOUT | POWER0_DAC_OFF |
+			POWER0_COM_OFF | POWER0_VCC5_OFF);
+
+	corgi_ssp_lcdtg_send(lcd, POWERREG1_ADRS,
+			POWER1_VW_OFF | POWER1_GVSS_OFF | POWER1_VDD_OFF);
+
+	/* VDD(+8V), SVSS(-4V) ON */
+	corgi_ssp_lcdtg_send(lcd, POWERREG1_ADRS,
+			POWER1_VW_OFF | POWER1_GVSS_OFF | POWER1_VDD_ON);
+	mdelay(3);
+
+	/* DAC ON */
+	corgi_ssp_lcdtg_send(lcd, POWERREG0_ADRS,
+			POWER0_COM_DCLK | POWER0_COM_DOUT | POWER0_DAC_ON |
+			POWER0_COM_OFF | POWER0_VCC5_OFF);
+
+	/* INIB = H, INI = L  */
+	/* PICTL[0] = H , PICTL[1] = PICTL[2] = PICTL[4] = L */
+	corgi_ssp_lcdtg_send(lcd, PICTRL_ADRS,
+			PICTRL_INIT_STATE | PICTRL_COM_SIGNAL_OFF);
+
+	/* Set Common Voltage */
+	comadj = sharpsl_param.comadj;
+	if (comadj < 0)
+		comadj = DEFAULT_COMADJ;
+
+	lcdtg_set_common_voltage(lcd, POWER0_DAC_ON | POWER0_COM_OFF |
+				 POWER0_VCC5_OFF, comadj);
+
+	/* VCC5 ON, DAC ON */
+	corgi_ssp_lcdtg_send(lcd, POWERREG0_ADRS,
+			POWER0_COM_DCLK | POWER0_COM_DOUT | POWER0_DAC_ON |
+			POWER0_COM_OFF | POWER0_VCC5_ON);
+
+	/* GVSS(-8V) ON, VDD ON */
+	corgi_ssp_lcdtg_send(lcd, POWERREG1_ADRS,
+			POWER1_VW_OFF | POWER1_GVSS_ON | POWER1_VDD_ON);
+	mdelay(2);
+
+	/* COM SIGNAL ON (PICTL[3] = L) */
+	corgi_ssp_lcdtg_send(lcd, PICTRL_ADRS, PICTRL_INIT_STATE);
+
+	/* COM ON, DAC ON, VCC5_ON */
+	corgi_ssp_lcdtg_send(lcd, POWERREG0_ADRS,
+			POWER0_COM_DCLK | POWER0_COM_DOUT | POWER0_DAC_ON |
+			POWER0_COM_ON | POWER0_VCC5_ON);
+
+	/* VW ON, GVSS ON, VDD ON */
+	corgi_ssp_lcdtg_send(lcd, POWERREG1_ADRS,
+			POWER1_VW_ON | POWER1_GVSS_ON | POWER1_VDD_ON);
+
+	/* Signals output enable */
+	corgi_ssp_lcdtg_send(lcd, PICTRL_ADRS, 0);
+
+	/* Set Phase Adjust */
+	lcdtg_set_phadadj(lcd, lcd->mode);
+
+	/* Initialize for Input Signals from ATI */
+	corgi_ssp_lcdtg_send(lcd, POLCTRL_ADRS,
+			POLCTRL_SYNC_POL_RISE | POLCTRL_EN_POL_RISE |
+			POLCTRL_DATA_POL_RISE | POLCTRL_SYNC_ACT_L |
+			POLCTRL_EN_ACT_H);
+	udelay(1000);
+
+	switch (lcd->mode) {
+	case CORGI_LCD_MODE_VGA:
+		corgi_ssp_lcdtg_send(lcd, RESCTL_ADRS, RESCTL_VGA);
+		break;
+	case CORGI_LCD_MODE_QVGA:
+	default:
+		corgi_ssp_lcdtg_send(lcd, RESCTL_ADRS, RESCTL_QVGA);
+		break;
+	}
+}
+
+static void corgi_lcd_power_off(struct corgi_lcd *lcd)
+{
+	/* 60Hz x 2 frame = 16.7msec x 2 = 33.4 msec */
+	msleep(34);
+
+	/* (1)VW OFF */
+	corgi_ssp_lcdtg_send(lcd, POWERREG1_ADRS,
+			POWER1_VW_OFF | POWER1_GVSS_ON | POWER1_VDD_ON);
+
+	/* (2)COM OFF */
+	corgi_ssp_lcdtg_send(lcd, PICTRL_ADRS, PICTRL_COM_SIGNAL_OFF);
+	corgi_ssp_lcdtg_send(lcd, POWERREG0_ADRS,
+			POWER0_DAC_ON | POWER0_COM_OFF | POWER0_VCC5_ON);
+
+	/* (3)Set Common Voltage Bias 0V */
+	lcdtg_set_common_voltage(lcd, POWER0_DAC_ON | POWER0_COM_OFF |
+			POWER0_VCC5_ON, 0);
+
+	/* (4)GVSS OFF */
+	corgi_ssp_lcdtg_send(lcd, POWERREG1_ADRS,
+			POWER1_VW_OFF | POWER1_GVSS_OFF | POWER1_VDD_ON);
+
+	/* (5)VCC5 OFF */
+	corgi_ssp_lcdtg_send(lcd, POWERREG0_ADRS,
+			POWER0_DAC_ON | POWER0_COM_OFF | POWER0_VCC5_OFF);
+
+	/* (6)Set PDWN, INIOFF, DACOFF */
+	corgi_ssp_lcdtg_send(lcd, PICTRL_ADRS,
+			PICTRL_INIOFF | PICTRL_DAC_SIGNAL_OFF |
+			PICTRL_POWER_DOWN | PICTRL_COM_SIGNAL_OFF);
+
+	/* (7)DAC OFF */
+	corgi_ssp_lcdtg_send(lcd, POWERREG0_ADRS,
+			POWER0_DAC_OFF | POWER0_COM_OFF | POWER0_VCC5_OFF);
+
+	/* (8)VDD OFF */
+	corgi_ssp_lcdtg_send(lcd, POWERREG1_ADRS,
+			POWER1_VW_OFF | POWER1_GVSS_OFF | POWER1_VDD_OFF);
+}
+
+static int corgi_lcd_set_mode(struct lcd_device *ld, struct fb_videomode *m)
+{
+	struct corgi_lcd *lcd = dev_get_drvdata(&ld->dev);
+	int mode = CORGI_LCD_MODE_QVGA;
+
+	if (m->xres == 640 || m->xres == 480)
+		mode = CORGI_LCD_MODE_VGA;
+
+	if (lcd->mode == mode)
+		return 0;
+
+	lcdtg_set_phadadj(lcd, mode);
+
+	switch (mode) {
+	case CORGI_LCD_MODE_VGA:
+		corgi_ssp_lcdtg_send(lcd, RESCTL_ADRS, RESCTL_VGA);
+		break;
+	case CORGI_LCD_MODE_QVGA:
+	default:
+		corgi_ssp_lcdtg_send(lcd, RESCTL_ADRS, RESCTL_QVGA);
+		break;
+	}
+
+	lcd->mode = mode;
+	return 0;
+}
+
+static int corgi_lcd_set_power(struct lcd_device *ld, int power)
+{
+	struct corgi_lcd *lcd = dev_get_drvdata(&ld->dev);
+
+	if (POWER_IS_ON(power) && !POWER_IS_ON(lcd->power))
+		corgi_lcd_power_on(lcd);
+
+	if (!POWER_IS_ON(power) && POWER_IS_ON(lcd->power))
+		corgi_lcd_power_off(lcd);
+
+	lcd->power = power;
+	return 0;
+}
+
+static int corgi_lcd_get_power(struct lcd_device *ld)
+{
+	struct corgi_lcd *lcd = dev_get_drvdata(&ld->dev);
+
+	return lcd->power;
+}
+
+static struct lcd_ops corgi_lcd_ops = {
+	.get_power	= corgi_lcd_get_power,
+	.set_power	= corgi_lcd_set_power,
+	.set_mode	= corgi_lcd_set_mode,
+};
+
+static int corgi_bl_get_intensity(struct backlight_device *bd)
+{
+	struct corgi_lcd *lcd = dev_get_drvdata(&bd->dev);
+
+	return lcd->intensity;
+}
+
+static int corgi_bl_set_intensity(struct corgi_lcd *lcd, int intensity)
+{
+	int cont;
+
+	if (intensity > 0x10)
+		intensity += 0x10;
+
+	corgi_ssp_lcdtg_send(lcd, DUTYCTRL_ADRS, intensity);
+
+	/* Bit 5 via GPIO_BACKLIGHT_CONT */
+	cont = !!(intensity & 0x20) ^ lcd->gpio_backlight_cont_inverted;
+
+	if (gpio_is_valid(lcd->gpio_backlight_cont))
+		gpio_set_value(lcd->gpio_backlight_cont, cont);
+
+	if (gpio_is_valid(lcd->gpio_backlight_on))
+		gpio_set_value(lcd->gpio_backlight_on, intensity);
+
+	if (lcd->kick_battery)
+		lcd->kick_battery();
+
+	lcd->intensity = intensity;
+	return 0;
+}
+
+static int corgi_bl_update_status(struct backlight_device *bd)
+{
+	struct corgi_lcd *lcd = dev_get_drvdata(&bd->dev);
+	int intensity = bd->props.brightness;
+
+	if (bd->props.power != FB_BLANK_UNBLANK)
+		intensity = 0;
+
+	if (bd->props.fb_blank != FB_BLANK_UNBLANK)
+		intensity = 0;
+
+	if (corgibl_flags & CORGIBL_SUSPENDED)
+		intensity = 0;
+	if (corgibl_flags & CORGIBL_BATTLOW)
+		intensity &= lcd->limit_mask;
+
+	return corgi_bl_set_intensity(lcd, intensity);
+}
+
+void corgibl_limit_intensity(int limit)
+{
+	if (limit)
+		corgibl_flags |= CORGIBL_BATTLOW;
+	else
+		corgibl_flags &= ~CORGIBL_BATTLOW;
+
+	backlight_update_status(the_corgi_lcd->bl_dev);
+}
+EXPORT_SYMBOL(corgibl_limit_intensity);
+
+static struct backlight_ops corgi_bl_ops = {
+	.get_brightness	= corgi_bl_get_intensity,
+	.update_status  = corgi_bl_update_status,
+};
+
+#ifdef CONFIG_PM
+static int corgi_lcd_suspend(struct spi_device *spi, pm_message_t state)
+{
+	struct corgi_lcd *lcd = dev_get_drvdata(&spi->dev);
+
+	corgibl_flags |= CORGIBL_SUSPENDED;
+	corgi_bl_set_intensity(lcd, 0);
+	corgi_lcd_set_power(lcd->lcd_dev, FB_BLANK_POWERDOWN);
+	return 0;
+}
+
+static int corgi_lcd_resume(struct spi_device *spi)
+{
+	struct corgi_lcd *lcd = dev_get_drvdata(&spi->dev);
+
+	corgibl_flags &= ~CORGIBL_SUSPENDED;
+	corgi_lcd_set_power(lcd->lcd_dev, FB_BLANK_UNBLANK);
+	backlight_update_status(lcd->bl_dev);
+	return 0;
+}
+#else
+#define corgi_lcd_suspend	NULL
+#define corgi_lcd_resume	NULL
+#endif
+
+static int setup_gpio_backlight(struct corgi_lcd *lcd,
+				struct corgi_lcd_platform_data *pdata)
+{
+	struct spi_device *spi = lcd->spi_dev;
+	int err;
+
+	lcd->gpio_backlight_on = -1;
+	lcd->gpio_backlight_cont = -1;
+
+	if (gpio_is_valid(pdata->gpio_backlight_on)) {
+		err = gpio_request(pdata->gpio_backlight_on, "BL_ON");
+		if (err) {
+			dev_err(&spi->dev, "failed to request GPIO%d for "
+				"backlight_on\n", pdata->gpio_backlight_on);
+			return err;
+		}
+
+		lcd->gpio_backlight_on = pdata->gpio_backlight_on;
+		gpio_direction_output(lcd->gpio_backlight_on, 0);
+	}
+
+	if (gpio_is_valid(pdata->gpio_backlight_cont)) {
+		err = gpio_request(pdata->gpio_backlight_cont, "BL_CONT");
+		if (err) {
+			dev_err(&spi->dev, "failed to request GPIO%d for "
+				"backlight_cont\n", pdata->gpio_backlight_cont);
+			goto err_free_backlight_on;
+		}
+
+		lcd->gpio_backlight_cont = pdata->gpio_backlight_cont;
+
+		/* spitz and akita use both GPIOs for backlight, and
+		 * have inverted polarity of GPIO_BACKLIGHT_CONT
+		 */
+		if (gpio_is_valid(lcd->gpio_backlight_on)) {
+			lcd->gpio_backlight_cont_inverted = 1;
+			gpio_direction_output(lcd->gpio_backlight_cont, 1);
+		} else {
+			lcd->gpio_backlight_cont_inverted = 0;
+			gpio_direction_output(lcd->gpio_backlight_cont, 0);
+		}
+	}
+	return 0;
+
+err_free_backlight_on:
+	if (gpio_is_valid(lcd->gpio_backlight_on))
+		gpio_free(lcd->gpio_backlight_on);
+	return err;
+}
+
+static int __devinit corgi_lcd_probe(struct spi_device *spi)
+{
+	struct corgi_lcd_platform_data *pdata = spi->dev.platform_data;
+	struct corgi_lcd *lcd;
+	int ret = 0;
+
+	if (pdata == NULL) {
+		dev_err(&spi->dev, "platform data not available\n");
+		return -EINVAL;
+	}
+
+	lcd = kzalloc(sizeof(struct corgi_lcd), GFP_KERNEL);
+	if (!lcd) {
+		dev_err(&spi->dev, "failed to allocate memory\n");
+		return -ENOMEM;
+	}
+
+	lcd->spi_dev = spi;
+
+	lcd->lcd_dev = lcd_device_register("corgi_lcd", &spi->dev,
+					lcd, &corgi_lcd_ops);
+	if (IS_ERR(lcd->lcd_dev)) {
+		ret = PTR_ERR(lcd->lcd_dev);
+		goto err_free_lcd;
+	}
+	lcd->power = FB_BLANK_POWERDOWN;
+	lcd->mode = (pdata) ? pdata->init_mode : CORGI_LCD_MODE_VGA;
+
+	lcd->bl_dev = backlight_device_register("corgi_bl", &spi->dev,
+					lcd, &corgi_bl_ops);
+	if (IS_ERR(lcd->bl_dev)) {
+		ret = PTR_ERR(lcd->bl_dev);
+		goto err_unregister_lcd;
+	}
+	lcd->bl_dev->props.max_brightness = pdata->max_intensity;
+	lcd->bl_dev->props.brightness = pdata->default_intensity;
+	lcd->bl_dev->props.power = FB_BLANK_UNBLANK;
+
+	ret = setup_gpio_backlight(lcd, pdata);
+	if (ret)
+		goto err_unregister_bl;
+
+	lcd->kick_battery = pdata->kick_battery;
+
+	dev_set_drvdata(&spi->dev, lcd);
+	corgi_lcd_set_power(lcd->lcd_dev, FB_BLANK_UNBLANK);
+	backlight_update_status(lcd->bl_dev);
+
+	lcd->limit_mask = pdata->limit_mask;
+	the_corgi_lcd = lcd;
+	return 0;
+
+err_unregister_bl:
+	backlight_device_unregister(lcd->bl_dev);
+err_unregister_lcd:
+	lcd_device_unregister(lcd->lcd_dev);
+err_free_lcd:
+	kfree(lcd);
+	return ret;
+}
+
+static int __devexit corgi_lcd_remove(struct spi_device *spi)
+{
+	struct corgi_lcd *lcd = dev_get_drvdata(&spi->dev);
+
+	lcd->bl_dev->props.power = FB_BLANK_UNBLANK;
+	lcd->bl_dev->props.brightness = 0;
+	backlight_update_status(lcd->bl_dev);
+	backlight_device_unregister(lcd->bl_dev);
+
+	if (gpio_is_valid(lcd->gpio_backlight_on))
+		gpio_free(lcd->gpio_backlight_on);
+
+	if (gpio_is_valid(lcd->gpio_backlight_cont))
+		gpio_free(lcd->gpio_backlight_cont);
+
+	corgi_lcd_set_power(lcd->lcd_dev, FB_BLANK_POWERDOWN);
+	lcd_device_unregister(lcd->lcd_dev);
+	kfree(lcd);
+
+	return 0;
+}
+
+static struct spi_driver corgi_lcd_driver = {
+	.driver		= {
+		.name	= "corgi-lcd",
+		.owner	= THIS_MODULE,
+	},
+	.probe		= corgi_lcd_probe,
+	.remove		= __devexit_p(corgi_lcd_remove),
+	.suspend	= corgi_lcd_suspend,
+	.resume		= corgi_lcd_resume,
+};
+
+static int __init corgi_lcd_init(void)
+{
+	return spi_register_driver(&corgi_lcd_driver);
+}
+module_init(corgi_lcd_init);
+
+static void __exit corgi_lcd_exit(void)
+{
+	spi_unregister_driver(&corgi_lcd_driver);
+}
+module_exit(corgi_lcd_exit);
+
+MODULE_DESCRIPTION("LCD and backlight driver for SHARP C7x0/Cxx00");
+MODULE_AUTHOR("Eric Miao <eric.miao@marvell.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/backlight/lcd.c b/drivers/video/backlight/lcd.c
index b15b2b8..8e1731d 100644
--- a/drivers/video/backlight/lcd.c
+++ b/drivers/video/backlight/lcd.c
@@ -27,14 +27,26 @@
 	struct fb_event *evdata = data;
 
 	/* If we aren't interested in this event, skip it immediately ... */
-	if (event != FB_EVENT_BLANK)
+	switch (event) {
+	case FB_EVENT_BLANK:
+	case FB_EVENT_MODE_CHANGE:
+	case FB_EVENT_MODE_CHANGE_ALL:
+		break;
+	default:
 		return 0;
+	}
 
 	ld = container_of(self, struct lcd_device, fb_notif);
+	if (!ld->ops)
+		return 0;
+
 	mutex_lock(&ld->ops_lock);
-	if (ld->ops)
-		if (!ld->ops->check_fb || ld->ops->check_fb(ld, evdata->info))
+	if (!ld->ops->check_fb || ld->ops->check_fb(ld, evdata->info)) {
+		if (event == FB_EVENT_BLANK)
 			ld->ops->set_power(ld, *(int *)evdata->data);
+		else
+			ld->ops->set_mode(ld, evdata->data);
+	}
 	mutex_unlock(&ld->ops_lock);
 	return 0;
 }
diff --git a/drivers/video/backlight/mbp_nvidia_bl.c b/drivers/video/backlight/mbp_nvidia_bl.c
index 385cba4..06964af 100644
--- a/drivers/video/backlight/mbp_nvidia_bl.c
+++ b/drivers/video/backlight/mbp_nvidia_bl.c
@@ -111,6 +111,4 @@
 MODULE_AUTHOR("Matthew Garrett <mjg@redhat.com>");
 MODULE_DESCRIPTION("Nvidia-based Macbook Pro Backlight Driver");
 MODULE_LICENSE("GPL");
-MODULE_ALIAS("svnAppleInc.:pnMacBookPro3,1");
-MODULE_ALIAS("svnAppleInc.:pnMacBookPro3,2");
-MODULE_ALIAS("svnAppleInc.:pnMacBookPro4,1");
+MODULE_DEVICE_TABLE(dmi, mbp_device_table);
diff --git a/drivers/video/backlight/tdo24m.c b/drivers/video/backlight/tdo24m.c
new file mode 100644
index 0000000..8427669
--- /dev/null
+++ b/drivers/video/backlight/tdo24m.c
@@ -0,0 +1,396 @@
+/*
+ * tdo24m - SPI-based drivers for Toppoly TDO24M series LCD panels
+ *
+ * Copyright (C) 2008 Marvell International Ltd.
+ * 	Eric Miao <eric.miao@marvell.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
+ *  publishhed by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/spi/spi.h>
+#include <linux/fb.h>
+#include <linux/lcd.h>
+
+#define POWER_IS_ON(pwr)	((pwr) <= FB_BLANK_NORMAL)
+
+#define TDO24M_SPI_BUFF_SIZE	(4)
+#define MODE_QVGA	0
+#define MODE_VGA	1
+
+struct tdo24m {
+	struct spi_device	*spi_dev;
+	struct lcd_device	*lcd_dev;
+
+	struct spi_message	msg;
+	struct spi_transfer	xfer;
+	uint8_t			*buf;
+
+	int			power;
+	int			mode;
+};
+
+/* use bit 30, 31 as the indicator of command parameter number */
+#define CMD0(x)		((0 << 30) | (x))
+#define CMD1(x, x1)	((1 << 30) | ((x) << 9) | 0x100 | (x1))
+#define CMD2(x, x1, x2)	((2 << 30) | ((x) << 18) | 0x20000 |\
+			((x1) << 9) | 0x100 | (x2))
+#define CMD_NULL	(-1)
+
+static uint32_t lcd_panel_reset[] = {
+	CMD0(0x1), /* reset */
+	CMD0(0x0), /* nop */
+	CMD0(0x0), /* nop */
+	CMD0(0x0), /* nop */
+	CMD_NULL,
+};
+
+static uint32_t lcd_panel_on[] = {
+	CMD0(0x29),		/* Display ON */
+	CMD2(0xB8, 0xFF, 0xF9),	/* Output Control */
+	CMD0(0x11),		/* Sleep out */
+	CMD1(0xB0, 0x16),	/* Wake */
+	CMD_NULL,
+};
+
+static uint32_t lcd_panel_off[] = {
+	CMD0(0x28),		/* Display OFF */
+	CMD2(0xB8, 0x80, 0x02),	/* Output Control */
+	CMD0(0x10),		/* Sleep in */
+	CMD1(0xB0, 0x00),	/* Deep stand by in */
+	CMD_NULL,
+};
+
+static uint32_t lcd_vga_pass_through[] = {
+	CMD1(0xB0, 0x16),
+	CMD1(0xBC, 0x80),
+	CMD1(0xE1, 0x00),
+	CMD1(0x36, 0x50),
+	CMD1(0x3B, 0x00),
+	CMD_NULL,
+};
+
+static uint32_t lcd_qvga_pass_through[] = {
+	CMD1(0xB0, 0x16),
+	CMD1(0xBC, 0x81),
+	CMD1(0xE1, 0x00),
+	CMD1(0x36, 0x50),
+	CMD1(0x3B, 0x22),
+	CMD_NULL,
+};
+
+static uint32_t lcd_vga_transfer[] = {
+	CMD1(0xcf, 0x02), 	/* Blanking period control (1) */
+	CMD2(0xd0, 0x08, 0x04),	/* Blanking period control (2) */
+	CMD1(0xd1, 0x01),	/* CKV timing control on/off */
+	CMD2(0xd2, 0x14, 0x00),	/* CKV 1,2 timing control */
+	CMD2(0xd3, 0x1a, 0x0f),	/* OEV timing control */
+	CMD2(0xd4, 0x1f, 0xaf),	/* ASW timing control (1) */
+	CMD1(0xd5, 0x14),	/* ASW timing control (2) */
+	CMD0(0x21),		/* Invert for normally black display */
+	CMD0(0x29),		/* Display on */
+	CMD_NULL,
+};
+
+static uint32_t lcd_qvga_transfer[] = {
+	CMD1(0xd6, 0x02),	/* Blanking period control (1) */
+	CMD2(0xd7, 0x08, 0x04),	/* Blanking period control (2) */
+	CMD1(0xd8, 0x01),	/* CKV timing control on/off */
+	CMD2(0xd9, 0x00, 0x08),	/* CKV 1,2 timing control */
+	CMD2(0xde, 0x05, 0x0a),	/* OEV timing control */
+	CMD2(0xdf, 0x0a, 0x19),	/* ASW timing control (1) */
+	CMD1(0xe0, 0x0a),	/* ASW timing control (2) */
+	CMD0(0x21),		/* Invert for normally black display */
+	CMD0(0x29),		/* Display on */
+	CMD_NULL,
+};
+
+static uint32_t lcd_panel_config[] = {
+	CMD2(0xb8, 0xff, 0xf9),	/* Output control */
+	CMD0(0x11),		/* sleep out */
+	CMD1(0xba, 0x01),	/* Display mode (1) */
+	CMD1(0xbb, 0x00),	/* Display mode (2) */
+	CMD1(0x3a, 0x60),	/* Display mode 18-bit RGB */
+	CMD1(0xbf, 0x10),	/* Drive system change control */
+	CMD1(0xb1, 0x56),	/* Booster operation setup */
+	CMD1(0xb2, 0x33),	/* Booster mode setup */
+	CMD1(0xb3, 0x11),	/* Booster frequency setup */
+	CMD1(0xb4, 0x02),	/* Op amp/system clock */
+	CMD1(0xb5, 0x35),	/* VCS voltage */
+	CMD1(0xb6, 0x40),	/* VCOM voltage */
+	CMD1(0xb7, 0x03),	/* External display signal */
+	CMD1(0xbd, 0x00),	/* ASW slew rate */
+	CMD1(0xbe, 0x00),	/* Dummy data for QuadData operation */
+	CMD1(0xc0, 0x11),	/* Sleep out FR count (A) */
+	CMD1(0xc1, 0x11),	/* Sleep out FR count (B) */
+	CMD1(0xc2, 0x11),	/* Sleep out FR count (C) */
+	CMD2(0xc3, 0x20, 0x40),	/* Sleep out FR count (D) */
+	CMD2(0xc4, 0x60, 0xc0),	/* Sleep out FR count (E) */
+	CMD2(0xc5, 0x10, 0x20),	/* Sleep out FR count (F) */
+	CMD1(0xc6, 0xc0),	/* Sleep out FR count (G) */
+	CMD2(0xc7, 0x33, 0x43),	/* Gamma 1 fine tuning (1) */
+	CMD1(0xc8, 0x44),	/* Gamma 1 fine tuning (2) */
+	CMD1(0xc9, 0x33),	/* Gamma 1 inclination adjustment */
+	CMD1(0xca, 0x00),	/* Gamma 1 blue offset adjustment */
+	CMD2(0xec, 0x01, 0xf0),	/* Horizontal clock cycles */
+	CMD_NULL,
+};
+
+static int tdo24m_writes(struct tdo24m *lcd, uint32_t *array)
+{
+	struct spi_transfer *x = &lcd->xfer;
+	uint32_t data, *p = array;
+	int nparams, err = 0;
+
+	for (; *p != CMD_NULL; p++) {
+
+		nparams = (*p >> 30) & 0x3;
+
+		data = *p << (7 - nparams);
+		switch (nparams) {
+		case 0:
+			lcd->buf[0] = (data >> 8) & 0xff;
+			lcd->buf[1] = data & 0xff;
+			break;
+		case 1:
+			lcd->buf[0] = (data >> 16) & 0xff;
+			lcd->buf[1] = (data >> 8) & 0xff;
+			lcd->buf[2] = data & 0xff;
+			break;
+		case 2:
+			lcd->buf[0] = (data >> 24) & 0xff;
+			lcd->buf[1] = (data >> 16) & 0xff;
+			lcd->buf[2] = (data >> 8) & 0xff;
+			lcd->buf[3] = data & 0xff;
+			break;
+		default:
+			continue;
+		}
+		x->len = nparams + 2;
+		err = spi_sync(lcd->spi_dev, &lcd->msg);
+		if (err)
+			break;
+	}
+
+	return err;
+}
+
+static int tdo24m_adj_mode(struct tdo24m *lcd, int mode)
+{
+	switch (mode) {
+	case MODE_VGA:
+		tdo24m_writes(lcd, lcd_vga_pass_through);
+		tdo24m_writes(lcd, lcd_panel_config);
+		tdo24m_writes(lcd, lcd_vga_transfer);
+		break;
+	case MODE_QVGA:
+		tdo24m_writes(lcd, lcd_qvga_pass_through);
+		tdo24m_writes(lcd, lcd_panel_config);
+		tdo24m_writes(lcd, lcd_qvga_transfer);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	lcd->mode = mode;
+	return 0;
+}
+
+static int tdo24m_power_on(struct tdo24m *lcd)
+{
+	int err;
+
+	err = tdo24m_writes(lcd, lcd_panel_on);
+	if (err)
+		goto out;
+
+	err = tdo24m_writes(lcd, lcd_panel_reset);
+	if (err)
+		goto out;
+
+	err = tdo24m_adj_mode(lcd, lcd->mode);
+out:
+	return err;
+}
+
+static int tdo24m_power_off(struct tdo24m *lcd)
+{
+	return tdo24m_writes(lcd, lcd_panel_off);
+}
+
+static int tdo24m_power(struct tdo24m *lcd, int power)
+{
+	int ret = 0;
+
+	if (POWER_IS_ON(power) && !POWER_IS_ON(lcd->power))
+		ret = tdo24m_power_on(lcd);
+	else if (!POWER_IS_ON(power) && POWER_IS_ON(lcd->power))
+		ret = tdo24m_power_off(lcd);
+
+	if (!ret)
+		lcd->power = power;
+
+	return ret;
+}
+
+
+static int tdo24m_set_power(struct lcd_device *ld, int power)
+{
+	struct tdo24m *lcd = lcd_get_data(ld);
+	return tdo24m_power(lcd, power);
+}
+
+static int tdo24m_get_power(struct lcd_device *ld)
+{
+	struct tdo24m *lcd = lcd_get_data(ld);
+	return lcd->power;
+}
+
+static int tdo24m_set_mode(struct lcd_device *ld, struct fb_videomode *m)
+{
+	struct tdo24m *lcd = lcd_get_data(ld);
+	int mode = MODE_QVGA;
+
+	if (m->xres == 640 || m->xres == 480)
+		mode = MODE_VGA;
+
+	if (lcd->mode == mode)
+		return 0;
+
+	return tdo24m_adj_mode(lcd, mode);
+}
+
+static struct lcd_ops tdo24m_ops = {
+	.get_power	= tdo24m_get_power,
+	.set_power	= tdo24m_set_power,
+	.set_mode	= tdo24m_set_mode,
+};
+
+static int __devinit tdo24m_probe(struct spi_device *spi)
+{
+	struct tdo24m *lcd;
+	struct spi_message *m;
+	struct spi_transfer *x;
+	int err;
+
+	spi->bits_per_word = 8;
+	spi->mode = SPI_MODE_3;
+	err = spi_setup(spi);
+	if (err)
+		return err;
+
+	lcd = kzalloc(sizeof(struct tdo24m), GFP_KERNEL);
+	if (!lcd)
+		return -ENOMEM;
+
+	lcd->spi_dev = spi;
+	lcd->power = FB_BLANK_POWERDOWN;
+	lcd->mode = MODE_VGA;	/* default to VGA */
+
+	lcd->buf = kmalloc(TDO24M_SPI_BUFF_SIZE, sizeof(GFP_KERNEL));
+	if (lcd->buf == NULL) {
+		kfree(lcd);
+		return -ENOMEM;
+	}
+
+	m = &lcd->msg;
+	x = &lcd->xfer;
+
+	spi_message_init(m);
+
+	x->tx_buf = &lcd->buf[0];
+	spi_message_add_tail(x, m);
+
+	lcd->lcd_dev = lcd_device_register("tdo24m", &spi->dev,
+					lcd, &tdo24m_ops);
+	if (IS_ERR(lcd->lcd_dev)) {
+		err = PTR_ERR(lcd->lcd_dev);
+		goto out_free;
+	}
+
+	dev_set_drvdata(&spi->dev, lcd);
+	err = tdo24m_power(lcd, FB_BLANK_UNBLANK);
+	if (err)
+		goto out_unregister;
+
+	return 0;
+
+out_unregister:
+	lcd_device_unregister(lcd->lcd_dev);
+out_free:
+	kfree(lcd->buf);
+	kfree(lcd);
+	return err;
+}
+
+static int __devexit tdo24m_remove(struct spi_device *spi)
+{
+	struct tdo24m *lcd = dev_get_drvdata(&spi->dev);
+
+	tdo24m_power(lcd, FB_BLANK_POWERDOWN);
+	lcd_device_unregister(lcd->lcd_dev);
+	kfree(lcd->buf);
+	kfree(lcd);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int tdo24m_suspend(struct spi_device *spi, pm_message_t state)
+{
+	struct tdo24m *lcd = dev_get_drvdata(&spi->dev);
+
+	return tdo24m_power(lcd, FB_BLANK_POWERDOWN);
+}
+
+static int tdo24m_resume(struct spi_device *spi)
+{
+	struct tdo24m *lcd = dev_get_drvdata(&spi->dev);
+
+	return tdo24m_power(lcd, FB_BLANK_UNBLANK);
+}
+#else
+#define tdo24m_suspend	NULL
+#define tdo24m_resume	NULL
+#endif
+
+/* Power down all displays on reboot, poweroff or halt */
+static void tdo24m_shutdown(struct spi_device *spi)
+{
+	struct tdo24m *lcd = dev_get_drvdata(&spi->dev);
+
+	tdo24m_power(lcd, FB_BLANK_POWERDOWN);
+}
+
+static struct spi_driver tdo24m_driver = {
+	.driver = {
+		.name		= "tdo24m",
+		.owner		= THIS_MODULE,
+	},
+	.probe		= tdo24m_probe,
+	.remove		= __devexit_p(tdo24m_remove),
+	.shutdown	= tdo24m_shutdown,
+	.suspend	= tdo24m_suspend,
+	.resume		= tdo24m_resume,
+};
+
+static int __init tdo24m_init(void)
+{
+	return spi_register_driver(&tdo24m_driver);
+}
+module_init(tdo24m_init);
+
+static void __exit tdo24m_exit(void)
+{
+	spi_unregister_driver(&tdo24m_driver);
+}
+module_exit(tdo24m_exit);
+
+MODULE_AUTHOR("Eric Miao <eric.miao@marvell.com>");
+MODULE_DESCRIPTION("Driver for Toppoly TDO24M LCD Panel");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/bw2.c b/drivers/video/bw2.c
index e721644..1e35ba6 100644
--- a/drivers/video/bw2.c
+++ b/drivers/video/bw2.c
@@ -372,7 +372,7 @@
 	return 0;
 }
 
-static struct of_device_id bw2_match[] = {
+static const struct of_device_id bw2_match[] = {
 	{
 		.name = "bwtwo",
 	},
diff --git a/drivers/video/cg14.c b/drivers/video/cg14.c
index b17e746..a2d1882 100644
--- a/drivers/video/cg14.c
+++ b/drivers/video/cg14.c
@@ -589,7 +589,7 @@
 	return 0;
 }
 
-static struct of_device_id cg14_match[] = {
+static const struct of_device_id cg14_match[] = {
 	{
 		.name = "cgfourteen",
 	},
diff --git a/drivers/video/cg3.c b/drivers/video/cg3.c
index 3aa7b6c..99f87fb 100644
--- a/drivers/video/cg3.c
+++ b/drivers/video/cg3.c
@@ -456,7 +456,7 @@
 	return 0;
 }
 
-static struct of_device_id cg3_match[] = {
+static const struct of_device_id cg3_match[] = {
 	{
 		.name = "cgthree",
 	},
diff --git a/drivers/video/cg6.c b/drivers/video/cg6.c
index 2f64bb3..940ec04 100644
--- a/drivers/video/cg6.c
+++ b/drivers/video/cg6.c
@@ -34,10 +34,11 @@
 
 static void cg6_imageblit(struct fb_info *, const struct fb_image *);
 static void cg6_fillrect(struct fb_info *, const struct fb_fillrect *);
+static void cg6_copyarea(struct fb_info *info, const struct fb_copyarea *area);
 static int cg6_sync(struct fb_info *);
 static int cg6_mmap(struct fb_info *, struct vm_area_struct *);
 static int cg6_ioctl(struct fb_info *, unsigned int, unsigned long);
-static void cg6_copyarea(struct fb_info *info, const struct fb_copyarea *area);
+static int cg6_pan_display(struct fb_var_screeninfo *, struct fb_info *);
 
 /*
  *  Frame buffer operations
@@ -47,6 +48,7 @@
 	.owner			= THIS_MODULE,
 	.fb_setcolreg		= cg6_setcolreg,
 	.fb_blank		= cg6_blank,
+	.fb_pan_display		= cg6_pan_display,
 	.fb_fillrect		= cg6_fillrect,
 	.fb_copyarea		= cg6_copyarea,
 	.fb_imageblit		= cg6_imageblit,
@@ -161,6 +163,7 @@
 #define CG6_THC_MISC_INT_ENAB		(1 << 5)
 #define CG6_THC_MISC_INT		(1 << 4)
 #define CG6_THC_MISC_INIT		0x9f
+#define CG6_THC_CURSOFF			((65536-32) | ((65536-32) << 16))
 
 /* The contents are unknown */
 struct cg6_tec {
@@ -280,6 +283,33 @@
 	return 0;
 }
 
+static void cg6_switch_from_graph(struct cg6_par *par)
+{
+	struct cg6_thc __iomem *thc = par->thc;
+	unsigned long flags;
+
+	spin_lock_irqsave(&par->lock, flags);
+
+	/* Hide the cursor. */
+	sbus_writel(CG6_THC_CURSOFF, &thc->thc_cursxy);
+
+	spin_unlock_irqrestore(&par->lock, flags);
+}
+
+static int cg6_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+	struct cg6_par *par = (struct cg6_par *)info->par;
+
+	/* We just use this to catch switches out of
+	 * graphics mode.
+	 */
+	cg6_switch_from_graph(par);
+
+	if (var->xoffset || var->yoffset || var->vmode)
+		return -EINVAL;
+	return 0;
+}
+
 /**
  *	cg6_fillrect -	Draws a rectangle on the screen.
  *
@@ -643,9 +673,13 @@
 	struct cg6_par *par = (struct cg6_par *)info->par;
 	struct cg6_tec __iomem *tec = par->tec;
 	struct cg6_fbc __iomem *fbc = par->fbc;
+	struct cg6_thc __iomem *thc = par->thc;
 	u32 rev, conf, mode;
 	int i;
 
+	/* Hide the cursor. */
+	sbus_writel(CG6_THC_CURSOFF, &thc->thc_cursxy);
+
 	/* Turn off stuff in the Transform Engine. */
 	sbus_writel(0, &tec->tec_matrix);
 	sbus_writel(0, &tec->tec_clip);
@@ -814,7 +848,7 @@
 	return 0;
 }
 
-static struct of_device_id cg6_match[] = {
+static const struct of_device_id cg6_match[] = {
 	{
 		.name = "cgsix",
 	},
diff --git a/drivers/video/console/Kconfig b/drivers/video/console/Kconfig
index 06f87b0..2f50a80 100644
--- a/drivers/video/console/Kconfig
+++ b/drivers/video/console/Kconfig
@@ -43,22 +43,6 @@
 	 buffer.  Each 64KB will give you approximately 16 80x25
 	 screenfuls of scrollback buffer
 
-config VIDEO_SELECT
-	bool "Video mode selection support"
-	depends on  X86 && VGA_CONSOLE
-	---help---
-	  This enables support for text mode selection on kernel startup. If
-	  you want to take advantage of some high-resolution text mode your
-	  card's BIOS offers, but the traditional Linux utilities like
-	  SVGATextMode don't, you can say Y here and set the mode using the
-	  "vga=" option from your boot loader (lilo or loadlin) or set
-	  "vga=ask" which brings up a video mode menu on kernel startup. (Try
-	  "man bootparam" or see the documentation of your boot loader about
-	  how to pass options to the kernel.)
-
-	  Read the file <file:Documentation/svga.txt> for more information
-	  about the Video mode selection support. If unsure, say N.
-
 config MDA_CONSOLE
 	depends on !M68K && !PARISC && ISA
 	tristate "MDA text console (dual-headed) (EXPERIMENTAL)"
diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c
index c6299e8..da91bb1 100644
--- a/drivers/video/console/fbcon.c
+++ b/drivers/video/console/fbcon.c
@@ -1855,8 +1855,6 @@
 	struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
 	struct display *p = &fb_display[vc->vc_num];
 	int scroll_partial = info->flags & FBINFO_PARTIAL_PAN_OK;
-	unsigned short saved_ec;
-	int ret;
 
 	if (fbcon_is_inactive(vc, info))
 		return -EINVAL;
@@ -1869,11 +1867,6 @@
 	 *           whole screen (prevents flicker).
 	 */
 
-	saved_ec = vc->vc_video_erase_char;
-	vc->vc_video_erase_char = vc->vc_scrl_erase_char;
-
-	ret = 0;
-
 	switch (dir) {
 	case SM_UP:
 		if (count > vc->vc_rows)	/* Maximum realistic size */
@@ -1890,9 +1883,9 @@
 			scr_memsetw((unsigned short *) (vc->vc_origin +
 							vc->vc_size_row *
 							(b - count)),
-				    vc->vc_scrl_erase_char,
+				    vc->vc_video_erase_char,
 				    vc->vc_size_row * count);
-			ret = 1;
+			return 1;
 			break;
 
 		case SCROLL_WRAP_MOVE:
@@ -1962,10 +1955,9 @@
 			scr_memsetw((unsigned short *) (vc->vc_origin +
 							vc->vc_size_row *
 							(b - count)),
-				    vc->vc_scrl_erase_char,
+				    vc->vc_video_erase_char,
 				    vc->vc_size_row * count);
-			ret = 1;
-			break;
+			return 1;
 		}
 		break;
 
@@ -1982,9 +1974,9 @@
 			scr_memsetw((unsigned short *) (vc->vc_origin +
 							vc->vc_size_row *
 							t),
-				    vc->vc_scrl_erase_char,
+				    vc->vc_video_erase_char,
 				    vc->vc_size_row * count);
-			ret = 1;
+			return 1;
 			break;
 
 		case SCROLL_WRAP_MOVE:
@@ -2052,15 +2044,12 @@
 			scr_memsetw((unsigned short *) (vc->vc_origin +
 							vc->vc_size_row *
 							t),
-				    vc->vc_scrl_erase_char,
+				    vc->vc_video_erase_char,
 				    vc->vc_size_row * count);
-			ret = 1;
-			break;
+			return 1;
 		}
-		break;
 	}
-	vc->vc_video_erase_char = saved_ec;
-	return ret;
+	return 0;
 }
 
 
@@ -2400,11 +2389,15 @@
 
  	if (!fbcon_is_inactive(vc, info)) {
 		if (ops->blank_state != blank) {
+			int ret = 1;
+
 			ops->blank_state = blank;
 			fbcon_cursor(vc, blank ? CM_ERASE : CM_DRAW);
 			ops->cursor_flash = (!blank);
 
-			if (fb_blank(info, blank))
+			if (info->fbops->fb_blank)
+				ret = info->fbops->fb_blank(blank, info);
+			if (ret)
 				fbcon_generic_blank(vc, info, blank);
 		}
 
@@ -2518,9 +2511,6 @@
 			c = vc->vc_video_erase_char;
 			vc->vc_video_erase_char =
 			    ((c & 0xfe00) >> 1) | (c & 0xff);
-			c = vc->vc_scrl_erase_char;
-			vc->vc_scrl_erase_char =
-			    ((c & 0xFE00) >> 1) | (c & 0xFF);
 			vc->vc_attr >>= 1;
 		}
 	} else if (!vc->vc_hi_font_mask && cnt == 512) {
@@ -2551,14 +2541,9 @@
 			if (vc->vc_can_do_color) {
 				vc->vc_video_erase_char =
 				    ((c & 0xff00) << 1) | (c & 0xff);
-				c = vc->vc_scrl_erase_char;
-				vc->vc_scrl_erase_char =
-				    ((c & 0xFF00) << 1) | (c & 0xFF);
 				vc->vc_attr <<= 1;
-			} else {
+			} else
 				vc->vc_video_erase_char = c & ~0x100;
-				vc->vc_scrl_erase_char = c & ~0x100;
-			}
 		}
 
 	}
diff --git a/drivers/video/console/fbcon.h b/drivers/video/console/fbcon.h
index a6e38e9..89a34688 100644
--- a/drivers/video/console/fbcon.h
+++ b/drivers/video/console/fbcon.h
@@ -110,7 +110,7 @@
 	__u32 max_len;
 	max_len = max(info->var.green.length, info->var.red.length);
 	max_len = max(info->var.blue.length, max_len);
-	return ~(0xfff << (max_len & 0xff));
+	return (~(0xfff << max_len)) & 0xff;
 }
 
 static inline int attr_col_ec(int shift, struct vc_data *vc,
diff --git a/drivers/video/console/mdacon.c b/drivers/video/console/mdacon.c
index 9901064..dd3eaaa 100644
--- a/drivers/video/console/mdacon.c
+++ b/drivers/video/console/mdacon.c
@@ -533,7 +533,7 @@
 
 static int mdacon_scroll(struct vc_data *c, int t, int b, int dir, int lines)
 {
-	u16 eattr = mda_convert_attr(c->vc_scrl_erase_char);
+	u16 eattr = mda_convert_attr(c->vc_video_erase_char);
 
 	if (!lines)
 		return 0;
diff --git a/drivers/video/console/sticon.c b/drivers/video/console/sticon.c
index 4055dbd..491c1c1 100644
--- a/drivers/video/console/sticon.c
+++ b/drivers/video/console/sticon.c
@@ -170,12 +170,12 @@
     switch (dir) {
     case SM_UP:
 	sti_bmove(sti, t + count, 0, t, 0, b - t - count, conp->vc_cols);
-	sti_clear(sti, b - count, 0, count, conp->vc_cols, conp->vc_scrl_erase_char);
+	sti_clear(sti, b - count, 0, count, conp->vc_cols, conp->vc_video_erase_char);
 	break;
 
     case SM_DOWN:
 	sti_bmove(sti, t, 0, t + count, 0, b - t - count, conp->vc_cols);
-	sti_clear(sti, t, 0, count, conp->vc_cols, conp->vc_scrl_erase_char);
+	sti_clear(sti, t, 0, count, conp->vc_cols, conp->vc_video_erase_char);
 	break;
     }
 
diff --git a/drivers/video/console/vgacon.c b/drivers/video/console/vgacon.c
index bd1f57b..6df29a6 100644
--- a/drivers/video/console/vgacon.c
+++ b/drivers/video/console/vgacon.c
@@ -1350,7 +1350,7 @@
 		} else
 			c->vc_origin += delta;
 		scr_memsetw((u16 *) (c->vc_origin + c->vc_screenbuf_size -
-				     delta), c->vc_scrl_erase_char,
+				     delta), c->vc_video_erase_char,
 			    delta);
 	} else {
 		if (oldo - delta < vga_vram_base) {
@@ -1363,7 +1363,7 @@
 		} else
 			c->vc_origin -= delta;
 		c->vc_scr_end = c->vc_origin + c->vc_screenbuf_size;
-		scr_memsetw((u16 *) (c->vc_origin), c->vc_scrl_erase_char,
+		scr_memsetw((u16 *) (c->vc_origin), c->vc_video_erase_char,
 			    delta);
 	}
 	c->vc_scr_end = c->vc_origin + c->vc_screenbuf_size;
diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c
index 98843c2..0737570 100644
--- a/drivers/video/fbmem.c
+++ b/drivers/video/fbmem.c
@@ -979,6 +979,7 @@
 
 				info->flags &= ~FBINFO_MISC_USEREVENT;
 				event.info = info;
+				event.data = &mode;
 				fb_notifier_call_chain(evnt, &event);
 			}
 		}
diff --git a/drivers/video/ffb.c b/drivers/video/ffb.c
index 7992b13..9dbb964 100644
--- a/drivers/video/ffb.c
+++ b/drivers/video/ffb.c
@@ -1042,7 +1042,7 @@
 	return 0;
 }
 
-static struct of_device_id ffb_match[] = {
+static const struct of_device_id ffb_match[] = {
 	{
 		.name = "SUNW,ffb",
 	},
diff --git a/drivers/video/leo.c b/drivers/video/leo.c
index 13fea61..7c7e8c2 100644
--- a/drivers/video/leo.c
+++ b/drivers/video/leo.c
@@ -33,6 +33,7 @@
 
 static int leo_mmap(struct fb_info *, struct vm_area_struct *);
 static int leo_ioctl(struct fb_info *, unsigned int, unsigned long);
+static int leo_pan_display(struct fb_var_screeninfo *, struct fb_info *);
 
 /*
  *  Frame buffer operations
@@ -42,6 +43,7 @@
 	.owner			= THIS_MODULE,
 	.fb_setcolreg		= leo_setcolreg,
 	.fb_blank		= leo_blank,
+	.fb_pan_display		= leo_pan_display,
 	.fb_fillrect		= cfb_fillrect,
 	.fb_copyarea		= cfb_copyarea,
 	.fb_imageblit		= cfb_imageblit,
@@ -206,6 +208,60 @@
 	return;
 }
 
+static void leo_switch_from_graph(struct fb_info *info)
+{
+	struct leo_par *par = (struct leo_par *) info->par;
+	struct leo_ld_ss0 __iomem *ss = par->ld_ss0;
+	struct leo_cursor __iomem *cursor = par->cursor;
+	unsigned long flags;
+	u32 val;
+
+	spin_lock_irqsave(&par->lock, flags);
+
+	par->extent = ((info->var.xres - 1) |
+		       ((info->var.yres - 1) << 16));
+
+	sbus_writel(0xffffffff, &ss->wid);
+	sbus_writel(0xffff, &ss->wmask);
+	sbus_writel(0, &ss->vclipmin);
+	sbus_writel(par->extent, &ss->vclipmax);
+	sbus_writel(0, &ss->fg);
+	sbus_writel(0xff000000, &ss->planemask);
+	sbus_writel(0x310850, &ss->rop);
+	sbus_writel(0, &ss->widclip);
+	sbus_writel((info->var.xres-1) | ((info->var.yres-1) << 11),
+		    &par->lc_ss0_usr->extent);
+	sbus_writel(4, &par->lc_ss0_usr->addrspace);
+	sbus_writel(0x80000000, &par->lc_ss0_usr->fill);
+	sbus_writel(0, &par->lc_ss0_usr->fontt);
+	do {
+		val = sbus_readl(&par->lc_ss0_usr->csr);
+	} while (val & 0x20000000);
+
+	/* setup screen buffer for cfb_* functions */
+	sbus_writel(1, &ss->wid);
+	sbus_writel(0x00ffffff, &ss->planemask);
+	sbus_writel(0x310b90, &ss->rop);
+	sbus_writel(0, &par->lc_ss0_usr->addrspace);
+
+	/* hide cursor */
+	sbus_writel(sbus_readl(&cursor->cur_misc) & ~LEO_CUR_ENABLE, &cursor->cur_misc);
+
+	spin_unlock_irqrestore(&par->lock, flags);
+}
+
+static int leo_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+	/* We just use this to catch switches out of
+	 * graphics mode.
+	 */
+	leo_switch_from_graph(info);
+
+	if (var->xoffset || var->yoffset || var->vmode)
+		return -EINVAL;
+	return 0;
+}
+
 /**
  *      leo_setcolreg - Optional function. Sets a color register.
  *      @regno: boolean, 0 copy local, 1 get_user() function
@@ -454,44 +510,6 @@
 	leo_wid_put(info, &wl);
 }
 
-static void leo_switch_from_graph(struct fb_info *info)
-{
-	struct leo_par *par = (struct leo_par *) info->par;
-	struct leo_ld_ss0 __iomem *ss = par->ld_ss0;
-	unsigned long flags;
-	u32 val;
-
-	spin_lock_irqsave(&par->lock, flags);
-
-	par->extent = ((info->var.xres - 1) |
-		       ((info->var.yres - 1) << 16));
-
-	sbus_writel(0xffffffff, &ss->wid);
-	sbus_writel(0xffff, &ss->wmask);
-	sbus_writel(0, &ss->vclipmin);
-	sbus_writel(par->extent, &ss->vclipmax);
-	sbus_writel(0, &ss->fg);
-	sbus_writel(0xff000000, &ss->planemask);
-	sbus_writel(0x310850, &ss->rop);
-	sbus_writel(0, &ss->widclip);
-	sbus_writel((info->var.xres-1) | ((info->var.yres-1) << 11),
-		    &par->lc_ss0_usr->extent);
-	sbus_writel(4, &par->lc_ss0_usr->addrspace);
-	sbus_writel(0x80000000, &par->lc_ss0_usr->fill);
-	sbus_writel(0, &par->lc_ss0_usr->fontt);
-	do {
-		val = sbus_readl(&par->lc_ss0_usr->csr);
-	} while (val & 0x20000000);
-
-	/* setup screen buffer for cfb_* functions */
-	sbus_writel(1, &ss->wid);
-	sbus_writel(0x00ffffff, &ss->planemask);
-	sbus_writel(0x310b90, &ss->rop);
-	sbus_writel(0, &par->lc_ss0_usr->addrspace);
-
-	spin_unlock_irqrestore(&par->lock, flags);
-}
-
 static void leo_init_hw(struct fb_info *info)
 {
 	struct leo_par *par = (struct leo_par *) info->par;
@@ -641,7 +659,7 @@
 	return 0;
 }
 
-static struct of_device_id leo_match[] = {
+static const struct of_device_id leo_match[] = {
 	{
 		.name = "SUNW,leo",
 	},
diff --git a/drivers/video/metronomefb.c b/drivers/video/metronomefb.c
index cc4c038..afeed06 100644
--- a/drivers/video/metronomefb.c
+++ b/drivers/video/metronomefb.c
@@ -40,29 +40,63 @@
 
 #include <asm/unaligned.h>
 
-
-#define DEBUG 1
-#ifdef DEBUG
-#define DPRINTK(f, a...) printk(KERN_DEBUG "%s: " f, __func__ , ## a)
-#else
-#define DPRINTK(f, a...)
-#endif
-
-
 /* Display specific information */
 #define DPY_W 832
 #define DPY_H 622
 
+static int user_wfm_size;
+
 /* frame differs from image. frame includes non-visible pixels */
 struct epd_frame {
 	int fw; /* frame width */
 	int fh; /* frame height */
+	u16 config[4];
+	int wfm_size;
 };
 
 static struct epd_frame epd_frame_table[] = {
 	{
-	.fw = 832,
-	.fh = 622
+		.fw = 832,
+		.fh = 622,
+		.config = {
+			15 /* sdlew */
+			| 2 << 8 /* sdosz */
+			| 0 << 11 /* sdor */
+			| 0 << 12 /* sdces */
+			| 0 << 15, /* sdcer */
+			42 /* gdspl */
+			| 1 << 8 /* gdr1 */
+			| 1 << 9 /* sdshr */
+			| 0 << 15, /* gdspp */
+			18 /* gdspw */
+			| 0 << 15, /* dispc */
+			599 /* vdlc */
+			| 0 << 11 /* dsi */
+			| 0 << 12, /* dsic */
+		},
+		.wfm_size = 47001,
+	},
+	{
+		.fw = 1088,
+		.fh = 791,
+		.config = {
+			0x0104,
+			0x031f,
+			0x0088,
+			0x02ff,
+		},
+		.wfm_size = 46770,
+	},
+	{
+		.fw = 1200,
+		.fh = 842,
+		.config = {
+			0x0101,
+			0x030e,
+			0x0012,
+			0x0280,
+		},
+		.wfm_size = 46770,
 	},
 };
 
@@ -134,9 +168,8 @@
 }
 
 /* here we decode the incoming waveform file and populate metromem */
-#define EXP_WFORM_SIZE 47001
-static int load_waveform(u8 *mem, size_t size, u8 *metromem, int m, int t,
-				u8 *frame_count)
+static int __devinit load_waveform(u8 *mem, size_t size, int m, int t,
+				struct metronomefb_par *par)
 {
 	int tta;
 	int wmta;
@@ -148,26 +181,31 @@
 	int wfm_idx, owfm_idx;
 	int mem_idx = 0;
 	struct waveform_hdr *wfm_hdr;
+	u8 *metromem = par->metromem_wfm;
+	struct device *dev = par->info->dev;
 
-	if (size != EXP_WFORM_SIZE) {
-		printk(KERN_ERR "Error: unexpected size %d != %d\n", size,
-					EXP_WFORM_SIZE);
+	if (user_wfm_size)
+		epd_frame_table[par->dt].wfm_size = user_wfm_size;
+
+	if (size != epd_frame_table[par->dt].wfm_size) {
+		dev_err(dev, "Error: unexpected size %d != %d\n", size,
+					epd_frame_table[par->dt].wfm_size);
 		return -EINVAL;
 	}
 
 	wfm_hdr = (struct waveform_hdr *) mem;
 
 	if (wfm_hdr->fvsn != 1) {
-		printk(KERN_ERR "Error: bad fvsn %x\n", wfm_hdr->fvsn);
+		dev_err(dev, "Error: bad fvsn %x\n", wfm_hdr->fvsn);
 		return -EINVAL;
 	}
 	if (wfm_hdr->luts != 0) {
-		printk(KERN_ERR "Error: bad luts %x\n", wfm_hdr->luts);
+		dev_err(dev, "Error: bad luts %x\n", wfm_hdr->luts);
 		return -EINVAL;
 	}
 	cksum = calc_cksum(32, 47, mem);
 	if (cksum != wfm_hdr->wfm_cs) {
-		printk(KERN_ERR "Error: bad cksum %x != %x\n", cksum,
+		dev_err(dev, "Error: bad cksum %x != %x\n", cksum,
 					wfm_hdr->wfm_cs);
 		return -EINVAL;
 	}
@@ -175,7 +213,7 @@
 	wfm_hdr->trc += 1;
 	for (i = 0; i < 5; i++) {
 		if (*(wfm_hdr->stuff2a + i) != 0) {
-			printk(KERN_ERR "Error: unexpected value in padding\n");
+			dev_err(dev, "Error: unexpected value in padding\n");
 			return -EINVAL;
 		}
 	}
@@ -200,7 +238,7 @@
 		return -EINVAL;
 	cksum = calc_cksum(sizeof(*wfm_hdr), cksum_idx, mem);
 	if (cksum != mem[cksum_idx]) {
-		printk(KERN_ERR "Error: bad temperature range table cksum"
+		dev_err(dev, "Error: bad temperature range table cksum"
 				" %x != %x\n", cksum, mem[cksum_idx]);
 		return -EINVAL;
 	}
@@ -212,7 +250,7 @@
 		return -EINVAL;
 	cksum = calc_cksum(cksum_idx - 3, cksum_idx, mem);
 	if (cksum != mem[cksum_idx]) {
-		printk(KERN_ERR "Error: bad mode table address cksum"
+		dev_err(dev, "Error: bad mode table address cksum"
 				" %x != %x\n", cksum, mem[cksum_idx]);
 		return -EINVAL;
 	}
@@ -224,7 +262,7 @@
 		return -EINVAL;
 	cksum = calc_cksum(cksum_idx - 3, cksum_idx, mem);
 	if (cksum != mem[cksum_idx]) {
-		printk(KERN_ERR "Error: bad temperature table address cksum"
+		dev_err(dev, "Error: bad temperature table address cksum"
 			" %x != %x\n", cksum, mem[cksum_idx]);
 		return -EINVAL;
 	}
@@ -259,11 +297,11 @@
 		return -EINVAL;
 	cksum = calc_cksum(owfm_idx, cksum_idx, mem);
 	if (cksum != mem[cksum_idx]) {
-		printk(KERN_ERR "Error: bad waveform data cksum"
+		dev_err(dev, "Error: bad waveform data cksum"
 				" %x != %x\n", cksum, mem[cksum_idx]);
 		return -EINVAL;
 	}
-	*frame_count = (mem_idx/64);
+	par->frame_count = (mem_idx/64);
 
 	return 0;
 }
@@ -274,15 +312,12 @@
 	u16 cs;
 	u16 opcode;
 	static u8 borderval;
-	u8 *ptr;
 
 	/* setup display command
 	we can't immediately set the opcode since the controller
 	will try parse the command before we've set it all up
 	so we just set cs here and set the opcode at the end */
 
-	ptr = par->metromem;
-
 	if (par->metromem_cmd->opcode == 0xCC40)
 		opcode = cs = 0xCC41;
 	else
@@ -335,44 +370,17 @@
 
 static int __devinit metronome_config_cmd(struct metronomefb_par *par)
 {
-	int i;
-	u16 cs;
-
 	/* setup config command
 	we can't immediately set the opcode since the controller
-	will try parse the command before we've set it all up
-	so we just set cs here and set the opcode at the end */
+	will try parse the command before we've set it all up */
 
-	cs = 0xCC10;
-
-	/* set the 12 args ( 8 bytes ) for config. see spec for meanings */
-	i = 0;
-	par->metromem_cmd->args[i] = 	15 /* sdlew */
-					| 2 << 8 /* sdosz */
-					| 0 << 11 /* sdor */
-					| 0 << 12 /* sdces */
-					| 0 << 15; /* sdcer */
-	cs += par->metromem_cmd->args[i++];
-
-	par->metromem_cmd->args[i] = 	42 /* gdspl */
-					| 1 << 8 /* gdr1 */
-					| 1 << 9 /* sdshr */
-					| 0 << 15; /* gdspp */
-	cs += par->metromem_cmd->args[i++];
-
-	par->metromem_cmd->args[i] = 	18 /* gdspw */
-					| 0 << 15; /* dispc */
-	cs += par->metromem_cmd->args[i++];
-
-	par->metromem_cmd->args[i] = 	599 /* vdlc */
-					| 0 << 11 /* dsi */
-					| 0 << 12; /* dsic */
-	cs += par->metromem_cmd->args[i++];
-
+	memcpy(par->metromem_cmd->args, epd_frame_table[par->dt].config,
+		sizeof(epd_frame_table[par->dt].config));
 	/* the rest are 0 */
-	memset((u8 *) (par->metromem_cmd->args + i), 0, (32-i)*2);
+	memset((u8 *) (par->metromem_cmd->args + 4), 0, (32-4)*2);
 
-	par->metromem_cmd->csum = cs;
+	par->metromem_cmd->csum = 0xCC10;
+	par->metromem_cmd->csum += calc_img_cksum(par->metromem_cmd->args, 4);
 	par->metromem_cmd->opcode = 0xCC10; /* config cmd */
 
 	return par->board->met_wait_event(par);
@@ -408,12 +416,9 @@
 {
 	int res;
 
-	par->board->init_gpio_regs(par);
-
-	par->board->init_lcdc_regs(par);
-
-	/* now that lcd is setup, setup dma descriptor */
-	par->board->post_dma_setup(par);
+	res = par->board->setup_io(par);
+	if (res)
+		return res;
 
 	res = metronome_powerup_cmd(par);
 	if (res)
@@ -430,16 +435,16 @@
 
 static void metronomefb_dpy_update(struct metronomefb_par *par)
 {
+	int fbsize;
 	u16 cksum;
 	unsigned char *buf = (unsigned char __force *)par->info->screen_base;
 
+	fbsize = par->info->fix.smem_len;
 	/* copy from vm to metromem */
-	memcpy(par->metromem_img, buf, DPY_W*DPY_H);
+	memcpy(par->metromem_img, buf, fbsize);
 
-	cksum = calc_img_cksum((u16 *) par->metromem_img,
-				(epd_frame_table[0].fw * DPY_H)/2);
-	*((u16 *)(par->metromem_img) +
-			(epd_frame_table[0].fw * DPY_H)/2) = cksum;
+	cksum = calc_img_cksum((u16 *) par->metromem_img, fbsize/2);
+	*((u16 *)(par->metromem_img) + fbsize/2) = cksum;
 	metronome_display_cmd(par);
 }
 
@@ -574,8 +579,10 @@
 	unsigned char *videomemory;
 	struct metronomefb_par *par;
 	const struct firmware *fw_entry;
-	int cmd_size, wfm_size, img_size, padding_size, totalsize;
 	int i;
+	int panel_type;
+	int fw, fh;
+	int epd_dt_index;
 
 	/* pick up board specific routines */
 	board = dev->dev.platform_data;
@@ -586,96 +593,108 @@
 	if (!try_module_get(board->owner))
 		return -ENODEV;
 
+	info = framebuffer_alloc(sizeof(struct metronomefb_par), &dev->dev);
+	if (!info)
+		goto err;
+
 	/* we have two blocks of memory.
 	info->screen_base which is vm, and is the fb used by apps.
 	par->metromem which is physically contiguous memory and
 	contains the display controller commands, waveform,
 	processed image data and padding. this is the data pulled
-	by the device's LCD controller and pushed to Metronome */
+	by the device's LCD controller and pushed to Metronome.
+	the metromem memory is allocated by the board driver and
+	is provided to us */
 
-	videomemorysize = (DPY_W*DPY_H);
+	panel_type = board->get_panel_type();
+	switch (panel_type) {
+	case 6:
+		epd_dt_index = 0;
+		break;
+	case 8:
+		epd_dt_index = 1;
+		break;
+	case 97:
+		epd_dt_index = 2;
+		break;
+	default:
+		dev_err(&dev->dev, "Unexpected panel type. Defaulting to 6\n");
+		epd_dt_index = 0;
+		break;
+	}
+
+	fw = epd_frame_table[epd_dt_index].fw;
+	fh = epd_frame_table[epd_dt_index].fh;
+
+	/* we need to add a spare page because our csum caching scheme walks
+	 * to the end of the page */
+	videomemorysize = PAGE_SIZE + (fw * fh);
 	videomemory = vmalloc(videomemorysize);
 	if (!videomemory)
-		return -ENOMEM;
+		goto err_fb_rel;
 
 	memset(videomemory, 0, videomemorysize);
 
-	info = framebuffer_alloc(sizeof(struct metronomefb_par), &dev->dev);
-	if (!info)
-		goto err_vfree;
-
 	info->screen_base = (char __force __iomem *)videomemory;
 	info->fbops = &metronomefb_ops;
 
+	metronomefb_fix.line_length = fw;
+	metronomefb_var.xres = fw;
+	metronomefb_var.yres = fh;
+	metronomefb_var.xres_virtual = fw;
+	metronomefb_var.yres_virtual = fh;
 	info->var = metronomefb_var;
 	info->fix = metronomefb_fix;
 	info->fix.smem_len = videomemorysize;
 	par = info->par;
 	par->info = info;
 	par->board = board;
+	par->dt = epd_dt_index;
 	init_waitqueue_head(&par->waitq);
 
 	/* this table caches per page csum values. */
 	par->csum_table = vmalloc(videomemorysize/PAGE_SIZE);
 	if (!par->csum_table)
-		goto err_csum_table;
-
-	/* the metromem buffer is divided as follows:
-	command | CRC | padding
-	16kb waveform data | CRC | padding
-	image data | CRC
-	and an extra 256 bytes for dma descriptors
-	eg: IW=832 IH=622 WS=128
-	*/
-
-	cmd_size = 1 * epd_frame_table[0].fw;
-	wfm_size = ((16*1024 + 2 + epd_frame_table[0].fw - 1)
-			/ epd_frame_table[0].fw) * epd_frame_table[0].fw;
-	img_size = epd_frame_table[0].fh * epd_frame_table[0].fw;
-	padding_size = 4 * epd_frame_table[0].fw;
-	totalsize = cmd_size + wfm_size + img_size + padding_size;
-	par->metromemsize = PAGE_ALIGN(totalsize + 256);
-	DPRINTK("desired memory size = %d\n", par->metromemsize);
-	dev->dev.coherent_dma_mask = 0xffffffffull;
-	par->metromem = dma_alloc_writecombine(&dev->dev, par->metromemsize,
-						&par->metromem_dma, GFP_KERNEL);
-	if (!par->metromem) {
-		printk(KERN_ERR
-			"metronomefb: unable to allocate dma buffer\n");
 		goto err_vfree;
+
+	/* the physical framebuffer that we use is setup by
+	 * the platform device driver. It will provide us
+	 * with cmd, wfm and image memory in a contiguous area. */
+	retval = board->setup_fb(par);
+	if (retval) {
+		dev_err(&dev->dev, "Failed to setup fb\n");
+		goto err_csum_table;
+	}
+
+	/* after this point we should have a framebuffer */
+	if ((!par->metromem_wfm) ||  (!par->metromem_img) ||
+		(!par->metromem_dma)) {
+		dev_err(&dev->dev, "fb access failure\n");
+		retval = -EINVAL;
+		goto err_csum_table;
 	}
 
 	info->fix.smem_start = par->metromem_dma;
-	par->metromem_cmd = (struct metromem_cmd *) par->metromem;
-	par->metromem_wfm = par->metromem + cmd_size;
-	par->metromem_img = par->metromem + cmd_size + wfm_size;
-	par->metromem_img_csum = (u16 *) (par->metromem_img +
-					(epd_frame_table[0].fw * DPY_H));
-	DPRINTK("img offset=0x%x\n", cmd_size + wfm_size);
-	par->metromem_desc = (struct metromem_desc *) (par->metromem + cmd_size
-					+ wfm_size + img_size + padding_size);
-	par->metromem_desc_dma = par->metromem_dma + cmd_size + wfm_size
-				 + img_size + padding_size;
 
 	/* load the waveform in. assume mode 3, temp 31 for now
 		a) request the waveform file from userspace
 		b) process waveform and decode into metromem */
 	retval = request_firmware(&fw_entry, "metronome.wbf", &dev->dev);
 	if (retval < 0) {
-		printk(KERN_ERR "metronomefb: couldn't get waveform\n");
-		goto err_dma_free;
+		dev_err(&dev->dev, "Failed to get waveform\n");
+		goto err_csum_table;
 	}
 
-	retval = load_waveform((u8 *) fw_entry->data, fw_entry->size,
-				par->metromem_wfm, 3, 31, &par->frame_count);
+	retval = load_waveform((u8 *) fw_entry->data, fw_entry->size, 3, 31,
+				par);
 	release_firmware(fw_entry);
 	if (retval < 0) {
-		printk(KERN_ERR "metronomefb: couldn't process waveform\n");
-		goto err_dma_free;
+		dev_err(&dev->dev, "Failed processing waveform\n");
+		goto err_csum_table;
 	}
 
 	if (board->setup_irq(info))
-		goto err_dma_free;
+		goto err_csum_table;
 
 	retval = metronome_init_regs(par);
 	if (retval < 0)
@@ -688,8 +707,8 @@
 
 	retval = fb_alloc_cmap(&info->cmap, 8, 0);
 	if (retval < 0) {
-		printk(KERN_ERR "Failed to allocate colormap\n");
-		goto err_fb_rel;
+		dev_err(&dev->dev, "Failed to allocate colormap\n");
+		goto err_free_irq;
 	}
 
 	/* set cmap */
@@ -704,7 +723,7 @@
 
 	platform_set_drvdata(dev, info);
 
-	printk(KERN_INFO
+	dev_dbg(&dev->dev,
 		"fb%d: Metronome frame buffer device, using %dK of video"
 		" memory\n", info->node, videomemorysize >> 10);
 
@@ -712,17 +731,15 @@
 
 err_cmap:
 	fb_dealloc_cmap(&info->cmap);
-err_fb_rel:
-	framebuffer_release(info);
 err_free_irq:
-	board->free_irq(info);
-err_dma_free:
-	dma_free_writecombine(&dev->dev, par->metromemsize, par->metromem,
-				par->metromem_dma);
+	board->cleanup(par);
 err_csum_table:
 	vfree(par->csum_table);
 err_vfree:
 	vfree(videomemory);
+err_fb_rel:
+	framebuffer_release(info);
+err:
 	module_put(board->owner);
 	return retval;
 }
@@ -733,15 +750,15 @@
 
 	if (info) {
 		struct metronomefb_par *par = info->par;
-		fb_deferred_io_cleanup(info);
-		dma_free_writecombine(&dev->dev, par->metromemsize,
-					par->metromem, par->metromem_dma);
-		fb_dealloc_cmap(&info->cmap);
-		vfree(par->csum_table);
+
 		unregister_framebuffer(info);
+		fb_deferred_io_cleanup(info);
+		fb_dealloc_cmap(&info->cmap);
+		par->board->cleanup(par);
+		vfree(par->csum_table);
 		vfree((void __force *)info->screen_base);
-		par->board->free_irq(info);
 		module_put(par->board->owner);
+		dev_dbg(&dev->dev, "calling release\n");
 		framebuffer_release(info);
 	}
 	return 0;
@@ -766,6 +783,9 @@
 	platform_driver_unregister(&metronomefb_driver);
 }
 
+module_param(user_wfm_size, uint, 0);
+MODULE_PARM_DESC(user_wfm_size, "Set custom waveform size");
+
 module_init(metronomefb_init);
 module_exit(metronomefb_exit);
 
diff --git a/drivers/video/p9100.c b/drivers/video/p9100.c
index 9e90345..7000f2c 100644
--- a/drivers/video/p9100.c
+++ b/drivers/video/p9100.c
@@ -349,7 +349,7 @@
 	return 0;
 }
 
-static struct of_device_id p9100_match[] = {
+static const struct of_device_id p9100_match[] = {
 	{
 		.name = "p9100",
 	},
diff --git a/drivers/video/tcx.c b/drivers/video/tcx.c
index 2a03f78..643afbfe 100644
--- a/drivers/video/tcx.c
+++ b/drivers/video/tcx.c
@@ -505,7 +505,7 @@
 	return 0;
 }
 
-static struct of_device_id tcx_match[] = {
+static const struct of_device_id tcx_match[] = {
 	{
 		.name = "SUNW,tcx",
 	},
diff --git a/drivers/video/xen-fbfront.c b/drivers/video/xen-fbfront.c
index 47ed39b..a463b3d 100644
--- a/drivers/video/xen-fbfront.c
+++ b/drivers/video/xen-fbfront.c
@@ -680,11 +680,11 @@
 
 static int __init xenfb_init(void)
 {
-	if (!is_running_on_xen())
+	if (!xen_domain())
 		return -ENODEV;
 
 	/* Nothing to do if running in dom0. */
-	if (is_initial_xendomain())
+	if (xen_initial_domain())
 		return -ENODEV;
 
 	return xenbus_register_frontend(&xenfb);
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index c510367..1a22fe7 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -66,6 +66,13 @@
 	  Watchdog timer embedded into AT91RM9200 chips. This will reboot your
 	  system when the timeout is reached.
 
+config AT91SAM9X_WATCHDOG
+	tristate "AT91SAM9X watchdog"
+	depends on WATCHDOG && (ARCH_AT91SAM9260 || ARCH_AT91SAM9261)
+	help
+	  Watchdog timer embedded into AT91SAM9X chips. This will reboot your
+	  system when the timeout is reached.
+
 config 21285_WATCHDOG
 	tristate "DC21285 watchdog"
 	depends on FOOTBRIDGE
@@ -217,6 +224,15 @@
 	  NOTE: once enabled, this timer cannot be disabled.
 	  Say N if you are unsure.
 
+config ORION5X_WATCHDOG
+	tristate "Orion5x watchdog"
+	depends on ARCH_ORION5X
+	help
+	  Say Y here if to include support for the watchdog timer
+	  in the Orion5x ARM SoCs.
+	  To compile this driver as a module, choose M here: the
+	  module will be called orion5x_wdt.
+
 # ARM26 Architecture
 
 # AVR32 Architecture
@@ -416,6 +432,18 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called it8712f_wdt.
 
+config IT87_WDT
+	tristate "IT87 Watchdog Timer"
+	depends on X86 && EXPERIMENTAL
+	---help---
+	  This is the driver for the hardware watchdog on the ITE IT8716,
+	  IT8718, IT8726, IT8712(Version J,K) Super I/O chips. This watchdog
+	  simply watches your kernel to make sure it doesn't freeze, and if
+	  it does, it reboots your computer after a certain amount of time.
+
+	  To compile this driver as a module, choose M here: the module will
+	  be called it87_wdt.
+
 config HP_WATCHDOG
 	tristate "HP Proliant iLO 2 Hardware Watchdog Timer"
 	depends on X86
@@ -573,6 +601,21 @@
 
 	  Most people will say N.
 
+config W83697UG_WDT
+	tristate "W83697UG/W83697UF Watchdog Timer"
+	depends on X86
+	---help---
+	  This is the driver for the hardware watchdog on the W83697UG/UF
+	  chipset as used in MSI Fuzzy CX700 VIA motherboards (and likely others).
+	  This watchdog simply watches your kernel to make sure it doesn't
+	  freeze, and if it does, it reboots your computer after a certain
+	  amount of time.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called w83697ug_wdt.
+
+	  Most people will say N.
+
 config W83877F_WDT
 	tristate "W83877F (EMACS) Watchdog Timer"
 	depends on X86
diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
index e0ef123..e352bbb 100644
--- a/drivers/watchdog/Makefile
+++ b/drivers/watchdog/Makefile
@@ -26,6 +26,7 @@
 
 # ARM Architecture
 obj-$(CONFIG_AT91RM9200_WATCHDOG) += at91rm9200_wdt.o
+obj-$(CONFIG_AT91SAM9X_WATCHDOG) += at91sam9_wdt.o
 obj-$(CONFIG_OMAP_WATCHDOG) += omap_wdt.o
 obj-$(CONFIG_21285_WATCHDOG) += wdt285.o
 obj-$(CONFIG_977_WATCHDOG) += wdt977.o
@@ -39,6 +40,7 @@
 obj-$(CONFIG_PNX4008_WATCHDOG) += pnx4008_wdt.o
 obj-$(CONFIG_IOP_WATCHDOG) += iop_wdt.o
 obj-$(CONFIG_DAVINCI_WATCHDOG) += davinci_wdt.o
+obj-$(CONFIG_ORION5X_WATCHDOG) += orion5x_wdt.o
 
 # ARM26 Architecture
 
@@ -71,6 +73,7 @@
 obj-$(CONFIG_ITCO_WDT) += iTCO_vendor_support.o
 endif
 obj-$(CONFIG_IT8712F_WDT) += it8712f_wdt.o
+obj-$(CONFIG_IT87_WDT) += it87_wdt.o
 obj-$(CONFIG_HP_WATCHDOG) += hpwdt.o
 obj-$(CONFIG_SC1200_WDT) += sc1200wdt.o
 obj-$(CONFIG_SCx200_WDT) += scx200_wdt.o
@@ -83,6 +86,7 @@
 obj-$(CONFIG_SMSC37B787_WDT) += smsc37b787_wdt.o
 obj-$(CONFIG_W83627HF_WDT) += w83627hf_wdt.o
 obj-$(CONFIG_W83697HF_WDT) += w83697hf_wdt.o
+obj-$(CONFIG_W83697UG_WDT) += w83697ug_wdt.o
 obj-$(CONFIG_W83877F_WDT) += w83877f_wdt.o
 obj-$(CONFIG_W83977F_WDT) += w83977f_wdt.o
 obj-$(CONFIG_MACHZ_WDT) += machzwd.o
@@ -123,6 +127,9 @@
 
 # SPARC64 Architecture
 
+obj-$(CONFIG_WATCHDOG_RIO)		+= riowd.o
+obj-$(CONFIG_WATCHDOG_CP1XXX)		+= cpwd.o
+
 # XTENSA Architecture
 
 # Architecture Independant
diff --git a/drivers/watchdog/at91sam9_wdt.c b/drivers/watchdog/at91sam9_wdt.c
new file mode 100644
index 0000000..b4babfc
--- /dev/null
+++ b/drivers/watchdog/at91sam9_wdt.c
@@ -0,0 +1,328 @@
+/*
+ * Watchdog driver for Atmel AT91SAM9x processors.
+ *
+ * Copyright (C) 2008 Renaud CERRATO r.cerrato@til-technologies.fr
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+/*
+ * The Watchdog Timer Mode Register can be only written to once. If the
+ * timeout need to be set from Linux, be sure that the bootstrap or the
+ * bootloader doesn't write to this register.
+ */
+
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/platform_device.h>
+#include <linux/types.h>
+#include <linux/watchdog.h>
+#include <linux/jiffies.h>
+#include <linux/timer.h>
+#include <linux/bitops.h>
+#include <linux/uaccess.h>
+
+#include <asm/arch/at91_wdt.h>
+
+#define DRV_NAME "AT91SAM9 Watchdog"
+
+/* AT91SAM9 watchdog runs a 12bit counter @ 256Hz,
+ * use this to convert a watchdog
+ * value from/to milliseconds.
+ */
+#define ms_to_ticks(t)	(((t << 8) / 1000) - 1)
+#define ticks_to_ms(t)	(((t + 1) * 1000) >> 8)
+
+/* Hardware timeout in seconds */
+#define WDT_HW_TIMEOUT 2
+
+/* Timer heartbeat (500ms) */
+#define WDT_TIMEOUT	(HZ/2)
+
+/* User land timeout */
+#define WDT_HEARTBEAT 15
+static int heartbeat = WDT_HEARTBEAT;
+module_param(heartbeat, int, 0);
+MODULE_PARM_DESC(heartbeat, "Watchdog heartbeats in seconds. "
+	"(default = " __MODULE_STRING(WDT_HEARTBEAT) ")");
+
+static int nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, int, 0);
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started "
+	"(default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
+
+static void at91_ping(unsigned long data);
+
+static struct {
+	unsigned long next_heartbeat;	/* the next_heartbeat for the timer */
+	unsigned long open;
+	char expect_close;
+	struct timer_list timer;	/* The timer that pings the watchdog */
+} at91wdt_private;
+
+/* ......................................................................... */
+
+
+/*
+ * Reload the watchdog timer.  (ie, pat the watchdog)
+ */
+static inline void at91_wdt_reset(void)
+{
+	at91_sys_write(AT91_WDT_CR, AT91_WDT_KEY | AT91_WDT_WDRSTT);
+}
+
+/*
+ * Timer tick
+ */
+static void at91_ping(unsigned long data)
+{
+	if (time_before(jiffies, at91wdt_private.next_heartbeat) ||
+			(!nowayout && !at91wdt_private.open)) {
+		at91_wdt_reset();
+		mod_timer(&at91wdt_private.timer, jiffies + WDT_TIMEOUT);
+	} else
+		printk(KERN_CRIT DRV_NAME": I will reset your machine !\n");
+}
+
+/*
+ * Watchdog device is opened, and watchdog starts running.
+ */
+static int at91_wdt_open(struct inode *inode, struct file *file)
+{
+	if (test_and_set_bit(0, &at91wdt_private.open))
+		return -EBUSY;
+
+	at91wdt_private.next_heartbeat = jiffies + heartbeat * HZ;
+	mod_timer(&at91wdt_private.timer, jiffies + WDT_TIMEOUT);
+
+	return nonseekable_open(inode, file);
+}
+
+/*
+ * Close the watchdog device.
+ */
+static int at91_wdt_close(struct inode *inode, struct file *file)
+{
+	clear_bit(0, &at91wdt_private.open);
+
+	/* stop internal ping */
+	if (!at91wdt_private.expect_close)
+		del_timer(&at91wdt_private.timer);
+
+	at91wdt_private.expect_close = 0;
+	return 0;
+}
+
+/*
+ * Set the watchdog time interval in 1/256Hz (write-once)
+ * Counter is 12 bit.
+ */
+static int at91_wdt_settimeout(unsigned int timeout)
+{
+	unsigned int reg;
+	unsigned int mr;
+
+	/* Check if disabled */
+	mr = at91_sys_read(AT91_WDT_MR);
+	if (mr & AT91_WDT_WDDIS) {
+		printk(KERN_ERR DRV_NAME": sorry, watchdog is disabled\n");
+		return -EIO;
+	}
+
+	/*
+	 * All counting occurs at SLOW_CLOCK / 128 = 256 Hz
+	 *
+	 * Since WDV is a 12-bit counter, the maximum period is
+	 * 4096 / 256 = 16 seconds.
+	 */
+	reg = AT91_WDT_WDRSTEN	/* causes watchdog reset */
+		/* | AT91_WDT_WDRPROC	causes processor reset only */
+		| AT91_WDT_WDDBGHLT	/* disabled in debug mode */
+		| AT91_WDT_WDD		/* restart at any time */
+		| (timeout & AT91_WDT_WDV);  /* timer value */
+	at91_sys_write(AT91_WDT_MR, reg);
+
+	return 0;
+}
+
+static const struct watchdog_info at91_wdt_info = {
+	.identity	= DRV_NAME,
+	.options	= WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
+};
+
+/*
+ * Handle commands from user-space.
+ */
+static long at91_wdt_ioctl(struct file *file,
+		unsigned int cmd, unsigned long arg)
+{
+	void __user *argp = (void __user *)arg;
+	int __user *p = argp;
+	int new_value;
+
+	switch (cmd) {
+	case WDIOC_GETSUPPORT:
+		return copy_to_user(argp, &at91_wdt_info,
+				    sizeof(at91_wdt_info)) ? -EFAULT : 0;
+
+	case WDIOC_GETSTATUS:
+	case WDIOC_GETBOOTSTATUS:
+		return put_user(0, p);
+
+	case WDIOC_KEEPALIVE:
+		at91wdt_private.next_heartbeat = jiffies + heartbeat * HZ;
+		return 0;
+
+	case WDIOC_SETTIMEOUT:
+		if (get_user(new_value, p))
+			return -EFAULT;
+
+		heartbeat = new_value;
+		at91wdt_private.next_heartbeat = jiffies + heartbeat * HZ;
+
+		return put_user(new_value, p);  /* return current value */
+
+	case WDIOC_GETTIMEOUT:
+		return put_user(heartbeat, p);
+	}
+	return -ENOTTY;
+}
+
+/*
+ * Pat the watchdog whenever device is written to.
+ */
+static ssize_t at91_wdt_write(struct file *file, const char *data, size_t len,
+      loff_t *ppos)
+{
+	if (!len)
+		return 0;
+
+	/* Scan for magic character */
+	if (!nowayout) {
+		size_t i;
+
+		at91wdt_private.expect_close = 0;
+
+		for (i = 0; i < len; i++) {
+			char c;
+			if (get_user(c, data + i))
+				return -EFAULT;
+			if (c == 'V') {
+				at91wdt_private.expect_close = 42;
+				break;
+			}
+		}
+	}
+
+	at91wdt_private.next_heartbeat = jiffies + heartbeat * HZ;
+
+	return len;
+}
+
+/* ......................................................................... */
+
+static const struct file_operations at91wdt_fops = {
+	.owner			= THIS_MODULE,
+	.llseek			= no_llseek,
+	.unlocked_ioctl	= at91_wdt_ioctl,
+	.open			= at91_wdt_open,
+	.release		= at91_wdt_close,
+	.write			= at91_wdt_write,
+};
+
+static struct miscdevice at91wdt_miscdev = {
+	.minor		= WATCHDOG_MINOR,
+	.name		= "watchdog",
+	.fops		= &at91wdt_fops,
+};
+
+static int __init at91wdt_probe(struct platform_device *pdev)
+{
+	int res;
+
+	if (at91wdt_miscdev.parent)
+		return -EBUSY;
+	at91wdt_miscdev.parent = &pdev->dev;
+
+	/* Set watchdog */
+	res = at91_wdt_settimeout(ms_to_ticks(WDT_HW_TIMEOUT * 1000));
+	if (res)
+		return res;
+
+	res = misc_register(&at91wdt_miscdev);
+	if (res)
+		return res;
+
+	at91wdt_private.next_heartbeat = jiffies + heartbeat * HZ;
+	setup_timer(&at91wdt_private.timer, at91_ping, 0);
+	mod_timer(&at91wdt_private.timer, jiffies + WDT_TIMEOUT);
+
+	printk(KERN_INFO DRV_NAME " enabled (heartbeat=%d sec, nowayout=%d)\n",
+		heartbeat, nowayout);
+
+	return 0;
+}
+
+static int __exit at91wdt_remove(struct platform_device *pdev)
+{
+	int res;
+
+	res = misc_deregister(&at91wdt_miscdev);
+	if (!res)
+		at91wdt_miscdev.parent = NULL;
+
+	return res;
+}
+
+#ifdef CONFIG_PM
+
+static int at91wdt_suspend(struct platform_device *pdev, pm_message_t message)
+{
+	return 0;
+}
+
+static int at91wdt_resume(struct platform_device *pdev)
+{
+	return 0;
+}
+
+#else
+#define at91wdt_suspend	NULL
+#define at91wdt_resume	NULL
+#endif
+
+static struct platform_driver at91wdt_driver = {
+	.remove		= __exit_p(at91wdt_remove),
+	.suspend	= at91wdt_suspend,
+	.resume		= at91wdt_resume,
+	.driver		= {
+		.name	= "at91_wdt",
+		.owner	= THIS_MODULE,
+	},
+};
+
+static int __init at91sam_wdt_init(void)
+{
+	return platform_driver_probe(&at91wdt_driver, at91wdt_probe);
+}
+
+static void __exit at91sam_wdt_exit(void)
+{
+	platform_driver_unregister(&at91wdt_driver);
+}
+
+module_init(at91sam_wdt_init);
+module_exit(at91sam_wdt_exit);
+
+MODULE_AUTHOR("Renaud CERRATO <r.cerrato@til-technologies.fr>");
+MODULE_DESCRIPTION("Watchdog driver for Atmel AT91SAM9x processors");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/watchdog/cpwd.c b/drivers/watchdog/cpwd.c
new file mode 100644
index 0000000..084dfe9
--- /dev/null
+++ b/drivers/watchdog/cpwd.c
@@ -0,0 +1,695 @@
+/* cpwd.c - driver implementation for hardware watchdog
+ * timers found on Sun Microsystems CP1400 and CP1500 boards.
+ *
+ * This device supports both the generic Linux watchdog 
+ * interface and Solaris-compatible ioctls as best it is
+ * able.
+ *
+ * NOTE: 	CP1400 systems appear to have a defective intr_mask
+ * 			register on the PLD, preventing the disabling of
+ * 			timer interrupts.  We use a timer to periodically 
+ * 			reset 'stopped' watchdogs on affected platforms.
+ *
+ * Copyright (c) 2000 Eric Brower (ebrower@usa.net)
+ * Copyright (C) 2008 David S. Miller <davem@davemloft.net>
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/errno.h>
+#include <linux/major.h>
+#include <linux/init.h>
+#include <linux/miscdevice.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/timer.h>
+#include <linux/smp_lock.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+
+#include <asm/watchdog.h>
+
+#define DRIVER_NAME	"cpwd"
+#define PFX		DRIVER_NAME ": "
+
+#define WD_OBPNAME	"watchdog"
+#define WD_BADMODEL	"SUNW,501-5336"
+#define WD_BTIMEOUT	(jiffies + (HZ * 1000))
+#define WD_BLIMIT	0xFFFF
+
+#define WD0_MINOR	212
+#define WD1_MINOR	213	
+#define WD2_MINOR	214	
+
+/* Internal driver definitions.  */
+#define WD0_ID			0
+#define WD1_ID			1
+#define WD2_ID			2
+#define WD_NUMDEVS		3
+
+#define WD_INTR_OFF		0
+#define WD_INTR_ON		1
+
+#define WD_STAT_INIT	0x01	/* Watchdog timer is initialized	*/
+#define WD_STAT_BSTOP	0x02	/* Watchdog timer is brokenstopped	*/
+#define WD_STAT_SVCD	0x04	/* Watchdog interrupt occurred		*/
+
+/* Register value definitions
+ */
+#define WD0_INTR_MASK	0x01	/* Watchdog device interrupt masks	*/
+#define WD1_INTR_MASK	0x02
+#define WD2_INTR_MASK	0x04
+
+#define WD_S_RUNNING	0x01	/* Watchdog device status running	*/
+#define WD_S_EXPIRED	0x02	/* Watchdog device status expired	*/
+
+struct cpwd {
+	void __iomem	*regs;
+	spinlock_t	lock;
+
+	unsigned int	irq;
+
+	unsigned long	timeout;
+	bool		enabled;
+	bool		reboot;
+	bool		broken;
+	bool		initialized;
+
+	struct {
+		struct miscdevice	misc;
+		void __iomem		*regs;
+		u8			intr_mask;
+		u8			runstatus;
+		u16			timeout;
+	} devs[WD_NUMDEVS];
+};
+
+static struct cpwd *cpwd_device;
+
+/* Sun uses Altera PLD EPF8820ATC144-4 
+ * providing three hardware watchdogs:
+ *
+ * 	1) RIC - sends an interrupt when triggered
+ * 	2) XIR - asserts XIR_B_RESET when triggered, resets CPU
+ * 	3) POR - asserts POR_B_RESET when triggered, resets CPU, backplane, board
+ *
+ *** Timer register block definition (struct wd_timer_regblk)
+ *
+ * dcntr and limit registers (halfword access):      
+ * -------------------
+ * | 15 | ...| 1 | 0 |
+ * -------------------
+ * |-  counter val  -|
+ * -------------------
+ * dcntr - 	Current 16-bit downcounter value.
+ * 			When downcounter reaches '0' watchdog expires.
+ * 			Reading this register resets downcounter with 'limit' value.
+ * limit - 	16-bit countdown value in 1/10th second increments.
+ * 			Writing this register begins countdown with input value.
+ * 			Reading from this register does not affect counter.
+ * NOTES:	After watchdog reset, dcntr and limit contain '1'
+ *
+ * status register (byte access):
+ * ---------------------------
+ * | 7 | ... | 2 |  1  |  0  |
+ * --------------+------------
+ * |-   UNUSED  -| EXP | RUN |
+ * ---------------------------
+ * status-	Bit 0 - Watchdog is running
+ * 			Bit 1 - Watchdog has expired
+ *
+ *** PLD register block definition (struct wd_pld_regblk)
+ *
+ * intr_mask register (byte access):
+ * ---------------------------------
+ * | 7 | ... | 3 |  2  |  1  |  0  |
+ * +-------------+------------------
+ * |-   UNUSED  -| WD3 | WD2 | WD1 |
+ * ---------------------------------
+ * WD3 -  1 == Interrupt disabled for watchdog 3
+ * WD2 -  1 == Interrupt disabled for watchdog 2
+ * WD1 -  1 == Interrupt disabled for watchdog 1
+ *
+ * pld_status register (byte access):
+ * UNKNOWN, MAGICAL MYSTERY REGISTER
+ *
+ */
+#define WD_TIMER_REGSZ	16
+#define WD0_OFF		0
+#define WD1_OFF		(WD_TIMER_REGSZ * 1)
+#define WD2_OFF		(WD_TIMER_REGSZ * 2)
+#define PLD_OFF		(WD_TIMER_REGSZ * 3)
+
+#define WD_DCNTR	0x00
+#define WD_LIMIT	0x04
+#define WD_STATUS	0x08
+
+#define PLD_IMASK	(PLD_OFF + 0x00)
+#define PLD_STATUS	(PLD_OFF + 0x04)
+
+static struct timer_list cpwd_timer;
+
+static int wd0_timeout = 0;
+static int wd1_timeout = 0;
+static int wd2_timeout = 0;
+
+module_param	(wd0_timeout, int, 0);
+MODULE_PARM_DESC(wd0_timeout, "Default watchdog0 timeout in 1/10secs");
+module_param 	(wd1_timeout, int, 0);
+MODULE_PARM_DESC(wd1_timeout, "Default watchdog1 timeout in 1/10secs");
+module_param 	(wd2_timeout, int, 0);
+MODULE_PARM_DESC(wd2_timeout, "Default watchdog2 timeout in 1/10secs");
+
+MODULE_AUTHOR("Eric Brower <ebrower@usa.net>");
+MODULE_DESCRIPTION("Hardware watchdog driver for Sun Microsystems CP1400/1500");
+MODULE_LICENSE("GPL");
+MODULE_SUPPORTED_DEVICE("watchdog");
+
+static void cpwd_writew(u16 val, void __iomem *addr)
+{
+	writew(cpu_to_le16(val), addr);
+}
+static u16 cpwd_readw(void __iomem *addr)
+{
+	u16 val = readw(addr);
+
+	return le16_to_cpu(val);
+}
+
+static void cpwd_writeb(u8 val, void __iomem *addr)
+{
+	writeb(val, addr);
+}
+
+static u8 cpwd_readb(void __iomem *addr)
+{
+	return readb(addr);
+}
+
+/* Enable or disable watchdog interrupts
+ * Because of the CP1400 defect this should only be
+ * called during initialzation or by wd_[start|stop]timer()
+ *
+ * index 	- sub-device index, or -1 for 'all'
+ * enable	- non-zero to enable interrupts, zero to disable
+ */
+static void cpwd_toggleintr(struct cpwd *p, int index, int enable)
+{
+	unsigned char curregs = cpwd_readb(p->regs + PLD_IMASK);
+	unsigned char setregs = 
+		(index == -1) ? 
+		(WD0_INTR_MASK | WD1_INTR_MASK | WD2_INTR_MASK) : 
+		(p->devs[index].intr_mask);
+
+	if (enable == WD_INTR_ON)
+		curregs &= ~setregs;
+	else
+		curregs |= setregs;
+
+	cpwd_writeb(curregs, p->regs + PLD_IMASK);
+}
+
+/* Restarts timer with maximum limit value and
+ * does not unset 'brokenstop' value.
+ */
+static void cpwd_resetbrokentimer(struct cpwd *p, int index)
+{
+	cpwd_toggleintr(p, index, WD_INTR_ON);
+	cpwd_writew(WD_BLIMIT, p->devs[index].regs + WD_LIMIT);
+}
+
+/* Timer method called to reset stopped watchdogs--
+ * because of the PLD bug on CP1400, we cannot mask
+ * interrupts within the PLD so me must continually
+ * reset the timers ad infinitum.
+ */
+static void cpwd_brokentimer(unsigned long data)
+{
+	struct cpwd *p = (struct cpwd *) data;
+	int id, tripped = 0;
+
+	/* kill a running timer instance, in case we
+	 * were called directly instead of by kernel timer
+	 */
+	if (timer_pending(&cpwd_timer))
+		del_timer(&cpwd_timer);
+
+	for (id = 0; id < WD_NUMDEVS; id++) {
+		if (p->devs[id].runstatus & WD_STAT_BSTOP) {
+			++tripped;
+			cpwd_resetbrokentimer(p, id);
+		}
+	}
+
+	if (tripped) {
+		/* there is at least one timer brokenstopped-- reschedule */
+		cpwd_timer.expires = WD_BTIMEOUT;
+		add_timer(&cpwd_timer);
+	}
+}
+
+/* Reset countdown timer with 'limit' value and continue countdown.
+ * This will not start a stopped timer.
+ */
+static void cpwd_pingtimer(struct cpwd *p, int index)
+{
+	if (cpwd_readb(p->devs[index].regs + WD_STATUS) & WD_S_RUNNING)
+		cpwd_readw(p->devs[index].regs + WD_DCNTR);
+}
+
+/* Stop a running watchdog timer-- the timer actually keeps
+ * running, but the interrupt is masked so that no action is
+ * taken upon expiration.
+ */
+static void cpwd_stoptimer(struct cpwd *p, int index)
+{
+	if (cpwd_readb(p->devs[index].regs + WD_STATUS) & WD_S_RUNNING) {
+		cpwd_toggleintr(p, index, WD_INTR_OFF);
+
+		if (p->broken) {
+			p->devs[index].runstatus |= WD_STAT_BSTOP;
+			cpwd_brokentimer((unsigned long) p);
+		}
+	}
+}
+
+/* Start a watchdog timer with the specified limit value
+ * If the watchdog is running, it will be restarted with
+ * the provided limit value.
+ *
+ * This function will enable interrupts on the specified
+ * watchdog.
+ */
+static void cpwd_starttimer(struct cpwd *p, int index)
+{
+	if (p->broken)
+		p->devs[index].runstatus &= ~WD_STAT_BSTOP;
+
+	p->devs[index].runstatus &= ~WD_STAT_SVCD;
+
+	cpwd_writew(p->devs[index].timeout, p->devs[index].regs + WD_LIMIT);
+	cpwd_toggleintr(p, index, WD_INTR_ON);
+}
+
+static int cpwd_getstatus(struct cpwd *p, int index)
+{
+	unsigned char stat = cpwd_readb(p->devs[index].regs + WD_STATUS);
+	unsigned char intr = cpwd_readb(p->devs[index].regs + PLD_IMASK);
+	unsigned char ret  = WD_STOPPED;
+
+	/* determine STOPPED */
+	if (!stat) 
+		return ret;
+
+	/* determine EXPIRED vs FREERUN vs RUNNING */
+	else if (WD_S_EXPIRED & stat) {
+		ret = WD_EXPIRED;
+	} else if(WD_S_RUNNING & stat) {
+		if (intr & p->devs[index].intr_mask) {
+			ret = WD_FREERUN;
+		} else {
+			/* Fudge WD_EXPIRED status for defective CP1400--
+			 * IF timer is running 
+			 * 	AND brokenstop is set 
+			 * 	AND an interrupt has been serviced
+			 * we are WD_EXPIRED.
+			 *
+			 * IF timer is running 
+			 * 	AND brokenstop is set 
+			 * 	AND no interrupt has been serviced
+			 * we are WD_FREERUN.
+			 */
+			if (p->broken &&
+			    (p->devs[index].runstatus & WD_STAT_BSTOP)) {
+				if (p->devs[index].runstatus & WD_STAT_SVCD) {
+					ret = WD_EXPIRED;
+				} else {
+					/* we could as well pretend we are expired */
+					ret = WD_FREERUN;
+				}
+			} else {
+				ret = WD_RUNNING;
+			}
+		}
+	}
+
+	/* determine SERVICED */
+	if (p->devs[index].runstatus & WD_STAT_SVCD)
+		ret |= WD_SERVICED;
+
+	return(ret);
+}
+
+static irqreturn_t cpwd_interrupt(int irq, void *dev_id)
+{
+	struct cpwd *p = dev_id;
+
+	/* Only WD0 will interrupt-- others are NMI and we won't
+	 * see them here....
+	 */
+	spin_lock_irq(&p->lock);
+
+	cpwd_stoptimer(p, WD0_ID);
+	p->devs[WD0_ID].runstatus |=  WD_STAT_SVCD;
+
+	spin_unlock_irq(&p->lock);
+
+	return IRQ_HANDLED;
+}
+
+static int cpwd_open(struct inode *inode, struct file *f)
+{
+	struct cpwd *p = cpwd_device;
+
+	lock_kernel();
+	switch(iminor(inode)) {
+		case WD0_MINOR:
+		case WD1_MINOR:
+		case WD2_MINOR:
+			break;
+
+		default:
+			unlock_kernel();
+			return -ENODEV;
+	}
+
+	/* Register IRQ on first open of device */
+	if (!p->initialized) {
+		if (request_irq(p->irq, &cpwd_interrupt, 
+				IRQF_SHARED, DRIVER_NAME, p)) {
+			printk(KERN_ERR PFX "Cannot register IRQ %d\n", 
+				p->irq);
+			unlock_kernel();
+			return -EBUSY;
+		}
+		p->initialized = true;
+	}
+
+	unlock_kernel();
+
+	return nonseekable_open(inode, f);
+}
+
+static int cpwd_release(struct inode *inode, struct file *file)
+{
+	return 0;
+}
+
+static int cpwd_ioctl(struct inode *inode, struct file *file, 
+		      unsigned int cmd, unsigned long arg)
+{
+	static struct watchdog_info info = {
+		.options		= WDIOF_SETTIMEOUT,
+		.firmware_version	= 1,
+		.identity		= DRIVER_NAME,
+	};
+	void __user *argp = (void __user *)arg;
+	int index = iminor(inode) - WD0_MINOR;
+	struct cpwd *p = cpwd_device;
+	int setopt = 0;
+
+	switch (cmd) {
+	/* Generic Linux IOCTLs */
+	case WDIOC_GETSUPPORT:
+		if (copy_to_user(argp, &info, sizeof(struct watchdog_info)))
+			return -EFAULT;
+		break;
+
+	case WDIOC_GETSTATUS:
+	case WDIOC_GETBOOTSTATUS:
+		if (put_user(0, (int __user *)argp))
+			return -EFAULT;
+		break;
+
+	case WDIOC_KEEPALIVE:
+		cpwd_pingtimer(p, index);
+		break;
+
+	case WDIOC_SETOPTIONS:
+		if (copy_from_user(&setopt, argp, sizeof(unsigned int)))
+			return -EFAULT;
+
+		if (setopt & WDIOS_DISABLECARD) {
+			if (p->enabled)
+				return -EINVAL;
+			cpwd_stoptimer(p, index);
+		} else if (setopt & WDIOS_ENABLECARD) {
+			cpwd_starttimer(p, index);
+		} else {
+			return -EINVAL;
+		}	
+		break;
+
+	/* Solaris-compatible IOCTLs */
+	case WIOCGSTAT:
+		setopt = cpwd_getstatus(p, index);
+		if (copy_to_user(argp, &setopt, sizeof(unsigned int)))
+			return -EFAULT;
+		break;
+
+	case WIOCSTART:
+		cpwd_starttimer(p, index);
+		break;
+
+	case WIOCSTOP:
+		if (p->enabled)
+			return(-EINVAL);
+
+		cpwd_stoptimer(p, index);
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static long cpwd_compat_ioctl(struct file *file, unsigned int cmd,
+			      unsigned long arg)
+{
+	int rval = -ENOIOCTLCMD;
+
+	switch (cmd) {
+	/* solaris ioctls are specific to this driver */
+	case WIOCSTART:
+	case WIOCSTOP:
+	case WIOCGSTAT:
+		lock_kernel();
+		rval = cpwd_ioctl(file->f_path.dentry->d_inode, file, cmd, arg);
+		unlock_kernel();
+		break;
+
+	/* everything else is handled by the generic compat layer */
+	default:
+		break;
+	}
+
+	return rval;
+}
+
+static ssize_t cpwd_write(struct file *file, const char __user *buf, 
+			  size_t count, loff_t *ppos)
+{
+	struct inode *inode = file->f_path.dentry->d_inode;
+	struct cpwd *p = cpwd_device;
+	int index = iminor(inode);
+
+	if (count) {
+		cpwd_pingtimer(p, index);
+		return 1;
+	}
+
+	return 0;
+}
+
+static ssize_t cpwd_read(struct file * file, char __user *buffer,
+			 size_t count, loff_t *ppos)
+{
+	return -EINVAL;
+}
+
+static const struct file_operations cpwd_fops = {
+	.owner =	THIS_MODULE,
+	.ioctl =	cpwd_ioctl,
+	.compat_ioctl =	cpwd_compat_ioctl,
+	.open =		cpwd_open,
+	.write =	cpwd_write,
+	.read =		cpwd_read,
+	.release =	cpwd_release,
+};
+
+static int __devinit cpwd_probe(struct of_device *op,
+				const struct of_device_id *match)
+{
+	struct device_node *options;
+	const char *str_prop;
+	const void *prop_val;
+	int i, err = -EINVAL;
+	struct cpwd *p;
+
+	if (cpwd_device)
+		return -EINVAL;
+
+	p = kzalloc(sizeof(*p), GFP_KERNEL);
+	err = -ENOMEM;
+	if (!p) {
+		printk(KERN_ERR PFX "Unable to allocate struct cpwd.\n");
+		goto out;
+	}
+
+	p->irq = op->irqs[0];
+
+	spin_lock_init(&p->lock);
+
+	p->regs = of_ioremap(&op->resource[0], 0,
+			     4 * WD_TIMER_REGSZ, DRIVER_NAME);
+	if (!p->regs) {
+		printk(KERN_ERR PFX "Unable to map registers.\n");
+		goto out_free;
+	}
+
+	options = of_find_node_by_path("/options");
+	err = -ENODEV;
+	if (!options) {
+		printk(KERN_ERR PFX "Unable to find /options node.\n");
+		goto out_iounmap;
+	}
+
+	prop_val = of_get_property(options, "watchdog-enable?", NULL);
+	p->enabled = (prop_val ? true : false);
+
+	prop_val = of_get_property(options, "watchdog-reboot?", NULL);
+	p->reboot = (prop_val ? true : false);
+
+	str_prop = of_get_property(options, "watchdog-timeout", NULL);
+	if (str_prop)
+		p->timeout = simple_strtoul(str_prop, NULL, 10);
+
+	/* CP1400s seem to have broken PLD implementations-- the
+	 * interrupt_mask register cannot be written, so no timer
+	 * interrupts can be masked within the PLD.
+	 */
+	str_prop = of_get_property(op->node, "model", NULL);
+	p->broken = (str_prop && !strcmp(str_prop, WD_BADMODEL));
+
+	if (!p->enabled)
+		cpwd_toggleintr(p, -1, WD_INTR_OFF);
+
+	for (i = 0; i < WD_NUMDEVS; i++) {
+		static const char *cpwd_names[] = { "RIC", "XIR", "POR" };
+		static int *parms[] = { &wd0_timeout,
+					&wd1_timeout,
+					&wd2_timeout };
+		struct miscdevice *mp = &p->devs[i].misc;
+
+		mp->minor = WD0_MINOR + i;
+		mp->name = cpwd_names[i];
+		mp->fops = &cpwd_fops;
+
+		p->devs[i].regs = p->regs + (i * WD_TIMER_REGSZ);
+		p->devs[i].intr_mask = (WD0_INTR_MASK << i);
+		p->devs[i].runstatus &= ~WD_STAT_BSTOP;
+		p->devs[i].runstatus |= WD_STAT_INIT;
+		p->devs[i].timeout = p->timeout;
+		if (*parms[i])
+			p->devs[i].timeout = *parms[i];
+
+		err = misc_register(&p->devs[i].misc);
+		if (err) {
+			printk(KERN_ERR "Could not register misc device for "
+			       "dev %d\n", i);
+			goto out_unregister;
+		}
+	}
+
+	if (p->broken) {
+		init_timer(&cpwd_timer);
+		cpwd_timer.function 	= cpwd_brokentimer;
+		cpwd_timer.data		= (unsigned long) p;
+		cpwd_timer.expires	= WD_BTIMEOUT;
+
+		printk(KERN_INFO PFX "PLD defect workaround enabled for "
+		       "model " WD_BADMODEL ".\n");
+	}
+
+	dev_set_drvdata(&op->dev, p);
+	cpwd_device = p;
+	err = 0;
+
+out:
+	return err;
+
+out_unregister:
+	for (i--; i >= 0; i--)
+		misc_deregister(&p->devs[i].misc);
+
+out_iounmap:
+	of_iounmap(&op->resource[0], p->regs, 4 * WD_TIMER_REGSZ);
+
+out_free:
+	kfree(p);
+	goto out;
+}
+
+static int __devexit cpwd_remove(struct of_device *op)
+{
+	struct cpwd *p = dev_get_drvdata(&op->dev);
+	int i;
+
+	for (i = 0; i < 4; i++) {
+		misc_deregister(&p->devs[i].misc);
+
+		if (!p->enabled) {
+			cpwd_stoptimer(p, i);
+			if (p->devs[i].runstatus & WD_STAT_BSTOP)
+				cpwd_resetbrokentimer(p, i);
+		}
+	}
+
+	if (p->broken)
+		del_timer_sync(&cpwd_timer);
+
+	if (p->initialized)
+		free_irq(p->irq, p);
+
+	of_iounmap(&op->resource[0], p->regs, 4 * WD_TIMER_REGSZ);
+	kfree(p);
+
+	cpwd_device = NULL;
+
+	return 0;
+}
+
+static const struct of_device_id cpwd_match[] = {
+	{
+		.name = "watchdog",
+	},
+	{},
+};
+MODULE_DEVICE_TABLE(of, cpwd_match);
+
+static struct of_platform_driver cpwd_driver = {
+	.name		= DRIVER_NAME,
+	.match_table	= cpwd_match,
+	.probe		= cpwd_probe,
+	.remove		= __devexit_p(cpwd_remove),
+};
+
+static int __init cpwd_init(void)
+{
+	return of_register_driver(&cpwd_driver, &of_bus_type);
+}
+
+static void __exit cpwd_exit(void)
+{
+	of_unregister_driver(&cpwd_driver);
+}
+
+module_init(cpwd_init);
+module_exit(cpwd_exit);
diff --git a/drivers/watchdog/geodewdt.c b/drivers/watchdog/geodewdt.c
index 614a5c7..6799a6d 100644
--- a/drivers/watchdog/geodewdt.c
+++ b/drivers/watchdog/geodewdt.c
@@ -130,8 +130,8 @@
 	return len;
 }
 
-static int geodewdt_ioctl(struct inode *inode, struct file *file,
-				unsigned int cmd, unsigned long arg)
+static long geodewdt_ioctl(struct file *file, unsigned int cmd,
+				unsigned long arg)
 {
 	void __user *argp = (void __user *)arg;
 	int __user *p = argp;
@@ -198,7 +198,7 @@
 	.owner          = THIS_MODULE,
 	.llseek         = no_llseek,
 	.write          = geodewdt_write,
-	.ioctl          = geodewdt_ioctl,
+	.unlocked_ioctl = geodewdt_ioctl,
 	.open           = geodewdt_open,
 	.release        = geodewdt_release,
 };
diff --git a/drivers/watchdog/ibmasr.c b/drivers/watchdog/ibmasr.c
index b82405c..89fcefc 100644
--- a/drivers/watchdog/ibmasr.c
+++ b/drivers/watchdog/ibmasr.c
@@ -85,7 +85,6 @@
 
 	outb(reg & ~asr_toggle_mask, asr_write_addr);
 	reg = inb(asr_read_addr);
-	spin_unlock(&asr_lock);
 }
 
 static void asr_toggle(void)
diff --git a/drivers/watchdog/it87_wdt.c b/drivers/watchdog/it87_wdt.c
new file mode 100644
index 0000000..afb8af3
--- /dev/null
+++ b/drivers/watchdog/it87_wdt.c
@@ -0,0 +1,725 @@
+/*
+ *	Watchdog Timer Driver
+ *	   for ITE IT87xx Environment Control - Low Pin Count Input / Output
+ *
+ *	(c) Copyright 2007  Oliver Schuster <olivers137@aol.com>
+ *
+ *	Based on softdog.c	by Alan Cox,
+ *		 83977f_wdt.c	by Jose Goncalves,
+ *		 it87.c		by Chris Gauthron, Jean Delvare
+ *
+ *	Data-sheets: Publicly available at the ITE website
+ *		    http://www.ite.com.tw/
+ *
+ *	Support of the watchdog timers, which are available on
+ *	IT8716, IT8718, IT8726 and IT8712 (J,K 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.
+ *
+ *	This program is distributed in the hope that it will be useful,
+ *	but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *	GNU General Public License for more details.
+ *
+ *	You should have received a copy of the GNU General Public License
+ *	along with this program; if not, write to the Free Software
+ *	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/watchdog.h>
+#include <linux/notifier.h>
+#include <linux/reboot.h>
+#include <linux/uaccess.h>
+#include <linux/io.h>
+
+#include <asm/system.h>
+
+#define WATCHDOG_VERSION	"1.12"
+#define WATCHDOG_NAME		"IT87 WDT"
+#define PFX			WATCHDOG_NAME ": "
+#define DRIVER_VERSION		WATCHDOG_NAME " driver, v" WATCHDOG_VERSION "\n"
+#define WD_MAGIC		'V'
+
+/* Defaults for Module Parameter */
+#define DEFAULT_NOGAMEPORT	0
+#define DEFAULT_EXCLUSIVE	1
+#define DEFAULT_TIMEOUT 	60
+#define DEFAULT_TESTMODE	0
+#define DEFAULT_NOWAYOUT	WATCHDOG_NOWAYOUT
+
+/* IO Ports */
+#define REG		0x2e
+#define VAL		0x2f
+
+/* Logical device Numbers LDN */
+#define GPIO		0x07
+#define GAMEPORT	0x09
+#define CIR		0x0a
+
+/* Configuration Registers and Functions */
+#define LDNREG		0x07
+#define CHIPID		0x20
+#define CHIPREV 	0x22
+#define ACTREG		0x30
+#define BASEREG 	0x60
+
+/* Chip Id numbers */
+#define NO_DEV_ID	0xffff
+#define IT8705_ID	0x8705
+#define IT8712_ID	0x8712
+#define IT8716_ID	0x8716
+#define IT8718_ID	0x8718
+#define IT8726_ID	0x8726	/* the data sheet suggest wrongly 0x8716 */
+
+/* GPIO Configuration Registers LDN=0x07 */
+#define WDTCTRL 	0x71
+#define WDTCFG		0x72
+#define WDTVALLSB	0x73
+#define WDTVALMSB	0x74
+
+/* GPIO Bits WDTCTRL */
+#define WDT_CIRINT	0x80
+#define WDT_MOUSEINT	0x40
+#define WDT_KYBINT	0x20
+#define WDT_GAMEPORT	0x10 /* not it8718 */
+#define WDT_FORCE	0x02
+#define WDT_ZERO	0x01
+
+/* GPIO Bits WDTCFG */
+#define WDT_TOV1	0x80
+#define WDT_KRST	0x40
+#define WDT_TOVE	0x20
+#define WDT_PWROK	0x10
+#define WDT_INT_MASK	0x0f
+
+/* CIR Configuration Register LDN=0x0a */
+#define CIR_ILS 	0x70
+
+/* The default Base address is not always available, we use this */
+#define CIR_BASE	0x0208
+
+/* CIR Controller */
+#define CIR_DR(b)	(b)
+#define CIR_IER(b)	(b + 1)
+#define CIR_RCR(b)	(b + 2)
+#define CIR_TCR1(b)	(b + 3)
+#define CIR_TCR2(b)	(b + 4)
+#define CIR_TSR(b)	(b + 5)
+#define CIR_RSR(b)	(b + 6)
+#define CIR_BDLR(b)	(b + 5)
+#define CIR_BDHR(b)	(b + 6)
+#define CIR_IIR(b)	(b + 7)
+
+/* Default Base address of Game port */
+#define GP_BASE_DEFAULT	0x0201
+
+/* wdt_status */
+#define WDTS_TIMER_RUN	0
+#define WDTS_DEV_OPEN	1
+#define WDTS_KEEPALIVE	2
+#define WDTS_LOCKED	3
+#define WDTS_USE_GP	4
+#define WDTS_EXPECTED	5
+
+static	unsigned int base, gpact, ciract;
+static	unsigned long wdt_status;
+static	DEFINE_SPINLOCK(spinlock);
+
+static	int nogameport = DEFAULT_NOGAMEPORT;
+static	int exclusive  = DEFAULT_EXCLUSIVE;
+static	int timeout    = DEFAULT_TIMEOUT;
+static	int testmode   = DEFAULT_TESTMODE;
+static	int nowayout   = DEFAULT_NOWAYOUT;
+
+module_param(nogameport, int, 0);
+MODULE_PARM_DESC(nogameport, "Forbid the activation of game port, default="
+		__MODULE_STRING(DEFAULT_NOGAMEPORT));
+module_param(exclusive, int, 0);
+MODULE_PARM_DESC(exclusive, "Watchdog exclusive device open, default="
+		__MODULE_STRING(DEFAULT_EXCLUSIVE));
+module_param(timeout, int, 0);
+MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds, default="
+		__MODULE_STRING(DEFAULT_TIMEOUT));
+module_param(testmode, int, 0);
+MODULE_PARM_DESC(testmode, "Watchdog test mode (1 = no reboot), default="
+		__MODULE_STRING(DEFAULT_TESTMODE));
+module_param(nowayout, int, 0);
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started, default="
+		__MODULE_STRING(WATCHDOG_NOWAYOUT));
+
+/* Superio Chip */
+
+static inline void superio_enter(void)
+{
+	outb(0x87, REG);
+	outb(0x01, REG);
+	outb(0x55, REG);
+	outb(0x55, REG);
+}
+
+static inline void superio_exit(void)
+{
+	outb(0x02, REG);
+	outb(0x02, VAL);
+}
+
+static inline void superio_select(int ldn)
+{
+	outb(LDNREG, REG);
+	outb(ldn, VAL);
+}
+
+static inline int superio_inb(int reg)
+{
+	outb(reg, REG);
+	return inb(VAL);
+}
+
+static inline void superio_outb(int val, int reg)
+{
+       outb(reg, REG);
+       outb(val, VAL);
+}
+
+static inline int superio_inw(int reg)
+{
+	int val;
+	outb(reg++, REG);
+	val = inb(VAL) << 8;
+	outb(reg, REG);
+	val |= inb(VAL);
+	return val;
+}
+
+static inline void superio_outw(int val, int reg)
+{
+       outb(reg++, REG);
+       outb(val >> 8, VAL);
+       outb(reg, REG);
+       outb(val, VAL);
+}
+
+/* watchdog timer handling */
+
+static void wdt_keepalive(void)
+{
+	if (test_bit(WDTS_USE_GP, &wdt_status))
+		inb(base);
+	else
+		/* The timer reloads with around 5 msec delay */
+		outb(0x55, CIR_DR(base));
+	set_bit(WDTS_KEEPALIVE, &wdt_status);
+}
+
+static void wdt_start(void)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&spinlock, flags);
+	superio_enter();
+
+	superio_select(GPIO);
+	if (test_bit(WDTS_USE_GP, &wdt_status))
+		superio_outb(WDT_GAMEPORT, WDTCTRL);
+	else
+		superio_outb(WDT_CIRINT, WDTCTRL);
+	if (!testmode)
+		superio_outb(WDT_TOV1 | WDT_KRST | WDT_PWROK, WDTCFG);
+	else
+		superio_outb(WDT_TOV1, WDTCFG);
+	superio_outb(timeout>>8, WDTVALMSB);
+	superio_outb(timeout, WDTVALLSB);
+
+	superio_exit();
+	spin_unlock_irqrestore(&spinlock, flags);
+}
+
+static void wdt_stop(void)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&spinlock, flags);
+	superio_enter();
+
+	superio_select(GPIO);
+	superio_outb(0x00, WDTCTRL);
+	superio_outb(WDT_TOV1, WDTCFG);
+	superio_outb(0x00, WDTVALMSB);
+	superio_outb(0x00, WDTVALLSB);
+
+	superio_exit();
+	spin_unlock_irqrestore(&spinlock, flags);
+}
+
+/**
+ *	wdt_set_timeout - set a new timeout value with watchdog ioctl
+ *	@t: timeout value in seconds
+ *
+ *	The hardware device has a 16 bit watchdog timer, thus the
+ *	timeout time ranges between 1 and 65535 seconds.
+ *
+ *	Used within WDIOC_SETTIMEOUT watchdog device ioctl.
+ */
+
+static int wdt_set_timeout(int t)
+{
+	unsigned long flags;
+
+	if (t < 1 || t > 65535)
+		return -EINVAL;
+
+	timeout = t;
+
+	spin_lock_irqsave(&spinlock, flags);
+	if (test_bit(WDTS_TIMER_RUN, &wdt_status)) {
+		superio_enter();
+
+		superio_select(GPIO);
+		superio_outb(t>>8, WDTVALMSB);
+		superio_outb(t, WDTVALLSB);
+
+		superio_exit();
+	}
+	spin_unlock_irqrestore(&spinlock, flags);
+	return 0;
+}
+
+/**
+ *	wdt_get_status - determines the status supported by watchdog ioctl
+ *	@status: status returned to user space
+ *
+ *	The status bit of the device does not allow to distinguish
+ *	between a regular system reset and a watchdog forced reset.
+ *	But, in test mode it is useful, so it is supported through
+ *	WDIOC_GETSTATUS watchdog ioctl. Additionally the driver
+ *	reports the keepalive signal and the acception of the magic.
+ *
+ *	Used within WDIOC_GETSTATUS watchdog device ioctl.
+ */
+
+static int wdt_get_status(int *status)
+{
+	unsigned long flags;
+
+	*status = 0;
+	if (testmode) {
+		spin_lock_irqsave(&spinlock, flags);
+		superio_enter();
+		superio_select(GPIO);
+		if (superio_inb(WDTCTRL) & WDT_ZERO) {
+			superio_outb(0x00, WDTCTRL);
+			clear_bit(WDTS_TIMER_RUN, &wdt_status);
+			*status |= WDIOF_CARDRESET;
+		}
+
+		superio_exit();
+		spin_unlock_irqrestore(&spinlock, flags);
+	}
+	if (test_and_clear_bit(WDTS_KEEPALIVE, &wdt_status))
+		*status |= WDIOF_KEEPALIVEPING;
+	if (test_bit(WDTS_EXPECTED, &wdt_status))
+		*status |= WDIOF_MAGICCLOSE;
+	return 0;
+}
+
+/* /dev/watchdog handling */
+
+/**
+ *	wdt_open - watchdog file_operations .open
+ *	@inode: inode of the device
+ *	@file: file handle to the device
+ *
+ *	The watchdog timer starts by opening the device.
+ *
+ *	Used within the file operation of the watchdog device.
+ */
+
+static int wdt_open(struct inode *inode, struct file *file)
+{
+	if (exclusive && test_and_set_bit(WDTS_DEV_OPEN, &wdt_status))
+		return -EBUSY;
+	if (!test_and_set_bit(WDTS_TIMER_RUN, &wdt_status)) {
+		if (nowayout && !test_and_set_bit(WDTS_LOCKED, &wdt_status))
+			__module_get(THIS_MODULE);
+		wdt_start();
+	}
+	return nonseekable_open(inode, file);
+}
+
+/**
+ *	wdt_release - watchdog file_operations .release
+ *	@inode: inode of the device
+ *	@file: file handle to the device
+ *
+ *	Closing the watchdog device either stops the watchdog timer
+ *	or in the case, that nowayout is set or the magic character
+ *	wasn't written, a critical warning about an running watchdog
+ *	timer is given.
+ *
+ *	Used within the file operation of the watchdog device.
+ */
+
+static int wdt_release(struct inode *inode, struct file *file)
+{
+	if (test_bit(WDTS_TIMER_RUN, &wdt_status)) {
+		if (test_and_clear_bit(WDTS_EXPECTED, &wdt_status)) {
+			wdt_stop();
+			clear_bit(WDTS_TIMER_RUN, &wdt_status);
+		} else {
+			wdt_keepalive();
+			printk(KERN_CRIT PFX
+			       "unexpected close, not stopping watchdog!\n");
+		}
+	}
+	clear_bit(WDTS_DEV_OPEN, &wdt_status);
+	return 0;
+}
+
+/**
+ *	wdt_write - watchdog file_operations .write
+ *	@file: file handle to the watchdog
+ *	@buf: buffer to write
+ *	@count: count of bytes
+ *	@ppos: pointer to the position to write. No seeks allowed
+ *
+ *	A write to a watchdog device is defined as a keepalive signal. Any
+ *	write of data will do, as we don't define content meaning.
+ *
+ *	Used within the file operation of the watchdog device.
+ */
+
+static ssize_t wdt_write(struct file *file, const char __user *buf,
+			    size_t count, loff_t *ppos)
+{
+	if (count) {
+		clear_bit(WDTS_EXPECTED, &wdt_status);
+		wdt_keepalive();
+	}
+	if (!nowayout) {
+		size_t ofs;
+
+	/* note: just in case someone wrote the magic character long ago */
+		for (ofs = 0; ofs != count; ofs++) {
+			char c;
+			if (get_user(c, buf + ofs))
+				return -EFAULT;
+			if (c == WD_MAGIC)
+				set_bit(WDTS_EXPECTED, &wdt_status);
+		}
+	}
+	return count;
+}
+
+static struct watchdog_info ident = {
+	.options = WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING,
+	.firmware_version =	1,
+	.identity = WATCHDOG_NAME,
+};
+
+/**
+ *	wdt_ioctl - watchdog file_operations .unlocked_ioctl
+ *	@file: file handle to the device
+ *	@cmd: watchdog command
+ *	@arg: argument pointer
+ *
+ *	The watchdog API defines a common set of functions for all watchdogs
+ *	according to their available features.
+ *
+ *	Used within the file operation of the watchdog device.
+ */
+
+static long wdt_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	int rc = 0, status, new_options, new_timeout;
+	union {
+		struct watchdog_info __user *ident;
+		int __user *i;
+	} uarg;
+
+	uarg.i = (int __user *)arg;
+
+	switch (cmd) {
+	case WDIOC_GETSUPPORT:
+		return copy_to_user(uarg.ident,
+				    &ident, sizeof(ident)) ? -EFAULT : 0;
+
+	case WDIOC_GETSTATUS:
+		wdt_get_status(&status);
+		return put_user(status, uarg.i);
+
+	case WDIOC_GETBOOTSTATUS:
+		return put_user(0, uarg.i);
+
+	case WDIOC_KEEPALIVE:
+		wdt_keepalive();
+		return 0;
+
+	case WDIOC_SETOPTIONS:
+		if (get_user(new_options, uarg.i))
+			return -EFAULT;
+
+		switch (new_options) {
+		case WDIOS_DISABLECARD:
+			if (test_bit(WDTS_TIMER_RUN, &wdt_status))
+				wdt_stop();
+			clear_bit(WDTS_TIMER_RUN, &wdt_status);
+			return 0;
+
+		case WDIOS_ENABLECARD:
+			if (!test_and_set_bit(WDTS_TIMER_RUN, &wdt_status))
+				wdt_start();
+			return 0;
+
+		default:
+			return -EFAULT;
+		}
+
+	case WDIOC_SETTIMEOUT:
+		if (get_user(new_timeout, uarg.i))
+			return -EFAULT;
+		rc = wdt_set_timeout(new_timeout);
+	case WDIOC_GETTIMEOUT:
+		if (put_user(timeout, uarg.i))
+			return -EFAULT;
+		return rc;
+
+	default:
+		return -ENOTTY;
+	}
+}
+
+static int wdt_notify_sys(struct notifier_block *this, unsigned long code,
+	void *unused)
+{
+	if (code == SYS_DOWN || code == SYS_HALT)
+		wdt_stop();
+	return NOTIFY_DONE;
+}
+
+static const struct file_operations wdt_fops = {
+	.owner		= THIS_MODULE,
+	.llseek		= no_llseek,
+	.write		= wdt_write,
+	.unlocked_ioctl	= wdt_ioctl,
+	.open		= wdt_open,
+	.release	= wdt_release,
+};
+
+static struct miscdevice wdt_miscdev = {
+	.minor		= WATCHDOG_MINOR,
+	.name		= "watchdog",
+	.fops		= &wdt_fops,
+};
+
+static struct notifier_block wdt_notifier = {
+	.notifier_call = wdt_notify_sys,
+};
+
+static int __init it87_wdt_init(void)
+{
+	int rc = 0;
+	u16 chip_type;
+	u8  chip_rev;
+	unsigned long flags;
+
+	spin_lock_irqsave(&spinlock, flags);
+	superio_enter();
+	chip_type = superio_inw(CHIPID);
+	chip_rev  = superio_inb(CHIPREV) & 0x0f;
+	superio_exit();
+	spin_unlock_irqrestore(&spinlock, flags);
+
+	switch (chip_type) {
+	case IT8716_ID:
+	case IT8718_ID:
+	case IT8726_ID:
+		break;
+	case IT8712_ID:
+		if (chip_rev > 7)
+			break;
+	case IT8705_ID:
+		printk(KERN_ERR PFX
+		       "Unsupported Chip found, Chip %04x Revision %02x\n",
+		       chip_type, chip_rev);
+		return -ENODEV;
+	case NO_DEV_ID:
+		printk(KERN_ERR PFX "no device\n");
+		return -ENODEV;
+	default:
+		printk(KERN_ERR PFX
+		       "Unknown Chip found, Chip %04x Revision %04x\n",
+		       chip_type, chip_rev);
+		return -ENODEV;
+	}
+
+	spin_lock_irqsave(&spinlock, flags);
+	superio_enter();
+
+	superio_select(GPIO);
+	superio_outb(WDT_TOV1, WDTCFG);
+	superio_outb(0x00, WDTCTRL);
+
+	/* First try to get Gameport support */
+	if (chip_type != IT8718_ID && !nogameport) {
+		superio_select(GAMEPORT);
+		base = superio_inw(BASEREG);
+		if (!base) {
+			base = GP_BASE_DEFAULT;
+			superio_outw(base, BASEREG);
+		}
+		gpact = superio_inb(ACTREG);
+		superio_outb(0x01, ACTREG);
+		superio_exit();
+		spin_unlock_irqrestore(&spinlock, flags);
+		if (request_region(base, 1, WATCHDOG_NAME))
+			set_bit(WDTS_USE_GP, &wdt_status);
+		else
+			rc = -EIO;
+	} else {
+		superio_exit();
+		spin_unlock_irqrestore(&spinlock, flags);
+	}
+
+	/* If we haven't Gameport support, try to get CIR support */
+	if (!test_bit(WDTS_USE_GP, &wdt_status)) {
+		if (!request_region(CIR_BASE, 8, WATCHDOG_NAME)) {
+			if (rc == -EIO)
+				printk(KERN_ERR PFX
+					"I/O Address 0x%04x and 0x%04x"
+					" already in use\n", base, CIR_BASE);
+			else
+				printk(KERN_ERR PFX
+					"I/O Address 0x%04x already in use\n",
+					CIR_BASE);
+			rc = -EIO;
+			goto err_out;
+		}
+		base = CIR_BASE;
+		spin_lock_irqsave(&spinlock, flags);
+		superio_enter();
+
+		superio_select(CIR);
+		superio_outw(base, BASEREG);
+		superio_outb(0x00, CIR_ILS);
+		ciract = superio_inb(ACTREG);
+		superio_outb(0x01, ACTREG);
+		if (rc == -EIO) {
+			superio_select(GAMEPORT);
+			superio_outb(gpact, ACTREG);
+		}
+
+		superio_exit();
+		spin_unlock_irqrestore(&spinlock, flags);
+	}
+
+	if (timeout < 1 || timeout > 65535) {
+		timeout = DEFAULT_TIMEOUT;
+		printk(KERN_WARNING PFX
+		       "Timeout value out of range, use default %d sec\n",
+		       DEFAULT_TIMEOUT);
+	}
+
+	rc = register_reboot_notifier(&wdt_notifier);
+	if (rc) {
+		printk(KERN_ERR PFX
+		       "Cannot register reboot notifier (err=%d)\n", rc);
+		goto err_out_region;
+	}
+
+	rc = misc_register(&wdt_miscdev);
+	if (rc) {
+		printk(KERN_ERR PFX
+		       "Cannot register miscdev on minor=%d (err=%d)\n",
+			wdt_miscdev.minor, rc);
+		goto err_out_reboot;
+	}
+
+	/* Initialize CIR to use it as keepalive source */
+	if (!test_bit(WDTS_USE_GP, &wdt_status)) {
+		outb(0x00, CIR_RCR(base));
+		outb(0xc0, CIR_TCR1(base));
+		outb(0x5c, CIR_TCR2(base));
+		outb(0x10, CIR_IER(base));
+		outb(0x00, CIR_BDHR(base));
+		outb(0x01, CIR_BDLR(base));
+		outb(0x09, CIR_IER(base));
+	}
+
+	printk(KERN_INFO PFX "Chip it%04x revision %d initialized. "
+		"timeout=%d sec (nowayout=%d testmode=%d exclusive=%d "
+		"nogameport=%d)\n", chip_type, chip_rev, timeout,
+		nowayout, testmode, exclusive, nogameport);
+
+	return 0;
+
+err_out_reboot:
+	unregister_reboot_notifier(&wdt_notifier);
+err_out_region:
+	release_region(base, test_bit(WDTS_USE_GP, &wdt_status) ? 1 : 8);
+	if (!test_bit(WDTS_USE_GP, &wdt_status)) {
+		spin_lock_irqsave(&spinlock, flags);
+		superio_enter();
+		superio_select(CIR);
+		superio_outb(ciract, ACTREG);
+		superio_exit();
+		spin_unlock_irqrestore(&spinlock, flags);
+	}
+err_out:
+	if (chip_type != IT8718_ID && !nogameport) {
+		spin_lock_irqsave(&spinlock, flags);
+		superio_enter();
+		superio_select(GAMEPORT);
+		superio_outb(gpact, ACTREG);
+		superio_exit();
+		spin_unlock_irqrestore(&spinlock, flags);
+	}
+
+	return rc;
+}
+
+static void __exit it87_wdt_exit(void)
+{
+	unsigned long flags;
+	int nolock;
+
+	nolock = !spin_trylock_irqsave(&spinlock, flags);
+	superio_enter();
+	superio_select(GPIO);
+	superio_outb(0x00, WDTCTRL);
+	superio_outb(0x00, WDTCFG);
+	superio_outb(0x00, WDTVALMSB);
+	superio_outb(0x00, WDTVALLSB);
+	if (test_bit(WDTS_USE_GP, &wdt_status)) {
+		superio_select(GAMEPORT);
+		superio_outb(gpact, ACTREG);
+	} else {
+		superio_select(CIR);
+		superio_outb(ciract, ACTREG);
+	}
+	superio_exit();
+	if (!nolock)
+		spin_unlock_irqrestore(&spinlock, flags);
+
+	misc_deregister(&wdt_miscdev);
+	unregister_reboot_notifier(&wdt_notifier);
+	release_region(base, test_bit(WDTS_USE_GP, &wdt_status) ? 1 : 8);
+}
+
+module_init(it87_wdt_init);
+module_exit(it87_wdt_exit);
+
+MODULE_AUTHOR("Oliver Schuster");
+MODULE_DESCRIPTION("Hardware Watchdog Device Driver for IT87xx EC-LPC I/O");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/watchdog/ixp4xx_wdt.c b/drivers/watchdog/ixp4xx_wdt.c
index 8302ef0..147b4d5 100644
--- a/drivers/watchdog/ixp4xx_wdt.c
+++ b/drivers/watchdog/ixp4xx_wdt.c
@@ -174,10 +174,8 @@
 static int __init ixp4xx_wdt_init(void)
 {
 	int ret;
-	unsigned long processor_id;
 
-	asm("mrc p15, 0, %0, cr0, cr0, 0;" : "=r"(processor_id) :);
-	if (!(processor_id & 0xf) && !cpu_is_ixp46x()) {
+	if (!(read_cpuid_id() & 0xf) && !cpu_is_ixp46x()) {
 		printk(KERN_ERR "IXP4XXX Watchdog: Rev. A0 IXP42x CPU detected"
 			" - watchdog disabled\n");
 
diff --git a/drivers/watchdog/omap_wdt.c b/drivers/watchdog/omap_wdt.c
index 3a11dad..7bcbb7f 100644
--- a/drivers/watchdog/omap_wdt.c
+++ b/drivers/watchdog/omap_wdt.c
@@ -1,7 +1,7 @@
 /*
- * linux/drivers/char/watchdog/omap_wdt.c
+ * omap_wdt.c
  *
- * Watchdog driver for the TI OMAP 16xx & 24xx 32KHz (non-secure) watchdog
+ * Watchdog driver for the TI OMAP 16xx & 24xx/34xx 32KHz (non-secure) watchdog
  *
  * Author: MontaVista Software, Inc.
  *	 <gdavis@mvista.com> or <source@mvista.com>
@@ -47,50 +47,68 @@
 
 #include "omap_wdt.h"
 
+static struct platform_device *omap_wdt_dev;
+
 static unsigned timer_margin;
 module_param(timer_margin, uint, 0);
 MODULE_PARM_DESC(timer_margin, "initial watchdog timeout (in seconds)");
 
-static int omap_wdt_users;
-static struct clk *armwdt_ck;
-static struct clk *mpu_wdt_ick;
-static struct clk *mpu_wdt_fck;
-
 static unsigned int wdt_trgr_pattern = 0x1234;
 static spinlock_t wdt_lock;
 
-static void omap_wdt_ping(void)
+struct omap_wdt_dev {
+	void __iomem    *base;          /* physical */
+	struct device   *dev;
+	int             omap_wdt_users;
+	struct clk      *armwdt_ck;
+	struct clk      *mpu_wdt_ick;
+	struct clk      *mpu_wdt_fck;
+	struct resource *mem;
+	struct miscdevice omap_wdt_miscdev;
+};
+
+static void omap_wdt_ping(struct omap_wdt_dev *wdev)
 {
+	void __iomem    *base = wdev->base;
+
 	/* wait for posted write to complete */
-	while ((omap_readl(OMAP_WATCHDOG_WPS)) & 0x08)
+	while ((__raw_readl(base + OMAP_WATCHDOG_WPS)) & 0x08)
 		cpu_relax();
+
 	wdt_trgr_pattern = ~wdt_trgr_pattern;
-	omap_writel(wdt_trgr_pattern, (OMAP_WATCHDOG_TGR));
+	__raw_writel(wdt_trgr_pattern, (base + OMAP_WATCHDOG_TGR));
+
 	/* wait for posted write to complete */
-	while ((omap_readl(OMAP_WATCHDOG_WPS)) & 0x08)
+	while ((__raw_readl(base + OMAP_WATCHDOG_WPS)) & 0x08)
 		cpu_relax();
 	/* reloaded WCRR from WLDR */
 }
 
-static void omap_wdt_enable(void)
+static void omap_wdt_enable(struct omap_wdt_dev *wdev)
 {
+	void __iomem *base = wdev->base;
+
 	/* Sequence to enable the watchdog */
-	omap_writel(0xBBBB, OMAP_WATCHDOG_SPR);
-	while ((omap_readl(OMAP_WATCHDOG_WPS)) & 0x10)
+	__raw_writel(0xBBBB, base + OMAP_WATCHDOG_SPR);
+	while ((__raw_readl(base + OMAP_WATCHDOG_WPS)) & 0x10)
 		cpu_relax();
-	omap_writel(0x4444, OMAP_WATCHDOG_SPR);
-	while ((omap_readl(OMAP_WATCHDOG_WPS)) & 0x10)
+
+	__raw_writel(0x4444, base + OMAP_WATCHDOG_SPR);
+	while ((__raw_readl(base + OMAP_WATCHDOG_WPS)) & 0x10)
 		cpu_relax();
 }
 
-static void omap_wdt_disable(void)
+static void omap_wdt_disable(struct omap_wdt_dev *wdev)
 {
+	void __iomem *base = wdev->base;
+
 	/* sequence required to disable watchdog */
-	omap_writel(0xAAAA, OMAP_WATCHDOG_SPR);	/* TIMER_MODE */
-	while (omap_readl(OMAP_WATCHDOG_WPS) & 0x10)
+	__raw_writel(0xAAAA, base + OMAP_WATCHDOG_SPR);	/* TIMER_MODE */
+	while (__raw_readl(base + OMAP_WATCHDOG_WPS) & 0x10)
 		cpu_relax();
-	omap_writel(0x5555, OMAP_WATCHDOG_SPR);	/* TIMER_MODE */
-	while (omap_readl(OMAP_WATCHDOG_WPS) & 0x10)
+
+	__raw_writel(0x5555, base + OMAP_WATCHDOG_SPR);	/* TIMER_MODE */
+	while (__raw_readl(base + OMAP_WATCHDOG_WPS) & 0x10)
 		cpu_relax();
 }
 
@@ -103,83 +121,90 @@
 	timer_margin = new_timeout;
 }
 
-static void omap_wdt_set_timeout(void)
+static void omap_wdt_set_timeout(struct omap_wdt_dev *wdev)
 {
 	u32 pre_margin = GET_WLDR_VAL(timer_margin);
+	void __iomem *base = wdev->base;
 
 	/* just count up at 32 KHz */
-	while (omap_readl(OMAP_WATCHDOG_WPS) & 0x04)
+	while (__raw_readl(base + OMAP_WATCHDOG_WPS) & 0x04)
 		cpu_relax();
-	omap_writel(pre_margin, OMAP_WATCHDOG_LDR);
-	while (omap_readl(OMAP_WATCHDOG_WPS) & 0x04)
+
+	__raw_writel(pre_margin, base + OMAP_WATCHDOG_LDR);
+	while (__raw_readl(base + OMAP_WATCHDOG_WPS) & 0x04)
 		cpu_relax();
 }
 
 /*
  *	Allow only one task to hold it open
  */
-
 static int omap_wdt_open(struct inode *inode, struct file *file)
 {
-	if (test_and_set_bit(1, (unsigned long *)&omap_wdt_users))
+	struct omap_wdt_dev *wdev = platform_get_drvdata(omap_wdt_dev);
+	void __iomem *base = wdev->base;
+
+	if (test_and_set_bit(1, (unsigned long *)&(wdev->omap_wdt_users)))
 		return -EBUSY;
 
 	if (cpu_is_omap16xx())
-		clk_enable(armwdt_ck);	/* Enable the clock */
+		clk_enable(wdev->armwdt_ck);	/* Enable the clock */
 
-	if (cpu_is_omap24xx()) {
-		clk_enable(mpu_wdt_ick);    /* Enable the interface clock */
-		clk_enable(mpu_wdt_fck);    /* Enable the functional clock */
+	if (cpu_is_omap24xx() || cpu_is_omap34xx()) {
+		clk_enable(wdev->mpu_wdt_ick);    /* Enable the interface clock */
+		clk_enable(wdev->mpu_wdt_fck);    /* Enable the functional clock */
 	}
 
 	/* initialize prescaler */
-	while (omap_readl(OMAP_WATCHDOG_WPS) & 0x01)
-		cpu_relax();
-	omap_writel((1 << 5) | (PTV << 2), OMAP_WATCHDOG_CNTRL);
-	while (omap_readl(OMAP_WATCHDOG_WPS) & 0x01)
+	while (__raw_readl(base + OMAP_WATCHDOG_WPS) & 0x01)
 		cpu_relax();
 
-	omap_wdt_set_timeout();
-	omap_wdt_enable();
+	__raw_writel((1 << 5) | (PTV << 2), base + OMAP_WATCHDOG_CNTRL);
+	while (__raw_readl(base + OMAP_WATCHDOG_WPS) & 0x01)
+		cpu_relax();
+
+	file->private_data = (void *) wdev;
+
+	omap_wdt_set_timeout(wdev);
+	omap_wdt_enable(wdev);
+
 	return nonseekable_open(inode, file);
 }
 
 static int omap_wdt_release(struct inode *inode, struct file *file)
 {
+	struct omap_wdt_dev *wdev = file->private_data;
+
 	/*
 	 *      Shut off the timer unless NOWAYOUT is defined.
 	 */
 #ifndef CONFIG_WATCHDOG_NOWAYOUT
-	omap_wdt_disable();
 
-	if (cpu_is_omap16xx()) {
-		clk_disable(armwdt_ck);	/* Disable the clock */
-		clk_put(armwdt_ck);
-		armwdt_ck = NULL;
-	}
+	omap_wdt_disable(wdev);
 
-	if (cpu_is_omap24xx()) {
-		clk_disable(mpu_wdt_ick);	/* Disable the clock */
-		clk_disable(mpu_wdt_fck);	/* Disable the clock */
-		clk_put(mpu_wdt_ick);
-		clk_put(mpu_wdt_fck);
-		mpu_wdt_ick = NULL;
-		mpu_wdt_fck = NULL;
+	if (cpu_is_omap16xx())
+		clk_disable(wdev->armwdt_ck);	/* Disable the clock */
+
+	if (cpu_is_omap24xx() || cpu_is_omap34xx()) {
+		clk_disable(wdev->mpu_wdt_ick);	/* Disable the clock */
+		clk_disable(wdev->mpu_wdt_fck);	/* Disable the clock */
 	}
 #else
 	printk(KERN_CRIT "omap_wdt: Unexpected close, not stopping!\n");
 #endif
-	omap_wdt_users = 0;
+	wdev->omap_wdt_users = 0;
+
 	return 0;
 }
 
 static ssize_t omap_wdt_write(struct file *file, const char __user *data,
 		size_t len, loff_t *ppos)
 {
+	struct omap_wdt_dev *wdev = file->private_data;
+
 	/* Refresh LOAD_TIME. */
 	if (len) {
 		spin_lock(&wdt_lock);
-		omap_wdt_ping();
+		omap_wdt_ping(wdev);
 		spin_unlock(&wdt_lock);
 	}
 	return len;
@@ -188,6 +213,7 @@
 static long omap_wdt_ioctl(struct file *file, unsigned int cmd,
 						unsigned long arg)
 {
+	struct omap_wdt_dev *wdev;
 	int new_margin;
 	static const struct watchdog_info ident = {
 		.identity = "OMAP Watchdog",
@@ -195,6 +221,8 @@
 		.firmware_version = 0,
 	};
 
+	wdev = file->private_data;
+
 	switch (cmd) {
 	case WDIOC_GETSUPPORT:
 		return copy_to_user((struct watchdog_info __user *)arg, &ident,
@@ -203,14 +231,14 @@
 		return put_user(0, (int __user *)arg);
 	case WDIOC_GETBOOTSTATUS:
 		if (cpu_is_omap16xx())
-			return put_user(omap_readw(ARM_SYSST),
+			return put_user(__raw_readw(ARM_SYSST),
 					(int __user *)arg);
 		if (cpu_is_omap24xx())
 			return put_user(omap_prcm_get_reset_sources(),
 					(int __user *)arg);
 	case WDIOC_KEEPALIVE:
 		spin_lock(&wdt_lock);
-		omap_wdt_ping();
+		omap_wdt_ping(wdev);
 		spin_unlock(&wdt_lock);
 		return 0;
 	case WDIOC_SETTIMEOUT:
@@ -219,11 +247,11 @@
 		omap_wdt_adjust_timeout(new_margin);
 
 		spin_lock(&wdt_lock);
-		omap_wdt_disable();
-		omap_wdt_set_timeout();
-		omap_wdt_enable();
+		omap_wdt_disable(wdev);
+		omap_wdt_set_timeout(wdev);
+		omap_wdt_enable(wdev);
 
-		omap_wdt_ping();
+		omap_wdt_ping(wdev);
 		spin_unlock(&wdt_lock);
 		/* Fall */
 	case WDIOC_GETTIMEOUT:
@@ -241,96 +269,173 @@
 	.release = omap_wdt_release,
 };
 
-static struct miscdevice omap_wdt_miscdev = {
-	.minor = WATCHDOG_MINOR,
-	.name = "watchdog",
-	.fops = &omap_wdt_fops,
-};
-
 static int __init omap_wdt_probe(struct platform_device *pdev)
 {
 	struct resource *res, *mem;
+	struct omap_wdt_dev *wdev;
 	int ret;
 
 	/* reserve static register mappings */
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!res)
-		return -ENOENT;
+	if (!res) {
+		ret = -ENOENT;
+		goto err_get_resource;
+	}
+
+	if (omap_wdt_dev) {
+		ret = -EBUSY;
+		goto err_busy;
+	}
 
 	mem = request_mem_region(res->start, res->end - res->start + 1,
 				 pdev->name);
-	if (mem == NULL)
-		return -EBUSY;
+	if (!mem) {
+		ret = -EBUSY;
+		goto err_busy;
+	}
 
-	platform_set_drvdata(pdev, mem);
+	wdev = kzalloc(sizeof(struct omap_wdt_dev), GFP_KERNEL);
+	if (!wdev) {
+		ret = -ENOMEM;
+		goto err_kzalloc;
+	}
 
-	omap_wdt_users = 0;
+	wdev->omap_wdt_users = 0;
+	wdev->mem = mem;
 
 	if (cpu_is_omap16xx()) {
-		armwdt_ck = clk_get(&pdev->dev, "armwdt_ck");
-		if (IS_ERR(armwdt_ck)) {
-			ret = PTR_ERR(armwdt_ck);
-			armwdt_ck = NULL;
-			goto fail;
+		wdev->armwdt_ck = clk_get(&pdev->dev, "armwdt_ck");
+		if (IS_ERR(wdev->armwdt_ck)) {
+			ret = PTR_ERR(wdev->armwdt_ck);
+			wdev->armwdt_ck = NULL;
+			goto err_clk;
 		}
 	}
 
 	if (cpu_is_omap24xx()) {
-		mpu_wdt_ick = clk_get(&pdev->dev, "mpu_wdt_ick");
-		if (IS_ERR(mpu_wdt_ick)) {
-			ret = PTR_ERR(mpu_wdt_ick);
-			mpu_wdt_ick = NULL;
-			goto fail;
+		wdev->mpu_wdt_ick = clk_get(&pdev->dev, "mpu_wdt_ick");
+		if (IS_ERR(wdev->mpu_wdt_ick)) {
+			ret = PTR_ERR(wdev->mpu_wdt_ick);
+			wdev->mpu_wdt_ick = NULL;
+			goto err_clk;
 		}
-		mpu_wdt_fck = clk_get(&pdev->dev, "mpu_wdt_fck");
-		if (IS_ERR(mpu_wdt_fck)) {
-			ret = PTR_ERR(mpu_wdt_fck);
-			mpu_wdt_fck = NULL;
-			goto fail;
+		wdev->mpu_wdt_fck = clk_get(&pdev->dev, "mpu_wdt_fck");
+		if (IS_ERR(wdev->mpu_wdt_fck)) {
+			ret = PTR_ERR(wdev->mpu_wdt_fck);
+			wdev->mpu_wdt_fck = NULL;
+			goto err_clk;
 		}
 	}
 
-	omap_wdt_disable();
+	if (cpu_is_omap34xx()) {
+		wdev->mpu_wdt_ick = clk_get(&pdev->dev, "wdt2_ick");
+		if (IS_ERR(wdev->mpu_wdt_ick)) {
+			ret = PTR_ERR(wdev->mpu_wdt_ick);
+			wdev->mpu_wdt_ick = NULL;
+			goto err_clk;
+		}
+		wdev->mpu_wdt_fck = clk_get(&pdev->dev, "wdt2_fck");
+		if (IS_ERR(wdev->mpu_wdt_fck)) {
+			ret = PTR_ERR(wdev->mpu_wdt_fck);
+			wdev->mpu_wdt_fck = NULL;
+			goto err_clk;
+		}
+	}
+	wdev->base = ioremap(res->start, res->end - res->start + 1);
+	if (!wdev->base) {
+		ret = -ENOMEM;
+		goto err_ioremap;
+	}
+
+	platform_set_drvdata(pdev, wdev);
+
+	omap_wdt_disable(wdev);
 	omap_wdt_adjust_timeout(timer_margin);
 
-	omap_wdt_miscdev.parent = &pdev->dev;
-	ret = misc_register(&omap_wdt_miscdev);
-	if (ret)
-		goto fail;
+	wdev->omap_wdt_miscdev.parent = &pdev->dev;
+	wdev->omap_wdt_miscdev.minor = WATCHDOG_MINOR;
+	wdev->omap_wdt_miscdev.name = "watchdog";
+	wdev->omap_wdt_miscdev.fops = &omap_wdt_fops;
 
-	pr_info("OMAP Watchdog Timer: initial timeout %d sec\n", timer_margin);
+	ret = misc_register(&(wdev->omap_wdt_miscdev));
+	if (ret)
+		goto err_misc;
+
+	pr_info("OMAP Watchdog Timer Rev 0x%02x: initial timeout %d sec\n",
+		__raw_readl(wdev->base + OMAP_WATCHDOG_REV) & 0xFF,
+		timer_margin);
 
 	/* autogate OCP interface clock */
-	omap_writel(0x01, OMAP_WATCHDOG_SYS_CONFIG);
+	__raw_writel(0x01, wdev->base + OMAP_WATCHDOG_SYS_CONFIG);
+
+	omap_wdt_dev = pdev;
+
 	return 0;
 
-fail:
-	if (armwdt_ck)
-		clk_put(armwdt_ck);
-	if (mpu_wdt_ick)
-		clk_put(mpu_wdt_ick);
-	if (mpu_wdt_fck)
-		clk_put(mpu_wdt_fck);
-	release_resource(mem);
+err_misc:
+	platform_set_drvdata(pdev, NULL);
+	iounmap(wdev->base);
+
+err_ioremap:
+	wdev->base = NULL;
+
+err_clk:
+	if (wdev->armwdt_ck)
+		clk_put(wdev->armwdt_ck);
+	if (wdev->mpu_wdt_ick)
+		clk_put(wdev->mpu_wdt_ick);
+	if (wdev->mpu_wdt_fck)
+		clk_put(wdev->mpu_wdt_fck);
+	kfree(wdev);
+
+err_kzalloc:
+	release_mem_region(res->start, res->end - res->start + 1);
+
+err_busy:
+err_get_resource:
+
 	return ret;
 }
 
 static void omap_wdt_shutdown(struct platform_device *pdev)
 {
-	omap_wdt_disable();
+	struct omap_wdt_dev *wdev = platform_get_drvdata(pdev);
+
+	if (wdev->omap_wdt_users)
+		omap_wdt_disable(wdev);
 }
 
 static int omap_wdt_remove(struct platform_device *pdev)
 {
-	struct resource *mem = platform_get_drvdata(pdev);
-	misc_deregister(&omap_wdt_miscdev);
-	release_resource(mem);
-	if (armwdt_ck)
-		clk_put(armwdt_ck);
-	if (mpu_wdt_ick)
-		clk_put(mpu_wdt_ick);
-	if (mpu_wdt_fck)
-		clk_put(mpu_wdt_fck);
+	struct omap_wdt_dev *wdev = platform_get_drvdata(pdev);
+	struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+	if (!res)
+		return -ENOENT;
+
+	misc_deregister(&(wdev->omap_wdt_miscdev));
+	release_mem_region(res->start, res->end - res->start + 1);
+	platform_set_drvdata(pdev, NULL);
+
+	if (wdev->armwdt_ck) {
+		clk_put(wdev->armwdt_ck);
+		wdev->armwdt_ck = NULL;
+	}
+
+	if (wdev->mpu_wdt_ick) {
+		clk_put(wdev->mpu_wdt_ick);
+		wdev->mpu_wdt_ick = NULL;
+	}
+
+	if (wdev->mpu_wdt_fck) {
+		clk_put(wdev->mpu_wdt_fck);
+		wdev->mpu_wdt_fck = NULL;
+	}
+	iounmap(wdev->base);
+
+	kfree(wdev);
+	omap_wdt_dev = NULL;
+
 	return 0;
 }
 
@@ -344,17 +449,23 @@
 
 static int omap_wdt_suspend(struct platform_device *pdev, pm_message_t state)
 {
-	if (omap_wdt_users)
-		omap_wdt_disable();
+	struct omap_wdt_dev *wdev = platform_get_drvdata(pdev);
+
+	if (wdev->omap_wdt_users)
+		omap_wdt_disable(wdev);
+
 	return 0;
 }
 
 static int omap_wdt_resume(struct platform_device *pdev)
 {
-	if (omap_wdt_users) {
-		omap_wdt_enable();
-		omap_wdt_ping();
+	struct omap_wdt_dev *wdev = platform_get_drvdata(pdev);
+
+	if (wdev->omap_wdt_users) {
+		omap_wdt_enable(wdev);
+		omap_wdt_ping(wdev);
 	}
+
 	return 0;
 }
 
diff --git a/drivers/watchdog/omap_wdt.h b/drivers/watchdog/omap_wdt.h
index 52a532a5..fc02ec6 100644
--- a/drivers/watchdog/omap_wdt.h
+++ b/drivers/watchdog/omap_wdt.h
@@ -30,25 +30,15 @@
 #ifndef _OMAP_WATCHDOG_H
 #define _OMAP_WATCHDOG_H
 
-#define OMAP1610_WATCHDOG_BASE		0xfffeb000
-#define OMAP2420_WATCHDOG_BASE		0x48022000	/*WDT Timer 2 */
-
-#ifdef CONFIG_ARCH_OMAP24XX
-#define OMAP_WATCHDOG_BASE 		OMAP2420_WATCHDOG_BASE
-#else
-#define OMAP_WATCHDOG_BASE 		OMAP1610_WATCHDOG_BASE
-#define RM_RSTST_WKUP			0
-#endif
-
-#define OMAP_WATCHDOG_REV		(OMAP_WATCHDOG_BASE + 0x00)
-#define OMAP_WATCHDOG_SYS_CONFIG	(OMAP_WATCHDOG_BASE + 0x10)
-#define OMAP_WATCHDOG_STATUS		(OMAP_WATCHDOG_BASE + 0x14)
-#define OMAP_WATCHDOG_CNTRL		(OMAP_WATCHDOG_BASE + 0x24)
-#define OMAP_WATCHDOG_CRR		(OMAP_WATCHDOG_BASE + 0x28)
-#define OMAP_WATCHDOG_LDR		(OMAP_WATCHDOG_BASE + 0x2c)
-#define OMAP_WATCHDOG_TGR		(OMAP_WATCHDOG_BASE + 0x30)
-#define OMAP_WATCHDOG_WPS		(OMAP_WATCHDOG_BASE + 0x34)
-#define OMAP_WATCHDOG_SPR		(OMAP_WATCHDOG_BASE + 0x48)
+#define OMAP_WATCHDOG_REV		(0x00)
+#define OMAP_WATCHDOG_SYS_CONFIG	(0x10)
+#define OMAP_WATCHDOG_STATUS		(0x14)
+#define OMAP_WATCHDOG_CNTRL		(0x24)
+#define OMAP_WATCHDOG_CRR		(0x28)
+#define OMAP_WATCHDOG_LDR		(0x2c)
+#define OMAP_WATCHDOG_TGR		(0x30)
+#define OMAP_WATCHDOG_WPS		(0x34)
+#define OMAP_WATCHDOG_SPR		(0x48)
 
 /* Using the prescaler, the OMAP watchdog could go for many
  * months before firing.  These limits work without scaling,
diff --git a/drivers/watchdog/orion5x_wdt.c b/drivers/watchdog/orion5x_wdt.c
new file mode 100644
index 0000000..14a339f
--- /dev/null
+++ b/drivers/watchdog/orion5x_wdt.c
@@ -0,0 +1,245 @@
+/*
+ * drivers/watchdog/orion5x_wdt.c
+ *
+ * Watchdog driver for Orion5x processors
+ *
+ * Author: Sylver Bruneau <sylver.bruneau@googlemail.com>
+ *
+ * This file is licensed under  the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/init.h>
+#include <linux/uaccess.h>
+#include <linux/io.h>
+#include <linux/spinlock.h>
+
+/*
+ * Watchdog timer block registers.
+ */
+#define TIMER_CTRL		(TIMER_VIRT_BASE + 0x0000)
+#define  WDT_EN			0x0010
+#define WDT_VAL			(TIMER_VIRT_BASE + 0x0024)
+
+#define WDT_MAX_DURATION	(0xffffffff / ORION5X_TCLK)
+#define WDT_IN_USE		0
+#define WDT_OK_TO_CLOSE		1
+
+static int nowayout = WATCHDOG_NOWAYOUT;
+static int heartbeat =  WDT_MAX_DURATION;	/* (seconds) */
+static unsigned long wdt_status;
+static spinlock_t wdt_lock;
+
+static void wdt_enable(void)
+{
+	u32 reg;
+
+	spin_lock(&wdt_lock);
+
+	/* Set watchdog duration */
+	writel(ORION5X_TCLK * heartbeat, WDT_VAL);
+
+	/* Clear watchdog timer interrupt */
+	reg = readl(BRIDGE_CAUSE);
+	reg &= ~WDT_INT_REQ;
+	writel(reg, BRIDGE_CAUSE);
+
+	/* Enable watchdog timer */
+	reg = readl(TIMER_CTRL);
+	reg |= WDT_EN;
+	writel(reg, TIMER_CTRL);
+
+	/* Enable reset on watchdog */
+	reg = readl(CPU_RESET_MASK);
+	reg |= WDT_RESET;
+	writel(reg, CPU_RESET_MASK);
+
+	spin_unlock(&wdt_lock);
+}
+
+static void wdt_disable(void)
+{
+	u32 reg;
+
+	spin_lock(&wdt_lock);
+
+	/* Disable reset on watchdog */
+	reg = readl(CPU_RESET_MASK);
+	reg &= ~WDT_RESET;
+	writel(reg, CPU_RESET_MASK);
+
+	/* Disable watchdog timer */
+	reg = readl(TIMER_CTRL);
+	reg &= ~WDT_EN;
+	writel(reg, TIMER_CTRL);
+
+	spin_unlock(&wdt_lock);
+}
+
+static int orion5x_wdt_get_timeleft(int *time_left)
+{
+	spin_lock(&wdt_lock);
+	*time_left = readl(WDT_VAL) / ORION5X_TCLK;
+	spin_unlock(&wdt_lock);
+	return 0;
+}
+
+static int orion5x_wdt_open(struct inode *inode, struct file *file)
+{
+	if (test_and_set_bit(WDT_IN_USE, &wdt_status))
+		return -EBUSY;
+	clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
+	wdt_enable();
+	return nonseekable_open(inode, file);
+}
+
+static ssize_t orion5x_wdt_write(struct file *file, const char *data,
+					size_t len, loff_t *ppos)
+{
+	if (len) {
+		if (!nowayout) {
+			size_t i;
+
+			clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
+			for (i = 0; i != len; i++) {
+				char c;
+
+				if (get_user(c, data + i))
+					return -EFAULT;
+				if (c == 'V')
+					set_bit(WDT_OK_TO_CLOSE, &wdt_status);
+			}
+		}
+		wdt_enable();
+	}
+	return len;
+}
+
+static struct watchdog_info ident = {
+	.options	= WDIOF_MAGICCLOSE | WDIOF_SETTIMEOUT |
+			  WDIOF_KEEPALIVEPING,
+	.identity	= "Orion5x Watchdog",
+};
+
+
+static long orion5x_wdt_ioctl(struct file *file, unsigned int cmd,
+				unsigned long arg)
+{
+	int ret = -ENOTTY;
+	int time;
+
+	switch (cmd) {
+	case WDIOC_GETSUPPORT:
+		ret = copy_to_user((struct watchdog_info *)arg, &ident,
+				   sizeof(ident)) ? -EFAULT : 0;
+		break;
+
+	case WDIOC_GETSTATUS:
+	case WDIOC_GETBOOTSTATUS:
+		ret = put_user(0, (int *)arg);
+		break;
+
+	case WDIOC_KEEPALIVE:
+		wdt_enable();
+		ret = 0;
+		break;
+
+	case WDIOC_SETTIMEOUT:
+		ret = get_user(time, (int *)arg);
+		if (ret)
+			break;
+
+		if (time <= 0 || time > WDT_MAX_DURATION) {
+			ret = -EINVAL;
+			break;
+		}
+		heartbeat = time;
+		wdt_enable();
+		/* Fall through */
+
+	case WDIOC_GETTIMEOUT:
+		ret = put_user(heartbeat, (int *)arg);
+		break;
+
+	case WDIOC_GETTIMELEFT:
+		if (orion5x_wdt_get_timeleft(&time)) {
+			ret = -EINVAL;
+			break;
+		}
+		ret = put_user(time, (int *)arg);
+		break;
+	}
+	return ret;
+}
+
+static int orion5x_wdt_release(struct inode *inode, struct file *file)
+{
+	if (test_bit(WDT_OK_TO_CLOSE, &wdt_status))
+		wdt_disable();
+	else
+		printk(KERN_CRIT "WATCHDOG: Device closed unexpectedly - "
+					"timer will not stop\n");
+	clear_bit(WDT_IN_USE, &wdt_status);
+	clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
+
+	return 0;
+}
+
+
+static const struct file_operations orion5x_wdt_fops = {
+	.owner		= THIS_MODULE,
+	.llseek		= no_llseek,
+	.write		= orion5x_wdt_write,
+	.unlocked_ioctl	= orion5x_wdt_ioctl,
+	.open		= orion5x_wdt_open,
+	.release	= orion5x_wdt_release,
+};
+
+static struct miscdevice orion5x_wdt_miscdev = {
+	.minor		= WATCHDOG_MINOR,
+	.name		= "watchdog",
+	.fops		= &orion5x_wdt_fops,
+};
+
+static int __init orion5x_wdt_init(void)
+{
+	int ret;
+
+	spin_lock_init(&wdt_lock);
+
+	ret = misc_register(&orion5x_wdt_miscdev);
+	if (ret == 0)
+		printk("Orion5x Watchdog Timer: heartbeat %d sec\n",
+								heartbeat);
+
+	return ret;
+}
+
+static void __exit orion5x_wdt_exit(void)
+{
+	misc_deregister(&orion5x_wdt_miscdev);
+}
+
+module_init(orion5x_wdt_init);
+module_exit(orion5x_wdt_exit);
+
+MODULE_AUTHOR("Sylver Bruneau <sylver.bruneau@googlemail.com>");
+MODULE_DESCRIPTION("Orion5x Processor Watchdog");
+
+module_param(heartbeat, int, 0);
+MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds (default is "
+					__MODULE_STRING(WDT_MAX_DURATION) ")");
+
+module_param(nowayout, int, 0);
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started");
+
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/watchdog/pnx4008_wdt.c b/drivers/watchdog/pnx4008_wdt.c
index 0ed8416..6d9f3d4 100644
--- a/drivers/watchdog/pnx4008_wdt.c
+++ b/drivers/watchdog/pnx4008_wdt.c
@@ -173,8 +173,8 @@
 	.identity = "PNX4008 Watchdog",
 };
 
-static long pnx4008_wdt_ioctl(struct inode *inode, struct file *file,
-					unsigned int cmd, unsigned long arg)
+static long pnx4008_wdt_ioctl(struct file *file, unsigned int cmd,
+				unsigned long arg)
 {
 	int ret = -ENOTTY;
 	int time;
diff --git a/drivers/watchdog/rc32434_wdt.c b/drivers/watchdog/rc32434_wdt.c
index 6756bcb..c9c73b6 100644
--- a/drivers/watchdog/rc32434_wdt.c
+++ b/drivers/watchdog/rc32434_wdt.c
@@ -182,8 +182,8 @@
 	return 0;
 }
 
-static int rc32434_wdt_ioctl(struct inode *inode, struct file *file,
-	unsigned int cmd, unsigned long arg)
+static long rc32434_wdt_ioctl(struct file *file, unsigned int cmd,
+				unsigned long arg)
 {
 	void __user *argp = (void __user *)arg;
 	int new_timeout;
@@ -242,7 +242,7 @@
 	.owner		= THIS_MODULE,
 	.llseek		= no_llseek,
 	.write		= rc32434_wdt_write,
-	.ioctl		= rc32434_wdt_ioctl,
+	.unlocked_ioctl	= rc32434_wdt_ioctl,
 	.open		= rc32434_wdt_open,
 	.release	= rc32434_wdt_release,
 };
diff --git a/drivers/watchdog/rdc321x_wdt.c b/drivers/watchdog/rdc321x_wdt.c
index 9108efa..bf92802 100644
--- a/drivers/watchdog/rdc321x_wdt.c
+++ b/drivers/watchdog/rdc321x_wdt.c
@@ -144,8 +144,8 @@
 	return 0;
 }
 
-static int rdc321x_wdt_ioctl(struct inode *inode, struct file *file,
-				unsigned int cmd, unsigned long arg)
+static long rdc321x_wdt_ioctl(struct file *file, unsigned int cmd,
+				unsigned long arg)
 {
 	void __user *argp = (void __user *)arg;
 	unsigned int value;
@@ -204,7 +204,7 @@
 static const struct file_operations rdc321x_wdt_fops = {
 	.owner		= THIS_MODULE,
 	.llseek		= no_llseek,
-	.ioctl		= rdc321x_wdt_ioctl,
+	.unlocked_ioctl	= rdc321x_wdt_ioctl,
 	.open		= rdc321x_wdt_open,
 	.write		= rdc321x_wdt_write,
 	.release	= rdc321x_wdt_release,
diff --git a/drivers/watchdog/riowd.c b/drivers/watchdog/riowd.c
new file mode 100644
index 0000000..09cb183
--- /dev/null
+++ b/drivers/watchdog/riowd.c
@@ -0,0 +1,259 @@
+/* riowd.c - driver for hw watchdog inside Super I/O of RIO
+ *
+ * Copyright (C) 2001, 2008 David S. Miller (davem@davemloft.net)
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/fs.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/miscdevice.h>
+#include <linux/smp_lock.h>
+#include <linux/watchdog.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+
+#include <asm/io.h>
+#include <asm/uaccess.h>
+
+
+/* RIO uses the NatSemi Super I/O power management logical device
+ * as its' watchdog.
+ *
+ * When the watchdog triggers, it asserts a line to the BBC (Boot Bus
+ * Controller) of the machine.  The BBC can only be configured to
+ * trigger a power-on reset when the signal is asserted.  The BBC
+ * can be configured to ignore the signal entirely as well.
+ *
+ * The only Super I/O device register we care about is at index
+ * 0x05 (WDTO_INDEX) which is the watchdog time-out in minutes (1-255).
+ * If set to zero, this disables the watchdog.  When set, the system
+ * must periodically (before watchdog expires) clear (set to zero) and
+ * re-set the watchdog else it will trigger.
+ *
+ * There are two other indexed watchdog registers inside this Super I/O
+ * logical device, but they are unused.  The first, at index 0x06 is
+ * the watchdog control and can be used to make the watchdog timer re-set
+ * when the PS/2 mouse or serial lines show activity.  The second, at
+ * index 0x07 is merely a sampling of the line from the watchdog to the
+ * BBC.
+ *
+ * The watchdog device generates no interrupts.
+ */
+
+MODULE_AUTHOR("David S. Miller <davem@davemloft.net>");
+MODULE_DESCRIPTION("Hardware watchdog driver for Sun RIO");
+MODULE_SUPPORTED_DEVICE("watchdog");
+MODULE_LICENSE("GPL");
+
+#define DRIVER_NAME	"riowd"
+#define PFX		DRIVER_NAME ": "
+
+struct riowd {
+	void __iomem		*regs;
+	spinlock_t		lock;
+};
+
+static struct riowd *riowd_device;
+
+#define WDTO_INDEX	0x05
+
+static int riowd_timeout = 1;		/* in minutes */
+module_param(riowd_timeout, int, 0);
+MODULE_PARM_DESC(riowd_timeout, "Watchdog timeout in minutes");
+
+static void riowd_writereg(struct riowd *p, u8 val, int index)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&p->lock, flags);
+	writeb(index, p->regs + 0);
+	writeb(val, p->regs + 1);
+	spin_unlock_irqrestore(&p->lock, flags);
+}
+
+static int riowd_open(struct inode *inode, struct file *filp)
+{
+	cycle_kernel_lock();
+	nonseekable_open(inode, filp);
+	return 0;
+}
+
+static int riowd_release(struct inode *inode, struct file *filp)
+{
+	return 0;
+}
+
+static int riowd_ioctl(struct inode *inode, struct file *filp,
+		       unsigned int cmd, unsigned long arg)
+{
+	static struct watchdog_info info = {
+		.options		= WDIOF_SETTIMEOUT,
+		.firmware_version	= 1,
+		.identity		= DRIVER_NAME,
+	};
+	void __user *argp = (void __user *)arg;
+	struct riowd *p = riowd_device;
+	unsigned int options;
+	int new_margin;
+
+	switch (cmd) {
+	case WDIOC_GETSUPPORT:
+		if (copy_to_user(argp, &info, sizeof(info)))
+			return -EFAULT;
+		break;
+
+	case WDIOC_GETSTATUS:
+	case WDIOC_GETBOOTSTATUS:
+		if (put_user(0, (int __user *)argp))
+			return -EFAULT;
+		break;
+
+	case WDIOC_KEEPALIVE:
+		riowd_writereg(p, riowd_timeout, WDTO_INDEX);
+		break;
+
+	case WDIOC_SETOPTIONS:
+		if (copy_from_user(&options, argp, sizeof(options)))
+			return -EFAULT;
+
+		if (options & WDIOS_DISABLECARD)
+			riowd_writereg(p, 0, WDTO_INDEX);
+		else if (options & WDIOS_ENABLECARD)
+			riowd_writereg(p, riowd_timeout, WDTO_INDEX);
+		else
+			return -EINVAL;
+
+		break;
+
+	case WDIOC_SETTIMEOUT:
+		if (get_user(new_margin, (int __user *)argp))
+			return -EFAULT;
+		if ((new_margin < 60) || (new_margin > (255 * 60)))
+			return -EINVAL;
+		riowd_timeout = (new_margin + 59) / 60;
+		riowd_writereg(p, riowd_timeout, WDTO_INDEX);
+		/* Fall */
+
+	case WDIOC_GETTIMEOUT:
+		return put_user(riowd_timeout * 60, (int __user *)argp);
+
+	default:
+		return -EINVAL;
+	};
+
+	return 0;
+}
+
+static ssize_t riowd_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
+{
+	struct riowd *p = riowd_device;
+
+	if (count) {
+		riowd_writereg(p, riowd_timeout, WDTO_INDEX);
+		return 1;
+	}
+
+	return 0;
+}
+
+static const struct file_operations riowd_fops = {
+	.owner =	THIS_MODULE,
+	.llseek =	no_llseek,
+	.ioctl =	riowd_ioctl,
+	.open =		riowd_open,
+	.write =	riowd_write,
+	.release =	riowd_release,
+};
+
+static struct miscdevice riowd_miscdev = {
+	.minor	= WATCHDOG_MINOR,
+	.name	= "watchdog",
+	.fops	= &riowd_fops
+};
+
+static int __devinit riowd_probe(struct of_device *op,
+				 const struct of_device_id *match)
+{
+	struct riowd *p;
+	int err = -EINVAL;
+
+	if (riowd_device)
+		goto out;
+
+	err = -ENOMEM;
+	p = kzalloc(sizeof(*p), GFP_KERNEL);
+	if (!p)
+		goto out;
+
+	spin_lock_init(&p->lock);
+
+	p->regs = of_ioremap(&op->resource[0], 0, 2, DRIVER_NAME);
+	if (!p->regs) {
+		printk(KERN_ERR PFX "Cannot map registers.\n");
+		goto out_free;
+	}
+
+	err = misc_register(&riowd_miscdev);
+	if (err) {
+		printk(KERN_ERR PFX "Cannot register watchdog misc device.\n");
+		goto out_iounmap;
+	}
+
+	printk(KERN_INFO PFX "Hardware watchdog [%i minutes], "
+	       "regs at %p\n", riowd_timeout, p->regs);
+
+	dev_set_drvdata(&op->dev, p);
+	riowd_device = p;
+	err = 0;
+
+out_iounmap:
+	of_iounmap(&op->resource[0], p->regs, 2);
+
+out_free:
+	kfree(p);
+
+out:
+	return err;
+}
+
+static int __devexit riowd_remove(struct of_device *op)
+{
+	struct riowd *p = dev_get_drvdata(&op->dev);
+
+	misc_deregister(&riowd_miscdev);
+	of_iounmap(&op->resource[0], p->regs, 2);
+	kfree(p);
+
+	return 0;
+}
+
+static const struct of_device_id riowd_match[] = {
+	{
+		.name = "pmc",
+	},
+	{},
+};
+MODULE_DEVICE_TABLE(of, riowd_match);
+
+static struct of_platform_driver riowd_driver = {
+	.name		= DRIVER_NAME,
+	.match_table	= riowd_match,
+	.probe		= riowd_probe,
+	.remove		= __devexit_p(riowd_remove),
+};
+
+static int __init riowd_init(void)
+{
+	return of_register_driver(&riowd_driver, &of_bus_type);
+}
+
+static void __exit riowd_exit(void)
+{
+	of_unregister_driver(&riowd_driver);
+}
+
+module_init(riowd_init);
+module_exit(riowd_exit);
diff --git a/drivers/watchdog/w83697ug_wdt.c b/drivers/watchdog/w83697ug_wdt.c
new file mode 100644
index 0000000..c73b5e2
--- /dev/null
+++ b/drivers/watchdog/w83697ug_wdt.c
@@ -0,0 +1,392 @@
+/*
+ *	w83697ug/uf WDT driver
+ *
+ *	(c) Copyright 2008 Flemming Fransen <ff@nrvissing.net>
+ *              reused original code to supoprt w83697ug/uf.
+ *
+ *	Based on w83627hf_wdt.c which is based on advantechwdt.c
+ *	which is based on wdt.c.
+ *	Original copyright messages:
+ *
+ *	(c) Copyright 2007 Vlad Drukker <vlad@storewiz.com>
+ *		added support for W83627THF.
+ *
+ *	(c) Copyright 2003 Pádraig Brady <P@draigBrady.com>
+ *
+ *	(c) Copyright 2000-2001 Marek Michalkiewicz <marekm@linux.org.pl>
+ *
+ *	(c) Copyright 1996 Alan Cox <alan@redhat.com>, All Rights Reserved.
+ *				http://www.redhat.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.
+ *
+ *	Neither Alan Cox nor CymruNet Ltd. admit liability nor provide
+ *	warranty for any of this software. This material is provided
+ *	"AS-IS" and at no charge.
+ *
+ *	(c) Copyright 1995    Alan Cox <alan@redhat.com>
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/types.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/fs.h>
+#include <linux/ioport.h>
+#include <linux/notifier.h>
+#include <linux/reboot.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/io.h>
+#include <linux/uaccess.h>
+
+#include <asm/system.h>
+
+#define WATCHDOG_NAME "w83697ug/uf WDT"
+#define PFX WATCHDOG_NAME ": "
+#define WATCHDOG_TIMEOUT 60		/* 60 sec default timeout */
+
+static unsigned long wdt_is_open;
+static char expect_close;
+static DEFINE_SPINLOCK(io_lock);
+
+static int wdt_io = 0x2e;
+module_param(wdt_io, int, 0);
+MODULE_PARM_DESC(wdt_io, "w83697ug/uf WDT io port (default 0x2e)");
+
+static int timeout = WATCHDOG_TIMEOUT;	/* in seconds */
+module_param(timeout, int, 0);
+MODULE_PARM_DESC(timeout,
+	"Watchdog timeout in seconds. 1<= timeout <=255 (default="
+				__MODULE_STRING(WATCHDOG_TIMEOUT) ")");
+
+static int nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, int, 0);
+MODULE_PARM_DESC(nowayout,
+	"Watchdog cannot be stopped once started (default="
+				__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
+
+/*
+ *	Kernel methods.
+ */
+
+#define WDT_EFER (wdt_io+0)   /* Extended Function Enable Registers */
+#define WDT_EFIR (wdt_io+0)   /* Extended Function Index Register
+							(same as EFER) */
+#define WDT_EFDR (WDT_EFIR+1) /* Extended Function Data Register */
+
+static void w83697ug_select_wd_register(void)
+{
+	unsigned char c;
+	unsigned char version;
+
+	outb_p(0x87, WDT_EFER); /* Enter extended function mode */
+	outb_p(0x87, WDT_EFER); /* Again according to manual */
+
+	outb(0x20, WDT_EFER); 	/* check chip version	*/
+	version = inb(WDT_EFDR);
+
+	if (version == 0x68) {	/* W83697UG 		*/
+		printk(KERN_INFO PFX "Watchdog chip version 0x%02x = "
+			"W83697UG/UF found at 0x%04x\n", version, wdt_io);
+
+		outb_p(0x2b, WDT_EFER);
+		c = inb_p(WDT_EFDR);    /* select WDT0 */
+		c &= ~0x04;
+		outb_p(0x2b, WDT_EFER);
+		outb_p(c, WDT_EFDR);	/* set pin118 to WDT0 */
+
+	} else {
+		printk(KERN_ERR PFX "No W83697UG/UF could be found\n");
+		return -EIO;
+	}
+
+	outb_p(0x07, WDT_EFER); /* point to logical device number reg */
+	outb_p(0x08, WDT_EFDR); /* select logical device 8 (GPIO2) */
+	outb_p(0x30, WDT_EFER); /* select CR30 */
+	c = inb_p(WDT_EFDR);
+	outb_p(c || 0x01, WDT_EFDR); /* set bit 0 to activate GPIO2 */
+}
+
+static void w83697ug_unselect_wd_register(void)
+{
+	outb_p(0xAA, WDT_EFER); /* Leave extended function mode */
+}
+
+static void w83697ug_init(void)
+{
+	unsigned char t;
+
+	w83697ug_select_wd_register();
+
+	outb_p(0xF6, WDT_EFER); /* Select CRF6 */
+	t = inb_p(WDT_EFDR);    /* read CRF6 */
+	if (t != 0) {
+		printk(KERN_INFO PFX "Watchdog already running."
+			" Resetting timeout to %d sec\n", timeout);
+		outb_p(timeout, WDT_EFDR);    /* Write back to CRF6 */
+	}
+	outb_p(0xF5, WDT_EFER); /* Select CRF5 */
+	t = inb_p(WDT_EFDR);    /* read CRF5 */
+	t &= ~0x0C;             /* set second mode &
+					disable keyboard turning off watchdog */
+	outb_p(t, WDT_EFDR);    /* Write back to CRF5 */
+
+	w83697ug_unselect_wd_register();
+}
+
+static void wdt_ctrl(int timeout)
+{
+	spin_lock(&io_lock);
+
+	w83697ug_select_wd_register();
+
+	outb_p(0xF4, WDT_EFER);    /* Select CRF4 */
+	outb_p(timeout, WDT_EFDR); /* Write Timeout counter to CRF4 */
+
+	w83697ug_unselect_wd_register();
+
+	spin_unlock(&io_lock);
+}
+
+static int wdt_ping(void)
+{
+	wdt_ctrl(timeout);
+	return 0;
+}
+
+static int wdt_disable(void)
+{
+	wdt_ctrl(0);
+	return 0;
+}
+
+static int wdt_set_heartbeat(int t)
+{
+	if (t < 1 || t > 255)
+		return -EINVAL;
+
+	timeout = t;
+	return 0;
+}
+
+static ssize_t wdt_write(struct file *file, const char __user *buf,
+						size_t count, loff_t *ppos)
+{
+	if (count) {
+		if (!nowayout) {
+			size_t i;
+
+			expect_close = 0;
+
+			for (i = 0; i != count; i++) {
+				char c;
+				if (get_user(c, buf + i))
+					return -EFAULT;
+				if (c == 'V')
+					expect_close = 42;
+			}
+		}
+		wdt_ping();
+	}
+	return count;
+}
+
+static long wdt_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	void __user *argp = (void __user *)arg;
+	int __user *p = argp;
+	int new_timeout;
+	static const struct watchdog_info ident = {
+		.options =		WDIOF_KEEPALIVEPING |
+					WDIOF_SETTIMEOUT |
+					WDIOF_MAGICCLOSE,
+		.firmware_version =	1,
+		.identity =		"W83697UG WDT",
+	};
+
+	switch (cmd) {
+	case WDIOC_GETSUPPORT:
+		if (copy_to_user(argp, &ident, sizeof(ident)))
+			return -EFAULT;
+		break;
+
+	case WDIOC_GETSTATUS:
+	case WDIOC_GETBOOTSTATUS:
+		return put_user(0, p);
+
+	case WDIOC_SETOPTIONS:
+	{
+		int options, retval = -EINVAL;
+
+		if (get_user(options, p))
+			return -EFAULT;
+
+		if (options & WDIOS_DISABLECARD) {
+			wdt_disable();
+			retval = 0;
+		}
+
+		if (options & WDIOS_ENABLECARD) {
+			wdt_ping();
+			retval = 0;
+		}
+
+		return retval;
+	}
+
+	case WDIOC_KEEPALIVE:
+		wdt_ping();
+		break;
+
+	case WDIOC_SETTIMEOUT:
+		if (get_user(new_timeout, p))
+			return -EFAULT;
+		if (wdt_set_heartbeat(new_timeout))
+			return -EINVAL;
+		wdt_ping();
+		/* Fall */
+
+	case WDIOC_GETTIMEOUT:
+		return put_user(timeout, p);
+
+	default:
+		return -ENOTTY;
+	}
+	return 0;
+}
+
+static int wdt_open(struct inode *inode, struct file *file)
+{
+	if (test_and_set_bit(0, &wdt_is_open))
+		return -EBUSY;
+	/*
+	 *	Activate
+	 */
+
+	wdt_ping();
+	return nonseekable_open(inode, file);
+}
+
+static int wdt_close(struct inode *inode, struct file *file)
+{
+	if (expect_close == 42)
+		wdt_disable();
+	else {
+		printk(KERN_CRIT PFX
+			"Unexpected close, not stopping watchdog!\n");
+		wdt_ping();
+	}
+	expect_close = 0;
+	clear_bit(0, &wdt_is_open);
+	return 0;
+}
+
+/*
+ *	Notifier for system down
+ */
+
+static int wdt_notify_sys(struct notifier_block *this, unsigned long code,
+	void *unused)
+{
+	if (code == SYS_DOWN || code == SYS_HALT)
+		wdt_disable();	/* Turn the WDT off */
+
+	return NOTIFY_DONE;
+}
+
+/*
+ *	Kernel Interfaces
+ */
+
+static const struct file_operations wdt_fops = {
+	.owner		= THIS_MODULE,
+	.llseek		= no_llseek,
+	.write		= wdt_write,
+	.unlocked_ioctl	= wdt_ioctl,
+	.open		= wdt_open,
+	.release	= wdt_close,
+};
+
+static struct miscdevice wdt_miscdev = {
+	.minor = WATCHDOG_MINOR,
+	.name = "watchdog",
+	.fops = &wdt_fops,
+};
+
+/*
+ *	The WDT needs to learn about soft shutdowns in order to
+ *	turn the timebomb registers off.
+ */
+
+static struct notifier_block wdt_notifier = {
+	.notifier_call = wdt_notify_sys,
+};
+
+static int __init wdt_init(void)
+{
+	int ret;
+
+	printk(KERN_INFO "WDT driver for the Winbond(TM) W83697UG/UF Super I/O chip initialising.\n");
+
+	if (wdt_set_heartbeat(timeout)) {
+		wdt_set_heartbeat(WATCHDOG_TIMEOUT);
+		printk(KERN_INFO PFX
+			"timeout value must be 1<=timeout<=255, using %d\n",
+			WATCHDOG_TIMEOUT);
+	}
+
+	if (!request_region(wdt_io, 1, WATCHDOG_NAME)) {
+		printk(KERN_ERR PFX "I/O address 0x%04x already in use\n",
+			wdt_io);
+		ret = -EIO;
+		goto out;
+	}
+
+	w83697ug_init();
+
+	ret = register_reboot_notifier(&wdt_notifier);
+	if (ret != 0) {
+		printk(KERN_ERR PFX
+			"cannot register reboot notifier (err=%d)\n", ret);
+		goto unreg_regions;
+	}
+
+	ret = misc_register(&wdt_miscdev);
+	if (ret != 0) {
+		printk(KERN_ERR PFX
+			"cannot register miscdev on minor=%d (err=%d)\n",
+			WATCHDOG_MINOR, ret);
+		goto unreg_reboot;
+	}
+
+	printk(KERN_INFO PFX "initialized. timeout=%d sec (nowayout=%d)\n",
+		timeout, nowayout);
+
+out:
+	return ret;
+unreg_reboot:
+	unregister_reboot_notifier(&wdt_notifier);
+unreg_regions:
+	release_region(wdt_io, 1);
+	goto out;
+}
+
+static void __exit wdt_exit(void)
+{
+	misc_deregister(&wdt_miscdev);
+	unregister_reboot_notifier(&wdt_notifier);
+	release_region(wdt_io, 1);
+}
+
+module_init(wdt_init);
+module_exit(wdt_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Flemming Frandsen <ff@nrvissing.net>");
+MODULE_DESCRIPTION("w83697ug/uf WDT driver");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/watchdog/wdt285.c b/drivers/watchdog/wdt285.c
index db362c3..191ea63 100644
--- a/drivers/watchdog/wdt285.c
+++ b/drivers/watchdog/wdt285.c
@@ -115,8 +115,8 @@
 	return 0;
 }
 
-static ssize_t watchdog_write(struct file *file, const char *data,
-						size_t len, loff_t *ppos)
+static ssize_t watchdog_write(struct file *file, const char __user *data,
+			      size_t len, loff_t *ppos)
 {
 	/*
 	 *	Refresh the timer.
@@ -133,21 +133,22 @@
 };
 
 static long watchdog_ioctl(struct file *file, unsigned int cmd,
-							unsigned long arg)
+			   unsigned long arg)
 {
 	unsigned int new_margin;
+	int __user *int_arg = (int __user *)arg;
 	int ret = -ENOTTY;
 
 	switch (cmd) {
 	case WDIOC_GETSUPPORT:
 		ret = 0;
-		if (copy_to_user((void *)arg, &ident, sizeof(ident)))
+		if (copy_to_user((void __user *)arg, &ident, sizeof(ident)))
 			ret = -EFAULT;
 		break;
 
 	case WDIOC_GETSTATUS:
 	case WDIOC_GETBOOTSTATUS:
-		ret = put_user(0, (int *)arg);
+		ret = put_user(0, int_arg);
 		break;
 
 	case WDIOC_KEEPALIVE:
@@ -156,7 +157,7 @@
 		break;
 
 	case WDIOC_SETTIMEOUT:
-		ret = get_user(new_margin, (int *)arg);
+		ret = get_user(new_margin, int_arg);
 		if (ret)
 			break;
 
@@ -171,7 +172,7 @@
 		watchdog_ping();
 		/* Fall */
 	case WDIOC_GETTIMEOUT:
-		ret = put_user(soft_margin, (int *)arg);
+		ret = put_user(soft_margin, int_arg);
 		break;
 	}
 	return ret;
diff --git a/drivers/xen/Makefile b/drivers/xen/Makefile
index 363286c..d2a8fdf 100644
--- a/drivers/xen/Makefile
+++ b/drivers/xen/Makefile
@@ -1,4 +1,5 @@
 obj-y	+= grant-table.o features.o events.o manage.o
 obj-y	+= xenbus/
+obj-$(CONFIG_HOTPLUG_CPU)	+= cpu_hotplug.o
 obj-$(CONFIG_XEN_XENCOMM)	+= xencomm.o
 obj-$(CONFIG_XEN_BALLOON)	+= balloon.o
diff --git a/drivers/xen/balloon.c b/drivers/xen/balloon.c
index 2e15da54..8c83abc 100644
--- a/drivers/xen/balloon.c
+++ b/drivers/xen/balloon.c
@@ -53,7 +53,6 @@
 #include <asm/tlb.h>
 
 #include <xen/interface/memory.h>
-#include <xen/balloon.h>
 #include <xen/xenbus.h>
 #include <xen/features.h>
 #include <xen/page.h>
@@ -226,9 +225,8 @@
 	}
 
 	set_xen_guest_handle(reservation.extent_start, frame_list);
-	reservation.nr_extents   = nr_pages;
-	rc = HYPERVISOR_memory_op(
-		XENMEM_populate_physmap, &reservation);
+	reservation.nr_extents = nr_pages;
+	rc = HYPERVISOR_memory_op(XENMEM_populate_physmap, &reservation);
 	if (rc < nr_pages) {
 		if (rc > 0) {
 			int ret;
@@ -236,7 +234,7 @@
 			/* We hit the Xen hard limit: reprobe. */
 			reservation.nr_extents = rc;
 			ret = HYPERVISOR_memory_op(XENMEM_decrease_reservation,
-					&reservation);
+						   &reservation);
 			BUG_ON(ret != rc);
 		}
 		if (rc >= 0)
@@ -420,7 +418,7 @@
 	unsigned long pfn;
 	struct page *page;
 
-	if (!is_running_on_xen())
+	if (!xen_pv_domain())
 		return -ENODEV;
 
 	pr_info("xen_balloon: Initialising balloon driver.\n");
@@ -464,136 +462,13 @@
 
 module_exit(balloon_exit);
 
-static void balloon_update_driver_allowance(long delta)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&balloon_lock, flags);
-	balloon_stats.driver_pages += delta;
-	spin_unlock_irqrestore(&balloon_lock, flags);
-}
-
-static int dealloc_pte_fn(
-	pte_t *pte, struct page *pmd_page, unsigned long addr, void *data)
-{
-	unsigned long mfn = pte_mfn(*pte);
-	int ret;
-	struct xen_memory_reservation reservation = {
-		.nr_extents   = 1,
-		.extent_order = 0,
-		.domid        = DOMID_SELF
-	};
-	set_xen_guest_handle(reservation.extent_start, &mfn);
-	set_pte_at(&init_mm, addr, pte, __pte_ma(0ull));
-	set_phys_to_machine(__pa(addr) >> PAGE_SHIFT, INVALID_P2M_ENTRY);
-	ret = HYPERVISOR_memory_op(XENMEM_decrease_reservation, &reservation);
-	BUG_ON(ret != 1);
-	return 0;
-}
-
-static struct page **alloc_empty_pages_and_pagevec(int nr_pages)
-{
-	unsigned long vaddr, flags;
-	struct page *page, **pagevec;
-	int i, ret;
-
-	pagevec = kmalloc(sizeof(page) * nr_pages, GFP_KERNEL);
-	if (pagevec == NULL)
-		return NULL;
-
-	for (i = 0; i < nr_pages; i++) {
-		page = pagevec[i] = alloc_page(GFP_KERNEL);
-		if (page == NULL)
-			goto err;
-
-		vaddr = (unsigned long)page_address(page);
-
-		scrub_page(page);
-
-		spin_lock_irqsave(&balloon_lock, flags);
-
-		if (xen_feature(XENFEAT_auto_translated_physmap)) {
-			unsigned long gmfn = page_to_pfn(page);
-			struct xen_memory_reservation reservation = {
-				.nr_extents   = 1,
-				.extent_order = 0,
-				.domid        = DOMID_SELF
-			};
-			set_xen_guest_handle(reservation.extent_start, &gmfn);
-			ret = HYPERVISOR_memory_op(XENMEM_decrease_reservation,
-						   &reservation);
-			if (ret == 1)
-				ret = 0; /* success */
-		} else {
-			ret = apply_to_page_range(&init_mm, vaddr, PAGE_SIZE,
-						  dealloc_pte_fn, NULL);
-		}
-
-		if (ret != 0) {
-			spin_unlock_irqrestore(&balloon_lock, flags);
-			__free_page(page);
-			goto err;
-		}
-
-		totalram_pages = --balloon_stats.current_pages;
-
-		spin_unlock_irqrestore(&balloon_lock, flags);
-	}
-
- out:
-	schedule_work(&balloon_worker);
-	flush_tlb_all();
-	return pagevec;
-
- err:
-	spin_lock_irqsave(&balloon_lock, flags);
-	while (--i >= 0)
-		balloon_append(pagevec[i]);
-	spin_unlock_irqrestore(&balloon_lock, flags);
-	kfree(pagevec);
-	pagevec = NULL;
-	goto out;
-}
-
-static void free_empty_pages_and_pagevec(struct page **pagevec, int nr_pages)
-{
-	unsigned long flags;
-	int i;
-
-	if (pagevec == NULL)
-		return;
-
-	spin_lock_irqsave(&balloon_lock, flags);
-	for (i = 0; i < nr_pages; i++) {
-		BUG_ON(page_count(pagevec[i]) != 1);
-		balloon_append(pagevec[i]);
-	}
-	spin_unlock_irqrestore(&balloon_lock, flags);
-
-	kfree(pagevec);
-
-	schedule_work(&balloon_worker);
-}
-
-static void balloon_release_driver_page(struct page *page)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&balloon_lock, flags);
-	balloon_append(page);
-	balloon_stats.driver_pages--;
-	spin_unlock_irqrestore(&balloon_lock, flags);
-
-	schedule_work(&balloon_worker);
-}
-
-
-#define BALLOON_SHOW(name, format, args...)			\
-	static ssize_t show_##name(struct sys_device *dev,	\
-				   char *buf)			\
-	{							\
-		return sprintf(buf, format, ##args);		\
-	}							\
+#define BALLOON_SHOW(name, format, args...)				\
+	static ssize_t show_##name(struct sys_device *dev,		\
+				   struct sysdev_attribute *attr,	\
+				   char *buf)				\
+	{								\
+		return sprintf(buf, format, ##args);			\
+	}								\
 	static SYSDEV_ATTR(name, S_IRUGO, show_##name, NULL)
 
 BALLOON_SHOW(current_kb, "%lu\n", PAGES2KB(balloon_stats.current_pages));
@@ -604,7 +479,8 @@
 	     (balloon_stats.hard_limit!=~0UL) ? PAGES2KB(balloon_stats.hard_limit) : 0);
 BALLOON_SHOW(driver_kb, "%lu\n", PAGES2KB(balloon_stats.driver_pages));
 
-static ssize_t show_target_kb(struct sys_device *dev, char *buf)
+static ssize_t show_target_kb(struct sys_device *dev, struct sysdev_attribute *attr,
+			      char *buf)
 {
 	return sprintf(buf, "%lu\n", PAGES2KB(balloon_stats.target_pages));
 }
@@ -614,19 +490,14 @@
 			       const char *buf,
 			       size_t count)
 {
-	char memstring[64], *endchar;
+	char *endchar;
 	unsigned long long target_bytes;
 
 	if (!capable(CAP_SYS_ADMIN))
 		return -EPERM;
 
-	if (count <= 1)
-		return -EBADMSG; /* runt */
-	if (count > sizeof(memstring))
-		return -EFBIG;   /* too long */
-	strcpy(memstring, buf);
+	target_bytes = memparse(buf, &endchar);
 
-	target_bytes = memparse(memstring, &endchar);
 	balloon_set_new_target(target_bytes >> PAGE_SHIFT);
 
 	return count;
@@ -694,20 +565,4 @@
 	return error;
 }
 
-static void unregister_balloon(struct sys_device *sysdev)
-{
-	int i;
-
-	sysfs_remove_group(&sysdev->kobj, &balloon_info_group);
-	for (i = 0; i < ARRAY_SIZE(balloon_attrs); i++)
-		sysdev_remove_file(sysdev, balloon_attrs[i]);
-	sysdev_unregister(sysdev);
-	sysdev_class_unregister(&balloon_sysdev_class);
-}
-
-static void balloon_sysfs_exit(void)
-{
-	unregister_balloon(&balloon_sysdev);
-}
-
 MODULE_LICENSE("GPL");
diff --git a/drivers/xen/cpu_hotplug.c b/drivers/xen/cpu_hotplug.c
new file mode 100644
index 0000000..565280ec
--- /dev/null
+++ b/drivers/xen/cpu_hotplug.c
@@ -0,0 +1,90 @@
+#include <linux/notifier.h>
+
+#include <xen/xenbus.h>
+
+#include <asm-x86/xen/hypervisor.h>
+#include <asm/cpu.h>
+
+static void enable_hotplug_cpu(int cpu)
+{
+	if (!cpu_present(cpu))
+		arch_register_cpu(cpu);
+
+	cpu_set(cpu, cpu_present_map);
+}
+
+static void disable_hotplug_cpu(int cpu)
+{
+	if (cpu_present(cpu))
+		arch_unregister_cpu(cpu);
+
+	cpu_clear(cpu, cpu_present_map);
+}
+
+static void vcpu_hotplug(unsigned int cpu)
+{
+	int err;
+	char dir[32], state[32];
+
+	if (!cpu_possible(cpu))
+		return;
+
+	sprintf(dir, "cpu/%u", cpu);
+	err = xenbus_scanf(XBT_NIL, dir, "availability", "%s", state);
+	if (err != 1) {
+		printk(KERN_ERR "XENBUS: Unable to read cpu state\n");
+		return;
+	}
+
+	if (strcmp(state, "online") == 0) {
+		enable_hotplug_cpu(cpu);
+	} else if (strcmp(state, "offline") == 0) {
+		(void)cpu_down(cpu);
+		disable_hotplug_cpu(cpu);
+	} else {
+		printk(KERN_ERR "XENBUS: unknown state(%s) on CPU%d\n",
+		       state, cpu);
+	}
+}
+
+static void handle_vcpu_hotplug_event(struct xenbus_watch *watch,
+					const char **vec, unsigned int len)
+{
+	unsigned int cpu;
+	char *cpustr;
+	const char *node = vec[XS_WATCH_PATH];
+
+	cpustr = strstr(node, "cpu/");
+	if (cpustr != NULL) {
+		sscanf(cpustr, "cpu/%u", &cpu);
+		vcpu_hotplug(cpu);
+	}
+}
+
+static int setup_cpu_watcher(struct notifier_block *notifier,
+			      unsigned long event, void *data)
+{
+	static struct xenbus_watch cpu_watch = {
+		.node = "cpu",
+		.callback = handle_vcpu_hotplug_event};
+
+	(void)register_xenbus_watch(&cpu_watch);
+
+	return NOTIFY_DONE;
+}
+
+static int __init setup_vcpu_hotplug_event(void)
+{
+	static struct notifier_block xsn_cpu = {
+		.notifier_call = setup_cpu_watcher };
+
+	if (!xen_pv_domain())
+		return -ENODEV;
+
+	register_xenstore_notifier(&xsn_cpu);
+
+	return 0;
+}
+
+arch_initcall(setup_vcpu_hotplug_event);
+
diff --git a/drivers/xen/events.c b/drivers/xen/events.c
index 0e0c285..c3290bc 100644
--- a/drivers/xen/events.c
+++ b/drivers/xen/events.c
@@ -84,17 +84,6 @@
 /* Xen will never allocate port zero for any purpose. */
 #define VALID_EVTCHN(chn)	((chn) != 0)
 
-/*
- * Force a proper event-channel callback from Xen after clearing the
- * callback mask. We do this in a very simple manner, by making a call
- * down into Xen. The pending flag will be checked by Xen on return.
- */
-void force_evtchn_callback(void)
-{
-	(void)HYPERVISOR_xen_version(0, NULL);
-}
-EXPORT_SYMBOL_GPL(force_evtchn_callback);
-
 static struct irq_chip xen_dynamic_chip;
 
 /* Constructor for packed IRQ information. */
@@ -175,6 +164,12 @@
 	sync_set_bit(port, &s->evtchn_pending[0]);
 }
 
+static inline int test_evtchn(int port)
+{
+	struct shared_info *s = HYPERVISOR_shared_info;
+	return sync_test_bit(port, &s->evtchn_pending[0]);
+}
+
 
 /**
  * notify_remote_via_irq - send event to remote end of event channel via irq
@@ -365,6 +360,10 @@
 			per_cpu(virq_to_irq, cpu_from_evtchn(evtchn))
 				[index_from_irq(irq)] = -1;
 			break;
+		case IRQT_IPI:
+			per_cpu(ipi_to_irq, cpu_from_evtchn(evtchn))
+				[index_from_irq(irq)] = -1;
+			break;
 		default:
 			break;
 		}
@@ -743,6 +742,25 @@
 		clear_evtchn(evtchn);
 }
 
+void xen_set_irq_pending(int irq)
+{
+	int evtchn = evtchn_from_irq(irq);
+
+	if (VALID_EVTCHN(evtchn))
+		set_evtchn(evtchn);
+}
+
+bool xen_test_irq_pending(int irq)
+{
+	int evtchn = evtchn_from_irq(irq);
+	bool ret = false;
+
+	if (VALID_EVTCHN(evtchn))
+		ret = test_evtchn(evtchn);
+
+	return ret;
+}
+
 /* Poll waiting for an irq to become pending.  In the usual case, the
    irq will be disabled so it won't deliver an interrupt. */
 void xen_poll_irq(int irq)
diff --git a/drivers/xen/grant-table.c b/drivers/xen/grant-table.c
index e9e1116..06592b9 100644
--- a/drivers/xen/grant-table.c
+++ b/drivers/xen/grant-table.c
@@ -508,7 +508,7 @@
 	unsigned int max_nr_glist_frames, nr_glist_frames;
 	unsigned int nr_init_grefs;
 
-	if (!is_running_on_xen())
+	if (!xen_domain())
 		return -ENODEV;
 
 	nr_grant_frames = 1;
diff --git a/drivers/xen/xenbus/xenbus_probe.c b/drivers/xen/xenbus/xenbus_probe.c
index 57ceb53..7f24a98 100644
--- a/drivers/xen/xenbus/xenbus_probe.c
+++ b/drivers/xen/xenbus/xenbus_probe.c
@@ -814,7 +814,7 @@
 	DPRINTK("");
 
 	err = -ENODEV;
-	if (!is_running_on_xen())
+	if (!xen_domain())
 		goto out_error;
 
 	/* Register ourselves with the kernel bus subsystem */
@@ -829,7 +829,7 @@
 	/*
 	 * Domain0 doesn't have a store_evtchn or store_mfn yet.
 	 */
-	if (is_initial_xendomain()) {
+	if (xen_initial_domain()) {
 		/* dom0 not yet supported */
 	} else {
 		xenstored_ready = 1;
@@ -846,7 +846,7 @@
 		goto out_unreg_back;
 	}
 
-	if (!is_initial_xendomain())
+	if (!xen_initial_domain())
 		xenbus_probe(NULL);
 
 	return 0;
@@ -937,7 +937,7 @@
 	unsigned long timeout = jiffies + 10*HZ;
 	struct device_driver *drv = xendrv ? &xendrv->driver : NULL;
 
-	if (!ready_to_wait_for_devices || !is_running_on_xen())
+	if (!ready_to_wait_for_devices || !xen_domain())
 		return;
 
 	while (exists_disconnected_device(drv)) {
diff --git a/firmware/Makefile b/firmware/Makefile
index da75a6f..ca8cd30 100644
--- a/firmware/Makefile
+++ b/firmware/Makefile
@@ -22,6 +22,7 @@
 
 fw-shipped-$(CONFIG_ATARI_DSP56K) += dsp56k/bootstrap.bin
 fw-shipped-$(CONFIG_ATM_AMBASSADOR) += atmsar11.fw
+fw-shipped-$(CONFIG_CASSINI) += sun/cassini.bin
 fw-shipped-$(CONFIG_COMPUTONE) += intelliport2.bin
 fw-shipped-$(CONFIG_DVB_TTUSB_BUDGET) += ttusb-budget/dspbootcode.bin
 fw-shipped-$(CONFIG_SMCTR) += tr_smctr.bin
diff --git a/firmware/WHENCE b/firmware/WHENCE
index 66c51b2..57002cd 100644
--- a/firmware/WHENCE
+++ b/firmware/WHENCE
@@ -339,3 +339,13 @@
 Found in hex form in kernel source.
 
 --------------------------------------------------------------------------
+
+Driver: CASSINI - Sun Cassini
+
+File: sun/cassini.bin
+
+Licence: Unknown
+
+Found in hex form in kernel source.
+
+--------------------------------------------------------------------------
diff --git a/firmware/sun/cassini.bin.ihex b/firmware/sun/cassini.bin.ihex
new file mode 100644
index 0000000..5cd7ae7
--- /dev/null
+++ b/firmware/sun/cassini.bin.ihex
@@ -0,0 +1,143 @@
+:1000000000827E82090000000000008E8EFFCE82FA
+:1000100025FF010FCE8426FF0111CE853DDFE58649
+:1000200039B78FF87EC3C2964784F38A009747CECC
+:100030008233FF010F9646840C8104270B96468479
+:100040000C810827577E8425964784F38A049747B6
+:10005000CE8254FF010F9646840C81042638B612D6
+:1000600020842026037E8425967BD67CFE8F56BD79
+:10007000F7B6FE8F4EBDEC8EBDFAF7BDF728CE82E7
+:1000800082FF010F9646840C8104260AB612208452
+:100090002027B57E8425BDF71F7E841F964784F3F5
+:1000A0008A089747DEE1AD00CE82AFFF010F7E8464
+:1000B00025964185102606962385402706BDED002E
+:1000C0007E83A2DE42BDEB8E9624840827037E83C6
+:1000D000DF967BD67CFE8F56BDF7B6FE8F50BDEC0B
+:1000E0008EBDFAF78611C649BDE412CE82EFFF013C
+:1000F0000F9646840C81002717C649BDE491240D54
+:10010000B612208520260CCE82C1FF010F7E8425E9
+:100110007E8416FE8F52BDEC8EBDFAF7866AC64904
+:10012000BDE412CE8327FF010F9646840C81002781
+:100130000AC649BDE49125067E84257E8416B6183C
+:1001400070BB19702A0481AF2E19967BF62007FA2E
+:100150002027C4388138270BF62007FA2027CB0840
+:100160007E82D3BDF7668674C649BDE412CE837124
+:10017000FF010F9646840C8108260AC649BDE4910A
+:1001800025067E84257E8416BDF73E260EBDE50934
+:100190002606CE82C1FF010F7E8425FE8F54BDEC62
+:1001A0008EBDFAF7BDF733860FC651BDE412CE837C
+:1001B000B2FF010F9646840C8108265CB61220849B
+:1001C0003F813A271C9623854027037E8425C6510C
+:1001D000BDE49125037E8425CE82C1FF010F7E847C
+:1001E00025BDF8377C007ACE83EEFF010F7E842593
+:1001F0009646840C81082620962484082629B61861
+:1002000082BB1982B1013B2209B6122084378132A8
+:100210002715BDF8447E82C1BDF71FBDF844BDFC63
+:1002200029CE8225FF010F39964784FC8A00974723
+:10023000CE8434FF011196468403810227037E8514
+:100240001E964784FC8A029747DEE1AD008601B71F
+:100250001251BDF714B6103184FDB71031BDF81E30
+:100260009681D682FE8F5ABDF7B6FE8F5CBDEC8EAE
+:10027000BDFAF78608D600C51026028B20C651BDF0
+:10028000E412CE8486FF011196468403810227037F
+:100290007E850FC651BDE49125037E851E9644855B
+:1002A00010260AB61250BA013C851027A8BDF76681
+:1002B000CE84B7FF01117E851E96468403810226F7
+:1002C00050B612308403810127037E851E96448533
+:1002D000102613B61250BA013C85102609CE84535D
+:1002E000FF01117E851EB610318A02B71031BD851F
+:1002F0001FBDF8377C0080CE84FEFF01117E851E75
+:100300009646840381022609B612308403810127B0
+:100310000FBDF844BDF70BBDFC29CE8426FF0111AB
+:1003200039D622C40FB61230BA12328404270D9681
+:100330002285042705CA107E853ACA20D72239862D
+:1003400000978318CE1C00BDEB4696578501270207
+:100350004F3985022701397F8F7D8604B7120486C5
+:1003600008B712078610B7120C8607B71206B68FA9
+:100370007DB712708601BA1204B71204010101019F
+:100380000101B6120484FE8A02B7120401010101C0
+:10039000010186FDB41204B71204B612008408816C
+:1003A000082716B68F7D810C27088B04B78F7D7EBA
+:1003B000856C860397407E896E8607B712065FF7C5
+:1003C0008F825FF78F7FF78F70F78F71F78F72F7DC
+:1003D0008F73F78F74F78F75F78F76F78F77F78FA7
+:1003E00078F78F79F78F7AF78F7BB612048A10B778
+:1003F000120486E4B71270B71207F71205F7120954
+:100400008608BA1204B7120486F7B41204B71204AD
+:10041000010101010101B61208277F8180260B86A8
+:1004200008CE8F79BD897B7E868E8140260B86041F
+:10043000CE8F76BD897B7E868E8120260B8602CE6E
+:100440008F73BD897B7E868E8110260B8601CE8FB1
+:1004500070BD897B7E868E8108260B8608CE8F79BB
+:10046000BD897F7E868E8104260B8604CE8F76BD65
+:10047000897F7E868E8102260B8A02CE8F73BD898C
+:100480007F7E868E810126088601CE8F70BD897F92
+:10049000B68F7F810F26037E8747B61209840381BA
+:1004A0000327067C12097E85FEB6120684078107A3
+:1004B00027088B01B712067E86D5B68F82260A7C66
+:1004C0008F824FB712067E85C0B61206843F813FE9
+:1004D00027108B08B71206B6120984FCB712097EE2
+:1004E00085FECE8F7018CE8F84C60CBD896FCE8FDF
+:1004F0008418CE8F70C60CBD896FD683C14F2D0373
+:100500007E8740B68F7F8107270F810B2715810DCE
+:10051000271B810E27217E8740F78F7B8602B78FAE
+:100520007A201CF78F788602B78F772012F78F75A5
+:100530008602B78F742008F78F728602B78F717E9C
+:100540008747860497407E896ECE8F72BD89F7CE2D
+:100550008F75BD89F7CE8F78BD89F7CE8F7BBD892A
+:10056000F74FB78F7DB78F81B68F7227477C8F7D0E
+:10057000B68F75273F7C8F7DB68F7827377C8F7D30
+:10058000B68F7B272F7F8F7D7C8F817A8F72271B81
+:100590007C8F7D7A8F7527167C8F7D7A8F782711D7
+:1005A0007C8F7D7A8F7B270C7E87837A8F757A8FFD
+:1005B000787A8F7BCEC1FCF68F7D3AA600B7127099
+:1005C000B68F7226037E87FAB68F75260A18CE8FED
+:1005D00073BD89D57E87FAB68F78260A18CE8F76B6
+:1005E000BD89D57E87FAB68F7B260A18CE8F79BD56
+:1005F00089D57E87FA860597407E8900B68F7581FA
+:10060000072EF2F61206C4F81BB71206B68F7881D1
+:10061000072EE2484848F61206C4C71BB71206B6B2
+:100620008F7B81072ECFF61205C4F81BB712058603
+:1006300000F68F71BD89948601F68F74BD8994860A
+:1006400002F68F77BD89948603F68F7ABD8994CEA2
+:100650008F70A60181012707810327037E8866A684
+:1006600000B88F818401260B8C8F792C0E08080826
+:100670007E8850B612048A40B71204B6120484FB76
+:1006800084EFB71204B6120736B68F7C4848B7120B
+:10069000078601BA1204B7120401010101010186A3
+:1006A000FEB41204B712048602BA1204B71204860A
+:1006B000FDB41204B7120432B71207B61200840850
+:1006C0008108270F7C82082607867697407E896EF0
+:1006D0007E86ECB68F7F810F273CBDE6C7B7120D33
+:1006E000BDE6CBB612048A20B71204CEFFFFB612C5
+:1006F00000810C26050926F6271CB6120484DFB7F4
+:100700001204968381072C057C0083200696838B38
+:100710000897837E85417F8F7E8680B7120C860185
+:10072000B78F7DB6120C847FB7120C8A80B7120C7B
+:10073000860ABD8A06B6120A2A09B6120CBA8F7D3D
+:10074000B7120CB68F7E8160271A8B20B78F7EB6CA
+:10075000120C849FBA8F7EB7120CB68F7D48B78F6C
+:100760007D7E8921B612048A20B71204BD8A0A4F01
+:1007700039A60018A7000818085A26F539366C0063
+:1007800032BA8F7FB78F7FB612098403A701B612E2
+:1007900006843FA70239368603B78F8032C1002610
+:1007A00006B78F7C7E89C9C1012718C102270CC1F9
+:1007B000032700F68F800505F78F80F68F800505EB
+:1007C000F78F80F68F800505F78F80F68F8053F4C2
+:1007D00012071BB7120739CE8F70A60018E6001853
+:1007E000A700E700A60118E60118A701E701A60285
+:1007F00018E60218A702E70239A6008407E600C43B
+:10080000385454541BA700394A26FD399622840FC8
+:1008100097228601B78F70B61207B78F71F6120C48
+:10082000C40FC80FF78F72F68F72B68F71840327CB
+:10083000148101271C81022724F48F70272A962215
+:100840008A807E8A64F48F70271E96228A107E8AA0
+:1008500064F48F70271296228A207E8A64F48F7047
+:10086000270696228A409722748F71748F71788F31
+:1008700070B68F70851027AFD622C41058B612708C
+:1008800081E4273681E1260C96228420441BD6225F
+:10089000C4CF20235881C6260D9622844044441B91
+:1008A000D622C4AF2011588127260F962284804477
+:1008B00044441BD622C46F1B972239270C7C820626
+:0D08C000BDD9EDB682077E8AB97F82063968
+:00000001FF
+/* firmware patch for NS_DP83065 */
diff --git a/fs/9p/v9fs.c b/fs/9p/v9fs.c
index 047c791..c061c3f 100644
--- a/fs/9p/v9fs.c
+++ b/fs/9p/v9fs.c
@@ -55,7 +55,7 @@
 	Opt_err
 };
 
-static match_table_t tokens = {
+static const match_table_t tokens = {
 	{Opt_debug, "debug=%x"},
 	{Opt_dfltuid, "dfltuid=%u"},
 	{Opt_dfltgid, "dfltgid=%u"},
diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c
index c95295c..e83aa5e 100644
--- a/fs/9p/vfs_inode.c
+++ b/fs/9p/vfs_inode.c
@@ -626,8 +626,7 @@
 	return NULL;
 
 error:
-	if (fid)
-		p9_client_clunk(fid);
+	p9_client_clunk(fid);
 
 	return ERR_PTR(result);
 }
diff --git a/fs/Kconfig b/fs/Kconfig
index abccb5d..9e9d70c 100644
--- a/fs/Kconfig
+++ b/fs/Kconfig
@@ -136,37 +136,51 @@
 	  If you are not using a security module that requires using
 	  extended attributes for file security labels, say N.
 
-config EXT4DEV_FS
-	tristate "Ext4dev/ext4 extended fs support development (EXPERIMENTAL)"
-	depends on EXPERIMENTAL
+config EXT4_FS
+	tristate "The Extended 4 (ext4) filesystem"
 	select JBD2
 	select CRC16
 	help
-	  Ext4dev is a predecessor filesystem of the next generation
-	  extended fs ext4, based on ext3 filesystem code. It will be
-	  renamed ext4 fs later, once ext4dev is mature and stabilized.
+	  This is the next generation of the ext3 filesystem.
 
 	  Unlike the change from ext2 filesystem to ext3 filesystem,
-	  the on-disk format of ext4dev is not the same as ext3 any more:
-	  it is based on extent maps and it supports 48-bit physical block
-	  numbers. These combined on-disk format changes will allow
-	  ext4dev/ext4 to handle more than 16 TB filesystem volumes --
-	  a hard limit that ext3 cannot overcome without changing the
-	  on-disk format.
+	  the on-disk format of ext4 is not forwards compatible with
+	  ext3; it is based on extent maps and it supports 48-bit
+	  physical block numbers.  The ext4 filesystem also supports delayed
+	  allocation, persistent preallocation, high resolution time stamps,
+	  and a number of other features to improve performance and speed
+	  up fsck time.  For more information, please see the web pages at
+	  http://ext4.wiki.kernel.org.
 
-	  Other than extent maps and 48-bit block numbers, ext4dev also is
-	  likely to have other new features such as persistent preallocation,
-	  high resolution time stamps, and larger file support etc.  These
-	  features will be added to ext4dev gradually.
+	  The ext4 filesystem will support mounting an ext3
+	  filesystem; while there will be some performance gains from
+	  the delayed allocation and inode table readahead, the best
+	  performance gains will require enabling ext4 features in the
+	  filesystem, or formating a new filesystem as an ext4
+	  filesystem initially.
 
 	  To compile this file system support as a module, choose M here. The
 	  module will be called ext4dev.
 
 	  If unsure, say N.
 
-config EXT4DEV_FS_XATTR
-	bool "Ext4dev extended attributes"
-	depends on EXT4DEV_FS
+config EXT4DEV_COMPAT
+	bool "Enable ext4dev compatibility"
+	depends on EXT4_FS
+	help
+	  Starting with 2.6.28, the name of the ext4 filesystem was
+	  renamed from ext4dev to ext4.  Unfortunately there are some
+	  legacy userspace programs (such as klibc's fstype) have
+	  "ext4dev" hardcoded.
+
+	  To enable backwards compatibility so that systems that are
+	  still expecting to mount ext4 filesystems using ext4dev,
+	  chose Y here.   This feature will go away by 2.6.31, so
+	  please arrange to get your userspace programs fixed!
+
+config EXT4_FS_XATTR
+	bool "Ext4 extended attributes"
+	depends on EXT4_FS
 	default y
 	help
 	  Extended attributes are name:value pairs associated with inodes by
@@ -175,11 +189,11 @@
 
 	  If unsure, say N.
 
-	  You need this for POSIX ACL support on ext4dev/ext4.
+	  You need this for POSIX ACL support on ext4.
 
-config EXT4DEV_FS_POSIX_ACL
-	bool "Ext4dev POSIX Access Control Lists"
-	depends on EXT4DEV_FS_XATTR
+config EXT4_FS_POSIX_ACL
+	bool "Ext4 POSIX Access Control Lists"
+	depends on EXT4_FS_XATTR
 	select FS_POSIX_ACL
 	help
 	  POSIX Access Control Lists (ACLs) support permissions for users and
@@ -190,14 +204,14 @@
 
 	  If you don't know what Access Control Lists are, say N
 
-config EXT4DEV_FS_SECURITY
-	bool "Ext4dev Security Labels"
-	depends on EXT4DEV_FS_XATTR
+config EXT4_FS_SECURITY
+	bool "Ext4 Security Labels"
+	depends on EXT4_FS_XATTR
 	help
 	  Security labels support alternative access control models
 	  implemented by security modules like SELinux.  This option
 	  enables an extended attribute handler for file security
-	  labels in the ext4dev/ext4 filesystem.
+	  labels in the ext4 filesystem.
 
 	  If you are not using a security module that requires using
 	  extended attributes for file security labels, say N.
@@ -206,17 +220,16 @@
 	tristate
 	help
 	  This is a generic journalling layer for block devices.  It is
-	  currently used by the ext3 and OCFS2 file systems, but it could
-	  also be used to add journal support to other file systems or block
+	  currently used by the ext3 file system, but it could also be
+	  used to add journal support to other file systems or block
 	  devices such as RAID or LVM.
 
-	  If you are using the ext3 or OCFS2 file systems, you need to
-	  say Y here. If you are not using ext3 OCFS2 then you will probably
-	  want to say N.
+	  If you are using the ext3 file system, you need to say Y here.
+	  If you are not using ext3 then you will probably want to say N.
 
 	  To compile this device as a module, choose M here: the module will be
-	  called jbd.  If you are compiling ext3 or OCFS2 into the kernel,
-	  you cannot compile this code as a module.
+	  called jbd.  If you are compiling ext3 into the kernel, you
+	  cannot compile this code as a module.
 
 config JBD_DEBUG
 	bool "JBD (ext3) debugging support"
@@ -240,22 +253,23 @@
 	help
 	  This is a generic journaling layer for block devices that support
 	  both 32-bit and 64-bit block numbers.  It is currently used by
-	  the ext4dev/ext4 filesystem, but it could also be used to add
+	  the ext4 and OCFS2 filesystems, but it could also be used to add
 	  journal support to other file systems or block devices such
 	  as RAID or LVM.
 
-	  If you are using ext4dev/ext4, you need to say Y here. If you are not
-	  using ext4dev/ext4 then you will probably want to say N.
+	  If you are using ext4 or OCFS2, you need to say Y here.
+	  If you are not using ext4 or OCFS2 then you will
+	  probably want to say N.
 
 	  To compile this device as a module, choose M here. The module will be
-	  called jbd2.  If you are compiling ext4dev/ext4 into the kernel,
+	  called jbd2.  If you are compiling ext4 or OCFS2 into the kernel,
 	  you cannot compile this code as a module.
 
 config JBD2_DEBUG
-	bool "JBD2 (ext4dev/ext4) debugging support"
+	bool "JBD2 (ext4) debugging support"
 	depends on JBD2 && DEBUG_FS
 	help
-	  If you are using the ext4dev/ext4 journaled file system (or
+	  If you are using the ext4 journaled file system (or
 	  potentially any other filesystem/device using JBD2), this option
 	  allows you to enable debugging output while the system is running,
 	  in order to help track down any problems you are having.
@@ -270,9 +284,9 @@
 config FS_MBCACHE
 # Meta block cache for Extended Attributes (ext2/ext3/ext4)
 	tristate
-	depends on EXT2_FS_XATTR || EXT3_FS_XATTR || EXT4DEV_FS_XATTR
-	default y if EXT2_FS=y || EXT3_FS=y || EXT4DEV_FS=y
-	default m if EXT2_FS=m || EXT3_FS=m || EXT4DEV_FS=m
+	depends on EXT2_FS_XATTR || EXT3_FS_XATTR || EXT4_FS_XATTR
+	default y if EXT2_FS=y || EXT3_FS=y || EXT4_FS=y
+	default m if EXT2_FS=m || EXT3_FS=m || EXT4_FS=m
 
 config REISERFS_FS
 	tristate "Reiserfs support"
@@ -419,6 +433,14 @@
 	bool
 	default n
 
+config FILE_LOCKING
+	bool "Enable POSIX file locking API" if EMBEDDED
+	default y
+	help
+	  This option enables standard file locking support, required
+          for filesystems like NFS and for the flock() system
+          call. Disabling this option saves about 11k.
+
 source "fs/xfs/Kconfig"
 source "fs/gfs2/Kconfig"
 
@@ -426,7 +448,7 @@
 	tristate "OCFS2 file system support"
 	depends on NET && SYSFS
 	select CONFIGFS_FS
-	select JBD
+	select JBD2
 	select CRC32
 	help
 	  OCFS2 is a general purpose extent based shared disk cluster file
@@ -497,6 +519,16 @@
 	  this option for debugging only as it is likely to decrease
 	  performance of the filesystem.
 
+config OCFS2_COMPAT_JBD
+	bool "Use JBD for compatibility"
+	depends on OCFS2_FS
+	default n
+	select JBD
+	help
+	  The ocfs2 filesystem now uses JBD2 for its journalling.  JBD2
+	  is backwards compatible with JBD.  It is safe to say N here.
+	  However, if you really want to use the original JBD, say Y here.
+
 endif # BLOCK
 
 config DNOTIFY
@@ -1765,6 +1797,28 @@
 
 	  If unsure, say N.
 
+config SUNRPC_REGISTER_V4
+	bool "Register local RPC services via rpcbind v4 (EXPERIMENTAL)"
+	depends on SUNRPC && EXPERIMENTAL
+	default n
+	help
+	  Sun added support for registering RPC services at an IPv6
+	  address by creating two new versions of the rpcbind protocol
+	  (RFC 1833).
+
+	  This option enables support in the kernel RPC server for
+	  registering kernel RPC services via version 4 of the rpcbind
+	  protocol.  If you enable this option, you must run a portmapper
+	  daemon that supports rpcbind protocol version 4.
+
+	  Serving NFS over IPv6 from knfsd (the kernel's NFS server)
+	  requires that you enable this option and use a portmapper that
+	  supports rpcbind version 4.
+
+	  If unsure, say N to get traditional behavior (register kernel
+	  RPC services using only rpcbind version 2).  Distributions
+	  using the legacy Linux portmapper daemon must say N here.
+
 config RPCSEC_GSS_KRB5
 	tristate "Secure RPC: Kerberos V mechanism (EXPERIMENTAL)"
 	depends on SUNRPC && EXPERIMENTAL
diff --git a/fs/Kconfig.binfmt b/fs/Kconfig.binfmt
index 4a551af..17c9c5e 100644
--- a/fs/Kconfig.binfmt
+++ b/fs/Kconfig.binfmt
@@ -59,10 +59,12 @@
 	help
 	  Support FLAT shared libraries
 
+config HAVE_AOUT
+       def_bool n
+
 config BINFMT_AOUT
 	tristate "Kernel support for a.out and ECOFF binaries"
-	depends on ARCH_SUPPORTS_AOUT && \
-		(X86_32 || ALPHA || ARM || M68K)
+	depends on HAVE_AOUT
 	---help---
 	  A.out (Assembler.OUTput) is a set of formats for libraries and
 	  executables used in the earliest versions of UNIX.  Linux used
diff --git a/fs/Makefile b/fs/Makefile
index a1482a5..b6f27dc 100644
--- a/fs/Makefile
+++ b/fs/Makefile
@@ -7,7 +7,7 @@
 
 obj-y :=	open.o read_write.o file_table.o super.o \
 		char_dev.o stat.o exec.o pipe.o namei.o fcntl.o \
-		ioctl.o readdir.o select.o fifo.o locks.o dcache.o inode.o \
+		ioctl.o readdir.o select.o fifo.o dcache.o inode.o \
 		attr.o bad_inode.o file.o filesystems.o namespace.o aio.o \
 		seq_file.o xattr.o libfs.o fs-writeback.o \
 		pnode.o drop_caches.o splice.o sync.o utimes.o \
@@ -27,6 +27,7 @@
 obj-$(CONFIG_SIGNALFD)		+= signalfd.o
 obj-$(CONFIG_TIMERFD)		+= timerfd.o
 obj-$(CONFIG_EVENTFD)		+= eventfd.o
+obj-$(CONFIG_FILE_LOCKING)      += locks.o
 obj-$(CONFIG_COMPAT)		+= compat.o compat_ioctl.o
 
 nfsd-$(CONFIG_NFSD)		:= nfsctl.o
@@ -69,7 +70,7 @@
 # Do not add any filesystems before this line
 obj-$(CONFIG_REISERFS_FS)	+= reiserfs/
 obj-$(CONFIG_EXT3_FS)		+= ext3/ # Before ext2 so root fs can be ext3
-obj-$(CONFIG_EXT4DEV_FS)	+= ext4/ # Before ext2 so root fs can be ext4dev
+obj-$(CONFIG_EXT4_FS)		+= ext4/ # Before ext2 so root fs can be ext4dev
 obj-$(CONFIG_JBD)		+= jbd/
 obj-$(CONFIG_JBD2)		+= jbd2/
 obj-$(CONFIG_EXT2_FS)		+= ext2/
diff --git a/fs/adfs/super.c b/fs/adfs/super.c
index 26f3b43..7f83a46 100644
--- a/fs/adfs/super.c
+++ b/fs/adfs/super.c
@@ -157,7 +157,7 @@
 
 enum {Opt_uid, Opt_gid, Opt_ownmask, Opt_othmask, Opt_err};
 
-static match_table_t tokens = {
+static const match_table_t tokens = {
 	{Opt_uid, "uid=%u"},
 	{Opt_gid, "gid=%u"},
 	{Opt_ownmask, "ownmask=%o"},
diff --git a/fs/affs/super.c b/fs/affs/super.c
index 3a89094..8989c93 100644
--- a/fs/affs/super.c
+++ b/fs/affs/super.c
@@ -135,7 +135,7 @@
 	Opt_verbose, Opt_volume, Opt_ignore, Opt_err,
 };
 
-static match_table_t tokens = {
+static const match_table_t tokens = {
 	{Opt_bs, "bs=%u"},
 	{Opt_mode, "mode=%o"},
 	{Opt_mufs, "mufs"},
diff --git a/fs/afs/super.c b/fs/afs/super.c
index 250d8c4..aee239a 100644
--- a/fs/afs/super.c
+++ b/fs/afs/super.c
@@ -64,7 +64,7 @@
 	afs_opt_vol,
 };
 
-static match_table_t afs_options_list = {
+static const match_table_t afs_options_list = {
 	{ afs_opt_cell,		"cell=%s"	},
 	{ afs_opt_rwpath,	"rwpath"	},
 	{ afs_opt_vol,		"vol=%s"	},
diff --git a/fs/autofs/inode.c b/fs/autofs/inode.c
index dda510d..b70eea1 100644
--- a/fs/autofs/inode.c
+++ b/fs/autofs/inode.c
@@ -59,7 +59,7 @@
 
 enum {Opt_err, Opt_fd, Opt_uid, Opt_gid, Opt_pgrp, Opt_minproto, Opt_maxproto};
 
-static match_table_t autofs_tokens = {
+static const match_table_t autofs_tokens = {
 	{Opt_fd, "fd=%u"},
 	{Opt_uid, "uid=%u"},
 	{Opt_gid, "gid=%u"},
diff --git a/fs/autofs4/inode.c b/fs/autofs4/inode.c
index 7bb3e5b..45d5581 100644
--- a/fs/autofs4/inode.c
+++ b/fs/autofs4/inode.c
@@ -213,7 +213,7 @@
 enum {Opt_err, Opt_fd, Opt_uid, Opt_gid, Opt_pgrp, Opt_minproto, Opt_maxproto,
 	Opt_indirect, Opt_direct, Opt_offset};
 
-static match_table_t tokens = {
+static const match_table_t tokens = {
 	{Opt_fd, "fd=%u"},
 	{Opt_uid, "uid=%u"},
 	{Opt_gid, "gid=%u"},
diff --git a/fs/befs/linuxvfs.c b/fs/befs/linuxvfs.c
index 740f536..9286b2a 100644
--- a/fs/befs/linuxvfs.c
+++ b/fs/befs/linuxvfs.c
@@ -650,7 +650,7 @@
 	Opt_uid, Opt_gid, Opt_charset, Opt_debug, Opt_err,
 };
 
-static match_table_t befs_tokens = {
+static const match_table_t befs_tokens = {
 	{Opt_uid, "uid=%d"},
 	{Opt_gid, "gid=%d"},
 	{Opt_charset, "iocharset=%s"},
diff --git a/fs/bio-integrity.c b/fs/bio-integrity.c
index c3e174b..19caf7c 100644
--- a/fs/bio-integrity.c
+++ b/fs/bio-integrity.c
@@ -107,7 +107,8 @@
 	BUG_ON(bip == NULL);
 
 	/* A cloned bio doesn't own the integrity metadata */
-	if (!bio_flagged(bio, BIO_CLONED) && bip->bip_buf != NULL)
+	if (!bio_flagged(bio, BIO_CLONED) && !bio_flagged(bio, BIO_FS_INTEGRITY)
+	    && bip->bip_buf != NULL)
 		kfree(bip->bip_buf);
 
 	mempool_free(bip->bip_vec, bs->bvec_pools[bip->bip_pool]);
@@ -150,6 +151,24 @@
 }
 EXPORT_SYMBOL(bio_integrity_add_page);
 
+static int bdev_integrity_enabled(struct block_device *bdev, int rw)
+{
+	struct blk_integrity *bi = bdev_get_integrity(bdev);
+
+	if (bi == NULL)
+		return 0;
+
+	if (rw == READ && bi->verify_fn != NULL &&
+	    (bi->flags & INTEGRITY_FLAG_READ))
+		return 1;
+
+	if (rw == WRITE && bi->generate_fn != NULL &&
+	    (bi->flags & INTEGRITY_FLAG_WRITE))
+		return 1;
+
+	return 0;
+}
+
 /**
  * bio_integrity_enabled - Check whether integrity can be passed
  * @bio:	bio to check
@@ -313,6 +332,14 @@
 	}
 }
 
+static inline unsigned short blk_integrity_tuple_size(struct blk_integrity *bi)
+{
+	if (bi)
+		return bi->tuple_size;
+
+	return 0;
+}
+
 /**
  * bio_integrity_prep - Prepare bio for integrity I/O
  * @bio:	bio to prepare
diff --git a/fs/bio.c b/fs/bio.c
index 3cba7ae..77a55bc 100644
--- a/fs/bio.c
+++ b/fs/bio.c
@@ -30,7 +30,7 @@
 
 static struct kmem_cache *bio_slab __read_mostly;
 
-mempool_t *bio_split_pool __read_mostly;
+static mempool_t *bio_split_pool __read_mostly;
 
 /*
  * if you change this list, also change bvec_alloc or things will
@@ -60,25 +60,46 @@
 	struct bio_vec *bvl;
 
 	/*
-	 * see comment near bvec_array define!
+	 * If 'bs' is given, lookup the pool and do the mempool alloc.
+	 * If not, this is a bio_kmalloc() allocation and just do a
+	 * kzalloc() for the exact number of vecs right away.
 	 */
-	switch (nr) {
-		case   1        : *idx = 0; break;
-		case   2 ...   4: *idx = 1; break;
-		case   5 ...  16: *idx = 2; break;
-		case  17 ...  64: *idx = 3; break;
-		case  65 ... 128: *idx = 4; break;
-		case 129 ... BIO_MAX_PAGES: *idx = 5; break;
+	if (bs) {
+		/*
+		 * see comment near bvec_array define!
+		 */
+		switch (nr) {
+		case 1:
+			*idx = 0;
+			break;
+		case 2 ... 4:
+			*idx = 1;
+			break;
+		case 5 ... 16:
+			*idx = 2;
+			break;
+		case 17 ... 64:
+			*idx = 3;
+			break;
+		case 65 ... 128:
+			*idx = 4;
+			break;
+		case 129 ... BIO_MAX_PAGES:
+			*idx = 5;
+			break;
 		default:
 			return NULL;
-	}
-	/*
-	 * idx now points to the pool we want to allocate from
-	 */
+		}
 
-	bvl = mempool_alloc(bs->bvec_pools[*idx], gfp_mask);
-	if (bvl)
-		memset(bvl, 0, bvec_nr_vecs(*idx) * sizeof(struct bio_vec));
+		/*
+		 * idx now points to the pool we want to allocate from
+		 */
+		bvl = mempool_alloc(bs->bvec_pools[*idx], gfp_mask);
+		if (bvl)
+			memset(bvl, 0,
+				bvec_nr_vecs(*idx) * sizeof(struct bio_vec));
+	} else
+		bvl = kzalloc(nr * sizeof(struct bio_vec), gfp_mask);
 
 	return bvl;
 }
@@ -107,10 +128,17 @@
 	bio_free(bio, fs_bio_set);
 }
 
+static void bio_kmalloc_destructor(struct bio *bio)
+{
+	kfree(bio->bi_io_vec);
+	kfree(bio);
+}
+
 void bio_init(struct bio *bio)
 {
 	memset(bio, 0, sizeof(*bio));
 	bio->bi_flags = 1 << BIO_UPTODATE;
+	bio->bi_comp_cpu = -1;
 	atomic_set(&bio->bi_cnt, 1);
 }
 
@@ -118,19 +146,25 @@
  * bio_alloc_bioset - allocate a bio for I/O
  * @gfp_mask:   the GFP_ mask given to the slab allocator
  * @nr_iovecs:	number of iovecs to pre-allocate
- * @bs:		the bio_set to allocate from
+ * @bs:		the bio_set to allocate from. If %NULL, just use kmalloc
  *
  * Description:
- *   bio_alloc_bioset will first try it's on mempool to satisfy the allocation.
+ *   bio_alloc_bioset will first try its own mempool to satisfy the allocation.
  *   If %__GFP_WAIT is set then we will block on the internal pool waiting
- *   for a &struct bio to become free.
+ *   for a &struct bio to become free. If a %NULL @bs is passed in, we will
+ *   fall back to just using @kmalloc to allocate the required memory.
  *
  *   allocate bio and iovecs from the memory pools specified by the
- *   bio_set structure.
+ *   bio_set structure, or @kmalloc if none given.
  **/
 struct bio *bio_alloc_bioset(gfp_t gfp_mask, int nr_iovecs, struct bio_set *bs)
 {
-	struct bio *bio = mempool_alloc(bs->bio_pool, gfp_mask);
+	struct bio *bio;
+
+	if (bs)
+		bio = mempool_alloc(bs->bio_pool, gfp_mask);
+	else
+		bio = kmalloc(sizeof(*bio), gfp_mask);
 
 	if (likely(bio)) {
 		struct bio_vec *bvl = NULL;
@@ -141,7 +175,10 @@
 
 			bvl = bvec_alloc_bs(gfp_mask, nr_iovecs, &idx, bs);
 			if (unlikely(!bvl)) {
-				mempool_free(bio, bs->bio_pool);
+				if (bs)
+					mempool_free(bio, bs->bio_pool);
+				else
+					kfree(bio);
 				bio = NULL;
 				goto out;
 			}
@@ -164,6 +201,23 @@
 	return bio;
 }
 
+/*
+ * Like bio_alloc(), but doesn't use a mempool backing. This means that
+ * it CAN fail, but while bio_alloc() can only be used for allocations
+ * that have a short (finite) life span, bio_kmalloc() should be used
+ * for more permanent bio allocations (like allocating some bio's for
+ * initalization or setup purposes).
+ */
+struct bio *bio_kmalloc(gfp_t gfp_mask, int nr_iovecs)
+{
+	struct bio *bio = bio_alloc_bioset(gfp_mask, nr_iovecs, NULL);
+
+	if (bio)
+		bio->bi_destructor = bio_kmalloc_destructor;
+
+	return bio;
+}
+
 void zero_fill_bio(struct bio *bio)
 {
 	unsigned long flags;
@@ -208,14 +262,6 @@
 	return bio->bi_phys_segments;
 }
 
-inline int bio_hw_segments(struct request_queue *q, struct bio *bio)
-{
-	if (unlikely(!bio_flagged(bio, BIO_SEG_VALID)))
-		blk_recount_segments(q, bio);
-
-	return bio->bi_hw_segments;
-}
-
 /**
  * 	__bio_clone	-	clone a bio
  * 	@bio: destination bio
@@ -350,8 +396,7 @@
 	 */
 
 	while (bio->bi_phys_segments >= q->max_phys_segments
-	       || bio->bi_hw_segments >= q->max_hw_segments
-	       || BIOVEC_VIRT_OVERSIZE(bio->bi_size)) {
+	       || bio->bi_phys_segments >= q->max_hw_segments) {
 
 		if (retried_segments)
 			return 0;
@@ -395,13 +440,11 @@
 	}
 
 	/* If we may be able to merge these biovecs, force a recount */
-	if (bio->bi_vcnt && (BIOVEC_PHYS_MERGEABLE(bvec-1, bvec) ||
-	    BIOVEC_VIRT_MERGEABLE(bvec-1, bvec)))
+	if (bio->bi_vcnt && (BIOVEC_PHYS_MERGEABLE(bvec-1, bvec)))
 		bio->bi_flags &= ~(1 << BIO_SEG_VALID);
 
 	bio->bi_vcnt++;
 	bio->bi_phys_segments++;
-	bio->bi_hw_segments++;
  done:
 	bio->bi_size += len;
 	return len;
@@ -449,16 +492,19 @@
 
 struct bio_map_data {
 	struct bio_vec *iovecs;
-	int nr_sgvecs;
 	struct sg_iovec *sgvecs;
+	int nr_sgvecs;
+	int is_our_pages;
 };
 
 static void bio_set_map_data(struct bio_map_data *bmd, struct bio *bio,
-			     struct sg_iovec *iov, int iov_count)
+			     struct sg_iovec *iov, int iov_count,
+			     int is_our_pages)
 {
 	memcpy(bmd->iovecs, bio->bi_io_vec, sizeof(struct bio_vec) * bio->bi_vcnt);
 	memcpy(bmd->sgvecs, iov, sizeof(struct sg_iovec) * iov_count);
 	bmd->nr_sgvecs = iov_count;
+	bmd->is_our_pages = is_our_pages;
 	bio->bi_private = bmd;
 }
 
@@ -493,7 +539,8 @@
 }
 
 static int __bio_copy_iov(struct bio *bio, struct bio_vec *iovecs,
-			  struct sg_iovec *iov, int iov_count, int uncopy)
+			  struct sg_iovec *iov, int iov_count, int uncopy,
+			  int do_free_page)
 {
 	int ret = 0, i;
 	struct bio_vec *bvec;
@@ -536,7 +583,7 @@
 			}
 		}
 
-		if (uncopy)
+		if (do_free_page)
 			__free_page(bvec->bv_page);
 	}
 
@@ -553,10 +600,11 @@
 int bio_uncopy_user(struct bio *bio)
 {
 	struct bio_map_data *bmd = bio->bi_private;
-	int ret;
+	int ret = 0;
 
-	ret = __bio_copy_iov(bio, bmd->iovecs, bmd->sgvecs, bmd->nr_sgvecs, 1);
-
+	if (!bio_flagged(bio, BIO_NULL_MAPPED))
+		ret = __bio_copy_iov(bio, bmd->iovecs, bmd->sgvecs,
+				     bmd->nr_sgvecs, 1, bmd->is_our_pages);
 	bio_free_map_data(bmd);
 	bio_put(bio);
 	return ret;
@@ -565,16 +613,20 @@
 /**
  *	bio_copy_user_iov	-	copy user data to bio
  *	@q: destination block queue
+ *	@map_data: pointer to the rq_map_data holding pages (if necessary)
  *	@iov:	the iovec.
  *	@iov_count: number of elements in the iovec
  *	@write_to_vm: bool indicating writing to pages or not
+ *	@gfp_mask: memory allocation flags
  *
  *	Prepares and returns a bio for indirect user io, bouncing data
  *	to/from kernel pages as necessary. Must be paired with
  *	call bio_uncopy_user() on io completion.
  */
-struct bio *bio_copy_user_iov(struct request_queue *q, struct sg_iovec *iov,
-			      int iov_count, int write_to_vm)
+struct bio *bio_copy_user_iov(struct request_queue *q,
+			      struct rq_map_data *map_data,
+			      struct sg_iovec *iov, int iov_count,
+			      int write_to_vm, gfp_t gfp_mask)
 {
 	struct bio_map_data *bmd;
 	struct bio_vec *bvec;
@@ -597,25 +649,38 @@
 		len += iov[i].iov_len;
 	}
 
-	bmd = bio_alloc_map_data(nr_pages, iov_count, GFP_KERNEL);
+	bmd = bio_alloc_map_data(nr_pages, iov_count, gfp_mask);
 	if (!bmd)
 		return ERR_PTR(-ENOMEM);
 
 	ret = -ENOMEM;
-	bio = bio_alloc(GFP_KERNEL, nr_pages);
+	bio = bio_alloc(gfp_mask, nr_pages);
 	if (!bio)
 		goto out_bmd;
 
 	bio->bi_rw |= (!write_to_vm << BIO_RW);
 
 	ret = 0;
+	i = 0;
 	while (len) {
-		unsigned int bytes = PAGE_SIZE;
+		unsigned int bytes;
+
+		if (map_data)
+			bytes = 1U << (PAGE_SHIFT + map_data->page_order);
+		else
+			bytes = PAGE_SIZE;
 
 		if (bytes > len)
 			bytes = len;
 
-		page = alloc_page(q->bounce_gfp | GFP_KERNEL);
+		if (map_data) {
+			if (i == map_data->nr_entries) {
+				ret = -ENOMEM;
+				break;
+			}
+			page = map_data->pages[i++];
+		} else
+			page = alloc_page(q->bounce_gfp | gfp_mask);
 		if (!page) {
 			ret = -ENOMEM;
 			break;
@@ -634,16 +699,17 @@
 	 * success
 	 */
 	if (!write_to_vm) {
-		ret = __bio_copy_iov(bio, bio->bi_io_vec, iov, iov_count, 0);
+		ret = __bio_copy_iov(bio, bio->bi_io_vec, iov, iov_count, 0, 0);
 		if (ret)
 			goto cleanup;
 	}
 
-	bio_set_map_data(bmd, bio, iov, iov_count);
+	bio_set_map_data(bmd, bio, iov, iov_count, map_data ? 0 : 1);
 	return bio;
 cleanup:
-	bio_for_each_segment(bvec, bio, i)
-		__free_page(bvec->bv_page);
+	if (!map_data)
+		bio_for_each_segment(bvec, bio, i)
+			__free_page(bvec->bv_page);
 
 	bio_put(bio);
 out_bmd:
@@ -654,29 +720,32 @@
 /**
  *	bio_copy_user	-	copy user data to bio
  *	@q: destination block queue
+ *	@map_data: pointer to the rq_map_data holding pages (if necessary)
  *	@uaddr: start of user address
  *	@len: length in bytes
  *	@write_to_vm: bool indicating writing to pages or not
+ *	@gfp_mask: memory allocation flags
  *
  *	Prepares and returns a bio for indirect user io, bouncing data
  *	to/from kernel pages as necessary. Must be paired with
  *	call bio_uncopy_user() on io completion.
  */
-struct bio *bio_copy_user(struct request_queue *q, unsigned long uaddr,
-			  unsigned int len, int write_to_vm)
+struct bio *bio_copy_user(struct request_queue *q, struct rq_map_data *map_data,
+			  unsigned long uaddr, unsigned int len,
+			  int write_to_vm, gfp_t gfp_mask)
 {
 	struct sg_iovec iov;
 
 	iov.iov_base = (void __user *)uaddr;
 	iov.iov_len = len;
 
-	return bio_copy_user_iov(q, &iov, 1, write_to_vm);
+	return bio_copy_user_iov(q, map_data, &iov, 1, write_to_vm, gfp_mask);
 }
 
 static struct bio *__bio_map_user_iov(struct request_queue *q,
 				      struct block_device *bdev,
 				      struct sg_iovec *iov, int iov_count,
-				      int write_to_vm)
+				      int write_to_vm, gfp_t gfp_mask)
 {
 	int i, j;
 	int nr_pages = 0;
@@ -702,12 +771,12 @@
 	if (!nr_pages)
 		return ERR_PTR(-EINVAL);
 
-	bio = bio_alloc(GFP_KERNEL, nr_pages);
+	bio = bio_alloc(gfp_mask, nr_pages);
 	if (!bio)
 		return ERR_PTR(-ENOMEM);
 
 	ret = -ENOMEM;
-	pages = kcalloc(nr_pages, sizeof(struct page *), GFP_KERNEL);
+	pages = kcalloc(nr_pages, sizeof(struct page *), gfp_mask);
 	if (!pages)
 		goto out;
 
@@ -786,19 +855,21 @@
  *	@uaddr: start of user address
  *	@len: length in bytes
  *	@write_to_vm: bool indicating writing to pages or not
+ *	@gfp_mask: memory allocation flags
  *
  *	Map the user space address into a bio suitable for io to a block
  *	device. Returns an error pointer in case of error.
  */
 struct bio *bio_map_user(struct request_queue *q, struct block_device *bdev,
-			 unsigned long uaddr, unsigned int len, int write_to_vm)
+			 unsigned long uaddr, unsigned int len, int write_to_vm,
+			 gfp_t gfp_mask)
 {
 	struct sg_iovec iov;
 
 	iov.iov_base = (void __user *)uaddr;
 	iov.iov_len = len;
 
-	return bio_map_user_iov(q, bdev, &iov, 1, write_to_vm);
+	return bio_map_user_iov(q, bdev, &iov, 1, write_to_vm, gfp_mask);
 }
 
 /**
@@ -808,18 +879,19 @@
  *	@iov:	the iovec.
  *	@iov_count: number of elements in the iovec
  *	@write_to_vm: bool indicating writing to pages or not
+ *	@gfp_mask: memory allocation flags
  *
  *	Map the user space address into a bio suitable for io to a block
  *	device. Returns an error pointer in case of error.
  */
 struct bio *bio_map_user_iov(struct request_queue *q, struct block_device *bdev,
 			     struct sg_iovec *iov, int iov_count,
-			     int write_to_vm)
+			     int write_to_vm, gfp_t gfp_mask)
 {
 	struct bio *bio;
 
-	bio = __bio_map_user_iov(q, bdev, iov, iov_count, write_to_vm);
-
+	bio = __bio_map_user_iov(q, bdev, iov, iov_count, write_to_vm,
+				 gfp_mask);
 	if (IS_ERR(bio))
 		return bio;
 
@@ -976,48 +1048,13 @@
 struct bio *bio_copy_kern(struct request_queue *q, void *data, unsigned int len,
 			  gfp_t gfp_mask, int reading)
 {
-	unsigned long kaddr = (unsigned long)data;
-	unsigned long end = (kaddr + len + PAGE_SIZE - 1) >> PAGE_SHIFT;
-	unsigned long start = kaddr >> PAGE_SHIFT;
-	const int nr_pages = end - start;
 	struct bio *bio;
 	struct bio_vec *bvec;
-	struct bio_map_data *bmd;
-	int i, ret;
-	struct sg_iovec iov;
+	int i;
 
-	iov.iov_base = data;
-	iov.iov_len = len;
-
-	bmd = bio_alloc_map_data(nr_pages, 1, gfp_mask);
-	if (!bmd)
-		return ERR_PTR(-ENOMEM);
-
-	ret = -ENOMEM;
-	bio = bio_alloc(gfp_mask, nr_pages);
-	if (!bio)
-		goto out_bmd;
-
-	while (len) {
-		struct page *page;
-		unsigned int bytes = PAGE_SIZE;
-
-		if (bytes > len)
-			bytes = len;
-
-		page = alloc_page(q->bounce_gfp | gfp_mask);
-		if (!page) {
-			ret = -ENOMEM;
-			goto cleanup;
-		}
-
-		if (bio_add_pc_page(q, bio, page, bytes, 0) < bytes) {
-			ret = -EINVAL;
-			goto cleanup;
-		}
-
-		len -= bytes;
-	}
+	bio = bio_copy_user(q, NULL, (unsigned long)data, len, 1, gfp_mask);
+	if (IS_ERR(bio))
+		return bio;
 
 	if (!reading) {
 		void *p = data;
@@ -1030,20 +1067,9 @@
 		}
 	}
 
-	bio->bi_private = bmd;
 	bio->bi_end_io = bio_copy_kern_endio;
 
-	bio_set_map_data(bmd, bio, &iov, 1);
 	return bio;
-cleanup:
-	bio_for_each_segment(bvec, bio, i)
-		__free_page(bvec->bv_page);
-
-	bio_put(bio);
-out_bmd:
-	bio_free_map_data(bmd);
-
-	return ERR_PTR(ret);
 }
 
 /*
@@ -1230,9 +1256,9 @@
  * split a bio - only worry about a bio with a single page
  * in it's iovec
  */
-struct bio_pair *bio_split(struct bio *bi, mempool_t *pool, int first_sectors)
+struct bio_pair *bio_split(struct bio *bi, int first_sectors)
 {
-	struct bio_pair *bp = mempool_alloc(pool, GFP_NOIO);
+	struct bio_pair *bp = mempool_alloc(bio_split_pool, GFP_NOIO);
 
 	if (!bp)
 		return bp;
@@ -1266,7 +1292,7 @@
 	bp->bio2.bi_end_io = bio_pair_end_2;
 
 	bp->bio1.bi_private = bi;
-	bp->bio2.bi_private = pool;
+	bp->bio2.bi_private = bio_split_pool;
 
 	if (bio_integrity(bi))
 		bio_integrity_split(bi, bp, first_sectors);
@@ -1274,6 +1300,42 @@
 	return bp;
 }
 
+/**
+ *      bio_sector_offset - Find hardware sector offset in bio
+ *      @bio:           bio to inspect
+ *      @index:         bio_vec index
+ *      @offset:        offset in bv_page
+ *
+ *      Return the number of hardware sectors between beginning of bio
+ *      and an end point indicated by a bio_vec index and an offset
+ *      within that vector's page.
+ */
+sector_t bio_sector_offset(struct bio *bio, unsigned short index,
+			   unsigned int offset)
+{
+	unsigned int sector_sz = queue_hardsect_size(bio->bi_bdev->bd_disk->queue);
+	struct bio_vec *bv;
+	sector_t sectors;
+	int i;
+
+	sectors = 0;
+
+	if (index >= bio->bi_idx)
+		index = bio->bi_vcnt - 1;
+
+	__bio_for_each_segment(bv, bio, i, 0) {
+		if (i == index) {
+			if (offset > bv->bv_offset)
+				sectors += (offset - bv->bv_offset) / sector_sz;
+			break;
+		}
+
+		sectors += bv->bv_len / sector_sz;
+	}
+
+	return sectors;
+}
+EXPORT_SYMBOL(bio_sector_offset);
 
 /*
  * create memory pools for biovec's in a bio_set.
@@ -1376,6 +1438,7 @@
 subsys_initcall(init_bio);
 
 EXPORT_SYMBOL(bio_alloc);
+EXPORT_SYMBOL(bio_kmalloc);
 EXPORT_SYMBOL(bio_put);
 EXPORT_SYMBOL(bio_free);
 EXPORT_SYMBOL(bio_endio);
@@ -1383,7 +1446,6 @@
 EXPORT_SYMBOL(__bio_clone);
 EXPORT_SYMBOL(bio_clone);
 EXPORT_SYMBOL(bio_phys_segments);
-EXPORT_SYMBOL(bio_hw_segments);
 EXPORT_SYMBOL(bio_add_page);
 EXPORT_SYMBOL(bio_add_pc_page);
 EXPORT_SYMBOL(bio_get_nr_vecs);
@@ -1393,7 +1455,6 @@
 EXPORT_SYMBOL(bio_copy_kern);
 EXPORT_SYMBOL(bio_pair_release);
 EXPORT_SYMBOL(bio_split);
-EXPORT_SYMBOL(bio_split_pool);
 EXPORT_SYMBOL(bio_copy_user);
 EXPORT_SYMBOL(bio_uncopy_user);
 EXPORT_SYMBOL(bioset_create);
diff --git a/fs/block_dev.c b/fs/block_dev.c
index aff5421..d84f0469 100644
--- a/fs/block_dev.c
+++ b/fs/block_dev.c
@@ -540,22 +540,6 @@
  *           /sys/block/sda/holders/dm-0 --> /sys/block/dm-0
  */
 
-static struct kobject *bdev_get_kobj(struct block_device *bdev)
-{
-	if (bdev->bd_contains != bdev)
-		return kobject_get(&bdev->bd_part->dev.kobj);
-	else
-		return kobject_get(&bdev->bd_disk->dev.kobj);
-}
-
-static struct kobject *bdev_get_holder(struct block_device *bdev)
-{
-	if (bdev->bd_contains != bdev)
-		return kobject_get(bdev->bd_part->holder_dir);
-	else
-		return kobject_get(bdev->bd_disk->holder_dir);
-}
-
 static int add_symlink(struct kobject *from, struct kobject *to)
 {
 	if (!from || !to)
@@ -604,11 +588,11 @@
 	if (!bo->hdev)
 		goto fail_put_sdir;
 
-	bo->sdev = bdev_get_kobj(bdev);
+	bo->sdev = kobject_get(&part_to_dev(bdev->bd_part)->kobj);
 	if (!bo->sdev)
 		goto fail_put_hdev;
 
-	bo->hdir = bdev_get_holder(bdev);
+	bo->hdir = kobject_get(bdev->bd_part->holder_dir);
 	if (!bo->hdir)
 		goto fail_put_sdev;
 
@@ -868,6 +852,87 @@
 
 EXPORT_SYMBOL(open_by_devnum);
 
+/**
+ * flush_disk - invalidates all buffer-cache entries on a disk
+ *
+ * @bdev:      struct block device to be flushed
+ *
+ * Invalidates all buffer-cache entries on a disk. It should be called
+ * when a disk has been changed -- either by a media change or online
+ * resize.
+ */
+static void flush_disk(struct block_device *bdev)
+{
+	if (__invalidate_device(bdev)) {
+		char name[BDEVNAME_SIZE] = "";
+
+		if (bdev->bd_disk)
+			disk_name(bdev->bd_disk, 0, name);
+		printk(KERN_WARNING "VFS: busy inodes on changed media or "
+		       "resized disk %s\n", name);
+	}
+
+	if (!bdev->bd_disk)
+		return;
+	if (disk_partitionable(bdev->bd_disk))
+		bdev->bd_invalidated = 1;
+}
+
+/**
+ * check_disk_size_change - checks for disk size change and adjusts bdev size.
+ * @disk: struct gendisk to check
+ * @bdev: struct bdev to adjust.
+ *
+ * This routine checks to see if the bdev size does not match the disk size
+ * and adjusts it if it differs.
+ */
+void check_disk_size_change(struct gendisk *disk, struct block_device *bdev)
+{
+	loff_t disk_size, bdev_size;
+
+	disk_size = (loff_t)get_capacity(disk) << 9;
+	bdev_size = i_size_read(bdev->bd_inode);
+	if (disk_size != bdev_size) {
+		char name[BDEVNAME_SIZE];
+
+		disk_name(disk, 0, name);
+		printk(KERN_INFO
+		       "%s: detected capacity change from %lld to %lld\n",
+		       name, bdev_size, disk_size);
+		i_size_write(bdev->bd_inode, disk_size);
+		flush_disk(bdev);
+	}
+}
+EXPORT_SYMBOL(check_disk_size_change);
+
+/**
+ * revalidate_disk - wrapper for lower-level driver's revalidate_disk call-back
+ * @disk: struct gendisk to be revalidated
+ *
+ * This routine is a wrapper for lower-level driver's revalidate_disk
+ * call-backs.  It is used to do common pre and post operations needed
+ * for all revalidate_disk operations.
+ */
+int revalidate_disk(struct gendisk *disk)
+{
+	struct block_device *bdev;
+	int ret = 0;
+
+	if (disk->fops->revalidate_disk)
+		ret = disk->fops->revalidate_disk(disk);
+
+	bdev = bdget_disk(disk, 0);
+	if (!bdev)
+		return ret;
+
+	mutex_lock(&bdev->bd_mutex);
+	check_disk_size_change(disk, bdev);
+	mutex_unlock(&bdev->bd_mutex);
+	bdput(bdev);
+	return ret;
+}
+EXPORT_SYMBOL(revalidate_disk);
+
 /*
  * This routine checks whether a removable media has been changed,
  * and invalidates all buffer-cache-entries in that case. This
@@ -887,13 +952,9 @@
 	if (!bdops->media_changed(bdev->bd_disk))
 		return 0;
 
-	if (__invalidate_device(bdev))
-		printk("VFS: busy inodes on changed media.\n");
-
+	flush_disk(bdev);
 	if (bdops->revalidate_disk)
 		bdops->revalidate_disk(bdev->bd_disk);
-	if (bdev->bd_disk->minors > 1)
-		bdev->bd_invalidated = 1;
 	return 1;
 }
 
@@ -927,10 +988,10 @@
 
 static int do_open(struct block_device *bdev, struct file *file, int for_part)
 {
-	struct module *owner = NULL;
 	struct gendisk *disk;
+	struct hd_struct *part = NULL;
 	int ret;
-	int part;
+	int partno;
 	int perm = 0;
 
 	if (file->f_mode & FMODE_READ)
@@ -948,25 +1009,27 @@
 
 	ret = -ENXIO;
 	file->f_mapping = bdev->bd_inode->i_mapping;
+
 	lock_kernel();
-	disk = get_gendisk(bdev->bd_dev, &part);
-	if (!disk) {
-		unlock_kernel();
-		bdput(bdev);
-		return ret;
-	}
-	owner = disk->fops->owner;
+
+	disk = get_gendisk(bdev->bd_dev, &partno);
+	if (!disk)
+		goto out_unlock_kernel;
+	part = disk_get_part(disk, partno);
+	if (!part)
+		goto out_unlock_kernel;
 
 	mutex_lock_nested(&bdev->bd_mutex, for_part);
 	if (!bdev->bd_openers) {
 		bdev->bd_disk = disk;
+		bdev->bd_part = part;
 		bdev->bd_contains = bdev;
-		if (!part) {
+		if (!partno) {
 			struct backing_dev_info *bdi;
 			if (disk->fops->open) {
 				ret = disk->fops->open(bdev->bd_inode, file);
 				if (ret)
-					goto out_first;
+					goto out_clear;
 			}
 			if (!bdev->bd_openers) {
 				bd_set_size(bdev,(loff_t)get_capacity(disk)<<9);
@@ -978,36 +1041,36 @@
 			if (bdev->bd_invalidated)
 				rescan_partitions(disk, bdev);
 		} else {
-			struct hd_struct *p;
 			struct block_device *whole;
 			whole = bdget_disk(disk, 0);
 			ret = -ENOMEM;
 			if (!whole)
-				goto out_first;
+				goto out_clear;
 			BUG_ON(for_part);
 			ret = __blkdev_get(whole, file->f_mode, file->f_flags, 1);
 			if (ret)
-				goto out_first;
+				goto out_clear;
 			bdev->bd_contains = whole;
-			p = disk->part[part - 1];
 			bdev->bd_inode->i_data.backing_dev_info =
 			   whole->bd_inode->i_data.backing_dev_info;
-			if (!(disk->flags & GENHD_FL_UP) || !p || !p->nr_sects) {
+			if (!(disk->flags & GENHD_FL_UP) ||
+			    !part || !part->nr_sects) {
 				ret = -ENXIO;
-				goto out_first;
+				goto out_clear;
 			}
-			kobject_get(&p->dev.kobj);
-			bdev->bd_part = p;
-			bd_set_size(bdev, (loff_t) p->nr_sects << 9);
+			bd_set_size(bdev, (loff_t)part->nr_sects << 9);
 		}
 	} else {
+		disk_put_part(part);
 		put_disk(disk);
-		module_put(owner);
+		module_put(disk->fops->owner);
+		part = NULL;
+		disk = NULL;
 		if (bdev->bd_contains == bdev) {
 			if (bdev->bd_disk->fops->open) {
 				ret = bdev->bd_disk->fops->open(bdev->bd_inode, file);
 				if (ret)
-					goto out;
+					goto out_unlock_bdev;
 			}
 			if (bdev->bd_invalidated)
 				rescan_partitions(bdev->bd_disk, bdev);
@@ -1020,19 +1083,24 @@
 	unlock_kernel();
 	return 0;
 
-out_first:
+ out_clear:
 	bdev->bd_disk = NULL;
+	bdev->bd_part = NULL;
 	bdev->bd_inode->i_data.backing_dev_info = &default_backing_dev_info;
 	if (bdev != bdev->bd_contains)
 		__blkdev_put(bdev->bd_contains, 1);
 	bdev->bd_contains = NULL;
-	put_disk(disk);
-	module_put(owner);
-out:
+ out_unlock_bdev:
 	mutex_unlock(&bdev->bd_mutex);
+ out_unlock_kernel:
 	unlock_kernel();
-	if (ret)
-		bdput(bdev);
+
+	disk_put_part(part);
+	if (disk)
+		module_put(disk->fops->owner);
+	put_disk(disk);
+	bdput(bdev);
+
 	return ret;
 }
 
@@ -1117,11 +1185,8 @@
 
 		put_disk(disk);
 		module_put(owner);
-
-		if (bdev->bd_contains != bdev) {
-			kobject_put(&bdev->bd_part->dev.kobj);
-			bdev->bd_part = NULL;
-		}
+		disk_put_part(bdev->bd_part);
+		bdev->bd_part = NULL;
 		bdev->bd_disk = NULL;
 		bdev->bd_inode->i_data.backing_dev_info = &default_backing_dev_info;
 		if (bdev != bdev->bd_contains)
@@ -1197,10 +1262,9 @@
 
 /**
  * lookup_bdev  - lookup a struct block_device by name
+ * @pathname:	special file representing the block device
  *
- * @path:	special file representing the block device
- *
- * Get a reference to the blockdevice at @path in the current
+ * Get a reference to the blockdevice at @pathname in the current
  * namespace if possible and return it.  Return ERR_PTR(error)
  * otherwise.
  */
diff --git a/fs/cifs/cifs_spnego.c b/fs/cifs/cifs_spnego.c
index 117ef4b..fcee929 100644
--- a/fs/cifs/cifs_spnego.c
+++ b/fs/cifs/cifs_spnego.c
@@ -66,11 +66,28 @@
 	.describe	= user_describe,
 };
 
-#define MAX_VER_STR_LEN   8 /* length of longest version string e.g.
-				strlen("ver=0xFF") */
-#define MAX_MECH_STR_LEN 13 /* length of longest security mechanism name, eg
-			       in future could have strlen(";sec=ntlmsspi") */
-#define MAX_IPV6_ADDR_LEN 42 /* eg FEDC:BA98:7654:3210:FEDC:BA98:7654:3210/60 */
+/* length of longest version string e.g.  strlen("ver=0xFF") */
+#define MAX_VER_STR_LEN		8
+
+/* length of longest security mechanism name, eg in future could have
+ * strlen(";sec=ntlmsspi") */
+#define MAX_MECH_STR_LEN	13
+
+/* max possible addr len eg FEDC:BA98:7654:3210:FEDC:BA98:7654:3210/60 */
+#define MAX_IPV6_ADDR_LEN	42
+
+/* strlen of "host=" */
+#define HOST_KEY_LEN		5
+
+/* strlen of ";ip4=" or ";ip6=" */
+#define IP_KEY_LEN		5
+
+/* strlen of ";uid=0x" */
+#define UID_KEY_LEN		7
+
+/* strlen of ";user=" */
+#define USER_KEY_LEN		6
+
 /* get a key struct with a SPNEGO security blob, suitable for session setup */
 struct key *
 cifs_get_spnego_key(struct cifsSesInfo *sesInfo)
@@ -84,11 +101,11 @@
 	/* length of fields (with semicolons): ver=0xyz ip4=ipaddress
 	   host=hostname sec=mechanism uid=0xFF user=username */
 	desc_len = MAX_VER_STR_LEN +
-		   6 /* len of "host=" */ + strlen(hostname) +
-		   5 /* len of ";ipv4=" */ + MAX_IPV6_ADDR_LEN +
+		   HOST_KEY_LEN + strlen(hostname) +
+		   IP_KEY_LEN + MAX_IPV6_ADDR_LEN +
 		   MAX_MECH_STR_LEN +
-		   7 /* len of ";uid=0x" */ + (sizeof(uid_t) * 2) +
-		   6 /* len of ";user=" */ + strlen(sesInfo->userName) + 1;
+		   UID_KEY_LEN + (sizeof(uid_t) * 2) +
+		   USER_KEY_LEN + strlen(sesInfo->userName) + 1;
 
 	spnego_key = ERR_PTR(-ENOMEM);
 	description = kzalloc(desc_len, GFP_KERNEL);
diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h
index 135c965..f7b4a5c 100644
--- a/fs/cifs/cifsfs.h
+++ b/fs/cifs/cifsfs.h
@@ -41,7 +41,7 @@
 		       struct nameidata *);
 extern struct dentry *cifs_lookup(struct inode *, struct dentry *,
 				  struct nameidata *);
-extern int cifs_unlink(struct inode *, struct dentry *);
+extern int cifs_unlink(struct inode *dir, struct dentry *dentry);
 extern int cifs_hardlink(struct dentry *, struct inode *, struct dentry *);
 extern int cifs_mknod(struct inode *, struct dentry *, int, dev_t);
 extern int cifs_mkdir(struct inode *, struct dentry *, int);
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 8dfd6f2..0d22479 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -309,6 +309,7 @@
 	__u32 resume_key;
 	char *ntwrk_buf_start;
 	char *srch_entries_start;
+	char *last_entry;
 	char *presume_name;
 	unsigned int resume_name_len;
 	bool endOfSearch:1;
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index a729d08..0cff7fe 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -179,6 +179,8 @@
 extern int CIFSSMBSetFileInfo(const int xid, struct cifsTconInfo *tcon,
 			const FILE_BASIC_INFO *data, __u16 fid,
 			__u32 pid_of_opener);
+extern int CIFSSMBSetFileDisposition(const int xid, struct cifsTconInfo *tcon,
+			bool delete_file, __u16 fid, __u32 pid_of_opener);
 #if 0
 extern int CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon,
 			char *fileName, __u16 dos_attributes,
@@ -229,7 +231,7 @@
 			const struct nls_table *nls_codepage,
 			int remap_special_chars);
 extern int CIFSSMBRenameOpenFile(const int xid, struct cifsTconInfo *pTcon,
-			int netfid, char *target_name,
+			int netfid, const char *target_name,
 			const struct nls_table *nls_codepage,
 			int remap_special_chars);
 extern int CIFSCreateHardLink(const int xid,
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index 994de7c..6f4ffe1 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -2017,7 +2017,7 @@
 }
 
 int CIFSSMBRenameOpenFile(const int xid, struct cifsTconInfo *pTcon,
-		int netfid, char *target_name,
+		int netfid, const char *target_name,
 		const struct nls_table *nls_codepage, int remap)
 {
 	struct smb_com_transaction2_sfi_req *pSMB  = NULL;
@@ -2071,7 +2071,7 @@
 					remap);
 	}
 	rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
-	count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str) + 2;
+	count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str);
 	byte_count += count;
 	pSMB->DataCount = cpu_to_le16(count);
 	pSMB->TotalDataCount = pSMB->DataCount;
@@ -3614,6 +3614,8 @@
 		/* BB remember to free buffer if error BB */
 		rc = validate_t2((struct smb_t2_rsp *)pSMBr);
 		if (rc == 0) {
+			unsigned int lnoff;
+
 			if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
 				psrch_inf->unicode = true;
 			else
@@ -3636,6 +3638,17 @@
 					le16_to_cpu(parms->SearchCount);
 			psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
 				psrch_inf->entries_in_buffer;
+			lnoff = le16_to_cpu(parms->LastNameOffset);
+			if (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE <
+			      lnoff) {
+				cERROR(1, ("ignoring corrupt resume name"));
+				psrch_inf->last_entry = NULL;
+				return rc;
+			}
+
+			psrch_inf->last_entry = psrch_inf->srch_entries_start +
+							lnoff;
+
 			*pnetfid = parms->SearchHandle;
 		} else {
 			cifs_buf_release(pSMB);
@@ -3725,6 +3738,8 @@
 		rc = validate_t2((struct smb_t2_rsp *)pSMBr);
 
 		if (rc == 0) {
+			unsigned int lnoff;
+
 			/* BB fixme add lock for file (srch_info) struct here */
 			if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
 				psrch_inf->unicode = true;
@@ -3751,6 +3766,16 @@
 						le16_to_cpu(parms->SearchCount);
 			psrch_inf->index_of_last_entry +=
 				psrch_inf->entries_in_buffer;
+			lnoff = le16_to_cpu(parms->LastNameOffset);
+			if (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE <
+			      lnoff) {
+				cERROR(1, ("ignoring corrupt resume name"));
+				psrch_inf->last_entry = NULL;
+				return rc;
+			} else
+				psrch_inf->last_entry =
+					psrch_inf->srch_entries_start + lnoff;
+
 /*  cFYI(1,("fnxt2 entries in buf %d index_of_last %d",
 	    psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry)); */
 
@@ -4876,6 +4901,61 @@
 	return rc;
 }
 
+int
+CIFSSMBSetFileDisposition(const int xid, struct cifsTconInfo *tcon,
+			  bool delete_file, __u16 fid, __u32 pid_of_opener)
+{
+	struct smb_com_transaction2_sfi_req *pSMB  = NULL;
+	char *data_offset;
+	int rc = 0;
+	__u16 params, param_offset, offset, byte_count, count;
+
+	cFYI(1, ("Set File Disposition (via SetFileInfo)"));
+	rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
+
+	if (rc)
+		return rc;
+
+	pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
+	pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
+
+	params = 6;
+	pSMB->MaxSetupCount = 0;
+	pSMB->Reserved = 0;
+	pSMB->Flags = 0;
+	pSMB->Timeout = 0;
+	pSMB->Reserved2 = 0;
+	param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
+	offset = param_offset + params;
+
+	data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
+
+	count = 1;
+	pSMB->MaxParameterCount = cpu_to_le16(2);
+	/* BB find max SMB PDU from sess */
+	pSMB->MaxDataCount = cpu_to_le16(1000);
+	pSMB->SetupCount = 1;
+	pSMB->Reserved3 = 0;
+	pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
+	byte_count = 3 /* pad */  + params + count;
+	pSMB->DataCount = cpu_to_le16(count);
+	pSMB->ParameterCount = cpu_to_le16(params);
+	pSMB->TotalDataCount = pSMB->DataCount;
+	pSMB->TotalParameterCount = pSMB->ParameterCount;
+	pSMB->ParameterOffset = cpu_to_le16(param_offset);
+	pSMB->DataOffset = cpu_to_le16(offset);
+	pSMB->Fid = fid;
+	pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_DISPOSITION_INFO);
+	pSMB->Reserved4 = 0;
+	pSMB->hdr.smb_buf_length += byte_count;
+	pSMB->ByteCount = cpu_to_le16(byte_count);
+	*data_offset = delete_file ? 1 : 0;
+	rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
+	if (rc)
+		cFYI(1, ("Send error in SetFileDisposition = %d", rc));
+
+	return rc;
+}
 
 int
 CIFSSMBSetPathInfo(const int xid, struct cifsTconInfo *tcon,
diff --git a/fs/cifs/dns_resolve.c b/fs/cifs/dns_resolve.c
index a2e0673..1e0c1bd 100644
--- a/fs/cifs/dns_resolve.c
+++ b/fs/cifs/dns_resolve.c
@@ -29,45 +29,13 @@
 #include "cifsproto.h"
 #include "cifs_debug.h"
 
-static int dns_resolver_instantiate(struct key *key, const void *data,
-		size_t datalen)
-{
-	int rc = 0;
-	char *ip;
-
-	ip = kmalloc(datalen+1, GFP_KERNEL);
-	if (!ip)
-		return -ENOMEM;
-
-	memcpy(ip, data, datalen);
-	ip[datalen] = '\0';
-
-	rcu_assign_pointer(key->payload.data, ip);
-
-	return rc;
-}
-
-static void
-dns_resolver_destroy(struct key *key)
-{
-	kfree(key->payload.data);
-}
-
-struct key_type key_type_dns_resolver = {
-	.name        = "dns_resolver",
-	.def_datalen = sizeof(struct in_addr),
-	.describe    = user_describe,
-	.instantiate = dns_resolver_instantiate,
-	.destroy     = dns_resolver_destroy,
-	.match       = user_match,
-};
-
 /* Checks if supplied name is IP address
  * returns:
  * 		1 - name is IP
  * 		0 - name is not IP
  */
-static int is_ip(const char *name)
+static int
+is_ip(const char *name)
 {
 	int rc;
 	struct sockaddr_in sin_server;
@@ -89,6 +57,47 @@
 	return 0;
 }
 
+static int
+dns_resolver_instantiate(struct key *key, const void *data,
+		size_t datalen)
+{
+	int rc = 0;
+	char *ip;
+
+	ip = kmalloc(datalen + 1, GFP_KERNEL);
+	if (!ip)
+		return -ENOMEM;
+
+	memcpy(ip, data, datalen);
+	ip[datalen] = '\0';
+
+	/* make sure this looks like an address */
+	if (!is_ip((const char *) ip)) {
+		kfree(ip);
+		return -EINVAL;
+	}
+
+	key->type_data.x[0] = datalen;
+	rcu_assign_pointer(key->payload.data, ip);
+
+	return rc;
+}
+
+static void
+dns_resolver_destroy(struct key *key)
+{
+	kfree(key->payload.data);
+}
+
+struct key_type key_type_dns_resolver = {
+	.name        = "dns_resolver",
+	.def_datalen = sizeof(struct in_addr),
+	.describe    = user_describe,
+	.instantiate = dns_resolver_instantiate,
+	.destroy     = dns_resolver_destroy,
+	.match       = user_match,
+};
+
 /* Resolves server name to ip address.
  * input:
  * 	unc - server UNC
@@ -140,6 +149,7 @@
 
 	rkey = request_key(&key_type_dns_resolver, name, "");
 	if (!IS_ERR(rkey)) {
+		len = rkey->type_data.x[0];
 		data = rkey->payload.data;
 	} else {
 		cERROR(1, ("%s: unable to resolve: %s", __func__, name));
@@ -148,11 +158,9 @@
 
 skip_upcall:
 	if (data) {
-		len = strlen(data);
-		*ip_addr = kmalloc(len+1, GFP_KERNEL);
+		*ip_addr = kmalloc(len + 1, GFP_KERNEL);
 		if (*ip_addr) {
-			memcpy(*ip_addr, data, len);
-			(*ip_addr)[len] = '\0';
+			memcpy(*ip_addr, data, len + 1);
 			if (!IS_ERR(rkey))
 				cFYI(1, ("%s: resolved: %s to %s", __func__,
 							name,
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index cbefe1f..c4a8a06 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -107,7 +107,7 @@
 
 	/* want handles we can use to read with first
 	   in the list so we do not have to walk the
-	   list to search for one in prepare_write */
+	   list to search for one in write_begin */
 	if ((file->f_flags & O_ACCMODE) == O_WRONLY) {
 		list_add_tail(&pCifsFile->flist,
 			      &pCifsInode->openFileList);
@@ -915,7 +915,7 @@
 }
 
 static ssize_t cifs_write(struct file *file, const char *write_data,
-	size_t write_size, loff_t *poffset)
+			  size_t write_size, loff_t *poffset)
 {
 	int rc = 0;
 	unsigned int bytes_written = 0;
@@ -1065,6 +1065,7 @@
 struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode)
 {
 	struct cifsFileInfo *open_file;
+	bool any_available = false;
 	int rc;
 
 	/* Having a null inode here (because mapping->host was set to zero by
@@ -1080,8 +1081,10 @@
 	read_lock(&GlobalSMBSeslock);
 refind_writable:
 	list_for_each_entry(open_file, &cifs_inode->openFileList, flist) {
-		if (open_file->closePend)
+		if (open_file->closePend ||
+		    (!any_available && open_file->pid != current->tgid))
 			continue;
+
 		if (open_file->pfile &&
 		    ((open_file->pfile->f_flags & O_RDWR) ||
 		     (open_file->pfile->f_flags & O_WRONLY))) {
@@ -1131,6 +1134,11 @@
 			   of the loop here. */
 		}
 	}
+	/* couldn't find useable FH with same pid, try any available */
+	if (!any_available) {
+		any_available = true;
+		goto refind_writable;
+	}
 	read_unlock(&GlobalSMBSeslock);
 	return NULL;
 }
@@ -1447,49 +1455,52 @@
 	return rc;
 }
 
-static int cifs_commit_write(struct file *file, struct page *page,
-	unsigned offset, unsigned to)
+static int cifs_write_end(struct file *file, struct address_space *mapping,
+			loff_t pos, unsigned len, unsigned copied,
+			struct page *page, void *fsdata)
 {
-	int xid;
-	int rc = 0;
-	struct inode *inode = page->mapping->host;
-	loff_t position = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to;
-	char *page_data;
+	int rc;
+	struct inode *inode = mapping->host;
 
-	xid = GetXid();
-	cFYI(1, ("commit write for page %p up to position %lld for %d",
-		 page, position, to));
-	spin_lock(&inode->i_lock);
-	if (position > inode->i_size)
-		i_size_write(inode, position);
+	cFYI(1, ("write_end for page %p from pos %lld with %d bytes",
+		 page, pos, copied));
 
-	spin_unlock(&inode->i_lock);
+	if (!PageUptodate(page) && copied == PAGE_CACHE_SIZE)
+		SetPageUptodate(page);
+
 	if (!PageUptodate(page)) {
-		position =  ((loff_t)page->index << PAGE_CACHE_SHIFT) + offset;
-		/* can not rely on (or let) writepage write this data */
-		if (to < offset) {
-			cFYI(1, ("Illegal offsets, can not copy from %d to %d",
-				offset, to));
-			FreeXid(xid);
-			return rc;
-		}
+		char *page_data;
+		unsigned offset = pos & (PAGE_CACHE_SIZE - 1);
+		int xid;
+
+		xid = GetXid();
 		/* this is probably better than directly calling
 		   partialpage_write since in this function the file handle is
 		   known which we might as well	leverage */
 		/* BB check if anything else missing out of ppw
 		   such as updating last write time */
 		page_data = kmap(page);
-		rc = cifs_write(file, page_data + offset, to-offset,
-				&position);
-		if (rc > 0)
-			rc = 0;
-		/* else if (rc < 0) should we set writebehind rc? */
+		rc = cifs_write(file, page_data + offset, copied, &pos);
+		/* if (rc < 0) should we set writebehind rc? */
 		kunmap(page);
+
+		FreeXid(xid);
 	} else {
+		rc = copied;
+		pos += copied;
 		set_page_dirty(page);
 	}
 
-	FreeXid(xid);
+	if (rc > 0) {
+		spin_lock(&inode->i_lock);
+		if (pos > inode->i_size)
+			i_size_write(inode, pos);
+		spin_unlock(&inode->i_lock);
+	}
+
+	unlock_page(page);
+	page_cache_release(page);
+
 	return rc;
 }
 
@@ -2035,49 +2046,44 @@
 		return true;
 }
 
-static int cifs_prepare_write(struct file *file, struct page *page,
-	unsigned from, unsigned to)
+static int cifs_write_begin(struct file *file, struct address_space *mapping,
+			loff_t pos, unsigned len, unsigned flags,
+			struct page **pagep, void **fsdata)
 {
-	int rc = 0;
-	loff_t i_size;
-	loff_t offset;
+	pgoff_t index = pos >> PAGE_CACHE_SHIFT;
+	loff_t offset = pos & (PAGE_CACHE_SIZE - 1);
 
-	cFYI(1, ("prepare write for page %p from %d to %d", page, from, to));
-	if (PageUptodate(page))
+	cFYI(1, ("write_begin from %lld len %d", (long long)pos, len));
+
+	*pagep = __grab_cache_page(mapping, index);
+	if (!*pagep)
+		return -ENOMEM;
+
+	if (PageUptodate(*pagep))
 		return 0;
 
 	/* If we are writing a full page it will be up to date,
 	   no need to read from the server */
-	if ((to == PAGE_CACHE_SIZE) && (from == 0)) {
-		SetPageUptodate(page);
+	if (len == PAGE_CACHE_SIZE && flags & AOP_FLAG_UNINTERRUPTIBLE)
 		return 0;
-	}
 
-	offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
-	i_size = i_size_read(page->mapping->host);
+	if ((file->f_flags & O_ACCMODE) != O_WRONLY) {
+		int rc;
 
-	if ((offset >= i_size) ||
-	    ((from == 0) && (offset + to) >= i_size)) {
-		/*
-		 * We don't need to read data beyond the end of the file.
-		 * zero it, and set the page uptodate
-		 */
-		simple_prepare_write(file, page, from, to);
-		SetPageUptodate(page);
-	} else if ((file->f_flags & O_ACCMODE) != O_WRONLY) {
 		/* might as well read a page, it is fast enough */
-		rc = cifs_readpage_worker(file, page, &offset);
+		rc = cifs_readpage_worker(file, *pagep, &offset);
+
+		/* we do not need to pass errors back
+		   e.g. if we do not have read access to the file
+		   because cifs_write_end will attempt synchronous writes
+		   -- shaggy */
 	} else {
 		/* we could try using another file handle if there is one -
 		   but how would we lock it to prevent close of that handle
 		   racing with this read? In any case
-		   this will be written out by commit_write so is fine */
+		   this will be written out by write_end so is fine */
 	}
 
-	/* we do not need to pass errors back
-	   e.g. if we do not have read access to the file
-	   because cifs_commit_write will do the right thing.  -- shaggy */
-
 	return 0;
 }
 
@@ -2086,8 +2092,8 @@
 	.readpages = cifs_readpages,
 	.writepage = cifs_writepage,
 	.writepages = cifs_writepages,
-	.prepare_write = cifs_prepare_write,
-	.commit_write = cifs_commit_write,
+	.write_begin = cifs_write_begin,
+	.write_end = cifs_write_end,
 	.set_page_dirty = __set_page_dirty_nobuffers,
 	/* .sync_page = cifs_sync_page, */
 	/* .direct_IO = */
@@ -2102,8 +2108,8 @@
 	.readpage = cifs_readpage,
 	.writepage = cifs_writepage,
 	.writepages = cifs_writepages,
-	.prepare_write = cifs_prepare_write,
-	.commit_write = cifs_commit_write,
+	.write_begin = cifs_write_begin,
+	.write_end = cifs_write_end,
 	.set_page_dirty = __set_page_dirty_nobuffers,
 	/* .sync_page = cifs_sync_page, */
 	/* .direct_IO = */
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index 9c548f1..a8c8333 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -665,40 +665,201 @@
 	return inode;
 }
 
-int cifs_unlink(struct inode *inode, struct dentry *direntry)
+static int
+cifs_set_file_info(struct inode *inode, struct iattr *attrs, int xid,
+		    char *full_path, __u32 dosattr)
+{
+	int rc;
+	int oplock = 0;
+	__u16 netfid;
+	__u32 netpid;
+	bool set_time = false;
+	struct cifsFileInfo *open_file;
+	struct cifsInodeInfo *cifsInode = CIFS_I(inode);
+	struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
+	struct cifsTconInfo *pTcon = cifs_sb->tcon;
+	FILE_BASIC_INFO	info_buf;
+
+	if (attrs->ia_valid & ATTR_ATIME) {
+		set_time = true;
+		info_buf.LastAccessTime =
+			cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_atime));
+	} else
+		info_buf.LastAccessTime = 0;
+
+	if (attrs->ia_valid & ATTR_MTIME) {
+		set_time = true;
+		info_buf.LastWriteTime =
+		    cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_mtime));
+	} else
+		info_buf.LastWriteTime = 0;
+
+	/*
+	 * Samba throws this field away, but windows may actually use it.
+	 * Do not set ctime unless other time stamps are changed explicitly
+	 * (i.e. by utimes()) since we would then have a mix of client and
+	 * server times.
+	 */
+	if (set_time && (attrs->ia_valid & ATTR_CTIME)) {
+		cFYI(1, ("CIFS - CTIME changed"));
+		info_buf.ChangeTime =
+		    cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_ctime));
+	} else
+		info_buf.ChangeTime = 0;
+
+	info_buf.CreationTime = 0;	/* don't change */
+	info_buf.Attributes = cpu_to_le32(dosattr);
+
+	/*
+	 * If the file is already open for write, just use that fileid
+	 */
+	open_file = find_writable_file(cifsInode);
+	if (open_file) {
+		netfid = open_file->netfid;
+		netpid = open_file->pid;
+		goto set_via_filehandle;
+	}
+
+	/*
+	 * NT4 apparently returns success on this call, but it doesn't
+	 * really work.
+	 */
+	if (!(pTcon->ses->flags & CIFS_SES_NT4)) {
+		rc = CIFSSMBSetPathInfo(xid, pTcon, full_path,
+				     &info_buf, cifs_sb->local_nls,
+				     cifs_sb->mnt_cifs_flags &
+					CIFS_MOUNT_MAP_SPECIAL_CHR);
+		if (rc == 0) {
+			cifsInode->cifsAttrs = dosattr;
+			goto out;
+		} else if (rc != -EOPNOTSUPP && rc != -EINVAL)
+			goto out;
+	}
+
+	cFYI(1, ("calling SetFileInfo since SetPathInfo for "
+		 "times not supported by this server"));
+	rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN,
+			 SYNCHRONIZE | FILE_WRITE_ATTRIBUTES,
+			 CREATE_NOT_DIR, &netfid, &oplock,
+			 NULL, cifs_sb->local_nls,
+			 cifs_sb->mnt_cifs_flags &
+				CIFS_MOUNT_MAP_SPECIAL_CHR);
+
+	if (rc != 0) {
+		if (rc == -EIO)
+			rc = -EINVAL;
+		goto out;
+	}
+
+	netpid = current->tgid;
+
+set_via_filehandle:
+	rc = CIFSSMBSetFileInfo(xid, pTcon, &info_buf, netfid, netpid);
+	if (!rc)
+		cifsInode->cifsAttrs = dosattr;
+
+	if (open_file == NULL)
+		CIFSSMBClose(xid, pTcon, netfid);
+	else
+		atomic_dec(&open_file->wrtPending);
+out:
+	return rc;
+}
+
+/*
+ * open the given file (if it isn't already), set the DELETE_ON_CLOSE bit
+ * and rename it to a random name that hopefully won't conflict with
+ * anything else.
+ */
+static int
+cifs_rename_pending_delete(char *full_path, struct inode *inode, int xid)
+{
+	int oplock = 0;
+	int rc;
+	__u16 netfid;
+	struct cifsInodeInfo *cifsInode = CIFS_I(inode);
+	struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
+	struct cifsTconInfo *tcon = cifs_sb->tcon;
+	__u32 dosattr;
+	FILE_BASIC_INFO *info_buf;
+
+	rc = CIFSSMBOpen(xid, tcon, full_path, FILE_OPEN,
+			 DELETE|FILE_WRITE_ATTRIBUTES,
+			 CREATE_NOT_DIR|CREATE_DELETE_ON_CLOSE,
+			 &netfid, &oplock, NULL, cifs_sb->local_nls,
+			 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
+	if (rc != 0)
+		goto out;
+
+	/* set ATTR_HIDDEN and clear ATTR_READONLY */
+	cifsInode = CIFS_I(inode);
+	dosattr = cifsInode->cifsAttrs & ~ATTR_READONLY;
+	if (dosattr == 0)
+		dosattr |= ATTR_NORMAL;
+	dosattr |= ATTR_HIDDEN;
+
+	info_buf = kzalloc(sizeof(*info_buf), GFP_KERNEL);
+	if (info_buf == NULL) {
+		rc = -ENOMEM;
+		goto out_close;
+	}
+	info_buf->Attributes = cpu_to_le32(dosattr);
+	rc = CIFSSMBSetFileInfo(xid, tcon, info_buf, netfid, current->tgid);
+	kfree(info_buf);
+	if (rc != 0)
+		goto out_close;
+	cifsInode->cifsAttrs = dosattr;
+
+	/* silly-rename the file */
+	CIFSSMBRenameOpenFile(xid, tcon, netfid, NULL, cifs_sb->local_nls,
+				   cifs_sb->mnt_cifs_flags &
+					    CIFS_MOUNT_MAP_SPECIAL_CHR);
+
+	/* set DELETE_ON_CLOSE */
+	rc = CIFSSMBSetFileDisposition(xid, tcon, true, netfid, current->tgid);
+
+	/*
+	 * some samba versions return -ENOENT when we try to set the file
+	 * disposition here. Likely a samba bug, but work around it for now
+	 */
+	if (rc == -ENOENT)
+		rc = 0;
+
+out_close:
+	CIFSSMBClose(xid, tcon, netfid);
+out:
+	return rc;
+}
+
+int cifs_unlink(struct inode *dir, struct dentry *dentry)
 {
 	int rc = 0;
 	int xid;
-	struct cifs_sb_info *cifs_sb;
-	struct cifsTconInfo *pTcon;
 	char *full_path = NULL;
-	struct cifsInodeInfo *cifsInode;
-	FILE_BASIC_INFO *pinfo_buf;
+	struct inode *inode = dentry->d_inode;
+	struct cifsInodeInfo *cifsInode = CIFS_I(inode);
+	struct super_block *sb = dir->i_sb;
+	struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
+	struct cifsTconInfo *tcon = cifs_sb->tcon;
+	struct iattr *attrs = NULL;
+	__u32 dosattr = 0, origattr = 0;
 
-	cFYI(1, ("cifs_unlink, inode = 0x%p", inode));
+	cFYI(1, ("cifs_unlink, dir=0x%p, dentry=0x%p", dir, dentry));
 
 	xid = GetXid();
 
-	if (inode)
-		cifs_sb = CIFS_SB(inode->i_sb);
-	else
-		cifs_sb = CIFS_SB(direntry->d_sb);
-	pTcon = cifs_sb->tcon;
-
-	/* Unlink can be called from rename so we can not grab the sem here
-	   since we deadlock otherwise */
-/*	mutex_lock(&direntry->d_sb->s_vfs_rename_mutex);*/
-	full_path = build_path_from_dentry(direntry);
-/*	mutex_unlock(&direntry->d_sb->s_vfs_rename_mutex);*/
+	/* Unlink can be called from rename so we can not take the
+	 * sb->s_vfs_rename_mutex here */
+	full_path = build_path_from_dentry(dentry);
 	if (full_path == NULL) {
 		FreeXid(xid);
 		return -ENOMEM;
 	}
 
-	if ((pTcon->ses->capabilities & CAP_UNIX) &&
+	if ((tcon->ses->capabilities & CAP_UNIX) &&
 		(CIFS_UNIX_POSIX_PATH_OPS_CAP &
-			le64_to_cpu(pTcon->fsUnixInfo.Capability))) {
-		rc = CIFSPOSIXDelFile(xid, pTcon, full_path,
+			le64_to_cpu(tcon->fsUnixInfo.Capability))) {
+		rc = CIFSPOSIXDelFile(xid, tcon, full_path,
 			SMB_POSIX_UNLINK_FILE_TARGET, cifs_sb->local_nls,
 			cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
 		cFYI(1, ("posix del rc %d", rc));
@@ -706,125 +867,60 @@
 			goto psx_del_no_retry;
 	}
 
-	rc = CIFSSMBDelFile(xid, pTcon, full_path, cifs_sb->local_nls,
+retry_std_delete:
+	rc = CIFSSMBDelFile(xid, tcon, full_path, cifs_sb->local_nls,
 			cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
+
 psx_del_no_retry:
 	if (!rc) {
-		if (direntry->d_inode)
-			drop_nlink(direntry->d_inode);
+		if (inode)
+			drop_nlink(inode);
 	} else if (rc == -ENOENT) {
-		d_drop(direntry);
+		d_drop(dentry);
 	} else if (rc == -ETXTBSY) {
-		int oplock = 0;
-		__u16 netfid;
-
-		rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, DELETE,
-				 CREATE_NOT_DIR | CREATE_DELETE_ON_CLOSE,
-				 &netfid, &oplock, NULL, cifs_sb->local_nls,
-				 cifs_sb->mnt_cifs_flags &
-					CIFS_MOUNT_MAP_SPECIAL_CHR);
-		if (rc == 0) {
-			CIFSSMBRenameOpenFile(xid, pTcon, netfid, NULL,
-					      cifs_sb->local_nls,
-					      cifs_sb->mnt_cifs_flags &
-						CIFS_MOUNT_MAP_SPECIAL_CHR);
-			CIFSSMBClose(xid, pTcon, netfid);
-			if (direntry->d_inode)
-				drop_nlink(direntry->d_inode);
+		rc = cifs_rename_pending_delete(full_path, inode, xid);
+		if (rc == 0)
+			drop_nlink(inode);
+	} else if (rc == -EACCES && dosattr == 0) {
+		attrs = kzalloc(sizeof(*attrs), GFP_KERNEL);
+		if (attrs == NULL) {
+			rc = -ENOMEM;
+			goto out_reval;
 		}
-	} else if (rc == -EACCES) {
-		/* try only if r/o attribute set in local lookup data? */
-		pinfo_buf = kzalloc(sizeof(FILE_BASIC_INFO), GFP_KERNEL);
-		if (pinfo_buf) {
-			/* ATTRS set to normal clears r/o bit */
-			pinfo_buf->Attributes = cpu_to_le32(ATTR_NORMAL);
-			if (!(pTcon->ses->flags & CIFS_SES_NT4))
-				rc = CIFSSMBSetPathInfo(xid, pTcon, full_path,
-						     pinfo_buf,
-						     cifs_sb->local_nls,
-						     cifs_sb->mnt_cifs_flags &
-							CIFS_MOUNT_MAP_SPECIAL_CHR);
-			else
-				rc = -EOPNOTSUPP;
 
-			if (rc == -EOPNOTSUPP) {
-				int oplock = 0;
-				__u16 netfid;
-			/*	rc = CIFSSMBSetAttrLegacy(xid, pTcon,
-							  full_path,
-							  (__u16)ATTR_NORMAL,
-							  cifs_sb->local_nls);
-			   For some strange reason it seems that NT4 eats the
-			   old setattr call without actually setting the
-			   attributes so on to the third attempted workaround
-			   */
+		/* try to reset dos attributes */
+		origattr = cifsInode->cifsAttrs;
+		if (origattr == 0)
+			origattr |= ATTR_NORMAL;
+		dosattr = origattr & ~ATTR_READONLY;
+		if (dosattr == 0)
+			dosattr |= ATTR_NORMAL;
+		dosattr |= ATTR_HIDDEN;
 
-			/* BB could scan to see if we already have it open
-			   and pass in pid of opener to function */
-				rc = CIFSSMBOpen(xid, pTcon, full_path,
-						 FILE_OPEN, SYNCHRONIZE |
-						 FILE_WRITE_ATTRIBUTES, 0,
-						 &netfid, &oplock, NULL,
-						 cifs_sb->local_nls,
-						 cifs_sb->mnt_cifs_flags &
-						    CIFS_MOUNT_MAP_SPECIAL_CHR);
-				if (rc == 0) {
-					rc = CIFSSMBSetFileInfo(xid, pTcon,
-								pinfo_buf,
-								netfid,
-								current->tgid);
-					CIFSSMBClose(xid, pTcon, netfid);
-				}
-			}
-			kfree(pinfo_buf);
-		}
-		if (rc == 0) {
-			rc = CIFSSMBDelFile(xid, pTcon, full_path,
-					    cifs_sb->local_nls,
-					    cifs_sb->mnt_cifs_flags &
-						CIFS_MOUNT_MAP_SPECIAL_CHR);
-			if (!rc) {
-				if (direntry->d_inode)
-					drop_nlink(direntry->d_inode);
-			} else if (rc == -ETXTBSY) {
-				int oplock = 0;
-				__u16 netfid;
+		rc = cifs_set_file_info(inode, attrs, xid, full_path, dosattr);
+		if (rc != 0)
+			goto out_reval;
 
-				rc = CIFSSMBOpen(xid, pTcon, full_path,
-						 FILE_OPEN, DELETE,
-						 CREATE_NOT_DIR |
-						 CREATE_DELETE_ON_CLOSE,
-						 &netfid, &oplock, NULL,
-						 cifs_sb->local_nls,
-						 cifs_sb->mnt_cifs_flags &
-						    CIFS_MOUNT_MAP_SPECIAL_CHR);
-				if (rc == 0) {
-					CIFSSMBRenameOpenFile(xid, pTcon,
-						netfid, NULL,
-						cifs_sb->local_nls,
-						cifs_sb->mnt_cifs_flags &
-						    CIFS_MOUNT_MAP_SPECIAL_CHR);
-					CIFSSMBClose(xid, pTcon, netfid);
-					if (direntry->d_inode)
-						drop_nlink(direntry->d_inode);
-				}
-			/* BB if rc = -ETXTBUSY goto the rename logic BB */
-			}
-		}
+		goto retry_std_delete;
 	}
-	if (direntry->d_inode) {
-		cifsInode = CIFS_I(direntry->d_inode);
+
+	/* undo the setattr if we errored out and it's needed */
+	if (rc != 0 && dosattr != 0)
+		cifs_set_file_info(inode, attrs, xid, full_path, origattr);
+
+out_reval:
+	if (inode) {
+		cifsInode = CIFS_I(inode);
 		cifsInode->time = 0;	/* will force revalidate to get info
 					   when needed */
-		direntry->d_inode->i_ctime = current_fs_time(inode->i_sb);
+		inode->i_ctime = current_fs_time(sb);
 	}
-	if (inode) {
-		inode->i_ctime = inode->i_mtime = current_fs_time(inode->i_sb);
-		cifsInode = CIFS_I(inode);
-		cifsInode->time = 0;	/* force revalidate of dir as well */
-	}
+	dir->i_ctime = dir->i_mtime = current_fs_time(sb);
+	cifsInode = CIFS_I(dir);
+	CIFS_I(dir)->time = 0;	/* force revalidate of dir as well */
 
 	kfree(full_path);
+	kfree(attrs);
 	FreeXid(xid);
 	return rc;
 }
@@ -869,7 +965,7 @@
 
 int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
 {
-	int rc = 0;
+	int rc = 0, tmprc;
 	int xid;
 	struct cifs_sb_info *cifs_sb;
 	struct cifsTconInfo *pTcon;
@@ -931,6 +1027,7 @@
 				kfree(pInfo);
 				goto mkdir_get_info;
 			}
+
 			/* Is an i_ino of zero legal? */
 			/* Are there sanity checks we can use to ensure that
 			   the server is really filling in that field? */
@@ -1019,12 +1116,20 @@
 			if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) &&
 			    (mode & S_IWUGO) == 0) {
 				FILE_BASIC_INFO pInfo;
+				struct cifsInodeInfo *cifsInode;
+				u32 dosattrs;
+
 				memset(&pInfo, 0, sizeof(pInfo));
-				pInfo.Attributes = cpu_to_le32(ATTR_READONLY);
-				CIFSSMBSetPathInfo(xid, pTcon, full_path,
-						&pInfo, cifs_sb->local_nls,
+				cifsInode = CIFS_I(newinode);
+				dosattrs = cifsInode->cifsAttrs|ATTR_READONLY;
+				pInfo.Attributes = cpu_to_le32(dosattrs);
+				tmprc = CIFSSMBSetPathInfo(xid, pTcon,
+						full_path, &pInfo,
+						cifs_sb->local_nls,
 						cifs_sb->mnt_cifs_flags &
 						CIFS_MOUNT_MAP_SPECIAL_CHR);
+				if (tmprc == 0)
+					cifsInode->cifsAttrs = dosattrs;
 			}
 			if (direntry->d_inode) {
 				if (cifs_sb->mnt_cifs_flags &
@@ -1096,117 +1201,141 @@
 	return rc;
 }
 
+static int
+cifs_do_rename(int xid, struct dentry *from_dentry, const char *fromPath,
+		struct dentry *to_dentry, const char *toPath)
+{
+	struct cifs_sb_info *cifs_sb = CIFS_SB(from_dentry->d_sb);
+	struct cifsTconInfo *pTcon = cifs_sb->tcon;
+	__u16 srcfid;
+	int oplock, rc;
+
+	/* try path-based rename first */
+	rc = CIFSSMBRename(xid, pTcon, fromPath, toPath, cifs_sb->local_nls,
+			   cifs_sb->mnt_cifs_flags &
+				CIFS_MOUNT_MAP_SPECIAL_CHR);
+
+	/*
+	 * don't bother with rename by filehandle unless file is busy and
+	 * source Note that cross directory moves do not work with
+	 * rename by filehandle to various Windows servers.
+	 */
+	if (rc == 0 || rc != -ETXTBSY)
+		return rc;
+
+	/* open the file to be renamed -- we need DELETE perms */
+	rc = CIFSSMBOpen(xid, pTcon, fromPath, FILE_OPEN, DELETE,
+			 CREATE_NOT_DIR, &srcfid, &oplock, NULL,
+			 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
+				CIFS_MOUNT_MAP_SPECIAL_CHR);
+
+	if (rc == 0) {
+		rc = CIFSSMBRenameOpenFile(xid, pTcon, srcfid,
+				(const char *) to_dentry->d_name.name,
+				cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
+					CIFS_MOUNT_MAP_SPECIAL_CHR);
+
+		CIFSSMBClose(xid, pTcon, srcfid);
+	}
+
+	return rc;
+}
+
 int cifs_rename(struct inode *source_inode, struct dentry *source_direntry,
 	struct inode *target_inode, struct dentry *target_direntry)
 {
-	char *fromName;
-	char *toName;
+	char *fromName = NULL;
+	char *toName = NULL;
 	struct cifs_sb_info *cifs_sb_source;
 	struct cifs_sb_info *cifs_sb_target;
 	struct cifsTconInfo *pTcon;
+	FILE_UNIX_BASIC_INFO *info_buf_source = NULL;
+	FILE_UNIX_BASIC_INFO *info_buf_target;
 	int xid;
-	int rc = 0;
-
-	xid = GetXid();
+	int rc;
 
 	cifs_sb_target = CIFS_SB(target_inode->i_sb);
 	cifs_sb_source = CIFS_SB(source_inode->i_sb);
 	pTcon = cifs_sb_source->tcon;
 
+	xid = GetXid();
+
+	/*
+	 * BB: this might be allowed if same server, but different share.
+	 * Consider adding support for this
+	 */
 	if (pTcon != cifs_sb_target->tcon) {
-		FreeXid(xid);
-		return -EXDEV;	/* BB actually could be allowed if same server,
-				   but different share.
-				   Might eventually add support for this */
+		rc = -EXDEV;
+		goto cifs_rename_exit;
 	}
 
-	/* we already  have the rename sem so we do not need to grab it again
-	   here to protect the path integrity */
+	/*
+	 * we already have the rename sem so we do not need to
+	 * grab it again here to protect the path integrity
+	 */
 	fromName = build_path_from_dentry(source_direntry);
-	toName = build_path_from_dentry(target_direntry);
-	if ((fromName == NULL) || (toName == NULL)) {
+	if (fromName == NULL) {
 		rc = -ENOMEM;
 		goto cifs_rename_exit;
 	}
 
-	rc = CIFSSMBRename(xid, pTcon, fromName, toName,
-			   cifs_sb_source->local_nls,
-			   cifs_sb_source->mnt_cifs_flags &
-				CIFS_MOUNT_MAP_SPECIAL_CHR);
-	if (rc == -EEXIST) {
-		/* check if they are the same file because rename of hardlinked
-		   files is a noop */
-		FILE_UNIX_BASIC_INFO *info_buf_source;
-		FILE_UNIX_BASIC_INFO *info_buf_target;
+	toName = build_path_from_dentry(target_direntry);
+	if (toName == NULL) {
+		rc = -ENOMEM;
+		goto cifs_rename_exit;
+	}
 
-		info_buf_source =
-			kmalloc(2 * sizeof(FILE_UNIX_BASIC_INFO), GFP_KERNEL);
-		if (info_buf_source != NULL) {
+	rc = cifs_do_rename(xid, source_direntry, fromName,
+			    target_direntry, toName);
+
+	if (rc == -EEXIST) {
+		if (pTcon->unix_ext) {
+			/*
+			 * Are src and dst hardlinks of same inode? We can
+			 * only tell with unix extensions enabled
+			 */
+			info_buf_source =
+				kmalloc(2 * sizeof(FILE_UNIX_BASIC_INFO),
+						GFP_KERNEL);
+			if (info_buf_source == NULL)
+				goto unlink_target;
+
 			info_buf_target = info_buf_source + 1;
-			if (pTcon->unix_ext)
-				rc = CIFSSMBUnixQPathInfo(xid, pTcon, fromName,
-					info_buf_source,
-					cifs_sb_source->local_nls,
-					cifs_sb_source->mnt_cifs_flags &
+			rc = CIFSSMBUnixQPathInfo(xid, pTcon, fromName,
+						info_buf_source,
+						cifs_sb_source->local_nls,
+						cifs_sb_source->mnt_cifs_flags &
 						CIFS_MOUNT_MAP_SPECIAL_CHR);
-			/* else rc is still EEXIST so will fall through to
-			   unlink the target and retry rename */
-			if (rc == 0) {
-				rc = CIFSSMBUnixQPathInfo(xid, pTcon, toName,
-						info_buf_target,
+			if (rc != 0)
+				goto unlink_target;
+
+			rc = CIFSSMBUnixQPathInfo(xid, pTcon,
+						toName, info_buf_target,
 						cifs_sb_target->local_nls,
 						/* remap based on source sb */
 						cifs_sb_source->mnt_cifs_flags &
-						    CIFS_MOUNT_MAP_SPECIAL_CHR);
-			}
-			if ((rc == 0) &&
-			    (info_buf_source->UniqueId ==
-			     info_buf_target->UniqueId)) {
-			/* do not rename since the files are hardlinked which
-			   is a noop */
-			} else {
-			/* we either can not tell the files are hardlinked
-			   (as with Windows servers) or files are not
-			   hardlinked so delete the target manually before
-			   renaming to follow POSIX rather than Windows
-			   semantics */
-				cifs_unlink(target_inode, target_direntry);
-				rc = CIFSSMBRename(xid, pTcon, fromName,
-						   toName,
-						   cifs_sb_source->local_nls,
-						   cifs_sb_source->mnt_cifs_flags
-						   & CIFS_MOUNT_MAP_SPECIAL_CHR);
-			}
-			kfree(info_buf_source);
-		} /* if we can not get memory just leave rc as EEXIST */
-	}
-
-	if (rc)
-		cFYI(1, ("rename rc %d", rc));
-
-	if ((rc == -EIO) || (rc == -EEXIST)) {
-		int oplock = 0;
-		__u16 netfid;
-
-		/* BB FIXME Is Generic Read correct for rename? */
-		/* if renaming directory - we should not say CREATE_NOT_DIR,
-		   need to test renaming open directory, also GENERIC_READ
-		   might not right be right access to request */
-		rc = CIFSSMBOpen(xid, pTcon, fromName, FILE_OPEN, GENERIC_READ,
-				 CREATE_NOT_DIR, &netfid, &oplock, NULL,
-				 cifs_sb_source->local_nls,
-				 cifs_sb_source->mnt_cifs_flags &
-					CIFS_MOUNT_MAP_SPECIAL_CHR);
-		if (rc == 0) {
-			rc = CIFSSMBRenameOpenFile(xid, pTcon, netfid, toName,
-					      cifs_sb_source->local_nls,
-					      cifs_sb_source->mnt_cifs_flags &
 						CIFS_MOUNT_MAP_SPECIAL_CHR);
-			CIFSSMBClose(xid, pTcon, netfid);
-		}
+
+			if (rc == 0 && (info_buf_source->UniqueId ==
+					info_buf_target->UniqueId))
+				/* same file, POSIX says that this is a noop */
+				goto cifs_rename_exit;
+		} /* else ... BB we could add the same check for Windows by
+		     checking the UniqueId via FILE_INTERNAL_INFO */
+unlink_target:
+		/*
+		 * we either can not tell the files are hardlinked (as with
+		 * Windows servers) or files are not hardlinked. Delete the
+		 * target manually before renaming to follow POSIX rather than
+		 * Windows semantics
+		 */
+		cifs_unlink(target_inode, target_direntry);
+		rc = cifs_do_rename(xid, source_direntry, fromName,
+				    target_direntry, toName);
 	}
 
 cifs_rename_exit:
+	kfree(info_buf_source);
 	kfree(fromName);
 	kfree(toName);
 	FreeXid(xid);
@@ -1507,101 +1636,6 @@
 }
 
 static int
-cifs_set_file_info(struct inode *inode, struct iattr *attrs, int xid,
-		    char *full_path, __u32 dosattr)
-{
-	int rc;
-	int oplock = 0;
-	__u16 netfid;
-	__u32 netpid;
-	bool set_time = false;
-	struct cifsFileInfo *open_file;
-	struct cifsInodeInfo *cifsInode = CIFS_I(inode);
-	struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
-	struct cifsTconInfo *pTcon = cifs_sb->tcon;
-	FILE_BASIC_INFO	info_buf;
-
-	if (attrs->ia_valid & ATTR_ATIME) {
-		set_time = true;
-		info_buf.LastAccessTime =
-			cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_atime));
-	} else
-		info_buf.LastAccessTime = 0;
-
-	if (attrs->ia_valid & ATTR_MTIME) {
-		set_time = true;
-		info_buf.LastWriteTime =
-		    cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_mtime));
-	} else
-		info_buf.LastWriteTime = 0;
-
-	/*
-	 * Samba throws this field away, but windows may actually use it.
-	 * Do not set ctime unless other time stamps are changed explicitly
-	 * (i.e. by utimes()) since we would then have a mix of client and
-	 * server times.
-	 */
-	if (set_time && (attrs->ia_valid & ATTR_CTIME)) {
-		cFYI(1, ("CIFS - CTIME changed"));
-		info_buf.ChangeTime =
-		    cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_ctime));
-	} else
-		info_buf.ChangeTime = 0;
-
-	info_buf.CreationTime = 0;	/* don't change */
-	info_buf.Attributes = cpu_to_le32(dosattr);
-
-	/*
-	 * If the file is already open for write, just use that fileid
-	 */
-	open_file = find_writable_file(cifsInode);
-	if (open_file) {
-		netfid = open_file->netfid;
-		netpid = open_file->pid;
-		goto set_via_filehandle;
-	}
-
-	/*
-	 * NT4 apparently returns success on this call, but it doesn't
-	 * really work.
-	 */
-	if (!(pTcon->ses->flags & CIFS_SES_NT4)) {
-		rc = CIFSSMBSetPathInfo(xid, pTcon, full_path,
-				     &info_buf, cifs_sb->local_nls,
-				     cifs_sb->mnt_cifs_flags &
-					CIFS_MOUNT_MAP_SPECIAL_CHR);
-		if (rc != -EOPNOTSUPP && rc != -EINVAL)
-			goto out;
-	}
-
-	cFYI(1, ("calling SetFileInfo since SetPathInfo for "
-		 "times not supported by this server"));
-	rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN,
-			 SYNCHRONIZE | FILE_WRITE_ATTRIBUTES,
-			 CREATE_NOT_DIR, &netfid, &oplock,
-			 NULL, cifs_sb->local_nls,
-			 cifs_sb->mnt_cifs_flags &
-				CIFS_MOUNT_MAP_SPECIAL_CHR);
-
-	if (rc != 0) {
-		if (rc == -EIO)
-			rc = -EINVAL;
-		goto out;
-	}
-
-	netpid = current->tgid;
-
-set_via_filehandle:
-	rc = CIFSSMBSetFileInfo(xid, pTcon, &info_buf, netfid, netpid);
-	if (open_file == NULL)
-		CIFSSMBClose(xid, pTcon, netfid);
-	else
-		atomic_dec(&open_file->wrtPending);
-out:
-	return rc;
-}
-
-static int
 cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs)
 {
 	int rc;
diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c
index 4b17f8f..88786ba 100644
--- a/fs/cifs/misc.c
+++ b/fs/cifs/misc.c
@@ -150,8 +150,7 @@
    but it may be more efficient to always alloc same size
    albeit slightly larger than necessary and maxbuffersize
    defaults to this and can not be bigger */
-	ret_buf = (struct smb_hdr *) mempool_alloc(cifs_req_poolp,
-						   GFP_KERNEL | GFP_NOFS);
+	ret_buf = mempool_alloc(cifs_req_poolp, GFP_NOFS);
 
 	/* clear the first few header bytes */
 	/* for most paths, more is cleared in header_assemble */
@@ -188,8 +187,7 @@
    but it may be more efficient to always alloc same size
    albeit slightly larger than necessary and maxbuffersize
    defaults to this and can not be bigger */
-	ret_buf = (struct smb_hdr *) mempool_alloc(cifs_sm_req_poolp,
-						   GFP_KERNEL | GFP_NOFS);
+	ret_buf = mempool_alloc(cifs_sm_req_poolp, GFP_NOFS);
 	if (ret_buf) {
 	/* No need to clear memory here, cleared in header assemble */
 	/*	memset(ret_buf, 0, sizeof(struct smb_hdr) + 27);*/
@@ -313,8 +311,6 @@
 	buffer->Flags2 = SMBFLG2_KNOWS_LONG_NAMES;
 	buffer->Pid = cpu_to_le16((__u16)current->tgid);
 	buffer->PidHigh = cpu_to_le16((__u16)(current->tgid >> 16));
-	spin_lock(&GlobalMid_Lock);
-	spin_unlock(&GlobalMid_Lock);
 	if (treeCon) {
 		buffer->Tid = treeCon->tid;
 		if (treeCon->ses) {
diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c
index 5f40ed3..765adf1 100644
--- a/fs/cifs/readdir.c
+++ b/fs/cifs/readdir.c
@@ -640,6 +640,70 @@
 
 }
 
+static int cifs_save_resume_key(const char *current_entry,
+	struct cifsFileInfo *cifsFile)
+{
+	int rc = 0;
+	unsigned int len = 0;
+	__u16 level;
+	char *filename;
+
+	if ((cifsFile == NULL) || (current_entry == NULL))
+		return -EINVAL;
+
+	level = cifsFile->srch_inf.info_level;
+
+	if (level == SMB_FIND_FILE_UNIX) {
+		FILE_UNIX_INFO *pFindData = (FILE_UNIX_INFO *)current_entry;
+
+		filename = &pFindData->FileName[0];
+		if (cifsFile->srch_inf.unicode) {
+			len = cifs_unicode_bytelen(filename);
+		} else {
+			/* BB should we make this strnlen of PATH_MAX? */
+			len = strnlen(filename, PATH_MAX);
+		}
+		cifsFile->srch_inf.resume_key = pFindData->ResumeKey;
+	} else if (level == SMB_FIND_FILE_DIRECTORY_INFO) {
+		FILE_DIRECTORY_INFO *pFindData =
+			(FILE_DIRECTORY_INFO *)current_entry;
+		filename = &pFindData->FileName[0];
+		len = le32_to_cpu(pFindData->FileNameLength);
+		cifsFile->srch_inf.resume_key = pFindData->FileIndex;
+	} else if (level == SMB_FIND_FILE_FULL_DIRECTORY_INFO) {
+		FILE_FULL_DIRECTORY_INFO *pFindData =
+			(FILE_FULL_DIRECTORY_INFO *)current_entry;
+		filename = &pFindData->FileName[0];
+		len = le32_to_cpu(pFindData->FileNameLength);
+		cifsFile->srch_inf.resume_key = pFindData->FileIndex;
+	} else if (level == SMB_FIND_FILE_ID_FULL_DIR_INFO) {
+		SEARCH_ID_FULL_DIR_INFO *pFindData =
+			(SEARCH_ID_FULL_DIR_INFO *)current_entry;
+		filename = &pFindData->FileName[0];
+		len = le32_to_cpu(pFindData->FileNameLength);
+		cifsFile->srch_inf.resume_key = pFindData->FileIndex;
+	} else if (level == SMB_FIND_FILE_BOTH_DIRECTORY_INFO) {
+		FILE_BOTH_DIRECTORY_INFO *pFindData =
+			(FILE_BOTH_DIRECTORY_INFO *)current_entry;
+		filename = &pFindData->FileName[0];
+		len = le32_to_cpu(pFindData->FileNameLength);
+		cifsFile->srch_inf.resume_key = pFindData->FileIndex;
+	} else if (level == SMB_FIND_FILE_INFO_STANDARD) {
+		FIND_FILE_STANDARD_INFO *pFindData =
+			(FIND_FILE_STANDARD_INFO *)current_entry;
+		filename = &pFindData->FileName[0];
+		/* one byte length, no name conversion */
+		len = (unsigned int)pFindData->FileNameLength;
+		cifsFile->srch_inf.resume_key = pFindData->ResumeKey;
+	} else {
+		cFYI(1, ("Unknown findfirst level %d", level));
+		return -EINVAL;
+	}
+	cifsFile->srch_inf.resume_name_len = len;
+	cifsFile->srch_inf.presume_name = filename;
+	return rc;
+}
+
 /* find the corresponding entry in the search */
 /* Note that the SMB server returns search entries for . and .. which
    complicates logic here if we choose to parse for them and we do not
@@ -703,6 +767,7 @@
 	while ((index_to_find >= cifsFile->srch_inf.index_of_last_entry) &&
 	      (rc == 0) && !cifsFile->srch_inf.endOfSearch) {
 		cFYI(1, ("calling findnext2"));
+		cifs_save_resume_key(cifsFile->srch_inf.last_entry, cifsFile);
 		rc = CIFSFindNext(xid, pTcon, cifsFile->netfid,
 				  &cifsFile->srch_inf);
 		if (rc)
@@ -919,69 +984,6 @@
 	return rc;
 }
 
-static int cifs_save_resume_key(const char *current_entry,
-	struct cifsFileInfo *cifsFile)
-{
-	int rc = 0;
-	unsigned int len = 0;
-	__u16 level;
-	char *filename;
-
-	if ((cifsFile == NULL) || (current_entry == NULL))
-		return -EINVAL;
-
-	level = cifsFile->srch_inf.info_level;
-
-	if (level == SMB_FIND_FILE_UNIX) {
-		FILE_UNIX_INFO *pFindData = (FILE_UNIX_INFO *)current_entry;
-
-		filename = &pFindData->FileName[0];
-		if (cifsFile->srch_inf.unicode) {
-			len = cifs_unicode_bytelen(filename);
-		} else {
-			/* BB should we make this strnlen of PATH_MAX? */
-			len = strnlen(filename, PATH_MAX);
-		}
-		cifsFile->srch_inf.resume_key = pFindData->ResumeKey;
-	} else if (level == SMB_FIND_FILE_DIRECTORY_INFO) {
-		FILE_DIRECTORY_INFO *pFindData =
-			(FILE_DIRECTORY_INFO *)current_entry;
-		filename = &pFindData->FileName[0];
-		len = le32_to_cpu(pFindData->FileNameLength);
-		cifsFile->srch_inf.resume_key = pFindData->FileIndex;
-	} else if (level == SMB_FIND_FILE_FULL_DIRECTORY_INFO) {
-		FILE_FULL_DIRECTORY_INFO *pFindData =
-			(FILE_FULL_DIRECTORY_INFO *)current_entry;
-		filename = &pFindData->FileName[0];
-		len = le32_to_cpu(pFindData->FileNameLength);
-		cifsFile->srch_inf.resume_key = pFindData->FileIndex;
-	} else if (level == SMB_FIND_FILE_ID_FULL_DIR_INFO) {
-		SEARCH_ID_FULL_DIR_INFO *pFindData =
-			(SEARCH_ID_FULL_DIR_INFO *)current_entry;
-		filename = &pFindData->FileName[0];
-		len = le32_to_cpu(pFindData->FileNameLength);
-		cifsFile->srch_inf.resume_key = pFindData->FileIndex;
-	} else if (level == SMB_FIND_FILE_BOTH_DIRECTORY_INFO) {
-		FILE_BOTH_DIRECTORY_INFO *pFindData =
-			(FILE_BOTH_DIRECTORY_INFO *)current_entry;
-		filename = &pFindData->FileName[0];
-		len = le32_to_cpu(pFindData->FileNameLength);
-		cifsFile->srch_inf.resume_key = pFindData->FileIndex;
-	} else if (level == SMB_FIND_FILE_INFO_STANDARD) {
-		FIND_FILE_STANDARD_INFO *pFindData =
-			(FIND_FILE_STANDARD_INFO *)current_entry;
-		filename = &pFindData->FileName[0];
-		/* one byte length, no name conversion */
-		len = (unsigned int)pFindData->FileNameLength;
-		cifsFile->srch_inf.resume_key = pFindData->ResumeKey;
-	} else {
-		cFYI(1, ("Unknown findfirst level %d", level));
-		return -EINVAL;
-	}
-	cifsFile->srch_inf.resume_name_len = len;
-	cifsFile->srch_inf.presume_name = filename;
-	return rc;
-}
 
 int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
 {
diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c
index 252fdc0..2851d5d 100644
--- a/fs/cifs/sess.c
+++ b/fs/cifs/sess.c
@@ -624,8 +624,10 @@
 					 ses, nls_cp);
 
 ssetup_exit:
-	if (spnego_key)
+	if (spnego_key) {
+		key_revoke(spnego_key);
 		key_put(spnego_key);
+	}
 	kfree(str_area);
 	if (resp_buf_type == CIFS_SMALL_BUFFER) {
 		cFYI(1, ("ssetup freeing small buf %p", iov[0].iov_base));
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c
index e286db9..bf0e6d8 100644
--- a/fs/cifs/transport.c
+++ b/fs/cifs/transport.c
@@ -50,8 +50,7 @@
 		return NULL;
 	}
 
-	temp = (struct mid_q_entry *) mempool_alloc(cifs_mid_poolp,
-						    GFP_KERNEL | GFP_NOFS);
+	temp = mempool_alloc(cifs_mid_poolp, GFP_NOFS);
 	if (temp == NULL)
 		return temp;
 	else {
diff --git a/fs/dcache.c b/fs/dcache.c
index 80e9395..e7a1a99 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -1395,6 +1395,10 @@
 		if (dentry->d_parent != parent)
 			goto next;
 
+		/* non-existing due to RCU? */
+		if (d_unhashed(dentry))
+			goto next;
+
 		/*
 		 * It is safe to compare names since d_move() cannot
 		 * change the qstr (protected by d_lock).
@@ -1410,10 +1414,8 @@
 				goto next;
 		}
 
-		if (!d_unhashed(dentry)) {
-			atomic_inc(&dentry->d_count);
-			found = dentry;
-		}
+		atomic_inc(&dentry->d_count);
+		found = dentry;
 		spin_unlock(&dentry->d_lock);
 		break;
 next:
diff --git a/fs/debugfs/inode.c b/fs/debugfs/inode.c
index 08e28c9..3dbe216 100644
--- a/fs/debugfs/inode.c
+++ b/fs/debugfs/inode.c
@@ -26,8 +26,7 @@
 #include <linux/debugfs.h>
 #include <linux/fsnotify.h>
 #include <linux/string.h>
-
-#define DEBUGFS_MAGIC	0x64626720
+#include <linux/magic.h>
 
 static struct vfsmount *debugfs_mount;
 static int debugfs_mount_count;
diff --git a/fs/devpts/inode.c b/fs/devpts/inode.c
index 488eb42..4a714f6c 100644
--- a/fs/devpts/inode.c
+++ b/fs/devpts/inode.c
@@ -27,6 +27,7 @@
 #define DEVPTS_SUPER_MAGIC 0x1cd1
 
 #define DEVPTS_DEFAULT_MODE 0600
+#define PTMX_MINOR	2
 
 extern int pty_limit;			/* Config limit on Unix98 ptys */
 static DEFINE_IDA(allocated_ptys);
@@ -48,7 +49,7 @@
 	Opt_err
 };
 
-static match_table_t tokens = {
+static const match_table_t tokens = {
 	{Opt_uid, "uid=%u"},
 	{Opt_gid, "gid=%u"},
 	{Opt_mode, "mode=%o"},
@@ -169,15 +170,7 @@
  * to the System V naming convention
  */
 
-static struct dentry *get_node(int num)
-{
-	char s[12];
-	struct dentry *root = devpts_root;
-	mutex_lock(&root->d_inode->i_mutex);
-	return lookup_one_len(s, root, sprintf(s, "%d", num));
-}
-
-int devpts_new_index(void)
+int devpts_new_index(struct inode *ptmx_inode)
 {
 	int index;
 	int ida_ret;
@@ -205,20 +198,21 @@
 	return index;
 }
 
-void devpts_kill_index(int idx)
+void devpts_kill_index(struct inode *ptmx_inode, int idx)
 {
 	mutex_lock(&allocated_ptys_lock);
 	ida_remove(&allocated_ptys, idx);
 	mutex_unlock(&allocated_ptys_lock);
 }
 
-int devpts_pty_new(struct tty_struct *tty)
+int devpts_pty_new(struct inode *ptmx_inode, struct tty_struct *tty)
 {
 	int number = tty->index; /* tty layer puts index from devpts_new_index() in here */
 	struct tty_driver *driver = tty->driver;
 	dev_t device = MKDEV(driver->major, driver->minor_start+number);
 	struct dentry *dentry;
 	struct inode *inode = new_inode(devpts_mnt->mnt_sb);
+	char s[12];
 
 	/* We're supposed to be given the slave end of a pty */
 	BUG_ON(driver->type != TTY_DRIVER_TYPE_PTY);
@@ -233,10 +227,15 @@
 	inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
 	init_special_inode(inode, S_IFCHR|config.mode, device);
 	inode->i_private = tty;
+	tty->driver_data = inode;
 
-	dentry = get_node(number);
-	if (!IS_ERR(dentry) && !dentry->d_inode) {
-		d_instantiate(dentry, inode);
+	sprintf(s, "%d", number);
+
+	mutex_lock(&devpts_root->d_inode->i_mutex);
+
+	dentry = d_alloc_name(devpts_root, s);
+	if (!IS_ERR(dentry)) {
+		d_add(dentry, inode);
 		fsnotify_create(devpts_root->d_inode, dentry);
 	}
 
@@ -245,36 +244,31 @@
 	return 0;
 }
 
-struct tty_struct *devpts_get_tty(int number)
+struct tty_struct *devpts_get_tty(struct inode *pts_inode, int number)
 {
-	struct dentry *dentry = get_node(number);
-	struct tty_struct *tty;
+	BUG_ON(pts_inode->i_rdev == MKDEV(TTYAUX_MAJOR, PTMX_MINOR));
 
-	tty = NULL;
-	if (!IS_ERR(dentry)) {
-		if (dentry->d_inode)
-			tty = dentry->d_inode->i_private;
-		dput(dentry);
-	}
-
-	mutex_unlock(&devpts_root->d_inode->i_mutex);
-
-	return tty;
+	if (pts_inode->i_sb->s_magic == DEVPTS_SUPER_MAGIC)
+		return (struct tty_struct *)pts_inode->i_private;
+	return NULL;
 }
 
-void devpts_pty_kill(int number)
+void devpts_pty_kill(struct tty_struct *tty)
 {
-	struct dentry *dentry = get_node(number);
+	struct inode *inode = tty->driver_data;
+	struct dentry *dentry;
 
-	if (!IS_ERR(dentry)) {
-		struct inode *inode = dentry->d_inode;
-		if (inode) {
-			inode->i_nlink--;
-			d_delete(dentry);
-			dput(dentry);
-		}
+	BUG_ON(inode->i_rdev == MKDEV(TTYAUX_MAJOR, PTMX_MINOR));
+
+	mutex_lock(&devpts_root->d_inode->i_mutex);
+
+	dentry = d_find_alias(inode);
+	if (dentry && !IS_ERR(dentry)) {
+		inode->i_nlink--;
+		d_delete(dentry);
 		dput(dentry);
 	}
+
 	mutex_unlock(&devpts_root->d_inode->i_mutex);
 }
 
diff --git a/fs/dlm/config.c b/fs/dlm/config.c
index 89d2fb7..fd9859f 100644
--- a/fs/dlm/config.c
+++ b/fs/dlm/config.c
@@ -14,6 +14,9 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/configfs.h>
+#include <linux/in.h>
+#include <linux/in6.h>
+#include <net/ipv6.h>
 #include <net/sock.h>
 
 #include "config.h"
@@ -377,24 +380,24 @@
 	.ct_owner = THIS_MODULE,
 };
 
-static struct dlm_cluster *to_cluster(struct config_item *i)
+static struct dlm_cluster *config_item_to_cluster(struct config_item *i)
 {
 	return i ? container_of(to_config_group(i), struct dlm_cluster, group) :
 		   NULL;
 }
 
-static struct dlm_space *to_space(struct config_item *i)
+static struct dlm_space *config_item_to_space(struct config_item *i)
 {
 	return i ? container_of(to_config_group(i), struct dlm_space, group) :
 		   NULL;
 }
 
-static struct dlm_comm *to_comm(struct config_item *i)
+static struct dlm_comm *config_item_to_comm(struct config_item *i)
 {
 	return i ? container_of(i, struct dlm_comm, item) : NULL;
 }
 
-static struct dlm_node *to_node(struct config_item *i)
+static struct dlm_node *config_item_to_node(struct config_item *i)
 {
 	return i ? container_of(i, struct dlm_node, item) : NULL;
 }
@@ -450,7 +453,7 @@
 
 static void drop_cluster(struct config_group *g, struct config_item *i)
 {
-	struct dlm_cluster *cl = to_cluster(i);
+	struct dlm_cluster *cl = config_item_to_cluster(i);
 	struct config_item *tmp;
 	int j;
 
@@ -468,7 +471,7 @@
 
 static void release_cluster(struct config_item *i)
 {
-	struct dlm_cluster *cl = to_cluster(i);
+	struct dlm_cluster *cl = config_item_to_cluster(i);
 	kfree(cl->group.default_groups);
 	kfree(cl);
 }
@@ -507,7 +510,7 @@
 
 static void drop_space(struct config_group *g, struct config_item *i)
 {
-	struct dlm_space *sp = to_space(i);
+	struct dlm_space *sp = config_item_to_space(i);
 	struct config_item *tmp;
 	int j;
 
@@ -524,7 +527,7 @@
 
 static void release_space(struct config_item *i)
 {
-	struct dlm_space *sp = to_space(i);
+	struct dlm_space *sp = config_item_to_space(i);
 	kfree(sp->group.default_groups);
 	kfree(sp);
 }
@@ -546,7 +549,7 @@
 
 static void drop_comm(struct config_group *g, struct config_item *i)
 {
-	struct dlm_comm *cm = to_comm(i);
+	struct dlm_comm *cm = config_item_to_comm(i);
 	if (local_comm == cm)
 		local_comm = NULL;
 	dlm_lowcomms_close(cm->nodeid);
@@ -557,13 +560,13 @@
 
 static void release_comm(struct config_item *i)
 {
-	struct dlm_comm *cm = to_comm(i);
+	struct dlm_comm *cm = config_item_to_comm(i);
 	kfree(cm);
 }
 
 static struct config_item *make_node(struct config_group *g, const char *name)
 {
-	struct dlm_space *sp = to_space(g->cg_item.ci_parent);
+	struct dlm_space *sp = config_item_to_space(g->cg_item.ci_parent);
 	struct dlm_node *nd;
 
 	nd = kzalloc(sizeof(struct dlm_node), GFP_KERNEL);
@@ -585,8 +588,8 @@
 
 static void drop_node(struct config_group *g, struct config_item *i)
 {
-	struct dlm_space *sp = to_space(g->cg_item.ci_parent);
-	struct dlm_node *nd = to_node(i);
+	struct dlm_space *sp = config_item_to_space(g->cg_item.ci_parent);
+	struct dlm_node *nd = config_item_to_node(i);
 
 	mutex_lock(&sp->members_lock);
 	list_del(&nd->list);
@@ -598,7 +601,7 @@
 
 static void release_node(struct config_item *i)
 {
-	struct dlm_node *nd = to_node(i);
+	struct dlm_node *nd = config_item_to_node(i);
 	kfree(nd);
 }
 
@@ -632,7 +635,7 @@
 static ssize_t show_cluster(struct config_item *i, struct configfs_attribute *a,
 			    char *buf)
 {
-	struct dlm_cluster *cl = to_cluster(i);
+	struct dlm_cluster *cl = config_item_to_cluster(i);
 	struct cluster_attribute *cla =
 			container_of(a, struct cluster_attribute, attr);
 	return cla->show ? cla->show(cl, buf) : 0;
@@ -642,7 +645,7 @@
 			     struct configfs_attribute *a,
 			     const char *buf, size_t len)
 {
-	struct dlm_cluster *cl = to_cluster(i);
+	struct dlm_cluster *cl = config_item_to_cluster(i);
 	struct cluster_attribute *cla =
 		container_of(a, struct cluster_attribute, attr);
 	return cla->store ? cla->store(cl, buf, len) : -EINVAL;
@@ -651,7 +654,7 @@
 static ssize_t show_comm(struct config_item *i, struct configfs_attribute *a,
 			 char *buf)
 {
-	struct dlm_comm *cm = to_comm(i);
+	struct dlm_comm *cm = config_item_to_comm(i);
 	struct comm_attribute *cma =
 			container_of(a, struct comm_attribute, attr);
 	return cma->show ? cma->show(cm, buf) : 0;
@@ -660,7 +663,7 @@
 static ssize_t store_comm(struct config_item *i, struct configfs_attribute *a,
 			  const char *buf, size_t len)
 {
-	struct dlm_comm *cm = to_comm(i);
+	struct dlm_comm *cm = config_item_to_comm(i);
 	struct comm_attribute *cma =
 		container_of(a, struct comm_attribute, attr);
 	return cma->store ? cma->store(cm, buf, len) : -EINVAL;
@@ -714,7 +717,7 @@
 static ssize_t show_node(struct config_item *i, struct configfs_attribute *a,
 			 char *buf)
 {
-	struct dlm_node *nd = to_node(i);
+	struct dlm_node *nd = config_item_to_node(i);
 	struct node_attribute *nda =
 			container_of(a, struct node_attribute, attr);
 	return nda->show ? nda->show(nd, buf) : 0;
@@ -723,7 +726,7 @@
 static ssize_t store_node(struct config_item *i, struct configfs_attribute *a,
 			  const char *buf, size_t len)
 {
-	struct dlm_node *nd = to_node(i);
+	struct dlm_node *nd = config_item_to_node(i);
 	struct node_attribute *nda =
 		container_of(a, struct node_attribute, attr);
 	return nda->store ? nda->store(nd, buf, len) : -EINVAL;
@@ -768,7 +771,7 @@
 	i = config_group_find_item(space_list, name);
 	mutex_unlock(&space_list->cg_subsys->su_mutex);
 
-	return to_space(i);
+	return config_item_to_space(i);
 }
 
 static void put_space(struct dlm_space *sp)
@@ -776,6 +779,33 @@
 	config_item_put(&sp->group.cg_item);
 }
 
+static int addr_compare(struct sockaddr_storage *x, struct sockaddr_storage *y)
+{
+	switch (x->ss_family) {
+	case AF_INET: {
+		struct sockaddr_in *sinx = (struct sockaddr_in *)x;
+		struct sockaddr_in *siny = (struct sockaddr_in *)y;
+		if (sinx->sin_addr.s_addr != siny->sin_addr.s_addr)
+			return 0;
+		if (sinx->sin_port != siny->sin_port)
+			return 0;
+		break;
+	}
+	case AF_INET6: {
+		struct sockaddr_in6 *sinx = (struct sockaddr_in6 *)x;
+		struct sockaddr_in6 *siny = (struct sockaddr_in6 *)y;
+		if (!ipv6_addr_equal(&sinx->sin6_addr, &siny->sin6_addr))
+			return 0;
+		if (sinx->sin6_port != siny->sin6_port)
+			return 0;
+		break;
+	}
+	default:
+		return 0;
+	}
+	return 1;
+}
+
 static struct dlm_comm *get_comm(int nodeid, struct sockaddr_storage *addr)
 {
 	struct config_item *i;
@@ -788,7 +818,7 @@
 	mutex_lock(&clusters_root.subsys.su_mutex);
 
 	list_for_each_entry(i, &comm_list->cg_children, ci_entry) {
-		cm = to_comm(i);
+		cm = config_item_to_comm(i);
 
 		if (nodeid) {
 			if (cm->nodeid != nodeid)
@@ -797,8 +827,7 @@
 			config_item_get(i);
 			break;
 		} else {
-			if (!cm->addr_count ||
-			    memcmp(cm->addr[0], addr, sizeof(*addr)))
+			if (!cm->addr_count || !addr_compare(cm->addr[0], addr))
 				continue;
 			found = 1;
 			config_item_get(i);
diff --git a/fs/dlm/dlm_internal.h b/fs/dlm/dlm_internal.h
index 5a7ac33..868e4c9 100644
--- a/fs/dlm/dlm_internal.h
+++ b/fs/dlm/dlm_internal.h
@@ -2,7 +2,7 @@
 *******************************************************************************
 **
 **  Copyright (C) Sistina Software, Inc.  1997-2003  All rights reserved.
-**  Copyright (C) 2004-2007 Red Hat, Inc.  All rights reserved.
+**  Copyright (C) 2004-2008 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
@@ -441,8 +441,11 @@
 	uint32_t		ls_global_id;	/* global unique lockspace ID */
 	uint32_t		ls_exflags;
 	int			ls_lvblen;
-	int			ls_count;	/* reference count */
+	int			ls_count;	/* refcount of processes in
+						   the dlm using this ls */
+	int			ls_create_count; /* create/release refcount */
 	unsigned long		ls_flags;	/* LSFL_ */
+	unsigned long		ls_scan_time;
 	struct kobject		ls_kobj;
 
 	struct dlm_rsbtable	*ls_rsbtbl;
diff --git a/fs/dlm/lockspace.c b/fs/dlm/lockspace.c
index 499e167..d910501 100644
--- a/fs/dlm/lockspace.c
+++ b/fs/dlm/lockspace.c
@@ -2,7 +2,7 @@
 *******************************************************************************
 **
 **  Copyright (C) Sistina Software, Inc.  1997-2003  All rights reserved.
-**  Copyright (C) 2004-2007 Red Hat, Inc.  All rights reserved.
+**  Copyright (C) 2004-2008 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
@@ -23,6 +23,7 @@
 #include "lock.h"
 #include "recover.h"
 #include "requestqueue.h"
+#include "user.h"
 
 static int			ls_count;
 static struct mutex		ls_lock;
@@ -211,19 +212,41 @@
 	kset_unregister(dlm_kset);
 }
 
-static int dlm_scand(void *data)
+static struct dlm_ls *find_ls_to_scan(void)
 {
 	struct dlm_ls *ls;
 
+	spin_lock(&lslist_lock);
+	list_for_each_entry(ls, &lslist, ls_list) {
+		if (time_after_eq(jiffies, ls->ls_scan_time +
+					    dlm_config.ci_scan_secs * HZ)) {
+			spin_unlock(&lslist_lock);
+			return ls;
+		}
+	}
+	spin_unlock(&lslist_lock);
+	return NULL;
+}
+
+static int dlm_scand(void *data)
+{
+	struct dlm_ls *ls;
+	int timeout_jiffies = dlm_config.ci_scan_secs * HZ;
+
 	while (!kthread_should_stop()) {
-		list_for_each_entry(ls, &lslist, ls_list) {
+		ls = find_ls_to_scan();
+		if (ls) {
 			if (dlm_lock_recovery_try(ls)) {
+				ls->ls_scan_time = jiffies;
 				dlm_scan_rsbs(ls);
 				dlm_scan_timeout(ls);
 				dlm_unlock_recovery(ls);
+			} else {
+				ls->ls_scan_time += HZ;
 			}
+		} else {
+			schedule_timeout_interruptible(timeout_jiffies);
 		}
-		schedule_timeout_interruptible(dlm_config.ci_scan_secs * HZ);
 	}
 	return 0;
 }
@@ -246,23 +269,6 @@
 	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;
@@ -327,6 +333,7 @@
 	for (;;) {
 		spin_lock(&lslist_lock);
 		if (ls->ls_count == 0) {
+			WARN_ON(ls->ls_create_count != 0);
 			list_del(&ls->ls_list);
 			spin_unlock(&lslist_lock);
 			return;
@@ -381,7 +388,7 @@
 			 uint32_t flags, int lvblen)
 {
 	struct dlm_ls *ls;
-	int i, size, error = -ENOMEM;
+	int i, size, error;
 	int do_unreg = 0;
 
 	if (namelen > DLM_LOCKSPACE_LEN)
@@ -393,13 +400,38 @@
 	if (!try_module_get(THIS_MODULE))
 		return -EINVAL;
 
-	ls = dlm_find_lockspace_name(name, namelen);
-	if (ls) {
-		*lockspace = ls;
+	if (!dlm_user_daemon_available()) {
 		module_put(THIS_MODULE);
-		return -EEXIST;
+		return -EUNATCH;
 	}
 
+	error = 0;
+
+	spin_lock(&lslist_lock);
+	list_for_each_entry(ls, &lslist, ls_list) {
+		WARN_ON(ls->ls_create_count <= 0);
+		if (ls->ls_namelen != namelen)
+			continue;
+		if (memcmp(ls->ls_name, name, namelen))
+			continue;
+		if (flags & DLM_LSFL_NEWEXCL) {
+			error = -EEXIST;
+			break;
+		}
+		ls->ls_create_count++;
+		module_put(THIS_MODULE);
+		error = 1; /* not an error, return 0 */
+		break;
+	}
+	spin_unlock(&lslist_lock);
+
+	if (error < 0)
+		goto out;
+	if (error)
+		goto ret_zero;
+
+	error = -ENOMEM;
+
 	ls = kzalloc(sizeof(struct dlm_ls) + namelen, GFP_KERNEL);
 	if (!ls)
 		goto out;
@@ -408,6 +440,7 @@
 	ls->ls_lvblen = lvblen;
 	ls->ls_count = 0;
 	ls->ls_flags = 0;
+	ls->ls_scan_time = jiffies;
 
 	if (flags & DLM_LSFL_TIMEWARN)
 		set_bit(LSFL_TIMEWARN, &ls->ls_flags);
@@ -418,8 +451,9 @@
 		ls->ls_allocation = GFP_KERNEL;
 
 	/* ls_exflags are forced to match among nodes, and we don't
-	   need to require all nodes to have TIMEWARN or FS set */
-	ls->ls_exflags = (flags & ~(DLM_LSFL_TIMEWARN | DLM_LSFL_FS));
+	   need to require all nodes to have some flags set */
+	ls->ls_exflags = (flags & ~(DLM_LSFL_TIMEWARN | DLM_LSFL_FS |
+				    DLM_LSFL_NEWEXCL));
 
 	size = dlm_config.ci_rsbtbl_size;
 	ls->ls_rsbtbl_size = size;
@@ -510,6 +544,7 @@
 	down_write(&ls->ls_in_recovery);
 
 	spin_lock(&lslist_lock);
+	ls->ls_create_count = 1;
 	list_add(&ls->ls_list, &lslist);
 	spin_unlock(&lslist_lock);
 
@@ -548,7 +583,7 @@
 	dlm_create_debug_file(ls);
 
 	log_debug(ls, "join complete");
-
+ ret_zero:
 	*lockspace = ls;
 	return 0;
 
@@ -635,13 +670,34 @@
 	struct dlm_lkb *lkb;
 	struct dlm_rsb *rsb;
 	struct list_head *head;
-	int i;
-	int busy = lockspace_busy(ls);
+	int i, busy, rv;
 
-	if (busy > force)
-		return -EBUSY;
+	busy = lockspace_busy(ls);
 
-	if (force < 3)
+	spin_lock(&lslist_lock);
+	if (ls->ls_create_count == 1) {
+		if (busy > force)
+			rv = -EBUSY;
+		else {
+			/* remove_lockspace takes ls off lslist */
+			ls->ls_create_count = 0;
+			rv = 0;
+		}
+	} else if (ls->ls_create_count > 1) {
+		rv = --ls->ls_create_count;
+	} else {
+		rv = -EINVAL;
+	}
+	spin_unlock(&lslist_lock);
+
+	if (rv) {
+		log_debug(ls, "release_lockspace no remove %d", rv);
+		return rv;
+	}
+
+	dlm_device_deregister(ls);
+
+	if (force < 3 && dlm_user_daemon_available())
 		do_uevent(ls, 0);
 
 	dlm_recoverd_stop(ls);
@@ -720,15 +776,10 @@
 	dlm_clear_members(ls);
 	dlm_clear_members_gone(ls);
 	kfree(ls->ls_node_array);
+	log_debug(ls, "release_lockspace final free");
 	kobject_put(&ls->ls_kobj);
 	/* The ls structure will be freed when the kobject is done with */
 
-	mutex_lock(&ls_lock);
-	ls_count--;
-	if (!ls_count)
-		threads_stop();
-	mutex_unlock(&ls_lock);
-
 	module_put(THIS_MODULE);
 	return 0;
 }
@@ -750,11 +801,38 @@
 int dlm_release_lockspace(void *lockspace, int force)
 {
 	struct dlm_ls *ls;
+	int error;
 
 	ls = dlm_find_lockspace_local(lockspace);
 	if (!ls)
 		return -EINVAL;
 	dlm_put_lockspace(ls);
-	return release_lockspace(ls, force);
+
+	mutex_lock(&ls_lock);
+	error = release_lockspace(ls, force);
+	if (!error)
+		ls_count--;
+	else if (!ls_count)
+		threads_stop();
+	mutex_unlock(&ls_lock);
+
+	return error;
+}
+
+void dlm_stop_lockspaces(void)
+{
+	struct dlm_ls *ls;
+
+ restart:
+	spin_lock(&lslist_lock);
+	list_for_each_entry(ls, &lslist, ls_list) {
+		if (!test_bit(LSFL_RUNNING, &ls->ls_flags))
+			continue;
+		spin_unlock(&lslist_lock);
+		log_error(ls, "no userland control daemon, stopping lockspace");
+		dlm_ls_stop(ls);
+		goto restart;
+	}
+	spin_unlock(&lslist_lock);
 }
 
diff --git a/fs/dlm/lockspace.h b/fs/dlm/lockspace.h
index 891eabb..f879f87 100644
--- a/fs/dlm/lockspace.h
+++ b/fs/dlm/lockspace.h
@@ -20,6 +20,7 @@
 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);
+void dlm_stop_lockspaces(void);
 
 #endif				/* __LOCKSPACE_DOT_H__ */
 
diff --git a/fs/dlm/user.c b/fs/dlm/user.c
index 34f14a1..b3832c6 100644
--- a/fs/dlm/user.c
+++ b/fs/dlm/user.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2006-2007 Red Hat, Inc.  All rights reserved.
+ * Copyright (C) 2006-2008 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
@@ -15,7 +15,6 @@
 #include <linux/poll.h>
 #include <linux/signal.h>
 #include <linux/spinlock.h>
-#include <linux/smp_lock.h>
 #include <linux/dlm.h>
 #include <linux/dlm_device.h>
 
@@ -27,6 +26,8 @@
 
 static const char name_prefix[] = "dlm";
 static const struct file_operations device_fops;
+static atomic_t dlm_monitor_opened;
+static int dlm_monitor_unused = 1;
 
 #ifdef CONFIG_COMPAT
 
@@ -340,10 +341,15 @@
 	return error;
 }
 
-static int create_misc_device(struct dlm_ls *ls, char *name)
+static int dlm_device_register(struct dlm_ls *ls, char *name)
 {
 	int error, len;
 
+	/* The device is already registered.  This happens when the
+	   lockspace is created multiple times from userspace. */
+	if (ls->ls_device.name)
+		return 0;
+
 	error = -ENOMEM;
 	len = strlen(name) + strlen(name_prefix) + 2;
 	ls->ls_device.name = kzalloc(len, GFP_KERNEL);
@@ -363,6 +369,22 @@
 	return error;
 }
 
+int dlm_device_deregister(struct dlm_ls *ls)
+{
+	int error;
+
+	/* The device is not registered.  This happens when the lockspace
+	   was never used from userspace, or when device_create_lockspace()
+	   calls dlm_release_lockspace() after the register fails. */
+	if (!ls->ls_device.name)
+		return 0;
+
+	error = misc_deregister(&ls->ls_device);
+	if (!error)
+		kfree(ls->ls_device.name);
+	return error;
+}
+
 static int device_user_purge(struct dlm_user_proc *proc,
 			     struct dlm_purge_params *params)
 {
@@ -397,7 +419,7 @@
 	if (!ls)
 		return -ENOENT;
 
-	error = create_misc_device(ls, params->name);
+	error = dlm_device_register(ls, params->name);
 	dlm_put_lockspace(ls);
 
 	if (error)
@@ -421,31 +443,22 @@
 	if (!ls)
 		return -ENOENT;
 
-	/* Deregister the misc device first, so we don't have
-	 * a device that's not attached to a lockspace. If
-	 * dlm_release_lockspace fails then we can recreate it
-	 */
-	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);
+
+	/* The final 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 proceed.  release also calls the
+	   device_deregister above.  Converting a positive return value
+	   from release to zero means that userspace won't know when its
+	   release was the final one, but it shouldn't need to know. */
+
 	error = dlm_release_lockspace(lockspace, force);
-	if (error)
-		create_misc_device(ls, ls->ls_name);
- out:
+	if (error > 0)
+		error = 0;
 	return error;
 }
 
@@ -623,17 +636,13 @@
 	struct dlm_user_proc *proc;
 	struct dlm_ls *ls;
 
-	lock_kernel();
 	ls = dlm_find_lockspace_device(iminor(inode));
-	if (!ls) {
-		unlock_kernel();
+	if (!ls)
 		return -ENOENT;
-	}
 
 	proc = kzalloc(sizeof(struct dlm_user_proc), GFP_KERNEL);
 	if (!proc) {
 		dlm_put_lockspace(ls);
-		unlock_kernel();
 		return -ENOMEM;
 	}
 
@@ -645,7 +654,6 @@
 	spin_lock_init(&proc->locks_spin);
 	init_waitqueue_head(&proc->wait);
 	file->private_data = proc;
-	unlock_kernel();
 
 	return 0;
 }
@@ -878,9 +886,28 @@
 	return 0;
 }
 
+int dlm_user_daemon_available(void)
+{
+	/* dlm_controld hasn't started (or, has started, but not
+	   properly populated configfs) */
+
+	if (!dlm_our_nodeid())
+		return 0;
+
+	/* This is to deal with versions of dlm_controld that don't
+	   know about the monitor device.  We assume that if the
+	   dlm_controld was started (above), but the monitor device
+	   was never opened, that it's an old version.  dlm_controld
+	   should open the monitor device before populating configfs. */
+
+	if (dlm_monitor_unused)
+		return 1;
+
+	return atomic_read(&dlm_monitor_opened) ? 1 : 0;
+}
+
 static int ctl_device_open(struct inode *inode, struct file *file)
 {
-	cycle_kernel_lock();
 	file->private_data = NULL;
 	return 0;
 }
@@ -890,6 +917,20 @@
 	return 0;
 }
 
+static int monitor_device_open(struct inode *inode, struct file *file)
+{
+	atomic_inc(&dlm_monitor_opened);
+	dlm_monitor_unused = 0;
+	return 0;
+}
+
+static int monitor_device_close(struct inode *inode, struct file *file)
+{
+	if (atomic_dec_and_test(&dlm_monitor_opened))
+		dlm_stop_lockspaces();
+	return 0;
+}
+
 static const struct file_operations device_fops = {
 	.open    = device_open,
 	.release = device_close,
@@ -913,19 +954,42 @@
 	.minor = MISC_DYNAMIC_MINOR,
 };
 
+static const struct file_operations monitor_device_fops = {
+	.open    = monitor_device_open,
+	.release = monitor_device_close,
+	.owner   = THIS_MODULE,
+};
+
+static struct miscdevice monitor_device = {
+	.name  = "dlm-monitor",
+	.fops  = &monitor_device_fops,
+	.minor = MISC_DYNAMIC_MINOR,
+};
+
 int __init dlm_user_init(void)
 {
 	int error;
 
-	error = misc_register(&ctl_device);
-	if (error)
-		log_print("misc_register failed for control device");
+	atomic_set(&dlm_monitor_opened, 0);
 
+	error = misc_register(&ctl_device);
+	if (error) {
+		log_print("misc_register failed for control device");
+		goto out;
+	}
+
+	error = misc_register(&monitor_device);
+	if (error) {
+		log_print("misc_register failed for monitor device");
+		misc_deregister(&ctl_device);
+	}
+ out:
 	return error;
 }
 
 void dlm_user_exit(void)
 {
 	misc_deregister(&ctl_device);
+	misc_deregister(&monitor_device);
 }
 
diff --git a/fs/dlm/user.h b/fs/dlm/user.h
index d38e9f3..35eb6a1 100644
--- a/fs/dlm/user.h
+++ b/fs/dlm/user.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2006 Red Hat, Inc.  All rights reserved.
+ * Copyright (C) 2006-2008 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
@@ -12,5 +12,7 @@
 void dlm_user_add_ast(struct dlm_lkb *lkb, int type);
 int dlm_user_init(void);
 void dlm_user_exit(void);
+int dlm_device_deregister(struct dlm_ls *ls);
+int dlm_user_daemon_available(void);
 
 #endif
diff --git a/fs/dquot.c b/fs/dquot.c
index 8ec4d6c..ad7e590 100644
--- a/fs/dquot.c
+++ b/fs/dquot.c
@@ -895,10 +895,9 @@
 	    warntype == QUOTA_NL_BSOFTBELOW || !need_print_warning(dquot))
 		return;
 
-	mutex_lock(&tty_mutex);
 	tty = get_current_tty();
 	if (!tty)
-		goto out_lock;
+		return;
 	tty_write_message(tty, dquot->dq_sb->s_id);
 	if (warntype == QUOTA_NL_ISOFTWARN || warntype == QUOTA_NL_BSOFTWARN)
 		tty_write_message(tty, ": warning, ");
@@ -926,8 +925,7 @@
 			break;
 	}
 	tty_write_message(tty, msg);
-out_lock:
-	mutex_unlock(&tty_mutex);
+	tty_kref_put(tty);
 }
 #endif
 
diff --git a/fs/ecryptfs/main.c b/fs/ecryptfs/main.c
index 448dfd5..8ebe9a5 100644
--- a/fs/ecryptfs/main.c
+++ b/fs/ecryptfs/main.c
@@ -211,7 +211,7 @@
        ecryptfs_opt_passthrough, ecryptfs_opt_xattr_metadata,
        ecryptfs_opt_encrypted_view, ecryptfs_opt_err };
 
-static match_table_t tokens = {
+static const match_table_t tokens = {
 	{ecryptfs_opt_sig, "sig=%s"},
 	{ecryptfs_opt_ecryptfs_sig, "ecryptfs_sig=%s"},
 	{ecryptfs_opt_cipher, "cipher=%s"},
diff --git a/fs/efs/super.c b/fs/efs/super.c
index 567b134..73b19cf 100644
--- a/fs/efs/super.c
+++ b/fs/efs/super.c
@@ -341,8 +341,6 @@
 			sb->inode_blocks *
 			(EFS_BLOCKSIZE / sizeof(struct efs_dinode));
 	buf->f_ffree   = sb->inode_free;	/* free inodes */
-	buf->f_fsid.val[0] = (sb->fs_magic >> 16) & 0xffff; /* fs ID */
-	buf->f_fsid.val[1] =  sb->fs_magic        & 0xffff; /* fs ID */
 	buf->f_namelen = EFS_MAXNAMELEN;	/* max filename length */
 
 	return 0;
diff --git a/fs/exec.c b/fs/exec.c
index 32993be..cecee50 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -752,11 +752,11 @@
 	tsk->active_mm = mm;
 	activate_mm(active_mm, mm);
 	task_unlock(tsk);
-	mm_update_next_owner(old_mm);
 	arch_pick_mmap_layout(mm);
 	if (old_mm) {
 		up_read(&old_mm->mmap_sem);
 		BUG_ON(active_mm != old_mm);
+		mm_update_next_owner(old_mm);
 		mmput(old_mm);
 		return 0;
 	}
diff --git a/fs/ext2/ext2.h b/fs/ext2/ext2.h
index 47d88da..bae998c 100644
--- a/fs/ext2/ext2.h
+++ b/fs/ext2/ext2.h
@@ -133,6 +133,8 @@
 extern int ext2_setattr (struct dentry *, struct iattr *);
 extern void ext2_set_inode_flags(struct inode *inode);
 extern void ext2_get_inode_flags(struct ext2_inode_info *);
+extern int ext2_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
+		       u64 start, u64 len);
 int __ext2_write_begin(struct file *file, struct address_space *mapping,
 		loff_t pos, unsigned len, unsigned flags,
 		struct page **pagep, void **fsdata);
diff --git a/fs/ext2/file.c b/fs/ext2/file.c
index 5f2fa9c..45ed071 100644
--- a/fs/ext2/file.c
+++ b/fs/ext2/file.c
@@ -86,4 +86,5 @@
 #endif
 	.setattr	= ext2_setattr,
 	.permission	= ext2_permission,
+	.fiemap		= ext2_fiemap,
 };
diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c
index 991d6df..7658b33 100644
--- a/fs/ext2/inode.c
+++ b/fs/ext2/inode.c
@@ -31,6 +31,7 @@
 #include <linux/writeback.h>
 #include <linux/buffer_head.h>
 #include <linux/mpage.h>
+#include <linux/fiemap.h>
 #include "ext2.h"
 #include "acl.h"
 #include "xip.h"
@@ -704,6 +705,13 @@
 
 }
 
+int ext2_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
+		u64 start, u64 len)
+{
+	return generic_block_fiemap(inode, fieinfo, start, len,
+				    ext2_get_block);
+}
+
 static int ext2_writepage(struct page *page, struct writeback_control *wbc)
 {
 	return block_write_full_page(page, ext2_get_block, wbc);
diff --git a/fs/ext2/super.c b/fs/ext2/super.c
index fd88c7b4..647cd88 100644
--- a/fs/ext2/super.c
+++ b/fs/ext2/super.c
@@ -393,7 +393,7 @@
 	Opt_usrquota, Opt_grpquota, Opt_reservation, Opt_noreservation
 };
 
-static match_table_t tokens = {
+static const match_table_t tokens = {
 	{Opt_bsd_df, "bsddf"},
 	{Opt_minix_df, "minixdf"},
 	{Opt_grpid, "grpid"},
diff --git a/fs/ext3/file.c b/fs/ext3/file.c
index acc4913..3be1e06 100644
--- a/fs/ext3/file.c
+++ b/fs/ext3/file.c
@@ -134,5 +134,6 @@
 	.removexattr	= generic_removexattr,
 #endif
 	.permission	= ext3_permission,
+	.fiemap		= ext3_fiemap,
 };
 
diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c
index 507d868..ebfec4d 100644
--- a/fs/ext3/inode.c
+++ b/fs/ext3/inode.c
@@ -36,6 +36,7 @@
 #include <linux/mpage.h>
 #include <linux/uio.h>
 #include <linux/bio.h>
+#include <linux/fiemap.h>
 #include "xattr.h"
 #include "acl.h"
 
@@ -981,6 +982,13 @@
 	return ret;
 }
 
+int ext3_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
+		u64 start, u64 len)
+{
+	return generic_block_fiemap(inode, fieinfo, start, len,
+				    ext3_get_block);
+}
+
 /*
  * `handle' can be NULL if create is zero
  */
diff --git a/fs/ext3/super.c b/fs/ext3/super.c
index f38a5af..399a96a 100644
--- a/fs/ext3/super.c
+++ b/fs/ext3/super.c
@@ -760,7 +760,7 @@
 	Opt_grpquota
 };
 
-static match_table_t tokens = {
+static const match_table_t tokens = {
 	{Opt_bsd_df, "bsddf"},
 	{Opt_minix_df, "minixdf"},
 	{Opt_grpid, "grpid"},
diff --git a/fs/ext4/Makefile b/fs/ext4/Makefile
index ac6fa8c..a8ff003 100644
--- a/fs/ext4/Makefile
+++ b/fs/ext4/Makefile
@@ -2,12 +2,12 @@
 # Makefile for the linux ext4-filesystem routines.
 #
 
-obj-$(CONFIG_EXT4DEV_FS) += ext4dev.o
+obj-$(CONFIG_EXT4_FS) += ext4.o
 
-ext4dev-y	:= balloc.o bitmap.o dir.o file.o fsync.o ialloc.o inode.o \
+ext4-y	:= balloc.o bitmap.o dir.o file.o fsync.o ialloc.o inode.o \
 		   ioctl.o namei.o super.o symlink.o hash.o resize.o extents.o \
 		   ext4_jbd2.o migrate.o mballoc.o
 
-ext4dev-$(CONFIG_EXT4DEV_FS_XATTR)	+= xattr.o xattr_user.o xattr_trusted.o
-ext4dev-$(CONFIG_EXT4DEV_FS_POSIX_ACL)	+= acl.o
-ext4dev-$(CONFIG_EXT4DEV_FS_SECURITY)	+= xattr_security.o
+ext4-$(CONFIG_EXT4_FS_XATTR)		+= xattr.o xattr_user.o xattr_trusted.o
+ext4-$(CONFIG_EXT4_FS_POSIX_ACL)	+= acl.o
+ext4-$(CONFIG_EXT4_FS_SECURITY)		+= xattr_security.o
diff --git a/fs/ext4/acl.h b/fs/ext4/acl.h
index cd2b855..cb45257 100644
--- a/fs/ext4/acl.h
+++ b/fs/ext4/acl.h
@@ -51,18 +51,18 @@
 	}
 }
 
-#ifdef CONFIG_EXT4DEV_FS_POSIX_ACL
+#ifdef CONFIG_EXT4_FS_POSIX_ACL
 
 /* Value for inode->u.ext4_i.i_acl and inode->u.ext4_i.i_default_acl
    if the ACL has not been cached */
 #define EXT4_ACL_NOT_CACHED ((void *)-1)
 
 /* acl.c */
-extern int ext4_permission (struct inode *, int);
-extern int ext4_acl_chmod (struct inode *);
-extern int ext4_init_acl (handle_t *, struct inode *, struct inode *);
+extern int ext4_permission(struct inode *, int);
+extern int ext4_acl_chmod(struct inode *);
+extern int ext4_init_acl(handle_t *, struct inode *, struct inode *);
 
-#else  /* CONFIG_EXT4DEV_FS_POSIX_ACL */
+#else  /* CONFIG_EXT4_FS_POSIX_ACL */
 #include <linux/sched.h>
 #define ext4_permission NULL
 
@@ -77,5 +77,5 @@
 {
 	return 0;
 }
-#endif  /* CONFIG_EXT4DEV_FS_POSIX_ACL */
+#endif  /* CONFIG_EXT4_FS_POSIX_ACL */
 
diff --git a/fs/ext4/balloc.c b/fs/ext4/balloc.c
index e9fa960..bd2ece2 100644
--- a/fs/ext4/balloc.c
+++ b/fs/ext4/balloc.c
@@ -83,6 +83,7 @@
 	}
 	return used_blocks;
 }
+
 /* Initializes an uninitialized block bitmap if given, and returns the
  * number of blocks free in the group. */
 unsigned ext4_init_block_bitmap(struct super_block *sb, struct buffer_head *bh,
@@ -132,7 +133,7 @@
 		 */
 		group_blocks = ext4_blocks_count(sbi->s_es) -
 			le32_to_cpu(sbi->s_es->s_first_data_block) -
-			(EXT4_BLOCKS_PER_GROUP(sb) * (sbi->s_groups_count -1));
+			(EXT4_BLOCKS_PER_GROUP(sb) * (sbi->s_groups_count - 1));
 	} else {
 		group_blocks = EXT4_BLOCKS_PER_GROUP(sb);
 	}
@@ -200,20 +201,20 @@
  * @bh:			pointer to the buffer head to store the block
  *			group descriptor
  */
-struct ext4_group_desc * ext4_get_group_desc(struct super_block * sb,
+struct ext4_group_desc * ext4_get_group_desc(struct super_block *sb,
 					     ext4_group_t block_group,
-					     struct buffer_head ** bh)
+					     struct buffer_head **bh)
 {
 	unsigned long group_desc;
 	unsigned long offset;
-	struct ext4_group_desc * desc;
+	struct ext4_group_desc *desc;
 	struct ext4_sb_info *sbi = EXT4_SB(sb);
 
 	if (block_group >= sbi->s_groups_count) {
-		ext4_error (sb, "ext4_get_group_desc",
-			    "block_group >= groups_count - "
-			    "block_group = %lu, groups_count = %lu",
-			    block_group, sbi->s_groups_count);
+		ext4_error(sb, "ext4_get_group_desc",
+			   "block_group >= groups_count - "
+			   "block_group = %lu, groups_count = %lu",
+			   block_group, sbi->s_groups_count);
 
 		return NULL;
 	}
@@ -222,10 +223,10 @@
 	group_desc = block_group >> EXT4_DESC_PER_BLOCK_BITS(sb);
 	offset = block_group & (EXT4_DESC_PER_BLOCK(sb) - 1);
 	if (!sbi->s_group_desc[group_desc]) {
-		ext4_error (sb, "ext4_get_group_desc",
-			    "Group descriptor not loaded - "
-			    "block_group = %lu, group_desc = %lu, desc = %lu",
-			     block_group, group_desc, offset);
+		ext4_error(sb, "ext4_get_group_desc",
+			   "Group descriptor not loaded - "
+			   "block_group = %lu, group_desc = %lu, desc = %lu",
+			   block_group, group_desc, offset);
 		return NULL;
 	}
 
@@ -302,8 +303,8 @@
 struct buffer_head *
 ext4_read_block_bitmap(struct super_block *sb, ext4_group_t block_group)
 {
-	struct ext4_group_desc * desc;
-	struct buffer_head * bh = NULL;
+	struct ext4_group_desc *desc;
+	struct buffer_head *bh = NULL;
 	ext4_fsblk_t bitmap_blk;
 
 	desc = ext4_get_group_desc(sb, block_group, NULL);
@@ -318,9 +319,11 @@
 			    block_group, bitmap_blk);
 		return NULL;
 	}
-	if (bh_uptodate_or_lock(bh))
+	if (buffer_uptodate(bh) &&
+	    !(desc->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT)))
 		return bh;
 
+	lock_buffer(bh);
 	spin_lock(sb_bgl_lock(EXT4_SB(sb), block_group));
 	if (desc->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT)) {
 		ext4_init_block_bitmap(sb, bh, block_group, desc);
@@ -345,301 +348,6 @@
 	 */
 	return bh;
 }
-/*
- * The reservation window structure operations
- * --------------------------------------------
- * Operations include:
- * dump, find, add, remove, is_empty, find_next_reservable_window, etc.
- *
- * We use a red-black tree to represent per-filesystem reservation
- * windows.
- *
- */
-
-/**
- * __rsv_window_dump() -- Dump the filesystem block allocation reservation map
- * @rb_root:		root of per-filesystem reservation rb tree
- * @verbose:		verbose mode
- * @fn:			function which wishes to dump the reservation map
- *
- * If verbose is turned on, it will print the whole block reservation
- * windows(start, end).	Otherwise, it will only print out the "bad" windows,
- * those windows that overlap with their immediate neighbors.
- */
-#if 1
-static void __rsv_window_dump(struct rb_root *root, int verbose,
-			      const char *fn)
-{
-	struct rb_node *n;
-	struct ext4_reserve_window_node *rsv, *prev;
-	int bad;
-
-restart:
-	n = rb_first(root);
-	bad = 0;
-	prev = NULL;
-
-	printk("Block Allocation Reservation Windows Map (%s):\n", fn);
-	while (n) {
-		rsv = rb_entry(n, struct ext4_reserve_window_node, rsv_node);
-		if (verbose)
-			printk("reservation window 0x%p "
-			       "start:  %llu, end:  %llu\n",
-			       rsv, rsv->rsv_start, rsv->rsv_end);
-		if (rsv->rsv_start && rsv->rsv_start >= rsv->rsv_end) {
-			printk("Bad reservation %p (start >= end)\n",
-			       rsv);
-			bad = 1;
-		}
-		if (prev && prev->rsv_end >= rsv->rsv_start) {
-			printk("Bad reservation %p (prev->end >= start)\n",
-			       rsv);
-			bad = 1;
-		}
-		if (bad) {
-			if (!verbose) {
-				printk("Restarting reservation walk in verbose mode\n");
-				verbose = 1;
-				goto restart;
-			}
-		}
-		n = rb_next(n);
-		prev = rsv;
-	}
-	printk("Window map complete.\n");
-	BUG_ON(bad);
-}
-#define rsv_window_dump(root, verbose) \
-	__rsv_window_dump((root), (verbose), __func__)
-#else
-#define rsv_window_dump(root, verbose) do {} while (0)
-#endif
-
-/**
- * goal_in_my_reservation()
- * @rsv:		inode's reservation window
- * @grp_goal:		given goal block relative to the allocation block group
- * @group:		the current allocation block group
- * @sb:			filesystem super block
- *
- * Test if the given goal block (group relative) is within the file's
- * own block reservation window range.
- *
- * If the reservation window is outside the goal allocation group, return 0;
- * grp_goal (given goal block) could be -1, which means no specific
- * goal block. In this case, always return 1.
- * If the goal block is within the reservation window, return 1;
- * otherwise, return 0;
- */
-static int
-goal_in_my_reservation(struct ext4_reserve_window *rsv, ext4_grpblk_t grp_goal,
-			ext4_group_t group, struct super_block *sb)
-{
-	ext4_fsblk_t group_first_block, group_last_block;
-
-	group_first_block = ext4_group_first_block_no(sb, group);
-	group_last_block = group_first_block + (EXT4_BLOCKS_PER_GROUP(sb) - 1);
-
-	if ((rsv->_rsv_start > group_last_block) ||
-	    (rsv->_rsv_end < group_first_block))
-		return 0;
-	if ((grp_goal >= 0) && ((grp_goal + group_first_block < rsv->_rsv_start)
-		|| (grp_goal + group_first_block > rsv->_rsv_end)))
-		return 0;
-	return 1;
-}
-
-/**
- * search_reserve_window()
- * @rb_root:		root of reservation tree
- * @goal:		target allocation block
- *
- * Find the reserved window which includes the goal, or the previous one
- * if the goal is not in any window.
- * Returns NULL if there are no windows or if all windows start after the goal.
- */
-static struct ext4_reserve_window_node *
-search_reserve_window(struct rb_root *root, ext4_fsblk_t goal)
-{
-	struct rb_node *n = root->rb_node;
-	struct ext4_reserve_window_node *rsv;
-
-	if (!n)
-		return NULL;
-
-	do {
-		rsv = rb_entry(n, struct ext4_reserve_window_node, rsv_node);
-
-		if (goal < rsv->rsv_start)
-			n = n->rb_left;
-		else if (goal > rsv->rsv_end)
-			n = n->rb_right;
-		else
-			return rsv;
-	} while (n);
-	/*
-	 * We've fallen off the end of the tree: the goal wasn't inside
-	 * any particular node.  OK, the previous node must be to one
-	 * side of the interval containing the goal.  If it's the RHS,
-	 * we need to back up one.
-	 */
-	if (rsv->rsv_start > goal) {
-		n = rb_prev(&rsv->rsv_node);
-		rsv = rb_entry(n, struct ext4_reserve_window_node, rsv_node);
-	}
-	return rsv;
-}
-
-/**
- * ext4_rsv_window_add() -- Insert a window to the block reservation rb tree.
- * @sb:			super block
- * @rsv:		reservation window to add
- *
- * Must be called with rsv_lock hold.
- */
-void ext4_rsv_window_add(struct super_block *sb,
-		    struct ext4_reserve_window_node *rsv)
-{
-	struct rb_root *root = &EXT4_SB(sb)->s_rsv_window_root;
-	struct rb_node *node = &rsv->rsv_node;
-	ext4_fsblk_t start = rsv->rsv_start;
-
-	struct rb_node ** p = &root->rb_node;
-	struct rb_node * parent = NULL;
-	struct ext4_reserve_window_node *this;
-
-	while (*p)
-	{
-		parent = *p;
-		this = rb_entry(parent, struct ext4_reserve_window_node, rsv_node);
-
-		if (start < this->rsv_start)
-			p = &(*p)->rb_left;
-		else if (start > this->rsv_end)
-			p = &(*p)->rb_right;
-		else {
-			rsv_window_dump(root, 1);
-			BUG();
-		}
-	}
-
-	rb_link_node(node, parent, p);
-	rb_insert_color(node, root);
-}
-
-/**
- * ext4_rsv_window_remove() -- unlink a window from the reservation rb tree
- * @sb:			super block
- * @rsv:		reservation window to remove
- *
- * Mark the block reservation window as not allocated, and unlink it
- * from the filesystem reservation window rb tree. Must be called with
- * rsv_lock hold.
- */
-static void rsv_window_remove(struct super_block *sb,
-			      struct ext4_reserve_window_node *rsv)
-{
-	rsv->rsv_start = EXT4_RESERVE_WINDOW_NOT_ALLOCATED;
-	rsv->rsv_end = EXT4_RESERVE_WINDOW_NOT_ALLOCATED;
-	rsv->rsv_alloc_hit = 0;
-	rb_erase(&rsv->rsv_node, &EXT4_SB(sb)->s_rsv_window_root);
-}
-
-/*
- * rsv_is_empty() -- Check if the reservation window is allocated.
- * @rsv:		given reservation window to check
- *
- * returns 1 if the end block is EXT4_RESERVE_WINDOW_NOT_ALLOCATED.
- */
-static inline int rsv_is_empty(struct ext4_reserve_window *rsv)
-{
-	/* a valid reservation end block could not be 0 */
-	return rsv->_rsv_end == EXT4_RESERVE_WINDOW_NOT_ALLOCATED;
-}
-
-/**
- * ext4_init_block_alloc_info()
- * @inode:		file inode structure
- *
- * Allocate and initialize the	reservation window structure, and
- * link the window to the ext4 inode structure at last
- *
- * The reservation window structure is only dynamically allocated
- * and linked to ext4 inode the first time the open file
- * needs a new block. So, before every ext4_new_block(s) call, for
- * regular files, we should check whether the reservation window
- * structure exists or not. In the latter case, this function is called.
- * Fail to do so will result in block reservation being turned off for that
- * open file.
- *
- * This function is called from ext4_get_blocks_handle(), also called
- * when setting the reservation window size through ioctl before the file
- * is open for write (needs block allocation).
- *
- * Needs down_write(i_data_sem) protection prior to call this function.
- */
-void ext4_init_block_alloc_info(struct inode *inode)
-{
-	struct ext4_inode_info *ei = EXT4_I(inode);
-	struct ext4_block_alloc_info *block_i = ei->i_block_alloc_info;
-	struct super_block *sb = inode->i_sb;
-
-	block_i = kmalloc(sizeof(*block_i), GFP_NOFS);
-	if (block_i) {
-		struct ext4_reserve_window_node *rsv = &block_i->rsv_window_node;
-
-		rsv->rsv_start = EXT4_RESERVE_WINDOW_NOT_ALLOCATED;
-		rsv->rsv_end = EXT4_RESERVE_WINDOW_NOT_ALLOCATED;
-
-		/*
-		 * if filesystem is mounted with NORESERVATION, the goal
-		 * reservation window size is set to zero to indicate
-		 * block reservation is off
-		 */
-		if (!test_opt(sb, RESERVATION))
-			rsv->rsv_goal_size = 0;
-		else
-			rsv->rsv_goal_size = EXT4_DEFAULT_RESERVE_BLOCKS;
-		rsv->rsv_alloc_hit = 0;
-		block_i->last_alloc_logical_block = 0;
-		block_i->last_alloc_physical_block = 0;
-	}
-	ei->i_block_alloc_info = block_i;
-}
-
-/**
- * ext4_discard_reservation()
- * @inode:		inode
- *
- * Discard(free) block reservation window on last file close, or truncate
- * or at last iput().
- *
- * It is being called in three cases:
- *	ext4_release_file(): last writer close the file
- *	ext4_clear_inode(): last iput(), when nobody link to this file.
- *	ext4_truncate(): when the block indirect map is about to change.
- *
- */
-void ext4_discard_reservation(struct inode *inode)
-{
-	struct ext4_inode_info *ei = EXT4_I(inode);
-	struct ext4_block_alloc_info *block_i = ei->i_block_alloc_info;
-	struct ext4_reserve_window_node *rsv;
-	spinlock_t *rsv_lock = &EXT4_SB(inode->i_sb)->s_rsv_window_lock;
-
-	ext4_mb_discard_inode_preallocations(inode);
-
-	if (!block_i)
-		return;
-
-	rsv = &block_i->rsv_window_node;
-	if (!rsv_is_empty(&rsv->rsv_window)) {
-		spin_lock(rsv_lock);
-		if (!rsv_is_empty(&rsv->rsv_window))
-			rsv_window_remove(inode->i_sb, rsv);
-		spin_unlock(rsv_lock);
-	}
-}
 
 /**
  * ext4_free_blocks_sb() -- Free given blocks and update quota
@@ -648,6 +356,13 @@
  * @block:			start physcial block to free
  * @count:			number of blocks to free
  * @pdquot_freed_blocks:	pointer to quota
+ *
+ * XXX This function is only used by the on-line resizing code, which
+ * should probably be fixed up to call the mballoc variant.  There
+ * this needs to be cleaned up later; in fact, I'm not convinced this
+ * is 100% correct in the face of the mballoc code.  The online resizing
+ * code needs to be fixed up to more tightly (and correctly) interlock
+ * with the mballoc code.
  */
 void ext4_free_blocks_sb(handle_t *handle, struct super_block *sb,
 			 ext4_fsblk_t block, unsigned long count,
@@ -659,8 +374,8 @@
 	ext4_grpblk_t bit;
 	unsigned long i;
 	unsigned long overflow;
-	struct ext4_group_desc * desc;
-	struct ext4_super_block * es;
+	struct ext4_group_desc *desc;
+	struct ext4_super_block *es;
 	struct ext4_sb_info *sbi;
 	int err = 0, ret;
 	ext4_grpblk_t group_freed;
@@ -671,13 +386,13 @@
 	if (block < le32_to_cpu(es->s_first_data_block) ||
 	    block + count < block ||
 	    block + count > ext4_blocks_count(es)) {
-		ext4_error (sb, "ext4_free_blocks",
-			    "Freeing blocks not in datazone - "
-			    "block = %llu, count = %lu", block, count);
+		ext4_error(sb, "ext4_free_blocks",
+			   "Freeing blocks not in datazone - "
+			   "block = %llu, count = %lu", block, count);
 		goto error_return;
 	}
 
-	ext4_debug ("freeing block(s) %llu-%llu\n", block, block + count - 1);
+	ext4_debug("freeing block(s) %llu-%llu\n", block, block + count - 1);
 
 do_more:
 	overflow = 0;
@@ -694,7 +409,7 @@
 	bitmap_bh = ext4_read_block_bitmap(sb, block_group);
 	if (!bitmap_bh)
 		goto error_return;
-	desc = ext4_get_group_desc (sb, block_group, &gd_bh);
+	desc = ext4_get_group_desc(sb, block_group, &gd_bh);
 	if (!desc)
 		goto error_return;
 
@@ -703,10 +418,10 @@
 	    in_range(block, ext4_inode_table(sb, desc), sbi->s_itb_per_group) ||
 	    in_range(block + count - 1, ext4_inode_table(sb, desc),
 		     sbi->s_itb_per_group)) {
-		ext4_error (sb, "ext4_free_blocks",
-			    "Freeing blocks in system zones - "
-			    "Block = %llu, count = %lu",
-			    block, count);
+		ext4_error(sb, "ext4_free_blocks",
+			   "Freeing blocks in system zones - "
+			   "Block = %llu, count = %lu",
+			   block, count);
 		goto error_return;
 	}
 
@@ -848,7 +563,7 @@
 			ext4_fsblk_t block, unsigned long count,
 			int metadata)
 {
-	struct super_block * sb;
+	struct super_block *sb;
 	unsigned long dquot_freed_blocks;
 
 	/* this isn't the right place to decide whether block is metadata
@@ -859,748 +574,52 @@
 
 	sb = inode->i_sb;
 
-	if (!test_opt(sb, MBALLOC) || !EXT4_SB(sb)->s_group_info)
-		ext4_free_blocks_sb(handle, sb, block, count,
-						&dquot_freed_blocks);
-	else
-		ext4_mb_free_blocks(handle, inode, block, count,
-						metadata, &dquot_freed_blocks);
+	ext4_mb_free_blocks(handle, inode, block, count,
+			    metadata, &dquot_freed_blocks);
 	if (dquot_freed_blocks)
 		DQUOT_FREE_BLOCK(inode, dquot_freed_blocks);
 	return;
 }
 
-/**
- * ext4_test_allocatable()
- * @nr:			given allocation block group
- * @bh:			bufferhead contains the bitmap of the given block group
- *
- * For ext4 allocations, we must not reuse any blocks which are
- * allocated in the bitmap buffer's "last committed data" copy.  This
- * prevents deletes from freeing up the page for reuse until we have
- * committed the delete transaction.
- *
- * If we didn't do this, then deleting something and reallocating it as
- * data would allow the old block to be overwritten before the
- * transaction committed (because we force data to disk before commit).
- * This would lead to corruption if we crashed between overwriting the
- * data and committing the delete.
- *
- * @@@ We may want to make this allocation behaviour conditional on
- * data-writes at some point, and disable it for metadata allocations or
- * sync-data inodes.
- */
-static int ext4_test_allocatable(ext4_grpblk_t nr, struct buffer_head *bh)
+int ext4_claim_free_blocks(struct ext4_sb_info *sbi,
+						s64 nblocks)
 {
-	int ret;
-	struct journal_head *jh = bh2jh(bh);
+	s64 free_blocks, dirty_blocks;
+	s64 root_blocks = 0;
+	struct percpu_counter *fbc = &sbi->s_freeblocks_counter;
+	struct percpu_counter *dbc = &sbi->s_dirtyblocks_counter;
 
-	if (ext4_test_bit(nr, bh->b_data))
-		return 0;
+	free_blocks  = percpu_counter_read_positive(fbc);
+	dirty_blocks = percpu_counter_read_positive(dbc);
 
-	jbd_lock_bh_state(bh);
-	if (!jh->b_committed_data)
-		ret = 1;
-	else
-		ret = !ext4_test_bit(nr, jh->b_committed_data);
-	jbd_unlock_bh_state(bh);
-	return ret;
-}
+	if (!capable(CAP_SYS_RESOURCE) &&
+		sbi->s_resuid != current->fsuid &&
+		(sbi->s_resgid == 0 || !in_group_p(sbi->s_resgid)))
+		root_blocks = ext4_r_blocks_count(sbi->s_es);
 
-/**
- * bitmap_search_next_usable_block()
- * @start:		the starting block (group relative) of the search
- * @bh:			bufferhead contains the block group bitmap
- * @maxblocks:		the ending block (group relative) of the reservation
- *
- * The bitmap search --- search forward alternately through the actual
- * bitmap on disk and the last-committed copy in journal, until we find a
- * bit free in both bitmaps.
- */
-static ext4_grpblk_t
-bitmap_search_next_usable_block(ext4_grpblk_t start, struct buffer_head *bh,
-					ext4_grpblk_t maxblocks)
-{
-	ext4_grpblk_t next;
-	struct journal_head *jh = bh2jh(bh);
-
-	while (start < maxblocks) {
-		next = ext4_find_next_zero_bit(bh->b_data, maxblocks, start);
-		if (next >= maxblocks)
-			return -1;
-		if (ext4_test_allocatable(next, bh))
-			return next;
-		jbd_lock_bh_state(bh);
-		if (jh->b_committed_data)
-			start = ext4_find_next_zero_bit(jh->b_committed_data,
-							maxblocks, next);
-		jbd_unlock_bh_state(bh);
-	}
-	return -1;
-}
-
-/**
- * find_next_usable_block()
- * @start:		the starting block (group relative) to find next
- *			allocatable block in bitmap.
- * @bh:			bufferhead contains the block group bitmap
- * @maxblocks:		the ending block (group relative) for the search
- *
- * Find an allocatable block in a bitmap.  We honor both the bitmap and
- * its last-committed copy (if that exists), and perform the "most
- * appropriate allocation" algorithm of looking for a free block near
- * the initial goal; then for a free byte somewhere in the bitmap; then
- * for any free bit in the bitmap.
- */
-static ext4_grpblk_t
-find_next_usable_block(ext4_grpblk_t start, struct buffer_head *bh,
-			ext4_grpblk_t maxblocks)
-{
-	ext4_grpblk_t here, next;
-	char *p, *r;
-
-	if (start > 0) {
-		/*
-		 * The goal was occupied; search forward for a free
-		 * block within the next XX blocks.
-		 *
-		 * end_goal is more or less random, but it has to be
-		 * less than EXT4_BLOCKS_PER_GROUP. Aligning up to the
-		 * next 64-bit boundary is simple..
-		 */
-		ext4_grpblk_t end_goal = (start + 63) & ~63;
-		if (end_goal > maxblocks)
-			end_goal = maxblocks;
-		here = ext4_find_next_zero_bit(bh->b_data, end_goal, start);
-		if (here < end_goal && ext4_test_allocatable(here, bh))
-			return here;
-		ext4_debug("Bit not found near goal\n");
-	}
-
-	here = start;
-	if (here < 0)
-		here = 0;
-
-	p = ((char *)bh->b_data) + (here >> 3);
-	r = memscan(p, 0, ((maxblocks + 7) >> 3) - (here >> 3));
-	next = (r - ((char *)bh->b_data)) << 3;
-
-	if (next < maxblocks && next >= start && ext4_test_allocatable(next, bh))
-		return next;
-
-	/*
-	 * The bitmap search --- search forward alternately through the actual
-	 * bitmap and the last-committed copy until we find a bit free in
-	 * both
-	 */
-	here = bitmap_search_next_usable_block(here, bh, maxblocks);
-	return here;
-}
-
-/**
- * claim_block()
- * @block:		the free block (group relative) to allocate
- * @bh:			the bufferhead containts the block group bitmap
- *
- * We think we can allocate this block in this bitmap.  Try to set the bit.
- * If that succeeds then check that nobody has allocated and then freed the
- * block since we saw that is was not marked in b_committed_data.  If it _was_
- * allocated and freed then clear the bit in the bitmap again and return
- * zero (failure).
- */
-static inline int
-claim_block(spinlock_t *lock, ext4_grpblk_t block, struct buffer_head *bh)
-{
-	struct journal_head *jh = bh2jh(bh);
-	int ret;
-
-	if (ext4_set_bit_atomic(lock, block, bh->b_data))
-		return 0;
-	jbd_lock_bh_state(bh);
-	if (jh->b_committed_data && ext4_test_bit(block,jh->b_committed_data)) {
-		ext4_clear_bit_atomic(lock, block, bh->b_data);
-		ret = 0;
-	} else {
-		ret = 1;
-	}
-	jbd_unlock_bh_state(bh);
-	return ret;
-}
-
-/**
- * ext4_try_to_allocate()
- * @sb:			superblock
- * @handle:		handle to this transaction
- * @group:		given allocation block group
- * @bitmap_bh:		bufferhead holds the block bitmap
- * @grp_goal:		given target block within the group
- * @count:		target number of blocks to allocate
- * @my_rsv:		reservation window
- *
- * Attempt to allocate blocks within a give range. Set the range of allocation
- * first, then find the first free bit(s) from the bitmap (within the range),
- * and at last, allocate the blocks by claiming the found free bit as allocated.
- *
- * To set the range of this allocation:
- *	if there is a reservation window, only try to allocate block(s) from the
- *	file's own reservation window;
- *	Otherwise, the allocation range starts from the give goal block, ends at
- *	the block group's last block.
- *
- * If we failed to allocate the desired block then we may end up crossing to a
- * new bitmap.  In that case we must release write access to the old one via
- * ext4_journal_release_buffer(), else we'll run out of credits.
- */
-static ext4_grpblk_t
-ext4_try_to_allocate(struct super_block *sb, handle_t *handle,
-			ext4_group_t group, struct buffer_head *bitmap_bh,
-			ext4_grpblk_t grp_goal, unsigned long *count,
-			struct ext4_reserve_window *my_rsv)
-{
-	ext4_fsblk_t group_first_block;
-	ext4_grpblk_t start, end;
-	unsigned long num = 0;
-
-	/* we do allocation within the reservation window if we have a window */
-	if (my_rsv) {
-		group_first_block = ext4_group_first_block_no(sb, group);
-		if (my_rsv->_rsv_start >= group_first_block)
-			start = my_rsv->_rsv_start - group_first_block;
-		else
-			/* reservation window cross group boundary */
-			start = 0;
-		end = my_rsv->_rsv_end - group_first_block + 1;
-		if (end > EXT4_BLOCKS_PER_GROUP(sb))
-			/* reservation window crosses group boundary */
-			end = EXT4_BLOCKS_PER_GROUP(sb);
-		if ((start <= grp_goal) && (grp_goal < end))
-			start = grp_goal;
-		else
-			grp_goal = -1;
-	} else {
-		if (grp_goal > 0)
-			start = grp_goal;
-		else
-			start = 0;
-		end = EXT4_BLOCKS_PER_GROUP(sb);
-	}
-
-	BUG_ON(start > EXT4_BLOCKS_PER_GROUP(sb));
-
-repeat:
-	if (grp_goal < 0 || !ext4_test_allocatable(grp_goal, bitmap_bh)) {
-		grp_goal = find_next_usable_block(start, bitmap_bh, end);
-		if (grp_goal < 0)
-			goto fail_access;
-		if (!my_rsv) {
-			int i;
-
-			for (i = 0; i < 7 && grp_goal > start &&
-					ext4_test_allocatable(grp_goal - 1,
-								bitmap_bh);
-					i++, grp_goal--)
-				;
+	if (free_blocks - (nblocks + root_blocks + dirty_blocks) <
+						EXT4_FREEBLOCKS_WATERMARK) {
+		free_blocks  = percpu_counter_sum(fbc);
+		dirty_blocks = percpu_counter_sum(dbc);
+		if (dirty_blocks < 0) {
+			printk(KERN_CRIT "Dirty block accounting "
+					"went wrong %lld\n",
+					dirty_blocks);
 		}
 	}
-	start = grp_goal;
-
-	if (!claim_block(sb_bgl_lock(EXT4_SB(sb), group),
-		grp_goal, bitmap_bh)) {
-		/*
-		 * The block was allocated by another thread, or it was
-		 * allocated and then freed by another thread
-		 */
-		start++;
-		grp_goal++;
-		if (start >= end)
-			goto fail_access;
-		goto repeat;
-	}
-	num++;
-	grp_goal++;
-	while (num < *count && grp_goal < end
-		&& ext4_test_allocatable(grp_goal, bitmap_bh)
-		&& claim_block(sb_bgl_lock(EXT4_SB(sb), group),
-				grp_goal, bitmap_bh)) {
-		num++;
-		grp_goal++;
-	}
-	*count = num;
-	return grp_goal - num;
-fail_access:
-	*count = num;
-	return -1;
-}
-
-/**
- *	find_next_reservable_window():
- *		find a reservable space within the given range.
- *		It does not allocate the reservation window for now:
- *		alloc_new_reservation() will do the work later.
- *
- *	@search_head: the head of the searching list;
- *		This is not necessarily the list head of the whole filesystem
- *
- *		We have both head and start_block to assist the search
- *		for the reservable space. The list starts from head,
- *		but we will shift to the place where start_block is,
- *		then start from there, when looking for a reservable space.
- *
- *	@size: the target new reservation window size
- *
- *	@group_first_block: the first block we consider to start
- *			the real search from
- *
- *	@last_block:
- *		the maximum block number that our goal reservable space
- *		could start from. This is normally the last block in this
- *		group. The search will end when we found the start of next
- *		possible reservable space is out of this boundary.
- *		This could handle the cross boundary reservation window
- *		request.
- *
- *	basically we search from the given range, rather than the whole
- *	reservation double linked list, (start_block, last_block)
- *	to find a free region that is of my size and has not
- *	been reserved.
- *
- */
-static int find_next_reservable_window(
-				struct ext4_reserve_window_node *search_head,
-				struct ext4_reserve_window_node *my_rsv,
-				struct super_block * sb,
-				ext4_fsblk_t start_block,
-				ext4_fsblk_t last_block)
-{
-	struct rb_node *next;
-	struct ext4_reserve_window_node *rsv, *prev;
-	ext4_fsblk_t cur;
-	int size = my_rsv->rsv_goal_size;
-
-	/* TODO: make the start of the reservation window byte-aligned */
-	/* cur = *start_block & ~7;*/
-	cur = start_block;
-	rsv = search_head;
-	if (!rsv)
-		return -1;
-
-	while (1) {
-		if (cur <= rsv->rsv_end)
-			cur = rsv->rsv_end + 1;
-
-		/* TODO?
-		 * in the case we could not find a reservable space
-		 * that is what is expected, during the re-search, we could
-		 * remember what's the largest reservable space we could have
-		 * and return that one.
-		 *
-		 * For now it will fail if we could not find the reservable
-		 * space with expected-size (or more)...
-		 */
-		if (cur > last_block)
-			return -1;		/* fail */
-
-		prev = rsv;
-		next = rb_next(&rsv->rsv_node);
-		rsv = rb_entry(next,struct ext4_reserve_window_node,rsv_node);
-
-		/*
-		 * Reached the last reservation, we can just append to the
-		 * previous one.
-		 */
-		if (!next)
-			break;
-
-		if (cur + size <= rsv->rsv_start) {
-			/*
-			 * Found a reserveable space big enough.  We could
-			 * have a reservation across the group boundary here
-			 */
-			break;
-		}
-	}
-	/*
-	 * we come here either :
-	 * when we reach the end of the whole list,
-	 * and there is empty reservable space after last entry in the list.
-	 * append it to the end of the list.
-	 *
-	 * or we found one reservable space in the middle of the list,
-	 * return the reservation window that we could append to.
-	 * succeed.
+	/* Check whether we have space after
+	 * accounting for current dirty blocks
 	 */
+	if (free_blocks < ((root_blocks + nblocks) + dirty_blocks))
+		/* we don't have free space */
+		return -ENOSPC;
 
-	if ((prev != my_rsv) && (!rsv_is_empty(&my_rsv->rsv_window)))
-		rsv_window_remove(sb, my_rsv);
-
-	/*
-	 * Let's book the whole avaliable window for now.  We will check the
-	 * disk bitmap later and then, if there are free blocks then we adjust
-	 * the window size if it's larger than requested.
-	 * Otherwise, we will remove this node from the tree next time
-	 * call find_next_reservable_window.
-	 */
-	my_rsv->rsv_start = cur;
-	my_rsv->rsv_end = cur + size - 1;
-	my_rsv->rsv_alloc_hit = 0;
-
-	if (prev != my_rsv)
-		ext4_rsv_window_add(sb, my_rsv);
-
+	/* Add the blocks to nblocks */
+	percpu_counter_add(dbc, nblocks);
 	return 0;
 }
 
 /**
- *	alloc_new_reservation()--allocate a new reservation window
- *
- *		To make a new reservation, we search part of the filesystem
- *		reservation list (the list that inside the group). We try to
- *		allocate a new reservation window near the allocation goal,
- *		or the beginning of the group, if there is no goal.
- *
- *		We first find a reservable space after the goal, then from
- *		there, we check the bitmap for the first free block after
- *		it. If there is no free block until the end of group, then the
- *		whole group is full, we failed. Otherwise, check if the free
- *		block is inside the expected reservable space, if so, we
- *		succeed.
- *		If the first free block is outside the reservable space, then
- *		start from the first free block, we search for next available
- *		space, and go on.
- *
- *	on succeed, a new reservation will be found and inserted into the list
- *	It contains at least one free block, and it does not overlap with other
- *	reservation windows.
- *
- *	failed: we failed to find a reservation window in this group
- *
- *	@rsv: the reservation
- *
- *	@grp_goal: The goal (group-relative).  It is where the search for a
- *		free reservable space should start from.
- *		if we have a grp_goal(grp_goal >0 ), then start from there,
- *		no grp_goal(grp_goal = -1), we start from the first block
- *		of the group.
- *
- *	@sb: the super block
- *	@group: the group we are trying to allocate in
- *	@bitmap_bh: the block group block bitmap
- *
- */
-static int alloc_new_reservation(struct ext4_reserve_window_node *my_rsv,
-		ext4_grpblk_t grp_goal, struct super_block *sb,
-		ext4_group_t group, struct buffer_head *bitmap_bh)
-{
-	struct ext4_reserve_window_node *search_head;
-	ext4_fsblk_t group_first_block, group_end_block, start_block;
-	ext4_grpblk_t first_free_block;
-	struct rb_root *fs_rsv_root = &EXT4_SB(sb)->s_rsv_window_root;
-	unsigned long size;
-	int ret;
-	spinlock_t *rsv_lock = &EXT4_SB(sb)->s_rsv_window_lock;
-
-	group_first_block = ext4_group_first_block_no(sb, group);
-	group_end_block = group_first_block + (EXT4_BLOCKS_PER_GROUP(sb) - 1);
-
-	if (grp_goal < 0)
-		start_block = group_first_block;
-	else
-		start_block = grp_goal + group_first_block;
-
-	size = my_rsv->rsv_goal_size;
-
-	if (!rsv_is_empty(&my_rsv->rsv_window)) {
-		/*
-		 * if the old reservation is cross group boundary
-		 * and if the goal is inside the old reservation window,
-		 * we will come here when we just failed to allocate from
-		 * the first part of the window. We still have another part
-		 * that belongs to the next group. In this case, there is no
-		 * point to discard our window and try to allocate a new one
-		 * in this group(which will fail). we should
-		 * keep the reservation window, just simply move on.
-		 *
-		 * Maybe we could shift the start block of the reservation
-		 * window to the first block of next group.
-		 */
-
-		if ((my_rsv->rsv_start <= group_end_block) &&
-				(my_rsv->rsv_end > group_end_block) &&
-				(start_block >= my_rsv->rsv_start))
-			return -1;
-
-		if ((my_rsv->rsv_alloc_hit >
-		     (my_rsv->rsv_end - my_rsv->rsv_start + 1) / 2)) {
-			/*
-			 * if the previously allocation hit ratio is
-			 * greater than 1/2, then we double the size of
-			 * the reservation window the next time,
-			 * otherwise we keep the same size window
-			 */
-			size = size * 2;
-			if (size > EXT4_MAX_RESERVE_BLOCKS)
-				size = EXT4_MAX_RESERVE_BLOCKS;
-			my_rsv->rsv_goal_size= size;
-		}
-	}
-
-	spin_lock(rsv_lock);
-	/*
-	 * shift the search start to the window near the goal block
-	 */
-	search_head = search_reserve_window(fs_rsv_root, start_block);
-
-	/*
-	 * find_next_reservable_window() simply finds a reservable window
-	 * inside the given range(start_block, group_end_block).
-	 *
-	 * To make sure the reservation window has a free bit inside it, we
-	 * need to check the bitmap after we found a reservable window.
-	 */
-retry:
-	ret = find_next_reservable_window(search_head, my_rsv, sb,
-						start_block, group_end_block);
-
-	if (ret == -1) {
-		if (!rsv_is_empty(&my_rsv->rsv_window))
-			rsv_window_remove(sb, my_rsv);
-		spin_unlock(rsv_lock);
-		return -1;
-	}
-
-	/*
-	 * On success, find_next_reservable_window() returns the
-	 * reservation window where there is a reservable space after it.
-	 * Before we reserve this reservable space, we need
-	 * to make sure there is at least a free block inside this region.
-	 *
-	 * searching the first free bit on the block bitmap and copy of
-	 * last committed bitmap alternatively, until we found a allocatable
-	 * block. Search start from the start block of the reservable space
-	 * we just found.
-	 */
-	spin_unlock(rsv_lock);
-	first_free_block = bitmap_search_next_usable_block(
-			my_rsv->rsv_start - group_first_block,
-			bitmap_bh, group_end_block - group_first_block + 1);
-
-	if (first_free_block < 0) {
-		/*
-		 * no free block left on the bitmap, no point
-		 * to reserve the space. return failed.
-		 */
-		spin_lock(rsv_lock);
-		if (!rsv_is_empty(&my_rsv->rsv_window))
-			rsv_window_remove(sb, my_rsv);
-		spin_unlock(rsv_lock);
-		return -1;		/* failed */
-	}
-
-	start_block = first_free_block + group_first_block;
-	/*
-	 * check if the first free block is within the
-	 * free space we just reserved
-	 */
-	if (start_block >= my_rsv->rsv_start && start_block <= my_rsv->rsv_end)
-		return 0;		/* success */
-	/*
-	 * if the first free bit we found is out of the reservable space
-	 * continue search for next reservable space,
-	 * start from where the free block is,
-	 * we also shift the list head to where we stopped last time
-	 */
-	search_head = my_rsv;
-	spin_lock(rsv_lock);
-	goto retry;
-}
-
-/**
- * try_to_extend_reservation()
- * @my_rsv:		given reservation window
- * @sb:			super block
- * @size:		the delta to extend
- *
- * Attempt to expand the reservation window large enough to have
- * required number of free blocks
- *
- * Since ext4_try_to_allocate() will always allocate blocks within
- * the reservation window range, if the window size is too small,
- * multiple blocks allocation has to stop at the end of the reservation
- * window. To make this more efficient, given the total number of
- * blocks needed and the current size of the window, we try to
- * expand the reservation window size if necessary on a best-effort
- * basis before ext4_new_blocks() tries to allocate blocks,
- */
-static void try_to_extend_reservation(struct ext4_reserve_window_node *my_rsv,
-			struct super_block *sb, int size)
-{
-	struct ext4_reserve_window_node *next_rsv;
-	struct rb_node *next;
-	spinlock_t *rsv_lock = &EXT4_SB(sb)->s_rsv_window_lock;
-
-	if (!spin_trylock(rsv_lock))
-		return;
-
-	next = rb_next(&my_rsv->rsv_node);
-
-	if (!next)
-		my_rsv->rsv_end += size;
-	else {
-		next_rsv = rb_entry(next, struct ext4_reserve_window_node, rsv_node);
-
-		if ((next_rsv->rsv_start - my_rsv->rsv_end - 1) >= size)
-			my_rsv->rsv_end += size;
-		else
-			my_rsv->rsv_end = next_rsv->rsv_start - 1;
-	}
-	spin_unlock(rsv_lock);
-}
-
-/**
- * ext4_try_to_allocate_with_rsv()
- * @sb:			superblock
- * @handle:		handle to this transaction
- * @group:		given allocation block group
- * @bitmap_bh:		bufferhead holds the block bitmap
- * @grp_goal:		given target block within the group
- * @count:		target number of blocks to allocate
- * @my_rsv:		reservation window
- * @errp:		pointer to store the error code
- *
- * This is the main function used to allocate a new block and its reservation
- * window.
- *
- * Each time when a new block allocation is need, first try to allocate from
- * its own reservation.  If it does not have a reservation window, instead of
- * looking for a free bit on bitmap first, then look up the reservation list to
- * see if it is inside somebody else's reservation window, we try to allocate a
- * reservation window for it starting from the goal first. Then do the block
- * allocation within the reservation window.
- *
- * This will avoid keeping on searching the reservation list again and
- * again when somebody is looking for a free block (without
- * reservation), and there are lots of free blocks, but they are all
- * being reserved.
- *
- * We use a red-black tree for the per-filesystem reservation list.
- *
- */
-static ext4_grpblk_t
-ext4_try_to_allocate_with_rsv(struct super_block *sb, handle_t *handle,
-			ext4_group_t group, struct buffer_head *bitmap_bh,
-			ext4_grpblk_t grp_goal,
-			struct ext4_reserve_window_node * my_rsv,
-			unsigned long *count, int *errp)
-{
-	ext4_fsblk_t group_first_block, group_last_block;
-	ext4_grpblk_t ret = 0;
-	int fatal;
-	unsigned long num = *count;
-
-	*errp = 0;
-
-	/*
-	 * Make sure we use undo access for the bitmap, because it is critical
-	 * that we do the frozen_data COW on bitmap buffers in all cases even
-	 * if the buffer is in BJ_Forget state in the committing transaction.
-	 */
-	BUFFER_TRACE(bitmap_bh, "get undo access for new block");
-	fatal = ext4_journal_get_undo_access(handle, bitmap_bh);
-	if (fatal) {
-		*errp = fatal;
-		return -1;
-	}
-
-	/*
-	 * we don't deal with reservation when
-	 * filesystem is mounted without reservation
-	 * or the file is not a regular file
-	 * or last attempt to allocate a block with reservation turned on failed
-	 */
-	if (my_rsv == NULL ) {
-		ret = ext4_try_to_allocate(sb, handle, group, bitmap_bh,
-						grp_goal, count, NULL);
-		goto out;
-	}
-	/*
-	 * grp_goal is a group relative block number (if there is a goal)
-	 * 0 <= grp_goal < EXT4_BLOCKS_PER_GROUP(sb)
-	 * first block is a filesystem wide block number
-	 * first block is the block number of the first block in this group
-	 */
-	group_first_block = ext4_group_first_block_no(sb, group);
-	group_last_block = group_first_block + (EXT4_BLOCKS_PER_GROUP(sb) - 1);
-
-	/*
-	 * Basically we will allocate a new block from inode's reservation
-	 * window.
-	 *
-	 * We need to allocate a new reservation window, if:
-	 * a) inode does not have a reservation window; or
-	 * b) last attempt to allocate a block from existing reservation
-	 *    failed; or
-	 * c) we come here with a goal and with a reservation window
-	 *
-	 * We do not need to allocate a new reservation window if we come here
-	 * at the beginning with a goal and the goal is inside the window, or
-	 * we don't have a goal but already have a reservation window.
-	 * then we could go to allocate from the reservation window directly.
-	 */
-	while (1) {
-		if (rsv_is_empty(&my_rsv->rsv_window) || (ret < 0) ||
-			!goal_in_my_reservation(&my_rsv->rsv_window,
-						grp_goal, group, sb)) {
-			if (my_rsv->rsv_goal_size < *count)
-				my_rsv->rsv_goal_size = *count;
-			ret = alloc_new_reservation(my_rsv, grp_goal, sb,
-							group, bitmap_bh);
-			if (ret < 0)
-				break;			/* failed */
-
-			if (!goal_in_my_reservation(&my_rsv->rsv_window,
-							grp_goal, group, sb))
-				grp_goal = -1;
-		} else if (grp_goal >= 0) {
-			int curr = my_rsv->rsv_end -
-					(grp_goal + group_first_block) + 1;
-
-			if (curr < *count)
-				try_to_extend_reservation(my_rsv, sb,
-							*count - curr);
-		}
-
-		if ((my_rsv->rsv_start > group_last_block) ||
-				(my_rsv->rsv_end < group_first_block)) {
-			rsv_window_dump(&EXT4_SB(sb)->s_rsv_window_root, 1);
-			BUG();
-		}
-		ret = ext4_try_to_allocate(sb, handle, group, bitmap_bh,
-					   grp_goal, &num, &my_rsv->rsv_window);
-		if (ret >= 0) {
-			my_rsv->rsv_alloc_hit += num;
-			*count = num;
-			break;				/* succeed */
-		}
-		num = *count;
-	}
-out:
-	if (ret >= 0) {
-		BUFFER_TRACE(bitmap_bh, "journal_dirty_metadata for "
-					"bitmap block");
-		fatal = ext4_journal_dirty_metadata(handle, bitmap_bh);
-		if (fatal) {
-			*errp = fatal;
-			return -1;
-		}
-		return ret;
-	}
-
-	BUFFER_TRACE(bitmap_bh, "journal_release_buffer");
-	ext4_journal_release_buffer(handle, bitmap_bh);
-	return ret;
-}
-
-/**
  * ext4_has_free_blocks()
  * @sbi:	in-core super block structure.
  * @nblocks:	number of neeed blocks
@@ -1610,29 +629,34 @@
  * On success, return nblocks
  */
 ext4_fsblk_t ext4_has_free_blocks(struct ext4_sb_info *sbi,
-						ext4_fsblk_t nblocks)
+						s64 nblocks)
 {
-	ext4_fsblk_t free_blocks;
-	ext4_fsblk_t root_blocks = 0;
+	s64 free_blocks, dirty_blocks;
+	s64 root_blocks = 0;
+	struct percpu_counter *fbc = &sbi->s_freeblocks_counter;
+	struct percpu_counter *dbc = &sbi->s_dirtyblocks_counter;
 
-	free_blocks = percpu_counter_read_positive(&sbi->s_freeblocks_counter);
+	free_blocks  = percpu_counter_read_positive(fbc);
+	dirty_blocks = percpu_counter_read_positive(dbc);
 
 	if (!capable(CAP_SYS_RESOURCE) &&
 		sbi->s_resuid != current->fsuid &&
 		(sbi->s_resgid == 0 || !in_group_p(sbi->s_resgid)))
 		root_blocks = ext4_r_blocks_count(sbi->s_es);
-#ifdef CONFIG_SMP
-	if (free_blocks - root_blocks < FBC_BATCH)
-		free_blocks =
-			percpu_counter_sum_and_set(&sbi->s_freeblocks_counter);
-#endif
-	if (free_blocks <= root_blocks)
+
+	if (free_blocks - (nblocks + root_blocks + dirty_blocks) <
+						EXT4_FREEBLOCKS_WATERMARK) {
+		free_blocks  = percpu_counter_sum(fbc);
+		dirty_blocks = percpu_counter_sum(dbc);
+	}
+	if (free_blocks <= (root_blocks + dirty_blocks))
 		/* we don't have free space */
 		return 0;
-	if (free_blocks - root_blocks < nblocks)
-		return free_blocks - root_blocks;
+
+	if (free_blocks - (root_blocks + dirty_blocks) < nblocks)
+		return free_blocks - (root_blocks + dirty_blocks);
 	return nblocks;
- }
+}
 
 
 /**
@@ -1657,303 +681,6 @@
 	return jbd2_journal_force_commit_nested(EXT4_SB(sb)->s_journal);
 }
 
-/**
- * ext4_old_new_blocks() -- core block bitmap based block allocation function
- *
- * @handle:		handle to this transaction
- * @inode:		file inode
- * @goal:		given target block(filesystem wide)
- * @count:		target number of blocks to allocate
- * @errp:		error code
- *
- * ext4_old_new_blocks uses a goal block to assist allocation and look up
- * the block bitmap directly to do block allocation.  It tries to
- * allocate block(s) from the block group contains the goal block first. If
- * that fails, it will try to allocate block(s) from other block groups
- * without any specific goal block.
- *
- * This function is called when -o nomballoc mount option is enabled
- *
- */
-ext4_fsblk_t ext4_old_new_blocks(handle_t *handle, struct inode *inode,
-			ext4_fsblk_t goal, unsigned long *count, int *errp)
-{
-	struct buffer_head *bitmap_bh = NULL;
-	struct buffer_head *gdp_bh;
-	ext4_group_t group_no;
-	ext4_group_t goal_group;
-	ext4_grpblk_t grp_target_blk;	/* blockgroup relative goal block */
-	ext4_grpblk_t grp_alloc_blk;	/* blockgroup-relative allocated block*/
-	ext4_fsblk_t ret_block;		/* filesyetem-wide allocated block */
-	ext4_group_t bgi;			/* blockgroup iteration index */
-	int fatal = 0, err;
-	int performed_allocation = 0;
-	ext4_grpblk_t free_blocks;	/* number of free blocks in a group */
-	struct super_block *sb;
-	struct ext4_group_desc *gdp;
-	struct ext4_super_block *es;
-	struct ext4_sb_info *sbi;
-	struct ext4_reserve_window_node *my_rsv = NULL;
-	struct ext4_block_alloc_info *block_i;
-	unsigned short windowsz = 0;
-	ext4_group_t ngroups;
-	unsigned long num = *count;
-
-	sb = inode->i_sb;
-	if (!sb) {
-		*errp = -ENODEV;
-		printk("ext4_new_block: nonexistent device");
-		return 0;
-	}
-
-	sbi = EXT4_SB(sb);
-	if (!EXT4_I(inode)->i_delalloc_reserved_flag) {
-		/*
-		 * With delalloc we already reserved the blocks
-		 */
-		*count = ext4_has_free_blocks(sbi, *count);
-	}
-	if (*count == 0) {
-		*errp = -ENOSPC;
-		return 0;	/*return with ENOSPC error */
-	}
-	num = *count;
-
-	/*
-	 * Check quota for allocation of this block.
-	 */
-	if (DQUOT_ALLOC_BLOCK(inode, num)) {
-		*errp = -EDQUOT;
-		return 0;
-	}
-
-	sbi = EXT4_SB(sb);
-	es = EXT4_SB(sb)->s_es;
-	ext4_debug("goal=%llu.\n", goal);
-	/*
-	 * Allocate a block from reservation only when
-	 * filesystem is mounted with reservation(default,-o reservation), and
-	 * it's a regular file, and
-	 * the desired window size is greater than 0 (One could use ioctl
-	 * command EXT4_IOC_SETRSVSZ to set the window size to 0 to turn off
-	 * reservation on that particular file)
-	 */
-	block_i = EXT4_I(inode)->i_block_alloc_info;
-	if (block_i && ((windowsz = block_i->rsv_window_node.rsv_goal_size) > 0))
-		my_rsv = &block_i->rsv_window_node;
-
-	/*
-	 * First, test whether the goal block is free.
-	 */
-	if (goal < le32_to_cpu(es->s_first_data_block) ||
-	    goal >= ext4_blocks_count(es))
-		goal = le32_to_cpu(es->s_first_data_block);
-	ext4_get_group_no_and_offset(sb, goal, &group_no, &grp_target_blk);
-	goal_group = group_no;
-retry_alloc:
-	gdp = ext4_get_group_desc(sb, group_no, &gdp_bh);
-	if (!gdp)
-		goto io_error;
-
-	free_blocks = le16_to_cpu(gdp->bg_free_blocks_count);
-	/*
-	 * if there is not enough free blocks to make a new resevation
-	 * turn off reservation for this allocation
-	 */
-	if (my_rsv && (free_blocks < windowsz)
-		&& (rsv_is_empty(&my_rsv->rsv_window)))
-		my_rsv = NULL;
-
-	if (free_blocks > 0) {
-		bitmap_bh = ext4_read_block_bitmap(sb, group_no);
-		if (!bitmap_bh)
-			goto io_error;
-		grp_alloc_blk = ext4_try_to_allocate_with_rsv(sb, handle,
-					group_no, bitmap_bh, grp_target_blk,
-					my_rsv,	&num, &fatal);
-		if (fatal)
-			goto out;
-		if (grp_alloc_blk >= 0)
-			goto allocated;
-	}
-
-	ngroups = EXT4_SB(sb)->s_groups_count;
-	smp_rmb();
-
-	/*
-	 * Now search the rest of the groups.  We assume that
-	 * group_no and gdp correctly point to the last group visited.
-	 */
-	for (bgi = 0; bgi < ngroups; bgi++) {
-		group_no++;
-		if (group_no >= ngroups)
-			group_no = 0;
-		gdp = ext4_get_group_desc(sb, group_no, &gdp_bh);
-		if (!gdp)
-			goto io_error;
-		free_blocks = le16_to_cpu(gdp->bg_free_blocks_count);
-		/*
-		 * skip this group if the number of
-		 * free blocks is less than half of the reservation
-		 * window size.
-		 */
-		if (free_blocks <= (windowsz/2))
-			continue;
-
-		brelse(bitmap_bh);
-		bitmap_bh = ext4_read_block_bitmap(sb, group_no);
-		if (!bitmap_bh)
-			goto io_error;
-		/*
-		 * try to allocate block(s) from this group, without a goal(-1).
-		 */
-		grp_alloc_blk = ext4_try_to_allocate_with_rsv(sb, handle,
-					group_no, bitmap_bh, -1, my_rsv,
-					&num, &fatal);
-		if (fatal)
-			goto out;
-		if (grp_alloc_blk >= 0)
-			goto allocated;
-	}
-	/*
-	 * We may end up a bogus ealier ENOSPC error due to
-	 * filesystem is "full" of reservations, but
-	 * there maybe indeed free blocks avaliable on disk
-	 * In this case, we just forget about the reservations
-	 * just do block allocation as without reservations.
-	 */
-	if (my_rsv) {
-		my_rsv = NULL;
-		windowsz = 0;
-		group_no = goal_group;
-		goto retry_alloc;
-	}
-	/* No space left on the device */
-	*errp = -ENOSPC;
-	goto out;
-
-allocated:
-
-	ext4_debug("using block group %lu(%d)\n",
-			group_no, gdp->bg_free_blocks_count);
-
-	BUFFER_TRACE(gdp_bh, "get_write_access");
-	fatal = ext4_journal_get_write_access(handle, gdp_bh);
-	if (fatal)
-		goto out;
-
-	ret_block = grp_alloc_blk + ext4_group_first_block_no(sb, group_no);
-
-	if (in_range(ext4_block_bitmap(sb, gdp), ret_block, num) ||
-	    in_range(ext4_inode_bitmap(sb, gdp), ret_block, num) ||
-	    in_range(ret_block, ext4_inode_table(sb, gdp),
-		     EXT4_SB(sb)->s_itb_per_group) ||
-	    in_range(ret_block + num - 1, ext4_inode_table(sb, gdp),
-		     EXT4_SB(sb)->s_itb_per_group)) {
-		ext4_error(sb, "ext4_new_block",
-			    "Allocating block in system zone - "
-			    "blocks from %llu, length %lu",
-			     ret_block, num);
-		/*
-		 * claim_block marked the blocks we allocated
-		 * as in use. So we may want to selectively
-		 * mark some of the blocks as free
-		 */
-		goto retry_alloc;
-	}
-
-	performed_allocation = 1;
-
-#ifdef CONFIG_JBD2_DEBUG
-	{
-		struct buffer_head *debug_bh;
-
-		/* Record bitmap buffer state in the newly allocated block */
-		debug_bh = sb_find_get_block(sb, ret_block);
-		if (debug_bh) {
-			BUFFER_TRACE(debug_bh, "state when allocated");
-			BUFFER_TRACE2(debug_bh, bitmap_bh, "bitmap state");
-			brelse(debug_bh);
-		}
-	}
-	jbd_lock_bh_state(bitmap_bh);
-	spin_lock(sb_bgl_lock(sbi, group_no));
-	if (buffer_jbd(bitmap_bh) && bh2jh(bitmap_bh)->b_committed_data) {
-		int i;
-
-		for (i = 0; i < num; i++) {
-			if (ext4_test_bit(grp_alloc_blk+i,
-					bh2jh(bitmap_bh)->b_committed_data)) {
-				printk("%s: block was unexpectedly set in "
-					"b_committed_data\n", __func__);
-			}
-		}
-	}
-	ext4_debug("found bit %d\n", grp_alloc_blk);
-	spin_unlock(sb_bgl_lock(sbi, group_no));
-	jbd_unlock_bh_state(bitmap_bh);
-#endif
-
-	if (ret_block + num - 1 >= ext4_blocks_count(es)) {
-		ext4_error(sb, "ext4_new_block",
-			    "block(%llu) >= blocks count(%llu) - "
-			    "block_group = %lu, es == %p ", ret_block,
-			ext4_blocks_count(es), group_no, es);
-		goto out;
-	}
-
-	/*
-	 * It is up to the caller to add the new buffer to a journal
-	 * list of some description.  We don't know in advance whether
-	 * the caller wants to use it as metadata or data.
-	 */
-	spin_lock(sb_bgl_lock(sbi, group_no));
-	if (gdp->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT))
-		gdp->bg_flags &= cpu_to_le16(~EXT4_BG_BLOCK_UNINIT);
-	le16_add_cpu(&gdp->bg_free_blocks_count, -num);
-	gdp->bg_checksum = ext4_group_desc_csum(sbi, group_no, gdp);
-	spin_unlock(sb_bgl_lock(sbi, group_no));
-	if (!EXT4_I(inode)->i_delalloc_reserved_flag)
-		percpu_counter_sub(&sbi->s_freeblocks_counter, num);
-
-	if (sbi->s_log_groups_per_flex) {
-		ext4_group_t flex_group = ext4_flex_group(sbi, group_no);
-		spin_lock(sb_bgl_lock(sbi, flex_group));
-		sbi->s_flex_groups[flex_group].free_blocks -= num;
-		spin_unlock(sb_bgl_lock(sbi, flex_group));
-	}
-
-	BUFFER_TRACE(gdp_bh, "journal_dirty_metadata for group descriptor");
-	err = ext4_journal_dirty_metadata(handle, gdp_bh);
-	if (!fatal)
-		fatal = err;
-
-	sb->s_dirt = 1;
-	if (fatal)
-		goto out;
-
-	*errp = 0;
-	brelse(bitmap_bh);
-	DQUOT_FREE_BLOCK(inode, *count-num);
-	*count = num;
-	return ret_block;
-
-io_error:
-	*errp = -EIO;
-out:
-	if (fatal) {
-		*errp = fatal;
-		ext4_std_error(sb, fatal);
-	}
-	/*
-	 * Undo the block allocation
-	 */
-	if (!performed_allocation)
-		DQUOT_FREE_BLOCK(inode, *count);
-	brelse(bitmap_bh);
-	return 0;
-}
-
 #define EXT4_META_BLOCK 0x1
 
 static ext4_fsblk_t do_blk_alloc(handle_t *handle, struct inode *inode,
@@ -1963,10 +690,6 @@
 	struct ext4_allocation_request ar;
 	ext4_fsblk_t ret;
 
-	if (!test_opt(inode->i_sb, MBALLOC)) {
-		return ext4_old_new_blocks(handle, inode, goal, count, errp);
-	}
-
 	memset(&ar, 0, sizeof(ar));
 	/* Fill with neighbour allocated blocks */
 
@@ -2008,7 +731,7 @@
 	/*
 	 * Account for the allocated meta blocks
 	 */
-	if (!(*errp)) {
+	if (!(*errp) && EXT4_I(inode)->i_delalloc_reserved_flag) {
 		spin_lock(&EXT4_I(inode)->i_block_reservation_lock);
 		EXT4_I(inode)->i_allocated_meta_blocks += *count;
 		spin_unlock(&EXT4_I(inode)->i_block_reservation_lock);
@@ -2093,10 +816,9 @@
 		bitmap_count += x;
 	}
 	brelse(bitmap_bh);
-	printk("ext4_count_free_blocks: stored = %llu"
-		", computed = %llu, %llu\n",
-		ext4_free_blocks_count(es),
-		desc_count, bitmap_count);
+	printk(KERN_DEBUG "ext4_count_free_blocks: stored = %llu"
+		", computed = %llu, %llu\n", ext4_free_blocks_count(es),
+	       desc_count, bitmap_count);
 	return bitmap_count;
 #else
 	desc_count = 0;
@@ -2183,8 +905,9 @@
 
 	if (!EXT4_HAS_INCOMPAT_FEATURE(sb,EXT4_FEATURE_INCOMPAT_META_BG) ||
 			metagroup < first_meta_bg)
-		return ext4_bg_num_gdb_nometa(sb,group);
+		return ext4_bg_num_gdb_nometa(sb, group);
 
 	return ext4_bg_num_gdb_meta(sb,group);
 
 }
+
diff --git a/fs/ext4/bitmap.c b/fs/ext4/bitmap.c
index d37ea67..0a7a666 100644
--- a/fs/ext4/bitmap.c
+++ b/fs/ext4/bitmap.c
@@ -15,17 +15,17 @@
 
 static const int nibblemap[] = {4, 3, 3, 2, 3, 2, 2, 1, 3, 2, 2, 1, 2, 1, 1, 0};
 
-unsigned long ext4_count_free (struct buffer_head * map, unsigned int numchars)
+unsigned long ext4_count_free(struct buffer_head *map, unsigned int numchars)
 {
 	unsigned int i;
 	unsigned long sum = 0;
 
 	if (!map)
-		return (0);
+		return 0;
 	for (i = 0; i < numchars; i++)
 		sum += nibblemap[map->b_data[i] & 0xf] +
 			nibblemap[(map->b_data[i] >> 4) & 0xf];
-	return (sum);
+	return sum;
 }
 
 #endif  /*  EXT4FS_DEBUG  */
diff --git a/fs/ext4/dir.c b/fs/ext4/dir.c
index ec8e33b..3ca6a2b 100644
--- a/fs/ext4/dir.c
+++ b/fs/ext4/dir.c
@@ -33,10 +33,10 @@
 };
 
 static int ext4_readdir(struct file *, void *, filldir_t);
-static int ext4_dx_readdir(struct file * filp,
-			   void * dirent, filldir_t filldir);
-static int ext4_release_dir (struct inode * inode,
-				struct file * filp);
+static int ext4_dx_readdir(struct file *filp,
+			   void *dirent, filldir_t filldir);
+static int ext4_release_dir(struct inode *inode,
+				struct file *filp);
 
 const struct file_operations ext4_dir_operations = {
 	.llseek		= generic_file_llseek,
@@ -61,12 +61,12 @@
 }
 
 
-int ext4_check_dir_entry (const char * function, struct inode * dir,
-			  struct ext4_dir_entry_2 * de,
-			  struct buffer_head * bh,
-			  unsigned long offset)
+int ext4_check_dir_entry(const char *function, struct inode *dir,
+			 struct ext4_dir_entry_2 *de,
+			 struct buffer_head *bh,
+			 unsigned long offset)
 {
-	const char * error_msg = NULL;
+	const char *error_msg = NULL;
 	const int rlen = ext4_rec_len_from_disk(de->rec_len);
 
 	if (rlen < EXT4_DIR_REC_LEN(1))
@@ -82,7 +82,7 @@
 		error_msg = "inode out of bounds";
 
 	if (error_msg != NULL)
-		ext4_error (dir->i_sb, function,
+		ext4_error(dir->i_sb, function,
 			"bad entry in directory #%lu: %s - "
 			"offset=%lu, inode=%lu, rec_len=%d, name_len=%d",
 			dir->i_ino, error_msg, offset,
@@ -91,8 +91,8 @@
 	return error_msg == NULL ? 1 : 0;
 }
 
-static int ext4_readdir(struct file * filp,
-			 void * dirent, filldir_t filldir)
+static int ext4_readdir(struct file *filp,
+			 void *dirent, filldir_t filldir)
 {
 	int error = 0;
 	unsigned long offset;
@@ -102,6 +102,7 @@
 	int err;
 	struct inode *inode = filp->f_path.dentry->d_inode;
 	int ret = 0;
+	int dir_has_error = 0;
 
 	sb = inode->i_sb;
 
@@ -148,9 +149,13 @@
 		 * of recovering data when there's a bad sector
 		 */
 		if (!bh) {
-			ext4_error (sb, "ext4_readdir",
-				"directory #%lu contains a hole at offset %lu",
-				inode->i_ino, (unsigned long)filp->f_pos);
+			if (!dir_has_error) {
+				ext4_error(sb, __func__, "directory #%lu "
+					   "contains a hole at offset %Lu",
+					   inode->i_ino,
+					   (unsigned long long) filp->f_pos);
+				dir_has_error = 1;
+			}
 			/* corrupt size?  Maybe no more blocks to read */
 			if (filp->f_pos > inode->i_blocks << 9)
 				break;
@@ -187,14 +192,14 @@
 		while (!error && filp->f_pos < inode->i_size
 		       && offset < sb->s_blocksize) {
 			de = (struct ext4_dir_entry_2 *) (bh->b_data + offset);
-			if (!ext4_check_dir_entry ("ext4_readdir", inode, de,
-						   bh, offset)) {
+			if (!ext4_check_dir_entry("ext4_readdir", inode, de,
+						  bh, offset)) {
 				/*
 				 * On error, skip the f_pos to the next block
 				 */
 				filp->f_pos = (filp->f_pos |
 						(sb->s_blocksize - 1)) + 1;
-				brelse (bh);
+				brelse(bh);
 				ret = stored;
 				goto out;
 			}
@@ -218,12 +223,12 @@
 					break;
 				if (version != filp->f_version)
 					goto revalidate;
-				stored ++;
+				stored++;
 			}
 			filp->f_pos += ext4_rec_len_from_disk(de->rec_len);
 		}
 		offset = 0;
-		brelse (bh);
+		brelse(bh);
 	}
 out:
 	return ret;
@@ -290,9 +295,9 @@
 		parent = rb_parent(n);
 		fname = rb_entry(n, struct fname, rb_hash);
 		while (fname) {
-			struct fname * old = fname;
+			struct fname *old = fname;
 			fname = fname->next;
-			kfree (old);
+			kfree(old);
 		}
 		if (!parent)
 			root->rb_node = NULL;
@@ -331,7 +336,7 @@
 			     struct ext4_dir_entry_2 *dirent)
 {
 	struct rb_node **p, *parent = NULL;
-	struct fname * fname, *new_fn;
+	struct fname *fname, *new_fn;
 	struct dir_private_info *info;
 	int len;
 
@@ -388,19 +393,20 @@
  * for all entres on the fname linked list.  (Normally there is only
  * one entry on the linked list, unless there are 62 bit hash collisions.)
  */
-static int call_filldir(struct file * filp, void * dirent,
+static int call_filldir(struct file *filp, void *dirent,
 			filldir_t filldir, struct fname *fname)
 {
 	struct dir_private_info *info = filp->private_data;
 	loff_t	curr_pos;
 	struct inode *inode = filp->f_path.dentry->d_inode;
-	struct super_block * sb;
+	struct super_block *sb;
 	int error;
 
 	sb = inode->i_sb;
 
 	if (!fname) {
-		printk("call_filldir: called with null fname?!?\n");
+		printk(KERN_ERR "ext4: call_filldir: called with "
+		       "null fname?!?\n");
 		return 0;
 	}
 	curr_pos = hash2pos(fname->hash, fname->minor_hash);
@@ -419,8 +425,8 @@
 	return 0;
 }
 
-static int ext4_dx_readdir(struct file * filp,
-			 void * dirent, filldir_t filldir)
+static int ext4_dx_readdir(struct file *filp,
+			 void *dirent, filldir_t filldir)
 {
 	struct dir_private_info *info = filp->private_data;
 	struct inode *inode = filp->f_path.dentry->d_inode;
@@ -511,7 +517,7 @@
 	return 0;
 }
 
-static int ext4_release_dir (struct inode * inode, struct file * filp)
+static int ext4_release_dir(struct inode *inode, struct file *filp)
 {
 	if (filp->private_data)
 		ext4_htree_free_dir_info(filp->private_data);
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
index 2950032..6690a41 100644
--- a/fs/ext4/ext4.h
+++ b/fs/ext4/ext4.h
@@ -44,9 +44,9 @@
 #ifdef EXT4FS_DEBUG
 #define ext4_debug(f, a...)						\
 	do {								\
-		printk (KERN_DEBUG "EXT4-fs DEBUG (%s, %d): %s:",	\
+		printk(KERN_DEBUG "EXT4-fs DEBUG (%s, %d): %s:",	\
 			__FILE__, __LINE__, __func__);			\
-		printk (KERN_DEBUG f, ## a);				\
+		printk(KERN_DEBUG f, ## a);				\
 	} while (0)
 #else
 #define ext4_debug(f, a...)	do {} while (0)
@@ -128,7 +128,7 @@
 #else
 # define EXT4_BLOCK_SIZE(s)		(EXT4_MIN_BLOCK_SIZE << (s)->s_log_block_size)
 #endif
-#define	EXT4_ADDR_PER_BLOCK(s)		(EXT4_BLOCK_SIZE(s) / sizeof (__u32))
+#define	EXT4_ADDR_PER_BLOCK(s)		(EXT4_BLOCK_SIZE(s) / sizeof(__u32))
 #ifdef __KERNEL__
 # define EXT4_BLOCK_SIZE_BITS(s)	((s)->s_blocksize_bits)
 #else
@@ -245,7 +245,7 @@
 #define EXT4_RESERVED_FL		0x80000000 /* reserved for ext4 lib */
 
 #define EXT4_FL_USER_VISIBLE		0x000BDFFF /* User visible flags */
-#define EXT4_FL_USER_MODIFIABLE		0x000380FF /* User modifiable flags */
+#define EXT4_FL_USER_MODIFIABLE		0x000B80FF /* User modifiable flags */
 
 /*
  * Inode dynamic state flags
@@ -291,8 +291,6 @@
 #define	EXT4_IOC_SETFLAGS		FS_IOC_SETFLAGS
 #define	EXT4_IOC_GETVERSION		_IOR('f', 3, long)
 #define	EXT4_IOC_SETVERSION		_IOW('f', 4, long)
-#define EXT4_IOC_GROUP_EXTEND		_IOW('f', 7, unsigned long)
-#define EXT4_IOC_GROUP_ADD		_IOW('f', 8,struct ext4_new_group_input)
 #define	EXT4_IOC_GETVERSION_OLD		FS_IOC_GETVERSION
 #define	EXT4_IOC_SETVERSION_OLD		FS_IOC_SETVERSION
 #ifdef CONFIG_JBD2_DEBUG
@@ -300,7 +298,10 @@
 #endif
 #define EXT4_IOC_GETRSVSZ		_IOR('f', 5, long)
 #define EXT4_IOC_SETRSVSZ		_IOW('f', 6, long)
-#define EXT4_IOC_MIGRATE		_IO('f', 7)
+#define EXT4_IOC_GROUP_EXTEND		_IOW('f', 7, unsigned long)
+#define EXT4_IOC_GROUP_ADD		_IOW('f', 8, struct ext4_new_group_input)
+#define EXT4_IOC_MIGRATE		_IO('f', 9)
+ /* note ioctl 11 reserved for filesystem-independent FIEMAP ioctl */
 
 /*
  * ioctl commands in 32 bit emulation
@@ -538,8 +539,9 @@
 #define EXT4_MOUNT_JOURNAL_CHECKSUM	0x800000 /* Journal checksums */
 #define EXT4_MOUNT_JOURNAL_ASYNC_COMMIT	0x1000000 /* Journal Async Commit */
 #define EXT4_MOUNT_I_VERSION            0x2000000 /* i_version support */
-#define EXT4_MOUNT_MBALLOC		0x4000000 /* Buddy allocation support */
 #define EXT4_MOUNT_DELALLOC		0x8000000 /* Delalloc support */
+#define EXT4_MOUNT_DATA_ERR_ABORT	0x10000000 /* Abort on file data write */
+
 /* Compatibility, for having both ext2_fs.h and ext4_fs.h included at once */
 #ifndef _LINUX_EXT2_FS_H
 #define clear_opt(o, opt)		o &= ~EXT4_MOUNT_##opt
@@ -667,7 +669,7 @@
 };
 
 #ifdef __KERNEL__
-static inline struct ext4_sb_info * EXT4_SB(struct super_block *sb)
+static inline struct ext4_sb_info *EXT4_SB(struct super_block *sb)
 {
 	return sb->s_fs_info;
 }
@@ -725,11 +727,11 @@
  */
 
 #define EXT4_HAS_COMPAT_FEATURE(sb,mask)			\
-	( EXT4_SB(sb)->s_es->s_feature_compat & cpu_to_le32(mask) )
+	(EXT4_SB(sb)->s_es->s_feature_compat & cpu_to_le32(mask))
 #define EXT4_HAS_RO_COMPAT_FEATURE(sb,mask)			\
-	( EXT4_SB(sb)->s_es->s_feature_ro_compat & cpu_to_le32(mask) )
+	(EXT4_SB(sb)->s_es->s_feature_ro_compat & cpu_to_le32(mask))
 #define EXT4_HAS_INCOMPAT_FEATURE(sb,mask)			\
-	( EXT4_SB(sb)->s_es->s_feature_incompat & cpu_to_le32(mask) )
+	(EXT4_SB(sb)->s_es->s_feature_incompat & cpu_to_le32(mask))
 #define EXT4_SET_COMPAT_FEATURE(sb,mask)			\
 	EXT4_SB(sb)->s_es->s_feature_compat |= cpu_to_le32(mask)
 #define EXT4_SET_RO_COMPAT_FEATURE(sb,mask)			\
@@ -789,6 +791,8 @@
 #define	EXT4_DEF_RESUID		0
 #define	EXT4_DEF_RESGID		0
 
+#define EXT4_DEF_INODE_READAHEAD_BLKS	32
+
 /*
  * Default mount options
  */
@@ -954,6 +958,24 @@
 void ext4_get_group_no_and_offset(struct super_block *sb, ext4_fsblk_t blocknr,
 			unsigned long *blockgrpp, ext4_grpblk_t *offsetp);
 
+extern struct proc_dir_entry *ext4_proc_root;
+
+#ifdef CONFIG_PROC_FS
+extern const struct file_operations ext4_ui_proc_fops;
+
+#define	EXT4_PROC_HANDLER(name, var)					\
+do {									\
+	proc = proc_create_data(name, mode, sbi->s_proc,		\
+				&ext4_ui_proc_fops, &sbi->s_##var);	\
+	if (proc == NULL) {						\
+		printk(KERN_ERR "EXT4-fs: can't create %s\n", name);	\
+		goto err_out;						\
+	}								\
+} while (0)
+#else
+#define EXT4_PROC_HANDLER(name, var)
+#endif
+
 /*
  * Function prototypes
  */
@@ -981,23 +1003,20 @@
 extern ext4_fsblk_t ext4_new_blocks(handle_t *handle, struct inode *inode,
 					ext4_lblk_t iblock, ext4_fsblk_t goal,
 					unsigned long *count, int *errp);
-extern ext4_fsblk_t ext4_old_new_blocks(handle_t *handle, struct inode *inode,
-			ext4_fsblk_t goal, unsigned long *count, int *errp);
+extern int ext4_claim_free_blocks(struct ext4_sb_info *sbi, s64 nblocks);
 extern ext4_fsblk_t ext4_has_free_blocks(struct ext4_sb_info *sbi,
-						ext4_fsblk_t nblocks);
-extern void ext4_free_blocks (handle_t *handle, struct inode *inode,
+					 s64 nblocks);
+extern void ext4_free_blocks(handle_t *handle, struct inode *inode,
 			ext4_fsblk_t block, unsigned long count, int metadata);
-extern void ext4_free_blocks_sb (handle_t *handle, struct super_block *sb,
-				 ext4_fsblk_t block, unsigned long count,
+extern void ext4_free_blocks_sb(handle_t *handle, struct super_block *sb,
+				ext4_fsblk_t block, unsigned long count,
 				unsigned long *pdquot_freed_blocks);
-extern ext4_fsblk_t ext4_count_free_blocks (struct super_block *);
-extern void ext4_check_blocks_bitmap (struct super_block *);
+extern ext4_fsblk_t ext4_count_free_blocks(struct super_block *);
+extern void ext4_check_blocks_bitmap(struct super_block *);
 extern struct ext4_group_desc * ext4_get_group_desc(struct super_block * sb,
 						    ext4_group_t block_group,
 						    struct buffer_head ** bh);
 extern int ext4_should_retry_alloc(struct super_block *sb, int *retries);
-extern void ext4_init_block_alloc_info(struct inode *);
-extern void ext4_rsv_window_add(struct super_block *sb, struct ext4_reserve_window_node *rsv);
 
 /* dir.c */
 extern int ext4_check_dir_entry(const char *, struct inode *,
@@ -1009,20 +1028,20 @@
 extern void ext4_htree_free_dir_info(struct dir_private_info *p);
 
 /* fsync.c */
-extern int ext4_sync_file (struct file *, struct dentry *, int);
+extern int ext4_sync_file(struct file *, struct dentry *, int);
 
 /* hash.c */
 extern int ext4fs_dirhash(const char *name, int len, struct
 			  dx_hash_info *hinfo);
 
 /* ialloc.c */
-extern struct inode * ext4_new_inode (handle_t *, struct inode *, int);
-extern void ext4_free_inode (handle_t *, struct inode *);
-extern struct inode * ext4_orphan_get (struct super_block *, unsigned long);
-extern unsigned long ext4_count_free_inodes (struct super_block *);
-extern unsigned long ext4_count_dirs (struct super_block *);
-extern void ext4_check_inodes_bitmap (struct super_block *);
-extern unsigned long ext4_count_free (struct buffer_head *, unsigned);
+extern struct inode * ext4_new_inode(handle_t *, struct inode *, int);
+extern void ext4_free_inode(handle_t *, struct inode *);
+extern struct inode * ext4_orphan_get(struct super_block *, unsigned long);
+extern unsigned long ext4_count_free_inodes(struct super_block *);
+extern unsigned long ext4_count_dirs(struct super_block *);
+extern void ext4_check_inodes_bitmap(struct super_block *);
+extern unsigned long ext4_count_free(struct buffer_head *, unsigned);
 
 /* mballoc.c */
 extern long ext4_mb_stats;
@@ -1032,7 +1051,7 @@
 extern ext4_fsblk_t ext4_mb_new_blocks(handle_t *,
 				struct ext4_allocation_request *, int *);
 extern int ext4_mb_reserve_blocks(struct super_block *, int);
-extern void ext4_mb_discard_inode_preallocations(struct inode *);
+extern void ext4_discard_preallocations(struct inode *);
 extern int __init init_ext4_mballoc(void);
 extern void exit_ext4_mballoc(void);
 extern void ext4_mb_free_blocks(handle_t *, struct inode *,
@@ -1050,24 +1069,25 @@
 						ext4_lblk_t, int, int *);
 struct buffer_head *ext4_bread(handle_t *, struct inode *,
 						ext4_lblk_t, int, int *);
+int ext4_get_block(struct inode *inode, sector_t iblock,
+				struct buffer_head *bh_result, int create);
 int ext4_get_blocks_handle(handle_t *handle, struct inode *inode,
 				ext4_lblk_t iblock, unsigned long maxblocks,
 				struct buffer_head *bh_result,
 				int create, int extend_disksize);
 
 extern struct inode *ext4_iget(struct super_block *, unsigned long);
-extern int  ext4_write_inode (struct inode *, int);
-extern int  ext4_setattr (struct dentry *, struct iattr *);
+extern int  ext4_write_inode(struct inode *, int);
+extern int  ext4_setattr(struct dentry *, struct iattr *);
 extern int  ext4_getattr(struct vfsmount *mnt, struct dentry *dentry,
 				struct kstat *stat);
-extern void ext4_delete_inode (struct inode *);
-extern int  ext4_sync_inode (handle_t *, struct inode *);
-extern void ext4_discard_reservation (struct inode *);
+extern void ext4_delete_inode(struct inode *);
+extern int  ext4_sync_inode(handle_t *, struct inode *);
 extern void ext4_dirty_inode(struct inode *);
 extern int ext4_change_inode_journal_flag(struct inode *, int);
 extern int ext4_get_inode_loc(struct inode *, struct ext4_iloc *);
 extern int ext4_can_truncate(struct inode *inode);
-extern void ext4_truncate (struct inode *);
+extern void ext4_truncate(struct inode *);
 extern void ext4_set_inode_flags(struct inode *);
 extern void ext4_get_inode_flags(struct ext4_inode_info *);
 extern void ext4_set_aops(struct inode *inode);
@@ -1080,11 +1100,10 @@
 
 /* ioctl.c */
 extern long ext4_ioctl(struct file *, unsigned int, unsigned long);
-extern long ext4_compat_ioctl (struct file *, unsigned int, unsigned long);
+extern long ext4_compat_ioctl(struct file *, unsigned int, unsigned long);
 
 /* migrate.c */
-extern int ext4_ext_migrate(struct inode *, struct file *, unsigned int,
-		       unsigned long);
+extern int ext4_ext_migrate(struct inode *);
 /* namei.c */
 extern int ext4_orphan_add(handle_t *, struct inode *);
 extern int ext4_orphan_del(handle_t *, struct inode *);
@@ -1099,14 +1118,14 @@
 				ext4_fsblk_t n_blocks_count);
 
 /* super.c */
-extern void ext4_error (struct super_block *, const char *, const char *, ...)
+extern void ext4_error(struct super_block *, const char *, const char *, ...)
 	__attribute__ ((format (printf, 3, 4)));
-extern void __ext4_std_error (struct super_block *, const char *, int);
-extern void ext4_abort (struct super_block *, const char *, const char *, ...)
+extern void __ext4_std_error(struct super_block *, const char *, int);
+extern void ext4_abort(struct super_block *, const char *, const char *, ...)
 	__attribute__ ((format (printf, 3, 4)));
-extern void ext4_warning (struct super_block *, const char *, const char *, ...)
+extern void ext4_warning(struct super_block *, const char *, const char *, ...)
 	__attribute__ ((format (printf, 3, 4)));
-extern void ext4_update_dynamic_rev (struct super_block *sb);
+extern void ext4_update_dynamic_rev(struct super_block *sb);
 extern int ext4_update_compat_feature(handle_t *handle, struct super_block *sb,
 					__u32 compat);
 extern int ext4_update_rocompat_feature(handle_t *handle,
@@ -1179,7 +1198,7 @@
 
 static inline
 struct ext4_group_info *ext4_get_group_info(struct super_block *sb,
-							ext4_group_t group)
+					    ext4_group_t group)
 {
 	 struct ext4_group_info ***grp_info;
 	 long indexv, indexh;
@@ -1207,6 +1226,28 @@
 		__ext4_std_error((sb), __func__, (errno));	\
 } while (0)
 
+#ifdef CONFIG_SMP
+/* Each CPU can accumulate FBC_BATCH blocks in their local
+ * counters. So we need to make sure we have free blocks more
+ * than FBC_BATCH  * nr_cpu_ids. Also add a window of 4 times.
+ */
+#define EXT4_FREEBLOCKS_WATERMARK (4 * (FBC_BATCH * nr_cpu_ids))
+#else
+#define EXT4_FREEBLOCKS_WATERMARK 0
+#endif
+
+static inline void ext4_update_i_disksize(struct inode *inode, loff_t newsize)
+{
+	/*
+	 * XXX: replace with spinlock if seen contended -bzzz
+	 */
+	down_write(&EXT4_I(inode)->i_data_sem);
+	if (newsize > EXT4_I(inode)->i_disksize)
+		EXT4_I(inode)->i_disksize = newsize;
+	up_write(&EXT4_I(inode)->i_data_sem);
+	return ;
+}
+
 /*
  * Inodes and files operations
  */
diff --git a/fs/ext4/ext4_extents.h b/fs/ext4/ext4_extents.h
index d33dc56..bec7ce5 100644
--- a/fs/ext4/ext4_extents.h
+++ b/fs/ext4/ext4_extents.h
@@ -124,6 +124,19 @@
 #define EXT4_EXT_CACHE_GAP	1
 #define EXT4_EXT_CACHE_EXTENT	2
 
+/*
+ * to be called by ext4_ext_walk_space()
+ * negative retcode - error
+ * positive retcode - signal for ext4_ext_walk_space(), see below
+ * callback must return valid extent (passed or newly created)
+ */
+typedef int (*ext_prepare_callback)(struct inode *, struct ext4_ext_path *,
+					struct ext4_ext_cache *,
+					struct ext4_extent *, void *);
+
+#define EXT_CONTINUE   0
+#define EXT_BREAK      1
+#define EXT_REPEAT     2
 
 #define EXT_MAX_BLOCK	0xffffffff
 
@@ -224,6 +237,8 @@
 				 struct ext4_extent *);
 extern unsigned int ext4_ext_check_overlap(struct inode *, struct ext4_extent *, struct ext4_ext_path *);
 extern int ext4_ext_insert_extent(handle_t *, struct inode *, struct ext4_ext_path *, struct ext4_extent *);
+extern int ext4_ext_walk_space(struct inode *, ext4_lblk_t, ext4_lblk_t,
+							ext_prepare_callback, void *);
 extern struct ext4_ext_path *ext4_ext_find_extent(struct inode *, ext4_lblk_t,
 							struct ext4_ext_path *);
 extern int ext4_ext_search_left(struct inode *, struct ext4_ext_path *,
diff --git a/fs/ext4/ext4_i.h b/fs/ext4/ext4_i.h
index ef7409f..5c124c0 100644
--- a/fs/ext4/ext4_i.h
+++ b/fs/ext4/ext4_i.h
@@ -33,38 +33,6 @@
 /* data type for block group number */
 typedef unsigned long ext4_group_t;
 
-struct ext4_reserve_window {
-	ext4_fsblk_t	_rsv_start;	/* First byte reserved */
-	ext4_fsblk_t	_rsv_end;	/* Last byte reserved or 0 */
-};
-
-struct ext4_reserve_window_node {
-	struct rb_node		rsv_node;
-	__u32			rsv_goal_size;
-	__u32			rsv_alloc_hit;
-	struct ext4_reserve_window	rsv_window;
-};
-
-struct ext4_block_alloc_info {
-	/* information about reservation window */
-	struct ext4_reserve_window_node rsv_window_node;
-	/*
-	 * was i_next_alloc_block in ext4_inode_info
-	 * is the logical (file-relative) number of the
-	 * most-recently-allocated block in this file.
-	 * We use this for detecting linearly ascending allocation requests.
-	 */
-	ext4_lblk_t last_alloc_logical_block;
-	/*
-	 * Was i_next_alloc_goal in ext4_inode_info
-	 * is the *physical* companion to i_next_alloc_block.
-	 * it the physical block number of the block which was most-recentl
-	 * allocated to this file.  This give us the goal (target) for the next
-	 * allocation when we detect linearly ascending requests.
-	 */
-	ext4_fsblk_t last_alloc_physical_block;
-};
-
 #define rsv_start rsv_window._rsv_start
 #define rsv_end rsv_window._rsv_end
 
@@ -97,11 +65,8 @@
 	ext4_group_t	i_block_group;
 	__u32	i_state;		/* Dynamic state flags for ext4 */
 
-	/* block reservation info */
-	struct ext4_block_alloc_info *i_block_alloc_info;
-
 	ext4_lblk_t		i_dir_start_lookup;
-#ifdef CONFIG_EXT4DEV_FS_XATTR
+#ifdef CONFIG_EXT4_FS_XATTR
 	/*
 	 * Extended attributes can be read independently of the main file
 	 * data. Taking i_mutex even when reading would cause contention
@@ -111,7 +76,7 @@
 	 */
 	struct rw_semaphore xattr_sem;
 #endif
-#ifdef CONFIG_EXT4DEV_FS_POSIX_ACL
+#ifdef CONFIG_EXT4_FS_POSIX_ACL
 	struct posix_acl	*i_acl;
 	struct posix_acl	*i_default_acl;
 #endif
diff --git a/fs/ext4/ext4_sb.h b/fs/ext4/ext4_sb.h
index 6300226..6a0b40d 100644
--- a/fs/ext4/ext4_sb.h
+++ b/fs/ext4/ext4_sb.h
@@ -40,8 +40,8 @@
 	unsigned long s_blocks_last;    /* Last seen block count */
 	loff_t s_bitmap_maxbytes;	/* max bytes for bitmap files */
 	struct buffer_head * s_sbh;	/* Buffer containing the super block */
-	struct ext4_super_block * s_es;	/* Pointer to the super block in the buffer */
-	struct buffer_head ** s_group_desc;
+	struct ext4_super_block *s_es;	/* Pointer to the super block in the buffer */
+	struct buffer_head **s_group_desc;
 	unsigned long  s_mount_opt;
 	ext4_fsblk_t s_sb_block;
 	uid_t s_resuid;
@@ -52,6 +52,7 @@
 	int s_desc_per_block_bits;
 	int s_inode_size;
 	int s_first_ino;
+	unsigned int s_inode_readahead_blks;
 	spinlock_t s_next_gen_lock;
 	u32 s_next_generation;
 	u32 s_hash_seed[4];
@@ -59,16 +60,17 @@
 	struct percpu_counter s_freeblocks_counter;
 	struct percpu_counter s_freeinodes_counter;
 	struct percpu_counter s_dirs_counter;
+	struct percpu_counter s_dirtyblocks_counter;
 	struct blockgroup_lock s_blockgroup_lock;
+	struct proc_dir_entry *s_proc;
 
 	/* root of the per fs reservation window tree */
 	spinlock_t s_rsv_window_lock;
 	struct rb_root s_rsv_window_root;
-	struct ext4_reserve_window_node s_rsv_window_head;
 
 	/* Journaling */
-	struct inode * s_journal_inode;
-	struct journal_s * s_journal;
+	struct inode *s_journal_inode;
+	struct journal_s *s_journal;
 	struct list_head s_orphan;
 	unsigned long s_commit_interval;
 	struct block_device *journal_bdev;
@@ -106,12 +108,12 @@
 
 	/* tunables */
 	unsigned long s_stripe;
-	unsigned long s_mb_stream_request;
-	unsigned long s_mb_max_to_scan;
-	unsigned long s_mb_min_to_scan;
-	unsigned long s_mb_stats;
-	unsigned long s_mb_order2_reqs;
-	unsigned long s_mb_group_prealloc;
+	unsigned int s_mb_stream_request;
+	unsigned int s_mb_max_to_scan;
+	unsigned int s_mb_min_to_scan;
+	unsigned int s_mb_stats;
+	unsigned int s_mb_order2_reqs;
+	unsigned int s_mb_group_prealloc;
 	/* where last allocation was done - for stream allocation */
 	unsigned long s_mb_last_group;
 	unsigned long s_mb_last_start;
@@ -121,7 +123,6 @@
 	int s_mb_history_cur;
 	int s_mb_history_max;
 	int s_mb_history_num;
-	struct proc_dir_entry *s_mb_proc;
 	spinlock_t s_mb_history_lock;
 	int s_mb_history_filter;
 
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
index b24d3c5..ea2ce3c 100644
--- a/fs/ext4/extents.c
+++ b/fs/ext4/extents.c
@@ -40,6 +40,7 @@
 #include <linux/slab.h>
 #include <linux/falloc.h>
 #include <asm/uaccess.h>
+#include <linux/fiemap.h>
 #include "ext4_jbd2.h"
 #include "ext4_extents.h"
 
@@ -383,8 +384,8 @@
 	ext_debug("\n");
 }
 #else
-#define ext4_ext_show_path(inode,path)
-#define ext4_ext_show_leaf(inode,path)
+#define ext4_ext_show_path(inode, path)
+#define ext4_ext_show_leaf(inode, path)
 #endif
 
 void ext4_ext_drop_refs(struct ext4_ext_path *path)
@@ -440,9 +441,10 @@
 		for (k = 0; k < le16_to_cpu(eh->eh_entries); k++, ix++) {
 		  if (k != 0 &&
 		      le32_to_cpu(ix->ei_block) <= le32_to_cpu(ix[-1].ei_block)) {
-				printk("k=%d, ix=0x%p, first=0x%p\n", k,
-					ix, EXT_FIRST_INDEX(eh));
-				printk("%u <= %u\n",
+				printk(KERN_DEBUG "k=%d, ix=0x%p, "
+				       "first=0x%p\n", k,
+				       ix, EXT_FIRST_INDEX(eh));
+				printk(KERN_DEBUG "%u <= %u\n",
 				       le32_to_cpu(ix->ei_block),
 				       le32_to_cpu(ix[-1].ei_block));
 			}
@@ -1475,7 +1477,7 @@
 				struct ext4_ext_path *path,
 				struct ext4_extent *newext)
 {
-	struct ext4_extent_header * eh;
+	struct ext4_extent_header *eh;
 	struct ext4_extent *ex, *fex;
 	struct ext4_extent *nearex; /* nearest extent */
 	struct ext4_ext_path *npath = NULL;
@@ -1625,6 +1627,113 @@
 	return err;
 }
 
+int ext4_ext_walk_space(struct inode *inode, ext4_lblk_t block,
+			ext4_lblk_t num, ext_prepare_callback func,
+			void *cbdata)
+{
+	struct ext4_ext_path *path = NULL;
+	struct ext4_ext_cache cbex;
+	struct ext4_extent *ex;
+	ext4_lblk_t next, start = 0, end = 0;
+	ext4_lblk_t last = block + num;
+	int depth, exists, err = 0;
+
+	BUG_ON(func == NULL);
+	BUG_ON(inode == NULL);
+
+	while (block < last && block != EXT_MAX_BLOCK) {
+		num = last - block;
+		/* find extent for this block */
+		path = ext4_ext_find_extent(inode, block, path);
+		if (IS_ERR(path)) {
+			err = PTR_ERR(path);
+			path = NULL;
+			break;
+		}
+
+		depth = ext_depth(inode);
+		BUG_ON(path[depth].p_hdr == NULL);
+		ex = path[depth].p_ext;
+		next = ext4_ext_next_allocated_block(path);
+
+		exists = 0;
+		if (!ex) {
+			/* there is no extent yet, so try to allocate
+			 * all requested space */
+			start = block;
+			end = block + num;
+		} else if (le32_to_cpu(ex->ee_block) > block) {
+			/* need to allocate space before found extent */
+			start = block;
+			end = le32_to_cpu(ex->ee_block);
+			if (block + num < end)
+				end = block + num;
+		} else if (block >= le32_to_cpu(ex->ee_block)
+					+ ext4_ext_get_actual_len(ex)) {
+			/* need to allocate space after found extent */
+			start = block;
+			end = block + num;
+			if (end >= next)
+				end = next;
+		} else if (block >= le32_to_cpu(ex->ee_block)) {
+			/*
+			 * some part of requested space is covered
+			 * by found extent
+			 */
+			start = block;
+			end = le32_to_cpu(ex->ee_block)
+				+ ext4_ext_get_actual_len(ex);
+			if (block + num < end)
+				end = block + num;
+			exists = 1;
+		} else {
+			BUG();
+		}
+		BUG_ON(end <= start);
+
+		if (!exists) {
+			cbex.ec_block = start;
+			cbex.ec_len = end - start;
+			cbex.ec_start = 0;
+			cbex.ec_type = EXT4_EXT_CACHE_GAP;
+		} else {
+			cbex.ec_block = le32_to_cpu(ex->ee_block);
+			cbex.ec_len = ext4_ext_get_actual_len(ex);
+			cbex.ec_start = ext_pblock(ex);
+			cbex.ec_type = EXT4_EXT_CACHE_EXTENT;
+		}
+
+		BUG_ON(cbex.ec_len == 0);
+		err = func(inode, path, &cbex, ex, cbdata);
+		ext4_ext_drop_refs(path);
+
+		if (err < 0)
+			break;
+
+		if (err == EXT_REPEAT)
+			continue;
+		else if (err == EXT_BREAK) {
+			err = 0;
+			break;
+		}
+
+		if (ext_depth(inode) != depth) {
+			/* depth was changed. we have to realloc path */
+			kfree(path);
+			path = NULL;
+		}
+
+		block = cbex.ec_block + cbex.ec_len;
+	}
+
+	if (path) {
+		ext4_ext_drop_refs(path);
+		kfree(path);
+	}
+
+	return err;
+}
+
 static void
 ext4_ext_put_in_cache(struct inode *inode, ext4_lblk_t block,
 			__u32 len, ext4_fsblk_t start, int type)
@@ -2142,7 +2251,7 @@
 	 */
 
 	if (test_opt(sb, EXTENTS)) {
-		printk("EXT4-fs: file extents enabled");
+		printk(KERN_INFO "EXT4-fs: file extents enabled");
 #ifdef AGGRESSIVE_TEST
 		printk(", aggressive tests");
 #endif
@@ -2696,11 +2805,8 @@
 		goto out2;
 	}
 	/*
-	 * Okay, we need to do block allocation.  Lazily initialize the block
-	 * allocation info here if necessary.
+	 * Okay, we need to do block allocation.
 	 */
-	if (S_ISREG(inode->i_mode) && (!EXT4_I(inode)->i_block_alloc_info))
-		ext4_init_block_alloc_info(inode);
 
 	/* find neighbour allocated blocks */
 	ar.lleft = iblock;
@@ -2760,7 +2866,7 @@
 		/* free data blocks we just allocated */
 		/* not a good idea to call discard here directly,
 		 * but otherwise we'd need to call it every free() */
-		ext4_mb_discard_inode_preallocations(inode);
+		ext4_discard_preallocations(inode);
 		ext4_free_blocks(handle, inode, ext_pblock(&newex),
 					ext4_ext_get_actual_len(&newex), 0);
 		goto out2;
@@ -2824,7 +2930,7 @@
 	down_write(&EXT4_I(inode)->i_data_sem);
 	ext4_ext_invalidate_cache(inode);
 
-	ext4_discard_reservation(inode);
+	ext4_discard_preallocations(inode);
 
 	/*
 	 * TODO: optimization is possible here.
@@ -2877,10 +2983,11 @@
 	 * Update only when preallocation was requested beyond
 	 * the file size.
 	 */
-	if (!(mode & FALLOC_FL_KEEP_SIZE) &&
-				new_size > i_size_read(inode)) {
-		i_size_write(inode, new_size);
-		EXT4_I(inode)->i_disksize = new_size;
+	if (!(mode & FALLOC_FL_KEEP_SIZE)) {
+		if (new_size > i_size_read(inode))
+			i_size_write(inode, new_size);
+		if (new_size > EXT4_I(inode)->i_disksize)
+			ext4_update_i_disksize(inode, new_size);
 	}
 
 }
@@ -2972,3 +3079,143 @@
 	mutex_unlock(&inode->i_mutex);
 	return ret > 0 ? ret2 : ret;
 }
+
+/*
+ * Callback function called for each extent to gather FIEMAP information.
+ */
+int ext4_ext_fiemap_cb(struct inode *inode, struct ext4_ext_path *path,
+		       struct ext4_ext_cache *newex, struct ext4_extent *ex,
+		       void *data)
+{
+	struct fiemap_extent_info *fieinfo = data;
+	unsigned long blksize_bits = inode->i_sb->s_blocksize_bits;
+	__u64	logical;
+	__u64	physical;
+	__u64	length;
+	__u32	flags = 0;
+	int	error;
+
+	logical =  (__u64)newex->ec_block << blksize_bits;
+
+	if (newex->ec_type == EXT4_EXT_CACHE_GAP) {
+		pgoff_t offset;
+		struct page *page;
+		struct buffer_head *bh = NULL;
+
+		offset = logical >> PAGE_SHIFT;
+		page = find_get_page(inode->i_mapping, offset);
+		if (!page || !page_has_buffers(page))
+			return EXT_CONTINUE;
+
+		bh = page_buffers(page);
+
+		if (!bh)
+			return EXT_CONTINUE;
+
+		if (buffer_delay(bh)) {
+			flags |= FIEMAP_EXTENT_DELALLOC;
+			page_cache_release(page);
+		} else {
+			page_cache_release(page);
+			return EXT_CONTINUE;
+		}
+	}
+
+	physical = (__u64)newex->ec_start << blksize_bits;
+	length =   (__u64)newex->ec_len << blksize_bits;
+
+	if (ex && ext4_ext_is_uninitialized(ex))
+		flags |= FIEMAP_EXTENT_UNWRITTEN;
+
+	/*
+	 * If this extent reaches EXT_MAX_BLOCK, it must be last.
+	 *
+	 * Or if ext4_ext_next_allocated_block is EXT_MAX_BLOCK,
+	 * this also indicates no more allocated blocks.
+	 *
+	 * XXX this might miss a single-block extent at EXT_MAX_BLOCK
+	 */
+	if (logical + length - 1 == EXT_MAX_BLOCK ||
+	    ext4_ext_next_allocated_block(path) == EXT_MAX_BLOCK)
+		flags |= FIEMAP_EXTENT_LAST;
+
+	error = fiemap_fill_next_extent(fieinfo, logical, physical,
+					length, flags);
+	if (error < 0)
+		return error;
+	if (error == 1)
+		return EXT_BREAK;
+
+	return EXT_CONTINUE;
+}
+
+/* fiemap flags we can handle specified here */
+#define EXT4_FIEMAP_FLAGS	(FIEMAP_FLAG_SYNC|FIEMAP_FLAG_XATTR)
+
+int ext4_xattr_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo)
+{
+	__u64 physical = 0;
+	__u64 length;
+	__u32 flags = FIEMAP_EXTENT_LAST;
+	int blockbits = inode->i_sb->s_blocksize_bits;
+	int error = 0;
+
+	/* in-inode? */
+	if (EXT4_I(inode)->i_state & EXT4_STATE_XATTR) {
+		struct ext4_iloc iloc;
+		int offset;	/* offset of xattr in inode */
+
+		error = ext4_get_inode_loc(inode, &iloc);
+		if (error)
+			return error;
+		physical = iloc.bh->b_blocknr << blockbits;
+		offset = EXT4_GOOD_OLD_INODE_SIZE +
+				EXT4_I(inode)->i_extra_isize;
+		physical += offset;
+		length = EXT4_SB(inode->i_sb)->s_inode_size - offset;
+		flags |= FIEMAP_EXTENT_DATA_INLINE;
+	} else { /* external block */
+		physical = EXT4_I(inode)->i_file_acl << blockbits;
+		length = inode->i_sb->s_blocksize;
+	}
+
+	if (physical)
+		error = fiemap_fill_next_extent(fieinfo, 0, physical,
+						length, flags);
+	return (error < 0 ? error : 0);
+}
+
+int ext4_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
+		__u64 start, __u64 len)
+{
+	ext4_lblk_t start_blk;
+	ext4_lblk_t len_blks;
+	int error = 0;
+
+	/* fallback to generic here if not in extents fmt */
+	if (!(EXT4_I(inode)->i_flags & EXT4_EXTENTS_FL))
+		return generic_block_fiemap(inode, fieinfo, start, len,
+			ext4_get_block);
+
+	if (fiemap_check_flags(fieinfo, EXT4_FIEMAP_FLAGS))
+		return -EBADR;
+
+	if (fieinfo->fi_flags & FIEMAP_FLAG_XATTR) {
+		error = ext4_xattr_fiemap(inode, fieinfo);
+	} else {
+		start_blk = start >> inode->i_sb->s_blocksize_bits;
+		len_blks = len >> inode->i_sb->s_blocksize_bits;
+
+		/*
+		 * Walk the extent tree gathering extent information.
+		 * ext4_ext_fiemap_cb will push extents back to user.
+		 */
+		down_write(&EXT4_I(inode)->i_data_sem);
+		error = ext4_ext_walk_space(inode, start_blk, len_blks,
+					  ext4_ext_fiemap_cb, fieinfo);
+		up_write(&EXT4_I(inode)->i_data_sem);
+	}
+
+	return error;
+}
+
diff --git a/fs/ext4/file.c b/fs/ext4/file.c
index 430eb79..6bd11fb 100644
--- a/fs/ext4/file.c
+++ b/fs/ext4/file.c
@@ -31,14 +31,14 @@
  * from ext4_file_open: open gets called at every open, but release
  * gets called only when /all/ the files are closed.
  */
-static int ext4_release_file (struct inode * inode, struct file * filp)
+static int ext4_release_file(struct inode *inode, struct file *filp)
 {
 	/* if we are the last writer on the inode, drop the block reservation */
 	if ((filp->f_mode & FMODE_WRITE) &&
 			(atomic_read(&inode->i_writecount) == 1))
 	{
 		down_write(&EXT4_I(inode)->i_data_sem);
-		ext4_discard_reservation(inode);
+		ext4_discard_preallocations(inode);
 		up_write(&EXT4_I(inode)->i_data_sem);
 	}
 	if (is_dx(inode) && filp->private_data)
@@ -140,6 +140,9 @@
 	return 0;
 }
 
+extern int ext4_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
+		__u64 start, __u64 len);
+
 const struct file_operations ext4_file_operations = {
 	.llseek		= generic_file_llseek,
 	.read		= do_sync_read,
@@ -162,7 +165,7 @@
 	.truncate	= ext4_truncate,
 	.setattr	= ext4_setattr,
 	.getattr	= ext4_getattr,
-#ifdef CONFIG_EXT4DEV_FS_XATTR
+#ifdef CONFIG_EXT4_FS_XATTR
 	.setxattr	= generic_setxattr,
 	.getxattr	= generic_getxattr,
 	.listxattr	= ext4_listxattr,
@@ -170,5 +173,6 @@
 #endif
 	.permission	= ext4_permission,
 	.fallocate	= ext4_fallocate,
+	.fiemap		= ext4_fiemap,
 };
 
diff --git a/fs/ext4/fsync.c b/fs/ext4/fsync.c
index a45c373..5afe437 100644
--- a/fs/ext4/fsync.c
+++ b/fs/ext4/fsync.c
@@ -28,6 +28,7 @@
 #include <linux/writeback.h>
 #include <linux/jbd2.h>
 #include <linux/blkdev.h>
+#include <linux/marker.h>
 #include "ext4.h"
 #include "ext4_jbd2.h"
 
@@ -43,7 +44,7 @@
  * inode to disk.
  */
 
-int ext4_sync_file(struct file * file, struct dentry *dentry, int datasync)
+int ext4_sync_file(struct file *file, struct dentry *dentry, int datasync)
 {
 	struct inode *inode = dentry->d_inode;
 	journal_t *journal = EXT4_SB(inode->i_sb)->s_journal;
@@ -51,6 +52,10 @@
 
 	J_ASSERT(ext4_journal_current_handle() == NULL);
 
+	trace_mark(ext4_sync_file, "dev %s datasync %d ino %ld parent %ld",
+		   inode->i_sb->s_id, datasync, inode->i_ino,
+		   dentry->d_parent->d_inode->i_ino);
+
 	/*
 	 * data=writeback:
 	 *  The caller's filemap_fdatawrite()/wait will sync the data.
diff --git a/fs/ext4/hash.c b/fs/ext4/hash.c
index 1d6329d..556ca8e 100644
--- a/fs/ext4/hash.c
+++ b/fs/ext4/hash.c
@@ -27,7 +27,7 @@
 		sum += DELTA;
 		b0 += ((b1 << 4)+a) ^ (b1+sum) ^ ((b1 >> 5)+b);
 		b1 += ((b0 << 4)+c) ^ (b0+sum) ^ ((b0 >> 5)+d);
-	} while(--n);
+	} while (--n);
 
 	buf[0] += b0;
 	buf[1] += b1;
@@ -35,7 +35,7 @@
 
 
 /* The old legacy hash */
-static __u32 dx_hack_hash (const char *name, int len)
+static __u32 dx_hack_hash(const char *name, int len)
 {
 	__u32 hash0 = 0x12a3fe2d, hash1 = 0x37abe8f9;
 	while (len--) {
@@ -59,7 +59,7 @@
 	val = pad;
 	if (len > num*4)
 		len = num * 4;
-	for (i=0; i < len; i++) {
+	for (i = 0; i < len; i++) {
 		if ((i % 4) == 0)
 			val = pad;
 		val = msg[i] + (val << 8);
@@ -104,7 +104,7 @@
 
 	/* Check to see if the seed is all zero's */
 	if (hinfo->seed) {
-		for (i=0; i < 4; i++) {
+		for (i = 0; i < 4; i++) {
 			if (hinfo->seed[i])
 				break;
 		}
diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c
index f344834..fe34d74 100644
--- a/fs/ext4/ialloc.c
+++ b/fs/ext4/ialloc.c
@@ -115,9 +115,11 @@
 			    block_group, bitmap_blk);
 		return NULL;
 	}
-	if (bh_uptodate_or_lock(bh))
+	if (buffer_uptodate(bh) &&
+	    !(desc->bg_flags & cpu_to_le16(EXT4_BG_INODE_UNINIT)))
 		return bh;
 
+	lock_buffer(bh);
 	spin_lock(sb_bgl_lock(EXT4_SB(sb), block_group));
 	if (desc->bg_flags & cpu_to_le16(EXT4_BG_INODE_UNINIT)) {
 		ext4_init_inode_bitmap(sb, bh, block_group, desc);
@@ -154,39 +156,40 @@
  * though), and then we'd have two inodes sharing the
  * same inode number and space on the harddisk.
  */
-void ext4_free_inode (handle_t *handle, struct inode * inode)
+void ext4_free_inode(handle_t *handle, struct inode *inode)
 {
-	struct super_block * sb = inode->i_sb;
+	struct super_block *sb = inode->i_sb;
 	int is_directory;
 	unsigned long ino;
 	struct buffer_head *bitmap_bh = NULL;
 	struct buffer_head *bh2;
 	ext4_group_t block_group;
 	unsigned long bit;
-	struct ext4_group_desc * gdp;
-	struct ext4_super_block * es;
+	struct ext4_group_desc *gdp;
+	struct ext4_super_block *es;
 	struct ext4_sb_info *sbi;
 	int fatal = 0, err;
 	ext4_group_t flex_group;
 
 	if (atomic_read(&inode->i_count) > 1) {
-		printk ("ext4_free_inode: inode has count=%d\n",
-					atomic_read(&inode->i_count));
+		printk(KERN_ERR "ext4_free_inode: inode has count=%d\n",
+		       atomic_read(&inode->i_count));
 		return;
 	}
 	if (inode->i_nlink) {
-		printk ("ext4_free_inode: inode has nlink=%d\n",
-			inode->i_nlink);
+		printk(KERN_ERR "ext4_free_inode: inode has nlink=%d\n",
+		       inode->i_nlink);
 		return;
 	}
 	if (!sb) {
-		printk("ext4_free_inode: inode on nonexistent device\n");
+		printk(KERN_ERR "ext4_free_inode: inode on "
+		       "nonexistent device\n");
 		return;
 	}
 	sbi = EXT4_SB(sb);
 
 	ino = inode->i_ino;
-	ext4_debug ("freeing inode %lu\n", ino);
+	ext4_debug("freeing inode %lu\n", ino);
 
 	/*
 	 * Note: we must free any quota before locking the superblock,
@@ -200,12 +203,12 @@
 	is_directory = S_ISDIR(inode->i_mode);
 
 	/* Do this BEFORE marking the inode not in use or returning an error */
-	clear_inode (inode);
+	clear_inode(inode);
 
 	es = EXT4_SB(sb)->s_es;
 	if (ino < EXT4_FIRST_INO(sb) || ino > le32_to_cpu(es->s_inodes_count)) {
-		ext4_error (sb, "ext4_free_inode",
-			    "reserved or nonexistent inode %lu", ino);
+		ext4_error(sb, "ext4_free_inode",
+			   "reserved or nonexistent inode %lu", ino);
 		goto error_return;
 	}
 	block_group = (ino - 1) / EXT4_INODES_PER_GROUP(sb);
@@ -222,10 +225,10 @@
 	/* Ok, now we can actually update the inode bitmaps.. */
 	if (!ext4_clear_bit_atomic(sb_bgl_lock(sbi, block_group),
 					bit, bitmap_bh->b_data))
-		ext4_error (sb, "ext4_free_inode",
-			      "bit already cleared for inode %lu", ino);
+		ext4_error(sb, "ext4_free_inode",
+			   "bit already cleared for inode %lu", ino);
 	else {
-		gdp = ext4_get_group_desc (sb, block_group, &bh2);
+		gdp = ext4_get_group_desc(sb, block_group, &bh2);
 
 		BUFFER_TRACE(bh2, "get_write_access");
 		fatal = ext4_journal_get_write_access(handle, bh2);
@@ -287,7 +290,7 @@
 	avefreei = freei / ngroups;
 
 	for (group = 0; group < ngroups; group++) {
-		desc = ext4_get_group_desc (sb, group, NULL);
+		desc = ext4_get_group_desc(sb, group, NULL);
 		if (!desc || !desc->bg_free_inodes_count)
 			continue;
 		if (le16_to_cpu(desc->bg_free_inodes_count) < avefreei)
@@ -576,16 +579,16 @@
  * For other inodes, search forward from the parent directory's block
  * group to find a free inode.
  */
-struct inode *ext4_new_inode(handle_t *handle, struct inode * dir, int mode)
+struct inode *ext4_new_inode(handle_t *handle, struct inode *dir, int mode)
 {
 	struct super_block *sb;
 	struct buffer_head *bitmap_bh = NULL;
 	struct buffer_head *bh2;
 	ext4_group_t group = 0;
 	unsigned long ino = 0;
-	struct inode * inode;
-	struct ext4_group_desc * gdp = NULL;
-	struct ext4_super_block * es;
+	struct inode *inode;
+	struct ext4_group_desc *gdp = NULL;
+	struct ext4_super_block *es;
 	struct ext4_inode_info *ei;
 	struct ext4_sb_info *sbi;
 	int ret2, err = 0;
@@ -613,7 +616,7 @@
 	}
 
 	if (S_ISDIR(mode)) {
-		if (test_opt (sb, OLDALLOC))
+		if (test_opt(sb, OLDALLOC))
 			ret2 = find_group_dir(sb, dir, &group);
 		else
 			ret2 = find_group_orlov(sb, dir, &group);
@@ -783,7 +786,7 @@
 	}
 
 	inode->i_uid = current->fsuid;
-	if (test_opt (sb, GRPID))
+	if (test_opt(sb, GRPID))
 		inode->i_gid = dir->i_gid;
 	else if (dir->i_mode & S_ISGID) {
 		inode->i_gid = dir->i_gid;
@@ -816,7 +819,6 @@
 		ei->i_flags &= ~EXT4_DIRSYNC_FL;
 	ei->i_file_acl = 0;
 	ei->i_dtime = 0;
-	ei->i_block_alloc_info = NULL;
 	ei->i_block_group = group;
 
 	ext4_set_inode_flags(inode);
@@ -832,7 +834,7 @@
 	ei->i_extra_isize = EXT4_SB(sb)->s_want_extra_isize;
 
 	ret = inode;
-	if(DQUOT_ALLOC_INODE(inode)) {
+	if (DQUOT_ALLOC_INODE(inode)) {
 		err = -EDQUOT;
 		goto fail_drop;
 	}
@@ -841,7 +843,7 @@
 	if (err)
 		goto fail_free_drop;
 
-	err = ext4_init_security(handle,inode, dir);
+	err = ext4_init_security(handle, inode, dir);
 	if (err)
 		goto fail_free_drop;
 
@@ -959,7 +961,7 @@
 	return ERR_PTR(err);
 }
 
-unsigned long ext4_count_free_inodes (struct super_block * sb)
+unsigned long ext4_count_free_inodes(struct super_block *sb)
 {
 	unsigned long desc_count;
 	struct ext4_group_desc *gdp;
@@ -974,7 +976,7 @@
 	bitmap_count = 0;
 	gdp = NULL;
 	for (i = 0; i < EXT4_SB(sb)->s_groups_count; i++) {
-		gdp = ext4_get_group_desc (sb, i, NULL);
+		gdp = ext4_get_group_desc(sb, i, NULL);
 		if (!gdp)
 			continue;
 		desc_count += le16_to_cpu(gdp->bg_free_inodes_count);
@@ -989,13 +991,14 @@
 		bitmap_count += x;
 	}
 	brelse(bitmap_bh);
-	printk("ext4_count_free_inodes: stored = %u, computed = %lu, %lu\n",
-		le32_to_cpu(es->s_free_inodes_count), desc_count, bitmap_count);
+	printk(KERN_DEBUG "ext4_count_free_inodes: "
+	       "stored = %u, computed = %lu, %lu\n",
+	       le32_to_cpu(es->s_free_inodes_count), desc_count, bitmap_count);
 	return desc_count;
 #else
 	desc_count = 0;
 	for (i = 0; i < EXT4_SB(sb)->s_groups_count; i++) {
-		gdp = ext4_get_group_desc (sb, i, NULL);
+		gdp = ext4_get_group_desc(sb, i, NULL);
 		if (!gdp)
 			continue;
 		desc_count += le16_to_cpu(gdp->bg_free_inodes_count);
@@ -1006,13 +1009,13 @@
 }
 
 /* Called at mount-time, super-block is locked */
-unsigned long ext4_count_dirs (struct super_block * sb)
+unsigned long ext4_count_dirs(struct super_block * sb)
 {
 	unsigned long count = 0;
 	ext4_group_t i;
 
 	for (i = 0; i < EXT4_SB(sb)->s_groups_count; i++) {
-		struct ext4_group_desc *gdp = ext4_get_group_desc (sb, i, NULL);
+		struct ext4_group_desc *gdp = ext4_get_group_desc(sb, i, NULL);
 		if (!gdp)
 			continue;
 		count += le16_to_cpu(gdp->bg_used_dirs_count);
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index 7e91913e..9b4ec9d 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -190,7 +190,7 @@
 /*
  * Called at the last iput() if i_nlink is zero.
  */
-void ext4_delete_inode (struct inode * inode)
+void ext4_delete_inode(struct inode *inode)
 {
 	handle_t *handle;
 	int err;
@@ -330,11 +330,11 @@
 	int final = 0;
 
 	if (i_block < 0) {
-		ext4_warning (inode->i_sb, "ext4_block_to_path", "block < 0");
+		ext4_warning(inode->i_sb, "ext4_block_to_path", "block < 0");
 	} else if (i_block < direct_blocks) {
 		offsets[n++] = i_block;
 		final = direct_blocks;
-	} else if ( (i_block -= direct_blocks) < indirect_blocks) {
+	} else if ((i_block -= direct_blocks) < indirect_blocks) {
 		offsets[n++] = EXT4_IND_BLOCK;
 		offsets[n++] = i_block;
 		final = ptrs;
@@ -400,14 +400,14 @@
 
 	*err = 0;
 	/* i_data is not going away, no lock needed */
-	add_chain (chain, NULL, EXT4_I(inode)->i_data + *offsets);
+	add_chain(chain, NULL, EXT4_I(inode)->i_data + *offsets);
 	if (!p->key)
 		goto no_block;
 	while (--depth) {
 		bh = sb_bread(sb, le32_to_cpu(p->key));
 		if (!bh)
 			goto failure;
-		add_chain(++p, bh, (__le32*)bh->b_data + *++offsets);
+		add_chain(++p, bh, (__le32 *)bh->b_data + *++offsets);
 		/* Reader: end */
 		if (!p->key)
 			goto no_block;
@@ -443,7 +443,7 @@
 static ext4_fsblk_t ext4_find_near(struct inode *inode, Indirect *ind)
 {
 	struct ext4_inode_info *ei = EXT4_I(inode);
-	__le32 *start = ind->bh ? (__le32*) ind->bh->b_data : ei->i_data;
+	__le32 *start = ind->bh ? (__le32 *) ind->bh->b_data : ei->i_data;
 	__le32 *p;
 	ext4_fsblk_t bg_start;
 	ext4_fsblk_t last_block;
@@ -486,18 +486,9 @@
 static ext4_fsblk_t ext4_find_goal(struct inode *inode, ext4_lblk_t block,
 		Indirect *partial)
 {
-	struct ext4_block_alloc_info *block_i;
-
-	block_i =  EXT4_I(inode)->i_block_alloc_info;
-
 	/*
-	 * try the heuristic for sequential allocation,
-	 * failing that at least try to get decent locality.
+	 * XXX need to get goal block from mballoc's data structures
 	 */
-	if (block_i && (block == block_i->last_alloc_logical_block + 1)
-		&& (block_i->last_alloc_physical_block != 0)) {
-		return block_i->last_alloc_physical_block + 1;
-	}
 
 	return ext4_find_near(inode, partial);
 }
@@ -630,7 +621,7 @@
 	*err = 0;
 	return ret;
 failed_out:
-	for (i = 0; i <index; i++)
+	for (i = 0; i < index; i++)
 		ext4_free_blocks(handle, inode, new_blocks[i], 1, 0);
 	return ret;
 }
@@ -703,7 +694,7 @@
 		branch[n].p = (__le32 *) bh->b_data + offsets[n];
 		branch[n].key = cpu_to_le32(new_blocks[n]);
 		*branch[n].p = branch[n].key;
-		if ( n == indirect_blks) {
+		if (n == indirect_blks) {
 			current_block = new_blocks[n];
 			/*
 			 * End of chain, update the last new metablock of
@@ -730,7 +721,7 @@
 		BUFFER_TRACE(branch[i].bh, "call jbd2_journal_forget");
 		ext4_journal_forget(handle, branch[i].bh);
 	}
-	for (i = 0; i <indirect_blks; i++)
+	for (i = 0; i < indirect_blks; i++)
 		ext4_free_blocks(handle, inode, new_blocks[i], 1, 0);
 
 	ext4_free_blocks(handle, inode, new_blocks[i], num, 0);
@@ -757,10 +748,8 @@
 {
 	int i;
 	int err = 0;
-	struct ext4_block_alloc_info *block_i;
 	ext4_fsblk_t current_block;
 
-	block_i = EXT4_I(inode)->i_block_alloc_info;
 	/*
 	 * If we're splicing into a [td]indirect block (as opposed to the
 	 * inode) then we need to get write access to the [td]indirect block
@@ -783,18 +772,7 @@
 	if (num == 0 && blks > 1) {
 		current_block = le32_to_cpu(where->key) + 1;
 		for (i = 1; i < blks; i++)
-			*(where->p + i ) = cpu_to_le32(current_block++);
-	}
-
-	/*
-	 * update the most recently allocated logical & physical block
-	 * in i_block_alloc_info, to assist find the proper goal block for next
-	 * allocation
-	 */
-	if (block_i) {
-		block_i->last_alloc_logical_block = block + blks - 1;
-		block_i->last_alloc_physical_block =
-				le32_to_cpu(where[num].key) + blks - 1;
+			*(where->p + i) = cpu_to_le32(current_block++);
 	}
 
 	/* We are done with atomic stuff, now do the rest of housekeeping */
@@ -914,12 +892,8 @@
 		goto cleanup;
 
 	/*
-	 * Okay, we need to do block allocation.  Lazily initialize the block
-	 * allocation info here if necessary
+	 * Okay, we need to do block allocation.
 	*/
-	if (S_ISREG(inode->i_mode) && (!ei->i_block_alloc_info))
-		ext4_init_block_alloc_info(inode);
-
 	goal = ext4_find_goal(inode, iblock, partial);
 
 	/* the number of blocks need to allocate for [d,t]indirect blocks */
@@ -1030,19 +1004,20 @@
 	BUG_ON(mdb > EXT4_I(inode)->i_reserved_meta_blocks);
 	mdb_free = EXT4_I(inode)->i_reserved_meta_blocks - mdb;
 
-	/* Account for allocated meta_blocks */
-	mdb_free -= EXT4_I(inode)->i_allocated_meta_blocks;
+	if (mdb_free) {
+		/* Account for allocated meta_blocks */
+		mdb_free -= EXT4_I(inode)->i_allocated_meta_blocks;
 
-	/* update fs free blocks counter for truncate case */
-	percpu_counter_add(&sbi->s_freeblocks_counter, mdb_free);
+		/* update fs dirty blocks counter */
+		percpu_counter_sub(&sbi->s_dirtyblocks_counter, mdb_free);
+		EXT4_I(inode)->i_allocated_meta_blocks = 0;
+		EXT4_I(inode)->i_reserved_meta_blocks = mdb;
+	}
 
 	/* update per-inode reservations */
 	BUG_ON(used  > EXT4_I(inode)->i_reserved_data_blocks);
 	EXT4_I(inode)->i_reserved_data_blocks -= used;
 
-	BUG_ON(mdb > EXT4_I(inode)->i_reserved_meta_blocks);
-	EXT4_I(inode)->i_reserved_meta_blocks = mdb;
-	EXT4_I(inode)->i_allocated_meta_blocks = 0;
 	spin_unlock(&EXT4_I(inode)->i_block_reservation_lock);
 }
 
@@ -1160,8 +1135,8 @@
 /* Maximum number of blocks we map for direct IO at once. */
 #define DIO_MAX_BLOCKS 4096
 
-static int ext4_get_block(struct inode *inode, sector_t iblock,
-			struct buffer_head *bh_result, int create)
+int ext4_get_block(struct inode *inode, sector_t iblock,
+		   struct buffer_head *bh_result, int create)
 {
 	handle_t *handle = ext4_journal_current_handle();
 	int ret = 0, started = 0;
@@ -1241,7 +1216,7 @@
 			BUFFER_TRACE(bh, "call get_create_access");
 			fatal = ext4_journal_get_create_access(handle, bh);
 			if (!fatal && !buffer_uptodate(bh)) {
-				memset(bh->b_data,0,inode->i_sb->s_blocksize);
+				memset(bh->b_data, 0, inode->i_sb->s_blocksize);
 				set_buffer_uptodate(bh);
 			}
 			unlock_buffer(bh);
@@ -1266,7 +1241,7 @@
 struct buffer_head *ext4_bread(handle_t *handle, struct inode *inode,
 			       ext4_lblk_t block, int create, int *err)
 {
-	struct buffer_head * bh;
+	struct buffer_head *bh;
 
 	bh = ext4_getblk(handle, inode, block, create, err);
 	if (!bh)
@@ -1282,13 +1257,13 @@
 	return NULL;
 }
 
-static int walk_page_buffers(	handle_t *handle,
-				struct buffer_head *head,
-				unsigned from,
-				unsigned to,
-				int *partial,
-				int (*fn)(	handle_t *handle,
-						struct buffer_head *bh))
+static int walk_page_buffers(handle_t *handle,
+			     struct buffer_head *head,
+			     unsigned from,
+			     unsigned to,
+			     int *partial,
+			     int (*fn)(handle_t *handle,
+				       struct buffer_head *bh))
 {
 	struct buffer_head *bh;
 	unsigned block_start, block_end;
@@ -1296,9 +1271,9 @@
 	int err, ret = 0;
 	struct buffer_head *next;
 
-	for (	bh = head, block_start = 0;
-		ret == 0 && (bh != head || !block_start);
-		block_start = block_end, bh = next)
+	for (bh = head, block_start = 0;
+	     ret == 0 && (bh != head || !block_start);
+	     block_start = block_end, bh = next)
 	{
 		next = bh->b_this_page;
 		block_end = block_start + blocksize;
@@ -1351,23 +1326,23 @@
 				loff_t pos, unsigned len, unsigned flags,
 				struct page **pagep, void **fsdata)
 {
- 	struct inode *inode = mapping->host;
+	struct inode *inode = mapping->host;
 	int ret, needed_blocks = ext4_writepage_trans_blocks(inode);
 	handle_t *handle;
 	int retries = 0;
- 	struct page *page;
+	struct page *page;
  	pgoff_t index;
- 	unsigned from, to;
+	unsigned from, to;
 
  	index = pos >> PAGE_CACHE_SHIFT;
- 	from = pos & (PAGE_CACHE_SIZE - 1);
- 	to = from + len;
+	from = pos & (PAGE_CACHE_SIZE - 1);
+	to = from + len;
 
 retry:
-  	handle = ext4_journal_start(inode, needed_blocks);
-  	if (IS_ERR(handle)) {
-  		ret = PTR_ERR(handle);
-  		goto out;
+	handle = ext4_journal_start(inode, needed_blocks);
+	if (IS_ERR(handle)) {
+		ret = PTR_ERR(handle);
+		goto out;
 	}
 
 	page = __grab_cache_page(mapping, index);
@@ -1387,9 +1362,16 @@
 	}
 
 	if (ret) {
- 		unlock_page(page);
+		unlock_page(page);
 		ext4_journal_stop(handle);
- 		page_cache_release(page);
+		page_cache_release(page);
+		/*
+		 * block_write_begin may have instantiated a few blocks
+		 * outside i_size.  Trim these off again. Don't need
+		 * i_size_read because we hold i_mutex.
+		 */
+		if (pos + len > inode->i_size)
+			vmtruncate(inode, inode->i_size);
 	}
 
 	if (ret == -ENOSPC && ext4_should_retry_alloc(inode->i_sb, &retries))
@@ -1426,16 +1408,18 @@
 	ret = ext4_jbd2_file_inode(handle, inode);
 
 	if (ret == 0) {
-		/*
-		 * generic_write_end() will run mark_inode_dirty() if i_size
-		 * changes.  So let's piggyback the i_disksize mark_inode_dirty
-		 * into that.
-		 */
 		loff_t new_i_size;
 
 		new_i_size = pos + copied;
-		if (new_i_size > EXT4_I(inode)->i_disksize)
-			EXT4_I(inode)->i_disksize = new_i_size;
+		if (new_i_size > EXT4_I(inode)->i_disksize) {
+			ext4_update_i_disksize(inode, new_i_size);
+			/* We need to mark inode dirty even if
+			 * new_i_size is less that inode->i_size
+			 * bu greater than i_disksize.(hint delalloc)
+			 */
+			ext4_mark_inode_dirty(handle, inode);
+		}
+
 		ret2 = generic_write_end(file, mapping, pos, len, copied,
 							page, fsdata);
 		copied = ret2;
@@ -1460,8 +1444,14 @@
 	loff_t new_i_size;
 
 	new_i_size = pos + copied;
-	if (new_i_size > EXT4_I(inode)->i_disksize)
-		EXT4_I(inode)->i_disksize = new_i_size;
+	if (new_i_size > EXT4_I(inode)->i_disksize) {
+		ext4_update_i_disksize(inode, new_i_size);
+		/* We need to mark inode dirty even if
+		 * new_i_size is less that inode->i_size
+		 * bu greater than i_disksize.(hint delalloc)
+		 */
+		ext4_mark_inode_dirty(handle, inode);
+	}
 
 	ret2 = generic_write_end(file, mapping, pos, len, copied,
 							page, fsdata);
@@ -1486,6 +1476,7 @@
 	int ret = 0, ret2;
 	int partial = 0;
 	unsigned from, to;
+	loff_t new_i_size;
 
 	from = pos & (PAGE_CACHE_SIZE - 1);
 	to = from + len;
@@ -1500,11 +1491,12 @@
 				to, &partial, write_end_fn);
 	if (!partial)
 		SetPageUptodate(page);
-	if (pos+copied > inode->i_size)
+	new_i_size = pos + copied;
+	if (new_i_size > inode->i_size)
 		i_size_write(inode, pos+copied);
 	EXT4_I(inode)->i_state |= EXT4_STATE_JDATA;
-	if (inode->i_size > EXT4_I(inode)->i_disksize) {
-		EXT4_I(inode)->i_disksize = inode->i_size;
+	if (new_i_size > EXT4_I(inode)->i_disksize) {
+		ext4_update_i_disksize(inode, new_i_size);
 		ret2 = ext4_mark_inode_dirty(handle, inode);
 		if (!ret)
 			ret = ret2;
@@ -1521,6 +1513,7 @@
 
 static int ext4_da_reserve_space(struct inode *inode, int nrblocks)
 {
+	int retries = 0;
        struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
        unsigned long md_needed, mdblocks, total = 0;
 
@@ -1529,6 +1522,7 @@
 	 * in order to allocate nrblocks
 	 * worse case is one extent per block
 	 */
+repeat:
 	spin_lock(&EXT4_I(inode)->i_block_reservation_lock);
 	total = EXT4_I(inode)->i_reserved_data_blocks + nrblocks;
 	mdblocks = ext4_calc_metadata_amount(inode, total);
@@ -1537,13 +1531,14 @@
 	md_needed = mdblocks - EXT4_I(inode)->i_reserved_meta_blocks;
 	total = md_needed + nrblocks;
 
-	if (ext4_has_free_blocks(sbi, total) < total) {
+	if (ext4_claim_free_blocks(sbi, total)) {
 		spin_unlock(&EXT4_I(inode)->i_block_reservation_lock);
+		if (ext4_should_retry_alloc(inode->i_sb, &retries)) {
+			yield();
+			goto repeat;
+		}
 		return -ENOSPC;
 	}
-	/* reduce fs free blocks counter */
-	percpu_counter_sub(&sbi->s_freeblocks_counter, total);
-
 	EXT4_I(inode)->i_reserved_data_blocks += nrblocks;
 	EXT4_I(inode)->i_reserved_meta_blocks = mdblocks;
 
@@ -1585,8 +1580,8 @@
 
 	release = to_free + mdb_free;
 
-	/* update fs free blocks counter for truncate case */
-	percpu_counter_add(&sbi->s_freeblocks_counter, release);
+	/* update fs dirty blocks counter for truncate case */
+	percpu_counter_sub(&sbi->s_dirtyblocks_counter, release);
 
 	/* update per-inode reservations */
 	BUG_ON(to_free > EXT4_I(inode)->i_reserved_data_blocks);
@@ -1630,6 +1625,7 @@
 	struct writeback_control *wbc;
 	int io_done;
 	long pages_written;
+	int retval;
 };
 
 /*
@@ -1783,6 +1779,57 @@
 		unmap_underlying_metadata(bdev, bh->b_blocknr + i);
 }
 
+static void ext4_da_block_invalidatepages(struct mpage_da_data *mpd,
+					sector_t logical, long blk_cnt)
+{
+	int nr_pages, i;
+	pgoff_t index, end;
+	struct pagevec pvec;
+	struct inode *inode = mpd->inode;
+	struct address_space *mapping = inode->i_mapping;
+
+	index = logical >> (PAGE_CACHE_SHIFT - inode->i_blkbits);
+	end   = (logical + blk_cnt - 1) >>
+				(PAGE_CACHE_SHIFT - inode->i_blkbits);
+	while (index <= end) {
+		nr_pages = pagevec_lookup(&pvec, mapping, index, PAGEVEC_SIZE);
+		if (nr_pages == 0)
+			break;
+		for (i = 0; i < nr_pages; i++) {
+			struct page *page = pvec.pages[i];
+			index = page->index;
+			if (index > end)
+				break;
+			index++;
+
+			BUG_ON(!PageLocked(page));
+			BUG_ON(PageWriteback(page));
+			block_invalidatepage(page, 0);
+			ClearPageUptodate(page);
+			unlock_page(page);
+		}
+	}
+	return;
+}
+
+static void ext4_print_free_blocks(struct inode *inode)
+{
+	struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
+	printk(KERN_EMERG "Total free blocks count %lld\n",
+			ext4_count_free_blocks(inode->i_sb));
+	printk(KERN_EMERG "Free/Dirty block details\n");
+	printk(KERN_EMERG "free_blocks=%lld\n",
+			percpu_counter_sum(&sbi->s_freeblocks_counter));
+	printk(KERN_EMERG "dirty_blocks=%lld\n",
+			percpu_counter_sum(&sbi->s_dirtyblocks_counter));
+	printk(KERN_EMERG "Block reservation details\n");
+	printk(KERN_EMERG "i_reserved_data_blocks=%lu\n",
+			EXT4_I(inode)->i_reserved_data_blocks);
+	printk(KERN_EMERG "i_reserved_meta_blocks=%lu\n",
+			EXT4_I(inode)->i_reserved_meta_blocks);
+	return;
+}
+
 /*
  * mpage_da_map_blocks - go through given space
  *
@@ -1792,32 +1839,69 @@
  * The function skips space we know is already mapped to disk blocks.
  *
  */
-static void mpage_da_map_blocks(struct mpage_da_data *mpd)
+static int  mpage_da_map_blocks(struct mpage_da_data *mpd)
 {
 	int err = 0;
-	struct buffer_head *lbh = &mpd->lbh;
-	sector_t next = lbh->b_blocknr;
 	struct buffer_head new;
+	struct buffer_head *lbh = &mpd->lbh;
+	sector_t next;
 
 	/*
 	 * We consider only non-mapped and non-allocated blocks
 	 */
 	if (buffer_mapped(lbh) && !buffer_delay(lbh))
-		return;
-
+		return 0;
 	new.b_state = lbh->b_state;
 	new.b_blocknr = 0;
 	new.b_size = lbh->b_size;
-
+	next = lbh->b_blocknr;
 	/*
 	 * If we didn't accumulate anything
 	 * to write simply return
 	 */
 	if (!new.b_size)
-		return;
+		return 0;
 	err = mpd->get_block(mpd->inode, next, &new, 1);
-	if (err)
-		return;
+	if (err) {
+
+		/* If get block returns with error
+		 * we simply return. Later writepage
+		 * will redirty the page and writepages
+		 * will find the dirty page again
+		 */
+		if (err == -EAGAIN)
+			return 0;
+
+		if (err == -ENOSPC &&
+				ext4_count_free_blocks(mpd->inode->i_sb)) {
+			mpd->retval = err;
+			return 0;
+		}
+
+		/*
+		 * get block failure will cause us
+		 * to loop in writepages. Because
+		 * a_ops->writepage won't be able to
+		 * make progress. The page will be redirtied
+		 * by writepage and writepages will again
+		 * try to write the same.
+		 */
+		printk(KERN_EMERG "%s block allocation failed for inode %lu "
+				  "at logical offset %llu with max blocks "
+				  "%zd with error %d\n",
+				  __func__, mpd->inode->i_ino,
+				  (unsigned long long)next,
+				  lbh->b_size >> mpd->inode->i_blkbits, err);
+		printk(KERN_EMERG "This should not happen.!! "
+					"Data will be lost\n");
+		if (err == -ENOSPC) {
+			ext4_print_free_blocks(mpd->inode);
+		}
+		/* invlaidate all the pages */
+		ext4_da_block_invalidatepages(mpd, next,
+				lbh->b_size >> mpd->inode->i_blkbits);
+		return err;
+	}
 	BUG_ON(new.b_size == 0);
 
 	if (buffer_new(&new))
@@ -1830,7 +1914,7 @@
 	if (buffer_delay(lbh) || buffer_unwritten(lbh))
 		mpage_put_bnr_to_bhs(mpd, next, &new);
 
-	return;
+	return 0;
 }
 
 #define BH_FLAGS ((1 << BH_Uptodate) | (1 << BH_Mapped) | \
@@ -1899,8 +1983,8 @@
 	 * We couldn't merge the block to our extent, so we
 	 * need to flush current  extent and start new one
 	 */
-	mpage_da_map_blocks(mpd);
-	mpage_da_submit_io(mpd);
+	if (mpage_da_map_blocks(mpd) == 0)
+		mpage_da_submit_io(mpd);
 	mpd->io_done = 1;
 	return;
 }
@@ -1942,8 +2026,8 @@
 		 * and start IO on them using writepage()
 		 */
 		if (mpd->next_page != mpd->first_page) {
-			mpage_da_map_blocks(mpd);
-			mpage_da_submit_io(mpd);
+			if (mpage_da_map_blocks(mpd) == 0)
+				mpage_da_submit_io(mpd);
 			/*
 			 * skip rest of the page in the page_vec
 			 */
@@ -2018,39 +2102,36 @@
  */
 static int mpage_da_writepages(struct address_space *mapping,
 			       struct writeback_control *wbc,
-			       get_block_t get_block)
+			       struct mpage_da_data *mpd)
 {
-	struct mpage_da_data mpd;
 	long to_write;
 	int ret;
 
-	if (!get_block)
+	if (!mpd->get_block)
 		return generic_writepages(mapping, wbc);
 
-	mpd.wbc = wbc;
-	mpd.inode = mapping->host;
-	mpd.lbh.b_size = 0;
-	mpd.lbh.b_state = 0;
-	mpd.lbh.b_blocknr = 0;
-	mpd.first_page = 0;
-	mpd.next_page = 0;
-	mpd.get_block = get_block;
-	mpd.io_done = 0;
-	mpd.pages_written = 0;
+	mpd->lbh.b_size = 0;
+	mpd->lbh.b_state = 0;
+	mpd->lbh.b_blocknr = 0;
+	mpd->first_page = 0;
+	mpd->next_page = 0;
+	mpd->io_done = 0;
+	mpd->pages_written = 0;
+	mpd->retval = 0;
 
 	to_write = wbc->nr_to_write;
 
-	ret = write_cache_pages(mapping, wbc, __mpage_da_writepage, &mpd);
+	ret = write_cache_pages(mapping, wbc, __mpage_da_writepage, mpd);
 
 	/*
 	 * Handle last extent of pages
 	 */
-	if (!mpd.io_done && mpd.next_page != mpd.first_page) {
-		mpage_da_map_blocks(&mpd);
-		mpage_da_submit_io(&mpd);
+	if (!mpd->io_done && mpd->next_page != mpd->first_page) {
+		if (mpage_da_map_blocks(mpd) == 0)
+			mpage_da_submit_io(mpd);
 	}
 
-	wbc->nr_to_write = to_write - mpd.pages_written;
+	wbc->nr_to_write = to_write - mpd->pages_written;
 	return ret;
 }
 
@@ -2103,18 +2184,24 @@
 	handle_t *handle = NULL;
 
 	handle = ext4_journal_current_handle();
-	if (!handle) {
-		ret = ext4_get_blocks_wrap(handle, inode, iblock, max_blocks,
-				   bh_result, 0, 0, 0);
-		BUG_ON(!ret);
-	} else {
-		ret = ext4_get_blocks_wrap(handle, inode, iblock, max_blocks,
-				   bh_result, create, 0, EXT4_DELALLOC_RSVED);
-	}
-
+	BUG_ON(!handle);
+	ret = ext4_get_blocks_wrap(handle, inode, iblock, max_blocks,
+			bh_result, create, 0, EXT4_DELALLOC_RSVED);
 	if (ret > 0) {
+
 		bh_result->b_size = (ret << inode->i_blkbits);
 
+		if (ext4_should_order_data(inode)) {
+			int retval;
+			retval = ext4_jbd2_file_inode(handle, inode);
+			if (retval)
+				/*
+				 * Failed to add inode for ordered
+				 * mode. Don't update file size
+				 */
+				return retval;
+		}
+
 		/*
 		 * Update on-disk size along with block allocation
 		 * we don't use 'extend_disksize' as size may change
@@ -2124,18 +2211,9 @@
 		if (disksize > i_size_read(inode))
 			disksize = i_size_read(inode);
 		if (disksize > EXT4_I(inode)->i_disksize) {
-			/*
-			 * XXX: replace with spinlock if seen contended -bzzz
-			 */
-			down_write(&EXT4_I(inode)->i_data_sem);
-			if (disksize > EXT4_I(inode)->i_disksize)
-				EXT4_I(inode)->i_disksize = disksize;
-			up_write(&EXT4_I(inode)->i_data_sem);
-
-			if (EXT4_I(inode)->i_disksize == disksize) {
-				ret = ext4_mark_inode_dirty(handle, inode);
-				return ret;
-			}
+			ext4_update_i_disksize(inode, disksize);
+			ret = ext4_mark_inode_dirty(handle, inode);
+			return ret;
 		}
 		ret = 0;
 	}
@@ -2284,6 +2362,7 @@
 {
 	handle_t *handle = NULL;
 	loff_t range_start = 0;
+	struct mpage_da_data mpd;
 	struct inode *inode = mapping->host;
 	int needed_blocks, ret = 0, nr_to_writebump = 0;
 	long to_write, pages_skipped = 0;
@@ -2317,6 +2396,9 @@
 	range_start =  wbc->range_start;
 	pages_skipped = wbc->pages_skipped;
 
+	mpd.wbc = wbc;
+	mpd.inode = mapping->host;
+
 restart_loop:
 	to_write = wbc->nr_to_write;
 	while (!ret && to_write > 0) {
@@ -2340,23 +2422,17 @@
 			dump_stack();
 			goto out_writepages;
 		}
-		if (ext4_should_order_data(inode)) {
-			/*
-			 * With ordered mode we need to add
-			 * the inode to the journal handl
-			 * when we do block allocation.
-			 */
-			ret = ext4_jbd2_file_inode(handle, inode);
-			if (ret) {
-				ext4_journal_stop(handle);
-				goto out_writepages;
-			}
-		}
-
 		to_write -= wbc->nr_to_write;
-		ret = mpage_da_writepages(mapping, wbc,
-					  ext4_da_get_block_write);
+
+		mpd.get_block = ext4_da_get_block_write;
+		ret = mpage_da_writepages(mapping, wbc, &mpd);
+
 		ext4_journal_stop(handle);
+
+		if (mpd.retval == -ENOSPC)
+			jbd2_journal_force_commit_nested(sbi->s_journal);
+
+		/* reset the retry count */
 		if (ret == MPAGE_DA_EXTENT_TAIL) {
 			/*
 			 * got one extent now try with
@@ -2391,6 +2467,33 @@
 	return ret;
 }
 
+#define FALL_BACK_TO_NONDELALLOC 1
+static int ext4_nonda_switch(struct super_block *sb)
+{
+	s64 free_blocks, dirty_blocks;
+	struct ext4_sb_info *sbi = EXT4_SB(sb);
+
+	/*
+	 * switch to non delalloc mode if we are running low
+	 * on free block. The free block accounting via percpu
+	 * counters can get slightly wrong with FBC_BATCH getting
+	 * accumulated on each CPU without updating global counters
+	 * Delalloc need an accurate free block accounting. So switch
+	 * to non delalloc when we are near to error range.
+	 */
+	free_blocks  = percpu_counter_read_positive(&sbi->s_freeblocks_counter);
+	dirty_blocks = percpu_counter_read_positive(&sbi->s_dirtyblocks_counter);
+	if (2 * free_blocks < 3 * dirty_blocks ||
+		free_blocks < (dirty_blocks + EXT4_FREEBLOCKS_WATERMARK)) {
+		/*
+		 * free block count is less that 150% of dirty blocks
+		 * or free blocks is less that watermark
+		 */
+		return 1;
+	}
+	return 0;
+}
+
 static int ext4_da_write_begin(struct file *file, struct address_space *mapping,
 				loff_t pos, unsigned len, unsigned flags,
 				struct page **pagep, void **fsdata)
@@ -2406,6 +2509,12 @@
 	from = pos & (PAGE_CACHE_SIZE - 1);
 	to = from + len;
 
+	if (ext4_nonda_switch(inode->i_sb)) {
+		*fsdata = (void *)FALL_BACK_TO_NONDELALLOC;
+		return ext4_write_begin(file, mapping, pos,
+					len, flags, pagep, fsdata);
+	}
+	*fsdata = (void *)0;
 retry:
 	/*
 	 * With delayed allocation, we don't log the i_disksize update
@@ -2433,6 +2542,13 @@
 		unlock_page(page);
 		ext4_journal_stop(handle);
 		page_cache_release(page);
+		/*
+		 * block_write_begin may have instantiated a few blocks
+		 * outside i_size.  Trim these off again. Don't need
+		 * i_size_read because we hold i_mutex.
+		 */
+		if (pos + len > inode->i_size)
+			vmtruncate(inode, inode->i_size);
 	}
 
 	if (ret == -ENOSPC && ext4_should_retry_alloc(inode->i_sb, &retries))
@@ -2456,7 +2572,7 @@
 	bh = page_buffers(page);
 	idx = offset >> inode->i_blkbits;
 
-	for (i=0; i < idx; i++)
+	for (i = 0; i < idx; i++)
 		bh = bh->b_this_page;
 
 	if (!buffer_mapped(bh) || (buffer_delay(bh)))
@@ -2474,9 +2590,22 @@
 	handle_t *handle = ext4_journal_current_handle();
 	loff_t new_i_size;
 	unsigned long start, end;
+	int write_mode = (int)(unsigned long)fsdata;
+
+	if (write_mode == FALL_BACK_TO_NONDELALLOC) {
+		if (ext4_should_order_data(inode)) {
+			return ext4_ordered_write_end(file, mapping, pos,
+					len, copied, page, fsdata);
+		} else if (ext4_should_writeback_data(inode)) {
+			return ext4_writeback_write_end(file, mapping, pos,
+					len, copied, page, fsdata);
+		} else {
+			BUG();
+		}
+	}
 
 	start = pos & (PAGE_CACHE_SIZE - 1);
-	end = start + copied -1;
+	end = start + copied - 1;
 
 	/*
 	 * generic_write_end() will run mark_inode_dirty() if i_size
@@ -2500,6 +2629,11 @@
 				EXT4_I(inode)->i_disksize = new_i_size;
 			}
 			up_write(&EXT4_I(inode)->i_data_sem);
+			/* We need to mark inode dirty even if
+			 * new_i_size is less that inode->i_size
+			 * bu greater than i_disksize.(hint delalloc)
+			 */
+			ext4_mark_inode_dirty(handle, inode);
 		}
 	}
 	ret2 = generic_write_end(file, mapping, pos, len, copied,
@@ -2591,7 +2725,7 @@
 			return 0;
 	}
 
-	return generic_block_bmap(mapping,block,ext4_get_block);
+	return generic_block_bmap(mapping, block, ext4_get_block);
 }
 
 static int bget_one(handle_t *handle, struct buffer_head *bh)
@@ -3197,7 +3331,7 @@
 	if (!partial->key && *partial->p)
 		/* Writer: end */
 		goto no_top;
-	for (p=partial; p>chain && all_zeroes((__le32*)p->bh->b_data,p->p); p--)
+	for (p = partial; (p > chain) && all_zeroes((__le32 *) p->bh->b_data, p->p); p--)
 		;
 	/*
 	 * OK, we've found the last block that must survive. The rest of our
@@ -3216,7 +3350,7 @@
 	}
 	/* Writer: end */
 
-	while(partial > p) {
+	while (partial > p) {
 		brelse(partial->bh);
 		partial--;
 	}
@@ -3408,9 +3542,9 @@
 			/* This zaps the entire block.  Bottom up. */
 			BUFFER_TRACE(bh, "free child branches");
 			ext4_free_branches(handle, inode, bh,
-					   (__le32*)bh->b_data,
-					   (__le32*)bh->b_data + addr_per_block,
-					   depth);
+					(__le32 *) bh->b_data,
+					(__le32 *) bh->b_data + addr_per_block,
+					depth);
 
 			/*
 			 * We've probably journalled the indirect block several
@@ -3578,7 +3712,7 @@
 	 */
 	down_write(&ei->i_data_sem);
 
-	ext4_discard_reservation(inode);
+	ext4_discard_preallocations(inode);
 
 	/*
 	 * The orphan list entry will now protect us from any crash which
@@ -3673,41 +3807,6 @@
 	ext4_journal_stop(handle);
 }
 
-static ext4_fsblk_t ext4_get_inode_block(struct super_block *sb,
-		unsigned long ino, struct ext4_iloc *iloc)
-{
-	ext4_group_t block_group;
-	unsigned long offset;
-	ext4_fsblk_t block;
-	struct ext4_group_desc *gdp;
-
-	if (!ext4_valid_inum(sb, ino)) {
-		/*
-		 * This error is already checked for in namei.c unless we are
-		 * looking at an NFS filehandle, in which case no error
-		 * report is needed
-		 */
-		return 0;
-	}
-
-	block_group = (ino - 1) / EXT4_INODES_PER_GROUP(sb);
-	gdp = ext4_get_group_desc(sb, block_group, NULL);
-	if (!gdp)
-		return 0;
-
-	/*
-	 * Figure out the offset within the block group inode table
-	 */
-	offset = ((ino - 1) % EXT4_INODES_PER_GROUP(sb)) *
-		EXT4_INODE_SIZE(sb);
-	block = ext4_inode_table(sb, gdp) +
-		(offset >> EXT4_BLOCK_SIZE_BITS(sb));
-
-	iloc->block_group = block_group;
-	iloc->offset = offset & (EXT4_BLOCK_SIZE(sb) - 1);
-	return block;
-}
-
 /*
  * ext4_get_inode_loc returns with an extra refcount against the inode's
  * underlying buffer_head on success. If 'in_mem' is true, we have all
@@ -3717,19 +3816,35 @@
 static int __ext4_get_inode_loc(struct inode *inode,
 				struct ext4_iloc *iloc, int in_mem)
 {
-	ext4_fsblk_t block;
-	struct buffer_head *bh;
+	struct ext4_group_desc	*gdp;
+	struct buffer_head	*bh;
+	struct super_block	*sb = inode->i_sb;
+	ext4_fsblk_t		block;
+	int			inodes_per_block, inode_offset;
 
-	block = ext4_get_inode_block(inode->i_sb, inode->i_ino, iloc);
-	if (!block)
+	iloc->bh = 0;
+	if (!ext4_valid_inum(sb, inode->i_ino))
 		return -EIO;
 
-	bh = sb_getblk(inode->i_sb, block);
+	iloc->block_group = (inode->i_ino - 1) / EXT4_INODES_PER_GROUP(sb);
+	gdp = ext4_get_group_desc(sb, iloc->block_group, NULL);
+	if (!gdp)
+		return -EIO;
+
+	/*
+	 * Figure out the offset within the block group inode table
+	 */
+	inodes_per_block = (EXT4_BLOCK_SIZE(sb) / EXT4_INODE_SIZE(sb));
+	inode_offset = ((inode->i_ino - 1) %
+			EXT4_INODES_PER_GROUP(sb));
+	block = ext4_inode_table(sb, gdp) + (inode_offset / inodes_per_block);
+	iloc->offset = (inode_offset % inodes_per_block) * EXT4_INODE_SIZE(sb);
+
+	bh = sb_getblk(sb, block);
 	if (!bh) {
-		ext4_error (inode->i_sb, "ext4_get_inode_loc",
-				"unable to read inode block - "
-				"inode=%lu, block=%llu",
-				 inode->i_ino, block);
+		ext4_error(sb, "ext4_get_inode_loc", "unable to read "
+			   "inode block - inode=%lu, block=%llu",
+			   inode->i_ino, block);
 		return -EIO;
 	}
 	if (!buffer_uptodate(bh)) {
@@ -3757,28 +3872,12 @@
 		 */
 		if (in_mem) {
 			struct buffer_head *bitmap_bh;
-			struct ext4_group_desc *desc;
-			int inodes_per_buffer;
-			int inode_offset, i;
-			ext4_group_t block_group;
-			int start;
+			int i, start;
 
-			block_group = (inode->i_ino - 1) /
-					EXT4_INODES_PER_GROUP(inode->i_sb);
-			inodes_per_buffer = bh->b_size /
-				EXT4_INODE_SIZE(inode->i_sb);
-			inode_offset = ((inode->i_ino - 1) %
-					EXT4_INODES_PER_GROUP(inode->i_sb));
-			start = inode_offset & ~(inodes_per_buffer - 1);
+			start = inode_offset & ~(inodes_per_block - 1);
 
 			/* Is the inode bitmap in cache? */
-			desc = ext4_get_group_desc(inode->i_sb,
-						block_group, NULL);
-			if (!desc)
-				goto make_io;
-
-			bitmap_bh = sb_getblk(inode->i_sb,
-				ext4_inode_bitmap(inode->i_sb, desc));
+			bitmap_bh = sb_getblk(sb, ext4_inode_bitmap(sb, gdp));
 			if (!bitmap_bh)
 				goto make_io;
 
@@ -3791,14 +3890,14 @@
 				brelse(bitmap_bh);
 				goto make_io;
 			}
-			for (i = start; i < start + inodes_per_buffer; i++) {
+			for (i = start; i < start + inodes_per_block; i++) {
 				if (i == inode_offset)
 					continue;
 				if (ext4_test_bit(i, bitmap_bh->b_data))
 					break;
 			}
 			brelse(bitmap_bh);
-			if (i == start + inodes_per_buffer) {
+			if (i == start + inodes_per_block) {
 				/* all other inodes are free, so skip I/O */
 				memset(bh->b_data, 0, bh->b_size);
 				set_buffer_uptodate(bh);
@@ -3809,6 +3908,36 @@
 
 make_io:
 		/*
+		 * If we need to do any I/O, try to pre-readahead extra
+		 * blocks from the inode table.
+		 */
+		if (EXT4_SB(sb)->s_inode_readahead_blks) {
+			ext4_fsblk_t b, end, table;
+			unsigned num;
+
+			table = ext4_inode_table(sb, gdp);
+			/* Make sure s_inode_readahead_blks is a power of 2 */
+			while (EXT4_SB(sb)->s_inode_readahead_blks &
+			       (EXT4_SB(sb)->s_inode_readahead_blks-1))
+				EXT4_SB(sb)->s_inode_readahead_blks = 
+				   (EXT4_SB(sb)->s_inode_readahead_blks &
+				    (EXT4_SB(sb)->s_inode_readahead_blks-1));
+			b = block & ~(EXT4_SB(sb)->s_inode_readahead_blks-1);
+			if (table > b)
+				b = table;
+			end = b + EXT4_SB(sb)->s_inode_readahead_blks;
+			num = EXT4_INODES_PER_GROUP(sb);
+			if (EXT4_HAS_RO_COMPAT_FEATURE(sb,
+				       EXT4_FEATURE_RO_COMPAT_GDT_CSUM))
+				num -= le16_to_cpu(gdp->bg_itable_unused);
+			table += num / inodes_per_block;
+			if (end > table)
+				end = table;
+			while (b <= end)
+				sb_breadahead(sb, b++);
+		}
+
+		/*
 		 * There are other valid inodes in the buffer, this inode
 		 * has in-inode xattrs, or we don't have this inode in memory.
 		 * Read the block from disk.
@@ -3818,10 +3947,9 @@
 		submit_bh(READ_META, bh);
 		wait_on_buffer(bh);
 		if (!buffer_uptodate(bh)) {
-			ext4_error(inode->i_sb, "ext4_get_inode_loc",
-					"unable to read inode block - "
-					"inode=%lu, block=%llu",
-					inode->i_ino, block);
+			ext4_error(sb, __func__,
+				   "unable to read inode block - inode=%lu, "
+				   "block=%llu", inode->i_ino, block);
 			brelse(bh);
 			return -EIO;
 		}
@@ -3913,11 +4041,10 @@
 		return inode;
 
 	ei = EXT4_I(inode);
-#ifdef CONFIG_EXT4DEV_FS_POSIX_ACL
+#ifdef CONFIG_EXT4_FS_POSIX_ACL
 	ei->i_acl = EXT4_ACL_NOT_CACHED;
 	ei->i_default_acl = EXT4_ACL_NOT_CACHED;
 #endif
-	ei->i_block_alloc_info = NULL;
 
 	ret = __ext4_get_inode_loc(inode, &iloc, 0);
 	if (ret < 0)
@@ -3927,7 +4054,7 @@
 	inode->i_mode = le16_to_cpu(raw_inode->i_mode);
 	inode->i_uid = (uid_t)le16_to_cpu(raw_inode->i_uid_low);
 	inode->i_gid = (gid_t)le16_to_cpu(raw_inode->i_gid_low);
-	if(!(test_opt (inode->i_sb, NO_UID32))) {
+	if (!(test_opt(inode->i_sb, NO_UID32))) {
 		inode->i_uid |= le16_to_cpu(raw_inode->i_uid_high) << 16;
 		inode->i_gid |= le16_to_cpu(raw_inode->i_gid_high) << 16;
 	}
@@ -3945,7 +4072,7 @@
 		if (inode->i_mode == 0 ||
 		    !(EXT4_SB(inode->i_sb)->s_mount_state & EXT4_ORPHAN_FS)) {
 			/* this inode is deleted */
-			brelse (bh);
+			brelse(bh);
 			ret = -ESTALE;
 			goto bad_inode;
 		}
@@ -3978,7 +4105,7 @@
 		ei->i_extra_isize = le16_to_cpu(raw_inode->i_extra_isize);
 		if (EXT4_GOOD_OLD_INODE_SIZE + ei->i_extra_isize >
 		    EXT4_INODE_SIZE(inode->i_sb)) {
-			brelse (bh);
+			brelse(bh);
 			ret = -EIO;
 			goto bad_inode;
 		}
@@ -4031,7 +4158,7 @@
 			init_special_inode(inode, inode->i_mode,
 			   new_decode_dev(le32_to_cpu(raw_inode->i_block[1])));
 	}
-	brelse (iloc.bh);
+	brelse(iloc.bh);
 	ext4_set_inode_flags(inode);
 	unlock_new_inode(inode);
 	return inode;
@@ -4113,14 +4240,14 @@
 
 	ext4_get_inode_flags(ei);
 	raw_inode->i_mode = cpu_to_le16(inode->i_mode);
-	if(!(test_opt(inode->i_sb, NO_UID32))) {
+	if (!(test_opt(inode->i_sb, NO_UID32))) {
 		raw_inode->i_uid_low = cpu_to_le16(low_16_bits(inode->i_uid));
 		raw_inode->i_gid_low = cpu_to_le16(low_16_bits(inode->i_gid));
 /*
  * Fix up interoperability with old kernels. Otherwise, old inodes get
  * re-used with the upper 16 bits of the uid/gid intact
  */
-		if(!ei->i_dtime) {
+		if (!ei->i_dtime) {
 			raw_inode->i_uid_high =
 				cpu_to_le16(high_16_bits(inode->i_uid));
 			raw_inode->i_gid_high =
@@ -4208,7 +4335,7 @@
 	ei->i_state &= ~EXT4_STATE_NEW;
 
 out_brelse:
-	brelse (bh);
+	brelse(bh);
 	ext4_std_error(inode->i_sb, err);
 	return err;
 }
@@ -4811,6 +4938,7 @@
 	loff_t size;
 	unsigned long len;
 	int ret = -EINVAL;
+	void *fsdata;
 	struct file *file = vma->vm_file;
 	struct inode *inode = file->f_path.dentry->d_inode;
 	struct address_space *mapping = inode->i_mapping;
@@ -4849,11 +4977,11 @@
 	 * on the same page though
 	 */
 	ret = mapping->a_ops->write_begin(file, mapping, page_offset(page),
-			len, AOP_FLAG_UNINTERRUPTIBLE, &page, NULL);
+			len, AOP_FLAG_UNINTERRUPTIBLE, &page, &fsdata);
 	if (ret < 0)
 		goto out_unlock;
 	ret = mapping->a_ops->write_end(file, mapping, page_offset(page),
-			len, len, page, NULL);
+			len, len, page, fsdata);
 	if (ret < 0)
 		goto out_unlock;
 	ret = 0;
diff --git a/fs/ext4/ioctl.c b/fs/ext4/ioctl.c
index 7a6c2f1..dc99b47 100644
--- a/fs/ext4/ioctl.c
+++ b/fs/ext4/ioctl.c
@@ -23,9 +23,8 @@
 	struct inode *inode = filp->f_dentry->d_inode;
 	struct ext4_inode_info *ei = EXT4_I(inode);
 	unsigned int flags;
-	unsigned short rsv_window_size;
 
-	ext4_debug ("cmd = %u, arg = %lu\n", cmd, arg);
+	ext4_debug("cmd = %u, arg = %lu\n", cmd, arg);
 
 	switch (cmd) {
 	case EXT4_IOC_GETFLAGS:
@@ -34,7 +33,7 @@
 		return put_user(flags, (int __user *) arg);
 	case EXT4_IOC_SETFLAGS: {
 		handle_t *handle = NULL;
-		int err;
+		int err, migrate = 0;
 		struct ext4_iloc iloc;
 		unsigned int oldflags;
 		unsigned int jflag;
@@ -82,6 +81,17 @@
 			if (!capable(CAP_SYS_RESOURCE))
 				goto flags_out;
 		}
+		if (oldflags & EXT4_EXTENTS_FL) {
+			/* We don't support clearning extent flags */
+			if (!(flags & EXT4_EXTENTS_FL)) {
+				err = -EOPNOTSUPP;
+				goto flags_out;
+			}
+		} else if (flags & EXT4_EXTENTS_FL) {
+			/* migrate the file */
+			migrate = 1;
+			flags &= ~EXT4_EXTENTS_FL;
+		}
 
 		handle = ext4_journal_start(inode, 1);
 		if (IS_ERR(handle)) {
@@ -109,6 +119,10 @@
 
 		if ((jflag ^ oldflags) & (EXT4_JOURNAL_DATA_FL))
 			err = ext4_change_inode_journal_flag(inode, jflag);
+		if (err)
+			goto flags_out;
+		if (migrate)
+			err = ext4_ext_migrate(inode);
 flags_out:
 		mutex_unlock(&inode->i_mutex);
 		mnt_drop_write(filp->f_path.mnt);
@@ -175,53 +189,10 @@
 			return ret;
 		}
 #endif
-	case EXT4_IOC_GETRSVSZ:
-		if (test_opt(inode->i_sb, RESERVATION)
-			&& S_ISREG(inode->i_mode)
-			&& ei->i_block_alloc_info) {
-			rsv_window_size = ei->i_block_alloc_info->rsv_window_node.rsv_goal_size;
-			return put_user(rsv_window_size, (int __user *)arg);
-		}
-		return -ENOTTY;
-	case EXT4_IOC_SETRSVSZ: {
-		int err;
-
-		if (!test_opt(inode->i_sb, RESERVATION) ||!S_ISREG(inode->i_mode))
-			return -ENOTTY;
-
-		if (!is_owner_or_cap(inode))
-			return -EACCES;
-
-		if (get_user(rsv_window_size, (int __user *)arg))
-			return -EFAULT;
-
-		err = mnt_want_write(filp->f_path.mnt);
-		if (err)
-			return err;
-
-		if (rsv_window_size > EXT4_MAX_RESERVE_BLOCKS)
-			rsv_window_size = EXT4_MAX_RESERVE_BLOCKS;
-
-		/*
-		 * need to allocate reservation structure for this inode
-		 * before set the window size
-		 */
-		down_write(&ei->i_data_sem);
-		if (!ei->i_block_alloc_info)
-			ext4_init_block_alloc_info(inode);
-
-		if (ei->i_block_alloc_info){
-			struct ext4_reserve_window_node *rsv = &ei->i_block_alloc_info->rsv_window_node;
-			rsv->rsv_goal_size = rsv_window_size;
-		}
-		up_write(&ei->i_data_sem);
-		mnt_drop_write(filp->f_path.mnt);
-		return 0;
-	}
 	case EXT4_IOC_GROUP_EXTEND: {
 		ext4_fsblk_t n_blocks_count;
 		struct super_block *sb = inode->i_sb;
-		int err;
+		int err, err2;
 
 		if (!capable(CAP_SYS_RESOURCE))
 			return -EPERM;
@@ -235,8 +206,10 @@
 
 		err = ext4_group_extend(sb, EXT4_SB(sb)->s_es, n_blocks_count);
 		jbd2_journal_lock_updates(EXT4_SB(sb)->s_journal);
-		jbd2_journal_flush(EXT4_SB(sb)->s_journal);
+		err2 = jbd2_journal_flush(EXT4_SB(sb)->s_journal);
 		jbd2_journal_unlock_updates(EXT4_SB(sb)->s_journal);
+		if (err == 0)
+			err = err2;
 		mnt_drop_write(filp->f_path.mnt);
 
 		return err;
@@ -244,7 +217,7 @@
 	case EXT4_IOC_GROUP_ADD: {
 		struct ext4_new_group_data input;
 		struct super_block *sb = inode->i_sb;
-		int err;
+		int err, err2;
 
 		if (!capable(CAP_SYS_RESOURCE))
 			return -EPERM;
@@ -259,15 +232,36 @@
 
 		err = ext4_group_add(sb, &input);
 		jbd2_journal_lock_updates(EXT4_SB(sb)->s_journal);
-		jbd2_journal_flush(EXT4_SB(sb)->s_journal);
+		err2 = jbd2_journal_flush(EXT4_SB(sb)->s_journal);
 		jbd2_journal_unlock_updates(EXT4_SB(sb)->s_journal);
+		if (err == 0)
+			err = err2;
 		mnt_drop_write(filp->f_path.mnt);
 
 		return err;
 	}
 
 	case EXT4_IOC_MIGRATE:
-		return ext4_ext_migrate(inode, filp, cmd, arg);
+	{
+		int err;
+		if (!is_owner_or_cap(inode))
+			return -EACCES;
+
+		err = mnt_want_write(filp->f_path.mnt);
+		if (err)
+			return err;
+		/*
+		 * inode_mutex prevent write and truncate on the file.
+		 * Read still goes through. We take i_data_sem in
+		 * ext4_ext_swap_inode_data before we switch the
+		 * inode format to prevent read.
+		 */
+		mutex_lock(&(inode->i_mutex));
+		err = ext4_ext_migrate(inode);
+		mutex_unlock(&(inode->i_mutex));
+		mnt_drop_write(filp->f_path.mnt);
+		return err;
+	}
 
 	default:
 		return -ENOTTY;
diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c
index e0e3a5e..b580714 100644
--- a/fs/ext4/mballoc.c
+++ b/fs/ext4/mballoc.c
@@ -477,9 +477,10 @@
 		b2 = (unsigned char *) bitmap;
 		for (i = 0; i < e4b->bd_sb->s_blocksize; i++) {
 			if (b1[i] != b2[i]) {
-				printk("corruption in group %lu at byte %u(%u):"
-				       " %x in copy != %x on disk/prealloc\n",
-					e4b->bd_group, i, i * 8, b1[i], b2[i]);
+				printk(KERN_ERR "corruption in group %lu "
+				       "at byte %u(%u): %x in copy != %x "
+				       "on disk/prealloc\n",
+				       e4b->bd_group, i, i * 8, b1[i], b2[i]);
 				BUG();
 			}
 		}
@@ -533,9 +534,6 @@
 	void *buddy;
 	void *buddy2;
 
-	if (!test_opt(sb, MBALLOC))
-		return 0;
-
 	{
 		static int mb_check_counter;
 		if (mb_check_counter++ % 100 != 0)
@@ -784,9 +782,11 @@
 		if (bh[i] == NULL)
 			goto out;
 
-		if (bh_uptodate_or_lock(bh[i]))
+		if (buffer_uptodate(bh[i]) &&
+		    !(desc->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT)))
 			continue;
 
+		lock_buffer(bh[i]);
 		spin_lock(sb_bgl_lock(EXT4_SB(sb), first_group + i));
 		if (desc->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT)) {
 			ext4_init_block_bitmap(sb, bh[i],
@@ -2169,9 +2169,10 @@
 {
 	struct ext4_sb_info *sbi = EXT4_SB(sb);
 
-	remove_proc_entry("mb_groups", sbi->s_mb_proc);
-	remove_proc_entry("mb_history", sbi->s_mb_proc);
-
+	if (sbi->s_proc != NULL) {
+		remove_proc_entry("mb_groups", sbi->s_proc);
+		remove_proc_entry("mb_history", sbi->s_proc);
+	}
 	kfree(sbi->s_mb_history);
 }
 
@@ -2180,10 +2181,10 @@
 	struct ext4_sb_info *sbi = EXT4_SB(sb);
 	int i;
 
-	if (sbi->s_mb_proc != NULL) {
-		proc_create_data("mb_history", S_IRUGO, sbi->s_mb_proc,
+	if (sbi->s_proc != NULL) {
+		proc_create_data("mb_history", S_IRUGO, sbi->s_proc,
 				 &ext4_mb_seq_history_fops, sb);
-		proc_create_data("mb_groups", S_IRUGO, sbi->s_mb_proc,
+		proc_create_data("mb_groups", S_IRUGO, sbi->s_proc,
 				 &ext4_mb_seq_groups_fops, sb);
 	}
 
@@ -2485,19 +2486,14 @@
 	unsigned max;
 	int ret;
 
-	if (!test_opt(sb, MBALLOC))
-		return 0;
-
 	i = (sb->s_blocksize_bits + 2) * sizeof(unsigned short);
 
 	sbi->s_mb_offsets = kmalloc(i, GFP_KERNEL);
 	if (sbi->s_mb_offsets == NULL) {
-		clear_opt(sbi->s_mount_opt, MBALLOC);
 		return -ENOMEM;
 	}
 	sbi->s_mb_maxs = kmalloc(i, GFP_KERNEL);
 	if (sbi->s_mb_maxs == NULL) {
-		clear_opt(sbi->s_mount_opt, MBALLOC);
 		kfree(sbi->s_mb_maxs);
 		return -ENOMEM;
 	}
@@ -2520,7 +2516,6 @@
 	/* init file for buddy data */
 	ret = ext4_mb_init_backend(sb);
 	if (ret != 0) {
-		clear_opt(sbi->s_mount_opt, MBALLOC);
 		kfree(sbi->s_mb_offsets);
 		kfree(sbi->s_mb_maxs);
 		return ret;
@@ -2540,17 +2535,15 @@
 	sbi->s_mb_history_filter = EXT4_MB_HISTORY_DEFAULT;
 	sbi->s_mb_group_prealloc = MB_DEFAULT_GROUP_PREALLOC;
 
-	i = sizeof(struct ext4_locality_group) * nr_cpu_ids;
-	sbi->s_locality_groups = kmalloc(i, GFP_KERNEL);
+	sbi->s_locality_groups = alloc_percpu(struct ext4_locality_group);
 	if (sbi->s_locality_groups == NULL) {
-		clear_opt(sbi->s_mount_opt, MBALLOC);
 		kfree(sbi->s_mb_offsets);
 		kfree(sbi->s_mb_maxs);
 		return -ENOMEM;
 	}
-	for (i = 0; i < nr_cpu_ids; i++) {
+	for_each_possible_cpu(i) {
 		struct ext4_locality_group *lg;
-		lg = &sbi->s_locality_groups[i];
+		lg = per_cpu_ptr(sbi->s_locality_groups, i);
 		mutex_init(&lg->lg_mutex);
 		for (j = 0; j < PREALLOC_TB_SIZE; j++)
 			INIT_LIST_HEAD(&lg->lg_prealloc_list[j]);
@@ -2560,7 +2553,7 @@
 	ext4_mb_init_per_dev_proc(sb);
 	ext4_mb_history_init(sb);
 
-	printk("EXT4-fs: mballoc enabled\n");
+	printk(KERN_INFO "EXT4-fs: mballoc enabled\n");
 	return 0;
 }
 
@@ -2589,9 +2582,6 @@
 	struct ext4_group_info *grinfo;
 	struct ext4_sb_info *sbi = EXT4_SB(sb);
 
-	if (!test_opt(sb, MBALLOC))
-		return 0;
-
 	/* release freed, non-committed blocks */
 	spin_lock(&sbi->s_md_lock);
 	list_splice_init(&sbi->s_closed_transaction,
@@ -2647,8 +2637,7 @@
 				atomic_read(&sbi->s_mb_discarded));
 	}
 
-	kfree(sbi->s_locality_groups);
-
+	free_percpu(sbi->s_locality_groups);
 	ext4_mb_history_release(sb);
 	ext4_mb_destroy_per_dev_proc(sb);
 
@@ -2721,118 +2710,46 @@
 #define EXT4_MB_STREAM_REQ		"stream_req"
 #define EXT4_MB_GROUP_PREALLOC		"group_prealloc"
 
-
-
-#define MB_PROC_FOPS(name)					\
-static int ext4_mb_##name##_proc_show(struct seq_file *m, void *v)	\
-{								\
-	struct ext4_sb_info *sbi = m->private;			\
-								\
-	seq_printf(m, "%ld\n", sbi->s_mb_##name);		\
-	return 0;						\
-}								\
-								\
-static int ext4_mb_##name##_proc_open(struct inode *inode, struct file *file)\
-{								\
-	return single_open(file, ext4_mb_##name##_proc_show, PDE(inode)->data);\
-}								\
-								\
-static ssize_t ext4_mb_##name##_proc_write(struct file *file,	\
-		const char __user *buf, size_t cnt, loff_t *ppos)	\
-{								\
-	struct ext4_sb_info *sbi = PDE(file->f_path.dentry->d_inode)->data;\
-	char str[32];						\
-	long value;						\
-	if (cnt >= sizeof(str))					\
-		return -EINVAL;					\
-	if (copy_from_user(str, buf, cnt))			\
-		return -EFAULT;					\
-	value = simple_strtol(str, NULL, 0);			\
-	if (value <= 0)						\
-		return -ERANGE;					\
-	sbi->s_mb_##name = value;				\
-	return cnt;						\
-}								\
-								\
-static const struct file_operations ext4_mb_##name##_proc_fops = {	\
-	.owner		= THIS_MODULE,				\
-	.open		= ext4_mb_##name##_proc_open,		\
-	.read		= seq_read,				\
-	.llseek		= seq_lseek,				\
-	.release	= single_release,			\
-	.write		= ext4_mb_##name##_proc_write,		\
-};
-
-MB_PROC_FOPS(stats);
-MB_PROC_FOPS(max_to_scan);
-MB_PROC_FOPS(min_to_scan);
-MB_PROC_FOPS(order2_reqs);
-MB_PROC_FOPS(stream_request);
-MB_PROC_FOPS(group_prealloc);
-
-#define	MB_PROC_HANDLER(name, var)					\
-do {									\
-	proc = proc_create_data(name, mode, sbi->s_mb_proc,		\
-				&ext4_mb_##var##_proc_fops, sbi);	\
-	if (proc == NULL) {						\
-		printk(KERN_ERR "EXT4-fs: can't to create %s\n", name);	\
-		goto err_out;						\
-	}								\
-} while (0)
-
 static int ext4_mb_init_per_dev_proc(struct super_block *sb)
 {
 	mode_t mode = S_IFREG | S_IRUGO | S_IWUSR;
 	struct ext4_sb_info *sbi = EXT4_SB(sb);
 	struct proc_dir_entry *proc;
-	char devname[64];
 
-	if (proc_root_ext4 == NULL) {
-		sbi->s_mb_proc = NULL;
+	if (sbi->s_proc == NULL)
 		return -EINVAL;
-	}
-	bdevname(sb->s_bdev, devname);
-	sbi->s_mb_proc = proc_mkdir(devname, proc_root_ext4);
 
-	MB_PROC_HANDLER(EXT4_MB_STATS_NAME, stats);
-	MB_PROC_HANDLER(EXT4_MB_MAX_TO_SCAN_NAME, max_to_scan);
-	MB_PROC_HANDLER(EXT4_MB_MIN_TO_SCAN_NAME, min_to_scan);
-	MB_PROC_HANDLER(EXT4_MB_ORDER2_REQ, order2_reqs);
-	MB_PROC_HANDLER(EXT4_MB_STREAM_REQ, stream_request);
-	MB_PROC_HANDLER(EXT4_MB_GROUP_PREALLOC, group_prealloc);
-
+	EXT4_PROC_HANDLER(EXT4_MB_STATS_NAME, mb_stats);
+	EXT4_PROC_HANDLER(EXT4_MB_MAX_TO_SCAN_NAME, mb_max_to_scan);
+	EXT4_PROC_HANDLER(EXT4_MB_MIN_TO_SCAN_NAME, mb_min_to_scan);
+	EXT4_PROC_HANDLER(EXT4_MB_ORDER2_REQ, mb_order2_reqs);
+	EXT4_PROC_HANDLER(EXT4_MB_STREAM_REQ, mb_stream_request);
+	EXT4_PROC_HANDLER(EXT4_MB_GROUP_PREALLOC, mb_group_prealloc);
 	return 0;
 
 err_out:
-	printk(KERN_ERR "EXT4-fs: Unable to create %s\n", devname);
-	remove_proc_entry(EXT4_MB_GROUP_PREALLOC, sbi->s_mb_proc);
-	remove_proc_entry(EXT4_MB_STREAM_REQ, sbi->s_mb_proc);
-	remove_proc_entry(EXT4_MB_ORDER2_REQ, sbi->s_mb_proc);
-	remove_proc_entry(EXT4_MB_MIN_TO_SCAN_NAME, sbi->s_mb_proc);
-	remove_proc_entry(EXT4_MB_MAX_TO_SCAN_NAME, sbi->s_mb_proc);
-	remove_proc_entry(EXT4_MB_STATS_NAME, sbi->s_mb_proc);
-	remove_proc_entry(devname, proc_root_ext4);
-	sbi->s_mb_proc = NULL;
-
+	remove_proc_entry(EXT4_MB_GROUP_PREALLOC, sbi->s_proc);
+	remove_proc_entry(EXT4_MB_STREAM_REQ, sbi->s_proc);
+	remove_proc_entry(EXT4_MB_ORDER2_REQ, sbi->s_proc);
+	remove_proc_entry(EXT4_MB_MIN_TO_SCAN_NAME, sbi->s_proc);
+	remove_proc_entry(EXT4_MB_MAX_TO_SCAN_NAME, sbi->s_proc);
+	remove_proc_entry(EXT4_MB_STATS_NAME, sbi->s_proc);
 	return -ENOMEM;
 }
 
 static int ext4_mb_destroy_per_dev_proc(struct super_block *sb)
 {
 	struct ext4_sb_info *sbi = EXT4_SB(sb);
-	char devname[64];
 
-	if (sbi->s_mb_proc == NULL)
+	if (sbi->s_proc == NULL)
 		return -EINVAL;
 
-	bdevname(sb->s_bdev, devname);
-	remove_proc_entry(EXT4_MB_GROUP_PREALLOC, sbi->s_mb_proc);
-	remove_proc_entry(EXT4_MB_STREAM_REQ, sbi->s_mb_proc);
-	remove_proc_entry(EXT4_MB_ORDER2_REQ, sbi->s_mb_proc);
-	remove_proc_entry(EXT4_MB_MIN_TO_SCAN_NAME, sbi->s_mb_proc);
-	remove_proc_entry(EXT4_MB_MAX_TO_SCAN_NAME, sbi->s_mb_proc);
-	remove_proc_entry(EXT4_MB_STATS_NAME, sbi->s_mb_proc);
-	remove_proc_entry(devname, proc_root_ext4);
+	remove_proc_entry(EXT4_MB_GROUP_PREALLOC, sbi->s_proc);
+	remove_proc_entry(EXT4_MB_STREAM_REQ, sbi->s_proc);
+	remove_proc_entry(EXT4_MB_ORDER2_REQ, sbi->s_proc);
+	remove_proc_entry(EXT4_MB_MIN_TO_SCAN_NAME, sbi->s_proc);
+	remove_proc_entry(EXT4_MB_MAX_TO_SCAN_NAME, sbi->s_proc);
+	remove_proc_entry(EXT4_MB_STATS_NAME, sbi->s_proc);
 
 	return 0;
 }
@@ -2854,11 +2771,6 @@
 		kmem_cache_destroy(ext4_pspace_cachep);
 		return -ENOMEM;
 	}
-#ifdef CONFIG_PROC_FS
-	proc_root_ext4 = proc_mkdir("fs/ext4", NULL);
-	if (proc_root_ext4 == NULL)
-		printk(KERN_ERR "EXT4-fs: Unable to create fs/ext4\n");
-#endif
 	return 0;
 }
 
@@ -2867,9 +2779,6 @@
 	/* XXX: synchronize_rcu(); */
 	kmem_cache_destroy(ext4_pspace_cachep);
 	kmem_cache_destroy(ext4_ac_cachep);
-#ifdef CONFIG_PROC_FS
-	remove_proc_entry("fs/ext4", NULL);
-#endif
 }
 
 
@@ -2879,7 +2788,7 @@
  */
 static noinline_for_stack int
 ext4_mb_mark_diskspace_used(struct ext4_allocation_context *ac,
-				handle_t *handle)
+				handle_t *handle, unsigned long reserv_blks)
 {
 	struct buffer_head *bitmap_bh = NULL;
 	struct ext4_super_block *es;
@@ -2968,15 +2877,16 @@
 	le16_add_cpu(&gdp->bg_free_blocks_count, -ac->ac_b_ex.fe_len);
 	gdp->bg_checksum = ext4_group_desc_csum(sbi, ac->ac_b_ex.fe_group, gdp);
 	spin_unlock(sb_bgl_lock(sbi, ac->ac_b_ex.fe_group));
-
+	percpu_counter_sub(&sbi->s_freeblocks_counter, ac->ac_b_ex.fe_len);
 	/*
-	 * free blocks account has already be reduced/reserved
-	 * at write_begin() time for delayed allocation
-	 * do not double accounting
+	 * Now reduce the dirty block count also. Should not go negative
 	 */
 	if (!(ac->ac_flags & EXT4_MB_DELALLOC_RESERVED))
-		percpu_counter_sub(&sbi->s_freeblocks_counter,
-					ac->ac_b_ex.fe_len);
+		/* release all the reserved blocks if non delalloc */
+		percpu_counter_sub(&sbi->s_dirtyblocks_counter, reserv_blks);
+	else
+		percpu_counter_sub(&sbi->s_dirtyblocks_counter,
+						ac->ac_b_ex.fe_len);
 
 	if (sbi->s_log_groups_per_flex) {
 		ext4_group_t flex_group = ext4_flex_group(sbi,
@@ -3884,7 +3794,7 @@
  *
  * FIXME!! Make sure it is valid at all the call sites
  */
-void ext4_mb_discard_inode_preallocations(struct inode *inode)
+void ext4_discard_preallocations(struct inode *inode)
 {
 	struct ext4_inode_info *ei = EXT4_I(inode);
 	struct super_block *sb = inode->i_sb;
@@ -3896,7 +3806,7 @@
 	struct ext4_buddy e4b;
 	int err;
 
-	if (!test_opt(sb, MBALLOC) || !S_ISREG(inode->i_mode)) {
+	if (!S_ISREG(inode->i_mode)) {
 		/*BUG_ON(!list_empty(&ei->i_prealloc_list));*/
 		return;
 	}
@@ -4094,8 +4004,7 @@
 	 * per cpu locality group is to reduce the contention between block
 	 * request from multiple CPUs.
 	 */
-	ac->ac_lg = &sbi->s_locality_groups[get_cpu()];
-	put_cpu();
+	ac->ac_lg = per_cpu_ptr(sbi->s_locality_groups, raw_smp_processor_id());
 
 	/* we're going to use group allocation */
 	ac->ac_flags |= EXT4_MB_HINT_GROUP_ALLOC;
@@ -4369,33 +4278,32 @@
 ext4_fsblk_t ext4_mb_new_blocks(handle_t *handle,
 				 struct ext4_allocation_request *ar, int *errp)
 {
+	int freed;
 	struct ext4_allocation_context *ac = NULL;
 	struct ext4_sb_info *sbi;
 	struct super_block *sb;
 	ext4_fsblk_t block = 0;
-	int freed;
-	int inquota;
+	unsigned long inquota;
+	unsigned long reserv_blks = 0;
 
 	sb = ar->inode->i_sb;
 	sbi = EXT4_SB(sb);
 
-	if (!test_opt(sb, MBALLOC)) {
-		block = ext4_old_new_blocks(handle, ar->inode, ar->goal,
-					    &(ar->len), errp);
-		return block;
-	}
 	if (!EXT4_I(ar->inode)->i_delalloc_reserved_flag) {
 		/*
 		 * With delalloc we already reserved the blocks
 		 */
-		ar->len = ext4_has_free_blocks(sbi, ar->len);
+		while (ar->len && ext4_claim_free_blocks(sbi, ar->len)) {
+			/* let others to free the space */
+			yield();
+			ar->len = ar->len >> 1;
+		}
+		if (!ar->len) {
+			*errp = -ENOSPC;
+			return 0;
+		}
+		reserv_blks = ar->len;
 	}
-
-	if (ar->len == 0) {
-		*errp = -ENOSPC;
-		return 0;
-	}
-
 	while (ar->len && DQUOT_ALLOC_BLOCK(ar->inode, ar->len)) {
 		ar->flags |= EXT4_MB_HINT_NOPREALLOC;
 		ar->len--;
@@ -4441,7 +4349,7 @@
 	}
 
 	if (likely(ac->ac_status == AC_STATUS_FOUND)) {
-		*errp = ext4_mb_mark_diskspace_used(ac, handle);
+		*errp = ext4_mb_mark_diskspace_used(ac, handle, reserv_blks);
 		if (*errp ==  -EAGAIN) {
 			ac->ac_b_ex.fe_group = 0;
 			ac->ac_b_ex.fe_start = 0;
diff --git a/fs/ext4/mballoc.h b/fs/ext4/mballoc.h
index c7c9906..b3b4828 100644
--- a/fs/ext4/mballoc.h
+++ b/fs/ext4/mballoc.h
@@ -257,7 +257,6 @@
 
 #define in_range(b, first, len)	((b) >= (first) && (b) <= (first) + (len) - 1)
 
-static struct proc_dir_entry *proc_root_ext4;
 struct buffer_head *read_block_bitmap(struct super_block *, ext4_group_t);
 
 static void ext4_mb_generate_from_pa(struct super_block *sb, void *bitmap,
diff --git a/fs/ext4/migrate.c b/fs/ext4/migrate.c
index 46fc0b5..f2a9cf4 100644
--- a/fs/ext4/migrate.c
+++ b/fs/ext4/migrate.c
@@ -447,8 +447,7 @@
 
 }
 
-int ext4_ext_migrate(struct inode *inode, struct file *filp,
-				unsigned int cmd, unsigned long arg)
+int ext4_ext_migrate(struct inode *inode)
 {
 	handle_t *handle;
 	int retval = 0, i;
@@ -516,12 +515,6 @@
 	 * when we add extents we extent the journal
 	 */
 	/*
-	 * inode_mutex prevent write and truncate on the file. Read still goes
-	 * through. We take i_data_sem in ext4_ext_swap_inode_data before we
-	 * switch the inode format to prevent read.
-	 */
-	mutex_lock(&(inode->i_mutex));
-	/*
 	 * Even though we take i_mutex we can still cause block allocation
 	 * via mmap write to holes. If we have allocated new blocks we fail
 	 * migrate.  New block allocation will clear EXT4_EXT_MIGRATE flag.
@@ -623,7 +616,6 @@
 	tmp_inode->i_nlink = 0;
 
 	ext4_journal_stop(handle);
-	mutex_unlock(&(inode->i_mutex));
 
 	if (tmp_inode)
 		iput(tmp_inode);
diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c
index 387ad98..92db9e9 100644
--- a/fs/ext4/namei.c
+++ b/fs/ext4/namei.c
@@ -151,34 +151,36 @@
 
 static inline ext4_lblk_t dx_get_block(struct dx_entry *entry);
 static void dx_set_block(struct dx_entry *entry, ext4_lblk_t value);
-static inline unsigned dx_get_hash (struct dx_entry *entry);
-static void dx_set_hash (struct dx_entry *entry, unsigned value);
-static unsigned dx_get_count (struct dx_entry *entries);
-static unsigned dx_get_limit (struct dx_entry *entries);
-static void dx_set_count (struct dx_entry *entries, unsigned value);
-static void dx_set_limit (struct dx_entry *entries, unsigned value);
-static unsigned dx_root_limit (struct inode *dir, unsigned infosize);
-static unsigned dx_node_limit (struct inode *dir);
-static struct dx_frame *dx_probe(struct dentry *dentry,
+static inline unsigned dx_get_hash(struct dx_entry *entry);
+static void dx_set_hash(struct dx_entry *entry, unsigned value);
+static unsigned dx_get_count(struct dx_entry *entries);
+static unsigned dx_get_limit(struct dx_entry *entries);
+static void dx_set_count(struct dx_entry *entries, unsigned value);
+static void dx_set_limit(struct dx_entry *entries, unsigned value);
+static unsigned dx_root_limit(struct inode *dir, unsigned infosize);
+static unsigned dx_node_limit(struct inode *dir);
+static struct dx_frame *dx_probe(const struct qstr *d_name,
 				 struct inode *dir,
 				 struct dx_hash_info *hinfo,
 				 struct dx_frame *frame,
 				 int *err);
-static void dx_release (struct dx_frame *frames);
-static int dx_make_map (struct ext4_dir_entry_2 *de, int size,
-			struct dx_hash_info *hinfo, struct dx_map_entry map[]);
+static void dx_release(struct dx_frame *frames);
+static int dx_make_map(struct ext4_dir_entry_2 *de, int size,
+		       struct dx_hash_info *hinfo, struct dx_map_entry map[]);
 static void dx_sort_map(struct dx_map_entry *map, unsigned count);
-static struct ext4_dir_entry_2 *dx_move_dirents (char *from, char *to,
+static struct ext4_dir_entry_2 *dx_move_dirents(char *from, char *to,
 		struct dx_map_entry *offsets, int count);
-static struct ext4_dir_entry_2* dx_pack_dirents (char *base, int size);
+static struct ext4_dir_entry_2* dx_pack_dirents(char *base, int size);
 static void dx_insert_block(struct dx_frame *frame,
 					u32 hash, ext4_lblk_t block);
 static int ext4_htree_next_block(struct inode *dir, __u32 hash,
 				 struct dx_frame *frame,
 				 struct dx_frame *frames,
 				 __u32 *start_hash);
-static struct buffer_head * ext4_dx_find_entry(struct dentry *dentry,
-		       struct ext4_dir_entry_2 **res_dir, int *err);
+static struct buffer_head * ext4_dx_find_entry(struct inode *dir,
+		const struct qstr *d_name,
+		struct ext4_dir_entry_2 **res_dir,
+		int *err);
 static int ext4_dx_add_entry(handle_t *handle, struct dentry *dentry,
 			     struct inode *inode);
 
@@ -207,44 +209,44 @@
 	entry->block = cpu_to_le32(value);
 }
 
-static inline unsigned dx_get_hash (struct dx_entry *entry)
+static inline unsigned dx_get_hash(struct dx_entry *entry)
 {
 	return le32_to_cpu(entry->hash);
 }
 
-static inline void dx_set_hash (struct dx_entry *entry, unsigned value)
+static inline void dx_set_hash(struct dx_entry *entry, unsigned value)
 {
 	entry->hash = cpu_to_le32(value);
 }
 
-static inline unsigned dx_get_count (struct dx_entry *entries)
+static inline unsigned dx_get_count(struct dx_entry *entries)
 {
 	return le16_to_cpu(((struct dx_countlimit *) entries)->count);
 }
 
-static inline unsigned dx_get_limit (struct dx_entry *entries)
+static inline unsigned dx_get_limit(struct dx_entry *entries)
 {
 	return le16_to_cpu(((struct dx_countlimit *) entries)->limit);
 }
 
-static inline void dx_set_count (struct dx_entry *entries, unsigned value)
+static inline void dx_set_count(struct dx_entry *entries, unsigned value)
 {
 	((struct dx_countlimit *) entries)->count = cpu_to_le16(value);
 }
 
-static inline void dx_set_limit (struct dx_entry *entries, unsigned value)
+static inline void dx_set_limit(struct dx_entry *entries, unsigned value)
 {
 	((struct dx_countlimit *) entries)->limit = cpu_to_le16(value);
 }
 
-static inline unsigned dx_root_limit (struct inode *dir, unsigned infosize)
+static inline unsigned dx_root_limit(struct inode *dir, unsigned infosize)
 {
 	unsigned entry_space = dir->i_sb->s_blocksize - EXT4_DIR_REC_LEN(1) -
 		EXT4_DIR_REC_LEN(2) - infosize;
 	return entry_space / sizeof(struct dx_entry);
 }
 
-static inline unsigned dx_node_limit (struct inode *dir)
+static inline unsigned dx_node_limit(struct inode *dir)
 {
 	unsigned entry_space = dir->i_sb->s_blocksize - EXT4_DIR_REC_LEN(0);
 	return entry_space / sizeof(struct dx_entry);
@@ -254,12 +256,12 @@
  * Debug
  */
 #ifdef DX_DEBUG
-static void dx_show_index (char * label, struct dx_entry *entries)
+static void dx_show_index(char * label, struct dx_entry *entries)
 {
 	int i, n = dx_get_count (entries);
-	printk("%s index ", label);
+	printk(KERN_DEBUG "%s index ", label);
 	for (i = 0; i < n; i++) {
-		printk("%x->%lu ", i? dx_get_hash(entries + i) :
+		printk("%x->%lu ", i ? dx_get_hash(entries + i) :
 				0, (unsigned long)dx_get_block(entries + i));
 	}
 	printk("\n");
@@ -306,7 +308,7 @@
 			     struct dx_entry *entries, int levels)
 {
 	unsigned blocksize = dir->i_sb->s_blocksize;
-	unsigned count = dx_get_count (entries), names = 0, space = 0, i;
+	unsigned count = dx_get_count(entries), names = 0, space = 0, i;
 	unsigned bcount = 0;
 	struct buffer_head *bh;
 	int err;
@@ -325,11 +327,12 @@
 		names += stats.names;
 		space += stats.space;
 		bcount += stats.bcount;
-		brelse (bh);
+		brelse(bh);
 	}
 	if (bcount)
-		printk("%snames %u, fullness %u (%u%%)\n", levels?"":"   ",
-			names, space/bcount,(space/bcount)*100/blocksize);
+		printk(KERN_DEBUG "%snames %u, fullness %u (%u%%)\n", 
+		       levels ? "" : "   ", names, space/bcount,
+		       (space/bcount)*100/blocksize);
 	return (struct stats) { names, space, bcount};
 }
 #endif /* DX_DEBUG */
@@ -344,7 +347,7 @@
  * back to userspace.
  */
 static struct dx_frame *
-dx_probe(struct dentry *dentry, struct inode *dir,
+dx_probe(const struct qstr *d_name, struct inode *dir,
 	 struct dx_hash_info *hinfo, struct dx_frame *frame_in, int *err)
 {
 	unsigned count, indirect;
@@ -355,8 +358,6 @@
 	u32 hash;
 
 	frame->bh = NULL;
-	if (dentry)
-		dir = dentry->d_parent->d_inode;
 	if (!(bh = ext4_bread (NULL,dir, 0, 0, err)))
 		goto fail;
 	root = (struct dx_root *) bh->b_data;
@@ -372,8 +373,8 @@
 	}
 	hinfo->hash_version = root->info.hash_version;
 	hinfo->seed = EXT4_SB(dir->i_sb)->s_hash_seed;
-	if (dentry)
-		ext4fs_dirhash(dentry->d_name.name, dentry->d_name.len, hinfo);
+	if (d_name)
+		ext4fs_dirhash(d_name->name, d_name->len, hinfo);
 	hash = hinfo->hash;
 
 	if (root->info.unused_flags & 1) {
@@ -406,7 +407,7 @@
 		goto fail;
 	}
 
-	dxtrace (printk("Look up %x", hash));
+	dxtrace(printk("Look up %x", hash));
 	while (1)
 	{
 		count = dx_get_count(entries);
@@ -555,7 +556,7 @@
 				      0, &err)))
 			return err; /* Failure */
 		p++;
-		brelse (p->bh);
+		brelse(p->bh);
 		p->bh = bh;
 		p->at = p->entries = ((struct dx_node *) bh->b_data)->entries;
 	}
@@ -593,7 +594,7 @@
 			/* On error, skip the f_pos to the next block. */
 			dir_file->f_pos = (dir_file->f_pos |
 					(dir->i_sb->s_blocksize - 1)) + 1;
-			brelse (bh);
+			brelse(bh);
 			return count;
 		}
 		ext4fs_dirhash(de->name, de->name_len, hinfo);
@@ -635,8 +636,8 @@
 	int ret, err;
 	__u32 hashval;
 
-	dxtrace(printk("In htree_fill_tree, start hash: %x:%x\n", start_hash,
-		       start_minor_hash));
+	dxtrace(printk(KERN_DEBUG "In htree_fill_tree, start hash: %x:%x\n", 
+		       start_hash, start_minor_hash));
 	dir = dir_file->f_path.dentry->d_inode;
 	if (!(EXT4_I(dir)->i_flags & EXT4_INDEX_FL)) {
 		hinfo.hash_version = EXT4_SB(dir->i_sb)->s_def_hash_version;
@@ -648,7 +649,7 @@
 	}
 	hinfo.hash = start_hash;
 	hinfo.minor_hash = 0;
-	frame = dx_probe(NULL, dir_file->f_path.dentry->d_inode, &hinfo, frames, &err);
+	frame = dx_probe(NULL, dir, &hinfo, frames, &err);
 	if (!frame)
 		return err;
 
@@ -694,8 +695,8 @@
 			break;
 	}
 	dx_release(frames);
-	dxtrace(printk("Fill tree: returned %d entries, next hash: %x\n",
-		       count, *next_hash));
+	dxtrace(printk(KERN_DEBUG "Fill tree: returned %d entries, "
+		       "next hash: %x\n", count, *next_hash));
 	return count;
 errout:
 	dx_release(frames);
@@ -802,17 +803,17 @@
 /*
  * Returns 0 if not found, -1 on failure, and 1 on success
  */
-static inline int search_dirblock(struct buffer_head * bh,
+static inline int search_dirblock(struct buffer_head *bh,
 				  struct inode *dir,
-				  struct dentry *dentry,
+				  const struct qstr *d_name,
 				  unsigned long offset,
 				  struct ext4_dir_entry_2 ** res_dir)
 {
 	struct ext4_dir_entry_2 * de;
 	char * dlimit;
 	int de_len;
-	const char *name = dentry->d_name.name;
-	int namelen = dentry->d_name.len;
+	const char *name = d_name->name;
+	int namelen = d_name->len;
 
 	de = (struct ext4_dir_entry_2 *) bh->b_data;
 	dlimit = bh->b_data + dir->i_sb->s_blocksize;
@@ -851,12 +852,13 @@
  * The returned buffer_head has ->b_count elevated.  The caller is expected
  * to brelse() it when appropriate.
  */
-static struct buffer_head * ext4_find_entry (struct dentry *dentry,
+static struct buffer_head * ext4_find_entry (struct inode *dir,
+					const struct qstr *d_name,
 					struct ext4_dir_entry_2 ** res_dir)
 {
-	struct super_block * sb;
-	struct buffer_head * bh_use[NAMEI_RA_SIZE];
-	struct buffer_head * bh, *ret = NULL;
+	struct super_block *sb;
+	struct buffer_head *bh_use[NAMEI_RA_SIZE];
+	struct buffer_head *bh, *ret = NULL;
 	ext4_lblk_t start, block, b;
 	int ra_max = 0;		/* Number of bh's in the readahead
 				   buffer, bh_use[] */
@@ -865,16 +867,15 @@
 	int num = 0;
 	ext4_lblk_t  nblocks;
 	int i, err;
-	struct inode *dir = dentry->d_parent->d_inode;
 	int namelen;
 
 	*res_dir = NULL;
 	sb = dir->i_sb;
-	namelen = dentry->d_name.len;
+	namelen = d_name->len;
 	if (namelen > EXT4_NAME_LEN)
 		return NULL;
 	if (is_dx(dir)) {
-		bh = ext4_dx_find_entry(dentry, res_dir, &err);
+		bh = ext4_dx_find_entry(dir, d_name, res_dir, &err);
 		/*
 		 * On success, or if the error was file not found,
 		 * return.  Otherwise, fall back to doing a search the
@@ -882,7 +883,8 @@
 		 */
 		if (bh || (err != ERR_BAD_DX_DIR))
 			return bh;
-		dxtrace(printk("ext4_find_entry: dx failed, falling back\n"));
+		dxtrace(printk(KERN_DEBUG "ext4_find_entry: dx failed, "
+			       "falling back\n"));
 	}
 	nblocks = dir->i_size >> EXT4_BLOCK_SIZE_BITS(sb);
 	start = EXT4_I(dir)->i_dir_start_lookup;
@@ -926,7 +928,7 @@
 			brelse(bh);
 			goto next;
 		}
-		i = search_dirblock(bh, dir, dentry,
+		i = search_dirblock(bh, dir, d_name,
 			    block << EXT4_BLOCK_SIZE_BITS(sb), res_dir);
 		if (i == 1) {
 			EXT4_I(dir)->i_dir_start_lookup = block;
@@ -956,11 +958,11 @@
 cleanup_and_exit:
 	/* Clean up the read-ahead blocks */
 	for (; ra_ptr < ra_max; ra_ptr++)
-		brelse (bh_use[ra_ptr]);
+		brelse(bh_use[ra_ptr]);
 	return ret;
 }
 
-static struct buffer_head * ext4_dx_find_entry(struct dentry *dentry,
+static struct buffer_head * ext4_dx_find_entry(struct inode *dir, const struct qstr *d_name,
 		       struct ext4_dir_entry_2 **res_dir, int *err)
 {
 	struct super_block * sb;
@@ -971,14 +973,13 @@
 	struct buffer_head *bh;
 	ext4_lblk_t block;
 	int retval;
-	int namelen = dentry->d_name.len;
-	const u8 *name = dentry->d_name.name;
-	struct inode *dir = dentry->d_parent->d_inode;
+	int namelen = d_name->len;
+	const u8 *name = d_name->name;
 
 	sb = dir->i_sb;
 	/* NFS may look up ".." - look at dx_root directory block */
 	if (namelen > 2 || name[0] != '.'||(name[1] != '.' && name[1] != '\0')){
-		if (!(frame = dx_probe(dentry, NULL, &hinfo, frames, err)))
+		if (!(frame = dx_probe(d_name, dir, &hinfo, frames, err)))
 			return NULL;
 	} else {
 		frame = frames;
@@ -1010,7 +1011,7 @@
 				return bh;
 			}
 		}
-		brelse (bh);
+		brelse(bh);
 		/* Check to see if we should continue to search */
 		retval = ext4_htree_next_block(dir, hash, frame,
 					       frames, NULL);
@@ -1025,25 +1026,25 @@
 
 	*err = -ENOENT;
 errout:
-	dxtrace(printk("%s not found\n", name));
+	dxtrace(printk(KERN_DEBUG "%s not found\n", name));
 	dx_release (frames);
 	return NULL;
 }
 
-static struct dentry *ext4_lookup(struct inode * dir, struct dentry *dentry, struct nameidata *nd)
+static struct dentry *ext4_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
 {
-	struct inode * inode;
-	struct ext4_dir_entry_2 * de;
-	struct buffer_head * bh;
+	struct inode *inode;
+	struct ext4_dir_entry_2 *de;
+	struct buffer_head *bh;
 
 	if (dentry->d_name.len > EXT4_NAME_LEN)
 		return ERR_PTR(-ENAMETOOLONG);
 
-	bh = ext4_find_entry(dentry, &de);
+	bh = ext4_find_entry(dir, &dentry->d_name, &de);
 	inode = NULL;
 	if (bh) {
 		unsigned long ino = le32_to_cpu(de->inode);
-		brelse (bh);
+		brelse(bh);
 		if (!ext4_valid_inum(dir->i_sb, ino)) {
 			ext4_error(dir->i_sb, "ext4_lookup",
 				   "bad inode number: %lu", ino);
@@ -1062,15 +1063,14 @@
 	unsigned long ino;
 	struct dentry *parent;
 	struct inode *inode;
-	struct dentry dotdot;
+	static const struct qstr dotdot = {
+		.name = "..",
+		.len = 2,
+	};
 	struct ext4_dir_entry_2 * de;
 	struct buffer_head *bh;
 
-	dotdot.d_name.name = "..";
-	dotdot.d_name.len = 2;
-	dotdot.d_parent = child; /* confusing, isn't it! */
-
-	bh = ext4_find_entry(&dotdot, &de);
+	bh = ext4_find_entry(child->d_inode, &dotdot, &de);
 	inode = NULL;
 	if (!bh)
 		return ERR_PTR(-ENOENT);
@@ -1201,10 +1201,10 @@
 
 	/* create map in the end of data2 block */
 	map = (struct dx_map_entry *) (data2 + blocksize);
-	count = dx_make_map ((struct ext4_dir_entry_2 *) data1,
+	count = dx_make_map((struct ext4_dir_entry_2 *) data1,
 			     blocksize, hinfo, map);
 	map -= count;
-	dx_sort_map (map, count);
+	dx_sort_map(map, count);
 	/* Split the existing block in the middle, size-wise */
 	size = 0;
 	move = 0;
@@ -1225,7 +1225,7 @@
 
 	/* Fancy dance to stay within two buffers */
 	de2 = dx_move_dirents(data1, data2, map + split, count - split);
-	de = dx_pack_dirents(data1,blocksize);
+	de = dx_pack_dirents(data1, blocksize);
 	de->rec_len = ext4_rec_len_to_disk(data1 + blocksize - (char *) de);
 	de2->rec_len = ext4_rec_len_to_disk(data2 + blocksize - (char *) de2);
 	dxtrace(dx_show_leaf (hinfo, (struct ext4_dir_entry_2 *) data1, blocksize, 1));
@@ -1237,15 +1237,15 @@
 		swap(*bh, bh2);
 		de = de2;
 	}
-	dx_insert_block (frame, hash2 + continued, newblock);
-	err = ext4_journal_dirty_metadata (handle, bh2);
+	dx_insert_block(frame, hash2 + continued, newblock);
+	err = ext4_journal_dirty_metadata(handle, bh2);
 	if (err)
 		goto journal_error;
-	err = ext4_journal_dirty_metadata (handle, frame->bh);
+	err = ext4_journal_dirty_metadata(handle, frame->bh);
 	if (err)
 		goto journal_error;
-	brelse (bh2);
-	dxtrace(dx_show_index ("frame", frame->entries));
+	brelse(bh2);
+	dxtrace(dx_show_index("frame", frame->entries));
 	return de;
 
 journal_error:
@@ -1271,7 +1271,7 @@
  */
 static int add_dirent_to_buf(handle_t *handle, struct dentry *dentry,
 			     struct inode *inode, struct ext4_dir_entry_2 *de,
-			     struct buffer_head * bh)
+			     struct buffer_head *bh)
 {
 	struct inode	*dir = dentry->d_parent->d_inode;
 	const char	*name = dentry->d_name.name;
@@ -1288,11 +1288,11 @@
 		while ((char *) de <= top) {
 			if (!ext4_check_dir_entry("ext4_add_entry", dir, de,
 						  bh, offset)) {
-				brelse (bh);
+				brelse(bh);
 				return -EIO;
 			}
-			if (ext4_match (namelen, name, de)) {
-				brelse (bh);
+			if (ext4_match(namelen, name, de)) {
+				brelse(bh);
 				return -EEXIST;
 			}
 			nlen = EXT4_DIR_REC_LEN(de->name_len);
@@ -1329,7 +1329,7 @@
 	} else
 		de->inode = 0;
 	de->name_len = namelen;
-	memcpy (de->name, name, namelen);
+	memcpy(de->name, name, namelen);
 	/*
 	 * XXX shouldn't update any times until successful
 	 * completion of syscall, but too many callers depend
@@ -1377,7 +1377,7 @@
 	struct fake_dirent *fde;
 
 	blocksize =  dir->i_sb->s_blocksize;
-	dxtrace(printk("Creating index\n"));
+	dxtrace(printk(KERN_DEBUG "Creating index\n"));
 	retval = ext4_journal_get_write_access(handle, bh);
 	if (retval) {
 		ext4_std_error(dir->i_sb, retval);
@@ -1386,7 +1386,7 @@
 	}
 	root = (struct dx_root *) bh->b_data;
 
-	bh2 = ext4_append (handle, dir, &block, &retval);
+	bh2 = ext4_append(handle, dir, &block, &retval);
 	if (!(bh2)) {
 		brelse(bh);
 		return retval;
@@ -1412,9 +1412,9 @@
 	root->info.info_length = sizeof(root->info);
 	root->info.hash_version = EXT4_SB(dir->i_sb)->s_def_hash_version;
 	entries = root->entries;
-	dx_set_block (entries, 1);
-	dx_set_count (entries, 1);
-	dx_set_limit (entries, dx_root_limit(dir, sizeof(root->info)));
+	dx_set_block(entries, 1);
+	dx_set_count(entries, 1);
+	dx_set_limit(entries, dx_root_limit(dir, sizeof(root->info)));
 
 	/* Initialize as for dx_probe */
 	hinfo.hash_version = root->info.hash_version;
@@ -1443,14 +1443,14 @@
  * may not sleep between calling this and putting something into
  * the entry, as someone else might have used it while you slept.
  */
-static int ext4_add_entry (handle_t *handle, struct dentry *dentry,
-	struct inode *inode)
+static int ext4_add_entry(handle_t *handle, struct dentry *dentry,
+			  struct inode *inode)
 {
 	struct inode *dir = dentry->d_parent->d_inode;
 	unsigned long offset;
-	struct buffer_head * bh;
+	struct buffer_head *bh;
 	struct ext4_dir_entry_2 *de;
-	struct super_block * sb;
+	struct super_block *sb;
 	int	retval;
 	int	dx_fallback=0;
 	unsigned blocksize;
@@ -1500,13 +1500,13 @@
 	struct dx_frame frames[2], *frame;
 	struct dx_entry *entries, *at;
 	struct dx_hash_info hinfo;
-	struct buffer_head * bh;
+	struct buffer_head *bh;
 	struct inode *dir = dentry->d_parent->d_inode;
-	struct super_block * sb = dir->i_sb;
+	struct super_block *sb = dir->i_sb;
 	struct ext4_dir_entry_2 *de;
 	int err;
 
-	frame = dx_probe(dentry, NULL, &hinfo, frames, &err);
+	frame = dx_probe(&dentry->d_name, dir, &hinfo, frames, &err);
 	if (!frame)
 		return err;
 	entries = frame->entries;
@@ -1527,7 +1527,7 @@
 	}
 
 	/* Block full, should compress but for now just split */
-	dxtrace(printk("using %u of %u node entries\n",
+	dxtrace(printk(KERN_DEBUG "using %u of %u node entries\n",
 		       dx_get_count(entries), dx_get_limit(entries)));
 	/* Need to split index? */
 	if (dx_get_count(entries) == dx_get_limit(entries)) {
@@ -1559,7 +1559,8 @@
 		if (levels) {
 			unsigned icount1 = icount/2, icount2 = icount - icount1;
 			unsigned hash2 = dx_get_hash(entries + icount1);
-			dxtrace(printk("Split index %i/%i\n", icount1, icount2));
+			dxtrace(printk(KERN_DEBUG "Split index %i/%i\n",
+				       icount1, icount2));
 
 			BUFFER_TRACE(frame->bh, "get_write_access"); /* index root */
 			err = ext4_journal_get_write_access(handle,
@@ -1567,11 +1568,11 @@
 			if (err)
 				goto journal_error;
 
-			memcpy ((char *) entries2, (char *) (entries + icount1),
-				icount2 * sizeof(struct dx_entry));
-			dx_set_count (entries, icount1);
-			dx_set_count (entries2, icount2);
-			dx_set_limit (entries2, dx_node_limit(dir));
+			memcpy((char *) entries2, (char *) (entries + icount1),
+			       icount2 * sizeof(struct dx_entry));
+			dx_set_count(entries, icount1);
+			dx_set_count(entries2, icount2);
+			dx_set_limit(entries2, dx_node_limit(dir));
 
 			/* Which index block gets the new entry? */
 			if (at - entries >= icount1) {
@@ -1579,16 +1580,17 @@
 				frame->entries = entries = entries2;
 				swap(frame->bh, bh2);
 			}
-			dx_insert_block (frames + 0, hash2, newblock);
-			dxtrace(dx_show_index ("node", frames[1].entries));
-			dxtrace(dx_show_index ("node",
+			dx_insert_block(frames + 0, hash2, newblock);
+			dxtrace(dx_show_index("node", frames[1].entries));
+			dxtrace(dx_show_index("node",
 			       ((struct dx_node *) bh2->b_data)->entries));
 			err = ext4_journal_dirty_metadata(handle, bh2);
 			if (err)
 				goto journal_error;
 			brelse (bh2);
 		} else {
-			dxtrace(printk("Creating second level index...\n"));
+			dxtrace(printk(KERN_DEBUG
+				       "Creating second level index...\n"));
 			memcpy((char *) entries2, (char *) entries,
 			       icount * sizeof(struct dx_entry));
 			dx_set_limit(entries2, dx_node_limit(dir));
@@ -1630,12 +1632,12 @@
  * ext4_delete_entry deletes a directory entry by merging it with the
  * previous entry
  */
-static int ext4_delete_entry (handle_t *handle,
-			      struct inode * dir,
-			      struct ext4_dir_entry_2 * de_del,
-			      struct buffer_head * bh)
+static int ext4_delete_entry(handle_t *handle,
+			     struct inode *dir,
+			     struct ext4_dir_entry_2 *de_del,
+			     struct buffer_head *bh)
 {
-	struct ext4_dir_entry_2 * de, * pde;
+	struct ext4_dir_entry_2 *de, *pde;
 	int i;
 
 	i = 0;
@@ -1716,11 +1718,11 @@
  * If the create succeeds, we fill in the inode information
  * with d_instantiate().
  */
-static int ext4_create (struct inode * dir, struct dentry * dentry, int mode,
-		struct nameidata *nd)
+static int ext4_create(struct inode *dir, struct dentry *dentry, int mode,
+		       struct nameidata *nd)
 {
 	handle_t *handle;
-	struct inode * inode;
+	struct inode *inode;
 	int err, retries = 0;
 
 retry:
@@ -1747,8 +1749,8 @@
 	return err;
 }
 
-static int ext4_mknod (struct inode * dir, struct dentry *dentry,
-			int mode, dev_t rdev)
+static int ext4_mknod(struct inode *dir, struct dentry *dentry,
+		      int mode, dev_t rdev)
 {
 	handle_t *handle;
 	struct inode *inode;
@@ -1767,11 +1769,11 @@
 	if (IS_DIRSYNC(dir))
 		handle->h_sync = 1;
 
-	inode = ext4_new_inode (handle, dir, mode);
+	inode = ext4_new_inode(handle, dir, mode);
 	err = PTR_ERR(inode);
 	if (!IS_ERR(inode)) {
 		init_special_inode(inode, inode->i_mode, rdev);
-#ifdef CONFIG_EXT4DEV_FS_XATTR
+#ifdef CONFIG_EXT4_FS_XATTR
 		inode->i_op = &ext4_special_inode_operations;
 #endif
 		err = ext4_add_nondir(handle, dentry, inode);
@@ -1782,12 +1784,12 @@
 	return err;
 }
 
-static int ext4_mkdir(struct inode * dir, struct dentry * dentry, int mode)
+static int ext4_mkdir(struct inode *dir, struct dentry *dentry, int mode)
 {
 	handle_t *handle;
-	struct inode * inode;
-	struct buffer_head * dir_block;
-	struct ext4_dir_entry_2 * de;
+	struct inode *inode;
+	struct buffer_head *dir_block;
+	struct ext4_dir_entry_2 *de;
 	int err, retries = 0;
 
 	if (EXT4_DIR_LINK_MAX(dir))
@@ -1803,7 +1805,7 @@
 	if (IS_DIRSYNC(dir))
 		handle->h_sync = 1;
 
-	inode = ext4_new_inode (handle, dir, S_IFDIR | mode);
+	inode = ext4_new_inode(handle, dir, S_IFDIR | mode);
 	err = PTR_ERR(inode);
 	if (IS_ERR(inode))
 		goto out_stop;
@@ -1811,7 +1813,7 @@
 	inode->i_op = &ext4_dir_inode_operations;
 	inode->i_fop = &ext4_dir_operations;
 	inode->i_size = EXT4_I(inode)->i_disksize = inode->i_sb->s_blocksize;
-	dir_block = ext4_bread (handle, inode, 0, 1, &err);
+	dir_block = ext4_bread(handle, inode, 0, 1, &err);
 	if (!dir_block)
 		goto out_clear_inode;
 	BUFFER_TRACE(dir_block, "get_write_access");
@@ -1820,26 +1822,26 @@
 	de->inode = cpu_to_le32(inode->i_ino);
 	de->name_len = 1;
 	de->rec_len = ext4_rec_len_to_disk(EXT4_DIR_REC_LEN(de->name_len));
-	strcpy (de->name, ".");
+	strcpy(de->name, ".");
 	ext4_set_de_type(dir->i_sb, de, S_IFDIR);
 	de = ext4_next_entry(de);
 	de->inode = cpu_to_le32(dir->i_ino);
 	de->rec_len = ext4_rec_len_to_disk(inode->i_sb->s_blocksize -
 						EXT4_DIR_REC_LEN(1));
 	de->name_len = 2;
-	strcpy (de->name, "..");
+	strcpy(de->name, "..");
 	ext4_set_de_type(dir->i_sb, de, S_IFDIR);
 	inode->i_nlink = 2;
 	BUFFER_TRACE(dir_block, "call ext4_journal_dirty_metadata");
 	ext4_journal_dirty_metadata(handle, dir_block);
-	brelse (dir_block);
+	brelse(dir_block);
 	ext4_mark_inode_dirty(handle, inode);
-	err = ext4_add_entry (handle, dentry, inode);
+	err = ext4_add_entry(handle, dentry, inode);
 	if (err) {
 out_clear_inode:
 		clear_nlink(inode);
 		ext4_mark_inode_dirty(handle, inode);
-		iput (inode);
+		iput(inode);
 		goto out_stop;
 	}
 	ext4_inc_count(handle, dir);
@@ -1856,17 +1858,17 @@
 /*
  * routine to check that the specified directory is empty (for rmdir)
  */
-static int empty_dir (struct inode * inode)
+static int empty_dir(struct inode *inode)
 {
 	unsigned long offset;
-	struct buffer_head * bh;
-	struct ext4_dir_entry_2 * de, * de1;
-	struct super_block * sb;
+	struct buffer_head *bh;
+	struct ext4_dir_entry_2 *de, *de1;
+	struct super_block *sb;
 	int err = 0;
 
 	sb = inode->i_sb;
 	if (inode->i_size < EXT4_DIR_REC_LEN(1) + EXT4_DIR_REC_LEN(2) ||
-	    !(bh = ext4_bread (NULL, inode, 0, 0, &err))) {
+	    !(bh = ext4_bread(NULL, inode, 0, 0, &err))) {
 		if (err)
 			ext4_error(inode->i_sb, __func__,
 				   "error %d reading directory #%lu offset 0",
@@ -1881,23 +1883,23 @@
 	de1 = ext4_next_entry(de);
 	if (le32_to_cpu(de->inode) != inode->i_ino ||
 			!le32_to_cpu(de1->inode) ||
-			strcmp (".", de->name) ||
-			strcmp ("..", de1->name)) {
-		ext4_warning (inode->i_sb, "empty_dir",
-			      "bad directory (dir #%lu) - no `.' or `..'",
-			      inode->i_ino);
-		brelse (bh);
+			strcmp(".", de->name) ||
+			strcmp("..", de1->name)) {
+		ext4_warning(inode->i_sb, "empty_dir",
+			     "bad directory (dir #%lu) - no `.' or `..'",
+			     inode->i_ino);
+		brelse(bh);
 		return 1;
 	}
 	offset = ext4_rec_len_from_disk(de->rec_len) +
 		 ext4_rec_len_from_disk(de1->rec_len);
 	de = ext4_next_entry(de1);
-	while (offset < inode->i_size ) {
+	while (offset < inode->i_size) {
 		if (!bh ||
 			(void *) de >= (void *) (bh->b_data+sb->s_blocksize)) {
 			err = 0;
-			brelse (bh);
-			bh = ext4_bread (NULL, inode,
+			brelse(bh);
+			bh = ext4_bread(NULL, inode,
 				offset >> EXT4_BLOCK_SIZE_BITS(sb), 0, &err);
 			if (!bh) {
 				if (err)
@@ -1917,13 +1919,13 @@
 			continue;
 		}
 		if (le32_to_cpu(de->inode)) {
-			brelse (bh);
+			brelse(bh);
 			return 0;
 		}
 		offset += ext4_rec_len_from_disk(de->rec_len);
 		de = ext4_next_entry(de);
 	}
-	brelse (bh);
+	brelse(bh);
 	return 1;
 }
 
@@ -1954,8 +1956,8 @@
 	 * ->i_nlink. For, say it, character device. Not a regular file,
 	 * not a directory, not a symlink and ->i_nlink > 0.
 	 */
-	J_ASSERT ((S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
-		S_ISLNK(inode->i_mode)) || inode->i_nlink == 0);
+	J_ASSERT((S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
+		  S_ISLNK(inode->i_mode)) || inode->i_nlink == 0);
 
 	BUFFER_TRACE(EXT4_SB(sb)->s_sbh, "get_write_access");
 	err = ext4_journal_get_write_access(handle, EXT4_SB(sb)->s_sbh);
@@ -2069,12 +2071,12 @@
 	goto out_err;
 }
 
-static int ext4_rmdir (struct inode * dir, struct dentry *dentry)
+static int ext4_rmdir(struct inode *dir, struct dentry *dentry)
 {
 	int retval;
-	struct inode * inode;
-	struct buffer_head * bh;
-	struct ext4_dir_entry_2 * de;
+	struct inode *inode;
+	struct buffer_head *bh;
+	struct ext4_dir_entry_2 *de;
 	handle_t *handle;
 
 	/* Initialize quotas before so that eventual writes go in
@@ -2085,7 +2087,7 @@
 		return PTR_ERR(handle);
 
 	retval = -ENOENT;
-	bh = ext4_find_entry (dentry, &de);
+	bh = ext4_find_entry(dir, &dentry->d_name, &de);
 	if (!bh)
 		goto end_rmdir;
 
@@ -2099,16 +2101,16 @@
 		goto end_rmdir;
 
 	retval = -ENOTEMPTY;
-	if (!empty_dir (inode))
+	if (!empty_dir(inode))
 		goto end_rmdir;
 
 	retval = ext4_delete_entry(handle, dir, de, bh);
 	if (retval)
 		goto end_rmdir;
 	if (!EXT4_DIR_LINK_EMPTY(inode))
-		ext4_warning (inode->i_sb, "ext4_rmdir",
-			      "empty directory has too many links (%d)",
-			      inode->i_nlink);
+		ext4_warning(inode->i_sb, "ext4_rmdir",
+			     "empty directory has too many links (%d)",
+			     inode->i_nlink);
 	inode->i_version++;
 	clear_nlink(inode);
 	/* There's no need to set i_disksize: the fact that i_nlink is
@@ -2124,16 +2126,16 @@
 
 end_rmdir:
 	ext4_journal_stop(handle);
-	brelse (bh);
+	brelse(bh);
 	return retval;
 }
 
-static int ext4_unlink(struct inode * dir, struct dentry *dentry)
+static int ext4_unlink(struct inode *dir, struct dentry *dentry)
 {
 	int retval;
-	struct inode * inode;
-	struct buffer_head * bh;
-	struct ext4_dir_entry_2 * de;
+	struct inode *inode;
+	struct buffer_head *bh;
+	struct ext4_dir_entry_2 *de;
 	handle_t *handle;
 
 	/* Initialize quotas before so that eventual writes go
@@ -2147,7 +2149,7 @@
 		handle->h_sync = 1;
 
 	retval = -ENOENT;
-	bh = ext4_find_entry (dentry, &de);
+	bh = ext4_find_entry(dir, &dentry->d_name, &de);
 	if (!bh)
 		goto end_unlink;
 
@@ -2158,9 +2160,9 @@
 		goto end_unlink;
 
 	if (!inode->i_nlink) {
-		ext4_warning (inode->i_sb, "ext4_unlink",
-			      "Deleting nonexistent file (%lu), %d",
-			      inode->i_ino, inode->i_nlink);
+		ext4_warning(inode->i_sb, "ext4_unlink",
+			     "Deleting nonexistent file (%lu), %d",
+			     inode->i_ino, inode->i_nlink);
 		inode->i_nlink = 1;
 	}
 	retval = ext4_delete_entry(handle, dir, de, bh);
@@ -2178,15 +2180,15 @@
 
 end_unlink:
 	ext4_journal_stop(handle);
-	brelse (bh);
+	brelse(bh);
 	return retval;
 }
 
-static int ext4_symlink (struct inode * dir,
-		struct dentry *dentry, const char * symname)
+static int ext4_symlink(struct inode *dir,
+			struct dentry *dentry, const char *symname)
 {
 	handle_t *handle;
-	struct inode * inode;
+	struct inode *inode;
 	int l, err, retries = 0;
 
 	l = strlen(symname)+1;
@@ -2203,12 +2205,12 @@
 	if (IS_DIRSYNC(dir))
 		handle->h_sync = 1;
 
-	inode = ext4_new_inode (handle, dir, S_IFLNK|S_IRWXUGO);
+	inode = ext4_new_inode(handle, dir, S_IFLNK|S_IRWXUGO);
 	err = PTR_ERR(inode);
 	if (IS_ERR(inode))
 		goto out_stop;
 
-	if (l > sizeof (EXT4_I(inode)->i_data)) {
+	if (l > sizeof(EXT4_I(inode)->i_data)) {
 		inode->i_op = &ext4_symlink_inode_operations;
 		ext4_set_aops(inode);
 		/*
@@ -2221,14 +2223,14 @@
 		if (err) {
 			clear_nlink(inode);
 			ext4_mark_inode_dirty(handle, inode);
-			iput (inode);
+			iput(inode);
 			goto out_stop;
 		}
 	} else {
 		/* clear the extent format for fast symlink */
 		EXT4_I(inode)->i_flags &= ~EXT4_EXTENTS_FL;
 		inode->i_op = &ext4_fast_symlink_inode_operations;
-		memcpy((char*)&EXT4_I(inode)->i_data,symname,l);
+		memcpy((char *)&EXT4_I(inode)->i_data, symname, l);
 		inode->i_size = l-1;
 	}
 	EXT4_I(inode)->i_disksize = inode->i_size;
@@ -2240,8 +2242,8 @@
 	return err;
 }
 
-static int ext4_link (struct dentry * old_dentry,
-		struct inode * dir, struct dentry *dentry)
+static int ext4_link(struct dentry *old_dentry,
+		     struct inode *dir, struct dentry *dentry)
 {
 	handle_t *handle;
 	struct inode *inode = old_dentry->d_inode;
@@ -2284,13 +2286,13 @@
  * Anybody can rename anything with this: the permission checks are left to the
  * higher-level routines.
  */
-static int ext4_rename (struct inode * old_dir, struct dentry *old_dentry,
-			   struct inode * new_dir,struct dentry *new_dentry)
+static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry,
+		       struct inode *new_dir, struct dentry *new_dentry)
 {
 	handle_t *handle;
-	struct inode * old_inode, * new_inode;
-	struct buffer_head * old_bh, * new_bh, * dir_bh;
-	struct ext4_dir_entry_2 * old_de, * new_de;
+	struct inode *old_inode, *new_inode;
+	struct buffer_head *old_bh, *new_bh, *dir_bh;
+	struct ext4_dir_entry_2 *old_de, *new_de;
 	int retval;
 
 	old_bh = new_bh = dir_bh = NULL;
@@ -2308,7 +2310,7 @@
 	if (IS_DIRSYNC(old_dir) || IS_DIRSYNC(new_dir))
 		handle->h_sync = 1;
 
-	old_bh = ext4_find_entry (old_dentry, &old_de);
+	old_bh = ext4_find_entry(old_dir, &old_dentry->d_name, &old_de);
 	/*
 	 *  Check for inode number is _not_ due to possible IO errors.
 	 *  We might rmdir the source, keep it as pwd of some process
@@ -2321,32 +2323,32 @@
 		goto end_rename;
 
 	new_inode = new_dentry->d_inode;
-	new_bh = ext4_find_entry (new_dentry, &new_de);
+	new_bh = ext4_find_entry(new_dir, &new_dentry->d_name, &new_de);
 	if (new_bh) {
 		if (!new_inode) {
-			brelse (new_bh);
+			brelse(new_bh);
 			new_bh = NULL;
 		}
 	}
 	if (S_ISDIR(old_inode->i_mode)) {
 		if (new_inode) {
 			retval = -ENOTEMPTY;
-			if (!empty_dir (new_inode))
+			if (!empty_dir(new_inode))
 				goto end_rename;
 		}
 		retval = -EIO;
-		dir_bh = ext4_bread (handle, old_inode, 0, 0, &retval);
+		dir_bh = ext4_bread(handle, old_inode, 0, 0, &retval);
 		if (!dir_bh)
 			goto end_rename;
 		if (le32_to_cpu(PARENT_INO(dir_bh->b_data)) != old_dir->i_ino)
 			goto end_rename;
 		retval = -EMLINK;
-		if (!new_inode && new_dir!=old_dir &&
+		if (!new_inode && new_dir != old_dir &&
 				new_dir->i_nlink >= EXT4_LINK_MAX)
 			goto end_rename;
 	}
 	if (!new_bh) {
-		retval = ext4_add_entry (handle, new_dentry, old_inode);
+		retval = ext4_add_entry(handle, new_dentry, old_inode);
 		if (retval)
 			goto end_rename;
 	} else {
@@ -2388,7 +2390,7 @@
 		struct buffer_head *old_bh2;
 		struct ext4_dir_entry_2 *old_de2;
 
-		old_bh2 = ext4_find_entry(old_dentry, &old_de2);
+		old_bh2 = ext4_find_entry(old_dir, &old_dentry->d_name, &old_de2);
 		if (old_bh2) {
 			retval = ext4_delete_entry(handle, old_dir,
 						   old_de2, old_bh2);
@@ -2433,9 +2435,9 @@
 	retval = 0;
 
 end_rename:
-	brelse (dir_bh);
-	brelse (old_bh);
-	brelse (new_bh);
+	brelse(dir_bh);
+	brelse(old_bh);
+	brelse(new_bh);
 	ext4_journal_stop(handle);
 	return retval;
 }
@@ -2454,7 +2456,7 @@
 	.mknod		= ext4_mknod,
 	.rename		= ext4_rename,
 	.setattr	= ext4_setattr,
-#ifdef CONFIG_EXT4DEV_FS_XATTR
+#ifdef CONFIG_EXT4_FS_XATTR
 	.setxattr	= generic_setxattr,
 	.getxattr	= generic_getxattr,
 	.listxattr	= ext4_listxattr,
@@ -2465,7 +2467,7 @@
 
 const struct inode_operations ext4_special_inode_operations = {
 	.setattr	= ext4_setattr,
-#ifdef CONFIG_EXT4DEV_FS_XATTR
+#ifdef CONFIG_EXT4_FS_XATTR
 	.setxattr	= generic_setxattr,
 	.getxattr	= generic_getxattr,
 	.listxattr	= ext4_listxattr,
diff --git a/fs/ext4/resize.c b/fs/ext4/resize.c
index b3d3560..b6ec184 100644
--- a/fs/ext4/resize.c
+++ b/fs/ext4/resize.c
@@ -416,8 +416,8 @@
 		       "EXT4-fs: ext4_add_new_gdb: adding group block %lu\n",
 		       gdb_num);
 
-        /*
-         * If we are not using the primary superblock/GDT copy don't resize,
+	/*
+	 * If we are not using the primary superblock/GDT copy don't resize,
          * because the user tools have no way of handling this.  Probably a
          * bad time to do it anyways.
          */
@@ -870,11 +870,10 @@
 	 * We can allocate memory for mb_alloc based on the new group
 	 * descriptor
 	 */
-	if (test_opt(sb, MBALLOC)) {
-		err = ext4_mb_add_more_groupinfo(sb, input->group, gdp);
-		if (err)
-			goto exit_journal;
-	}
+	err = ext4_mb_add_more_groupinfo(sb, input->group, gdp);
+	if (err)
+		goto exit_journal;
+
 	/*
 	 * Make the new blocks and inodes valid next.  We do this before
 	 * increasing the group count so that once the group is enabled,
@@ -929,6 +928,15 @@
 	percpu_counter_add(&sbi->s_freeinodes_counter,
 			   EXT4_INODES_PER_GROUP(sb));
 
+	if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_FLEX_BG)) {
+		ext4_group_t flex_group;
+		flex_group = ext4_flex_group(sbi, input->group);
+		sbi->s_flex_groups[flex_group].free_blocks +=
+			input->free_blocks_count;
+		sbi->s_flex_groups[flex_group].free_inodes +=
+			EXT4_INODES_PER_GROUP(sb);
+	}
+
 	ext4_journal_dirty_metadata(handle, sbi->s_sbh);
 	sb->s_dirt = 1;
 
@@ -964,7 +972,7 @@
 	ext4_group_t o_groups_count;
 	ext4_grpblk_t last;
 	ext4_grpblk_t add;
-	struct buffer_head * bh;
+	struct buffer_head *bh;
 	handle_t *handle;
 	int err;
 	unsigned long freed_blocks;
@@ -1077,8 +1085,15 @@
 	/*
 	 * Mark mballoc pages as not up to date so that they will be updated
 	 * next time they are loaded by ext4_mb_load_buddy.
+	 *
+	 * XXX Bad, Bad, BAD!!!  We should not be overloading the
+	 * Uptodate flag, particularly on thte bitmap bh, as way of
+	 * hinting to ext4_mb_load_buddy() that it needs to be
+	 * overloaded.  A user could take a LVM snapshot, then do an
+	 * on-line fsck, and clear the uptodate flag, and this would
+	 * not be a bug in userspace, but a bug in the kernel.  FIXME!!!
 	 */
-	if (test_opt(sb, MBALLOC)) {
+	{
 		struct ext4_sb_info *sbi = EXT4_SB(sb);
 		struct inode *inode = sbi->s_buddy_cache;
 		int blocks_per_page;
diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index 566344b..dea8f13 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -34,6 +34,8 @@
 #include <linux/namei.h>
 #include <linux/quotaops.h>
 #include <linux/seq_file.h>
+#include <linux/proc_fs.h>
+#include <linux/marker.h>
 #include <linux/log2.h>
 #include <linux/crc16.h>
 #include <asm/uaccess.h>
@@ -45,6 +47,8 @@
 #include "namei.h"
 #include "group.h"
 
+struct proc_dir_entry *ext4_proc_root;
+
 static int ext4_load_journal(struct super_block *, struct ext4_super_block *,
 			     unsigned long journal_devnum);
 static int ext4_create_journal(struct super_block *, struct ext4_super_block *,
@@ -503,15 +507,18 @@
 	ext4_mb_release(sb);
 	ext4_ext_release(sb);
 	ext4_xattr_put_super(sb);
-	jbd2_journal_destroy(sbi->s_journal);
+	if (jbd2_journal_destroy(sbi->s_journal) < 0)
+		ext4_abort(sb, __func__, "Couldn't clean up the journal");
 	sbi->s_journal = NULL;
 	if (!(sb->s_flags & MS_RDONLY)) {
 		EXT4_CLEAR_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER);
 		es->s_state = cpu_to_le16(sbi->s_mount_state);
-		BUFFER_TRACE(sbi->s_sbh, "marking dirty");
-		mark_buffer_dirty(sbi->s_sbh);
 		ext4_commit_super(sb, es, 1);
 	}
+	if (sbi->s_proc) {
+		remove_proc_entry("inode_readahead_blks", sbi->s_proc);
+		remove_proc_entry(sb->s_id, ext4_proc_root);
+	}
 
 	for (i = 0; i < sbi->s_gdb_count; i++)
 		brelse(sbi->s_group_desc[i]);
@@ -520,6 +527,7 @@
 	percpu_counter_destroy(&sbi->s_freeblocks_counter);
 	percpu_counter_destroy(&sbi->s_freeinodes_counter);
 	percpu_counter_destroy(&sbi->s_dirs_counter);
+	percpu_counter_destroy(&sbi->s_dirtyblocks_counter);
 	brelse(sbi->s_sbh);
 #ifdef CONFIG_QUOTA
 	for (i = 0; i < MAXQUOTAS; i++)
@@ -562,11 +570,10 @@
 	ei = kmem_cache_alloc(ext4_inode_cachep, GFP_NOFS);
 	if (!ei)
 		return NULL;
-#ifdef CONFIG_EXT4DEV_FS_POSIX_ACL
+#ifdef CONFIG_EXT4_FS_POSIX_ACL
 	ei->i_acl = EXT4_ACL_NOT_CACHED;
 	ei->i_default_acl = EXT4_ACL_NOT_CACHED;
 #endif
-	ei->i_block_alloc_info = NULL;
 	ei->vfs_inode.i_version = 1;
 	ei->vfs_inode.i_data.writeback_index = 0;
 	memset(&ei->i_cached_extent, 0, sizeof(struct ext4_ext_cache));
@@ -599,7 +606,7 @@
 	struct ext4_inode_info *ei = (struct ext4_inode_info *) foo;
 
 	INIT_LIST_HEAD(&ei->i_orphan);
-#ifdef CONFIG_EXT4DEV_FS_XATTR
+#ifdef CONFIG_EXT4_FS_XATTR
 	init_rwsem(&ei->xattr_sem);
 #endif
 	init_rwsem(&ei->i_data_sem);
@@ -625,8 +632,7 @@
 
 static void ext4_clear_inode(struct inode *inode)
 {
-	struct ext4_block_alloc_info *rsv = EXT4_I(inode)->i_block_alloc_info;
-#ifdef CONFIG_EXT4DEV_FS_POSIX_ACL
+#ifdef CONFIG_EXT4_FS_POSIX_ACL
 	if (EXT4_I(inode)->i_acl &&
 			EXT4_I(inode)->i_acl != EXT4_ACL_NOT_CACHED) {
 		posix_acl_release(EXT4_I(inode)->i_acl);
@@ -638,10 +644,7 @@
 		EXT4_I(inode)->i_default_acl = EXT4_ACL_NOT_CACHED;
 	}
 #endif
-	ext4_discard_reservation(inode);
-	EXT4_I(inode)->i_block_alloc_info = NULL;
-	if (unlikely(rsv))
-		kfree(rsv);
+	ext4_discard_preallocations(inode);
 	jbd2_journal_release_jbd_inode(EXT4_SB(inode->i_sb)->s_journal,
 				       &EXT4_I(inode)->jinode);
 }
@@ -654,7 +657,7 @@
 
 	if (sbi->s_jquota_fmt)
 		seq_printf(seq, ",jqfmt=%s",
-		(sbi->s_jquota_fmt == QFMT_VFS_OLD) ? "vfsold": "vfsv0");
+		(sbi->s_jquota_fmt == QFMT_VFS_OLD) ? "vfsold" : "vfsv0");
 
 	if (sbi->s_qf_names[USRQUOTA])
 		seq_printf(seq, ",usrjquota=%s", sbi->s_qf_names[USRQUOTA]);
@@ -718,7 +721,7 @@
 		seq_puts(seq, ",debug");
 	if (test_opt(sb, OLDALLOC))
 		seq_puts(seq, ",oldalloc");
-#ifdef CONFIG_EXT4DEV_FS_XATTR
+#ifdef CONFIG_EXT4_FS_XATTR
 	if (test_opt(sb, XATTR_USER) &&
 		!(def_mount_opts & EXT4_DEFM_XATTR_USER))
 		seq_puts(seq, ",user_xattr");
@@ -727,7 +730,7 @@
 		seq_puts(seq, ",nouser_xattr");
 	}
 #endif
-#ifdef CONFIG_EXT4DEV_FS_POSIX_ACL
+#ifdef CONFIG_EXT4_FS_POSIX_ACL
 	if (test_opt(sb, POSIX_ACL) && !(def_mount_opts & EXT4_DEFM_ACL))
 		seq_puts(seq, ",acl");
 	if (!test_opt(sb, POSIX_ACL) && (def_mount_opts & EXT4_DEFM_ACL))
@@ -752,8 +755,6 @@
 		seq_puts(seq, ",nobh");
 	if (!test_opt(sb, EXTENTS))
 		seq_puts(seq, ",noextents");
-	if (!test_opt(sb, MBALLOC))
-		seq_puts(seq, ",nomballoc");
 	if (test_opt(sb, I_VERSION))
 		seq_puts(seq, ",i_version");
 	if (!test_opt(sb, DELALLOC))
@@ -773,6 +774,13 @@
 	else if (test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_WRITEBACK_DATA)
 		seq_puts(seq, ",data=writeback");
 
+	if (sbi->s_inode_readahead_blks != EXT4_DEF_INODE_READAHEAD_BLKS)
+		seq_printf(seq, ",inode_readahead_blks=%u",
+			   sbi->s_inode_readahead_blks);
+
+	if (test_opt(sb, DATA_ERR_ABORT))
+		seq_puts(seq, ",data_err=abort");
+
 	ext4_show_quota_options(seq, sb);
 	return 0;
 }
@@ -822,7 +830,7 @@
 }
 
 #ifdef CONFIG_QUOTA
-#define QTYPE2NAME(t) ((t) == USRQUOTA?"user":"group")
+#define QTYPE2NAME(t) ((t) == USRQUOTA ? "user" : "group")
 #define QTYPE2MOPT(on, t) ((t) == USRQUOTA?((on)##USRJQUOTA):((on)##GRPJQUOTA))
 
 static int ext4_dquot_initialize(struct inode *inode, int type);
@@ -902,14 +910,16 @@
 	Opt_commit, Opt_journal_update, Opt_journal_inum, Opt_journal_dev,
 	Opt_journal_checksum, Opt_journal_async_commit,
 	Opt_abort, Opt_data_journal, Opt_data_ordered, Opt_data_writeback,
+	Opt_data_err_abort, Opt_data_err_ignore,
 	Opt_usrjquota, Opt_grpjquota, Opt_offusrjquota, Opt_offgrpjquota,
 	Opt_jqfmt_vfsold, Opt_jqfmt_vfsv0, Opt_quota, Opt_noquota,
 	Opt_ignore, Opt_barrier, Opt_err, Opt_resize, Opt_usrquota,
 	Opt_grpquota, Opt_extents, Opt_noextents, Opt_i_version,
 	Opt_mballoc, Opt_nomballoc, Opt_stripe, Opt_delalloc, Opt_nodelalloc,
+	Opt_inode_readahead_blks
 };
 
-static match_table_t tokens = {
+static const match_table_t tokens = {
 	{Opt_bsd_df, "bsddf"},
 	{Opt_minix_df, "minixdf"},
 	{Opt_grpid, "grpid"},
@@ -947,6 +957,8 @@
 	{Opt_data_journal, "data=journal"},
 	{Opt_data_ordered, "data=ordered"},
 	{Opt_data_writeback, "data=writeback"},
+	{Opt_data_err_abort, "data_err=abort"},
+	{Opt_data_err_ignore, "data_err=ignore"},
 	{Opt_offusrjquota, "usrjquota="},
 	{Opt_usrjquota, "usrjquota=%s"},
 	{Opt_offgrpjquota, "grpjquota="},
@@ -967,6 +979,7 @@
 	{Opt_resize, "resize"},
 	{Opt_delalloc, "delalloc"},
 	{Opt_nodelalloc, "nodelalloc"},
+	{Opt_inode_readahead_blks, "inode_readahead_blks=%u"},
 	{Opt_err, NULL},
 };
 
@@ -981,7 +994,7 @@
 	/*todo: use simple_strtoll with >32bit ext4 */
 	sb_block = simple_strtoul(options, &options, 0);
 	if (*options && *options != ',') {
-		printk("EXT4-fs: Invalid sb specification: %s\n",
+		printk(KERN_ERR "EXT4-fs: Invalid sb specification: %s\n",
 		       (char *) *data);
 		return 1;
 	}
@@ -1072,7 +1085,7 @@
 		case Opt_orlov:
 			clear_opt(sbi->s_mount_opt, OLDALLOC);
 			break;
-#ifdef CONFIG_EXT4DEV_FS_XATTR
+#ifdef CONFIG_EXT4_FS_XATTR
 		case Opt_user_xattr:
 			set_opt(sbi->s_mount_opt, XATTR_USER);
 			break;
@@ -1082,10 +1095,11 @@
 #else
 		case Opt_user_xattr:
 		case Opt_nouser_xattr:
-			printk("EXT4 (no)user_xattr options not supported\n");
+			printk(KERN_ERR "EXT4 (no)user_xattr options "
+			       "not supported\n");
 			break;
 #endif
-#ifdef CONFIG_EXT4DEV_FS_POSIX_ACL
+#ifdef CONFIG_EXT4_FS_POSIX_ACL
 		case Opt_acl:
 			set_opt(sbi->s_mount_opt, POSIX_ACL);
 			break;
@@ -1095,7 +1109,8 @@
 #else
 		case Opt_acl:
 		case Opt_noacl:
-			printk("EXT4 (no)acl options not supported\n");
+			printk(KERN_ERR "EXT4 (no)acl options "
+			       "not supported\n");
 			break;
 #endif
 		case Opt_reservation:
@@ -1178,6 +1193,12 @@
 				sbi->s_mount_opt |= data_opt;
 			}
 			break;
+		case Opt_data_err_abort:
+			set_opt(sbi->s_mount_opt, DATA_ERR_ABORT);
+			break;
+		case Opt_data_err_ignore:
+			clear_opt(sbi->s_mount_opt, DATA_ERR_ABORT);
+			break;
 #ifdef CONFIG_QUOTA
 		case Opt_usrjquota:
 			qtype = USRQUOTA;
@@ -1189,8 +1210,8 @@
 			     sb_any_quota_suspended(sb)) &&
 			    !sbi->s_qf_names[qtype]) {
 				printk(KERN_ERR
-					"EXT4-fs: Cannot change journaled "
-					"quota options when quota turned on.\n");
+				       "EXT4-fs: Cannot change journaled "
+				       "quota options when quota turned on.\n");
 				return 0;
 			}
 			qname = match_strdup(&args[0]);
@@ -1357,12 +1378,6 @@
 		case Opt_nodelalloc:
 			clear_opt(sbi->s_mount_opt, DELALLOC);
 			break;
-		case Opt_mballoc:
-			set_opt(sbi->s_mount_opt, MBALLOC);
-			break;
-		case Opt_nomballoc:
-			clear_opt(sbi->s_mount_opt, MBALLOC);
-			break;
 		case Opt_stripe:
 			if (match_int(&args[0], &option))
 				return 0;
@@ -1373,6 +1388,13 @@
 		case Opt_delalloc:
 			set_opt(sbi->s_mount_opt, DELALLOC);
 			break;
+		case Opt_inode_readahead_blks:
+			if (match_int(&args[0], &option))
+				return 0;
+			if (option < 0 || option > (1 << 30))
+				return 0;
+			sbi->s_inode_readahead_blks = option;
+			break;
 		default:
 			printk(KERN_ERR
 			       "EXT4-fs: Unrecognized mount option \"%s\" "
@@ -1473,15 +1495,9 @@
 			EXT4_INODES_PER_GROUP(sb),
 			sbi->s_mount_opt);
 
-	printk(KERN_INFO "EXT4 FS on %s, ", sb->s_id);
-	if (EXT4_SB(sb)->s_journal->j_inode == NULL) {
-		char b[BDEVNAME_SIZE];
-
-		printk("external journal on %s\n",
-			bdevname(EXT4_SB(sb)->s_journal->j_dev, b));
-	} else {
-		printk("internal journal\n");
-	}
+	printk(KERN_INFO "EXT4 FS on %s, %s journal on %s\n",
+	       sb->s_id, EXT4_SB(sb)->s_journal->j_inode ? "internal" :
+	       "external", EXT4_SB(sb)->s_journal->j_devname);
 	return res;
 }
 
@@ -1504,8 +1520,11 @@
 	sbi->s_log_groups_per_flex = sbi->s_es->s_log_groups_per_flex;
 	groups_per_flex = 1 << sbi->s_log_groups_per_flex;
 
-	flex_group_count = (sbi->s_groups_count + groups_per_flex - 1) /
-		groups_per_flex;
+	/* We allocate both existing and potentially added groups */
+	flex_group_count = ((sbi->s_groups_count + groups_per_flex - 1) +
+			    ((sbi->s_es->s_reserved_gdt_blocks +1 ) <<
+			      EXT4_DESC_PER_BLOCK_BITS(sb))) /
+			   groups_per_flex;
 	sbi->s_flex_groups = kzalloc(flex_group_count *
 				     sizeof(struct flex_groups), GFP_KERNEL);
 	if (sbi->s_flex_groups == NULL) {
@@ -1584,7 +1603,7 @@
 	if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_FLEX_BG))
 		flexbg_flag = 1;
 
-	ext4_debug ("Checking group descriptors");
+	ext4_debug("Checking group descriptors");
 
 	for (i = 0; i < sbi->s_groups_count; i++) {
 		struct ext4_group_desc *gdp = ext4_get_group_desc(sb, i, NULL);
@@ -1623,8 +1642,10 @@
 			       "Checksum for group %lu failed (%u!=%u)\n",
 			       i, le16_to_cpu(ext4_group_desc_csum(sbi, i,
 			       gdp)), le16_to_cpu(gdp->bg_checksum));
-			if (!(sb->s_flags & MS_RDONLY))
+			if (!(sb->s_flags & MS_RDONLY)) {
+				spin_unlock(sb_bgl_lock(sbi, i));
 				return 0;
+			}
 		}
 		spin_unlock(sb_bgl_lock(sbi, i));
 		if (!flexbg_flag)
@@ -1714,9 +1735,9 @@
 		DQUOT_INIT(inode);
 		if (inode->i_nlink) {
 			printk(KERN_DEBUG
-				"%s: truncating inode %lu to %Ld bytes\n",
+				"%s: truncating inode %lu to %lld bytes\n",
 				__func__, inode->i_ino, inode->i_size);
-			jbd_debug(2, "truncating inode %lu to %Ld bytes\n",
+			jbd_debug(2, "truncating inode %lu to %lld bytes\n",
 				  inode->i_ino, inode->i_size);
 			ext4_truncate(inode);
 			nr_truncates++;
@@ -1914,6 +1935,7 @@
 	unsigned long journal_devnum = 0;
 	unsigned long def_mount_opts;
 	struct inode *root;
+	char *cp;
 	int ret = -EINVAL;
 	int blocksize;
 	int db_count;
@@ -1930,10 +1952,15 @@
 	sbi->s_mount_opt = 0;
 	sbi->s_resuid = EXT4_DEF_RESUID;
 	sbi->s_resgid = EXT4_DEF_RESGID;
+	sbi->s_inode_readahead_blks = EXT4_DEF_INODE_READAHEAD_BLKS;
 	sbi->s_sb_block = sb_block;
 
 	unlock_kernel();
 
+	/* Cleanup superblock name */
+	for (cp = sb->s_id; (cp = strchr(cp, '/'));)
+		*cp = '!';
+
 	blocksize = sb_min_blocksize(sb, EXT4_MIN_BLOCK_SIZE);
 	if (!blocksize) {
 		printk(KERN_ERR "EXT4-fs: unable to set blocksize\n");
@@ -1973,11 +2000,11 @@
 		set_opt(sbi->s_mount_opt, GRPID);
 	if (def_mount_opts & EXT4_DEFM_UID16)
 		set_opt(sbi->s_mount_opt, NO_UID32);
-#ifdef CONFIG_EXT4DEV_FS_XATTR
+#ifdef CONFIG_EXT4_FS_XATTR
 	if (def_mount_opts & EXT4_DEFM_XATTR_USER)
 		set_opt(sbi->s_mount_opt, XATTR_USER);
 #endif
-#ifdef CONFIG_EXT4DEV_FS_POSIX_ACL
+#ifdef CONFIG_EXT4_FS_POSIX_ACL
 	if (def_mount_opts & EXT4_DEFM_ACL)
 		set_opt(sbi->s_mount_opt, POSIX_ACL);
 #endif
@@ -2012,11 +2039,6 @@
 		ext4_warning(sb, __func__,
 			"extents feature not enabled on this filesystem, "
 			"use tune2fs.\n");
-	/*
-	 * turn on mballoc code by default in ext4 filesystem
-	 * Use -o nomballoc to turn it off
-	 */
-	set_opt(sbi->s_mount_opt, MBALLOC);
 
 	/*
 	 * enable delayed allocation by default
@@ -2041,16 +2063,6 @@
 		       "running e2fsck is recommended\n");
 
 	/*
-	 * Since ext4 is still considered development code, we require
-	 * that the TEST_FILESYS flag in s->flags be set.
-	 */
-	if (!(le32_to_cpu(es->s_flags) & EXT2_FLAGS_TEST_FILESYS)) {
-		printk(KERN_WARNING "EXT4-fs: %s: not marked "
-		       "OK to use with test code.\n", sb->s_id);
-		goto failed_mount;
-	}
-
-	/*
 	 * Check feature flags regardless of the revision level, since we
 	 * previously didn't change the revision level when setting the flags,
 	 * so there is a chance incompat flags are set on a rev 0 filesystem.
@@ -2219,6 +2231,16 @@
 		goto failed_mount;
 	}
 
+#ifdef CONFIG_PROC_FS
+	if (ext4_proc_root)
+		sbi->s_proc = proc_mkdir(sb->s_id, ext4_proc_root);
+
+	if (sbi->s_proc)
+		proc_create_data("inode_readahead_blks", 0644, sbi->s_proc,
+				 &ext4_ui_proc_fops,
+				 &sbi->s_inode_readahead_blks);
+#endif
+
 	bgl_lock_init(&sbi->s_blockgroup_lock);
 
 	for (i = 0; i < db_count; i++) {
@@ -2257,24 +2279,14 @@
 		err = percpu_counter_init(&sbi->s_dirs_counter,
 				ext4_count_dirs(sb));
 	}
+	if (!err) {
+		err = percpu_counter_init(&sbi->s_dirtyblocks_counter, 0);
+	}
 	if (err) {
 		printk(KERN_ERR "EXT4-fs: insufficient memory\n");
 		goto failed_mount3;
 	}
 
-	/* per fileystem reservation list head & lock */
-	spin_lock_init(&sbi->s_rsv_window_lock);
-	sbi->s_rsv_window_root = RB_ROOT;
-	/* Add a single, static dummy reservation to the start of the
-	 * reservation window list --- it gives us a placeholder for
-	 * append-at-start-of-list which makes the allocation logic
-	 * _much_ simpler. */
-	sbi->s_rsv_window_head.rsv_start = EXT4_RESERVE_WINDOW_NOT_ALLOCATED;
-	sbi->s_rsv_window_head.rsv_end = EXT4_RESERVE_WINDOW_NOT_ALLOCATED;
-	sbi->s_rsv_window_head.rsv_alloc_hit = 0;
-	sbi->s_rsv_window_head.rsv_goal_size = 0;
-	ext4_rsv_window_add(sb, &sbi->s_rsv_window_head);
-
 	sbi->s_stripe = ext4_get_stripe_size(sbi);
 
 	/*
@@ -2471,7 +2483,12 @@
 		printk(KERN_INFO "EXT4-fs: delayed allocation enabled\n");
 
 	ext4_ext_init(sb);
-	ext4_mb_init(sb, needs_recovery);
+	err = ext4_mb_init(sb, needs_recovery);
+	if (err) {
+		printk(KERN_ERR "EXT4-fs: failed to initalize mballoc (%d)\n",
+		       err);
+		goto failed_mount4;
+	}
 
 	lock_kernel();
 	return 0;
@@ -2489,11 +2506,16 @@
 	percpu_counter_destroy(&sbi->s_freeblocks_counter);
 	percpu_counter_destroy(&sbi->s_freeinodes_counter);
 	percpu_counter_destroy(&sbi->s_dirs_counter);
+	percpu_counter_destroy(&sbi->s_dirtyblocks_counter);
 failed_mount2:
 	for (i = 0; i < db_count; i++)
 		brelse(sbi->s_group_desc[i]);
 	kfree(sbi->s_group_desc);
 failed_mount:
+	if (sbi->s_proc) {
+		remove_proc_entry("inode_readahead_blks", sbi->s_proc);
+		remove_proc_entry(sb->s_id, ext4_proc_root);
+	}
 #ifdef CONFIG_QUOTA
 	for (i = 0; i < MAXQUOTAS; i++)
 		kfree(sbi->s_qf_names[i]);
@@ -2527,6 +2549,10 @@
 		journal->j_flags |= JBD2_BARRIER;
 	else
 		journal->j_flags &= ~JBD2_BARRIER;
+	if (test_opt(sb, DATA_ERR_ABORT))
+		journal->j_flags |= JBD2_ABORT_ON_SYNCDATA_ERR;
+	else
+		journal->j_flags &= ~JBD2_ABORT_ON_SYNCDATA_ERR;
 	spin_unlock(&journal->j_state_lock);
 }
 
@@ -2552,7 +2578,7 @@
 		return NULL;
 	}
 
-	jbd_debug(2, "Journal inode found at %p: %Ld bytes\n",
+	jbd_debug(2, "Journal inode found at %p: %lld bytes\n",
 		  journal_inode, journal_inode->i_size);
 	if (!S_ISREG(journal_inode->i_mode)) {
 		printk(KERN_ERR "EXT4-fs: invalid journal inode.\n");
@@ -2715,6 +2741,11 @@
 			return -EINVAL;
 	}
 
+	if (journal->j_flags & JBD2_BARRIER)
+		printk(KERN_INFO "EXT4-fs: barriers enabled\n");
+	else
+		printk(KERN_INFO "EXT4-fs: barriers disabled\n");
+
 	if (!really_read_only && test_opt(sb, UPDATE_JOURNAL)) {
 		err = jbd2_journal_update_format(journal);
 		if (err)  {
@@ -2799,13 +2830,34 @@
 
 	if (!sbh)
 		return;
+	if (buffer_write_io_error(sbh)) {
+		/*
+		 * Oh, dear.  A previous attempt to write the
+		 * superblock failed.  This could happen because the
+		 * USB device was yanked out.  Or it could happen to
+		 * be a transient write error and maybe the block will
+		 * be remapped.  Nothing we can do but to retry the
+		 * write and hope for the best.
+		 */
+		printk(KERN_ERR "ext4: previous I/O error to "
+		       "superblock detected for %s.\n", sb->s_id);
+		clear_buffer_write_io_error(sbh);
+		set_buffer_uptodate(sbh);
+	}
 	es->s_wtime = cpu_to_le32(get_seconds());
 	ext4_free_blocks_count_set(es, ext4_count_free_blocks(sb));
 	es->s_free_inodes_count = cpu_to_le32(ext4_count_free_inodes(sb));
 	BUFFER_TRACE(sbh, "marking dirty");
 	mark_buffer_dirty(sbh);
-	if (sync)
+	if (sync) {
 		sync_dirty_buffer(sbh);
+		if (buffer_write_io_error(sbh)) {
+			printk(KERN_ERR "ext4: I/O error while writing "
+			       "superblock for %s.\n", sb->s_id);
+			clear_buffer_write_io_error(sbh);
+			set_buffer_uptodate(sbh);
+		}
+	}
 }
 
 
@@ -2820,7 +2872,9 @@
 	journal_t *journal = EXT4_SB(sb)->s_journal;
 
 	jbd2_journal_lock_updates(journal);
-	jbd2_journal_flush(journal);
+	if (jbd2_journal_flush(journal) < 0)
+		goto out;
+
 	lock_super(sb);
 	if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER) &&
 	    sb->s_flags & MS_RDONLY) {
@@ -2829,6 +2883,8 @@
 		ext4_commit_super(sb, es, 1);
 	}
 	unlock_super(sb);
+
+out:
 	jbd2_journal_unlock_updates(journal);
 }
 
@@ -2907,6 +2963,7 @@
 {
 	tid_t target;
 
+	trace_mark(ext4_sync_fs, "dev %s wait %d", sb->s_id, wait);
 	sb->s_dirt = 0;
 	if (jbd2_journal_start_commit(EXT4_SB(sb)->s_journal, &target)) {
 		if (wait)
@@ -2928,7 +2985,13 @@
 
 		/* Now we set up the journal barrier. */
 		jbd2_journal_lock_updates(journal);
-		jbd2_journal_flush(journal);
+
+		/*
+		 * We don't want to clear needs_recovery flag when we failed
+		 * to flush the journal.
+		 */
+		if (jbd2_journal_flush(journal) < 0)
+			return;
 
 		/* Journal blocked and flushed, clear needs_recovery flag. */
 		EXT4_CLEAR_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER);
@@ -3162,7 +3225,8 @@
 	buf->f_type = EXT4_SUPER_MAGIC;
 	buf->f_bsize = sb->s_blocksize;
 	buf->f_blocks = ext4_blocks_count(es) - sbi->s_overhead_last;
-	buf->f_bfree = percpu_counter_sum_positive(&sbi->s_freeblocks_counter);
+	buf->f_bfree = percpu_counter_sum_positive(&sbi->s_freeblocks_counter) -
+		       percpu_counter_sum_positive(&sbi->s_dirtyblocks_counter);
 	ext4_free_blocks_count_set(es, buf->f_bfree);
 	buf->f_bavail = buf->f_bfree - ext4_r_blocks_count(es);
 	if (buf->f_bfree < ext4_r_blocks_count(es))
@@ -3367,8 +3431,12 @@
 		 * otherwise be livelocked...
 		 */
 		jbd2_journal_lock_updates(EXT4_SB(sb)->s_journal);
-		jbd2_journal_flush(EXT4_SB(sb)->s_journal);
+		err = jbd2_journal_flush(EXT4_SB(sb)->s_journal);
 		jbd2_journal_unlock_updates(EXT4_SB(sb)->s_journal);
+		if (err) {
+			path_put(&nd.path);
+			return err;
+		}
 	}
 
 	err = vfs_quota_on_path(sb, type, format_id, &nd.path);
@@ -3432,7 +3500,7 @@
 	handle_t *handle = journal_current_handle();
 
 	if (!handle) {
-		printk(KERN_WARNING "EXT4-fs: Quota write (off=%Lu, len=%Lu)"
+		printk(KERN_WARNING "EXT4-fs: Quota write (off=%llu, len=%llu)"
 			" cancelled because transaction is not started.\n",
 			(unsigned long long)off, (unsigned long long)len);
 		return -EIO;
@@ -3493,18 +3561,82 @@
 	return get_sb_bdev(fs_type, flags, dev_name, data, ext4_fill_super, mnt);
 }
 
-static struct file_system_type ext4dev_fs_type = {
+#ifdef CONFIG_PROC_FS
+static int ext4_ui_proc_show(struct seq_file *m, void *v)
+{
+	unsigned int *p = m->private;
+
+	seq_printf(m, "%u\n", *p);
+	return 0;
+}
+
+static int ext4_ui_proc_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, ext4_ui_proc_show, PDE(inode)->data);
+}
+
+static ssize_t ext4_ui_proc_write(struct file *file, const char __user *buf,
+			       size_t cnt, loff_t *ppos)
+{
+	unsigned int *p = PDE(file->f_path.dentry->d_inode)->data;
+	char str[32];
+	unsigned long value;
+
+	if (cnt >= sizeof(str))
+		return -EINVAL;
+	if (copy_from_user(str, buf, cnt))
+		return -EFAULT;
+	value = simple_strtol(str, NULL, 0);
+	if (value < 0)
+		return -ERANGE;
+	*p = value;
+	return cnt;
+}
+
+const struct file_operations ext4_ui_proc_fops = {
 	.owner		= THIS_MODULE,
-	.name		= "ext4dev",
+	.open		= ext4_ui_proc_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= single_release,
+	.write		= ext4_ui_proc_write,
+};
+#endif
+
+static struct file_system_type ext4_fs_type = {
+	.owner		= THIS_MODULE,
+	.name		= "ext4",
 	.get_sb		= ext4_get_sb,
 	.kill_sb	= kill_block_super,
 	.fs_flags	= FS_REQUIRES_DEV,
 };
 
+#ifdef CONFIG_EXT4DEV_COMPAT
+static int ext4dev_get_sb(struct file_system_type *fs_type,
+	int flags, const char *dev_name, void *data, struct vfsmount *mnt)
+{
+	printk(KERN_WARNING "EXT4-fs: Update your userspace programs "
+	       "to mount using ext4\n");
+	printk(KERN_WARNING "EXT4-fs: ext4dev backwards compatibility "
+	       "will go away by 2.6.31\n");
+	return get_sb_bdev(fs_type, flags, dev_name, data, ext4_fill_super, mnt);
+}
+
+static struct file_system_type ext4dev_fs_type = {
+	.owner		= THIS_MODULE,
+	.name		= "ext4dev",
+	.get_sb		= ext4dev_get_sb,
+	.kill_sb	= kill_block_super,
+	.fs_flags	= FS_REQUIRES_DEV,
+};
+MODULE_ALIAS("ext4dev");
+#endif
+
 static int __init init_ext4_fs(void)
 {
 	int err;
 
+	ext4_proc_root = proc_mkdir("fs/ext4", NULL);
 	err = init_ext4_mballoc();
 	if (err)
 		return err;
@@ -3515,9 +3647,16 @@
 	err = init_inodecache();
 	if (err)
 		goto out1;
-	err = register_filesystem(&ext4dev_fs_type);
+	err = register_filesystem(&ext4_fs_type);
 	if (err)
 		goto out;
+#ifdef CONFIG_EXT4DEV_COMPAT
+	err = register_filesystem(&ext4dev_fs_type);
+	if (err) {
+		unregister_filesystem(&ext4_fs_type);
+		goto out;
+	}
+#endif
 	return 0;
 out:
 	destroy_inodecache();
@@ -3530,10 +3669,14 @@
 
 static void __exit exit_ext4_fs(void)
 {
+	unregister_filesystem(&ext4_fs_type);
+#ifdef CONFIG_EXT4DEV_COMPAT
 	unregister_filesystem(&ext4dev_fs_type);
+#endif
 	destroy_inodecache();
 	exit_ext4_xattr();
 	exit_ext4_mballoc();
+	remove_proc_entry("fs/ext4", NULL);
 }
 
 MODULE_AUTHOR("Remy Card, Stephen Tweedie, Andrew Morton, Andreas Dilger, Theodore Ts'o and others");
diff --git a/fs/ext4/symlink.c b/fs/ext4/symlink.c
index e917864..00740cb 100644
--- a/fs/ext4/symlink.c
+++ b/fs/ext4/symlink.c
@@ -23,10 +23,10 @@
 #include "ext4.h"
 #include "xattr.h"
 
-static void * ext4_follow_link(struct dentry *dentry, struct nameidata *nd)
+static void *ext4_follow_link(struct dentry *dentry, struct nameidata *nd)
 {
 	struct ext4_inode_info *ei = EXT4_I(dentry->d_inode);
-	nd_set_link(nd, (char*)ei->i_data);
+	nd_set_link(nd, (char *) ei->i_data);
 	return NULL;
 }
 
@@ -34,7 +34,7 @@
 	.readlink	= generic_readlink,
 	.follow_link	= page_follow_link_light,
 	.put_link	= page_put_link,
-#ifdef CONFIG_EXT4DEV_FS_XATTR
+#ifdef CONFIG_EXT4_FS_XATTR
 	.setxattr	= generic_setxattr,
 	.getxattr	= generic_getxattr,
 	.listxattr	= ext4_listxattr,
@@ -45,7 +45,7 @@
 const struct inode_operations ext4_fast_symlink_inode_operations = {
 	.readlink	= generic_readlink,
 	.follow_link	= ext4_follow_link,
-#ifdef CONFIG_EXT4DEV_FS_XATTR
+#ifdef CONFIG_EXT4_FS_XATTR
 	.setxattr	= generic_setxattr,
 	.getxattr	= generic_getxattr,
 	.listxattr	= ext4_listxattr,
diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c
index 8954208..80626d5 100644
--- a/fs/ext4/xattr.c
+++ b/fs/ext4/xattr.c
@@ -99,12 +99,12 @@
 
 static struct xattr_handler *ext4_xattr_handler_map[] = {
 	[EXT4_XATTR_INDEX_USER]		     = &ext4_xattr_user_handler,
-#ifdef CONFIG_EXT4DEV_FS_POSIX_ACL
+#ifdef CONFIG_EXT4_FS_POSIX_ACL
 	[EXT4_XATTR_INDEX_POSIX_ACL_ACCESS]  = &ext4_xattr_acl_access_handler,
 	[EXT4_XATTR_INDEX_POSIX_ACL_DEFAULT] = &ext4_xattr_acl_default_handler,
 #endif
 	[EXT4_XATTR_INDEX_TRUSTED]	     = &ext4_xattr_trusted_handler,
-#ifdef CONFIG_EXT4DEV_FS_SECURITY
+#ifdef CONFIG_EXT4_FS_SECURITY
 	[EXT4_XATTR_INDEX_SECURITY]	     = &ext4_xattr_security_handler,
 #endif
 };
@@ -112,11 +112,11 @@
 struct xattr_handler *ext4_xattr_handlers[] = {
 	&ext4_xattr_user_handler,
 	&ext4_xattr_trusted_handler,
-#ifdef CONFIG_EXT4DEV_FS_POSIX_ACL
+#ifdef CONFIG_EXT4_FS_POSIX_ACL
 	&ext4_xattr_acl_access_handler,
 	&ext4_xattr_acl_default_handler,
 #endif
-#ifdef CONFIG_EXT4DEV_FS_SECURITY
+#ifdef CONFIG_EXT4_FS_SECURITY
 	&ext4_xattr_security_handler,
 #endif
 	NULL
@@ -959,6 +959,7 @@
 	struct ext4_xattr_block_find bs = {
 		.s = { .not_found = -ENODATA, },
 	};
+	unsigned long no_expand;
 	int error;
 
 	if (!name)
@@ -966,6 +967,9 @@
 	if (strlen(name) > 255)
 		return -ERANGE;
 	down_write(&EXT4_I(inode)->xattr_sem);
+	no_expand = EXT4_I(inode)->i_state & EXT4_STATE_NO_EXPAND;
+	EXT4_I(inode)->i_state |= EXT4_STATE_NO_EXPAND;
+
 	error = ext4_get_inode_loc(inode, &is.iloc);
 	if (error)
 		goto cleanup;
@@ -1042,6 +1046,8 @@
 cleanup:
 	brelse(is.iloc.bh);
 	brelse(bs.bh);
+	if (no_expand == 0)
+		EXT4_I(inode)->i_state &= ~EXT4_STATE_NO_EXPAND;
 	up_write(&EXT4_I(inode)->xattr_sem);
 	return error;
 }
diff --git a/fs/ext4/xattr.h b/fs/ext4/xattr.h
index 5992fe9..8ede88b 100644
--- a/fs/ext4/xattr.h
+++ b/fs/ext4/xattr.h
@@ -51,8 +51,8 @@
 	(((name_len) + EXT4_XATTR_ROUND + \
 	sizeof(struct ext4_xattr_entry)) & ~EXT4_XATTR_ROUND)
 #define EXT4_XATTR_NEXT(entry) \
-	( (struct ext4_xattr_entry *)( \
-	  (char *)(entry) + EXT4_XATTR_LEN((entry)->e_name_len)) )
+	((struct ext4_xattr_entry *)( \
+	 (char *)(entry) + EXT4_XATTR_LEN((entry)->e_name_len)))
 #define EXT4_XATTR_SIZE(size) \
 	(((size) + EXT4_XATTR_ROUND) & ~EXT4_XATTR_ROUND)
 
@@ -63,7 +63,7 @@
 		EXT4_I(inode)->i_extra_isize))
 #define IFIRST(hdr) ((struct ext4_xattr_entry *)((hdr)+1))
 
-# ifdef CONFIG_EXT4DEV_FS_XATTR
+# ifdef CONFIG_EXT4_FS_XATTR
 
 extern struct xattr_handler ext4_xattr_user_handler;
 extern struct xattr_handler ext4_xattr_trusted_handler;
@@ -88,7 +88,7 @@
 
 extern struct xattr_handler *ext4_xattr_handlers[];
 
-# else  /* CONFIG_EXT4DEV_FS_XATTR */
+# else  /* CONFIG_EXT4_FS_XATTR */
 
 static inline int
 ext4_xattr_get(struct inode *inode, int name_index, const char *name,
@@ -141,9 +141,9 @@
 
 #define ext4_xattr_handlers	NULL
 
-# endif  /* CONFIG_EXT4DEV_FS_XATTR */
+# endif  /* CONFIG_EXT4_FS_XATTR */
 
-#ifdef CONFIG_EXT4DEV_FS_SECURITY
+#ifdef CONFIG_EXT4_FS_SECURITY
 extern int ext4_init_security(handle_t *handle, struct inode *inode,
 				struct inode *dir);
 #else
diff --git a/fs/fat/fatent.c b/fs/fat/fatent.c
index 302e95c..fb98b3d 100644
--- a/fs/fat/fatent.c
+++ b/fs/fat/fatent.c
@@ -6,6 +6,7 @@
 #include <linux/module.h>
 #include <linux/fs.h>
 #include <linux/msdos_fs.h>
+#include <linux/blkdev.h>
 
 struct fatent_operations {
 	void (*ent_blocknr)(struct super_block *, int, int *, sector_t *);
@@ -535,6 +536,7 @@
 	struct fat_entry fatent;
 	struct buffer_head *bhs[MAX_BUF_PER_PAGE];
 	int i, err, nr_bhs;
+	int first_cl = cluster;
 
 	nr_bhs = 0;
 	fatent_init(&fatent);
@@ -551,6 +553,18 @@
 			goto error;
 		}
 
+		/* 
+		 * Issue discard for the sectors we no longer care about,
+		 * batching contiguous clusters into one request
+		 */
+		if (cluster != fatent.entry + 1) {
+			int nr_clus = fatent.entry - first_cl + 1;
+
+			sb_issue_discard(sb, fat_clus_to_blknr(sbi, first_cl),
+					 nr_clus * sbi->sec_per_clus);
+			first_cl = cluster;
+		}
+
 		ops->ent_put(&fatent, FAT_ENT_FREE);
 		if (sbi->free_clusters != -1) {
 			sbi->free_clusters++;
diff --git a/fs/fat/inode.c b/fs/fat/inode.c
index 80ff338..d12cdf2 100644
--- a/fs/fat/inode.c
+++ b/fs/fat/inode.c
@@ -855,7 +855,7 @@
 	Opt_obsolate, Opt_flush, Opt_tz_utc, Opt_err,
 };
 
-static match_table_t fat_tokens = {
+static const match_table_t fat_tokens = {
 	{Opt_check_r, "check=relaxed"},
 	{Opt_check_s, "check=strict"},
 	{Opt_check_n, "check=normal"},
@@ -890,14 +890,14 @@
 	{Opt_tz_utc, "tz=UTC"},
 	{Opt_err, NULL},
 };
-static match_table_t msdos_tokens = {
+static const match_table_t msdos_tokens = {
 	{Opt_nodots, "nodots"},
 	{Opt_nodots, "dotsOK=no"},
 	{Opt_dots, "dots"},
 	{Opt_dots, "dotsOK=yes"},
 	{Opt_err, NULL}
 };
-static match_table_t vfat_tokens = {
+static const match_table_t vfat_tokens = {
 	{Opt_charset, "iocharset=%s"},
 	{Opt_shortname_lower, "shortname=lower"},
 	{Opt_shortname_win95, "shortname=win95"},
diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c
index d2249f1..6a84388 100644
--- a/fs/fuse/inode.c
+++ b/fs/fuse/inode.c
@@ -354,7 +354,7 @@
 	OPT_ERR
 };
 
-static match_table_t tokens = {
+static const match_table_t tokens = {
 	{OPT_FD,			"fd=%u"},
 	{OPT_ROOTMODE,			"rootmode=%o"},
 	{OPT_USER_ID,			"user_id=%u"},
diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c
index 13391e5..c962283 100644
--- a/fs/gfs2/glock.c
+++ b/fs/gfs2/glock.c
@@ -1265,6 +1265,8 @@
 	holdtime = gl->gl_tchange + gl->gl_ops->go_min_hold_time;
 	if (time_before(now, holdtime))
 		delay = holdtime - now;
+	if (test_bit(GLF_REPLY_PENDING, &gl->gl_flags))
+		delay = gl->gl_ops->go_min_hold_time;
 
 	spin_lock(&gl->gl_spin);
 	handle_callback(gl, state, 1, delay);
@@ -1578,8 +1580,6 @@
 		*p++ = 'a';
 	if (flags & GL_EXACT)
 		*p++ = 'E';
-	if (flags & GL_ATIME)
-		*p++ = 'a';
 	if (flags & GL_NOCACHE)
 		*p++ = 'c';
 	if (test_bit(HIF_HOLDER, &iflags))
@@ -1816,15 +1816,17 @@
 	if (gl) {
 		gi->gl = hlist_entry(gl->gl_list.next,
 				     struct gfs2_glock, gl_list);
-		if (gi->gl)
-			gfs2_glock_hold(gi->gl);
+	} else {
+		gi->gl = hlist_entry(gl_hash_table[gi->hash].hb_list.first,
+				     struct gfs2_glock, gl_list);
 	}
+	if (gi->gl)
+		gfs2_glock_hold(gi->gl);
 	read_unlock(gl_lock_addr(gi->hash));
 	if (gl)
 		gfs2_glock_put(gl);
-	if (gl && gi->gl == NULL)
-		gi->hash++;
 	while (gi->gl == NULL) {
+		gi->hash++;
 		if (gi->hash >= GFS2_GL_HASH_SIZE)
 			return 1;
 		read_lock(gl_lock_addr(gi->hash));
@@ -1833,7 +1835,6 @@
 		if (gi->gl)
 			gfs2_glock_hold(gi->gl);
 		read_unlock(gl_lock_addr(gi->hash));
-		gi->hash++;
 	}
 
 	if (gi->sdp != gi->gl->gl_sbd)
diff --git a/fs/gfs2/glock.h b/fs/gfs2/glock.h
index 971d92a..695c6b1 100644
--- a/fs/gfs2/glock.h
+++ b/fs/gfs2/glock.h
@@ -24,7 +24,6 @@
 #define GL_ASYNC		0x00000040
 #define GL_EXACT		0x00000080
 #define GL_SKIP			0x00000100
-#define GL_ATIME		0x00000200
 #define GL_NOCACHE		0x00000400
 
 #define GLR_TRYFAILED		13
diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h
index 448697a..f566ec1 100644
--- a/fs/gfs2/incore.h
+++ b/fs/gfs2/incore.h
@@ -386,20 +386,21 @@
 #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 */
+	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 */
+	unsigned int ar_spectator:1;		/* Don't get a journal */
+	unsigned int ar_ignore_local_fs:1;	/* Ignore optimisations */
+	unsigned int ar_localflocks:1;		/* Let the VFS do flock|fcntl */
+	unsigned int ar_localcaching:1;		/* Local caching */
+	unsigned int ar_debug:1;		/* Oops on errors */
+	unsigned int ar_upgrade:1;		/* Upgrade ondisk format */
+	unsigned int ar_posix_acl:1;		/* Enable posix acls */
+	unsigned int ar_quota:2;		/* off/account/on */
+	unsigned int ar_suiddir:1;		/* suiddir support */
+	unsigned int ar_data:2;			/* ordered/writeback */
+	unsigned int ar_meta:1;			/* mount metafs */
+	unsigned int ar_num_glockd;		/* Number of glockd threads */
 };
 
 struct gfs2_tune {
@@ -419,7 +420,6 @@
 	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_max_readahead; /* Max bytes to read-ahead from disk */
 	unsigned int gt_stall_secs; /* Detects trouble! */
@@ -432,7 +432,7 @@
 	SDF_JOURNAL_CHECKED	= 0,
 	SDF_JOURNAL_LIVE	= 1,
 	SDF_SHUTDOWN		= 2,
-	SDF_NOATIME		= 3,
+	SDF_NOBARRIERS		= 3,
 };
 
 #define GFS2_FSNAME_LEN		256
@@ -461,7 +461,6 @@
 
 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_host sd_sb;
@@ -499,7 +498,9 @@
 
 	/* Inode Stuff */
 
-	struct inode *sd_master_dir;
+	struct dentry *sd_master_dir;
+	struct dentry *sd_root_dir;
+
 	struct inode *sd_jindex;
 	struct inode *sd_inum_inode;
 	struct inode *sd_statfs_inode;
@@ -634,7 +635,6 @@
 	/* Debugging crud */
 
 	unsigned long sd_last_warning;
-	struct vfsmount *sd_gfs2mnt;
 	struct dentry *debugfs_dir;    /* debugfs directory */
 	struct dentry *debugfs_dentry_glocks; /* for debugfs */
 };
diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c
index 8b0806a..7cee695 100644
--- a/fs/gfs2/inode.c
+++ b/fs/gfs2/inode.c
@@ -18,6 +18,7 @@
 #include <linux/crc32.h>
 #include <linux/lm_interface.h>
 #include <linux/security.h>
+#include <linux/time.h>
 
 #include "gfs2.h"
 #include "incore.h"
@@ -249,6 +250,7 @@
 {
 	struct gfs2_dinode_host *di = &ip->i_di;
 	const struct gfs2_dinode *str = buf;
+	struct timespec atime;
 	u16 height, depth;
 
 	if (unlikely(ip->i_no_addr != be64_to_cpu(str->di_num.no_addr)))
@@ -275,8 +277,10 @@
 	di->di_size = be64_to_cpu(str->di_size);
 	i_size_write(&ip->i_inode, di->di_size);
 	gfs2_set_inode_blocks(&ip->i_inode, be64_to_cpu(str->di_blocks));
-	ip->i_inode.i_atime.tv_sec = be64_to_cpu(str->di_atime);
-	ip->i_inode.i_atime.tv_nsec = be32_to_cpu(str->di_atime_nsec);
+	atime.tv_sec = be64_to_cpu(str->di_atime);
+	atime.tv_nsec = be32_to_cpu(str->di_atime_nsec);
+	if (timespec_compare(&ip->i_inode.i_atime, &atime) < 0)
+		ip->i_inode.i_atime = atime;
 	ip->i_inode.i_mtime.tv_sec = be64_to_cpu(str->di_mtime);
 	ip->i_inode.i_mtime.tv_nsec = be32_to_cpu(str->di_mtime_nsec);
 	ip->i_inode.i_ctime.tv_sec = be64_to_cpu(str->di_ctime);
@@ -1033,13 +1037,11 @@
 
 	if (bh)
 		brelse(bh);
-	if (!inode)
-		return ERR_PTR(-ENOMEM);
 	return inode;
 
 fail_gunlock2:
 	gfs2_glock_dq_uninit(ghs + 1);
-	if (inode)
+	if (inode && !IS_ERR(inode))
 		iput(inode);
 fail_gunlock:
 	gfs2_glock_dq(ghs);
@@ -1140,54 +1142,6 @@
 	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);
-		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
@@ -1207,8 +1161,8 @@
 	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);
+	gfs2_holder_init(ip->i_gl, LM_ST_SHARED, 0, &i_gh);
+	error = gfs2_glock_nq(&i_gh);
 	if (error) {
 		gfs2_holder_uninit(&i_gh);
 		return error;
@@ -1243,101 +1197,6 @@
 	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 quantum = gfs2_tune_get(sdp, gt_atime_quantum);
-	unsigned int state;
-	int flags;
-	int error;
-	struct timespec tv = CURRENT_TIME;
-
-	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;
-
-	if (tv.tv_sec - ip->i_inode.i_atime.tv_sec >= 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. */
-
-		tv = CURRENT_TIME;
-		if (tv.tv_sec - ip->i_inode.i_atime.tv_sec >= 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_inode.i_atime = tv;
-
-			gfs2_trans_add_bh(ip->i_gl, dibh, 1);
-			di = (struct gfs2_dinode *)dibh->b_data;
-			di->di_atime = cpu_to_be64(ip->i_inode.i_atime.tv_sec);
-			di->di_atime_nsec = cpu_to_be32(ip->i_inode.i_atime.tv_nsec);
-			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;
-}
-
 static int
 __gfs2_setattr_simple(struct gfs2_inode *ip, struct iattr *attr)
 {
diff --git a/fs/gfs2/inode.h b/fs/gfs2/inode.h
index 58f9607..2d43f69 100644
--- a/fs/gfs2/inode.h
+++ b/fs/gfs2/inode.h
@@ -91,9 +91,7 @@
 int gfs2_unlink_ok(struct gfs2_inode *dip, const struct qstr *name,
 		   const struct gfs2_inode *ip);
 int gfs2_permission(struct inode *inode, int mask);
-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_setattr_simple(struct gfs2_inode *ip, struct iattr *attr);
 struct inode *gfs2_lookup_simple(struct inode *dip, const char *name);
 void gfs2_dinode_out(const struct gfs2_inode *ip, void *buf);
diff --git a/fs/gfs2/locking/dlm/mount.c b/fs/gfs2/locking/dlm/mount.c
index 09d78c2..0c4cbe6 100644
--- a/fs/gfs2/locking/dlm/mount.c
+++ b/fs/gfs2/locking/dlm/mount.c
@@ -144,7 +144,8 @@
 
 	error = dlm_new_lockspace(ls->fsname, strlen(ls->fsname),
 				  &ls->dlm_lockspace,
-				  DLM_LSFL_FS | (nodir ? DLM_LSFL_NODIR : 0),
+				  DLM_LSFL_FS | DLM_LSFL_NEWEXCL |
+				  (nodir ? DLM_LSFL_NODIR : 0),
 				  GDLM_LVB_SIZE);
 	if (error) {
 		log_error("dlm_new_lockspace error %d", error);
diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c
index 6c6af9f..ad30585 100644
--- a/fs/gfs2/log.c
+++ b/fs/gfs2/log.c
@@ -18,6 +18,7 @@
 #include <linux/delay.h>
 #include <linux/kthread.h>
 #include <linux/freezer.h>
+#include <linux/bio.h>
 
 #include "gfs2.h"
 #include "incore.h"
@@ -584,7 +585,6 @@
 	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);
@@ -601,8 +601,23 @@
 	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))
+	bh->b_end_io = end_buffer_write_sync;
+	if (test_bit(SDF_NOBARRIERS, &sdp->sd_flags))
+		goto skip_barrier;
+	get_bh(bh);
+	submit_bh(WRITE_BARRIER | (1 << BIO_RW_META), bh);
+	wait_on_buffer(bh);
+	if (buffer_eopnotsupp(bh)) {
+		clear_buffer_eopnotsupp(bh);
+		set_buffer_uptodate(bh);
+		set_bit(SDF_NOBARRIERS, &sdp->sd_flags);
+		lock_buffer(bh);
+skip_barrier:
+		get_bh(bh);
+		submit_bh(WRITE_SYNC | (1 << BIO_RW_META), bh);
+		wait_on_buffer(bh);
+	}
+	if (!buffer_uptodate(bh))
 		gfs2_io_error_bh(sdp, bh);
 	brelse(bh);
 
diff --git a/fs/gfs2/mount.c b/fs/gfs2/mount.c
index b941f9f..f96eb90 100644
--- a/fs/gfs2/mount.c
+++ b/fs/gfs2/mount.c
@@ -42,10 +42,11 @@
 	Opt_nosuiddir,
 	Opt_data_writeback,
 	Opt_data_ordered,
+	Opt_meta,
 	Opt_err,
 };
 
-static match_table_t tokens = {
+static const match_table_t tokens = {
 	{Opt_lockproto, "lockproto=%s"},
 	{Opt_locktable, "locktable=%s"},
 	{Opt_hostdata, "hostdata=%s"},
@@ -66,6 +67,7 @@
 	{Opt_nosuiddir, "nosuiddir"},
 	{Opt_data_writeback, "data=writeback"},
 	{Opt_data_ordered, "data=ordered"},
+	{Opt_meta, "meta"},
 	{Opt_err, NULL}
 };
 
@@ -239,6 +241,11 @@
 		case Opt_data_ordered:
 			args->ar_data = GFS2_DATA_ORDERED;
 			break;
+		case Opt_meta:
+			if (remount && args->ar_meta != 1)
+				goto cant_remount;
+			args->ar_meta = 1;
+			break;
 		case Opt_err:
 		default:
 			fs_info(sdp, "unknown option: %s\n", o);
diff --git a/fs/gfs2/ops_address.c b/fs/gfs2/ops_address.c
index e64a1b0..2756381 100644
--- a/fs/gfs2/ops_address.c
+++ b/fs/gfs2/ops_address.c
@@ -512,8 +512,8 @@
 	int error;
 
 	unlock_page(page);
-	gfs2_holder_init(ip->i_gl, LM_ST_SHARED, GL_ATIME, &gh);
-	error = gfs2_glock_nq_atime(&gh);
+	gfs2_holder_init(ip->i_gl, LM_ST_SHARED, 0, &gh);
+	error = gfs2_glock_nq(&gh);
 	if (unlikely(error))
 		goto out;
 	error = AOP_TRUNCATED_PAGE;
@@ -594,8 +594,8 @@
 	struct gfs2_holder gh;
 	int ret;
 
-	gfs2_holder_init(ip->i_gl, LM_ST_SHARED, GL_ATIME, &gh);
-	ret = gfs2_glock_nq_atime(&gh);
+	gfs2_holder_init(ip->i_gl, LM_ST_SHARED, 0, &gh);
+	ret = gfs2_glock_nq(&gh);
 	if (unlikely(ret))
 		goto out_uninit;
 	if (!gfs2_is_stuffed(ip))
@@ -636,8 +636,8 @@
 	unsigned to = from + len;
 	struct page *page;
 
-	gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, GL_ATIME, &ip->i_gh);
-	error = gfs2_glock_nq_atime(&ip->i_gh);
+	gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &ip->i_gh);
+	error = gfs2_glock_nq(&ip->i_gh);
 	if (unlikely(error))
 		goto out_uninit;
 
@@ -975,7 +975,7 @@
 	if (gfs2_is_stuffed(ip))
 		return 0;
 
-	if (offset > i_size_read(&ip->i_inode))
+	if (offset >= i_size_read(&ip->i_inode))
 		return 0;
 	return 1;
 }
@@ -1000,8 +1000,8 @@
 	 * unfortunately have the option of only flushing a range like
 	 * the VFS does.
 	 */
-	gfs2_holder_init(ip->i_gl, LM_ST_DEFERRED, GL_ATIME, &gh);
-	rv = gfs2_glock_nq_atime(&gh);
+	gfs2_holder_init(ip->i_gl, LM_ST_DEFERRED, 0, &gh);
+	rv = gfs2_glock_nq(&gh);
 	if (rv)
 		return rv;
 	rv = gfs2_ok_for_dio(ip, rw, offset);
diff --git a/fs/gfs2/ops_file.c b/fs/gfs2/ops_file.c
index e9a366d..3a747f8 100644
--- a/fs/gfs2/ops_file.c
+++ b/fs/gfs2/ops_file.c
@@ -89,8 +89,8 @@
 	u64 offset = file->f_pos;
 	int error;
 
-	gfs2_holder_init(dip->i_gl, LM_ST_SHARED, GL_ATIME, &d_gh);
-	error = gfs2_glock_nq_atime(&d_gh);
+	gfs2_holder_init(dip->i_gl, LM_ST_SHARED, 0, &d_gh);
+	error = gfs2_glock_nq(&d_gh);
 	if (error) {
 		gfs2_holder_uninit(&d_gh);
 		return error;
@@ -153,8 +153,8 @@
 	int error;
 	u32 fsflags;
 
-	gfs2_holder_init(ip->i_gl, LM_ST_SHARED, GL_ATIME, &gh);
-	error = gfs2_glock_nq_atime(&gh);
+	gfs2_holder_init(ip->i_gl, LM_ST_SHARED, 0, &gh);
+	error = gfs2_glock_nq(&gh);
 	if (error)
 		return error;
 
@@ -351,8 +351,8 @@
 	struct gfs2_alloc *al;
 	int ret;
 
-	gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, GL_ATIME, &gh);
-	ret = gfs2_glock_nq_atime(&gh);
+	gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh);
+	ret = gfs2_glock_nq(&gh);
 	if (ret)
 		goto out;
 
@@ -434,8 +434,8 @@
 	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);
+	gfs2_holder_init(ip->i_gl, LM_ST_SHARED, 0, &i_gh);
+	error = gfs2_glock_nq(&i_gh);
 	if (error) {
 		gfs2_holder_uninit(&i_gh);
 		return error;
diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c
index b4d1d64..b117fcf 100644
--- a/fs/gfs2/ops_fstype.c
+++ b/fs/gfs2/ops_fstype.c
@@ -40,6 +40,44 @@
 #define DO 0
 #define UNDO 1
 
+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
+ *
+ */
+
+static void gfs2_tune_init(struct gfs2_tune *gt)
+{
+	spin_lock_init(&gt->gt_spin);
+
+	gt->gt_demote_secs = 300;
+	gt->gt_incore_log_blocks = 1024;
+	gt->gt_log_flush_secs = 60;
+	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_new_files_jdata = 0;
+	gt->gt_max_readahead = 1 << 18;
+	gt->gt_stall_secs = 600;
+	gt->gt_complain_secs = 10;
+	gt->gt_statfs_quantum = 30;
+	gt->gt_statfs_slow = 0;
+}
+
 static struct gfs2_sbd *init_sbd(struct super_block *sb)
 {
 	struct gfs2_sbd *sdp;
@@ -96,21 +134,271 @@
 	return sdp;
 }
 
-static void init_vfs(struct super_block *sb, unsigned noatime)
+
+/**
+ * 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.
+ */
+
+static int gfs2_check_sb(struct gfs2_sbd *sdp, struct gfs2_sb_host *sb, int silent)
 {
-	struct gfs2_sbd *sdp = sb->s_fs_info;
+	unsigned int x;
 
-	sb->s_magic = GFS2_MAGIC;
-	sb->s_op = &gfs2_super_ops;
-	sb->s_export_op = &gfs2_export_ops;
-	sb->s_time_gran = 1;
-	sb->s_maxbytes = MAX_LFS_FILESIZE;
+	if (sb->sb_magic != GFS2_MAGIC ||
+	    sb->sb_type != GFS2_METATYPE_SB) {
+		if (!silent)
+			printk(KERN_WARNING "GFS2: not a GFS2 filesystem\n");
+		return -EINVAL;
+	}
 
-	if (sb->s_flags & (MS_NOATIME | MS_NODIRATIME))
-		set_bit(noatime, &sdp->sd_flags);
+	/*  If format numbers match exactly, we're done.  */
 
-	/* Don't let the VFS update atimes.  GFS2 handles this itself. */
-	sb->s_flags |= MS_NOATIME | MS_NODIRATIME;
+	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 void end_bio_io_page(struct bio *bio, int error)
+{
+	struct page *page = bio->bi_private;
+
+	if (!error)
+		SetPageUptodate(page);
+	else
+		printk(KERN_WARNING "gfs2: error %d reading superblock\n", error);
+	unlock_page(page);
+}
+
+static void gfs2_sb_in(struct gfs2_sb_host *sb, const void *buf)
+{
+	const struct gfs2_sb *str = buf;
+
+	sb->sb_magic = be32_to_cpu(str->sb_header.mh_magic);
+	sb->sb_type = be32_to_cpu(str->sb_header.mh_type);
+	sb->sb_format = be32_to_cpu(str->sb_header.mh_format);
+	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);
+	sb->sb_master_dir.no_addr = be64_to_cpu(str->sb_master_dir.no_addr);
+	sb->sb_master_dir.no_formal_ino = be64_to_cpu(str->sb_master_dir.no_formal_ino);
+	sb->sb_root_dir.no_addr = be64_to_cpu(str->sb_root_dir.no_addr);
+	sb->sb_root_dir.no_formal_ino = be64_to_cpu(str->sb_root_dir.no_formal_ino);
+
+	memcpy(sb->sb_lockproto, str->sb_lockproto, GFS2_LOCKNAME_LEN);
+	memcpy(sb->sb_locktable, str->sb_locktable, GFS2_LOCKNAME_LEN);
+}
+
+/**
+ * gfs2_read_super - Read the gfs2 super block from disk
+ * @sdp: The GFS2 super block
+ * @sector: The location of the super block
+ * @error: The error code to return
+ *
+ * This uses the bio functions to read the super block from disk
+ * because we want to be 100% sure that we never read cached data.
+ * A super block is read twice only during each GFS2 mount and is
+ * never written to by the filesystem. The first time its read no
+ * locks are held, and the only details which are looked at are those
+ * relating to the locking protocol. Once locking is up and working,
+ * the sb is read again under the lock to establish the location of
+ * the master directory (contains pointers to journals etc) and the
+ * root directory.
+ *
+ * Returns: 0 on success or error
+ */
+
+static int gfs2_read_super(struct gfs2_sbd *sdp, sector_t sector)
+{
+	struct super_block *sb = sdp->sd_vfs;
+	struct gfs2_sb *p;
+	struct page *page;
+	struct bio *bio;
+
+	page = alloc_page(GFP_NOFS);
+	if (unlikely(!page))
+		return -ENOBUFS;
+
+	ClearPageUptodate(page);
+	ClearPageDirty(page);
+	lock_page(page);
+
+	bio = bio_alloc(GFP_NOFS, 1);
+	if (unlikely(!bio)) {
+		__free_page(page);
+		return -ENOBUFS;
+	}
+
+	bio->bi_sector = sector * (sb->s_blocksize >> 9);
+	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 -EIO;
+	}
+	p = kmap(page);
+	gfs2_sb_in(&sdp->sd_sb, p);
+	kunmap(page);
+	__free_page(page);
+	return 0;
+}
+/**
+ * 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
+ *
+ */
+
+static 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;
+
+	error = gfs2_read_super(sdp, GFS2_SB_ADDR >> sdp->sd_fsb2bb_shift);
+	if (error) {
+		if (!silent)
+			fs_err(sdp, "can't read superblock\n");
+		return error;
+	}
+
+	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;
+	sdp->sd_heightsize[x] = ~0;
+	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;
+	sdp->sd_jheightsize[x] = ~0;
+	gfs2_assert(sdp, sdp->sd_max_jheight <= GFS2_MAX_META_HEIGHT);
+
+	return 0;
 }
 
 static int init_names(struct gfs2_sbd *sdp, int silent)
@@ -224,51 +512,59 @@
 	return error;
 }
 
-static inline struct inode *gfs2_lookup_root(struct super_block *sb,
-					     u64 no_addr)
+static int gfs2_lookup_root(struct super_block *sb, struct dentry **dptr,
+			    u64 no_addr, const char *name)
 {
-	return gfs2_inode_lookup(sb, DT_DIR, no_addr, 0, 0);
+	struct gfs2_sbd *sdp = sb->s_fs_info;
+	struct dentry *dentry;
+	struct inode *inode;
+
+	inode = gfs2_inode_lookup(sb, DT_DIR, no_addr, 0, 0);
+	if (IS_ERR(inode)) {
+		fs_err(sdp, "can't read in %s inode: %ld\n", name, PTR_ERR(inode));
+		return PTR_ERR(inode);
+	}
+	dentry = d_alloc_root(inode);
+	if (!dentry) {
+		fs_err(sdp, "can't alloc %s dentry\n", name);
+		iput(inode);
+		return -ENOMEM;
+	}
+	dentry->d_op = &gfs2_dops;
+	*dptr = dentry;
+	return 0;
 }
 
-static int init_sb(struct gfs2_sbd *sdp, int silent, int undo)
+static int init_sb(struct gfs2_sbd *sdp, int silent)
 {
 	struct super_block *sb = sdp->sd_vfs;
 	struct gfs2_holder sb_gh;
 	u64 no_addr;
-	struct inode *inode;
-	int error = 0;
+	int ret;
 
-	if (undo) {
-		if (sb->s_root) {
-			dput(sb->s_root);
-			sb->s_root = NULL;
-		}
-		return 0;
+	ret = gfs2_glock_nq_num(sdp, GFS2_SB_LOCK, &gfs2_meta_glops,
+				LM_ST_SHARED, 0, &sb_gh);
+	if (ret) {
+		fs_err(sdp, "can't acquire superblock glock: %d\n", ret);
+		return ret;
 	}
 
-	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);
+	ret = gfs2_read_sb(sdp, sb_gh.gh_gl, silent);
+	if (ret) {
+		fs_err(sdp, "can't read superblock: %d\n", ret);
 		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;
+		ret = -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;
+		ret = -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);
@@ -278,26 +574,21 @@
 
 	/* Get the root inode */
 	no_addr = sdp->sd_sb.sb_root_dir.no_addr;
-	if (sb->s_type == &gfs2meta_fs_type)
-		no_addr = sdp->sd_sb.sb_master_dir.no_addr;
-	inode = gfs2_lookup_root(sb, no_addr);
-	if (IS_ERR(inode)) {
-		error = PTR_ERR(inode);
-		fs_err(sdp, "can't read in root inode: %d\n", error);
+	ret = gfs2_lookup_root(sb, &sdp->sd_root_dir, no_addr, "root");
+	if (ret)
+		goto out;
+
+	/* Get the master inode */
+	no_addr = sdp->sd_sb.sb_master_dir.no_addr;
+	ret = gfs2_lookup_root(sb, &sdp->sd_master_dir, no_addr, "master");
+	if (ret) {
+		dput(sdp->sd_root_dir);
 		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);
-	} else
-		sb->s_root->d_op = &gfs2_dops;
-	
+	sb->s_root = dget(sdp->sd_args.ar_meta ? sdp->sd_master_dir : sdp->sd_root_dir);
 out:
 	gfs2_glock_dq_uninit(&sb_gh);
-	return error;
+	return ret;
 }
 
 /**
@@ -372,6 +663,7 @@
 
 static int init_journal(struct gfs2_sbd *sdp, int undo)
 {
+	struct inode *master = sdp->sd_master_dir->d_inode;
 	struct gfs2_holder ji_gh;
 	struct task_struct *p;
 	struct gfs2_inode *ip;
@@ -383,7 +675,7 @@
 		goto fail_recoverd;
 	}
 
-	sdp->sd_jindex = gfs2_lookup_simple(sdp->sd_master_dir, "jindex");
+	sdp->sd_jindex = gfs2_lookup_simple(master, "jindex");
 	if (IS_ERR(sdp->sd_jindex)) {
 		fs_err(sdp, "can't lookup journal index: %d\n", error);
 		return PTR_ERR(sdp->sd_jindex);
@@ -506,25 +798,17 @@
 {
 	int error = 0;
 	struct gfs2_inode *ip;
-	struct inode *inode;
+	struct inode *master = sdp->sd_master_dir->d_inode;
 
 	if (undo)
 		goto fail_qinode;
 
-	inode = gfs2_lookup_root(sdp->sd_vfs, sdp->sd_sb.sb_master_dir.no_addr);
-	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;
+		goto fail;
 
 	/* Read in the master inode number inode */
-	sdp->sd_inum_inode = gfs2_lookup_simple(sdp->sd_master_dir, "inum");
+	sdp->sd_inum_inode = gfs2_lookup_simple(master, "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);
@@ -533,7 +817,7 @@
 
 
 	/* Read in the master statfs inode */
-	sdp->sd_statfs_inode = gfs2_lookup_simple(sdp->sd_master_dir, "statfs");
+	sdp->sd_statfs_inode = gfs2_lookup_simple(master, "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);
@@ -541,7 +825,7 @@
 	}
 
 	/* Read in the resource index inode */
-	sdp->sd_rindex = gfs2_lookup_simple(sdp->sd_master_dir, "rindex");
+	sdp->sd_rindex = gfs2_lookup_simple(master, "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);
@@ -552,7 +836,7 @@
 	sdp->sd_rindex_uptodate = 0;
 
 	/* Read in the quota inode */
-	sdp->sd_quota_inode = gfs2_lookup_simple(sdp->sd_master_dir, "quota");
+	sdp->sd_quota_inode = gfs2_lookup_simple(master, "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);
@@ -571,8 +855,6 @@
 	iput(sdp->sd_inum_inode);
 fail_journal:
 	init_journal(sdp, UNDO);
-fail_master:
-	iput(sdp->sd_master_dir);
 fail:
 	return error;
 }
@@ -583,6 +865,7 @@
 	char buf[30];
 	int error = 0;
 	struct gfs2_inode *ip;
+	struct inode *master = sdp->sd_master_dir->d_inode;
 
 	if (sdp->sd_args.ar_spectator)
 		return 0;
@@ -590,7 +873,7 @@
 	if (undo)
 		goto fail_qc_gh;
 
-	pn = gfs2_lookup_simple(sdp->sd_master_dir, "per_node");
+	pn = gfs2_lookup_simple(master, "per_node");
 	if (IS_ERR(pn)) {
 		error = PTR_ERR(pn);
 		fs_err(sdp, "can't find per_node directory: %d\n", error);
@@ -800,7 +1083,11 @@
 		goto fail;
 	}
 
-	init_vfs(sb, SDF_NOATIME);
+	sb->s_magic = GFS2_MAGIC;
+	sb->s_op = &gfs2_super_ops;
+	sb->s_export_op = &gfs2_export_ops;
+	sb->s_time_gran = 1;
+	sb->s_maxbytes = MAX_LFS_FILESIZE;
 
 	/* Set up the buffer cache and fill in some fake block size values
 	   to allow us to read-in the on-disk superblock. */
@@ -828,7 +1115,7 @@
 	if (error)
 		goto fail_lm;
 
-	error = init_sb(sdp, silent, DO);
+	error = init_sb(sdp, silent);
 	if (error)
 		goto fail_locking;
 
@@ -869,7 +1156,11 @@
 fail_inodes:
 	init_inodes(sdp, UNDO);
 fail_sb:
-	init_sb(sdp, 0, UNDO);
+	if (sdp->sd_root_dir)
+		dput(sdp->sd_root_dir);
+	if (sdp->sd_master_dir)
+		dput(sdp->sd_master_dir);
+	sb->s_root = NULL;
 fail_locking:
 	init_locking(sdp, &mount_gh, UNDO);
 fail_lm:
@@ -887,151 +1178,63 @@
 }
 
 static int gfs2_get_sb(struct file_system_type *fs_type, int flags,
-		const char *dev_name, void *data, struct vfsmount *mnt)
+		       const char *dev_name, void *data, struct vfsmount *mnt)
+{
+	return get_sb_bdev(fs_type, flags, dev_name, data, fill_super, mnt);
+}
+
+static struct super_block *get_gfs2_sb(const char *dev_name)
 {
 	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);
-	} else
-		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 super_block *sb = NULL, *s;
 	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;
+		printk(KERN_WARNING "GFS2: path_lookup on %s returned error %d\n",
+		       dev_name, error);
+		return NULL;
 	}
-	error = vfs_getattr(nd.path.mnt, nd.path.dentry, &stat);
-
-	list_for_each_entry(s, &gfs2_fs_type.fs_supers, s_instances) {
-		if ((S_ISBLK(stat.mode) && s->s_dev == stat.rdev) ||
-		    (S_ISDIR(stat.mode) &&
-		     s == nd.path.dentry->d_inode->i_sb)) {
-			sb = s;
-			goto free_nd;
-		}
-	}
-
-	printk(KERN_WARNING "GFS2: Unrecognized block device or "
-	       "mount point %s\n", dev_name);
-
-free_nd:
+	sb = nd.path.dentry->d_inode->i_sb;
+	if (sb && (sb->s_type == &gfs2_fs_type))
+		atomic_inc(&sb->s_active);
+	else
+		sb = NULL;
 	path_put(&nd.path);
-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 super_block *sb = NULL;
 	struct gfs2_sbd *sdp;
 
 	sb = get_gfs2_sb(dev_name);
 	if (!sb) {
 		printk(KERN_WARNING "GFS2: gfs2 mount does not exist\n");
-		error = -ENOENT;
-		goto error;
+		return -ENOENT;
 	}
 	sdp = sb->s_fs_info;
-	if (sdp->sd_vfs_meta) {
-		printk(KERN_WARNING "GFS2: gfs2meta mount already exists\n");
-		error = -EBUSY;
-		goto error;
-	}
-	down(&sb->s_bdev->bd_mount_sem);
-	new = sget(fs_type, test_bdev_super, set_bdev_super, sb->s_bdev);
-	up(&sb->s_bdev->bd_mount_sem);
-	if (IS_ERR(new)) {
-		error = PTR_ERR(new);
-		goto error;
-	}
-	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:
-	return error;
+	mnt->mnt_sb = sb;
+	mnt->mnt_root = dget(sdp->sd_master_dir);
+	return 0;
 }
 
 static void gfs2_kill_sb(struct super_block *sb)
 {
-	if (sb->s_fs_info) {
-		gfs2_delete_debugfs_file(sb->s_fs_info);
-		gfs2_meta_syncfs(sb->s_fs_info);
-	}
-	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);
+	if (sdp) {
+		gfs2_meta_syncfs(sdp);
+		dput(sdp->sd_root_dir);
+		dput(sdp->sd_master_dir);
+		sdp->sd_root_dir = NULL;
+		sdp->sd_master_dir = NULL;
+	}
+	shrink_dcache_sb(sb);
+	kill_block_super(sb);
+	if (sdp)
+		gfs2_delete_debugfs_file(sdp);
 }
 
 struct file_system_type gfs2_fs_type = {
@@ -1046,7 +1249,6 @@
 	.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_inode.c b/fs/gfs2/ops_inode.c
index e2c62f7..534e1e2 100644
--- a/fs/gfs2/ops_inode.c
+++ b/fs/gfs2/ops_inode.c
@@ -159,9 +159,13 @@
 	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);
+	error = gfs2_glock_nq(ghs); /* parent */
 	if (error)
-		goto out;
+		goto out_parent;
+
+	error = gfs2_glock_nq(ghs + 1); /* child */
+	if (error)
+		goto out_child;
 
 	error = gfs2_permission(dir, MAY_WRITE | MAY_EXEC);
 	if (error)
@@ -245,8 +249,10 @@
 	if (alloc_required)
 		gfs2_alloc_put(dip);
 out_gunlock:
-	gfs2_glock_dq_m(2, ghs);
-out:
+	gfs2_glock_dq(ghs + 1);
+out_child:
+	gfs2_glock_dq(ghs);
+out_parent:
 	gfs2_holder_uninit(ghs);
 	gfs2_holder_uninit(ghs + 1);
 	if (!error) {
@@ -302,7 +308,7 @@
 
 	error = gfs2_unlink_ok(dip, &dentry->d_name, ip);
 	if (error)
-		goto out_rgrp;
+		goto out_gunlock;
 
 	error = gfs2_trans_begin(sdp, 2*RES_DINODE + RES_LEAF + RES_RG_BIT, 0);
 	if (error)
@@ -316,6 +322,7 @@
 
 out_end_trans:
 	gfs2_trans_end(sdp);
+out_gunlock:
 	gfs2_glock_dq(ghs + 2);
 out_rgrp:
 	gfs2_holder_uninit(ghs + 2);
@@ -485,7 +492,6 @@
 	struct gfs2_holder ri_gh;
 	int error;
 
-
 	error = gfs2_rindex_hold(sdp, &ri_gh);
 	if (error)
 		return error;
@@ -495,9 +501,17 @@
 	rgd = gfs2_blk2rgrpd(sdp, ip->i_no_addr);
 	gfs2_holder_init(rgd->rd_gl, LM_ST_EXCLUSIVE, 0, ghs + 2);
 
-	error = gfs2_glock_nq_m(3, ghs);
+	error = gfs2_glock_nq(ghs); /* parent */
 	if (error)
-		goto out;
+		goto out_parent;
+
+	error = gfs2_glock_nq(ghs + 1); /* child */
+	if (error)
+		goto out_child;
+
+	error = gfs2_glock_nq(ghs + 2); /* rgrp */
+	if (error)
+		goto out_rgrp;
 
 	error = gfs2_unlink_ok(dip, &dentry->d_name, ip);
 	if (error)
@@ -523,11 +537,15 @@
 	gfs2_trans_end(sdp);
 
 out_gunlock:
-	gfs2_glock_dq_m(3, ghs);
-out:
-	gfs2_holder_uninit(ghs);
-	gfs2_holder_uninit(ghs + 1);
+	gfs2_glock_dq(ghs + 2);
+out_rgrp:
 	gfs2_holder_uninit(ghs + 2);
+	gfs2_glock_dq(ghs + 1);
+out_child:
+	gfs2_holder_uninit(ghs + 1);
+	gfs2_glock_dq(ghs);
+out_parent:
+	gfs2_holder_uninit(ghs);
 	gfs2_glock_dq_uninit(&ri_gh);
 	return error;
 }
@@ -571,6 +589,54 @@
 	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
+ */
+
+static 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);
+		if (IS_ERR(tmp)) {
+			error = PTR_ERR(tmp);
+			break;
+		}
+
+		iput(dir);
+		dir = tmp;
+	}
+
+	iput(dir);
+
+	return error;
+}
+
 /**
  * gfs2_rename - Rename a file
  * @odir: Parent directory of old file name
@@ -589,7 +655,7 @@
 	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[5], r_gh;
+	struct gfs2_holder ghs[5], r_gh = { .gh_gl = NULL, };
 	struct gfs2_rgrpd *nrgd;
 	unsigned int num_gh;
 	int dir_rename = 0;
@@ -603,19 +669,20 @@
 			return 0;
 	}
 
-	/* Make sure we aren't trying to move a dirctory into it's subdir */
 
-	if (S_ISDIR(ip->i_inode.i_mode) && odip != ndip) {
-		dir_rename = 1;
-
-		error = gfs2_glock_nq_init(sdp->sd_rename_gl, LM_ST_EXCLUSIVE, 0,
-					   &r_gh);
+	if (odip != ndip) {
+		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;
+		if (S_ISDIR(ip->i_inode.i_mode)) {
+			dir_rename = 1;
+			/* don't move a dirctory into it's subdir */
+			error = gfs2_ok_to_move(ip, ndip);
+			if (error)
+				goto out_gunlock_r;
+		}
 	}
 
 	num_gh = 1;
@@ -639,9 +706,11 @@
 			gfs2_holder_init(nrgd->rd_gl, LM_ST_EXCLUSIVE, 0, ghs + num_gh++);
 	}
 
-	error = gfs2_glock_nq_m(num_gh, ghs);
-	if (error)
-		goto out_uninit;
+	for (x = 0; x < num_gh; x++) {
+		error = gfs2_glock_nq(ghs + x);
+		if (error)
+			goto out_gunlock;
+	}
 
 	/* Check out the old directory */
 
@@ -804,12 +873,12 @@
 	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++)
+	while (x--) {
+		gfs2_glock_dq(ghs + x);
 		gfs2_holder_uninit(ghs + x);
+	}
 out_gunlock_r:
-	if (dir_rename)
+	if (r_gh.gh_gl)
 		gfs2_glock_dq_uninit(&r_gh);
 out:
 	return error;
diff --git a/fs/gfs2/ops_super.c b/fs/gfs2/ops_super.c
index f66ea0f..d5355d9 100644
--- a/fs/gfs2/ops_super.c
+++ b/fs/gfs2/ops_super.c
@@ -20,6 +20,7 @@
 #include <linux/gfs2_ondisk.h>
 #include <linux/crc32.h>
 #include <linux/lm_interface.h>
+#include <linux/time.h>
 
 #include "gfs2.h"
 #include "incore.h"
@@ -38,6 +39,7 @@
 #include "dir.h"
 #include "eattr.h"
 #include "bmap.h"
+#include "meta_io.h"
 
 /**
  * gfs2_write_inode - Make sure the inode is stable on the disk
@@ -50,16 +52,74 @@
 static int gfs2_write_inode(struct inode *inode, int sync)
 {
 	struct gfs2_inode *ip = GFS2_I(inode);
+	struct gfs2_sbd *sdp = GFS2_SB(inode);
+	struct gfs2_holder gh;
+	struct buffer_head *bh;
+	struct timespec atime;
+	struct gfs2_dinode *di;
+	int ret = 0;
 
-	/* Check this is a "normal" inode */
-	if (test_bit(GIF_USER, &ip->i_flags)) {
-		if (current->flags & PF_MEMALLOC)
-			return 0;
-		if (sync)
-			gfs2_log_flush(GFS2_SB(inode), ip->i_gl);
+	/* Check this is a "normal" inode, etc */
+	if (!test_bit(GIF_USER, &ip->i_flags) ||
+	    (current->flags & PF_MEMALLOC))
+		return 0;
+	ret = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh);
+	if (ret)
+		goto do_flush;
+	ret = gfs2_trans_begin(sdp, RES_DINODE, 0);
+	if (ret)
+		goto do_unlock;
+	ret = gfs2_meta_inode_buffer(ip, &bh);
+	if (ret == 0) {
+		di = (struct gfs2_dinode *)bh->b_data;
+		atime.tv_sec = be64_to_cpu(di->di_atime);
+		atime.tv_nsec = be32_to_cpu(di->di_atime_nsec);
+		if (timespec_compare(&inode->i_atime, &atime) > 0) {
+			gfs2_trans_add_bh(ip->i_gl, bh, 1);
+			gfs2_dinode_out(ip, bh->b_data);
+		}
+		brelse(bh);
 	}
+	gfs2_trans_end(sdp);
+do_unlock:
+	gfs2_glock_dq_uninit(&gh);
+do_flush:
+	if (sync != 0)
+		gfs2_log_flush(GFS2_SB(inode), ip->i_gl);
+	return ret;
+}
 
-	return 0;
+/**
+ * gfs2_make_fs_ro - Turn a Read-Write FS into a Read-Only one
+ * @sdp: the filesystem
+ *
+ * Returns: errno
+ */
+
+static 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_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;
 }
 
 /**
@@ -73,12 +133,6 @@
 	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);
@@ -101,7 +155,6 @@
 
 	/*  Release stuff  */
 
-	iput(sdp->sd_master_dir);
 	iput(sdp->sd_jindex);
 	iput(sdp->sd_inum_inode);
 	iput(sdp->sd_statfs_inode);
@@ -152,6 +205,7 @@
  *
  * Flushes the log to disk.
  */
+
 static int gfs2_sync_fs(struct super_block *sb, int wait)
 {
 	sb->s_dirt = 0;
@@ -270,14 +324,6 @@
 		}
 	}
 
-	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;
 }
 
@@ -295,6 +341,7 @@
  * inode's blocks, or alternatively pass the baton on to another
  * node for later deallocation.
  */
+
 static void gfs2_drop_inode(struct inode *inode)
 {
 	struct gfs2_inode *ip = GFS2_I(inode);
@@ -333,6 +380,16 @@
 	}
 }
 
+static int is_ancestor(const struct dentry *d1, const struct dentry *d2)
+{
+	do {
+		if (d1 == d2)
+			return 1;
+		d1 = d1->d_parent;
+	} while (!IS_ROOT(d1));
+	return 0;
+}
+
 /**
  * gfs2_show_options - Show mount options for /proc/mounts
  * @s: seq_file structure
@@ -346,6 +403,8 @@
 	struct gfs2_sbd *sdp = mnt->mnt_sb->s_fs_info;
 	struct gfs2_args *args = &sdp->sd_args;
 
+	if (is_ancestor(mnt->mnt_root, sdp->sd_master_dir))
+		seq_printf(s, ",meta");
 	if (args->ar_lockproto[0])
 		seq_printf(s, ",lockproto=%s", args->ar_lockproto);
 	if (args->ar_locktable[0])
@@ -414,6 +473,7 @@
  * 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;
@@ -478,8 +538,6 @@
 	clear_inode(inode);
 }
 
-
-
 static struct inode *gfs2_alloc_inode(struct super_block *sb)
 {
 	struct gfs2_inode *ip;
diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c
index ca83199..c3ba3d9 100644
--- a/fs/gfs2/super.c
+++ b/fs/gfs2/super.c
@@ -33,313 +33,6 @@
 #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_demote_secs = 300;
-	gt->gt_incore_log_blocks = 1024;
-	gt->gt_log_flush_secs = 60;
-	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_max_readahead = 1 << 18;
-	gt->gt_stall_secs = 600;
-	gt->gt_complain_secs = 10;
-	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_host *sb, int silent)
-{
-	unsigned int x;
-
-	if (sb->sb_magic != GFS2_MAGIC ||
-	    sb->sb_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 void end_bio_io_page(struct bio *bio, int error)
-{
-	struct page *page = bio->bi_private;
-
-	if (!error)
-		SetPageUptodate(page);
-	else
-		printk(KERN_WARNING "gfs2: error %d reading superblock\n", error);
-	unlock_page(page);
-}
-
-static void gfs2_sb_in(struct gfs2_sb_host *sb, const void *buf)
-{
-	const struct gfs2_sb *str = buf;
-
-	sb->sb_magic = be32_to_cpu(str->sb_header.mh_magic);
-	sb->sb_type = be32_to_cpu(str->sb_header.mh_type);
-	sb->sb_format = be32_to_cpu(str->sb_header.mh_format);
-	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);
-	sb->sb_master_dir.no_addr = be64_to_cpu(str->sb_master_dir.no_addr);
-	sb->sb_master_dir.no_formal_ino = be64_to_cpu(str->sb_master_dir.no_formal_ino);
-	sb->sb_root_dir.no_addr = be64_to_cpu(str->sb_root_dir.no_addr);
-	sb->sb_root_dir.no_formal_ino = be64_to_cpu(str->sb_root_dir.no_formal_ino);
-
-	memcpy(sb->sb_lockproto, str->sb_lockproto, GFS2_LOCKNAME_LEN);
-	memcpy(sb->sb_locktable, str->sb_locktable, GFS2_LOCKNAME_LEN);
-}
-
-/**
- * gfs2_read_super - Read the gfs2 super block from disk
- * @sdp: The GFS2 super block
- * @sector: The location of the super block
- * @error: The error code to return
- *
- * This uses the bio functions to read the super block from disk
- * because we want to be 100% sure that we never read cached data.
- * A super block is read twice only during each GFS2 mount and is
- * never written to by the filesystem. The first time its read no
- * locks are held, and the only details which are looked at are those
- * relating to the locking protocol. Once locking is up and working,
- * the sb is read again under the lock to establish the location of
- * the master directory (contains pointers to journals etc) and the
- * root directory.
- *
- * Returns: 0 on success or error
- */
-
-int gfs2_read_super(struct gfs2_sbd *sdp, sector_t sector)
-{
-	struct super_block *sb = sdp->sd_vfs;
-	struct gfs2_sb *p;
-	struct page *page;
-	struct bio *bio;
-
-	page = alloc_page(GFP_NOFS);
-	if (unlikely(!page))
-		return -ENOBUFS;
-
-	ClearPageUptodate(page);
-	ClearPageDirty(page);
-	lock_page(page);
-
-	bio = bio_alloc(GFP_NOFS, 1);
-	if (unlikely(!bio)) {
-		__free_page(page);
-		return -ENOBUFS;
-	}
-
-	bio->bi_sector = sector * (sb->s_blocksize >> 9);
-	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 -EIO;
-	}
-	p = kmap(page);
-	gfs2_sb_in(&sdp->sd_sb, p);
-	kunmap(page);
-	__free_page(page);
-	return 0;
-}
-
-/**
- * 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;
-
-	error = gfs2_read_super(sdp, GFS2_SB_ADDR >> sdp->sd_fsb2bb_shift);
-	if (error) {
-		if (!silent)
-			fs_err(sdp, "can't read superblock\n");
-		return error;
-	}
-
-	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;
-	sdp->sd_heightsize[x] = ~0;
-	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;
-	sdp->sd_jheightsize[x] = ~0;
-	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
@@ -581,39 +274,6 @@
 	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_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;
-}
-
 static void gfs2_statfs_change_in(struct gfs2_statfs_change_host *sc, const void *buf)
 {
 	const struct gfs2_statfs_change *str = buf;
diff --git a/fs/gfs2/super.h b/fs/gfs2/super.h
index 44361ec..50a4c9b 100644
--- a/fs/gfs2/super.h
+++ b/fs/gfs2/super.h
@@ -12,11 +12,6 @@
 
 #include "incore.h"
 
-void gfs2_tune_init(struct gfs2_tune *gt);
-
-int gfs2_check_sb(struct gfs2_sbd *sdp, struct gfs2_sb_host *sb, int silent);
-int gfs2_read_sb(struct gfs2_sbd *sdp, struct gfs2_glock *gl, int silent);
-int gfs2_read_super(struct gfs2_sbd *sdp, sector_t sector);
 void gfs2_lm_unmount(struct gfs2_sbd *sdp);
 
 static inline unsigned int gfs2_jindex_size(struct gfs2_sbd *sdp)
@@ -40,7 +35,6 @@
 			      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,
diff --git a/fs/gfs2/sys.c b/fs/gfs2/sys.c
index 7484655..7e1879f 100644
--- a/fs/gfs2/sys.c
+++ b/fs/gfs2/sys.c
@@ -269,14 +269,6 @@
 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,
@@ -292,7 +284,6 @@
 	&args_attr_quota.attr,
 	&args_attr_suiddir.attr,
 	&args_attr_data.attr,
-	&args_attr_noatime.attr,
 	NULL,
 };
 
@@ -407,7 +398,6 @@
 TUNE_ATTR(log_flush_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(statfs_slow, 0);
@@ -427,7 +417,6 @@
 	&tune_attr_log_flush_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_statfs_slow.attr,
diff --git a/fs/hfs/super.c b/fs/hfs/super.c
index 4abb104..3c7c763 100644
--- a/fs/hfs/super.c
+++ b/fs/hfs/super.c
@@ -173,7 +173,7 @@
 	opt_err
 };
 
-static match_table_t tokens = {
+static const match_table_t tokens = {
 	{ opt_uid, "uid=%u" },
 	{ opt_gid, "gid=%u" },
 	{ opt_umask, "umask=%o" },
diff --git a/fs/hfsplus/options.c b/fs/hfsplus/options.c
index 9997cbf..9699c56 100644
--- a/fs/hfsplus/options.c
+++ b/fs/hfsplus/options.c
@@ -25,7 +25,7 @@
 	opt_force, opt_err
 };
 
-static match_table_t tokens = {
+static const match_table_t tokens = {
 	{ opt_creator, "creator=%s" },
 	{ opt_type, "type=%s" },
 	{ opt_umask, "umask=%o" },
diff --git a/fs/hpfs/super.c b/fs/hpfs/super.c
index b8ae9c9..29ad461 100644
--- a/fs/hpfs/super.c
+++ b/fs/hpfs/super.c
@@ -215,7 +215,7 @@
 	Opt_timeshift, Opt_err,
 };
 
-static match_table_t tokens = {
+static const match_table_t tokens = {
 	{Opt_help, "help"},
 	{Opt_uid, "uid=%u"},
 	{Opt_gid, "gid=%u"},
diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c
index 3f58923..61edc70 100644
--- a/fs/hugetlbfs/inode.c
+++ b/fs/hugetlbfs/inode.c
@@ -57,7 +57,7 @@
 	Opt_err,
 };
 
-static match_table_t tokens = {
+static const match_table_t tokens = {
 	{Opt_size,	"size=%s"},
 	{Opt_nr_inodes,	"nr_inodes=%s"},
 	{Opt_mode,	"mode=%o"},
diff --git a/fs/inotify_user.c b/fs/inotify_user.c
index 6024942..d85c7d9 100644
--- a/fs/inotify_user.c
+++ b/fs/inotify_user.c
@@ -323,7 +323,7 @@
 }
 
 /*
- * remove_kevent - cleans up and ultimately frees the given kevent
+ * remove_kevent - cleans up the given kevent
  *
  * Caller must hold dev->ev_mutex.
  */
@@ -334,7 +334,13 @@
 
 	dev->event_count--;
 	dev->queue_size -= sizeof(struct inotify_event) + kevent->event.len;
+}
 
+/*
+ * free_kevent - frees the given kevent.
+ */
+static void free_kevent(struct inotify_kernel_event *kevent)
+{
 	kfree(kevent->name);
 	kmem_cache_free(event_cachep, kevent);
 }
@@ -350,6 +356,7 @@
 		struct inotify_kernel_event *kevent;
 		kevent = inotify_dev_get_event(dev);
 		remove_kevent(dev, kevent);
+		free_kevent(kevent);
 	}
 }
 
@@ -433,17 +440,15 @@
 	dev = file->private_data;
 
 	while (1) {
-		int events;
 
 		prepare_to_wait(&dev->wq, &wait, TASK_INTERRUPTIBLE);
 
 		mutex_lock(&dev->ev_mutex);
-		events = !list_empty(&dev->events);
-		mutex_unlock(&dev->ev_mutex);
-		if (events) {
+		if (!list_empty(&dev->events)) {
 			ret = 0;
 			break;
 		}
+		mutex_unlock(&dev->ev_mutex);
 
 		if (file->f_flags & O_NONBLOCK) {
 			ret = -EAGAIN;
@@ -462,7 +467,6 @@
 	if (ret)
 		return ret;
 
-	mutex_lock(&dev->ev_mutex);
 	while (1) {
 		struct inotify_kernel_event *kevent;
 
@@ -481,6 +485,13 @@
 			}
 			break;
 		}
+		remove_kevent(dev, kevent);
+
+		/*
+		 * Must perform the copy_to_user outside the mutex in order
+		 * to avoid a lock order reversal with mmap_sem.
+		 */
+		mutex_unlock(&dev->ev_mutex);
 
 		if (copy_to_user(buf, &kevent->event, event_size)) {
 			ret = -EFAULT;
@@ -498,7 +509,9 @@
 			count -= kevent->event.len;
 		}
 
-		remove_kevent(dev, kevent);
+		free_kevent(kevent);
+
+		mutex_lock(&dev->ev_mutex);
 	}
 	mutex_unlock(&dev->ev_mutex);
 
diff --git a/fs/ioctl.c b/fs/ioctl.c
index 7db32b3..d152856 100644
--- a/fs/ioctl.c
+++ b/fs/ioctl.c
@@ -13,9 +13,14 @@
 #include <linux/security.h>
 #include <linux/module.h>
 #include <linux/uaccess.h>
+#include <linux/writeback.h>
+#include <linux/buffer_head.h>
 
 #include <asm/ioctls.h>
 
+/* So that the fiemap access checks can't overflow on 32 bit machines. */
+#define FIEMAP_MAX_EXTENTS	(UINT_MAX / sizeof(struct fiemap_extent))
+
 /**
  * vfs_ioctl - call filesystem specific ioctl methods
  * @filp:	open file to invoke ioctl method on
@@ -71,6 +76,276 @@
 	return put_user(res, p);
 }
 
+/**
+ * fiemap_fill_next_extent - Fiemap helper function
+ * @fieinfo:	Fiemap context passed into ->fiemap
+ * @logical:	Extent logical start offset, in bytes
+ * @phys:	Extent physical start offset, in bytes
+ * @len:	Extent length, in bytes
+ * @flags:	FIEMAP_EXTENT flags that describe this extent
+ *
+ * Called from file system ->fiemap callback. Will populate extent
+ * info as passed in via arguments and copy to user memory. On
+ * success, extent count on fieinfo is incremented.
+ *
+ * Returns 0 on success, -errno on error, 1 if this was the last
+ * extent that will fit in user array.
+ */
+#define SET_UNKNOWN_FLAGS	(FIEMAP_EXTENT_DELALLOC)
+#define SET_NO_UNMOUNTED_IO_FLAGS	(FIEMAP_EXTENT_DATA_ENCRYPTED)
+#define SET_NOT_ALIGNED_FLAGS	(FIEMAP_EXTENT_DATA_TAIL|FIEMAP_EXTENT_DATA_INLINE)
+int fiemap_fill_next_extent(struct fiemap_extent_info *fieinfo, u64 logical,
+			    u64 phys, u64 len, u32 flags)
+{
+	struct fiemap_extent extent;
+	struct fiemap_extent *dest = fieinfo->fi_extents_start;
+
+	/* only count the extents */
+	if (fieinfo->fi_extents_max == 0) {
+		fieinfo->fi_extents_mapped++;
+		return (flags & FIEMAP_EXTENT_LAST) ? 1 : 0;
+	}
+
+	if (fieinfo->fi_extents_mapped >= fieinfo->fi_extents_max)
+		return 1;
+
+	if (flags & SET_UNKNOWN_FLAGS)
+		flags |= FIEMAP_EXTENT_UNKNOWN;
+	if (flags & SET_NO_UNMOUNTED_IO_FLAGS)
+		flags |= FIEMAP_EXTENT_ENCODED;
+	if (flags & SET_NOT_ALIGNED_FLAGS)
+		flags |= FIEMAP_EXTENT_NOT_ALIGNED;
+
+	memset(&extent, 0, sizeof(extent));
+	extent.fe_logical = logical;
+	extent.fe_physical = phys;
+	extent.fe_length = len;
+	extent.fe_flags = flags;
+
+	dest += fieinfo->fi_extents_mapped;
+	if (copy_to_user(dest, &extent, sizeof(extent)))
+		return -EFAULT;
+
+	fieinfo->fi_extents_mapped++;
+	if (fieinfo->fi_extents_mapped == fieinfo->fi_extents_max)
+		return 1;
+	return (flags & FIEMAP_EXTENT_LAST) ? 1 : 0;
+}
+EXPORT_SYMBOL(fiemap_fill_next_extent);
+
+/**
+ * fiemap_check_flags - check validity of requested flags for fiemap
+ * @fieinfo:	Fiemap context passed into ->fiemap
+ * @fs_flags:	Set of fiemap flags that the file system understands
+ *
+ * Called from file system ->fiemap callback. This will compute the
+ * intersection of valid fiemap flags and those that the fs supports. That
+ * value is then compared against the user supplied flags. In case of bad user
+ * flags, the invalid values will be written into the fieinfo structure, and
+ * -EBADR is returned, which tells ioctl_fiemap() to return those values to
+ * userspace. For this reason, a return code of -EBADR should be preserved.
+ *
+ * Returns 0 on success, -EBADR on bad flags.
+ */
+int fiemap_check_flags(struct fiemap_extent_info *fieinfo, u32 fs_flags)
+{
+	u32 incompat_flags;
+
+	incompat_flags = fieinfo->fi_flags & ~(FIEMAP_FLAGS_COMPAT & fs_flags);
+	if (incompat_flags) {
+		fieinfo->fi_flags = incompat_flags;
+		return -EBADR;
+	}
+	return 0;
+}
+EXPORT_SYMBOL(fiemap_check_flags);
+
+static int fiemap_check_ranges(struct super_block *sb,
+			       u64 start, u64 len, u64 *new_len)
+{
+	*new_len = len;
+
+	if (len == 0)
+		return -EINVAL;
+
+	if (start > sb->s_maxbytes)
+		return -EFBIG;
+
+	/*
+	 * Shrink request scope to what the fs can actually handle.
+	 */
+	if ((len > sb->s_maxbytes) ||
+	    (sb->s_maxbytes - len) < start)
+		*new_len = sb->s_maxbytes - start;
+
+	return 0;
+}
+
+static int ioctl_fiemap(struct file *filp, unsigned long arg)
+{
+	struct fiemap fiemap;
+	struct fiemap_extent_info fieinfo = { 0, };
+	struct inode *inode = filp->f_path.dentry->d_inode;
+	struct super_block *sb = inode->i_sb;
+	u64 len;
+	int error;
+
+	if (!inode->i_op->fiemap)
+		return -EOPNOTSUPP;
+
+	if (copy_from_user(&fiemap, (struct fiemap __user *)arg,
+			   sizeof(struct fiemap)))
+		return -EFAULT;
+
+	if (fiemap.fm_extent_count > FIEMAP_MAX_EXTENTS)
+		return -EINVAL;
+
+	error = fiemap_check_ranges(sb, fiemap.fm_start, fiemap.fm_length,
+				    &len);
+	if (error)
+		return error;
+
+	fieinfo.fi_flags = fiemap.fm_flags;
+	fieinfo.fi_extents_max = fiemap.fm_extent_count;
+	fieinfo.fi_extents_start = (struct fiemap_extent *)(arg + sizeof(fiemap));
+
+	if (fiemap.fm_extent_count != 0 &&
+	    !access_ok(VERIFY_WRITE, fieinfo.fi_extents_start,
+		       fieinfo.fi_extents_max * sizeof(struct fiemap_extent)))
+		return -EFAULT;
+
+	if (fieinfo.fi_flags & FIEMAP_FLAG_SYNC)
+		filemap_write_and_wait(inode->i_mapping);
+
+	error = inode->i_op->fiemap(inode, &fieinfo, fiemap.fm_start, len);
+	fiemap.fm_flags = fieinfo.fi_flags;
+	fiemap.fm_mapped_extents = fieinfo.fi_extents_mapped;
+	if (copy_to_user((char *)arg, &fiemap, sizeof(fiemap)))
+		error = -EFAULT;
+
+	return error;
+}
+
+#ifdef CONFIG_BLOCK
+
+#define blk_to_logical(inode, blk) (blk << (inode)->i_blkbits)
+#define logical_to_blk(inode, offset) (offset >> (inode)->i_blkbits);
+
+/*
+ * @inode - the inode to map
+ * @arg - the pointer to userspace where we copy everything to
+ * @get_block - the fs's get_block function
+ *
+ * This does FIEMAP for block based inodes.  Basically it will just loop
+ * through get_block until we hit the number of extents we want to map, or we
+ * go past the end of the file and hit a hole.
+ *
+ * If it is possible to have data blocks beyond a hole past @inode->i_size, then
+ * please do not use this function, it will stop at the first unmapped block
+ * beyond i_size
+ */
+int generic_block_fiemap(struct inode *inode,
+			 struct fiemap_extent_info *fieinfo, u64 start,
+			 u64 len, get_block_t *get_block)
+{
+	struct buffer_head tmp;
+	unsigned int start_blk;
+	long long length = 0, map_len = 0;
+	u64 logical = 0, phys = 0, size = 0;
+	u32 flags = FIEMAP_EXTENT_MERGED;
+	int ret = 0;
+
+	if ((ret = fiemap_check_flags(fieinfo, FIEMAP_FLAG_SYNC)))
+		return ret;
+
+	start_blk = logical_to_blk(inode, start);
+
+	/* guard against change */
+	mutex_lock(&inode->i_mutex);
+
+	length = (long long)min_t(u64, len, i_size_read(inode));
+	map_len = length;
+
+	do {
+		/*
+		 * we set b_size to the total size we want so it will map as
+		 * many contiguous blocks as possible at once
+		 */
+		memset(&tmp, 0, sizeof(struct buffer_head));
+		tmp.b_size = map_len;
+
+		ret = get_block(inode, start_blk, &tmp, 0);
+		if (ret)
+			break;
+
+		/* HOLE */
+		if (!buffer_mapped(&tmp)) {
+			/*
+			 * first hole after going past the EOF, this is our
+			 * last extent
+			 */
+			if (length <= 0) {
+				flags = FIEMAP_EXTENT_MERGED|FIEMAP_EXTENT_LAST;
+				ret = fiemap_fill_next_extent(fieinfo, logical,
+							      phys, size,
+							      flags);
+				break;
+			}
+
+			length -= blk_to_logical(inode, 1);
+
+			/* if we have holes up to/past EOF then we're done */
+			if (length <= 0)
+				break;
+
+			start_blk++;
+		} else {
+			if (length <= 0 && size) {
+				ret = fiemap_fill_next_extent(fieinfo, logical,
+							      phys, size,
+							      flags);
+				if (ret)
+					break;
+			}
+
+			logical = blk_to_logical(inode, start_blk);
+			phys = blk_to_logical(inode, tmp.b_blocknr);
+			size = tmp.b_size;
+			flags = FIEMAP_EXTENT_MERGED;
+
+			length -= tmp.b_size;
+			start_blk += logical_to_blk(inode, size);
+
+			/*
+			 * if we are past the EOF we need to loop again to see
+			 * if there is a hole so we can mark this extent as the
+			 * last one, and if not keep mapping things until we
+			 * find a hole, or we run out of slots in the extent
+			 * array
+			 */
+			if (length <= 0)
+				continue;
+
+			ret = fiemap_fill_next_extent(fieinfo, logical, phys,
+						      size, flags);
+			if (ret)
+				break;
+		}
+		cond_resched();
+	} while (1);
+
+	mutex_unlock(&inode->i_mutex);
+
+	/* if ret is 1 then we just hit the end of the extent array */
+	if (ret == 1)
+		ret = 0;
+
+	return ret;
+}
+EXPORT_SYMBOL(generic_block_fiemap);
+
+#endif  /*  CONFIG_BLOCK  */
+
 static int file_ioctl(struct file *filp, unsigned int cmd,
 		unsigned long arg)
 {
@@ -80,6 +355,8 @@
 	switch (cmd) {
 	case FIBMAP:
 		return ioctl_fibmap(filp, p);
+	case FS_IOC_FIEMAP:
+		return ioctl_fiemap(filp, arg);
 	case FIGETBSZ:
 		return put_user(inode->i_sb->s_blocksize, p);
 	case FIONREAD:
diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c
index 26948a6..3f8af0f 100644
--- a/fs/isofs/inode.c
+++ b/fs/isofs/inode.c
@@ -310,7 +310,7 @@
 	Opt_nocompress, Opt_hide, Opt_showassoc, Opt_dmode,
 };
 
-static match_table_t tokens = {
+static const match_table_t tokens = {
 	{Opt_norock, "norock"},
 	{Opt_nojoliet, "nojoliet"},
 	{Opt_unhide, "unhide"},
diff --git a/fs/jbd2/checkpoint.c b/fs/jbd2/checkpoint.c
index 91389c8..9203c33 100644
--- a/fs/jbd2/checkpoint.c
+++ b/fs/jbd2/checkpoint.c
@@ -20,6 +20,7 @@
 #include <linux/time.h>
 #include <linux/fs.h>
 #include <linux/jbd2.h>
+#include <linux/marker.h>
 #include <linux/errno.h>
 #include <linux/slab.h>
 
@@ -93,7 +94,8 @@
 	int ret = 0;
 	struct buffer_head *bh = jh2bh(jh);
 
-	if (jh->b_jlist == BJ_None && !buffer_locked(bh) && !buffer_dirty(bh)) {
+	if (jh->b_jlist == BJ_None && !buffer_locked(bh) &&
+	    !buffer_dirty(bh) && !buffer_write_io_error(bh)) {
 		JBUFFER_TRACE(jh, "remove from checkpoint list");
 		ret = __jbd2_journal_remove_checkpoint(jh) + 1;
 		jbd_unlock_bh_state(bh);
@@ -126,14 +128,29 @@
 
 		/*
 		 * Test again, another process may have checkpointed while we
-		 * were waiting for the checkpoint lock
+		 * were waiting for the checkpoint lock. If there are no
+		 * outstanding transactions there is nothing to checkpoint and
+		 * we can't make progress. Abort the journal in this case.
 		 */
 		spin_lock(&journal->j_state_lock);
+		spin_lock(&journal->j_list_lock);
 		nblocks = jbd_space_needed(journal);
 		if (__jbd2_log_space_left(journal) < nblocks) {
+			int chkpt = journal->j_checkpoint_transactions != NULL;
+
+			spin_unlock(&journal->j_list_lock);
 			spin_unlock(&journal->j_state_lock);
-			jbd2_log_do_checkpoint(journal);
+			if (chkpt) {
+				jbd2_log_do_checkpoint(journal);
+			} else {
+				printk(KERN_ERR "%s: no transactions\n",
+				       __func__);
+				jbd2_journal_abort(journal, 0);
+			}
+
 			spin_lock(&journal->j_state_lock);
+		} else {
+			spin_unlock(&journal->j_list_lock);
 		}
 		mutex_unlock(&journal->j_checkpoint_mutex);
 	}
@@ -160,21 +177,25 @@
  * buffers. Note that we take the buffers in the opposite ordering
  * from the one in which they were submitted for IO.
  *
+ * Return 0 on success, and return <0 if some buffers have failed
+ * to be written out.
+ *
  * Called with j_list_lock held.
  */
-static void __wait_cp_io(journal_t *journal, transaction_t *transaction)
+static int __wait_cp_io(journal_t *journal, transaction_t *transaction)
 {
 	struct journal_head *jh;
 	struct buffer_head *bh;
 	tid_t this_tid;
 	int released = 0;
+	int ret = 0;
 
 	this_tid = transaction->t_tid;
 restart:
 	/* Did somebody clean up the transaction in the meanwhile? */
 	if (journal->j_checkpoint_transactions != transaction ||
 			transaction->t_tid != this_tid)
-		return;
+		return ret;
 	while (!released && transaction->t_checkpoint_io_list) {
 		jh = transaction->t_checkpoint_io_list;
 		bh = jh2bh(jh);
@@ -194,6 +215,9 @@
 			spin_lock(&journal->j_list_lock);
 			goto restart;
 		}
+		if (unlikely(buffer_write_io_error(bh)))
+			ret = -EIO;
+
 		/*
 		 * Now in whatever state the buffer currently is, we know that
 		 * it has been written out and so we can drop it from the list
@@ -203,6 +227,8 @@
 		jbd2_journal_remove_journal_head(bh);
 		__brelse(bh);
 	}
+
+	return ret;
 }
 
 #define NR_BATCH	64
@@ -226,7 +252,8 @@
  * Try to flush one buffer from the checkpoint list to disk.
  *
  * Return 1 if something happened which requires us to abort the current
- * scan of the checkpoint list.
+ * scan of the checkpoint list.  Return <0 if the buffer has failed to
+ * be written out.
  *
  * Called with j_list_lock held and drops it if 1 is returned
  * Called under jbd_lock_bh_state(jh2bh(jh)), and drops it
@@ -258,6 +285,9 @@
 		jbd2_log_wait_commit(journal, tid);
 		ret = 1;
 	} else if (!buffer_dirty(bh)) {
+		ret = 1;
+		if (unlikely(buffer_write_io_error(bh)))
+			ret = -EIO;
 		J_ASSERT_JH(jh, !buffer_jbddirty(bh));
 		BUFFER_TRACE(bh, "remove from checkpoint");
 		__jbd2_journal_remove_checkpoint(jh);
@@ -265,7 +295,6 @@
 		jbd_unlock_bh_state(bh);
 		jbd2_journal_remove_journal_head(bh);
 		__brelse(bh);
-		ret = 1;
 	} else {
 		/*
 		 * Important: we are about to write the buffer, and
@@ -298,6 +327,7 @@
  * to disk. We submit larger chunks of data at once.
  *
  * The journal should be locked before calling this function.
+ * Called with j_checkpoint_mutex held.
  */
 int jbd2_log_do_checkpoint(journal_t *journal)
 {
@@ -313,6 +343,8 @@
 	 * journal straight away.
 	 */
 	result = jbd2_cleanup_journal_tail(journal);
+	trace_mark(jbd2_checkpoint, "dev %s need_checkpoint %d",
+		   journal->j_devname, result);
 	jbd_debug(1, "cleanup_journal_tail returned %d\n", result);
 	if (result <= 0)
 		return result;
@@ -321,6 +353,7 @@
 	 * OK, we need to start writing disk blocks.  Take one transaction
 	 * and write it.
 	 */
+	result = 0;
 	spin_lock(&journal->j_list_lock);
 	if (!journal->j_checkpoint_transactions)
 		goto out;
@@ -339,7 +372,7 @@
 		int batch_count = 0;
 		struct buffer_head *bhs[NR_BATCH];
 		struct journal_head *jh;
-		int retry = 0;
+		int retry = 0, err;
 
 		while (!retry && transaction->t_checkpoint_list) {
 			struct buffer_head *bh;
@@ -353,6 +386,8 @@
 			}
 			retry = __process_buffer(journal, jh, bhs, &batch_count,
 						 transaction);
+			if (retry < 0 && !result)
+				result = retry;
 			if (!retry && (need_resched() ||
 				spin_needbreak(&journal->j_list_lock))) {
 				spin_unlock(&journal->j_list_lock);
@@ -377,14 +412,18 @@
 		 * Now we have cleaned up the first transaction's checkpoint
 		 * list. Let's clean up the second one
 		 */
-		__wait_cp_io(journal, transaction);
+		err = __wait_cp_io(journal, transaction);
+		if (!result)
+			result = err;
 	}
 out:
 	spin_unlock(&journal->j_list_lock);
-	result = jbd2_cleanup_journal_tail(journal);
 	if (result < 0)
-		return result;
-	return 0;
+		jbd2_journal_abort(journal, result);
+	else
+		result = jbd2_cleanup_journal_tail(journal);
+
+	return (result < 0) ? result : 0;
 }
 
 /*
@@ -400,8 +439,9 @@
  * This is the only part of the journaling code which really needs to be
  * aware of transaction aborts.  Checkpointing involves writing to the
  * main filesystem area rather than to the journal, so it can proceed
- * even in abort state, but we must not update the journal superblock if
- * we have an abort error outstanding.
+ * even in abort state, but we must not update the super block if
+ * checkpointing may have failed.  Otherwise, we would lose some metadata
+ * buffers which should be written-back to the filesystem.
  */
 
 int jbd2_cleanup_journal_tail(journal_t *journal)
@@ -410,6 +450,9 @@
 	tid_t		first_tid;
 	unsigned long	blocknr, freed;
 
+	if (is_journal_aborted(journal))
+		return 1;
+
 	/* OK, work out the oldest transaction remaining in the log, and
 	 * the log block it starts at.
 	 *
diff --git a/fs/jbd2/commit.c b/fs/jbd2/commit.c
index f2ad061..0abe02c 100644
--- a/fs/jbd2/commit.c
+++ b/fs/jbd2/commit.c
@@ -16,6 +16,7 @@
 #include <linux/time.h>
 #include <linux/fs.h>
 #include <linux/jbd2.h>
+#include <linux/marker.h>
 #include <linux/errno.h>
 #include <linux/slab.h>
 #include <linux/mm.h>
@@ -126,8 +127,7 @@
 
 	JBUFFER_TRACE(descriptor, "submit commit block");
 	lock_buffer(bh);
-	get_bh(bh);
-	set_buffer_dirty(bh);
+	clear_buffer_dirty(bh);
 	set_buffer_uptodate(bh);
 	bh->b_end_io = journal_end_buffer_io_sync;
 
@@ -147,12 +147,9 @@
 	 * to remember if we sent a barrier request
 	 */
 	if (ret == -EOPNOTSUPP && barrier_done) {
-		char b[BDEVNAME_SIZE];
-
 		printk(KERN_WARNING
-			"JBD: barrier-based sync failed on %s - "
-			"disabling barriers\n",
-			bdevname(journal->j_dev, b));
+		       "JBD: barrier-based sync failed on %s - "
+		       "disabling barriers\n", journal->j_devname);
 		spin_lock(&journal->j_state_lock);
 		journal->j_flags &= ~JBD2_BARRIER;
 		spin_unlock(&journal->j_state_lock);
@@ -160,7 +157,7 @@
 		/* And try again, without the barrier */
 		lock_buffer(bh);
 		set_buffer_uptodate(bh);
-		set_buffer_dirty(bh);
+		clear_buffer_dirty(bh);
 		ret = submit_bh(WRITE, bh);
 	}
 	*cbh = bh;
@@ -371,6 +368,8 @@
 	commit_transaction = journal->j_running_transaction;
 	J_ASSERT(commit_transaction->t_state == T_RUNNING);
 
+	trace_mark(jbd2_start_commit, "dev %s transaction %d",
+		   journal->j_devname, commit_transaction->t_tid);
 	jbd_debug(1, "JBD: starting commit of transaction %d\n",
 			commit_transaction->t_tid);
 
@@ -505,9 +504,10 @@
 		jh = commit_transaction->t_buffers;
 
 		/* If we're in abort mode, we just un-journal the buffer and
-		   release it for background writing. */
+		   release it. */
 
 		if (is_journal_aborted(journal)) {
+			clear_buffer_jbddirty(jh2bh(jh));
 			JBUFFER_TRACE(jh, "journal is aborting: refile");
 			jbd2_journal_refile_buffer(journal, jh);
 			/* If that was the last one, we need to clean up
@@ -681,11 +681,11 @@
 	 */
 	err = journal_finish_inode_data_buffers(journal, commit_transaction);
 	if (err) {
-		char b[BDEVNAME_SIZE];
-
 		printk(KERN_WARNING
 			"JBD2: Detected IO errors while flushing file data "
-			"on %s\n", bdevname(journal->j_fs_dev, b));
+		       "on %s\n", journal->j_devname);
+		if (journal->j_flags & JBD2_ABORT_ON_SYNCDATA_ERR)
+			jbd2_journal_abort(journal, err);
 		err = 0;
 	}
 
@@ -786,6 +786,9 @@
 		/* AKPM: bforget here */
 	}
 
+	if (err)
+		jbd2_journal_abort(journal, err);
+
 	jbd_debug(3, "JBD: commit phase 5\n");
 
 	if (!JBD2_HAS_INCOMPAT_FEATURE(journal,
@@ -884,6 +887,8 @@
 		if (buffer_jbddirty(bh)) {
 			JBUFFER_TRACE(jh, "add to new checkpointing trans");
 			__jbd2_journal_insert_checkpoint(jh, commit_transaction);
+			if (is_journal_aborted(journal))
+				clear_buffer_jbddirty(bh);
 			JBUFFER_TRACE(jh, "refile for checkpoint writeback");
 			__jbd2_journal_refile_buffer(jh);
 			jbd_unlock_bh_state(bh);
@@ -990,6 +995,9 @@
 	}
 	spin_unlock(&journal->j_list_lock);
 
+	trace_mark(jbd2_end_commit, "dev %s transaction %d head %d",
+		   journal->j_devname, commit_transaction->t_tid,
+		   journal->j_tail_sequence);
 	jbd_debug(1, "JBD: commit %d complete, head %d\n",
 		  journal->j_commit_sequence, journal->j_tail_sequence);
 
diff --git a/fs/jbd2/journal.c b/fs/jbd2/journal.c
index 8207a01..783de11 100644
--- a/fs/jbd2/journal.c
+++ b/fs/jbd2/journal.c
@@ -597,13 +597,9 @@
 		if (ret)
 			*retp = ret;
 		else {
-			char b[BDEVNAME_SIZE];
-
 			printk(KERN_ALERT "%s: journal block not found "
 					"at offset %lu on %s\n",
-				__func__,
-				blocknr,
-				bdevname(journal->j_dev, b));
+			       __func__, blocknr, journal->j_devname);
 			err = -EIO;
 			__journal_abort_soft(journal, err);
 		}
@@ -901,10 +897,7 @@
 
 static void jbd2_stats_proc_init(journal_t *journal)
 {
-	char name[BDEVNAME_SIZE];
-
-	bdevname(journal->j_dev, name);
-	journal->j_proc_entry = proc_mkdir(name, proc_jbd2_stats);
+	journal->j_proc_entry = proc_mkdir(journal->j_devname, proc_jbd2_stats);
 	if (journal->j_proc_entry) {
 		proc_create_data("history", S_IRUGO, journal->j_proc_entry,
 				 &jbd2_seq_history_fops, journal);
@@ -915,12 +908,9 @@
 
 static void jbd2_stats_proc_exit(journal_t *journal)
 {
-	char name[BDEVNAME_SIZE];
-
-	bdevname(journal->j_dev, name);
 	remove_proc_entry("info", journal->j_proc_entry);
 	remove_proc_entry("history", journal->j_proc_entry);
-	remove_proc_entry(name, proc_jbd2_stats);
+	remove_proc_entry(journal->j_devname, proc_jbd2_stats);
 }
 
 static void journal_init_stats(journal_t *journal)
@@ -1018,6 +1008,7 @@
 {
 	journal_t *journal = journal_init_common();
 	struct buffer_head *bh;
+	char *p;
 	int n;
 
 	if (!journal)
@@ -1039,6 +1030,10 @@
 	journal->j_fs_dev = fs_dev;
 	journal->j_blk_offset = start;
 	journal->j_maxlen = len;
+	bdevname(journal->j_dev, journal->j_devname);
+	p = journal->j_devname;
+	while ((p = strchr(p, '/')))
+		*p = '!';
 	jbd2_stats_proc_init(journal);
 
 	bh = __getblk(journal->j_dev, start, journal->j_blocksize);
@@ -1061,6 +1056,7 @@
 {
 	struct buffer_head *bh;
 	journal_t *journal = journal_init_common();
+	char *p;
 	int err;
 	int n;
 	unsigned long long blocknr;
@@ -1070,6 +1066,12 @@
 
 	journal->j_dev = journal->j_fs_dev = inode->i_sb->s_bdev;
 	journal->j_inode = inode;
+	bdevname(journal->j_dev, journal->j_devname);
+	p = journal->j_devname;
+	while ((p = strchr(p, '/')))
+		*p = '!';
+	p = journal->j_devname + strlen(journal->j_devname);
+	sprintf(p, ":%lu", journal->j_inode->i_ino);
 	jbd_debug(1,
 		  "journal %p: inode %s/%ld, size %Ld, bits %d, blksize %ld\n",
 		  journal, inode->i_sb->s_id, inode->i_ino,
@@ -1253,6 +1255,22 @@
 		goto out;
 	}
 
+	if (buffer_write_io_error(bh)) {
+		/*
+		 * Oh, dear.  A previous attempt to write the journal
+		 * superblock failed.  This could happen because the
+		 * USB device was yanked out.  Or it could happen to
+		 * be a transient write error and maybe the block will
+		 * be remapped.  Nothing we can do but to retry the
+		 * write and hope for the best.
+		 */
+		printk(KERN_ERR "JBD2: previous I/O error detected "
+		       "for journal superblock update for %s.\n",
+		       journal->j_devname);
+		clear_buffer_write_io_error(bh);
+		set_buffer_uptodate(bh);
+	}
+
 	spin_lock(&journal->j_state_lock);
 	jbd_debug(1,"JBD: updating superblock (start %ld, seq %d, errno %d)\n",
 		  journal->j_tail, journal->j_tail_sequence, journal->j_errno);
@@ -1264,9 +1282,16 @@
 
 	BUFFER_TRACE(bh, "marking dirty");
 	mark_buffer_dirty(bh);
-	if (wait)
+	if (wait) {
 		sync_dirty_buffer(bh);
-	else
+		if (buffer_write_io_error(bh)) {
+			printk(KERN_ERR "JBD2: I/O error detected "
+			       "when updating journal superblock for %s.\n",
+			       journal->j_devname);
+			clear_buffer_write_io_error(bh);
+			set_buffer_uptodate(bh);
+		}
+	} else
 		ll_rw_block(SWRITE, 1, &bh);
 
 out:
@@ -1426,9 +1451,12 @@
  *
  * Release a journal_t structure once it is no longer in use by the
  * journaled object.
+ * Return <0 if we couldn't clean up the journal.
  */
-void jbd2_journal_destroy(journal_t *journal)
+int jbd2_journal_destroy(journal_t *journal)
 {
+	int err = 0;
+
 	/* Wait for the commit thread to wake up and die. */
 	journal_kill_thread(journal);
 
@@ -1451,11 +1479,16 @@
 	J_ASSERT(journal->j_checkpoint_transactions == NULL);
 	spin_unlock(&journal->j_list_lock);
 
-	/* We can now mark the journal as empty. */
-	journal->j_tail = 0;
-	journal->j_tail_sequence = ++journal->j_transaction_sequence;
 	if (journal->j_sb_buffer) {
-		jbd2_journal_update_superblock(journal, 1);
+		if (!is_journal_aborted(journal)) {
+			/* We can now mark the journal as empty. */
+			journal->j_tail = 0;
+			journal->j_tail_sequence =
+				++journal->j_transaction_sequence;
+			jbd2_journal_update_superblock(journal, 1);
+		} else {
+			err = -EIO;
+		}
 		brelse(journal->j_sb_buffer);
 	}
 
@@ -1467,6 +1500,8 @@
 		jbd2_journal_destroy_revoke(journal);
 	kfree(journal->j_wbuf);
 	kfree(journal);
+
+	return err;
 }
 
 
@@ -1692,10 +1727,16 @@
 	spin_lock(&journal->j_list_lock);
 	while (!err && journal->j_checkpoint_transactions != NULL) {
 		spin_unlock(&journal->j_list_lock);
+		mutex_lock(&journal->j_checkpoint_mutex);
 		err = jbd2_log_do_checkpoint(journal);
+		mutex_unlock(&journal->j_checkpoint_mutex);
 		spin_lock(&journal->j_list_lock);
 	}
 	spin_unlock(&journal->j_list_lock);
+
+	if (is_journal_aborted(journal))
+		return -EIO;
+
 	jbd2_cleanup_journal_tail(journal);
 
 	/* Finally, mark the journal as really needing no recovery.
@@ -1717,7 +1758,7 @@
 	J_ASSERT(journal->j_head == journal->j_tail);
 	J_ASSERT(journal->j_tail_sequence == journal->j_transaction_sequence);
 	spin_unlock(&journal->j_state_lock);
-	return err;
+	return 0;
 }
 
 /**
@@ -1761,23 +1802,6 @@
 }
 
 /*
- * journal_dev_name: format a character string to describe on what
- * device this journal is present.
- */
-
-static const char *journal_dev_name(journal_t *journal, char *buffer)
-{
-	struct block_device *bdev;
-
-	if (journal->j_inode)
-		bdev = journal->j_inode->i_sb->s_bdev;
-	else
-		bdev = journal->j_dev;
-
-	return bdevname(bdev, buffer);
-}
-
-/*
  * Journal abort has very specific semantics, which we describe
  * for journal abort.
  *
@@ -1793,13 +1817,12 @@
 void __jbd2_journal_abort_hard(journal_t *journal)
 {
 	transaction_t *transaction;
-	char b[BDEVNAME_SIZE];
 
 	if (journal->j_flags & JBD2_ABORT)
 		return;
 
 	printk(KERN_ERR "Aborting journal on device %s.\n",
-		journal_dev_name(journal, b));
+	       journal->j_devname);
 
 	spin_lock(&journal->j_state_lock);
 	journal->j_flags |= JBD2_ABORT;
diff --git a/fs/jbd2/recovery.c b/fs/jbd2/recovery.c
index 058f50f..7306328 100644
--- a/fs/jbd2/recovery.c
+++ b/fs/jbd2/recovery.c
@@ -225,7 +225,7 @@
  */
 int jbd2_journal_recover(journal_t *journal)
 {
-	int			err;
+	int			err, err2;
 	journal_superblock_t *	sb;
 
 	struct recovery_info	info;
@@ -263,7 +263,10 @@
 	journal->j_transaction_sequence = ++info.end_transaction;
 
 	jbd2_journal_clear_revoke(journal);
-	sync_blockdev(journal->j_fs_dev);
+	err2 = sync_blockdev(journal->j_fs_dev);
+	if (!err)
+		err = err2;
+
 	return err;
 }
 
diff --git a/fs/jfs/super.c b/fs/jfs/super.c
index 3630718..0dae345 100644
--- a/fs/jfs/super.c
+++ b/fs/jfs/super.c
@@ -199,7 +199,7 @@
 	Opt_usrquota, Opt_grpquota, Opt_uid, Opt_gid, Opt_umask
 };
 
-static match_table_t tokens = {
+static const match_table_t tokens = {
 	{Opt_integrity, "integrity"},
 	{Opt_nointegrity, "nointegrity"},
 	{Opt_iocharset, "iocharset=%s"},
diff --git a/fs/lockd/Makefile b/fs/lockd/Makefile
index 7725a0a..97f6073 100644
--- a/fs/lockd/Makefile
+++ b/fs/lockd/Makefile
@@ -5,6 +5,6 @@
 obj-$(CONFIG_LOCKD) += lockd.o
 
 lockd-objs-y := clntlock.o clntproc.o host.o svc.o svclock.o svcshare.o \
-	        svcproc.o svcsubs.o mon.o xdr.o
+	        svcproc.o svcsubs.o mon.o xdr.o grace.o
 lockd-objs-$(CONFIG_LOCKD_V4) += xdr4.o svc4proc.o
 lockd-objs		      := $(lockd-objs-y)
diff --git a/fs/lockd/clntlock.c b/fs/lockd/clntlock.c
index 0b45fd3..8307dd6 100644
--- a/fs/lockd/clntlock.c
+++ b/fs/lockd/clntlock.c
@@ -54,14 +54,13 @@
 	u32 nlm_version = (nlm_init->nfs_version == 2) ? 1 : 4;
 	int status;
 
-	status = lockd_up(nlm_init->protocol);
+	status = lockd_up();
 	if (status < 0)
 		return ERR_PTR(status);
 
-	host = nlmclnt_lookup_host((struct sockaddr_in *)nlm_init->address,
+	host = nlmclnt_lookup_host(nlm_init->address, nlm_init->addrlen,
 				   nlm_init->protocol, nlm_version,
-				   nlm_init->hostname,
-				   strlen(nlm_init->hostname));
+				   nlm_init->hostname);
 	if (host == NULL) {
 		lockd_down();
 		return ERR_PTR(-ENOLCK);
@@ -142,7 +141,7 @@
 /*
  * The server lockd has called us back to tell us the lock was granted
  */
-__be32 nlmclnt_grant(const struct sockaddr_in *addr, const struct nlm_lock *lock)
+__be32 nlmclnt_grant(const struct sockaddr *addr, const struct nlm_lock *lock)
 {
 	const struct file_lock *fl = &lock->fl;
 	const struct nfs_fh *fh = &lock->fh;
@@ -166,7 +165,7 @@
 		 */
 		if (fl_blocked->fl_u.nfs_fl.owner->pid != lock->svid)
 			continue;
-		if (!nlm_cmp_addr(&block->b_host->h_addr, addr))
+		if (!nlm_cmp_addr(nlm_addr(block->b_host), addr))
 			continue;
 		if (nfs_compare_fh(NFS_FH(fl_blocked->fl_file->f_path.dentry->d_inode) ,fh) != 0)
 			continue;
@@ -216,7 +215,7 @@
 	/* 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 */
+	lockd_up();	/* note: this cannot fail as lockd is already running */
 
 	dprintk("lockd: reclaiming locks for host %s\n", host->h_name);
 
diff --git a/fs/lockd/grace.c b/fs/lockd/grace.c
new file mode 100644
index 0000000..183cc1f
--- /dev/null
+++ b/fs/lockd/grace.c
@@ -0,0 +1,59 @@
+/*
+ * Common code for control of lockd and nfsv4 grace periods.
+ */
+
+#include <linux/module.h>
+#include <linux/lockd/bind.h>
+
+static LIST_HEAD(grace_list);
+static DEFINE_SPINLOCK(grace_lock);
+
+/**
+ * locks_start_grace
+ * @lm: who this grace period is for
+ *
+ * A grace period is a period during which locks should not be given
+ * out.  Currently grace periods are only enforced by the two lock
+ * managers (lockd and nfsd), using the locks_in_grace() function to
+ * check when they are in a grace period.
+ *
+ * This function is called to start a grace period.
+ */
+void locks_start_grace(struct lock_manager *lm)
+{
+	spin_lock(&grace_lock);
+	list_add(&lm->list, &grace_list);
+	spin_unlock(&grace_lock);
+}
+EXPORT_SYMBOL_GPL(locks_start_grace);
+
+/**
+ * locks_end_grace
+ * @lm: who this grace period is for
+ *
+ * Call this function to state that the given lock manager is ready to
+ * resume regular locking.  The grace period will not end until all lock
+ * managers that called locks_start_grace() also call locks_end_grace().
+ * Note that callers count on it being safe to call this more than once,
+ * and the second call should be a no-op.
+ */
+void locks_end_grace(struct lock_manager *lm)
+{
+	spin_lock(&grace_lock);
+	list_del_init(&lm->list);
+	spin_unlock(&grace_lock);
+}
+EXPORT_SYMBOL_GPL(locks_end_grace);
+
+/**
+ * locks_in_grace
+ *
+ * Lock managers call this function to determine when it is OK for them
+ * to answer ordinary lock requests, and when they should accept only
+ * lock reclaims.
+ */
+int locks_in_grace(void)
+{
+	return !list_empty(&grace_list);
+}
+EXPORT_SYMBOL_GPL(locks_in_grace);
diff --git a/fs/lockd/host.c b/fs/lockd/host.c
index a17664c..9fd8889 100644
--- a/fs/lockd/host.c
+++ b/fs/lockd/host.c
@@ -11,16 +11,17 @@
 #include <linux/types.h>
 #include <linux/slab.h>
 #include <linux/in.h>
+#include <linux/in6.h>
 #include <linux/sunrpc/clnt.h>
 #include <linux/sunrpc/svc.h>
 #include <linux/lockd/lockd.h>
 #include <linux/lockd/sm_inter.h>
 #include <linux/mutex.h>
 
+#include <net/ipv6.h>
 
 #define NLMDBG_FACILITY		NLMDBG_HOSTCACHE
 #define NLM_HOST_NRHASH		32
-#define NLM_ADDRHASH(addr)	(ntohl(addr) & (NLM_HOST_NRHASH-1))
 #define NLM_HOST_REBIND		(60 * HZ)
 #define NLM_HOST_EXPIRE		(300 * HZ)
 #define NLM_HOST_COLLECT	(120 * HZ)
@@ -30,42 +31,115 @@
 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 *, unsigned int, int);
-static struct nsm_handle *	nsm_find(const struct sockaddr_in *sin,
-					 const char *hostname,
-					 unsigned int hostname_len);
+static struct nsm_handle	*nsm_find(const struct sockaddr *sap,
+						const size_t salen,
+						const char *hostname,
+						const size_t hostname_len,
+						const int create);
+
+struct nlm_lookup_host_info {
+	const int		server;		/* search for server|client */
+	const struct sockaddr	*sap;		/* address to search for */
+	const size_t		salen;		/* it's length */
+	const unsigned short	protocol;	/* transport to search for*/
+	const u32		version;	/* NLM version to search for */
+	const char		*hostname;	/* remote's hostname */
+	const size_t		hostname_len;	/* it's length */
+	const struct sockaddr	*src_sap;	/* our address (optional) */
+	const size_t		src_len;	/* it's length */
+};
+
+/*
+ * Hash function must work well on big- and little-endian platforms
+ */
+static unsigned int __nlm_hash32(const __be32 n)
+{
+	unsigned int hash = (__force u32)n ^ ((__force u32)n >> 16);
+	return hash ^ (hash >> 8);
+}
+
+static unsigned int __nlm_hash_addr4(const struct sockaddr *sap)
+{
+	const struct sockaddr_in *sin = (struct sockaddr_in *)sap;
+	return __nlm_hash32(sin->sin_addr.s_addr);
+}
+
+static unsigned int __nlm_hash_addr6(const struct sockaddr *sap)
+{
+	const struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sap;
+	const struct in6_addr addr = sin6->sin6_addr;
+	return __nlm_hash32(addr.s6_addr32[0]) ^
+	       __nlm_hash32(addr.s6_addr32[1]) ^
+	       __nlm_hash32(addr.s6_addr32[2]) ^
+	       __nlm_hash32(addr.s6_addr32[3]);
+}
+
+static unsigned int nlm_hash_address(const struct sockaddr *sap)
+{
+	unsigned int hash;
+
+	switch (sap->sa_family) {
+	case AF_INET:
+		hash = __nlm_hash_addr4(sap);
+		break;
+	case AF_INET6:
+		hash = __nlm_hash_addr6(sap);
+		break;
+	default:
+		hash = 0;
+	}
+	return hash & (NLM_HOST_NRHASH - 1);
+}
+
+static void nlm_clear_port(struct sockaddr *sap)
+{
+	switch (sap->sa_family) {
+	case AF_INET:
+		((struct sockaddr_in *)sap)->sin_port = 0;
+		break;
+	case AF_INET6:
+		((struct sockaddr_in6 *)sap)->sin6_port = 0;
+		break;
+	}
+}
+
+static void nlm_display_address(const struct sockaddr *sap,
+				char *buf, const size_t len)
+{
+	const struct sockaddr_in *sin = (struct sockaddr_in *)sap;
+	const struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sap;
+
+	switch (sap->sa_family) {
+	case AF_UNSPEC:
+		snprintf(buf, len, "unspecified");
+		break;
+	case AF_INET:
+		snprintf(buf, len, NIPQUAD_FMT, NIPQUAD(sin->sin_addr.s_addr));
+		break;
+	case AF_INET6:
+		if (ipv6_addr_v4mapped(&sin6->sin6_addr))
+			snprintf(buf, len, NIPQUAD_FMT,
+				 NIPQUAD(sin6->sin6_addr.s6_addr32[3]));
+		else
+			snprintf(buf, len, NIP6_FMT, NIP6(sin6->sin6_addr));
+		break;
+	default:
+		snprintf(buf, len, "unsupported address family");
+		break;
+	}
+}
 
 /*
  * Common host lookup routine for server & client
  */
-static struct nlm_host *nlm_lookup_host(int server,
-					const struct sockaddr_in *sin,
-					int proto, u32 version,
-					const char *hostname,
-					unsigned int hostname_len,
-					const struct sockaddr_in *ssin)
+static struct nlm_host *nlm_lookup_host(struct nlm_lookup_host_info *ni)
 {
 	struct hlist_head *chain;
 	struct hlist_node *pos;
 	struct nlm_host	*host;
 	struct nsm_handle *nsm = NULL;
-	int		hash;
 
-	dprintk("lockd: nlm_lookup_host("NIPQUAD_FMT"->"NIPQUAD_FMT
-			", p=%d, v=%u, my role=%s, name=%.*s)\n",
-			NIPQUAD(ssin->sin_addr.s_addr),
-			NIPQUAD(sin->sin_addr.s_addr), proto, version,
-			server? "server" : "client",
-			hostname_len,
-			hostname? hostname : "<none>");
-
-
-	hash = NLM_ADDRHASH(sin->sin_addr.s_addr);
-
-	/* Lock hash table */
 	mutex_lock(&nlm_host_mutex);
 
 	if (time_after_eq(jiffies, next_gc))
@@ -78,22 +152,22 @@
 	 * 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];
+	chain = &nlm_hosts[nlm_hash_address(ni->sap)];
 	hlist_for_each_entry(host, pos, chain, h_hash) {
-		if (!nlm_cmp_addr(&host->h_addr, sin))
+		if (!nlm_cmp_addr(nlm_addr(host), ni->sap))
 			continue;
 
 		/* See if we have an NSM handle for this client */
 		if (!nsm)
 			nsm = host->h_nsmhandle;
 
-		if (host->h_proto != proto)
+		if (host->h_proto != ni->protocol)
 			continue;
-		if (host->h_version != version)
+		if (host->h_version != ni->version)
 			continue;
-		if (host->h_server != server)
+		if (host->h_server != ni->server)
 			continue;
-		if (!nlm_cmp_addr(&host->h_saddr, ssin))
+		if (!nlm_cmp_addr(nlm_srcaddr(host), ni->src_sap))
 			continue;
 
 		/* Move to head of hash chain. */
@@ -101,30 +175,41 @@
 		hlist_add_head(&host->h_hash, chain);
 
 		nlm_get_host(host);
+		dprintk("lockd: nlm_lookup_host found host %s (%s)\n",
+				host->h_name, host->h_addrbuf);
 		goto out;
 	}
+
+	/*
+	 * The host wasn't in our hash table.  If we don't
+	 * have an NSM handle for it yet, create one.
+	 */
 	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;
+	else {
+		host = NULL;
+		nsm = nsm_find(ni->sap, ni->salen,
+				ni->hostname, ni->hostname_len, 1);
+		if (!nsm) {
+			dprintk("lockd: nlm_lookup_host failed; "
+				"no nsm handle\n");
+			goto out;
+		}
+	}
 
 	host = kzalloc(sizeof(*host), GFP_KERNEL);
 	if (!host) {
 		nsm_release(nsm);
+		dprintk("lockd: nlm_lookup_host failed; no memory\n");
 		goto out;
 	}
 	host->h_name	   = nsm->sm_name;
-	host->h_addr       = *sin;
-	host->h_addr.sin_port = 0;	/* ouch! */
-	host->h_saddr	   = *ssin;
-	host->h_version    = version;
-	host->h_proto      = proto;
+	memcpy(nlm_addr(host), ni->sap, ni->salen);
+	host->h_addrlen = ni->salen;
+	nlm_clear_port(nlm_addr(host));
+	memcpy(nlm_srcaddr(host), ni->src_sap, ni->src_len);
+	host->h_version    = ni->version;
+	host->h_proto      = ni->protocol;
 	host->h_rpcclnt    = NULL;
 	mutex_init(&host->h_mutex);
 	host->h_nextrebind = jiffies + NLM_HOST_REBIND;
@@ -135,7 +220,7 @@
 	host->h_state      = 0;			/* pseudo NSM state */
 	host->h_nsmstate   = 0;			/* real NSM state */
 	host->h_nsmhandle  = nsm;
-	host->h_server	   = server;
+	host->h_server	   = ni->server;
 	hlist_add_head(&host->h_hash, chain);
 	INIT_LIST_HEAD(&host->h_lockowners);
 	spin_lock_init(&host->h_lock);
@@ -143,6 +228,15 @@
 	INIT_LIST_HEAD(&host->h_reclaim);
 
 	nrhosts++;
+
+	nlm_display_address((struct sockaddr *)&host->h_addr,
+				host->h_addrbuf, sizeof(host->h_addrbuf));
+	nlm_display_address((struct sockaddr *)&host->h_srcaddr,
+				host->h_srcaddrbuf, sizeof(host->h_srcaddrbuf));
+
+	dprintk("lockd: nlm_lookup_host created host %s\n",
+			host->h_name);
+
 out:
 	mutex_unlock(&nlm_host_mutex);
 	return host;
@@ -170,33 +264,103 @@
 	kfree(host);
 }
 
-/*
- * Find an NLM server handle in the cache. If there is none, create it.
+/**
+ * nlmclnt_lookup_host - Find an NLM host handle matching a remote server
+ * @sap: network address of server
+ * @salen: length of server address
+ * @protocol: transport protocol to use
+ * @version: NLM protocol version
+ * @hostname: '\0'-terminated hostname of server
+ *
+ * Returns an nlm_host structure that matches the passed-in
+ * [server address, transport protocol, NLM version, server hostname].
+ * If one doesn't already exist in the host cache, a new handle is
+ * created and returned.
  */
-struct nlm_host *nlmclnt_lookup_host(const struct sockaddr_in *sin,
-				     int proto, u32 version,
-				     const char *hostname,
-				     unsigned int hostname_len)
+struct nlm_host *nlmclnt_lookup_host(const struct sockaddr *sap,
+				     const size_t salen,
+				     const unsigned short protocol,
+				     const u32 version, const char *hostname)
 {
-	struct sockaddr_in ssin = {0};
+	const struct sockaddr source = {
+		.sa_family	= AF_UNSPEC,
+	};
+	struct nlm_lookup_host_info ni = {
+		.server		= 0,
+		.sap		= sap,
+		.salen		= salen,
+		.protocol	= protocol,
+		.version	= version,
+		.hostname	= hostname,
+		.hostname_len	= strlen(hostname),
+		.src_sap	= &source,
+		.src_len	= sizeof(source),
+	};
 
-	return nlm_lookup_host(0, sin, proto, version,
-			       hostname, hostname_len, &ssin);
+	dprintk("lockd: %s(host='%s', vers=%u, proto=%s)\n", __func__,
+			(hostname ? hostname : "<none>"), version,
+			(protocol == IPPROTO_UDP ? "udp" : "tcp"));
+
+	return nlm_lookup_host(&ni);
 }
 
-/*
- * Find an NLM client handle in the cache. If there is none, create it.
+/**
+ * nlmsvc_lookup_host - Find an NLM host handle matching a remote client
+ * @rqstp: incoming NLM request
+ * @hostname: name of client host
+ * @hostname_len: length of client hostname
+ *
+ * Returns an nlm_host structure that matches the [client address,
+ * transport protocol, NLM version, client hostname] of the passed-in
+ * NLM request.  If one doesn't already exist in the host cache, a
+ * new handle is created and returned.
+ *
+ * Before possibly creating a new nlm_host, construct a sockaddr
+ * for a specific source address in case the local system has
+ * multiple network addresses.  The family of the address in
+ * rq_daddr is guaranteed to be the same as the family of the
+ * address in rq_addr, so it's safe to use the same family for
+ * the source address.
  */
-struct nlm_host *
-nlmsvc_lookup_host(struct svc_rqst *rqstp,
-			const char *hostname, unsigned int hostname_len)
+struct nlm_host *nlmsvc_lookup_host(const struct svc_rqst *rqstp,
+				    const char *hostname,
+				    const size_t hostname_len)
 {
-	struct sockaddr_in ssin = {0};
+	struct sockaddr_in sin = {
+		.sin_family	= AF_INET,
+	};
+	struct sockaddr_in6 sin6 = {
+		.sin6_family	= AF_INET6,
+	};
+	struct nlm_lookup_host_info ni = {
+		.server		= 1,
+		.sap		= svc_addr(rqstp),
+		.salen		= rqstp->rq_addrlen,
+		.protocol	= rqstp->rq_prot,
+		.version	= rqstp->rq_vers,
+		.hostname	= hostname,
+		.hostname_len	= hostname_len,
+		.src_len	= rqstp->rq_addrlen,
+	};
 
-	ssin.sin_addr = rqstp->rq_daddr.addr;
-	return nlm_lookup_host(1, svc_addr_in(rqstp),
-			       rqstp->rq_prot, rqstp->rq_vers,
-			       hostname, hostname_len, &ssin);
+	dprintk("lockd: %s(host='%*s', vers=%u, proto=%s)\n", __func__,
+			(int)hostname_len, hostname, rqstp->rq_vers,
+			(rqstp->rq_prot == IPPROTO_UDP ? "udp" : "tcp"));
+
+	switch (ni.sap->sa_family) {
+	case AF_INET:
+		sin.sin_addr.s_addr = rqstp->rq_daddr.addr.s_addr;
+		ni.src_sap = (struct sockaddr *)&sin;
+		break;
+	case AF_INET6:
+		ipv6_addr_copy(&sin6.sin6_addr, &rqstp->rq_daddr.addr6);
+		ni.src_sap = (struct sockaddr *)&sin6;
+		break;
+	default:
+		return NULL;
+	}
+
+	return nlm_lookup_host(&ni);
 }
 
 /*
@@ -207,9 +371,8 @@
 {
 	struct rpc_clnt	*clnt;
 
-	dprintk("lockd: nlm_bind_host("NIPQUAD_FMT"->"NIPQUAD_FMT")\n",
-			NIPQUAD(host->h_saddr.sin_addr),
-			NIPQUAD(host->h_addr.sin_addr));
+	dprintk("lockd: nlm_bind_host %s (%s), my addr=%s\n",
+			host->h_name, host->h_addrbuf, host->h_srcaddrbuf);
 
 	/* Lock host handle */
 	mutex_lock(&host->h_mutex);
@@ -221,7 +384,7 @@
 		if (time_after_eq(jiffies, host->h_nextrebind)) {
 			rpc_force_rebind(clnt);
 			host->h_nextrebind = jiffies + NLM_HOST_REBIND;
-			dprintk("lockd: next rebind in %ld jiffies\n",
+			dprintk("lockd: next rebind in %lu jiffies\n",
 					host->h_nextrebind - jiffies);
 		}
 	} else {
@@ -234,9 +397,9 @@
 		};
 		struct rpc_create_args args = {
 			.protocol	= host->h_proto,
-			.address	= (struct sockaddr *)&host->h_addr,
-			.addrsize	= sizeof(host->h_addr),
-			.saddress	= (struct sockaddr *)&host->h_saddr,
+			.address	= nlm_addr(host),
+			.addrsize	= host->h_addrlen,
+			.saddress	= nlm_srcaddr(host),
 			.timeout	= &timeparms,
 			.servername	= host->h_name,
 			.program	= &nlm_program,
@@ -324,12 +487,16 @@
 	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)))
+	nsm = nsm_find((struct sockaddr *)sin, sizeof(*sin),
+			hostname, hostname_len, 0);
+	if (nsm == NULL) {
+		dprintk("lockd: never saw rebooted peer '%.*s' before\n",
+				hostname_len, hostname);
 		return;
+	}
+
+	dprintk("lockd: nlm_host_rebooted(%.*s, %s)\n",
+			hostname_len, hostname, nsm->sm_addrbuf);
 
 	/* When reclaiming locks on this peer, make sure that
 	 * we set up a new notification */
@@ -461,22 +628,23 @@
 static LIST_HEAD(nsm_handles);
 static DEFINE_SPINLOCK(nsm_lock);
 
-static struct nsm_handle *
-__nsm_find(const struct sockaddr_in *sin,
-		const char *hostname, unsigned int hostname_len,
-		int create)
+static struct nsm_handle *nsm_find(const struct sockaddr *sap,
+				   const size_t salen,
+				   const char *hostname,
+				   const size_t hostname_len,
+				   const int create)
 {
 	struct nsm_handle *nsm = NULL;
 	struct nsm_handle *pos;
 
-	if (!sin)
+	if (!sap)
 		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);
+				(int)hostname_len, hostname);
 		}
 		return NULL;
 	}
@@ -489,7 +657,7 @@
 			if (strlen(pos->sm_name) != hostname_len
 			 || memcmp(pos->sm_name, hostname, hostname_len))
 				continue;
-		} else if (!nlm_cmp_addr(&pos->sm_addr, sin))
+		} else if (!nlm_cmp_addr(nsm_addr(pos), sap))
 			continue;
 		atomic_inc(&pos->sm_count);
 		kfree(nsm);
@@ -509,10 +677,13 @@
 	if (nsm == NULL)
 		return NULL;
 
-	nsm->sm_addr = *sin;
+	memcpy(nsm_addr(nsm), sap, salen);
+	nsm->sm_addrlen = salen;
 	nsm->sm_name = (char *) (nsm + 1);
 	memcpy(nsm->sm_name, hostname, hostname_len);
 	nsm->sm_name[hostname_len] = '\0';
+	nlm_display_address((struct sockaddr *)&nsm->sm_addr,
+				nsm->sm_addrbuf, sizeof(nsm->sm_addrbuf));
 	atomic_set(&nsm->sm_count, 1);
 	goto retry;
 
@@ -521,13 +692,6 @@
 	return nsm;
 }
 
-static struct nsm_handle *
-nsm_find(const struct sockaddr_in *sin, const char *hostname,
-	 unsigned int hostname_len)
-{
-	return __nsm_find(sin, hostname, hostname_len, 1);
-}
-
 /*
  * Release an NSM handle
  */
diff --git a/fs/lockd/mon.c b/fs/lockd/mon.c
index e4d5635..4e7e958 100644
--- a/fs/lockd/mon.c
+++ b/fs/lockd/mon.c
@@ -51,7 +51,7 @@
 
 	memset(&args, 0, sizeof(args));
 	args.mon_name = nsm->sm_name;
-	args.addr = nsm->sm_addr.sin_addr.s_addr;
+	args.addr = nsm_addr_in(nsm)->sin_addr.s_addr;
 	args.prog = NLM_PROGRAM;
 	args.vers = 3;
 	args.proc = NLMPROC_NSM_NOTIFY;
diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c
index 5bd9bf0..c631a83 100644
--- a/fs/lockd/svc.c
+++ b/fs/lockd/svc.c
@@ -51,7 +51,6 @@
 static unsigned int		nlmsvc_users;
 static struct task_struct	*nlmsvc_task;
 static struct svc_rqst		*nlmsvc_rqst;
-int				nlmsvc_grace_period;
 unsigned long			nlmsvc_timeout;
 
 /*
@@ -85,27 +84,23 @@
 		return nlm_timeout * 5 * HZ;
 }
 
-unsigned long get_nfs_grace_period(void)
+static struct lock_manager lockd_manager = {
+};
+
+static void grace_ender(struct work_struct *not_used)
 {
-	unsigned long lockdgrace = get_lockd_grace_period();
-	unsigned long nfsdgrace = 0;
-
-	if (nlmsvc_ops)
-		nfsdgrace = nlmsvc_ops->get_grace_period();
-
-	return max(lockdgrace, nfsdgrace);
-}
-EXPORT_SYMBOL(get_nfs_grace_period);
-
-static unsigned long set_grace_period(void)
-{
-	nlmsvc_grace_period = 1;
-	return get_nfs_grace_period() + jiffies;
+	locks_end_grace(&lockd_manager);
 }
 
-static inline void clear_grace_period(void)
+static DECLARE_DELAYED_WORK(grace_period_end, grace_ender);
+
+static void set_grace_period(void)
 {
-	nlmsvc_grace_period = 0;
+	unsigned long grace_period = get_lockd_grace_period();
+
+	locks_start_grace(&lockd_manager);
+	cancel_delayed_work_sync(&grace_period_end);
+	schedule_delayed_work(&grace_period_end, grace_period);
 }
 
 /*
@@ -116,7 +111,6 @@
 {
 	int		err = 0, preverr = 0;
 	struct svc_rqst *rqstp = vrqstp;
-	unsigned long grace_period_expire;
 
 	/* try_to_freeze() is called from svc_recv() */
 	set_freezable();
@@ -139,7 +133,7 @@
 		nlm_timeout = LOCKD_DFLT_TIMEO;
 	nlmsvc_timeout = nlm_timeout * HZ;
 
-	grace_period_expire = set_grace_period();
+	set_grace_period();
 
 	/*
 	 * The main request loop. We don't terminate until the last
@@ -153,21 +147,12 @@
 			flush_signals(current);
 			if (nlmsvc_ops) {
 				nlmsvc_invalidate_all();
-				grace_period_expire = set_grace_period();
+				set_grace_period();
 			}
 			continue;
 		}
 
-		/*
-		 * Retry any blocked locks that have been notified by
-		 * the VFS. Don't do this during grace period.
-		 * (Theoretically, there shouldn't even be blocked locks
-		 * during grace period).
-		 */
-		if (!nlmsvc_grace_period) {
-			timeout = nlmsvc_retry_blocked();
-		} else if (time_before(grace_period_expire, jiffies))
-			clear_grace_period();
+		timeout = nlmsvc_retry_blocked();
 
 		/*
 		 * Find a socket with data available and call its
@@ -195,6 +180,7 @@
 		svc_process(rqstp);
 	}
 	flush_signals(current);
+	cancel_delayed_work_sync(&grace_period_end);
 	if (nlmsvc_ops)
 		nlmsvc_invalidate_all();
 	nlm_shutdown_hosts();
@@ -203,25 +189,28 @@
 }
 
 /*
- * Make any sockets that are needed but not present.
- * If nlm_udpport or nlm_tcpport were set as module
- * options, make those sockets unconditionally
+ * Ensure there are active UDP and TCP listeners for lockd.
+ *
+ * Even if we have only TCP NFS mounts and/or TCP NFSDs, some
+ * local services (such as rpc.statd) still require UDP, and
+ * some NFS servers do not yet support NLM over TCP.
+ *
+ * Returns zero if all listeners are available; otherwise a
+ * negative errno value is returned.
  */
-static int make_socks(struct svc_serv *serv, int proto)
+static int make_socks(struct svc_serv *serv)
 {
 	static int warned;
 	struct svc_xprt *xprt;
 	int err = 0;
 
-	if (proto == IPPROTO_UDP || nlm_udpport) {
-		xprt = svc_find_xprt(serv, "udp", 0, 0);
-		if (!xprt)
-			err = svc_create_xprt(serv, "udp", nlm_udpport,
-					      SVC_SOCK_DEFAULTS);
-		else
-			svc_xprt_put(xprt);
-	}
-	if (err >= 0 && (proto == IPPROTO_TCP || nlm_tcpport)) {
+	xprt = svc_find_xprt(serv, "udp", 0, 0);
+	if (!xprt)
+		err = svc_create_xprt(serv, "udp", nlm_udpport,
+				      SVC_SOCK_DEFAULTS);
+	else
+		svc_xprt_put(xprt);
+	if (err >= 0) {
 		xprt = svc_find_xprt(serv, "tcp", 0, 0);
 		if (!xprt)
 			err = svc_create_xprt(serv, "tcp", nlm_tcpport,
@@ -241,8 +230,7 @@
 /*
  * Bring up the lockd process if it's not already up.
  */
-int
-lockd_up(int proto) /* Maybe add a 'family' option when IPv6 is supported ?? */
+int lockd_up(void)
 {
 	struct svc_serv *serv;
 	int		error = 0;
@@ -251,11 +239,8 @@
 	/*
 	 * Check whether we're already up and running.
 	 */
-	if (nlmsvc_rqst) {
-		if (proto)
-			error = make_socks(nlmsvc_rqst->rq_server, proto);
+	if (nlmsvc_rqst)
 		goto out;
-	}
 
 	/*
 	 * Sanity check: if there's no pid,
@@ -266,13 +251,14 @@
 			"lockd_up: no pid, %d users??\n", nlmsvc_users);
 
 	error = -ENOMEM;
-	serv = svc_create(&nlmsvc_program, LOCKD_BUFSIZE, NULL);
+	serv = svc_create(&nlmsvc_program, LOCKD_BUFSIZE, AF_INET, NULL);
 	if (!serv) {
 		printk(KERN_WARNING "lockd_up: create service failed\n");
 		goto out;
 	}
 
-	if ((error = make_socks(serv, proto)) < 0)
+	error = make_socks(serv);
+	if (error < 0)
 		goto destroy_and_out;
 
 	/*
diff --git a/fs/lockd/svc4proc.c b/fs/lockd/svc4proc.c
index 4a714f64..014f6ce 100644
--- a/fs/lockd/svc4proc.c
+++ b/fs/lockd/svc4proc.c
@@ -88,12 +88,6 @@
 	dprintk("lockd: TEST4        called\n");
 	resp->cookie = argp->cookie;
 
-	/* Don't accept test requests during grace period */
-	if (nlmsvc_grace_period) {
-		resp->status = nlm_lck_denied_grace_period;
-		return rc;
-	}
-
 	/* Obtain client and file */
 	if ((resp->status = nlm4svc_retrieve_args(rqstp, argp, &host, &file)))
 		return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success;
@@ -122,12 +116,6 @@
 
 	resp->cookie = argp->cookie;
 
-	/* Don't accept new lock requests during grace period */
-	if (nlmsvc_grace_period && !argp->reclaim) {
-		resp->status = nlm_lck_denied_grace_period;
-		return rc;
-	}
-
 	/* Obtain client and file */
 	if ((resp->status = nlm4svc_retrieve_args(rqstp, argp, &host, &file)))
 		return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success;
@@ -146,7 +134,8 @@
 
 	/* Now try to lock the file */
 	resp->status = nlmsvc_lock(rqstp, file, host, &argp->lock,
-					argp->block, &argp->cookie);
+					argp->block, &argp->cookie,
+					argp->reclaim);
 	if (resp->status == nlm_drop_reply)
 		rc = rpc_drop_reply;
 	else
@@ -169,7 +158,7 @@
 	resp->cookie = argp->cookie;
 
 	/* Don't accept requests during grace period */
-	if (nlmsvc_grace_period) {
+	if (locks_in_grace()) {
 		resp->status = nlm_lck_denied_grace_period;
 		return rpc_success;
 	}
@@ -202,7 +191,7 @@
 	resp->cookie = argp->cookie;
 
 	/* Don't accept new lock requests during grace period */
-	if (nlmsvc_grace_period) {
+	if (locks_in_grace()) {
 		resp->status = nlm_lck_denied_grace_period;
 		return rpc_success;
 	}
@@ -231,7 +220,7 @@
 	resp->cookie = argp->cookie;
 
 	dprintk("lockd: GRANTED       called\n");
-	resp->status = nlmclnt_grant(svc_addr_in(rqstp), &argp->lock);
+	resp->status = nlmclnt_grant(svc_addr(rqstp), &argp->lock);
 	dprintk("lockd: GRANTED       status %d\n", ntohl(resp->status));
 	return rpc_success;
 }
@@ -341,7 +330,7 @@
 	resp->cookie = argp->cookie;
 
 	/* Don't accept new lock requests during grace period */
-	if (nlmsvc_grace_period && !argp->reclaim) {
+	if (locks_in_grace() && !argp->reclaim) {
 		resp->status = nlm_lck_denied_grace_period;
 		return rpc_success;
 	}
@@ -374,7 +363,7 @@
 	resp->cookie = argp->cookie;
 
 	/* Don't accept requests during grace period */
-	if (nlmsvc_grace_period) {
+	if (locks_in_grace()) {
 		resp->status = nlm_lck_denied_grace_period;
 		return rpc_success;
 	}
@@ -432,11 +421,9 @@
 {
 	struct sockaddr_in	saddr;
 
-	memcpy(&saddr, svc_addr_in(rqstp), sizeof(saddr));
-
 	dprintk("lockd: SM_NOTIFY     called\n");
-	if (saddr.sin_addr.s_addr != htonl(INADDR_LOOPBACK)
-	 || ntohs(saddr.sin_port) >= 1024) {
+
+	if (!nlm_privileged_requester(rqstp)) {
 		char buf[RPC_MAX_ADDRBUFLEN];
 		printk(KERN_WARNING "lockd: rejected NSM callback from %s\n",
 				svc_print_addr(rqstp, buf, sizeof(buf)));
diff --git a/fs/lockd/svclock.c b/fs/lockd/svclock.c
index cf0d5c2..6063a8e 100644
--- a/fs/lockd/svclock.c
+++ b/fs/lockd/svclock.c
@@ -360,7 +360,7 @@
 __be32
 nlmsvc_lock(struct svc_rqst *rqstp, struct nlm_file *file,
 	    struct nlm_host *host, struct nlm_lock *lock, int wait,
-	    struct nlm_cookie *cookie)
+	    struct nlm_cookie *cookie, int reclaim)
 {
 	struct nlm_block	*block = NULL;
 	int			error;
@@ -406,6 +406,15 @@
 		goto out;
 	}
 
+	if (locks_in_grace() && !reclaim) {
+		ret = nlm_lck_denied_grace_period;
+		goto out;
+	}
+	if (reclaim && !locks_in_grace()) {
+		ret = nlm_lck_denied_grace_period;
+		goto out;
+	}
+
 	if (!wait)
 		lock->fl.fl_flags &= ~FL_SLEEP;
 	error = vfs_lock_file(file->f_file, F_SETLK, &lock->fl, NULL);
@@ -502,6 +511,10 @@
 		goto out;
 	}
 
+	if (locks_in_grace()) {
+		ret = nlm_lck_denied_grace_period;
+		goto out;
+	}
 	error = vfs_test_lock(file->f_file, &lock->fl);
 	if (error == FILE_LOCK_DEFERRED) {
 		ret = nlmsvc_defer_lock_rqst(rqstp, block);
@@ -582,6 +595,9 @@
 				(long long)lock->fl.fl_start,
 				(long long)lock->fl.fl_end);
 
+	if (locks_in_grace())
+		return nlm_lck_denied_grace_period;
+
 	mutex_lock(&file->f_mutex);
 	block = nlmsvc_lookup_block(file, lock);
 	mutex_unlock(&file->f_mutex);
diff --git a/fs/lockd/svcproc.c b/fs/lockd/svcproc.c
index 76262c1..548b0bb 100644
--- a/fs/lockd/svcproc.c
+++ b/fs/lockd/svcproc.c
@@ -117,12 +117,6 @@
 	dprintk("lockd: TEST          called\n");
 	resp->cookie = argp->cookie;
 
-	/* Don't accept test requests during grace period */
-	if (nlmsvc_grace_period) {
-		resp->status = nlm_lck_denied_grace_period;
-		return rc;
-	}
-
 	/* Obtain client and file */
 	if ((resp->status = nlmsvc_retrieve_args(rqstp, argp, &host, &file)))
 		return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success;
@@ -152,12 +146,6 @@
 
 	resp->cookie = argp->cookie;
 
-	/* Don't accept new lock requests during grace period */
-	if (nlmsvc_grace_period && !argp->reclaim) {
-		resp->status = nlm_lck_denied_grace_period;
-		return rc;
-	}
-
 	/* Obtain client and file */
 	if ((resp->status = nlmsvc_retrieve_args(rqstp, argp, &host, &file)))
 		return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success;
@@ -176,7 +164,8 @@
 
 	/* Now try to lock the file */
 	resp->status = cast_status(nlmsvc_lock(rqstp, file, host, &argp->lock,
-					       argp->block, &argp->cookie));
+					       argp->block, &argp->cookie,
+					       argp->reclaim));
 	if (resp->status == nlm_drop_reply)
 		rc = rpc_drop_reply;
 	else
@@ -199,7 +188,7 @@
 	resp->cookie = argp->cookie;
 
 	/* Don't accept requests during grace period */
-	if (nlmsvc_grace_period) {
+	if (locks_in_grace()) {
 		resp->status = nlm_lck_denied_grace_period;
 		return rpc_success;
 	}
@@ -232,7 +221,7 @@
 	resp->cookie = argp->cookie;
 
 	/* Don't accept new lock requests during grace period */
-	if (nlmsvc_grace_period) {
+	if (locks_in_grace()) {
 		resp->status = nlm_lck_denied_grace_period;
 		return rpc_success;
 	}
@@ -261,7 +250,7 @@
 	resp->cookie = argp->cookie;
 
 	dprintk("lockd: GRANTED       called\n");
-	resp->status = nlmclnt_grant(svc_addr_in(rqstp), &argp->lock);
+	resp->status = nlmclnt_grant(svc_addr(rqstp), &argp->lock);
 	dprintk("lockd: GRANTED       status %d\n", ntohl(resp->status));
 	return rpc_success;
 }
@@ -373,7 +362,7 @@
 	resp->cookie = argp->cookie;
 
 	/* Don't accept new lock requests during grace period */
-	if (nlmsvc_grace_period && !argp->reclaim) {
+	if (locks_in_grace() && !argp->reclaim) {
 		resp->status = nlm_lck_denied_grace_period;
 		return rpc_success;
 	}
@@ -406,7 +395,7 @@
 	resp->cookie = argp->cookie;
 
 	/* Don't accept requests during grace period */
-	if (nlmsvc_grace_period) {
+	if (locks_in_grace()) {
 		resp->status = nlm_lck_denied_grace_period;
 		return rpc_success;
 	}
@@ -464,11 +453,9 @@
 {
 	struct sockaddr_in	saddr;
 
-	memcpy(&saddr, svc_addr_in(rqstp), sizeof(saddr));
-
 	dprintk("lockd: SM_NOTIFY     called\n");
-	if (saddr.sin_addr.s_addr != htonl(INADDR_LOOPBACK)
-	 || ntohs(saddr.sin_port) >= 1024) {
+
+	if (!nlm_privileged_requester(rqstp)) {
 		char buf[RPC_MAX_ADDRBUFLEN];
 		printk(KERN_WARNING "lockd: rejected NSM callback from %s\n",
 				svc_print_addr(rqstp, buf, sizeof(buf)));
diff --git a/fs/lockd/svcsubs.c b/fs/lockd/svcsubs.c
index 198b4e5..34c2766 100644
--- a/fs/lockd/svcsubs.c
+++ b/fs/lockd/svcsubs.c
@@ -418,7 +418,7 @@
 static int
 nlmsvc_match_ip(void *datap, struct nlm_host *host)
 {
-	return nlm_cmp_addr(&host->h_saddr, datap);
+	return nlm_cmp_addr(nlm_srcaddr(host), datap);
 }
 
 /**
diff --git a/fs/lockd/xdr.c b/fs/lockd/xdr.c
index 3e459e1..1f22629 100644
--- a/fs/lockd/xdr.c
+++ b/fs/lockd/xdr.c
@@ -351,8 +351,6 @@
 	argp->state = ntohl(*p++);
 	/* Preserve the address in network byte order */
 	argp->addr = *p++;
-	argp->vers = *p++;
-	argp->proto = *p++;
 	return xdr_argsize_check(rqstp, p);
 }
 
diff --git a/fs/lockd/xdr4.c b/fs/lockd/xdr4.c
index 43ff939..50c493a 100644
--- a/fs/lockd/xdr4.c
+++ b/fs/lockd/xdr4.c
@@ -358,8 +358,6 @@
 	argp->state = ntohl(*p++);
 	/* Preserve the address in network byte order */
 	argp->addr  = *p++;
-	argp->vers  = *p++;
-	argp->proto = *p++;
 	return xdr_argsize_check(rqstp, p);
 }
 
diff --git a/fs/nfs/callback.c b/fs/nfs/callback.c
index f447f4b..6a09760 100644
--- a/fs/nfs/callback.c
+++ b/fs/nfs/callback.c
@@ -105,7 +105,8 @@
 	mutex_lock(&nfs_callback_mutex);
 	if (nfs_callback_info.users++ || nfs_callback_info.task != NULL)
 		goto out;
-	serv = svc_create(&nfs4_callback_program, NFS4_CALLBACK_BUFSIZE, NULL);
+	serv = svc_create(&nfs4_callback_program, NFS4_CALLBACK_BUFSIZE,
+				AF_INET, NULL);
 	ret = -ENOMEM;
 	if (!serv)
 		goto out_err;
diff --git a/fs/nfs/nfsroot.c b/fs/nfs/nfsroot.c
index 46763d1c..8478fc2 100644
--- a/fs/nfs/nfsroot.c
+++ b/fs/nfs/nfsroot.c
@@ -127,7 +127,7 @@
 	Opt_err
 };
 
-static match_table_t __initdata tokens = {
+static match_table_t __initconst tokens = {
 	{Opt_port, "port=%u"},
 	{Opt_rsize, "rsize=%u"},
 	{Opt_wsize, "wsize=%u"},
diff --git a/fs/nfs/super.c b/fs/nfs/super.c
index e9b2017..ffb6974 100644
--- a/fs/nfs/super.c
+++ b/fs/nfs/super.c
@@ -98,7 +98,7 @@
 	Opt_err
 };
 
-static match_table_t nfs_mount_option_tokens = {
+static const match_table_t nfs_mount_option_tokens = {
 	{ Opt_userspace, "bg" },
 	{ Opt_userspace, "fg" },
 	{ Opt_userspace, "retry=%s" },
@@ -163,7 +163,7 @@
 	Opt_xprt_err
 };
 
-static match_table_t nfs_xprt_protocol_tokens = {
+static const match_table_t nfs_xprt_protocol_tokens = {
 	{ Opt_xprt_udp, "udp" },
 	{ Opt_xprt_tcp, "tcp" },
 	{ Opt_xprt_rdma, "rdma" },
@@ -180,7 +180,7 @@
 	Opt_sec_err
 };
 
-static match_table_t nfs_secflavor_tokens = {
+static const match_table_t nfs_secflavor_tokens = {
 	{ Opt_sec_none, "none" },
 	{ Opt_sec_none, "null" },
 	{ Opt_sec_sys, "sys" },
diff --git a/fs/nfsd/lockd.c b/fs/nfsd/lockd.c
index 15c6fae..b2786a5 100644
--- a/fs/nfsd/lockd.c
+++ b/fs/nfsd/lockd.c
@@ -70,7 +70,6 @@
 static struct nlmsvc_binding	nfsd_nlm_ops = {
 	.fopen		= nlm_fopen,		/* open file for locking */
 	.fclose		= nlm_fclose,		/* close file */
-	.get_grace_period = get_nfs4_grace_period,
 };
 
 void
diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c
index 4d617ea..9dbd2eb 100644
--- a/fs/nfsd/nfs3proc.c
+++ b/fs/nfsd/nfs3proc.c
@@ -63,7 +63,8 @@
 		SVCFH_fmt(&argp->fh));
 
 	fh_copy(&resp->fh, &argp->fh);
-	nfserr = fh_verify(rqstp, &resp->fh, 0, NFSD_MAY_NOP);
+	nfserr = fh_verify(rqstp, &resp->fh, 0,
+			NFSD_MAY_NOP | NFSD_MAY_BYPASS_GSS_ON_ROOT);
 	if (nfserr)
 		RETURN_STATUS(nfserr);
 
@@ -530,7 +531,7 @@
 	dprintk("nfsd: FSSTAT(3)   %s\n",
 				SVCFH_fmt(&argp->fh));
 
-	nfserr = nfsd_statfs(rqstp, &argp->fh, &resp->stats);
+	nfserr = nfsd_statfs(rqstp, &argp->fh, &resp->stats, 0);
 	fh_put(&argp->fh);
 	RETURN_STATUS(nfserr);
 }
@@ -558,7 +559,8 @@
 	resp->f_maxfilesize = ~(u32) 0;
 	resp->f_properties = NFS3_FSF_DEFAULT;
 
-	nfserr = fh_verify(rqstp, &argp->fh, 0, NFSD_MAY_NOP);
+	nfserr = fh_verify(rqstp, &argp->fh, 0,
+			NFSD_MAY_NOP | NFSD_MAY_BYPASS_GSS_ON_ROOT);
 
 	/* Check special features of the file system. May request
 	 * different read/write sizes for file systems known to have
diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c
index 702fa57..094747a 100644
--- a/fs/nfsd/nfs4callback.c
+++ b/fs/nfsd/nfs4callback.c
@@ -225,7 +225,8 @@
 
 	RESERVE_SPACE(12+sizeof(cb_rec->cbr_stateid) + len);
 	WRITE32(OP_CB_RECALL);
-	WRITEMEM(&cb_rec->cbr_stateid, sizeof(stateid_t));
+	WRITE32(cb_rec->cbr_stateid.si_generation);
+	WRITEMEM(&cb_rec->cbr_stateid.si_opaque, sizeof(stateid_opaque_t));
 	WRITE32(cb_rec->cbr_trunc);
 	WRITE32(len);
 	WRITEMEM(cb_rec->cbr_fhval, len);
@@ -379,6 +380,7 @@
 		.addrsize	= sizeof(addr),
 		.timeout	= &timeparms,
 		.program	= &cb_program,
+		.prognumber	= cb->cb_prog,
 		.version	= nfs_cb_version[1]->number,
 		.authflavor	= RPC_AUTH_UNIX, /* XXX: need AUTH_GSS... */
 		.flags		= (RPC_CLNT_CREATE_NOPING | RPC_CLNT_CREATE_QUIET),
@@ -396,9 +398,6 @@
 	addr.sin_port = htons(cb->cb_port);
 	addr.sin_addr.s_addr = htonl(cb->cb_addr);
 
-	/* Initialize rpc_stat */
-	memset(args.program->stats, 0, sizeof(struct rpc_stat));
-
 	/* Create RPC client */
 	client = rpc_create(&args);
 	if (IS_ERR(client)) {
diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
index e5b51ff..669461e 100644
--- a/fs/nfsd/nfs4proc.c
+++ b/fs/nfsd/nfs4proc.c
@@ -201,10 +201,10 @@
 	/* Openowner is now set, so sequence id will get bumped.  Now we need
 	 * these checks before we do any creates: */
 	status = nfserr_grace;
-	if (nfs4_in_grace() && open->op_claim_type != NFS4_OPEN_CLAIM_PREVIOUS)
+	if (locks_in_grace() && open->op_claim_type != NFS4_OPEN_CLAIM_PREVIOUS)
 		goto out;
 	status = nfserr_no_grace;
-	if (!nfs4_in_grace() && open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS)
+	if (!locks_in_grace() && open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS)
 		goto out;
 
 	switch (open->op_claim_type) {
@@ -575,7 +575,7 @@
 {
 	__be32 status;
 
-	if (nfs4_in_grace())
+	if (locks_in_grace())
 		return nfserr_grace;
 	status = nfsd_unlink(rqstp, &cstate->current_fh, 0,
 			     remove->rm_name, remove->rm_namelen);
@@ -596,7 +596,7 @@
 
 	if (!cstate->save_fh.fh_dentry)
 		return status;
-	if (nfs4_in_grace() && !(cstate->save_fh.fh_export->ex_flags
+	if (locks_in_grace() && !(cstate->save_fh.fh_export->ex_flags
 					& NFSEXP_NOSUBTREECHECK))
 		return nfserr_grace;
 	status = nfsd_rename(rqstp, &cstate->save_fh, rename->rn_sname,
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 1578d7a..0cc7ff5 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -61,7 +61,6 @@
 static time_t lease_time = 90;     /* default lease time */
 static time_t user_lease_time = 90;
 static time_t boot_time;
-static int in_grace = 1;
 static u32 current_ownerid = 1;
 static u32 current_fileid = 1;
 static u32 current_delegid = 1;
@@ -1640,7 +1639,7 @@
 		case NFS4_OPEN_CLAIM_NULL:
 			/* Let's not give out any delegations till everyone's
 			 * had the chance to reclaim theirs.... */
-			if (nfs4_in_grace())
+			if (locks_in_grace())
 				goto out;
 			if (!atomic_read(&cb->cb_set) || !sop->so_confirmed)
 				goto out;
@@ -1816,12 +1815,15 @@
 	return status;
 }
 
+struct lock_manager nfsd4_manager = {
+};
+
 static void
-end_grace(void)
+nfsd4_end_grace(void)
 {
 	dprintk("NFSD: end of grace period\n");
 	nfsd4_recdir_purge_old();
-	in_grace = 0;
+	locks_end_grace(&nfsd4_manager);
 }
 
 static time_t
@@ -1838,8 +1840,8 @@
 	nfs4_lock_state();
 
 	dprintk("NFSD: laundromat service - starting\n");
-	if (in_grace)
-		end_grace();
+	if (locks_in_grace())
+		nfsd4_end_grace();
 	list_for_each_safe(pos, next, &client_lru) {
 		clp = list_entry(pos, struct nfs4_client, cl_lru);
 		if (time_after((unsigned long)clp->cl_time, (unsigned long)cutoff)) {
@@ -1974,7 +1976,7 @@
 		return nfserr_bad_stateid;
 	else if (ONE_STATEID(stateid) && (flags & RD_STATE))
 		return nfs_ok;
-	else if (nfs4_in_grace()) {
+	else if (locks_in_grace()) {
 		/* Answer in remaining cases depends on existance of
 		 * conflicting state; so we must wait out the grace period. */
 		return nfserr_grace;
@@ -1993,7 +1995,7 @@
 static inline int
 io_during_grace_disallowed(struct inode *inode, int flags)
 {
-	return nfs4_in_grace() && (flags & (RD_STATE | WR_STATE))
+	return locks_in_grace() && (flags & (RD_STATE | WR_STATE))
 		&& mandatory_lock(inode);
 }
 
@@ -2693,10 +2695,10 @@
 	filp = lock_stp->st_vfs_file;
 
 	status = nfserr_grace;
-	if (nfs4_in_grace() && !lock->lk_reclaim)
+	if (locks_in_grace() && !lock->lk_reclaim)
 		goto out;
 	status = nfserr_no_grace;
-	if (!nfs4_in_grace() && lock->lk_reclaim)
+	if (!locks_in_grace() && lock->lk_reclaim)
 		goto out;
 
 	locks_init_lock(&file_lock);
@@ -2779,7 +2781,7 @@
 	int error;
 	__be32 status;
 
-	if (nfs4_in_grace())
+	if (locks_in_grace())
 		return nfserr_grace;
 
 	if (check_lock_length(lockt->lt_offset, lockt->lt_length))
@@ -3192,9 +3194,9 @@
 	unsigned long grace_time;
 
 	boot_time = get_seconds();
-	grace_time = get_nfs_grace_period();
+	grace_time = get_nfs4_grace_period();
 	lease_time = user_lease_time;
-	in_grace = 1;
+	locks_start_grace(&nfsd4_manager);
 	printk(KERN_INFO "NFSD: starting %ld-second grace period\n",
 	       grace_time/HZ);
 	laundry_wq = create_singlethread_workqueue("nfsd4");
@@ -3213,12 +3215,6 @@
 	return;
 }
 
-int
-nfs4_in_grace(void)
-{
-	return in_grace;
-}
-
 time_t
 nfs4_lease_time(void)
 {
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index 14ba4d9..afcdf4b 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -413,6 +413,18 @@
 }
 
 static __be32
+nfsd4_decode_stateid(struct nfsd4_compoundargs *argp, stateid_t *sid)
+{
+	DECODE_HEAD;
+
+	READ_BUF(sizeof(stateid_t));
+	READ32(sid->si_generation);
+	COPYMEM(&sid->si_opaque, sizeof(stateid_opaque_t));
+
+	DECODE_TAIL;
+}
+
+static __be32
 nfsd4_decode_access(struct nfsd4_compoundargs *argp, struct nfsd4_access *access)
 {
 	DECODE_HEAD;
@@ -429,10 +441,9 @@
 	DECODE_HEAD;
 
 	close->cl_stateowner = NULL;
-	READ_BUF(4 + sizeof(stateid_t));
+	READ_BUF(4);
 	READ32(close->cl_seqid);
-	READ32(close->cl_stateid.si_generation);
-	COPYMEM(&close->cl_stateid.si_opaque, sizeof(stateid_opaque_t));
+	return nfsd4_decode_stateid(argp, &close->cl_stateid);
 
 	DECODE_TAIL;
 }
@@ -493,13 +504,7 @@
 static inline __be32
 nfsd4_decode_delegreturn(struct nfsd4_compoundargs *argp, struct nfsd4_delegreturn *dr)
 {
-	DECODE_HEAD;
-
-	READ_BUF(sizeof(stateid_t));
-	READ32(dr->dr_stateid.si_generation);
-	COPYMEM(&dr->dr_stateid.si_opaque, sizeof(stateid_opaque_t));
-
-	DECODE_TAIL;
+	return nfsd4_decode_stateid(argp, &dr->dr_stateid);
 }
 
 static inline __be32
@@ -542,20 +547,22 @@
 	READ32(lock->lk_is_new);
 
 	if (lock->lk_is_new) {
-		READ_BUF(36);
+		READ_BUF(4);
 		READ32(lock->lk_new_open_seqid);
-		READ32(lock->lk_new_open_stateid.si_generation);
-
-		COPYMEM(&lock->lk_new_open_stateid.si_opaque, sizeof(stateid_opaque_t));
+		status = nfsd4_decode_stateid(argp, &lock->lk_new_open_stateid);
+		if (status)
+			return status;
+		READ_BUF(8 + sizeof(clientid_t));
 		READ32(lock->lk_new_lock_seqid);
 		COPYMEM(&lock->lk_new_clientid, sizeof(clientid_t));
 		READ32(lock->lk_new_owner.len);
 		READ_BUF(lock->lk_new_owner.len);
 		READMEM(lock->lk_new_owner.data, lock->lk_new_owner.len);
 	} else {
-		READ_BUF(20);
-		READ32(lock->lk_old_lock_stateid.si_generation);
-		COPYMEM(&lock->lk_old_lock_stateid.si_opaque, sizeof(stateid_opaque_t));
+		status = nfsd4_decode_stateid(argp, &lock->lk_old_lock_stateid);
+		if (status)
+			return status;
+		READ_BUF(4);
 		READ32(lock->lk_old_lock_seqid);
 	}
 
@@ -587,13 +594,15 @@
 	DECODE_HEAD;
 
 	locku->lu_stateowner = NULL;
-	READ_BUF(24 + sizeof(stateid_t));
+	READ_BUF(8);
 	READ32(locku->lu_type);
 	if ((locku->lu_type < NFS4_READ_LT) || (locku->lu_type > NFS4_WRITEW_LT))
 		goto xdr_error;
 	READ32(locku->lu_seqid);
-	READ32(locku->lu_stateid.si_generation);
-	COPYMEM(&locku->lu_stateid.si_opaque, sizeof(stateid_opaque_t));
+	status = nfsd4_decode_stateid(argp, &locku->lu_stateid);
+	if (status)
+		return status;
+	READ_BUF(16);
 	READ64(locku->lu_offset);
 	READ64(locku->lu_length);
 
@@ -678,8 +687,10 @@
 		READ32(open->op_delegate_type);
 		break;
 	case NFS4_OPEN_CLAIM_DELEGATE_CUR:
-		READ_BUF(sizeof(stateid_t) + 4);
-		COPYMEM(&open->op_delegate_stateid, sizeof(stateid_t));
+		status = nfsd4_decode_stateid(argp, &open->op_delegate_stateid);
+		if (status)
+			return status;
+		READ_BUF(4);
 		READ32(open->op_fname.len);
 		READ_BUF(open->op_fname.len);
 		SAVEMEM(open->op_fname.data, open->op_fname.len);
@@ -699,9 +710,10 @@
 	DECODE_HEAD;
 		    
 	open_conf->oc_stateowner = NULL;
-	READ_BUF(4 + sizeof(stateid_t));
-	READ32(open_conf->oc_req_stateid.si_generation);
-	COPYMEM(&open_conf->oc_req_stateid.si_opaque, sizeof(stateid_opaque_t));
+	status = nfsd4_decode_stateid(argp, &open_conf->oc_req_stateid);
+	if (status)
+		return status;
+	READ_BUF(4);
 	READ32(open_conf->oc_seqid);
 						        
 	DECODE_TAIL;
@@ -713,9 +725,10 @@
 	DECODE_HEAD;
 		    
 	open_down->od_stateowner = NULL;
-	READ_BUF(12 + sizeof(stateid_t));
-	READ32(open_down->od_stateid.si_generation);
-	COPYMEM(&open_down->od_stateid.si_opaque, sizeof(stateid_opaque_t));
+	status = nfsd4_decode_stateid(argp, &open_down->od_stateid);
+	if (status)
+		return status;
+	READ_BUF(12);
 	READ32(open_down->od_seqid);
 	READ32(open_down->od_share_access);
 	READ32(open_down->od_share_deny);
@@ -743,9 +756,10 @@
 {
 	DECODE_HEAD;
 
-	READ_BUF(sizeof(stateid_t) + 12);
-	READ32(read->rd_stateid.si_generation);
-	COPYMEM(&read->rd_stateid.si_opaque, sizeof(stateid_opaque_t));
+	status = nfsd4_decode_stateid(argp, &read->rd_stateid);
+	if (status)
+		return status;
+	READ_BUF(12);
 	READ64(read->rd_offset);
 	READ32(read->rd_length);
 
@@ -834,15 +848,13 @@
 static __be32
 nfsd4_decode_setattr(struct nfsd4_compoundargs *argp, struct nfsd4_setattr *setattr)
 {
-	DECODE_HEAD;
+	__be32 status;
 
-	READ_BUF(sizeof(stateid_t));
-	READ32(setattr->sa_stateid.si_generation);
-	COPYMEM(&setattr->sa_stateid.si_opaque, sizeof(stateid_opaque_t));
-	if ((status = nfsd4_decode_fattr(argp, setattr->sa_bmval, &setattr->sa_iattr, &setattr->sa_acl)))
-		goto out;
-
-	DECODE_TAIL;
+	status = nfsd4_decode_stateid(argp, &setattr->sa_stateid);
+	if (status)
+		return status;
+	return nfsd4_decode_fattr(argp, setattr->sa_bmval,
+				  &setattr->sa_iattr, &setattr->sa_acl);
 }
 
 static __be32
@@ -927,9 +939,10 @@
 	int len;
 	DECODE_HEAD;
 
-	READ_BUF(sizeof(stateid_opaque_t) + 20);
-	READ32(write->wr_stateid.si_generation);
-	COPYMEM(&write->wr_stateid.si_opaque, sizeof(stateid_opaque_t));
+	status = nfsd4_decode_stateid(argp, &write->wr_stateid);
+	if (status)
+		return status;
+	READ_BUF(16);
 	READ64(write->wr_offset);
 	READ32(write->wr_stable_how);
 	if (write->wr_stable_how > 2)
@@ -1183,7 +1196,6 @@
  * Header routine to setup seqid operation replay cache
  */
 #define ENCODE_SEQID_OP_HEAD					\
-	__be32 *p;						\
 	__be32 *save;						\
 								\
 	save = resp->p;
@@ -1950,6 +1962,17 @@
 	return -EINVAL;
 }
 
+static void
+nfsd4_encode_stateid(struct nfsd4_compoundres *resp, stateid_t *sid)
+{
+	ENCODE_HEAD;
+
+	RESERVE_SPACE(sizeof(stateid_t));
+	WRITE32(sid->si_generation);
+	WRITEMEM(&sid->si_opaque, sizeof(stateid_opaque_t));
+	ADJUST_ARGS();
+}
+
 static __be32
 nfsd4_encode_access(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_access *access)
 {
@@ -1969,12 +1992,9 @@
 {
 	ENCODE_SEQID_OP_HEAD;
 
-	if (!nfserr) {
-		RESERVE_SPACE(sizeof(stateid_t));
-		WRITE32(close->cl_stateid.si_generation);
-		WRITEMEM(&close->cl_stateid.si_opaque, sizeof(stateid_opaque_t));
-		ADJUST_ARGS();
-	}
+	if (!nfserr)
+		nfsd4_encode_stateid(resp, &close->cl_stateid);
+
 	ENCODE_SEQID_OP_TAIL(close->cl_stateowner);
 	return nfserr;
 }
@@ -2074,12 +2094,9 @@
 {
 	ENCODE_SEQID_OP_HEAD;
 
-	if (!nfserr) {
-		RESERVE_SPACE(4 + sizeof(stateid_t));
-		WRITE32(lock->lk_resp_stateid.si_generation);
-		WRITEMEM(&lock->lk_resp_stateid.si_opaque, sizeof(stateid_opaque_t));
-		ADJUST_ARGS();
-	} else if (nfserr == nfserr_denied)
+	if (!nfserr)
+		nfsd4_encode_stateid(resp, &lock->lk_resp_stateid);
+	else if (nfserr == nfserr_denied)
 		nfsd4_encode_lock_denied(resp, &lock->lk_denied);
 
 	ENCODE_SEQID_OP_TAIL(lock->lk_replay_owner);
@@ -2099,13 +2116,9 @@
 {
 	ENCODE_SEQID_OP_HEAD;
 
-	if (!nfserr) {
-		RESERVE_SPACE(sizeof(stateid_t));
-		WRITE32(locku->lu_stateid.si_generation);
-		WRITEMEM(&locku->lu_stateid.si_opaque, sizeof(stateid_opaque_t));
-		ADJUST_ARGS();
-	}
-				        
+	if (!nfserr)
+		nfsd4_encode_stateid(resp, &locku->lu_stateid);
+
 	ENCODE_SEQID_OP_TAIL(locku->lu_stateowner);
 	return nfserr;
 }
@@ -2128,14 +2141,14 @@
 static __be32
 nfsd4_encode_open(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_open *open)
 {
+	ENCODE_HEAD;
 	ENCODE_SEQID_OP_HEAD;
 
 	if (nfserr)
 		goto out;
 
-	RESERVE_SPACE(36 + sizeof(stateid_t));
-	WRITE32(open->op_stateid.si_generation);
-	WRITEMEM(&open->op_stateid.si_opaque, sizeof(stateid_opaque_t));
+	nfsd4_encode_stateid(resp, &open->op_stateid);
+	RESERVE_SPACE(40);
 	WRITECINFO(open->op_cinfo);
 	WRITE32(open->op_rflags);
 	WRITE32(2);
@@ -2148,8 +2161,8 @@
 	case NFS4_OPEN_DELEGATE_NONE:
 		break;
 	case NFS4_OPEN_DELEGATE_READ:
-		RESERVE_SPACE(20 + sizeof(stateid_t));
-		WRITEMEM(&open->op_delegate_stateid, sizeof(stateid_t));
+		nfsd4_encode_stateid(resp, &open->op_delegate_stateid);
+		RESERVE_SPACE(20);
 		WRITE32(open->op_recall);
 
 		/*
@@ -2162,8 +2175,8 @@
 		ADJUST_ARGS();
 		break;
 	case NFS4_OPEN_DELEGATE_WRITE:
-		RESERVE_SPACE(32 + sizeof(stateid_t));
-		WRITEMEM(&open->op_delegate_stateid, sizeof(stateid_t));
+		nfsd4_encode_stateid(resp, &open->op_delegate_stateid);
+		RESERVE_SPACE(32);
 		WRITE32(0);
 
 		/*
@@ -2195,13 +2208,9 @@
 nfsd4_encode_open_confirm(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_open_confirm *oc)
 {
 	ENCODE_SEQID_OP_HEAD;
-				        
-	if (!nfserr) {
-		RESERVE_SPACE(sizeof(stateid_t));
-		WRITE32(oc->oc_resp_stateid.si_generation);
-		WRITEMEM(&oc->oc_resp_stateid.si_opaque, sizeof(stateid_opaque_t));
-		ADJUST_ARGS();
-	}
+
+	if (!nfserr)
+		nfsd4_encode_stateid(resp, &oc->oc_resp_stateid);
 
 	ENCODE_SEQID_OP_TAIL(oc->oc_stateowner);
 	return nfserr;
@@ -2211,13 +2220,9 @@
 nfsd4_encode_open_downgrade(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_open_downgrade *od)
 {
 	ENCODE_SEQID_OP_HEAD;
-				        
-	if (!nfserr) {
-		RESERVE_SPACE(sizeof(stateid_t));
-		WRITE32(od->od_stateid.si_generation);
-		WRITEMEM(&od->od_stateid.si_opaque, sizeof(stateid_opaque_t));
-		ADJUST_ARGS();
-	}
+
+	if (!nfserr)
+		nfsd4_encode_stateid(resp, &od->od_stateid);
 
 	ENCODE_SEQID_OP_TAIL(od->od_stateowner);
 	return nfserr;
diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c
index c53e65f..97543df 100644
--- a/fs/nfsd/nfsctl.c
+++ b/fs/nfsd/nfsctl.c
@@ -614,10 +614,9 @@
 			return -EINVAL;
 		err = nfsd_create_serv();
 		if (!err) {
-			int proto = 0;
-			err = svc_addsock(nfsd_serv, fd, buf, &proto);
+			err = svc_addsock(nfsd_serv, fd, buf);
 			if (err >= 0) {
-				err = lockd_up(proto);
+				err = lockd_up();
 				if (err < 0)
 					svc_sock_names(buf+strlen(buf)+1, nfsd_serv, buf);
 			}
diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c
index ea37c96..cd25d91 100644
--- a/fs/nfsd/nfsfh.c
+++ b/fs/nfsd/nfsfh.c
@@ -302,17 +302,27 @@
 	if (error)
 		goto out;
 
-	if (!(access & NFSD_MAY_LOCK)) {
-		/*
-		 * pseudoflavor restrictions are not enforced on NLM,
-		 * which clients virtually always use auth_sys for,
-		 * even while using RPCSEC_GSS for NFS.
-		 */
-		error = check_nfsd_access(exp, rqstp);
-		if (error)
-			goto out;
-	}
+	/*
+	 * pseudoflavor restrictions are not enforced on NLM,
+	 * which clients virtually always use auth_sys for,
+	 * even while using RPCSEC_GSS for NFS.
+	 */
+	if (access & NFSD_MAY_LOCK)
+		goto skip_pseudoflavor_check;
+	/*
+	 * Clients may expect to be able to use auth_sys during mount,
+	 * even if they use gss for everything else; see section 2.3.2
+	 * of rfc 2623.
+	 */
+	if (access & NFSD_MAY_BYPASS_GSS_ON_ROOT
+			&& exp->ex_path.dentry == dentry)
+		goto skip_pseudoflavor_check;
 
+	error = check_nfsd_access(exp, rqstp);
+	if (error)
+		goto out;
+
+skip_pseudoflavor_check:
 	/* Finally, check access permissions. */
 	error = nfsd_permission(rqstp, exp, dentry, access);
 
diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c
index 0766f95..5cffeca 100644
--- a/fs/nfsd/nfsproc.c
+++ b/fs/nfsd/nfsproc.c
@@ -65,7 +65,8 @@
 	dprintk("nfsd: GETATTR  %s\n", SVCFH_fmt(&argp->fh));
 
 	fh_copy(&resp->fh, &argp->fh);
-	nfserr = fh_verify(rqstp, &resp->fh, 0, NFSD_MAY_NOP);
+	nfserr = fh_verify(rqstp, &resp->fh, 0,
+			NFSD_MAY_NOP | NFSD_MAY_BYPASS_GSS_ON_ROOT);
 	return nfsd_return_attrs(nfserr, resp);
 }
 
@@ -521,7 +522,8 @@
 
 	dprintk("nfsd: STATFS   %s\n", SVCFH_fmt(&argp->fh));
 
-	nfserr = nfsd_statfs(rqstp, &argp->fh, &resp->stats);
+	nfserr = nfsd_statfs(rqstp, &argp->fh, &resp->stats,
+			NFSD_MAY_BYPASS_GSS_ON_ROOT);
 	fh_put(&argp->fh);
 	return nfserr;
 }
diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c
index 80292ff..59eeb46 100644
--- a/fs/nfsd/nfssvc.c
+++ b/fs/nfsd/nfssvc.c
@@ -229,6 +229,7 @@
 
 	atomic_set(&nfsd_busy, 0);
 	nfsd_serv = svc_create_pooled(&nfsd_program, nfsd_max_blksize,
+				      AF_INET,
 				      nfsd_last_thread, nfsd, THIS_MODULE);
 	if (nfsd_serv == NULL)
 		err = -ENOMEM;
@@ -243,25 +244,20 @@
 	if (!list_empty(&nfsd_serv->sv_permsocks))
 		return 0;
 
-	error = lockd_up(IPPROTO_UDP);
-	if (error >= 0) {
-		error = svc_create_xprt(nfsd_serv, "udp", port,
+	error = svc_create_xprt(nfsd_serv, "udp", port,
 					SVC_SOCK_DEFAULTS);
-		if (error < 0)
-			lockd_down();
-	}
 	if (error < 0)
 		return error;
 
-	error = lockd_up(IPPROTO_TCP);
-	if (error >= 0) {
-		error = svc_create_xprt(nfsd_serv, "tcp", port,
+	error = svc_create_xprt(nfsd_serv, "tcp", port,
 					SVC_SOCK_DEFAULTS);
-		if (error < 0)
-			lockd_down();
-	}
 	if (error < 0)
 		return error;
+
+	error = lockd_up();
+	if (error < 0)
+		return error;
+
 	return 0;
 }
 
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
index 18060be..aa1d0d6 100644
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -83,7 +83,6 @@
 	spinlock_t		pb_lock;
 } ____cacheline_aligned_in_smp;
 
-static struct raparms *		raparml;
 #define RAPARM_HASH_BITS	4
 #define RAPARM_HASH_SIZE	(1<<RAPARM_HASH_BITS)
 #define RAPARM_HASH_MASK	(RAPARM_HASH_SIZE-1)
@@ -1866,9 +1865,9 @@
  * N.B. After this call fhp needs an fh_put
  */
 __be32
-nfsd_statfs(struct svc_rqst *rqstp, struct svc_fh *fhp, struct kstatfs *stat)
+nfsd_statfs(struct svc_rqst *rqstp, struct svc_fh *fhp, struct kstatfs *stat, int access)
 {
-	__be32 err = fh_verify(rqstp, fhp, 0, NFSD_MAY_NOP);
+	__be32 err = fh_verify(rqstp, fhp, 0, NFSD_MAY_NOP | access);
 	if (!err && vfs_statfs(fhp->fh_dentry,stat))
 		err = nfserr_io;
 	return err;
@@ -1966,11 +1965,20 @@
 void
 nfsd_racache_shutdown(void)
 {
-	if (!raparml)
-		return;
+	struct raparms *raparm, *last_raparm;
+	unsigned int i;
+
 	dprintk("nfsd: freeing readahead buffers.\n");
-	kfree(raparml);
-	raparml = NULL;
+
+	for (i = 0; i < RAPARM_HASH_SIZE; i++) {
+		raparm = raparm_hash[i].pb_head;
+		while(raparm) {
+			last_raparm = raparm;
+			raparm = raparm->p_next;
+			kfree(last_raparm);
+		}
+		raparm_hash[i].pb_head = NULL;
+	}
 }
 /*
  * Initialize readahead param cache
@@ -1981,35 +1989,38 @@
 	int	i;
 	int	j = 0;
 	int	nperbucket;
+	struct raparms **raparm = NULL;
 
 
-	if (raparml)
+	if (raparm_hash[0].pb_head)
 		return 0;
-	if (cache_size < 2*RAPARM_HASH_SIZE)
-		cache_size = 2*RAPARM_HASH_SIZE;
-	raparml = kcalloc(cache_size, sizeof(struct raparms), GFP_KERNEL);
-
-	if (!raparml) {
-		printk(KERN_WARNING
-			"nfsd: Could not allocate memory read-ahead cache.\n");
-		return -ENOMEM;
-	}
+	nperbucket = DIV_ROUND_UP(cache_size, RAPARM_HASH_SIZE);
+	if (nperbucket < 2)
+		nperbucket = 2;
+	cache_size = nperbucket * RAPARM_HASH_SIZE;
 
 	dprintk("nfsd: allocating %d readahead buffers.\n", cache_size);
-	for (i = 0 ; i < RAPARM_HASH_SIZE ; i++) {
-		raparm_hash[i].pb_head = NULL;
+
+	for (i = 0; i < RAPARM_HASH_SIZE; i++) {
 		spin_lock_init(&raparm_hash[i].pb_lock);
-	}
-	nperbucket = DIV_ROUND_UP(cache_size, RAPARM_HASH_SIZE);
-	for (i = 0; i < cache_size - 1; i++) {
-		if (i % nperbucket == 0)
-			raparm_hash[j++].pb_head = raparml + i;
-		if (i % nperbucket < nperbucket-1)
-			raparml[i].p_next = raparml + i + 1;
+
+		raparm = &raparm_hash[i].pb_head;
+		for (j = 0; j < nperbucket; j++) {
+			*raparm = kzalloc(sizeof(struct raparms), GFP_KERNEL);
+			if (!*raparm)
+				goto out_nomem;
+			raparm = &(*raparm)->p_next;
+		}
+		*raparm = NULL;
 	}
 
 	nfsdstats.ra_size = cache_size;
 	return 0;
+
+out_nomem:
+	dprintk("nfsd: kmalloc failed, freeing readahead buffers\n");
+	nfsd_racache_shutdown();
+	return -ENOMEM;
 }
 
 #if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL)
diff --git a/fs/ocfs2/Makefile b/fs/ocfs2/Makefile
index f6956de..589dcdf 100644
--- a/fs/ocfs2/Makefile
+++ b/fs/ocfs2/Makefile
@@ -34,7 +34,8 @@
 	symlink.o 		\
 	sysfile.o 		\
 	uptodate.o		\
-	ver.o
+	ver.o			\
+	xattr.o
 
 ocfs2_stackglue-objs := stackglue.o
 ocfs2_stack_o2cb-objs := stack_o2cb.o
diff --git a/fs/ocfs2/alloc.c b/fs/ocfs2/alloc.c
index 10bfb46..0cc2deb 100644
--- a/fs/ocfs2/alloc.c
+++ b/fs/ocfs2/alloc.c
@@ -49,6 +49,340 @@
 
 #include "buffer_head_io.h"
 
+
+/*
+ * Operations for a specific extent tree type.
+ *
+ * To implement an on-disk btree (extent tree) type in ocfs2, add
+ * an ocfs2_extent_tree_operations structure and the matching
+ * ocfs2_init_<thingy>_extent_tree() function.  That's pretty much it
+ * for the allocation portion of the extent tree.
+ */
+struct ocfs2_extent_tree_operations {
+	/*
+	 * last_eb_blk is the block number of the right most leaf extent
+	 * block.  Most on-disk structures containing an extent tree store
+	 * this value for fast access.  The ->eo_set_last_eb_blk() and
+	 * ->eo_get_last_eb_blk() operations access this value.  They are
+	 *  both required.
+	 */
+	void (*eo_set_last_eb_blk)(struct ocfs2_extent_tree *et,
+				   u64 blkno);
+	u64 (*eo_get_last_eb_blk)(struct ocfs2_extent_tree *et);
+
+	/*
+	 * The on-disk structure usually keeps track of how many total
+	 * clusters are stored in this extent tree.  This function updates
+	 * that value.  new_clusters is the delta, and must be
+	 * added to the total.  Required.
+	 */
+	void (*eo_update_clusters)(struct inode *inode,
+				   struct ocfs2_extent_tree *et,
+				   u32 new_clusters);
+
+	/*
+	 * If ->eo_insert_check() exists, it is called before rec is
+	 * inserted into the extent tree.  It is optional.
+	 */
+	int (*eo_insert_check)(struct inode *inode,
+			       struct ocfs2_extent_tree *et,
+			       struct ocfs2_extent_rec *rec);
+	int (*eo_sanity_check)(struct inode *inode, struct ocfs2_extent_tree *et);
+
+	/*
+	 * --------------------------------------------------------------
+	 * The remaining are internal to ocfs2_extent_tree and don't have
+	 * accessor functions
+	 */
+
+	/*
+	 * ->eo_fill_root_el() takes et->et_object and sets et->et_root_el.
+	 * It is required.
+	 */
+	void (*eo_fill_root_el)(struct ocfs2_extent_tree *et);
+
+	/*
+	 * ->eo_fill_max_leaf_clusters sets et->et_max_leaf_clusters if
+	 * it exists.  If it does not, et->et_max_leaf_clusters is set
+	 * to 0 (unlimited).  Optional.
+	 */
+	void (*eo_fill_max_leaf_clusters)(struct inode *inode,
+					  struct ocfs2_extent_tree *et);
+};
+
+
+/*
+ * Pre-declare ocfs2_dinode_et_ops so we can use it as a sanity check
+ * in the methods.
+ */
+static u64 ocfs2_dinode_get_last_eb_blk(struct ocfs2_extent_tree *et);
+static void ocfs2_dinode_set_last_eb_blk(struct ocfs2_extent_tree *et,
+					 u64 blkno);
+static void ocfs2_dinode_update_clusters(struct inode *inode,
+					 struct ocfs2_extent_tree *et,
+					 u32 clusters);
+static int ocfs2_dinode_insert_check(struct inode *inode,
+				     struct ocfs2_extent_tree *et,
+				     struct ocfs2_extent_rec *rec);
+static int ocfs2_dinode_sanity_check(struct inode *inode,
+				     struct ocfs2_extent_tree *et);
+static void ocfs2_dinode_fill_root_el(struct ocfs2_extent_tree *et);
+static struct ocfs2_extent_tree_operations ocfs2_dinode_et_ops = {
+	.eo_set_last_eb_blk	= ocfs2_dinode_set_last_eb_blk,
+	.eo_get_last_eb_blk	= ocfs2_dinode_get_last_eb_blk,
+	.eo_update_clusters	= ocfs2_dinode_update_clusters,
+	.eo_insert_check	= ocfs2_dinode_insert_check,
+	.eo_sanity_check	= ocfs2_dinode_sanity_check,
+	.eo_fill_root_el	= ocfs2_dinode_fill_root_el,
+};
+
+static void ocfs2_dinode_set_last_eb_blk(struct ocfs2_extent_tree *et,
+					 u64 blkno)
+{
+	struct ocfs2_dinode *di = et->et_object;
+
+	BUG_ON(et->et_ops != &ocfs2_dinode_et_ops);
+	di->i_last_eb_blk = cpu_to_le64(blkno);
+}
+
+static u64 ocfs2_dinode_get_last_eb_blk(struct ocfs2_extent_tree *et)
+{
+	struct ocfs2_dinode *di = et->et_object;
+
+	BUG_ON(et->et_ops != &ocfs2_dinode_et_ops);
+	return le64_to_cpu(di->i_last_eb_blk);
+}
+
+static void ocfs2_dinode_update_clusters(struct inode *inode,
+					 struct ocfs2_extent_tree *et,
+					 u32 clusters)
+{
+	struct ocfs2_dinode *di = et->et_object;
+
+	le32_add_cpu(&di->i_clusters, clusters);
+	spin_lock(&OCFS2_I(inode)->ip_lock);
+	OCFS2_I(inode)->ip_clusters = le32_to_cpu(di->i_clusters);
+	spin_unlock(&OCFS2_I(inode)->ip_lock);
+}
+
+static int ocfs2_dinode_insert_check(struct inode *inode,
+				     struct ocfs2_extent_tree *et,
+				     struct ocfs2_extent_rec *rec)
+{
+	struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+
+	BUG_ON(OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL);
+	mlog_bug_on_msg(!ocfs2_sparse_alloc(osb) &&
+			(OCFS2_I(inode)->ip_clusters != rec->e_cpos),
+			"Device %s, asking for sparse allocation: inode %llu, "
+			"cpos %u, clusters %u\n",
+			osb->dev_str,
+			(unsigned long long)OCFS2_I(inode)->ip_blkno,
+			rec->e_cpos,
+			OCFS2_I(inode)->ip_clusters);
+
+	return 0;
+}
+
+static int ocfs2_dinode_sanity_check(struct inode *inode,
+				     struct ocfs2_extent_tree *et)
+{
+	int ret = 0;
+	struct ocfs2_dinode *di;
+
+	BUG_ON(et->et_ops != &ocfs2_dinode_et_ops);
+
+	di = et->et_object;
+	if (!OCFS2_IS_VALID_DINODE(di)) {
+		ret = -EIO;
+		ocfs2_error(inode->i_sb,
+			"Inode %llu has invalid path root",
+			(unsigned long long)OCFS2_I(inode)->ip_blkno);
+	}
+
+	return ret;
+}
+
+static void ocfs2_dinode_fill_root_el(struct ocfs2_extent_tree *et)
+{
+	struct ocfs2_dinode *di = et->et_object;
+
+	et->et_root_el = &di->id2.i_list;
+}
+
+
+static void ocfs2_xattr_value_fill_root_el(struct ocfs2_extent_tree *et)
+{
+	struct ocfs2_xattr_value_root *xv = et->et_object;
+
+	et->et_root_el = &xv->xr_list;
+}
+
+static void ocfs2_xattr_value_set_last_eb_blk(struct ocfs2_extent_tree *et,
+					      u64 blkno)
+{
+	struct ocfs2_xattr_value_root *xv =
+		(struct ocfs2_xattr_value_root *)et->et_object;
+
+	xv->xr_last_eb_blk = cpu_to_le64(blkno);
+}
+
+static u64 ocfs2_xattr_value_get_last_eb_blk(struct ocfs2_extent_tree *et)
+{
+	struct ocfs2_xattr_value_root *xv =
+		(struct ocfs2_xattr_value_root *) et->et_object;
+
+	return le64_to_cpu(xv->xr_last_eb_blk);
+}
+
+static void ocfs2_xattr_value_update_clusters(struct inode *inode,
+					      struct ocfs2_extent_tree *et,
+					      u32 clusters)
+{
+	struct ocfs2_xattr_value_root *xv =
+		(struct ocfs2_xattr_value_root *)et->et_object;
+
+	le32_add_cpu(&xv->xr_clusters, clusters);
+}
+
+static struct ocfs2_extent_tree_operations ocfs2_xattr_value_et_ops = {
+	.eo_set_last_eb_blk	= ocfs2_xattr_value_set_last_eb_blk,
+	.eo_get_last_eb_blk	= ocfs2_xattr_value_get_last_eb_blk,
+	.eo_update_clusters	= ocfs2_xattr_value_update_clusters,
+	.eo_fill_root_el	= ocfs2_xattr_value_fill_root_el,
+};
+
+static void ocfs2_xattr_tree_fill_root_el(struct ocfs2_extent_tree *et)
+{
+	struct ocfs2_xattr_block *xb = et->et_object;
+
+	et->et_root_el = &xb->xb_attrs.xb_root.xt_list;
+}
+
+static void ocfs2_xattr_tree_fill_max_leaf_clusters(struct inode *inode,
+						    struct ocfs2_extent_tree *et)
+{
+	et->et_max_leaf_clusters =
+		ocfs2_clusters_for_bytes(inode->i_sb,
+					 OCFS2_MAX_XATTR_TREE_LEAF_SIZE);
+}
+
+static void ocfs2_xattr_tree_set_last_eb_blk(struct ocfs2_extent_tree *et,
+					     u64 blkno)
+{
+	struct ocfs2_xattr_block *xb = et->et_object;
+	struct ocfs2_xattr_tree_root *xt = &xb->xb_attrs.xb_root;
+
+	xt->xt_last_eb_blk = cpu_to_le64(blkno);
+}
+
+static u64 ocfs2_xattr_tree_get_last_eb_blk(struct ocfs2_extent_tree *et)
+{
+	struct ocfs2_xattr_block *xb = et->et_object;
+	struct ocfs2_xattr_tree_root *xt = &xb->xb_attrs.xb_root;
+
+	return le64_to_cpu(xt->xt_last_eb_blk);
+}
+
+static void ocfs2_xattr_tree_update_clusters(struct inode *inode,
+					     struct ocfs2_extent_tree *et,
+					     u32 clusters)
+{
+	struct ocfs2_xattr_block *xb = et->et_object;
+
+	le32_add_cpu(&xb->xb_attrs.xb_root.xt_clusters, clusters);
+}
+
+static struct ocfs2_extent_tree_operations ocfs2_xattr_tree_et_ops = {
+	.eo_set_last_eb_blk	= ocfs2_xattr_tree_set_last_eb_blk,
+	.eo_get_last_eb_blk	= ocfs2_xattr_tree_get_last_eb_blk,
+	.eo_update_clusters	= ocfs2_xattr_tree_update_clusters,
+	.eo_fill_root_el	= ocfs2_xattr_tree_fill_root_el,
+	.eo_fill_max_leaf_clusters = ocfs2_xattr_tree_fill_max_leaf_clusters,
+};
+
+static void __ocfs2_init_extent_tree(struct ocfs2_extent_tree *et,
+				     struct inode *inode,
+				     struct buffer_head *bh,
+				     void *obj,
+				     struct ocfs2_extent_tree_operations *ops)
+{
+	et->et_ops = ops;
+	et->et_root_bh = bh;
+	if (!obj)
+		obj = (void *)bh->b_data;
+	et->et_object = obj;
+
+	et->et_ops->eo_fill_root_el(et);
+	if (!et->et_ops->eo_fill_max_leaf_clusters)
+		et->et_max_leaf_clusters = 0;
+	else
+		et->et_ops->eo_fill_max_leaf_clusters(inode, et);
+}
+
+void ocfs2_init_dinode_extent_tree(struct ocfs2_extent_tree *et,
+				   struct inode *inode,
+				   struct buffer_head *bh)
+{
+	__ocfs2_init_extent_tree(et, inode, bh, NULL, &ocfs2_dinode_et_ops);
+}
+
+void ocfs2_init_xattr_tree_extent_tree(struct ocfs2_extent_tree *et,
+				       struct inode *inode,
+				       struct buffer_head *bh)
+{
+	__ocfs2_init_extent_tree(et, inode, bh, NULL,
+				 &ocfs2_xattr_tree_et_ops);
+}
+
+void ocfs2_init_xattr_value_extent_tree(struct ocfs2_extent_tree *et,
+					struct inode *inode,
+					struct buffer_head *bh,
+					struct ocfs2_xattr_value_root *xv)
+{
+	__ocfs2_init_extent_tree(et, inode, bh, xv,
+				 &ocfs2_xattr_value_et_ops);
+}
+
+static inline void ocfs2_et_set_last_eb_blk(struct ocfs2_extent_tree *et,
+					    u64 new_last_eb_blk)
+{
+	et->et_ops->eo_set_last_eb_blk(et, new_last_eb_blk);
+}
+
+static inline u64 ocfs2_et_get_last_eb_blk(struct ocfs2_extent_tree *et)
+{
+	return et->et_ops->eo_get_last_eb_blk(et);
+}
+
+static inline void ocfs2_et_update_clusters(struct inode *inode,
+					    struct ocfs2_extent_tree *et,
+					    u32 clusters)
+{
+	et->et_ops->eo_update_clusters(inode, et, clusters);
+}
+
+static inline int ocfs2_et_insert_check(struct inode *inode,
+					struct ocfs2_extent_tree *et,
+					struct ocfs2_extent_rec *rec)
+{
+	int ret = 0;
+
+	if (et->et_ops->eo_insert_check)
+		ret = et->et_ops->eo_insert_check(inode, et, rec);
+	return ret;
+}
+
+static inline int ocfs2_et_sanity_check(struct inode *inode,
+					struct ocfs2_extent_tree *et)
+{
+	int ret = 0;
+
+	if (et->et_ops->eo_sanity_check)
+		ret = et->et_ops->eo_sanity_check(inode, et);
+	return ret;
+}
+
 static void ocfs2_free_truncate_context(struct ocfs2_truncate_context *tc);
 static int ocfs2_cache_extent_block_free(struct ocfs2_cached_dealloc_ctxt *ctxt,
 					 struct ocfs2_extent_block *eb);
@@ -205,17 +539,6 @@
 }
 
 /*
- * Allocate and initialize a new path based on a disk inode tree.
- */
-static struct ocfs2_path *ocfs2_new_inode_path(struct buffer_head *di_bh)
-{
-	struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data;
-	struct ocfs2_extent_list *el = &di->id2.i_list;
-
-	return ocfs2_new_path(di_bh, el);
-}
-
-/*
  * Convenience function to journal all components in a path.
  */
 static int ocfs2_journal_access_path(struct inode *inode, handle_t *handle,
@@ -368,39 +691,35 @@
  */
 int ocfs2_num_free_extents(struct ocfs2_super *osb,
 			   struct inode *inode,
-			   struct ocfs2_dinode *fe)
+			   struct ocfs2_extent_tree *et)
 {
 	int retval;
-	struct ocfs2_extent_list *el;
+	struct ocfs2_extent_list *el = NULL;
 	struct ocfs2_extent_block *eb;
 	struct buffer_head *eb_bh = NULL;
+	u64 last_eb_blk = 0;
 
 	mlog_entry_void();
 
-	if (!OCFS2_IS_VALID_DINODE(fe)) {
-		OCFS2_RO_ON_INVALID_DINODE(inode->i_sb, fe);
-		retval = -EIO;
-		goto bail;
-	}
+	el = et->et_root_el;
+	last_eb_blk = ocfs2_et_get_last_eb_blk(et);
 
-	if (fe->i_last_eb_blk) {
-		retval = ocfs2_read_block(osb, le64_to_cpu(fe->i_last_eb_blk),
-					  &eb_bh, OCFS2_BH_CACHED, inode);
+	if (last_eb_blk) {
+		retval = ocfs2_read_block(inode, last_eb_blk,
+					  &eb_bh);
 		if (retval < 0) {
 			mlog_errno(retval);
 			goto bail;
 		}
 		eb = (struct ocfs2_extent_block *) eb_bh->b_data;
 		el = &eb->h_list;
-	} else
-		el = &fe->id2.i_list;
+	}
 
 	BUG_ON(el->l_tree_depth != 0);
 
 	retval = le16_to_cpu(el->l_count) - le16_to_cpu(el->l_next_free_rec);
 bail:
-	if (eb_bh)
-		brelse(eb_bh);
+	brelse(eb_bh);
 
 	mlog_exit(retval);
 	return retval;
@@ -486,8 +805,7 @@
 bail:
 	if (status < 0) {
 		for(i = 0; i < wanted; i++) {
-			if (bhs[i])
-				brelse(bhs[i]);
+			brelse(bhs[i]);
 			bhs[i] = NULL;
 		}
 	}
@@ -531,7 +849,7 @@
 static int ocfs2_add_branch(struct ocfs2_super *osb,
 			    handle_t *handle,
 			    struct inode *inode,
-			    struct buffer_head *fe_bh,
+			    struct ocfs2_extent_tree *et,
 			    struct buffer_head *eb_bh,
 			    struct buffer_head **last_eb_bh,
 			    struct ocfs2_alloc_context *meta_ac)
@@ -540,7 +858,6 @@
 	u64 next_blkno, new_last_eb_blk;
 	struct buffer_head *bh;
 	struct buffer_head **new_eb_bhs = NULL;
-	struct ocfs2_dinode *fe;
 	struct ocfs2_extent_block *eb;
 	struct ocfs2_extent_list  *eb_el;
 	struct ocfs2_extent_list  *el;
@@ -550,13 +867,11 @@
 
 	BUG_ON(!last_eb_bh || !*last_eb_bh);
 
-	fe = (struct ocfs2_dinode *) fe_bh->b_data;
-
 	if (eb_bh) {
 		eb = (struct ocfs2_extent_block *) eb_bh->b_data;
 		el = &eb->h_list;
 	} else
-		el = &fe->id2.i_list;
+		el = et->et_root_el;
 
 	/* we never add a branch to a leaf. */
 	BUG_ON(!el->l_tree_depth);
@@ -646,7 +961,7 @@
 		mlog_errno(status);
 		goto bail;
 	}
-	status = ocfs2_journal_access(handle, inode, fe_bh,
+	status = ocfs2_journal_access(handle, inode, et->et_root_bh,
 				      OCFS2_JOURNAL_ACCESS_WRITE);
 	if (status < 0) {
 		mlog_errno(status);
@@ -662,7 +977,7 @@
 	}
 
 	/* Link the new branch into the rest of the tree (el will
-	 * either be on the fe, or the extent block passed in. */
+	 * either be on the root_bh, or the extent block passed in. */
 	i = le16_to_cpu(el->l_next_free_rec);
 	el->l_recs[i].e_blkno = cpu_to_le64(next_blkno);
 	el->l_recs[i].e_cpos = cpu_to_le32(new_cpos);
@@ -671,7 +986,7 @@
 
 	/* fe needs a new last extent block pointer, as does the
 	 * next_leaf on the previously last-extent-block. */
-	fe->i_last_eb_blk = cpu_to_le64(new_last_eb_blk);
+	ocfs2_et_set_last_eb_blk(et, new_last_eb_blk);
 
 	eb = (struct ocfs2_extent_block *) (*last_eb_bh)->b_data;
 	eb->h_next_leaf_blk = cpu_to_le64(new_last_eb_blk);
@@ -679,7 +994,7 @@
 	status = ocfs2_journal_dirty(handle, *last_eb_bh);
 	if (status < 0)
 		mlog_errno(status);
-	status = ocfs2_journal_dirty(handle, fe_bh);
+	status = ocfs2_journal_dirty(handle, et->et_root_bh);
 	if (status < 0)
 		mlog_errno(status);
 	if (eb_bh) {
@@ -700,8 +1015,7 @@
 bail:
 	if (new_eb_bhs) {
 		for (i = 0; i < new_blocks; i++)
-			if (new_eb_bhs[i])
-				brelse(new_eb_bhs[i]);
+			brelse(new_eb_bhs[i]);
 		kfree(new_eb_bhs);
 	}
 
@@ -717,16 +1031,15 @@
 static int ocfs2_shift_tree_depth(struct ocfs2_super *osb,
 				  handle_t *handle,
 				  struct inode *inode,
-				  struct buffer_head *fe_bh,
+				  struct ocfs2_extent_tree *et,
 				  struct ocfs2_alloc_context *meta_ac,
 				  struct buffer_head **ret_new_eb_bh)
 {
 	int status, i;
 	u32 new_clusters;
 	struct buffer_head *new_eb_bh = NULL;
-	struct ocfs2_dinode *fe;
 	struct ocfs2_extent_block *eb;
-	struct ocfs2_extent_list  *fe_el;
+	struct ocfs2_extent_list  *root_el;
 	struct ocfs2_extent_list  *eb_el;
 
 	mlog_entry_void();
@@ -746,8 +1059,7 @@
 	}
 
 	eb_el = &eb->h_list;
-	fe = (struct ocfs2_dinode *) fe_bh->b_data;
-	fe_el = &fe->id2.i_list;
+	root_el = et->et_root_el;
 
 	status = ocfs2_journal_access(handle, inode, new_eb_bh,
 				      OCFS2_JOURNAL_ACCESS_CREATE);
@@ -756,11 +1068,11 @@
 		goto bail;
 	}
 
-	/* copy the fe data into the new extent block */
-	eb_el->l_tree_depth = fe_el->l_tree_depth;
-	eb_el->l_next_free_rec = fe_el->l_next_free_rec;
-	for(i = 0; i < le16_to_cpu(fe_el->l_next_free_rec); i++)
-		eb_el->l_recs[i] = fe_el->l_recs[i];
+	/* copy the root extent list data into the new extent block */
+	eb_el->l_tree_depth = root_el->l_tree_depth;
+	eb_el->l_next_free_rec = root_el->l_next_free_rec;
+	for (i = 0; i < le16_to_cpu(root_el->l_next_free_rec); i++)
+		eb_el->l_recs[i] = root_el->l_recs[i];
 
 	status = ocfs2_journal_dirty(handle, new_eb_bh);
 	if (status < 0) {
@@ -768,7 +1080,7 @@
 		goto bail;
 	}
 
-	status = ocfs2_journal_access(handle, inode, fe_bh,
+	status = ocfs2_journal_access(handle, inode, et->et_root_bh,
 				      OCFS2_JOURNAL_ACCESS_WRITE);
 	if (status < 0) {
 		mlog_errno(status);
@@ -777,21 +1089,21 @@
 
 	new_clusters = ocfs2_sum_rightmost_rec(eb_el);
 
-	/* update fe now */
-	le16_add_cpu(&fe_el->l_tree_depth, 1);
-	fe_el->l_recs[0].e_cpos = 0;
-	fe_el->l_recs[0].e_blkno = eb->h_blkno;
-	fe_el->l_recs[0].e_int_clusters = cpu_to_le32(new_clusters);
-	for(i = 1; i < le16_to_cpu(fe_el->l_next_free_rec); i++)
-		memset(&fe_el->l_recs[i], 0, sizeof(struct ocfs2_extent_rec));
-	fe_el->l_next_free_rec = cpu_to_le16(1);
+	/* update root_bh now */
+	le16_add_cpu(&root_el->l_tree_depth, 1);
+	root_el->l_recs[0].e_cpos = 0;
+	root_el->l_recs[0].e_blkno = eb->h_blkno;
+	root_el->l_recs[0].e_int_clusters = cpu_to_le32(new_clusters);
+	for (i = 1; i < le16_to_cpu(root_el->l_next_free_rec); i++)
+		memset(&root_el->l_recs[i], 0, sizeof(struct ocfs2_extent_rec));
+	root_el->l_next_free_rec = cpu_to_le16(1);
 
 	/* If this is our 1st tree depth shift, then last_eb_blk
 	 * becomes the allocated extent block */
-	if (fe_el->l_tree_depth == cpu_to_le16(1))
-		fe->i_last_eb_blk = eb->h_blkno;
+	if (root_el->l_tree_depth == cpu_to_le16(1))
+		ocfs2_et_set_last_eb_blk(et, le64_to_cpu(eb->h_blkno));
 
-	status = ocfs2_journal_dirty(handle, fe_bh);
+	status = ocfs2_journal_dirty(handle, et->et_root_bh);
 	if (status < 0) {
 		mlog_errno(status);
 		goto bail;
@@ -801,8 +1113,7 @@
 	new_eb_bh = NULL;
 	status = 0;
 bail:
-	if (new_eb_bh)
-		brelse(new_eb_bh);
+	brelse(new_eb_bh);
 
 	mlog_exit(status);
 	return status;
@@ -817,22 +1128,21 @@
  * 1) a lowest extent block is found, then we pass it back in
  *    *lowest_eb_bh and return '0'
  *
- * 2) the search fails to find anything, but the dinode has room. We
+ * 2) the search fails to find anything, but the root_el has room. We
  *    pass NULL back in *lowest_eb_bh, but still return '0'
  *
- * 3) the search fails to find anything AND the dinode is full, in
+ * 3) the search fails to find anything AND the root_el is full, in
  *    which case we return > 0
  *
  * return status < 0 indicates an error.
  */
 static int ocfs2_find_branch_target(struct ocfs2_super *osb,
 				    struct inode *inode,
-				    struct buffer_head *fe_bh,
+				    struct ocfs2_extent_tree *et,
 				    struct buffer_head **target_bh)
 {
 	int status = 0, i;
 	u64 blkno;
-	struct ocfs2_dinode *fe;
 	struct ocfs2_extent_block *eb;
 	struct ocfs2_extent_list  *el;
 	struct buffer_head *bh = NULL;
@@ -842,8 +1152,7 @@
 
 	*target_bh = NULL;
 
-	fe = (struct ocfs2_dinode *) fe_bh->b_data;
-	el = &fe->id2.i_list;
+	el = et->et_root_el;
 
 	while(le16_to_cpu(el->l_tree_depth) > 1) {
 		if (le16_to_cpu(el->l_next_free_rec) == 0) {
@@ -864,13 +1173,10 @@
 			goto bail;
 		}
 
-		if (bh) {
-			brelse(bh);
-			bh = NULL;
-		}
+		brelse(bh);
+		bh = NULL;
 
-		status = ocfs2_read_block(osb, blkno, &bh, OCFS2_BH_CACHED,
-					  inode);
+		status = ocfs2_read_block(inode, blkno, &bh);
 		if (status < 0) {
 			mlog_errno(status);
 			goto bail;
@@ -886,8 +1192,7 @@
 
 		if (le16_to_cpu(el->l_next_free_rec) <
 		    le16_to_cpu(el->l_count)) {
-			if (lowest_bh)
-				brelse(lowest_bh);
+			brelse(lowest_bh);
 			lowest_bh = bh;
 			get_bh(lowest_bh);
 		}
@@ -895,14 +1200,13 @@
 
 	/* If we didn't find one and the fe doesn't have any room,
 	 * then return '1' */
-	if (!lowest_bh
-	    && (fe->id2.i_list.l_next_free_rec == fe->id2.i_list.l_count))
+	el = et->et_root_el;
+	if (!lowest_bh && (el->l_next_free_rec == el->l_count))
 		status = 1;
 
 	*target_bh = lowest_bh;
 bail:
-	if (bh)
-		brelse(bh);
+	brelse(bh);
 
 	mlog_exit(status);
 	return status;
@@ -919,19 +1223,19 @@
  * *last_eb_bh will be updated by ocfs2_add_branch().
  */
 static int ocfs2_grow_tree(struct inode *inode, handle_t *handle,
-			   struct buffer_head *di_bh, int *final_depth,
+			   struct ocfs2_extent_tree *et, int *final_depth,
 			   struct buffer_head **last_eb_bh,
 			   struct ocfs2_alloc_context *meta_ac)
 {
 	int ret, shift;
-	struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data;
-	int depth = le16_to_cpu(di->id2.i_list.l_tree_depth);
+	struct ocfs2_extent_list *el = et->et_root_el;
+	int depth = le16_to_cpu(el->l_tree_depth);
 	struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
 	struct buffer_head *bh = NULL;
 
 	BUG_ON(meta_ac == NULL);
 
-	shift = ocfs2_find_branch_target(osb, inode, di_bh, &bh);
+	shift = ocfs2_find_branch_target(osb, inode, et, &bh);
 	if (shift < 0) {
 		ret = shift;
 		mlog_errno(ret);
@@ -948,7 +1252,7 @@
 		/* ocfs2_shift_tree_depth will return us a buffer with
 		 * the new extent block (so we can pass that to
 		 * ocfs2_add_branch). */
-		ret = ocfs2_shift_tree_depth(osb, handle, inode, di_bh,
+		ret = ocfs2_shift_tree_depth(osb, handle, inode, et,
 					     meta_ac, &bh);
 		if (ret < 0) {
 			mlog_errno(ret);
@@ -975,7 +1279,7 @@
 	/* call ocfs2_add_branch to add the final part of the tree with
 	 * the new data. */
 	mlog(0, "add branch. bh = %p\n", bh);
-	ret = ocfs2_add_branch(osb, handle, inode, di_bh, bh, last_eb_bh,
+	ret = ocfs2_add_branch(osb, handle, inode, et, bh, last_eb_bh,
 			       meta_ac);
 	if (ret < 0) {
 		mlog_errno(ret);
@@ -990,15 +1294,6 @@
 }
 
 /*
- * This is only valid for leaf nodes, which are the only ones that can
- * have empty extents anyway.
- */
-static inline int ocfs2_is_empty_extent(struct ocfs2_extent_rec *rec)
-{
-	return !rec->e_leaf_clusters;
-}
-
-/*
  * This function will discard the rightmost extent record.
  */
 static void ocfs2_shift_records_right(struct ocfs2_extent_list *el)
@@ -1245,8 +1540,7 @@
 
 		brelse(bh);
 		bh = NULL;
-		ret = ocfs2_read_block(OCFS2_SB(inode->i_sb), blkno,
-				       &bh, OCFS2_BH_CACHED, inode);
+		ret = ocfs2_read_block(inode, blkno, &bh);
 		if (ret) {
 			mlog_errno(ret);
 			goto out;
@@ -2067,11 +2361,11 @@
 				     struct ocfs2_path *right_path,
 				     int subtree_index,
 				     struct ocfs2_cached_dealloc_ctxt *dealloc,
-				     int *deleted)
+				     int *deleted,
+				     struct ocfs2_extent_tree *et)
 {
 	int ret, i, del_right_subtree = 0, right_has_empty = 0;
-	struct buffer_head *root_bh, *di_bh = path_root_bh(right_path);
-	struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data;
+	struct buffer_head *root_bh, *et_root_bh = path_root_bh(right_path);
 	struct ocfs2_extent_list *right_leaf_el, *left_leaf_el;
 	struct ocfs2_extent_block *eb;
 
@@ -2123,7 +2417,7 @@
 		 * We have to update i_last_eb_blk during the meta
 		 * data delete.
 		 */
-		ret = ocfs2_journal_access(handle, inode, di_bh,
+		ret = ocfs2_journal_access(handle, inode, et_root_bh,
 					   OCFS2_JOURNAL_ACCESS_WRITE);
 		if (ret) {
 			mlog_errno(ret);
@@ -2198,7 +2492,7 @@
 		ocfs2_update_edge_lengths(inode, handle, left_path);
 
 		eb = (struct ocfs2_extent_block *)path_leaf_bh(left_path)->b_data;
-		di->i_last_eb_blk = eb->h_blkno;
+		ocfs2_et_set_last_eb_blk(et, le64_to_cpu(eb->h_blkno));
 
 		/*
 		 * Removal of the extent in the left leaf was skipped
@@ -2208,7 +2502,7 @@
 		if (right_has_empty)
 			ocfs2_remove_empty_extent(left_leaf_el);
 
-		ret = ocfs2_journal_dirty(handle, di_bh);
+		ret = ocfs2_journal_dirty(handle, et_root_bh);
 		if (ret)
 			mlog_errno(ret);
 
@@ -2331,7 +2625,8 @@
 				    handle_t *handle, int orig_credits,
 				    struct ocfs2_path *path,
 				    struct ocfs2_cached_dealloc_ctxt *dealloc,
-				    struct ocfs2_path **empty_extent_path)
+				    struct ocfs2_path **empty_extent_path,
+				    struct ocfs2_extent_tree *et)
 {
 	int ret, subtree_root, deleted;
 	u32 right_cpos;
@@ -2404,7 +2699,7 @@
 
 		ret = ocfs2_rotate_subtree_left(inode, handle, left_path,
 						right_path, subtree_root,
-						dealloc, &deleted);
+						dealloc, &deleted, et);
 		if (ret == -EAGAIN) {
 			/*
 			 * The rotation has to temporarily stop due to
@@ -2447,29 +2742,20 @@
 }
 
 static int ocfs2_remove_rightmost_path(struct inode *inode, handle_t *handle,
-				       struct ocfs2_path *path,
-				       struct ocfs2_cached_dealloc_ctxt *dealloc)
+				struct ocfs2_path *path,
+				struct ocfs2_cached_dealloc_ctxt *dealloc,
+				struct ocfs2_extent_tree *et)
 {
 	int ret, subtree_index;
 	u32 cpos;
 	struct ocfs2_path *left_path = NULL;
-	struct ocfs2_dinode *di;
 	struct ocfs2_extent_block *eb;
 	struct ocfs2_extent_list *el;
 
-	/*
-	 * XXX: This code assumes that the root is an inode, which is
-	 * true for now but may change as tree code gets generic.
-	 */
-	di = (struct ocfs2_dinode *)path_root_bh(path)->b_data;
-	if (!OCFS2_IS_VALID_DINODE(di)) {
-		ret = -EIO;
-		ocfs2_error(inode->i_sb,
-			    "Inode %llu has invalid path root",
-			    (unsigned long long)OCFS2_I(inode)->ip_blkno);
-		goto out;
-	}
 
+	ret = ocfs2_et_sanity_check(inode, et);
+	if (ret)
+		goto out;
 	/*
 	 * There's two ways we handle this depending on
 	 * whether path is the only existing one.
@@ -2526,7 +2812,7 @@
 		ocfs2_update_edge_lengths(inode, handle, left_path);
 
 		eb = (struct ocfs2_extent_block *)path_leaf_bh(left_path)->b_data;
-		di->i_last_eb_blk = eb->h_blkno;
+		ocfs2_et_set_last_eb_blk(et, le64_to_cpu(eb->h_blkno));
 	} else {
 		/*
 		 * 'path' is also the leftmost path which
@@ -2537,12 +2823,12 @@
 		 */
 		ocfs2_unlink_path(inode, handle, dealloc, path, 1);
 
-		el = &di->id2.i_list;
+		el = et->et_root_el;
 		el->l_tree_depth = 0;
 		el->l_next_free_rec = 0;
 		memset(&el->l_recs[0], 0, sizeof(struct ocfs2_extent_rec));
 
-		di->i_last_eb_blk = 0;
+		ocfs2_et_set_last_eb_blk(et, 0);
 	}
 
 	ocfs2_journal_dirty(handle, path_root_bh(path));
@@ -2570,7 +2856,8 @@
  */
 static int ocfs2_rotate_tree_left(struct inode *inode, handle_t *handle,
 				  struct ocfs2_path *path,
-				  struct ocfs2_cached_dealloc_ctxt *dealloc)
+				  struct ocfs2_cached_dealloc_ctxt *dealloc,
+				  struct ocfs2_extent_tree *et)
 {
 	int ret, orig_credits = handle->h_buffer_credits;
 	struct ocfs2_path *tmp_path = NULL, *restart_path = NULL;
@@ -2584,7 +2871,7 @@
 	if (path->p_tree_depth == 0) {
 rightmost_no_delete:
 		/*
-		 * In-inode extents. This is trivially handled, so do
+		 * Inline extents. This is trivially handled, so do
 		 * it up front.
 		 */
 		ret = ocfs2_rotate_rightmost_leaf_left(inode, handle,
@@ -2638,7 +2925,7 @@
 		 */
 
 		ret = ocfs2_remove_rightmost_path(inode, handle, path,
-						  dealloc);
+						  dealloc, et);
 		if (ret)
 			mlog_errno(ret);
 		goto out;
@@ -2650,7 +2937,7 @@
 	 */
 try_rotate:
 	ret = __ocfs2_rotate_tree_left(inode, handle, orig_credits, path,
-				       dealloc, &restart_path);
+				       dealloc, &restart_path, et);
 	if (ret && ret != -EAGAIN) {
 		mlog_errno(ret);
 		goto out;
@@ -2662,7 +2949,7 @@
 
 		ret = __ocfs2_rotate_tree_left(inode, handle, orig_credits,
 					       tmp_path, dealloc,
-					       &restart_path);
+					       &restart_path, et);
 		if (ret && ret != -EAGAIN) {
 			mlog_errno(ret);
 			goto out;
@@ -2948,6 +3235,7 @@
 				handle_t *handle,
 				struct ocfs2_extent_rec *split_rec,
 				struct ocfs2_cached_dealloc_ctxt *dealloc,
+				struct ocfs2_extent_tree *et,
 				int index)
 {
 	int ret, i, subtree_index = 0, has_empty_extent = 0;
@@ -3068,7 +3356,8 @@
 		    le16_to_cpu(el->l_next_free_rec) == 1) {
 
 			ret = ocfs2_remove_rightmost_path(inode, handle,
-							  right_path, dealloc);
+							  right_path,
+							  dealloc, et);
 			if (ret) {
 				mlog_errno(ret);
 				goto out;
@@ -3095,7 +3384,8 @@
 				     int split_index,
 				     struct ocfs2_extent_rec *split_rec,
 				     struct ocfs2_cached_dealloc_ctxt *dealloc,
-				     struct ocfs2_merge_ctxt *ctxt)
+				     struct ocfs2_merge_ctxt *ctxt,
+				     struct ocfs2_extent_tree *et)
 
 {
 	int ret = 0;
@@ -3113,7 +3403,7 @@
 		 * illegal.
 		 */
 		ret = ocfs2_rotate_tree_left(inode, handle, path,
-					     dealloc);
+					     dealloc, et);
 		if (ret) {
 			mlog_errno(ret);
 			goto out;
@@ -3156,7 +3446,8 @@
 		BUG_ON(!ocfs2_is_empty_extent(&el->l_recs[0]));
 
 		/* The merge left us with an empty extent, remove it. */
-		ret = ocfs2_rotate_tree_left(inode, handle, path, dealloc);
+		ret = ocfs2_rotate_tree_left(inode, handle, path,
+					     dealloc, et);
 		if (ret) {
 			mlog_errno(ret);
 			goto out;
@@ -3170,7 +3461,7 @@
 		 */
 		ret = ocfs2_merge_rec_left(inode, path,
 					   handle, rec,
-					   dealloc,
+					   dealloc, et,
 					   split_index);
 
 		if (ret) {
@@ -3179,7 +3470,7 @@
 		}
 
 		ret = ocfs2_rotate_tree_left(inode, handle, path,
-					     dealloc);
+					     dealloc, et);
 		/*
 		 * Error from this last rotate is not critical, so
 		 * print but don't bubble it up.
@@ -3199,7 +3490,7 @@
 			ret = ocfs2_merge_rec_left(inode,
 						   path,
 						   handle, split_rec,
-						   dealloc,
+						   dealloc, et,
 						   split_index);
 			if (ret) {
 				mlog_errno(ret);
@@ -3222,7 +3513,7 @@
 			 * our leaf. Try to rotate it away.
 			 */
 			ret = ocfs2_rotate_tree_left(inode, handle, path,
-						     dealloc);
+						     dealloc, et);
 			if (ret)
 				mlog_errno(ret);
 			ret = 0;
@@ -3356,16 +3647,6 @@
 	ocfs2_rotate_leaf(el, insert_rec);
 }
 
-static inline void ocfs2_update_dinode_clusters(struct inode *inode,
-						struct ocfs2_dinode *di,
-						u32 clusters)
-{
-	le32_add_cpu(&di->i_clusters, clusters);
-	spin_lock(&OCFS2_I(inode)->ip_lock);
-	OCFS2_I(inode)->ip_clusters = le32_to_cpu(di->i_clusters);
-	spin_unlock(&OCFS2_I(inode)->ip_lock);
-}
-
 static void ocfs2_adjust_rightmost_records(struct inode *inode,
 					   handle_t *handle,
 					   struct ocfs2_path *path,
@@ -3567,8 +3848,8 @@
 }
 
 /*
- * This function only does inserts on an allocation b-tree. For dinode
- * lists, ocfs2_insert_at_leaf() is called directly.
+ * This function only does inserts on an allocation b-tree. For tree
+ * depth = 0, ocfs2_insert_at_leaf() is called directly.
  *
  * right_path is the path we want to do the actual insert
  * in. left_path should only be passed in if we need to update that
@@ -3665,7 +3946,7 @@
 
 static int ocfs2_do_insert_extent(struct inode *inode,
 				  handle_t *handle,
-				  struct buffer_head *di_bh,
+				  struct ocfs2_extent_tree *et,
 				  struct ocfs2_extent_rec *insert_rec,
 				  struct ocfs2_insert_type *type)
 {
@@ -3673,13 +3954,11 @@
 	u32 cpos;
 	struct ocfs2_path *right_path = NULL;
 	struct ocfs2_path *left_path = NULL;
-	struct ocfs2_dinode *di;
 	struct ocfs2_extent_list *el;
 
-	di = (struct ocfs2_dinode *) di_bh->b_data;
-	el = &di->id2.i_list;
+	el = et->et_root_el;
 
-	ret = ocfs2_journal_access(handle, inode, di_bh,
+	ret = ocfs2_journal_access(handle, inode, et->et_root_bh,
 				   OCFS2_JOURNAL_ACCESS_WRITE);
 	if (ret) {
 		mlog_errno(ret);
@@ -3691,7 +3970,7 @@
 		goto out_update_clusters;
 	}
 
-	right_path = ocfs2_new_inode_path(di_bh);
+	right_path = ocfs2_new_path(et->et_root_bh, et->et_root_el);
 	if (!right_path) {
 		ret = -ENOMEM;
 		mlog_errno(ret);
@@ -3741,7 +4020,7 @@
 		 * ocfs2_rotate_tree_right() might have extended the
 		 * transaction without re-journaling our tree root.
 		 */
-		ret = ocfs2_journal_access(handle, inode, di_bh,
+		ret = ocfs2_journal_access(handle, inode, et->et_root_bh,
 					   OCFS2_JOURNAL_ACCESS_WRITE);
 		if (ret) {
 			mlog_errno(ret);
@@ -3766,10 +4045,10 @@
 
 out_update_clusters:
 	if (type->ins_split == SPLIT_NONE)
-		ocfs2_update_dinode_clusters(inode, di,
-					     le16_to_cpu(insert_rec->e_leaf_clusters));
+		ocfs2_et_update_clusters(inode, et,
+					 le16_to_cpu(insert_rec->e_leaf_clusters));
 
-	ret = ocfs2_journal_dirty(handle, di_bh);
+	ret = ocfs2_journal_dirty(handle, et->et_root_bh);
 	if (ret)
 		mlog_errno(ret);
 
@@ -3899,7 +4178,8 @@
 static void ocfs2_figure_contig_type(struct inode *inode,
 				     struct ocfs2_insert_type *insert,
 				     struct ocfs2_extent_list *el,
-				     struct ocfs2_extent_rec *insert_rec)
+				     struct ocfs2_extent_rec *insert_rec,
+				     struct ocfs2_extent_tree *et)
 {
 	int i;
 	enum ocfs2_contig_type contig_type = CONTIG_NONE;
@@ -3915,6 +4195,21 @@
 		}
 	}
 	insert->ins_contig = contig_type;
+
+	if (insert->ins_contig != CONTIG_NONE) {
+		struct ocfs2_extent_rec *rec =
+				&el->l_recs[insert->ins_contig_index];
+		unsigned int len = le16_to_cpu(rec->e_leaf_clusters) +
+				   le16_to_cpu(insert_rec->e_leaf_clusters);
+
+		/*
+		 * Caller might want us to limit the size of extents, don't
+		 * calculate contiguousness if we might exceed that limit.
+		 */
+		if (et->et_max_leaf_clusters &&
+		    (len > et->et_max_leaf_clusters))
+			insert->ins_contig = CONTIG_NONE;
+	}
 }
 
 /*
@@ -3923,8 +4218,8 @@
  * ocfs2_figure_appending_type() will figure out whether we'll have to
  * insert at the tail of the rightmost leaf.
  *
- * This should also work against the dinode list for tree's with 0
- * depth. If we consider the dinode list to be the rightmost leaf node
+ * This should also work against the root extent list for tree's with 0
+ * depth. If we consider the root extent list to be the rightmost leaf node
  * then the logic here makes sense.
  */
 static void ocfs2_figure_appending_type(struct ocfs2_insert_type *insert,
@@ -3975,14 +4270,13 @@
  * structure.
  */
 static int ocfs2_figure_insert_type(struct inode *inode,
-				    struct buffer_head *di_bh,
+				    struct ocfs2_extent_tree *et,
 				    struct buffer_head **last_eb_bh,
 				    struct ocfs2_extent_rec *insert_rec,
 				    int *free_records,
 				    struct ocfs2_insert_type *insert)
 {
 	int ret;
-	struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data;
 	struct ocfs2_extent_block *eb;
 	struct ocfs2_extent_list *el;
 	struct ocfs2_path *path = NULL;
@@ -3990,7 +4284,7 @@
 
 	insert->ins_split = SPLIT_NONE;
 
-	el = &di->id2.i_list;
+	el = et->et_root_el;
 	insert->ins_tree_depth = le16_to_cpu(el->l_tree_depth);
 
 	if (el->l_tree_depth) {
@@ -4000,9 +4294,7 @@
 		 * ocfs2_figure_insert_type() and ocfs2_add_branch()
 		 * may want it later.
 		 */
-		ret = ocfs2_read_block(OCFS2_SB(inode->i_sb),
-				       le64_to_cpu(di->i_last_eb_blk), &bh,
-				       OCFS2_BH_CACHED, inode);
+		ret = ocfs2_read_block(inode, ocfs2_et_get_last_eb_blk(et), &bh);
 		if (ret) {
 			mlog_exit(ret);
 			goto out;
@@ -4023,12 +4315,12 @@
 		le16_to_cpu(el->l_next_free_rec);
 
 	if (!insert->ins_tree_depth) {
-		ocfs2_figure_contig_type(inode, insert, el, insert_rec);
+		ocfs2_figure_contig_type(inode, insert, el, insert_rec, et);
 		ocfs2_figure_appending_type(insert, el, insert_rec);
 		return 0;
 	}
 
-	path = ocfs2_new_inode_path(di_bh);
+	path = ocfs2_new_path(et->et_root_bh, et->et_root_el);
 	if (!path) {
 		ret = -ENOMEM;
 		mlog_errno(ret);
@@ -4057,7 +4349,7 @@
          *     into two types of appends: simple record append, or a
          *     rotate inside the tail leaf.
 	 */
-	ocfs2_figure_contig_type(inode, insert, el, insert_rec);
+	ocfs2_figure_contig_type(inode, insert, el, insert_rec, et);
 
 	/*
 	 * The insert code isn't quite ready to deal with all cases of
@@ -4078,7 +4370,8 @@
 	 * the case that we're doing a tail append, so maybe we can
 	 * take advantage of that information somehow.
 	 */
-	if (le64_to_cpu(di->i_last_eb_blk) == path_leaf_bh(path)->b_blocknr) {
+	if (ocfs2_et_get_last_eb_blk(et) ==
+	    path_leaf_bh(path)->b_blocknr) {
 		/*
 		 * Ok, ocfs2_find_path() returned us the rightmost
 		 * tree path. This might be an appending insert. There are
@@ -4108,7 +4401,7 @@
 int ocfs2_insert_extent(struct ocfs2_super *osb,
 			handle_t *handle,
 			struct inode *inode,
-			struct buffer_head *fe_bh,
+			struct ocfs2_extent_tree *et,
 			u32 cpos,
 			u64 start_blk,
 			u32 new_clusters,
@@ -4121,26 +4414,21 @@
 	struct ocfs2_insert_type insert = {0, };
 	struct ocfs2_extent_rec rec;
 
-	BUG_ON(OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL);
-
 	mlog(0, "add %u clusters at position %u to inode %llu\n",
 	     new_clusters, cpos, (unsigned long long)OCFS2_I(inode)->ip_blkno);
 
-	mlog_bug_on_msg(!ocfs2_sparse_alloc(osb) &&
-			(OCFS2_I(inode)->ip_clusters != cpos),
-			"Device %s, asking for sparse allocation: inode %llu, "
-			"cpos %u, clusters %u\n",
-			osb->dev_str,
-			(unsigned long long)OCFS2_I(inode)->ip_blkno, cpos,
-			OCFS2_I(inode)->ip_clusters);
-
 	memset(&rec, 0, sizeof(rec));
 	rec.e_cpos = cpu_to_le32(cpos);
 	rec.e_blkno = cpu_to_le64(start_blk);
 	rec.e_leaf_clusters = cpu_to_le16(new_clusters);
 	rec.e_flags = flags;
+	status = ocfs2_et_insert_check(inode, et, &rec);
+	if (status) {
+		mlog_errno(status);
+		goto bail;
+	}
 
-	status = ocfs2_figure_insert_type(inode, fe_bh, &last_eb_bh, &rec,
+	status = ocfs2_figure_insert_type(inode, et, &last_eb_bh, &rec,
 					  &free_records, &insert);
 	if (status < 0) {
 		mlog_errno(status);
@@ -4154,7 +4442,7 @@
 	     free_records, insert.ins_tree_depth);
 
 	if (insert.ins_contig == CONTIG_NONE && free_records == 0) {
-		status = ocfs2_grow_tree(inode, handle, fe_bh,
+		status = ocfs2_grow_tree(inode, handle, et,
 					 &insert.ins_tree_depth, &last_eb_bh,
 					 meta_ac);
 		if (status) {
@@ -4164,20 +4452,127 @@
 	}
 
 	/* Finally, we can add clusters. This might rotate the tree for us. */
-	status = ocfs2_do_insert_extent(inode, handle, fe_bh, &rec, &insert);
+	status = ocfs2_do_insert_extent(inode, handle, et, &rec, &insert);
 	if (status < 0)
 		mlog_errno(status);
-	else
+	else if (et->et_ops == &ocfs2_dinode_et_ops)
 		ocfs2_extent_map_insert_rec(inode, &rec);
 
 bail:
-	if (last_eb_bh)
-		brelse(last_eb_bh);
+	brelse(last_eb_bh);
 
 	mlog_exit(status);
 	return status;
 }
 
+/*
+ * Allcate and add clusters into the extent b-tree.
+ * The new clusters(clusters_to_add) will be inserted at logical_offset.
+ * The extent b-tree's root is specified by et, and
+ * it is not limited to the file storage. Any extent tree can use this
+ * function if it implements the proper ocfs2_extent_tree.
+ */
+int ocfs2_add_clusters_in_btree(struct ocfs2_super *osb,
+				struct inode *inode,
+				u32 *logical_offset,
+				u32 clusters_to_add,
+				int mark_unwritten,
+				struct ocfs2_extent_tree *et,
+				handle_t *handle,
+				struct ocfs2_alloc_context *data_ac,
+				struct ocfs2_alloc_context *meta_ac,
+				enum ocfs2_alloc_restarted *reason_ret)
+{
+	int status = 0;
+	int free_extents;
+	enum ocfs2_alloc_restarted reason = RESTART_NONE;
+	u32 bit_off, num_bits;
+	u64 block;
+	u8 flags = 0;
+
+	BUG_ON(!clusters_to_add);
+
+	if (mark_unwritten)
+		flags = OCFS2_EXT_UNWRITTEN;
+
+	free_extents = ocfs2_num_free_extents(osb, inode, et);
+	if (free_extents < 0) {
+		status = free_extents;
+		mlog_errno(status);
+		goto leave;
+	}
+
+	/* there are two cases which could cause us to EAGAIN in the
+	 * we-need-more-metadata case:
+	 * 1) we haven't reserved *any*
+	 * 2) we are so fragmented, we've needed to add metadata too
+	 *    many times. */
+	if (!free_extents && !meta_ac) {
+		mlog(0, "we haven't reserved any metadata!\n");
+		status = -EAGAIN;
+		reason = RESTART_META;
+		goto leave;
+	} else if ((!free_extents)
+		   && (ocfs2_alloc_context_bits_left(meta_ac)
+		       < ocfs2_extend_meta_needed(et->et_root_el))) {
+		mlog(0, "filesystem is really fragmented...\n");
+		status = -EAGAIN;
+		reason = RESTART_META;
+		goto leave;
+	}
+
+	status = __ocfs2_claim_clusters(osb, handle, data_ac, 1,
+					clusters_to_add, &bit_off, &num_bits);
+	if (status < 0) {
+		if (status != -ENOSPC)
+			mlog_errno(status);
+		goto leave;
+	}
+
+	BUG_ON(num_bits > clusters_to_add);
+
+	/* reserve our write early -- insert_extent may update the inode */
+	status = ocfs2_journal_access(handle, inode, et->et_root_bh,
+				      OCFS2_JOURNAL_ACCESS_WRITE);
+	if (status < 0) {
+		mlog_errno(status);
+		goto leave;
+	}
+
+	block = ocfs2_clusters_to_blocks(osb->sb, bit_off);
+	mlog(0, "Allocating %u clusters at block %u for inode %llu\n",
+	     num_bits, bit_off, (unsigned long long)OCFS2_I(inode)->ip_blkno);
+	status = ocfs2_insert_extent(osb, handle, inode, et,
+				     *logical_offset, block,
+				     num_bits, flags, meta_ac);
+	if (status < 0) {
+		mlog_errno(status);
+		goto leave;
+	}
+
+	status = ocfs2_journal_dirty(handle, et->et_root_bh);
+	if (status < 0) {
+		mlog_errno(status);
+		goto leave;
+	}
+
+	clusters_to_add -= num_bits;
+	*logical_offset += num_bits;
+
+	if (clusters_to_add) {
+		mlog(0, "need to alloc once more, wanted = %u\n",
+		     clusters_to_add);
+		status = -EAGAIN;
+		reason = RESTART_TRANS;
+	}
+
+leave:
+	mlog_exit(status);
+	if (reason_ret)
+		*reason_ret = reason;
+	return status;
+}
+
 static void ocfs2_make_right_split_rec(struct super_block *sb,
 				       struct ocfs2_extent_rec *split_rec,
 				       u32 cpos,
@@ -4201,7 +4596,7 @@
 static int ocfs2_split_and_insert(struct inode *inode,
 				  handle_t *handle,
 				  struct ocfs2_path *path,
-				  struct buffer_head *di_bh,
+				  struct ocfs2_extent_tree *et,
 				  struct buffer_head **last_eb_bh,
 				  int split_index,
 				  struct ocfs2_extent_rec *orig_split_rec,
@@ -4215,7 +4610,6 @@
 	struct ocfs2_extent_rec split_rec = *orig_split_rec;
 	struct ocfs2_insert_type insert;
 	struct ocfs2_extent_block *eb;
-	struct ocfs2_dinode *di;
 
 leftright:
 	/*
@@ -4224,8 +4618,7 @@
 	 */
 	rec = path_leaf_el(path)->l_recs[split_index];
 
-	di = (struct ocfs2_dinode *)di_bh->b_data;
-	rightmost_el = &di->id2.i_list;
+	rightmost_el = et->et_root_el;
 
 	depth = le16_to_cpu(rightmost_el->l_tree_depth);
 	if (depth) {
@@ -4236,8 +4629,8 @@
 
 	if (le16_to_cpu(rightmost_el->l_next_free_rec) ==
 	    le16_to_cpu(rightmost_el->l_count)) {
-		ret = ocfs2_grow_tree(inode, handle, di_bh, &depth, last_eb_bh,
-				      meta_ac);
+		ret = ocfs2_grow_tree(inode, handle, et,
+				      &depth, last_eb_bh, meta_ac);
 		if (ret) {
 			mlog_errno(ret);
 			goto out;
@@ -4274,8 +4667,7 @@
 		do_leftright = 1;
 	}
 
-	ret = ocfs2_do_insert_extent(inode, handle, di_bh, &split_rec,
-				     &insert);
+	ret = ocfs2_do_insert_extent(inode, handle, et, &split_rec, &insert);
 	if (ret) {
 		mlog_errno(ret);
 		goto out;
@@ -4317,8 +4709,9 @@
  * of the tree is required. All other cases will degrade into a less
  * optimal tree layout.
  *
- * last_eb_bh should be the rightmost leaf block for any inode with a
- * btree. Since a split may grow the tree or a merge might shrink it, the caller cannot trust the contents of that buffer after this call.
+ * last_eb_bh should be the rightmost leaf block for any extent
+ * btree. Since a split may grow the tree or a merge might shrink it,
+ * the caller cannot trust the contents of that buffer after this call.
  *
  * This code is optimized for readability - several passes might be
  * made over certain portions of the tree. All of those blocks will
@@ -4326,7 +4719,7 @@
  * extra overhead is not expressed in terms of disk reads.
  */
 static int __ocfs2_mark_extent_written(struct inode *inode,
-				       struct buffer_head *di_bh,
+				       struct ocfs2_extent_tree *et,
 				       handle_t *handle,
 				       struct ocfs2_path *path,
 				       int split_index,
@@ -4366,11 +4759,9 @@
 	 */
 	if (path->p_tree_depth) {
 		struct ocfs2_extent_block *eb;
-		struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data;
 
-		ret = ocfs2_read_block(OCFS2_SB(inode->i_sb),
-				       le64_to_cpu(di->i_last_eb_blk),
-				       &last_eb_bh, OCFS2_BH_CACHED, inode);
+		ret = ocfs2_read_block(inode, ocfs2_et_get_last_eb_blk(et),
+				       &last_eb_bh);
 		if (ret) {
 			mlog_exit(ret);
 			goto out;
@@ -4403,7 +4794,7 @@
 		if (ctxt.c_split_covers_rec)
 			el->l_recs[split_index] = *split_rec;
 		else
-			ret = ocfs2_split_and_insert(inode, handle, path, di_bh,
+			ret = ocfs2_split_and_insert(inode, handle, path, et,
 						     &last_eb_bh, split_index,
 						     split_rec, meta_ac);
 		if (ret)
@@ -4411,7 +4802,7 @@
 	} else {
 		ret = ocfs2_try_to_merge_extent(inode, handle, path,
 						split_index, split_rec,
-						dealloc, &ctxt);
+						dealloc, &ctxt, et);
 		if (ret)
 			mlog_errno(ret);
 	}
@@ -4429,7 +4820,8 @@
  *
  * The caller is responsible for passing down meta_ac if we'll need it.
  */
-int ocfs2_mark_extent_written(struct inode *inode, struct buffer_head *di_bh,
+int ocfs2_mark_extent_written(struct inode *inode,
+			      struct ocfs2_extent_tree *et,
 			      handle_t *handle, u32 cpos, u32 len, u32 phys,
 			      struct ocfs2_alloc_context *meta_ac,
 			      struct ocfs2_cached_dealloc_ctxt *dealloc)
@@ -4455,10 +4847,14 @@
 	/*
 	 * XXX: This should be fixed up so that we just re-insert the
 	 * next extent records.
+	 *
+	 * XXX: This is a hack on the extent tree, maybe it should be
+	 * an op?
 	 */
-	ocfs2_extent_map_trunc(inode, 0);
+	if (et->et_ops == &ocfs2_dinode_et_ops)
+		ocfs2_extent_map_trunc(inode, 0);
 
-	left_path = ocfs2_new_inode_path(di_bh);
+	left_path = ocfs2_new_path(et->et_root_bh, et->et_root_el);
 	if (!left_path) {
 		ret = -ENOMEM;
 		mlog_errno(ret);
@@ -4489,8 +4885,9 @@
 	split_rec.e_flags = path_leaf_el(left_path)->l_recs[index].e_flags;
 	split_rec.e_flags &= ~OCFS2_EXT_UNWRITTEN;
 
-	ret = __ocfs2_mark_extent_written(inode, di_bh, handle, left_path,
-					  index, &split_rec, meta_ac, dealloc);
+	ret = __ocfs2_mark_extent_written(inode, et, handle, left_path,
+					  index, &split_rec, meta_ac,
+					  dealloc);
 	if (ret)
 		mlog_errno(ret);
 
@@ -4499,13 +4896,12 @@
 	return ret;
 }
 
-static int ocfs2_split_tree(struct inode *inode, struct buffer_head *di_bh,
+static int ocfs2_split_tree(struct inode *inode, struct ocfs2_extent_tree *et,
 			    handle_t *handle, struct ocfs2_path *path,
 			    int index, u32 new_range,
 			    struct ocfs2_alloc_context *meta_ac)
 {
 	int ret, depth, credits = handle->h_buffer_credits;
-	struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data;
 	struct buffer_head *last_eb_bh = NULL;
 	struct ocfs2_extent_block *eb;
 	struct ocfs2_extent_list *rightmost_el, *el;
@@ -4522,9 +4918,8 @@
 
 	depth = path->p_tree_depth;
 	if (depth > 0) {
-		ret = ocfs2_read_block(OCFS2_SB(inode->i_sb),
-				       le64_to_cpu(di->i_last_eb_blk),
-				       &last_eb_bh, OCFS2_BH_CACHED, inode);
+		ret = ocfs2_read_block(inode, ocfs2_et_get_last_eb_blk(et),
+				       &last_eb_bh);
 		if (ret < 0) {
 			mlog_errno(ret);
 			goto out;
@@ -4535,7 +4930,8 @@
 	} else
 		rightmost_el = path_leaf_el(path);
 
-	credits += path->p_tree_depth + ocfs2_extend_meta_needed(di);
+	credits += path->p_tree_depth +
+		   ocfs2_extend_meta_needed(et->et_root_el);
 	ret = ocfs2_extend_trans(handle, credits);
 	if (ret) {
 		mlog_errno(ret);
@@ -4544,7 +4940,7 @@
 
 	if (le16_to_cpu(rightmost_el->l_next_free_rec) ==
 	    le16_to_cpu(rightmost_el->l_count)) {
-		ret = ocfs2_grow_tree(inode, handle, di_bh, &depth, &last_eb_bh,
+		ret = ocfs2_grow_tree(inode, handle, et, &depth, &last_eb_bh,
 				      meta_ac);
 		if (ret) {
 			mlog_errno(ret);
@@ -4558,7 +4954,7 @@
 	insert.ins_split = SPLIT_RIGHT;
 	insert.ins_tree_depth = depth;
 
-	ret = ocfs2_do_insert_extent(inode, handle, di_bh, &split_rec, &insert);
+	ret = ocfs2_do_insert_extent(inode, handle, et, &split_rec, &insert);
 	if (ret)
 		mlog_errno(ret);
 
@@ -4570,7 +4966,8 @@
 static int ocfs2_truncate_rec(struct inode *inode, handle_t *handle,
 			      struct ocfs2_path *path, int index,
 			      struct ocfs2_cached_dealloc_ctxt *dealloc,
-			      u32 cpos, u32 len)
+			      u32 cpos, u32 len,
+			      struct ocfs2_extent_tree *et)
 {
 	int ret;
 	u32 left_cpos, rec_range, trunc_range;
@@ -4582,7 +4979,7 @@
 	struct ocfs2_extent_block *eb;
 
 	if (ocfs2_is_empty_extent(&el->l_recs[0]) && index > 0) {
-		ret = ocfs2_rotate_tree_left(inode, handle, path, dealloc);
+		ret = ocfs2_rotate_tree_left(inode, handle, path, dealloc, et);
 		if (ret) {
 			mlog_errno(ret);
 			goto out;
@@ -4713,7 +5110,7 @@
 
 	ocfs2_journal_dirty(handle, path_leaf_bh(path));
 
-	ret = ocfs2_rotate_tree_left(inode, handle, path, dealloc);
+	ret = ocfs2_rotate_tree_left(inode, handle, path, dealloc, et);
 	if (ret) {
 		mlog_errno(ret);
 		goto out;
@@ -4724,7 +5121,8 @@
 	return ret;
 }
 
-int ocfs2_remove_extent(struct inode *inode, struct buffer_head *di_bh,
+int ocfs2_remove_extent(struct inode *inode,
+			struct ocfs2_extent_tree *et,
 			u32 cpos, u32 len, handle_t *handle,
 			struct ocfs2_alloc_context *meta_ac,
 			struct ocfs2_cached_dealloc_ctxt *dealloc)
@@ -4733,11 +5131,11 @@
 	u32 rec_range, trunc_range;
 	struct ocfs2_extent_rec *rec;
 	struct ocfs2_extent_list *el;
-	struct ocfs2_path *path;
+	struct ocfs2_path *path = NULL;
 
 	ocfs2_extent_map_trunc(inode, 0);
 
-	path = ocfs2_new_inode_path(di_bh);
+	path = ocfs2_new_path(et->et_root_bh, et->et_root_el);
 	if (!path) {
 		ret = -ENOMEM;
 		mlog_errno(ret);
@@ -4790,13 +5188,13 @@
 
 	if (le32_to_cpu(rec->e_cpos) == cpos || rec_range == trunc_range) {
 		ret = ocfs2_truncate_rec(inode, handle, path, index, dealloc,
-					 cpos, len);
+					 cpos, len, et);
 		if (ret) {
 			mlog_errno(ret);
 			goto out;
 		}
 	} else {
-		ret = ocfs2_split_tree(inode, di_bh, handle, path, index,
+		ret = ocfs2_split_tree(inode, et, handle, path, index,
 				       trunc_range, meta_ac);
 		if (ret) {
 			mlog_errno(ret);
@@ -4845,7 +5243,7 @@
 		}
 
 		ret = ocfs2_truncate_rec(inode, handle, path, index, dealloc,
-					 cpos, len);
+					 cpos, len, et);
 		if (ret) {
 			mlog_errno(ret);
 			goto out;
@@ -5188,8 +5586,7 @@
 		goto bail;
 	}
 
-	status = ocfs2_read_block(osb, OCFS2_I(inode)->ip_blkno, &bh,
-				  OCFS2_BH_CACHED, inode);
+	status = ocfs2_read_block(inode, OCFS2_I(inode)->ip_blkno, &bh);
 	if (status < 0) {
 		iput(inode);
 		mlog_errno(status);
@@ -5264,8 +5661,7 @@
 bail:
 	if (tl_inode)
 		iput(tl_inode);
-	if (tl_bh)
-		brelse(tl_bh);
+	brelse(tl_bh);
 
 	if (status < 0 && (*tl_copy)) {
 		kfree(*tl_copy);
@@ -6008,20 +6404,13 @@
 	return status;
 }
 
-static int ocfs2_writeback_zero_func(handle_t *handle, struct buffer_head *bh)
+static int ocfs2_zero_func(handle_t *handle, struct buffer_head *bh)
 {
 	set_buffer_uptodate(bh);
 	mark_buffer_dirty(bh);
 	return 0;
 }
 
-static int ocfs2_ordered_zero_func(handle_t *handle, struct buffer_head *bh)
-{
-	set_buffer_uptodate(bh);
-	mark_buffer_dirty(bh);
-	return ocfs2_journal_dirty_data(handle, bh);
-}
-
 static void ocfs2_map_and_dirty_page(struct inode *inode, handle_t *handle,
 				     unsigned int from, unsigned int to,
 				     struct page *page, int zero, u64 *phys)
@@ -6040,17 +6429,18 @@
 	 * here if they aren't - ocfs2_map_page_blocks()
 	 * might've skipped some
 	 */
-	if (ocfs2_should_order_data(inode)) {
-		ret = walk_page_buffers(handle,
-					page_buffers(page),
-					from, to, &partial,
-					ocfs2_ordered_zero_func);
-		if (ret < 0)
-			mlog_errno(ret);
-	} else {
+	ret = walk_page_buffers(handle, page_buffers(page),
+				from, to, &partial,
+				ocfs2_zero_func);
+	if (ret < 0)
+		mlog_errno(ret);
+	else if (ocfs2_should_order_data(inode)) {
+		ret = ocfs2_jbd2_file_inode(handle, inode);
+#ifdef CONFIG_OCFS2_COMPAT_JBD
 		ret = walk_page_buffers(handle, page_buffers(page),
 					from, to, &partial,
-					ocfs2_writeback_zero_func);
+					ocfs2_journal_dirty_data);
+#endif
 		if (ret < 0)
 			mlog_errno(ret);
 	}
@@ -6215,20 +6605,29 @@
 	return ret;
 }
 
-static void ocfs2_zero_dinode_id2(struct inode *inode, struct ocfs2_dinode *di)
+static void ocfs2_zero_dinode_id2_with_xattr(struct inode *inode,
+					     struct ocfs2_dinode *di)
 {
 	unsigned int blocksize = 1 << inode->i_sb->s_blocksize_bits;
+	unsigned int xattrsize = le16_to_cpu(di->i_xattr_inline_size);
 
-	memset(&di->id2, 0, blocksize - offsetof(struct ocfs2_dinode, id2));
+	if (le16_to_cpu(di->i_dyn_features) & OCFS2_INLINE_XATTR_FL)
+		memset(&di->id2, 0, blocksize -
+				    offsetof(struct ocfs2_dinode, id2) -
+				    xattrsize);
+	else
+		memset(&di->id2, 0, blocksize -
+				    offsetof(struct ocfs2_dinode, id2));
 }
 
 void ocfs2_dinode_new_extent_list(struct inode *inode,
 				  struct ocfs2_dinode *di)
 {
-	ocfs2_zero_dinode_id2(inode, di);
+	ocfs2_zero_dinode_id2_with_xattr(inode, di);
 	di->id2.i_list.l_tree_depth = 0;
 	di->id2.i_list.l_next_free_rec = 0;
-	di->id2.i_list.l_count = cpu_to_le16(ocfs2_extent_recs_per_inode(inode->i_sb));
+	di->id2.i_list.l_count = cpu_to_le16(
+		ocfs2_extent_recs_per_inode_with_xattr(inode->i_sb, di));
 }
 
 void ocfs2_set_inode_data_inline(struct inode *inode, struct ocfs2_dinode *di)
@@ -6245,9 +6644,10 @@
 	 * We clear the entire i_data structure here so that all
 	 * fields can be properly initialized.
 	 */
-	ocfs2_zero_dinode_id2(inode, di);
+	ocfs2_zero_dinode_id2_with_xattr(inode, di);
 
-	idata->id_count = cpu_to_le16(ocfs2_max_inline_data(inode->i_sb));
+	idata->id_count = cpu_to_le16(
+			ocfs2_max_inline_data_with_xattr(inode->i_sb, di));
 }
 
 int ocfs2_convert_inline_data_to_extents(struct inode *inode,
@@ -6262,6 +6662,7 @@
 	struct ocfs2_alloc_context *data_ac = NULL;
 	struct page **pages = NULL;
 	loff_t end = osb->s_clustersize;
+	struct ocfs2_extent_tree et;
 
 	has_data = i_size_read(inode) ? 1 : 0;
 
@@ -6361,7 +6762,8 @@
 		 * this proves to be false, we could always re-build
 		 * the in-inode data from our pages.
 		 */
-		ret = ocfs2_insert_extent(osb, handle, inode, di_bh,
+		ocfs2_init_dinode_extent_tree(&et, inode, di_bh);
+		ret = ocfs2_insert_extent(osb, handle, inode, &et,
 					  0, block, 1, 0, NULL);
 		if (ret) {
 			mlog_errno(ret);
@@ -6404,13 +6806,14 @@
 	handle_t *handle = NULL;
 	struct inode *tl_inode = osb->osb_tl_inode;
 	struct ocfs2_path *path = NULL;
+	struct ocfs2_dinode *di = (struct ocfs2_dinode *)fe_bh->b_data;
 
 	mlog_entry_void();
 
 	new_highest_cpos = ocfs2_clusters_for_bytes(osb->sb,
 						     i_size_read(inode));
 
-	path = ocfs2_new_inode_path(fe_bh);
+	path = ocfs2_new_path(fe_bh, &di->id2.i_list);
 	if (!path) {
 		status = -ENOMEM;
 		mlog_errno(status);
@@ -6581,8 +6984,8 @@
 	ocfs2_init_dealloc_ctxt(&(*tc)->tc_dealloc);
 
 	if (fe->id2.i_list.l_tree_depth) {
-		status = ocfs2_read_block(osb, le64_to_cpu(fe->i_last_eb_blk),
-					  &last_eb_bh, OCFS2_BH_CACHED, inode);
+		status = ocfs2_read_block(inode, le64_to_cpu(fe->i_last_eb_blk),
+					  &last_eb_bh);
 		if (status < 0) {
 			mlog_errno(status);
 			goto bail;
@@ -6695,8 +7098,7 @@
 		mlog(ML_NOTICE,
 		     "Truncate completion has non-empty dealloc context\n");
 
-	if (tc->tc_last_eb_bh)
-		brelse(tc->tc_last_eb_bh);
+	brelse(tc->tc_last_eb_bh);
 
 	kfree(tc);
 }
diff --git a/fs/ocfs2/alloc.h b/fs/ocfs2/alloc.h
index 42ff94b..70257c8 100644
--- a/fs/ocfs2/alloc.h
+++ b/fs/ocfs2/alloc.h
@@ -26,30 +26,102 @@
 #ifndef OCFS2_ALLOC_H
 #define OCFS2_ALLOC_H
 
+
+/*
+ * For xattr tree leaf, we limit the leaf byte size to be 64K.
+ */
+#define OCFS2_MAX_XATTR_TREE_LEAF_SIZE 65536
+
+/*
+ * ocfs2_extent_tree and ocfs2_extent_tree_operations are used to abstract
+ * the b-tree operations in ocfs2. Now all the b-tree operations are not
+ * limited to ocfs2_dinode only. Any data which need to allocate clusters
+ * to store can use b-tree. And it only needs to implement its ocfs2_extent_tree
+ * and operation.
+ *
+ * ocfs2_extent_tree becomes the first-class object for extent tree
+ * manipulation.  Callers of the alloc.c code need to fill it via one of
+ * the ocfs2_init_*_extent_tree() operations below.
+ *
+ * ocfs2_extent_tree contains info for the root of the b-tree, it must have a
+ * root ocfs2_extent_list and a root_bh so that they can be used in the b-tree
+ * functions.
+ * ocfs2_extent_tree_operations abstract the normal operations we do for
+ * the root of extent b-tree.
+ */
+struct ocfs2_extent_tree_operations;
+struct ocfs2_extent_tree {
+	struct ocfs2_extent_tree_operations	*et_ops;
+	struct buffer_head			*et_root_bh;
+	struct ocfs2_extent_list		*et_root_el;
+	void					*et_object;
+	unsigned int				et_max_leaf_clusters;
+};
+
+/*
+ * ocfs2_init_*_extent_tree() will fill an ocfs2_extent_tree from the
+ * specified object buffer.
+ */
+void ocfs2_init_dinode_extent_tree(struct ocfs2_extent_tree *et,
+				   struct inode *inode,
+				   struct buffer_head *bh);
+void ocfs2_init_xattr_tree_extent_tree(struct ocfs2_extent_tree *et,
+				       struct inode *inode,
+				       struct buffer_head *bh);
+void ocfs2_init_xattr_value_extent_tree(struct ocfs2_extent_tree *et,
+					struct inode *inode,
+					struct buffer_head *bh,
+					struct ocfs2_xattr_value_root *xv);
+
 struct ocfs2_alloc_context;
 int ocfs2_insert_extent(struct ocfs2_super *osb,
 			handle_t *handle,
 			struct inode *inode,
-			struct buffer_head *fe_bh,
+			struct ocfs2_extent_tree *et,
 			u32 cpos,
 			u64 start_blk,
 			u32 new_clusters,
 			u8 flags,
 			struct ocfs2_alloc_context *meta_ac);
+
+enum ocfs2_alloc_restarted {
+	RESTART_NONE = 0,
+	RESTART_TRANS,
+	RESTART_META
+};
+int ocfs2_add_clusters_in_btree(struct ocfs2_super *osb,
+				struct inode *inode,
+				u32 *logical_offset,
+				u32 clusters_to_add,
+				int mark_unwritten,
+				struct ocfs2_extent_tree *et,
+				handle_t *handle,
+				struct ocfs2_alloc_context *data_ac,
+				struct ocfs2_alloc_context *meta_ac,
+				enum ocfs2_alloc_restarted *reason_ret);
 struct ocfs2_cached_dealloc_ctxt;
-int ocfs2_mark_extent_written(struct inode *inode, struct buffer_head *di_bh,
+int ocfs2_mark_extent_written(struct inode *inode,
+			      struct ocfs2_extent_tree *et,
 			      handle_t *handle, u32 cpos, u32 len, u32 phys,
 			      struct ocfs2_alloc_context *meta_ac,
 			      struct ocfs2_cached_dealloc_ctxt *dealloc);
-int ocfs2_remove_extent(struct inode *inode, struct buffer_head *di_bh,
+int ocfs2_remove_extent(struct inode *inode,
+			struct ocfs2_extent_tree *et,
 			u32 cpos, u32 len, handle_t *handle,
 			struct ocfs2_alloc_context *meta_ac,
 			struct ocfs2_cached_dealloc_ctxt *dealloc);
 int ocfs2_num_free_extents(struct ocfs2_super *osb,
 			   struct inode *inode,
-			   struct ocfs2_dinode *fe);
-/* how many new metadata chunks would an allocation need at maximum? */
-static inline int ocfs2_extend_meta_needed(struct ocfs2_dinode *fe)
+			   struct ocfs2_extent_tree *et);
+
+/*
+ * how many new metadata chunks would an allocation need at maximum?
+ *
+ * Please note that the caller must make sure that root_el is the root
+ * of extent tree. So for an inode, it should be &fe->id2.i_list. Otherwise
+ * the result may be wrong.
+ */
+static inline int ocfs2_extend_meta_needed(struct ocfs2_extent_list *root_el)
 {
 	/*
 	 * Rather than do all the work of determining how much we need
@@ -59,7 +131,7 @@
 	 * new tree_depth==0 extent_block, and one block at the new
 	 * top-of-the tree.
 	 */
-	return le16_to_cpu(fe->id2.i_list.l_tree_depth) + 2;
+	return le16_to_cpu(root_el->l_tree_depth) + 2;
 }
 
 void ocfs2_dinode_new_extent_list(struct inode *inode, struct ocfs2_dinode *di);
@@ -146,4 +218,13 @@
 		return le16_to_cpu(rec->e_leaf_clusters);
 }
 
+/*
+ * This is only valid for leaf nodes, which are the only ones that can
+ * have empty extents anyway.
+ */
+static inline int ocfs2_is_empty_extent(struct ocfs2_extent_rec *rec)
+{
+	return !rec->e_leaf_clusters;
+}
+
 #endif /* OCFS2_ALLOC_H */
diff --git a/fs/ocfs2/aops.c b/fs/ocfs2/aops.c
index a53da14..c22543b 100644
--- a/fs/ocfs2/aops.c
+++ b/fs/ocfs2/aops.c
@@ -68,9 +68,7 @@
 		goto bail;
 	}
 
-	status = ocfs2_read_block(OCFS2_SB(inode->i_sb),
-				  OCFS2_I(inode)->ip_blkno,
-				  &bh, OCFS2_BH_CACHED, inode);
+	status = ocfs2_read_block(inode, OCFS2_I(inode)->ip_blkno, &bh);
 	if (status < 0) {
 		mlog_errno(status);
 		goto bail;
@@ -128,8 +126,7 @@
 	err = 0;
 
 bail:
-	if (bh)
-		brelse(bh);
+	brelse(bh);
 
 	mlog_exit(err);
 	return err;
@@ -261,13 +258,11 @@
 {
 	int ret;
 	struct buffer_head *di_bh = NULL;
-	struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
 
 	BUG_ON(!PageLocked(page));
 	BUG_ON(!(OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL));
 
-	ret = ocfs2_read_block(osb, OCFS2_I(inode)->ip_blkno, &di_bh,
-			       OCFS2_BH_CACHED, inode);
+	ret = ocfs2_read_block(inode, OCFS2_I(inode)->ip_blkno, &di_bh);
 	if (ret) {
 		mlog_errno(ret);
 		goto out;
@@ -485,11 +480,14 @@
 	}
 
 	if (ocfs2_should_order_data(inode)) {
+		ret = ocfs2_jbd2_file_inode(handle, inode);
+#ifdef CONFIG_OCFS2_COMPAT_JBD
 		ret = walk_page_buffers(handle,
 					page_buffers(page),
 					from, to, NULL,
 					ocfs2_journal_dirty_data);
-		if (ret < 0) 
+#endif
+		if (ret < 0)
 			mlog_errno(ret);
 	}
 out:
@@ -669,7 +667,7 @@
 {
 	journal_t *journal = OCFS2_SB(page->mapping->host->i_sb)->journal->j_journal;
 
-	journal_invalidatepage(journal, page, offset);
+	jbd2_journal_invalidatepage(journal, page, offset);
 }
 
 static int ocfs2_releasepage(struct page *page, gfp_t wait)
@@ -678,7 +676,7 @@
 
 	if (!page_has_buffers(page))
 		return 0;
-	return journal_try_to_free_buffers(journal, page, wait);
+	return jbd2_journal_try_to_free_buffers(journal, page, wait);
 }
 
 static ssize_t ocfs2_direct_IO(int rw,
@@ -1074,11 +1072,15 @@
 		tmppage = wc->w_pages[i];
 
 		if (page_has_buffers(tmppage)) {
-			if (ocfs2_should_order_data(inode))
+			if (ocfs2_should_order_data(inode)) {
+				ocfs2_jbd2_file_inode(wc->w_handle, inode);
+#ifdef CONFIG_OCFS2_COMPAT_JBD
 				walk_page_buffers(wc->w_handle,
 						  page_buffers(tmppage),
 						  from, to, NULL,
 						  ocfs2_journal_dirty_data);
+#endif
+			}
 
 			block_commit_write(tmppage, from, to);
 		}
@@ -1242,6 +1244,7 @@
 	int ret, i, new, should_zero = 0;
 	u64 v_blkno, p_blkno;
 	struct inode *inode = mapping->host;
+	struct ocfs2_extent_tree et;
 
 	new = phys == 0 ? 1 : 0;
 	if (new || unwritten)
@@ -1255,10 +1258,10 @@
 		 * any additional semaphores or cluster locks.
 		 */
 		tmp_pos = cpos;
-		ret = ocfs2_do_extend_allocation(OCFS2_SB(inode->i_sb), inode,
-						 &tmp_pos, 1, 0, wc->w_di_bh,
-						 wc->w_handle, data_ac,
-						 meta_ac, NULL);
+		ret = ocfs2_add_inode_data(OCFS2_SB(inode->i_sb), inode,
+					   &tmp_pos, 1, 0, wc->w_di_bh,
+					   wc->w_handle, data_ac,
+					   meta_ac, NULL);
 		/*
 		 * This shouldn't happen because we must have already
 		 * calculated the correct meta data allocation required. The
@@ -1276,7 +1279,8 @@
 			goto out;
 		}
 	} else if (unwritten) {
-		ret = ocfs2_mark_extent_written(inode, wc->w_di_bh,
+		ocfs2_init_dinode_extent_tree(&et, inode, wc->w_di_bh);
+		ret = ocfs2_mark_extent_written(inode, &et,
 						wc->w_handle, cpos, 1, phys,
 						meta_ac, &wc->w_dealloc);
 		if (ret < 0) {
@@ -1665,6 +1669,7 @@
 	struct ocfs2_alloc_context *data_ac = NULL;
 	struct ocfs2_alloc_context *meta_ac = NULL;
 	handle_t *handle;
+	struct ocfs2_extent_tree et;
 
 	ret = ocfs2_alloc_write_ctxt(&wc, osb, pos, len, di_bh);
 	if (ret) {
@@ -1712,14 +1717,23 @@
 		 * ocfs2_lock_allocators(). It greatly over-estimates
 		 * the work to be done.
 		 */
-		ret = ocfs2_lock_allocators(inode, di, clusters_to_alloc,
-					    extents_to_split, &data_ac, &meta_ac);
+		mlog(0, "extend inode %llu, i_size = %lld, di->i_clusters = %u,"
+		     " clusters_to_add = %u, extents_to_split = %u\n",
+		     (unsigned long long)OCFS2_I(inode)->ip_blkno,
+		     (long long)i_size_read(inode), le32_to_cpu(di->i_clusters),
+		     clusters_to_alloc, extents_to_split);
+
+		ocfs2_init_dinode_extent_tree(&et, inode, wc->w_di_bh);
+		ret = ocfs2_lock_allocators(inode, &et,
+					    clusters_to_alloc, extents_to_split,
+					    &data_ac, &meta_ac);
 		if (ret) {
 			mlog_errno(ret);
 			goto out;
 		}
 
-		credits = ocfs2_calc_extend_credits(inode->i_sb, di,
+		credits = ocfs2_calc_extend_credits(inode->i_sb,
+						    &di->id2.i_list,
 						    clusters_to_alloc);
 
 	}
@@ -1905,11 +1919,15 @@
 		}
 
 		if (page_has_buffers(tmppage)) {
-			if (ocfs2_should_order_data(inode))
+			if (ocfs2_should_order_data(inode)) {
+				ocfs2_jbd2_file_inode(wc->w_handle, inode);
+#ifdef CONFIG_OCFS2_COMPAT_JBD
 				walk_page_buffers(wc->w_handle,
 						  page_buffers(tmppage),
 						  from, to, NULL,
 						  ocfs2_journal_dirty_data);
+#endif
+			}
 			block_commit_write(tmppage, from, to);
 		}
 	}
diff --git a/fs/ocfs2/buffer_head_io.c b/fs/ocfs2/buffer_head_io.c
index f136639..7e947c6 100644
--- a/fs/ocfs2/buffer_head_io.c
+++ b/fs/ocfs2/buffer_head_io.c
@@ -66,7 +66,7 @@
 	/* remove from dirty list before I/O. */
 	clear_buffer_dirty(bh);
 
-	get_bh(bh); /* for end_buffer_write_sync() */                   
+	get_bh(bh); /* for end_buffer_write_sync() */
 	bh->b_end_io = end_buffer_write_sync;
 	submit_bh(WRITE, bh);
 
@@ -88,22 +88,103 @@
 	return ret;
 }
 
-int ocfs2_read_blocks(struct ocfs2_super *osb, u64 block, int nr,
-		      struct buffer_head *bhs[], int flags,
-		      struct inode *inode)
+int ocfs2_read_blocks_sync(struct ocfs2_super *osb, u64 block,
+			   unsigned int nr, struct buffer_head *bhs[])
 {
 	int status = 0;
-	struct super_block *sb;
+	unsigned int i;
+	struct buffer_head *bh;
+
+	if (!nr) {
+		mlog(ML_BH_IO, "No buffers will be read!\n");
+		goto bail;
+	}
+
+	for (i = 0 ; i < nr ; i++) {
+		if (bhs[i] == NULL) {
+			bhs[i] = sb_getblk(osb->sb, block++);
+			if (bhs[i] == NULL) {
+				status = -EIO;
+				mlog_errno(status);
+				goto bail;
+			}
+		}
+		bh = bhs[i];
+
+		if (buffer_jbd(bh)) {
+			mlog(ML_ERROR,
+			     "trying to sync read a jbd "
+			     "managed bh (blocknr = %llu), skipping\n",
+			     (unsigned long long)bh->b_blocknr);
+			continue;
+		}
+
+		if (buffer_dirty(bh)) {
+			/* This should probably be a BUG, or
+			 * at least return an error. */
+			mlog(ML_ERROR,
+			     "trying to sync read a dirty "
+			     "buffer! (blocknr = %llu), skipping\n",
+			     (unsigned long long)bh->b_blocknr);
+			continue;
+		}
+
+		lock_buffer(bh);
+		if (buffer_jbd(bh)) {
+			mlog(ML_ERROR,
+			     "block %llu had the JBD bit set "
+			     "while I was in lock_buffer!",
+			     (unsigned long long)bh->b_blocknr);
+			BUG();
+		}
+
+		clear_buffer_uptodate(bh);
+		get_bh(bh); /* for end_buffer_read_sync() */
+		bh->b_end_io = end_buffer_read_sync;
+		submit_bh(READ, bh);
+	}
+
+	for (i = nr; i > 0; i--) {
+		bh = bhs[i - 1];
+
+		if (buffer_jbd(bh)) {
+			mlog(ML_ERROR,
+			     "the journal got the buffer while it was "
+			     "locked for io! (blocknr = %llu)\n",
+			     (unsigned long long)bh->b_blocknr);
+			BUG();
+		}
+
+		wait_on_buffer(bh);
+		if (!buffer_uptodate(bh)) {
+			/* Status won't be cleared from here on out,
+			 * so we can safely record this and loop back
+			 * to cleanup the other buffers. */
+			status = -EIO;
+			put_bh(bh);
+			bhs[i - 1] = NULL;
+		}
+	}
+
+bail:
+	return status;
+}
+
+int ocfs2_read_blocks(struct inode *inode, u64 block, int nr,
+		      struct buffer_head *bhs[], int flags)
+{
+	int status = 0;
 	int i, ignore_cache = 0;
 	struct buffer_head *bh;
 
-	mlog_entry("(block=(%llu), nr=(%d), flags=%d, inode=%p)\n",
-		   (unsigned long long)block, nr, flags, inode);
+	mlog_entry("(inode=%p, block=(%llu), nr=(%d), flags=%d)\n",
+		   inode, (unsigned long long)block, nr, flags);
 
+	BUG_ON(!inode);
 	BUG_ON((flags & OCFS2_BH_READAHEAD) &&
-	       (!inode || !(flags & OCFS2_BH_CACHED)));
+	       (flags & OCFS2_BH_IGNORE_CACHE));
 
-	if (osb == NULL || osb->sb == NULL || bhs == NULL) {
+	if (bhs == NULL) {
 		status = -EINVAL;
 		mlog_errno(status);
 		goto bail;
@@ -122,26 +203,19 @@
 		goto bail;
 	}
 
-	sb = osb->sb;
-
-	if (flags & OCFS2_BH_CACHED && !inode)
-		flags &= ~OCFS2_BH_CACHED;
-
-	if (inode)
-		mutex_lock(&OCFS2_I(inode)->ip_io_mutex);
+	mutex_lock(&OCFS2_I(inode)->ip_io_mutex);
 	for (i = 0 ; i < nr ; i++) {
 		if (bhs[i] == NULL) {
-			bhs[i] = sb_getblk(sb, block++);
+			bhs[i] = sb_getblk(inode->i_sb, block++);
 			if (bhs[i] == NULL) {
-				if (inode)
-					mutex_unlock(&OCFS2_I(inode)->ip_io_mutex);
+				mutex_unlock(&OCFS2_I(inode)->ip_io_mutex);
 				status = -EIO;
 				mlog_errno(status);
 				goto bail;
 			}
 		}
 		bh = bhs[i];
-		ignore_cache = 0;
+		ignore_cache = (flags & OCFS2_BH_IGNORE_CACHE);
 
 		/* There are three read-ahead cases here which we need to
 		 * be concerned with. All three assume a buffer has
@@ -167,26 +241,27 @@
 		 *    before our is-it-in-flight check.
 		 */
 
-		if (flags & OCFS2_BH_CACHED &&
-		    !ocfs2_buffer_uptodate(inode, bh)) {
+		if (!ignore_cache && !ocfs2_buffer_uptodate(inode, bh)) {
 			mlog(ML_UPTODATE,
 			     "bh (%llu), inode %llu not uptodate\n",
 			     (unsigned long long)bh->b_blocknr,
 			     (unsigned long long)OCFS2_I(inode)->ip_blkno);
+			/* We're using ignore_cache here to say
+			 * "go to disk" */
 			ignore_cache = 1;
 		}
 
 		/* XXX: Can we ever get this and *not* have the cached
 		 * flag set? */
 		if (buffer_jbd(bh)) {
-			if (!(flags & OCFS2_BH_CACHED) || ignore_cache)
+			if (ignore_cache)
 				mlog(ML_BH_IO, "trying to sync read a jbd "
 					       "managed bh (blocknr = %llu)\n",
 				     (unsigned long long)bh->b_blocknr);
 			continue;
 		}
 
-		if (!(flags & OCFS2_BH_CACHED) || ignore_cache) {
+		if (ignore_cache) {
 			if (buffer_dirty(bh)) {
 				/* This should probably be a BUG, or
 				 * at least return an error. */
@@ -221,7 +296,7 @@
 			 * previously read-ahead buffer may have
 			 * completed I/O while we were waiting for the
 			 * buffer lock. */
-			if ((flags & OCFS2_BH_CACHED)
+			if (!(flags & OCFS2_BH_IGNORE_CACHE)
 			    && !(flags & OCFS2_BH_READAHEAD)
 			    && ocfs2_buffer_uptodate(inode, bh)) {
 				unlock_buffer(bh);
@@ -265,15 +340,14 @@
 		/* Always set the buffer in the cache, even if it was
 		 * a forced read, or read-ahead which hasn't yet
 		 * completed. */
-		if (inode)
-			ocfs2_set_buffer_uptodate(inode, bh);
+		ocfs2_set_buffer_uptodate(inode, bh);
 	}
-	if (inode)
-		mutex_unlock(&OCFS2_I(inode)->ip_io_mutex);
+	mutex_unlock(&OCFS2_I(inode)->ip_io_mutex);
 
 	mlog(ML_BH_IO, "block=(%llu), nr=(%d), cached=%s, flags=0x%x\n", 
 	     (unsigned long long)block, nr,
-	     (!(flags & OCFS2_BH_CACHED) || ignore_cache) ? "no" : "yes", flags);
+	     ((flags & OCFS2_BH_IGNORE_CACHE) || ignore_cache) ? "no" : "yes",
+	     flags);
 
 bail:
 
diff --git a/fs/ocfs2/buffer_head_io.h b/fs/ocfs2/buffer_head_io.h
index c2e7861..75e1dcb 100644
--- a/fs/ocfs2/buffer_head_io.h
+++ b/fs/ocfs2/buffer_head_io.h
@@ -31,31 +31,29 @@
 void ocfs2_end_buffer_io_sync(struct buffer_head *bh,
 			     int uptodate);
 
-static inline int ocfs2_read_block(struct ocfs2_super          *osb,
+static inline int ocfs2_read_block(struct inode	       *inode,
 				   u64                  off,
-				   struct buffer_head **bh,
-				   int                  flags,
-				   struct inode        *inode);
+				   struct buffer_head **bh);
 
 int ocfs2_write_block(struct ocfs2_super          *osb,
 		      struct buffer_head  *bh,
 		      struct inode        *inode);
-int ocfs2_read_blocks(struct ocfs2_super          *osb,
+int ocfs2_read_blocks(struct inode	  *inode,
 		      u64                  block,
 		      int                  nr,
 		      struct buffer_head  *bhs[],
-		      int                  flags,
-		      struct inode        *inode);
+		      int                  flags);
+int ocfs2_read_blocks_sync(struct ocfs2_super *osb, u64 block,
+			   unsigned int nr, struct buffer_head *bhs[]);
 
 int ocfs2_write_super_or_backup(struct ocfs2_super *osb,
 				struct buffer_head *bh);
 
-#define OCFS2_BH_CACHED            1
+#define OCFS2_BH_IGNORE_CACHE      1
 #define OCFS2_BH_READAHEAD         8
 
-static inline int ocfs2_read_block(struct ocfs2_super * osb, u64 off,
-				   struct buffer_head **bh, int flags,
-				   struct inode *inode)
+static inline int ocfs2_read_block(struct inode *inode, u64 off,
+				   struct buffer_head **bh)
 {
 	int status = 0;
 
@@ -65,8 +63,7 @@
 		goto bail;
 	}
 
-	status = ocfs2_read_blocks(osb, off, 1, bh,
-				   flags, inode);
+	status = ocfs2_read_blocks(inode, off, 1, bh, 0);
 
 bail:
 	return status;
diff --git a/fs/ocfs2/cluster/masklog.c b/fs/ocfs2/cluster/masklog.c
index 23c732f..d8a0cb9 100644
--- a/fs/ocfs2/cluster/masklog.c
+++ b/fs/ocfs2/cluster/masklog.c
@@ -109,6 +109,7 @@
 	define_mask(CONN),
 	define_mask(QUORUM),
 	define_mask(EXPORT),
+	define_mask(XATTR),
 	define_mask(ERROR),
 	define_mask(NOTICE),
 	define_mask(KTHREAD),
diff --git a/fs/ocfs2/cluster/masklog.h b/fs/ocfs2/cluster/masklog.h
index 597e064..57670c6 100644
--- a/fs/ocfs2/cluster/masklog.h
+++ b/fs/ocfs2/cluster/masklog.h
@@ -112,6 +112,7 @@
 #define ML_CONN		0x0000000004000000ULL /* net connection management */
 #define ML_QUORUM	0x0000000008000000ULL /* net connection quorum */
 #define ML_EXPORT	0x0000000010000000ULL /* ocfs2 export operations */
+#define ML_XATTR	0x0000000020000000ULL /* ocfs2 extended attributes */
 /* bits that are infrequently given and frequently matched in the high word */
 #define ML_ERROR	0x0000000100000000ULL /* sent to KERN_ERR */
 #define ML_NOTICE	0x0000000200000000ULL /* setn to KERN_NOTICE */
diff --git a/fs/ocfs2/dir.c b/fs/ocfs2/dir.c
index 9cce563..026e6eb 100644
--- a/fs/ocfs2/dir.c
+++ b/fs/ocfs2/dir.c
@@ -82,6 +82,49 @@
 			       struct ocfs2_alloc_context *meta_ac,
 			       struct buffer_head **new_bh);
 
+static struct buffer_head *ocfs2_bread(struct inode *inode,
+				       int block, int *err, int reada)
+{
+	struct buffer_head *bh = NULL;
+	int tmperr;
+	u64 p_blkno;
+	int readflags = 0;
+
+	if (reada)
+		readflags |= OCFS2_BH_READAHEAD;
+
+	if (((u64)block << inode->i_sb->s_blocksize_bits) >=
+	    i_size_read(inode)) {
+		BUG_ON(!reada);
+		return NULL;
+	}
+
+	down_read(&OCFS2_I(inode)->ip_alloc_sem);
+	tmperr = ocfs2_extent_map_get_blocks(inode, block, &p_blkno, NULL,
+					     NULL);
+	up_read(&OCFS2_I(inode)->ip_alloc_sem);
+	if (tmperr < 0) {
+		mlog_errno(tmperr);
+		goto fail;
+	}
+
+	tmperr = ocfs2_read_blocks(inode, p_blkno, 1, &bh, readflags);
+	if (tmperr < 0)
+		goto fail;
+
+	tmperr = 0;
+
+	*err = 0;
+	return bh;
+
+fail:
+	brelse(bh);
+	bh = NULL;
+
+	*err = -EIO;
+	return NULL;
+}
+
 /*
  * bh passed here can be an inode block or a dir data block, depending
  * on the inode inline data flag.
@@ -188,8 +231,7 @@
 	struct ocfs2_dinode *di;
 	struct ocfs2_inline_data *data;
 
-	ret = ocfs2_read_block(OCFS2_SB(dir->i_sb), OCFS2_I(dir)->ip_blkno,
-			       &di_bh, OCFS2_BH_CACHED, dir);
+	ret = ocfs2_read_block(dir, OCFS2_I(dir)->ip_blkno, &di_bh);
 	if (ret) {
 		mlog_errno(ret);
 		goto out;
@@ -260,14 +302,13 @@
 		}
 		if ((bh = bh_use[ra_ptr++]) == NULL)
 			goto next;
-		wait_on_buffer(bh);
-		if (!buffer_uptodate(bh)) {
-			/* read error, skip block & hope for the best */
+		if (ocfs2_read_block(dir, block, &bh)) {
+			/* read error, skip block & hope for the best.
+			 * ocfs2_read_block() has released the bh. */
 			ocfs2_error(dir->i_sb, "reading directory %llu, "
 				    "offset %lu\n",
 				    (unsigned long long)OCFS2_I(dir)->ip_blkno,
 				    block);
-			brelse(bh);
 			goto next;
 		}
 		i = ocfs2_search_dirblock(bh, dir, name, namelen,
@@ -417,8 +458,7 @@
 	struct ocfs2_dinode *di;
 	struct ocfs2_inline_data *data;
 
-	ret = ocfs2_read_block(OCFS2_SB(dir->i_sb), OCFS2_I(dir)->ip_blkno,
-			       &di_bh, OCFS2_BH_CACHED, dir);
+	ret = ocfs2_read_block(dir, OCFS2_I(dir)->ip_blkno, &di_bh);
 	if (ret) {
 		mlog_errno(ret);
 		goto out;
@@ -596,8 +636,7 @@
 	struct ocfs2_inline_data *data;
 	struct ocfs2_dir_entry *de;
 
-	ret = ocfs2_read_block(OCFS2_SB(inode->i_sb), OCFS2_I(inode)->ip_blkno,
-			       &di_bh, OCFS2_BH_CACHED, inode);
+	ret = ocfs2_read_block(inode, OCFS2_I(inode)->ip_blkno, &di_bh);
 	if (ret) {
 		mlog(ML_ERROR, "Unable to read inode block for dir %llu\n",
 		     (unsigned long long)OCFS2_I(inode)->ip_blkno);
@@ -716,8 +755,7 @@
 			for (i = ra_sectors >> (sb->s_blocksize_bits - 9);
 			     i > 0; i--) {
 				tmp = ocfs2_bread(inode, ++blk, &err, 1);
-				if (tmp)
-					brelse(tmp);
+				brelse(tmp);
 			}
 			last_ra_blk = blk;
 			ra_sectors = 8;
@@ -899,10 +937,8 @@
 leave:
 	if (status < 0) {
 		*dirent = NULL;
-		if (*dirent_bh) {
-			brelse(*dirent_bh);
-			*dirent_bh = NULL;
-		}
+		brelse(*dirent_bh);
+		*dirent_bh = NULL;
 	}
 
 	mlog_exit(status);
@@ -951,8 +987,7 @@
 
 	ret = 0;
 bail:
-	if (dirent_bh)
-		brelse(dirent_bh);
+	brelse(dirent_bh);
 
 	mlog_exit(ret);
 	return ret;
@@ -1127,8 +1162,7 @@
 
 	status = 0;
 bail:
-	if (new_bh)
-		brelse(new_bh);
+	brelse(new_bh);
 
 	mlog_exit(status);
 	return status;
@@ -1192,6 +1226,9 @@
 	struct buffer_head *dirdata_bh = NULL;
 	struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data;
 	handle_t *handle;
+	struct ocfs2_extent_tree et;
+
+	ocfs2_init_dinode_extent_tree(&et, dir, di_bh);
 
 	alloc = ocfs2_clusters_for_bytes(sb, bytes);
 
@@ -1305,8 +1342,8 @@
 	 * This should never fail as our extent list is empty and all
 	 * related blocks have been journaled already.
 	 */
-	ret = ocfs2_insert_extent(osb, handle, dir, di_bh, 0, blkno, len, 0,
-				  NULL);
+	ret = ocfs2_insert_extent(osb, handle, dir, &et, 0, blkno, len,
+				  0, NULL);
 	if (ret) {
 		mlog_errno(ret);
 		goto out_commit;
@@ -1337,8 +1374,8 @@
 		}
 		blkno = ocfs2_clusters_to_blocks(dir->i_sb, bit_off);
 
-		ret = ocfs2_insert_extent(osb, handle, dir, di_bh, 1, blkno,
-					  len, 0, NULL);
+		ret = ocfs2_insert_extent(osb, handle, dir, &et, 1,
+					  blkno, len, 0, NULL);
 		if (ret) {
 			mlog_errno(ret);
 			goto out_commit;
@@ -1383,9 +1420,9 @@
 	if (extend) {
 		u32 offset = OCFS2_I(dir)->ip_clusters;
 
-		status = ocfs2_do_extend_allocation(OCFS2_SB(sb), dir, &offset,
-						    1, 0, parent_fe_bh, handle,
-						    data_ac, meta_ac, NULL);
+		status = ocfs2_add_inode_data(OCFS2_SB(sb), dir, &offset,
+					      1, 0, parent_fe_bh, handle,
+					      data_ac, meta_ac, NULL);
 		BUG_ON(status == -EAGAIN);
 		if (status < 0) {
 			mlog_errno(status);
@@ -1430,12 +1467,14 @@
 	int credits, num_free_extents, drop_alloc_sem = 0;
 	loff_t dir_i_size;
 	struct ocfs2_dinode *fe = (struct ocfs2_dinode *) parent_fe_bh->b_data;
+	struct ocfs2_extent_list *el = &fe->id2.i_list;
 	struct ocfs2_alloc_context *data_ac = NULL;
 	struct ocfs2_alloc_context *meta_ac = NULL;
 	handle_t *handle = NULL;
 	struct buffer_head *new_bh = NULL;
 	struct ocfs2_dir_entry * de;
 	struct super_block *sb = osb->sb;
+	struct ocfs2_extent_tree et;
 
 	mlog_entry_void();
 
@@ -1479,7 +1518,8 @@
 	spin_lock(&OCFS2_I(dir)->ip_lock);
 	if (dir_i_size == ocfs2_clusters_to_bytes(sb, OCFS2_I(dir)->ip_clusters)) {
 		spin_unlock(&OCFS2_I(dir)->ip_lock);
-		num_free_extents = ocfs2_num_free_extents(osb, dir, fe);
+		ocfs2_init_dinode_extent_tree(&et, dir, parent_fe_bh);
+		num_free_extents = ocfs2_num_free_extents(osb, dir, &et);
 		if (num_free_extents < 0) {
 			status = num_free_extents;
 			mlog_errno(status);
@@ -1487,7 +1527,7 @@
 		}
 
 		if (!num_free_extents) {
-			status = ocfs2_reserve_new_metadata(osb, fe, &meta_ac);
+			status = ocfs2_reserve_new_metadata(osb, el, &meta_ac);
 			if (status < 0) {
 				if (status != -ENOSPC)
 					mlog_errno(status);
@@ -1502,7 +1542,7 @@
 			goto bail;
 		}
 
-		credits = ocfs2_calc_extend_credits(sb, fe, 1);
+		credits = ocfs2_calc_extend_credits(sb, el, 1);
 	} else {
 		spin_unlock(&OCFS2_I(dir)->ip_lock);
 		credits = OCFS2_SIMPLE_DIR_EXTEND_CREDITS;
@@ -1568,8 +1608,7 @@
 	if (meta_ac)
 		ocfs2_free_alloc_context(meta_ac);
 
-	if (new_bh)
-		brelse(new_bh);
+	brelse(new_bh);
 
 	mlog_exit(status);
 	return status;
@@ -1696,8 +1735,7 @@
 
 	status = 0;
 bail:
-	if (bh)
-		brelse(bh);
+	brelse(bh);
 
 	mlog_exit(status);
 	return status;
@@ -1756,7 +1794,6 @@
 	*ret_de_bh = bh;
 	bh = NULL;
 out:
-	if (bh)
-		brelse(bh);
+	brelse(bh);
 	return ret;
 }
diff --git a/fs/ocfs2/dlmglue.c b/fs/ocfs2/dlmglue.c
index eae3d64..ec68442 100644
--- a/fs/ocfs2/dlmglue.c
+++ b/fs/ocfs2/dlmglue.c
@@ -2024,8 +2024,7 @@
 	} else {
 		/* Boo, we have to go to disk. */
 		/* read bh, cast, ocfs2_refresh_inode */
-		status = ocfs2_read_block(OCFS2_SB(inode->i_sb), oi->ip_blkno,
-					  bh, OCFS2_BH_CACHED, inode);
+		status = ocfs2_read_block(inode, oi->ip_blkno, bh);
 		if (status < 0) {
 			mlog_errno(status);
 			goto bail_refresh;
@@ -2086,11 +2085,7 @@
 		return 0;
 	}
 
-	status = ocfs2_read_block(OCFS2_SB(inode->i_sb),
-				  OCFS2_I(inode)->ip_blkno,
-				  ret_bh,
-				  OCFS2_BH_CACHED,
-				  inode);
+	status = ocfs2_read_block(inode, OCFS2_I(inode)->ip_blkno, ret_bh);
 	if (status < 0)
 		mlog_errno(status);
 
diff --git a/fs/ocfs2/extent_map.c b/fs/ocfs2/extent_map.c
index c58668a..2baedac 100644
--- a/fs/ocfs2/extent_map.c
+++ b/fs/ocfs2/extent_map.c
@@ -25,6 +25,7 @@
 #include <linux/fs.h>
 #include <linux/init.h>
 #include <linux/types.h>
+#include <linux/fiemap.h>
 
 #define MLOG_MASK_PREFIX ML_EXTENT_MAP
 #include <cluster/masklog.h>
@@ -32,6 +33,7 @@
 #include "ocfs2.h"
 
 #include "alloc.h"
+#include "dlmglue.h"
 #include "extent_map.h"
 #include "inode.h"
 #include "super.h"
@@ -282,6 +284,50 @@
 		kfree(new_emi);
 }
 
+static int ocfs2_last_eb_is_empty(struct inode *inode,
+				  struct ocfs2_dinode *di)
+{
+	int ret, next_free;
+	u64 last_eb_blk = le64_to_cpu(di->i_last_eb_blk);
+	struct buffer_head *eb_bh = NULL;
+	struct ocfs2_extent_block *eb;
+	struct ocfs2_extent_list *el;
+
+	ret = ocfs2_read_block(inode, last_eb_blk, &eb_bh);
+	if (ret) {
+		mlog_errno(ret);
+		goto out;
+	}
+
+	eb = (struct ocfs2_extent_block *) eb_bh->b_data;
+	el = &eb->h_list;
+
+	if (!OCFS2_IS_VALID_EXTENT_BLOCK(eb)) {
+		ret = -EROFS;
+		OCFS2_RO_ON_INVALID_EXTENT_BLOCK(inode->i_sb, eb);
+		goto out;
+	}
+
+	if (el->l_tree_depth) {
+		ocfs2_error(inode->i_sb,
+			    "Inode %lu has non zero tree depth in "
+			    "leaf block %llu\n", inode->i_ino,
+			    (unsigned long long)eb_bh->b_blocknr);
+		ret = -EROFS;
+		goto out;
+	}
+
+	next_free = le16_to_cpu(el->l_next_free_rec);
+
+	if (next_free == 0 ||
+	    (next_free == 1 && ocfs2_is_empty_extent(&el->l_recs[0])))
+		ret = 1;
+
+out:
+	brelse(eb_bh);
+	return ret;
+}
+
 /*
  * Return the 1st index within el which contains an extent start
  * larger than v_cluster.
@@ -335,9 +381,9 @@
 		if (le64_to_cpu(eb->h_next_leaf_blk) == 0ULL)
 			goto no_more_extents;
 
-		ret = ocfs2_read_block(OCFS2_SB(inode->i_sb),
+		ret = ocfs2_read_block(inode,
 				       le64_to_cpu(eb->h_next_leaf_blk),
-				       &next_eb_bh, OCFS2_BH_CACHED, inode);
+				       &next_eb_bh);
 		if (ret) {
 			mlog_errno(ret);
 			goto out;
@@ -373,42 +419,28 @@
 	return ret;
 }
 
-int ocfs2_get_clusters(struct inode *inode, u32 v_cluster,
-		       u32 *p_cluster, u32 *num_clusters,
-		       unsigned int *extent_flags)
+static int ocfs2_get_clusters_nocache(struct inode *inode,
+				      struct buffer_head *di_bh,
+				      u32 v_cluster, unsigned int *hole_len,
+				      struct ocfs2_extent_rec *ret_rec,
+				      unsigned int *is_last)
 {
-	int ret, i;
-	unsigned int flags = 0;
-	struct buffer_head *di_bh = NULL;
-	struct buffer_head *eb_bh = NULL;
+	int i, ret, tree_height, len;
 	struct ocfs2_dinode *di;
-	struct ocfs2_extent_block *eb;
+	struct ocfs2_extent_block *uninitialized_var(eb);
 	struct ocfs2_extent_list *el;
 	struct ocfs2_extent_rec *rec;
-	u32 coff;
+	struct buffer_head *eb_bh = NULL;
 
-	if (OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL) {
-		ret = -ERANGE;
-		mlog_errno(ret);
-		goto out;
-	}
-
-	ret = ocfs2_extent_map_lookup(inode, v_cluster, p_cluster,
-				      num_clusters, extent_flags);
-	if (ret == 0)
-		goto out;
-
-	ret = ocfs2_read_block(OCFS2_SB(inode->i_sb), OCFS2_I(inode)->ip_blkno,
-			       &di_bh, OCFS2_BH_CACHED, inode);
-	if (ret) {
-		mlog_errno(ret);
-		goto out;
-	}
+	memset(ret_rec, 0, sizeof(*ret_rec));
+	if (is_last)
+		*is_last = 0;
 
 	di = (struct ocfs2_dinode *) di_bh->b_data;
 	el = &di->id2.i_list;
+	tree_height = le16_to_cpu(el->l_tree_depth);
 
-	if (el->l_tree_depth) {
+	if (tree_height > 0) {
 		ret = ocfs2_find_leaf(inode, el, v_cluster, &eb_bh);
 		if (ret) {
 			mlog_errno(ret);
@@ -431,46 +463,202 @@
 	i = ocfs2_search_extent_list(el, v_cluster);
 	if (i == -1) {
 		/*
+		 * Holes can be larger than the maximum size of an
+		 * extent, so we return their lengths in a seperate
+		 * field.
+		 */
+		if (hole_len) {
+			ret = ocfs2_figure_hole_clusters(inode, el, eb_bh,
+							 v_cluster, &len);
+			if (ret) {
+				mlog_errno(ret);
+				goto out;
+			}
+
+			*hole_len = len;
+		}
+		goto out_hole;
+	}
+
+	rec = &el->l_recs[i];
+
+	BUG_ON(v_cluster < le32_to_cpu(rec->e_cpos));
+
+	if (!rec->e_blkno) {
+		ocfs2_error(inode->i_sb, "Inode %lu has bad extent "
+			    "record (%u, %u, 0)", inode->i_ino,
+			    le32_to_cpu(rec->e_cpos),
+			    ocfs2_rec_clusters(el, rec));
+		ret = -EROFS;
+		goto out;
+	}
+
+	*ret_rec = *rec;
+
+	/*
+	 * Checking for last extent is potentially expensive - we
+	 * might have to look at the next leaf over to see if it's
+	 * empty.
+	 *
+	 * The first two checks are to see whether the caller even
+	 * cares for this information, and if the extent is at least
+	 * the last in it's list.
+	 *
+	 * If those hold true, then the extent is last if any of the
+	 * additional conditions hold true:
+	 *  - Extent list is in-inode
+	 *  - Extent list is right-most
+	 *  - Extent list is 2nd to rightmost, with empty right-most
+	 */
+	if (is_last) {
+		if (i == (le16_to_cpu(el->l_next_free_rec) - 1)) {
+			if (tree_height == 0)
+				*is_last = 1;
+			else if (eb->h_blkno == di->i_last_eb_blk)
+				*is_last = 1;
+			else if (eb->h_next_leaf_blk == di->i_last_eb_blk) {
+				ret = ocfs2_last_eb_is_empty(inode, di);
+				if (ret < 0) {
+					mlog_errno(ret);
+					goto out;
+				}
+				if (ret == 1)
+					*is_last = 1;
+			}
+		}
+	}
+
+out_hole:
+	ret = 0;
+out:
+	brelse(eb_bh);
+	return ret;
+}
+
+static void ocfs2_relative_extent_offsets(struct super_block *sb,
+					  u32 v_cluster,
+					  struct ocfs2_extent_rec *rec,
+					  u32 *p_cluster, u32 *num_clusters)
+
+{
+	u32 coff = v_cluster - le32_to_cpu(rec->e_cpos);
+
+	*p_cluster = ocfs2_blocks_to_clusters(sb, le64_to_cpu(rec->e_blkno));
+	*p_cluster = *p_cluster + coff;
+
+	if (num_clusters)
+		*num_clusters = le16_to_cpu(rec->e_leaf_clusters) - coff;
+}
+
+int ocfs2_xattr_get_clusters(struct inode *inode, u32 v_cluster,
+			     u32 *p_cluster, u32 *num_clusters,
+			     struct ocfs2_extent_list *el)
+{
+	int ret = 0, i;
+	struct buffer_head *eb_bh = NULL;
+	struct ocfs2_extent_block *eb;
+	struct ocfs2_extent_rec *rec;
+	u32 coff;
+
+	if (el->l_tree_depth) {
+		ret = ocfs2_find_leaf(inode, el, v_cluster, &eb_bh);
+		if (ret) {
+			mlog_errno(ret);
+			goto out;
+		}
+
+		eb = (struct ocfs2_extent_block *) eb_bh->b_data;
+		el = &eb->h_list;
+
+		if (el->l_tree_depth) {
+			ocfs2_error(inode->i_sb,
+				    "Inode %lu has non zero tree depth in "
+				    "xattr leaf block %llu\n", inode->i_ino,
+				    (unsigned long long)eb_bh->b_blocknr);
+			ret = -EROFS;
+			goto out;
+		}
+	}
+
+	i = ocfs2_search_extent_list(el, v_cluster);
+	if (i == -1) {
+		ret = -EROFS;
+		mlog_errno(ret);
+		goto out;
+	} else {
+		rec = &el->l_recs[i];
+		BUG_ON(v_cluster < le32_to_cpu(rec->e_cpos));
+
+		if (!rec->e_blkno) {
+			ocfs2_error(inode->i_sb, "Inode %lu has bad extent "
+				    "record (%u, %u, 0) in xattr", inode->i_ino,
+				    le32_to_cpu(rec->e_cpos),
+				    ocfs2_rec_clusters(el, rec));
+			ret = -EROFS;
+			goto out;
+		}
+		coff = v_cluster - le32_to_cpu(rec->e_cpos);
+		*p_cluster = ocfs2_blocks_to_clusters(inode->i_sb,
+						    le64_to_cpu(rec->e_blkno));
+		*p_cluster = *p_cluster + coff;
+		if (num_clusters)
+			*num_clusters = ocfs2_rec_clusters(el, rec) - coff;
+	}
+out:
+	if (eb_bh)
+		brelse(eb_bh);
+	return ret;
+}
+
+int ocfs2_get_clusters(struct inode *inode, u32 v_cluster,
+		       u32 *p_cluster, u32 *num_clusters,
+		       unsigned int *extent_flags)
+{
+	int ret;
+	unsigned int uninitialized_var(hole_len), flags = 0;
+	struct buffer_head *di_bh = NULL;
+	struct ocfs2_extent_rec rec;
+
+	if (OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL) {
+		ret = -ERANGE;
+		mlog_errno(ret);
+		goto out;
+	}
+
+	ret = ocfs2_extent_map_lookup(inode, v_cluster, p_cluster,
+				      num_clusters, extent_flags);
+	if (ret == 0)
+		goto out;
+
+	ret = ocfs2_read_block(inode, OCFS2_I(inode)->ip_blkno, &di_bh);
+	if (ret) {
+		mlog_errno(ret);
+		goto out;
+	}
+
+	ret = ocfs2_get_clusters_nocache(inode, di_bh, v_cluster, &hole_len,
+					 &rec, NULL);
+	if (ret) {
+		mlog_errno(ret);
+		goto out;
+	}
+
+	if (rec.e_blkno == 0ULL) {
+		/*
 		 * A hole was found. Return some canned values that
 		 * callers can key on. If asked for, num_clusters will
 		 * be populated with the size of the hole.
 		 */
 		*p_cluster = 0;
 		if (num_clusters) {
-			ret = ocfs2_figure_hole_clusters(inode, el, eb_bh,
-							 v_cluster,
-							 num_clusters);
-			if (ret) {
-				mlog_errno(ret);
-				goto out;
-			}
+			*num_clusters = hole_len;
 		}
 	} else {
-		rec = &el->l_recs[i];
+		ocfs2_relative_extent_offsets(inode->i_sb, v_cluster, &rec,
+					      p_cluster, num_clusters);
+		flags = rec.e_flags;
 
-		BUG_ON(v_cluster < le32_to_cpu(rec->e_cpos));
-
-		if (!rec->e_blkno) {
-			ocfs2_error(inode->i_sb, "Inode %lu has bad extent "
-				    "record (%u, %u, 0)", inode->i_ino,
-				    le32_to_cpu(rec->e_cpos),
-				    ocfs2_rec_clusters(el, rec));
-			ret = -EROFS;
-			goto out;
-		}
-
-		coff = v_cluster - le32_to_cpu(rec->e_cpos);
-
-		*p_cluster = ocfs2_blocks_to_clusters(inode->i_sb,
-						    le64_to_cpu(rec->e_blkno));
-		*p_cluster = *p_cluster + coff;
-
-		if (num_clusters)
-			*num_clusters = ocfs2_rec_clusters(el, rec) - coff;
-
-		flags = rec->e_flags;
-
-		ocfs2_extent_map_insert_rec(inode, rec);
+		ocfs2_extent_map_insert_rec(inode, &rec);
 	}
 
 	if (extent_flags)
@@ -478,7 +666,6 @@
 
 out:
 	brelse(di_bh);
-	brelse(eb_bh);
 	return ret;
 }
 
@@ -521,3 +708,114 @@
 out:
 	return ret;
 }
+
+static int ocfs2_fiemap_inline(struct inode *inode, struct buffer_head *di_bh,
+			       struct fiemap_extent_info *fieinfo,
+			       u64 map_start)
+{
+	int ret;
+	unsigned int id_count;
+	struct ocfs2_dinode *di;
+	u64 phys;
+	u32 flags = FIEMAP_EXTENT_DATA_INLINE|FIEMAP_EXTENT_LAST;
+	struct ocfs2_inode_info *oi = OCFS2_I(inode);
+
+	di = (struct ocfs2_dinode *)di_bh->b_data;
+	id_count = le16_to_cpu(di->id2.i_data.id_count);
+
+	if (map_start < id_count) {
+		phys = oi->ip_blkno << inode->i_sb->s_blocksize_bits;
+		phys += offsetof(struct ocfs2_dinode, id2.i_data.id_data);
+
+		ret = fiemap_fill_next_extent(fieinfo, 0, phys, id_count,
+					      flags);
+		if (ret < 0)
+			return ret;
+	}
+
+	return 0;
+}
+
+#define OCFS2_FIEMAP_FLAGS	(FIEMAP_FLAG_SYNC)
+
+int ocfs2_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
+		 u64 map_start, u64 map_len)
+{
+	int ret, is_last;
+	u32 mapping_end, cpos;
+	unsigned int hole_size;
+	struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+	u64 len_bytes, phys_bytes, virt_bytes;
+	struct buffer_head *di_bh = NULL;
+	struct ocfs2_extent_rec rec;
+
+	ret = fiemap_check_flags(fieinfo, OCFS2_FIEMAP_FLAGS);
+	if (ret)
+		return ret;
+
+	ret = ocfs2_inode_lock(inode, &di_bh, 0);
+	if (ret) {
+		mlog_errno(ret);
+		goto out;
+	}
+
+	down_read(&OCFS2_I(inode)->ip_alloc_sem);
+
+	/*
+	 * Handle inline-data separately.
+	 */
+	if (OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL) {
+		ret = ocfs2_fiemap_inline(inode, di_bh, fieinfo, map_start);
+		goto out_unlock;
+	}
+
+	cpos = map_start >> osb->s_clustersize_bits;
+	mapping_end = ocfs2_clusters_for_bytes(inode->i_sb,
+					       map_start + map_len);
+	mapping_end -= cpos;
+	is_last = 0;
+	while (cpos < mapping_end && !is_last) {
+		u32 fe_flags;
+
+		ret = ocfs2_get_clusters_nocache(inode, di_bh, cpos,
+						 &hole_size, &rec, &is_last);
+		if (ret) {
+			mlog_errno(ret);
+			goto out;
+		}
+
+		if (rec.e_blkno == 0ULL) {
+			cpos += hole_size;
+			continue;
+		}
+
+		fe_flags = 0;
+		if (rec.e_flags & OCFS2_EXT_UNWRITTEN)
+			fe_flags |= FIEMAP_EXTENT_UNWRITTEN;
+		if (is_last)
+			fe_flags |= FIEMAP_EXTENT_LAST;
+		len_bytes = (u64)le16_to_cpu(rec.e_leaf_clusters) << osb->s_clustersize_bits;
+		phys_bytes = le64_to_cpu(rec.e_blkno) << osb->sb->s_blocksize_bits;
+		virt_bytes = (u64)le32_to_cpu(rec.e_cpos) << osb->s_clustersize_bits;
+
+		ret = fiemap_fill_next_extent(fieinfo, virt_bytes, phys_bytes,
+					      len_bytes, fe_flags);
+		if (ret)
+			break;
+
+		cpos = le32_to_cpu(rec.e_cpos)+ le16_to_cpu(rec.e_leaf_clusters);
+	}
+
+	if (ret > 0)
+		ret = 0;
+
+out_unlock:
+	brelse(di_bh);
+
+	up_read(&OCFS2_I(inode)->ip_alloc_sem);
+
+	ocfs2_inode_unlock(inode, 0);
+out:
+
+	return ret;
+}
diff --git a/fs/ocfs2/extent_map.h b/fs/ocfs2/extent_map.h
index de91e3e..1c4aa8b 100644
--- a/fs/ocfs2/extent_map.h
+++ b/fs/ocfs2/extent_map.h
@@ -50,4 +50,11 @@
 int ocfs2_extent_map_get_blocks(struct inode *inode, u64 v_blkno, u64 *p_blkno,
 				u64 *ret_count, unsigned int *extent_flags);
 
+int ocfs2_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
+		 u64 map_start, u64 map_len);
+
+int ocfs2_xattr_get_clusters(struct inode *inode, u32 v_cluster,
+			     u32 *p_cluster, u32 *num_clusters,
+			     struct ocfs2_extent_list *el);
+
 #endif  /* _EXTENT_MAP_H */
diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c
index ec2ed15..8d3225a 100644
--- a/fs/ocfs2/file.c
+++ b/fs/ocfs2/file.c
@@ -55,6 +55,7 @@
 #include "mmap.h"
 #include "suballoc.h"
 #include "super.h"
+#include "xattr.h"
 
 #include "buffer_head_io.h"
 
@@ -184,7 +185,7 @@
 		goto bail;
 
 	journal = osb->journal->j_journal;
-	err = journal_force_commit(journal);
+	err = jbd2_journal_force_commit(journal);
 
 bail:
 	mlog_exit(err);
@@ -488,7 +489,7 @@
 }
 
 /*
- * extend allocation only here.
+ * extend file allocation only here.
  * we'll update all the disk stuff, and oip->alloc_size
  *
  * expect stuff to be locked, a transaction started and enough data /
@@ -497,189 +498,25 @@
  * Will return -EAGAIN, and a reason if a restart is needed.
  * If passed in, *reason will always be set, even in error.
  */
-int ocfs2_do_extend_allocation(struct ocfs2_super *osb,
-			       struct inode *inode,
-			       u32 *logical_offset,
-			       u32 clusters_to_add,
-			       int mark_unwritten,
-			       struct buffer_head *fe_bh,
-			       handle_t *handle,
-			       struct ocfs2_alloc_context *data_ac,
-			       struct ocfs2_alloc_context *meta_ac,
-			       enum ocfs2_alloc_restarted *reason_ret)
+int ocfs2_add_inode_data(struct ocfs2_super *osb,
+			 struct inode *inode,
+			 u32 *logical_offset,
+			 u32 clusters_to_add,
+			 int mark_unwritten,
+			 struct buffer_head *fe_bh,
+			 handle_t *handle,
+			 struct ocfs2_alloc_context *data_ac,
+			 struct ocfs2_alloc_context *meta_ac,
+			 enum ocfs2_alloc_restarted *reason_ret)
 {
-	int status = 0;
-	int free_extents;
-	struct ocfs2_dinode *fe = (struct ocfs2_dinode *) fe_bh->b_data;
-	enum ocfs2_alloc_restarted reason = RESTART_NONE;
-	u32 bit_off, num_bits;
-	u64 block;
-	u8 flags = 0;
+	int ret;
+	struct ocfs2_extent_tree et;
 
-	BUG_ON(!clusters_to_add);
-
-	if (mark_unwritten)
-		flags = OCFS2_EXT_UNWRITTEN;
-
-	free_extents = ocfs2_num_free_extents(osb, inode, fe);
-	if (free_extents < 0) {
-		status = free_extents;
-		mlog_errno(status);
-		goto leave;
-	}
-
-	/* there are two cases which could cause us to EAGAIN in the
-	 * we-need-more-metadata case:
-	 * 1) we haven't reserved *any*
-	 * 2) we are so fragmented, we've needed to add metadata too
-	 *    many times. */
-	if (!free_extents && !meta_ac) {
-		mlog(0, "we haven't reserved any metadata!\n");
-		status = -EAGAIN;
-		reason = RESTART_META;
-		goto leave;
-	} else if ((!free_extents)
-		   && (ocfs2_alloc_context_bits_left(meta_ac)
-		       < ocfs2_extend_meta_needed(fe))) {
-		mlog(0, "filesystem is really fragmented...\n");
-		status = -EAGAIN;
-		reason = RESTART_META;
-		goto leave;
-	}
-
-	status = __ocfs2_claim_clusters(osb, handle, data_ac, 1,
-					clusters_to_add, &bit_off, &num_bits);
-	if (status < 0) {
-		if (status != -ENOSPC)
-			mlog_errno(status);
-		goto leave;
-	}
-
-	BUG_ON(num_bits > clusters_to_add);
-
-	/* reserve our write early -- insert_extent may update the inode */
-	status = ocfs2_journal_access(handle, inode, fe_bh,
-				      OCFS2_JOURNAL_ACCESS_WRITE);
-	if (status < 0) {
-		mlog_errno(status);
-		goto leave;
-	}
-
-	block = ocfs2_clusters_to_blocks(osb->sb, bit_off);
-	mlog(0, "Allocating %u clusters at block %u for inode %llu\n",
-	     num_bits, bit_off, (unsigned long long)OCFS2_I(inode)->ip_blkno);
-	status = ocfs2_insert_extent(osb, handle, inode, fe_bh,
-				     *logical_offset, block, num_bits,
-				     flags, meta_ac);
-	if (status < 0) {
-		mlog_errno(status);
-		goto leave;
-	}
-
-	status = ocfs2_journal_dirty(handle, fe_bh);
-	if (status < 0) {
-		mlog_errno(status);
-		goto leave;
-	}
-
-	clusters_to_add -= num_bits;
-	*logical_offset += num_bits;
-
-	if (clusters_to_add) {
-		mlog(0, "need to alloc once more, clusters = %u, wanted = "
-		     "%u\n", fe->i_clusters, clusters_to_add);
-		status = -EAGAIN;
-		reason = RESTART_TRANS;
-	}
-
-leave:
-	mlog_exit(status);
-	if (reason_ret)
-		*reason_ret = reason;
-	return status;
-}
-
-/*
- * For a given allocation, determine which allocators will need to be
- * accessed, and lock them, reserving the appropriate number of bits.
- *
- * Sparse file systems call this from ocfs2_write_begin_nolock()
- * and ocfs2_allocate_unwritten_extents().
- *
- * File systems which don't support holes call this from
- * ocfs2_extend_allocation().
- */
-int ocfs2_lock_allocators(struct inode *inode, struct ocfs2_dinode *di,
-			  u32 clusters_to_add, u32 extents_to_split,
-			  struct ocfs2_alloc_context **data_ac,
-			  struct ocfs2_alloc_context **meta_ac)
-{
-	int ret = 0, num_free_extents;
-	unsigned int max_recs_needed = clusters_to_add + 2 * extents_to_split;
-	struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
-
-	*meta_ac = NULL;
-	if (data_ac)
-		*data_ac = NULL;
-
-	BUG_ON(clusters_to_add != 0 && data_ac == NULL);
-
-	mlog(0, "extend inode %llu, i_size = %lld, di->i_clusters = %u, "
-	     "clusters_to_add = %u, extents_to_split = %u\n",
-	     (unsigned long long)OCFS2_I(inode)->ip_blkno, (long long)i_size_read(inode),
-	     le32_to_cpu(di->i_clusters), clusters_to_add, extents_to_split);
-
-	num_free_extents = ocfs2_num_free_extents(osb, inode, di);
-	if (num_free_extents < 0) {
-		ret = num_free_extents;
-		mlog_errno(ret);
-		goto out;
-	}
-
-	/*
-	 * Sparse allocation file systems need to be more conservative
-	 * with reserving room for expansion - the actual allocation
-	 * happens while we've got a journal handle open so re-taking
-	 * a cluster lock (because we ran out of room for another
-	 * extent) will violate ordering rules.
-	 *
-	 * Most of the time we'll only be seeing this 1 cluster at a time
-	 * anyway.
-	 *
-	 * Always lock for any unwritten extents - we might want to
-	 * add blocks during a split.
-	 */
-	if (!num_free_extents ||
-	    (ocfs2_sparse_alloc(osb) && num_free_extents < max_recs_needed)) {
-		ret = ocfs2_reserve_new_metadata(osb, di, meta_ac);
-		if (ret < 0) {
-			if (ret != -ENOSPC)
-				mlog_errno(ret);
-			goto out;
-		}
-	}
-
-	if (clusters_to_add == 0)
-		goto out;
-
-	ret = ocfs2_reserve_clusters(osb, clusters_to_add, data_ac);
-	if (ret < 0) {
-		if (ret != -ENOSPC)
-			mlog_errno(ret);
-		goto out;
-	}
-
-out:
-	if (ret) {
-		if (*meta_ac) {
-			ocfs2_free_alloc_context(*meta_ac);
-			*meta_ac = NULL;
-		}
-
-		/*
-		 * We cannot have an error and a non null *data_ac.
-		 */
-	}
+	ocfs2_init_dinode_extent_tree(&et, inode, fe_bh);
+	ret = ocfs2_add_clusters_in_btree(osb, inode, logical_offset,
+					   clusters_to_add, mark_unwritten,
+					   &et, handle,
+					   data_ac, meta_ac, reason_ret);
 
 	return ret;
 }
@@ -698,6 +535,7 @@
 	struct ocfs2_alloc_context *meta_ac = NULL;
 	enum ocfs2_alloc_restarted why;
 	struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+	struct ocfs2_extent_tree et;
 
 	mlog_entry("(clusters_to_add = %u)\n", clusters_to_add);
 
@@ -707,8 +545,7 @@
 	 */
 	BUG_ON(mark_unwritten && !ocfs2_sparse_alloc(osb));
 
-	status = ocfs2_read_block(osb, OCFS2_I(inode)->ip_blkno, &bh,
-				  OCFS2_BH_CACHED, inode);
+	status = ocfs2_read_block(inode, OCFS2_I(inode)->ip_blkno, &bh);
 	if (status < 0) {
 		mlog_errno(status);
 		goto leave;
@@ -724,14 +561,21 @@
 restart_all:
 	BUG_ON(le32_to_cpu(fe->i_clusters) != OCFS2_I(inode)->ip_clusters);
 
-	status = ocfs2_lock_allocators(inode, fe, clusters_to_add, 0, &data_ac,
-				       &meta_ac);
+	mlog(0, "extend inode %llu, i_size = %lld, di->i_clusters = %u, "
+	     "clusters_to_add = %u\n",
+	     (unsigned long long)OCFS2_I(inode)->ip_blkno,
+	     (long long)i_size_read(inode), le32_to_cpu(fe->i_clusters),
+	     clusters_to_add);
+	ocfs2_init_dinode_extent_tree(&et, inode, bh);
+	status = ocfs2_lock_allocators(inode, &et, clusters_to_add, 0,
+				       &data_ac, &meta_ac);
 	if (status) {
 		mlog_errno(status);
 		goto leave;
 	}
 
-	credits = ocfs2_calc_extend_credits(osb->sb, fe, clusters_to_add);
+	credits = ocfs2_calc_extend_credits(osb->sb, &fe->id2.i_list,
+					    clusters_to_add);
 	handle = ocfs2_start_trans(osb, credits);
 	if (IS_ERR(handle)) {
 		status = PTR_ERR(handle);
@@ -753,16 +597,16 @@
 
 	prev_clusters = OCFS2_I(inode)->ip_clusters;
 
-	status = ocfs2_do_extend_allocation(osb,
-					    inode,
-					    &logical_start,
-					    clusters_to_add,
-					    mark_unwritten,
-					    bh,
-					    handle,
-					    data_ac,
-					    meta_ac,
-					    &why);
+	status = ocfs2_add_inode_data(osb,
+				      inode,
+				      &logical_start,
+				      clusters_to_add,
+				      mark_unwritten,
+				      bh,
+				      handle,
+				      data_ac,
+				      meta_ac,
+				      &why);
 	if ((status < 0) && (status != -EAGAIN)) {
 		if (status != -ENOSPC)
 			mlog_errno(status);
@@ -789,7 +633,7 @@
 			mlog(0, "restarting transaction.\n");
 			/* TODO: This can be more intelligent. */
 			credits = ocfs2_calc_extend_credits(osb->sb,
-							    fe,
+							    &fe->id2.i_list,
 							    clusters_to_add);
 			status = ocfs2_extend_trans(handle, credits);
 			if (status < 0) {
@@ -826,10 +670,8 @@
 		restart_func = 0;
 		goto restart_all;
 	}
-	if (bh) {
-		brelse(bh);
-		bh = NULL;
-	}
+	brelse(bh);
+	bh = NULL;
 
 	mlog_exit(status);
 	return status;
@@ -1096,9 +938,15 @@
 			goto bail_unlock;
 		}
 
-		if (i_size_read(inode) > attr->ia_size)
+		if (i_size_read(inode) > attr->ia_size) {
+			if (ocfs2_should_order_data(inode)) {
+				status = ocfs2_begin_ordered_truncate(inode,
+								      attr->ia_size);
+				if (status)
+					goto bail_unlock;
+			}
 			status = ocfs2_truncate_file(inode, bh, attr->ia_size);
-		else
+		} else
 			status = ocfs2_extend_file(inode, bh, attr->ia_size);
 		if (status < 0) {
 			if (status != -ENOSPC)
@@ -1140,8 +988,7 @@
 	if (size_change)
 		ocfs2_rw_unlock(inode, 1);
 bail:
-	if (bh)
-		brelse(bh);
+	brelse(bh);
 
 	mlog_exit(status);
 	return status;
@@ -1284,8 +1131,7 @@
 	struct buffer_head *bh = NULL;
 	struct ocfs2_inode_info *oi = OCFS2_I(inode);
 
-	ret = ocfs2_read_block(OCFS2_SB(inode->i_sb),
-			       oi->ip_blkno, &bh, OCFS2_BH_CACHED, inode);
+	ret = ocfs2_read_block(inode, oi->ip_blkno, &bh);
 	if (ret < 0) {
 		mlog_errno(ret);
 		goto out;
@@ -1311,9 +1157,8 @@
 	struct buffer_head *di_bh = NULL;
 
 	if (OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL) {
-		ret = ocfs2_read_block(OCFS2_SB(inode->i_sb),
-				       OCFS2_I(inode)->ip_blkno, &di_bh,
-				       OCFS2_BH_CACHED, inode);
+		ret = ocfs2_read_block(inode, OCFS2_I(inode)->ip_blkno,
+				       &di_bh);
 		if (ret) {
 			mlog_errno(ret);
 			goto out;
@@ -1394,8 +1239,11 @@
 	handle_t *handle;
 	struct ocfs2_alloc_context *meta_ac = NULL;
 	struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data;
+	struct ocfs2_extent_tree et;
 
-	ret = ocfs2_lock_allocators(inode, di, 0, 1, NULL, &meta_ac);
+	ocfs2_init_dinode_extent_tree(&et, inode, di_bh);
+
+	ret = ocfs2_lock_allocators(inode, &et, 0, 1, NULL, &meta_ac);
 	if (ret) {
 		mlog_errno(ret);
 		return ret;
@@ -1425,7 +1273,7 @@
 		goto out;
 	}
 
-	ret = ocfs2_remove_extent(inode, di_bh, cpos, len, handle, meta_ac,
+	ret = ocfs2_remove_extent(inode, &et, cpos, len, handle, meta_ac,
 				  dealloc);
 	if (ret) {
 		mlog_errno(ret);
@@ -2040,7 +1888,7 @@
 		 */
 		if (old_size != i_size_read(inode) ||
 		    old_clusters != OCFS2_I(inode)->ip_clusters) {
-			ret = journal_force_commit(osb->journal->j_journal);
+			ret = jbd2_journal_force_commit(osb->journal->j_journal);
 			if (ret < 0)
 				written = ret;
 		}
@@ -2227,7 +2075,12 @@
 	.setattr	= ocfs2_setattr,
 	.getattr	= ocfs2_getattr,
 	.permission	= ocfs2_permission,
+	.setxattr	= generic_setxattr,
+	.getxattr	= generic_getxattr,
+	.listxattr	= ocfs2_listxattr,
+	.removexattr	= generic_removexattr,
 	.fallocate	= ocfs2_fallocate,
+	.fiemap		= ocfs2_fiemap,
 };
 
 const struct inode_operations ocfs2_special_file_iops = {
@@ -2236,6 +2089,10 @@
 	.permission	= ocfs2_permission,
 };
 
+/*
+ * Other than ->lock, keep ocfs2_fops and ocfs2_dops in sync with
+ * ocfs2_fops_no_plocks and ocfs2_dops_no_plocks!
+ */
 const struct file_operations ocfs2_fops = {
 	.llseek		= generic_file_llseek,
 	.read		= do_sync_read,
@@ -2250,12 +2107,59 @@
 #ifdef CONFIG_COMPAT
 	.compat_ioctl   = ocfs2_compat_ioctl,
 #endif
+	.lock		= ocfs2_lock,
+	.flock		= ocfs2_flock,
+	.splice_read	= ocfs2_file_splice_read,
+	.splice_write	= ocfs2_file_splice_write,
+};
+
+const struct file_operations ocfs2_dops = {
+	.llseek		= generic_file_llseek,
+	.read		= generic_read_dir,
+	.readdir	= ocfs2_readdir,
+	.fsync		= ocfs2_sync_file,
+	.release	= ocfs2_dir_release,
+	.open		= ocfs2_dir_open,
+	.unlocked_ioctl	= ocfs2_ioctl,
+#ifdef CONFIG_COMPAT
+	.compat_ioctl   = ocfs2_compat_ioctl,
+#endif
+	.lock		= ocfs2_lock,
+	.flock		= ocfs2_flock,
+};
+
+/*
+ * POSIX-lockless variants of our file_operations.
+ *
+ * These will be used if the underlying cluster stack does not support
+ * posix file locking, if the user passes the "localflocks" mount
+ * option, or if we have a local-only fs.
+ *
+ * ocfs2_flock is in here because all stacks handle UNIX file locks,
+ * so we still want it in the case of no stack support for
+ * plocks. Internally, it will do the right thing when asked to ignore
+ * the cluster.
+ */
+const struct file_operations ocfs2_fops_no_plocks = {
+	.llseek		= generic_file_llseek,
+	.read		= do_sync_read,
+	.write		= do_sync_write,
+	.mmap		= ocfs2_mmap,
+	.fsync		= ocfs2_sync_file,
+	.release	= ocfs2_file_release,
+	.open		= ocfs2_file_open,
+	.aio_read	= ocfs2_file_aio_read,
+	.aio_write	= ocfs2_file_aio_write,
+	.unlocked_ioctl	= ocfs2_ioctl,
+#ifdef CONFIG_COMPAT
+	.compat_ioctl   = ocfs2_compat_ioctl,
+#endif
 	.flock		= ocfs2_flock,
 	.splice_read	= ocfs2_file_splice_read,
 	.splice_write	= ocfs2_file_splice_write,
 };
 
-const struct file_operations ocfs2_dops = {
+const struct file_operations ocfs2_dops_no_plocks = {
 	.llseek		= generic_file_llseek,
 	.read		= generic_read_dir,
 	.readdir	= ocfs2_readdir,
diff --git a/fs/ocfs2/file.h b/fs/ocfs2/file.h
index 1e27b4d..e92382c 100644
--- a/fs/ocfs2/file.h
+++ b/fs/ocfs2/file.h
@@ -28,9 +28,12 @@
 
 extern const struct file_operations ocfs2_fops;
 extern const struct file_operations ocfs2_dops;
+extern const struct file_operations ocfs2_fops_no_plocks;
+extern const struct file_operations ocfs2_dops_no_plocks;
 extern const struct inode_operations ocfs2_file_iops;
 extern const struct inode_operations ocfs2_special_file_iops;
 struct ocfs2_alloc_context;
+enum ocfs2_alloc_restarted;
 
 struct ocfs2_file_private {
 	struct file		*fp_file;
@@ -38,27 +41,18 @@
 	struct ocfs2_lock_res	fp_flock;
 };
 
-enum ocfs2_alloc_restarted {
-	RESTART_NONE = 0,
-	RESTART_TRANS,
-	RESTART_META
-};
-int ocfs2_do_extend_allocation(struct ocfs2_super *osb,
-			       struct inode *inode,
-			       u32 *logical_offset,
-			       u32 clusters_to_add,
-			       int mark_unwritten,
-			       struct buffer_head *fe_bh,
-			       handle_t *handle,
-			       struct ocfs2_alloc_context *data_ac,
-			       struct ocfs2_alloc_context *meta_ac,
-			       enum ocfs2_alloc_restarted *reason_ret);
+int ocfs2_add_inode_data(struct ocfs2_super *osb,
+			 struct inode *inode,
+			 u32 *logical_offset,
+			 u32 clusters_to_add,
+			 int mark_unwritten,
+			 struct buffer_head *fe_bh,
+			 handle_t *handle,
+			 struct ocfs2_alloc_context *data_ac,
+			 struct ocfs2_alloc_context *meta_ac,
+			 enum ocfs2_alloc_restarted *reason_ret);
 int ocfs2_extend_no_holes(struct inode *inode, u64 new_i_size,
 			  u64 zero_to);
-int ocfs2_lock_allocators(struct inode *inode, struct ocfs2_dinode *di,
-			  u32 clusters_to_add, u32 extents_to_split,
-			  struct ocfs2_alloc_context **data_ac,
-			  struct ocfs2_alloc_context **meta_ac);
 int ocfs2_setattr(struct dentry *dentry, struct iattr *attr);
 int ocfs2_getattr(struct vfsmount *mnt, struct dentry *dentry,
 		  struct kstat *stat);
diff --git a/fs/ocfs2/inode.c b/fs/ocfs2/inode.c
index 7e9e4c7..4903688 100644
--- a/fs/ocfs2/inode.c
+++ b/fs/ocfs2/inode.c
@@ -49,6 +49,7 @@
 #include "symlink.h"
 #include "sysfile.h"
 #include "uptodate.h"
+#include "xattr.h"
 
 #include "buffer_head_io.h"
 
@@ -219,6 +220,7 @@
 	struct super_block *sb;
 	struct ocfs2_super *osb;
 	int status = -EINVAL;
+	int use_plocks = 1;
 
 	mlog_entry("(0x%p, size:%llu)\n", inode,
 		   (unsigned long long)le64_to_cpu(fe->i_size));
@@ -226,6 +228,10 @@
 	sb = inode->i_sb;
 	osb = OCFS2_SB(sb);
 
+	if ((osb->s_mount_opt & OCFS2_MOUNT_LOCALFLOCKS) ||
+	    ocfs2_mount_local(osb) || !ocfs2_stack_supports_plocks())
+		use_plocks = 0;
+
 	/* this means that read_inode cannot create a superblock inode
 	 * today.  change if needed. */
 	if (!OCFS2_IS_VALID_DINODE(fe) ||
@@ -295,13 +301,19 @@
 
 	switch (inode->i_mode & S_IFMT) {
 	    case S_IFREG:
-		    inode->i_fop = &ocfs2_fops;
+		    if (use_plocks)
+			    inode->i_fop = &ocfs2_fops;
+		    else
+			    inode->i_fop = &ocfs2_fops_no_plocks;
 		    inode->i_op = &ocfs2_file_iops;
 		    i_size_write(inode, le64_to_cpu(fe->i_size));
 		    break;
 	    case S_IFDIR:
 		    inode->i_op = &ocfs2_dir_iops;
-		    inode->i_fop = &ocfs2_dops;
+		    if (use_plocks)
+			    inode->i_fop = &ocfs2_dops;
+		    else
+			    inode->i_fop = &ocfs2_dops_no_plocks;
 		    i_size_write(inode, le64_to_cpu(fe->i_size));
 		    break;
 	    case S_IFLNK:
@@ -448,8 +460,11 @@
 		}
 	}
 
-	status = ocfs2_read_block(osb, args->fi_blkno, &bh, 0,
-				  can_lock ? inode : NULL);
+	if (can_lock)
+		status = ocfs2_read_blocks(inode, args->fi_blkno, 1, &bh,
+					   OCFS2_BH_IGNORE_CACHE);
+	else
+		status = ocfs2_read_blocks_sync(osb, args->fi_blkno, 1, &bh);
 	if (status < 0) {
 		mlog_errno(status);
 		goto bail;
@@ -522,6 +537,9 @@
 	 * data and fast symlinks.
 	 */
 	if (fe->i_clusters) {
+		if (ocfs2_should_order_data(inode))
+			ocfs2_begin_ordered_truncate(inode, 0);
+
 		handle = ocfs2_start_trans(osb, OCFS2_INODE_UPDATE_CREDITS);
 		if (IS_ERR(handle)) {
 			status = PTR_ERR(handle);
@@ -730,6 +748,13 @@
 		goto bail_unlock_dir;
 	}
 
+	/*Free extended attribute resources associated with this inode.*/
+	status = ocfs2_xattr_remove(inode, di_bh);
+	if (status < 0) {
+		mlog_errno(status);
+		goto bail_unlock_dir;
+	}
+
 	status = ocfs2_remove_inode(inode, di_bh, orphan_dir_inode,
 				    orphan_dir_bh);
 	if (status < 0)
@@ -1081,6 +1106,8 @@
 	oi->ip_last_trans = 0;
 	oi->ip_dir_start_lookup = 0;
 	oi->ip_blkno = 0ULL;
+	jbd2_journal_release_jbd_inode(OCFS2_SB(inode->i_sb)->journal->j_journal,
+				       &oi->ip_jinode);
 
 bail:
 	mlog_exit_void();
@@ -1107,58 +1134,6 @@
 }
 
 /*
- * TODO: this should probably be merged into ocfs2_get_block
- *
- * However, you now need to pay attention to the cont_prepare_write()
- * stuff in ocfs2_get_block (that is, ocfs2_get_block pretty much
- * expects never to extend).
- */
-struct buffer_head *ocfs2_bread(struct inode *inode,
-				int block, int *err, int reada)
-{
-	struct buffer_head *bh = NULL;
-	int tmperr;
-	u64 p_blkno;
-	int readflags = OCFS2_BH_CACHED;
-
-	if (reada)
-		readflags |= OCFS2_BH_READAHEAD;
-
-	if (((u64)block << inode->i_sb->s_blocksize_bits) >=
-	    i_size_read(inode)) {
-		BUG_ON(!reada);
-		return NULL;
-	}
-
-	down_read(&OCFS2_I(inode)->ip_alloc_sem);
-	tmperr = ocfs2_extent_map_get_blocks(inode, block, &p_blkno, NULL,
-					     NULL);
-	up_read(&OCFS2_I(inode)->ip_alloc_sem);
-	if (tmperr < 0) {
-		mlog_errno(tmperr);
-		goto fail;
-	}
-
-	tmperr = ocfs2_read_block(OCFS2_SB(inode->i_sb), p_blkno, &bh,
-				  readflags, inode);
-	if (tmperr < 0)
-		goto fail;
-
-	tmperr = 0;
-
-	*err = 0;
-	return bh;
-
-fail:
-	if (bh) {
-		brelse(bh);
-		bh = NULL;
-	}
-	*err = -EIO;
-	return NULL;
-}
-
-/*
  * This is called from our getattr.
  */
 int ocfs2_inode_revalidate(struct dentry *dentry)
diff --git a/fs/ocfs2/inode.h b/fs/ocfs2/inode.h
index 390a855..2f37af9 100644
--- a/fs/ocfs2/inode.h
+++ b/fs/ocfs2/inode.h
@@ -40,6 +40,9 @@
 	/* protects allocation changes on this inode. */
 	struct rw_semaphore		ip_alloc_sem;
 
+	/* protects extended attribute changes on this inode */
+	struct rw_semaphore		ip_xattr_sem;
+
 	/* These fields are protected by ip_lock */
 	spinlock_t			ip_lock;
 	u32				ip_open_count;
@@ -68,6 +71,7 @@
 	struct ocfs2_extent_map		ip_extent_map;
 
 	struct inode			vfs_inode;
+	struct jbd2_inode		ip_jinode;
 };
 
 /*
@@ -113,8 +117,6 @@
 
 extern const struct address_space_operations ocfs2_aops;
 
-struct buffer_head *ocfs2_bread(struct inode *inode, int block,
-				int *err, int reada);
 void ocfs2_clear_inode(struct inode *inode);
 void ocfs2_delete_inode(struct inode *inode);
 void ocfs2_drop_inode(struct inode *inode);
diff --git a/fs/ocfs2/ioctl.c b/fs/ocfs2/ioctl.c
index 7b142f0..9fcd36d 100644
--- a/fs/ocfs2/ioctl.c
+++ b/fs/ocfs2/ioctl.c
@@ -102,8 +102,7 @@
 bail:
 	mutex_unlock(&inode->i_mutex);
 
-	if (bh)
-		brelse(bh);
+	brelse(bh);
 
 	mlog_exit(status);
 	return status;
diff --git a/fs/ocfs2/journal.c b/fs/ocfs2/journal.c
index c47bc2a..81e4067 100644
--- a/fs/ocfs2/journal.c
+++ b/fs/ocfs2/journal.c
@@ -215,9 +215,9 @@
 		goto finally;
 	}
 
-	journal_lock_updates(journal->j_journal);
-	status = journal_flush(journal->j_journal);
-	journal_unlock_updates(journal->j_journal);
+	jbd2_journal_lock_updates(journal->j_journal);
+	status = jbd2_journal_flush(journal->j_journal);
+	jbd2_journal_unlock_updates(journal->j_journal);
 	if (status < 0) {
 		up_write(&journal->j_trans_barrier);
 		mlog_errno(status);
@@ -264,7 +264,7 @@
 
 	down_read(&osb->journal->j_trans_barrier);
 
-	handle = journal_start(journal, max_buffs);
+	handle = jbd2_journal_start(journal, max_buffs);
 	if (IS_ERR(handle)) {
 		up_read(&osb->journal->j_trans_barrier);
 
@@ -290,7 +290,7 @@
 
 	BUG_ON(!handle);
 
-	ret = journal_stop(handle);
+	ret = jbd2_journal_stop(handle);
 	if (ret < 0)
 		mlog_errno(ret);
 
@@ -304,7 +304,7 @@
  * transaction. extend_trans will either extend the current handle by
  * nblocks, or commit it and start a new one with nblocks credits.
  *
- * This might call journal_restart() which will commit dirty buffers
+ * This might call jbd2_journal_restart() which will commit dirty buffers
  * and then restart the transaction. Before calling
  * ocfs2_extend_trans(), any changed blocks should have been
  * dirtied. After calling it, all blocks which need to be changed must
@@ -332,7 +332,7 @@
 #ifdef CONFIG_OCFS2_DEBUG_FS
 	status = 1;
 #else
-	status = journal_extend(handle, nblocks);
+	status = jbd2_journal_extend(handle, nblocks);
 	if (status < 0) {
 		mlog_errno(status);
 		goto bail;
@@ -340,8 +340,10 @@
 #endif
 
 	if (status > 0) {
-		mlog(0, "journal_extend failed, trying journal_restart\n");
-		status = journal_restart(handle, nblocks);
+		mlog(0,
+		     "jbd2_journal_extend failed, trying "
+		     "jbd2_journal_restart\n");
+		status = jbd2_journal_restart(handle, nblocks);
 		if (status < 0) {
 			mlog_errno(status);
 			goto bail;
@@ -393,11 +395,11 @@
 	switch (type) {
 	case OCFS2_JOURNAL_ACCESS_CREATE:
 	case OCFS2_JOURNAL_ACCESS_WRITE:
-		status = journal_get_write_access(handle, bh);
+		status = jbd2_journal_get_write_access(handle, bh);
 		break;
 
 	case OCFS2_JOURNAL_ACCESS_UNDO:
-		status = journal_get_undo_access(handle, bh);
+		status = jbd2_journal_get_undo_access(handle, bh);
 		break;
 
 	default:
@@ -422,7 +424,7 @@
 	mlog_entry("(bh->b_blocknr=%llu)\n",
 		   (unsigned long long)bh->b_blocknr);
 
-	status = journal_dirty_metadata(handle, bh);
+	status = jbd2_journal_dirty_metadata(handle, bh);
 	if (status < 0)
 		mlog(ML_ERROR, "Could not dirty metadata buffer. "
 		     "(bh->b_blocknr=%llu)\n",
@@ -432,6 +434,7 @@
 	return status;
 }
 
+#ifdef CONFIG_OCFS2_COMPAT_JBD
 int ocfs2_journal_dirty_data(handle_t *handle,
 			     struct buffer_head *bh)
 {
@@ -443,8 +446,9 @@
 
 	return err;
 }
+#endif
 
-#define OCFS2_DEFAULT_COMMIT_INTERVAL 	(HZ * JBD_DEFAULT_MAX_COMMIT_AGE)
+#define OCFS2_DEFAULT_COMMIT_INTERVAL	(HZ * JBD2_DEFAULT_MAX_COMMIT_AGE)
 
 void ocfs2_set_journal_params(struct ocfs2_super *osb)
 {
@@ -457,9 +461,9 @@
 	spin_lock(&journal->j_state_lock);
 	journal->j_commit_interval = commit_interval;
 	if (osb->s_mount_opt & OCFS2_MOUNT_BARRIER)
-		journal->j_flags |= JFS_BARRIER;
+		journal->j_flags |= JBD2_BARRIER;
 	else
-		journal->j_flags &= ~JFS_BARRIER;
+		journal->j_flags &= ~JBD2_BARRIER;
 	spin_unlock(&journal->j_state_lock);
 }
 
@@ -524,14 +528,14 @@
 	mlog(0, "inode->ip_clusters = %u\n", OCFS2_I(inode)->ip_clusters);
 
 	/* call the kernels journal init function now */
-	j_journal = journal_init_inode(inode);
+	j_journal = jbd2_journal_init_inode(inode);
 	if (j_journal == NULL) {
 		mlog(ML_ERROR, "Linux journal layer error\n");
 		status = -EINVAL;
 		goto done;
 	}
 
-	mlog(0, "Returned from journal_init_inode\n");
+	mlog(0, "Returned from jbd2_journal_init_inode\n");
 	mlog(0, "j_journal->j_maxlen = %u\n", j_journal->j_maxlen);
 
 	*dirty = (le32_to_cpu(di->id1.journal1.ij_flags) &
@@ -550,8 +554,7 @@
 	if (status < 0) {
 		if (inode_lock)
 			ocfs2_inode_unlock(inode, 1);
-		if (bh != NULL)
-			brelse(bh);
+		brelse(bh);
 		if (inode) {
 			OCFS2_I(inode)->ip_open_count--;
 			iput(inode);
@@ -639,7 +642,7 @@
 	if (journal->j_state != OCFS2_JOURNAL_LOADED)
 		goto done;
 
-	/* need to inc inode use count as journal_destroy will iput. */
+	/* need to inc inode use count - jbd2_journal_destroy will iput. */
 	if (!igrab(inode))
 		BUG();
 
@@ -668,9 +671,9 @@
 	BUG_ON(atomic_read(&(osb->journal->j_num_trans)) != 0);
 
 	if (ocfs2_mount_local(osb)) {
-		journal_lock_updates(journal->j_journal);
-		status = journal_flush(journal->j_journal);
-		journal_unlock_updates(journal->j_journal);
+		jbd2_journal_lock_updates(journal->j_journal);
+		status = jbd2_journal_flush(journal->j_journal);
+		jbd2_journal_unlock_updates(journal->j_journal);
 		if (status < 0)
 			mlog_errno(status);
 	}
@@ -686,7 +689,7 @@
 	}
 
 	/* Shutdown the kernel journal system */
-	journal_destroy(journal->j_journal);
+	jbd2_journal_destroy(journal->j_journal);
 
 	OCFS2_I(inode)->ip_open_count--;
 
@@ -711,15 +714,15 @@
 {
 	int olderr;
 
-	olderr = journal_errno(journal);
+	olderr = jbd2_journal_errno(journal);
 	if (olderr) {
 		mlog(ML_ERROR, "File system error %d recorded in "
 		     "journal %u.\n", olderr, slot);
 		mlog(ML_ERROR, "File system on device %s needs checking.\n",
 		     sb->s_id);
 
-		journal_ack_err(journal);
-		journal_clear_err(journal);
+		jbd2_journal_ack_err(journal);
+		jbd2_journal_clear_err(journal);
 	}
 }
 
@@ -734,7 +737,7 @@
 
 	osb = journal->j_osb;
 
-	status = journal_load(journal->j_journal);
+	status = jbd2_journal_load(journal->j_journal);
 	if (status < 0) {
 		mlog(ML_ERROR, "Failed to load journal!\n");
 		goto done;
@@ -778,7 +781,7 @@
 
 	BUG_ON(!journal);
 
-	status = journal_wipe(journal->j_journal, full);
+	status = jbd2_journal_wipe(journal->j_journal, full);
 	if (status < 0) {
 		mlog_errno(status);
 		goto bail;
@@ -847,9 +850,8 @@
 
 		/* We are reading journal data which should not
 		 * be put in the uptodate cache */
-		status = ocfs2_read_blocks(OCFS2_SB(inode->i_sb),
-					   p_blkno, p_blocks, bhs, 0,
-					   NULL);
+		status = ocfs2_read_blocks_sync(OCFS2_SB(inode->i_sb),
+						p_blkno, p_blocks, bhs);
 		if (status < 0) {
 			mlog_errno(status);
 			goto bail;
@@ -865,8 +867,7 @@
 
 bail:
 	for(i = 0; i < CONCURRENT_JOURNAL_FILL; i++)
-		if (bhs[i])
-			brelse(bhs[i]);
+		brelse(bhs[i]);
 	mlog_exit(status);
 	return status;
 }
@@ -1133,7 +1134,8 @@
 	}
 	SET_INODE_JOURNAL(inode);
 
-	status = ocfs2_read_block(osb, OCFS2_I(inode)->ip_blkno, bh, 0, inode);
+	status = ocfs2_read_blocks(inode, OCFS2_I(inode)->ip_blkno, 1, bh,
+				   OCFS2_BH_IGNORE_CACHE);
 	if (status < 0) {
 		mlog_errno(status);
 		goto bail;
@@ -1229,19 +1231,19 @@
 	}
 
 	mlog(0, "calling journal_init_inode\n");
-	journal = journal_init_inode(inode);
+	journal = jbd2_journal_init_inode(inode);
 	if (journal == NULL) {
 		mlog(ML_ERROR, "Linux journal layer error\n");
 		status = -EIO;
 		goto done;
 	}
 
-	status = journal_load(journal);
+	status = jbd2_journal_load(journal);
 	if (status < 0) {
 		mlog_errno(status);
 		if (!igrab(inode))
 			BUG();
-		journal_destroy(journal);
+		jbd2_journal_destroy(journal);
 		goto done;
 	}
 
@@ -1249,9 +1251,9 @@
 
 	/* wipe the journal */
 	mlog(0, "flushing the journal.\n");
-	journal_lock_updates(journal);
-	status = journal_flush(journal);
-	journal_unlock_updates(journal);
+	jbd2_journal_lock_updates(journal);
+	status = jbd2_journal_flush(journal);
+	jbd2_journal_unlock_updates(journal);
 	if (status < 0)
 		mlog_errno(status);
 
@@ -1272,7 +1274,7 @@
 	if (!igrab(inode))
 		BUG();
 
-	journal_destroy(journal);
+	jbd2_journal_destroy(journal);
 
 done:
 	/* drop the lock on this nodes journal */
@@ -1282,8 +1284,7 @@
 	if (inode)
 		iput(inode);
 
-	if (bh)
-		brelse(bh);
+	brelse(bh);
 
 	mlog_exit(status);
 	return status;
diff --git a/fs/ocfs2/journal.h b/fs/ocfs2/journal.h
index 2178ebf..d4d14e9 100644
--- a/fs/ocfs2/journal.h
+++ b/fs/ocfs2/journal.h
@@ -27,7 +27,12 @@
 #define OCFS2_JOURNAL_H
 
 #include <linux/fs.h>
-#include <linux/jbd.h>
+#ifndef CONFIG_OCFS2_COMPAT_JBD
+# include <linux/jbd2.h>
+#else
+# include <linux/jbd.h>
+# include "ocfs2_jbd_compat.h"
+#endif
 
 enum ocfs2_journal_state {
 	OCFS2_JOURNAL_FREE = 0,
@@ -215,8 +220,8 @@
  *                          buffer. Will have to call ocfs2_journal_dirty once
  *                          we've actually dirtied it. Type is one of . or .
  *  ocfs2_journal_dirty    - Mark a journalled buffer as having dirty data.
- *  ocfs2_journal_dirty_data - Indicate that a data buffer should go out before
- *                             the current handle commits.
+ *  ocfs2_jbd2_file_inode  - Mark an inode so that its data goes out before
+ *                           the current handle commits.
  */
 
 /* You must always start_trans with a number of buffs > 0, but it's
@@ -268,8 +273,10 @@
  */
 int                  ocfs2_journal_dirty(handle_t *handle,
 					 struct buffer_head *bh);
+#ifdef CONFIG_OCFS2_COMPAT_JBD
 int                  ocfs2_journal_dirty_data(handle_t *handle,
 					      struct buffer_head *bh);
+#endif
 
 /*
  *  Credit Macros:
@@ -283,6 +290,9 @@
 /* simple file updates like chmod, etc. */
 #define OCFS2_INODE_UPDATE_CREDITS 1
 
+/* extended attribute block update */
+#define OCFS2_XATTR_BLOCK_UPDATE_CREDITS 1
+
 /* group extend. inode update and last group update. */
 #define OCFS2_GROUP_EXTEND_CREDITS	(OCFS2_INODE_UPDATE_CREDITS + 1)
 
@@ -340,11 +350,23 @@
 #define OCFS2_RENAME_CREDITS (3 * OCFS2_INODE_UPDATE_CREDITS + 3              \
 			     + OCFS2_UNLINK_CREDITS)
 
+/* global bitmap dinode, group desc., relinked group,
+ * suballocator dinode, group desc., relinked group,
+ * dinode, xattr block */
+#define OCFS2_XATTR_BLOCK_CREATE_CREDITS (OCFS2_SUBALLOC_ALLOC * 2 + \
+					  + OCFS2_INODE_UPDATE_CREDITS \
+					  + OCFS2_XATTR_BLOCK_UPDATE_CREDITS)
+
+/*
+ * Please note that the caller must make sure that root_el is the root
+ * of extent tree. So for an inode, it should be &fe->id2.i_list. Otherwise
+ * the result may be wrong.
+ */
 static inline int ocfs2_calc_extend_credits(struct super_block *sb,
-					    struct ocfs2_dinode *fe,
+					    struct ocfs2_extent_list *root_el,
 					    u32 bits_wanted)
 {
-	int bitmap_blocks, sysfile_bitmap_blocks, dinode_blocks;
+	int bitmap_blocks, sysfile_bitmap_blocks, extent_blocks;
 
 	/* bitmap dinode, group desc. + relinked group. */
 	bitmap_blocks = OCFS2_SUBALLOC_ALLOC;
@@ -355,16 +377,16 @@
 	 * however many metadata chunks needed * a remaining suballoc
 	 * alloc. */
 	sysfile_bitmap_blocks = 1 +
-		(OCFS2_SUBALLOC_ALLOC - 1) * ocfs2_extend_meta_needed(fe);
+		(OCFS2_SUBALLOC_ALLOC - 1) * ocfs2_extend_meta_needed(root_el);
 
 	/* this does not include *new* metadata blocks, which are
-	 * accounted for in sysfile_bitmap_blocks. fe +
+	 * accounted for in sysfile_bitmap_blocks. root_el +
 	 * prev. last_eb_blk + blocks along edge of tree.
 	 * calc_symlink_credits passes because we just need 1
 	 * credit for the dinode there. */
-	dinode_blocks = 1 + 1 + le16_to_cpu(fe->id2.i_list.l_tree_depth);
+	extent_blocks = 1 + 1 + le16_to_cpu(root_el->l_tree_depth);
 
-	return bitmap_blocks + sysfile_bitmap_blocks + dinode_blocks;
+	return bitmap_blocks + sysfile_bitmap_blocks + extent_blocks;
 }
 
 static inline int ocfs2_calc_symlink_credits(struct super_block *sb)
@@ -415,4 +437,16 @@
 	return credits;
 }
 
+static inline int ocfs2_jbd2_file_inode(handle_t *handle, struct inode *inode)
+{
+	return jbd2_journal_file_inode(handle, &OCFS2_I(inode)->ip_jinode);
+}
+
+static inline int ocfs2_begin_ordered_truncate(struct inode *inode,
+					       loff_t new_size)
+{
+	return jbd2_journal_begin_ordered_truncate(&OCFS2_I(inode)->ip_jinode,
+						   new_size);
+}
+
 #endif /* OCFS2_JOURNAL_H */
diff --git a/fs/ocfs2/localalloc.c b/fs/ocfs2/localalloc.c
index 28e492e..687b287 100644
--- a/fs/ocfs2/localalloc.c
+++ b/fs/ocfs2/localalloc.c
@@ -28,6 +28,7 @@
 #include <linux/slab.h>
 #include <linux/highmem.h>
 #include <linux/bitops.h>
+#include <linux/debugfs.h>
 
 #define MLOG_MASK_PREFIX ML_DISK_ALLOC
 #include <cluster/masklog.h>
@@ -47,8 +48,6 @@
 
 #define OCFS2_LOCAL_ALLOC(dinode)	(&((dinode)->id2.i_lab))
 
-static inline int ocfs2_local_alloc_window_bits(struct ocfs2_super *osb);
-
 static u32 ocfs2_local_alloc_count_bits(struct ocfs2_dinode *alloc);
 
 static int ocfs2_local_alloc_find_clear_bits(struct ocfs2_super *osb,
@@ -75,24 +74,129 @@
 static int ocfs2_local_alloc_slide_window(struct ocfs2_super *osb,
 					  struct inode *local_alloc_inode);
 
-static inline int ocfs2_local_alloc_window_bits(struct ocfs2_super *osb)
-{
-	BUG_ON(osb->s_clustersize_bits > 20);
+#ifdef CONFIG_OCFS2_FS_STATS
 
-	/* Size local alloc windows by the megabyte */
-	return osb->local_alloc_size << (20 - osb->s_clustersize_bits);
+static int ocfs2_la_debug_open(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	return 0;
+}
+
+#define LA_DEBUG_BUF_SZ	PAGE_CACHE_SIZE
+#define LA_DEBUG_VER	1
+static ssize_t ocfs2_la_debug_read(struct file *file, char __user *userbuf,
+				   size_t count, loff_t *ppos)
+{
+	static DEFINE_MUTEX(la_debug_mutex);
+	struct ocfs2_super *osb = file->private_data;
+	int written, ret;
+	char *buf = osb->local_alloc_debug_buf;
+
+	mutex_lock(&la_debug_mutex);
+	memset(buf, 0, LA_DEBUG_BUF_SZ);
+
+	written = snprintf(buf, LA_DEBUG_BUF_SZ,
+			   "0x%x\t0x%llx\t%u\t%u\t0x%x\n",
+			   LA_DEBUG_VER,
+			   (unsigned long long)osb->la_last_gd,
+			   osb->local_alloc_default_bits,
+			   osb->local_alloc_bits, osb->local_alloc_state);
+
+	ret = simple_read_from_buffer(userbuf, count, ppos, buf, written);
+
+	mutex_unlock(&la_debug_mutex);
+	return ret;
+}
+
+static const struct file_operations ocfs2_la_debug_fops = {
+	.open =		ocfs2_la_debug_open,
+	.read =		ocfs2_la_debug_read,
+};
+
+static void ocfs2_init_la_debug(struct ocfs2_super *osb)
+{
+	osb->local_alloc_debug_buf = kmalloc(LA_DEBUG_BUF_SZ, GFP_NOFS);
+	if (!osb->local_alloc_debug_buf)
+		return;
+
+	osb->local_alloc_debug = debugfs_create_file("local_alloc_stats",
+						     S_IFREG|S_IRUSR,
+						     osb->osb_debug_root,
+						     osb,
+						     &ocfs2_la_debug_fops);
+	if (!osb->local_alloc_debug) {
+		kfree(osb->local_alloc_debug_buf);
+		osb->local_alloc_debug_buf = NULL;
+	}
+}
+
+static void ocfs2_shutdown_la_debug(struct ocfs2_super *osb)
+{
+	if (osb->local_alloc_debug)
+		debugfs_remove(osb->local_alloc_debug);
+
+	if (osb->local_alloc_debug_buf)
+		kfree(osb->local_alloc_debug_buf);
+
+	osb->local_alloc_debug_buf = NULL;
+	osb->local_alloc_debug = NULL;
+}
+#else	/* CONFIG_OCFS2_FS_STATS */
+static void ocfs2_init_la_debug(struct ocfs2_super *osb)
+{
+	return;
+}
+static void ocfs2_shutdown_la_debug(struct ocfs2_super *osb)
+{
+	return;
+}
+#endif
+
+static inline int ocfs2_la_state_enabled(struct ocfs2_super *osb)
+{
+	return (osb->local_alloc_state == OCFS2_LA_THROTTLED ||
+		osb->local_alloc_state == OCFS2_LA_ENABLED);
+}
+
+void ocfs2_local_alloc_seen_free_bits(struct ocfs2_super *osb,
+				      unsigned int num_clusters)
+{
+	spin_lock(&osb->osb_lock);
+	if (osb->local_alloc_state == OCFS2_LA_DISABLED ||
+	    osb->local_alloc_state == OCFS2_LA_THROTTLED)
+		if (num_clusters >= osb->local_alloc_default_bits) {
+			cancel_delayed_work(&osb->la_enable_wq);
+			osb->local_alloc_state = OCFS2_LA_ENABLED;
+		}
+	spin_unlock(&osb->osb_lock);
+}
+
+void ocfs2_la_enable_worker(struct work_struct *work)
+{
+	struct ocfs2_super *osb =
+		container_of(work, struct ocfs2_super,
+			     la_enable_wq.work);
+	spin_lock(&osb->osb_lock);
+	osb->local_alloc_state = OCFS2_LA_ENABLED;
+	spin_unlock(&osb->osb_lock);
 }
 
 /*
  * Tell us whether a given allocation should use the local alloc
  * file. Otherwise, it has to go to the main bitmap.
+ *
+ * This function does semi-dirty reads of local alloc size and state!
+ * This is ok however, as the values are re-checked once under mutex.
  */
 int ocfs2_alloc_should_use_local(struct ocfs2_super *osb, u64 bits)
 {
-	int la_bits = ocfs2_local_alloc_window_bits(osb);
 	int ret = 0;
+	int la_bits;
 
-	if (osb->local_alloc_state != OCFS2_LA_ENABLED)
+	spin_lock(&osb->osb_lock);
+	la_bits = osb->local_alloc_bits;
+
+	if (!ocfs2_la_state_enabled(osb))
 		goto bail;
 
 	/* la_bits should be at least twice the size (in clusters) of
@@ -106,6 +210,7 @@
 bail:
 	mlog(0, "state=%d, bits=%llu, la_bits=%d, ret=%d\n",
 	     osb->local_alloc_state, (unsigned long long)bits, la_bits, ret);
+	spin_unlock(&osb->osb_lock);
 	return ret;
 }
 
@@ -120,14 +225,18 @@
 
 	mlog_entry_void();
 
-	if (osb->local_alloc_size == 0)
+	ocfs2_init_la_debug(osb);
+
+	if (osb->local_alloc_bits == 0)
 		goto bail;
 
-	if (ocfs2_local_alloc_window_bits(osb) >= osb->bitmap_cpg) {
+	if (osb->local_alloc_bits >= osb->bitmap_cpg) {
 		mlog(ML_NOTICE, "Requested local alloc window %d is larger "
 		     "than max possible %u. Using defaults.\n",
-		     ocfs2_local_alloc_window_bits(osb), (osb->bitmap_cpg - 1));
-		osb->local_alloc_size = OCFS2_DEFAULT_LOCAL_ALLOC_SIZE;
+		     osb->local_alloc_bits, (osb->bitmap_cpg - 1));
+		osb->local_alloc_bits =
+			ocfs2_megabytes_to_clusters(osb->sb,
+						    OCFS2_DEFAULT_LOCAL_ALLOC_SIZE);
 	}
 
 	/* read the alloc off disk */
@@ -139,8 +248,8 @@
 		goto bail;
 	}
 
-	status = ocfs2_read_block(osb, OCFS2_I(inode)->ip_blkno,
-				  &alloc_bh, 0, inode);
+	status = ocfs2_read_blocks(inode, OCFS2_I(inode)->ip_blkno, 1,
+				   &alloc_bh, OCFS2_BH_IGNORE_CACHE);
 	if (status < 0) {
 		mlog_errno(status);
 		goto bail;
@@ -185,13 +294,14 @@
 
 bail:
 	if (status < 0)
-		if (alloc_bh)
-			brelse(alloc_bh);
+		brelse(alloc_bh);
 	if (inode)
 		iput(inode);
 
-	mlog(0, "Local alloc window bits = %d\n",
-	     ocfs2_local_alloc_window_bits(osb));
+	if (status < 0)
+		ocfs2_shutdown_la_debug(osb);
+
+	mlog(0, "Local alloc window bits = %d\n", osb->local_alloc_bits);
 
 	mlog_exit(status);
 	return status;
@@ -217,6 +327,11 @@
 
 	mlog_entry_void();
 
+	cancel_delayed_work(&osb->la_enable_wq);
+	flush_workqueue(ocfs2_wq);
+
+	ocfs2_shutdown_la_debug(osb);
+
 	if (osb->local_alloc_state == OCFS2_LA_UNUSED)
 		goto out;
 
@@ -295,8 +410,7 @@
 	ocfs2_commit_trans(osb, handle);
 
 out_unlock:
-	if (main_bm_bh)
-		brelse(main_bm_bh);
+	brelse(main_bm_bh);
 
 	ocfs2_inode_unlock(main_bm_inode, 1);
 
@@ -345,8 +459,8 @@
 
 	mutex_lock(&inode->i_mutex);
 
-	status = ocfs2_read_block(osb, OCFS2_I(inode)->ip_blkno,
-				  &alloc_bh, 0, inode);
+	status = ocfs2_read_blocks(inode, OCFS2_I(inode)->ip_blkno, 1,
+				   &alloc_bh, OCFS2_BH_IGNORE_CACHE);
 	if (status < 0) {
 		mlog_errno(status);
 		goto bail;
@@ -372,8 +486,7 @@
 		*alloc_copy = NULL;
 	}
 
-	if (alloc_bh)
-		brelse(alloc_bh);
+	brelse(alloc_bh);
 
 	if (inode) {
 		mutex_unlock(&inode->i_mutex);
@@ -441,8 +554,7 @@
 out_mutex:
 	mutex_unlock(&main_bm_inode->i_mutex);
 
-	if (main_bm_bh)
-		brelse(main_bm_bh);
+	brelse(main_bm_bh);
 
 	iput(main_bm_inode);
 
@@ -453,8 +565,48 @@
 	return status;
 }
 
+/* Check to see if the local alloc window is within ac->ac_max_block */
+static int ocfs2_local_alloc_in_range(struct inode *inode,
+				      struct ocfs2_alloc_context *ac,
+				      u32 bits_wanted)
+{
+	struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+	struct ocfs2_dinode *alloc;
+	struct ocfs2_local_alloc *la;
+	int start;
+	u64 block_off;
+
+	if (!ac->ac_max_block)
+		return 1;
+
+	alloc = (struct ocfs2_dinode *) osb->local_alloc_bh->b_data;
+	la = OCFS2_LOCAL_ALLOC(alloc);
+
+	start = ocfs2_local_alloc_find_clear_bits(osb, alloc, bits_wanted);
+	if (start == -1) {
+		mlog_errno(-ENOSPC);
+		return 0;
+	}
+
+	/*
+	 * Converting (bm_off + start + bits_wanted) to blocks gives us
+	 * the blkno just past our actual allocation.  This is perfect
+	 * to compare with ac_max_block.
+	 */
+	block_off = ocfs2_clusters_to_blocks(inode->i_sb,
+					     le32_to_cpu(la->la_bm_off) +
+					     start + bits_wanted);
+	mlog(0, "Checking %llu against %llu\n",
+	     (unsigned long long)block_off,
+	     (unsigned long long)ac->ac_max_block);
+	if (block_off > ac->ac_max_block)
+		return 0;
+
+	return 1;
+}
+
 /*
- * make sure we've got at least bitswanted contiguous bits in the
+ * make sure we've got at least bits_wanted contiguous bits in the
  * local alloc. You lose them when you drop i_mutex.
  *
  * We will add ourselves to the transaction passed in, but may start
@@ -485,16 +637,18 @@
 
 	mutex_lock(&local_alloc_inode->i_mutex);
 
-	if (osb->local_alloc_state != OCFS2_LA_ENABLED) {
+	/*
+	 * We must double check state and allocator bits because
+	 * another process may have changed them while holding i_mutex.
+	 */
+	spin_lock(&osb->osb_lock);
+	if (!ocfs2_la_state_enabled(osb) ||
+	    (bits_wanted > osb->local_alloc_bits)) {
+		spin_unlock(&osb->osb_lock);
 		status = -ENOSPC;
 		goto bail;
 	}
-
-	if (bits_wanted > ocfs2_local_alloc_window_bits(osb)) {
-		mlog(0, "Asking for more than my max window size!\n");
-		status = -ENOSPC;
-		goto bail;
-	}
+	spin_unlock(&osb->osb_lock);
 
 	alloc = (struct ocfs2_dinode *) osb->local_alloc_bh->b_data;
 
@@ -522,6 +676,36 @@
 				mlog_errno(status);
 			goto bail;
 		}
+
+		/*
+		 * Under certain conditions, the window slide code
+		 * might have reduced the number of bits available or
+		 * disabled the the local alloc entirely. Re-check
+		 * here and return -ENOSPC if necessary.
+		 */
+		status = -ENOSPC;
+		if (!ocfs2_la_state_enabled(osb))
+			goto bail;
+
+		free_bits = le32_to_cpu(alloc->id1.bitmap1.i_total) -
+			le32_to_cpu(alloc->id1.bitmap1.i_used);
+		if (bits_wanted > free_bits)
+			goto bail;
+	}
+
+	if (ac->ac_max_block)
+		mlog(0, "Calling in_range for max block %llu\n",
+		     (unsigned long long)ac->ac_max_block);
+
+	if (!ocfs2_local_alloc_in_range(local_alloc_inode, ac,
+					bits_wanted)) {
+		/*
+		 * The window is outside ac->ac_max_block.
+		 * This errno tells the caller to keep localalloc enabled
+		 * but to get the allocation from the main bitmap.
+		 */
+		status = -EFBIG;
+		goto bail;
 	}
 
 	ac->ac_inode = local_alloc_inode;
@@ -789,6 +973,85 @@
 	return status;
 }
 
+enum ocfs2_la_event {
+	OCFS2_LA_EVENT_SLIDE,		/* Normal window slide. */
+	OCFS2_LA_EVENT_FRAGMENTED,	/* The global bitmap has
+					 * enough bits theoretically
+					 * free, but a contiguous
+					 * allocation could not be
+					 * found. */
+	OCFS2_LA_EVENT_ENOSPC,		/* Global bitmap doesn't have
+					 * enough bits free to satisfy
+					 * our request. */
+};
+#define OCFS2_LA_ENABLE_INTERVAL (30 * HZ)
+/*
+ * Given an event, calculate the size of our next local alloc window.
+ *
+ * This should always be called under i_mutex of the local alloc inode
+ * so that local alloc disabling doesn't race with processes trying to
+ * use the allocator.
+ *
+ * Returns the state which the local alloc was left in. This value can
+ * be ignored by some paths.
+ */
+static int ocfs2_recalc_la_window(struct ocfs2_super *osb,
+				  enum ocfs2_la_event event)
+{
+	unsigned int bits;
+	int state;
+
+	spin_lock(&osb->osb_lock);
+	if (osb->local_alloc_state == OCFS2_LA_DISABLED) {
+		WARN_ON_ONCE(osb->local_alloc_state == OCFS2_LA_DISABLED);
+		goto out_unlock;
+	}
+
+	/*
+	 * ENOSPC and fragmentation are treated similarly for now.
+	 */
+	if (event == OCFS2_LA_EVENT_ENOSPC ||
+	    event == OCFS2_LA_EVENT_FRAGMENTED) {
+		/*
+		 * We ran out of contiguous space in the primary
+		 * bitmap. Drastically reduce the number of bits used
+		 * by local alloc until we have to disable it.
+		 */
+		bits = osb->local_alloc_bits >> 1;
+		if (bits > ocfs2_megabytes_to_clusters(osb->sb, 1)) {
+			/*
+			 * By setting state to THROTTLED, we'll keep
+			 * the number of local alloc bits used down
+			 * until an event occurs which would give us
+			 * reason to assume the bitmap situation might
+			 * have changed.
+			 */
+			osb->local_alloc_state = OCFS2_LA_THROTTLED;
+			osb->local_alloc_bits = bits;
+		} else {
+			osb->local_alloc_state = OCFS2_LA_DISABLED;
+		}
+		queue_delayed_work(ocfs2_wq, &osb->la_enable_wq,
+				   OCFS2_LA_ENABLE_INTERVAL);
+		goto out_unlock;
+	}
+
+	/*
+	 * Don't increase the size of the local alloc window until we
+	 * know we might be able to fulfill the request. Otherwise, we
+	 * risk bouncing around the global bitmap during periods of
+	 * low space.
+	 */
+	if (osb->local_alloc_state != OCFS2_LA_THROTTLED)
+		osb->local_alloc_bits = osb->local_alloc_default_bits;
+
+out_unlock:
+	state = osb->local_alloc_state;
+	spin_unlock(&osb->osb_lock);
+
+	return state;
+}
+
 static int ocfs2_local_alloc_reserve_for_window(struct ocfs2_super *osb,
 						struct ocfs2_alloc_context **ac,
 						struct inode **bitmap_inode,
@@ -803,12 +1066,21 @@
 		goto bail;
 	}
 
-	(*ac)->ac_bits_wanted = ocfs2_local_alloc_window_bits(osb);
+retry_enospc:
+	(*ac)->ac_bits_wanted = osb->local_alloc_bits;
 
 	status = ocfs2_reserve_cluster_bitmap_bits(osb, *ac);
+	if (status == -ENOSPC) {
+		if (ocfs2_recalc_la_window(osb, OCFS2_LA_EVENT_ENOSPC) ==
+		    OCFS2_LA_DISABLED)
+			goto bail;
+
+		ocfs2_free_ac_resource(*ac);
+		memset(*ac, 0, sizeof(struct ocfs2_alloc_context));
+		goto retry_enospc;
+	}
 	if (status < 0) {
-		if (status != -ENOSPC)
-			mlog_errno(status);
+		mlog_errno(status);
 		goto bail;
 	}
 
@@ -849,7 +1121,7 @@
 		     "one\n");
 
 	mlog(0, "Allocating %u clusters for a new window.\n",
-	     ocfs2_local_alloc_window_bits(osb));
+	     osb->local_alloc_bits);
 
 	/* Instruct the allocation code to try the most recently used
 	 * cluster group. We'll re-record the group used this pass
@@ -859,9 +1131,36 @@
 	/* we used the generic suballoc reserve function, but we set
 	 * everything up nicely, so there's no reason why we can't use
 	 * the more specific cluster api to claim bits. */
-	status = ocfs2_claim_clusters(osb, handle, ac,
-				      ocfs2_local_alloc_window_bits(osb),
+	status = ocfs2_claim_clusters(osb, handle, ac, osb->local_alloc_bits,
 				      &cluster_off, &cluster_count);
+	if (status == -ENOSPC) {
+retry_enospc:
+		/*
+		 * Note: We could also try syncing the journal here to
+		 * allow use of any free bits which the current
+		 * transaction can't give us access to. --Mark
+		 */
+		if (ocfs2_recalc_la_window(osb, OCFS2_LA_EVENT_FRAGMENTED) ==
+		    OCFS2_LA_DISABLED)
+			goto bail;
+
+		status = ocfs2_claim_clusters(osb, handle, ac,
+					      osb->local_alloc_bits,
+					      &cluster_off,
+					      &cluster_count);
+		if (status == -ENOSPC)
+			goto retry_enospc;
+		/*
+		 * We only shrunk the *minimum* number of in our
+		 * request - it's entirely possible that the allocator
+		 * might give us more than we asked for.
+		 */
+		if (status == 0) {
+			spin_lock(&osb->osb_lock);
+			osb->local_alloc_bits = cluster_count;
+			spin_unlock(&osb->osb_lock);
+		}
+	}
 	if (status < 0) {
 		if (status != -ENOSPC)
 			mlog_errno(status);
@@ -905,6 +1204,8 @@
 
 	mlog_entry_void();
 
+	ocfs2_recalc_la_window(osb, OCFS2_LA_EVENT_SLIDE);
+
 	/* This will lock the main bitmap for us. */
 	status = ocfs2_local_alloc_reserve_for_window(osb,
 						      &ac,
@@ -976,8 +1277,7 @@
 	if (handle)
 		ocfs2_commit_trans(osb, handle);
 
-	if (main_bm_bh)
-		brelse(main_bm_bh);
+	brelse(main_bm_bh);
 
 	if (main_bm_inode)
 		iput(main_bm_inode);
diff --git a/fs/ocfs2/localalloc.h b/fs/ocfs2/localalloc.h
index 3f76631..ac5ea9f8 100644
--- a/fs/ocfs2/localalloc.h
+++ b/fs/ocfs2/localalloc.h
@@ -52,4 +52,8 @@
 				 u32 *bit_off,
 				 u32 *num_bits);
 
+void ocfs2_local_alloc_seen_free_bits(struct ocfs2_super *osb,
+				      unsigned int num_clusters);
+void ocfs2_la_enable_worker(struct work_struct *work);
+
 #endif /* OCFS2_LOCALALLOC_H */
diff --git a/fs/ocfs2/locks.c b/fs/ocfs2/locks.c
index 203f871..544ac62 100644
--- a/fs/ocfs2/locks.c
+++ b/fs/ocfs2/locks.c
@@ -24,6 +24,7 @@
  */
 
 #include <linux/fs.h>
+#include <linux/fcntl.h>
 
 #define MLOG_MASK_PREFIX ML_INODE
 #include <cluster/masklog.h>
@@ -32,6 +33,7 @@
 
 #include "dlmglue.h"
 #include "file.h"
+#include "inode.h"
 #include "locks.h"
 
 static int ocfs2_do_flock(struct file *file, struct inode *inode,
@@ -123,3 +125,16 @@
 	else
 		return ocfs2_do_flock(file, inode, cmd, fl);
 }
+
+int ocfs2_lock(struct file *file, int cmd, struct file_lock *fl)
+{
+	struct inode *inode = file->f_mapping->host;
+	struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+
+	if (!(fl->fl_flags & FL_POSIX))
+		return -ENOLCK;
+	if (__mandatory_lock(inode))
+		return -ENOLCK;
+
+	return ocfs2_plock(osb->cconn, OCFS2_I(inode)->ip_blkno, file, cmd, fl);
+}
diff --git a/fs/ocfs2/locks.h b/fs/ocfs2/locks.h
index 9743ef2..496d488 100644
--- a/fs/ocfs2/locks.h
+++ b/fs/ocfs2/locks.h
@@ -27,5 +27,6 @@
 #define OCFS2_LOCKS_H
 
 int ocfs2_flock(struct file *file, int cmd, struct file_lock *fl);
+int ocfs2_lock(struct file *file, int cmd, struct file_lock *fl);
 
 #endif /* OCFS2_LOCKS_H */
diff --git a/fs/ocfs2/namei.c b/fs/ocfs2/namei.c
index d5d808f..485a6aa 100644
--- a/fs/ocfs2/namei.c
+++ b/fs/ocfs2/namei.c
@@ -60,6 +60,7 @@
 #include "symlink.h"
 #include "sysfile.h"
 #include "uptodate.h"
+#include "xattr.h"
 
 #include "buffer_head_io.h"
 
@@ -327,14 +328,9 @@
 	if (status == -ENOSPC)
 		mlog(0, "Disk is full\n");
 
-	if (new_fe_bh)
-		brelse(new_fe_bh);
-
-	if (de_bh)
-		brelse(de_bh);
-
-	if (parent_fe_bh)
-		brelse(parent_fe_bh);
+	brelse(new_fe_bh);
+	brelse(de_bh);
+	brelse(parent_fe_bh);
 
 	if ((status < 0) && inode)
 		iput(inode);
@@ -647,12 +643,9 @@
 out:
 	ocfs2_inode_unlock(dir, 1);
 
-	if (de_bh)
-		brelse(de_bh);
-	if (fe_bh)
-		brelse(fe_bh);
-	if (parent_fe_bh)
-		brelse(parent_fe_bh);
+	brelse(de_bh);
+	brelse(fe_bh);
+	brelse(parent_fe_bh);
 
 	mlog_exit(err);
 
@@ -851,17 +844,10 @@
 		iput(orphan_dir);
 	}
 
-	if (fe_bh)
-		brelse(fe_bh);
-
-	if (dirent_bh)
-		brelse(dirent_bh);
-
-	if (parent_node_bh)
-		brelse(parent_node_bh);
-
-	if (orphan_entry_bh)
-		brelse(orphan_entry_bh);
+	brelse(fe_bh);
+	brelse(dirent_bh);
+	brelse(parent_node_bh);
+	brelse(orphan_entry_bh);
 
 	mlog_exit(status);
 
@@ -1372,24 +1358,15 @@
 
 	if (new_inode)
 		iput(new_inode);
-	if (newfe_bh)
-		brelse(newfe_bh);
-	if (old_inode_bh)
-		brelse(old_inode_bh);
-	if (old_dir_bh)
-		brelse(old_dir_bh);
-	if (new_dir_bh)
-		brelse(new_dir_bh);
-	if (new_de_bh)
-		brelse(new_de_bh);
-	if (old_de_bh)
-		brelse(old_de_bh);
-	if (old_inode_de_bh)
-		brelse(old_inode_de_bh);
-	if (orphan_entry_bh)
-		brelse(orphan_entry_bh);
-	if (insert_entry_bh)
-		brelse(insert_entry_bh);
+	brelse(newfe_bh);
+	brelse(old_inode_bh);
+	brelse(old_dir_bh);
+	brelse(new_dir_bh);
+	brelse(new_de_bh);
+	brelse(old_de_bh);
+	brelse(old_inode_de_bh);
+	brelse(orphan_entry_bh);
+	brelse(insert_entry_bh);
 
 	mlog_exit(status);
 
@@ -1492,8 +1469,7 @@
 
 	if (bhs) {
 		for(i = 0; i < blocks; i++)
-			if (bhs[i])
-				brelse(bhs[i]);
+			brelse(bhs[i]);
 		kfree(bhs);
 	}
 
@@ -1598,10 +1574,10 @@
 		u32 offset = 0;
 
 		inode->i_op = &ocfs2_symlink_inode_operations;
-		status = ocfs2_do_extend_allocation(osb, inode, &offset, 1, 0,
-						    new_fe_bh,
-						    handle, data_ac, NULL,
-						    NULL);
+		status = ocfs2_add_inode_data(osb, inode, &offset, 1, 0,
+					      new_fe_bh,
+					      handle, data_ac, NULL,
+					      NULL);
 		if (status < 0) {
 			if (status != -ENOSPC && status != -EINTR) {
 				mlog(ML_ERROR,
@@ -1659,12 +1635,9 @@
 
 	ocfs2_inode_unlock(dir, 1);
 
-	if (new_fe_bh)
-		brelse(new_fe_bh);
-	if (parent_fe_bh)
-		brelse(parent_fe_bh);
-	if (de_bh)
-		brelse(de_bh);
+	brelse(new_fe_bh);
+	brelse(parent_fe_bh);
+	brelse(de_bh);
 	if (inode_ac)
 		ocfs2_free_alloc_context(inode_ac);
 	if (data_ac)
@@ -1759,8 +1732,7 @@
 		iput(orphan_dir_inode);
 	}
 
-	if (orphan_dir_bh)
-		brelse(orphan_dir_bh);
+	brelse(orphan_dir_bh);
 
 	mlog_exit(status);
 	return status;
@@ -1780,10 +1752,9 @@
 
 	mlog_entry("(inode->i_ino = %lu)\n", inode->i_ino);
 
-	status = ocfs2_read_block(osb,
+	status = ocfs2_read_block(orphan_dir_inode,
 				  OCFS2_I(orphan_dir_inode)->ip_blkno,
-				  &orphan_dir_bh, OCFS2_BH_CACHED,
-				  orphan_dir_inode);
+				  &orphan_dir_bh);
 	if (status < 0) {
 		mlog_errno(status);
 		goto leave;
@@ -1829,8 +1800,7 @@
 	     (unsigned long long)OCFS2_I(inode)->ip_blkno, osb->slot_num);
 
 leave:
-	if (orphan_dir_bh)
-		brelse(orphan_dir_bh);
+	brelse(orphan_dir_bh);
 
 	mlog_exit(status);
 	return status;
@@ -1898,8 +1868,7 @@
 	}
 
 leave:
-	if (target_de_bh)
-		brelse(target_de_bh);
+	brelse(target_de_bh);
 
 	mlog_exit(status);
 	return status;
@@ -1918,4 +1887,8 @@
 	.setattr	= ocfs2_setattr,
 	.getattr	= ocfs2_getattr,
 	.permission	= ocfs2_permission,
+	.setxattr	= generic_setxattr,
+	.getxattr	= generic_getxattr,
+	.listxattr	= ocfs2_listxattr,
+	.removexattr	= generic_removexattr,
 };
diff --git a/fs/ocfs2/ocfs2.h b/fs/ocfs2/ocfs2.h
index 7f625f2..a21a465 100644
--- a/fs/ocfs2/ocfs2.h
+++ b/fs/ocfs2/ocfs2.h
@@ -34,7 +34,12 @@
 #include <linux/workqueue.h>
 #include <linux/kref.h>
 #include <linux/mutex.h>
-#include <linux/jbd.h>
+#ifndef CONFIG_OCFS2_COMPAT_JBD
+# include <linux/jbd2.h>
+#else
+# include <linux/jbd.h>
+# include "ocfs2_jbd_compat.h"
+#endif
 
 /* For union ocfs2_dlm_lksb */
 #include "stackglue.h"
@@ -171,9 +176,13 @@
 
 enum ocfs2_local_alloc_state
 {
-	OCFS2_LA_UNUSED = 0,
-	OCFS2_LA_ENABLED,
-	OCFS2_LA_DISABLED
+	OCFS2_LA_UNUSED = 0,	/* Local alloc will never be used for
+				 * this mountpoint. */
+	OCFS2_LA_ENABLED,	/* Local alloc is in use. */
+	OCFS2_LA_THROTTLED,	/* Local alloc is in use, but number
+				 * of bits has been reduced. */
+	OCFS2_LA_DISABLED	/* Local alloc has temporarily been
+				 * disabled. */
 };
 
 enum ocfs2_mount_options
@@ -184,6 +193,8 @@
 	OCFS2_MOUNT_ERRORS_PANIC = 1 << 3, /* Panic on errors */
 	OCFS2_MOUNT_DATA_WRITEBACK = 1 << 4, /* No data ordering */
 	OCFS2_MOUNT_LOCALFLOCKS = 1 << 5, /* No cluster aware user file locks */
+	OCFS2_MOUNT_NOUSERXATTR = 1 << 6, /* No user xattr */
+	OCFS2_MOUNT_INODE64 = 1 << 7,	/* Allow inode numbers > 2^32 */
 };
 
 #define OCFS2_OSB_SOFT_RO	0x0001
@@ -214,6 +225,7 @@
 	u32 bitmap_cpg;
 	u8 *uuid;
 	char *uuid_str;
+	u32 uuid_hash;
 	u8 *vol_label;
 	u64 first_cluster_group_blkno;
 	u32 fs_generation;
@@ -241,6 +253,7 @@
 	int s_sectsize_bits;
 	int s_clustersize;
 	int s_clustersize_bits;
+	unsigned int s_xattr_inline_size;
 
 	atomic_t vol_state;
 	struct mutex recovery_lock;
@@ -252,11 +265,27 @@
 	struct ocfs2_journal *journal;
 	unsigned long osb_commit_interval;
 
-	int local_alloc_size;
-	enum ocfs2_local_alloc_state local_alloc_state;
+	struct delayed_work		la_enable_wq;
+
+	/*
+	 * Must hold local alloc i_mutex and osb->osb_lock to change
+	 * local_alloc_bits. Reads can be done under either lock.
+	 */
+	unsigned int local_alloc_bits;
+	unsigned int local_alloc_default_bits;
+
+	enum ocfs2_local_alloc_state local_alloc_state; /* protected
+							 * by osb_lock */
+
 	struct buffer_head *local_alloc_bh;
+
 	u64 la_last_gd;
 
+#ifdef CONFIG_OCFS2_FS_STATS
+	struct dentry *local_alloc_debug;
+	char *local_alloc_debug_buf;
+#endif
+
 	/* Next two fields are for local node slot recovery during
 	 * mount. */
 	int dirty;
@@ -340,6 +369,13 @@
 	return 0;
 }
 
+static inline int ocfs2_supports_xattr(struct ocfs2_super *osb)
+{
+	if (osb->s_feature_incompat & OCFS2_FEATURE_INCOMPAT_XATTR)
+		return 1;
+	return 0;
+}
+
 /* set / clear functions because cluster events can make these happen
  * in parallel so we want the transitions to be atomic. this also
  * means that any future flags osb_flags must be protected by spinlock
@@ -554,6 +590,14 @@
 	return pages_per_cluster;
 }
 
+static inline unsigned int ocfs2_megabytes_to_clusters(struct super_block *sb,
+						       unsigned int megs)
+{
+	BUILD_BUG_ON(OCFS2_MAX_CLUSTERSIZE > 1048576);
+
+	return megs << (20 - OCFS2_SB(sb)->s_clustersize_bits);
+}
+
 static inline void ocfs2_init_inode_steal_slot(struct ocfs2_super *osb)
 {
 	spin_lock(&osb->osb_lock);
diff --git a/fs/ocfs2/ocfs2_fs.h b/fs/ocfs2/ocfs2_fs.h
index 4f61985..f24ce3d 100644
--- a/fs/ocfs2/ocfs2_fs.h
+++ b/fs/ocfs2/ocfs2_fs.h
@@ -64,6 +64,7 @@
 #define OCFS2_INODE_SIGNATURE		"INODE01"
 #define OCFS2_EXTENT_BLOCK_SIGNATURE	"EXBLK01"
 #define OCFS2_GROUP_DESC_SIGNATURE      "GROUP01"
+#define OCFS2_XATTR_BLOCK_SIGNATURE	"XATTR01"
 
 /* Compatibility flags */
 #define OCFS2_HAS_COMPAT_FEATURE(sb,mask)			\
@@ -90,7 +91,8 @@
 					 | OCFS2_FEATURE_INCOMPAT_SPARSE_ALLOC \
 					 | OCFS2_FEATURE_INCOMPAT_INLINE_DATA \
 					 | OCFS2_FEATURE_INCOMPAT_EXTENDED_SLOT_MAP \
-					 | OCFS2_FEATURE_INCOMPAT_USERSPACE_STACK)
+					 | OCFS2_FEATURE_INCOMPAT_USERSPACE_STACK \
+					 | OCFS2_FEATURE_INCOMPAT_XATTR)
 #define OCFS2_FEATURE_RO_COMPAT_SUPP	OCFS2_FEATURE_RO_COMPAT_UNWRITTEN
 
 /*
@@ -127,10 +129,6 @@
 /* Support for data packed into inode blocks */
 #define OCFS2_FEATURE_INCOMPAT_INLINE_DATA	0x0040
 
-/* Support for the extended slot map */
-#define OCFS2_FEATURE_INCOMPAT_EXTENDED_SLOT_MAP 0x100
-
-
 /*
  * Support for alternate, userspace cluster stacks.  If set, the superblock
  * field s_cluster_info contains a tag for the alternate stack in use as
@@ -142,6 +140,12 @@
  */
 #define OCFS2_FEATURE_INCOMPAT_USERSPACE_STACK	0x0080
 
+/* Support for the extended slot map */
+#define OCFS2_FEATURE_INCOMPAT_EXTENDED_SLOT_MAP 0x100
+
+/* Support for extended attributes */
+#define OCFS2_FEATURE_INCOMPAT_XATTR		0x0200
+
 /*
  * backup superblock flag is used to indicate that this volume
  * has backup superblocks.
@@ -299,6 +303,12 @@
  */
 #define OCFS2_DEFAULT_LOCAL_ALLOC_SIZE	8
 
+/*
+ * Inline extended attribute size (in bytes)
+ * The value chosen should be aligned to 16 byte boundaries.
+ */
+#define OCFS2_MIN_XATTR_INLINE_SIZE     256
+
 struct ocfs2_system_inode_info {
 	char	*si_name;
 	int	si_iflags;
@@ -563,7 +573,7 @@
 /*40*/	__le16 s_max_slots;		/* Max number of simultaneous mounts
 					   before tunefs required */
 	__le16 s_tunefs_flag;
-	__le32 s_reserved1;
+	__le32 s_uuid_hash;		/* hash value of uuid */
 	__le64 s_first_cluster_group;	/* Block offset of 1st cluster
 					 * group header */
 /*50*/	__u8  s_label[OCFS2_MAX_VOL_LABEL_LEN];	/* Label for mounting, etc. */
@@ -571,7 +581,11 @@
 /*A0*/  struct ocfs2_cluster_info s_cluster_info; /* Selected userspace
 						     stack.  Only valid
 						     with INCOMPAT flag. */
-/*B8*/  __le64 s_reserved2[17];		/* Fill out superblock */
+/*B8*/	__le16 s_xattr_inline_size;	/* extended attribute inline size
+					   for this fs*/
+	__le16 s_reserved0;
+	__le32 s_reserved1;
+/*C0*/  __le64 s_reserved2[16];		/* Fill out superblock */
 /*140*/
 
 	/*
@@ -621,7 +635,8 @@
 					   belongs to */
 	__le16 i_suballoc_bit;		/* Bit offset in suballocator
 					   block group */
-/*10*/	__le32 i_reserved0;
+/*10*/	__le16 i_reserved0;
+	__le16 i_xattr_inline_size;
 	__le32 i_clusters;		/* Cluster count */
 	__le32 i_uid;			/* Owner UID */
 	__le32 i_gid;			/* Owning GID */
@@ -640,11 +655,12 @@
 	__le32 i_atime_nsec;
 	__le32 i_ctime_nsec;
 	__le32 i_mtime_nsec;
-	__le32 i_attr;
+/*70*/	__le32 i_attr;
 	__le16 i_orphaned_slot;		/* Only valid when OCFS2_ORPHANED_FL
 					   was set in i_flags */
 	__le16 i_dyn_features;
-/*70*/	__le64 i_reserved2[8];
+	__le64 i_xattr_loc;
+/*80*/	__le64 i_reserved2[7];
 /*B8*/	union {
 		__le64 i_pad1;		/* Generic way to refer to this
 					   64bit union */
@@ -715,6 +731,136 @@
 /*40*/	__u8    bg_bitmap[0];
 };
 
+/*
+ * On disk extended attribute structure for OCFS2.
+ */
+
+/*
+ * ocfs2_xattr_entry indicates one extend attribute.
+ *
+ * Note that it can be stored in inode, one block or one xattr bucket.
+ */
+struct ocfs2_xattr_entry {
+	__le32	xe_name_hash;    /* hash value of xattr prefix+suffix. */
+	__le16	xe_name_offset;  /* byte offset from the 1st etnry in the local
+				    local xattr storage(inode, xattr block or
+				    xattr bucket). */
+	__u8	xe_name_len;	 /* xattr name len, does't include prefix. */
+	__u8	xe_type;         /* the low 7 bits indicates the name prefix's
+				  * type and the highest 1 bits indicate whether
+				  * the EA is stored in the local storage. */
+	__le64	xe_value_size;	 /* real xattr value length. */
+};
+
+/*
+ * On disk structure for xattr header.
+ *
+ * One ocfs2_xattr_header describes how many ocfs2_xattr_entry records in
+ * the local xattr storage.
+ */
+struct ocfs2_xattr_header {
+	__le16	xh_count;                       /* contains the count of how
+						   many records are in the
+						   local xattr storage. */
+	__le16	xh_free_start;                  /* current offset for storing
+						   xattr. */
+	__le16	xh_name_value_len;              /* total length of name/value
+						   length in this bucket. */
+	__le16	xh_num_buckets;                 /* bucket nums in one extent
+						   record, only valid in the
+						   first bucket. */
+	__le64  xh_csum;
+	struct ocfs2_xattr_entry xh_entries[0]; /* xattr entry list. */
+};
+
+/*
+ * On disk structure for xattr value root.
+ *
+ * It is used when one extended attribute's size is larger, and we will save it
+ * in an outside cluster. It will stored in a b-tree like file content.
+ */
+struct ocfs2_xattr_value_root {
+/*00*/	__le32	xr_clusters;              /* clusters covered by xattr value. */
+	__le32	xr_reserved0;
+	__le64	xr_last_eb_blk;           /* Pointer to last extent block */
+/*10*/	struct ocfs2_extent_list xr_list; /* Extent record list */
+};
+
+/*
+ * On disk structure for xattr tree root.
+ *
+ * It is used when there are too many extended attributes for one file. These
+ * attributes will be organized and stored in an indexed-btree.
+ */
+struct ocfs2_xattr_tree_root {
+/*00*/	__le32	xt_clusters;              /* clusters covered by xattr. */
+	__le32	xt_reserved0;
+	__le64	xt_last_eb_blk;           /* Pointer to last extent block */
+/*10*/	struct ocfs2_extent_list xt_list; /* Extent record list */
+};
+
+#define OCFS2_XATTR_INDEXED	0x1
+#define OCFS2_HASH_SHIFT	5
+#define OCFS2_XATTR_ROUND	3
+#define OCFS2_XATTR_SIZE(size)	(((size) + OCFS2_XATTR_ROUND) & \
+				~(OCFS2_XATTR_ROUND))
+
+#define OCFS2_XATTR_BUCKET_SIZE			4096
+#define OCFS2_XATTR_MAX_BLOCKS_PER_BUCKET 	(OCFS2_XATTR_BUCKET_SIZE \
+						 / OCFS2_MIN_BLOCKSIZE)
+
+/*
+ * On disk structure for xattr block.
+ */
+struct ocfs2_xattr_block {
+/*00*/	__u8	xb_signature[8];     /* Signature for verification */
+	__le16	xb_suballoc_slot;    /* Slot suballocator this
+					block belongs to. */
+	__le16	xb_suballoc_bit;     /* Bit offset in suballocator
+					block group */
+	__le32	xb_fs_generation;    /* Must match super block */
+/*10*/	__le64	xb_blkno;            /* Offset on disk, in blocks */
+	__le64	xb_csum;
+/*20*/	__le16	xb_flags;            /* Indicates whether this block contains
+					real xattr or a xattr tree. */
+	__le16	xb_reserved0;
+	__le32  xb_reserved1;
+	__le64	xb_reserved2;
+/*30*/	union {
+		struct ocfs2_xattr_header xb_header; /* xattr header if this
+							block contains xattr */
+		struct ocfs2_xattr_tree_root xb_root;/* xattr tree root if this
+							block cotains xattr
+							tree. */
+	} xb_attrs;
+};
+
+#define OCFS2_XATTR_ENTRY_LOCAL		0x80
+#define OCFS2_XATTR_TYPE_MASK		0x7F
+static inline void ocfs2_xattr_set_local(struct ocfs2_xattr_entry *xe,
+					 int local)
+{
+	if (local)
+		xe->xe_type |= OCFS2_XATTR_ENTRY_LOCAL;
+	else
+		xe->xe_type &= ~OCFS2_XATTR_ENTRY_LOCAL;
+}
+
+static inline int ocfs2_xattr_is_local(struct ocfs2_xattr_entry *xe)
+{
+	return xe->xe_type & OCFS2_XATTR_ENTRY_LOCAL;
+}
+
+static inline void ocfs2_xattr_set_type(struct ocfs2_xattr_entry *xe, int type)
+{
+	xe->xe_type |= type & OCFS2_XATTR_TYPE_MASK;
+}
+
+static inline int ocfs2_xattr_get_type(struct ocfs2_xattr_entry *xe)
+{
+	return xe->xe_type & OCFS2_XATTR_TYPE_MASK;
+}
+
 #ifdef __KERNEL__
 static inline int ocfs2_fast_symlink_chars(struct super_block *sb)
 {
@@ -728,6 +874,20 @@
 		offsetof(struct ocfs2_dinode, id2.i_data.id_data);
 }
 
+static inline int ocfs2_max_inline_data_with_xattr(struct super_block *sb,
+						   struct ocfs2_dinode *di)
+{
+	unsigned int xattrsize = le16_to_cpu(di->i_xattr_inline_size);
+
+	if (le16_to_cpu(di->i_dyn_features) & OCFS2_INLINE_XATTR_FL)
+		return sb->s_blocksize -
+			offsetof(struct ocfs2_dinode, id2.i_data.id_data) -
+			xattrsize;
+	else
+		return sb->s_blocksize -
+			offsetof(struct ocfs2_dinode, id2.i_data.id_data);
+}
+
 static inline int ocfs2_extent_recs_per_inode(struct super_block *sb)
 {
 	int size;
@@ -738,6 +898,24 @@
 	return size / sizeof(struct ocfs2_extent_rec);
 }
 
+static inline int ocfs2_extent_recs_per_inode_with_xattr(
+						struct super_block *sb,
+						struct ocfs2_dinode *di)
+{
+	int size;
+	unsigned int xattrsize = le16_to_cpu(di->i_xattr_inline_size);
+
+	if (le16_to_cpu(di->i_dyn_features) & OCFS2_INLINE_XATTR_FL)
+		size = sb->s_blocksize -
+			offsetof(struct ocfs2_dinode, id2.i_list.l_recs) -
+			xattrsize;
+	else
+		size = sb->s_blocksize -
+			offsetof(struct ocfs2_dinode, id2.i_list.l_recs);
+
+	return size / sizeof(struct ocfs2_extent_rec);
+}
+
 static inline int ocfs2_chain_recs_per_inode(struct super_block *sb)
 {
 	int size;
@@ -801,6 +979,17 @@
 	return 0;
 
 }
+
+static inline u16 ocfs2_xattr_recs_per_xb(struct super_block *sb)
+{
+	int size;
+
+	size = sb->s_blocksize -
+		offsetof(struct ocfs2_xattr_block,
+			 xb_attrs.xb_root.xt_list.l_recs);
+
+	return size / sizeof(struct ocfs2_extent_rec);
+}
 #else
 static inline int ocfs2_fast_symlink_chars(int blocksize)
 {
@@ -884,6 +1073,17 @@
 
 	return 0;
 }
+
+static inline int ocfs2_xattr_recs_per_xb(int blocksize)
+{
+	int size;
+
+	size = blocksize -
+		offsetof(struct ocfs2_xattr_block,
+			 xb_attrs.xb_root.xt_list.l_recs);
+
+	return size / sizeof(struct ocfs2_extent_rec);
+}
 #endif  /* __KERNEL__ */
 
 
diff --git a/fs/ocfs2/ocfs2_jbd_compat.h b/fs/ocfs2/ocfs2_jbd_compat.h
new file mode 100644
index 0000000..b91c78f
--- /dev/null
+++ b/fs/ocfs2/ocfs2_jbd_compat.h
@@ -0,0 +1,82 @@
+/* -*- mode: c; c-basic-offset: 8; -*-
+ * vim: noexpandtab sw=8 ts=8 sts=0:
+ *
+ * ocfs2_jbd_compat.h
+ *
+ * Compatibility defines for JBD.
+ *
+ * Copyright (C) 2008 Oracle.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License 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.
+ */
+
+#ifndef OCFS2_JBD_COMPAT_H
+#define OCFS2_JBD_COMPAT_H
+
+#ifndef CONFIG_OCFS2_COMPAT_JBD
+# error Should not have been included
+#endif
+
+struct jbd2_inode {
+	unsigned int dummy;
+};
+
+#define JBD2_BARRIER			JFS_BARRIER
+#define JBD2_DEFAULT_MAX_COMMIT_AGE	JBD_DEFAULT_MAX_COMMIT_AGE
+
+#define jbd2_journal_ack_err			journal_ack_err
+#define jbd2_journal_clear_err			journal_clear_err
+#define jbd2_journal_destroy			journal_destroy
+#define jbd2_journal_dirty_metadata		journal_dirty_metadata
+#define jbd2_journal_errno			journal_errno
+#define jbd2_journal_extend			journal_extend
+#define jbd2_journal_flush			journal_flush
+#define jbd2_journal_force_commit		journal_force_commit
+#define jbd2_journal_get_write_access		journal_get_write_access
+#define jbd2_journal_get_undo_access		journal_get_undo_access
+#define jbd2_journal_init_inode			journal_init_inode
+#define jbd2_journal_invalidatepage		journal_invalidatepage
+#define jbd2_journal_load			journal_load
+#define jbd2_journal_lock_updates		journal_lock_updates
+#define jbd2_journal_restart			journal_restart
+#define jbd2_journal_start			journal_start
+#define jbd2_journal_start_commit		journal_start_commit
+#define jbd2_journal_stop			journal_stop
+#define jbd2_journal_try_to_free_buffers	journal_try_to_free_buffers
+#define jbd2_journal_unlock_updates		journal_unlock_updates
+#define jbd2_journal_wipe			journal_wipe
+#define jbd2_log_wait_commit			log_wait_commit
+
+static inline int jbd2_journal_file_inode(handle_t *handle,
+					  struct jbd2_inode *inode)
+{
+	return 0;
+}
+
+static inline int jbd2_journal_begin_ordered_truncate(struct jbd2_inode *inode,
+						      loff_t new_size)
+{
+	return 0;
+}
+
+static inline void jbd2_journal_init_jbd_inode(struct jbd2_inode *jinode,
+					       struct inode *inode)
+{
+	return;
+}
+
+static inline void jbd2_journal_release_jbd_inode(journal_t *journal,
+						  struct jbd2_inode *jinode)
+{
+	return;
+}
+
+
+#endif  /* OCFS2_JBD_COMPAT_H */
diff --git a/fs/ocfs2/resize.c b/fs/ocfs2/resize.c
index 8166968..ffd48db 100644
--- a/fs/ocfs2/resize.c
+++ b/fs/ocfs2/resize.c
@@ -200,7 +200,7 @@
 		if (cluster > clusters)
 			break;
 
-		ret = ocfs2_read_block(osb, blkno, &backup, 0, NULL);
+		ret = ocfs2_read_blocks_sync(osb, blkno, 1, &backup);
 		if (ret < 0) {
 			mlog_errno(ret);
 			break;
@@ -236,8 +236,8 @@
 	 * update the superblock last.
 	 * It doesn't matter if the write failed.
 	 */
-	ret = ocfs2_read_block(osb, OCFS2_SUPER_BLOCK_BLKNO,
-			       &super_bh, 0, NULL);
+	ret = ocfs2_read_blocks_sync(osb, OCFS2_SUPER_BLOCK_BLKNO, 1,
+				     &super_bh);
 	if (ret < 0) {
 		mlog_errno(ret);
 		goto out;
@@ -332,8 +332,7 @@
 	lgd_blkno = ocfs2_which_cluster_group(main_bm_inode,
 					      first_new_cluster - 1);
 
-	ret = ocfs2_read_block(osb, lgd_blkno, &group_bh, OCFS2_BH_CACHED,
-			       main_bm_inode);
+	ret = ocfs2_read_block(main_bm_inode, lgd_blkno, &group_bh);
 	if (ret < 0) {
 		mlog_errno(ret);
 		goto out_unlock;
@@ -540,7 +539,7 @@
 		goto out_unlock;
 	}
 
-	ret = ocfs2_read_block(osb, input->group, &group_bh, 0, NULL);
+	ret = ocfs2_read_blocks_sync(osb, input->group, 1, &group_bh);
 	if (ret < 0) {
 		mlog(ML_ERROR, "Can't read the group descriptor # %llu "
 		     "from the device.", (unsigned long long)input->group);
diff --git a/fs/ocfs2/slot_map.c b/fs/ocfs2/slot_map.c
index bb5ff89..bdda2d8 100644
--- a/fs/ocfs2/slot_map.c
+++ b/fs/ocfs2/slot_map.c
@@ -150,8 +150,8 @@
 	 * be !NULL.  Thus, ocfs2_read_blocks() will ignore blocknr.  If
 	 * this is not true, the read of -1 (UINT64_MAX) will fail.
 	 */
-	ret = ocfs2_read_blocks(osb, -1, si->si_blocks, si->si_bh, 0,
-				si->si_inode);
+	ret = ocfs2_read_blocks(si->si_inode, -1, si->si_blocks, si->si_bh,
+				OCFS2_BH_IGNORE_CACHE);
 	if (ret == 0) {
 		spin_lock(&osb->osb_lock);
 		ocfs2_update_slot_info(si);
@@ -404,7 +404,8 @@
 		     (unsigned long long)blkno);
 
 		bh = NULL;  /* Acquire a fresh bh */
-		status = ocfs2_read_block(osb, blkno, &bh, 0, si->si_inode);
+		status = ocfs2_read_blocks(si->si_inode, blkno, 1, &bh,
+					   OCFS2_BH_IGNORE_CACHE);
 		if (status < 0) {
 			mlog_errno(status);
 			goto bail;
diff --git a/fs/ocfs2/stack_user.c b/fs/ocfs2/stack_user.c
index 353fc35..faec2d8 100644
--- a/fs/ocfs2/stack_user.c
+++ b/fs/ocfs2/stack_user.c
@@ -28,6 +28,7 @@
 #include "ocfs2.h"  /* For struct ocfs2_lock_res */
 #include "stackglue.h"
 
+#include <linux/dlm_plock.h>
 
 /*
  * The control protocol starts with a handshake.  Until the handshake
@@ -746,6 +747,37 @@
 {
 }
 
+static int user_plock(struct ocfs2_cluster_connection *conn,
+		      u64 ino,
+		      struct file *file,
+		      int cmd,
+		      struct file_lock *fl)
+{
+	/*
+	 * This more or less just demuxes the plock request into any
+	 * one of three dlm calls.
+	 *
+	 * Internally, fs/dlm will pass these to a misc device, which
+	 * a userspace daemon will read and write to.
+	 *
+	 * For now, cancel requests (which happen internally only),
+	 * are turned into unlocks. Most of this function taken from
+	 * gfs2_lock.
+	 */
+
+	if (cmd == F_CANCELLK) {
+		cmd = F_SETLK;
+		fl->fl_type = F_UNLCK;
+	}
+
+	if (IS_GETLK(cmd))
+		return dlm_posix_get(conn->cc_lockspace, ino, file, fl);
+	else if (fl->fl_type == F_UNLCK)
+		return dlm_posix_unlock(conn->cc_lockspace, ino, file, fl);
+	else
+		return dlm_posix_lock(conn->cc_lockspace, ino, file, cmd, fl);
+}
+
 /*
  * Compare a requested locking protocol version against the current one.
  *
@@ -839,6 +871,7 @@
 	.dlm_unlock	= user_dlm_unlock,
 	.lock_status	= user_dlm_lock_status,
 	.lock_lvb	= user_dlm_lvb,
+	.plock		= user_plock,
 	.dump_lksb	= user_dlm_dump_lksb,
 };
 
diff --git a/fs/ocfs2/stackglue.c b/fs/ocfs2/stackglue.c
index 07f348b..68b668b 100644
--- a/fs/ocfs2/stackglue.c
+++ b/fs/ocfs2/stackglue.c
@@ -288,6 +288,26 @@
 }
 EXPORT_SYMBOL_GPL(ocfs2_dlm_dump_lksb);
 
+int ocfs2_stack_supports_plocks(void)
+{
+	return active_stack && active_stack->sp_ops->plock;
+}
+EXPORT_SYMBOL_GPL(ocfs2_stack_supports_plocks);
+
+/*
+ * ocfs2_plock() can only be safely called if
+ * ocfs2_stack_supports_plocks() returned true
+ */
+int ocfs2_plock(struct ocfs2_cluster_connection *conn, u64 ino,
+		struct file *file, int cmd, struct file_lock *fl)
+{
+	WARN_ON_ONCE(active_stack->sp_ops->plock == NULL);
+	if (active_stack->sp_ops->plock)
+		return active_stack->sp_ops->plock(conn, ino, file, cmd, fl);
+	return -EOPNOTSUPP;
+}
+EXPORT_SYMBOL_GPL(ocfs2_plock);
+
 int ocfs2_cluster_connect(const char *stack_name,
 			  const char *group,
 			  int grouplen,
diff --git a/fs/ocfs2/stackglue.h b/fs/ocfs2/stackglue.h
index db56281..c571af3 100644
--- a/fs/ocfs2/stackglue.h
+++ b/fs/ocfs2/stackglue.h
@@ -28,6 +28,10 @@
 #include "dlm/dlmapi.h"
 #include <linux/dlm.h>
 
+/* Needed for plock-related prototypes */
+struct file;
+struct file_lock;
+
 /*
  * dlmconstants.h does not have a LOCAL flag.  We hope to remove it
  * some day, but right now we need it.  Let's fake it.  This value is larger
@@ -187,6 +191,17 @@
 	void *(*lock_lvb)(union ocfs2_dlm_lksb *lksb);
 
 	/*
+	 * Cluster-aware posix locks
+	 *
+	 * This is NULL for stacks which do not support posix locks.
+	 */
+	int (*plock)(struct ocfs2_cluster_connection *conn,
+		     u64 ino,
+		     struct file *file,
+		     int cmd,
+		     struct file_lock *fl);
+
+	/*
 	 * This is an optoinal debugging hook.  If provided, the
 	 * stack can dump debugging information about this lock.
 	 */
@@ -240,6 +255,10 @@
 void *ocfs2_dlm_lvb(union ocfs2_dlm_lksb *lksb);
 void ocfs2_dlm_dump_lksb(union ocfs2_dlm_lksb *lksb);
 
+int ocfs2_stack_supports_plocks(void);
+int ocfs2_plock(struct ocfs2_cluster_connection *conn, u64 ino,
+		struct file *file, int cmd, struct file_lock *fl);
+
 void ocfs2_stack_glue_set_locking_protocol(struct ocfs2_locking_protocol *proto);
 
 
diff --git a/fs/ocfs2/suballoc.c b/fs/ocfs2/suballoc.c
index d2d278f..c5ff18b 100644
--- a/fs/ocfs2/suballoc.c
+++ b/fs/ocfs2/suballoc.c
@@ -62,15 +62,18 @@
 				  struct ocfs2_chain_list *cl);
 static int ocfs2_block_group_alloc(struct ocfs2_super *osb,
 				   struct inode *alloc_inode,
-				   struct buffer_head *bh);
+				   struct buffer_head *bh,
+				   u64 max_block);
 
 static int ocfs2_cluster_group_search(struct inode *inode,
 				      struct buffer_head *group_bh,
 				      u32 bits_wanted, u32 min_bits,
+				      u64 max_block,
 				      u16 *bit_off, u16 *bits_found);
 static int ocfs2_block_group_search(struct inode *inode,
 				    struct buffer_head *group_bh,
 				    u32 bits_wanted, u32 min_bits,
+				    u64 max_block,
 				    u16 *bit_off, u16 *bits_found);
 static int ocfs2_claim_suballoc_bits(struct ocfs2_super *osb,
 				     struct ocfs2_alloc_context *ac,
@@ -110,8 +113,11 @@
 						u64 data_blkno,
 						u64 *bg_blkno,
 						u16 *bg_bit_off);
+static int ocfs2_reserve_clusters_with_limit(struct ocfs2_super *osb,
+					     u32 bits_wanted, u64 max_block,
+					     struct ocfs2_alloc_context **ac);
 
-static void ocfs2_free_ac_resource(struct ocfs2_alloc_context *ac)
+void ocfs2_free_ac_resource(struct ocfs2_alloc_context *ac)
 {
 	struct inode *inode = ac->ac_inode;
 
@@ -124,10 +130,8 @@
 		iput(inode);
 		ac->ac_inode = NULL;
 	}
-	if (ac->ac_bh) {
-		brelse(ac->ac_bh);
-		ac->ac_bh = NULL;
-	}
+	brelse(ac->ac_bh);
+	ac->ac_bh = NULL;
 }
 
 void ocfs2_free_alloc_context(struct ocfs2_alloc_context *ac)
@@ -276,7 +280,8 @@
  */
 static int ocfs2_block_group_alloc(struct ocfs2_super *osb,
 				   struct inode *alloc_inode,
-				   struct buffer_head *bh)
+				   struct buffer_head *bh,
+				   u64 max_block)
 {
 	int status, credits;
 	struct ocfs2_dinode *fe = (struct ocfs2_dinode *) bh->b_data;
@@ -294,9 +299,9 @@
 	mlog_entry_void();
 
 	cl = &fe->id2.i_chain;
-	status = ocfs2_reserve_clusters(osb,
-					le16_to_cpu(cl->cl_cpg),
-					&ac);
+	status = ocfs2_reserve_clusters_with_limit(osb,
+						   le16_to_cpu(cl->cl_cpg),
+						   max_block, &ac);
 	if (status < 0) {
 		if (status != -ENOSPC)
 			mlog_errno(status);
@@ -394,8 +399,7 @@
 	if (ac)
 		ocfs2_free_alloc_context(ac);
 
-	if (bg_bh)
-		brelse(bg_bh);
+	brelse(bg_bh);
 
 	mlog_exit(status);
 	return status;
@@ -469,7 +473,8 @@
 			goto bail;
 		}
 
-		status = ocfs2_block_group_alloc(osb, alloc_inode, bh);
+		status = ocfs2_block_group_alloc(osb, alloc_inode, bh,
+						 ac->ac_max_block);
 		if (status < 0) {
 			if (status != -ENOSPC)
 				mlog_errno(status);
@@ -486,16 +491,15 @@
 	get_bh(bh);
 	ac->ac_bh = bh;
 bail:
-	if (bh)
-		brelse(bh);
+	brelse(bh);
 
 	mlog_exit(status);
 	return status;
 }
 
-int ocfs2_reserve_new_metadata(struct ocfs2_super *osb,
-			       struct ocfs2_dinode *fe,
-			       struct ocfs2_alloc_context **ac)
+int ocfs2_reserve_new_metadata_blocks(struct ocfs2_super *osb,
+				      int blocks,
+				      struct ocfs2_alloc_context **ac)
 {
 	int status;
 	u32 slot;
@@ -507,7 +511,7 @@
 		goto bail;
 	}
 
-	(*ac)->ac_bits_wanted = ocfs2_extend_meta_needed(fe);
+	(*ac)->ac_bits_wanted = blocks;
 	(*ac)->ac_which = OCFS2_AC_USE_META;
 	slot = osb->slot_num;
 	(*ac)->ac_group_search = ocfs2_block_group_search;
@@ -532,6 +536,15 @@
 	return status;
 }
 
+int ocfs2_reserve_new_metadata(struct ocfs2_super *osb,
+			       struct ocfs2_extent_list *root_el,
+			       struct ocfs2_alloc_context **ac)
+{
+	return ocfs2_reserve_new_metadata_blocks(osb,
+					ocfs2_extend_meta_needed(root_el),
+					ac);
+}
+
 static int ocfs2_steal_inode_from_other_nodes(struct ocfs2_super *osb,
 					      struct ocfs2_alloc_context *ac)
 {
@@ -582,6 +595,14 @@
 	(*ac)->ac_group_search = ocfs2_block_group_search;
 
 	/*
+	 * stat(2) can't handle i_ino > 32bits, so we tell the
+	 * lower levels not to allocate us a block group past that
+	 * limit.  The 'inode64' mount option avoids this behavior.
+	 */
+	if (!(osb->s_mount_opt & OCFS2_MOUNT_INODE64))
+		(*ac)->ac_max_block = (u32)~0U;
+
+	/*
 	 * slot is set when we successfully steal inode from other nodes.
 	 * It is reset in 3 places:
 	 * 1. when we flush the truncate log
@@ -661,9 +682,9 @@
 /* Callers don't need to care which bitmap (local alloc or main) to
  * use so we figure it out for them, but unfortunately this clutters
  * things a bit. */
-int ocfs2_reserve_clusters(struct ocfs2_super *osb,
-			   u32 bits_wanted,
-			   struct ocfs2_alloc_context **ac)
+static int ocfs2_reserve_clusters_with_limit(struct ocfs2_super *osb,
+					     u32 bits_wanted, u64 max_block,
+					     struct ocfs2_alloc_context **ac)
 {
 	int status;
 
@@ -677,24 +698,20 @@
 	}
 
 	(*ac)->ac_bits_wanted = bits_wanted;
+	(*ac)->ac_max_block = max_block;
 
 	status = -ENOSPC;
 	if (ocfs2_alloc_should_use_local(osb, bits_wanted)) {
 		status = ocfs2_reserve_local_alloc_bits(osb,
 							bits_wanted,
 							*ac);
-		if ((status < 0) && (status != -ENOSPC)) {
+		if (status == -EFBIG) {
+			/* The local alloc window is outside ac_max_block.
+			 * use the main bitmap. */
+			status = -ENOSPC;
+		} else if ((status < 0) && (status != -ENOSPC)) {
 			mlog_errno(status);
 			goto bail;
-		} else if (status == -ENOSPC) {
-			/* reserve_local_bits will return enospc with
-			 * the local alloc inode still locked, so we
-			 * can change this safely here. */
-			mlog(0, "Disabling local alloc\n");
-			/* We set to OCFS2_LA_DISABLED so that umount
-			 * can clean up what's left of the local
-			 * allocation */
-			osb->local_alloc_state = OCFS2_LA_DISABLED;
 		}
 	}
 
@@ -718,6 +735,13 @@
 	return status;
 }
 
+int ocfs2_reserve_clusters(struct ocfs2_super *osb,
+			   u32 bits_wanted,
+			   struct ocfs2_alloc_context **ac)
+{
+	return ocfs2_reserve_clusters_with_limit(osb, bits_wanted, 0, ac);
+}
+
 /*
  * More or less lifted from ext3. I'll leave their description below:
  *
@@ -1000,11 +1024,14 @@
 static int ocfs2_cluster_group_search(struct inode *inode,
 				      struct buffer_head *group_bh,
 				      u32 bits_wanted, u32 min_bits,
+				      u64 max_block,
 				      u16 *bit_off, u16 *bits_found)
 {
 	int search = -ENOSPC;
 	int ret;
+	u64 blkoff;
 	struct ocfs2_group_desc *gd = (struct ocfs2_group_desc *) group_bh->b_data;
+	struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
 	u16 tmp_off, tmp_found;
 	unsigned int max_bits, gd_cluster_off;
 
@@ -1037,6 +1064,17 @@
 		if (ret)
 			return ret;
 
+		if (max_block) {
+			blkoff = ocfs2_clusters_to_blocks(inode->i_sb,
+							  gd_cluster_off +
+							  tmp_off + tmp_found);
+			mlog(0, "Checking %llu against %llu\n",
+			     (unsigned long long)blkoff,
+			     (unsigned long long)max_block);
+			if (blkoff > max_block)
+				return -ENOSPC;
+		}
+
 		/* ocfs2_block_group_find_clear_bits() might
 		 * return success, but we still want to return
 		 * -ENOSPC unless it found the minimum number
@@ -1045,6 +1083,12 @@
 			*bit_off = tmp_off;
 			*bits_found = tmp_found;
 			search = 0; /* success */
+		} else if (tmp_found) {
+			/*
+			 * Don't show bits which we'll be returning
+			 * for allocation to the local alloc bitmap.
+			 */
+			ocfs2_local_alloc_seen_free_bits(osb, tmp_found);
 		}
 	}
 
@@ -1054,19 +1098,31 @@
 static int ocfs2_block_group_search(struct inode *inode,
 				    struct buffer_head *group_bh,
 				    u32 bits_wanted, u32 min_bits,
+				    u64 max_block,
 				    u16 *bit_off, u16 *bits_found)
 {
 	int ret = -ENOSPC;
+	u64 blkoff;
 	struct ocfs2_group_desc *bg = (struct ocfs2_group_desc *) group_bh->b_data;
 
 	BUG_ON(min_bits != 1);
 	BUG_ON(ocfs2_is_cluster_bitmap(inode));
 
-	if (bg->bg_free_bits_count)
+	if (bg->bg_free_bits_count) {
 		ret = ocfs2_block_group_find_clear_bits(OCFS2_SB(inode->i_sb),
 							group_bh, bits_wanted,
 							le16_to_cpu(bg->bg_bits),
 							bit_off, bits_found);
+		if (!ret && max_block) {
+			blkoff = le64_to_cpu(bg->bg_blkno) + *bit_off +
+				*bits_found;
+			mlog(0, "Checking %llu against %llu\n",
+			     (unsigned long long)blkoff,
+			     (unsigned long long)max_block);
+			if (blkoff > max_block)
+				ret = -ENOSPC;
+		}
+	}
 
 	return ret;
 }
@@ -1116,8 +1172,7 @@
 	struct ocfs2_group_desc *gd;
 	struct inode *alloc_inode = ac->ac_inode;
 
-	ret = ocfs2_read_block(OCFS2_SB(alloc_inode->i_sb), gd_blkno,
-			       &group_bh, OCFS2_BH_CACHED, alloc_inode);
+	ret = ocfs2_read_block(alloc_inode, gd_blkno, &group_bh);
 	if (ret < 0) {
 		mlog_errno(ret);
 		return ret;
@@ -1131,7 +1186,7 @@
 	}
 
 	ret = ac->ac_group_search(alloc_inode, group_bh, bits_wanted, min_bits,
-				  bit_off, &found);
+				  ac->ac_max_block, bit_off, &found);
 	if (ret < 0) {
 		if (ret != -ENOSPC)
 			mlog_errno(ret);
@@ -1186,9 +1241,9 @@
 	     bits_wanted, chain,
 	     (unsigned long long)OCFS2_I(alloc_inode)->ip_blkno);
 
-	status = ocfs2_read_block(OCFS2_SB(alloc_inode->i_sb),
+	status = ocfs2_read_block(alloc_inode,
 				  le64_to_cpu(cl->cl_recs[chain].c_blkno),
-				  &group_bh, OCFS2_BH_CACHED, alloc_inode);
+				  &group_bh);
 	if (status < 0) {
 		mlog_errno(status);
 		goto bail;
@@ -1204,21 +1259,20 @@
 	/* for now, the chain search is a bit simplistic. We just use
 	 * the 1st group with any empty bits. */
 	while ((status = ac->ac_group_search(alloc_inode, group_bh,
-					     bits_wanted, min_bits, bit_off,
+					     bits_wanted, min_bits,
+					     ac->ac_max_block, bit_off,
 					     &tmp_bits)) == -ENOSPC) {
 		if (!bg->bg_next_group)
 			break;
 
-		if (prev_group_bh) {
-			brelse(prev_group_bh);
-			prev_group_bh = NULL;
-		}
+		brelse(prev_group_bh);
+		prev_group_bh = NULL;
+
 		next_group = le64_to_cpu(bg->bg_next_group);
 		prev_group_bh = group_bh;
 		group_bh = NULL;
-		status = ocfs2_read_block(OCFS2_SB(alloc_inode->i_sb),
-					  next_group, &group_bh,
-					  OCFS2_BH_CACHED, alloc_inode);
+		status = ocfs2_read_block(alloc_inode,
+					  next_group, &group_bh);
 		if (status < 0) {
 			mlog_errno(status);
 			goto bail;
@@ -1307,10 +1361,8 @@
 	*bg_blkno = le64_to_cpu(bg->bg_blkno);
 	*bits_left = le16_to_cpu(bg->bg_free_bits_count);
 bail:
-	if (group_bh)
-		brelse(group_bh);
-	if (prev_group_bh)
-		brelse(prev_group_bh);
+	brelse(group_bh);
+	brelse(prev_group_bh);
 
 	mlog_exit(status);
 	return status;
@@ -1723,7 +1775,6 @@
 {
 	int status = 0;
 	u32 tmp_used;
-	struct ocfs2_super *osb = OCFS2_SB(alloc_inode->i_sb);
 	struct ocfs2_dinode *fe = (struct ocfs2_dinode *) alloc_bh->b_data;
 	struct ocfs2_chain_list *cl = &fe->id2.i_chain;
 	struct buffer_head *group_bh = NULL;
@@ -1742,8 +1793,7 @@
 	     (unsigned long long)OCFS2_I(alloc_inode)->ip_blkno, count,
 	     (unsigned long long)bg_blkno, start_bit);
 
-	status = ocfs2_read_block(osb, bg_blkno, &group_bh, OCFS2_BH_CACHED,
-				  alloc_inode);
+	status = ocfs2_read_block(alloc_inode, bg_blkno, &group_bh);
 	if (status < 0) {
 		mlog_errno(status);
 		goto bail;
@@ -1784,8 +1834,7 @@
 	}
 
 bail:
-	if (group_bh)
-		brelse(group_bh);
+	brelse(group_bh);
 
 	mlog_exit(status);
 	return status;
@@ -1838,9 +1887,15 @@
 	status = ocfs2_free_suballoc_bits(handle, bitmap_inode, bitmap_bh,
 					  bg_start_bit, bg_blkno,
 					  num_clusters);
-	if (status < 0)
+	if (status < 0) {
 		mlog_errno(status);
+		goto out;
+	}
 
+	ocfs2_local_alloc_seen_free_bits(OCFS2_SB(bitmap_inode->i_sb),
+					 num_clusters);
+
+out:
 	mlog_exit(status);
 	return status;
 }
@@ -1891,3 +1946,84 @@
 		       (unsigned long long)fe->id2.i_chain.cl_recs[i].c_blkno);
 	}
 }
+
+/*
+ * For a given allocation, determine which allocators will need to be
+ * accessed, and lock them, reserving the appropriate number of bits.
+ *
+ * Sparse file systems call this from ocfs2_write_begin_nolock()
+ * and ocfs2_allocate_unwritten_extents().
+ *
+ * File systems which don't support holes call this from
+ * ocfs2_extend_allocation().
+ */
+int ocfs2_lock_allocators(struct inode *inode,
+			  struct ocfs2_extent_tree *et,
+			  u32 clusters_to_add, u32 extents_to_split,
+			  struct ocfs2_alloc_context **data_ac,
+			  struct ocfs2_alloc_context **meta_ac)
+{
+	int ret = 0, num_free_extents;
+	unsigned int max_recs_needed = clusters_to_add + 2 * extents_to_split;
+	struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+
+	*meta_ac = NULL;
+	if (data_ac)
+		*data_ac = NULL;
+
+	BUG_ON(clusters_to_add != 0 && data_ac == NULL);
+
+	num_free_extents = ocfs2_num_free_extents(osb, inode, et);
+	if (num_free_extents < 0) {
+		ret = num_free_extents;
+		mlog_errno(ret);
+		goto out;
+	}
+
+	/*
+	 * Sparse allocation file systems need to be more conservative
+	 * with reserving room for expansion - the actual allocation
+	 * happens while we've got a journal handle open so re-taking
+	 * a cluster lock (because we ran out of room for another
+	 * extent) will violate ordering rules.
+	 *
+	 * Most of the time we'll only be seeing this 1 cluster at a time
+	 * anyway.
+	 *
+	 * Always lock for any unwritten extents - we might want to
+	 * add blocks during a split.
+	 */
+	if (!num_free_extents ||
+	    (ocfs2_sparse_alloc(osb) && num_free_extents < max_recs_needed)) {
+		ret = ocfs2_reserve_new_metadata(osb, et->et_root_el, meta_ac);
+		if (ret < 0) {
+			if (ret != -ENOSPC)
+				mlog_errno(ret);
+			goto out;
+		}
+	}
+
+	if (clusters_to_add == 0)
+		goto out;
+
+	ret = ocfs2_reserve_clusters(osb, clusters_to_add, data_ac);
+	if (ret < 0) {
+		if (ret != -ENOSPC)
+			mlog_errno(ret);
+		goto out;
+	}
+
+out:
+	if (ret) {
+		if (*meta_ac) {
+			ocfs2_free_alloc_context(*meta_ac);
+			*meta_ac = NULL;
+		}
+
+		/*
+		 * We cannot have an error and a non null *data_ac.
+		 */
+	}
+
+	return ret;
+}
diff --git a/fs/ocfs2/suballoc.h b/fs/ocfs2/suballoc.h
index 544c600..4df159d 100644
--- a/fs/ocfs2/suballoc.h
+++ b/fs/ocfs2/suballoc.h
@@ -28,10 +28,11 @@
 
 typedef int (group_search_t)(struct inode *,
 			     struct buffer_head *,
-			     u32,
-			     u32,
-			     u16 *,
-			     u16 *);
+			     u32,			/* bits_wanted */
+			     u32,			/* min_bits */
+			     u64,			/* max_block */
+			     u16 *,			/* *bit_off */
+			     u16 *);			/* *bits_found */
 
 struct ocfs2_alloc_context {
 	struct inode *ac_inode;    /* which bitmap are we allocating from? */
@@ -51,6 +52,8 @@
 	group_search_t *ac_group_search;
 
 	u64    ac_last_group;
+	u64    ac_max_block;  /* Highest block number to allocate. 0 is
+				 is the same as ~0 - unlimited */
 };
 
 void ocfs2_free_alloc_context(struct ocfs2_alloc_context *ac);
@@ -59,9 +62,17 @@
 	return ac->ac_bits_wanted - ac->ac_bits_given;
 }
 
+/*
+ * Please note that the caller must make sure that root_el is the root
+ * of extent tree. So for an inode, it should be &fe->id2.i_list. Otherwise
+ * the result may be wrong.
+ */
 int ocfs2_reserve_new_metadata(struct ocfs2_super *osb,
-			       struct ocfs2_dinode *fe,
+			       struct ocfs2_extent_list *root_el,
 			       struct ocfs2_alloc_context **ac);
+int ocfs2_reserve_new_metadata_blocks(struct ocfs2_super *osb,
+				      int blocks,
+				      struct ocfs2_alloc_context **ac);
 int ocfs2_reserve_new_inode(struct ocfs2_super *osb,
 			    struct ocfs2_alloc_context **ac);
 int ocfs2_reserve_clusters(struct ocfs2_super *osb,
@@ -147,6 +158,7 @@
  * apis above. */
 int ocfs2_reserve_cluster_bitmap_bits(struct ocfs2_super *osb,
 				      struct ocfs2_alloc_context *ac);
+void ocfs2_free_ac_resource(struct ocfs2_alloc_context *ac);
 
 /* given a cluster offset, calculate which block group it belongs to
  * and return that block offset. */
@@ -156,4 +168,8 @@
 int ocfs2_check_group_descriptor(struct super_block *sb,
 				 struct ocfs2_dinode *di,
 				 struct ocfs2_group_desc *gd);
+int ocfs2_lock_allocators(struct inode *inode, struct ocfs2_extent_tree *et,
+			  u32 clusters_to_add, u32 extents_to_split,
+			  struct ocfs2_alloc_context **data_ac,
+			  struct ocfs2_alloc_context **meta_ac);
 #endif /* _CHAINALLOC_H_ */
diff --git a/fs/ocfs2/super.c b/fs/ocfs2/super.c
index 88255d3f..304b63a 100644
--- a/fs/ocfs2/super.c
+++ b/fs/ocfs2/super.c
@@ -64,6 +64,7 @@
 #include "sysfile.h"
 #include "uptodate.h"
 #include "ver.h"
+#include "xattr.h"
 
 #include "buffer_head_io.h"
 
@@ -154,10 +155,13 @@
 	Opt_localalloc,
 	Opt_localflocks,
 	Opt_stack,
+	Opt_user_xattr,
+	Opt_nouser_xattr,
+	Opt_inode64,
 	Opt_err,
 };
 
-static match_table_t tokens = {
+static const match_table_t tokens = {
 	{Opt_barrier, "barrier=%u"},
 	{Opt_err_panic, "errors=panic"},
 	{Opt_err_ro, "errors=remount-ro"},
@@ -173,6 +177,9 @@
 	{Opt_localalloc, "localalloc=%d"},
 	{Opt_localflocks, "localflocks"},
 	{Opt_stack, "cluster_stack=%s"},
+	{Opt_user_xattr, "user_xattr"},
+	{Opt_nouser_xattr, "nouser_xattr"},
+	{Opt_inode64, "inode64"},
 	{Opt_err, NULL}
 };
 
@@ -205,10 +212,11 @@
 		ocfs2_schedule_truncate_log_flush(osb, 0);
 	}
 
-	if (journal_start_commit(OCFS2_SB(sb)->journal->j_journal, &target)) {
+	if (jbd2_journal_start_commit(OCFS2_SB(sb)->journal->j_journal,
+				      &target)) {
 		if (wait)
-			log_wait_commit(OCFS2_SB(sb)->journal->j_journal,
-					target);
+			jbd2_log_wait_commit(OCFS2_SB(sb)->journal->j_journal,
+					     target);
 	}
 	return 0;
 }
@@ -325,6 +333,7 @@
 	if (!oi)
 		return NULL;
 
+	jbd2_journal_init_jbd_inode(&oi->ip_jinode, &oi->vfs_inode);
 	return &oi->vfs_inode;
 }
 
@@ -406,6 +415,15 @@
 		goto out;
 	}
 
+	/* Probably don't want this on remount; it might
+	 * mess with other nodes */
+	if (!(osb->s_mount_opt & OCFS2_MOUNT_INODE64) &&
+	    (parsed_options.mount_opt & OCFS2_MOUNT_INODE64)) {
+		ret = -EINVAL;
+		mlog(ML_ERROR, "Cannot enable inode64 on remount\n");
+		goto out;
+	}
+
 	/* We're going to/from readonly mode. */
 	if ((*flags & MS_RDONLY) != (sb->s_flags & MS_RDONLY)) {
 		/* Lock here so the check of HARD_RO and the potential
@@ -637,7 +655,8 @@
 	osb->s_atime_quantum = parsed_options.atime_quantum;
 	osb->preferred_slot = parsed_options.slot;
 	osb->osb_commit_interval = parsed_options.commit_interval;
-	osb->local_alloc_size = parsed_options.localalloc_opt;
+	osb->local_alloc_default_bits = ocfs2_megabytes_to_clusters(sb, parsed_options.localalloc_opt);
+	osb->local_alloc_bits = osb->local_alloc_default_bits;
 
 	status = ocfs2_verify_userspace_stack(osb, &parsed_options);
 	if (status)
@@ -743,8 +762,7 @@
 	return status;
 
 read_super_error:
-	if (bh != NULL)
-		brelse(bh);
+	brelse(bh);
 
 	if (inode)
 		iput(inode);
@@ -847,6 +865,12 @@
 		case Opt_data_writeback:
 			mopt->mount_opt |= OCFS2_MOUNT_DATA_WRITEBACK;
 			break;
+		case Opt_user_xattr:
+			mopt->mount_opt &= ~OCFS2_MOUNT_NOUSERXATTR;
+			break;
+		case Opt_nouser_xattr:
+			mopt->mount_opt |= OCFS2_MOUNT_NOUSERXATTR;
+			break;
 		case Opt_atime_quantum:
 			if (match_int(&args[0], &option)) {
 				status = 0;
@@ -873,7 +897,7 @@
 			if (option < 0)
 				return 0;
 			if (option == 0)
-				option = JBD_DEFAULT_MAX_COMMIT_AGE;
+				option = JBD2_DEFAULT_MAX_COMMIT_AGE;
 			mopt->commit_interval = HZ * option;
 			break;
 		case Opt_localalloc:
@@ -918,6 +942,9 @@
 			       OCFS2_STACK_LABEL_LEN);
 			mopt->cluster_stack[OCFS2_STACK_LABEL_LEN] = '\0';
 			break;
+		case Opt_inode64:
+			mopt->mount_opt |= OCFS2_MOUNT_INODE64;
+			break;
 		default:
 			mlog(ML_ERROR,
 			     "Unrecognized mount option \"%s\" "
@@ -938,6 +965,7 @@
 {
 	struct ocfs2_super *osb = OCFS2_SB(mnt->mnt_sb);
 	unsigned long opts = osb->s_mount_opt;
+	unsigned int local_alloc_megs;
 
 	if (opts & OCFS2_MOUNT_HB_LOCAL)
 		seq_printf(s, ",_netdev,heartbeat=local");
@@ -970,8 +998,9 @@
 		seq_printf(s, ",commit=%u",
 			   (unsigned) (osb->osb_commit_interval / HZ));
 
-	if (osb->local_alloc_size != OCFS2_DEFAULT_LOCAL_ALLOC_SIZE)
-		seq_printf(s, ",localalloc=%d", osb->local_alloc_size);
+	local_alloc_megs = osb->local_alloc_bits >> (20 - osb->s_clustersize_bits);
+	if (local_alloc_megs != OCFS2_DEFAULT_LOCAL_ALLOC_SIZE)
+		seq_printf(s, ",localalloc=%d", local_alloc_megs);
 
 	if (opts & OCFS2_MOUNT_LOCALFLOCKS)
 		seq_printf(s, ",localflocks,");
@@ -980,6 +1009,14 @@
 		seq_printf(s, ",cluster_stack=%.*s", OCFS2_STACK_LABEL_LEN,
 			   osb->osb_cluster_stack);
 
+	if (opts & OCFS2_MOUNT_NOUSERXATTR)
+		seq_printf(s, ",nouser_xattr");
+	else
+		seq_printf(s, ",user_xattr");
+
+	if (opts & OCFS2_MOUNT_INODE64)
+		seq_printf(s, ",inode64");
+
 	return 0;
 }
 
@@ -1132,6 +1169,7 @@
 	oi->ip_dir_start_lookup = 0;
 
 	init_rwsem(&oi->ip_alloc_sem);
+	init_rwsem(&oi->ip_xattr_sem);
 	mutex_init(&oi->ip_io_mutex);
 
 	oi->ip_blkno = 0ULL;
@@ -1375,6 +1413,7 @@
 	sb->s_fs_info = osb;
 	sb->s_op = &ocfs2_sops;
 	sb->s_export_op = &ocfs2_export_ops;
+	sb->s_xattr = ocfs2_xattr_handlers;
 	sb->s_time_gran = 1;
 	sb->s_flags |= MS_NOATIME;
 	/* this is needed to support O_LARGEFILE */
@@ -1421,8 +1460,12 @@
 
 	osb->slot_num = OCFS2_INVALID_SLOT;
 
+	osb->s_xattr_inline_size = le16_to_cpu(
+					di->id2.i_super.s_xattr_inline_size);
+
 	osb->local_alloc_state = OCFS2_LA_UNUSED;
 	osb->local_alloc_bh = NULL;
+	INIT_DELAYED_WORK(&osb->la_enable_wq, ocfs2_la_enable_worker);
 
 	init_waitqueue_head(&osb->osb_mount_event);
 
@@ -1568,6 +1611,7 @@
 	osb->first_cluster_group_blkno =
 		le64_to_cpu(di->id2.i_super.s_first_cluster_group);
 	osb->fs_generation = le32_to_cpu(di->i_fs_generation);
+	osb->uuid_hash = le32_to_cpu(di->id2.i_super.s_uuid_hash);
 	mlog(0, "vol_label: %s\n", osb->vol_label);
 	mlog(0, "uuid: %s\n", osb->uuid_str);
 	mlog(0, "root_blkno=%llu, system_dir_blkno=%llu\n",
diff --git a/fs/ocfs2/symlink.c b/fs/ocfs2/symlink.c
index ba9dbb5..cbd03df 100644
--- a/fs/ocfs2/symlink.c
+++ b/fs/ocfs2/symlink.c
@@ -50,6 +50,7 @@
 #include "inode.h"
 #include "journal.h"
 #include "symlink.h"
+#include "xattr.h"
 
 #include "buffer_head_io.h"
 
@@ -83,11 +84,7 @@
 
 	mlog_entry_void();
 
-	status = ocfs2_read_block(OCFS2_SB(inode->i_sb),
-				  OCFS2_I(inode)->ip_blkno,
-				  bh,
-				  OCFS2_BH_CACHED,
-				  inode);
+	status = ocfs2_read_block(inode, OCFS2_I(inode)->ip_blkno, bh);
 	if (status < 0) {
 		mlog_errno(status);
 		link = ERR_PTR(status);
@@ -157,8 +154,7 @@
 		kunmap(page);
 		page_cache_release(page);
 	}
-	if (bh)
-		brelse(bh);
+	brelse(bh);
 
 	return ERR_PTR(status);
 }
@@ -168,10 +164,18 @@
 	.follow_link	= ocfs2_follow_link,
 	.getattr	= ocfs2_getattr,
 	.setattr	= ocfs2_setattr,
+	.setxattr	= generic_setxattr,
+	.getxattr	= generic_getxattr,
+	.listxattr	= ocfs2_listxattr,
+	.removexattr	= generic_removexattr,
 };
 const struct inode_operations ocfs2_fast_symlink_inode_operations = {
 	.readlink	= ocfs2_readlink,
 	.follow_link	= ocfs2_follow_link,
 	.getattr	= ocfs2_getattr,
 	.setattr	= ocfs2_setattr,
+	.setxattr	= generic_setxattr,
+	.getxattr	= generic_getxattr,
+	.listxattr	= ocfs2_listxattr,
+	.removexattr	= generic_removexattr,
 };
diff --git a/fs/ocfs2/uptodate.c b/fs/ocfs2/uptodate.c
index 4da8851..187b99f 100644
--- a/fs/ocfs2/uptodate.c
+++ b/fs/ocfs2/uptodate.c
@@ -53,7 +53,11 @@
 #include <linux/highmem.h>
 #include <linux/buffer_head.h>
 #include <linux/rbtree.h>
-#include <linux/jbd.h>
+#ifndef CONFIG_OCFS2_COMPAT_JBD
+# include <linux/jbd2.h>
+#else
+# include <linux/jbd.h>
+#endif
 
 #define MLOG_MASK_PREFIX ML_UPTODATE
 
@@ -511,14 +515,10 @@
 	ci->ci_num_cached--;
 }
 
-/* Called when we remove a chunk of metadata from an inode. We don't
- * bother reverting things to an inlined array in the case of a remove
- * which moves us back under the limit. */
-void ocfs2_remove_from_cache(struct inode *inode,
-			     struct buffer_head *bh)
+static void ocfs2_remove_block_from_cache(struct inode *inode,
+					  sector_t block)
 {
 	int index;
-	sector_t block = bh->b_blocknr;
 	struct ocfs2_meta_cache_item *item = NULL;
 	struct ocfs2_inode_info *oi = OCFS2_I(inode);
 	struct ocfs2_caching_info *ci = &oi->ip_metadata_cache;
@@ -544,6 +544,30 @@
 		kmem_cache_free(ocfs2_uptodate_cachep, item);
 }
 
+/*
+ * Called when we remove a chunk of metadata from an inode. We don't
+ * bother reverting things to an inlined array in the case of a remove
+ * which moves us back under the limit.
+ */
+void ocfs2_remove_from_cache(struct inode *inode,
+			     struct buffer_head *bh)
+{
+	sector_t block = bh->b_blocknr;
+
+	ocfs2_remove_block_from_cache(inode, block);
+}
+
+/* Called when we remove xattr clusters from an inode. */
+void ocfs2_remove_xattr_clusters_from_cache(struct inode *inode,
+					    sector_t block,
+					    u32 c_len)
+{
+	unsigned int i, b_len = ocfs2_clusters_to_blocks(inode->i_sb, 1) * c_len;
+
+	for (i = 0; i < b_len; i++, block++)
+		ocfs2_remove_block_from_cache(inode, block);
+}
+
 int __init init_ocfs2_uptodate_cache(void)
 {
 	ocfs2_uptodate_cachep = kmem_cache_create("ocfs2_uptodate",
diff --git a/fs/ocfs2/uptodate.h b/fs/ocfs2/uptodate.h
index 2e73206..531b4b3 100644
--- a/fs/ocfs2/uptodate.h
+++ b/fs/ocfs2/uptodate.h
@@ -40,6 +40,9 @@
 				   struct buffer_head *bh);
 void ocfs2_remove_from_cache(struct inode *inode,
 			     struct buffer_head *bh);
+void ocfs2_remove_xattr_clusters_from_cache(struct inode *inode,
+					    sector_t block,
+					    u32 c_len);
 int ocfs2_buffer_read_ahead(struct inode *inode,
 			    struct buffer_head *bh);
 
diff --git a/fs/ocfs2/xattr.c b/fs/ocfs2/xattr.c
new file mode 100644
index 0000000..c25780a
--- /dev/null
+++ b/fs/ocfs2/xattr.c
@@ -0,0 +1,4834 @@
+/* -*- mode: c; c-basic-offset: 8; -*-
+ * vim: noexpandtab sw=8 ts=8 sts=0:
+ *
+ * xattr.c
+ *
+ * Copyright (C) 2008 Oracle.  All rights reserved.
+ *
+ * CREDITS:
+ * Lots of code in this file is taken from ext3.
+ *
+ * This program is free software; you can redistribute it and/or
+ * 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 021110-1307, USA.
+ */
+
+#include <linux/capability.h>
+#include <linux/fs.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/highmem.h>
+#include <linux/pagemap.h>
+#include <linux/uio.h>
+#include <linux/sched.h>
+#include <linux/splice.h>
+#include <linux/mount.h>
+#include <linux/writeback.h>
+#include <linux/falloc.h>
+#include <linux/sort.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/string.h>
+
+#define MLOG_MASK_PREFIX ML_XATTR
+#include <cluster/masklog.h>
+
+#include "ocfs2.h"
+#include "alloc.h"
+#include "dlmglue.h"
+#include "file.h"
+#include "symlink.h"
+#include "sysfile.h"
+#include "inode.h"
+#include "journal.h"
+#include "ocfs2_fs.h"
+#include "suballoc.h"
+#include "uptodate.h"
+#include "buffer_head_io.h"
+#include "super.h"
+#include "xattr.h"
+
+
+struct ocfs2_xattr_def_value_root {
+	struct ocfs2_xattr_value_root	xv;
+	struct ocfs2_extent_rec		er;
+};
+
+struct ocfs2_xattr_bucket {
+	struct buffer_head *bhs[OCFS2_XATTR_MAX_BLOCKS_PER_BUCKET];
+	struct ocfs2_xattr_header *xh;
+};
+
+#define OCFS2_XATTR_ROOT_SIZE	(sizeof(struct ocfs2_xattr_def_value_root))
+#define OCFS2_XATTR_INLINE_SIZE	80
+
+static struct ocfs2_xattr_def_value_root def_xv = {
+	.xv.xr_list.l_count = cpu_to_le16(1),
+};
+
+struct xattr_handler *ocfs2_xattr_handlers[] = {
+	&ocfs2_xattr_user_handler,
+	&ocfs2_xattr_trusted_handler,
+	NULL
+};
+
+static struct xattr_handler *ocfs2_xattr_handler_map[] = {
+	[OCFS2_XATTR_INDEX_USER]	= &ocfs2_xattr_user_handler,
+	[OCFS2_XATTR_INDEX_TRUSTED]	= &ocfs2_xattr_trusted_handler,
+};
+
+struct ocfs2_xattr_info {
+	int name_index;
+	const char *name;
+	const void *value;
+	size_t value_len;
+};
+
+struct ocfs2_xattr_search {
+	struct buffer_head *inode_bh;
+	/*
+	 * xattr_bh point to the block buffer head which has extended attribute
+	 * when extended attribute in inode, xattr_bh is equal to inode_bh.
+	 */
+	struct buffer_head *xattr_bh;
+	struct ocfs2_xattr_header *header;
+	struct ocfs2_xattr_bucket bucket;
+	void *base;
+	void *end;
+	struct ocfs2_xattr_entry *here;
+	int not_found;
+};
+
+static int ocfs2_xattr_bucket_get_name_value(struct inode *inode,
+					     struct ocfs2_xattr_header *xh,
+					     int index,
+					     int *block_off,
+					     int *new_offset);
+
+static int ocfs2_xattr_index_block_find(struct inode *inode,
+					struct buffer_head *root_bh,
+					int name_index,
+					const char *name,
+					struct ocfs2_xattr_search *xs);
+
+static int ocfs2_xattr_tree_list_index_block(struct inode *inode,
+					struct ocfs2_xattr_tree_root *xt,
+					char *buffer,
+					size_t buffer_size);
+
+static int ocfs2_xattr_create_index_block(struct inode *inode,
+					  struct ocfs2_xattr_search *xs);
+
+static int ocfs2_xattr_set_entry_index_block(struct inode *inode,
+					     struct ocfs2_xattr_info *xi,
+					     struct ocfs2_xattr_search *xs);
+
+static int ocfs2_delete_xattr_index_block(struct inode *inode,
+					  struct buffer_head *xb_bh);
+
+static inline const char *ocfs2_xattr_prefix(int name_index)
+{
+	struct xattr_handler *handler = NULL;
+
+	if (name_index > 0 && name_index < OCFS2_XATTR_MAX)
+		handler = ocfs2_xattr_handler_map[name_index];
+
+	return handler ? handler->prefix : NULL;
+}
+
+static u32 ocfs2_xattr_name_hash(struct inode *inode,
+				 const char *name,
+				 int name_len)
+{
+	/* Get hash value of uuid from super block */
+	u32 hash = OCFS2_SB(inode->i_sb)->uuid_hash;
+	int i;
+
+	/* hash extended attribute name */
+	for (i = 0; i < name_len; i++) {
+		hash = (hash << OCFS2_HASH_SHIFT) ^
+		       (hash >> (8*sizeof(hash) - OCFS2_HASH_SHIFT)) ^
+		       *name++;
+	}
+
+	return hash;
+}
+
+/*
+ * ocfs2_xattr_hash_entry()
+ *
+ * Compute the hash of an extended attribute.
+ */
+static void ocfs2_xattr_hash_entry(struct inode *inode,
+				   struct ocfs2_xattr_header *header,
+				   struct ocfs2_xattr_entry *entry)
+{
+	u32 hash = 0;
+	char *name = (char *)header + le16_to_cpu(entry->xe_name_offset);
+
+	hash = ocfs2_xattr_name_hash(inode, name, entry->xe_name_len);
+	entry->xe_name_hash = cpu_to_le32(hash);
+
+	return;
+}
+
+static int ocfs2_xattr_extend_allocation(struct inode *inode,
+					 u32 clusters_to_add,
+					 struct buffer_head *xattr_bh,
+					 struct ocfs2_xattr_value_root *xv)
+{
+	int status = 0;
+	int restart_func = 0;
+	int credits = 0;
+	handle_t *handle = NULL;
+	struct ocfs2_alloc_context *data_ac = NULL;
+	struct ocfs2_alloc_context *meta_ac = NULL;
+	enum ocfs2_alloc_restarted why;
+	struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+	u32 prev_clusters, logical_start = le32_to_cpu(xv->xr_clusters);
+	struct ocfs2_extent_tree et;
+
+	mlog(0, "(clusters_to_add for xattr= %u)\n", clusters_to_add);
+
+	ocfs2_init_xattr_value_extent_tree(&et, inode, xattr_bh, xv);
+
+restart_all:
+
+	status = ocfs2_lock_allocators(inode, &et, clusters_to_add, 0,
+				       &data_ac, &meta_ac);
+	if (status) {
+		mlog_errno(status);
+		goto leave;
+	}
+
+	credits = ocfs2_calc_extend_credits(osb->sb, et.et_root_el,
+					    clusters_to_add);
+	handle = ocfs2_start_trans(osb, credits);
+	if (IS_ERR(handle)) {
+		status = PTR_ERR(handle);
+		handle = NULL;
+		mlog_errno(status);
+		goto leave;
+	}
+
+restarted_transaction:
+	status = ocfs2_journal_access(handle, inode, xattr_bh,
+				      OCFS2_JOURNAL_ACCESS_WRITE);
+	if (status < 0) {
+		mlog_errno(status);
+		goto leave;
+	}
+
+	prev_clusters = le32_to_cpu(xv->xr_clusters);
+	status = ocfs2_add_clusters_in_btree(osb,
+					     inode,
+					     &logical_start,
+					     clusters_to_add,
+					     0,
+					     &et,
+					     handle,
+					     data_ac,
+					     meta_ac,
+					     &why);
+	if ((status < 0) && (status != -EAGAIN)) {
+		if (status != -ENOSPC)
+			mlog_errno(status);
+		goto leave;
+	}
+
+	status = ocfs2_journal_dirty(handle, xattr_bh);
+	if (status < 0) {
+		mlog_errno(status);
+		goto leave;
+	}
+
+	clusters_to_add -= le32_to_cpu(xv->xr_clusters) - prev_clusters;
+
+	if (why != RESTART_NONE && clusters_to_add) {
+		if (why == RESTART_META) {
+			mlog(0, "restarting function.\n");
+			restart_func = 1;
+		} else {
+			BUG_ON(why != RESTART_TRANS);
+
+			mlog(0, "restarting transaction.\n");
+			/* TODO: This can be more intelligent. */
+			credits = ocfs2_calc_extend_credits(osb->sb,
+							    et.et_root_el,
+							    clusters_to_add);
+			status = ocfs2_extend_trans(handle, credits);
+			if (status < 0) {
+				/* handle still has to be committed at
+				 * this point. */
+				status = -ENOMEM;
+				mlog_errno(status);
+				goto leave;
+			}
+			goto restarted_transaction;
+		}
+	}
+
+leave:
+	if (handle) {
+		ocfs2_commit_trans(osb, handle);
+		handle = NULL;
+	}
+	if (data_ac) {
+		ocfs2_free_alloc_context(data_ac);
+		data_ac = NULL;
+	}
+	if (meta_ac) {
+		ocfs2_free_alloc_context(meta_ac);
+		meta_ac = NULL;
+	}
+	if ((!status) && restart_func) {
+		restart_func = 0;
+		goto restart_all;
+	}
+
+	return status;
+}
+
+static int __ocfs2_remove_xattr_range(struct inode *inode,
+				      struct buffer_head *root_bh,
+				      struct ocfs2_xattr_value_root *xv,
+				      u32 cpos, u32 phys_cpos, u32 len,
+				      struct ocfs2_cached_dealloc_ctxt *dealloc)
+{
+	int ret;
+	u64 phys_blkno = ocfs2_clusters_to_blocks(inode->i_sb, phys_cpos);
+	struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+	struct inode *tl_inode = osb->osb_tl_inode;
+	handle_t *handle;
+	struct ocfs2_alloc_context *meta_ac = NULL;
+	struct ocfs2_extent_tree et;
+
+	ocfs2_init_xattr_value_extent_tree(&et, inode, root_bh, xv);
+
+	ret = ocfs2_lock_allocators(inode, &et, 0, 1, NULL, &meta_ac);
+	if (ret) {
+		mlog_errno(ret);
+		return ret;
+	}
+
+	mutex_lock(&tl_inode->i_mutex);
+
+	if (ocfs2_truncate_log_needs_flush(osb)) {
+		ret = __ocfs2_flush_truncate_log(osb);
+		if (ret < 0) {
+			mlog_errno(ret);
+			goto out;
+		}
+	}
+
+	handle = ocfs2_start_trans(osb, OCFS2_REMOVE_EXTENT_CREDITS);
+	if (IS_ERR(handle)) {
+		ret = PTR_ERR(handle);
+		mlog_errno(ret);
+		goto out;
+	}
+
+	ret = ocfs2_journal_access(handle, inode, root_bh,
+				   OCFS2_JOURNAL_ACCESS_WRITE);
+	if (ret) {
+		mlog_errno(ret);
+		goto out_commit;
+	}
+
+	ret = ocfs2_remove_extent(inode, &et, cpos, len, handle, meta_ac,
+				  dealloc);
+	if (ret) {
+		mlog_errno(ret);
+		goto out_commit;
+	}
+
+	le32_add_cpu(&xv->xr_clusters, -len);
+
+	ret = ocfs2_journal_dirty(handle, root_bh);
+	if (ret) {
+		mlog_errno(ret);
+		goto out_commit;
+	}
+
+	ret = ocfs2_truncate_log_append(osb, handle, phys_blkno, len);
+	if (ret)
+		mlog_errno(ret);
+
+out_commit:
+	ocfs2_commit_trans(osb, handle);
+out:
+	mutex_unlock(&tl_inode->i_mutex);
+
+	if (meta_ac)
+		ocfs2_free_alloc_context(meta_ac);
+
+	return ret;
+}
+
+static int ocfs2_xattr_shrink_size(struct inode *inode,
+				   u32 old_clusters,
+				   u32 new_clusters,
+				   struct buffer_head *root_bh,
+				   struct ocfs2_xattr_value_root *xv)
+{
+	int ret = 0;
+	u32 trunc_len, cpos, phys_cpos, alloc_size;
+	u64 block;
+	struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+	struct ocfs2_cached_dealloc_ctxt dealloc;
+
+	ocfs2_init_dealloc_ctxt(&dealloc);
+
+	if (old_clusters <= new_clusters)
+		return 0;
+
+	cpos = new_clusters;
+	trunc_len = old_clusters - new_clusters;
+	while (trunc_len) {
+		ret = ocfs2_xattr_get_clusters(inode, cpos, &phys_cpos,
+					       &alloc_size, &xv->xr_list);
+		if (ret) {
+			mlog_errno(ret);
+			goto out;
+		}
+
+		if (alloc_size > trunc_len)
+			alloc_size = trunc_len;
+
+		ret = __ocfs2_remove_xattr_range(inode, root_bh, xv, cpos,
+						 phys_cpos, alloc_size,
+						 &dealloc);
+		if (ret) {
+			mlog_errno(ret);
+			goto out;
+		}
+
+		block = ocfs2_clusters_to_blocks(inode->i_sb, phys_cpos);
+		ocfs2_remove_xattr_clusters_from_cache(inode, block,
+						       alloc_size);
+		cpos += alloc_size;
+		trunc_len -= alloc_size;
+	}
+
+out:
+	ocfs2_schedule_truncate_log_flush(osb, 1);
+	ocfs2_run_deallocs(osb, &dealloc);
+
+	return ret;
+}
+
+static int ocfs2_xattr_value_truncate(struct inode *inode,
+				      struct buffer_head *root_bh,
+				      struct ocfs2_xattr_value_root *xv,
+				      int len)
+{
+	int ret;
+	u32 new_clusters = ocfs2_clusters_for_bytes(inode->i_sb, len);
+	u32 old_clusters = le32_to_cpu(xv->xr_clusters);
+
+	if (new_clusters == old_clusters)
+		return 0;
+
+	if (new_clusters > old_clusters)
+		ret = ocfs2_xattr_extend_allocation(inode,
+						    new_clusters - old_clusters,
+						    root_bh, xv);
+	else
+		ret = ocfs2_xattr_shrink_size(inode,
+					      old_clusters, new_clusters,
+					      root_bh, xv);
+
+	return ret;
+}
+
+static int ocfs2_xattr_list_entry(char *buffer, size_t size,
+				  size_t *result, const char *prefix,
+				  const char *name, int name_len)
+{
+	char *p = buffer + *result;
+	int prefix_len = strlen(prefix);
+	int total_len = prefix_len + name_len + 1;
+
+	*result += total_len;
+
+	/* we are just looking for how big our buffer needs to be */
+	if (!size)
+		return 0;
+
+	if (*result > size)
+		return -ERANGE;
+
+	memcpy(p, prefix, prefix_len);
+	memcpy(p + prefix_len, name, name_len);
+	p[prefix_len + name_len] = '\0';
+
+	return 0;
+}
+
+static int ocfs2_xattr_list_entries(struct inode *inode,
+				    struct ocfs2_xattr_header *header,
+				    char *buffer, size_t buffer_size)
+{
+	size_t result = 0;
+	int i, type, ret;
+	const char *prefix, *name;
+
+	for (i = 0 ; i < le16_to_cpu(header->xh_count); i++) {
+		struct ocfs2_xattr_entry *entry = &header->xh_entries[i];
+		type = ocfs2_xattr_get_type(entry);
+		prefix = ocfs2_xattr_prefix(type);
+
+		if (prefix) {
+			name = (const char *)header +
+				le16_to_cpu(entry->xe_name_offset);
+
+			ret = ocfs2_xattr_list_entry(buffer, buffer_size,
+						     &result, prefix, name,
+						     entry->xe_name_len);
+			if (ret)
+				return ret;
+		}
+	}
+
+	return result;
+}
+
+static int ocfs2_xattr_ibody_list(struct inode *inode,
+				  struct ocfs2_dinode *di,
+				  char *buffer,
+				  size_t buffer_size)
+{
+	struct ocfs2_xattr_header *header = NULL;
+	struct ocfs2_inode_info *oi = OCFS2_I(inode);
+	int ret = 0;
+
+	if (!(oi->ip_dyn_features & OCFS2_INLINE_XATTR_FL))
+		return ret;
+
+	header = (struct ocfs2_xattr_header *)
+		 ((void *)di + inode->i_sb->s_blocksize -
+		 le16_to_cpu(di->i_xattr_inline_size));
+
+	ret = ocfs2_xattr_list_entries(inode, header, buffer, buffer_size);
+
+	return ret;
+}
+
+static int ocfs2_xattr_block_list(struct inode *inode,
+				  struct ocfs2_dinode *di,
+				  char *buffer,
+				  size_t buffer_size)
+{
+	struct buffer_head *blk_bh = NULL;
+	struct ocfs2_xattr_block *xb;
+	int ret = 0;
+
+	if (!di->i_xattr_loc)
+		return ret;
+
+	ret = ocfs2_read_block(inode, le64_to_cpu(di->i_xattr_loc), &blk_bh);
+	if (ret < 0) {
+		mlog_errno(ret);
+		return ret;
+	}
+	/*Verify the signature of xattr block*/
+	if (memcmp((void *)blk_bh->b_data, OCFS2_XATTR_BLOCK_SIGNATURE,
+		   strlen(OCFS2_XATTR_BLOCK_SIGNATURE))) {
+		ret = -EFAULT;
+		goto cleanup;
+	}
+
+	xb = (struct ocfs2_xattr_block *)blk_bh->b_data;
+
+	if (!(le16_to_cpu(xb->xb_flags) & OCFS2_XATTR_INDEXED)) {
+		struct ocfs2_xattr_header *header = &xb->xb_attrs.xb_header;
+		ret = ocfs2_xattr_list_entries(inode, header,
+					       buffer, buffer_size);
+	} else {
+		struct ocfs2_xattr_tree_root *xt = &xb->xb_attrs.xb_root;
+		ret = ocfs2_xattr_tree_list_index_block(inode, xt,
+						   buffer, buffer_size);
+	}
+cleanup:
+	brelse(blk_bh);
+
+	return ret;
+}
+
+ssize_t ocfs2_listxattr(struct dentry *dentry,
+			char *buffer,
+			size_t size)
+{
+	int ret = 0, i_ret = 0, b_ret = 0;
+	struct buffer_head *di_bh = NULL;
+	struct ocfs2_dinode *di = NULL;
+	struct ocfs2_inode_info *oi = OCFS2_I(dentry->d_inode);
+
+	if (!ocfs2_supports_xattr(OCFS2_SB(dentry->d_sb)))
+		return -EOPNOTSUPP;
+
+	if (!(oi->ip_dyn_features & OCFS2_HAS_XATTR_FL))
+		return ret;
+
+	ret = ocfs2_inode_lock(dentry->d_inode, &di_bh, 0);
+	if (ret < 0) {
+		mlog_errno(ret);
+		return ret;
+	}
+
+	di = (struct ocfs2_dinode *)di_bh->b_data;
+
+	down_read(&oi->ip_xattr_sem);
+	i_ret = ocfs2_xattr_ibody_list(dentry->d_inode, di, buffer, size);
+	if (i_ret < 0)
+		b_ret = 0;
+	else {
+		if (buffer) {
+			buffer += i_ret;
+			size -= i_ret;
+		}
+		b_ret = ocfs2_xattr_block_list(dentry->d_inode, di,
+					       buffer, size);
+		if (b_ret < 0)
+			i_ret = 0;
+	}
+	up_read(&oi->ip_xattr_sem);
+	ocfs2_inode_unlock(dentry->d_inode, 0);
+
+	brelse(di_bh);
+
+	return i_ret + b_ret;
+}
+
+static int ocfs2_xattr_find_entry(int name_index,
+				  const char *name,
+				  struct ocfs2_xattr_search *xs)
+{
+	struct ocfs2_xattr_entry *entry;
+	size_t name_len;
+	int i, cmp = 1;
+
+	if (name == NULL)
+		return -EINVAL;
+
+	name_len = strlen(name);
+	entry = xs->here;
+	for (i = 0; i < le16_to_cpu(xs->header->xh_count); i++) {
+		cmp = name_index - ocfs2_xattr_get_type(entry);
+		if (!cmp)
+			cmp = name_len - entry->xe_name_len;
+		if (!cmp)
+			cmp = memcmp(name, (xs->base +
+				     le16_to_cpu(entry->xe_name_offset)),
+				     name_len);
+		if (cmp == 0)
+			break;
+		entry += 1;
+	}
+	xs->here = entry;
+
+	return cmp ? -ENODATA : 0;
+}
+
+static int ocfs2_xattr_get_value_outside(struct inode *inode,
+					 struct ocfs2_xattr_value_root *xv,
+					 void *buffer,
+					 size_t len)
+{
+	u32 cpos, p_cluster, num_clusters, bpc, clusters;
+	u64 blkno;
+	int i, ret = 0;
+	size_t cplen, blocksize;
+	struct buffer_head *bh = NULL;
+	struct ocfs2_extent_list *el;
+
+	el = &xv->xr_list;
+	clusters = le32_to_cpu(xv->xr_clusters);
+	bpc = ocfs2_clusters_to_blocks(inode->i_sb, 1);
+	blocksize = inode->i_sb->s_blocksize;
+
+	cpos = 0;
+	while (cpos < clusters) {
+		ret = ocfs2_xattr_get_clusters(inode, cpos, &p_cluster,
+					       &num_clusters, el);
+		if (ret) {
+			mlog_errno(ret);
+			goto out;
+		}
+
+		blkno = ocfs2_clusters_to_blocks(inode->i_sb, p_cluster);
+		/* Copy ocfs2_xattr_value */
+		for (i = 0; i < num_clusters * bpc; i++, blkno++) {
+			ret = ocfs2_read_block(inode, blkno, &bh);
+			if (ret) {
+				mlog_errno(ret);
+				goto out;
+			}
+
+			cplen = len >= blocksize ? blocksize : len;
+			memcpy(buffer, bh->b_data, cplen);
+			len -= cplen;
+			buffer += cplen;
+
+			brelse(bh);
+			bh = NULL;
+			if (len == 0)
+				break;
+		}
+		cpos += num_clusters;
+	}
+out:
+	return ret;
+}
+
+static int ocfs2_xattr_ibody_get(struct inode *inode,
+				 int name_index,
+				 const char *name,
+				 void *buffer,
+				 size_t buffer_size,
+				 struct ocfs2_xattr_search *xs)
+{
+	struct ocfs2_inode_info *oi = OCFS2_I(inode);
+	struct ocfs2_dinode *di = (struct ocfs2_dinode *)xs->inode_bh->b_data;
+	struct ocfs2_xattr_value_root *xv;
+	size_t size;
+	int ret = 0;
+
+	if (!(oi->ip_dyn_features & OCFS2_INLINE_XATTR_FL))
+		return -ENODATA;
+
+	xs->end = (void *)di + inode->i_sb->s_blocksize;
+	xs->header = (struct ocfs2_xattr_header *)
+			(xs->end - le16_to_cpu(di->i_xattr_inline_size));
+	xs->base = (void *)xs->header;
+	xs->here = xs->header->xh_entries;
+
+	ret = ocfs2_xattr_find_entry(name_index, name, xs);
+	if (ret)
+		return ret;
+	size = le64_to_cpu(xs->here->xe_value_size);
+	if (buffer) {
+		if (size > buffer_size)
+			return -ERANGE;
+		if (ocfs2_xattr_is_local(xs->here)) {
+			memcpy(buffer, (void *)xs->base +
+			       le16_to_cpu(xs->here->xe_name_offset) +
+			       OCFS2_XATTR_SIZE(xs->here->xe_name_len), size);
+		} else {
+			xv = (struct ocfs2_xattr_value_root *)
+				(xs->base + le16_to_cpu(
+				 xs->here->xe_name_offset) +
+				OCFS2_XATTR_SIZE(xs->here->xe_name_len));
+			ret = ocfs2_xattr_get_value_outside(inode, xv,
+							    buffer, size);
+			if (ret < 0) {
+				mlog_errno(ret);
+				return ret;
+			}
+		}
+	}
+
+	return size;
+}
+
+static int ocfs2_xattr_block_get(struct inode *inode,
+				 int name_index,
+				 const char *name,
+				 void *buffer,
+				 size_t buffer_size,
+				 struct ocfs2_xattr_search *xs)
+{
+	struct ocfs2_dinode *di = (struct ocfs2_dinode *)xs->inode_bh->b_data;
+	struct buffer_head *blk_bh = NULL;
+	struct ocfs2_xattr_block *xb;
+	struct ocfs2_xattr_value_root *xv;
+	size_t size;
+	int ret = -ENODATA, name_offset, name_len, block_off, i;
+
+	if (!di->i_xattr_loc)
+		return ret;
+
+	memset(&xs->bucket, 0, sizeof(xs->bucket));
+
+	ret = ocfs2_read_block(inode, le64_to_cpu(di->i_xattr_loc), &blk_bh);
+	if (ret < 0) {
+		mlog_errno(ret);
+		return ret;
+	}
+	/*Verify the signature of xattr block*/
+	if (memcmp((void *)blk_bh->b_data, OCFS2_XATTR_BLOCK_SIGNATURE,
+		   strlen(OCFS2_XATTR_BLOCK_SIGNATURE))) {
+		ret = -EFAULT;
+		goto cleanup;
+	}
+
+	xs->xattr_bh = blk_bh;
+	xb = (struct ocfs2_xattr_block *)blk_bh->b_data;
+
+	if (!(le16_to_cpu(xb->xb_flags) & OCFS2_XATTR_INDEXED)) {
+		xs->header = &xb->xb_attrs.xb_header;
+		xs->base = (void *)xs->header;
+		xs->end = (void *)(blk_bh->b_data) + blk_bh->b_size;
+		xs->here = xs->header->xh_entries;
+
+		ret = ocfs2_xattr_find_entry(name_index, name, xs);
+	} else
+		ret = ocfs2_xattr_index_block_find(inode, blk_bh,
+						   name_index,
+						   name, xs);
+
+	if (ret)
+		goto cleanup;
+	size = le64_to_cpu(xs->here->xe_value_size);
+	if (buffer) {
+		ret = -ERANGE;
+		if (size > buffer_size)
+			goto cleanup;
+
+		name_offset = le16_to_cpu(xs->here->xe_name_offset);
+		name_len = OCFS2_XATTR_SIZE(xs->here->xe_name_len);
+		i = xs->here - xs->header->xh_entries;
+
+		if (le16_to_cpu(xb->xb_flags) & OCFS2_XATTR_INDEXED) {
+			ret = ocfs2_xattr_bucket_get_name_value(inode,
+								xs->bucket.xh,
+								i,
+								&block_off,
+								&name_offset);
+			xs->base = xs->bucket.bhs[block_off]->b_data;
+		}
+		if (ocfs2_xattr_is_local(xs->here)) {
+			memcpy(buffer, (void *)xs->base +
+			       name_offset + name_len, size);
+		} else {
+			xv = (struct ocfs2_xattr_value_root *)
+				(xs->base + name_offset + name_len);
+			ret = ocfs2_xattr_get_value_outside(inode, xv,
+							    buffer, size);
+			if (ret < 0) {
+				mlog_errno(ret);
+				goto cleanup;
+			}
+		}
+	}
+	ret = size;
+cleanup:
+	for (i = 0; i < OCFS2_XATTR_MAX_BLOCKS_PER_BUCKET; i++)
+		brelse(xs->bucket.bhs[i]);
+	memset(&xs->bucket, 0, sizeof(xs->bucket));
+
+	brelse(blk_bh);
+	return ret;
+}
+
+/* ocfs2_xattr_get()
+ *
+ * Copy an extended attribute into the buffer provided.
+ * Buffer is NULL to compute the size of buffer required.
+ */
+int ocfs2_xattr_get(struct inode *inode,
+		    int name_index,
+		    const char *name,
+		    void *buffer,
+		    size_t buffer_size)
+{
+	int ret;
+	struct ocfs2_dinode *di = NULL;
+	struct buffer_head *di_bh = NULL;
+	struct ocfs2_inode_info *oi = OCFS2_I(inode);
+	struct ocfs2_xattr_search xis = {
+		.not_found = -ENODATA,
+	};
+	struct ocfs2_xattr_search xbs = {
+		.not_found = -ENODATA,
+	};
+
+	if (!ocfs2_supports_xattr(OCFS2_SB(inode->i_sb)))
+		return -EOPNOTSUPP;
+
+	if (!(oi->ip_dyn_features & OCFS2_HAS_XATTR_FL))
+		ret = -ENODATA;
+
+	ret = ocfs2_inode_lock(inode, &di_bh, 0);
+	if (ret < 0) {
+		mlog_errno(ret);
+		return ret;
+	}
+	xis.inode_bh = xbs.inode_bh = di_bh;
+	di = (struct ocfs2_dinode *)di_bh->b_data;
+
+	down_read(&oi->ip_xattr_sem);
+	ret = ocfs2_xattr_ibody_get(inode, name_index, name, buffer,
+				    buffer_size, &xis);
+	if (ret == -ENODATA)
+		ret = ocfs2_xattr_block_get(inode, name_index, name, buffer,
+					    buffer_size, &xbs);
+	up_read(&oi->ip_xattr_sem);
+	ocfs2_inode_unlock(inode, 0);
+
+	brelse(di_bh);
+
+	return ret;
+}
+
+static int __ocfs2_xattr_set_value_outside(struct inode *inode,
+					   struct ocfs2_xattr_value_root *xv,
+					   const void *value,
+					   int value_len)
+{
+	int ret = 0, i, cp_len, credits;
+	u16 blocksize = inode->i_sb->s_blocksize;
+	u32 p_cluster, num_clusters;
+	u32 cpos = 0, bpc = ocfs2_clusters_to_blocks(inode->i_sb, 1);
+	u32 clusters = ocfs2_clusters_for_bytes(inode->i_sb, value_len);
+	u64 blkno;
+	struct buffer_head *bh = NULL;
+	handle_t *handle;
+
+	BUG_ON(clusters > le32_to_cpu(xv->xr_clusters));
+
+	credits = clusters * bpc;
+	handle = ocfs2_start_trans(OCFS2_SB(inode->i_sb), credits);
+	if (IS_ERR(handle)) {
+		ret = PTR_ERR(handle);
+		mlog_errno(ret);
+		goto out;
+	}
+
+	while (cpos < clusters) {
+		ret = ocfs2_xattr_get_clusters(inode, cpos, &p_cluster,
+					       &num_clusters, &xv->xr_list);
+		if (ret) {
+			mlog_errno(ret);
+			goto out_commit;
+		}
+
+		blkno = ocfs2_clusters_to_blocks(inode->i_sb, p_cluster);
+
+		for (i = 0; i < num_clusters * bpc; i++, blkno++) {
+			ret = ocfs2_read_block(inode, blkno, &bh);
+			if (ret) {
+				mlog_errno(ret);
+				goto out_commit;
+			}
+
+			ret = ocfs2_journal_access(handle,
+						   inode,
+						   bh,
+						   OCFS2_JOURNAL_ACCESS_WRITE);
+			if (ret < 0) {
+				mlog_errno(ret);
+				goto out_commit;
+			}
+
+			cp_len = value_len > blocksize ? blocksize : value_len;
+			memcpy(bh->b_data, value, cp_len);
+			value_len -= cp_len;
+			value += cp_len;
+			if (cp_len < blocksize)
+				memset(bh->b_data + cp_len, 0,
+				       blocksize - cp_len);
+
+			ret = ocfs2_journal_dirty(handle, bh);
+			if (ret < 0) {
+				mlog_errno(ret);
+				goto out_commit;
+			}
+			brelse(bh);
+			bh = NULL;
+
+			/*
+			 * XXX: do we need to empty all the following
+			 * blocks in this cluster?
+			 */
+			if (!value_len)
+				break;
+		}
+		cpos += num_clusters;
+	}
+out_commit:
+	ocfs2_commit_trans(OCFS2_SB(inode->i_sb), handle);
+out:
+	brelse(bh);
+
+	return ret;
+}
+
+static int ocfs2_xattr_cleanup(struct inode *inode,
+			       struct ocfs2_xattr_info *xi,
+			       struct ocfs2_xattr_search *xs,
+			       size_t offs)
+{
+	handle_t *handle = NULL;
+	int ret = 0;
+	size_t name_len = strlen(xi->name);
+	void *val = xs->base + offs;
+	size_t size = OCFS2_XATTR_SIZE(name_len) + OCFS2_XATTR_ROOT_SIZE;
+
+	handle = ocfs2_start_trans((OCFS2_SB(inode->i_sb)),
+				   OCFS2_XATTR_BLOCK_UPDATE_CREDITS);
+	if (IS_ERR(handle)) {
+		ret = PTR_ERR(handle);
+		mlog_errno(ret);
+		goto out;
+	}
+	ret = ocfs2_journal_access(handle, inode, xs->xattr_bh,
+				   OCFS2_JOURNAL_ACCESS_WRITE);
+	if (ret) {
+		mlog_errno(ret);
+		goto out_commit;
+	}
+	/* Decrease xattr count */
+	le16_add_cpu(&xs->header->xh_count, -1);
+	/* Remove the xattr entry and tree root which has already be set*/
+	memset((void *)xs->here, 0, sizeof(struct ocfs2_xattr_entry));
+	memset(val, 0, size);
+
+	ret = ocfs2_journal_dirty(handle, xs->xattr_bh);
+	if (ret < 0)
+		mlog_errno(ret);
+out_commit:
+	ocfs2_commit_trans(OCFS2_SB(inode->i_sb), handle);
+out:
+	return ret;
+}
+
+static int ocfs2_xattr_update_entry(struct inode *inode,
+				    struct ocfs2_xattr_info *xi,
+				    struct ocfs2_xattr_search *xs,
+				    size_t offs)
+{
+	handle_t *handle = NULL;
+	int ret = 0;
+
+	handle = ocfs2_start_trans((OCFS2_SB(inode->i_sb)),
+				   OCFS2_XATTR_BLOCK_UPDATE_CREDITS);
+	if (IS_ERR(handle)) {
+		ret = PTR_ERR(handle);
+		mlog_errno(ret);
+		goto out;
+	}
+	ret = ocfs2_journal_access(handle, inode, xs->xattr_bh,
+				   OCFS2_JOURNAL_ACCESS_WRITE);
+	if (ret) {
+		mlog_errno(ret);
+		goto out_commit;
+	}
+
+	xs->here->xe_name_offset = cpu_to_le16(offs);
+	xs->here->xe_value_size = cpu_to_le64(xi->value_len);
+	if (xi->value_len <= OCFS2_XATTR_INLINE_SIZE)
+		ocfs2_xattr_set_local(xs->here, 1);
+	else
+		ocfs2_xattr_set_local(xs->here, 0);
+	ocfs2_xattr_hash_entry(inode, xs->header, xs->here);
+
+	ret = ocfs2_journal_dirty(handle, xs->xattr_bh);
+	if (ret < 0)
+		mlog_errno(ret);
+out_commit:
+	ocfs2_commit_trans(OCFS2_SB(inode->i_sb), handle);
+out:
+	return ret;
+}
+
+/*
+ * ocfs2_xattr_set_value_outside()
+ *
+ * Set large size value in B tree.
+ */
+static int ocfs2_xattr_set_value_outside(struct inode *inode,
+					 struct ocfs2_xattr_info *xi,
+					 struct ocfs2_xattr_search *xs,
+					 size_t offs)
+{
+	size_t name_len = strlen(xi->name);
+	void *val = xs->base + offs;
+	struct ocfs2_xattr_value_root *xv = NULL;
+	size_t size = OCFS2_XATTR_SIZE(name_len) + OCFS2_XATTR_ROOT_SIZE;
+	int ret = 0;
+
+	memset(val, 0, size);
+	memcpy(val, xi->name, name_len);
+	xv = (struct ocfs2_xattr_value_root *)
+		(val + OCFS2_XATTR_SIZE(name_len));
+	xv->xr_clusters = 0;
+	xv->xr_last_eb_blk = 0;
+	xv->xr_list.l_tree_depth = 0;
+	xv->xr_list.l_count = cpu_to_le16(1);
+	xv->xr_list.l_next_free_rec = 0;
+
+	ret = ocfs2_xattr_value_truncate(inode, xs->xattr_bh, xv,
+					 xi->value_len);
+	if (ret < 0) {
+		mlog_errno(ret);
+		return ret;
+	}
+	ret = __ocfs2_xattr_set_value_outside(inode, xv, xi->value,
+					      xi->value_len);
+	if (ret < 0) {
+		mlog_errno(ret);
+		return ret;
+	}
+	ret = ocfs2_xattr_update_entry(inode, xi, xs, offs);
+	if (ret < 0)
+		mlog_errno(ret);
+
+	return ret;
+}
+
+/*
+ * ocfs2_xattr_set_entry_local()
+ *
+ * Set, replace or remove extended attribute in local.
+ */
+static void ocfs2_xattr_set_entry_local(struct inode *inode,
+					struct ocfs2_xattr_info *xi,
+					struct ocfs2_xattr_search *xs,
+					struct ocfs2_xattr_entry *last,
+					size_t min_offs)
+{
+	size_t name_len = strlen(xi->name);
+	int i;
+
+	if (xi->value && xs->not_found) {
+		/* Insert the new xattr entry. */
+		le16_add_cpu(&xs->header->xh_count, 1);
+		ocfs2_xattr_set_type(last, xi->name_index);
+		ocfs2_xattr_set_local(last, 1);
+		last->xe_name_len = name_len;
+	} else {
+		void *first_val;
+		void *val;
+		size_t offs, size;
+
+		first_val = xs->base + min_offs;
+		offs = le16_to_cpu(xs->here->xe_name_offset);
+		val = xs->base + offs;
+
+		if (le64_to_cpu(xs->here->xe_value_size) >
+		    OCFS2_XATTR_INLINE_SIZE)
+			size = OCFS2_XATTR_SIZE(name_len) +
+				OCFS2_XATTR_ROOT_SIZE;
+		else
+			size = OCFS2_XATTR_SIZE(name_len) +
+			OCFS2_XATTR_SIZE(le64_to_cpu(xs->here->xe_value_size));
+
+		if (xi->value && size == OCFS2_XATTR_SIZE(name_len) +
+				OCFS2_XATTR_SIZE(xi->value_len)) {
+			/* The old and the new value have the
+			   same size. Just replace the value. */
+			ocfs2_xattr_set_local(xs->here, 1);
+			xs->here->xe_value_size = cpu_to_le64(xi->value_len);
+			/* Clear value bytes. */
+			memset(val + OCFS2_XATTR_SIZE(name_len),
+			       0,
+			       OCFS2_XATTR_SIZE(xi->value_len));
+			memcpy(val + OCFS2_XATTR_SIZE(name_len),
+			       xi->value,
+			       xi->value_len);
+			return;
+		}
+		/* Remove the old name+value. */
+		memmove(first_val + size, first_val, val - first_val);
+		memset(first_val, 0, size);
+		xs->here->xe_name_hash = 0;
+		xs->here->xe_name_offset = 0;
+		ocfs2_xattr_set_local(xs->here, 1);
+		xs->here->xe_value_size = 0;
+
+		min_offs += size;
+
+		/* Adjust all value offsets. */
+		last = xs->header->xh_entries;
+		for (i = 0 ; i < le16_to_cpu(xs->header->xh_count); i++) {
+			size_t o = le16_to_cpu(last->xe_name_offset);
+
+			if (o < offs)
+				last->xe_name_offset = cpu_to_le16(o + size);
+			last += 1;
+		}
+
+		if (!xi->value) {
+			/* Remove the old entry. */
+			last -= 1;
+			memmove(xs->here, xs->here + 1,
+				(void *)last - (void *)xs->here);
+			memset(last, 0, sizeof(struct ocfs2_xattr_entry));
+			le16_add_cpu(&xs->header->xh_count, -1);
+		}
+	}
+	if (xi->value) {
+		/* Insert the new name+value. */
+		size_t size = OCFS2_XATTR_SIZE(name_len) +
+				OCFS2_XATTR_SIZE(xi->value_len);
+		void *val = xs->base + min_offs - size;
+
+		xs->here->xe_name_offset = cpu_to_le16(min_offs - size);
+		memset(val, 0, size);
+		memcpy(val, xi->name, name_len);
+		memcpy(val + OCFS2_XATTR_SIZE(name_len),
+		       xi->value,
+		       xi->value_len);
+		xs->here->xe_value_size = cpu_to_le64(xi->value_len);
+		ocfs2_xattr_set_local(xs->here, 1);
+		ocfs2_xattr_hash_entry(inode, xs->header, xs->here);
+	}
+
+	return;
+}
+
+/*
+ * ocfs2_xattr_set_entry()
+ *
+ * Set extended attribute entry into inode or block.
+ *
+ * If extended attribute value size > OCFS2_XATTR_INLINE_SIZE,
+ * We first insert tree root(ocfs2_xattr_value_root) with set_entry_local(),
+ * then set value in B tree with set_value_outside().
+ */
+static int ocfs2_xattr_set_entry(struct inode *inode,
+				 struct ocfs2_xattr_info *xi,
+				 struct ocfs2_xattr_search *xs,
+				 int flag)
+{
+	struct ocfs2_xattr_entry *last;
+	struct ocfs2_inode_info *oi = OCFS2_I(inode);
+	struct ocfs2_dinode *di = (struct ocfs2_dinode *)xs->inode_bh->b_data;
+	size_t min_offs = xs->end - xs->base, name_len = strlen(xi->name);
+	size_t size_l = 0;
+	handle_t *handle = NULL;
+	int free, i, ret;
+	struct ocfs2_xattr_info xi_l = {
+		.name_index = xi->name_index,
+		.name = xi->name,
+		.value = xi->value,
+		.value_len = xi->value_len,
+	};
+
+	/* Compute min_offs, last and free space. */
+	last = xs->header->xh_entries;
+
+	for (i = 0 ; i < le16_to_cpu(xs->header->xh_count); i++) {
+		size_t offs = le16_to_cpu(last->xe_name_offset);
+		if (offs < min_offs)
+			min_offs = offs;
+		last += 1;
+	}
+
+	free = min_offs - ((void *)last - xs->base) - sizeof(__u32);
+	if (free < 0)
+		return -EFAULT;
+
+	if (!xs->not_found) {
+		size_t size = 0;
+		if (ocfs2_xattr_is_local(xs->here))
+			size = OCFS2_XATTR_SIZE(name_len) +
+			OCFS2_XATTR_SIZE(le64_to_cpu(xs->here->xe_value_size));
+		else
+			size = OCFS2_XATTR_SIZE(name_len) +
+				OCFS2_XATTR_ROOT_SIZE;
+		free += (size + sizeof(struct ocfs2_xattr_entry));
+	}
+	/* Check free space in inode or block */
+	if (xi->value && xi->value_len > OCFS2_XATTR_INLINE_SIZE) {
+		if (free < sizeof(struct ocfs2_xattr_entry) +
+			   OCFS2_XATTR_SIZE(name_len) +
+			   OCFS2_XATTR_ROOT_SIZE) {
+			ret = -ENOSPC;
+			goto out;
+		}
+		size_l = OCFS2_XATTR_SIZE(name_len) + OCFS2_XATTR_ROOT_SIZE;
+		xi_l.value = (void *)&def_xv;
+		xi_l.value_len = OCFS2_XATTR_ROOT_SIZE;
+	} else if (xi->value) {
+		if (free < sizeof(struct ocfs2_xattr_entry) +
+			   OCFS2_XATTR_SIZE(name_len) +
+			   OCFS2_XATTR_SIZE(xi->value_len)) {
+			ret = -ENOSPC;
+			goto out;
+		}
+	}
+
+	if (!xs->not_found) {
+		/* For existing extended attribute */
+		size_t size = OCFS2_XATTR_SIZE(name_len) +
+			OCFS2_XATTR_SIZE(le64_to_cpu(xs->here->xe_value_size));
+		size_t offs = le16_to_cpu(xs->here->xe_name_offset);
+		void *val = xs->base + offs;
+
+		if (ocfs2_xattr_is_local(xs->here) && size == size_l) {
+			/* Replace existing local xattr with tree root */
+			ret = ocfs2_xattr_set_value_outside(inode, xi, xs,
+							    offs);
+			if (ret < 0)
+				mlog_errno(ret);
+			goto out;
+		} else if (!ocfs2_xattr_is_local(xs->here)) {
+			/* For existing xattr which has value outside */
+			struct ocfs2_xattr_value_root *xv = NULL;
+			xv = (struct ocfs2_xattr_value_root *)(val +
+				OCFS2_XATTR_SIZE(name_len));
+
+			if (xi->value_len > OCFS2_XATTR_INLINE_SIZE) {
+				/*
+				 * If new value need set outside also,
+				 * first truncate old value to new value,
+				 * then set new value with set_value_outside().
+				 */
+				ret = ocfs2_xattr_value_truncate(inode,
+								 xs->xattr_bh,
+								 xv,
+								 xi->value_len);
+				if (ret < 0) {
+					mlog_errno(ret);
+					goto out;
+				}
+
+				ret = __ocfs2_xattr_set_value_outside(inode,
+								xv,
+								xi->value,
+								xi->value_len);
+				if (ret < 0) {
+					mlog_errno(ret);
+					goto out;
+				}
+
+				ret = ocfs2_xattr_update_entry(inode,
+							       xi,
+							       xs,
+							       offs);
+				if (ret < 0)
+					mlog_errno(ret);
+				goto out;
+			} else {
+				/*
+				 * If new value need set in local,
+				 * just trucate old value to zero.
+				 */
+				 ret = ocfs2_xattr_value_truncate(inode,
+								 xs->xattr_bh,
+								 xv,
+								 0);
+				if (ret < 0)
+					mlog_errno(ret);
+			}
+		}
+	}
+
+	handle = ocfs2_start_trans((OCFS2_SB(inode->i_sb)),
+				   OCFS2_INODE_UPDATE_CREDITS);
+	if (IS_ERR(handle)) {
+		ret = PTR_ERR(handle);
+		mlog_errno(ret);
+		goto out;
+	}
+
+	ret = ocfs2_journal_access(handle, inode, xs->inode_bh,
+				   OCFS2_JOURNAL_ACCESS_WRITE);
+	if (ret) {
+		mlog_errno(ret);
+		goto out_commit;
+	}
+
+	if (!(flag & OCFS2_INLINE_XATTR_FL)) {
+		/* set extended attribute in external block. */
+		ret = ocfs2_extend_trans(handle,
+					 OCFS2_INODE_UPDATE_CREDITS +
+					 OCFS2_XATTR_BLOCK_UPDATE_CREDITS);
+		if (ret) {
+			mlog_errno(ret);
+			goto out_commit;
+		}
+		ret = ocfs2_journal_access(handle, inode, xs->xattr_bh,
+					   OCFS2_JOURNAL_ACCESS_WRITE);
+		if (ret) {
+			mlog_errno(ret);
+			goto out_commit;
+		}
+	}
+
+	/*
+	 * Set value in local, include set tree root in local.
+	 * This is the first step for value size >INLINE_SIZE.
+	 */
+	ocfs2_xattr_set_entry_local(inode, &xi_l, xs, last, min_offs);
+
+	if (!(flag & OCFS2_INLINE_XATTR_FL)) {
+		ret = ocfs2_journal_dirty(handle, xs->xattr_bh);
+		if (ret < 0) {
+			mlog_errno(ret);
+			goto out_commit;
+		}
+	}
+
+	if (!(oi->ip_dyn_features & OCFS2_INLINE_XATTR_FL) &&
+	    (flag & OCFS2_INLINE_XATTR_FL)) {
+		struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+		unsigned int xattrsize = osb->s_xattr_inline_size;
+
+		/*
+		 * Adjust extent record count or inline data size
+		 * to reserve space for extended attribute.
+		 */
+		if (oi->ip_dyn_features & OCFS2_INLINE_DATA_FL) {
+			struct ocfs2_inline_data *idata = &di->id2.i_data;
+			le16_add_cpu(&idata->id_count, -xattrsize);
+		} else if (!(ocfs2_inode_is_fast_symlink(inode))) {
+			struct ocfs2_extent_list *el = &di->id2.i_list;
+			le16_add_cpu(&el->l_count, -(xattrsize /
+					sizeof(struct ocfs2_extent_rec)));
+		}
+		di->i_xattr_inline_size = cpu_to_le16(xattrsize);
+	}
+	/* Update xattr flag */
+	spin_lock(&oi->ip_lock);
+	oi->ip_dyn_features |= flag;
+	di->i_dyn_features = cpu_to_le16(oi->ip_dyn_features);
+	spin_unlock(&oi->ip_lock);
+	/* Update inode ctime */
+	inode->i_ctime = CURRENT_TIME;
+	di->i_ctime = cpu_to_le64(inode->i_ctime.tv_sec);
+	di->i_ctime_nsec = cpu_to_le32(inode->i_ctime.tv_nsec);
+
+	ret = ocfs2_journal_dirty(handle, xs->inode_bh);
+	if (ret < 0)
+		mlog_errno(ret);
+
+out_commit:
+	ocfs2_commit_trans(OCFS2_SB(inode->i_sb), handle);
+
+	if (!ret && xi->value_len > OCFS2_XATTR_INLINE_SIZE) {
+		/*
+		 * Set value outside in B tree.
+		 * This is the second step for value size > INLINE_SIZE.
+		 */
+		size_t offs = le16_to_cpu(xs->here->xe_name_offset);
+		ret = ocfs2_xattr_set_value_outside(inode, xi, xs, offs);
+		if (ret < 0) {
+			int ret2;
+
+			mlog_errno(ret);
+			/*
+			 * If set value outside failed, we have to clean
+			 * the junk tree root we have already set in local.
+			 */
+			ret2 = ocfs2_xattr_cleanup(inode, xi, xs, offs);
+			if (ret2 < 0)
+				mlog_errno(ret2);
+		}
+	}
+out:
+	return ret;
+
+}
+
+static int ocfs2_remove_value_outside(struct inode*inode,
+				      struct buffer_head *bh,
+				      struct ocfs2_xattr_header *header)
+{
+	int ret = 0, i;
+
+	for (i = 0; i < le16_to_cpu(header->xh_count); i++) {
+		struct ocfs2_xattr_entry *entry = &header->xh_entries[i];
+
+		if (!ocfs2_xattr_is_local(entry)) {
+			struct ocfs2_xattr_value_root *xv;
+			void *val;
+
+			val = (void *)header +
+				le16_to_cpu(entry->xe_name_offset);
+			xv = (struct ocfs2_xattr_value_root *)
+				(val + OCFS2_XATTR_SIZE(entry->xe_name_len));
+			ret = ocfs2_xattr_value_truncate(inode, bh, xv, 0);
+			if (ret < 0) {
+				mlog_errno(ret);
+				return ret;
+			}
+		}
+	}
+
+	return ret;
+}
+
+static int ocfs2_xattr_ibody_remove(struct inode *inode,
+				    struct buffer_head *di_bh)
+{
+
+	struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data;
+	struct ocfs2_xattr_header *header;
+	int ret;
+
+	header = (struct ocfs2_xattr_header *)
+		 ((void *)di + inode->i_sb->s_blocksize -
+		 le16_to_cpu(di->i_xattr_inline_size));
+
+	ret = ocfs2_remove_value_outside(inode, di_bh, header);
+
+	return ret;
+}
+
+static int ocfs2_xattr_block_remove(struct inode *inode,
+				    struct buffer_head *blk_bh)
+{
+	struct ocfs2_xattr_block *xb;
+	int ret = 0;
+
+	xb = (struct ocfs2_xattr_block *)blk_bh->b_data;
+	if (!(le16_to_cpu(xb->xb_flags) & OCFS2_XATTR_INDEXED)) {
+		struct ocfs2_xattr_header *header = &(xb->xb_attrs.xb_header);
+		ret = ocfs2_remove_value_outside(inode, blk_bh, header);
+	} else
+		ret = ocfs2_delete_xattr_index_block(inode, blk_bh);
+
+	return ret;
+}
+
+static int ocfs2_xattr_free_block(struct inode *inode,
+				  u64 block)
+{
+	struct inode *xb_alloc_inode;
+	struct buffer_head *xb_alloc_bh = NULL;
+	struct buffer_head *blk_bh = NULL;
+	struct ocfs2_xattr_block *xb;
+	struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+	handle_t *handle;
+	int ret = 0;
+	u64 blk, bg_blkno;
+	u16 bit;
+
+	ret = ocfs2_read_block(inode, block, &blk_bh);
+	if (ret < 0) {
+		mlog_errno(ret);
+		goto out;
+	}
+
+	/*Verify the signature of xattr block*/
+	if (memcmp((void *)blk_bh->b_data, OCFS2_XATTR_BLOCK_SIGNATURE,
+		   strlen(OCFS2_XATTR_BLOCK_SIGNATURE))) {
+		ret = -EFAULT;
+		goto out;
+	}
+
+	ret = ocfs2_xattr_block_remove(inode, blk_bh);
+	if (ret < 0) {
+		mlog_errno(ret);
+		goto out;
+	}
+
+	xb = (struct ocfs2_xattr_block *)blk_bh->b_data;
+	blk = le64_to_cpu(xb->xb_blkno);
+	bit = le16_to_cpu(xb->xb_suballoc_bit);
+	bg_blkno = ocfs2_which_suballoc_group(blk, bit);
+
+	xb_alloc_inode = ocfs2_get_system_file_inode(osb,
+				EXTENT_ALLOC_SYSTEM_INODE,
+				le16_to_cpu(xb->xb_suballoc_slot));
+	if (!xb_alloc_inode) {
+		ret = -ENOMEM;
+		mlog_errno(ret);
+		goto out;
+	}
+	mutex_lock(&xb_alloc_inode->i_mutex);
+
+	ret = ocfs2_inode_lock(xb_alloc_inode, &xb_alloc_bh, 1);
+	if (ret < 0) {
+		mlog_errno(ret);
+		goto out_mutex;
+	}
+
+	handle = ocfs2_start_trans(osb, OCFS2_SUBALLOC_FREE);
+	if (IS_ERR(handle)) {
+		ret = PTR_ERR(handle);
+		mlog_errno(ret);
+		goto out_unlock;
+	}
+
+	ret = ocfs2_free_suballoc_bits(handle, xb_alloc_inode, xb_alloc_bh,
+				       bit, bg_blkno, 1);
+	if (ret < 0)
+		mlog_errno(ret);
+
+	ocfs2_commit_trans(osb, handle);
+out_unlock:
+	ocfs2_inode_unlock(xb_alloc_inode, 1);
+	brelse(xb_alloc_bh);
+out_mutex:
+	mutex_unlock(&xb_alloc_inode->i_mutex);
+	iput(xb_alloc_inode);
+out:
+	brelse(blk_bh);
+	return ret;
+}
+
+/*
+ * ocfs2_xattr_remove()
+ *
+ * Free extended attribute resources associated with this inode.
+ */
+int ocfs2_xattr_remove(struct inode *inode, struct buffer_head *di_bh)
+{
+	struct ocfs2_inode_info *oi = OCFS2_I(inode);
+	struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data;
+	handle_t *handle;
+	int ret;
+
+	if (!ocfs2_supports_xattr(OCFS2_SB(inode->i_sb)))
+		return 0;
+
+	if (!(oi->ip_dyn_features & OCFS2_HAS_XATTR_FL))
+		return 0;
+
+	if (oi->ip_dyn_features & OCFS2_INLINE_XATTR_FL) {
+		ret = ocfs2_xattr_ibody_remove(inode, di_bh);
+		if (ret < 0) {
+			mlog_errno(ret);
+			goto out;
+		}
+	}
+
+	if (di->i_xattr_loc) {
+		ret = ocfs2_xattr_free_block(inode,
+					     le64_to_cpu(di->i_xattr_loc));
+		if (ret < 0) {
+			mlog_errno(ret);
+			goto out;
+		}
+	}
+
+	handle = ocfs2_start_trans((OCFS2_SB(inode->i_sb)),
+				   OCFS2_INODE_UPDATE_CREDITS);
+	if (IS_ERR(handle)) {
+		ret = PTR_ERR(handle);
+		mlog_errno(ret);
+		goto out;
+	}
+	ret = ocfs2_journal_access(handle, inode, di_bh,
+				   OCFS2_JOURNAL_ACCESS_WRITE);
+	if (ret) {
+		mlog_errno(ret);
+		goto out_commit;
+	}
+
+	di->i_xattr_loc = 0;
+
+	spin_lock(&oi->ip_lock);
+	oi->ip_dyn_features &= ~(OCFS2_INLINE_XATTR_FL | OCFS2_HAS_XATTR_FL);
+	di->i_dyn_features = cpu_to_le16(oi->ip_dyn_features);
+	spin_unlock(&oi->ip_lock);
+
+	ret = ocfs2_journal_dirty(handle, di_bh);
+	if (ret < 0)
+		mlog_errno(ret);
+out_commit:
+	ocfs2_commit_trans(OCFS2_SB(inode->i_sb), handle);
+out:
+	return ret;
+}
+
+static int ocfs2_xattr_has_space_inline(struct inode *inode,
+					struct ocfs2_dinode *di)
+{
+	struct ocfs2_inode_info *oi = OCFS2_I(inode);
+	unsigned int xattrsize = OCFS2_SB(inode->i_sb)->s_xattr_inline_size;
+	int free;
+
+	if (xattrsize < OCFS2_MIN_XATTR_INLINE_SIZE)
+		return 0;
+
+	if (oi->ip_dyn_features & OCFS2_INLINE_DATA_FL) {
+		struct ocfs2_inline_data *idata = &di->id2.i_data;
+		free = le16_to_cpu(idata->id_count) - le64_to_cpu(di->i_size);
+	} else if (ocfs2_inode_is_fast_symlink(inode)) {
+		free = ocfs2_fast_symlink_chars(inode->i_sb) -
+			le64_to_cpu(di->i_size);
+	} else {
+		struct ocfs2_extent_list *el = &di->id2.i_list;
+		free = (le16_to_cpu(el->l_count) -
+			le16_to_cpu(el->l_next_free_rec)) *
+			sizeof(struct ocfs2_extent_rec);
+	}
+	if (free >= xattrsize)
+		return 1;
+
+	return 0;
+}
+
+/*
+ * ocfs2_xattr_ibody_find()
+ *
+ * Find extended attribute in inode block and
+ * fill search info into struct ocfs2_xattr_search.
+ */
+static int ocfs2_xattr_ibody_find(struct inode *inode,
+				  int name_index,
+				  const char *name,
+				  struct ocfs2_xattr_search *xs)
+{
+	struct ocfs2_inode_info *oi = OCFS2_I(inode);
+	struct ocfs2_dinode *di = (struct ocfs2_dinode *)xs->inode_bh->b_data;
+	int ret;
+	int has_space = 0;
+
+	if (inode->i_sb->s_blocksize == OCFS2_MIN_BLOCKSIZE)
+		return 0;
+
+	if (!(oi->ip_dyn_features & OCFS2_INLINE_XATTR_FL)) {
+		down_read(&oi->ip_alloc_sem);
+		has_space = ocfs2_xattr_has_space_inline(inode, di);
+		up_read(&oi->ip_alloc_sem);
+		if (!has_space)
+			return 0;
+	}
+
+	xs->xattr_bh = xs->inode_bh;
+	xs->end = (void *)di + inode->i_sb->s_blocksize;
+	if (oi->ip_dyn_features & OCFS2_INLINE_XATTR_FL)
+		xs->header = (struct ocfs2_xattr_header *)
+			(xs->end - le16_to_cpu(di->i_xattr_inline_size));
+	else
+		xs->header = (struct ocfs2_xattr_header *)
+			(xs->end - OCFS2_SB(inode->i_sb)->s_xattr_inline_size);
+	xs->base = (void *)xs->header;
+	xs->here = xs->header->xh_entries;
+
+	/* Find the named attribute. */
+	if (oi->ip_dyn_features & OCFS2_INLINE_XATTR_FL) {
+		ret = ocfs2_xattr_find_entry(name_index, name, xs);
+		if (ret && ret != -ENODATA)
+			return ret;
+		xs->not_found = ret;
+	}
+
+	return 0;
+}
+
+/*
+ * ocfs2_xattr_ibody_set()
+ *
+ * Set, replace or remove an extended attribute into inode block.
+ *
+ */
+static int ocfs2_xattr_ibody_set(struct inode *inode,
+				 struct ocfs2_xattr_info *xi,
+				 struct ocfs2_xattr_search *xs)
+{
+	struct ocfs2_inode_info *oi = OCFS2_I(inode);
+	struct ocfs2_dinode *di = (struct ocfs2_dinode *)xs->inode_bh->b_data;
+	int ret;
+
+	if (inode->i_sb->s_blocksize == OCFS2_MIN_BLOCKSIZE)
+		return -ENOSPC;
+
+	down_write(&oi->ip_alloc_sem);
+	if (!(oi->ip_dyn_features & OCFS2_INLINE_XATTR_FL)) {
+		if (!ocfs2_xattr_has_space_inline(inode, di)) {
+			ret = -ENOSPC;
+			goto out;
+		}
+	}
+
+	ret = ocfs2_xattr_set_entry(inode, xi, xs,
+				(OCFS2_INLINE_XATTR_FL | OCFS2_HAS_XATTR_FL));
+out:
+	up_write(&oi->ip_alloc_sem);
+
+	return ret;
+}
+
+/*
+ * ocfs2_xattr_block_find()
+ *
+ * Find extended attribute in external block and
+ * fill search info into struct ocfs2_xattr_search.
+ */
+static int ocfs2_xattr_block_find(struct inode *inode,
+				  int name_index,
+				  const char *name,
+				  struct ocfs2_xattr_search *xs)
+{
+	struct ocfs2_dinode *di = (struct ocfs2_dinode *)xs->inode_bh->b_data;
+	struct buffer_head *blk_bh = NULL;
+	struct ocfs2_xattr_block *xb;
+	int ret = 0;
+
+	if (!di->i_xattr_loc)
+		return ret;
+
+	ret = ocfs2_read_block(inode, le64_to_cpu(di->i_xattr_loc), &blk_bh);
+	if (ret < 0) {
+		mlog_errno(ret);
+		return ret;
+	}
+	/*Verify the signature of xattr block*/
+	if (memcmp((void *)blk_bh->b_data, OCFS2_XATTR_BLOCK_SIGNATURE,
+		   strlen(OCFS2_XATTR_BLOCK_SIGNATURE))) {
+			ret = -EFAULT;
+			goto cleanup;
+	}
+
+	xs->xattr_bh = blk_bh;
+	xb = (struct ocfs2_xattr_block *)blk_bh->b_data;
+
+	if (!(le16_to_cpu(xb->xb_flags) & OCFS2_XATTR_INDEXED)) {
+		xs->header = &xb->xb_attrs.xb_header;
+		xs->base = (void *)xs->header;
+		xs->end = (void *)(blk_bh->b_data) + blk_bh->b_size;
+		xs->here = xs->header->xh_entries;
+
+		ret = ocfs2_xattr_find_entry(name_index, name, xs);
+	} else
+		ret = ocfs2_xattr_index_block_find(inode, blk_bh,
+						   name_index,
+						   name, xs);
+
+	if (ret && ret != -ENODATA) {
+		xs->xattr_bh = NULL;
+		goto cleanup;
+	}
+	xs->not_found = ret;
+	return 0;
+cleanup:
+	brelse(blk_bh);
+
+	return ret;
+}
+
+/*
+ * When all the xattrs are deleted from index btree, the ocfs2_xattr_tree
+ * will be erased and ocfs2_xattr_block will have its ocfs2_xattr_header
+ * re-initialized.
+ */
+static int ocfs2_restore_xattr_block(struct inode *inode,
+				     struct ocfs2_xattr_search *xs)
+{
+	int ret;
+	handle_t *handle;
+	struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+	struct ocfs2_xattr_block *xb =
+		(struct ocfs2_xattr_block *)xs->xattr_bh->b_data;
+	struct ocfs2_extent_list *el = &xb->xb_attrs.xb_root.xt_list;
+	u16 xb_flags = le16_to_cpu(xb->xb_flags);
+
+	BUG_ON(!(xb_flags & OCFS2_XATTR_INDEXED) ||
+		le16_to_cpu(el->l_next_free_rec) != 0);
+
+	handle = ocfs2_start_trans(osb, OCFS2_XATTR_BLOCK_UPDATE_CREDITS);
+	if (IS_ERR(handle)) {
+		ret = PTR_ERR(handle);
+		handle = NULL;
+		goto out;
+	}
+
+	ret = ocfs2_journal_access(handle, inode, xs->xattr_bh,
+				   OCFS2_JOURNAL_ACCESS_WRITE);
+	if (ret < 0) {
+		mlog_errno(ret);
+		goto out_commit;
+	}
+
+	memset(&xb->xb_attrs, 0, inode->i_sb->s_blocksize -
+	       offsetof(struct ocfs2_xattr_block, xb_attrs));
+
+	xb->xb_flags = cpu_to_le16(xb_flags & ~OCFS2_XATTR_INDEXED);
+
+	ocfs2_journal_dirty(handle, xs->xattr_bh);
+
+out_commit:
+	ocfs2_commit_trans(osb, handle);
+out:
+	return ret;
+}
+
+/*
+ * ocfs2_xattr_block_set()
+ *
+ * Set, replace or remove an extended attribute into external block.
+ *
+ */
+static int ocfs2_xattr_block_set(struct inode *inode,
+				 struct ocfs2_xattr_info *xi,
+				 struct ocfs2_xattr_search *xs)
+{
+	struct buffer_head *new_bh = NULL;
+	struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+	struct ocfs2_dinode *di =  (struct ocfs2_dinode *)xs->inode_bh->b_data;
+	struct ocfs2_alloc_context *meta_ac = NULL;
+	handle_t *handle = NULL;
+	struct ocfs2_xattr_block *xblk = NULL;
+	u16 suballoc_bit_start;
+	u32 num_got;
+	u64 first_blkno;
+	int ret;
+
+	if (!xs->xattr_bh) {
+		/*
+		 * Alloc one external block for extended attribute
+		 * outside of inode.
+		 */
+		ret = ocfs2_reserve_new_metadata_blocks(osb, 1, &meta_ac);
+		if (ret < 0) {
+			mlog_errno(ret);
+			goto out;
+		}
+		handle = ocfs2_start_trans(osb,
+					   OCFS2_XATTR_BLOCK_CREATE_CREDITS);
+		if (IS_ERR(handle)) {
+			ret = PTR_ERR(handle);
+			mlog_errno(ret);
+			goto out;
+		}
+		ret = ocfs2_journal_access(handle, inode, xs->inode_bh,
+					   OCFS2_JOURNAL_ACCESS_CREATE);
+		if (ret < 0) {
+			mlog_errno(ret);
+			goto out_commit;
+		}
+
+		ret = ocfs2_claim_metadata(osb, handle, meta_ac, 1,
+					   &suballoc_bit_start, &num_got,
+					   &first_blkno);
+		if (ret < 0) {
+			mlog_errno(ret);
+			goto out_commit;
+		}
+
+		new_bh = sb_getblk(inode->i_sb, first_blkno);
+		ocfs2_set_new_buffer_uptodate(inode, new_bh);
+
+		ret = ocfs2_journal_access(handle, inode, new_bh,
+					   OCFS2_JOURNAL_ACCESS_CREATE);
+		if (ret < 0) {
+			mlog_errno(ret);
+			goto out_commit;
+		}
+
+		/* Initialize ocfs2_xattr_block */
+		xs->xattr_bh = new_bh;
+		xblk = (struct ocfs2_xattr_block *)new_bh->b_data;
+		memset(xblk, 0, inode->i_sb->s_blocksize);
+		strcpy((void *)xblk, OCFS2_XATTR_BLOCK_SIGNATURE);
+		xblk->xb_suballoc_slot = cpu_to_le16(osb->slot_num);
+		xblk->xb_suballoc_bit = cpu_to_le16(suballoc_bit_start);
+		xblk->xb_fs_generation = cpu_to_le32(osb->fs_generation);
+		xblk->xb_blkno = cpu_to_le64(first_blkno);
+
+		xs->header = &xblk->xb_attrs.xb_header;
+		xs->base = (void *)xs->header;
+		xs->end = (void *)xblk + inode->i_sb->s_blocksize;
+		xs->here = xs->header->xh_entries;
+
+
+		ret = ocfs2_journal_dirty(handle, new_bh);
+		if (ret < 0) {
+			mlog_errno(ret);
+			goto out_commit;
+		}
+		di->i_xattr_loc = cpu_to_le64(first_blkno);
+		ret = ocfs2_journal_dirty(handle, xs->inode_bh);
+		if (ret < 0)
+			mlog_errno(ret);
+out_commit:
+		ocfs2_commit_trans(osb, handle);
+out:
+		if (meta_ac)
+			ocfs2_free_alloc_context(meta_ac);
+		if (ret < 0)
+			return ret;
+	} else
+		xblk = (struct ocfs2_xattr_block *)xs->xattr_bh->b_data;
+
+	if (!(le16_to_cpu(xblk->xb_flags) & OCFS2_XATTR_INDEXED)) {
+		/* Set extended attribute into external block */
+		ret = ocfs2_xattr_set_entry(inode, xi, xs, OCFS2_HAS_XATTR_FL);
+		if (!ret || ret != -ENOSPC)
+			goto end;
+
+		ret = ocfs2_xattr_create_index_block(inode, xs);
+		if (ret)
+			goto end;
+	}
+
+	ret = ocfs2_xattr_set_entry_index_block(inode, xi, xs);
+	if (!ret && xblk->xb_attrs.xb_root.xt_list.l_next_free_rec == 0)
+		ret = ocfs2_restore_xattr_block(inode, xs);
+
+end:
+
+	return ret;
+}
+
+/*
+ * ocfs2_xattr_set()
+ *
+ * Set, replace or remove an extended attribute for this inode.
+ * value is NULL to remove an existing extended attribute, else either
+ * create or replace an extended attribute.
+ */
+int ocfs2_xattr_set(struct inode *inode,
+		    int name_index,
+		    const char *name,
+		    const void *value,
+		    size_t value_len,
+		    int flags)
+{
+	struct buffer_head *di_bh = NULL;
+	struct ocfs2_dinode *di;
+	int ret;
+	u16 i, blk_per_bucket = ocfs2_blocks_per_xattr_bucket(inode->i_sb);
+
+	struct ocfs2_xattr_info xi = {
+		.name_index = name_index,
+		.name = name,
+		.value = value,
+		.value_len = value_len,
+	};
+
+	struct ocfs2_xattr_search xis = {
+		.not_found = -ENODATA,
+	};
+
+	struct ocfs2_xattr_search xbs = {
+		.not_found = -ENODATA,
+	};
+
+	if (!ocfs2_supports_xattr(OCFS2_SB(inode->i_sb)))
+		return -EOPNOTSUPP;
+
+	ret = ocfs2_inode_lock(inode, &di_bh, 1);
+	if (ret < 0) {
+		mlog_errno(ret);
+		return ret;
+	}
+	xis.inode_bh = xbs.inode_bh = di_bh;
+	di = (struct ocfs2_dinode *)di_bh->b_data;
+
+	down_write(&OCFS2_I(inode)->ip_xattr_sem);
+	/*
+	 * Scan inode and external block to find the same name
+	 * extended attribute and collect search infomation.
+	 */
+	ret = ocfs2_xattr_ibody_find(inode, name_index, name, &xis);
+	if (ret)
+		goto cleanup;
+	if (xis.not_found) {
+		ret = ocfs2_xattr_block_find(inode, name_index, name, &xbs);
+		if (ret)
+			goto cleanup;
+	}
+
+	if (xis.not_found && xbs.not_found) {
+		ret = -ENODATA;
+		if (flags & XATTR_REPLACE)
+			goto cleanup;
+		ret = 0;
+		if (!value)
+			goto cleanup;
+	} else {
+		ret = -EEXIST;
+		if (flags & XATTR_CREATE)
+			goto cleanup;
+	}
+
+	if (!value) {
+		/* Remove existing extended attribute */
+		if (!xis.not_found)
+			ret = ocfs2_xattr_ibody_set(inode, &xi, &xis);
+		else if (!xbs.not_found)
+			ret = ocfs2_xattr_block_set(inode, &xi, &xbs);
+	} else {
+		/* We always try to set extended attribute into inode first*/
+		ret = ocfs2_xattr_ibody_set(inode, &xi, &xis);
+		if (!ret && !xbs.not_found) {
+			/*
+			 * If succeed and that extended attribute existing in
+			 * external block, then we will remove it.
+			 */
+			xi.value = NULL;
+			xi.value_len = 0;
+			ret = ocfs2_xattr_block_set(inode, &xi, &xbs);
+		} else if (ret == -ENOSPC) {
+			if (di->i_xattr_loc && !xbs.xattr_bh) {
+				ret = ocfs2_xattr_block_find(inode, name_index,
+							     name, &xbs);
+				if (ret)
+					goto cleanup;
+			}
+			/*
+			 * If no space in inode, we will set extended attribute
+			 * into external block.
+			 */
+			ret = ocfs2_xattr_block_set(inode, &xi, &xbs);
+			if (ret)
+				goto cleanup;
+			if (!xis.not_found) {
+				/*
+				 * If succeed and that extended attribute
+				 * existing in inode, we will remove it.
+				 */
+				xi.value = NULL;
+				xi.value_len = 0;
+				ret = ocfs2_xattr_ibody_set(inode, &xi, &xis);
+			}
+		}
+	}
+cleanup:
+	up_write(&OCFS2_I(inode)->ip_xattr_sem);
+	ocfs2_inode_unlock(inode, 1);
+	brelse(di_bh);
+	brelse(xbs.xattr_bh);
+	for (i = 0; i < blk_per_bucket; i++)
+		brelse(xbs.bucket.bhs[i]);
+
+	return ret;
+}
+
+/*
+ * Find the xattr extent rec which may contains name_hash.
+ * e_cpos will be the first name hash of the xattr rec.
+ * el must be the ocfs2_xattr_header.xb_attrs.xb_root.xt_list.
+ */
+static int ocfs2_xattr_get_rec(struct inode *inode,
+			       u32 name_hash,
+			       u64 *p_blkno,
+			       u32 *e_cpos,
+			       u32 *num_clusters,
+			       struct ocfs2_extent_list *el)
+{
+	int ret = 0, i;
+	struct buffer_head *eb_bh = NULL;
+	struct ocfs2_extent_block *eb;
+	struct ocfs2_extent_rec *rec = NULL;
+	u64 e_blkno = 0;
+
+	if (el->l_tree_depth) {
+		ret = ocfs2_find_leaf(inode, el, name_hash, &eb_bh);
+		if (ret) {
+			mlog_errno(ret);
+			goto out;
+		}
+
+		eb = (struct ocfs2_extent_block *) eb_bh->b_data;
+		el = &eb->h_list;
+
+		if (el->l_tree_depth) {
+			ocfs2_error(inode->i_sb,
+				    "Inode %lu has non zero tree depth in "
+				    "xattr tree block %llu\n", inode->i_ino,
+				    (unsigned long long)eb_bh->b_blocknr);
+			ret = -EROFS;
+			goto out;
+		}
+	}
+
+	for (i = le16_to_cpu(el->l_next_free_rec) - 1; i >= 0; i--) {
+		rec = &el->l_recs[i];
+
+		if (le32_to_cpu(rec->e_cpos) <= name_hash) {
+			e_blkno = le64_to_cpu(rec->e_blkno);
+			break;
+		}
+	}
+
+	if (!e_blkno) {
+		ocfs2_error(inode->i_sb, "Inode %lu has bad extent "
+			    "record (%u, %u, 0) in xattr", inode->i_ino,
+			    le32_to_cpu(rec->e_cpos),
+			    ocfs2_rec_clusters(el, rec));
+		ret = -EROFS;
+		goto out;
+	}
+
+	*p_blkno = le64_to_cpu(rec->e_blkno);
+	*num_clusters = le16_to_cpu(rec->e_leaf_clusters);
+	if (e_cpos)
+		*e_cpos = le32_to_cpu(rec->e_cpos);
+out:
+	brelse(eb_bh);
+	return ret;
+}
+
+typedef int (xattr_bucket_func)(struct inode *inode,
+				struct ocfs2_xattr_bucket *bucket,
+				void *para);
+
+static int ocfs2_find_xe_in_bucket(struct inode *inode,
+				   struct buffer_head *header_bh,
+				   int name_index,
+				   const char *name,
+				   u32 name_hash,
+				   u16 *xe_index,
+				   int *found)
+{
+	int i, ret = 0, cmp = 1, block_off, new_offset;
+	struct ocfs2_xattr_header *xh =
+			(struct ocfs2_xattr_header *)header_bh->b_data;
+	size_t name_len = strlen(name);
+	struct ocfs2_xattr_entry *xe = NULL;
+	struct buffer_head *name_bh = NULL;
+	char *xe_name;
+
+	/*
+	 * We don't use binary search in the bucket because there
+	 * may be multiple entries with the same name hash.
+	 */
+	for (i = 0; i < le16_to_cpu(xh->xh_count); i++) {
+		xe = &xh->xh_entries[i];
+
+		if (name_hash > le32_to_cpu(xe->xe_name_hash))
+			continue;
+		else if (name_hash < le32_to_cpu(xe->xe_name_hash))
+			break;
+
+		cmp = name_index - ocfs2_xattr_get_type(xe);
+		if (!cmp)
+			cmp = name_len - xe->xe_name_len;
+		if (cmp)
+			continue;
+
+		ret = ocfs2_xattr_bucket_get_name_value(inode,
+							xh,
+							i,
+							&block_off,
+							&new_offset);
+		if (ret) {
+			mlog_errno(ret);
+			break;
+		}
+
+		ret = ocfs2_read_block(inode, header_bh->b_blocknr + block_off,
+				       &name_bh);
+		if (ret) {
+			mlog_errno(ret);
+			break;
+		}
+		xe_name = name_bh->b_data + new_offset;
+
+		cmp = memcmp(name, xe_name, name_len);
+		brelse(name_bh);
+		name_bh = NULL;
+
+		if (cmp == 0) {
+			*xe_index = i;
+			*found = 1;
+			ret = 0;
+			break;
+		}
+	}
+
+	return ret;
+}
+
+/*
+ * Find the specified xattr entry in a series of buckets.
+ * This series start from p_blkno and last for num_clusters.
+ * The ocfs2_xattr_header.xh_num_buckets of the first bucket contains
+ * the num of the valid buckets.
+ *
+ * Return the buffer_head this xattr should reside in. And if the xattr's
+ * hash is in the gap of 2 buckets, return the lower bucket.
+ */
+static int ocfs2_xattr_bucket_find(struct inode *inode,
+				   int name_index,
+				   const char *name,
+				   u32 name_hash,
+				   u64 p_blkno,
+				   u32 first_hash,
+				   u32 num_clusters,
+				   struct ocfs2_xattr_search *xs)
+{
+	int ret, found = 0;
+	struct buffer_head *bh = NULL;
+	struct buffer_head *lower_bh = NULL;
+	struct ocfs2_xattr_header *xh = NULL;
+	struct ocfs2_xattr_entry *xe = NULL;
+	u16 index = 0;
+	u16 blk_per_bucket = ocfs2_blocks_per_xattr_bucket(inode->i_sb);
+	int low_bucket = 0, bucket, high_bucket;
+	u32 last_hash;
+	u64 blkno;
+
+	ret = ocfs2_read_block(inode, p_blkno, &bh);
+	if (ret) {
+		mlog_errno(ret);
+		goto out;
+	}
+
+	xh = (struct ocfs2_xattr_header *)bh->b_data;
+	high_bucket = le16_to_cpu(xh->xh_num_buckets) - 1;
+
+	while (low_bucket <= high_bucket) {
+		brelse(bh);
+		bh = NULL;
+		bucket = (low_bucket + high_bucket) / 2;
+
+		blkno = p_blkno + bucket * blk_per_bucket;
+
+		ret = ocfs2_read_block(inode, blkno, &bh);
+		if (ret) {
+			mlog_errno(ret);
+			goto out;
+		}
+
+		xh = (struct ocfs2_xattr_header *)bh->b_data;
+		xe = &xh->xh_entries[0];
+		if (name_hash < le32_to_cpu(xe->xe_name_hash)) {
+			high_bucket = bucket - 1;
+			continue;
+		}
+
+		/*
+		 * Check whether the hash of the last entry in our
+		 * bucket is larger than the search one. for an empty
+		 * bucket, the last one is also the first one.
+		 */
+		if (xh->xh_count)
+			xe = &xh->xh_entries[le16_to_cpu(xh->xh_count) - 1];
+
+		last_hash = le32_to_cpu(xe->xe_name_hash);
+
+		/* record lower_bh which may be the insert place. */
+		brelse(lower_bh);
+		lower_bh = bh;
+		bh = NULL;
+
+		if (name_hash > le32_to_cpu(xe->xe_name_hash)) {
+			low_bucket = bucket + 1;
+			continue;
+		}
+
+		/* the searched xattr should reside in this bucket if exists. */
+		ret = ocfs2_find_xe_in_bucket(inode, lower_bh,
+					      name_index, name, name_hash,
+					      &index, &found);
+		if (ret) {
+			mlog_errno(ret);
+			goto out;
+		}
+		break;
+	}
+
+	/*
+	 * Record the bucket we have found.
+	 * When the xattr's hash value is in the gap of 2 buckets, we will
+	 * always set it to the previous bucket.
+	 */
+	if (!lower_bh) {
+		/*
+		 * We can't find any bucket whose first name_hash is less
+		 * than the find name_hash.
+		 */
+		BUG_ON(bh->b_blocknr != p_blkno);
+		lower_bh = bh;
+		bh = NULL;
+	}
+	xs->bucket.bhs[0] = lower_bh;
+	xs->bucket.xh = (struct ocfs2_xattr_header *)
+					xs->bucket.bhs[0]->b_data;
+	lower_bh = NULL;
+
+	xs->header = xs->bucket.xh;
+	xs->base = xs->bucket.bhs[0]->b_data;
+	xs->end = xs->base + inode->i_sb->s_blocksize;
+
+	if (found) {
+		/*
+		 * If we have found the xattr enty, read all the blocks in
+		 * this bucket.
+		 */
+		ret = ocfs2_read_blocks(inode, xs->bucket.bhs[0]->b_blocknr + 1,
+					blk_per_bucket - 1, &xs->bucket.bhs[1],
+					OCFS2_BH_CACHED);
+		if (ret) {
+			mlog_errno(ret);
+			goto out;
+		}
+
+		xs->here = &xs->header->xh_entries[index];
+		mlog(0, "find xattr %s in bucket %llu, entry = %u\n", name,
+		     (unsigned long long)xs->bucket.bhs[0]->b_blocknr, index);
+	} else
+		ret = -ENODATA;
+
+out:
+	brelse(bh);
+	brelse(lower_bh);
+	return ret;
+}
+
+static int ocfs2_xattr_index_block_find(struct inode *inode,
+					struct buffer_head *root_bh,
+					int name_index,
+					const char *name,
+					struct ocfs2_xattr_search *xs)
+{
+	int ret;
+	struct ocfs2_xattr_block *xb =
+			(struct ocfs2_xattr_block *)root_bh->b_data;
+	struct ocfs2_xattr_tree_root *xb_root = &xb->xb_attrs.xb_root;
+	struct ocfs2_extent_list *el = &xb_root->xt_list;
+	u64 p_blkno = 0;
+	u32 first_hash, num_clusters = 0;
+	u32 name_hash = ocfs2_xattr_name_hash(inode, name, strlen(name));
+
+	if (le16_to_cpu(el->l_next_free_rec) == 0)
+		return -ENODATA;
+
+	mlog(0, "find xattr %s, hash = %u, index = %d in xattr tree\n",
+	     name, name_hash, name_index);
+
+	ret = ocfs2_xattr_get_rec(inode, name_hash, &p_blkno, &first_hash,
+				  &num_clusters, el);
+	if (ret) {
+		mlog_errno(ret);
+		goto out;
+	}
+
+	BUG_ON(p_blkno == 0 || num_clusters == 0 || first_hash > name_hash);
+
+	mlog(0, "find xattr extent rec %u clusters from %llu, the first hash "
+	     "in the rec is %u\n", num_clusters, p_blkno, first_hash);
+
+	ret = ocfs2_xattr_bucket_find(inode, name_index, name, name_hash,
+				      p_blkno, first_hash, num_clusters, xs);
+
+out:
+	return ret;
+}
+
+static int ocfs2_iterate_xattr_buckets(struct inode *inode,
+				       u64 blkno,
+				       u32 clusters,
+				       xattr_bucket_func *func,
+				       void *para)
+{
+	int i, j, ret = 0;
+	int blk_per_bucket = ocfs2_blocks_per_xattr_bucket(inode->i_sb);
+	u32 bpc = ocfs2_xattr_buckets_per_cluster(OCFS2_SB(inode->i_sb));
+	u32 num_buckets = clusters * bpc;
+	struct ocfs2_xattr_bucket bucket;
+
+	memset(&bucket, 0, sizeof(bucket));
+
+	mlog(0, "iterating xattr buckets in %u clusters starting from %llu\n",
+	     clusters, blkno);
+
+	for (i = 0; i < num_buckets; i++, blkno += blk_per_bucket) {
+		ret = ocfs2_read_blocks(inode, blkno, blk_per_bucket,
+					bucket.bhs, OCFS2_BH_CACHED);
+		if (ret) {
+			mlog_errno(ret);
+			goto out;
+		}
+
+		bucket.xh = (struct ocfs2_xattr_header *)bucket.bhs[0]->b_data;
+		/*
+		 * The real bucket num in this series of blocks is stored
+		 * in the 1st bucket.
+		 */
+		if (i == 0)
+			num_buckets = le16_to_cpu(bucket.xh->xh_num_buckets);
+
+		mlog(0, "iterating xattr bucket %llu, first hash %u\n", blkno,
+		     le32_to_cpu(bucket.xh->xh_entries[0].xe_name_hash));
+		if (func) {
+			ret = func(inode, &bucket, para);
+			if (ret) {
+				mlog_errno(ret);
+				break;
+			}
+		}
+
+		for (j = 0; j < blk_per_bucket; j++)
+			brelse(bucket.bhs[j]);
+		memset(&bucket, 0, sizeof(bucket));
+	}
+
+out:
+	for (j = 0; j < blk_per_bucket; j++)
+		brelse(bucket.bhs[j]);
+
+	return ret;
+}
+
+struct ocfs2_xattr_tree_list {
+	char *buffer;
+	size_t buffer_size;
+	size_t result;
+};
+
+static int ocfs2_xattr_bucket_get_name_value(struct inode *inode,
+					     struct ocfs2_xattr_header *xh,
+					     int index,
+					     int *block_off,
+					     int *new_offset)
+{
+	u16 name_offset;
+
+	if (index < 0 || index >= le16_to_cpu(xh->xh_count))
+		return -EINVAL;
+
+	name_offset = le16_to_cpu(xh->xh_entries[index].xe_name_offset);
+
+	*block_off = name_offset >> inode->i_sb->s_blocksize_bits;
+	*new_offset = name_offset % inode->i_sb->s_blocksize;
+
+	return 0;
+}
+
+static int ocfs2_list_xattr_bucket(struct inode *inode,
+				   struct ocfs2_xattr_bucket *bucket,
+				   void *para)
+{
+	int ret = 0, type;
+	struct ocfs2_xattr_tree_list *xl = (struct ocfs2_xattr_tree_list *)para;
+	int i, block_off, new_offset;
+	const char *prefix, *name;
+
+	for (i = 0 ; i < le16_to_cpu(bucket->xh->xh_count); i++) {
+		struct ocfs2_xattr_entry *entry = &bucket->xh->xh_entries[i];
+		type = ocfs2_xattr_get_type(entry);
+		prefix = ocfs2_xattr_prefix(type);
+
+		if (prefix) {
+			ret = ocfs2_xattr_bucket_get_name_value(inode,
+								bucket->xh,
+								i,
+								&block_off,
+								&new_offset);
+			if (ret)
+				break;
+
+			name = (const char *)bucket->bhs[block_off]->b_data +
+				new_offset;
+			ret = ocfs2_xattr_list_entry(xl->buffer,
+						     xl->buffer_size,
+						     &xl->result,
+						     prefix, name,
+						     entry->xe_name_len);
+			if (ret)
+				break;
+		}
+	}
+
+	return ret;
+}
+
+static int ocfs2_xattr_tree_list_index_block(struct inode *inode,
+					     struct ocfs2_xattr_tree_root *xt,
+					     char *buffer,
+					     size_t buffer_size)
+{
+	struct ocfs2_extent_list *el = &xt->xt_list;
+	int ret = 0;
+	u32 name_hash = UINT_MAX, e_cpos = 0, num_clusters = 0;
+	u64 p_blkno = 0;
+	struct ocfs2_xattr_tree_list xl = {
+		.buffer = buffer,
+		.buffer_size = buffer_size,
+		.result = 0,
+	};
+
+	if (le16_to_cpu(el->l_next_free_rec) == 0)
+		return 0;
+
+	while (name_hash > 0) {
+		ret = ocfs2_xattr_get_rec(inode, name_hash, &p_blkno,
+					  &e_cpos, &num_clusters, el);
+		if (ret) {
+			mlog_errno(ret);
+			goto out;
+		}
+
+		ret = ocfs2_iterate_xattr_buckets(inode, p_blkno, num_clusters,
+						  ocfs2_list_xattr_bucket,
+						  &xl);
+		if (ret) {
+			mlog_errno(ret);
+			goto out;
+		}
+
+		if (e_cpos == 0)
+			break;
+
+		name_hash = e_cpos - 1;
+	}
+
+	ret = xl.result;
+out:
+	return ret;
+}
+
+static int cmp_xe(const void *a, const void *b)
+{
+	const struct ocfs2_xattr_entry *l = a, *r = b;
+	u32 l_hash = le32_to_cpu(l->xe_name_hash);
+	u32 r_hash = le32_to_cpu(r->xe_name_hash);
+
+	if (l_hash > r_hash)
+		return 1;
+	if (l_hash < r_hash)
+		return -1;
+	return 0;
+}
+
+static void swap_xe(void *a, void *b, int size)
+{
+	struct ocfs2_xattr_entry *l = a, *r = b, tmp;
+
+	tmp = *l;
+	memcpy(l, r, sizeof(struct ocfs2_xattr_entry));
+	memcpy(r, &tmp, sizeof(struct ocfs2_xattr_entry));
+}
+
+/*
+ * When the ocfs2_xattr_block is filled up, new bucket will be created
+ * and all the xattr entries will be moved to the new bucket.
+ * Note: we need to sort the entries since they are not saved in order
+ * in the ocfs2_xattr_block.
+ */
+static void ocfs2_cp_xattr_block_to_bucket(struct inode *inode,
+					   struct buffer_head *xb_bh,
+					   struct buffer_head *xh_bh,
+					   struct buffer_head *data_bh)
+{
+	int i, blocksize = inode->i_sb->s_blocksize;
+	u16 offset, size, off_change;
+	struct ocfs2_xattr_entry *xe;
+	struct ocfs2_xattr_block *xb =
+				(struct ocfs2_xattr_block *)xb_bh->b_data;
+	struct ocfs2_xattr_header *xb_xh = &xb->xb_attrs.xb_header;
+	struct ocfs2_xattr_header *xh =
+				(struct ocfs2_xattr_header *)xh_bh->b_data;
+	u16 count = le16_to_cpu(xb_xh->xh_count);
+	char *target = xh_bh->b_data, *src = xb_bh->b_data;
+
+	mlog(0, "cp xattr from block %llu to bucket %llu\n",
+	     (unsigned long long)xb_bh->b_blocknr,
+	     (unsigned long long)xh_bh->b_blocknr);
+
+	memset(xh_bh->b_data, 0, blocksize);
+	if (data_bh)
+		memset(data_bh->b_data, 0, blocksize);
+	/*
+	 * Since the xe_name_offset is based on ocfs2_xattr_header,
+	 * there is a offset change corresponding to the change of
+	 * ocfs2_xattr_header's position.
+	 */
+	off_change = offsetof(struct ocfs2_xattr_block, xb_attrs.xb_header);
+	xe = &xb_xh->xh_entries[count - 1];
+	offset = le16_to_cpu(xe->xe_name_offset) + off_change;
+	size = blocksize - offset;
+
+	/* copy all the names and values. */
+	if (data_bh)
+		target = data_bh->b_data;
+	memcpy(target + offset, src + offset, size);
+
+	/* Init new header now. */
+	xh->xh_count = xb_xh->xh_count;
+	xh->xh_num_buckets = cpu_to_le16(1);
+	xh->xh_name_value_len = cpu_to_le16(size);
+	xh->xh_free_start = cpu_to_le16(OCFS2_XATTR_BUCKET_SIZE - size);
+
+	/* copy all the entries. */
+	target = xh_bh->b_data;
+	offset = offsetof(struct ocfs2_xattr_header, xh_entries);
+	size = count * sizeof(struct ocfs2_xattr_entry);
+	memcpy(target + offset, (char *)xb_xh + offset, size);
+
+	/* Change the xe offset for all the xe because of the move. */
+	off_change = OCFS2_XATTR_BUCKET_SIZE - blocksize +
+		 offsetof(struct ocfs2_xattr_block, xb_attrs.xb_header);
+	for (i = 0; i < count; i++)
+		le16_add_cpu(&xh->xh_entries[i].xe_name_offset, off_change);
+
+	mlog(0, "copy entry: start = %u, size = %u, offset_change = %u\n",
+	     offset, size, off_change);
+
+	sort(target + offset, count, sizeof(struct ocfs2_xattr_entry),
+	     cmp_xe, swap_xe);
+}
+
+/*
+ * After we move xattr from block to index btree, we have to
+ * update ocfs2_xattr_search to the new xe and base.
+ *
+ * When the entry is in xattr block, xattr_bh indicates the storage place.
+ * While if the entry is in index b-tree, "bucket" indicates the
+ * real place of the xattr.
+ */
+static int ocfs2_xattr_update_xattr_search(struct inode *inode,
+					   struct ocfs2_xattr_search *xs,
+					   struct buffer_head *old_bh,
+					   struct buffer_head *new_bh)
+{
+	int ret = 0;
+	char *buf = old_bh->b_data;
+	struct ocfs2_xattr_block *old_xb = (struct ocfs2_xattr_block *)buf;
+	struct ocfs2_xattr_header *old_xh = &old_xb->xb_attrs.xb_header;
+	int i, blocksize = inode->i_sb->s_blocksize;
+	u16 blk_per_bucket = ocfs2_blocks_per_xattr_bucket(inode->i_sb);
+
+	xs->bucket.bhs[0] = new_bh;
+	get_bh(new_bh);
+	xs->bucket.xh = (struct ocfs2_xattr_header *)xs->bucket.bhs[0]->b_data;
+	xs->header = xs->bucket.xh;
+
+	xs->base = new_bh->b_data;
+	xs->end = xs->base + inode->i_sb->s_blocksize;
+
+	if (!xs->not_found) {
+		if (OCFS2_XATTR_BUCKET_SIZE != blocksize) {
+			ret = ocfs2_read_blocks(inode,
+					xs->bucket.bhs[0]->b_blocknr + 1,
+					blk_per_bucket - 1, &xs->bucket.bhs[1],
+					OCFS2_BH_CACHED);
+			if (ret) {
+				mlog_errno(ret);
+				return ret;
+			}
+
+			i = xs->here - old_xh->xh_entries;
+			xs->here = &xs->header->xh_entries[i];
+		}
+	}
+
+	return ret;
+}
+
+static int ocfs2_xattr_create_index_block(struct inode *inode,
+					  struct ocfs2_xattr_search *xs)
+{
+	int ret, credits = OCFS2_SUBALLOC_ALLOC;
+	u32 bit_off, len;
+	u64 blkno;
+	handle_t *handle;
+	struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+	struct ocfs2_inode_info *oi = OCFS2_I(inode);
+	struct ocfs2_alloc_context *data_ac;
+	struct buffer_head *xh_bh = NULL, *data_bh = NULL;
+	struct buffer_head *xb_bh = xs->xattr_bh;
+	struct ocfs2_xattr_block *xb =
+			(struct ocfs2_xattr_block *)xb_bh->b_data;
+	struct ocfs2_xattr_tree_root *xr;
+	u16 xb_flags = le16_to_cpu(xb->xb_flags);
+	u16 bpb = ocfs2_blocks_per_xattr_bucket(inode->i_sb);
+
+	mlog(0, "create xattr index block for %llu\n",
+	     (unsigned long long)xb_bh->b_blocknr);
+
+	BUG_ON(xb_flags & OCFS2_XATTR_INDEXED);
+
+	ret = ocfs2_reserve_clusters(osb, 1, &data_ac);
+	if (ret) {
+		mlog_errno(ret);
+		goto out;
+	}
+
+	/*
+	 * XXX:
+	 * We can use this lock for now, and maybe move to a dedicated mutex
+	 * if performance becomes a problem later.
+	 */
+	down_write(&oi->ip_alloc_sem);
+
+	/*
+	 * 3 more credits, one for xattr block update, one for the 1st block
+	 * of the new xattr bucket and one for the value/data.
+	 */
+	credits += 3;
+	handle = ocfs2_start_trans(osb, credits);
+	if (IS_ERR(handle)) {
+		ret = PTR_ERR(handle);
+		mlog_errno(ret);
+		goto out_sem;
+	}
+
+	ret = ocfs2_journal_access(handle, inode, xb_bh,
+				   OCFS2_JOURNAL_ACCESS_WRITE);
+	if (ret) {
+		mlog_errno(ret);
+		goto out_commit;
+	}
+
+	ret = ocfs2_claim_clusters(osb, handle, data_ac, 1, &bit_off, &len);
+	if (ret) {
+		mlog_errno(ret);
+		goto out_commit;
+	}
+
+	/*
+	 * The bucket may spread in many blocks, and
+	 * we will only touch the 1st block and the last block
+	 * in the whole bucket(one for entry and one for data).
+	 */
+	blkno = ocfs2_clusters_to_blocks(inode->i_sb, bit_off);
+
+	mlog(0, "allocate 1 cluster from %llu to xattr block\n", blkno);
+
+	xh_bh = sb_getblk(inode->i_sb, blkno);
+	if (!xh_bh) {
+		ret = -EIO;
+		mlog_errno(ret);
+		goto out_commit;
+	}
+
+	ocfs2_set_new_buffer_uptodate(inode, xh_bh);
+
+	ret = ocfs2_journal_access(handle, inode, xh_bh,
+				   OCFS2_JOURNAL_ACCESS_CREATE);
+	if (ret) {
+		mlog_errno(ret);
+		goto out_commit;
+	}
+
+	if (bpb > 1) {
+		data_bh = sb_getblk(inode->i_sb, blkno + bpb - 1);
+		if (!data_bh) {
+			ret = -EIO;
+			mlog_errno(ret);
+			goto out_commit;
+		}
+
+		ocfs2_set_new_buffer_uptodate(inode, data_bh);
+
+		ret = ocfs2_journal_access(handle, inode, data_bh,
+					   OCFS2_JOURNAL_ACCESS_CREATE);
+		if (ret) {
+			mlog_errno(ret);
+			goto out_commit;
+		}
+	}
+
+	ocfs2_cp_xattr_block_to_bucket(inode, xb_bh, xh_bh, data_bh);
+
+	ocfs2_journal_dirty(handle, xh_bh);
+	if (data_bh)
+		ocfs2_journal_dirty(handle, data_bh);
+
+	ocfs2_xattr_update_xattr_search(inode, xs, xb_bh, xh_bh);
+
+	/* Change from ocfs2_xattr_header to ocfs2_xattr_tree_root */
+	memset(&xb->xb_attrs, 0, inode->i_sb->s_blocksize -
+	       offsetof(struct ocfs2_xattr_block, xb_attrs));
+
+	xr = &xb->xb_attrs.xb_root;
+	xr->xt_clusters = cpu_to_le32(1);
+	xr->xt_last_eb_blk = 0;
+	xr->xt_list.l_tree_depth = 0;
+	xr->xt_list.l_count = cpu_to_le16(ocfs2_xattr_recs_per_xb(inode->i_sb));
+	xr->xt_list.l_next_free_rec = cpu_to_le16(1);
+
+	xr->xt_list.l_recs[0].e_cpos = 0;
+	xr->xt_list.l_recs[0].e_blkno = cpu_to_le64(blkno);
+	xr->xt_list.l_recs[0].e_leaf_clusters = cpu_to_le16(1);
+
+	xb->xb_flags = cpu_to_le16(xb_flags | OCFS2_XATTR_INDEXED);
+
+	ret = ocfs2_journal_dirty(handle, xb_bh);
+	if (ret) {
+		mlog_errno(ret);
+		goto out_commit;
+	}
+
+out_commit:
+	ocfs2_commit_trans(osb, handle);
+
+out_sem:
+	up_write(&oi->ip_alloc_sem);
+
+out:
+	if (data_ac)
+		ocfs2_free_alloc_context(data_ac);
+
+	brelse(xh_bh);
+	brelse(data_bh);
+
+	return ret;
+}
+
+static int cmp_xe_offset(const void *a, const void *b)
+{
+	const struct ocfs2_xattr_entry *l = a, *r = b;
+	u32 l_name_offset = le16_to_cpu(l->xe_name_offset);
+	u32 r_name_offset = le16_to_cpu(r->xe_name_offset);
+
+	if (l_name_offset < r_name_offset)
+		return 1;
+	if (l_name_offset > r_name_offset)
+		return -1;
+	return 0;
+}
+
+/*
+ * defrag a xattr bucket if we find that the bucket has some
+ * holes beteen name/value pairs.
+ * We will move all the name/value pairs to the end of the bucket
+ * so that we can spare some space for insertion.
+ */
+static int ocfs2_defrag_xattr_bucket(struct inode *inode,
+				     struct ocfs2_xattr_bucket *bucket)
+{
+	int ret, i;
+	size_t end, offset, len, value_len;
+	struct ocfs2_xattr_header *xh;
+	char *entries, *buf, *bucket_buf = NULL;
+	u64 blkno = bucket->bhs[0]->b_blocknr;
+	u16 blk_per_bucket = ocfs2_blocks_per_xattr_bucket(inode->i_sb);
+	u16 xh_free_start;
+	size_t blocksize = inode->i_sb->s_blocksize;
+	handle_t *handle;
+	struct buffer_head **bhs;
+	struct ocfs2_xattr_entry *xe;
+
+	bhs = kzalloc(sizeof(struct buffer_head *) * blk_per_bucket,
+			GFP_NOFS);
+	if (!bhs)
+		return -ENOMEM;
+
+	ret = ocfs2_read_blocks(inode, blkno, blk_per_bucket, bhs,
+				OCFS2_BH_CACHED);
+	if (ret)
+		goto out;
+
+	/*
+	 * In order to make the operation more efficient and generic,
+	 * we copy all the blocks into a contiguous memory and do the
+	 * defragment there, so if anything is error, we will not touch
+	 * the real block.
+	 */
+	bucket_buf = kmalloc(OCFS2_XATTR_BUCKET_SIZE, GFP_NOFS);
+	if (!bucket_buf) {
+		ret = -EIO;
+		goto out;
+	}
+
+	buf = bucket_buf;
+	for (i = 0; i < blk_per_bucket; i++, buf += blocksize)
+		memcpy(buf, bhs[i]->b_data, blocksize);
+
+	handle = ocfs2_start_trans((OCFS2_SB(inode->i_sb)), blk_per_bucket);
+	if (IS_ERR(handle)) {
+		ret = PTR_ERR(handle);
+		handle = NULL;
+		mlog_errno(ret);
+		goto out;
+	}
+
+	for (i = 0; i < blk_per_bucket; i++) {
+		ret = ocfs2_journal_access(handle, inode, bhs[i],
+					   OCFS2_JOURNAL_ACCESS_WRITE);
+		if (ret < 0) {
+			mlog_errno(ret);
+			goto commit;
+		}
+	}
+
+	xh = (struct ocfs2_xattr_header *)bucket_buf;
+	entries = (char *)xh->xh_entries;
+	xh_free_start = le16_to_cpu(xh->xh_free_start);
+
+	mlog(0, "adjust xattr bucket in %llu, count = %u, "
+	     "xh_free_start = %u, xh_name_value_len = %u.\n",
+	     blkno, le16_to_cpu(xh->xh_count), xh_free_start,
+	     le16_to_cpu(xh->xh_name_value_len));
+
+	/*
+	 * sort all the entries by their offset.
+	 * the largest will be the first, so that we can
+	 * move them to the end one by one.
+	 */
+	sort(entries, le16_to_cpu(xh->xh_count),
+	     sizeof(struct ocfs2_xattr_entry),
+	     cmp_xe_offset, swap_xe);
+
+	/* Move all name/values to the end of the bucket. */
+	xe = xh->xh_entries;
+	end = OCFS2_XATTR_BUCKET_SIZE;
+	for (i = 0; i < le16_to_cpu(xh->xh_count); i++, xe++) {
+		offset = le16_to_cpu(xe->xe_name_offset);
+		if (ocfs2_xattr_is_local(xe))
+			value_len = OCFS2_XATTR_SIZE(
+					le64_to_cpu(xe->xe_value_size));
+		else
+			value_len = OCFS2_XATTR_ROOT_SIZE;
+		len = OCFS2_XATTR_SIZE(xe->xe_name_len) + value_len;
+
+		/*
+		 * We must make sure that the name/value pair
+		 * exist in the same block. So adjust end to
+		 * the previous block end if needed.
+		 */
+		if (((end - len) / blocksize !=
+			(end - 1) / blocksize))
+			end = end - end % blocksize;
+
+		if (end > offset + len) {
+			memmove(bucket_buf + end - len,
+				bucket_buf + offset, len);
+			xe->xe_name_offset = cpu_to_le16(end - len);
+		}
+
+		mlog_bug_on_msg(end < offset + len, "Defrag check failed for "
+				"bucket %llu\n", (unsigned long long)blkno);
+
+		end -= len;
+	}
+
+	mlog_bug_on_msg(xh_free_start > end, "Defrag check failed for "
+			"bucket %llu\n", (unsigned long long)blkno);
+
+	if (xh_free_start == end)
+		goto commit;
+
+	memset(bucket_buf + xh_free_start, 0, end - xh_free_start);
+	xh->xh_free_start = cpu_to_le16(end);
+
+	/* sort the entries by their name_hash. */
+	sort(entries, le16_to_cpu(xh->xh_count),
+	     sizeof(struct ocfs2_xattr_entry),
+	     cmp_xe, swap_xe);
+
+	buf = bucket_buf;
+	for (i = 0; i < blk_per_bucket; i++, buf += blocksize) {
+		memcpy(bhs[i]->b_data, buf, blocksize);
+		ocfs2_journal_dirty(handle, bhs[i]);
+	}
+
+commit:
+	ocfs2_commit_trans(OCFS2_SB(inode->i_sb), handle);
+out:
+
+	if (bhs) {
+		for (i = 0; i < blk_per_bucket; i++)
+			brelse(bhs[i]);
+	}
+	kfree(bhs);
+
+	kfree(bucket_buf);
+	return ret;
+}
+
+/*
+ * Move half nums of the xattr bucket in the previous cluster to this new
+ * cluster. We only touch the last cluster of the previous extend record.
+ *
+ * first_bh is the first buffer_head of a series of bucket in the same
+ * extent rec and header_bh is the header of one bucket in this cluster.
+ * They will be updated if we move the data header_bh contains to the new
+ * cluster. first_hash will be set as the 1st xe's name_hash of the new cluster.
+ */
+static int ocfs2_mv_xattr_bucket_cross_cluster(struct inode *inode,
+					       handle_t *handle,
+					       struct buffer_head **first_bh,
+					       struct buffer_head **header_bh,
+					       u64 new_blkno,
+					       u64 prev_blkno,
+					       u32 num_clusters,
+					       u32 *first_hash)
+{
+	int i, ret, credits;
+	struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+	int bpc = ocfs2_clusters_to_blocks(inode->i_sb, 1);
+	int num_buckets = ocfs2_xattr_buckets_per_cluster(osb);
+	int blocksize = inode->i_sb->s_blocksize;
+	struct buffer_head *old_bh, *new_bh, *prev_bh, *new_first_bh = NULL;
+	struct ocfs2_xattr_header *new_xh;
+	struct ocfs2_xattr_header *xh =
+			(struct ocfs2_xattr_header *)((*first_bh)->b_data);
+
+	BUG_ON(le16_to_cpu(xh->xh_num_buckets) < num_buckets);
+	BUG_ON(OCFS2_XATTR_BUCKET_SIZE == osb->s_clustersize);
+
+	prev_bh = *first_bh;
+	get_bh(prev_bh);
+	xh = (struct ocfs2_xattr_header *)prev_bh->b_data;
+
+	prev_blkno += (num_clusters - 1) * bpc + bpc / 2;
+
+	mlog(0, "move half of xattrs in cluster %llu to %llu\n",
+	     prev_blkno, new_blkno);
+
+	/*
+	 * We need to update the 1st half of the new cluster and
+	 * 1 more for the update of the 1st bucket of the previous
+	 * extent record.
+	 */
+	credits = bpc / 2 + 1;
+	ret = ocfs2_extend_trans(handle, credits);
+	if (ret) {
+		mlog_errno(ret);
+		goto out;
+	}
+
+	ret = ocfs2_journal_access(handle, inode, prev_bh,
+				   OCFS2_JOURNAL_ACCESS_WRITE);
+	if (ret) {
+		mlog_errno(ret);
+		goto out;
+	}
+
+	for (i = 0; i < bpc / 2; i++, prev_blkno++, new_blkno++) {
+		old_bh = new_bh = NULL;
+		new_bh = sb_getblk(inode->i_sb, new_blkno);
+		if (!new_bh) {
+			ret = -EIO;
+			mlog_errno(ret);
+			goto out;
+		}
+
+		ocfs2_set_new_buffer_uptodate(inode, new_bh);
+
+		ret = ocfs2_journal_access(handle, inode, new_bh,
+					   OCFS2_JOURNAL_ACCESS_CREATE);
+		if (ret < 0) {
+			mlog_errno(ret);
+			brelse(new_bh);
+			goto out;
+		}
+
+		ret = ocfs2_read_block(inode, prev_blkno, &old_bh);
+		if (ret < 0) {
+			mlog_errno(ret);
+			brelse(new_bh);
+			goto out;
+		}
+
+		memcpy(new_bh->b_data, old_bh->b_data, blocksize);
+
+		if (i == 0) {
+			new_xh = (struct ocfs2_xattr_header *)new_bh->b_data;
+			new_xh->xh_num_buckets = cpu_to_le16(num_buckets / 2);
+
+			if (first_hash)
+				*first_hash = le32_to_cpu(
+					new_xh->xh_entries[0].xe_name_hash);
+			new_first_bh = new_bh;
+			get_bh(new_first_bh);
+		}
+
+		ocfs2_journal_dirty(handle, new_bh);
+
+		if (*header_bh == old_bh) {
+			brelse(*header_bh);
+			*header_bh = new_bh;
+			get_bh(*header_bh);
+
+			brelse(*first_bh);
+			*first_bh = new_first_bh;
+			get_bh(*first_bh);
+		}
+		brelse(new_bh);
+		brelse(old_bh);
+	}
+
+	le16_add_cpu(&xh->xh_num_buckets, -(num_buckets / 2));
+
+	ocfs2_journal_dirty(handle, prev_bh);
+out:
+	brelse(prev_bh);
+	brelse(new_first_bh);
+	return ret;
+}
+
+static int ocfs2_read_xattr_bucket(struct inode *inode,
+				   u64 blkno,
+				   struct buffer_head **bhs,
+				   int new)
+{
+	int ret = 0;
+	u16 i, blk_per_bucket = ocfs2_blocks_per_xattr_bucket(inode->i_sb);
+
+	if (!new)
+		return ocfs2_read_blocks(inode, blkno,
+					 blk_per_bucket, bhs,
+					 OCFS2_BH_CACHED);
+
+	for (i = 0; i < blk_per_bucket; i++) {
+		bhs[i] = sb_getblk(inode->i_sb, blkno + i);
+		if (bhs[i] == NULL) {
+			ret = -EIO;
+			mlog_errno(ret);
+			break;
+		}
+		ocfs2_set_new_buffer_uptodate(inode, bhs[i]);
+	}
+
+	return ret;
+}
+
+/*
+ * Move half num of the xattrs in old bucket(blk) to new bucket(new_blk).
+ * first_hash will record the 1st hash of the new bucket.
+ */
+static int ocfs2_half_xattr_bucket(struct inode *inode,
+				   handle_t *handle,
+				   u64 blk,
+				   u64 new_blk,
+				   u32 *first_hash,
+				   int new_bucket_head)
+{
+	int ret, i;
+	u16 count, start, len, name_value_len, xe_len, name_offset;
+	u16 blk_per_bucket = ocfs2_blocks_per_xattr_bucket(inode->i_sb);
+	struct buffer_head **s_bhs, **t_bhs = NULL;
+	struct ocfs2_xattr_header *xh;
+	struct ocfs2_xattr_entry *xe;
+	int blocksize = inode->i_sb->s_blocksize;
+
+	mlog(0, "move half of xattrs from bucket %llu to %llu\n",
+	     blk, new_blk);
+
+	s_bhs = kcalloc(blk_per_bucket, sizeof(struct buffer_head *), GFP_NOFS);
+	if (!s_bhs)
+		return -ENOMEM;
+
+	ret = ocfs2_read_xattr_bucket(inode, blk, s_bhs, 0);
+	if (ret) {
+		mlog_errno(ret);
+		goto out;
+	}
+
+	ret = ocfs2_journal_access(handle, inode, s_bhs[0],
+				   OCFS2_JOURNAL_ACCESS_WRITE);
+	if (ret) {
+		mlog_errno(ret);
+		goto out;
+	}
+
+	t_bhs = kcalloc(blk_per_bucket, sizeof(struct buffer_head *), GFP_NOFS);
+	if (!t_bhs) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	ret = ocfs2_read_xattr_bucket(inode, new_blk, t_bhs, new_bucket_head);
+	if (ret) {
+		mlog_errno(ret);
+		goto out;
+	}
+
+	for (i = 0; i < blk_per_bucket; i++) {
+		ret = ocfs2_journal_access(handle, inode, t_bhs[i],
+					   OCFS2_JOURNAL_ACCESS_CREATE);
+		if (ret) {
+			mlog_errno(ret);
+			goto out;
+		}
+	}
+
+	/* copy the whole bucket to the new first. */
+	for (i = 0; i < blk_per_bucket; i++)
+		memcpy(t_bhs[i]->b_data, s_bhs[i]->b_data, blocksize);
+
+	/* update the new bucket. */
+	xh = (struct ocfs2_xattr_header *)t_bhs[0]->b_data;
+	count = le16_to_cpu(xh->xh_count);
+	start = count / 2;
+
+	/*
+	 * Calculate the total name/value len and xh_free_start for
+	 * the old bucket first.
+	 */
+	name_offset = OCFS2_XATTR_BUCKET_SIZE;
+	name_value_len = 0;
+	for (i = 0; i < start; i++) {
+		xe = &xh->xh_entries[i];
+		xe_len = OCFS2_XATTR_SIZE(xe->xe_name_len);
+		if (ocfs2_xattr_is_local(xe))
+			xe_len +=
+			   OCFS2_XATTR_SIZE(le64_to_cpu(xe->xe_value_size));
+		else
+			xe_len += OCFS2_XATTR_ROOT_SIZE;
+		name_value_len += xe_len;
+		if (le16_to_cpu(xe->xe_name_offset) < name_offset)
+			name_offset = le16_to_cpu(xe->xe_name_offset);
+	}
+
+	/*
+	 * Now begin the modification to the new bucket.
+	 *
+	 * In the new bucket, We just move the xattr entry to the beginning
+	 * and don't touch the name/value. So there will be some holes in the
+	 * bucket, and they will be removed when ocfs2_defrag_xattr_bucket is
+	 * called.
+	 */
+	xe = &xh->xh_entries[start];
+	len = sizeof(struct ocfs2_xattr_entry) * (count - start);
+	mlog(0, "mv xattr entry len %d from %d to %d\n", len,
+	     (int)((char *)xe - (char *)xh),
+	     (int)((char *)xh->xh_entries - (char *)xh));
+	memmove((char *)xh->xh_entries, (char *)xe, len);
+	xe = &xh->xh_entries[count - start];
+	len = sizeof(struct ocfs2_xattr_entry) * start;
+	memset((char *)xe, 0, len);
+
+	le16_add_cpu(&xh->xh_count, -start);
+	le16_add_cpu(&xh->xh_name_value_len, -name_value_len);
+
+	/* Calculate xh_free_start for the new bucket. */
+	xh->xh_free_start = cpu_to_le16(OCFS2_XATTR_BUCKET_SIZE);
+	for (i = 0; i < le16_to_cpu(xh->xh_count); i++) {
+		xe = &xh->xh_entries[i];
+		xe_len = OCFS2_XATTR_SIZE(xe->xe_name_len);
+		if (ocfs2_xattr_is_local(xe))
+			xe_len +=
+			   OCFS2_XATTR_SIZE(le64_to_cpu(xe->xe_value_size));
+		else
+			xe_len += OCFS2_XATTR_ROOT_SIZE;
+		if (le16_to_cpu(xe->xe_name_offset) <
+		    le16_to_cpu(xh->xh_free_start))
+			xh->xh_free_start = xe->xe_name_offset;
+	}
+
+	/* set xh->xh_num_buckets for the new xh. */
+	if (new_bucket_head)
+		xh->xh_num_buckets = cpu_to_le16(1);
+	else
+		xh->xh_num_buckets = 0;
+
+	for (i = 0; i < blk_per_bucket; i++) {
+		ocfs2_journal_dirty(handle, t_bhs[i]);
+		if (ret)
+			mlog_errno(ret);
+	}
+
+	/* store the first_hash of the new bucket. */
+	if (first_hash)
+		*first_hash = le32_to_cpu(xh->xh_entries[0].xe_name_hash);
+
+	/*
+	 * Now only update the 1st block of the old bucket.
+	 * Please note that the entry has been sorted already above.
+	 */
+	xh = (struct ocfs2_xattr_header *)s_bhs[0]->b_data;
+	memset(&xh->xh_entries[start], 0,
+	       sizeof(struct ocfs2_xattr_entry) * (count - start));
+	xh->xh_count = cpu_to_le16(start);
+	xh->xh_free_start = cpu_to_le16(name_offset);
+	xh->xh_name_value_len = cpu_to_le16(name_value_len);
+
+	ocfs2_journal_dirty(handle, s_bhs[0]);
+	if (ret)
+		mlog_errno(ret);
+
+out:
+	if (s_bhs) {
+		for (i = 0; i < blk_per_bucket; i++)
+			brelse(s_bhs[i]);
+	}
+	kfree(s_bhs);
+
+	if (t_bhs) {
+		for (i = 0; i < blk_per_bucket; i++)
+			brelse(t_bhs[i]);
+	}
+	kfree(t_bhs);
+
+	return ret;
+}
+
+/*
+ * Copy xattr from one bucket to another bucket.
+ *
+ * The caller must make sure that the journal transaction
+ * has enough space for journaling.
+ */
+static int ocfs2_cp_xattr_bucket(struct inode *inode,
+				 handle_t *handle,
+				 u64 s_blkno,
+				 u64 t_blkno,
+				 int t_is_new)
+{
+	int ret, i;
+	int blk_per_bucket = ocfs2_blocks_per_xattr_bucket(inode->i_sb);
+	int blocksize = inode->i_sb->s_blocksize;
+	struct buffer_head **s_bhs, **t_bhs = NULL;
+
+	BUG_ON(s_blkno == t_blkno);
+
+	mlog(0, "cp bucket %llu to %llu, target is %d\n",
+	     s_blkno, t_blkno, t_is_new);
+
+	s_bhs = kzalloc(sizeof(struct buffer_head *) * blk_per_bucket,
+			GFP_NOFS);
+	if (!s_bhs)
+		return -ENOMEM;
+
+	ret = ocfs2_read_xattr_bucket(inode, s_blkno, s_bhs, 0);
+	if (ret)
+		goto out;
+
+	t_bhs = kzalloc(sizeof(struct buffer_head *) * blk_per_bucket,
+			GFP_NOFS);
+	if (!t_bhs) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	ret = ocfs2_read_xattr_bucket(inode, t_blkno, t_bhs, t_is_new);
+	if (ret)
+		goto out;
+
+	for (i = 0; i < blk_per_bucket; i++) {
+		ret = ocfs2_journal_access(handle, inode, t_bhs[i],
+					   OCFS2_JOURNAL_ACCESS_WRITE);
+		if (ret)
+			goto out;
+	}
+
+	for (i = 0; i < blk_per_bucket; i++) {
+		memcpy(t_bhs[i]->b_data, s_bhs[i]->b_data, blocksize);
+		ocfs2_journal_dirty(handle, t_bhs[i]);
+	}
+
+out:
+	if (s_bhs) {
+		for (i = 0; i < blk_per_bucket; i++)
+			brelse(s_bhs[i]);
+	}
+	kfree(s_bhs);
+
+	if (t_bhs) {
+		for (i = 0; i < blk_per_bucket; i++)
+			brelse(t_bhs[i]);
+	}
+	kfree(t_bhs);
+
+	return ret;
+}
+
+/*
+ * Copy one xattr cluster from src_blk to to_blk.
+ * The to_blk will become the first bucket header of the cluster, so its
+ * xh_num_buckets will be initialized as the bucket num in the cluster.
+ */
+static int ocfs2_cp_xattr_cluster(struct inode *inode,
+				  handle_t *handle,
+				  struct buffer_head *first_bh,
+				  u64 src_blk,
+				  u64 to_blk,
+				  u32 *first_hash)
+{
+	int i, ret, credits;
+	struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+	int bpc = ocfs2_clusters_to_blocks(inode->i_sb, 1);
+	int num_buckets = ocfs2_xattr_buckets_per_cluster(osb);
+	struct buffer_head *bh = NULL;
+	struct ocfs2_xattr_header *xh;
+	u64 to_blk_start = to_blk;
+
+	mlog(0, "cp xattrs from cluster %llu to %llu\n", src_blk, to_blk);
+
+	/*
+	 * We need to update the new cluster and 1 more for the update of
+	 * the 1st bucket of the previous extent rec.
+	 */
+	credits = bpc + 1;
+	ret = ocfs2_extend_trans(handle, credits);
+	if (ret) {
+		mlog_errno(ret);
+		goto out;
+	}
+
+	ret = ocfs2_journal_access(handle, inode, first_bh,
+				   OCFS2_JOURNAL_ACCESS_WRITE);
+	if (ret) {
+		mlog_errno(ret);
+		goto out;
+	}
+
+	for (i = 0; i < num_buckets; i++) {
+		ret = ocfs2_cp_xattr_bucket(inode, handle,
+					    src_blk, to_blk, 1);
+		if (ret) {
+			mlog_errno(ret);
+			goto out;
+		}
+
+		src_blk += ocfs2_blocks_per_xattr_bucket(inode->i_sb);
+		to_blk += ocfs2_blocks_per_xattr_bucket(inode->i_sb);
+	}
+
+	/* update the old bucket header. */
+	xh = (struct ocfs2_xattr_header *)first_bh->b_data;
+	le16_add_cpu(&xh->xh_num_buckets, -num_buckets);
+
+	ocfs2_journal_dirty(handle, first_bh);
+
+	/* update the new bucket header. */
+	ret = ocfs2_read_block(inode, to_blk_start, &bh);
+	if (ret < 0) {
+		mlog_errno(ret);
+		goto out;
+	}
+
+	ret = ocfs2_journal_access(handle, inode, bh,
+				   OCFS2_JOURNAL_ACCESS_WRITE);
+	if (ret) {
+		mlog_errno(ret);
+		goto out;
+	}
+
+	xh = (struct ocfs2_xattr_header *)bh->b_data;
+	xh->xh_num_buckets = cpu_to_le16(num_buckets);
+
+	ocfs2_journal_dirty(handle, bh);
+
+	if (first_hash)
+		*first_hash = le32_to_cpu(xh->xh_entries[0].xe_name_hash);
+out:
+	brelse(bh);
+	return ret;
+}
+
+/*
+ * Move half of the xattrs in this cluster to the new cluster.
+ * This function should only be called when bucket size == cluster size.
+ * Otherwise ocfs2_mv_xattr_bucket_cross_cluster should be used instead.
+ */
+static int ocfs2_half_xattr_cluster(struct inode *inode,
+				    handle_t *handle,
+				    u64 prev_blk,
+				    u64 new_blk,
+				    u32 *first_hash)
+{
+	u16 blk_per_bucket = ocfs2_blocks_per_xattr_bucket(inode->i_sb);
+	int ret, credits = 2 * blk_per_bucket;
+
+	BUG_ON(OCFS2_XATTR_BUCKET_SIZE < OCFS2_SB(inode->i_sb)->s_clustersize);
+
+	ret = ocfs2_extend_trans(handle, credits);
+	if (ret) {
+		mlog_errno(ret);
+		return ret;
+	}
+
+	/* Move half of the xattr in start_blk to the next bucket. */
+	return  ocfs2_half_xattr_bucket(inode, handle, prev_blk,
+					new_blk, first_hash, 1);
+}
+
+/*
+ * Move some xattrs from the old cluster to the new one since they are not
+ * contiguous in ocfs2 xattr tree.
+ *
+ * new_blk starts a new separate cluster, and we will move some xattrs from
+ * prev_blk to it. v_start will be set as the first name hash value in this
+ * new cluster so that it can be used as e_cpos during tree insertion and
+ * don't collide with our original b-tree operations. first_bh and header_bh
+ * will also be updated since they will be used in ocfs2_extend_xattr_bucket
+ * to extend the insert bucket.
+ *
+ * The problem is how much xattr should we move to the new one and when should
+ * we update first_bh and header_bh?
+ * 1. If cluster size > bucket size, that means the previous cluster has more
+ *    than 1 bucket, so just move half nums of bucket into the new cluster and
+ *    update the first_bh and header_bh if the insert bucket has been moved
+ *    to the new cluster.
+ * 2. If cluster_size == bucket_size:
+ *    a) If the previous extent rec has more than one cluster and the insert
+ *       place isn't in the last cluster, copy the entire last cluster to the
+ *       new one. This time, we don't need to upate the first_bh and header_bh
+ *       since they will not be moved into the new cluster.
+ *    b) Otherwise, move the bottom half of the xattrs in the last cluster into
+ *       the new one. And we set the extend flag to zero if the insert place is
+ *       moved into the new allocated cluster since no extend is needed.
+ */
+static int ocfs2_adjust_xattr_cross_cluster(struct inode *inode,
+					    handle_t *handle,
+					    struct buffer_head **first_bh,
+					    struct buffer_head **header_bh,
+					    u64 new_blk,
+					    u64 prev_blk,
+					    u32 prev_clusters,
+					    u32 *v_start,
+					    int *extend)
+{
+	int ret = 0;
+	int bpc = ocfs2_clusters_to_blocks(inode->i_sb, 1);
+
+	mlog(0, "adjust xattrs from cluster %llu len %u to %llu\n",
+	     prev_blk, prev_clusters, new_blk);
+
+	if (ocfs2_xattr_buckets_per_cluster(OCFS2_SB(inode->i_sb)) > 1)
+		ret = ocfs2_mv_xattr_bucket_cross_cluster(inode,
+							  handle,
+							  first_bh,
+							  header_bh,
+							  new_blk,
+							  prev_blk,
+							  prev_clusters,
+							  v_start);
+	else {
+		u64 last_blk = prev_blk + bpc * (prev_clusters - 1);
+
+		if (prev_clusters > 1 && (*header_bh)->b_blocknr != last_blk)
+			ret = ocfs2_cp_xattr_cluster(inode, handle, *first_bh,
+						     last_blk, new_blk,
+						     v_start);
+		else {
+			ret = ocfs2_half_xattr_cluster(inode, handle,
+						       last_blk, new_blk,
+						       v_start);
+
+			if ((*header_bh)->b_blocknr == last_blk && extend)
+				*extend = 0;
+		}
+	}
+
+	return ret;
+}
+
+/*
+ * Add a new cluster for xattr storage.
+ *
+ * If the new cluster is contiguous with the previous one, it will be
+ * appended to the same extent record, and num_clusters will be updated.
+ * If not, we will insert a new extent for it and move some xattrs in
+ * the last cluster into the new allocated one.
+ * We also need to limit the maximum size of a btree leaf, otherwise we'll
+ * lose the benefits of hashing because we'll have to search large leaves.
+ * So now the maximum size is OCFS2_MAX_XATTR_TREE_LEAF_SIZE(or clustersize,
+ * if it's bigger).
+ *
+ * first_bh is the first block of the previous extent rec and header_bh
+ * indicates the bucket we will insert the new xattrs. They will be updated
+ * when the header_bh is moved into the new cluster.
+ */
+static int ocfs2_add_new_xattr_cluster(struct inode *inode,
+				       struct buffer_head *root_bh,
+				       struct buffer_head **first_bh,
+				       struct buffer_head **header_bh,
+				       u32 *num_clusters,
+				       u32 prev_cpos,
+				       u64 prev_blkno,
+				       int *extend)
+{
+	int ret, credits;
+	u16 bpc = ocfs2_clusters_to_blocks(inode->i_sb, 1);
+	u32 prev_clusters = *num_clusters;
+	u32 clusters_to_add = 1, bit_off, num_bits, v_start = 0;
+	u64 block;
+	handle_t *handle = NULL;
+	struct ocfs2_alloc_context *data_ac = NULL;
+	struct ocfs2_alloc_context *meta_ac = NULL;
+	struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+	struct ocfs2_extent_tree et;
+
+	mlog(0, "Add new xattr cluster for %llu, previous xattr hash = %u, "
+	     "previous xattr blkno = %llu\n",
+	     (unsigned long long)OCFS2_I(inode)->ip_blkno,
+	     prev_cpos, prev_blkno);
+
+	ocfs2_init_xattr_tree_extent_tree(&et, inode, root_bh);
+
+	ret = ocfs2_lock_allocators(inode, &et, clusters_to_add, 0,
+				    &data_ac, &meta_ac);
+	if (ret) {
+		mlog_errno(ret);
+		goto leave;
+	}
+
+	credits = ocfs2_calc_extend_credits(osb->sb, et.et_root_el,
+					    clusters_to_add);
+	handle = ocfs2_start_trans(osb, credits);
+	if (IS_ERR(handle)) {
+		ret = PTR_ERR(handle);
+		handle = NULL;
+		mlog_errno(ret);
+		goto leave;
+	}
+
+	ret = ocfs2_journal_access(handle, inode, root_bh,
+				   OCFS2_JOURNAL_ACCESS_WRITE);
+	if (ret < 0) {
+		mlog_errno(ret);
+		goto leave;
+	}
+
+	ret = __ocfs2_claim_clusters(osb, handle, data_ac, 1,
+				     clusters_to_add, &bit_off, &num_bits);
+	if (ret < 0) {
+		if (ret != -ENOSPC)
+			mlog_errno(ret);
+		goto leave;
+	}
+
+	BUG_ON(num_bits > clusters_to_add);
+
+	block = ocfs2_clusters_to_blocks(osb->sb, bit_off);
+	mlog(0, "Allocating %u clusters at block %u for xattr in inode %llu\n",
+	     num_bits, bit_off, (unsigned long long)OCFS2_I(inode)->ip_blkno);
+
+	if (prev_blkno + prev_clusters * bpc == block &&
+	    (prev_clusters + num_bits) << osb->s_clustersize_bits <=
+	     OCFS2_MAX_XATTR_TREE_LEAF_SIZE) {
+		/*
+		 * If this cluster is contiguous with the old one and
+		 * adding this new cluster, we don't surpass the limit of
+		 * OCFS2_MAX_XATTR_TREE_LEAF_SIZE, cool. We will let it be
+		 * initialized and used like other buckets in the previous
+		 * cluster.
+		 * So add it as a contiguous one. The caller will handle
+		 * its init process.
+		 */
+		v_start = prev_cpos + prev_clusters;
+		*num_clusters = prev_clusters + num_bits;
+		mlog(0, "Add contiguous %u clusters to previous extent rec.\n",
+		     num_bits);
+	} else {
+		ret = ocfs2_adjust_xattr_cross_cluster(inode,
+						       handle,
+						       first_bh,
+						       header_bh,
+						       block,
+						       prev_blkno,
+						       prev_clusters,
+						       &v_start,
+						       extend);
+		if (ret) {
+			mlog_errno(ret);
+			goto leave;
+		}
+	}
+
+	if (handle->h_buffer_credits < credits) {
+		/*
+		 * The journal has been restarted before, and don't
+		 * have enough space for the insertion, so extend it
+		 * here.
+		 */
+		ret = ocfs2_extend_trans(handle, credits);
+		if (ret) {
+			mlog_errno(ret);
+			goto leave;
+		}
+	}
+	mlog(0, "Insert %u clusters at block %llu for xattr at %u\n",
+	     num_bits, block, v_start);
+	ret = ocfs2_insert_extent(osb, handle, inode, &et, v_start, block,
+				  num_bits, 0, meta_ac);
+	if (ret < 0) {
+		mlog_errno(ret);
+		goto leave;
+	}
+
+	ret = ocfs2_journal_dirty(handle, root_bh);
+	if (ret < 0) {
+		mlog_errno(ret);
+		goto leave;
+	}
+
+leave:
+	if (handle)
+		ocfs2_commit_trans(osb, handle);
+	if (data_ac)
+		ocfs2_free_alloc_context(data_ac);
+	if (meta_ac)
+		ocfs2_free_alloc_context(meta_ac);
+
+	return ret;
+}
+
+/*
+ * Extend a new xattr bucket and move xattrs to the end one by one until
+ * We meet with start_bh. Only move half of the xattrs to the bucket after it.
+ */
+static int ocfs2_extend_xattr_bucket(struct inode *inode,
+				     struct buffer_head *first_bh,
+				     struct buffer_head *start_bh,
+				     u32 num_clusters)
+{
+	int ret, credits;
+	struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+	u16 blk_per_bucket = ocfs2_blocks_per_xattr_bucket(inode->i_sb);
+	u64 start_blk = start_bh->b_blocknr, end_blk;
+	u32 num_buckets = num_clusters * ocfs2_xattr_buckets_per_cluster(osb);
+	handle_t *handle;
+	struct ocfs2_xattr_header *first_xh =
+				(struct ocfs2_xattr_header *)first_bh->b_data;
+	u16 bucket = le16_to_cpu(first_xh->xh_num_buckets);
+
+	mlog(0, "extend xattr bucket in %llu, xattr extend rec starting "
+	     "from %llu, len = %u\n", start_blk,
+	     (unsigned long long)first_bh->b_blocknr, num_clusters);
+
+	BUG_ON(bucket >= num_buckets);
+
+	end_blk = first_bh->b_blocknr + (bucket - 1) * blk_per_bucket;
+
+	/*
+	 * We will touch all the buckets after the start_bh(include it).
+	 * Add one more bucket and modify the first_bh.
+	 */
+	credits = end_blk - start_blk + 2 * blk_per_bucket + 1;
+	handle = ocfs2_start_trans(osb, credits);
+	if (IS_ERR(handle)) {
+		ret = PTR_ERR(handle);
+		handle = NULL;
+		mlog_errno(ret);
+		goto out;
+	}
+
+	ret = ocfs2_journal_access(handle, inode, first_bh,
+				   OCFS2_JOURNAL_ACCESS_WRITE);
+	if (ret) {
+		mlog_errno(ret);
+		goto commit;
+	}
+
+	while (end_blk != start_blk) {
+		ret = ocfs2_cp_xattr_bucket(inode, handle, end_blk,
+					    end_blk + blk_per_bucket, 0);
+		if (ret)
+			goto commit;
+		end_blk -= blk_per_bucket;
+	}
+
+	/* Move half of the xattr in start_blk to the next bucket. */
+	ret = ocfs2_half_xattr_bucket(inode, handle, start_blk,
+				      start_blk + blk_per_bucket, NULL, 0);
+
+	le16_add_cpu(&first_xh->xh_num_buckets, 1);
+	ocfs2_journal_dirty(handle, first_bh);
+
+commit:
+	ocfs2_commit_trans(osb, handle);
+out:
+	return ret;
+}
+
+/*
+ * Add new xattr bucket in an extent record and adjust the buckets accordingly.
+ * xb_bh is the ocfs2_xattr_block.
+ * We will move all the buckets starting from header_bh to the next place. As
+ * for this one, half num of its xattrs will be moved to the next one.
+ *
+ * We will allocate a new cluster if current cluster is full and adjust
+ * header_bh and first_bh if the insert place is moved to the new cluster.
+ */
+static int ocfs2_add_new_xattr_bucket(struct inode *inode,
+				      struct buffer_head *xb_bh,
+				      struct buffer_head *header_bh)
+{
+	struct ocfs2_xattr_header *first_xh = NULL;
+	struct buffer_head *first_bh = NULL;
+	struct ocfs2_xattr_block *xb =
+			(struct ocfs2_xattr_block *)xb_bh->b_data;
+	struct ocfs2_xattr_tree_root *xb_root = &xb->xb_attrs.xb_root;
+	struct ocfs2_extent_list *el = &xb_root->xt_list;
+	struct ocfs2_xattr_header *xh =
+			(struct ocfs2_xattr_header *)header_bh->b_data;
+	u32 name_hash = le32_to_cpu(xh->xh_entries[0].xe_name_hash);
+	struct super_block *sb = inode->i_sb;
+	struct ocfs2_super *osb = OCFS2_SB(sb);
+	int ret, num_buckets, extend = 1;
+	u64 p_blkno;
+	u32 e_cpos, num_clusters;
+
+	mlog(0, "Add new xattr bucket starting form %llu\n",
+	     (unsigned long long)header_bh->b_blocknr);
+
+	/*
+	 * Add refrence for header_bh here because it may be
+	 * changed in ocfs2_add_new_xattr_cluster and we need
+	 * to free it in the end.
+	 */
+	get_bh(header_bh);
+
+	ret = ocfs2_xattr_get_rec(inode, name_hash, &p_blkno, &e_cpos,
+				  &num_clusters, el);
+	if (ret) {
+		mlog_errno(ret);
+		goto out;
+	}
+
+	ret = ocfs2_read_block(inode, p_blkno, &first_bh);
+	if (ret) {
+		mlog_errno(ret);
+		goto out;
+	}
+
+	num_buckets = ocfs2_xattr_buckets_per_cluster(osb) * num_clusters;
+	first_xh = (struct ocfs2_xattr_header *)first_bh->b_data;
+
+	if (num_buckets == le16_to_cpu(first_xh->xh_num_buckets)) {
+		ret = ocfs2_add_new_xattr_cluster(inode,
+						  xb_bh,
+						  &first_bh,
+						  &header_bh,
+						  &num_clusters,
+						  e_cpos,
+						  p_blkno,
+						  &extend);
+		if (ret) {
+			mlog_errno(ret);
+			goto out;
+		}
+	}
+
+	if (extend)
+		ret = ocfs2_extend_xattr_bucket(inode,
+						first_bh,
+						header_bh,
+						num_clusters);
+	if (ret)
+		mlog_errno(ret);
+out:
+	brelse(first_bh);
+	brelse(header_bh);
+	return ret;
+}
+
+static inline char *ocfs2_xattr_bucket_get_val(struct inode *inode,
+					struct ocfs2_xattr_bucket *bucket,
+					int offs)
+{
+	int block_off = offs >> inode->i_sb->s_blocksize_bits;
+
+	offs = offs % inode->i_sb->s_blocksize;
+	return bucket->bhs[block_off]->b_data + offs;
+}
+
+/*
+ * Handle the normal xattr set, including replace, delete and new.
+ *
+ * Note: "local" indicates the real data's locality. So we can't
+ * just its bucket locality by its length.
+ */
+static void ocfs2_xattr_set_entry_normal(struct inode *inode,
+					 struct ocfs2_xattr_info *xi,
+					 struct ocfs2_xattr_search *xs,
+					 u32 name_hash,
+					 int local)
+{
+	struct ocfs2_xattr_entry *last, *xe;
+	int name_len = strlen(xi->name);
+	struct ocfs2_xattr_header *xh = xs->header;
+	u16 count = le16_to_cpu(xh->xh_count), start;
+	size_t blocksize = inode->i_sb->s_blocksize;
+	char *val;
+	size_t offs, size, new_size;
+
+	last = &xh->xh_entries[count];
+	if (!xs->not_found) {
+		xe = xs->here;
+		offs = le16_to_cpu(xe->xe_name_offset);
+		if (ocfs2_xattr_is_local(xe))
+			size = OCFS2_XATTR_SIZE(name_len) +
+			OCFS2_XATTR_SIZE(le64_to_cpu(xe->xe_value_size));
+		else
+			size = OCFS2_XATTR_SIZE(name_len) +
+			OCFS2_XATTR_SIZE(OCFS2_XATTR_ROOT_SIZE);
+
+		/*
+		 * If the new value will be stored outside, xi->value has been
+		 * initalized as an empty ocfs2_xattr_value_root, and the same
+		 * goes with xi->value_len, so we can set new_size safely here.
+		 * See ocfs2_xattr_set_in_bucket.
+		 */
+		new_size = OCFS2_XATTR_SIZE(name_len) +
+			   OCFS2_XATTR_SIZE(xi->value_len);
+
+		le16_add_cpu(&xh->xh_name_value_len, -size);
+		if (xi->value) {
+			if (new_size > size)
+				goto set_new_name_value;
+
+			/* Now replace the old value with new one. */
+			if (local)
+				xe->xe_value_size = cpu_to_le64(xi->value_len);
+			else
+				xe->xe_value_size = 0;
+
+			val = ocfs2_xattr_bucket_get_val(inode,
+							 &xs->bucket, offs);
+			memset(val + OCFS2_XATTR_SIZE(name_len), 0,
+			       size - OCFS2_XATTR_SIZE(name_len));
+			if (OCFS2_XATTR_SIZE(xi->value_len) > 0)
+				memcpy(val + OCFS2_XATTR_SIZE(name_len),
+				       xi->value, xi->value_len);
+
+			le16_add_cpu(&xh->xh_name_value_len, new_size);
+			ocfs2_xattr_set_local(xe, local);
+			return;
+		} else {
+			/*
+			 * Remove the old entry if there is more than one.
+			 * We don't remove the last entry so that we can
+			 * use it to indicate the hash value of the empty
+			 * bucket.
+			 */
+			last -= 1;
+			le16_add_cpu(&xh->xh_count, -1);
+			if (xh->xh_count) {
+				memmove(xe, xe + 1,
+					(void *)last - (void *)xe);
+				memset(last, 0,
+				       sizeof(struct ocfs2_xattr_entry));
+			} else
+				xh->xh_free_start =
+					cpu_to_le16(OCFS2_XATTR_BUCKET_SIZE);
+
+			return;
+		}
+	} else {
+		/* find a new entry for insert. */
+		int low = 0, high = count - 1, tmp;
+		struct ocfs2_xattr_entry *tmp_xe;
+
+		while (low <= high && count) {
+			tmp = (low + high) / 2;
+			tmp_xe = &xh->xh_entries[tmp];
+
+			if (name_hash > le32_to_cpu(tmp_xe->xe_name_hash))
+				low = tmp + 1;
+			else if (name_hash <
+				 le32_to_cpu(tmp_xe->xe_name_hash))
+				high = tmp - 1;
+			else {
+				low = tmp;
+				break;
+			}
+		}
+
+		xe = &xh->xh_entries[low];
+		if (low != count)
+			memmove(xe + 1, xe, (void *)last - (void *)xe);
+
+		le16_add_cpu(&xh->xh_count, 1);
+		memset(xe, 0, sizeof(struct ocfs2_xattr_entry));
+		xe->xe_name_hash = cpu_to_le32(name_hash);
+		xe->xe_name_len = name_len;
+		ocfs2_xattr_set_type(xe, xi->name_index);
+	}
+
+set_new_name_value:
+	/* Insert the new name+value. */
+	size = OCFS2_XATTR_SIZE(name_len) + OCFS2_XATTR_SIZE(xi->value_len);
+
+	/*
+	 * We must make sure that the name/value pair
+	 * exists in the same block.
+	 */
+	offs = le16_to_cpu(xh->xh_free_start);
+	start = offs - size;
+
+	if (start >> inode->i_sb->s_blocksize_bits !=
+	    (offs - 1) >> inode->i_sb->s_blocksize_bits) {
+		offs = offs - offs % blocksize;
+		xh->xh_free_start = cpu_to_le16(offs);
+	}
+
+	val = ocfs2_xattr_bucket_get_val(inode,
+					 &xs->bucket, offs - size);
+	xe->xe_name_offset = cpu_to_le16(offs - size);
+
+	memset(val, 0, size);
+	memcpy(val, xi->name, name_len);
+	memcpy(val + OCFS2_XATTR_SIZE(name_len), xi->value, xi->value_len);
+
+	xe->xe_value_size = cpu_to_le64(xi->value_len);
+	ocfs2_xattr_set_local(xe, local);
+	xs->here = xe;
+	le16_add_cpu(&xh->xh_free_start, -size);
+	le16_add_cpu(&xh->xh_name_value_len, size);
+
+	return;
+}
+
+static int ocfs2_xattr_bucket_handle_journal(struct inode *inode,
+					     handle_t *handle,
+					     struct ocfs2_xattr_search *xs,
+					     struct buffer_head **bhs,
+					     u16 bh_num)
+{
+	int ret = 0, off, block_off;
+	struct ocfs2_xattr_entry *xe = xs->here;
+
+	/*
+	 * First calculate all the blocks we should journal_access
+	 * and journal_dirty. The first block should always be touched.
+	 */
+	ret = ocfs2_journal_dirty(handle, bhs[0]);
+	if (ret)
+		mlog_errno(ret);
+
+	/* calc the data. */
+	off = le16_to_cpu(xe->xe_name_offset);
+	block_off = off >> inode->i_sb->s_blocksize_bits;
+	ret = ocfs2_journal_dirty(handle, bhs[block_off]);
+	if (ret)
+		mlog_errno(ret);
+
+	return ret;
+}
+
+/*
+ * Set the xattr entry in the specified bucket.
+ * The bucket is indicated by xs->bucket and it should have the enough
+ * space for the xattr insertion.
+ */
+static int ocfs2_xattr_set_entry_in_bucket(struct inode *inode,
+					   struct ocfs2_xattr_info *xi,
+					   struct ocfs2_xattr_search *xs,
+					   u32 name_hash,
+					   int local)
+{
+	int i, ret;
+	handle_t *handle = NULL;
+	u16 blk_per_bucket = ocfs2_blocks_per_xattr_bucket(inode->i_sb);
+	struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+
+	mlog(0, "Set xattr entry len = %lu index = %d in bucket %llu\n",
+	     (unsigned long)xi->value_len, xi->name_index,
+	     (unsigned long long)xs->bucket.bhs[0]->b_blocknr);
+
+	if (!xs->bucket.bhs[1]) {
+		ret = ocfs2_read_blocks(inode,
+					xs->bucket.bhs[0]->b_blocknr + 1,
+					blk_per_bucket - 1, &xs->bucket.bhs[1],
+					OCFS2_BH_CACHED);
+		if (ret) {
+			mlog_errno(ret);
+			goto out;
+		}
+	}
+
+	handle = ocfs2_start_trans(osb, blk_per_bucket);
+	if (IS_ERR(handle)) {
+		ret = PTR_ERR(handle);
+		handle = NULL;
+		mlog_errno(ret);
+		goto out;
+	}
+
+	for (i = 0; i < blk_per_bucket; i++) {
+		ret = ocfs2_journal_access(handle, inode, xs->bucket.bhs[i],
+					   OCFS2_JOURNAL_ACCESS_WRITE);
+		if (ret < 0) {
+			mlog_errno(ret);
+			goto out;
+		}
+	}
+
+	ocfs2_xattr_set_entry_normal(inode, xi, xs, name_hash, local);
+
+	/*Only dirty the blocks we have touched in set xattr. */
+	ret = ocfs2_xattr_bucket_handle_journal(inode, handle, xs,
+						xs->bucket.bhs, blk_per_bucket);
+	if (ret)
+		mlog_errno(ret);
+out:
+	ocfs2_commit_trans(osb, handle);
+
+	return ret;
+}
+
+static int ocfs2_xattr_value_update_size(struct inode *inode,
+					 struct buffer_head *xe_bh,
+					 struct ocfs2_xattr_entry *xe,
+					 u64 new_size)
+{
+	int ret;
+	struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+	handle_t *handle = NULL;
+
+	handle = ocfs2_start_trans(osb, 1);
+	if (handle == NULL) {
+		ret = -ENOMEM;
+		mlog_errno(ret);
+		goto out;
+	}
+
+	ret = ocfs2_journal_access(handle, inode, xe_bh,
+				   OCFS2_JOURNAL_ACCESS_WRITE);
+	if (ret < 0) {
+		mlog_errno(ret);
+		goto out_commit;
+	}
+
+	xe->xe_value_size = cpu_to_le64(new_size);
+
+	ret = ocfs2_journal_dirty(handle, xe_bh);
+	if (ret < 0)
+		mlog_errno(ret);
+
+out_commit:
+	ocfs2_commit_trans(osb, handle);
+out:
+	return ret;
+}
+
+/*
+ * Truncate the specified xe_off entry in xattr bucket.
+ * bucket is indicated by header_bh and len is the new length.
+ * Both the ocfs2_xattr_value_root and the entry will be updated here.
+ *
+ * Copy the new updated xe and xe_value_root to new_xe and new_xv if needed.
+ */
+static int ocfs2_xattr_bucket_value_truncate(struct inode *inode,
+					     struct buffer_head *header_bh,
+					     int xe_off,
+					     int len)
+{
+	int ret, offset;
+	u64 value_blk;
+	struct buffer_head *value_bh = NULL;
+	struct ocfs2_xattr_value_root *xv;
+	struct ocfs2_xattr_entry *xe;
+	struct ocfs2_xattr_header *xh =
+			(struct ocfs2_xattr_header *)header_bh->b_data;
+	size_t blocksize = inode->i_sb->s_blocksize;
+
+	xe = &xh->xh_entries[xe_off];
+
+	BUG_ON(!xe || ocfs2_xattr_is_local(xe));
+
+	offset = le16_to_cpu(xe->xe_name_offset) +
+		 OCFS2_XATTR_SIZE(xe->xe_name_len);
+
+	value_blk = offset / blocksize;
+
+	/* We don't allow ocfs2_xattr_value to be stored in different block. */
+	BUG_ON(value_blk != (offset + OCFS2_XATTR_ROOT_SIZE - 1) / blocksize);
+	value_blk += header_bh->b_blocknr;
+
+	ret = ocfs2_read_block(inode, value_blk, &value_bh);
+	if (ret) {
+		mlog_errno(ret);
+		goto out;
+	}
+
+	xv = (struct ocfs2_xattr_value_root *)
+		(value_bh->b_data + offset % blocksize);
+
+	mlog(0, "truncate %u in xattr bucket %llu to %d bytes.\n",
+	     xe_off, (unsigned long long)header_bh->b_blocknr, len);
+	ret = ocfs2_xattr_value_truncate(inode, value_bh, xv, len);
+	if (ret) {
+		mlog_errno(ret);
+		goto out;
+	}
+
+	ret = ocfs2_xattr_value_update_size(inode, header_bh, xe, len);
+	if (ret) {
+		mlog_errno(ret);
+		goto out;
+	}
+
+out:
+	brelse(value_bh);
+	return ret;
+}
+
+static int ocfs2_xattr_bucket_value_truncate_xs(struct inode *inode,
+						struct ocfs2_xattr_search *xs,
+						int len)
+{
+	int ret, offset;
+	struct ocfs2_xattr_entry *xe = xs->here;
+	struct ocfs2_xattr_header *xh = (struct ocfs2_xattr_header *)xs->base;
+
+	BUG_ON(!xs->bucket.bhs[0] || !xe || ocfs2_xattr_is_local(xe));
+
+	offset = xe - xh->xh_entries;
+	ret = ocfs2_xattr_bucket_value_truncate(inode, xs->bucket.bhs[0],
+						offset, len);
+	if (ret)
+		mlog_errno(ret);
+
+	return ret;
+}
+
+static int ocfs2_xattr_bucket_set_value_outside(struct inode *inode,
+						struct ocfs2_xattr_search *xs,
+						char *val,
+						int value_len)
+{
+	int offset;
+	struct ocfs2_xattr_value_root *xv;
+	struct ocfs2_xattr_entry *xe = xs->here;
+
+	BUG_ON(!xs->base || !xe || ocfs2_xattr_is_local(xe));
+
+	offset = le16_to_cpu(xe->xe_name_offset) +
+		 OCFS2_XATTR_SIZE(xe->xe_name_len);
+
+	xv = (struct ocfs2_xattr_value_root *)(xs->base + offset);
+
+	return __ocfs2_xattr_set_value_outside(inode, xv, val, value_len);
+}
+
+static int ocfs2_rm_xattr_cluster(struct inode *inode,
+				  struct buffer_head *root_bh,
+				  u64 blkno,
+				  u32 cpos,
+				  u32 len)
+{
+	int ret;
+	struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+	struct inode *tl_inode = osb->osb_tl_inode;
+	handle_t *handle;
+	struct ocfs2_xattr_block *xb =
+			(struct ocfs2_xattr_block *)root_bh->b_data;
+	struct ocfs2_alloc_context *meta_ac = NULL;
+	struct ocfs2_cached_dealloc_ctxt dealloc;
+	struct ocfs2_extent_tree et;
+
+	ocfs2_init_xattr_tree_extent_tree(&et, inode, root_bh);
+
+	ocfs2_init_dealloc_ctxt(&dealloc);
+
+	mlog(0, "rm xattr extent rec at %u len = %u, start from %llu\n",
+	     cpos, len, (unsigned long long)blkno);
+
+	ocfs2_remove_xattr_clusters_from_cache(inode, blkno, len);
+
+	ret = ocfs2_lock_allocators(inode, &et, 0, 1, NULL, &meta_ac);
+	if (ret) {
+		mlog_errno(ret);
+		return ret;
+	}
+
+	mutex_lock(&tl_inode->i_mutex);
+
+	if (ocfs2_truncate_log_needs_flush(osb)) {
+		ret = __ocfs2_flush_truncate_log(osb);
+		if (ret < 0) {
+			mlog_errno(ret);
+			goto out;
+		}
+	}
+
+	handle = ocfs2_start_trans(osb, OCFS2_REMOVE_EXTENT_CREDITS);
+	if (handle == NULL) {
+		ret = -ENOMEM;
+		mlog_errno(ret);
+		goto out;
+	}
+
+	ret = ocfs2_journal_access(handle, inode, root_bh,
+				   OCFS2_JOURNAL_ACCESS_WRITE);
+	if (ret) {
+		mlog_errno(ret);
+		goto out_commit;
+	}
+
+	ret = ocfs2_remove_extent(inode, &et, cpos, len, handle, meta_ac,
+				  &dealloc);
+	if (ret) {
+		mlog_errno(ret);
+		goto out_commit;
+	}
+
+	le32_add_cpu(&xb->xb_attrs.xb_root.xt_clusters, -len);
+
+	ret = ocfs2_journal_dirty(handle, root_bh);
+	if (ret) {
+		mlog_errno(ret);
+		goto out_commit;
+	}
+
+	ret = ocfs2_truncate_log_append(osb, handle, blkno, len);
+	if (ret)
+		mlog_errno(ret);
+
+out_commit:
+	ocfs2_commit_trans(osb, handle);
+out:
+	ocfs2_schedule_truncate_log_flush(osb, 1);
+
+	mutex_unlock(&tl_inode->i_mutex);
+
+	if (meta_ac)
+		ocfs2_free_alloc_context(meta_ac);
+
+	ocfs2_run_deallocs(osb, &dealloc);
+
+	return ret;
+}
+
+static void ocfs2_xattr_bucket_remove_xs(struct inode *inode,
+					 struct ocfs2_xattr_search *xs)
+{
+	handle_t *handle = NULL;
+	struct ocfs2_xattr_header *xh = xs->bucket.xh;
+	struct ocfs2_xattr_entry *last = &xh->xh_entries[
+						le16_to_cpu(xh->xh_count) - 1];
+	int ret = 0;
+
+	handle = ocfs2_start_trans((OCFS2_SB(inode->i_sb)), 1);
+	if (IS_ERR(handle)) {
+		ret = PTR_ERR(handle);
+		mlog_errno(ret);
+		return;
+	}
+
+	ret = ocfs2_journal_access(handle, inode, xs->bucket.bhs[0],
+				   OCFS2_JOURNAL_ACCESS_WRITE);
+	if (ret) {
+		mlog_errno(ret);
+		goto out_commit;
+	}
+
+	/* Remove the old entry. */
+	memmove(xs->here, xs->here + 1,
+		(void *)last - (void *)xs->here);
+	memset(last, 0, sizeof(struct ocfs2_xattr_entry));
+	le16_add_cpu(&xh->xh_count, -1);
+
+	ret = ocfs2_journal_dirty(handle, xs->bucket.bhs[0]);
+	if (ret < 0)
+		mlog_errno(ret);
+out_commit:
+	ocfs2_commit_trans(OCFS2_SB(inode->i_sb), handle);
+}
+
+/*
+ * Set the xattr name/value in the bucket specified in xs.
+ *
+ * As the new value in xi may be stored in the bucket or in an outside cluster,
+ * we divide the whole process into 3 steps:
+ * 1. insert name/value in the bucket(ocfs2_xattr_set_entry_in_bucket)
+ * 2. truncate of the outside cluster(ocfs2_xattr_bucket_value_truncate_xs)
+ * 3. Set the value to the outside cluster(ocfs2_xattr_bucket_set_value_outside)
+ * 4. If the clusters for the new outside value can't be allocated, we need
+ *    to free the xattr we allocated in set.
+ */
+static int ocfs2_xattr_set_in_bucket(struct inode *inode,
+				     struct ocfs2_xattr_info *xi,
+				     struct ocfs2_xattr_search *xs)
+{
+	int ret, local = 1;
+	size_t value_len;
+	char *val = (char *)xi->value;
+	struct ocfs2_xattr_entry *xe = xs->here;
+	u32 name_hash = ocfs2_xattr_name_hash(inode, xi->name,
+					      strlen(xi->name));
+
+	if (!xs->not_found && !ocfs2_xattr_is_local(xe)) {
+		/*
+		 * We need to truncate the xattr storage first.
+		 *
+		 * If both the old and new value are stored to
+		 * outside block, we only need to truncate
+		 * the storage and then set the value outside.
+		 *
+		 * If the new value should be stored within block,
+		 * we should free all the outside block first and
+		 * the modification to the xattr block will be done
+		 * by following steps.
+		 */
+		if (xi->value_len > OCFS2_XATTR_INLINE_SIZE)
+			value_len = xi->value_len;
+		else
+			value_len = 0;
+
+		ret = ocfs2_xattr_bucket_value_truncate_xs(inode, xs,
+							   value_len);
+		if (ret)
+			goto out;
+
+		if (value_len)
+			goto set_value_outside;
+	}
+
+	value_len = xi->value_len;
+	/* So we have to handle the inside block change now. */
+	if (value_len > OCFS2_XATTR_INLINE_SIZE) {
+		/*
+		 * If the new value will be stored outside of block,
+		 * initalize a new empty value root and insert it first.
+		 */
+		local = 0;
+		xi->value = &def_xv;
+		xi->value_len = OCFS2_XATTR_ROOT_SIZE;
+	}
+
+	ret = ocfs2_xattr_set_entry_in_bucket(inode, xi, xs, name_hash, local);
+	if (ret) {
+		mlog_errno(ret);
+		goto out;
+	}
+
+	if (value_len <= OCFS2_XATTR_INLINE_SIZE)
+		goto out;
+
+	/* allocate the space now for the outside block storage. */
+	ret = ocfs2_xattr_bucket_value_truncate_xs(inode, xs,
+						   value_len);
+	if (ret) {
+		mlog_errno(ret);
+
+		if (xs->not_found) {
+			/*
+			 * We can't allocate enough clusters for outside
+			 * storage and we have allocated xattr already,
+			 * so need to remove it.
+			 */
+			ocfs2_xattr_bucket_remove_xs(inode, xs);
+		}
+		goto out;
+	}
+
+set_value_outside:
+	ret = ocfs2_xattr_bucket_set_value_outside(inode, xs, val, value_len);
+out:
+	return ret;
+}
+
+/* check whether the xattr bucket is filled up with the same hash value. */
+static int ocfs2_check_xattr_bucket_collision(struct inode *inode,
+					      struct ocfs2_xattr_bucket *bucket)
+{
+	struct ocfs2_xattr_header *xh = bucket->xh;
+
+	if (xh->xh_entries[le16_to_cpu(xh->xh_count) - 1].xe_name_hash ==
+	    xh->xh_entries[0].xe_name_hash) {
+		mlog(ML_ERROR, "Too much hash collision in xattr bucket %llu, "
+		     "hash = %u\n",
+		     (unsigned long long)bucket->bhs[0]->b_blocknr,
+		     le32_to_cpu(xh->xh_entries[0].xe_name_hash));
+		return -ENOSPC;
+	}
+
+	return 0;
+}
+
+static int ocfs2_xattr_set_entry_index_block(struct inode *inode,
+					     struct ocfs2_xattr_info *xi,
+					     struct ocfs2_xattr_search *xs)
+{
+	struct ocfs2_xattr_header *xh;
+	struct ocfs2_xattr_entry *xe;
+	u16 count, header_size, xh_free_start;
+	int i, free, max_free, need, old;
+	size_t value_size = 0, name_len = strlen(xi->name);
+	size_t blocksize = inode->i_sb->s_blocksize;
+	int ret, allocation = 0;
+	u16 blk_per_bucket = ocfs2_blocks_per_xattr_bucket(inode->i_sb);
+
+	mlog_entry("Set xattr %s in xattr index block\n", xi->name);
+
+try_again:
+	xh = xs->header;
+	count = le16_to_cpu(xh->xh_count);
+	xh_free_start = le16_to_cpu(xh->xh_free_start);
+	header_size = sizeof(struct ocfs2_xattr_header) +
+			count * sizeof(struct ocfs2_xattr_entry);
+	max_free = OCFS2_XATTR_BUCKET_SIZE -
+		le16_to_cpu(xh->xh_name_value_len) - header_size;
+
+	mlog_bug_on_msg(header_size > blocksize, "bucket %llu has header size "
+			"of %u which exceed block size\n",
+			(unsigned long long)xs->bucket.bhs[0]->b_blocknr,
+			header_size);
+
+	if (xi->value && xi->value_len > OCFS2_XATTR_INLINE_SIZE)
+		value_size = OCFS2_XATTR_ROOT_SIZE;
+	else if (xi->value)
+		value_size = OCFS2_XATTR_SIZE(xi->value_len);
+
+	if (xs->not_found)
+		need = sizeof(struct ocfs2_xattr_entry) +
+			OCFS2_XATTR_SIZE(name_len) + value_size;
+	else {
+		need = value_size + OCFS2_XATTR_SIZE(name_len);
+
+		/*
+		 * We only replace the old value if the new length is smaller
+		 * than the old one. Otherwise we will allocate new space in the
+		 * bucket to store it.
+		 */
+		xe = xs->here;
+		if (ocfs2_xattr_is_local(xe))
+			old = OCFS2_XATTR_SIZE(le64_to_cpu(xe->xe_value_size));
+		else
+			old = OCFS2_XATTR_SIZE(OCFS2_XATTR_ROOT_SIZE);
+
+		if (old >= value_size)
+			need = 0;
+	}
+
+	free = xh_free_start - header_size;
+	/*
+	 * We need to make sure the new name/value pair
+	 * can exist in the same block.
+	 */
+	if (xh_free_start % blocksize < need)
+		free -= xh_free_start % blocksize;
+
+	mlog(0, "xs->not_found = %d, in xattr bucket %llu: free = %d, "
+	     "need = %d, max_free = %d, xh_free_start = %u, xh_name_value_len ="
+	     " %u\n", xs->not_found,
+	     (unsigned long long)xs->bucket.bhs[0]->b_blocknr,
+	     free, need, max_free, le16_to_cpu(xh->xh_free_start),
+	     le16_to_cpu(xh->xh_name_value_len));
+
+	if (free < need || count == ocfs2_xattr_max_xe_in_bucket(inode->i_sb)) {
+		if (need <= max_free &&
+		    count < ocfs2_xattr_max_xe_in_bucket(inode->i_sb)) {
+			/*
+			 * We can create the space by defragment. Since only the
+			 * name/value will be moved, the xe shouldn't be changed
+			 * in xs.
+			 */
+			ret = ocfs2_defrag_xattr_bucket(inode, &xs->bucket);
+			if (ret) {
+				mlog_errno(ret);
+				goto out;
+			}
+
+			xh_free_start = le16_to_cpu(xh->xh_free_start);
+			free = xh_free_start - header_size;
+			if (xh_free_start % blocksize < need)
+				free -= xh_free_start % blocksize;
+
+			if (free >= need)
+				goto xattr_set;
+
+			mlog(0, "Can't get enough space for xattr insert by "
+			     "defragment. Need %u bytes, but we have %d, so "
+			     "allocate new bucket for it.\n", need, free);
+		}
+
+		/*
+		 * We have to add new buckets or clusters and one
+		 * allocation should leave us enough space for insert.
+		 */
+		BUG_ON(allocation);
+
+		/*
+		 * We do not allow for overlapping ranges between buckets. And
+		 * the maximum number of collisions we will allow for then is
+		 * one bucket's worth, so check it here whether we need to
+		 * add a new bucket for the insert.
+		 */
+		ret = ocfs2_check_xattr_bucket_collision(inode, &xs->bucket);
+		if (ret) {
+			mlog_errno(ret);
+			goto out;
+		}
+
+		ret = ocfs2_add_new_xattr_bucket(inode,
+						 xs->xattr_bh,
+						 xs->bucket.bhs[0]);
+		if (ret) {
+			mlog_errno(ret);
+			goto out;
+		}
+
+		for (i = 0; i < blk_per_bucket; i++)
+			brelse(xs->bucket.bhs[i]);
+
+		memset(&xs->bucket, 0, sizeof(xs->bucket));
+
+		ret = ocfs2_xattr_index_block_find(inode, xs->xattr_bh,
+						   xi->name_index,
+						   xi->name, xs);
+		if (ret && ret != -ENODATA)
+			goto out;
+		xs->not_found = ret;
+		allocation = 1;
+		goto try_again;
+	}
+
+xattr_set:
+	ret = ocfs2_xattr_set_in_bucket(inode, xi, xs);
+out:
+	mlog_exit(ret);
+	return ret;
+}
+
+static int ocfs2_delete_xattr_in_bucket(struct inode *inode,
+					struct ocfs2_xattr_bucket *bucket,
+					void *para)
+{
+	int ret = 0;
+	struct ocfs2_xattr_header *xh = bucket->xh;
+	u16 i;
+	struct ocfs2_xattr_entry *xe;
+
+	for (i = 0; i < le16_to_cpu(xh->xh_count); i++) {
+		xe = &xh->xh_entries[i];
+		if (ocfs2_xattr_is_local(xe))
+			continue;
+
+		ret = ocfs2_xattr_bucket_value_truncate(inode,
+							bucket->bhs[0],
+							i, 0);
+		if (ret) {
+			mlog_errno(ret);
+			break;
+		}
+	}
+
+	return ret;
+}
+
+static int ocfs2_delete_xattr_index_block(struct inode *inode,
+					  struct buffer_head *xb_bh)
+{
+	struct ocfs2_xattr_block *xb =
+			(struct ocfs2_xattr_block *)xb_bh->b_data;
+	struct ocfs2_extent_list *el = &xb->xb_attrs.xb_root.xt_list;
+	int ret = 0;
+	u32 name_hash = UINT_MAX, e_cpos, num_clusters;
+	u64 p_blkno;
+
+	if (le16_to_cpu(el->l_next_free_rec) == 0)
+		return 0;
+
+	while (name_hash > 0) {
+		ret = ocfs2_xattr_get_rec(inode, name_hash, &p_blkno,
+					  &e_cpos, &num_clusters, el);
+		if (ret) {
+			mlog_errno(ret);
+			goto out;
+		}
+
+		ret = ocfs2_iterate_xattr_buckets(inode, p_blkno, num_clusters,
+						  ocfs2_delete_xattr_in_bucket,
+						  NULL);
+		if (ret) {
+			mlog_errno(ret);
+			goto out;
+		}
+
+		ret = ocfs2_rm_xattr_cluster(inode, xb_bh,
+					     p_blkno, e_cpos, num_clusters);
+		if (ret) {
+			mlog_errno(ret);
+			break;
+		}
+
+		if (e_cpos == 0)
+			break;
+
+		name_hash = e_cpos - 1;
+	}
+
+out:
+	return ret;
+}
+
+/*
+ * 'trusted' attributes support
+ */
+
+#define XATTR_TRUSTED_PREFIX "trusted."
+
+static size_t ocfs2_xattr_trusted_list(struct inode *inode, char *list,
+				       size_t list_size, const char *name,
+				       size_t name_len)
+{
+	const size_t prefix_len = sizeof(XATTR_TRUSTED_PREFIX) - 1;
+	const size_t total_len = prefix_len + name_len + 1;
+
+	if (list && total_len <= list_size) {
+		memcpy(list, XATTR_TRUSTED_PREFIX, prefix_len);
+		memcpy(list + prefix_len, name, name_len);
+		list[prefix_len + name_len] = '\0';
+	}
+	return total_len;
+}
+
+static int ocfs2_xattr_trusted_get(struct inode *inode, const char *name,
+				   void *buffer, size_t size)
+{
+	if (strcmp(name, "") == 0)
+		return -EINVAL;
+	return ocfs2_xattr_get(inode, OCFS2_XATTR_INDEX_TRUSTED, name,
+			       buffer, size);
+}
+
+static int ocfs2_xattr_trusted_set(struct inode *inode, const char *name,
+				   const void *value, size_t size, int flags)
+{
+	if (strcmp(name, "") == 0)
+		return -EINVAL;
+
+	return ocfs2_xattr_set(inode, OCFS2_XATTR_INDEX_TRUSTED, name, value,
+			       size, flags);
+}
+
+struct xattr_handler ocfs2_xattr_trusted_handler = {
+	.prefix	= XATTR_TRUSTED_PREFIX,
+	.list	= ocfs2_xattr_trusted_list,
+	.get	= ocfs2_xattr_trusted_get,
+	.set	= ocfs2_xattr_trusted_set,
+};
+
+
+/*
+ * 'user' attributes support
+ */
+
+#define XATTR_USER_PREFIX "user."
+
+static size_t ocfs2_xattr_user_list(struct inode *inode, char *list,
+				    size_t list_size, const char *name,
+				    size_t name_len)
+{
+	const size_t prefix_len = sizeof(XATTR_USER_PREFIX) - 1;
+	const size_t total_len = prefix_len + name_len + 1;
+	struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+
+	if (osb->s_mount_opt & OCFS2_MOUNT_NOUSERXATTR)
+		return 0;
+
+	if (list && total_len <= list_size) {
+		memcpy(list, XATTR_USER_PREFIX, prefix_len);
+		memcpy(list + prefix_len, name, name_len);
+		list[prefix_len + name_len] = '\0';
+	}
+	return total_len;
+}
+
+static int ocfs2_xattr_user_get(struct inode *inode, const char *name,
+				void *buffer, size_t size)
+{
+	struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+
+	if (strcmp(name, "") == 0)
+		return -EINVAL;
+	if (osb->s_mount_opt & OCFS2_MOUNT_NOUSERXATTR)
+		return -EOPNOTSUPP;
+	return ocfs2_xattr_get(inode, OCFS2_XATTR_INDEX_USER, name,
+			       buffer, size);
+}
+
+static int ocfs2_xattr_user_set(struct inode *inode, const char *name,
+				const void *value, size_t size, int flags)
+{
+	struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+
+	if (strcmp(name, "") == 0)
+		return -EINVAL;
+	if (osb->s_mount_opt & OCFS2_MOUNT_NOUSERXATTR)
+		return -EOPNOTSUPP;
+
+	return ocfs2_xattr_set(inode, OCFS2_XATTR_INDEX_USER, name, value,
+			       size, flags);
+}
+
+struct xattr_handler ocfs2_xattr_user_handler = {
+	.prefix	= XATTR_USER_PREFIX,
+	.list	= ocfs2_xattr_user_list,
+	.get	= ocfs2_xattr_user_get,
+	.set	= ocfs2_xattr_user_set,
+};
diff --git a/fs/ocfs2/xattr.h b/fs/ocfs2/xattr.h
new file mode 100644
index 0000000..c25c7c6
--- /dev/null
+++ b/fs/ocfs2/xattr.h
@@ -0,0 +1,68 @@
+/* -*- mode: c; c-basic-offset: 8; -*-
+ * vim: noexpandtab sw=8 ts=8 sts=0:
+ *
+ * xattr.h
+ *
+ * Function prototypes
+ *
+ * Copyright (C) 2008 Oracle.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 021110-1307, USA.
+ */
+
+#ifndef OCFS2_XATTR_H
+#define OCFS2_XATTR_H
+
+#include <linux/init.h>
+#include <linux/xattr.h>
+
+enum ocfs2_xattr_type {
+	OCFS2_XATTR_INDEX_USER = 1,
+	OCFS2_XATTR_INDEX_POSIX_ACL_ACCESS,
+	OCFS2_XATTR_INDEX_POSIX_ACL_DEFAULT,
+	OCFS2_XATTR_INDEX_TRUSTED,
+	OCFS2_XATTR_INDEX_SECURITY,
+	OCFS2_XATTR_MAX
+};
+
+extern struct xattr_handler ocfs2_xattr_user_handler;
+extern struct xattr_handler ocfs2_xattr_trusted_handler;
+
+extern ssize_t ocfs2_listxattr(struct dentry *, char *, size_t);
+extern int ocfs2_xattr_get(struct inode *, int, const char *, void *, size_t);
+extern int ocfs2_xattr_set(struct inode *, int, const char *, const void *,
+			   size_t, int);
+extern int ocfs2_xattr_remove(struct inode *inode, struct buffer_head *di_bh);
+extern struct xattr_handler *ocfs2_xattr_handlers[];
+
+static inline u16 ocfs2_xattr_buckets_per_cluster(struct ocfs2_super *osb)
+{
+	return (1 << osb->s_clustersize_bits) / OCFS2_XATTR_BUCKET_SIZE;
+}
+
+static inline u16 ocfs2_blocks_per_xattr_bucket(struct super_block *sb)
+{
+	return OCFS2_XATTR_BUCKET_SIZE / (1 << sb->s_blocksize_bits);
+}
+
+static inline u16 ocfs2_xattr_max_xe_in_bucket(struct super_block *sb)
+{
+	u16 len = sb->s_blocksize -
+		 offsetof(struct ocfs2_xattr_header, xh_entries);
+
+	return len / sizeof(struct ocfs2_xattr_entry);
+}
+#endif /* OCFS2_XATTR_H */
diff --git a/fs/omfs/inode.c b/fs/omfs/inode.c
index d29047b..cbf047a 100644
--- a/fs/omfs/inode.c
+++ b/fs/omfs/inode.c
@@ -346,7 +346,7 @@
 	Opt_uid, Opt_gid, Opt_umask, Opt_dmask, Opt_fmask
 };
 
-static match_table_t tokens = {
+static const match_table_t tokens = {
 	{Opt_uid, "uid=%u"},
 	{Opt_gid, "gid=%u"},
 	{Opt_umask, "umask=%o"},
diff --git a/fs/open.c b/fs/open.c
index 07da935..5596049 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -1141,8 +1141,7 @@
 asmlinkage long sys_vhangup(void)
 {
 	if (capable(CAP_SYS_TTY_CONFIG)) {
-		/* XXX: this needs locking */
-		tty_vhangup(current->signal->tty);
+		tty_vhangup_self();
 		return 0;
 	}
 	return -EPERM;
diff --git a/fs/partitions/check.c b/fs/partitions/check.c
index ecc3330..7408227 100644
--- a/fs/partitions/check.c
+++ b/fs/partitions/check.c
@@ -120,22 +120,21 @@
  * a pointer to that same buffer (for convenience).
  */
 
-char *disk_name(struct gendisk *hd, int part, char *buf)
+char *disk_name(struct gendisk *hd, int partno, char *buf)
 {
-	if (!part)
+	if (!partno)
 		snprintf(buf, BDEVNAME_SIZE, "%s", hd->disk_name);
 	else if (isdigit(hd->disk_name[strlen(hd->disk_name)-1]))
-		snprintf(buf, BDEVNAME_SIZE, "%sp%d", hd->disk_name, part);
+		snprintf(buf, BDEVNAME_SIZE, "%sp%d", hd->disk_name, partno);
 	else
-		snprintf(buf, BDEVNAME_SIZE, "%s%d", hd->disk_name, part);
+		snprintf(buf, BDEVNAME_SIZE, "%s%d", hd->disk_name, partno);
 
 	return buf;
 }
 
 const char *bdevname(struct block_device *bdev, char *buf)
 {
-	int part = MINOR(bdev->bd_dev) - bdev->bd_disk->first_minor;
-	return disk_name(bdev->bd_disk, part, buf);
+	return disk_name(bdev->bd_disk, bdev->bd_part->partno, buf);
 }
 
 EXPORT_SYMBOL(bdevname);
@@ -169,7 +168,7 @@
 	if (isdigit(state->name[strlen(state->name)-1]))
 		sprintf(state->name, "p");
 
-	state->limit = hd->minors;
+	state->limit = disk_max_parts(hd);
 	i = res = err = 0;
 	while (!res && check_part[i]) {
 		memset(&state->parts, 0, sizeof(state->parts));
@@ -204,21 +203,22 @@
 	return sprintf(buf, "%llu\n",(unsigned long long)p->start_sect);
 }
 
-static ssize_t part_size_show(struct device *dev,
-			      struct device_attribute *attr, char *buf)
+ssize_t part_size_show(struct device *dev,
+		       struct device_attribute *attr, char *buf)
 {
 	struct hd_struct *p = dev_to_part(dev);
 	return sprintf(buf, "%llu\n",(unsigned long long)p->nr_sects);
 }
 
-static ssize_t part_stat_show(struct device *dev,
-			      struct device_attribute *attr, char *buf)
+ssize_t part_stat_show(struct device *dev,
+		       struct device_attribute *attr, char *buf)
 {
 	struct hd_struct *p = dev_to_part(dev);
+	int cpu;
 
-	preempt_disable();
-	part_round_stats(p);
-	preempt_enable();
+	cpu = part_stat_lock();
+	part_round_stats(cpu, p);
+	part_stat_unlock();
 	return sprintf(buf,
 		"%8lu %8lu %8llu %8u "
 		"%8lu %8lu %8llu %8u "
@@ -238,17 +238,17 @@
 }
 
 #ifdef CONFIG_FAIL_MAKE_REQUEST
-static ssize_t part_fail_show(struct device *dev,
-			      struct device_attribute *attr, char *buf)
+ssize_t part_fail_show(struct device *dev,
+		       struct device_attribute *attr, char *buf)
 {
 	struct hd_struct *p = dev_to_part(dev);
 
 	return sprintf(buf, "%d\n", p->make_it_fail);
 }
 
-static ssize_t part_fail_store(struct device *dev,
-			       struct device_attribute *attr,
-			       const char *buf, size_t count)
+ssize_t part_fail_store(struct device *dev,
+			struct device_attribute *attr,
+			const char *buf, size_t count)
 {
 	struct hd_struct *p = dev_to_part(dev);
 	int i;
@@ -300,40 +300,34 @@
 	.release	= part_release,
 };
 
-static inline void partition_sysfs_add_subdir(struct hd_struct *p)
+static void delete_partition_rcu_cb(struct rcu_head *head)
 {
-	struct kobject *k;
+	struct hd_struct *part = container_of(head, struct hd_struct, rcu_head);
 
-	k = kobject_get(&p->dev.kobj);
-	p->holder_dir = kobject_create_and_add("holders", k);
-	kobject_put(k);
+	part->start_sect = 0;
+	part->nr_sects = 0;
+	part_stat_set_all(part, 0);
+	put_device(part_to_dev(part));
 }
 
-static inline void disk_sysfs_add_subdirs(struct gendisk *disk)
+void delete_partition(struct gendisk *disk, int partno)
 {
-	struct kobject *k;
+	struct disk_part_tbl *ptbl = disk->part_tbl;
+	struct hd_struct *part;
 
-	k = kobject_get(&disk->dev.kobj);
-	disk->holder_dir = kobject_create_and_add("holders", k);
-	disk->slave_dir = kobject_create_and_add("slaves", k);
-	kobject_put(k);
-}
-
-void delete_partition(struct gendisk *disk, int part)
-{
-	struct hd_struct *p = disk->part[part-1];
-
-	if (!p)
+	if (partno >= ptbl->len)
 		return;
-	if (!p->nr_sects)
+
+	part = ptbl->part[partno];
+	if (!part)
 		return;
-	disk->part[part-1] = NULL;
-	p->start_sect = 0;
-	p->nr_sects = 0;
-	part_stat_set_all(p, 0);
-	kobject_put(p->holder_dir);
-	device_del(&p->dev);
-	put_device(&p->dev);
+
+	blk_free_devt(part_devt(part));
+	rcu_assign_pointer(ptbl->part[partno], NULL);
+	kobject_put(part->holder_dir);
+	device_del(part_to_dev(part));
+
+	call_rcu(&part->rcu_head, delete_partition_rcu_cb);
 }
 
 static ssize_t whole_disk_show(struct device *dev,
@@ -344,102 +338,132 @@
 static DEVICE_ATTR(whole_disk, S_IRUSR | S_IRGRP | S_IROTH,
 		   whole_disk_show, NULL);
 
-int add_partition(struct gendisk *disk, int part, sector_t start, sector_t len, int flags)
+int add_partition(struct gendisk *disk, int partno,
+		  sector_t start, sector_t len, int flags)
 {
 	struct hd_struct *p;
+	dev_t devt = MKDEV(0, 0);
+	struct device *ddev = disk_to_dev(disk);
+	struct device *pdev;
+	struct disk_part_tbl *ptbl;
+	const char *dname;
 	int err;
 
+	err = disk_expand_part_tbl(disk, partno);
+	if (err)
+		return err;
+	ptbl = disk->part_tbl;
+
+	if (ptbl->part[partno])
+		return -EBUSY;
+
 	p = kzalloc(sizeof(*p), GFP_KERNEL);
 	if (!p)
 		return -ENOMEM;
 
 	if (!init_part_stats(p)) {
 		err = -ENOMEM;
-		goto out0;
+		goto out_free;
 	}
+	pdev = part_to_dev(p);
+
 	p->start_sect = start;
 	p->nr_sects = len;
-	p->partno = part;
-	p->policy = disk->policy;
+	p->partno = partno;
+	p->policy = get_disk_ro(disk);
 
-	if (isdigit(disk->dev.bus_id[strlen(disk->dev.bus_id)-1]))
-		snprintf(p->dev.bus_id, BUS_ID_SIZE,
-		"%sp%d", disk->dev.bus_id, part);
+	dname = dev_name(ddev);
+	if (isdigit(dname[strlen(dname) - 1]))
+		snprintf(pdev->bus_id, BUS_ID_SIZE, "%sp%d", dname, partno);
 	else
-		snprintf(p->dev.bus_id, BUS_ID_SIZE,
-			 "%s%d", disk->dev.bus_id, part);
+		snprintf(pdev->bus_id, BUS_ID_SIZE, "%s%d", dname, partno);
 
-	device_initialize(&p->dev);
-	p->dev.devt = MKDEV(disk->major, disk->first_minor + part);
-	p->dev.class = &block_class;
-	p->dev.type = &part_type;
-	p->dev.parent = &disk->dev;
-	disk->part[part-1] = p;
+	device_initialize(pdev);
+	pdev->class = &block_class;
+	pdev->type = &part_type;
+	pdev->parent = ddev;
+
+	err = blk_alloc_devt(p, &devt);
+	if (err)
+		goto out_free;
+	pdev->devt = devt;
 
 	/* delay uevent until 'holders' subdir is created */
-	p->dev.uevent_suppress = 1;
-	err = device_add(&p->dev);
+	pdev->uevent_suppress = 1;
+	err = device_add(pdev);
 	if (err)
-		goto out1;
-	partition_sysfs_add_subdir(p);
-	p->dev.uevent_suppress = 0;
+		goto out_put;
+
+	err = -ENOMEM;
+	p->holder_dir = kobject_create_and_add("holders", &pdev->kobj);
+	if (!p->holder_dir)
+		goto out_del;
+
+	pdev->uevent_suppress = 0;
 	if (flags & ADDPART_FLAG_WHOLEDISK) {
-		err = device_create_file(&p->dev, &dev_attr_whole_disk);
+		err = device_create_file(pdev, &dev_attr_whole_disk);
 		if (err)
-			goto out2;
+			goto out_del;
 	}
 
+	/* everything is up and running, commence */
+	INIT_RCU_HEAD(&p->rcu_head);
+	rcu_assign_pointer(ptbl->part[partno], p);
+
 	/* suppress uevent if the disk supresses it */
-	if (!disk->dev.uevent_suppress)
-		kobject_uevent(&p->dev.kobj, KOBJ_ADD);
+	if (!ddev->uevent_suppress)
+		kobject_uevent(&pdev->kobj, KOBJ_ADD);
 
 	return 0;
 
-out2:
-	device_del(&p->dev);
-out1:
-	put_device(&p->dev);
-	free_part_stats(p);
-out0:
+out_free:
 	kfree(p);
 	return err;
+out_del:
+	kobject_put(p->holder_dir);
+	device_del(pdev);
+out_put:
+	put_device(pdev);
+	blk_free_devt(devt);
+	return err;
 }
 
 /* Not exported, helper to add_disk(). */
 void register_disk(struct gendisk *disk)
 {
+	struct device *ddev = disk_to_dev(disk);
 	struct block_device *bdev;
+	struct disk_part_iter piter;
+	struct hd_struct *part;
 	char *s;
-	int i;
-	struct hd_struct *p;
 	int err;
 
-	disk->dev.parent = disk->driverfs_dev;
-	disk->dev.devt = MKDEV(disk->major, disk->first_minor);
+	ddev->parent = disk->driverfs_dev;
 
-	strlcpy(disk->dev.bus_id, disk->disk_name, BUS_ID_SIZE);
+	strlcpy(ddev->bus_id, disk->disk_name, BUS_ID_SIZE);
 	/* ewww... some of these buggers have / in the name... */
-	s = strchr(disk->dev.bus_id, '/');
+	s = strchr(ddev->bus_id, '/');
 	if (s)
 		*s = '!';
 
 	/* delay uevents, until we scanned partition table */
-	disk->dev.uevent_suppress = 1;
+	ddev->uevent_suppress = 1;
 
-	if (device_add(&disk->dev))
+	if (device_add(ddev))
 		return;
 #ifndef CONFIG_SYSFS_DEPRECATED
-	err = sysfs_create_link(block_depr, &disk->dev.kobj,
-				kobject_name(&disk->dev.kobj));
+	err = sysfs_create_link(block_depr, &ddev->kobj,
+				kobject_name(&ddev->kobj));
 	if (err) {
-		device_del(&disk->dev);
+		device_del(ddev);
 		return;
 	}
 #endif
-	disk_sysfs_add_subdirs(disk);
+	disk->part0.holder_dir = kobject_create_and_add("holders", &ddev->kobj);
+	disk->slave_dir = kobject_create_and_add("slaves", &ddev->kobj);
 
 	/* No minors to use for partitions */
-	if (disk->minors == 1)
+	if (!disk_partitionable(disk))
 		goto exit;
 
 	/* No such device (e.g., media were just removed) */
@@ -458,41 +482,57 @@
 
 exit:
 	/* announce disk after possible partitions are created */
-	disk->dev.uevent_suppress = 0;
-	kobject_uevent(&disk->dev.kobj, KOBJ_ADD);
+	ddev->uevent_suppress = 0;
+	kobject_uevent(&ddev->kobj, KOBJ_ADD);
 
 	/* announce possible partitions */
-	for (i = 1; i < disk->minors; i++) {
-		p = disk->part[i-1];
-		if (!p || !p->nr_sects)
-			continue;
-		kobject_uevent(&p->dev.kobj, KOBJ_ADD);
-	}
+	disk_part_iter_init(&piter, disk, 0);
+	while ((part = disk_part_iter_next(&piter)))
+		kobject_uevent(&part_to_dev(part)->kobj, KOBJ_ADD);
+	disk_part_iter_exit(&piter);
 }
 
 int rescan_partitions(struct gendisk *disk, struct block_device *bdev)
 {
+	struct disk_part_iter piter;
+	struct hd_struct *part;
 	struct parsed_partitions *state;
-	int p, res;
+	int p, highest, res;
 
 	if (bdev->bd_part_count)
 		return -EBUSY;
 	res = invalidate_partition(disk, 0);
 	if (res)
 		return res;
-	bdev->bd_invalidated = 0;
-	for (p = 1; p < disk->minors; p++)
-		delete_partition(disk, p);
+
+	disk_part_iter_init(&piter, disk, DISK_PITER_INCL_EMPTY);
+	while ((part = disk_part_iter_next(&piter)))
+		delete_partition(disk, part->partno);
+	disk_part_iter_exit(&piter);
+
 	if (disk->fops->revalidate_disk)
 		disk->fops->revalidate_disk(disk);
+	check_disk_size_change(disk, bdev);
+	bdev->bd_invalidated = 0;
 	if (!get_capacity(disk) || !(state = check_partition(disk, bdev)))
 		return 0;
 	if (IS_ERR(state))	/* I/O error reading the partition table */
 		return -EIO;
 
 	/* tell userspace that the media / partition table may have changed */
-	kobject_uevent(&disk->dev.kobj, KOBJ_CHANGE);
+	kobject_uevent(&disk_to_dev(disk)->kobj, KOBJ_CHANGE);
 
+	/* Detect the highest partition number and preallocate
+	 * disk->part_tbl.  This is an optimization and not strictly
+	 * necessary.
+	 */
+	for (p = 1, highest = 0; p < state->limit; p++)
+		if (state->parts[p].size)
+			highest = p;
+
+	disk_expand_part_tbl(disk, highest);
+
+	/* add partitions */
 	for (p = 1; p < state->limit; p++) {
 		sector_t size = state->parts[p].size;
 		sector_t from = state->parts[p].from;
@@ -541,25 +581,31 @@
 
 void del_gendisk(struct gendisk *disk)
 {
-	int p;
+	struct disk_part_iter piter;
+	struct hd_struct *part;
 
 	/* invalidate stuff */
-	for (p = disk->minors - 1; p > 0; p--) {
-		invalidate_partition(disk, p);
-		delete_partition(disk, p);
+	disk_part_iter_init(&piter, disk,
+			     DISK_PITER_INCL_EMPTY | DISK_PITER_REVERSE);
+	while ((part = disk_part_iter_next(&piter))) {
+		invalidate_partition(disk, part->partno);
+		delete_partition(disk, part->partno);
 	}
+	disk_part_iter_exit(&piter);
+
 	invalidate_partition(disk, 0);
-	disk->capacity = 0;
+	blk_free_devt(disk_to_dev(disk)->devt);
+	set_capacity(disk, 0);
 	disk->flags &= ~GENHD_FL_UP;
 	unlink_gendisk(disk);
-	disk_stat_set_all(disk, 0);
-	disk->stamp = 0;
+	part_stat_set_all(&disk->part0, 0);
+	disk->part0.stamp = 0;
 
-	kobject_put(disk->holder_dir);
+	kobject_put(disk->part0.holder_dir);
 	kobject_put(disk->slave_dir);
 	disk->driverfs_dev = NULL;
 #ifndef CONFIG_SYSFS_DEPRECATED
-	sysfs_remove_link(block_depr, disk->dev.bus_id);
+	sysfs_remove_link(block_depr, dev_name(disk_to_dev(disk)));
 #endif
-	device_del(&disk->dev);
+	device_del(disk_to_dev(disk));
 }
diff --git a/fs/partitions/check.h b/fs/partitions/check.h
index 17ae8ec..98dbe1a 100644
--- a/fs/partitions/check.h
+++ b/fs/partitions/check.h
@@ -5,15 +5,13 @@
  * add_gd_partition adds a partitions details to the devices partition
  * description.
  */
-enum { MAX_PART = 256 };
-
 struct parsed_partitions {
 	char name[BDEVNAME_SIZE];
 	struct {
 		sector_t from;
 		sector_t size;
 		int flags;
-	} parts[MAX_PART];
+	} parts[DISK_MAX_PARTS];
 	int next;
 	int limit;
 };
diff --git a/fs/proc/Kconfig b/fs/proc/Kconfig
index 73cd7a4..50f8f06 100644
--- a/fs/proc/Kconfig
+++ b/fs/proc/Kconfig
@@ -57,3 +57,13 @@
 	  As it is generally a good thing, you should say Y here unless
 	  building a kernel for install/rescue disks or your system is very
 	  limited in memory.
+
+config PROC_PAGE_MONITOR
+ 	default y
+	depends on PROC_FS && MMU
+	bool "Enable /proc page monitoring" if EMBEDDED
+ 	help
+	  Various /proc files exist to monitor process memory utilization:
+	  /proc/pid/smaps, /proc/pid/clear_refs, /proc/pid/pagemap,
+	  /proc/kpagecount, and /proc/kpageflags. Disabling these
+          interfaces will reduce the size of the kernel by approximately 4kb.
diff --git a/fs/proc/array.c b/fs/proc/array.c
index 71c9be5..f4bc0e7 100644
--- a/fs/proc/array.c
+++ b/fs/proc/array.c
@@ -86,11 +86,6 @@
 #include <asm/processor.h>
 #include "internal.h"
 
-/* Gcc optimizes away "strlen(x)" for constant x */
-#define ADDBUF(buffer, string) \
-do { memcpy(buffer, string, strlen(string)); \
-     buffer += strlen(string); } while (0)
-
 static inline void task_name(struct seq_file *m, struct task_struct *p)
 {
 	int i;
@@ -261,7 +256,6 @@
 	sigemptyset(&ignored);
 	sigemptyset(&caught);
 
-	rcu_read_lock();
 	if (lock_task_sighand(p, &flags)) {
 		pending = p->pending.signal;
 		shpending = p->signal->shared_pending.signal;
@@ -272,7 +266,6 @@
 		qlim = p->signal->rlim[RLIMIT_SIGPENDING].rlim_cur;
 		unlock_task_sighand(p, &flags);
 	}
-	rcu_read_unlock();
 
 	seq_printf(m, "Threads:\t%d\n", num_threads);
 	seq_printf(m, "SigQ:\t%lu/%lu\n", qsize, qlim);
diff --git a/fs/proc/base.c b/fs/proc/base.c
index a28840b..b5918ae 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -148,9 +148,6 @@
 	return count;
 }
 
-int maps_protect;
-EXPORT_SYMBOL(maps_protect);
-
 static struct fs_struct *get_fs_struct(struct task_struct *task)
 {
 	struct fs_struct *fs;
@@ -164,7 +161,6 @@
 
 static int get_nr_threads(struct task_struct *tsk)
 {
-	/* Must be called with the rcu_read_lock held */
 	unsigned long flags;
 	int count = 0;
 
@@ -471,14 +467,10 @@
 
 	struct rlimit rlim[RLIM_NLIMITS];
 
-	rcu_read_lock();
-	if (!lock_task_sighand(task,&flags)) {
-		rcu_read_unlock();
+	if (!lock_task_sighand(task, &flags))
 		return 0;
-	}
 	memcpy(rlim, task->signal->rlim, sizeof(struct rlimit) * RLIM_NLIMITS);
 	unlock_task_sighand(task, &flags);
-	rcu_read_unlock();
 
 	/*
 	 * print the file header
@@ -2443,6 +2435,13 @@
 }
 #endif /* CONFIG_TASK_IO_ACCOUNTING */
 
+static int proc_pid_personality(struct seq_file *m, struct pid_namespace *ns,
+				struct pid *pid, struct task_struct *task)
+{
+	seq_printf(m, "%08x\n", task->personality);
+	return 0;
+}
+
 /*
  * Thread groups
  */
@@ -2459,6 +2458,7 @@
 	REG("environ",    S_IRUSR, environ),
 	INF("auxv",       S_IRUSR, pid_auxv),
 	ONE("status",     S_IRUGO, pid_status),
+	ONE("personality", S_IRUSR, pid_personality),
 	INF("limits",	  S_IRUSR, pid_limits),
 #ifdef CONFIG_SCHED_DEBUG
 	REG("sched",      S_IRUGO|S_IWUSR, pid_sched),
@@ -2794,6 +2794,7 @@
 	REG("environ",   S_IRUSR, environ),
 	INF("auxv",      S_IRUSR, pid_auxv),
 	ONE("status",    S_IRUGO, pid_status),
+	ONE("personality", S_IRUSR, pid_personality),
 	INF("limits",	 S_IRUSR, pid_limits),
 #ifdef CONFIG_SCHED_DEBUG
 	REG("sched",     S_IRUGO|S_IWUSR, pid_sched),
@@ -3088,9 +3089,7 @@
 	generic_fillattr(inode, stat);
 
 	if (p) {
-		rcu_read_lock();
 		stat->nlink += get_nr_threads(p);
-		rcu_read_unlock();
 		put_task_struct(p);
 	}
 
diff --git a/fs/proc/inode.c b/fs/proc/inode.c
index 8bb03f0..c6b4fa7 100644
--- a/fs/proc/inode.c
+++ b/fs/proc/inode.c
@@ -342,7 +342,7 @@
 	if (!pde->proc_fops) {
 		spin_unlock(&pde->pde_unload_lock);
 		kfree(pdeo);
-		return rv;
+		return -EINVAL;
 	}
 	pde->pde_users++;
 	open = pde->proc_fops->open;
diff --git a/fs/proc/internal.h b/fs/proc/internal.h
index 4422023..3bfb7b8 100644
--- a/fs/proc/internal.h
+++ b/fs/proc/internal.h
@@ -45,8 +45,6 @@
 extern int nommu_vma_show(struct seq_file *, struct vm_area_struct *);
 #endif
 
-extern int maps_protect;
-
 extern int proc_tid_stat(struct seq_file *m, struct pid_namespace *ns,
 				struct pid *pid, struct task_struct *task);
 extern int proc_tgid_stat(struct seq_file *m, struct pid_namespace *ns,
diff --git a/fs/proc/proc_misc.c b/fs/proc/proc_misc.c
index 29e20c6..b675a49 100644
--- a/fs/proc/proc_misc.c
+++ b/fs/proc/proc_misc.c
@@ -68,7 +68,6 @@
 extern int get_hardware_list(char *);
 extern int get_stram_list(char *);
 extern int get_exec_domain_list(char *);
-extern int get_dma_list(char *);
 
 static int proc_calc_metrics(char *page, char **start, off_t off,
 				 int count, int *eof, int len)
@@ -684,6 +683,7 @@
 	return proc_calc_metrics(page, start, off, count, eof, len);
 }
 
+#ifdef CONFIG_FILE_LOCKING
 static int locks_open(struct inode *inode, struct file *filp)
 {
 	return seq_open(filp, &locks_seq_operations);
@@ -695,6 +695,7 @@
 	.llseek		= seq_lseek,
 	.release	= seq_release,
 };
+#endif /* CONFIG_FILE_LOCKING */
 
 static int execdomains_read_proc(char *page, char **start, off_t off,
 				 int count, int *eof, void *data)
@@ -888,7 +889,9 @@
 #ifdef CONFIG_PRINTK
 	proc_create("kmsg", S_IRUSR, NULL, &proc_kmsg_operations);
 #endif
+#ifdef CONFIG_FILE_LOCKING
 	proc_create("locks", 0, NULL, &proc_locks_operations);
+#endif
 	proc_create("devices", 0, NULL, &proc_devinfo_operations);
 	proc_create("cpuinfo", 0, NULL, &proc_cpuinfo_operations);
 #ifdef CONFIG_BLOCK
diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c
index f9a8b89..945a810 100644
--- a/fs/proc/proc_sysctl.c
+++ b/fs/proc/proc_sysctl.c
@@ -66,7 +66,7 @@
 	return NULL;
 }
 
-struct ctl_table_header *grab_header(struct inode *inode)
+static struct ctl_table_header *grab_header(struct inode *inode)
 {
 	if (PROC_I(inode)->sysctl)
 		return sysctl_head_grab(PROC_I(inode)->sysctl);
@@ -395,10 +395,10 @@
 	.d_compare	= proc_sys_compare,
 };
 
-static struct proc_dir_entry *proc_sys_root;
-
 int proc_sys_init(void)
 {
+	struct proc_dir_entry *proc_sys_root;
+
 	proc_sys_root = proc_mkdir("sys", NULL);
 	proc_sys_root->proc_iops = &proc_sys_dir_operations;
 	proc_sys_root->proc_fops = &proc_sys_dir_file_operations;
diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c
index 73d1891..4806830 100644
--- a/fs/proc/task_mmu.c
+++ b/fs/proc/task_mmu.c
@@ -210,9 +210,6 @@
 	dev_t dev = 0;
 	int len;
 
-	if (maps_protect && !ptrace_may_access(task, PTRACE_MODE_READ))
-		return -EACCES;
-
 	if (file) {
 		struct inode *inode = vma->vm_file->f_path.dentry->d_inode;
 		dev = inode->i_sb->s_dev;
@@ -742,22 +739,11 @@
 #ifdef CONFIG_NUMA
 extern int show_numa_map(struct seq_file *m, void *v);
 
-static int show_numa_map_checked(struct seq_file *m, void *v)
-{
-	struct proc_maps_private *priv = m->private;
-	struct task_struct *task = priv->task;
-
-	if (maps_protect && !ptrace_may_access(task, PTRACE_MODE_READ))
-		return -EACCES;
-
-	return show_numa_map(m, v);
-}
-
 static const struct seq_operations proc_pid_numa_maps_op = {
         .start  = m_start,
         .next   = m_next,
         .stop   = m_stop,
-        .show   = show_numa_map_checked
+        .show   = show_numa_map,
 };
 
 static int numa_maps_open(struct inode *inode, struct file *file)
diff --git a/fs/proc/task_nommu.c b/fs/proc/task_nommu.c
index 5d84e71..219bd79 100644
--- a/fs/proc/task_nommu.c
+++ b/fs/proc/task_nommu.c
@@ -110,11 +110,6 @@
 static int show_map(struct seq_file *m, void *_vml)
 {
 	struct vm_list_struct *vml = _vml;
-	struct proc_maps_private *priv = m->private;
-	struct task_struct *task = priv->task;
-
-	if (maps_protect && !ptrace_may_access(task, PTRACE_MODE_READ))
-		return -EACCES;
 
 	return nommu_vma_show(m, vml->vma);
 }
diff --git a/fs/proc/vmcore.c b/fs/proc/vmcore.c
index 9ac0f5e..841368b 100644
--- a/fs/proc/vmcore.c
+++ b/fs/proc/vmcore.c
@@ -165,14 +165,8 @@
 	return acc;
 }
 
-static int open_vmcore(struct inode *inode, struct file *filp)
-{
-	return 0;
-}
-
 const struct file_operations proc_vmcore_operations = {
 	.read		= read_vmcore,
-	.open		= open_vmcore,
 };
 
 static struct vmcore* __init get_new_element(void)
diff --git a/fs/ramfs/file-nommu.c b/fs/ramfs/file-nommu.c
index 52312ec..5145cb9 100644
--- a/fs/ramfs/file-nommu.c
+++ b/fs/ramfs/file-nommu.c
@@ -58,7 +58,7 @@
  * size 0 on the assumption that it's going to be used for an mmap of shared
  * memory
  */
-static int ramfs_nommu_expand_for_mapping(struct inode *inode, size_t newsize)
+int ramfs_nommu_expand_for_mapping(struct inode *inode, size_t newsize)
 {
 	struct pagevec lru_pvec;
 	unsigned long npages, xpages, loop, limit;
diff --git a/fs/splice.c b/fs/splice.c
index 1bbc6f4..a1e701c 100644
--- a/fs/splice.c
+++ b/fs/splice.c
@@ -898,6 +898,9 @@
 	if (unlikely(!(out->f_mode & FMODE_WRITE)))
 		return -EBADF;
 
+	if (unlikely(out->f_flags & O_APPEND))
+		return -EINVAL;
+
 	ret = rw_verify_area(WRITE, out, ppos, len);
 	if (unlikely(ret < 0))
 		return ret;
diff --git a/fs/ubifs/debug.c b/fs/ubifs/debug.c
index b9cb774..d7f7645 100644
--- a/fs/ubifs/debug.c
+++ b/fs/ubifs/debug.c
@@ -538,7 +538,7 @@
 		printk(KERN_DEBUG "\t%d orphan inode numbers:\n", n);
 		for (i = 0; i < n; i++)
 			printk(KERN_DEBUG "\t  ino %llu\n",
-			       le64_to_cpu(orph->inos[i]));
+			       (unsigned long long)le64_to_cpu(orph->inos[i]));
 		break;
 	}
 	default:
diff --git a/fs/ubifs/dir.c b/fs/ubifs/dir.c
index 2b267c9..526c01e 100644
--- a/fs/ubifs/dir.c
+++ b/fs/ubifs/dir.c
@@ -426,7 +426,7 @@
 
 	while (1) {
 		dbg_gen("feed '%s', ino %llu, new f_pos %#x",
-			dent->name, le64_to_cpu(dent->inum),
+			dent->name, (unsigned long long)le64_to_cpu(dent->inum),
 			key_hash_flash(c, &dent->key));
 		ubifs_assert(dent->ch.sqnum > ubifs_inode(dir)->creat_sqnum);
 
diff --git a/fs/ubifs/find.c b/fs/ubifs/find.c
index e045c8b..47814cd 100644
--- a/fs/ubifs/find.c
+++ b/fs/ubifs/find.c
@@ -507,7 +507,6 @@
 		rsvd_idx_lebs = 0;
 	lebs = c->lst.empty_lebs + c->freeable_cnt + c->idx_gc_cnt -
 	       c->lst.taken_empty_lebs;
-	ubifs_assert(lebs + c->lst.idx_lebs >= c->min_idx_lebs);
 	if (rsvd_idx_lebs < lebs)
 		/*
 		 * OK to allocate an empty LEB, but we still don't want to go
diff --git a/fs/ubifs/gc.c b/fs/ubifs/gc.c
index 13f1019..02aba36 100644
--- a/fs/ubifs/gc.c
+++ b/fs/ubifs/gc.c
@@ -334,15 +334,15 @@
 
 		err = move_nodes(c, sleb);
 		if (err)
-			goto out;
+			goto out_inc_seq;
 
 		err = gc_sync_wbufs(c);
 		if (err)
-			goto out;
+			goto out_inc_seq;
 
 		err = ubifs_change_one_lp(c, lnum, c->leb_size, 0, 0, 0, 0);
 		if (err)
-			goto out;
+			goto out_inc_seq;
 
 		/* Allow for races with TNC */
 		c->gced_lnum = lnum;
@@ -369,6 +369,14 @@
 out:
 	ubifs_scan_destroy(sleb);
 	return err;
+
+out_inc_seq:
+	/* We may have moved at least some nodes so allow for races with TNC */
+	c->gced_lnum = lnum;
+	smp_wmb();
+	c->gc_seq += 1;
+	smp_wmb();
+	goto out;
 }
 
 /**
diff --git a/fs/ubifs/super.c b/fs/ubifs/super.c
index 7562464..9a92203 100644
--- a/fs/ubifs/super.c
+++ b/fs/ubifs/super.c
@@ -848,7 +848,7 @@
 	Opt_err,
 };
 
-static match_table_t tokens = {
+static const match_table_t tokens = {
 	{Opt_fast_unmount, "fast_unmount"},
 	{Opt_norm_unmount, "norm_unmount"},
 	{Opt_err, NULL},
@@ -1024,14 +1024,13 @@
 		goto out_dereg;
 	}
 
+	sprintf(c->bgt_name, BGT_NAME_PATTERN, c->vi.ubi_num, c->vi.vol_id);
 	if (!mounted_read_only) {
 		err = alloc_wbufs(c);
 		if (err)
 			goto out_cbuf;
 
 		/* Create background thread */
-		sprintf(c->bgt_name, BGT_NAME_PATTERN, c->vi.ubi_num,
-			c->vi.vol_id);
 		c->bgt = kthread_create(ubifs_bg_thread, c, c->bgt_name);
 		if (!c->bgt)
 			c->bgt = ERR_PTR(-EINVAL);
diff --git a/fs/ubifs/tnc.c b/fs/ubifs/tnc.c
index 7da209a..7634c59 100644
--- a/fs/ubifs/tnc.c
+++ b/fs/ubifs/tnc.c
@@ -1476,7 +1476,7 @@
 	}
 
 	err = fallible_read_node(c, key, &zbr, node);
-	if (maybe_leb_gced(c, zbr.lnum, gc_seq1)) {
+	if (err <= 0 || maybe_leb_gced(c, zbr.lnum, gc_seq1)) {
 		/*
 		 * The node may have been GC'ed out from under us so try again
 		 * while keeping the TNC mutex locked.
diff --git a/fs/udf/super.c b/fs/udf/super.c
index 5698bbf..e25e701 100644
--- a/fs/udf/super.c
+++ b/fs/udf/super.c
@@ -369,7 +369,7 @@
 	Opt_err, Opt_uforget, Opt_uignore, Opt_gforget, Opt_gignore
 };
 
-static match_table_t tokens = {
+static const match_table_t tokens = {
 	{Opt_novrs,	"novrs"},
 	{Opt_nostrict,	"nostrict"},
 	{Opt_bs,	"bs=%u"},
diff --git a/fs/ufs/super.c b/fs/ufs/super.c
index 3141969..e65212d 100644
--- a/fs/ufs/super.c
+++ b/fs/ufs/super.c
@@ -309,7 +309,7 @@
        Opt_err
 };
 
-static match_table_t tokens = {
+static const match_table_t tokens = {
 	{Opt_type_old, "ufstype=old"},
 	{Opt_type_sunx86, "ufstype=sunx86"},
 	{Opt_type_sun, "ufstype=sun"},
@@ -1233,7 +1233,7 @@
 {
 	struct ufs_sb_info *sbi = UFS_SB(vfs->mnt_sb);
 	unsigned mval = sbi->s_mount_opt & UFS_MOUNT_UFSTYPE;
-	struct match_token *tp = tokens;
+	const struct match_token *tp = tokens;
 
 	while (tp->token != Opt_onerror_panic && tp->token != mval)
 		++tp;
diff --git a/fs/xfs/linux-2.6/xfs_aops.c b/fs/xfs/linux-2.6/xfs_aops.c
index f42f80a..a44d68e 100644
--- a/fs/xfs/linux-2.6/xfs_aops.c
+++ b/fs/xfs/linux-2.6/xfs_aops.c
@@ -1338,6 +1338,10 @@
 	offset = (xfs_off_t)iblock << inode->i_blkbits;
 	ASSERT(bh_result->b_size >= (1 << inode->i_blkbits));
 	size = bh_result->b_size;
+
+	if (!create && direct && offset >= i_size_read(inode))
+		return 0;
+
 	error = xfs_iomap(XFS_I(inode), offset, size,
 			     create ? flags : BMAPI_READ, &iomap, &niomap);
 	if (error)
diff --git a/fs/xfs/linux-2.6/xfs_buf.c b/fs/xfs/linux-2.6/xfs_buf.c
index 986061a..36d5fcd 100644
--- a/fs/xfs/linux-2.6/xfs_buf.c
+++ b/fs/xfs/linux-2.6/xfs_buf.c
@@ -1001,12 +1001,13 @@
 	 * We can get an EOPNOTSUPP to ordered writes.  Here we clear the
 	 * ordered flag and reissue them.  Because we can't tell the higher
 	 * layers directly that they should not issue ordered I/O anymore, they
-	 * need to check if the ordered flag was cleared during I/O completion.
+	 * need to check if the _XFS_BARRIER_FAILED flag was set during I/O completion.
 	 */
 	if ((bp->b_error == EOPNOTSUPP) &&
 	    (bp->b_flags & (XBF_ORDERED|XBF_ASYNC)) == (XBF_ORDERED|XBF_ASYNC)) {
 		XB_TRACE(bp, "ordered_retry", bp->b_iodone);
 		bp->b_flags &= ~XBF_ORDERED;
+		bp->b_flags |= _XFS_BARRIER_FAILED;
 		xfs_buf_iorequest(bp);
 	} else if (bp->b_iodone)
 		(*(bp->b_iodone))(bp);
diff --git a/fs/xfs/linux-2.6/xfs_buf.h b/fs/xfs/linux-2.6/xfs_buf.h
index fe01099..456519a 100644
--- a/fs/xfs/linux-2.6/xfs_buf.h
+++ b/fs/xfs/linux-2.6/xfs_buf.h
@@ -85,6 +85,14 @@
 	 * modifications being lost.
 	 */
 	_XBF_PAGE_LOCKED = (1 << 22),
+
+	/*
+	 * If we try a barrier write, but it fails we have to communicate
+	 * this to the upper layers.  Unfortunately b_error gets overwritten
+	 * when the buffer is re-issued so we have to add another flag to
+	 * keep this information.
+	 */
+	_XFS_BARRIER_FAILED = (1 << 23),
 } xfs_buf_flags_t;
 
 typedef enum {
diff --git a/fs/xfs/linux-2.6/xfs_super.c b/fs/xfs/linux-2.6/xfs_super.c
index 73c65f1..7227b2e 100644
--- a/fs/xfs/linux-2.6/xfs_super.c
+++ b/fs/xfs/linux-2.6/xfs_super.c
@@ -158,7 +158,7 @@
 	Opt_barrier, Opt_nobarrier, Opt_err
 };
 
-static match_table_t tokens = {
+static const match_table_t tokens = {
 	{Opt_barrier, "barrier"},
 	{Opt_nobarrier, "nobarrier"},
 	{Opt_err, NULL}
@@ -1302,9 +1302,29 @@
 			mp->m_flags &= ~XFS_MOUNT_BARRIER;
 			break;
 		default:
+			/*
+			 * Logically we would return an error here to prevent
+			 * users from believing they might have changed
+			 * mount options using remount which can't be changed.
+			 *
+			 * But unfortunately mount(8) adds all options from
+			 * mtab and fstab to the mount arguments in some cases
+			 * so we can't blindly reject options, but have to
+			 * check for each specified option if it actually
+			 * differs from the currently set option and only
+			 * reject it if that's the case.
+			 *
+			 * Until that is implemented we return success for
+			 * every remount request, and silently ignore all
+			 * options that we can't actually change.
+			 */
+#if 0
 			printk(KERN_INFO
 	"XFS: mount option \"%s\" not supported for remount\n", p);
 			return -EINVAL;
+#else
+			return 0;
+#endif
 		}
 	}
 
diff --git a/fs/xfs/xfs_buf_item.c b/fs/xfs/xfs_buf_item.c
index 608c30c..002fc26 100644
--- a/fs/xfs/xfs_buf_item.c
+++ b/fs/xfs/xfs_buf_item.c
@@ -732,6 +732,7 @@
 	bip->bli_item.li_ops = &xfs_buf_item_ops;
 	bip->bli_item.li_mountp = mp;
 	bip->bli_buf = bp;
+	xfs_buf_hold(bp);
 	bip->bli_format.blf_type = XFS_LI_BUF;
 	bip->bli_format.blf_blkno = (__int64_t)XFS_BUF_ADDR(bp);
 	bip->bli_format.blf_len = (ushort)BTOBB(XFS_BUF_COUNT(bp));
@@ -867,6 +868,21 @@
 	return (bip->bli_flags & XFS_BLI_DIRTY);
 }
 
+STATIC void
+xfs_buf_item_free(
+	xfs_buf_log_item_t	*bip)
+{
+#ifdef XFS_TRANS_DEBUG
+	kmem_free(bip->bli_orig);
+	kmem_free(bip->bli_logged);
+#endif /* XFS_TRANS_DEBUG */
+
+#ifdef XFS_BLI_TRACE
+	ktrace_free(bip->bli_trace);
+#endif
+	kmem_zone_free(xfs_buf_item_zone, bip);
+}
+
 /*
  * This is called when the buf log item is no longer needed.  It should
  * free the buf log item associated with the given buffer and clear
@@ -887,18 +903,8 @@
 	    (XFS_BUF_IODONE_FUNC(bp) != NULL)) {
 		XFS_BUF_CLR_IODONE_FUNC(bp);
 	}
-
-#ifdef XFS_TRANS_DEBUG
-	kmem_free(bip->bli_orig);
-	bip->bli_orig = NULL;
-	kmem_free(bip->bli_logged);
-	bip->bli_logged = NULL;
-#endif /* XFS_TRANS_DEBUG */
-
-#ifdef XFS_BLI_TRACE
-	ktrace_free(bip->bli_trace);
-#endif
-	kmem_zone_free(xfs_buf_item_zone, bip);
+	xfs_buf_rele(bp);
+	xfs_buf_item_free(bip);
 }
 
 
@@ -1120,6 +1126,7 @@
 
 	ASSERT(bip->bli_buf == bp);
 
+	xfs_buf_rele(bp);
 	mp = bip->bli_item.li_mountp;
 
 	/*
@@ -1136,18 +1143,7 @@
 	 * xfs_trans_delete_ail() drops the AIL lock.
 	 */
 	xfs_trans_delete_ail(mp, (xfs_log_item_t *)bip);
-
-#ifdef XFS_TRANS_DEBUG
-	kmem_free(bip->bli_orig);
-	bip->bli_orig = NULL;
-	kmem_free(bip->bli_logged);
-	bip->bli_logged = NULL;
-#endif /* XFS_TRANS_DEBUG */
-
-#ifdef XFS_BLI_TRACE
-	ktrace_free(bip->bli_trace);
-#endif
-	kmem_zone_free(xfs_buf_item_zone, bip);
+	xfs_buf_item_free(bip);
 }
 
 #if defined(XFS_BLI_TRACE)
diff --git a/fs/xfs/xfs_dfrag.c b/fs/xfs/xfs_dfrag.c
index 760f4c5..75b0cd4 100644
--- a/fs/xfs/xfs_dfrag.c
+++ b/fs/xfs/xfs_dfrag.c
@@ -149,7 +149,14 @@
 
 	sbp = &sxp->sx_stat;
 
-	xfs_lock_two_inodes(ip, tip, lock_flags);
+	/*
+	 * we have to do two separate lock calls here to keep lockdep
+	 * happy. If we try to get all the locks in one call, lock will
+	 * report false positives when we drop the ILOCK and regain them
+	 * below.
+	 */
+	xfs_lock_two_inodes(ip, tip, XFS_IOLOCK_EXCL);
+	xfs_lock_two_inodes(ip, tip, XFS_ILOCK_EXCL);
 	locked = 1;
 
 	/* Verify that both files have the same format */
diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
index 00e80df..dbd9cef 100644
--- a/fs/xfs/xfs_inode.c
+++ b/fs/xfs/xfs_inode.c
@@ -4118,7 +4118,7 @@
 	ASSERT(nextents <= XFS_LINEAR_EXTS);
 	size = nextents * sizeof(xfs_bmbt_rec_t);
 
-	xfs_iext_irec_compact_full(ifp);
+	xfs_iext_irec_compact_pages(ifp);
 	ASSERT(ifp->if_real_bytes == XFS_IEXT_BUFSZ);
 
 	ep = ifp->if_u1.if_ext_irec->er_extbuf;
@@ -4449,8 +4449,7 @@
  * compaction policy is as follows:
  *
  *    Full Compaction: Extents fit into a single page (or inline buffer)
- *    Full Compaction: Extents occupy less than 10% of allocated space
- * Partial Compaction: Extents occupy > 10% and < 50% of allocated space
+ * Partial Compaction: Extents occupy less than 50% of allocated space
  *      No Compaction: Extents occupy at least 50% of allocated space
  */
 void
@@ -4471,8 +4470,6 @@
 		xfs_iext_direct_to_inline(ifp, nextents);
 	} else if (nextents <= XFS_LINEAR_EXTS) {
 		xfs_iext_indirect_to_direct(ifp);
-	} else if (nextents < (nlists * XFS_LINEAR_EXTS) >> 3) {
-		xfs_iext_irec_compact_full(ifp);
 	} else if (nextents < (nlists * XFS_LINEAR_EXTS) >> 1) {
 		xfs_iext_irec_compact_pages(ifp);
 	}
@@ -4496,7 +4493,7 @@
 		erp_next = erp + 1;
 		if (erp_next->er_extcount <=
 		    (XFS_LINEAR_EXTS - erp->er_extcount)) {
-			memmove(&erp->er_extbuf[erp->er_extcount],
+			memcpy(&erp->er_extbuf[erp->er_extcount],
 				erp_next->er_extbuf, erp_next->er_extcount *
 				sizeof(xfs_bmbt_rec_t));
 			erp->er_extcount += erp_next->er_extcount;
@@ -4516,91 +4513,6 @@
 }
 
 /*
- * Fully compact the extent records managed by the indirection array.
- */
-void
-xfs_iext_irec_compact_full(
-	xfs_ifork_t	*ifp)			/* inode fork pointer */
-{
-	xfs_bmbt_rec_host_t *ep, *ep_next;	/* extent record pointers */
-	xfs_ext_irec_t	*erp, *erp_next;	/* extent irec pointers */
-	int		erp_idx = 0;		/* extent irec index */
-	int		ext_avail;		/* empty entries in ex list */
-	int		ext_diff;		/* number of exts to add */
-	int		nlists;			/* number of irec's (ex lists) */
-
-	ASSERT(ifp->if_flags & XFS_IFEXTIREC);
-
-	nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ;
-	erp = ifp->if_u1.if_ext_irec;
-	ep = &erp->er_extbuf[erp->er_extcount];
-	erp_next = erp + 1;
-	ep_next = erp_next->er_extbuf;
-
-	while (erp_idx < nlists - 1) {
-		/*
-		 * Check how many extent records are available in this irec.
-		 * If there is none skip the whole exercise.
-		 */
-		ext_avail = XFS_LINEAR_EXTS - erp->er_extcount;
-		if (ext_avail) {
-
-			/*
-			 * Copy over as many as possible extent records into
-			 * the previous page.
-			 */
-			ext_diff = MIN(ext_avail, erp_next->er_extcount);
-			memcpy(ep, ep_next, ext_diff * sizeof(xfs_bmbt_rec_t));
-			erp->er_extcount += ext_diff;
-			erp_next->er_extcount -= ext_diff;
-
-			/*
-			 * If the next irec is empty now we can simply
-			 * remove it.
-			 */
-			if (erp_next->er_extcount == 0) {
-				/*
-				 * Free page before removing extent record
-				 * so er_extoffs don't get modified in
-				 * xfs_iext_irec_remove.
-				 */
-				kmem_free(erp_next->er_extbuf);
-				erp_next->er_extbuf = NULL;
-				xfs_iext_irec_remove(ifp, erp_idx + 1);
-				erp = &ifp->if_u1.if_ext_irec[erp_idx];
-				nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ;
-
-			/*
-			 * If the next irec is not empty move up the content
-			 * that has not been copied to the previous page to
-			 * the beggining of this one.
-			 */
-			} else {
-				memmove(erp_next->er_extbuf, &ep_next[ext_diff],
-					erp_next->er_extcount *
-					sizeof(xfs_bmbt_rec_t));
-				ep_next = erp_next->er_extbuf;
-				memset(&ep_next[erp_next->er_extcount], 0,
-					(XFS_LINEAR_EXTS -
-						erp_next->er_extcount) *
-					sizeof(xfs_bmbt_rec_t));
-			}
-		}
-
-		if (erp->er_extcount == XFS_LINEAR_EXTS) {
-			erp_idx++;
-			if (erp_idx < nlists)
-				erp = &ifp->if_u1.if_ext_irec[erp_idx];
-			else
-				break;
-		}
-		ep = &erp->er_extbuf[erp->er_extcount];
-		erp_next = erp + 1;
-		ep_next = erp_next->er_extbuf;
-	}
-}
-
-/*
  * This is called to update the er_extoff field in the indirection
  * array when extents have been added or removed from one of the
  * extent lists. erp_idx contains the irec index to begin updating
diff --git a/fs/xfs/xfs_log.c b/fs/xfs/xfs_log.c
index ccba14e..0b02c64 100644
--- a/fs/xfs/xfs_log.c
+++ b/fs/xfs/xfs_log.c
@@ -124,16 +124,27 @@
 STATIC int	xlog_iclogs_empty(xlog_t *log);
 
 #if defined(XFS_LOG_TRACE)
+
+#define XLOG_TRACE_LOGGRANT_SIZE	2048
+#define XLOG_TRACE_ICLOG_SIZE		256
+
+void
+xlog_trace_loggrant_alloc(xlog_t *log)
+{
+	log->l_grant_trace = ktrace_alloc(XLOG_TRACE_LOGGRANT_SIZE, KM_NOFS);
+}
+
+void
+xlog_trace_loggrant_dealloc(xlog_t *log)
+{
+	ktrace_free(log->l_grant_trace);
+}
+
 void
 xlog_trace_loggrant(xlog_t *log, xlog_ticket_t *tic, xfs_caddr_t string)
 {
 	unsigned long cnts;
 
-	if (!log->l_grant_trace) {
-		log->l_grant_trace = ktrace_alloc(2048, KM_NOSLEEP);
-		if (!log->l_grant_trace)
-			return;
-	}
 	/* ticket counts are 1 byte each */
 	cnts = ((unsigned long)tic->t_ocnt) | ((unsigned long)tic->t_cnt) << 8;
 
@@ -157,10 +168,20 @@
 }
 
 void
+xlog_trace_iclog_alloc(xlog_in_core_t *iclog)
+{
+	iclog->ic_trace = ktrace_alloc(XLOG_TRACE_ICLOG_SIZE, KM_NOFS);
+}
+
+void
+xlog_trace_iclog_dealloc(xlog_in_core_t *iclog)
+{
+	ktrace_free(iclog->ic_trace);
+}
+
+void
 xlog_trace_iclog(xlog_in_core_t *iclog, uint state)
 {
-	if (!iclog->ic_trace)
-		iclog->ic_trace = ktrace_alloc(256, KM_NOFS);
 	ktrace_enter(iclog->ic_trace,
 		     (void *)((unsigned long)state),
 		     (void *)((unsigned long)current_pid()),
@@ -170,8 +191,15 @@
 		     (void *)NULL, (void *)NULL);
 }
 #else
+
+#define	xlog_trace_loggrant_alloc(log)
+#define	xlog_trace_loggrant_dealloc(log)
 #define	xlog_trace_loggrant(log,tic,string)
+
+#define	xlog_trace_iclog_alloc(iclog)
+#define	xlog_trace_iclog_dealloc(iclog)
 #define	xlog_trace_iclog(iclog,state)
+
 #endif /* XFS_LOG_TRACE */
 
 
@@ -1005,11 +1033,12 @@
 	l = iclog->ic_log;
 
 	/*
-	 * If the ordered flag has been removed by a lower
-	 * layer, it means the underlyin device no longer supports
+	 * If the _XFS_BARRIER_FAILED flag was set by a lower
+	 * layer, it means the underlying device no longer supports
 	 * barrier I/O. Warn loudly and turn off barriers.
 	 */
-	if ((l->l_mp->m_flags & XFS_MOUNT_BARRIER) && !XFS_BUF_ORDERED(bp)) {
+	if (bp->b_flags & _XFS_BARRIER_FAILED) {
+		bp->b_flags &= ~_XFS_BARRIER_FAILED;
 		l->l_mp->m_flags &= ~XFS_MOUNT_BARRIER;
 		xfs_fs_cmn_err(CE_WARN, l->l_mp,
 				"xlog_iodone: Barriers are no longer supported"
@@ -1231,6 +1260,7 @@
 	spin_lock_init(&log->l_grant_lock);
 	sv_init(&log->l_flush_wait, 0, "flush_wait");
 
+	xlog_trace_loggrant_alloc(log);
 	/* log record size must be multiple of BBSIZE; see xlog_rec_header_t */
 	ASSERT((XFS_BUF_SIZE(bp) & BBMASK) == 0);
 
@@ -1285,6 +1315,8 @@
 		sv_init(&iclog->ic_force_wait, SV_DEFAULT, "iclog-force");
 		sv_init(&iclog->ic_write_wait, SV_DEFAULT, "iclog-write");
 
+		xlog_trace_iclog_alloc(iclog);
+
 		iclogp = &iclog->ic_next;
 	}
 	*iclogp = log->l_iclog;			/* complete ring */
@@ -1565,11 +1597,7 @@
 		sv_destroy(&iclog->ic_force_wait);
 		sv_destroy(&iclog->ic_write_wait);
 		xfs_buf_free(iclog->ic_bp);
-#ifdef XFS_LOG_TRACE
-		if (iclog->ic_trace != NULL) {
-			ktrace_free(iclog->ic_trace);
-		}
-#endif
+		xlog_trace_iclog_dealloc(iclog);
 		next_iclog = iclog->ic_next;
 		kmem_free(iclog);
 		iclog = next_iclog;
@@ -1578,14 +1606,7 @@
 	spinlock_destroy(&log->l_grant_lock);
 
 	xfs_buf_free(log->l_xbuf);
-#ifdef XFS_LOG_TRACE
-	if (log->l_trace != NULL) {
-		ktrace_free(log->l_trace);
-	}
-	if (log->l_grant_trace != NULL) {
-		ktrace_free(log->l_grant_trace);
-	}
-#endif
+	xlog_trace_loggrant_dealloc(log);
 	log->l_mp->m_log = NULL;
 	kmem_free(log);
 }	/* xlog_dealloc_log */
diff --git a/fs/xfs/xfs_log_priv.h b/fs/xfs/xfs_log_priv.h
index c8a5b22..e7d8f84 100644
--- a/fs/xfs/xfs_log_priv.h
+++ b/fs/xfs/xfs_log_priv.h
@@ -448,7 +448,6 @@
 	int			l_grant_write_bytes;
 
 #ifdef XFS_LOG_TRACE
-	struct ktrace		*l_trace;
 	struct ktrace		*l_grant_trace;
 #endif
 
diff --git a/fs/xfs/xfs_vnodeops.c b/fs/xfs/xfs_vnodeops.c
index aa238c8..8b6812f 100644
--- a/fs/xfs/xfs_vnodeops.c
+++ b/fs/xfs/xfs_vnodeops.c
@@ -1838,6 +1838,12 @@
 #endif
 }
 
+/*
+ * xfs_lock_two_inodes() can only be used to lock one type of lock
+ * at a time - the iolock or the ilock, but not both at once. If
+ * we lock both at once, lockdep will report false positives saying
+ * we have violated locking orders.
+ */
 void
 xfs_lock_two_inodes(
 	xfs_inode_t		*ip0,
@@ -1848,6 +1854,8 @@
 	int			attempts = 0;
 	xfs_log_item_t		*lp;
 
+	if (lock_mode & (XFS_IOLOCK_SHARED|XFS_IOLOCK_EXCL))
+		ASSERT((lock_mode & (XFS_ILOCK_SHARED|XFS_ILOCK_EXCL)) == 0);
 	ASSERT(ip0->i_ino != ip1->i_ino);
 
 	if (ip0->i_ino > ip1->i_ino) {
@@ -3152,6 +3160,13 @@
 /*
  * Zero file bytes between startoff and endoff inclusive.
  * The iolock is held exclusive and no blocks are buffered.
+ *
+ * This function is used by xfs_free_file_space() to zero
+ * partial blocks when the range to free is not block aligned.
+ * When unreserving space with boundaries that are not block
+ * aligned we round up the start and round down the end
+ * boundaries and then use this function to zero the parts of
+ * the blocks that got dropped during the rounding.
  */
 STATIC int
 xfs_zero_remaining_bytes(
@@ -3168,6 +3183,17 @@
 	int			nimap;
 	int			error = 0;
 
+	/*
+	 * Avoid doing I/O beyond eof - it's not necessary
+	 * since nothing can read beyond eof.  The space will
+	 * be zeroed when the file is extended anyway.
+	 */
+	if (startoff >= ip->i_size)
+		return 0;
+
+	if (endoff > ip->i_size)
+		endoff = ip->i_size;
+
 	bp = xfs_buf_get_noaddr(mp->m_sb.sb_blocksize,
 				XFS_IS_REALTIME_INODE(ip) ?
 				mp->m_rtdev_targp : mp->m_ddev_targp);
diff --git a/include/asm-cris/a.out.h b/include/asm-cris/a.out.h
deleted file mode 100644
index c82e9f9..0000000
--- a/include/asm-cris/a.out.h
+++ /dev/null
@@ -1,26 +0,0 @@
-#ifndef __CRIS_A_OUT_H__
-#define __CRIS_A_OUT_H__
-
-/* we don't support a.out binaries on Linux/CRIS anyway, so this is
- * not really used but still needed because binfmt_elf.c for some reason
- * wants to know about a.out even if there is no interpreter available...
- */
-
-struct exec
-{
-  unsigned long a_info;		/* Use macros N_MAGIC, etc for access */
-  unsigned a_text;		/* length of text, in bytes */
-  unsigned a_data;		/* length of data, in bytes */
-  unsigned a_bss;		/* length of uninitialized data area for file, in bytes */
-  unsigned a_syms;		/* length of symbol table data in file, in bytes */
-  unsigned a_entry;		/* start address */
-  unsigned a_trsize;		/* length of relocation info for text, in bytes */
-  unsigned a_drsize;		/* length of relocation info for data, in bytes */
-};
-
-
-#define N_TRSIZE(a)	((a).a_trsize)
-#define N_DRSIZE(a)	((a).a_drsize)
-#define N_SYMSIZE(a)	((a).a_syms)
-
-#endif
diff --git a/include/asm-generic/bug.h b/include/asm-generic/bug.h
index a3f738c..edc6ba8 100644
--- a/include/asm-generic/bug.h
+++ b/include/asm-generic/bug.h
@@ -97,6 +97,16 @@
 	unlikely(__ret_warn_once);				\
 })
 
+#define WARN_ONCE(condition, format...)	({			\
+	static int __warned;					\
+	int __ret_warn_once = !!(condition);			\
+								\
+	if (unlikely(__ret_warn_once))				\
+		if (WARN(!__warned, format)) 			\
+			__warned = 1;				\
+	unlikely(__ret_warn_once);				\
+})
+
 #define WARN_ON_RATELIMIT(condition, state)			\
 		WARN_ON((condition) && __ratelimit(state))
 
diff --git a/include/asm-generic/siginfo.h b/include/asm-generic/siginfo.h
index 8786e01..9695701 100644
--- a/include/asm-generic/siginfo.h
+++ b/include/asm-generic/siginfo.h
@@ -199,6 +199,8 @@
  */
 #define TRAP_BRKPT	(__SI_FAULT|1)	/* process breakpoint */
 #define TRAP_TRACE	(__SI_FAULT|2)	/* process trace trap */
+#define TRAP_BRANCH     (__SI_FAULT|3)  /* process taken branch trap */
+#define TRAP_HWBKPT     (__SI_FAULT|4)  /* hardware breakpoint/watchpoint */
 #define NSIGTRAP	2
 
 /*
diff --git a/include/asm-generic/statfs.h b/include/asm-generic/statfs.h
index 1d01043..6129d68 100644
--- a/include/asm-generic/statfs.h
+++ b/include/asm-generic/statfs.h
@@ -6,33 +6,64 @@
 typedef __kernel_fsid_t	fsid_t;
 #endif
 
+/*
+ * Most 64-bit platforms use 'long', while most 32-bit platforms use '__u32'.
+ * Yes, they differ in signedness as well as size.
+ * Special cases can override it for themselves -- except for S390x, which
+ * is just a little too special for us. And MIPS, which I'm not touching
+ * with a 10' pole.
+ */
+#ifndef __statfs_word
+#if BITS_PER_LONG == 64
+#define __statfs_word long
+#else
+#define __statfs_word __u32
+#endif
+#endif
+
 struct statfs {
-	__u32 f_type;
-	__u32 f_bsize;
-	__u32 f_blocks;
-	__u32 f_bfree;
-	__u32 f_bavail;
-	__u32 f_files;
-	__u32 f_ffree;
+	__statfs_word f_type;
+	__statfs_word f_bsize;
+	__statfs_word f_blocks;
+	__statfs_word f_bfree;
+	__statfs_word f_bavail;
+	__statfs_word f_files;
+	__statfs_word f_ffree;
 	__kernel_fsid_t f_fsid;
-	__u32 f_namelen;
-	__u32 f_frsize;
-	__u32 f_spare[5];
+	__statfs_word f_namelen;
+	__statfs_word f_frsize;
+	__statfs_word f_spare[5];
 };
 
+/*
+ * ARM needs to avoid the 32-bit padding at the end, for consistency
+ * between EABI and OABI 
+ */
+#ifndef ARCH_PACK_STATFS64
+#define ARCH_PACK_STATFS64
+#endif
+
 struct statfs64 {
-	__u32 f_type;
-	__u32 f_bsize;
+	__statfs_word f_type;
+	__statfs_word f_bsize;
 	__u64 f_blocks;
 	__u64 f_bfree;
 	__u64 f_bavail;
 	__u64 f_files;
 	__u64 f_ffree;
 	__kernel_fsid_t f_fsid;
-	__u32 f_namelen;
-	__u32 f_frsize;
-	__u32 f_spare[5];
-};
+	__statfs_word f_namelen;
+	__statfs_word f_frsize;
+	__statfs_word f_spare[5];
+} ARCH_PACK_STATFS64;
+
+/* 
+ * IA64 and x86_64 need to avoid the 32-bit padding at the end,
+ * to be compatible with the i386 ABI
+ */
+#ifndef ARCH_PACK_COMPAT_STATFS64
+#define ARCH_PACK_COMPAT_STATFS64
+#endif
 
 struct compat_statfs64 {
 	__u32 f_type;
@@ -46,6 +77,6 @@
 	__u32 f_namelen;
 	__u32 f_frsize;
 	__u32 f_spare[5];
-};
+} ARCH_PACK_COMPAT_STATFS64;
 
 #endif
diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
index cb752ba..7440a0d 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -385,6 +385,7 @@
 	. = ALIGN(align);						\
 	VMLINUX_SYMBOL(__per_cpu_start) = .;				\
 	.data.percpu  : AT(ADDR(.data.percpu) - LOAD_OFFSET) {		\
+		*(.data.percpu.page_aligned)				\
 		*(.data.percpu)						\
 		*(.data.percpu.shared_aligned)				\
 	}								\
diff --git a/include/asm-m32r/a.out.h b/include/asm-m32r/a.out.h
deleted file mode 100644
index ab150f5..0000000
--- a/include/asm-m32r/a.out.h
+++ /dev/null
@@ -1,20 +0,0 @@
-#ifndef _ASM_M32R_A_OUT_H
-#define _ASM_M32R_A_OUT_H
-
-struct exec
-{
-  unsigned long a_info;		/* Use macros N_MAGIC, etc for access */
-  unsigned a_text;		/* length of text, in bytes */
-  unsigned a_data;		/* length of data, in bytes */
-  unsigned a_bss;		/* length of uninitialized data area for file, in bytes */
-  unsigned a_syms;		/* length of symbol table data in file, in bytes */
-  unsigned a_entry;		/* start address */
-  unsigned a_trsize;		/* length of relocation info for text, in bytes */
-  unsigned a_drsize;		/* length of relocation info for data, in bytes */
-};
-
-#define N_TRSIZE(a)	((a).a_trsize)
-#define N_DRSIZE(a)	((a).a_drsize)
-#define N_SYMSIZE(a)	((a).a_syms)
-
-#endif /* _ASM_M32R_A_OUT_H */
diff --git a/include/asm-m68k/atarihw.h b/include/asm-m68k/atarihw.h
index ecf007d..1412b4a 100644
--- a/include/asm-m68k/atarihw.h
+++ b/include/asm-m68k/atarihw.h
@@ -39,7 +39,6 @@
 #define MACH_IS_TT	((atari_mch_cookie >> 16) == ATARI_MCH_TT)
 #define MACH_IS_FALCON	((atari_mch_cookie >> 16) == ATARI_MCH_FALCON)
 #define MACH_IS_MEDUSA	(atari_mch_type == ATARI_MACH_MEDUSA)
-#define MACH_IS_HADES	(atari_mch_type == ATARI_MACH_HADES)
 #define MACH_IS_AB40	(atari_mch_type == ATARI_MACH_AB40)
 
 /* values for atari_switches */
diff --git a/include/asm-m68k/dma-mapping.h b/include/asm-m68k/dma-mapping.h
index 91f7944..26f5054 100644
--- a/include/asm-m68k/dma-mapping.h
+++ b/include/asm-m68k/dma-mapping.h
@@ -74,6 +74,14 @@
 extern void dma_sync_sg_for_device(struct device *, struct scatterlist *, int,
 				   enum dma_data_direction);
 
+static inline void dma_sync_single_range_for_device(struct device *dev,
+		dma_addr_t dma_handle, unsigned long offset, size_t size,
+		enum dma_data_direction direction)
+{
+	/* just sync everything for now */
+	dma_sync_single_for_device(dev, dma_handle, offset + size, direction);
+}
+
 static inline void dma_sync_single_for_cpu(struct device *dev, dma_addr_t handle,
 					   size_t size, enum dma_data_direction dir)
 {
@@ -84,6 +92,14 @@
 {
 }
 
+static inline void dma_sync_single_range_for_cpu(struct device *dev,
+		dma_addr_t dma_handle, unsigned long offset, size_t size,
+		enum dma_data_direction direction)
+{
+	/* just sync everything for now */
+	dma_sync_single_for_cpu(dev, dma_handle, offset + size, direction);
+}
+
 static inline int dma_mapping_error(struct device *dev, dma_addr_t handle)
 {
 	return 0;
diff --git a/include/asm-m68k/dma.h b/include/asm-m68k/dma.h
index d0c9e61..4240fbc9 100644
--- a/include/asm-m68k/dma.h
+++ b/include/asm-m68k/dma.h
@@ -11,10 +11,6 @@
 extern int request_dma(unsigned int dmanr, const char * device_id);	/* reserve a DMA channel */
 extern void free_dma(unsigned int dmanr);	/* release it again */
 
-#ifdef CONFIG_PCI
-extern int isa_dma_bridge_buggy;
-#else
 #define isa_dma_bridge_buggy    (0)
-#endif
 
 #endif /* _M68K_DMA_H */
diff --git a/include/asm-m68k/entry.h b/include/asm-m68k/entry.h
index f8f6b18..5202f5a 100644
--- a/include/asm-m68k/entry.h
+++ b/include/asm-m68k/entry.h
@@ -31,7 +31,7 @@
  */
 
 /* the following macro is used when enabling interrupts */
-#if defined(MACH_ATARI_ONLY) && !defined(CONFIG_HADES)
+#if defined(MACH_ATARI_ONLY)
 	/* block out HSYNC on the atari */
 #define ALLOWINT	(~0x400)
 #define	MAX_NOINT_IPL	3
diff --git a/include/asm-m68k/io.h b/include/asm-m68k/io.h
index 657187f..9e673e3 100644
--- a/include/asm-m68k/io.h
+++ b/include/asm-m68k/io.h
@@ -7,15 +7,12 @@
  *            - added skeleton for GG-II and Amiga PCMCIA
  * 2/3/01 RZ: - moved a few more defs into raw_io.h
  *
- * inX/outX/readX/writeX should not be used by any driver unless it does
- * ISA or PCI access. Other drivers should use function defined in raw_io.h
+ * inX/outX should not be used by any driver unless it does
+ * ISA access. Other drivers should use function defined in raw_io.h
  * or define its own macros on top of these.
  *
- *    inX(),outX()              are for PCI and ISA I/O
- *    readX(),writeX()          are for PCI memory
+ *    inX(),outX()              are for ISA I/O
  *    isa_readX(),isa_writeX()  are for ISA memory
- *
- * moved mem{cpy,set}_*io inside CONFIG_PCI
  */
 
 #ifndef _IO_H
@@ -256,10 +253,7 @@
        (ISA_SEX ? raw_outsl(isa_itl(port), (u32 *)(buf), (nr)) :  \
                   raw_outsw_swapw(isa_itw(port), (u16 *)(buf), (nr)<<1))
 
-#endif  /* CONFIG_ISA */
 
-
-#if defined(CONFIG_ISA) && !defined(CONFIG_PCI)
 #define inb     isa_inb
 #define inb_p   isa_inb_p
 #define outb    isa_outb
@@ -282,55 +276,9 @@
 #define readw   isa_readw
 #define writeb  isa_writeb
 #define writew  isa_writew
-#endif /* CONFIG_ISA */
 
-#if defined(CONFIG_PCI)
+#else  /* CONFIG_ISA */
 
-#define readl(addr)      in_le32(addr)
-#define writel(val,addr) out_le32((addr),(val))
-
-/* those can be defined for both ISA and PCI - it won't work though */
-#define readb(addr)       in_8(addr)
-#define readw(addr)       in_le16(addr)
-#define writeb(val,addr)  out_8((addr),(val))
-#define writew(val,addr)  out_le16((addr),(val))
-
-#define readb_relaxed(addr) readb(addr)
-#define readw_relaxed(addr) readw(addr)
-#define readl_relaxed(addr) readl(addr)
-
-#ifndef CONFIG_ISA
-#define inb(port)      in_8(port)
-#define outb(val,port) out_8((port),(val))
-#define inw(port)      in_le16(port)
-#define outw(val,port) out_le16((port),(val))
-#define inl(port)      in_le32(port)
-#define outl(val,port) out_le32((port),(val))
-
-#else
-/*
- * kernel with both ISA and PCI compiled in, those have
- * conflicting defs for in/out. Simply consider port < 1024
- * ISA and everything else PCI. read,write not defined
- * in this case
- */
-#define inb(port) ((port)<1024 ? isa_inb(port) : in_8(port))
-#define inb_p(port) ((port)<1024 ? isa_inb_p(port) : in_8(port))
-#define inw(port) ((port)<1024 ? isa_inw(port) : in_le16(port))
-#define inw_p(port) ((port)<1024 ? isa_inw_p(port) : in_le16(port))
-#define inl(port) ((port)<1024 ? isa_inl(port) : in_le32(port))
-#define inl_p(port) ((port)<1024 ? isa_inl_p(port) : in_le32(port))
-
-#define outb(val,port) ((port)<1024 ? isa_outb((val),(port)) : out_8((port),(val)))
-#define outb_p(val,port) ((port)<1024 ? isa_outb_p((val),(port)) : out_8((port),(val)))
-#define outw(val,port) ((port)<1024 ? isa_outw((val),(port)) : out_le16((port),(val)))
-#define outw_p(val,port) ((port)<1024 ? isa_outw_p((val),(port)) : out_le16((port),(val)))
-#define outl(val,port) ((port)<1024 ? isa_outl((val),(port)) : out_le32((port),(val)))
-#define outl_p(val,port) ((port)<1024 ? isa_outl_p((val),(port)) : out_le32((port),(val)))
-#endif
-#endif /* CONFIG_PCI */
-
-#if !defined(CONFIG_ISA) && !defined(CONFIG_PCI)
 /*
  * We need to define dummy functions for GENERIC_IOMAP support.
  */
@@ -357,11 +305,11 @@
 #define writeb(val,addr) out_8((addr),(val))
 #define readw(addr)      in_le16(addr)
 #define writew(val,addr) out_le16((addr),(val))
-#endif
-#if !defined(CONFIG_PCI)
+
+#endif /* CONFIG_ISA */
+
 #define readl(addr)      in_le32(addr)
 #define writel(val,addr) out_le32((addr),(val))
-#endif
 
 #define mmiowb()
 
diff --git a/include/asm-m68k/pci.h b/include/asm-m68k/pci.h
index 678cb0b..4ad0aea 100644
--- a/include/asm-m68k/pci.h
+++ b/include/asm-m68k/pci.h
@@ -1,52 +1,7 @@
 #ifndef _ASM_M68K_PCI_H
 #define _ASM_M68K_PCI_H
 
-/*
- * asm-m68k/pci_m68k.h - m68k specific PCI declarations.
- *
- * Written by Wout Klaren.
- */
-
-#include <asm/scatterlist.h>
-
-struct pci_ops;
-
-/*
- * Structure with hardware dependent information and functions of the
- * PCI bus.
- */
-
-struct pci_bus_info
-{
-	/*
-	 * Resources of the PCI bus.
-	 */
-
-	struct resource mem_space;
-	struct resource io_space;
-
-	/*
-	 * System dependent functions.
-	 */
-
-	struct pci_ops *m68k_pci_ops;
-
-	void (*fixup)(int pci_modify);
-	void (*conf_device)(struct pci_dev *dev);
-};
-
-#define pcibios_assign_all_busses()	0
-#define pcibios_scan_all_fns(a, b)	0
-
-static inline void pcibios_set_master(struct pci_dev *dev)
-{
-	/* No special bus mastering setup handling */
-}
-
-static inline void pcibios_penalize_isa_irq(int irq, int active)
-{
-	/* We don't do dynamic PCI IRQ allocation */
-}
+#include <asm-generic/pci-dma-compat.h>
 
 /* The PCI address space does equal the physical memory
  * address space.  The networking and block device layers use
diff --git a/include/asm-m68k/virtconvert.h b/include/asm-m68k/virtconvert.h
index dea32fb..22ab05c 100644
--- a/include/asm-m68k/virtconvert.h
+++ b/include/asm-m68k/virtconvert.h
@@ -40,15 +40,9 @@
 
 /*
  * IO bus memory addresses are 1:1 with the physical address,
- * except on the PCI bus of the Hades.
  */
-#ifdef CONFIG_HADES
-#define virt_to_bus(a) (virt_to_phys(a) + (MACH_IS_HADES ? 0x80000000 : 0))
-#define bus_to_virt(a) (phys_to_virt((a) - (MACH_IS_HADES ? 0x80000000 : 0)))
-#else
 #define virt_to_bus virt_to_phys
 #define bus_to_virt phys_to_virt
-#endif
 
 #endif
 #endif
diff --git a/include/asm-mips/a.out.h b/include/asm-mips/a.out.h
deleted file mode 100644
index cad8371..0000000
--- a/include/asm-mips/a.out.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 1994 - 1999, 2003 by Ralf Baechle
- */
-#ifndef _ASM_A_OUT_H
-#define _ASM_A_OUT_H
-
-#ifdef __KERNEL__
-
-
-#endif
-
-struct exec
-{
-	unsigned long a_info;	/* Use macros N_MAGIC, etc for access */
-	unsigned a_text;	/* length of text, in bytes */
-	unsigned a_data;	/* length of data, in bytes */
-	unsigned a_bss;		/* length of uninitialized data area for
-				    file, in bytes */
-	unsigned a_syms;	/* length of symbol table data in file,
-				   in bytes */
-	unsigned a_entry;	/* start address */
-	unsigned a_trsize;	/* length of relocation info for text, in
-				    bytes */
-	unsigned a_drsize;	/* length of relocation info for data, in bytes */
-};
-
-#define N_TRSIZE(a)	((a).a_trsize)
-#define N_DRSIZE(a)	((a).a_drsize)
-#define N_SYMSIZE(a)	((a).a_syms)
-
-#endif /* _ASM_A_OUT_H */
diff --git a/include/asm-mips/cevt-r4k.h b/include/asm-mips/cevt-r4k.h
new file mode 100644
index 0000000..fa4328f
--- /dev/null
+++ b/include/asm-mips/cevt-r4k.h
@@ -0,0 +1,46 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2008 Kevin D. Kissell
+ */
+
+/*
+ * Definitions used for common event timer implementation
+ * for MIPS 4K-type processors and their MIPS MT variants.
+ * Avoids unsightly extern declarations in C files.
+ */
+#ifndef __ASM_CEVT_R4K_H
+#define __ASM_CEVT_R4K_H
+
+DECLARE_PER_CPU(struct clock_event_device, mips_clockevent_device);
+
+void mips_event_handler(struct clock_event_device *dev);
+int c0_compare_int_usable(void);
+void mips_set_clock_mode(enum clock_event_mode, struct clock_event_device *);
+irqreturn_t c0_compare_interrupt(int, void *);
+
+extern struct irqaction c0_compare_irqaction;
+extern int cp0_timer_irq_installed;
+
+/*
+ * Possibly handle a performance counter interrupt.
+ * Return true if the timer interrupt should not be checked
+ */
+
+static inline int handle_perf_irq(int r2)
+{
+	/*
+	 * The performance counter overflow interrupt may be shared with the
+	 * timer interrupt (cp0_perfcount_irq < 0). If it is and a
+	 * performance counter has overflowed (perf_irq() == IRQ_HANDLED)
+	 * and we can't reliably determine if a counter interrupt has also
+	 * happened (!r2) then don't check for a timer interrupt.
+	 */
+	return (cp0_perfcount_irq < 0) &&
+		perf_irq() == IRQ_HANDLED &&
+		!r2;
+}
+
+#endif /* __ASM_CEVT_R4K_H */
diff --git a/include/asm-mips/cpu-info.h b/include/asm-mips/cpu-info.h
deleted file mode 100644
index 2de73db..0000000
--- a/include/asm-mips/cpu-info.h
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 1994 Waldorf GMBH
- * Copyright (C) 1995, 1996, 1997, 1998, 1999, 2001, 2002, 2003 Ralf Baechle
- * Copyright (C) 1996 Paul M. Antoine
- * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
- * Copyright (C) 2004  Maciej W. Rozycki
- */
-#ifndef __ASM_CPU_INFO_H
-#define __ASM_CPU_INFO_H
-
-#include <asm/cache.h>
-
-/*
- * Descriptor for a cache
- */
-struct cache_desc {
-	unsigned int waysize;	/* Bytes per way */
-	unsigned short sets;	/* Number of lines per set */
-	unsigned char ways;	/* Number of ways */
-	unsigned char linesz;	/* Size of line in bytes */
-	unsigned char waybit;	/* Bits to select in a cache set */
-	unsigned char flags;	/* Flags describing cache properties */
-};
-
-/*
- * Flag definitions
- */
-#define MIPS_CACHE_NOT_PRESENT	0x00000001
-#define MIPS_CACHE_VTAG		0x00000002	/* Virtually tagged cache */
-#define MIPS_CACHE_ALIASES	0x00000004	/* Cache could have aliases */
-#define MIPS_CACHE_IC_F_DC	0x00000008	/* Ic can refill from D-cache */
-#define MIPS_IC_SNOOPS_REMOTE	0x00000010	/* Ic snoops remote stores */
-#define MIPS_CACHE_PINDEX	0x00000020	/* Physically indexed cache */
-
-struct cpuinfo_mips {
-	unsigned long		udelay_val;
-	unsigned long		asid_cache;
-
-	/*
-	 * Capability and feature descriptor structure for MIPS CPU
-	 */
-	unsigned long		options;
-	unsigned long		ases;
-	unsigned int		processor_id;
-	unsigned int		fpu_id;
-	unsigned int		cputype;
-	int			isa_level;
-	int			tlbsize;
-	struct cache_desc	icache;	/* Primary I-cache */
-	struct cache_desc	dcache;	/* Primary D or combined I/D cache */
-	struct cache_desc	scache;	/* Secondary cache */
-	struct cache_desc	tcache;	/* Tertiary/split secondary cache */
-	int			srsets;	/* Shadow register sets */
-	int			core;	/* physical core number */
-#if defined(CONFIG_MIPS_MT_SMP) || defined(CONFIG_MIPS_MT_SMTC)
-	/*
-	 * In the MIPS MT "SMTC" model, each TC is considered
-	 * to be a "CPU" for the purposes of scheduling, but
-	 * exception resources, ASID spaces, etc, are common
-	 * to all TCs within the same VPE.
-	 */
-	int			vpe_id;  /* Virtual Processor number */
-#endif
-#ifdef CONFIG_MIPS_MT_SMTC
-	int			tc_id;   /* Thread Context number */
-#endif
-	void 			*data;	/* Additional data */
-} __attribute__((aligned(SMP_CACHE_BYTES)));
-
-extern struct cpuinfo_mips cpu_data[];
-#define current_cpu_data cpu_data[smp_processor_id()]
-#define raw_current_cpu_data cpu_data[raw_smp_processor_id()]
-
-extern void cpu_probe(void);
-extern void cpu_report(void);
-
-extern const char *__cpu_name[];
-#define cpu_name_string()	__cpu_name[smp_processor_id()]
-
-#endif /* __ASM_CPU_INFO_H */
diff --git a/include/asm-mips/irqflags.h b/include/asm-mips/irqflags.h
deleted file mode 100644
index 881e886..0000000
--- a/include/asm-mips/irqflags.h
+++ /dev/null
@@ -1,263 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 1994, 95, 96, 97, 98, 99, 2003 by Ralf Baechle
- * Copyright (C) 1996 by Paul M. Antoine
- * Copyright (C) 1999 Silicon Graphics
- * Copyright (C) 2000 MIPS Technologies, Inc.
- */
-#ifndef _ASM_IRQFLAGS_H
-#define _ASM_IRQFLAGS_H
-
-#ifndef __ASSEMBLY__
-
-#include <linux/compiler.h>
-#include <asm/hazards.h>
-
-__asm__(
-	"	.macro	raw_local_irq_enable				\n"
-	"	.set	push						\n"
-	"	.set	reorder						\n"
-	"	.set	noat						\n"
-#ifdef CONFIG_MIPS_MT_SMTC
-	"	mfc0	$1, $2, 1	# SMTC - clear TCStatus.IXMT	\n"
-	"	ori	$1, 0x400					\n"
-	"	xori	$1, 0x400					\n"
-	"	mtc0	$1, $2, 1					\n"
-#elif defined(CONFIG_CPU_MIPSR2)
-	"	ei							\n"
-#else
-	"	mfc0	$1,$12						\n"
-	"	ori	$1,0x1f						\n"
-	"	xori	$1,0x1e						\n"
-	"	mtc0	$1,$12						\n"
-#endif
-	"	irq_enable_hazard					\n"
-	"	.set	pop						\n"
-	"	.endm");
-
-static inline void raw_local_irq_enable(void)
-{
-	__asm__ __volatile__(
-		"raw_local_irq_enable"
-		: /* no outputs */
-		: /* no inputs */
-		: "memory");
-}
-
-/*
- * For cli() we have to insert nops to make sure that the new value
- * has actually arrived in the status register before the end of this
- * macro.
- * R4000/R4400 need three nops, the R4600 two nops and the R10000 needs
- * no nops at all.
- */
-/*
- * For TX49, operating only IE bit is not enough.
- *
- * If mfc0 $12 follows store and the mfc0 is last instruction of a
- * page and fetching the next instruction causes TLB miss, the result
- * of the mfc0 might wrongly contain EXL bit.
- *
- * ERT-TX49H2-027, ERT-TX49H3-012, ERT-TX49HL3-006, ERT-TX49H4-008
- *
- * Workaround: mask EXL bit of the result or place a nop before mfc0.
- */
-__asm__(
-	"	.macro	raw_local_irq_disable\n"
-	"	.set	push						\n"
-	"	.set	noat						\n"
-#ifdef CONFIG_MIPS_MT_SMTC
-	"	mfc0	$1, $2, 1					\n"
-	"	ori	$1, 0x400					\n"
-	"	.set	noreorder					\n"
-	"	mtc0	$1, $2, 1					\n"
-#elif defined(CONFIG_CPU_MIPSR2)
-	"	di							\n"
-#else
-	"	mfc0	$1,$12						\n"
-	"	ori	$1,0x1f						\n"
-	"	xori	$1,0x1f						\n"
-	"	.set	noreorder					\n"
-	"	mtc0	$1,$12						\n"
-#endif
-	"	irq_disable_hazard					\n"
-	"	.set	pop						\n"
-	"	.endm							\n");
-
-static inline void raw_local_irq_disable(void)
-{
-	__asm__ __volatile__(
-		"raw_local_irq_disable"
-		: /* no outputs */
-		: /* no inputs */
-		: "memory");
-}
-
-__asm__(
-	"	.macro	raw_local_save_flags flags			\n"
-	"	.set	push						\n"
-	"	.set	reorder						\n"
-#ifdef CONFIG_MIPS_MT_SMTC
-	"	mfc0	\\flags, $2, 1					\n"
-#else
-	"	mfc0	\\flags, $12					\n"
-#endif
-	"	.set	pop						\n"
-	"	.endm							\n");
-
-#define raw_local_save_flags(x)						\
-__asm__ __volatile__(							\
-	"raw_local_save_flags %0"					\
-	: "=r" (x))
-
-__asm__(
-	"	.macro	raw_local_irq_save result			\n"
-	"	.set	push						\n"
-	"	.set	reorder						\n"
-	"	.set	noat						\n"
-#ifdef CONFIG_MIPS_MT_SMTC
-	"	mfc0	\\result, $2, 1					\n"
-	"	ori	$1, \\result, 0x400				\n"
-	"	.set	noreorder					\n"
-	"	mtc0	$1, $2, 1					\n"
-	"	andi	\\result, \\result, 0x400			\n"
-#elif defined(CONFIG_CPU_MIPSR2)
-	"	di	\\result					\n"
-	"	andi	\\result, 1					\n"
-#else
-	"	mfc0	\\result, $12					\n"
-	"	ori	$1, \\result, 0x1f				\n"
-	"	xori	$1, 0x1f					\n"
-	"	.set	noreorder					\n"
-	"	mtc0	$1, $12						\n"
-#endif
-	"	irq_disable_hazard					\n"
-	"	.set	pop						\n"
-	"	.endm							\n");
-
-#define raw_local_irq_save(x)						\
-__asm__ __volatile__(							\
-	"raw_local_irq_save\t%0"					\
-	: "=r" (x)							\
-	: /* no inputs */						\
-	: "memory")
-
-__asm__(
-	"	.macro	raw_local_irq_restore flags			\n"
-	"	.set	push						\n"
-	"	.set	noreorder					\n"
-	"	.set	noat						\n"
-#ifdef CONFIG_MIPS_MT_SMTC
-	"mfc0	$1, $2, 1						\n"
-	"andi	\\flags, 0x400						\n"
-	"ori	$1, 0x400						\n"
-	"xori	$1, 0x400						\n"
-	"or	\\flags, $1						\n"
-	"mtc0	\\flags, $2, 1						\n"
-#elif defined(CONFIG_CPU_MIPSR2) && defined(CONFIG_IRQ_CPU)
-	/*
-	 * Slow, but doesn't suffer from a relativly unlikely race
-	 * condition we're having since days 1.
-	 */
-	"	beqz	\\flags, 1f					\n"
-	"	 di							\n"
-	"	ei							\n"
-	"1:								\n"
-#elif defined(CONFIG_CPU_MIPSR2)
-	/*
-	 * Fast, dangerous.  Life is fun, life is good.
-	 */
-	"	mfc0	$1, $12						\n"
-	"	ins	$1, \\flags, 0, 1				\n"
-	"	mtc0	$1, $12						\n"
-#else
-	"	mfc0	$1, $12						\n"
-	"	andi	\\flags, 1					\n"
-	"	ori	$1, 0x1f					\n"
-	"	xori	$1, 0x1f					\n"
-	"	or	\\flags, $1					\n"
-	"	mtc0	\\flags, $12					\n"
-#endif
-	"	irq_disable_hazard					\n"
-	"	.set	pop						\n"
-	"	.endm							\n");
-
-extern void smtc_ipi_replay(void);
-
-static inline void raw_local_irq_restore(unsigned long flags)
-{
-	unsigned long __tmp1;
-
-#ifdef CONFIG_MIPS_MT_SMTC_INSTANT_REPLAY
-	/*
-	 * CONFIG_MIPS_MT_SMTC_INSTANT_REPLAY does prompt replay of deferred
-	 * IPIs, at the cost of branch and call overhead on each
-	 * local_irq_restore()
-	 */
-	if (unlikely(!(flags & 0x0400)))
-		smtc_ipi_replay();
-#endif
-
-	__asm__ __volatile__(
-		"raw_local_irq_restore\t%0"
-		: "=r" (__tmp1)
-		: "0" (flags)
-		: "memory");
-}
-
-static inline int raw_irqs_disabled_flags(unsigned long flags)
-{
-#ifdef CONFIG_MIPS_MT_SMTC
-	/*
-	 * SMTC model uses TCStatus.IXMT to disable interrupts for a thread/CPU
-	 */
-	return flags & 0x400;
-#else
-	return !(flags & 1);
-#endif
-}
-
-#endif
-
-/*
- * Do the CPU's IRQ-state tracing from assembly code.
- */
-#ifdef CONFIG_TRACE_IRQFLAGS
-/* Reload some registers clobbered by trace_hardirqs_on */
-#ifdef CONFIG_64BIT
-# define TRACE_IRQS_RELOAD_REGS						\
-	LONG_L	$11, PT_R11(sp);					\
-	LONG_L	$10, PT_R10(sp);					\
-	LONG_L	$9, PT_R9(sp);						\
-	LONG_L	$8, PT_R8(sp);						\
-	LONG_L	$7, PT_R7(sp);						\
-	LONG_L	$6, PT_R6(sp);						\
-	LONG_L	$5, PT_R5(sp);						\
-	LONG_L	$4, PT_R4(sp);						\
-	LONG_L	$2, PT_R2(sp)
-#else
-# define TRACE_IRQS_RELOAD_REGS						\
-	LONG_L	$7, PT_R7(sp);						\
-	LONG_L	$6, PT_R6(sp);						\
-	LONG_L	$5, PT_R5(sp);						\
-	LONG_L	$4, PT_R4(sp);						\
-	LONG_L	$2, PT_R2(sp)
-#endif
-# define TRACE_IRQS_ON							\
-	CLI;	/* make sure trace_hardirqs_on() is called in kernel level */ \
-	jal	trace_hardirqs_on
-# define TRACE_IRQS_ON_RELOAD						\
-	TRACE_IRQS_ON;							\
-	TRACE_IRQS_RELOAD_REGS
-# define TRACE_IRQS_OFF							\
-	jal	trace_hardirqs_off
-#else
-# define TRACE_IRQS_ON
-# define TRACE_IRQS_ON_RELOAD
-# define TRACE_IRQS_OFF
-#endif
-
-#endif /* _ASM_IRQFLAGS_H */
diff --git a/include/asm-mips/mach-generic/ide.h b/include/asm-mips/mach-generic/ide.h
deleted file mode 100644
index 73008f7..0000000
--- a/include/asm-mips/mach-generic/ide.h
+++ /dev/null
@@ -1,167 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 1994-1996  Linus Torvalds & authors
- *
- * Copied from i386; many of the especially older MIPS or ISA-based platforms
- * are basically identical.  Using this file probably implies i8259 PIC
- * support in a system but the very least interrupt numbers 0 - 15 need to
- * be put aside for legacy devices.
- */
-#ifndef __ASM_MACH_GENERIC_IDE_H
-#define __ASM_MACH_GENERIC_IDE_H
-
-#ifdef __KERNEL__
-
-#include <linux/pci.h>
-#include <linux/stddef.h>
-#include <asm/processor.h>
-
-static __inline__ int ide_probe_legacy(void)
-{
-#ifdef CONFIG_PCI
-	struct pci_dev *dev;
-	/*
-	 * This can be called on the ide_setup() path, super-early in
-	 * boot.  But the down_read() will enable local interrupts,
-	 * which can cause some machines to crash.  So here we detect
-	 * and flag that situation and bail out early.
-	 */
-	if (no_pci_devices())
-		return 0;
-	dev = pci_get_class(PCI_CLASS_BRIDGE_EISA << 8, NULL);
-	if (dev)
-		goto found;
-	dev = pci_get_class(PCI_CLASS_BRIDGE_ISA << 8, NULL);
-	if (dev)
-		goto found;
-	return 0;
-found:
-	pci_dev_put(dev);
-	return 1;
-#elif defined(CONFIG_EISA) || defined(CONFIG_ISA)
-	return 1;
-#else
-	return 0;
-#endif
-}
-
-/* MIPS port and memory-mapped I/O string operations.  */
-static inline void __ide_flush_prologue(void)
-{
-#ifdef CONFIG_SMP
-	if (cpu_has_dc_aliases)
-		preempt_disable();
-#endif
-}
-
-static inline void __ide_flush_epilogue(void)
-{
-#ifdef CONFIG_SMP
-	if (cpu_has_dc_aliases)
-		preempt_enable();
-#endif
-}
-
-static inline void __ide_flush_dcache_range(unsigned long addr, unsigned long size)
-{
-	if (cpu_has_dc_aliases) {
-		unsigned long end = addr + size;
-
-		while (addr < end) {
-			local_flush_data_cache_page((void *)addr);
-			addr += PAGE_SIZE;
-		}
-	}
-}
-
-/*
- * insw() and gang might be called with interrupts disabled, so we can't
- * send IPIs for flushing due to the potencial of deadlocks, see the comment
- * above smp_call_function() in arch/mips/kernel/smp.c.  We work around the
- * problem by disabling preemption so we know we actually perform the flush
- * on the processor that actually has the lines to be flushed which hopefully
- * is even better for performance anyway.
- */
-static inline void __ide_insw(unsigned long port, void *addr,
-	unsigned int count)
-{
-	__ide_flush_prologue();
-	insw(port, addr, count);
-	__ide_flush_dcache_range((unsigned long)addr, count * 2);
-	__ide_flush_epilogue();
-}
-
-static inline void __ide_insl(unsigned long port, void *addr, unsigned int count)
-{
-	__ide_flush_prologue();
-	insl(port, addr, count);
-	__ide_flush_dcache_range((unsigned long)addr, count * 4);
-	__ide_flush_epilogue();
-}
-
-static inline void __ide_outsw(unsigned long port, const void *addr,
-	unsigned long count)
-{
-	__ide_flush_prologue();
-	outsw(port, addr, count);
-	__ide_flush_dcache_range((unsigned long)addr, count * 2);
-	__ide_flush_epilogue();
-}
-
-static inline void __ide_outsl(unsigned long port, const void *addr,
-	unsigned long count)
-{
-	__ide_flush_prologue();
-	outsl(port, addr, count);
-	__ide_flush_dcache_range((unsigned long)addr, count * 4);
-	__ide_flush_epilogue();
-}
-
-static inline void __ide_mm_insw(void __iomem *port, void *addr, u32 count)
-{
-	__ide_flush_prologue();
-	readsw(port, addr, count);
-	__ide_flush_dcache_range((unsigned long)addr, count * 2);
-	__ide_flush_epilogue();
-}
-
-static inline void __ide_mm_insl(void __iomem *port, void *addr, u32 count)
-{
-	__ide_flush_prologue();
-	readsl(port, addr, count);
-	__ide_flush_dcache_range((unsigned long)addr, count * 4);
-	__ide_flush_epilogue();
-}
-
-static inline void __ide_mm_outsw(void __iomem *port, void *addr, u32 count)
-{
-	__ide_flush_prologue();
-	writesw(port, addr, count);
-	__ide_flush_dcache_range((unsigned long)addr, count * 2);
-	__ide_flush_epilogue();
-}
-
-static inline void __ide_mm_outsl(void __iomem * port, void *addr, u32 count)
-{
-	__ide_flush_prologue();
-	writesl(port, addr, count);
-	__ide_flush_dcache_range((unsigned long)addr, count * 4);
-	__ide_flush_epilogue();
-}
-
-/* ide_insw calls insw, not __ide_insw.  Why? */
-#undef insw
-#undef insl
-#undef outsw
-#undef outsl
-#define insw(port, addr, count) __ide_insw(port, addr, count)
-#define insl(port, addr, count) __ide_insl(port, addr, count)
-#define outsw(port, addr, count) __ide_outsw(port, addr, count)
-#define outsl(port, addr, count) __ide_outsl(port, addr, count)
-
-#endif /* __KERNEL__ */
-
-#endif /* __ASM_MACH_GENERIC_IDE_H */
diff --git a/include/asm-mips/mach-rc32434/gpio.h b/include/asm-mips/mach-rc32434/gpio.h
deleted file mode 100644
index f946f5f..0000000
--- a/include/asm-mips/mach-rc32434/gpio.h
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * Copyright 2002 Integrated Device Technology, Inc.
- *	All rights reserved.
- *
- * GPIO register definition.
- *
- * Author : ryan.holmQVist@idt.com
- * Date   : 20011005
- * Copyright (C) 2001, 2002 Ryan Holm <ryan.holmQVist@idt.com>
- * Copyright (C) 2008 Florian Fainelli <florian@openwrt.org>
- */
-
-#ifndef _RC32434_GPIO_H_
-#define _RC32434_GPIO_H_
-
-#include <linux/types.h>
-
-struct rb532_gpio_reg {
-	u32   gpiofunc;   /* GPIO Function Register
-			   * gpiofunc[x]==0 bit = gpio
-			   * func[x]==1  bit = altfunc
-			   */
-	u32   gpiocfg;	  /* GPIO Configuration Register
-			   * gpiocfg[x]==0 bit = input
-			   * gpiocfg[x]==1 bit = output
-			   */
-	u32   gpiod;	  /* GPIO Data Register
-			   * gpiod[x] read/write gpio pinX status
-			   */
-	u32   gpioilevel; /* GPIO Interrupt Status Register
-			   * interrupt level (see gpioistat)
-			   */
-	u32   gpioistat;  /* Gpio Interrupt Status Register
-			   * istat[x] = (gpiod[x] == level[x])
-			   * cleared in ISR (STICKY bits)
-			   */
-	u32   gpionmien;  /* GPIO Non-maskable Interrupt Enable Register */
-};
-
-/* UART GPIO signals */
-#define RC32434_UART0_SOUT	(1 << 0)
-#define RC32434_UART0_SIN	(1 << 1)
-#define RC32434_UART0_RTS	(1 << 2)
-#define RC32434_UART0_CTS	(1 << 3)
-
-/* M & P bus GPIO signals */
-#define RC32434_MP_BIT_22	(1 << 4)
-#define RC32434_MP_BIT_23	(1 << 5)
-#define RC32434_MP_BIT_24	(1 << 6)
-#define RC32434_MP_BIT_25	(1 << 7)
-
-/* CPU GPIO signals */
-#define RC32434_CPU_GPIO	(1 << 8)
-
-/* Reserved GPIO signals */
-#define RC32434_AF_SPARE_6	(1 << 9)
-#define RC32434_AF_SPARE_4	(1 << 10)
-#define RC32434_AF_SPARE_3	(1 << 11)
-#define RC32434_AF_SPARE_2	(1 << 12)
-
-/* PCI messaging unit */
-#define RC32434_PCI_MSU_GPIO	(1 << 13)
-
-
-extern void set_434_reg(unsigned reg_offs, unsigned bit, unsigned len, unsigned val);
-extern unsigned get_434_reg(unsigned reg_offs);
-extern void set_latch_u5(unsigned char or_mask, unsigned char nand_mask);
-extern unsigned char get_latch_u5(void);
-
-extern int rb532_gpio_get_value(unsigned gpio);
-extern void rb532_gpio_set_value(unsigned gpio, int value);
-extern int rb532_gpio_direction_input(unsigned gpio);
-extern int rb532_gpio_direction_output(unsigned gpio, int value);
-extern void rb532_gpio_set_int_level(unsigned gpio, int value);
-extern int rb532_gpio_get_int_level(unsigned gpio);
-extern void rb532_gpio_set_int_status(unsigned gpio, int value);
-extern int rb532_gpio_get_int_status(unsigned gpio);
-
-
-/* Wrappers for the arch-neutral GPIO API */
-
-static inline int gpio_request(unsigned gpio, const char *label)
-{
-	/* Not yet implemented */
-	return 0;
-}
-
-static inline void gpio_free(unsigned gpio)
-{
-	/* Not yet implemented */
-}
-
-static inline int gpio_direction_input(unsigned gpio)
-{
-	return rb532_gpio_direction_input(gpio);
-}
-
-static inline int gpio_direction_output(unsigned gpio, int value)
-{
-	return rb532_gpio_direction_output(gpio, value);
-}
-
-static inline int gpio_get_value(unsigned gpio)
-{
-	return rb532_gpio_get_value(gpio);
-}
-
-static inline void gpio_set_value(unsigned gpio, int value)
-{
-	rb532_gpio_set_value(gpio, value);
-}
-
-static inline int gpio_to_irq(unsigned gpio)
-{
-	return gpio;
-}
-
-static inline int irq_to_gpio(unsigned irq)
-{
-	return irq;
-}
-
-/* For cansleep */
-#include <asm-generic/gpio.h>
-
-#endif /* _RC32434_GPIO_H_ */
diff --git a/include/asm-mips/mach-rc32434/irq.h b/include/asm-mips/mach-rc32434/irq.h
deleted file mode 100644
index cb9e472..0000000
--- a/include/asm-mips/mach-rc32434/irq.h
+++ /dev/null
@@ -1,8 +0,0 @@
-#ifndef __ASM_RC32434_IRQ_H
-#define __ASM_RC32434_IRQ_H
-
-#define NR_IRQS	256
-
-#include <asm/mach-generic/irq.h>
-
-#endif  /* __ASM_RC32434_IRQ_H */
diff --git a/include/asm-mips/mach-rc32434/prom.h b/include/asm-mips/mach-rc32434/prom.h
deleted file mode 100644
index 1d66ddc..0000000
--- a/include/asm-mips/mach-rc32434/prom.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- *  Definitions for the PROM
- *
- *  Copyright 2002 Ryan Holm <ryan.holmQVist@idt.com>
- *  Copyright 2008 Florian Fainelli <florian@openwrt.org>
- *
- *  This program is free software; you can redistribute  it and/or modify it
- *  under  the terms of  the GNU General  Public License as published by the
- *  Free Software Foundation;  either version 2 of the  License, or (at your
- *  option) any later version.
- *
- *  THIS  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.
- *
- */
-
-#define PROM_ENTRY(x)		(0xbfc00000 + ((x) * 8))
-
-#define GPIO_INIT_NOBUTTON	""
-#define GPIO_INIT_BUTTON	" 2"
-
-#define SR_NMI			0x00180000
-#define SERIAL_SPEED_ENTRY	0x00000001
-
-#define FREQ_TAG		"HZ="
-#define GPIO_TAG		"gpio="
-#define KMAC_TAG		"kmac="
-#define MEM_TAG			"mem="
-#define BOARD_TAG		"board="
-
-#define BOARD_RB532		"500"
-#define BOARD_RB532A		"500r5"
diff --git a/include/asm-mips/mach-rc32434/rb.h b/include/asm-mips/mach-rc32434/rb.h
deleted file mode 100644
index e0a76e3..0000000
--- a/include/asm-mips/mach-rc32434/rb.h
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- *  GNU General Public License for more details.
- *
- *  Copyright (C) 2004 IDT Inc.
- *  Copyright (C) 2006 Felix Fietkau <nbd@openwrt.org>
- */
-#ifndef __ASM_RC32434_RB_H
-#define __ASM_RC32434_RB_H
-
-#include <linux/genhd.h>
-
-#define IDT434_REG_BASE	((volatile void *) KSEG1ADDR(0x18000000))
-#define DEV0BASE	0x010000
-#define DEV0MASK	0x010004
-#define DEV0C		0x010008
-#define DEV0T		0x01000C
-#define DEV1BASE	0x010010
-#define DEV1MASK	0x010014
-#define DEV1C		0x010018
-#define DEV1TC		0x01001C
-#define DEV2BASE	0x010020
-#define DEV2MASK	0x010024
-#define DEV2C		0x010028
-#define DEV2TC		0x01002C
-#define DEV3BASE	0x010030
-#define DEV3MASK	0x010034
-#define DEV3C		0x010038
-#define DEV3TC		0x01003C
-#define BTCS		0x010040
-#define BTCOMPARE	0x010044
-#define GPIOBASE	0x050000
-#define GPIOCFG		0x050004
-#define GPIOD		0x050008
-#define GPIOILEVEL	0x05000C
-#define GPIOISTAT	0x050010
-#define GPIONMIEN	0x050014
-#define IMASK6		0x038038
-#define LO_WPX		(1 << 0)
-#define LO_ALE		(1 << 1)
-#define LO_CLE		(1 << 2)
-#define LO_CEX		(1 << 3)
-#define LO_FOFF		(1 << 5)
-#define LO_SPICS	(1 << 6)
-#define LO_ULED		(1 << 7)
-
-#define BIT_TO_MASK(x)	(1 << x)
-
-struct dev_reg {
-	u32	base;
-	u32	mask;
-	u32	ctl;
-	u32	timing;
-};
-
-struct korina_device {
-	char *name;
-	unsigned char mac[6];
-	struct net_device *dev;
-};
-
-struct cf_device {
-	int gpio_pin;
-	void *dev;
-	struct gendisk *gd;
-};
-
-struct mpmc_device {
-	unsigned char	state;
-	spinlock_t	lock;
-	void __iomem 	*base;
-};
-
-#endif  /* __ASM_RC32434_RB_H */
diff --git a/include/asm-mips/mach-rc32434/rc32434.h b/include/asm-mips/mach-rc32434/rc32434.h
deleted file mode 100644
index c4a0214..0000000
--- a/include/asm-mips/mach-rc32434/rc32434.h
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Definitions for IDT RC323434 CPU.
- */
-
-#ifndef _ASM_RC32434_RC32434_H_
-#define _ASM_RC32434_RC32434_H_
-
-#include <linux/delay.h>
-#include <linux/io.h>
-
-#define RC32434_REG_BASE	0x18000000
-#define RC32434_RST		(1 << 15)
-
-#define IDT_CLOCK_MULT		2
-#define MIPS_CPU_TIMER_IRQ	7
-
-/* Interrupt Controller */
-#define IC_GROUP0_PEND		(RC32434_REG_BASE + 0x38000)
-#define IC_GROUP0_MASK		(RC32434_REG_BASE + 0x38008)
-#define IC_GROUP_OFFSET		0x0C
-
-#define NUM_INTR_GROUPS		5
-
-/* 16550 UARTs */
-#define GROUP0_IRQ_BASE		8	/* GRP2 IRQ numbers start here */
-					/* GRP3 IRQ numbers start here */
-#define GROUP1_IRQ_BASE		(GROUP0_IRQ_BASE + 32)
-					/* GRP4 IRQ numbers start here */
-#define GROUP2_IRQ_BASE		(GROUP1_IRQ_BASE + 32)
-					/* GRP5 IRQ numbers start here */
-#define GROUP3_IRQ_BASE		(GROUP2_IRQ_BASE + 32)
-#define GROUP4_IRQ_BASE		(GROUP3_IRQ_BASE + 32)
-
-
-#ifdef __MIPSEB__
-#define RC32434_UART0_BASE	(RC32434_REG_BASE + 0x58003)
-#else
-#define RC32434_UART0_BASE	(RC32434_REG_BASE + 0x58000)
-#endif
-
-#define RC32434_UART0_IRQ	(GROUP3_IRQ_BASE + 0)
-
-/* cpu pipeline flush */
-static inline void rc32434_sync(void)
-{
-	__asm__ volatile ("sync");
-}
-
-static inline void rc32434_sync_udelay(int us)
-{
-	__asm__ volatile ("sync");
-	udelay(us);
-}
-
-static inline void rc32434_sync_delay(int ms)
-{
-	__asm__ volatile ("sync");
-	mdelay(ms);
-}
-
-#endif  /* _ASM_RC32434_RC32434_H_ */
diff --git a/include/asm-mips/mipsregs.h b/include/asm-mips/mipsregs.h
deleted file mode 100644
index a46f8e2..0000000
--- a/include/asm-mips/mipsregs.h
+++ /dev/null
@@ -1,1526 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 1994, 1995, 1996, 1997, 2000, 2001 by Ralf Baechle
- * Copyright (C) 2000 Silicon Graphics, Inc.
- * Modified for further R[236]000 support by Paul M. Antoine, 1996.
- * Kevin D. Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com
- * Copyright (C) 2000, 07 MIPS Technologies, Inc.
- * Copyright (C) 2003, 2004  Maciej W. Rozycki
- */
-#ifndef _ASM_MIPSREGS_H
-#define _ASM_MIPSREGS_H
-
-#include <linux/linkage.h>
-#include <asm/hazards.h>
-#include <asm/war.h>
-
-/*
- * The following macros are especially useful for __asm__
- * inline assembler.
- */
-#ifndef __STR
-#define __STR(x) #x
-#endif
-#ifndef STR
-#define STR(x) __STR(x)
-#endif
-
-/*
- *  Configure language
- */
-#ifdef __ASSEMBLY__
-#define _ULCAST_
-#else
-#define _ULCAST_ (unsigned long)
-#endif
-
-/*
- * Coprocessor 0 register names
- */
-#define CP0_INDEX $0
-#define CP0_RANDOM $1
-#define CP0_ENTRYLO0 $2
-#define CP0_ENTRYLO1 $3
-#define CP0_CONF $3
-#define CP0_CONTEXT $4
-#define CP0_PAGEMASK $5
-#define CP0_WIRED $6
-#define CP0_INFO $7
-#define CP0_BADVADDR $8
-#define CP0_COUNT $9
-#define CP0_ENTRYHI $10
-#define CP0_COMPARE $11
-#define CP0_STATUS $12
-#define CP0_CAUSE $13
-#define CP0_EPC $14
-#define CP0_PRID $15
-#define CP0_CONFIG $16
-#define CP0_LLADDR $17
-#define CP0_WATCHLO $18
-#define CP0_WATCHHI $19
-#define CP0_XCONTEXT $20
-#define CP0_FRAMEMASK $21
-#define CP0_DIAGNOSTIC $22
-#define CP0_DEBUG $23
-#define CP0_DEPC $24
-#define CP0_PERFORMANCE $25
-#define CP0_ECC $26
-#define CP0_CACHEERR $27
-#define CP0_TAGLO $28
-#define CP0_TAGHI $29
-#define CP0_ERROREPC $30
-#define CP0_DESAVE $31
-
-/*
- * R4640/R4650 cp0 register names.  These registers are listed
- * here only for completeness; without MMU these CPUs are not useable
- * by Linux.  A future ELKS port might take make Linux run on them
- * though ...
- */
-#define CP0_IBASE $0
-#define CP0_IBOUND $1
-#define CP0_DBASE $2
-#define CP0_DBOUND $3
-#define CP0_CALG $17
-#define CP0_IWATCH $18
-#define CP0_DWATCH $19
-
-/*
- * Coprocessor 0 Set 1 register names
- */
-#define CP0_S1_DERRADDR0  $26
-#define CP0_S1_DERRADDR1  $27
-#define CP0_S1_INTCONTROL $20
-
-/*
- * Coprocessor 0 Set 2 register names
- */
-#define CP0_S2_SRSCTL	  $12	/* MIPSR2 */
-
-/*
- * Coprocessor 0 Set 3 register names
- */
-#define CP0_S3_SRSMAP	  $12	/* MIPSR2 */
-
-/*
- *  TX39 Series
- */
-#define CP0_TX39_CACHE	$7
-
-/*
- * Coprocessor 1 (FPU) register names
- */
-#define CP1_REVISION   $0
-#define CP1_STATUS     $31
-
-/*
- * FPU Status Register Values
- */
-/*
- * Status Register Values
- */
-
-#define FPU_CSR_FLUSH   0x01000000      /* flush denormalised results to 0 */
-#define FPU_CSR_COND    0x00800000      /* $fcc0 */
-#define FPU_CSR_COND0   0x00800000      /* $fcc0 */
-#define FPU_CSR_COND1   0x02000000      /* $fcc1 */
-#define FPU_CSR_COND2   0x04000000      /* $fcc2 */
-#define FPU_CSR_COND3   0x08000000      /* $fcc3 */
-#define FPU_CSR_COND4   0x10000000      /* $fcc4 */
-#define FPU_CSR_COND5   0x20000000      /* $fcc5 */
-#define FPU_CSR_COND6   0x40000000      /* $fcc6 */
-#define FPU_CSR_COND7   0x80000000      /* $fcc7 */
-
-/*
- * X the exception cause indicator
- * E the exception enable
- * S the sticky/flag bit
-*/
-#define FPU_CSR_ALL_X   0x0003f000
-#define FPU_CSR_UNI_X   0x00020000
-#define FPU_CSR_INV_X   0x00010000
-#define FPU_CSR_DIV_X   0x00008000
-#define FPU_CSR_OVF_X   0x00004000
-#define FPU_CSR_UDF_X   0x00002000
-#define FPU_CSR_INE_X   0x00001000
-
-#define FPU_CSR_ALL_E   0x00000f80
-#define FPU_CSR_INV_E   0x00000800
-#define FPU_CSR_DIV_E   0x00000400
-#define FPU_CSR_OVF_E   0x00000200
-#define FPU_CSR_UDF_E   0x00000100
-#define FPU_CSR_INE_E   0x00000080
-
-#define FPU_CSR_ALL_S   0x0000007c
-#define FPU_CSR_INV_S   0x00000040
-#define FPU_CSR_DIV_S   0x00000020
-#define FPU_CSR_OVF_S   0x00000010
-#define FPU_CSR_UDF_S   0x00000008
-#define FPU_CSR_INE_S   0x00000004
-
-/* rounding mode */
-#define FPU_CSR_RN      0x0     /* nearest */
-#define FPU_CSR_RZ      0x1     /* towards zero */
-#define FPU_CSR_RU      0x2     /* towards +Infinity */
-#define FPU_CSR_RD      0x3     /* towards -Infinity */
-
-
-/*
- * Values for PageMask register
- */
-#ifdef CONFIG_CPU_VR41XX
-
-/* Why doesn't stupidity hurt ... */
-
-#define PM_1K		0x00000000
-#define PM_4K		0x00001800
-#define PM_16K		0x00007800
-#define PM_64K		0x0001f800
-#define PM_256K		0x0007f800
-
-#else
-
-#define PM_4K		0x00000000
-#define PM_16K		0x00006000
-#define PM_64K		0x0001e000
-#define PM_256K		0x0007e000
-#define PM_1M		0x001fe000
-#define PM_4M		0x007fe000
-#define PM_16M		0x01ffe000
-#define PM_64M		0x07ffe000
-#define PM_256M		0x1fffe000
-
-#endif
-
-/*
- * Default page size for a given kernel configuration
- */
-#ifdef CONFIG_PAGE_SIZE_4KB
-#define PM_DEFAULT_MASK	PM_4K
-#elif defined(CONFIG_PAGE_SIZE_16KB)
-#define PM_DEFAULT_MASK	PM_16K
-#elif defined(CONFIG_PAGE_SIZE_64KB)
-#define PM_DEFAULT_MASK	PM_64K
-#else
-#error Bad page size configuration!
-#endif
-
-
-/*
- * Values used for computation of new tlb entries
- */
-#define PL_4K		12
-#define PL_16K		14
-#define PL_64K		16
-#define PL_256K		18
-#define PL_1M		20
-#define PL_4M		22
-#define PL_16M		24
-#define PL_64M		26
-#define PL_256M		28
-
-/*
- * R4x00 interrupt enable / cause bits
- */
-#define IE_SW0          (_ULCAST_(1) <<  8)
-#define IE_SW1          (_ULCAST_(1) <<  9)
-#define IE_IRQ0         (_ULCAST_(1) << 10)
-#define IE_IRQ1         (_ULCAST_(1) << 11)
-#define IE_IRQ2         (_ULCAST_(1) << 12)
-#define IE_IRQ3         (_ULCAST_(1) << 13)
-#define IE_IRQ4         (_ULCAST_(1) << 14)
-#define IE_IRQ5         (_ULCAST_(1) << 15)
-
-/*
- * R4x00 interrupt cause bits
- */
-#define C_SW0           (_ULCAST_(1) <<  8)
-#define C_SW1           (_ULCAST_(1) <<  9)
-#define C_IRQ0          (_ULCAST_(1) << 10)
-#define C_IRQ1          (_ULCAST_(1) << 11)
-#define C_IRQ2          (_ULCAST_(1) << 12)
-#define C_IRQ3          (_ULCAST_(1) << 13)
-#define C_IRQ4          (_ULCAST_(1) << 14)
-#define C_IRQ5          (_ULCAST_(1) << 15)
-
-/*
- * Bitfields in the R4xx0 cp0 status register
- */
-#define ST0_IE			0x00000001
-#define ST0_EXL			0x00000002
-#define ST0_ERL			0x00000004
-#define ST0_KSU			0x00000018
-#  define KSU_USER		0x00000010
-#  define KSU_SUPERVISOR	0x00000008
-#  define KSU_KERNEL		0x00000000
-#define ST0_UX			0x00000020
-#define ST0_SX			0x00000040
-#define ST0_KX 			0x00000080
-#define ST0_DE			0x00010000
-#define ST0_CE			0x00020000
-
-/*
- * Setting c0_status.co enables Hit_Writeback and Hit_Writeback_Invalidate
- * cacheops in userspace.  This bit exists only on RM7000 and RM9000
- * processors.
- */
-#define ST0_CO			0x08000000
-
-/*
- * Bitfields in the R[23]000 cp0 status register.
- */
-#define ST0_IEC                 0x00000001
-#define ST0_KUC			0x00000002
-#define ST0_IEP			0x00000004
-#define ST0_KUP			0x00000008
-#define ST0_IEO			0x00000010
-#define ST0_KUO			0x00000020
-/* bits 6 & 7 are reserved on R[23]000 */
-#define ST0_ISC			0x00010000
-#define ST0_SWC			0x00020000
-#define ST0_CM			0x00080000
-
-/*
- * Bits specific to the R4640/R4650
- */
-#define ST0_UM			(_ULCAST_(1) <<  4)
-#define ST0_IL			(_ULCAST_(1) << 23)
-#define ST0_DL			(_ULCAST_(1) << 24)
-
-/*
- * Enable the MIPS MDMX and DSP ASEs
- */
-#define ST0_MX			0x01000000
-
-/*
- * Bitfields in the TX39 family CP0 Configuration Register 3
- */
-#define TX39_CONF_ICS_SHIFT	19
-#define TX39_CONF_ICS_MASK	0x00380000
-#define TX39_CONF_ICS_1KB 	0x00000000
-#define TX39_CONF_ICS_2KB 	0x00080000
-#define TX39_CONF_ICS_4KB 	0x00100000
-#define TX39_CONF_ICS_8KB 	0x00180000
-#define TX39_CONF_ICS_16KB 	0x00200000
-
-#define TX39_CONF_DCS_SHIFT	16
-#define TX39_CONF_DCS_MASK	0x00070000
-#define TX39_CONF_DCS_1KB 	0x00000000
-#define TX39_CONF_DCS_2KB 	0x00010000
-#define TX39_CONF_DCS_4KB 	0x00020000
-#define TX39_CONF_DCS_8KB 	0x00030000
-#define TX39_CONF_DCS_16KB 	0x00040000
-
-#define TX39_CONF_CWFON 	0x00004000
-#define TX39_CONF_WBON  	0x00002000
-#define TX39_CONF_RF_SHIFT	10
-#define TX39_CONF_RF_MASK	0x00000c00
-#define TX39_CONF_DOZE		0x00000200
-#define TX39_CONF_HALT		0x00000100
-#define TX39_CONF_LOCK		0x00000080
-#define TX39_CONF_ICE		0x00000020
-#define TX39_CONF_DCE		0x00000010
-#define TX39_CONF_IRSIZE_SHIFT	2
-#define TX39_CONF_IRSIZE_MASK	0x0000000c
-#define TX39_CONF_DRSIZE_SHIFT	0
-#define TX39_CONF_DRSIZE_MASK	0x00000003
-
-/*
- * Status register bits available in all MIPS CPUs.
- */
-#define ST0_IM			0x0000ff00
-#define  STATUSB_IP0		8
-#define  STATUSF_IP0		(_ULCAST_(1) <<  8)
-#define  STATUSB_IP1		9
-#define  STATUSF_IP1		(_ULCAST_(1) <<  9)
-#define  STATUSB_IP2		10
-#define  STATUSF_IP2		(_ULCAST_(1) << 10)
-#define  STATUSB_IP3		11
-#define  STATUSF_IP3		(_ULCAST_(1) << 11)
-#define  STATUSB_IP4		12
-#define  STATUSF_IP4		(_ULCAST_(1) << 12)
-#define  STATUSB_IP5		13
-#define  STATUSF_IP5		(_ULCAST_(1) << 13)
-#define  STATUSB_IP6		14
-#define  STATUSF_IP6		(_ULCAST_(1) << 14)
-#define  STATUSB_IP7		15
-#define  STATUSF_IP7		(_ULCAST_(1) << 15)
-#define  STATUSB_IP8		0
-#define  STATUSF_IP8		(_ULCAST_(1) <<  0)
-#define  STATUSB_IP9		1
-#define  STATUSF_IP9		(_ULCAST_(1) <<  1)
-#define  STATUSB_IP10		2
-#define  STATUSF_IP10		(_ULCAST_(1) <<  2)
-#define  STATUSB_IP11		3
-#define  STATUSF_IP11		(_ULCAST_(1) <<  3)
-#define  STATUSB_IP12		4
-#define  STATUSF_IP12		(_ULCAST_(1) <<  4)
-#define  STATUSB_IP13		5
-#define  STATUSF_IP13		(_ULCAST_(1) <<  5)
-#define  STATUSB_IP14		6
-#define  STATUSF_IP14		(_ULCAST_(1) <<  6)
-#define  STATUSB_IP15		7
-#define  STATUSF_IP15		(_ULCAST_(1) <<  7)
-#define ST0_CH			0x00040000
-#define ST0_SR			0x00100000
-#define ST0_TS			0x00200000
-#define ST0_BEV			0x00400000
-#define ST0_RE			0x02000000
-#define ST0_FR			0x04000000
-#define ST0_CU			0xf0000000
-#define ST0_CU0			0x10000000
-#define ST0_CU1			0x20000000
-#define ST0_CU2			0x40000000
-#define ST0_CU3			0x80000000
-#define ST0_XX			0x80000000	/* MIPS IV naming */
-
-/*
- * Bitfields and bit numbers in the coprocessor 0 cause register.
- *
- * Refer to your MIPS R4xx0 manual, chapter 5 for explanation.
- */
-#define  CAUSEB_EXCCODE		2
-#define  CAUSEF_EXCCODE		(_ULCAST_(31)  <<  2)
-#define  CAUSEB_IP		8
-#define  CAUSEF_IP		(_ULCAST_(255) <<  8)
-#define  CAUSEB_IP0		8
-#define  CAUSEF_IP0		(_ULCAST_(1)   <<  8)
-#define  CAUSEB_IP1		9
-#define  CAUSEF_IP1		(_ULCAST_(1)   <<  9)
-#define  CAUSEB_IP2		10
-#define  CAUSEF_IP2		(_ULCAST_(1)   << 10)
-#define  CAUSEB_IP3		11
-#define  CAUSEF_IP3		(_ULCAST_(1)   << 11)
-#define  CAUSEB_IP4		12
-#define  CAUSEF_IP4		(_ULCAST_(1)   << 12)
-#define  CAUSEB_IP5		13
-#define  CAUSEF_IP5		(_ULCAST_(1)   << 13)
-#define  CAUSEB_IP6		14
-#define  CAUSEF_IP6		(_ULCAST_(1)   << 14)
-#define  CAUSEB_IP7		15
-#define  CAUSEF_IP7		(_ULCAST_(1)   << 15)
-#define  CAUSEB_IV		23
-#define  CAUSEF_IV		(_ULCAST_(1)   << 23)
-#define  CAUSEB_CE		28
-#define  CAUSEF_CE		(_ULCAST_(3)   << 28)
-#define  CAUSEB_BD		31
-#define  CAUSEF_BD		(_ULCAST_(1)   << 31)
-
-/*
- * Bits in the coprocessor 0 config register.
- */
-/* Generic bits.  */
-#define CONF_CM_CACHABLE_NO_WA		0
-#define CONF_CM_CACHABLE_WA		1
-#define CONF_CM_UNCACHED		2
-#define CONF_CM_CACHABLE_NONCOHERENT	3
-#define CONF_CM_CACHABLE_CE		4
-#define CONF_CM_CACHABLE_COW		5
-#define CONF_CM_CACHABLE_CUW		6
-#define CONF_CM_CACHABLE_ACCELERATED	7
-#define CONF_CM_CMASK			7
-#define CONF_BE			(_ULCAST_(1) << 15)
-
-/* Bits common to various processors.  */
-#define CONF_CU			(_ULCAST_(1) <<  3)
-#define CONF_DB			(_ULCAST_(1) <<  4)
-#define CONF_IB			(_ULCAST_(1) <<  5)
-#define CONF_DC			(_ULCAST_(7) <<  6)
-#define CONF_IC			(_ULCAST_(7) <<  9)
-#define CONF_EB			(_ULCAST_(1) << 13)
-#define CONF_EM			(_ULCAST_(1) << 14)
-#define CONF_SM			(_ULCAST_(1) << 16)
-#define CONF_SC			(_ULCAST_(1) << 17)
-#define CONF_EW			(_ULCAST_(3) << 18)
-#define CONF_EP			(_ULCAST_(15)<< 24)
-#define CONF_EC			(_ULCAST_(7) << 28)
-#define CONF_CM			(_ULCAST_(1) << 31)
-
-/* Bits specific to the R4xx0.  */
-#define R4K_CONF_SW		(_ULCAST_(1) << 20)
-#define R4K_CONF_SS		(_ULCAST_(1) << 21)
-#define R4K_CONF_SB		(_ULCAST_(3) << 22)
-
-/* Bits specific to the R5000.  */
-#define R5K_CONF_SE		(_ULCAST_(1) << 12)
-#define R5K_CONF_SS		(_ULCAST_(3) << 20)
-
-/* Bits specific to the RM7000.  */
-#define RM7K_CONF_SE		(_ULCAST_(1) <<  3)
-#define RM7K_CONF_TE		(_ULCAST_(1) << 12)
-#define RM7K_CONF_CLK		(_ULCAST_(1) << 16)
-#define RM7K_CONF_TC		(_ULCAST_(1) << 17)
-#define RM7K_CONF_SI		(_ULCAST_(3) << 20)
-#define RM7K_CONF_SC		(_ULCAST_(1) << 31)
-
-/* Bits specific to the R10000.  */
-#define R10K_CONF_DN		(_ULCAST_(3) <<  3)
-#define R10K_CONF_CT		(_ULCAST_(1) <<  5)
-#define R10K_CONF_PE		(_ULCAST_(1) <<  6)
-#define R10K_CONF_PM		(_ULCAST_(3) <<  7)
-#define R10K_CONF_EC		(_ULCAST_(15)<<  9)
-#define R10K_CONF_SB		(_ULCAST_(1) << 13)
-#define R10K_CONF_SK		(_ULCAST_(1) << 14)
-#define R10K_CONF_SS		(_ULCAST_(7) << 16)
-#define R10K_CONF_SC		(_ULCAST_(7) << 19)
-#define R10K_CONF_DC		(_ULCAST_(7) << 26)
-#define R10K_CONF_IC		(_ULCAST_(7) << 29)
-
-/* Bits specific to the VR41xx.  */
-#define VR41_CONF_CS		(_ULCAST_(1) << 12)
-#define VR41_CONF_P4K		(_ULCAST_(1) << 13)
-#define VR41_CONF_BP		(_ULCAST_(1) << 16)
-#define VR41_CONF_M16		(_ULCAST_(1) << 20)
-#define VR41_CONF_AD		(_ULCAST_(1) << 23)
-
-/* Bits specific to the R30xx.  */
-#define R30XX_CONF_FDM		(_ULCAST_(1) << 19)
-#define R30XX_CONF_REV		(_ULCAST_(1) << 22)
-#define R30XX_CONF_AC		(_ULCAST_(1) << 23)
-#define R30XX_CONF_RF		(_ULCAST_(1) << 24)
-#define R30XX_CONF_HALT		(_ULCAST_(1) << 25)
-#define R30XX_CONF_FPINT	(_ULCAST_(7) << 26)
-#define R30XX_CONF_DBR		(_ULCAST_(1) << 29)
-#define R30XX_CONF_SB		(_ULCAST_(1) << 30)
-#define R30XX_CONF_LOCK		(_ULCAST_(1) << 31)
-
-/* Bits specific to the TX49.  */
-#define TX49_CONF_DC		(_ULCAST_(1) << 16)
-#define TX49_CONF_IC		(_ULCAST_(1) << 17)  /* conflict with CONF_SC */
-#define TX49_CONF_HALT		(_ULCAST_(1) << 18)
-#define TX49_CONF_CWFON		(_ULCAST_(1) << 27)
-
-/* Bits specific to the MIPS32/64 PRA.  */
-#define MIPS_CONF_MT		(_ULCAST_(7) <<  7)
-#define MIPS_CONF_AR		(_ULCAST_(7) << 10)
-#define MIPS_CONF_AT		(_ULCAST_(3) << 13)
-#define MIPS_CONF_M		(_ULCAST_(1) << 31)
-
-/*
- * Bits in the MIPS32/64 PRA coprocessor 0 config registers 1 and above.
- */
-#define MIPS_CONF1_FP		(_ULCAST_(1) <<  0)
-#define MIPS_CONF1_EP		(_ULCAST_(1) <<  1)
-#define MIPS_CONF1_CA		(_ULCAST_(1) <<  2)
-#define MIPS_CONF1_WR		(_ULCAST_(1) <<  3)
-#define MIPS_CONF1_PC		(_ULCAST_(1) <<  4)
-#define MIPS_CONF1_MD		(_ULCAST_(1) <<  5)
-#define MIPS_CONF1_C2		(_ULCAST_(1) <<  6)
-#define MIPS_CONF1_DA		(_ULCAST_(7) <<  7)
-#define MIPS_CONF1_DL		(_ULCAST_(7) << 10)
-#define MIPS_CONF1_DS		(_ULCAST_(7) << 13)
-#define MIPS_CONF1_IA		(_ULCAST_(7) << 16)
-#define MIPS_CONF1_IL		(_ULCAST_(7) << 19)
-#define MIPS_CONF1_IS		(_ULCAST_(7) << 22)
-#define MIPS_CONF1_TLBS		(_ULCAST_(63)<< 25)
-
-#define MIPS_CONF2_SA		(_ULCAST_(15)<<  0)
-#define MIPS_CONF2_SL		(_ULCAST_(15)<<  4)
-#define MIPS_CONF2_SS		(_ULCAST_(15)<<  8)
-#define MIPS_CONF2_SU		(_ULCAST_(15)<< 12)
-#define MIPS_CONF2_TA		(_ULCAST_(15)<< 16)
-#define MIPS_CONF2_TL		(_ULCAST_(15)<< 20)
-#define MIPS_CONF2_TS		(_ULCAST_(15)<< 24)
-#define MIPS_CONF2_TU		(_ULCAST_(7) << 28)
-
-#define MIPS_CONF3_TL		(_ULCAST_(1) <<  0)
-#define MIPS_CONF3_SM		(_ULCAST_(1) <<  1)
-#define MIPS_CONF3_MT		(_ULCAST_(1) <<  2)
-#define MIPS_CONF3_SP		(_ULCAST_(1) <<  4)
-#define MIPS_CONF3_VINT		(_ULCAST_(1) <<  5)
-#define MIPS_CONF3_VEIC		(_ULCAST_(1) <<  6)
-#define MIPS_CONF3_LPA		(_ULCAST_(1) <<  7)
-#define MIPS_CONF3_DSP		(_ULCAST_(1) << 10)
-#define MIPS_CONF3_ULRI		(_ULCAST_(1) << 13)
-
-#define MIPS_CONF7_WII		(_ULCAST_(1) << 31)
-
-#define MIPS_CONF7_RPS		(_ULCAST_(1) << 2)
-
-
-/*
- * Bits in the MIPS32/64 coprocessor 1 (FPU) revision register.
- */
-#define MIPS_FPIR_S		(_ULCAST_(1) << 16)
-#define MIPS_FPIR_D		(_ULCAST_(1) << 17)
-#define MIPS_FPIR_PS		(_ULCAST_(1) << 18)
-#define MIPS_FPIR_3D		(_ULCAST_(1) << 19)
-#define MIPS_FPIR_W		(_ULCAST_(1) << 20)
-#define MIPS_FPIR_L		(_ULCAST_(1) << 21)
-#define MIPS_FPIR_F64		(_ULCAST_(1) << 22)
-
-#ifndef __ASSEMBLY__
-
-/*
- * Functions to access the R10000 performance counters.  These are basically
- * mfc0 and mtc0 instructions from and to coprocessor register with a 5-bit
- * performance counter number encoded into bits 1 ... 5 of the instruction.
- * Only performance counters 0 to 1 actually exist, so for a non-R10000 aware
- * disassembler these will look like an access to sel 0 or 1.
- */
-#define read_r10k_perf_cntr(counter)				\
-({								\
-	unsigned int __res;					\
-	__asm__ __volatile__(					\
-	"mfpc\t%0, %1"						\
-        : "=r" (__res)						\
-	: "i" (counter));					\
-								\
-        __res;							\
-})
-
-#define write_r10k_perf_cntr(counter,val)                       \
-do {								\
-	__asm__ __volatile__(					\
-	"mtpc\t%0, %1"						\
-	:							\
-	: "r" (val), "i" (counter));				\
-} while (0)
-
-#define read_r10k_perf_event(counter)				\
-({								\
-	unsigned int __res;					\
-	__asm__ __volatile__(					\
-	"mfps\t%0, %1"						\
-        : "=r" (__res)						\
-	: "i" (counter));					\
-								\
-        __res;							\
-})
-
-#define write_r10k_perf_cntl(counter,val)                       \
-do {								\
-	__asm__ __volatile__(					\
-	"mtps\t%0, %1"						\
-	:							\
-	: "r" (val), "i" (counter));				\
-} while (0)
-
-
-/*
- * Macros to access the system control coprocessor
- */
-
-#define __read_32bit_c0_register(source, sel)				\
-({ int __res;								\
-	if (sel == 0)							\
-		__asm__ __volatile__(					\
-			"mfc0\t%0, " #source "\n\t"			\
-			: "=r" (__res));				\
-	else								\
-		__asm__ __volatile__(					\
-			".set\tmips32\n\t"				\
-			"mfc0\t%0, " #source ", " #sel "\n\t"		\
-			".set\tmips0\n\t"				\
-			: "=r" (__res));				\
-	__res;								\
-})
-
-#define __read_64bit_c0_register(source, sel)				\
-({ unsigned long long __res;						\
-	if (sizeof(unsigned long) == 4)					\
-		__res = __read_64bit_c0_split(source, sel);		\
-	else if (sel == 0)						\
-		__asm__ __volatile__(					\
-			".set\tmips3\n\t"				\
-			"dmfc0\t%0, " #source "\n\t"			\
-			".set\tmips0"					\
-			: "=r" (__res));				\
-	else								\
-		__asm__ __volatile__(					\
-			".set\tmips64\n\t"				\
-			"dmfc0\t%0, " #source ", " #sel "\n\t"		\
-			".set\tmips0"					\
-			: "=r" (__res));				\
-	__res;								\
-})
-
-#define __write_32bit_c0_register(register, sel, value)			\
-do {									\
-	if (sel == 0)							\
-		__asm__ __volatile__(					\
-			"mtc0\t%z0, " #register "\n\t"			\
-			: : "Jr" ((unsigned int)(value)));		\
-	else								\
-		__asm__ __volatile__(					\
-			".set\tmips32\n\t"				\
-			"mtc0\t%z0, " #register ", " #sel "\n\t"	\
-			".set\tmips0"					\
-			: : "Jr" ((unsigned int)(value)));		\
-} while (0)
-
-#define __write_64bit_c0_register(register, sel, value)			\
-do {									\
-	if (sizeof(unsigned long) == 4)					\
-		__write_64bit_c0_split(register, sel, value);		\
-	else if (sel == 0)						\
-		__asm__ __volatile__(					\
-			".set\tmips3\n\t"				\
-			"dmtc0\t%z0, " #register "\n\t"			\
-			".set\tmips0"					\
-			: : "Jr" (value));				\
-	else								\
-		__asm__ __volatile__(					\
-			".set\tmips64\n\t"				\
-			"dmtc0\t%z0, " #register ", " #sel "\n\t"	\
-			".set\tmips0"					\
-			: : "Jr" (value));				\
-} while (0)
-
-#define __read_ulong_c0_register(reg, sel)				\
-	((sizeof(unsigned long) == 4) ?					\
-	(unsigned long) __read_32bit_c0_register(reg, sel) :		\
-	(unsigned long) __read_64bit_c0_register(reg, sel))
-
-#define __write_ulong_c0_register(reg, sel, val)			\
-do {									\
-	if (sizeof(unsigned long) == 4)					\
-		__write_32bit_c0_register(reg, sel, val);		\
-	else								\
-		__write_64bit_c0_register(reg, sel, val);		\
-} while (0)
-
-/*
- * On RM7000/RM9000 these are uses to access cop0 set 1 registers
- */
-#define __read_32bit_c0_ctrl_register(source)				\
-({ int __res;								\
-	__asm__ __volatile__(						\
-		"cfc0\t%0, " #source "\n\t"				\
-		: "=r" (__res));					\
-	__res;								\
-})
-
-#define __write_32bit_c0_ctrl_register(register, value)			\
-do {									\
-	__asm__ __volatile__(						\
-		"ctc0\t%z0, " #register "\n\t"				\
-		: : "Jr" ((unsigned int)(value)));			\
-} while (0)
-
-/*
- * These versions are only needed for systems with more than 38 bits of
- * physical address space running the 32-bit kernel.  That's none atm :-)
- */
-#define __read_64bit_c0_split(source, sel)				\
-({									\
-	unsigned long long __val;					\
-	unsigned long __flags;						\
-									\
-	local_irq_save(__flags);					\
-	if (sel == 0)							\
-		__asm__ __volatile__(					\
-			".set\tmips64\n\t"				\
-			"dmfc0\t%M0, " #source "\n\t"			\
-			"dsll\t%L0, %M0, 32\n\t"			\
-			"dsrl\t%M0, %M0, 32\n\t"			\
-			"dsrl\t%L0, %L0, 32\n\t"			\
-			".set\tmips0"					\
-			: "=r" (__val));				\
-	else								\
-		__asm__ __volatile__(					\
-			".set\tmips64\n\t"				\
-			"dmfc0\t%M0, " #source ", " #sel "\n\t"		\
-			"dsll\t%L0, %M0, 32\n\t"			\
-			"dsrl\t%M0, %M0, 32\n\t"			\
-			"dsrl\t%L0, %L0, 32\n\t"			\
-			".set\tmips0"					\
-			: "=r" (__val));				\
-	local_irq_restore(__flags);					\
-									\
-	__val;								\
-})
-
-#define __write_64bit_c0_split(source, sel, val)			\
-do {									\
-	unsigned long __flags;						\
-									\
-	local_irq_save(__flags);					\
-	if (sel == 0)							\
-		__asm__ __volatile__(					\
-			".set\tmips64\n\t"				\
-			"dsll\t%L0, %L0, 32\n\t"			\
-			"dsrl\t%L0, %L0, 32\n\t"			\
-			"dsll\t%M0, %M0, 32\n\t"			\
-			"or\t%L0, %L0, %M0\n\t"				\
-			"dmtc0\t%L0, " #source "\n\t"			\
-			".set\tmips0"					\
-			: : "r" (val));					\
-	else								\
-		__asm__ __volatile__(					\
-			".set\tmips64\n\t"				\
-			"dsll\t%L0, %L0, 32\n\t"			\
-			"dsrl\t%L0, %L0, 32\n\t"			\
-			"dsll\t%M0, %M0, 32\n\t"			\
-			"or\t%L0, %L0, %M0\n\t"				\
-			"dmtc0\t%L0, " #source ", " #sel "\n\t"		\
-			".set\tmips0"					\
-			: : "r" (val));					\
-	local_irq_restore(__flags);					\
-} while (0)
-
-#define read_c0_index()		__read_32bit_c0_register($0, 0)
-#define write_c0_index(val)	__write_32bit_c0_register($0, 0, val)
-
-#define read_c0_random()	__read_32bit_c0_register($1, 0)
-#define write_c0_random(val)	__write_32bit_c0_register($1, 0, val)
-
-#define read_c0_entrylo0()	__read_ulong_c0_register($2, 0)
-#define write_c0_entrylo0(val)	__write_ulong_c0_register($2, 0, val)
-
-#define read_c0_entrylo1()	__read_ulong_c0_register($3, 0)
-#define write_c0_entrylo1(val)	__write_ulong_c0_register($3, 0, val)
-
-#define read_c0_conf()		__read_32bit_c0_register($3, 0)
-#define write_c0_conf(val)	__write_32bit_c0_register($3, 0, val)
-
-#define read_c0_context()	__read_ulong_c0_register($4, 0)
-#define write_c0_context(val)	__write_ulong_c0_register($4, 0, val)
-
-#define read_c0_userlocal()	__read_ulong_c0_register($4, 2)
-#define write_c0_userlocal(val)	__write_ulong_c0_register($4, 2, val)
-
-#define read_c0_pagemask()	__read_32bit_c0_register($5, 0)
-#define write_c0_pagemask(val)	__write_32bit_c0_register($5, 0, val)
-
-#define read_c0_wired()		__read_32bit_c0_register($6, 0)
-#define write_c0_wired(val)	__write_32bit_c0_register($6, 0, val)
-
-#define read_c0_info()		__read_32bit_c0_register($7, 0)
-
-#define read_c0_cache()		__read_32bit_c0_register($7, 0)	/* TX39xx */
-#define write_c0_cache(val)	__write_32bit_c0_register($7, 0, val)
-
-#define read_c0_badvaddr()	__read_ulong_c0_register($8, 0)
-#define write_c0_badvaddr(val)	__write_ulong_c0_register($8, 0, val)
-
-#define read_c0_count()		__read_32bit_c0_register($9, 0)
-#define write_c0_count(val)	__write_32bit_c0_register($9, 0, val)
-
-#define read_c0_count2()	__read_32bit_c0_register($9, 6) /* pnx8550 */
-#define write_c0_count2(val)	__write_32bit_c0_register($9, 6, val)
-
-#define read_c0_count3()	__read_32bit_c0_register($9, 7) /* pnx8550 */
-#define write_c0_count3(val)	__write_32bit_c0_register($9, 7, val)
-
-#define read_c0_entryhi()	__read_ulong_c0_register($10, 0)
-#define write_c0_entryhi(val)	__write_ulong_c0_register($10, 0, val)
-
-#define read_c0_compare()	__read_32bit_c0_register($11, 0)
-#define write_c0_compare(val)	__write_32bit_c0_register($11, 0, val)
-
-#define read_c0_compare2()	__read_32bit_c0_register($11, 6) /* pnx8550 */
-#define write_c0_compare2(val)	__write_32bit_c0_register($11, 6, val)
-
-#define read_c0_compare3()	__read_32bit_c0_register($11, 7) /* pnx8550 */
-#define write_c0_compare3(val)	__write_32bit_c0_register($11, 7, val)
-
-#define read_c0_status()	__read_32bit_c0_register($12, 0)
-#ifdef CONFIG_MIPS_MT_SMTC
-#define write_c0_status(val)						\
-do {									\
-	__write_32bit_c0_register($12, 0, val);				\
-	__ehb();							\
-} while (0)
-#else
-/*
- * Legacy non-SMTC code, which may be hazardous
- * but which might not support EHB
- */
-#define write_c0_status(val)	__write_32bit_c0_register($12, 0, val)
-#endif /* CONFIG_MIPS_MT_SMTC */
-
-#define read_c0_cause()		__read_32bit_c0_register($13, 0)
-#define write_c0_cause(val)	__write_32bit_c0_register($13, 0, val)
-
-#define read_c0_epc()		__read_ulong_c0_register($14, 0)
-#define write_c0_epc(val)	__write_ulong_c0_register($14, 0, val)
-
-#define read_c0_prid()		__read_32bit_c0_register($15, 0)
-
-#define read_c0_config()	__read_32bit_c0_register($16, 0)
-#define read_c0_config1()	__read_32bit_c0_register($16, 1)
-#define read_c0_config2()	__read_32bit_c0_register($16, 2)
-#define read_c0_config3()	__read_32bit_c0_register($16, 3)
-#define read_c0_config4()	__read_32bit_c0_register($16, 4)
-#define read_c0_config5()	__read_32bit_c0_register($16, 5)
-#define read_c0_config6()	__read_32bit_c0_register($16, 6)
-#define read_c0_config7()	__read_32bit_c0_register($16, 7)
-#define write_c0_config(val)	__write_32bit_c0_register($16, 0, val)
-#define write_c0_config1(val)	__write_32bit_c0_register($16, 1, val)
-#define write_c0_config2(val)	__write_32bit_c0_register($16, 2, val)
-#define write_c0_config3(val)	__write_32bit_c0_register($16, 3, val)
-#define write_c0_config4(val)	__write_32bit_c0_register($16, 4, val)
-#define write_c0_config5(val)	__write_32bit_c0_register($16, 5, val)
-#define write_c0_config6(val)	__write_32bit_c0_register($16, 6, val)
-#define write_c0_config7(val)	__write_32bit_c0_register($16, 7, val)
-
-/*
- * The WatchLo register.  There may be upto 8 of them.
- */
-#define read_c0_watchlo0()	__read_ulong_c0_register($18, 0)
-#define read_c0_watchlo1()	__read_ulong_c0_register($18, 1)
-#define read_c0_watchlo2()	__read_ulong_c0_register($18, 2)
-#define read_c0_watchlo3()	__read_ulong_c0_register($18, 3)
-#define read_c0_watchlo4()	__read_ulong_c0_register($18, 4)
-#define read_c0_watchlo5()	__read_ulong_c0_register($18, 5)
-#define read_c0_watchlo6()	__read_ulong_c0_register($18, 6)
-#define read_c0_watchlo7()	__read_ulong_c0_register($18, 7)
-#define write_c0_watchlo0(val)	__write_ulong_c0_register($18, 0, val)
-#define write_c0_watchlo1(val)	__write_ulong_c0_register($18, 1, val)
-#define write_c0_watchlo2(val)	__write_ulong_c0_register($18, 2, val)
-#define write_c0_watchlo3(val)	__write_ulong_c0_register($18, 3, val)
-#define write_c0_watchlo4(val)	__write_ulong_c0_register($18, 4, val)
-#define write_c0_watchlo5(val)	__write_ulong_c0_register($18, 5, val)
-#define write_c0_watchlo6(val)	__write_ulong_c0_register($18, 6, val)
-#define write_c0_watchlo7(val)	__write_ulong_c0_register($18, 7, val)
-
-/*
- * The WatchHi register.  There may be upto 8 of them.
- */
-#define read_c0_watchhi0()	__read_32bit_c0_register($19, 0)
-#define read_c0_watchhi1()	__read_32bit_c0_register($19, 1)
-#define read_c0_watchhi2()	__read_32bit_c0_register($19, 2)
-#define read_c0_watchhi3()	__read_32bit_c0_register($19, 3)
-#define read_c0_watchhi4()	__read_32bit_c0_register($19, 4)
-#define read_c0_watchhi5()	__read_32bit_c0_register($19, 5)
-#define read_c0_watchhi6()	__read_32bit_c0_register($19, 6)
-#define read_c0_watchhi7()	__read_32bit_c0_register($19, 7)
-
-#define write_c0_watchhi0(val)	__write_32bit_c0_register($19, 0, val)
-#define write_c0_watchhi1(val)	__write_32bit_c0_register($19, 1, val)
-#define write_c0_watchhi2(val)	__write_32bit_c0_register($19, 2, val)
-#define write_c0_watchhi3(val)	__write_32bit_c0_register($19, 3, val)
-#define write_c0_watchhi4(val)	__write_32bit_c0_register($19, 4, val)
-#define write_c0_watchhi5(val)	__write_32bit_c0_register($19, 5, val)
-#define write_c0_watchhi6(val)	__write_32bit_c0_register($19, 6, val)
-#define write_c0_watchhi7(val)	__write_32bit_c0_register($19, 7, val)
-
-#define read_c0_xcontext()	__read_ulong_c0_register($20, 0)
-#define write_c0_xcontext(val)	__write_ulong_c0_register($20, 0, val)
-
-#define read_c0_intcontrol()	__read_32bit_c0_ctrl_register($20)
-#define write_c0_intcontrol(val) __write_32bit_c0_ctrl_register($20, val)
-
-#define read_c0_framemask()	__read_32bit_c0_register($21, 0)
-#define write_c0_framemask(val)	__write_32bit_c0_register($21, 0, val)
-
-/* RM9000 PerfControl performance counter control register */
-#define read_c0_perfcontrol()	__read_32bit_c0_register($22, 0)
-#define write_c0_perfcontrol(val) __write_32bit_c0_register($22, 0, val)
-
-#define read_c0_diag()		__read_32bit_c0_register($22, 0)
-#define write_c0_diag(val)	__write_32bit_c0_register($22, 0, val)
-
-#define read_c0_diag1()		__read_32bit_c0_register($22, 1)
-#define write_c0_diag1(val)	__write_32bit_c0_register($22, 1, val)
-
-#define read_c0_diag2()		__read_32bit_c0_register($22, 2)
-#define write_c0_diag2(val)	__write_32bit_c0_register($22, 2, val)
-
-#define read_c0_diag3()		__read_32bit_c0_register($22, 3)
-#define write_c0_diag3(val)	__write_32bit_c0_register($22, 3, val)
-
-#define read_c0_diag4()		__read_32bit_c0_register($22, 4)
-#define write_c0_diag4(val)	__write_32bit_c0_register($22, 4, val)
-
-#define read_c0_diag5()		__read_32bit_c0_register($22, 5)
-#define write_c0_diag5(val)	__write_32bit_c0_register($22, 5, val)
-
-#define read_c0_debug()		__read_32bit_c0_register($23, 0)
-#define write_c0_debug(val)	__write_32bit_c0_register($23, 0, val)
-
-#define read_c0_depc()		__read_ulong_c0_register($24, 0)
-#define write_c0_depc(val)	__write_ulong_c0_register($24, 0, val)
-
-/*
- * MIPS32 / MIPS64 performance counters
- */
-#define read_c0_perfctrl0()	__read_32bit_c0_register($25, 0)
-#define write_c0_perfctrl0(val)	__write_32bit_c0_register($25, 0, val)
-#define read_c0_perfcntr0()	__read_32bit_c0_register($25, 1)
-#define write_c0_perfcntr0(val)	__write_32bit_c0_register($25, 1, val)
-#define read_c0_perfctrl1()	__read_32bit_c0_register($25, 2)
-#define write_c0_perfctrl1(val)	__write_32bit_c0_register($25, 2, val)
-#define read_c0_perfcntr1()	__read_32bit_c0_register($25, 3)
-#define write_c0_perfcntr1(val)	__write_32bit_c0_register($25, 3, val)
-#define read_c0_perfctrl2()	__read_32bit_c0_register($25, 4)
-#define write_c0_perfctrl2(val)	__write_32bit_c0_register($25, 4, val)
-#define read_c0_perfcntr2()	__read_32bit_c0_register($25, 5)
-#define write_c0_perfcntr2(val)	__write_32bit_c0_register($25, 5, val)
-#define read_c0_perfctrl3()	__read_32bit_c0_register($25, 6)
-#define write_c0_perfctrl3(val)	__write_32bit_c0_register($25, 6, val)
-#define read_c0_perfcntr3()	__read_32bit_c0_register($25, 7)
-#define write_c0_perfcntr3(val)	__write_32bit_c0_register($25, 7, val)
-
-/* RM9000 PerfCount performance counter register */
-#define read_c0_perfcount()	__read_64bit_c0_register($25, 0)
-#define write_c0_perfcount(val)	__write_64bit_c0_register($25, 0, val)
-
-#define read_c0_ecc()		__read_32bit_c0_register($26, 0)
-#define write_c0_ecc(val)	__write_32bit_c0_register($26, 0, val)
-
-#define read_c0_derraddr0()	__read_ulong_c0_register($26, 1)
-#define write_c0_derraddr0(val)	__write_ulong_c0_register($26, 1, val)
-
-#define read_c0_cacheerr()	__read_32bit_c0_register($27, 0)
-
-#define read_c0_derraddr1()	__read_ulong_c0_register($27, 1)
-#define write_c0_derraddr1(val)	__write_ulong_c0_register($27, 1, val)
-
-#define read_c0_taglo()		__read_32bit_c0_register($28, 0)
-#define write_c0_taglo(val)	__write_32bit_c0_register($28, 0, val)
-
-#define read_c0_dtaglo()	__read_32bit_c0_register($28, 2)
-#define write_c0_dtaglo(val)	__write_32bit_c0_register($28, 2, val)
-
-#define read_c0_taghi()		__read_32bit_c0_register($29, 0)
-#define write_c0_taghi(val)	__write_32bit_c0_register($29, 0, val)
-
-#define read_c0_errorepc()	__read_ulong_c0_register($30, 0)
-#define write_c0_errorepc(val)	__write_ulong_c0_register($30, 0, val)
-
-/* MIPSR2 */
-#define read_c0_hwrena()	__read_32bit_c0_register($7, 0)
-#define write_c0_hwrena(val)	__write_32bit_c0_register($7, 0, val)
-
-#define read_c0_intctl()	__read_32bit_c0_register($12, 1)
-#define write_c0_intctl(val)	__write_32bit_c0_register($12, 1, val)
-
-#define read_c0_srsctl()	__read_32bit_c0_register($12, 2)
-#define write_c0_srsctl(val)	__write_32bit_c0_register($12, 2, val)
-
-#define read_c0_srsmap()	__read_32bit_c0_register($12, 3)
-#define write_c0_srsmap(val)	__write_32bit_c0_register($12, 3, val)
-
-#define read_c0_ebase()		__read_32bit_c0_register($15, 1)
-#define write_c0_ebase(val)	__write_32bit_c0_register($15, 1, val)
-
-/*
- * Macros to access the floating point coprocessor control registers
- */
-#define read_32bit_cp1_register(source)                         \
-({ int __res;                                                   \
-	__asm__ __volatile__(                                   \
-	".set\tpush\n\t"					\
-	".set\treorder\n\t"					\
-        "cfc1\t%0,"STR(source)"\n\t"                            \
-	".set\tpop"						\
-        : "=r" (__res));                                        \
-        __res;})
-
-#define rddsp(mask)							\
-({									\
-	unsigned int __res;						\
-									\
-	__asm__ __volatile__(						\
-	"	.set	push				\n"		\
-	"	.set	noat				\n"		\
-	"	# rddsp $1, %x1				\n"		\
-	"	.word	0x7c000cb8 | (%x1 << 16)	\n"		\
-	"	move	%0, $1				\n"		\
-	"	.set	pop				\n"		\
-	: "=r" (__res)							\
-	: "i" (mask));							\
-	__res;								\
-})
-
-#define wrdsp(val, mask)						\
-do {									\
-	__asm__ __volatile__(						\
-	"	.set	push					\n"	\
-	"	.set	noat					\n"	\
-	"	move	$1, %0					\n"	\
-	"	# wrdsp $1, %x1					\n"	\
-	"	.word	0x7c2004f8 | (%x1 << 11)		\n"	\
-	"	.set	pop					\n"	\
-        :								\
-	: "r" (val), "i" (mask));					\
-} while (0)
-
-#if 0	/* Need DSP ASE capable assembler ... */
-#define mflo0() ({ long mflo0; __asm__("mflo %0, $ac0" : "=r" (mflo0)); mflo0;})
-#define mflo1() ({ long mflo1; __asm__("mflo %0, $ac1" : "=r" (mflo1)); mflo1;})
-#define mflo2() ({ long mflo2; __asm__("mflo %0, $ac2" : "=r" (mflo2)); mflo2;})
-#define mflo3() ({ long mflo3; __asm__("mflo %0, $ac3" : "=r" (mflo3)); mflo3;})
-
-#define mfhi0() ({ long mfhi0; __asm__("mfhi %0, $ac0" : "=r" (mfhi0)); mfhi0;})
-#define mfhi1() ({ long mfhi1; __asm__("mfhi %0, $ac1" : "=r" (mfhi1)); mfhi1;})
-#define mfhi2() ({ long mfhi2; __asm__("mfhi %0, $ac2" : "=r" (mfhi2)); mfhi2;})
-#define mfhi3() ({ long mfhi3; __asm__("mfhi %0, $ac3" : "=r" (mfhi3)); mfhi3;})
-
-#define mtlo0(x) __asm__("mtlo %0, $ac0" ::"r" (x))
-#define mtlo1(x) __asm__("mtlo %0, $ac1" ::"r" (x))
-#define mtlo2(x) __asm__("mtlo %0, $ac2" ::"r" (x))
-#define mtlo3(x) __asm__("mtlo %0, $ac3" ::"r" (x))
-
-#define mthi0(x) __asm__("mthi %0, $ac0" ::"r" (x))
-#define mthi1(x) __asm__("mthi %0, $ac1" ::"r" (x))
-#define mthi2(x) __asm__("mthi %0, $ac2" ::"r" (x))
-#define mthi3(x) __asm__("mthi %0, $ac3" ::"r" (x))
-
-#else
-
-#define mfhi0()								\
-({									\
-	unsigned long __treg;						\
-									\
-	__asm__ __volatile__(						\
-	"	.set	push			\n"			\
-	"	.set	noat			\n"			\
-	"	# mfhi	%0, $ac0		\n"			\
-	"	.word	0x00000810		\n"			\
-	"	move	%0, $1			\n"			\
-	"	.set	pop			\n"			\
-	: "=r" (__treg));						\
-	__treg;								\
-})
-
-#define mfhi1()								\
-({									\
-	unsigned long __treg;						\
-									\
-	__asm__ __volatile__(						\
-	"	.set	push			\n"			\
-	"	.set	noat			\n"			\
-	"	# mfhi	%0, $ac1		\n"			\
-	"	.word	0x00200810		\n"			\
-	"	move	%0, $1			\n"			\
-	"	.set	pop			\n"			\
-	: "=r" (__treg));						\
-	__treg;								\
-})
-
-#define mfhi2()								\
-({									\
-	unsigned long __treg;						\
-									\
-	__asm__ __volatile__(						\
-	"	.set	push			\n"			\
-	"	.set	noat			\n"			\
-	"	# mfhi	%0, $ac2		\n"			\
-	"	.word	0x00400810		\n"			\
-	"	move	%0, $1			\n"			\
-	"	.set	pop			\n"			\
-	: "=r" (__treg));						\
-	__treg;								\
-})
-
-#define mfhi3()								\
-({									\
-	unsigned long __treg;						\
-									\
-	__asm__ __volatile__(						\
-	"	.set	push			\n"			\
-	"	.set	noat			\n"			\
-	"	# mfhi	%0, $ac3		\n"			\
-	"	.word	0x00600810		\n"			\
-	"	move	%0, $1			\n"			\
-	"	.set	pop			\n"			\
-	: "=r" (__treg));						\
-	__treg;								\
-})
-
-#define mflo0()								\
-({									\
-	unsigned long __treg;						\
-									\
-	__asm__ __volatile__(						\
-	"	.set	push			\n"			\
-	"	.set	noat			\n"			\
-	"	# mflo	%0, $ac0		\n"			\
-	"	.word	0x00000812		\n"			\
-	"	move	%0, $1			\n"			\
-	"	.set	pop			\n"			\
-	: "=r" (__treg));						\
-	__treg;								\
-})
-
-#define mflo1()								\
-({									\
-	unsigned long __treg;						\
-									\
-	__asm__ __volatile__(						\
-	"	.set	push			\n"			\
-	"	.set	noat			\n"			\
-	"	# mflo	%0, $ac1		\n"			\
-	"	.word	0x00200812		\n"			\
-	"	move	%0, $1			\n"			\
-	"	.set	pop			\n"			\
-	: "=r" (__treg));						\
-	__treg;								\
-})
-
-#define mflo2()								\
-({									\
-	unsigned long __treg;						\
-									\
-	__asm__ __volatile__(						\
-	"	.set	push			\n"			\
-	"	.set	noat			\n"			\
-	"	# mflo	%0, $ac2		\n"			\
-	"	.word	0x00400812		\n"			\
-	"	move	%0, $1			\n"			\
-	"	.set	pop			\n"			\
-	: "=r" (__treg));						\
-	__treg;								\
-})
-
-#define mflo3()								\
-({									\
-	unsigned long __treg;						\
-									\
-	__asm__ __volatile__(						\
-	"	.set	push			\n"			\
-	"	.set	noat			\n"			\
-	"	# mflo	%0, $ac3		\n"			\
-	"	.word	0x00600812		\n"			\
-	"	move	%0, $1			\n"			\
-	"	.set	pop			\n"			\
-	: "=r" (__treg));						\
-	__treg;								\
-})
-
-#define mthi0(x)							\
-do {									\
-	__asm__ __volatile__(						\
-	"	.set	push					\n"	\
-	"	.set	noat					\n"	\
-	"	move	$1, %0					\n"	\
-	"	# mthi	$1, $ac0				\n"	\
-	"	.word	0x00200011				\n"	\
-	"	.set	pop					\n"	\
-	:								\
-	: "r" (x));							\
-} while (0)
-
-#define mthi1(x)							\
-do {									\
-	__asm__ __volatile__(						\
-	"	.set	push					\n"	\
-	"	.set	noat					\n"	\
-	"	move	$1, %0					\n"	\
-	"	# mthi	$1, $ac1				\n"	\
-	"	.word	0x00200811				\n"	\
-	"	.set	pop					\n"	\
-	:								\
-	: "r" (x));							\
-} while (0)
-
-#define mthi2(x)							\
-do {									\
-	__asm__ __volatile__(						\
-	"	.set	push					\n"	\
-	"	.set	noat					\n"	\
-	"	move	$1, %0					\n"	\
-	"	# mthi	$1, $ac2				\n"	\
-	"	.word	0x00201011				\n"	\
-	"	.set	pop					\n"	\
-	:								\
-	: "r" (x));							\
-} while (0)
-
-#define mthi3(x)							\
-do {									\
-	__asm__ __volatile__(						\
-	"	.set	push					\n"	\
-	"	.set	noat					\n"	\
-	"	move	$1, %0					\n"	\
-	"	# mthi	$1, $ac3				\n"	\
-	"	.word	0x00201811				\n"	\
-	"	.set	pop					\n"	\
-	:								\
-	: "r" (x));							\
-} while (0)
-
-#define mtlo0(x)							\
-do {									\
-	__asm__ __volatile__(						\
-	"	.set	push					\n"	\
-	"	.set	noat					\n"	\
-	"	move	$1, %0					\n"	\
-	"	# mtlo	$1, $ac0				\n"	\
-	"	.word	0x00200013				\n"	\
-	"	.set	pop					\n"	\
-	:								\
-	: "r" (x));							\
-} while (0)
-
-#define mtlo1(x)							\
-do {									\
-	__asm__ __volatile__(						\
-	"	.set	push					\n"	\
-	"	.set	noat					\n"	\
-	"	move	$1, %0					\n"	\
-	"	# mtlo	$1, $ac1				\n"	\
-	"	.word	0x00200813				\n"	\
-	"	.set	pop					\n"	\
-	:								\
-	: "r" (x));							\
-} while (0)
-
-#define mtlo2(x)							\
-do {									\
-	__asm__ __volatile__(						\
-	"	.set	push					\n"	\
-	"	.set	noat					\n"	\
-	"	move	$1, %0					\n"	\
-	"	# mtlo	$1, $ac2				\n"	\
-	"	.word	0x00201013				\n"	\
-	"	.set	pop					\n"	\
-	:								\
-	: "r" (x));							\
-} while (0)
-
-#define mtlo3(x)							\
-do {									\
-	__asm__ __volatile__(						\
-	"	.set	push					\n"	\
-	"	.set	noat					\n"	\
-	"	move	$1, %0					\n"	\
-	"	# mtlo	$1, $ac3				\n"	\
-	"	.word	0x00201813				\n"	\
-	"	.set	pop					\n"	\
-	:								\
-	: "r" (x));							\
-} while (0)
-
-#endif
-
-/*
- * TLB operations.
- *
- * It is responsibility of the caller to take care of any TLB hazards.
- */
-static inline void tlb_probe(void)
-{
-	__asm__ __volatile__(
-		".set noreorder\n\t"
-		"tlbp\n\t"
-		".set reorder");
-}
-
-static inline void tlb_read(void)
-{
-#if MIPS34K_MISSED_ITLB_WAR
-	int res = 0;
-
-	__asm__ __volatile__(
-	"	.set	push					\n"
-	"	.set	noreorder				\n"
-	"	.set	noat					\n"
-	"	.set	mips32r2				\n"
-	"	.word	0x41610001		# dvpe $1	\n"
-	"	move	%0, $1					\n"
-	"	ehb						\n"
-	"	.set	pop					\n"
-	: "=r" (res));
-
-	instruction_hazard();
-#endif
-
-	__asm__ __volatile__(
-		".set noreorder\n\t"
-		"tlbr\n\t"
-		".set reorder");
-
-#if MIPS34K_MISSED_ITLB_WAR
-	if ((res & _ULCAST_(1)))
-		__asm__ __volatile__(
-		"	.set	push				\n"
-		"	.set	noreorder			\n"
-		"	.set	noat				\n"
-		"	.set	mips32r2			\n"
-		"	.word	0x41600021	# evpe		\n"
-		"	ehb					\n"
-		"	.set	pop				\n");
-#endif
-}
-
-static inline void tlb_write_indexed(void)
-{
-	__asm__ __volatile__(
-		".set noreorder\n\t"
-		"tlbwi\n\t"
-		".set reorder");
-}
-
-static inline void tlb_write_random(void)
-{
-	__asm__ __volatile__(
-		".set noreorder\n\t"
-		"tlbwr\n\t"
-		".set reorder");
-}
-
-/*
- * Manipulate bits in a c0 register.
- */
-#ifndef CONFIG_MIPS_MT_SMTC
-/*
- * SMTC Linux requires shutting-down microthread scheduling
- * during CP0 register read-modify-write sequences.
- */
-#define __BUILD_SET_C0(name)					\
-static inline unsigned int					\
-set_c0_##name(unsigned int set)					\
-{								\
-	unsigned int res;					\
-								\
-	res = read_c0_##name();					\
-	res |= set;						\
-	write_c0_##name(res);					\
-								\
-	return res;						\
-}								\
-								\
-static inline unsigned int					\
-clear_c0_##name(unsigned int clear)				\
-{								\
-	unsigned int res;					\
-								\
-	res = read_c0_##name();					\
-	res &= ~clear;						\
-	write_c0_##name(res);					\
-								\
-	return res;						\
-}								\
-								\
-static inline unsigned int					\
-change_c0_##name(unsigned int change, unsigned int new)		\
-{								\
-	unsigned int res;					\
-								\
-	res = read_c0_##name();					\
-	res &= ~change;						\
-	res |= (new & change);					\
-	write_c0_##name(res);					\
-								\
-	return res;						\
-}
-
-#else /* SMTC versions that manage MT scheduling */
-
-#include <linux/irqflags.h>
-
-/*
- * This is a duplicate of dmt() in mipsmtregs.h to avoid problems with
- * header file recursion.
- */
-static inline unsigned int __dmt(void)
-{
-	int res;
-
-	__asm__ __volatile__(
-	"	.set	push						\n"
-	"	.set	mips32r2					\n"
-	"	.set	noat						\n"
-	"	.word	0x41610BC1			# dmt $1	\n"
-	"	ehb							\n"
-	"	move	%0, $1						\n"
-	"	.set	pop						\n"
-	: "=r" (res));
-
-	instruction_hazard();
-
-	return res;
-}
-
-#define __VPECONTROL_TE_SHIFT	15
-#define __VPECONTROL_TE		(1UL << __VPECONTROL_TE_SHIFT)
-
-#define __EMT_ENABLE		__VPECONTROL_TE
-
-static inline void __emt(unsigned int previous)
-{
-	if ((previous & __EMT_ENABLE))
-		__asm__ __volatile__(
-		"	.set	mips32r2				\n"
-		"	.word	0x41600be1		# emt		\n"
-		"	ehb						\n"
-		"	.set	mips0					\n");
-}
-
-static inline void __ehb(void)
-{
-	__asm__ __volatile__(
-	"	.set	mips32r2					\n"
-	"	ehb							\n"		"	.set	mips0						\n");
-}
-
-/*
- * Note that local_irq_save/restore affect TC-specific IXMT state,
- * not Status.IE as in non-SMTC kernel.
- */
-
-#define __BUILD_SET_C0(name)					\
-static inline unsigned int					\
-set_c0_##name(unsigned int set)					\
-{								\
-	unsigned int res;					\
-	unsigned int omt;					\
-	unsigned int flags;					\
-								\
-	local_irq_save(flags);					\
-	omt = __dmt();						\
-	res = read_c0_##name();					\
-	res |= set;						\
-	write_c0_##name(res);					\
-	__emt(omt);						\
-	local_irq_restore(flags);				\
-								\
-	return res;						\
-}								\
-								\
-static inline unsigned int					\
-clear_c0_##name(unsigned int clear)				\
-{								\
-	unsigned int res;					\
-	unsigned int omt;					\
-	unsigned int flags;					\
-								\
-	local_irq_save(flags);					\
-	omt = __dmt();						\
-	res = read_c0_##name();					\
-	res &= ~clear;						\
-	write_c0_##name(res);					\
-	__emt(omt);						\
-	local_irq_restore(flags);				\
-								\
-	return res;						\
-}								\
-								\
-static inline unsigned int					\
-change_c0_##name(unsigned int change, unsigned int new)		\
-{								\
-	unsigned int res;					\
-	unsigned int omt;					\
-	unsigned int flags;					\
-								\
-	local_irq_save(flags);					\
-								\
-	omt = __dmt();						\
-	res = read_c0_##name();					\
-	res &= ~change;						\
-	res |= (new & change);					\
-	write_c0_##name(res);					\
-	__emt(omt);						\
-	local_irq_restore(flags);				\
-								\
-	return res;						\
-}
-#endif
-
-__BUILD_SET_C0(status)
-__BUILD_SET_C0(cause)
-__BUILD_SET_C0(config)
-__BUILD_SET_C0(intcontrol)
-__BUILD_SET_C0(intctl)
-__BUILD_SET_C0(srsmap)
-
-#endif /* !__ASSEMBLY__ */
-
-#endif /* _ASM_MIPSREGS_H */
diff --git a/include/asm-mips/mmu_context.h b/include/asm-mips/mmu_context.h
deleted file mode 100644
index 0c4f245..0000000
--- a/include/asm-mips/mmu_context.h
+++ /dev/null
@@ -1,297 +0,0 @@
-/*
- * Switch a MMU context.
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 1996, 1997, 1998, 1999 by Ralf Baechle
- * Copyright (C) 1999 Silicon Graphics, Inc.
- */
-#ifndef _ASM_MMU_CONTEXT_H
-#define _ASM_MMU_CONTEXT_H
-
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <asm/cacheflush.h>
-#include <asm/tlbflush.h>
-#ifdef CONFIG_MIPS_MT_SMTC
-#include <asm/mipsmtregs.h>
-#include <asm/smtc.h>
-#endif /* SMTC */
-#include <asm-generic/mm_hooks.h>
-
-/*
- * For the fast tlb miss handlers, we keep a per cpu array of pointers
- * to the current pgd for each processor. Also, the proc. id is stuffed
- * into the context register.
- */
-extern unsigned long pgd_current[];
-
-#define TLBMISS_HANDLER_SETUP_PGD(pgd) \
-	pgd_current[smp_processor_id()] = (unsigned long)(pgd)
-
-#ifdef CONFIG_32BIT
-#define TLBMISS_HANDLER_SETUP()						\
-	write_c0_context((unsigned long) smp_processor_id() << 25);	\
-	TLBMISS_HANDLER_SETUP_PGD(swapper_pg_dir)
-#endif
-#ifdef CONFIG_64BIT
-#define TLBMISS_HANDLER_SETUP()						\
-	write_c0_context((unsigned long) smp_processor_id() << 26);	\
-	TLBMISS_HANDLER_SETUP_PGD(swapper_pg_dir)
-#endif
-
-#if defined(CONFIG_CPU_R3000) || defined(CONFIG_CPU_TX39XX)
-
-#define ASID_INC	0x40
-#define ASID_MASK	0xfc0
-
-#elif defined(CONFIG_CPU_R8000)
-
-#define ASID_INC	0x10
-#define ASID_MASK	0xff0
-
-#elif defined(CONFIG_CPU_RM9000)
-
-#define ASID_INC	0x1
-#define ASID_MASK	0xfff
-
-/* SMTC/34K debug hack - but maybe we'll keep it */
-#elif defined(CONFIG_MIPS_MT_SMTC)
-
-#define ASID_INC	0x1
-extern unsigned long smtc_asid_mask;
-#define ASID_MASK	(smtc_asid_mask)
-#define	HW_ASID_MASK	0xff
-/* End SMTC/34K debug hack */
-#else /* FIXME: not correct for R6000 */
-
-#define ASID_INC	0x1
-#define ASID_MASK	0xff
-
-#endif
-
-#define cpu_context(cpu, mm)	((mm)->context[cpu])
-#define cpu_asid(cpu, mm)	(cpu_context((cpu), (mm)) & ASID_MASK)
-#define asid_cache(cpu)		(cpu_data[cpu].asid_cache)
-
-static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk)
-{
-}
-
-/*
- *  All unused by hardware upper bits will be considered
- *  as a software asid extension.
- */
-#define ASID_VERSION_MASK  ((unsigned long)~(ASID_MASK|(ASID_MASK-1)))
-#define ASID_FIRST_VERSION ((unsigned long)(~ASID_VERSION_MASK) + 1)
-
-#ifndef CONFIG_MIPS_MT_SMTC
-/* Normal, classic MIPS get_new_mmu_context */
-static inline void
-get_new_mmu_context(struct mm_struct *mm, unsigned long cpu)
-{
-	unsigned long asid = asid_cache(cpu);
-
-	if (! ((asid += ASID_INC) & ASID_MASK) ) {
-		if (cpu_has_vtag_icache)
-			flush_icache_all();
-		local_flush_tlb_all();	/* start new asid cycle */
-		if (!asid)		/* fix version if needed */
-			asid = ASID_FIRST_VERSION;
-	}
-	cpu_context(cpu, mm) = asid_cache(cpu) = asid;
-}
-
-#else /* CONFIG_MIPS_MT_SMTC */
-
-#define get_new_mmu_context(mm, cpu) smtc_get_new_mmu_context((mm), (cpu))
-
-#endif /* CONFIG_MIPS_MT_SMTC */
-
-/*
- * Initialize the context related info for a new mm_struct
- * instance.
- */
-static inline int
-init_new_context(struct task_struct *tsk, struct mm_struct *mm)
-{
-	int i;
-
-	for_each_online_cpu(i)
-		cpu_context(i, mm) = 0;
-
-	return 0;
-}
-
-static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
-                             struct task_struct *tsk)
-{
-	unsigned int cpu = smp_processor_id();
-	unsigned long flags;
-#ifdef CONFIG_MIPS_MT_SMTC
-	unsigned long oldasid;
-	unsigned long mtflags;
-	int mytlb = (smtc_status & SMTC_TLB_SHARED) ? 0 : cpu_data[cpu].vpe_id;
-	local_irq_save(flags);
-	mtflags = dvpe();
-#else /* Not SMTC */
-	local_irq_save(flags);
-#endif /* CONFIG_MIPS_MT_SMTC */
-
-	/* Check if our ASID is of an older version and thus invalid */
-	if ((cpu_context(cpu, next) ^ asid_cache(cpu)) & ASID_VERSION_MASK)
-		get_new_mmu_context(next, cpu);
-#ifdef CONFIG_MIPS_MT_SMTC
-	/*
-	 * If the EntryHi ASID being replaced happens to be
-	 * the value flagged at ASID recycling time as having
-	 * an extended life, clear the bit showing it being
-	 * in use by this "CPU", and if that's the last bit,
-	 * free up the ASID value for use and flush any old
-	 * instances of it from the TLB.
-	 */
-	oldasid = (read_c0_entryhi() & ASID_MASK);
-	if(smtc_live_asid[mytlb][oldasid]) {
-		smtc_live_asid[mytlb][oldasid] &= ~(0x1 << cpu);
-		if(smtc_live_asid[mytlb][oldasid] == 0)
-			smtc_flush_tlb_asid(oldasid);
-	}
-	/*
-	 * Tread softly on EntryHi, and so long as we support
-	 * having ASID_MASK smaller than the hardware maximum,
-	 * make sure no "soft" bits become "hard"...
-	 */
-	write_c0_entryhi((read_c0_entryhi() & ~HW_ASID_MASK)
-			| (cpu_context(cpu, next) & ASID_MASK));
-	ehb(); /* Make sure it propagates to TCStatus */
-	evpe(mtflags);
-#else
-	write_c0_entryhi(cpu_context(cpu, next));
-#endif /* CONFIG_MIPS_MT_SMTC */
-	TLBMISS_HANDLER_SETUP_PGD(next->pgd);
-
-	/*
-	 * Mark current->active_mm as not "active" anymore.
-	 * We don't want to mislead possible IPI tlb flush routines.
-	 */
-	cpu_clear(cpu, prev->cpu_vm_mask);
-	cpu_set(cpu, next->cpu_vm_mask);
-
-	local_irq_restore(flags);
-}
-
-/*
- * Destroy context related info for an mm_struct that is about
- * to be put to rest.
- */
-static inline void destroy_context(struct mm_struct *mm)
-{
-}
-
-#define deactivate_mm(tsk, mm)	do { } while (0)
-
-/*
- * After we have set current->mm to a new value, this activates
- * the context for the new mm so we see the new mappings.
- */
-static inline void
-activate_mm(struct mm_struct *prev, struct mm_struct *next)
-{
-	unsigned long flags;
-	unsigned int cpu = smp_processor_id();
-
-#ifdef CONFIG_MIPS_MT_SMTC
-	unsigned long oldasid;
-	unsigned long mtflags;
-	int mytlb = (smtc_status & SMTC_TLB_SHARED) ? 0 : cpu_data[cpu].vpe_id;
-#endif /* CONFIG_MIPS_MT_SMTC */
-
-	local_irq_save(flags);
-
-	/* Unconditionally get a new ASID.  */
-	get_new_mmu_context(next, cpu);
-
-#ifdef CONFIG_MIPS_MT_SMTC
-	/* See comments for similar code above */
-	mtflags = dvpe();
-	oldasid = read_c0_entryhi() & ASID_MASK;
-	if(smtc_live_asid[mytlb][oldasid]) {
-		smtc_live_asid[mytlb][oldasid] &= ~(0x1 << cpu);
-       		if(smtc_live_asid[mytlb][oldasid] == 0)
-               		 smtc_flush_tlb_asid(oldasid);
-	}
-	/* See comments for similar code above */
-	write_c0_entryhi((read_c0_entryhi() & ~HW_ASID_MASK) |
-	                 (cpu_context(cpu, next) & ASID_MASK));
-	ehb(); /* Make sure it propagates to TCStatus */
-	evpe(mtflags);
-#else
-	write_c0_entryhi(cpu_context(cpu, next));
-#endif /* CONFIG_MIPS_MT_SMTC */
-	TLBMISS_HANDLER_SETUP_PGD(next->pgd);
-
-	/* mark mmu ownership change */
-	cpu_clear(cpu, prev->cpu_vm_mask);
-	cpu_set(cpu, next->cpu_vm_mask);
-
-	local_irq_restore(flags);
-}
-
-/*
- * If mm is currently active_mm, we can't really drop it.  Instead,
- * we will get a new one for it.
- */
-static inline void
-drop_mmu_context(struct mm_struct *mm, unsigned cpu)
-{
-	unsigned long flags;
-#ifdef CONFIG_MIPS_MT_SMTC
-	unsigned long oldasid;
-	/* Can't use spinlock because called from TLB flush within DVPE */
-	unsigned int prevvpe;
-	int mytlb = (smtc_status & SMTC_TLB_SHARED) ? 0 : cpu_data[cpu].vpe_id;
-#endif /* CONFIG_MIPS_MT_SMTC */
-
-	local_irq_save(flags);
-
-	if (cpu_isset(cpu, mm->cpu_vm_mask))  {
-		get_new_mmu_context(mm, cpu);
-#ifdef CONFIG_MIPS_MT_SMTC
-		/* See comments for similar code above */
-		prevvpe = dvpe();
-		oldasid = (read_c0_entryhi() & ASID_MASK);
-		if (smtc_live_asid[mytlb][oldasid]) {
-			smtc_live_asid[mytlb][oldasid] &= ~(0x1 << cpu);
-			if(smtc_live_asid[mytlb][oldasid] == 0)
-				smtc_flush_tlb_asid(oldasid);
-		}
-		/* See comments for similar code above */
-		write_c0_entryhi((read_c0_entryhi() & ~HW_ASID_MASK)
-				| cpu_asid(cpu, mm));
-		ehb(); /* Make sure it propagates to TCStatus */
-		evpe(prevvpe);
-#else /* not CONFIG_MIPS_MT_SMTC */
-		write_c0_entryhi(cpu_asid(cpu, mm));
-#endif /* CONFIG_MIPS_MT_SMTC */
-	} else {
-		/* will get a new context next time */
-#ifndef CONFIG_MIPS_MT_SMTC
-		cpu_context(cpu, mm) = 0;
-#else /* SMTC */
-		int i;
-
-		/* SMTC shares the TLB (and ASIDs) across VPEs */
-		for_each_online_cpu(i) {
-	    	    if((smtc_status & SMTC_TLB_SHARED)
-	    	    || (cpu_data[i].vpe_id == cpu_data[cpu].vpe_id))
-			cpu_context(i, mm) = 0;
-		}
-#endif /* CONFIG_MIPS_MT_SMTC */
-	}
-	local_irq_restore(flags);
-}
-
-#endif /* _ASM_MMU_CONTEXT_H */
diff --git a/include/asm-mips/pgtable-32.h b/include/asm-mips/pgtable-32.h
deleted file mode 100644
index 4396e9f..0000000
--- a/include/asm-mips/pgtable-32.h
+++ /dev/null
@@ -1,234 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 1994, 95, 96, 97, 98, 99, 2000, 2003 Ralf Baechle
- * Copyright (C) 1999, 2000, 2001 Silicon Graphics, Inc.
- */
-#ifndef _ASM_PGTABLE_32_H
-#define _ASM_PGTABLE_32_H
-
-#include <asm/addrspace.h>
-#include <asm/page.h>
-
-#include <linux/linkage.h>
-#include <asm/cachectl.h>
-#include <asm/fixmap.h>
-
-#include <asm-generic/pgtable-nopmd.h>
-
-/*
- * - add_wired_entry() add a fixed TLB entry, and move wired register
- */
-extern void add_wired_entry(unsigned long entrylo0, unsigned long entrylo1,
-			       unsigned long entryhi, unsigned long pagemask);
-
-/*
- * - add_temporary_entry() add a temporary TLB entry. We use TLB entries
- *	starting at the top and working down. This is for populating the
- *	TLB before trap_init() puts the TLB miss handler in place. It
- *	should be used only for entries matching the actual page tables,
- *	to prevent inconsistencies.
- */
-extern int add_temporary_entry(unsigned long entrylo0, unsigned long entrylo1,
-			       unsigned long entryhi, unsigned long pagemask);
-
-
-/* Basically we have the same two-level (which is the logical three level
- * Linux page table layout folded) page tables as the i386.  Some day
- * when we have proper page coloring support we can have a 1% quicker
- * tlb refill handling mechanism, but for now it is a bit slower but
- * works even with the cache aliasing problem the R4k and above have.
- */
-
-/* PGDIR_SHIFT determines what a third-level page table entry can map */
-#define PGDIR_SHIFT	(2 * PAGE_SHIFT + PTE_ORDER - PTE_T_LOG2)
-#define PGDIR_SIZE	(1UL << PGDIR_SHIFT)
-#define PGDIR_MASK	(~(PGDIR_SIZE-1))
-
-/*
- * Entries per page directory level: we use two-level, so
- * we don't really have any PUD/PMD directory physically.
- */
-#define __PGD_ORDER	(32 - 3 * PAGE_SHIFT + PGD_T_LOG2 + PTE_T_LOG2)
-#define PGD_ORDER	(__PGD_ORDER >= 0 ? __PGD_ORDER : 0)
-#define PUD_ORDER	aieeee_attempt_to_allocate_pud
-#define PMD_ORDER	1
-#define PTE_ORDER	0
-
-#define PTRS_PER_PGD	((PAGE_SIZE << PGD_ORDER) / sizeof(pgd_t))
-#define PTRS_PER_PTE	((PAGE_SIZE << PTE_ORDER) / sizeof(pte_t))
-
-#define USER_PTRS_PER_PGD	(0x80000000UL/PGDIR_SIZE)
-#define FIRST_USER_ADDRESS	0
-
-#define VMALLOC_START     MAP_BASE
-
-#define PKMAP_BASE		(0xfe000000UL)
-
-#ifdef CONFIG_HIGHMEM
-# define VMALLOC_END	(PKMAP_BASE-2*PAGE_SIZE)
-#else
-# define VMALLOC_END	(FIXADDR_START-2*PAGE_SIZE)
-#endif
-
-#ifdef CONFIG_64BIT_PHYS_ADDR
-#define pte_ERROR(e) \
-	printk("%s:%d: bad pte %016Lx.\n", __FILE__, __LINE__, pte_val(e))
-#else
-#define pte_ERROR(e) \
-	printk("%s:%d: bad pte %08lx.\n", __FILE__, __LINE__, pte_val(e))
-#endif
-#define pgd_ERROR(e) \
-	printk("%s:%d: bad pgd %08lx.\n", __FILE__, __LINE__, pgd_val(e))
-
-extern void load_pgd(unsigned long pg_dir);
-
-extern pte_t invalid_pte_table[PAGE_SIZE/sizeof(pte_t)];
-
-/*
- * Empty pgd/pmd entries point to the invalid_pte_table.
- */
-static inline int pmd_none(pmd_t pmd)
-{
-	return pmd_val(pmd) == (unsigned long) invalid_pte_table;
-}
-
-#define pmd_bad(pmd)		(pmd_val(pmd) & ~PAGE_MASK)
-
-static inline int pmd_present(pmd_t pmd)
-{
-	return pmd_val(pmd) != (unsigned long) invalid_pte_table;
-}
-
-static inline void pmd_clear(pmd_t *pmdp)
-{
-	pmd_val(*pmdp) = ((unsigned long) invalid_pte_table);
-}
-
-#if defined(CONFIG_64BIT_PHYS_ADDR) && defined(CONFIG_CPU_MIPS32)
-#define pte_page(x)		pfn_to_page(pte_pfn(x))
-#define pte_pfn(x)		((unsigned long)((x).pte_high >> 6))
-static inline pte_t
-pfn_pte(unsigned long pfn, pgprot_t prot)
-{
-	pte_t pte;
-	pte.pte_high = (pfn << 6) | (pgprot_val(prot) & 0x3f);
-	pte.pte_low = pgprot_val(prot);
-	return pte;
-}
-
-#else
-
-#define pte_page(x)		pfn_to_page(pte_pfn(x))
-
-#ifdef CONFIG_CPU_VR41XX
-#define pte_pfn(x)		((unsigned long)((x).pte >> (PAGE_SHIFT + 2)))
-#define pfn_pte(pfn, prot)	__pte(((pfn) << (PAGE_SHIFT + 2)) | pgprot_val(prot))
-#else
-#define pte_pfn(x)		((unsigned long)((x).pte >> PAGE_SHIFT))
-#define pfn_pte(pfn, prot)	__pte(((unsigned long long)(pfn) << PAGE_SHIFT) | pgprot_val(prot))
-#endif
-#endif /* defined(CONFIG_64BIT_PHYS_ADDR) && defined(CONFIG_CPU_MIPS32) */
-
-#define __pgd_offset(address)	pgd_index(address)
-#define __pud_offset(address)	(((address) >> PUD_SHIFT) & (PTRS_PER_PUD-1))
-#define __pmd_offset(address)	(((address) >> PMD_SHIFT) & (PTRS_PER_PMD-1))
-
-/* to find an entry in a kernel page-table-directory */
-#define pgd_offset_k(address) pgd_offset(&init_mm, address)
-
-#define pgd_index(address)	(((address) >> PGDIR_SHIFT) & (PTRS_PER_PGD-1))
-
-/* to find an entry in a page-table-directory */
-#define pgd_offset(mm, addr)	((mm)->pgd + pgd_index(addr))
-
-/* Find an entry in the third-level page table.. */
-#define __pte_offset(address)						\
-	(((address) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1))
-#define pte_offset(dir, address)					\
-	((pte_t *) pmd_page_vaddr(*(dir)) + __pte_offset(address))
-#define pte_offset_kernel(dir, address)					\
-	((pte_t *) pmd_page_vaddr(*(dir)) + __pte_offset(address))
-
-#define pte_offset_map(dir, address)                                    \
-	((pte_t *)page_address(pmd_page(*(dir))) + __pte_offset(address))
-#define pte_offset_map_nested(dir, address)                             \
-	((pte_t *)page_address(pmd_page(*(dir))) + __pte_offset(address))
-#define pte_unmap(pte) ((void)(pte))
-#define pte_unmap_nested(pte) ((void)(pte))
-
-#if defined(CONFIG_CPU_R3000) || defined(CONFIG_CPU_TX39XX)
-
-/* Swap entries must have VALID bit cleared. */
-#define __swp_type(x)		(((x).val >> 10) & 0x1f)
-#define __swp_offset(x)		((x).val >> 15)
-#define __swp_entry(type,offset)	\
-	((swp_entry_t) { ((type) << 10) | ((offset) << 15) })
-
-/*
- * Bits 0, 4, 8, and 9 are taken, split up 28 bits of offset into this range:
- */
-#define PTE_FILE_MAX_BITS	28
-
-#define pte_to_pgoff(_pte)	((((_pte).pte >> 1 ) & 0x07) | \
-				 (((_pte).pte >> 2 ) & 0x38) | \
-				 (((_pte).pte >> 10) <<  6 ))
-
-#define pgoff_to_pte(off)	((pte_t) { (((off) & 0x07) << 1 ) | \
-					   (((off) & 0x38) << 2 ) | \
-					   (((off) >>  6 ) << 10) | \
-					   _PAGE_FILE })
-
-#else
-
-/* Swap entries must have VALID and GLOBAL bits cleared. */
-#if defined(CONFIG_64BIT_PHYS_ADDR) && defined(CONFIG_CPU_MIPS32)
-#define __swp_type(x)		(((x).val >> 2) & 0x1f)
-#define __swp_offset(x) 	 ((x).val >> 7)
-#define __swp_entry(type,offset)	\
-		((swp_entry_t)  { ((type) << 2) | ((offset) << 7) })
-#else
-#define __swp_type(x)		(((x).val >> 8) & 0x1f)
-#define __swp_offset(x) 	 ((x).val >> 13)
-#define __swp_entry(type,offset)	\
-		((swp_entry_t)  { ((type) << 8) | ((offset) << 13) })
-#endif /* defined(CONFIG_64BIT_PHYS_ADDR) && defined(CONFIG_CPU_MIPS32) */
-
-#if defined(CONFIG_64BIT_PHYS_ADDR) && defined(CONFIG_CPU_MIPS32)
-/*
- * Bits 0 and 1 of pte_high are taken, use the rest for the page offset...
- */
-#define PTE_FILE_MAX_BITS	30
-
-#define pte_to_pgoff(_pte)	((_pte).pte_high >> 2)
-#define pgoff_to_pte(off) 	((pte_t) { _PAGE_FILE, (off) << 2 })
-
-#else
-/*
- * Bits 0, 4, 6, and 7 are taken, split up 28 bits of offset into this range:
- */
-#define PTE_FILE_MAX_BITS	28
-
-#define pte_to_pgoff(_pte)	((((_pte).pte >> 1) & 0x7) | \
-				 (((_pte).pte >> 2) & 0x8) | \
-				 (((_pte).pte >> 8) <<  4))
-
-#define pgoff_to_pte(off)	((pte_t) { (((off) & 0x7) << 1) | \
-					   (((off) & 0x8) << 2) | \
-					   (((off) >>  4) << 8) | \
-					   _PAGE_FILE })
-#endif
-
-#endif
-
-#if defined(CONFIG_64BIT_PHYS_ADDR) && defined(CONFIG_CPU_MIPS32)
-#define __pte_to_swp_entry(pte) ((swp_entry_t) { (pte).pte_high })
-#define __swp_entry_to_pte(x)	((pte_t) { 0, (x).val })
-#else
-#define __pte_to_swp_entry(pte)	((swp_entry_t) { pte_val(pte) })
-#define __swp_entry_to_pte(x)	((pte_t) { (x).val })
-#endif
-
-#endif /* _ASM_PGTABLE_32_H */
diff --git a/include/asm-mips/processor.h b/include/asm-mips/processor.h
deleted file mode 100644
index a1e4453..0000000
--- a/include/asm-mips/processor.h
+++ /dev/null
@@ -1,263 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 1994 Waldorf GMBH
- * Copyright (C) 1995, 1996, 1997, 1998, 1999, 2001, 2002, 2003 Ralf Baechle
- * Copyright (C) 1996 Paul M. Antoine
- * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
- */
-#ifndef _ASM_PROCESSOR_H
-#define _ASM_PROCESSOR_H
-
-#include <linux/cpumask.h>
-#include <linux/threads.h>
-
-#include <asm/cachectl.h>
-#include <asm/cpu.h>
-#include <asm/cpu-info.h>
-#include <asm/mipsregs.h>
-#include <asm/prefetch.h>
-#include <asm/system.h>
-
-/*
- * Return current * instruction pointer ("program counter").
- */
-#define current_text_addr() ({ __label__ _l; _l: &&_l;})
-
-/*
- * System setup and hardware flags..
- */
-extern void (*cpu_wait)(void);
-
-extern unsigned int vced_count, vcei_count;
-
-#ifdef CONFIG_32BIT
-/*
- * User space process size: 2GB. This is hardcoded into a few places,
- * so don't change it unless you know what you are doing.
- */
-#define TASK_SIZE	0x7fff8000UL
-#define STACK_TOP	TASK_SIZE
-
-/*
- * This decides where the kernel will search for a free chunk of vm
- * space during mmap's.
- */
-#define TASK_UNMAPPED_BASE	((TASK_SIZE / 3) & ~(PAGE_SIZE))
-#endif
-
-#ifdef CONFIG_64BIT
-/*
- * User space process size: 1TB. This is hardcoded into a few places,
- * so don't change it unless you know what you are doing.  TASK_SIZE
- * is limited to 1TB by the R4000 architecture; R10000 and better can
- * support 16TB; the architectural reserve for future expansion is
- * 8192EB ...
- */
-#define TASK_SIZE32	0x7fff8000UL
-#define TASK_SIZE	0x10000000000UL
-#define STACK_TOP	\
-      (test_thread_flag(TIF_32BIT_ADDR) ? TASK_SIZE32 : TASK_SIZE)
-
-/*
- * This decides where the kernel will search for a free chunk of vm
- * space during mmap's.
- */
-#define TASK_UNMAPPED_BASE						\
-	(test_thread_flag(TIF_32BIT_ADDR) ?				\
-		PAGE_ALIGN(TASK_SIZE32 / 3) : PAGE_ALIGN(TASK_SIZE / 3))
-#define TASK_SIZE_OF(tsk)						\
-	(test_tsk_thread_flag(tsk, TIF_32BIT_ADDR) ? TASK_SIZE32 : TASK_SIZE)
-#endif
-
-#ifdef __KERNEL__
-#define STACK_TOP_MAX	TASK_SIZE
-#endif
-
-#define NUM_FPU_REGS	32
-
-typedef __u64 fpureg_t;
-
-/*
- * It would be nice to add some more fields for emulator statistics, but there
- * are a number of fixed offsets in offset.h and elsewhere that would have to
- * be recalculated by hand.  So the additional information will be private to
- * the FPU emulator for now.  See asm-mips/fpu_emulator.h.
- */
-
-struct mips_fpu_struct {
-	fpureg_t	fpr[NUM_FPU_REGS];
-	unsigned int	fcr31;
-};
-
-#define NUM_DSP_REGS   6
-
-typedef __u32 dspreg_t;
-
-struct mips_dsp_state {
-	dspreg_t        dspr[NUM_DSP_REGS];
-	unsigned int    dspcontrol;
-};
-
-#define INIT_CPUMASK { \
-	{0,} \
-}
-
-typedef struct {
-	unsigned long seg;
-} mm_segment_t;
-
-#define ARCH_MIN_TASKALIGN	8
-
-struct mips_abi;
-
-/*
- * If you change thread_struct remember to change the #defines below too!
- */
-struct thread_struct {
-	/* Saved main processor registers. */
-	unsigned long reg16;
-	unsigned long reg17, reg18, reg19, reg20, reg21, reg22, reg23;
-	unsigned long reg29, reg30, reg31;
-
-	/* Saved cp0 stuff. */
-	unsigned long cp0_status;
-
-	/* Saved fpu/fpu emulator stuff. */
-	struct mips_fpu_struct fpu;
-#ifdef CONFIG_MIPS_MT_FPAFF
-	/* Emulated instruction count */
-	unsigned long emulated_fp;
-	/* Saved per-thread scheduler affinity mask */
-	cpumask_t user_cpus_allowed;
-#endif /* CONFIG_MIPS_MT_FPAFF */
-
-	/* Saved state of the DSP ASE, if available. */
-	struct mips_dsp_state dsp;
-
-	/* Other stuff associated with the thread. */
-	unsigned long cp0_badvaddr;	/* Last user fault */
-	unsigned long cp0_baduaddr;	/* Last kernel fault accessing USEG */
-	unsigned long error_code;
-	unsigned long trap_no;
-	unsigned long irix_trampoline;  /* Wheee... */
-	unsigned long irix_oldctx;
-	struct mips_abi *abi;
-};
-
-#ifdef CONFIG_MIPS_MT_FPAFF
-#define FPAFF_INIT						\
-	.emulated_fp			= 0,			\
-	.user_cpus_allowed		= INIT_CPUMASK,
-#else
-#define FPAFF_INIT
-#endif /* CONFIG_MIPS_MT_FPAFF */
-
-#define INIT_THREAD  {						\
-        /*							\
-         * Saved main processor registers			\
-         */							\
-	.reg16			= 0,				\
-	.reg17			= 0,				\
-	.reg18			= 0,				\
-	.reg19			= 0,				\
-	.reg20			= 0,				\
-	.reg21			= 0,				\
-	.reg22			= 0,				\
-	.reg23			= 0,				\
-	.reg29			= 0,				\
-	.reg30			= 0,				\
-	.reg31			= 0,				\
-	/*							\
-	 * Saved cp0 stuff					\
-	 */							\
-	.cp0_status		= 0,				\
-	/*							\
-	 * Saved FPU/FPU emulator stuff				\
-	 */							\
-	.fpu			= {				\
-		.fpr		= {0,},				\
-		.fcr31		= 0,				\
-	},							\
-	/*							\
-	 * FPU affinity state (null if not FPAFF)		\
-	 */							\
-	FPAFF_INIT						\
-	/*							\
-	 * Saved DSP stuff					\
-	 */							\
-	.dsp			= {				\
-		.dspr		= {0, },			\
-		.dspcontrol	= 0,				\
-	},							\
-	/*							\
-	 * Other stuff associated with the process		\
-	 */							\
-	.cp0_badvaddr		= 0,				\
-	.cp0_baduaddr		= 0,				\
-	.error_code		= 0,				\
-	.trap_no		= 0,				\
-	.irix_trampoline	= 0,				\
-	.irix_oldctx		= 0,				\
-}
-
-struct task_struct;
-
-/* Free all resources held by a thread. */
-#define release_thread(thread) do { } while(0)
-
-/* Prepare to copy thread state - unlazy all lazy status */
-#define prepare_to_copy(tsk)	do { } while (0)
-
-extern long kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
-
-extern unsigned long thread_saved_pc(struct task_struct *tsk);
-
-/*
- * Do necessary setup to start up a newly executed thread.
- */
-extern void start_thread(struct pt_regs * regs, unsigned long pc, unsigned long sp);
-
-unsigned long get_wchan(struct task_struct *p);
-
-#define __KSTK_TOS(tsk) ((unsigned long)task_stack_page(tsk) + THREAD_SIZE - 32)
-#define task_pt_regs(tsk) ((struct pt_regs *)__KSTK_TOS(tsk) - 1)
-#define KSTK_EIP(tsk) (task_pt_regs(tsk)->cp0_epc)
-#define KSTK_ESP(tsk) (task_pt_regs(tsk)->regs[29])
-#define KSTK_STATUS(tsk) (task_pt_regs(tsk)->cp0_status)
-
-#define cpu_relax()	barrier()
-
-/*
- * Return_address is a replacement for __builtin_return_address(count)
- * which on certain architectures cannot reasonably be implemented in GCC
- * (MIPS, Alpha) or is unuseable with -fomit-frame-pointer (i386).
- * Note that __builtin_return_address(x>=1) is forbidden because GCC
- * aborts compilation on some CPUs.  It's simply not possible to unwind
- * some CPU's stackframes.
- *
- * __builtin_return_address works only for non-leaf functions.  We avoid the
- * overhead of a function call by forcing the compiler to save the return
- * address register on the stack.
- */
-#define return_address() ({__asm__ __volatile__("":::"$31");__builtin_return_address(0);})
-
-#ifdef CONFIG_CPU_HAS_PREFETCH
-
-#define ARCH_HAS_PREFETCH
-
-static inline void prefetch(const void *addr)
-{
-	__asm__ __volatile__(
-	"	.set	mips4		\n"
-	"	pref	%0, (%1)	\n"
-	"	.set	mips0		\n"
-	:
-	: "i" (Pref_Load), "r" (addr));
-}
-
-#endif
-
-#endif /* _ASM_PROCESSOR_H */
diff --git a/include/asm-mips/ptrace.h b/include/asm-mips/ptrace.h
deleted file mode 100644
index 786f7e3..0000000
--- a/include/asm-mips/ptrace.h
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 1994, 95, 96, 97, 98, 99, 2000 by Ralf Baechle
- * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
- */
-#ifndef _ASM_PTRACE_H
-#define _ASM_PTRACE_H
-
-
-/* 0 - 31 are integer registers, 32 - 63 are fp registers.  */
-#define FPR_BASE	32
-#define PC		64
-#define CAUSE		65
-#define BADVADDR	66
-#define MMHI		67
-#define MMLO		68
-#define FPC_CSR		69
-#define FPC_EIR		70
-#define DSP_BASE	71		/* 3 more hi / lo register pairs */
-#define DSP_CONTROL	77
-#define ACX		78
-
-/*
- * This struct defines the way the registers are stored on the stack during a
- * system call/exception. As usual the registers k0/k1 aren't being saved.
- */
-struct pt_regs {
-#ifdef CONFIG_32BIT
-	/* Pad bytes for argument save space on the stack. */
-	unsigned long pad0[6];
-#endif
-
-	/* Saved main processor registers. */
-	unsigned long regs[32];
-
-	/* Saved special registers. */
-	unsigned long cp0_status;
-	unsigned long hi;
-	unsigned long lo;
-#ifdef CONFIG_CPU_HAS_SMARTMIPS
-	unsigned long acx;
-#endif
-	unsigned long cp0_badvaddr;
-	unsigned long cp0_cause;
-	unsigned long cp0_epc;
-#ifdef CONFIG_MIPS_MT_SMTC
-	unsigned long cp0_tcstatus;
-#endif /* CONFIG_MIPS_MT_SMTC */
-} __attribute__ ((aligned (8)));
-
-/* Arbitrarily choose the same ptrace numbers as used by the Sparc code. */
-#define PTRACE_GETREGS		12
-#define PTRACE_SETREGS		13
-#define PTRACE_GETFPREGS		14
-#define PTRACE_SETFPREGS		15
-/* #define PTRACE_GETFPXREGS		18 */
-/* #define PTRACE_SETFPXREGS		19 */
-
-#define PTRACE_OLDSETOPTIONS	21
-
-#define PTRACE_GET_THREAD_AREA	25
-#define PTRACE_SET_THREAD_AREA	26
-
-/* Calls to trace a 64bit program from a 32bit program.  */
-#define PTRACE_PEEKTEXT_3264	0xc0
-#define PTRACE_PEEKDATA_3264	0xc1
-#define PTRACE_POKETEXT_3264	0xc2
-#define PTRACE_POKEDATA_3264	0xc3
-#define PTRACE_GET_THREAD_AREA_3264	0xc4
-
-#ifdef __KERNEL__
-
-#include <linux/linkage.h>
-#include <asm/isadep.h>
-
-/*
- * Does the process account for user or for system time?
- */
-#define user_mode(regs) (((regs)->cp0_status & KU_MASK) == KU_USER)
-
-#define instruction_pointer(regs) ((regs)->cp0_epc)
-#define profile_pc(regs) instruction_pointer(regs)
-
-extern asmlinkage void do_syscall_trace(struct pt_regs *regs, int entryexit);
-
-extern NORET_TYPE void die(const char *, const struct pt_regs *) ATTRIB_NORET;
-
-static inline void die_if_kernel(const char *str, const struct pt_regs *regs)
-{
-	if (unlikely(!user_mode(regs)))
-		die(str, regs);
-}
-
-#endif
-
-#endif /* _ASM_PTRACE_H */
diff --git a/include/asm-mips/smtc.h b/include/asm-mips/smtc.h
deleted file mode 100644
index 3639b28..0000000
--- a/include/asm-mips/smtc.h
+++ /dev/null
@@ -1,69 +0,0 @@
-#ifndef _ASM_SMTC_MT_H
-#define _ASM_SMTC_MT_H
-
-/*
- * Definitions for SMTC multitasking on MIPS MT cores
- */
-
-#include <asm/mips_mt.h>
-
-/*
- * System-wide SMTC status information
- */
-
-extern unsigned int smtc_status;
-
-#define SMTC_TLB_SHARED	0x00000001
-#define SMTC_MTC_ACTIVE	0x00000002
-
-/*
- * TLB/ASID Management information
- */
-
-#define MAX_SMTC_TLBS 2
-#define MAX_SMTC_ASIDS 256
-#if NR_CPUS <= 8
-typedef char asiduse;
-#else
-#if NR_CPUS <= 16
-typedef short asiduse;
-#else
-typedef long asiduse;
-#endif
-#endif
-
-extern asiduse smtc_live_asid[MAX_SMTC_TLBS][MAX_SMTC_ASIDS];
-
-struct mm_struct;
-struct task_struct;
-
-void smtc_get_new_mmu_context(struct mm_struct *mm, unsigned long cpu);
-
-void smtc_flush_tlb_asid(unsigned long asid);
-extern int mipsmt_build_cpu_map(int startslot);
-extern void mipsmt_prepare_cpus(void);
-extern void smtc_smp_finish(void);
-extern void smtc_boot_secondary(int cpu, struct task_struct *t);
-extern void smtc_cpus_done(void);
-
-/*
- * Sharing the TLB between multiple VPEs means that the
- * "random" index selection function is not allowed to
- * select the current value of the Index register. To
- * avoid additional TLB pressure, the Index registers
- * are "parked" with an non-Valid value.
- */
-
-#define PARKED_INDEX	((unsigned int)0x80000000)
-
-/*
- * Define low-level interrupt mask for IPIs, if necessary.
- * By default, use SW interrupt 1, which requires no external
- * hardware support, but which works only for single-core
- * MIPS MT systems.
- */
-#ifndef MIPS_CPU_IPI_IRQ
-#define MIPS_CPU_IPI_IRQ 1
-#endif
-
-#endif /*  _ASM_SMTC_MT_H */
diff --git a/include/asm-mips/sn/klconfig.h b/include/asm-mips/sn/klconfig.h
deleted file mode 100644
index 96cfd2a..0000000
--- a/include/asm-mips/sn/klconfig.h
+++ /dev/null
@@ -1,898 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Derived from IRIX <sys/SN/klconfig.h>.
- *
- * Copyright (C) 1992 - 1997, 1999, 2000 Silicon Graphics, Inc.
- * Copyright (C) 1999, 2000 by Ralf Baechle
- */
-#ifndef	_ASM_SN_KLCONFIG_H
-#define	_ASM_SN_KLCONFIG_H
-
-/*
- * The KLCONFIG structures store info about the various BOARDs found
- * during Hardware Discovery. In addition, it stores info about the
- * components found on the BOARDs.
- */
-
-/*
- * WARNING:
- *	Certain assembly language routines (notably xxxxx.s) in the IP27PROM
- *	will depend on the format of the data structures in this file.  In
- *      most cases, rearranging the fields can seriously break things.
- *      Adding fields in the beginning or middle can also break things.
- *      Add fields if necessary, to the end of a struct in such a way
- *      that offsets of existing fields do not change.
- */
-
-#include <linux/types.h>
-#include <asm/sn/types.h>
-
-#if defined(CONFIG_SGI_IP27)
-
-#include <asm/sn/sn0/addrs.h>
-//#include <sys/SN/router.h>
-// XXX Stolen from <sys/SN/router.h>:
-#define MAX_ROUTER_PORTS (6)    /* Max. number of ports on a router */
-#include <asm/sn/fru.h>
-//#include <sys/graph.h>
-//#include <sys/xtalk/xbow.h>
-
-#elif defined(CONFIG_SGI_IP35)
-
-#include <asm/sn/sn1/addrs.h>
-#include <sys/sn/router.h>
-#include <sys/graph.h>
-#include <asm/xtalk/xbow.h>
-
-#endif /* !CONFIG_SGI_IP27 && !CONFIG_SGI_IP35 */
-
-#if defined(CONFIG_SGI_IP27) || defined(CONFIG_SGI_IP35)
-#include <asm/sn/agent.h>
-#include <asm/fw/arc/types.h>
-#include <asm/fw/arc/hinv.h>
-#if defined(CONFIG_SGI_IP35)
-// The hack file has to be before vector and after sn0_fru....
-#include <asm/hack.h>
-#include <asm/sn/vector.h>
-#include <asm/xtalk/xtalk.h>
-#endif /* CONFIG_SGI_IP35 */
-#endif /* CONFIG_SGI_IP27 || CONFIG_SGI_IP35 */
-
-typedef u64  nic_t;
-
-#define KLCFGINFO_MAGIC	0xbeedbabe
-
-typedef s32 klconf_off_t;
-
-/*
- * Some IMPORTANT OFFSETS. These are the offsets on all NODES.
- */
-#define	MAX_MODULE_ID		255
-#define SIZE_PAD		4096 /* 4k padding for structures */
-/*
- * 1 NODE brd, 2 Router brd (1 8p, 1 meta), 6 Widgets,
- * 2 Midplanes assuming no pci card cages
- */
-#define MAX_SLOTS_PER_NODE	(1 + 2 + 6 + 2)
-
-/* XXX if each node is guranteed to have some memory */
-
-#define MAX_PCI_DEVS		8
-
-/* lboard_t->brd_flags fields */
-/* All bits in this field are currently used. Try the pad fields if
-   you need more flag bits */
-
-#define ENABLE_BOARD 		0x01
-#define FAILED_BOARD  		0x02
-#define DUPLICATE_BOARD 	0x04    /* Boards like midplanes/routers which
-					   are discovered twice. Use one of them */
-#define VISITED_BOARD		0x08	/* Used for compact hub numbering. */
-#define LOCAL_MASTER_IO6	0x10 	/* master io6 for that node */
-#define GLOBAL_MASTER_IO6	0x20
-#define THIRD_NIC_PRESENT 	0x40  	/* for future use */
-#define SECOND_NIC_PRESENT 	0x80 	/* addons like MIO are present */
-
-/* klinfo->flags fields */
-
-#define KLINFO_ENABLE 		0x01    /* This component is enabled */
-#define KLINFO_FAILED   	0x02 	/* This component failed */
-#define KLINFO_DEVICE   	0x04 	/* This component is a device */
-#define KLINFO_VISITED  	0x08 	/* This component has been visited */
-#define KLINFO_CONTROLLER   	0x10 	/* This component is a device controller */
-#define KLINFO_INSTALL   	0x20  	/* Install a driver */
-#define	KLINFO_HEADLESS		0x40	/* Headless (or hubless) component */
-#define IS_CONSOLE_IOC3(i)	((((klinfo_t *)i)->flags) & KLINFO_INSTALL)
-
-#define GB2		0x80000000
-
-#define MAX_RSV_PTRS	32
-
-/* Structures to manage various data storage areas */
-/* The numbers must be contiguous since the array index i
-   is used in the code to allocate various areas.
-*/
-
-#define BOARD_STRUCT 		0
-#define COMPONENT_STRUCT 	1
-#define ERRINFO_STRUCT 		2
-#define KLMALLOC_TYPE_MAX 	(ERRINFO_STRUCT + 1)
-#define DEVICE_STRUCT 		3
-
-
-typedef struct console_s {
-	unsigned long 	uart_base;
-	unsigned long 	config_base;
-	unsigned long 	memory_base;
-	short		baud;
-	short		flag;
-	int		type;
-	nasid_t		nasid;
-	char		wid;
-	char 		npci;
-	nic_t		baseio_nic;
-} console_t;
-
-typedef struct klc_malloc_hdr {
-        klconf_off_t km_base;
-        klconf_off_t km_limit;
-        klconf_off_t km_current;
-} klc_malloc_hdr_t;
-
-/* Functions/macros needed to use this structure */
-
-typedef struct kl_config_hdr {
-	u64		ch_magic;	/* set this to KLCFGINFO_MAGIC */
-	u32		ch_version;    /* structure version number */
-	klconf_off_t	ch_malloc_hdr_off; /* offset of ch_malloc_hdr */
-	klconf_off_t	ch_cons_off;       /* offset of ch_cons */
-	klconf_off_t	ch_board_info;	/* the link list of boards */
-	console_t	ch_cons_info;	/* address info of the console */
-	klc_malloc_hdr_t ch_malloc_hdr[KLMALLOC_TYPE_MAX];
-	confidence_t	ch_sw_belief;	/* confidence that software is bad*/
-	confidence_t	ch_sn0net_belief; /* confidence that sn0net is bad */
-} kl_config_hdr_t;
-
-
-#define KL_CONFIG_HDR(_nasid) 	((kl_config_hdr_t *)(KLCONFIG_ADDR(_nasid)))
-#define KL_CONFIG_INFO_OFFSET(_nasid)					\
-        (KL_CONFIG_HDR(_nasid)->ch_board_info)
-#define KL_CONFIG_INFO_SET_OFFSET(_nasid, _off)				\
-        (KL_CONFIG_HDR(_nasid)->ch_board_info = (_off))
-
-#define KL_CONFIG_INFO(_nasid) 						\
-        (lboard_t *)((KL_CONFIG_HDR(_nasid)->ch_board_info) ?		\
-	 NODE_OFFSET_TO_K1((_nasid), KL_CONFIG_HDR(_nasid)->ch_board_info) : \
-	 0)
-#define KL_CONFIG_MAGIC(_nasid)		(KL_CONFIG_HDR(_nasid)->ch_magic)
-
-#define KL_CONFIG_CHECK_MAGIC(_nasid)					\
-        (KL_CONFIG_HDR(_nasid)->ch_magic == KLCFGINFO_MAGIC)
-
-#define KL_CONFIG_HDR_INIT_MAGIC(_nasid)	\
-                  (KL_CONFIG_HDR(_nasid)->ch_magic = KLCFGINFO_MAGIC)
-
-/* --- New Macros for the changed kl_config_hdr_t structure --- */
-
-#define PTR_CH_MALLOC_HDR(_k)   ((klc_malloc_hdr_t *)\
-			((unsigned long)_k + (_k->ch_malloc_hdr_off)))
-
-#define KL_CONFIG_CH_MALLOC_HDR(_n)   PTR_CH_MALLOC_HDR(KL_CONFIG_HDR(_n))
-
-#define PTR_CH_CONS_INFO(_k)	((console_t *)\
-			((unsigned long)_k + (_k->ch_cons_off)))
-
-#define KL_CONFIG_CH_CONS_INFO(_n)   PTR_CH_CONS_INFO(KL_CONFIG_HDR(_n))
-
-/* ------------------------------------------------------------- */
-
-#define KL_CONFIG_INFO_START(_nasid)	\
-        (klconf_off_t)(KLCONFIG_OFFSET(_nasid) + sizeof(kl_config_hdr_t))
-
-#define KL_CONFIG_BOARD_NASID(_brd)	((_brd)->brd_nasid)
-#define KL_CONFIG_BOARD_SET_NEXT(_brd, _off)	((_brd)->brd_next = (_off))
-
-#define KL_CONFIG_DUPLICATE_BOARD(_brd)	((_brd)->brd_flags & DUPLICATE_BOARD)
-
-#define XBOW_PORT_TYPE_HUB(_xbowp, _link) 	\
-               ((_xbowp)->xbow_port_info[(_link) - BASE_XBOW_PORT].port_flag & XBOW_PORT_HUB)
-#define XBOW_PORT_TYPE_IO(_xbowp, _link) 	\
-               ((_xbowp)->xbow_port_info[(_link) - BASE_XBOW_PORT].port_flag & XBOW_PORT_IO)
-
-#define XBOW_PORT_IS_ENABLED(_xbowp, _link) 	\
-               ((_xbowp)->xbow_port_info[(_link) - BASE_XBOW_PORT].port_flag & XBOW_PORT_ENABLE)
-#define XBOW_PORT_NASID(_xbowp, _link) 	\
-               ((_xbowp)->xbow_port_info[(_link) - BASE_XBOW_PORT].port_nasid)
-
-#define XBOW_PORT_IO     0x1
-#define XBOW_PORT_HUB    0x2
-#define XBOW_PORT_ENABLE 0x4
-
-#define	SN0_PORT_FENCE_SHFT	0
-#define	SN0_PORT_FENCE_MASK	(1 << SN0_PORT_FENCE_SHFT)
-
-/*
- * The KLCONFIG area is organized as a LINKED LIST of BOARDs. A BOARD
- * can be either 'LOCAL' or 'REMOTE'. LOCAL means it is attached to
- * the LOCAL/current NODE. REMOTE means it is attached to a different
- * node.(TBD - Need a way to treat ROUTER boards.)
- *
- * There are 2 different structures to represent these boards -
- * lboard - Local board, rboard - remote board. These 2 structures
- * can be arbitrarily mixed in the LINKED LIST of BOARDs. (Refer
- * Figure below). The first byte of the rboard or lboard structure
- * is used to find out its type - no unions are used.
- * If it is a lboard, then the config info of this board will be found
- * on the local node. (LOCAL NODE BASE + offset value gives pointer to
- * the structure.
- * If it is a rboard, the local structure contains the node number
- * and the offset of the beginning of the LINKED LIST on the remote node.
- * The details of the hardware on a remote node can be built locally,
- * if required, by reading the LINKED LIST on the remote node and
- * ignoring all the rboards on that node.
- *
- * The local node uses the REMOTE NODE NUMBER + OFFSET to point to the
- * First board info on the remote node. The remote node list is
- * traversed as the local list, using the REMOTE BASE ADDRESS and not
- * the local base address and ignoring all rboard values.
- *
- *
- KLCONFIG
-
- +------------+      +------------+      +------------+      +------------+
- |  lboard    |  +-->|   lboard   |  +-->|   rboard   |  +-->|   lboard   |
- +------------+  |   +------------+  |   +------------+  |   +------------+
- | board info |  |   | board info |  |   |errinfo,bptr|  |   | board info |
- +------------+  |   +------------+  |   +------------+  |   +------------+
- | offset     |--+   |  offset    |--+   |  offset    |--+   |offset=NULL |
- +------------+      +------------+      +------------+      +------------+
-
-
- +------------+
- | board info |
- +------------+       +--------------------------------+
- | compt 1    |------>| type, rev, diaginfo, size ...  |  (CPU)
- +------------+       +--------------------------------+
- | compt 2    |--+
- +------------+  |    +--------------------------------+
- |  ...       |  +--->| type, rev, diaginfo, size ...  |  (MEM_BANK)
- +------------+       +--------------------------------+
- | errinfo    |--+
- +------------+  |    +--------------------------------+
-                 +--->|r/l brd errinfo,compt err flags |
-                      +--------------------------------+
-
- *
- * Each BOARD consists of COMPONENTs and the BOARD structure has
- * pointers (offsets) to its COMPONENT structure.
- * The COMPONENT structure has version info, size and speed info, revision,
- * error info and the NIC info. This structure can accommodate any
- * BOARD with arbitrary COMPONENT composition.
- *
- * The ERRORINFO part of each BOARD has error information
- * that describes errors about the BOARD itself. It also has flags to
- * indicate the COMPONENT(s) on the board that have errors. The error
- * information specific to the COMPONENT is present in the respective
- * COMPONENT structure.
- *
- * The ERRORINFO structure is also treated like a COMPONENT, ie. the
- * BOARD has pointers(offset) to the ERRORINFO structure. The rboard
- * structure also has a pointer to the ERRORINFO structure. This is
- * the place to store ERRORINFO about a REMOTE NODE, if the HUB on
- * that NODE is not working or if the REMOTE MEMORY is BAD. In cases where
- * only the CPU of the REMOTE NODE is disabled, the ERRORINFO pointer can
- * be a NODE NUMBER, REMOTE OFFSET combination, pointing to error info
- * which is present on the REMOTE NODE.(TBD)
- * REMOTE ERRINFO can be stored on any of the nearest nodes
- * or on all the nearest nodes.(TBD)
- * Like BOARD structures, REMOTE ERRINFO structures can be built locally
- * using the rboard errinfo pointer.
- *
- * In order to get useful information from this Data organization, a set of
- * interface routines are provided (TBD). The important thing to remember while
- * manipulating the structures, is that, the NODE number information should
- * be used. If the NODE is non-zero (remote) then each offset should
- * be added to the REMOTE BASE ADDR else it should be added to the LOCAL BASE ADDR.
- * This includes offsets for BOARDS, COMPONENTS and ERRORINFO.
- *
- * Note that these structures do not provide much info about connectivity.
- * That info will be part of HWGRAPH, which is an extension of the cfg_t
- * data structure. (ref IP27prom/cfg.h) It has to be extended to include
- * the IO part of the Network(TBD).
- *
- * The data structures below define the above concepts.
- */
-
-/*
- * Values for CPU types
- */
-#define KL_CPU_R4000		0x1	/* Standard R4000 */
-#define KL_CPU_TFP		0x2	/* TFP processor */
-#define	KL_CPU_R10000		0x3	/* R10000 (T5) */
-#define KL_CPU_NONE		(-1)	/* no cpu present in slot */
-
-/*
- * IP27 BOARD classes
- */
-
-#define KLCLASS_MASK	0xf0
-#define KLCLASS_NONE	0x00
-#define KLCLASS_NODE	0x10             /* CPU, Memory and HUB board */
-#define KLCLASS_CPU	KLCLASS_NODE
-#define KLCLASS_IO	0x20             /* BaseIO, 4 ch SCSI, ethernet, FDDI
-					    and the non-graphics widget boards */
-#define KLCLASS_ROUTER	0x30             /* Router board */
-#define KLCLASS_MIDPLANE 0x40            /* We need to treat this as a board
-                                            so that we can record error info */
-#define KLCLASS_GFX	0x50		/* graphics boards */
-
-#define KLCLASS_PSEUDO_GFX	0x60	/* HDTV type cards that use a gfx
-					 * hw ifc to xtalk and are not gfx
-					 * class for sw purposes */
-
-#define KLCLASS_MAX	7		/* Bump this if a new CLASS is added */
-#define KLTYPE_MAX	10		/* Bump this if a new CLASS is added */
-
-#define KLCLASS_UNKNOWN	0xf0
-
-#define KLCLASS(_x) ((_x) & KLCLASS_MASK)
-
-/*
- * IP27 board types
- */
-
-#define KLTYPE_MASK	0x0f
-#define KLTYPE_NONE	0x00
-#define KLTYPE_EMPTY	0x00
-
-#define KLTYPE_WEIRDCPU (KLCLASS_CPU | 0x0)
-#define KLTYPE_IP27	(KLCLASS_CPU | 0x1) /* 2 CPUs(R10K) per board */
-
-#define KLTYPE_WEIRDIO	(KLCLASS_IO  | 0x0)
-#define KLTYPE_BASEIO	(KLCLASS_IO  | 0x1) /* IOC3, SuperIO, Bridge, SCSI */
-#define KLTYPE_IO6	KLTYPE_BASEIO       /* Additional name */
-#define KLTYPE_4CHSCSI	(KLCLASS_IO  | 0x2)
-#define KLTYPE_MSCSI	KLTYPE_4CHSCSI      /* Additional name */
-#define KLTYPE_ETHERNET	(KLCLASS_IO  | 0x3)
-#define KLTYPE_MENET	KLTYPE_ETHERNET     /* Additional name */
-#define KLTYPE_FDDI  	(KLCLASS_IO  | 0x4)
-#define KLTYPE_UNUSED	(KLCLASS_IO  | 0x5) /* XXX UNUSED */
-#define KLTYPE_HAROLD   (KLCLASS_IO  | 0x6) /* PCI SHOE BOX */
-#define KLTYPE_PCI	KLTYPE_HAROLD
-#define KLTYPE_VME      (KLCLASS_IO  | 0x7) /* Any 3rd party VME card */
-#define KLTYPE_MIO   	(KLCLASS_IO  | 0x8)
-#define KLTYPE_FC    	(KLCLASS_IO  | 0x9)
-#define KLTYPE_LINC    	(KLCLASS_IO  | 0xA)
-#define KLTYPE_TPU    	(KLCLASS_IO  | 0xB) /* Tensor Processing Unit */
-#define KLTYPE_GSN_A   	(KLCLASS_IO  | 0xC) /* Main GSN board */
-#define KLTYPE_GSN_B   	(KLCLASS_IO  | 0xD) /* Auxiliary GSN board */
-
-#define KLTYPE_GFX	(KLCLASS_GFX | 0x0) /* unknown graphics type */
-#define KLTYPE_GFX_KONA (KLCLASS_GFX | 0x1) /* KONA graphics on IP27 */
-#define KLTYPE_GFX_MGRA (KLCLASS_GFX | 0x3) /* MGRAS graphics on IP27 */
-
-#define KLTYPE_WEIRDROUTER (KLCLASS_ROUTER | 0x0)
-#define KLTYPE_ROUTER     (KLCLASS_ROUTER | 0x1)
-#define KLTYPE_ROUTER2    KLTYPE_ROUTER		/* Obsolete! */
-#define KLTYPE_NULL_ROUTER (KLCLASS_ROUTER | 0x2)
-#define KLTYPE_META_ROUTER (KLCLASS_ROUTER | 0x3)
-
-#define KLTYPE_WEIRDMIDPLANE (KLCLASS_MIDPLANE | 0x0)
-#define KLTYPE_MIDPLANE8  (KLCLASS_MIDPLANE | 0x1) /* 8 slot backplane */
-#define KLTYPE_MIDPLANE    KLTYPE_MIDPLANE8
-#define KLTYPE_PBRICK_XBOW	(KLCLASS_MIDPLANE | 0x2)
-
-#define KLTYPE_IOBRICK		(KLCLASS_IOBRICK | 0x0)
-#define KLTYPE_IBRICK		(KLCLASS_IOBRICK | 0x1)
-#define KLTYPE_PBRICK		(KLCLASS_IOBRICK | 0x2)
-#define KLTYPE_XBRICK		(KLCLASS_IOBRICK | 0x3)
-
-#define KLTYPE_PBRICK_BRIDGE	KLTYPE_PBRICK
-
-/* The value of type should be more than 8 so that hinv prints
- * out the board name from the NIC string. For values less than
- * 8 the name of the board needs to be hard coded in a few places.
- * When bringup started nic names had not standardized and so we
- * had to hard code. (For people interested in history.)
- */
-#define KLTYPE_XTHD   	(KLCLASS_PSEUDO_GFX | 0x9)
-
-#define KLTYPE_UNKNOWN	(KLCLASS_UNKNOWN | 0xf)
-
-#define KLTYPE(_x) 	((_x) & KLTYPE_MASK)
-#define IS_MIO_PRESENT(l)	((l->brd_type == KLTYPE_BASEIO) && \
-				 (l->brd_flags & SECOND_NIC_PRESENT))
-#define IS_MIO_IOC3(l, n)	(IS_MIO_PRESENT(l) && (n > 2))
-
-/*
- * board structures
- */
-
-#define MAX_COMPTS_PER_BRD 24
-
-#define LOCAL_BOARD 1
-#define REMOTE_BOARD 2
-
-#define LBOARD_STRUCT_VERSION 	2
-
-typedef struct lboard_s {
-	klconf_off_t 	brd_next;         /* Next BOARD */
-	unsigned char 	struct_type;      /* type of structure, local or remote */
-	unsigned char 	brd_type;         /* type+class */
-	unsigned char 	brd_sversion;     /* version of this structure */
-        unsigned char 	brd_brevision;    /* board revision */
-        unsigned char 	brd_promver;      /* board prom version, if any */
- 	unsigned char 	brd_flags;        /* Enabled, Disabled etc */
-	unsigned char 	brd_slot;         /* slot number */
-	unsigned short	brd_debugsw;      /* Debug switches */
-	moduleid_t	brd_module;       /* module to which it belongs */
-	partid_t 	brd_partition;    /* Partition number */
-        unsigned short 	brd_diagval;      /* diagnostic value */
-        unsigned short 	brd_diagparm;     /* diagnostic parameter */
-        unsigned char 	brd_inventory;    /* inventory history */
-        unsigned char 	brd_numcompts;    /* Number of components */
-        nic_t         	brd_nic;          /* Number in CAN */
-	nasid_t		brd_nasid;        /* passed parameter */
-	klconf_off_t 	brd_compts[MAX_COMPTS_PER_BRD]; /* pointers to COMPONENTS */
-	klconf_off_t 	brd_errinfo;      /* Board's error information */
-	struct lboard_s *brd_parent;	  /* Logical parent for this brd */
-	vertex_hdl_t	brd_graph_link;   /* vertex hdl to connect extern compts */
-	confidence_t	brd_confidence;	  /* confidence that the board is bad */
-	nasid_t		brd_owner;        /* who owns this board */
-	unsigned char 	brd_nic_flags;    /* To handle 8 more NICs */
-	char		brd_name[32];
-} lboard_t;
-
-
-/*
- *	Make sure we pass back the calias space address for local boards.
- *	klconfig board traversal and error structure extraction defines.
- */
-
-#define BOARD_SLOT(_brd)	((_brd)->brd_slot)
-
-#define KLCF_CLASS(_brd)	KLCLASS((_brd)->brd_type)
-#define KLCF_TYPE(_brd)		KLTYPE((_brd)->brd_type)
-#define KLCF_REMOTE(_brd)  	(((_brd)->struct_type & LOCAL_BOARD) ? 0 : 1)
-#define KLCF_NUM_COMPS(_brd)	((_brd)->brd_numcompts)
-#define KLCF_MODULE_ID(_brd)	((_brd)->brd_module)
-
-#define KLCF_NEXT(_brd) 	\
-        ((_brd)->brd_next ? 	\
-	 (lboard_t *)(NODE_OFFSET_TO_K1(NASID_GET(_brd), (_brd)->brd_next)):\
-	 NULL)
-#define KLCF_COMP(_brd, _ndx)   \
-                (klinfo_t *)(NODE_OFFSET_TO_K1(NASID_GET(_brd),	\
-					       (_brd)->brd_compts[(_ndx)]))
-
-#define KLCF_COMP_ERROR(_brd, _comp)	\
-               (NODE_OFFSET_TO_K1(NASID_GET(_brd), (_comp)->errinfo))
-
-#define KLCF_COMP_TYPE(_comp)	((_comp)->struct_type)
-#define KLCF_BRIDGE_W_ID(_comp)	((_comp)->physid)	/* Widget ID */
-
-
-
-/*
- * Generic info structure. This stores common info about a
- * component.
- */
-
-typedef struct klinfo_s {                  /* Generic info */
-        unsigned char   struct_type;       /* type of this structure */
-        unsigned char   struct_version;    /* version of this structure */
-        unsigned char   flags;            /* Enabled, disabled etc */
-        unsigned char   revision;         /* component revision */
-        unsigned short  diagval;          /* result of diagnostics */
-        unsigned short  diagparm;         /* diagnostic parameter */
-        unsigned char   inventory;        /* previous inventory status */
-	nic_t 		nic;              /* MUst be aligned properly */
-        unsigned char   physid;           /* physical id of component */
-        unsigned int    virtid;           /* virtual id as seen by system */
-	unsigned char	widid;	          /* Widget id - if applicable */
-	nasid_t		nasid;            /* node number - from parent */
-	char		pad1;		  /* pad out structure. */
-	char		pad2;		  /* pad out structure. */
-	COMPONENT	*arcs_compt;      /* ptr to the arcs struct for ease*/
-        klconf_off_t	errinfo;          /* component specific errors */
-        unsigned short  pad3;             /* pci fields have moved over to */
-        unsigned short  pad4;             /* klbri_t */
-} klinfo_t ;
-
-#define KLCONFIG_INFO_ENABLED(_i)	((_i)->flags & KLINFO_ENABLE)
-/*
- * Component structures.
- * Following are the currently identified components:
- * 	CPU, HUB, MEM_BANK,
- * 	XBOW(consists of 16 WIDGETs, each of which can be HUB or GRAPHICS or BRIDGE)
- * 	BRIDGE, IOC3, SuperIO, SCSI, FDDI
- * 	ROUTER
- * 	GRAPHICS
- */
-#define KLSTRUCT_UNKNOWN	0
-#define KLSTRUCT_CPU  		1
-#define KLSTRUCT_HUB  		2
-#define KLSTRUCT_MEMBNK 	3
-#define KLSTRUCT_XBOW 		4
-#define KLSTRUCT_BRI 		5
-#define KLSTRUCT_IOC3 		6
-#define KLSTRUCT_PCI 		7
-#define KLSTRUCT_VME 		8
-#define KLSTRUCT_ROU		9
-#define KLSTRUCT_GFX 		10
-#define KLSTRUCT_SCSI 		11
-#define KLSTRUCT_FDDI 		12
-#define KLSTRUCT_MIO 		13
-#define KLSTRUCT_DISK 		14
-#define KLSTRUCT_TAPE 		15
-#define KLSTRUCT_CDROM 		16
-#define KLSTRUCT_HUB_UART 	17
-#define KLSTRUCT_IOC3ENET 	18
-#define KLSTRUCT_IOC3UART 	19
-#define KLSTRUCT_UNUSED		20 /* XXX UNUSED */
-#define KLSTRUCT_IOC3PCKM       21
-#define KLSTRUCT_RAD        	22
-#define KLSTRUCT_HUB_TTY        23
-#define KLSTRUCT_IOC3_TTY 	24
-
-/* Early Access IO proms are compatible
-   only with KLSTRUCT values upto 24. */
-
-#define KLSTRUCT_FIBERCHANNEL 	25
-#define KLSTRUCT_MOD_SERIAL_NUM 26
-#define KLSTRUCT_IOC3MS         27
-#define KLSTRUCT_TPU            28
-#define KLSTRUCT_GSN_A          29
-#define KLSTRUCT_GSN_B          30
-#define KLSTRUCT_XTHD           31
-
-/*
- * These are the indices of various components within a lboard structure.
- */
-
-#define IP27_CPU0_INDEX 0
-#define IP27_CPU1_INDEX 1
-#define IP27_HUB_INDEX 2
-#define IP27_MEM_INDEX 3
-
-#define BASEIO_BRIDGE_INDEX 0
-#define BASEIO_IOC3_INDEX 1
-#define BASEIO_SCSI1_INDEX 2
-#define BASEIO_SCSI2_INDEX 3
-
-#define MIDPLANE_XBOW_INDEX 0
-#define ROUTER_COMPONENT_INDEX 0
-
-#define CH4SCSI_BRIDGE_INDEX 0
-
-/* Info holders for various hardware components */
-
-typedef u64 *pci_t;
-typedef u64 *vmeb_t;
-typedef u64 *vmed_t;
-typedef u64 *fddi_t;
-typedef u64 *scsi_t;
-typedef u64 *mio_t;
-typedef u64 *graphics_t;
-typedef u64 *router_t;
-
-/*
- * The port info in ip27_cfg area translates to a lboart_t in the
- * KLCONFIG area. But since KLCONFIG does not use pointers, lboart_t
- * is stored in terms of a nasid and a offset from start of KLCONFIG
- * area  on that nasid.
- */
-typedef struct klport_s {
-	nasid_t		port_nasid;
-	unsigned char	port_flag;
-	klconf_off_t	port_offset;
-} klport_t;
-
-typedef struct klcpu_s {                          /* CPU */
-	klinfo_t 	cpu_info;
-	unsigned short 	cpu_prid;	/* Processor PRID value */
-	unsigned short 	cpu_fpirr;	/* FPU IRR value */
-    	unsigned short 	cpu_speed;	/* Speed in MHZ */
-    	unsigned short 	cpu_scachesz;	/* secondary cache size in MB */
-    	unsigned short 	cpu_scachespeed;/* secondary cache speed in MHz */
-} klcpu_t ;
-
-#define CPU_STRUCT_VERSION   2
-
-typedef struct klhub_s {			/* HUB */
-	klinfo_t 	hub_info;
-	unsigned int 		hub_flags;		/* PCFG_HUB_xxx flags */
-	klport_t	hub_port;		/* hub is connected to this */
-	nic_t		hub_box_nic;		/* nic of containing box */
-	klconf_off_t	hub_mfg_nic;		/* MFG NIC string */
-	u64		hub_speed;		/* Speed of hub in HZ */
-} klhub_t ;
-
-typedef struct klhub_uart_s {			/* HUB */
-	klinfo_t 	hubuart_info;
-	unsigned int 		hubuart_flags;		/* PCFG_HUB_xxx flags */
-	nic_t		hubuart_box_nic;	/* nic of containing box */
-} klhub_uart_t ;
-
-#define MEMORY_STRUCT_VERSION   2
-
-typedef struct klmembnk_s {			/* MEMORY BANK */
-	klinfo_t 	membnk_info;
-    	short 		membnk_memsz;		/* Total memory in megabytes */
-	short		membnk_dimm_select; /* bank to physical addr mapping*/
-	short		membnk_bnksz[MD_MEM_BANKS]; /* Memory bank sizes */
-	short		membnk_attr;
-} klmembnk_t ;
-
-#define KLCONFIG_MEMBNK_SIZE(_info, _bank)	\
-                            ((_info)->membnk_bnksz[(_bank)])
-
-
-#define MEMBNK_PREMIUM 1
-#define KLCONFIG_MEMBNK_PREMIUM(_info, _bank)	\
-                            ((_info)->membnk_attr & (MEMBNK_PREMIUM << (_bank)))
-
-#define MAX_SERIAL_NUM_SIZE 10
-
-typedef struct klmod_serial_num_s {
-      klinfo_t        snum_info;
-      union {
-              char snum_str[MAX_SERIAL_NUM_SIZE];
-              unsigned long long       snum_int;
-      } snum;
-} klmod_serial_num_t;
-
-/* Macros needed to access serial number structure in lboard_t.
-   Hard coded values are necessary since we cannot treat
-   serial number struct as a component without losing compatibility
-   between prom versions. */
-
-#define GET_SNUM_COMP(_l) 	((klmod_serial_num_t *)\
-				KLCF_COMP(_l, _l->brd_numcompts))
-
-#define MAX_XBOW_LINKS 16
-
-typedef struct klxbow_s {                          /* XBOW */
-	klinfo_t 	xbow_info ;
-    	klport_t	xbow_port_info[MAX_XBOW_LINKS] ; /* Module number */
-        int		xbow_master_hub_link;
-        /* type of brd connected+component struct ptr+flags */
-} klxbow_t ;
-
-#define MAX_PCI_SLOTS 8
-
-typedef struct klpci_device_s {
-	s32	pci_device_id;	/* 32 bits of vendor/device ID. */
-	s32	pci_device_pad;	/* 32 bits of padding. */
-} klpci_device_t;
-
-#define BRIDGE_STRUCT_VERSION	2
-
-typedef struct klbri_s {                          /* BRIDGE */
-	klinfo_t 	bri_info ;
-    	unsigned char	bri_eprominfo ;    /* IO6prom connected to bridge */
-    	unsigned char	bri_bustype ;      /* PCI/VME BUS bridge/GIO */
-    	pci_t    	pci_specific  ;    /* PCI Board config info */
-	klpci_device_t	bri_devices[MAX_PCI_DEVS] ;	/* PCI IDs */
-	klconf_off_t	bri_mfg_nic ;
-} klbri_t ;
-
-#define MAX_IOC3_TTY	2
-
-typedef struct klioc3_s {                          /* IOC3 */
-	klinfo_t 	ioc3_info ;
-    	unsigned char	ioc3_ssram ;        /* Info about ssram */
-    	unsigned char	ioc3_nvram ;        /* Info about nvram */
-    	klinfo_t	ioc3_superio ;      /* Info about superio */
-	klconf_off_t	ioc3_tty_off ;
-	klinfo_t	ioc3_enet ;
-	klconf_off_t	ioc3_enet_off ;
-	klconf_off_t	ioc3_kbd_off ;
-} klioc3_t ;
-
-#define MAX_VME_SLOTS 8
-
-typedef struct klvmeb_s {                          /* VME BRIDGE - PCI CTLR */
-	klinfo_t 	vmeb_info ;
-	vmeb_t		vmeb_specific ;
-    	klconf_off_t   	vmeb_brdinfo[MAX_VME_SLOTS]   ;    /* VME Board config info */
-} klvmeb_t ;
-
-typedef struct klvmed_s {                          /* VME DEVICE - VME BOARD */
-	klinfo_t	vmed_info ;
-	vmed_t		vmed_specific ;
-    	klconf_off_t   	vmed_brdinfo[MAX_VME_SLOTS]   ;    /* VME Board config info */
-} klvmed_t ;
-
-#define ROUTER_VECTOR_VERS	2
-
-/* XXX - Don't we need the number of ports here?!? */
-typedef struct klrou_s {                          /* ROUTER */
-	klinfo_t 	rou_info ;
-	unsigned int		rou_flags ;           /* PCFG_ROUTER_xxx flags */
-	nic_t		rou_box_nic ;         /* nic of the containing module */
-    	klport_t 	rou_port[MAX_ROUTER_PORTS + 1] ; /* array index 1 to 6 */
-	klconf_off_t	rou_mfg_nic ;     /* MFG NIC string */
-	u64	rou_vector;	  /* vector from master node */
-} klrou_t ;
-
-/*
- *  Graphics Controller/Device
- *
- *  (IP27/IO6) Prom versions 6.13 (and 6.5.1 kernels) and earlier
- *  used a couple different structures to store graphics information.
- *  For compatibility reasons, the newer data structure preserves some
- *  of the layout so that fields that are used in the old versions remain
- *  in the same place (with the same info).  Determination of what version
- *  of this structure we have is done by checking the cookie field.
- */
-#define KLGFX_COOKIE	0x0c0de000
-
-typedef struct klgfx_s {		/* GRAPHICS Device */
-	klinfo_t 	gfx_info;
-	klconf_off_t    old_gndevs;	/* for compatibility with older proms */
-	klconf_off_t    old_gdoff0;	/* for compatibility with older proms */
-	unsigned int		cookie;		/* for compatibility with older proms */
-	unsigned int		moduleslot;
-	struct klgfx_s	*gfx_next_pipe;
-	graphics_t	gfx_specific;
-	klconf_off_t    pad0;		/* for compatibility with older proms */
-	klconf_off_t    gfx_mfg_nic;
-} klgfx_t;
-
-typedef struct klxthd_s {
-	klinfo_t 	xthd_info ;
-	klconf_off_t	xthd_mfg_nic ;        /* MFG NIC string */
-} klxthd_t ;
-
-typedef struct kltpu_s {                     /* TPU board */
-	klinfo_t 	tpu_info ;
-	klconf_off_t	tpu_mfg_nic ;        /* MFG NIC string */
-} kltpu_t ;
-
-typedef struct klgsn_s {                     /* GSN board */
-	klinfo_t 	gsn_info ;
-	klconf_off_t	gsn_mfg_nic ;        /* MFG NIC string */
-} klgsn_t ;
-
-#define MAX_SCSI_DEVS 16
-
-/*
- * NOTE: THis is the max sized kl* structure and is used in klmalloc.c
- * to allocate space of type COMPONENT. Make sure that if the size of
- * any other component struct becomes more than this, then redefine
- * that as the size to be klmalloced.
- */
-
-typedef struct klscsi_s {                          /* SCSI Controller */
-	klinfo_t 	scsi_info ;
-    	scsi_t       	scsi_specific   ;
-	unsigned char 	scsi_numdevs ;
-	klconf_off_t	scsi_devinfo[MAX_SCSI_DEVS] ;
-} klscsi_t ;
-
-typedef struct klscdev_s {                          /* SCSI device */
-	klinfo_t 	scdev_info ;
-	struct scsidisk_data *scdev_cfg ; /* driver fills up this */
-} klscdev_t ;
-
-typedef struct klttydev_s {                          /* TTY device */
-	klinfo_t 	ttydev_info ;
-	struct terminal_data *ttydev_cfg ; /* driver fills up this */
-} klttydev_t ;
-
-typedef struct klenetdev_s {                          /* ENET device */
-	klinfo_t 	enetdev_info ;
-	struct net_data *enetdev_cfg ; /* driver fills up this */
-} klenetdev_t ;
-
-typedef struct klkbddev_s {                          /* KBD device */
-	klinfo_t 	kbddev_info ;
-	struct keyboard_data *kbddev_cfg ; /* driver fills up this */
-} klkbddev_t ;
-
-typedef struct klmsdev_s {                          /* mouse device */
-        klinfo_t        msdev_info ;
-        void 		*msdev_cfg ;
-} klmsdev_t ;
-
-#define MAX_FDDI_DEVS 10 /* XXX Is this true */
-
-typedef struct klfddi_s {                          /* FDDI */
-	klinfo_t 	fddi_info ;
-    	fddi_t        	fddi_specific ;
-	klconf_off_t	fddi_devinfo[MAX_FDDI_DEVS] ;
-} klfddi_t ;
-
-typedef struct klmio_s {                          /* MIO */
-	klinfo_t 	mio_info ;
-    	mio_t       	mio_specific   ;
-} klmio_t ;
-
-
-typedef union klcomp_s {
-	klcpu_t		kc_cpu;
-	klhub_t		kc_hub;
-	klmembnk_t 	kc_mem;
-	klxbow_t  	kc_xbow;
-	klbri_t		kc_bri;
-	klioc3_t	kc_ioc3;
-	klvmeb_t	kc_vmeb;
-	klvmed_t	kc_vmed;
-	klrou_t		kc_rou;
-	klgfx_t		kc_gfx;
-	klscsi_t	kc_scsi;
-	klscdev_t	kc_scsi_dev;
-	klfddi_t	kc_fddi;
-	klmio_t		kc_mio;
-	klmod_serial_num_t kc_snum ;
-} klcomp_t;
-
-typedef union kldev_s {      /* for device structure allocation */
-	klscdev_t	kc_scsi_dev ;
-	klttydev_t	kc_tty_dev ;
-	klenetdev_t	kc_enet_dev ;
-	klkbddev_t 	kc_kbd_dev ;
-} kldev_t ;
-
-/* Data structure interface routines. TBD */
-
-/* Include launch info in this file itself? TBD */
-
-/*
- * TBD - Can the ARCS and device driver related info also be included in the
- * KLCONFIG area. On the IO4PROM, prom device driver info is part of cfgnode_t
- * structure, viz private to the IO4prom.
- */
-
-/*
- * TBD - Allocation issues.
- *
- * Do we need to Mark off sepatate heaps for lboard_t, rboard_t, component,
- * errinfo and allocate from them, or have a single heap and allocate all
- * structures from it. Debug is easier in the former method since we can
- * dump all similar structs in one command, but there will be lots of holes,
- * in memory and max limits are needed for number of structures.
- * Another way to make it organized, is to have a union of all components
- * and allocate a aligned chunk of memory greater than the biggest
- * component.
- */
-
-typedef union {
-	lboard_t *lbinfo ;
-} biptr_t ;
-
-
-#define BRI_PER_XBOW 6
-#define PCI_PER_BRI  8
-#define DEV_PER_PCI  16
-
-
-/* Virtual dipswitch values (starting from switch "7"): */
-
-#define VDS_NOGFX		0x8000	/* Don't enable gfx and autoboot */
-#define VDS_NOMP		0x100	/* Don't start slave processors */
-#define VDS_MANUMODE		0x80	/* Manufacturing mode */
-#define VDS_NOARB		0x40	/* No bootmaster arbitration */
-#define VDS_PODMODE		0x20	/* Go straight to POD mode */
-#define VDS_NO_DIAGS		0x10	/* Don't run any diags after BM arb */
-#define VDS_DEFAULTS		0x08	/* Use default environment values */
-#define VDS_NOMEMCLEAR		0x04	/* Don't run mem cfg code */
-#define VDS_2ND_IO4		0x02	/* Boot from the second IO4 */
-#define VDS_DEBUG_PROM		0x01	/* Print PROM debugging messages */
-
-/* external declarations of Linux kernel functions. */
-
-extern lboard_t *find_lboard(lboard_t *start, unsigned char type);
-extern klinfo_t *find_component(lboard_t *brd, klinfo_t *kli, unsigned char type);
-extern klinfo_t *find_first_component(lboard_t *brd, unsigned char type);
-extern klcpu_t *nasid_slice_to_cpuinfo(nasid_t, int);
-extern lboard_t *find_lboard_class(lboard_t *start, unsigned char brd_class);
-
-
-extern klcpu_t *sn_get_cpuinfo(cpuid_t cpu);
-
-#endif /* _ASM_SN_KLCONFIG_H */
diff --git a/include/asm-mips/sn/mapped_kernel.h b/include/asm-mips/sn/mapped_kernel.h
deleted file mode 100644
index c3dd5d0..0000000
--- a/include/asm-mips/sn/mapped_kernel.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * File created by Kanoj Sarcar 06/06/00.
- * Copyright 2000 Silicon Graphics, Inc.
- */
-#ifndef __ASM_SN_MAPPED_KERNEL_H
-#define __ASM_SN_MAPPED_KERNEL_H
-
-/*
- * Note on how mapped kernels work: the text and data section is
- * compiled at cksseg segment (LOADADDR = 0xc001c000), and the
- * init/setup/data section gets a 16M virtual address bump in the
- * ld.script file (so that tlblo0 and tlblo1 maps the sections).
- * The vmlinux.64 section addresses are put in the xkseg range
- * using the change-addresses makefile option. Use elfdump -of
- * on IRIX to see where the sections go. The Origin loader loads
- * the two sections contiguously in physical memory. The loader
- * sets the entry point into kernel_entry using a xkphys address,
- * but instead of using 0xa800000001160000, it uses the address
- * 0xa800000000160000, which is where it physically loaded that
- * code. So no jumps can be done before we have switched to using
- * cksseg addresses.
- */
-#include <asm/addrspace.h>
-
-#define REP_BASE	CAC_BASE
-
-#ifdef CONFIG_MAPPED_KERNEL
-
-#define MAPPED_ADDR_RO_TO_PHYS(x)	(x - REP_BASE)
-#define MAPPED_ADDR_RW_TO_PHYS(x)	(x - REP_BASE - 16777216)
-
-#define MAPPED_KERN_RO_PHYSBASE(n) \
-			(PLAT_NODE_DATA(n)->kern_vars.kv_ro_baseaddr)
-#define MAPPED_KERN_RW_PHYSBASE(n) \
-			(PLAT_NODE_DATA(n)->kern_vars.kv_rw_baseaddr)
-
-#define MAPPED_KERN_RO_TO_PHYS(x) \
-				((unsigned long)MAPPED_ADDR_RO_TO_PHYS(x) | \
-				MAPPED_KERN_RO_PHYSBASE(get_compact_nodeid()))
-#define MAPPED_KERN_RW_TO_PHYS(x) \
-				((unsigned long)MAPPED_ADDR_RW_TO_PHYS(x) | \
-				MAPPED_KERN_RW_PHYSBASE(get_compact_nodeid()))
-
-#else /* CONFIG_MAPPED_KERNEL */
-
-#define MAPPED_KERN_RO_TO_PHYS(x)	(x - REP_BASE)
-#define MAPPED_KERN_RW_TO_PHYS(x)	(x - REP_BASE)
-
-#endif /* CONFIG_MAPPED_KERNEL */
-
-#define MAPPED_KERN_RO_TO_K0(x)	PHYS_TO_K0(MAPPED_KERN_RO_TO_PHYS(x))
-#define MAPPED_KERN_RW_TO_K0(x)	PHYS_TO_K0(MAPPED_KERN_RW_TO_PHYS(x))
-
-#endif /* __ASM_SN_MAPPED_KERNEL_H  */
diff --git a/include/asm-mips/sn/sn0/hubio.h b/include/asm-mips/sn/sn0/hubio.h
deleted file mode 100644
index 0187895..0000000
--- a/include/asm-mips/sn/sn0/hubio.h
+++ /dev/null
@@ -1,972 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Derived from IRIX <sys/SN/SN0/hubio.h>, Revision 1.80.
- *
- * Copyright (C) 1992 - 1997, 1999 Silicon Graphics, Inc.
- * Copyright (C) 1999 by Ralf Baechle
- */
-#ifndef	_ASM_SGI_SN_SN0_HUBIO_H
-#define	_ASM_SGI_SN_SN0_HUBIO_H
-
-/*
- * Hub I/O interface registers
- *
- * All registers in this file are subject to change until Hub chip tapeout.
- * In general, the longer software name should be used when available.
- */
-
-/*
- * Slightly friendlier names for some common registers.
- * The hardware definitions follow.
- */
-#define IIO_WIDGET		IIO_WID      /* Widget identification */
-#define IIO_WIDGET_STAT		IIO_WSTAT    /* Widget status register */
-#define IIO_WIDGET_CTRL		IIO_WCR	     /* Widget control register */
-#define IIO_WIDGET_TOUT		IIO_WRTO     /* Widget request timeout */
-#define IIO_WIDGET_FLUSH	IIO_WTFR     /* Widget target flush */
-#define IIO_PROTECT		IIO_ILAPR    /* IO interface protection */
-#define IIO_PROTECT_OVRRD	IIO_ILAPO    /* IO protect override */
-#define IIO_OUTWIDGET_ACCESS	IIO_IOWA     /* Outbound widget access */
-#define IIO_INWIDGET_ACCESS	IIO_IIWA     /* Inbound widget access */
-#define IIO_INDEV_ERR_MASK	IIO_IIDEM    /* Inbound device error mask */
-#define IIO_LLP_CSR		IIO_ILCSR    /* LLP control and status */
-#define IIO_LLP_LOG		IIO_ILLR     /* LLP log */
-#define IIO_XTALKCC_TOUT	IIO_IXCC     /* Xtalk credit count timeout*/
-#define IIO_XTALKTT_TOUT	IIO_IXTT     /* Xtalk tail timeout */
-#define IIO_IO_ERR_CLR		IIO_IECLR    /* IO error clear */
-#define IIO_BTE_CRB_CNT         IIO_IBCN     /* IO BTE CRB count */
-
-#define IIO_LLP_CSR_IS_UP		0x00002000
-#define	IIO_LLP_CSR_LLP_STAT_MASK	0x00003000
-#define	IIO_LLP_CSR_LLP_STAT_SHFT	12
-
-/* key to IIO_PROTECT_OVRRD */
-#define IIO_PROTECT_OVRRD_KEY	0x53474972756c6573ull	/* "SGIrules" */
-
-/* BTE register names */
-#define IIO_BTE_STAT_0		IIO_IBLS_0   /* Also BTE length/status 0 */
-#define IIO_BTE_SRC_0		IIO_IBSA_0   /* Also BTE source address  0 */
-#define IIO_BTE_DEST_0		IIO_IBDA_0   /* Also BTE dest. address 0 */
-#define IIO_BTE_CTRL_0		IIO_IBCT_0   /* Also BTE control/terminate 0 */
-#define IIO_BTE_NOTIFY_0 	IIO_IBNA_0   /* Also BTE notification 0 */
-#define IIO_BTE_INT_0		IIO_IBIA_0   /* Also BTE interrupt 0 */
-#define IIO_BTE_OFF_0		0	     /* Base offset from BTE 0 regs. */
-#define IIO_BTE_OFF_1	IIO_IBLS_1 - IIO_IBLS_0 /* Offset from base to BTE 1 */
-
-/* BTE register offsets from base */
-#define BTEOFF_STAT		0
-#define BTEOFF_SRC		(IIO_BTE_SRC_0 - IIO_BTE_STAT_0)
-#define BTEOFF_DEST		(IIO_BTE_DEST_0 - IIO_BTE_STAT_0)
-#define BTEOFF_CTRL		(IIO_BTE_CTRL_0 - IIO_BTE_STAT_0)
-#define BTEOFF_NOTIFY		(IIO_BTE_NOTIFY_0 - IIO_BTE_STAT_0)
-#define BTEOFF_INT		(IIO_BTE_INT_0 - IIO_BTE_STAT_0)
-
-
-/*
- * The following definitions use the names defined in the IO interface
- * document for ease of reference.  When possible, software should
- * generally use the longer but clearer names defined above.
- */
-
-#define IIO_BASE	0x400000
-#define IIO_BASE_BTE0	0x410000
-#define IIO_BASE_BTE1	0x420000
-#define IIO_BASE_PERF	0x430000
-#define IIO_PERF_CNT	0x430008
-
-#define IO_PERF_SETS	32
-
-#define IIO_WID		0x400000	/* Widget identification */
-#define IIO_WSTAT	0x400008	/* Widget status */
-#define IIO_WCR		0x400020	/* Widget control */
-
-#define	IIO_WSTAT_ECRAZY	(1ULL << 32)	/* Hub gone crazy */
-#define	IIO_WSTAT_TXRETRY	(1ULL << 9)	/* Hub Tx Retry timeout */
-#define	IIO_WSTAT_TXRETRY_MASK	(0x7F)
-#define	IIO_WSTAT_TXRETRY_SHFT	(16)
-#define	IIO_WSTAT_TXRETRY_CNT(w)	(((w) >> IIO_WSTAT_TXRETRY_SHFT) & \
-					  IIO_WSTAT_TXRETRY_MASK)
-
-#define IIO_ILAPR	0x400100	/* Local Access Protection */
-#define IIO_ILAPO	0x400108	/* Protection override */
-#define IIO_IOWA	0x400110	/* outbound widget access */
-#define IIO_IIWA	0x400118	/* inbound widget access */
-#define IIO_IIDEM	0x400120	/* Inbound Device Error Mask */
-#define IIO_ILCSR	0x400128	/* LLP control and status */
-#define IIO_ILLR	0x400130	/* LLP Log */
-#define IIO_IIDSR	0x400138	/* Interrupt destination */
-
-#define IIO_IIBUSERR	0x1400208	/* Reads here cause a bus error. */
-
-/* IO Interrupt Destination Register */
-#define IIO_IIDSR_SENT_SHIFT	28
-#define IIO_IIDSR_SENT_MASK	0x10000000
-#define IIO_IIDSR_ENB_SHIFT	24
-#define IIO_IIDSR_ENB_MASK	0x01000000
-#define IIO_IIDSR_NODE_SHIFT	8
-#define IIO_IIDSR_NODE_MASK	0x0000ff00
-#define IIO_IIDSR_LVL_SHIFT	0
-#define IIO_IIDSR_LVL_MASK	0x0000003f
-
-
-/* GFX Flow Control Node/Widget Register */
-#define IIO_IGFX_0	0x400140	/* gfx node/widget register 0 */
-#define IIO_IGFX_1	0x400148	/* gfx node/widget register 1 */
-#define IIO_IGFX_W_NUM_BITS	4	/* size of widget num field */
-#define IIO_IGFX_W_NUM_MASK	((1<<IIO_IGFX_W_NUM_BITS)-1)
-#define IIO_IGFX_W_NUM_SHIFT	0
-#define IIO_IGFX_N_NUM_BITS	9	/* size of node num field */
-#define IIO_IGFX_N_NUM_MASK	((1<<IIO_IGFX_N_NUM_BITS)-1)
-#define IIO_IGFX_N_NUM_SHIFT	4
-#define IIO_IGFX_P_NUM_BITS	1	/* size of processor num field */
-#define IIO_IGFX_P_NUM_MASK	((1<<IIO_IGFX_P_NUM_BITS)-1)
-#define IIO_IGFX_P_NUM_SHIFT	16
-#define IIO_IGFX_VLD_BITS	1	/* size of valid field */
-#define IIO_IGFX_VLD_MASK	((1<<IIO_IGFX_VLD_BITS)-1)
-#define IIO_IGFX_VLD_SHIFT	20
-#define IIO_IGFX_INIT(widget, node, cpu, valid)				(\
-	(((widget) & IIO_IGFX_W_NUM_MASK) << IIO_IGFX_W_NUM_SHIFT) |	 \
-	(((node)   & IIO_IGFX_N_NUM_MASK) << IIO_IGFX_N_NUM_SHIFT) |	 \
-	(((cpu)    & IIO_IGFX_P_NUM_MASK) << IIO_IGFX_P_NUM_SHIFT) |	 \
-	(((valid)  & IIO_IGFX_VLD_MASK)   << IIO_IGFX_VLD_SHIFT)	 )
-
-/* Scratch registers (not all bits available) */
-#define IIO_SCRATCH_REG0	0x400150
-#define	IIO_SCRATCH_REG1	0x400158
-#define IIO_SCRATCH_MASK	0x0000000f00f11fff
-
-#define IIO_SCRATCH_BIT0_0	0x0000000800000000
-#define IIO_SCRATCH_BIT0_1	0x0000000400000000
-#define IIO_SCRATCH_BIT0_2	0x0000000200000000
-#define IIO_SCRATCH_BIT0_3	0x0000000100000000
-#define IIO_SCRATCH_BIT0_4	0x0000000000800000
-#define IIO_SCRATCH_BIT0_5	0x0000000000400000
-#define IIO_SCRATCH_BIT0_6	0x0000000000200000
-#define IIO_SCRATCH_BIT0_7	0x0000000000100000
-#define IIO_SCRATCH_BIT0_8	0x0000000000010000
-#define IIO_SCRATCH_BIT0_9	0x0000000000001000
-#define IIO_SCRATCH_BIT0_R	0x0000000000000fff
-
-/* IO Translation Table Entries */
-#define IIO_NUM_ITTES	7		/* ITTEs numbered 0..6 */
-					/* Hw manuals number them 1..7! */
-
-/*
- * As a permanent workaround for a bug in the PI side of the hub, we've
- * redefined big window 7 as small window 0.
- */
-#define HUB_NUM_BIG_WINDOW	IIO_NUM_ITTES - 1
-
-/*
- * Use the top big window as a surrogate for the first small window
- */
-#define SWIN0_BIGWIN		HUB_NUM_BIG_WINDOW
-
-#define ILCSR_WARM_RESET	0x100
-/*
- * The IO LLP control status register and widget control register
- */
-#ifndef __ASSEMBLY__
-
-typedef union hubii_wid_u {
-	u64	wid_reg_value;
-	struct {
-		u64 	wid_rsvd: 	32,	/* unused */
-                   	wid_rev_num:	 4,	/* revision number */
-                   	wid_part_num:	16,	/* the widget type: hub=c101 */
-                   	wid_mfg_num:	11,	/* Manufacturer id (IBM) */
-                   	wid_rsvd1:	 1;	/* Reserved */
-        } wid_fields_s;
-} hubii_wid_t;
-
-
-typedef union hubii_wcr_u {
-	u64	wcr_reg_value;
-	struct {
-		u64 	wcr_rsvd: 	41,	/* unused */
-                   	wcr_e_thresh:	 5,	/* elasticity threshold */
-			wcr_dir_con:	 1,	/* widget direct connect */
-                   	wcr_f_bad_pkt:	 1,	/* Force bad llp pkt enable */
-                   	wcr_xbar_crd:	 3,	/* LLP crossbar credit */
-                   	wcr_rsvd1:	 8,	/* Reserved */
-			wcr_tag_mode:    1,	/* Tag mode */
-                   	wcr_widget_id:	 4;	/* LLP crossbar credit */
-        } wcr_fields_s;
-} hubii_wcr_t;
-
-#define	iwcr_dir_con	wcr_fields_s.wcr_dir_con
-
-typedef union hubii_wstat_u {
-	u64      reg_value;
-	struct {
-		u64	rsvd1:		31,
-			crazy:		 1,	/* Crazy bit		*/
-			rsvd2:		 8,
-			llp_tx_cnt:	 8, 	/* LLP Xmit retry counter */
-			rsvd3:		 6,
-			tx_max_rtry:	 1,	/* LLP Retry Timeout Signal */
-			rsvd4:		 2,
-			xt_tail_to:	 1,	/* Xtalk Tail Timeout	*/
-			xt_crd_to:	 1,	/* Xtalk Credit Timeout	*/
-			pending:	 4;	/* Pending Requests	*/
-	} wstat_fields_s;
-} hubii_wstat_t;
-
-
-typedef union hubii_ilcsr_u {
-	u64	icsr_reg_value;
-	struct {
-		u64 	icsr_rsvd: 	22,	/* unused */
-                   	icsr_max_burst:	10,	/* max burst */
-                        icsr_rsvd4:	 6,	/* reserved */
-                   	icsr_max_retry:	10,	/* max retry */
-                        icsr_rsvd3:	 2,	/* reserved */
-                        icsr_lnk_stat:	 2,	/* link status */
-                        icsr_bm8:	 1,	/* Bit mode 8 */
-                        icsr_llp_en:	 1,	/* LLP enable bit */
-                 	icsr_rsvd2:	 1,     /* reserver */
-                        icsr_wrm_reset:	 1,	/* Warm reset bit */
-			icsr_rsvd1:	 2,	/* Data ready offset */
-                        icsr_null_to:	 6;	/* Null timeout   */
-
-        } icsr_fields_s;
-} hubii_ilcsr_t;
-
-
-typedef union hubii_iowa_u {
-	u64	iowa_reg_value;
-	struct {
-		u64 	iowa_rsvd: 	48,	/* unused */
-                       	iowa_wxoac:	 8,	/* xtalk widget access bits */
-                   	iowa_rsvd1:	 7,	/* xtalk widget access bits */
-                  	iowa_w0oac:	 1;	/* xtalk widget access bits */
-        } iowa_fields_s;
-} hubii_iowa_t;
-
-typedef union hubii_iiwa_u {
-	u64	iiwa_reg_value;
-	struct {
-		u64 	iiwa_rsvd: 	48,	/* unused */
-			iiwa_wxiac:	 8,	/* hub wid access bits */
-			iiwa_rsvd1:	 7,	/* reserved */
-			iiwa_w0iac:	 1;	/* hub wid0 access */
-        } iiwa_fields_s;
-} hubii_iiwa_t;
-
-typedef union	hubii_illr_u {
-	u64	illr_reg_value;
-	struct {
-		u64 	illr_rsvd: 	32,	/* unused */
-			illr_cb_cnt:	16,	/* checkbit error count */
-                   	illr_sn_cnt:	16;	/* sequence number count */
-        } illr_fields_s;
-} hubii_illr_t;
-
-/* The structures below are defined to extract and modify the ii
-performance registers */
-
-/* io_perf_sel allows the caller to specify what tests will be
-   performed */
-typedef union io_perf_sel {
-	u64 perf_sel_reg;
-	struct {
-		u64 	perf_rsvd  : 48,
-			perf_icct  :  8,
-		 	perf_ippr1 :  4,
-			perf_ippr0 :  4;
-	} perf_sel_bits;
-} io_perf_sel_t;
-
-/* io_perf_cnt is to extract the count from the hub registers. Due to
-   hardware problems there is only one counter, not two. */
-
-typedef union io_perf_cnt {
-	u64	perf_cnt;
-	struct {
-		u64	perf_rsvd1 : 32,
-			perf_rsvd2 : 12,
-			perf_cnt   : 20;
-	} perf_cnt_bits;
-} io_perf_cnt_t;
-
-#endif /* !__ASSEMBLY__ */
-
-
-#define LNK_STAT_WORKING	0x2
-
-#define IIO_LLP_CB_MAX	0xffff
-#define IIO_LLP_SN_MAX	0xffff
-
-/* IO PRB Entries */
-#define	IIO_NUM_IPRBS	(9)
-#define IIO_IOPRB_0	0x400198	/* PRB entry 0 */
-#define IIO_IOPRB_8	0x4001a0	/* PRB entry 8 */
-#define IIO_IOPRB_9	0x4001a8	/* PRB entry 9 */
-#define IIO_IOPRB_A	0x4001b0	/* PRB entry a */
-#define IIO_IOPRB_B	0x4001b8	/* PRB entry b */
-#define IIO_IOPRB_C	0x4001c0	/* PRB entry c */
-#define IIO_IOPRB_D	0x4001c8	/* PRB entry d */
-#define IIO_IOPRB_E	0x4001d0	/* PRB entry e */
-#define IIO_IOPRB_F	0x4001d8	/* PRB entry f */
-
-
-#define IIO_IXCC	0x4001e0	/* Crosstalk credit count timeout */
-#define IIO_IXTCC	IIO_IXCC
-#define IIO_IMEM	0x4001e8	/* Miscellaneous Enable Mask */
-#define IIO_IXTT	0x4001f0	/* Crosstalk tail timeout */
-#define IIO_IECLR	0x4001f8	/* IO error clear */
-#define IIO_IBCN        0x400200        /* IO BTE CRB count */
-
-/*
- * IIO_IMEM Register fields.
- */
-#define IIO_IMEM_W0ESD  0x1             /* Widget 0 shut down due to error */
-#define IIO_IMEM_B0ESD  (1 << 4)        /* BTE 0 shut down due to error */
-#define IIO_IMEM_B1ESD  (1 << 8)        /* BTE 1 Shut down due to error */
-
-/* PIO Read address Table Entries */
-#define IIO_IPCA	0x400300	/* PRB Counter adjust */
-#define IIO_NUM_PRTES	8		/* Total number of PRB table entries */
-#define IIO_PRTE_0	0x400308	/* PIO Read address table entry 0 */
-#define IIO_PRTE(_x)	(IIO_PRTE_0 + (8 * (_x)))
-#define	IIO_WIDPRTE(x)	IIO_PRTE(((x) - 8)) /* widget ID to its PRTE num */
-#define IIO_IPDR	0x400388	/* PIO table entry deallocation */
-#define IIO_ICDR	0x400390	/* CRB Entry Deallocation */
-#define IIO_IFDR	0x400398	/* IOQ FIFO Depth */
-#define IIO_IIAP	0x4003a0	/* IIQ Arbitration Parameters */
-#define IIO_IMMR	IIO_IIAP
-#define IIO_ICMR	0x4003a8	/* CRB Management Register */
-#define IIO_ICCR	0x4003b0	/* CRB Control Register */
-#define IIO_ICTO	0x4003b8	/* CRB Time Out Register */
-#define IIO_ICTP	0x4003c0	/* CRB Time Out Prescalar */
-
-
-/*
- * ICMR register fields
- */
-#define IIO_ICMR_PC_VLD_SHFT	36
-#define IIO_ICMR_PC_VLD_MASK	(0x7fffUL << IIO_ICMR_PC_VLD_SHFT)
-
-#define IIO_ICMR_CRB_VLD_SHFT	20
-#define IIO_ICMR_CRB_VLD_MASK	(0x7fffUL << IIO_ICMR_CRB_VLD_SHFT)
-
-#define IIO_ICMR_FC_CNT_SHFT	16
-#define IIO_ICMR_FC_CNT_MASK	(0xf << IIO_ICMR_FC_CNT_SHFT)
-
-#define IIO_ICMR_C_CNT_SHFT	4
-#define IIO_ICMR_C_CNT_MASK	(0xf << IIO_ICMR_C_CNT_SHFT)
-
-#define IIO_ICMR_P_CNT_SHFT	0
-#define IIO_ICMR_P_CNT_MASK	(0xf << IIO_ICMR_P_CNT_SHFT)
-
-#define IIO_ICMR_PRECISE	(1UL << 52)
-#define IIO_ICMR_CLR_RPPD	(1UL << 13)
-#define IIO_ICMR_CLR_RQPD	(1UL << 12)
-
-/*
- * IIO PIO Deallocation register field masks : (IIO_IPDR)
- */
-#define	IIO_IPDR_PND	(1 << 4)
-
-/*
- * IIO CRB deallocation register field masks: (IIO_ICDR)
- */
-#define	IIO_ICDR_PND	(1 << 4)
-
-/*
- * IIO CRB control register Fields: IIO_ICCR
- */
-#define	IIO_ICCR_PENDING	(0x10000)
-#define	IIO_ICCR_CMD_MASK	(0xFF)
-#define	IIO_ICCR_CMD_SHFT	(7)
-#define	IIO_ICCR_CMD_NOP	(0x0)	/* No Op */
-#define	IIO_ICCR_CMD_WAKE	(0x100) /* Reactivate CRB entry and process */
-#define	IIO_ICCR_CMD_TIMEOUT	(0x200)	/* Make CRB timeout & mark invalid */
-#define	IIO_ICCR_CMD_EJECT	(0x400)	/* Contents of entry written to memory
-					 * via a WB
-					 */
-#define	IIO_ICCR_CMD_FLUSH	(0x800)
-
-/*
- * CRB manipulation macros
- *	The CRB macros are slightly complicated, since there are up to
- * 	four registers associated with each CRB entry.
- */
-#define IIO_NUM_CRBS		15	/* Number of CRBs */
-#define IIO_NUM_NORMAL_CRBS     12	/* Number of regular CRB entries */
-#define IIO_NUM_PC_CRBS 	4	/* Number of partial cache CRBs */
-#define IIO_ICRB_OFFSET		8
-#define IIO_ICRB_0		0x400400
-/* XXX - This is now tuneable:
-	#define IIO_FIRST_PC_ENTRY 12
- */
-
-#define IIO_ICRB_A(_x)	(IIO_ICRB_0 + (4 * IIO_ICRB_OFFSET * (_x)))
-#define IIO_ICRB_B(_x)  (IIO_ICRB_A(_x) + 1*IIO_ICRB_OFFSET)
-#define IIO_ICRB_C(_x)	(IIO_ICRB_A(_x) + 2*IIO_ICRB_OFFSET)
-#define IIO_ICRB_D(_x)  (IIO_ICRB_A(_x) + 3*IIO_ICRB_OFFSET)
-
-/* XXX - IBUE register coming for Hub 2 */
-
-/*
- *
- * CRB Register description.
- *
- * WARNING * WARNING * WARNING * WARNING * WARNING * WARNING * WARNING
- * WARNING * WARNING * WARNING * WARNING * WARNING * WARNING * WARNING
- * WARNING * WARNING * WARNING * WARNING * WARNING * WARNING * WARNING
- * WARNING * WARNING * WARNING * WARNING * WARNING * WARNING * WARNING
- * WARNING * WARNING * WARNING * WARNING * WARNING * WARNING * WARNING
- *
- * Many of the fields in CRB are status bits used by hardware
- * for implementation of the protocol. It's very dangerous to
- * mess around with the CRB registers.
- *
- * It's OK to read the CRB registers and try to make sense out of the
- * fields in CRB.
- *
- * Updating CRB requires all activities in Hub IIO to be quiesced.
- * otherwise, a write to CRB could corrupt other CRB entries.
- * CRBs are here only as a back door peek to hub IIO's status.
- * Quiescing implies  no dmas no PIOs
- * either directly from the cpu or from sn0net.
- * this is not something that can be done easily. So, AVOID updating
- * CRBs.
- */
-
-/*
- * Fields in CRB Register A
- */
-#ifndef __ASSEMBLY__
-typedef union icrba_u {
-	u64	reg_value;
-	struct {
-		u64 	resvd: 	6,
-			stall_bte0: 1,	/* Stall BTE 0 */
-			stall_bte1: 1,	/* Stall BTE 1 */
-			error:	1,	/* CRB has an error	*/
-			ecode:	3,	/* Error Code 		*/
-			lnetuce: 1,	/* SN0net Uncorrectable error */
-			mark:	1,	/* CRB Has been marked 	*/
-			xerr:	1,	/* Error bit set in xtalk header */
-			sidn:	4,	/* SIDN field from xtalk	*/
-			tnum: 	5,	/* TNUM field in xtalk		*/
-			addr:	38,	/* Address of request	*/
-			valid:	1,	/* Valid status		*/
-			iow:	1;	/* IO Write operation	*/
-	} icrba_fields_s;
-} icrba_t;
-
-/* This is an alternate typedef for the HUB1 CRB A in order to allow
-   runtime selection of the format based on the REV_ID field of the
-   NI_STATUS_REV_ID register. */
-typedef union h1_icrba_u {
-	u64	reg_value;
-
-	struct {
-		u64 	resvd: 	6,
-			unused:	1,	/* Unused but RW!!	*/
-			error:	1,	/* CRB has an error	*/
-			ecode:	4,	/* Error Code 		*/
-			lnetuce: 1,	/* SN0net Uncorrectable error */
-			mark:	1,	/* CRB Has been marked 	*/
-			xerr:	1,	/* Error bit set in xtalk header */
-			sidn:	4,	/* SIDN field from xtalk	*/
-			tnum: 	5,	/* TNUM field in xtalk		*/
-			addr:	38,	/* Address of request	*/
-			valid:	1,	/* Valid status		*/
-			iow:	1;	/* IO Write operation	*/
-	} h1_icrba_fields_s;
-} h1_icrba_t;
-
-/* XXX - Is this still right?  Check the spec. */
-#define ICRBN_A_CERR_SHFT	54
-#define ICRBN_A_ERR_MASK	0x3ff
-
-#endif /* !__ASSEMBLY__ */
-
-#define	IIO_ICRB_ADDR_SHFT	2	/* Shift to get proper address */
-
-/*
- * values for "ecode" field
- */
-#define	IIO_ICRB_ECODE_DERR	0	/* Directory error due to IIO access */
-#define	IIO_ICRB_ECODE_PERR	1	/* Poison error on IO access */
-#define	IIO_ICRB_ECODE_WERR	2	/* Write error by IIO access
-					 * e.g. WINV to a Read only line.
-					 */
-#define	IIO_ICRB_ECODE_AERR	3	/* Access error caused by IIO access */
-#define	IIO_ICRB_ECODE_PWERR	4	/* Error on partial write	*/
-#define	IIO_ICRB_ECODE_PRERR	5	/* Error on partial read	*/
-#define	IIO_ICRB_ECODE_TOUT	6	/* CRB timeout before deallocating */
-#define	IIO_ICRB_ECODE_XTERR	7	/* Incoming xtalk pkt had error bit */
-
-
-
-/*
- * Fields in CRB Register B
- */
-#ifndef __ASSEMBLY__
-typedef union icrbb_u {
-	u64	reg_value;
-	struct {
-	    u64	rsvd1:	5,
-		btenum:	1,	/* BTE to which entry belongs to */
-		cohtrans: 1,	/* Coherent transaction	*/
-		xtsize:	2,	/* Xtalk operation size
-				 * 0: Double Word
-				 * 1: 32 Bytes.
-				 * 2: 128 Bytes,
-				 * 3: Reserved.
-				 */
-		srcnode: 9,	/* Source Node ID		*/
-		srcinit: 2,	/* Source Initiator:
-				 * See below for field values.
-				 */
-		useold:	1,	/* Use OLD command for processing */
-		imsgtype: 2,	/* Incoming message type
-				 * see below for field values
-				 */
-		imsg: 	8,	/* Incoming message 	*/
-		initator: 3,	/* Initiator of original request
-				 * See below for field values.
-				 */
-		reqtype: 5,	/* Identifies type of request
-				 * See below for field values.
-				 */
-		rsvd2:	7,
-		ackcnt:	11,	/* Invalidate ack count	*/
-		resp:	1,	/* data response  given to processor */
-		ack: 	1,	/* indicates data ack received 	*/
-		hold:	1,	/* entry is gathering inval acks */
-		wb_pend:1,	/* waiting for writeback to complete */
-		intvn: 	1,	/* Intervention */
-		stall_ib: 1,	/* Stall Ibuf (from crosstalk) */
-		stall_intr: 1;	/* Stall internal interrupts */
-	} icrbb_field_s;
-} icrbb_t;
-
-/* This is an alternate typedef for the HUB1 CRB B in order to allow
-   runtime selection of the format based on the REV_ID field of the
-   NI_STATUS_REV_ID register. */
-typedef union h1_icrbb_u {
-	u64	reg_value;
-	struct {
-		u64	rsvd1:	5,
-			btenum:	1,	/* BTE to which entry belongs to */
-			cohtrans: 1,	/* Coherent transaction	*/
-			xtsize:	2,	/* Xtalk operation size
-					 * 0: Double Word
-					 * 1: 32 Bytes.
-					 * 2: 128 Bytes,
-					 * 3: Reserved.
-					 */
-			srcnode: 9,	/* Source Node ID		*/
-			srcinit: 2,	/* Source Initiator:
-					 * See below for field values.
-					 */
-			useold:	1,	/* Use OLD command for processing */
-			imsgtype: 2,	/* Incoming message type
-					 * see below for field values
-					 */
-			imsg: 	8,	/* Incoming message 	*/
-			initator: 3,	/* Initiator of original request
-					 * See below for field values.
-					 */
-			rsvd2: 	1,
-			pcache: 1,	/* entry belongs to partial cache */
-			reqtype: 5,	/* Identifies type of request
-					 * See below for field values.
-					 */
-			stl_ib:	1,	/* stall Ibus coming from xtalk	*/
-			stl_intr: 1,	/* Stall internal interrupts */
-			stl_bte0: 1,	/* Stall BTE 0 	*/
-			stl_bte1: 1,	/* Stall BTE 1	*/
-			intrvn:	1,	/* Req was target of intervention */
-			ackcnt:	11,	/* Invalidate ack count	*/
-			resp:	1,	/* data response  given to processor */
-			ack: 	1,	/* indicates data ack received 	*/
-			hold:	1,	/* entry is gathering inval acks */
-			wb_pend:1,	/* waiting for writeback to complete */
-			sleep: 	1,	/* xtalk req sleeping till IO-sync */
-			pnd_reply: 1,	/* replies not issed due to IOQ full */
-			pnd_req: 1;	/* reqs not issued due to IOQ full */
-	} h1_icrbb_field_s;
-} h1_icrbb_t;
-
-
-#define	b_imsgtype	icrbb_field_s.imsgtype
-#define	b_btenum	icrbb_field_s.btenum
-#define	b_cohtrans	icrbb_field_s.cohtrans
-#define	b_xtsize	icrbb_field_s.xtsize
-#define	b_srcnode	icrbb_field_s.srcnode
-#define	b_srcinit	icrbb_field_s.srcinit
-#define	b_imsgtype	icrbb_field_s.imsgtype
-#define	b_imsg		icrbb_field_s.imsg
-#define	b_initiator	icrbb_field_s.initiator
-
-#endif /* !__ASSEMBLY__ */
-
-/*
- * values for field xtsize
- */
-#define	IIO_ICRB_XTSIZE_DW	0	/* Xtalk operation size is 8 bytes  */
-#define	IIO_ICRB_XTSIZE_32	1	/* Xtalk operation size is 32 bytes */
-#define	IIO_ICRB_XTSIZE_128	2	/* Xtalk operation size is 128 bytes */
-
-/*
- * values for field srcinit
- */
-#define	IIO_ICRB_PROC0		0	/* Source of request is Proc 0 */
-#define	IIO_ICRB_PROC1		1	/* Source of request is Proc 1 */
-#define	IIO_ICRB_GB_REQ		2	/* Source is Guranteed BW request */
-#define	IIO_ICRB_IO_REQ		3	/* Source is Normal IO request	*/
-
-/*
- * Values for field imsgtype
- */
-#define	IIO_ICRB_IMSGT_XTALK	0	/* Incoming Meessage from Xtalk	*/
-#define	IIO_ICRB_IMSGT_BTE	1	/* Incoming message from BTE 	*/
-#define	IIO_ICRB_IMSGT_SN0NET	2	/* Incoming message from SN0 net */
-#define	IIO_ICRB_IMSGT_CRB	3	/* Incoming message from CRB ???  */
-
-/*
- * values for field initiator.
- */
-#define	IIO_ICRB_INIT_XTALK	0	/* Message originated in xtalk	*/
-#define	IIO_ICRB_INIT_BTE0	0x1	/* Message originated in BTE 0	*/
-#define	IIO_ICRB_INIT_SN0NET	0x2	/* Message originated in SN0net */
-#define	IIO_ICRB_INIT_CRB	0x3	/* Message originated in CRB ? 	*/
-#define	IIO_ICRB_INIT_BTE1	0x5	/* MEssage originated in BTE 1	*/
-
-/*
- * Values for field reqtype.
- */
-/* XXX - Need to fix this for Hub 2 */
-#define	IIO_ICRB_REQ_DWRD	0	/* Request type double word	*/
-#define	IIO_ICRB_REQ_QCLRD	1	/* Request is Qrtr Caceh line Rd */
-#define	IIO_ICRB_REQ_BLKRD	2	/* Request is block read	*/
-#define	IIO_ICRB_REQ_RSHU	6	/* Request is BTE block read	*/
-#define	IIO_ICRB_REQ_REXU	7	/* request is BTE Excl Read	*/
-#define	IIO_ICRB_REQ_RDEX	8	/* Request is Read Exclusive	*/
-#define	IIO_ICRB_REQ_WINC	9	/* Request is Write Invalidate 	*/
-#define	IIO_ICRB_REQ_BWINV	10	/* Request is BTE Winv		*/
-#define	IIO_ICRB_REQ_PIORD	11	/* Request is PIO read		*/
-#define	IIO_ICRB_REQ_PIOWR	12	/* Request is PIO Write 	*/
-#define	IIO_ICRB_REQ_PRDM	13	/* Request is Fetch&Op		*/
-#define	IIO_ICRB_REQ_PWRM	14	/* Request is Store &Op		*/
-#define	IIO_ICRB_REQ_PTPWR	15	/* Request is Peer to peer	*/
-#define	IIO_ICRB_REQ_WB		16	/* Request is Write back	*/
-#define	IIO_ICRB_REQ_DEX	17	/* Retained DEX Cache line	*/
-
-/*
- * Fields in CRB Register C
- */
-
-#ifndef __ASSEMBLY__
-
-typedef union icrbc_s {
-	u64	reg_value;
-	struct {
-		u64	rsvd:	6,
-			sleep:	1,
-			pricnt: 4,	/* Priority count sent with Read req */
-			pripsc: 4,	/* Priority Pre scalar 	*/
-			bteop:	1,	/* BTE Operation 	*/
-			push_be: 34,	/* Push address Byte enable
-					 * Holds push addr, if CRB is for BTE
-					 * If CRB belongs to Partial cache,
-					 * this contains byte enables bits
-					 * ([47:46] = 0)
-					 */
-			suppl:	11,	/* Supplemental field	*/
-			barrop: 1,	/* Barrier Op bit set in xtalk req */
-			doresp: 1,	/* Xtalk req needs a response 	*/
-			gbr:	1;	/* GBR bit set in xtalk packet 	*/
-	} icrbc_field_s;
-} icrbc_t;
-
-#define	c_pricnt	icrbc_field_s.pricnt
-#define	c_pripsc	icrbc_field_s.pripsc
-#define	c_bteop		icrbc_field_s.bteop
-#define	c_bteaddr	icrbc_field_s.push_be	/* push_be field has 2 names */
-#define c_benable 	icrbc_field_s.push_be	/* push_be field has 2 names */
-#define	c_suppl		icrbc_field_s.suppl
-#define	c_barrop	icrbc_field_s.barrop
-#define	c_doresp	icrbc_field_s.doresp
-#define	c_gbr	icrbc_field_s.gbr
-#endif /* !__ASSEMBLY__ */
-
-/*
- * Fields in CRB Register D
- */
-
-#ifndef __ASSEMBLY__
-typedef union icrbd_s {
-	u64	reg_value;
-	struct {
-	    u64	rsvd:	38,
-		toutvld: 1,	/* Timeout in progress for this CRB */
-		ctxtvld: 1,	/* Context field below is valid	*/
-		rsvd2:	1,
-		context: 15, 	/* Bit vector:
-				 * Has a bit set for each CRB entry
-				 * which needs to be deallocated
-				 * before this CRB entry is processed.
-				 * Set only for barrier operations.
-				 */
-		timeout: 8;	/* Timeout Upper 8 bits	*/
-	} icrbd_field_s;
-} icrbd_t;
-
-#define	icrbd_toutvld	icrbd_field_s.toutvld
-#define	icrbd_ctxtvld	icrbd_field_s.ctxtvld
-#define	icrbd_context	icrbd_field_s.context
-
-
-typedef union hubii_ifdr_u {
-	u64	hi_ifdr_value;
-	struct {
-		u64	ifdr_rsvd:	49,
-	                ifdr_maxrp:	 7,
-	                ifdr_rsvd1:	 1,
-                      	ifdr_maxrq:	 7;
-	} hi_ifdr_fields;
-} hubii_ifdr_t;
-
-#endif /* !__ASSEMBLY__ */
-
-/*
- * Hardware designed names for the BTE control registers.
- */
-#define IIO_IBLS_0	0x410000	/* BTE length/status 0 */
-#define IIO_IBSA_0	0x410008	/* BTE source address 0 */
-#define IIO_IBDA_0	0x410010	/* BTE destination address 0 */
-#define IIO_IBCT_0	0x410018	/* BTE control/terminate 0 */
-#define IIO_IBNA_0	0x410020	/* BTE notification address 0 */
-#define IIO_IBNR_0	IIO_IBNA_0
-#define IIO_IBIA_0	0x410028	/* BTE interrupt address 0 */
-
-#define IIO_IBLS_1	0x420000	/* BTE length/status 1 */
-#define IIO_IBSA_1	0x420008	/* BTE source address 1 */
-#define IIO_IBDA_1	0x420010	/* BTE destination address 1 */
-#define IIO_IBCT_1	0x420018	/* BTE control/terminate 1 */
-#define IIO_IBNA_1	0x420020	/* BTE notification address 1 */
-#define IIO_IBNR_1	IIO_IBNA_1
-#define IIO_IBIA_1	0x420028	/* BTE interrupt address 1 */
-
-/*
- * More miscellaneous registers
- */
-#define IIO_IPCR	0x430000	/* Performance Control */
-#define IIO_IPPR	0x430008	/* Performance Profiling */
-
-/*
- * IO Error Clear register bit field definitions
- */
-#define IECLR_BTE1		(1 << 18)  /* clear bte error 1 ??? */
-#define IECLR_BTE0		(1 << 17)  /* clear bte error 0 ??? */
-#define IECLR_CRAZY		(1 << 16)  /* clear crazy bit in wstat reg */
-#define IECLR_PRB_F		(1 << 15)  /* clear err bit in PRB_F reg */
-#define IECLR_PRB_E		(1 << 14)  /* clear err bit in PRB_E reg */
-#define IECLR_PRB_D		(1 << 13)  /* clear err bit in PRB_D reg */
-#define IECLR_PRB_C		(1 << 12)  /* clear err bit in PRB_C reg */
-#define IECLR_PRB_B		(1 << 11)  /* clear err bit in PRB_B reg */
-#define IECLR_PRB_A		(1 << 10)  /* clear err bit in PRB_A reg */
-#define IECLR_PRB_9		(1 << 9)   /* clear err bit in PRB_9 reg */
-#define IECLR_PRB_8		(1 << 8)   /* clear err bit in PRB_8 reg */
-#define IECLR_PRB_0		(1 << 0)   /* clear err bit in PRB_0 reg */
-
-/*
- * IO PIO Read Table Entry format
- */
-
-#ifndef __ASSEMBLY__
-
-typedef union iprte_a {
-	u64	entry;
-	struct {
-	    u64	rsvd1     : 7,  /* Reserved field 		*/
-		valid     : 1,	/* Maps to a timeout entry	*/
-		rsvd2     : 1,
-		srcnode   : 9,	/* Node which did this PIO	*/
-		initiator : 2,	/* If T5A or T5B or IO 		*/
-		rsvd3     : 3,
-		addr      : 38,	/* Physical address of PIO	*/
-		rsvd4     : 3;
-	} iprte_fields;
-} iprte_a_t;
-
-#define	iprte_valid	iprte_fields.valid
-#define	iprte_timeout	iprte_fields.timeout
-#define	iprte_srcnode	iprte_fields.srcnode
-#define	iprte_init	iprte_fields.initiator
-#define	iprte_addr	iprte_fields.addr
-
-#endif /* !__ASSEMBLY__ */
-
-#define	IPRTE_ADDRSHFT	3
-
-/*
- * Hub IIO PRB Register format.
- */
-
-#ifndef __ASSEMBLY__
-/*
- * Note: Fields bnakctr, anakctr, xtalkctrmode, ovflow fields are
- * "Status" fields, and should only be used in case of clean up after errors.
- */
-
-typedef union iprb_u {
-	u64	reg_value;
-	struct {
-	    u64	rsvd1:	15,
-		error:	1,	/* Widget rcvd wr resp pkt w/ error */
-		ovflow:	5,	/* Over flow count. perf measurement */
-		fire_and_forget: 1, /* Launch Write without response */
-		mode:	2,	/* Widget operation Mode	*/
-		rsvd2:	2,
-		bnakctr: 14,
-		rsvd3: 	2,
-		anakctr: 14,
-		xtalkctr: 8;
-	} iprb_fields_s;
-} iprb_t;
-
-#define iprb_regval	reg_value
-
-#define	iprb_error	iprb_fields_s.error
-#define	iprb_ovflow	iprb_fields_s.ovflow
-#define	iprb_ff		iprb_fields_s.fire_and_forget
-#define	iprb_mode	iprb_fields_s.mode
-#define	iprb_bnakctr	iprb_fields_s.bnakctr
-#define	iprb_anakctr	iprb_fields_s.anakctr
-#define	iprb_xtalkctr	iprb_fields_s.xtalkctr
-
-#endif /* !__ASSEMBLY__ */
-
-/*
- * values for mode field in iprb_t.
- * For details of the meanings of NAK and Accept, refer the PIO flow
- * document
- */
-#define	IPRB_MODE_NORMAL	(0)
-#define	IPRB_MODE_COLLECT_A	(1)	/* PRB in collect A mode */
-#define	IPRB_MODE_SERVICE_A	(2)	/* NAK B and Accept A */
-#define	IPRB_MODE_SERVICE_B	(3)	/* NAK A and Accept B */
-
-/*
- * IO CRB entry C_A to E_A : Partial (cache) CRBS
- */
-#ifndef __ASSEMBLY__
-typedef union icrbp_a {
-	u64   ip_reg;	    /* the entire register value	*/
-	struct {
-	     u64 error:	1,  /*    63, error occurred		*/
-		ln_uce:	1,  /*    62: uncorrectable memory 	*/
-		ln_ae:	1,  /*    61: protection violation 	*/
-		ln_werr:1,  /*    60: write access error 	*/
-		ln_aerr:1,  /*    59: sn0net: Address error	*/
-		ln_perr:1,  /*    58: sn0net: poison error	*/
-		timeout:1,  /*    57: CRB timed out		*/
-		l_bdpkt:1,  /*    56: truncated pkt on sn0net	*/
-		c_bdpkt:1,  /*    55: truncated pkt on xtalk	*/
-		c_err:	1,  /*    54: incoming xtalk req, err set*/
-		rsvd1: 12,  /* 53-42: reserved			*/
-		valid:	1,  /*    41: Valid status		*/
-		sidn:	4,  /* 40-37: SIDN field of xtalk rqst	*/
-		tnum:	5,  /* 36-32: TNUM of xtalk request	*/
-		bo:	1,  /*    31: barrier op set in xtalk rqst*/
-		resprqd:1,  /*    30: xtalk rqst requires response*/
-		gbr:	1,  /*    29: gbr bit set in xtalk rqst	*/
-		size:	2,  /* 28-27: size of xtalk request	*/
-		excl:	4,  /* 26-23: exclusive bit(s)		*/
-		stall:	3,  /* 22-20: stall (xtalk, bte 0/1)	*/
-		intvn:	1,  /*    19: rqst target of intervention*/
-		resp:	1,  /*    18: Data response given to t5	*/
-		ack:	1,  /*    17: Data ack received.	*/
-		hold:	1,  /*    16: crb gathering invalidate acks*/
-		wb:	1,  /*    15: writeback pending.	*/
-		ack_cnt:11, /* 14-04: counter of invalidate acks*/
-		tscaler:4;  /* 03-00: Timeout prescaler		*/
-	} ip_fmt;
-} icrbp_a_t;
-
-#endif /* !__ASSEMBLY__ */
-
-/*
- * A couple of defines to go with the above structure.
- */
-#define ICRBP_A_CERR_SHFT	54
-#define ICRBP_A_ERR_MASK	0x3ff
-
-#ifndef __ASSEMBLY__
-typedef union hubii_idsr {
-	u64 iin_reg;
-	struct {
-		u64 rsvd1 : 35,
-	            isent : 1,
-	            rsvd2 : 3,
-	            ienable: 1,
-	            rsvd  : 7,
-	            node  : 9,
-	            rsvd4 : 1,
-	            level : 7;
-	} iin_fmt;
-} hubii_idsr_t;
-#endif /* !__ASSEMBLY__ */
-
-/*
- * IO BTE Length/Status (IIO_IBLS) register bit field definitions
- */
-#define IBLS_BUSY		(0x1 << 20)
-#define IBLS_ERROR_SHFT		16
-#define IBLS_ERROR		(0x1 << IBLS_ERROR_SHFT)
-#define IBLS_LENGTH_MASK	0xffff
-
-/*
- * IO BTE Control/Terminate register (IBCT) register bit field definitions
- */
-#define IBCT_POISON		(0x1 << 8)
-#define IBCT_NOTIFY		(0x1 << 4)
-#define IBCT_ZFIL_MODE		(0x1 << 0)
-
-/*
- * IO BTE Interrupt Address Register (IBIA) register bit field definitions
- */
-#define IBIA_LEVEL_SHFT		16
-#define IBIA_LEVEL_MASK		(0x7f << IBIA_LEVEL_SHFT)
-#define IBIA_NODE_ID_SHFT	0
-#define IBIA_NODE_ID_MASK	(0x1ff)
-
-/*
- * Miscellaneous hub constants
- */
-
-/* Number of widgets supported by hub */
-#define HUB_NUM_WIDGET		9
-#define HUB_WIDGET_ID_MIN	0x8
-#define HUB_WIDGET_ID_MAX	0xf
-
-#define HUB_WIDGET_PART_NUM	0xc101
-#define MAX_HUBS_PER_XBOW	2
-
-/*
- * Get a hub's widget id from widget control register
- */
-#define IIO_WCR_WID_GET(nasid)	(REMOTE_HUB_L(nasid, III_WCR) & 0xf)
-#define IIO_WST_ERROR_MASK	(UINT64_CAST 1 << 32) /* Widget status error */
-
-/*
- * Number of credits Hub widget has while sending req/response to
- * xbow.
- * Value of 3 is required by Xbow 1.1
- * We may be able to increase this to 4 with Xbow 1.2.
- */
-#define       HUBII_XBOW_CREDIT       3
-#define	      HUBII_XBOW_REV2_CREDIT  4
-
-#endif /* _ASM_SGI_SN_SN0_HUBIO_H */
diff --git a/include/asm-mips/spinlock.h b/include/asm-mips/spinlock.h
deleted file mode 100644
index bb89701..0000000
--- a/include/asm-mips/spinlock.h
+++ /dev/null
@@ -1,376 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 1999, 2000, 06 Ralf Baechle (ralf@linux-mips.org)
- * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
- */
-#ifndef _ASM_SPINLOCK_H
-#define _ASM_SPINLOCK_H
-
-#include <asm/barrier.h>
-#include <asm/war.h>
-
-/*
- * Your basic SMP spinlocks, allowing only a single CPU anywhere
- */
-
-#define __raw_spin_is_locked(x)       ((x)->lock != 0)
-#define __raw_spin_lock_flags(lock, flags) __raw_spin_lock(lock)
-#define __raw_spin_unlock_wait(x) \
-	do { cpu_relax(); } while ((x)->lock)
-
-/*
- * Simple spin lock operations.  There are two variants, one clears IRQ's
- * on the local processor, one does not.
- *
- * We make no fairness assumptions.  They have a cost.
- */
-
-static inline void __raw_spin_lock(raw_spinlock_t *lock)
-{
-	unsigned int tmp;
-
-	if (R10000_LLSC_WAR) {
-		__asm__ __volatile__(
-		"	.set	noreorder	# __raw_spin_lock	\n"
-		"1:	ll	%1, %2					\n"
-		"	bnez	%1, 1b					\n"
-		"	 li	%1, 1					\n"
-		"	sc	%1, %0					\n"
-		"	beqzl	%1, 1b					\n"
-		"	 nop						\n"
-		"	.set	reorder					\n"
-		: "=m" (lock->lock), "=&r" (tmp)
-		: "m" (lock->lock)
-		: "memory");
-	} else {
-		__asm__ __volatile__(
-		"	.set	noreorder	# __raw_spin_lock	\n"
-		"1:	ll	%1, %2					\n"
-		"	bnez	%1, 2f					\n"
-		"	 li	%1, 1					\n"
-		"	sc	%1, %0					\n"
-		"	beqz	%1, 2f					\n"
-		"	 nop						\n"
-		"	.subsection 2					\n"
-		"2:	ll	%1, %2					\n"
-		"	bnez	%1, 2b					\n"
-		"	 li	%1, 1					\n"
-		"	b	1b					\n"
-		"	 nop						\n"
-		"	.previous					\n"
-		"	.set	reorder					\n"
-		: "=m" (lock->lock), "=&r" (tmp)
-		: "m" (lock->lock)
-		: "memory");
-	}
-
-	smp_llsc_mb();
-}
-
-static inline void __raw_spin_unlock(raw_spinlock_t *lock)
-{
-	smp_mb();
-
-	__asm__ __volatile__(
-	"	.set	noreorder	# __raw_spin_unlock	\n"
-	"	sw	$0, %0					\n"
-	"	.set\treorder					\n"
-	: "=m" (lock->lock)
-	: "m" (lock->lock)
-	: "memory");
-}
-
-static inline unsigned int __raw_spin_trylock(raw_spinlock_t *lock)
-{
-	unsigned int temp, res;
-
-	if (R10000_LLSC_WAR) {
-		__asm__ __volatile__(
-		"	.set	noreorder	# __raw_spin_trylock	\n"
-		"1:	ll	%0, %3					\n"
-		"	ori	%2, %0, 1				\n"
-		"	sc	%2, %1					\n"
-		"	beqzl	%2, 1b					\n"
-		"	 nop						\n"
-		"	andi	%2, %0, 1				\n"
-		"	.set	reorder"
-		: "=&r" (temp), "=m" (lock->lock), "=&r" (res)
-		: "m" (lock->lock)
-		: "memory");
-	} else {
-		__asm__ __volatile__(
-		"	.set	noreorder	# __raw_spin_trylock	\n"
-		"1:	ll	%0, %3					\n"
-		"	ori	%2, %0, 1				\n"
-		"	sc	%2, %1					\n"
-		"	beqz	%2, 2f					\n"
-		"	 andi	%2, %0, 1				\n"
-		"	.subsection 2					\n"
-		"2:	b	1b					\n"
-		"	 nop						\n"
-		"	.previous					\n"
-		"	.set	reorder"
-		: "=&r" (temp), "=m" (lock->lock), "=&r" (res)
-		: "m" (lock->lock)
-		: "memory");
-	}
-
-	smp_llsc_mb();
-
-	return res == 0;
-}
-
-/*
- * Read-write spinlocks, allowing multiple readers but only one writer.
- *
- * NOTE! it is quite common to have readers in interrupts but no interrupt
- * writers. For those circumstances we can "mix" irq-safe locks - any writer
- * needs to get a irq-safe write-lock, but readers can get non-irqsafe
- * read-locks.
- */
-
-/*
- * read_can_lock - would read_trylock() succeed?
- * @lock: the rwlock in question.
- */
-#define __raw_read_can_lock(rw)	((rw)->lock >= 0)
-
-/*
- * write_can_lock - would write_trylock() succeed?
- * @lock: the rwlock in question.
- */
-#define __raw_write_can_lock(rw)	(!(rw)->lock)
-
-static inline void __raw_read_lock(raw_rwlock_t *rw)
-{
-	unsigned int tmp;
-
-	if (R10000_LLSC_WAR) {
-		__asm__ __volatile__(
-		"	.set	noreorder	# __raw_read_lock	\n"
-		"1:	ll	%1, %2					\n"
-		"	bltz	%1, 1b					\n"
-		"	 addu	%1, 1					\n"
-		"	sc	%1, %0					\n"
-		"	beqzl	%1, 1b					\n"
-		"	 nop						\n"
-		"	.set	reorder					\n"
-		: "=m" (rw->lock), "=&r" (tmp)
-		: "m" (rw->lock)
-		: "memory");
-	} else {
-		__asm__ __volatile__(
-		"	.set	noreorder	# __raw_read_lock	\n"
-		"1:	ll	%1, %2					\n"
-		"	bltz	%1, 2f					\n"
-		"	 addu	%1, 1					\n"
-		"	sc	%1, %0					\n"
-		"	beqz	%1, 1b					\n"
-		"	 nop						\n"
-		"	.subsection 2					\n"
-		"2:	ll	%1, %2					\n"
-		"	bltz	%1, 2b					\n"
-		"	 addu	%1, 1					\n"
-		"	b	1b					\n"
-		"	 nop						\n"
-		"	.previous					\n"
-		"	.set	reorder					\n"
-		: "=m" (rw->lock), "=&r" (tmp)
-		: "m" (rw->lock)
-		: "memory");
-	}
-
-	smp_llsc_mb();
-}
-
-/* Note the use of sub, not subu which will make the kernel die with an
-   overflow exception if we ever try to unlock an rwlock that is already
-   unlocked or is being held by a writer.  */
-static inline void __raw_read_unlock(raw_rwlock_t *rw)
-{
-	unsigned int tmp;
-
-	smp_llsc_mb();
-
-	if (R10000_LLSC_WAR) {
-		__asm__ __volatile__(
-		"1:	ll	%1, %2		# __raw_read_unlock	\n"
-		"	sub	%1, 1					\n"
-		"	sc	%1, %0					\n"
-		"	beqzl	%1, 1b					\n"
-		: "=m" (rw->lock), "=&r" (tmp)
-		: "m" (rw->lock)
-		: "memory");
-	} else {
-		__asm__ __volatile__(
-		"	.set	noreorder	# __raw_read_unlock	\n"
-		"1:	ll	%1, %2					\n"
-		"	sub	%1, 1					\n"
-		"	sc	%1, %0					\n"
-		"	beqz	%1, 2f					\n"
-		"	 nop						\n"
-		"	.subsection 2					\n"
-		"2:	b	1b					\n"
-		"	 nop						\n"
-		"	.previous					\n"
-		"	.set	reorder					\n"
-		: "=m" (rw->lock), "=&r" (tmp)
-		: "m" (rw->lock)
-		: "memory");
-	}
-}
-
-static inline void __raw_write_lock(raw_rwlock_t *rw)
-{
-	unsigned int tmp;
-
-	if (R10000_LLSC_WAR) {
-		__asm__ __volatile__(
-		"	.set	noreorder	# __raw_write_lock	\n"
-		"1:	ll	%1, %2					\n"
-		"	bnez	%1, 1b					\n"
-		"	 lui	%1, 0x8000				\n"
-		"	sc	%1, %0					\n"
-		"	beqzl	%1, 1b					\n"
-		"	 nop						\n"
-		"	.set	reorder					\n"
-		: "=m" (rw->lock), "=&r" (tmp)
-		: "m" (rw->lock)
-		: "memory");
-	} else {
-		__asm__ __volatile__(
-		"	.set	noreorder	# __raw_write_lock	\n"
-		"1:	ll	%1, %2					\n"
-		"	bnez	%1, 2f					\n"
-		"	 lui	%1, 0x8000				\n"
-		"	sc	%1, %0					\n"
-		"	beqz	%1, 2f					\n"
-		"	 nop						\n"
-		"	.subsection 2					\n"
-		"2:	ll	%1, %2					\n"
-		"	bnez	%1, 2b					\n"
-		"	 lui	%1, 0x8000				\n"
-		"	b	1b					\n"
-		"	 nop						\n"
-		"	.previous					\n"
-		"	.set	reorder					\n"
-		: "=m" (rw->lock), "=&r" (tmp)
-		: "m" (rw->lock)
-		: "memory");
-	}
-
-	smp_llsc_mb();
-}
-
-static inline void __raw_write_unlock(raw_rwlock_t *rw)
-{
-	smp_mb();
-
-	__asm__ __volatile__(
-	"				# __raw_write_unlock	\n"
-	"	sw	$0, %0					\n"
-	: "=m" (rw->lock)
-	: "m" (rw->lock)
-	: "memory");
-}
-
-static inline int __raw_read_trylock(raw_rwlock_t *rw)
-{
-	unsigned int tmp;
-	int ret;
-
-	if (R10000_LLSC_WAR) {
-		__asm__ __volatile__(
-		"	.set	noreorder	# __raw_read_trylock	\n"
-		"	li	%2, 0					\n"
-		"1:	ll	%1, %3					\n"
-		"	bltz	%1, 2f					\n"
-		"	 addu	%1, 1					\n"
-		"	sc	%1, %0					\n"
-		"	.set	reorder					\n"
-		"	beqzl	%1, 1b					\n"
-		"	 nop						\n"
-		__WEAK_LLSC_MB
-		"	li	%2, 1					\n"
-		"2:							\n"
-		: "=m" (rw->lock), "=&r" (tmp), "=&r" (ret)
-		: "m" (rw->lock)
-		: "memory");
-	} else {
-		__asm__ __volatile__(
-		"	.set	noreorder	# __raw_read_trylock	\n"
-		"	li	%2, 0					\n"
-		"1:	ll	%1, %3					\n"
-		"	bltz	%1, 2f					\n"
-		"	 addu	%1, 1					\n"
-		"	sc	%1, %0					\n"
-		"	beqz	%1, 1b					\n"
-		"	 nop						\n"
-		"	.set	reorder					\n"
-		__WEAK_LLSC_MB
-		"	li	%2, 1					\n"
-		"2:							\n"
-		: "=m" (rw->lock), "=&r" (tmp), "=&r" (ret)
-		: "m" (rw->lock)
-		: "memory");
-	}
-
-	return ret;
-}
-
-static inline int __raw_write_trylock(raw_rwlock_t *rw)
-{
-	unsigned int tmp;
-	int ret;
-
-	if (R10000_LLSC_WAR) {
-		__asm__ __volatile__(
-		"	.set	noreorder	# __raw_write_trylock	\n"
-		"	li	%2, 0					\n"
-		"1:	ll	%1, %3					\n"
-		"	bnez	%1, 2f					\n"
-		"	 lui	%1, 0x8000				\n"
-		"	sc	%1, %0					\n"
-		"	beqzl	%1, 1b					\n"
-		"	 nop						\n"
-		__WEAK_LLSC_MB
-		"	li	%2, 1					\n"
-		"	.set	reorder					\n"
-		"2:							\n"
-		: "=m" (rw->lock), "=&r" (tmp), "=&r" (ret)
-		: "m" (rw->lock)
-		: "memory");
-	} else {
-		__asm__ __volatile__(
-		"	.set	noreorder	# __raw_write_trylock	\n"
-		"	li	%2, 0					\n"
-		"1:	ll	%1, %3					\n"
-		"	bnez	%1, 2f					\n"
-		"	lui	%1, 0x8000				\n"
-		"	sc	%1, %0					\n"
-		"	beqz	%1, 3f					\n"
-		"	 li	%2, 1					\n"
-		"2:							\n"
-		__WEAK_LLSC_MB
-		"	.subsection 2					\n"
-		"3:	b	1b					\n"
-		"	 li	%2, 0					\n"
-		"	.previous					\n"
-		"	.set	reorder					\n"
-		: "=m" (rw->lock), "=&r" (tmp), "=&r" (ret)
-		: "m" (rw->lock)
-		: "memory");
-	}
-
-	return ret;
-}
-
-
-#define _raw_spin_relax(lock)	cpu_relax()
-#define _raw_read_relax(lock)	cpu_relax()
-#define _raw_write_relax(lock)	cpu_relax()
-
-#endif /* _ASM_SPINLOCK_H */
diff --git a/include/asm-mips/spinlock_types.h b/include/asm-mips/spinlock_types.h
deleted file mode 100644
index ce26c50..0000000
--- a/include/asm-mips/spinlock_types.h
+++ /dev/null
@@ -1,20 +0,0 @@
-#ifndef _ASM_SPINLOCK_TYPES_H
-#define _ASM_SPINLOCK_TYPES_H
-
-#ifndef __LINUX_SPINLOCK_TYPES_H
-# error "please don't include this file directly"
-#endif
-
-typedef struct {
-	volatile unsigned int lock;
-} raw_spinlock_t;
-
-#define __RAW_SPIN_LOCK_UNLOCKED	{ 0 }
-
-typedef struct {
-	volatile unsigned int lock;
-} raw_rwlock_t;
-
-#define __RAW_RW_LOCK_UNLOCKED		{ 0 }
-
-#endif
diff --git a/include/asm-mips/stackframe.h b/include/asm-mips/stackframe.h
deleted file mode 100644
index 051e1af..0000000
--- a/include/asm-mips/stackframe.h
+++ /dev/null
@@ -1,524 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 1994, 95, 96, 99, 2001 Ralf Baechle
- * Copyright (C) 1994, 1995, 1996 Paul M. Antoine.
- * Copyright (C) 1999 Silicon Graphics, Inc.
- * Copyright (C) 2007  Maciej W. Rozycki
- */
-#ifndef _ASM_STACKFRAME_H
-#define _ASM_STACKFRAME_H
-
-#include <linux/threads.h>
-
-#include <asm/asm.h>
-#include <asm/asmmacro.h>
-#include <asm/mipsregs.h>
-#include <asm/asm-offsets.h>
-
-/*
- * For SMTC kernel, global IE should be left set, and interrupts
- * controlled exclusively via IXMT.
- */
-#ifdef CONFIG_MIPS_MT_SMTC
-#define STATMASK 0x1e
-#elif defined(CONFIG_CPU_R3000) || defined(CONFIG_CPU_TX39XX)
-#define STATMASK 0x3f
-#else
-#define STATMASK 0x1f
-#endif
-
-#ifdef CONFIG_MIPS_MT_SMTC
-#include <asm/mipsmtregs.h>
-#endif /* CONFIG_MIPS_MT_SMTC */
-
-		.macro	SAVE_AT
-		.set	push
-		.set	noat
-		LONG_S	$1, PT_R1(sp)
-		.set	pop
-		.endm
-
-		.macro	SAVE_TEMP
-#ifdef CONFIG_CPU_HAS_SMARTMIPS
-		mflhxu	v1
-		LONG_S	v1, PT_LO(sp)
-		mflhxu	v1
-		LONG_S	v1, PT_HI(sp)
-		mflhxu	v1
-		LONG_S	v1, PT_ACX(sp)
-#else
-		mfhi	v1
-		LONG_S	v1, PT_HI(sp)
-		mflo	v1
-		LONG_S	v1, PT_LO(sp)
-#endif
-#ifdef CONFIG_32BIT
-		LONG_S	$8, PT_R8(sp)
-		LONG_S	$9, PT_R9(sp)
-#endif
-		LONG_S	$10, PT_R10(sp)
-		LONG_S	$11, PT_R11(sp)
-		LONG_S	$12, PT_R12(sp)
-		LONG_S	$13, PT_R13(sp)
-		LONG_S	$14, PT_R14(sp)
-		LONG_S	$15, PT_R15(sp)
-		LONG_S	$24, PT_R24(sp)
-		.endm
-
-		.macro	SAVE_STATIC
-		LONG_S	$16, PT_R16(sp)
-		LONG_S	$17, PT_R17(sp)
-		LONG_S	$18, PT_R18(sp)
-		LONG_S	$19, PT_R19(sp)
-		LONG_S	$20, PT_R20(sp)
-		LONG_S	$21, PT_R21(sp)
-		LONG_S	$22, PT_R22(sp)
-		LONG_S	$23, PT_R23(sp)
-		LONG_S	$30, PT_R30(sp)
-		.endm
-
-#ifdef CONFIG_SMP
-#ifdef CONFIG_MIPS_MT_SMTC
-#define PTEBASE_SHIFT	19	/* TCBIND */
-#else
-#define PTEBASE_SHIFT	23	/* CONTEXT */
-#endif
-		.macro	get_saved_sp	/* SMP variation */
-#ifdef CONFIG_MIPS_MT_SMTC
-		mfc0	k0, CP0_TCBIND
-#else
-		MFC0	k0, CP0_CONTEXT
-#endif
-#if defined(CONFIG_32BIT) || defined(KBUILD_64BIT_SYM32)
-		lui	k1, %hi(kernelsp)
-#else
-		lui	k1, %highest(kernelsp)
-		daddiu	k1, %higher(kernelsp)
-		dsll	k1, 16
-		daddiu	k1, %hi(kernelsp)
-		dsll	k1, 16
-#endif
-		LONG_SRL	k0, PTEBASE_SHIFT
-		LONG_ADDU	k1, k0
-		LONG_L	k1, %lo(kernelsp)(k1)
-		.endm
-
-		.macro	set_saved_sp stackp temp temp2
-#ifdef CONFIG_MIPS_MT_SMTC
-		mfc0	\temp, CP0_TCBIND
-#else
-		MFC0	\temp, CP0_CONTEXT
-#endif
-		LONG_SRL	\temp, PTEBASE_SHIFT
-		LONG_S	\stackp, kernelsp(\temp)
-		.endm
-#else
-		.macro	get_saved_sp	/* Uniprocessor variation */
-#if defined(CONFIG_32BIT) || defined(KBUILD_64BIT_SYM32)
-		lui	k1, %hi(kernelsp)
-#else
-		lui	k1, %highest(kernelsp)
-		daddiu	k1, %higher(kernelsp)
-		dsll	k1, k1, 16
-		daddiu	k1, %hi(kernelsp)
-		dsll	k1, k1, 16
-#endif
-		LONG_L	k1, %lo(kernelsp)(k1)
-		.endm
-
-		.macro	set_saved_sp stackp temp temp2
-		LONG_S	\stackp, kernelsp
-		.endm
-#endif
-
-		.macro	SAVE_SOME
-		.set	push
-		.set	noat
-		.set	reorder
-		mfc0	k0, CP0_STATUS
-		sll	k0, 3		/* extract cu0 bit */
-		.set	noreorder
-		bltz	k0, 8f
-		 move	k1, sp
-		.set	reorder
-		/* Called from user mode, new stack. */
-		get_saved_sp
-#ifndef CONFIG_CPU_DADDI_WORKAROUNDS
-8:		move	k0, sp
-		PTR_SUBU sp, k1, PT_SIZE
-#else
-		.set	at=k0
-8:		PTR_SUBU k1, PT_SIZE
-		.set	noat
-		move	k0, sp
-		move	sp, k1
-#endif
-		LONG_S	k0, PT_R29(sp)
-		LONG_S	$3, PT_R3(sp)
-		/*
-		 * You might think that you don't need to save $0,
-		 * but the FPU emulator and gdb remote debug stub
-		 * need it to operate correctly
-		 */
-		LONG_S	$0, PT_R0(sp)
-		mfc0	v1, CP0_STATUS
-		LONG_S	$2, PT_R2(sp)
-		LONG_S	v1, PT_STATUS(sp)
-#ifdef CONFIG_MIPS_MT_SMTC
-		/*
-		 * Ideally, these instructions would be shuffled in
-		 * to cover the pipeline delay.
-		 */
-		.set	mips32
-		mfc0	v1, CP0_TCSTATUS
-		.set	mips0
-		LONG_S	v1, PT_TCSTATUS(sp)
-#endif /* CONFIG_MIPS_MT_SMTC */
-		LONG_S	$4, PT_R4(sp)
-		mfc0	v1, CP0_CAUSE
-		LONG_S	$5, PT_R5(sp)
-		LONG_S	v1, PT_CAUSE(sp)
-		LONG_S	$6, PT_R6(sp)
-		MFC0	v1, CP0_EPC
-		LONG_S	$7, PT_R7(sp)
-#ifdef CONFIG_64BIT
-		LONG_S	$8, PT_R8(sp)
-		LONG_S	$9, PT_R9(sp)
-#endif
-		LONG_S	v1, PT_EPC(sp)
-		LONG_S	$25, PT_R25(sp)
-		LONG_S	$28, PT_R28(sp)
-		LONG_S	$31, PT_R31(sp)
-		ori	$28, sp, _THREAD_MASK
-		xori	$28, _THREAD_MASK
-		.set	pop
-		.endm
-
-		.macro	SAVE_ALL
-		SAVE_SOME
-		SAVE_AT
-		SAVE_TEMP
-		SAVE_STATIC
-		.endm
-
-		.macro	RESTORE_AT
-		.set	push
-		.set	noat
-		LONG_L	$1,  PT_R1(sp)
-		.set	pop
-		.endm
-
-		.macro	RESTORE_TEMP
-#ifdef CONFIG_CPU_HAS_SMARTMIPS
-		LONG_L	$24, PT_ACX(sp)
-		mtlhx	$24
-		LONG_L	$24, PT_HI(sp)
-		mtlhx	$24
-		LONG_L	$24, PT_LO(sp)
-		mtlhx	$24
-#else
-		LONG_L	$24, PT_LO(sp)
-		mtlo	$24
-		LONG_L	$24, PT_HI(sp)
-		mthi	$24
-#endif
-#ifdef CONFIG_32BIT
-		LONG_L	$8, PT_R8(sp)
-		LONG_L	$9, PT_R9(sp)
-#endif
-		LONG_L	$10, PT_R10(sp)
-		LONG_L	$11, PT_R11(sp)
-		LONG_L	$12, PT_R12(sp)
-		LONG_L	$13, PT_R13(sp)
-		LONG_L	$14, PT_R14(sp)
-		LONG_L	$15, PT_R15(sp)
-		LONG_L	$24, PT_R24(sp)
-		.endm
-
-		.macro	RESTORE_STATIC
-		LONG_L	$16, PT_R16(sp)
-		LONG_L	$17, PT_R17(sp)
-		LONG_L	$18, PT_R18(sp)
-		LONG_L	$19, PT_R19(sp)
-		LONG_L	$20, PT_R20(sp)
-		LONG_L	$21, PT_R21(sp)
-		LONG_L	$22, PT_R22(sp)
-		LONG_L	$23, PT_R23(sp)
-		LONG_L	$30, PT_R30(sp)
-		.endm
-
-#if defined(CONFIG_CPU_R3000) || defined(CONFIG_CPU_TX39XX)
-
-		.macro	RESTORE_SOME
-		.set	push
-		.set	reorder
-		.set	noat
-		mfc0	a0, CP0_STATUS
-		li	v1, 0xff00
-		ori	a0, STATMASK
-		xori	a0, STATMASK
-		mtc0	a0, CP0_STATUS
-		and	a0, v1
-		LONG_L	v0, PT_STATUS(sp)
-		nor	v1, $0, v1
-		and	v0, v1
-		or	v0, a0
-		mtc0	v0, CP0_STATUS
-		LONG_L	$31, PT_R31(sp)
-		LONG_L	$28, PT_R28(sp)
-		LONG_L	$25, PT_R25(sp)
-		LONG_L	$7,  PT_R7(sp)
-		LONG_L	$6,  PT_R6(sp)
-		LONG_L	$5,  PT_R5(sp)
-		LONG_L	$4,  PT_R4(sp)
-		LONG_L	$3,  PT_R3(sp)
-		LONG_L	$2,  PT_R2(sp)
-		.set	pop
-		.endm
-
-		.macro	RESTORE_SP_AND_RET
-		.set	push
-		.set	noreorder
-		LONG_L	k0, PT_EPC(sp)
-		LONG_L	sp, PT_R29(sp)
-		jr	k0
-		 rfe
-		.set	pop
-		.endm
-
-#else
-		.macro	RESTORE_SOME
-		.set	push
-		.set	reorder
-		.set	noat
-#ifdef CONFIG_MIPS_MT_SMTC
-		.set	mips32r2
-		/*
-		 * This may not really be necessary if ints are already
-		 * inhibited here.
-		 */
-		mfc0	v0, CP0_TCSTATUS
-		ori	v0, TCSTATUS_IXMT
-		mtc0	v0, CP0_TCSTATUS
-		_ehb
-		DMT	5				# dmt a1
-		jal	mips_ihb
-#endif /* CONFIG_MIPS_MT_SMTC */
-		mfc0	a0, CP0_STATUS
-		ori	a0, STATMASK
-		xori	a0, STATMASK
-		mtc0	a0, CP0_STATUS
-		li	v1, 0xff00
-		and	a0, v1
-		LONG_L	v0, PT_STATUS(sp)
-		nor	v1, $0, v1
-		and	v0, v1
-		or	v0, a0
-		mtc0	v0, CP0_STATUS
-#ifdef CONFIG_MIPS_MT_SMTC
-/*
- * Only after EXL/ERL have been restored to status can we
- * restore TCStatus.IXMT.
- */
-		LONG_L	v1, PT_TCSTATUS(sp)
-		_ehb
-		mfc0	v0, CP0_TCSTATUS
-		andi	v1, TCSTATUS_IXMT
-		/* We know that TCStatua.IXMT should be set from above */
-		xori	v0, v0, TCSTATUS_IXMT
-		or	v0, v0, v1
-		mtc0	v0, CP0_TCSTATUS
-		_ehb
-		andi	a1, a1, VPECONTROL_TE
-		beqz	a1, 1f
-		emt
-1:
-		.set	mips0
-#endif /* CONFIG_MIPS_MT_SMTC */
-		LONG_L	v1, PT_EPC(sp)
-		MTC0	v1, CP0_EPC
-		LONG_L	$31, PT_R31(sp)
-		LONG_L	$28, PT_R28(sp)
-		LONG_L	$25, PT_R25(sp)
-#ifdef CONFIG_64BIT
-		LONG_L	$8, PT_R8(sp)
-		LONG_L	$9, PT_R9(sp)
-#endif
-		LONG_L	$7,  PT_R7(sp)
-		LONG_L	$6,  PT_R6(sp)
-		LONG_L	$5,  PT_R5(sp)
-		LONG_L	$4,  PT_R4(sp)
-		LONG_L	$3,  PT_R3(sp)
-		LONG_L	$2,  PT_R2(sp)
-		.set	pop
-		.endm
-
-		.macro	RESTORE_SP_AND_RET
-		LONG_L	sp, PT_R29(sp)
-		.set	mips3
-		eret
-		.set	mips0
-		.endm
-
-#endif
-
-		.macro	RESTORE_SP
-		LONG_L	sp, PT_R29(sp)
-		.endm
-
-		.macro	RESTORE_ALL
-		RESTORE_TEMP
-		RESTORE_STATIC
-		RESTORE_AT
-		RESTORE_SOME
-		RESTORE_SP
-		.endm
-
-		.macro	RESTORE_ALL_AND_RET
-		RESTORE_TEMP
-		RESTORE_STATIC
-		RESTORE_AT
-		RESTORE_SOME
-		RESTORE_SP_AND_RET
-		.endm
-
-/*
- * Move to kernel mode and disable interrupts.
- * Set cp0 enable bit as sign that we're running on the kernel stack
- */
-		.macro	CLI
-#if !defined(CONFIG_MIPS_MT_SMTC)
-		mfc0	t0, CP0_STATUS
-		li	t1, ST0_CU0 | STATMASK
-		or	t0, t1
-		xori	t0, STATMASK
-		mtc0	t0, CP0_STATUS
-#else /* CONFIG_MIPS_MT_SMTC */
-		/*
-		 * For SMTC, we need to set privilege
-		 * and disable interrupts only for the
-		 * current TC, using the TCStatus register.
-		 */
-		mfc0	t0, CP0_TCSTATUS
-		/* Fortunately CU 0 is in the same place in both registers */
-		/* Set TCU0, TMX, TKSU (for later inversion) and IXMT */
-		li	t1, ST0_CU0 | 0x08001c00
-		or	t0, t1
-		/* Clear TKSU, leave IXMT */
-		xori	t0, 0x00001800
-		mtc0	t0, CP0_TCSTATUS
-		_ehb
-		/* We need to leave the global IE bit set, but clear EXL...*/
-		mfc0	t0, CP0_STATUS
-		ori	t0, ST0_EXL | ST0_ERL
-		xori	t0, ST0_EXL | ST0_ERL
-		mtc0	t0, CP0_STATUS
-#endif /* CONFIG_MIPS_MT_SMTC */
-		irq_disable_hazard
-		.endm
-
-/*
- * Move to kernel mode and enable interrupts.
- * Set cp0 enable bit as sign that we're running on the kernel stack
- */
-		.macro	STI
-#if !defined(CONFIG_MIPS_MT_SMTC)
-		mfc0	t0, CP0_STATUS
-		li	t1, ST0_CU0 | STATMASK
-		or	t0, t1
-		xori	t0, STATMASK & ~1
-		mtc0	t0, CP0_STATUS
-#else /* CONFIG_MIPS_MT_SMTC */
-		/*
-		 * For SMTC, we need to set privilege
-		 * and enable interrupts only for the
-		 * current TC, using the TCStatus register.
-		 */
-		_ehb
-		mfc0	t0, CP0_TCSTATUS
-		/* Fortunately CU 0 is in the same place in both registers */
-		/* Set TCU0, TKSU (for later inversion) and IXMT */
-		li	t1, ST0_CU0 | 0x08001c00
-		or	t0, t1
-		/* Clear TKSU *and* IXMT */
-		xori	t0, 0x00001c00
-		mtc0	t0, CP0_TCSTATUS
-		_ehb
-		/* We need to leave the global IE bit set, but clear EXL...*/
-		mfc0	t0, CP0_STATUS
-		ori	t0, ST0_EXL
-		xori	t0, ST0_EXL
-		mtc0	t0, CP0_STATUS
-		/* irq_enable_hazard below should expand to EHB for 24K/34K cpus */
-#endif /* CONFIG_MIPS_MT_SMTC */
-		irq_enable_hazard
-		.endm
-
-/*
- * Just move to kernel mode and leave interrupts as they are.  Note
- * for the R3000 this means copying the previous enable from IEp.
- * Set cp0 enable bit as sign that we're running on the kernel stack
- */
-		.macro	KMODE
-#ifdef CONFIG_MIPS_MT_SMTC
-		/*
-		 * This gets baroque in SMTC.  We want to
-		 * protect the non-atomic clearing of EXL
-		 * with DMT/EMT, but we don't want to take
-		 * an interrupt while DMT is still in effect.
-		 */
-
-		/* KMODE gets invoked from both reorder and noreorder code */
-		.set	push
-		.set	mips32r2
-		.set	noreorder
-		mfc0	v0, CP0_TCSTATUS
-		andi	v1, v0, TCSTATUS_IXMT
-		ori	v0, TCSTATUS_IXMT
-		mtc0	v0, CP0_TCSTATUS
-		_ehb
-		DMT	2				# dmt	v0
-		/*
-		 * We don't know a priori if ra is "live"
-		 */
-		move	t0, ra
-		jal	mips_ihb
-		nop	/* delay slot */
-		move	ra, t0
-#endif /* CONFIG_MIPS_MT_SMTC */
-		mfc0	t0, CP0_STATUS
-		li	t1, ST0_CU0 | (STATMASK & ~1)
-#if defined(CONFIG_CPU_R3000) || defined(CONFIG_CPU_TX39XX)
-		andi	t2, t0, ST0_IEP
-		srl	t2, 2
-		or	t0, t2
-#endif
-		or	t0, t1
-		xori	t0, STATMASK & ~1
-		mtc0	t0, CP0_STATUS
-#ifdef CONFIG_MIPS_MT_SMTC
-		_ehb
-		andi	v0, v0, VPECONTROL_TE
-		beqz	v0, 2f
-		nop	/* delay slot */
-		emt
-2:
-		mfc0	v0, CP0_TCSTATUS
-		/* Clear IXMT, then OR in previous value */
-		ori	v0, TCSTATUS_IXMT
-		xori	v0, TCSTATUS_IXMT
-		or	v0, v1, v0
-		mtc0	v0, CP0_TCSTATUS
-		/*
-		 * irq_disable_hazard below should expand to EHB
-		 * on 24K/34K CPUS
-		 */
-		.set pop
-#endif /* CONFIG_MIPS_MT_SMTC */
-		irq_disable_hazard
-		.endm
-
-#endif /* _ASM_STACKFRAME_H */
diff --git a/include/asm-mips/system.h b/include/asm-mips/system.h
deleted file mode 100644
index a944eda..0000000
--- a/include/asm-mips/system.h
+++ /dev/null
@@ -1,220 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 1994, 95, 96, 97, 98, 99, 2003, 06 by Ralf Baechle
- * Copyright (C) 1996 by Paul M. Antoine
- * Copyright (C) 1999 Silicon Graphics
- * Kevin D. Kissell, kevink@mips.org and Carsten Langgaard, carstenl@mips.com
- * Copyright (C) 2000 MIPS Technologies, Inc.
- */
-#ifndef _ASM_SYSTEM_H
-#define _ASM_SYSTEM_H
-
-#include <linux/types.h>
-#include <linux/irqflags.h>
-
-#include <asm/addrspace.h>
-#include <asm/barrier.h>
-#include <asm/cmpxchg.h>
-#include <asm/cpu-features.h>
-#include <asm/dsp.h>
-#include <asm/war.h>
-
-
-/*
- * switch_to(n) should switch tasks to task nr n, first
- * checking that n isn't the current task, in which case it does nothing.
- */
-extern asmlinkage void *resume(void *last, void *next, void *next_ti);
-
-struct task_struct;
-
-#ifdef CONFIG_MIPS_MT_FPAFF
-
-/*
- * Handle the scheduler resume end of FPU affinity management.  We do this
- * inline to try to keep the overhead down. If we have been forced to run on
- * a "CPU" with an FPU because of a previous high level of FP computation,
- * but did not actually use the FPU during the most recent time-slice (CU1
- * isn't set), we undo the restriction on cpus_allowed.
- *
- * We're not calling set_cpus_allowed() here, because we have no need to
- * force prompt migration - we're already switching the current CPU to a
- * different thread.
- */
-
-#define __mips_mt_fpaff_switch_to(prev)					\
-do {									\
-	struct thread_info *__prev_ti = task_thread_info(prev);		\
-									\
-	if (cpu_has_fpu &&						\
-	    test_ti_thread_flag(__prev_ti, TIF_FPUBOUND) &&		\
-	    (!(KSTK_STATUS(prev) & ST0_CU1))) {				\
-		clear_ti_thread_flag(__prev_ti, TIF_FPUBOUND);		\
-		prev->cpus_allowed = prev->thread.user_cpus_allowed;	\
-	}								\
-	next->thread.emulated_fp = 0;					\
-} while(0)
-
-#else
-#define __mips_mt_fpaff_switch_to(prev) do { (void) (prev); } while (0)
-#endif
-
-#define switch_to(prev, next, last)					\
-do {									\
-	__mips_mt_fpaff_switch_to(prev);				\
-	if (cpu_has_dsp)						\
-		__save_dsp(prev);					\
-	(last) = resume(prev, next, task_thread_info(next));		\
-} while (0)
-
-#define finish_arch_switch(prev)					\
-do {									\
-	if (cpu_has_dsp)						\
-		__restore_dsp(current);					\
-	if (cpu_has_userlocal)						\
-		write_c0_userlocal(current_thread_info()->tp_value);	\
-} while (0)
-
-static inline unsigned long __xchg_u32(volatile int * m, unsigned int val)
-{
-	__u32 retval;
-
-	if (cpu_has_llsc && R10000_LLSC_WAR) {
-		unsigned long dummy;
-
-		__asm__ __volatile__(
-		"	.set	mips3					\n"
-		"1:	ll	%0, %3			# xchg_u32	\n"
-		"	.set	mips0					\n"
-		"	move	%2, %z4					\n"
-		"	.set	mips3					\n"
-		"	sc	%2, %1					\n"
-		"	beqzl	%2, 1b					\n"
-		"	.set	mips0					\n"
-		: "=&r" (retval), "=m" (*m), "=&r" (dummy)
-		: "R" (*m), "Jr" (val)
-		: "memory");
-	} else if (cpu_has_llsc) {
-		unsigned long dummy;
-
-		__asm__ __volatile__(
-		"	.set	mips3					\n"
-		"1:	ll	%0, %3			# xchg_u32	\n"
-		"	.set	mips0					\n"
-		"	move	%2, %z4					\n"
-		"	.set	mips3					\n"
-		"	sc	%2, %1					\n"
-		"	beqz	%2, 2f					\n"
-		"	.subsection 2					\n"
-		"2:	b	1b					\n"
-		"	.previous					\n"
-		"	.set	mips0					\n"
-		: "=&r" (retval), "=m" (*m), "=&r" (dummy)
-		: "R" (*m), "Jr" (val)
-		: "memory");
-	} else {
-		unsigned long flags;
-
-		raw_local_irq_save(flags);
-		retval = *m;
-		*m = val;
-		raw_local_irq_restore(flags);	/* implies memory barrier  */
-	}
-
-	smp_llsc_mb();
-
-	return retval;
-}
-
-#ifdef CONFIG_64BIT
-static inline __u64 __xchg_u64(volatile __u64 * m, __u64 val)
-{
-	__u64 retval;
-
-	if (cpu_has_llsc && R10000_LLSC_WAR) {
-		unsigned long dummy;
-
-		__asm__ __volatile__(
-		"	.set	mips3					\n"
-		"1:	lld	%0, %3			# xchg_u64	\n"
-		"	move	%2, %z4					\n"
-		"	scd	%2, %1					\n"
-		"	beqzl	%2, 1b					\n"
-		"	.set	mips0					\n"
-		: "=&r" (retval), "=m" (*m), "=&r" (dummy)
-		: "R" (*m), "Jr" (val)
-		: "memory");
-	} else if (cpu_has_llsc) {
-		unsigned long dummy;
-
-		__asm__ __volatile__(
-		"	.set	mips3					\n"
-		"1:	lld	%0, %3			# xchg_u64	\n"
-		"	move	%2, %z4					\n"
-		"	scd	%2, %1					\n"
-		"	beqz	%2, 2f					\n"
-		"	.subsection 2					\n"
-		"2:	b	1b					\n"
-		"	.previous					\n"
-		"	.set	mips0					\n"
-		: "=&r" (retval), "=m" (*m), "=&r" (dummy)
-		: "R" (*m), "Jr" (val)
-		: "memory");
-	} else {
-		unsigned long flags;
-
-		raw_local_irq_save(flags);
-		retval = *m;
-		*m = val;
-		raw_local_irq_restore(flags);	/* implies memory barrier  */
-	}
-
-	smp_llsc_mb();
-
-	return retval;
-}
-#else
-extern __u64 __xchg_u64_unsupported_on_32bit_kernels(volatile __u64 * m, __u64 val);
-#define __xchg_u64 __xchg_u64_unsupported_on_32bit_kernels
-#endif
-
-/* This function doesn't exist, so you'll get a linker error
-   if something tries to do an invalid xchg().  */
-extern void __xchg_called_with_bad_pointer(void);
-
-static inline unsigned long __xchg(unsigned long x, volatile void * ptr, int size)
-{
-	switch (size) {
-	case 4:
-		return __xchg_u32(ptr, x);
-	case 8:
-		return __xchg_u64(ptr, x);
-	}
-	__xchg_called_with_bad_pointer();
-	return x;
-}
-
-#define xchg(ptr, x) ((__typeof__(*(ptr)))__xchg((unsigned long)(x), (ptr), sizeof(*(ptr))))
-
-extern void set_handler(unsigned long offset, void *addr, unsigned long len);
-extern void set_uncached_handler(unsigned long offset, void *addr, unsigned long len);
-
-typedef void (*vi_handler_t)(void);
-extern void *set_vi_handler(int n, vi_handler_t addr);
-
-extern void *set_except_vector(int n, void *addr);
-extern unsigned long ebase;
-extern void per_cpu_trap_init(void);
-
-/*
- * See include/asm-ia64/system.h; prevents deadlock on SMP
- * systems.
- */
-#define __ARCH_WANT_UNLOCKED_CTXSW
-
-extern unsigned long arch_align_stack(unsigned long sp);
-
-#endif /* _ASM_SYSTEM_H */
diff --git a/include/asm-mips/thread_info.h b/include/asm-mips/thread_info.h
deleted file mode 100644
index bb30606..0000000
--- a/include/asm-mips/thread_info.h
+++ /dev/null
@@ -1,151 +0,0 @@
-/* thread_info.h: MIPS low-level thread information
- *
- * Copyright (C) 2002  David Howells (dhowells@redhat.com)
- * - Incorporating suggestions made by Linus Torvalds and Dave Miller
- */
-
-#ifndef _ASM_THREAD_INFO_H
-#define _ASM_THREAD_INFO_H
-
-#ifdef __KERNEL__
-
-
-#ifndef __ASSEMBLY__
-
-#include <asm/processor.h>
-
-/*
- * low level task data that entry.S needs immediate access to
- * - this struct should fit entirely inside of one cache line
- * - this struct shares the supervisor stack pages
- * - if the contents of this structure are changed, the assembly constants
- *   must also be changed
- */
-struct thread_info {
-	struct task_struct	*task;		/* main task structure */
-	struct exec_domain	*exec_domain;	/* execution domain */
-	unsigned long		flags;		/* low level flags */
-	unsigned long		tp_value;	/* thread pointer */
-	__u32			cpu;		/* current CPU */
-	int			preempt_count;	/* 0 => preemptable, <0 => BUG */
-
-	mm_segment_t		addr_limit;	/* thread address space:
-						   0-0xBFFFFFFF for user-thead
-						   0-0xFFFFFFFF for kernel-thread
-						*/
-	struct restart_block	restart_block;
-	struct pt_regs		*regs;
-};
-
-/*
- * macros/functions for gaining access to the thread information structure
- *
- * preempt_count needs to be 1 initially, until the scheduler is functional.
- */
-#define INIT_THREAD_INFO(tsk)			\
-{						\
-	.task		= &tsk,			\
-	.exec_domain	= &default_exec_domain,	\
-	.flags		= _TIF_FIXADE,		\
-	.cpu		= 0,			\
-	.preempt_count	= 1,			\
-	.addr_limit	= KERNEL_DS,		\
-	.restart_block	= {			\
-		.fn = do_no_restart_syscall,	\
-	},					\
-}
-
-#define init_thread_info	(init_thread_union.thread_info)
-#define init_stack		(init_thread_union.stack)
-
-/* How to get the thread information struct from C.  */
-register struct thread_info *__current_thread_info __asm__("$28");
-#define current_thread_info()  __current_thread_info
-
-/* thread information allocation */
-#if defined(CONFIG_PAGE_SIZE_4KB) && defined(CONFIG_32BIT)
-#define THREAD_SIZE_ORDER (1)
-#endif
-#if defined(CONFIG_PAGE_SIZE_4KB) && defined(CONFIG_64BIT)
-#define THREAD_SIZE_ORDER (2)
-#endif
-#ifdef CONFIG_PAGE_SIZE_8KB
-#define THREAD_SIZE_ORDER (1)
-#endif
-#ifdef CONFIG_PAGE_SIZE_16KB
-#define THREAD_SIZE_ORDER (0)
-#endif
-#ifdef CONFIG_PAGE_SIZE_64KB
-#define THREAD_SIZE_ORDER (0)
-#endif
-
-#define THREAD_SIZE (PAGE_SIZE << THREAD_SIZE_ORDER)
-#define THREAD_MASK (THREAD_SIZE - 1UL)
-
-#define __HAVE_ARCH_THREAD_INFO_ALLOCATOR
-
-#ifdef CONFIG_DEBUG_STACK_USAGE
-#define alloc_thread_info(tsk)					\
-({								\
-	struct thread_info *ret;				\
-								\
-	ret = kzalloc(THREAD_SIZE, GFP_KERNEL);			\
-								\
-	ret;							\
-})
-#else
-#define alloc_thread_info(tsk) kmalloc(THREAD_SIZE, GFP_KERNEL)
-#endif
-
-#define free_thread_info(info) kfree(info)
-
-#endif /* !__ASSEMBLY__ */
-
-#define PREEMPT_ACTIVE		0x10000000
-
-/*
- * thread information flags
- * - these are process state flags that various assembly files may need to
- *   access
- * - pending work-to-be-done flags are in LSW
- * - other flags in MSW
- */
-#define TIF_SIGPENDING		1	/* signal pending */
-#define TIF_NEED_RESCHED	2	/* rescheduling necessary */
-#define TIF_SYSCALL_AUDIT	3	/* syscall auditing active */
-#define TIF_SECCOMP		4	/* secure computing */
-#define TIF_RESTORE_SIGMASK	9	/* restore signal mask in do_signal() */
-#define TIF_USEDFPU		16	/* FPU was used by this task this quantum (SMP) */
-#define TIF_POLLING_NRFLAG	17	/* true if poll_idle() is polling TIF_NEED_RESCHED */
-#define TIF_MEMDIE		18
-#define TIF_FREEZE		19
-#define TIF_FIXADE		20	/* Fix address errors in software */
-#define TIF_LOGADE		21	/* Log address errors to syslog */
-#define TIF_32BIT_REGS		22	/* also implies 16/32 fprs */
-#define TIF_32BIT_ADDR		23	/* 32-bit address space (o32/n32) */
-#define TIF_FPUBOUND		24	/* thread bound to FPU-full CPU set */
-#define TIF_SYSCALL_TRACE	31	/* syscall trace active */
-
-#define _TIF_SYSCALL_TRACE	(1<<TIF_SYSCALL_TRACE)
-#define _TIF_SIGPENDING		(1<<TIF_SIGPENDING)
-#define _TIF_NEED_RESCHED	(1<<TIF_NEED_RESCHED)
-#define _TIF_SYSCALL_AUDIT	(1<<TIF_SYSCALL_AUDIT)
-#define _TIF_SECCOMP		(1<<TIF_SECCOMP)
-#define _TIF_RESTORE_SIGMASK	(1<<TIF_RESTORE_SIGMASK)
-#define _TIF_USEDFPU		(1<<TIF_USEDFPU)
-#define _TIF_POLLING_NRFLAG	(1<<TIF_POLLING_NRFLAG)
-#define _TIF_FREEZE		(1<<TIF_FREEZE)
-#define _TIF_FIXADE		(1<<TIF_FIXADE)
-#define _TIF_LOGADE		(1<<TIF_LOGADE)
-#define _TIF_32BIT_REGS		(1<<TIF_32BIT_REGS)
-#define _TIF_32BIT_ADDR		(1<<TIF_32BIT_ADDR)
-#define _TIF_FPUBOUND		(1<<TIF_FPUBOUND)
-
-/* work to do on interrupt/exception return */
-#define _TIF_WORK_MASK		(0x0000ffef & ~_TIF_SECCOMP)
-/* work to do on any return to u-space */
-#define _TIF_ALLWORK_MASK	(0x8000ffff & ~_TIF_SECCOMP)
-
-#endif /* __KERNEL__ */
-
-#endif /* _ASM_THREAD_INFO_H */
diff --git a/include/asm-mips/txx9/generic.h b/include/asm-mips/txx9/generic.h
deleted file mode 100644
index 5b1ccf9..0000000
--- a/include/asm-mips/txx9/generic.h
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * linux/include/asm-mips/txx9/generic.h
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- */
-#ifndef __ASM_TXX9_GENERIC_H
-#define __ASM_TXX9_GENERIC_H
-
-#include <linux/init.h>
-#include <linux/ioport.h>	/* for struct resource */
-
-extern struct resource txx9_ce_res[];
-#define TXX9_CE(n)	(unsigned long)(txx9_ce_res[(n)].start)
-extern unsigned int txx9_pcode;
-extern char txx9_pcode_str[8];
-void txx9_reg_res_init(unsigned int pcode, unsigned long base,
-		       unsigned long size);
-
-extern unsigned int txx9_master_clock;
-extern unsigned int txx9_cpu_clock;
-extern unsigned int txx9_gbus_clock;
-#define TXX9_IMCLK	(txx9_gbus_clock / 2)
-
-extern int txx9_ccfg_toeon;
-struct uart_port;
-int early_serial_txx9_setup(struct uart_port *port);
-
-struct pci_dev;
-struct txx9_board_vec {
-	const char *system;
-	void (*prom_init)(void);
-	void (*mem_setup)(void);
-	void (*irq_setup)(void);
-	void (*time_init)(void);
-	void (*arch_init)(void);
-	void (*device_init)(void);
-#ifdef CONFIG_PCI
-	int (*pci_map_irq)(const struct pci_dev *dev, u8 slot, u8 pin);
-#endif
-};
-extern struct txx9_board_vec *txx9_board_vec;
-extern int (*txx9_irq_dispatch)(int pending);
-void prom_init_cmdline(void);
-char *prom_getcmdline(void);
-void txx9_wdt_init(unsigned long base);
-void txx9_spi_init(int busid, unsigned long base, int irq);
-void txx9_ethaddr_init(unsigned int id, unsigned char *ethaddr);
-void txx9_sio_init(unsigned long baseaddr, int irq,
-		   unsigned int line, unsigned int sclk, int nocts);
-void prom_putchar(char c);
-#ifdef CONFIG_EARLY_PRINTK
-extern void (*txx9_prom_putchar)(char c);
-void txx9_sio_putchar_init(unsigned long baseaddr);
-#else
-static inline void txx9_sio_putchar_init(unsigned long baseaddr)
-{
-}
-#endif
-
-#endif /* __ASM_TXX9_GENERIC_H */
diff --git a/include/asm-mips/txx9/rbtx4927.h b/include/asm-mips/txx9/rbtx4927.h
deleted file mode 100644
index 6fcec91..0000000
--- a/include/asm-mips/txx9/rbtx4927.h
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Author: MontaVista Software, Inc.
- *         source@mvista.com
- *
- * Copyright 2001-2002 MontaVista Software Inc.
- *
- *  This program is free software; you can redistribute it and/or modify it
- *  under the terms of the GNU General Public License as published by the
- *  Free Software Foundation; either version 2 of the License, or (at your
- *  option) any later version.
- *
- *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
- *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- *  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- *  OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- *  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
- *  TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
- *  USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- *  You should have received a copy of the GNU General Public License along
- *  with this program; if not, write to the Free Software Foundation, Inc.,
- *  675 Mass Ave, Cambridge, MA 02139, USA.
- */
-#ifndef __ASM_TXX9_RBTX4927_H
-#define __ASM_TXX9_RBTX4927_H
-
-#include <asm/txx9/tx4927.h>
-
-#define RBTX4927_PCIMEM		0x08000000
-#define RBTX4927_PCIMEM_SIZE	0x08000000
-#define RBTX4927_PCIIO		0x16000000
-#define RBTX4927_PCIIO_SIZE	0x01000000
-
-#define RBTX4927_IMASK_ADDR	(IO_BASE + TXX9_CE(2) + 0x00002000)
-#define RBTX4927_IMSTAT_ADDR	(IO_BASE + TXX9_CE(2) + 0x00002006)
-#define RBTX4927_SOFTRESET_ADDR	(IO_BASE + TXX9_CE(2) + 0x0000f000)
-#define RBTX4927_SOFTRESETLOCK_ADDR	(IO_BASE + TXX9_CE(2) + 0x0000f002)
-#define RBTX4927_PCIRESET_ADDR	(IO_BASE + TXX9_CE(2) + 0x0000f006)
-#define RBTX4927_BRAMRTC_BASE	(IO_BASE + TXX9_CE(2) + 0x00010000)
-#define RBTX4927_ETHER_BASE	(IO_BASE + TXX9_CE(2) + 0x00020000)
-
-/* Ethernet port address */
-#define RBTX4927_ETHER_ADDR	(RBTX4927_ETHER_BASE + 0x280)
-
-#define rbtx4927_imask_addr	((__u8 __iomem *)RBTX4927_IMASK_ADDR)
-#define rbtx4927_imstat_addr	((__u8 __iomem *)RBTX4927_IMSTAT_ADDR)
-#define rbtx4927_softreset_addr	((__u8 __iomem *)RBTX4927_SOFTRESET_ADDR)
-#define rbtx4927_softresetlock_addr	\
-				((__u8 __iomem *)RBTX4927_SOFTRESETLOCK_ADDR)
-#define rbtx4927_pcireset_addr	((__u8 __iomem *)RBTX4927_PCIRESET_ADDR)
-
-/* bits for ISTAT/IMASK/IMSTAT */
-#define RBTX4927_INTB_PCID	0
-#define RBTX4927_INTB_PCIC	1
-#define RBTX4927_INTB_PCIB	2
-#define RBTX4927_INTB_PCIA	3
-#define RBTX4927_INTF_PCID	(1 << RBTX4927_INTB_PCID)
-#define RBTX4927_INTF_PCIC	(1 << RBTX4927_INTB_PCIC)
-#define RBTX4927_INTF_PCIB	(1 << RBTX4927_INTB_PCIB)
-#define RBTX4927_INTF_PCIA	(1 << RBTX4927_INTB_PCIA)
-
-#define RBTX4927_NR_IRQ_IOC	8	/* IOC */
-
-#define RBTX4927_IRQ_IOC	(TXX9_IRQ_BASE + TX4927_NUM_IR)
-#define RBTX4927_IRQ_IOC_PCID	(RBTX4927_IRQ_IOC + RBTX4927_INTB_PCID)
-#define RBTX4927_IRQ_IOC_PCIC	(RBTX4927_IRQ_IOC + RBTX4927_INTB_PCIC)
-#define RBTX4927_IRQ_IOC_PCIB	(RBTX4927_IRQ_IOC + RBTX4927_INTB_PCIB)
-#define RBTX4927_IRQ_IOC_PCIA	(RBTX4927_IRQ_IOC + RBTX4927_INTB_PCIA)
-
-#define RBTX4927_IRQ_IOCINT	(TXX9_IRQ_BASE + TX4927_IR_INT(1))
-
-#ifdef CONFIG_PCI
-#define RBTX4927_ISA_IO_OFFSET RBTX4927_PCIIO
-#else
-#define RBTX4927_ISA_IO_OFFSET 0
-#endif
-
-#define RBTX4927_RTL_8019_BASE (RBTX4927_ETHER_ADDR - mips_io_port_base)
-#define RBTX4927_RTL_8019_IRQ  (TXX9_IRQ_BASE + TX4927_IR_INT(3))
-
-void rbtx4927_prom_init(void);
-void rbtx4927_irq_setup(void);
-struct pci_dev;
-int rbtx4927_pci_map_irq(const struct pci_dev *dev, u8 slot, u8 pin);
-
-#endif /* __ASM_TXX9_RBTX4927_H */
diff --git a/include/asm-mips/txx9/smsc_fdc37m81x.h b/include/asm-mips/txx9/smsc_fdc37m81x.h
deleted file mode 100644
index 02e161d0..0000000
--- a/include/asm-mips/txx9/smsc_fdc37m81x.h
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Interface for smsc fdc48m81x Super IO chip
- *
- * Author: MontaVista Software, Inc. source@mvista.com
- *
- * 2001-2003 (c) MontaVista Software, Inc. This file is licensed under
- * the terms of the GNU General Public License version 2. This program
- * is licensed "as is" without any warranty of any kind, whether express
- * or implied.
- *
- * Copyright (C) 2004 MontaVista Software Inc.
- * Manish Lachwani, mlachwani@mvista.com
- */
-
-#ifndef _SMSC_FDC37M81X_H_
-#define _SMSC_FDC37M81X_H_
-
-/* Common Registers */
-#define SMSC_FDC37M81X_CONFIG_INDEX  0x00
-#define SMSC_FDC37M81X_CONFIG_DATA   0x01
-#define SMSC_FDC37M81X_CONF          0x02
-#define SMSC_FDC37M81X_INDEX         0x03
-#define SMSC_FDC37M81X_DNUM          0x07
-#define SMSC_FDC37M81X_DID           0x20
-#define SMSC_FDC37M81X_DREV          0x21
-#define SMSC_FDC37M81X_PCNT          0x22
-#define SMSC_FDC37M81X_PMGT          0x23
-#define SMSC_FDC37M81X_OSC           0x24
-#define SMSC_FDC37M81X_CONFPA0       0x26
-#define SMSC_FDC37M81X_CONFPA1       0x27
-#define SMSC_FDC37M81X_TEST4         0x2B
-#define SMSC_FDC37M81X_TEST5         0x2C
-#define SMSC_FDC37M81X_TEST1         0x2D
-#define SMSC_FDC37M81X_TEST2         0x2E
-#define SMSC_FDC37M81X_TEST3         0x2F
-
-/* Logical device numbers */
-#define SMSC_FDC37M81X_FDD           0x00
-#define SMSC_FDC37M81X_PARALLEL      0x03
-#define SMSC_FDC37M81X_SERIAL1       0x04
-#define SMSC_FDC37M81X_SERIAL2       0x05
-#define SMSC_FDC37M81X_KBD           0x07
-#define SMSC_FDC37M81X_AUXIO         0x08
-#define SMSC_FDC37M81X_NONE          0xff
-
-/* Logical device Config Registers */
-#define SMSC_FDC37M81X_ACTIVE        0x30
-#define SMSC_FDC37M81X_BASEADDR0     0x60
-#define SMSC_FDC37M81X_BASEADDR1     0x61
-#define SMSC_FDC37M81X_INT           0x70
-#define SMSC_FDC37M81X_INT2          0x72
-#define SMSC_FDC37M81X_LDCR_F0       0xF0
-
-/* Chip Config Values */
-#define SMSC_FDC37M81X_CONFIG_ENTER  0x55
-#define SMSC_FDC37M81X_CONFIG_EXIT   0xaa
-#define SMSC_FDC37M81X_CHIP_ID       0x4d
-
-unsigned long smsc_fdc37m81x_init(unsigned long port);
-
-void smsc_fdc37m81x_config_beg(void);
-
-void smsc_fdc37m81x_config_end(void);
-
-void smsc_fdc37m81x_config_set(u8 reg, u8 val);
-
-#endif
diff --git a/include/asm-mips/txx9/spi.h b/include/asm-mips/txx9/spi.h
deleted file mode 100644
index ddfb2a0..0000000
--- a/include/asm-mips/txx9/spi.h
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * Definitions for TX4937/TX4938 SPI
- *
- * Copyright (C) 2000-2001 Toshiba Corporation
- *
- * 2003-2005 (c) MontaVista Software, Inc. This file is licensed under the
- * terms of the GNU General Public License version 2. This program is
- * licensed "as is" without any warranty of any kind, whether express
- * or implied.
- *
- * Support for TX4938 in 2.6 - Manish Lachwani (mlachwani@mvista.com)
- */
-#ifndef __ASM_TXX9_SPI_H
-#define __ASM_TXX9_SPI_H
-
-extern int spi_eeprom_register(int chipid);
-extern int spi_eeprom_read(int chipid, int address, unsigned char *buf, int len);
-
-#endif /* __ASM_TXX9_SPI_H */
diff --git a/include/asm-mips/txx9/tx3927.h b/include/asm-mips/txx9/tx3927.h
deleted file mode 100644
index 587deb9..0000000
--- a/include/asm-mips/txx9/tx3927.h
+++ /dev/null
@@ -1,339 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 2000 Toshiba Corporation
- */
-#ifndef __ASM_TXX9_TX3927_H
-#define __ASM_TXX9_TX3927_H
-
-#define TX3927_REG_BASE	0xfffe0000UL
-#define TX3927_REG_SIZE	0x00010000
-#define TX3927_SDRAMC_REG	(TX3927_REG_BASE + 0x8000)
-#define TX3927_ROMC_REG		(TX3927_REG_BASE + 0x9000)
-#define TX3927_DMA_REG		(TX3927_REG_BASE + 0xb000)
-#define TX3927_IRC_REG		(TX3927_REG_BASE + 0xc000)
-#define TX3927_PCIC_REG		(TX3927_REG_BASE + 0xd000)
-#define TX3927_CCFG_REG		(TX3927_REG_BASE + 0xe000)
-#define TX3927_NR_TMR	3
-#define TX3927_TMR_REG(ch)	(TX3927_REG_BASE + 0xf000 + (ch) * 0x100)
-#define TX3927_NR_SIO	2
-#define TX3927_SIO_REG(ch)	(TX3927_REG_BASE + 0xf300 + (ch) * 0x100)
-#define TX3927_PIO_REG		(TX3927_REG_BASE + 0xf500)
-
-struct tx3927_sdramc_reg {
-	volatile unsigned long cr[8];
-	volatile unsigned long tr[3];
-	volatile unsigned long cmd;
-	volatile unsigned long smrs[2];
-};
-
-struct tx3927_romc_reg {
-	volatile unsigned long cr[8];
-};
-
-struct tx3927_dma_reg {
-	struct tx3927_dma_ch_reg {
-		volatile unsigned long cha;
-		volatile unsigned long sar;
-		volatile unsigned long dar;
-		volatile unsigned long cntr;
-		volatile unsigned long sair;
-		volatile unsigned long dair;
-		volatile unsigned long ccr;
-		volatile unsigned long csr;
-	} ch[4];
-	volatile unsigned long dbr[8];
-	volatile unsigned long tdhr;
-	volatile unsigned long mcr;
-	volatile unsigned long unused0;
-};
-
-#include <asm/byteorder.h>
-
-#ifdef __BIG_ENDIAN
-#define endian_def_s2(e1, e2)	\
-	volatile unsigned short e1, e2
-#define endian_def_sb2(e1, e2, e3)	\
-	volatile unsigned short e1;volatile unsigned char e2, e3
-#define endian_def_b2s(e1, e2, e3)	\
-	volatile unsigned char e1, e2;volatile unsigned short e3
-#define endian_def_b4(e1, e2, e3, e4)	\
-	volatile unsigned char e1, e2, e3, e4
-#else
-#define endian_def_s2(e1, e2)	\
-	volatile unsigned short e2, e1
-#define endian_def_sb2(e1, e2, e3)	\
-	volatile unsigned char e3, e2;volatile unsigned short e1
-#define endian_def_b2s(e1, e2, e3)	\
-	volatile unsigned short e3;volatile unsigned char e2, e1
-#define endian_def_b4(e1, e2, e3, e4)	\
-	volatile unsigned char e4, e3, e2, e1
-#endif
-
-struct tx3927_pcic_reg {
-	endian_def_s2(did, vid);
-	endian_def_s2(pcistat, pcicmd);
-	endian_def_b4(cc, scc, rpli, rid);
-	endian_def_b4(unused0, ht, mlt, cls);
-	volatile unsigned long ioba;		/* +10 */
-	volatile unsigned long mba;
-	volatile unsigned long unused1[5];
-	endian_def_s2(svid, ssvid);
-	volatile unsigned long unused2;		/* +30 */
-	endian_def_sb2(unused3, unused4, capptr);
-	volatile unsigned long unused5;
-	endian_def_b4(ml, mg, ip, il);
-	volatile unsigned long unused6;		/* +40 */
-	volatile unsigned long istat;
-	volatile unsigned long iim;
-	volatile unsigned long rrt;
-	volatile unsigned long unused7[3];		/* +50 */
-	volatile unsigned long ipbmma;
-	volatile unsigned long ipbioma;		/* +60 */
-	volatile unsigned long ilbmma;
-	volatile unsigned long ilbioma;
-	volatile unsigned long unused8[9];
-	volatile unsigned long tc;		/* +90 */
-	volatile unsigned long tstat;
-	volatile unsigned long tim;
-	volatile unsigned long tccmd;
-	volatile unsigned long pcirrt;		/* +a0 */
-	volatile unsigned long pcirrt_cmd;
-	volatile unsigned long pcirrdt;
-	volatile unsigned long unused9[3];
-	volatile unsigned long tlboap;
-	volatile unsigned long tlbiap;
-	volatile unsigned long tlbmma;		/* +c0 */
-	volatile unsigned long tlbioma;
-	volatile unsigned long sc_msg;
-	volatile unsigned long sc_be;
-	volatile unsigned long tbl;		/* +d0 */
-	volatile unsigned long unused10[3];
-	volatile unsigned long pwmng;		/* +e0 */
-	volatile unsigned long pwmngs;
-	volatile unsigned long unused11[6];
-	volatile unsigned long req_trace;		/* +100 */
-	volatile unsigned long pbapmc;
-	volatile unsigned long pbapms;
-	volatile unsigned long pbapmim;
-	volatile unsigned long bm;		/* +110 */
-	volatile unsigned long cpcibrs;
-	volatile unsigned long cpcibgs;
-	volatile unsigned long pbacs;
-	volatile unsigned long iobas;		/* +120 */
-	volatile unsigned long mbas;
-	volatile unsigned long lbc;
-	volatile unsigned long lbstat;
-	volatile unsigned long lbim;		/* +130 */
-	volatile unsigned long pcistatim;
-	volatile unsigned long ica;
-	volatile unsigned long icd;
-	volatile unsigned long iiadp;		/* +140 */
-	volatile unsigned long iscdp;
-	volatile unsigned long mmas;
-	volatile unsigned long iomas;
-	volatile unsigned long ipciaddr;		/* +150 */
-	volatile unsigned long ipcidata;
-	volatile unsigned long ipcibe;
-};
-
-struct tx3927_ccfg_reg {
-	volatile unsigned long ccfg;
-	volatile unsigned long crir;
-	volatile unsigned long pcfg;
-	volatile unsigned long tear;
-	volatile unsigned long pdcr;
-};
-
-/*
- * SDRAMC
- */
-
-/*
- * ROMC
- */
-
-/*
- * DMA
- */
-/* bits for MCR */
-#define TX3927_DMA_MCR_EIS(ch)	(0x10000000<<(ch))
-#define TX3927_DMA_MCR_DIS(ch)	(0x01000000<<(ch))
-#define TX3927_DMA_MCR_RSFIF	0x00000080
-#define TX3927_DMA_MCR_FIFUM(ch)	(0x00000008<<(ch))
-#define TX3927_DMA_MCR_LE	0x00000004
-#define TX3927_DMA_MCR_RPRT	0x00000002
-#define TX3927_DMA_MCR_MSTEN	0x00000001
-
-/* bits for CCRn */
-#define TX3927_DMA_CCR_DBINH	0x04000000
-#define TX3927_DMA_CCR_SBINH	0x02000000
-#define TX3927_DMA_CCR_CHRST	0x01000000
-#define TX3927_DMA_CCR_RVBYTE	0x00800000
-#define TX3927_DMA_CCR_ACKPOL	0x00400000
-#define TX3927_DMA_CCR_REQPL	0x00200000
-#define TX3927_DMA_CCR_EGREQ	0x00100000
-#define TX3927_DMA_CCR_CHDN	0x00080000
-#define TX3927_DMA_CCR_DNCTL	0x00060000
-#define TX3927_DMA_CCR_EXTRQ	0x00010000
-#define TX3927_DMA_CCR_INTRQD	0x0000e000
-#define TX3927_DMA_CCR_INTENE	0x00001000
-#define TX3927_DMA_CCR_INTENC	0x00000800
-#define TX3927_DMA_CCR_INTENT	0x00000400
-#define TX3927_DMA_CCR_CHNEN	0x00000200
-#define TX3927_DMA_CCR_XFACT	0x00000100
-#define TX3927_DMA_CCR_SNOP	0x00000080
-#define TX3927_DMA_CCR_DSTINC	0x00000040
-#define TX3927_DMA_CCR_SRCINC	0x00000020
-#define TX3927_DMA_CCR_XFSZ(order)	(((order) << 2) & 0x0000001c)
-#define TX3927_DMA_CCR_XFSZ_1W	TX3927_DMA_CCR_XFSZ(2)
-#define TX3927_DMA_CCR_XFSZ_4W	TX3927_DMA_CCR_XFSZ(4)
-#define TX3927_DMA_CCR_XFSZ_8W	TX3927_DMA_CCR_XFSZ(5)
-#define TX3927_DMA_CCR_XFSZ_16W	TX3927_DMA_CCR_XFSZ(6)
-#define TX3927_DMA_CCR_XFSZ_32W	TX3927_DMA_CCR_XFSZ(7)
-#define TX3927_DMA_CCR_MEMIO	0x00000002
-#define TX3927_DMA_CCR_ONEAD	0x00000001
-
-/* bits for CSRn */
-#define TX3927_DMA_CSR_CHNACT	0x00000100
-#define TX3927_DMA_CSR_ABCHC	0x00000080
-#define TX3927_DMA_CSR_NCHNC	0x00000040
-#define TX3927_DMA_CSR_NTRNFC	0x00000020
-#define TX3927_DMA_CSR_EXTDN	0x00000010
-#define TX3927_DMA_CSR_CFERR	0x00000008
-#define TX3927_DMA_CSR_CHERR	0x00000004
-#define TX3927_DMA_CSR_DESERR	0x00000002
-#define TX3927_DMA_CSR_SORERR	0x00000001
-
-/*
- * IRC
- */
-#define TX3927_IR_INT0	0
-#define TX3927_IR_INT1	1
-#define TX3927_IR_INT2	2
-#define TX3927_IR_INT3	3
-#define TX3927_IR_INT4	4
-#define TX3927_IR_INT5	5
-#define TX3927_IR_SIO0	6
-#define TX3927_IR_SIO1	7
-#define TX3927_IR_SIO(ch)	(6 + (ch))
-#define TX3927_IR_DMA	8
-#define TX3927_IR_PIO	9
-#define TX3927_IR_PCI	10
-#define TX3927_IR_TMR(ch)	(13 + (ch))
-#define TX3927_NUM_IR	16
-
-/*
- * PCIC
- */
-/* bits for PCICMD */
-/* see PCI_COMMAND_XXX in linux/pci.h */
-
-/* bits for PCISTAT */
-/* see PCI_STATUS_XXX in linux/pci.h */
-#define PCI_STATUS_NEW_CAP	0x0010
-
-/* bits for ISTAT/IIM */
-#define TX3927_PCIC_IIM_ALL	0x00001600
-
-/* bits for TC */
-#define TX3927_PCIC_TC_OF16E	0x00000020
-#define TX3927_PCIC_TC_IF8E	0x00000010
-#define TX3927_PCIC_TC_OF8E	0x00000008
-
-/* bits for TSTAT/TIM */
-#define TX3927_PCIC_TIM_ALL	0x0003ffff
-
-/* bits for IOBA/MBA */
-/* see PCI_BASE_ADDRESS_XXX in linux/pci.h */
-
-/* bits for PBAPMC */
-#define TX3927_PCIC_PBAPMC_RPBA	0x00000004
-#define TX3927_PCIC_PBAPMC_PBAEN	0x00000002
-#define TX3927_PCIC_PBAPMC_BMCEN	0x00000001
-
-/* bits for LBSTAT/LBIM */
-#define TX3927_PCIC_LBIM_ALL	0x0000003e
-
-/* bits for PCISTATIM (see also PCI_STATUS_XXX in linux/pci.h */
-#define TX3927_PCIC_PCISTATIM_ALL	0x0000f900
-
-/* bits for LBC */
-#define TX3927_PCIC_LBC_IBSE	0x00004000
-#define TX3927_PCIC_LBC_TIBSE	0x00002000
-#define TX3927_PCIC_LBC_TMFBSE	0x00001000
-#define TX3927_PCIC_LBC_HRST	0x00000800
-#define TX3927_PCIC_LBC_SRST	0x00000400
-#define TX3927_PCIC_LBC_EPCAD	0x00000200
-#define TX3927_PCIC_LBC_MSDSE	0x00000100
-#define TX3927_PCIC_LBC_CRR	0x00000080
-#define TX3927_PCIC_LBC_ILMDE	0x00000040
-#define TX3927_PCIC_LBC_ILIDE	0x00000020
-
-#define TX3927_PCIC_IDSEL_AD_TO_SLOT(ad)	((ad) - 11)
-#define TX3927_PCIC_MAX_DEVNU	TX3927_PCIC_IDSEL_AD_TO_SLOT(32)
-
-/*
- * CCFG
- */
-/* CCFG : Chip Configuration */
-#define TX3927_CCFG_TLBOFF	0x00020000
-#define TX3927_CCFG_BEOW	0x00010000
-#define TX3927_CCFG_WR	0x00008000
-#define TX3927_CCFG_TOE	0x00004000
-#define TX3927_CCFG_PCIXARB	0x00002000
-#define TX3927_CCFG_PCI3	0x00001000
-#define TX3927_CCFG_PSNP	0x00000800
-#define TX3927_CCFG_PPRI	0x00000400
-#define TX3927_CCFG_PLLM	0x00000030
-#define TX3927_CCFG_ENDIAN	0x00000004
-#define TX3927_CCFG_HALT	0x00000002
-#define TX3927_CCFG_ACEHOLD	0x00000001
-
-/* PCFG : Pin Configuration */
-#define TX3927_PCFG_SYSCLKEN	0x08000000
-#define TX3927_PCFG_SDRCLKEN_ALL	0x07c00000
-#define TX3927_PCFG_SDRCLKEN(ch)	(0x00400000<<(ch))
-#define TX3927_PCFG_PCICLKEN_ALL	0x003c0000
-#define TX3927_PCFG_PCICLKEN(ch)	(0x00040000<<(ch))
-#define TX3927_PCFG_SELALL	0x0003ffff
-#define TX3927_PCFG_SELCS	0x00020000
-#define TX3927_PCFG_SELDSF	0x00010000
-#define TX3927_PCFG_SELSIOC_ALL	0x0000c000
-#define TX3927_PCFG_SELSIOC(ch)	(0x00004000<<(ch))
-#define TX3927_PCFG_SELSIO_ALL	0x00003000
-#define TX3927_PCFG_SELSIO(ch)	(0x00001000<<(ch))
-#define TX3927_PCFG_SELTMR_ALL	0x00000e00
-#define TX3927_PCFG_SELTMR(ch)	(0x00000200<<(ch))
-#define TX3927_PCFG_SELDONE	0x00000100
-#define TX3927_PCFG_INTDMA_ALL	0x000000f0
-#define TX3927_PCFG_INTDMA(ch)	(0x00000010<<(ch))
-#define TX3927_PCFG_SELDMA_ALL	0x0000000f
-#define TX3927_PCFG_SELDMA(ch)	(0x00000001<<(ch))
-
-#define tx3927_sdramcptr	((struct tx3927_sdramc_reg *)TX3927_SDRAMC_REG)
-#define tx3927_romcptr		((struct tx3927_romc_reg *)TX3927_ROMC_REG)
-#define tx3927_dmaptr		((struct tx3927_dma_reg *)TX3927_DMA_REG)
-#define tx3927_pcicptr		((struct tx3927_pcic_reg *)TX3927_PCIC_REG)
-#define tx3927_ccfgptr		((struct tx3927_ccfg_reg *)TX3927_CCFG_REG)
-#define tx3927_sioptr(ch)	((struct txx927_sio_reg *)TX3927_SIO_REG(ch))
-#define tx3927_pioptr		((struct txx9_pio_reg __iomem *)TX3927_PIO_REG)
-
-#define TX3927_REV_PCODE()	(tx3927_ccfgptr->crir >> 16)
-#define TX3927_ROMC_BA(ch)	(tx3927_romcptr->cr[(ch)] & 0xfff00000)
-#define TX3927_ROMC_SIZE(ch)	\
-	(0x00100000 << ((tx3927_romcptr->cr[(ch)] >> 8) & 0xf))
-
-void tx3927_wdt_init(void);
-void tx3927_setup(void);
-void tx3927_time_init(unsigned int evt_tmrnr, unsigned int src_tmrnr);
-void tx3927_sio_init(unsigned int sclk, unsigned int cts_mask);
-struct pci_controller;
-void tx3927_pcic_setup(struct pci_controller *channel,
-		       unsigned long sdram_size, int extarb);
-void tx3927_setup_pcierr_irq(void);
-void tx3927_irq_init(void);
-
-#endif /* __ASM_TXX9_TX3927_H */
diff --git a/include/asm-mips/txx9/tx4927.h b/include/asm-mips/txx9/tx4927.h
deleted file mode 100644
index 195f651..0000000
--- a/include/asm-mips/txx9/tx4927.h
+++ /dev/null
@@ -1,255 +0,0 @@
-/*
- * Author: MontaVista Software, Inc.
- *         source@mvista.com
- *
- * Copyright 2001-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.
- *
- *  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.
- */
-#ifndef __ASM_TXX9_TX4927_H
-#define __ASM_TXX9_TX4927_H
-
-#include <linux/types.h>
-#include <linux/io.h>
-#include <asm/txx9irq.h>
-#include <asm/txx9/tx4927pcic.h>
-
-#ifdef CONFIG_64BIT
-#define TX4927_REG_BASE	0xffffffffff1f0000UL
-#else
-#define TX4927_REG_BASE	0xff1f0000UL
-#endif
-#define TX4927_REG_SIZE	0x00010000
-
-#define TX4927_SDRAMC_REG	(TX4927_REG_BASE + 0x8000)
-#define TX4927_EBUSC_REG	(TX4927_REG_BASE + 0x9000)
-#define TX4927_PCIC_REG		(TX4927_REG_BASE + 0xd000)
-#define TX4927_CCFG_REG		(TX4927_REG_BASE + 0xe000)
-#define TX4927_IRC_REG		(TX4927_REG_BASE + 0xf600)
-#define TX4927_NR_TMR	3
-#define TX4927_TMR_REG(ch)	(TX4927_REG_BASE + 0xf000 + (ch) * 0x100)
-#define TX4927_NR_SIO	2
-#define TX4927_SIO_REG(ch)	(TX4927_REG_BASE + 0xf300 + (ch) * 0x100)
-#define TX4927_PIO_REG		(TX4927_REG_BASE + 0xf500)
-
-#define TX4927_IR_INT(n)	(2 + (n))
-#define TX4927_IR_SIO(n)	(8 + (n))
-#define TX4927_IR_PCIC		16
-#define TX4927_NUM_IR_TMR	3
-#define TX4927_IR_TMR(n)	(17 + (n))
-#define TX4927_IR_PCIERR	22
-#define TX4927_NUM_IR	32
-
-#define TX4927_IRC_INT	2	/* IP[2] in Status register */
-
-#define TX4927_NUM_PIO	16
-
-struct tx4927_sdramc_reg {
-	u64 cr[4];
-	u64 unused0[4];
-	u64 tr;
-	u64 unused1[2];
-	u64 cmd;
-};
-
-struct tx4927_ebusc_reg {
-	u64 cr[8];
-};
-
-struct tx4927_ccfg_reg {
-	u64 ccfg;
-	u64 crir;
-	u64 pcfg;
-	u64 toea;
-	u64 clkctr;
-	u64 unused0;
-	u64 garbc;
-	u64 unused1;
-	u64 unused2;
-	u64 ramp;
-};
-
-/*
- * CCFG
- */
-/* CCFG : Chip Configuration */
-#define TX4927_CCFG_WDRST	0x0000020000000000ULL
-#define TX4927_CCFG_WDREXEN	0x0000010000000000ULL
-#define TX4927_CCFG_BCFG_MASK	0x000000ff00000000ULL
-#define TX4927_CCFG_TINTDIS	0x01000000
-#define TX4927_CCFG_PCI66	0x00800000
-#define TX4927_CCFG_PCIMODE	0x00400000
-#define TX4927_CCFG_DIVMODE_MASK	0x000e0000
-#define TX4927_CCFG_DIVMODE_8	(0x0 << 17)
-#define TX4927_CCFG_DIVMODE_12	(0x1 << 17)
-#define TX4927_CCFG_DIVMODE_16	(0x2 << 17)
-#define TX4927_CCFG_DIVMODE_10	(0x3 << 17)
-#define TX4927_CCFG_DIVMODE_2	(0x4 << 17)
-#define TX4927_CCFG_DIVMODE_3	(0x5 << 17)
-#define TX4927_CCFG_DIVMODE_4	(0x6 << 17)
-#define TX4927_CCFG_DIVMODE_2_5	(0x7 << 17)
-#define TX4927_CCFG_BEOW	0x00010000
-#define TX4927_CCFG_WR	0x00008000
-#define TX4927_CCFG_TOE	0x00004000
-#define TX4927_CCFG_PCIARB	0x00002000
-#define TX4927_CCFG_PCIDIVMODE_MASK	0x00001800
-#define TX4927_CCFG_PCIDIVMODE_2_5	0x00000000
-#define TX4927_CCFG_PCIDIVMODE_3	0x00000800
-#define TX4927_CCFG_PCIDIVMODE_5	0x00001000
-#define TX4927_CCFG_PCIDIVMODE_6	0x00001800
-#define TX4927_CCFG_SYSSP_MASK	0x000000c0
-#define TX4927_CCFG_ENDIAN	0x00000004
-#define TX4927_CCFG_HALT	0x00000002
-#define TX4927_CCFG_ACEHOLD	0x00000001
-#define TX4927_CCFG_W1CBITS	(TX4927_CCFG_WDRST | TX4927_CCFG_BEOW)
-
-/* PCFG : Pin Configuration */
-#define TX4927_PCFG_SDCLKDLY_MASK	0x30000000
-#define TX4927_PCFG_SDCLKDLY(d)	((d)<<28)
-#define TX4927_PCFG_SYSCLKEN	0x08000000
-#define TX4927_PCFG_SDCLKEN_ALL	0x07800000
-#define TX4927_PCFG_SDCLKEN(ch)	(0x00800000<<(ch))
-#define TX4927_PCFG_PCICLKEN_ALL	0x003f0000
-#define TX4927_PCFG_PCICLKEN(ch)	(0x00010000<<(ch))
-#define TX4927_PCFG_SEL2	0x00000200
-#define TX4927_PCFG_SEL1	0x00000100
-#define TX4927_PCFG_DMASEL_ALL	0x000000ff
-#define TX4927_PCFG_DMASEL0_MASK	0x00000003
-#define TX4927_PCFG_DMASEL1_MASK	0x0000000c
-#define TX4927_PCFG_DMASEL2_MASK	0x00000030
-#define TX4927_PCFG_DMASEL3_MASK	0x000000c0
-#define TX4927_PCFG_DMASEL0_DRQ0	0x00000000
-#define TX4927_PCFG_DMASEL0_SIO1	0x00000001
-#define TX4927_PCFG_DMASEL0_ACL0	0x00000002
-#define TX4927_PCFG_DMASEL0_ACL2	0x00000003
-#define TX4927_PCFG_DMASEL1_DRQ1	0x00000000
-#define TX4927_PCFG_DMASEL1_SIO1	0x00000004
-#define TX4927_PCFG_DMASEL1_ACL1	0x00000008
-#define TX4927_PCFG_DMASEL1_ACL3	0x0000000c
-#define TX4927_PCFG_DMASEL2_DRQ2	0x00000000	/* SEL2=0 */
-#define TX4927_PCFG_DMASEL2_SIO0	0x00000010	/* SEL2=0 */
-#define TX4927_PCFG_DMASEL2_ACL1	0x00000000	/* SEL2=1 */
-#define TX4927_PCFG_DMASEL2_ACL2	0x00000020	/* SEL2=1 */
-#define TX4927_PCFG_DMASEL2_ACL0	0x00000030	/* SEL2=1 */
-#define TX4927_PCFG_DMASEL3_DRQ3	0x00000000
-#define TX4927_PCFG_DMASEL3_SIO0	0x00000040
-#define TX4927_PCFG_DMASEL3_ACL3	0x00000080
-#define TX4927_PCFG_DMASEL3_ACL1	0x000000c0
-
-/* CLKCTR : Clock Control */
-#define TX4927_CLKCTR_ACLCKD	0x02000000
-#define TX4927_CLKCTR_PIOCKD	0x01000000
-#define TX4927_CLKCTR_DMACKD	0x00800000
-#define TX4927_CLKCTR_PCICKD	0x00400000
-#define TX4927_CLKCTR_TM0CKD	0x00100000
-#define TX4927_CLKCTR_TM1CKD	0x00080000
-#define TX4927_CLKCTR_TM2CKD	0x00040000
-#define TX4927_CLKCTR_SIO0CKD	0x00020000
-#define TX4927_CLKCTR_SIO1CKD	0x00010000
-#define TX4927_CLKCTR_ACLRST	0x00000200
-#define TX4927_CLKCTR_PIORST	0x00000100
-#define TX4927_CLKCTR_DMARST	0x00000080
-#define TX4927_CLKCTR_PCIRST	0x00000040
-#define TX4927_CLKCTR_TM0RST	0x00000010
-#define TX4927_CLKCTR_TM1RST	0x00000008
-#define TX4927_CLKCTR_TM2RST	0x00000004
-#define TX4927_CLKCTR_SIO0RST	0x00000002
-#define TX4927_CLKCTR_SIO1RST	0x00000001
-
-#define tx4927_sdramcptr \
-		((struct tx4927_sdramc_reg __iomem *)TX4927_SDRAMC_REG)
-#define tx4927_pcicptr \
-		((struct tx4927_pcic_reg __iomem *)TX4927_PCIC_REG)
-#define tx4927_ccfgptr \
-		((struct tx4927_ccfg_reg __iomem *)TX4927_CCFG_REG)
-#define tx4927_ebuscptr \
-		((struct tx4927_ebusc_reg __iomem *)TX4927_EBUSC_REG)
-#define tx4927_pioptr		((struct txx9_pio_reg __iomem *)TX4927_PIO_REG)
-
-#define TX4927_REV_PCODE()	\
-	((__u32)__raw_readq(&tx4927_ccfgptr->crir) >> 16)
-
-#define TX4927_SDRAMC_CR(ch)	__raw_readq(&tx4927_sdramcptr->cr[(ch)])
-#define TX4927_SDRAMC_BA(ch)	((TX4927_SDRAMC_CR(ch) >> 49) << 21)
-#define TX4927_SDRAMC_SIZE(ch)	\
-	((((TX4927_SDRAMC_CR(ch) >> 33) & 0x7fff) + 1) << 21)
-
-#define TX4927_EBUSC_CR(ch)	__raw_readq(&tx4927_ebuscptr->cr[(ch)])
-#define TX4927_EBUSC_BA(ch)	((TX4927_EBUSC_CR(ch) >> 48) << 20)
-#define TX4927_EBUSC_SIZE(ch)	\
-	(0x00100000 << ((unsigned long)(TX4927_EBUSC_CR(ch) >> 8) & 0xf))
-
-/* utilities */
-static inline void txx9_clear64(__u64 __iomem *adr, __u64 bits)
-{
-#ifdef CONFIG_32BIT
-	unsigned long flags;
-	local_irq_save(flags);
-#endif
-	____raw_writeq(____raw_readq(adr) & ~bits, adr);
-#ifdef CONFIG_32BIT
-	local_irq_restore(flags);
-#endif
-}
-static inline void txx9_set64(__u64 __iomem *adr, __u64 bits)
-{
-#ifdef CONFIG_32BIT
-	unsigned long flags;
-	local_irq_save(flags);
-#endif
-	____raw_writeq(____raw_readq(adr) | bits, adr);
-#ifdef CONFIG_32BIT
-	local_irq_restore(flags);
-#endif
-}
-
-/* These functions are not interrupt safe. */
-static inline void tx4927_ccfg_clear(__u64 bits)
-{
-	____raw_writeq(____raw_readq(&tx4927_ccfgptr->ccfg)
-		       & ~(TX4927_CCFG_W1CBITS | bits),
-		       &tx4927_ccfgptr->ccfg);
-}
-static inline void tx4927_ccfg_set(__u64 bits)
-{
-	____raw_writeq((____raw_readq(&tx4927_ccfgptr->ccfg)
-			& ~TX4927_CCFG_W1CBITS) | bits,
-		       &tx4927_ccfgptr->ccfg);
-}
-static inline void tx4927_ccfg_change(__u64 change, __u64 new)
-{
-	____raw_writeq((____raw_readq(&tx4927_ccfgptr->ccfg)
-			& ~(TX4927_CCFG_W1CBITS | change)) |
-		       new,
-		       &tx4927_ccfgptr->ccfg);
-}
-
-unsigned int tx4927_get_mem_size(void);
-void tx4927_wdt_init(void);
-void tx4927_setup(void);
-void tx4927_time_init(unsigned int tmrnr);
-void tx4927_sio_init(unsigned int sclk, unsigned int cts_mask);
-int tx4927_report_pciclk(void);
-int tx4927_pciclk66_setup(void);
-void tx4927_setup_pcierr_irq(void);
-void tx4927_irq_init(void);
-
-#endif /* __ASM_TXX9_TX4927_H */
diff --git a/include/asm-mips/txx9/tx4938.h b/include/asm-mips/txx9/tx4938.h
deleted file mode 100644
index 8175d4c..0000000
--- a/include/asm-mips/txx9/tx4938.h
+++ /dev/null
@@ -1,293 +0,0 @@
-/*
- * Definitions for TX4937/TX4938
- * Copyright (C) 2000-2001 Toshiba Corporation
- *
- * 2003-2005 (c) MontaVista Software, Inc. This file is licensed under the
- * terms of the GNU General Public License version 2. This program is
- * licensed "as is" without any warranty of any kind, whether express
- * or implied.
- *
- * Support for TX4938 in 2.6 - Manish Lachwani (mlachwani@mvista.com)
- */
-#ifndef __ASM_TXX9_TX4938_H
-#define __ASM_TXX9_TX4938_H
-
-/* some controllers are compatible with 4927 */
-#include <asm/txx9/tx4927.h>
-
-#ifdef CONFIG_64BIT
-#define TX4938_REG_BASE	0xffffffffff1f0000UL /* == TX4937_REG_BASE */
-#else
-#define TX4938_REG_BASE	0xff1f0000UL /* == TX4937_REG_BASE */
-#endif
-#define TX4938_REG_SIZE	0x00010000 /* == TX4937_REG_SIZE */
-
-/* NDFMC, SRAMC, PCIC1, SPIC: TX4938 only */
-#define TX4938_NDFMC_REG	(TX4938_REG_BASE + 0x5000)
-#define TX4938_SRAMC_REG	(TX4938_REG_BASE + 0x6000)
-#define TX4938_PCIC1_REG	(TX4938_REG_BASE + 0x7000)
-#define TX4938_SDRAMC_REG	(TX4938_REG_BASE + 0x8000)
-#define TX4938_EBUSC_REG	(TX4938_REG_BASE + 0x9000)
-#define TX4938_DMA_REG(ch)	(TX4938_REG_BASE + 0xb000 + (ch) * 0x800)
-#define TX4938_PCIC_REG		(TX4938_REG_BASE + 0xd000)
-#define TX4938_CCFG_REG		(TX4938_REG_BASE + 0xe000)
-#define TX4938_NR_TMR	3
-#define TX4938_TMR_REG(ch)	((TX4938_REG_BASE + 0xf000) + (ch) * 0x100)
-#define TX4938_NR_SIO	2
-#define TX4938_SIO_REG(ch)	((TX4938_REG_BASE + 0xf300) + (ch) * 0x100)
-#define TX4938_PIO_REG		(TX4938_REG_BASE + 0xf500)
-#define TX4938_IRC_REG		(TX4938_REG_BASE + 0xf600)
-#define TX4938_ACLC_REG		(TX4938_REG_BASE + 0xf700)
-#define TX4938_SPI_REG		(TX4938_REG_BASE + 0xf800)
-
-struct tx4938_sramc_reg {
-	u64 cr;
-};
-
-struct tx4938_ccfg_reg {
-	u64 ccfg;
-	u64 crir;
-	u64 pcfg;
-	u64 toea;
-	u64 clkctr;
-	u64 unused0;
-	u64 garbc;
-	u64 unused1;
-	u64 unused2;
-	u64 ramp;
-	u64 unused3;
-	u64 jmpadr;
-};
-
-/*
- * IRC
- */
-
-#define TX4938_IR_ECCERR	0
-#define TX4938_IR_WTOERR	1
-#define TX4938_NUM_IR_INT	6
-#define TX4938_IR_INT(n)	(2 + (n))
-#define TX4938_NUM_IR_SIO	2
-#define TX4938_IR_SIO(n)	(8 + (n))
-#define TX4938_NUM_IR_DMA	4
-#define TX4938_IR_DMA(ch, n)	((ch ? 27 : 10) + (n)) /* 10-13, 27-30 */
-#define TX4938_IR_PIO	14
-#define TX4938_IR_PDMAC	15
-#define TX4938_IR_PCIC	16
-#define TX4938_NUM_IR_TMR	3
-#define TX4938_IR_TMR(n)	(17 + (n))
-#define TX4938_IR_NDFMC	21
-#define TX4938_IR_PCIERR	22
-#define TX4938_IR_PCIPME	23
-#define TX4938_IR_ACLC	24
-#define TX4938_IR_ACLCPME	25
-#define TX4938_IR_PCIC1	26
-#define TX4938_IR_SPI	31
-#define TX4938_NUM_IR	32
-/* multiplex */
-#define TX4938_IR_ETH0	TX4938_IR_INT(4)
-#define TX4938_IR_ETH1	TX4938_IR_INT(3)
-
-#define TX4938_IRC_INT	2	/* IP[2] in Status register */
-
-#define TX4938_NUM_PIO	16
-
-/*
- * CCFG
- */
-/* CCFG : Chip Configuration */
-#define TX4938_CCFG_WDRST	0x0000020000000000ULL
-#define TX4938_CCFG_WDREXEN	0x0000010000000000ULL
-#define TX4938_CCFG_BCFG_MASK	0x000000ff00000000ULL
-#define TX4938_CCFG_TINTDIS	0x01000000
-#define TX4938_CCFG_PCI66	0x00800000
-#define TX4938_CCFG_PCIMODE	0x00400000
-#define TX4938_CCFG_PCI1_66	0x00200000
-#define TX4938_CCFG_DIVMODE_MASK	0x001e0000
-#define TX4938_CCFG_DIVMODE_2	(0x4 << 17)
-#define TX4938_CCFG_DIVMODE_2_5	(0xf << 17)
-#define TX4938_CCFG_DIVMODE_3	(0x5 << 17)
-#define TX4938_CCFG_DIVMODE_4	(0x6 << 17)
-#define TX4938_CCFG_DIVMODE_4_5	(0xd << 17)
-#define TX4938_CCFG_DIVMODE_8	(0x0 << 17)
-#define TX4938_CCFG_DIVMODE_10	(0xb << 17)
-#define TX4938_CCFG_DIVMODE_12	(0x1 << 17)
-#define TX4938_CCFG_DIVMODE_16	(0x2 << 17)
-#define TX4938_CCFG_DIVMODE_18	(0x9 << 17)
-#define TX4938_CCFG_BEOW	0x00010000
-#define TX4938_CCFG_WR	0x00008000
-#define TX4938_CCFG_TOE	0x00004000
-#define TX4938_CCFG_PCIARB	0x00002000
-#define TX4938_CCFG_PCIDIVMODE_MASK	0x00001c00
-#define TX4938_CCFG_PCIDIVMODE_4	(0x1 << 10)
-#define TX4938_CCFG_PCIDIVMODE_4_5	(0x3 << 10)
-#define TX4938_CCFG_PCIDIVMODE_5	(0x5 << 10)
-#define TX4938_CCFG_PCIDIVMODE_5_5	(0x7 << 10)
-#define TX4938_CCFG_PCIDIVMODE_8	(0x0 << 10)
-#define TX4938_CCFG_PCIDIVMODE_9	(0x2 << 10)
-#define TX4938_CCFG_PCIDIVMODE_10	(0x4 << 10)
-#define TX4938_CCFG_PCIDIVMODE_11	(0x6 << 10)
-#define TX4938_CCFG_PCI1DMD	0x00000100
-#define TX4938_CCFG_SYSSP_MASK	0x000000c0
-#define TX4938_CCFG_ENDIAN	0x00000004
-#define TX4938_CCFG_HALT	0x00000002
-#define TX4938_CCFG_ACEHOLD	0x00000001
-
-/* PCFG : Pin Configuration */
-#define TX4938_PCFG_ETH0_SEL	0x8000000000000000ULL
-#define TX4938_PCFG_ETH1_SEL	0x4000000000000000ULL
-#define TX4938_PCFG_ATA_SEL	0x2000000000000000ULL
-#define TX4938_PCFG_ISA_SEL	0x1000000000000000ULL
-#define TX4938_PCFG_SPI_SEL	0x0800000000000000ULL
-#define TX4938_PCFG_NDF_SEL	0x0400000000000000ULL
-#define TX4938_PCFG_SDCLKDLY_MASK	0x30000000
-#define TX4938_PCFG_SDCLKDLY(d)	((d)<<28)
-#define TX4938_PCFG_SYSCLKEN	0x08000000
-#define TX4938_PCFG_SDCLKEN_ALL	0x07800000
-#define TX4938_PCFG_SDCLKEN(ch)	(0x00800000<<(ch))
-#define TX4938_PCFG_PCICLKEN_ALL	0x003f0000
-#define TX4938_PCFG_PCICLKEN(ch)	(0x00010000<<(ch))
-#define TX4938_PCFG_SEL2	0x00000200
-#define TX4938_PCFG_SEL1	0x00000100
-#define TX4938_PCFG_DMASEL_ALL	0x0000000f
-#define TX4938_PCFG_DMASEL0_DRQ0	0x00000000
-#define TX4938_PCFG_DMASEL0_SIO1	0x00000001
-#define TX4938_PCFG_DMASEL1_DRQ1	0x00000000
-#define TX4938_PCFG_DMASEL1_SIO1	0x00000002
-#define TX4938_PCFG_DMASEL2_DRQ2	0x00000000
-#define TX4938_PCFG_DMASEL2_SIO0	0x00000004
-#define TX4938_PCFG_DMASEL3_DRQ3	0x00000000
-#define TX4938_PCFG_DMASEL3_SIO0	0x00000008
-
-/* CLKCTR : Clock Control */
-#define TX4938_CLKCTR_NDFCKD	0x0001000000000000ULL
-#define TX4938_CLKCTR_NDFRST	0x0000000100000000ULL
-#define TX4938_CLKCTR_ETH1CKD	0x80000000
-#define TX4938_CLKCTR_ETH0CKD	0x40000000
-#define TX4938_CLKCTR_SPICKD	0x20000000
-#define TX4938_CLKCTR_SRAMCKD	0x10000000
-#define TX4938_CLKCTR_PCIC1CKD	0x08000000
-#define TX4938_CLKCTR_DMA1CKD	0x04000000
-#define TX4938_CLKCTR_ACLCKD	0x02000000
-#define TX4938_CLKCTR_PIOCKD	0x01000000
-#define TX4938_CLKCTR_DMACKD	0x00800000
-#define TX4938_CLKCTR_PCICKD	0x00400000
-#define TX4938_CLKCTR_TM0CKD	0x00100000
-#define TX4938_CLKCTR_TM1CKD	0x00080000
-#define TX4938_CLKCTR_TM2CKD	0x00040000
-#define TX4938_CLKCTR_SIO0CKD	0x00020000
-#define TX4938_CLKCTR_SIO1CKD	0x00010000
-#define TX4938_CLKCTR_ETH1RST	0x00008000
-#define TX4938_CLKCTR_ETH0RST	0x00004000
-#define TX4938_CLKCTR_SPIRST	0x00002000
-#define TX4938_CLKCTR_SRAMRST	0x00001000
-#define TX4938_CLKCTR_PCIC1RST	0x00000800
-#define TX4938_CLKCTR_DMA1RST	0x00000400
-#define TX4938_CLKCTR_ACLRST	0x00000200
-#define TX4938_CLKCTR_PIORST	0x00000100
-#define TX4938_CLKCTR_DMARST	0x00000080
-#define TX4938_CLKCTR_PCIRST	0x00000040
-#define TX4938_CLKCTR_TM0RST	0x00000010
-#define TX4938_CLKCTR_TM1RST	0x00000008
-#define TX4938_CLKCTR_TM2RST	0x00000004
-#define TX4938_CLKCTR_SIO0RST	0x00000002
-#define TX4938_CLKCTR_SIO1RST	0x00000001
-
-/*
- * DMA
- */
-/* bits for MCR */
-#define TX4938_DMA_MCR_EIS(ch)	(0x10000000<<(ch))
-#define TX4938_DMA_MCR_DIS(ch)	(0x01000000<<(ch))
-#define TX4938_DMA_MCR_RSFIF	0x00000080
-#define TX4938_DMA_MCR_FIFUM(ch)	(0x00000008<<(ch))
-#define TX4938_DMA_MCR_RPRT	0x00000002
-#define TX4938_DMA_MCR_MSTEN	0x00000001
-
-/* bits for CCRn */
-#define TX4938_DMA_CCR_IMMCHN	0x20000000
-#define TX4938_DMA_CCR_USEXFSZ	0x10000000
-#define TX4938_DMA_CCR_LE	0x08000000
-#define TX4938_DMA_CCR_DBINH	0x04000000
-#define TX4938_DMA_CCR_SBINH	0x02000000
-#define TX4938_DMA_CCR_CHRST	0x01000000
-#define TX4938_DMA_CCR_RVBYTE	0x00800000
-#define TX4938_DMA_CCR_ACKPOL	0x00400000
-#define TX4938_DMA_CCR_REQPL	0x00200000
-#define TX4938_DMA_CCR_EGREQ	0x00100000
-#define TX4938_DMA_CCR_CHDN	0x00080000
-#define TX4938_DMA_CCR_DNCTL	0x00060000
-#define TX4938_DMA_CCR_EXTRQ	0x00010000
-#define TX4938_DMA_CCR_INTRQD	0x0000e000
-#define TX4938_DMA_CCR_INTENE	0x00001000
-#define TX4938_DMA_CCR_INTENC	0x00000800
-#define TX4938_DMA_CCR_INTENT	0x00000400
-#define TX4938_DMA_CCR_CHNEN	0x00000200
-#define TX4938_DMA_CCR_XFACT	0x00000100
-#define TX4938_DMA_CCR_SMPCHN	0x00000020
-#define TX4938_DMA_CCR_XFSZ(order)	(((order) << 2) & 0x0000001c)
-#define TX4938_DMA_CCR_XFSZ_1W	TX4938_DMA_CCR_XFSZ(2)
-#define TX4938_DMA_CCR_XFSZ_2W	TX4938_DMA_CCR_XFSZ(3)
-#define TX4938_DMA_CCR_XFSZ_4W	TX4938_DMA_CCR_XFSZ(4)
-#define TX4938_DMA_CCR_XFSZ_8W	TX4938_DMA_CCR_XFSZ(5)
-#define TX4938_DMA_CCR_XFSZ_16W	TX4938_DMA_CCR_XFSZ(6)
-#define TX4938_DMA_CCR_XFSZ_32W	TX4938_DMA_CCR_XFSZ(7)
-#define TX4938_DMA_CCR_MEMIO	0x00000002
-#define TX4938_DMA_CCR_SNGAD	0x00000001
-
-/* bits for CSRn */
-#define TX4938_DMA_CSR_CHNEN	0x00000400
-#define TX4938_DMA_CSR_STLXFER	0x00000200
-#define TX4938_DMA_CSR_CHNACT	0x00000100
-#define TX4938_DMA_CSR_ABCHC	0x00000080
-#define TX4938_DMA_CSR_NCHNC	0x00000040
-#define TX4938_DMA_CSR_NTRNFC	0x00000020
-#define TX4938_DMA_CSR_EXTDN	0x00000010
-#define TX4938_DMA_CSR_CFERR	0x00000008
-#define TX4938_DMA_CSR_CHERR	0x00000004
-#define TX4938_DMA_CSR_DESERR	0x00000002
-#define TX4938_DMA_CSR_SORERR	0x00000001
-
-#define tx4938_sdramcptr	tx4927_sdramcptr
-#define tx4938_ebuscptr		tx4927_ebuscptr
-#define tx4938_pcicptr		tx4927_pcicptr
-#define tx4938_pcic1ptr \
-		((struct tx4927_pcic_reg __iomem *)TX4938_PCIC1_REG)
-#define tx4938_ccfgptr \
-		((struct tx4938_ccfg_reg __iomem *)TX4938_CCFG_REG)
-#define tx4938_pioptr		((struct txx9_pio_reg __iomem *)TX4938_PIO_REG)
-#define tx4938_sramcptr \
-		((struct tx4938_sramc_reg __iomem *)TX4938_SRAMC_REG)
-
-
-#define TX4938_REV_PCODE()	\
-	((__u32)__raw_readq(&tx4938_ccfgptr->crir) >> 16)
-
-#define tx4938_ccfg_clear(bits)	tx4927_ccfg_clear(bits)
-#define tx4938_ccfg_set(bits)	tx4927_ccfg_set(bits)
-#define tx4938_ccfg_change(change, new)	tx4927_ccfg_change(change, new)
-
-#define TX4938_SDRAMC_CR(ch)	TX4927_SDRAMC_CR(ch)
-#define TX4938_SDRAMC_BA(ch)	TX4927_SDRAMC_BA(ch)
-#define TX4938_SDRAMC_SIZE(ch)	TX4927_SDRAMC_SIZE(ch)
-
-#define TX4938_EBUSC_CR(ch)	TX4927_EBUSC_CR(ch)
-#define TX4938_EBUSC_BA(ch)	TX4927_EBUSC_BA(ch)
-#define TX4938_EBUSC_SIZE(ch)	TX4927_EBUSC_SIZE(ch)
-
-#define tx4938_get_mem_size() tx4927_get_mem_size()
-void tx4938_wdt_init(void);
-void tx4938_setup(void);
-void tx4938_time_init(unsigned int tmrnr);
-void tx4938_sio_init(unsigned int sclk, unsigned int cts_mask);
-void tx4938_spi_init(int busid);
-void tx4938_ethaddr_init(unsigned char *addr0, unsigned char *addr1);
-int tx4938_report_pciclk(void);
-void tx4938_report_pci1clk(void);
-int tx4938_pciclk66_setup(void);
-struct pci_dev;
-int tx4938_pcic1_map_irq(const struct pci_dev *dev, u8 slot);
-void tx4938_setup_pcierr_irq(void);
-void tx4938_irq_init(void);
-
-#endif
diff --git a/include/asm-mips/uaccess.h b/include/asm-mips/uaccess.h
deleted file mode 100644
index 66523d6..0000000
--- a/include/asm-mips/uaccess.h
+++ /dev/null
@@ -1,852 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 1996, 1997, 1998, 1999, 2000, 03, 04 by Ralf Baechle
- * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
- * Copyright (C) 2007  Maciej W. Rozycki
- */
-#ifndef _ASM_UACCESS_H
-#define _ASM_UACCESS_H
-
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/thread_info.h>
-#include <asm-generic/uaccess.h>
-
-/*
- * The fs value determines whether argument validity checking should be
- * performed or not.  If get_fs() == USER_DS, checking is performed, with
- * get_fs() == KERNEL_DS, checking is bypassed.
- *
- * For historical reasons, these macros are grossly misnamed.
- */
-#ifdef CONFIG_32BIT
-
-#define __UA_LIMIT	0x80000000UL
-
-#define __UA_ADDR	".word"
-#define __UA_LA		"la"
-#define __UA_ADDU	"addu"
-#define __UA_t0		"$8"
-#define __UA_t1		"$9"
-
-#endif /* CONFIG_32BIT */
-
-#ifdef CONFIG_64BIT
-
-#define __UA_LIMIT	(- TASK_SIZE)
-
-#define __UA_ADDR	".dword"
-#define __UA_LA		"dla"
-#define __UA_ADDU	"daddu"
-#define __UA_t0		"$12"
-#define __UA_t1		"$13"
-
-#endif /* CONFIG_64BIT */
-
-/*
- * USER_DS is a bitmask that has the bits set that may not be set in a valid
- * userspace address.  Note that we limit 32-bit userspace to 0x7fff8000 but
- * the arithmetic we're doing only works if the limit is a power of two, so
- * we use 0x80000000 here on 32-bit kernels.  If a process passes an invalid
- * address in this range it's the process's problem, not ours :-)
- */
-
-#define KERNEL_DS	((mm_segment_t) { 0UL })
-#define USER_DS		((mm_segment_t) { __UA_LIMIT })
-
-#define VERIFY_READ    0
-#define VERIFY_WRITE   1
-
-#define get_ds()	(KERNEL_DS)
-#define get_fs()	(current_thread_info()->addr_limit)
-#define set_fs(x)	(current_thread_info()->addr_limit = (x))
-
-#define segment_eq(a, b)	((a).seg == (b).seg)
-
-
-/*
- * Is a address valid? This does a straighforward calculation rather
- * than tests.
- *
- * Address valid if:
- *  - "addr" doesn't have any high-bits set
- *  - AND "size" doesn't have any high-bits set
- *  - AND "addr+size" doesn't have any high-bits set
- *  - OR we are in kernel mode.
- *
- * __ua_size() is a trick to avoid runtime checking of positive constant
- * sizes; for those we already know at compile time that the size is ok.
- */
-#define __ua_size(size)							\
-	((__builtin_constant_p(size) && (signed long) (size) > 0) ? 0 : (size))
-
-/*
- * access_ok: - Checks if a user space pointer is valid
- * @type: Type of access: %VERIFY_READ or %VERIFY_WRITE.  Note that
- *        %VERIFY_WRITE is a superset of %VERIFY_READ - if it is safe
- *        to write to a block, it is always safe to read from it.
- * @addr: User space pointer to start of block to check
- * @size: Size of block to check
- *
- * Context: User context only.  This function may sleep.
- *
- * Checks if a pointer to a block of memory in user space is valid.
- *
- * Returns true (nonzero) if the memory block may be valid, false (zero)
- * if it is definitely invalid.
- *
- * Note that, depending on architecture, this function probably just
- * checks that the pointer is in the user space range - after calling
- * this function, memory access functions may still return -EFAULT.
- */
-
-#define __access_mask get_fs().seg
-
-#define __access_ok(addr, size, mask)					\
-	(((signed long)((mask) & ((addr) | ((addr) + (size)) | __ua_size(size)))) == 0)
-
-#define access_ok(type, addr, size)					\
-	likely(__access_ok((unsigned long)(addr), (size), __access_mask))
-
-/*
- * put_user: - Write a simple value into user space.
- * @x:   Value to copy to user space.
- * @ptr: Destination address, in user space.
- *
- * Context: User context only.  This function may sleep.
- *
- * This macro copies a single simple value from kernel space to user
- * space.  It supports simple types like char and int, but not larger
- * data types like structures or arrays.
- *
- * @ptr must have pointer-to-simple-variable type, and @x must be assignable
- * to the result of dereferencing @ptr.
- *
- * Returns zero on success, or -EFAULT on error.
- */
-#define put_user(x,ptr)	\
-	__put_user_check((x), (ptr), sizeof(*(ptr)))
-
-/*
- * get_user: - Get a simple variable from user space.
- * @x:   Variable to store result.
- * @ptr: Source address, in user space.
- *
- * Context: User context only.  This function may sleep.
- *
- * This macro copies a single simple variable from user space to kernel
- * space.  It supports simple types like char and int, but not larger
- * data types like structures or arrays.
- *
- * @ptr must have pointer-to-simple-variable type, and the result of
- * dereferencing @ptr must be assignable to @x without a cast.
- *
- * Returns zero on success, or -EFAULT on error.
- * On error, the variable @x is set to zero.
- */
-#define get_user(x,ptr) \
-	__get_user_check((x), (ptr), sizeof(*(ptr)))
-
-/*
- * __put_user: - Write a simple value into user space, with less checking.
- * @x:   Value to copy to user space.
- * @ptr: Destination address, in user space.
- *
- * Context: User context only.  This function may sleep.
- *
- * This macro copies a single simple value from kernel space to user
- * space.  It supports simple types like char and int, but not larger
- * data types like structures or arrays.
- *
- * @ptr must have pointer-to-simple-variable type, and @x must be assignable
- * to the result of dereferencing @ptr.
- *
- * Caller must check the pointer with access_ok() before calling this
- * function.
- *
- * Returns zero on success, or -EFAULT on error.
- */
-#define __put_user(x,ptr) \
-	__put_user_nocheck((x), (ptr), sizeof(*(ptr)))
-
-/*
- * __get_user: - Get a simple variable from user space, with less checking.
- * @x:   Variable to store result.
- * @ptr: Source address, in user space.
- *
- * Context: User context only.  This function may sleep.
- *
- * This macro copies a single simple variable from user space to kernel
- * space.  It supports simple types like char and int, but not larger
- * data types like structures or arrays.
- *
- * @ptr must have pointer-to-simple-variable type, and the result of
- * dereferencing @ptr must be assignable to @x without a cast.
- *
- * Caller must check the pointer with access_ok() before calling this
- * function.
- *
- * Returns zero on success, or -EFAULT on error.
- * On error, the variable @x is set to zero.
- */
-#define __get_user(x,ptr) \
-	__get_user_nocheck((x), (ptr), sizeof(*(ptr)))
-
-struct __large_struct { unsigned long buf[100]; };
-#define __m(x) (*(struct __large_struct __user *)(x))
-
-/*
- * Yuck.  We need two variants, one for 64bit operation and one
- * for 32 bit mode and old iron.
- */
-#ifdef CONFIG_32BIT
-#define __GET_USER_DW(val, ptr) __get_user_asm_ll32(val, ptr)
-#endif
-#ifdef CONFIG_64BIT
-#define __GET_USER_DW(val, ptr) __get_user_asm(val, "ld", ptr)
-#endif
-
-extern void __get_user_unknown(void);
-
-#define __get_user_common(val, size, ptr)				\
-do {									\
-	switch (size) {							\
-	case 1: __get_user_asm(val, "lb", ptr); break;			\
-	case 2: __get_user_asm(val, "lh", ptr); break;			\
-	case 4: __get_user_asm(val, "lw", ptr); break;			\
-	case 8: __GET_USER_DW(val, ptr); break;				\
-	default: __get_user_unknown(); break;				\
-	}								\
-} while (0)
-
-#define __get_user_nocheck(x, ptr, size)				\
-({									\
-	long __gu_err;							\
-									\
-	__get_user_common((x), size, ptr);				\
-	__gu_err;							\
-})
-
-#define __get_user_check(x, ptr, size)					\
-({									\
-	long __gu_err = -EFAULT;					\
-	const __typeof__(*(ptr)) __user * __gu_ptr = (ptr);		\
-									\
-	if (likely(access_ok(VERIFY_READ,  __gu_ptr, size)))		\
-		__get_user_common((x), size, __gu_ptr);			\
-									\
-	__gu_err;							\
-})
-
-#define __get_user_asm(val, insn, addr)					\
-{									\
-	long __gu_tmp;							\
-									\
-	__asm__ __volatile__(						\
-	"1:	" insn "	%1, %3				\n"	\
-	"2:							\n"	\
-	"	.section .fixup,\"ax\"				\n"	\
-	"3:	li	%0, %4					\n"	\
-	"	j	2b					\n"	\
-	"	.previous					\n"	\
-	"	.section __ex_table,\"a\"			\n"	\
-	"	"__UA_ADDR "\t1b, 3b				\n"	\
-	"	.previous					\n"	\
-	: "=r" (__gu_err), "=r" (__gu_tmp)				\
-	: "0" (0), "o" (__m(addr)), "i" (-EFAULT));			\
-									\
-	(val) = (__typeof__(*(addr))) __gu_tmp;				\
-}
-
-/*
- * Get a long long 64 using 32 bit registers.
- */
-#define __get_user_asm_ll32(val, addr)					\
-{									\
-	union {								\
-		unsigned long long	l;				\
-		__typeof__(*(addr))	t;				\
-	} __gu_tmp;							\
-									\
-	__asm__ __volatile__(						\
-	"1:	lw	%1, (%3)				\n"	\
-	"2:	lw	%D1, 4(%3)				\n"	\
-	"3:	.section	.fixup,\"ax\"			\n"	\
-	"4:	li	%0, %4					\n"	\
-	"	move	%1, $0					\n"	\
-	"	move	%D1, $0					\n"	\
-	"	j	3b					\n"	\
-	"	.previous					\n"	\
-	"	.section	__ex_table,\"a\"		\n"	\
-	"	" __UA_ADDR "	1b, 4b				\n"	\
-	"	" __UA_ADDR "	2b, 4b				\n"	\
-	"	.previous					\n"	\
-	: "=r" (__gu_err), "=&r" (__gu_tmp.l)				\
-	: "0" (0), "r" (addr), "i" (-EFAULT));				\
-									\
-	(val) = __gu_tmp.t;						\
-}
-
-/*
- * Yuck.  We need two variants, one for 64bit operation and one
- * for 32 bit mode and old iron.
- */
-#ifdef CONFIG_32BIT
-#define __PUT_USER_DW(ptr) __put_user_asm_ll32(ptr)
-#endif
-#ifdef CONFIG_64BIT
-#define __PUT_USER_DW(ptr) __put_user_asm("sd", ptr)
-#endif
-
-#define __put_user_nocheck(x, ptr, size)				\
-({									\
-	__typeof__(*(ptr)) __pu_val;					\
-	long __pu_err = 0;						\
-									\
-	__pu_val = (x);							\
-	switch (size) {							\
-	case 1: __put_user_asm("sb", ptr); break;			\
-	case 2: __put_user_asm("sh", ptr); break;			\
-	case 4: __put_user_asm("sw", ptr); break;			\
-	case 8: __PUT_USER_DW(ptr); break;				\
-	default: __put_user_unknown(); break;				\
-	}								\
-	__pu_err;							\
-})
-
-#define __put_user_check(x, ptr, size)					\
-({									\
-	__typeof__(*(ptr)) __user *__pu_addr = (ptr);			\
-	__typeof__(*(ptr)) __pu_val = (x);				\
-	long __pu_err = -EFAULT;					\
-									\
-	if (likely(access_ok(VERIFY_WRITE,  __pu_addr, size))) {	\
-		switch (size) {						\
-		case 1: __put_user_asm("sb", __pu_addr); break;		\
-		case 2: __put_user_asm("sh", __pu_addr); break;		\
-		case 4: __put_user_asm("sw", __pu_addr); break;		\
-		case 8: __PUT_USER_DW(__pu_addr); break;		\
-		default: __put_user_unknown(); break;			\
-		}							\
-	}								\
-	__pu_err;							\
-})
-
-#define __put_user_asm(insn, ptr)					\
-{									\
-	__asm__ __volatile__(						\
-	"1:	" insn "	%z2, %3		# __put_user_asm\n"	\
-	"2:							\n"	\
-	"	.section	.fixup,\"ax\"			\n"	\
-	"3:	li	%0, %4					\n"	\
-	"	j	2b					\n"	\
-	"	.previous					\n"	\
-	"	.section	__ex_table,\"a\"		\n"	\
-	"	" __UA_ADDR "	1b, 3b				\n"	\
-	"	.previous					\n"	\
-	: "=r" (__pu_err)						\
-	: "0" (0), "Jr" (__pu_val), "o" (__m(ptr)),			\
-	  "i" (-EFAULT));						\
-}
-
-#define __put_user_asm_ll32(ptr)					\
-{									\
-	__asm__ __volatile__(						\
-	"1:	sw	%2, (%3)	# __put_user_asm_ll32	\n"	\
-	"2:	sw	%D2, 4(%3)				\n"	\
-	"3:							\n"	\
-	"	.section	.fixup,\"ax\"			\n"	\
-	"4:	li	%0, %4					\n"	\
-	"	j	3b					\n"	\
-	"	.previous					\n"	\
-	"	.section	__ex_table,\"a\"		\n"	\
-	"	" __UA_ADDR "	1b, 4b				\n"	\
-	"	" __UA_ADDR "	2b, 4b				\n"	\
-	"	.previous"						\
-	: "=r" (__pu_err)						\
-	: "0" (0), "r" (__pu_val), "r" (ptr),				\
-	  "i" (-EFAULT));						\
-}
-
-extern void __put_user_unknown(void);
-
-/*
- * We're generating jump to subroutines which will be outside the range of
- * jump instructions
- */
-#ifdef MODULE
-#define __MODULE_JAL(destination)					\
-	".set\tnoat\n\t"						\
-	__UA_LA "\t$1, " #destination "\n\t" 				\
-	"jalr\t$1\n\t"							\
-	".set\tat\n\t"
-#else
-#define __MODULE_JAL(destination)					\
-	"jal\t" #destination "\n\t"
-#endif
-
-#ifndef CONFIG_CPU_DADDI_WORKAROUNDS
-#define DADDI_SCRATCH "$0"
-#else
-#define DADDI_SCRATCH "$3"
-#endif
-
-extern size_t __copy_user(void *__to, const void *__from, size_t __n);
-
-#define __invoke_copy_to_user(to, from, n)				\
-({									\
-	register void __user *__cu_to_r __asm__("$4");			\
-	register const void *__cu_from_r __asm__("$5");			\
-	register long __cu_len_r __asm__("$6");				\
-									\
-	__cu_to_r = (to);						\
-	__cu_from_r = (from);						\
-	__cu_len_r = (n);						\
-	__asm__ __volatile__(						\
-	__MODULE_JAL(__copy_user)					\
-	: "+r" (__cu_to_r), "+r" (__cu_from_r), "+r" (__cu_len_r)	\
-	:								\
-	: "$8", "$9", "$10", "$11", "$12", "$15", "$24", "$31",		\
-	  DADDI_SCRATCH, "memory");					\
-	__cu_len_r;							\
-})
-
-/*
- * __copy_to_user: - Copy a block of data into user space, with less checking.
- * @to:   Destination address, in user space.
- * @from: Source address, in kernel space.
- * @n:    Number of bytes to copy.
- *
- * Context: User context only.  This function may sleep.
- *
- * Copy data from kernel space to user space.  Caller must check
- * the specified block with access_ok() before calling this function.
- *
- * Returns number of bytes that could not be copied.
- * On success, this will be zero.
- */
-#define __copy_to_user(to, from, n)					\
-({									\
-	void __user *__cu_to;						\
-	const void *__cu_from;						\
-	long __cu_len;							\
-									\
-	might_sleep();							\
-	__cu_to = (to);							\
-	__cu_from = (from);						\
-	__cu_len = (n);							\
-	__cu_len = __invoke_copy_to_user(__cu_to, __cu_from, __cu_len);	\
-	__cu_len;							\
-})
-
-extern size_t __copy_user_inatomic(void *__to, const void *__from, size_t __n);
-
-#define __copy_to_user_inatomic(to, from, n)				\
-({									\
-	void __user *__cu_to;						\
-	const void *__cu_from;						\
-	long __cu_len;							\
-									\
-	__cu_to = (to);							\
-	__cu_from = (from);						\
-	__cu_len = (n);							\
-	__cu_len = __invoke_copy_to_user(__cu_to, __cu_from, __cu_len);	\
-	__cu_len;							\
-})
-
-#define __copy_from_user_inatomic(to, from, n)				\
-({									\
-	void *__cu_to;							\
-	const void __user *__cu_from;					\
-	long __cu_len;							\
-									\
-	__cu_to = (to);							\
-	__cu_from = (from);						\
-	__cu_len = (n);							\
-	__cu_len = __invoke_copy_from_user_inatomic(__cu_to, __cu_from,	\
-	                                            __cu_len);		\
-	__cu_len;							\
-})
-
-/*
- * copy_to_user: - Copy a block of data into user space.
- * @to:   Destination address, in user space.
- * @from: Source address, in kernel space.
- * @n:    Number of bytes to copy.
- *
- * Context: User context only.  This function may sleep.
- *
- * Copy data from kernel space to user space.
- *
- * Returns number of bytes that could not be copied.
- * On success, this will be zero.
- */
-#define copy_to_user(to, from, n)					\
-({									\
-	void __user *__cu_to;						\
-	const void *__cu_from;						\
-	long __cu_len;							\
-									\
-	might_sleep();							\
-	__cu_to = (to);							\
-	__cu_from = (from);						\
-	__cu_len = (n);							\
-	if (access_ok(VERIFY_WRITE, __cu_to, __cu_len))			\
-		__cu_len = __invoke_copy_to_user(__cu_to, __cu_from,	\
-		                                 __cu_len);		\
-	__cu_len;							\
-})
-
-#define __invoke_copy_from_user(to, from, n)				\
-({									\
-	register void *__cu_to_r __asm__("$4");				\
-	register const void __user *__cu_from_r __asm__("$5");		\
-	register long __cu_len_r __asm__("$6");				\
-									\
-	__cu_to_r = (to);						\
-	__cu_from_r = (from);						\
-	__cu_len_r = (n);						\
-	__asm__ __volatile__(						\
-	".set\tnoreorder\n\t"						\
-	__MODULE_JAL(__copy_user)					\
-	".set\tnoat\n\t"						\
-	__UA_ADDU "\t$1, %1, %2\n\t"					\
-	".set\tat\n\t"							\
-	".set\treorder"							\
-	: "+r" (__cu_to_r), "+r" (__cu_from_r), "+r" (__cu_len_r)	\
-	:								\
-	: "$8", "$9", "$10", "$11", "$12", "$15", "$24", "$31",		\
-	  DADDI_SCRATCH, "memory");					\
-	__cu_len_r;							\
-})
-
-#define __invoke_copy_from_user_inatomic(to, from, n)			\
-({									\
-	register void *__cu_to_r __asm__("$4");				\
-	register const void __user *__cu_from_r __asm__("$5");		\
-	register long __cu_len_r __asm__("$6");				\
-									\
-	__cu_to_r = (to);						\
-	__cu_from_r = (from);						\
-	__cu_len_r = (n);						\
-	__asm__ __volatile__(						\
-	".set\tnoreorder\n\t"						\
-	__MODULE_JAL(__copy_user_inatomic)				\
-	".set\tnoat\n\t"						\
-	__UA_ADDU "\t$1, %1, %2\n\t"					\
-	".set\tat\n\t"							\
-	".set\treorder"							\
-	: "+r" (__cu_to_r), "+r" (__cu_from_r), "+r" (__cu_len_r)	\
-	:								\
-	: "$8", "$9", "$10", "$11", "$12", "$15", "$24", "$31",		\
-	  DADDI_SCRATCH, "memory");					\
-	__cu_len_r;							\
-})
-
-/*
- * __copy_from_user: - Copy a block of data from user space, with less checking.
- * @to:   Destination address, in kernel space.
- * @from: Source address, in user space.
- * @n:    Number of bytes to copy.
- *
- * Context: User context only.  This function may sleep.
- *
- * Copy data from user space to kernel space.  Caller must check
- * the specified block with access_ok() before calling this function.
- *
- * Returns number of bytes that could not be copied.
- * On success, this will be zero.
- *
- * If some data could not be copied, this function will pad the copied
- * data to the requested size using zero bytes.
- */
-#define __copy_from_user(to, from, n)					\
-({									\
-	void *__cu_to;							\
-	const void __user *__cu_from;					\
-	long __cu_len;							\
-									\
-	might_sleep();							\
-	__cu_to = (to);							\
-	__cu_from = (from);						\
-	__cu_len = (n);							\
-	__cu_len = __invoke_copy_from_user(__cu_to, __cu_from,		\
-	                                   __cu_len);			\
-	__cu_len;							\
-})
-
-/*
- * copy_from_user: - Copy a block of data from user space.
- * @to:   Destination address, in kernel space.
- * @from: Source address, in user space.
- * @n:    Number of bytes to copy.
- *
- * Context: User context only.  This function may sleep.
- *
- * Copy data from user space to kernel space.
- *
- * Returns number of bytes that could not be copied.
- * On success, this will be zero.
- *
- * If some data could not be copied, this function will pad the copied
- * data to the requested size using zero bytes.
- */
-#define copy_from_user(to, from, n)					\
-({									\
-	void *__cu_to;							\
-	const void __user *__cu_from;					\
-	long __cu_len;							\
-									\
-	might_sleep();							\
-	__cu_to = (to);							\
-	__cu_from = (from);						\
-	__cu_len = (n);							\
-	if (access_ok(VERIFY_READ, __cu_from, __cu_len))		\
-		__cu_len = __invoke_copy_from_user(__cu_to, __cu_from,	\
-		                                   __cu_len);		\
-	__cu_len;							\
-})
-
-#define __copy_in_user(to, from, n)	__copy_from_user(to, from, n)
-
-#define copy_in_user(to, from, n)					\
-({									\
-	void __user *__cu_to;						\
-	const void __user *__cu_from;					\
-	long __cu_len;							\
-									\
-	might_sleep();							\
-	__cu_to = (to);							\
-	__cu_from = (from);						\
-	__cu_len = (n);							\
-	if (likely(access_ok(VERIFY_READ, __cu_from, __cu_len) &&	\
-	           access_ok(VERIFY_WRITE, __cu_to, __cu_len)))		\
-		__cu_len = __invoke_copy_from_user(__cu_to, __cu_from,	\
-		                                   __cu_len);		\
-	__cu_len;							\
-})
-
-/*
- * __clear_user: - Zero a block of memory in user space, with less checking.
- * @to:   Destination address, in user space.
- * @n:    Number of bytes to zero.
- *
- * Zero a block of memory in user space.  Caller must check
- * the specified block with access_ok() before calling this function.
- *
- * Returns number of bytes that could not be cleared.
- * On success, this will be zero.
- */
-static inline __kernel_size_t
-__clear_user(void __user *addr, __kernel_size_t size)
-{
-	__kernel_size_t res;
-
-	might_sleep();
-	__asm__ __volatile__(
-		"move\t$4, %1\n\t"
-		"move\t$5, $0\n\t"
-		"move\t$6, %2\n\t"
-		__MODULE_JAL(__bzero)
-		"move\t%0, $6"
-		: "=r" (res)
-		: "r" (addr), "r" (size)
-		: "$4", "$5", "$6", __UA_t0, __UA_t1, "$31");
-
-	return res;
-}
-
-#define clear_user(addr,n)						\
-({									\
-	void __user * __cl_addr = (addr);				\
-	unsigned long __cl_size = (n);					\
-	if (__cl_size && access_ok(VERIFY_WRITE,			\
-		((unsigned long)(__cl_addr)), __cl_size))		\
-		__cl_size = __clear_user(__cl_addr, __cl_size);		\
-	__cl_size;							\
-})
-
-/*
- * __strncpy_from_user: - Copy a NUL terminated string from userspace, with less checking.
- * @dst:   Destination address, in kernel space.  This buffer must be at
- *         least @count bytes long.
- * @src:   Source address, in user space.
- * @count: Maximum number of bytes to copy, including the trailing NUL.
- *
- * Copies a NUL-terminated string from userspace to kernel space.
- * Caller must check the specified block with access_ok() before calling
- * this function.
- *
- * On success, returns the length of the string (not including the trailing
- * NUL).
- *
- * If access to userspace fails, returns -EFAULT (some data may have been
- * copied).
- *
- * If @count is smaller than the length of the string, copies @count bytes
- * and returns @count.
- */
-static inline long
-__strncpy_from_user(char *__to, const char __user *__from, long __len)
-{
-	long res;
-
-	might_sleep();
-	__asm__ __volatile__(
-		"move\t$4, %1\n\t"
-		"move\t$5, %2\n\t"
-		"move\t$6, %3\n\t"
-		__MODULE_JAL(__strncpy_from_user_nocheck_asm)
-		"move\t%0, $2"
-		: "=r" (res)
-		: "r" (__to), "r" (__from), "r" (__len)
-		: "$2", "$3", "$4", "$5", "$6", __UA_t0, "$31", "memory");
-
-	return res;
-}
-
-/*
- * strncpy_from_user: - Copy a NUL terminated string from userspace.
- * @dst:   Destination address, in kernel space.  This buffer must be at
- *         least @count bytes long.
- * @src:   Source address, in user space.
- * @count: Maximum number of bytes to copy, including the trailing NUL.
- *
- * Copies a NUL-terminated string from userspace to kernel space.
- *
- * On success, returns the length of the string (not including the trailing
- * NUL).
- *
- * If access to userspace fails, returns -EFAULT (some data may have been
- * copied).
- *
- * If @count is smaller than the length of the string, copies @count bytes
- * and returns @count.
- */
-static inline long
-strncpy_from_user(char *__to, const char __user *__from, long __len)
-{
-	long res;
-
-	might_sleep();
-	__asm__ __volatile__(
-		"move\t$4, %1\n\t"
-		"move\t$5, %2\n\t"
-		"move\t$6, %3\n\t"
-		__MODULE_JAL(__strncpy_from_user_asm)
-		"move\t%0, $2"
-		: "=r" (res)
-		: "r" (__to), "r" (__from), "r" (__len)
-		: "$2", "$3", "$4", "$5", "$6", __UA_t0, "$31", "memory");
-
-	return res;
-}
-
-/* Returns: 0 if bad, string length+1 (memory size) of string if ok */
-static inline long __strlen_user(const char __user *s)
-{
-	long res;
-
-	might_sleep();
-	__asm__ __volatile__(
-		"move\t$4, %1\n\t"
-		__MODULE_JAL(__strlen_user_nocheck_asm)
-		"move\t%0, $2"
-		: "=r" (res)
-		: "r" (s)
-		: "$2", "$4", __UA_t0, "$31");
-
-	return res;
-}
-
-/*
- * strlen_user: - Get the size of a string in user space.
- * @str: The string to measure.
- *
- * Context: User context only.  This function may sleep.
- *
- * Get the size of a NUL-terminated string in user space.
- *
- * Returns the size of the string INCLUDING the terminating NUL.
- * On exception, returns 0.
- *
- * If there is a limit on the length of a valid string, you may wish to
- * consider using strnlen_user() instead.
- */
-static inline long strlen_user(const char __user *s)
-{
-	long res;
-
-	might_sleep();
-	__asm__ __volatile__(
-		"move\t$4, %1\n\t"
-		__MODULE_JAL(__strlen_user_asm)
-		"move\t%0, $2"
-		: "=r" (res)
-		: "r" (s)
-		: "$2", "$4", __UA_t0, "$31");
-
-	return res;
-}
-
-/* Returns: 0 if bad, string length+1 (memory size) of string if ok */
-static inline long __strnlen_user(const char __user *s, long n)
-{
-	long res;
-
-	might_sleep();
-	__asm__ __volatile__(
-		"move\t$4, %1\n\t"
-		"move\t$5, %2\n\t"
-		__MODULE_JAL(__strnlen_user_nocheck_asm)
-		"move\t%0, $2"
-		: "=r" (res)
-		: "r" (s), "r" (n)
-		: "$2", "$4", "$5", __UA_t0, "$31");
-
-	return res;
-}
-
-/*
- * strlen_user: - Get the size of a string in user space.
- * @str: The string to measure.
- *
- * Context: User context only.  This function may sleep.
- *
- * Get the size of a NUL-terminated string in user space.
- *
- * Returns the size of the string INCLUDING the terminating NUL.
- * On exception, returns 0.
- *
- * If there is a limit on the length of a valid string, you may wish to
- * consider using strnlen_user() instead.
- */
-static inline long strnlen_user(const char __user *s, long n)
-{
-	long res;
-
-	might_sleep();
-	__asm__ __volatile__(
-		"move\t$4, %1\n\t"
-		"move\t$5, %2\n\t"
-		__MODULE_JAL(__strnlen_user_asm)
-		"move\t%0, $2"
-		: "=r" (res)
-		: "r" (s), "r" (n)
-		: "$2", "$4", "$5", __UA_t0, "$31");
-
-	return res;
-}
-
-struct exception_table_entry
-{
-	unsigned long insn;
-	unsigned long nextinsn;
-};
-
-extern int fixup_exception(struct pt_regs *regs);
-
-#endif /* _ASM_UACCESS_H */
diff --git a/include/asm-parisc/a.out.h b/include/asm-parisc/a.out.h
deleted file mode 100644
index eb04e34..0000000
--- a/include/asm-parisc/a.out.h
+++ /dev/null
@@ -1,20 +0,0 @@
-#ifndef __PARISC_A_OUT_H__
-#define __PARISC_A_OUT_H__
-
-struct exec
-{
-  unsigned int a_info;		/* Use macros N_MAGIC, etc for access */
-  unsigned a_text;		/* length of text, in bytes */
-  unsigned a_data;		/* length of data, in bytes */
-  unsigned a_bss;		/* length of uninitialized data area for file, in bytes */
-  unsigned a_syms;		/* length of symbol table data in file, in bytes */
-  unsigned a_entry;		/* start address */
-  unsigned a_trsize;		/* length of relocation info for text, in bytes */
-  unsigned a_drsize;		/* length of relocation info for data, in bytes */
-};
-
-#define N_TRSIZE(a)	((a).a_trsize)
-#define N_DRSIZE(a)	((a).a_drsize)
-#define N_SYMSIZE(a)	((a).a_syms)
-
-#endif /* __A_OUT_GNU_H__ */
diff --git a/include/asm-parisc/siginfo.h b/include/asm-parisc/siginfo.h
index d4909f5..d703472 100644
--- a/include/asm-parisc/siginfo.h
+++ b/include/asm-parisc/siginfo.h
@@ -3,11 +3,6 @@
 
 #include <asm-generic/siginfo.h>
 
-/*
- * SIGTRAP si_codes
- */
-#define TRAP_BRANCH	(__SI_FAULT|3)	/* process taken branch trap */
-#define TRAP_HWBKPT	(__SI_FAULT|4)	/* hardware breakpoint or watchpoint */
 #undef NSIGTRAP
 #define NSIGTRAP	4
 
diff --git a/include/asm-parisc/statfs.h b/include/asm-parisc/statfs.h
index 1d2b813..324bea9 100644
--- a/include/asm-parisc/statfs.h
+++ b/include/asm-parisc/statfs.h
@@ -1,58 +1,7 @@
 #ifndef _PARISC_STATFS_H
 #define _PARISC_STATFS_H
 
-#ifndef __KERNEL_STRICT_NAMES
-
-#include <linux/types.h>
-
-typedef __kernel_fsid_t	fsid_t;
-
-#endif
-
-/*
- * It appears that PARISC could be 64 _or_ 32 bit.
- * 64-bit fields must be explicitly 64-bit in statfs64.
- */
-struct statfs {
-	long f_type;
-	long f_bsize;
-	long f_blocks;
-	long f_bfree;
-	long f_bavail;
-	long f_files;
-	long f_ffree;
-	__kernel_fsid_t f_fsid;
-	long f_namelen;
-	long f_frsize;
-	long f_spare[5];
-};
-
-struct statfs64 {
-	long f_type;
-	long f_bsize;
-	__u64 f_blocks;
-	__u64 f_bfree;
-	__u64 f_bavail;
-	__u64 f_files;
-	__u64 f_ffree;
-	__kernel_fsid_t f_fsid;
-	long f_namelen;
-	long f_frsize;
-	long f_spare[5];
-};
-
-struct compat_statfs64 {
-	__u32 f_type;
-	__u32 f_bsize;
-	__u64 f_blocks;
-	__u64 f_bfree;
-	__u64 f_bavail;
-	__u64 f_files;
-	__u64 f_ffree;
-	__kernel_fsid_t f_fsid;
-	__u32 f_namelen;
-	__u32 f_frsize;
-	__u32 f_spare[5];
-};
+#define __statfs_word long
+#include <asm-generic/statfs.h>
 
 #endif
diff --git a/include/asm-um/dma-mapping.h b/include/asm-um/dma-mapping.h
index f0ee4fb..90fc708 100644
--- a/include/asm-um/dma-mapping.h
+++ b/include/asm-um/dma-mapping.h
@@ -118,4 +118,11 @@
 	BUG();
 }
 
+static inline int
+dma_mapping_error(struct device *dev, dma_addr_t dma_handle)
+{
+	BUG();
+	return 0;
+}
+
 #endif
diff --git a/include/asm-x86/a.out-core.h b/include/asm-x86/a.out-core.h
index 714207a..f570576 100644
--- a/include/asm-x86/a.out-core.h
+++ b/include/asm-x86/a.out-core.h
@@ -9,8 +9,8 @@
  * 2 of the Licence, or (at your option) any later version.
  */
 
-#ifndef _ASM_A_OUT_CORE_H
-#define _ASM_A_OUT_CORE_H
+#ifndef ASM_X86__A_OUT_CORE_H
+#define ASM_X86__A_OUT_CORE_H
 
 #ifdef __KERNEL__
 #ifdef CONFIG_X86_32
@@ -70,4 +70,4 @@
 
 #endif /* CONFIG_X86_32 */
 #endif /* __KERNEL__ */
-#endif /* _ASM_A_OUT_CORE_H */
+#endif /* ASM_X86__A_OUT_CORE_H */
diff --git a/include/asm-x86/a.out.h b/include/asm-x86/a.out.h
index 4684f97..0948748 100644
--- a/include/asm-x86/a.out.h
+++ b/include/asm-x86/a.out.h
@@ -1,5 +1,5 @@
-#ifndef _ASM_X86_A_OUT_H
-#define _ASM_X86_A_OUT_H
+#ifndef ASM_X86__A_OUT_H
+#define ASM_X86__A_OUT_H
 
 struct exec
 {
@@ -17,4 +17,4 @@
 #define N_DRSIZE(a)	((a).a_drsize)
 #define N_SYMSIZE(a)	((a).a_syms)
 
-#endif /* _ASM_X86_A_OUT_H */
+#endif /* ASM_X86__A_OUT_H */
diff --git a/include/asm-x86/acpi.h b/include/asm-x86/acpi.h
index 635d764..392e173 100644
--- a/include/asm-x86/acpi.h
+++ b/include/asm-x86/acpi.h
@@ -1,5 +1,5 @@
-#ifndef _ASM_X86_ACPI_H
-#define _ASM_X86_ACPI_H
+#ifndef ASM_X86__ACPI_H
+#define ASM_X86__ACPI_H
 
 /*
  *  Copyright (C) 2001 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
@@ -140,6 +140,8 @@
 	    boot_cpu_data.x86_model <= 0x05 &&
 	    boot_cpu_data.x86_mask < 0x0A)
 		return 1;
+	else if (boot_cpu_has(X86_FEATURE_AMDC1E))
+		return 1;
 	else
 		return max_cstate;
 }
@@ -173,4 +175,4 @@
 
 #define acpi_unlazy_tlb(x)	leave_mm(x)
 
-#endif /*__X86_ASM_ACPI_H*/
+#endif /* ASM_X86__ACPI_H */
diff --git a/include/asm-x86/agp.h b/include/asm-x86/agp.h
index e4004a9..3617fd4 100644
--- a/include/asm-x86/agp.h
+++ b/include/asm-x86/agp.h
@@ -1,5 +1,5 @@
-#ifndef _ASM_X86_AGP_H
-#define _ASM_X86_AGP_H
+#ifndef ASM_X86__AGP_H
+#define ASM_X86__AGP_H
 
 #include <asm/pgtable.h>
 #include <asm/cacheflush.h>
@@ -32,4 +32,4 @@
 #define free_gatt_pages(table, order)	\
 	free_pages((unsigned long)(table), (order))
 
-#endif
+#endif /* ASM_X86__AGP_H */
diff --git a/include/asm-x86/alternative.h b/include/asm-x86/alternative.h
index f6aa18e..22d3c98 100644
--- a/include/asm-x86/alternative.h
+++ b/include/asm-x86/alternative.h
@@ -1,5 +1,5 @@
-#ifndef _ASM_X86_ALTERNATIVE_H
-#define _ASM_X86_ALTERNATIVE_H
+#ifndef ASM_X86__ALTERNATIVE_H
+#define ASM_X86__ALTERNATIVE_H
 
 #include <linux/types.h>
 #include <linux/stddef.h>
@@ -180,4 +180,4 @@
 extern void *text_poke(void *addr, const void *opcode, size_t len);
 extern void *text_poke_early(void *addr, const void *opcode, size_t len);
 
-#endif /* _ASM_X86_ALTERNATIVE_H */
+#endif /* ASM_X86__ALTERNATIVE_H */
diff --git a/include/asm-x86/amd_iommu.h b/include/asm-x86/amd_iommu.h
index 30a1204..041d0db 100644
--- a/include/asm-x86/amd_iommu.h
+++ b/include/asm-x86/amd_iommu.h
@@ -17,16 +17,19 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  */
 
-#ifndef _ASM_X86_AMD_IOMMU_H
-#define _ASM_X86_AMD_IOMMU_H
+#ifndef ASM_X86__AMD_IOMMU_H
+#define ASM_X86__AMD_IOMMU_H
+
+#include <linux/irqreturn.h>
 
 #ifdef CONFIG_AMD_IOMMU
 extern int amd_iommu_init(void);
 extern int amd_iommu_init_dma_ops(void);
 extern void amd_iommu_detect(void);
+extern irqreturn_t amd_iommu_int_handler(int irq, void *data);
 #else
 static inline int amd_iommu_init(void) { return -ENODEV; }
 static inline void amd_iommu_detect(void) { }
 #endif
 
-#endif
+#endif /* ASM_X86__AMD_IOMMU_H */
diff --git a/include/asm-x86/amd_iommu_types.h b/include/asm-x86/amd_iommu_types.h
index dcc8120..b308586 100644
--- a/include/asm-x86/amd_iommu_types.h
+++ b/include/asm-x86/amd_iommu_types.h
@@ -17,8 +17,8 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  */
 
-#ifndef __AMD_IOMMU_TYPES_H__
-#define __AMD_IOMMU_TYPES_H__
+#ifndef ASM_X86__AMD_IOMMU_TYPES_H
+#define ASM_X86__AMD_IOMMU_TYPES_H
 
 #include <linux/types.h>
 #include <linux/list.h>
@@ -37,6 +37,7 @@
 /* Capability offsets used by the driver */
 #define MMIO_CAP_HDR_OFFSET	0x00
 #define MMIO_RANGE_OFFSET	0x0c
+#define MMIO_MISC_OFFSET	0x10
 
 /* Masks, shifts and macros to parse the device range capability */
 #define MMIO_RANGE_LD_MASK	0xff000000
@@ -48,6 +49,7 @@
 #define MMIO_GET_LD(x)  (((x) & MMIO_RANGE_LD_MASK) >> MMIO_RANGE_LD_SHIFT)
 #define MMIO_GET_FD(x)  (((x) & MMIO_RANGE_FD_MASK) >> MMIO_RANGE_FD_SHIFT)
 #define MMIO_GET_BUS(x) (((x) & MMIO_RANGE_BUS_MASK) >> MMIO_RANGE_BUS_SHIFT)
+#define MMIO_MSI_NUM(x)	((x) & 0x1f)
 
 /* Flag masks for the AMD IOMMU exclusion range */
 #define MMIO_EXCL_ENABLE_MASK 0x01ULL
@@ -69,6 +71,25 @@
 /* MMIO status bits */
 #define MMIO_STATUS_COM_WAIT_INT_MASK	0x04
 
+/* event logging constants */
+#define EVENT_ENTRY_SIZE	0x10
+#define EVENT_TYPE_SHIFT	28
+#define EVENT_TYPE_MASK		0xf
+#define EVENT_TYPE_ILL_DEV	0x1
+#define EVENT_TYPE_IO_FAULT	0x2
+#define EVENT_TYPE_DEV_TAB_ERR	0x3
+#define EVENT_TYPE_PAGE_TAB_ERR	0x4
+#define EVENT_TYPE_ILL_CMD	0x5
+#define EVENT_TYPE_CMD_HARD_ERR	0x6
+#define EVENT_TYPE_IOTLB_INV_TO	0x7
+#define EVENT_TYPE_INV_DEV_REQ	0x8
+#define EVENT_DEVID_MASK	0xffff
+#define EVENT_DEVID_SHIFT	0
+#define EVENT_DOMID_MASK	0xffff
+#define EVENT_DOMID_SHIFT	0
+#define EVENT_FLAGS_MASK	0xfff
+#define EVENT_FLAGS_SHIFT	0x10
+
 /* feature control bits */
 #define CONTROL_IOMMU_EN        0x00ULL
 #define CONTROL_HT_TUN_EN       0x01ULL
@@ -109,6 +130,8 @@
 #define DEV_ENTRY_NMI_PASS      0xba
 #define DEV_ENTRY_LINT0_PASS    0xbe
 #define DEV_ENTRY_LINT1_PASS    0xbf
+#define DEV_ENTRY_MODE_MASK	0x07
+#define DEV_ENTRY_MODE_SHIFT	0x09
 
 /* constants to configure the command buffer */
 #define CMD_BUFFER_SIZE    8192
@@ -116,6 +139,10 @@
 #define MMIO_CMD_SIZE_SHIFT 56
 #define MMIO_CMD_SIZE_512 (0x9ULL << MMIO_CMD_SIZE_SHIFT)
 
+/* constants for event buffer handling */
+#define EVT_BUFFER_SIZE		8192 /* 512 entries */
+#define EVT_LEN_MASK		(0x9ULL << 56)
+
 #define PAGE_MODE_1_LEVEL 0x01
 #define PAGE_MODE_2_LEVEL 0x02
 #define PAGE_MODE_3_LEVEL 0x03
@@ -134,6 +161,7 @@
 #define IOMMU_MAP_SIZE_L3 (1ULL << 39)
 
 #define IOMMU_PTE_P  (1ULL << 0)
+#define IOMMU_PTE_TV (1ULL << 1)
 #define IOMMU_PTE_U  (1ULL << 59)
 #define IOMMU_PTE_FC (1ULL << 60)
 #define IOMMU_PTE_IR (1ULL << 61)
@@ -159,6 +187,9 @@
 
 #define MAX_DOMAIN_ID 65536
 
+/* FIXME: move this macro to <linux/pci.h> */
+#define PCI_BUS(x) (((x) >> 8) & 0xff)
+
 /*
  * This structure contains generic data for  IOMMU protection domains
  * independent of their use.
@@ -196,6 +227,15 @@
 	 * just calculate its address in constant time.
 	 */
 	u64 **pte_pages;
+
+	/* This will be set to true when TLB needs to be flushed */
+	bool need_flush;
+
+	/*
+	 * if this is a preallocated domain, keep the device for which it was
+	 * preallocated in this variable
+	 */
+	u16 target_dev;
 };
 
 /*
@@ -208,8 +248,9 @@
 	/* locks the accesses to the hardware */
 	spinlock_t lock;
 
-	/* device id of this IOMMU */
-	u16 devid;
+	/* Pointer to PCI device of this IOMMU */
+	struct pci_dev *dev;
+
 	/*
 	 * Capability pointer. There could be more than one IOMMU per PCI
 	 * device function if there are more than one AMD IOMMU capability
@@ -225,6 +266,9 @@
 	/* capabilities of that IOMMU read from ACPI */
 	u32 cap;
 
+	/* pci domain of this IOMMU */
+	u16 pci_seg;
+
 	/* first device this IOMMU handles. read from PCI */
 	u16 first_device;
 	/* last device this IOMMU handles. read from PCI */
@@ -240,9 +284,19 @@
 	/* size of command buffer */
 	u32 cmd_buf_size;
 
+	/* event buffer virtual address */
+	u8 *evt_buf;
+	/* size of event buffer */
+	u32 evt_buf_size;
+	/* MSI number for event interrupt */
+	u16 evt_msi_num;
+
 	/* if one, we need to send a completion wait command */
 	int need_sync;
 
+	/* true if interrupts for this IOMMU are already enabled */
+	bool int_enabled;
+
 	/* default dma_ops domain for that IOMMU */
 	struct dma_ops_domain *default_dom;
 };
@@ -322,6 +376,12 @@
 /* will be 1 if device isolation is enabled */
 extern int amd_iommu_isolate;
 
+/*
+ * If true, the addresses will be flushed on unmap time, not when
+ * they are reused
+ */
+extern bool amd_iommu_unmap_flush;
+
 /* takes a PCI device id and prints it out in a readable form */
 static inline void print_devid(u16 devid, int nl)
 {
@@ -341,4 +401,4 @@
 	return (((u16)bus) << 8) | devfn;
 }
 
-#endif
+#endif /* ASM_X86__AMD_IOMMU_TYPES_H */
diff --git a/include/asm-x86/apic.h b/include/asm-x86/apic.h
index 133c998..d76a083 100644
--- a/include/asm-x86/apic.h
+++ b/include/asm-x86/apic.h
@@ -1,5 +1,5 @@
-#ifndef _ASM_X86_APIC_H
-#define _ASM_X86_APIC_H
+#ifndef ASM_X86__APIC_H
+#define ASM_X86__APIC_H
 
 #include <linux/pm.h>
 #include <linux/delay.h>
@@ -9,6 +9,8 @@
 #include <asm/apicdef.h>
 #include <asm/processor.h>
 #include <asm/system.h>
+#include <asm/cpufeature.h>
+#include <asm/msr.h>
 
 #define ARCH_APICTIMER_STOPS_ON_C3	1
 
@@ -47,15 +49,18 @@
 #ifdef CONFIG_PARAVIRT
 #include <asm/paravirt.h>
 #else
-#define apic_write native_apic_write
-#define apic_read native_apic_read
 #define setup_boot_clock setup_boot_APIC_clock
 #define setup_secondary_clock setup_secondary_APIC_clock
 #endif
 
 extern int is_vsmp_box(void);
+extern void xapic_wait_icr_idle(void);
+extern u32 safe_xapic_wait_icr_idle(void);
+extern u64 xapic_icr_read(void);
+extern void xapic_icr_write(u32, u32);
+extern int setup_profiling_timer(unsigned int);
 
-static inline void native_apic_write(unsigned long reg, u32 v)
+static inline void native_apic_mem_write(u32 reg, u32 v)
 {
 	volatile u32 *addr = (volatile u32 *)(APIC_BASE + reg);
 
@@ -64,21 +69,72 @@
 		       ASM_OUTPUT2("0" (v), "m" (*addr)));
 }
 
-static inline u32 native_apic_read(unsigned long reg)
+static inline u32 native_apic_mem_read(u32 reg)
 {
 	return *((volatile u32 *)(APIC_BASE + reg));
 }
 
-extern void apic_wait_icr_idle(void);
-extern u32 safe_apic_wait_icr_idle(void);
+static inline void native_apic_msr_write(u32 reg, u32 v)
+{
+	if (reg == APIC_DFR || reg == APIC_ID || reg == APIC_LDR ||
+	    reg == APIC_LVR)
+		return;
+
+	wrmsr(APIC_BASE_MSR + (reg >> 4), v, 0);
+}
+
+static inline u32 native_apic_msr_read(u32 reg)
+{
+	u32 low, high;
+
+	if (reg == APIC_DFR)
+		return -1;
+
+	rdmsr(APIC_BASE_MSR + (reg >> 4), low, high);
+	return low;
+}
+
+#ifndef CONFIG_X86_32
+extern int x2apic, x2apic_preenabled;
+extern void check_x2apic(void);
+extern void enable_x2apic(void);
+extern void enable_IR_x2apic(void);
+extern void x2apic_icr_write(u32 low, u32 id);
+#endif
+
+struct apic_ops {
+	u32 (*read)(u32 reg);
+	void (*write)(u32 reg, u32 v);
+	u64 (*icr_read)(void);
+	void (*icr_write)(u32 low, u32 high);
+	void (*wait_icr_idle)(void);
+	u32 (*safe_wait_icr_idle)(void);
+};
+
+extern struct apic_ops *apic_ops;
+
+#define apic_read (apic_ops->read)
+#define apic_write (apic_ops->write)
+#define apic_icr_read (apic_ops->icr_read)
+#define apic_icr_write (apic_ops->icr_write)
+#define apic_wait_icr_idle (apic_ops->wait_icr_idle)
+#define safe_apic_wait_icr_idle (apic_ops->safe_wait_icr_idle)
+
 extern int get_physical_broadcast(void);
 
+#ifdef CONFIG_X86_64
+static inline void ack_x2APIC_irq(void)
+{
+	/* Docs say use 0 for future compatibility */
+	native_apic_msr_write(APIC_EOI, 0);
+}
+#endif
+
+
 static inline void ack_APIC_irq(void)
 {
 	/*
-	 * ack_APIC_irq() actually gets compiled as a single instruction:
-	 * - a single rmw on Pentium/82489DX
-	 * - a single write on P6+ cores (CONFIG_X86_GOOD_APIC)
+	 * ack_APIC_irq() actually gets compiled as a single instruction
 	 * ... yummie.
 	 */
 
@@ -128,4 +184,4 @@
 
 #endif /* !CONFIG_X86_LOCAL_APIC */
 
-#endif /* __ASM_APIC_H */
+#endif /* ASM_X86__APIC_H */
diff --git a/include/asm-x86/apicdef.h b/include/asm-x86/apicdef.h
index 6b9008c..b922c85 100644
--- a/include/asm-x86/apicdef.h
+++ b/include/asm-x86/apicdef.h
@@ -1,5 +1,5 @@
-#ifndef _ASM_X86_APICDEF_H
-#define _ASM_X86_APICDEF_H
+#ifndef ASM_X86__APICDEF_H
+#define ASM_X86__APICDEF_H
 
 /*
  * Constants for various Intel APICs. (local APIC, IOAPIC, etc.)
@@ -105,6 +105,7 @@
 #define	APIC_TMICT	0x380
 #define	APIC_TMCCT	0x390
 #define	APIC_TDCR	0x3E0
+#define APIC_SELF_IPI	0x3F0
 #define		APIC_TDR_DIV_TMBASE	(1 << 2)
 #define		APIC_TDR_DIV_1		0xB
 #define		APIC_TDR_DIV_2		0x0
@@ -128,6 +129,8 @@
 #define	APIC_EILVT3     0x530
 
 #define APIC_BASE (fix_to_virt(FIX_APIC_BASE))
+#define APIC_BASE_MSR	0x800
+#define X2APIC_ENABLE	(1UL << 10)
 
 #ifdef CONFIG_X86_32
 # define MAX_IO_APICS 64
@@ -411,4 +414,4 @@
 #else
  #define BAD_APICID 0xFFFFu
 #endif
-#endif
+#endif /* ASM_X86__APICDEF_H */
diff --git a/include/asm-x86/arch_hooks.h b/include/asm-x86/arch_hooks.h
index 8411750..de4596b 100644
--- a/include/asm-x86/arch_hooks.h
+++ b/include/asm-x86/arch_hooks.h
@@ -1,5 +1,5 @@
-#ifndef _ASM_ARCH_HOOKS_H
-#define _ASM_ARCH_HOOKS_H
+#ifndef ASM_X86__ARCH_HOOKS_H
+#define ASM_X86__ARCH_HOOKS_H
 
 #include <linux/interrupt.h>
 
@@ -12,8 +12,6 @@
 /* these aren't arch hooks, they are generic routines
  * that can be used by the hooks */
 extern void init_ISA_irqs(void);
-extern void apic_intr_init(void);
-extern void smp_intr_init(void);
 extern irqreturn_t timer_interrupt(int irq, void *dev_id);
 
 /* these are the defined hooks */
@@ -25,4 +23,4 @@
 extern void time_init_hook(void);
 extern void mca_nmi_hook(void);
 
-#endif
+#endif /* ASM_X86__ARCH_HOOKS_H */
diff --git a/include/asm-x86/asm.h b/include/asm-x86/asm.h
index 9722032..e1355f4 100644
--- a/include/asm-x86/asm.h
+++ b/include/asm-x86/asm.h
@@ -1,5 +1,5 @@
-#ifndef _ASM_X86_ASM_H
-#define _ASM_X86_ASM_H
+#ifndef ASM_X86__ASM_H
+#define ASM_X86__ASM_H
 
 #ifdef __ASSEMBLY__
 # define __ASM_FORM(x)	x
@@ -20,17 +20,22 @@
 
 #define _ASM_PTR	__ASM_SEL(.long, .quad)
 #define _ASM_ALIGN	__ASM_SEL(.balign 4, .balign 8)
-#define _ASM_MOV_UL	__ASM_SIZE(mov)
 
+#define _ASM_MOV	__ASM_SIZE(mov)
 #define _ASM_INC	__ASM_SIZE(inc)
 #define _ASM_DEC	__ASM_SIZE(dec)
 #define _ASM_ADD	__ASM_SIZE(add)
 #define _ASM_SUB	__ASM_SIZE(sub)
 #define _ASM_XADD	__ASM_SIZE(xadd)
+
 #define _ASM_AX		__ASM_REG(ax)
 #define _ASM_BX		__ASM_REG(bx)
 #define _ASM_CX		__ASM_REG(cx)
 #define _ASM_DX		__ASM_REG(dx)
+#define _ASM_SP		__ASM_REG(sp)
+#define _ASM_BP		__ASM_REG(bp)
+#define _ASM_SI		__ASM_REG(si)
+#define _ASM_DI		__ASM_REG(di)
 
 /* Exception table entry */
 # define _ASM_EXTABLE(from,to) \
@@ -39,4 +44,4 @@
 	_ASM_PTR #from "," #to "\n" \
 	" .previous\n"
 
-#endif /* _ASM_X86_ASM_H */
+#endif /* ASM_X86__ASM_H */
diff --git a/include/asm-x86/atomic_32.h b/include/asm-x86/atomic_32.h
index 21a4825..14d3f0b 100644
--- a/include/asm-x86/atomic_32.h
+++ b/include/asm-x86/atomic_32.h
@@ -1,5 +1,5 @@
-#ifndef __ARCH_I386_ATOMIC__
-#define __ARCH_I386_ATOMIC__
+#ifndef ASM_X86__ATOMIC_32_H
+#define ASM_X86__ATOMIC_32_H
 
 #include <linux/compiler.h>
 #include <asm/processor.h>
@@ -256,4 +256,4 @@
 #define smp_mb__after_atomic_inc()	barrier()
 
 #include <asm-generic/atomic.h>
-#endif
+#endif /* ASM_X86__ATOMIC_32_H */
diff --git a/include/asm-x86/atomic_64.h b/include/asm-x86/atomic_64.h
index 91c7d03..2cb218c 100644
--- a/include/asm-x86/atomic_64.h
+++ b/include/asm-x86/atomic_64.h
@@ -1,5 +1,5 @@
-#ifndef __ARCH_X86_64_ATOMIC__
-#define __ARCH_X86_64_ATOMIC__
+#ifndef ASM_X86__ATOMIC_64_H
+#define ASM_X86__ATOMIC_64_H
 
 #include <asm/alternative.h>
 #include <asm/cmpxchg.h>
@@ -470,4 +470,4 @@
 #define smp_mb__after_atomic_inc()	barrier()
 
 #include <asm-generic/atomic.h>
-#endif
+#endif /* ASM_X86__ATOMIC_64_H */
diff --git a/include/asm-x86/auxvec.h b/include/asm-x86/auxvec.h
index 87f5e6d..12c7cac 100644
--- a/include/asm-x86/auxvec.h
+++ b/include/asm-x86/auxvec.h
@@ -1,5 +1,5 @@
-#ifndef _ASM_X86_AUXVEC_H
-#define _ASM_X86_AUXVEC_H
+#ifndef ASM_X86__AUXVEC_H
+#define ASM_X86__AUXVEC_H
 /*
  * Architecture-neutral AT_ values in 0-17, leave some room
  * for more of them, start the x86-specific ones at 32.
@@ -9,4 +9,4 @@
 #endif
 #define AT_SYSINFO_EHDR		33
 
-#endif
+#endif /* ASM_X86__AUXVEC_H */
diff --git a/include/asm-x86/bigsmp/apic.h b/include/asm-x86/bigsmp/apic.h
new file mode 100644
index 0000000..0a9cd7c
--- /dev/null
+++ b/include/asm-x86/bigsmp/apic.h
@@ -0,0 +1,144 @@
+#ifndef __ASM_MACH_APIC_H
+#define __ASM_MACH_APIC_H
+
+#define xapic_phys_to_log_apicid(cpu) (per_cpu(x86_bios_cpu_apicid, cpu))
+#define esr_disable (1)
+
+static inline int apic_id_registered(void)
+{
+	return (1);
+}
+
+/* Round robin the irqs amoung the online cpus */
+static inline cpumask_t target_cpus(void)
+{
+	static unsigned long cpu = NR_CPUS;
+	do {
+		if (cpu >= NR_CPUS)
+			cpu = first_cpu(cpu_online_map);
+		else
+			cpu = next_cpu(cpu, cpu_online_map);
+	} while (cpu >= NR_CPUS);
+	return cpumask_of_cpu(cpu);
+}
+
+#undef APIC_DEST_LOGICAL
+#define APIC_DEST_LOGICAL	0
+#define TARGET_CPUS		(target_cpus())
+#define APIC_DFR_VALUE		(APIC_DFR_FLAT)
+#define INT_DELIVERY_MODE	(dest_Fixed)
+#define INT_DEST_MODE		(0)    /* phys delivery to target proc */
+#define NO_BALANCE_IRQ		(0)
+#define WAKE_SECONDARY_VIA_INIT
+
+
+static inline unsigned long check_apicid_used(physid_mask_t bitmap, int apicid)
+{
+	return (0);
+}
+
+static inline unsigned long check_apicid_present(int bit)
+{
+	return (1);
+}
+
+static inline unsigned long calculate_ldr(int cpu)
+{
+	unsigned long val, id;
+	val = apic_read(APIC_LDR) & ~APIC_LDR_MASK;
+	id = xapic_phys_to_log_apicid(cpu);
+	val |= SET_APIC_LOGICAL_ID(id);
+	return val;
+}
+
+/*
+ * Set up the logical destination ID.
+ *
+ * Intel recommends to set DFR, LDR and TPR before enabling
+ * an APIC.  See e.g. "AP-388 82489DX User's Manual" (Intel
+ * document number 292116).  So here it goes...
+ */
+static inline void init_apic_ldr(void)
+{
+	unsigned long val;
+	int cpu = smp_processor_id();
+
+	apic_write(APIC_DFR, APIC_DFR_VALUE);
+	val = calculate_ldr(cpu);
+	apic_write(APIC_LDR, val);
+}
+
+static inline void setup_apic_routing(void)
+{
+	printk("Enabling APIC mode:  %s.  Using %d I/O APICs\n",
+		"Physflat", nr_ioapics);
+}
+
+static inline int multi_timer_check(int apic, int irq)
+{
+	return (0);
+}
+
+static inline int apicid_to_node(int logical_apicid)
+{
+	return apicid_2_node[hard_smp_processor_id()];
+}
+
+static inline int cpu_present_to_apicid(int mps_cpu)
+{
+	if (mps_cpu < NR_CPUS)
+		return (int) per_cpu(x86_bios_cpu_apicid, mps_cpu);
+
+	return BAD_APICID;
+}
+
+static inline physid_mask_t apicid_to_cpu_present(int phys_apicid)
+{
+	return physid_mask_of_physid(phys_apicid);
+}
+
+extern u8 cpu_2_logical_apicid[];
+/* Mapping from cpu number to logical apicid */
+static inline int cpu_to_logical_apicid(int cpu)
+{
+	if (cpu >= NR_CPUS)
+		return BAD_APICID;
+	return cpu_physical_id(cpu);
+}
+
+static inline physid_mask_t ioapic_phys_id_map(physid_mask_t phys_map)
+{
+	/* For clustered we don't have a good way to do this yet - hack */
+	return physids_promote(0xFFL);
+}
+
+static inline void setup_portio_remap(void)
+{
+}
+
+static inline void enable_apic_mode(void)
+{
+}
+
+static inline int check_phys_apicid_present(int boot_cpu_physical_apicid)
+{
+	return (1);
+}
+
+/* As we are using single CPU as destination, pick only one CPU here */
+static inline unsigned int cpu_mask_to_apicid(cpumask_t cpumask)
+{
+	int cpu;
+	int apicid;	
+
+	cpu = first_cpu(cpumask);
+	apicid = cpu_to_logical_apicid(cpu);
+	return apicid;
+}
+
+static inline u32 phys_pkg_id(u32 cpuid_apic, int index_msb)
+{
+	return cpuid_apic >> index_msb;
+}
+
+#endif /* __ASM_MACH_APIC_H */
diff --git a/include/asm-x86/bigsmp/apicdef.h b/include/asm-x86/bigsmp/apicdef.h
new file mode 100644
index 0000000..392c3f5
--- /dev/null
+++ b/include/asm-x86/bigsmp/apicdef.h
@@ -0,0 +1,13 @@
+#ifndef __ASM_MACH_APICDEF_H
+#define __ASM_MACH_APICDEF_H
+
+#define		APIC_ID_MASK		(0xFF<<24)
+
+static inline unsigned get_apic_id(unsigned long x)
+{
+	return (((x)>>24)&0xFF);
+}
+
+#define		GET_APIC_ID(x)	get_apic_id(x)
+
+#endif
diff --git a/include/asm-x86/mach-bigsmp/mach_ipi.h b/include/asm-x86/bigsmp/ipi.h
similarity index 100%
rename from include/asm-x86/mach-bigsmp/mach_ipi.h
rename to include/asm-x86/bigsmp/ipi.h
diff --git a/include/asm-x86/bios_ebda.h b/include/asm-x86/bios_ebda.h
index 0033e50..79b4b88 100644
--- a/include/asm-x86/bios_ebda.h
+++ b/include/asm-x86/bios_ebda.h
@@ -1,5 +1,5 @@
-#ifndef _MACH_BIOS_EBDA_H
-#define _MACH_BIOS_EBDA_H
+#ifndef ASM_X86__BIOS_EBDA_H
+#define ASM_X86__BIOS_EBDA_H
 
 #include <asm/io.h>
 
@@ -16,4 +16,21 @@
 
 void reserve_ebda_region(void);
 
-#endif /* _MACH_BIOS_EBDA_H */
+#ifdef CONFIG_X86_CHECK_BIOS_CORRUPTION
+/*
+ * This is obviously not a great place for this, but we want to be
+ * able to scatter it around anywhere in the kernel.
+ */
+void check_for_bios_corruption(void);
+void start_periodic_check_for_corruption(void);
+#else
+static inline void check_for_bios_corruption(void)
+{
+}
+
+static inline void start_periodic_check_for_corruption(void)
+{
+}
+#endif
+
+#endif /* ASM_X86__BIOS_EBDA_H */
diff --git a/include/asm-x86/bitops.h b/include/asm-x86/bitops.h
index cfb2b64..451a747 100644
--- a/include/asm-x86/bitops.h
+++ b/include/asm-x86/bitops.h
@@ -1,5 +1,5 @@
-#ifndef _ASM_X86_BITOPS_H
-#define _ASM_X86_BITOPS_H
+#ifndef ASM_X86__BITOPS_H
+#define ASM_X86__BITOPS_H
 
 /*
  * Copyright 1992, Linus Torvalds.
@@ -424,16 +424,6 @@
 
 #undef ADDR
 
-static inline void set_bit_string(unsigned long *bitmap,
-		unsigned long i, int len)
-{
-	unsigned long end = i + len;
-	while (i < end) {
-		__set_bit(i, bitmap);
-		i++;
-	}
-}
-
 #ifdef __KERNEL__
 
 #include <asm-generic/bitops/sched.h>
@@ -458,4 +448,4 @@
 #include <asm-generic/bitops/minix.h>
 
 #endif /* __KERNEL__ */
-#endif	/* _ASM_X86_BITOPS_H */
+#endif /* ASM_X86__BITOPS_H */
diff --git a/include/asm-x86/boot.h b/include/asm-x86/boot.h
index 2faed7e..1d63bd5 100644
--- a/include/asm-x86/boot.h
+++ b/include/asm-x86/boot.h
@@ -1,10 +1,8 @@
-#ifndef _ASM_BOOT_H
-#define _ASM_BOOT_H
+#ifndef ASM_X86__BOOT_H
+#define ASM_X86__BOOT_H
 
 /* Don't touch these, unless you really know what you're doing. */
-#define DEF_INITSEG	0x9000
 #define DEF_SYSSEG	0x1000
-#define DEF_SETUPSEG	0x9020
 #define DEF_SYSSIZE	0x7F00
 
 /* Internal svga startup constants */
@@ -25,4 +23,4 @@
 #define BOOT_STACK_SIZE	0x1000
 #endif
 
-#endif /* _ASM_BOOT_H */
+#endif /* ASM_X86__BOOT_H */
diff --git a/include/asm-x86/bootparam.h b/include/asm-x86/bootparam.h
index ae22bdf..ccf027e 100644
--- a/include/asm-x86/bootparam.h
+++ b/include/asm-x86/bootparam.h
@@ -1,5 +1,5 @@
-#ifndef _ASM_BOOTPARAM_H
-#define _ASM_BOOTPARAM_H
+#ifndef ASM_X86__BOOTPARAM_H
+#define ASM_X86__BOOTPARAM_H
 
 #include <linux/types.h>
 #include <linux/screen_info.h>
@@ -108,4 +108,4 @@
 	__u8  _pad9[276];				/* 0xeec */
 } __attribute__((packed));
 
-#endif /* _ASM_BOOTPARAM_H */
+#endif /* ASM_X86__BOOTPARAM_H */
diff --git a/include/asm-x86/bug.h b/include/asm-x86/bug.h
index b69aa64..91ad43a 100644
--- a/include/asm-x86/bug.h
+++ b/include/asm-x86/bug.h
@@ -1,5 +1,5 @@
-#ifndef _ASM_X86_BUG_H
-#define _ASM_X86_BUG_H
+#ifndef ASM_X86__BUG_H
+#define ASM_X86__BUG_H
 
 #ifdef CONFIG_BUG
 #define HAVE_ARCH_BUG
@@ -36,4 +36,4 @@
 #endif /* !CONFIG_BUG */
 
 #include <asm-generic/bug.h>
-#endif
+#endif /* ASM_X86__BUG_H */
diff --git a/include/asm-x86/bugs.h b/include/asm-x86/bugs.h
index 021cbdd..dc60498 100644
--- a/include/asm-x86/bugs.h
+++ b/include/asm-x86/bugs.h
@@ -1,7 +1,12 @@
-#ifndef _ASM_X86_BUGS_H
-#define _ASM_X86_BUGS_H
+#ifndef ASM_X86__BUGS_H
+#define ASM_X86__BUGS_H
 
 extern void check_bugs(void);
-int ppro_with_ram_bug(void);
 
-#endif /* _ASM_X86_BUGS_H */
+#if defined(CONFIG_CPU_SUP_INTEL) && defined(CONFIG_X86_32)
+int ppro_with_ram_bug(void);
+#else
+static inline int ppro_with_ram_bug(void) { return 0; }
+#endif
+
+#endif /* ASM_X86__BUGS_H */
diff --git a/include/asm-x86/byteorder.h b/include/asm-x86/byteorder.h
index e02ae2d..722f27d 100644
--- a/include/asm-x86/byteorder.h
+++ b/include/asm-x86/byteorder.h
@@ -1,5 +1,5 @@
-#ifndef _ASM_X86_BYTEORDER_H
-#define _ASM_X86_BYTEORDER_H
+#ifndef ASM_X86__BYTEORDER_H
+#define ASM_X86__BYTEORDER_H
 
 #include <asm/types.h>
 #include <linux/compiler.h>
@@ -78,4 +78,4 @@
 
 #include <linux/byteorder/little_endian.h>
 
-#endif /* _ASM_X86_BYTEORDER_H */
+#endif /* ASM_X86__BYTEORDER_H */
diff --git a/include/asm-x86/cache.h b/include/asm-x86/cache.h
index 1e0bac8..ea3f1cc 100644
--- a/include/asm-x86/cache.h
+++ b/include/asm-x86/cache.h
@@ -1,5 +1,5 @@
-#ifndef _ARCH_X86_CACHE_H
-#define _ARCH_X86_CACHE_H
+#ifndef ASM_X86__CACHE_H
+#define ASM_X86__CACHE_H
 
 /* L1 cache line size */
 #define L1_CACHE_SHIFT	(CONFIG_X86_L1_CACHE_SHIFT)
@@ -17,4 +17,4 @@
 #endif
 #endif
 
-#endif
+#endif /* ASM_X86__CACHE_H */
diff --git a/include/asm-x86/cacheflush.h b/include/asm-x86/cacheflush.h
index f4c0ab5..68840ef 100644
--- a/include/asm-x86/cacheflush.h
+++ b/include/asm-x86/cacheflush.h
@@ -1,5 +1,5 @@
-#ifndef _ASM_X86_CACHEFLUSH_H
-#define _ASM_X86_CACHEFLUSH_H
+#ifndef ASM_X86__CACHEFLUSH_H
+#define ASM_X86__CACHEFLUSH_H
 
 /* Keep includes the same across arches.  */
 #include <linux/mm.h>
@@ -24,6 +24,8 @@
 #define copy_from_user_page(vma, page, vaddr, dst, src, len)	\
 	memcpy((dst), (src), (len))
 
+#define PG_non_WB				PG_arch_1
+PAGEFLAG(NonWB, non_WB)
 
 /*
  * The set_memory_* API can be used to change various attributes of a virtual
@@ -66,6 +68,9 @@
 int set_memory_np(unsigned long addr, int numpages);
 int set_memory_4k(unsigned long addr, int numpages);
 
+int set_memory_array_uc(unsigned long *addr, int addrinarray);
+int set_memory_array_wb(unsigned long *addr, int addrinarray);
+
 /*
  * For legacy compatibility with the old APIs, a few functions
  * are provided that work on a "struct page".
@@ -96,8 +101,6 @@
 
 void clflush_cache_range(void *addr, unsigned int size);
 
-void cpa_init(void);
-
 #ifdef CONFIG_DEBUG_RODATA
 void mark_rodata_ro(void);
 extern const int rodata_test_data;
@@ -112,4 +115,4 @@
 }
 #endif
 
-#endif
+#endif /* ASM_X86__CACHEFLUSH_H */
diff --git a/include/asm-x86/calgary.h b/include/asm-x86/calgary.h
index 67f6040..933fd27 100644
--- a/include/asm-x86/calgary.h
+++ b/include/asm-x86/calgary.h
@@ -21,8 +21,8 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  */
 
-#ifndef _ASM_X86_64_CALGARY_H
-#define _ASM_X86_64_CALGARY_H
+#ifndef ASM_X86__CALGARY_H
+#define ASM_X86__CALGARY_H
 
 #include <linux/spinlock.h>
 #include <linux/device.h>
@@ -69,4 +69,4 @@
 static inline void detect_calgary(void) { return; }
 #endif
 
-#endif /* _ASM_X86_64_CALGARY_H */
+#endif /* ASM_X86__CALGARY_H */
diff --git a/include/asm-x86/checksum_32.h b/include/asm-x86/checksum_32.h
index 52bbb0d..d041e8c 100644
--- a/include/asm-x86/checksum_32.h
+++ b/include/asm-x86/checksum_32.h
@@ -1,5 +1,5 @@
-#ifndef _I386_CHECKSUM_H
-#define _I386_CHECKSUM_H
+#ifndef ASM_X86__CHECKSUM_32_H
+#define ASM_X86__CHECKSUM_32_H
 
 #include <linux/in6.h>
 
@@ -186,4 +186,4 @@
 	return (__force __wsum)-1; /* invalid checksum */
 }
 
-#endif
+#endif /* ASM_X86__CHECKSUM_32_H */
diff --git a/include/asm-x86/checksum_64.h b/include/asm-x86/checksum_64.h
index 8bd861c..110f403 100644
--- a/include/asm-x86/checksum_64.h
+++ b/include/asm-x86/checksum_64.h
@@ -1,5 +1,5 @@
-#ifndef _X86_64_CHECKSUM_H
-#define _X86_64_CHECKSUM_H
+#ifndef ASM_X86__CHECKSUM_64_H
+#define ASM_X86__CHECKSUM_64_H
 
 /*
  * Checksums for x86-64
@@ -188,4 +188,4 @@
 	return a;
 }
 
-#endif
+#endif /* ASM_X86__CHECKSUM_64_H */
diff --git a/include/asm-x86/cmpxchg_32.h b/include/asm-x86/cmpxchg_32.h
index bf5a69d..0622e45 100644
--- a/include/asm-x86/cmpxchg_32.h
+++ b/include/asm-x86/cmpxchg_32.h
@@ -1,5 +1,5 @@
-#ifndef __ASM_CMPXCHG_H
-#define __ASM_CMPXCHG_H
+#ifndef ASM_X86__CMPXCHG_32_H
+#define ASM_X86__CMPXCHG_32_H
 
 #include <linux/bitops.h> /* for LOCK_PREFIX */
 
@@ -341,4 +341,4 @@
 
 #endif
 
-#endif
+#endif /* ASM_X86__CMPXCHG_32_H */
diff --git a/include/asm-x86/cmpxchg_64.h b/include/asm-x86/cmpxchg_64.h
index 17463cc..63c1a5e 100644
--- a/include/asm-x86/cmpxchg_64.h
+++ b/include/asm-x86/cmpxchg_64.h
@@ -1,5 +1,5 @@
-#ifndef __ASM_CMPXCHG_H
-#define __ASM_CMPXCHG_H
+#ifndef ASM_X86__CMPXCHG_64_H
+#define ASM_X86__CMPXCHG_64_H
 
 #include <asm/alternative.h> /* Provides LOCK_PREFIX */
 
@@ -182,4 +182,4 @@
 	cmpxchg_local((ptr), (o), (n));					\
 })
 
-#endif
+#endif /* ASM_X86__CMPXCHG_64_H */
diff --git a/include/asm-x86/compat.h b/include/asm-x86/compat.h
index 1793ac3..6732b15 100644
--- a/include/asm-x86/compat.h
+++ b/include/asm-x86/compat.h
@@ -1,5 +1,5 @@
-#ifndef _ASM_X86_64_COMPAT_H
-#define _ASM_X86_64_COMPAT_H
+#ifndef ASM_X86__COMPAT_H
+#define ASM_X86__COMPAT_H
 
 /*
  * Architecture specific compatibility types
@@ -215,4 +215,4 @@
 	return current_thread_info()->status & TS_COMPAT;
 }
 
-#endif /* _ASM_X86_64_COMPAT_H */
+#endif /* ASM_X86__COMPAT_H */
diff --git a/include/asm-x86/cpu.h b/include/asm-x86/cpu.h
index 73f2ea8..83a1150 100644
--- a/include/asm-x86/cpu.h
+++ b/include/asm-x86/cpu.h
@@ -1,5 +1,5 @@
-#ifndef _ASM_I386_CPU_H_
-#define _ASM_I386_CPU_H_
+#ifndef ASM_X86__CPU_H
+#define ASM_X86__CPU_H
 
 #include <linux/device.h>
 #include <linux/cpu.h>
@@ -17,4 +17,4 @@
 #endif
 
 DECLARE_PER_CPU(int, cpu_state);
-#endif /* _ASM_I386_CPU_H_ */
+#endif /* ASM_X86__CPU_H */
diff --git a/include/asm-x86/cpufeature.h b/include/asm-x86/cpufeature.h
index 9489283..adfeae6 100644
--- a/include/asm-x86/cpufeature.h
+++ b/include/asm-x86/cpufeature.h
@@ -1,12 +1,18 @@
 /*
  * Defines x86 CPU feature bits
  */
-#ifndef _ASM_X86_CPUFEATURE_H
-#define _ASM_X86_CPUFEATURE_H
+#ifndef ASM_X86__CPUFEATURE_H
+#define ASM_X86__CPUFEATURE_H
 
 #include <asm/required-features.h>
 
-#define NCAPINTS	8	/* N 32-bit words worth of info */
+#define NCAPINTS	9	/* N 32-bit words worth of info */
+
+/*
+ * Note: If the comment begins with a quoted string, that string is used
+ * in /proc/cpuinfo instead of the macro name.  If the string is "",
+ * this feature bit is not displayed in /proc/cpuinfo at all.
+ */
 
 /* Intel-defined CPU features, CPUID level 0x00000001 (edx), word 0 */
 #define X86_FEATURE_FPU		(0*32+ 0) /* Onboard FPU */
@@ -14,7 +20,7 @@
 #define X86_FEATURE_DE		(0*32+ 2) /* Debugging Extensions */
 #define X86_FEATURE_PSE		(0*32+ 3) /* Page Size Extensions */
 #define X86_FEATURE_TSC		(0*32+ 4) /* Time Stamp Counter */
-#define X86_FEATURE_MSR		(0*32+ 5) /* Model-Specific Registers, RDMSR, WRMSR */
+#define X86_FEATURE_MSR		(0*32+ 5) /* Model-Specific Registers */
 #define X86_FEATURE_PAE		(0*32+ 6) /* Physical Address Extensions */
 #define X86_FEATURE_MCE		(0*32+ 7) /* Machine Check Architecture */
 #define X86_FEATURE_CX8		(0*32+ 8) /* CMPXCHG8 instruction */
@@ -23,22 +29,23 @@
 #define X86_FEATURE_MTRR	(0*32+12) /* Memory Type Range Registers */
 #define X86_FEATURE_PGE		(0*32+13) /* Page Global Enable */
 #define X86_FEATURE_MCA		(0*32+14) /* Machine Check Architecture */
-#define X86_FEATURE_CMOV	(0*32+15) /* CMOV instruction (FCMOVCC and FCOMI too if FPU present) */
+#define X86_FEATURE_CMOV	(0*32+15) /* CMOV instructions */
+					  /* (plus FCMOVcc, FCOMI with FPU) */
 #define X86_FEATURE_PAT		(0*32+16) /* Page Attribute Table */
 #define X86_FEATURE_PSE36	(0*32+17) /* 36-bit PSEs */
 #define X86_FEATURE_PN		(0*32+18) /* Processor serial number */
-#define X86_FEATURE_CLFLSH	(0*32+19) /* Supports the CLFLUSH instruction */
-#define X86_FEATURE_DS		(0*32+21) /* Debug Store */
+#define X86_FEATURE_CLFLSH	(0*32+19) /* "clflush" CLFLUSH instruction */
+#define X86_FEATURE_DS		(0*32+21) /* "dts" Debug Store */
 #define X86_FEATURE_ACPI	(0*32+22) /* ACPI via MSR */
 #define X86_FEATURE_MMX		(0*32+23) /* Multimedia Extensions */
-#define X86_FEATURE_FXSR	(0*32+24) /* FXSAVE and FXRSTOR instructions (fast save and restore */
-					  /* of FPU context), and CR4.OSFXSR available */
-#define X86_FEATURE_XMM		(0*32+25) /* Streaming SIMD Extensions */
-#define X86_FEATURE_XMM2	(0*32+26) /* Streaming SIMD Extensions-2 */
-#define X86_FEATURE_SELFSNOOP	(0*32+27) /* CPU self snoop */
+#define X86_FEATURE_FXSR	(0*32+24) /* FXSAVE/FXRSTOR, CR4.OSFXSR */
+#define X86_FEATURE_XMM		(0*32+25) /* "sse" */
+#define X86_FEATURE_XMM2	(0*32+26) /* "sse2" */
+#define X86_FEATURE_SELFSNOOP	(0*32+27) /* "ss" CPU self snoop */
 #define X86_FEATURE_HT		(0*32+28) /* Hyper-Threading */
-#define X86_FEATURE_ACC		(0*32+29) /* Automatic clock control */
+#define X86_FEATURE_ACC		(0*32+29) /* "tm" Automatic clock control */
 #define X86_FEATURE_IA64	(0*32+30) /* IA-64 processor */
+#define X86_FEATURE_PBE		(0*32+31) /* Pending Break Enable */
 
 /* AMD-defined CPU features, CPUID level 0x80000001, word 1 */
 /* Don't duplicate feature flags which are redundant with Intel! */
@@ -46,7 +53,8 @@
 #define X86_FEATURE_MP		(1*32+19) /* MP Capable. */
 #define X86_FEATURE_NX		(1*32+20) /* Execute Disable */
 #define X86_FEATURE_MMXEXT	(1*32+22) /* AMD MMX extensions */
-#define X86_FEATURE_GBPAGES	(1*32+26) /* GB pages */
+#define X86_FEATURE_FXSR_OPT	(1*32+25) /* FXSAVE/FXRSTOR optimizations */
+#define X86_FEATURE_GBPAGES	(1*32+26) /* "pdpe1gb" GB pages */
 #define X86_FEATURE_RDTSCP	(1*32+27) /* RDTSCP */
 #define X86_FEATURE_LM		(1*32+29) /* Long Mode (x86-64) */
 #define X86_FEATURE_3DNOWEXT	(1*32+30) /* AMD 3DNow! extensions */
@@ -64,52 +72,79 @@
 #define X86_FEATURE_CYRIX_ARR	(3*32+ 2) /* Cyrix ARRs (= MTRRs) */
 #define X86_FEATURE_CENTAUR_MCR	(3*32+ 3) /* Centaur MCRs (= MTRRs) */
 /* cpu types for specific tunings: */
-#define X86_FEATURE_K8		(3*32+ 4) /* Opteron, Athlon64 */
-#define X86_FEATURE_K7		(3*32+ 5) /* Athlon */
-#define X86_FEATURE_P3		(3*32+ 6) /* P3 */
-#define X86_FEATURE_P4		(3*32+ 7) /* P4 */
+#define X86_FEATURE_K8		(3*32+ 4) /* "" Opteron, Athlon64 */
+#define X86_FEATURE_K7		(3*32+ 5) /* "" Athlon */
+#define X86_FEATURE_P3		(3*32+ 6) /* "" P3 */
+#define X86_FEATURE_P4		(3*32+ 7) /* "" P4 */
 #define X86_FEATURE_CONSTANT_TSC (3*32+ 8) /* TSC ticks at a constant rate */
 #define X86_FEATURE_UP		(3*32+ 9) /* smp kernel running on up */
-#define X86_FEATURE_FXSAVE_LEAK (3*32+10) /* FXSAVE leaks FOP/FIP/FOP */
+#define X86_FEATURE_FXSAVE_LEAK (3*32+10) /* "" FXSAVE leaks FOP/FIP/FOP */
 #define X86_FEATURE_ARCH_PERFMON (3*32+11) /* Intel Architectural PerfMon */
+#define X86_FEATURE_NOPL	(3*32+20) /* The NOPL (0F 1F) instructions */
 #define X86_FEATURE_PEBS	(3*32+12) /* Precise-Event Based Sampling */
 #define X86_FEATURE_BTS		(3*32+13) /* Branch Trace Store */
-#define X86_FEATURE_SYSCALL32	(3*32+14) /* syscall in ia32 userspace */
-#define X86_FEATURE_SYSENTER32	(3*32+15) /* sysenter in ia32 userspace */
-#define X86_FEATURE_REP_GOOD	(3*32+16) /* rep microcode works well on this CPU */
-#define X86_FEATURE_MFENCE_RDTSC (3*32+17) /* Mfence synchronizes RDTSC */
-#define X86_FEATURE_LFENCE_RDTSC (3*32+18) /* Lfence synchronizes RDTSC */
-#define X86_FEATURE_11AP	(3*32+19) /* Bad local APIC aka 11AP */
+#define X86_FEATURE_SYSCALL32	(3*32+14) /* "" syscall in ia32 userspace */
+#define X86_FEATURE_SYSENTER32	(3*32+15) /* "" sysenter in ia32 userspace */
+#define X86_FEATURE_REP_GOOD	(3*32+16) /* rep microcode works well */
+#define X86_FEATURE_MFENCE_RDTSC (3*32+17) /* "" Mfence synchronizes RDTSC */
+#define X86_FEATURE_LFENCE_RDTSC (3*32+18) /* "" Lfence synchronizes RDTSC */
+#define X86_FEATURE_11AP	(3*32+19) /* "" Bad local APIC aka 11AP */
 #define X86_FEATURE_NOPL	(3*32+20) /* The NOPL (0F 1F) instructions */
+#define X86_FEATURE_AMDC1E	(3*32+21) /* AMD C1E detected */
+#define X86_FEATURE_XTOPOLOGY	(3*32+21) /* cpu topology enum extensions */
 
 /* Intel-defined CPU features, CPUID level 0x00000001 (ecx), word 4 */
-#define X86_FEATURE_XMM3	(4*32+ 0) /* Streaming SIMD Extensions-3 */
-#define X86_FEATURE_MWAIT	(4*32+ 3) /* Monitor/Mwait support */
-#define X86_FEATURE_DSCPL	(4*32+ 4) /* CPL Qualified Debug Store */
+#define X86_FEATURE_XMM3	(4*32+ 0) /* "pni" SSE-3 */
+#define X86_FEATURE_PCLMULQDQ	(4*32+ 1) /* PCLMULQDQ instruction */
+#define X86_FEATURE_DTES64	(4*32+ 2) /* 64-bit Debug Store */
+#define X86_FEATURE_MWAIT	(4*32+ 3) /* "monitor" Monitor/Mwait support */
+#define X86_FEATURE_DSCPL	(4*32+ 4) /* "ds_cpl" CPL Qual. Debug Store */
+#define X86_FEATURE_VMX		(4*32+ 5) /* Hardware virtualization */
+#define X86_FEATURE_SMX		(4*32+ 6) /* Safer mode */
 #define X86_FEATURE_EST		(4*32+ 7) /* Enhanced SpeedStep */
 #define X86_FEATURE_TM2		(4*32+ 8) /* Thermal Monitor 2 */
+#define X86_FEATURE_SSSE3	(4*32+ 9) /* Supplemental SSE-3 */
 #define X86_FEATURE_CID		(4*32+10) /* Context ID */
+#define X86_FEATURE_FMA		(4*32+12) /* Fused multiply-add */
 #define X86_FEATURE_CX16	(4*32+13) /* CMPXCHG16B */
 #define X86_FEATURE_XTPR	(4*32+14) /* Send Task Priority Messages */
+#define X86_FEATURE_PDCM	(4*32+15) /* Performance Capabilities */
 #define X86_FEATURE_DCA		(4*32+18) /* Direct Cache Access */
-#define X86_FEATURE_XMM4_2	(4*32+20) /* Streaming SIMD Extensions-4.2 */
+#define X86_FEATURE_XMM4_1	(4*32+19) /* "sse4_1" SSE-4.1 */
+#define X86_FEATURE_XMM4_2	(4*32+20) /* "sse4_2" SSE-4.2 */
+#define X86_FEATURE_X2APIC	(4*32+21) /* x2APIC */
+#define X86_FEATURE_AES		(4*32+25) /* AES instructions */
+#define X86_FEATURE_XSAVE	(4*32+26) /* XSAVE/XRSTOR/XSETBV/XGETBV */
+#define X86_FEATURE_OSXSAVE	(4*32+27) /* "" XSAVE enabled in the OS */
+#define X86_FEATURE_AVX		(4*32+28) /* Advanced Vector Extensions */
 
 /* VIA/Cyrix/Centaur-defined CPU features, CPUID level 0xC0000001, word 5 */
-#define X86_FEATURE_XSTORE	(5*32+ 2) /* on-CPU RNG present (xstore insn) */
-#define X86_FEATURE_XSTORE_EN	(5*32+ 3) /* on-CPU RNG enabled */
-#define X86_FEATURE_XCRYPT	(5*32+ 6) /* on-CPU crypto (xcrypt insn) */
-#define X86_FEATURE_XCRYPT_EN	(5*32+ 7) /* on-CPU crypto enabled */
+#define X86_FEATURE_XSTORE	(5*32+ 2) /* "rng" RNG present (xstore) */
+#define X86_FEATURE_XSTORE_EN	(5*32+ 3) /* "rng_en" RNG enabled */
+#define X86_FEATURE_XCRYPT	(5*32+ 6) /* "ace" on-CPU crypto (xcrypt) */
+#define X86_FEATURE_XCRYPT_EN	(5*32+ 7) /* "ace_en" on-CPU crypto enabled */
 #define X86_FEATURE_ACE2	(5*32+ 8) /* Advanced Cryptography Engine v2 */
 #define X86_FEATURE_ACE2_EN	(5*32+ 9) /* ACE v2 enabled */
-#define X86_FEATURE_PHE		(5*32+ 10) /* PadLock Hash Engine */
-#define X86_FEATURE_PHE_EN	(5*32+ 11) /* PHE enabled */
-#define X86_FEATURE_PMM		(5*32+ 12) /* PadLock Montgomery Multiplier */
-#define X86_FEATURE_PMM_EN	(5*32+ 13) /* PMM enabled */
+#define X86_FEATURE_PHE		(5*32+10) /* PadLock Hash Engine */
+#define X86_FEATURE_PHE_EN	(5*32+11) /* PHE enabled */
+#define X86_FEATURE_PMM		(5*32+12) /* PadLock Montgomery Multiplier */
+#define X86_FEATURE_PMM_EN	(5*32+13) /* PMM enabled */
 
 /* More extended AMD flags: CPUID level 0x80000001, ecx, word 6 */
 #define X86_FEATURE_LAHF_LM	(6*32+ 0) /* LAHF/SAHF in long mode */
 #define X86_FEATURE_CMP_LEGACY	(6*32+ 1) /* If yes HyperThreading not valid */
-#define X86_FEATURE_IBS		(6*32+ 10) /* Instruction Based Sampling */
+#define X86_FEATURE_SVM		(6*32+ 2) /* Secure virtual machine */
+#define X86_FEATURE_EXTAPIC	(6*32+ 3) /* Extended APIC space */
+#define X86_FEATURE_CR8_LEGACY	(6*32+ 4) /* CR8 in 32-bit mode */
+#define X86_FEATURE_ABM		(6*32+ 5) /* Advanced bit manipulation */
+#define X86_FEATURE_SSE4A	(6*32+ 6) /* SSE-4A */
+#define X86_FEATURE_MISALIGNSSE (6*32+ 7) /* Misaligned SSE mode */
+#define X86_FEATURE_3DNOWPREFETCH (6*32+ 8) /* 3DNow prefetch instructions */
+#define X86_FEATURE_OSVW	(6*32+ 9) /* OS Visible Workaround */
+#define X86_FEATURE_IBS		(6*32+10) /* Instruction Based Sampling */
+#define X86_FEATURE_SSE5	(6*32+11) /* SSE-5 */
+#define X86_FEATURE_SKINIT	(6*32+12) /* SKINIT/STGI instructions */
+#define X86_FEATURE_WDT		(6*32+13) /* Watchdog timer */
 
 /*
  * Auxiliary flags: Linux defined - For features scattered in various
@@ -117,6 +152,13 @@
  */
 #define X86_FEATURE_IDA		(7*32+ 0) /* Intel Dynamic Acceleration */
 
+/* Virtualization flags: Linux defined */
+#define X86_FEATURE_TPR_SHADOW  (8*32+ 0) /* Intel TPR Shadow */
+#define X86_FEATURE_VNMI        (8*32+ 1) /* Intel Virtual NMI */
+#define X86_FEATURE_FLEXPRIORITY (8*32+ 2) /* Intel FlexPriority */
+#define X86_FEATURE_EPT         (8*32+ 3) /* Intel Extended Page Table */
+#define X86_FEATURE_VPID        (8*32+ 4) /* Intel Virtual Processor ID */
+
 #if defined(__KERNEL__) && !defined(__ASSEMBLY__)
 
 #include <linux/bitops.h>
@@ -150,7 +192,7 @@
 } while (0)
 #define setup_force_cpu_cap(bit) do { \
 	set_cpu_cap(&boot_cpu_data, bit);	\
-	clear_bit(bit, (unsigned long *)cleared_cpu_caps); 	\
+	clear_bit(bit, (unsigned long *)cleared_cpu_caps);	\
 } while (0)
 
 #define cpu_has_fpu		boot_cpu_has(X86_FEATURE_FPU)
@@ -191,7 +233,10 @@
 #define cpu_has_gbpages		boot_cpu_has(X86_FEATURE_GBPAGES)
 #define cpu_has_arch_perfmon	boot_cpu_has(X86_FEATURE_ARCH_PERFMON)
 #define cpu_has_pat		boot_cpu_has(X86_FEATURE_PAT)
+#define cpu_has_xmm4_1		boot_cpu_has(X86_FEATURE_XMM4_1)
 #define cpu_has_xmm4_2		boot_cpu_has(X86_FEATURE_XMM4_2)
+#define cpu_has_x2apic		boot_cpu_has(X86_FEATURE_X2APIC)
+#define cpu_has_xsave		boot_cpu_has(X86_FEATURE_XSAVE)
 
 #if defined(CONFIG_X86_INVLPG) || defined(CONFIG_X86_64)
 # define cpu_has_invlpg		1
@@ -223,4 +268,4 @@
 
 #endif /* defined(__KERNEL__) && !defined(__ASSEMBLY__) */
 
-#endif /* _ASM_X86_CPUFEATURE_H */
+#endif /* ASM_X86__CPUFEATURE_H */
diff --git a/include/asm-x86/current.h b/include/asm-x86/current.h
index 7515c19..a863ead 100644
--- a/include/asm-x86/current.h
+++ b/include/asm-x86/current.h
@@ -1,5 +1,5 @@
-#ifndef _X86_CURRENT_H
-#define _X86_CURRENT_H
+#ifndef ASM_X86__CURRENT_H
+#define ASM_X86__CURRENT_H
 
 #ifdef CONFIG_X86_32
 #include <linux/compiler.h>
@@ -36,4 +36,4 @@
 
 #define current get_current()
 
-#endif /* X86_CURRENT_H */
+#endif /* ASM_X86__CURRENT_H */
diff --git a/include/asm-x86/debugreg.h b/include/asm-x86/debugreg.h
index c6344d5..ecb6907 100644
--- a/include/asm-x86/debugreg.h
+++ b/include/asm-x86/debugreg.h
@@ -1,5 +1,5 @@
-#ifndef _ASM_X86_DEBUGREG_H
-#define _ASM_X86_DEBUGREG_H
+#ifndef ASM_X86__DEBUGREG_H
+#define ASM_X86__DEBUGREG_H
 
 
 /* Indicate the register numbers for a number of the specific
@@ -67,4 +67,4 @@
 #define DR_LOCAL_SLOWDOWN (0x100)   /* Local slow the pipeline */
 #define DR_GLOBAL_SLOWDOWN (0x200)  /* Global slow the pipeline */
 
-#endif
+#endif /* ASM_X86__DEBUGREG_H */
diff --git a/include/asm-x86/delay.h b/include/asm-x86/delay.h
index 409a649..8a0da95 100644
--- a/include/asm-x86/delay.h
+++ b/include/asm-x86/delay.h
@@ -1,5 +1,5 @@
-#ifndef _ASM_X86_DELAY_H
-#define _ASM_X86_DELAY_H
+#ifndef ASM_X86__DELAY_H
+#define ASM_X86__DELAY_H
 
 /*
  * Copyright (C) 1993 Linus Torvalds
@@ -28,4 +28,4 @@
 
 void use_tsc_delay(void);
 
-#endif /* _ASM_X86_DELAY_H */
+#endif /* ASM_X86__DELAY_H */
diff --git a/include/asm-x86/desc.h b/include/asm-x86/desc.h
index a44c4dc..f06adac 100644
--- a/include/asm-x86/desc.h
+++ b/include/asm-x86/desc.h
@@ -1,5 +1,5 @@
-#ifndef _ASM_DESC_H_
-#define _ASM_DESC_H_
+#ifndef ASM_X86__DESC_H
+#define ASM_X86__DESC_H
 
 #ifndef __ASSEMBLY__
 #include <asm/desc_defs.h>
@@ -24,6 +24,11 @@
 	desc->d = info->seg_32bit;
 	desc->g = info->limit_in_pages;
 	desc->base2 = (info->base_addr & 0xff000000) >> 24;
+	/*
+	 * Don't allow setting of the lm bit. It is useless anyway
+	 * because 64bit system calls require __USER_CS:
+	 */
+	desc->l = 0;
 }
 
 extern struct desc_ptr idt_descr;
@@ -97,7 +102,15 @@
 	native_write_gdt_entry(dt, entry, desc, type)
 #define write_idt_entry(dt, entry, g)		\
 	native_write_idt_entry(dt, entry, g)
-#endif
+
+static inline void paravirt_alloc_ldt(struct desc_struct *ldt, unsigned entries)
+{
+}
+
+static inline void paravirt_free_ldt(struct desc_struct *ldt, unsigned entries)
+{
+}
+#endif	/* CONFIG_PARAVIRT */
 
 static inline void native_write_idt_entry(gate_desc *idt, int entry,
 					  const gate_desc *gate)
@@ -338,22 +351,18 @@
 	_set_gate(n, GATE_INTERRUPT, addr, 0x3, 0, __KERNEL_CS);
 }
 
+static inline void set_system_trap_gate(unsigned int n, void *addr)
+{
+	BUG_ON((unsigned)n > 0xFF);
+	_set_gate(n, GATE_TRAP, addr, 0x3, 0, __KERNEL_CS);
+}
+
 static inline void set_trap_gate(unsigned int n, void *addr)
 {
 	BUG_ON((unsigned)n > 0xFF);
 	_set_gate(n, GATE_TRAP, addr, 0, 0, __KERNEL_CS);
 }
 
-static inline void set_system_gate(unsigned int n, void *addr)
-{
-	BUG_ON((unsigned)n > 0xFF);
-#ifdef CONFIG_X86_32
-	_set_gate(n, GATE_TRAP, addr, 0x3, 0, __KERNEL_CS);
-#else
-	_set_gate(n, GATE_INTERRUPT, addr, 0x3, 0, __KERNEL_CS);
-#endif
-}
-
 static inline void set_task_gate(unsigned int n, unsigned int gdt_entry)
 {
 	BUG_ON((unsigned)n > 0xFF);
@@ -366,7 +375,7 @@
 	_set_gate(n, GATE_INTERRUPT, addr, 0, ist, __KERNEL_CS);
 }
 
-static inline void set_system_gate_ist(int n, void *addr, unsigned ist)
+static inline void set_system_intr_gate_ist(int n, void *addr, unsigned ist)
 {
 	BUG_ON((unsigned)n > 0xFF);
 	_set_gate(n, GATE_INTERRUPT, addr, 0x3, ist, __KERNEL_CS);
@@ -397,4 +406,4 @@
 
 #endif /* __ASSEMBLY__ */
 
-#endif
+#endif /* ASM_X86__DESC_H */
diff --git a/include/asm-x86/desc_defs.h b/include/asm-x86/desc_defs.h
index f7bacf3..b881db6 100644
--- a/include/asm-x86/desc_defs.h
+++ b/include/asm-x86/desc_defs.h
@@ -1,6 +1,6 @@
 /* Written 2000 by Andi Kleen */
-#ifndef __ARCH_DESC_DEFS_H
-#define __ARCH_DESC_DEFS_H
+#ifndef ASM_X86__DESC_DEFS_H
+#define ASM_X86__DESC_DEFS_H
 
 /*
  * Segment descriptor structure definitions, usable from both x86_64 and i386
@@ -92,4 +92,4 @@
 
 #endif /* !__ASSEMBLY__ */
 
-#endif
+#endif /* ASM_X86__DESC_DEFS_H */
diff --git a/include/asm-x86/device.h b/include/asm-x86/device.h
index 3c034f4..1bece04 100644
--- a/include/asm-x86/device.h
+++ b/include/asm-x86/device.h
@@ -1,5 +1,5 @@
-#ifndef _ASM_X86_DEVICE_H
-#define _ASM_X86_DEVICE_H
+#ifndef ASM_X86__DEVICE_H
+#define ASM_X86__DEVICE_H
 
 struct dev_archdata {
 #ifdef CONFIG_ACPI
@@ -13,4 +13,4 @@
 #endif
 };
 
-#endif /* _ASM_X86_DEVICE_H */
+#endif /* ASM_X86__DEVICE_H */
diff --git a/include/asm-x86/div64.h b/include/asm-x86/div64.h
index 9a2d644..f9530f2 100644
--- a/include/asm-x86/div64.h
+++ b/include/asm-x86/div64.h
@@ -1,5 +1,5 @@
-#ifndef _ASM_X86_DIV64_H
-#define _ASM_X86_DIV64_H
+#ifndef ASM_X86__DIV64_H
+#define ASM_X86__DIV64_H
 
 #ifdef CONFIG_X86_32
 
@@ -57,4 +57,4 @@
 # include <asm-generic/div64.h>
 #endif /* CONFIG_X86_32 */
 
-#endif /* _ASM_X86_DIV64_H */
+#endif /* ASM_X86__DIV64_H */
diff --git a/include/asm-x86/dma-mapping.h b/include/asm-x86/dma-mapping.h
index ad9cd6d..219c33d 100644
--- a/include/asm-x86/dma-mapping.h
+++ b/include/asm-x86/dma-mapping.h
@@ -1,5 +1,5 @@
-#ifndef _ASM_DMA_MAPPING_H_
-#define _ASM_DMA_MAPPING_H_
+#ifndef ASM_X86__DMA_MAPPING_H
+#define ASM_X86__DMA_MAPPING_H
 
 /*
  * IOMMU interface. See Documentation/DMA-mapping.txt and DMA-API.txt for
@@ -9,12 +9,12 @@
 #include <linux/scatterlist.h>
 #include <asm/io.h>
 #include <asm/swiotlb.h>
+#include <asm-generic/dma-coherent.h>
 
 extern dma_addr_t bad_dma_address;
 extern int iommu_merge;
-extern struct device fallback_dev;
+extern struct device x86_dma_fallback_dev;
 extern int panic_on_overflow;
-extern int force_iommu;
 
 struct dma_mapping_ops {
 	int             (*mapping_error)(struct device *dev,
@@ -25,9 +25,6 @@
 				void *vaddr, dma_addr_t dma_handle);
 	dma_addr_t      (*map_single)(struct device *hwdev, phys_addr_t ptr,
 				size_t size, int direction);
-	/* like map_single, but doesn't check the device mask */
-	dma_addr_t      (*map_simple)(struct device *hwdev, phys_addr_t ptr,
-				size_t size, int direction);
 	void            (*unmap_single)(struct device *dev, dma_addr_t addr,
 				size_t size, int direction);
 	void            (*sync_single_for_cpu)(struct device *hwdev,
@@ -68,7 +65,7 @@
 		return dma_ops;
 	else
 		return dev->archdata.dma_ops;
-#endif
+#endif /* ASM_X86__DMA_MAPPING_H */
 }
 
 /* Make sure we keep the same behaviour */
@@ -87,17 +84,14 @@
 
 #define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f)
 #define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h)
-
-void *dma_alloc_coherent(struct device *dev, size_t size,
-			   dma_addr_t *dma_handle, gfp_t flag);
-
-void dma_free_coherent(struct device *dev, size_t size,
-			 void *vaddr, dma_addr_t dma_handle);
-
+#define dma_is_consistent(d, h)	(1)
 
 extern int dma_supported(struct device *hwdev, u64 mask);
 extern int dma_set_mask(struct device *dev, u64 mask);
 
+extern void *dma_generic_alloc_coherent(struct device *dev, size_t size,
+					dma_addr_t *dma_addr, gfp_t flag);
+
 static inline dma_addr_t
 dma_map_single(struct device *hwdev, void *ptr, size_t size,
 	       int direction)
@@ -247,7 +241,68 @@
 	return boot_cpu_data.x86_clflush_size;
 }
 
-#define dma_is_consistent(d, h)	(1)
+static inline unsigned long dma_alloc_coherent_mask(struct device *dev,
+						    gfp_t gfp)
+{
+	unsigned long dma_mask = 0;
 
-#include <asm-generic/dma-coherent.h>
+	dma_mask = dev->coherent_dma_mask;
+	if (!dma_mask)
+		dma_mask = (gfp & GFP_DMA) ? DMA_24BIT_MASK : DMA_32BIT_MASK;
+
+	return dma_mask;
+}
+
+static inline gfp_t dma_alloc_coherent_gfp_flags(struct device *dev, gfp_t gfp)
+{
+#ifdef CONFIG_X86_64
+	unsigned long dma_mask = dma_alloc_coherent_mask(dev, gfp);
+
+	if (dma_mask <= DMA_32BIT_MASK && !(gfp & GFP_DMA))
+		gfp |= GFP_DMA32;
+#endif
+       return gfp;
+}
+
+static inline void *
+dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle,
+		gfp_t gfp)
+{
+	struct dma_mapping_ops *ops = get_dma_ops(dev);
+	void *memory;
+
+	gfp &= ~(__GFP_DMA | __GFP_HIGHMEM | __GFP_DMA32);
+
+	if (dma_alloc_from_coherent(dev, size, dma_handle, &memory))
+		return memory;
+
+	if (!dev) {
+		dev = &x86_dma_fallback_dev;
+		gfp |= GFP_DMA;
+	}
+
+	if (!is_device_dma_capable(dev))
+		return NULL;
+
+	if (!ops->alloc_coherent)
+		return NULL;
+
+	return ops->alloc_coherent(dev, size, dma_handle,
+				   dma_alloc_coherent_gfp_flags(dev, gfp));
+}
+
+static inline void dma_free_coherent(struct device *dev, size_t size,
+				     void *vaddr, dma_addr_t bus)
+{
+	struct dma_mapping_ops *ops = get_dma_ops(dev);
+
+	WARN_ON(irqs_disabled());       /* for portability */
+
+	if (dma_release_from_coherent(dev, get_order(size), vaddr))
+		return;
+
+	if (ops->free_coherent)
+		ops->free_coherent(dev, size, vaddr, bus);
+}
+
 #endif
diff --git a/include/asm-x86/dma.h b/include/asm-x86/dma.h
index ca1098a..c9f7a4e 100644
--- a/include/asm-x86/dma.h
+++ b/include/asm-x86/dma.h
@@ -5,8 +5,8 @@
  * and John Boyd, Nov. 1992.
  */
 
-#ifndef _ASM_X86_DMA_H
-#define _ASM_X86_DMA_H
+#ifndef ASM_X86__DMA_H
+#define ASM_X86__DMA_H
 
 #include <linux/spinlock.h>	/* And spinlocks */
 #include <asm/io.h>		/* need byte IO */
@@ -315,4 +315,4 @@
 #define isa_dma_bridge_buggy	(0)
 #endif
 
-#endif /* _ASM_X86_DMA_H */
+#endif /* ASM_X86__DMA_H */
diff --git a/include/asm-x86/dmi.h b/include/asm-x86/dmi.h
index 58a8657..1cff6fe 100644
--- a/include/asm-x86/dmi.h
+++ b/include/asm-x86/dmi.h
@@ -1,5 +1,5 @@
-#ifndef _ASM_X86_DMI_H
-#define _ASM_X86_DMI_H
+#ifndef ASM_X86__DMI_H
+#define ASM_X86__DMI_H
 
 #include <asm/io.h>
 
@@ -23,4 +23,4 @@
 #define dmi_ioremap early_ioremap
 #define dmi_iounmap early_iounmap
 
-#endif
+#endif /* ASM_X86__DMI_H */
diff --git a/include/asm-x86/ds.h b/include/asm-x86/ds.h
index 7881368..c3c953a 100644
--- a/include/asm-x86/ds.h
+++ b/include/asm-x86/ds.h
@@ -2,71 +2,237 @@
  * Debug Store (DS) support
  *
  * This provides a low-level interface to the hardware's Debug Store
- * feature that is used for last branch recording (LBR) and
+ * feature that is used for branch trace store (BTS) and
  * precise-event based sampling (PEBS).
  *
- * Different architectures use a different DS layout/pointer size.
- * The below functions therefore work on a void*.
+ * It manages:
+ * - per-thread and per-cpu allocation of BTS and PEBS
+ * - buffer memory allocation (optional)
+ * - buffer overflow handling
+ * - buffer access
+ *
+ * It assumes:
+ * - get_task_struct on all parameter tasks
+ * - current is allowed to trace parameter tasks
  *
  *
- * Since there is no user for PEBS, yet, only LBR (or branch
- * trace store, BTS) is supported.
- *
- *
- * Copyright (C) 2007 Intel Corporation.
- * Markus Metzger <markus.t.metzger@intel.com>, Dec 2007
+ * Copyright (C) 2007-2008 Intel Corporation.
+ * Markus Metzger <markus.t.metzger@intel.com>, 2007-2008
  */
 
-#ifndef _ASM_X86_DS_H
-#define _ASM_X86_DS_H
+#ifndef ASM_X86__DS_H
+#define ASM_X86__DS_H
+
+#ifdef CONFIG_X86_DS
 
 #include <linux/types.h>
 #include <linux/init.h>
 
-struct cpuinfo_x86;
 
+struct task_struct;
 
-/* a branch trace record entry
+/*
+ * Request BTS or PEBS
  *
- * In order to unify the interface between various processor versions,
- * we use the below data structure for all processors.
+ * Due to alignement constraints, the actual buffer may be slightly
+ * smaller than the requested or provided buffer.
+ *
+ * Returns 0 on success; -Eerrno otherwise
+ *
+ * task: the task to request recording for;
+ *       NULL for per-cpu recording on the current cpu
+ * base: the base pointer for the (non-pageable) buffer;
+ *       NULL if buffer allocation requested
+ * size: the size of the requested or provided buffer
+ * ovfl: pointer to a function to be called on buffer overflow;
+ *       NULL if cyclic buffer requested
  */
-enum bts_qualifier {
-	BTS_INVALID = 0,
-	BTS_BRANCH,
-	BTS_TASK_ARRIVES,
-	BTS_TASK_DEPARTS
+typedef void (*ds_ovfl_callback_t)(struct task_struct *);
+extern int ds_request_bts(struct task_struct *task, void *base, size_t size,
+			  ds_ovfl_callback_t ovfl);
+extern int ds_request_pebs(struct task_struct *task, void *base, size_t size,
+			   ds_ovfl_callback_t ovfl);
+
+/*
+ * Release BTS or PEBS resources
+ *
+ * Frees buffers allocated on ds_request.
+ *
+ * Returns 0 on success; -Eerrno otherwise
+ *
+ * task: the task to release resources for;
+ *       NULL to release resources for the current cpu
+ */
+extern int ds_release_bts(struct task_struct *task);
+extern int ds_release_pebs(struct task_struct *task);
+
+/*
+ * Return the (array) index of the write pointer.
+ * (assuming an array of BTS/PEBS records)
+ *
+ * Returns -Eerrno on error
+ *
+ * task: the task to access;
+ *       NULL to access the current cpu
+ * pos (out): if not NULL, will hold the result
+ */
+extern int ds_get_bts_index(struct task_struct *task, size_t *pos);
+extern int ds_get_pebs_index(struct task_struct *task, size_t *pos);
+
+/*
+ * Return the (array) index one record beyond the end of the array.
+ * (assuming an array of BTS/PEBS records)
+ *
+ * Returns -Eerrno on error
+ *
+ * task: the task to access;
+ *       NULL to access the current cpu
+ * pos (out): if not NULL, will hold the result
+ */
+extern int ds_get_bts_end(struct task_struct *task, size_t *pos);
+extern int ds_get_pebs_end(struct task_struct *task, size_t *pos);
+
+/*
+ * Provide a pointer to the BTS/PEBS record at parameter index.
+ * (assuming an array of BTS/PEBS records)
+ *
+ * The pointer points directly into the buffer. The user is
+ * responsible for copying the record.
+ *
+ * Returns the size of a single record on success; -Eerrno on error
+ *
+ * task: the task to access;
+ *       NULL to access the current cpu
+ * index: the index of the requested record
+ * record (out): pointer to the requested record
+ */
+extern int ds_access_bts(struct task_struct *task,
+			 size_t index, const void **record);
+extern int ds_access_pebs(struct task_struct *task,
+			  size_t index, const void **record);
+
+/*
+ * Write one or more BTS/PEBS records at the write pointer index and
+ * advance the write pointer.
+ *
+ * If size is not a multiple of the record size, trailing bytes are
+ * zeroed out.
+ *
+ * May result in one or more overflow notifications.
+ *
+ * If called during overflow handling, that is, with index >=
+ * interrupt threshold, the write will wrap around.
+ *
+ * An overflow notification is given if and when the interrupt
+ * threshold is reached during or after the write.
+ *
+ * Returns the number of bytes written or -Eerrno.
+ *
+ * task: the task to access;
+ *       NULL to access the current cpu
+ * buffer: the buffer to write
+ * size: the size of the buffer
+ */
+extern int ds_write_bts(struct task_struct *task,
+			const void *buffer, size_t size);
+extern int ds_write_pebs(struct task_struct *task,
+			 const void *buffer, size_t size);
+
+/*
+ * Same as ds_write_bts/pebs, but omit ownership checks.
+ *
+ * This is needed to have some other task than the owner of the
+ * BTS/PEBS buffer or the parameter task itself write into the
+ * respective buffer.
+ */
+extern int ds_unchecked_write_bts(struct task_struct *task,
+				  const void *buffer, size_t size);
+extern int ds_unchecked_write_pebs(struct task_struct *task,
+				   const void *buffer, size_t size);
+
+/*
+ * Reset the write pointer of the BTS/PEBS buffer.
+ *
+ * Returns 0 on success; -Eerrno on error
+ *
+ * task: the task to access;
+ *       NULL to access the current cpu
+ */
+extern int ds_reset_bts(struct task_struct *task);
+extern int ds_reset_pebs(struct task_struct *task);
+
+/*
+ * Clear the BTS/PEBS buffer and reset the write pointer.
+ * The entire buffer will be zeroed out.
+ *
+ * Returns 0 on success; -Eerrno on error
+ *
+ * task: the task to access;
+ *       NULL to access the current cpu
+ */
+extern int ds_clear_bts(struct task_struct *task);
+extern int ds_clear_pebs(struct task_struct *task);
+
+/*
+ * Provide the PEBS counter reset value.
+ *
+ * Returns 0 on success; -Eerrno on error
+ *
+ * task: the task to access;
+ *       NULL to access the current cpu
+ * value (out): the counter reset value
+ */
+extern int ds_get_pebs_reset(struct task_struct *task, u64 *value);
+
+/*
+ * Set the PEBS counter reset value.
+ *
+ * Returns 0 on success; -Eerrno on error
+ *
+ * task: the task to access;
+ *       NULL to access the current cpu
+ * value: the new counter reset value
+ */
+extern int ds_set_pebs_reset(struct task_struct *task, u64 value);
+
+/*
+ * Initialization
+ */
+struct cpuinfo_x86;
+extern void __cpuinit ds_init_intel(struct cpuinfo_x86 *);
+
+
+
+/*
+ * The DS context - part of struct thread_struct.
+ */
+struct ds_context {
+	/* pointer to the DS configuration; goes into MSR_IA32_DS_AREA */
+	unsigned char *ds;
+	/* the owner of the BTS and PEBS configuration, respectively */
+	struct task_struct *owner[2];
+	/* buffer overflow notification function for BTS and PEBS */
+	ds_ovfl_callback_t callback[2];
+	/* the original buffer address */
+	void *buffer[2];
+	/* the number of allocated pages for on-request allocated buffers */
+	unsigned int pages[2];
+	/* use count */
+	unsigned long count;
+	/* a pointer to the context location inside the thread_struct
+	 * or the per_cpu context array */
+	struct ds_context **this;
+	/* a pointer to the task owning this context, or NULL, if the
+	 * context is owned by a cpu */
+	struct task_struct *task;
 };
 
-struct bts_struct {
-	u64 qualifier;
-	union {
-		/* BTS_BRANCH */
-		struct {
-			u64 from_ip;
-			u64 to_ip;
-		} lbr;
-		/* BTS_TASK_ARRIVES or
-		   BTS_TASK_DEPARTS */
-		u64 jiffies;
-	} variant;
-};
+/* called by exit_thread() to free leftover contexts */
+extern void ds_free(struct ds_context *context);
 
-/* Overflow handling mechanisms */
-#define DS_O_SIGNAL	1 /* send overflow signal */
-#define DS_O_WRAP	2 /* wrap around */
+#else /* CONFIG_X86_DS */
 
-extern int ds_allocate(void **, size_t);
-extern int ds_free(void **);
-extern int ds_get_bts_size(void *);
-extern int ds_get_bts_end(void *);
-extern int ds_get_bts_index(void *);
-extern int ds_set_overflow(void *, int);
-extern int ds_get_overflow(void *);
-extern int ds_clear(void *);
-extern int ds_read_bts(void *, int, struct bts_struct *);
-extern int ds_write_bts(void *, const struct bts_struct *);
-extern unsigned long ds_debugctl_mask(void);
-extern void __cpuinit ds_init_intel(struct cpuinfo_x86 *c);
+#define ds_init_intel(config) do {} while (0)
 
-#endif /* _ASM_X86_DS_H */
+#endif /* CONFIG_X86_DS */
+#endif /* ASM_X86__DS_H */
diff --git a/include/asm-x86/dwarf2.h b/include/asm-x86/dwarf2.h
index 738bb9f..21d1bc3 100644
--- a/include/asm-x86/dwarf2.h
+++ b/include/asm-x86/dwarf2.h
@@ -1,5 +1,5 @@
-#ifndef _DWARF2_H
-#define _DWARF2_H
+#ifndef ASM_X86__DWARF2_H
+#define ASM_X86__DWARF2_H
 
 #ifndef __ASSEMBLY__
 #warning "asm/dwarf2.h should be only included in pure assembly files"
@@ -58,4 +58,4 @@
 
 #endif
 
-#endif
+#endif /* ASM_X86__DWARF2_H */
diff --git a/include/asm-x86/e820.h b/include/asm-x86/e820.h
index 16a31e2..5abbdec 100644
--- a/include/asm-x86/e820.h
+++ b/include/asm-x86/e820.h
@@ -1,5 +1,5 @@
-#ifndef __ASM_E820_H
-#define __ASM_E820_H
+#ifndef ASM_X86__E820_H
+#define ASM_X86__E820_H
 #define E820MAP	0x2d0		/* our map */
 #define E820MAX	128		/* number of entries in E820MAP */
 
@@ -43,6 +43,7 @@
 #define E820_RESERVED	2
 #define E820_ACPI	3
 #define E820_NVS	4
+#define E820_UNUSABLE	5
 
 /* reserved RAM used by kernel itself */
 #define E820_RESERVED_KERN        128
@@ -64,6 +65,7 @@
 extern struct e820map e820;
 extern struct e820map e820_saved;
 
+extern unsigned long pci_mem_start;
 extern int e820_any_mapped(u64 start, u64 end, unsigned type);
 extern int e820_all_mapped(u64 start, u64 end, unsigned type);
 extern void e820_add_region(u64 start, u64 size, int type);
@@ -120,6 +122,7 @@
 extern u64 e820_hole_size(u64 start, u64 end);
 extern void finish_e820_parsing(void);
 extern void e820_reserve_resources(void);
+extern void e820_reserve_resources_late(void);
 extern void setup_memory_map(void);
 extern char *default_machine_specific_memory_setup(void);
 extern char *machine_specific_memory_setup(void);
@@ -140,4 +143,4 @@
 #define HIGH_MEMORY	(1024*1024)
 #endif /* __KERNEL__ */
 
-#endif  /* __ASM_E820_H */
+#endif /* ASM_X86__E820_H */
diff --git a/include/asm-x86/edac.h b/include/asm-x86/edac.h
index a8088f6..9493c5b 100644
--- a/include/asm-x86/edac.h
+++ b/include/asm-x86/edac.h
@@ -1,5 +1,5 @@
-#ifndef _ASM_X86_EDAC_H
-#define _ASM_X86_EDAC_H
+#ifndef ASM_X86__EDAC_H
+#define ASM_X86__EDAC_H
 
 /* ECC atomic, DMA, SMP and interrupt safe scrub function */
 
@@ -15,4 +15,4 @@
 		asm volatile("lock; addl $0, %0"::"m" (*virt_addr));
 }
 
-#endif
+#endif /* ASM_X86__EDAC_H */
diff --git a/include/asm-x86/efi.h b/include/asm-x86/efi.h
index d4f2b0a..ed2de22 100644
--- a/include/asm-x86/efi.h
+++ b/include/asm-x86/efi.h
@@ -1,5 +1,5 @@
-#ifndef _ASM_X86_EFI_H
-#define _ASM_X86_EFI_H
+#ifndef ASM_X86__EFI_H
+#define ASM_X86__EFI_H
 
 #ifdef CONFIG_X86_32
 
@@ -94,4 +94,4 @@
 extern void efi_call_phys_prelog(void);
 extern void efi_call_phys_epilog(void);
 
-#endif
+#endif /* ASM_X86__EFI_H */
diff --git a/include/asm-x86/elf.h b/include/asm-x86/elf.h
index 7be4733..5c4745b 100644
--- a/include/asm-x86/elf.h
+++ b/include/asm-x86/elf.h
@@ -1,5 +1,5 @@
-#ifndef _ASM_X86_ELF_H
-#define _ASM_X86_ELF_H
+#ifndef ASM_X86__ELF_H
+#define ASM_X86__ELF_H
 
 /*
  * ELF register definitions..
@@ -148,8 +148,9 @@
 
 static inline void start_ia32_thread(struct pt_regs *regs, u32 ip, u32 sp)
 {
-	asm volatile("movl %0,%%fs" :: "r" (0));
-	asm volatile("movl %0,%%es; movl %0,%%ds" : : "r" (__USER32_DS));
+	loadsegment(fs, 0);
+	loadsegment(ds, __USER32_DS);
+	loadsegment(es, __USER32_DS);
 	load_gs_index(0);
 	regs->ip = ip;
 	regs->sp = sp;
@@ -332,4 +333,4 @@
 extern unsigned long arch_randomize_brk(struct mm_struct *mm);
 #define arch_randomize_brk arch_randomize_brk
 
-#endif
+#endif /* ASM_X86__ELF_H */
diff --git a/include/asm-x86/emergency-restart.h b/include/asm-x86/emergency-restart.h
index 8e6aef1..190d0d8 100644
--- a/include/asm-x86/emergency-restart.h
+++ b/include/asm-x86/emergency-restart.h
@@ -1,5 +1,5 @@
-#ifndef _ASM_EMERGENCY_RESTART_H
-#define _ASM_EMERGENCY_RESTART_H
+#ifndef ASM_X86__EMERGENCY_RESTART_H
+#define ASM_X86__EMERGENCY_RESTART_H
 
 enum reboot_type {
 	BOOT_TRIPLE = 't',
@@ -15,4 +15,4 @@
 
 extern void machine_emergency_restart(void);
 
-#endif /* _ASM_EMERGENCY_RESTART_H */
+#endif /* ASM_X86__EMERGENCY_RESTART_H */
diff --git a/include/asm-x86/es7000/apic.h b/include/asm-x86/es7000/apic.h
new file mode 100644
index 0000000..bd2c44d
--- /dev/null
+++ b/include/asm-x86/es7000/apic.h
@@ -0,0 +1,194 @@
+#ifndef __ASM_ES7000_APIC_H
+#define __ASM_ES7000_APIC_H
+
+#define xapic_phys_to_log_apicid(cpu) per_cpu(x86_bios_cpu_apicid, cpu)
+#define esr_disable (1)
+
+static inline int apic_id_registered(void)
+{
+	        return (1);
+}
+
+static inline cpumask_t target_cpus(void)
+{
+#if defined CONFIG_ES7000_CLUSTERED_APIC
+	return CPU_MASK_ALL;
+#else
+	return cpumask_of_cpu(smp_processor_id());
+#endif
+}
+#define TARGET_CPUS	(target_cpus())
+
+#if defined CONFIG_ES7000_CLUSTERED_APIC
+#define APIC_DFR_VALUE		(APIC_DFR_CLUSTER)
+#define INT_DELIVERY_MODE	(dest_LowestPrio)
+#define INT_DEST_MODE		(1)    /* logical delivery broadcast to all procs */
+#define NO_BALANCE_IRQ		(1)
+#undef  WAKE_SECONDARY_VIA_INIT
+#define WAKE_SECONDARY_VIA_MIP
+#else
+#define APIC_DFR_VALUE		(APIC_DFR_FLAT)
+#define INT_DELIVERY_MODE	(dest_Fixed)
+#define INT_DEST_MODE		(0)    /* phys delivery to target procs */
+#define NO_BALANCE_IRQ		(0)
+#undef  APIC_DEST_LOGICAL
+#define APIC_DEST_LOGICAL	0x0
+#define WAKE_SECONDARY_VIA_INIT
+#endif
+
+static inline unsigned long check_apicid_used(physid_mask_t bitmap, int apicid)
+{
+	return 0;
+}
+static inline unsigned long check_apicid_present(int bit)
+{
+	return physid_isset(bit, phys_cpu_present_map);
+}
+
+#define apicid_cluster(apicid) (apicid & 0xF0)
+
+static inline unsigned long calculate_ldr(int cpu)
+{
+	unsigned long id;
+	id = xapic_phys_to_log_apicid(cpu);
+	return (SET_APIC_LOGICAL_ID(id));
+}
+
+/*
+ * Set up the logical destination ID.
+ *
+ * Intel recommends to set DFR, LdR and TPR before enabling
+ * an APIC.  See e.g. "AP-388 82489DX User's Manual" (Intel
+ * document number 292116).  So here it goes...
+ */
+static inline void init_apic_ldr(void)
+{
+	unsigned long val;
+	int cpu = smp_processor_id();
+
+	apic_write(APIC_DFR, APIC_DFR_VALUE);
+	val = calculate_ldr(cpu);
+	apic_write(APIC_LDR, val);
+}
+
+#ifndef CONFIG_X86_GENERICARCH
+extern void enable_apic_mode(void);
+#endif
+
+extern int apic_version [MAX_APICS];
+static inline void setup_apic_routing(void)
+{
+	int apic = per_cpu(x86_bios_cpu_apicid, smp_processor_id());
+	printk("Enabling APIC mode:  %s.  Using %d I/O APICs, target cpus %lx\n",
+		(apic_version[apic] == 0x14) ?
+		"Physical Cluster" : "Logical Cluster", nr_ioapics, cpus_addr(TARGET_CPUS)[0]);
+}
+
+static inline int multi_timer_check(int apic, int irq)
+{
+	return 0;
+}
+
+static inline int apicid_to_node(int logical_apicid)
+{
+	return 0;
+}
+
+
+static inline int cpu_present_to_apicid(int mps_cpu)
+{
+	if (!mps_cpu)
+		return boot_cpu_physical_apicid;
+	else if (mps_cpu < NR_CPUS)
+		return (int) per_cpu(x86_bios_cpu_apicid, mps_cpu);
+	else
+		return BAD_APICID;
+}
+
+static inline physid_mask_t apicid_to_cpu_present(int phys_apicid)
+{
+	static int id = 0;
+	physid_mask_t mask;
+	mask = physid_mask_of_physid(id);
+	++id;
+	return mask;
+}
+
+extern u8 cpu_2_logical_apicid[];
+/* Mapping from cpu number to logical apicid */
+static inline int cpu_to_logical_apicid(int cpu)
+{
+#ifdef CONFIG_SMP
+       if (cpu >= NR_CPUS)
+	       return BAD_APICID;
+       return (int)cpu_2_logical_apicid[cpu];
+#else
+	return logical_smp_processor_id();
+#endif
+}
+
+static inline physid_mask_t ioapic_phys_id_map(physid_mask_t phys_map)
+{
+	/* For clustered we don't have a good way to do this yet - hack */
+	return physids_promote(0xff);
+}
+
+
+static inline void setup_portio_remap(void)
+{
+}
+
+extern unsigned int boot_cpu_physical_apicid;
+static inline int check_phys_apicid_present(int cpu_physical_apicid)
+{
+	boot_cpu_physical_apicid = read_apic_id();
+	return (1);
+}
+
+static inline unsigned int cpu_mask_to_apicid(cpumask_t cpumask)
+{
+	int num_bits_set;
+	int cpus_found = 0;
+	int cpu;
+	int apicid;
+
+	num_bits_set = cpus_weight(cpumask);
+	/* Return id to all */
+	if (num_bits_set == NR_CPUS)
+#if defined CONFIG_ES7000_CLUSTERED_APIC
+		return 0xFF;
+#else
+		return cpu_to_logical_apicid(0);
+#endif
+	/*
+	 * The cpus in the mask must all be on the apic cluster.  If are not
+	 * on the same apicid cluster return default value of TARGET_CPUS.
+	 */
+	cpu = first_cpu(cpumask);
+	apicid = cpu_to_logical_apicid(cpu);
+	while (cpus_found < num_bits_set) {
+		if (cpu_isset(cpu, cpumask)) {
+			int new_apicid = cpu_to_logical_apicid(cpu);
+			if (apicid_cluster(apicid) !=
+					apicid_cluster(new_apicid)){
+				printk ("%s: Not a valid mask!\n",__FUNCTION__);
+#if defined CONFIG_ES7000_CLUSTERED_APIC
+				return 0xFF;
+#else
+				return cpu_to_logical_apicid(0);
+#endif
+			}
+			apicid = new_apicid;
+			cpus_found++;
+		}
+		cpu++;
+	}
+	return apicid;
+}
+
+static inline u32 phys_pkg_id(u32 cpuid_apic, int index_msb)
+{
+	return cpuid_apic >> index_msb;
+}
+
+#endif /* __ASM_ES7000_APIC_H */
diff --git a/include/asm-x86/es7000/apicdef.h b/include/asm-x86/es7000/apicdef.h
new file mode 100644
index 0000000..8b234a3
--- /dev/null
+++ b/include/asm-x86/es7000/apicdef.h
@@ -0,0 +1,13 @@
+#ifndef __ASM_ES7000_APICDEF_H
+#define __ASM_ES7000_APICDEF_H
+
+#define		APIC_ID_MASK		(0xFF<<24)
+
+static inline unsigned get_apic_id(unsigned long x)
+{
+	return (((x)>>24)&0xFF);
+}
+
+#define		GET_APIC_ID(x)	get_apic_id(x)
+
+#endif
diff --git a/include/asm-x86/es7000/ipi.h b/include/asm-x86/es7000/ipi.h
new file mode 100644
index 0000000..632a955
--- /dev/null
+++ b/include/asm-x86/es7000/ipi.h
@@ -0,0 +1,24 @@
+#ifndef __ASM_ES7000_IPI_H
+#define __ASM_ES7000_IPI_H
+
+void send_IPI_mask_sequence(cpumask_t mask, int vector);
+
+static inline void send_IPI_mask(cpumask_t mask, int vector)
+{
+	send_IPI_mask_sequence(mask, vector);
+}
+
+static inline void send_IPI_allbutself(int vector)
+{
+	cpumask_t mask = cpu_online_map;
+	cpu_clear(smp_processor_id(), mask);
+	if (!cpus_empty(mask))
+		send_IPI_mask(mask, vector);
+}
+
+static inline void send_IPI_all(int vector)
+{
+	send_IPI_mask(cpu_online_map, vector);
+}
+
+#endif /* __ASM_ES7000_IPI_H */
diff --git a/include/asm-x86/es7000/mpparse.h b/include/asm-x86/es7000/mpparse.h
new file mode 100644
index 0000000..ed5a3ca
--- /dev/null
+++ b/include/asm-x86/es7000/mpparse.h
@@ -0,0 +1,30 @@
+#ifndef __ASM_ES7000_MPPARSE_H
+#define __ASM_ES7000_MPPARSE_H
+
+#include <linux/acpi.h>
+
+extern int parse_unisys_oem (char *oemptr);
+extern int find_unisys_acpi_oem_table(unsigned long *oem_addr);
+extern void unmap_unisys_acpi_oem_table(unsigned long oem_addr);
+extern void setup_unisys(void);
+
+#ifndef CONFIG_X86_GENERICARCH
+extern int acpi_madt_oem_check(char *oem_id, char *oem_table_id);
+extern int mps_oem_check(struct mp_config_table *mpc, char *oem,
+				char *productid);
+#endif
+
+#ifdef CONFIG_ACPI
+
+static inline int es7000_check_dsdt(void)
+{
+	struct acpi_table_header header;
+
+	if (ACPI_SUCCESS(acpi_get_table_header(ACPI_SIG_DSDT, 0, &header)) &&
+	    !strncmp(header.oem_id, "UNISYS", 6))
+		return 1;
+	return 0;
+}
+#endif
+
+#endif /* __ASM_MACH_MPPARSE_H */
diff --git a/include/asm-x86/es7000/wakecpu.h b/include/asm-x86/es7000/wakecpu.h
new file mode 100644
index 0000000..3ffc5a7
--- /dev/null
+++ b/include/asm-x86/es7000/wakecpu.h
@@ -0,0 +1,59 @@
+#ifndef __ASM_ES7000_WAKECPU_H
+#define __ASM_ES7000_WAKECPU_H
+
+/*
+ * This file copes with machines that wakeup secondary CPUs by the
+ * INIT, INIT, STARTUP sequence.
+ */
+
+#ifdef CONFIG_ES7000_CLUSTERED_APIC
+#define WAKE_SECONDARY_VIA_MIP
+#else
+#define WAKE_SECONDARY_VIA_INIT
+#endif
+
+#ifdef WAKE_SECONDARY_VIA_MIP
+extern int es7000_start_cpu(int cpu, unsigned long eip);
+static inline int
+wakeup_secondary_cpu(int phys_apicid, unsigned long start_eip)
+{
+	int boot_error = 0;
+	boot_error = es7000_start_cpu(phys_apicid, start_eip);
+	return boot_error;
+}
+#endif
+
+#define TRAMPOLINE_LOW phys_to_virt(0x467)
+#define TRAMPOLINE_HIGH phys_to_virt(0x469)
+
+#define boot_cpu_apicid boot_cpu_physical_apicid
+
+static inline void wait_for_init_deassert(atomic_t *deassert)
+{
+#ifdef WAKE_SECONDARY_VIA_INIT
+	while (!atomic_read(deassert))
+		cpu_relax();
+#endif
+	return;
+}
+
+/* Nothing to do for most platforms, since cleared by the INIT cycle */
+static inline void smp_callin_clear_local_apic(void)
+{
+}
+
+static inline void store_NMI_vector(unsigned short *high, unsigned short *low)
+{
+}
+
+static inline void restore_NMI_vector(unsigned short *high, unsigned short *low)
+{
+}
+
+#if APIC_DEBUG
+ #define inquire_remote_apic(apicid) __inquire_remote_apic(apicid)
+#else
+ #define inquire_remote_apic(apicid) {}
+#endif
+
+#endif /* __ASM_MACH_WAKECPU_H */
diff --git a/include/asm-x86/fb.h b/include/asm-x86/fb.h
index 5301846..aca38dbd 100644
--- a/include/asm-x86/fb.h
+++ b/include/asm-x86/fb.h
@@ -1,5 +1,5 @@
-#ifndef _ASM_X86_FB_H
-#define _ASM_X86_FB_H
+#ifndef ASM_X86__FB_H
+#define ASM_X86__FB_H
 
 #include <linux/fb.h>
 #include <linux/fs.h>
@@ -18,4 +18,4 @@
 static inline int fb_is_primary_device(struct fb_info *info) { return 0; }
 #endif
 
-#endif /* _ASM_X86_FB_H */
+#endif /* ASM_X86__FB_H */
diff --git a/include/asm-x86/fixmap.h b/include/asm-x86/fixmap.h
index 44d4f82..78e33a1 100644
--- a/include/asm-x86/fixmap.h
+++ b/include/asm-x86/fixmap.h
@@ -1,5 +1,5 @@
-#ifndef _ASM_FIXMAP_H
-#define _ASM_FIXMAP_H
+#ifndef ASM_X86__FIXMAP_H
+#define ASM_X86__FIXMAP_H
 
 #ifdef CONFIG_X86_32
 # include "fixmap_32.h"
@@ -65,4 +65,4 @@
 	BUG_ON(vaddr >= FIXADDR_TOP || vaddr < FIXADDR_START);
 	return __virt_to_fix(vaddr);
 }
-#endif
+#endif /* ASM_X86__FIXMAP_H */
diff --git a/include/asm-x86/fixmap_32.h b/include/asm-x86/fixmap_32.h
index f1ac2b2..8844002 100644
--- a/include/asm-x86/fixmap_32.h
+++ b/include/asm-x86/fixmap_32.h
@@ -10,8 +10,8 @@
  * Support of BIGMEM added by Gerhard Wichert, Siemens AG, July 1999
  */
 
-#ifndef _ASM_FIXMAP_32_H
-#define _ASM_FIXMAP_32_H
+#ifndef ASM_X86__FIXMAP_32_H
+#define ASM_X86__FIXMAP_32_H
 
 
 /* used by vmalloc.c, vsyscall.lds.S.
@@ -94,10 +94,10 @@
 	 * can have a single pgd entry and a single pte table:
 	 */
 #define NR_FIX_BTMAPS		64
-#define FIX_BTMAPS_NESTING	4
+#define FIX_BTMAPS_SLOTS	4
 	FIX_BTMAP_END = __end_of_permanent_fixed_addresses + 256 -
 			(__end_of_permanent_fixed_addresses & 255),
-	FIX_BTMAP_BEGIN = FIX_BTMAP_END + NR_FIX_BTMAPS*FIX_BTMAPS_NESTING - 1,
+	FIX_BTMAP_BEGIN = FIX_BTMAP_END + NR_FIX_BTMAPS*FIX_BTMAPS_SLOTS - 1,
 	FIX_WP_TEST,
 #ifdef CONFIG_ACPI
 	FIX_ACPI_BEGIN,
@@ -120,4 +120,4 @@
 #define FIXADDR_BOOT_START	(FIXADDR_TOP - __FIXADDR_BOOT_SIZE)
 
 #endif /* !__ASSEMBLY__ */
-#endif
+#endif /* ASM_X86__FIXMAP_32_H */
diff --git a/include/asm-x86/fixmap_64.h b/include/asm-x86/fixmap_64.h
index 00f3d74..dab4751 100644
--- a/include/asm-x86/fixmap_64.h
+++ b/include/asm-x86/fixmap_64.h
@@ -8,8 +8,8 @@
  * Copyright (C) 1998 Ingo Molnar
  */
 
-#ifndef _ASM_FIXMAP_64_H
-#define _ASM_FIXMAP_64_H
+#ifndef ASM_X86__FIXMAP_64_H
+#define ASM_X86__FIXMAP_64_H
 
 #include <linux/kernel.h>
 #include <asm/acpi.h>
@@ -49,6 +49,7 @@
 #ifdef CONFIG_PARAVIRT
 	FIX_PARAVIRT_BOOTMAP,
 #endif
+	__end_of_permanent_fixed_addresses,
 #ifdef CONFIG_ACPI
 	FIX_ACPI_BEGIN,
 	FIX_ACPI_END = FIX_ACPI_BEGIN + FIX_ACPI_PAGES - 1,
@@ -56,19 +57,18 @@
 #ifdef CONFIG_PROVIDE_OHCI1394_DMA_INIT
 	FIX_OHCI1394_BASE,
 #endif
-	__end_of_permanent_fixed_addresses,
 	/*
 	 * 256 temporary boot-time mappings, used by early_ioremap(),
 	 * before ioremap() is functional.
 	 *
-	 * We round it up to the next 512 pages boundary so that we
+	 * We round it up to the next 256 pages boundary so that we
 	 * can have a single pgd entry and a single pte table:
 	 */
 #define NR_FIX_BTMAPS		64
-#define FIX_BTMAPS_NESTING	4
-	FIX_BTMAP_END = __end_of_permanent_fixed_addresses + 512 -
-			(__end_of_permanent_fixed_addresses & 511),
-	FIX_BTMAP_BEGIN = FIX_BTMAP_END + NR_FIX_BTMAPS*FIX_BTMAPS_NESTING - 1,
+#define FIX_BTMAPS_SLOTS	4
+	FIX_BTMAP_END = __end_of_permanent_fixed_addresses + 256 -
+			(__end_of_permanent_fixed_addresses & 255),
+	FIX_BTMAP_BEGIN = FIX_BTMAP_END + NR_FIX_BTMAPS*FIX_BTMAPS_SLOTS - 1,
 	__end_of_fixed_addresses
 };
 
@@ -80,4 +80,4 @@
 #define FIXADDR_USER_START	((unsigned long)VSYSCALL32_VSYSCALL)
 #define FIXADDR_USER_END	(FIXADDR_USER_START + PAGE_SIZE)
 
-#endif
+#endif /* ASM_X86__FIXMAP_64_H */
diff --git a/include/asm-x86/floppy.h b/include/asm-x86/floppy.h
index dbe82a5..7d83a3a 100644
--- a/include/asm-x86/floppy.h
+++ b/include/asm-x86/floppy.h
@@ -7,8 +7,8 @@
  *
  * Copyright (C) 1995
  */
-#ifndef _ASM_X86_FLOPPY_H
-#define _ASM_X86_FLOPPY_H
+#ifndef ASM_X86__FLOPPY_H
+#define ASM_X86__FLOPPY_H
 
 #include <linux/vmalloc.h>
 
@@ -278,4 +278,4 @@
 
 #define EXTRA_FLOPPY_PARAMS
 
-#endif /* _ASM_X86_FLOPPY_H */
+#endif /* ASM_X86__FLOPPY_H */
diff --git a/include/asm-x86/ftrace.h b/include/asm-x86/ftrace.h
index 5c68b32..be0e004 100644
--- a/include/asm-x86/ftrace.h
+++ b/include/asm-x86/ftrace.h
@@ -1,5 +1,5 @@
-#ifndef _ASM_X86_FTRACE
-#define _ASM_X86_FTRACE
+#ifndef ASM_X86__FTRACE_H
+#define ASM_X86__FTRACE_H
 
 #ifdef CONFIG_FTRACE
 #define MCOUNT_ADDR		((long)(mcount))
@@ -11,4 +11,4 @@
 
 #endif /* CONFIG_FTRACE */
 
-#endif /* _ASM_X86_FTRACE */
+#endif /* ASM_X86__FTRACE_H */
diff --git a/include/asm-x86/futex.h b/include/asm-x86/futex.h
index e7a76b3..06b924e 100644
--- a/include/asm-x86/futex.h
+++ b/include/asm-x86/futex.h
@@ -1,5 +1,5 @@
-#ifndef _ASM_X86_FUTEX_H
-#define _ASM_X86_FUTEX_H
+#ifndef ASM_X86__FUTEX_H
+#define ASM_X86__FUTEX_H
 
 #ifdef __KERNEL__
 
@@ -25,7 +25,7 @@
 	asm volatile("1:\tmovl	%2, %0\n"			\
 		     "\tmovl\t%0, %3\n"				\
 		     "\t" insn "\n"				\
-		     "2:\tlock; cmpxchgl %3, %2\n"		\
+		     "2:\t" LOCK_PREFIX "cmpxchgl %3, %2\n"	\
 		     "\tjnz\t1b\n"				\
 		     "3:\t.section .fixup,\"ax\"\n"		\
 		     "4:\tmov\t%5, %1\n"			\
@@ -64,7 +64,7 @@
 		__futex_atomic_op1("xchgl %0, %2", ret, oldval, uaddr, oparg);
 		break;
 	case FUTEX_OP_ADD:
-		__futex_atomic_op1("lock; xaddl %0, %2", ret, oldval,
+		__futex_atomic_op1(LOCK_PREFIX "xaddl %0, %2", ret, oldval,
 				   uaddr, oparg);
 		break;
 	case FUTEX_OP_OR:
@@ -122,7 +122,7 @@
 	if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
 		return -EFAULT;
 
-	asm volatile("1:\tlock; cmpxchgl %3, %1\n"
+	asm volatile("1:\t" LOCK_PREFIX "cmpxchgl %3, %1\n"
 		     "2:\t.section .fixup, \"ax\"\n"
 		     "3:\tmov     %2, %0\n"
 		     "\tjmp     2b\n"
@@ -137,4 +137,4 @@
 }
 
 #endif
-#endif
+#endif /* ASM_X86__FUTEX_H */
diff --git a/include/asm-x86/gart.h b/include/asm-x86/gart.h
index 3f62a83..605edb3 100644
--- a/include/asm-x86/gart.h
+++ b/include/asm-x86/gart.h
@@ -1,5 +1,5 @@
-#ifndef _ASM_X8664_GART_H
-#define _ASM_X8664_GART_H 1
+#ifndef ASM_X86__GART_H
+#define ASM_X86__GART_H
 
 #include <asm/e820.h>
 
@@ -29,6 +29,8 @@
 #define AMD64_GARTCACHECTL	0x9c
 #define AMD64_GARTEN		(1<<0)
 
+extern int agp_amd64_init(void);
+
 static inline void enable_gart_translation(struct pci_dev *dev, u64 addr)
 {
 	u32 tmp, ctl;
@@ -52,15 +54,15 @@
 		return 0;
 
 	if (aper_base + aper_size > 0x100000000ULL) {
-		printk(KERN_ERR "Aperture beyond 4GB. Ignoring.\n");
+		printk(KERN_INFO "Aperture beyond 4GB. Ignoring.\n");
 		return 0;
 	}
 	if (e820_any_mapped(aper_base, aper_base + aper_size, E820_RAM)) {
-		printk(KERN_ERR "Aperture pointing to e820 RAM. Ignoring.\n");
+		printk(KERN_INFO "Aperture pointing to e820 RAM. Ignoring.\n");
 		return 0;
 	}
 	if (aper_size < min_size) {
-		printk(KERN_ERR "Aperture too small (%d MB) than (%d MB)\n",
+		printk(KERN_INFO "Aperture too small (%d MB) than (%d MB)\n",
 				 aper_size>>20, min_size>>20);
 		return 0;
 	}
@@ -68,4 +70,4 @@
 	return 1;
 }
 
-#endif
+#endif /* ASM_X86__GART_H */
diff --git a/include/asm-x86/genapic_32.h b/include/asm-x86/genapic_32.h
index 754d635..34280f0 100644
--- a/include/asm-x86/genapic_32.h
+++ b/include/asm-x86/genapic_32.h
@@ -1,5 +1,5 @@
-#ifndef _ASM_GENAPIC_H
-#define _ASM_GENAPIC_H 1
+#ifndef ASM_X86__GENAPIC_32_H
+#define ASM_X86__GENAPIC_32_H
 
 #include <asm/mpspec.h>
 
@@ -121,4 +121,4 @@
 #define uv_system_init()		do {} while (0)
 
 
-#endif
+#endif /* ASM_X86__GENAPIC_32_H */
diff --git a/include/asm-x86/genapic_64.h b/include/asm-x86/genapic_64.h
index a47d631..ed6a488 100644
--- a/include/asm-x86/genapic_64.h
+++ b/include/asm-x86/genapic_64.h
@@ -1,5 +1,5 @@
-#ifndef _ASM_GENAPIC_H
-#define _ASM_GENAPIC_H 1
+#ifndef ASM_X86__GENAPIC_64_H
+#define ASM_X86__GENAPIC_64_H
 
 /*
  * Copyright 2004 James Cleverdon, IBM.
@@ -14,6 +14,7 @@
 
 struct genapic {
 	char *name;
+	int (*acpi_madt_oem_check)(char *oem_id, char *oem_table_id);
 	u32 int_delivery_mode;
 	u32 int_dest_mode;
 	int (*apic_id_registered)(void);
@@ -24,17 +25,24 @@
 	void (*send_IPI_mask)(cpumask_t mask, int vector);
 	void (*send_IPI_allbutself)(int vector);
 	void (*send_IPI_all)(int vector);
+	void (*send_IPI_self)(int vector);
 	/* */
 	unsigned int (*cpu_mask_to_apicid)(cpumask_t cpumask);
 	unsigned int (*phys_pkg_id)(int index_msb);
+	unsigned int (*get_apic_id)(unsigned long x);
+	unsigned long (*set_apic_id)(unsigned int id);
+	unsigned long apic_id_mask;
 };
 
 extern struct genapic *genapic;
 
 extern struct genapic apic_flat;
 extern struct genapic apic_physflat;
+extern struct genapic apic_x2apic_cluster;
+extern struct genapic apic_x2apic_phys;
 extern int acpi_madt_oem_check(char *, char *);
 
+extern void apic_send_IPI_self(int vector);
 enum uv_system_type {UV_NONE, UV_LEGACY_APIC, UV_X2APIC, UV_NON_UNIQUE_APIC};
 extern enum uv_system_type get_uv_system_type(void);
 extern int is_uv_system(void);
@@ -47,4 +55,4 @@
 
 extern void setup_apic_routing(void);
 
-#endif
+#endif /* ASM_X86__GENAPIC_64_H */
diff --git a/include/asm-x86/geode.h b/include/asm-x86/geode.h
index 2c1cda0..3f3444b 100644
--- a/include/asm-x86/geode.h
+++ b/include/asm-x86/geode.h
@@ -7,8 +7,8 @@
  * as published by the Free Software Foundation.
  */
 
-#ifndef _ASM_GEODE_H_
-#define _ASM_GEODE_H_
+#ifndef ASM_X86__GEODE_H
+#define ASM_X86__GEODE_H
 
 #include <asm/processor.h>
 #include <linux/io.h>
@@ -250,4 +250,4 @@
 static inline int mfgpt_timer_setup(void) { return 0; }
 #endif
 
-#endif
+#endif /* ASM_X86__GEODE_H */
diff --git a/include/asm-x86/gpio.h b/include/asm-x86/gpio.h
index c4c91b3..497fb98 100644
--- a/include/asm-x86/gpio.h
+++ b/include/asm-x86/gpio.h
@@ -53,4 +53,4 @@
 
 #endif /* CONFIG_GPIOLIB */
 
-#endif /* _ASM_I386_GPIO_H */
+#endif /* ASM_X86__GPIO_H */
diff --git a/include/asm-x86/hardirq_32.h b/include/asm-x86/hardirq_32.h
index 4f85f0f..700fe23 100644
--- a/include/asm-x86/hardirq_32.h
+++ b/include/asm-x86/hardirq_32.h
@@ -1,5 +1,5 @@
-#ifndef __ASM_HARDIRQ_H
-#define __ASM_HARDIRQ_H
+#ifndef ASM_X86__HARDIRQ_32_H
+#define ASM_X86__HARDIRQ_32_H
 
 #include <linux/threads.h>
 #include <linux/irq.h>
@@ -25,4 +25,4 @@
 void ack_bad_irq(unsigned int irq);
 #include <linux/irq_cpustat.h>
 
-#endif /* __ASM_HARDIRQ_H */
+#endif /* ASM_X86__HARDIRQ_32_H */
diff --git a/include/asm-x86/hardirq_64.h b/include/asm-x86/hardirq_64.h
index 95d5e09..f8bd291 100644
--- a/include/asm-x86/hardirq_64.h
+++ b/include/asm-x86/hardirq_64.h
@@ -1,5 +1,5 @@
-#ifndef __ASM_HARDIRQ_H
-#define __ASM_HARDIRQ_H
+#ifndef ASM_X86__HARDIRQ_64_H
+#define ASM_X86__HARDIRQ_64_H
 
 #include <linux/threads.h>
 #include <linux/irq.h>
@@ -20,4 +20,4 @@
 
 extern void ack_bad_irq(unsigned int irq);
 
-#endif /* __ASM_HARDIRQ_H */
+#endif /* ASM_X86__HARDIRQ_64_H */
diff --git a/include/asm-x86/highmem.h b/include/asm-x86/highmem.h
index 4514b16..bc3f6a2 100644
--- a/include/asm-x86/highmem.h
+++ b/include/asm-x86/highmem.h
@@ -15,8 +15,8 @@
  * Copyright (C) 1999 Ingo Molnar <mingo@redhat.com>
  */
 
-#ifndef _ASM_HIGHMEM_H
-#define _ASM_HIGHMEM_H
+#ifndef ASM_X86__HIGHMEM_H
+#define ASM_X86__HIGHMEM_H
 
 #ifdef __KERNEL__
 
@@ -79,4 +79,4 @@
 
 #endif /* __KERNEL__ */
 
-#endif /* _ASM_HIGHMEM_H */
+#endif /* ASM_X86__HIGHMEM_H */
diff --git a/include/asm-x86/hpet.h b/include/asm-x86/hpet.h
index 82f1ac6..cbbbb6d 100644
--- a/include/asm-x86/hpet.h
+++ b/include/asm-x86/hpet.h
@@ -1,5 +1,5 @@
-#ifndef ASM_X86_HPET_H
-#define ASM_X86_HPET_H
+#ifndef ASM_X86__HPET_H
+#define ASM_X86__HPET_H
 
 #ifdef CONFIG_HPET_TIMER
 
@@ -90,4 +90,4 @@
 #define hpet_readl(a) 0
 
 #endif
-#endif /* ASM_X86_HPET_H */
+#endif /* ASM_X86__HPET_H */
diff --git a/include/asm-x86/hugetlb.h b/include/asm-x86/hugetlb.h
index 439a9ac..0b7ec5d 100644
--- a/include/asm-x86/hugetlb.h
+++ b/include/asm-x86/hugetlb.h
@@ -1,5 +1,5 @@
-#ifndef _ASM_X86_HUGETLB_H
-#define _ASM_X86_HUGETLB_H
+#ifndef ASM_X86__HUGETLB_H
+#define ASM_X86__HUGETLB_H
 
 #include <asm/page.h>
 
@@ -90,4 +90,4 @@
 {
 }
 
-#endif /* _ASM_X86_HUGETLB_H */
+#endif /* ASM_X86__HUGETLB_H */
diff --git a/include/asm-x86/hw_irq.h b/include/asm-x86/hw_irq.h
index edd0b95..50f6e03 100644
--- a/include/asm-x86/hw_irq.h
+++ b/include/asm-x86/hw_irq.h
@@ -1,5 +1,5 @@
-#ifndef _ASM_HW_IRQ_H
-#define _ASM_HW_IRQ_H
+#ifndef ASM_X86__HW_IRQ_H
+#define ASM_X86__HW_IRQ_H
 
 /*
  * (C) 1992, 1993 Linus Torvalds, (C) 1997 Ingo Molnar
@@ -64,7 +64,6 @@
 extern void init_VISWS_APIC_irqs(void);
 extern void setup_IO_APIC(void);
 extern void disable_IO_APIC(void);
-extern void print_IO_APIC(void);
 extern int IO_APIC_get_PCI_irq_vector(int bus, int slot, int fn);
 extern void setup_ioapic_dest(void);
 
@@ -73,7 +72,9 @@
 #endif
 
 /* IPI functions */
+#ifdef CONFIG_X86_32
 extern void send_IPI_self(int vector);
+#endif
 extern void send_IPI(int dest, int vector);
 
 /* Statistics */
@@ -93,6 +94,26 @@
 extern asmlinkage void qic_enable_irq_interrupt(void);
 extern asmlinkage void qic_call_function_interrupt(void);
 
+/* SMP */
+extern void smp_apic_timer_interrupt(struct pt_regs *);
+#ifdef CONFIG_X86_32
+extern void smp_spurious_interrupt(struct pt_regs *);
+extern void smp_error_interrupt(struct pt_regs *);
+#else
+extern asmlinkage void smp_spurious_interrupt(void);
+extern asmlinkage void smp_error_interrupt(void);
+#endif
+#ifdef CONFIG_X86_SMP
+extern void smp_reschedule_interrupt(struct pt_regs *);
+extern void smp_call_function_interrupt(struct pt_regs *);
+extern void smp_call_function_single_interrupt(struct pt_regs *);
+#ifdef CONFIG_X86_32
+extern void smp_invalidate_interrupt(struct pt_regs *);
+#else
+extern asmlinkage void smp_invalidate_interrupt(struct pt_regs *);
+#endif
+#endif
+
 #ifdef CONFIG_X86_32
 extern void (*const interrupt[NR_IRQS])(void);
 #else
@@ -112,4 +133,4 @@
 
 #endif /* !ASSEMBLY_ */
 
-#endif
+#endif /* ASM_X86__HW_IRQ_H */
diff --git a/include/asm-x86/hypertransport.h b/include/asm-x86/hypertransport.h
index d2bbd23..cc011a3 100644
--- a/include/asm-x86/hypertransport.h
+++ b/include/asm-x86/hypertransport.h
@@ -1,5 +1,5 @@
-#ifndef ASM_HYPERTRANSPORT_H
-#define ASM_HYPERTRANSPORT_H
+#ifndef ASM_X86__HYPERTRANSPORT_H
+#define ASM_X86__HYPERTRANSPORT_H
 
 /*
  * Constants for x86 Hypertransport Interrupts.
@@ -42,4 +42,4 @@
 #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 */
+#endif /* ASM_X86__HYPERTRANSPORT_H */
diff --git a/include/asm-x86/i387.h b/include/asm-x86/i387.h
index 56d00e3..9ba862a 100644
--- a/include/asm-x86/i387.h
+++ b/include/asm-x86/i387.h
@@ -7,8 +7,8 @@
  * x86-64 work by Andi Kleen 2002
  */
 
-#ifndef _ASM_X86_I387_H
-#define _ASM_X86_I387_H
+#ifndef ASM_X86__I387_H
+#define ASM_X86__I387_H
 
 #include <linux/sched.h>
 #include <linux/kernel_stat.h>
@@ -19,23 +19,32 @@
 #include <asm/sigcontext.h>
 #include <asm/user.h>
 #include <asm/uaccess.h>
+#include <asm/xsave.h>
 
+extern unsigned int sig_xstate_size;
 extern void fpu_init(void);
 extern void mxcsr_feature_mask_init(void);
 extern int init_fpu(struct task_struct *child);
 extern asmlinkage void math_state_restore(void);
 extern void init_thread_xstate(void);
+extern int dump_fpu(struct pt_regs *, struct user_i387_struct *);
 
 extern user_regset_active_fn fpregs_active, xfpregs_active;
 extern user_regset_get_fn fpregs_get, xfpregs_get, fpregs_soft_get;
 extern user_regset_set_fn fpregs_set, xfpregs_set, fpregs_soft_set;
 
+extern struct _fpx_sw_bytes fx_sw_reserved;
 #ifdef CONFIG_IA32_EMULATION
+extern unsigned int sig_xstate_ia32_size;
+extern struct _fpx_sw_bytes fx_sw_reserved_ia32;
 struct _fpstate_ia32;
-extern int save_i387_ia32(struct _fpstate_ia32 __user *buf);
-extern int restore_i387_ia32(struct _fpstate_ia32 __user *buf);
+struct _xstate_ia32;
+extern int save_i387_xstate_ia32(void __user *buf);
+extern int restore_i387_xstate_ia32(void __user *buf);
 #endif
 
+#define X87_FSW_ES (1 << 7)	/* Exception Summary */
+
 #ifdef CONFIG_X86_64
 
 /* Ignore delayed exceptions from user space */
@@ -46,7 +55,7 @@
 		     _ASM_EXTABLE(1b, 2b));
 }
 
-static inline int restore_fpu_checking(struct i387_fxsave_struct *fx)
+static inline int fxrstor_checking(struct i387_fxsave_struct *fx)
 {
 	int err;
 
@@ -66,15 +75,31 @@
 	return err;
 }
 
-#define X87_FSW_ES (1 << 7)	/* Exception Summary */
+static inline int restore_fpu_checking(struct task_struct *tsk)
+{
+	if (task_thread_info(tsk)->status & TS_XSAVE)
+		return xrstor_checking(&tsk->thread.xstate->xsave);
+	else
+		return fxrstor_checking(&tsk->thread.xstate->fxsave);
+}
 
 /* AMD CPUs don't save/restore FDP/FIP/FOP unless an exception
    is pending. Clear the x87 state here by setting it to fixed
    values. The kernel data segment can be sometimes 0 and sometimes
    new user value. Both should be ok.
    Use the PDA as safe address because it should be already in L1. */
-static inline void clear_fpu_state(struct i387_fxsave_struct *fx)
+static inline void clear_fpu_state(struct task_struct *tsk)
 {
+	struct xsave_struct *xstate = &tsk->thread.xstate->xsave;
+	struct i387_fxsave_struct *fx = &tsk->thread.xstate->fxsave;
+
+	/*
+	 * xsave header may indicate the init state of the FP.
+	 */
+	if ((task_thread_info(tsk)->status & TS_XSAVE) &&
+	    !(xstate->xsave_hdr.xstate_bv & XSTATE_FP))
+		return;
+
 	if (unlikely(fx->swd & X87_FSW_ES))
 		asm volatile("fnclex");
 	alternative_input(ASM_NOP8 ASM_NOP2,
@@ -83,7 +108,7 @@
 			  X86_FEATURE_FXSAVE_LEAK);
 }
 
-static inline int save_i387_checking(struct i387_fxsave_struct __user *fx)
+static inline int fxsave_user(struct i387_fxsave_struct __user *fx)
 {
 	int err;
 
@@ -107,7 +132,7 @@
 	return err;
 }
 
-static inline void __save_init_fpu(struct task_struct *tsk)
+static inline void fxsave(struct task_struct *tsk)
 {
 	/* Using "rex64; fxsave %0" is broken because, if the memory operand
 	   uses any extended registers for addressing, a second REX prefix
@@ -132,7 +157,16 @@
 			     : "=m" (tsk->thread.xstate->fxsave)
 			     : "cdaSDb" (&tsk->thread.xstate->fxsave));
 #endif
-	clear_fpu_state(&tsk->thread.xstate->fxsave);
+}
+
+static inline void __save_init_fpu(struct task_struct *tsk)
+{
+	if (task_thread_info(tsk)->status & TS_XSAVE)
+		xsave(tsk);
+	else
+		fxsave(tsk);
+
+	clear_fpu_state(tsk);
 	task_thread_info(tsk)->status &= ~TS_USEDFPU;
 }
 
@@ -147,6 +181,10 @@
 
 static inline void restore_fpu(struct task_struct *tsk)
 {
+	if (task_thread_info(tsk)->status & TS_XSAVE) {
+		xrstor_checking(&tsk->thread.xstate->xsave);
+		return;
+	}
 	/*
 	 * The "nop" is needed to make the instructions the same
 	 * length.
@@ -172,6 +210,27 @@
  */
 static inline void __save_init_fpu(struct task_struct *tsk)
 {
+	if (task_thread_info(tsk)->status & TS_XSAVE) {
+		struct xsave_struct *xstate = &tsk->thread.xstate->xsave;
+		struct i387_fxsave_struct *fx = &tsk->thread.xstate->fxsave;
+
+		xsave(tsk);
+
+		/*
+		 * xsave header may indicate the init state of the FP.
+		 */
+		if (!(xstate->xsave_hdr.xstate_bv & XSTATE_FP))
+			goto end;
+
+		if (unlikely(fx->swd & X87_FSW_ES))
+			asm volatile("fnclex");
+
+		/*
+		 * we can do a simple return here or be paranoid :)
+		 */
+		goto clear_state;
+	}
+
 	/* Use more nops than strictly needed in case the compiler
 	   varies code */
 	alternative_input(
@@ -181,6 +240,7 @@
 		X86_FEATURE_FXSR,
 		[fx] "m" (tsk->thread.xstate->fxsave),
 		[fsw] "m" (tsk->thread.xstate->fxsave.swd) : "memory");
+clear_state:
 	/* AMD K7/K8 CPUs don't save/restore FDP/FIP/FOP unless an exception
 	   is pending.  Clear the x87 state here by setting it to fixed
 	   values. safe_address is a random variable that should be in L1 */
@@ -190,16 +250,17 @@
 		"fildl %[addr]", 	/* set F?P to defined value */
 		X86_FEATURE_FXSAVE_LEAK,
 		[addr] "m" (safe_address));
+end:
 	task_thread_info(tsk)->status &= ~TS_USEDFPU;
 }
 
+#endif	/* CONFIG_X86_64 */
+
 /*
  * Signal frame handlers...
  */
-extern int save_i387(struct _fpstate __user *buf);
-extern int restore_i387(struct _fpstate __user *buf);
-
-#endif	/* CONFIG_X86_64 */
+extern int save_i387_xstate(void __user *buf);
+extern int restore_i387_xstate(void __user *buf);
 
 static inline void __unlazy_fpu(struct task_struct *tsk)
 {
@@ -336,4 +397,4 @@
 	}
 }
 
-#endif	/* _ASM_X86_I387_H */
+#endif /* ASM_X86__I387_H */
diff --git a/include/asm-x86/i8253.h b/include/asm-x86/i8253.h
index b51c048..15a5b53 100644
--- a/include/asm-x86/i8253.h
+++ b/include/asm-x86/i8253.h
@@ -1,5 +1,5 @@
-#ifndef __ASM_I8253_H__
-#define __ASM_I8253_H__
+#ifndef ASM_X86__I8253_H
+#define ASM_X86__I8253_H
 
 /* i8253A PIT registers */
 #define PIT_MODE		0x43
@@ -15,4 +15,4 @@
 #define inb_pit		inb_p
 #define outb_pit	outb_p
 
-#endif	/* __ASM_I8253_H__ */
+#endif /* ASM_X86__I8253_H */
diff --git a/include/asm-x86/i8259.h b/include/asm-x86/i8259.h
index 2f98df9..23c1b3b 100644
--- a/include/asm-x86/i8259.h
+++ b/include/asm-x86/i8259.h
@@ -1,5 +1,5 @@
-#ifndef __ASM_I8259_H__
-#define __ASM_I8259_H__
+#ifndef ASM_X86__I8259_H
+#define ASM_X86__I8259_H
 
 #include <linux/delay.h>
 
@@ -57,4 +57,7 @@
 
 extern struct irq_chip i8259A_chip;
 
-#endif	/* __ASM_I8259_H__ */
+extern void mask_8259A(void);
+extern void unmask_8259A(void);
+
+#endif /* ASM_X86__I8259_H */
diff --git a/include/asm-x86/ia32.h b/include/asm-x86/ia32.h
index 55d3abe..f932f7a 100644
--- a/include/asm-x86/ia32.h
+++ b/include/asm-x86/ia32.h
@@ -1,5 +1,5 @@
-#ifndef _ASM_X86_64_IA32_H
-#define _ASM_X86_64_IA32_H
+#ifndef ASM_X86__IA32_H
+#define ASM_X86__IA32_H
 
 
 #ifdef CONFIG_IA32_EMULATION
@@ -167,4 +167,4 @@
 
 #endif /* !CONFIG_IA32_SUPPORT */
 
-#endif
+#endif /* ASM_X86__IA32_H */
diff --git a/include/asm-x86/ia32_unistd.h b/include/asm-x86/ia32_unistd.h
index 61cea9e..dbd887d 100644
--- a/include/asm-x86/ia32_unistd.h
+++ b/include/asm-x86/ia32_unistd.h
@@ -1,5 +1,5 @@
-#ifndef _ASM_X86_64_IA32_UNISTD_H_
-#define _ASM_X86_64_IA32_UNISTD_H_
+#ifndef ASM_X86__IA32_UNISTD_H
+#define ASM_X86__IA32_UNISTD_H
 
 /*
  * This file contains the system call numbers of the ia32 port,
@@ -15,4 +15,4 @@
 #define __NR_ia32_sigreturn	119
 #define __NR_ia32_rt_sigreturn	173
 
-#endif /* _ASM_X86_64_IA32_UNISTD_H_ */
+#endif /* ASM_X86__IA32_UNISTD_H */
diff --git a/include/asm-x86/idle.h b/include/asm-x86/idle.h
index d240e5b..baa3f783 100644
--- a/include/asm-x86/idle.h
+++ b/include/asm-x86/idle.h
@@ -1,5 +1,5 @@
-#ifndef _ASM_X86_64_IDLE_H
-#define _ASM_X86_64_IDLE_H 1
+#ifndef ASM_X86__IDLE_H
+#define ASM_X86__IDLE_H
 
 #define IDLE_START 1
 #define IDLE_END 2
@@ -10,4 +10,6 @@
 void enter_idle(void);
 void exit_idle(void);
 
-#endif
+void c1e_remove_cpu(int cpu);
+
+#endif /* ASM_X86__IDLE_H */
diff --git a/include/asm-x86/intel_arch_perfmon.h b/include/asm-x86/intel_arch_perfmon.h
index fa0fd06..07c03c6 100644
--- a/include/asm-x86/intel_arch_perfmon.h
+++ b/include/asm-x86/intel_arch_perfmon.h
@@ -1,5 +1,5 @@
-#ifndef _ASM_X86_INTEL_ARCH_PERFMON_H
-#define _ASM_X86_INTEL_ARCH_PERFMON_H
+#ifndef ASM_X86__INTEL_ARCH_PERFMON_H
+#define ASM_X86__INTEL_ARCH_PERFMON_H
 
 #define MSR_ARCH_PERFMON_PERFCTR0		0xc1
 #define MSR_ARCH_PERFMON_PERFCTR1		0xc2
@@ -28,4 +28,4 @@
 	unsigned int full;
 };
 
-#endif /* _ASM_X86_INTEL_ARCH_PERFMON_H */
+#endif /* ASM_X86__INTEL_ARCH_PERFMON_H */
diff --git a/include/asm-x86/io.h b/include/asm-x86/io.h
index 0f954dc..a233f83 100644
--- a/include/asm-x86/io.h
+++ b/include/asm-x86/io.h
@@ -1,24 +1,10 @@
-#ifndef _ASM_X86_IO_H
-#define _ASM_X86_IO_H
+#ifndef ASM_X86__IO_H
+#define ASM_X86__IO_H
 
 #define ARCH_HAS_IOREMAP_WC
 
 #include <linux/compiler.h>
 
-/*
- * early_ioremap() and early_iounmap() are for temporary early boot-time
- * mappings, before the real ioremap() is functional.
- * A boot-time mapping is currently limited to at most 16 pages.
- */
-#ifndef __ASSEMBLY__
-extern void early_ioremap_init(void);
-extern void early_ioremap_clear(void);
-extern void early_ioremap_reset(void);
-extern void *early_ioremap(unsigned long offset, unsigned long size);
-extern void early_iounmap(void *addr, unsigned long size);
-extern void __iomem *fix_ioremap(unsigned idx, unsigned long phys);
-#endif
-
 #define build_mmio_read(name, size, type, reg, barrier) \
 static inline type name(const volatile void __iomem *addr) \
 { type ret; asm volatile("mov" size " %1,%0":reg (ret) \
@@ -73,6 +59,8 @@
 #define writeq writeq
 #endif
 
+extern int iommu_bio_merge;
+
 #ifdef CONFIG_X86_32
 # include "io_32.h"
 #else
@@ -95,8 +83,9 @@
 extern void early_ioremap_clear(void);
 extern void early_ioremap_reset(void);
 extern void *early_ioremap(unsigned long offset, unsigned long size);
+extern void *early_memremap(unsigned long offset, unsigned long size);
 extern void early_iounmap(void *addr, unsigned long size);
 extern void __iomem *fix_ioremap(unsigned idx, unsigned long phys);
 
 
-#endif /* _ASM_X86_IO_H */
+#endif /* ASM_X86__IO_H */
diff --git a/include/asm-x86/io_32.h b/include/asm-x86/io_32.h
index e876d89..4f7d878 100644
--- a/include/asm-x86/io_32.h
+++ b/include/asm-x86/io_32.h
@@ -1,5 +1,5 @@
-#ifndef _ASM_IO_H
-#define _ASM_IO_H
+#ifndef ASM_X86__IO_32_H
+#define ASM_X86__IO_32_H
 
 #include <linux/string.h>
 #include <linux/compiler.h>
@@ -281,4 +281,4 @@
 BUILDIO(w, w, short)
 BUILDIO(l, , int)
 
-#endif
+#endif /* ASM_X86__IO_32_H */
diff --git a/include/asm-x86/io_64.h b/include/asm-x86/io_64.h
index 22995c5..ee6e086 100644
--- a/include/asm-x86/io_64.h
+++ b/include/asm-x86/io_64.h
@@ -1,5 +1,5 @@
-#ifndef _ASM_IO_H
-#define _ASM_IO_H
+#ifndef ASM_X86__IO_64_H
+#define ASM_X86__IO_64_H
 
 
 /*
@@ -165,9 +165,6 @@
 
 #include <asm-generic/iomap.h>
 
-extern void *early_ioremap(unsigned long addr, unsigned long size);
-extern void early_iounmap(void *addr, unsigned long size);
-
 /*
  * This one maps high address device memory and turns off caching for that area.
  * it's useful if some control registers are in such an area and write combining
@@ -235,7 +232,6 @@
 
 #define flush_write_buffers()
 
-extern int iommu_bio_merge;
 #define BIO_VMERGE_BOUNDARY iommu_bio_merge
 
 /*
@@ -245,4 +241,4 @@
 
 #endif /* __KERNEL__ */
 
-#endif
+#endif /* ASM_X86__IO_64_H */
diff --git a/include/asm-x86/io_apic.h b/include/asm-x86/io_apic.h
index 14f82bb..8ec68a5 100644
--- a/include/asm-x86/io_apic.h
+++ b/include/asm-x86/io_apic.h
@@ -1,5 +1,5 @@
-#ifndef __ASM_IO_APIC_H
-#define __ASM_IO_APIC_H
+#ifndef ASM_X86__IO_APIC_H
+#define ASM_X86__IO_APIC_H
 
 #include <linux/types.h>
 #include <asm/mpspec.h>
@@ -107,6 +107,20 @@
 
 } __attribute__ ((packed));
 
+struct IR_IO_APIC_route_entry {
+	__u64	vector		: 8,
+		zero		: 3,
+		index2		: 1,
+		delivery_status : 1,
+		polarity	: 1,
+		irr		: 1,
+		trigger		: 1,
+		mask		: 1,
+		reserved	: 31,
+		format		: 1,
+		index		: 15;
+} __attribute__ ((packed));
+
 #ifdef CONFIG_X86_IO_APIC
 
 /*
@@ -183,10 +197,16 @@
 extern int (*ioapic_renumber_irq)(int ioapic, int irq);
 extern void ioapic_init_mappings(void);
 
+#ifdef CONFIG_X86_64
+extern int save_mask_IO_APIC_setup(void);
+extern void restore_IO_APIC_setup(void);
+extern void reinit_intr_remapped_IO_APIC(int);
+#endif
+
 #else  /* !CONFIG_X86_IO_APIC */
 #define io_apic_assign_pci_irqs 0
 static const int timer_through_8259 = 0;
 static inline void ioapic_init_mappings(void) { }
 #endif
 
-#endif
+#endif /* ASM_X86__IO_APIC_H */
diff --git a/include/asm-x86/ioctls.h b/include/asm-x86/ioctls.h
index c0c338b..06752a6 100644
--- a/include/asm-x86/ioctls.h
+++ b/include/asm-x86/ioctls.h
@@ -1,5 +1,5 @@
-#ifndef _ASM_X86_IOCTLS_H
-#define _ASM_X86_IOCTLS_H
+#ifndef ASM_X86__IOCTLS_H
+#define ASM_X86__IOCTLS_H
 
 #include <asm/ioctl.h>
 
@@ -51,9 +51,15 @@
 #define TCSETS2		_IOW('T', 0x2B, struct termios2)
 #define TCSETSW2	_IOW('T', 0x2C, struct termios2)
 #define TCSETSF2	_IOW('T', 0x2D, struct termios2)
+#define TIOCGRS485	0x542E
+#define TIOCSRS485	0x542F
 #define TIOCGPTN	_IOR('T', 0x30, unsigned int)
 				/* Get Pty Number (of pty-mux device) */
 #define TIOCSPTLCK	_IOW('T', 0x31, int)  /* Lock/unlock Pty */
+#define TCGETX		0x5432 /* SYS5 TCGETX compatibility */
+#define TCSETX		0x5433
+#define TCSETXF		0x5434
+#define TCSETXW		0x5435
 
 #define FIONCLEX	0x5450
 #define FIOCLEX		0x5451
@@ -85,4 +91,4 @@
 
 #define TIOCSER_TEMT    0x01	/* Transmitter physically empty */
 
-#endif
+#endif /* ASM_X86__IOCTLS_H */
diff --git a/include/asm-x86/iommu.h b/include/asm-x86/iommu.h
index 5f888cc..546ad31 100644
--- a/include/asm-x86/iommu.h
+++ b/include/asm-x86/iommu.h
@@ -1,11 +1,12 @@
-#ifndef _ASM_X8664_IOMMU_H
-#define _ASM_X8664_IOMMU_H 1
+#ifndef ASM_X86__IOMMU_H
+#define ASM_X86__IOMMU_H
 
 extern void pci_iommu_shutdown(void);
 extern void no_iommu_init(void);
 extern struct dma_mapping_ops nommu_dma_ops;
 extern int force_iommu, no_iommu;
 extern int iommu_detected;
+extern int dmar_disabled;
 
 extern unsigned long iommu_num_pages(unsigned long addr, unsigned long len);
 
@@ -42,4 +43,4 @@
 }
 #endif
 
-#endif
+#endif /* ASM_X86__IOMMU_H */
diff --git a/include/asm-x86/ipcbuf.h b/include/asm-x86/ipcbuf.h
index ee678fd..910304f 100644
--- a/include/asm-x86/ipcbuf.h
+++ b/include/asm-x86/ipcbuf.h
@@ -1,5 +1,5 @@
-#ifndef _ASM_X86_IPCBUF_H
-#define _ASM_X86_IPCBUF_H
+#ifndef ASM_X86__IPCBUF_H
+#define ASM_X86__IPCBUF_H
 
 /*
  * The ipc64_perm structure for x86 architecture.
@@ -25,4 +25,4 @@
 	unsigned long		__unused2;
 };
 
-#endif /* _ASM_X86_IPCBUF_H */
+#endif /* ASM_X86__IPCBUF_H */
diff --git a/include/asm-x86/ipi.h b/include/asm-x86/ipi.h
index bb1c09f..30a692c 100644
--- a/include/asm-x86/ipi.h
+++ b/include/asm-x86/ipi.h
@@ -1,5 +1,5 @@
-#ifndef __ASM_IPI_H
-#define __ASM_IPI_H
+#ifndef ASM_X86__IPI_H
+#define ASM_X86__IPI_H
 
 /*
  * Copyright 2004 James Cleverdon, IBM.
@@ -49,6 +49,12 @@
 	return SET_APIC_DEST_FIELD(mask);
 }
 
+static inline void __xapic_wait_icr_idle(void)
+{
+	while (native_apic_mem_read(APIC_ICR) & APIC_ICR_BUSY)
+		cpu_relax();
+}
+
 static inline void __send_IPI_shortcut(unsigned int shortcut, int vector,
 				       unsigned int dest)
 {
@@ -64,7 +70,7 @@
 	/*
 	 * Wait for idle.
 	 */
-	apic_wait_icr_idle();
+	__xapic_wait_icr_idle();
 
 	/*
 	 * No need to touch the target chip field
@@ -74,7 +80,7 @@
 	/*
 	 * Send the IPI. The write to APIC_ICR fires this off.
 	 */
-	apic_write(APIC_ICR, cfg);
+	native_apic_mem_write(APIC_ICR, cfg);
 }
 
 /*
@@ -92,13 +98,13 @@
 	if (unlikely(vector == NMI_VECTOR))
 		safe_apic_wait_icr_idle();
 	else
-		apic_wait_icr_idle();
+		__xapic_wait_icr_idle();
 
 	/*
 	 * prepare target chip field
 	 */
 	cfg = __prepare_ICR2(mask);
-	apic_write(APIC_ICR2, cfg);
+	native_apic_mem_write(APIC_ICR2, cfg);
 
 	/*
 	 * program the ICR
@@ -108,7 +114,7 @@
 	/*
 	 * Send the IPI. The write to APIC_ICR fires this off.
 	 */
-	apic_write(APIC_ICR, cfg);
+	native_apic_mem_write(APIC_ICR, cfg);
 }
 
 static inline void send_IPI_mask_sequence(cpumask_t mask, int vector)
@@ -129,4 +135,4 @@
 	local_irq_restore(flags);
 }
 
-#endif /* __ASM_IPI_H */
+#endif /* ASM_X86__IPI_H */
diff --git a/include/asm-x86/irq.h b/include/asm-x86/irq.h
index 1a29257..1e5f290 100644
--- a/include/asm-x86/irq.h
+++ b/include/asm-x86/irq.h
@@ -1,5 +1,5 @@
-#ifndef _ASM_IRQ_H
-#define _ASM_IRQ_H
+#ifndef ASM_X86__IRQ_H
+#define ASM_X86__IRQ_H
 /*
  *	(C) 1992, 1993 Linus Torvalds, (C) 1997 Ingo Molnar
  *
@@ -47,4 +47,4 @@
 /* Interrupt vector management */
 extern DECLARE_BITMAP(used_vectors, NR_VECTORS);
 
-#endif /* _ASM_IRQ_H */
+#endif /* ASM_X86__IRQ_H */
diff --git a/include/asm-x86/irq_regs_32.h b/include/asm-x86/irq_regs_32.h
index 3368b20..316a3b2 100644
--- a/include/asm-x86/irq_regs_32.h
+++ b/include/asm-x86/irq_regs_32.h
@@ -4,8 +4,8 @@
  *
  * Jeremy Fitzhardinge <jeremy@goop.org>
  */
-#ifndef _ASM_I386_IRQ_REGS_H
-#define _ASM_I386_IRQ_REGS_H
+#ifndef ASM_X86__IRQ_REGS_32_H
+#define ASM_X86__IRQ_REGS_32_H
 
 #include <asm/percpu.h>
 
@@ -26,4 +26,4 @@
 	return old_regs;
 }
 
-#endif /* _ASM_I386_IRQ_REGS_H */
+#endif /* ASM_X86__IRQ_REGS_32_H */
diff --git a/include/asm-x86/irq_remapping.h b/include/asm-x86/irq_remapping.h
new file mode 100644
index 0000000..78242c6
--- /dev/null
+++ b/include/asm-x86/irq_remapping.h
@@ -0,0 +1,8 @@
+#ifndef _ASM_IRQ_REMAPPING_H
+#define _ASM_IRQ_REMAPPING_H
+
+extern int x2apic;
+
+#define IRTE_DEST(dest) ((x2apic) ? dest : dest << 8)
+
+#endif
diff --git a/include/asm-x86/irq_vectors.h b/include/asm-x86/irq_vectors.h
index a48c7f2..c5d2d76 100644
--- a/include/asm-x86/irq_vectors.h
+++ b/include/asm-x86/irq_vectors.h
@@ -1,5 +1,5 @@
-#ifndef _ASM_IRQ_VECTORS_H
-#define _ASM_IRQ_VECTORS_H
+#ifndef ASM_X86__IRQ_VECTORS_H
+#define ASM_X86__IRQ_VECTORS_H
 
 #include <linux/threads.h>
 
@@ -179,4 +179,4 @@
 #define VIC_CPU_BOOT_ERRATA_CPI		(VIC_CPI_LEVEL0 + 8)
 
 
-#endif /* _ASM_IRQ_VECTORS_H */
+#endif /* ASM_X86__IRQ_VECTORS_H */
diff --git a/include/asm-x86/irqflags.h b/include/asm-x86/irqflags.h
index 424acb4..2bdab21 100644
--- a/include/asm-x86/irqflags.h
+++ b/include/asm-x86/irqflags.h
@@ -166,27 +166,6 @@
 	return raw_irqs_disabled_flags(flags);
 }
 
-/*
- * makes the traced hardirq state match with the machine state
- *
- * should be a rarely used function, only in places where its
- * otherwise impossible to know the irq state, like in traps.
- */
-static inline void trace_hardirqs_fixup_flags(unsigned long flags)
-{
-	if (raw_irqs_disabled_flags(flags))
-		trace_hardirqs_off();
-	else
-		trace_hardirqs_on();
-}
-
-static inline void trace_hardirqs_fixup(void)
-{
-	unsigned long flags = __raw_local_save_flags();
-
-	trace_hardirqs_fixup_flags(flags);
-}
-
 #else
 
 #ifdef CONFIG_X86_64
diff --git a/include/asm-x86/ist.h b/include/asm-x86/ist.h
index 6ec6cee..35a2fe9 100644
--- a/include/asm-x86/ist.h
+++ b/include/asm-x86/ist.h
@@ -1,5 +1,5 @@
-#ifndef _ASM_IST_H
-#define _ASM_IST_H
+#ifndef ASM_X86__IST_H
+#define ASM_X86__IST_H
 
 /*
  * Include file for the interface to IST BIOS
@@ -31,4 +31,4 @@
 extern struct ist_info ist_info;
 
 #endif	/* __KERNEL__ */
-#endif	/* _ASM_IST_H */
+#endif /* ASM_X86__IST_H */
diff --git a/include/asm-x86/k8.h b/include/asm-x86/k8.h
index 452e2b6..2bbaf43 100644
--- a/include/asm-x86/k8.h
+++ b/include/asm-x86/k8.h
@@ -1,5 +1,5 @@
-#ifndef _ASM_K8_H
-#define _ASM_K8_H 1
+#ifndef ASM_X86__K8_H
+#define ASM_X86__K8_H
 
 #include <linux/pci.h>
 
@@ -12,4 +12,4 @@
 extern void k8_flush_garts(void);
 extern int k8_scan_nodes(unsigned long start, unsigned long end);
 
-#endif
+#endif /* ASM_X86__K8_H */
diff --git a/include/asm-x86/kdebug.h b/include/asm-x86/kdebug.h
index 96651bb..fbbab66 100644
--- a/include/asm-x86/kdebug.h
+++ b/include/asm-x86/kdebug.h
@@ -1,5 +1,5 @@
-#ifndef _ASM_X86_KDEBUG_H
-#define _ASM_X86_KDEBUG_H
+#ifndef ASM_X86__KDEBUG_H
+#define ASM_X86__KDEBUG_H
 
 #include <linux/notifier.h>
 
@@ -27,12 +27,11 @@
 extern void die(const char *, struct pt_regs *,long);
 extern int __must_check __die(const char *, struct pt_regs *, long);
 extern void show_registers(struct pt_regs *regs);
-extern void __show_registers(struct pt_regs *, int all);
 extern void show_trace(struct task_struct *t, struct pt_regs *regs,
 		       unsigned long *sp, unsigned long bp);
-extern void __show_regs(struct pt_regs *regs);
+extern void __show_regs(struct pt_regs *regs, int all);
 extern void show_regs(struct pt_regs *regs);
 extern unsigned long oops_begin(void);
 extern void oops_end(unsigned long, struct pt_regs *, int signr);
 
-#endif
+#endif /* ASM_X86__KDEBUG_H */
diff --git a/include/asm-x86/kexec.h b/include/asm-x86/kexec.h
index 4246ab7..ea09600 100644
--- a/include/asm-x86/kexec.h
+++ b/include/asm-x86/kexec.h
@@ -1,5 +1,5 @@
-#ifndef _KEXEC_H
-#define _KEXEC_H
+#ifndef ASM_X86__KEXEC_H
+#define ASM_X86__KEXEC_H
 
 #ifdef CONFIG_X86_32
 # define PA_CONTROL_PAGE	0
@@ -172,4 +172,4 @@
 
 #endif /* __ASSEMBLY__ */
 
-#endif /* _KEXEC_H */
+#endif /* ASM_X86__KEXEC_H */
diff --git a/include/asm-x86/kgdb.h b/include/asm-x86/kgdb.h
index 484c475..d283863 100644
--- a/include/asm-x86/kgdb.h
+++ b/include/asm-x86/kgdb.h
@@ -1,5 +1,5 @@
-#ifndef _ASM_KGDB_H_
-#define _ASM_KGDB_H_
+#ifndef ASM_X86__KGDB_H
+#define ASM_X86__KGDB_H
 
 /*
  * Copyright (C) 2001-2004 Amit S. Kale
@@ -39,12 +39,13 @@
 	GDB_FS,			/* 14 */
 	GDB_GS,			/* 15 */
 };
+#define NUMREGBYTES		((GDB_GS+1)*4)
 #else /* ! CONFIG_X86_32 */
-enum regnames {
+enum regnames64 {
 	GDB_AX,			/* 0 */
-	GDB_DX,			/* 1 */
+	GDB_BX,			/* 1 */
 	GDB_CX,			/* 2 */
-	GDB_BX,			/* 3 */
+	GDB_DX,			/* 3 */
 	GDB_SI,			/* 4 */
 	GDB_DI,			/* 5 */
 	GDB_BP,			/* 6 */
@@ -58,18 +59,15 @@
 	GDB_R14,		/* 14 */
 	GDB_R15,		/* 15 */
 	GDB_PC,			/* 16 */
-	GDB_PS,			/* 17 */
 };
-#endif /* CONFIG_X86_32 */
 
-/*
- * Number of bytes of registers:
- */
-#ifdef CONFIG_X86_32
-# define NUMREGBYTES		64
-#else
-# define NUMREGBYTES		((GDB_PS+1)*8)
-#endif
+enum regnames32 {
+	GDB_PS = 34,
+	GDB_CS,
+	GDB_SS,
+};
+#define NUMREGBYTES		((GDB_SS+1)*4)
+#endif /* CONFIG_X86_32 */
 
 static inline void arch_kgdb_breakpoint(void)
 {
@@ -78,4 +76,4 @@
 #define BREAK_INSTR_SIZE	1
 #define CACHE_FLUSH_IS_SAFE	1
 
-#endif				/* _ASM_KGDB_H_ */
+#endif /* ASM_X86__KGDB_H */
diff --git a/include/asm-x86/kmap_types.h b/include/asm-x86/kmap_types.h
index 5f41741..89f4449 100644
--- a/include/asm-x86/kmap_types.h
+++ b/include/asm-x86/kmap_types.h
@@ -1,5 +1,5 @@
-#ifndef _ASM_X86_KMAP_TYPES_H
-#define _ASM_X86_KMAP_TYPES_H
+#ifndef ASM_X86__KMAP_TYPES_H
+#define ASM_X86__KMAP_TYPES_H
 
 #if defined(CONFIG_X86_32) && defined(CONFIG_DEBUG_HIGHMEM)
 # define D(n) __KM_FENCE_##n ,
@@ -26,4 +26,4 @@
 
 #undef D
 
-#endif
+#endif /* ASM_X86__KMAP_TYPES_H */
diff --git a/include/asm-x86/kprobes.h b/include/asm-x86/kprobes.h
index 54980b0..8a0748d 100644
--- a/include/asm-x86/kprobes.h
+++ b/include/asm-x86/kprobes.h
@@ -1,5 +1,5 @@
-#ifndef _ASM_KPROBES_H
-#define _ASM_KPROBES_H
+#ifndef ASM_X86__KPROBES_H
+#define ASM_X86__KPROBES_H
 /*
  *  Kernel Probes (KProbes)
  *
@@ -82,16 +82,7 @@
 	struct prev_kprobe prev_kprobe;
 };
 
-/* trap3/1 are intr gates for kprobes.  So, restore the status of IF,
- * if necessary, before executing the original int3/1 (trap) handler.
- */
-static inline void restore_interrupts(struct pt_regs *regs)
-{
-	if (regs->flags & X86_EFLAGS_IF)
-		local_irq_enable();
-}
-
 extern int kprobe_fault_handler(struct pt_regs *regs, int trapnr);
 extern int kprobe_exceptions_notify(struct notifier_block *self,
 				    unsigned long val, void *data);
-#endif				/* _ASM_KPROBES_H */
+#endif /* ASM_X86__KPROBES_H */
diff --git a/include/asm-x86/kvm.h b/include/asm-x86/kvm.h
index 6f18408..78e954d 100644
--- a/include/asm-x86/kvm.h
+++ b/include/asm-x86/kvm.h
@@ -1,5 +1,5 @@
-#ifndef __LINUX_KVM_X86_H
-#define __LINUX_KVM_X86_H
+#ifndef ASM_X86__KVM_H
+#define ASM_X86__KVM_H
 
 /*
  * KVM x86 specific structures and definitions
@@ -230,4 +230,4 @@
 #define KVM_TRC_APIC_ACCESS      (KVM_TRC_HANDLER + 0x14)
 #define KVM_TRC_TDP_FAULT        (KVM_TRC_HANDLER + 0x15)
 
-#endif
+#endif /* ASM_X86__KVM_H */
diff --git a/include/asm-x86/kvm_host.h b/include/asm-x86/kvm_host.h
index c2e34c2..6979454 100644
--- a/include/asm-x86/kvm_host.h
+++ b/include/asm-x86/kvm_host.h
@@ -1,4 +1,4 @@
-#/*
+/*
  * Kernel-based Virtual Machine driver for Linux
  *
  * This header defines architecture specific interfaces, x86 version
@@ -8,8 +8,8 @@
  *
  */
 
-#ifndef ASM_KVM_HOST_H
-#define ASM_KVM_HOST_H
+#ifndef ASM_X86__KVM_HOST_H
+#define ASM_X86__KVM_HOST_H
 
 #include <linux/types.h>
 #include <linux/mm.h>
@@ -735,4 +735,4 @@
 int kvm_unmap_hva(struct kvm *kvm, unsigned long hva);
 int kvm_age_hva(struct kvm *kvm, unsigned long hva);
 
-#endif
+#endif /* ASM_X86__KVM_HOST_H */
diff --git a/include/asm-x86/kvm_para.h b/include/asm-x86/kvm_para.h
index 76f3921..30054fd 100644
--- a/include/asm-x86/kvm_para.h
+++ b/include/asm-x86/kvm_para.h
@@ -1,5 +1,5 @@
-#ifndef __X86_KVM_PARA_H
-#define __X86_KVM_PARA_H
+#ifndef ASM_X86__KVM_PARA_H
+#define ASM_X86__KVM_PARA_H
 
 /* This CPUID returns the signature 'KVMKVMKVM' in ebx, ecx, and edx.  It
  * should be used to determine that a VM is running under KVM.
@@ -144,4 +144,4 @@
 
 #endif
 
-#endif
+#endif /* ASM_X86__KVM_PARA_H */
diff --git a/include/asm-x86/kvm_x86_emulate.h b/include/asm-x86/kvm_x86_emulate.h
index 4e8c1e4..e2d9b03 100644
--- a/include/asm-x86/kvm_x86_emulate.h
+++ b/include/asm-x86/kvm_x86_emulate.h
@@ -8,8 +8,8 @@
  * From: xen-unstable 10676:af9809f51f81a3c43f276f00c81a52ef558afda4
  */
 
-#ifndef __X86_EMULATE_H__
-#define __X86_EMULATE_H__
+#ifndef ASM_X86__KVM_X86_EMULATE_H
+#define ASM_X86__KVM_X86_EMULATE_H
 
 struct x86_emulate_ctxt;
 
@@ -181,4 +181,4 @@
 int x86_emulate_insn(struct x86_emulate_ctxt *ctxt,
 		     struct x86_emulate_ops *ops);
 
-#endif				/* __X86_EMULATE_H__ */
+#endif /* ASM_X86__KVM_X86_EMULATE_H */
diff --git a/include/asm-x86/ldt.h b/include/asm-x86/ldt.h
index 20c5972..a522850 100644
--- a/include/asm-x86/ldt.h
+++ b/include/asm-x86/ldt.h
@@ -3,8 +3,8 @@
  *
  * Definitions of structures used with the modify_ldt system call.
  */
-#ifndef _ASM_X86_LDT_H
-#define _ASM_X86_LDT_H
+#ifndef ASM_X86__LDT_H
+#define ASM_X86__LDT_H
 
 /* Maximum number of LDT entries supported. */
 #define LDT_ENTRIES	8192
@@ -37,4 +37,4 @@
 #define MODIFY_LDT_CONTENTS_CODE	2
 
 #endif /* !__ASSEMBLY__ */
-#endif
+#endif /* ASM_X86__LDT_H */
diff --git a/include/asm-x86/lguest.h b/include/asm-x86/lguest.h
index be4a724..7505e94 100644
--- a/include/asm-x86/lguest.h
+++ b/include/asm-x86/lguest.h
@@ -1,5 +1,5 @@
-#ifndef _X86_LGUEST_H
-#define _X86_LGUEST_H
+#ifndef ASM_X86__LGUEST_H
+#define ASM_X86__LGUEST_H
 
 #define GDT_ENTRY_LGUEST_CS	10
 #define GDT_ENTRY_LGUEST_DS	11
@@ -91,4 +91,4 @@
 
 #endif /* __ASSEMBLY__ */
 
-#endif
+#endif /* ASM_X86__LGUEST_H */
diff --git a/include/asm-x86/lguest_hcall.h b/include/asm-x86/lguest_hcall.h
index a3241f2..8f034ba 100644
--- a/include/asm-x86/lguest_hcall.h
+++ b/include/asm-x86/lguest_hcall.h
@@ -1,6 +1,6 @@
 /* Architecture specific portion of the lguest hypercalls */
-#ifndef _X86_LGUEST_HCALL_H
-#define _X86_LGUEST_HCALL_H
+#ifndef ASM_X86__LGUEST_HCALL_H
+#define ASM_X86__LGUEST_HCALL_H
 
 #define LHCALL_FLUSH_ASYNC	0
 #define LHCALL_LGUEST_INIT	1
@@ -68,4 +68,4 @@
 };
 
 #endif /* !__ASSEMBLY__ */
-#endif	/* _I386_LGUEST_HCALL_H */
+#endif /* ASM_X86__LGUEST_HCALL_H */
diff --git a/include/asm-x86/linkage.h b/include/asm-x86/linkage.h
index 64e444f..42d8b62 100644
--- a/include/asm-x86/linkage.h
+++ b/include/asm-x86/linkage.h
@@ -1,5 +1,5 @@
-#ifndef __ASM_LINKAGE_H
-#define __ASM_LINKAGE_H
+#ifndef ASM_X86__LINKAGE_H
+#define ASM_X86__LINKAGE_H
 
 #undef notrace
 #define notrace __attribute__((no_instrument_function))
@@ -57,5 +57,5 @@
 #define __ALIGN_STR ".align 16,0x90"
 #endif
 
-#endif
+#endif /* ASM_X86__LINKAGE_H */
 
diff --git a/include/asm-x86/local.h b/include/asm-x86/local.h
index 330a724..ae91994 100644
--- a/include/asm-x86/local.h
+++ b/include/asm-x86/local.h
@@ -1,5 +1,5 @@
-#ifndef _ARCH_LOCAL_H
-#define _ARCH_LOCAL_H
+#ifndef ASM_X86__LOCAL_H
+#define ASM_X86__LOCAL_H
 
 #include <linux/percpu.h>
 
@@ -232,4 +232,4 @@
 #define __cpu_local_add(i, l)	cpu_local_add((i), (l))
 #define __cpu_local_sub(i, l)	cpu_local_sub((i), (l))
 
-#endif /* _ARCH_LOCAL_H */
+#endif /* ASM_X86__LOCAL_H */
diff --git a/include/asm-x86/mach-bigsmp/mach_apic.h b/include/asm-x86/mach-bigsmp/mach_apic.h
deleted file mode 100644
index c3b9dc6..0000000
--- a/include/asm-x86/mach-bigsmp/mach_apic.h
+++ /dev/null
@@ -1,144 +0,0 @@
-#ifndef __ASM_MACH_APIC_H
-#define __ASM_MACH_APIC_H
-
-#define xapic_phys_to_log_apicid(cpu) (per_cpu(x86_bios_cpu_apicid, cpu))
-#define esr_disable (1)
-
-static inline int apic_id_registered(void)
-{
-	return (1);
-}
-
-/* Round robin the irqs amoung the online cpus */
-static inline cpumask_t target_cpus(void)
-{ 
-	static unsigned long cpu = NR_CPUS;
-	do {
-		if (cpu >= NR_CPUS)
-			cpu = first_cpu(cpu_online_map);
-		else
-			cpu = next_cpu(cpu, cpu_online_map);
-	} while (cpu >= NR_CPUS);
-	return cpumask_of_cpu(cpu);
-}
-
-#undef APIC_DEST_LOGICAL
-#define APIC_DEST_LOGICAL 	0
-#define TARGET_CPUS		(target_cpus())
-#define APIC_DFR_VALUE		(APIC_DFR_FLAT)
-#define INT_DELIVERY_MODE	(dest_Fixed)
-#define INT_DEST_MODE		(0)    /* phys delivery to target proc */
-#define NO_BALANCE_IRQ		(0)
-#define WAKE_SECONDARY_VIA_INIT
-
-
-static inline unsigned long check_apicid_used(physid_mask_t bitmap, int apicid)
-{
-	return (0);
-}
-
-static inline unsigned long check_apicid_present(int bit)
-{
-	return (1);
-}
-
-static inline unsigned long calculate_ldr(int cpu)
-{
-	unsigned long val, id;
-	val = apic_read(APIC_LDR) & ~APIC_LDR_MASK;
-	id = xapic_phys_to_log_apicid(cpu);
-	val |= SET_APIC_LOGICAL_ID(id);
-	return val;
-}
-
-/*
- * Set up the logical destination ID.
- *
- * Intel recommends to set DFR, LDR and TPR before enabling
- * an APIC.  See e.g. "AP-388 82489DX User's Manual" (Intel
- * document number 292116).  So here it goes...
- */
-static inline void init_apic_ldr(void)
-{
-	unsigned long val;
-	int cpu = smp_processor_id();
-
-	apic_write(APIC_DFR, APIC_DFR_VALUE);
-	val = calculate_ldr(cpu);
-	apic_write(APIC_LDR, val);
-}
-
-static inline void setup_apic_routing(void)
-{
-	printk("Enabling APIC mode:  %s.  Using %d I/O APICs\n",
-		"Physflat", nr_ioapics);
-}
-
-static inline int multi_timer_check(int apic, int irq)
-{
-	return (0);
-}
-
-static inline int apicid_to_node(int logical_apicid)
-{
-	return apicid_2_node[hard_smp_processor_id()];
-}
-
-static inline int cpu_present_to_apicid(int mps_cpu)
-{
-	if (mps_cpu < NR_CPUS)
-		return (int) per_cpu(x86_bios_cpu_apicid, mps_cpu);
-
-	return BAD_APICID;
-}
-
-static inline physid_mask_t apicid_to_cpu_present(int phys_apicid)
-{
-	return physid_mask_of_physid(phys_apicid);
-}
-
-extern u8 cpu_2_logical_apicid[];
-/* Mapping from cpu number to logical apicid */
-static inline int cpu_to_logical_apicid(int cpu)
-{
-	if (cpu >= NR_CPUS)
-		return BAD_APICID;
-	return cpu_physical_id(cpu);
-}
-
-static inline physid_mask_t ioapic_phys_id_map(physid_mask_t phys_map)
-{
-	/* For clustered we don't have a good way to do this yet - hack */
-	return physids_promote(0xFFL);
-}
-
-static inline void setup_portio_remap(void)
-{
-}
-
-static inline void enable_apic_mode(void)
-{
-}
-
-static inline int check_phys_apicid_present(int boot_cpu_physical_apicid)
-{
-	return (1);
-}
-
-/* As we are using single CPU as destination, pick only one CPU here */
-static inline unsigned int cpu_mask_to_apicid(cpumask_t cpumask)
-{
-	int cpu;
-	int apicid;	
-
-	cpu = first_cpu(cpumask);
-	apicid = cpu_to_logical_apicid(cpu);
-	return apicid;
-}
-
-static inline u32 phys_pkg_id(u32 cpuid_apic, int index_msb)
-{
-	return cpuid_apic >> index_msb;
-}
-
-#endif /* __ASM_MACH_APIC_H */
diff --git a/include/asm-x86/mach-bigsmp/mach_apicdef.h b/include/asm-x86/mach-bigsmp/mach_apicdef.h
deleted file mode 100644
index a58ab5a..0000000
--- a/include/asm-x86/mach-bigsmp/mach_apicdef.h
+++ /dev/null
@@ -1,13 +0,0 @@
-#ifndef __ASM_MACH_APICDEF_H
-#define __ASM_MACH_APICDEF_H
-
-#define		APIC_ID_MASK		(0xFF<<24)
-
-static inline unsigned get_apic_id(unsigned long x) 
-{ 
-	return (((x)>>24)&0xFF);
-} 
-
-#define		GET_APIC_ID(x)	get_apic_id(x)
-
-#endif
diff --git a/include/asm-x86/mach-default/apm.h b/include/asm-x86/mach-default/apm.h
index 989f34c..2aa61b5 100644
--- a/include/asm-x86/mach-default/apm.h
+++ b/include/asm-x86/mach-default/apm.h
@@ -3,8 +3,8 @@
  *  Split out from apm.c by Osamu Tomita <tomita@cinet.co.jp>
  */
 
-#ifndef _ASM_APM_H
-#define _ASM_APM_H
+#ifndef ASM_X86__MACH_DEFAULT__APM_H
+#define ASM_X86__MACH_DEFAULT__APM_H
 
 #ifdef APM_ZERO_SEGS
 #	define APM_DO_ZERO_SEGS \
@@ -70,4 +70,4 @@
 	return error;
 }
 
-#endif /* _ASM_APM_H */
+#endif /* ASM_X86__MACH_DEFAULT__APM_H */
diff --git a/include/asm-x86/mach-default/mach_apic.h b/include/asm-x86/mach-default/mach_apic.h
index f3226b9..2a330a4 100644
--- a/include/asm-x86/mach-default/mach_apic.h
+++ b/include/asm-x86/mach-default/mach_apic.h
@@ -1,5 +1,5 @@
-#ifndef __ASM_MACH_APIC_H
-#define __ASM_MACH_APIC_H
+#ifndef ASM_X86__MACH_DEFAULT__MACH_APIC_H
+#define ASM_X86__MACH_DEFAULT__MACH_APIC_H
 
 #ifdef CONFIG_X86_LOCAL_APIC
 
@@ -30,6 +30,8 @@
 #define cpu_mask_to_apicid (genapic->cpu_mask_to_apicid)
 #define phys_pkg_id	(genapic->phys_pkg_id)
 #define vector_allocation_domain    (genapic->vector_allocation_domain)
+#define read_apic_id()  (GET_APIC_ID(apic_read(APIC_ID)))
+#define send_IPI_self (genapic->send_IPI_self)
 extern void setup_apic_routing(void);
 #else
 #define INT_DELIVERY_MODE dest_LowestPrio
@@ -54,7 +56,7 @@
 
 static inline int apic_id_registered(void)
 {
-	return physid_isset(GET_APIC_ID(read_apic_id()), phys_cpu_present_map);
+	return physid_isset(read_apic_id(), phys_cpu_present_map);
 }
 
 static inline unsigned int cpu_mask_to_apicid(cpumask_t cpumask)
@@ -138,4 +140,4 @@
 }
 
 #endif /* CONFIG_X86_LOCAL_APIC */
-#endif /* __ASM_MACH_APIC_H */
+#endif /* ASM_X86__MACH_DEFAULT__MACH_APIC_H */
diff --git a/include/asm-x86/mach-default/mach_apicdef.h b/include/asm-x86/mach-default/mach_apicdef.h
index e4b29ba..0c2d41c 100644
--- a/include/asm-x86/mach-default/mach_apicdef.h
+++ b/include/asm-x86/mach-default/mach_apicdef.h
@@ -1,12 +1,12 @@
-#ifndef __ASM_MACH_APICDEF_H
-#define __ASM_MACH_APICDEF_H
+#ifndef ASM_X86__MACH_DEFAULT__MACH_APICDEF_H
+#define ASM_X86__MACH_DEFAULT__MACH_APICDEF_H
 
 #include <asm/apic.h>
 
 #ifdef CONFIG_X86_64
-#define	APIC_ID_MASK		(0xFFu<<24)
-#define GET_APIC_ID(x)          (((x)>>24)&0xFFu)
-#define	SET_APIC_ID(x)		(((x)<<24))
+#define	APIC_ID_MASK		(genapic->apic_id_mask)
+#define GET_APIC_ID(x)		(genapic->get_apic_id(x))
+#define	SET_APIC_ID(x)		(genapic->set_apic_id(x))
 #else
 #define		APIC_ID_MASK		(0xF<<24)
 static inline unsigned get_apic_id(unsigned long x) 
@@ -21,4 +21,4 @@
 #define		GET_APIC_ID(x)	get_apic_id(x)
 #endif
 
-#endif
+#endif /* ASM_X86__MACH_DEFAULT__MACH_APICDEF_H */
diff --git a/include/asm-x86/mach-default/mach_ipi.h b/include/asm-x86/mach-default/mach_ipi.h
index be32336..674bc7e 100644
--- a/include/asm-x86/mach-default/mach_ipi.h
+++ b/include/asm-x86/mach-default/mach_ipi.h
@@ -1,5 +1,5 @@
-#ifndef __ASM_MACH_IPI_H
-#define __ASM_MACH_IPI_H
+#ifndef ASM_X86__MACH_DEFAULT__MACH_IPI_H
+#define ASM_X86__MACH_DEFAULT__MACH_IPI_H
 
 /* Avoid include hell */
 #define NMI_VECTOR 0x02
@@ -61,4 +61,4 @@
 }
 #endif
 
-#endif /* __ASM_MACH_IPI_H */
+#endif /* ASM_X86__MACH_DEFAULT__MACH_IPI_H */
diff --git a/include/asm-x86/mach-default/mach_mpparse.h b/include/asm-x86/mach-default/mach_mpparse.h
index d141085..9c381f2 100644
--- a/include/asm-x86/mach-default/mach_mpparse.h
+++ b/include/asm-x86/mach-default/mach_mpparse.h
@@ -1,5 +1,5 @@
-#ifndef __ASM_MACH_MPPARSE_H
-#define __ASM_MACH_MPPARSE_H
+#ifndef ASM_X86__MACH_DEFAULT__MACH_MPPARSE_H
+#define ASM_X86__MACH_DEFAULT__MACH_MPPARSE_H
 
 static inline int mps_oem_check(struct mp_config_table *mpc, char *oem, 
 		char *productid)
@@ -14,4 +14,4 @@
 }
 
 
-#endif /* __ASM_MACH_MPPARSE_H */
+#endif /* ASM_X86__MACH_DEFAULT__MACH_MPPARSE_H */
diff --git a/include/asm-x86/mach-default/mach_mpspec.h b/include/asm-x86/mach-default/mach_mpspec.h
index 51c9a97..d77646f 100644
--- a/include/asm-x86/mach-default/mach_mpspec.h
+++ b/include/asm-x86/mach-default/mach_mpspec.h
@@ -1,5 +1,5 @@
-#ifndef __ASM_MACH_MPSPEC_H
-#define __ASM_MACH_MPSPEC_H
+#ifndef ASM_X86__MACH_DEFAULT__MACH_MPSPEC_H
+#define ASM_X86__MACH_DEFAULT__MACH_MPSPEC_H
 
 #define MAX_IRQ_SOURCES 256
 
@@ -9,4 +9,4 @@
 #define MAX_MP_BUSSES 32
 #endif
 
-#endif /* __ASM_MACH_MPSPEC_H */
+#endif /* ASM_X86__MACH_DEFAULT__MACH_MPSPEC_H */
diff --git a/include/asm-x86/mach-default/mach_timer.h b/include/asm-x86/mach-default/mach_timer.h
index 4b76e53..990b158 100644
--- a/include/asm-x86/mach-default/mach_timer.h
+++ b/include/asm-x86/mach-default/mach_timer.h
@@ -10,8 +10,8 @@
  * directly because of the awkward 8-bit access mechanism of the 82C54
  * device.
  */
-#ifndef _MACH_TIMER_H
-#define _MACH_TIMER_H
+#ifndef ASM_X86__MACH_DEFAULT__MACH_TIMER_H
+#define ASM_X86__MACH_DEFAULT__MACH_TIMER_H
 
 #define CALIBRATE_TIME_MSEC 30 /* 30 msecs */
 #define CALIBRATE_LATCH	\
@@ -45,4 +45,4 @@
 	*count_p = count;
 }
 
-#endif /* !_MACH_TIMER_H */
+#endif /* ASM_X86__MACH_DEFAULT__MACH_TIMER_H */
diff --git a/include/asm-x86/mach-default/mach_traps.h b/include/asm-x86/mach-default/mach_traps.h
index 2fe7705..ff8778f 100644
--- a/include/asm-x86/mach-default/mach_traps.h
+++ b/include/asm-x86/mach-default/mach_traps.h
@@ -2,17 +2,11 @@
  *  Machine specific NMI handling for generic.
  *  Split out from traps.c by Osamu Tomita <tomita@cinet.co.jp>
  */
-#ifndef _MACH_TRAPS_H
-#define _MACH_TRAPS_H
+#ifndef ASM_X86__MACH_DEFAULT__MACH_TRAPS_H
+#define ASM_X86__MACH_DEFAULT__MACH_TRAPS_H
 
 #include <asm/mc146818rtc.h>
 
-static inline void clear_mem_error(unsigned char reason)
-{
-	reason = (reason & 0xf) | 4;
-	outb(reason, 0x61);
-}
-
 static inline unsigned char get_nmi_reason(void)
 {
 	return inb(0x61);
@@ -36,4 +30,4 @@
 		unlock_cmos();
 }
 
-#endif /* !_MACH_TRAPS_H */
+#endif /* ASM_X86__MACH_DEFAULT__MACH_TRAPS_H */
diff --git a/include/asm-x86/mach-default/mach_wakecpu.h b/include/asm-x86/mach-default/mach_wakecpu.h
index 3ebb178..361b810 100644
--- a/include/asm-x86/mach-default/mach_wakecpu.h
+++ b/include/asm-x86/mach-default/mach_wakecpu.h
@@ -1,5 +1,5 @@
-#ifndef __ASM_MACH_WAKECPU_H
-#define __ASM_MACH_WAKECPU_H
+#ifndef ASM_X86__MACH_DEFAULT__MACH_WAKECPU_H
+#define ASM_X86__MACH_DEFAULT__MACH_WAKECPU_H
 
 /* 
  * This file copes with machines that wakeup secondary CPUs by the
@@ -39,4 +39,4 @@
  #define inquire_remote_apic(apicid) {}
 #endif
 
-#endif /* __ASM_MACH_WAKECPU_H */
+#endif /* ASM_X86__MACH_DEFAULT__MACH_WAKECPU_H */
diff --git a/include/asm-x86/mach-es7000/mach_apic.h b/include/asm-x86/mach-es7000/mach_apic.h
deleted file mode 100644
index 0a3fdf9..0000000
--- a/include/asm-x86/mach-es7000/mach_apic.h
+++ /dev/null
@@ -1,194 +0,0 @@
-#ifndef __ASM_MACH_APIC_H
-#define __ASM_MACH_APIC_H
-
-#define xapic_phys_to_log_apicid(cpu) per_cpu(x86_bios_cpu_apicid, cpu)
-#define esr_disable (1)
-
-static inline int apic_id_registered(void)
-{
-	        return (1);
-}
-
-static inline cpumask_t target_cpus(void)
-{ 
-#if defined CONFIG_ES7000_CLUSTERED_APIC
-	return CPU_MASK_ALL;
-#else
-	return cpumask_of_cpu(smp_processor_id());
-#endif
-}
-#define TARGET_CPUS	(target_cpus())
-
-#if defined CONFIG_ES7000_CLUSTERED_APIC
-#define APIC_DFR_VALUE		(APIC_DFR_CLUSTER)
-#define INT_DELIVERY_MODE	(dest_LowestPrio)
-#define INT_DEST_MODE		(1)    /* logical delivery broadcast to all procs */
-#define NO_BALANCE_IRQ 		(1)
-#undef  WAKE_SECONDARY_VIA_INIT
-#define WAKE_SECONDARY_VIA_MIP
-#else
-#define APIC_DFR_VALUE		(APIC_DFR_FLAT)
-#define INT_DELIVERY_MODE	(dest_Fixed)
-#define INT_DEST_MODE		(0)    /* phys delivery to target procs */
-#define NO_BALANCE_IRQ 		(0)
-#undef  APIC_DEST_LOGICAL
-#define APIC_DEST_LOGICAL	0x0
-#define WAKE_SECONDARY_VIA_INIT
-#endif
-
-static inline unsigned long check_apicid_used(physid_mask_t bitmap, int apicid)
-{ 
-	return 0;
-} 
-static inline unsigned long check_apicid_present(int bit) 
-{
-	return physid_isset(bit, phys_cpu_present_map);
-}
-
-#define apicid_cluster(apicid) (apicid & 0xF0)
-
-static inline unsigned long calculate_ldr(int cpu)
-{
-	unsigned long id;
-	id = xapic_phys_to_log_apicid(cpu);
-	return (SET_APIC_LOGICAL_ID(id));
-}
-
-/*
- * Set up the logical destination ID.
- *
- * Intel recommends to set DFR, LdR and TPR before enabling
- * an APIC.  See e.g. "AP-388 82489DX User's Manual" (Intel
- * document number 292116).  So here it goes...
- */
-static inline void init_apic_ldr(void)
-{
-	unsigned long val;
-	int cpu = smp_processor_id();
-
-	apic_write(APIC_DFR, APIC_DFR_VALUE);
-	val = calculate_ldr(cpu);
-	apic_write(APIC_LDR, val);
-}
-
-#ifndef CONFIG_X86_GENERICARCH
-extern void enable_apic_mode(void);
-#endif
-
-extern int apic_version [MAX_APICS];
-static inline void setup_apic_routing(void)
-{
-	int apic = per_cpu(x86_bios_cpu_apicid, smp_processor_id());
-	printk("Enabling APIC mode:  %s.  Using %d I/O APICs, target cpus %lx\n",
-		(apic_version[apic] == 0x14) ? 
-		"Physical Cluster" : "Logical Cluster", nr_ioapics, cpus_addr(TARGET_CPUS)[0]);
-}
-
-static inline int multi_timer_check(int apic, int irq)
-{
-	return 0;
-}
-
-static inline int apicid_to_node(int logical_apicid)
-{
-	return 0;
-}
-
-
-static inline int cpu_present_to_apicid(int mps_cpu)
-{
-	if (!mps_cpu)
-		return boot_cpu_physical_apicid;
-	else if (mps_cpu < NR_CPUS)
-		return (int) per_cpu(x86_bios_cpu_apicid, mps_cpu);
-	else
-		return BAD_APICID;
-}
-
-static inline physid_mask_t apicid_to_cpu_present(int phys_apicid)
-{
-	static int id = 0;
-	physid_mask_t mask;
-	mask = physid_mask_of_physid(id);
-	++id;
-	return mask;
-}
-
-extern u8 cpu_2_logical_apicid[];
-/* Mapping from cpu number to logical apicid */
-static inline int cpu_to_logical_apicid(int cpu)
-{
-#ifdef CONFIG_SMP
-       if (cpu >= NR_CPUS)
-	       return BAD_APICID;
-       return (int)cpu_2_logical_apicid[cpu];
-#else
-	return logical_smp_processor_id();
-#endif
-}
-
-static inline physid_mask_t ioapic_phys_id_map(physid_mask_t phys_map)
-{
-	/* For clustered we don't have a good way to do this yet - hack */
-	return physids_promote(0xff);
-}
-
-
-static inline void setup_portio_remap(void)
-{
-}
-
-extern unsigned int boot_cpu_physical_apicid;
-static inline int check_phys_apicid_present(int cpu_physical_apicid)
-{
-	boot_cpu_physical_apicid = GET_APIC_ID(read_apic_id());
-	return (1);
-}
-
-static inline unsigned int cpu_mask_to_apicid(cpumask_t cpumask)
-{
-	int num_bits_set;
-	int cpus_found = 0;
-	int cpu;
-	int apicid;	
-
-	num_bits_set = cpus_weight(cpumask);
-	/* Return id to all */
-	if (num_bits_set == NR_CPUS)
-#if defined CONFIG_ES7000_CLUSTERED_APIC
-		return 0xFF;
-#else
-		return cpu_to_logical_apicid(0);
-#endif
-	/* 
-	 * The cpus in the mask must all be on the apic cluster.  If are not 
-	 * on the same apicid cluster return default value of TARGET_CPUS. 
-	 */
-	cpu = first_cpu(cpumask);
-	apicid = cpu_to_logical_apicid(cpu);
-	while (cpus_found < num_bits_set) {
-		if (cpu_isset(cpu, cpumask)) {
-			int new_apicid = cpu_to_logical_apicid(cpu);
-			if (apicid_cluster(apicid) != 
-					apicid_cluster(new_apicid)){
-				printk ("%s: Not a valid mask!\n",__FUNCTION__);
-#if defined CONFIG_ES7000_CLUSTERED_APIC
-				return 0xFF;
-#else
-				return cpu_to_logical_apicid(0);
-#endif
-			}
-			apicid = new_apicid;
-			cpus_found++;
-		}
-		cpu++;
-	}
-	return apicid;
-}
-
-static inline u32 phys_pkg_id(u32 cpuid_apic, int index_msb)
-{
-	return cpuid_apic >> index_msb;
-}
-
-#endif /* __ASM_MACH_APIC_H */
diff --git a/include/asm-x86/mach-es7000/mach_apicdef.h b/include/asm-x86/mach-es7000/mach_apicdef.h
deleted file mode 100644
index a58ab5a..0000000
--- a/include/asm-x86/mach-es7000/mach_apicdef.h
+++ /dev/null
@@ -1,13 +0,0 @@
-#ifndef __ASM_MACH_APICDEF_H
-#define __ASM_MACH_APICDEF_H
-
-#define		APIC_ID_MASK		(0xFF<<24)
-
-static inline unsigned get_apic_id(unsigned long x) 
-{ 
-	return (((x)>>24)&0xFF);
-} 
-
-#define		GET_APIC_ID(x)	get_apic_id(x)
-
-#endif
diff --git a/include/asm-x86/mach-es7000/mach_ipi.h b/include/asm-x86/mach-es7000/mach_ipi.h
deleted file mode 100644
index 5e61bd2..0000000
--- a/include/asm-x86/mach-es7000/mach_ipi.h
+++ /dev/null
@@ -1,24 +0,0 @@
-#ifndef __ASM_MACH_IPI_H
-#define __ASM_MACH_IPI_H
-
-void send_IPI_mask_sequence(cpumask_t mask, int vector);
-
-static inline void send_IPI_mask(cpumask_t mask, int vector)
-{
-	send_IPI_mask_sequence(mask, vector);
-}
-
-static inline void send_IPI_allbutself(int vector)
-{
-	cpumask_t mask = cpu_online_map;
-	cpu_clear(smp_processor_id(), mask);
-	if (!cpus_empty(mask))
-		send_IPI_mask(mask, vector);
-}
-
-static inline void send_IPI_all(int vector)
-{
-	send_IPI_mask(cpu_online_map, vector);
-}
-
-#endif /* __ASM_MACH_IPI_H */
diff --git a/include/asm-x86/mach-es7000/mach_mpparse.h b/include/asm-x86/mach-es7000/mach_mpparse.h
deleted file mode 100644
index ef26d35..0000000
--- a/include/asm-x86/mach-es7000/mach_mpparse.h
+++ /dev/null
@@ -1,29 +0,0 @@
-#ifndef __ASM_MACH_MPPARSE_H
-#define __ASM_MACH_MPPARSE_H
-
-#include <linux/acpi.h>
-
-extern int parse_unisys_oem (char *oemptr);
-extern int find_unisys_acpi_oem_table(unsigned long *oem_addr);
-extern void setup_unisys(void);
-
-#ifndef CONFIG_X86_GENERICARCH
-extern int acpi_madt_oem_check(char *oem_id, char *oem_table_id);
-extern int mps_oem_check(struct mp_config_table *mpc, char *oem,
-				char *productid);
-#endif
-
-#ifdef CONFIG_ACPI
-
-static inline int es7000_check_dsdt(void)
-{
-	struct acpi_table_header header;
-
-	if (ACPI_SUCCESS(acpi_get_table_header(ACPI_SIG_DSDT, 0, &header)) &&
-	    !strncmp(header.oem_id, "UNISYS", 6))
-		return 1;
-	return 0;
-}
-#endif
-
-#endif /* __ASM_MACH_MPPARSE_H */
diff --git a/include/asm-x86/mach-es7000/mach_wakecpu.h b/include/asm-x86/mach-es7000/mach_wakecpu.h
deleted file mode 100644
index 84ff583..0000000
--- a/include/asm-x86/mach-es7000/mach_wakecpu.h
+++ /dev/null
@@ -1,59 +0,0 @@
-#ifndef __ASM_MACH_WAKECPU_H
-#define __ASM_MACH_WAKECPU_H
-
-/* 
- * This file copes with machines that wakeup secondary CPUs by the
- * INIT, INIT, STARTUP sequence.
- */
-
-#ifdef CONFIG_ES7000_CLUSTERED_APIC
-#define WAKE_SECONDARY_VIA_MIP
-#else
-#define WAKE_SECONDARY_VIA_INIT
-#endif
-
-#ifdef WAKE_SECONDARY_VIA_MIP
-extern int es7000_start_cpu(int cpu, unsigned long eip);
-static inline int
-wakeup_secondary_cpu(int phys_apicid, unsigned long start_eip)
-{
-	int boot_error = 0;
-	boot_error = es7000_start_cpu(phys_apicid, start_eip);
-	return boot_error;
-}
-#endif
-
-#define TRAMPOLINE_LOW phys_to_virt(0x467)
-#define TRAMPOLINE_HIGH phys_to_virt(0x469)
-
-#define boot_cpu_apicid boot_cpu_physical_apicid
-
-static inline void wait_for_init_deassert(atomic_t *deassert)
-{
-#ifdef WAKE_SECONDARY_VIA_INIT
-	while (!atomic_read(deassert))
-		cpu_relax();
-#endif
-	return;
-}
-
-/* Nothing to do for most platforms, since cleared by the INIT cycle */
-static inline void smp_callin_clear_local_apic(void)
-{
-}
-
-static inline void store_NMI_vector(unsigned short *high, unsigned short *low)
-{
-}
-
-static inline void restore_NMI_vector(unsigned short *high, unsigned short *low)
-{
-}
-
-#if APIC_DEBUG
- #define inquire_remote_apic(apicid) __inquire_remote_apic(apicid)
-#else
- #define inquire_remote_apic(apicid) {}
-#endif
-
-#endif /* __ASM_MACH_WAKECPU_H */
diff --git a/include/asm-x86/mach-generic/gpio.h b/include/asm-x86/mach-generic/gpio.h
index 5305dcb..6ce0f77 100644
--- a/include/asm-x86/mach-generic/gpio.h
+++ b/include/asm-x86/mach-generic/gpio.h
@@ -1,5 +1,5 @@
-#ifndef __ASM_MACH_GENERIC_GPIO_H
-#define __ASM_MACH_GENERIC_GPIO_H
+#ifndef ASM_X86__MACH_GENERIC__GPIO_H
+#define ASM_X86__MACH_GENERIC__GPIO_H
 
 int gpio_request(unsigned gpio, const char *label);
 void gpio_free(unsigned gpio);
@@ -12,4 +12,4 @@
 
 #include <asm-generic/gpio.h>           /* cansleep wrappers */
 
-#endif /* __ASM_MACH_GENERIC_GPIO_H */
+#endif /* ASM_X86__MACH_GENERIC__GPIO_H */
diff --git a/include/asm-x86/mach-generic/irq_vectors_limits.h b/include/asm-x86/mach-generic/irq_vectors_limits.h
index 890ce3f..f7870e1 100644
--- a/include/asm-x86/mach-generic/irq_vectors_limits.h
+++ b/include/asm-x86/mach-generic/irq_vectors_limits.h
@@ -1,5 +1,5 @@
-#ifndef _ASM_IRQ_VECTORS_LIMITS_H
-#define _ASM_IRQ_VECTORS_LIMITS_H
+#ifndef ASM_X86__MACH_GENERIC__IRQ_VECTORS_LIMITS_H
+#define ASM_X86__MACH_GENERIC__IRQ_VECTORS_LIMITS_H
 
 /*
  * For Summit or generic (i.e. installer) kernels, we have lots of I/O APICs,
@@ -11,4 +11,4 @@
 #define NR_IRQS	224
 #define NR_IRQ_VECTORS	1024
 
-#endif /* _ASM_IRQ_VECTORS_LIMITS_H */
+#endif /* ASM_X86__MACH_GENERIC__IRQ_VECTORS_LIMITS_H */
diff --git a/include/asm-x86/mach-generic/mach_apic.h b/include/asm-x86/mach-generic/mach_apic.h
index 6eff343..5d010c6 100644
--- a/include/asm-x86/mach-generic/mach_apic.h
+++ b/include/asm-x86/mach-generic/mach_apic.h
@@ -1,5 +1,5 @@
-#ifndef __ASM_MACH_APIC_H
-#define __ASM_MACH_APIC_H
+#ifndef ASM_X86__MACH_GENERIC__MACH_APIC_H
+#define ASM_X86__MACH_GENERIC__MACH_APIC_H
 
 #include <asm/genapic.h>
 
@@ -29,4 +29,4 @@
 
 extern void generic_bigsmp_probe(void);
 
-#endif /* __ASM_MACH_APIC_H */
+#endif /* ASM_X86__MACH_GENERIC__MACH_APIC_H */
diff --git a/include/asm-x86/mach-generic/mach_apicdef.h b/include/asm-x86/mach-generic/mach_apicdef.h
index 28ed989..1657f38 100644
--- a/include/asm-x86/mach-generic/mach_apicdef.h
+++ b/include/asm-x86/mach-generic/mach_apicdef.h
@@ -1,5 +1,5 @@
-#ifndef _GENAPIC_MACH_APICDEF_H
-#define _GENAPIC_MACH_APICDEF_H 1
+#ifndef ASM_X86__MACH_GENERIC__MACH_APICDEF_H
+#define ASM_X86__MACH_GENERIC__MACH_APICDEF_H
 
 #ifndef APIC_DEFINITION
 #include <asm/genapic.h>
@@ -8,4 +8,4 @@
 #define APIC_ID_MASK (genapic->apic_id_mask)
 #endif
 
-#endif
+#endif /* ASM_X86__MACH_GENERIC__MACH_APICDEF_H */
diff --git a/include/asm-x86/mach-generic/mach_ipi.h b/include/asm-x86/mach-generic/mach_ipi.h
index 441b0fe..f67433d 100644
--- a/include/asm-x86/mach-generic/mach_ipi.h
+++ b/include/asm-x86/mach-generic/mach_ipi.h
@@ -1,5 +1,5 @@
-#ifndef _MACH_IPI_H
-#define _MACH_IPI_H 1
+#ifndef ASM_X86__MACH_GENERIC__MACH_IPI_H
+#define ASM_X86__MACH_GENERIC__MACH_IPI_H
 
 #include <asm/genapic.h>
 
@@ -7,4 +7,4 @@
 #define send_IPI_allbutself (genapic->send_IPI_allbutself)
 #define send_IPI_all (genapic->send_IPI_all)
 
-#endif
+#endif /* ASM_X86__MACH_GENERIC__MACH_IPI_H */
diff --git a/include/asm-x86/mach-generic/mach_mpparse.h b/include/asm-x86/mach-generic/mach_mpparse.h
index 586cadb..3115564 100644
--- a/include/asm-x86/mach-generic/mach_mpparse.h
+++ b/include/asm-x86/mach-generic/mach_mpparse.h
@@ -1,5 +1,5 @@
-#ifndef _MACH_MPPARSE_H
-#define _MACH_MPPARSE_H 1
+#ifndef ASM_X86__MACH_GENERIC__MACH_MPPARSE_H
+#define ASM_X86__MACH_GENERIC__MACH_MPPARSE_H
 
 
 extern int mps_oem_check(struct mp_config_table *mpc, char *oem,
@@ -7,4 +7,4 @@
 
 extern int acpi_madt_oem_check(char *oem_id, char *oem_table_id);
 
-#endif
+#endif /* ASM_X86__MACH_GENERIC__MACH_MPPARSE_H */
diff --git a/include/asm-x86/mach-generic/mach_mpspec.h b/include/asm-x86/mach-generic/mach_mpspec.h
index c83c120..6061b15 100644
--- a/include/asm-x86/mach-generic/mach_mpspec.h
+++ b/include/asm-x86/mach-generic/mach_mpspec.h
@@ -1,5 +1,5 @@
-#ifndef __ASM_MACH_MPSPEC_H
-#define __ASM_MACH_MPSPEC_H
+#ifndef ASM_X86__MACH_GENERIC__MACH_MPSPEC_H
+#define ASM_X86__MACH_GENERIC__MACH_MPSPEC_H
 
 #define MAX_IRQ_SOURCES 256
 
@@ -9,4 +9,4 @@
 
 extern void numaq_mps_oem_check(struct mp_config_table *mpc, char *oem,
 				char *productid);
-#endif /* __ASM_MACH_MPSPEC_H */
+#endif /* ASM_X86__MACH_GENERIC__MACH_MPSPEC_H */
diff --git a/include/asm-x86/mach-numaq/mach_apic.h b/include/asm-x86/mach-numaq/mach_apic.h
deleted file mode 100644
index d802465..0000000
--- a/include/asm-x86/mach-numaq/mach_apic.h
+++ /dev/null
@@ -1,138 +0,0 @@
-#ifndef __ASM_MACH_APIC_H
-#define __ASM_MACH_APIC_H
-
-#include <asm/io.h>
-#include <linux/mmzone.h>
-#include <linux/nodemask.h>
-
-#define APIC_DFR_VALUE	(APIC_DFR_CLUSTER)
-
-static inline cpumask_t target_cpus(void)
-{
-	return CPU_MASK_ALL;
-}
-
-#define TARGET_CPUS (target_cpus())
-
-#define NO_BALANCE_IRQ (1)
-#define esr_disable (1)
-
-#define INT_DELIVERY_MODE dest_LowestPrio
-#define INT_DEST_MODE 0     /* physical delivery on LOCAL quad */
- 
-static inline unsigned long check_apicid_used(physid_mask_t bitmap, int apicid)
-{
-	return physid_isset(apicid, bitmap);
-}
-static inline unsigned long check_apicid_present(int bit)
-{
-	return physid_isset(bit, phys_cpu_present_map);
-}
-#define apicid_cluster(apicid) (apicid & 0xF0)
-
-static inline int apic_id_registered(void)
-{
-	return 1;
-}
-
-static inline void init_apic_ldr(void)
-{
-	/* Already done in NUMA-Q firmware */
-}
-
-static inline void setup_apic_routing(void)
-{
-	printk("Enabling APIC mode:  %s.  Using %d I/O APICs\n",
-		"NUMA-Q", nr_ioapics);
-}
-
-/*
- * Skip adding the timer int on secondary nodes, which causes
- * a small but painful rift in the time-space continuum.
- */
-static inline int multi_timer_check(int apic, int irq)
-{
-	return apic != 0 && irq == 0;
-}
-
-static inline physid_mask_t ioapic_phys_id_map(physid_mask_t phys_map)
-{
-	/* We don't have a good way to do this yet - hack */
-	return physids_promote(0xFUL);
-}
-
-/* Mapping from cpu number to logical apicid */
-extern u8 cpu_2_logical_apicid[];
-static inline int cpu_to_logical_apicid(int cpu)
-{
-       if (cpu >= NR_CPUS)
-	       return BAD_APICID;
-	return (int)cpu_2_logical_apicid[cpu];
-}
-
-/*
- * Supporting over 60 cpus on NUMA-Q requires a locality-dependent
- * cpu to APIC ID relation to properly interact with the intelligent
- * mode of the cluster controller.
- */
-static inline int cpu_present_to_apicid(int mps_cpu)
-{
-	if (mps_cpu < 60)
-		return ((mps_cpu >> 2) << 4) | (1 << (mps_cpu & 0x3));
-	else
-		return BAD_APICID;
-}
-
-static inline int apicid_to_node(int logical_apicid) 
-{
-	return logical_apicid >> 4;
-}
-
-static inline physid_mask_t apicid_to_cpu_present(int logical_apicid)
-{
-	int node = apicid_to_node(logical_apicid);
-	int cpu = __ffs(logical_apicid & 0xf);
-
-	return physid_mask_of_physid(cpu + 4*node);
-}
-
-extern void *xquad_portio;
-
-static inline void setup_portio_remap(void)
-{
-	int num_quads = num_online_nodes();
-
-	if (num_quads <= 1)
-       		return;
-
-	printk("Remapping cross-quad port I/O for %d quads\n", num_quads);
-	xquad_portio = ioremap(XQUAD_PORTIO_BASE, num_quads*XQUAD_PORTIO_QUAD);
-	printk("xquad_portio vaddr 0x%08lx, len %08lx\n",
-		(u_long) xquad_portio, (u_long) num_quads*XQUAD_PORTIO_QUAD);
-}
-
-static inline int check_phys_apicid_present(int boot_cpu_physical_apicid)
-{
-	return (1);
-}
-
-static inline void enable_apic_mode(void)
-{
-}
-
-/*
- * We use physical apicids here, not logical, so just return the default
- * physical broadcast to stop people from breaking us
- */
-static inline unsigned int cpu_mask_to_apicid(cpumask_t cpumask)
-{
-	return (int) 0xF;
-}
-
-/* No NUMA-Q box has a HT CPU, but it can't hurt to use the default code. */
-static inline u32 phys_pkg_id(u32 cpuid_apic, int index_msb)
-{
-	return cpuid_apic >> index_msb;
-}
-
-#endif /* __ASM_MACH_APIC_H */
diff --git a/include/asm-x86/mach-numaq/mach_apicdef.h b/include/asm-x86/mach-numaq/mach_apicdef.h
deleted file mode 100644
index bf439d0..0000000
--- a/include/asm-x86/mach-numaq/mach_apicdef.h
+++ /dev/null
@@ -1,14 +0,0 @@
-#ifndef __ASM_MACH_APICDEF_H
-#define __ASM_MACH_APICDEF_H
-
-
-#define APIC_ID_MASK (0xF<<24)
-
-static inline unsigned get_apic_id(unsigned long x)
-{
-	        return (((x)>>24)&0x0F);
-}
-
-#define         GET_APIC_ID(x)  get_apic_id(x)
-
-#endif
diff --git a/include/asm-x86/mach-numaq/mach_ipi.h b/include/asm-x86/mach-numaq/mach_ipi.h
deleted file mode 100644
index c604448..0000000
--- a/include/asm-x86/mach-numaq/mach_ipi.h
+++ /dev/null
@@ -1,25 +0,0 @@
-#ifndef __ASM_MACH_IPI_H
-#define __ASM_MACH_IPI_H
-
-void send_IPI_mask_sequence(cpumask_t, int vector);
-
-static inline void send_IPI_mask(cpumask_t mask, int vector)
-{
-	send_IPI_mask_sequence(mask, vector);
-}
-
-static inline void send_IPI_allbutself(int vector)
-{
-	cpumask_t mask = cpu_online_map;
-	cpu_clear(smp_processor_id(), mask);
-
-	if (!cpus_empty(mask))
-		send_IPI_mask(mask, vector);
-}
-
-static inline void send_IPI_all(int vector)
-{
-	send_IPI_mask(cpu_online_map, vector);
-}
-
-#endif /* __ASM_MACH_IPI_H */
diff --git a/include/asm-x86/mach-numaq/mach_mpparse.h b/include/asm-x86/mach-numaq/mach_mpparse.h
deleted file mode 100644
index 626aef6..0000000
--- a/include/asm-x86/mach-numaq/mach_mpparse.h
+++ /dev/null
@@ -1,7 +0,0 @@
-#ifndef __ASM_MACH_MPPARSE_H
-#define __ASM_MACH_MPPARSE_H
-
-extern void numaq_mps_oem_check(struct mp_config_table *mpc, char *oem,
-				char *productid);
-
-#endif /* __ASM_MACH_MPPARSE_H */
diff --git a/include/asm-x86/mach-numaq/mach_wakecpu.h b/include/asm-x86/mach-numaq/mach_wakecpu.h
deleted file mode 100644
index 0053004..0000000
--- a/include/asm-x86/mach-numaq/mach_wakecpu.h
+++ /dev/null
@@ -1,43 +0,0 @@
-#ifndef __ASM_MACH_WAKECPU_H
-#define __ASM_MACH_WAKECPU_H
-
-/* This file copes with machines that wakeup secondary CPUs by NMIs */
-
-#define WAKE_SECONDARY_VIA_NMI
-
-#define TRAMPOLINE_LOW phys_to_virt(0x8)
-#define TRAMPOLINE_HIGH phys_to_virt(0xa)
-
-#define boot_cpu_apicid boot_cpu_logical_apicid
-
-/* We don't do anything here because we use NMI's to boot instead */
-static inline void wait_for_init_deassert(atomic_t *deassert)
-{
-}
-
-/*
- * Because we use NMIs rather than the INIT-STARTUP sequence to
- * bootstrap the CPUs, the APIC may be in a weird state. Kick it.
- */
-static inline void smp_callin_clear_local_apic(void)
-{
-	clear_local_APIC();
-}
-
-static inline void store_NMI_vector(unsigned short *high, unsigned short *low)
-{
-	printk("Storing NMI vector\n");
-	*high = *((volatile unsigned short *) TRAMPOLINE_HIGH);
-	*low = *((volatile unsigned short *) TRAMPOLINE_LOW);
-}
-
-static inline void restore_NMI_vector(unsigned short *high, unsigned short *low)
-{
-	printk("Restoring NMI vector\n");
-	*((volatile unsigned short *) TRAMPOLINE_HIGH) = *high;
-	*((volatile unsigned short *) TRAMPOLINE_LOW) = *low;
-}
-
-#define inquire_remote_apic(apicid) {}
-
-#endif /* __ASM_MACH_WAKECPU_H */
diff --git a/include/asm-x86/mach-rdc321x/gpio.h b/include/asm-x86/mach-rdc321x/gpio.h
index acce0b7..94b6cdf 100644
--- a/include/asm-x86/mach-rdc321x/gpio.h
+++ b/include/asm-x86/mach-rdc321x/gpio.h
@@ -1,5 +1,7 @@
-#ifndef _RDC321X_GPIO_H
-#define _RDC321X_GPIO_H
+#ifndef ASM_X86__MACH_RDC321X__GPIO_H
+#define ASM_X86__MACH_RDC321X__GPIO_H
+
+#include <linux/kernel.h>
 
 extern int rdc_gpio_get_value(unsigned gpio);
 extern void rdc_gpio_set_value(unsigned gpio, int value);
@@ -18,6 +20,7 @@
 
 static inline void gpio_free(unsigned gpio)
 {
+	might_sleep();
 	rdc_gpio_free(gpio);
 }
 
@@ -54,4 +57,4 @@
 /* For cansleep */
 #include <asm-generic/gpio.h>
 
-#endif /* _RDC321X_GPIO_H_ */
+#endif /* ASM_X86__MACH_RDC321X__GPIO_H */
diff --git a/include/asm-x86/mach-summit/mach_apic.h b/include/asm-x86/mach-summit/mach_apic.h
deleted file mode 100644
index c47e2ab..0000000
--- a/include/asm-x86/mach-summit/mach_apic.h
+++ /dev/null
@@ -1,185 +0,0 @@
-#ifndef __ASM_MACH_APIC_H
-#define __ASM_MACH_APIC_H
-
-#include <asm/smp.h>
-
-#define esr_disable (1)
-#define NO_BALANCE_IRQ (0)
-
-/* In clustered mode, the high nibble of APIC ID is a cluster number.
- * The low nibble is a 4-bit bitmap. */
-#define XAPIC_DEST_CPUS_SHIFT	4
-#define XAPIC_DEST_CPUS_MASK	((1u << XAPIC_DEST_CPUS_SHIFT) - 1)
-#define XAPIC_DEST_CLUSTER_MASK	(XAPIC_DEST_CPUS_MASK << XAPIC_DEST_CPUS_SHIFT)
-
-#define APIC_DFR_VALUE	(APIC_DFR_CLUSTER)
-
-static inline cpumask_t target_cpus(void)
-{
-	/* CPU_MASK_ALL (0xff) has undefined behaviour with
-	 * dest_LowestPrio mode logical clustered apic interrupt routing
-	 * Just start on cpu 0.  IRQ balancing will spread load
-	 */
-	return cpumask_of_cpu(0);
-} 
-#define TARGET_CPUS	(target_cpus())
-
-#define INT_DELIVERY_MODE (dest_LowestPrio)
-#define INT_DEST_MODE 1     /* logical delivery broadcast to all procs */
-
-static inline unsigned long check_apicid_used(physid_mask_t bitmap, int apicid)
-{
-	return 0;
-} 
-
-/* we don't use the phys_cpu_present_map to indicate apicid presence */
-static inline unsigned long check_apicid_present(int bit) 
-{
-	return 1;
-}
-
-#define apicid_cluster(apicid) ((apicid) & XAPIC_DEST_CLUSTER_MASK)
-
-extern u8 cpu_2_logical_apicid[];
-
-static inline void init_apic_ldr(void)
-{
-	unsigned long val, id;
-	int count = 0;
-	u8 my_id = (u8)hard_smp_processor_id();
-	u8 my_cluster = (u8)apicid_cluster(my_id);
-#ifdef CONFIG_SMP
-	u8 lid;
-	int i;
-
-	/* Create logical APIC IDs by counting CPUs already in cluster. */
-	for (count = 0, i = NR_CPUS; --i >= 0; ) {
-		lid = cpu_2_logical_apicid[i];
-		if (lid != BAD_APICID && apicid_cluster(lid) == my_cluster)
-			++count;
-	}
-#endif
-	/* We only have a 4 wide bitmap in cluster mode.  If a deranged
-	 * BIOS puts 5 CPUs in one APIC cluster, we're hosed. */
-	BUG_ON(count >= XAPIC_DEST_CPUS_SHIFT);
-	id = my_cluster | (1UL << count);
-	apic_write(APIC_DFR, APIC_DFR_VALUE);
-	val = apic_read(APIC_LDR) & ~APIC_LDR_MASK;
-	val |= SET_APIC_LOGICAL_ID(id);
-	apic_write(APIC_LDR, val);
-}
-
-static inline int multi_timer_check(int apic, int irq)
-{
-	return 0;
-}
-
-static inline int apic_id_registered(void)
-{
-	return 1;
-}
-
-static inline void setup_apic_routing(void)
-{
-	printk("Enabling APIC mode:  Summit.  Using %d I/O APICs\n",
-						nr_ioapics);
-}
-
-static inline int apicid_to_node(int logical_apicid)
-{
-#ifdef CONFIG_SMP
-	return apicid_2_node[hard_smp_processor_id()];
-#else
-	return 0;
-#endif
-}
-
-/* Mapping from cpu number to logical apicid */
-static inline int cpu_to_logical_apicid(int cpu)
-{
-#ifdef CONFIG_SMP
-       if (cpu >= NR_CPUS)
-	       return BAD_APICID;
-	return (int)cpu_2_logical_apicid[cpu];
-#else
-	return logical_smp_processor_id();
-#endif
-}
-
-static inline int cpu_present_to_apicid(int mps_cpu)
-{
-	if (mps_cpu < NR_CPUS)
-		return (int)per_cpu(x86_bios_cpu_apicid, mps_cpu);
-	else
-		return BAD_APICID;
-}
-
-static inline physid_mask_t ioapic_phys_id_map(physid_mask_t phys_id_map)
-{
-	/* For clustered we don't have a good way to do this yet - hack */
-	return physids_promote(0x0F);
-}
-
-static inline physid_mask_t apicid_to_cpu_present(int apicid)
-{
-	return physid_mask_of_physid(apicid);
-}
-
-static inline void setup_portio_remap(void)
-{
-}
-
-static inline int check_phys_apicid_present(int boot_cpu_physical_apicid)
-{
-	return 1;
-}
-
-static inline void enable_apic_mode(void)
-{
-}
-
-static inline unsigned int cpu_mask_to_apicid(cpumask_t cpumask)
-{
-	int num_bits_set;
-	int cpus_found = 0;
-	int cpu;
-	int apicid;	
-
-	num_bits_set = cpus_weight(cpumask);
-	/* Return id to all */
-	if (num_bits_set == NR_CPUS)
-		return (int) 0xFF;
-	/* 
-	 * The cpus in the mask must all be on the apic cluster.  If are not 
-	 * on the same apicid cluster return default value of TARGET_CPUS. 
-	 */
-	cpu = first_cpu(cpumask);
-	apicid = cpu_to_logical_apicid(cpu);
-	while (cpus_found < num_bits_set) {
-		if (cpu_isset(cpu, cpumask)) {
-			int new_apicid = cpu_to_logical_apicid(cpu);
-			if (apicid_cluster(apicid) != 
-					apicid_cluster(new_apicid)){
-				printk ("%s: Not a valid mask!\n",__FUNCTION__);
-				return 0xFF;
-			}
-			apicid = apicid | new_apicid;
-			cpus_found++;
-		}
-		cpu++;
-	}
-	return apicid;
-}
-
-/* cpuid returns the value latched in the HW at reset, not the APIC ID
- * register's value.  For any box whose BIOS changes APIC IDs, like
- * clustered APIC systems, we must use hard_smp_processor_id.
- *
- * See Intel's IA-32 SW Dev's Manual Vol2 under CPUID.
- */
-static inline u32 phys_pkg_id(u32 cpuid_apic, int index_msb)
-{
-	return hard_smp_processor_id() >> index_msb;
-}
-
-#endif /* __ASM_MACH_APIC_H */
diff --git a/include/asm-x86/mach-summit/mach_apicdef.h b/include/asm-x86/mach-summit/mach_apicdef.h
deleted file mode 100644
index a58ab5a..0000000
--- a/include/asm-x86/mach-summit/mach_apicdef.h
+++ /dev/null
@@ -1,13 +0,0 @@
-#ifndef __ASM_MACH_APICDEF_H
-#define __ASM_MACH_APICDEF_H
-
-#define		APIC_ID_MASK		(0xFF<<24)
-
-static inline unsigned get_apic_id(unsigned long x) 
-{ 
-	return (((x)>>24)&0xFF);
-} 
-
-#define		GET_APIC_ID(x)	get_apic_id(x)
-
-#endif
diff --git a/include/asm-x86/mach-summit/mach_ipi.h b/include/asm-x86/mach-summit/mach_ipi.h
deleted file mode 100644
index 9404c53..0000000
--- a/include/asm-x86/mach-summit/mach_ipi.h
+++ /dev/null
@@ -1,25 +0,0 @@
-#ifndef __ASM_MACH_IPI_H
-#define __ASM_MACH_IPI_H
-
-void send_IPI_mask_sequence(cpumask_t mask, int vector);
-
-static inline void send_IPI_mask(cpumask_t mask, int vector)
-{
-	send_IPI_mask_sequence(mask, vector);
-}
-
-static inline void send_IPI_allbutself(int vector)
-{
-	cpumask_t mask = cpu_online_map;
-	cpu_clear(smp_processor_id(), mask);
-
-	if (!cpus_empty(mask))
-		send_IPI_mask(mask, vector);
-}
-
-static inline void send_IPI_all(int vector)
-{
-	send_IPI_mask(cpu_online_map, vector);
-}
-
-#endif /* __ASM_MACH_IPI_H */
diff --git a/include/asm-x86/mach-summit/mach_mpparse.h b/include/asm-x86/mach-summit/mach_mpparse.h
deleted file mode 100644
index fdf5917..0000000
--- a/include/asm-x86/mach-summit/mach_mpparse.h
+++ /dev/null
@@ -1,110 +0,0 @@
-#ifndef __ASM_MACH_MPPARSE_H
-#define __ASM_MACH_MPPARSE_H
-
-#include <mach_apic.h>
-#include <asm/tsc.h>
-
-extern int use_cyclone;
-
-#ifdef CONFIG_X86_SUMMIT_NUMA
-extern void setup_summit(void);
-#else
-#define setup_summit()	{}
-#endif
-
-static inline int mps_oem_check(struct mp_config_table *mpc, char *oem, 
-		char *productid)
-{
-	if (!strncmp(oem, "IBM ENSW", 8) && 
-			(!strncmp(productid, "VIGIL SMP", 9) 
-			 || !strncmp(productid, "EXA", 3)
-			 || !strncmp(productid, "RUTHLESS SMP", 12))){
-		mark_tsc_unstable("Summit based system");
-		use_cyclone = 1; /*enable cyclone-timer*/
-		setup_summit();
-		return 1;
-	}
-	return 0;
-}
-
-/* Hook from generic ACPI tables.c */
-static inline int acpi_madt_oem_check(char *oem_id, char *oem_table_id)
-{
-	if (!strncmp(oem_id, "IBM", 3) &&
-	    (!strncmp(oem_table_id, "SERVIGIL", 8)
-	     || !strncmp(oem_table_id, "EXA", 3))){
-		mark_tsc_unstable("Summit based system");
-		use_cyclone = 1; /*enable cyclone-timer*/
-		setup_summit();
-		return 1;
-	}
-	return 0;
-}
-
-struct rio_table_hdr {
-	unsigned char version;      /* Version number of this data structure           */
-	                            /* Version 3 adds chassis_num & WP_index           */
-	unsigned char num_scal_dev; /* # of Scalability devices (Twisters for Vigil)   */
-	unsigned char num_rio_dev;  /* # of RIO I/O devices (Cyclones and Winnipegs)   */
-} __attribute__((packed));
-
-struct scal_detail {
-	unsigned char node_id;      /* Scalability Node ID                             */
-	unsigned long CBAR;         /* Address of 1MB register space                   */
-	unsigned char port0node;    /* Node ID port connected to: 0xFF=None            */
-	unsigned char port0port;    /* Port num port connected to: 0,1,2, or 0xFF=None */
-	unsigned char port1node;    /* Node ID port connected to: 0xFF = None          */
-	unsigned char port1port;    /* Port num port connected to: 0,1,2, or 0xFF=None */
-	unsigned char port2node;    /* Node ID port connected to: 0xFF = None          */
-	unsigned char port2port;    /* Port num port connected to: 0,1,2, or 0xFF=None */
-	unsigned char chassis_num;  /* 1 based Chassis number (1 = boot node)          */
-} __attribute__((packed));
-
-struct rio_detail {
-	unsigned char node_id;      /* RIO Node ID                                     */
-	unsigned long BBAR;         /* Address of 1MB register space                   */
-	unsigned char type;         /* Type of device                                  */
-	unsigned char owner_id;     /* For WPEG: Node ID of Cyclone that owns this WPEG*/
-	                            /* For CYC:  Node ID of Twister that owns this CYC */
-	unsigned char port0node;    /* Node ID port connected to: 0xFF=None            */
-	unsigned char port0port;    /* Port num port connected to: 0,1,2, or 0xFF=None */
-	unsigned char port1node;    /* Node ID port connected to: 0xFF=None            */
-	unsigned char port1port;    /* Port num port connected to: 0,1,2, or 0xFF=None */
-	unsigned char first_slot;   /* For WPEG: Lowest slot number below this WPEG    */
-	                            /* For CYC:  0                                     */
-	unsigned char status;       /* For WPEG: Bit 0 = 1 : the XAPIC is used         */
-	                            /*                 = 0 : the XAPIC is not used, ie:*/
-	                            /*                     ints fwded to another XAPIC */
-	                            /*           Bits1:7 Reserved                      */
-	                            /* For CYC:  Bits0:7 Reserved                      */
-	unsigned char WP_index;     /* For WPEG: WPEG instance index - lower ones have */
-	                            /*           lower slot numbers/PCI bus numbers    */
-	                            /* For CYC:  No meaning                            */
-	unsigned char chassis_num;  /* 1 based Chassis number                          */
-	                            /* For LookOut WPEGs this field indicates the      */
-	                            /* Expansion Chassis #, enumerated from Boot       */
-	                            /* Node WPEG external port, then Boot Node CYC     */
-	                            /* external port, then Next Vigil chassis WPEG     */
-	                            /* external port, etc.                             */
-	                            /* Shared Lookouts have only 1 chassis number (the */
-	                            /* first one assigned)                             */
-} __attribute__((packed));
-
-
-typedef enum {
-	CompatTwister = 0,  /* Compatibility Twister               */
-	AltTwister    = 1,  /* Alternate Twister of internal 8-way */
-	CompatCyclone = 2,  /* Compatibility Cyclone               */
-	AltCyclone    = 3,  /* Alternate Cyclone of internal 8-way */
-	CompatWPEG    = 4,  /* Compatibility WPEG                  */
-	AltWPEG       = 5,  /* Second Planar WPEG                  */
-	LookOutAWPEG  = 6,  /* LookOut WPEG                        */
-	LookOutBWPEG  = 7,  /* LookOut WPEG                        */
-} node_type;
-
-static inline int is_WPEG(struct rio_detail *rio){
-	return (rio->type == CompatWPEG || rio->type == AltWPEG ||
-		rio->type == LookOutAWPEG || rio->type == LookOutBWPEG);
-}
-
-#endif /* __ASM_MACH_MPPARSE_H */
diff --git a/include/asm-x86/math_emu.h b/include/asm-x86/math_emu.h
index 9bf4ae9..5768d8e 100644
--- a/include/asm-x86/math_emu.h
+++ b/include/asm-x86/math_emu.h
@@ -1,5 +1,5 @@
-#ifndef _I386_MATH_EMU_H
-#define _I386_MATH_EMU_H
+#ifndef ASM_X86__MATH_EMU_H
+#define ASM_X86__MATH_EMU_H
 
 /* This structure matches the layout of the data saved to the stack
    following a device-not-present interrupt, part of it saved
@@ -28,4 +28,4 @@
 	long ___vm86_fs;
 	long ___vm86_gs;
 };
-#endif
+#endif /* ASM_X86__MATH_EMU_H */
diff --git a/include/asm-x86/mc146818rtc.h b/include/asm-x86/mc146818rtc.h
index daf1ccd..a995f33 100644
--- a/include/asm-x86/mc146818rtc.h
+++ b/include/asm-x86/mc146818rtc.h
@@ -1,8 +1,8 @@
 /*
  * Machine dependent access functions for RTC registers.
  */
-#ifndef _ASM_MC146818RTC_H
-#define _ASM_MC146818RTC_H
+#ifndef ASM_X86__MC146818RTC_H
+#define ASM_X86__MC146818RTC_H
 
 #include <asm/io.h>
 #include <asm/system.h>
@@ -101,4 +101,4 @@
 
 #define RTC_IRQ 8
 
-#endif /* _ASM_MC146818RTC_H */
+#endif /* ASM_X86__MC146818RTC_H */
diff --git a/include/asm-x86/mca.h b/include/asm-x86/mca.h
index 09adf2e..60d1ed2 100644
--- a/include/asm-x86/mca.h
+++ b/include/asm-x86/mca.h
@@ -1,8 +1,8 @@
 /* -*- mode: c; c-basic-offset: 8 -*- */
 
 /* Platform specific MCA defines */
-#ifndef _ASM_MCA_H
-#define _ASM_MCA_H
+#ifndef ASM_X86__MCA_H
+#define ASM_X86__MCA_H
 
 /* Maximal number of MCA slots - actually, some machines have less, but
  * they all have sufficient number of POS registers to cover 8.
@@ -40,4 +40,4 @@
  */
 #define MCA_NUMADAPTERS (MCA_MAX_SLOT_NR+3)
 
-#endif
+#endif /* ASM_X86__MCA_H */
diff --git a/include/asm-x86/mca_dma.h b/include/asm-x86/mca_dma.h
index c3dca6e..49f22be 100644
--- a/include/asm-x86/mca_dma.h
+++ b/include/asm-x86/mca_dma.h
@@ -1,5 +1,5 @@
-#ifndef MCA_DMA_H
-#define MCA_DMA_H
+#ifndef ASM_X86__MCA_DMA_H
+#define ASM_X86__MCA_DMA_H
 
 #include <asm/io.h>
 #include <linux/ioport.h>
@@ -198,4 +198,4 @@
 	outb(mode, MCA_DMA_REG_EXE);
 }
 
-#endif /* MCA_DMA_H */
+#endif /* ASM_X86__MCA_DMA_H */
diff --git a/include/asm-x86/mce.h b/include/asm-x86/mce.h
index 531eaa5..036133e 100644
--- a/include/asm-x86/mce.h
+++ b/include/asm-x86/mce.h
@@ -1,5 +1,5 @@
-#ifndef _ASM_X86_MCE_H
-#define _ASM_X86_MCE_H
+#ifndef ASM_X86__MCE_H
+#define ASM_X86__MCE_H
 
 #ifdef __x86_64__
 
@@ -127,4 +127,4 @@
 
 #endif /* __KERNEL__ */
 
-#endif
+#endif /* ASM_X86__MCE_H */
diff --git a/include/asm-x86/microcode.h b/include/asm-x86/microcode.h
new file mode 100644
index 0000000..62c793b
--- /dev/null
+++ b/include/asm-x86/microcode.h
@@ -0,0 +1,47 @@
+#ifndef ASM_X86__MICROCODE_H
+#define ASM_X86__MICROCODE_H
+
+struct cpu_signature {
+	unsigned int sig;
+	unsigned int pf;
+	unsigned int rev;
+};
+
+struct device;
+
+struct microcode_ops {
+	int  (*request_microcode_user) (int cpu, const void __user *buf, size_t size);
+	int  (*request_microcode_fw) (int cpu, struct device *device);
+
+	void (*apply_microcode) (int cpu);
+
+	int  (*collect_cpu_info) (int cpu, struct cpu_signature *csig);
+	void (*microcode_fini_cpu) (int cpu);
+};
+
+struct ucode_cpu_info {
+	struct cpu_signature cpu_sig;
+	int valid;
+	void *mc;
+};
+extern struct ucode_cpu_info ucode_cpu_info[];
+
+#ifdef CONFIG_MICROCODE_INTEL
+extern struct microcode_ops * __init init_intel_microcode(void);
+#else
+static inline struct microcode_ops * __init init_intel_microcode(void)
+{
+	return NULL;
+}
+#endif /* CONFIG_MICROCODE_INTEL */
+
+#ifdef CONFIG_MICROCODE_AMD
+extern struct microcode_ops * __init init_amd_microcode(void);
+#else
+static inline struct microcode_ops * __init init_amd_microcode(void)
+{
+	return NULL;
+}
+#endif
+
+#endif /* ASM_X86__MICROCODE_H */
diff --git a/include/asm-x86/mman.h b/include/asm-x86/mman.h
index 90bc410..4ef28e6 100644
--- a/include/asm-x86/mman.h
+++ b/include/asm-x86/mman.h
@@ -1,5 +1,5 @@
-#ifndef _ASM_X86_MMAN_H
-#define _ASM_X86_MMAN_H
+#ifndef ASM_X86__MMAN_H
+#define ASM_X86__MMAN_H
 
 #include <asm-generic/mman.h>
 
@@ -17,4 +17,4 @@
 #define MCL_CURRENT	1		/* lock all current mappings */
 #define MCL_FUTURE	2		/* lock all future mappings */
 
-#endif /* _ASM_X86_MMAN_H */
+#endif /* ASM_X86__MMAN_H */
diff --git a/include/asm-x86/mmconfig.h b/include/asm-x86/mmconfig.h
index e293ab8..fb79b1c 100644
--- a/include/asm-x86/mmconfig.h
+++ b/include/asm-x86/mmconfig.h
@@ -1,5 +1,5 @@
-#ifndef _ASM_MMCONFIG_H
-#define _ASM_MMCONFIG_H
+#ifndef ASM_X86__MMCONFIG_H
+#define ASM_X86__MMCONFIG_H
 
 #ifdef CONFIG_PCI_MMCONFIG
 extern void __cpuinit fam10h_check_enable_mmcfg(void);
@@ -9,4 +9,4 @@
 static inline void check_enable_amd_mmconf_dmi(void) { }
 #endif
 
-#endif
+#endif /* ASM_X86__MMCONFIG_H */
diff --git a/include/asm-x86/mmu.h b/include/asm-x86/mmu.h
index 00e8867..9d5aff1 100644
--- a/include/asm-x86/mmu.h
+++ b/include/asm-x86/mmu.h
@@ -1,5 +1,5 @@
-#ifndef _ASM_X86_MMU_H
-#define _ASM_X86_MMU_H
+#ifndef ASM_X86__MMU_H
+#define ASM_X86__MMU_H
 
 #include <linux/spinlock.h>
 #include <linux/mutex.h>
@@ -7,14 +7,9 @@
 /*
  * The x86 doesn't have a mmu context, but
  * we put the segment information here.
- *
- * cpu_vm_mask is used to optimize ldt flushing.
  */
 typedef struct {
 	void *ldt;
-#ifdef CONFIG_X86_64
-	rwlock_t ldtlock;
-#endif
 	int size;
 	struct mutex lock;
 	void *vdso;
@@ -28,4 +23,4 @@
 }
 #endif
 
-#endif /* _ASM_X86_MMU_H */
+#endif /* ASM_X86__MMU_H */
diff --git a/include/asm-x86/mmu_context.h b/include/asm-x86/mmu_context.h
index fac5701..8ec940b 100644
--- a/include/asm-x86/mmu_context.h
+++ b/include/asm-x86/mmu_context.h
@@ -1,5 +1,5 @@
-#ifndef __ASM_X86_MMU_CONTEXT_H
-#define __ASM_X86_MMU_CONTEXT_H
+#ifndef ASM_X86__MMU_CONTEXT_H
+#define ASM_X86__MMU_CONTEXT_H
 
 #include <asm/desc.h>
 #include <asm/atomic.h>
@@ -34,4 +34,4 @@
 } while (0);
 
 
-#endif /* __ASM_X86_MMU_CONTEXT_H */
+#endif /* ASM_X86__MMU_CONTEXT_H */
diff --git a/include/asm-x86/mmu_context_32.h b/include/asm-x86/mmu_context_32.h
index 824fc57..cce6f6e 100644
--- a/include/asm-x86/mmu_context_32.h
+++ b/include/asm-x86/mmu_context_32.h
@@ -1,5 +1,5 @@
-#ifndef __I386_SCHED_H
-#define __I386_SCHED_H
+#ifndef ASM_X86__MMU_CONTEXT_32_H
+#define ASM_X86__MMU_CONTEXT_32_H
 
 static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk)
 {
@@ -53,4 +53,4 @@
 #define deactivate_mm(tsk, mm)			\
 	asm("movl %0,%%gs": :"r" (0));
 
-#endif
+#endif /* ASM_X86__MMU_CONTEXT_32_H */
diff --git a/include/asm-x86/mmu_context_64.h b/include/asm-x86/mmu_context_64.h
index c700063..2675867 100644
--- a/include/asm-x86/mmu_context_64.h
+++ b/include/asm-x86/mmu_context_64.h
@@ -1,5 +1,5 @@
-#ifndef __X86_64_MMU_CONTEXT_H
-#define __X86_64_MMU_CONTEXT_H
+#ifndef ASM_X86__MMU_CONTEXT_64_H
+#define ASM_X86__MMU_CONTEXT_64_H
 
 #include <asm/pda.h>
 
@@ -51,4 +51,4 @@
 	asm volatile("movl %0,%%fs"::"r"(0));	\
 } while (0)
 
-#endif
+#endif /* ASM_X86__MMU_CONTEXT_64_H */
diff --git a/include/asm-x86/mmx.h b/include/asm-x86/mmx.h
index 9408812..2e7299b 100644
--- a/include/asm-x86/mmx.h
+++ b/include/asm-x86/mmx.h
@@ -1,5 +1,5 @@
-#ifndef _ASM_MMX_H
-#define _ASM_MMX_H
+#ifndef ASM_X86__MMX_H
+#define ASM_X86__MMX_H
 
 /*
  *	MMX 3Dnow! helper operations
@@ -11,4 +11,4 @@
 extern void mmx_clear_page(void *page);
 extern void mmx_copy_page(void *to, void *from);
 
-#endif
+#endif /* ASM_X86__MMX_H */
diff --git a/include/asm-x86/mmzone_32.h b/include/asm-x86/mmzone_32.h
index 5862e64..121b65d 100644
--- a/include/asm-x86/mmzone_32.h
+++ b/include/asm-x86/mmzone_32.h
@@ -3,8 +3,8 @@
  *
  */
 
-#ifndef _ASM_MMZONE_H_
-#define _ASM_MMZONE_H_
+#ifndef ASM_X86__MMZONE_32_H
+#define ASM_X86__MMZONE_32_H
 
 #include <asm/smp.h>
 
@@ -131,4 +131,4 @@
 })
 #endif /* CONFIG_NEED_MULTIPLE_NODES */
 
-#endif /* _ASM_MMZONE_H_ */
+#endif /* ASM_X86__MMZONE_32_H */
diff --git a/include/asm-x86/mmzone_64.h b/include/asm-x86/mmzone_64.h
index 594bd0d..6480f33 100644
--- a/include/asm-x86/mmzone_64.h
+++ b/include/asm-x86/mmzone_64.h
@@ -1,13 +1,13 @@
 /* K8 NUMA support */
 /* Copyright 2002,2003 by Andi Kleen, SuSE Labs */
 /* 2.5 Version loosely based on the NUMAQ Code by Pat Gaughen. */
-#ifndef _ASM_X86_64_MMZONE_H
-#define _ASM_X86_64_MMZONE_H 1
+#ifndef ASM_X86__MMZONE_64_H
+#define ASM_X86__MMZONE_64_H
 
 
 #ifdef CONFIG_NUMA
 
-#define VIRTUAL_BUG_ON(x)
+#include <linux/mmdebug.h>
 
 #include <asm/smp.h>
 
@@ -29,7 +29,6 @@
 {
 	unsigned nid;
 	VIRTUAL_BUG_ON(!memnodemap);
-	VIRTUAL_BUG_ON((addr >> memnode_shift) >= memnodemapsize);
 	nid = memnodemap[addr >> memnode_shift];
 	VIRTUAL_BUG_ON(nid >= MAX_NUMNODES || !node_data[nid]);
 	return nid;
@@ -49,4 +48,4 @@
 #endif
 
 #endif
-#endif
+#endif /* ASM_X86__MMZONE_64_H */
diff --git a/include/asm-x86/module.h b/include/asm-x86/module.h
index bfedb24..864f200 100644
--- a/include/asm-x86/module.h
+++ b/include/asm-x86/module.h
@@ -1,5 +1,5 @@
-#ifndef _ASM_MODULE_H
-#define _ASM_MODULE_H
+#ifndef ASM_X86__MODULE_H
+#define ASM_X86__MODULE_H
 
 /* x86_32/64 are simple */
 struct mod_arch_specific {};
@@ -52,8 +52,6 @@
 #define MODULE_PROC_FAMILY "EFFICEON "
 #elif defined CONFIG_MWINCHIPC6
 #define MODULE_PROC_FAMILY "WINCHIPC6 "
-#elif defined CONFIG_MWINCHIP2
-#define MODULE_PROC_FAMILY "WINCHIP2 "
 #elif defined CONFIG_MWINCHIP3D
 #define MODULE_PROC_FAMILY "WINCHIP3D "
 #elif defined CONFIG_MCYRIXIII
@@ -79,4 +77,4 @@
 # define MODULE_ARCH_VERMAGIC MODULE_PROC_FAMILY MODULE_STACKSIZE
 #endif
 
-#endif /* _ASM_MODULE_H */
+#endif /* ASM_X86__MODULE_H */
diff --git a/include/asm-x86/mpspec.h b/include/asm-x86/mpspec.h
index b6995e5..be2241a 100644
--- a/include/asm-x86/mpspec.h
+++ b/include/asm-x86/mpspec.h
@@ -1,15 +1,16 @@
-#ifndef _AM_X86_MPSPEC_H
-#define _AM_X86_MPSPEC_H
+#ifndef ASM_X86__MPSPEC_H
+#define ASM_X86__MPSPEC_H
 
 #include <linux/init.h>
 
 #include <asm/mpspec_def.h>
 
+extern int apic_version[MAX_APICS];
+
 #ifdef CONFIG_X86_32
 #include <mach_mpspec.h>
 
 extern unsigned int def_to_bigsmp;
-extern int apic_version[MAX_APICS];
 extern u8 apicid_2_node[];
 extern int pic_mode;
 
@@ -141,4 +142,4 @@
 
 extern physid_mask_t phys_cpu_present_map;
 
-#endif
+#endif /* ASM_X86__MPSPEC_H */
diff --git a/include/asm-x86/mpspec_def.h b/include/asm-x86/mpspec_def.h
index 38d1e73..79166b0 100644
--- a/include/asm-x86/mpspec_def.h
+++ b/include/asm-x86/mpspec_def.h
@@ -1,5 +1,5 @@
-#ifndef __ASM_MPSPEC_DEF_H
-#define __ASM_MPSPEC_DEF_H
+#ifndef ASM_X86__MPSPEC_DEF_H
+#define ASM_X86__MPSPEC_DEF_H
 
 /*
  * Structure definitions for SMP machines following the
@@ -177,4 +177,4 @@
 	MP_BUS_PCI,
 	MP_BUS_MCA,
 };
-#endif
+#endif /* ASM_X86__MPSPEC_DEF_H */
diff --git a/include/asm-x86/msgbuf.h b/include/asm-x86/msgbuf.h
index 7e4e948..1b538c9 100644
--- a/include/asm-x86/msgbuf.h
+++ b/include/asm-x86/msgbuf.h
@@ -1,5 +1,5 @@
-#ifndef _ASM_X86_MSGBUF_H
-#define _ASM_X86_MSGBUF_H
+#ifndef ASM_X86__MSGBUF_H
+#define ASM_X86__MSGBUF_H
 
 /*
  * The msqid64_ds structure for i386 architecture.
@@ -36,4 +36,4 @@
 	unsigned long  __unused5;
 };
 
-#endif /* _ASM_X86_MSGBUF_H */
+#endif /* ASM_X86__MSGBUF_H */
diff --git a/include/asm-x86/msidef.h b/include/asm-x86/msidef.h
index 296f29c..ed91902 100644
--- a/include/asm-x86/msidef.h
+++ b/include/asm-x86/msidef.h
@@ -1,5 +1,5 @@
-#ifndef ASM_MSIDEF_H
-#define ASM_MSIDEF_H
+#ifndef ASM_X86__MSIDEF_H
+#define ASM_X86__MSIDEF_H
 
 /*
  * Constants for Intel APIC based MSI messages.
@@ -48,4 +48,8 @@
 #define  MSI_ADDR_DEST_ID(dest)		(((dest) << MSI_ADDR_DEST_ID_SHIFT) & \
 					 MSI_ADDR_DEST_ID_MASK)
 
-#endif /* ASM_MSIDEF_H */
+#define MSI_ADDR_IR_EXT_INT		(1 << 4)
+#define MSI_ADDR_IR_SHV			(1 << 3)
+#define MSI_ADDR_IR_INDEX1(index)	((index & 0x8000) >> 13)
+#define MSI_ADDR_IR_INDEX2(index)	((index & 0x7fff) << 5)
+#endif /* ASM_X86__MSIDEF_H */
diff --git a/include/asm-x86/msr-index.h b/include/asm-x86/msr-index.h
index 44bce77..0bb4330 100644
--- a/include/asm-x86/msr-index.h
+++ b/include/asm-x86/msr-index.h
@@ -1,5 +1,5 @@
-#ifndef __ASM_MSR_INDEX_H
-#define __ASM_MSR_INDEX_H
+#ifndef ASM_X86__MSR_INDEX_H
+#define ASM_X86__MSR_INDEX_H
 
 /* CPU model specific register (MSR) numbers */
 
@@ -176,6 +176,7 @@
 #define MSR_IA32_TSC			0x00000010
 #define MSR_IA32_PLATFORM_ID		0x00000017
 #define MSR_IA32_EBL_CR_POWERON		0x0000002a
+#define MSR_IA32_FEATURE_CONTROL        0x0000003a
 
 #define MSR_IA32_APICBASE		0x0000001b
 #define MSR_IA32_APICBASE_BSP		(1<<8)
@@ -310,4 +311,19 @@
 /* Geode defined MSRs */
 #define MSR_GEODE_BUSCONT_CONF0		0x00001900
 
-#endif /* __ASM_MSR_INDEX_H */
+/* Intel VT MSRs */
+#define MSR_IA32_VMX_BASIC              0x00000480
+#define MSR_IA32_VMX_PINBASED_CTLS      0x00000481
+#define MSR_IA32_VMX_PROCBASED_CTLS     0x00000482
+#define MSR_IA32_VMX_EXIT_CTLS          0x00000483
+#define MSR_IA32_VMX_ENTRY_CTLS         0x00000484
+#define MSR_IA32_VMX_MISC               0x00000485
+#define MSR_IA32_VMX_CR0_FIXED0         0x00000486
+#define MSR_IA32_VMX_CR0_FIXED1         0x00000487
+#define MSR_IA32_VMX_CR4_FIXED0         0x00000488
+#define MSR_IA32_VMX_CR4_FIXED1         0x00000489
+#define MSR_IA32_VMX_VMCS_ENUM          0x0000048a
+#define MSR_IA32_VMX_PROCBASED_CTLS2    0x0000048b
+#define MSR_IA32_VMX_EPT_VPID_CAP       0x0000048c
+
+#endif /* ASM_X86__MSR_INDEX_H */
diff --git a/include/asm-x86/msr.h b/include/asm-x86/msr.h
index 2362cfd..530af1f 100644
--- a/include/asm-x86/msr.h
+++ b/include/asm-x86/msr.h
@@ -1,5 +1,5 @@
-#ifndef __ASM_X86_MSR_H_
-#define __ASM_X86_MSR_H_
+#ifndef ASM_X86__MSR_H
+#define ASM_X86__MSR_H
 
 #include <asm/msr-index.h>
 
@@ -63,6 +63,22 @@
 	return EAX_EDX_VAL(val, low, high);
 }
 
+static inline unsigned long long native_read_msr_amd_safe(unsigned int msr,
+						      int *err)
+{
+	DECLARE_ARGS(val, low, high);
+
+	asm volatile("2: rdmsr ; xor %0,%0\n"
+		     "1:\n\t"
+		     ".section .fixup,\"ax\"\n\t"
+		     "3:  mov %3,%0 ; jmp 1b\n\t"
+		     ".previous\n\t"
+		     _ASM_EXTABLE(2b, 3b)
+		     : "=r" (*err), EAX_EDX_RET(val, low, high)
+		     : "c" (msr), "D" (0x9c5a203a), "i" (-EFAULT));
+	return EAX_EDX_VAL(val, low, high);
+}
+
 static inline void native_write_msr(unsigned int msr,
 				    unsigned low, unsigned high)
 {
@@ -158,6 +174,13 @@
 	*p = native_read_msr_safe(msr, &err);
 	return err;
 }
+static inline int rdmsrl_amd_safe(unsigned msr, unsigned long long *p)
+{
+	int err;
+
+	*p = native_read_msr_amd_safe(msr, &err);
+	return err;
+}
 
 #define rdtscl(low)						\
 	((low) = (u32)native_read_tsc())
@@ -221,4 +244,4 @@
 #endif /* __KERNEL__ */
 
 
-#endif
+#endif /* ASM_X86__MSR_H */
diff --git a/include/asm-x86/mtrr.h b/include/asm-x86/mtrr.h
index a69a01a..23a7f83 100644
--- a/include/asm-x86/mtrr.h
+++ b/include/asm-x86/mtrr.h
@@ -20,8 +20,8 @@
     The postal address is:
       Richard Gooch, c/o ATNF, P. O. Box 76, Epping, N.S.W., 2121, Australia.
 */
-#ifndef _ASM_X86_MTRR_H
-#define _ASM_X86_MTRR_H
+#ifndef ASM_X86__MTRR_H
+#define ASM_X86__MTRR_H
 
 #include <linux/ioctl.h>
 #include <linux/errno.h>
@@ -170,4 +170,4 @@
 
 #endif /* __KERNEL__ */
 
-#endif  /*  _ASM_X86_MTRR_H  */
+#endif /* ASM_X86__MTRR_H */
diff --git a/include/asm-x86/mutex_32.h b/include/asm-x86/mutex_32.h
index 73e928e..25c16d8 100644
--- a/include/asm-x86/mutex_32.h
+++ b/include/asm-x86/mutex_32.h
@@ -6,8 +6,8 @@
  *
  *  Copyright (C) 2004, 2005, 2006 Red Hat, Inc., Ingo Molnar <mingo@redhat.com>
  */
-#ifndef _ASM_MUTEX_H
-#define _ASM_MUTEX_H
+#ifndef ASM_X86__MUTEX_32_H
+#define ASM_X86__MUTEX_32_H
 
 #include <asm/alternative.h>
 
@@ -122,4 +122,4 @@
 #endif
 }
 
-#endif
+#endif /* ASM_X86__MUTEX_32_H */
diff --git a/include/asm-x86/mutex_64.h b/include/asm-x86/mutex_64.h
index f3fae9b..918ba21 100644
--- a/include/asm-x86/mutex_64.h
+++ b/include/asm-x86/mutex_64.h
@@ -6,8 +6,8 @@
  *
  *  Copyright (C) 2004, 2005, 2006 Red Hat, Inc., Ingo Molnar <mingo@redhat.com>
  */
-#ifndef _ASM_MUTEX_H
-#define _ASM_MUTEX_H
+#ifndef ASM_X86__MUTEX_64_H
+#define ASM_X86__MUTEX_64_H
 
 /**
  * __mutex_fastpath_lock - decrement and call function if negative
@@ -97,4 +97,4 @@
 		return 0;
 }
 
-#endif
+#endif /* ASM_X86__MUTEX_64_H */
diff --git a/include/asm-x86/nmi.h b/include/asm-x86/nmi.h
index 21f8d02..a53f829 100644
--- a/include/asm-x86/nmi.h
+++ b/include/asm-x86/nmi.h
@@ -1,5 +1,5 @@
-#ifndef _ASM_X86_NMI_H_
-#define _ASM_X86_NMI_H_
+#ifndef ASM_X86__NMI_H
+#define ASM_X86__NMI_H
 
 #include <linux/pm.h>
 #include <asm/irq.h>
@@ -15,10 +15,6 @@
  */
 int do_nmi_callback(struct pt_regs *regs, int cpu);
 
-#ifdef CONFIG_X86_64
-extern void default_do_nmi(struct pt_regs *);
-#endif
-
 extern void die_nmi(char *str, struct pt_regs *regs, int do_panic);
 extern int check_nmi_watchdog(void);
 extern int nmi_watchdog_enabled;
@@ -34,6 +30,7 @@
 extern void disable_timer_nmi_watchdog(void);
 extern void enable_timer_nmi_watchdog(void);
 extern int nmi_watchdog_tick(struct pt_regs *regs, unsigned reason);
+extern void cpu_nmi_set_wd_enabled(void);
 
 extern atomic_t nmi_active;
 extern unsigned int nmi_watchdog;
@@ -81,4 +78,4 @@
 void stop_nmi(void);
 void restart_nmi(void);
 
-#endif
+#endif /* ASM_X86__NMI_H */
diff --git a/include/asm-x86/nops.h b/include/asm-x86/nops.h
index ad0bedd..ae74272 100644
--- a/include/asm-x86/nops.h
+++ b/include/asm-x86/nops.h
@@ -1,5 +1,5 @@
-#ifndef _ASM_NOPS_H
-#define _ASM_NOPS_H 1
+#ifndef ASM_X86__NOPS_H
+#define ASM_X86__NOPS_H
 
 /* Define nops for use with alternative() */
 
@@ -115,4 +115,4 @@
 
 #define ASM_NOP_MAX 8
 
-#endif
+#endif /* ASM_X86__NOPS_H */
diff --git a/include/asm-x86/numa_32.h b/include/asm-x86/numa_32.h
index 220d7b7..44cb078 100644
--- a/include/asm-x86/numa_32.h
+++ b/include/asm-x86/numa_32.h
@@ -1,5 +1,5 @@
-#ifndef _ASM_X86_32_NUMA_H
-#define _ASM_X86_32_NUMA_H 1
+#ifndef ASM_X86__NUMA_32_H
+#define ASM_X86__NUMA_32_H
 
 extern int pxm_to_nid(int pxm);
 extern void numa_remove_cpu(int cpu);
@@ -8,4 +8,4 @@
 extern void set_highmem_pages_init(void);
 #endif
 
-#endif /* _ASM_X86_32_NUMA_H */
+#endif /* ASM_X86__NUMA_32_H */
diff --git a/include/asm-x86/numa_64.h b/include/asm-x86/numa_64.h
index 3830094..15c9903 100644
--- a/include/asm-x86/numa_64.h
+++ b/include/asm-x86/numa_64.h
@@ -1,5 +1,5 @@
-#ifndef _ASM_X8664_NUMA_H
-#define _ASM_X8664_NUMA_H 1
+#ifndef ASM_X86__NUMA_64_H
+#define ASM_X86__NUMA_64_H
 
 #include <linux/nodemask.h>
 #include <asm/apicdef.h>
@@ -40,4 +40,4 @@
 static inline void numa_remove_cpu(int cpu)		{ }
 #endif
 
-#endif
+#endif /* ASM_X86__NUMA_64_H */
diff --git a/include/asm-x86/numaq.h b/include/asm-x86/numaq.h
index 34b92d5..124bf7d 100644
--- a/include/asm-x86/numaq.h
+++ b/include/asm-x86/numaq.h
@@ -23,8 +23,8 @@
  * Send feedback to <gone@us.ibm.com>
  */
 
-#ifndef NUMAQ_H
-#define NUMAQ_H
+#ifndef ASM_X86__NUMAQ_H
+#define ASM_X86__NUMAQ_H
 
 #ifdef CONFIG_X86_NUMAQ
 
@@ -165,5 +165,5 @@
 	return 0;
 }
 #endif /* CONFIG_X86_NUMAQ */
-#endif /* NUMAQ_H */
+#endif /* ASM_X86__NUMAQ_H */
 
diff --git a/include/asm-x86/numaq/apic.h b/include/asm-x86/numaq/apic.h
new file mode 100644
index 0000000..a8344ba
--- /dev/null
+++ b/include/asm-x86/numaq/apic.h
@@ -0,0 +1,138 @@
+#ifndef __ASM_NUMAQ_APIC_H
+#define __ASM_NUMAQ_APIC_H
+
+#include <asm/io.h>
+#include <linux/mmzone.h>
+#include <linux/nodemask.h>
+
+#define APIC_DFR_VALUE	(APIC_DFR_CLUSTER)
+
+static inline cpumask_t target_cpus(void)
+{
+	return CPU_MASK_ALL;
+}
+
+#define TARGET_CPUS (target_cpus())
+
+#define NO_BALANCE_IRQ (1)
+#define esr_disable (1)
+
+#define INT_DELIVERY_MODE dest_LowestPrio
+#define INT_DEST_MODE 0     /* physical delivery on LOCAL quad */
+ 
+static inline unsigned long check_apicid_used(physid_mask_t bitmap, int apicid)
+{
+	return physid_isset(apicid, bitmap);
+}
+static inline unsigned long check_apicid_present(int bit)
+{
+	return physid_isset(bit, phys_cpu_present_map);
+}
+#define apicid_cluster(apicid) (apicid & 0xF0)
+
+static inline int apic_id_registered(void)
+{
+	return 1;
+}
+
+static inline void init_apic_ldr(void)
+{
+	/* Already done in NUMA-Q firmware */
+}
+
+static inline void setup_apic_routing(void)
+{
+	printk("Enabling APIC mode:  %s.  Using %d I/O APICs\n",
+		"NUMA-Q", nr_ioapics);
+}
+
+/*
+ * Skip adding the timer int on secondary nodes, which causes
+ * a small but painful rift in the time-space continuum.
+ */
+static inline int multi_timer_check(int apic, int irq)
+{
+	return apic != 0 && irq == 0;
+}
+
+static inline physid_mask_t ioapic_phys_id_map(physid_mask_t phys_map)
+{
+	/* We don't have a good way to do this yet - hack */
+	return physids_promote(0xFUL);
+}
+
+/* Mapping from cpu number to logical apicid */
+extern u8 cpu_2_logical_apicid[];
+static inline int cpu_to_logical_apicid(int cpu)
+{
+       if (cpu >= NR_CPUS)
+	       return BAD_APICID;
+	return (int)cpu_2_logical_apicid[cpu];
+}
+
+/*
+ * Supporting over 60 cpus on NUMA-Q requires a locality-dependent
+ * cpu to APIC ID relation to properly interact with the intelligent
+ * mode of the cluster controller.
+ */
+static inline int cpu_present_to_apicid(int mps_cpu)
+{
+	if (mps_cpu < 60)
+		return ((mps_cpu >> 2) << 4) | (1 << (mps_cpu & 0x3));
+	else
+		return BAD_APICID;
+}
+
+static inline int apicid_to_node(int logical_apicid) 
+{
+	return logical_apicid >> 4;
+}
+
+static inline physid_mask_t apicid_to_cpu_present(int logical_apicid)
+{
+	int node = apicid_to_node(logical_apicid);
+	int cpu = __ffs(logical_apicid & 0xf);
+
+	return physid_mask_of_physid(cpu + 4*node);
+}
+
+extern void *xquad_portio;
+
+static inline void setup_portio_remap(void)
+{
+	int num_quads = num_online_nodes();
+
+	if (num_quads <= 1)
+       		return;
+
+	printk("Remapping cross-quad port I/O for %d quads\n", num_quads);
+	xquad_portio = ioremap(XQUAD_PORTIO_BASE, num_quads*XQUAD_PORTIO_QUAD);
+	printk("xquad_portio vaddr 0x%08lx, len %08lx\n",
+		(u_long) xquad_portio, (u_long) num_quads*XQUAD_PORTIO_QUAD);
+}
+
+static inline int check_phys_apicid_present(int boot_cpu_physical_apicid)
+{
+	return (1);
+}
+
+static inline void enable_apic_mode(void)
+{
+}
+
+/*
+ * We use physical apicids here, not logical, so just return the default
+ * physical broadcast to stop people from breaking us
+ */
+static inline unsigned int cpu_mask_to_apicid(cpumask_t cpumask)
+{
+	return (int) 0xF;
+}
+
+/* No NUMA-Q box has a HT CPU, but it can't hurt to use the default code. */
+static inline u32 phys_pkg_id(u32 cpuid_apic, int index_msb)
+{
+	return cpuid_apic >> index_msb;
+}
+
+#endif /* __ASM_NUMAQ_APIC_H */
diff --git a/include/asm-x86/numaq/apicdef.h b/include/asm-x86/numaq/apicdef.h
new file mode 100644
index 0000000..e012a46
--- /dev/null
+++ b/include/asm-x86/numaq/apicdef.h
@@ -0,0 +1,14 @@
+#ifndef __ASM_NUMAQ_APICDEF_H
+#define __ASM_NUMAQ_APICDEF_H
+
+
+#define APIC_ID_MASK (0xF<<24)
+
+static inline unsigned get_apic_id(unsigned long x)
+{
+	        return (((x)>>24)&0x0F);
+}
+
+#define         GET_APIC_ID(x)  get_apic_id(x)
+
+#endif
diff --git a/include/asm-x86/numaq/ipi.h b/include/asm-x86/numaq/ipi.h
new file mode 100644
index 0000000..935588d2
--- /dev/null
+++ b/include/asm-x86/numaq/ipi.h
@@ -0,0 +1,25 @@
+#ifndef __ASM_NUMAQ_IPI_H
+#define __ASM_NUMAQ_IPI_H
+
+void send_IPI_mask_sequence(cpumask_t, int vector);
+
+static inline void send_IPI_mask(cpumask_t mask, int vector)
+{
+	send_IPI_mask_sequence(mask, vector);
+}
+
+static inline void send_IPI_allbutself(int vector)
+{
+	cpumask_t mask = cpu_online_map;
+	cpu_clear(smp_processor_id(), mask);
+
+	if (!cpus_empty(mask))
+		send_IPI_mask(mask, vector);
+}
+
+static inline void send_IPI_all(int vector)
+{
+	send_IPI_mask(cpu_online_map, vector);
+}
+
+#endif /* __ASM_NUMAQ_IPI_H */
diff --git a/include/asm-x86/numaq/mpparse.h b/include/asm-x86/numaq/mpparse.h
new file mode 100644
index 0000000..252292e
--- /dev/null
+++ b/include/asm-x86/numaq/mpparse.h
@@ -0,0 +1,7 @@
+#ifndef __ASM_NUMAQ_MPPARSE_H
+#define __ASM_NUMAQ_MPPARSE_H
+
+extern void numaq_mps_oem_check(struct mp_config_table *mpc, char *oem,
+				char *productid);
+
+#endif /* __ASM_NUMAQ_MPPARSE_H */
diff --git a/include/asm-x86/numaq/wakecpu.h b/include/asm-x86/numaq/wakecpu.h
new file mode 100644
index 0000000..c577bda
--- /dev/null
+++ b/include/asm-x86/numaq/wakecpu.h
@@ -0,0 +1,43 @@
+#ifndef __ASM_NUMAQ_WAKECPU_H
+#define __ASM_NUMAQ_WAKECPU_H
+
+/* This file copes with machines that wakeup secondary CPUs by NMIs */
+
+#define WAKE_SECONDARY_VIA_NMI
+
+#define TRAMPOLINE_LOW phys_to_virt(0x8)
+#define TRAMPOLINE_HIGH phys_to_virt(0xa)
+
+#define boot_cpu_apicid boot_cpu_logical_apicid
+
+/* We don't do anything here because we use NMI's to boot instead */
+static inline void wait_for_init_deassert(atomic_t *deassert)
+{
+}
+
+/*
+ * Because we use NMIs rather than the INIT-STARTUP sequence to
+ * bootstrap the CPUs, the APIC may be in a weird state. Kick it.
+ */
+static inline void smp_callin_clear_local_apic(void)
+{
+	clear_local_APIC();
+}
+
+static inline void store_NMI_vector(unsigned short *high, unsigned short *low)
+{
+	printk("Storing NMI vector\n");
+	*high = *((volatile unsigned short *) TRAMPOLINE_HIGH);
+	*low = *((volatile unsigned short *) TRAMPOLINE_LOW);
+}
+
+static inline void restore_NMI_vector(unsigned short *high, unsigned short *low)
+{
+	printk("Restoring NMI vector\n");
+	*((volatile unsigned short *) TRAMPOLINE_HIGH) = *high;
+	*((volatile unsigned short *) TRAMPOLINE_LOW) = *low;
+}
+
+#define inquire_remote_apic(apicid) {}
+
+#endif /* __ASM_NUMAQ_WAKECPU_H */
diff --git a/include/asm-x86/olpc.h b/include/asm-x86/olpc.h
index 97d4713..d7328b1 100644
--- a/include/asm-x86/olpc.h
+++ b/include/asm-x86/olpc.h
@@ -1,7 +1,7 @@
 /* OLPC machine specific definitions */
 
-#ifndef ASM_OLPC_H_
-#define ASM_OLPC_H_
+#ifndef ASM_X86__OLPC_H
+#define ASM_X86__OLPC_H
 
 #include <asm/geode.h>
 
@@ -129,4 +129,4 @@
 #define OLPC_GPIO_LID		geode_gpio(26)
 #define OLPC_GPIO_ECSCI		geode_gpio(27)
 
-#endif
+#endif /* ASM_X86__OLPC_H */
diff --git a/include/asm-x86/page.h b/include/asm-x86/page.h
index 4998211..d4f1d57 100644
--- a/include/asm-x86/page.h
+++ b/include/asm-x86/page.h
@@ -1,5 +1,5 @@
-#ifndef _ASM_X86_PAGE_H
-#define _ASM_X86_PAGE_H
+#ifndef ASM_X86__PAGE_H
+#define ASM_X86__PAGE_H
 
 #include <linux/const.h>
 
@@ -57,6 +57,7 @@
 typedef struct { pgprotval_t pgprot; } pgprot_t;
 
 extern int page_is_ram(unsigned long pagenr);
+extern int pagerange_is_ram(unsigned long start, unsigned long end);
 extern int devmem_is_allowed(unsigned long pagenr);
 extern void map_devmem(unsigned long pfn, unsigned long size,
 		       pgprot_t vma_prot);
@@ -178,6 +179,7 @@
 #endif	/* CONFIG_PARAVIRT */
 
 #define __pa(x)		__phys_addr((unsigned long)(x))
+#define __pa_nodebug(x)	__phys_addr_nodebug((unsigned long)(x))
 /* __pa_symbol should be used for C visible symbols.
    This seems to be the official gcc blessed way to do such arithmetic. */
 #define __pa_symbol(x)	__pa(__phys_reloc_hide((unsigned long)(x)))
@@ -187,9 +189,14 @@
 #define __boot_va(x)		__va(x)
 #define __boot_pa(x)		__pa(x)
 
+/*
+ * virt_to_page(kaddr) returns a valid pointer if and only if
+ * virt_addr_valid(kaddr) returns true.
+ */
 #define virt_to_page(kaddr)	pfn_to_page(__pa(kaddr) >> PAGE_SHIFT)
 #define pfn_to_kaddr(pfn)      __va((pfn) << PAGE_SHIFT)
-#define virt_addr_valid(kaddr)	pfn_valid(__pa(kaddr) >> PAGE_SHIFT)
+extern bool __virt_addr_valid(unsigned long kaddr);
+#define virt_addr_valid(kaddr)	__virt_addr_valid((unsigned long) (kaddr))
 
 #endif	/* __ASSEMBLY__ */
 
@@ -199,4 +206,4 @@
 #define __HAVE_ARCH_GATE_AREA 1
 
 #endif	/* __KERNEL__ */
-#endif	/* _ASM_X86_PAGE_H */
+#endif /* ASM_X86__PAGE_H */
diff --git a/include/asm-x86/page_32.h b/include/asm-x86/page_32.h
index ab85287..bdf5dba 100644
--- a/include/asm-x86/page_32.h
+++ b/include/asm-x86/page_32.h
@@ -1,5 +1,5 @@
-#ifndef _ASM_X86_PAGE_32_H
-#define _ASM_X86_PAGE_32_H
+#ifndef ASM_X86__PAGE_32_H
+#define ASM_X86__PAGE_32_H
 
 /*
  * This handles the memory map.
@@ -20,6 +20,12 @@
 #endif
 #define THREAD_SIZE 	(PAGE_SIZE << THREAD_ORDER)
 
+#define STACKFAULT_STACK 0
+#define DOUBLEFAULT_STACK 1
+#define NMI_STACK 0
+#define DEBUG_STACK 0
+#define MCE_STACK 0
+#define N_EXCEPTION_STACKS 1
 
 #ifdef CONFIG_X86_PAE
 /* 44=32+12, the limit we can fit into an unsigned long pfn */
@@ -33,7 +39,6 @@
 typedef u64	pudval_t;
 typedef u64	pgdval_t;
 typedef u64	pgprotval_t;
-typedef u64	phys_addr_t;
 
 typedef union {
 	struct {
@@ -54,7 +59,6 @@
 typedef unsigned long	pudval_t;
 typedef unsigned long	pgdval_t;
 typedef unsigned long	pgprotval_t;
-typedef unsigned long	phys_addr_t;
 
 typedef union {
 	pteval_t pte;
@@ -73,7 +77,12 @@
 #endif
 
 #ifndef __ASSEMBLY__
-#define __phys_addr(x)		((x) - PAGE_OFFSET)
+#define __phys_addr_nodebug(x)	((x) - PAGE_OFFSET)
+#ifdef CONFIG_DEBUG_VIRTUAL
+extern unsigned long __phys_addr(unsigned long);
+#else
+#define __phys_addr(x)		__phys_addr_nodebug(x)
+#endif
 #define __phys_reloc_hide(x)	RELOC_HIDE((x), 0)
 
 #ifdef CONFIG_FLATMEM
@@ -89,13 +98,11 @@
 extern unsigned int __VMALLOC_RESERVE;
 extern int sysctl_legacy_va_layout;
 
-#define VMALLOC_RESERVE		((unsigned long)__VMALLOC_RESERVE)
-#define MAXMEM			(-__PAGE_OFFSET - __VMALLOC_RESERVE)
-
 extern void find_low_pfn_range(void);
 extern unsigned long init_memory_mapping(unsigned long start,
 					 unsigned long end);
 extern void initmem_init(unsigned long, unsigned long);
+extern void free_initmem(void);
 extern void setup_bootmem_allocator(void);
 
 
@@ -126,4 +133,4 @@
 #endif	/* CONFIG_X86_3DNOW */
 #endif	/* !__ASSEMBLY__ */
 
-#endif /* _ASM_X86_PAGE_32_H */
+#endif /* ASM_X86__PAGE_32_H */
diff --git a/include/asm-x86/page_64.h b/include/asm-x86/page_64.h
index c6916c8..49380b8 100644
--- a/include/asm-x86/page_64.h
+++ b/include/asm-x86/page_64.h
@@ -1,5 +1,5 @@
-#ifndef _X86_64_PAGE_H
-#define _X86_64_PAGE_H
+#ifndef ASM_X86__PAGE_64_H
+#define ASM_X86__PAGE_64_H
 
 #define PAGETABLE_LEVELS	4
 
@@ -79,7 +79,6 @@
 typedef unsigned long	pudval_t;
 typedef unsigned long	pgdval_t;
 typedef unsigned long	pgprotval_t;
-typedef unsigned long	phys_addr_t;
 
 typedef struct page *pgtable_t;
 
@@ -91,6 +90,7 @@
 					 unsigned long end);
 
 extern void initmem_init(unsigned long start_pfn, unsigned long end_pfn);
+extern void free_initmem(void);
 
 extern void init_extra_mapping_uc(unsigned long phys, unsigned long size);
 extern void init_extra_mapping_wb(unsigned long phys, unsigned long size);
@@ -102,4 +102,4 @@
 #endif
 
 
-#endif /* _X86_64_PAGE_H */
+#endif /* ASM_X86__PAGE_64_H */
diff --git a/include/asm-x86/param.h b/include/asm-x86/param.h
index 6f0d042..0009cfb 100644
--- a/include/asm-x86/param.h
+++ b/include/asm-x86/param.h
@@ -1,5 +1,5 @@
-#ifndef _ASM_X86_PARAM_H
-#define _ASM_X86_PARAM_H
+#ifndef ASM_X86__PARAM_H
+#define ASM_X86__PARAM_H
 
 #ifdef __KERNEL__
 # define HZ		CONFIG_HZ	/* Internal kernel timer frequency */
@@ -19,4 +19,4 @@
 
 #define MAXHOSTNAMELEN	64	/* max length of hostname */
 
-#endif /* _ASM_X86_PARAM_H */
+#endif /* ASM_X86__PARAM_H */
diff --git a/include/asm-x86/paravirt.h b/include/asm-x86/paravirt.h
index fbbde93f..8d6ae2f 100644
--- a/include/asm-x86/paravirt.h
+++ b/include/asm-x86/paravirt.h
@@ -1,5 +1,5 @@
-#ifndef __ASM_PARAVIRT_H
-#define __ASM_PARAVIRT_H
+#ifndef ASM_X86__PARAVIRT_H
+#define ASM_X86__PARAVIRT_H
 /* Various instructions on x86 need to be replaced for
  * para-virtualization: those hooks are defined here. */
 
@@ -124,6 +124,9 @@
 				int entrynum, const void *desc, int size);
 	void (*write_idt_entry)(gate_desc *,
 				int entrynum, const gate_desc *gate);
+	void (*alloc_ldt)(struct desc_struct *ldt, unsigned entries);
+	void (*free_ldt)(struct desc_struct *ldt, unsigned entries);
+
 	void (*load_sp0)(struct tss_struct *tss, struct thread_struct *t);
 
 	void (*set_iopl_mask)(unsigned mask);
@@ -137,6 +140,7 @@
 
 	/* MSR, PMC and TSR operations.
 	   err = 0/-EFAULT.  wrmsr returns 0/-EFAULT. */
+	u64 (*read_msr_amd)(unsigned int msr, int *err);
 	u64 (*read_msr)(unsigned int msr, int *err);
 	int (*write_msr)(unsigned int msr, unsigned low, unsigned high);
 
@@ -200,12 +204,6 @@
 
 struct pv_apic_ops {
 #ifdef CONFIG_X86_LOCAL_APIC
-	/*
-	 * Direct APIC operations, principally for VMI.  Ideally
-	 * these shouldn't be in this interface.
-	 */
-	void (*apic_write)(unsigned long reg, u32 v);
-	u32 (*apic_read)(unsigned long reg);
 	void (*setup_boot_clock)(void);
 	void (*setup_secondary_clock)(void);
 
@@ -257,13 +255,13 @@
 	 * Hooks for allocating/releasing pagetable pages when they're
 	 * attached to a pagetable
 	 */
-	void (*alloc_pte)(struct mm_struct *mm, u32 pfn);
-	void (*alloc_pmd)(struct mm_struct *mm, u32 pfn);
-	void (*alloc_pmd_clone)(u32 pfn, u32 clonepfn, u32 start, u32 count);
-	void (*alloc_pud)(struct mm_struct *mm, u32 pfn);
-	void (*release_pte)(u32 pfn);
-	void (*release_pmd)(u32 pfn);
-	void (*release_pud)(u32 pfn);
+	void (*alloc_pte)(struct mm_struct *mm, unsigned long pfn);
+	void (*alloc_pmd)(struct mm_struct *mm, unsigned long pfn);
+	void (*alloc_pmd_clone)(unsigned long pfn, unsigned long clonepfn, unsigned long start, unsigned long count);
+	void (*alloc_pud)(struct mm_struct *mm, unsigned long pfn);
+	void (*release_pte)(unsigned long pfn);
+	void (*release_pmd)(unsigned long pfn);
+	void (*release_pud)(unsigned long pfn);
 
 	/* Pagetable manipulation functions */
 	void (*set_pte)(pte_t *ptep, pte_t pteval);
@@ -330,6 +328,7 @@
 	int (*spin_is_locked)(struct raw_spinlock *lock);
 	int (*spin_is_contended)(struct raw_spinlock *lock);
 	void (*spin_lock)(struct raw_spinlock *lock);
+	void (*spin_lock_flags)(struct raw_spinlock *lock, unsigned long flags);
 	int (*spin_trylock)(struct raw_spinlock *lock);
 	void (*spin_unlock)(struct raw_spinlock *lock);
 };
@@ -726,6 +725,10 @@
 {
 	return PVOP_CALL2(u64, pv_cpu_ops.read_msr, msr, err);
 }
+static inline u64 paravirt_read_msr_amd(unsigned msr, int *err)
+{
+	return PVOP_CALL2(u64, pv_cpu_ops.read_msr_amd, msr, err);
+}
 static inline int paravirt_write_msr(unsigned msr, unsigned low, unsigned high)
 {
 	return PVOP_CALL3(int, pv_cpu_ops.write_msr, msr, low, high);
@@ -771,6 +774,13 @@
 	*p = paravirt_read_msr(msr, &err);
 	return err;
 }
+static inline int rdmsrl_amd_safe(unsigned msr, unsigned long long *p)
+{
+	int err;
+
+	*p = paravirt_read_msr_amd(msr, &err);
+	return err;
+}
 
 static inline u64 paravirt_read_tsc(void)
 {
@@ -824,6 +834,16 @@
 	(aux) = __aux;					\
 } while (0)
 
+static inline void paravirt_alloc_ldt(struct desc_struct *ldt, unsigned entries)
+{
+	PVOP_VCALL2(pv_cpu_ops.alloc_ldt, ldt, entries);
+}
+
+static inline void paravirt_free_ldt(struct desc_struct *ldt, unsigned entries)
+{
+	PVOP_VCALL2(pv_cpu_ops.free_ldt, ldt, entries);
+}
+
 static inline void load_TR_desc(void)
 {
 	PVOP_VCALL0(pv_cpu_ops.load_tr_desc);
@@ -898,19 +918,6 @@
 }
 
 #ifdef CONFIG_X86_LOCAL_APIC
-/*
- * Basic functions accessing APICs.
- */
-static inline void apic_write(unsigned long reg, u32 v)
-{
-	PVOP_VCALL2(pv_apic_ops.apic_write, reg, v);
-}
-
-static inline u32 apic_read(unsigned long reg)
-{
-	return PVOP_CALL1(unsigned long, pv_apic_ops.apic_read, reg);
-}
-
 static inline void setup_boot_clock(void)
 {
 	PVOP_VCALL0(pv_apic_ops.setup_boot_clock);
@@ -993,35 +1000,35 @@
 	PVOP_VCALL2(pv_mmu_ops.pgd_free, mm, pgd);
 }
 
-static inline void paravirt_alloc_pte(struct mm_struct *mm, unsigned pfn)
+static inline void paravirt_alloc_pte(struct mm_struct *mm, unsigned long pfn)
 {
 	PVOP_VCALL2(pv_mmu_ops.alloc_pte, mm, pfn);
 }
-static inline void paravirt_release_pte(unsigned pfn)
+static inline void paravirt_release_pte(unsigned long pfn)
 {
 	PVOP_VCALL1(pv_mmu_ops.release_pte, pfn);
 }
 
-static inline void paravirt_alloc_pmd(struct mm_struct *mm, unsigned pfn)
+static inline void paravirt_alloc_pmd(struct mm_struct *mm, unsigned long pfn)
 {
 	PVOP_VCALL2(pv_mmu_ops.alloc_pmd, mm, pfn);
 }
 
-static inline void paravirt_alloc_pmd_clone(unsigned pfn, unsigned clonepfn,
-					    unsigned start, unsigned count)
+static inline void paravirt_alloc_pmd_clone(unsigned long pfn, unsigned long clonepfn,
+					    unsigned long start, unsigned long count)
 {
 	PVOP_VCALL4(pv_mmu_ops.alloc_pmd_clone, pfn, clonepfn, start, count);
 }
-static inline void paravirt_release_pmd(unsigned pfn)
+static inline void paravirt_release_pmd(unsigned long pfn)
 {
 	PVOP_VCALL1(pv_mmu_ops.release_pmd, pfn);
 }
 
-static inline void paravirt_alloc_pud(struct mm_struct *mm, unsigned pfn)
+static inline void paravirt_alloc_pud(struct mm_struct *mm, unsigned long pfn)
 {
 	PVOP_VCALL2(pv_mmu_ops.alloc_pud, mm, pfn);
 }
-static inline void paravirt_release_pud(unsigned pfn)
+static inline void paravirt_release_pud(unsigned long pfn)
 {
 	PVOP_VCALL1(pv_mmu_ops.release_pud, pfn);
 }
@@ -1401,6 +1408,12 @@
 	PVOP_VCALL1(pv_lock_ops.spin_lock, lock);
 }
 
+static __always_inline void __raw_spin_lock_flags(struct raw_spinlock *lock,
+						  unsigned long flags)
+{
+	PVOP_VCALL2(pv_lock_ops.spin_lock_flags, lock, flags);
+}
+
 static __always_inline int __raw_spin_trylock(struct raw_spinlock *lock)
 {
 	return PVOP_CALL1(int, pv_lock_ops.spin_trylock, lock);
@@ -1634,4 +1647,4 @@
 
 #endif /* __ASSEMBLY__ */
 #endif /* CONFIG_PARAVIRT */
-#endif	/* __ASM_PARAVIRT_H */
+#endif /* ASM_X86__PARAVIRT_H */
diff --git a/include/asm-x86/parport.h b/include/asm-x86/parport.h
index 3c4ffeb..2e3dda4 100644
--- a/include/asm-x86/parport.h
+++ b/include/asm-x86/parport.h
@@ -1,5 +1,5 @@
-#ifndef _ASM_X86_PARPORT_H
-#define _ASM_X86_PARPORT_H
+#ifndef ASM_X86__PARPORT_H
+#define ASM_X86__PARPORT_H
 
 static int __devinit parport_pc_find_isa_ports(int autoirq, int autodma);
 static int __devinit parport_pc_find_nonpci_ports(int autoirq, int autodma)
@@ -7,4 +7,4 @@
 	return parport_pc_find_isa_ports(autoirq, autodma);
 }
 
-#endif /* _ASM_X86_PARPORT_H */
+#endif /* ASM_X86__PARPORT_H */
diff --git a/include/asm-x86/pat.h b/include/asm-x86/pat.h
index 7edc473..482c3e3 100644
--- a/include/asm-x86/pat.h
+++ b/include/asm-x86/pat.h
@@ -1,5 +1,5 @@
-#ifndef _ASM_PAT_H
-#define _ASM_PAT_H
+#ifndef ASM_X86__PAT_H
+#define ASM_X86__PAT_H
 
 #include <linux/types.h>
 
@@ -19,4 +19,4 @@
 
 extern void pat_disable(char *reason);
 
-#endif
+#endif /* ASM_X86__PAT_H */
diff --git a/include/asm-x86/pci-direct.h b/include/asm-x86/pci-direct.h
index 80c775d..da42be0 100644
--- a/include/asm-x86/pci-direct.h
+++ b/include/asm-x86/pci-direct.h
@@ -1,5 +1,5 @@
-#ifndef ASM_PCI_DIRECT_H
-#define ASM_PCI_DIRECT_H 1
+#ifndef ASM_X86__PCI_DIRECT_H
+#define ASM_X86__PCI_DIRECT_H
 
 #include <linux/types.h>
 
@@ -18,4 +18,4 @@
 extern unsigned int pci_early_dump_regs;
 extern void early_dump_pci_device(u8 bus, u8 slot, u8 func);
 extern void early_dump_pci_devices(void);
-#endif
+#endif /* ASM_X86__PCI_DIRECT_H */
diff --git a/include/asm-x86/pci.h b/include/asm-x86/pci.h
index 2db14cf..6025831 100644
--- a/include/asm-x86/pci.h
+++ b/include/asm-x86/pci.h
@@ -1,5 +1,5 @@
-#ifndef __x86_PCI_H
-#define __x86_PCI_H
+#ifndef ASM_X86__PCI_H
+#define ASM_X86__PCI_H
 
 #include <linux/mm.h> /* for struct page */
 #include <linux/types.h>
@@ -111,4 +111,4 @@
 }
 #endif
 
-#endif
+#endif /* ASM_X86__PCI_H */
diff --git a/include/asm-x86/pci_32.h b/include/asm-x86/pci_32.h
index a50d468..3f22882 100644
--- a/include/asm-x86/pci_32.h
+++ b/include/asm-x86/pci_32.h
@@ -1,5 +1,5 @@
-#ifndef __i386_PCI_H
-#define __i386_PCI_H
+#ifndef ASM_X86__PCI_32_H
+#define ASM_X86__PCI_32_H
 
 
 #ifdef __KERNEL__
@@ -31,4 +31,4 @@
 #endif /* __KERNEL__ */
 
 
-#endif /* __i386_PCI_H */
+#endif /* ASM_X86__PCI_32_H */
diff --git a/include/asm-x86/pci_64.h b/include/asm-x86/pci_64.h
index f330234..f72e12d 100644
--- a/include/asm-x86/pci_64.h
+++ b/include/asm-x86/pci_64.h
@@ -1,5 +1,5 @@
-#ifndef __x8664_PCI_H
-#define __x8664_PCI_H
+#ifndef ASM_X86__PCI_64_H
+#define ASM_X86__PCI_64_H
 
 #ifdef __KERNEL__
 
@@ -63,4 +63,4 @@
 
 #endif /* __KERNEL__ */
 
-#endif /* __x8664_PCI_H */
+#endif /* ASM_X86__PCI_64_H */
diff --git a/include/asm-x86/pda.h b/include/asm-x86/pda.h
index b34e9a7..80860af 100644
--- a/include/asm-x86/pda.h
+++ b/include/asm-x86/pda.h
@@ -1,5 +1,5 @@
-#ifndef X86_64_PDA_H
-#define X86_64_PDA_H
+#ifndef ASM_X86__PDA_H
+#define ASM_X86__PDA_H
 
 #ifndef __ASSEMBLY__
 #include <linux/stddef.h>
@@ -134,4 +134,4 @@
 
 #define PDA_STACKOFFSET (5*8)
 
-#endif
+#endif /* ASM_X86__PDA_H */
diff --git a/include/asm-x86/percpu.h b/include/asm-x86/percpu.h
index f643a3a9..e10a1d0 100644
--- a/include/asm-x86/percpu.h
+++ b/include/asm-x86/percpu.h
@@ -1,5 +1,5 @@
-#ifndef _ASM_X86_PERCPU_H_
-#define _ASM_X86_PERCPU_H_
+#ifndef ASM_X86__PERCPU_H
+#define ASM_X86__PERCPU_H
 
 #ifdef CONFIG_X86_64
 #include <linux/compiler.h>
@@ -215,4 +215,4 @@
 
 #endif	/* !CONFIG_SMP */
 
-#endif /* _ASM_X86_PERCPU_H_ */
+#endif /* ASM_X86__PERCPU_H */
diff --git a/include/asm-x86/pgalloc.h b/include/asm-x86/pgalloc.h
index d63ea43..3cd23ad 100644
--- a/include/asm-x86/pgalloc.h
+++ b/include/asm-x86/pgalloc.h
@@ -1,5 +1,5 @@
-#ifndef _ASM_X86_PGALLOC_H
-#define _ASM_X86_PGALLOC_H
+#ifndef ASM_X86__PGALLOC_H
+#define ASM_X86__PGALLOC_H
 
 #include <linux/threads.h>
 #include <linux/mm.h>		/* for struct page */
@@ -111,4 +111,4 @@
 #endif	/* PAGETABLE_LEVELS > 3 */
 #endif	/* PAGETABLE_LEVELS > 2 */
 
-#endif	/* _ASM_X86_PGALLOC_H */
+#endif /* ASM_X86__PGALLOC_H */
diff --git a/include/asm-x86/pgtable-2level-defs.h b/include/asm-x86/pgtable-2level-defs.h
index 0f71c9f..7ec48f4 100644
--- a/include/asm-x86/pgtable-2level-defs.h
+++ b/include/asm-x86/pgtable-2level-defs.h
@@ -1,5 +1,5 @@
-#ifndef _I386_PGTABLE_2LEVEL_DEFS_H
-#define _I386_PGTABLE_2LEVEL_DEFS_H
+#ifndef ASM_X86__PGTABLE_2LEVEL_DEFS_H
+#define ASM_X86__PGTABLE_2LEVEL_DEFS_H
 
 #define SHARED_KERNEL_PMD	0
 
@@ -17,4 +17,4 @@
 
 #define PTRS_PER_PTE	1024
 
-#endif /* _I386_PGTABLE_2LEVEL_DEFS_H */
+#endif /* ASM_X86__PGTABLE_2LEVEL_DEFS_H */
diff --git a/include/asm-x86/pgtable-2level.h b/include/asm-x86/pgtable-2level.h
index 46bc52c..8176208 100644
--- a/include/asm-x86/pgtable-2level.h
+++ b/include/asm-x86/pgtable-2level.h
@@ -1,5 +1,5 @@
-#ifndef _I386_PGTABLE_2LEVEL_H
-#define _I386_PGTABLE_2LEVEL_H
+#ifndef ASM_X86__PGTABLE_2LEVEL_H
+#define ASM_X86__PGTABLE_2LEVEL_H
 
 #define pte_ERROR(e) \
 	printk("%s:%d: bad pte %08lx.\n", __FILE__, __LINE__, (e).pte_low)
@@ -53,9 +53,7 @@
 #define native_ptep_get_and_clear(xp) native_local_ptep_get_and_clear(xp)
 #endif
 
-#define pte_page(x)		pfn_to_page(pte_pfn(x))
 #define pte_none(x)		(!(x).pte_low)
-#define pte_pfn(x)		(pte_val(x) >> PAGE_SHIFT)
 
 /*
  * Bits 0, 6 and 7 are taken, split up the 29 bits of offset
@@ -78,4 +76,4 @@
 #define __pte_to_swp_entry(pte)		((swp_entry_t) { (pte).pte_low })
 #define __swp_entry_to_pte(x)		((pte_t) { .pte = (x).val })
 
-#endif /* _I386_PGTABLE_2LEVEL_H */
+#endif /* ASM_X86__PGTABLE_2LEVEL_H */
diff --git a/include/asm-x86/pgtable-3level-defs.h b/include/asm-x86/pgtable-3level-defs.h
index 448ac95..c05fe6f 100644
--- a/include/asm-x86/pgtable-3level-defs.h
+++ b/include/asm-x86/pgtable-3level-defs.h
@@ -1,5 +1,5 @@
-#ifndef _I386_PGTABLE_3LEVEL_DEFS_H
-#define _I386_PGTABLE_3LEVEL_DEFS_H
+#ifndef ASM_X86__PGTABLE_3LEVEL_DEFS_H
+#define ASM_X86__PGTABLE_3LEVEL_DEFS_H
 
 #ifdef CONFIG_PARAVIRT
 #define SHARED_KERNEL_PMD	(pv_info.shared_kernel_pmd)
@@ -25,4 +25,4 @@
  */
 #define PTRS_PER_PTE	512
 
-#endif /* _I386_PGTABLE_3LEVEL_DEFS_H */
+#endif /* ASM_X86__PGTABLE_3LEVEL_DEFS_H */
diff --git a/include/asm-x86/pgtable-3level.h b/include/asm-x86/pgtable-3level.h
index 105057f..75f4276 100644
--- a/include/asm-x86/pgtable-3level.h
+++ b/include/asm-x86/pgtable-3level.h
@@ -1,5 +1,5 @@
-#ifndef _I386_PGTABLE_3LEVEL_H
-#define _I386_PGTABLE_3LEVEL_H
+#ifndef ASM_X86__PGTABLE_3LEVEL_H
+#define ASM_X86__PGTABLE_3LEVEL_H
 
 /*
  * Intel Physical Address Extension (PAE) Mode - three-level page
@@ -151,18 +151,11 @@
 	return a.pte_low == b.pte_low && a.pte_high == b.pte_high;
 }
 
-#define pte_page(x)	pfn_to_page(pte_pfn(x))
-
 static inline int pte_none(pte_t pte)
 {
 	return !pte.pte_low && !pte.pte_high;
 }
 
-static inline unsigned long pte_pfn(pte_t pte)
-{
-	return (pte_val(pte) & PTE_PFN_MASK) >> PAGE_SHIFT;
-}
-
 /*
  * Bits 0, 6 and 7 are taken in the low part of the pte,
  * put the 32 bits of offset into the high part.
@@ -179,4 +172,4 @@
 #define __pte_to_swp_entry(pte)		((swp_entry_t){ (pte).pte_high })
 #define __swp_entry_to_pte(x)		((pte_t){ { .pte_high = (x).val } })
 
-#endif /* _I386_PGTABLE_3LEVEL_H */
+#endif /* ASM_X86__PGTABLE_3LEVEL_H */
diff --git a/include/asm-x86/pgtable.h b/include/asm-x86/pgtable.h
index 04caa2f..182f9d4 100644
--- a/include/asm-x86/pgtable.h
+++ b/include/asm-x86/pgtable.h
@@ -1,5 +1,5 @@
-#ifndef _ASM_X86_PGTABLE_H
-#define _ASM_X86_PGTABLE_H
+#ifndef ASM_X86__PGTABLE_H
+#define ASM_X86__PGTABLE_H
 
 #define FIRST_USER_ADDRESS	0
 
@@ -15,10 +15,11 @@
 #define _PAGE_BIT_PAT		7	/* on 4KB pages */
 #define _PAGE_BIT_GLOBAL	8	/* Global TLB entry PPro+ */
 #define _PAGE_BIT_UNUSED1	9	/* available for programmer */
-#define _PAGE_BIT_UNUSED2	10
+#define _PAGE_BIT_IOMAP		10	/* flag used to indicate IO mapping */
 #define _PAGE_BIT_UNUSED3	11
 #define _PAGE_BIT_PAT_LARGE	12	/* On 2MB or 1GB pages */
 #define _PAGE_BIT_SPECIAL	_PAGE_BIT_UNUSED1
+#define _PAGE_BIT_CPA_TEST	_PAGE_BIT_UNUSED1
 #define _PAGE_BIT_NX           63       /* No execute: only valid after cpuid check */
 
 #define _PAGE_PRESENT	(_AT(pteval_t, 1) << _PAGE_BIT_PRESENT)
@@ -31,11 +32,12 @@
 #define _PAGE_PSE	(_AT(pteval_t, 1) << _PAGE_BIT_PSE)
 #define _PAGE_GLOBAL	(_AT(pteval_t, 1) << _PAGE_BIT_GLOBAL)
 #define _PAGE_UNUSED1	(_AT(pteval_t, 1) << _PAGE_BIT_UNUSED1)
-#define _PAGE_UNUSED2	(_AT(pteval_t, 1) << _PAGE_BIT_UNUSED2)
+#define _PAGE_IOMAP	(_AT(pteval_t, 1) << _PAGE_BIT_IOMAP)
 #define _PAGE_UNUSED3	(_AT(pteval_t, 1) << _PAGE_BIT_UNUSED3)
 #define _PAGE_PAT	(_AT(pteval_t, 1) << _PAGE_BIT_PAT)
 #define _PAGE_PAT_LARGE (_AT(pteval_t, 1) << _PAGE_BIT_PAT_LARGE)
 #define _PAGE_SPECIAL	(_AT(pteval_t, 1) << _PAGE_BIT_SPECIAL)
+#define _PAGE_CPA_TEST	(_AT(pteval_t, 1) << _PAGE_BIT_CPA_TEST)
 #define __HAVE_ARCH_PTE_SPECIAL
 
 #if defined(CONFIG_X86_64) || defined(CONFIG_X86_PAE)
@@ -97,6 +99,11 @@
 #define __PAGE_KERNEL_LARGE_NOCACHE	(__PAGE_KERNEL | _PAGE_CACHE_UC | _PAGE_PSE)
 #define __PAGE_KERNEL_LARGE_EXEC	(__PAGE_KERNEL_EXEC | _PAGE_PSE)
 
+#define __PAGE_KERNEL_IO		(__PAGE_KERNEL | _PAGE_IOMAP)
+#define __PAGE_KERNEL_IO_NOCACHE	(__PAGE_KERNEL_NOCACHE | _PAGE_IOMAP)
+#define __PAGE_KERNEL_IO_UC_MINUS	(__PAGE_KERNEL_UC_MINUS | _PAGE_IOMAP)
+#define __PAGE_KERNEL_IO_WC		(__PAGE_KERNEL_WC | _PAGE_IOMAP)
+
 #define PAGE_KERNEL			__pgprot(__PAGE_KERNEL)
 #define PAGE_KERNEL_RO			__pgprot(__PAGE_KERNEL_RO)
 #define PAGE_KERNEL_EXEC		__pgprot(__PAGE_KERNEL_EXEC)
@@ -111,6 +118,11 @@
 #define PAGE_KERNEL_VSYSCALL		__pgprot(__PAGE_KERNEL_VSYSCALL)
 #define PAGE_KERNEL_VSYSCALL_NOCACHE	__pgprot(__PAGE_KERNEL_VSYSCALL_NOCACHE)
 
+#define PAGE_KERNEL_IO			__pgprot(__PAGE_KERNEL_IO)
+#define PAGE_KERNEL_IO_NOCACHE		__pgprot(__PAGE_KERNEL_IO_NOCACHE)
+#define PAGE_KERNEL_IO_UC_MINUS		__pgprot(__PAGE_KERNEL_IO_UC_MINUS)
+#define PAGE_KERNEL_IO_WC		__pgprot(__PAGE_KERNEL_IO_WC)
+
 /*         xwr */
 #define __P000	PAGE_NONE
 #define __P001	PAGE_READONLY
@@ -130,6 +142,17 @@
 #define __S110	PAGE_SHARED_EXEC
 #define __S111	PAGE_SHARED_EXEC
 
+/*
+ * early identity mapping  pte attrib macros.
+ */
+#ifdef CONFIG_X86_64
+#define __PAGE_KERNEL_IDENT_LARGE_EXEC	__PAGE_KERNEL_LARGE_EXEC
+#else
+#define PTE_IDENT_ATTR	 0x003		/* PRESENT+RW */
+#define PDE_IDENT_ATTR	 0x063		/* PRESENT+RW+DIRTY+ACCESSED */
+#define PGD_IDENT_ATTR	 0x001		/* PRESENT (no other attributes) */
+#endif
+
 #ifndef __ASSEMBLY__
 
 /*
@@ -183,9 +206,16 @@
 
 static inline int pte_special(pte_t pte)
 {
-	return pte_val(pte) & _PAGE_SPECIAL;
+	return pte_flags(pte) & _PAGE_SPECIAL;
 }
 
+static inline unsigned long pte_pfn(pte_t pte)
+{
+	return (pte_val(pte) & PTE_PFN_MASK) >> PAGE_SHIFT;
+}
+
+#define pte_page(pte)	pfn_to_page(pte_pfn(pte))
+
 static inline int pmd_large(pmd_t pte)
 {
 	return (pmd_val(pte) & (_PAGE_PSE | _PAGE_PRESENT)) ==
@@ -313,6 +343,8 @@
 static inline void native_pagetable_setup_done(pgd_t *base) {}
 #endif
 
+extern int arch_report_meminfo(char *page);
+
 #ifdef CONFIG_PARAVIRT
 #include <asm/paravirt.h>
 #else  /* !CONFIG_PARAVIRT */
@@ -521,4 +553,4 @@
 #include <asm-generic/pgtable.h>
 #endif	/* __ASSEMBLY__ */
 
-#endif	/* _ASM_X86_PGTABLE_H */
+#endif /* ASM_X86__PGTABLE_H */
diff --git a/include/asm-x86/pgtable_32.h b/include/asm-x86/pgtable_32.h
index 5c3b265..8de702d 100644
--- a/include/asm-x86/pgtable_32.h
+++ b/include/asm-x86/pgtable_32.h
@@ -1,5 +1,5 @@
-#ifndef _I386_PGTABLE_H
-#define _I386_PGTABLE_H
+#ifndef ASM_X86__PGTABLE_32_H
+#define ASM_X86__PGTABLE_32_H
 
 
 /*
@@ -31,6 +31,7 @@
 static inline void check_pgt_cache(void) { }
 void paging_init(void);
 
+extern void set_pmd_pfn(unsigned long, unsigned long, pgprot_t);
 
 /*
  * The Linux x86 paging architecture is 'compile-time dual-mode', it
@@ -56,8 +57,7 @@
  * area for the same reason. ;)
  */
 #define VMALLOC_OFFSET	(8 * 1024 * 1024)
-#define VMALLOC_START	(((unsigned long)high_memory + 2 * VMALLOC_OFFSET - 1) \
-			 & ~(VMALLOC_OFFSET - 1))
+#define VMALLOC_START	((unsigned long)high_memory + VMALLOC_OFFSET)
 #ifdef CONFIG_X86_PAE
 #define LAST_PKMAP 512
 #else
@@ -73,6 +73,8 @@
 # define VMALLOC_END	(FIXADDR_START - 2 * PAGE_SIZE)
 #endif
 
+#define MAXMEM	(VMALLOC_END - PAGE_OFFSET - __VMALLOC_RESERVE)
+
 /*
  * Define this if things work differently on an i386 and an i486:
  * it will (on an i486) warn about kernel memory accesses that are
@@ -186,4 +188,4 @@
 #define io_remap_pfn_range(vma, vaddr, pfn, size, prot)	\
 	remap_pfn_range(vma, vaddr, pfn, size, prot)
 
-#endif /* _I386_PGTABLE_H */
+#endif /* ASM_X86__PGTABLE_32_H */
diff --git a/include/asm-x86/pgtable_64.h b/include/asm-x86/pgtable_64.h
index 549144d..fde9770 100644
--- a/include/asm-x86/pgtable_64.h
+++ b/include/asm-x86/pgtable_64.h
@@ -1,5 +1,5 @@
-#ifndef _X86_64_PGTABLE_H
-#define _X86_64_PGTABLE_H
+#ifndef ASM_X86__PGTABLE_64_H
+#define ASM_X86__PGTABLE_64_H
 
 #include <linux/const.h>
 #ifndef __ASSEMBLY__
@@ -175,8 +175,6 @@
 #define pte_present(x)	(pte_val((x)) & (_PAGE_PRESENT | _PAGE_PROTNONE))
 
 #define pages_to_mb(x)	((x) >> (20 - PAGE_SHIFT))   /* FIXME: is this right? */
-#define pte_page(x)	pfn_to_page(pte_pfn((x)))
-#define pte_pfn(x)	((pte_val((x)) & __PHYSICAL_MASK) >> PAGE_SHIFT)
 
 /*
  * Macro to mark a page protection value as "uncacheable".
@@ -284,4 +282,4 @@
 #define __HAVE_ARCH_PTE_SAME
 #endif /* !__ASSEMBLY__ */
 
-#endif /* _X86_64_PGTABLE_H */
+#endif /* ASM_X86__PGTABLE_64_H */
diff --git a/include/asm-x86/posix_types_32.h b/include/asm-x86/posix_types_32.h
index b031efd..70cf2bb 100644
--- a/include/asm-x86/posix_types_32.h
+++ b/include/asm-x86/posix_types_32.h
@@ -1,5 +1,5 @@
-#ifndef __ARCH_I386_POSIX_TYPES_H
-#define __ARCH_I386_POSIX_TYPES_H
+#ifndef ASM_X86__POSIX_TYPES_32_H
+#define ASM_X86__POSIX_TYPES_32_H
 
 /*
  * This file is generally used by user-level software, so you need to
@@ -82,4 +82,4 @@
 
 #endif /* defined(__KERNEL__) */
 
-#endif
+#endif /* ASM_X86__POSIX_TYPES_32_H */
diff --git a/include/asm-x86/posix_types_64.h b/include/asm-x86/posix_types_64.h
index d6624c9..388b4e7 100644
--- a/include/asm-x86/posix_types_64.h
+++ b/include/asm-x86/posix_types_64.h
@@ -1,5 +1,5 @@
-#ifndef _ASM_X86_64_POSIX_TYPES_H
-#define _ASM_X86_64_POSIX_TYPES_H
+#ifndef ASM_X86__POSIX_TYPES_64_H
+#define ASM_X86__POSIX_TYPES_64_H
 
 /*
  * This file is generally used by user-level software, so you need to
@@ -116,4 +116,4 @@
 
 #endif /* defined(__KERNEL__) */
 
-#endif
+#endif /* ASM_X86__POSIX_TYPES_64_H */
diff --git a/include/asm-x86/prctl.h b/include/asm-x86/prctl.h
index 52952ad..e7ae34e 100644
--- a/include/asm-x86/prctl.h
+++ b/include/asm-x86/prctl.h
@@ -1,5 +1,5 @@
-#ifndef X86_64_PRCTL_H
-#define X86_64_PRCTL_H 1
+#ifndef ASM_X86__PRCTL_H
+#define ASM_X86__PRCTL_H
 
 #define ARCH_SET_GS 0x1001
 #define ARCH_SET_FS 0x1002
@@ -7,4 +7,4 @@
 #define ARCH_GET_GS 0x1004
 
 
-#endif
+#endif /* ASM_X86__PRCTL_H */
diff --git a/include/asm-x86/processor-cyrix.h b/include/asm-x86/processor-cyrix.h
index 97568ad..1198f2a 100644
--- a/include/asm-x86/processor-cyrix.h
+++ b/include/asm-x86/processor-cyrix.h
@@ -28,3 +28,11 @@
 	outb(reg, 0x22);
 	outb(data, 0x23);
 }
+
+#define getCx86_old(reg) ({ outb((reg), 0x22); inb(0x23); })
+
+#define setCx86_old(reg, data) do { \
+	outb((reg), 0x22); \
+	outb((data), 0x23); \
+} while (0)
+
diff --git a/include/asm-x86/processor-flags.h b/include/asm-x86/processor-flags.h
index eff2ecd..dc5f071 100644
--- a/include/asm-x86/processor-flags.h
+++ b/include/asm-x86/processor-flags.h
@@ -1,5 +1,5 @@
-#ifndef __ASM_I386_PROCESSOR_FLAGS_H
-#define __ASM_I386_PROCESSOR_FLAGS_H
+#ifndef ASM_X86__PROCESSOR_FLAGS_H
+#define ASM_X86__PROCESSOR_FLAGS_H
 /* Various flags defined: can be included from assembler. */
 
 /*
@@ -59,6 +59,7 @@
 #define X86_CR4_OSFXSR	0x00000200 /* enable fast FPU save and restore */
 #define X86_CR4_OSXMMEXCPT 0x00000400 /* enable unmasked SSE exceptions */
 #define X86_CR4_VMXE	0x00002000 /* enable VMX virtualization */
+#define X86_CR4_OSXSAVE 0x00040000 /* enable xsave and xrestore */
 
 /*
  * x86-64 Task Priority Register, CR8
@@ -96,4 +97,4 @@
 #endif
 #endif
 
-#endif	/* __ASM_I386_PROCESSOR_FLAGS_H */
+#endif /* ASM_X86__PROCESSOR_FLAGS_H */
diff --git a/include/asm-x86/processor.h b/include/asm-x86/processor.h
index 4df3e2f..ee7cbb3 100644
--- a/include/asm-x86/processor.h
+++ b/include/asm-x86/processor.h
@@ -1,5 +1,5 @@
-#ifndef __ASM_X86_PROCESSOR_H
-#define __ASM_X86_PROCESSOR_H
+#ifndef ASM_X86__PROCESSOR_H
+#define ASM_X86__PROCESSOR_H
 
 #include <asm/processor-flags.h>
 
@@ -20,6 +20,7 @@
 #include <asm/msr.h>
 #include <asm/desc_defs.h>
 #include <asm/nops.h>
+#include <asm/ds.h>
 
 #include <linux/personality.h>
 #include <linux/cpumask.h>
@@ -75,11 +76,11 @@
 	int			 x86_tlbsize;
 	__u8			x86_virt_bits;
 	__u8			x86_phys_bits;
+#endif
 	/* CPUID returned core id bits: */
 	__u8			x86_coreid_bits;
 	/* Max extended CPUID function supported: */
 	__u32			extended_cpuid_level;
-#endif
 	/* Maximum supported CPUID level, -1=no CPUID: */
 	int			cpuid_level;
 	__u32			x86_capability[NCAPINTS];
@@ -140,6 +141,8 @@
 #define current_cpu_data	boot_cpu_data
 #endif
 
+extern const struct seq_operations cpuinfo_op;
+
 static inline int hlt_works(int cpu)
 {
 #ifdef CONFIG_X86_32
@@ -153,6 +156,8 @@
 
 extern void cpu_detect(struct cpuinfo_x86 *c);
 
+extern struct pt_regs *idle_regs(struct pt_regs *);
+
 extern void early_cpu_init(void);
 extern void identify_boot_cpu(void);
 extern void identify_secondary_cpu(struct cpuinfo_x86 *);
@@ -161,11 +166,8 @@
 extern unsigned int init_intel_cacheinfo(struct cpuinfo_x86 *c);
 extern unsigned short num_cache_leaves;
 
-#if defined(CONFIG_X86_HT) || defined(CONFIG_X86_64)
+extern void detect_extended_topology(struct cpuinfo_x86 *c);
 extern void detect_ht(struct cpuinfo_x86 *c);
-#else
-static inline void detect_ht(struct cpuinfo_x86 *c) {}
-#endif
 
 static inline void native_cpuid(unsigned int *eax, unsigned int *ebx,
 				unsigned int *ecx, unsigned int *edx)
@@ -322,7 +324,12 @@
 	/* 16*16 bytes for each XMM-reg = 256 bytes:			*/
 	u32			xmm_space[64];
 
-	u32			padding[24];
+	u32			padding[12];
+
+	union {
+		u32		padding1[12];
+		u32		sw_reserved[12];
+	};
 
 } __attribute__((aligned(16)));
 
@@ -346,10 +353,23 @@
 	u32			entry_eip;
 };
 
+struct xsave_hdr_struct {
+	u64 xstate_bv;
+	u64 reserved1[2];
+	u64 reserved2[5];
+} __attribute__((packed));
+
+struct xsave_struct {
+	struct i387_fxsave_struct i387;
+	struct xsave_hdr_struct xsave_hdr;
+	/* new processor state extensions will go here */
+} __attribute__ ((packed, aligned (64)));
+
 union thread_xstate {
 	struct i387_fsave_struct	fsave;
 	struct i387_fxsave_struct	fxsave;
 	struct i387_soft_struct		soft;
+	struct xsave_struct		xsave;
 };
 
 #ifdef CONFIG_X86_64
@@ -411,9 +431,14 @@
 	unsigned		io_bitmap_max;
 /* MSR_IA32_DEBUGCTLMSR value to switch in if TIF_DEBUGCTLMSR is set.  */
 	unsigned long	debugctlmsr;
-/* Debug Store - if not 0 points to a DS Save Area configuration;
- *               goes into MSR_IA32_DS_AREA */
-	unsigned long	ds_area_msr;
+#ifdef CONFIG_X86_DS
+/* Debug Store context; see include/asm-x86/ds.h; goes into MSR_IA32_DS_AREA */
+	struct ds_context	*ds_ctx;
+#endif /* CONFIG_X86_DS */
+#ifdef CONFIG_X86_PTRACE_BTS
+/* the signal to send on a bts buffer overflow */
+	unsigned int	bts_ovfl_signal;
+#endif /* CONFIG_X86_PTRACE_BTS */
 };
 
 static inline unsigned long native_get_debugreg(int regno)
@@ -561,41 +586,6 @@
 	write_cr4(cr4);
 }
 
-struct microcode_header {
-	unsigned int		hdrver;
-	unsigned int		rev;
-	unsigned int		date;
-	unsigned int		sig;
-	unsigned int		cksum;
-	unsigned int		ldrver;
-	unsigned int		pf;
-	unsigned int		datasize;
-	unsigned int		totalsize;
-	unsigned int		reserved[3];
-};
-
-struct microcode {
-	struct microcode_header	hdr;
-	unsigned int		bits[0];
-};
-
-typedef struct microcode	microcode_t;
-typedef struct microcode_header	microcode_header_t;
-
-/* microcode format is extended from prescott processors */
-struct extended_signature {
-	unsigned int		sig;
-	unsigned int		pf;
-	unsigned int		cksum;
-};
-
-struct extended_sigtable {
-	unsigned int		count;
-	unsigned int		cksum;
-	unsigned int		reserved[3];
-	struct extended_signature sigs[0];
-};
-
 typedef struct {
 	unsigned long		seg;
 } mm_segment_t;
@@ -943,4 +933,4 @@
 extern int get_tsc_mode(unsigned long adr);
 extern int set_tsc_mode(unsigned int val);
 
-#endif
+#endif /* ASM_X86__PROCESSOR_H */
diff --git a/include/asm-x86/proto.h b/include/asm-x86/proto.h
index 3dd458c..6e89e8b 100644
--- a/include/asm-x86/proto.h
+++ b/include/asm-x86/proto.h
@@ -1,5 +1,5 @@
-#ifndef _ASM_X8664_PROTO_H
-#define _ASM_X8664_PROTO_H 1
+#ifndef ASM_X86__PROTO_H
+#define ASM_X86__PROTO_H
 
 #include <asm/ldt.h>
 
@@ -29,4 +29,4 @@
 #define round_up(x, y) (((x) + (y) - 1) & ~((y) - 1))
 #define round_down(x, y) ((x) & ~((y) - 1))
 
-#endif
+#endif /* ASM_X86__PROTO_H */
diff --git a/include/asm-x86/ptrace-abi.h b/include/asm-x86/ptrace-abi.h
index 72e7b9d..4298b88 100644
--- a/include/asm-x86/ptrace-abi.h
+++ b/include/asm-x86/ptrace-abi.h
@@ -1,5 +1,5 @@
-#ifndef _ASM_X86_PTRACE_ABI_H
-#define _ASM_X86_PTRACE_ABI_H
+#ifndef ASM_X86__PTRACE_ABI_H
+#define ASM_X86__PTRACE_ABI_H
 
 #ifdef __i386__
 
@@ -80,8 +80,9 @@
 
 #define PTRACE_SINGLEBLOCK	33	/* resume execution until next branch */
 
-#ifndef __ASSEMBLY__
+#ifdef CONFIG_X86_PTRACE_BTS
 
+#ifndef __ASSEMBLY__
 #include <asm/types.h>
 
 /* configuration/status structure used in PTRACE_BTS_CONFIG and
@@ -97,20 +98,20 @@
 	/* actual size of bts_struct in bytes */
 	__u32 bts_size;
 };
-#endif
+#endif /* __ASSEMBLY__ */
 
 #define PTRACE_BTS_O_TRACE	0x1 /* branch trace */
 #define PTRACE_BTS_O_SCHED	0x2 /* scheduling events w/ jiffies */
 #define PTRACE_BTS_O_SIGNAL     0x4 /* send SIG<signal> on buffer overflow
 				       instead of wrapping around */
-#define PTRACE_BTS_O_CUT_SIZE	0x8 /* cut requested size to max available
-				       instead of failing */
+#define PTRACE_BTS_O_ALLOC	0x8 /* (re)allocate buffer */
 
 #define PTRACE_BTS_CONFIG	40
 /* Configure branch trace recording.
    ADDR points to a struct ptrace_bts_config.
    DATA gives the size of that buffer.
-   A new buffer is allocated, iff the size changes.
+   A new buffer is allocated, if requested in the flags.
+   An overflow signal may only be requested for new buffers.
    Returns the number of bytes read.
 */
 #define PTRACE_BTS_STATUS	41
@@ -119,7 +120,7 @@
    Returns the number of bytes written.
 */
 #define PTRACE_BTS_SIZE		42
-/* Return the number of available BTS records.
+/* Return the number of available BTS records for draining.
    DATA and ADDR are ignored.
 */
 #define PTRACE_BTS_GET		43
@@ -139,5 +140,6 @@
    BTS records are read from oldest to newest.
    Returns number of BTS records drained.
 */
+#endif /* CONFIG_X86_PTRACE_BTS */
 
-#endif
+#endif /* ASM_X86__PTRACE_ABI_H */
diff --git a/include/asm-x86/ptrace.h b/include/asm-x86/ptrace.h
index 8a71db8..a202552 100644
--- a/include/asm-x86/ptrace.h
+++ b/include/asm-x86/ptrace.h
@@ -1,5 +1,5 @@
-#ifndef _ASM_X86_PTRACE_H
-#define _ASM_X86_PTRACE_H
+#ifndef ASM_X86__PTRACE_H
+#define ASM_X86__PTRACE_H
 
 #include <linux/compiler.h>	/* For __user */
 #include <asm/ptrace-abi.h>
@@ -127,26 +127,59 @@
 #endif /* __KERNEL__ */
 #endif /* !__i386__ */
 
+
+#ifdef CONFIG_X86_PTRACE_BTS
+/* a branch trace record entry
+ *
+ * In order to unify the interface between various processor versions,
+ * we use the below data structure for all processors.
+ */
+enum bts_qualifier {
+	BTS_INVALID = 0,
+	BTS_BRANCH,
+	BTS_TASK_ARRIVES,
+	BTS_TASK_DEPARTS
+};
+
+struct bts_struct {
+	__u64 qualifier;
+	union {
+		/* BTS_BRANCH */
+		struct {
+			__u64 from_ip;
+			__u64 to_ip;
+		} lbr;
+		/* BTS_TASK_ARRIVES or
+		   BTS_TASK_DEPARTS */
+		__u64 jiffies;
+	} variant;
+};
+#endif /* CONFIG_X86_PTRACE_BTS */
+
 #ifdef __KERNEL__
 
-/* the DS BTS struct is used for ptrace as well */
-#include <asm/ds.h>
+#include <linux/init.h>
 
+struct cpuinfo_x86;
 struct task_struct;
 
+#ifdef CONFIG_X86_PTRACE_BTS
+extern void __cpuinit ptrace_bts_init_intel(struct cpuinfo_x86 *);
 extern void ptrace_bts_take_timestamp(struct task_struct *, enum bts_qualifier);
+#else
+#define ptrace_bts_init_intel(config) do {} while (0)
+#endif /* CONFIG_X86_PTRACE_BTS */
 
 extern unsigned long profile_pc(struct pt_regs *regs);
 
 extern unsigned long
 convert_ip_to_linear(struct task_struct *child, struct pt_regs *regs);
-
-#ifdef CONFIG_X86_32
 extern void send_sigtrap(struct task_struct *tsk, struct pt_regs *regs,
-			 int error_code);
-#else
+			 int error_code, int si_code);
 void signal_fault(struct pt_regs *regs, void __user *frame, char *where);
-#endif
+
+extern long syscall_trace_enter(struct pt_regs *);
+extern void syscall_trace_leave(struct pt_regs *);
 
 static inline unsigned long regs_return_value(struct pt_regs *regs)
 {
@@ -213,6 +246,11 @@
 	return regs->bp;
 }
 
+static inline unsigned long user_stack_pointer(struct pt_regs *regs)
+{
+	return regs->sp;
+}
+
 /*
  * These are defined as per linux/ptrace.h, which see.
  */
@@ -239,4 +277,4 @@
 
 #endif /* !__ASSEMBLY__ */
 
-#endif
+#endif /* ASM_X86__PTRACE_H */
diff --git a/include/asm-x86/pvclock-abi.h b/include/asm-x86/pvclock-abi.h
index 6857f84..edb3b4e 100644
--- a/include/asm-x86/pvclock-abi.h
+++ b/include/asm-x86/pvclock-abi.h
@@ -1,5 +1,5 @@
-#ifndef _ASM_X86_PVCLOCK_ABI_H_
-#define _ASM_X86_PVCLOCK_ABI_H_
+#ifndef ASM_X86__PVCLOCK_ABI_H
+#define ASM_X86__PVCLOCK_ABI_H
 #ifndef __ASSEMBLY__
 
 /*
@@ -39,4 +39,4 @@
 } __attribute__((__packed__));
 
 #endif /* __ASSEMBLY__ */
-#endif /* _ASM_X86_PVCLOCK_ABI_H_ */
+#endif /* ASM_X86__PVCLOCK_ABI_H */
diff --git a/include/asm-x86/pvclock.h b/include/asm-x86/pvclock.h
index 85b1bba..1a38f68 100644
--- a/include/asm-x86/pvclock.h
+++ b/include/asm-x86/pvclock.h
@@ -1,5 +1,5 @@
-#ifndef _ASM_X86_PVCLOCK_H_
-#define _ASM_X86_PVCLOCK_H_
+#ifndef ASM_X86__PVCLOCK_H
+#define ASM_X86__PVCLOCK_H
 
 #include <linux/clocksource.h>
 #include <asm/pvclock-abi.h>
@@ -10,4 +10,4 @@
 			    struct pvclock_vcpu_time_info *vcpu,
 			    struct timespec *ts);
 
-#endif /* _ASM_X86_PVCLOCK_H_ */
+#endif /* ASM_X86__PVCLOCK_H */
diff --git a/include/asm-x86/reboot.h b/include/asm-x86/reboot.h
index 206f355..1c2f0ce 100644
--- a/include/asm-x86/reboot.h
+++ b/include/asm-x86/reboot.h
@@ -1,5 +1,5 @@
-#ifndef _ASM_REBOOT_H
-#define _ASM_REBOOT_H
+#ifndef ASM_X86__REBOOT_H
+#define ASM_X86__REBOOT_H
 
 struct pt_regs;
 
@@ -18,4 +18,4 @@
 void native_machine_shutdown(void);
 void machine_real_restart(const unsigned char *code, int length);
 
-#endif	/* _ASM_REBOOT_H */
+#endif /* ASM_X86__REBOOT_H */
diff --git a/include/asm-x86/reboot_fixups.h b/include/asm-x86/reboot_fixups.h
index 0cb7d87..2c2987d 100644
--- a/include/asm-x86/reboot_fixups.h
+++ b/include/asm-x86/reboot_fixups.h
@@ -1,6 +1,6 @@
-#ifndef _LINUX_REBOOT_FIXUPS_H
-#define _LINUX_REBOOT_FIXUPS_H
+#ifndef ASM_X86__REBOOT_FIXUPS_H
+#define ASM_X86__REBOOT_FIXUPS_H
 
 extern void mach_reboot_fixups(void);
 
-#endif /* _LINUX_REBOOT_FIXUPS_H */
+#endif /* ASM_X86__REBOOT_FIXUPS_H */
diff --git a/include/asm-x86/required-features.h b/include/asm-x86/required-features.h
index 5c2ff4b..a01c4e37 100644
--- a/include/asm-x86/required-features.h
+++ b/include/asm-x86/required-features.h
@@ -1,5 +1,5 @@
-#ifndef _ASM_REQUIRED_FEATURES_H
-#define _ASM_REQUIRED_FEATURES_H 1
+#ifndef ASM_X86__REQUIRED_FEATURES_H
+#define ASM_X86__REQUIRED_FEATURES_H
 
 /* Define minimum CPUID feature set for kernel These bits are checked
    really early to actually display a visible error message before the
@@ -79,4 +79,4 @@
 #define REQUIRED_MASK6	0
 #define REQUIRED_MASK7	0
 
-#endif
+#endif /* ASM_X86__REQUIRED_FEATURES_H */
diff --git a/include/asm-x86/resume-trace.h b/include/asm-x86/resume-trace.h
index 8d9f0b4..e39376d 100644
--- a/include/asm-x86/resume-trace.h
+++ b/include/asm-x86/resume-trace.h
@@ -1,5 +1,5 @@
-#ifndef _ASM_X86_RESUME_TRACE_H
-#define _ASM_X86_RESUME_TRACE_H
+#ifndef ASM_X86__RESUME_TRACE_H
+#define ASM_X86__RESUME_TRACE_H
 
 #include <asm/asm.h>
 
@@ -7,7 +7,7 @@
 do {								\
 	if (pm_trace_enabled) {					\
 		const void *tracedata;				\
-		asm volatile(_ASM_MOV_UL " $1f,%0\n"		\
+		asm volatile(_ASM_MOV " $1f,%0\n"		\
 			     ".section .tracedata,\"a\"\n"	\
 			     "1:\t.word %c1\n\t"		\
 			     _ASM_PTR " %c2\n"			\
@@ -18,4 +18,4 @@
 	}							\
 } while (0)
 
-#endif
+#endif /* ASM_X86__RESUME_TRACE_H */
diff --git a/include/asm-x86/rio.h b/include/asm-x86/rio.h
index c9448bd..5e1256b 100644
--- a/include/asm-x86/rio.h
+++ b/include/asm-x86/rio.h
@@ -5,8 +5,8 @@
  * Author: Laurent Vivier <Laurent.Vivier@bull.net>
  */
 
-#ifndef __ASM_RIO_H
-#define __ASM_RIO_H
+#ifndef ASM_X86__RIO_H
+#define ASM_X86__RIO_H
 
 #define RIO_TABLE_VERSION	3
 
@@ -60,4 +60,4 @@
 	ALT_CALGARY	= 5,	/* Second Planar Calgary      */
 };
 
-#endif /* __ASM_RIO_H */
+#endif /* ASM_X86__RIO_H */
diff --git a/include/asm-x86/rwlock.h b/include/asm-x86/rwlock.h
index 6a8c0d6..48a3109 100644
--- a/include/asm-x86/rwlock.h
+++ b/include/asm-x86/rwlock.h
@@ -1,8 +1,8 @@
-#ifndef _ASM_X86_RWLOCK_H
-#define _ASM_X86_RWLOCK_H
+#ifndef ASM_X86__RWLOCK_H
+#define ASM_X86__RWLOCK_H
 
 #define RW_LOCK_BIAS		 0x01000000
 
 /* Actual code is in asm/spinlock.h or in arch/x86/lib/rwlock.S */
 
-#endif /* _ASM_X86_RWLOCK_H */
+#endif /* ASM_X86__RWLOCK_H */
diff --git a/include/asm-x86/rwsem.h b/include/asm-x86/rwsem.h
index 750f2a3..3ff3015 100644
--- a/include/asm-x86/rwsem.h
+++ b/include/asm-x86/rwsem.h
@@ -29,8 +29,8 @@
  * front, then they'll all be woken up, but no other readers will be.
  */
 
-#ifndef _I386_RWSEM_H
-#define _I386_RWSEM_H
+#ifndef ASM_X86__RWSEM_H
+#define ASM_X86__RWSEM_H
 
 #ifndef _LINUX_RWSEM_H
 #error "please don't include asm/rwsem.h directly, use linux/rwsem.h instead"
@@ -262,4 +262,4 @@
 }
 
 #endif /* __KERNEL__ */
-#endif /* _I386_RWSEM_H */
+#endif /* ASM_X86__RWSEM_H */
diff --git a/include/asm-x86/scatterlist.h b/include/asm-x86/scatterlist.h
index c043206..ee48f88 100644
--- a/include/asm-x86/scatterlist.h
+++ b/include/asm-x86/scatterlist.h
@@ -1,5 +1,5 @@
-#ifndef _ASM_X86_SCATTERLIST_H
-#define _ASM_X86_SCATTERLIST_H
+#ifndef ASM_X86__SCATTERLIST_H
+#define ASM_X86__SCATTERLIST_H
 
 #include <asm/types.h>
 
@@ -30,4 +30,4 @@
 # define sg_dma_len(sg)		((sg)->dma_length)
 #endif
 
-#endif
+#endif /* ASM_X86__SCATTERLIST_H */
diff --git a/include/asm-x86/seccomp_32.h b/include/asm-x86/seccomp_32.h
index 36e71c5..cf9ab2d 100644
--- a/include/asm-x86/seccomp_32.h
+++ b/include/asm-x86/seccomp_32.h
@@ -1,5 +1,5 @@
-#ifndef _ASM_SECCOMP_H
-#define _ASM_SECCOMP_H
+#ifndef ASM_X86__SECCOMP_32_H
+#define ASM_X86__SECCOMP_32_H
 
 #include <linux/thread_info.h>
 
@@ -14,4 +14,4 @@
 #define __NR_seccomp_exit __NR_exit
 #define __NR_seccomp_sigreturn __NR_sigreturn
 
-#endif /* _ASM_SECCOMP_H */
+#endif /* ASM_X86__SECCOMP_32_H */
diff --git a/include/asm-x86/seccomp_64.h b/include/asm-x86/seccomp_64.h
index 76cfe69..03274ce 100644
--- a/include/asm-x86/seccomp_64.h
+++ b/include/asm-x86/seccomp_64.h
@@ -1,5 +1,5 @@
-#ifndef _ASM_SECCOMP_H
-#define _ASM_SECCOMP_H
+#ifndef ASM_X86__SECCOMP_64_H
+#define ASM_X86__SECCOMP_64_H
 
 #include <linux/thread_info.h>
 
@@ -22,4 +22,4 @@
 #define __NR_seccomp_exit_32 __NR_ia32_exit
 #define __NR_seccomp_sigreturn_32 __NR_ia32_sigreturn
 
-#endif /* _ASM_SECCOMP_H */
+#endif /* ASM_X86__SECCOMP_64_H */
diff --git a/include/asm-x86/segment.h b/include/asm-x86/segment.h
index 646452e..5d6e694 100644
--- a/include/asm-x86/segment.h
+++ b/include/asm-x86/segment.h
@@ -1,5 +1,5 @@
-#ifndef _ASM_X86_SEGMENT_H_
-#define _ASM_X86_SEGMENT_H_
+#ifndef ASM_X86__SEGMENT_H
+#define ASM_X86__SEGMENT_H
 
 /* Constructor for a conventional segment GDT (or LDT) entry */
 /* This is a macro so it can be used in initializers */
@@ -131,12 +131,6 @@
  * Matching rules for certain types of segments.
  */
 
-/* Matches only __KERNEL_CS, ignoring PnP / USER / APM segments */
-#define SEGMENT_IS_KERNEL_CODE(x) (((x) & 0xfc) == GDT_ENTRY_KERNEL_CS * 8)
-
-/* Matches __KERNEL_CS and __USER_CS (they must be 2 entries apart) */
-#define SEGMENT_IS_FLAT_CODE(x)  (((x) & 0xec) == GDT_ENTRY_KERNEL_CS * 8)
-
 /* Matches PNP_CS32 and PNP_CS16 (they must be consecutive) */
 #define SEGMENT_IS_PNP_CODE(x)   (((x) & 0xf4) == GDT_ENTRY_PNPBIOS_BASE * 8)
 
@@ -212,4 +206,4 @@
 #endif
 #endif
 
-#endif
+#endif /* ASM_X86__SEGMENT_H */
diff --git a/include/asm-x86/sembuf.h b/include/asm-x86/sembuf.h
index ee50c80..81f06b7 100644
--- a/include/asm-x86/sembuf.h
+++ b/include/asm-x86/sembuf.h
@@ -1,5 +1,5 @@
-#ifndef _ASM_X86_SEMBUF_H
-#define _ASM_X86_SEMBUF_H
+#ifndef ASM_X86__SEMBUF_H
+#define ASM_X86__SEMBUF_H
 
 /*
  * The semid64_ds structure for x86 architecture.
@@ -21,4 +21,4 @@
 	unsigned long	__unused4;
 };
 
-#endif /* _ASM_X86_SEMBUF_H */
+#endif /* ASM_X86__SEMBUF_H */
diff --git a/include/asm-x86/serial.h b/include/asm-x86/serial.h
index 628c801..303660b 100644
--- a/include/asm-x86/serial.h
+++ b/include/asm-x86/serial.h
@@ -1,5 +1,5 @@
-#ifndef _ASM_X86_SERIAL_H
-#define _ASM_X86_SERIAL_H
+#ifndef ASM_X86__SERIAL_H
+#define ASM_X86__SERIAL_H
 
 /*
  * This assumes you have a 1.8432 MHz clock for your UART.
@@ -26,4 +26,4 @@
 	{ 0, BASE_BAUD, 0x3E8, 4, STD_COM_FLAGS },	/* ttyS2 */	\
 	{ 0, BASE_BAUD, 0x2E8, 3, STD_COM4_FLAGS },	/* ttyS3 */
 
-#endif /* _ASM_X86_SERIAL_H */
+#endif /* ASM_X86__SERIAL_H */
diff --git a/include/asm-x86/setup.h b/include/asm-x86/setup.h
index a07c6f1..11b6cc1 100644
--- a/include/asm-x86/setup.h
+++ b/include/asm-x86/setup.h
@@ -1,5 +1,5 @@
-#ifndef _ASM_X86_SETUP_H
-#define _ASM_X86_SETUP_H
+#ifndef ASM_X86__SETUP_H
+#define ASM_X86__SETUP_H
 
 #define COMMAND_LINE_SIZE 2048
 
@@ -38,9 +38,11 @@
 	void (*mpc_oem_pci_bus)(struct mpc_config_bus *m);
 	void (*smp_read_mpc_oem)(struct mp_config_oemtable *oemtable,
                                     unsigned short oemsize);
+	int (*setup_ioapic_ids)(void);
 };
 
 extern struct x86_quirks *x86_quirks;
+extern unsigned long saved_video_mode;
 
 #ifndef CONFIG_PARAVIRT
 #define paravirt_post_allocator_init()	do {} while (0)
@@ -100,4 +102,4 @@
 #endif /* __ASSEMBLY__ */
 #endif  /*  __KERNEL__  */
 
-#endif /* _ASM_X86_SETUP_H */
+#endif /* ASM_X86__SETUP_H */
diff --git a/include/asm-x86/shmbuf.h b/include/asm-x86/shmbuf.h
index b51413b..f51aec2 100644
--- a/include/asm-x86/shmbuf.h
+++ b/include/asm-x86/shmbuf.h
@@ -1,5 +1,5 @@
-#ifndef _ASM_X86_SHMBUF_H
-#define _ASM_X86_SHMBUF_H
+#ifndef ASM_X86__SHMBUF_H
+#define ASM_X86__SHMBUF_H
 
 /*
  * The shmid64_ds structure for x86 architecture.
@@ -48,4 +48,4 @@
 	unsigned long	__unused4;
 };
 
-#endif /* _ASM_X86_SHMBUF_H */
+#endif /* ASM_X86__SHMBUF_H */
diff --git a/include/asm-x86/shmparam.h b/include/asm-x86/shmparam.h
index 0880cf0..a83a1fd 100644
--- a/include/asm-x86/shmparam.h
+++ b/include/asm-x86/shmparam.h
@@ -1,6 +1,6 @@
-#ifndef _ASM_X86_SHMPARAM_H
-#define _ASM_X86_SHMPARAM_H
+#ifndef ASM_X86__SHMPARAM_H
+#define ASM_X86__SHMPARAM_H
 
 #define SHMLBA PAGE_SIZE	 /* attach addr a multiple of this */
 
-#endif /* _ASM_X86_SHMPARAM_H */
+#endif /* ASM_X86__SHMPARAM_H */
diff --git a/include/asm-x86/sigcontext.h b/include/asm-x86/sigcontext.h
index 2f9c884..ee813f4 100644
--- a/include/asm-x86/sigcontext.h
+++ b/include/asm-x86/sigcontext.h
@@ -1,9 +1,43 @@
-#ifndef _ASM_X86_SIGCONTEXT_H
-#define _ASM_X86_SIGCONTEXT_H
+#ifndef ASM_X86__SIGCONTEXT_H
+#define ASM_X86__SIGCONTEXT_H
 
 #include <linux/compiler.h>
 #include <asm/types.h>
 
+#define FP_XSTATE_MAGIC1	0x46505853U
+#define FP_XSTATE_MAGIC2	0x46505845U
+#define FP_XSTATE_MAGIC2_SIZE	sizeof(FP_XSTATE_MAGIC2)
+
+/*
+ * bytes 464..511 in the current 512byte layout of fxsave/fxrstor frame
+ * are reserved for SW usage. On cpu's supporting xsave/xrstor, these bytes
+ * are used to extended the fpstate pointer in the sigcontext, which now
+ * includes the extended state information along with fpstate information.
+ *
+ * Presence of FP_XSTATE_MAGIC1 at the beginning of this SW reserved
+ * area and FP_XSTATE_MAGIC2 at the end of memory layout
+ * (extended_size - FP_XSTATE_MAGIC2_SIZE) indicates the presence of the
+ * extended state information in the memory layout pointed by the fpstate
+ * pointer in sigcontext.
+ */
+struct _fpx_sw_bytes {
+	__u32 magic1;		/* FP_XSTATE_MAGIC1 */
+	__u32 extended_size;	/* total size of the layout referred by
+				 * fpstate pointer in the sigcontext.
+				 */
+	__u64 xstate_bv;
+				/* feature bit mask (including fp/sse/extended
+				 * state) that is present in the memory
+				 * layout.
+				 */
+	__u32 xstate_size;	/* actual xsave state size, based on the
+				 * features saved in the layout.
+				 * 'extended_size' will be greater than
+				 * 'xstate_size'.
+				 */
+	__u32 padding[7];	/*  for future use. */
+};
+
 #ifdef __i386__
 /*
  * As documented in the iBCS2 standard..
@@ -53,7 +87,13 @@
 	unsigned long	reserved;
 	struct _fpxreg	_fxsr_st[8];	/* FXSR FPU reg data is ignored */
 	struct _xmmreg	_xmm[8];
-	unsigned long	padding[56];
+	unsigned long	padding1[44];
+
+	union {
+		unsigned long	padding2[12];
+		struct _fpx_sw_bytes sw_reserved; /* represents the extended
+						   * state info */
+	};
 };
 
 #define X86_FXSR_MAGIC		0x0000
@@ -79,7 +119,15 @@
 	unsigned long flags;
 	unsigned long sp_at_signal;
 	unsigned short ss, __ssh;
-	struct _fpstate __user *fpstate;
+
+	/*
+	 * fpstate is really (struct _fpstate *) or (struct _xstate *)
+	 * depending on the FP_XSTATE_MAGIC1 encoded in the SW reserved
+	 * bytes of (struct _fpstate) and FP_XSTATE_MAGIC2 present at the end
+	 * of extended memory layout. See comments at the defintion of
+	 * (struct _fpx_sw_bytes)
+	 */
+	void __user *fpstate;		/* zero when no FPU/extended context */
 	unsigned long oldmask;
 	unsigned long cr2;
 };
@@ -130,7 +178,12 @@
 	__u32	mxcsr_mask;
 	__u32	st_space[32];	/* 8*16 bytes for each FP-reg */
 	__u32	xmm_space[64];	/* 16*16 bytes for each XMM-reg  */
-	__u32	reserved2[24];
+	__u32	reserved2[12];
+	union {
+		__u32	reserved3[12];
+		struct _fpx_sw_bytes sw_reserved; /* represents the extended
+						   * state information */
+	};
 };
 
 #ifdef __KERNEL__
@@ -161,7 +214,15 @@
 	unsigned long trapno;
 	unsigned long oldmask;
 	unsigned long cr2;
-	struct _fpstate __user *fpstate;	/* zero when no FPU context */
+
+	/*
+	 * fpstate is really (struct _fpstate *) or (struct _xstate *)
+	 * depending on the FP_XSTATE_MAGIC1 encoded in the SW reserved
+	 * bytes of (struct _fpstate) and FP_XSTATE_MAGIC2 present at the end
+	 * of extended memory layout. See comments at the defintion of
+	 * (struct _fpx_sw_bytes)
+	 */
+	void __user *fpstate;		/* zero when no FPU/extended context */
 	unsigned long reserved1[8];
 };
 #else /* __KERNEL__ */
@@ -202,4 +263,22 @@
 
 #endif /* !__i386__ */
 
-#endif
+struct _xsave_hdr {
+	__u64 xstate_bv;
+	__u64 reserved1[2];
+	__u64 reserved2[5];
+};
+
+/*
+ * Extended state pointed by the fpstate pointer in the sigcontext.
+ * In addition to the fpstate, information encoded in the xstate_hdr
+ * indicates the presence of other extended state information
+ * supported by the processor and OS.
+ */
+struct _xstate {
+	struct _fpstate fpstate;
+	struct _xsave_hdr xstate_hdr;
+	/* new processor state extensions go here */
+};
+
+#endif /* ASM_X86__SIGCONTEXT_H */
diff --git a/include/asm-x86/sigcontext32.h b/include/asm-x86/sigcontext32.h
index 57a9686..8c34703 100644
--- a/include/asm-x86/sigcontext32.h
+++ b/include/asm-x86/sigcontext32.h
@@ -1,5 +1,5 @@
-#ifndef _SIGCONTEXT32_H
-#define _SIGCONTEXT32_H 1
+#ifndef ASM_X86__SIGCONTEXT32_H
+#define ASM_X86__SIGCONTEXT32_H
 
 /* signal context for 32bit programs. */
 
@@ -40,7 +40,11 @@
 	__u32	reserved;
 	struct _fpxreg	_fxsr_st[8];
 	struct _xmmreg	_xmm[8];	/* It's actually 16 */
-	__u32	padding[56];
+	__u32	padding[44];
+	union {
+		__u32 padding2[12];
+		struct _fpx_sw_bytes sw_reserved;
+	};
 };
 
 struct sigcontext_ia32 {
@@ -68,4 +72,4 @@
        unsigned int cr2;
 };
 
-#endif
+#endif /* ASM_X86__SIGCONTEXT32_H */
diff --git a/include/asm-x86/siginfo.h b/include/asm-x86/siginfo.h
index a477bea..808bdfb 100644
--- a/include/asm-x86/siginfo.h
+++ b/include/asm-x86/siginfo.h
@@ -1,5 +1,5 @@
-#ifndef _ASM_X86_SIGINFO_H
-#define _ASM_X86_SIGINFO_H
+#ifndef ASM_X86__SIGINFO_H
+#define ASM_X86__SIGINFO_H
 
 #ifdef __x86_64__
 # define __ARCH_SI_PREAMBLE_SIZE	(4 * sizeof(int))
@@ -7,4 +7,4 @@
 
 #include <asm-generic/siginfo.h>
 
-#endif
+#endif /* ASM_X86__SIGINFO_H */
diff --git a/include/asm-x86/signal.h b/include/asm-x86/signal.h
index 6dac493..65acc82 100644
--- a/include/asm-x86/signal.h
+++ b/include/asm-x86/signal.h
@@ -1,5 +1,5 @@
-#ifndef _ASM_X86_SIGNAL_H
-#define _ASM_X86_SIGNAL_H
+#ifndef ASM_X86__SIGNAL_H
+#define ASM_X86__SIGNAL_H
 
 #ifndef __ASSEMBLY__
 #include <linux/types.h>
@@ -140,6 +140,9 @@
 struct k_sigaction {
 	struct sigaction sa;
 };
+
+extern void do_notify_resume(struct pt_regs *, void *, __u32);
+
 # else /* __KERNEL__ */
 /* Here we must cater to libcs that poke about in kernel headers.  */
 
@@ -256,4 +259,4 @@
 #endif /* __KERNEL__ */
 #endif /* __ASSEMBLY__ */
 
-#endif
+#endif /* ASM_X86__SIGNAL_H */
diff --git a/include/asm-x86/smp.h b/include/asm-x86/smp.h
index 3c877f7..a6afc29 100644
--- a/include/asm-x86/smp.h
+++ b/include/asm-x86/smp.h
@@ -1,5 +1,5 @@
-#ifndef _ASM_X86_SMP_H_
-#define _ASM_X86_SMP_H_
+#ifndef ASM_X86__SMP_H
+#define ASM_X86__SMP_H
 #ifndef __ASSEMBLY__
 #include <linux/cpumask.h>
 #include <linux/init.h>
@@ -34,6 +34,9 @@
 DECLARE_PER_CPU(cpumask_t, cpu_sibling_map);
 DECLARE_PER_CPU(cpumask_t, cpu_core_map);
 DECLARE_PER_CPU(u16, cpu_llc_id);
+#ifdef CONFIG_X86_32
+DECLARE_PER_CPU(int, cpu_number);
+#endif
 
 DECLARE_EARLY_PER_CPU(u16, x86_cpu_to_apicid);
 DECLARE_EARLY_PER_CPU(u16, x86_bios_cpu_apicid);
@@ -47,12 +50,16 @@
 struct smp_ops {
 	void (*smp_prepare_boot_cpu)(void);
 	void (*smp_prepare_cpus)(unsigned max_cpus);
-	int (*cpu_up)(unsigned cpu);
 	void (*smp_cpus_done)(unsigned max_cpus);
 
 	void (*smp_send_stop)(void);
 	void (*smp_send_reschedule)(int cpu);
 
+	int (*cpu_up)(unsigned cpu);
+	int (*cpu_disable)(void);
+	void (*cpu_die)(unsigned int cpu);
+	void (*play_dead)(void);
+
 	void (*send_call_func_ipi)(cpumask_t mask);
 	void (*send_call_func_single_ipi)(int cpu);
 };
@@ -91,6 +98,21 @@
 	return smp_ops.cpu_up(cpu);
 }
 
+static inline int __cpu_disable(void)
+{
+	return smp_ops.cpu_disable();
+}
+
+static inline void __cpu_die(unsigned int cpu)
+{
+	smp_ops.cpu_die(cpu);
+}
+
+static inline void play_dead(void)
+{
+	smp_ops.play_dead();
+}
+
 static inline void smp_send_reschedule(int cpu)
 {
 	smp_ops.smp_send_reschedule(cpu);
@@ -106,15 +128,20 @@
 	smp_ops.send_call_func_ipi(mask);
 }
 
+void cpu_disable_common(void);
 void native_smp_prepare_boot_cpu(void);
 void native_smp_prepare_cpus(unsigned int max_cpus);
 void native_smp_cpus_done(unsigned int max_cpus);
 int native_cpu_up(unsigned int cpunum);
+int native_cpu_disable(void);
+void native_cpu_die(unsigned int cpu);
+void native_play_dead(void);
+void play_dead_common(void);
+
 void native_send_call_func_ipi(cpumask_t mask);
 void native_send_call_func_single_ipi(int cpu);
 
-extern int __cpu_disable(void);
-extern void __cpu_die(unsigned int cpu);
+extern void prefill_possible_map(void);
 
 void smp_store_cpu_info(int id);
 #define cpu_physical_id(cpu)	per_cpu(x86_cpu_to_apicid, cpu)
@@ -124,15 +151,11 @@
 {
 	return cpus_weight(cpu_callout_map);
 }
-#endif /* CONFIG_SMP */
-
-#if defined(CONFIG_SMP) && defined(CONFIG_HOTPLUG_CPU)
-extern void prefill_possible_map(void);
 #else
 static inline void prefill_possible_map(void)
 {
 }
-#endif
+#endif /* CONFIG_SMP */
 
 extern unsigned disabled_cpus __cpuinitdata;
 
@@ -142,7 +165,6 @@
  * from the initial startup. We map APIC_BASE very early in page_setup(),
  * so this is correct in the x86 case.
  */
-DECLARE_PER_CPU(int, cpu_number);
 #define raw_smp_processor_id() (x86_read_percpu(cpu_number))
 extern int safe_smp_processor_id(void);
 
@@ -165,30 +187,33 @@
 
 #ifdef CONFIG_X86_LOCAL_APIC
 
+#ifndef CONFIG_X86_64
 static inline int logical_smp_processor_id(void)
 {
 	/* we don't want to mark this access volatile - bad code generation */
 	return GET_APIC_LOGICAL_ID(*(u32 *)(APIC_BASE + APIC_LDR));
 }
 
-#ifndef CONFIG_X86_64
+#include <mach_apicdef.h>
 static inline unsigned int read_apic_id(void)
 {
-	return *(u32 *)(APIC_BASE + APIC_ID);
+	unsigned int reg;
+
+	reg = *(u32 *)(APIC_BASE + APIC_ID);
+
+	return GET_APIC_ID(reg);
 }
-#else
-extern unsigned int read_apic_id(void);
 #endif
 
 
-# ifdef APIC_DEFINITION
+# if defined(APIC_DEFINITION) || defined(CONFIG_X86_64)
 extern int hard_smp_processor_id(void);
 # else
-#  include <mach_apicdef.h>
+#include <mach_apicdef.h>
 static inline int hard_smp_processor_id(void)
 {
 	/* we don't want to mark this access volatile - bad code generation */
-	return GET_APIC_ID(read_apic_id());
+	return read_apic_id();
 }
 # endif /* APIC_DEFINITION */
 
@@ -200,9 +225,5 @@
 
 #endif /* CONFIG_X86_LOCAL_APIC */
 
-#ifdef CONFIG_HOTPLUG_CPU
-extern void cpu_uninit(void);
-#endif
-
 #endif /* __ASSEMBLY__ */
-#endif
+#endif /* ASM_X86__SMP_H */
diff --git a/include/asm-x86/socket.h b/include/asm-x86/socket.h
index 80af9c4..db73274 100644
--- a/include/asm-x86/socket.h
+++ b/include/asm-x86/socket.h
@@ -1,5 +1,5 @@
-#ifndef _ASM_SOCKET_H
-#define _ASM_SOCKET_H
+#ifndef ASM_X86__SOCKET_H
+#define ASM_X86__SOCKET_H
 
 #include <asm/sockios.h>
 
@@ -54,4 +54,4 @@
 
 #define SO_MARK			36
 
-#endif /* _ASM_SOCKET_H */
+#endif /* ASM_X86__SOCKET_H */
diff --git a/include/asm-x86/sockios.h b/include/asm-x86/sockios.h
index 49cc72b..a006704 100644
--- a/include/asm-x86/sockios.h
+++ b/include/asm-x86/sockios.h
@@ -1,5 +1,5 @@
-#ifndef _ASM_X86_SOCKIOS_H
-#define _ASM_X86_SOCKIOS_H
+#ifndef ASM_X86__SOCKIOS_H
+#define ASM_X86__SOCKIOS_H
 
 /* Socket-level I/O control calls. */
 #define FIOSETOWN	0x8901
@@ -10,4 +10,4 @@
 #define SIOCGSTAMP	0x8906		/* Get stamp (timeval) */
 #define SIOCGSTAMPNS	0x8907		/* Get stamp (timespec) */
 
-#endif /* _ASM_X86_SOCKIOS_H */
+#endif /* ASM_X86__SOCKIOS_H */
diff --git a/include/asm-x86/sparsemem.h b/include/asm-x86/sparsemem.h
index 9bd48b0..38f8e6b 100644
--- a/include/asm-x86/sparsemem.h
+++ b/include/asm-x86/sparsemem.h
@@ -1,5 +1,5 @@
-#ifndef _ASM_X86_SPARSEMEM_H
-#define _ASM_X86_SPARSEMEM_H
+#ifndef ASM_X86__SPARSEMEM_H
+#define ASM_X86__SPARSEMEM_H
 
 #ifdef CONFIG_SPARSEMEM
 /*
@@ -31,4 +31,4 @@
 #endif
 
 #endif /* CONFIG_SPARSEMEM */
-#endif
+#endif /* ASM_X86__SPARSEMEM_H */
diff --git a/include/asm-x86/spinlock.h b/include/asm-x86/spinlock.h
index e39c790..157ff7f 100644
--- a/include/asm-x86/spinlock.h
+++ b/include/asm-x86/spinlock.h
@@ -1,5 +1,5 @@
-#ifndef _X86_SPINLOCK_H_
-#define _X86_SPINLOCK_H_
+#ifndef ASM_X86__SPINLOCK_H
+#define ASM_X86__SPINLOCK_H
 
 #include <asm/atomic.h>
 #include <asm/rwlock.h>
@@ -21,8 +21,10 @@
 
 #ifdef CONFIG_X86_32
 # define LOCK_PTR_REG "a"
+# define REG_PTR_MODE "k"
 #else
 # define LOCK_PTR_REG "D"
+# define REG_PTR_MODE "q"
 #endif
 
 #if defined(CONFIG_X86_32) && \
@@ -54,19 +56,7 @@
  * much between them in performance though, especially as locks are out of line.
  */
 #if (NR_CPUS < 256)
-static inline int __ticket_spin_is_locked(raw_spinlock_t *lock)
-{
-	int tmp = ACCESS_ONCE(lock->slock);
-
-	return (((tmp >> 8) & 0xff) != (tmp & 0xff));
-}
-
-static inline int __ticket_spin_is_contended(raw_spinlock_t *lock)
-{
-	int tmp = ACCESS_ONCE(lock->slock);
-
-	return (((tmp >> 8) - tmp) & 0xff) > 1;
-}
+#define TICKET_SHIFT 8
 
 static __always_inline void __ticket_spin_lock(raw_spinlock_t *lock)
 {
@@ -89,19 +79,17 @@
 
 static __always_inline int __ticket_spin_trylock(raw_spinlock_t *lock)
 {
-	int tmp;
-	short new;
+	int tmp, new;
 
-	asm volatile("movw %2,%w0\n\t"
+	asm volatile("movzwl %2, %0\n\t"
 		     "cmpb %h0,%b0\n\t"
+		     "leal 0x100(%" REG_PTR_MODE "0), %1\n\t"
 		     "jne 1f\n\t"
-		     "movw %w0,%w1\n\t"
-		     "incb %h1\n\t"
-		     "lock ; cmpxchgw %w1,%2\n\t"
+		     LOCK_PREFIX "cmpxchgw %w1,%2\n\t"
 		     "1:"
 		     "sete %b1\n\t"
 		     "movzbl %b1,%0\n\t"
-		     : "=&a" (tmp), "=Q" (new), "+m" (lock->slock)
+		     : "=&a" (tmp), "=&q" (new), "+m" (lock->slock)
 		     :
 		     : "memory", "cc");
 
@@ -116,26 +104,14 @@
 		     : "memory", "cc");
 }
 #else
-static inline int __ticket_spin_is_locked(raw_spinlock_t *lock)
-{
-	int tmp = ACCESS_ONCE(lock->slock);
-
-	return (((tmp >> 16) & 0xffff) != (tmp & 0xffff));
-}
-
-static inline int __ticket_spin_is_contended(raw_spinlock_t *lock)
-{
-	int tmp = ACCESS_ONCE(lock->slock);
-
-	return (((tmp >> 16) - tmp) & 0xffff) > 1;
-}
+#define TICKET_SHIFT 16
 
 static __always_inline void __ticket_spin_lock(raw_spinlock_t *lock)
 {
 	int inc = 0x00010000;
 	int tmp;
 
-	asm volatile("lock ; xaddl %0, %1\n"
+	asm volatile(LOCK_PREFIX "xaddl %0, %1\n"
 		     "movzwl %w0, %2\n\t"
 		     "shrl $16, %0\n\t"
 		     "1:\t"
@@ -146,7 +122,7 @@
 		     /* don't need lfence here, because loads are in-order */
 		     "jmp 1b\n"
 		     "2:"
-		     : "+Q" (inc), "+m" (lock->slock), "=r" (tmp)
+		     : "+r" (inc), "+m" (lock->slock), "=&r" (tmp)
 		     :
 		     : "memory", "cc");
 }
@@ -160,13 +136,13 @@
 		     "movl %0,%1\n\t"
 		     "roll $16, %0\n\t"
 		     "cmpl %0,%1\n\t"
+		     "leal 0x00010000(%" REG_PTR_MODE "0), %1\n\t"
 		     "jne 1f\n\t"
-		     "addl $0x00010000, %1\n\t"
-		     "lock ; cmpxchgl %1,%2\n\t"
+		     LOCK_PREFIX "cmpxchgl %1,%2\n\t"
 		     "1:"
 		     "sete %b1\n\t"
 		     "movzbl %b1,%0\n\t"
-		     : "=&a" (tmp), "=r" (new), "+m" (lock->slock)
+		     : "=&a" (tmp), "=&q" (new), "+m" (lock->slock)
 		     :
 		     : "memory", "cc");
 
@@ -182,7 +158,19 @@
 }
 #endif
 
-#define __raw_spin_lock_flags(lock, flags) __raw_spin_lock(lock)
+static inline int __ticket_spin_is_locked(raw_spinlock_t *lock)
+{
+	int tmp = ACCESS_ONCE(lock->slock);
+
+	return !!(((tmp >> TICKET_SHIFT) ^ tmp) & ((1 << TICKET_SHIFT) - 1));
+}
+
+static inline int __ticket_spin_is_contended(raw_spinlock_t *lock)
+{
+	int tmp = ACCESS_ONCE(lock->slock);
+
+	return (((tmp >> TICKET_SHIFT) - tmp) & ((1 << TICKET_SHIFT) - 1)) > 1;
+}
 
 #ifdef CONFIG_PARAVIRT
 /*
@@ -272,6 +260,13 @@
 {
 	__ticket_spin_unlock(lock);
 }
+
+static __always_inline void __raw_spin_lock_flags(raw_spinlock_t *lock,
+						  unsigned long flags)
+{
+	__raw_spin_lock(lock);
+}
+
 #endif	/* CONFIG_PARAVIRT */
 
 static inline void __raw_spin_unlock_wait(raw_spinlock_t *lock)
@@ -366,4 +361,4 @@
 #define _raw_read_relax(lock)	cpu_relax()
 #define _raw_write_relax(lock)	cpu_relax()
 
-#endif
+#endif /* ASM_X86__SPINLOCK_H */
diff --git a/include/asm-x86/spinlock_types.h b/include/asm-x86/spinlock_types.h
index 06c071c..6aa9b56 100644
--- a/include/asm-x86/spinlock_types.h
+++ b/include/asm-x86/spinlock_types.h
@@ -1,5 +1,5 @@
-#ifndef __ASM_SPINLOCK_TYPES_H
-#define __ASM_SPINLOCK_TYPES_H
+#ifndef ASM_X86__SPINLOCK_TYPES_H
+#define ASM_X86__SPINLOCK_TYPES_H
 
 #ifndef __LINUX_SPINLOCK_TYPES_H
 # error "please don't include this file directly"
@@ -17,4 +17,4 @@
 
 #define __RAW_RW_LOCK_UNLOCKED		{ RW_LOCK_BIAS }
 
-#endif
+#endif /* ASM_X86__SPINLOCK_TYPES_H */
diff --git a/include/asm-x86/srat.h b/include/asm-x86/srat.h
index 774c919..5363e4f 100644
--- a/include/asm-x86/srat.h
+++ b/include/asm-x86/srat.h
@@ -24,8 +24,8 @@
  * Send feedback to Pat Gaughen <gone@us.ibm.com>
  */
 
-#ifndef _ASM_SRAT_H_
-#define _ASM_SRAT_H_
+#ifndef ASM_X86__SRAT_H
+#define ASM_X86__SRAT_H
 
 #ifdef CONFIG_ACPI_NUMA
 extern int get_memcfg_from_srat(void);
@@ -36,4 +36,4 @@
 }
 #endif
 
-#endif /* _ASM_SRAT_H_ */
+#endif /* ASM_X86__SRAT_H */
diff --git a/include/asm-x86/stacktrace.h b/include/asm-x86/stacktrace.h
index 30f8252..f43517e 100644
--- a/include/asm-x86/stacktrace.h
+++ b/include/asm-x86/stacktrace.h
@@ -1,5 +1,5 @@
-#ifndef _ASM_STACKTRACE_H
-#define _ASM_STACKTRACE_H 1
+#ifndef ASM_X86__STACKTRACE_H
+#define ASM_X86__STACKTRACE_H
 
 extern int kstack_depth_to_print;
 
@@ -18,4 +18,4 @@
 		unsigned long *stack, unsigned long bp,
 		const struct stacktrace_ops *ops, void *data);
 
-#endif
+#endif /* ASM_X86__STACKTRACE_H */
diff --git a/include/asm-x86/stat.h b/include/asm-x86/stat.h
index 5c22dcb..1e120f6 100644
--- a/include/asm-x86/stat.h
+++ b/include/asm-x86/stat.h
@@ -1,5 +1,5 @@
-#ifndef _ASM_X86_STAT_H
-#define _ASM_X86_STAT_H
+#ifndef ASM_X86__STAT_H
+#define ASM_X86__STAT_H
 
 #define STAT_HAVE_NSEC 1
 
@@ -111,4 +111,4 @@
 #endif
 };
 
-#endif
+#endif /* ASM_X86__STAT_H */
diff --git a/include/asm-x86/statfs.h b/include/asm-x86/statfs.h
index 7c651aa..ca5dc19 100644
--- a/include/asm-x86/statfs.h
+++ b/include/asm-x86/statfs.h
@@ -1,63 +1,12 @@
-#ifndef _ASM_X86_STATFS_H
-#define _ASM_X86_STATFS_H
-
-#ifdef __i386__
-#include <asm-generic/statfs.h>
-#else
-
-#ifndef __KERNEL_STRICT_NAMES
-
-#include <linux/types.h>
-
-typedef __kernel_fsid_t	fsid_t;
-
-#endif
+#ifndef ASM_X86__STATFS_H
+#define ASM_X86__STATFS_H
 
 /*
- * This is ugly -- we're already 64-bit clean, so just duplicate the
- * definitions.
+ * We need compat_statfs64 to be packed, because the i386 ABI won't
+ * add padding at the end to bring it to a multiple of 8 bytes, but
+ * the x86_64 ABI will.
  */
-struct statfs {
-	long f_type;
-	long f_bsize;
-	long f_blocks;
-	long f_bfree;
-	long f_bavail;
-	long f_files;
-	long f_ffree;
-	__kernel_fsid_t f_fsid;
-	long f_namelen;
-	long f_frsize;
-	long f_spare[5];
-};
+#define ARCH_PACK_COMPAT_STATFS64 __attribute__((packed,aligned(4)))
 
-struct statfs64 {
-	long f_type;
-	long f_bsize;
-	long f_blocks;
-	long f_bfree;
-	long f_bavail;
-	long f_files;
-	long f_ffree;
-	__kernel_fsid_t f_fsid;
-	long f_namelen;
-	long f_frsize;
-	long f_spare[5];
-};
-
-struct compat_statfs64 {
-	__u32 f_type;
-	__u32 f_bsize;
-	__u64 f_blocks;
-	__u64 f_bfree;
-	__u64 f_bavail;
-	__u64 f_files;
-	__u64 f_ffree;
-	__kernel_fsid_t f_fsid;
-	__u32 f_namelen;
-	__u32 f_frsize;
-	__u32 f_spare[5];
-} __attribute__((packed));
-
-#endif /* !__i386__ */
-#endif
+#include <asm-generic/statfs.h>
+#endif /* ASM_X86__STATFS_H */
diff --git a/include/asm-x86/string_32.h b/include/asm-x86/string_32.h
index 193578c..487843e 100644
--- a/include/asm-x86/string_32.h
+++ b/include/asm-x86/string_32.h
@@ -1,5 +1,5 @@
-#ifndef _I386_STRING_H_
-#define _I386_STRING_H_
+#ifndef ASM_X86__STRING_32_H
+#define ASM_X86__STRING_32_H
 
 #ifdef __KERNEL__
 
@@ -323,4 +323,4 @@
 
 #endif /* __KERNEL__ */
 
-#endif
+#endif /* ASM_X86__STRING_32_H */
diff --git a/include/asm-x86/string_64.h b/include/asm-x86/string_64.h
index 52b5ab3..a2add11d 100644
--- a/include/asm-x86/string_64.h
+++ b/include/asm-x86/string_64.h
@@ -1,5 +1,5 @@
-#ifndef _X86_64_STRING_H_
-#define _X86_64_STRING_H_
+#ifndef ASM_X86__STRING_64_H
+#define ASM_X86__STRING_64_H
 
 #ifdef __KERNEL__
 
@@ -57,4 +57,4 @@
 
 #endif /* __KERNEL__ */
 
-#endif
+#endif /* ASM_X86__STRING_64_H */
diff --git a/include/asm-x86/summit/apic.h b/include/asm-x86/summit/apic.h
new file mode 100644
index 0000000..c5b2e4b
--- /dev/null
+++ b/include/asm-x86/summit/apic.h
@@ -0,0 +1,185 @@
+#ifndef __ASM_SUMMIT_APIC_H
+#define __ASM_SUMMIT_APIC_H
+
+#include <asm/smp.h>
+
+#define esr_disable (1)
+#define NO_BALANCE_IRQ (0)
+
+/* In clustered mode, the high nibble of APIC ID is a cluster number.
+ * The low nibble is a 4-bit bitmap. */
+#define XAPIC_DEST_CPUS_SHIFT	4
+#define XAPIC_DEST_CPUS_MASK	((1u << XAPIC_DEST_CPUS_SHIFT) - 1)
+#define XAPIC_DEST_CLUSTER_MASK	(XAPIC_DEST_CPUS_MASK << XAPIC_DEST_CPUS_SHIFT)
+
+#define APIC_DFR_VALUE	(APIC_DFR_CLUSTER)
+
+static inline cpumask_t target_cpus(void)
+{
+	/* CPU_MASK_ALL (0xff) has undefined behaviour with
+	 * dest_LowestPrio mode logical clustered apic interrupt routing
+	 * Just start on cpu 0.  IRQ balancing will spread load
+	 */
+	return cpumask_of_cpu(0);
+}
+#define TARGET_CPUS	(target_cpus())
+
+#define INT_DELIVERY_MODE (dest_LowestPrio)
+#define INT_DEST_MODE 1     /* logical delivery broadcast to all procs */
+
+static inline unsigned long check_apicid_used(physid_mask_t bitmap, int apicid)
+{
+	return 0;
+}
+
+/* we don't use the phys_cpu_present_map to indicate apicid presence */
+static inline unsigned long check_apicid_present(int bit)
+{
+	return 1;
+}
+
+#define apicid_cluster(apicid) ((apicid) & XAPIC_DEST_CLUSTER_MASK)
+
+extern u8 cpu_2_logical_apicid[];
+
+static inline void init_apic_ldr(void)
+{
+	unsigned long val, id;
+	int count = 0;
+	u8 my_id = (u8)hard_smp_processor_id();
+	u8 my_cluster = (u8)apicid_cluster(my_id);
+#ifdef CONFIG_SMP
+	u8 lid;
+	int i;
+
+	/* Create logical APIC IDs by counting CPUs already in cluster. */
+	for (count = 0, i = NR_CPUS; --i >= 0; ) {
+		lid = cpu_2_logical_apicid[i];
+		if (lid != BAD_APICID && apicid_cluster(lid) == my_cluster)
+			++count;
+	}
+#endif
+	/* We only have a 4 wide bitmap in cluster mode.  If a deranged
+	 * BIOS puts 5 CPUs in one APIC cluster, we're hosed. */
+	BUG_ON(count >= XAPIC_DEST_CPUS_SHIFT);
+	id = my_cluster | (1UL << count);
+	apic_write(APIC_DFR, APIC_DFR_VALUE);
+	val = apic_read(APIC_LDR) & ~APIC_LDR_MASK;
+	val |= SET_APIC_LOGICAL_ID(id);
+	apic_write(APIC_LDR, val);
+}
+
+static inline int multi_timer_check(int apic, int irq)
+{
+	return 0;
+}
+
+static inline int apic_id_registered(void)
+{
+	return 1;
+}
+
+static inline void setup_apic_routing(void)
+{
+	printk("Enabling APIC mode:  Summit.  Using %d I/O APICs\n",
+						nr_ioapics);
+}
+
+static inline int apicid_to_node(int logical_apicid)
+{
+#ifdef CONFIG_SMP
+	return apicid_2_node[hard_smp_processor_id()];
+#else
+	return 0;
+#endif
+}
+
+/* Mapping from cpu number to logical apicid */
+static inline int cpu_to_logical_apicid(int cpu)
+{
+#ifdef CONFIG_SMP
+       if (cpu >= NR_CPUS)
+	       return BAD_APICID;
+	return (int)cpu_2_logical_apicid[cpu];
+#else
+	return logical_smp_processor_id();
+#endif
+}
+
+static inline int cpu_present_to_apicid(int mps_cpu)
+{
+	if (mps_cpu < NR_CPUS)
+		return (int)per_cpu(x86_bios_cpu_apicid, mps_cpu);
+	else
+		return BAD_APICID;
+}
+
+static inline physid_mask_t ioapic_phys_id_map(physid_mask_t phys_id_map)
+{
+	/* For clustered we don't have a good way to do this yet - hack */
+	return physids_promote(0x0F);
+}
+
+static inline physid_mask_t apicid_to_cpu_present(int apicid)
+{
+	return physid_mask_of_physid(0);
+}
+
+static inline void setup_portio_remap(void)
+{
+}
+
+static inline int check_phys_apicid_present(int boot_cpu_physical_apicid)
+{
+	return 1;
+}
+
+static inline void enable_apic_mode(void)
+{
+}
+
+static inline unsigned int cpu_mask_to_apicid(cpumask_t cpumask)
+{
+	int num_bits_set;
+	int cpus_found = 0;
+	int cpu;
+	int apicid;
+
+	num_bits_set = cpus_weight(cpumask);
+	/* Return id to all */
+	if (num_bits_set == NR_CPUS)
+		return (int) 0xFF;
+	/*
+	 * The cpus in the mask must all be on the apic cluster.  If are not
+	 * on the same apicid cluster return default value of TARGET_CPUS.
+	 */
+	cpu = first_cpu(cpumask);
+	apicid = cpu_to_logical_apicid(cpu);
+	while (cpus_found < num_bits_set) {
+		if (cpu_isset(cpu, cpumask)) {
+			int new_apicid = cpu_to_logical_apicid(cpu);
+			if (apicid_cluster(apicid) !=
+					apicid_cluster(new_apicid)){
+				printk ("%s: Not a valid mask!\n",__FUNCTION__);
+				return 0xFF;
+			}
+			apicid = apicid | new_apicid;
+			cpus_found++;
+		}
+		cpu++;
+	}
+	return apicid;
+}
+
+/* cpuid returns the value latched in the HW at reset, not the APIC ID
+ * register's value.  For any box whose BIOS changes APIC IDs, like
+ * clustered APIC systems, we must use hard_smp_processor_id.
+ *
+ * See Intel's IA-32 SW Dev's Manual Vol2 under CPUID.
+ */
+static inline u32 phys_pkg_id(u32 cpuid_apic, int index_msb)
+{
+	return hard_smp_processor_id() >> index_msb;
+}
+
+#endif /* __ASM_SUMMIT_APIC_H */
diff --git a/include/asm-x86/summit/apicdef.h b/include/asm-x86/summit/apicdef.h
new file mode 100644
index 0000000..f3fbca1
--- /dev/null
+++ b/include/asm-x86/summit/apicdef.h
@@ -0,0 +1,13 @@
+#ifndef __ASM_SUMMIT_APICDEF_H
+#define __ASM_SUMMIT_APICDEF_H
+
+#define		APIC_ID_MASK		(0xFF<<24)
+
+static inline unsigned get_apic_id(unsigned long x)
+{
+	return (x>>24)&0xFF;
+}
+
+#define		GET_APIC_ID(x)	get_apic_id(x)
+
+#endif
diff --git a/include/asm-x86/summit/ipi.h b/include/asm-x86/summit/ipi.h
new file mode 100644
index 0000000..53bd1e7
--- /dev/null
+++ b/include/asm-x86/summit/ipi.h
@@ -0,0 +1,25 @@
+#ifndef __ASM_SUMMIT_IPI_H
+#define __ASM_SUMMIT_IPI_H
+
+void send_IPI_mask_sequence(cpumask_t mask, int vector);
+
+static inline void send_IPI_mask(cpumask_t mask, int vector)
+{
+	send_IPI_mask_sequence(mask, vector);
+}
+
+static inline void send_IPI_allbutself(int vector)
+{
+	cpumask_t mask = cpu_online_map;
+	cpu_clear(smp_processor_id(), mask);
+
+	if (!cpus_empty(mask))
+		send_IPI_mask(mask, vector);
+}
+
+static inline void send_IPI_all(int vector)
+{
+	send_IPI_mask(cpu_online_map, vector);
+}
+
+#endif /* __ASM_SUMMIT_IPI_H */
diff --git a/include/asm-x86/mach-summit/irq_vectors_limits.h b/include/asm-x86/summit/irq_vectors_limits.h
similarity index 100%
rename from include/asm-x86/mach-summit/irq_vectors_limits.h
rename to include/asm-x86/summit/irq_vectors_limits.h
diff --git a/include/asm-x86/summit/mpparse.h b/include/asm-x86/summit/mpparse.h
new file mode 100644
index 0000000..013ce6f
--- /dev/null
+++ b/include/asm-x86/summit/mpparse.h
@@ -0,0 +1,109 @@
+#ifndef __ASM_SUMMIT_MPPARSE_H
+#define __ASM_SUMMIT_MPPARSE_H
+
+#include <asm/tsc.h>
+
+extern int use_cyclone;
+
+#ifdef CONFIG_X86_SUMMIT_NUMA
+extern void setup_summit(void);
+#else
+#define setup_summit()	{}
+#endif
+
+static inline int mps_oem_check(struct mp_config_table *mpc, char *oem,
+		char *productid)
+{
+	if (!strncmp(oem, "IBM ENSW", 8) &&
+			(!strncmp(productid, "VIGIL SMP", 9)
+			 || !strncmp(productid, "EXA", 3)
+			 || !strncmp(productid, "RUTHLESS SMP", 12))){
+		mark_tsc_unstable("Summit based system");
+		use_cyclone = 1; /*enable cyclone-timer*/
+		setup_summit();
+		return 1;
+	}
+	return 0;
+}
+
+/* Hook from generic ACPI tables.c */
+static inline int acpi_madt_oem_check(char *oem_id, char *oem_table_id)
+{
+	if (!strncmp(oem_id, "IBM", 3) &&
+	    (!strncmp(oem_table_id, "SERVIGIL", 8)
+	     || !strncmp(oem_table_id, "EXA", 3))){
+		mark_tsc_unstable("Summit based system");
+		use_cyclone = 1; /*enable cyclone-timer*/
+		setup_summit();
+		return 1;
+	}
+	return 0;
+}
+
+struct rio_table_hdr {
+	unsigned char version;      /* Version number of this data structure           */
+	                            /* Version 3 adds chassis_num & WP_index           */
+	unsigned char num_scal_dev; /* # of Scalability devices (Twisters for Vigil)   */
+	unsigned char num_rio_dev;  /* # of RIO I/O devices (Cyclones and Winnipegs)   */
+} __attribute__((packed));
+
+struct scal_detail {
+	unsigned char node_id;      /* Scalability Node ID                             */
+	unsigned long CBAR;         /* Address of 1MB register space                   */
+	unsigned char port0node;    /* Node ID port connected to: 0xFF=None            */
+	unsigned char port0port;    /* Port num port connected to: 0,1,2, or 0xFF=None */
+	unsigned char port1node;    /* Node ID port connected to: 0xFF = None          */
+	unsigned char port1port;    /* Port num port connected to: 0,1,2, or 0xFF=None */
+	unsigned char port2node;    /* Node ID port connected to: 0xFF = None          */
+	unsigned char port2port;    /* Port num port connected to: 0,1,2, or 0xFF=None */
+	unsigned char chassis_num;  /* 1 based Chassis number (1 = boot node)          */
+} __attribute__((packed));
+
+struct rio_detail {
+	unsigned char node_id;      /* RIO Node ID                                     */
+	unsigned long BBAR;         /* Address of 1MB register space                   */
+	unsigned char type;         /* Type of device                                  */
+	unsigned char owner_id;     /* For WPEG: Node ID of Cyclone that owns this WPEG*/
+	                            /* For CYC:  Node ID of Twister that owns this CYC */
+	unsigned char port0node;    /* Node ID port connected to: 0xFF=None            */
+	unsigned char port0port;    /* Port num port connected to: 0,1,2, or 0xFF=None */
+	unsigned char port1node;    /* Node ID port connected to: 0xFF=None            */
+	unsigned char port1port;    /* Port num port connected to: 0,1,2, or 0xFF=None */
+	unsigned char first_slot;   /* For WPEG: Lowest slot number below this WPEG    */
+	                            /* For CYC:  0                                     */
+	unsigned char status;       /* For WPEG: Bit 0 = 1 : the XAPIC is used         */
+	                            /*                 = 0 : the XAPIC is not used, ie:*/
+	                            /*                     ints fwded to another XAPIC */
+	                            /*           Bits1:7 Reserved                      */
+	                            /* For CYC:  Bits0:7 Reserved                      */
+	unsigned char WP_index;     /* For WPEG: WPEG instance index - lower ones have */
+	                            /*           lower slot numbers/PCI bus numbers    */
+	                            /* For CYC:  No meaning                            */
+	unsigned char chassis_num;  /* 1 based Chassis number                          */
+	                            /* For LookOut WPEGs this field indicates the      */
+	                            /* Expansion Chassis #, enumerated from Boot       */
+	                            /* Node WPEG external port, then Boot Node CYC     */
+	                            /* external port, then Next Vigil chassis WPEG     */
+	                            /* external port, etc.                             */
+	                            /* Shared Lookouts have only 1 chassis number (the */
+	                            /* first one assigned)                             */
+} __attribute__((packed));
+
+
+typedef enum {
+	CompatTwister = 0,  /* Compatibility Twister               */
+	AltTwister    = 1,  /* Alternate Twister of internal 8-way */
+	CompatCyclone = 2,  /* Compatibility Cyclone               */
+	AltCyclone    = 3,  /* Alternate Cyclone of internal 8-way */
+	CompatWPEG    = 4,  /* Compatibility WPEG                  */
+	AltWPEG       = 5,  /* Second Planar WPEG                  */
+	LookOutAWPEG  = 6,  /* LookOut WPEG                        */
+	LookOutBWPEG  = 7,  /* LookOut WPEG                        */
+} node_type;
+
+static inline int is_WPEG(struct rio_detail *rio){
+	return (rio->type == CompatWPEG || rio->type == AltWPEG ||
+		rio->type == LookOutAWPEG || rio->type == LookOutBWPEG);
+}
+
+#endif /* __ASM_SUMMIT_MPPARSE_H */
diff --git a/include/asm-x86/suspend_32.h b/include/asm-x86/suspend_32.h
index 8675c67..acb6d4d 100644
--- a/include/asm-x86/suspend_32.h
+++ b/include/asm-x86/suspend_32.h
@@ -3,8 +3,8 @@
  * Based on code
  * Copyright 2001 Patrick Mochel <mochel@osdl.org>
  */
-#ifndef __ASM_X86_32_SUSPEND_H
-#define __ASM_X86_32_SUSPEND_H
+#ifndef ASM_X86__SUSPEND_32_H
+#define ASM_X86__SUSPEND_32_H
 
 #include <asm/desc.h>
 #include <asm/i387.h>
@@ -48,4 +48,4 @@
 extern int acpi_save_state_mem(void);
 #endif
 
-#endif /* __ASM_X86_32_SUSPEND_H */
+#endif /* ASM_X86__SUSPEND_32_H */
diff --git a/include/asm-x86/suspend_64.h b/include/asm-x86/suspend_64.h
index dc3262b..cf821dd 100644
--- a/include/asm-x86/suspend_64.h
+++ b/include/asm-x86/suspend_64.h
@@ -3,8 +3,8 @@
  * Based on code
  * Copyright 2001 Patrick Mochel <mochel@osdl.org>
  */
-#ifndef __ASM_X86_64_SUSPEND_H
-#define __ASM_X86_64_SUSPEND_H
+#ifndef ASM_X86__SUSPEND_64_H
+#define ASM_X86__SUSPEND_64_H
 
 #include <asm/desc.h>
 #include <asm/i387.h>
@@ -49,4 +49,4 @@
 extern char core_restore_code;
 extern char restore_registers;
 
-#endif /* __ASM_X86_64_SUSPEND_H */
+#endif /* ASM_X86__SUSPEND_64_H */
diff --git a/include/asm-x86/swiotlb.h b/include/asm-x86/swiotlb.h
index 2730b35..1e20adb 100644
--- a/include/asm-x86/swiotlb.h
+++ b/include/asm-x86/swiotlb.h
@@ -1,5 +1,5 @@
-#ifndef _ASM_SWIOTLB_H
-#define _ASM_SWIOTLB_H 1
+#ifndef ASM_X86__SWIOTLB_H
+#define ASM_X86__SWIOTLB_H
 
 #include <asm/dma-mapping.h>
 
@@ -55,4 +55,4 @@
 
 static inline void dma_mark_clean(void *addr, size_t size) {}
 
-#endif /* _ASM_SWIOTLB_H */
+#endif /* ASM_X86__SWIOTLB_H */
diff --git a/include/asm-x86/sync_bitops.h b/include/asm-x86/sync_bitops.h
index b47a1d0..b689bee 100644
--- a/include/asm-x86/sync_bitops.h
+++ b/include/asm-x86/sync_bitops.h
@@ -1,5 +1,5 @@
-#ifndef _I386_SYNC_BITOPS_H
-#define _I386_SYNC_BITOPS_H
+#ifndef ASM_X86__SYNC_BITOPS_H
+#define ASM_X86__SYNC_BITOPS_H
 
 /*
  * Copyright 1992, Linus Torvalds.
@@ -127,4 +127,4 @@
 
 #undef ADDR
 
-#endif /* _I386_SYNC_BITOPS_H */
+#endif /* ASM_X86__SYNC_BITOPS_H */
diff --git a/include/asm-x86/syscall.h b/include/asm-x86/syscall.h
new file mode 100644
index 0000000..04c47dc
--- /dev/null
+++ b/include/asm-x86/syscall.h
@@ -0,0 +1,211 @@
+/*
+ * Access to user system call parameters and results
+ *
+ * Copyright (C) 2008 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.
+ *
+ * See asm-generic/syscall.h for descriptions of what we must do here.
+ */
+
+#ifndef _ASM_SYSCALL_H
+#define _ASM_SYSCALL_H	1
+
+#include <linux/sched.h>
+#include <linux/err.h>
+
+static inline long syscall_get_nr(struct task_struct *task,
+				  struct pt_regs *regs)
+{
+	/*
+	 * We always sign-extend a -1 value being set here,
+	 * so this is always either -1L or a syscall number.
+	 */
+	return regs->orig_ax;
+}
+
+static inline void syscall_rollback(struct task_struct *task,
+				    struct pt_regs *regs)
+{
+	regs->ax = regs->orig_ax;
+}
+
+static inline long syscall_get_error(struct task_struct *task,
+				     struct pt_regs *regs)
+{
+	unsigned long error = regs->ax;
+#ifdef CONFIG_IA32_EMULATION
+	/*
+	 * TS_COMPAT is set for 32-bit syscall entries and then
+	 * remains set until we return to user mode.
+	 */
+	if (task_thread_info(task)->status & TS_COMPAT)
+		/*
+		 * Sign-extend the value so (int)-EFOO becomes (long)-EFOO
+		 * and will match correctly in comparisons.
+		 */
+		error = (long) (int) error;
+#endif
+	return IS_ERR_VALUE(error) ? error : 0;
+}
+
+static inline long syscall_get_return_value(struct task_struct *task,
+					    struct pt_regs *regs)
+{
+	return regs->ax;
+}
+
+static inline void syscall_set_return_value(struct task_struct *task,
+					    struct pt_regs *regs,
+					    int error, long val)
+{
+	regs->ax = (long) error ?: val;
+}
+
+#ifdef CONFIG_X86_32
+
+static inline void syscall_get_arguments(struct task_struct *task,
+					 struct pt_regs *regs,
+					 unsigned int i, unsigned int n,
+					 unsigned long *args)
+{
+	BUG_ON(i + n > 6);
+	memcpy(args, &regs->bx + i, n * sizeof(args[0]));
+}
+
+static inline void syscall_set_arguments(struct task_struct *task,
+					 struct pt_regs *regs,
+					 unsigned int i, unsigned int n,
+					 const unsigned long *args)
+{
+	BUG_ON(i + n > 6);
+	memcpy(&regs->bx + i, args, n * sizeof(args[0]));
+}
+
+#else	 /* CONFIG_X86_64 */
+
+static inline void syscall_get_arguments(struct task_struct *task,
+					 struct pt_regs *regs,
+					 unsigned int i, unsigned int n,
+					 unsigned long *args)
+{
+# ifdef CONFIG_IA32_EMULATION
+	if (task_thread_info(task)->status & TS_COMPAT)
+		switch (i + n) {
+		case 6:
+			if (!n--) break;
+			*args++ = regs->bp;
+		case 5:
+			if (!n--) break;
+			*args++ = regs->di;
+		case 4:
+			if (!n--) break;
+			*args++ = regs->si;
+		case 3:
+			if (!n--) break;
+			*args++ = regs->dx;
+		case 2:
+			if (!n--) break;
+			*args++ = regs->cx;
+		case 1:
+			if (!n--) break;
+			*args++ = regs->bx;
+		case 0:
+			if (!n--) break;
+		default:
+			BUG();
+			break;
+		}
+	else
+# endif
+		switch (i + n) {
+		case 6:
+			if (!n--) break;
+			*args++ = regs->r9;
+		case 5:
+			if (!n--) break;
+			*args++ = regs->r8;
+		case 4:
+			if (!n--) break;
+			*args++ = regs->r10;
+		case 3:
+			if (!n--) break;
+			*args++ = regs->dx;
+		case 2:
+			if (!n--) break;
+			*args++ = regs->si;
+		case 1:
+			if (!n--) break;
+			*args++ = regs->di;
+		case 0:
+			if (!n--) break;
+		default:
+			BUG();
+			break;
+		}
+}
+
+static inline void syscall_set_arguments(struct task_struct *task,
+					 struct pt_regs *regs,
+					 unsigned int i, unsigned int n,
+					 const unsigned long *args)
+{
+# ifdef CONFIG_IA32_EMULATION
+	if (task_thread_info(task)->status & TS_COMPAT)
+		switch (i + n) {
+		case 6:
+			if (!n--) break;
+			regs->bp = *args++;
+		case 5:
+			if (!n--) break;
+			regs->di = *args++;
+		case 4:
+			if (!n--) break;
+			regs->si = *args++;
+		case 3:
+			if (!n--) break;
+			regs->dx = *args++;
+		case 2:
+			if (!n--) break;
+			regs->cx = *args++;
+		case 1:
+			if (!n--) break;
+			regs->bx = *args++;
+		case 0:
+			if (!n--) break;
+		default:
+			BUG();
+		}
+	else
+# endif
+		switch (i + n) {
+		case 6:
+			if (!n--) break;
+			regs->r9 = *args++;
+		case 5:
+			if (!n--) break;
+			regs->r8 = *args++;
+		case 4:
+			if (!n--) break;
+			regs->r10 = *args++;
+		case 3:
+			if (!n--) break;
+			regs->dx = *args++;
+		case 2:
+			if (!n--) break;
+			regs->si = *args++;
+		case 1:
+			if (!n--) break;
+			regs->di = *args++;
+		case 0:
+			if (!n--) break;
+		default:
+			BUG();
+		}
+}
+
+#endif	/* CONFIG_X86_32 */
+
+#endif	/* _ASM_SYSCALL_H */
diff --git a/include/asm-x86/syscalls.h b/include/asm-x86/syscalls.h
new file mode 100644
index 0000000..87803da
--- /dev/null
+++ b/include/asm-x86/syscalls.h
@@ -0,0 +1,93 @@
+/*
+ * syscalls.h - Linux syscall interfaces (arch-specific)
+ *
+ * Copyright (c) 2008 Jaswinder Singh
+ *
+ * This file is released under the GPLv2.
+ * See the file COPYING for more details.
+ */
+
+#ifndef _ASM_X86_SYSCALLS_H
+#define _ASM_X86_SYSCALLS_H
+
+#include <linux/compiler.h>
+#include <linux/linkage.h>
+#include <linux/types.h>
+#include <linux/signal.h>
+
+/* Common in X86_32 and X86_64 */
+/* kernel/ioport.c */
+asmlinkage long sys_ioperm(unsigned long, unsigned long, int);
+
+/* X86_32 only */
+#ifdef CONFIG_X86_32
+/* kernel/process_32.c */
+asmlinkage int sys_fork(struct pt_regs);
+asmlinkage int sys_clone(struct pt_regs);
+asmlinkage int sys_vfork(struct pt_regs);
+asmlinkage int sys_execve(struct pt_regs);
+
+/* kernel/signal_32.c */
+asmlinkage int sys_sigsuspend(int, int, old_sigset_t);
+asmlinkage int sys_sigaction(int, const struct old_sigaction __user *,
+			     struct old_sigaction __user *);
+asmlinkage int sys_sigaltstack(unsigned long);
+asmlinkage unsigned long sys_sigreturn(unsigned long);
+asmlinkage int sys_rt_sigreturn(unsigned long);
+
+/* kernel/ioport.c */
+asmlinkage long sys_iopl(unsigned long);
+
+/* kernel/ldt.c */
+asmlinkage int sys_modify_ldt(int, void __user *, unsigned long);
+
+/* kernel/sys_i386_32.c */
+asmlinkage long sys_mmap2(unsigned long, unsigned long, unsigned long,
+			  unsigned long, unsigned long, unsigned long);
+struct mmap_arg_struct;
+asmlinkage int old_mmap(struct mmap_arg_struct __user *);
+struct sel_arg_struct;
+asmlinkage int old_select(struct sel_arg_struct __user *);
+asmlinkage int sys_ipc(uint, int, int, int, void __user *, long);
+struct old_utsname;
+asmlinkage int sys_uname(struct old_utsname __user *);
+struct oldold_utsname;
+asmlinkage int sys_olduname(struct oldold_utsname __user *);
+
+/* kernel/tls.c */
+asmlinkage int sys_set_thread_area(struct user_desc __user *);
+asmlinkage int sys_get_thread_area(struct user_desc __user *);
+
+/* kernel/vm86_32.c */
+asmlinkage int sys_vm86old(struct pt_regs);
+asmlinkage int sys_vm86(struct pt_regs);
+
+#else /* CONFIG_X86_32 */
+
+/* X86_64 only */
+/* kernel/process_64.c */
+asmlinkage long sys_fork(struct pt_regs *);
+asmlinkage long sys_clone(unsigned long, unsigned long,
+			  void __user *, void __user *,
+			  struct pt_regs *);
+asmlinkage long sys_vfork(struct pt_regs *);
+asmlinkage long sys_execve(char __user *, char __user * __user *,
+			   char __user * __user *,
+			   struct pt_regs *);
+
+/* kernel/ioport.c */
+asmlinkage long sys_iopl(unsigned int, struct pt_regs *);
+
+/* kernel/signal_64.c */
+asmlinkage long sys_sigaltstack(const stack_t __user *, stack_t __user *,
+				struct pt_regs *);
+asmlinkage long sys_rt_sigreturn(struct pt_regs *);
+
+/* kernel/sys_x86_64.c */
+asmlinkage long sys_mmap(unsigned long, unsigned long, unsigned long,
+			 unsigned long, unsigned long, unsigned long);
+struct new_utsname;
+asmlinkage long sys_uname(struct new_utsname __user *);
+
+#endif /* CONFIG_X86_32 */
+#endif /* _ASM_X86_SYSCALLS_H */
diff --git a/include/asm-x86/system.h b/include/asm-x86/system.h
index 983ce37..b20c894 100644
--- a/include/asm-x86/system.h
+++ b/include/asm-x86/system.h
@@ -1,5 +1,5 @@
-#ifndef _ASM_X86_SYSTEM_H_
-#define _ASM_X86_SYSTEM_H_
+#ifndef ASM_X86__SYSTEM_H
+#define ASM_X86__SYSTEM_H
 
 #include <asm/asm.h>
 #include <asm/segment.h>
@@ -64,7 +64,10 @@
 		       							\
 		       /* regparm parameters for __switch_to(): */	\
 		       [prev]     "a" (prev),				\
-		       [next]     "d" (next));				\
+		       [next]     "d" (next)				\
+									\
+		     : /* reloaded segment registers */			\
+			"memory");					\
 } while (0)
 
 /*
@@ -419,4 +422,4 @@
 	alternative(ASM_NOP3, "lfence", X86_FEATURE_LFENCE_RDTSC);
 }
 
-#endif
+#endif /* ASM_X86__SYSTEM_H */
diff --git a/include/asm-x86/system_64.h b/include/asm-x86/system_64.h
index 97fa251..5aedb8b 100644
--- a/include/asm-x86/system_64.h
+++ b/include/asm-x86/system_64.h
@@ -1,5 +1,5 @@
-#ifndef __ASM_SYSTEM_H
-#define __ASM_SYSTEM_H
+#ifndef ASM_X86__SYSTEM_64_H
+#define ASM_X86__SYSTEM_64_H
 
 #include <asm/segment.h>
 #include <asm/cmpxchg.h>
@@ -19,4 +19,4 @@
 
 #include <linux/irqflags.h>
 
-#endif
+#endif /* ASM_X86__SYSTEM_64_H */
diff --git a/include/asm-x86/tce.h b/include/asm-x86/tce.h
index b1a4ea0..e7932d7 100644
--- a/include/asm-x86/tce.h
+++ b/include/asm-x86/tce.h
@@ -21,8 +21,8 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  */
 
-#ifndef _ASM_X86_64_TCE_H
-#define _ASM_X86_64_TCE_H
+#ifndef ASM_X86__TCE_H
+#define ASM_X86__TCE_H
 
 extern unsigned int specified_table_size;
 struct iommu_table;
@@ -45,4 +45,4 @@
 extern void __init free_tce_table(void *tbl);
 extern int __init build_tce_table(struct pci_dev *dev, void __iomem *bbar);
 
-#endif /* _ASM_X86_64_TCE_H */
+#endif /* ASM_X86__TCE_H */
diff --git a/include/asm-x86/termbits.h b/include/asm-x86/termbits.h
index af1b70e..3d00dc5 100644
--- a/include/asm-x86/termbits.h
+++ b/include/asm-x86/termbits.h
@@ -1,5 +1,5 @@
-#ifndef _ASM_X86_TERMBITS_H
-#define _ASM_X86_TERMBITS_H
+#ifndef ASM_X86__TERMBITS_H
+#define ASM_X86__TERMBITS_H
 
 #include <linux/posix_types.h>
 
@@ -195,4 +195,4 @@
 #define	TCSADRAIN	1
 #define	TCSAFLUSH	2
 
-#endif /* _ASM_X86_TERMBITS_H */
+#endif /* ASM_X86__TERMBITS_H */
diff --git a/include/asm-x86/termios.h b/include/asm-x86/termios.h
index f729563..e235db2 100644
--- a/include/asm-x86/termios.h
+++ b/include/asm-x86/termios.h
@@ -1,5 +1,5 @@
-#ifndef _ASM_X86_TERMIOS_H
-#define _ASM_X86_TERMIOS_H
+#ifndef ASM_X86__TERMIOS_H
+#define ASM_X86__TERMIOS_H
 
 #include <asm/termbits.h>
 #include <asm/ioctls.h>
@@ -110,4 +110,4 @@
 
 #endif	/* __KERNEL__ */
 
-#endif /* _ASM_X86_TERMIOS_H */
+#endif /* ASM_X86__TERMIOS_H */
diff --git a/include/asm-x86/therm_throt.h b/include/asm-x86/therm_throt.h
index 399bf60..1c7f57b 100644
--- a/include/asm-x86/therm_throt.h
+++ b/include/asm-x86/therm_throt.h
@@ -1,9 +1,9 @@
-#ifndef __ASM_I386_THERM_THROT_H__
-#define __ASM_I386_THERM_THROT_H__ 1
+#ifndef ASM_X86__THERM_THROT_H
+#define ASM_X86__THERM_THROT_H
 
 #include <asm/atomic.h>
 
 extern atomic_t therm_throt_en;
 int therm_throt_process(int curr);
 
-#endif /* __ASM_I386_THERM_THROT_H__ */
+#endif /* ASM_X86__THERM_THROT_H */
diff --git a/include/asm-x86/thread_info.h b/include/asm-x86/thread_info.h
index da0a675..3f4e52b 100644
--- a/include/asm-x86/thread_info.h
+++ b/include/asm-x86/thread_info.h
@@ -4,8 +4,8 @@
  * - Incorporating suggestions made by Linus Torvalds and Dave Miller
  */
 
-#ifndef _ASM_X86_THREAD_INFO_H
-#define _ASM_X86_THREAD_INFO_H
+#ifndef ASM_X86__THREAD_INFO_H
+#define ASM_X86__THREAD_INFO_H
 
 #include <linux/compiler.h>
 #include <asm/page.h>
@@ -71,6 +71,7 @@
  * Warning: layout of LSW is hardcoded in entry.S
  */
 #define TIF_SYSCALL_TRACE	0	/* syscall trace active */
+#define TIF_NOTIFY_RESUME	1	/* callback before returning to user */
 #define TIF_SIGPENDING		2	/* signal pending */
 #define TIF_NEED_RESCHED	3	/* rescheduling necessary */
 #define TIF_SINGLESTEP		4	/* reenable singlestep on user return*/
@@ -93,6 +94,7 @@
 #define TIF_BTS_TRACE_TS	27      /* record scheduling event timestamps */
 
 #define _TIF_SYSCALL_TRACE	(1 << TIF_SYSCALL_TRACE)
+#define _TIF_NOTIFY_RESUME	(1 << TIF_NOTIFY_RESUME)
 #define _TIF_SIGPENDING		(1 << TIF_SIGPENDING)
 #define _TIF_SINGLESTEP		(1 << TIF_SINGLESTEP)
 #define _TIF_NEED_RESCHED	(1 << TIF_NEED_RESCHED)
@@ -133,7 +135,7 @@
 
 /* Only used for 64 bit */
 #define _TIF_DO_NOTIFY_MASK						\
-	(_TIF_SIGPENDING|_TIF_MCE_NOTIFY)
+	(_TIF_SIGPENDING|_TIF_MCE_NOTIFY|_TIF_NOTIFY_RESUME)
 
 /* flags to check in __switch_to() */
 #define _TIF_WORK_CTXSW							\
@@ -239,6 +241,7 @@
 #define TS_POLLING		0x0004	/* true if in idle loop
 					   and not sleeping */
 #define TS_RESTORE_SIGMASK	0x0008	/* restore signal mask in do_signal() */
+#define TS_XSAVE		0x0010	/* Use xsave/xrstor */
 
 #define tsk_is_polling(t) (task_thread_info(t)->status & TS_POLLING)
 
@@ -258,4 +261,4 @@
 extern int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src);
 #define arch_task_cache_init arch_task_cache_init
 #endif
-#endif /* _ASM_X86_THREAD_INFO_H */
+#endif /* ASM_X86__THREAD_INFO_H */
diff --git a/include/asm-x86/time.h b/include/asm-x86/time.h
index a17fa47..3e724ee 100644
--- a/include/asm-x86/time.h
+++ b/include/asm-x86/time.h
@@ -1,5 +1,5 @@
-#ifndef _ASMX86_TIME_H
-#define _ASMX86_TIME_H
+#ifndef ASM_X86__TIME_H
+#define ASM_X86__TIME_H
 
 extern void hpet_time_init(void);
 
@@ -46,6 +46,8 @@
 
 #endif
 
+extern void time_init(void);
+
 #ifdef CONFIG_PARAVIRT
 #include <asm/paravirt.h>
 #else /* !CONFIG_PARAVIRT */
@@ -58,4 +60,4 @@
 
 extern unsigned long __init calibrate_cpu(void);
 
-#endif
+#endif /* ASM_X86__TIME_H */
diff --git a/include/asm-x86/timer.h b/include/asm-x86/timer.h
index fb2a4dd..d0babce 100644
--- a/include/asm-x86/timer.h
+++ b/include/asm-x86/timer.h
@@ -1,5 +1,5 @@
-#ifndef _ASMi386_TIMER_H
-#define _ASMi386_TIMER_H
+#ifndef ASM_X86__TIMER_H
+#define ASM_X86__TIMER_H
 #include <linux/init.h>
 #include <linux/pm.h>
 #include <linux/percpu.h>
@@ -9,9 +9,12 @@
 unsigned long long native_sched_clock(void);
 unsigned long native_calibrate_tsc(void);
 
+#ifdef CONFIG_X86_32
 extern int timer_ack;
-extern int no_timer_check;
 extern int recalibrate_cpu_khz(void);
+#endif /* CONFIG_X86_32 */
+
+extern int no_timer_check;
 
 #ifndef CONFIG_PARAVIRT
 #define calibrate_tsc() native_calibrate_tsc()
@@ -60,4 +63,4 @@
 	return ns;
 }
 
-#endif
+#endif /* ASM_X86__TIMER_H */
diff --git a/include/asm-x86/timex.h b/include/asm-x86/timex.h
index 43e5a78..d1ce241 100644
--- a/include/asm-x86/timex.h
+++ b/include/asm-x86/timex.h
@@ -1,6 +1,6 @@
 /* x86 architecture timex specifications */
-#ifndef _ASM_X86_TIMEX_H
-#define _ASM_X86_TIMEX_H
+#ifndef ASM_X86__TIMEX_H
+#define ASM_X86__TIMEX_H
 
 #include <asm/processor.h>
 #include <asm/tsc.h>
@@ -16,4 +16,4 @@
 
 #define ARCH_HAS_READ_CURRENT_TIMER
 
-#endif
+#endif /* ASM_X86__TIMEX_H */
diff --git a/include/asm-x86/tlb.h b/include/asm-x86/tlb.h
index e4e9e2d..db36e9e 100644
--- a/include/asm-x86/tlb.h
+++ b/include/asm-x86/tlb.h
@@ -1,5 +1,5 @@
-#ifndef _ASM_X86_TLB_H
-#define _ASM_X86_TLB_H
+#ifndef ASM_X86__TLB_H
+#define ASM_X86__TLB_H
 
 #define tlb_start_vma(tlb, vma) do { } while (0)
 #define tlb_end_vma(tlb, vma) do { } while (0)
@@ -8,4 +8,4 @@
 
 #include <asm-generic/tlb.h>
 
-#endif
+#endif /* ASM_X86__TLB_H */
diff --git a/include/asm-x86/tlbflush.h b/include/asm-x86/tlbflush.h
index 35c76ce..3cdd08b 100644
--- a/include/asm-x86/tlbflush.h
+++ b/include/asm-x86/tlbflush.h
@@ -1,5 +1,5 @@
-#ifndef _ASM_X86_TLBFLUSH_H
-#define _ASM_X86_TLBFLUSH_H
+#ifndef ASM_X86__TLBFLUSH_H
+#define ASM_X86__TLBFLUSH_H
 
 #include <linux/mm.h>
 #include <linux/sched.h>
@@ -119,6 +119,10 @@
 {
 }
 
+static inline void reset_lazy_tlbstate(void)
+{
+}
+
 #else  /* SMP */
 
 #include <asm/smp.h>
@@ -151,6 +155,12 @@
 	char __cacheline_padding[L1_CACHE_BYTES-8];
 };
 DECLARE_PER_CPU(struct tlb_state, cpu_tlbstate);
+
+void reset_lazy_tlbstate(void);
+#else
+static inline void reset_lazy_tlbstate(void)
+{
+}
 #endif
 
 #endif	/* SMP */
@@ -165,4 +175,4 @@
 	flush_tlb_all();
 }
 
-#endif /* _ASM_X86_TLBFLUSH_H */
+#endif /* ASM_X86__TLBFLUSH_H */
diff --git a/include/asm-x86/topology.h b/include/asm-x86/topology.h
index 90ac771..7eca9bc 100644
--- a/include/asm-x86/topology.h
+++ b/include/asm-x86/topology.h
@@ -22,8 +22,8 @@
  *
  * Send feedback to <colpatch@us.ibm.com>
  */
-#ifndef _ASM_X86_TOPOLOGY_H
-#define _ASM_X86_TOPOLOGY_H
+#ifndef ASM_X86__TOPOLOGY_H
+#define ASM_X86__TOPOLOGY_H
 
 #ifdef CONFIG_X86_32
 # ifdef CONFIG_X86_HT
@@ -255,4 +255,4 @@
 }
 #endif
 
-#endif /* _ASM_X86_TOPOLOGY_H */
+#endif /* ASM_X86__TOPOLOGY_H */
diff --git a/include/asm-x86/trampoline.h b/include/asm-x86/trampoline.h
index b156b08..0406bbd 100644
--- a/include/asm-x86/trampoline.h
+++ b/include/asm-x86/trampoline.h
@@ -1,5 +1,5 @@
-#ifndef __TRAMPOLINE_HEADER
-#define __TRAMPOLINE_HEADER
+#ifndef ASM_X86__TRAMPOLINE_H
+#define ASM_X86__TRAMPOLINE_H
 
 #ifndef __ASSEMBLY__
 
@@ -18,4 +18,4 @@
 
 #endif /* __ASSEMBLY__ */
 
-#endif /* __TRAMPOLINE_HEADER */
+#endif /* ASM_X86__TRAMPOLINE_H */
diff --git a/include/asm-x86/traps.h b/include/asm-x86/traps.h
index a4b65a7..6c3dc2c 100644
--- a/include/asm-x86/traps.h
+++ b/include/asm-x86/traps.h
@@ -1,7 +1,14 @@
-#ifndef _ASM_X86_TRAPS_H
-#define _ASM_X86_TRAPS_H
+#ifndef ASM_X86__TRAPS_H
+#define ASM_X86__TRAPS_H
 
-/* Common in X86_32 and X86_64 */
+#include <asm/debugreg.h>
+
+#ifdef CONFIG_X86_32
+#define dotraplinkage
+#else
+#define dotraplinkage asmlinkage
+#endif
+
 asmlinkage void divide_error(void);
 asmlinkage void debug(void);
 asmlinkage void nmi(void);
@@ -10,57 +17,65 @@
 asmlinkage void bounds(void);
 asmlinkage void invalid_op(void);
 asmlinkage void device_not_available(void);
+#ifdef CONFIG_X86_64
+asmlinkage void double_fault(void);
+#endif
 asmlinkage void coprocessor_segment_overrun(void);
 asmlinkage void invalid_TSS(void);
 asmlinkage void segment_not_present(void);
 asmlinkage void stack_segment(void);
 asmlinkage void general_protection(void);
 asmlinkage void page_fault(void);
-asmlinkage void coprocessor_error(void);
-asmlinkage void simd_coprocessor_error(void);
-asmlinkage void alignment_check(void);
 asmlinkage void spurious_interrupt_bug(void);
+asmlinkage void coprocessor_error(void);
+asmlinkage void alignment_check(void);
 #ifdef CONFIG_X86_MCE
 asmlinkage void machine_check(void);
 #endif /* CONFIG_X86_MCE */
+asmlinkage void simd_coprocessor_error(void);
 
-void do_divide_error(struct pt_regs *, long);
-void do_overflow(struct pt_regs *, long);
-void do_bounds(struct pt_regs *, long);
-void do_coprocessor_segment_overrun(struct pt_regs *, long);
-void do_invalid_TSS(struct pt_regs *, long);
-void do_segment_not_present(struct pt_regs *, long);
-void do_stack_segment(struct pt_regs *, long);
-void do_alignment_check(struct pt_regs *, long);
-void do_invalid_op(struct pt_regs *, long);
-void do_general_protection(struct pt_regs *, long);
-void do_nmi(struct pt_regs *, long);
+dotraplinkage void do_divide_error(struct pt_regs *, long);
+dotraplinkage void do_debug(struct pt_regs *, long);
+dotraplinkage void do_nmi(struct pt_regs *, long);
+dotraplinkage void do_int3(struct pt_regs *, long);
+dotraplinkage void do_overflow(struct pt_regs *, long);
+dotraplinkage void do_bounds(struct pt_regs *, long);
+dotraplinkage void do_invalid_op(struct pt_regs *, long);
+dotraplinkage void do_device_not_available(struct pt_regs *, long);
+dotraplinkage void do_coprocessor_segment_overrun(struct pt_regs *, long);
+dotraplinkage void do_invalid_TSS(struct pt_regs *, long);
+dotraplinkage void do_segment_not_present(struct pt_regs *, long);
+dotraplinkage void do_stack_segment(struct pt_regs *, long);
+dotraplinkage void do_general_protection(struct pt_regs *, long);
+dotraplinkage void do_page_fault(struct pt_regs *, unsigned long);
+dotraplinkage void do_spurious_interrupt_bug(struct pt_regs *, long);
+dotraplinkage void do_coprocessor_error(struct pt_regs *, long);
+dotraplinkage void do_alignment_check(struct pt_regs *, long);
+#ifdef CONFIG_X86_MCE
+dotraplinkage void do_machine_check(struct pt_regs *, long);
+#endif
+dotraplinkage void do_simd_coprocessor_error(struct pt_regs *, long);
+#ifdef CONFIG_X86_32
+dotraplinkage void do_iret_error(struct pt_regs *, long);
+#endif
+
+static inline int get_si_code(unsigned long condition)
+{
+	if (condition & DR_STEP)
+		return TRAP_TRACE;
+	else if (condition & (DR_TRAP0|DR_TRAP1|DR_TRAP2|DR_TRAP3))
+		return TRAP_HWBKPT;
+	else
+		return TRAP_BRKPT;
+}
 
 extern int panic_on_unrecovered_nmi;
 extern int kstack_depth_to_print;
 
 #ifdef CONFIG_X86_32
-
-void do_iret_error(struct pt_regs *, long);
-void do_int3(struct pt_regs *, long);
-void do_debug(struct pt_regs *, long);
 void math_error(void __user *);
-void do_coprocessor_error(struct pt_regs *, long);
-void do_simd_coprocessor_error(struct pt_regs *, long);
-void do_spurious_interrupt_bug(struct pt_regs *, long);
 unsigned long patch_espfix_desc(unsigned long, unsigned long);
 asmlinkage void math_emulate(long);
+#endif
 
-#else /* CONFIG_X86_32 */
-
-asmlinkage void double_fault(void);
-
-asmlinkage void do_int3(struct pt_regs *, long);
-asmlinkage void do_stack_segment(struct pt_regs *, long);
-asmlinkage void do_debug(struct pt_regs *, unsigned long);
-asmlinkage void do_coprocessor_error(struct pt_regs *);
-asmlinkage void do_simd_coprocessor_error(struct pt_regs *);
-asmlinkage void do_spurious_interrupt_bug(struct pt_regs *);
-
-#endif /* CONFIG_X86_32 */
-#endif /* _ASM_X86_TRAPS_H */
+#endif /* ASM_X86__TRAPS_H */
diff --git a/include/asm-x86/tsc.h b/include/asm-x86/tsc.h
index cb6f6ee..ad0f5c4 100644
--- a/include/asm-x86/tsc.h
+++ b/include/asm-x86/tsc.h
@@ -1,8 +1,8 @@
 /*
  * x86 TSC related functions
  */
-#ifndef _ASM_X86_TSC_H
-#define _ASM_X86_TSC_H
+#ifndef ASM_X86__TSC_H
+#define ASM_X86__TSC_H
 
 #include <asm/processor.h>
 
@@ -59,4 +59,4 @@
 
 extern int notsc_setup(char *);
 
-#endif
+#endif /* ASM_X86__TSC_H */
diff --git a/include/asm-x86/types.h b/include/asm-x86/types.h
index 1ac80cd..e78b52e 100644
--- a/include/asm-x86/types.h
+++ b/include/asm-x86/types.h
@@ -1,5 +1,5 @@
-#ifndef _ASM_X86_TYPES_H
-#define _ASM_X86_TYPES_H
+#ifndef ASM_X86__TYPES_H
+#define ASM_X86__TYPES_H
 
 #include <asm-generic/int-ll64.h>
 
@@ -33,4 +33,4 @@
 #endif /* __ASSEMBLY__ */
 #endif /* __KERNEL__ */
 
-#endif
+#endif /* ASM_X86__TYPES_H */
diff --git a/include/asm-x86/uaccess.h b/include/asm-x86/uaccess.h
index 5f702d1..48ebc0a 100644
--- a/include/asm-x86/uaccess.h
+++ b/include/asm-x86/uaccess.h
@@ -1,5 +1,5 @@
-#ifndef _ASM_UACCES_H_
-#define _ASM_UACCES_H_
+#ifndef ASM_X86__UACCESS_H
+#define ASM_X86__UACCESS_H
 /*
  * User space memory access functions
  */
@@ -450,5 +450,5 @@
 # include "uaccess_64.h"
 #endif
 
-#endif
+#endif /* ASM_X86__UACCESS_H */
 
diff --git a/include/asm-x86/uaccess_32.h b/include/asm-x86/uaccess_32.h
index 6fdef39..6b5b57d 100644
--- a/include/asm-x86/uaccess_32.h
+++ b/include/asm-x86/uaccess_32.h
@@ -1,5 +1,5 @@
-#ifndef __i386_UACCESS_H
-#define __i386_UACCESS_H
+#ifndef ASM_X86__UACCESS_32_H
+#define ASM_X86__UACCESS_32_H
 
 /*
  * User space memory access functions
@@ -215,4 +215,4 @@
 unsigned long __must_check clear_user(void __user *mem, unsigned long len);
 unsigned long __must_check __clear_user(void __user *mem, unsigned long len);
 
-#endif /* __i386_UACCESS_H */
+#endif /* ASM_X86__UACCESS_32_H */
diff --git a/include/asm-x86/uaccess_64.h b/include/asm-x86/uaccess_64.h
index 515d4dc..c96c1f5 100644
--- a/include/asm-x86/uaccess_64.h
+++ b/include/asm-x86/uaccess_64.h
@@ -1,5 +1,5 @@
-#ifndef __X86_64_UACCESS_H
-#define __X86_64_UACCESS_H
+#ifndef ASM_X86__UACCESS_64_H
+#define ASM_X86__UACCESS_64_H
 
 /*
  * User space memory access functions
@@ -7,6 +7,7 @@
 #include <linux/compiler.h>
 #include <linux/errno.h>
 #include <linux/prefetch.h>
+#include <linux/lockdep.h>
 #include <asm/page.h>
 
 /*
@@ -198,4 +199,4 @@
 unsigned long
 copy_user_handle_tail(char *to, char *from, unsigned len, unsigned zerorest);
 
-#endif /* __X86_64_UACCESS_H */
+#endif /* ASM_X86__UACCESS_64_H */
diff --git a/include/asm-x86/ucontext.h b/include/asm-x86/ucontext.h
index 50a79f7..89eaa54 100644
--- a/include/asm-x86/ucontext.h
+++ b/include/asm-x86/ucontext.h
@@ -1,5 +1,11 @@
-#ifndef _ASM_X86_UCONTEXT_H
-#define _ASM_X86_UCONTEXT_H
+#ifndef ASM_X86__UCONTEXT_H
+#define ASM_X86__UCONTEXT_H
+
+#define UC_FP_XSTATE	0x1	/* indicates the presence of extended state
+				 * information in the memory layout pointed
+				 * by the fpstate pointer in the ucontext's
+				 * sigcontext struct (uc_mcontext).
+				 */
 
 struct ucontext {
 	unsigned long	  uc_flags;
@@ -9,4 +15,4 @@
 	sigset_t	  uc_sigmask;	/* mask last for extensibility */
 };
 
-#endif /* _ASM_X86_UCONTEXT_H */
+#endif /* ASM_X86__UCONTEXT_H */
diff --git a/include/asm-x86/unaligned.h b/include/asm-x86/unaligned.h
index a7bd416..59dcdec 100644
--- a/include/asm-x86/unaligned.h
+++ b/include/asm-x86/unaligned.h
@@ -1,5 +1,5 @@
-#ifndef _ASM_X86_UNALIGNED_H
-#define _ASM_X86_UNALIGNED_H
+#ifndef ASM_X86__UNALIGNED_H
+#define ASM_X86__UNALIGNED_H
 
 /*
  * The x86 can do unaligned accesses itself.
@@ -11,4 +11,4 @@
 #define get_unaligned __get_unaligned_le
 #define put_unaligned __put_unaligned_le
 
-#endif /* _ASM_X86_UNALIGNED_H */
+#endif /* ASM_X86__UNALIGNED_H */
diff --git a/include/asm-x86/unistd_32.h b/include/asm-x86/unistd_32.h
index d739467..017f4a8 100644
--- a/include/asm-x86/unistd_32.h
+++ b/include/asm-x86/unistd_32.h
@@ -1,5 +1,5 @@
-#ifndef _ASM_I386_UNISTD_H_
-#define _ASM_I386_UNISTD_H_
+#ifndef ASM_X86__UNISTD_32_H
+#define ASM_X86__UNISTD_32_H
 
 /*
  * This file contains the system call numbers.
@@ -376,4 +376,4 @@
 #endif
 
 #endif /* __KERNEL__ */
-#endif /* _ASM_I386_UNISTD_H_ */
+#endif /* ASM_X86__UNISTD_32_H */
diff --git a/include/asm-x86/unistd_64.h b/include/asm-x86/unistd_64.h
index 3a341d7..ace83f1 100644
--- a/include/asm-x86/unistd_64.h
+++ b/include/asm-x86/unistd_64.h
@@ -1,5 +1,5 @@
-#ifndef _ASM_X86_64_UNISTD_H_
-#define _ASM_X86_64_UNISTD_H_
+#ifndef ASM_X86__UNISTD_64_H
+#define ASM_X86__UNISTD_64_H
 
 #ifndef __SYSCALL
 #define __SYSCALL(a, b)
@@ -690,4 +690,4 @@
 #define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall")
 #endif	/* __KERNEL__ */
 
-#endif /* _ASM_X86_64_UNISTD_H_ */
+#endif /* ASM_X86__UNISTD_64_H */
diff --git a/include/asm-x86/unwind.h b/include/asm-x86/unwind.h
index 8b064bd..a215156 100644
--- a/include/asm-x86/unwind.h
+++ b/include/asm-x86/unwind.h
@@ -1,5 +1,5 @@
-#ifndef _ASM_X86_UNWIND_H
-#define _ASM_X86_UNWIND_H
+#ifndef ASM_X86__UNWIND_H
+#define ASM_X86__UNWIND_H
 
 #define UNW_PC(frame) ((void)(frame), 0UL)
 #define UNW_SP(frame) ((void)(frame), 0UL)
@@ -10,4 +10,4 @@
 	return 0;
 }
 
-#endif /* _ASM_X86_UNWIND_H */
+#endif /* ASM_X86__UNWIND_H */
diff --git a/include/asm-x86/user32.h b/include/asm-x86/user32.h
index a3d9100..aa66c18 100644
--- a/include/asm-x86/user32.h
+++ b/include/asm-x86/user32.h
@@ -1,5 +1,5 @@
-#ifndef USER32_H
-#define USER32_H 1
+#ifndef ASM_X86__USER32_H
+#define ASM_X86__USER32_H
 
 /* IA32 compatible user structures for ptrace.
  * These should be used for 32bit coredumps too. */
@@ -67,4 +67,4 @@
 };
 
 
-#endif
+#endif /* ASM_X86__USER32_H */
diff --git a/include/asm-x86/user_32.h b/include/asm-x86/user_32.h
index d6e51ed..e0fe2f5 100644
--- a/include/asm-x86/user_32.h
+++ b/include/asm-x86/user_32.h
@@ -1,5 +1,5 @@
-#ifndef _I386_USER_H
-#define _I386_USER_H
+#ifndef ASM_X86__USER_32_H
+#define ASM_X86__USER_32_H
 
 #include <asm/page.h>
 /* Core file format: The core file is written in such a way that gdb
@@ -128,4 +128,4 @@
 #define HOST_TEXT_START_ADDR (u.start_code)
 #define HOST_STACK_END_ADDR (u.start_stack + u.u_ssize * NBPG)
 
-#endif /* _I386_USER_H */
+#endif /* ASM_X86__USER_32_H */
diff --git a/include/asm-x86/user_64.h b/include/asm-x86/user_64.h
index 6037b63..38b5799 100644
--- a/include/asm-x86/user_64.h
+++ b/include/asm-x86/user_64.h
@@ -1,5 +1,5 @@
-#ifndef _X86_64_USER_H
-#define _X86_64_USER_H
+#ifndef ASM_X86__USER_64_H
+#define ASM_X86__USER_64_H
 
 #include <asm/types.h>
 #include <asm/page.h>
@@ -134,4 +134,4 @@
 #define HOST_TEXT_START_ADDR (u.start_code)
 #define HOST_STACK_END_ADDR (u.start_stack + u.u_ssize * NBPG)
 
-#endif /* _X86_64_USER_H */
+#endif /* ASM_X86__USER_64_H */
diff --git a/include/asm-x86/uv/bios.h b/include/asm-x86/uv/bios.h
index aa73362..7cd6d7e 100644
--- a/include/asm-x86/uv/bios.h
+++ b/include/asm-x86/uv/bios.h
@@ -1,5 +1,5 @@
-#ifndef _ASM_X86_BIOS_H
-#define _ASM_X86_BIOS_H
+#ifndef ASM_X86__UV__BIOS_H
+#define ASM_X86__UV__BIOS_H
 
 /*
  * BIOS layer definitions.
@@ -65,4 +65,4 @@
 		   unsigned long *drift_info);
 extern const char *x86_bios_strerror(long status);
 
-#endif /* _ASM_X86_BIOS_H */
+#endif /* ASM_X86__UV__BIOS_H */
diff --git a/include/asm-x86/uv/uv_bau.h b/include/asm-x86/uv/uv_bau.h
index 610b6b3..77153fb 100644
--- a/include/asm-x86/uv/uv_bau.h
+++ b/include/asm-x86/uv/uv_bau.h
@@ -8,8 +8,8 @@
  * Copyright (C) 2008 Silicon Graphics, Inc. All rights reserved.
  */
 
-#ifndef __ASM_X86_UV_BAU__
-#define __ASM_X86_UV_BAU__
+#ifndef ASM_X86__UV__UV_BAU_H
+#define ASM_X86__UV__UV_BAU_H
 
 #include <linux/bitmap.h>
 #define BITSPERBYTE 8
@@ -329,4 +329,4 @@
 extern void uv_bau_message_intr1(void);
 extern void uv_bau_timeout_intr1(void);
 
-#endif /* __ASM_X86_UV_BAU__ */
+#endif /* ASM_X86__UV__UV_BAU_H */
diff --git a/include/asm-x86/uv/uv_hub.h b/include/asm-x86/uv/uv_hub.h
index a4ef26e..bdb5b01 100644
--- a/include/asm-x86/uv/uv_hub.h
+++ b/include/asm-x86/uv/uv_hub.h
@@ -8,8 +8,8 @@
  * Copyright (C) 2007-2008 Silicon Graphics, Inc. All rights reserved.
  */
 
-#ifndef __ASM_X86_UV_HUB_H__
-#define __ASM_X86_UV_HUB_H__
+#ifndef ASM_X86__UV__UV_HUB_H
+#define ASM_X86__UV__UV_HUB_H
 
 #include <linux/numa.h>
 #include <linux/percpu.h>
@@ -350,5 +350,5 @@
 	return uv_possible_blades;
 }
 
-#endif /* __ASM_X86_UV_HUB__ */
+#endif /* ASM_X86__UV__UV_HUB_H */
 
diff --git a/include/asm-x86/uv/uv_mmrs.h b/include/asm-x86/uv/uv_mmrs.h
index 151fd7f..8b03d89 100644
--- a/include/asm-x86/uv/uv_mmrs.h
+++ b/include/asm-x86/uv/uv_mmrs.h
@@ -8,8 +8,8 @@
  * Copyright (C) 2007-2008 Silicon Graphics, Inc. All rights reserved.
  */
 
-#ifndef __ASM_X86_UV_MMRS__
-#define __ASM_X86_UV_MMRS__
+#ifndef ASM_X86__UV__UV_MMRS_H
+#define ASM_X86__UV__UV_MMRS_H
 
 #define UV_MMR_ENABLE		(1UL << 63)
 
@@ -1292,4 +1292,4 @@
 };
 
 
-#endif /* __ASM_X86_UV_MMRS__ */
+#endif /* ASM_X86__UV__UV_MMRS_H */
diff --git a/include/asm-x86/vdso.h b/include/asm-x86/vdso.h
index 8e18fb8..4ab3209 100644
--- a/include/asm-x86/vdso.h
+++ b/include/asm-x86/vdso.h
@@ -1,5 +1,5 @@
-#ifndef _ASM_X86_VDSO_H
-#define _ASM_X86_VDSO_H	1
+#ifndef ASM_X86__VDSO_H
+#define ASM_X86__VDSO_H
 
 #ifdef CONFIG_X86_64
 extern const char VDSO64_PRELINK[];
@@ -44,4 +44,4 @@
 extern const char vdso32_syscall_start, vdso32_syscall_end;
 extern const char vdso32_sysenter_start, vdso32_sysenter_end;
 
-#endif	/* asm-x86/vdso.h */
+#endif /* ASM_X86__VDSO_H */
diff --git a/include/asm-x86/vga.h b/include/asm-x86/vga.h
index 0ccf804..b9e493d 100644
--- a/include/asm-x86/vga.h
+++ b/include/asm-x86/vga.h
@@ -4,8 +4,8 @@
  *	(c) 1998 Martin Mares <mj@ucw.cz>
  */
 
-#ifndef _LINUX_ASM_VGA_H_
-#define _LINUX_ASM_VGA_H_
+#ifndef ASM_X86__VGA_H
+#define ASM_X86__VGA_H
 
 /*
  *	On the PC, we can just recalculate addresses and then
@@ -17,4 +17,4 @@
 #define vga_readb(x) (*(x))
 #define vga_writeb(x, y) (*(y) = (x))
 
-#endif
+#endif /* ASM_X86__VGA_H */
diff --git a/include/asm-x86/vgtod.h b/include/asm-x86/vgtod.h
index 3301f09..38fd133 100644
--- a/include/asm-x86/vgtod.h
+++ b/include/asm-x86/vgtod.h
@@ -1,5 +1,5 @@
-#ifndef _ASM_VGTOD_H
-#define _ASM_VGTOD_H 1
+#ifndef ASM_X86__VGTOD_H
+#define ASM_X86__VGTOD_H
 
 #include <asm/vsyscall.h>
 #include <linux/clocksource.h>
@@ -26,4 +26,4 @@
 __section_vsyscall_gtod_data;
 extern struct vsyscall_gtod_data vsyscall_gtod_data;
 
-#endif
+#endif /* ASM_X86__VGTOD_H */
diff --git a/include/asm-x86/visws/cobalt.h b/include/asm-x86/visws/cobalt.h
index 9952588..9627a8f 100644
--- a/include/asm-x86/visws/cobalt.h
+++ b/include/asm-x86/visws/cobalt.h
@@ -1,5 +1,5 @@
-#ifndef __I386_SGI_COBALT_H
-#define __I386_SGI_COBALT_H
+#ifndef ASM_X86__VISWS__COBALT_H
+#define ASM_X86__VISWS__COBALT_H
 
 #include <asm/fixmap.h>
 
@@ -122,4 +122,4 @@
 
 extern char visws_board_rev;
 
-#endif /* __I386_SGI_COBALT_H */
+#endif /* ASM_X86__VISWS__COBALT_H */
diff --git a/include/asm-x86/visws/lithium.h b/include/asm-x86/visws/lithium.h
index dfcd4f0..b36d3b3 100644
--- a/include/asm-x86/visws/lithium.h
+++ b/include/asm-x86/visws/lithium.h
@@ -1,5 +1,5 @@
-#ifndef __I386_SGI_LITHIUM_H
-#define __I386_SGI_LITHIUM_H
+#ifndef ASM_X86__VISWS__LITHIUM_H
+#define ASM_X86__VISWS__LITHIUM_H
 
 #include <asm/fixmap.h>
 
@@ -49,5 +49,5 @@
 	return *((volatile unsigned short *)(LI_PCIB_VADDR+reg));
 }
 
-#endif
+#endif /* ASM_X86__VISWS__LITHIUM_H */
 
diff --git a/include/asm-x86/visws/piix4.h b/include/asm-x86/visws/piix4.h
index 83ea4f4..61c9380 100644
--- a/include/asm-x86/visws/piix4.h
+++ b/include/asm-x86/visws/piix4.h
@@ -1,5 +1,5 @@
-#ifndef __I386_SGI_PIIX_H
-#define __I386_SGI_PIIX_H
+#ifndef ASM_X86__VISWS__PIIX4_H
+#define ASM_X86__VISWS__PIIX4_H
 
 /*
  * PIIX4 as used on SGI Visual Workstations
@@ -104,4 +104,4 @@
  */
 #define	PIIX_GPI_STPCLK		0x4	// STPCLK signal routed back in
 
-#endif
+#endif /* ASM_X86__VISWS__PIIX4_H */
diff --git a/include/asm-x86/vm86.h b/include/asm-x86/vm86.h
index 5ce3513..998bd18 100644
--- a/include/asm-x86/vm86.h
+++ b/include/asm-x86/vm86.h
@@ -1,5 +1,5 @@
-#ifndef _LINUX_VM86_H
-#define _LINUX_VM86_H
+#ifndef ASM_X86__VM86_H
+#define ASM_X86__VM86_H
 
 /*
  * I'm guessing at the VIF/VIP flag usage, but hope that this is how
@@ -205,4 +205,4 @@
 
 #endif /* __KERNEL__ */
 
-#endif
+#endif /* ASM_X86__VM86_H */
diff --git a/include/asm-x86/vmi_time.h b/include/asm-x86/vmi_time.h
index c3118c3..b2d39e6 100644
--- a/include/asm-x86/vmi_time.h
+++ b/include/asm-x86/vmi_time.h
@@ -22,8 +22,8 @@
  *
  */
 
-#ifndef __VMI_TIME_H
-#define __VMI_TIME_H
+#ifndef ASM_X86__VMI_TIME_H
+#define ASM_X86__VMI_TIME_H
 
 /*
  * Raw VMI call indices for timer functions
@@ -95,4 +95,4 @@
 
 #define CONFIG_VMI_ALARM_HZ	100
 
-#endif
+#endif /* ASM_X86__VMI_TIME_H */
diff --git a/include/asm-x86/vsyscall.h b/include/asm-x86/vsyscall.h
index 6b66ff9..dcd4682 100644
--- a/include/asm-x86/vsyscall.h
+++ b/include/asm-x86/vsyscall.h
@@ -1,5 +1,5 @@
-#ifndef _ASM_X86_64_VSYSCALL_H_
-#define _ASM_X86_64_VSYSCALL_H_
+#ifndef ASM_X86__VSYSCALL_H
+#define ASM_X86__VSYSCALL_H
 
 enum vsyscall_num {
 	__NR_vgettimeofday,
@@ -41,4 +41,4 @@
 
 #endif /* __KERNEL__ */
 
-#endif /* _ASM_X86_64_VSYSCALL_H_ */
+#endif /* ASM_X86__VSYSCALL_H */
diff --git a/include/asm-x86/xcr.h b/include/asm-x86/xcr.h
new file mode 100644
index 0000000..f2cba4e7
--- /dev/null
+++ b/include/asm-x86/xcr.h
@@ -0,0 +1,49 @@
+/* -*- linux-c -*- ------------------------------------------------------- *
+ *
+ *   Copyright 2008 rPath, Inc. - All Rights Reserved
+ *
+ *   This file is part of the Linux kernel, and is made available under
+ *   the terms of the GNU General Public License version 2 or (at your
+ *   option) any later version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * asm-x86/xcr.h
+ *
+ * Definitions for the eXtended Control Register instructions
+ */
+
+#ifndef _ASM_X86_XCR_H
+#define _ASM_X86_XCR_H
+
+#define XCR_XFEATURE_ENABLED_MASK	0x00000000
+
+#ifdef __KERNEL__
+# ifndef __ASSEMBLY__
+
+#include <linux/types.h>
+
+static inline u64 xgetbv(u32 index)
+{
+	u32 eax, edx;
+
+	asm volatile(".byte 0x0f,0x01,0xd0" /* xgetbv */
+		     : "=a" (eax), "=d" (edx)
+		     : "c" (index));
+	return eax + ((u64)edx << 32);
+}
+
+static inline void xsetbv(u32 index, u64 value)
+{
+	u32 eax = value;
+	u32 edx = value >> 32;
+
+	asm volatile(".byte 0x0f,0x01,0xd1" /* xsetbv */
+		     : : "a" (eax), "d" (edx), "c" (index));
+}
+
+# endif /* __ASSEMBLY__ */
+#endif /* __KERNEL__ */
+
+#endif /* _ASM_X86_XCR_H */
diff --git a/include/asm-x86/xen/events.h b/include/asm-x86/xen/events.h
index 8ded747..8151f5b 100644
--- a/include/asm-x86/xen/events.h
+++ b/include/asm-x86/xen/events.h
@@ -1,5 +1,5 @@
-#ifndef __XEN_EVENTS_H
-#define __XEN_EVENTS_H
+#ifndef ASM_X86__XEN__EVENTS_H
+#define ASM_X86__XEN__EVENTS_H
 
 enum ipi_vector {
 	XEN_RESCHEDULE_VECTOR,
@@ -21,4 +21,4 @@
 	do_IRQ(regs);
 }
 
-#endif /* __XEN_EVENTS_H */
+#endif /* ASM_X86__XEN__EVENTS_H */
diff --git a/include/asm-x86/xen/grant_table.h b/include/asm-x86/xen/grant_table.h
index 2444d45..c4baab4 100644
--- a/include/asm-x86/xen/grant_table.h
+++ b/include/asm-x86/xen/grant_table.h
@@ -1,7 +1,7 @@
-#ifndef __XEN_GRANT_TABLE_H
-#define __XEN_GRANT_TABLE_H
+#ifndef ASM_X86__XEN__GRANT_TABLE_H
+#define ASM_X86__XEN__GRANT_TABLE_H
 
 #define xen_alloc_vm_area(size)	alloc_vm_area(size)
 #define xen_free_vm_area(area)	free_vm_area(area)
 
-#endif /* __XEN_GRANT_TABLE_H */
+#endif /* ASM_X86__XEN__GRANT_TABLE_H */
diff --git a/include/asm-x86/xen/hypercall.h b/include/asm-x86/xen/hypercall.h
index 91cb7fd..44f4259 100644
--- a/include/asm-x86/xen/hypercall.h
+++ b/include/asm-x86/xen/hypercall.h
@@ -30,8 +30,8 @@
  * IN THE SOFTWARE.
  */
 
-#ifndef __HYPERCALL_H__
-#define __HYPERCALL_H__
+#ifndef ASM_X86__XEN__HYPERCALL_H
+#define ASM_X86__XEN__HYPERCALL_H
 
 #include <linux/errno.h>
 #include <linux/string.h>
@@ -524,4 +524,4 @@
 	mcl->args[1] = esp;
 }
 
-#endif /* __HYPERCALL_H__ */
+#endif /* ASM_X86__XEN__HYPERCALL_H */
diff --git a/include/asm-x86/xen/hypervisor.h b/include/asm-x86/xen/hypervisor.h
index 04ee061..445a247 100644
--- a/include/asm-x86/xen/hypervisor.h
+++ b/include/asm-x86/xen/hypervisor.h
@@ -30,8 +30,8 @@
  * IN THE SOFTWARE.
  */
 
-#ifndef __HYPERVISOR_H__
-#define __HYPERVISOR_H__
+#ifndef ASM_X86__XEN__HYPERVISOR_H
+#define ASM_X86__XEN__HYPERVISOR_H
 
 #include <linux/types.h>
 #include <linux/kernel.h>
@@ -54,7 +54,6 @@
 /* arch/i386/kernel/setup.c */
 extern struct shared_info *HYPERVISOR_shared_info;
 extern struct start_info *xen_start_info;
-#define is_initial_xendomain() (xen_start_info->flags & SIF_INITDOMAIN)
 
 /* arch/i386/mach-xen/evtchn.c */
 /* Force a proper event-channel callback from Xen. */
@@ -67,6 +66,17 @@
 #define MULTI_UVMFLAGS_INDEX 3
 #define MULTI_UVMDOMID_INDEX 4
 
-#define is_running_on_xen()	(xen_start_info ? 1 : 0)
+enum xen_domain_type {
+	XEN_NATIVE,
+	XEN_PV_DOMAIN,
+	XEN_HVM_DOMAIN,
+};
 
-#endif /* __HYPERVISOR_H__ */
+extern enum xen_domain_type xen_domain_type;
+
+#define xen_domain()		(xen_domain_type != XEN_NATIVE)
+#define xen_pv_domain()		(xen_domain_type == XEN_PV_DOMAIN)
+#define xen_initial_domain()	(xen_pv_domain() && xen_start_info->flags & SIF_INITDOMAIN)
+#define xen_hvm_domain()	(xen_domain_type == XEN_HVM_DOMAIN)
+
+#endif /* ASM_X86__XEN__HYPERVISOR_H */
diff --git a/include/asm-x86/xen/interface.h b/include/asm-x86/xen/interface.h
index 9d810f2..d077bba 100644
--- a/include/asm-x86/xen/interface.h
+++ b/include/asm-x86/xen/interface.h
@@ -6,8 +6,8 @@
  * Copyright (c) 2004, K A Fraser
  */
 
-#ifndef __ASM_X86_XEN_INTERFACE_H
-#define __ASM_X86_XEN_INTERFACE_H
+#ifndef ASM_X86__XEN__INTERFACE_H
+#define ASM_X86__XEN__INTERFACE_H
 
 #ifdef __XEN__
 #define __DEFINE_GUEST_HANDLE(name, type) \
@@ -172,4 +172,4 @@
 #define XEN_CPUID          XEN_EMULATE_PREFIX "cpuid"
 #endif
 
-#endif	/* __ASM_X86_XEN_INTERFACE_H */
+#endif /* ASM_X86__XEN__INTERFACE_H */
diff --git a/include/asm-x86/xen/interface_32.h b/include/asm-x86/xen/interface_32.h
index d8ac41d..08167e1 100644
--- a/include/asm-x86/xen/interface_32.h
+++ b/include/asm-x86/xen/interface_32.h
@@ -6,8 +6,8 @@
  * Copyright (c) 2004, K A Fraser
  */
 
-#ifndef __ASM_X86_XEN_INTERFACE_32_H
-#define __ASM_X86_XEN_INTERFACE_32_H
+#ifndef ASM_X86__XEN__INTERFACE_32_H
+#define ASM_X86__XEN__INTERFACE_32_H
 
 
 /*
@@ -94,4 +94,4 @@
 #define xen_pfn_to_cr3(pfn) (((unsigned)(pfn) << 12) | ((unsigned)(pfn) >> 20))
 #define xen_cr3_to_pfn(cr3) (((unsigned)(cr3) >> 12) | ((unsigned)(cr3) << 20))
 
-#endif	/* __ASM_X86_XEN_INTERFACE_32_H */
+#endif /* ASM_X86__XEN__INTERFACE_32_H */
diff --git a/include/asm-x86/xen/interface_64.h b/include/asm-x86/xen/interface_64.h
index 842266c..046c0f1 100644
--- a/include/asm-x86/xen/interface_64.h
+++ b/include/asm-x86/xen/interface_64.h
@@ -1,5 +1,5 @@
-#ifndef __ASM_X86_XEN_INTERFACE_64_H
-#define __ASM_X86_XEN_INTERFACE_64_H
+#ifndef ASM_X86__XEN__INTERFACE_64_H
+#define ASM_X86__XEN__INTERFACE_64_H
 
 /*
  * 64-bit segment selectors
@@ -156,4 +156,4 @@
 #endif /* !__ASSEMBLY__ */
 
 
-#endif	/* __ASM_X86_XEN_INTERFACE_64_H */
+#endif /* ASM_X86__XEN__INTERFACE_64_H */
diff --git a/include/asm-x86/xen/page.h b/include/asm-x86/xen/page.h
index 7b3835d..d5eada0 100644
--- a/include/asm-x86/xen/page.h
+++ b/include/asm-x86/xen/page.h
@@ -1,5 +1,5 @@
-#ifndef __XEN_PAGE_H
-#define __XEN_PAGE_H
+#ifndef ASM_X86__XEN__PAGE_H
+#define ASM_X86__XEN__PAGE_H
 
 #include <linux/pfn.h>
 
@@ -76,13 +76,13 @@
 static inline xmaddr_t phys_to_machine(xpaddr_t phys)
 {
 	unsigned offset = phys.paddr & ~PAGE_MASK;
-	return XMADDR(PFN_PHYS((u64)pfn_to_mfn(PFN_DOWN(phys.paddr))) | offset);
+	return XMADDR(PFN_PHYS(pfn_to_mfn(PFN_DOWN(phys.paddr))) | offset);
 }
 
 static inline xpaddr_t machine_to_phys(xmaddr_t machine)
 {
 	unsigned offset = machine.maddr & ~PAGE_MASK;
-	return XPADDR(PFN_PHYS((u64)mfn_to_pfn(PFN_DOWN(machine.maddr))) | offset);
+	return XPADDR(PFN_PHYS(mfn_to_pfn(PFN_DOWN(machine.maddr))) | offset);
 }
 
 /*
@@ -162,4 +162,4 @@
 void make_lowmem_page_readonly(void *vaddr);
 void make_lowmem_page_readwrite(void *vaddr);
 
-#endif /* __XEN_PAGE_H */
+#endif /* ASM_X86__XEN__PAGE_H */
diff --git a/include/asm-x86/xsave.h b/include/asm-x86/xsave.h
new file mode 100644
index 0000000..08e9a1a
--- /dev/null
+++ b/include/asm-x86/xsave.h
@@ -0,0 +1,118 @@
+#ifndef __ASM_X86_XSAVE_H
+#define __ASM_X86_XSAVE_H
+
+#include <linux/types.h>
+#include <asm/processor.h>
+#include <asm/i387.h>
+
+#define XSTATE_FP	0x1
+#define XSTATE_SSE	0x2
+
+#define XSTATE_FPSSE	(XSTATE_FP | XSTATE_SSE)
+
+#define FXSAVE_SIZE	512
+
+/*
+ * These are the features that the OS can handle currently.
+ */
+#define XCNTXT_MASK	(XSTATE_FP | XSTATE_SSE)
+
+#ifdef CONFIG_X86_64
+#define REX_PREFIX	"0x48, "
+#else
+#define REX_PREFIX
+#endif
+
+extern unsigned int xstate_size;
+extern u64 pcntxt_mask;
+extern struct xsave_struct *init_xstate_buf;
+
+extern void xsave_cntxt_init(void);
+extern void xsave_init(void);
+extern int init_fpu(struct task_struct *child);
+extern int check_for_xstate(struct i387_fxsave_struct __user *buf,
+			    void __user *fpstate,
+			    struct _fpx_sw_bytes *sw);
+
+static inline int xrstor_checking(struct xsave_struct *fx)
+{
+	int err;
+
+	asm volatile("1: .byte " REX_PREFIX "0x0f,0xae,0x2f\n\t"
+		     "2:\n"
+		     ".section .fixup,\"ax\"\n"
+		     "3:  movl $-1,%[err]\n"
+		     "    jmp  2b\n"
+		     ".previous\n"
+		     _ASM_EXTABLE(1b, 3b)
+		     : [err] "=r" (err)
+		     : "D" (fx), "m" (*fx), "a" (-1), "d" (-1), "0" (0)
+		     : "memory");
+
+	return err;
+}
+
+static inline int xsave_user(struct xsave_struct __user *buf)
+{
+	int err;
+	__asm__ __volatile__("1: .byte " REX_PREFIX "0x0f,0xae,0x27\n"
+			     "2:\n"
+			     ".section .fixup,\"ax\"\n"
+			     "3:  movl $-1,%[err]\n"
+			     "    jmp  2b\n"
+			     ".previous\n"
+			     ".section __ex_table,\"a\"\n"
+			     _ASM_ALIGN "\n"
+			     _ASM_PTR "1b,3b\n"
+			     ".previous"
+			     : [err] "=r" (err)
+			     : "D" (buf), "a" (-1), "d" (-1), "0" (0)
+			     : "memory");
+	if (unlikely(err) && __clear_user(buf, xstate_size))
+		err = -EFAULT;
+	/* No need to clear here because the caller clears USED_MATH */
+	return err;
+}
+
+static inline int xrestore_user(struct xsave_struct __user *buf, u64 mask)
+{
+	int err;
+	struct xsave_struct *xstate = ((__force struct xsave_struct *)buf);
+	u32 lmask = mask;
+	u32 hmask = mask >> 32;
+
+	__asm__ __volatile__("1: .byte " REX_PREFIX "0x0f,0xae,0x2f\n"
+			     "2:\n"
+			     ".section .fixup,\"ax\"\n"
+			     "3:  movl $-1,%[err]\n"
+			     "    jmp  2b\n"
+			     ".previous\n"
+			     ".section __ex_table,\"a\"\n"
+			     _ASM_ALIGN "\n"
+			     _ASM_PTR "1b,3b\n"
+			     ".previous"
+			     : [err] "=r" (err)
+			     : "D" (xstate), "a" (lmask), "d" (hmask), "0" (0)
+			     : "memory");	/* memory required? */
+	return err;
+}
+
+static inline void xrstor_state(struct xsave_struct *fx, u64 mask)
+{
+	u32 lmask = mask;
+	u32 hmask = mask >> 32;
+
+	asm volatile(".byte " REX_PREFIX "0x0f,0xae,0x2f\n\t"
+		     : : "D" (fx), "m" (*fx), "a" (lmask), "d" (hmask)
+		     :   "memory");
+}
+
+static inline void xsave(struct task_struct *tsk)
+{
+	/* This, however, we can work around by forcing the compiler to select
+	   an addressing mode that doesn't require extended registers. */
+	__asm__ __volatile__(".byte " REX_PREFIX "0x0f,0xae,0x27"
+			     : : "D" (&(tsk->thread.xstate->xsave)),
+				 "a" (-1), "d"(-1) : "memory");
+}
+#endif
diff --git a/include/asm-xtensa/a.out.h b/include/asm-xtensa/a.out.h
deleted file mode 100644
index fdf1370..0000000
--- a/include/asm-xtensa/a.out.h
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * include/asm-xtensa/a.out.h
- *
- * Dummy a.out file. Xtensa does not support the a.out format, but the kernel
- * seems to depend on it.
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 2001 - 2005 Tensilica Inc.
- */
-
-#ifndef _XTENSA_A_OUT_H
-#define _XTENSA_A_OUT_H
-
-struct exec
-{
-  unsigned long a_info;
-  unsigned a_text;
-  unsigned a_data;
-  unsigned a_bss;
-  unsigned a_syms;
-  unsigned a_entry;
-  unsigned a_trsize;
-  unsigned a_drsize;
-};
-
-#endif /* _XTENSA_A_OUT_H */
diff --git a/include/crypto/internal/rng.h b/include/crypto/internal/rng.h
new file mode 100644
index 0000000..8969733
--- /dev/null
+++ b/include/crypto/internal/rng.h
@@ -0,0 +1,26 @@
+/*
+ * RNG: Random Number Generator  algorithms under the crypto API
+ *
+ * Copyright (c) 2008 Neil Horman <nhorman@tuxdriver.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 _CRYPTO_INTERNAL_RNG_H
+#define _CRYPTO_INTERNAL_RNG_H
+
+#include <crypto/algapi.h>
+#include <crypto/rng.h>
+
+extern const struct crypto_type crypto_rng_type;
+
+static inline void *crypto_rng_ctx(struct crypto_rng *tfm)
+{
+	return crypto_tfm_ctx(&tfm->base);
+}
+
+#endif
diff --git a/include/crypto/internal/skcipher.h b/include/crypto/internal/skcipher.h
index ccc32ba..2ba42cd 100644
--- a/include/crypto/internal/skcipher.h
+++ b/include/crypto/internal/skcipher.h
@@ -15,7 +15,6 @@
 
 #include <crypto/algapi.h>
 #include <crypto/skcipher.h>
-#include <linux/init.h>
 #include <linux/types.h>
 
 struct rtattr;
@@ -65,11 +64,6 @@
 int skcipher_geniv_init(struct crypto_tfm *tfm);
 void skcipher_geniv_exit(struct crypto_tfm *tfm);
 
-int __init eseqiv_module_init(void);
-void __exit eseqiv_module_exit(void);
-int __init chainiv_module_init(void);
-void chainiv_module_exit(void);
-
 static inline struct crypto_ablkcipher *skcipher_geniv_cipher(
 	struct crypto_ablkcipher *geniv)
 {
diff --git a/include/crypto/rng.h b/include/crypto/rng.h
new file mode 100644
index 0000000..c93f9b9
--- /dev/null
+++ b/include/crypto/rng.h
@@ -0,0 +1,75 @@
+/*
+ * RNG: Random Number Generator  algorithms under the crypto API
+ *
+ * Copyright (c) 2008 Neil Horman <nhorman@tuxdriver.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 _CRYPTO_RNG_H
+#define _CRYPTO_RNG_H
+
+#include <linux/crypto.h>
+
+extern struct crypto_rng *crypto_default_rng;
+
+int crypto_get_default_rng(void);
+void crypto_put_default_rng(void);
+
+static inline struct crypto_rng *__crypto_rng_cast(struct crypto_tfm *tfm)
+{
+	return (struct crypto_rng *)tfm;
+}
+
+static inline struct crypto_rng *crypto_alloc_rng(const char *alg_name,
+						  u32 type, u32 mask)
+{
+	type &= ~CRYPTO_ALG_TYPE_MASK;
+	type |= CRYPTO_ALG_TYPE_RNG;
+	mask |= CRYPTO_ALG_TYPE_MASK;
+
+	return __crypto_rng_cast(crypto_alloc_base(alg_name, type, mask));
+}
+
+static inline struct crypto_tfm *crypto_rng_tfm(struct crypto_rng *tfm)
+{
+	return &tfm->base;
+}
+
+static inline struct rng_alg *crypto_rng_alg(struct crypto_rng *tfm)
+{
+	return &crypto_rng_tfm(tfm)->__crt_alg->cra_rng;
+}
+
+static inline struct rng_tfm *crypto_rng_crt(struct crypto_rng *tfm)
+{
+	return &crypto_rng_tfm(tfm)->crt_rng;
+}
+
+static inline void crypto_free_rng(struct crypto_rng *tfm)
+{
+	crypto_free_tfm(crypto_rng_tfm(tfm));
+}
+
+static inline int crypto_rng_get_bytes(struct crypto_rng *tfm,
+				       u8 *rdata, unsigned int dlen)
+{
+	return crypto_rng_crt(tfm)->rng_gen_random(tfm, rdata, dlen);
+}
+
+static inline int crypto_rng_reset(struct crypto_rng *tfm,
+				   u8 *seed, unsigned int slen)
+{
+	return crypto_rng_crt(tfm)->rng_reset(tfm, seed, slen);
+}
+
+static inline int crypto_rng_seedsize(struct crypto_rng *tfm)
+{
+	return crypto_rng_alg(tfm)->seedsize;
+}
+
+#endif
diff --git a/include/linux/Kbuild b/include/linux/Kbuild
index b68ec09..282a504 100644
--- a/include/linux/Kbuild
+++ b/include/linux/Kbuild
@@ -126,6 +126,7 @@
 header-y += pfkeyv2.h
 header-y += pg.h
 header-y += phantom.h
+header-y += phonet.h
 header-y += pkt_cls.h
 header-y += pkt_sched.h
 header-y += posix_types.h
@@ -180,6 +181,7 @@
 unifdef-y += auto_fs.h
 unifdef-y += auxvec.h
 unifdef-y += binfmts.h
+unifdef-y += blktrace_api.h
 unifdef-y += capability.h
 unifdef-y += capi.h
 unifdef-y += cciss_ioctl.h
@@ -232,6 +234,7 @@
 unifdef-y += if_frad.h
 unifdef-y += if_ltalk.h
 unifdef-y += if_link.h
+unifdef-y += if_phonet.h
 unifdef-y += if_pppol2tp.h
 unifdef-y += if_pppox.h
 unifdef-y += if_tr.h
diff --git a/include/linux/ata.h b/include/linux/ata.h
index 8a12d71..a53318b 100644
--- a/include/linux/ata.h
+++ b/include/linux/ata.h
@@ -30,6 +30,7 @@
 #define __LINUX_ATA_H__
 
 #include <linux/types.h>
+#include <asm/byteorder.h>
 
 /* defines only for the constants which don't work well as enums */
 #define ATA_DMA_BOUNDARY	0xffffUL
@@ -88,6 +89,7 @@
 	ATA_ID_DLF		= 128,
 	ATA_ID_CSFO		= 129,
 	ATA_ID_CFA_POWER	= 160,
+	ATA_ID_ROT_SPEED	= 217,
 	ATA_ID_PIO4		= (1 << 1),
 
 	ATA_ID_SERNO_LEN	= 20,
@@ -557,6 +559,15 @@
 	return id[ATA_ID_COMMAND_SET_2] & (1 << 12);
 }
 
+static inline int ata_id_flush_enabled(const u16 *id)
+{
+	if (ata_id_has_flush(id) == 0)
+		return 0;
+	if ((id[ATA_ID_CSF_DEFAULT] & 0xC000) != 0x4000)
+		return 0;
+	return id[ATA_ID_CFS_ENABLE_2] & (1 << 12);
+}
+
 static inline int ata_id_has_flush_ext(const u16 *id)
 {
 	if ((id[ATA_ID_COMMAND_SET_2] & 0xC000) != 0x4000)
@@ -564,6 +575,19 @@
 	return id[ATA_ID_COMMAND_SET_2] & (1 << 13);
 }
 
+static inline int ata_id_flush_ext_enabled(const u16 *id)
+{
+	if (ata_id_has_flush_ext(id) == 0)
+		return 0;
+	if ((id[ATA_ID_CSF_DEFAULT] & 0xC000) != 0x4000)
+		return 0;
+	/*
+	 * some Maxtor disks have bit 13 defined incorrectly
+	 * so check bit 10 too
+	 */
+	return (id[ATA_ID_CFS_ENABLE_2] & 0x2400) == 0x2400;
+}
+
 static inline int ata_id_has_lba48(const u16 *id)
 {
 	if ((id[ATA_ID_COMMAND_SET_2] & 0xC000) != 0x4000)
@@ -573,6 +597,15 @@
 	return id[ATA_ID_COMMAND_SET_2] & (1 << 10);
 }
 
+static inline int ata_id_lba48_enabled(const u16 *id)
+{
+	if (ata_id_has_lba48(id) == 0)
+		return 0;
+	if ((id[ATA_ID_CSF_DEFAULT] & 0xC000) != 0x4000)
+		return 0;
+	return id[ATA_ID_CFS_ENABLE_2] & (1 << 10);
+}
+
 static inline int ata_id_hpa_enabled(const u16 *id)
 {
 	/* Yes children, word 83 valid bits cover word 82 data */
@@ -644,7 +677,15 @@
 
 static inline int ata_id_is_sata(const u16 *id)
 {
-	return ata_id_major_version(id) >= 5 && id[ATA_ID_HW_CONFIG] == 0;
+	/*
+	 * See if word 93 is 0 AND drive is at least ATA-5 compatible
+	 * verifying that word 80 by casting it to a signed type --
+	 * this trick allows us to filter out the reserved values of
+	 * 0x0000 and 0xffff along with the earlier ATA revisions...
+	 */
+	if (id[ATA_ID_HW_CONFIG] == 0 && (short)id[ATA_ID_MAJOR_VER] >= 0x0020)
+		return 1;
+	return 0;
 }
 
 static inline int ata_id_has_tpm(const u16 *id)
@@ -667,6 +708,15 @@
 	return 0;
 }
 
+static inline int ata_id_has_unload(const u16 *id)
+{
+	if (ata_id_major_version(id) >= 7 &&
+	    (id[ATA_ID_CFSSE] & 0xC000) == 0x4000 &&
+	    id[ATA_ID_CFSSE] & (1 << 13))
+		return 1;
+	return 0;
+}
+
 static inline int ata_id_current_chs_valid(const u16 *id)
 {
 	/* For ATA-1 devices, if the INITIALIZE DEVICE PARAMETERS command
@@ -691,6 +741,11 @@
 	return 0;
 }
 
+static inline int ata_id_is_ssd(const u16 *id)
+{
+	return id[ATA_ID_ROT_SPEED] == 0x01;
+}
+
 static inline int ata_drive_40wire(const u16 *dev_id)
 {
 	if (ata_id_is_sata(dev_id))
@@ -727,6 +782,76 @@
 	return ata_id_major_version(dev_id) >= 7 && (dev_id[62] & 0x8000);
 }
 
+/*
+ * ata_id_is_lba_capacity_ok() performs a sanity check on
+ * the claimed LBA capacity value for the device.
+ *
+ * Returns 1 if LBA capacity looks sensible, 0 otherwise.
+ *
+ * It is called only once for each device.
+ */
+static inline int ata_id_is_lba_capacity_ok(u16 *id)
+{
+	unsigned long lba_sects, chs_sects, head, tail;
+
+	/* No non-LBA info .. so valid! */
+	if (id[ATA_ID_CYLS] == 0)
+		return 1;
+
+	lba_sects = ata_id_u32(id, ATA_ID_LBA_CAPACITY);
+
+	/*
+	 * The ATA spec tells large drives to return
+	 * C/H/S = 16383/16/63 independent of their size.
+	 * Some drives can be jumpered to use 15 heads instead of 16.
+	 * Some drives can be jumpered to use 4092 cyls instead of 16383.
+	 */
+	if ((id[ATA_ID_CYLS] == 16383 ||
+	     (id[ATA_ID_CYLS] == 4092 && id[ATA_ID_CUR_CYLS] == 16383)) &&
+	    id[ATA_ID_SECTORS] == 63 &&
+	    (id[ATA_ID_HEADS] == 15 || id[ATA_ID_HEADS] == 16) &&
+	    (lba_sects >= 16383 * 63 * id[ATA_ID_HEADS]))
+		return 1;
+
+	chs_sects = id[ATA_ID_CYLS] * id[ATA_ID_HEADS] * id[ATA_ID_SECTORS];
+
+	/* perform a rough sanity check on lba_sects: within 10% is OK */
+	if (lba_sects - chs_sects < chs_sects/10)
+		return 1;
+
+	/* some drives have the word order reversed */
+	head = (lba_sects >> 16) & 0xffff;
+	tail = lba_sects & 0xffff;
+	lba_sects = head | (tail << 16);
+
+	if (lba_sects - chs_sects < chs_sects/10) {
+		*(__le32 *)&id[ATA_ID_LBA_CAPACITY] = __cpu_to_le32(lba_sects);
+		return 1;	/* LBA capacity is (now) good */
+	}
+
+	return 0;	/* LBA capacity value may be bad */
+}
+
+static inline void ata_id_to_hd_driveid(u16 *id)
+{
+#ifdef __BIG_ENDIAN
+	/* accessed in struct hd_driveid as 8-bit values */
+	id[ATA_ID_MAX_MULTSECT]	 = __cpu_to_le16(id[ATA_ID_MAX_MULTSECT]);
+	id[ATA_ID_CAPABILITY]	 = __cpu_to_le16(id[ATA_ID_CAPABILITY]);
+	id[ATA_ID_OLD_PIO_MODES] = __cpu_to_le16(id[ATA_ID_OLD_PIO_MODES]);
+	id[ATA_ID_OLD_DMA_MODES] = __cpu_to_le16(id[ATA_ID_OLD_DMA_MODES]);
+	id[ATA_ID_MULTSECT]	 = __cpu_to_le16(id[ATA_ID_MULTSECT]);
+
+	/* as 32-bit values */
+	*(u32 *)&id[ATA_ID_LBA_CAPACITY] = ata_id_u32(id, ATA_ID_LBA_CAPACITY);
+	*(u32 *)&id[ATA_ID_SPG]		 = ata_id_u32(id, ATA_ID_SPG);
+
+	/* as 64-bit value */
+	*(u64 *)&id[ATA_ID_LBA_CAPACITY_2] =
+		ata_id_u64(id, ATA_ID_LBA_CAPACITY_2);
+#endif
+}
+
 static inline int is_multi_taskfile(struct ata_taskfile *tf)
 {
 	return (tf->command == ATA_CMD_READ_MULTI) ||
diff --git a/include/linux/bio.h b/include/linux/bio.h
index 0933a14..ff5b4cf 100644
--- a/include/linux/bio.h
+++ b/include/linux/bio.h
@@ -26,21 +26,8 @@
 
 #ifdef CONFIG_BLOCK
 
-/* Platforms may set this to teach the BIO layer about IOMMU hardware. */
 #include <asm/io.h>
 
-#if defined(BIO_VMERGE_MAX_SIZE) && defined(BIO_VMERGE_BOUNDARY)
-#define BIOVEC_VIRT_START_SIZE(x) (bvec_to_phys(x) & (BIO_VMERGE_BOUNDARY - 1))
-#define BIOVEC_VIRT_OVERSIZE(x)	((x) > BIO_VMERGE_MAX_SIZE)
-#else
-#define BIOVEC_VIRT_START_SIZE(x)	0
-#define BIOVEC_VIRT_OVERSIZE(x)		0
-#endif
-
-#ifndef BIO_VMERGE_BOUNDARY
-#define BIO_VMERGE_BOUNDARY	0
-#endif
-
 #define BIO_DEBUG
 
 #ifdef BIO_DEBUG
@@ -88,25 +75,14 @@
 	/* Number of segments in this BIO after
 	 * physical address coalescing is performed.
 	 */
-	unsigned short		bi_phys_segments;
-
-	/* Number of segments after physical and DMA remapping
-	 * hardware coalescing is performed.
-	 */
-	unsigned short		bi_hw_segments;
+	unsigned int		bi_phys_segments;
 
 	unsigned int		bi_size;	/* residual I/O count */
 
-	/*
-	 * To keep track of the max hw size, we account for the
-	 * sizes of the first and last virtually mergeable segments
-	 * in this bio
-	 */
-	unsigned int		bi_hw_front_size;
-	unsigned int		bi_hw_back_size;
-
 	unsigned int		bi_max_vecs;	/* max bvl_vecs we can hold */
 
+	unsigned int		bi_comp_cpu;	/* completion CPU */
+
 	struct bio_vec		*bi_io_vec;	/* the actual vec list */
 
 	bio_end_io_t		*bi_end_io;
@@ -126,11 +102,14 @@
 #define BIO_UPTODATE	0	/* ok after I/O completion */
 #define BIO_RW_BLOCK	1	/* RW_AHEAD set, and read/write would block */
 #define BIO_EOF		2	/* out-out-bounds error */
-#define BIO_SEG_VALID	3	/* nr_hw_seg valid */
+#define BIO_SEG_VALID	3	/* bi_phys_segments valid */
 #define BIO_CLONED	4	/* doesn't own data */
 #define BIO_BOUNCED	5	/* bio is a bounce bio */
 #define BIO_USER_MAPPED 6	/* contains user pages */
 #define BIO_EOPNOTSUPP	7	/* not supported */
+#define BIO_CPU_AFFINE	8	/* complete bio on same CPU as submitted */
+#define BIO_NULL_MAPPED 9	/* contains invalid user pages */
+#define BIO_FS_INTEGRITY 10	/* fs owns integrity data, not block layer */
 #define bio_flagged(bio, flag)	((bio)->bi_flags & (1 << (flag)))
 
 /*
@@ -144,18 +123,31 @@
 /*
  * bio bi_rw flags
  *
- * bit 0 -- read (not set) or write (set)
+ * bit 0 -- data direction
+ *	If not set, bio is a read from device. If set, it's a write to device.
  * bit 1 -- rw-ahead when set
  * bit 2 -- barrier
+ *	Insert a serialization point in the IO queue, forcing previously
+ *	submitted IO to be completed before this oen is issued.
  * bit 3 -- fail fast, don't want low level driver retries
  * bit 4 -- synchronous I/O hint: the block layer will unplug immediately
+ *	Note that this does NOT indicate that the IO itself is sync, just
+ *	that the block layer will not postpone issue of this IO by plugging.
+ * bit 5 -- metadata request
+ *	Used for tracing to differentiate metadata and data IO. May also
+ *	get some preferential treatment in the IO scheduler
+ * bit 6 -- discard sectors
+ *	Informs the lower level device that this range of sectors is no longer
+ *	used by the file system and may thus be freed by the device. Used
+ *	for flash based storage.
  */
-#define BIO_RW		0
-#define BIO_RW_AHEAD	1
+#define BIO_RW		0	/* Must match RW in req flags (blkdev.h) */
+#define BIO_RW_AHEAD	1	/* Must match FAILFAST in req flags */
 #define BIO_RW_BARRIER	2
 #define BIO_RW_FAILFAST	3
 #define BIO_RW_SYNC	4
 #define BIO_RW_META	5
+#define BIO_RW_DISCARD	6
 
 /*
  * upper 16 bits of bi_rw define the io priority of this bio
@@ -185,14 +177,15 @@
 #define bio_failfast(bio)	((bio)->bi_rw & (1 << BIO_RW_FAILFAST))
 #define bio_rw_ahead(bio)	((bio)->bi_rw & (1 << BIO_RW_AHEAD))
 #define bio_rw_meta(bio)	((bio)->bi_rw & (1 << BIO_RW_META))
-#define bio_empty_barrier(bio)	(bio_barrier(bio) && !(bio)->bi_size)
+#define bio_discard(bio)	((bio)->bi_rw & (1 << BIO_RW_DISCARD))
+#define bio_empty_barrier(bio)	(bio_barrier(bio) && !bio_has_data(bio) && !bio_discard(bio))
 
 static inline unsigned int bio_cur_sectors(struct bio *bio)
 {
 	if (bio->bi_vcnt)
 		return bio_iovec(bio)->bv_len >> 9;
-
-	return 0;
+	else /* dataless requests such as discard */
+		return bio->bi_size >> 9;
 }
 
 static inline void *bio_data(struct bio *bio)
@@ -236,8 +229,6 @@
 	((bvec_to_phys((vec1)) + (vec1)->bv_len) == bvec_to_phys((vec2)))
 #endif
 
-#define BIOVEC_VIRT_MERGEABLE(vec1, vec2)	\
-	((((bvec_to_phys((vec1)) + (vec1)->bv_len) | bvec_to_phys((vec2))) & (BIO_VMERGE_BOUNDARY - 1)) == 0)
 #define __BIO_SEG_BOUNDARY(addr1, addr2, mask) \
 	(((addr1) | (mask)) == (((addr2) - 1) | (mask)))
 #define BIOVEC_SEG_BOUNDARY(q, b1, b2) \
@@ -319,15 +310,14 @@
 	atomic_t			cnt;
 	int				error;
 };
-extern struct bio_pair *bio_split(struct bio *bi, mempool_t *pool,
-				  int first_sectors);
-extern mempool_t *bio_split_pool;
+extern struct bio_pair *bio_split(struct bio *bi, int first_sectors);
 extern void bio_pair_release(struct bio_pair *dbio);
 
 extern struct bio_set *bioset_create(int, int);
 extern void bioset_free(struct bio_set *);
 
 extern struct bio *bio_alloc(gfp_t, int);
+extern struct bio *bio_kmalloc(gfp_t, int);
 extern struct bio *bio_alloc_bioset(gfp_t, int, struct bio_set *);
 extern void bio_put(struct bio *);
 extern void bio_free(struct bio *, struct bio_set *);
@@ -335,7 +325,6 @@
 extern void bio_endio(struct bio *, int);
 struct request_queue;
 extern int bio_phys_segments(struct request_queue *, struct bio *);
-extern int bio_hw_segments(struct request_queue *, struct bio *);
 
 extern void __bio_clone(struct bio *, struct bio *);
 extern struct bio *bio_clone(struct bio *, gfp_t);
@@ -346,12 +335,14 @@
 extern int bio_add_pc_page(struct request_queue *, struct bio *, struct page *,
 			   unsigned int, unsigned int);
 extern int bio_get_nr_vecs(struct block_device *);
+extern sector_t bio_sector_offset(struct bio *, unsigned short, unsigned int);
 extern struct bio *bio_map_user(struct request_queue *, struct block_device *,
-				unsigned long, unsigned int, int);
+				unsigned long, unsigned int, int, gfp_t);
 struct sg_iovec;
+struct rq_map_data;
 extern struct bio *bio_map_user_iov(struct request_queue *,
 				    struct block_device *,
-				    struct sg_iovec *, int, int);
+				    struct sg_iovec *, int, int, gfp_t);
 extern void bio_unmap_user(struct bio *);
 extern struct bio *bio_map_kern(struct request_queue *, void *, unsigned int,
 				gfp_t);
@@ -359,15 +350,25 @@
 				 gfp_t, int);
 extern void bio_set_pages_dirty(struct bio *bio);
 extern void bio_check_pages_dirty(struct bio *bio);
-extern struct bio *bio_copy_user(struct request_queue *, unsigned long, unsigned int, int);
-extern struct bio *bio_copy_user_iov(struct request_queue *, struct sg_iovec *,
-				     int, int);
+extern struct bio *bio_copy_user(struct request_queue *, struct rq_map_data *,
+				 unsigned long, unsigned int, int, gfp_t);
+extern struct bio *bio_copy_user_iov(struct request_queue *,
+				     struct rq_map_data *, struct sg_iovec *,
+				     int, int, gfp_t);
 extern int bio_uncopy_user(struct bio *);
 void zero_fill_bio(struct bio *bio);
 extern struct bio_vec *bvec_alloc_bs(gfp_t, int, unsigned long *, struct bio_set *);
 extern unsigned int bvec_nr_vecs(unsigned short idx);
 
 /*
+ * Allow queuer to specify a completion CPU for this bio
+ */
+static inline void bio_set_completion_cpu(struct bio *bio, unsigned int cpu)
+{
+	bio->bi_comp_cpu = cpu;
+}
+
+/*
  * bio_set is used to allow other portions of the IO system to
  * allocate their own private memory pools for bio and iovec structures.
  * These memory pools in turn all allocate from the bio_slab
@@ -445,6 +446,14 @@
 	__bio_kmap_irq((bio), (bio)->bi_idx, (flags))
 #define bio_kunmap_irq(buf,flags)	__bio_kunmap_irq(buf, flags)
 
+/*
+ * Check whether this bio carries any data or not. A NULL bio is allowed.
+ */
+static inline int bio_has_data(struct bio *bio)
+{
+	return bio && bio->bi_io_vec != NULL;
+}
+
 #if defined(CONFIG_BLK_DEV_INTEGRITY)
 
 #define bip_vec_idx(bip, idx)	(&(bip->bip_vec[(idx)]))
@@ -458,14 +467,7 @@
 #define bip_for_each_vec(bvl, bip, i)					\
 	__bip_for_each_vec(bvl, bip, i, (bip)->bip_idx)
 
-static inline int bio_integrity(struct bio *bio)
-{
-#if defined(CONFIG_BLK_DEV_INTEGRITY)
-	return bio->bi_integrity != NULL;
-#else
-	return 0;
-#endif
-}
+#define bio_integrity(bio) (bio->bi_integrity != NULL)
 
 extern struct bio_integrity_payload *bio_integrity_alloc_bioset(struct bio *, gfp_t, unsigned int, struct bio_set *);
 extern struct bio_integrity_payload *bio_integrity_alloc(struct bio *, gfp_t, unsigned int);
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index 53ea933..a92d9e4 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -16,7 +16,9 @@
 #include <linux/bio.h>
 #include <linux/module.h>
 #include <linux/stringify.h>
+#include <linux/gfp.h>
 #include <linux/bsg.h>
+#include <linux/smp.h>
 
 #include <asm/scatterlist.h>
 
@@ -54,7 +56,6 @@
 	REQ_TYPE_PM_SUSPEND,		/* suspend request */
 	REQ_TYPE_PM_RESUME,		/* resume request */
 	REQ_TYPE_PM_SHUTDOWN,		/* shutdown request */
-	REQ_TYPE_FLUSH,			/* flush request */
 	REQ_TYPE_SPECIAL,		/* driver defined type */
 	REQ_TYPE_LINUX_BLOCK,		/* generic block layer message */
 	/*
@@ -76,19 +77,18 @@
  *
  */
 enum {
-	/*
-	 * just examples for now
-	 */
 	REQ_LB_OP_EJECT	= 0x40,		/* eject request */
-	REQ_LB_OP_FLUSH = 0x41,		/* flush device */
+	REQ_LB_OP_FLUSH = 0x41,		/* flush request */
+	REQ_LB_OP_DISCARD = 0x42,	/* discard sectors */
 };
 
 /*
- * request type modified bits. first three bits match BIO_RW* bits, important
+ * request type modified bits. first two bits match BIO_RW* bits, important
  */
 enum rq_flag_bits {
 	__REQ_RW,		/* not set, read. set, write */
 	__REQ_FAILFAST,		/* no low level driver retries */
+	__REQ_DISCARD,		/* request to discard sectors */
 	__REQ_SORTED,		/* elevator knows about this request */
 	__REQ_SOFTBARRIER,	/* may not be passed by ioscheduler */
 	__REQ_HARDBARRIER,	/* may not be passed by drive either */
@@ -111,6 +111,7 @@
 };
 
 #define REQ_RW		(1 << __REQ_RW)
+#define REQ_DISCARD	(1 << __REQ_DISCARD)
 #define REQ_FAILFAST	(1 << __REQ_FAILFAST)
 #define REQ_SORTED	(1 << __REQ_SORTED)
 #define REQ_SOFTBARRIER	(1 << __REQ_SOFTBARRIER)
@@ -140,12 +141,14 @@
  */
 struct request {
 	struct list_head queuelist;
-	struct list_head donelist;
+	struct call_single_data csd;
+	int cpu;
 
 	struct request_queue *q;
 
 	unsigned int cmd_flags;
 	enum rq_cmd_type_bits cmd_type;
+	unsigned long atomic_flags;
 
 	/* Maintain bio traversal state for part by part I/O submission.
 	 * hard_* are block layer internals, no driver should touch them!
@@ -190,13 +193,6 @@
 	 */
 	unsigned short nr_phys_segments;
 
-	/* Number of scatter-gather addr+len pairs after
-	 * physical and DMA remapping hardware coalescing is performed.
-	 * This is the number of scatter-gather entries the driver
-	 * will actually have to deal with after DMA mapping is done.
-	 */
-	unsigned short nr_hw_segments;
-
 	unsigned short ioprio;
 
 	void *special;
@@ -220,6 +216,8 @@
 	void *data;
 	void *sense;
 
+	unsigned long deadline;
+	struct list_head timeout_list;
 	unsigned int timeout;
 	int retries;
 
@@ -233,6 +231,11 @@
 	struct request *next_rq;
 };
 
+static inline unsigned short req_get_ioprio(struct request *req)
+{
+	return req->ioprio;
+}
+
 /*
  * State information carried for REQ_TYPE_PM_SUSPEND and REQ_TYPE_PM_RESUME
  * requests. Some step values could eventually be made generic.
@@ -252,6 +255,7 @@
 typedef int (make_request_fn) (struct request_queue *q, struct bio *bio);
 typedef int (prep_rq_fn) (struct request_queue *, struct request *);
 typedef void (unplug_fn) (struct request_queue *);
+typedef int (prepare_discard_fn) (struct request_queue *, struct request *);
 
 struct bio_vec;
 struct bvec_merge_data {
@@ -265,6 +269,15 @@
 typedef void (prepare_flush_fn) (struct request_queue *, struct request *);
 typedef void (softirq_done_fn)(struct request *);
 typedef int (dma_drain_needed_fn)(struct request *);
+typedef int (lld_busy_fn) (struct request_queue *q);
+
+enum blk_eh_timer_return {
+	BLK_EH_NOT_HANDLED,
+	BLK_EH_HANDLED,
+	BLK_EH_RESET_TIMER,
+};
+
+typedef enum blk_eh_timer_return (rq_timed_out_fn)(struct request *);
 
 enum blk_queue_state {
 	Queue_down,
@@ -307,10 +320,13 @@
 	make_request_fn		*make_request_fn;
 	prep_rq_fn		*prep_rq_fn;
 	unplug_fn		*unplug_fn;
+	prepare_discard_fn	*prepare_discard_fn;
 	merge_bvec_fn		*merge_bvec_fn;
 	prepare_flush_fn	*prepare_flush_fn;
 	softirq_done_fn		*softirq_done_fn;
+	rq_timed_out_fn		*rq_timed_out_fn;
 	dma_drain_needed_fn	*dma_drain_needed;
+	lld_busy_fn		*lld_busy_fn;
 
 	/*
 	 * Dispatch queue sorting
@@ -385,6 +401,10 @@
 	unsigned int		nr_sorted;
 	unsigned int		in_flight;
 
+	unsigned int		rq_timeout;
+	struct timer_list	timeout;
+	struct list_head	timeout_list;
+
 	/*
 	 * sg stuff
 	 */
@@ -421,6 +441,10 @@
 #define QUEUE_FLAG_ELVSWITCH	8	/* don't use elevator, just do FIFO */
 #define QUEUE_FLAG_BIDI		9	/* queue supports bidi requests */
 #define QUEUE_FLAG_NOMERGES    10	/* disable merge attempts */
+#define QUEUE_FLAG_SAME_COMP   11	/* force complete on same CPU */
+#define QUEUE_FLAG_FAIL_IO     12	/* fake timeout */
+#define QUEUE_FLAG_STACKABLE   13	/* supports request stacking */
+#define QUEUE_FLAG_NONROT      14	/* non-rotational device (SSD) */
 
 static inline int queue_is_locked(struct request_queue *q)
 {
@@ -526,7 +550,10 @@
 #define blk_queue_tagged(q)	test_bit(QUEUE_FLAG_QUEUED, &(q)->queue_flags)
 #define blk_queue_stopped(q)	test_bit(QUEUE_FLAG_STOPPED, &(q)->queue_flags)
 #define blk_queue_nomerges(q)	test_bit(QUEUE_FLAG_NOMERGES, &(q)->queue_flags)
+#define blk_queue_nonrot(q)	test_bit(QUEUE_FLAG_NONROT, &(q)->queue_flags)
 #define blk_queue_flushing(q)	((q)->ordseq)
+#define blk_queue_stackable(q)	\
+	test_bit(QUEUE_FLAG_STACKABLE, &(q)->queue_flags)
 
 #define blk_fs_request(rq)	((rq)->cmd_type == REQ_TYPE_FS)
 #define blk_pc_request(rq)	((rq)->cmd_type == REQ_TYPE_BLOCK_PC)
@@ -536,16 +563,18 @@
 #define blk_noretry_request(rq)	((rq)->cmd_flags & REQ_FAILFAST)
 #define blk_rq_started(rq)	((rq)->cmd_flags & REQ_STARTED)
 
-#define blk_account_rq(rq)	(blk_rq_started(rq) && blk_fs_request(rq))
+#define blk_account_rq(rq)	(blk_rq_started(rq) && (blk_fs_request(rq) || blk_discard_rq(rq))) 
 
 #define blk_pm_suspend_request(rq)	((rq)->cmd_type == REQ_TYPE_PM_SUSPEND)
 #define blk_pm_resume_request(rq)	((rq)->cmd_type == REQ_TYPE_PM_RESUME)
 #define blk_pm_request(rq)	\
 	(blk_pm_suspend_request(rq) || blk_pm_resume_request(rq))
 
+#define blk_rq_cpu_valid(rq)	((rq)->cpu != -1)
 #define blk_sorted_rq(rq)	((rq)->cmd_flags & REQ_SORTED)
 #define blk_barrier_rq(rq)	((rq)->cmd_flags & REQ_HARDBARRIER)
 #define blk_fua_rq(rq)		((rq)->cmd_flags & REQ_FUA)
+#define blk_discard_rq(rq)	((rq)->cmd_flags & REQ_DISCARD)
 #define blk_bidi_rq(rq)		((rq)->next_rq != NULL)
 #define blk_empty_barrier(rq)	(blk_barrier_rq(rq) && blk_fs_request(rq) && !(rq)->hard_nr_sectors)
 /* rq->queuelist of dequeued request must be list_empty() */
@@ -592,7 +621,8 @@
 #define RQ_NOMERGE_FLAGS	\
 	(REQ_NOMERGE | REQ_STARTED | REQ_HARDBARRIER | REQ_SOFTBARRIER)
 #define rq_mergeable(rq)	\
-	(!((rq)->cmd_flags & RQ_NOMERGE_FLAGS) && blk_fs_request((rq)))
+	(!((rq)->cmd_flags & RQ_NOMERGE_FLAGS) && \
+	 (blk_discard_rq(rq) || blk_fs_request((rq))))
 
 /*
  * q->prep_rq_fn return values
@@ -637,6 +667,12 @@
 }
 #endif /* CONFIG_MMU */
 
+struct rq_map_data {
+	struct page **pages;
+	int page_order;
+	int nr_entries;
+};
+
 struct req_iterator {
 	int i;
 	struct bio *bio;
@@ -664,6 +700,10 @@
 extern struct request *blk_get_request(struct request_queue *, int, gfp_t);
 extern void blk_insert_request(struct request_queue *, struct request *, int, void *);
 extern void blk_requeue_request(struct request_queue *, struct request *);
+extern int blk_rq_check_limits(struct request_queue *q, struct request *rq);
+extern int blk_lld_busy(struct request_queue *q);
+extern int blk_insert_cloned_request(struct request_queue *q,
+				     struct request *rq);
 extern void blk_plug_device(struct request_queue *);
 extern void blk_plug_device_unlocked(struct request_queue *);
 extern int blk_remove_plug(struct request_queue *);
@@ -705,11 +745,14 @@
 extern void __blk_run_queue(struct request_queue *);
 extern void blk_run_queue(struct request_queue *);
 extern void blk_start_queueing(struct request_queue *);
-extern int blk_rq_map_user(struct request_queue *, struct request *, void __user *, unsigned long);
+extern int blk_rq_map_user(struct request_queue *, struct request *,
+			   struct rq_map_data *, void __user *, unsigned long,
+			   gfp_t);
 extern int blk_rq_unmap_user(struct bio *);
 extern int blk_rq_map_kern(struct request_queue *, struct request *, void *, unsigned int, gfp_t);
 extern int blk_rq_map_user_iov(struct request_queue *, struct request *,
-			       struct sg_iovec *, int, unsigned int);
+			       struct rq_map_data *, struct sg_iovec *, int,
+			       unsigned int, gfp_t);
 extern int blk_execute_rq(struct request_queue *, struct gendisk *,
 			  struct request *, int);
 extern void blk_execute_rq_nowait(struct request_queue *, struct gendisk *,
@@ -750,12 +793,15 @@
 extern int blk_end_bidi_request(struct request *rq, int error,
 				unsigned int nr_bytes, unsigned int bidi_bytes);
 extern void end_request(struct request *, int);
-extern void end_queued_request(struct request *, int);
-extern void end_dequeued_request(struct request *, int);
 extern int blk_end_request_callback(struct request *rq, int error,
 				unsigned int nr_bytes,
 				int (drv_callback)(struct request *));
 extern void blk_complete_request(struct request *);
+extern void __blk_complete_request(struct request *);
+extern void blk_abort_request(struct request *);
+extern void blk_abort_queue(struct request_queue *);
+extern void blk_update_request(struct request *rq, int error,
+			       unsigned int nr_bytes);
 
 /*
  * blk_end_request() takes bytes instead of sectors as a complete size.
@@ -790,12 +836,16 @@
 extern int blk_queue_dma_drain(struct request_queue *q,
 			       dma_drain_needed_fn *dma_drain_needed,
 			       void *buf, unsigned int size);
+extern void blk_queue_lld_busy(struct request_queue *q, lld_busy_fn *fn);
 extern void blk_queue_segment_boundary(struct request_queue *, unsigned long);
 extern void blk_queue_prep_rq(struct request_queue *, prep_rq_fn *pfn);
 extern void blk_queue_merge_bvec(struct request_queue *, merge_bvec_fn *);
 extern void blk_queue_dma_alignment(struct request_queue *, int);
 extern void blk_queue_update_dma_alignment(struct request_queue *, int);
 extern void blk_queue_softirq_done(struct request_queue *, softirq_done_fn *);
+extern void blk_queue_set_discard(struct request_queue *, prepare_discard_fn *);
+extern void blk_queue_rq_timed_out(struct request_queue *, rq_timed_out_fn *);
+extern void blk_queue_rq_timeout(struct request_queue *, unsigned int);
 extern struct backing_dev_info *blk_get_backing_dev_info(struct block_device *bdev);
 extern int blk_queue_ordered(struct request_queue *, unsigned, prepare_flush_fn *);
 extern int blk_do_ordered(struct request_queue *, struct request **);
@@ -837,6 +887,16 @@
 }
 
 extern int blkdev_issue_flush(struct block_device *, sector_t *);
+extern int blkdev_issue_discard(struct block_device *,
+				sector_t sector, sector_t nr_sects, gfp_t);
+
+static inline int sb_issue_discard(struct super_block *sb,
+				   sector_t block, sector_t nr_blocks)
+{
+	block <<= (sb->s_blocksize_bits - 9);
+	nr_blocks <<= (sb->s_blocksize_bits - 9);
+	return blkdev_issue_discard(sb->s_bdev, block, nr_blocks, GFP_KERNEL);
+}
 
 /*
 * command filter functions
@@ -874,6 +934,13 @@
 	return q ? q->dma_alignment : 511;
 }
 
+static inline int blk_rq_aligned(struct request_queue *q, void *addr,
+				 unsigned int len)
+{
+	unsigned int alignment = queue_dma_alignment(q) | q->dma_pad_mask;
+	return !((unsigned long)addr & alignment) && !(len & alignment);
+}
+
 /* assumes size > 256 */
 static inline unsigned int blksize_bits(unsigned int size)
 {
@@ -900,7 +967,7 @@
 }
 
 struct work_struct;
-int kblockd_schedule_work(struct work_struct *work);
+int kblockd_schedule_work(struct request_queue *q, struct work_struct *work);
 void kblockd_flush_work(struct work_struct *work);
 
 #define MODULE_ALIAS_BLOCKDEV(major,minor) \
@@ -945,49 +1012,19 @@
 
 extern int blk_integrity_register(struct gendisk *, struct blk_integrity *);
 extern void blk_integrity_unregister(struct gendisk *);
-extern int blk_integrity_compare(struct block_device *, struct block_device *);
+extern int blk_integrity_compare(struct gendisk *, struct gendisk *);
 extern int blk_rq_map_integrity_sg(struct request *, struct scatterlist *);
 extern int blk_rq_count_integrity_sg(struct request *);
 
-static inline unsigned short blk_integrity_tuple_size(struct blk_integrity *bi)
-{
-	if (bi)
-		return bi->tuple_size;
-
-	return 0;
-}
-
-static inline struct blk_integrity *bdev_get_integrity(struct block_device *bdev)
+static inline
+struct blk_integrity *bdev_get_integrity(struct block_device *bdev)
 {
 	return bdev->bd_disk->integrity;
 }
 
-static inline unsigned int bdev_get_tag_size(struct block_device *bdev)
+static inline struct blk_integrity *blk_get_integrity(struct gendisk *disk)
 {
-	struct blk_integrity *bi = bdev_get_integrity(bdev);
-
-	if (bi)
-		return bi->tag_size;
-
-	return 0;
-}
-
-static inline int bdev_integrity_enabled(struct block_device *bdev, int rw)
-{
-	struct blk_integrity *bi = bdev_get_integrity(bdev);
-
-	if (bi == NULL)
-		return 0;
-
-	if (rw == READ && bi->verify_fn != NULL &&
-	    (bi->flags & INTEGRITY_FLAG_READ))
-		return 1;
-
-	if (rw == WRITE && bi->generate_fn != NULL &&
-	    (bi->flags & INTEGRITY_FLAG_WRITE))
-		return 1;
-
-	return 0;
+	return disk->integrity;
 }
 
 static inline int blk_integrity_rq(struct request *rq)
@@ -1004,7 +1041,7 @@
 #define blk_rq_count_integrity_sg(a)		(0)
 #define blk_rq_map_integrity_sg(a, b)		(0)
 #define bdev_get_integrity(a)			(0)
-#define bdev_get_tag_size(a)			(0)
+#define blk_get_integrity(a)			(0)
 #define blk_integrity_compare(a, b)		(0)
 #define blk_integrity_register(a, b)		(0)
 #define blk_integrity_unregister(a)		do { } while (0);
diff --git a/include/linux/blktrace_api.h b/include/linux/blktrace_api.h
index d084b8d..3a31eb5 100644
--- a/include/linux/blktrace_api.h
+++ b/include/linux/blktrace_api.h
@@ -1,8 +1,10 @@
 #ifndef BLKTRACE_H
 #define BLKTRACE_H
 
+#ifdef __KERNEL__
 #include <linux/blkdev.h>
 #include <linux/relay.h>
+#endif
 
 /*
  * Trace categories
@@ -21,6 +23,7 @@
 	BLK_TC_NOTIFY	= 1 << 10,	/* special message */
 	BLK_TC_AHEAD	= 1 << 11,	/* readahead */
 	BLK_TC_META	= 1 << 12,	/* metadata */
+	BLK_TC_DISCARD	= 1 << 13,	/* discard requests */
 
 	BLK_TC_END	= 1 << 15,	/* only 16-bits, reminder */
 };
@@ -47,6 +50,7 @@
 	__BLK_TA_SPLIT,			/* bio was split */
 	__BLK_TA_BOUNCE,		/* bio was bounced */
 	__BLK_TA_REMAP,			/* bio was remapped */
+	__BLK_TA_ABORT,			/* request aborted */
 };
 
 /*
@@ -77,6 +81,7 @@
 #define BLK_TA_SPLIT		(__BLK_TA_SPLIT)
 #define BLK_TA_BOUNCE		(__BLK_TA_BOUNCE)
 #define BLK_TA_REMAP		(__BLK_TA_REMAP | BLK_TC_ACT(BLK_TC_QUEUE))
+#define BLK_TA_ABORT		(__BLK_TA_ABORT | BLK_TC_ACT(BLK_TC_QUEUE))
 
 #define BLK_TN_PROCESS		(__BLK_TN_PROCESS | BLK_TC_ACT(BLK_TC_NOTIFY))
 #define BLK_TN_TIMESTAMP	(__BLK_TN_TIMESTAMP | BLK_TC_ACT(BLK_TC_NOTIFY))
@@ -89,17 +94,17 @@
  * The trace itself
  */
 struct blk_io_trace {
-	u32 magic;		/* MAGIC << 8 | version */
-	u32 sequence;		/* event number */
-	u64 time;		/* in microseconds */
-	u64 sector;		/* disk offset */
-	u32 bytes;		/* transfer length */
-	u32 action;		/* what happened */
-	u32 pid;		/* who did it */
-	u32 device;		/* device number */
-	u32 cpu;		/* on what cpu did it happen */
-	u16 error;		/* completion error */
-	u16 pdu_len;		/* length of data after this trace */
+	__u32 magic;		/* MAGIC << 8 | version */
+	__u32 sequence;		/* event number */
+	__u64 time;		/* in microseconds */
+	__u64 sector;		/* disk offset */
+	__u32 bytes;		/* transfer length */
+	__u32 action;		/* what happened */
+	__u32 pid;		/* who did it */
+	__u32 device;		/* device number */
+	__u32 cpu;		/* on what cpu did it happen */
+	__u16 error;		/* completion error */
+	__u16 pdu_len;		/* length of data after this trace */
 };
 
 /*
@@ -117,6 +122,23 @@
 	Blktrace_stopped,
 };
 
+#define BLKTRACE_BDEV_SIZE	32
+
+/*
+ * User setup structure passed with BLKTRACESTART
+ */
+struct blk_user_trace_setup {
+	char name[BLKTRACE_BDEV_SIZE];	/* output */
+	__u16 act_mask;			/* input */
+	__u32 buf_size;			/* input */
+	__u32 buf_nr;			/* input */
+	__u64 start_lba;
+	__u64 end_lba;
+	__u32 pid;
+};
+
+#ifdef __KERNEL__
+#if defined(CONFIG_BLK_DEV_IO_TRACE)
 struct blk_trace {
 	int trace_state;
 	struct rchan *rchan;
@@ -133,21 +155,6 @@
 	atomic_t dropped;
 };
 
-/*
- * User setup structure passed with BLKTRACESTART
- */
-struct blk_user_trace_setup {
-	char name[BDEVNAME_SIZE];	/* output */
-	u16 act_mask;			/* input */
-	u32 buf_size;			/* input */
-	u32 buf_nr;			/* input */
-	u64 start_lba;
-	u64 end_lba;
-	u32 pid;
-};
-
-#ifdef __KERNEL__
-#if defined(CONFIG_BLK_DEV_IO_TRACE)
 extern int blk_trace_ioctl(struct block_device *, unsigned, char __user *);
 extern void blk_trace_shutdown(struct request_queue *);
 extern void __blk_add_trace(struct blk_trace *, sector_t, int, int, u32, int, int, void *);
@@ -195,6 +202,9 @@
 	if (likely(!bt))
 		return;
 
+	if (blk_discard_rq(rq))
+		rw |= (1 << BIO_RW_DISCARD);
+
 	if (blk_pc_request(rq)) {
 		what |= BLK_TC_ACT(BLK_TC_PC);
 		__blk_add_trace(bt, 0, rq->data_len, rw, what, rq->errors, sizeof(rq->cmd), rq->cmd);
diff --git a/include/linux/cnt32_to_63.h b/include/linux/cnt32_to_63.h
new file mode 100644
index 0000000..8c0f950
--- /dev/null
+++ b/include/linux/cnt32_to_63.h
@@ -0,0 +1,80 @@
+/*
+ *  Extend a 32-bit counter to 63 bits
+ *
+ *  Author:	Nicolas Pitre
+ *  Created:	December 3, 2006
+ *  Copyright:	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 version 2
+ * as published by the Free Software Foundation.
+ */
+
+#ifndef __LINUX_CNT32_TO_63_H__
+#define __LINUX_CNT32_TO_63_H__
+
+#include <linux/compiler.h>
+#include <linux/types.h>
+#include <asm/byteorder.h>
+
+/* this is used only to give gcc a clue about good code generation */
+union cnt32_to_63 {
+	struct {
+#if defined(__LITTLE_ENDIAN)
+		u32 lo, hi;
+#elif defined(__BIG_ENDIAN)
+		u32 hi, lo;
+#endif
+	};
+	u64 val;
+};
+
+
+/**
+ * cnt32_to_63 - Expand a 32-bit counter to a 63-bit counter
+ * @cnt_lo: The low part of the counter
+ *
+ * Many hardware clock counters are only 32 bits wide and therefore have
+ * a relatively short period making wrap-arounds rather frequent.  This
+ * is a problem when implementing sched_clock() for example, where a 64-bit
+ * non-wrapping monotonic value is expected to be returned.
+ *
+ * To overcome that limitation, let's extend a 32-bit counter to 63 bits
+ * in a completely lock free fashion. Bits 0 to 31 of the clock are provided
+ * by the hardware while bits 32 to 62 are stored in memory.  The top bit in
+ * memory is used to synchronize with the hardware clock half-period.  When
+ * the top bit of both counters (hardware and in memory) differ then the
+ * memory is updated with a new value, incrementing it when the hardware
+ * counter wraps around.
+ *
+ * Because a word store in memory is atomic then the incremented value will
+ * always be in synch with the top bit indicating to any potential concurrent
+ * reader if the value in memory is up to date or not with regards to the
+ * needed increment.  And any race in updating the value in memory is harmless
+ * as the same value would simply be stored more than once.
+ *
+ * The only restriction for the algorithm to work properly is that this
+ * code must be executed at least once per each half period of the 32-bit
+ * counter to properly update the state bit in memory. This is usually not a
+ * problem in practice, but if it is then a kernel timer could be scheduled
+ * to manage for this code to be executed often enough.
+ *
+ * Note that the top bit (bit 63) in the returned value should be considered
+ * as garbage.  It is not cleared here because callers are likely to use a
+ * multiplier on the returned value which can get rid of the top bit
+ * implicitly by making the multiplier even, therefore saving on a runtime
+ * clear-bit instruction. Otherwise caller must remember to clear the top
+ * bit explicitly.
+ */
+#define cnt32_to_63(cnt_lo) \
+({ \
+	static volatile u32 __m_cnt_hi; \
+	union cnt32_to_63 __x; \
+	__x.hi = __m_cnt_hi; \
+	__x.lo = (cnt_lo); \
+	if (unlikely((s32)(__x.hi ^ __x.lo) < 0)) \
+		__m_cnt_hi = __x.hi = (__x.hi ^ 0x80000000) + (__x.hi >> 31); \
+	__x.val; \
+})
+
+#endif
diff --git a/include/linux/compiler.h b/include/linux/compiler.h
index c8bd2da..8322141 100644
--- a/include/linux/compiler.h
+++ b/include/linux/compiler.h
@@ -190,7 +190,9 @@
  * ACCESS_ONCE() in different C statements.
  *
  * This macro does absolutely -nothing- to prevent the CPU from reordering,
- * merging, or refetching absolutely anything at any time.
+ * merging, or refetching absolutely anything at any time.  Its main intended
+ * use is to mediate communication between process-level code and irq/NMI
+ * handlers, all running on the same CPU.
  */
 #define ACCESS_ONCE(x) (*(volatile typeof(x) *)&(x))
 
diff --git a/include/linux/completion.h b/include/linux/completion.h
index 02ef883..4a6b604 100644
--- a/include/linux/completion.h
+++ b/include/linux/completion.h
@@ -10,6 +10,18 @@
 
 #include <linux/wait.h>
 
+/**
+ * struct completion - structure used to maintain state for a "completion"
+ *
+ * This is the opaque structure used to maintain the state for a "completion".
+ * Completions currently use a FIFO to queue threads that have to wait for
+ * the "completion" event.
+ *
+ * See also:  complete(), wait_for_completion() (and friends _timeout,
+ * _interruptible, _interruptible_timeout, and _killable), init_completion(),
+ * and macros DECLARE_COMPLETION(), DECLARE_COMPLETION_ONSTACK(), and
+ * INIT_COMPLETION().
+ */
 struct completion {
 	unsigned int done;
 	wait_queue_head_t wait;
@@ -21,6 +33,14 @@
 #define COMPLETION_INITIALIZER_ONSTACK(work) \
 	({ init_completion(&work); work; })
 
+/**
+ * DECLARE_COMPLETION: - declare and initialize a completion structure
+ * @work:  identifier for the completion structure
+ *
+ * This macro declares and initializes a completion structure. Generally used
+ * for static declarations. You should use the _ONSTACK variant for automatic
+ * variables.
+ */
 #define DECLARE_COMPLETION(work) \
 	struct completion work = COMPLETION_INITIALIZER(work)
 
@@ -29,6 +49,13 @@
  * completions - so we use the _ONSTACK() variant for those that
  * are on the kernel stack:
  */
+/**
+ * DECLARE_COMPLETION_ONSTACK: - declare and initialize a completion structure
+ * @work:  identifier for the completion structure
+ *
+ * This macro declares and initializes a completion structure on the kernel
+ * stack.
+ */
 #ifdef CONFIG_LOCKDEP
 # define DECLARE_COMPLETION_ONSTACK(work) \
 	struct completion work = COMPLETION_INITIALIZER_ONSTACK(work)
@@ -36,6 +63,13 @@
 # define DECLARE_COMPLETION_ONSTACK(work) DECLARE_COMPLETION(work)
 #endif
 
+/**
+ * init_completion: - Initialize a dynamically allocated completion
+ * @x:  completion structure that is to be initialized
+ *
+ * This inline function will initialize a dynamically created completion
+ * structure.
+ */
 static inline void init_completion(struct completion *x)
 {
 	x->done = 0;
@@ -55,6 +89,13 @@
 extern void complete(struct completion *);
 extern void complete_all(struct completion *);
 
+/**
+ * INIT_COMPLETION: - reinitialize a completion structure
+ * @x:  completion structure to be reinitialized
+ *
+ * This macro should be used to reinitialize a completion structure so it can
+ * be reused. This is especially important after complete_all() is used.
+ */
 #define INIT_COMPLETION(x)	((x).done = 0)
 
 
diff --git a/include/linux/console_struct.h b/include/linux/console_struct.h
index b03f80a..d71f7c0 100644
--- a/include/linux/console_struct.h
+++ b/include/linux/console_struct.h
@@ -53,7 +53,6 @@
 	unsigned short	vc_hi_font_mask;	/* [#] Attribute set for upper 256 chars of font or 0 if not supported */
 	struct console_font vc_font;		/* Current VC font set */
 	unsigned short	vc_video_erase_char;	/* Background erase character */
-	unsigned short	vc_scrl_erase_char;	/* Erase character for scroll */
 	/* VT terminal data */
 	unsigned int	vc_state;		/* Escape sequence parser state */
 	unsigned int	vc_npar,vc_par[NPAR];	/* Parameters of current escape sequence */
diff --git a/include/linux/cpu.h b/include/linux/cpu.h
index d7faf88..c2747ac 100644
--- a/include/linux/cpu.h
+++ b/include/linux/cpu.h
@@ -69,6 +69,7 @@
 #endif
 
 int cpu_up(unsigned int cpu);
+void notify_cpu_starting(unsigned int cpu);
 extern void cpu_hotplug_init(void);
 extern void cpu_maps_update_begin(void);
 extern void cpu_maps_update_done(void);
diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h
index 6fd5668..1ee608f 100644
--- a/include/linux/cpufreq.h
+++ b/include/linux/cpufreq.h
@@ -187,7 +187,8 @@
 				   unsigned int relation);
 
 
-extern int __cpufreq_driver_getavg(struct cpufreq_policy *policy);
+extern int __cpufreq_driver_getavg(struct cpufreq_policy *policy,
+				   unsigned int cpu);
 
 int cpufreq_register_governor(struct cpufreq_governor *governor);
 void cpufreq_unregister_governor(struct cpufreq_governor *governor);
@@ -226,7 +227,9 @@
 	unsigned int	(*get)	(unsigned int cpu);
 
 	/* optional */
-	unsigned int (*getavg)	(unsigned int cpu);
+	unsigned int (*getavg)	(struct cpufreq_policy *policy,
+				 unsigned int cpu);
+
 	int	(*exit)		(struct cpufreq_policy *policy);
 	int	(*suspend)	(struct cpufreq_policy *policy, pm_message_t pmsg);
 	int	(*resume)	(struct cpufreq_policy *policy);
diff --git a/include/linux/crypto.h b/include/linux/crypto.h
index c43dc47..3d2317e 100644
--- a/include/linux/crypto.h
+++ b/include/linux/crypto.h
@@ -38,6 +38,7 @@
 #define CRYPTO_ALG_TYPE_DIGEST		0x00000008
 #define CRYPTO_ALG_TYPE_HASH		0x00000009
 #define CRYPTO_ALG_TYPE_AHASH		0x0000000a
+#define CRYPTO_ALG_TYPE_RNG		0x0000000c
 
 #define CRYPTO_ALG_TYPE_HASH_MASK	0x0000000e
 #define CRYPTO_ALG_TYPE_AHASH_MASK	0x0000000c
@@ -61,6 +62,14 @@
 #define CRYPTO_ALG_GENIV		0x00000200
 
 /*
+ * Set if the algorithm has passed automated run-time testing.  Note that
+ * if there is no run-time testing for a given algorithm it is considered
+ * to have passed.
+ */
+
+#define CRYPTO_ALG_TESTED		0x00000400
+
+/*
  * Transform masks and values (for crt_flags).
  */
 #define CRYPTO_TFM_REQ_MASK		0x000fff00
@@ -105,6 +114,7 @@
 struct crypto_blkcipher;
 struct crypto_hash;
 struct crypto_ahash;
+struct crypto_rng;
 struct crypto_tfm;
 struct crypto_type;
 struct aead_givcrypt_request;
@@ -290,6 +300,15 @@
 			      unsigned int slen, u8 *dst, unsigned int *dlen);
 };
 
+struct rng_alg {
+	int (*rng_make_random)(struct crypto_rng *tfm, u8 *rdata,
+			       unsigned int dlen);
+	int (*rng_reset)(struct crypto_rng *tfm, u8 *seed, unsigned int slen);
+
+	unsigned int seedsize;
+};
+
+
 #define cra_ablkcipher	cra_u.ablkcipher
 #define cra_aead	cra_u.aead
 #define cra_blkcipher	cra_u.blkcipher
@@ -298,6 +317,7 @@
 #define cra_hash	cra_u.hash
 #define cra_ahash	cra_u.ahash
 #define cra_compress	cra_u.compress
+#define cra_rng		cra_u.rng
 
 struct crypto_alg {
 	struct list_head cra_list;
@@ -325,6 +345,7 @@
 		struct hash_alg hash;
 		struct ahash_alg ahash;
 		struct compress_alg compress;
+		struct rng_alg rng;
 	} cra_u;
 
 	int (*cra_init)(struct crypto_tfm *tfm);
@@ -430,6 +451,12 @@
 	                      u8 *dst, unsigned int *dlen);
 };
 
+struct rng_tfm {
+	int (*rng_gen_random)(struct crypto_rng *tfm, u8 *rdata,
+			      unsigned int dlen);
+	int (*rng_reset)(struct crypto_rng *tfm, u8 *seed, unsigned int slen);
+};
+
 #define crt_ablkcipher	crt_u.ablkcipher
 #define crt_aead	crt_u.aead
 #define crt_blkcipher	crt_u.blkcipher
@@ -437,6 +464,7 @@
 #define crt_hash	crt_u.hash
 #define crt_ahash	crt_u.ahash
 #define crt_compress	crt_u.compress
+#define crt_rng		crt_u.rng
 
 struct crypto_tfm {
 
@@ -450,6 +478,7 @@
 		struct hash_tfm hash;
 		struct ahash_tfm ahash;
 		struct compress_tfm compress;
+		struct rng_tfm rng;
 	} crt_u;
 	
 	struct crypto_alg *__crt_alg;
@@ -481,6 +510,10 @@
 	struct crypto_tfm base;
 };
 
+struct crypto_rng {
+	struct crypto_tfm base;
+};
+
 enum {
 	CRYPTOA_UNSPEC,
 	CRYPTOA_ALG,
@@ -515,6 +548,8 @@
 struct crypto_tfm *crypto_alloc_base(const char *alg_name, u32 type, u32 mask);
 void crypto_free_tfm(struct crypto_tfm *tfm);
 
+int alg_test(const char *driver, const char *alg, u32 type, u32 mask);
+
 /*
  * Transform helpers which query the underlying algorithm.
  */
diff --git a/include/linux/device-mapper.h b/include/linux/device-mapper.h
index a90222e..08d7835 100644
--- a/include/linux/device-mapper.h
+++ b/include/linux/device-mapper.h
@@ -13,7 +13,6 @@
 
 struct dm_target;
 struct dm_table;
-struct dm_dev;
 struct mapped_device;
 struct bio_vec;
 
@@ -84,6 +83,12 @@
  */
 void dm_set_device_limits(struct dm_target *ti, struct block_device *bdev);
 
+struct dm_dev {
+	struct block_device *bdev;
+	int mode;
+	char name[16];
+};
+
 /*
  * Constructors should call these functions to ensure destination devices
  * are opened/closed correctly.
@@ -202,6 +207,7 @@
 struct gendisk *dm_disk(struct mapped_device *md);
 int dm_suspended(struct mapped_device *md);
 int dm_noflush_suspending(struct dm_target *ti);
+union map_info *dm_get_mapinfo(struct bio *bio);
 
 /*
  * Geometry functions.
@@ -232,6 +238,11 @@
 int dm_table_complete(struct dm_table *t);
 
 /*
+ * Unplug all devices in a table.
+ */
+void dm_table_unplug_all(struct dm_table *t);
+
+/*
  * Table reference counting.
  */
 struct dm_table *dm_get_table(struct mapped_device *md);
@@ -256,6 +267,11 @@
  */
 int dm_swap_table(struct mapped_device *md, struct dm_table *t);
 
+/*
+ * A wrapper around vmalloc.
+ */
+void *dm_vcalloc(unsigned long nmemb, unsigned long elem_size);
+
 /*-----------------------------------------------------------------
  * Macros.
  *---------------------------------------------------------------*/
diff --git a/include/linux/device.h b/include/linux/device.h
index 4d8372d..246937c 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -199,6 +199,11 @@
 	struct class_private *p;
 };
 
+struct class_dev_iter {
+	struct klist_iter		ki;
+	const struct device_type	*type;
+};
+
 extern struct kobject *sysfs_dev_block_kobj;
 extern struct kobject *sysfs_dev_char_kobj;
 extern int __must_check __class_register(struct class *class,
@@ -213,6 +218,13 @@
 	__class_register(class, &__key);	\
 })
 
+extern void class_dev_iter_init(struct class_dev_iter *iter,
+				struct class *class,
+				struct device *start,
+				const struct device_type *type);
+extern struct device *class_dev_iter_next(struct class_dev_iter *iter);
+extern void class_dev_iter_exit(struct class_dev_iter *iter);
+
 extern int class_for_each_device(struct class *class, struct device *start,
 				 void *data,
 				 int (*fn)(struct device *dev, void *data));
@@ -396,7 +408,7 @@
 	spinlock_t		devres_lock;
 	struct list_head	devres_head;
 
-	struct list_head	node;
+	struct klist_node	knode_class;
 	struct class		*class;
 	dev_t			devt;	/* dev_t, creates the sysfs "dev" */
 	struct attribute_group	**groups;	/* optional groups */
diff --git a/include/linux/devpts_fs.h b/include/linux/devpts_fs.h
index 154769c..5ce0e5f 100644
--- a/include/linux/devpts_fs.h
+++ b/include/linux/devpts_fs.h
@@ -17,20 +17,31 @@
 
 #ifdef CONFIG_UNIX98_PTYS
 
-int devpts_new_index(void);
-void devpts_kill_index(int idx);
-int devpts_pty_new(struct tty_struct *tty);      /* mknod in devpts */
-struct tty_struct *devpts_get_tty(int number);	 /* get tty structure */
-void devpts_pty_kill(int number);		 /* unlink */
+int devpts_new_index(struct inode *ptmx_inode);
+void devpts_kill_index(struct inode *ptmx_inode, int idx);
+/* mknod in devpts */
+int devpts_pty_new(struct inode *ptmx_inode, struct tty_struct *tty);
+/* get tty structure */
+struct tty_struct *devpts_get_tty(struct inode *pts_inode, int number);
+/* unlink */
+void devpts_pty_kill(struct tty_struct *tty);
 
 #else
 
 /* Dummy stubs in the no-pty case */
-static inline int devpts_new_index(void) { return -EINVAL; }
-static inline void devpts_kill_index(int idx) { }
-static inline int devpts_pty_new(struct tty_struct *tty) { return -EINVAL; }
-static inline struct tty_struct *devpts_get_tty(int number) { return NULL; }
-static inline void devpts_pty_kill(int number) { }
+static inline int devpts_new_index(struct inode *ptmx_inode) { return -EINVAL; }
+static inline void devpts_kill_index(struct inode *ptmx_inode, int idx) { }
+static inline int devpts_pty_new(struct inode *ptmx_inode,
+				struct tty_struct *tty)
+{
+	return -EINVAL;
+}
+static inline struct tty_struct *devpts_get_tty(struct inode *pts_inode,
+		int number)
+{
+	return NULL;
+}
+static inline void devpts_pty_kill(struct tty_struct *tty) { }
 
 #endif
 
diff --git a/include/linux/dlm.h b/include/linux/dlm.h
index 203a025..b9cd386 100644
--- a/include/linux/dlm.h
+++ b/include/linux/dlm.h
@@ -2,7 +2,7 @@
 *******************************************************************************
 **
 **  Copyright (C) Sistina Software, Inc.  1997-2003  All rights reserved.
-**  Copyright (C) 2004-2007 Red Hat, Inc.  All rights reserved.
+**  Copyright (C) 2004-2008 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
@@ -65,9 +65,12 @@
 	char *	 sb_lvbptr;
 };
 
+/* dlm_new_lockspace() flags */
+
 #define DLM_LSFL_NODIR		0x00000001
 #define DLM_LSFL_TIMEWARN	0x00000002
 #define DLM_LSFL_FS     	0x00000004
+#define DLM_LSFL_NEWEXCL     	0x00000008
 
 #ifdef __KERNEL__
 
diff --git a/include/linux/dlm_device.h b/include/linux/dlm_device.h
index c603450..3060783 100644
--- a/include/linux/dlm_device.h
+++ b/include/linux/dlm_device.h
@@ -26,7 +26,7 @@
 /* Version of the device interface */
 #define DLM_DEVICE_VERSION_MAJOR 6
 #define DLM_DEVICE_VERSION_MINOR 0
-#define DLM_DEVICE_VERSION_PATCH 0
+#define DLM_DEVICE_VERSION_PATCH 1
 
 /* struct passed to the lock write */
 struct dlm_lock_params {
diff --git a/include/linux/dma-mapping.h b/include/linux/dma-mapping.h
index 952e0f8..ba9114e 100644
--- a/include/linux/dma-mapping.h
+++ b/include/linux/dma-mapping.h
@@ -48,6 +48,11 @@
 	return dev->dma_mask != NULL && *dev->dma_mask != DMA_MASK_NONE;
 }
 
+static inline int is_buffer_dma_capable(u64 mask, dma_addr_t addr, size_t size)
+{
+	return addr + size <= mask;
+}
+
 #ifdef CONFIG_HAS_DMA
 #include <asm/dma-mapping.h>
 #else
@@ -58,6 +63,13 @@
 #define dma_sync_single		dma_sync_single_for_cpu
 #define dma_sync_sg		dma_sync_sg_for_cpu
 
+static inline u64 dma_get_mask(struct device *dev)
+{
+	if (dev && dev->dma_mask && *dev->dma_mask)
+		return *dev->dma_mask;
+	return DMA_32BIT_MASK;
+}
+
 extern u64 dma_get_required_mask(struct device *dev);
 
 static inline unsigned int dma_get_max_seg_size(struct device *dev)
diff --git a/include/linux/dmar.h b/include/linux/dmar.h
index 56c73b8..c360c55 100644
--- a/include/linux/dmar.h
+++ b/include/linux/dmar.h
@@ -25,9 +25,99 @@
 #include <linux/types.h>
 #include <linux/msi.h>
 
-#ifdef CONFIG_DMAR
+#if defined(CONFIG_DMAR) || defined(CONFIG_INTR_REMAP)
 struct intel_iommu;
 
+struct dmar_drhd_unit {
+	struct list_head list;		/* list of drhd units	*/
+	struct  acpi_dmar_header *hdr;	/* ACPI header		*/
+	u64	reg_base_addr;		/* register base address*/
+	struct	pci_dev **devices; 	/* target device array	*/
+	int	devices_cnt;		/* target device count	*/
+	u8	ignored:1; 		/* ignore drhd		*/
+	u8	include_all:1;
+	struct intel_iommu *iommu;
+};
+
+extern struct list_head dmar_drhd_units;
+
+#define for_each_drhd_unit(drhd) \
+	list_for_each_entry(drhd, &dmar_drhd_units, list)
+
+extern int dmar_table_init(void);
+extern int early_dmar_detect(void);
+extern int dmar_dev_scope_init(void);
+
+/* Intel IOMMU detection */
+extern void detect_intel_iommu(void);
+
+
+extern int parse_ioapics_under_ir(void);
+extern int alloc_iommu(struct dmar_drhd_unit *);
+#else
+static inline void detect_intel_iommu(void)
+{
+	return;
+}
+
+static inline int dmar_table_init(void)
+{
+	return -ENODEV;
+}
+#endif /* !CONFIG_DMAR && !CONFIG_INTR_REMAP */
+
+#ifdef CONFIG_INTR_REMAP
+extern int intr_remapping_enabled;
+extern int enable_intr_remapping(int);
+
+struct irte {
+	union {
+		struct {
+			__u64	present 	: 1,
+				fpd		: 1,
+				dst_mode	: 1,
+				redir_hint	: 1,
+				trigger_mode	: 1,
+				dlvry_mode	: 3,
+				avail		: 4,
+				__reserved_1	: 4,
+				vector		: 8,
+				__reserved_2	: 8,
+				dest_id		: 32;
+		};
+		__u64 low;
+	};
+
+	union {
+		struct {
+			__u64	sid		: 16,
+				sq		: 2,
+				svt		: 2,
+				__reserved_3	: 44;
+		};
+		__u64 high;
+	};
+};
+extern int get_irte(int irq, struct irte *entry);
+extern int modify_irte(int irq, struct irte *irte_modified);
+extern int alloc_irte(struct intel_iommu *iommu, int irq, u16 count);
+extern int set_irte_irq(int irq, struct intel_iommu *iommu, u16 index,
+   			u16 sub_handle);
+extern int map_irq_to_irte_handle(int irq, u16 *sub_handle);
+extern int clear_irte_irq(int irq, struct intel_iommu *iommu, u16 index);
+extern int flush_irte(int irq);
+extern int free_irte(int irq);
+
+extern int irq_remapped(int irq);
+extern struct intel_iommu *map_dev_to_ir(struct pci_dev *dev);
+extern struct intel_iommu *map_ioapic_to_ir(int apic);
+#else
+#define irq_remapped(irq)		(0)
+#define enable_intr_remapping(mode)	(-1)
+#define intr_remapping_enabled		(0)
+#endif
+
+#ifdef CONFIG_DMAR
 extern const char *dmar_get_fault_reason(u8 fault_reason);
 
 /* Can't use the common MSI interrupt functions
@@ -40,47 +130,30 @@
 extern int dmar_set_interrupt(struct intel_iommu *iommu);
 extern int arch_setup_dmar_msi(unsigned int irq);
 
-/* Intel IOMMU detection and initialization functions */
-extern void detect_intel_iommu(void);
-extern int intel_iommu_init(void);
-
-extern int dmar_table_init(void);
-extern int early_dmar_detect(void);
-
-extern struct list_head dmar_drhd_units;
+extern int iommu_detected, no_iommu;
 extern struct list_head dmar_rmrr_units;
-
-struct dmar_drhd_unit {
-	struct list_head list;		/* list of drhd units	*/
-	u64	reg_base_addr;		/* register base address*/
-	struct	pci_dev **devices; 	/* target device array	*/
-	int	devices_cnt;		/* target device count	*/
-	u8	ignored:1; 		/* ignore drhd		*/
-	u8	include_all:1;
-	struct intel_iommu *iommu;
-};
-
 struct dmar_rmrr_unit {
 	struct list_head list;		/* list of rmrr units	*/
+	struct acpi_dmar_header *hdr;	/* ACPI header		*/
 	u64	base_address;		/* reserved base address*/
 	u64	end_address;		/* reserved end address */
 	struct pci_dev **devices;	/* target devices */
 	int	devices_cnt;		/* target device count */
 };
 
-#define for_each_drhd_unit(drhd) \
-	list_for_each_entry(drhd, &dmar_drhd_units, list)
 #define for_each_rmrr_units(rmrr) \
 	list_for_each_entry(rmrr, &dmar_rmrr_units, list)
+/* Intel DMAR  initialization functions */
+extern int intel_iommu_init(void);
+extern int dmar_disabled;
 #else
-static inline void detect_intel_iommu(void)
-{
-	return;
-}
 static inline int intel_iommu_init(void)
 {
+#ifdef CONFIG_INTR_REMAP
+	return dmar_dev_scope_init();
+#else
 	return -ENODEV;
+#endif
 }
-
 #endif /* !CONFIG_DMAR */
 #endif /* __DMAR_H__ */
diff --git a/include/linux/dmi.h b/include/linux/dmi.h
index 2a063b6..e5084eb 100644
--- a/include/linux/dmi.h
+++ b/include/linux/dmi.h
@@ -2,29 +2,9 @@
 #define __DMI_H__
 
 #include <linux/list.h>
+#include <linux/mod_devicetable.h>
 
-enum dmi_field {
-	DMI_NONE,
-	DMI_BIOS_VENDOR,
-	DMI_BIOS_VERSION,
-	DMI_BIOS_DATE,
-	DMI_SYS_VENDOR,
-	DMI_PRODUCT_NAME,
-	DMI_PRODUCT_VERSION,
-	DMI_PRODUCT_SERIAL,
-	DMI_PRODUCT_UUID,
-	DMI_BOARD_VENDOR,
-	DMI_BOARD_NAME,
-	DMI_BOARD_VERSION,
-	DMI_BOARD_SERIAL,
-	DMI_BOARD_ASSET_TAG,
-	DMI_CHASSIS_VENDOR,
-	DMI_CHASSIS_TYPE,
-	DMI_CHASSIS_VERSION,
-	DMI_CHASSIS_SERIAL,
-	DMI_CHASSIS_ASSET_TAG,
-	DMI_STRING_MAX,
-};
+/* enum dmi_field is in mod_devicetable.h */
 
 enum dmi_device_type {
 	DMI_DEV_TYPE_ANY = 0,
@@ -48,23 +28,6 @@
 	u16 handle;
 };
 
-/*
- *	DMI callbacks for problem boards
- */
-struct dmi_strmatch {
-	u8 slot;
-	char *substr;
-};
-
-struct dmi_system_id {
-	int (*callback)(const struct dmi_system_id *);
-	const char *ident;
-	struct dmi_strmatch matches[4];
-	void *driver_data;
-};
-
-#define DMI_MATCH(a, b)	{ a, b }
-
 struct dmi_device {
 	struct list_head list;
 	int type;
diff --git a/include/linux/dvb/frontend.h b/include/linux/dvb/frontend.h
index c8cbd90..6e4ace2 100644
--- a/include/linux/dvb/frontend.h
+++ b/include/linux/dvb/frontend.h
@@ -62,6 +62,7 @@
 	FE_CAN_HIERARCHY_AUTO		= 0x100000,
 	FE_CAN_8VSB			= 0x200000,
 	FE_CAN_16VSB			= 0x400000,
+	FE_HAS_EXTENDED_CAPS		= 0x800000,   // We need more bitspace for newer APIs, indicate this.
 	FE_NEEDS_BENDING		= 0x20000000, // not supported anymore, don't use (frontend requires frequency bending)
 	FE_CAN_RECOVER			= 0x40000000, // frontend can recover from a cable unplug automatically
 	FE_CAN_MUTE_TS			= 0x80000000  // frontend can stop spurious TS data output
@@ -147,7 +148,9 @@
 	FEC_6_7,
 	FEC_7_8,
 	FEC_8_9,
-	FEC_AUTO
+	FEC_AUTO,
+	FEC_3_5,
+	FEC_9_10,
 } fe_code_rate_t;
 
 
@@ -160,7 +163,10 @@
 	QAM_256,
 	QAM_AUTO,
 	VSB_8,
-	VSB_16
+	VSB_16,
+	PSK_8,
+	APSK_16,
+	DQPSK,
 } fe_modulation_t;
 
 typedef enum fe_transmit_mode {
@@ -239,6 +245,106 @@
 	struct dvb_frontend_parameters parameters;
 };
 
+/* S2API Commands */
+#define DTV_UNDEFINED		0
+#define DTV_TUNE		1
+#define DTV_CLEAR		2
+#define DTV_FREQUENCY		3
+#define DTV_MODULATION		4
+#define DTV_BANDWIDTH_HZ	5
+#define DTV_INVERSION		6
+#define DTV_DISEQC_MASTER	7
+#define DTV_SYMBOL_RATE		8
+#define DTV_INNER_FEC		9
+#define DTV_VOLTAGE		10
+#define DTV_TONE		11
+#define DTV_PILOT		12
+#define DTV_ROLLOFF		13
+#define DTV_DISEQC_SLAVE_REPLY	14
+
+/* Basic enumeration set for querying unlimited capabilities */
+#define DTV_FE_CAPABILITY_COUNT	15
+#define DTV_FE_CAPABILITY	16
+#define DTV_DELIVERY_SYSTEM	17
+
+#define DTV_API_VERSION				35
+#define DTV_API_VERSION				35
+#define DTV_CODE_RATE_HP			36
+#define DTV_CODE_RATE_LP			37
+#define DTV_GUARD_INTERVAL			38
+#define DTV_TRANSMISSION_MODE			39
+#define DTV_HIERARCHY				40
+
+#define DTV_MAX_COMMAND				DTV_HIERARCHY
+
+typedef enum fe_pilot {
+	PILOT_ON,
+	PILOT_OFF,
+	PILOT_AUTO,
+} fe_pilot_t;
+
+typedef enum fe_rolloff {
+	ROLLOFF_35, /* Implied value in DVB-S, default for DVB-S2 */
+	ROLLOFF_20,
+	ROLLOFF_25,
+	ROLLOFF_AUTO,
+} fe_rolloff_t;
+
+typedef enum fe_delivery_system {
+	SYS_UNDEFINED,
+	SYS_DVBC_ANNEX_AC,
+	SYS_DVBC_ANNEX_B,
+	SYS_DVBT,
+	SYS_DVBS,
+	SYS_DVBS2,
+	SYS_DVBH,
+	SYS_ISDBT,
+	SYS_ISDBS,
+	SYS_ISDBC,
+	SYS_ATSC,
+	SYS_ATSCMH,
+	SYS_DMBTH,
+	SYS_CMMB,
+	SYS_DAB,
+} fe_delivery_system_t;
+
+struct dtv_cmds_h {
+	char	*name;		/* A display name for debugging purposes */
+
+	__u32	cmd;		/* A unique ID */
+
+	/* Flags */
+	__u32	set:1;		/* Either a set or get property */
+	__u32	buffer:1;	/* Does this property use the buffer? */
+	__u32	reserved:30;	/* Align */
+};
+
+struct dtv_property {
+	__u32 cmd;
+	__u32 reserved[3];
+	union {
+		__u32 data;
+		struct {
+			__u8 data[32];
+			__u32 len;
+			__u32 reserved1[3];
+			void *reserved2;
+		} buffer;
+	} u;
+	int result;
+} __attribute__ ((packed));
+
+/* num of properties cannot exceed DTV_IOCTL_MAX_MSGS per ioctl */
+#define DTV_IOCTL_MAX_MSGS 64
+
+struct dtv_properties {
+	__u32 num;
+	struct dtv_property *props;
+};
+
+#define FE_SET_PROPERTY		   _IOW('o', 82, struct dtv_properties)
+#define FE_GET_PROPERTY		   _IOR('o', 83, struct dtv_properties)
+
 
 /**
  * When set, this flag will disable any zigzagging or other "normal" tuning
diff --git a/include/linux/dvb/version.h b/include/linux/dvb/version.h
index 126e0c2..25b823b 100644
--- a/include/linux/dvb/version.h
+++ b/include/linux/dvb/version.h
@@ -23,7 +23,7 @@
 #ifndef _DVBVERSION_H_
 #define _DVBVERSION_H_
 
-#define DVB_API_VERSION 3
-#define DVB_API_VERSION_MINOR 2
+#define DVB_API_VERSION 5
+#define DVB_API_VERSION_MINOR 0
 
 #endif /*_DVBVERSION_H_*/
diff --git a/include/linux/elevator.h b/include/linux/elevator.h
index 639624b..92f6f63 100644
--- a/include/linux/elevator.h
+++ b/include/linux/elevator.h
@@ -112,6 +112,7 @@
 extern int elv_register_queue(struct request_queue *q);
 extern void elv_unregister_queue(struct request_queue *q);
 extern int elv_may_queue(struct request_queue *, int);
+extern void elv_abort_queue(struct request_queue *);
 extern void elv_completed_request(struct request_queue *, struct request *);
 extern int elv_set_request(struct request_queue *, struct request *, gfp_t);
 extern void elv_put_request(struct request_queue *, struct request *);
@@ -173,15 +174,15 @@
 #define rb_entry_rq(node)	rb_entry((node), struct request, rb_node)
 
 /*
- * Hack to reuse the donelist list_head as the fifo time holder while
+ * Hack to reuse the csd.list list_head as the fifo time holder while
  * the request is in the io scheduler. Saves an unsigned long in rq.
  */
-#define rq_fifo_time(rq)	((unsigned long) (rq)->donelist.next)
-#define rq_set_fifo_time(rq,exp)	((rq)->donelist.next = (void *) (exp))
+#define rq_fifo_time(rq)	((unsigned long) (rq)->csd.list.next)
+#define rq_set_fifo_time(rq,exp)	((rq)->csd.list.next = (void *) (exp))
 #define rq_entry_fifo(ptr)	list_entry((ptr), struct request, queuelist)
 #define rq_fifo_clear(rq)	do {		\
 	list_del_init(&(rq)->queuelist);	\
-	INIT_LIST_HEAD(&(rq)->donelist);	\
+	INIT_LIST_HEAD(&(rq)->csd.list);	\
 	} while (0)
 
 /*
diff --git a/include/linux/elf.h b/include/linux/elf.h
index edc3dac..0b61ca4 100644
--- a/include/linux/elf.h
+++ b/include/linux/elf.h
@@ -360,6 +360,7 @@
 #define NT_PPC_SPE	0x101		/* PowerPC SPE/EVR registers */
 #define NT_PPC_VSX	0x102		/* PowerPC VSX registers */
 #define NT_386_TLS	0x200		/* i386 TLS slots (struct user_desc) */
+#define NT_386_IOPERM	0x201		/* x86 io permission bitmap (1=deny) */
 
 
 /* Note header in a PT_NOTE section */
diff --git a/include/linux/ext3_fs.h b/include/linux/ext3_fs.h
index 80171ee..8120fa1 100644
--- a/include/linux/ext3_fs.h
+++ b/include/linux/ext3_fs.h
@@ -837,6 +837,8 @@
 extern void ext3_set_inode_flags(struct inode *);
 extern void ext3_get_inode_flags(struct ext3_inode_info *);
 extern void ext3_set_aops(struct inode *inode);
+extern int ext3_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
+		       u64 start, u64 len);
 
 /* ioctl.c */
 extern int ext3_ioctl (struct inode *, struct file *, unsigned int,
diff --git a/include/linux/fd.h b/include/linux/fd.h
index b6bd41d..f5d194a 100644
--- a/include/linux/fd.h
+++ b/include/linux/fd.h
@@ -15,10 +15,16 @@
 			sect,		/* sectors per track */
 			head,		/* nr of heads */
 			track,		/* nr of tracks */
-			stretch;	/* !=0 means double track steps */
+			stretch;	/* bit 0 !=0 means double track steps */
+					/* bit 1 != 0 means swap sides */
+					/* bits 2..9 give the first sector */
+					/*  number (the LSB is flipped) */
 #define FD_STRETCH 1
 #define FD_SWAPSIDES 2
 #define FD_ZEROBASED 4
+#define FD_SECTBASEMASK 0x3FC
+#define FD_MKSECTBASE(s) (((s) ^ 1) << 2)
+#define FD_SECTBASE(floppy) ((((floppy)->stretch & FD_SECTBASEMASK) >> 2) ^ 1)
 
 	unsigned char	gap,		/* gap1 size */
 
diff --git a/include/linux/fiemap.h b/include/linux/fiemap.h
new file mode 100644
index 0000000..671decb
--- /dev/null
+++ b/include/linux/fiemap.h
@@ -0,0 +1,64 @@
+/*
+ * FS_IOC_FIEMAP ioctl infrastructure.
+ *
+ * Some portions copyright (C) 2007 Cluster File Systems, Inc
+ *
+ * Authors: Mark Fasheh <mfasheh@suse.com>
+ *          Kalpak Shah <kalpak.shah@sun.com>
+ *          Andreas Dilger <adilger@sun.com>
+ */
+
+#ifndef _LINUX_FIEMAP_H
+#define _LINUX_FIEMAP_H
+
+struct fiemap_extent {
+	__u64 fe_logical;  /* logical offset in bytes for the start of
+			    * the extent from the beginning of the file */
+	__u64 fe_physical; /* physical offset in bytes for the start
+			    * of the extent from the beginning of the disk */
+	__u64 fe_length;   /* length in bytes for this extent */
+	__u64 fe_reserved64[2];
+	__u32 fe_flags;    /* FIEMAP_EXTENT_* flags for this extent */
+	__u32 fe_reserved[3];
+};
+
+struct fiemap {
+	__u64 fm_start;		/* logical offset (inclusive) at
+				 * which to start mapping (in) */
+	__u64 fm_length;	/* logical length of mapping which
+				 * userspace wants (in) */
+	__u32 fm_flags;		/* FIEMAP_FLAG_* flags for request (in/out) */
+	__u32 fm_mapped_extents;/* number of extents that were mapped (out) */
+	__u32 fm_extent_count;  /* size of fm_extents array (in) */
+	__u32 fm_reserved;
+	struct fiemap_extent fm_extents[0]; /* array of mapped extents (out) */
+};
+
+#define FIEMAP_MAX_OFFSET	(~0ULL)
+
+#define FIEMAP_FLAG_SYNC	0x00000001 /* sync file data before map */
+#define FIEMAP_FLAG_XATTR	0x00000002 /* map extended attribute tree */
+
+#define FIEMAP_FLAGS_COMPAT	(FIEMAP_FLAG_SYNC | FIEMAP_FLAG_XATTR)
+
+#define FIEMAP_EXTENT_LAST		0x00000001 /* Last extent in file. */
+#define FIEMAP_EXTENT_UNKNOWN		0x00000002 /* Data location unknown. */
+#define FIEMAP_EXTENT_DELALLOC		0x00000004 /* Location still pending.
+						    * Sets EXTENT_UNKNOWN. */
+#define FIEMAP_EXTENT_ENCODED		0x00000008 /* Data can not be read
+						    * while fs is unmounted */
+#define FIEMAP_EXTENT_DATA_ENCRYPTED	0x00000080 /* Data is encrypted by fs.
+						    * Sets EXTENT_NO_BYPASS. */
+#define FIEMAP_EXTENT_NOT_ALIGNED	0x00000100 /* Extent offsets may not be
+						    * block aligned. */
+#define FIEMAP_EXTENT_DATA_INLINE	0x00000200 /* Data mixed with metadata.
+						    * Sets EXTENT_NOT_ALIGNED.*/
+#define FIEMAP_EXTENT_DATA_TAIL		0x00000400 /* Multiple files in block.
+						    * Sets EXTENT_NOT_ALIGNED.*/
+#define FIEMAP_EXTENT_UNWRITTEN		0x00000800 /* Space allocated, but
+						    * no data (i.e. zero). */
+#define FIEMAP_EXTENT_MERGED		0x00001000 /* File does not natively
+						    * support extents. Result
+						    * merged for efficiency. */
+
+#endif /* _LINUX_FIEMAP_H */
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 580b513..a6a625b 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -86,7 +86,9 @@
 #define READ_META	(READ | (1 << BIO_RW_META))
 #define WRITE_SYNC	(WRITE | (1 << BIO_RW_SYNC))
 #define SWRITE_SYNC	(SWRITE | (1 << BIO_RW_SYNC))
-#define WRITE_BARRIER	((1 << BIO_RW) | (1 << BIO_RW_BARRIER))
+#define WRITE_BARRIER	(WRITE | (1 << BIO_RW_BARRIER))
+#define DISCARD_NOBARRIER (1 << BIO_RW_DISCARD)
+#define DISCARD_BARRIER ((1 << BIO_RW_DISCARD) | (1 << BIO_RW_BARRIER))
 
 #define SEL_IN		1
 #define SEL_OUT		2
@@ -222,6 +224,7 @@
 #define BLKTRACESTART _IO(0x12,116)
 #define BLKTRACESTOP _IO(0x12,117)
 #define BLKTRACETEARDOWN _IO(0x12,118)
+#define BLKDISCARD _IO(0x12,119)
 
 #define BMAP_IOCTL 1		/* obsolete - kept for compatibility */
 #define FIBMAP	   _IO(0x00,1)	/* bmap access */
@@ -231,6 +234,7 @@
 #define	FS_IOC_SETFLAGS			_IOW('f', 2, long)
 #define	FS_IOC_GETVERSION		_IOR('v', 1, long)
 #define	FS_IOC_SETVERSION		_IOW('v', 2, long)
+#define FS_IOC_FIEMAP			_IOWR('f', 11, struct fiemap)
 #define FS_IOC32_GETFLAGS		_IOR('f', 1, int)
 #define FS_IOC32_SETFLAGS		_IOW('f', 2, int)
 #define FS_IOC32_GETVERSION		_IOR('v', 1, int)
@@ -291,6 +295,7 @@
 #include <linux/mutex.h>
 #include <linux/capability.h>
 #include <linux/semaphore.h>
+#include <linux/fiemap.h>
 
 #include <asm/atomic.h>
 #include <asm/byteorder.h>
@@ -942,6 +947,14 @@
 	int (*fl_change)(struct file_lock **, int);
 };
 
+struct lock_manager {
+	struct list_head list;
+};
+
+void locks_start_grace(struct lock_manager *);
+void locks_end_grace(struct lock_manager *);
+int locks_in_grace(void);
+
 /* that will die - we need it for nfs_lock_info */
 #include <linux/nfs_fs_i.h>
 
@@ -983,6 +996,13 @@
 
 #include <linux/fcntl.h>
 
+extern void send_sigio(struct fown_struct *fown, int fd, int band);
+
+/* fs/sync.c */
+extern int do_sync_mapping_range(struct address_space *mapping, loff_t offset,
+			loff_t endbyte, unsigned int flags);
+
+#ifdef CONFIG_FILE_LOCKING
 extern int fcntl_getlk(struct file *, struct flock __user *);
 extern int fcntl_setlk(unsigned int, struct file *, unsigned int,
 			struct flock __user *);
@@ -993,14 +1013,9 @@
 			struct flock64 __user *);
 #endif
 
-extern void send_sigio(struct fown_struct *fown, int fd, int band);
 extern int fcntl_setlease(unsigned int fd, struct file *filp, long arg);
 extern int fcntl_getlease(struct file *filp);
 
-/* fs/sync.c */
-extern int do_sync_mapping_range(struct address_space *mapping, loff_t offset,
-			loff_t endbyte, unsigned int flags);
-
 /* fs/locks.c */
 extern void locks_init_lock(struct file_lock *);
 extern void locks_copy_lock(struct file_lock *, struct file_lock *);
@@ -1023,6 +1038,37 @@
 extern int lock_may_read(struct inode *, loff_t start, unsigned long count);
 extern int lock_may_write(struct inode *, loff_t start, unsigned long count);
 extern struct seq_operations locks_seq_operations;
+#else /* !CONFIG_FILE_LOCKING */
+#define fcntl_getlk(a, b) ({ -EINVAL; })
+#define fcntl_setlk(a, b, c, d) ({ -EACCES; })
+#if BITS_PER_LONG == 32
+#define fcntl_getlk64(a, b) ({ -EINVAL; })
+#define fcntl_setlk64(a, b, c, d) ({ -EACCES; })
+#endif
+#define fcntl_setlease(a, b, c) ({ 0; })
+#define fcntl_getlease(a) ({ 0; })
+#define locks_init_lock(a) ({ })
+#define __locks_copy_lock(a, b) ({ })
+#define locks_copy_lock(a, b) ({ })
+#define locks_remove_posix(a, b) ({ })
+#define locks_remove_flock(a) ({ })
+#define posix_test_lock(a, b) ({ 0; })
+#define posix_lock_file(a, b, c) ({ -ENOLCK; })
+#define posix_lock_file_wait(a, b) ({ -ENOLCK; })
+#define posix_unblock_lock(a, b) (-ENOENT)
+#define vfs_test_lock(a, b) ({ 0; })
+#define vfs_lock_file(a, b, c, d) (-ENOLCK)
+#define vfs_cancel_lock(a, b) ({ 0; })
+#define flock_lock_file_wait(a, b) ({ -ENOLCK; })
+#define __break_lease(a, b) ({ 0; })
+#define lease_get_mtime(a, b) ({ })
+#define generic_setlease(a, b, c) ({ -EINVAL; })
+#define vfs_setlease(a, b, c) ({ -EINVAL; })
+#define lease_modify(a, b) ({ -EINVAL; })
+#define lock_may_read(a, b, c) ({ 1; })
+#define lock_may_write(a, b, c) ({ 1; })
+#endif /* !CONFIG_FILE_LOCKING */
+
 
 struct fasync_struct {
 	int	magic;
@@ -1179,6 +1225,20 @@
 extern int file_permission(struct file *, int);
 
 /*
+ * VFS FS_IOC_FIEMAP helper definitions.
+ */
+struct fiemap_extent_info {
+	unsigned int fi_flags;		/* Flags as passed from user */
+	unsigned int fi_extents_mapped;	/* Number of mapped extents */
+	unsigned int fi_extents_max;	/* Size of fiemap_extent array */
+	struct fiemap_extent *fi_extents_start; /* Start of fiemap_extent
+						 * array */
+};
+int fiemap_fill_next_extent(struct fiemap_extent_info *info, u64 logical,
+			    u64 phys, u64 len, u32 flags);
+int fiemap_check_flags(struct fiemap_extent_info *fieinfo, u32 fs_flags);
+
+/*
  * File types
  *
  * NOTE! These match bits 12..15 of stat.st_mode
@@ -1287,6 +1347,8 @@
 	void (*truncate_range)(struct inode *, loff_t, loff_t);
 	long (*fallocate)(struct inode *inode, int mode, loff_t offset,
 			  loff_t len);
+	int (*fiemap)(struct inode *, struct fiemap_extent_info *, u64 start,
+		      u64 len);
 };
 
 struct seq_file;
@@ -1554,9 +1616,12 @@
 /* /sys/fs */
 extern struct kobject *fs_kobj;
 
+extern int rw_verify_area(int, struct file *, loff_t *, size_t);
+
 #define FLOCK_VERIFY_READ  1
 #define FLOCK_VERIFY_WRITE 2
 
+#ifdef CONFIG_FILE_LOCKING
 extern int locks_mandatory_locked(struct inode *);
 extern int locks_mandatory_area(int, struct inode *, struct file *, loff_t, size_t);
 
@@ -1587,8 +1652,6 @@
 	return 0;
 }
 
-extern int rw_verify_area(int, struct file *, loff_t *, size_t);
-
 static inline int locks_verify_truncate(struct inode *inode,
 				    struct file *filp,
 				    loff_t size)
@@ -1609,6 +1672,15 @@
 		return __break_lease(inode, mode);
 	return 0;
 }
+#else /* !CONFIG_FILE_LOCKING */
+#define locks_mandatory_locked(a) ({ 0; })
+#define locks_mandatory_area(a, b, c, d, e) ({ 0; })
+#define __mandatory_lock(a) ({ 0; })
+#define mandatory_lock(a) ({ 0; })
+#define locks_verify_locked(a) ({ 0; })
+#define locks_verify_truncate(a, b, c) ({ 0; })
+#define break_lease(a, b) ({ 0; })
+#endif /* CONFIG_FILE_LOCKING */
 
 /* fs/open.c */
 
@@ -1682,6 +1754,7 @@
 
 /* fs/block_dev.c */
 #define BDEVNAME_SIZE	32	/* Largest string for a blockdev identifier */
+#define BDEVT_SIZE	10	/* Largest string for MAJ:MIN for blkdev */
 
 #ifdef CONFIG_BLOCK
 #define BLKDEV_MAJOR_HASH_SIZE	255
@@ -1718,6 +1791,9 @@
  */
 #define bio_data_dir(bio)	((bio)->bi_rw & 1)
 
+extern void check_disk_size_change(struct gendisk *disk,
+				   struct block_device *bdev);
+extern int revalidate_disk(struct gendisk *);
 extern int check_disk_change(struct block_device *);
 extern int __invalidate_device(struct block_device *);
 extern int invalidate_partition(struct gendisk *, int);
@@ -1980,6 +2056,9 @@
 
 extern int do_vfs_ioctl(struct file *filp, unsigned int fd, unsigned int cmd,
 		    unsigned long arg);
+extern int generic_block_fiemap(struct inode *inode,
+				struct fiemap_extent_info *fieinfo, u64 start,
+				u64 len, get_block_t *get_block);
 
 extern void get_filesystem(struct file_system_type *fs);
 extern void put_filesystem(struct file_system_type *fs);
diff --git a/include/linux/genhd.h b/include/linux/genhd.h
index be4f5e5..206cdf9 100644
--- a/include/linux/genhd.h
+++ b/include/linux/genhd.h
@@ -11,12 +11,15 @@
 
 #include <linux/types.h>
 #include <linux/kdev_t.h>
+#include <linux/rcupdate.h>
 
 #ifdef CONFIG_BLOCK
 
-#define kobj_to_dev(k) container_of(k, struct device, kobj)
-#define dev_to_disk(device) container_of(device, struct gendisk, dev)
-#define dev_to_part(device) container_of(device, struct hd_struct, dev)
+#define kobj_to_dev(k)		container_of((k), struct device, kobj)
+#define dev_to_disk(device)	container_of((device), struct gendisk, part0.__dev)
+#define dev_to_part(device)	container_of((device), struct hd_struct, __dev)
+#define disk_to_dev(disk)	(&(disk)->part0.__dev)
+#define part_to_dev(part)	(&((part)->__dev))
 
 extern struct device_type part_type;
 extern struct kobject *block_depr;
@@ -55,6 +58,9 @@
 	UNIXWARE_PARTITION = 0x63,	/* Same as GNU_HURD and SCO Unix */
 };
 
+#define DISK_MAX_PARTS			256
+#define DISK_NAME_LEN			32
+
 #include <linux/major.h>
 #include <linux/device.h>
 #include <linux/smp.h>
@@ -87,7 +93,7 @@
 struct hd_struct {
 	sector_t start_sect;
 	sector_t nr_sects;
-	struct device dev;
+	struct device __dev;
 	struct kobject *holder_dir;
 	int policy, partno;
 #ifdef CONFIG_FAIL_MAKE_REQUEST
@@ -100,6 +106,7 @@
 #else
 	struct disk_stats dkstats;
 #endif
+	struct rcu_head rcu_head;
 };
 
 #define GENHD_FL_REMOVABLE			1
@@ -108,100 +115,148 @@
 #define GENHD_FL_CD				8
 #define GENHD_FL_UP				16
 #define GENHD_FL_SUPPRESS_PARTITION_INFO	32
-#define GENHD_FL_FAIL				64
+#define GENHD_FL_EXT_DEVT			64 /* allow extended devt */
+
+#define BLK_SCSI_MAX_CMDS	(256)
+#define BLK_SCSI_CMD_PER_LONG	(BLK_SCSI_MAX_CMDS / (sizeof(long) * 8))
+
+struct blk_scsi_cmd_filter {
+	unsigned long read_ok[BLK_SCSI_CMD_PER_LONG];
+	unsigned long write_ok[BLK_SCSI_CMD_PER_LONG];
+	struct kobject kobj;
+};
+
+struct disk_part_tbl {
+	struct rcu_head rcu_head;
+	int len;
+	struct hd_struct *part[];
+};
 
 struct gendisk {
+	/* major, first_minor and minors are input parameters only,
+	 * don't use directly.  Use disk_devt() and disk_max_parts().
+	 */
 	int major;			/* major number of driver */
 	int first_minor;
 	int minors;                     /* maximum number of minors, =1 for
                                          * disks that can't be partitioned. */
-	char disk_name[32];		/* name of major driver */
-	struct hd_struct **part;	/* [indexed by minor] */
+
+	char disk_name[DISK_NAME_LEN];	/* name of major driver */
+
+	/* Array of pointers to partitions indexed by partno.
+	 * Protected with matching bdev lock but stat and other
+	 * non-critical accesses use RCU.  Always access through
+	 * helpers.
+	 */
+	struct disk_part_tbl *part_tbl;
+	struct hd_struct part0;
+
 	struct block_device_operations *fops;
 	struct request_queue *queue;
 	void *private_data;
-	sector_t capacity;
 
 	int flags;
 	struct device *driverfs_dev;  // FIXME: remove
-	struct device dev;
-	struct kobject *holder_dir;
 	struct kobject *slave_dir;
 
 	struct timer_rand_state *random;
-	int policy;
 
 	atomic_t sync_io;		/* RAID */
-	unsigned long stamp;
-	int in_flight;
-#ifdef	CONFIG_SMP
-	struct disk_stats *dkstats;
-#else
-	struct disk_stats dkstats;
-#endif
 	struct work_struct async_notify;
 #ifdef  CONFIG_BLK_DEV_INTEGRITY
 	struct blk_integrity *integrity;
 #endif
+	int node_id;
 };
 
-/* 
- * Macros to operate on percpu disk statistics:
- *
- * The __ variants should only be called in critical sections. The full
- * variants disable/enable preemption.
- */
-static inline struct hd_struct *get_part(struct gendisk *gendiskp,
-					 sector_t sector)
+static inline struct gendisk *part_to_disk(struct hd_struct *part)
 {
-	struct hd_struct *part;
-	int i;
-	for (i = 0; i < gendiskp->minors - 1; i++) {
-		part = gendiskp->part[i];
-		if (part && part->start_sect <= sector
-		    && sector < part->start_sect + part->nr_sects)
-			return part;
+	if (likely(part)) {
+		if (part->partno)
+			return dev_to_disk(part_to_dev(part)->parent);
+		else
+			return dev_to_disk(part_to_dev(part));
 	}
 	return NULL;
 }
 
+static inline int disk_max_parts(struct gendisk *disk)
+{
+	if (disk->flags & GENHD_FL_EXT_DEVT)
+		return DISK_MAX_PARTS;
+	return disk->minors;
+}
+
+static inline bool disk_partitionable(struct gendisk *disk)
+{
+	return disk_max_parts(disk) > 1;
+}
+
+static inline dev_t disk_devt(struct gendisk *disk)
+{
+	return disk_to_dev(disk)->devt;
+}
+
+static inline dev_t part_devt(struct hd_struct *part)
+{
+	return part_to_dev(part)->devt;
+}
+
+extern struct hd_struct *disk_get_part(struct gendisk *disk, int partno);
+
+static inline void disk_put_part(struct hd_struct *part)
+{
+	if (likely(part))
+		put_device(part_to_dev(part));
+}
+
+/*
+ * Smarter partition iterator without context limits.
+ */
+#define DISK_PITER_REVERSE	(1 << 0) /* iterate in the reverse direction */
+#define DISK_PITER_INCL_EMPTY	(1 << 1) /* include 0-sized parts */
+#define DISK_PITER_INCL_PART0	(1 << 2) /* include partition 0 */
+
+struct disk_part_iter {
+	struct gendisk		*disk;
+	struct hd_struct	*part;
+	int			idx;
+	unsigned int		flags;
+};
+
+extern void disk_part_iter_init(struct disk_part_iter *piter,
+				 struct gendisk *disk, unsigned int flags);
+extern struct hd_struct *disk_part_iter_next(struct disk_part_iter *piter);
+extern void disk_part_iter_exit(struct disk_part_iter *piter);
+
+extern struct hd_struct *disk_map_sector_rcu(struct gendisk *disk,
+					     sector_t sector);
+
+/*
+ * Macros to operate on percpu disk statistics:
+ *
+ * {disk|part|all}_stat_{add|sub|inc|dec}() modify the stat counters
+ * and should be called between disk_stat_lock() and
+ * disk_stat_unlock().
+ *
+ * part_stat_read() can be called at any time.
+ *
+ * part_stat_{add|set_all}() and {init|free}_part_stats are for
+ * internal use only.
+ */
 #ifdef	CONFIG_SMP
-#define __disk_stat_add(gendiskp, field, addnd) 	\
-	(per_cpu_ptr(gendiskp->dkstats, smp_processor_id())->field += addnd)
+#define part_stat_lock()	({ rcu_read_lock(); get_cpu(); })
+#define part_stat_unlock()	do { put_cpu(); rcu_read_unlock(); } while (0)
 
-#define disk_stat_read(gendiskp, field)					\
-({									\
-	typeof(gendiskp->dkstats->field) res = 0;			\
-	int i;								\
-	for_each_possible_cpu(i)					\
-		res += per_cpu_ptr(gendiskp->dkstats, i)->field;	\
-	res;								\
-})
-
-static inline void disk_stat_set_all(struct gendisk *gendiskp, int value)	{
-	int i;
-
-	for_each_possible_cpu(i)
-		memset(per_cpu_ptr(gendiskp->dkstats, i), value,
-				sizeof(struct disk_stats));
-}		
-
-#define __part_stat_add(part, field, addnd)				\
-	(per_cpu_ptr(part->dkstats, smp_processor_id())->field += addnd)
-
-#define __all_stat_add(gendiskp, part, field, addnd, sector)	\
-({								\
-	if (part)						\
-		__part_stat_add(part, field, addnd);		\
-	__disk_stat_add(gendiskp, field, addnd);		\
-})
+#define __part_stat_add(cpu, part, field, addnd)			\
+	(per_cpu_ptr((part)->dkstats, (cpu))->field += (addnd))
 
 #define part_stat_read(part, field)					\
 ({									\
-	typeof(part->dkstats->field) res = 0;				\
+	typeof((part)->dkstats->field) res = 0;				\
 	int i;								\
 	for_each_possible_cpu(i)					\
-		res += per_cpu_ptr(part->dkstats, i)->field;		\
+		res += per_cpu_ptr((part)->dkstats, i)->field;		\
 	res;								\
 })
 
@@ -213,108 +268,6 @@
 		memset(per_cpu_ptr(part->dkstats, i), value,
 				sizeof(struct disk_stats));
 }
-				
-#else /* !CONFIG_SMP */
-#define __disk_stat_add(gendiskp, field, addnd) \
-				(gendiskp->dkstats.field += addnd)
-#define disk_stat_read(gendiskp, field)	(gendiskp->dkstats.field)
-
-static inline void disk_stat_set_all(struct gendisk *gendiskp, int value)
-{
-	memset(&gendiskp->dkstats, value, sizeof (struct disk_stats));
-}
-
-#define __part_stat_add(part, field, addnd) \
-	(part->dkstats.field += addnd)
-
-#define __all_stat_add(gendiskp, part, field, addnd, sector)	\
-({								\
-	if (part)						\
-		part->dkstats.field += addnd;			\
-	__disk_stat_add(gendiskp, field, addnd);		\
-})
-
-#define part_stat_read(part, field)	(part->dkstats.field)
-
-static inline void part_stat_set_all(struct hd_struct *part, int value)
-{
-	memset(&part->dkstats, value, sizeof(struct disk_stats));
-}
-
-#endif /* CONFIG_SMP */
-
-#define disk_stat_add(gendiskp, field, addnd)			\
-	do {							\
-		preempt_disable();				\
-		__disk_stat_add(gendiskp, field, addnd);	\
-		preempt_enable();				\
-	} while (0)
-
-#define __disk_stat_dec(gendiskp, field) __disk_stat_add(gendiskp, field, -1)
-#define disk_stat_dec(gendiskp, field) disk_stat_add(gendiskp, field, -1)
-
-#define __disk_stat_inc(gendiskp, field) __disk_stat_add(gendiskp, field, 1)
-#define disk_stat_inc(gendiskp, field) disk_stat_add(gendiskp, field, 1)
-
-#define __disk_stat_sub(gendiskp, field, subnd) \
-		__disk_stat_add(gendiskp, field, -subnd)
-#define disk_stat_sub(gendiskp, field, subnd) \
-		disk_stat_add(gendiskp, field, -subnd)
-
-#define part_stat_add(gendiskp, field, addnd)		\
-	do {						\
-		preempt_disable();			\
-		__part_stat_add(gendiskp, field, addnd);\
-		preempt_enable();			\
-	} while (0)
-
-#define __part_stat_dec(gendiskp, field) __part_stat_add(gendiskp, field, -1)
-#define part_stat_dec(gendiskp, field) part_stat_add(gendiskp, field, -1)
-
-#define __part_stat_inc(gendiskp, field) __part_stat_add(gendiskp, field, 1)
-#define part_stat_inc(gendiskp, field) part_stat_add(gendiskp, field, 1)
-
-#define __part_stat_sub(gendiskp, field, subnd) \
-		__part_stat_add(gendiskp, field, -subnd)
-#define part_stat_sub(gendiskp, field, subnd) \
-		part_stat_add(gendiskp, field, -subnd)
-
-#define all_stat_add(gendiskp, part, field, addnd, sector)	\
-	do {							\
-		preempt_disable();				\
-		__all_stat_add(gendiskp, part, field, addnd, sector);	\
-		preempt_enable();				\
-	} while (0)
-
-#define __all_stat_dec(gendiskp, field, sector) \
-		__all_stat_add(gendiskp, field, -1, sector)
-#define all_stat_dec(gendiskp, field, sector) \
-		all_stat_add(gendiskp, field, -1, sector)
-
-#define __all_stat_inc(gendiskp, part, field, sector) \
-		__all_stat_add(gendiskp, part, field, 1, sector)
-#define all_stat_inc(gendiskp, part, field, sector) \
-		all_stat_add(gendiskp, part, field, 1, sector)
-
-#define __all_stat_sub(gendiskp, part, field, subnd, sector) \
-		__all_stat_add(gendiskp, part, field, -subnd, sector)
-#define all_stat_sub(gendiskp, part, field, subnd, sector) \
-		all_stat_add(gendiskp, part, field, -subnd, sector)
-
-/* Inlines to alloc and free disk stats in struct gendisk */
-#ifdef  CONFIG_SMP
-static inline int init_disk_stats(struct gendisk *disk)
-{
-	disk->dkstats = alloc_percpu(struct disk_stats);
-	if (!disk->dkstats)
-		return 0;
-	return 1;
-}
-
-static inline void free_disk_stats(struct gendisk *disk)
-{
-	free_percpu(disk->dkstats);
-}
 
 static inline int init_part_stats(struct hd_struct *part)
 {
@@ -329,14 +282,18 @@
 	free_percpu(part->dkstats);
 }
 
-#else	/* CONFIG_SMP */
-static inline int init_disk_stats(struct gendisk *disk)
-{
-	return 1;
-}
+#else /* !CONFIG_SMP */
+#define part_stat_lock()	({ rcu_read_lock(); 0; })
+#define part_stat_unlock()	rcu_read_unlock()
 
-static inline void free_disk_stats(struct gendisk *disk)
+#define __part_stat_add(cpu, part, field, addnd)				\
+	((part)->dkstats.field += addnd)
+
+#define part_stat_read(part, field)	((part)->dkstats.field)
+
+static inline void part_stat_set_all(struct hd_struct *part, int value)
 {
+	memset(&part->dkstats, value, sizeof(struct disk_stats));
 }
 
 static inline int init_part_stats(struct hd_struct *part)
@@ -347,37 +304,71 @@
 static inline void free_part_stats(struct hd_struct *part)
 {
 }
-#endif	/* CONFIG_SMP */
+
+#endif /* CONFIG_SMP */
+
+#define part_stat_add(cpu, part, field, addnd)	do {			\
+	__part_stat_add((cpu), (part), field, addnd);			\
+	if ((part)->partno)						\
+		__part_stat_add((cpu), &part_to_disk((part))->part0,	\
+				field, addnd);				\
+} while (0)
+
+#define part_stat_dec(cpu, gendiskp, field)				\
+	part_stat_add(cpu, gendiskp, field, -1)
+#define part_stat_inc(cpu, gendiskp, field)				\
+	part_stat_add(cpu, gendiskp, field, 1)
+#define part_stat_sub(cpu, gendiskp, field, subnd)			\
+	part_stat_add(cpu, gendiskp, field, -subnd)
+
+static inline void part_inc_in_flight(struct hd_struct *part)
+{
+	part->in_flight++;
+	if (part->partno)
+		part_to_disk(part)->part0.in_flight++;
+}
+
+static inline void part_dec_in_flight(struct hd_struct *part)
+{
+	part->in_flight--;
+	if (part->partno)
+		part_to_disk(part)->part0.in_flight--;
+}
 
 /* drivers/block/ll_rw_blk.c */
-extern void disk_round_stats(struct gendisk *disk);
-extern void part_round_stats(struct hd_struct *part);
+extern void part_round_stats(int cpu, struct hd_struct *part);
 
 /* drivers/block/genhd.c */
 extern int get_blkdev_list(char *, int);
 extern void add_disk(struct gendisk *disk);
 extern void del_gendisk(struct gendisk *gp);
 extern void unlink_gendisk(struct gendisk *gp);
-extern struct gendisk *get_gendisk(dev_t dev, int *part);
+extern struct gendisk *get_gendisk(dev_t dev, int *partno);
+extern struct block_device *bdget_disk(struct gendisk *disk, int partno);
 
 extern void set_device_ro(struct block_device *bdev, int flag);
 extern void set_disk_ro(struct gendisk *disk, int flag);
 
+static inline int get_disk_ro(struct gendisk *disk)
+{
+	return disk->part0.policy;
+}
+
 /* drivers/char/random.c */
 extern void add_disk_randomness(struct gendisk *disk);
 extern void rand_initialize_disk(struct gendisk *disk);
 
 static inline sector_t get_start_sect(struct block_device *bdev)
 {
-	return bdev->bd_contains == bdev ? 0 : bdev->bd_part->start_sect;
+	return bdev->bd_part->start_sect;
 }
 static inline sector_t get_capacity(struct gendisk *disk)
 {
-	return disk->capacity;
+	return disk->part0.nr_sects;
 }
 static inline void set_capacity(struct gendisk *disk, sector_t size)
 {
-	disk->capacity = size;
+	disk->part0.nr_sects = size;
 }
 
 #ifdef CONFIG_SOLARIS_X86_PARTITION
@@ -527,9 +518,12 @@
 #define ADDPART_FLAG_RAID	1
 #define ADDPART_FLAG_WHOLEDISK	2
 
-extern dev_t blk_lookup_devt(const char *name, int part);
-extern char *disk_name (struct gendisk *hd, int part, char *buf);
+extern int blk_alloc_devt(struct hd_struct *part, dev_t *devt);
+extern void blk_free_devt(dev_t devt);
+extern dev_t blk_lookup_devt(const char *name, int partno);
+extern char *disk_name (struct gendisk *hd, int partno, char *buf);
 
+extern int disk_expand_part_tbl(struct gendisk *disk, int target);
 extern int rescan_partitions(struct gendisk *disk, struct block_device *bdev);
 extern int __must_check add_partition(struct gendisk *, int, sector_t, sector_t, int);
 extern void delete_partition(struct gendisk *, int);
@@ -546,16 +540,23 @@
 			void *data);
 extern void blk_unregister_region(dev_t devt, unsigned long range);
 
-static inline struct block_device *bdget_disk(struct gendisk *disk, int index)
-{
-	return bdget(MKDEV(disk->major, disk->first_minor) + index);
-}
+extern ssize_t part_size_show(struct device *dev,
+			      struct device_attribute *attr, char *buf);
+extern ssize_t part_stat_show(struct device *dev,
+			      struct device_attribute *attr, char *buf);
+#ifdef CONFIG_FAIL_MAKE_REQUEST
+extern ssize_t part_fail_show(struct device *dev,
+			      struct device_attribute *attr, char *buf);
+extern ssize_t part_fail_store(struct device *dev,
+			       struct device_attribute *attr,
+			       const char *buf, size_t count);
+#endif /* CONFIG_FAIL_MAKE_REQUEST */
 
 #else /* CONFIG_BLOCK */
 
 static inline void printk_all_partitions(void) { }
 
-static inline dev_t blk_lookup_devt(const char *name, int part)
+static inline dev_t blk_lookup_devt(const char *name, int partno)
 {
 	dev_t devt = MKDEV(0, 0);
 	return devt;
diff --git a/include/linux/gfs2_ondisk.h b/include/linux/gfs2_ondisk.h
index c3c19f9..14d0df0 100644
--- a/include/linux/gfs2_ondisk.h
+++ b/include/linux/gfs2_ondisk.h
@@ -118,7 +118,11 @@
 
 	char sb_lockproto[GFS2_LOCKNAME_LEN];
 	char sb_locktable[GFS2_LOCKNAME_LEN];
-	/* In gfs1, quota and license dinodes followed */
+
+	struct gfs2_inum __pad3; /* Was quota inode in gfs1 */
+	struct gfs2_inum __pad4; /* Was licence inode in gfs1 */
+#define GFS2_HAS_UUID 1
+	__u8 sb_uuid[16]; /* The UUID, maybe 0 for backwards compat */
 };
 
 /*
diff --git a/include/linux/hid.h b/include/linux/hid.h
index ac4e678..f13bca2 100644
--- a/include/linux/hid.h
+++ b/include/linux/hid.h
@@ -67,6 +67,7 @@
 #include <linux/types.h>
 #include <linux/slab.h>
 #include <linux/list.h>
+#include <linux/mod_devicetable.h> /* hid_device_id */
 #include <linux/timer.h>
 #include <linux/workqueue.h>
 #include <linux/input.h>
@@ -246,6 +247,19 @@
 #define HID_FEATURE_REPORT	2
 
 /*
+ * HID connect requests
+ */
+
+#define HID_CONNECT_HIDINPUT		0x01
+#define HID_CONNECT_HIDINPUT_FORCE	0x02
+#define HID_CONNECT_HIDRAW		0x04
+#define HID_CONNECT_HIDDEV		0x08
+#define HID_CONNECT_HIDDEV_FORCE	0x10
+#define HID_CONNECT_FF			0x20
+#define HID_CONNECT_DEFAULT	(HID_CONNECT_HIDINPUT|HID_CONNECT_HIDRAW| \
+		HID_CONNECT_HIDDEV|HID_CONNECT_FF)
+
+/*
  * HID device quirks.
  */
 
@@ -256,48 +270,11 @@
 
 #define HID_QUIRK_INVERT			0x00000001
 #define HID_QUIRK_NOTOUCH			0x00000002
-#define HID_QUIRK_IGNORE			0x00000004
 #define HID_QUIRK_NOGET				0x00000008
-#define HID_QUIRK_HIDDEV			0x00000010
 #define HID_QUIRK_BADPAD			0x00000020
 #define HID_QUIRK_MULTI_INPUT			0x00000040
-#define HID_QUIRK_2WHEEL_MOUSE_HACK_7		0x00000080
-#define HID_QUIRK_2WHEEL_MOUSE_HACK_5		0x00000100
-#define HID_QUIRK_2WHEEL_MOUSE_HACK_ON		0x00000200
-#define HID_QUIRK_MIGHTYMOUSE			0x00000400
-#define HID_QUIRK_APPLE_HAS_FN			0x00000800
-#define HID_QUIRK_APPLE_FN_ON			0x00001000
-#define HID_QUIRK_INVERT_HWHEEL			0x00002000
-#define HID_QUIRK_APPLE_ISO_KEYBOARD		0x00004000
-#define HID_QUIRK_BAD_RELATIVE_KEYS		0x00008000
 #define HID_QUIRK_SKIP_OUTPUT_REPORTS		0x00010000
-#define HID_QUIRK_IGNORE_MOUSE			0x00020000
-#define HID_QUIRK_SONY_PS3_CONTROLLER		0x00040000
-#define HID_QUIRK_DUPLICATE_USAGES		0x00080000
-#define HID_QUIRK_RESET_LEDS			0x00100000
-#define HID_QUIRK_HIDINPUT			0x00200000
-#define HID_QUIRK_LOGITECH_IGNORE_DOUBLED_WHEEL	0x00400000
-#define HID_QUIRK_LOGITECH_EXPANDED_KEYMAP	0x00800000
-#define HID_QUIRK_IGNORE_HIDINPUT		0x01000000
-#define HID_QUIRK_2WHEEL_MOUSE_HACK_B8		0x02000000
-#define HID_QUIRK_HWHEEL_WHEEL_INVERT		0x04000000
-#define HID_QUIRK_MICROSOFT_KEYS		0x08000000
 #define HID_QUIRK_FULLSPEED_INTERVAL		0x10000000
-#define HID_QUIRK_APPLE_NUMLOCK_EMULATION	0x20000000
-
-/*
- * Separate quirks for runtime report descriptor fixup
- */
-
-#define HID_QUIRK_RDESC_CYMOTION		0x00000001
-#define HID_QUIRK_RDESC_LOGITECH		0x00000002
-#define HID_QUIRK_RDESC_SWAPPED_MIN_MAX		0x00000004
-#define HID_QUIRK_RDESC_PETALYNX		0x00000008
-#define HID_QUIRK_RDESC_MACBOOK_JIS		0x00000010
-#define HID_QUIRK_RDESC_BUTTON_CONSUMER		0x00000020
-#define HID_QUIRK_RDESC_SAMSUNG_REMOTE		0x00000040
-#define HID_QUIRK_RDESC_MICROSOFT_RECV_1028	0x00000080
-#define HID_QUIRK_RDESC_SUNPLUS_WDESKTOP	0x00000100
 
 /*
  * This is the global environment of the parser. This information is
@@ -411,12 +388,21 @@
 struct hid_control_fifo {
 	unsigned char dir;
 	struct hid_report *report;
+	char *raw_report;
+};
+
+struct hid_output_fifo {
+	struct hid_report *report;
+	char *raw_report;
 };
 
 #define HID_CLAIMED_INPUT	1
 #define HID_CLAIMED_HIDDEV	2
 #define HID_CLAIMED_HIDRAW	4
 
+#define HID_STAT_ADDED		1
+#define HID_STAT_PARSED		2
+
 #define HID_CTRL_RUNNING	1
 #define HID_OUT_RUNNING		2
 #define HID_IN_RUNNING		3
@@ -431,22 +417,28 @@
 	struct input_dev *input;
 };
 
+struct hid_driver;
+struct hid_ll_driver;
+
 struct hid_device {							/* device report descriptor */
-	 __u8 *rdesc;
+	__u8 *rdesc;
 	unsigned rsize;
 	struct hid_collection *collection;				/* List of HID collections */
 	unsigned collection_size;					/* Number of allocated hid_collections */
 	unsigned maxcollection;						/* Number of parsed collections */
 	unsigned maxapplication;					/* Number of applications */
-	unsigned short bus;                                             /* BUS ID */
-	unsigned short vendor;                                          /* Vendor ID */
-	unsigned short product;                                         /* Product ID */
-	unsigned version;						/* HID version */
+	__u16 bus;							/* BUS ID */
+	__u32 vendor;							/* Vendor ID */
+	__u32 product;							/* Product ID */
+	__u32 version;							/* HID version */
 	unsigned country;						/* HID country */
 	struct hid_report_enum report_enum[HID_REPORT_TYPES];
 
-	struct device *dev;						/* device */
+	struct device dev;						/* device */
+	struct hid_driver *driver;
+	struct hid_ll_driver *ll_driver;
 
+	unsigned int status;						/* see STAT flags above */
 	unsigned claimed;						/* Claimed by hidinput, hiddev? */
 	unsigned quirks;						/* Various quirks the device can pull on us */
 
@@ -462,26 +454,29 @@
 
 	void *driver_data;
 
-	__s32 delayed_value;						/* For A4 Tech mice hwheel quirk */
-
-	/* device-specific function pointers */
-	int (*hidinput_input_event) (struct input_dev *, unsigned int, unsigned int, int);
-	int (*hid_open) (struct hid_device *);
-	void (*hid_close) (struct hid_device *);
+	/* temporary hid_ff handling (until moved to the drivers) */
+	int (*ff_init)(struct hid_device *);
 
 	/* hiddev event handler */
+	int (*hiddev_connect)(struct hid_device *, unsigned int);
 	void (*hiddev_hid_event) (struct hid_device *, struct hid_field *field,
 				  struct hid_usage *, __s32);
 	void (*hiddev_report_event) (struct hid_device *, struct hid_report *);
 
 	/* handler for raw output data, used by hidraw */
 	int (*hid_output_raw_report) (struct hid_device *, __u8 *, size_t);
-#ifdef CONFIG_USB_HIDINPUT_POWERBOOK
-	unsigned long apple_pressed_fn[BITS_TO_LONGS(KEY_CNT)];
-	unsigned long pb_pressed_numlock[BITS_TO_LONGS(KEY_CNT)];
-#endif
 };
 
+static inline void *hid_get_drvdata(struct hid_device *hdev)
+{
+	return dev_get_drvdata(&hdev->dev);
+}
+
+static inline void hid_set_drvdata(struct hid_device *hdev, void *data)
+{
+	dev_set_drvdata(&hdev->dev, data);
+}
+
 #define HID_GLOBAL_STACK_SIZE 4
 #define HID_COLLECTION_STACK_SIZE 4
 
@@ -510,6 +505,107 @@
 	struct hid_class_descriptor desc[1];
 } __attribute__ ((packed));
 
+#define HID_DEVICE(b, ven, prod) \
+	.bus = (b), \
+	.vendor = (ven), .product = (prod)
+
+#define HID_USB_DEVICE(ven, prod)	HID_DEVICE(BUS_USB, ven, prod)
+#define HID_BLUETOOTH_DEVICE(ven, prod)	HID_DEVICE(BUS_BLUETOOTH, ven, prod)
+
+#define HID_REPORT_ID(rep) \
+	.report_type = (rep)
+#define HID_USAGE_ID(uhid, utype, ucode) \
+	.usage_hid = (uhid), .usage_type = (utype), .usage_code = (ucode)
+/* we don't want to catch types and codes equal to 0 */
+#define HID_TERMINATOR		(HID_ANY_ID - 1)
+
+struct hid_report_id {
+	__u32 report_type;
+};
+struct hid_usage_id {
+	__u32 usage_hid;
+	__u32 usage_type;
+	__u32 usage_code;
+};
+
+/**
+ * struct hid_driver
+ * @name: driver name (e.g. "Footech_bar-wheel")
+ * @id_table: which devices is this driver for (must be non-NULL for probe
+ * 	      to be called)
+ * @probe: new device inserted
+ * @remove: device removed (NULL if not a hot-plug capable driver)
+ * @report_table: on which reports to call raw_event (NULL means all)
+ * @raw_event: if report in report_table, this hook is called (NULL means nop)
+ * @usage_table: on which events to call event (NULL means all)
+ * @event: if usage in usage_table, this hook is called (NULL means nop)
+ * @report_fixup: called before report descriptor parsing (NULL means nop)
+ * @input_mapping: invoked on input registering before mapping an usage
+ * @input_mapped: invoked on input registering after mapping an usage
+ *
+ * raw_event and event should return 0 on no action performed, 1 when no
+ * further processing should be done and negative on error
+ *
+ * input_mapping shall return a negative value to completely ignore this usage
+ * (e.g. doubled or invalid usage), zero to continue with parsing of this
+ * usage by generic code (no special handling needed) or positive to skip
+ * generic parsing (needed special handling which was done in the hook already)
+ * input_mapped shall return negative to inform the layer that this usage
+ * should not be considered for further processing or zero to notify that
+ * no processing was performed and should be done in a generic manner
+ * Both these functions may be NULL which means the same behavior as returning
+ * zero from them.
+ */
+struct hid_driver {
+	char *name;
+	const struct hid_device_id *id_table;
+
+	int (*probe)(struct hid_device *dev, const struct hid_device_id *id);
+	void (*remove)(struct hid_device *dev);
+
+	const struct hid_report_id *report_table;
+	int (*raw_event)(struct hid_device *hdev, struct hid_report *report,
+			u8 *data, int size);
+	const struct hid_usage_id *usage_table;
+	int (*event)(struct hid_device *hdev, struct hid_field *field,
+			struct hid_usage *usage, __s32 value);
+
+	void (*report_fixup)(struct hid_device *hdev, __u8 *buf,
+			unsigned int size);
+
+	int (*input_mapping)(struct hid_device *hdev,
+			struct hid_input *hidinput, struct hid_field *field,
+			struct hid_usage *usage, unsigned long **bit, int *max);
+	int (*input_mapped)(struct hid_device *hdev,
+			struct hid_input *hidinput, struct hid_field *field,
+			struct hid_usage *usage, unsigned long **bit, int *max);
+/* private: */
+	struct device_driver driver;
+};
+
+/**
+ * hid_ll_driver - low level driver callbacks
+ * @start: called on probe to start the device
+ * @stop: called on remove
+ * @open: called by input layer on open
+ * @close: called by input layer on close
+ * @hidinput_input_event: event input event (e.g. ff or leds)
+ * @parse: this method is called only once to parse the device data,
+ *	   shouldn't allocate anything to not leak memory
+ */
+struct hid_ll_driver {
+	int (*start)(struct hid_device *hdev);
+	void (*stop)(struct hid_device *hdev);
+
+	int (*open)(struct hid_device *hdev);
+	void (*close)(struct hid_device *hdev);
+
+	int (*hidinput_input_event) (struct input_dev *idev, unsigned int type,
+			unsigned int code, int value);
+
+	int (*parse)(struct hid_device *hdev);
+};
+
 /* Applications from HID Usage Tables 4/8/99 Version 1.1 */
 /* We ignore a few input applications that are not widely used */
 #define IS_INPUT_APPLICATION(a) (((a >= 0x00010000) && (a <= 0x00010008)) || (a == 0x00010080) || (a == 0x000c0001) || (a == 0x000d0002))
@@ -520,43 +616,157 @@
 extern int hid_debug;
 #endif
 
+extern int hid_add_device(struct hid_device *);
+extern void hid_destroy_device(struct hid_device *);
+
+extern int __must_check __hid_register_driver(struct hid_driver *,
+		struct module *, const char *mod_name);
+static inline int __must_check hid_register_driver(struct hid_driver *driver)
+{
+	return __hid_register_driver(driver, THIS_MODULE, KBUILD_MODNAME);
+}
+extern void hid_unregister_driver(struct hid_driver *);
+
 extern void hidinput_hid_event(struct hid_device *, struct hid_field *, struct hid_usage *, __s32);
 extern void hidinput_report_event(struct hid_device *hid, struct hid_report *report);
-extern int hidinput_connect(struct hid_device *);
+extern int hidinput_connect(struct hid_device *hid, unsigned int force);
 extern void hidinput_disconnect(struct hid_device *);
 
 int hid_set_field(struct hid_field *, unsigned, __s32);
 int hid_input_report(struct hid_device *, int type, u8 *, int, int);
 int hidinput_find_field(struct hid_device *hid, unsigned int type, unsigned int code, struct hid_field **field);
-int hidinput_mapping_quirks(struct hid_usage *, struct input_dev *, unsigned long **, int *);
-int hidinput_event_quirks(struct hid_device *, struct hid_field *, struct hid_usage *, __s32);
-int hidinput_apple_event(struct hid_device *, struct input_dev *, struct hid_usage *, __s32);
 void hid_output_report(struct hid_report *report, __u8 *data);
-void hid_free_device(struct hid_device *device);
-struct hid_device *hid_parse_report(__u8 *start, unsigned size);
+struct hid_device *hid_allocate_device(void);
+int hid_parse_report(struct hid_device *hid, __u8 *start, unsigned size);
+int hid_connect(struct hid_device *hid, unsigned int connect_mask);
+
+/**
+ * hid_map_usage - map usage input bits
+ *
+ * @hidinput: hidinput which we are interested in
+ * @usage: usage to fill in
+ * @bit: pointer to input->{}bit (out parameter)
+ * @max: maximal valid usage->code to consider later (out parameter)
+ * @type: input event type (EV_KEY, EV_REL, ...)
+ * @c: code which corresponds to this usage and type
+ */
+static inline void hid_map_usage(struct hid_input *hidinput,
+		struct hid_usage *usage, unsigned long **bit, int *max,
+		__u8 type, __u16 c)
+{
+	struct input_dev *input = hidinput->input;
+
+	usage->type = type;
+	usage->code = c;
+
+	switch (type) {
+	case EV_ABS:
+		*bit = input->absbit;
+		*max = ABS_MAX;
+		break;
+	case EV_REL:
+		*bit = input->relbit;
+		*max = REL_MAX;
+		break;
+	case EV_KEY:
+		*bit = input->keybit;
+		*max = KEY_MAX;
+		break;
+	case EV_LED:
+		*bit = input->ledbit;
+		*max = LED_MAX;
+		break;
+	}
+}
+
+/**
+ * hid_map_usage_clear - map usage input bits and clear the input bit
+ *
+ * The same as hid_map_usage, except the @c bit is also cleared in supported
+ * bits (@bit).
+ */
+static inline void hid_map_usage_clear(struct hid_input *hidinput,
+		struct hid_usage *usage, unsigned long **bit, int *max,
+		__u8 type, __u16 c)
+{
+	hid_map_usage(hidinput, usage, bit, max, type, c);
+	clear_bit(c, *bit);
+}
+
+/**
+ * hid_parse - parse HW reports
+ *
+ * @hdev: hid device
+ *
+ * Call this from probe after you set up the device (if needed). Your
+ * report_fixup will be called (if non-NULL) after reading raw report from
+ * device before passing it to hid layer for real parsing.
+ */
+static inline int __must_check hid_parse(struct hid_device *hdev)
+{
+	int ret;
+
+	if (hdev->status & HID_STAT_PARSED)
+		return 0;
+
+	ret = hdev->ll_driver->parse(hdev);
+	if (!ret)
+		hdev->status |= HID_STAT_PARSED;
+
+	return ret;
+}
+
+/**
+ * hid_hw_start - start underlaying HW
+ *
+ * @hdev: hid device
+ * @connect_mask: which outputs to connect, see HID_CONNECT_*
+ *
+ * Call this in probe function *after* hid_parse. This will setup HW buffers
+ * and start the device (if not deffered to device open). hid_hw_stop must be
+ * called if this was successfull.
+ */
+static inline int __must_check hid_hw_start(struct hid_device *hdev,
+		unsigned int connect_mask)
+{
+	int ret = hdev->ll_driver->start(hdev);
+	if (ret || !connect_mask)
+		return ret;
+	ret = hid_connect(hdev, connect_mask);
+	if (ret)
+		hdev->ll_driver->stop(hdev);
+	return ret;
+}
+
+/**
+ * hid_hw_stop - stop underlaying HW
+ *
+ * @hdev: hid device
+ *
+ * This is usually called from remove function or from probe when something
+ * failed and hid_hw_start was called already.
+ */
+static inline void hid_hw_stop(struct hid_device *hdev)
+{
+	hdev->ll_driver->stop(hdev);
+}
+
+void hid_report_raw_event(struct hid_device *hid, int type, u8 *data, int size,
+		int interrupt);
+
+extern int hid_generic_init(void);
+extern void hid_generic_exit(void);
 
 /* HID quirks API */
 u32 usbhid_lookup_quirk(const u16 idVendor, const u16 idProduct);
 int usbhid_quirks_init(char **quirks_param);
 void usbhid_quirks_exit(void);
-void usbhid_fixup_report_descriptor(const u16, const u16, char *, unsigned, char **);
+void usbhid_set_leds(struct hid_device *hid);
 
-#ifdef CONFIG_HID_FF
-int hid_ff_init(struct hid_device *hid);
-
-int hid_lgff_init(struct hid_device *hid);
-int hid_lg2ff_init(struct hid_device *hid);
-int hid_plff_init(struct hid_device *hid);
-int hid_tmff_init(struct hid_device *hid);
-int hid_zpff_init(struct hid_device *hid);
 #ifdef CONFIG_HID_PID
 int hid_pidff_init(struct hid_device *hid);
 #else
-static inline int hid_pidff_init(struct hid_device *hid) { return -ENODEV; }
-#endif
-
-#else
-static inline int hid_ff_init(struct hid_device *hid) { return -1; }
+#define hid_pidff_init NULL
 #endif
 
 #ifdef CONFIG_HID_DEBUG
@@ -572,10 +782,23 @@
 	return 0;
 }
 #define dbg_hid_line dbg_hid
-#endif
+#endif /* HID_DEBUG */
 
 #define err_hid(format, arg...) printk(KERN_ERR "%s: " format "\n" , \
 		__FILE__ , ## arg)
-#endif
+#endif /* HID_FF */
+
+#ifdef CONFIG_HID_COMPAT
+#define HID_COMPAT_LOAD_DRIVER(name)	\
+void hid_compat_##name(void) { }	\
+EXPORT_SYMBOL(hid_compat_##name)
+#else
+#define HID_COMPAT_LOAD_DRIVER(name)
+#endif /* HID_COMPAT */
+#define HID_COMPAT_CALL_DRIVER(name)	do {	\
+	extern void hid_compat_##name(void);	\
+	hid_compat_##name();			\
+} while (0)
+
 #endif
 
diff --git a/include/linux/hiddev.h b/include/linux/hiddev.h
index a416b90..c760ae0 100644
--- a/include/linux/hiddev.h
+++ b/include/linux/hiddev.h
@@ -182,26 +182,28 @@
 /* To traverse the input report descriptor info for a HID device, perform the 
  * following:
  *
- *  rinfo.report_type = HID_REPORT_TYPE_INPUT;
- *  rinfo.report_id = HID_REPORT_ID_FIRST;
- *  ret = ioctl(fd, HIDIOCGREPORTINFO, &rinfo);
+ * rinfo.report_type = HID_REPORT_TYPE_INPUT;
+ * rinfo.report_id = HID_REPORT_ID_FIRST;
+ * ret = ioctl(fd, HIDIOCGREPORTINFO, &rinfo);
  *
- *  while (ret >= 0) {
- *      for (i = 0; i < rinfo.num_fields; i++) { 
- *	    finfo.report_type = rinfo.report_type;
- *          finfo.report_id = rinfo.report_id;
- *          finfo.field_index = i;
- *          ioctl(fd, HIDIOCGFIELDINFO, &finfo);
- *          for (j = 0; j < finfo.maxusage; j++) {
- *              uref.field_index = i;
- *		uref.usage_index = j;
- *		ioctl(fd, HIDIOCGUCODE, &uref);
- *		ioctl(fd, HIDIOCGUSAGE, &uref);
- *          }
- *	}
- *	rinfo.report_id |= HID_REPORT_ID_NEXT;
- *	ret = ioctl(fd, HIDIOCGREPORTINFO, &rinfo);
- *  }
+ * while (ret >= 0) {
+ * 	for (i = 0; i < rinfo.num_fields; i++) {
+ * 		finfo.report_type = rinfo.report_type;
+ * 		finfo.report_id = rinfo.report_id;
+ * 		finfo.field_index = i;
+ * 		ioctl(fd, HIDIOCGFIELDINFO, &finfo);
+ * 		for (j = 0; j < finfo.maxusage; j++) {
+ * 			uref.report_type = rinfo.report_type;
+ * 			uref.report_id = rinfo.report_id;
+ * 			uref.field_index = i;
+ * 			uref.usage_index = j;
+ * 			ioctl(fd, HIDIOCGUCODE, &uref);
+ * 			ioctl(fd, HIDIOCGUSAGE, &uref);
+ * 		}
+ * 	}
+ * 	rinfo.report_id |= HID_REPORT_ID_NEXT;
+ * 	ret = ioctl(fd, HIDIOCGREPORTINFO, &rinfo);
+ * }
  */
 
 
@@ -217,7 +219,7 @@
 struct hid_report;
 
 #ifdef CONFIG_USB_HIDDEV
-int hiddev_connect(struct hid_device *);
+int hiddev_connect(struct hid_device *hid, unsigned int force);
 void hiddev_disconnect(struct hid_device *);
 void hiddev_hid_event(struct hid_device *hid, struct hid_field *field,
 		      struct hid_usage *usage, __s32 value);
@@ -225,7 +227,9 @@
 int __init hiddev_init(void);
 void hiddev_exit(void);
 #else
-static inline int hiddev_connect(struct hid_device *hid) { return -1; }
+static inline int hiddev_connect(struct hid_device *hid,
+		unsigned int force)
+{ return -1; }
 static inline void hiddev_disconnect(struct hid_device *hid) { }
 static inline void hiddev_hid_event(struct hid_device *hid, struct hid_field *field,
 		      struct hid_usage *usage, __s32 value) { }
diff --git a/include/linux/hpet.h b/include/linux/hpet.h
index 2dc29ce..79f63a2 100644
--- a/include/linux/hpet.h
+++ b/include/linux/hpet.h
@@ -37,6 +37,7 @@
 #define	hpet_compare	_u1._hpet_compare
 
 #define	HPET_MAX_TIMERS	(32)
+#define	HPET_MAX_IRQ	(32)
 
 /*
  * HPET general capabilities register
@@ -64,7 +65,7 @@
  */
 
 #define	Tn_INT_ROUTE_CAP_MASK		(0xffffffff00000000ULL)
-#define	Tn_INI_ROUTE_CAP_SHIFT		(32UL)
+#define	Tn_INT_ROUTE_CAP_SHIFT		(32UL)
 #define	Tn_FSB_INT_DELCAP_MASK		(0x8000UL)
 #define	Tn_FSB_INT_DELCAP_SHIFT		(15)
 #define	Tn_FSB_EN_CNF_MASK		(0x4000UL)
@@ -91,23 +92,14 @@
  * exported interfaces
  */
 
-struct hpet_task {
-	void (*ht_func) (void *);
-	void *ht_data;
-	void *ht_opaque;
-};
-
 struct hpet_data {
 	unsigned long hd_phys_address;
 	void __iomem *hd_address;
 	unsigned short hd_nirqs;
-	unsigned short hd_flags;
 	unsigned int hd_state;	/* timer allocated */
 	unsigned int hd_irq[HPET_MAX_TIMERS];
 };
 
-#define	HPET_DATA_PLATFORM	0x0001	/* platform call to hpet_alloc */
-
 static inline void hpet_reserve_timer(struct hpet_data *hd, int timer)
 {
 	hd->hd_state |= (1 << timer);
@@ -125,7 +117,7 @@
 	unsigned short hi_timer;
 };
 
-#define	HPET_INFO_PERIODIC	0x0001	/* timer is periodic */
+#define HPET_INFO_PERIODIC	0x0010	/* periodic-capable comparator */
 
 #define	HPET_IE_ON	_IO('h', 0x01)	/* interrupt on */
 #define	HPET_IE_OFF	_IO('h', 0x02)	/* interrupt off */
diff --git a/include/linux/hrtimer.h b/include/linux/hrtimer.h
index 6d93dce..2f245fe 100644
--- a/include/linux/hrtimer.h
+++ b/include/linux/hrtimer.h
@@ -47,14 +47,22 @@
  *	HRTIMER_CB_IRQSAFE:		Callback may run in hardirq context
  *	HRTIMER_CB_IRQSAFE_NO_RESTART:	Callback may run in hardirq context and
  *					does not restart the timer
- *	HRTIMER_CB_IRQSAFE_NO_SOFTIRQ:	Callback must run in hardirq context
- *					Special mode for tick emultation
+ *	HRTIMER_CB_IRQSAFE_PERCPU:	Callback must run in hardirq context
+ *					Special mode for tick emulation and
+ *					scheduler timer. Such timers are per
+ *					cpu and not allowed to be migrated on
+ *					cpu unplug.
+ *	HRTIMER_CB_IRQSAFE_UNLOCKED:	Callback should run in hardirq context
+ *					with timer->base lock unlocked
+ *					used for timers which call wakeup to
+ *					avoid lock order problems with rq->lock
  */
 enum hrtimer_cb_mode {
 	HRTIMER_CB_SOFTIRQ,
 	HRTIMER_CB_IRQSAFE,
 	HRTIMER_CB_IRQSAFE_NO_RESTART,
-	HRTIMER_CB_IRQSAFE_NO_SOFTIRQ,
+	HRTIMER_CB_IRQSAFE_PERCPU,
+	HRTIMER_CB_IRQSAFE_UNLOCKED,
 };
 
 /*
@@ -67,9 +75,10 @@
  * 0x02		callback function running
  * 0x04		callback pending (high resolution mode)
  *
- * Special case:
+ * Special cases:
  * 0x03		callback function running and enqueued
  *		(was requeued on another CPU)
+ * 0x09		timer was migrated on CPU hotunplug
  * The "callback function running and enqueued" status is only possible on
  * SMP. It happens for example when a posix timer expired and the callback
  * queued a signal. Between dropping the lock which protects the posix timer
@@ -87,6 +96,7 @@
 #define HRTIMER_STATE_ENQUEUED	0x01
 #define HRTIMER_STATE_CALLBACK	0x02
 #define HRTIMER_STATE_PENDING	0x04
+#define HRTIMER_STATE_MIGRATE	0x08
 
 /**
  * struct hrtimer - the basic hrtimer structure
diff --git a/include/linux/i2c-id.h b/include/linux/i2c-id.h
index bf34c5f..493435b 100644
--- a/include/linux/i2c-id.h
+++ b/include/linux/i2c-id.h
@@ -41,7 +41,6 @@
 #define I2C_DRIVERID_SAA7110	22	/* video decoder		*/
 #define I2C_DRIVERID_SAA5249	24	/* SAA5249 and compatibles	*/
 #define I2C_DRIVERID_PCF8583	25	/* real time clock		*/
-#define I2C_DRIVERID_SAB3036	26	/* SAB3036 tuner		*/
 #define I2C_DRIVERID_TDA7432	27	/* Stereo sound processor	*/
 #define I2C_DRIVERID_TVMIXER    28      /* Mixer driver for tv cards    */
 #define I2C_DRIVERID_TVAUDIO    29      /* Generic TV sound driver      */
diff --git a/include/linux/ide.h b/include/linux/ide.h
index 1524829..c47e371 100644
--- a/include/linux/ide.h
+++ b/include/linux/ide.h
@@ -8,7 +8,7 @@
 
 #include <linux/init.h>
 #include <linux/ioport.h>
-#include <linux/hdreg.h>
+#include <linux/ata.h>
 #include <linux/blkdev.h>
 #include <linux/proc_fs.h>
 #include <linux/interrupt.h>
@@ -17,6 +17,7 @@
 #include <linux/device.h>
 #include <linux/pci.h>
 #include <linux/completion.h>
+#include <linux/pm.h>
 #ifdef CONFIG_BLK_DEV_IDEACPI
 #include <acpi/acpi.h>
 #endif
@@ -47,12 +48,6 @@
 #define ERROR_RESET	3	/* Reset controller every 4th retry */
 #define ERROR_RECAL	1	/* Recalibrate every 2nd retry */
 
-/*
- * state flags
- */
-
-#define DMA_PIO_RETRY	1	/* retrying in PIO */
-
 #define HWIF(drive)		((ide_hwif_t *)((drive)->hwif))
 #define HWGROUP(drive)		((ide_hwgroup_t *)(HWIF(drive)->hwgroup))
 
@@ -87,12 +82,13 @@
 };
 
 #define OK_STAT(stat,good,bad)	(((stat)&((good)|(bad)))==(good))
-#define BAD_R_STAT		(BUSY_STAT   | ERR_STAT)
-#define BAD_W_STAT		(BAD_R_STAT  | WRERR_STAT)
-#define BAD_STAT		(BAD_R_STAT  | DRQ_STAT)
-#define DRIVE_READY		(READY_STAT  | SEEK_STAT)
 
-#define BAD_CRC			(ABRT_ERR    | ICRC_ERR)
+#define BAD_R_STAT	(ATA_BUSY | ATA_ERR)
+#define BAD_W_STAT	(BAD_R_STAT | ATA_DF)
+#define BAD_STAT	(BAD_R_STAT | ATA_DRQ)
+#define DRIVE_READY	(ATA_DRDY | ATA_DSC)
+
+#define BAD_CRC		(ATA_ABORTED | ATA_ICRC)
 
 #define SATA_NR_PORTS		(3)	/* 16 possible ?? */
 
@@ -125,24 +121,43 @@
 #define PARTN_BITS	6	/* number of minor dev bits for partitions */
 #define MAX_DRIVES	2	/* per interface; 2 assumed by lots of code */
 #define SECTOR_SIZE	512
-#define SECTOR_WORDS	(SECTOR_SIZE / 4)	/* number of 32bit words per sector */
+
 #define IDE_LARGE_SEEK(b1,b2,t)	(((b1) > (b2) + (t)) || ((b2) > (b1) + (t)))
 
 /*
  * Timeouts for various operations:
  */
-#define WAIT_DRQ	(HZ/10)		/* 100msec - spec allows up to 20ms */
-#define WAIT_READY	(5*HZ)		/* 5sec - some laptops are very slow */
-#define WAIT_PIDENTIFY	(10*HZ)	/* 10sec  - should be less than 3ms (?), if all ATAPI CD is closed at boot */
-#define WAIT_WORSTCASE	(30*HZ)	/* 30sec  - worst case when spinning up */
-#define WAIT_CMD	(10*HZ)	/* 10sec  - maximum wait for an IRQ to happen */
-#define WAIT_MIN_SLEEP	(2*HZ/100)	/* 20msec - minimum sleep time */
+enum {
+	/* spec allows up to 20ms */
+	WAIT_DRQ	= HZ / 10,	/* 100ms */
+	/* some laptops are very slow */
+	WAIT_READY	= 5 * HZ,	/* 5s */
+	/* should be less than 3ms (?), if all ATAPI CD is closed at boot */
+	WAIT_PIDENTIFY	= 10 * HZ,	/* 10s */
+	/* worst case when spinning up */
+	WAIT_WORSTCASE	= 30 * HZ,	/* 30s */
+	/* maximum wait for an IRQ to happen */
+	WAIT_CMD	= 10 * HZ,	/* 10s */
+	/* Some drives require a longer IRQ timeout. */
+	WAIT_FLOPPY_CMD	= 50 * HZ,	/* 50s */
+	/*
+	 * Some drives (for example, Seagate STT3401A Travan) require a very
+	 * long timeout, because they don't return an interrupt or clear their
+	 * BSY bit until after the command completes (even retension commands).
+	 */
+	WAIT_TAPE_CMD	= 900 * HZ,	/* 900s */
+	/* minimum sleep time */
+	WAIT_MIN_SLEEP	= HZ / 50,	/* 20ms */
+};
 
 /*
  * Op codes for special requests to be handled by ide_special_rq().
  * Values should be in the range of 0x20 to 0x3f.
  */
 #define REQ_DRIVE_RESET		0x20
+#define REQ_DEVSET_EXEC		0x21
+#define REQ_PARK_HEADS		0x22
+#define REQ_UNPARK_HEADS	0x23
 
 /*
  * Check for an interrupt and acknowledge the interrupt status
@@ -249,8 +264,6 @@
  * set_geometry	: respecify drive geometry
  * recalibrate	: seek to cyl 0
  * set_multmode	: set multmode count
- * set_tune	: tune interface for drive
- * serviced	: service command
  * reserved	: unused
  */
 typedef union {
@@ -259,43 +272,11 @@
 		unsigned set_geometry	: 1;
 		unsigned recalibrate	: 1;
 		unsigned set_multmode	: 1;
-		unsigned set_tune	: 1;
-		unsigned serviced	: 1;
-		unsigned reserved	: 3;
+		unsigned reserved	: 5;
 	} b;
 } special_t;
 
 /*
- * ATA-IDE Select Register, aka Device-Head
- *
- * head		: always zeros here
- * unit		: drive select number: 0/1
- * bit5		: always 1
- * lba		: using LBA instead of CHS
- * bit7		: always 1
- */
-typedef union {
-	unsigned all			: 8;
-	struct {
-#if defined(__LITTLE_ENDIAN_BITFIELD)
-		unsigned head		: 4;
-		unsigned unit		: 1;
-		unsigned bit5		: 1;
-		unsigned lba		: 1;
-		unsigned bit7		: 1;
-#elif defined(__BIG_ENDIAN_BITFIELD)
-		unsigned bit7		: 1;
-		unsigned lba		: 1;
-		unsigned bit5		: 1;
-		unsigned unit		: 1;
-		unsigned head		: 4;
-#else
-#error "Please fix <asm/byteorder.h>"
-#endif
-	} b;
-} select_t, ata_select_t;
-
-/*
  * Status returned from various ide_ functions
  */
 typedef enum {
@@ -303,633 +284,6 @@
 	ide_started,	/* a drive operation was started, handler was set */
 } ide_startstop_t;
 
-struct ide_driver_s;
-struct ide_settings_s;
-
-#ifdef CONFIG_BLK_DEV_IDEACPI
-struct ide_acpi_drive_link;
-struct ide_acpi_hwif_link;
-#endif
-
-/* ATAPI device flags */
-enum {
-	IDE_AFLAG_DRQ_INTERRUPT		= (1 << 0),
-	IDE_AFLAG_MEDIA_CHANGED		= (1 << 1),
-
-	/* ide-cd */
-	/* Drive cannot lock the door. */
-	IDE_AFLAG_NO_DOORLOCK		= (1 << 2),
-	/* Drive cannot eject the disc. */
-	IDE_AFLAG_NO_EJECT		= (1 << 3),
-	/* Drive is a pre ATAPI 1.2 drive. */
-	IDE_AFLAG_PRE_ATAPI12		= (1 << 4),
-	/* TOC addresses are in BCD. */
-	IDE_AFLAG_TOCADDR_AS_BCD	= (1 << 5),
-	/* TOC track numbers are in BCD. */
-	IDE_AFLAG_TOCTRACKS_AS_BCD	= (1 << 6),
-	/*
-	 * Drive does not provide data in multiples of SECTOR_SIZE
-	 * when more than one interrupt is needed.
-	 */
-	IDE_AFLAG_LIMIT_NFRAMES		= (1 << 7),
-	/* Seeking in progress. */
-	IDE_AFLAG_SEEKING		= (1 << 8),
-	/* Saved TOC information is current. */
-	IDE_AFLAG_TOC_VALID		= (1 << 9),
-	/* We think that the drive door is locked. */
-	IDE_AFLAG_DOOR_LOCKED		= (1 << 10),
-	/* SET_CD_SPEED command is unsupported. */
-	IDE_AFLAG_NO_SPEED_SELECT	= (1 << 11),
-	IDE_AFLAG_VERTOS_300_SSD	= (1 << 12),
-	IDE_AFLAG_VERTOS_600_ESD	= (1 << 13),
-	IDE_AFLAG_SANYO_3CD		= (1 << 14),
-	IDE_AFLAG_FULL_CAPS_PAGE	= (1 << 15),
-	IDE_AFLAG_PLAY_AUDIO_OK		= (1 << 16),
-	IDE_AFLAG_LE_SPEED_FIELDS	= (1 << 17),
-
-	/* ide-floppy */
-	/* Format in progress */
-	IDE_AFLAG_FORMAT_IN_PROGRESS	= (1 << 18),
-	/* Avoid commands not supported in Clik drive */
-	IDE_AFLAG_CLIK_DRIVE		= (1 << 19),
-	/* Requires BH algorithm for packets */
-	IDE_AFLAG_ZIP_DRIVE		= (1 << 20),
-
-	/* ide-tape */
-	IDE_AFLAG_IGNORE_DSC		= (1 << 21),
-	/* 0 When the tape position is unknown */
-	IDE_AFLAG_ADDRESS_VALID		= (1 <<	22),
-	/* Device already opened */
-	IDE_AFLAG_BUSY			= (1 << 23),
-	/* Attempt to auto-detect the current user block size */
-	IDE_AFLAG_DETECT_BS		= (1 << 24),
-	/* Currently on a filemark */
-	IDE_AFLAG_FILEMARK		= (1 << 25),
-	/* 0 = no tape is loaded, so we don't rewind after ejecting */
-	IDE_AFLAG_MEDIUM_PRESENT	= (1 << 26)
-};
-
-struct ide_drive_s {
-	char		name[4];	/* drive name, such as "hda" */
-        char            driver_req[10];	/* requests specific driver */
-
-	struct request_queue	*queue;	/* request queue */
-
-	struct request		*rq;	/* current request */
-	struct ide_drive_s 	*next;	/* circular list of hwgroup drives */
-	void		*driver_data;	/* extra driver data */
-	struct hd_driveid	*id;	/* drive model identification info */
-#ifdef CONFIG_IDE_PROC_FS
-	struct proc_dir_entry *proc;	/* /proc/ide/ directory entry */
-	struct ide_settings_s *settings;/* /proc/ide/ drive settings */
-#endif
-	struct hwif_s		*hwif;	/* actually (ide_hwif_t *) */
-
-	unsigned long sleep;		/* sleep until this time */
-	unsigned long service_start;	/* time we started last request */
-	unsigned long service_time;	/* service time of last request */
-	unsigned long timeout;		/* max time to wait for irq */
-
-	special_t	special;	/* special action flags */
-	select_t	select;		/* basic drive/head select reg value */
-
-	u8	keep_settings;		/* restore settings after drive reset */
-	u8	using_dma;		/* disk is using dma for read/write */
-	u8	retry_pio;		/* retrying dma capable host in pio */
-	u8	state;			/* retry state */
-	u8	waiting_for_dma;	/* dma currently in progress */
-	u8	unmask;			/* okay to unmask other irqs */
-	u8	noflush;		/* don't attempt flushes */
-	u8	dsc_overlap;		/* DSC overlap */
-	u8	nice1;			/* give potential excess bandwidth */
-
-	unsigned present	: 1;	/* drive is physically present */
-	unsigned dead		: 1;	/* device ejected hint */
-	unsigned id_read	: 1;	/* 1=id read from disk 0 = synthetic */
-	unsigned noprobe 	: 1;	/* from:  hdx=noprobe */
-	unsigned removable	: 1;	/* 1 if need to do check_media_change */
-	unsigned attach		: 1;	/* needed for removable devices */
-	unsigned forced_geom	: 1;	/* 1 if hdx=c,h,s was given at boot */
-	unsigned no_unmask	: 1;	/* disallow setting unmask bit */
-	unsigned no_io_32bit	: 1;	/* disallow enabling 32bit I/O */
-	unsigned atapi_overlap	: 1;	/* ATAPI overlap (not supported) */
-	unsigned doorlocking	: 1;	/* for removable only: door lock/unlock works */
-	unsigned nodma		: 1;	/* disallow DMA */
-	unsigned remap_0_to_1	: 1;	/* 0=noremap, 1=remap 0->1 (for EZDrive) */
-	unsigned blocked        : 1;	/* 1=powermanagment told us not to do anything, so sleep nicely */
-	unsigned scsi		: 1;	/* 0=default, 1=ide-scsi emulation */
-	unsigned sleeping	: 1;	/* 1=sleeping & sleep field valid */
-	unsigned post_reset	: 1;
-	unsigned udma33_warned	: 1;
-
-	u8	addressing;	/* 0=28-bit, 1=48-bit, 2=48-bit doing 28-bit */
-        u8	quirk_list;	/* considered quirky, set for a specific host */
-        u8	init_speed;	/* transfer rate set at boot */
-        u8	current_speed;	/* current transfer rate set */
-	u8	desired_speed;	/* desired transfer rate set */
-        u8	dn;		/* now wide spread use */
-        u8	wcache;		/* status of write cache */
-	u8	acoustic;	/* acoustic management */
-	u8	media;		/* disk, cdrom, tape, floppy, ... */
-	u8	ready_stat;	/* min status value for drive ready */
-	u8	mult_count;	/* current multiple sector setting */
-	u8	mult_req;	/* requested multiple sector setting */
-	u8	tune_req;	/* requested drive tuning setting */
-	u8	io_32bit;	/* 0=16-bit, 1=32-bit, 2/3=32bit+sync */
-	u8	bad_wstat;	/* used for ignoring WRERR_STAT */
-	u8	nowerr;		/* used for ignoring WRERR_STAT */
-	u8	sect0;		/* offset of first sector for DM6:DDO */
-	u8	head;		/* "real" number of heads */
-	u8	sect;		/* "real" sectors per track */
-	u8	bios_head;	/* BIOS/fdisk/LILO number of heads */
-	u8	bios_sect;	/* BIOS/fdisk/LILO sectors per track */
-
-	unsigned int	bios_cyl;	/* BIOS/fdisk/LILO number of cyls */
-	unsigned int	cyl;		/* "real" number of cyls */
-	unsigned int	drive_data;	/* used by set_pio_mode/selectproc */
-	unsigned int	failures;	/* current failure count */
-	unsigned int	max_failures;	/* maximum allowed failure count */
-	u64		probed_capacity;/* initial reported media capacity (ide-cd only currently) */
-
-	u64		capacity64;	/* total number of sectors */
-
-	int		lun;		/* logical unit */
-	int		crc_count;	/* crc counter to reduce drive speed */
-#ifdef CONFIG_BLK_DEV_IDEACPI
-	struct ide_acpi_drive_link *acpidata;
-#endif
-	struct list_head list;
-	struct device	gendev;
-	struct completion gendev_rel_comp;	/* to deal with device release() */
-
-	/* callback for packet commands */
-	void (*pc_callback)(struct ide_drive_s *);
-
-	unsigned long atapi_flags;
-};
-
-typedef struct ide_drive_s ide_drive_t;
-
-#define to_ide_device(dev)container_of(dev, ide_drive_t, gendev)
-
-#define IDE_CHIPSET_PCI_MASK	\
-    ((1<<ide_pci)|(1<<ide_cmd646)|(1<<ide_ali14xx))
-#define IDE_CHIPSET_IS_PCI(c)	((IDE_CHIPSET_PCI_MASK >> (c)) & 1)
-
-struct ide_task_s;
-struct ide_port_info;
-
-struct ide_tp_ops {
-	void	(*exec_command)(struct hwif_s *, u8);
-	u8	(*read_status)(struct hwif_s *);
-	u8	(*read_altstatus)(struct hwif_s *);
-	u8	(*read_sff_dma_status)(struct hwif_s *);
-
-	void	(*set_irq)(struct hwif_s *, int);
-
-	void	(*tf_load)(ide_drive_t *, struct ide_task_s *);
-	void	(*tf_read)(ide_drive_t *, struct ide_task_s *);
-
-	void	(*input_data)(ide_drive_t *, struct request *, void *,
-			      unsigned int);
-	void	(*output_data)(ide_drive_t *, struct request *, void *,
-			       unsigned int);
-};
-
-extern const struct ide_tp_ops default_tp_ops;
-
-/**
- * struct ide_port_ops - IDE port operations
- *
- * @init_dev:		host specific initialization of a device
- * @set_pio_mode:	routine to program host for PIO mode
- * @set_dma_mode:	routine to program host for DMA mode
- * @selectproc:		tweaks hardware to select drive
- * @reset_poll:		chipset polling based on hba specifics
- * @pre_reset:		chipset specific changes to default for device-hba resets
- * @resetproc:		routine to reset controller after a disk reset
- * @maskproc:		special host masking for drive selection
- * @quirkproc:		check host's drive quirk list
- *
- * @mdma_filter:	filter MDMA modes
- * @udma_filter:	filter UDMA modes
- *
- * @cable_detect:	detect cable type
- */
-struct ide_port_ops {
-	void	(*init_dev)(ide_drive_t *);
-	void	(*set_pio_mode)(ide_drive_t *, const u8);
-	void	(*set_dma_mode)(ide_drive_t *, const u8);
-	void	(*selectproc)(ide_drive_t *);
-	int	(*reset_poll)(ide_drive_t *);
-	void	(*pre_reset)(ide_drive_t *);
-	void	(*resetproc)(ide_drive_t *);
-	void	(*maskproc)(ide_drive_t *, int);
-	void	(*quirkproc)(ide_drive_t *);
-
-	u8	(*mdma_filter)(ide_drive_t *);
-	u8	(*udma_filter)(ide_drive_t *);
-
-	u8	(*cable_detect)(struct hwif_s *);
-};
-
-struct ide_dma_ops {
-	void	(*dma_host_set)(struct ide_drive_s *, int);
-	int	(*dma_setup)(struct ide_drive_s *);
-	void	(*dma_exec_cmd)(struct ide_drive_s *, u8);
-	void	(*dma_start)(struct ide_drive_s *);
-	int	(*dma_end)(struct ide_drive_s *);
-	int	(*dma_test_irq)(struct ide_drive_s *);
-	void	(*dma_lost_irq)(struct ide_drive_s *);
-	void	(*dma_timeout)(struct ide_drive_s *);
-};
-
-struct ide_host;
-
-typedef struct hwif_s {
-	struct hwif_s *next;		/* for linked-list in ide_hwgroup_t */
-	struct hwif_s *mate;		/* other hwif from same PCI chip */
-	struct hwgroup_s *hwgroup;	/* actually (ide_hwgroup_t *) */
-	struct proc_dir_entry *proc;	/* /proc/ide/ directory entry */
-
-	struct ide_host *host;
-
-	char name[6];			/* name of interface, eg. "ide0" */
-
-	struct ide_io_ports	io_ports;
-
-	unsigned long	sata_scr[SATA_NR_PORTS];
-
-	ide_drive_t	drives[MAX_DRIVES];	/* drive info */
-
-	u8 major;	/* our major number */
-	u8 index;	/* 0 for ide0; 1 for ide1; ... */
-	u8 channel;	/* for dual-port chips: 0=primary, 1=secondary */
-	u8 bus_state;	/* power state of the IDE bus */
-
-	u32 host_flags;
-
-	u8 pio_mask;
-
-	u8 ultra_mask;
-	u8 mwdma_mask;
-	u8 swdma_mask;
-
-	u8 cbl;		/* cable type */
-
-	hwif_chipset_t chipset;	/* sub-module for tuning.. */
-
-	struct device *dev;
-
-	ide_ack_intr_t *ack_intr;
-
-	void (*rw_disk)(ide_drive_t *, struct request *);
-
-	const struct ide_tp_ops		*tp_ops;
-	const struct ide_port_ops	*port_ops;
-	const struct ide_dma_ops	*dma_ops;
-
-	void (*ide_dma_clear_irq)(ide_drive_t *drive);
-
-	/* dma physical region descriptor table (cpu view) */
-	unsigned int	*dmatable_cpu;
-	/* dma physical region descriptor table (dma view) */
-	dma_addr_t	dmatable_dma;
-	/* Scatter-gather list used to build the above */
-	struct scatterlist *sg_table;
-	int sg_max_nents;		/* Maximum number of entries in it */
-	int sg_nents;			/* Current number of entries in it */
-	int sg_dma_direction;		/* dma transfer direction */
-
-	/* data phase of the active command (currently only valid for PIO/DMA) */
-	int		data_phase;
-
-	unsigned int nsect;
-	unsigned int nleft;
-	struct scatterlist *cursg;
-	unsigned int cursg_ofs;
-
-	int		rqsize;		/* max sectors per request */
-	int		irq;		/* our irq number */
-
-	unsigned long	dma_base;	/* base addr for dma ports */
-
-	unsigned long	config_data;	/* for use by chipset-specific code */
-	unsigned long	select_data;	/* for use by chipset-specific code */
-
-	unsigned long	extra_base;	/* extra addr for dma ports */
-	unsigned	extra_ports;	/* number of extra dma ports */
-
-	unsigned	present    : 1;	/* this interface exists */
-	unsigned	serialized : 1;	/* serialized all channel operation */
-	unsigned	sharing_irq: 1;	/* 1 = sharing irq with another hwif */
-	unsigned	sg_mapped  : 1;	/* sg_table and sg_nents are ready */
-
-	struct device		gendev;
-	struct device		*portdev;
-
-	struct completion gendev_rel_comp; /* To deal with device release() */
-
-	void		*hwif_data;	/* extra hwif data */
-
-	unsigned dma;
-
-#ifdef CONFIG_BLK_DEV_IDEACPI
-	struct ide_acpi_hwif_link *acpidata;
-#endif
-} ____cacheline_internodealigned_in_smp ide_hwif_t;
-
-struct ide_host {
-	ide_hwif_t	*ports[MAX_HWIFS];
-	unsigned int	n_ports;
-	struct device	*dev[2];
-	unsigned long	host_flags;
-	void		*host_priv;
-};
-
-/*
- *  internal ide interrupt handler type
- */
-typedef ide_startstop_t (ide_handler_t)(ide_drive_t *);
-typedef int (ide_expiry_t)(ide_drive_t *);
-
-/* used by ide-cd, ide-floppy, etc. */
-typedef void (xfer_func_t)(ide_drive_t *, struct request *rq, void *, unsigned);
-
-typedef struct hwgroup_s {
-		/* irq handler, if active */
-	ide_startstop_t	(*handler)(ide_drive_t *);
-
-		/* BOOL: protects all fields below */
-	volatile int busy;
-		/* BOOL: wake us up on timer expiry */
-	unsigned int sleeping	: 1;
-		/* BOOL: polling active & poll_timeout field valid */
-	unsigned int polling	: 1;
-
-		/* current drive */
-	ide_drive_t *drive;
-		/* ptr to current hwif in linked-list */
-	ide_hwif_t *hwif;
-
-		/* current request */
-	struct request *rq;
-
-		/* failsafe timer */
-	struct timer_list timer;
-		/* timeout value during long polls */
-	unsigned long poll_timeout;
-		/* queried upon timeouts */
-	int (*expiry)(ide_drive_t *);
-
-	int req_gen;
-	int req_gen_timer;
-} ide_hwgroup_t;
-
-typedef struct ide_driver_s ide_driver_t;
-
-extern struct mutex ide_setting_mtx;
-
-int set_io_32bit(ide_drive_t *, int);
-int set_pio_mode(ide_drive_t *, int);
-int set_using_dma(ide_drive_t *, int);
-
-/* ATAPI packet command flags */
-enum {
-	/* set when an error is considered normal - no retry (ide-tape) */
-	PC_FLAG_ABORT			= (1 << 0),
-	PC_FLAG_SUPPRESS_ERROR		= (1 << 1),
-	PC_FLAG_WAIT_FOR_DSC		= (1 << 2),
-	PC_FLAG_DMA_OK			= (1 << 3),
-	PC_FLAG_DMA_IN_PROGRESS		= (1 << 4),
-	PC_FLAG_DMA_ERROR		= (1 << 5),
-	PC_FLAG_WRITING			= (1 << 6),
-	/* command timed out */
-	PC_FLAG_TIMEDOUT		= (1 << 7),
-};
-
-struct ide_atapi_pc {
-	/* actual packet bytes */
-	u8 c[12];
-	/* incremented on each retry */
-	int retries;
-	int error;
-
-	/* bytes to transfer */
-	int req_xfer;
-	/* bytes actually transferred */
-	int xferred;
-
-	/* data buffer */
-	u8 *buf;
-	/* current buffer position */
-	u8 *cur_pos;
-	int buf_size;
-	/* missing/available data on the current buffer */
-	int b_count;
-
-	/* the corresponding request */
-	struct request *rq;
-
-	unsigned long flags;
-
-	/*
-	 * those are more or less driver-specific and some of them are subject
-	 * to change/removal later.
-	 */
-	u8 pc_buf[256];
-
-	/* idetape only */
-	struct idetape_bh *bh;
-	char *b_data;
-
-	/* idescsi only for now */
-	struct scatterlist *sg;
-	unsigned int sg_cnt;
-
-	struct scsi_cmnd *scsi_cmd;
-	void (*done) (struct scsi_cmnd *);
-
-	unsigned long timeout;
-};
-
-#ifdef CONFIG_IDE_PROC_FS
-/*
- * configurable drive settings
- */
-
-#define TYPE_INT	0
-#define TYPE_BYTE	1
-#define TYPE_SHORT	2
-
-#define SETTING_READ	(1 << 0)
-#define SETTING_WRITE	(1 << 1)
-#define SETTING_RW	(SETTING_READ | SETTING_WRITE)
-
-typedef int (ide_procset_t)(ide_drive_t *, int);
-typedef struct ide_settings_s {
-	char			*name;
-	int			rw;
-	int			data_type;
-	int			min;
-	int			max;
-	int			mul_factor;
-	int			div_factor;
-	void			*data;
-	ide_procset_t		*set;
-	int			auto_remove;
-	struct ide_settings_s	*next;
-} ide_settings_t;
-
-int ide_add_setting(ide_drive_t *, const char *, int, int, int, int, int, int, void *, ide_procset_t *set);
-
-/*
- * /proc/ide interface
- */
-typedef struct {
-	const char	*name;
-	mode_t		mode;
-	read_proc_t	*read_proc;
-	write_proc_t	*write_proc;
-} ide_proc_entry_t;
-
-void proc_ide_create(void);
-void proc_ide_destroy(void);
-void ide_proc_register_port(ide_hwif_t *);
-void ide_proc_port_register_devices(ide_hwif_t *);
-void ide_proc_unregister_device(ide_drive_t *);
-void ide_proc_unregister_port(ide_hwif_t *);
-void ide_proc_register_driver(ide_drive_t *, ide_driver_t *);
-void ide_proc_unregister_driver(ide_drive_t *, ide_driver_t *);
-
-void ide_add_generic_settings(ide_drive_t *);
-
-read_proc_t proc_ide_read_capacity;
-read_proc_t proc_ide_read_geometry;
-
-/*
- * Standard exit stuff:
- */
-#define PROC_IDE_READ_RETURN(page,start,off,count,eof,len) \
-{					\
-	len -= off;			\
-	if (len < count) {		\
-		*eof = 1;		\
-		if (len <= 0)		\
-			return 0;	\
-	} else				\
-		len = count;		\
-	*start = page + off;		\
-	return len;			\
-}
-#else
-static inline void proc_ide_create(void) { ; }
-static inline void proc_ide_destroy(void) { ; }
-static inline void ide_proc_register_port(ide_hwif_t *hwif) { ; }
-static inline void ide_proc_port_register_devices(ide_hwif_t *hwif) { ; }
-static inline void ide_proc_unregister_device(ide_drive_t *drive) { ; }
-static inline void ide_proc_unregister_port(ide_hwif_t *hwif) { ; }
-static inline void ide_proc_register_driver(ide_drive_t *drive, ide_driver_t *driver) { ; }
-static inline void ide_proc_unregister_driver(ide_drive_t *drive, ide_driver_t *driver) { ; }
-static inline void ide_add_generic_settings(ide_drive_t *drive) { ; }
-#define PROC_IDE_READ_RETURN(page,start,off,count,eof,len) return 0;
-#endif
-
-/*
- * Power Management step value (rq->pm->pm_step).
- *
- * The step value starts at 0 (ide_pm_state_start_suspend) for a
- * suspend operation or 1000 (ide_pm_state_start_resume) for a
- * resume operation.
- *
- * For each step, the core calls the subdriver start_power_step() first.
- * This can return:
- *	- ide_stopped :	In this case, the core calls us back again unless
- *			step have been set to ide_power_state_completed.
- *	- ide_started :	In this case, the channel is left busy until an
- *			async event (interrupt) occurs.
- * Typically, start_power_step() will issue a taskfile request with
- * do_rw_taskfile().
- *
- * Upon reception of the interrupt, the core will call complete_power_step()
- * with the error code if any. This routine should update the step value
- * and return. It should not start a new request. The core will call
- * start_power_step for the new step value, unless step have been set to
- * ide_power_state_completed.
- *
- * Subdrivers are expected to define their own additional power
- * steps from 1..999 for suspend and from 1001..1999 for resume,
- * other values are reserved for future use.
- */
-
-enum {
-	ide_pm_state_completed		= -1,
-	ide_pm_state_start_suspend	= 0,
-	ide_pm_state_start_resume	= 1000,
-};
-
-/*
- * Subdrivers support.
- *
- * The gendriver.owner field should be set to the module owner of this driver.
- * The gendriver.name field should be set to the name of this driver
- */
-struct ide_driver_s {
-	const char			*version;
-	u8				media;
-	unsigned supports_dsc_overlap	: 1;
-	ide_startstop_t	(*do_request)(ide_drive_t *, struct request *, sector_t);
-	int		(*end_request)(ide_drive_t *, int, int);
-	ide_startstop_t	(*error)(ide_drive_t *, struct request *rq, u8, u8);
-	struct device_driver	gen_driver;
-	int		(*probe)(ide_drive_t *);
-	void		(*remove)(ide_drive_t *);
-	void		(*resume)(ide_drive_t *);
-	void		(*shutdown)(ide_drive_t *);
-#ifdef CONFIG_IDE_PROC_FS
-	ide_proc_entry_t	*proc;
-#endif
-};
-
-#define to_ide_driver(drv) container_of(drv, ide_driver_t, gen_driver)
-
-int ide_device_get(ide_drive_t *);
-void ide_device_put(ide_drive_t *);
-
-int generic_ide_ioctl(ide_drive_t *, struct file *, struct block_device *, unsigned, unsigned long);
-
-extern int ide_vlb_clk;
-extern int ide_pci_clk;
-
-extern int ide_end_request (ide_drive_t *drive, int uptodate, int nrsecs);
-int ide_end_dequeued_request(ide_drive_t *drive, struct request *rq,
-			     int uptodate, int nr_sectors);
-
-extern void ide_set_handler (ide_drive_t *drive, ide_handler_t *handler, unsigned int timeout, ide_expiry_t *expiry);
-
-void ide_execute_command(ide_drive_t *, u8, ide_handler_t *, unsigned int,
-			 ide_expiry_t *);
-
-void ide_execute_pkt_cmd(ide_drive_t *);
-
-void ide_pad_transfer(ide_drive_t *, int, int);
-
-ide_startstop_t __ide_error(ide_drive_t *, struct request *, u8, u8);
-
-ide_startstop_t ide_error (ide_drive_t *drive, const char *msg, byte stat);
-
-extern void ide_fix_driveid(struct hd_driveid *);
-
-extern void ide_fixstring(u8 *, const int, const int);
-
-int ide_wait_stat(ide_startstop_t *, ide_drive_t *, u8, u8, unsigned long);
-
-extern ide_startstop_t ide_do_reset (ide_drive_t *);
-
-extern void ide_do_drive_cmd(ide_drive_t *, struct request *);
-
-extern void ide_end_drive_cmd(ide_drive_t *, u8, u8);
-
 enum {
 	IDE_TFLAG_LBA48			= (1 << 0),
 	IDE_TFLAG_FLAGGED		= (1 << 2),
@@ -1034,6 +388,800 @@
 	void			*special;	/* valid_t generally */
 } ide_task_t;
 
+/* ATAPI packet command flags */
+enum {
+	/* set when an error is considered normal - no retry (ide-tape) */
+	PC_FLAG_ABORT			= (1 << 0),
+	PC_FLAG_SUPPRESS_ERROR		= (1 << 1),
+	PC_FLAG_WAIT_FOR_DSC		= (1 << 2),
+	PC_FLAG_DMA_OK			= (1 << 3),
+	PC_FLAG_DMA_IN_PROGRESS		= (1 << 4),
+	PC_FLAG_DMA_ERROR		= (1 << 5),
+	PC_FLAG_WRITING			= (1 << 6),
+	/* command timed out */
+	PC_FLAG_TIMEDOUT		= (1 << 7),
+};
+
+/*
+ * With each packet command, we allocate a buffer of IDE_PC_BUFFER_SIZE bytes.
+ * This is used for several packet commands (not for READ/WRITE commands).
+ */
+#define IDE_PC_BUFFER_SIZE	256
+
+struct ide_atapi_pc {
+	/* actual packet bytes */
+	u8 c[12];
+	/* incremented on each retry */
+	int retries;
+	int error;
+
+	/* bytes to transfer */
+	int req_xfer;
+	/* bytes actually transferred */
+	int xferred;
+
+	/* data buffer */
+	u8 *buf;
+	/* current buffer position */
+	u8 *cur_pos;
+	int buf_size;
+	/* missing/available data on the current buffer */
+	int b_count;
+
+	/* the corresponding request */
+	struct request *rq;
+
+	unsigned long flags;
+
+	/*
+	 * those are more or less driver-specific and some of them are subject
+	 * to change/removal later.
+	 */
+	u8 pc_buf[IDE_PC_BUFFER_SIZE];
+
+	/* idetape only */
+	struct idetape_bh *bh;
+	char *b_data;
+
+	/* idescsi only for now */
+	struct scatterlist *sg;
+	unsigned int sg_cnt;
+
+	struct scsi_cmnd *scsi_cmd;
+	void (*done) (struct scsi_cmnd *);
+
+	unsigned long timeout;
+};
+
+struct ide_devset;
+struct ide_driver_s;
+
+#ifdef CONFIG_BLK_DEV_IDEACPI
+struct ide_acpi_drive_link;
+struct ide_acpi_hwif_link;
+#endif
+
+/* ATAPI device flags */
+enum {
+	IDE_AFLAG_DRQ_INTERRUPT		= (1 << 0),
+	IDE_AFLAG_MEDIA_CHANGED		= (1 << 1),
+	/* Drive cannot lock the door. */
+	IDE_AFLAG_NO_DOORLOCK		= (1 << 2),
+
+	/* ide-cd */
+	/* Drive cannot eject the disc. */
+	IDE_AFLAG_NO_EJECT		= (1 << 3),
+	/* Drive is a pre ATAPI 1.2 drive. */
+	IDE_AFLAG_PRE_ATAPI12		= (1 << 4),
+	/* TOC addresses are in BCD. */
+	IDE_AFLAG_TOCADDR_AS_BCD	= (1 << 5),
+	/* TOC track numbers are in BCD. */
+	IDE_AFLAG_TOCTRACKS_AS_BCD	= (1 << 6),
+	/*
+	 * Drive does not provide data in multiples of SECTOR_SIZE
+	 * when more than one interrupt is needed.
+	 */
+	IDE_AFLAG_LIMIT_NFRAMES		= (1 << 7),
+	/* Seeking in progress. */
+	IDE_AFLAG_SEEKING		= (1 << 8),
+	/* Saved TOC information is current. */
+	IDE_AFLAG_TOC_VALID		= (1 << 9),
+	/* We think that the drive door is locked. */
+	IDE_AFLAG_DOOR_LOCKED		= (1 << 10),
+	/* SET_CD_SPEED command is unsupported. */
+	IDE_AFLAG_NO_SPEED_SELECT	= (1 << 11),
+	IDE_AFLAG_VERTOS_300_SSD	= (1 << 12),
+	IDE_AFLAG_VERTOS_600_ESD	= (1 << 13),
+	IDE_AFLAG_SANYO_3CD		= (1 << 14),
+	IDE_AFLAG_FULL_CAPS_PAGE	= (1 << 15),
+	IDE_AFLAG_PLAY_AUDIO_OK		= (1 << 16),
+	IDE_AFLAG_LE_SPEED_FIELDS	= (1 << 17),
+
+	/* ide-floppy */
+	/* Format in progress */
+	IDE_AFLAG_FORMAT_IN_PROGRESS	= (1 << 18),
+	/* Avoid commands not supported in Clik drive */
+	IDE_AFLAG_CLIK_DRIVE		= (1 << 19),
+	/* Requires BH algorithm for packets */
+	IDE_AFLAG_ZIP_DRIVE		= (1 << 20),
+	/* Write protect */
+	IDE_AFLAG_WP			= (1 << 21),
+	/* Supports format progress report */
+	IDE_AFLAG_SRFP			= (1 << 22),
+
+	/* ide-tape */
+	IDE_AFLAG_IGNORE_DSC		= (1 << 23),
+	/* 0 When the tape position is unknown */
+	IDE_AFLAG_ADDRESS_VALID		= (1 <<	24),
+	/* Device already opened */
+	IDE_AFLAG_BUSY			= (1 << 25),
+	/* Attempt to auto-detect the current user block size */
+	IDE_AFLAG_DETECT_BS		= (1 << 26),
+	/* Currently on a filemark */
+	IDE_AFLAG_FILEMARK		= (1 << 27),
+	/* 0 = no tape is loaded, so we don't rewind after ejecting */
+	IDE_AFLAG_MEDIUM_PRESENT	= (1 << 28),
+
+	IDE_AFLAG_NO_AUTOCLOSE		= (1 << 29),
+};
+
+/* device flags */
+enum {
+	/* restore settings after device reset */
+	IDE_DFLAG_KEEP_SETTINGS		= (1 << 0),
+	/* device is using DMA for read/write */
+	IDE_DFLAG_USING_DMA		= (1 << 1),
+	/* okay to unmask other IRQs */
+	IDE_DFLAG_UNMASK		= (1 << 2),
+	/* don't attempt flushes */
+	IDE_DFLAG_NOFLUSH		= (1 << 3),
+	/* DSC overlap */
+	IDE_DFLAG_DSC_OVERLAP		= (1 << 4),
+	/* give potential excess bandwidth */
+	IDE_DFLAG_NICE1			= (1 << 5),
+	/* device is physically present */
+	IDE_DFLAG_PRESENT		= (1 << 6),
+	/* device ejected hint */
+	IDE_DFLAG_DEAD			= (1 << 7),
+	/* id read from device (synthetic if not set) */
+	IDE_DFLAG_ID_READ		= (1 << 8),
+	IDE_DFLAG_NOPROBE		= (1 << 9),
+	/* need to do check_media_change() */
+	IDE_DFLAG_REMOVABLE		= (1 << 10),
+	/* needed for removable devices */
+	IDE_DFLAG_ATTACH		= (1 << 11),
+	IDE_DFLAG_FORCED_GEOM		= (1 << 12),
+	/* disallow setting unmask bit */
+	IDE_DFLAG_NO_UNMASK		= (1 << 13),
+	/* disallow enabling 32-bit I/O */
+	IDE_DFLAG_NO_IO_32BIT		= (1 << 14),
+	/* for removable only: door lock/unlock works */
+	IDE_DFLAG_DOORLOCKING		= (1 << 15),
+	/* disallow DMA */
+	IDE_DFLAG_NODMA			= (1 << 16),
+	/* powermanagment told us not to do anything, so sleep nicely */
+	IDE_DFLAG_BLOCKED		= (1 << 17),
+	/* ide-scsi emulation */
+	IDE_DFLAG_SCSI			= (1 << 18),
+	/* sleeping & sleep field valid */
+	IDE_DFLAG_SLEEPING		= (1 << 19),
+	IDE_DFLAG_POST_RESET		= (1 << 20),
+	IDE_DFLAG_UDMA33_WARNED		= (1 << 21),
+	IDE_DFLAG_LBA48			= (1 << 22),
+	/* status of write cache */
+	IDE_DFLAG_WCACHE		= (1 << 23),
+	/* used for ignoring ATA_DF */
+	IDE_DFLAG_NOWERR		= (1 << 24),
+	/* retrying in PIO */
+	IDE_DFLAG_DMA_PIO_RETRY		= (1 << 25),
+	IDE_DFLAG_LBA			= (1 << 26),
+	/* don't unload heads */
+	IDE_DFLAG_NO_UNLOAD		= (1 << 27),
+	/* heads unloaded, please don't reset port */
+	IDE_DFLAG_PARKED		= (1 << 28)
+};
+
+struct ide_drive_s {
+	char		name[4];	/* drive name, such as "hda" */
+        char            driver_req[10];	/* requests specific driver */
+
+	struct request_queue	*queue;	/* request queue */
+
+	struct request		*rq;	/* current request */
+	struct ide_drive_s 	*next;	/* circular list of hwgroup drives */
+	void		*driver_data;	/* extra driver data */
+	u16			*id;	/* identification info */
+#ifdef CONFIG_IDE_PROC_FS
+	struct proc_dir_entry *proc;	/* /proc/ide/ directory entry */
+	const struct ide_proc_devset *settings; /* /proc/ide/ drive settings */
+#endif
+	struct hwif_s		*hwif;	/* actually (ide_hwif_t *) */
+
+	unsigned long dev_flags;
+
+	unsigned long sleep;		/* sleep until this time */
+	unsigned long service_start;	/* time we started last request */
+	unsigned long service_time;	/* service time of last request */
+	unsigned long timeout;		/* max time to wait for irq */
+
+	special_t	special;	/* special action flags */
+
+	u8	select;			/* basic drive/head select reg value */
+	u8	retry_pio;		/* retrying dma capable host in pio */
+	u8	waiting_for_dma;	/* dma currently in progress */
+	u8	dma;			/* atapi dma flag */
+
+        u8	quirk_list;	/* considered quirky, set for a specific host */
+        u8	init_speed;	/* transfer rate set at boot */
+        u8	current_speed;	/* current transfer rate set */
+	u8	desired_speed;	/* desired transfer rate set */
+        u8	dn;		/* now wide spread use */
+	u8	acoustic;	/* acoustic management */
+	u8	media;		/* disk, cdrom, tape, floppy, ... */
+	u8	ready_stat;	/* min status value for drive ready */
+	u8	mult_count;	/* current multiple sector setting */
+	u8	mult_req;	/* requested multiple sector setting */
+	u8	io_32bit;	/* 0=16-bit, 1=32-bit, 2/3=32bit+sync */
+	u8	bad_wstat;	/* used for ignoring ATA_DF */
+	u8	head;		/* "real" number of heads */
+	u8	sect;		/* "real" sectors per track */
+	u8	bios_head;	/* BIOS/fdisk/LILO number of heads */
+	u8	bios_sect;	/* BIOS/fdisk/LILO sectors per track */
+
+	/* delay this long before sending packet command */
+	u8 pc_delay;
+
+	unsigned int	bios_cyl;	/* BIOS/fdisk/LILO number of cyls */
+	unsigned int	cyl;		/* "real" number of cyls */
+	unsigned int	drive_data;	/* used by set_pio_mode/selectproc */
+	unsigned int	failures;	/* current failure count */
+	unsigned int	max_failures;	/* maximum allowed failure count */
+	u64		probed_capacity;/* initial reported media capacity (ide-cd only currently) */
+
+	u64		capacity64;	/* total number of sectors */
+
+	int		lun;		/* logical unit */
+	int		crc_count;	/* crc counter to reduce drive speed */
+
+	unsigned long	debug_mask;	/* debugging levels switch */
+
+#ifdef CONFIG_BLK_DEV_IDEACPI
+	struct ide_acpi_drive_link *acpidata;
+#endif
+	struct list_head list;
+	struct device	gendev;
+	struct completion gendev_rel_comp;	/* to deal with device release() */
+
+	/* current packet command */
+	struct ide_atapi_pc *pc;
+
+	/* callback for packet commands */
+	void (*pc_callback)(struct ide_drive_s *, int);
+
+	void (*pc_update_buffers)(struct ide_drive_s *, struct ide_atapi_pc *);
+	int  (*pc_io_buffers)(struct ide_drive_s *, struct ide_atapi_pc *,
+			      unsigned int, int);
+
+	unsigned long atapi_flags;
+
+	struct ide_atapi_pc request_sense_pc;
+	struct request request_sense_rq;
+};
+
+typedef struct ide_drive_s ide_drive_t;
+
+#define to_ide_device(dev)		container_of(dev, ide_drive_t, gendev)
+
+#define to_ide_drv(obj, cont_type)	\
+	container_of(obj, struct cont_type, kref)
+
+#define ide_drv_g(disk, cont_type)	\
+	container_of((disk)->private_data, struct cont_type, driver)
+
+struct ide_port_info;
+
+struct ide_tp_ops {
+	void	(*exec_command)(struct hwif_s *, u8);
+	u8	(*read_status)(struct hwif_s *);
+	u8	(*read_altstatus)(struct hwif_s *);
+	u8	(*read_sff_dma_status)(struct hwif_s *);
+
+	void	(*set_irq)(struct hwif_s *, int);
+
+	void	(*tf_load)(ide_drive_t *, struct ide_task_s *);
+	void	(*tf_read)(ide_drive_t *, struct ide_task_s *);
+
+	void	(*input_data)(ide_drive_t *, struct request *, void *,
+			      unsigned int);
+	void	(*output_data)(ide_drive_t *, struct request *, void *,
+			       unsigned int);
+};
+
+extern const struct ide_tp_ops default_tp_ops;
+
+/**
+ * struct ide_port_ops - IDE port operations
+ *
+ * @init_dev:		host specific initialization of a device
+ * @set_pio_mode:	routine to program host for PIO mode
+ * @set_dma_mode:	routine to program host for DMA mode
+ * @selectproc:		tweaks hardware to select drive
+ * @reset_poll:		chipset polling based on hba specifics
+ * @pre_reset:		chipset specific changes to default for device-hba resets
+ * @resetproc:		routine to reset controller after a disk reset
+ * @maskproc:		special host masking for drive selection
+ * @quirkproc:		check host's drive quirk list
+ * @clear_irq:		clear IRQ
+ *
+ * @mdma_filter:	filter MDMA modes
+ * @udma_filter:	filter UDMA modes
+ *
+ * @cable_detect:	detect cable type
+ */
+struct ide_port_ops {
+	void	(*init_dev)(ide_drive_t *);
+	void	(*set_pio_mode)(ide_drive_t *, const u8);
+	void	(*set_dma_mode)(ide_drive_t *, const u8);
+	void	(*selectproc)(ide_drive_t *);
+	int	(*reset_poll)(ide_drive_t *);
+	void	(*pre_reset)(ide_drive_t *);
+	void	(*resetproc)(ide_drive_t *);
+	void	(*maskproc)(ide_drive_t *, int);
+	void	(*quirkproc)(ide_drive_t *);
+	void	(*clear_irq)(ide_drive_t *);
+
+	u8	(*mdma_filter)(ide_drive_t *);
+	u8	(*udma_filter)(ide_drive_t *);
+
+	u8	(*cable_detect)(struct hwif_s *);
+};
+
+struct ide_dma_ops {
+	void	(*dma_host_set)(struct ide_drive_s *, int);
+	int	(*dma_setup)(struct ide_drive_s *);
+	void	(*dma_exec_cmd)(struct ide_drive_s *, u8);
+	void	(*dma_start)(struct ide_drive_s *);
+	int	(*dma_end)(struct ide_drive_s *);
+	int	(*dma_test_irq)(struct ide_drive_s *);
+	void	(*dma_lost_irq)(struct ide_drive_s *);
+	void	(*dma_timeout)(struct ide_drive_s *);
+};
+
+struct ide_host;
+
+typedef struct hwif_s {
+	struct hwif_s *next;		/* for linked-list in ide_hwgroup_t */
+	struct hwif_s *mate;		/* other hwif from same PCI chip */
+	struct hwgroup_s *hwgroup;	/* actually (ide_hwgroup_t *) */
+	struct proc_dir_entry *proc;	/* /proc/ide/ directory entry */
+
+	struct ide_host *host;
+
+	char name[6];			/* name of interface, eg. "ide0" */
+
+	struct ide_io_ports	io_ports;
+
+	unsigned long	sata_scr[SATA_NR_PORTS];
+
+	ide_drive_t	drives[MAX_DRIVES];	/* drive info */
+
+	u8 major;	/* our major number */
+	u8 index;	/* 0 for ide0; 1 for ide1; ... */
+	u8 channel;	/* for dual-port chips: 0=primary, 1=secondary */
+
+	u32 host_flags;
+
+	u8 pio_mask;
+
+	u8 ultra_mask;
+	u8 mwdma_mask;
+	u8 swdma_mask;
+
+	u8 cbl;		/* cable type */
+
+	hwif_chipset_t chipset;	/* sub-module for tuning.. */
+
+	struct device *dev;
+
+	ide_ack_intr_t *ack_intr;
+
+	void (*rw_disk)(ide_drive_t *, struct request *);
+
+	const struct ide_tp_ops		*tp_ops;
+	const struct ide_port_ops	*port_ops;
+	const struct ide_dma_ops	*dma_ops;
+
+	/* dma physical region descriptor table (cpu view) */
+	unsigned int	*dmatable_cpu;
+	/* dma physical region descriptor table (dma view) */
+	dma_addr_t	dmatable_dma;
+
+	/* maximum number of PRD table entries */
+	int prd_max_nents;
+	/* PRD entry size in bytes */
+	int prd_ent_size;
+
+	/* Scatter-gather list used to build the above */
+	struct scatterlist *sg_table;
+	int sg_max_nents;		/* Maximum number of entries in it */
+	int sg_nents;			/* Current number of entries in it */
+	int sg_dma_direction;		/* dma transfer direction */
+
+	/* data phase of the active command (currently only valid for PIO/DMA) */
+	int		data_phase;
+
+	struct ide_task_s task;		/* current command */
+
+	unsigned int nsect;
+	unsigned int nleft;
+	struct scatterlist *cursg;
+	unsigned int cursg_ofs;
+
+	int		rqsize;		/* max sectors per request */
+	int		irq;		/* our irq number */
+
+	unsigned long	dma_base;	/* base addr for dma ports */
+
+	unsigned long	config_data;	/* for use by chipset-specific code */
+	unsigned long	select_data;	/* for use by chipset-specific code */
+
+	unsigned long	extra_base;	/* extra addr for dma ports */
+	unsigned	extra_ports;	/* number of extra dma ports */
+
+	unsigned	present    : 1;	/* this interface exists */
+	unsigned	serialized : 1;	/* serialized all channel operation */
+	unsigned	sharing_irq: 1;	/* 1 = sharing irq with another hwif */
+	unsigned	sg_mapped  : 1;	/* sg_table and sg_nents are ready */
+
+	struct device		gendev;
+	struct device		*portdev;
+
+	struct completion gendev_rel_comp; /* To deal with device release() */
+
+	void		*hwif_data;	/* extra hwif data */
+
+#ifdef CONFIG_BLK_DEV_IDEACPI
+	struct ide_acpi_hwif_link *acpidata;
+#endif
+} ____cacheline_internodealigned_in_smp ide_hwif_t;
+
+#define MAX_HOST_PORTS 4
+
+struct ide_host {
+	ide_hwif_t	*ports[MAX_HOST_PORTS];
+	unsigned int	n_ports;
+	struct device	*dev[2];
+	unsigned int	(*init_chipset)(struct pci_dev *);
+	unsigned long	host_flags;
+	void		*host_priv;
+};
+
+/*
+ *  internal ide interrupt handler type
+ */
+typedef ide_startstop_t (ide_handler_t)(ide_drive_t *);
+typedef int (ide_expiry_t)(ide_drive_t *);
+
+/* used by ide-cd, ide-floppy, etc. */
+typedef void (xfer_func_t)(ide_drive_t *, struct request *rq, void *, unsigned);
+
+typedef struct hwgroup_s {
+		/* irq handler, if active */
+	ide_startstop_t	(*handler)(ide_drive_t *);
+
+		/* BOOL: protects all fields below */
+	volatile int busy;
+		/* BOOL: wake us up on timer expiry */
+	unsigned int sleeping	: 1;
+		/* BOOL: polling active & poll_timeout field valid */
+	unsigned int polling	: 1;
+
+		/* current drive */
+	ide_drive_t *drive;
+		/* ptr to current hwif in linked-list */
+	ide_hwif_t *hwif;
+
+		/* current request */
+	struct request *rq;
+
+		/* failsafe timer */
+	struct timer_list timer;
+		/* timeout value during long polls */
+	unsigned long poll_timeout;
+		/* queried upon timeouts */
+	int (*expiry)(ide_drive_t *);
+
+	int req_gen;
+	int req_gen_timer;
+} ide_hwgroup_t;
+
+typedef struct ide_driver_s ide_driver_t;
+
+extern struct mutex ide_setting_mtx;
+
+/*
+ * configurable drive settings
+ */
+
+#define DS_SYNC	(1 << 0)
+
+struct ide_devset {
+	int		(*get)(ide_drive_t *);
+	int		(*set)(ide_drive_t *, int);
+	unsigned int	flags;
+};
+
+#define __DEVSET(_flags, _get, _set) { \
+	.flags	= _flags, \
+	.get	= _get,	\
+	.set	= _set,	\
+}
+
+#define ide_devset_get(name, field) \
+static int get_##name(ide_drive_t *drive) \
+{ \
+	return drive->field; \
+}
+
+#define ide_devset_set(name, field) \
+static int set_##name(ide_drive_t *drive, int arg) \
+{ \
+	drive->field = arg; \
+	return 0; \
+}
+
+#define ide_devset_get_flag(name, flag) \
+static int get_##name(ide_drive_t *drive) \
+{ \
+	return !!(drive->dev_flags & flag); \
+}
+
+#define ide_devset_set_flag(name, flag) \
+static int set_##name(ide_drive_t *drive, int arg) \
+{ \
+	if (arg) \
+		drive->dev_flags |= flag; \
+	else \
+		drive->dev_flags &= ~flag; \
+	return 0; \
+}
+
+#define __IDE_DEVSET(_name, _flags, _get, _set) \
+const struct ide_devset ide_devset_##_name = \
+	__DEVSET(_flags, _get, _set)
+
+#define IDE_DEVSET(_name, _flags, _get, _set) \
+static __IDE_DEVSET(_name, _flags, _get, _set)
+
+#define ide_devset_rw(_name, _func) \
+IDE_DEVSET(_name, 0, get_##_func, set_##_func)
+
+#define ide_devset_w(_name, _func) \
+IDE_DEVSET(_name, 0, NULL, set_##_func)
+
+#define ide_ext_devset_rw(_name, _func) \
+__IDE_DEVSET(_name, 0, get_##_func, set_##_func)
+
+#define ide_ext_devset_rw_sync(_name, _func) \
+__IDE_DEVSET(_name, DS_SYNC, get_##_func, set_##_func)
+
+#define ide_decl_devset(_name) \
+extern const struct ide_devset ide_devset_##_name
+
+ide_decl_devset(io_32bit);
+ide_decl_devset(keepsettings);
+ide_decl_devset(pio_mode);
+ide_decl_devset(unmaskirq);
+ide_decl_devset(using_dma);
+
+#ifdef CONFIG_IDE_PROC_FS
+/*
+ * /proc/ide interface
+ */
+
+#define ide_devset_rw_field(_name, _field) \
+ide_devset_get(_name, _field); \
+ide_devset_set(_name, _field); \
+IDE_DEVSET(_name, DS_SYNC, get_##_name, set_##_name)
+
+#define ide_devset_rw_flag(_name, _field) \
+ide_devset_get_flag(_name, _field); \
+ide_devset_set_flag(_name, _field); \
+IDE_DEVSET(_name, DS_SYNC, get_##_name, set_##_name)
+
+struct ide_proc_devset {
+	const char		*name;
+	const struct ide_devset	*setting;
+	int			min, max;
+	int			(*mulf)(ide_drive_t *);
+	int			(*divf)(ide_drive_t *);
+};
+
+#define __IDE_PROC_DEVSET(_name, _min, _max, _mulf, _divf) { \
+	.name = __stringify(_name), \
+	.setting = &ide_devset_##_name, \
+	.min = _min, \
+	.max = _max, \
+	.mulf = _mulf, \
+	.divf = _divf, \
+}
+
+#define IDE_PROC_DEVSET(_name, _min, _max) \
+__IDE_PROC_DEVSET(_name, _min, _max, NULL, NULL)
+
+typedef struct {
+	const char	*name;
+	mode_t		mode;
+	read_proc_t	*read_proc;
+	write_proc_t	*write_proc;
+} ide_proc_entry_t;
+
+void proc_ide_create(void);
+void proc_ide_destroy(void);
+void ide_proc_register_port(ide_hwif_t *);
+void ide_proc_port_register_devices(ide_hwif_t *);
+void ide_proc_unregister_device(ide_drive_t *);
+void ide_proc_unregister_port(ide_hwif_t *);
+void ide_proc_register_driver(ide_drive_t *, ide_driver_t *);
+void ide_proc_unregister_driver(ide_drive_t *, ide_driver_t *);
+
+read_proc_t proc_ide_read_capacity;
+read_proc_t proc_ide_read_geometry;
+
+/*
+ * Standard exit stuff:
+ */
+#define PROC_IDE_READ_RETURN(page,start,off,count,eof,len) \
+{					\
+	len -= off;			\
+	if (len < count) {		\
+		*eof = 1;		\
+		if (len <= 0)		\
+			return 0;	\
+	} else				\
+		len = count;		\
+	*start = page + off;		\
+	return len;			\
+}
+#else
+static inline void proc_ide_create(void) { ; }
+static inline void proc_ide_destroy(void) { ; }
+static inline void ide_proc_register_port(ide_hwif_t *hwif) { ; }
+static inline void ide_proc_port_register_devices(ide_hwif_t *hwif) { ; }
+static inline void ide_proc_unregister_device(ide_drive_t *drive) { ; }
+static inline void ide_proc_unregister_port(ide_hwif_t *hwif) { ; }
+static inline void ide_proc_register_driver(ide_drive_t *drive, ide_driver_t *driver) { ; }
+static inline void ide_proc_unregister_driver(ide_drive_t *drive, ide_driver_t *driver) { ; }
+#define PROC_IDE_READ_RETURN(page,start,off,count,eof,len) return 0;
+#endif
+
+enum {
+	/* enter/exit functions */
+	IDE_DBG_FUNC =			(1 << 0),
+	/* sense key/asc handling */
+	IDE_DBG_SENSE =			(1 << 1),
+	/* packet commands handling */
+	IDE_DBG_PC =			(1 << 2),
+	/* request handling */
+	IDE_DBG_RQ =			(1 << 3),
+	/* driver probing/setup */
+	IDE_DBG_PROBE =			(1 << 4),
+};
+
+/* DRV_NAME has to be defined in the driver before using the macro below */
+#define __ide_debug_log(lvl, fmt, args...)			\
+{								\
+	if (unlikely(drive->debug_mask & lvl))			\
+		printk(KERN_INFO DRV_NAME ": " fmt, ## args);	\
+}
+
+/*
+ * Power Management state machine (rq->pm->pm_step).
+ *
+ * For each step, the core calls ide_start_power_step() first.
+ * This can return:
+ *	- ide_stopped :	In this case, the core calls us back again unless
+ *			step have been set to ide_power_state_completed.
+ *	- ide_started :	In this case, the channel is left busy until an
+ *			async event (interrupt) occurs.
+ * Typically, ide_start_power_step() will issue a taskfile request with
+ * do_rw_taskfile().
+ *
+ * Upon reception of the interrupt, the core will call ide_complete_power_step()
+ * with the error code if any. This routine should update the step value
+ * and return. It should not start a new request. The core will call
+ * ide_start_power_step() for the new step value, unless step have been
+ * set to IDE_PM_COMPLETED.
+ */
+enum {
+	IDE_PM_START_SUSPEND,
+	IDE_PM_FLUSH_CACHE	= IDE_PM_START_SUSPEND,
+	IDE_PM_STANDBY,
+
+	IDE_PM_START_RESUME,
+	IDE_PM_RESTORE_PIO	= IDE_PM_START_RESUME,
+	IDE_PM_IDLE,
+	IDE_PM_RESTORE_DMA,
+
+	IDE_PM_COMPLETED,
+};
+
+/*
+ * Subdrivers support.
+ *
+ * The gendriver.owner field should be set to the module owner of this driver.
+ * The gendriver.name field should be set to the name of this driver
+ */
+struct ide_driver_s {
+	const char			*version;
+	ide_startstop_t	(*do_request)(ide_drive_t *, struct request *, sector_t);
+	int		(*end_request)(ide_drive_t *, int, int);
+	ide_startstop_t	(*error)(ide_drive_t *, struct request *rq, u8, u8);
+	struct device_driver	gen_driver;
+	int		(*probe)(ide_drive_t *);
+	void		(*remove)(ide_drive_t *);
+	void		(*resume)(ide_drive_t *);
+	void		(*shutdown)(ide_drive_t *);
+#ifdef CONFIG_IDE_PROC_FS
+	ide_proc_entry_t		*proc;
+	const struct ide_proc_devset	*settings;
+#endif
+};
+
+#define to_ide_driver(drv) container_of(drv, ide_driver_t, gen_driver)
+
+int ide_device_get(ide_drive_t *);
+void ide_device_put(ide_drive_t *);
+
+struct ide_ioctl_devset {
+	unsigned int	get_ioctl;
+	unsigned int	set_ioctl;
+	const struct ide_devset *setting;
+};
+
+int ide_setting_ioctl(ide_drive_t *, struct block_device *, unsigned int,
+		      unsigned long, const struct ide_ioctl_devset *);
+
+int generic_ide_ioctl(ide_drive_t *, struct file *, struct block_device *,
+		      unsigned, unsigned long);
+
+extern int ide_vlb_clk;
+extern int ide_pci_clk;
+
+extern int ide_end_request (ide_drive_t *drive, int uptodate, int nrsecs);
+int ide_end_dequeued_request(ide_drive_t *drive, struct request *rq,
+			     int uptodate, int nr_sectors);
+
+extern void ide_set_handler (ide_drive_t *drive, ide_handler_t *handler, unsigned int timeout, ide_expiry_t *expiry);
+
+void ide_execute_command(ide_drive_t *, u8, ide_handler_t *, unsigned int,
+			 ide_expiry_t *);
+
+void ide_execute_pkt_cmd(ide_drive_t *);
+
+void ide_pad_transfer(ide_drive_t *, int, int);
+
+ide_startstop_t __ide_error(ide_drive_t *, struct request *, u8, u8);
+
+ide_startstop_t ide_error (ide_drive_t *drive, const char *msg, byte stat);
+
+void ide_fix_driveid(u16 *);
+
+extern void ide_fixstring(u8 *, const int, const int);
+
+int ide_busy_sleep(ide_hwif_t *, unsigned long, int);
+
+int ide_wait_stat(ide_startstop_t *, ide_drive_t *, u8, u8, unsigned long);
+
+extern ide_startstop_t ide_do_reset (ide_drive_t *);
+
+extern int ide_devset_execute(ide_drive_t *drive,
+			      const struct ide_devset *setting, int arg);
+
+extern void ide_do_drive_cmd(ide_drive_t *, struct request *);
+
+extern void ide_end_drive_cmd(ide_drive_t *, u8, u8);
+
 void ide_tf_dump(const char *, struct ide_taskfile *);
 
 void ide_exec_command(ide_hwif_t *, u8);
@@ -1049,6 +1197,8 @@
 void ide_input_data(ide_drive_t *, struct request *, void *, unsigned int);
 void ide_output_data(ide_drive_t *, struct request *, void *, unsigned int);
 
+int ide_io_buffers(ide_drive_t *, struct ide_atapi_pc *, unsigned int, int);
+
 extern void SELECT_DRIVE(ide_drive_t *);
 void SELECT_MASK(ide_drive_t *, int);
 
@@ -1059,16 +1209,46 @@
 
 void ide_pktcmd_tf_load(ide_drive_t *, u32, u16, u8);
 
-ide_startstop_t ide_pc_intr(ide_drive_t *drive, struct ide_atapi_pc *pc,
-	ide_handler_t *handler, unsigned int timeout, ide_expiry_t *expiry,
-	void (*update_buffers)(ide_drive_t *, struct ide_atapi_pc *),
-	void (*retry_pc)(ide_drive_t *), void (*dsc_handle)(ide_drive_t *),
-	void (*io_buffers)(ide_drive_t *, struct ide_atapi_pc *, unsigned int,
-			   int));
-ide_startstop_t ide_transfer_pc(ide_drive_t *, struct ide_atapi_pc *,
-				ide_handler_t *, unsigned int, ide_expiry_t *);
-ide_startstop_t ide_issue_pc(ide_drive_t *, struct ide_atapi_pc *,
-			     ide_handler_t *, unsigned int, ide_expiry_t *);
+int ide_check_atapi_device(ide_drive_t *, const char *);
+
+void ide_init_pc(struct ide_atapi_pc *);
+
+/* Disk head parking */
+extern wait_queue_head_t ide_park_wq;
+ssize_t ide_park_show(struct device *dev, struct device_attribute *attr,
+		      char *buf);
+ssize_t ide_park_store(struct device *dev, struct device_attribute *attr,
+		       const char *buf, size_t len);
+
+/*
+ * Special requests for ide-tape block device strategy routine.
+ *
+ * In order to service a character device command, we add special requests to
+ * the tail of our block device request queue and wait for their completion.
+ */
+enum {
+	REQ_IDETAPE_PC1		= (1 << 0), /* packet command (first stage) */
+	REQ_IDETAPE_PC2		= (1 << 1), /* packet command (second stage) */
+	REQ_IDETAPE_READ	= (1 << 2),
+	REQ_IDETAPE_WRITE	= (1 << 3),
+};
+
+int ide_queue_pc_tail(ide_drive_t *, struct gendisk *, struct ide_atapi_pc *);
+
+int ide_do_test_unit_ready(ide_drive_t *, struct gendisk *);
+int ide_do_start_stop(ide_drive_t *, struct gendisk *, int);
+int ide_set_media_lock(ide_drive_t *, struct gendisk *, int);
+void ide_create_request_sense_cmd(ide_drive_t *, struct ide_atapi_pc *);
+void ide_retry_pc(ide_drive_t *, struct gendisk *);
+
+static inline unsigned long ide_scsi_get_timeout(struct ide_atapi_pc *pc)
+{
+	return max_t(unsigned long, WAIT_CMD, pc->timeout - jiffies);
+}
+
+int ide_scsi_expiry(ide_drive_t *);
+
+ide_startstop_t ide_issue_pc(ide_drive_t *, unsigned int, ide_expiry_t *);
 
 ide_startstop_t do_rw_taskfile(ide_drive_t *, ide_task_t *);
 
@@ -1078,8 +1258,6 @@
 int ide_no_data_taskfile(ide_drive_t *, ide_task_t *);
 
 int ide_taskfile_ioctl(ide_drive_t *, unsigned int, unsigned long);
-int ide_cmd_ioctl(ide_drive_t *, unsigned int, unsigned long);
-int ide_task_ioctl(ide_drive_t *, unsigned int, unsigned long);
 
 extern int ide_driveid_update(ide_drive_t *);
 extern int ide_config_drive_speed(ide_drive_t *, u8);
@@ -1090,7 +1268,6 @@
 
 extern void ide_stall_queue(ide_drive_t *drive, unsigned long timeout);
 
-extern int ide_spin_wait_hwgroup(ide_drive_t *);
 extern void ide_timer_expiry(unsigned long);
 extern irqreturn_t ide_intr(int irq, void *dev_id);
 extern void do_ide_request(struct request_queue *);
@@ -1227,6 +1404,14 @@
 		     const struct ide_port_info *, void *);
 void ide_pci_remove(struct pci_dev *);
 
+#ifdef CONFIG_PM
+int ide_pci_suspend(struct pci_dev *, pm_message_t);
+int ide_pci_resume(struct pci_dev *);
+#else
+#define ide_pci_suspend NULL
+#define ide_pci_resume NULL
+#endif
+
 void ide_map_sg(ide_drive_t *, struct request *);
 void ide_init_sg_cmd(ide_drive_t *, struct request *);
 
@@ -1238,9 +1423,10 @@
 	const char *id_firmware;
 };
 
-int ide_in_drive_list(struct hd_driveid *, const struct drive_list_entry *);
+int ide_in_drive_list(u16 *, const struct drive_list_entry *);
 
 #ifdef CONFIG_BLK_DEV_IDEDMA
+int ide_dma_good_drive(ide_drive_t *);
 int __ide_dma_bad_drive(ide_drive_t *);
 int ide_id_dma_bug(ide_drive_t *);
 
@@ -1258,25 +1444,29 @@
 void ide_check_dma_crc(ide_drive_t *);
 ide_startstop_t ide_dma_intr(ide_drive_t *);
 
+int ide_allocate_dma_engine(ide_hwif_t *);
+void ide_release_dma_engine(ide_hwif_t *);
+
 int ide_build_sglist(ide_drive_t *, struct request *);
 void ide_destroy_dmatable(ide_drive_t *);
 
 #ifdef CONFIG_BLK_DEV_IDEDMA_SFF
+int config_drive_for_dma(ide_drive_t *);
 extern int ide_build_dmatable(ide_drive_t *, struct request *);
-int ide_allocate_dma_engine(ide_hwif_t *);
-void ide_release_dma_engine(ide_hwif_t *);
-
 void ide_dma_host_set(ide_drive_t *, int);
 extern int ide_dma_setup(ide_drive_t *);
 void ide_dma_exec_cmd(ide_drive_t *, u8);
 extern void ide_dma_start(ide_drive_t *);
-extern int __ide_dma_end(ide_drive_t *);
+int ide_dma_end(ide_drive_t *);
 int ide_dma_test_irq(ide_drive_t *);
-extern void ide_dma_lost_irq(ide_drive_t *);
-extern void ide_dma_timeout(ide_drive_t *);
 extern const struct ide_dma_ops sff_dma_ops;
+#else
+static inline int config_drive_for_dma(ide_drive_t *drive) { return 0; }
 #endif /* CONFIG_BLK_DEV_IDEDMA_SFF */
 
+void ide_dma_lost_irq(ide_drive_t *);
+void ide_dma_timeout(ide_drive_t *);
+
 #else
 static inline int ide_id_dma_bug(ide_drive_t *drive) { return 0; }
 static inline u8 ide_find_dma_mode(ide_drive_t *drive, u8 speed) { return 0; }
@@ -1287,11 +1477,8 @@
 static inline void ide_dma_verbose(ide_drive_t *drive) { ; }
 static inline int ide_set_dma(ide_drive_t *drive) { return 1; }
 static inline void ide_check_dma_crc(ide_drive_t *drive) { ; }
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-
-#ifndef CONFIG_BLK_DEV_IDEDMA_SFF
 static inline void ide_release_dma_engine(ide_hwif_t *hwif) { ; }
-#endif
+#endif /* CONFIG_BLK_DEV_IDEDMA */
 
 #ifdef CONFIG_BLK_DEV_IDEACPI
 extern int ide_acpi_exec_tfs(ide_drive_t *drive);
@@ -1319,7 +1506,6 @@
 
 void ide_port_apply_params(ide_hwif_t *);
 
-struct ide_host *ide_host_alloc_all(const struct ide_port_info *, hw_regs_t **);
 struct ide_host *ide_host_alloc(const struct ide_port_info *, hw_regs_t **);
 void ide_host_free(struct ide_host *);
 int ide_host_register(struct ide_host *, const struct ide_port_info *,
@@ -1345,24 +1531,6 @@
 extern void ide_toggle_bounce(ide_drive_t *drive, int on);
 extern int ide_set_xfer_rate(ide_drive_t *drive, u8 rate);
 
-static inline int ide_dev_has_iordy(struct hd_driveid *id)
-{
-	return ((id->field_valid & 2) && (id->capability & 8)) ? 1 : 0;
-}
-
-static inline int ide_dev_is_sata(struct hd_driveid *id)
-{
-	/*
-	 * See if word 93 is 0 AND drive is at least ATA-5 compatible
-	 * verifying that word 80 by casting it to a signed type --
-	 * this trick allows us to filter out the reserved values of
-	 * 0x0000 and 0xffff along with the earlier ATA revisions...
-	 */
-	if (id->hw_config == 0 && (short)id->major_rev_num >= 0x0020)
-		return 1;
-	return 0;
-}
-
 u64 ide_get_lba_addr(struct ide_taskfile *, int);
 u8 ide_dump_status(ide_drive_t *, const char *, u8);
 
@@ -1434,13 +1602,6 @@
 extern struct bus_type ide_bus_type;
 extern struct class *ide_port_class;
 
-/* check if CACHE FLUSH (EXT) command is supported (bits defined in ATA-6) */
-#define ide_id_has_flush_cache(id)	((id)->cfs_enable_2 & 0x3000)
-
-/* some Maxtor disks have bit 13 defined incorrectly so check bit 10 too */
-#define ide_id_has_flush_cache_ext(id)	\
-	(((id)->cfs_enable_2 & 0x2400) == 0x2400)
-
 static inline void ide_dump_identify(u8 *id)
 {
 	print_hex_dump(KERN_INFO, "", DUMP_PREFIX_NONE, 16, 2, id, 512, 0);
@@ -1451,10 +1612,10 @@
 	return hwif->dev ? dev_to_node(hwif->dev) : -1;
 }
 
-static inline ide_drive_t *ide_get_paired_drive(ide_drive_t *drive)
+static inline ide_drive_t *ide_get_pair_dev(ide_drive_t *drive)
 {
-	ide_hwif_t *hwif	= HWIF(drive);
+	ide_drive_t *peer = &drive->hwif->drives[(drive->dn ^ 1) & 1];
 
-	return &hwif->drives[(drive->dn ^ 1) & 1];
+	return (peer->dev_flags & IDE_DFLAG_PRESENT) ? peer : NULL;
 }
 #endif /* _IDE_H */
diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h
index 7f4df7c..14126bc 100644
--- a/include/linux/ieee80211.h
+++ b/include/linux/ieee80211.h
@@ -471,6 +471,11 @@
 	u8 eaddr3[6];
 } __attribute__ ((packed));
 
+/* Mesh flags */
+#define MESH_FLAGS_AE_A4 	0x1
+#define MESH_FLAGS_AE_A5_A6	0x2
+#define MESH_FLAGS_PS_DEEP	0x4
+
 /**
  * struct ieee80211_quiet_ie
  *
@@ -643,6 +648,9 @@
 	} u;
 } __attribute__ ((packed));
 
+/* mgmt header + 1 byte category code */
+#define IEEE80211_MIN_ACTION_SIZE offsetof(struct ieee80211_mgmt, u.action.u)
+
 
 /* Control frames */
 struct ieee80211_rts {
@@ -708,12 +716,13 @@
 
 /* 802.11n HT capabilities masks */
 #define IEEE80211_HT_CAP_SUP_WIDTH		0x0002
-#define IEEE80211_HT_CAP_MIMO_PS		0x000C
+#define IEEE80211_HT_CAP_SM_PS			0x000C
 #define IEEE80211_HT_CAP_GRN_FLD		0x0010
 #define IEEE80211_HT_CAP_SGI_20			0x0020
 #define IEEE80211_HT_CAP_SGI_40			0x0040
 #define IEEE80211_HT_CAP_DELAY_BA		0x0400
 #define IEEE80211_HT_CAP_MAX_AMSDU		0x0800
+#define IEEE80211_HT_CAP_DSSSCCK40		0x1000
 /* 802.11n HT capability AMPDU settings */
 #define IEEE80211_HT_CAP_AMPDU_FACTOR		0x03
 #define IEEE80211_HT_CAP_AMPDU_DENSITY		0x1C
@@ -736,11 +745,26 @@
 #define IEEE80211_HT_IE_NON_GF_STA_PRSNT	0x0004
 #define IEEE80211_HT_IE_NON_HT_STA_PRSNT	0x0010
 
-/* MIMO Power Save Modes */
-#define WLAN_HT_CAP_MIMO_PS_STATIC	0
-#define WLAN_HT_CAP_MIMO_PS_DYNAMIC	1
-#define WLAN_HT_CAP_MIMO_PS_INVALID	2
-#define WLAN_HT_CAP_MIMO_PS_DISABLED	3
+/* block-ack parameters */
+#define IEEE80211_ADDBA_PARAM_POLICY_MASK 0x0002
+#define IEEE80211_ADDBA_PARAM_TID_MASK 0x003C
+#define IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK 0xFFA0
+#define IEEE80211_DELBA_PARAM_TID_MASK 0xF000
+#define IEEE80211_DELBA_PARAM_INITIATOR_MASK 0x0800
+
+/*
+ * A-PMDU buffer sizes
+ * According to IEEE802.11n spec size varies from 8K to 64K (in powers of 2)
+ */
+#define IEEE80211_MIN_AMPDU_BUF 0x8
+#define IEEE80211_MAX_AMPDU_BUF 0x40
+
+
+/* Spatial Multiplexing Power Save Modes */
+#define WLAN_HT_CAP_SM_PS_STATIC	0
+#define WLAN_HT_CAP_SM_PS_DYNAMIC	1
+#define WLAN_HT_CAP_SM_PS_INVALID	2
+#define WLAN_HT_CAP_SM_PS_DISABLED	3
 
 /* Authentication algorithms */
 #define WLAN_AUTH_OPEN 0
diff --git a/include/linux/if.h b/include/linux/if.h
index 5c9d1fa..6524684 100644
--- a/include/linux/if.h
+++ b/include/linux/if.h
@@ -24,6 +24,7 @@
 #include <linux/compiler.h>		/* for "__user" et al           */
 
 #define	IFNAMSIZ	16
+#define	IFALIASZ	256
 #include <linux/hdlc/ioctl.h>
 
 /* Standard interface flags (netdevice->flags). */
diff --git a/include/linux/if_ether.h b/include/linux/if_ether.h
index e157c13..7f3c735 100644
--- a/include/linux/if_ether.h
+++ b/include/linux/if_ether.h
@@ -9,7 +9,7 @@
  *
  * Author:	Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
  *		Donald Becker, <becker@super.org>
- *		Alan Cox, <alan@redhat.com>
+ *		Alan Cox, <alan@lxorguk.ukuu.org.uk>
  *		Steve Whitehouse, <gw7rrm@eeshack3.swan.ac.uk>
  *
  *		This program is free software; you can redistribute it and/or
@@ -56,6 +56,7 @@
 #define ETH_P_DIAG      0x6005          /* DEC Diagnostics              */
 #define ETH_P_CUST      0x6006          /* DEC Customer use             */
 #define ETH_P_SCA       0x6007          /* DEC Systems Comms Arch       */
+#define ETH_P_TEB	0x6558		/* Trans Ether Bridging		*/
 #define ETH_P_RARP      0x8035		/* Reverse Addr Res packet	*/
 #define ETH_P_ATALK	0x809B		/* Appletalk DDP		*/
 #define ETH_P_AARP	0x80F3		/* Appletalk AARP		*/
@@ -74,8 +75,10 @@
 #define ETH_P_ATMFATE	0x8884		/* Frame-based ATM Transport
 					 * over Ethernet
 					 */
+#define ETH_P_PAE	0x888E		/* Port Access Entity (IEEE 802.1X) */
 #define ETH_P_AOE	0x88A2		/* ATA over Ethernet		*/
 #define ETH_P_TIPC	0x88CA		/* TIPC 			*/
+#define ETH_P_EDSA	0xDADA		/* Ethertype DSA [ NOT AN OFFICIALLY REGISTERED ID ] */
 
 /*
  *	Non DIX types. Won't clash for 1500 types.
@@ -99,6 +102,9 @@
 #define ETH_P_ECONET	0x0018		/* Acorn Econet			*/
 #define ETH_P_HDLC	0x0019		/* HDLC frames			*/
 #define ETH_P_ARCNET	0x001A		/* 1A for ArcNet :-)            */
+#define ETH_P_DSA	0x001B		/* Distributed Switch Arch.	*/
+#define ETH_P_TRAILER	0x001C		/* Trailer switch tagging	*/
+#define ETH_P_PHONET	0x00F5		/* Nokia Phonet frames          */
 
 /*
  *	This is an Ethernet frame header.
diff --git a/include/linux/if_fddi.h b/include/linux/if_fddi.h
index ae77dae..45de104 100644
--- a/include/linux/if_fddi.h
+++ b/include/linux/if_fddi.h
@@ -12,7 +12,7 @@
  *		if_fddi.h is based on previous if_ether.h and if_tr.h work by
  *			Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
  *			Donald Becker, <becker@super.org>
- *			Alan Cox, <alan@redhat.com>
+ *			Alan Cox, <alan@lxorguk.ukuu.org.uk>
  *			Steve Whitehouse, <gw7rrm@eeshack3.swan.ac.uk>
  *			Peter De Schrijver, <stud11@cc4.kuleuven.ac.be>
  *
diff --git a/include/linux/if_hippi.h b/include/linux/if_hippi.h
index 94d31ca..f0f2351 100644
--- a/include/linux/if_hippi.h
+++ b/include/linux/if_hippi.h
@@ -9,7 +9,7 @@
  *
  * Author:	Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
  *		Donald Becker, <becker@super.org>
- *		Alan Cox, <alan@redhat.com>
+ *		Alan Cox, <alan@lxorguk.ukuu.org.uk>
  *		Steve Whitehouse, <gw7rrm@eeshack3.swan.ac.uk>
  *		Jes Sorensen, <Jes.Sorensen@cern.ch>
  *
diff --git a/include/linux/if_link.h b/include/linux/if_link.h
index 84c3492..f9032c8 100644
--- a/include/linux/if_link.h
+++ b/include/linux/if_link.h
@@ -79,6 +79,7 @@
 	IFLA_LINKINFO,
 #define IFLA_LINKINFO IFLA_LINKINFO
 	IFLA_NET_NS_PID,
+	IFLA_IFALIAS,
 	__IFLA_MAX
 };
 
diff --git a/include/linux/if_phonet.h b/include/linux/if_phonet.h
new file mode 100644
index 0000000..d70034b
--- /dev/null
+++ b/include/linux/if_phonet.h
@@ -0,0 +1,19 @@
+/*
+ * File: if_phonet.h
+ *
+ * Phonet interface kernel definitions
+ *
+ * Copyright (C) 2008 Nokia Corporation. All rights reserved.
+ */
+#ifndef LINUX_IF_PHONET_H
+#define LINUX_IF_PHONET_H
+
+#define PHONET_MIN_MTU		6	/* pn_length = 0 */
+#define PHONET_MAX_MTU		65541	/* pn_length = 0xffff */
+#define PHONET_DEV_MTU		PHONET_MAX_MTU
+
+#ifdef __KERNEL__
+extern struct header_ops phonet_header_ops;
+#endif
+
+#endif
diff --git a/include/linux/if_tunnel.h b/include/linux/if_tunnel.h
index d4efe40..aeab2cb 100644
--- a/include/linux/if_tunnel.h
+++ b/include/linux/if_tunnel.h
@@ -2,6 +2,7 @@
 #define _IF_TUNNEL_H_
 
 #include <linux/types.h>
+#include <linux/ip.h>
 
 #define SIOCGETTUNNEL   (SIOCDEVPRIVATE + 0)
 #define SIOCADDTUNNEL   (SIOCDEVPRIVATE + 1)
@@ -47,4 +48,22 @@
 /* PRL flags */
 #define	PRL_DEFAULT		0x0001
 
+enum
+{
+	IFLA_GRE_UNSPEC,
+	IFLA_GRE_LINK,
+	IFLA_GRE_IFLAGS,
+	IFLA_GRE_OFLAGS,
+	IFLA_GRE_IKEY,
+	IFLA_GRE_OKEY,
+	IFLA_GRE_LOCAL,
+	IFLA_GRE_REMOTE,
+	IFLA_GRE_TTL,
+	IFLA_GRE_TOS,
+	IFLA_GRE_PMTUDISC,
+	__IFLA_GRE_MAX,
+};
+
+#define IFLA_GRE_MAX	(__IFLA_GRE_MAX - 1)
+
 #endif /* _IF_TUNNEL_H_ */
diff --git a/include/linux/igmp.h b/include/linux/igmp.h
index 7bb3c09..f734a0b 100644
--- a/include/linux/igmp.h
+++ b/include/linux/igmp.h
@@ -2,7 +2,7 @@
  *	Linux NET3:	Internet Group Management Protocol  [IGMP]
  *
  *	Authors:
- *		Alan Cox <Alan.Cox@linux.org>
+ *		Alan Cox <alan@lxorguk.ukuu.org.uk>
  *
  *	Extended to talk the BSD extended IGMP protocol of mrouted 3.6
  *
diff --git a/include/linux/in.h b/include/linux/in.h
index 4065313..db458be 100644
--- a/include/linux/in.h
+++ b/include/linux/in.h
@@ -75,6 +75,7 @@
 #define IP_IPSEC_POLICY	16
 #define IP_XFRM_POLICY	17
 #define IP_PASSSEC	18
+#define IP_TRANSPARENT	19
 
 /* BSD compatibility */
 #define IP_RECVRETOPTS	IP_RETOPTS
diff --git a/include/linux/inetdevice.h b/include/linux/inetdevice.h
index c6f51ad..06fcdb4 100644
--- a/include/linux/inetdevice.h
+++ b/include/linux/inetdevice.h
@@ -25,6 +25,7 @@
 	struct in_ifaddr	*ifa_list;	/* IP ifaddr chain		*/
 	rwlock_t		mc_list_lock;
 	struct ip_mc_list	*mc_list;	/* IP multicast filter chain    */
+	int			mc_count;	          /* Number of installed mcasts	*/
 	spinlock_t		mc_tomb_lock;
 	struct ip_mc_list	*mc_tomb;
 	unsigned long		mr_v1_seen;
diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h
index 58ff4e7..54b3623 100644
--- a/include/linux/interrupt.h
+++ b/include/linux/interrupt.h
@@ -252,6 +252,8 @@
 	HRTIMER_SOFTIRQ,
 #endif
 	RCU_SOFTIRQ, 	/* Preferable RCU should always be the last softirq */
+
+	NR_SOFTIRQS
 };
 
 /* softirq mask and active fields moved to irq_cpustat_t in
diff --git a/include/linux/iommu-helper.h b/include/linux/iommu-helper.h
index c975caf..a6d0586 100644
--- a/include/linux/iommu-helper.h
+++ b/include/linux/iommu-helper.h
@@ -1,6 +1,20 @@
+#ifndef _LINUX_IOMMU_HELPER_H
+#define _LINUX_IOMMU_HELPER_H
+
+static inline unsigned long iommu_device_max_index(unsigned long size,
+						   unsigned long offset,
+						   u64 dma_mask)
+{
+	if (size + offset > dma_mask)
+		return dma_mask - offset + 1;
+	else
+		return size;
+}
+
 extern int iommu_is_span_boundary(unsigned int index, unsigned int nr,
 				  unsigned long shift,
 				  unsigned long boundary_size);
+extern void iommu_area_reserve(unsigned long *map, unsigned long i, int len);
 extern unsigned long iommu_area_alloc(unsigned long *map, unsigned long size,
 				      unsigned long start, unsigned int nr,
 				      unsigned long shift,
@@ -8,3 +22,5 @@
 				      unsigned long align_mask);
 extern void iommu_area_free(unsigned long *map, unsigned long start,
 			    unsigned int nr);
+
+#endif
diff --git a/include/linux/ioport.h b/include/linux/ioport.h
index 350033e..e38b6aa 100644
--- a/include/linux/ioport.h
+++ b/include/linux/ioport.h
@@ -108,6 +108,9 @@
 
 extern int request_resource(struct resource *root, struct resource *new);
 extern int release_resource(struct resource *new);
+extern void reserve_region_with_split(struct resource *root,
+			     resource_size_t start, resource_size_t end,
+			     const char *name);
 extern int insert_resource(struct resource *parent, struct resource *new);
 extern void insert_resource_expand_to_fit(struct resource *root, struct resource *new);
 extern int allocate_resource(struct resource *root, struct resource *new,
@@ -166,6 +169,7 @@
 
 extern void __devm_release_region(struct device *dev, struct resource *parent,
 				  resource_size_t start, resource_size_t n);
+extern int iomem_map_sanity_check(resource_size_t addr, unsigned long size);
 
 #endif /* __ASSEMBLY__ */
 #endif	/* _LINUX_IOPORT_H */
diff --git a/include/linux/ip_vs.h b/include/linux/ip_vs.h
index ec6eb49..0f434a2 100644
--- a/include/linux/ip_vs.h
+++ b/include/linux/ip_vs.h
@@ -242,4 +242,164 @@
 	int			syncid;
 };
 
+/*
+ *
+ * IPVS Generic Netlink interface definitions
+ *
+ */
+
+/* Generic Netlink family info */
+
+#define IPVS_GENL_NAME		"IPVS"
+#define IPVS_GENL_VERSION	0x1
+
+struct ip_vs_flags {
+	__be32 flags;
+	__be32 mask;
+};
+
+/* Generic Netlink command attributes */
+enum {
+	IPVS_CMD_UNSPEC = 0,
+
+	IPVS_CMD_NEW_SERVICE,		/* add service */
+	IPVS_CMD_SET_SERVICE,		/* modify service */
+	IPVS_CMD_DEL_SERVICE,		/* delete service */
+	IPVS_CMD_GET_SERVICE,		/* get service info */
+
+	IPVS_CMD_NEW_DEST,		/* add destination */
+	IPVS_CMD_SET_DEST,		/* modify destination */
+	IPVS_CMD_DEL_DEST,		/* delete destination */
+	IPVS_CMD_GET_DEST,		/* get destination info */
+
+	IPVS_CMD_NEW_DAEMON,		/* start sync daemon */
+	IPVS_CMD_DEL_DAEMON,		/* stop sync daemon */
+	IPVS_CMD_GET_DAEMON,		/* get sync daemon status */
+
+	IPVS_CMD_SET_CONFIG,		/* set config settings */
+	IPVS_CMD_GET_CONFIG,		/* get config settings */
+
+	IPVS_CMD_SET_INFO,		/* only used in GET_INFO reply */
+	IPVS_CMD_GET_INFO,		/* get general IPVS info */
+
+	IPVS_CMD_ZERO,			/* zero all counters and stats */
+	IPVS_CMD_FLUSH,			/* flush services and dests */
+
+	__IPVS_CMD_MAX,
+};
+
+#define IPVS_CMD_MAX (__IPVS_CMD_MAX - 1)
+
+/* Attributes used in the first level of commands */
+enum {
+	IPVS_CMD_ATTR_UNSPEC = 0,
+	IPVS_CMD_ATTR_SERVICE,		/* nested service attribute */
+	IPVS_CMD_ATTR_DEST,		/* nested destination attribute */
+	IPVS_CMD_ATTR_DAEMON,		/* nested sync daemon attribute */
+	IPVS_CMD_ATTR_TIMEOUT_TCP,	/* TCP connection timeout */
+	IPVS_CMD_ATTR_TIMEOUT_TCP_FIN,	/* TCP FIN wait timeout */
+	IPVS_CMD_ATTR_TIMEOUT_UDP,	/* UDP timeout */
+	__IPVS_CMD_ATTR_MAX,
+};
+
+#define IPVS_CMD_ATTR_MAX (__IPVS_SVC_ATTR_MAX - 1)
+
+/*
+ * Attributes used to describe a service
+ *
+ * Used inside nested attribute IPVS_CMD_ATTR_SERVICE
+ */
+enum {
+	IPVS_SVC_ATTR_UNSPEC = 0,
+	IPVS_SVC_ATTR_AF,		/* address family */
+	IPVS_SVC_ATTR_PROTOCOL,		/* virtual service protocol */
+	IPVS_SVC_ATTR_ADDR,		/* virtual service address */
+	IPVS_SVC_ATTR_PORT,		/* virtual service port */
+	IPVS_SVC_ATTR_FWMARK,		/* firewall mark of service */
+
+	IPVS_SVC_ATTR_SCHED_NAME,	/* name of scheduler */
+	IPVS_SVC_ATTR_FLAGS,		/* virtual service flags */
+	IPVS_SVC_ATTR_TIMEOUT,		/* persistent timeout */
+	IPVS_SVC_ATTR_NETMASK,		/* persistent netmask */
+
+	IPVS_SVC_ATTR_STATS,		/* nested attribute for service stats */
+	__IPVS_SVC_ATTR_MAX,
+};
+
+#define IPVS_SVC_ATTR_MAX (__IPVS_SVC_ATTR_MAX - 1)
+
+/*
+ * Attributes used to describe a destination (real server)
+ *
+ * Used inside nested attribute IPVS_CMD_ATTR_DEST
+ */
+enum {
+	IPVS_DEST_ATTR_UNSPEC = 0,
+	IPVS_DEST_ATTR_ADDR,		/* real server address */
+	IPVS_DEST_ATTR_PORT,		/* real server port */
+
+	IPVS_DEST_ATTR_FWD_METHOD,	/* forwarding method */
+	IPVS_DEST_ATTR_WEIGHT,		/* destination weight */
+
+	IPVS_DEST_ATTR_U_THRESH,	/* upper threshold */
+	IPVS_DEST_ATTR_L_THRESH,	/* lower threshold */
+
+	IPVS_DEST_ATTR_ACTIVE_CONNS,	/* active connections */
+	IPVS_DEST_ATTR_INACT_CONNS,	/* inactive connections */
+	IPVS_DEST_ATTR_PERSIST_CONNS,	/* persistent connections */
+
+	IPVS_DEST_ATTR_STATS,		/* nested attribute for dest stats */
+	__IPVS_DEST_ATTR_MAX,
+};
+
+#define IPVS_DEST_ATTR_MAX (__IPVS_DEST_ATTR_MAX - 1)
+
+/*
+ * Attributes describing a sync daemon
+ *
+ * Used inside nested attribute IPVS_CMD_ATTR_DAEMON
+ */
+enum {
+	IPVS_DAEMON_ATTR_UNSPEC = 0,
+	IPVS_DAEMON_ATTR_STATE,		/* sync daemon state (master/backup) */
+	IPVS_DAEMON_ATTR_MCAST_IFN,	/* multicast interface name */
+	IPVS_DAEMON_ATTR_SYNC_ID,	/* SyncID we belong to */
+	__IPVS_DAEMON_ATTR_MAX,
+};
+
+#define IPVS_DAEMON_ATTR_MAX (__IPVS_DAEMON_ATTR_MAX - 1)
+
+/*
+ * Attributes used to describe service or destination entry statistics
+ *
+ * Used inside nested attributes IPVS_SVC_ATTR_STATS and IPVS_DEST_ATTR_STATS
+ */
+enum {
+	IPVS_STATS_ATTR_UNSPEC = 0,
+	IPVS_STATS_ATTR_CONNS,		/* connections scheduled */
+	IPVS_STATS_ATTR_INPKTS,		/* incoming packets */
+	IPVS_STATS_ATTR_OUTPKTS,	/* outgoing packets */
+	IPVS_STATS_ATTR_INBYTES,	/* incoming bytes */
+	IPVS_STATS_ATTR_OUTBYTES,	/* outgoing bytes */
+
+	IPVS_STATS_ATTR_CPS,		/* current connection rate */
+	IPVS_STATS_ATTR_INPPS,		/* current in packet rate */
+	IPVS_STATS_ATTR_OUTPPS,		/* current out packet rate */
+	IPVS_STATS_ATTR_INBPS,		/* current in byte rate */
+	IPVS_STATS_ATTR_OUTBPS,		/* current out byte rate */
+	__IPVS_STATS_ATTR_MAX,
+};
+
+#define IPVS_STATS_ATTR_MAX (__IPVS_STATS_ATTR_MAX - 1)
+
+/* Attributes used in response to IPVS_CMD_GET_INFO command */
+enum {
+	IPVS_INFO_ATTR_UNSPEC = 0,
+	IPVS_INFO_ATTR_VERSION,		/* IPVS version number */
+	IPVS_INFO_ATTR_CONN_TAB_SIZE,	/* size of connection hash table */
+	__IPVS_INFO_ATTR_MAX,
+};
+
+#define IPVS_INFO_ATTR_MAX (__IPVS_INFO_ATTR_MAX - 1)
+
 #endif	/* _IP_VS_H */
diff --git a/include/linux/irq.h b/include/linux/irq.h
index 8ccb462..8d9411b 100644
--- a/include/linux/irq.h
+++ b/include/linux/irq.h
@@ -62,6 +62,7 @@
 #define IRQ_MOVE_PENDING	0x00200000	/* need to re-target IRQ destination */
 #define IRQ_NO_BALANCING	0x00400000	/* IRQ is excluded from balancing */
 #define IRQ_SPURIOUS_DISABLED	0x00800000	/* IRQ was disabled by the spurious trap */
+#define IRQ_MOVE_PCNTXT	0x01000000	/* IRQ migration from process context */
 
 #ifdef CONFIG_IRQ_PER_CPU
 # define CHECK_IRQ_PER_CPU(var) ((var) & IRQ_PER_CPU)
diff --git a/include/linux/isdn_ppp.h b/include/linux/isdn_ppp.h
index 8687a7d..4c218ee 100644
--- a/include/linux/isdn_ppp.h
+++ b/include/linux/isdn_ppp.h
@@ -157,7 +157,7 @@
 
 typedef struct {
   int mp_mrru;                        /* unused                             */
-  struct sk_buff * frags;	/* fragments sl list -- use skb->next */
+  struct sk_buff_head frags;	/* fragments sl list */
   long frames;			/* number of frames in the frame list */
   unsigned int seq;		/* last processed packet seq #: any packets
   				 * with smaller seq # will be dropped
diff --git a/include/linux/ivtv.h b/include/linux/ivtv.h
index 17ca64b..f272028 100644
--- a/include/linux/ivtv.h
+++ b/include/linux/ivtv.h
@@ -23,6 +23,7 @@
 
 #include <linux/compiler.h>
 #include <linux/types.h>
+#include <linux/videodev2.h>
 
 /* ivtv knows several distinct output modes: MPEG streaming,
    YUV streaming, YUV updates through user DMA and the passthrough
diff --git a/include/linux/jbd2.h b/include/linux/jbd2.h
index 3dd2090..d2e91ea 100644
--- a/include/linux/jbd2.h
+++ b/include/linux/jbd2.h
@@ -850,7 +850,8 @@
 	 */
 	struct block_device	*j_dev;
 	int			j_blocksize;
-	unsigned long long		j_blk_offset;
+	unsigned long long	j_blk_offset;
+	char			j_devname[BDEVNAME_SIZE+24];
 
 	/*
 	 * Device which holds the client fs.  For internal journal this will be
@@ -966,6 +967,9 @@
 #define JBD2_FLUSHED	0x008	/* The journal superblock has been flushed */
 #define JBD2_LOADED	0x010	/* The journal superblock has been loaded */
 #define JBD2_BARRIER	0x020	/* Use IDE barriers */
+#define JBD2_ABORT_ON_SYNCDATA_ERR	0x040	/* Abort the journal on file
+						 * data write error in ordered
+						 * mode */
 
 /*
  * Function declarations for the journaling transaction and buffer
@@ -1059,7 +1063,7 @@
 		   (journal_t *, unsigned long, unsigned long, unsigned long);
 extern int	   jbd2_journal_create     (journal_t *);
 extern int	   jbd2_journal_load       (journal_t *journal);
-extern void	   jbd2_journal_destroy    (journal_t *);
+extern int	   jbd2_journal_destroy    (journal_t *);
 extern int	   jbd2_journal_recover    (journal_t *journal);
 extern int	   jbd2_journal_wipe       (journal_t *, int);
 extern int	   jbd2_journal_skip_recovery	(journal_t *);
diff --git a/include/linux/kernel.h b/include/linux/kernel.h
index 2651f80..9687491 100644
--- a/include/linux/kernel.h
+++ b/include/linux/kernel.h
@@ -182,7 +182,7 @@
 
 extern int get_option(char **str, int *pint);
 extern char *get_options(const char *str, int nints, int *ints);
-extern unsigned long long memparse(char *ptr, char **retptr);
+extern unsigned long long memparse(const char *ptr, char **retptr);
 
 extern int core_kernel_text(unsigned long addr);
 extern int __kernel_text_address(unsigned long addr);
@@ -213,6 +213,9 @@
 		{ return false; }
 #endif
 
+extern int printk_needs_cpu(int cpu);
+extern void printk_tick(void);
+
 extern void asmlinkage __attribute__((format(printf, 1, 2)))
 	early_printk(const char *fmt, ...);
 
diff --git a/include/linux/key.h b/include/linux/key.h
index c45c962..1b70e35 100644
--- a/include/linux/key.h
+++ b/include/linux/key.h
@@ -299,6 +299,7 @@
 #define key_validate(k)			0
 #define key_serial(k)			0
 #define key_get(k) 			({ NULL; })
+#define key_revoke(k)			do { } while(0)
 #define key_put(k)			do { } while(0)
 #define key_ref_put(k)			do { } while(0)
 #define make_key_ref(k, p)			({ NULL; })
diff --git a/include/linux/klist.h b/include/linux/klist.h
index 06c338e..8ea98db 100644
--- a/include/linux/klist.h
+++ b/include/linux/klist.h
@@ -38,7 +38,7 @@
 		       void (*put)(struct klist_node *));
 
 struct klist_node {
-	struct klist		*n_klist;
+	void			*n_klist;	/* never access directly */
 	struct list_head	n_node;
 	struct kref		n_ref;
 	struct completion	n_removed;
@@ -57,7 +57,6 @@
 
 struct klist_iter {
 	struct klist		*i_klist;
-	struct list_head	*i_head;
 	struct klist_node	*i_cur;
 };
 
diff --git a/include/linux/lcd.h b/include/linux/lcd.h
index 173feba..c67feca 100644
--- a/include/linux/lcd.h
+++ b/include/linux/lcd.h
@@ -11,6 +11,7 @@
 #include <linux/device.h>
 #include <linux/mutex.h>
 #include <linux/notifier.h>
+#include <linux/fb.h>
 
 /* Notes on locking:
  *
@@ -45,6 +46,8 @@
 	int (*get_contrast)(struct lcd_device *);
 	/* Set LCD panel contrast */
         int (*set_contrast)(struct lcd_device *, int contrast);
+	/* Set LCD panel mode (resolutions ...) */
+	int (*set_mode)(struct lcd_device *, struct fb_videomode *);
 	/* Check if given framebuffer device is the one LCD is bound to;
 	   return 0 if not, !=0 if it is. If NULL, lcd always matches the fb. */
 	int (*check_fb)(struct lcd_device *, struct fb_info *);
diff --git a/include/linux/libata.h b/include/linux/libata.h
index 225bfc5..947cf84 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -146,6 +146,7 @@
 	ATA_DFLAG_SPUNDOWN	= (1 << 14), /* XXX: for spindown_compat */
 	ATA_DFLAG_SLEEPING	= (1 << 15), /* device is sleeping */
 	ATA_DFLAG_DUBIOUS_XFER	= (1 << 16), /* data transfer not verified */
+	ATA_DFLAG_NO_UNLOAD	= (1 << 17), /* device doesn't support unload */
 	ATA_DFLAG_INIT_MASK	= (1 << 24) - 1,
 
 	ATA_DFLAG_DETACH	= (1 << 24),
@@ -244,6 +245,7 @@
 	ATA_TMOUT_BOOT		= 30000,	/* heuristic */
 	ATA_TMOUT_BOOT_QUICK	=  7000,	/* heuristic */
 	ATA_TMOUT_INTERNAL_QUICK = 5000,
+	ATA_TMOUT_MAX_PARK	= 30000,
 
 	/* FIXME: GoVault needs 2s but we can't afford that without
 	 * parallel probing.  800ms is enough for iVDR disk
@@ -319,8 +321,11 @@
 	ATA_EH_RESET		= ATA_EH_SOFTRESET | ATA_EH_HARDRESET,
 	ATA_EH_ENABLE_LINK	= (1 << 3),
 	ATA_EH_LPM		= (1 << 4),  /* link power management action */
+	ATA_EH_PARK		= (1 << 5), /* unload heads and stop I/O */
 
-	ATA_EH_PERDEV_MASK	= ATA_EH_REVALIDATE,
+	ATA_EH_PERDEV_MASK	= ATA_EH_REVALIDATE | ATA_EH_PARK,
+	ATA_EH_ALL_ACTIONS	= ATA_EH_REVALIDATE | ATA_EH_RESET |
+				  ATA_EH_ENABLE_LINK | ATA_EH_LPM,
 
 	/* ata_eh_info->flags */
 	ATA_EHI_HOTPLUGGED	= (1 << 0),  /* could have been hotplugged */
@@ -452,6 +457,7 @@
 	MEDIUM_POWER,
 };
 extern struct device_attribute dev_attr_link_power_management_policy;
+extern struct device_attribute dev_attr_unload_heads;
 extern struct device_attribute dev_attr_em_message_type;
 extern struct device_attribute dev_attr_em_message;
 extern struct device_attribute dev_attr_sw_activity;
@@ -554,8 +560,8 @@
 struct ata_device {
 	struct ata_link		*link;
 	unsigned int		devno;		/* 0 or 1 */
-	unsigned long		flags;		/* ATA_DFLAG_xxx */
 	unsigned int		horkage;	/* List of broken features */
+	unsigned long		flags;		/* ATA_DFLAG_xxx */
 	struct scsi_device	*sdev;		/* attached SCSI device */
 #ifdef CONFIG_ATA_ACPI
 	acpi_handle		acpi_handle;
@@ -564,6 +570,7 @@
 	/* n_sector is used as CLEAR_OFFSET, read comment above CLEAR_OFFSET */
 	u64			n_sectors;	/* size of device, if ATA */
 	unsigned int		class;		/* ATA_DEV_xxx */
+	unsigned long		unpark_deadline;
 
 	u8			pio_mode;
 	u8			dma_mode;
@@ -621,6 +628,7 @@
 					       [ATA_EH_CMD_TIMEOUT_TABLE_SIZE];
 	unsigned int		classes[ATA_MAX_DEVICES];
 	unsigned int		did_probe_mask;
+	unsigned int		unloaded_mask;
 	unsigned int		saved_ncq_enabled;
 	u8			saved_xfer_mode[ATA_MAX_DEVICES];
 	/* timestamp for the last reset attempt or success */
@@ -688,7 +696,8 @@
 	unsigned int		qc_active;
 	int			nr_active_links; /* #links with active qcs */
 
-	struct ata_link		link;	/* host default link */
+	struct ata_link		link;		/* host default link */
+	struct ata_link		*slave_link;	/* see ata_slave_link_init() */
 
 	int			nr_pmp_links;	/* nr of available PMP links */
 	struct ata_link		*pmp_link;	/* array of PMP links */
@@ -709,6 +718,7 @@
 	struct list_head	eh_done_q;
 	wait_queue_head_t	eh_wait_q;
 	int			eh_tries;
+	struct completion	park_req_pending;
 
 	pm_message_t		pm_mesg;
 	int			*pm_result;
@@ -772,8 +782,8 @@
 	/*
 	 * Optional features
 	 */
-	int  (*scr_read)(struct ata_port *ap, unsigned int sc_reg, u32 *val);
-	int  (*scr_write)(struct ata_port *ap, unsigned int sc_reg, u32 val);
+	int  (*scr_read)(struct ata_link *link, unsigned int sc_reg, u32 *val);
+	int  (*scr_write)(struct ata_link *link, unsigned int sc_reg, u32 val);
 	void (*pmp_attach)(struct ata_port *ap);
 	void (*pmp_detach)(struct ata_port *ap);
 	int  (*enable_pm)(struct ata_port *ap, enum link_pm policy);
@@ -895,6 +905,7 @@
 extern struct ata_host *ata_host_alloc(struct device *dev, int max_ports);
 extern struct ata_host *ata_host_alloc_pinfo(struct device *dev,
 			const struct ata_port_info * const * ppi, int n_ports);
+extern int ata_slave_link_init(struct ata_port *ap);
 extern int ata_host_start(struct ata_host *host);
 extern int ata_host_register(struct ata_host *host,
 			     struct scsi_host_template *sht);
@@ -920,8 +931,8 @@
 extern int sata_scr_read(struct ata_link *link, int reg, u32 *val);
 extern int sata_scr_write(struct ata_link *link, int reg, u32 val);
 extern int sata_scr_write_flush(struct ata_link *link, int reg, u32 val);
-extern int ata_link_online(struct ata_link *link);
-extern int ata_link_offline(struct ata_link *link);
+extern bool ata_link_online(struct ata_link *link);
+extern bool ata_link_offline(struct ata_link *link);
 #ifdef CONFIG_PM
 extern int ata_host_suspend(struct ata_host *host, pm_message_t mesg);
 extern void ata_host_resume(struct ata_host *host);
@@ -1098,6 +1109,7 @@
  */
 extern const struct ata_port_operations ata_base_port_ops;
 extern const struct ata_port_operations sata_port_ops;
+extern struct device_attribute *ata_common_sdev_attrs[];
 
 #define ATA_BASE_SHT(drv_name)					\
 	.module			= THIS_MODULE,			\
@@ -1112,7 +1124,8 @@
 	.proc_name		= drv_name,			\
 	.slave_configure	= ata_scsi_slave_config,	\
 	.slave_destroy		= ata_scsi_slave_destroy,	\
-	.bios_param		= ata_std_bios_param
+	.bios_param		= ata_std_bios_param,		\
+	.sdev_attrs		= ata_common_sdev_attrs
 
 #define ATA_NCQ_SHT(drv_name)					\
 	ATA_BASE_SHT(drv_name),					\
@@ -1134,7 +1147,7 @@
 
 static inline int ata_is_host_link(const struct ata_link *link)
 {
-	return link == &link->ap->link;
+	return link == &link->ap->link || link == link->ap->slave_link;
 }
 #else /* CONFIG_SATA_PMP */
 static inline bool sata_pmp_supported(struct ata_port *ap)
@@ -1167,7 +1180,7 @@
 	printk("%sata%u: "fmt, lv, (ap)->print_id , ##args)
 
 #define ata_link_printk(link, lv, fmt, args...) do { \
-	if (sata_pmp_attached((link)->ap)) \
+	if (sata_pmp_attached((link)->ap) || (link)->ap->slave_link)	\
 		printk("%sata%u.%02u: "fmt, lv, (link)->ap->print_id,	\
 		       (link)->pmp , ##args); \
 	else \
@@ -1265,34 +1278,17 @@
 	return ata_tag_valid(link->active_tag) || link->sactive;
 }
 
-static inline struct ata_link *ata_port_first_link(struct ata_port *ap)
-{
-	if (sata_pmp_attached(ap))
-		return ap->pmp_link;
-	return &ap->link;
-}
+extern struct ata_link *__ata_port_next_link(struct ata_port *ap,
+					     struct ata_link *link,
+					     bool dev_only);
 
-static inline struct ata_link *ata_port_next_link(struct ata_link *link)
-{
-	struct ata_port *ap = link->ap;
-
-	if (ata_is_host_link(link)) {
-		if (!sata_pmp_attached(ap))
-			return NULL;
-		return ap->pmp_link;
-	}
-
-	if (++link < ap->nr_pmp_links + ap->pmp_link)
-		return link;
-	return NULL;
-}
-
-#define __ata_port_for_each_link(lk, ap) \
-	for ((lk) = &(ap)->link; (lk); (lk) = ata_port_next_link(lk))
+#define __ata_port_for_each_link(link, ap) \
+	for ((link) = __ata_port_next_link((ap), NULL, false); (link); \
+	     (link) = __ata_port_next_link((ap), (link), false))
 
 #define ata_port_for_each_link(link, ap) \
-	for ((link) = ata_port_first_link(ap); (link); \
-	     (link) = ata_port_next_link(link))
+	for ((link) = __ata_port_next_link((ap), NULL, true); (link); \
+	     (link) = __ata_port_next_link((ap), (link), true))
 
 #define ata_link_for_each_dev(dev, link) \
 	for ((dev) = (link)->device; \
diff --git a/include/linux/lockd/bind.h b/include/linux/lockd/bind.h
index 3d25bcd..e5872dc 100644
--- a/include/linux/lockd/bind.h
+++ b/include/linux/lockd/bind.h
@@ -27,7 +27,6 @@
 						struct nfs_fh *,
 						struct file **);
 	void			(*fclose)(struct file *);
-	unsigned long		(*get_grace_period)(void);
 };
 
 extern struct nlmsvc_binding *	nlmsvc_ops;
@@ -53,15 +52,7 @@
 
 extern int	nlmclnt_proc(struct nlm_host *host, int cmd,
 					struct file_lock *fl);
-extern int	lockd_up(int proto);
+extern int	lockd_up(void);
 extern void	lockd_down(void);
 
-unsigned long get_nfs_grace_period(void);
-
-#ifdef CONFIG_NFSD_V4
-unsigned long get_nfs4_grace_period(void);
-#else
-static inline unsigned long get_nfs4_grace_period(void) {return 0;}
-#endif
-
 #endif /* LINUX_LOCKD_BIND_H */
diff --git a/include/linux/lockd/lockd.h b/include/linux/lockd/lockd.h
index dbb87ab..b56d5aa 100644
--- a/include/linux/lockd/lockd.h
+++ b/include/linux/lockd/lockd.h
@@ -12,6 +12,8 @@
 #ifdef __KERNEL__
 
 #include <linux/in.h>
+#include <linux/in6.h>
+#include <net/ipv6.h>
 #include <linux/fs.h>
 #include <linux/kref.h>
 #include <linux/utsname.h>
@@ -38,8 +40,9 @@
  */
 struct nlm_host {
 	struct hlist_node	h_hash;		/* doubly linked list */
-	struct sockaddr_in	h_addr;		/* peer address */
-	struct sockaddr_in	h_saddr;	/* our address (optional) */
+	struct sockaddr_storage	h_addr;		/* peer address */
+	size_t			h_addrlen;
+	struct sockaddr_storage	h_srcaddr;	/* our address (optional) */
 	struct rpc_clnt	*	h_rpcclnt;	/* RPC client to talk to peer */
 	char *			h_name;		/* remote hostname */
 	u32			h_version;	/* interface version */
@@ -61,18 +64,56 @@
 	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 */
+
+	char			h_addrbuf[48],	/* address eyecatchers */
+				h_srcaddrbuf[48];
 };
 
 struct nsm_handle {
 	struct list_head	sm_link;
 	atomic_t		sm_count;
 	char *			sm_name;
-	struct sockaddr_in	sm_addr;
+	struct sockaddr_storage	sm_addr;
+	size_t			sm_addrlen;
 	unsigned int		sm_monitored : 1,
 				sm_sticky : 1;	/* don't unmonitor */
+	char			sm_addrbuf[48];	/* address eyecatcher */
 };
 
 /*
+ * Rigorous type checking on sockaddr type conversions
+ */
+static inline struct sockaddr_in *nlm_addr_in(const struct nlm_host *host)
+{
+	return (struct sockaddr_in *)&host->h_addr;
+}
+
+static inline struct sockaddr *nlm_addr(const struct nlm_host *host)
+{
+	return (struct sockaddr *)&host->h_addr;
+}
+
+static inline struct sockaddr_in *nlm_srcaddr_in(const struct nlm_host *host)
+{
+	return (struct sockaddr_in *)&host->h_srcaddr;
+}
+
+static inline struct sockaddr *nlm_srcaddr(const struct nlm_host *host)
+{
+	return (struct sockaddr *)&host->h_srcaddr;
+}
+
+static inline struct sockaddr_in *nsm_addr_in(const struct nsm_handle *handle)
+{
+	return (struct sockaddr_in *)&handle->sm_addr;
+}
+
+static inline struct sockaddr *nsm_addr(const struct nsm_handle *handle)
+{
+	return (struct sockaddr *)&handle->sm_addr;
+}
+
+/*
  * Map an fl_owner_t into a unique 32-bit "pid"
  */
 struct nlm_lockowner {
@@ -166,7 +207,8 @@
 struct nlm_wait * nlmclnt_prepare_block(struct nlm_host *host, struct file_lock *fl);
 void		  nlmclnt_finish_block(struct nlm_wait *block);
 int		  nlmclnt_block(struct nlm_wait *block, struct nlm_rqst *req, long timeout);
-__be32		  nlmclnt_grant(const struct sockaddr_in *addr, const struct nlm_lock *);
+__be32		  nlmclnt_grant(const struct sockaddr *addr,
+				const struct nlm_lock *lock);
 void		  nlmclnt_recovery(struct nlm_host *);
 int		  nlmclnt_reclaim(struct nlm_host *, struct file_lock *);
 void		  nlmclnt_next_cookie(struct nlm_cookie *);
@@ -174,12 +216,14 @@
 /*
  * Host cache
  */
-struct nlm_host  *nlmclnt_lookup_host(const struct sockaddr_in *sin,
-					int proto, u32 version,
+struct nlm_host  *nlmclnt_lookup_host(const struct sockaddr *sap,
+					const size_t salen,
+					const unsigned short protocol,
+					const u32 version,
+					const char *hostname);
+struct nlm_host  *nlmsvc_lookup_host(const struct svc_rqst *rqstp,
 					const char *hostname,
-					unsigned int hostname_len);
-struct nlm_host  *nlmsvc_lookup_host(struct svc_rqst *, const char *,
-					unsigned int);
+					const size_t hostname_len);
 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 *);
@@ -201,7 +245,7 @@
  */
 __be32		  nlmsvc_lock(struct svc_rqst *, struct nlm_file *,
 			      struct nlm_host *, struct nlm_lock *, int,
-			      struct nlm_cookie *);
+			      struct nlm_cookie *, int);
 __be32		  nlmsvc_unlock(struct nlm_file *, struct nlm_lock *);
 __be32		  nlmsvc_testlock(struct svc_rqst *, struct nlm_file *,
 			struct nlm_host *, struct nlm_lock *,
@@ -233,15 +277,82 @@
 	return file->f_file->f_path.dentry->d_inode;
 }
 
-/*
- * Compare two host addresses (needs modifying for ipv6)
- */
-static inline int nlm_cmp_addr(const struct sockaddr_in *sin1,
-			       const struct sockaddr_in *sin2)
+static inline int __nlm_privileged_request4(const struct sockaddr *sap)
 {
+	const struct sockaddr_in *sin = (struct sockaddr_in *)sap;
+	return (sin->sin_addr.s_addr == htonl(INADDR_LOOPBACK)) &&
+			(ntohs(sin->sin_port) < 1024);
+}
+
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+static inline int __nlm_privileged_request6(const struct sockaddr *sap)
+{
+	const struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sap;
+	return (ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LOOPBACK) &&
+			(ntohs(sin6->sin6_port) < 1024);
+}
+#else	/* defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) */
+static inline int __nlm_privileged_request6(const struct sockaddr *sap)
+{
+	return 0;
+}
+#endif	/* defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) */
+
+/*
+ * Ensure incoming requests are from local privileged callers.
+ *
+ * Return TRUE if sender is local and is connecting via a privileged port;
+ * otherwise return FALSE.
+ */
+static inline int nlm_privileged_requester(const struct svc_rqst *rqstp)
+{
+	const struct sockaddr *sap = svc_addr(rqstp);
+
+	switch (sap->sa_family) {
+	case AF_INET:
+		return __nlm_privileged_request4(sap);
+	case AF_INET6:
+		return __nlm_privileged_request6(sap);
+	default:
+		return 0;
+	}
+}
+
+static inline int __nlm_cmp_addr4(const struct sockaddr *sap1,
+				  const struct sockaddr *sap2)
+{
+	const struct sockaddr_in *sin1 = (const struct sockaddr_in *)sap1;
+	const struct sockaddr_in *sin2 = (const struct sockaddr_in *)sap2;
 	return sin1->sin_addr.s_addr == sin2->sin_addr.s_addr;
 }
 
+static inline int __nlm_cmp_addr6(const struct sockaddr *sap1,
+				  const struct sockaddr *sap2)
+{
+	const struct sockaddr_in6 *sin1 = (const struct sockaddr_in6 *)sap1;
+	const struct sockaddr_in6 *sin2 = (const struct sockaddr_in6 *)sap2;
+	return ipv6_addr_equal(&sin1->sin6_addr, &sin2->sin6_addr);
+}
+
+/*
+ * Compare two host addresses
+ *
+ * Return TRUE if the addresses are the same; otherwise FALSE.
+ */
+static inline int nlm_cmp_addr(const struct sockaddr *sap1,
+			       const struct sockaddr *sap2)
+{
+	if (sap1->sa_family == sap2->sa_family) {
+		switch (sap1->sa_family) {
+		case AF_INET:
+			return __nlm_cmp_addr4(sap1, sap2);
+		case AF_INET6:
+			return __nlm_cmp_addr6(sap1, sap2);
+		}
+	}
+	return 0;
+}
+
 /*
  * Compare two NLM locks.
  * When the second lock is of type F_UNLCK, this acts like a wildcard.
diff --git a/include/linux/lockd/xdr.h b/include/linux/lockd/xdr.h
index df18fa0..d6b3a80 100644
--- a/include/linux/lockd/xdr.h
+++ b/include/linux/lockd/xdr.h
@@ -81,8 +81,6 @@
 	unsigned int	len;
 	u32		state;
 	__be32		addr;
-	__be32		vers;
-	__be32		proto;
 };
 
 /*
diff --git a/include/linux/magic.h b/include/linux/magic.h
index 1fa0c2c..f7f3fdd 100644
--- a/include/linux/magic.h
+++ b/include/linux/magic.h
@@ -6,6 +6,10 @@
 #define AFS_SUPER_MAGIC                0x5346414F
 #define AUTOFS_SUPER_MAGIC	0x0187
 #define CODA_SUPER_MAGIC	0x73757245
+#define DEBUGFS_MAGIC          0x64626720
+#define SYSFS_MAGIC		0x62656572
+#define SECURITYFS_MAGIC	0x73636673
+#define TMPFS_MAGIC		0x01021994
 #define EFS_SUPER_MAGIC		0x414A53
 #define EXT2_SUPER_MAGIC	0xEF53
 #define EXT3_SUPER_MAGIC	0xEF53
diff --git a/include/linux/major.h b/include/linux/major.h
index 53d5faf..8824945 100644
--- a/include/linux/major.h
+++ b/include/linux/major.h
@@ -170,4 +170,6 @@
 
 #define VIOTAPE_MAJOR		230
 
+#define BLOCK_EXT_MAJOR		259
+
 #endif
diff --git a/include/linux/mfd/wm8350/audio.h b/include/linux/mfd/wm8350/audio.h
new file mode 100644
index 0000000..217bb22
--- /dev/null
+++ b/include/linux/mfd/wm8350/audio.h
@@ -0,0 +1,598 @@
+/*
+ * audio.h  --  Audio Driver for Wolfson WM8350 PMIC
+ *
+ * Copyright 2007 Wolfson Microelectronics PLC
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ */
+
+#ifndef __LINUX_MFD_WM8350_AUDIO_H_
+#define __LINUX_MFD_WM8350_AUDIO_H_
+
+#include <linux/platform_device.h>
+
+#define WM8350_CLOCK_CONTROL_1                  0x28
+#define WM8350_CLOCK_CONTROL_2                  0x29
+#define WM8350_FLL_CONTROL_1                    0x2A
+#define WM8350_FLL_CONTROL_2                    0x2B
+#define WM8350_FLL_CONTROL_3                    0x2C
+#define WM8350_FLL_CONTROL_4                    0x2D
+#define WM8350_DAC_CONTROL                      0x30
+#define WM8350_DAC_DIGITAL_VOLUME_L             0x32
+#define WM8350_DAC_DIGITAL_VOLUME_R             0x33
+#define WM8350_DAC_LR_RATE                      0x35
+#define WM8350_DAC_CLOCK_CONTROL                0x36
+#define WM8350_DAC_MUTE                         0x3A
+#define WM8350_DAC_MUTE_VOLUME                  0x3B
+#define WM8350_DAC_SIDE                         0x3C
+#define WM8350_ADC_CONTROL                      0x40
+#define WM8350_ADC_DIGITAL_VOLUME_L             0x42
+#define WM8350_ADC_DIGITAL_VOLUME_R             0x43
+#define WM8350_ADC_DIVIDER                      0x44
+#define WM8350_ADC_LR_RATE                      0x46
+#define WM8350_INPUT_CONTROL                    0x48
+#define WM8350_IN3_INPUT_CONTROL                0x49
+#define WM8350_MIC_BIAS_CONTROL                 0x4A
+#define WM8350_OUTPUT_CONTROL                   0x4C
+#define WM8350_JACK_DETECT                      0x4D
+#define WM8350_ANTI_POP_CONTROL                 0x4E
+#define WM8350_LEFT_INPUT_VOLUME                0x50
+#define WM8350_RIGHT_INPUT_VOLUME               0x51
+#define WM8350_LEFT_MIXER_CONTROL               0x58
+#define WM8350_RIGHT_MIXER_CONTROL              0x59
+#define WM8350_OUT3_MIXER_CONTROL               0x5C
+#define WM8350_OUT4_MIXER_CONTROL               0x5D
+#define WM8350_OUTPUT_LEFT_MIXER_VOLUME         0x60
+#define WM8350_OUTPUT_RIGHT_MIXER_VOLUME        0x61
+#define WM8350_INPUT_MIXER_VOLUME_L             0x62
+#define WM8350_INPUT_MIXER_VOLUME_R             0x63
+#define WM8350_INPUT_MIXER_VOLUME               0x64
+#define WM8350_LOUT1_VOLUME                     0x68
+#define WM8350_ROUT1_VOLUME                     0x69
+#define WM8350_LOUT2_VOLUME                     0x6A
+#define WM8350_ROUT2_VOLUME                     0x6B
+#define WM8350_BEEP_VOLUME                      0x6F
+#define WM8350_AI_FORMATING                     0x70
+#define WM8350_ADC_DAC_COMP                     0x71
+#define WM8350_AI_ADC_CONTROL                   0x72
+#define WM8350_AI_DAC_CONTROL                   0x73
+#define WM8350_AIF_TEST                         0x74
+#define WM8350_JACK_PIN_STATUS                  0xE7
+
+/* Bit values for R08 (0x08) */
+#define WM8350_CODEC_ISEL_1_5                   0	/* x1.5 */
+#define WM8350_CODEC_ISEL_1_0                   1	/* x1.0 */
+#define WM8350_CODEC_ISEL_0_75                  2	/* x0.75 */
+#define WM8350_CODEC_ISEL_0_5                   3	/* x0.5 */
+
+#define WM8350_VMID_OFF                         0
+#define WM8350_VMID_500K                        1
+#define WM8350_VMID_100K                        2
+#define WM8350_VMID_10K                         3
+
+/*
+ * R40 (0x28) - Clock Control 1
+ */
+#define WM8350_TOCLK_RATE                       0x4000
+#define WM8350_MCLK_SEL                         0x0800
+#define WM8350_MCLK_DIV_MASK                    0x0100
+#define WM8350_BCLK_DIV_MASK                    0x00F0
+#define WM8350_OPCLK_DIV_MASK                   0x0007
+
+/*
+ * R41 (0x29) - Clock Control 2
+ */
+#define WM8350_LRC_ADC_SEL                      0x8000
+#define WM8350_MCLK_DIR                         0x0001
+
+/*
+ * R42 (0x2A) - FLL Control 1
+ */
+#define WM8350_FLL_DITHER_WIDTH_MASK            0x3000
+#define WM8350_FLL_DITHER_HP                    0x0800
+#define WM8350_FLL_OUTDIV_MASK                  0x0700
+#define WM8350_FLL_RSP_RATE_MASK                0x00F0
+#define WM8350_FLL_RATE_MASK                    0x0007
+
+/*
+ * R43 (0x2B) - FLL Control 2
+ */
+#define WM8350_FLL_RATIO_MASK                   0xF800
+#define WM8350_FLL_N_MASK                       0x03FF
+
+/*
+ * R44 (0x2C) - FLL Control 3
+ */
+#define WM8350_FLL_K_MASK                       0xFFFF
+
+/*
+ * R45 (0x2D) - FLL Control 4
+ */
+#define WM8350_FLL_FRAC                         0x0020
+#define WM8350_FLL_SLOW_LOCK_REF                0x0010
+#define WM8350_FLL_CLK_SRC_MASK                 0x0003
+
+/*
+ * R48 (0x30) - DAC Control
+ */
+#define WM8350_DAC_MONO                         0x2000
+#define WM8350_AIF_LRCLKRATE                    0x1000
+#define WM8350_DEEMP_MASK                       0x0030
+#define WM8350_DACL_DATINV                      0x0002
+#define WM8350_DACR_DATINV                      0x0001
+
+/*
+ * R50 (0x32) - DAC Digital Volume L
+ */
+#define WM8350_DAC_VU                           0x0100
+#define WM8350_DACL_VOL_MASK                    0x00FF
+
+/*
+ * R51 (0x33) - DAC Digital Volume R
+ */
+#define WM8350_DAC_VU                           0x0100
+#define WM8350_DACR_VOL_MASK                    0x00FF
+
+/*
+ * R53 (0x35) - DAC LR Rate
+ */
+#define WM8350_DACLRC_ENA                       0x0800
+#define WM8350_DACLRC_RATE_MASK                 0x07FF
+
+/*
+ * R54 (0x36) - DAC Clock Control
+ */
+#define WM8350_DACCLK_POL                       0x0010
+#define WM8350_DAC_CLKDIV_MASK                  0x0007
+
+/*
+ * R58 (0x3A) - DAC Mute
+ */
+#define WM8350_DAC_MUTE_ENA                     0x4000
+
+/*
+ * R59 (0x3B) - DAC Mute Volume
+ */
+#define WM8350_DAC_MUTEMODE                     0x4000
+#define WM8350_DAC_MUTERATE                     0x2000
+#define WM8350_DAC_SB_FILT                      0x1000
+
+/*
+ * R60 (0x3C) - DAC Side
+ */
+#define WM8350_ADC_TO_DACL_MASK                 0x3000
+#define WM8350_ADC_TO_DACR_MASK                 0x0C00
+
+/*
+ * R64 (0x40) - ADC Control
+ */
+#define WM8350_ADC_HPF_CUT_MASK                 0x0300
+#define WM8350_ADCL_DATINV                      0x0002
+#define WM8350_ADCR_DATINV                      0x0001
+
+/*
+ * R66 (0x42) - ADC Digital Volume L
+ */
+#define WM8350_ADC_VU                           0x0100
+#define WM8350_ADCL_VOL_MASK                    0x00FF
+
+/*
+ * R67 (0x43) - ADC Digital Volume R
+ */
+#define WM8350_ADC_VU                           0x0100
+#define WM8350_ADCR_VOL_MASK                    0x00FF
+
+/*
+ * R68 (0x44) - ADC Divider
+ */
+#define WM8350_ADCL_DAC_SVOL_MASK               0x0F00
+#define WM8350_ADCR_DAC_SVOL_MASK               0x00F0
+#define WM8350_ADCCLK_POL                       0x0008
+#define WM8350_ADC_CLKDIV_MASK                  0x0007
+
+/*
+ * R70 (0x46) - ADC LR Rate
+ */
+#define WM8350_ADCLRC_ENA                       0x0800
+#define WM8350_ADCLRC_RATE_MASK                 0x07FF
+
+/*
+ * R72 (0x48) - Input Control
+ */
+#define WM8350_IN2R_ENA                         0x0400
+#define WM8350_IN1RN_ENA                        0x0200
+#define WM8350_IN1RP_ENA                        0x0100
+#define WM8350_IN2L_ENA                         0x0004
+#define WM8350_IN1LN_ENA                        0x0002
+#define WM8350_IN1LP_ENA                        0x0001
+
+/*
+ * R73 (0x49) - IN3 Input Control
+ */
+#define WM8350_IN3R_SHORT                       0x4000
+#define WM8350_IN3L_SHORT                       0x0040
+
+/*
+ * R74 (0x4A) - Mic Bias Control
+ */
+#define WM8350_MICBSEL                          0x4000
+#define WM8350_MCDTHR_MASK                      0x001C
+#define WM8350_MCDSCTHR_MASK                    0x0003
+
+/*
+ * R76 (0x4C) - Output Control
+ */
+#define WM8350_OUT4_VROI                        0x0800
+#define WM8350_OUT3_VROI                        0x0400
+#define WM8350_OUT2_VROI                        0x0200
+#define WM8350_OUT1_VROI                        0x0100
+#define WM8350_OUT2_FB                          0x0004
+#define WM8350_OUT1_FB                          0x0001
+
+/*
+ * R77 (0x4D) - Jack Detect
+ */
+#define WM8350_JDL_ENA                          0x8000
+#define WM8350_JDR_ENA                          0x4000
+
+/*
+ * R78 (0x4E) - Anti Pop Control
+ */
+#define WM8350_ANTI_POP_MASK                    0x0300
+#define WM8350_DIS_OP_LN4_MASK                  0x00C0
+#define WM8350_DIS_OP_LN3_MASK                  0x0030
+#define WM8350_DIS_OP_OUT2_MASK                 0x000C
+#define WM8350_DIS_OP_OUT1_MASK                 0x0003
+
+/*
+ * R80 (0x50) - Left Input Volume
+ */
+#define WM8350_INL_MUTE                         0x4000
+#define WM8350_INL_ZC                           0x2000
+#define WM8350_IN_VU                            0x0100
+#define WM8350_INL_VOL_MASK                     0x00FC
+
+/*
+ * R81 (0x51) - Right Input Volume
+ */
+#define WM8350_INR_MUTE                         0x4000
+#define WM8350_INR_ZC                           0x2000
+#define WM8350_IN_VU                            0x0100
+#define WM8350_INR_VOL_MASK                     0x00FC
+
+/*
+ * R88 (0x58) - Left Mixer Control
+ */
+#define WM8350_DACR_TO_MIXOUTL                  0x1000
+#define WM8350_DACL_TO_MIXOUTL                  0x0800
+#define WM8350_IN3L_TO_MIXOUTL                  0x0004
+#define WM8350_INR_TO_MIXOUTL                   0x0002
+#define WM8350_INL_TO_MIXOUTL                   0x0001
+
+/*
+ * R89 (0x59) - Right Mixer Control
+ */
+#define WM8350_DACR_TO_MIXOUTR                  0x1000
+#define WM8350_DACL_TO_MIXOUTR                  0x0800
+#define WM8350_IN3R_TO_MIXOUTR                  0x0008
+#define WM8350_INR_TO_MIXOUTR                   0x0002
+#define WM8350_INL_TO_MIXOUTR                   0x0001
+
+/*
+ * R92 (0x5C) - OUT3 Mixer Control
+ */
+#define WM8350_DACL_TO_OUT3                     0x0800
+#define WM8350_MIXINL_TO_OUT3                   0x0100
+#define WM8350_OUT4_TO_OUT3                     0x0008
+#define WM8350_MIXOUTL_TO_OUT3                  0x0001
+
+/*
+ * R93 (0x5D) - OUT4 Mixer Control
+ */
+#define WM8350_DACR_TO_OUT4                     0x1000
+#define WM8350_DACL_TO_OUT4                     0x0800
+#define WM8350_OUT4_ATTN                        0x0400
+#define WM8350_MIXINR_TO_OUT4                   0x0200
+#define WM8350_OUT3_TO_OUT4                     0x0004
+#define WM8350_MIXOUTR_TO_OUT4                  0x0002
+#define WM8350_MIXOUTL_TO_OUT4                  0x0001
+
+/*
+ * R96 (0x60) - Output Left Mixer Volume
+ */
+#define WM8350_IN3L_MIXOUTL_VOL_MASK            0x0E00
+#define WM8350_IN3L_MIXOUTL_VOL_SHIFT                9
+#define WM8350_INR_MIXOUTL_VOL_MASK             0x00E0
+#define WM8350_INR_MIXOUTL_VOL_SHIFT                 5
+#define WM8350_INL_MIXOUTL_VOL_MASK             0x000E
+#define WM8350_INL_MIXOUTL_VOL_SHIFT                 1
+
+/* Bit values for R96 (0x60) */
+#define WM8350_IN3L_MIXOUTL_VOL_OFF                  0
+#define WM8350_IN3L_MIXOUTL_VOL_M12DB                1
+#define WM8350_IN3L_MIXOUTL_VOL_M9DB                 2
+#define WM8350_IN3L_MIXOUTL_VOL_M6DB                 3
+#define WM8350_IN3L_MIXOUTL_VOL_M3DB                 4
+#define WM8350_IN3L_MIXOUTL_VOL_0DB                  5
+#define WM8350_IN3L_MIXOUTL_VOL_3DB                  6
+#define WM8350_IN3L_MIXOUTL_VOL_6DB                  7
+
+#define WM8350_INR_MIXOUTL_VOL_OFF                   0
+#define WM8350_INR_MIXOUTL_VOL_M12DB                 1
+#define WM8350_INR_MIXOUTL_VOL_M9DB                  2
+#define WM8350_INR_MIXOUTL_VOL_M6DB                  3
+#define WM8350_INR_MIXOUTL_VOL_M3DB                  4
+#define WM8350_INR_MIXOUTL_VOL_0DB                   5
+#define WM8350_INR_MIXOUTL_VOL_3DB                   6
+#define WM8350_INR_MIXOUTL_VOL_6DB                   7
+
+#define WM8350_INL_MIXOUTL_VOL_OFF                   0
+#define WM8350_INL_MIXOUTL_VOL_M12DB                 1
+#define WM8350_INL_MIXOUTL_VOL_M9DB                  2
+#define WM8350_INL_MIXOUTL_VOL_M6DB                  3
+#define WM8350_INL_MIXOUTL_VOL_M3DB                  4
+#define WM8350_INL_MIXOUTL_VOL_0DB                   5
+#define WM8350_INL_MIXOUTL_VOL_3DB                   6
+#define WM8350_INL_MIXOUTL_VOL_6DB                   7
+
+/*
+ * R97 (0x61) - Output Right Mixer Volume
+ */
+#define WM8350_IN3R_MIXOUTR_VOL_MASK            0xE000
+#define WM8350_IN3R_MIXOUTR_VOL_SHIFT               13
+#define WM8350_INR_MIXOUTR_VOL_MASK             0x00E0
+#define WM8350_INR_MIXOUTR_VOL_SHIFT                 5
+#define WM8350_INL_MIXOUTR_VOL_MASK             0x000E
+#define WM8350_INL_MIXOUTR_VOL_SHIFT                 1
+
+/* Bit values for R96 (0x60) */
+#define WM8350_IN3R_MIXOUTR_VOL_OFF                  0
+#define WM8350_IN3R_MIXOUTR_VOL_M12DB                1
+#define WM8350_IN3R_MIXOUTR_VOL_M9DB                 2
+#define WM8350_IN3R_MIXOUTR_VOL_M6DB                 3
+#define WM8350_IN3R_MIXOUTR_VOL_M3DB                 4
+#define WM8350_IN3R_MIXOUTR_VOL_0DB                  5
+#define WM8350_IN3R_MIXOUTR_VOL_3DB                  6
+#define WM8350_IN3R_MIXOUTR_VOL_6DB                  7
+
+#define WM8350_INR_MIXOUTR_VOL_OFF                   0
+#define WM8350_INR_MIXOUTR_VOL_M12DB                 1
+#define WM8350_INR_MIXOUTR_VOL_M9DB                  2
+#define WM8350_INR_MIXOUTR_VOL_M6DB                  3
+#define WM8350_INR_MIXOUTR_VOL_M3DB                  4
+#define WM8350_INR_MIXOUTR_VOL_0DB                   5
+#define WM8350_INR_MIXOUTR_VOL_3DB                   6
+#define WM8350_INR_MIXOUTR_VOL_6DB                   7
+
+#define WM8350_INL_MIXOUTR_VOL_OFF                   0
+#define WM8350_INL_MIXOUTR_VOL_M12DB                 1
+#define WM8350_INL_MIXOUTR_VOL_M9DB                  2
+#define WM8350_INL_MIXOUTR_VOL_M6DB                  3
+#define WM8350_INL_MIXOUTR_VOL_M3DB                  4
+#define WM8350_INL_MIXOUTR_VOL_0DB                   5
+#define WM8350_INL_MIXOUTR_VOL_3DB                   6
+#define WM8350_INL_MIXOUTR_VOL_6DB                   7
+
+/*
+ * R98 (0x62) - Input Mixer Volume L
+ */
+#define WM8350_IN3L_MIXINL_VOL_MASK             0x0E00
+#define WM8350_IN2L_MIXINL_VOL_MASK             0x000E
+#define WM8350_INL_MIXINL_VOL                   0x0001
+
+/*
+ * R99 (0x63) - Input Mixer Volume R
+ */
+#define WM8350_IN3R_MIXINR_VOL_MASK             0xE000
+#define WM8350_IN2R_MIXINR_VOL_MASK             0x00E0
+#define WM8350_INR_MIXINR_VOL                   0x0001
+
+/*
+ * R100 (0x64) - Input Mixer Volume
+ */
+#define WM8350_OUT4_MIXIN_DST                   0x8000
+#define WM8350_OUT4_MIXIN_VOL_MASK              0x000E
+
+/*
+ * R104 (0x68) - LOUT1 Volume
+ */
+#define WM8350_OUT1L_MUTE                       0x4000
+#define WM8350_OUT1L_ZC                         0x2000
+#define WM8350_OUT1_VU                          0x0100
+#define WM8350_OUT1L_VOL_MASK                   0x00FC
+#define WM8350_OUT1L_VOL_SHIFT                       2
+
+/*
+ * R105 (0x69) - ROUT1 Volume
+ */
+#define WM8350_OUT1R_MUTE                       0x4000
+#define WM8350_OUT1R_ZC                         0x2000
+#define WM8350_OUT1_VU                          0x0100
+#define WM8350_OUT1R_VOL_MASK                   0x00FC
+#define WM8350_OUT1R_VOL_SHIFT                       2
+
+/*
+ * R106 (0x6A) - LOUT2 Volume
+ */
+#define WM8350_OUT2L_MUTE                       0x4000
+#define WM8350_OUT2L_ZC                         0x2000
+#define WM8350_OUT2_VU                          0x0100
+#define WM8350_OUT2L_VOL_MASK                   0x00FC
+
+/*
+ * R107 (0x6B) - ROUT2 Volume
+ */
+#define WM8350_OUT2R_MUTE                       0x4000
+#define WM8350_OUT2R_ZC                         0x2000
+#define WM8350_OUT2R_INV                        0x0400
+#define WM8350_OUT2R_INV_MUTE                   0x0200
+#define WM8350_OUT2_VU                          0x0100
+#define WM8350_OUT2R_VOL_MASK                   0x00FC
+
+/*
+ * R111 (0x6F) - BEEP Volume
+ */
+#define WM8350_IN3R_OUT2R_VOL_MASK              0x00E0
+
+/*
+ * R112 (0x70) - AI Formating
+ */
+#define WM8350_AIF_BCLK_INV                     0x8000
+#define WM8350_AIF_TRI                          0x2000
+#define WM8350_AIF_LRCLK_INV                    0x1000
+#define WM8350_AIF_WL_MASK                      0x0C00
+#define WM8350_AIF_FMT_MASK                     0x0300
+
+/*
+ * R113 (0x71) - ADC DAC COMP
+ */
+#define WM8350_DAC_COMP                         0x0080
+#define WM8350_DAC_COMPMODE                     0x0040
+#define WM8350_ADC_COMP                         0x0020
+#define WM8350_ADC_COMPMODE                     0x0010
+#define WM8350_LOOPBACK                         0x0001
+
+/*
+ * R114 (0x72) - AI ADC Control
+ */
+#define WM8350_AIFADC_PD                        0x0080
+#define WM8350_AIFADCL_SRC                      0x0040
+#define WM8350_AIFADCR_SRC                      0x0020
+#define WM8350_AIFADC_TDM_CHAN                  0x0010
+#define WM8350_AIFADC_TDM                       0x0008
+
+/*
+ * R115 (0x73) - AI DAC Control
+ */
+#define WM8350_BCLK_MSTR                        0x4000
+#define WM8350_AIFDAC_PD                        0x0080
+#define WM8350_DACL_SRC                         0x0040
+#define WM8350_DACR_SRC                         0x0020
+#define WM8350_AIFDAC_TDM_CHAN                  0x0010
+#define WM8350_AIFDAC_TDM                       0x0008
+#define WM8350_DAC_BOOST_MASK                   0x0003
+
+/*
+ * R116 (0x74) - AIF Test
+ */
+#define WM8350_CODEC_BYP                        0x4000
+#define WM8350_AIFADC_WR_TST                    0x2000
+#define WM8350_AIFADC_RD_TST                    0x1000
+#define WM8350_AIFDAC_WR_TST                    0x0800
+#define WM8350_AIFDAC_RD_TST                    0x0400
+#define WM8350_AIFADC_ASYN                      0x0020
+#define WM8350_AIFDAC_ASYN                      0x0010
+
+/*
+ * R231 (0xE7) - Jack Status
+ */
+#define WM8350_JACK_R_LVL                       0x0400
+
+/*
+ * WM8350 Platform setup
+ */
+#define WM8350_S_CURVE_NONE			0x0
+#define WM8350_S_CURVE_FAST			0x1
+#define WM8350_S_CURVE_MEDIUM			0x2
+#define WM8350_S_CURVE_SLOW			0x3
+
+#define WM8350_DISCHARGE_OFF			0x0
+#define WM8350_DISCHARGE_FAST			0x1
+#define WM8350_DISCHARGE_MEDIUM			0x2
+#define WM8350_DISCHARGE_SLOW			0x3
+
+#define WM8350_TIE_OFF_500R			0x0
+#define WM8350_TIE_OFF_30K			0x1
+
+/*
+ * Clock sources & directions
+ */
+#define WM8350_SYSCLK				0
+
+#define WM8350_MCLK_SEL_PLL_MCLK		0
+#define WM8350_MCLK_SEL_PLL_DAC			1
+#define WM8350_MCLK_SEL_PLL_ADC			2
+#define WM8350_MCLK_SEL_PLL_32K			3
+#define WM8350_MCLK_SEL_MCLK			5
+
+#define WM8350_MCLK_DIR_OUT			0
+#define WM8350_MCLK_DIR_IN			1
+
+/* clock divider id's */
+#define WM8350_ADC_CLKDIV			0
+#define WM8350_DAC_CLKDIV			1
+#define WM8350_BCLK_CLKDIV			2
+#define WM8350_OPCLK_CLKDIV			3
+#define WM8350_TO_CLKDIV			4
+#define WM8350_SYS_CLKDIV			5
+#define WM8350_DACLR_CLKDIV			6
+#define WM8350_ADCLR_CLKDIV			7
+
+/* ADC clock dividers */
+#define WM8350_ADCDIV_1				0x0
+#define WM8350_ADCDIV_1_5			0x1
+#define WM8350_ADCDIV_2				0x2
+#define WM8350_ADCDIV_3				0x3
+#define WM8350_ADCDIV_4				0x4
+#define WM8350_ADCDIV_5_5			0x5
+#define WM8350_ADCDIV_6				0x6
+
+/* ADC clock dividers */
+#define WM8350_DACDIV_1				0x0
+#define WM8350_DACDIV_1_5			0x1
+#define WM8350_DACDIV_2				0x2
+#define WM8350_DACDIV_3				0x3
+#define WM8350_DACDIV_4				0x4
+#define WM8350_DACDIV_5_5			0x5
+#define WM8350_DACDIV_6				0x6
+
+/* BCLK clock dividers */
+#define WM8350_BCLK_DIV_1			(0x0 << 4)
+#define WM8350_BCLK_DIV_1_5			(0x1 << 4)
+#define WM8350_BCLK_DIV_2			(0x2 << 4)
+#define WM8350_BCLK_DIV_3			(0x3 << 4)
+#define WM8350_BCLK_DIV_4			(0x4 << 4)
+#define WM8350_BCLK_DIV_5_5			(0x5 << 4)
+#define WM8350_BCLK_DIV_6			(0x6 << 4)
+#define WM8350_BCLK_DIV_8			(0x7 << 4)
+#define WM8350_BCLK_DIV_11			(0x8 << 4)
+#define WM8350_BCLK_DIV_12			(0x9 << 4)
+#define WM8350_BCLK_DIV_16			(0xa << 4)
+#define WM8350_BCLK_DIV_22			(0xb << 4)
+#define WM8350_BCLK_DIV_24			(0xc << 4)
+#define WM8350_BCLK_DIV_32			(0xd << 4)
+#define WM8350_BCLK_DIV_44			(0xe << 4)
+#define WM8350_BCLK_DIV_48			(0xf << 4)
+
+/* Sys (MCLK) clock dividers */
+#define WM8350_MCLK_DIV_1			(0x0 << 8)
+#define WM8350_MCLK_DIV_2			(0x1 << 8)
+
+/* OP clock dividers */
+#define WM8350_OPCLK_DIV_1			0x0
+#define WM8350_OPCLK_DIV_2			0x1
+#define WM8350_OPCLK_DIV_3			0x2
+#define WM8350_OPCLK_DIV_4			0x3
+#define WM8350_OPCLK_DIV_5_5			0x4
+#define WM8350_OPCLK_DIV_6			0x5
+
+/* DAI ID */
+#define WM8350_HIFI_DAI				0
+
+/*
+ * Audio interrupts.
+ */
+#define WM8350_IRQ_CODEC_JCK_DET_L		39
+#define WM8350_IRQ_CODEC_JCK_DET_R		40
+#define WM8350_IRQ_CODEC_MICSCD			41
+#define WM8350_IRQ_CODEC_MICD			42
+
+struct wm8350_codec {
+	struct platform_device *pdev;
+};
+
+#endif
diff --git a/include/linux/mfd/wm8350/comparator.h b/include/linux/mfd/wm8350/comparator.h
new file mode 100644
index 0000000..0537886
--- /dev/null
+++ b/include/linux/mfd/wm8350/comparator.h
@@ -0,0 +1,167 @@
+/*
+ * comparator.h  --  Comparator Aux ADC for Wolfson WM8350 PMIC
+ *
+ * Copyright 2007 Wolfson Microelectronics PLC
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ */
+
+#ifndef __LINUX_MFD_WM8350_COMPARATOR_H_
+#define __LINUX_MFD_WM8350_COMPARATOR_H_
+
+/*
+ * Registers
+ */
+
+#define WM8350_DIGITISER_CONTROL_1              0x90
+#define WM8350_DIGITISER_CONTROL_2              0x91
+#define WM8350_AUX1_READBACK                    0x98
+#define WM8350_AUX2_READBACK                    0x99
+#define WM8350_AUX3_READBACK                    0x9A
+#define WM8350_AUX4_READBACK                    0x9B
+#define WM8350_CHIP_TEMP_READBACK               0x9F
+#define WM8350_GENERIC_COMPARATOR_CONTROL       0xA3
+#define WM8350_GENERIC_COMPARATOR_1             0xA4
+#define WM8350_GENERIC_COMPARATOR_2             0xA5
+#define WM8350_GENERIC_COMPARATOR_3             0xA6
+#define WM8350_GENERIC_COMPARATOR_4             0xA7
+
+/*
+ * R144 (0x90) - Digitiser Control (1)
+ */
+#define WM8350_AUXADC_CTC                       0x4000
+#define WM8350_AUXADC_POLL                      0x2000
+#define WM8350_AUXADC_HIB_MODE                  0x1000
+#define WM8350_AUXADC_SEL8                      0x0080
+#define WM8350_AUXADC_SEL7                      0x0040
+#define WM8350_AUXADC_SEL6                      0x0020
+#define WM8350_AUXADC_SEL5                      0x0010
+#define WM8350_AUXADC_SEL4                      0x0008
+#define WM8350_AUXADC_SEL3                      0x0004
+#define WM8350_AUXADC_SEL2                      0x0002
+#define WM8350_AUXADC_SEL1                      0x0001
+
+/*
+ * R145 (0x91) - Digitiser Control (2)
+ */
+#define WM8350_AUXADC_MASKMODE_MASK             0x3000
+#define WM8350_AUXADC_CRATE_MASK                0x0700
+#define WM8350_AUXADC_CAL                       0x0004
+#define WM8350_AUX_RBMODE                       0x0002
+#define WM8350_AUXADC_WAIT                      0x0001
+
+/*
+ * R152 (0x98) - AUX1 Readback
+ */
+#define WM8350_AUXADC_SCALE1_MASK               0x6000
+#define WM8350_AUXADC_REF1                      0x1000
+#define WM8350_AUXADC_DATA1_MASK                0x0FFF
+
+/*
+ * R153 (0x99) - AUX2 Readback
+ */
+#define WM8350_AUXADC_SCALE2_MASK               0x6000
+#define WM8350_AUXADC_REF2                      0x1000
+#define WM8350_AUXADC_DATA2_MASK                0x0FFF
+
+/*
+ * R154 (0x9A) - AUX3 Readback
+ */
+#define WM8350_AUXADC_SCALE3_MASK               0x6000
+#define WM8350_AUXADC_REF3                      0x1000
+#define WM8350_AUXADC_DATA3_MASK                0x0FFF
+
+/*
+ * R155 (0x9B) - AUX4 Readback
+ */
+#define WM8350_AUXADC_SCALE4_MASK               0x6000
+#define WM8350_AUXADC_REF4                      0x1000
+#define WM8350_AUXADC_DATA4_MASK                0x0FFF
+
+/*
+ * R156 (0x9C) - USB Voltage Readback
+ */
+#define WM8350_AUXADC_DATA_USB_MASK             0x0FFF
+
+/*
+ * R157 (0x9D) - LINE Voltage Readback
+ */
+#define WM8350_AUXADC_DATA_LINE_MASK            0x0FFF
+
+/*
+ * R158 (0x9E) - BATT Voltage Readback
+ */
+#define WM8350_AUXADC_DATA_BATT_MASK            0x0FFF
+
+/*
+ * R159 (0x9F) - Chip Temp Readback
+ */
+#define WM8350_AUXADC_DATA_CHIPTEMP_MASK        0x0FFF
+
+/*
+ * R163 (0xA3) - Generic Comparator Control
+ */
+#define WM8350_DCMP4_ENA                        0x0008
+#define WM8350_DCMP3_ENA                        0x0004
+#define WM8350_DCMP2_ENA                        0x0002
+#define WM8350_DCMP1_ENA                        0x0001
+
+/*
+ * R164 (0xA4) - Generic comparator 1
+ */
+#define WM8350_DCMP1_SRCSEL_MASK                0xE000
+#define WM8350_DCMP1_GT                         0x1000
+#define WM8350_DCMP1_THR_MASK                   0x0FFF
+
+/*
+ * R165 (0xA5) - Generic comparator 2
+ */
+#define WM8350_DCMP2_SRCSEL_MASK                0xE000
+#define WM8350_DCMP2_GT                         0x1000
+#define WM8350_DCMP2_THR_MASK                   0x0FFF
+
+/*
+ * R166 (0xA6) - Generic comparator 3
+ */
+#define WM8350_DCMP3_SRCSEL_MASK                0xE000
+#define WM8350_DCMP3_GT                         0x1000
+#define WM8350_DCMP3_THR_MASK                   0x0FFF
+
+/*
+ * R167 (0xA7) - Generic comparator 4
+ */
+#define WM8350_DCMP4_SRCSEL_MASK                0xE000
+#define WM8350_DCMP4_GT                         0x1000
+#define WM8350_DCMP4_THR_MASK                   0x0FFF
+
+/*
+ * Interrupts.
+ */
+#define WM8350_IRQ_AUXADC_DATARDY		16
+#define WM8350_IRQ_AUXADC_DCOMP4		17
+#define WM8350_IRQ_AUXADC_DCOMP3		18
+#define WM8350_IRQ_AUXADC_DCOMP2		19
+#define WM8350_IRQ_AUXADC_DCOMP1		20
+#define WM8350_IRQ_SYS_HYST_COMP_FAIL		21
+#define WM8350_IRQ_SYS_CHIP_GT115		22
+#define WM8350_IRQ_SYS_CHIP_GT140		23
+
+/*
+ * USB/2, LINE & BATT = ((VRTC * 2) / 4095)) * 10e6 uV
+ * Where VRTC = 2.7 V
+ */
+#define WM8350_AUX_COEFF			1319
+
+#define WM8350_AUXADC_AUX1			0
+#define WM8350_AUXADC_AUX2			1
+#define WM8350_AUXADC_AUX3			2
+#define WM8350_AUXADC_AUX4			3
+#define WM8350_AUXADC_USB			4
+#define WM8350_AUXADC_LINE			5
+#define WM8350_AUXADC_BATT			6
+#define WM8350_AUXADC_TEMP			7
+
+#endif
diff --git a/include/linux/mfd/wm8350/core.h b/include/linux/mfd/wm8350/core.h
new file mode 100644
index 0000000..6ebf97f
--- /dev/null
+++ b/include/linux/mfd/wm8350/core.h
@@ -0,0 +1,631 @@
+/*
+ * core.h  --  Core Driver for Wolfson WM8350 PMIC
+ *
+ * Copyright 2007 Wolfson Microelectronics PLC
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ */
+
+#ifndef __LINUX_MFD_WM8350_CORE_H_
+#define __LINUX_MFD_WM8350_CORE_H_
+
+#include <linux/kernel.h>
+#include <linux/mutex.h>
+#include <linux/workqueue.h>
+
+#include <linux/mfd/wm8350/audio.h>
+#include <linux/mfd/wm8350/gpio.h>
+#include <linux/mfd/wm8350/pmic.h>
+#include <linux/mfd/wm8350/rtc.h>
+#include <linux/mfd/wm8350/supply.h>
+#include <linux/mfd/wm8350/wdt.h>
+
+/*
+ * Register values.
+ */
+#define WM8350_RESET_ID                         0x00
+#define WM8350_ID                               0x01
+#define WM8350_SYSTEM_CONTROL_1                 0x03
+#define WM8350_SYSTEM_CONTROL_2                 0x04
+#define WM8350_SYSTEM_HIBERNATE                 0x05
+#define WM8350_INTERFACE_CONTROL                0x06
+#define WM8350_POWER_MGMT_1                     0x08
+#define WM8350_POWER_MGMT_2                     0x09
+#define WM8350_POWER_MGMT_3                     0x0A
+#define WM8350_POWER_MGMT_4                     0x0B
+#define WM8350_POWER_MGMT_5                     0x0C
+#define WM8350_POWER_MGMT_6                     0x0D
+#define WM8350_POWER_MGMT_7                     0x0E
+
+#define WM8350_SYSTEM_INTERRUPTS                0x18
+#define WM8350_INT_STATUS_1                     0x19
+#define WM8350_INT_STATUS_2                     0x1A
+#define WM8350_POWER_UP_INT_STATUS              0x1B
+#define WM8350_UNDER_VOLTAGE_INT_STATUS         0x1C
+#define WM8350_OVER_CURRENT_INT_STATUS          0x1D
+#define WM8350_GPIO_INT_STATUS                  0x1E
+#define WM8350_COMPARATOR_INT_STATUS            0x1F
+#define WM8350_SYSTEM_INTERRUPTS_MASK           0x20
+#define WM8350_INT_STATUS_1_MASK                0x21
+#define WM8350_INT_STATUS_2_MASK                0x22
+#define WM8350_POWER_UP_INT_STATUS_MASK         0x23
+#define WM8350_UNDER_VOLTAGE_INT_STATUS_MASK    0x24
+#define WM8350_OVER_CURRENT_INT_STATUS_MASK     0x25
+#define WM8350_GPIO_INT_STATUS_MASK             0x26
+#define WM8350_COMPARATOR_INT_STATUS_MASK       0x27
+
+#define WM8350_MAX_REGISTER                     0xFF
+
+/*
+ * Field Definitions.
+ */
+
+/*
+ * R0 (0x00) - Reset/ID
+ */
+#define WM8350_SW_RESET_CHIP_ID_MASK            0xFFFF
+
+/*
+ * R1 (0x01) - ID
+ */
+#define WM8350_CHIP_REV_MASK                    0x7000
+#define WM8350_CONF_STS_MASK                    0x0C00
+#define WM8350_CUST_ID_MASK                     0x00FF
+
+/*
+ * R3 (0x03) - System Control 1
+ */
+#define WM8350_CHIP_ON                          0x8000
+#define WM8350_POWERCYCLE                       0x2000
+#define WM8350_VCC_FAULT_OV                     0x1000
+#define WM8350_REG_RSTB_TIME_MASK               0x0C00
+#define WM8350_BG_SLEEP                         0x0200
+#define WM8350_MEM_VALID                        0x0020
+#define WM8350_CHIP_SET_UP                      0x0010
+#define WM8350_ON_DEB_T                         0x0008
+#define WM8350_ON_POL                           0x0002
+#define WM8350_IRQ_POL                          0x0001
+
+/*
+ * R4 (0x04) - System Control 2
+ */
+#define WM8350_USB_SUSPEND_8MA                  0x8000
+#define WM8350_USB_SUSPEND                      0x4000
+#define WM8350_USB_MSTR                         0x2000
+#define WM8350_USB_MSTR_SRC                     0x1000
+#define WM8350_USB_500MA                        0x0800
+#define WM8350_USB_NOLIM                        0x0400
+
+/*
+ * R5 (0x05) - System Hibernate
+ */
+#define WM8350_HIBERNATE                        0x8000
+#define WM8350_WDOG_HIB_MODE                    0x0080
+#define WM8350_REG_HIB_STARTUP_SEQ              0x0040
+#define WM8350_REG_RESET_HIB_MODE               0x0020
+#define WM8350_RST_HIB_MODE                     0x0010
+#define WM8350_IRQ_HIB_MODE                     0x0008
+#define WM8350_MEMRST_HIB_MODE                  0x0004
+#define WM8350_PCCOMP_HIB_MODE                  0x0002
+#define WM8350_TEMPMON_HIB_MODE                 0x0001
+
+/*
+ * R6 (0x06) - Interface Control
+ */
+#define WM8350_USE_DEV_PINS                     0x8000
+#define WM8350_USE_DEV_PINS_MASK                0x8000
+#define WM8350_USE_DEV_PINS_SHIFT                   15
+#define WM8350_DEV_ADDR_MASK                    0x6000
+#define WM8350_DEV_ADDR_SHIFT                       13
+#define WM8350_CONFIG_DONE                      0x1000
+#define WM8350_CONFIG_DONE_MASK                 0x1000
+#define WM8350_CONFIG_DONE_SHIFT                    12
+#define WM8350_RECONFIG_AT_ON                   0x0800
+#define WM8350_RECONFIG_AT_ON_MASK              0x0800
+#define WM8350_RECONFIG_AT_ON_SHIFT                 11
+#define WM8350_AUTOINC                          0x0200
+#define WM8350_AUTOINC_MASK                     0x0200
+#define WM8350_AUTOINC_SHIFT                         9
+#define WM8350_ARA                              0x0100
+#define WM8350_ARA_MASK                         0x0100
+#define WM8350_ARA_SHIFT                             8
+#define WM8350_SPI_CFG                          0x0008
+#define WM8350_SPI_CFG_MASK                     0x0008
+#define WM8350_SPI_CFG_SHIFT                         3
+#define WM8350_SPI_4WIRE                        0x0004
+#define WM8350_SPI_4WIRE_MASK                   0x0004
+#define WM8350_SPI_4WIRE_SHIFT                       2
+#define WM8350_SPI_3WIRE                        0x0002
+#define WM8350_SPI_3WIRE_MASK                   0x0002
+#define WM8350_SPI_3WIRE_SHIFT                       1
+
+/* Bit values for R06 (0x06) */
+#define WM8350_USE_DEV_PINS_PRIMARY                  0
+#define WM8350_USE_DEV_PINS_DEV                      1
+
+#define WM8350_DEV_ADDR_34                           0
+#define WM8350_DEV_ADDR_36                           1
+#define WM8350_DEV_ADDR_3C                           2
+#define WM8350_DEV_ADDR_3E                           3
+
+#define WM8350_CONFIG_DONE_OFF                       0
+#define WM8350_CONFIG_DONE_DONE                      1
+
+#define WM8350_RECONFIG_AT_ON_OFF                    0
+#define WM8350_RECONFIG_AT_ON_ON                     1
+
+#define WM8350_AUTOINC_OFF                           0
+#define WM8350_AUTOINC_ON                            1
+
+#define WM8350_ARA_OFF                               0
+#define WM8350_ARA_ON                                1
+
+#define WM8350_SPI_CFG_CMOS                          0
+#define WM8350_SPI_CFG_OD                            1
+
+#define WM8350_SPI_4WIRE_3WIRE                       0
+#define WM8350_SPI_4WIRE_4WIRE                       1
+
+#define WM8350_SPI_3WIRE_I2C                         0
+#define WM8350_SPI_3WIRE_SPI                         1
+
+/*
+ * R8 (0x08) - Power mgmt (1)
+ */
+#define WM8350_CODEC_ISEL_MASK                  0xC000
+#define WM8350_VBUFEN                           0x2000
+#define WM8350_OUTPUT_DRAIN_EN                  0x0400
+#define WM8350_MIC_DET_ENA                      0x0100
+#define WM8350_BIASEN                           0x0020
+#define WM8350_MICBEN                           0x0010
+#define WM8350_VMIDEN                           0x0004
+#define WM8350_VMID_MASK                        0x0003
+#define WM8350_VMID_SHIFT                            0
+
+/*
+ * R9 (0x09) - Power mgmt (2)
+ */
+#define WM8350_IN3R_ENA                         0x0800
+#define WM8350_IN3L_ENA                         0x0400
+#define WM8350_INR_ENA                          0x0200
+#define WM8350_INL_ENA                          0x0100
+#define WM8350_MIXINR_ENA                       0x0080
+#define WM8350_MIXINL_ENA                       0x0040
+#define WM8350_OUT4_ENA                         0x0020
+#define WM8350_OUT3_ENA                         0x0010
+#define WM8350_MIXOUTR_ENA                      0x0002
+#define WM8350_MIXOUTL_ENA                      0x0001
+
+/*
+ * R10 (0x0A) - Power mgmt (3)
+ */
+#define WM8350_IN3R_TO_OUT2R                    0x0080
+#define WM8350_OUT2R_ENA                        0x0008
+#define WM8350_OUT2L_ENA                        0x0004
+#define WM8350_OUT1R_ENA                        0x0002
+#define WM8350_OUT1L_ENA                        0x0001
+
+/*
+ * R11 (0x0B) - Power mgmt (4)
+ */
+#define WM8350_SYSCLK_ENA                       0x4000
+#define WM8350_ADC_HPF_ENA                      0x2000
+#define WM8350_FLL_ENA                          0x0800
+#define WM8350_FLL_OSC_ENA                      0x0400
+#define WM8350_TOCLK_ENA                        0x0100
+#define WM8350_DACR_ENA                         0x0020
+#define WM8350_DACL_ENA                         0x0010
+#define WM8350_ADCR_ENA                         0x0008
+#define WM8350_ADCL_ENA                         0x0004
+
+/*
+ * R12 (0x0C) - Power mgmt (5)
+ */
+#define WM8350_CODEC_ENA                        0x1000
+#define WM8350_RTC_TICK_ENA                     0x0800
+#define WM8350_OSC32K_ENA                       0x0400
+#define WM8350_CHG_ENA                          0x0200
+#define WM8350_ACC_DET_ENA                      0x0100
+#define WM8350_AUXADC_ENA                       0x0080
+#define WM8350_DCMP4_ENA                        0x0008
+#define WM8350_DCMP3_ENA                        0x0004
+#define WM8350_DCMP2_ENA                        0x0002
+#define WM8350_DCMP1_ENA                        0x0001
+
+/*
+ * R13 (0x0D) - Power mgmt (6)
+ */
+#define WM8350_LS_ENA                           0x8000
+#define WM8350_LDO4_ENA                         0x0800
+#define WM8350_LDO3_ENA                         0x0400
+#define WM8350_LDO2_ENA                         0x0200
+#define WM8350_LDO1_ENA                         0x0100
+#define WM8350_DC6_ENA                          0x0020
+#define WM8350_DC5_ENA                          0x0010
+#define WM8350_DC4_ENA                          0x0008
+#define WM8350_DC3_ENA                          0x0004
+#define WM8350_DC2_ENA                          0x0002
+#define WM8350_DC1_ENA                          0x0001
+
+/*
+ * R14 (0x0E) - Power mgmt (7)
+ */
+#define WM8350_CS2_ENA                          0x0002
+#define WM8350_CS1_ENA                          0x0001
+
+/*
+ * R24 (0x18) - System Interrupts
+ */
+#define WM8350_OC_INT                           0x2000
+#define WM8350_UV_INT                           0x1000
+#define WM8350_PUTO_INT                         0x0800
+#define WM8350_CS_INT                           0x0200
+#define WM8350_EXT_INT                          0x0100
+#define WM8350_CODEC_INT                        0x0080
+#define WM8350_GP_INT                           0x0040
+#define WM8350_AUXADC_INT                       0x0020
+#define WM8350_RTC_INT                          0x0010
+#define WM8350_SYS_INT                          0x0008
+#define WM8350_CHG_INT                          0x0004
+#define WM8350_USB_INT                          0x0002
+#define WM8350_WKUP_INT                         0x0001
+
+/*
+ * R25 (0x19) - Interrupt Status 1
+ */
+#define WM8350_CHG_BAT_HOT_EINT                 0x8000
+#define WM8350_CHG_BAT_COLD_EINT                0x4000
+#define WM8350_CHG_BAT_FAIL_EINT                0x2000
+#define WM8350_CHG_TO_EINT                      0x1000
+#define WM8350_CHG_END_EINT                     0x0800
+#define WM8350_CHG_START_EINT                   0x0400
+#define WM8350_CHG_FAST_RDY_EINT                0x0200
+#define WM8350_RTC_PER_EINT                     0x0080
+#define WM8350_RTC_SEC_EINT                     0x0040
+#define WM8350_RTC_ALM_EINT                     0x0020
+#define WM8350_CHG_VBATT_LT_3P9_EINT            0x0004
+#define WM8350_CHG_VBATT_LT_3P1_EINT            0x0002
+#define WM8350_CHG_VBATT_LT_2P85_EINT           0x0001
+
+/*
+ * R26 (0x1A) - Interrupt Status 2
+ */
+#define WM8350_CS1_EINT                         0x2000
+#define WM8350_CS2_EINT                         0x1000
+#define WM8350_USB_LIMIT_EINT                   0x0400
+#define WM8350_AUXADC_DATARDY_EINT              0x0100
+#define WM8350_AUXADC_DCOMP4_EINT               0x0080
+#define WM8350_AUXADC_DCOMP3_EINT               0x0040
+#define WM8350_AUXADC_DCOMP2_EINT               0x0020
+#define WM8350_AUXADC_DCOMP1_EINT               0x0010
+#define WM8350_SYS_HYST_COMP_FAIL_EINT          0x0008
+#define WM8350_SYS_CHIP_GT115_EINT              0x0004
+#define WM8350_SYS_CHIP_GT140_EINT              0x0002
+#define WM8350_SYS_WDOG_TO_EINT                 0x0001
+
+/*
+ * R27 (0x1B) - Power Up Interrupt Status
+ */
+#define WM8350_PUTO_LDO4_EINT                   0x0800
+#define WM8350_PUTO_LDO3_EINT                   0x0400
+#define WM8350_PUTO_LDO2_EINT                   0x0200
+#define WM8350_PUTO_LDO1_EINT                   0x0100
+#define WM8350_PUTO_DC6_EINT                    0x0020
+#define WM8350_PUTO_DC5_EINT                    0x0010
+#define WM8350_PUTO_DC4_EINT                    0x0008
+#define WM8350_PUTO_DC3_EINT                    0x0004
+#define WM8350_PUTO_DC2_EINT                    0x0002
+#define WM8350_PUTO_DC1_EINT                    0x0001
+
+/*
+ * R28 (0x1C) - Under Voltage Interrupt status
+ */
+#define WM8350_UV_LDO4_EINT                     0x0800
+#define WM8350_UV_LDO3_EINT                     0x0400
+#define WM8350_UV_LDO2_EINT                     0x0200
+#define WM8350_UV_LDO1_EINT                     0x0100
+#define WM8350_UV_DC6_EINT                      0x0020
+#define WM8350_UV_DC5_EINT                      0x0010
+#define WM8350_UV_DC4_EINT                      0x0008
+#define WM8350_UV_DC3_EINT                      0x0004
+#define WM8350_UV_DC2_EINT                      0x0002
+#define WM8350_UV_DC1_EINT                      0x0001
+
+/*
+ * R29 (0x1D) - Over Current Interrupt status
+ */
+#define WM8350_OC_LS_EINT                       0x8000
+
+/*
+ * R30 (0x1E) - GPIO Interrupt Status
+ */
+#define WM8350_GP12_EINT                        0x1000
+#define WM8350_GP11_EINT                        0x0800
+#define WM8350_GP10_EINT                        0x0400
+#define WM8350_GP9_EINT                         0x0200
+#define WM8350_GP8_EINT                         0x0100
+#define WM8350_GP7_EINT                         0x0080
+#define WM8350_GP6_EINT                         0x0040
+#define WM8350_GP5_EINT                         0x0020
+#define WM8350_GP4_EINT                         0x0010
+#define WM8350_GP3_EINT                         0x0008
+#define WM8350_GP2_EINT                         0x0004
+#define WM8350_GP1_EINT                         0x0002
+#define WM8350_GP0_EINT                         0x0001
+
+/*
+ * R31 (0x1F) - Comparator Interrupt Status
+ */
+#define WM8350_EXT_USB_FB_EINT                  0x8000
+#define WM8350_EXT_WALL_FB_EINT                 0x4000
+#define WM8350_EXT_BAT_FB_EINT                  0x2000
+#define WM8350_CODEC_JCK_DET_L_EINT             0x0800
+#define WM8350_CODEC_JCK_DET_R_EINT             0x0400
+#define WM8350_CODEC_MICSCD_EINT                0x0200
+#define WM8350_CODEC_MICD_EINT                  0x0100
+#define WM8350_WKUP_OFF_STATE_EINT              0x0040
+#define WM8350_WKUP_HIB_STATE_EINT              0x0020
+#define WM8350_WKUP_CONV_FAULT_EINT             0x0010
+#define WM8350_WKUP_WDOG_RST_EINT               0x0008
+#define WM8350_WKUP_GP_PWR_ON_EINT              0x0004
+#define WM8350_WKUP_ONKEY_EINT                  0x0002
+#define WM8350_WKUP_GP_WAKEUP_EINT              0x0001
+
+/*
+ * R32 (0x20) - System Interrupts Mask
+ */
+#define WM8350_IM_OC_INT                        0x2000
+#define WM8350_IM_UV_INT                        0x1000
+#define WM8350_IM_PUTO_INT                      0x0800
+#define WM8350_IM_SPARE_INT                     0x0400
+#define WM8350_IM_CS_INT                        0x0200
+#define WM8350_IM_EXT_INT                       0x0100
+#define WM8350_IM_CODEC_INT                     0x0080
+#define WM8350_IM_GP_INT                        0x0040
+#define WM8350_IM_AUXADC_INT                    0x0020
+#define WM8350_IM_RTC_INT                       0x0010
+#define WM8350_IM_SYS_INT                       0x0008
+#define WM8350_IM_CHG_INT                       0x0004
+#define WM8350_IM_USB_INT                       0x0002
+#define WM8350_IM_WKUP_INT                      0x0001
+
+/*
+ * R33 (0x21) - Interrupt Status 1 Mask
+ */
+#define WM8350_IM_CHG_BAT_HOT_EINT              0x8000
+#define WM8350_IM_CHG_BAT_COLD_EINT             0x4000
+#define WM8350_IM_CHG_BAT_FAIL_EINT             0x2000
+#define WM8350_IM_CHG_TO_EINT                   0x1000
+#define WM8350_IM_CHG_END_EINT                  0x0800
+#define WM8350_IM_CHG_START_EINT                0x0400
+#define WM8350_IM_CHG_FAST_RDY_EINT             0x0200
+#define WM8350_IM_RTC_PER_EINT                  0x0080
+#define WM8350_IM_RTC_SEC_EINT                  0x0040
+#define WM8350_IM_RTC_ALM_EINT                  0x0020
+#define WM8350_IM_CHG_VBATT_LT_3P9_EINT         0x0004
+#define WM8350_IM_CHG_VBATT_LT_3P1_EINT         0x0002
+#define WM8350_IM_CHG_VBATT_LT_2P85_EINT        0x0001
+
+/*
+ * R34 (0x22) - Interrupt Status 2 Mask
+ */
+#define WM8350_IM_SPARE2_EINT                   0x8000
+#define WM8350_IM_SPARE1_EINT                   0x4000
+#define WM8350_IM_CS1_EINT                      0x2000
+#define WM8350_IM_CS2_EINT                      0x1000
+#define WM8350_IM_USB_LIMIT_EINT                0x0400
+#define WM8350_IM_AUXADC_DATARDY_EINT           0x0100
+#define WM8350_IM_AUXADC_DCOMP4_EINT            0x0080
+#define WM8350_IM_AUXADC_DCOMP3_EINT            0x0040
+#define WM8350_IM_AUXADC_DCOMP2_EINT            0x0020
+#define WM8350_IM_AUXADC_DCOMP1_EINT            0x0010
+#define WM8350_IM_SYS_HYST_COMP_FAIL_EINT       0x0008
+#define WM8350_IM_SYS_CHIP_GT115_EINT           0x0004
+#define WM8350_IM_SYS_CHIP_GT140_EINT           0x0002
+#define WM8350_IM_SYS_WDOG_TO_EINT              0x0001
+
+/*
+ * R35 (0x23) - Power Up Interrupt Status Mask
+ */
+#define WM8350_IM_PUTO_LDO4_EINT                0x0800
+#define WM8350_IM_PUTO_LDO3_EINT                0x0400
+#define WM8350_IM_PUTO_LDO2_EINT                0x0200
+#define WM8350_IM_PUTO_LDO1_EINT                0x0100
+#define WM8350_IM_PUTO_DC6_EINT                 0x0020
+#define WM8350_IM_PUTO_DC5_EINT                 0x0010
+#define WM8350_IM_PUTO_DC4_EINT                 0x0008
+#define WM8350_IM_PUTO_DC3_EINT                 0x0004
+#define WM8350_IM_PUTO_DC2_EINT                 0x0002
+#define WM8350_IM_PUTO_DC1_EINT                 0x0001
+
+/*
+ * R36 (0x24) - Under Voltage Interrupt status Mask
+ */
+#define WM8350_IM_UV_LDO4_EINT                  0x0800
+#define WM8350_IM_UV_LDO3_EINT                  0x0400
+#define WM8350_IM_UV_LDO2_EINT                  0x0200
+#define WM8350_IM_UV_LDO1_EINT                  0x0100
+#define WM8350_IM_UV_DC6_EINT                   0x0020
+#define WM8350_IM_UV_DC5_EINT                   0x0010
+#define WM8350_IM_UV_DC4_EINT                   0x0008
+#define WM8350_IM_UV_DC3_EINT                   0x0004
+#define WM8350_IM_UV_DC2_EINT                   0x0002
+#define WM8350_IM_UV_DC1_EINT                   0x0001
+
+/*
+ * R37 (0x25) - Over Current Interrupt status Mask
+ */
+#define WM8350_IM_OC_LS_EINT                    0x8000
+
+/*
+ * R38 (0x26) - GPIO Interrupt Status Mask
+ */
+#define WM8350_IM_GP12_EINT                     0x1000
+#define WM8350_IM_GP11_EINT                     0x0800
+#define WM8350_IM_GP10_EINT                     0x0400
+#define WM8350_IM_GP9_EINT                      0x0200
+#define WM8350_IM_GP8_EINT                      0x0100
+#define WM8350_IM_GP7_EINT                      0x0080
+#define WM8350_IM_GP6_EINT                      0x0040
+#define WM8350_IM_GP5_EINT                      0x0020
+#define WM8350_IM_GP4_EINT                      0x0010
+#define WM8350_IM_GP3_EINT                      0x0008
+#define WM8350_IM_GP2_EINT                      0x0004
+#define WM8350_IM_GP1_EINT                      0x0002
+#define WM8350_IM_GP0_EINT                      0x0001
+
+/*
+ * R39 (0x27) - Comparator Interrupt Status Mask
+ */
+#define WM8350_IM_EXT_USB_FB_EINT               0x8000
+#define WM8350_IM_EXT_WALL_FB_EINT              0x4000
+#define WM8350_IM_EXT_BAT_FB_EINT               0x2000
+#define WM8350_IM_CODEC_JCK_DET_L_EINT          0x0800
+#define WM8350_IM_CODEC_JCK_DET_R_EINT          0x0400
+#define WM8350_IM_CODEC_MICSCD_EINT             0x0200
+#define WM8350_IM_CODEC_MICD_EINT               0x0100
+#define WM8350_IM_WKUP_OFF_STATE_EINT           0x0040
+#define WM8350_IM_WKUP_HIB_STATE_EINT           0x0020
+#define WM8350_IM_WKUP_CONV_FAULT_EINT          0x0010
+#define WM8350_IM_WKUP_WDOG_RST_EINT            0x0008
+#define WM8350_IM_WKUP_GP_PWR_ON_EINT           0x0004
+#define WM8350_IM_WKUP_ONKEY_EINT               0x0002
+#define WM8350_IM_WKUP_GP_WAKEUP_EINT           0x0001
+
+/*
+ * R220 (0xDC) - RAM BIST 1
+ */
+#define WM8350_READ_STATUS                      0x0800
+#define WM8350_TSTRAM_CLK                       0x0100
+#define WM8350_TSTRAM_CLK_ENA                   0x0080
+#define WM8350_STARTSEQ                         0x0040
+#define WM8350_READ_SRC                         0x0020
+#define WM8350_COUNT_DIR                        0x0010
+#define WM8350_TSTRAM_MODE_MASK                 0x000E
+#define WM8350_TSTRAM_ENA                       0x0001
+
+/*
+ * R225 (0xE1) - DCDC/LDO status
+ */
+#define WM8350_LS_STS                           0x8000
+#define WM8350_LDO4_STS                         0x0800
+#define WM8350_LDO3_STS                         0x0400
+#define WM8350_LDO2_STS                         0x0200
+#define WM8350_LDO1_STS                         0x0100
+#define WM8350_DC6_STS                          0x0020
+#define WM8350_DC5_STS                          0x0010
+#define WM8350_DC4_STS                          0x0008
+#define WM8350_DC3_STS                          0x0004
+#define WM8350_DC2_STS                          0x0002
+#define WM8350_DC1_STS                          0x0001
+
+/* WM8350 wake up conditions */
+#define WM8350_IRQ_WKUP_OFF_STATE		43
+#define WM8350_IRQ_WKUP_HIB_STATE		44
+#define WM8350_IRQ_WKUP_CONV_FAULT		45
+#define WM8350_IRQ_WKUP_WDOG_RST		46
+#define WM8350_IRQ_WKUP_GP_PWR_ON		47
+#define WM8350_IRQ_WKUP_ONKEY			48
+#define WM8350_IRQ_WKUP_GP_WAKEUP		49
+
+/* wm8350 chip revisions */
+#define WM8350_REV_E				0x4
+#define WM8350_REV_F				0x5
+#define WM8350_REV_G				0x6
+
+#define WM8350_NUM_IRQ				63
+
+struct wm8350_reg_access {
+	u16 readable;		/* Mask of readable bits */
+	u16 writable;		/* Mask of writable bits */
+	u16 vol;		/* Mask of volatile bits */
+};
+extern const struct wm8350_reg_access wm8350_reg_io_map[];
+extern const u16 wm8350_mode0_defaults[];
+extern const u16 wm8350_mode1_defaults[];
+extern const u16 wm8350_mode2_defaults[];
+extern const u16 wm8350_mode3_defaults[];
+
+struct wm8350;
+
+struct wm8350_irq {
+	void (*handler) (struct wm8350 *, int, void *);
+	void *data;
+};
+
+struct wm8350 {
+	int rev;		/* chip revision */
+
+	struct device *dev;
+
+	/* device IO */
+	union {
+		struct i2c_client *i2c_client;
+		struct spi_device *spi_device;
+	};
+	int (*read_dev)(struct wm8350 *wm8350, char reg, int size, void *dest);
+	int (*write_dev)(struct wm8350 *wm8350, char reg, int size,
+			 void *src);
+	u16 *reg_cache;
+
+	/* Interrupt handling */
+	struct work_struct irq_work;
+	struct mutex irq_mutex; /* IRQ table mutex */
+	struct wm8350_irq irq[WM8350_NUM_IRQ];
+	int chip_irq;
+
+	/* Client devices */
+	struct wm8350_codec codec;
+	struct wm8350_gpio gpio;
+	struct wm8350_pmic pmic;
+	struct wm8350_power power;
+	struct wm8350_rtc rtc;
+	struct wm8350_wdt wdt;
+};
+
+/**
+ * Data to be supplied by the platform to initialise the WM8350.
+ *
+ * @init: Function called during driver initialisation.  Should be
+ *        used by the platform to configure GPIO functions and similar.
+ */
+struct wm8350_platform_data {
+	int (*init)(struct wm8350 *wm8350);
+};
+
+
+/*
+ * WM8350 device initialisation and exit.
+ */
+int wm8350_device_init(struct wm8350 *wm8350, int irq,
+		       struct wm8350_platform_data *pdata);
+void wm8350_device_exit(struct wm8350 *wm8350);
+
+/*
+ * WM8350 device IO
+ */
+int wm8350_clear_bits(struct wm8350 *wm8350, u16 reg, u16 mask);
+int wm8350_set_bits(struct wm8350 *wm8350, u16 reg, u16 mask);
+u16 wm8350_reg_read(struct wm8350 *wm8350, int reg);
+int wm8350_reg_write(struct wm8350 *wm8350, int reg, u16 val);
+int wm8350_reg_lock(struct wm8350 *wm8350);
+int wm8350_reg_unlock(struct wm8350 *wm8350);
+int wm8350_block_read(struct wm8350 *wm8350, int reg, int size, u16 *dest);
+int wm8350_block_write(struct wm8350 *wm8350, int reg, int size, u16 *src);
+
+/*
+ * WM8350 internal interrupts
+ */
+int wm8350_register_irq(struct wm8350 *wm8350, int irq,
+			void (*handler) (struct wm8350 *, int, void *),
+			void *data);
+int wm8350_free_irq(struct wm8350 *wm8350, int irq);
+int wm8350_mask_irq(struct wm8350 *wm8350, int irq);
+int wm8350_unmask_irq(struct wm8350 *wm8350, int irq);
+
+
+#endif
diff --git a/include/linux/mfd/wm8350/gpio.h b/include/linux/mfd/wm8350/gpio.h
new file mode 100644
index 0000000..ed91e8f
--- /dev/null
+++ b/include/linux/mfd/wm8350/gpio.h
@@ -0,0 +1,342 @@
+/*
+ * gpio.h  --  GPIO Driver for Wolfson WM8350 PMIC
+ *
+ * Copyright 2007 Wolfson Microelectronics PLC
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ */
+
+#ifndef __LINUX_MFD_WM8350_GPIO_H_
+#define __LINUX_MFD_WM8350_GPIO_H_
+
+#include <linux/platform_device.h>
+
+/*
+ * GPIO Registers.
+ */
+#define WM8350_GPIO_DEBOUNCE                    0x80
+#define WM8350_GPIO_PIN_PULL_UP_CONTROL         0x81
+#define WM8350_GPIO_PULL_DOWN_CONTROL           0x82
+#define WM8350_GPIO_INT_MODE                    0x83
+#define WM8350_GPIO_CONTROL                     0x85
+#define WM8350_GPIO_CONFIGURATION_I_O           0x86
+#define WM8350_GPIO_PIN_POLARITY_TYPE           0x87
+#define WM8350_GPIO_FUNCTION_SELECT_1           0x8C
+#define WM8350_GPIO_FUNCTION_SELECT_2           0x8D
+#define WM8350_GPIO_FUNCTION_SELECT_3           0x8E
+#define WM8350_GPIO_FUNCTION_SELECT_4           0x8F
+
+/*
+ * GPIO Functions
+ */
+#define WM8350_GPIO0_GPIO_IN			0x0
+#define WM8350_GPIO0_GPIO_OUT			0x0
+#define WM8350_GPIO0_PWR_ON_IN			0x1
+#define WM8350_GPIO0_PWR_ON_OUT			0x1
+#define WM8350_GPIO0_LDO_EN_IN			0x2
+#define WM8350_GPIO0_VRTC_OUT			0x2
+#define WM8350_GPIO0_LPWR1_IN			0x3
+#define WM8350_GPIO0_POR_B_OUT			0x3
+
+#define WM8350_GPIO1_GPIO_IN			0x0
+#define WM8350_GPIO1_GPIO_OUT			0x0
+#define WM8350_GPIO1_PWR_ON_IN			0x1
+#define WM8350_GPIO1_DO_CONF_OUT		0x1
+#define WM8350_GPIO1_LDO_EN_IN			0x2
+#define WM8350_GPIO1_RESET_OUT			0x2
+#define WM8350_GPIO1_LPWR2_IN			0x3
+#define WM8350_GPIO1_MEMRST_OUT			0x3
+
+#define WM8350_GPIO2_GPIO_IN			0x0
+#define WM8350_GPIO2_GPIO_OUT			0x0
+#define WM8350_GPIO2_PWR_ON_IN			0x1
+#define WM8350_GPIO2_PWR_ON_OUT			0x1
+#define WM8350_GPIO2_WAKE_UP_IN			0x2
+#define WM8350_GPIO2_VRTC_OUT			0x2
+#define WM8350_GPIO2_32KHZ_IN			0x3
+#define WM8350_GPIO2_32KHZ_OUT			0x3
+
+#define WM8350_GPIO3_GPIO_IN			0x0
+#define WM8350_GPIO3_GPIO_OUT			0x0
+#define WM8350_GPIO3_PWR_ON_IN			0x1
+#define WM8350_GPIO3_P_CLK_OUT			0x1
+#define WM8350_GPIO3_LDO_EN_IN			0x2
+#define WM8350_GPIO3_VRTC_OUT			0x2
+#define WM8350_GPIO3_PWR_OFF_IN			0x3
+#define WM8350_GPIO3_32KHZ_OUT			0x3
+
+#define WM8350_GPIO4_GPIO_IN			0x0
+#define WM8350_GPIO4_GPIO_OUT			0x0
+#define WM8350_GPIO4_MR_IN			0x1
+#define WM8350_GPIO4_MEM_RST_OUT		0x1
+#define WM8350_GPIO4_FLASH_IN			0x2
+#define WM8350_GPIO4_ADA_OUT			0x2
+#define WM8350_GPIO4_HIBERNATE_IN		0x3
+#define WM8350_GPIO4_FLASH_OUT			0x3
+#define WM8350_GPIO4_MICDET_OUT			0x4
+#define WM8350_GPIO4_MICSHT_OUT			0x5
+
+#define WM8350_GPIO5_GPIO_IN			0x0
+#define WM8350_GPIO5_GPIO_OUT			0x0
+#define WM8350_GPIO5_LPWR1_IN			0x1
+#define WM8350_GPIO5_P_CLK_OUT			0x1
+#define WM8350_GPIO5_ADCLRCLK_IN		0x2
+#define WM8350_GPIO5_ADCLRCLK_OUT		0x2
+#define WM8350_GPIO5_HIBERNATE_IN		0x3
+#define WM8350_GPIO5_32KHZ_OUT			0x3
+#define WM8350_GPIO5_MICDET_OUT			0x4
+#define WM8350_GPIO5_MICSHT_OUT			0x5
+#define WM8350_GPIO5_ADA_OUT			0x6
+#define WM8350_GPIO5_OPCLK_OUT			0x7
+
+#define WM8350_GPIO6_GPIO_IN			0x0
+#define WM8350_GPIO6_GPIO_OUT			0x0
+#define WM8350_GPIO6_LPWR2_IN			0x1
+#define WM8350_GPIO6_MEMRST_OUT			0x1
+#define WM8350_GPIO6_FLASH_IN			0x2
+#define WM8350_GPIO6_ADA_OUT			0x2
+#define WM8350_GPIO6_HIBERNATE_IN		0x3
+#define WM8350_GPIO6_RTC_OUT			0x3
+#define WM8350_GPIO6_MICDET_OUT			0x4
+#define WM8350_GPIO6_MICSHT_OUT			0x5
+#define WM8350_GPIO6_ADCLRCLKB_OUT		0x6
+#define WM8350_GPIO6_SDOUT_OUT			0x7
+
+#define WM8350_GPIO7_GPIO_IN			0x0
+#define WM8350_GPIO7_GPIO_OUT			0x0
+#define WM8350_GPIO7_LPWR3_IN			0x1
+#define WM8350_GPIO7_P_CLK_OUT			0x1
+#define WM8350_GPIO7_MASK_IN			0x2
+#define WM8350_GPIO7_VCC_FAULT_OUT		0x2
+#define WM8350_GPIO7_HIBERNATE_IN		0x3
+#define WM8350_GPIO7_BATT_FAULT_OUT		0x3
+#define WM8350_GPIO7_MICDET_OUT			0x4
+#define WM8350_GPIO7_MICSHT_OUT			0x5
+#define WM8350_GPIO7_ADA_OUT			0x6
+#define WM8350_GPIO7_CSB_IN			0x7
+
+#define WM8350_GPIO8_GPIO_IN			0x0
+#define WM8350_GPIO8_GPIO_OUT			0x0
+#define WM8350_GPIO8_MR_IN			0x1
+#define WM8350_GPIO8_VCC_FAULT_OUT		0x1
+#define WM8350_GPIO8_ADCBCLK_IN			0x2
+#define WM8350_GPIO8_ADCBCLK_OUT		0x2
+#define WM8350_GPIO8_PWR_OFF_IN			0x3
+#define WM8350_GPIO8_BATT_FAULT_OUT		0x3
+#define WM8350_GPIO8_ALTSCL_IN			0xf
+
+#define WM8350_GPIO9_GPIO_IN			0x0
+#define WM8350_GPIO9_GPIO_OUT			0x0
+#define WM8350_GPIO9_HEARTBEAT_IN		0x1
+#define WM8350_GPIO9_VCC_FAULT_OUT		0x1
+#define WM8350_GPIO9_MASK_IN			0x2
+#define WM8350_GPIO9_LINE_GT_BATT_OUT		0x2
+#define WM8350_GPIO9_PWR_OFF_IN			0x3
+#define WM8350_GPIO9_BATT_FAULT_OUT		0x3
+#define WM8350_GPIO9_ALTSDA_OUT			0xf
+
+#define WM8350_GPIO10_GPIO_IN			0x0
+#define WM8350_GPIO10_GPIO_OUT			0x0
+#define WM8350_GPIO10_ISINKC_OUT		0x1
+#define WM8350_GPIO10_PWR_OFF_IN		0x2
+#define WM8350_GPIO10_LINE_GT_BATT_OUT		0x2
+#define WM8350_GPIO10_CHD_IND_IN		0x3
+
+#define WM8350_GPIO11_GPIO_IN			0x0
+#define WM8350_GPIO11_GPIO_OUT			0x0
+#define WM8350_GPIO11_ISINKD_OUT		0x1
+#define WM8350_GPIO11_WAKEUP_IN			0x2
+#define WM8350_GPIO11_LINE_GT_BATT_OUT		0x2
+#define WM8350_GPIO11_CHD_IND_IN		0x3
+
+#define WM8350_GPIO12_GPIO_IN			0x0
+#define WM8350_GPIO12_GPIO_OUT			0x0
+#define WM8350_GPIO12_ISINKE_OUT		0x1
+#define WM8350_GPIO12_LINE_GT_BATT_OUT		0x2
+#define WM8350_GPIO12_LINE_EN_OUT		0x3
+#define WM8350_GPIO12_32KHZ_OUT			0x4
+
+#define WM8350_GPIO_DIR_IN			0
+#define WM8350_GPIO_DIR_OUT			1
+#define WM8350_GPIO_ACTIVE_LOW			0
+#define WM8350_GPIO_ACTIVE_HIGH			1
+#define WM8350_GPIO_PULL_NONE			0
+#define WM8350_GPIO_PULL_UP			1
+#define WM8350_GPIO_PULL_DOWN			2
+#define WM8350_GPIO_INVERT_OFF			0
+#define WM8350_GPIO_INVERT_ON			1
+#define WM8350_GPIO_DEBOUNCE_OFF		0
+#define WM8350_GPIO_DEBOUNCE_ON			1
+
+/*
+ * R128 (0x80) - GPIO Debounce
+ */
+#define WM8350_GP12_DB                          0x1000
+#define WM8350_GP11_DB                          0x0800
+#define WM8350_GP10_DB                          0x0400
+#define WM8350_GP9_DB                           0x0200
+#define WM8350_GP8_DB                           0x0100
+#define WM8350_GP7_DB                           0x0080
+#define WM8350_GP6_DB                           0x0040
+#define WM8350_GP5_DB                           0x0020
+#define WM8350_GP4_DB                           0x0010
+#define WM8350_GP3_DB                           0x0008
+#define WM8350_GP2_DB                           0x0004
+#define WM8350_GP1_DB                           0x0002
+#define WM8350_GP0_DB                           0x0001
+
+/*
+ * R129 (0x81) - GPIO Pin pull up Control
+ */
+#define WM8350_GP12_PU                          0x1000
+#define WM8350_GP11_PU                          0x0800
+#define WM8350_GP10_PU                          0x0400
+#define WM8350_GP9_PU                           0x0200
+#define WM8350_GP8_PU                           0x0100
+#define WM8350_GP7_PU                           0x0080
+#define WM8350_GP6_PU                           0x0040
+#define WM8350_GP5_PU                           0x0020
+#define WM8350_GP4_PU                           0x0010
+#define WM8350_GP3_PU                           0x0008
+#define WM8350_GP2_PU                           0x0004
+#define WM8350_GP1_PU                           0x0002
+#define WM8350_GP0_PU                           0x0001
+
+/*
+ * R130 (0x82) - GPIO Pull down Control
+ */
+#define WM8350_GP12_PD                          0x1000
+#define WM8350_GP11_PD                          0x0800
+#define WM8350_GP10_PD                          0x0400
+#define WM8350_GP9_PD                           0x0200
+#define WM8350_GP8_PD                           0x0100
+#define WM8350_GP7_PD                           0x0080
+#define WM8350_GP6_PD                           0x0040
+#define WM8350_GP5_PD                           0x0020
+#define WM8350_GP4_PD                           0x0010
+#define WM8350_GP3_PD                           0x0008
+#define WM8350_GP2_PD                           0x0004
+#define WM8350_GP1_PD                           0x0002
+#define WM8350_GP0_PD                           0x0001
+
+/*
+ * R131 (0x83) - GPIO Interrupt Mode
+ */
+#define WM8350_GP12_INTMODE                     0x1000
+#define WM8350_GP11_INTMODE                     0x0800
+#define WM8350_GP10_INTMODE                     0x0400
+#define WM8350_GP9_INTMODE                      0x0200
+#define WM8350_GP8_INTMODE                      0x0100
+#define WM8350_GP7_INTMODE                      0x0080
+#define WM8350_GP6_INTMODE                      0x0040
+#define WM8350_GP5_INTMODE                      0x0020
+#define WM8350_GP4_INTMODE                      0x0010
+#define WM8350_GP3_INTMODE                      0x0008
+#define WM8350_GP2_INTMODE                      0x0004
+#define WM8350_GP1_INTMODE                      0x0002
+#define WM8350_GP0_INTMODE                      0x0001
+
+/*
+ * R133 (0x85) - GPIO Control
+ */
+#define WM8350_GP_DBTIME_MASK                   0x00C0
+
+/*
+ * R134 (0x86) - GPIO Configuration (i/o)
+ */
+#define WM8350_GP12_DIR                         0x1000
+#define WM8350_GP11_DIR                         0x0800
+#define WM8350_GP10_DIR                         0x0400
+#define WM8350_GP9_DIR                          0x0200
+#define WM8350_GP8_DIR                          0x0100
+#define WM8350_GP7_DIR                          0x0080
+#define WM8350_GP6_DIR                          0x0040
+#define WM8350_GP5_DIR                          0x0020
+#define WM8350_GP4_DIR                          0x0010
+#define WM8350_GP3_DIR                          0x0008
+#define WM8350_GP2_DIR                          0x0004
+#define WM8350_GP1_DIR                          0x0002
+#define WM8350_GP0_DIR                          0x0001
+
+/*
+ * R135 (0x87) - GPIO Pin Polarity / Type
+ */
+#define WM8350_GP12_CFG                         0x1000
+#define WM8350_GP11_CFG                         0x0800
+#define WM8350_GP10_CFG                         0x0400
+#define WM8350_GP9_CFG                          0x0200
+#define WM8350_GP8_CFG                          0x0100
+#define WM8350_GP7_CFG                          0x0080
+#define WM8350_GP6_CFG                          0x0040
+#define WM8350_GP5_CFG                          0x0020
+#define WM8350_GP4_CFG                          0x0010
+#define WM8350_GP3_CFG                          0x0008
+#define WM8350_GP2_CFG                          0x0004
+#define WM8350_GP1_CFG                          0x0002
+#define WM8350_GP0_CFG                          0x0001
+
+/*
+ * R140 (0x8C) - GPIO Function Select 1
+ */
+#define WM8350_GP3_FN_MASK                      0xF000
+#define WM8350_GP2_FN_MASK                      0x0F00
+#define WM8350_GP1_FN_MASK                      0x00F0
+#define WM8350_GP0_FN_MASK                      0x000F
+
+/*
+ * R141 (0x8D) - GPIO Function Select 2
+ */
+#define WM8350_GP7_FN_MASK                      0xF000
+#define WM8350_GP6_FN_MASK                      0x0F00
+#define WM8350_GP5_FN_MASK                      0x00F0
+#define WM8350_GP4_FN_MASK                      0x000F
+
+/*
+ * R142 (0x8E) - GPIO Function Select 3
+ */
+#define WM8350_GP11_FN_MASK                     0xF000
+#define WM8350_GP10_FN_MASK                     0x0F00
+#define WM8350_GP9_FN_MASK                      0x00F0
+#define WM8350_GP8_FN_MASK                      0x000F
+
+/*
+ * R143 (0x8F) - GPIO Function Select 4
+ */
+#define WM8350_GP12_FN_MASK                     0x000F
+
+/*
+ * R230 (0xE6) - GPIO Pin Status
+ */
+#define WM8350_GP12_LVL                         0x1000
+#define WM8350_GP11_LVL                         0x0800
+#define WM8350_GP10_LVL                         0x0400
+#define WM8350_GP9_LVL                          0x0200
+#define WM8350_GP8_LVL                          0x0100
+#define WM8350_GP7_LVL                          0x0080
+#define WM8350_GP6_LVL                          0x0040
+#define WM8350_GP5_LVL                          0x0020
+#define WM8350_GP4_LVL                          0x0010
+#define WM8350_GP3_LVL                          0x0008
+#define WM8350_GP2_LVL                          0x0004
+#define WM8350_GP1_LVL                          0x0002
+#define WM8350_GP0_LVL                          0x0001
+
+struct wm8350;
+
+int wm8350_gpio_config(struct wm8350 *wm8350, int gpio, int dir, int func,
+		       int pol, int pull, int invert, int debounce);
+
+struct wm8350_gpio {
+	struct platform_device *pdev;
+};
+
+/*
+ * GPIO Interrupts
+ */
+#define WM8350_IRQ_GPIO(x)                      (50 + x)
+
+#endif
diff --git a/include/linux/mfd/wm8350/pmic.h b/include/linux/mfd/wm8350/pmic.h
new file mode 100644
index 0000000..69b69e0
--- /dev/null
+++ b/include/linux/mfd/wm8350/pmic.h
@@ -0,0 +1,741 @@
+/*
+ * pmic.h  --  Power Managment Driver for Wolfson WM8350 PMIC
+ *
+ * Copyright 2007 Wolfson Microelectronics PLC
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ */
+
+#ifndef __LINUX_MFD_WM8350_PMIC_H
+#define __LINUX_MFD_WM8350_PMIC_H
+
+/*
+ * Register values.
+ */
+
+#define WM8350_CURRENT_SINK_DRIVER_A            0xAC
+#define WM8350_CSA_FLASH_CONTROL                0xAD
+#define WM8350_CURRENT_SINK_DRIVER_B            0xAE
+#define WM8350_CSB_FLASH_CONTROL                0xAF
+#define WM8350_DCDC_LDO_REQUESTED               0xB0
+#define WM8350_DCDC_ACTIVE_OPTIONS              0xB1
+#define WM8350_DCDC_SLEEP_OPTIONS               0xB2
+#define WM8350_POWER_CHECK_COMPARATOR           0xB3
+#define WM8350_DCDC1_CONTROL                    0xB4
+#define WM8350_DCDC1_TIMEOUTS                   0xB5
+#define WM8350_DCDC1_LOW_POWER                  0xB6
+#define WM8350_DCDC2_CONTROL                    0xB7
+#define WM8350_DCDC2_TIMEOUTS                   0xB8
+#define WM8350_DCDC3_CONTROL                    0xBA
+#define WM8350_DCDC3_TIMEOUTS                   0xBB
+#define WM8350_DCDC3_LOW_POWER                  0xBC
+#define WM8350_DCDC4_CONTROL                    0xBD
+#define WM8350_DCDC4_TIMEOUTS                   0xBE
+#define WM8350_DCDC4_LOW_POWER                  0xBF
+#define WM8350_DCDC5_CONTROL                    0xC0
+#define WM8350_DCDC5_TIMEOUTS                   0xC1
+#define WM8350_DCDC6_CONTROL                    0xC3
+#define WM8350_DCDC6_TIMEOUTS                   0xC4
+#define WM8350_DCDC6_LOW_POWER                  0xC5
+#define WM8350_LIMIT_SWITCH_CONTROL             0xC7
+#define WM8350_LDO1_CONTROL                     0xC8
+#define WM8350_LDO1_TIMEOUTS                    0xC9
+#define WM8350_LDO1_LOW_POWER                   0xCA
+#define WM8350_LDO2_CONTROL                     0xCB
+#define WM8350_LDO2_TIMEOUTS                    0xCC
+#define WM8350_LDO2_LOW_POWER                   0xCD
+#define WM8350_LDO3_CONTROL                     0xCE
+#define WM8350_LDO3_TIMEOUTS                    0xCF
+#define WM8350_LDO3_LOW_POWER                   0xD0
+#define WM8350_LDO4_CONTROL                     0xD1
+#define WM8350_LDO4_TIMEOUTS                    0xD2
+#define WM8350_LDO4_LOW_POWER                   0xD3
+#define WM8350_VCC_FAULT_MASKS                  0xD7
+#define WM8350_MAIN_BANDGAP_CONTROL             0xD8
+#define WM8350_OSC_CONTROL                      0xD9
+#define WM8350_RTC_TICK_CONTROL                 0xDA
+#define WM8350_SECURITY                         0xDB
+#define WM8350_RAM_BIST_1                       0xDC
+#define WM8350_DCDC_LDO_STATUS                  0xE1
+#define WM8350_GPIO_PIN_STATUS                  0xE6
+
+#define WM8350_DCDC1_FORCE_PWM                  0xF8
+#define WM8350_DCDC3_FORCE_PWM                  0xFA
+#define WM8350_DCDC4_FORCE_PWM                  0xFB
+#define WM8350_DCDC6_FORCE_PWM                  0xFD
+
+/*
+ * R172 (0xAC) - Current Sink Driver A
+ */
+#define WM8350_CS1_HIB_MODE                     0x1000
+#define WM8350_CS1_HIB_MODE_MASK                0x1000
+#define WM8350_CS1_HIB_MODE_SHIFT                   12
+#define WM8350_CS1_ISEL_MASK                    0x003F
+#define WM8350_CS1_ISEL_SHIFT                        0
+
+/* Bit values for R172 (0xAC) */
+#define WM8350_CS1_HIB_MODE_DISABLE                  0
+#define WM8350_CS1_HIB_MODE_LEAVE                    1
+
+#define WM8350_CS1_ISEL_220M                      0x3F
+
+/*
+ * R173 (0xAD) - CSA Flash control
+ */
+#define WM8350_CS1_FLASH_MODE                   0x8000
+#define WM8350_CS1_TRIGSRC                      0x4000
+#define WM8350_CS1_DRIVE                        0x2000
+#define WM8350_CS1_FLASH_DUR_MASK               0x0300
+#define WM8350_CS1_OFF_RAMP_MASK                0x0030
+#define WM8350_CS1_ON_RAMP_MASK                 0x0003
+
+/*
+ * R174 (0xAE) - Current Sink Driver B
+ */
+#define WM8350_CS2_HIB_MODE                     0x1000
+#define WM8350_CS2_ISEL_MASK                    0x003F
+
+/*
+ * R175 (0xAF) - CSB Flash control
+ */
+#define WM8350_CS2_FLASH_MODE                   0x8000
+#define WM8350_CS2_TRIGSRC                      0x4000
+#define WM8350_CS2_DRIVE                        0x2000
+#define WM8350_CS2_FLASH_DUR_MASK               0x0300
+#define WM8350_CS2_OFF_RAMP_MASK                0x0030
+#define WM8350_CS2_ON_RAMP_MASK                 0x0003
+
+/*
+ * R176 (0xB0) - DCDC/LDO requested
+ */
+#define WM8350_LS_ENA                           0x8000
+#define WM8350_LDO4_ENA                         0x0800
+#define WM8350_LDO3_ENA                         0x0400
+#define WM8350_LDO2_ENA                         0x0200
+#define WM8350_LDO1_ENA                         0x0100
+#define WM8350_DC6_ENA                          0x0020
+#define WM8350_DC5_ENA                          0x0010
+#define WM8350_DC4_ENA                          0x0008
+#define WM8350_DC3_ENA                          0x0004
+#define WM8350_DC2_ENA                          0x0002
+#define WM8350_DC1_ENA                          0x0001
+
+/*
+ * R177 (0xB1) - DCDC Active options
+ */
+#define WM8350_PUTO_MASK                        0x3000
+#define WM8350_PWRUP_DELAY_MASK                 0x0300
+#define WM8350_DC6_ACTIVE                       0x0020
+#define WM8350_DC4_ACTIVE                       0x0008
+#define WM8350_DC3_ACTIVE                       0x0004
+#define WM8350_DC1_ACTIVE                       0x0001
+
+/*
+ * R178 (0xB2) - DCDC Sleep options
+ */
+#define WM8350_DC6_SLEEP                        0x0020
+#define WM8350_DC4_SLEEP                        0x0008
+#define WM8350_DC3_SLEEP                        0x0004
+#define WM8350_DC1_SLEEP                        0x0001
+
+/*
+ * R179 (0xB3) - Power-check comparator
+ */
+#define WM8350_PCCMP_ERRACT                     0x4000
+#define WM8350_PCCMP_RAIL                       0x0100
+#define WM8350_PCCMP_OFF_THR_MASK               0x0070
+#define WM8350_PCCMP_ON_THR_MASK                0x0007
+
+/*
+ * R180 (0xB4) - DCDC1 Control
+ */
+#define WM8350_DC1_OPFLT                        0x0400
+#define WM8350_DC1_VSEL_MASK                    0x007F
+#define WM8350_DC1_VSEL_SHIFT                        0
+
+/*
+ * R181 (0xB5) - DCDC1 Timeouts
+ */
+#define WM8350_DC1_ERRACT_MASK                  0xC000
+#define WM8350_DC1_ERRACT_SHIFT                     14
+#define WM8350_DC1_ENSLOT_MASK                  0x3C00
+#define WM8350_DC1_ENSLOT_SHIFT                     10
+#define WM8350_DC1_SDSLOT_MASK                  0x03C0
+#define WM8350_DC1_UVTO_MASK                    0x0030
+#define WM8350_DC1_SDSLOT_SHIFT                      6
+
+/* Bit values for R181 (0xB5) */
+#define WM8350_DC1_ERRACT_NONE                       0
+#define WM8350_DC1_ERRACT_SHUTDOWN_CONV              1
+#define WM8350_DC1_ERRACT_SHUTDOWN_SYS               2
+
+/*
+ * R182 (0xB6) - DCDC1 Low Power
+ */
+#define WM8350_DC1_HIB_MODE_MASK                0x7000
+#define WM8350_DC1_HIB_TRIG_MASK                0x0300
+#define WM8350_DC1_VIMG_MASK                    0x007F
+
+/*
+ * R183 (0xB7) - DCDC2 Control
+ */
+#define WM8350_DC2_MODE                         0x4000
+#define WM8350_DC2_MODE_MASK                    0x4000
+#define WM8350_DC2_MODE_SHIFT                       14
+#define WM8350_DC2_HIB_MODE                     0x1000
+#define WM8350_DC2_HIB_MODE_MASK                0x1000
+#define WM8350_DC2_HIB_MODE_SHIFT                   12
+#define WM8350_DC2_HIB_TRIG_MASK                0x0300
+#define WM8350_DC2_HIB_TRIG_SHIFT                    8
+#define WM8350_DC2_ILIM                         0x0040
+#define WM8350_DC2_ILIM_MASK                    0x0040
+#define WM8350_DC2_ILIM_SHIFT                        6
+#define WM8350_DC2_RMP_MASK                     0x0018
+#define WM8350_DC2_RMP_SHIFT                         3
+#define WM8350_DC2_FBSRC_MASK                   0x0003
+#define WM8350_DC2_FBSRC_SHIFT                       0
+
+/* Bit values for R183 (0xB7) */
+#define WM8350_DC2_MODE_BOOST                        0
+#define WM8350_DC2_MODE_SWITCH                       1
+
+#define WM8350_DC2_HIB_MODE_ACTIVE                   1
+#define WM8350_DC2_HIB_MODE_DISABLE                  0
+
+#define WM8350_DC2_HIB_TRIG_NONE                     0
+#define WM8350_DC2_HIB_TRIG_LPWR1                    1
+#define WM8350_DC2_HIB_TRIG_LPWR2                    2
+#define WM8350_DC2_HIB_TRIG_LPWR3                    3
+
+#define WM8350_DC2_ILIM_HIGH                         0
+#define WM8350_DC2_ILIM_LOW                          1
+
+#define WM8350_DC2_RMP_30V                           0
+#define WM8350_DC2_RMP_20V                           1
+#define WM8350_DC2_RMP_10V                           2
+#define WM8350_DC2_RMP_5V                            3
+
+#define WM8350_DC2_FBSRC_FB2                         0
+#define WM8350_DC2_FBSRC_ISINKA                      1
+#define WM8350_DC2_FBSRC_ISINKB                      2
+#define WM8350_DC2_FBSRC_USB                         3
+
+/*
+ * R184 (0xB8) - DCDC2 Timeouts
+ */
+#define WM8350_DC2_ERRACT_MASK                  0xC000
+#define WM8350_DC2_ERRACT_SHIFT                     14
+#define WM8350_DC2_ENSLOT_MASK                  0x3C00
+#define WM8350_DC2_ENSLOT_SHIFT                     10
+#define WM8350_DC2_SDSLOT_MASK                  0x03C0
+#define WM8350_DC2_UVTO_MASK                    0x0030
+
+/* Bit values for R184 (0xB8) */
+#define WM8350_DC2_ERRACT_NONE                       0
+#define WM8350_DC2_ERRACT_SHUTDOWN_CONV              1
+#define WM8350_DC2_ERRACT_SHUTDOWN_SYS               2
+
+/*
+ * R186 (0xBA) - DCDC3 Control
+ */
+#define WM8350_DC3_OPFLT                        0x0400
+#define WM8350_DC3_VSEL_MASK                    0x007F
+#define WM8350_DC3_VSEL_SHIFT                        0
+
+/*
+ * R187 (0xBB) - DCDC3 Timeouts
+ */
+#define WM8350_DC3_ERRACT_MASK                  0xC000
+#define WM8350_DC3_ERRACT_SHIFT                     14
+#define WM8350_DC3_ENSLOT_MASK                  0x3C00
+#define WM8350_DC3_ENSLOT_SHIFT                     10
+#define WM8350_DC3_SDSLOT_MASK                  0x03C0
+#define WM8350_DC3_UVTO_MASK                    0x0030
+#define WM8350_DC3_SDSLOT_SHIFT                      6
+
+/* Bit values for R187 (0xBB) */
+#define WM8350_DC3_ERRACT_NONE                       0
+#define WM8350_DC3_ERRACT_SHUTDOWN_CONV              1
+#define WM8350_DC3_ERRACT_SHUTDOWN_SYS               2
+/*
+ * R188 (0xBC) - DCDC3 Low Power
+ */
+#define WM8350_DC3_HIB_MODE_MASK                0x7000
+#define WM8350_DC3_HIB_TRIG_MASK                0x0300
+#define WM8350_DC3_VIMG_MASK                    0x007F
+
+/*
+ * R189 (0xBD) - DCDC4 Control
+ */
+#define WM8350_DC4_OPFLT                        0x0400
+#define WM8350_DC4_VSEL_MASK                    0x007F
+#define WM8350_DC4_VSEL_SHIFT                        0
+
+/*
+ * R190 (0xBE) - DCDC4 Timeouts
+ */
+#define WM8350_DC4_ERRACT_MASK                  0xC000
+#define WM8350_DC4_ERRACT_SHIFT                     14
+#define WM8350_DC4_ENSLOT_MASK                  0x3C00
+#define WM8350_DC4_ENSLOT_SHIFT                     10
+#define WM8350_DC4_SDSLOT_MASK                  0x03C0
+#define WM8350_DC4_UVTO_MASK                    0x0030
+#define WM8350_DC4_SDSLOT_SHIFT                      6
+
+/* Bit values for R190 (0xBE) */
+#define WM8350_DC4_ERRACT_NONE                       0
+#define WM8350_DC4_ERRACT_SHUTDOWN_CONV              1
+#define WM8350_DC4_ERRACT_SHUTDOWN_SYS               2
+
+/*
+ * R191 (0xBF) - DCDC4 Low Power
+ */
+#define WM8350_DC4_HIB_MODE_MASK                0x7000
+#define WM8350_DC4_HIB_TRIG_MASK                0x0300
+#define WM8350_DC4_VIMG_MASK                    0x007F
+
+/*
+ * R192 (0xC0) - DCDC5 Control
+ */
+#define WM8350_DC5_MODE                         0x4000
+#define WM8350_DC5_MODE_MASK                    0x4000
+#define WM8350_DC5_MODE_SHIFT                       14
+#define WM8350_DC5_HIB_MODE                     0x1000
+#define WM8350_DC5_HIB_MODE_MASK                0x1000
+#define WM8350_DC5_HIB_MODE_SHIFT                   12
+#define WM8350_DC5_HIB_TRIG_MASK                0x0300
+#define WM8350_DC5_HIB_TRIG_SHIFT                    8
+#define WM8350_DC5_ILIM                         0x0040
+#define WM8350_DC5_ILIM_MASK                    0x0040
+#define WM8350_DC5_ILIM_SHIFT                        6
+#define WM8350_DC5_RMP_MASK                     0x0018
+#define WM8350_DC5_RMP_SHIFT                         3
+#define WM8350_DC5_FBSRC_MASK                   0x0003
+#define WM8350_DC5_FBSRC_SHIFT                       0
+
+/* Bit values for R192 (0xC0) */
+#define WM8350_DC5_MODE_BOOST                        0
+#define WM8350_DC5_MODE_SWITCH                       1
+
+#define WM8350_DC5_HIB_MODE_ACTIVE                   1
+#define WM8350_DC5_HIB_MODE_DISABLE                  0
+
+#define WM8350_DC5_HIB_TRIG_NONE                     0
+#define WM8350_DC5_HIB_TRIG_LPWR1                    1
+#define WM8350_DC5_HIB_TRIG_LPWR2                    2
+#define WM8350_DC5_HIB_TRIG_LPWR3                    3
+
+#define WM8350_DC5_ILIM_HIGH                         0
+#define WM8350_DC5_ILIM_LOW                          1
+
+#define WM8350_DC5_RMP_30V                           0
+#define WM8350_DC5_RMP_20V                           1
+#define WM8350_DC5_RMP_10V                           2
+#define WM8350_DC5_RMP_5V                            3
+
+#define WM8350_DC5_FBSRC_FB2                         0
+#define WM8350_DC5_FBSRC_ISINKA                      1
+#define WM8350_DC5_FBSRC_ISINKB                      2
+#define WM8350_DC5_FBSRC_USB                         3
+
+/*
+ * R193 (0xC1) - DCDC5 Timeouts
+ */
+#define WM8350_DC5_ERRACT_MASK                  0xC000
+#define WM8350_DC5_ERRACT_SHIFT                     14
+#define WM8350_DC5_ENSLOT_MASK                  0x3C00
+#define WM8350_DC5_ENSLOT_SHIFT                     10
+#define WM8350_DC5_SDSLOT_MASK                  0x03C0
+#define WM8350_DC5_UVTO_MASK                    0x0030
+#define WM8350_DC5_SDSLOT_SHIFT                      6
+
+/* Bit values for R193 (0xC1) */
+#define WM8350_DC5_ERRACT_NONE                       0
+#define WM8350_DC5_ERRACT_SHUTDOWN_CONV              1
+#define WM8350_DC5_ERRACT_SHUTDOWN_SYS               2
+
+/*
+ * R195 (0xC3) - DCDC6 Control
+ */
+#define WM8350_DC6_OPFLT                        0x0400
+#define WM8350_DC6_VSEL_MASK                    0x007F
+#define WM8350_DC6_VSEL_SHIFT                        0
+
+/*
+ * R196 (0xC4) - DCDC6 Timeouts
+ */
+#define WM8350_DC6_ERRACT_MASK                  0xC000
+#define WM8350_DC6_ERRACT_SHIFT                     14
+#define WM8350_DC6_ENSLOT_MASK                  0x3C00
+#define WM8350_DC6_ENSLOT_SHIFT                     10
+#define WM8350_DC6_SDSLOT_MASK                  0x03C0
+#define WM8350_DC6_UVTO_MASK                    0x0030
+#define WM8350_DC6_SDSLOT_SHIFT                      6
+
+/* Bit values for R196 (0xC4) */
+#define WM8350_DC6_ERRACT_NONE                       0
+#define WM8350_DC6_ERRACT_SHUTDOWN_CONV              1
+#define WM8350_DC6_ERRACT_SHUTDOWN_SYS               2
+
+/*
+ * R197 (0xC5) - DCDC6 Low Power
+ */
+#define WM8350_DC6_HIB_MODE_MASK                0x7000
+#define WM8350_DC6_HIB_TRIG_MASK                0x0300
+#define WM8350_DC6_VIMG_MASK                    0x007F
+
+/*
+ * R199 (0xC7) - Limit Switch Control
+ */
+#define WM8350_LS_ERRACT_MASK                   0xC000
+#define WM8350_LS_ERRACT_SHIFT                      14
+#define WM8350_LS_ENSLOT_MASK                   0x3C00
+#define WM8350_LS_ENSLOT_SHIFT                      10
+#define WM8350_LS_SDSLOT_MASK                   0x03C0
+#define WM8350_LS_SDSLOT_SHIFT                       6
+#define WM8350_LS_HIB_MODE                      0x0010
+#define WM8350_LS_HIB_MODE_MASK                 0x0010
+#define WM8350_LS_HIB_MODE_SHIFT                     4
+#define WM8350_LS_HIB_PROT                      0x0002
+#define WM8350_LS_HIB_PROT_MASK                 0x0002
+#define WM8350_LS_HIB_PROT_SHIFT                     1
+#define WM8350_LS_PROT                          0x0001
+#define WM8350_LS_PROT_MASK                     0x0001
+#define WM8350_LS_PROT_SHIFT                         0
+
+/* Bit values for R199 (0xC7) */
+#define WM8350_LS_ERRACT_NONE                       0
+#define WM8350_LS_ERRACT_SHUTDOWN_CONV              1
+#define WM8350_LS_ERRACT_SHUTDOWN_SYS               2
+
+/*
+ * R200 (0xC8) - LDO1 Control
+ */
+#define WM8350_LDO1_SWI                         0x4000
+#define WM8350_LDO1_OPFLT                       0x0400
+#define WM8350_LDO1_VSEL_MASK                   0x001F
+#define WM8350_LDO1_VSEL_SHIFT                       0
+
+/*
+ * R201 (0xC9) - LDO1 Timeouts
+ */
+#define WM8350_LDO1_ERRACT_MASK                 0xC000
+#define WM8350_LDO1_ERRACT_SHIFT                    14
+#define WM8350_LDO1_ENSLOT_MASK                 0x3C00
+#define WM8350_LDO1_ENSLOT_SHIFT                    10
+#define WM8350_LDO1_SDSLOT_MASK                 0x03C0
+#define WM8350_LDO1_UVTO_MASK                   0x0030
+#define WM8350_LDO1_SDSLOT_SHIFT                     6
+
+/* Bit values for R201 (0xC9) */
+#define WM8350_LDO1_ERRACT_NONE                       0
+#define WM8350_LDO1_ERRACT_SHUTDOWN_CONV              1
+#define WM8350_LDO1_ERRACT_SHUTDOWN_SYS               2
+
+/*
+ * R202 (0xCA) - LDO1 Low Power
+ */
+#define WM8350_LDO1_HIB_MODE_MASK               0x3000
+#define WM8350_LDO1_HIB_TRIG_MASK               0x0300
+#define WM8350_LDO1_VIMG_MASK                   0x001F
+#define WM8350_LDO1_HIB_MODE_DIS		(0x1 << 12)
+
+
+/*
+ * R203 (0xCB) - LDO2 Control
+ */
+#define WM8350_LDO2_SWI                         0x4000
+#define WM8350_LDO2_OPFLT                       0x0400
+#define WM8350_LDO2_VSEL_MASK                   0x001F
+#define WM8350_LDO2_VSEL_SHIFT                       0
+
+/*
+ * R204 (0xCC) - LDO2 Timeouts
+ */
+#define WM8350_LDO2_ERRACT_MASK                 0xC000
+#define WM8350_LDO2_ERRACT_SHIFT                    14
+#define WM8350_LDO2_ENSLOT_MASK                 0x3C00
+#define WM8350_LDO2_ENSLOT_SHIFT                    10
+#define WM8350_LDO2_SDSLOT_MASK                 0x03C0
+#define WM8350_LDO2_SDSLOT_SHIFT                     6
+
+/* Bit values for R204 (0xCC) */
+#define WM8350_LDO2_ERRACT_NONE                       0
+#define WM8350_LDO2_ERRACT_SHUTDOWN_CONV              1
+#define WM8350_LDO2_ERRACT_SHUTDOWN_SYS               2
+
+/*
+ * R205 (0xCD) - LDO2 Low Power
+ */
+#define WM8350_LDO2_HIB_MODE_MASK               0x3000
+#define WM8350_LDO2_HIB_TRIG_MASK               0x0300
+#define WM8350_LDO2_VIMG_MASK                   0x001F
+
+/*
+ * R206 (0xCE) - LDO3 Control
+ */
+#define WM8350_LDO3_SWI                         0x4000
+#define WM8350_LDO3_OPFLT                       0x0400
+#define WM8350_LDO3_VSEL_MASK                   0x001F
+#define WM8350_LDO3_VSEL_SHIFT                       0
+
+/*
+ * R207 (0xCF) - LDO3 Timeouts
+ */
+#define WM8350_LDO3_ERRACT_MASK                 0xC000
+#define WM8350_LDO3_ERRACT_SHIFT                    14
+#define WM8350_LDO3_ENSLOT_MASK                 0x3C00
+#define WM8350_LDO3_ENSLOT_SHIFT                    10
+#define WM8350_LDO3_SDSLOT_MASK                 0x03C0
+#define WM8350_LDO3_UVTO_MASK                   0x0030
+#define WM8350_LDO3_SDSLOT_SHIFT                     6
+
+/* Bit values for R207 (0xCF) */
+#define WM8350_LDO3_ERRACT_NONE                       0
+#define WM8350_LDO3_ERRACT_SHUTDOWN_CONV              1
+#define WM8350_LDO3_ERRACT_SHUTDOWN_SYS               2
+
+/*
+ * R208 (0xD0) - LDO3 Low Power
+ */
+#define WM8350_LDO3_HIB_MODE_MASK               0x3000
+#define WM8350_LDO3_HIB_TRIG_MASK               0x0300
+#define WM8350_LDO3_VIMG_MASK                   0x001F
+
+/*
+ * R209 (0xD1) - LDO4 Control
+ */
+#define WM8350_LDO4_SWI                         0x4000
+#define WM8350_LDO4_OPFLT                       0x0400
+#define WM8350_LDO4_VSEL_MASK                   0x001F
+#define WM8350_LDO4_VSEL_SHIFT                       0
+
+/*
+ * R210 (0xD2) - LDO4 Timeouts
+ */
+#define WM8350_LDO4_ERRACT_MASK                 0xC000
+#define WM8350_LDO4_ERRACT_SHIFT                    14
+#define WM8350_LDO4_ENSLOT_MASK                 0x3C00
+#define WM8350_LDO4_ENSLOT_SHIFT                    10
+#define WM8350_LDO4_SDSLOT_MASK                 0x03C0
+#define WM8350_LDO4_UVTO_MASK                   0x0030
+#define WM8350_LDO4_SDSLOT_SHIFT                     6
+
+/* Bit values for R210 (0xD2) */
+#define WM8350_LDO4_ERRACT_NONE                       0
+#define WM8350_LDO4_ERRACT_SHUTDOWN_CONV              1
+#define WM8350_LDO4_ERRACT_SHUTDOWN_SYS               2
+
+/*
+ * R211 (0xD3) - LDO4 Low Power
+ */
+#define WM8350_LDO4_HIB_MODE_MASK               0x3000
+#define WM8350_LDO4_HIB_TRIG_MASK               0x0300
+#define WM8350_LDO4_VIMG_MASK                   0x001F
+
+/*
+ * R215 (0xD7) - VCC_FAULT Masks
+ */
+#define WM8350_LS_FAULT                         0x8000
+#define WM8350_LDO4_FAULT                       0x0800
+#define WM8350_LDO3_FAULT                       0x0400
+#define WM8350_LDO2_FAULT                       0x0200
+#define WM8350_LDO1_FAULT                       0x0100
+#define WM8350_DC6_FAULT                        0x0020
+#define WM8350_DC5_FAULT                        0x0010
+#define WM8350_DC4_FAULT                        0x0008
+#define WM8350_DC3_FAULT                        0x0004
+#define WM8350_DC2_FAULT                        0x0002
+#define WM8350_DC1_FAULT                        0x0001
+
+/*
+ * R216 (0xD8) - Main Bandgap Control
+ */
+#define WM8350_MBG_LOAD_FUSES                   0x8000
+#define WM8350_MBG_FUSE_WPREP                   0x4000
+#define WM8350_MBG_FUSE_WRITE                   0x2000
+#define WM8350_MBG_FUSE_TRIM_MASK               0x1F00
+#define WM8350_MBG_TRIM_SRC                     0x0020
+#define WM8350_MBG_USER_TRIM_MASK               0x001F
+
+/*
+ * R217 (0xD9) - OSC Control
+ */
+#define WM8350_OSC_LOAD_FUSES                   0x8000
+#define WM8350_OSC_FUSE_WPREP                   0x4000
+#define WM8350_OSC_FUSE_WRITE                   0x2000
+#define WM8350_OSC_FUSE_TRIM_MASK               0x0F00
+#define WM8350_OSC_TRIM_SRC                     0x0020
+#define WM8350_OSC_USER_TRIM_MASK               0x000F
+
+/*
+ * R248 (0xF8) - DCDC1 Force PWM
+ */
+#define WM8350_DCDC1_FORCE_PWM_ENA              0x0010
+
+/*
+ * R250 (0xFA) - DCDC3 Force PWM
+ */
+#define WM8350_DCDC3_FORCE_PWM_ENA              0x0010
+
+/*
+ * R251 (0xFB) - DCDC4 Force PWM
+ */
+#define WM8350_DCDC4_FORCE_PWM_ENA              0x0010
+
+/*
+ * R253 (0xFD) - DCDC1 Force PWM
+ */
+#define WM8350_DCDC6_FORCE_PWM_ENA              0x0010
+
+/*
+ * DCDC's
+ */
+#define WM8350_DCDC_1				0
+#define WM8350_DCDC_2				1
+#define WM8350_DCDC_3				2
+#define WM8350_DCDC_4				3
+#define WM8350_DCDC_5				4
+#define WM8350_DCDC_6				5
+
+/* DCDC modes */
+#define WM8350_DCDC_ACTIVE_STANDBY		0
+#define WM8350_DCDC_ACTIVE_PULSE		1
+#define WM8350_DCDC_SLEEP_NORMAL		0
+#define WM8350_DCDC_SLEEP_LOW			1
+
+/* DCDC Low power (Hibernate) mode */
+#define WM8350_DCDC_HIB_MODE_CUR		(0 << 12)
+#define WM8350_DCDC_HIB_MODE_IMAGE		(1 << 12)
+#define WM8350_DCDC_HIB_MODE_STANDBY		(2 << 12)
+#define WM8350_DCDC_HIB_MODE_LDO		(4 << 12)
+#define WM8350_DCDC_HIB_MODE_LDO_IM		(5 << 12)
+#define WM8350_DCDC_HIB_MODE_DIS		(7 << 12)
+#define WM8350_DCDC_HIB_MODE_MASK		(7 << 12)
+
+/* DCDC Low Power (Hibernate) signal */
+#define WM8350_DCDC_HIB_SIG_REG			(0 << 8)
+#define WM8350_DCDC_HIB_SIG_LPWR1		(1 << 8)
+#define WM8350_DCDC_HIB_SIG_LPWR2		(2 << 8)
+#define WM8350_DCDC_HIB_SIG_LPWR3		(3 << 8)
+
+/* LDO Low power (Hibernate) mode */
+#define WM8350_LDO_HIB_MODE_IMAGE		(0 << 0)
+#define WM8350_LDO_HIB_MODE_DIS			(1 << 0)
+
+/* LDO Low Power (Hibernate) signal */
+#define WM8350_LDO_HIB_SIG_REG			(0 << 8)
+#define WM8350_LDO_HIB_SIG_LPWR1		(1 << 8)
+#define WM8350_LDO_HIB_SIG_LPWR2		(2 << 8)
+#define WM8350_LDO_HIB_SIG_LPWR3		(3 << 8)
+
+/*
+ * LDOs
+ */
+#define WM8350_LDO_1				6
+#define WM8350_LDO_2				7
+#define WM8350_LDO_3				8
+#define WM8350_LDO_4				9
+
+/*
+ * ISINKs
+ */
+#define WM8350_ISINK_A				10
+#define WM8350_ISINK_B				11
+
+#define WM8350_ISINK_MODE_BOOST			0
+#define WM8350_ISINK_MODE_SWITCH		1
+#define WM8350_ISINK_ILIM_NORMAL		0
+#define WM8350_ISINK_ILIM_LOW			1
+
+#define WM8350_ISINK_FLASH_DISABLE		0
+#define WM8350_ISINK_FLASH_ENABLE		1
+#define WM8350_ISINK_FLASH_TRIG_BIT		0
+#define WM8350_ISINK_FLASH_TRIG_GPIO		1
+#define WM8350_ISINK_FLASH_MODE_EN		(1 << 13)
+#define WM8350_ISINK_FLASH_MODE_DIS		(0 << 13)
+#define WM8350_ISINK_FLASH_DUR_32MS		(0 << 8)
+#define WM8350_ISINK_FLASH_DUR_64MS		(1 << 8)
+#define WM8350_ISINK_FLASH_DUR_96MS		(2 << 8)
+#define WM8350_ISINK_FLASH_DUR_1024MS		(3 << 8)
+#define WM8350_ISINK_FLASH_ON_INSTANT		(0 << 4)
+#define WM8350_ISINK_FLASH_ON_0_25S		(1 << 4)
+#define WM8350_ISINK_FLASH_ON_0_50S		(2 << 4)
+#define WM8350_ISINK_FLASH_ON_1_00S		(3 << 4)
+#define WM8350_ISINK_FLASH_ON_1_95S		(1 << 4)
+#define WM8350_ISINK_FLASH_ON_3_91S		(2 << 4)
+#define WM8350_ISINK_FLASH_ON_7_80S		(3 << 4)
+#define WM8350_ISINK_FLASH_OFF_INSTANT		(0 << 0)
+#define WM8350_ISINK_FLASH_OFF_0_25S		(1 << 0)
+#define WM8350_ISINK_FLASH_OFF_0_50S		(2 << 0)
+#define WM8350_ISINK_FLASH_OFF_1_00S		(3 << 0)
+#define WM8350_ISINK_FLASH_OFF_1_95S		(1 << 0)
+#define WM8350_ISINK_FLASH_OFF_3_91S		(2 << 0)
+#define WM8350_ISINK_FLASH_OFF_7_80S		(3 << 0)
+
+/*
+ * Regulator Interrupts.
+ */
+#define WM8350_IRQ_CS1				13
+#define WM8350_IRQ_CS2				14
+#define WM8350_IRQ_UV_LDO4			25
+#define WM8350_IRQ_UV_LDO3			26
+#define WM8350_IRQ_UV_LDO2			27
+#define WM8350_IRQ_UV_LDO1			28
+#define WM8350_IRQ_UV_DC6			29
+#define WM8350_IRQ_UV_DC5			30
+#define WM8350_IRQ_UV_DC4			31
+#define WM8350_IRQ_UV_DC3			32
+#define WM8350_IRQ_UV_DC2			33
+#define WM8350_IRQ_UV_DC1			34
+#define WM8350_IRQ_OC_LS			35
+
+#define NUM_WM8350_REGULATORS			12
+
+struct wm8350;
+struct platform_device;
+struct regulator_init_data;
+
+struct wm8350_pmic {
+	/* ISINK to DCDC mapping */
+	int isink_A_dcdc;
+	int isink_B_dcdc;
+
+	/* hibernate configs */
+	u16 dcdc1_hib_mode;
+	u16 dcdc3_hib_mode;
+	u16 dcdc4_hib_mode;
+	u16 dcdc6_hib_mode;
+
+	/* regulator devices */
+	struct platform_device *pdev[NUM_WM8350_REGULATORS];
+};
+
+int wm8350_register_regulator(struct wm8350 *wm8350, int reg,
+			      struct regulator_init_data *initdata);
+
+/*
+ * Additional DCDC control not supported via regulator API
+ */
+int wm8350_dcdc_set_slot(struct wm8350 *wm8350, int dcdc, u16 start,
+			 u16 stop, u16 fault);
+int wm8350_dcdc25_set_mode(struct wm8350 *wm8350, int dcdc, u16 mode,
+			   u16 ilim, u16 ramp, u16 feedback);
+
+/*
+ * Additional LDO control not supported via regulator API
+ */
+int wm8350_ldo_set_slot(struct wm8350 *wm8350, int ldo, u16 start, u16 stop);
+
+/*
+ * Additional ISINK control not supported via regulator API
+ */
+int wm8350_isink_set_flash(struct wm8350 *wm8350, int isink, u16 mode,
+			   u16 trigger, u16 duration, u16 on_ramp,
+			   u16 off_ramp, u16 drive);
+
+#endif
diff --git a/include/linux/mfd/wm8350/rtc.h b/include/linux/mfd/wm8350/rtc.h
new file mode 100644
index 0000000..dfda69e
--- /dev/null
+++ b/include/linux/mfd/wm8350/rtc.h
@@ -0,0 +1,266 @@
+/*
+ * rtc.h  --  RTC driver for Wolfson WM8350 PMIC
+ *
+ * Copyright 2007 Wolfson Microelectronics PLC
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ */
+
+#ifndef __LINUX_MFD_WM8350_RTC_H
+#define __LINUX_MFD_WM8350_RTC_H
+
+#include <linux/platform_device.h>
+
+/*
+ * Register values.
+ */
+#define WM8350_RTC_SECONDS_MINUTES              0x10
+#define WM8350_RTC_HOURS_DAY                    0x11
+#define WM8350_RTC_DATE_MONTH                   0x12
+#define WM8350_RTC_YEAR                         0x13
+#define WM8350_ALARM_SECONDS_MINUTES            0x14
+#define WM8350_ALARM_HOURS_DAY                  0x15
+#define WM8350_ALARM_DATE_MONTH                 0x16
+#define WM8350_RTC_TIME_CONTROL                 0x17
+
+/*
+ * R16 (0x10) - RTC Seconds/Minutes
+ */
+#define WM8350_RTC_MINS_MASK                    0x7F00
+#define WM8350_RTC_MINS_SHIFT                        8
+#define WM8350_RTC_SECS_MASK                    0x007F
+#define WM8350_RTC_SECS_SHIFT                        0
+
+/*
+ * R17 (0x11) - RTC Hours/Day
+ */
+#define WM8350_RTC_DAY_MASK                     0x0700
+#define WM8350_RTC_DAY_SHIFT                         8
+#define WM8350_RTC_HPM_MASK                     0x0020
+#define WM8350_RTC_HPM_SHIFT                         5
+#define WM8350_RTC_HRS_MASK                     0x001F
+#define WM8350_RTC_HRS_SHIFT                         0
+
+/* Bit values for R21 (0x15) */
+#define WM8350_RTC_DAY_SUN                           1
+#define WM8350_RTC_DAY_MON                           2
+#define WM8350_RTC_DAY_TUE                           3
+#define WM8350_RTC_DAY_WED                           4
+#define WM8350_RTC_DAY_THU                           5
+#define WM8350_RTC_DAY_FRI                           6
+#define WM8350_RTC_DAY_SAT                           7
+
+#define WM8350_RTC_HPM_AM                            0
+#define WM8350_RTC_HPM_PM                            1
+
+/*
+ * R18 (0x12) - RTC Date/Month
+ */
+#define WM8350_RTC_MTH_MASK                     0x1F00
+#define WM8350_RTC_MTH_SHIFT                         8
+#define WM8350_RTC_DATE_MASK                    0x003F
+#define WM8350_RTC_DATE_SHIFT                        0
+
+/* Bit values for R22 (0x16) */
+#define WM8350_RTC_MTH_JAN                           1
+#define WM8350_RTC_MTH_FEB                           2
+#define WM8350_RTC_MTH_MAR                           3
+#define WM8350_RTC_MTH_APR                           4
+#define WM8350_RTC_MTH_MAY                           5
+#define WM8350_RTC_MTH_JUN                           6
+#define WM8350_RTC_MTH_JUL                           7
+#define WM8350_RTC_MTH_AUG                           8
+#define WM8350_RTC_MTH_SEP                           9
+#define WM8350_RTC_MTH_OCT                          10
+#define WM8350_RTC_MTH_NOV                          11
+#define WM8350_RTC_MTH_DEC                          12
+#define WM8350_RTC_MTH_JAN_BCD                    0x01
+#define WM8350_RTC_MTH_FEB_BCD                    0x02
+#define WM8350_RTC_MTH_MAR_BCD                    0x03
+#define WM8350_RTC_MTH_APR_BCD                    0x04
+#define WM8350_RTC_MTH_MAY_BCD                    0x05
+#define WM8350_RTC_MTH_JUN_BCD                    0x06
+#define WM8350_RTC_MTH_JUL_BCD                    0x07
+#define WM8350_RTC_MTH_AUG_BCD                    0x08
+#define WM8350_RTC_MTH_SEP_BCD                    0x09
+#define WM8350_RTC_MTH_OCT_BCD                    0x10
+#define WM8350_RTC_MTH_NOV_BCD                    0x11
+#define WM8350_RTC_MTH_DEC_BCD                    0x12
+
+/*
+ * R19 (0x13) - RTC Year
+ */
+#define WM8350_RTC_YHUNDREDS_MASK               0x3F00
+#define WM8350_RTC_YHUNDREDS_SHIFT                   8
+#define WM8350_RTC_YUNITS_MASK                  0x00FF
+#define WM8350_RTC_YUNITS_SHIFT                      0
+
+/*
+ * R20 (0x14) - Alarm Seconds/Minutes
+ */
+#define WM8350_RTC_ALMMINS_MASK                 0x7F00
+#define WM8350_RTC_ALMMINS_SHIFT                     8
+#define WM8350_RTC_ALMSECS_MASK                 0x007F
+#define WM8350_RTC_ALMSECS_SHIFT                     0
+
+/* Bit values for R20 (0x14) */
+#define WM8350_RTC_ALMMINS_DONT_CARE                -1
+#define WM8350_RTC_ALMSECS_DONT_CARE                -1
+
+/*
+ * R21 (0x15) - Alarm Hours/Day
+ */
+#define WM8350_RTC_ALMDAY_MASK                  0x0F00
+#define WM8350_RTC_ALMDAY_SHIFT                      8
+#define WM8350_RTC_ALMHPM_MASK                  0x0020
+#define WM8350_RTC_ALMHPM_SHIFT                      5
+#define WM8350_RTC_ALMHRS_MASK                  0x001F
+#define WM8350_RTC_ALMHRS_SHIFT                      0
+
+/* Bit values for R21 (0x15) */
+#define WM8350_RTC_ALMDAY_DONT_CARE                 -1
+#define WM8350_RTC_ALMDAY_SUN                        1
+#define WM8350_RTC_ALMDAY_MON                        2
+#define WM8350_RTC_ALMDAY_TUE                        3
+#define WM8350_RTC_ALMDAY_WED                        4
+#define WM8350_RTC_ALMDAY_THU                        5
+#define WM8350_RTC_ALMDAY_FRI                        6
+#define WM8350_RTC_ALMDAY_SAT                        7
+
+#define WM8350_RTC_ALMHPM_AM                         0
+#define WM8350_RTC_ALMHPM_PM                         1
+
+#define WM8350_RTC_ALMHRS_DONT_CARE                 -1
+
+/*
+ * R22 (0x16) - Alarm Date/Month
+ */
+#define WM8350_RTC_ALMMTH_MASK                  0x1F00
+#define WM8350_RTC_ALMMTH_SHIFT                      8
+#define WM8350_RTC_ALMDATE_MASK                 0x003F
+#define WM8350_RTC_ALMDATE_SHIFT                     0
+
+/* Bit values for R22 (0x16) */
+#define WM8350_RTC_ALMDATE_DONT_CARE                -1
+
+#define WM8350_RTC_ALMMTH_DONT_CARE                 -1
+#define WM8350_RTC_ALMMTH_JAN                        1
+#define WM8350_RTC_ALMMTH_FEB                        2
+#define WM8350_RTC_ALMMTH_MAR                        3
+#define WM8350_RTC_ALMMTH_APR                        4
+#define WM8350_RTC_ALMMTH_MAY                        5
+#define WM8350_RTC_ALMMTH_JUN                        6
+#define WM8350_RTC_ALMMTH_JUL                        7
+#define WM8350_RTC_ALMMTH_AUG                        8
+#define WM8350_RTC_ALMMTH_SEP                        9
+#define WM8350_RTC_ALMMTH_OCT                       10
+#define WM8350_RTC_ALMMTH_NOV                       11
+#define WM8350_RTC_ALMMTH_DEC                       12
+#define WM8350_RTC_ALMMTH_JAN_BCD                 0x01
+#define WM8350_RTC_ALMMTH_FEB_BCD                 0x02
+#define WM8350_RTC_ALMMTH_MAR_BCD                 0x03
+#define WM8350_RTC_ALMMTH_APR_BCD                 0x04
+#define WM8350_RTC_ALMMTH_MAY_BCD                 0x05
+#define WM8350_RTC_ALMMTH_JUN_BCD                 0x06
+#define WM8350_RTC_ALMMTH_JUL_BCD                 0x07
+#define WM8350_RTC_ALMMTH_AUG_BCD                 0x08
+#define WM8350_RTC_ALMMTH_SEP_BCD                 0x09
+#define WM8350_RTC_ALMMTH_OCT_BCD                 0x10
+#define WM8350_RTC_ALMMTH_NOV_BCD                 0x11
+#define WM8350_RTC_ALMMTH_DEC_BCD                 0x12
+
+/*
+ * R23 (0x17) - RTC Time Control
+ */
+#define WM8350_RTC_BCD                          0x8000
+#define WM8350_RTC_BCD_MASK                     0x8000
+#define WM8350_RTC_BCD_SHIFT                        15
+#define WM8350_RTC_12HR                         0x4000
+#define WM8350_RTC_12HR_MASK                    0x4000
+#define WM8350_RTC_12HR_SHIFT                       14
+#define WM8350_RTC_DST                          0x2000
+#define WM8350_RTC_DST_MASK                     0x2000
+#define WM8350_RTC_DST_SHIFT                        13
+#define WM8350_RTC_SET                          0x0800
+#define WM8350_RTC_SET_MASK                     0x0800
+#define WM8350_RTC_SET_SHIFT                        11
+#define WM8350_RTC_STS                          0x0400
+#define WM8350_RTC_STS_MASK                     0x0400
+#define WM8350_RTC_STS_SHIFT                        10
+#define WM8350_RTC_ALMSET                       0x0200
+#define WM8350_RTC_ALMSET_MASK                  0x0200
+#define WM8350_RTC_ALMSET_SHIFT                      9
+#define WM8350_RTC_ALMSTS                       0x0100
+#define WM8350_RTC_ALMSTS_MASK                  0x0100
+#define WM8350_RTC_ALMSTS_SHIFT                      8
+#define WM8350_RTC_PINT                         0x0070
+#define WM8350_RTC_PINT_MASK                    0x0070
+#define WM8350_RTC_PINT_SHIFT                        4
+#define WM8350_RTC_DSW                          0x000F
+#define WM8350_RTC_DSW_MASK                     0x000F
+#define WM8350_RTC_DSW_SHIFT                         0
+
+/* Bit values for R23 (0x17) */
+#define WM8350_RTC_BCD_BINARY                        0
+#define WM8350_RTC_BCD_BCD                           1
+
+#define WM8350_RTC_12HR_24HR                         0
+#define WM8350_RTC_12HR_12HR                         1
+
+#define WM8350_RTC_DST_DISABLED                      0
+#define WM8350_RTC_DST_ENABLED                       1
+
+#define WM8350_RTC_SET_RUN                           0
+#define WM8350_RTC_SET_SET                           1
+
+#define WM8350_RTC_STS_RUNNING                       0
+#define WM8350_RTC_STS_STOPPED                       1
+
+#define WM8350_RTC_ALMSET_RUN                        0
+#define WM8350_RTC_ALMSET_SET                        1
+
+#define WM8350_RTC_ALMSTS_RUNNING                    0
+#define WM8350_RTC_ALMSTS_STOPPED                    1
+
+#define WM8350_RTC_PINT_DISABLED                     0
+#define WM8350_RTC_PINT_SECS                         1
+#define WM8350_RTC_PINT_MINS                         2
+#define WM8350_RTC_PINT_HRS                          3
+#define WM8350_RTC_PINT_DAYS                         4
+#define WM8350_RTC_PINT_MTHS                         5
+
+#define WM8350_RTC_DSW_DISABLED                      0
+#define WM8350_RTC_DSW_1HZ                           1
+#define WM8350_RTC_DSW_2HZ                           2
+#define WM8350_RTC_DSW_4HZ                           3
+#define WM8350_RTC_DSW_8HZ                           4
+#define WM8350_RTC_DSW_16HZ                          5
+#define WM8350_RTC_DSW_32HZ                          6
+#define WM8350_RTC_DSW_64HZ                          7
+#define WM8350_RTC_DSW_128HZ                         8
+#define WM8350_RTC_DSW_256HZ                         9
+#define WM8350_RTC_DSW_512HZ                        10
+#define WM8350_RTC_DSW_1024HZ                       11
+
+/*
+ * R218 (0xDA) - RTC Tick Control
+ */
+#define WM8350_RTC_TICKSTS                      0x4000
+#define WM8350_RTC_CLKSRC                       0x2000
+#define WM8350_RTC_TRIM_MASK                    0x03FF
+
+/*
+ * RTC Interrupts.
+ */
+#define WM8350_IRQ_RTC_PER			7
+#define WM8350_IRQ_RTC_SEC			8
+#define WM8350_IRQ_RTC_ALM			9
+
+struct wm8350_rtc {
+	struct platform_device *pdev;
+};
+
+#endif
diff --git a/include/linux/mfd/wm8350/supply.h b/include/linux/mfd/wm8350/supply.h
new file mode 100644
index 0000000..1c8f3cd
--- /dev/null
+++ b/include/linux/mfd/wm8350/supply.h
@@ -0,0 +1,111 @@
+/*
+ * supply.h  --  Power Supply Driver for Wolfson WM8350 PMIC
+ *
+ * Copyright 2007 Wolfson Microelectronics PLC
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ */
+
+#ifndef __LINUX_MFD_WM8350_SUPPLY_H_
+#define __LINUX_MFD_WM8350_SUPPLY_H_
+
+#include <linux/platform_device.h>
+
+/*
+ * Charger registers
+ */
+#define WM8350_BATTERY_CHARGER_CONTROL_1        0xA8
+#define WM8350_BATTERY_CHARGER_CONTROL_2        0xA9
+#define WM8350_BATTERY_CHARGER_CONTROL_3        0xAA
+
+/*
+ * R168 (0xA8) - Battery Charger Control 1
+ */
+#define WM8350_CHG_ENA_R168                     0x8000
+#define WM8350_CHG_THR                          0x2000
+#define WM8350_CHG_EOC_SEL_MASK                 0x1C00
+#define WM8350_CHG_TRICKLE_TEMP_CHOKE           0x0200
+#define WM8350_CHG_TRICKLE_USB_CHOKE            0x0100
+#define WM8350_CHG_RECOVER_T                    0x0080
+#define WM8350_CHG_END_ACT                      0x0040
+#define WM8350_CHG_FAST                         0x0020
+#define WM8350_CHG_FAST_USB_THROTTLE            0x0010
+#define WM8350_CHG_NTC_MON                      0x0008
+#define WM8350_CHG_BATT_HOT_MON                 0x0004
+#define WM8350_CHG_BATT_COLD_MON                0x0002
+#define WM8350_CHG_CHIP_TEMP_MON                0x0001
+
+/*
+ * R169 (0xA9) - Battery Charger Control 2
+ */
+#define WM8350_CHG_ACTIVE                       0x8000
+#define WM8350_CHG_PAUSE                        0x4000
+#define WM8350_CHG_STS_MASK                     0x3000
+#define WM8350_CHG_TIME_MASK                    0x0F00
+#define WM8350_CHG_MASK_WALL_FB                 0x0080
+#define WM8350_CHG_TRICKLE_SEL                  0x0040
+#define WM8350_CHG_VSEL_MASK                    0x0030
+#define WM8350_CHG_ISEL_MASK                    0x000F
+#define WM8350_CHG_STS_OFF                      0x0000
+#define WM8350_CHG_STS_TRICKLE                  0x1000
+#define WM8350_CHG_STS_FAST                     0x2000
+
+/*
+ * R170 (0xAA) - Battery Charger Control 3
+ */
+#define WM8350_CHG_THROTTLE_T_MASK              0x0060
+#define WM8350_CHG_SMART                        0x0010
+#define WM8350_CHG_TIMER_ADJT_MASK              0x000F
+
+/*
+ * Charger Interrupts
+ */
+#define WM8350_IRQ_CHG_BAT_HOT			0
+#define WM8350_IRQ_CHG_BAT_COLD			1
+#define WM8350_IRQ_CHG_BAT_FAIL			2
+#define WM8350_IRQ_CHG_TO			3
+#define WM8350_IRQ_CHG_END			4
+#define WM8350_IRQ_CHG_START			5
+#define WM8350_IRQ_CHG_FAST_RDY			6
+#define WM8350_IRQ_CHG_VBATT_LT_3P9		10
+#define WM8350_IRQ_CHG_VBATT_LT_3P1		11
+#define WM8350_IRQ_CHG_VBATT_LT_2P85		12
+
+/*
+ * Charger Policy
+ */
+#define WM8350_CHG_TRICKLE_50mA			(0 << 6)
+#define WM8350_CHG_TRICKLE_100mA		(1 << 6)
+#define WM8350_CHG_4_05V			(0 << 4)
+#define WM8350_CHG_4_10V			(1 << 4)
+#define WM8350_CHG_4_15V			(2 << 4)
+#define WM8350_CHG_4_20V			(3 << 4)
+#define WM8350_CHG_FAST_LIMIT_mA(x)		((x / 50) & 0xf)
+#define WM8350_CHG_EOC_mA(x)			(((x - 10) & 0x7) << 10)
+#define WM8350_CHG_TRICKLE_3_1V			(0 << 13)
+#define WM8350_CHG_TRICKLE_3_9V			(1 << 13)
+
+/*
+ * Supply Registers.
+ */
+#define WM8350_USB_VOLTAGE_READBACK             0x9C
+#define WM8350_LINE_VOLTAGE_READBACK            0x9D
+#define WM8350_BATT_VOLTAGE_READBACK            0x9E
+
+/*
+ * Supply Interrupts.
+ */
+#define WM8350_IRQ_USB_LIMIT			15
+#define WM8350_IRQ_EXT_USB_FB			36
+#define WM8350_IRQ_EXT_WALL_FB			37
+#define WM8350_IRQ_EXT_BAT_FB			38
+
+struct wm8350_power {
+	struct platform_device *pdev;
+};
+
+#endif
diff --git a/include/linux/mfd/wm8350/wdt.h b/include/linux/mfd/wm8350/wdt.h
new file mode 100644
index 0000000..f6135b5
--- /dev/null
+++ b/include/linux/mfd/wm8350/wdt.h
@@ -0,0 +1,28 @@
+/*
+ * wdt.h  --  Watchdog Driver for Wolfson WM8350 PMIC
+ *
+ * Copyright 2007, 2008 Wolfson Microelectronics PLC
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ */
+
+#ifndef __LINUX_MFD_WM8350_WDT_H_
+#define __LINUX_MFD_WM8350_WDT_H_
+
+#include <linux/platform_device.h>
+
+#define WM8350_WDOG_HIB_MODE                    0x0080
+#define WM8350_WDOG_DEBUG                       0x0040
+#define WM8350_WDOG_MODE_MASK                   0x0030
+#define WM8350_WDOG_TO_MASK                     0x0007
+
+#define WM8350_IRQ_SYS_WDOG_TO			24
+
+struct wm8350_wdt {
+	struct platform_device *pdev;
+};
+
+#endif
diff --git a/include/linux/mfd/wm8400-audio.h b/include/linux/mfd/wm8400-audio.h
new file mode 100644
index 0000000..b6640e0
--- /dev/null
+++ b/include/linux/mfd/wm8400-audio.h
@@ -0,0 +1,1186 @@
+/*
+ * wm8400 private definitions for audio
+ *
+ * Copyright 2008 Wolfson Microelectronics plc
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __LINUX_MFD_WM8400_AUDIO_H
+#define __LINUX_MFD_WM8400_AUDIO_H
+
+#include <linux/mfd/wm8400-audio.h>
+
+/*
+ * R2 (0x02) - Power Management (1)
+ */
+#define WM8400_CODEC_ENA                        0x8000  /* CODEC_ENA */
+#define WM8400_CODEC_ENA_MASK                   0x8000  /* CODEC_ENA */
+#define WM8400_CODEC_ENA_SHIFT                      15  /* CODEC_ENA */
+#define WM8400_CODEC_ENA_WIDTH                       1  /* CODEC_ENA */
+#define WM8400_SYSCLK_ENA                       0x4000  /* SYSCLK_ENA */
+#define WM8400_SYSCLK_ENA_MASK                  0x4000  /* SYSCLK_ENA */
+#define WM8400_SYSCLK_ENA_SHIFT                     14  /* SYSCLK_ENA */
+#define WM8400_SYSCLK_ENA_WIDTH                      1  /* SYSCLK_ENA */
+#define WM8400_SPK_MIX_ENA                      0x2000  /* SPK_MIX_ENA */
+#define WM8400_SPK_MIX_ENA_MASK                 0x2000  /* SPK_MIX_ENA */
+#define WM8400_SPK_MIX_ENA_SHIFT                    13  /* SPK_MIX_ENA */
+#define WM8400_SPK_MIX_ENA_WIDTH                     1  /* SPK_MIX_ENA */
+#define WM8400_SPK_ENA                          0x1000  /* SPK_ENA */
+#define WM8400_SPK_ENA_MASK                     0x1000  /* SPK_ENA */
+#define WM8400_SPK_ENA_SHIFT                        12  /* SPK_ENA */
+#define WM8400_SPK_ENA_WIDTH                         1  /* SPK_ENA */
+#define WM8400_OUT3_ENA                         0x0800  /* OUT3_ENA */
+#define WM8400_OUT3_ENA_MASK                    0x0800  /* OUT3_ENA */
+#define WM8400_OUT3_ENA_SHIFT                       11  /* OUT3_ENA */
+#define WM8400_OUT3_ENA_WIDTH                        1  /* OUT3_ENA */
+#define WM8400_OUT4_ENA                         0x0400  /* OUT4_ENA */
+#define WM8400_OUT4_ENA_MASK                    0x0400  /* OUT4_ENA */
+#define WM8400_OUT4_ENA_SHIFT                       10  /* OUT4_ENA */
+#define WM8400_OUT4_ENA_WIDTH                        1  /* OUT4_ENA */
+#define WM8400_LOUT_ENA                         0x0200  /* LOUT_ENA */
+#define WM8400_LOUT_ENA_MASK                    0x0200  /* LOUT_ENA */
+#define WM8400_LOUT_ENA_SHIFT                        9  /* LOUT_ENA */
+#define WM8400_LOUT_ENA_WIDTH                        1  /* LOUT_ENA */
+#define WM8400_ROUT_ENA                         0x0100  /* ROUT_ENA */
+#define WM8400_ROUT_ENA_MASK                    0x0100  /* ROUT_ENA */
+#define WM8400_ROUT_ENA_SHIFT                        8  /* ROUT_ENA */
+#define WM8400_ROUT_ENA_WIDTH                        1  /* ROUT_ENA */
+#define WM8400_MIC1BIAS_ENA                     0x0010  /* MIC1BIAS_ENA */
+#define WM8400_MIC1BIAS_ENA_MASK                0x0010  /* MIC1BIAS_ENA */
+#define WM8400_MIC1BIAS_ENA_SHIFT                    4  /* MIC1BIAS_ENA */
+#define WM8400_MIC1BIAS_ENA_WIDTH                    1  /* MIC1BIAS_ENA */
+#define WM8400_VMID_MODE_MASK                   0x0006  /* VMID_MODE - [2:1] */
+#define WM8400_VMID_MODE_SHIFT                       1  /* VMID_MODE - [2:1] */
+#define WM8400_VMID_MODE_WIDTH                       2  /* VMID_MODE - [2:1] */
+#define WM8400_VREF_ENA                         0x0001  /* VREF_ENA */
+#define WM8400_VREF_ENA_MASK                    0x0001  /* VREF_ENA */
+#define WM8400_VREF_ENA_SHIFT                        0  /* VREF_ENA */
+#define WM8400_VREF_ENA_WIDTH                        1  /* VREF_ENA */
+
+/*
+ * R3 (0x03) - Power Management (2)
+ */
+#define WM8400_FLL_ENA                          0x8000  /* FLL_ENA */
+#define WM8400_FLL_ENA_MASK                     0x8000  /* FLL_ENA */
+#define WM8400_FLL_ENA_SHIFT                        15  /* FLL_ENA */
+#define WM8400_FLL_ENA_WIDTH                         1  /* FLL_ENA */
+#define WM8400_TSHUT_ENA                        0x4000  /* TSHUT_ENA */
+#define WM8400_TSHUT_ENA_MASK                   0x4000  /* TSHUT_ENA */
+#define WM8400_TSHUT_ENA_SHIFT                      14  /* TSHUT_ENA */
+#define WM8400_TSHUT_ENA_WIDTH                       1  /* TSHUT_ENA */
+#define WM8400_TSHUT_OPDIS                      0x2000  /* TSHUT_OPDIS */
+#define WM8400_TSHUT_OPDIS_MASK                 0x2000  /* TSHUT_OPDIS */
+#define WM8400_TSHUT_OPDIS_SHIFT                    13  /* TSHUT_OPDIS */
+#define WM8400_TSHUT_OPDIS_WIDTH                     1  /* TSHUT_OPDIS */
+#define WM8400_OPCLK_ENA                        0x0800  /* OPCLK_ENA */
+#define WM8400_OPCLK_ENA_MASK                   0x0800  /* OPCLK_ENA */
+#define WM8400_OPCLK_ENA_SHIFT                      11  /* OPCLK_ENA */
+#define WM8400_OPCLK_ENA_WIDTH                       1  /* OPCLK_ENA */
+#define WM8400_AINL_ENA                         0x0200  /* AINL_ENA */
+#define WM8400_AINL_ENA_MASK                    0x0200  /* AINL_ENA */
+#define WM8400_AINL_ENA_SHIFT                        9  /* AINL_ENA */
+#define WM8400_AINL_ENA_WIDTH                        1  /* AINL_ENA */
+#define WM8400_AINR_ENA                         0x0100  /* AINR_ENA */
+#define WM8400_AINR_ENA_MASK                    0x0100  /* AINR_ENA */
+#define WM8400_AINR_ENA_SHIFT                        8  /* AINR_ENA */
+#define WM8400_AINR_ENA_WIDTH                        1  /* AINR_ENA */
+#define WM8400_LIN34_ENA                        0x0080  /* LIN34_ENA */
+#define WM8400_LIN34_ENA_MASK                   0x0080  /* LIN34_ENA */
+#define WM8400_LIN34_ENA_SHIFT                       7  /* LIN34_ENA */
+#define WM8400_LIN34_ENA_WIDTH                       1  /* LIN34_ENA */
+#define WM8400_LIN12_ENA                        0x0040  /* LIN12_ENA */
+#define WM8400_LIN12_ENA_MASK                   0x0040  /* LIN12_ENA */
+#define WM8400_LIN12_ENA_SHIFT                       6  /* LIN12_ENA */
+#define WM8400_LIN12_ENA_WIDTH                       1  /* LIN12_ENA */
+#define WM8400_RIN34_ENA                        0x0020  /* RIN34_ENA */
+#define WM8400_RIN34_ENA_MASK                   0x0020  /* RIN34_ENA */
+#define WM8400_RIN34_ENA_SHIFT                       5  /* RIN34_ENA */
+#define WM8400_RIN34_ENA_WIDTH                       1  /* RIN34_ENA */
+#define WM8400_RIN12_ENA                        0x0010  /* RIN12_ENA */
+#define WM8400_RIN12_ENA_MASK                   0x0010  /* RIN12_ENA */
+#define WM8400_RIN12_ENA_SHIFT                       4  /* RIN12_ENA */
+#define WM8400_RIN12_ENA_WIDTH                       1  /* RIN12_ENA */
+#define WM8400_ADCL_ENA                         0x0002  /* ADCL_ENA */
+#define WM8400_ADCL_ENA_MASK                    0x0002  /* ADCL_ENA */
+#define WM8400_ADCL_ENA_SHIFT                        1  /* ADCL_ENA */
+#define WM8400_ADCL_ENA_WIDTH                        1  /* ADCL_ENA */
+#define WM8400_ADCR_ENA                         0x0001  /* ADCR_ENA */
+#define WM8400_ADCR_ENA_MASK                    0x0001  /* ADCR_ENA */
+#define WM8400_ADCR_ENA_SHIFT                        0  /* ADCR_ENA */
+#define WM8400_ADCR_ENA_WIDTH                        1  /* ADCR_ENA */
+
+/*
+ * R4 (0x04) - Power Management (3)
+ */
+#define WM8400_LON_ENA                          0x2000  /* LON_ENA */
+#define WM8400_LON_ENA_MASK                     0x2000  /* LON_ENA */
+#define WM8400_LON_ENA_SHIFT                        13  /* LON_ENA */
+#define WM8400_LON_ENA_WIDTH                         1  /* LON_ENA */
+#define WM8400_LOP_ENA                          0x1000  /* LOP_ENA */
+#define WM8400_LOP_ENA_MASK                     0x1000  /* LOP_ENA */
+#define WM8400_LOP_ENA_SHIFT                        12  /* LOP_ENA */
+#define WM8400_LOP_ENA_WIDTH                         1  /* LOP_ENA */
+#define WM8400_RON_ENA                          0x0800  /* RON_ENA */
+#define WM8400_RON_ENA_MASK                     0x0800  /* RON_ENA */
+#define WM8400_RON_ENA_SHIFT                        11  /* RON_ENA */
+#define WM8400_RON_ENA_WIDTH                         1  /* RON_ENA */
+#define WM8400_ROP_ENA                          0x0400  /* ROP_ENA */
+#define WM8400_ROP_ENA_MASK                     0x0400  /* ROP_ENA */
+#define WM8400_ROP_ENA_SHIFT                        10  /* ROP_ENA */
+#define WM8400_ROP_ENA_WIDTH                         1  /* ROP_ENA */
+#define WM8400_LOPGA_ENA                        0x0080  /* LOPGA_ENA */
+#define WM8400_LOPGA_ENA_MASK                   0x0080  /* LOPGA_ENA */
+#define WM8400_LOPGA_ENA_SHIFT                       7  /* LOPGA_ENA */
+#define WM8400_LOPGA_ENA_WIDTH                       1  /* LOPGA_ENA */
+#define WM8400_ROPGA_ENA                        0x0040  /* ROPGA_ENA */
+#define WM8400_ROPGA_ENA_MASK                   0x0040  /* ROPGA_ENA */
+#define WM8400_ROPGA_ENA_SHIFT                       6  /* ROPGA_ENA */
+#define WM8400_ROPGA_ENA_WIDTH                       1  /* ROPGA_ENA */
+#define WM8400_LOMIX_ENA                        0x0020  /* LOMIX_ENA */
+#define WM8400_LOMIX_ENA_MASK                   0x0020  /* LOMIX_ENA */
+#define WM8400_LOMIX_ENA_SHIFT                       5  /* LOMIX_ENA */
+#define WM8400_LOMIX_ENA_WIDTH                       1  /* LOMIX_ENA */
+#define WM8400_ROMIX_ENA                        0x0010  /* ROMIX_ENA */
+#define WM8400_ROMIX_ENA_MASK                   0x0010  /* ROMIX_ENA */
+#define WM8400_ROMIX_ENA_SHIFT                       4  /* ROMIX_ENA */
+#define WM8400_ROMIX_ENA_WIDTH                       1  /* ROMIX_ENA */
+#define WM8400_DACL_ENA                         0x0002  /* DACL_ENA */
+#define WM8400_DACL_ENA_MASK                    0x0002  /* DACL_ENA */
+#define WM8400_DACL_ENA_SHIFT                        1  /* DACL_ENA */
+#define WM8400_DACL_ENA_WIDTH                        1  /* DACL_ENA */
+#define WM8400_DACR_ENA                         0x0001  /* DACR_ENA */
+#define WM8400_DACR_ENA_MASK                    0x0001  /* DACR_ENA */
+#define WM8400_DACR_ENA_SHIFT                        0  /* DACR_ENA */
+#define WM8400_DACR_ENA_WIDTH                        1  /* DACR_ENA */
+
+/*
+ * R5 (0x05) - Audio Interface (1)
+ */
+#define WM8400_AIFADCL_SRC                      0x8000  /* AIFADCL_SRC */
+#define WM8400_AIFADCL_SRC_MASK                 0x8000  /* AIFADCL_SRC */
+#define WM8400_AIFADCL_SRC_SHIFT                    15  /* AIFADCL_SRC */
+#define WM8400_AIFADCL_SRC_WIDTH                     1  /* AIFADCL_SRC */
+#define WM8400_AIFADCR_SRC                      0x4000  /* AIFADCR_SRC */
+#define WM8400_AIFADCR_SRC_MASK                 0x4000  /* AIFADCR_SRC */
+#define WM8400_AIFADCR_SRC_SHIFT                    14  /* AIFADCR_SRC */
+#define WM8400_AIFADCR_SRC_WIDTH                     1  /* AIFADCR_SRC */
+#define WM8400_AIFADC_TDM                       0x2000  /* AIFADC_TDM */
+#define WM8400_AIFADC_TDM_MASK                  0x2000  /* AIFADC_TDM */
+#define WM8400_AIFADC_TDM_SHIFT                     13  /* AIFADC_TDM */
+#define WM8400_AIFADC_TDM_WIDTH                      1  /* AIFADC_TDM */
+#define WM8400_AIFADC_TDM_CHAN                  0x1000  /* AIFADC_TDM_CHAN */
+#define WM8400_AIFADC_TDM_CHAN_MASK             0x1000  /* AIFADC_TDM_CHAN */
+#define WM8400_AIFADC_TDM_CHAN_SHIFT                12  /* AIFADC_TDM_CHAN */
+#define WM8400_AIFADC_TDM_CHAN_WIDTH                 1  /* AIFADC_TDM_CHAN */
+#define WM8400_AIF_BCLK_INV                     0x0100  /* AIF_BCLK_INV */
+#define WM8400_AIF_BCLK_INV_MASK                0x0100  /* AIF_BCLK_INV */
+#define WM8400_AIF_BCLK_INV_SHIFT                    8  /* AIF_BCLK_INV */
+#define WM8400_AIF_BCLK_INV_WIDTH                    1  /* AIF_BCLK_INV */
+#define WM8400_AIF_LRCLK_INV                    0x0080  /* AIF_LRCLK_INV */
+#define WM8400_AIF_LRCLK_INV_MASK               0x0080  /* AIF_LRCLK_INV */
+#define WM8400_AIF_LRCLK_INV_SHIFT                   7  /* AIF_LRCLK_INV */
+#define WM8400_AIF_LRCLK_INV_WIDTH                   1  /* AIF_LRCLK_INV */
+#define WM8400_AIF_WL_MASK                      0x0060  /* AIF_WL - [6:5] */
+#define WM8400_AIF_WL_SHIFT                          5  /* AIF_WL - [6:5] */
+#define WM8400_AIF_WL_WIDTH                          2  /* AIF_WL - [6:5] */
+#define WM8400_AIF_WL_16BITS			(0 << 5)
+#define WM8400_AIF_WL_20BITS			(1 << 5)
+#define WM8400_AIF_WL_24BITS			(2 << 5)
+#define WM8400_AIF_WL_32BITS			(3 << 5)
+#define WM8400_AIF_FMT_MASK                     0x0018  /* AIF_FMT - [4:3] */
+#define WM8400_AIF_FMT_SHIFT                         3  /* AIF_FMT - [4:3] */
+#define WM8400_AIF_FMT_WIDTH                         2  /* AIF_FMT - [4:3] */
+#define WM8400_AIF_FMT_RIGHTJ			(0 << 3)
+#define WM8400_AIF_FMT_LEFTJ			(1 << 3)
+#define WM8400_AIF_FMT_I2S			(2 << 3)
+#define WM8400_AIF_FMT_DSP			(3 << 3)
+
+/*
+ * R6 (0x06) - Audio Interface (2)
+ */
+#define WM8400_DACL_SRC                         0x8000  /* DACL_SRC */
+#define WM8400_DACL_SRC_MASK                    0x8000  /* DACL_SRC */
+#define WM8400_DACL_SRC_SHIFT                       15  /* DACL_SRC */
+#define WM8400_DACL_SRC_WIDTH                        1  /* DACL_SRC */
+#define WM8400_DACR_SRC                         0x4000  /* DACR_SRC */
+#define WM8400_DACR_SRC_MASK                    0x4000  /* DACR_SRC */
+#define WM8400_DACR_SRC_SHIFT                       14  /* DACR_SRC */
+#define WM8400_DACR_SRC_WIDTH                        1  /* DACR_SRC */
+#define WM8400_AIFDAC_TDM                       0x2000  /* AIFDAC_TDM */
+#define WM8400_AIFDAC_TDM_MASK                  0x2000  /* AIFDAC_TDM */
+#define WM8400_AIFDAC_TDM_SHIFT                     13  /* AIFDAC_TDM */
+#define WM8400_AIFDAC_TDM_WIDTH                      1  /* AIFDAC_TDM */
+#define WM8400_AIFDAC_TDM_CHAN                  0x1000  /* AIFDAC_TDM_CHAN */
+#define WM8400_AIFDAC_TDM_CHAN_MASK             0x1000  /* AIFDAC_TDM_CHAN */
+#define WM8400_AIFDAC_TDM_CHAN_SHIFT                12  /* AIFDAC_TDM_CHAN */
+#define WM8400_AIFDAC_TDM_CHAN_WIDTH                 1  /* AIFDAC_TDM_CHAN */
+#define WM8400_DAC_BOOST_MASK                   0x0C00  /* DAC_BOOST - [11:10] */
+#define WM8400_DAC_BOOST_SHIFT                      10  /* DAC_BOOST - [11:10] */
+#define WM8400_DAC_BOOST_WIDTH                       2  /* DAC_BOOST - [11:10] */
+#define WM8400_DAC_COMP                         0x0010  /* DAC_COMP */
+#define WM8400_DAC_COMP_MASK                    0x0010  /* DAC_COMP */
+#define WM8400_DAC_COMP_SHIFT                        4  /* DAC_COMP */
+#define WM8400_DAC_COMP_WIDTH                        1  /* DAC_COMP */
+#define WM8400_DAC_COMPMODE                     0x0008  /* DAC_COMPMODE */
+#define WM8400_DAC_COMPMODE_MASK                0x0008  /* DAC_COMPMODE */
+#define WM8400_DAC_COMPMODE_SHIFT                    3  /* DAC_COMPMODE */
+#define WM8400_DAC_COMPMODE_WIDTH                    1  /* DAC_COMPMODE */
+#define WM8400_ADC_COMP                         0x0004  /* ADC_COMP */
+#define WM8400_ADC_COMP_MASK                    0x0004  /* ADC_COMP */
+#define WM8400_ADC_COMP_SHIFT                        2  /* ADC_COMP */
+#define WM8400_ADC_COMP_WIDTH                        1  /* ADC_COMP */
+#define WM8400_ADC_COMPMODE                     0x0002  /* ADC_COMPMODE */
+#define WM8400_ADC_COMPMODE_MASK                0x0002  /* ADC_COMPMODE */
+#define WM8400_ADC_COMPMODE_SHIFT                    1  /* ADC_COMPMODE */
+#define WM8400_ADC_COMPMODE_WIDTH                    1  /* ADC_COMPMODE */
+#define WM8400_LOOPBACK                         0x0001  /* LOOPBACK */
+#define WM8400_LOOPBACK_MASK                    0x0001  /* LOOPBACK */
+#define WM8400_LOOPBACK_SHIFT                        0  /* LOOPBACK */
+#define WM8400_LOOPBACK_WIDTH                        1  /* LOOPBACK */
+
+/*
+ * R7 (0x07) - Clocking (1)
+ */
+#define WM8400_TOCLK_RATE                       0x8000  /* TOCLK_RATE */
+#define WM8400_TOCLK_RATE_MASK                  0x8000  /* TOCLK_RATE */
+#define WM8400_TOCLK_RATE_SHIFT                     15  /* TOCLK_RATE */
+#define WM8400_TOCLK_RATE_WIDTH                      1  /* TOCLK_RATE */
+#define WM8400_TOCLK_ENA                        0x4000  /* TOCLK_ENA */
+#define WM8400_TOCLK_ENA_MASK                   0x4000  /* TOCLK_ENA */
+#define WM8400_TOCLK_ENA_SHIFT                      14  /* TOCLK_ENA */
+#define WM8400_TOCLK_ENA_WIDTH                       1  /* TOCLK_ENA */
+#define WM8400_OPCLKDIV_MASK                    0x1E00  /* OPCLKDIV - [12:9] */
+#define WM8400_OPCLKDIV_SHIFT                        9  /* OPCLKDIV - [12:9] */
+#define WM8400_OPCLKDIV_WIDTH                        4  /* OPCLKDIV - [12:9] */
+#define WM8400_DCLKDIV_MASK                     0x01C0  /* DCLKDIV - [8:6] */
+#define WM8400_DCLKDIV_SHIFT                         6  /* DCLKDIV - [8:6] */
+#define WM8400_DCLKDIV_WIDTH                         3  /* DCLKDIV - [8:6] */
+#define WM8400_BCLK_DIV_MASK                    0x001E  /* BCLK_DIV - [4:1] */
+#define WM8400_BCLK_DIV_SHIFT                        1  /* BCLK_DIV - [4:1] */
+#define WM8400_BCLK_DIV_WIDTH                        4  /* BCLK_DIV - [4:1] */
+
+/*
+ * R8 (0x08) - Clocking (2)
+ */
+#define WM8400_MCLK_SRC                         0x8000  /* MCLK_SRC */
+#define WM8400_MCLK_SRC_MASK                    0x8000  /* MCLK_SRC */
+#define WM8400_MCLK_SRC_SHIFT                       15  /* MCLK_SRC */
+#define WM8400_MCLK_SRC_WIDTH                        1  /* MCLK_SRC */
+#define WM8400_SYSCLK_SRC                       0x4000  /* SYSCLK_SRC */
+#define WM8400_SYSCLK_SRC_MASK                  0x4000  /* SYSCLK_SRC */
+#define WM8400_SYSCLK_SRC_SHIFT                     14  /* SYSCLK_SRC */
+#define WM8400_SYSCLK_SRC_WIDTH                      1  /* SYSCLK_SRC */
+#define WM8400_CLK_FORCE                        0x2000  /* CLK_FORCE */
+#define WM8400_CLK_FORCE_MASK                   0x2000  /* CLK_FORCE */
+#define WM8400_CLK_FORCE_SHIFT                      13  /* CLK_FORCE */
+#define WM8400_CLK_FORCE_WIDTH                       1  /* CLK_FORCE */
+#define WM8400_MCLK_DIV_MASK                    0x1800  /* MCLK_DIV - [12:11] */
+#define WM8400_MCLK_DIV_SHIFT                       11  /* MCLK_DIV - [12:11] */
+#define WM8400_MCLK_DIV_WIDTH                        2  /* MCLK_DIV - [12:11] */
+#define WM8400_MCLK_INV                         0x0400  /* MCLK_INV */
+#define WM8400_MCLK_INV_MASK                    0x0400  /* MCLK_INV */
+#define WM8400_MCLK_INV_SHIFT                       10  /* MCLK_INV */
+#define WM8400_MCLK_INV_WIDTH                        1  /* MCLK_INV */
+#define WM8400_ADC_CLKDIV_MASK                  0x00E0  /* ADC_CLKDIV - [7:5] */
+#define WM8400_ADC_CLKDIV_SHIFT                      5  /* ADC_CLKDIV - [7:5] */
+#define WM8400_ADC_CLKDIV_WIDTH                      3  /* ADC_CLKDIV - [7:5] */
+#define WM8400_DAC_CLKDIV_MASK                  0x001C  /* DAC_CLKDIV - [4:2] */
+#define WM8400_DAC_CLKDIV_SHIFT                      2  /* DAC_CLKDIV - [4:2] */
+#define WM8400_DAC_CLKDIV_WIDTH                      3  /* DAC_CLKDIV - [4:2] */
+
+/*
+ * R9 (0x09) - Audio Interface (3)
+ */
+#define WM8400_AIF_MSTR1                        0x8000  /* AIF_MSTR1 */
+#define WM8400_AIF_MSTR1_MASK                   0x8000  /* AIF_MSTR1 */
+#define WM8400_AIF_MSTR1_SHIFT                      15  /* AIF_MSTR1 */
+#define WM8400_AIF_MSTR1_WIDTH                       1  /* AIF_MSTR1 */
+#define WM8400_AIF_MSTR2                        0x4000  /* AIF_MSTR2 */
+#define WM8400_AIF_MSTR2_MASK                   0x4000  /* AIF_MSTR2 */
+#define WM8400_AIF_MSTR2_SHIFT                      14  /* AIF_MSTR2 */
+#define WM8400_AIF_MSTR2_WIDTH                       1  /* AIF_MSTR2 */
+#define WM8400_AIF_SEL                          0x2000  /* AIF_SEL */
+#define WM8400_AIF_SEL_MASK                     0x2000  /* AIF_SEL */
+#define WM8400_AIF_SEL_SHIFT                        13  /* AIF_SEL */
+#define WM8400_AIF_SEL_WIDTH                         1  /* AIF_SEL */
+#define WM8400_ADCLRC_DIR                       0x0800  /* ADCLRC_DIR */
+#define WM8400_ADCLRC_DIR_MASK                  0x0800  /* ADCLRC_DIR */
+#define WM8400_ADCLRC_DIR_SHIFT                     11  /* ADCLRC_DIR */
+#define WM8400_ADCLRC_DIR_WIDTH                      1  /* ADCLRC_DIR */
+#define WM8400_ADCLRC_RATE_MASK                 0x07FF  /* ADCLRC_RATE - [10:0] */
+#define WM8400_ADCLRC_RATE_SHIFT                     0  /* ADCLRC_RATE - [10:0] */
+#define WM8400_ADCLRC_RATE_WIDTH                    11  /* ADCLRC_RATE - [10:0] */
+
+/*
+ * R10 (0x0A) - Audio Interface (4)
+ */
+#define WM8400_ALRCGPIO1                        0x8000  /* ALRCGPIO1 */
+#define WM8400_ALRCGPIO1_MASK                   0x8000  /* ALRCGPIO1 */
+#define WM8400_ALRCGPIO1_SHIFT                      15  /* ALRCGPIO1 */
+#define WM8400_ALRCGPIO1_WIDTH                       1  /* ALRCGPIO1 */
+#define WM8400_ALRCBGPIO6                       0x4000  /* ALRCBGPIO6 */
+#define WM8400_ALRCBGPIO6_MASK                  0x4000  /* ALRCBGPIO6 */
+#define WM8400_ALRCBGPIO6_SHIFT                     14  /* ALRCBGPIO6 */
+#define WM8400_ALRCBGPIO6_WIDTH                      1  /* ALRCBGPIO6 */
+#define WM8400_AIF_TRIS                         0x2000  /* AIF_TRIS */
+#define WM8400_AIF_TRIS_MASK                    0x2000  /* AIF_TRIS */
+#define WM8400_AIF_TRIS_SHIFT                       13  /* AIF_TRIS */
+#define WM8400_AIF_TRIS_WIDTH                        1  /* AIF_TRIS */
+#define WM8400_DACLRC_DIR                       0x0800  /* DACLRC_DIR */
+#define WM8400_DACLRC_DIR_MASK                  0x0800  /* DACLRC_DIR */
+#define WM8400_DACLRC_DIR_SHIFT                     11  /* DACLRC_DIR */
+#define WM8400_DACLRC_DIR_WIDTH                      1  /* DACLRC_DIR */
+#define WM8400_DACLRC_RATE_MASK                 0x07FF  /* DACLRC_RATE - [10:0] */
+#define WM8400_DACLRC_RATE_SHIFT                     0  /* DACLRC_RATE - [10:0] */
+#define WM8400_DACLRC_RATE_WIDTH                    11  /* DACLRC_RATE - [10:0] */
+
+/*
+ * R11 (0x0B) - DAC CTRL
+ */
+#define WM8400_DAC_SDMCLK_RATE                  0x2000  /* DAC_SDMCLK_RATE */
+#define WM8400_DAC_SDMCLK_RATE_MASK             0x2000  /* DAC_SDMCLK_RATE */
+#define WM8400_DAC_SDMCLK_RATE_SHIFT                13  /* DAC_SDMCLK_RATE */
+#define WM8400_DAC_SDMCLK_RATE_WIDTH                 1  /* DAC_SDMCLK_RATE */
+#define WM8400_AIF_LRCLKRATE                    0x0400  /* AIF_LRCLKRATE */
+#define WM8400_AIF_LRCLKRATE_MASK               0x0400  /* AIF_LRCLKRATE */
+#define WM8400_AIF_LRCLKRATE_SHIFT                  10  /* AIF_LRCLKRATE */
+#define WM8400_AIF_LRCLKRATE_WIDTH                   1  /* AIF_LRCLKRATE */
+#define WM8400_DAC_MONO                         0x0200  /* DAC_MONO */
+#define WM8400_DAC_MONO_MASK                    0x0200  /* DAC_MONO */
+#define WM8400_DAC_MONO_SHIFT                        9  /* DAC_MONO */
+#define WM8400_DAC_MONO_WIDTH                        1  /* DAC_MONO */
+#define WM8400_DAC_SB_FILT                      0x0100  /* DAC_SB_FILT */
+#define WM8400_DAC_SB_FILT_MASK                 0x0100  /* DAC_SB_FILT */
+#define WM8400_DAC_SB_FILT_SHIFT                     8  /* DAC_SB_FILT */
+#define WM8400_DAC_SB_FILT_WIDTH                     1  /* DAC_SB_FILT */
+#define WM8400_DAC_MUTERATE                     0x0080  /* DAC_MUTERATE */
+#define WM8400_DAC_MUTERATE_MASK                0x0080  /* DAC_MUTERATE */
+#define WM8400_DAC_MUTERATE_SHIFT                    7  /* DAC_MUTERATE */
+#define WM8400_DAC_MUTERATE_WIDTH                    1  /* DAC_MUTERATE */
+#define WM8400_DAC_MUTEMODE                     0x0040  /* DAC_MUTEMODE */
+#define WM8400_DAC_MUTEMODE_MASK                0x0040  /* DAC_MUTEMODE */
+#define WM8400_DAC_MUTEMODE_SHIFT                    6  /* DAC_MUTEMODE */
+#define WM8400_DAC_MUTEMODE_WIDTH                    1  /* DAC_MUTEMODE */
+#define WM8400_DEEMP_MASK                       0x0030  /* DEEMP - [5:4] */
+#define WM8400_DEEMP_SHIFT                           4  /* DEEMP - [5:4] */
+#define WM8400_DEEMP_WIDTH                           2  /* DEEMP - [5:4] */
+#define WM8400_DAC_MUTE                         0x0004  /* DAC_MUTE */
+#define WM8400_DAC_MUTE_MASK                    0x0004  /* DAC_MUTE */
+#define WM8400_DAC_MUTE_SHIFT                        2  /* DAC_MUTE */
+#define WM8400_DAC_MUTE_WIDTH                        1  /* DAC_MUTE */
+#define WM8400_DACL_DATINV                      0x0002  /* DACL_DATINV */
+#define WM8400_DACL_DATINV_MASK                 0x0002  /* DACL_DATINV */
+#define WM8400_DACL_DATINV_SHIFT                     1  /* DACL_DATINV */
+#define WM8400_DACL_DATINV_WIDTH                     1  /* DACL_DATINV */
+#define WM8400_DACR_DATINV                      0x0001  /* DACR_DATINV */
+#define WM8400_DACR_DATINV_MASK                 0x0001  /* DACR_DATINV */
+#define WM8400_DACR_DATINV_SHIFT                     0  /* DACR_DATINV */
+#define WM8400_DACR_DATINV_WIDTH                     1  /* DACR_DATINV */
+
+/*
+ * R12 (0x0C) - Left DAC Digital Volume
+ */
+#define WM8400_DAC_VU                           0x0100  /* DAC_VU */
+#define WM8400_DAC_VU_MASK                      0x0100  /* DAC_VU */
+#define WM8400_DAC_VU_SHIFT                          8  /* DAC_VU */
+#define WM8400_DAC_VU_WIDTH                          1  /* DAC_VU */
+#define WM8400_DACL_VOL_MASK                    0x00FF  /* DACL_VOL - [7:0] */
+#define WM8400_DACL_VOL_SHIFT                        0  /* DACL_VOL - [7:0] */
+#define WM8400_DACL_VOL_WIDTH                        8  /* DACL_VOL - [7:0] */
+
+/*
+ * R13 (0x0D) - Right DAC Digital Volume
+ */
+#define WM8400_DAC_VU                           0x0100  /* DAC_VU */
+#define WM8400_DAC_VU_MASK                      0x0100  /* DAC_VU */
+#define WM8400_DAC_VU_SHIFT                          8  /* DAC_VU */
+#define WM8400_DAC_VU_WIDTH                          1  /* DAC_VU */
+#define WM8400_DACR_VOL_MASK                    0x00FF  /* DACR_VOL - [7:0] */
+#define WM8400_DACR_VOL_SHIFT                        0  /* DACR_VOL - [7:0] */
+#define WM8400_DACR_VOL_WIDTH                        8  /* DACR_VOL - [7:0] */
+
+/*
+ * R14 (0x0E) - Digital Side Tone
+ */
+#define WM8400_ADCL_DAC_SVOL_MASK               0x1E00  /*   ADCL_DAC_SVOL - [12:9] */
+#define WM8400_ADCL_DAC_SVOL_SHIFT                   9  /*   ADCL_DAC_SVOL - [12:9] */
+#define WM8400_ADCL_DAC_SVOL_WIDTH                   4  /*   ADCL_DAC_SVOL - [12:9] */
+#define WM8400_ADCR_DAC_SVOL_MASK               0x01E0  /* ADCR_DAC_SVOL - [8:5] */
+#define WM8400_ADCR_DAC_SVOL_SHIFT                   5  /* ADCR_DAC_SVOL - [8:5] */
+#define WM8400_ADCR_DAC_SVOL_WIDTH                   4  /* ADCR_DAC_SVOL - [8:5] */
+#define WM8400_ADC_TO_DACL_MASK                 0x000C  /* ADC_TO_DACL - [3:2] */
+#define WM8400_ADC_TO_DACL_SHIFT                     2  /* ADC_TO_DACL - [3:2] */
+#define WM8400_ADC_TO_DACL_WIDTH                     2  /* ADC_TO_DACL - [3:2] */
+#define WM8400_ADC_TO_DACR_MASK                 0x0003  /* ADC_TO_DACR - [1:0] */
+#define WM8400_ADC_TO_DACR_SHIFT                     0  /* ADC_TO_DACR - [1:0] */
+#define WM8400_ADC_TO_DACR_WIDTH                     2  /* ADC_TO_DACR - [1:0] */
+
+/*
+ * R15 (0x0F) - ADC CTRL
+ */
+#define WM8400_ADC_HPF_ENA                      0x0100  /* ADC_HPF_ENA */
+#define WM8400_ADC_HPF_ENA_MASK                 0x0100  /* ADC_HPF_ENA */
+#define WM8400_ADC_HPF_ENA_SHIFT                     8  /* ADC_HPF_ENA */
+#define WM8400_ADC_HPF_ENA_WIDTH                     1  /* ADC_HPF_ENA */
+#define WM8400_ADC_HPF_CUT_MASK                 0x0060  /* ADC_HPF_CUT - [6:5] */
+#define WM8400_ADC_HPF_CUT_SHIFT                     5  /* ADC_HPF_CUT - [6:5] */
+#define WM8400_ADC_HPF_CUT_WIDTH                     2  /* ADC_HPF_CUT - [6:5] */
+#define WM8400_ADCL_DATINV                      0x0002  /* ADCL_DATINV */
+#define WM8400_ADCL_DATINV_MASK                 0x0002  /* ADCL_DATINV */
+#define WM8400_ADCL_DATINV_SHIFT                     1  /* ADCL_DATINV */
+#define WM8400_ADCL_DATINV_WIDTH                     1  /* ADCL_DATINV */
+#define WM8400_ADCR_DATINV                      0x0001  /* ADCR_DATINV */
+#define WM8400_ADCR_DATINV_MASK                 0x0001  /* ADCR_DATINV */
+#define WM8400_ADCR_DATINV_SHIFT                     0  /* ADCR_DATINV */
+#define WM8400_ADCR_DATINV_WIDTH                     1  /* ADCR_DATINV */
+
+/*
+ * R16 (0x10) - Left ADC Digital Volume
+ */
+#define WM8400_ADC_VU                           0x0100  /* ADC_VU */
+#define WM8400_ADC_VU_MASK                      0x0100  /* ADC_VU */
+#define WM8400_ADC_VU_SHIFT                          8  /* ADC_VU */
+#define WM8400_ADC_VU_WIDTH                          1  /* ADC_VU */
+#define WM8400_ADCL_VOL_MASK                    0x00FF  /* ADCL_VOL - [7:0] */
+#define WM8400_ADCL_VOL_SHIFT                        0  /* ADCL_VOL - [7:0] */
+#define WM8400_ADCL_VOL_WIDTH                        8  /* ADCL_VOL - [7:0] */
+
+/*
+ * R17 (0x11) - Right ADC Digital Volume
+ */
+#define WM8400_ADC_VU                           0x0100  /* ADC_VU */
+#define WM8400_ADC_VU_MASK                      0x0100  /* ADC_VU */
+#define WM8400_ADC_VU_SHIFT                          8  /* ADC_VU */
+#define WM8400_ADC_VU_WIDTH                          1  /* ADC_VU */
+#define WM8400_ADCR_VOL_MASK                    0x00FF  /* ADCR_VOL - [7:0] */
+#define WM8400_ADCR_VOL_SHIFT                        0  /* ADCR_VOL - [7:0] */
+#define WM8400_ADCR_VOL_WIDTH                        8  /* ADCR_VOL - [7:0] */
+
+/*
+ * R24 (0x18) - Left Line Input 1&2 Volume
+ */
+#define WM8400_IPVU                             0x0100  /* IPVU */
+#define WM8400_IPVU_MASK                        0x0100  /* IPVU */
+#define WM8400_IPVU_SHIFT                            8  /* IPVU */
+#define WM8400_IPVU_WIDTH                            1  /* IPVU */
+#define WM8400_LI12MUTE                         0x0080  /* LI12MUTE */
+#define WM8400_LI12MUTE_MASK                    0x0080  /* LI12MUTE */
+#define WM8400_LI12MUTE_SHIFT                        7  /* LI12MUTE */
+#define WM8400_LI12MUTE_WIDTH                        1  /* LI12MUTE */
+#define WM8400_LI12ZC                           0x0040  /* LI12ZC */
+#define WM8400_LI12ZC_MASK                      0x0040  /* LI12ZC */
+#define WM8400_LI12ZC_SHIFT                          6  /* LI12ZC */
+#define WM8400_LI12ZC_WIDTH                          1  /* LI12ZC */
+#define WM8400_LIN12VOL_MASK                    0x001F  /* LIN12VOL - [4:0] */
+#define WM8400_LIN12VOL_SHIFT                        0  /* LIN12VOL - [4:0] */
+#define WM8400_LIN12VOL_WIDTH                        5  /* LIN12VOL - [4:0] */
+
+/*
+ * R25 (0x19) - Left Line Input 3&4 Volume
+ */
+#define WM8400_IPVU                             0x0100  /* IPVU */
+#define WM8400_IPVU_MASK                        0x0100  /* IPVU */
+#define WM8400_IPVU_SHIFT                            8  /* IPVU */
+#define WM8400_IPVU_WIDTH                            1  /* IPVU */
+#define WM8400_LI34MUTE                         0x0080  /* LI34MUTE */
+#define WM8400_LI34MUTE_MASK                    0x0080  /* LI34MUTE */
+#define WM8400_LI34MUTE_SHIFT                        7  /* LI34MUTE */
+#define WM8400_LI34MUTE_WIDTH                        1  /* LI34MUTE */
+#define WM8400_LI34ZC                           0x0040  /* LI34ZC */
+#define WM8400_LI34ZC_MASK                      0x0040  /* LI34ZC */
+#define WM8400_LI34ZC_SHIFT                          6  /* LI34ZC */
+#define WM8400_LI34ZC_WIDTH                          1  /* LI34ZC */
+#define WM8400_LIN34VOL_MASK                    0x001F  /* LIN34VOL - [4:0] */
+#define WM8400_LIN34VOL_SHIFT                        0  /* LIN34VOL - [4:0] */
+#define WM8400_LIN34VOL_WIDTH                        5  /* LIN34VOL - [4:0] */
+
+/*
+ * R26 (0x1A) - Right Line Input 1&2 Volume
+ */
+#define WM8400_IPVU                             0x0100  /* IPVU */
+#define WM8400_IPVU_MASK                        0x0100  /* IPVU */
+#define WM8400_IPVU_SHIFT                            8  /* IPVU */
+#define WM8400_IPVU_WIDTH                            1  /* IPVU */
+#define WM8400_RI12MUTE                         0x0080  /* RI12MUTE */
+#define WM8400_RI12MUTE_MASK                    0x0080  /* RI12MUTE */
+#define WM8400_RI12MUTE_SHIFT                        7  /* RI12MUTE */
+#define WM8400_RI12MUTE_WIDTH                        1  /* RI12MUTE */
+#define WM8400_RI12ZC                           0x0040  /* RI12ZC */
+#define WM8400_RI12ZC_MASK                      0x0040  /* RI12ZC */
+#define WM8400_RI12ZC_SHIFT                          6  /* RI12ZC */
+#define WM8400_RI12ZC_WIDTH                          1  /* RI12ZC */
+#define WM8400_RIN12VOL_MASK                    0x001F  /* RIN12VOL - [4:0] */
+#define WM8400_RIN12VOL_SHIFT                        0  /* RIN12VOL - [4:0] */
+#define WM8400_RIN12VOL_WIDTH                        5  /* RIN12VOL - [4:0] */
+
+/*
+ * R27 (0x1B) - Right Line Input 3&4 Volume
+ */
+#define WM8400_IPVU                             0x0100  /* IPVU */
+#define WM8400_IPVU_MASK                        0x0100  /* IPVU */
+#define WM8400_IPVU_SHIFT                            8  /* IPVU */
+#define WM8400_IPVU_WIDTH                            1  /* IPVU */
+#define WM8400_RI34MUTE                         0x0080  /* RI34MUTE */
+#define WM8400_RI34MUTE_MASK                    0x0080  /* RI34MUTE */
+#define WM8400_RI34MUTE_SHIFT                        7  /* RI34MUTE */
+#define WM8400_RI34MUTE_WIDTH                        1  /* RI34MUTE */
+#define WM8400_RI34ZC                           0x0040  /* RI34ZC */
+#define WM8400_RI34ZC_MASK                      0x0040  /* RI34ZC */
+#define WM8400_RI34ZC_SHIFT                          6  /* RI34ZC */
+#define WM8400_RI34ZC_WIDTH                          1  /* RI34ZC */
+#define WM8400_RIN34VOL_MASK                    0x001F  /* RIN34VOL - [4:0] */
+#define WM8400_RIN34VOL_SHIFT                        0  /* RIN34VOL - [4:0] */
+#define WM8400_RIN34VOL_WIDTH                        5  /* RIN34VOL - [4:0] */
+
+/*
+ * R28 (0x1C) - Left Output Volume
+ */
+#define WM8400_OPVU                             0x0100  /* OPVU */
+#define WM8400_OPVU_MASK                        0x0100  /* OPVU */
+#define WM8400_OPVU_SHIFT                            8  /* OPVU */
+#define WM8400_OPVU_WIDTH                            1  /* OPVU */
+#define WM8400_LOZC                             0x0080  /* LOZC */
+#define WM8400_LOZC_MASK                        0x0080  /* LOZC */
+#define WM8400_LOZC_SHIFT                            7  /* LOZC */
+#define WM8400_LOZC_WIDTH                            1  /* LOZC */
+#define WM8400_LOUTVOL_MASK                     0x007F  /* LOUTVOL - [6:0] */
+#define WM8400_LOUTVOL_SHIFT                         0  /* LOUTVOL - [6:0] */
+#define WM8400_LOUTVOL_WIDTH                         7  /* LOUTVOL - [6:0] */
+
+/*
+ * R29 (0x1D) - Right Output Volume
+ */
+#define WM8400_OPVU                             0x0100  /* OPVU */
+#define WM8400_OPVU_MASK                        0x0100  /* OPVU */
+#define WM8400_OPVU_SHIFT                            8  /* OPVU */
+#define WM8400_OPVU_WIDTH                            1  /* OPVU */
+#define WM8400_ROZC                             0x0080  /* ROZC */
+#define WM8400_ROZC_MASK                        0x0080  /* ROZC */
+#define WM8400_ROZC_SHIFT                            7  /* ROZC */
+#define WM8400_ROZC_WIDTH                            1  /* ROZC */
+#define WM8400_ROUTVOL_MASK                     0x007F  /* ROUTVOL - [6:0] */
+#define WM8400_ROUTVOL_SHIFT                         0  /* ROUTVOL - [6:0] */
+#define WM8400_ROUTVOL_WIDTH                         7  /* ROUTVOL - [6:0] */
+
+/*
+ * R30 (0x1E) - Line Outputs Volume
+ */
+#define WM8400_LONMUTE                          0x0040  /* LONMUTE */
+#define WM8400_LONMUTE_MASK                     0x0040  /* LONMUTE */
+#define WM8400_LONMUTE_SHIFT                         6  /* LONMUTE */
+#define WM8400_LONMUTE_WIDTH                         1  /* LONMUTE */
+#define WM8400_LOPMUTE                          0x0020  /* LOPMUTE */
+#define WM8400_LOPMUTE_MASK                     0x0020  /* LOPMUTE */
+#define WM8400_LOPMUTE_SHIFT                         5  /* LOPMUTE */
+#define WM8400_LOPMUTE_WIDTH                         1  /* LOPMUTE */
+#define WM8400_LOATTN                           0x0010  /* LOATTN */
+#define WM8400_LOATTN_MASK                      0x0010  /* LOATTN */
+#define WM8400_LOATTN_SHIFT                          4  /* LOATTN */
+#define WM8400_LOATTN_WIDTH                          1  /* LOATTN */
+#define WM8400_RONMUTE                          0x0004  /* RONMUTE */
+#define WM8400_RONMUTE_MASK                     0x0004  /* RONMUTE */
+#define WM8400_RONMUTE_SHIFT                         2  /* RONMUTE */
+#define WM8400_RONMUTE_WIDTH                         1  /* RONMUTE */
+#define WM8400_ROPMUTE                          0x0002  /* ROPMUTE */
+#define WM8400_ROPMUTE_MASK                     0x0002  /* ROPMUTE */
+#define WM8400_ROPMUTE_SHIFT                         1  /* ROPMUTE */
+#define WM8400_ROPMUTE_WIDTH                         1  /* ROPMUTE */
+#define WM8400_ROATTN                           0x0001  /* ROATTN */
+#define WM8400_ROATTN_MASK                      0x0001  /* ROATTN */
+#define WM8400_ROATTN_SHIFT                          0  /* ROATTN */
+#define WM8400_ROATTN_WIDTH                          1  /* ROATTN */
+
+/*
+ * R31 (0x1F) - Out3/4 Volume
+ */
+#define WM8400_OUT3MUTE                         0x0020  /* OUT3MUTE */
+#define WM8400_OUT3MUTE_MASK                    0x0020  /* OUT3MUTE */
+#define WM8400_OUT3MUTE_SHIFT                        5  /* OUT3MUTE */
+#define WM8400_OUT3MUTE_WIDTH                        1  /* OUT3MUTE */
+#define WM8400_OUT3ATTN                         0x0010  /* OUT3ATTN */
+#define WM8400_OUT3ATTN_MASK                    0x0010  /* OUT3ATTN */
+#define WM8400_OUT3ATTN_SHIFT                        4  /* OUT3ATTN */
+#define WM8400_OUT3ATTN_WIDTH                        1  /* OUT3ATTN */
+#define WM8400_OUT4MUTE                         0x0002  /* OUT4MUTE */
+#define WM8400_OUT4MUTE_MASK                    0x0002  /* OUT4MUTE */
+#define WM8400_OUT4MUTE_SHIFT                        1  /* OUT4MUTE */
+#define WM8400_OUT4MUTE_WIDTH                        1  /* OUT4MUTE */
+#define WM8400_OUT4ATTN                         0x0001  /* OUT4ATTN */
+#define WM8400_OUT4ATTN_MASK                    0x0001  /* OUT4ATTN */
+#define WM8400_OUT4ATTN_SHIFT                        0  /* OUT4ATTN */
+#define WM8400_OUT4ATTN_WIDTH                        1  /* OUT4ATTN */
+
+/*
+ * R32 (0x20) - Left OPGA Volume
+ */
+#define WM8400_OPVU                             0x0100  /* OPVU */
+#define WM8400_OPVU_MASK                        0x0100  /* OPVU */
+#define WM8400_OPVU_SHIFT                            8  /* OPVU */
+#define WM8400_OPVU_WIDTH                            1  /* OPVU */
+#define WM8400_LOPGAZC                          0x0080  /* LOPGAZC */
+#define WM8400_LOPGAZC_MASK                     0x0080  /* LOPGAZC */
+#define WM8400_LOPGAZC_SHIFT                         7  /* LOPGAZC */
+#define WM8400_LOPGAZC_WIDTH                         1  /* LOPGAZC */
+#define WM8400_LOPGAVOL_MASK                    0x007F  /* LOPGAVOL - [6:0] */
+#define WM8400_LOPGAVOL_SHIFT                        0  /* LOPGAVOL - [6:0] */
+#define WM8400_LOPGAVOL_WIDTH                        7  /* LOPGAVOL - [6:0] */
+
+/*
+ * R33 (0x21) - Right OPGA Volume
+ */
+#define WM8400_OPVU                             0x0100  /* OPVU */
+#define WM8400_OPVU_MASK                        0x0100  /* OPVU */
+#define WM8400_OPVU_SHIFT                            8  /* OPVU */
+#define WM8400_OPVU_WIDTH                            1  /* OPVU */
+#define WM8400_ROPGAZC                          0x0080  /* ROPGAZC */
+#define WM8400_ROPGAZC_MASK                     0x0080  /* ROPGAZC */
+#define WM8400_ROPGAZC_SHIFT                         7  /* ROPGAZC */
+#define WM8400_ROPGAZC_WIDTH                         1  /* ROPGAZC */
+#define WM8400_ROPGAVOL_MASK                    0x007F  /* ROPGAVOL - [6:0] */
+#define WM8400_ROPGAVOL_SHIFT                        0  /* ROPGAVOL - [6:0] */
+#define WM8400_ROPGAVOL_WIDTH                        7  /* ROPGAVOL - [6:0] */
+
+/*
+ * R34 (0x22) - Speaker Volume
+ */
+#define WM8400_SPKATTN_MASK                     0x0003  /* SPKATTN - [1:0] */
+#define WM8400_SPKATTN_SHIFT                         0  /* SPKATTN - [1:0] */
+#define WM8400_SPKATTN_WIDTH                         2  /* SPKATTN - [1:0] */
+
+/*
+ * R35 (0x23) - ClassD1
+ */
+#define WM8400_CDMODE                           0x0100  /* CDMODE */
+#define WM8400_CDMODE_MASK                      0x0100  /* CDMODE */
+#define WM8400_CDMODE_SHIFT                          8  /* CDMODE */
+#define WM8400_CDMODE_WIDTH                          1  /* CDMODE */
+#define WM8400_CLASSD_CLK_SEL                   0x0080  /* CLASSD_CLK_SEL */
+#define WM8400_CLASSD_CLK_SEL_MASK              0x0080  /* CLASSD_CLK_SEL */
+#define WM8400_CLASSD_CLK_SEL_SHIFT                  7  /* CLASSD_CLK_SEL */
+#define WM8400_CLASSD_CLK_SEL_WIDTH                  1  /* CLASSD_CLK_SEL */
+#define WM8400_CD_SRCTRL                        0x0040  /* CD_SRCTRL */
+#define WM8400_CD_SRCTRL_MASK                   0x0040  /* CD_SRCTRL */
+#define WM8400_CD_SRCTRL_SHIFT                       6  /* CD_SRCTRL */
+#define WM8400_CD_SRCTRL_WIDTH                       1  /* CD_SRCTRL */
+#define WM8400_SPKNOPOP                         0x0020  /* SPKNOPOP */
+#define WM8400_SPKNOPOP_MASK                    0x0020  /* SPKNOPOP */
+#define WM8400_SPKNOPOP_SHIFT                        5  /* SPKNOPOP */
+#define WM8400_SPKNOPOP_WIDTH                        1  /* SPKNOPOP */
+#define WM8400_DBLERATE                         0x0010  /* DBLERATE */
+#define WM8400_DBLERATE_MASK                    0x0010  /* DBLERATE */
+#define WM8400_DBLERATE_SHIFT                        4  /* DBLERATE */
+#define WM8400_DBLERATE_WIDTH                        1  /* DBLERATE */
+#define WM8400_LOOPTEST                         0x0008  /* LOOPTEST */
+#define WM8400_LOOPTEST_MASK                    0x0008  /* LOOPTEST */
+#define WM8400_LOOPTEST_SHIFT                        3  /* LOOPTEST */
+#define WM8400_LOOPTEST_WIDTH                        1  /* LOOPTEST */
+#define WM8400_HALFABBIAS                       0x0004  /* HALFABBIAS */
+#define WM8400_HALFABBIAS_MASK                  0x0004  /* HALFABBIAS */
+#define WM8400_HALFABBIAS_SHIFT                      2  /* HALFABBIAS */
+#define WM8400_HALFABBIAS_WIDTH                      1  /* HALFABBIAS */
+#define WM8400_TRIDEL_MASK                      0x0003  /* TRIDEL - [1:0] */
+#define WM8400_TRIDEL_SHIFT                          0  /* TRIDEL - [1:0] */
+#define WM8400_TRIDEL_WIDTH                          2  /* TRIDEL - [1:0] */
+
+/*
+ * R37 (0x25) - ClassD3
+ */
+#define WM8400_DCGAIN_MASK                      0x0038  /* DCGAIN - [5:3] */
+#define WM8400_DCGAIN_SHIFT                          3  /* DCGAIN - [5:3] */
+#define WM8400_DCGAIN_WIDTH                          3  /* DCGAIN - [5:3] */
+#define WM8400_ACGAIN_MASK                      0x0007  /* ACGAIN - [2:0] */
+#define WM8400_ACGAIN_SHIFT                          0  /* ACGAIN - [2:0] */
+#define WM8400_ACGAIN_WIDTH                          3  /* ACGAIN - [2:0] */
+
+/*
+ * R39 (0x27) - Input Mixer1
+ */
+#define WM8400_AINLMODE_MASK                    0x000C  /* AINLMODE - [3:2] */
+#define WM8400_AINLMODE_SHIFT                        2  /* AINLMODE - [3:2] */
+#define WM8400_AINLMODE_WIDTH                        2  /* AINLMODE - [3:2] */
+#define WM8400_AINRMODE_MASK                    0x0003  /* AINRMODE - [1:0] */
+#define WM8400_AINRMODE_SHIFT                        0  /* AINRMODE - [1:0] */
+#define WM8400_AINRMODE_WIDTH                        2  /* AINRMODE - [1:0] */
+
+/*
+ * R40 (0x28) - Input Mixer2
+ */
+#define WM8400_LMP4                             0x0080  /* LMP4 */
+#define WM8400_LMP4_MASK                        0x0080  /* LMP4 */
+#define WM8400_LMP4_SHIFT                            7  /* LMP4 */
+#define WM8400_LMP4_WIDTH                            1  /* LMP4 */
+#define WM8400_LMN3                             0x0040  /* LMN3 */
+#define WM8400_LMN3_MASK                        0x0040  /* LMN3 */
+#define WM8400_LMN3_SHIFT                            6  /* LMN3 */
+#define WM8400_LMN3_WIDTH                            1  /* LMN3 */
+#define WM8400_LMP2                             0x0020  /* LMP2 */
+#define WM8400_LMP2_MASK                        0x0020  /* LMP2 */
+#define WM8400_LMP2_SHIFT                            5  /* LMP2 */
+#define WM8400_LMP2_WIDTH                            1  /* LMP2 */
+#define WM8400_LMN1                             0x0010  /* LMN1 */
+#define WM8400_LMN1_MASK                        0x0010  /* LMN1 */
+#define WM8400_LMN1_SHIFT                            4  /* LMN1 */
+#define WM8400_LMN1_WIDTH                            1  /* LMN1 */
+#define WM8400_RMP4                             0x0008  /* RMP4 */
+#define WM8400_RMP4_MASK                        0x0008  /* RMP4 */
+#define WM8400_RMP4_SHIFT                            3  /* RMP4 */
+#define WM8400_RMP4_WIDTH                            1  /* RMP4 */
+#define WM8400_RMN3                             0x0004  /* RMN3 */
+#define WM8400_RMN3_MASK                        0x0004  /* RMN3 */
+#define WM8400_RMN3_SHIFT                            2  /* RMN3 */
+#define WM8400_RMN3_WIDTH                            1  /* RMN3 */
+#define WM8400_RMP2                             0x0002  /* RMP2 */
+#define WM8400_RMP2_MASK                        0x0002  /* RMP2 */
+#define WM8400_RMP2_SHIFT                            1  /* RMP2 */
+#define WM8400_RMP2_WIDTH                            1  /* RMP2 */
+#define WM8400_RMN1                             0x0001  /* RMN1 */
+#define WM8400_RMN1_MASK                        0x0001  /* RMN1 */
+#define WM8400_RMN1_SHIFT                            0  /* RMN1 */
+#define WM8400_RMN1_WIDTH                            1  /* RMN1 */
+
+/*
+ * R41 (0x29) - Input Mixer3
+ */
+#define WM8400_L34MNB                           0x0100  /* L34MNB */
+#define WM8400_L34MNB_MASK                      0x0100  /* L34MNB */
+#define WM8400_L34MNB_SHIFT                          8  /* L34MNB */
+#define WM8400_L34MNB_WIDTH                          1  /* L34MNB */
+#define WM8400_L34MNBST                         0x0080  /* L34MNBST */
+#define WM8400_L34MNBST_MASK                    0x0080  /* L34MNBST */
+#define WM8400_L34MNBST_SHIFT                        7  /* L34MNBST */
+#define WM8400_L34MNBST_WIDTH                        1  /* L34MNBST */
+#define WM8400_L12MNB                           0x0020  /* L12MNB */
+#define WM8400_L12MNB_MASK                      0x0020  /* L12MNB */
+#define WM8400_L12MNB_SHIFT                          5  /* L12MNB */
+#define WM8400_L12MNB_WIDTH                          1  /* L12MNB */
+#define WM8400_L12MNBST                         0x0010  /* L12MNBST */
+#define WM8400_L12MNBST_MASK                    0x0010  /* L12MNBST */
+#define WM8400_L12MNBST_SHIFT                        4  /* L12MNBST */
+#define WM8400_L12MNBST_WIDTH                        1  /* L12MNBST */
+#define WM8400_LDBVOL_MASK                      0x0007  /* LDBVOL - [2:0] */
+#define WM8400_LDBVOL_SHIFT                          0  /* LDBVOL - [2:0] */
+#define WM8400_LDBVOL_WIDTH                          3  /* LDBVOL - [2:0] */
+
+/*
+ * R42 (0x2A) - Input Mixer4
+ */
+#define WM8400_R34MNB                           0x0100  /* R34MNB */
+#define WM8400_R34MNB_MASK                      0x0100  /* R34MNB */
+#define WM8400_R34MNB_SHIFT                          8  /* R34MNB */
+#define WM8400_R34MNB_WIDTH                          1  /* R34MNB */
+#define WM8400_R34MNBST                         0x0080  /* R34MNBST */
+#define WM8400_R34MNBST_MASK                    0x0080  /* R34MNBST */
+#define WM8400_R34MNBST_SHIFT                        7  /* R34MNBST */
+#define WM8400_R34MNBST_WIDTH                        1  /* R34MNBST */
+#define WM8400_R12MNB                           0x0020  /* R12MNB */
+#define WM8400_R12MNB_MASK                      0x0020  /* R12MNB */
+#define WM8400_R12MNB_SHIFT                          5  /* R12MNB */
+#define WM8400_R12MNB_WIDTH                          1  /* R12MNB */
+#define WM8400_R12MNBST                         0x0010  /* R12MNBST */
+#define WM8400_R12MNBST_MASK                    0x0010  /* R12MNBST */
+#define WM8400_R12MNBST_SHIFT                        4  /* R12MNBST */
+#define WM8400_R12MNBST_WIDTH                        1  /* R12MNBST */
+#define WM8400_RDBVOL_MASK                      0x0007  /* RDBVOL - [2:0] */
+#define WM8400_RDBVOL_SHIFT                          0  /* RDBVOL - [2:0] */
+#define WM8400_RDBVOL_WIDTH                          3  /* RDBVOL - [2:0] */
+
+/*
+ * R43 (0x2B) - Input Mixer5
+ */
+#define WM8400_LI2BVOL_MASK                     0x01C0  /* LI2BVOL - [8:6] */
+#define WM8400_LI2BVOL_SHIFT                         6  /* LI2BVOL - [8:6] */
+#define WM8400_LI2BVOL_WIDTH                         3  /* LI2BVOL - [8:6] */
+#define WM8400_LR4BVOL_MASK                     0x0038  /* LR4BVOL - [5:3] */
+#define WM8400_LR4BVOL_SHIFT                         3  /* LR4BVOL - [5:3] */
+#define WM8400_LR4BVOL_WIDTH                         3  /* LR4BVOL - [5:3] */
+#define WM8400_LL4BVOL_MASK                     0x0007  /* LL4BVOL - [2:0] */
+#define WM8400_LL4BVOL_SHIFT                         0  /* LL4BVOL - [2:0] */
+#define WM8400_LL4BVOL_WIDTH                         3  /* LL4BVOL - [2:0] */
+
+/*
+ * R44 (0x2C) - Input Mixer6
+ */
+#define WM8400_RI2BVOL_MASK                     0x01C0  /* RI2BVOL - [8:6] */
+#define WM8400_RI2BVOL_SHIFT                         6  /* RI2BVOL - [8:6] */
+#define WM8400_RI2BVOL_WIDTH                         3  /* RI2BVOL - [8:6] */
+#define WM8400_RL4BVOL_MASK                     0x0038  /* RL4BVOL - [5:3] */
+#define WM8400_RL4BVOL_SHIFT                         3  /* RL4BVOL - [5:3] */
+#define WM8400_RL4BVOL_WIDTH                         3  /* RL4BVOL - [5:3] */
+#define WM8400_RR4BVOL_MASK                     0x0007  /* RR4BVOL - [2:0] */
+#define WM8400_RR4BVOL_SHIFT                         0  /* RR4BVOL - [2:0] */
+#define WM8400_RR4BVOL_WIDTH                         3  /* RR4BVOL - [2:0] */
+
+/*
+ * R45 (0x2D) - Output Mixer1
+ */
+#define WM8400_LRBLO                            0x0080  /* LRBLO */
+#define WM8400_LRBLO_MASK                       0x0080  /* LRBLO */
+#define WM8400_LRBLO_SHIFT                           7  /* LRBLO */
+#define WM8400_LRBLO_WIDTH                           1  /* LRBLO */
+#define WM8400_LLBLO                            0x0040  /* LLBLO */
+#define WM8400_LLBLO_MASK                       0x0040  /* LLBLO */
+#define WM8400_LLBLO_SHIFT                           6  /* LLBLO */
+#define WM8400_LLBLO_WIDTH                           1  /* LLBLO */
+#define WM8400_LRI3LO                           0x0020  /* LRI3LO */
+#define WM8400_LRI3LO_MASK                      0x0020  /* LRI3LO */
+#define WM8400_LRI3LO_SHIFT                          5  /* LRI3LO */
+#define WM8400_LRI3LO_WIDTH                          1  /* LRI3LO */
+#define WM8400_LLI3LO                           0x0010  /* LLI3LO */
+#define WM8400_LLI3LO_MASK                      0x0010  /* LLI3LO */
+#define WM8400_LLI3LO_SHIFT                          4  /* LLI3LO */
+#define WM8400_LLI3LO_WIDTH                          1  /* LLI3LO */
+#define WM8400_LR12LO                           0x0008  /* LR12LO */
+#define WM8400_LR12LO_MASK                      0x0008  /* LR12LO */
+#define WM8400_LR12LO_SHIFT                          3  /* LR12LO */
+#define WM8400_LR12LO_WIDTH                          1  /* LR12LO */
+#define WM8400_LL12LO                           0x0004  /* LL12LO */
+#define WM8400_LL12LO_MASK                      0x0004  /* LL12LO */
+#define WM8400_LL12LO_SHIFT                          2  /* LL12LO */
+#define WM8400_LL12LO_WIDTH                          1  /* LL12LO */
+#define WM8400_LDLO                             0x0001  /* LDLO */
+#define WM8400_LDLO_MASK                        0x0001  /* LDLO */
+#define WM8400_LDLO_SHIFT                            0  /* LDLO */
+#define WM8400_LDLO_WIDTH                            1  /* LDLO */
+
+/*
+ * R46 (0x2E) - Output Mixer2
+ */
+#define WM8400_RLBRO                            0x0080  /* RLBRO */
+#define WM8400_RLBRO_MASK                       0x0080  /* RLBRO */
+#define WM8400_RLBRO_SHIFT                           7  /* RLBRO */
+#define WM8400_RLBRO_WIDTH                           1  /* RLBRO */
+#define WM8400_RRBRO                            0x0040  /* RRBRO */
+#define WM8400_RRBRO_MASK                       0x0040  /* RRBRO */
+#define WM8400_RRBRO_SHIFT                           6  /* RRBRO */
+#define WM8400_RRBRO_WIDTH                           1  /* RRBRO */
+#define WM8400_RLI3RO                           0x0020  /* RLI3RO */
+#define WM8400_RLI3RO_MASK                      0x0020  /* RLI3RO */
+#define WM8400_RLI3RO_SHIFT                          5  /* RLI3RO */
+#define WM8400_RLI3RO_WIDTH                          1  /* RLI3RO */
+#define WM8400_RRI3RO                           0x0010  /* RRI3RO */
+#define WM8400_RRI3RO_MASK                      0x0010  /* RRI3RO */
+#define WM8400_RRI3RO_SHIFT                          4  /* RRI3RO */
+#define WM8400_RRI3RO_WIDTH                          1  /* RRI3RO */
+#define WM8400_RL12RO                           0x0008  /* RL12RO */
+#define WM8400_RL12RO_MASK                      0x0008  /* RL12RO */
+#define WM8400_RL12RO_SHIFT                          3  /* RL12RO */
+#define WM8400_RL12RO_WIDTH                          1  /* RL12RO */
+#define WM8400_RR12RO                           0x0004  /* RR12RO */
+#define WM8400_RR12RO_MASK                      0x0004  /* RR12RO */
+#define WM8400_RR12RO_SHIFT                          2  /* RR12RO */
+#define WM8400_RR12RO_WIDTH                          1  /* RR12RO */
+#define WM8400_RDRO                             0x0001  /* RDRO */
+#define WM8400_RDRO_MASK                        0x0001  /* RDRO */
+#define WM8400_RDRO_SHIFT                            0  /* RDRO */
+#define WM8400_RDRO_WIDTH                            1  /* RDRO */
+
+/*
+ * R47 (0x2F) - Output Mixer3
+ */
+#define WM8400_LLI3LOVOL_MASK                   0x01C0  /* LLI3LOVOL - [8:6] */
+#define WM8400_LLI3LOVOL_SHIFT                       6  /* LLI3LOVOL - [8:6] */
+#define WM8400_LLI3LOVOL_WIDTH                       3  /* LLI3LOVOL - [8:6] */
+#define WM8400_LR12LOVOL_MASK                   0x0038  /* LR12LOVOL - [5:3] */
+#define WM8400_LR12LOVOL_SHIFT                       3  /* LR12LOVOL - [5:3] */
+#define WM8400_LR12LOVOL_WIDTH                       3  /* LR12LOVOL - [5:3] */
+#define WM8400_LL12LOVOL_MASK                   0x0007  /* LL12LOVOL - [2:0] */
+#define WM8400_LL12LOVOL_SHIFT                       0  /* LL12LOVOL - [2:0] */
+#define WM8400_LL12LOVOL_WIDTH                       3  /* LL12LOVOL - [2:0] */
+
+/*
+ * R48 (0x30) - Output Mixer4
+ */
+#define WM8400_RRI3ROVOL_MASK                   0x01C0  /* RRI3ROVOL - [8:6] */
+#define WM8400_RRI3ROVOL_SHIFT                       6  /* RRI3ROVOL - [8:6] */
+#define WM8400_RRI3ROVOL_WIDTH                       3  /* RRI3ROVOL - [8:6] */
+#define WM8400_RL12ROVOL_MASK                   0x0038  /* RL12ROVOL - [5:3] */
+#define WM8400_RL12ROVOL_SHIFT                       3  /* RL12ROVOL - [5:3] */
+#define WM8400_RL12ROVOL_WIDTH                       3  /* RL12ROVOL - [5:3] */
+#define WM8400_RR12ROVOL_MASK                   0x0007  /* RR12ROVOL - [2:0] */
+#define WM8400_RR12ROVOL_SHIFT                       0  /* RR12ROVOL - [2:0] */
+#define WM8400_RR12ROVOL_WIDTH                       3  /* RR12ROVOL - [2:0] */
+
+/*
+ * R49 (0x31) - Output Mixer5
+ */
+#define WM8400_LRI3LOVOL_MASK                   0x01C0  /* LRI3LOVOL - [8:6] */
+#define WM8400_LRI3LOVOL_SHIFT                       6  /* LRI3LOVOL - [8:6] */
+#define WM8400_LRI3LOVOL_WIDTH                       3  /* LRI3LOVOL - [8:6] */
+#define WM8400_LRBLOVOL_MASK                    0x0038  /* LRBLOVOL - [5:3] */
+#define WM8400_LRBLOVOL_SHIFT                        3  /* LRBLOVOL - [5:3] */
+#define WM8400_LRBLOVOL_WIDTH                        3  /* LRBLOVOL - [5:3] */
+#define WM8400_LLBLOVOL_MASK                    0x0007  /* LLBLOVOL - [2:0] */
+#define WM8400_LLBLOVOL_SHIFT                        0  /* LLBLOVOL - [2:0] */
+#define WM8400_LLBLOVOL_WIDTH                        3  /* LLBLOVOL - [2:0] */
+
+/*
+ * R50 (0x32) - Output Mixer6
+ */
+#define WM8400_RLI3ROVOL_MASK                   0x01C0  /* RLI3ROVOL - [8:6] */
+#define WM8400_RLI3ROVOL_SHIFT                       6  /* RLI3ROVOL - [8:6] */
+#define WM8400_RLI3ROVOL_WIDTH                       3  /* RLI3ROVOL - [8:6] */
+#define WM8400_RLBROVOL_MASK                    0x0038  /* RLBROVOL - [5:3] */
+#define WM8400_RLBROVOL_SHIFT                        3  /* RLBROVOL - [5:3] */
+#define WM8400_RLBROVOL_WIDTH                        3  /* RLBROVOL - [5:3] */
+#define WM8400_RRBROVOL_MASK                    0x0007  /* RRBROVOL - [2:0] */
+#define WM8400_RRBROVOL_SHIFT                        0  /* RRBROVOL - [2:0] */
+#define WM8400_RRBROVOL_WIDTH                        3  /* RRBROVOL - [2:0] */
+
+/*
+ * R51 (0x33) - Out3/4 Mixer
+ */
+#define WM8400_VSEL_MASK                        0x0180  /* VSEL - [8:7] */
+#define WM8400_VSEL_SHIFT                            7  /* VSEL - [8:7] */
+#define WM8400_VSEL_WIDTH                            2  /* VSEL - [8:7] */
+#define WM8400_LI4O3                            0x0020  /* LI4O3 */
+#define WM8400_LI4O3_MASK                       0x0020  /* LI4O3 */
+#define WM8400_LI4O3_SHIFT                           5  /* LI4O3 */
+#define WM8400_LI4O3_WIDTH                           1  /* LI4O3 */
+#define WM8400_LPGAO3                           0x0010  /* LPGAO3 */
+#define WM8400_LPGAO3_MASK                      0x0010  /* LPGAO3 */
+#define WM8400_LPGAO3_SHIFT                          4  /* LPGAO3 */
+#define WM8400_LPGAO3_WIDTH                          1  /* LPGAO3 */
+#define WM8400_RI4O4                            0x0002  /* RI4O4 */
+#define WM8400_RI4O4_MASK                       0x0002  /* RI4O4 */
+#define WM8400_RI4O4_SHIFT                           1  /* RI4O4 */
+#define WM8400_RI4O4_WIDTH                           1  /* RI4O4 */
+#define WM8400_RPGAO4                           0x0001  /* RPGAO4 */
+#define WM8400_RPGAO4_MASK                      0x0001  /* RPGAO4 */
+#define WM8400_RPGAO4_SHIFT                          0  /* RPGAO4 */
+#define WM8400_RPGAO4_WIDTH                          1  /* RPGAO4 */
+
+/*
+ * R52 (0x34) - Line Mixer1
+ */
+#define WM8400_LLOPGALON                        0x0040  /* LLOPGALON */
+#define WM8400_LLOPGALON_MASK                   0x0040  /* LLOPGALON */
+#define WM8400_LLOPGALON_SHIFT                       6  /* LLOPGALON */
+#define WM8400_LLOPGALON_WIDTH                       1  /* LLOPGALON */
+#define WM8400_LROPGALON                        0x0020  /* LROPGALON */
+#define WM8400_LROPGALON_MASK                   0x0020  /* LROPGALON */
+#define WM8400_LROPGALON_SHIFT                       5  /* LROPGALON */
+#define WM8400_LROPGALON_WIDTH                       1  /* LROPGALON */
+#define WM8400_LOPLON                           0x0010  /* LOPLON */
+#define WM8400_LOPLON_MASK                      0x0010  /* LOPLON */
+#define WM8400_LOPLON_SHIFT                          4  /* LOPLON */
+#define WM8400_LOPLON_WIDTH                          1  /* LOPLON */
+#define WM8400_LR12LOP                          0x0004  /* LR12LOP */
+#define WM8400_LR12LOP_MASK                     0x0004  /* LR12LOP */
+#define WM8400_LR12LOP_SHIFT                         2  /* LR12LOP */
+#define WM8400_LR12LOP_WIDTH                         1  /* LR12LOP */
+#define WM8400_LL12LOP                          0x0002  /* LL12LOP */
+#define WM8400_LL12LOP_MASK                     0x0002  /* LL12LOP */
+#define WM8400_LL12LOP_SHIFT                         1  /* LL12LOP */
+#define WM8400_LL12LOP_WIDTH                         1  /* LL12LOP */
+#define WM8400_LLOPGALOP                        0x0001  /* LLOPGALOP */
+#define WM8400_LLOPGALOP_MASK                   0x0001  /* LLOPGALOP */
+#define WM8400_LLOPGALOP_SHIFT                       0  /* LLOPGALOP */
+#define WM8400_LLOPGALOP_WIDTH                       1  /* LLOPGALOP */
+
+/*
+ * R53 (0x35) - Line Mixer2
+ */
+#define WM8400_RROPGARON                        0x0040  /* RROPGARON */
+#define WM8400_RROPGARON_MASK                   0x0040  /* RROPGARON */
+#define WM8400_RROPGARON_SHIFT                       6  /* RROPGARON */
+#define WM8400_RROPGARON_WIDTH                       1  /* RROPGARON */
+#define WM8400_RLOPGARON                        0x0020  /* RLOPGARON */
+#define WM8400_RLOPGARON_MASK                   0x0020  /* RLOPGARON */
+#define WM8400_RLOPGARON_SHIFT                       5  /* RLOPGARON */
+#define WM8400_RLOPGARON_WIDTH                       1  /* RLOPGARON */
+#define WM8400_ROPRON                           0x0010  /* ROPRON */
+#define WM8400_ROPRON_MASK                      0x0010  /* ROPRON */
+#define WM8400_ROPRON_SHIFT                          4  /* ROPRON */
+#define WM8400_ROPRON_WIDTH                          1  /* ROPRON */
+#define WM8400_RL12ROP                          0x0004  /* RL12ROP */
+#define WM8400_RL12ROP_MASK                     0x0004  /* RL12ROP */
+#define WM8400_RL12ROP_SHIFT                         2  /* RL12ROP */
+#define WM8400_RL12ROP_WIDTH                         1  /* RL12ROP */
+#define WM8400_RR12ROP                          0x0002  /* RR12ROP */
+#define WM8400_RR12ROP_MASK                     0x0002  /* RR12ROP */
+#define WM8400_RR12ROP_SHIFT                         1  /* RR12ROP */
+#define WM8400_RR12ROP_WIDTH                         1  /* RR12ROP */
+#define WM8400_RROPGAROP                        0x0001  /* RROPGAROP */
+#define WM8400_RROPGAROP_MASK                   0x0001  /* RROPGAROP */
+#define WM8400_RROPGAROP_SHIFT                       0  /* RROPGAROP */
+#define WM8400_RROPGAROP_WIDTH                       1  /* RROPGAROP */
+
+/*
+ * R54 (0x36) - Speaker Mixer
+ */
+#define WM8400_LB2SPK                           0x0080  /* LB2SPK */
+#define WM8400_LB2SPK_MASK                      0x0080  /* LB2SPK */
+#define WM8400_LB2SPK_SHIFT                          7  /* LB2SPK */
+#define WM8400_LB2SPK_WIDTH                          1  /* LB2SPK */
+#define WM8400_RB2SPK                           0x0040  /* RB2SPK */
+#define WM8400_RB2SPK_MASK                      0x0040  /* RB2SPK */
+#define WM8400_RB2SPK_SHIFT                          6  /* RB2SPK */
+#define WM8400_RB2SPK_WIDTH                          1  /* RB2SPK */
+#define WM8400_LI2SPK                           0x0020  /* LI2SPK */
+#define WM8400_LI2SPK_MASK                      0x0020  /* LI2SPK */
+#define WM8400_LI2SPK_SHIFT                          5  /* LI2SPK */
+#define WM8400_LI2SPK_WIDTH                          1  /* LI2SPK */
+#define WM8400_RI2SPK                           0x0010  /* RI2SPK */
+#define WM8400_RI2SPK_MASK                      0x0010  /* RI2SPK */
+#define WM8400_RI2SPK_SHIFT                          4  /* RI2SPK */
+#define WM8400_RI2SPK_WIDTH                          1  /* RI2SPK */
+#define WM8400_LOPGASPK                         0x0008  /* LOPGASPK */
+#define WM8400_LOPGASPK_MASK                    0x0008  /* LOPGASPK */
+#define WM8400_LOPGASPK_SHIFT                        3  /* LOPGASPK */
+#define WM8400_LOPGASPK_WIDTH                        1  /* LOPGASPK */
+#define WM8400_ROPGASPK                         0x0004  /* ROPGASPK */
+#define WM8400_ROPGASPK_MASK                    0x0004  /* ROPGASPK */
+#define WM8400_ROPGASPK_SHIFT                        2  /* ROPGASPK */
+#define WM8400_ROPGASPK_WIDTH                        1  /* ROPGASPK */
+#define WM8400_LDSPK                            0x0002  /* LDSPK */
+#define WM8400_LDSPK_MASK                       0x0002  /* LDSPK */
+#define WM8400_LDSPK_SHIFT                           1  /* LDSPK */
+#define WM8400_LDSPK_WIDTH                           1  /* LDSPK */
+#define WM8400_RDSPK                            0x0001  /* RDSPK */
+#define WM8400_RDSPK_MASK                       0x0001  /* RDSPK */
+#define WM8400_RDSPK_SHIFT                           0  /* RDSPK */
+#define WM8400_RDSPK_WIDTH                           1  /* RDSPK */
+
+/*
+ * R55 (0x37) - Additional Control
+ */
+#define WM8400_VROI                             0x0001  /* VROI */
+#define WM8400_VROI_MASK                        0x0001  /* VROI */
+#define WM8400_VROI_SHIFT                            0  /* VROI */
+#define WM8400_VROI_WIDTH                            1  /* VROI */
+
+/*
+ * R56 (0x38) - AntiPOP1
+ */
+#define WM8400_DIS_LLINE                        0x0020  /* DIS_LLINE */
+#define WM8400_DIS_LLINE_MASK                   0x0020  /* DIS_LLINE */
+#define WM8400_DIS_LLINE_SHIFT                       5  /* DIS_LLINE */
+#define WM8400_DIS_LLINE_WIDTH                       1  /* DIS_LLINE */
+#define WM8400_DIS_RLINE                        0x0010  /* DIS_RLINE */
+#define WM8400_DIS_RLINE_MASK                   0x0010  /* DIS_RLINE */
+#define WM8400_DIS_RLINE_SHIFT                       4  /* DIS_RLINE */
+#define WM8400_DIS_RLINE_WIDTH                       1  /* DIS_RLINE */
+#define WM8400_DIS_OUT3                         0x0008  /* DIS_OUT3 */
+#define WM8400_DIS_OUT3_MASK                    0x0008  /* DIS_OUT3 */
+#define WM8400_DIS_OUT3_SHIFT                        3  /* DIS_OUT3 */
+#define WM8400_DIS_OUT3_WIDTH                        1  /* DIS_OUT3 */
+#define WM8400_DIS_OUT4                         0x0004  /* DIS_OUT4 */
+#define WM8400_DIS_OUT4_MASK                    0x0004  /* DIS_OUT4 */
+#define WM8400_DIS_OUT4_SHIFT                        2  /* DIS_OUT4 */
+#define WM8400_DIS_OUT4_WIDTH                        1  /* DIS_OUT4 */
+#define WM8400_DIS_LOUT                         0x0002  /* DIS_LOUT */
+#define WM8400_DIS_LOUT_MASK                    0x0002  /* DIS_LOUT */
+#define WM8400_DIS_LOUT_SHIFT                        1  /* DIS_LOUT */
+#define WM8400_DIS_LOUT_WIDTH                        1  /* DIS_LOUT */
+#define WM8400_DIS_ROUT                         0x0001  /* DIS_ROUT */
+#define WM8400_DIS_ROUT_MASK                    0x0001  /* DIS_ROUT */
+#define WM8400_DIS_ROUT_SHIFT                        0  /* DIS_ROUT */
+#define WM8400_DIS_ROUT_WIDTH                        1  /* DIS_ROUT */
+
+/*
+ * R57 (0x39) - AntiPOP2
+ */
+#define WM8400_SOFTST                           0x0040  /* SOFTST */
+#define WM8400_SOFTST_MASK                      0x0040  /* SOFTST */
+#define WM8400_SOFTST_SHIFT                          6  /* SOFTST */
+#define WM8400_SOFTST_WIDTH                          1  /* SOFTST */
+#define WM8400_BUFIOEN                          0x0008  /* BUFIOEN */
+#define WM8400_BUFIOEN_MASK                     0x0008  /* BUFIOEN */
+#define WM8400_BUFIOEN_SHIFT                         3  /* BUFIOEN */
+#define WM8400_BUFIOEN_WIDTH                         1  /* BUFIOEN */
+#define WM8400_BUFDCOPEN                        0x0004  /* BUFDCOPEN */
+#define WM8400_BUFDCOPEN_MASK                   0x0004  /* BUFDCOPEN */
+#define WM8400_BUFDCOPEN_SHIFT                       2  /* BUFDCOPEN */
+#define WM8400_BUFDCOPEN_WIDTH                       1  /* BUFDCOPEN */
+#define WM8400_POBCTRL                          0x0002  /* POBCTRL */
+#define WM8400_POBCTRL_MASK                     0x0002  /* POBCTRL */
+#define WM8400_POBCTRL_SHIFT                         1  /* POBCTRL */
+#define WM8400_POBCTRL_WIDTH                         1  /* POBCTRL */
+#define WM8400_VMIDTOG                          0x0001  /* VMIDTOG */
+#define WM8400_VMIDTOG_MASK                     0x0001  /* VMIDTOG */
+#define WM8400_VMIDTOG_SHIFT                         0  /* VMIDTOG */
+#define WM8400_VMIDTOG_WIDTH                         1  /* VMIDTOG */
+
+/*
+ * R58 (0x3A) - MICBIAS
+ */
+#define WM8400_MCDSCTH_MASK                     0x00C0  /* MCDSCTH - [7:6] */
+#define WM8400_MCDSCTH_SHIFT                         6  /* MCDSCTH - [7:6] */
+#define WM8400_MCDSCTH_WIDTH                         2  /* MCDSCTH - [7:6] */
+#define WM8400_MCDTHR_MASK                      0x0038  /* MCDTHR - [5:3] */
+#define WM8400_MCDTHR_SHIFT                          3  /* MCDTHR - [5:3] */
+#define WM8400_MCDTHR_WIDTH                          3  /* MCDTHR - [5:3] */
+#define WM8400_MCD                              0x0004  /* MCD */
+#define WM8400_MCD_MASK                         0x0004  /* MCD */
+#define WM8400_MCD_SHIFT                             2  /* MCD */
+#define WM8400_MCD_WIDTH                             1  /* MCD */
+#define WM8400_MBSEL                            0x0001  /* MBSEL */
+#define WM8400_MBSEL_MASK                       0x0001  /* MBSEL */
+#define WM8400_MBSEL_SHIFT                           0  /* MBSEL */
+#define WM8400_MBSEL_WIDTH                           1  /* MBSEL */
+
+/*
+ * R60 (0x3C) - FLL Control 1
+ */
+#define WM8400_FLL_REF_FREQ                     0x1000  /* FLL_REF_FREQ */
+#define WM8400_FLL_REF_FREQ_MASK                0x1000  /* FLL_REF_FREQ */
+#define WM8400_FLL_REF_FREQ_SHIFT                   12  /* FLL_REF_FREQ */
+#define WM8400_FLL_REF_FREQ_WIDTH                    1  /* FLL_REF_FREQ */
+#define WM8400_FLL_CLK_SRC_MASK                 0x0C00  /* FLL_CLK_SRC - [11:10] */
+#define WM8400_FLL_CLK_SRC_SHIFT                    10  /* FLL_CLK_SRC - [11:10] */
+#define WM8400_FLL_CLK_SRC_WIDTH                     2  /* FLL_CLK_SRC - [11:10] */
+#define WM8400_FLL_FRAC                         0x0200  /* FLL_FRAC */
+#define WM8400_FLL_FRAC_MASK                    0x0200  /* FLL_FRAC */
+#define WM8400_FLL_FRAC_SHIFT                        9  /* FLL_FRAC */
+#define WM8400_FLL_FRAC_WIDTH                        1  /* FLL_FRAC */
+#define WM8400_FLL_OSC_ENA                      0x0100  /* FLL_OSC_ENA */
+#define WM8400_FLL_OSC_ENA_MASK                 0x0100  /* FLL_OSC_ENA */
+#define WM8400_FLL_OSC_ENA_SHIFT                     8  /* FLL_OSC_ENA */
+#define WM8400_FLL_OSC_ENA_WIDTH                     1  /* FLL_OSC_ENA */
+#define WM8400_FLL_CTRL_RATE_MASK               0x00E0  /* FLL_CTRL_RATE - [7:5] */
+#define WM8400_FLL_CTRL_RATE_SHIFT                   5  /* FLL_CTRL_RATE - [7:5] */
+#define WM8400_FLL_CTRL_RATE_WIDTH                   3  /* FLL_CTRL_RATE - [7:5] */
+#define WM8400_FLL_FRATIO_MASK                  0x001F  /* FLL_FRATIO - [4:0] */
+#define WM8400_FLL_FRATIO_SHIFT                      0  /* FLL_FRATIO - [4:0] */
+#define WM8400_FLL_FRATIO_WIDTH                      5  /* FLL_FRATIO - [4:0] */
+
+/*
+ * R61 (0x3D) - FLL Control 2
+ */
+#define WM8400_FLL_K_MASK                       0xFFFF  /* FLL_K - [15:0] */
+#define WM8400_FLL_K_SHIFT                           0  /* FLL_K - [15:0] */
+#define WM8400_FLL_K_WIDTH                          16  /* FLL_K - [15:0] */
+
+/*
+ * R62 (0x3E) - FLL Control 3
+ */
+#define WM8400_FLL_N_MASK                       0x03FF  /* FLL_N - [9:0] */
+#define WM8400_FLL_N_SHIFT                           0  /* FLL_N - [9:0] */
+#define WM8400_FLL_N_WIDTH                          10  /* FLL_N - [9:0] */
+
+/*
+ * R63 (0x3F) - FLL Control 4
+ */
+#define WM8400_FLL_TRK_GAIN_MASK                0x0078  /* FLL_TRK_GAIN - [6:3] */
+#define WM8400_FLL_TRK_GAIN_SHIFT                    3  /* FLL_TRK_GAIN - [6:3] */
+#define WM8400_FLL_TRK_GAIN_WIDTH                    4  /* FLL_TRK_GAIN - [6:3] */
+#define WM8400_FLL_OUTDIV_MASK                  0x0007  /* FLL_OUTDIV - [2:0] */
+#define WM8400_FLL_OUTDIV_SHIFT                      0  /* FLL_OUTDIV - [2:0] */
+#define WM8400_FLL_OUTDIV_WIDTH                      3  /* FLL_OUTDIV - [2:0] */
+
+void wm8400_reset_codec_reg_cache(struct wm8400 *wm8400);
+
+#endif
diff --git a/include/linux/mfd/wm8400-private.h b/include/linux/mfd/wm8400-private.h
new file mode 100644
index 0000000..2aab4e9
--- /dev/null
+++ b/include/linux/mfd/wm8400-private.h
@@ -0,0 +1,936 @@
+/*
+ * wm8400 private definitions.
+ *
+ * Copyright 2008 Wolfson Microelectronics plc
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __LINUX_MFD_WM8400_PRIV_H
+#define __LINUX_MFD_WM8400_PRIV_H
+
+#include <linux/mfd/wm8400.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+
+#define WM8400_REGISTER_COUNT 0x55
+
+struct wm8400 {
+	struct device *dev;
+
+	int (*read_dev)(void *data, char reg, int count, u16 *dst);
+	int (*write_dev)(void *data, char reg, int count, const u16 *src);
+
+	struct mutex io_lock;
+	void *io_data;
+
+	u16 reg_cache[WM8400_REGISTER_COUNT];
+
+	struct platform_device regulators[6];
+};
+
+/*
+ * Register values.
+ */
+#define WM8400_RESET_ID                         0x00
+#define WM8400_ID                               0x01
+#define WM8400_POWER_MANAGEMENT_1               0x02
+#define WM8400_POWER_MANAGEMENT_2               0x03
+#define WM8400_POWER_MANAGEMENT_3               0x04
+#define WM8400_AUDIO_INTERFACE_1                0x05
+#define WM8400_AUDIO_INTERFACE_2                0x06
+#define WM8400_CLOCKING_1                       0x07
+#define WM8400_CLOCKING_2                       0x08
+#define WM8400_AUDIO_INTERFACE_3                0x09
+#define WM8400_AUDIO_INTERFACE_4                0x0A
+#define WM8400_DAC_CTRL                         0x0B
+#define WM8400_LEFT_DAC_DIGITAL_VOLUME          0x0C
+#define WM8400_RIGHT_DAC_DIGITAL_VOLUME         0x0D
+#define WM8400_DIGITAL_SIDE_TONE                0x0E
+#define WM8400_ADC_CTRL                         0x0F
+#define WM8400_LEFT_ADC_DIGITAL_VOLUME          0x10
+#define WM8400_RIGHT_ADC_DIGITAL_VOLUME         0x11
+#define WM8400_GPIO_CTRL_1                      0x12
+#define WM8400_GPIO1_GPIO2                      0x13
+#define WM8400_GPIO3_GPIO4                      0x14
+#define WM8400_GPIO5_GPIO6                      0x15
+#define WM8400_GPIOCTRL_2                       0x16
+#define WM8400_GPIO_POL                         0x17
+#define WM8400_LEFT_LINE_INPUT_1_2_VOLUME       0x18
+#define WM8400_LEFT_LINE_INPUT_3_4_VOLUME       0x19
+#define WM8400_RIGHT_LINE_INPUT_1_2_VOLUME      0x1A
+#define WM8400_RIGHT_LINE_INPUT_3_4_VOLUME      0x1B
+#define WM8400_LEFT_OUTPUT_VOLUME               0x1C
+#define WM8400_RIGHT_OUTPUT_VOLUME              0x1D
+#define WM8400_LINE_OUTPUTS_VOLUME              0x1E
+#define WM8400_OUT3_4_VOLUME                    0x1F
+#define WM8400_LEFT_OPGA_VOLUME                 0x20
+#define WM8400_RIGHT_OPGA_VOLUME                0x21
+#define WM8400_SPEAKER_VOLUME                   0x22
+#define WM8400_CLASSD1                          0x23
+#define WM8400_CLASSD3                          0x25
+#define WM8400_INPUT_MIXER1                     0x27
+#define WM8400_INPUT_MIXER2                     0x28
+#define WM8400_INPUT_MIXER3                     0x29
+#define WM8400_INPUT_MIXER4                     0x2A
+#define WM8400_INPUT_MIXER5                     0x2B
+#define WM8400_INPUT_MIXER6                     0x2C
+#define WM8400_OUTPUT_MIXER1                    0x2D
+#define WM8400_OUTPUT_MIXER2                    0x2E
+#define WM8400_OUTPUT_MIXER3                    0x2F
+#define WM8400_OUTPUT_MIXER4                    0x30
+#define WM8400_OUTPUT_MIXER5                    0x31
+#define WM8400_OUTPUT_MIXER6                    0x32
+#define WM8400_OUT3_4_MIXER                     0x33
+#define WM8400_LINE_MIXER1                      0x34
+#define WM8400_LINE_MIXER2                      0x35
+#define WM8400_SPEAKER_MIXER                    0x36
+#define WM8400_ADDITIONAL_CONTROL               0x37
+#define WM8400_ANTIPOP1                         0x38
+#define WM8400_ANTIPOP2                         0x39
+#define WM8400_MICBIAS                          0x3A
+#define WM8400_FLL_CONTROL_1                    0x3C
+#define WM8400_FLL_CONTROL_2                    0x3D
+#define WM8400_FLL_CONTROL_3                    0x3E
+#define WM8400_FLL_CONTROL_4                    0x3F
+#define WM8400_LDO1_CONTROL                     0x41
+#define WM8400_LDO2_CONTROL                     0x42
+#define WM8400_LDO3_CONTROL                     0x43
+#define WM8400_LDO4_CONTROL                     0x44
+#define WM8400_DCDC1_CONTROL_1                  0x46
+#define WM8400_DCDC1_CONTROL_2                  0x47
+#define WM8400_DCDC2_CONTROL_1                  0x48
+#define WM8400_DCDC2_CONTROL_2                  0x49
+#define WM8400_INTERFACE                        0x4B
+#define WM8400_PM_GENERAL                       0x4C
+#define WM8400_PM_SHUTDOWN_CONTROL              0x4E
+#define WM8400_INTERRUPT_STATUS_1               0x4F
+#define WM8400_INTERRUPT_STATUS_1_MASK          0x50
+#define WM8400_INTERRUPT_LEVELS                 0x51
+#define WM8400_SHUTDOWN_REASON                  0x52
+#define WM8400_LINE_CIRCUITS                    0x54
+
+/*
+ * Field Definitions.
+ */
+
+/*
+ * R0 (0x00) - Reset/ID
+ */
+#define WM8400_SW_RESET_CHIP_ID_MASK            0xFFFF  /* SW_RESET/CHIP_ID - [15:0] */
+#define WM8400_SW_RESET_CHIP_ID_SHIFT                0  /* SW_RESET/CHIP_ID - [15:0] */
+#define WM8400_SW_RESET_CHIP_ID_WIDTH               16  /* SW_RESET/CHIP_ID - [15:0] */
+
+/*
+ * R1 (0x01) - ID
+ */
+#define WM8400_CHIP_REV_MASK                    0x7000  /* CHIP_REV - [14:12] */
+#define WM8400_CHIP_REV_SHIFT                       12  /* CHIP_REV - [14:12] */
+#define WM8400_CHIP_REV_WIDTH                        3  /* CHIP_REV - [14:12] */
+
+/*
+ * R18 (0x12) - GPIO CTRL 1
+ */
+#define WM8400_IRQ                              0x1000  /* IRQ */
+#define WM8400_IRQ_MASK                         0x1000  /* IRQ */
+#define WM8400_IRQ_SHIFT                            12  /* IRQ */
+#define WM8400_IRQ_WIDTH                             1  /* IRQ */
+#define WM8400_TEMPOK                           0x0800  /* TEMPOK */
+#define WM8400_TEMPOK_MASK                      0x0800  /* TEMPOK */
+#define WM8400_TEMPOK_SHIFT                         11  /* TEMPOK */
+#define WM8400_TEMPOK_WIDTH                          1  /* TEMPOK */
+#define WM8400_MIC1SHRT                         0x0400  /* MIC1SHRT */
+#define WM8400_MIC1SHRT_MASK                    0x0400  /* MIC1SHRT */
+#define WM8400_MIC1SHRT_SHIFT                       10  /* MIC1SHRT */
+#define WM8400_MIC1SHRT_WIDTH                        1  /* MIC1SHRT */
+#define WM8400_MIC1DET                          0x0200  /* MIC1DET */
+#define WM8400_MIC1DET_MASK                     0x0200  /* MIC1DET */
+#define WM8400_MIC1DET_SHIFT                         9  /* MIC1DET */
+#define WM8400_MIC1DET_WIDTH                         1  /* MIC1DET */
+#define WM8400_FLL_LCK                          0x0100  /* FLL_LCK */
+#define WM8400_FLL_LCK_MASK                     0x0100  /* FLL_LCK */
+#define WM8400_FLL_LCK_SHIFT                         8  /* FLL_LCK */
+#define WM8400_FLL_LCK_WIDTH                         1  /* FLL_LCK */
+#define WM8400_GPIO_STATUS_MASK                 0x00FF  /* GPIO_STATUS - [7:0] */
+#define WM8400_GPIO_STATUS_SHIFT                     0  /* GPIO_STATUS - [7:0] */
+#define WM8400_GPIO_STATUS_WIDTH                     8  /* GPIO_STATUS - [7:0] */
+
+/*
+ * R19 (0x13) - GPIO1 & GPIO2
+ */
+#define WM8400_GPIO2_DEB_ENA                    0x8000  /* GPIO2_DEB_ENA */
+#define WM8400_GPIO2_DEB_ENA_MASK               0x8000  /* GPIO2_DEB_ENA */
+#define WM8400_GPIO2_DEB_ENA_SHIFT                  15  /* GPIO2_DEB_ENA */
+#define WM8400_GPIO2_DEB_ENA_WIDTH                   1  /* GPIO2_DEB_ENA */
+#define WM8400_GPIO2_IRQ_ENA                    0x4000  /* GPIO2_IRQ_ENA */
+#define WM8400_GPIO2_IRQ_ENA_MASK               0x4000  /* GPIO2_IRQ_ENA */
+#define WM8400_GPIO2_IRQ_ENA_SHIFT                  14  /* GPIO2_IRQ_ENA */
+#define WM8400_GPIO2_IRQ_ENA_WIDTH                   1  /* GPIO2_IRQ_ENA */
+#define WM8400_GPIO2_PU                         0x2000  /* GPIO2_PU */
+#define WM8400_GPIO2_PU_MASK                    0x2000  /* GPIO2_PU */
+#define WM8400_GPIO2_PU_SHIFT                       13  /* GPIO2_PU */
+#define WM8400_GPIO2_PU_WIDTH                        1  /* GPIO2_PU */
+#define WM8400_GPIO2_PD                         0x1000  /* GPIO2_PD */
+#define WM8400_GPIO2_PD_MASK                    0x1000  /* GPIO2_PD */
+#define WM8400_GPIO2_PD_SHIFT                       12  /* GPIO2_PD */
+#define WM8400_GPIO2_PD_WIDTH                        1  /* GPIO2_PD */
+#define WM8400_GPIO2_SEL_MASK                   0x0F00  /* GPIO2_SEL - [11:8] */
+#define WM8400_GPIO2_SEL_SHIFT                       8  /* GPIO2_SEL - [11:8] */
+#define WM8400_GPIO2_SEL_WIDTH                       4  /* GPIO2_SEL - [11:8] */
+#define WM8400_GPIO1_DEB_ENA                    0x0080  /* GPIO1_DEB_ENA */
+#define WM8400_GPIO1_DEB_ENA_MASK               0x0080  /* GPIO1_DEB_ENA */
+#define WM8400_GPIO1_DEB_ENA_SHIFT                   7  /* GPIO1_DEB_ENA */
+#define WM8400_GPIO1_DEB_ENA_WIDTH                   1  /* GPIO1_DEB_ENA */
+#define WM8400_GPIO1_IRQ_ENA                    0x0040  /* GPIO1_IRQ_ENA */
+#define WM8400_GPIO1_IRQ_ENA_MASK               0x0040  /* GPIO1_IRQ_ENA */
+#define WM8400_GPIO1_IRQ_ENA_SHIFT                   6  /* GPIO1_IRQ_ENA */
+#define WM8400_GPIO1_IRQ_ENA_WIDTH                   1  /* GPIO1_IRQ_ENA */
+#define WM8400_GPIO1_PU                         0x0020  /* GPIO1_PU */
+#define WM8400_GPIO1_PU_MASK                    0x0020  /* GPIO1_PU */
+#define WM8400_GPIO1_PU_SHIFT                        5  /* GPIO1_PU */
+#define WM8400_GPIO1_PU_WIDTH                        1  /* GPIO1_PU */
+#define WM8400_GPIO1_PD                         0x0010  /* GPIO1_PD */
+#define WM8400_GPIO1_PD_MASK                    0x0010  /* GPIO1_PD */
+#define WM8400_GPIO1_PD_SHIFT                        4  /* GPIO1_PD */
+#define WM8400_GPIO1_PD_WIDTH                        1  /* GPIO1_PD */
+#define WM8400_GPIO1_SEL_MASK                   0x000F  /* GPIO1_SEL - [3:0] */
+#define WM8400_GPIO1_SEL_SHIFT                       0  /* GPIO1_SEL - [3:0] */
+#define WM8400_GPIO1_SEL_WIDTH                       4  /* GPIO1_SEL - [3:0] */
+
+/*
+ * R20 (0x14) - GPIO3 & GPIO4
+ */
+#define WM8400_GPIO4_DEB_ENA                    0x8000  /* GPIO4_DEB_ENA */
+#define WM8400_GPIO4_DEB_ENA_MASK               0x8000  /* GPIO4_DEB_ENA */
+#define WM8400_GPIO4_DEB_ENA_SHIFT                  15  /* GPIO4_DEB_ENA */
+#define WM8400_GPIO4_DEB_ENA_WIDTH                   1  /* GPIO4_DEB_ENA */
+#define WM8400_GPIO4_IRQ_ENA                    0x4000  /* GPIO4_IRQ_ENA */
+#define WM8400_GPIO4_IRQ_ENA_MASK               0x4000  /* GPIO4_IRQ_ENA */
+#define WM8400_GPIO4_IRQ_ENA_SHIFT                  14  /* GPIO4_IRQ_ENA */
+#define WM8400_GPIO4_IRQ_ENA_WIDTH                   1  /* GPIO4_IRQ_ENA */
+#define WM8400_GPIO4_PU                         0x2000  /* GPIO4_PU */
+#define WM8400_GPIO4_PU_MASK                    0x2000  /* GPIO4_PU */
+#define WM8400_GPIO4_PU_SHIFT                       13  /* GPIO4_PU */
+#define WM8400_GPIO4_PU_WIDTH                        1  /* GPIO4_PU */
+#define WM8400_GPIO4_PD                         0x1000  /* GPIO4_PD */
+#define WM8400_GPIO4_PD_MASK                    0x1000  /* GPIO4_PD */
+#define WM8400_GPIO4_PD_SHIFT                       12  /* GPIO4_PD */
+#define WM8400_GPIO4_PD_WIDTH                        1  /* GPIO4_PD */
+#define WM8400_GPIO4_SEL_MASK                   0x0F00  /* GPIO4_SEL - [11:8] */
+#define WM8400_GPIO4_SEL_SHIFT                       8  /* GPIO4_SEL - [11:8] */
+#define WM8400_GPIO4_SEL_WIDTH                       4  /* GPIO4_SEL - [11:8] */
+#define WM8400_GPIO3_DEB_ENA                    0x0080  /* GPIO3_DEB_ENA */
+#define WM8400_GPIO3_DEB_ENA_MASK               0x0080  /* GPIO3_DEB_ENA */
+#define WM8400_GPIO3_DEB_ENA_SHIFT                   7  /* GPIO3_DEB_ENA */
+#define WM8400_GPIO3_DEB_ENA_WIDTH                   1  /* GPIO3_DEB_ENA */
+#define WM8400_GPIO3_IRQ_ENA                    0x0040  /* GPIO3_IRQ_ENA */
+#define WM8400_GPIO3_IRQ_ENA_MASK               0x0040  /* GPIO3_IRQ_ENA */
+#define WM8400_GPIO3_IRQ_ENA_SHIFT                   6  /* GPIO3_IRQ_ENA */
+#define WM8400_GPIO3_IRQ_ENA_WIDTH                   1  /* GPIO3_IRQ_ENA */
+#define WM8400_GPIO3_PU                         0x0020  /* GPIO3_PU */
+#define WM8400_GPIO3_PU_MASK                    0x0020  /* GPIO3_PU */
+#define WM8400_GPIO3_PU_SHIFT                        5  /* GPIO3_PU */
+#define WM8400_GPIO3_PU_WIDTH                        1  /* GPIO3_PU */
+#define WM8400_GPIO3_PD                         0x0010  /* GPIO3_PD */
+#define WM8400_GPIO3_PD_MASK                    0x0010  /* GPIO3_PD */
+#define WM8400_GPIO3_PD_SHIFT                        4  /* GPIO3_PD */
+#define WM8400_GPIO3_PD_WIDTH                        1  /* GPIO3_PD */
+#define WM8400_GPIO3_SEL_MASK                   0x000F  /* GPIO3_SEL - [3:0] */
+#define WM8400_GPIO3_SEL_SHIFT                       0  /* GPIO3_SEL - [3:0] */
+#define WM8400_GPIO3_SEL_WIDTH                       4  /* GPIO3_SEL - [3:0] */
+
+/*
+ * R21 (0x15) - GPIO5 & GPIO6
+ */
+#define WM8400_GPIO6_DEB_ENA                    0x8000  /* GPIO6_DEB_ENA */
+#define WM8400_GPIO6_DEB_ENA_MASK               0x8000  /* GPIO6_DEB_ENA */
+#define WM8400_GPIO6_DEB_ENA_SHIFT                  15  /* GPIO6_DEB_ENA */
+#define WM8400_GPIO6_DEB_ENA_WIDTH                   1  /* GPIO6_DEB_ENA */
+#define WM8400_GPIO6_IRQ_ENA                    0x4000  /* GPIO6_IRQ_ENA */
+#define WM8400_GPIO6_IRQ_ENA_MASK               0x4000  /* GPIO6_IRQ_ENA */
+#define WM8400_GPIO6_IRQ_ENA_SHIFT                  14  /* GPIO6_IRQ_ENA */
+#define WM8400_GPIO6_IRQ_ENA_WIDTH                   1  /* GPIO6_IRQ_ENA */
+#define WM8400_GPIO6_PU                         0x2000  /* GPIO6_PU */
+#define WM8400_GPIO6_PU_MASK                    0x2000  /* GPIO6_PU */
+#define WM8400_GPIO6_PU_SHIFT                       13  /* GPIO6_PU */
+#define WM8400_GPIO6_PU_WIDTH                        1  /* GPIO6_PU */
+#define WM8400_GPIO6_PD                         0x1000  /* GPIO6_PD */
+#define WM8400_GPIO6_PD_MASK                    0x1000  /* GPIO6_PD */
+#define WM8400_GPIO6_PD_SHIFT                       12  /* GPIO6_PD */
+#define WM8400_GPIO6_PD_WIDTH                        1  /* GPIO6_PD */
+#define WM8400_GPIO6_SEL_MASK                   0x0F00  /* GPIO6_SEL - [11:8] */
+#define WM8400_GPIO6_SEL_SHIFT                       8  /* GPIO6_SEL - [11:8] */
+#define WM8400_GPIO6_SEL_WIDTH                       4  /* GPIO6_SEL - [11:8] */
+#define WM8400_GPIO5_DEB_ENA                    0x0080  /* GPIO5_DEB_ENA */
+#define WM8400_GPIO5_DEB_ENA_MASK               0x0080  /* GPIO5_DEB_ENA */
+#define WM8400_GPIO5_DEB_ENA_SHIFT                   7  /* GPIO5_DEB_ENA */
+#define WM8400_GPIO5_DEB_ENA_WIDTH                   1  /* GPIO5_DEB_ENA */
+#define WM8400_GPIO5_IRQ_ENA                    0x0040  /* GPIO5_IRQ_ENA */
+#define WM8400_GPIO5_IRQ_ENA_MASK               0x0040  /* GPIO5_IRQ_ENA */
+#define WM8400_GPIO5_IRQ_ENA_SHIFT                   6  /* GPIO5_IRQ_ENA */
+#define WM8400_GPIO5_IRQ_ENA_WIDTH                   1  /* GPIO5_IRQ_ENA */
+#define WM8400_GPIO5_PU                         0x0020  /* GPIO5_PU */
+#define WM8400_GPIO5_PU_MASK                    0x0020  /* GPIO5_PU */
+#define WM8400_GPIO5_PU_SHIFT                        5  /* GPIO5_PU */
+#define WM8400_GPIO5_PU_WIDTH                        1  /* GPIO5_PU */
+#define WM8400_GPIO5_PD                         0x0010  /* GPIO5_PD */
+#define WM8400_GPIO5_PD_MASK                    0x0010  /* GPIO5_PD */
+#define WM8400_GPIO5_PD_SHIFT                        4  /* GPIO5_PD */
+#define WM8400_GPIO5_PD_WIDTH                        1  /* GPIO5_PD */
+#define WM8400_GPIO5_SEL_MASK                   0x000F  /* GPIO5_SEL - [3:0] */
+#define WM8400_GPIO5_SEL_SHIFT                       0  /* GPIO5_SEL - [3:0] */
+#define WM8400_GPIO5_SEL_WIDTH                       4  /* GPIO5_SEL - [3:0] */
+
+/*
+ * R22 (0x16) - GPIOCTRL 2
+ */
+#define WM8400_TEMPOK_IRQ_ENA                   0x0800  /* TEMPOK_IRQ_ENA */
+#define WM8400_TEMPOK_IRQ_ENA_MASK              0x0800  /* TEMPOK_IRQ_ENA */
+#define WM8400_TEMPOK_IRQ_ENA_SHIFT                 11  /* TEMPOK_IRQ_ENA */
+#define WM8400_TEMPOK_IRQ_ENA_WIDTH                  1  /* TEMPOK_IRQ_ENA */
+#define WM8400_MIC1SHRT_IRQ_ENA                 0x0400  /* MIC1SHRT_IRQ_ENA */
+#define WM8400_MIC1SHRT_IRQ_ENA_MASK            0x0400  /* MIC1SHRT_IRQ_ENA */
+#define WM8400_MIC1SHRT_IRQ_ENA_SHIFT               10  /* MIC1SHRT_IRQ_ENA */
+#define WM8400_MIC1SHRT_IRQ_ENA_WIDTH                1  /* MIC1SHRT_IRQ_ENA */
+#define WM8400_MIC1DET_IRQ_ENA                  0x0200  /* MIC1DET_IRQ_ENA */
+#define WM8400_MIC1DET_IRQ_ENA_MASK             0x0200  /* MIC1DET_IRQ_ENA */
+#define WM8400_MIC1DET_IRQ_ENA_SHIFT                 9  /* MIC1DET_IRQ_ENA */
+#define WM8400_MIC1DET_IRQ_ENA_WIDTH                 1  /* MIC1DET_IRQ_ENA */
+#define WM8400_FLL_LCK_IRQ_ENA                  0x0100  /* FLL_LCK_IRQ_ENA */
+#define WM8400_FLL_LCK_IRQ_ENA_MASK             0x0100  /* FLL_LCK_IRQ_ENA */
+#define WM8400_FLL_LCK_IRQ_ENA_SHIFT                 8  /* FLL_LCK_IRQ_ENA */
+#define WM8400_FLL_LCK_IRQ_ENA_WIDTH                 1  /* FLL_LCK_IRQ_ENA */
+#define WM8400_GPI8_DEB_ENA                     0x0080  /* GPI8_DEB_ENA */
+#define WM8400_GPI8_DEB_ENA_MASK                0x0080  /* GPI8_DEB_ENA */
+#define WM8400_GPI8_DEB_ENA_SHIFT                    7  /* GPI8_DEB_ENA */
+#define WM8400_GPI8_DEB_ENA_WIDTH                    1  /* GPI8_DEB_ENA */
+#define WM8400_GPI8_IRQ_ENA                     0x0040  /* GPI8_IRQ_ENA */
+#define WM8400_GPI8_IRQ_ENA_MASK                0x0040  /* GPI8_IRQ_ENA */
+#define WM8400_GPI8_IRQ_ENA_SHIFT                    6  /* GPI8_IRQ_ENA */
+#define WM8400_GPI8_IRQ_ENA_WIDTH                    1  /* GPI8_IRQ_ENA */
+#define WM8400_GPI8_ENA                         0x0010  /* GPI8_ENA */
+#define WM8400_GPI8_ENA_MASK                    0x0010  /* GPI8_ENA */
+#define WM8400_GPI8_ENA_SHIFT                        4  /* GPI8_ENA */
+#define WM8400_GPI8_ENA_WIDTH                        1  /* GPI8_ENA */
+#define WM8400_GPI7_DEB_ENA                     0x0008  /* GPI7_DEB_ENA */
+#define WM8400_GPI7_DEB_ENA_MASK                0x0008  /* GPI7_DEB_ENA */
+#define WM8400_GPI7_DEB_ENA_SHIFT                    3  /* GPI7_DEB_ENA */
+#define WM8400_GPI7_DEB_ENA_WIDTH                    1  /* GPI7_DEB_ENA */
+#define WM8400_GPI7_IRQ_ENA                     0x0004  /* GPI7_IRQ_ENA */
+#define WM8400_GPI7_IRQ_ENA_MASK                0x0004  /* GPI7_IRQ_ENA */
+#define WM8400_GPI7_IRQ_ENA_SHIFT                    2  /* GPI7_IRQ_ENA */
+#define WM8400_GPI7_IRQ_ENA_WIDTH                    1  /* GPI7_IRQ_ENA */
+#define WM8400_GPI7_ENA                         0x0001  /* GPI7_ENA */
+#define WM8400_GPI7_ENA_MASK                    0x0001  /* GPI7_ENA */
+#define WM8400_GPI7_ENA_SHIFT                        0  /* GPI7_ENA */
+#define WM8400_GPI7_ENA_WIDTH                        1  /* GPI7_ENA */
+
+/*
+ * R23 (0x17) - GPIO_POL
+ */
+#define WM8400_IRQ_INV                          0x1000  /* IRQ_INV */
+#define WM8400_IRQ_INV_MASK                     0x1000  /* IRQ_INV */
+#define WM8400_IRQ_INV_SHIFT                        12  /* IRQ_INV */
+#define WM8400_IRQ_INV_WIDTH                         1  /* IRQ_INV */
+#define WM8400_TEMPOK_POL                       0x0800  /* TEMPOK_POL */
+#define WM8400_TEMPOK_POL_MASK                  0x0800  /* TEMPOK_POL */
+#define WM8400_TEMPOK_POL_SHIFT                     11  /* TEMPOK_POL */
+#define WM8400_TEMPOK_POL_WIDTH                      1  /* TEMPOK_POL */
+#define WM8400_MIC1SHRT_POL                     0x0400  /* MIC1SHRT_POL */
+#define WM8400_MIC1SHRT_POL_MASK                0x0400  /* MIC1SHRT_POL */
+#define WM8400_MIC1SHRT_POL_SHIFT                   10  /* MIC1SHRT_POL */
+#define WM8400_MIC1SHRT_POL_WIDTH                    1  /* MIC1SHRT_POL */
+#define WM8400_MIC1DET_POL                      0x0200  /* MIC1DET_POL */
+#define WM8400_MIC1DET_POL_MASK                 0x0200  /* MIC1DET_POL */
+#define WM8400_MIC1DET_POL_SHIFT                     9  /* MIC1DET_POL */
+#define WM8400_MIC1DET_POL_WIDTH                     1  /* MIC1DET_POL */
+#define WM8400_FLL_LCK_POL                      0x0100  /* FLL_LCK_POL */
+#define WM8400_FLL_LCK_POL_MASK                 0x0100  /* FLL_LCK_POL */
+#define WM8400_FLL_LCK_POL_SHIFT                     8  /* FLL_LCK_POL */
+#define WM8400_FLL_LCK_POL_WIDTH                     1  /* FLL_LCK_POL */
+#define WM8400_GPIO_POL_MASK                    0x00FF  /* GPIO_POL - [7:0] */
+#define WM8400_GPIO_POL_SHIFT                        0  /* GPIO_POL - [7:0] */
+#define WM8400_GPIO_POL_WIDTH                        8  /* GPIO_POL - [7:0] */
+
+/*
+ * R65 (0x41) - LDO 1 Control
+ */
+#define WM8400_LDO1_ENA                         0x8000  /* LDO1_ENA */
+#define WM8400_LDO1_ENA_MASK                    0x8000  /* LDO1_ENA */
+#define WM8400_LDO1_ENA_SHIFT                       15  /* LDO1_ENA */
+#define WM8400_LDO1_ENA_WIDTH                        1  /* LDO1_ENA */
+#define WM8400_LDO1_SWI                         0x4000  /* LDO1_SWI */
+#define WM8400_LDO1_SWI_MASK                    0x4000  /* LDO1_SWI */
+#define WM8400_LDO1_SWI_SHIFT                       14  /* LDO1_SWI */
+#define WM8400_LDO1_SWI_WIDTH                        1  /* LDO1_SWI */
+#define WM8400_LDO1_OPFLT                       0x1000  /* LDO1_OPFLT */
+#define WM8400_LDO1_OPFLT_MASK                  0x1000  /* LDO1_OPFLT */
+#define WM8400_LDO1_OPFLT_SHIFT                     12  /* LDO1_OPFLT */
+#define WM8400_LDO1_OPFLT_WIDTH                      1  /* LDO1_OPFLT */
+#define WM8400_LDO1_ERRACT                      0x0800  /* LDO1_ERRACT */
+#define WM8400_LDO1_ERRACT_MASK                 0x0800  /* LDO1_ERRACT */
+#define WM8400_LDO1_ERRACT_SHIFT                    11  /* LDO1_ERRACT */
+#define WM8400_LDO1_ERRACT_WIDTH                     1  /* LDO1_ERRACT */
+#define WM8400_LDO1_HIB_MODE                    0x0400  /* LDO1_HIB_MODE */
+#define WM8400_LDO1_HIB_MODE_MASK               0x0400  /* LDO1_HIB_MODE */
+#define WM8400_LDO1_HIB_MODE_SHIFT                  10  /* LDO1_HIB_MODE */
+#define WM8400_LDO1_HIB_MODE_WIDTH                   1  /* LDO1_HIB_MODE */
+#define WM8400_LDO1_VIMG_MASK                   0x03E0  /* LDO1_VIMG - [9:5] */
+#define WM8400_LDO1_VIMG_SHIFT                       5  /* LDO1_VIMG - [9:5] */
+#define WM8400_LDO1_VIMG_WIDTH                       5  /* LDO1_VIMG - [9:5] */
+#define WM8400_LDO1_VSEL_MASK                   0x001F  /* LDO1_VSEL - [4:0] */
+#define WM8400_LDO1_VSEL_SHIFT                       0  /* LDO1_VSEL - [4:0] */
+#define WM8400_LDO1_VSEL_WIDTH                       5  /* LDO1_VSEL - [4:0] */
+
+/*
+ * R66 (0x42) - LDO 2 Control
+ */
+#define WM8400_LDO2_ENA                         0x8000  /* LDO2_ENA */
+#define WM8400_LDO2_ENA_MASK                    0x8000  /* LDO2_ENA */
+#define WM8400_LDO2_ENA_SHIFT                       15  /* LDO2_ENA */
+#define WM8400_LDO2_ENA_WIDTH                        1  /* LDO2_ENA */
+#define WM8400_LDO2_SWI                         0x4000  /* LDO2_SWI */
+#define WM8400_LDO2_SWI_MASK                    0x4000  /* LDO2_SWI */
+#define WM8400_LDO2_SWI_SHIFT                       14  /* LDO2_SWI */
+#define WM8400_LDO2_SWI_WIDTH                        1  /* LDO2_SWI */
+#define WM8400_LDO2_OPFLT                       0x1000  /* LDO2_OPFLT */
+#define WM8400_LDO2_OPFLT_MASK                  0x1000  /* LDO2_OPFLT */
+#define WM8400_LDO2_OPFLT_SHIFT                     12  /* LDO2_OPFLT */
+#define WM8400_LDO2_OPFLT_WIDTH                      1  /* LDO2_OPFLT */
+#define WM8400_LDO2_ERRACT                      0x0800  /* LDO2_ERRACT */
+#define WM8400_LDO2_ERRACT_MASK                 0x0800  /* LDO2_ERRACT */
+#define WM8400_LDO2_ERRACT_SHIFT                    11  /* LDO2_ERRACT */
+#define WM8400_LDO2_ERRACT_WIDTH                     1  /* LDO2_ERRACT */
+#define WM8400_LDO2_HIB_MODE                    0x0400  /* LDO2_HIB_MODE */
+#define WM8400_LDO2_HIB_MODE_MASK               0x0400  /* LDO2_HIB_MODE */
+#define WM8400_LDO2_HIB_MODE_SHIFT                  10  /* LDO2_HIB_MODE */
+#define WM8400_LDO2_HIB_MODE_WIDTH                   1  /* LDO2_HIB_MODE */
+#define WM8400_LDO2_VIMG_MASK                   0x03E0  /* LDO2_VIMG - [9:5] */
+#define WM8400_LDO2_VIMG_SHIFT                       5  /* LDO2_VIMG - [9:5] */
+#define WM8400_LDO2_VIMG_WIDTH                       5  /* LDO2_VIMG - [9:5] */
+#define WM8400_LDO2_VSEL_MASK                   0x001F  /* LDO2_VSEL - [4:0] */
+#define WM8400_LDO2_VSEL_SHIFT                       0  /* LDO2_VSEL - [4:0] */
+#define WM8400_LDO2_VSEL_WIDTH                       5  /* LDO2_VSEL - [4:0] */
+
+/*
+ * R67 (0x43) - LDO 3 Control
+ */
+#define WM8400_LDO3_ENA                         0x8000  /* LDO3_ENA */
+#define WM8400_LDO3_ENA_MASK                    0x8000  /* LDO3_ENA */
+#define WM8400_LDO3_ENA_SHIFT                       15  /* LDO3_ENA */
+#define WM8400_LDO3_ENA_WIDTH                        1  /* LDO3_ENA */
+#define WM8400_LDO3_SWI                         0x4000  /* LDO3_SWI */
+#define WM8400_LDO3_SWI_MASK                    0x4000  /* LDO3_SWI */
+#define WM8400_LDO3_SWI_SHIFT                       14  /* LDO3_SWI */
+#define WM8400_LDO3_SWI_WIDTH                        1  /* LDO3_SWI */
+#define WM8400_LDO3_OPFLT                       0x1000  /* LDO3_OPFLT */
+#define WM8400_LDO3_OPFLT_MASK                  0x1000  /* LDO3_OPFLT */
+#define WM8400_LDO3_OPFLT_SHIFT                     12  /* LDO3_OPFLT */
+#define WM8400_LDO3_OPFLT_WIDTH                      1  /* LDO3_OPFLT */
+#define WM8400_LDO3_ERRACT                      0x0800  /* LDO3_ERRACT */
+#define WM8400_LDO3_ERRACT_MASK                 0x0800  /* LDO3_ERRACT */
+#define WM8400_LDO3_ERRACT_SHIFT                    11  /* LDO3_ERRACT */
+#define WM8400_LDO3_ERRACT_WIDTH                     1  /* LDO3_ERRACT */
+#define WM8400_LDO3_HIB_MODE                    0x0400  /* LDO3_HIB_MODE */
+#define WM8400_LDO3_HIB_MODE_MASK               0x0400  /* LDO3_HIB_MODE */
+#define WM8400_LDO3_HIB_MODE_SHIFT                  10  /* LDO3_HIB_MODE */
+#define WM8400_LDO3_HIB_MODE_WIDTH                   1  /* LDO3_HIB_MODE */
+#define WM8400_LDO3_VIMG_MASK                   0x03E0  /* LDO3_VIMG - [9:5] */
+#define WM8400_LDO3_VIMG_SHIFT                       5  /* LDO3_VIMG - [9:5] */
+#define WM8400_LDO3_VIMG_WIDTH                       5  /* LDO3_VIMG - [9:5] */
+#define WM8400_LDO3_VSEL_MASK                   0x001F  /* LDO3_VSEL - [4:0] */
+#define WM8400_LDO3_VSEL_SHIFT                       0  /* LDO3_VSEL - [4:0] */
+#define WM8400_LDO3_VSEL_WIDTH                       5  /* LDO3_VSEL - [4:0] */
+
+/*
+ * R68 (0x44) - LDO 4 Control
+ */
+#define WM8400_LDO4_ENA                         0x8000  /* LDO4_ENA */
+#define WM8400_LDO4_ENA_MASK                    0x8000  /* LDO4_ENA */
+#define WM8400_LDO4_ENA_SHIFT                       15  /* LDO4_ENA */
+#define WM8400_LDO4_ENA_WIDTH                        1  /* LDO4_ENA */
+#define WM8400_LDO4_SWI                         0x4000  /* LDO4_SWI */
+#define WM8400_LDO4_SWI_MASK                    0x4000  /* LDO4_SWI */
+#define WM8400_LDO4_SWI_SHIFT                       14  /* LDO4_SWI */
+#define WM8400_LDO4_SWI_WIDTH                        1  /* LDO4_SWI */
+#define WM8400_LDO4_OPFLT                       0x1000  /* LDO4_OPFLT */
+#define WM8400_LDO4_OPFLT_MASK                  0x1000  /* LDO4_OPFLT */
+#define WM8400_LDO4_OPFLT_SHIFT                     12  /* LDO4_OPFLT */
+#define WM8400_LDO4_OPFLT_WIDTH                      1  /* LDO4_OPFLT */
+#define WM8400_LDO4_ERRACT                      0x0800  /* LDO4_ERRACT */
+#define WM8400_LDO4_ERRACT_MASK                 0x0800  /* LDO4_ERRACT */
+#define WM8400_LDO4_ERRACT_SHIFT                    11  /* LDO4_ERRACT */
+#define WM8400_LDO4_ERRACT_WIDTH                     1  /* LDO4_ERRACT */
+#define WM8400_LDO4_HIB_MODE                    0x0400  /* LDO4_HIB_MODE */
+#define WM8400_LDO4_HIB_MODE_MASK               0x0400  /* LDO4_HIB_MODE */
+#define WM8400_LDO4_HIB_MODE_SHIFT                  10  /* LDO4_HIB_MODE */
+#define WM8400_LDO4_HIB_MODE_WIDTH                   1  /* LDO4_HIB_MODE */
+#define WM8400_LDO4_VIMG_MASK                   0x03E0  /* LDO4_VIMG - [9:5] */
+#define WM8400_LDO4_VIMG_SHIFT                       5  /* LDO4_VIMG - [9:5] */
+#define WM8400_LDO4_VIMG_WIDTH                       5  /* LDO4_VIMG - [9:5] */
+#define WM8400_LDO4_VSEL_MASK                   0x001F  /* LDO4_VSEL - [4:0] */
+#define WM8400_LDO4_VSEL_SHIFT                       0  /* LDO4_VSEL - [4:0] */
+#define WM8400_LDO4_VSEL_WIDTH                       5  /* LDO4_VSEL - [4:0] */
+
+/*
+ * R70 (0x46) - DCDC1 Control 1
+ */
+#define WM8400_DC1_ENA                          0x8000  /* DC1_ENA */
+#define WM8400_DC1_ENA_MASK                     0x8000  /* DC1_ENA */
+#define WM8400_DC1_ENA_SHIFT                        15  /* DC1_ENA */
+#define WM8400_DC1_ENA_WIDTH                         1  /* DC1_ENA */
+#define WM8400_DC1_ACTIVE                       0x4000  /* DC1_ACTIVE */
+#define WM8400_DC1_ACTIVE_MASK                  0x4000  /* DC1_ACTIVE */
+#define WM8400_DC1_ACTIVE_SHIFT                     14  /* DC1_ACTIVE */
+#define WM8400_DC1_ACTIVE_WIDTH                      1  /* DC1_ACTIVE */
+#define WM8400_DC1_SLEEP                        0x2000  /* DC1_SLEEP */
+#define WM8400_DC1_SLEEP_MASK                   0x2000  /* DC1_SLEEP */
+#define WM8400_DC1_SLEEP_SHIFT                      13  /* DC1_SLEEP */
+#define WM8400_DC1_SLEEP_WIDTH                       1  /* DC1_SLEEP */
+#define WM8400_DC1_OPFLT                        0x1000  /* DC1_OPFLT */
+#define WM8400_DC1_OPFLT_MASK                   0x1000  /* DC1_OPFLT */
+#define WM8400_DC1_OPFLT_SHIFT                      12  /* DC1_OPFLT */
+#define WM8400_DC1_OPFLT_WIDTH                       1  /* DC1_OPFLT */
+#define WM8400_DC1_ERRACT                       0x0800  /* DC1_ERRACT */
+#define WM8400_DC1_ERRACT_MASK                  0x0800  /* DC1_ERRACT */
+#define WM8400_DC1_ERRACT_SHIFT                     11  /* DC1_ERRACT */
+#define WM8400_DC1_ERRACT_WIDTH                      1  /* DC1_ERRACT */
+#define WM8400_DC1_HIB_MODE                     0x0400  /* DC1_HIB_MODE */
+#define WM8400_DC1_HIB_MODE_MASK                0x0400  /* DC1_HIB_MODE */
+#define WM8400_DC1_HIB_MODE_SHIFT                   10  /* DC1_HIB_MODE */
+#define WM8400_DC1_HIB_MODE_WIDTH                    1  /* DC1_HIB_MODE */
+#define WM8400_DC1_SOFTST_MASK                  0x0300  /* DC1_SOFTST - [9:8] */
+#define WM8400_DC1_SOFTST_SHIFT                      8  /* DC1_SOFTST - [9:8] */
+#define WM8400_DC1_SOFTST_WIDTH                      2  /* DC1_SOFTST - [9:8] */
+#define WM8400_DC1_OV_PROT                      0x0080  /* DC1_OV_PROT */
+#define WM8400_DC1_OV_PROT_MASK                 0x0080  /* DC1_OV_PROT */
+#define WM8400_DC1_OV_PROT_SHIFT                     7  /* DC1_OV_PROT */
+#define WM8400_DC1_OV_PROT_WIDTH                     1  /* DC1_OV_PROT */
+#define WM8400_DC1_VSEL_MASK                    0x007F  /* DC1_VSEL - [6:0] */
+#define WM8400_DC1_VSEL_SHIFT                        0  /* DC1_VSEL - [6:0] */
+#define WM8400_DC1_VSEL_WIDTH                        7  /* DC1_VSEL - [6:0] */
+
+/*
+ * R71 (0x47) - DCDC1 Control 2
+ */
+#define WM8400_DC1_FRC_PWM                      0x2000  /* DC1_FRC_PWM */
+#define WM8400_DC1_FRC_PWM_MASK                 0x2000  /* DC1_FRC_PWM */
+#define WM8400_DC1_FRC_PWM_SHIFT                    13  /* DC1_FRC_PWM */
+#define WM8400_DC1_FRC_PWM_WIDTH                     1  /* DC1_FRC_PWM */
+#define WM8400_DC1_STBY_LIM_MASK                0x0300  /* DC1_STBY_LIM - [9:8] */
+#define WM8400_DC1_STBY_LIM_SHIFT                    8  /* DC1_STBY_LIM - [9:8] */
+#define WM8400_DC1_STBY_LIM_WIDTH                    2  /* DC1_STBY_LIM - [9:8] */
+#define WM8400_DC1_ACT_LIM                      0x0080  /* DC1_ACT_LIM */
+#define WM8400_DC1_ACT_LIM_MASK                 0x0080  /* DC1_ACT_LIM */
+#define WM8400_DC1_ACT_LIM_SHIFT                     7  /* DC1_ACT_LIM */
+#define WM8400_DC1_ACT_LIM_WIDTH                     1  /* DC1_ACT_LIM */
+#define WM8400_DC1_VIMG_MASK                    0x007F  /* DC1_VIMG - [6:0] */
+#define WM8400_DC1_VIMG_SHIFT                        0  /* DC1_VIMG - [6:0] */
+#define WM8400_DC1_VIMG_WIDTH                        7  /* DC1_VIMG - [6:0] */
+
+/*
+ * R72 (0x48) - DCDC2 Control 1
+ */
+#define WM8400_DC2_ENA                          0x8000  /* DC2_ENA */
+#define WM8400_DC2_ENA_MASK                     0x8000  /* DC2_ENA */
+#define WM8400_DC2_ENA_SHIFT                        15  /* DC2_ENA */
+#define WM8400_DC2_ENA_WIDTH                         1  /* DC2_ENA */
+#define WM8400_DC2_ACTIVE                       0x4000  /* DC2_ACTIVE */
+#define WM8400_DC2_ACTIVE_MASK                  0x4000  /* DC2_ACTIVE */
+#define WM8400_DC2_ACTIVE_SHIFT                     14  /* DC2_ACTIVE */
+#define WM8400_DC2_ACTIVE_WIDTH                      1  /* DC2_ACTIVE */
+#define WM8400_DC2_SLEEP                        0x2000  /* DC2_SLEEP */
+#define WM8400_DC2_SLEEP_MASK                   0x2000  /* DC2_SLEEP */
+#define WM8400_DC2_SLEEP_SHIFT                      13  /* DC2_SLEEP */
+#define WM8400_DC2_SLEEP_WIDTH                       1  /* DC2_SLEEP */
+#define WM8400_DC2_OPFLT                        0x1000  /* DC2_OPFLT */
+#define WM8400_DC2_OPFLT_MASK                   0x1000  /* DC2_OPFLT */
+#define WM8400_DC2_OPFLT_SHIFT                      12  /* DC2_OPFLT */
+#define WM8400_DC2_OPFLT_WIDTH                       1  /* DC2_OPFLT */
+#define WM8400_DC2_ERRACT                       0x0800  /* DC2_ERRACT */
+#define WM8400_DC2_ERRACT_MASK                  0x0800  /* DC2_ERRACT */
+#define WM8400_DC2_ERRACT_SHIFT                     11  /* DC2_ERRACT */
+#define WM8400_DC2_ERRACT_WIDTH                      1  /* DC2_ERRACT */
+#define WM8400_DC2_HIB_MODE                     0x0400  /* DC2_HIB_MODE */
+#define WM8400_DC2_HIB_MODE_MASK                0x0400  /* DC2_HIB_MODE */
+#define WM8400_DC2_HIB_MODE_SHIFT                   10  /* DC2_HIB_MODE */
+#define WM8400_DC2_HIB_MODE_WIDTH                    1  /* DC2_HIB_MODE */
+#define WM8400_DC2_SOFTST_MASK                  0x0300  /* DC2_SOFTST - [9:8] */
+#define WM8400_DC2_SOFTST_SHIFT                      8  /* DC2_SOFTST - [9:8] */
+#define WM8400_DC2_SOFTST_WIDTH                      2  /* DC2_SOFTST - [9:8] */
+#define WM8400_DC2_OV_PROT                      0x0080  /* DC2_OV_PROT */
+#define WM8400_DC2_OV_PROT_MASK                 0x0080  /* DC2_OV_PROT */
+#define WM8400_DC2_OV_PROT_SHIFT                     7  /* DC2_OV_PROT */
+#define WM8400_DC2_OV_PROT_WIDTH                     1  /* DC2_OV_PROT */
+#define WM8400_DC2_VSEL_MASK                    0x007F  /* DC2_VSEL - [6:0] */
+#define WM8400_DC2_VSEL_SHIFT                        0  /* DC2_VSEL - [6:0] */
+#define WM8400_DC2_VSEL_WIDTH                        7  /* DC2_VSEL - [6:0] */
+
+/*
+ * R73 (0x49) - DCDC2 Control 2
+ */
+#define WM8400_DC2_FRC_PWM                      0x2000  /* DC2_FRC_PWM */
+#define WM8400_DC2_FRC_PWM_MASK                 0x2000  /* DC2_FRC_PWM */
+#define WM8400_DC2_FRC_PWM_SHIFT                    13  /* DC2_FRC_PWM */
+#define WM8400_DC2_FRC_PWM_WIDTH                     1  /* DC2_FRC_PWM */
+#define WM8400_DC2_STBY_LIM_MASK                0x0300  /* DC2_STBY_LIM - [9:8] */
+#define WM8400_DC2_STBY_LIM_SHIFT                    8  /* DC2_STBY_LIM - [9:8] */
+#define WM8400_DC2_STBY_LIM_WIDTH                    2  /* DC2_STBY_LIM - [9:8] */
+#define WM8400_DC2_ACT_LIM                      0x0080  /* DC2_ACT_LIM */
+#define WM8400_DC2_ACT_LIM_MASK                 0x0080  /* DC2_ACT_LIM */
+#define WM8400_DC2_ACT_LIM_SHIFT                     7  /* DC2_ACT_LIM */
+#define WM8400_DC2_ACT_LIM_WIDTH                     1  /* DC2_ACT_LIM */
+#define WM8400_DC2_VIMG_MASK                    0x007F  /* DC2_VIMG - [6:0] */
+#define WM8400_DC2_VIMG_SHIFT                        0  /* DC2_VIMG - [6:0] */
+#define WM8400_DC2_VIMG_WIDTH                        7  /* DC2_VIMG - [6:0] */
+
+/*
+ * R75 (0x4B) - Interface
+ */
+#define WM8400_AUTOINC                          0x0008  /* AUTOINC */
+#define WM8400_AUTOINC_MASK                     0x0008  /* AUTOINC */
+#define WM8400_AUTOINC_SHIFT                         3  /* AUTOINC */
+#define WM8400_AUTOINC_WIDTH                         1  /* AUTOINC */
+#define WM8400_ARA_ENA                          0x0004  /* ARA_ENA */
+#define WM8400_ARA_ENA_MASK                     0x0004  /* ARA_ENA */
+#define WM8400_ARA_ENA_SHIFT                         2  /* ARA_ENA */
+#define WM8400_ARA_ENA_WIDTH                         1  /* ARA_ENA */
+#define WM8400_SPI_CFG                          0x0002  /* SPI_CFG */
+#define WM8400_SPI_CFG_MASK                     0x0002  /* SPI_CFG */
+#define WM8400_SPI_CFG_SHIFT                         1  /* SPI_CFG */
+#define WM8400_SPI_CFG_WIDTH                         1  /* SPI_CFG */
+
+/*
+ * R76 (0x4C) - PM GENERAL
+ */
+#define WM8400_CODEC_SOFTST                     0x8000  /* CODEC_SOFTST */
+#define WM8400_CODEC_SOFTST_MASK                0x8000  /* CODEC_SOFTST */
+#define WM8400_CODEC_SOFTST_SHIFT                   15  /* CODEC_SOFTST */
+#define WM8400_CODEC_SOFTST_WIDTH                    1  /* CODEC_SOFTST */
+#define WM8400_CODEC_SOFTSD                     0x4000  /* CODEC_SOFTSD */
+#define WM8400_CODEC_SOFTSD_MASK                0x4000  /* CODEC_SOFTSD */
+#define WM8400_CODEC_SOFTSD_SHIFT                   14  /* CODEC_SOFTSD */
+#define WM8400_CODEC_SOFTSD_WIDTH                    1  /* CODEC_SOFTSD */
+#define WM8400_CHIP_SOFTSD                      0x2000  /* CHIP_SOFTSD */
+#define WM8400_CHIP_SOFTSD_MASK                 0x2000  /* CHIP_SOFTSD */
+#define WM8400_CHIP_SOFTSD_SHIFT                    13  /* CHIP_SOFTSD */
+#define WM8400_CHIP_SOFTSD_WIDTH                     1  /* CHIP_SOFTSD */
+#define WM8400_DSLEEP1_POL                      0x0008  /* DSLEEP1_POL */
+#define WM8400_DSLEEP1_POL_MASK                 0x0008  /* DSLEEP1_POL */
+#define WM8400_DSLEEP1_POL_SHIFT                     3  /* DSLEEP1_POL */
+#define WM8400_DSLEEP1_POL_WIDTH                     1  /* DSLEEP1_POL */
+#define WM8400_DSLEEP2_POL                      0x0004  /* DSLEEP2_POL */
+#define WM8400_DSLEEP2_POL_MASK                 0x0004  /* DSLEEP2_POL */
+#define WM8400_DSLEEP2_POL_SHIFT                     2  /* DSLEEP2_POL */
+#define WM8400_DSLEEP2_POL_WIDTH                     1  /* DSLEEP2_POL */
+#define WM8400_PWR_STATE_MASK                   0x0003  /* PWR_STATE - [1:0] */
+#define WM8400_PWR_STATE_SHIFT                       0  /* PWR_STATE - [1:0] */
+#define WM8400_PWR_STATE_WIDTH                       2  /* PWR_STATE - [1:0] */
+
+/*
+ * R78 (0x4E) - PM Shutdown Control
+ */
+#define WM8400_CHIP_GT150_ERRACT                0x0200  /* CHIP_GT150_ERRACT */
+#define WM8400_CHIP_GT150_ERRACT_MASK           0x0200  /* CHIP_GT150_ERRACT */
+#define WM8400_CHIP_GT150_ERRACT_SHIFT               9  /* CHIP_GT150_ERRACT */
+#define WM8400_CHIP_GT150_ERRACT_WIDTH               1  /* CHIP_GT150_ERRACT */
+#define WM8400_CHIP_GT115_ERRACT                0x0100  /* CHIP_GT115_ERRACT */
+#define WM8400_CHIP_GT115_ERRACT_MASK           0x0100  /* CHIP_GT115_ERRACT */
+#define WM8400_CHIP_GT115_ERRACT_SHIFT               8  /* CHIP_GT115_ERRACT */
+#define WM8400_CHIP_GT115_ERRACT_WIDTH               1  /* CHIP_GT115_ERRACT */
+#define WM8400_LINE_CMP_ERRACT                  0x0080  /* LINE_CMP_ERRACT */
+#define WM8400_LINE_CMP_ERRACT_MASK             0x0080  /* LINE_CMP_ERRACT */
+#define WM8400_LINE_CMP_ERRACT_SHIFT                 7  /* LINE_CMP_ERRACT */
+#define WM8400_LINE_CMP_ERRACT_WIDTH                 1  /* LINE_CMP_ERRACT */
+#define WM8400_UVLO_ERRACT                      0x0040  /* UVLO_ERRACT */
+#define WM8400_UVLO_ERRACT_MASK                 0x0040  /* UVLO_ERRACT */
+#define WM8400_UVLO_ERRACT_SHIFT                     6  /* UVLO_ERRACT */
+#define WM8400_UVLO_ERRACT_WIDTH                     1  /* UVLO_ERRACT */
+
+/*
+ * R79 (0x4F) - Interrupt Status 1
+ */
+#define WM8400_MICD_CINT                        0x8000  /* MICD_CINT */
+#define WM8400_MICD_CINT_MASK                   0x8000  /* MICD_CINT */
+#define WM8400_MICD_CINT_SHIFT                      15  /* MICD_CINT */
+#define WM8400_MICD_CINT_WIDTH                       1  /* MICD_CINT */
+#define WM8400_MICSCD_CINT                      0x4000  /* MICSCD_CINT */
+#define WM8400_MICSCD_CINT_MASK                 0x4000  /* MICSCD_CINT */
+#define WM8400_MICSCD_CINT_SHIFT                    14  /* MICSCD_CINT */
+#define WM8400_MICSCD_CINT_WIDTH                     1  /* MICSCD_CINT */
+#define WM8400_JDL_CINT                         0x2000  /* JDL_CINT */
+#define WM8400_JDL_CINT_MASK                    0x2000  /* JDL_CINT */
+#define WM8400_JDL_CINT_SHIFT                       13  /* JDL_CINT */
+#define WM8400_JDL_CINT_WIDTH                        1  /* JDL_CINT */
+#define WM8400_JDR_CINT                         0x1000  /* JDR_CINT */
+#define WM8400_JDR_CINT_MASK                    0x1000  /* JDR_CINT */
+#define WM8400_JDR_CINT_SHIFT                       12  /* JDR_CINT */
+#define WM8400_JDR_CINT_WIDTH                        1  /* JDR_CINT */
+#define WM8400_CODEC_SEQ_END_EINT               0x0800  /* CODEC_SEQ_END_EINT */
+#define WM8400_CODEC_SEQ_END_EINT_MASK          0x0800  /* CODEC_SEQ_END_EINT */
+#define WM8400_CODEC_SEQ_END_EINT_SHIFT             11  /* CODEC_SEQ_END_EINT */
+#define WM8400_CODEC_SEQ_END_EINT_WIDTH              1  /* CODEC_SEQ_END_EINT */
+#define WM8400_CDEL_TO_EINT                     0x0400  /* CDEL_TO_EINT */
+#define WM8400_CDEL_TO_EINT_MASK                0x0400  /* CDEL_TO_EINT */
+#define WM8400_CDEL_TO_EINT_SHIFT                   10  /* CDEL_TO_EINT */
+#define WM8400_CDEL_TO_EINT_WIDTH                    1  /* CDEL_TO_EINT */
+#define WM8400_CHIP_GT150_EINT                  0x0200  /* CHIP_GT150_EINT */
+#define WM8400_CHIP_GT150_EINT_MASK             0x0200  /* CHIP_GT150_EINT */
+#define WM8400_CHIP_GT150_EINT_SHIFT                 9  /* CHIP_GT150_EINT */
+#define WM8400_CHIP_GT150_EINT_WIDTH                 1  /* CHIP_GT150_EINT */
+#define WM8400_CHIP_GT115_EINT                  0x0100  /* CHIP_GT115_EINT */
+#define WM8400_CHIP_GT115_EINT_MASK             0x0100  /* CHIP_GT115_EINT */
+#define WM8400_CHIP_GT115_EINT_SHIFT                 8  /* CHIP_GT115_EINT */
+#define WM8400_CHIP_GT115_EINT_WIDTH                 1  /* CHIP_GT115_EINT */
+#define WM8400_LINE_CMP_EINT                    0x0080  /* LINE_CMP_EINT */
+#define WM8400_LINE_CMP_EINT_MASK               0x0080  /* LINE_CMP_EINT */
+#define WM8400_LINE_CMP_EINT_SHIFT                   7  /* LINE_CMP_EINT */
+#define WM8400_LINE_CMP_EINT_WIDTH                   1  /* LINE_CMP_EINT */
+#define WM8400_UVLO_EINT                        0x0040  /* UVLO_EINT */
+#define WM8400_UVLO_EINT_MASK                   0x0040  /* UVLO_EINT */
+#define WM8400_UVLO_EINT_SHIFT                       6  /* UVLO_EINT */
+#define WM8400_UVLO_EINT_WIDTH                       1  /* UVLO_EINT */
+#define WM8400_DC2_UV_EINT                      0x0020  /* DC2_UV_EINT */
+#define WM8400_DC2_UV_EINT_MASK                 0x0020  /* DC2_UV_EINT */
+#define WM8400_DC2_UV_EINT_SHIFT                     5  /* DC2_UV_EINT */
+#define WM8400_DC2_UV_EINT_WIDTH                     1  /* DC2_UV_EINT */
+#define WM8400_DC1_UV_EINT                      0x0010  /* DC1_UV_EINT */
+#define WM8400_DC1_UV_EINT_MASK                 0x0010  /* DC1_UV_EINT */
+#define WM8400_DC1_UV_EINT_SHIFT                     4  /* DC1_UV_EINT */
+#define WM8400_DC1_UV_EINT_WIDTH                     1  /* DC1_UV_EINT */
+#define WM8400_LDO4_UV_EINT                     0x0008  /* LDO4_UV_EINT */
+#define WM8400_LDO4_UV_EINT_MASK                0x0008  /* LDO4_UV_EINT */
+#define WM8400_LDO4_UV_EINT_SHIFT                    3  /* LDO4_UV_EINT */
+#define WM8400_LDO4_UV_EINT_WIDTH                    1  /* LDO4_UV_EINT */
+#define WM8400_LDO3_UV_EINT                     0x0004  /* LDO3_UV_EINT */
+#define WM8400_LDO3_UV_EINT_MASK                0x0004  /* LDO3_UV_EINT */
+#define WM8400_LDO3_UV_EINT_SHIFT                    2  /* LDO3_UV_EINT */
+#define WM8400_LDO3_UV_EINT_WIDTH                    1  /* LDO3_UV_EINT */
+#define WM8400_LDO2_UV_EINT                     0x0002  /* LDO2_UV_EINT */
+#define WM8400_LDO2_UV_EINT_MASK                0x0002  /* LDO2_UV_EINT */
+#define WM8400_LDO2_UV_EINT_SHIFT                    1  /* LDO2_UV_EINT */
+#define WM8400_LDO2_UV_EINT_WIDTH                    1  /* LDO2_UV_EINT */
+#define WM8400_LDO1_UV_EINT                     0x0001  /* LDO1_UV_EINT */
+#define WM8400_LDO1_UV_EINT_MASK                0x0001  /* LDO1_UV_EINT */
+#define WM8400_LDO1_UV_EINT_SHIFT                    0  /* LDO1_UV_EINT */
+#define WM8400_LDO1_UV_EINT_WIDTH                    1  /* LDO1_UV_EINT */
+
+/*
+ * R80 (0x50) - Interrupt Status 1 Mask
+ */
+#define WM8400_IM_MICD_CINT                     0x8000  /* IM_MICD_CINT */
+#define WM8400_IM_MICD_CINT_MASK                0x8000  /* IM_MICD_CINT */
+#define WM8400_IM_MICD_CINT_SHIFT                   15  /* IM_MICD_CINT */
+#define WM8400_IM_MICD_CINT_WIDTH                    1  /* IM_MICD_CINT */
+#define WM8400_IM_MICSCD_CINT                   0x4000  /* IM_MICSCD_CINT */
+#define WM8400_IM_MICSCD_CINT_MASK              0x4000  /* IM_MICSCD_CINT */
+#define WM8400_IM_MICSCD_CINT_SHIFT                 14  /* IM_MICSCD_CINT */
+#define WM8400_IM_MICSCD_CINT_WIDTH                  1  /* IM_MICSCD_CINT */
+#define WM8400_IM_JDL_CINT                      0x2000  /* IM_JDL_CINT */
+#define WM8400_IM_JDL_CINT_MASK                 0x2000  /* IM_JDL_CINT */
+#define WM8400_IM_JDL_CINT_SHIFT                    13  /* IM_JDL_CINT */
+#define WM8400_IM_JDL_CINT_WIDTH                     1  /* IM_JDL_CINT */
+#define WM8400_IM_JDR_CINT                      0x1000  /* IM_JDR_CINT */
+#define WM8400_IM_JDR_CINT_MASK                 0x1000  /* IM_JDR_CINT */
+#define WM8400_IM_JDR_CINT_SHIFT                    12  /* IM_JDR_CINT */
+#define WM8400_IM_JDR_CINT_WIDTH                     1  /* IM_JDR_CINT */
+#define WM8400_IM_CODEC_SEQ_END_EINT            0x0800  /* IM_CODEC_SEQ_END_EINT */
+#define WM8400_IM_CODEC_SEQ_END_EINT_MASK       0x0800  /* IM_CODEC_SEQ_END_EINT */
+#define WM8400_IM_CODEC_SEQ_END_EINT_SHIFT          11  /* IM_CODEC_SEQ_END_EINT */
+#define WM8400_IM_CODEC_SEQ_END_EINT_WIDTH           1  /* IM_CODEC_SEQ_END_EINT */
+#define WM8400_IM_CDEL_TO_EINT                  0x0400  /* IM_CDEL_TO_EINT */
+#define WM8400_IM_CDEL_TO_EINT_MASK             0x0400  /* IM_CDEL_TO_EINT */
+#define WM8400_IM_CDEL_TO_EINT_SHIFT                10  /* IM_CDEL_TO_EINT */
+#define WM8400_IM_CDEL_TO_EINT_WIDTH                 1  /* IM_CDEL_TO_EINT */
+#define WM8400_IM_CHIP_GT150_EINT               0x0200  /* IM_CHIP_GT150_EINT */
+#define WM8400_IM_CHIP_GT150_EINT_MASK          0x0200  /* IM_CHIP_GT150_EINT */
+#define WM8400_IM_CHIP_GT150_EINT_SHIFT              9  /* IM_CHIP_GT150_EINT */
+#define WM8400_IM_CHIP_GT150_EINT_WIDTH              1  /* IM_CHIP_GT150_EINT */
+#define WM8400_IM_CHIP_GT115_EINT               0x0100  /* IM_CHIP_GT115_EINT */
+#define WM8400_IM_CHIP_GT115_EINT_MASK          0x0100  /* IM_CHIP_GT115_EINT */
+#define WM8400_IM_CHIP_GT115_EINT_SHIFT              8  /* IM_CHIP_GT115_EINT */
+#define WM8400_IM_CHIP_GT115_EINT_WIDTH              1  /* IM_CHIP_GT115_EINT */
+#define WM8400_IM_LINE_CMP_EINT                 0x0080  /* IM_LINE_CMP_EINT */
+#define WM8400_IM_LINE_CMP_EINT_MASK            0x0080  /* IM_LINE_CMP_EINT */
+#define WM8400_IM_LINE_CMP_EINT_SHIFT                7  /* IM_LINE_CMP_EINT */
+#define WM8400_IM_LINE_CMP_EINT_WIDTH                1  /* IM_LINE_CMP_EINT */
+#define WM8400_IM_UVLO_EINT                     0x0040  /* IM_UVLO_EINT */
+#define WM8400_IM_UVLO_EINT_MASK                0x0040  /* IM_UVLO_EINT */
+#define WM8400_IM_UVLO_EINT_SHIFT                    6  /* IM_UVLO_EINT */
+#define WM8400_IM_UVLO_EINT_WIDTH                    1  /* IM_UVLO_EINT */
+#define WM8400_IM_DC2_UV_EINT                   0x0020  /* IM_DC2_UV_EINT */
+#define WM8400_IM_DC2_UV_EINT_MASK              0x0020  /* IM_DC2_UV_EINT */
+#define WM8400_IM_DC2_UV_EINT_SHIFT                  5  /* IM_DC2_UV_EINT */
+#define WM8400_IM_DC2_UV_EINT_WIDTH                  1  /* IM_DC2_UV_EINT */
+#define WM8400_IM_DC1_UV_EINT                   0x0010  /* IM_DC1_UV_EINT */
+#define WM8400_IM_DC1_UV_EINT_MASK              0x0010  /* IM_DC1_UV_EINT */
+#define WM8400_IM_DC1_UV_EINT_SHIFT                  4  /* IM_DC1_UV_EINT */
+#define WM8400_IM_DC1_UV_EINT_WIDTH                  1  /* IM_DC1_UV_EINT */
+#define WM8400_IM_LDO4_UV_EINT                  0x0008  /* IM_LDO4_UV_EINT */
+#define WM8400_IM_LDO4_UV_EINT_MASK             0x0008  /* IM_LDO4_UV_EINT */
+#define WM8400_IM_LDO4_UV_EINT_SHIFT                 3  /* IM_LDO4_UV_EINT */
+#define WM8400_IM_LDO4_UV_EINT_WIDTH                 1  /* IM_LDO4_UV_EINT */
+#define WM8400_IM_LDO3_UV_EINT                  0x0004  /* IM_LDO3_UV_EINT */
+#define WM8400_IM_LDO3_UV_EINT_MASK             0x0004  /* IM_LDO3_UV_EINT */
+#define WM8400_IM_LDO3_UV_EINT_SHIFT                 2  /* IM_LDO3_UV_EINT */
+#define WM8400_IM_LDO3_UV_EINT_WIDTH                 1  /* IM_LDO3_UV_EINT */
+#define WM8400_IM_LDO2_UV_EINT                  0x0002  /* IM_LDO2_UV_EINT */
+#define WM8400_IM_LDO2_UV_EINT_MASK             0x0002  /* IM_LDO2_UV_EINT */
+#define WM8400_IM_LDO2_UV_EINT_SHIFT                 1  /* IM_LDO2_UV_EINT */
+#define WM8400_IM_LDO2_UV_EINT_WIDTH                 1  /* IM_LDO2_UV_EINT */
+#define WM8400_IM_LDO1_UV_EINT                  0x0001  /* IM_LDO1_UV_EINT */
+#define WM8400_IM_LDO1_UV_EINT_MASK             0x0001  /* IM_LDO1_UV_EINT */
+#define WM8400_IM_LDO1_UV_EINT_SHIFT                 0  /* IM_LDO1_UV_EINT */
+#define WM8400_IM_LDO1_UV_EINT_WIDTH                 1  /* IM_LDO1_UV_EINT */
+
+/*
+ * R81 (0x51) - Interrupt Levels
+ */
+#define WM8400_MICD_LVL                         0x8000  /* MICD_LVL */
+#define WM8400_MICD_LVL_MASK                    0x8000  /* MICD_LVL */
+#define WM8400_MICD_LVL_SHIFT                       15  /* MICD_LVL */
+#define WM8400_MICD_LVL_WIDTH                        1  /* MICD_LVL */
+#define WM8400_MICSCD_LVL                       0x4000  /* MICSCD_LVL */
+#define WM8400_MICSCD_LVL_MASK                  0x4000  /* MICSCD_LVL */
+#define WM8400_MICSCD_LVL_SHIFT                     14  /* MICSCD_LVL */
+#define WM8400_MICSCD_LVL_WIDTH                      1  /* MICSCD_LVL */
+#define WM8400_JDL_LVL                          0x2000  /* JDL_LVL */
+#define WM8400_JDL_LVL_MASK                     0x2000  /* JDL_LVL */
+#define WM8400_JDL_LVL_SHIFT                        13  /* JDL_LVL */
+#define WM8400_JDL_LVL_WIDTH                         1  /* JDL_LVL */
+#define WM8400_JDR_LVL                          0x1000  /* JDR_LVL */
+#define WM8400_JDR_LVL_MASK                     0x1000  /* JDR_LVL */
+#define WM8400_JDR_LVL_SHIFT                        12  /* JDR_LVL */
+#define WM8400_JDR_LVL_WIDTH                         1  /* JDR_LVL */
+#define WM8400_CODEC_SEQ_END_LVL                0x0800  /* CODEC_SEQ_END_LVL */
+#define WM8400_CODEC_SEQ_END_LVL_MASK           0x0800  /* CODEC_SEQ_END_LVL */
+#define WM8400_CODEC_SEQ_END_LVL_SHIFT              11  /* CODEC_SEQ_END_LVL */
+#define WM8400_CODEC_SEQ_END_LVL_WIDTH               1  /* CODEC_SEQ_END_LVL */
+#define WM8400_CDEL_TO_LVL                      0x0400  /* CDEL_TO_LVL */
+#define WM8400_CDEL_TO_LVL_MASK                 0x0400  /* CDEL_TO_LVL */
+#define WM8400_CDEL_TO_LVL_SHIFT                    10  /* CDEL_TO_LVL */
+#define WM8400_CDEL_TO_LVL_WIDTH                     1  /* CDEL_TO_LVL */
+#define WM8400_CHIP_GT150_LVL                   0x0200  /* CHIP_GT150_LVL */
+#define WM8400_CHIP_GT150_LVL_MASK              0x0200  /* CHIP_GT150_LVL */
+#define WM8400_CHIP_GT150_LVL_SHIFT                  9  /* CHIP_GT150_LVL */
+#define WM8400_CHIP_GT150_LVL_WIDTH                  1  /* CHIP_GT150_LVL */
+#define WM8400_CHIP_GT115_LVL                   0x0100  /* CHIP_GT115_LVL */
+#define WM8400_CHIP_GT115_LVL_MASK              0x0100  /* CHIP_GT115_LVL */
+#define WM8400_CHIP_GT115_LVL_SHIFT                  8  /* CHIP_GT115_LVL */
+#define WM8400_CHIP_GT115_LVL_WIDTH                  1  /* CHIP_GT115_LVL */
+#define WM8400_LINE_CMP_LVL                     0x0080  /* LINE_CMP_LVL */
+#define WM8400_LINE_CMP_LVL_MASK                0x0080  /* LINE_CMP_LVL */
+#define WM8400_LINE_CMP_LVL_SHIFT                    7  /* LINE_CMP_LVL */
+#define WM8400_LINE_CMP_LVL_WIDTH                    1  /* LINE_CMP_LVL */
+#define WM8400_UVLO_LVL                         0x0040  /* UVLO_LVL */
+#define WM8400_UVLO_LVL_MASK                    0x0040  /* UVLO_LVL */
+#define WM8400_UVLO_LVL_SHIFT                        6  /* UVLO_LVL */
+#define WM8400_UVLO_LVL_WIDTH                        1  /* UVLO_LVL */
+#define WM8400_DC2_UV_LVL                       0x0020  /* DC2_UV_LVL */
+#define WM8400_DC2_UV_LVL_MASK                  0x0020  /* DC2_UV_LVL */
+#define WM8400_DC2_UV_LVL_SHIFT                      5  /* DC2_UV_LVL */
+#define WM8400_DC2_UV_LVL_WIDTH                      1  /* DC2_UV_LVL */
+#define WM8400_DC1_UV_LVL                       0x0010  /* DC1_UV_LVL */
+#define WM8400_DC1_UV_LVL_MASK                  0x0010  /* DC1_UV_LVL */
+#define WM8400_DC1_UV_LVL_SHIFT                      4  /* DC1_UV_LVL */
+#define WM8400_DC1_UV_LVL_WIDTH                      1  /* DC1_UV_LVL */
+#define WM8400_LDO4_UV_LVL                      0x0008  /* LDO4_UV_LVL */
+#define WM8400_LDO4_UV_LVL_MASK                 0x0008  /* LDO4_UV_LVL */
+#define WM8400_LDO4_UV_LVL_SHIFT                     3  /* LDO4_UV_LVL */
+#define WM8400_LDO4_UV_LVL_WIDTH                     1  /* LDO4_UV_LVL */
+#define WM8400_LDO3_UV_LVL                      0x0004  /* LDO3_UV_LVL */
+#define WM8400_LDO3_UV_LVL_MASK                 0x0004  /* LDO3_UV_LVL */
+#define WM8400_LDO3_UV_LVL_SHIFT                     2  /* LDO3_UV_LVL */
+#define WM8400_LDO3_UV_LVL_WIDTH                     1  /* LDO3_UV_LVL */
+#define WM8400_LDO2_UV_LVL                      0x0002  /* LDO2_UV_LVL */
+#define WM8400_LDO2_UV_LVL_MASK                 0x0002  /* LDO2_UV_LVL */
+#define WM8400_LDO2_UV_LVL_SHIFT                     1  /* LDO2_UV_LVL */
+#define WM8400_LDO2_UV_LVL_WIDTH                     1  /* LDO2_UV_LVL */
+#define WM8400_LDO1_UV_LVL                      0x0001  /* LDO1_UV_LVL */
+#define WM8400_LDO1_UV_LVL_MASK                 0x0001  /* LDO1_UV_LVL */
+#define WM8400_LDO1_UV_LVL_SHIFT                     0  /* LDO1_UV_LVL */
+#define WM8400_LDO1_UV_LVL_WIDTH                     1  /* LDO1_UV_LVL */
+
+/*
+ * R82 (0x52) - Shutdown Reason
+ */
+#define WM8400_SDR_CHIP_SOFTSD                  0x2000  /* SDR_CHIP_SOFTSD */
+#define WM8400_SDR_CHIP_SOFTSD_MASK             0x2000  /* SDR_CHIP_SOFTSD */
+#define WM8400_SDR_CHIP_SOFTSD_SHIFT                13  /* SDR_CHIP_SOFTSD */
+#define WM8400_SDR_CHIP_SOFTSD_WIDTH                 1  /* SDR_CHIP_SOFTSD */
+#define WM8400_SDR_NPDN                         0x0800  /* SDR_NPDN */
+#define WM8400_SDR_NPDN_MASK                    0x0800  /* SDR_NPDN */
+#define WM8400_SDR_NPDN_SHIFT                       11  /* SDR_NPDN */
+#define WM8400_SDR_NPDN_WIDTH                        1  /* SDR_NPDN */
+#define WM8400_SDR_CHIP_GT150                   0x0200  /* SDR_CHIP_GT150 */
+#define WM8400_SDR_CHIP_GT150_MASK              0x0200  /* SDR_CHIP_GT150 */
+#define WM8400_SDR_CHIP_GT150_SHIFT                  9  /* SDR_CHIP_GT150 */
+#define WM8400_SDR_CHIP_GT150_WIDTH                  1  /* SDR_CHIP_GT150 */
+#define WM8400_SDR_CHIP_GT115                   0x0100  /* SDR_CHIP_GT115 */
+#define WM8400_SDR_CHIP_GT115_MASK              0x0100  /* SDR_CHIP_GT115 */
+#define WM8400_SDR_CHIP_GT115_SHIFT                  8  /* SDR_CHIP_GT115 */
+#define WM8400_SDR_CHIP_GT115_WIDTH                  1  /* SDR_CHIP_GT115 */
+#define WM8400_SDR_LINE_CMP                     0x0080  /* SDR_LINE_CMP */
+#define WM8400_SDR_LINE_CMP_MASK                0x0080  /* SDR_LINE_CMP */
+#define WM8400_SDR_LINE_CMP_SHIFT                    7  /* SDR_LINE_CMP */
+#define WM8400_SDR_LINE_CMP_WIDTH                    1  /* SDR_LINE_CMP */
+#define WM8400_SDR_UVLO                         0x0040  /* SDR_UVLO */
+#define WM8400_SDR_UVLO_MASK                    0x0040  /* SDR_UVLO */
+#define WM8400_SDR_UVLO_SHIFT                        6  /* SDR_UVLO */
+#define WM8400_SDR_UVLO_WIDTH                        1  /* SDR_UVLO */
+#define WM8400_SDR_DC2_UV                       0x0020  /* SDR_DC2_UV */
+#define WM8400_SDR_DC2_UV_MASK                  0x0020  /* SDR_DC2_UV */
+#define WM8400_SDR_DC2_UV_SHIFT                      5  /* SDR_DC2_UV */
+#define WM8400_SDR_DC2_UV_WIDTH                      1  /* SDR_DC2_UV */
+#define WM8400_SDR_DC1_UV                       0x0010  /* SDR_DC1_UV */
+#define WM8400_SDR_DC1_UV_MASK                  0x0010  /* SDR_DC1_UV */
+#define WM8400_SDR_DC1_UV_SHIFT                      4  /* SDR_DC1_UV */
+#define WM8400_SDR_DC1_UV_WIDTH                      1  /* SDR_DC1_UV */
+#define WM8400_SDR_LDO4_UV                      0x0008  /* SDR_LDO4_UV */
+#define WM8400_SDR_LDO4_UV_MASK                 0x0008  /* SDR_LDO4_UV */
+#define WM8400_SDR_LDO4_UV_SHIFT                     3  /* SDR_LDO4_UV */
+#define WM8400_SDR_LDO4_UV_WIDTH                     1  /* SDR_LDO4_UV */
+#define WM8400_SDR_LDO3_UV                      0x0004  /* SDR_LDO3_UV */
+#define WM8400_SDR_LDO3_UV_MASK                 0x0004  /* SDR_LDO3_UV */
+#define WM8400_SDR_LDO3_UV_SHIFT                     2  /* SDR_LDO3_UV */
+#define WM8400_SDR_LDO3_UV_WIDTH                     1  /* SDR_LDO3_UV */
+#define WM8400_SDR_LDO2_UV                      0x0002  /* SDR_LDO2_UV */
+#define WM8400_SDR_LDO2_UV_MASK                 0x0002  /* SDR_LDO2_UV */
+#define WM8400_SDR_LDO2_UV_SHIFT                     1  /* SDR_LDO2_UV */
+#define WM8400_SDR_LDO2_UV_WIDTH                     1  /* SDR_LDO2_UV */
+#define WM8400_SDR_LDO1_UV                      0x0001  /* SDR_LDO1_UV */
+#define WM8400_SDR_LDO1_UV_MASK                 0x0001  /* SDR_LDO1_UV */
+#define WM8400_SDR_LDO1_UV_SHIFT                     0  /* SDR_LDO1_UV */
+#define WM8400_SDR_LDO1_UV_WIDTH                     1  /* SDR_LDO1_UV */
+
+/*
+ * R84 (0x54) - Line Circuits
+ */
+#define WM8400_BG_LINE_COMP                     0x8000  /* BG_LINE_COMP */
+#define WM8400_BG_LINE_COMP_MASK                0x8000  /* BG_LINE_COMP */
+#define WM8400_BG_LINE_COMP_SHIFT                   15  /* BG_LINE_COMP */
+#define WM8400_BG_LINE_COMP_WIDTH                    1  /* BG_LINE_COMP */
+#define WM8400_LINE_CMP_VTHI_MASK               0x00F0  /* LINE_CMP_VTHI - [7:4] */
+#define WM8400_LINE_CMP_VTHI_SHIFT                   4  /* LINE_CMP_VTHI - [7:4] */
+#define WM8400_LINE_CMP_VTHI_WIDTH                   4  /* LINE_CMP_VTHI - [7:4] */
+#define WM8400_LINE_CMP_VTHD_MASK               0x000F  /* LINE_CMP_VTHD - [3:0] */
+#define WM8400_LINE_CMP_VTHD_SHIFT                   0  /* LINE_CMP_VTHD - [3:0] */
+#define WM8400_LINE_CMP_VTHD_WIDTH                   4  /* LINE_CMP_VTHD - [3:0] */
+
+u16 wm8400_reg_read(struct wm8400 *wm8400, u8 reg);
+int wm8400_block_read(struct wm8400 *wm8400, u8 reg, int count, u16 *data);
+int wm8400_set_bits(struct wm8400 *wm8400, u8 reg, u16 mask, u16 val);
+
+#endif
diff --git a/include/linux/mfd/wm8400.h b/include/linux/mfd/wm8400.h
new file mode 100644
index 0000000..b46b566
--- /dev/null
+++ b/include/linux/mfd/wm8400.h
@@ -0,0 +1,40 @@
+/*
+ * wm8400 client interface
+ *
+ * Copyright 2008 Wolfson Microelectronics plc
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __LINUX_MFD_WM8400_H
+#define __LINUX_MFD_WM8400_H
+
+#include <linux/regulator/machine.h>
+
+#define WM8400_LDO1  0
+#define WM8400_LDO2  1
+#define WM8400_LDO3  2
+#define WM8400_LDO4  3
+#define WM8400_DCDC1 4
+#define WM8400_DCDC2 5
+
+struct wm8400_platform_data {
+	int (*platform_init)(struct device *dev);
+};
+
+int wm8400_register_regulator(struct device *dev, int reg,
+			      struct regulator_init_data *initdata);
+
+#endif
diff --git a/include/linux/mlx4/device.h b/include/linux/mlx4/device.h
index 655ea0d..b2f9444 100644
--- a/include/linux/mlx4/device.h
+++ b/include/linux/mlx4/device.h
@@ -141,6 +141,10 @@
 	MLX4_STAT_RATE_OFFSET	= 5
 };
 
+enum {
+	MLX4_MTT_FLAG_PRESENT		= 1
+};
+
 static inline u64 mlx4_fw_ver(u64 major, u64 minor, u64 subminor)
 {
 	return (major << 32) | (minor << 16) | subminor;
diff --git a/include/linux/mm.h b/include/linux/mm.h
index 72a15dc..c61ba10 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -7,6 +7,7 @@
 
 #include <linux/gfp.h>
 #include <linux/list.h>
+#include <linux/mmdebug.h>
 #include <linux/mmzone.h>
 #include <linux/rbtree.h>
 #include <linux/prio_tree.h>
@@ -219,12 +220,6 @@
  */
 #include <linux/page-flags.h>
 
-#ifdef CONFIG_DEBUG_VM
-#define VM_BUG_ON(cond) BUG_ON(cond)
-#else
-#define VM_BUG_ON(condition) do { } while(0)
-#endif
-
 /*
  * Methods to modify the page usage count.
  *
@@ -919,7 +914,7 @@
 }
 #endif /* CONFIG_MMU && !__ARCH_HAS_4LEVEL_HACK */
 
-#if NR_CPUS >= CONFIG_SPLIT_PTLOCK_CPUS
+#if USE_SPLIT_PTLOCKS
 /*
  * We tuck a spinlock to guard each pagetable page into its struct page,
  * at page->private, with BUILD_BUG_ON to make sure that this will not
@@ -932,14 +927,14 @@
 } while (0)
 #define pte_lock_deinit(page)	((page)->mapping = NULL)
 #define pte_lockptr(mm, pmd)	({(void)(mm); __pte_lockptr(pmd_page(*(pmd)));})
-#else
+#else	/* !USE_SPLIT_PTLOCKS */
 /*
  * We use mm->page_table_lock to guard all pagetable pages of the mm.
  */
 #define pte_lock_init(page)	do {} while (0)
 #define pte_lock_deinit(page)	do {} while (0)
 #define pte_lockptr(mm, pmd)	({(void)(pmd); &(mm)->page_table_lock;})
-#endif /* NR_CPUS < CONFIG_SPLIT_PTLOCK_CPUS */
+#endif /* USE_SPLIT_PTLOCKS */
 
 static inline void pgtable_page_ctor(struct page *page)
 {
diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h
index bf33413..9d49fa3 100644
--- a/include/linux/mm_types.h
+++ b/include/linux/mm_types.h
@@ -21,11 +21,13 @@
 
 struct address_space;
 
-#if NR_CPUS >= CONFIG_SPLIT_PTLOCK_CPUS
+#define USE_SPLIT_PTLOCKS	(NR_CPUS >= CONFIG_SPLIT_PTLOCK_CPUS)
+
+#if USE_SPLIT_PTLOCKS
 typedef atomic_long_t mm_counter_t;
-#else  /* NR_CPUS < CONFIG_SPLIT_PTLOCK_CPUS */
+#else  /* !USE_SPLIT_PTLOCKS */
 typedef unsigned long mm_counter_t;
-#endif /* NR_CPUS < CONFIG_SPLIT_PTLOCK_CPUS */
+#endif /* !USE_SPLIT_PTLOCKS */
 
 /*
  * Each physical page in the system has a struct page associated with
@@ -65,7 +67,7 @@
 						 * see PAGE_MAPPING_ANON below.
 						 */
 	    };
-#if NR_CPUS >= CONFIG_SPLIT_PTLOCK_CPUS
+#if USE_SPLIT_PTLOCKS
 	    spinlock_t ptl;
 #endif
 	    struct kmem_cache *slab;	/* SLUB: Pointer to slab */
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index 9c288c9..bde891f 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -65,7 +65,7 @@
 	 *   -ENOSYS when not supported (equal to NULL callback)
 	 *   or a negative errno value when something bad happened
 	 *
-	 * Return values for the get_ro callback should be:
+	 * Return values for the get_cd callback should be:
 	 *   0 for a absent card
 	 *   1 for a present card
 	 *   -ENOSYS when not supported (equal to NULL callback)
diff --git a/include/linux/mmdebug.h b/include/linux/mmdebug.h
new file mode 100644
index 0000000..8a55098
--- /dev/null
+++ b/include/linux/mmdebug.h
@@ -0,0 +1,18 @@
+#ifndef LINUX_MM_DEBUG_H
+#define LINUX_MM_DEBUG_H 1
+
+#include <linux/autoconf.h>
+
+#ifdef CONFIG_DEBUG_VM
+#define VM_BUG_ON(cond) BUG_ON(cond)
+#else
+#define VM_BUG_ON(cond) do { } while (0)
+#endif
+
+#ifdef CONFIG_DEBUG_VIRTUAL
+#define VIRTUAL_BUG_ON(cond) BUG_ON(cond)
+#else
+#define VIRTUAL_BUG_ON(cond) do { } while (0)
+#endif
+
+#endif
diff --git a/include/linux/mod_devicetable.h b/include/linux/mod_devicetable.h
index c4db582..d6a3f47 100644
--- a/include/linux/mod_devicetable.h
+++ b/include/linux/mod_devicetable.h
@@ -131,6 +131,16 @@
 #define USB_DEVICE_ID_MATCH_INT_SUBCLASS	0x0100
 #define USB_DEVICE_ID_MATCH_INT_PROTOCOL	0x0200
 
+#define HID_ANY_ID				(~0)
+
+struct hid_device_id {
+	__u16 bus;
+	__u32 vendor;
+	__u32 product;
+	kernel_ulong_t driver_data
+		__attribute__((aligned(sizeof(kernel_ulong_t))));
+};
+
 /* s390 CCW devices */
 struct ccw_device_id {
 	__u16	match_flags;	/* which fields to match against */
@@ -388,5 +398,52 @@
 			__attribute__((aligned(sizeof(kernel_ulong_t))));
 };
 
+/* dmi */
+enum dmi_field {
+	DMI_NONE,
+	DMI_BIOS_VENDOR,
+	DMI_BIOS_VERSION,
+	DMI_BIOS_DATE,
+	DMI_SYS_VENDOR,
+	DMI_PRODUCT_NAME,
+	DMI_PRODUCT_VERSION,
+	DMI_PRODUCT_SERIAL,
+	DMI_PRODUCT_UUID,
+	DMI_BOARD_VENDOR,
+	DMI_BOARD_NAME,
+	DMI_BOARD_VERSION,
+	DMI_BOARD_SERIAL,
+	DMI_BOARD_ASSET_TAG,
+	DMI_CHASSIS_VENDOR,
+	DMI_CHASSIS_TYPE,
+	DMI_CHASSIS_VERSION,
+	DMI_CHASSIS_SERIAL,
+	DMI_CHASSIS_ASSET_TAG,
+	DMI_STRING_MAX,
+};
+
+struct dmi_strmatch {
+	unsigned char slot;
+	char substr[79];
+};
+
+#ifndef __KERNEL__
+struct dmi_system_id {
+	kernel_ulong_t callback;
+	kernel_ulong_t ident;
+	struct dmi_strmatch matches[4];
+	kernel_ulong_t driver_data
+			__attribute__((aligned(sizeof(kernel_ulong_t))));
+};
+#else
+struct dmi_system_id {
+	int (*callback)(const struct dmi_system_id *);
+	const char *ident;
+	struct dmi_strmatch matches[4];
+	void *driver_data;
+};
+#endif
+
+#define DMI_MATCH(a, b)	{ a, b }
 
 #endif /* LINUX_MOD_DEVICETABLE_H */
diff --git a/include/linux/mtd/blktrans.h b/include/linux/mtd/blktrans.h
index 310e616..8b4aa05 100644
--- a/include/linux/mtd/blktrans.h
+++ b/include/linux/mtd/blktrans.h
@@ -41,6 +41,8 @@
 		    unsigned long block, char *buffer);
 	int (*writesect)(struct mtd_blktrans_dev *dev,
 		     unsigned long block, char *buffer);
+	int (*discard)(struct mtd_blktrans_dev *dev,
+		       unsigned long block, unsigned nr_blocks);
 
 	/* Block layer ioctls */
 	int (*getgeo)(struct mtd_blktrans_dev *dev, struct hd_geometry *geo);
diff --git a/include/linux/mv643xx_eth.h b/include/linux/mv643xx_eth.h
index 1207857..cbbbe9b 100644
--- a/include/linux/mv643xx_eth.h
+++ b/include/linux/mv643xx_eth.h
@@ -17,9 +17,14 @@
 
 struct mv643xx_eth_shared_platform_data {
 	struct mbus_dram_target_info	*dram;
+	struct platform_device	*shared_smi;
 	unsigned int		t_clk;
 };
 
+#define MV643XX_ETH_PHY_ADDR_DEFAULT	0
+#define MV643XX_ETH_PHY_ADDR(x)		(0x80 | (x))
+#define MV643XX_ETH_PHY_NONE		0xff
+
 struct mv643xx_eth_platform_data {
 	/*
 	 * Pointer back to our parent instance, and our port number.
@@ -30,8 +35,6 @@
 	/*
 	 * Whether a PHY is present, and if yes, at which address.
 	 */
-	struct platform_device	*shared_smi;
-	int			force_phy_addr;
 	int			phy_addr;
 
 	/*
@@ -49,10 +52,10 @@
 	int			duplex;
 
 	/*
-	 * Which RX/TX queues to use.
+	 * How many RX/TX queues to use.
 	 */
-	int			rx_queue_mask;
-	int			tx_queue_mask;
+	int			rx_queue_count;
+	int			tx_queue_count;
 
 	/*
 	 * Override default RX/TX queue sizes if nonzero.
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 488c56e..6487585 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -11,7 +11,7 @@
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
  *		Corey Minyard <wf-rch!minyard@relay.EU.net>
  *		Donald J. Becker, <becker@cesdis.gsfc.nasa.gov>
- *		Alan Cox, <Alan.Cox@linux.org>
+ *		Alan Cox, <alan@lxorguk.ukuu.org.uk>
  *		Bjorn Ekwall. <bj0rn@blox.se>
  *              Pekka Riikonen <priikone@poseidon.pspt.fi>
  *
@@ -42,6 +42,7 @@
 #include <linux/workqueue.h>
 
 #include <net/net_namespace.h>
+#include <net/dsa.h>
 
 struct vlan_group;
 struct ethtool_ops;
@@ -471,6 +472,8 @@
 	char			name[IFNAMSIZ];
 	/* device name hash chain */
 	struct hlist_node	name_hlist;
+	/* snmp alias */
+	char 			*ifalias;
 
 	/*
 	 *	I/O specific fields
@@ -605,6 +608,9 @@
 
 	/* Protocol specific pointers */
 	
+#ifdef CONFIG_NET_DSA
+	void			*dsa_ptr;	/* dsa specific data */
+#endif
 	void 			*atalk_ptr;	/* AppleTalk link 	*/
 	void			*ip_ptr;	/* IPv4 specific data	*/  
 	void                    *dn_ptr;        /* DECnet specific data */
@@ -796,6 +802,26 @@
 #endif
 }
 
+static inline bool netdev_uses_dsa_tags(struct net_device *dev)
+{
+#ifdef CONFIG_NET_DSA_TAG_DSA
+	if (dev->dsa_ptr != NULL)
+		return dsa_uses_dsa_tags(dev->dsa_ptr);
+#endif
+
+	return 0;
+}
+
+static inline bool netdev_uses_trailer_tags(struct net_device *dev)
+{
+#ifdef CONFIG_NET_DSA_TAG_TRAILER
+	if (dev->dsa_ptr != NULL)
+		return dsa_uses_trailer_tags(dev->dsa_ptr);
+#endif
+
+	return 0;
+}
+
 /**
  *	netdev_priv - access network device private data
  *	@dev: network device
@@ -1223,7 +1249,8 @@
 extern int		dev_ethtool(struct net *net, struct ifreq *);
 extern unsigned		dev_get_flags(const struct net_device *);
 extern int		dev_change_flags(struct net_device *, unsigned);
-extern int		dev_change_name(struct net_device *, char *);
+extern int		dev_change_name(struct net_device *, const char *);
+extern int		dev_set_alias(struct net_device *, const char *, size_t);
 extern int		dev_change_net_namespace(struct net_device *,
 						 struct net *, const char *);
 extern int		dev_set_mtu(struct net_device *, int);
@@ -1667,7 +1694,7 @@
 extern int netdev_class_create_file(struct class_attribute *class_attr);
 extern void netdev_class_remove_file(struct class_attribute *class_attr);
 
-extern char *netdev_drivername(struct net_device *dev, char *buffer, int len);
+extern char *netdev_drivername(const struct net_device *dev, char *buffer, int len);
 
 extern void linkwatch_run_queue(void);
 
diff --git a/include/linux/netfilter.h b/include/linux/netfilter.h
index 0c5eb7e..48cfe51 100644
--- a/include/linux/netfilter.h
+++ b/include/linux/netfilter.h
@@ -5,13 +5,11 @@
 #include <linux/init.h>
 #include <linux/skbuff.h>
 #include <linux/net.h>
-#include <linux/netdevice.h>
 #include <linux/if.h>
 #include <linux/in.h>
 #include <linux/in6.h>
 #include <linux/wait.h>
 #include <linux/list.h>
-#include <net/net_namespace.h>
 #endif
 #include <linux/types.h>
 #include <linux/compiler.h>
@@ -52,6 +50,16 @@
 	NF_INET_NUMHOOKS
 };
 
+enum {
+	NFPROTO_UNSPEC =  0,
+	NFPROTO_IPV4   =  2,
+	NFPROTO_ARP    =  3,
+	NFPROTO_BRIDGE =  7,
+	NFPROTO_IPV6   = 10,
+	NFPROTO_DECNET = 12,
+	NFPROTO_NUMPROTO,
+};
+
 union nf_inet_addr {
 	__u32		all[4];
 	__be32		ip;
@@ -92,8 +100,8 @@
 	/* User fills in from here down. */
 	nf_hookfn *hook;
 	struct module *owner;
-	int pf;
-	int hooknum;
+	u_int8_t pf;
+	unsigned int hooknum;
 	/* Hooks are ordered in ascending priority. */
 	int priority;
 };
@@ -102,7 +110,7 @@
 {
 	struct list_head list;
 
-	int pf;
+	u_int8_t pf;
 
 	/* Non-inclusive ranges: use 0/0/NULL to never get called. */
 	int set_optmin;
@@ -138,9 +146,9 @@
 extern struct ctl_path nf_net_ipv4_netfilter_sysctl_path[];
 #endif /* CONFIG_SYSCTL */
 
-extern struct list_head nf_hooks[NPROTO][NF_MAX_HOOKS];
+extern struct list_head nf_hooks[NFPROTO_NUMPROTO][NF_MAX_HOOKS];
 
-int nf_hook_slow(int pf, unsigned int hook, struct sk_buff *skb,
+int nf_hook_slow(u_int8_t pf, unsigned int hook, struct sk_buff *skb,
 		 struct net_device *indev, struct net_device *outdev,
 		 int (*okfn)(struct sk_buff *), int thresh);
 
@@ -151,7 +159,7 @@
  *	okfn must be invoked by the caller in this case.  Any other return
  *	value indicates the packet has been consumed by the hook.
  */
-static inline int nf_hook_thresh(int pf, unsigned int hook,
+static inline int nf_hook_thresh(u_int8_t pf, unsigned int hook,
 				 struct sk_buff *skb,
 				 struct net_device *indev,
 				 struct net_device *outdev,
@@ -167,7 +175,7 @@
 	return nf_hook_slow(pf, hook, skb, indev, outdev, okfn, thresh);
 }
 
-static inline int nf_hook(int pf, unsigned int hook, struct sk_buff *skb,
+static inline int nf_hook(u_int8_t pf, unsigned int hook, struct sk_buff *skb,
 			  struct net_device *indev, struct net_device *outdev,
 			  int (*okfn)(struct sk_buff *))
 {
@@ -212,14 +220,14 @@
 	NF_HOOK_THRESH(pf, hook, skb, indev, outdev, okfn, INT_MIN)
 
 /* Call setsockopt() */
-int nf_setsockopt(struct sock *sk, int pf, int optval, char __user *opt, 
+int nf_setsockopt(struct sock *sk, u_int8_t pf, int optval, char __user *opt,
 		  int len);
-int nf_getsockopt(struct sock *sk, int pf, int optval, char __user *opt,
+int nf_getsockopt(struct sock *sk, u_int8_t pf, int optval, char __user *opt,
 		  int *len);
 
-int compat_nf_setsockopt(struct sock *sk, int pf, int optval,
+int compat_nf_setsockopt(struct sock *sk, u_int8_t pf, int optval,
 		char __user *opt, int len);
-int compat_nf_getsockopt(struct sock *sk, int pf, int optval,
+int compat_nf_getsockopt(struct sock *sk, u_int8_t pf, int optval,
 		char __user *opt, int *len);
 
 /* Call this before modifying an existing packet: ensures it is
@@ -247,7 +255,7 @@
 	int		route_key_size;
 };
 
-extern const struct nf_afinfo *nf_afinfo[NPROTO];
+extern const struct nf_afinfo *nf_afinfo[NFPROTO_NUMPROTO];
 static inline const struct nf_afinfo *nf_get_afinfo(unsigned short family)
 {
 	return rcu_dereference(nf_afinfo[family]);
@@ -292,7 +300,7 @@
 extern void (*ip_nat_decode_session)(struct sk_buff *, struct flowi *);
 
 static inline void
-nf_nat_decode_session(struct sk_buff *skb, struct flowi *fl, int family)
+nf_nat_decode_session(struct sk_buff *skb, struct flowi *fl, u_int8_t family)
 {
 #ifdef CONFIG_NF_NAT_NEEDED
 	void (*decodefn)(struct sk_buff *, struct flowi *);
@@ -315,7 +323,7 @@
 #else /* !CONFIG_NETFILTER */
 #define NF_HOOK(pf, hook, skb, indev, outdev, okfn) (okfn)(skb)
 #define NF_HOOK_COND(pf, hook, skb, indev, outdev, okfn, cond) (okfn)(skb)
-static inline int nf_hook_thresh(int pf, unsigned int hook,
+static inline int nf_hook_thresh(u_int8_t pf, unsigned int hook,
 				 struct sk_buff *skb,
 				 struct net_device *indev,
 				 struct net_device *outdev,
@@ -324,7 +332,7 @@
 {
 	return okfn(skb);
 }
-static inline int nf_hook(int pf, unsigned int hook, struct sk_buff *skb,
+static inline int nf_hook(u_int8_t pf, unsigned int hook, struct sk_buff *skb,
 			  struct net_device *indev, struct net_device *outdev,
 			  int (*okfn)(struct sk_buff *))
 {
@@ -332,7 +340,9 @@
 }
 struct flowi;
 static inline void
-nf_nat_decode_session(struct sk_buff *skb, struct flowi *fl, int family) {}
+nf_nat_decode_session(struct sk_buff *skb, struct flowi *fl, u_int8_t family)
+{
+}
 #endif /*CONFIG_NETFILTER*/
 
 #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
@@ -343,56 +353,5 @@
 static inline void nf_ct_attach(struct sk_buff *new, struct sk_buff *skb) {}
 #endif
 
-static inline struct net *nf_pre_routing_net(const struct net_device *in,
-					     const struct net_device *out)
-{
-#ifdef CONFIG_NET_NS
-	return in->nd_net;
-#else
-	return &init_net;
-#endif
-}
-
-static inline struct net *nf_local_in_net(const struct net_device *in,
-					  const struct net_device *out)
-{
-#ifdef CONFIG_NET_NS
-	return in->nd_net;
-#else
-	return &init_net;
-#endif
-}
-
-static inline struct net *nf_forward_net(const struct net_device *in,
-					 const struct net_device *out)
-{
-#ifdef CONFIG_NET_NS
-	BUG_ON(in->nd_net != out->nd_net);
-	return in->nd_net;
-#else
-	return &init_net;
-#endif
-}
-
-static inline struct net *nf_local_out_net(const struct net_device *in,
-					   const struct net_device *out)
-{
-#ifdef CONFIG_NET_NS
-	return out->nd_net;
-#else
-	return &init_net;
-#endif
-}
-
-static inline struct net *nf_post_routing_net(const struct net_device *in,
-					      const struct net_device *out)
-{
-#ifdef CONFIG_NET_NS
-	return out->nd_net;
-#else
-	return &init_net;
-#endif
-}
-
 #endif /*__KERNEL__*/
 #endif /*__LINUX_NETFILTER_H*/
diff --git a/include/linux/netfilter/Kbuild b/include/linux/netfilter/Kbuild
index 3aff513..5a8af87 100644
--- a/include/linux/netfilter/Kbuild
+++ b/include/linux/netfilter/Kbuild
@@ -32,6 +32,7 @@
 header-y += xt_pkttype.h
 header-y += xt_rateest.h
 header-y += xt_realm.h
+header-y += xt_recent.h
 header-y += xt_sctp.h
 header-y += xt_state.h
 header-y += xt_statistic.h
diff --git a/include/linux/netfilter/nf_conntrack_proto_gre.h b/include/linux/netfilter/nf_conntrack_proto_gre.h
index 535e4219..2a10efd 100644
--- a/include/linux/netfilter/nf_conntrack_proto_gre.h
+++ b/include/linux/netfilter/nf_conntrack_proto_gre.h
@@ -87,7 +87,7 @@
 /* delete keymap entries */
 void nf_ct_gre_keymap_destroy(struct nf_conn *ct);
 
-extern void nf_ct_gre_keymap_flush(void);
+extern void nf_ct_gre_keymap_flush(struct net *net);
 extern void nf_nat_need_gre(void);
 
 #endif /* __KERNEL__ */
diff --git a/include/linux/netfilter/x_tables.h b/include/linux/netfilter/x_tables.h
index 2326296..be41b60 100644
--- a/include/linux/netfilter/x_tables.h
+++ b/include/linux/netfilter/x_tables.h
@@ -173,6 +173,98 @@
 
 #include <linux/netdevice.h>
 
+/**
+ * struct xt_match_param - parameters for match extensions' match functions
+ *
+ * @in:		input netdevice
+ * @out:	output netdevice
+ * @match:	struct xt_match through which this function was invoked
+ * @matchinfo:	per-match data
+ * @fragoff:	packet is a fragment, this is the data offset
+ * @thoff:	position of transport header relative to skb->data
+ * @hotdrop:	drop packet if we had inspection problems
+ * @family:	Actual NFPROTO_* through which the function is invoked
+ * 		(helpful when match->family == NFPROTO_UNSPEC)
+ */
+struct xt_match_param {
+	const struct net_device *in, *out;
+	const struct xt_match *match;
+	const void *matchinfo;
+	int fragoff;
+	unsigned int thoff;
+	bool *hotdrop;
+	u_int8_t family;
+};
+
+/**
+ * struct xt_mtchk_param - parameters for match extensions'
+ * checkentry functions
+ *
+ * @table:	table the rule is tried to be inserted into
+ * @entryinfo:	the family-specific rule data
+ * 		(struct ipt_ip, ip6t_ip, ebt_entry)
+ * @match:	struct xt_match through which this function was invoked
+ * @matchinfo:	per-match data
+ * @hook_mask:	via which hooks the new rule is reachable
+ */
+struct xt_mtchk_param {
+	const char *table;
+	const void *entryinfo;
+	const struct xt_match *match;
+	void *matchinfo;
+	unsigned int hook_mask;
+	u_int8_t family;
+};
+
+/* Match destructor parameters */
+struct xt_mtdtor_param {
+	const struct xt_match *match;
+	void *matchinfo;
+	u_int8_t family;
+};
+
+/**
+ * struct xt_target_param - parameters for target extensions' target functions
+ *
+ * @hooknum:	hook through which this target was invoked
+ * @target:	struct xt_target through which this function was invoked
+ * @targinfo:	per-target data
+ *
+ * Other fields see above.
+ */
+struct xt_target_param {
+	const struct net_device *in, *out;
+	unsigned int hooknum;
+	const struct xt_target *target;
+	const void *targinfo;
+	u_int8_t family;
+};
+
+/**
+ * struct xt_tgchk_param - parameters for target extensions'
+ * checkentry functions
+ *
+ * @entryinfo:	the family-specific rule data
+ * 		(struct ipt_entry, ip6t_entry, arpt_entry, ebt_entry)
+ *
+ * Other fields see above.
+ */
+struct xt_tgchk_param {
+	const char *table;
+	void *entryinfo;
+	const struct xt_target *target;
+	void *targinfo;
+	unsigned int hook_mask;
+	u_int8_t family;
+};
+
+/* Target destructor parameters */
+struct xt_tgdtor_param {
+	const struct xt_target *target;
+	void *targinfo;
+	u_int8_t family;
+};
+
 struct xt_match
 {
 	struct list_head list;
@@ -185,24 +277,13 @@
 	   non-linear skb, using skb_header_pointer and
 	   skb_ip_make_writable. */
 	bool (*match)(const struct sk_buff *skb,
-		      const struct net_device *in,
-		      const struct net_device *out,
-		      const struct xt_match *match,
-		      const void *matchinfo,
-		      int offset,
-		      unsigned int protoff,
-		      bool *hotdrop);
+		      const struct xt_match_param *);
 
 	/* Called when user tries to insert an entry of this type. */
-	/* Should return true or false. */
-	bool (*checkentry)(const char *tablename,
-			   const void *ip,
-			   const struct xt_match *match,
-			   void *matchinfo,
-			   unsigned int hook_mask);
+	bool (*checkentry)(const struct xt_mtchk_param *);
 
 	/* Called when entry of this type deleted. */
-	void (*destroy)(const struct xt_match *match, void *matchinfo);
+	void (*destroy)(const struct xt_mtdtor_param *);
 
 	/* Called when userspace align differs from kernel space one */
 	void (*compat_from_user)(void *dst, void *src);
@@ -235,24 +316,16 @@
 	   must now handle non-linear skbs, using skb_copy_bits and
 	   skb_ip_make_writable. */
 	unsigned int (*target)(struct sk_buff *skb,
-			       const struct net_device *in,
-			       const struct net_device *out,
-			       unsigned int hooknum,
-			       const struct xt_target *target,
-			       const void *targinfo);
+			       const struct xt_target_param *);
 
 	/* Called when user tries to insert an entry of this type:
            hook_mask is a bitmask of hooks from which it can be
            called. */
 	/* Should return true or false. */
-	bool (*checkentry)(const char *tablename,
-			   const void *entry,
-			   const struct xt_target *target,
-			   void *targinfo,
-			   unsigned int hook_mask);
+	bool (*checkentry)(const struct xt_tgchk_param *);
 
 	/* Called when entry of this type deleted. */
-	void (*destroy)(const struct xt_target *target, void *targinfo);
+	void (*destroy)(const struct xt_tgdtor_param *);
 
 	/* Called when userspace align differs from kernel space one */
 	void (*compat_from_user)(void *dst, void *src);
@@ -292,7 +365,7 @@
 	/* Set this to THIS_MODULE if you are a module, otherwise NULL */
 	struct module *me;
 
-	int af;		/* address/protocol family */
+	u_int8_t af;		/* address/protocol family */
 };
 
 #include <linux/netfilter_ipv4.h>
@@ -328,12 +401,10 @@
 extern int xt_register_matches(struct xt_match *match, unsigned int n);
 extern void xt_unregister_matches(struct xt_match *match, unsigned int n);
 
-extern int xt_check_match(const struct xt_match *match, unsigned short family,
-			  unsigned int size, const char *table, unsigned int hook,
-			  unsigned short proto, int inv_proto);
-extern int xt_check_target(const struct xt_target *target, unsigned short family,
-			   unsigned int size, const char *table, unsigned int hook,
-			   unsigned short proto, int inv_proto);
+extern int xt_check_match(struct xt_mtchk_param *,
+			  unsigned int size, u_int8_t proto, bool inv_proto);
+extern int xt_check_target(struct xt_tgchk_param *,
+			   unsigned int size, u_int8_t proto, bool inv_proto);
 
 extern struct xt_table *xt_register_table(struct net *net,
 					  struct xt_table *table,
@@ -346,19 +417,19 @@
 					      struct xt_table_info *newinfo,
 					      int *error);
 
-extern struct xt_match *xt_find_match(int af, const char *name, u8 revision);
-extern struct xt_target *xt_find_target(int af, const char *name, u8 revision);
-extern struct xt_target *xt_request_find_target(int af, const char *name, 
+extern struct xt_match *xt_find_match(u8 af, const char *name, u8 revision);
+extern struct xt_target *xt_find_target(u8 af, const char *name, u8 revision);
+extern struct xt_target *xt_request_find_target(u8 af, const char *name,
 						u8 revision);
-extern int xt_find_revision(int af, const char *name, u8 revision, int target,
-			    int *err);
+extern int xt_find_revision(u8 af, const char *name, u8 revision,
+			    int target, int *err);
 
-extern struct xt_table *xt_find_table_lock(struct net *net, int af,
+extern struct xt_table *xt_find_table_lock(struct net *net, u_int8_t af,
 					   const char *name);
 extern void xt_table_unlock(struct xt_table *t);
 
-extern int xt_proto_init(struct net *net, int af);
-extern void xt_proto_fini(struct net *net, int af);
+extern int xt_proto_init(struct net *net, u_int8_t af);
+extern void xt_proto_fini(struct net *net, u_int8_t af);
 
 extern struct xt_table_info *xt_alloc_table_info(unsigned int size);
 extern void xt_free_table_info(struct xt_table_info *info);
@@ -423,12 +494,12 @@
 #define COMPAT_XT_ALIGN(s) (((s) + (__alignof__(struct compat_xt_counters)-1)) \
 		& ~(__alignof__(struct compat_xt_counters)-1))
 
-extern void xt_compat_lock(int af);
-extern void xt_compat_unlock(int af);
+extern void xt_compat_lock(u_int8_t af);
+extern void xt_compat_unlock(u_int8_t af);
 
-extern int xt_compat_add_offset(int af, unsigned int offset, short delta);
-extern void xt_compat_flush_offsets(int af);
-extern short xt_compat_calc_jump(int af, unsigned int offset);
+extern int xt_compat_add_offset(u_int8_t af, unsigned int offset, short delta);
+extern void xt_compat_flush_offsets(u_int8_t af);
+extern short xt_compat_calc_jump(u_int8_t af, unsigned int offset);
 
 extern int xt_compat_match_offset(const struct xt_match *match);
 extern int xt_compat_match_from_user(struct xt_entry_match *m,
diff --git a/include/linux/netfilter/xt_TPROXY.h b/include/linux/netfilter/xt_TPROXY.h
new file mode 100644
index 0000000..152e8f9
--- /dev/null
+++ b/include/linux/netfilter/xt_TPROXY.h
@@ -0,0 +1,14 @@
+#ifndef _XT_TPROXY_H_target
+#define _XT_TPROXY_H_target
+
+/* TPROXY target is capable of marking the packet to perform
+ * redirection. We can get rid of that whenever we get support for
+ * mutliple targets in the same rule. */
+struct xt_tproxy_target_info {
+	u_int32_t mark_mask;
+	u_int32_t mark_value;
+	__be32 laddr;
+	__be16 lport;
+};
+
+#endif /* _XT_TPROXY_H_target */
diff --git a/include/linux/netfilter/xt_recent.h b/include/linux/netfilter/xt_recent.h
new file mode 100644
index 0000000..5cfeb81
--- /dev/null
+++ b/include/linux/netfilter/xt_recent.h
@@ -0,0 +1,26 @@
+#ifndef _LINUX_NETFILTER_XT_RECENT_H
+#define _LINUX_NETFILTER_XT_RECENT_H 1
+
+enum {
+	XT_RECENT_CHECK    = 1 << 0,
+	XT_RECENT_SET      = 1 << 1,
+	XT_RECENT_UPDATE   = 1 << 2,
+	XT_RECENT_REMOVE   = 1 << 3,
+	XT_RECENT_TTL      = 1 << 4,
+
+	XT_RECENT_SOURCE   = 0,
+	XT_RECENT_DEST     = 1,
+
+	XT_RECENT_NAME_LEN = 200,
+};
+
+struct xt_recent_mtinfo {
+	u_int32_t seconds;
+	u_int32_t hit_count;
+	u_int8_t check_set;
+	u_int8_t invert;
+	char name[XT_RECENT_NAME_LEN];
+	u_int8_t side;
+};
+
+#endif /* _LINUX_NETFILTER_XT_RECENT_H */
diff --git a/include/linux/netfilter_bridge/ebtables.h b/include/linux/netfilter_bridge/ebtables.h
index 892f5b7..d45e29c 100644
--- a/include/linux/netfilter_bridge/ebtables.h
+++ b/include/linux/netfilter_bridge/ebtables.h
@@ -31,6 +31,9 @@
  * The 4 lsb are more than enough to store the verdict. */
 #define EBT_VERDICT_BITS 0x0000000F
 
+struct xt_match;
+struct xt_target;
+
 struct ebt_counter
 {
 	uint64_t pcnt;
@@ -121,7 +124,7 @@
 {
 	union {
 		char name[EBT_FUNCTION_MAXNAMELEN];
-		struct ebt_match *match;
+		struct xt_match *match;
 	} u;
 	/* size of data */
 	unsigned int match_size;
@@ -132,7 +135,7 @@
 {
 	union {
 		char name[EBT_FUNCTION_MAXNAMELEN];
-		struct ebt_watcher *watcher;
+		struct xt_target *watcher;
 	} u;
 	/* size of data */
 	unsigned int watcher_size;
@@ -143,7 +146,7 @@
 {
 	union {
 		char name[EBT_FUNCTION_MAXNAMELEN];
-		struct ebt_target *target;
+		struct xt_target *target;
 	} u;
 	/* size of data */
 	unsigned int target_size;
@@ -207,14 +210,17 @@
 {
 	struct list_head list;
 	const char name[EBT_FUNCTION_MAXNAMELEN];
-	/* 0 == it matches */
-	int (*match)(const struct sk_buff *skb, const struct net_device *in,
-	   const struct net_device *out, const void *matchdata,
-	   unsigned int datalen);
-	/* 0 == let it in */
-	int (*check)(const char *tablename, unsigned int hookmask,
-	   const struct ebt_entry *e, void *matchdata, unsigned int datalen);
-	void (*destroy)(void *matchdata, unsigned int datalen);
+	bool (*match)(const struct sk_buff *skb, const struct net_device *in,
+		const struct net_device *out, const struct xt_match *match,
+		const void *matchinfo, int offset, unsigned int protoff,
+		bool *hotdrop);
+	bool (*checkentry)(const char *table, const void *entry,
+		const struct xt_match *match, void *matchinfo,
+		unsigned int hook_mask);
+	void (*destroy)(const struct xt_match *match, void *matchinfo);
+	unsigned int matchsize;
+	u_int8_t revision;
+	u_int8_t family;
 	struct module *me;
 };
 
@@ -222,13 +228,17 @@
 {
 	struct list_head list;
 	const char name[EBT_FUNCTION_MAXNAMELEN];
-	void (*watcher)(const struct sk_buff *skb, unsigned int hooknr,
-	   const struct net_device *in, const struct net_device *out,
-	   const void *watcherdata, unsigned int datalen);
-	/* 0 == let it in */
-	int (*check)(const char *tablename, unsigned int hookmask,
-	   const struct ebt_entry *e, void *watcherdata, unsigned int datalen);
-	void (*destroy)(void *watcherdata, unsigned int datalen);
+	unsigned int (*target)(struct sk_buff *skb,
+		const struct net_device *in, const struct net_device *out,
+		unsigned int hook_num, const struct xt_target *target,
+		const void *targinfo);
+	bool (*checkentry)(const char *table, const void *entry,
+		const struct xt_target *target, void *targinfo,
+		unsigned int hook_mask);
+	void (*destroy)(const struct xt_target *target, void *targinfo);
+	unsigned int targetsize;
+	u_int8_t revision;
+	u_int8_t family;
 	struct module *me;
 };
 
@@ -236,14 +246,18 @@
 {
 	struct list_head list;
 	const char name[EBT_FUNCTION_MAXNAMELEN];
-	/* returns one of the standard verdicts */
-	int (*target)(struct sk_buff *skb, unsigned int hooknr,
-	   const struct net_device *in, const struct net_device *out,
-	   const void *targetdata, unsigned int datalen);
-	/* 0 == let it in */
-	int (*check)(const char *tablename, unsigned int hookmask,
-	   const struct ebt_entry *e, void *targetdata, unsigned int datalen);
-	void (*destroy)(void *targetdata, unsigned int datalen);
+	/* returns one of the standard EBT_* verdicts */
+	unsigned int (*target)(struct sk_buff *skb,
+		const struct net_device *in, const struct net_device *out,
+		unsigned int hook_num, const struct xt_target *target,
+		const void *targinfo);
+	bool (*checkentry)(const char *table, const void *entry,
+		const struct xt_target *target, void *targinfo,
+		unsigned int hook_mask);
+	void (*destroy)(const struct xt_target *target, void *targinfo);
+	unsigned int targetsize;
+	u_int8_t revision;
+	u_int8_t family;
 	struct module *me;
 };
 
@@ -288,12 +302,6 @@
 		     ~(__alignof__(struct ebt_replace)-1))
 extern int ebt_register_table(struct ebt_table *table);
 extern void ebt_unregister_table(struct ebt_table *table);
-extern int ebt_register_match(struct ebt_match *match);
-extern void ebt_unregister_match(struct ebt_match *match);
-extern int ebt_register_watcher(struct ebt_watcher *watcher);
-extern void ebt_unregister_watcher(struct ebt_watcher *watcher);
-extern int ebt_register_target(struct ebt_target *target);
-extern void ebt_unregister_target(struct ebt_target *target);
 extern unsigned int ebt_do_table(unsigned int hook, struct sk_buff *skb,
    const struct net_device *in, const struct net_device *out,
    struct ebt_table *table);
@@ -302,9 +310,9 @@
 #define FWINV(bool,invflg) ((bool) ^ !!(info->invflags & invflg))
 /* True if the hook mask denotes that the rule is in a base chain,
  * used in the check() functions */
-#define BASE_CHAIN (hookmask & (1 << NF_BR_NUMHOOKS))
+#define BASE_CHAIN (par->hook_mask & (1 << NF_BR_NUMHOOKS))
 /* Clear the bit in the hook mask that tells if the rule is on a base chain */
-#define CLEAR_BASE_CHAIN_BIT (hookmask &= ~(1 << NF_BR_NUMHOOKS))
+#define CLEAR_BASE_CHAIN_BIT (par->hook_mask &= ~(1 << NF_BR_NUMHOOKS))
 /* True if the target is not a standard target */
 #define INVALID_TARGET (info->target < -NUM_STANDARD_TARGETS || info->target >= 0)
 
diff --git a/include/linux/netfilter_ipv4/ipt_recent.h b/include/linux/netfilter_ipv4/ipt_recent.h
index 6508a45..d636cca 100644
--- a/include/linux/netfilter_ipv4/ipt_recent.h
+++ b/include/linux/netfilter_ipv4/ipt_recent.h
@@ -1,27 +1,21 @@
 #ifndef _IPT_RECENT_H
 #define _IPT_RECENT_H
 
-#define RECENT_NAME	"ipt_recent"
-#define RECENT_VER	"v0.3.1"
+#include <linux/netfilter/xt_recent.h>
 
-#define IPT_RECENT_CHECK  1
-#define IPT_RECENT_SET    2
-#define IPT_RECENT_UPDATE 4
-#define IPT_RECENT_REMOVE 8
-#define IPT_RECENT_TTL   16
+#define ipt_recent_info xt_recent_mtinfo
 
-#define IPT_RECENT_SOURCE 0
-#define IPT_RECENT_DEST   1
+enum {
+	IPT_RECENT_CHECK    = XT_RECENT_CHECK,
+	IPT_RECENT_SET      = XT_RECENT_SET,
+	IPT_RECENT_UPDATE   = XT_RECENT_UPDATE,
+	IPT_RECENT_REMOVE   = XT_RECENT_REMOVE,
+	IPT_RECENT_TTL      = XT_RECENT_TTL,
 
-#define IPT_RECENT_NAME_LEN 200
+	IPT_RECENT_SOURCE   = XT_RECENT_SOURCE,
+	IPT_RECENT_DEST     = XT_RECENT_DEST,
 
-struct ipt_recent_info {
-	u_int32_t   seconds;
-	u_int32_t   hit_count;
-	u_int8_t    check_set;
-	u_int8_t    invert;
-	char        name[IPT_RECENT_NAME_LEN];
-	u_int8_t    side;
+	IPT_RECENT_NAME_LEN = XT_RECENT_NAME_LEN,
 };
 
 #endif /*_IPT_RECENT_H*/
diff --git a/include/linux/nfsd/nfsd.h b/include/linux/nfsd/nfsd.h
index 108f47e..2126940 100644
--- a/include/linux/nfsd/nfsd.h
+++ b/include/linux/nfsd/nfsd.h
@@ -38,6 +38,7 @@
 #define NFSD_MAY_LOCK		32
 #define NFSD_MAY_OWNER_OVERRIDE	64
 #define NFSD_MAY_LOCAL_ACCESS	128 /* IRIX doing local access check on device special file*/
+#define NFSD_MAY_BYPASS_GSS_ON_ROOT 256
 
 #define NFSD_MAY_CREATE		(NFSD_MAY_EXEC|NFSD_MAY_WRITE)
 #define NFSD_MAY_REMOVE		(NFSD_MAY_EXEC|NFSD_MAY_WRITE|NFSD_MAY_TRUNC)
@@ -125,7 +126,7 @@
 __be32		nfsd_readdir(struct svc_rqst *, struct svc_fh *,
 			     loff_t *, struct readdir_cd *, filldir_t);
 __be32		nfsd_statfs(struct svc_rqst *, struct svc_fh *,
-				struct kstatfs *);
+				struct kstatfs *, int access);
 
 int		nfsd_notify_change(struct inode *, struct iattr *);
 __be32		nfsd_permission(struct svc_rqst *, struct svc_export *,
diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h
index 2be7c63..9bad6540 100644
--- a/include/linux/nl80211.h
+++ b/include/linux/nl80211.h
@@ -89,6 +89,22 @@
  * @NL80211_CMD_DEL_PATH: Remove a mesh path identified by %NL80211_ATTR_MAC
  *	or, if no MAC address given, all mesh paths, on the interface identified
  *	by %NL80211_ATTR_IFINDEX.
+ * @NL80211_CMD_SET_BSS: Set BSS attributes for BSS identified by
+ *	%NL80211_ATTR_IFINDEX.
+ *
+ * @NL80211_CMD_SET_REG: Set current regulatory domain. CRDA sends this command
+ *	after being queried by the kernel. CRDA replies by sending a regulatory
+ *	domain structure which consists of %NL80211_ATTR_REG_ALPHA set to our
+ *	current alpha2 if it found a match. It also provides
+ * 	NL80211_ATTR_REG_RULE_FLAGS, and a set of regulatory rules. Each
+ * 	regulatory rule is a nested set of attributes  given by
+ * 	%NL80211_ATTR_REG_RULE_FREQ_[START|END] and
+ * 	%NL80211_ATTR_FREQ_RANGE_MAX_BW with an attached power rule given by
+ * 	%NL80211_ATTR_REG_RULE_POWER_MAX_ANT_GAIN and
+ * 	%NL80211_ATTR_REG_RULE_POWER_MAX_EIRP.
+ * @NL80211_CMD_REQ_SET_REG: ask the wireless core to set the regulatory domain
+ * 	to the the specified ISO/IEC 3166-1 alpha2 country code. The core will
+ * 	store this as a valid request and then query userspace for it.
  *
  * @NL80211_CMD_MAX: highest used command number
  * @__NL80211_CMD_AFTER_LAST: internal use
@@ -127,13 +143,23 @@
 	NL80211_CMD_NEW_MPATH,
 	NL80211_CMD_DEL_MPATH,
 
-	/* add commands here */
+	NL80211_CMD_SET_BSS,
+
+	NL80211_CMD_SET_REG,
+	NL80211_CMD_REQ_SET_REG,
+
+	/* add new commands above here */
 
 	/* used to define NL80211_CMD_MAX below */
 	__NL80211_CMD_AFTER_LAST,
 	NL80211_CMD_MAX = __NL80211_CMD_AFTER_LAST - 1
 };
 
+/*
+ * Allow user space programs to use #ifdef on new commands by defining them
+ * here
+ */
+#define NL80211_CMD_SET_BSS NL80211_CMD_SET_BSS
 
 /**
  * enum nl80211_attrs - nl80211 netlink attributes
@@ -188,10 +214,34 @@
  * 	info given for %NL80211_CMD_GET_MPATH, nested attribute described at
  *	&enum nl80211_mpath_info.
  *
- *
  * @NL80211_ATTR_MNTR_FLAGS: flags, nested element with NLA_FLAG attributes of
  *      &enum nl80211_mntr_flags.
  *
+ * @NL80211_ATTR_REG_ALPHA2: an ISO-3166-alpha2 country code for which the
+ * 	current regulatory domain should be set to or is already set to.
+ * 	For example, 'CR', for Costa Rica. This attribute is used by the kernel
+ * 	to query the CRDA to retrieve one regulatory domain. This attribute can
+ * 	also be used by userspace to query the kernel for the currently set
+ * 	regulatory domain. We chose an alpha2 as that is also used by the
+ * 	IEEE-802.11d country information element to identify a country.
+ * 	Users can also simply ask the wireless core to set regulatory domain
+ * 	to a specific alpha2.
+ * @NL80211_ATTR_REG_RULES: a nested array of regulatory domain regulatory
+ *	rules.
+ *
+ * @NL80211_ATTR_BSS_CTS_PROT: whether CTS protection is enabled (u8, 0 or 1)
+ * @NL80211_ATTR_BSS_SHORT_PREAMBLE: whether short preamble is enabled
+ *	(u8, 0 or 1)
+ * @NL80211_ATTR_BSS_SHORT_SLOT_TIME: whether short slot time enabled
+ *	(u8, 0 or 1)
+ *
+ * @NL80211_ATTR_HT_CAPABILITY: HT Capability information element (from
+ *	association request when used with NL80211_CMD_NEW_STATION)
+ *
+ * @NL80211_ATTR_SUPPORTED_IFTYPES: nested attribute containing all
+ *	supported interface types, each a flag attribute with the number
+ *	of the interface mode.
+ *
  * @NL80211_ATTR_MAX: highest attribute number currently defined
  * @__NL80211_ATTR_AFTER_LAST: internal use
  */
@@ -235,16 +285,35 @@
 	NL80211_ATTR_MPATH_NEXT_HOP,
 	NL80211_ATTR_MPATH_INFO,
 
+	NL80211_ATTR_BSS_CTS_PROT,
+	NL80211_ATTR_BSS_SHORT_PREAMBLE,
+	NL80211_ATTR_BSS_SHORT_SLOT_TIME,
+
+	NL80211_ATTR_HT_CAPABILITY,
+
+	NL80211_ATTR_SUPPORTED_IFTYPES,
+
+	NL80211_ATTR_REG_ALPHA2,
+	NL80211_ATTR_REG_RULES,
+
 	/* add attributes here, update the policy in nl80211.c */
 
 	__NL80211_ATTR_AFTER_LAST,
 	NL80211_ATTR_MAX = __NL80211_ATTR_AFTER_LAST - 1
 };
 
+/*
+ * Allow user space programs to use #ifdef on new attributes by defining them
+ * here
+ */
+#define NL80211_ATTR_HT_CAPABILITY NL80211_ATTR_HT_CAPABILITY
+
 #define NL80211_MAX_SUPP_RATES			32
+#define NL80211_MAX_SUPP_REG_RULES		32
 #define NL80211_TKIP_DATA_OFFSET_ENCR_KEY	0
 #define NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY	16
 #define NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY	24
+#define NL80211_HT_CAPABILITY_LEN		26
 
 /**
  * enum nl80211_iftype - (virtual) interface types
@@ -436,6 +505,66 @@
 };
 
 /**
+ * enum nl80211_reg_rule_attr - regulatory rule attributes
+ * @NL80211_ATTR_REG_RULE_FLAGS: a set of flags which specify additional
+ * 	considerations for a given frequency range. These are the
+ * 	&enum nl80211_reg_rule_flags.
+ * @NL80211_ATTR_FREQ_RANGE_START: starting frequencry for the regulatory
+ * 	rule in KHz. This is not a center of frequency but an actual regulatory
+ * 	band edge.
+ * @NL80211_ATTR_FREQ_RANGE_END: ending frequency for the regulatory rule
+ * 	in KHz. This is not a center a frequency but an actual regulatory
+ * 	band edge.
+ * @NL80211_ATTR_FREQ_RANGE_MAX_BW: maximum allowed bandwidth for this
+ * 	frequency range, in KHz.
+ * @NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN: the maximum allowed antenna gain
+ * 	for a given frequency range. The value is in mBi (100 * dBi).
+ * 	If you don't have one then don't send this.
+ * @NL80211_ATTR_POWER_RULE_MAX_EIRP: the maximum allowed EIRP for
+ * 	a given frequency range. The value is in mBm (100 * dBm).
+ */
+enum nl80211_reg_rule_attr {
+	__NL80211_REG_RULE_ATTR_INVALID,
+	NL80211_ATTR_REG_RULE_FLAGS,
+
+	NL80211_ATTR_FREQ_RANGE_START,
+	NL80211_ATTR_FREQ_RANGE_END,
+	NL80211_ATTR_FREQ_RANGE_MAX_BW,
+
+	NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN,
+	NL80211_ATTR_POWER_RULE_MAX_EIRP,
+
+	/* keep last */
+	__NL80211_REG_RULE_ATTR_AFTER_LAST,
+	NL80211_REG_RULE_ATTR_MAX = __NL80211_REG_RULE_ATTR_AFTER_LAST - 1
+};
+
+/**
+ * enum nl80211_reg_rule_flags - regulatory rule flags
+ *
+ * @NL80211_RRF_NO_OFDM: OFDM modulation not allowed
+ * @NL80211_RRF_NO_CCK: CCK modulation not allowed
+ * @NL80211_RRF_NO_INDOOR: indoor operation not allowed
+ * @NL80211_RRF_NO_OUTDOOR: outdoor operation not allowed
+ * @NL80211_RRF_DFS: DFS support is required to be used
+ * @NL80211_RRF_PTP_ONLY: this is only for Point To Point links
+ * @NL80211_RRF_PTMP_ONLY: this is only for Point To Multi Point links
+ * @NL80211_RRF_PASSIVE_SCAN: passive scan is required
+ * @NL80211_RRF_NO_IBSS: no IBSS is allowed
+ */
+enum nl80211_reg_rule_flags {
+	NL80211_RRF_NO_OFDM		= 1<<0,
+	NL80211_RRF_NO_CCK		= 1<<1,
+	NL80211_RRF_NO_INDOOR		= 1<<2,
+	NL80211_RRF_NO_OUTDOOR		= 1<<3,
+	NL80211_RRF_DFS			= 1<<4,
+	NL80211_RRF_PTP_ONLY		= 1<<5,
+	NL80211_RRF_PTMP_ONLY		= 1<<6,
+	NL80211_RRF_PASSIVE_SCAN	= 1<<7,
+	NL80211_RRF_NO_IBSS		= 1<<8,
+};
+
+/**
  * enum nl80211_mntr_flags - monitor configuration flags
  *
  * Monitor configuration flags.
diff --git a/include/linux/notifier.h b/include/linux/notifier.h
index da2698b..b86fa2f 100644
--- a/include/linux/notifier.h
+++ b/include/linux/notifier.h
@@ -213,9 +213,16 @@
 #define CPU_DOWN_FAILED		0x0006 /* CPU (unsigned)v NOT going down */
 #define CPU_DEAD		0x0007 /* CPU (unsigned)v dead */
 #define CPU_DYING		0x0008 /* CPU (unsigned)v not running any task,
-				        * not handling interrupts, soon dead */
+					* not handling interrupts, soon dead.
+					* Called on the dying cpu, interrupts
+					* are already disabled. Must not
+					* sleep, must not fail */
 #define CPU_POST_DEAD		0x0009 /* CPU (unsigned)v dead, cpu_hotplug
 					* lock is dropped */
+#define CPU_STARTING		0x000A /* CPU (unsigned)v soon running.
+					* Called on the new cpu, just before
+					* enabling interrupts. Must not sleep,
+					* must not fail */
 
 /* Used for CPU hotplug events occuring while tasks are frozen due to a suspend
  * operation in progress
@@ -229,6 +236,7 @@
 #define CPU_DOWN_FAILED_FROZEN	(CPU_DOWN_FAILED | CPU_TASKS_FROZEN)
 #define CPU_DEAD_FROZEN		(CPU_DEAD | CPU_TASKS_FROZEN)
 #define CPU_DYING_FROZEN	(CPU_DYING | CPU_TASKS_FROZEN)
+#define CPU_STARTING_FROZEN	(CPU_STARTING | CPU_TASKS_FROZEN)
 
 /* Hibernation and suspend events */
 #define PM_HIBERNATION_PREPARE	0x0001 /* Going to hibernate */
diff --git a/include/linux/oprofile.h b/include/linux/oprofile.h
index 041bb31..bcb8f72 100644
--- a/include/linux/oprofile.h
+++ b/include/linux/oprofile.h
@@ -36,6 +36,8 @@
 #define XEN_ENTER_SWITCH_CODE		10
 #define SPU_PROFILING_CODE		11
 #define SPU_CTX_SWITCH_CODE		12
+#define IBS_FETCH_CODE			13
+#define IBS_OP_CODE			14
 
 struct super_block;
 struct dentry;
diff --git a/include/linux/parser.h b/include/linux/parser.h
index 7dcd050..ea2281e 100644
--- a/include/linux/parser.h
+++ b/include/linux/parser.h
@@ -25,7 +25,7 @@
 	char *to;
 } substring_t;
 
-int match_token(char *, match_table_t table, substring_t args[]);
+int match_token(char *, const match_table_t table, substring_t args[]);
 int match_int(substring_t *, int *result);
 int match_octal(substring_t *, int *result);
 int match_hex(substring_t *, int *result);
diff --git a/include/linux/pci.h b/include/linux/pci.h
index c0e1400..98dc624 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -534,7 +534,7 @@
 #ifdef CONFIG_PCI_LEGACY
 struct pci_dev __deprecated *pci_find_device(unsigned int vendor,
 					     unsigned int device,
-					     const struct pci_dev *from);
+					     struct pci_dev *from);
 struct pci_dev __deprecated *pci_find_slot(unsigned int bus,
 					   unsigned int devfn);
 #endif /* CONFIG_PCI_LEGACY */
@@ -550,7 +550,7 @@
 				struct pci_dev *from);
 struct pci_dev *pci_get_subsys(unsigned int vendor, unsigned int device,
 				unsigned int ss_vendor, unsigned int ss_device,
-				const struct pci_dev *from);
+				struct pci_dev *from);
 struct pci_dev *pci_get_slot(struct pci_bus *bus, unsigned int devfn);
 struct pci_dev *pci_get_bus_and_slot(unsigned int bus, unsigned int devfn);
 struct pci_dev *pci_get_class(unsigned int class, struct pci_dev *from);
@@ -816,7 +816,7 @@
 
 static inline struct pci_dev *pci_find_device(unsigned int vendor,
 					      unsigned int device,
-					      const struct pci_dev *from)
+					      struct pci_dev *from)
 {
 	return NULL;
 }
@@ -838,7 +838,7 @@
 					     unsigned int device,
 					     unsigned int ss_vendor,
 					     unsigned int ss_device,
-					     const struct pci_dev *from)
+					     struct pci_dev *from)
 {
 	return NULL;
 }
diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h
index f1624b3..1176f1f 100644
--- a/include/linux/pci_ids.h
+++ b/include/linux/pci_ids.h
@@ -497,6 +497,16 @@
 #define PCI_DEVICE_ID_AMD_K8_NB_ADDRMAP	0x1101
 #define PCI_DEVICE_ID_AMD_K8_NB_MEMCTL	0x1102
 #define PCI_DEVICE_ID_AMD_K8_NB_MISC	0x1103
+#define PCI_DEVICE_ID_AMD_10H_NB_HT	0x1200
+#define PCI_DEVICE_ID_AMD_10H_NB_MAP	0x1201
+#define PCI_DEVICE_ID_AMD_10H_NB_DRAM	0x1202
+#define PCI_DEVICE_ID_AMD_10H_NB_MISC	0x1203
+#define PCI_DEVICE_ID_AMD_10H_NB_LINK	0x1204
+#define PCI_DEVICE_ID_AMD_11H_NB_HT	0x1300
+#define PCI_DEVICE_ID_AMD_11H_NB_MAP	0x1301
+#define PCI_DEVICE_ID_AMD_11H_NB_DRAM	0x1302
+#define PCI_DEVICE_ID_AMD_11H_NB_MISC	0x1303
+#define PCI_DEVICE_ID_AMD_11H_NB_LINK	0x1304
 #define PCI_DEVICE_ID_AMD_LANCE		0x2000
 #define PCI_DEVICE_ID_AMD_LANCE_HOME	0x2001
 #define PCI_DEVICE_ID_AMD_SCSI		0x2020
@@ -1411,6 +1421,8 @@
 #define PCI_DEVICE_ID_EICON_MAESTRAQ_U	0xe013
 #define PCI_DEVICE_ID_EICON_MAESTRAP	0xe014
 
+#define PCI_VENDOR_ID_CISCO		0x1137
+
 #define PCI_VENDOR_ID_ZIATECH		0x1138
 #define PCI_DEVICE_ID_ZIATECH_5550_HC	0x5550
  
@@ -1521,7 +1533,9 @@
 #define PCI_DEVICE_ID_MARVELL_GT64260	0x6430
 #define PCI_DEVICE_ID_MARVELL_MV64360	0x6460
 #define PCI_DEVICE_ID_MARVELL_MV64460	0x6480
-#define PCI_DEVICE_ID_MARVELL_CAFE_SD	0x4101
+#define PCI_DEVICE_ID_MARVELL_88ALP01_NAND	0x4100
+#define PCI_DEVICE_ID_MARVELL_88ALP01_SD	0x4101
+#define PCI_DEVICE_ID_MARVELL_88ALP01_CCIC	0x4102
 
 #define PCI_VENDOR_ID_V3		0x11b0
 #define PCI_DEVICE_ID_V3_V960		0x0001
@@ -2213,6 +2227,7 @@
 
 #define PCI_VENDOR_ID_ATTANSIC		0x1969
 #define PCI_DEVICE_ID_ATTANSIC_L1	0x1048
+#define PCI_DEVICE_ID_ATTANSIC_L2	0x2048
 
 #define PCI_VENDOR_ID_JMICRON		0x197B
 #define PCI_DEVICE_ID_JMICRON_JMB360	0x2360
@@ -2244,6 +2259,16 @@
 #define PCI_DEVICE_ID_3DLABS_PERMEDIA2	0x0007
 #define PCI_DEVICE_ID_3DLABS_PERMEDIA2V	0x0009
 
+#define PCI_VENDOR_ID_NETXEN		0x4040
+#define PCI_DEVICE_ID_NX2031_10GXSR	0x0001
+#define PCI_DEVICE_ID_NX2031_10GCX4	0x0002
+#define PCI_DEVICE_ID_NX2031_4GCU	0x0003
+#define PCI_DEVICE_ID_NX2031_IMEZ	0x0004
+#define PCI_DEVICE_ID_NX2031_HMEZ	0x0005
+#define PCI_DEVICE_ID_NX2031_XG_MGMT	0x0024
+#define PCI_DEVICE_ID_NX2031_XG_MGMT2	0x0025
+#define PCI_DEVICE_ID_NX3031		0x0100
+
 #define PCI_VENDOR_ID_AKS		0x416c
 #define PCI_DEVICE_ID_AKS_ALADDINCARD	0x0100
 
diff --git a/include/linux/percpu.h b/include/linux/percpu.h
index fac3337..9f2a375 100644
--- a/include/linux/percpu.h
+++ b/include/linux/percpu.h
@@ -23,12 +23,19 @@
 	__attribute__((__section__(SHARED_ALIGNED_SECTION)))		\
 	PER_CPU_ATTRIBUTES __typeof__(type) per_cpu__##name		\
 	____cacheline_aligned_in_smp
+
+#define DEFINE_PER_CPU_PAGE_ALIGNED(type, name)			\
+	__attribute__((__section__(".data.percpu.page_aligned")))	\
+	PER_CPU_ATTRIBUTES __typeof__(type) per_cpu__##name
 #else
 #define DEFINE_PER_CPU(type, name)					\
 	PER_CPU_ATTRIBUTES __typeof__(type) per_cpu__##name
 
 #define DEFINE_PER_CPU_SHARED_ALIGNED(type, name)		      \
 	DEFINE_PER_CPU(type, name)
+
+#define DEFINE_PER_CPU_PAGE_ALIGNED(type, name)		      \
+	DEFINE_PER_CPU(type, name)
 #endif
 
 #define EXPORT_PER_CPU_SYMBOL(var) EXPORT_SYMBOL(per_cpu__##var)
diff --git a/include/linux/percpu_counter.h b/include/linux/percpu_counter.h
index 2083888..9007ccd 100644
--- a/include/linux/percpu_counter.h
+++ b/include/linux/percpu_counter.h
@@ -35,7 +35,7 @@
 void percpu_counter_destroy(struct percpu_counter *fbc);
 void percpu_counter_set(struct percpu_counter *fbc, s64 amount);
 void __percpu_counter_add(struct percpu_counter *fbc, s64 amount, s32 batch);
-s64 __percpu_counter_sum(struct percpu_counter *fbc, int set);
+s64 __percpu_counter_sum(struct percpu_counter *fbc);
 
 static inline void percpu_counter_add(struct percpu_counter *fbc, s64 amount)
 {
@@ -44,19 +44,13 @@
 
 static inline s64 percpu_counter_sum_positive(struct percpu_counter *fbc)
 {
-	s64 ret = __percpu_counter_sum(fbc, 0);
+	s64 ret = __percpu_counter_sum(fbc);
 	return ret < 0 ? 0 : ret;
 }
 
-static inline s64 percpu_counter_sum_and_set(struct percpu_counter *fbc)
-{
-	return __percpu_counter_sum(fbc, 1);
-}
-
-
 static inline s64 percpu_counter_sum(struct percpu_counter *fbc)
 {
-	return __percpu_counter_sum(fbc, 0);
+	return __percpu_counter_sum(fbc);
 }
 
 static inline s64 percpu_counter_read(struct percpu_counter *fbc)
diff --git a/include/linux/pfkeyv2.h b/include/linux/pfkeyv2.h
index 700725d..01b2629 100644
--- a/include/linux/pfkeyv2.h
+++ b/include/linux/pfkeyv2.h
@@ -226,6 +226,15 @@
 } __attribute__((packed));
 /* sizeof(struct sadb_sec_ctx) = 8 */
 
+/* Used by MIGRATE to pass addresses IKE will use to perform
+ * negotiation with the peer */
+struct sadb_x_kmaddress {
+	uint16_t	sadb_x_kmaddress_len;
+	uint16_t	sadb_x_kmaddress_exttype;
+	uint32_t	sadb_x_kmaddress_reserved;
+} __attribute__((packed));
+/* sizeof(struct sadb_x_kmaddress) == 8 */
+
 /* Message types */
 #define SADB_RESERVED		0
 #define SADB_GETSPI		1
@@ -346,7 +355,9 @@
 #define SADB_X_EXT_NAT_T_DPORT		22
 #define SADB_X_EXT_NAT_T_OA		23
 #define SADB_X_EXT_SEC_CTX		24
-#define SADB_EXT_MAX			24
+/* Used with MIGRATE to pass @ to IKE for negotiation */
+#define SADB_X_EXT_KMADDRESS		25
+#define SADB_EXT_MAX			25
 
 /* Identity Extension values */
 #define SADB_IDENTTYPE_RESERVED	0
diff --git a/include/linux/pfn.h b/include/linux/pfn.h
index bb01f8b..7646637 100644
--- a/include/linux/pfn.h
+++ b/include/linux/pfn.h
@@ -1,9 +1,13 @@
 #ifndef _LINUX_PFN_H_
 #define _LINUX_PFN_H_
 
+#ifndef __ASSEMBLY__
+#include <linux/types.h>
+#endif
+
 #define PFN_ALIGN(x)	(((unsigned long)(x) + (PAGE_SIZE - 1)) & PAGE_MASK)
 #define PFN_UP(x)	(((x) + PAGE_SIZE-1) >> PAGE_SHIFT)
 #define PFN_DOWN(x)	((x) >> PAGE_SHIFT)
-#define PFN_PHYS(x)	((x) << PAGE_SHIFT)
+#define PFN_PHYS(x)	((phys_addr_t)(x) << PAGE_SHIFT)
 
 #endif
diff --git a/include/linux/phonet.h b/include/linux/phonet.h
new file mode 100644
index 0000000..c9609f9
--- /dev/null
+++ b/include/linux/phonet.h
@@ -0,0 +1,170 @@
+/**
+ * file phonet.h
+ *
+ * Phonet sockets kernel interface
+ *
+ * Copyright (C) 2008 Nokia Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#ifndef LINUX_PHONET_H
+#define LINUX_PHONET_H
+
+/* Automatic protocol selection */
+#define PN_PROTO_TRANSPORT	0
+/* Phonet datagram socket */
+#define PN_PROTO_PHONET		1
+/* Phonet pipe */
+#define PN_PROTO_PIPE		2
+#define PHONET_NPROTO		3
+
+/* Socket options for SOL_PNPIPE level */
+#define PNPIPE_ENCAP		1
+#define PNPIPE_IFINDEX		2
+
+#define PNADDR_ANY		0
+#define PNPORT_RESOURCE_ROUTING	0
+
+/* Values for PNPIPE_ENCAP option */
+#define PNPIPE_ENCAP_NONE	0
+#define PNPIPE_ENCAP_IP		1
+
+/* ioctls */
+#define SIOCPNGETOBJECT		(SIOCPROTOPRIVATE + 0)
+
+/* Phonet protocol header */
+struct phonethdr {
+	__u8	pn_rdev;
+	__u8	pn_sdev;
+	__u8	pn_res;
+	__be16	pn_length;
+	__u8	pn_robj;
+	__u8	pn_sobj;
+} __attribute__((packed));
+
+/* Common Phonet payload header */
+struct phonetmsg {
+	__u8	pn_trans_id;	/* transaction ID */
+	__u8	pn_msg_id;	/* message type */
+	union {
+		struct {
+			__u8	pn_submsg_id;	/* message subtype */
+			__u8	pn_data[5];
+		} base;
+		struct {
+			__u16	pn_e_res_id;	/* extended resource ID */
+			__u8	pn_e_submsg_id;	/* message subtype */
+			__u8	pn_e_data[3];
+		} ext;
+	} pn_msg_u;
+};
+#define PN_COMMON_MESSAGE	0xF0
+#define PN_PREFIX		0xE0 /* resource for extended messages */
+#define pn_submsg_id		pn_msg_u.base.pn_submsg_id
+#define pn_e_submsg_id		pn_msg_u.ext.pn_e_submsg_id
+#define pn_e_res_id		pn_msg_u.ext.pn_e_res_id
+#define pn_data			pn_msg_u.base.pn_data
+#define pn_e_data		pn_msg_u.ext.pn_e_data
+
+/* data for unreachable errors */
+#define PN_COMM_SERVICE_NOT_IDENTIFIED_RESP	0x01
+#define PN_COMM_ISA_ENTITY_NOT_REACHABLE_RESP	0x14
+#define pn_orig_msg_id		pn_data[0]
+#define pn_status		pn_data[1]
+#define pn_e_orig_msg_id	pn_e_data[0]
+#define pn_e_status		pn_e_data[1]
+
+/* Phonet socket address structure */
+struct sockaddr_pn {
+	sa_family_t spn_family;
+	__u8 spn_obj;
+	__u8 spn_dev;
+	__u8 spn_resource;
+	__u8 spn_zero[sizeof(struct sockaddr) - sizeof(sa_family_t) - 3];
+} __attribute__ ((packed));
+
+static inline __u16 pn_object(__u8 addr, __u16 port)
+{
+	return (addr << 8) | (port & 0x3ff);
+}
+
+static inline __u8 pn_obj(__u16 handle)
+{
+	return handle & 0xff;
+}
+
+static inline __u8 pn_dev(__u16 handle)
+{
+	return handle >> 8;
+}
+
+static inline __u16 pn_port(__u16 handle)
+{
+	return handle & 0x3ff;
+}
+
+static inline __u8 pn_addr(__u16 handle)
+{
+	return (handle >> 8) & 0xfc;
+}
+
+static inline void pn_sockaddr_set_addr(struct sockaddr_pn *spn, __u8 addr)
+{
+	spn->spn_dev &= 0x03;
+	spn->spn_dev |= addr & 0xfc;
+}
+
+static inline void pn_sockaddr_set_port(struct sockaddr_pn *spn, __u16 port)
+{
+	spn->spn_dev &= 0xfc;
+	spn->spn_dev |= (port >> 8) & 0x03;
+	spn->spn_obj = port & 0xff;
+}
+
+static inline void pn_sockaddr_set_object(struct sockaddr_pn *spn,
+						__u16 handle)
+{
+	spn->spn_dev = pn_dev(handle);
+	spn->spn_obj = pn_obj(handle);
+}
+
+static inline void pn_sockaddr_set_resource(struct sockaddr_pn *spn,
+						__u8 resource)
+{
+	spn->spn_resource = resource;
+}
+
+static inline __u8 pn_sockaddr_get_addr(const struct sockaddr_pn *spn)
+{
+	return spn->spn_dev & 0xfc;
+}
+
+static inline __u16 pn_sockaddr_get_port(const struct sockaddr_pn *spn)
+{
+	return ((spn->spn_dev & 0x03) << 8) | spn->spn_obj;
+}
+
+static inline __u16 pn_sockaddr_get_object(const struct sockaddr_pn *spn)
+{
+	return pn_object(spn->spn_dev, spn->spn_obj);
+}
+
+static inline __u8 pn_sockaddr_get_resource(const struct sockaddr_pn *spn)
+{
+	return spn->spn_resource;
+}
+
+#endif
diff --git a/include/linux/phy.h b/include/linux/phy.h
index 7224c40..77c4ed6 100644
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -99,7 +99,14 @@
 	 */
 	struct mutex mdio_lock;
 
-	struct device *dev;
+	struct device *parent;
+	enum {
+		MDIOBUS_ALLOCATED = 1,
+		MDIOBUS_REGISTERED,
+		MDIOBUS_UNREGISTERED,
+		MDIOBUS_RELEASED,
+	} state;
+	struct device dev;
 
 	/* list of all PHYs on bus */
 	struct phy_device *phy_map[PHY_MAX_ADDR];
@@ -113,6 +120,16 @@
 	 */
 	int *irq;
 };
+#define to_mii_bus(d) container_of(d, struct mii_bus, dev)
+
+struct mii_bus *mdiobus_alloc(void);
+int mdiobus_register(struct mii_bus *bus);
+void mdiobus_unregister(struct mii_bus *bus);
+void mdiobus_free(struct mii_bus *bus);
+struct phy_device *mdiobus_scan(struct mii_bus *bus, int addr);
+int mdiobus_read(struct mii_bus *bus, int addr, u16 regnum);
+int mdiobus_write(struct mii_bus *bus, int addr, u16 regnum, u16 val);
+
 
 #define PHY_INTERRUPT_DISABLED	0x0
 #define PHY_INTERRUPT_ENABLED	0x80000000
@@ -391,8 +408,35 @@
 	int (*run)(struct phy_device *phydev);
 };
 
-int phy_read(struct phy_device *phydev, u16 regnum);
-int phy_write(struct phy_device *phydev, u16 regnum, u16 val);
+/**
+ * phy_read - Convenience function for reading a given PHY register
+ * @phydev: the phy_device struct
+ * @regnum: register number to read
+ *
+ * NOTE: MUST NOT be called from interrupt context,
+ * because the bus read/write functions may wait for an interrupt
+ * to conclude the operation.
+ */
+static inline int phy_read(struct phy_device *phydev, u16 regnum)
+{
+	return mdiobus_read(phydev->bus, phydev->addr, regnum);
+}
+
+/**
+ * phy_write - Convenience function for writing a given PHY register
+ * @phydev: the phy_device struct
+ * @regnum: register number to write
+ * @val: value to write to @regnum
+ *
+ * NOTE: MUST NOT be called from interrupt context,
+ * because the bus read/write functions may wait for an interrupt
+ * to conclude the operation.
+ */
+static inline int phy_write(struct phy_device *phydev, u16 regnum, u16 val)
+{
+	return mdiobus_write(phydev->bus, phydev->addr, regnum, val);
+}
+
 int get_phy_id(struct mii_bus *bus, int addr, u32 *phy_id);
 struct phy_device* get_phy_device(struct mii_bus *bus, int addr);
 int phy_clear_interrupt(struct phy_device *phydev);
@@ -408,8 +452,6 @@
 void phy_stop(struct phy_device *phydev);
 int phy_start_aneg(struct phy_device *phydev);
 
-int mdiobus_register(struct mii_bus *bus);
-void mdiobus_unregister(struct mii_bus *bus);
 void phy_sanitize_settings(struct phy_device *phydev);
 int phy_stop_interrupts(struct phy_device *phydev);
 int phy_enable_interrupts(struct phy_device *phydev);
diff --git a/include/linux/pkt_sched.h b/include/linux/pkt_sched.h
index e5de421..5d921fa 100644
--- a/include/linux/pkt_sched.h
+++ b/include/linux/pkt_sched.h
@@ -123,6 +123,13 @@
 	__u8	priomap[TC_PRIO_MAX+1];	/* Map: logical priority -> PRIO band */
 };
 
+/* MULTIQ section */
+
+struct tc_multiq_qopt {
+	__u16	bands;			/* Number of bands */
+	__u16	max_bands;		/* Maximum number of queues */
+};
+
 /* TBF section */
 
 struct tc_tbf_qopt
diff --git a/include/linux/pnp.h b/include/linux/pnp.h
index 1ce54b6..be764e5 100644
--- a/include/linux/pnp.h
+++ b/include/linux/pnp.h
@@ -21,7 +21,14 @@
 /*
  * Resource Management
  */
+#ifdef CONFIG_PNP
 struct resource *pnp_get_resource(struct pnp_dev *, unsigned int, unsigned int);
+#else
+static inline struct resource *pnp_get_resource(struct pnp_dev *dev, unsigned int type, unsigned int num)
+{
+	return NULL;
+}
+#endif
 
 static inline int pnp_resource_valid(struct resource *res)
 {
diff --git a/include/linux/proportions.h b/include/linux/proportions.h
index 5afc1b2..cf793bb 100644
--- a/include/linux/proportions.h
+++ b/include/linux/proportions.h
@@ -104,8 +104,8 @@
 	 * snapshot of the last seen global state
 	 * and a lock protecting this state
 	 */
-	int shift;
 	unsigned long period;
+	int shift;
 	spinlock_t lock;		/* protect the snapshot state */
 };
 
diff --git a/include/linux/ramfs.h b/include/linux/ramfs.h
index b160fb18..37aaf2b 100644
--- a/include/linux/ramfs.h
+++ b/include/linux/ramfs.h
@@ -6,6 +6,7 @@
 	 int flags, const char *dev_name, void *data, struct vfsmount *mnt);
 
 #ifndef CONFIG_MMU
+extern int ramfs_nommu_expand_for_mapping(struct inode *inode, size_t newsize);
 extern unsigned long ramfs_nommu_get_unmapped_area(struct file *file,
 						   unsigned long addr,
 						   unsigned long len,
diff --git a/include/linux/rcuclassic.h b/include/linux/rcuclassic.h
index 4ab8436..5f89b62 100644
--- a/include/linux/rcuclassic.h
+++ b/include/linux/rcuclassic.h
@@ -40,12 +40,21 @@
 #include <linux/cpumask.h>
 #include <linux/seqlock.h>
 
+#ifdef CONFIG_RCU_CPU_STALL_DETECTOR
+#define RCU_SECONDS_TILL_STALL_CHECK	( 3 * HZ) /* for rcp->jiffies_stall */
+#define RCU_SECONDS_TILL_STALL_RECHECK	(30 * HZ) /* for rcp->jiffies_stall */
+#endif /* #ifdef CONFIG_RCU_CPU_STALL_DETECTOR */
 
 /* Global control variables for rcupdate callback mechanism. */
 struct rcu_ctrlblk {
 	long	cur;		/* Current batch number.                      */
 	long	completed;	/* Number of the last completed batch         */
-	int	next_pending;	/* Is the next batch already waiting?         */
+	long	pending;	/* Number of the last pending batch           */
+#ifdef CONFIG_RCU_CPU_STALL_DETECTOR
+	unsigned long gp_start;	/* Time at which GP started in jiffies. */
+	unsigned long jiffies_stall;
+				/* Time at which to check for CPU stalls. */
+#endif /* #ifdef CONFIG_RCU_CPU_STALL_DETECTOR */
 
 	int	signaled;
 
@@ -66,11 +75,7 @@
 	return (a - b) > 0;
 }
 
-/*
- * Per-CPU data for Read-Copy UPdate.
- * nxtlist - new callbacks are added here
- * curlist - current batch for which quiescent cycle started if any
- */
+/* Per-CPU data for Read-Copy UPdate. */
 struct rcu_data {
 	/* 1) quiescent state handling : */
 	long		quiescbatch;     /* Batch # for grace period */
@@ -78,12 +83,24 @@
 	int		qs_pending;	 /* core waits for quiesc state */
 
 	/* 2) batch handling */
-	long  	       	batch;           /* Batch # for current RCU batch */
+	/*
+	 * if nxtlist is not NULL, then:
+	 * batch:
+	 *	The batch # for the last entry of nxtlist
+	 * [*nxttail[1], NULL = *nxttail[2]):
+	 *	Entries that batch # <= batch
+	 * [*nxttail[0], *nxttail[1]):
+	 *	Entries that batch # <= batch - 1
+	 * [nxtlist, *nxttail[0]):
+	 *	Entries that batch # <= batch - 2
+	 *	The grace period for these entries has completed, and
+	 *	the other grace-period-completed entries may be moved
+	 *	here temporarily in rcu_process_callbacks().
+	 */
+	long  	       	batch;
 	struct rcu_head *nxtlist;
-	struct rcu_head **nxttail;
+	struct rcu_head **nxttail[3];
 	long            qlen; 	 	 /* # of queued callbacks */
-	struct rcu_head *curlist;
-	struct rcu_head **curtail;
 	struct rcu_head *donelist;
 	struct rcu_head **donetail;
 	long		blimit;		 /* Upper limit on a processed batch */
diff --git a/include/linux/rculist.h b/include/linux/rculist.h
index eb4443c..e649bd3 100644
--- a/include/linux/rculist.h
+++ b/include/linux/rculist.h
@@ -198,20 +198,6 @@
 	at->prev = last;
 }
 
-/**
- * list_for_each_rcu	-	iterate over an rcu-protected list
- * @pos:	the &struct list_head to use as a loop cursor.
- * @head:	the head for your list.
- *
- * This list-traversal primitive may safely run concurrently with
- * the _rcu list-mutation primitives such as list_add_rcu()
- * as long as the traversal is guarded by rcu_read_lock().
- */
-#define list_for_each_rcu(pos, head) \
-	for (pos = rcu_dereference((head)->next); \
-		prefetch(pos->next), pos != (head); \
-		pos = rcu_dereference(pos->next))
-
 #define __list_for_each_rcu(pos, head) \
 	for (pos = rcu_dereference((head)->next); \
 		pos != (head); \
diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h
index e8b4039..86f1f5e 100644
--- a/include/linux/rcupdate.h
+++ b/include/linux/rcupdate.h
@@ -133,6 +133,26 @@
 #define rcu_read_unlock_bh() __rcu_read_unlock_bh()
 
 /**
+ * rcu_read_lock_sched - mark the beginning of a RCU-classic critical section
+ *
+ * Should be used with either
+ * - synchronize_sched()
+ * or
+ * - call_rcu_sched() and rcu_barrier_sched()
+ * on the write-side to insure proper synchronization.
+ */
+#define rcu_read_lock_sched() preempt_disable()
+
+/*
+ * rcu_read_unlock_sched - marks the end of a RCU-classic critical section
+ *
+ * See rcu_read_lock_sched for more information.
+ */
+#define rcu_read_unlock_sched() preempt_enable()
+
+
+
+/**
  * rcu_dereference - fetch an RCU-protected pointer in an
  * RCU read-side critical section.  This pointer may later
  * be safely dereferenced.
diff --git a/include/linux/rcupreempt.h b/include/linux/rcupreempt.h
index 0967f03..3e05c09 100644
--- a/include/linux/rcupreempt.h
+++ b/include/linux/rcupreempt.h
@@ -57,7 +57,13 @@
 	rdssp->sched_qs++;
 }
 #define rcu_bh_qsctr_inc(cpu)
-#define call_rcu_bh(head, rcu) call_rcu(head, rcu)
+
+/*
+ * Someone might want to pass call_rcu_bh as a function pointer.
+ * So this needs to just be a rename and not a macro function.
+ *  (no parentheses)
+ */
+#define call_rcu_bh	 	call_rcu
 
 /**
  * call_rcu_sched - Queue RCU callback for invocation after sched grace period.
@@ -111,7 +117,6 @@
 struct softirq_action;
 
 #ifdef CONFIG_NO_HZ
-DECLARE_PER_CPU(struct rcu_dyntick_sched, rcu_dyntick_sched);
 
 static inline void rcu_enter_nohz(void)
 {
@@ -126,8 +131,8 @@
 {
 	static DEFINE_RATELIMIT_STATE(rs, 10 * HZ, 1);
 
-	smp_mb(); /* CPUs seeing ++ must see later RCU read-side crit sects */
 	__get_cpu_var(rcu_dyntick_sched).dynticks++;
+	smp_mb(); /* CPUs seeing ++ must see later RCU read-side crit sects */
 	WARN_ON_RATELIMIT(!(__get_cpu_var(rcu_dyntick_sched).dynticks & 0x1),
 				&rs);
 }
diff --git a/include/linux/regulator/driver.h b/include/linux/regulator/driver.h
index 1d712c7..e37d805 100644
--- a/include/linux/regulator/driver.h
+++ b/include/linux/regulator/driver.h
@@ -18,8 +18,8 @@
 #include <linux/device.h>
 #include <linux/regulator/consumer.h>
 
-struct regulator_constraints;
 struct regulator_dev;
+struct regulator_init_data;
 
 /**
  * struct regulator_ops - regulator operations.
@@ -51,7 +51,7 @@
 					  int output_uV, int load_uA);
 
 	/* the operations below are for configuration of regulator state when
-	 * it's parent PMIC enters a global STANBY/HIBERNATE state */
+	 * its parent PMIC enters a global STANDBY/HIBERNATE state */
 
 	/* set regulator suspend voltage */
 	int (*set_suspend_voltage) (struct regulator_dev *, int uV);
@@ -85,15 +85,17 @@
 	struct module *owner;
 };
 
-
 struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc,
-					  void *reg_data);
+	struct device *dev, void *driver_data);
 void regulator_unregister(struct regulator_dev *rdev);
 
 int regulator_notifier_call_chain(struct regulator_dev *rdev,
 				  unsigned long event, void *data);
 
 void *rdev_get_drvdata(struct regulator_dev *rdev);
+struct device *rdev_get_dev(struct regulator_dev *rdev);
 int rdev_get_id(struct regulator_dev *rdev);
 
+void *regulator_get_init_drvdata(struct regulator_init_data *reg_init_data);
+
 #endif
diff --git a/include/linux/regulator/machine.h b/include/linux/regulator/machine.h
index 11e737d..c6d6933 100644
--- a/include/linux/regulator/machine.h
+++ b/include/linux/regulator/machine.h
@@ -89,15 +89,33 @@
 	unsigned apply_uV:1;	/* apply uV constraint iff min == max */
 };
 
-int regulator_set_supply(const char *regulator, const char *regulator_supply);
+/**
+ * struct regulator_consumer_supply - supply -> device mapping
+ *
+ * This maps a supply name to a device.
+ */
+struct regulator_consumer_supply {
+	struct device *dev;	/* consumer */
+	const char *supply;	/* consumer supply - e.g. "vcc" */
+};
 
-const char *regulator_get_supply(const char *regulator);
+/**
+ * struct regulator_init_data - regulator platform initialisation data.
+ *
+ * Initialisation constraints, our supply and consumers supplies.
+ */
+struct regulator_init_data {
+	struct device *supply_regulator_dev; /* or NULL for LINE */
 
-int regulator_set_machine_constraints(const char *regulator,
-	struct regulation_constraints *constraints);
+	struct regulation_constraints constraints;
 
-int regulator_set_device_supply(const char *regulator, struct device *dev,
-				const char *supply);
+	int num_consumer_supplies;
+	struct regulator_consumer_supply *consumer_supplies;
+
+	/* optional regulator machine specific init */
+	int (*regulator_init)(void *driver_data);
+	void *driver_data;	/* core does not touch this */
+};
 
 int regulator_suspend_prepare(suspend_state_t state);
 
diff --git a/include/linux/rfkill.h b/include/linux/rfkill.h
index 741d1a6..4cd64b0 100644
--- a/include/linux/rfkill.h
+++ b/include/linux/rfkill.h
@@ -49,6 +49,7 @@
 	RFKILL_STATE_SOFT_BLOCKED = 0,	/* Radio output blocked */
 	RFKILL_STATE_UNBLOCKED    = 1,	/* Radio output allowed */
 	RFKILL_STATE_HARD_BLOCKED = 2,	/* Output blocked, non-overrideable */
+	RFKILL_STATE_MAX,		/* marker for last valid state */
 };
 
 /*
@@ -110,12 +111,14 @@
 };
 #define to_rfkill(d)	container_of(d, struct rfkill, dev)
 
-struct rfkill *rfkill_allocate(struct device *parent, enum rfkill_type type);
+struct rfkill * __must_check rfkill_allocate(struct device *parent,
+					     enum rfkill_type type);
 void rfkill_free(struct rfkill *rfkill);
-int rfkill_register(struct rfkill *rfkill);
+int __must_check rfkill_register(struct rfkill *rfkill);
 void rfkill_unregister(struct rfkill *rfkill);
 
 int rfkill_force_state(struct rfkill *rfkill, enum rfkill_state state);
+int rfkill_set_default(enum rfkill_type type, enum rfkill_state state);
 
 /**
  * rfkill_state_complement - return complementar state
diff --git a/include/linux/rtc/m48t59.h b/include/linux/rtc/m48t59.h
index e8c7c21..6fc9614 100644
--- a/include/linux/rtc/m48t59.h
+++ b/include/linux/rtc/m48t59.h
@@ -18,40 +18,47 @@
 /*
  * M48T59 Register Offset
  */
-#define M48T59_YEAR		0x1fff
-#define M48T59_MONTH		0x1ffe
-#define M48T59_MDAY		0x1ffd	/* Day of Month */
-#define M48T59_WDAY		0x1ffc	/* Day of Week */
+#define M48T59_YEAR		0xf
+#define M48T59_MONTH		0xe
+#define M48T59_MDAY		0xd	/* Day of Month */
+#define M48T59_WDAY		0xc	/* Day of Week */
 #define M48T59_WDAY_CB			0x20	/* Century Bit */
 #define M48T59_WDAY_CEB			0x10	/* Century Enable Bit */
-#define M48T59_HOUR		0x1ffb
-#define M48T59_MIN		0x1ffa
-#define M48T59_SEC		0x1ff9
-#define M48T59_CNTL		0x1ff8
+#define M48T59_HOUR		0xb
+#define M48T59_MIN		0xa
+#define M48T59_SEC		0x9
+#define M48T59_CNTL		0x8
 #define M48T59_CNTL_READ		0x40
 #define M48T59_CNTL_WRITE		0x80
-#define M48T59_WATCHDOG		0x1ff7
-#define M48T59_INTR		0x1ff6
+#define M48T59_WATCHDOG		0x7
+#define M48T59_INTR		0x6
 #define M48T59_INTR_AFE			0x80	/* Alarm Interrupt Enable */
 #define M48T59_INTR_ABE			0x20
-#define M48T59_ALARM_DATE	0x1ff5
-#define M48T59_ALARM_HOUR	0x1ff4
-#define M48T59_ALARM_MIN	0x1ff3
-#define M48T59_ALARM_SEC	0x1ff2
-#define M48T59_UNUSED		0x1ff1
-#define M48T59_FLAGS		0x1ff0
+#define M48T59_ALARM_DATE	0x5
+#define M48T59_ALARM_HOUR	0x4
+#define M48T59_ALARM_MIN	0x3
+#define M48T59_ALARM_SEC	0x2
+#define M48T59_UNUSED		0x1
+#define M48T59_FLAGS		0x0
 #define M48T59_FLAGS_WDT		0x80	/* watchdog timer expired */
 #define M48T59_FLAGS_AF			0x40	/* alarm */
 #define M48T59_FLAGS_BF			0x10	/* low battery */
 
-#define M48T59_NVRAM_SIZE	0x1ff0
+#define M48T59RTC_TYPE_M48T59	0 /* to keep compatibility */
+#define M48T59RTC_TYPE_M48T02	1
+#define M48T59RTC_TYPE_M48T08	2
 
 struct m48t59_plat_data {
-	/* The method to access M48T59 registers,
-	 * NOTE: The 'ofs' should be 0x00~0x1fff
-	 */
+	/* The method to access M48T59 registers */
 	void (*write_byte)(struct device *dev, u32 ofs, u8 val);
 	unsigned char (*read_byte)(struct device *dev, u32 ofs);
+
+	int type; /* RTC model */
+
+	/* ioaddr mapped externally */
+	void __iomem *ioaddr;
+	/* offset to RTC registers, automatically set according to the type */
+	unsigned int offset;
 };
 
 #endif /* _LINUX_RTC_M48T59_H_ */
diff --git a/include/linux/rtnetlink.h b/include/linux/rtnetlink.h
index ca643b1..2b3d51c 100644
--- a/include/linux/rtnetlink.h
+++ b/include/linux/rtnetlink.h
@@ -582,6 +582,10 @@
 #define RTNLGRP_IPV6_RULE	RTNLGRP_IPV6_RULE
 	RTNLGRP_ND_USEROPT,
 #define RTNLGRP_ND_USEROPT	RTNLGRP_ND_USEROPT
+	RTNLGRP_PHONET_IFADDR,
+#define RTNLGRP_PHONET_IFADDR	RTNLGRP_PHONET_IFADDR
+	RTNLGRP_PHONET_ROUTE,
+#define RTNLGRP_PHONET_ROUTE	RTNLGRP_PHONET_ROUTE
 	__RTNLGRP_MAX
 };
 #define RTNLGRP_MAX	(__RTNLGRP_MAX - 1)
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 3d9120c..c226c7b 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -352,7 +352,7 @@
 extern void arch_unmap_area(struct mm_struct *, unsigned long);
 extern void arch_unmap_area_topdown(struct mm_struct *, unsigned long);
 
-#if NR_CPUS >= CONFIG_SPLIT_PTLOCK_CPUS
+#if USE_SPLIT_PTLOCKS
 /*
  * The mm counters are not protected by its page_table_lock,
  * so must be incremented atomically.
@@ -363,7 +363,7 @@
 #define inc_mm_counter(mm, member) atomic_long_inc(&(mm)->_##member)
 #define dec_mm_counter(mm, member) atomic_long_dec(&(mm)->_##member)
 
-#else  /* NR_CPUS < CONFIG_SPLIT_PTLOCK_CPUS */
+#else  /* !USE_SPLIT_PTLOCKS */
 /*
  * The mm counters are protected by its page_table_lock,
  * so can be incremented directly.
@@ -374,7 +374,7 @@
 #define inc_mm_counter(mm, member) (mm)->_##member++
 #define dec_mm_counter(mm, member) (mm)->_##member--
 
-#endif /* NR_CPUS < CONFIG_SPLIT_PTLOCK_CPUS */
+#endif /* !USE_SPLIT_PTLOCKS */
 
 #define get_mm_rss(mm)					\
 	(get_mm_counter(mm, file_rss) + get_mm_counter(mm, anon_rss))
@@ -451,8 +451,8 @@
 	 * - everyone except group_exit_task is stopped during signal delivery
 	 *   of fatal signals, group_exit_task processes the signal.
 	 */
-	struct task_struct	*group_exit_task;
 	int			notify_count;
+	struct task_struct	*group_exit_task;
 
 	/* thread group stop support, overloads group_exit_code too */
 	int			group_stop_count;
@@ -824,6 +824,9 @@
 	unsigned int ttwu_move_affine;
 	unsigned int ttwu_move_balance;
 #endif
+#ifdef CONFIG_SCHED_DEBUG
+	char *name;
+#endif
 };
 
 extern void partition_sched_domains(int ndoms_new, cpumask_t *doms_new,
@@ -897,7 +900,7 @@
 	void (*yield_task) (struct rq *rq);
 	int  (*select_task_rq)(struct task_struct *p, int sync);
 
-	void (*check_preempt_curr) (struct rq *rq, struct task_struct *p);
+	void (*check_preempt_curr) (struct rq *rq, struct task_struct *p, int sync);
 
 	struct task_struct * (*pick_next_task) (struct rq *rq);
 	void (*put_prev_task) (struct rq *rq, struct task_struct *p);
@@ -1010,8 +1013,8 @@
 
 struct sched_rt_entity {
 	struct list_head run_list;
-	unsigned int time_slice;
 	unsigned long timeout;
+	unsigned int time_slice;
 	int nr_cpus_allowed;
 
 	struct sched_rt_entity *back;
diff --git a/include/linux/security.h b/include/linux/security.h
index 80c4d00..f5c4a51 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -1560,11 +1560,6 @@
 extern int security_init(void);
 extern int security_module_enable(struct security_operations *ops);
 extern int register_security(struct security_operations *ops);
-extern struct dentry *securityfs_create_file(const char *name, mode_t mode,
-					     struct dentry *parent, void *data,
-					     const struct file_operations *fops);
-extern struct dentry *securityfs_create_dir(const char *name, struct dentry *parent);
-extern void securityfs_remove(struct dentry *dentry);
 
 /* Security operations */
 int security_ptrace_may_access(struct task_struct *child, unsigned int mode);
@@ -2424,25 +2419,6 @@
 	return cap_netlink_recv(skb, cap);
 }
 
-static inline struct dentry *securityfs_create_dir(const char *name,
-					struct dentry *parent)
-{
-	return ERR_PTR(-ENODEV);
-}
-
-static inline struct dentry *securityfs_create_file(const char *name,
-						mode_t mode,
-						struct dentry *parent,
-						void *data,
-						const struct file_operations *fops)
-{
-	return ERR_PTR(-ENODEV);
-}
-
-static inline void securityfs_remove(struct dentry *dentry)
-{
-}
-
 static inline int security_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
 {
 	return -EOPNOTSUPP;
@@ -2806,5 +2782,35 @@
 #endif /* CONFIG_SECURITY */
 #endif /* CONFIG_AUDIT */
 
+#ifdef CONFIG_SECURITYFS
+
+extern struct dentry *securityfs_create_file(const char *name, mode_t mode,
+					     struct dentry *parent, void *data,
+					     const struct file_operations *fops);
+extern struct dentry *securityfs_create_dir(const char *name, struct dentry *parent);
+extern void securityfs_remove(struct dentry *dentry);
+
+#else /* CONFIG_SECURITYFS */
+
+static inline struct dentry *securityfs_create_dir(const char *name,
+						   struct dentry *parent)
+{
+	return ERR_PTR(-ENODEV);
+}
+
+static inline struct dentry *securityfs_create_file(const char *name,
+						    mode_t mode,
+						    struct dentry *parent,
+						    void *data,
+						    const struct file_operations *fops)
+{
+	return ERR_PTR(-ENODEV);
+}
+
+static inline void securityfs_remove(struct dentry *dentry)
+{}
+
+#endif
+
 #endif /* ! __LINUX_SECURITY_H */
 
diff --git a/include/linux/serial.h b/include/linux/serial.h
index deb71431..1ea8d92 100644
--- a/include/linux/serial.h
+++ b/include/linux/serial.h
@@ -173,6 +173,22 @@
 	int reserved[9];
 };
 
+/*
+ * Serial interface for controlling RS485 settings on chips with suitable
+ * support. Set with TIOCSRS485 and get with TIOCGRS485 if supported by your
+ * platform. The set function returns the new state, with any unsupported bits
+ * reverted appropriately.
+ */
+
+struct serial_rs485 {
+	__u32	flags;			/* RS485 feature flags */
+#define SER_RS485_ENABLED		(1 << 0)
+#define SER_RS485_RTS_ON_SEND		(1 << 1)
+#define SER_RS485_RTS_AFTER_SEND	(1 << 2)
+	__u32	delay_rts_before_send;	/* Milliseconds */
+	__u32	padding[6];		/* Memory is cheap, new structs
+					   are a royal PITA .. */
+};
 
 #ifdef __KERNEL__
 #include <linux/compiler.h>
diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h
index 3b2f6c0..e27f216 100644
--- a/include/linux/serial_core.h
+++ b/include/linux/serial_core.h
@@ -241,7 +241,7 @@
 
 struct uart_port {
 	spinlock_t		lock;			/* port lock */
-	unsigned int		iobase;			/* in/out[bwl] */
+	unsigned long		iobase;			/* in/out[bwl] */
 	unsigned char __iomem	*membase;		/* read/write[bwl] */
 	unsigned int		irq;			/* irq number */
 	unsigned int		uartclk;		/* base uart clock */
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index 9099237..2725f4e 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -146,8 +146,14 @@
 	unsigned short	gso_segs;
 	unsigned short  gso_type;
 	__be32          ip6_frag_id;
+#ifdef CONFIG_HAS_DMA
+	unsigned int	num_dma_maps;
+#endif
 	struct sk_buff	*frag_list;
 	skb_frag_t	frags[MAX_SKB_FRAGS];
+#ifdef CONFIG_HAS_DMA
+	dma_addr_t	dma_maps[MAX_SKB_FRAGS + 1];
+#endif
 };
 
 /* We divide dataref into two halves.  The higher 16 bits hold references
@@ -353,6 +359,14 @@
 
 #include <asm/system.h>
 
+#ifdef CONFIG_HAS_DMA
+#include <linux/dma-mapping.h>
+extern int skb_dma_map(struct device *dev, struct sk_buff *skb,
+		       enum dma_data_direction dir);
+extern void skb_dma_unmap(struct device *dev, struct sk_buff *skb,
+			  enum dma_data_direction dir);
+#endif
+
 extern void kfree_skb(struct sk_buff *skb);
 extern void	       __kfree_skb(struct sk_buff *skb);
 extern struct sk_buff *__alloc_skb(unsigned int size,
@@ -369,6 +383,8 @@
 	return __alloc_skb(size, priority, 1, -1);
 }
 
+extern int skb_recycle_check(struct sk_buff *skb, int skb_size);
+
 extern struct sk_buff *skb_morph(struct sk_buff *dst, struct sk_buff *src);
 extern struct sk_buff *skb_clone(struct sk_buff *skb,
 				 gfp_t priority);
@@ -459,6 +475,37 @@
 }
 
 /**
+ *	skb_queue_is_last - check if skb is the last entry in the queue
+ *	@list: queue head
+ *	@skb: buffer
+ *
+ *	Returns true if @skb is the last buffer on the list.
+ */
+static inline bool skb_queue_is_last(const struct sk_buff_head *list,
+				     const struct sk_buff *skb)
+{
+	return (skb->next == (struct sk_buff *) list);
+}
+
+/**
+ *	skb_queue_next - return the next packet in the queue
+ *	@list: queue head
+ *	@skb: current buffer
+ *
+ *	Return the next packet in @list after @skb.  It is only valid to
+ *	call this if skb_queue_is_last() evaluates to false.
+ */
+static inline struct sk_buff *skb_queue_next(const struct sk_buff_head *list,
+					     const struct sk_buff *skb)
+{
+	/* This BUG_ON may seem severe, but if we just return then we
+	 * are going to dereference garbage.
+	 */
+	BUG_ON(skb_queue_is_last(list, skb));
+	return skb->next;
+}
+
+/**
  *	skb_get - reference buffer
  *	@skb: buffer to reference
  *
@@ -646,6 +693,22 @@
 	return list_->qlen;
 }
 
+/**
+ *	__skb_queue_head_init - initialize non-spinlock portions of sk_buff_head
+ *	@list: queue to initialize
+ *
+ *	This initializes only the list and queue length aspects of
+ *	an sk_buff_head object.  This allows to initialize the list
+ *	aspects of an sk_buff_head without reinitializing things like
+ *	the spinlock.  It can also be used for on-stack sk_buff_head
+ *	objects where the spinlock is known to not be used.
+ */
+static inline void __skb_queue_head_init(struct sk_buff_head *list)
+{
+	list->prev = list->next = (struct sk_buff *)list;
+	list->qlen = 0;
+}
+
 /*
  * This function creates a split out lock class for each invocation;
  * this is needed for now since a whole lot of users of the skb-queue
@@ -657,8 +720,7 @@
 static inline void skb_queue_head_init(struct sk_buff_head *list)
 {
 	spin_lock_init(&list->lock);
-	list->prev = list->next = (struct sk_buff *)list;
-	list->qlen = 0;
+	__skb_queue_head_init(list);
 }
 
 static inline void skb_queue_head_init_class(struct sk_buff_head *list,
@@ -685,6 +747,83 @@
 	list->qlen++;
 }
 
+static inline void __skb_queue_splice(const struct sk_buff_head *list,
+				      struct sk_buff *prev,
+				      struct sk_buff *next)
+{
+	struct sk_buff *first = list->next;
+	struct sk_buff *last = list->prev;
+
+	first->prev = prev;
+	prev->next = first;
+
+	last->next = next;
+	next->prev = last;
+}
+
+/**
+ *	skb_queue_splice - join two skb lists, this is designed for stacks
+ *	@list: the new list to add
+ *	@head: the place to add it in the first list
+ */
+static inline void skb_queue_splice(const struct sk_buff_head *list,
+				    struct sk_buff_head *head)
+{
+	if (!skb_queue_empty(list)) {
+		__skb_queue_splice(list, (struct sk_buff *) head, head->next);
+		head->qlen += list->qlen;
+	}
+}
+
+/**
+ *	skb_queue_splice - join two skb lists and reinitialise the emptied list
+ *	@list: the new list to add
+ *	@head: the place to add it in the first list
+ *
+ *	The list at @list is reinitialised
+ */
+static inline void skb_queue_splice_init(struct sk_buff_head *list,
+					 struct sk_buff_head *head)
+{
+	if (!skb_queue_empty(list)) {
+		__skb_queue_splice(list, (struct sk_buff *) head, head->next);
+		head->qlen += list->qlen;
+		__skb_queue_head_init(list);
+	}
+}
+
+/**
+ *	skb_queue_splice_tail - join two skb lists, each list being a queue
+ *	@list: the new list to add
+ *	@head: the place to add it in the first list
+ */
+static inline void skb_queue_splice_tail(const struct sk_buff_head *list,
+					 struct sk_buff_head *head)
+{
+	if (!skb_queue_empty(list)) {
+		__skb_queue_splice(list, head->prev, (struct sk_buff *) head);
+		head->qlen += list->qlen;
+	}
+}
+
+/**
+ *	skb_queue_splice_tail - join two skb lists and reinitialise the emptied list
+ *	@list: the new list to add
+ *	@head: the place to add it in the first list
+ *
+ *	Each of the lists is a queue.
+ *	The list at @list is reinitialised
+ */
+static inline void skb_queue_splice_tail_init(struct sk_buff_head *list,
+					      struct sk_buff_head *head)
+{
+	if (!skb_queue_empty(list)) {
+		__skb_queue_splice(list, head->prev, (struct sk_buff *) head);
+		head->qlen += list->qlen;
+		__skb_queue_head_init(list);
+	}
+}
+
 /**
  *	__skb_queue_after - queue a buffer at the list head
  *	@list: list to use
@@ -829,6 +968,9 @@
 	skb_shinfo(skb)->nr_frags = i + 1;
 }
 
+extern void skb_add_rx_frag(struct sk_buff *skb, int i, struct page *page,
+			    int off, int size);
+
 #define SKB_PAGE_ASSERT(skb) 	BUG_ON(skb_shinfo(skb)->nr_frags)
 #define SKB_FRAG_ASSERT(skb) 	BUG_ON(skb_shinfo(skb)->frag_list)
 #define SKB_LINEAR_ASSERT(skb)  BUG_ON(skb_is_nonlinear(skb))
@@ -1243,6 +1385,26 @@
 	return __netdev_alloc_skb(dev, length, GFP_ATOMIC);
 }
 
+extern struct page *__netdev_alloc_page(struct net_device *dev, gfp_t gfp_mask);
+
+/**
+ *	netdev_alloc_page - allocate a page for ps-rx on a specific device
+ *	@dev: network device to receive on
+ *
+ * 	Allocate a new page node local to the specified device.
+ *
+ * 	%NULL is returned if there is no free memory.
+ */
+static inline struct page *netdev_alloc_page(struct net_device *dev)
+{
+	return __netdev_alloc_page(dev, GFP_ATOMIC);
+}
+
+static inline void netdev_free_page(struct net_device *dev, struct page *page)
+{
+	__free_page(page);
+}
+
 /**
  *	skb_clone_writable - is the header of a clone writable
  *	@skb: buffer to check
@@ -1434,6 +1596,15 @@
 		     skb != (struct sk_buff *)(queue);				\
 		     skb = tmp, tmp = skb->next)
 
+#define skb_queue_walk_from(queue, skb)						\
+		for (; prefetch(skb->next), (skb != (struct sk_buff *)(queue));	\
+		     skb = skb->next)
+
+#define skb_queue_walk_from_safe(queue, skb, tmp)				\
+		for (tmp = skb->next;						\
+		     skb != (struct sk_buff *)(queue);				\
+		     skb = tmp, tmp = skb->next)
+
 #define skb_queue_reverse_walk(queue, skb) \
 		for (skb = (queue)->prev;					\
 		     prefetch(skb->prev), (skb != (struct sk_buff *)(queue));	\
diff --git a/include/linux/smb.h b/include/linux/smb.h
index caa43b2..82fefdd 100644
--- a/include/linux/smb.h
+++ b/include/linux/smb.h
@@ -11,7 +11,9 @@
 
 #include <linux/types.h>
 #include <linux/magic.h>
+#ifdef __KERNEL__
 #include <linux/time.h>
+#endif
 
 enum smb_protocol { 
 	SMB_PROTOCOL_NONE, 
diff --git a/include/linux/smc91x.h b/include/linux/smc91x.h
index 3827b92..bc21db5 100644
--- a/include/linux/smc91x.h
+++ b/include/linux/smc91x.h
@@ -16,8 +16,19 @@
 
 #define SMC91X_USE_DMA		(1 << 6)
 
+#define RPC_LED_100_10	(0x00)	/* LED = 100Mbps OR's with 10Mbps link detect */
+#define RPC_LED_RES	(0x01)	/* LED = Reserved */
+#define RPC_LED_10	(0x02)	/* LED = 10Mbps link detect */
+#define RPC_LED_FD	(0x03)	/* LED = Full Duplex Mode */
+#define RPC_LED_TX_RX	(0x04)	/* LED = TX or RX packet occurred */
+#define RPC_LED_100	(0x05)	/* LED = 100Mbps link dectect */
+#define RPC_LED_TX	(0x06)	/* LED = TX packet occurred */
+#define RPC_LED_RX	(0x07)	/* LED = RX packet occurred */
+
 struct smc91x_platdata {
 	unsigned long flags;
+	unsigned char leda;
+	unsigned char ledb;
 };
 
 #endif /* __SMC91X_H__ */
diff --git a/include/linux/socket.h b/include/linux/socket.h
index dc5086f..20fc4bb 100644
--- a/include/linux/socket.h
+++ b/include/linux/socket.h
@@ -190,7 +190,8 @@
 #define AF_IUCV		32	/* IUCV sockets			*/
 #define AF_RXRPC	33	/* RxRPC sockets 		*/
 #define AF_ISDN		34	/* mISDN sockets 		*/
-#define AF_MAX		35	/* For now.. */
+#define AF_PHONET	35	/* Phonet sockets		*/
+#define AF_MAX		36	/* For now.. */
 
 /* Protocol families, same as address families. */
 #define PF_UNSPEC	AF_UNSPEC
@@ -227,6 +228,7 @@
 #define PF_IUCV		AF_IUCV
 #define PF_RXRPC	AF_RXRPC
 #define PF_ISDN		AF_ISDN
+#define PF_PHONET	AF_PHONET
 #define PF_MAX		AF_MAX
 
 /* Maximum queue length specifiable by listen.  */
@@ -295,6 +297,7 @@
 #define SOL_RXRPC	272
 #define SOL_PPPOL2TP	273
 #define SOL_BLUETOOTH	274
+#define SOL_PNPIPE	275
 
 /* IPX options */
 #define IPX_TYPE	1
diff --git a/include/linux/spi/ads7846.h b/include/linux/spi/ads7846.h
index daf7440..05eab2f 100644
--- a/include/linux/spi/ads7846.h
+++ b/include/linux/spi/ads7846.h
@@ -43,6 +43,9 @@
 	u16	debounce_tol;		/* tolerance used for filtering */
 	u16	debounce_rep;		/* additional consecutive good readings
 					 * required after the first two */
+	int	gpio_pendown;		/* the GPIO used to decide the pendown
+					 * state if get_pendown_state == NULL
+					 */
 	int	(*get_pendown_state)(void);
 	int	(*filter_init)	(struct ads7846_platform_data *pdata,
 				 void **filter_data);
diff --git a/include/linux/spi/corgi_lcd.h b/include/linux/spi/corgi_lcd.h
new file mode 100644
index 0000000..6692b34
--- /dev/null
+++ b/include/linux/spi/corgi_lcd.h
@@ -0,0 +1,20 @@
+#ifndef __LINUX_SPI_CORGI_LCD_H
+#define __LINUX_SPI_CORGI_LCD_H
+
+#define CORGI_LCD_MODE_QVGA	1
+#define CORGI_LCD_MODE_VGA	2
+
+struct corgi_lcd_platform_data {
+	int	init_mode;
+	int	max_intensity;
+	int	default_intensity;
+	int	limit_mask;
+
+	int	gpio_backlight_on;	/* -1 if n/a */
+	int	gpio_backlight_cont;	/* -1 if n/a */
+
+	void (*notify)(int intensity);
+	void (*kick_battery)(void);
+};
+
+#endif /* __LINUX_SPI_CORGI_LCD_H */
diff --git a/include/linux/ssb/ssb_regs.h b/include/linux/ssb/ssb_regs.h
index ebad0ba..99a0f99 100644
--- a/include/linux/ssb/ssb_regs.h
+++ b/include/linux/ssb/ssb_regs.h
@@ -245,8 +245,6 @@
 
 /* SPROM Revision 3 (inherits most data from rev 2) */
 #define SSB_SPROM3_IL0MAC		0x104A	/* 6 bytes MAC address for 802.11b/g */
-#define SSB_SPROM3_ET0MAC		0x1050	/* 6 bytes MAC address for Ethernet ?? */
-#define SSB_SPROM3_ET1MAC		0x1050	/* 6 bytes MAC address for 802.11a ?? */
 #define SSB_SPROM3_OFDMAPO		0x102C	/* A-PHY OFDM Mid Power Offset (4 bytes, BigEndian) */
 #define SSB_SPROM3_OFDMALPO		0x1030	/* A-PHY OFDM Low Power Offset (4 bytes, BigEndian) */
 #define SSB_SPROM3_OFDMAHPO		0x1034	/* A-PHY OFDM High Power Offset (4 bytes, BigEndian) */
@@ -267,8 +265,6 @@
 
 /* SPROM Revision 4 */
 #define SSB_SPROM4_IL0MAC		0x104C	/* 6 byte MAC address for a/b/g/n */
-#define SSB_SPROM4_ET0MAC		0x1018	/* 6 bytes MAC address for Ethernet ?? */
-#define SSB_SPROM4_ET1MAC		0x1018	/* 6 bytes MAC address for 802.11a ?? */
 #define SSB_SPROM4_ETHPHY		0x105A	/* Ethernet PHY settings ?? */
 #define  SSB_SPROM4_ETHPHY_ET0A		0x001F	/* MII Address for enet0 */
 #define  SSB_SPROM4_ETHPHY_ET1A		0x03E0	/* MII Address for enet1 */
@@ -316,6 +312,21 @@
 #define SSB_SPROM4_PA1B1		0x1090
 #define SSB_SPROM4_PA1B2		0x1092
 
+/* SPROM Revision 5 (inherits most data from rev 4) */
+#define SSB_SPROM5_BFLLO		0x104A	/* Boardflags (low 16 bits) */
+#define SSB_SPROM5_BFLHI		0x104C  /* Board Flags Hi */
+#define SSB_SPROM5_IL0MAC		0x1052	/* 6 byte MAC address for a/b/g/n */
+#define SSB_SPROM5_CCODE		0x1044	/* Country Code (2 bytes) */
+#define SSB_SPROM5_GPIOA		0x1076	/* Gen. Purpose IO # 0 and 1 */
+#define  SSB_SPROM5_GPIOA_P0		0x00FF	/* Pin 0 */
+#define  SSB_SPROM5_GPIOA_P1		0xFF00	/* Pin 1 */
+#define  SSB_SPROM5_GPIOA_P1_SHIFT	8
+#define SSB_SPROM5_GPIOB		0x1078	/* Gen. Purpose IO # 2 and 3 */
+#define  SSB_SPROM5_GPIOB_P2		0x00FF	/* Pin 2 */
+#define  SSB_SPROM5_GPIOB_P3		0xFF00	/* Pin 3 */
+#define  SSB_SPROM5_GPIOB_P3_SHIFT	8
+
+
 /* Values for SSB_SPROM1_BINF_CCODE */
 enum {
 	SSB_SPROM1CCODE_WORLD = 0,
diff --git a/include/linux/stacktrace.h b/include/linux/stacktrace.h
index 5da9794..b106fd8 100644
--- a/include/linux/stacktrace.h
+++ b/include/linux/stacktrace.h
@@ -1,6 +1,8 @@
 #ifndef __LINUX_STACKTRACE_H
 #define __LINUX_STACKTRACE_H
 
+struct task_struct;
+
 #ifdef CONFIG_STACKTRACE
 struct stack_trace {
 	unsigned int nr_entries, max_entries;
diff --git a/include/linux/string_helpers.h b/include/linux/string_helpers.h
new file mode 100644
index 0000000..a3eb2f6
--- /dev/null
+++ b/include/linux/string_helpers.h
@@ -0,0 +1,16 @@
+#ifndef _LINUX_STRING_HELPERS_H_
+#define _LINUX_STRING_HELPERS_H_
+
+#include <linux/types.h>
+
+/* Descriptions of the types of units to
+ * print in */
+enum string_size_units {
+	STRING_UNITS_10,	/* use powers of 10^3 (standard SI) */
+	STRING_UNITS_2,		/* use binary powers of 2^10 */
+};
+
+int string_get_size(u64 size, enum string_size_units units,
+		    char *buf, int len);
+
+#endif
diff --git a/include/linux/sunrpc/clnt.h b/include/linux/sunrpc/clnt.h
index e5bfe01..6f0ee1b 100644
--- a/include/linux/sunrpc/clnt.h
+++ b/include/linux/sunrpc/clnt.h
@@ -104,6 +104,7 @@
 	const struct rpc_timeout *timeout;
 	char			*servername;
 	struct rpc_program	*program;
+	u32			prognumber;	/* overrides program->number */
 	u32			version;
 	rpc_authflavor_t	authflavor;
 	unsigned long		flags;
@@ -124,10 +125,10 @@
 void		rpc_shutdown_client(struct rpc_clnt *);
 void		rpc_release_client(struct rpc_clnt *);
 
-int		rpcb_register(u32, u32, int, unsigned short, int *);
+int		rpcb_register(u32, u32, int, unsigned short);
 int		rpcb_v4_register(const u32 program, const u32 version,
 				 const struct sockaddr *address,
-				 const char *netid, int *result);
+				 const char *netid);
 int		rpcb_getport_sync(struct sockaddr_in *, u32, u32, int);
 void		rpcb_getport_async(struct rpc_task *);
 
diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h
index dc69068..3afe7fb 100644
--- a/include/linux/sunrpc/svc.h
+++ b/include/linux/sunrpc/svc.h
@@ -66,6 +66,7 @@
 	struct list_head	sv_tempsocks;	/* all temporary sockets */
 	int			sv_tmpcnt;	/* count of temporary sockets */
 	struct timer_list	sv_temptimer;	/* timer for aging temporary sockets */
+	sa_family_t		sv_family;	/* listener's address family */
 
 	char *			sv_name;	/* service name */
 
@@ -265,17 +266,17 @@
 /*
  * Rigorous type checking on sockaddr type conversions
  */
-static inline struct sockaddr_in *svc_addr_in(struct svc_rqst *rqst)
+static inline struct sockaddr_in *svc_addr_in(const struct svc_rqst *rqst)
 {
 	return (struct sockaddr_in *) &rqst->rq_addr;
 }
 
-static inline struct sockaddr_in6 *svc_addr_in6(struct svc_rqst *rqst)
+static inline struct sockaddr_in6 *svc_addr_in6(const struct svc_rqst *rqst)
 {
 	return (struct sockaddr_in6 *) &rqst->rq_addr;
 }
 
-static inline struct sockaddr *svc_addr(struct svc_rqst *rqst)
+static inline struct sockaddr *svc_addr(const struct svc_rqst *rqst)
 {
 	return (struct sockaddr *) &rqst->rq_addr;
 }
@@ -381,18 +382,20 @@
 /*
  * Function prototypes.
  */
-struct svc_serv *  svc_create(struct svc_program *, unsigned int,
-			      void (*shutdown)(struct svc_serv*));
+struct svc_serv *svc_create(struct svc_program *, unsigned int, sa_family_t,
+			    void (*shutdown)(struct svc_serv *));
 struct svc_rqst *svc_prepare_thread(struct svc_serv *serv,
 					struct svc_pool *pool);
 void		   svc_exit_thread(struct svc_rqst *);
 struct svc_serv *  svc_create_pooled(struct svc_program *, unsigned int,
-			void (*shutdown)(struct svc_serv*), svc_thread_fn,
-			struct module *);
+			sa_family_t, void (*shutdown)(struct svc_serv *),
+			svc_thread_fn, struct module *);
 int		   svc_set_num_threads(struct svc_serv *, struct svc_pool *, int);
 void		   svc_destroy(struct svc_serv *);
 int		   svc_process(struct svc_rqst *);
-int		   svc_register(struct svc_serv *, int, unsigned short);
+int		   svc_register(const struct svc_serv *, const unsigned short,
+				const unsigned short);
+
 void		   svc_wake_up(struct svc_serv *);
 void		   svc_reserve(struct svc_rqst *rqstp, int space);
 struct svc_pool *  svc_pool_for_cpu(struct svc_serv *serv, int cpu);
diff --git a/include/linux/sunrpc/svc_rdma.h b/include/linux/sunrpc/svc_rdma.h
index dc05b54..c14fe86 100644
--- a/include/linux/sunrpc/svc_rdma.h
+++ b/include/linux/sunrpc/svc_rdma.h
@@ -72,6 +72,7 @@
  */
 struct svc_rdma_op_ctxt {
 	struct svc_rdma_op_ctxt *read_hdr;
+	struct svc_rdma_fastreg_mr *frmr;
 	int hdr_count;
 	struct xdr_buf arg;
 	struct list_head dto_q;
@@ -103,16 +104,30 @@
 	int start;		/* sge no for this chunk */
 	int count;		/* sge count for this chunk */
 };
+struct svc_rdma_fastreg_mr {
+	struct ib_mr *mr;
+	void *kva;
+	struct ib_fast_reg_page_list *page_list;
+	int page_list_len;
+	unsigned long access_flags;
+	unsigned long map_len;
+	enum dma_data_direction direction;
+	struct list_head frmr_list;
+};
 struct svc_rdma_req_map {
+	struct svc_rdma_fastreg_mr *frmr;
 	unsigned long count;
 	union {
 		struct kvec sge[RPCSVC_MAXPAGES];
 		struct svc_rdma_chunk_sge ch[RPCSVC_MAXPAGES];
 	};
 };
-
+#define RDMACTXT_F_FAST_UNREG	1
 #define RDMACTXT_F_LAST_CTXT	2
 
+#define	SVCRDMA_DEVCAP_FAST_REG		1	/* fast mr registration */
+#define	SVCRDMA_DEVCAP_READ_W_INV	2	/* read w/ invalidate */
+
 struct svcxprt_rdma {
 	struct svc_xprt      sc_xprt;		/* SVC transport structure */
 	struct rdma_cm_id    *sc_cm_id;		/* RDMA connection id */
@@ -136,6 +151,11 @@
 	struct ib_cq         *sc_rq_cq;
 	struct ib_cq         *sc_sq_cq;
 	struct ib_mr         *sc_phys_mr;	/* MR for server memory */
+	u32		     sc_dev_caps;	/* distilled device caps */
+	u32		     sc_dma_lkey;	/* local dma key */
+	unsigned int	     sc_frmr_pg_list_len;
+	struct list_head     sc_frmr_q;
+	spinlock_t	     sc_frmr_q_lock;
 
 	spinlock_t	     sc_lock;		/* transport lock */
 
@@ -192,8 +212,13 @@
 extern int svc_rdma_create_listen(struct svc_serv *, int, struct sockaddr *);
 extern struct svc_rdma_op_ctxt *svc_rdma_get_context(struct svcxprt_rdma *);
 extern void svc_rdma_put_context(struct svc_rdma_op_ctxt *, int);
+extern void svc_rdma_unmap_dma(struct svc_rdma_op_ctxt *ctxt);
 extern struct svc_rdma_req_map *svc_rdma_get_req_map(void);
 extern void svc_rdma_put_req_map(struct svc_rdma_req_map *);
+extern int svc_rdma_fastreg(struct svcxprt_rdma *, struct svc_rdma_fastreg_mr *);
+extern struct svc_rdma_fastreg_mr *svc_rdma_get_frmr(struct svcxprt_rdma *);
+extern void svc_rdma_put_frmr(struct svcxprt_rdma *,
+			      struct svc_rdma_fastreg_mr *);
 extern void svc_sq_reap(struct svcxprt_rdma *);
 extern void svc_rq_reap(struct svcxprt_rdma *);
 extern struct svc_xprt_class svc_rdma_class;
diff --git a/include/linux/sunrpc/svcsock.h b/include/linux/sunrpc/svcsock.h
index 8cff696..483e103 100644
--- a/include/linux/sunrpc/svcsock.h
+++ b/include/linux/sunrpc/svcsock.h
@@ -39,10 +39,7 @@
 void		svc_drop(struct svc_rqst *);
 void		svc_sock_update_bufs(struct svc_serv *serv);
 int		svc_sock_names(char *buf, struct svc_serv *serv, char *toclose);
-int		svc_addsock(struct svc_serv *serv,
-			    int fd,
-			    char *name_return,
-			    int *proto);
+int		svc_addsock(struct svc_serv *serv, int fd, char *name_return);
 void		svc_init_xprt_sock(void);
 void		svc_cleanup_xprt_sock(void);
 
diff --git a/include/linux/tc_act/Kbuild b/include/linux/tc_act/Kbuild
index 6dac0d7..7699093 100644
--- a/include/linux/tc_act/Kbuild
+++ b/include/linux/tc_act/Kbuild
@@ -3,3 +3,4 @@
 header-y += tc_mirred.h
 header-y += tc_pedit.h
 header-y += tc_nat.h
+header-y += tc_skbedit.h
diff --git a/include/linux/tc_act/tc_skbedit.h b/include/linux/tc_act/tc_skbedit.h
new file mode 100644
index 0000000..a14e461
--- /dev/null
+++ b/include/linux/tc_act/tc_skbedit.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2008, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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.
+ *
+ * Author: Alexander Duyck <alexander.h.duyck@intel.com>
+ */
+
+#ifndef __LINUX_TC_SKBEDIT_H
+#define __LINUX_TC_SKBEDIT_H
+
+#include <linux/pkt_cls.h>
+
+#define TCA_ACT_SKBEDIT 11
+
+#define SKBEDIT_F_PRIORITY		0x1
+#define SKBEDIT_F_QUEUE_MAPPING		0x2
+
+struct tc_skbedit {
+	tc_gen;
+};
+
+enum {
+	TCA_SKBEDIT_UNSPEC,
+	TCA_SKBEDIT_TM,
+	TCA_SKBEDIT_PARMS,
+	TCA_SKBEDIT_PRIORITY,
+	TCA_SKBEDIT_QUEUE_MAPPING,
+	__TCA_SKBEDIT_MAX
+};
+#define TCA_SKBEDIT_MAX (__TCA_SKBEDIT_MAX - 1)
+
+#endif
diff --git a/include/linux/tcp.h b/include/linux/tcp.h
index 2e25573..fe77e14 100644
--- a/include/linux/tcp.h
+++ b/include/linux/tcp.h
@@ -312,8 +312,11 @@
 	u32	retrans_out;	/* Retransmitted packets out		*/
 
 	u16	urg_data;	/* Saved octet of OOB data and control flags */
-	u8	urg_mode;	/* In urgent mode		*/
 	u8	ecn_flags;	/* ECN status bits.			*/
+	u8	reordering;	/* Packet reordering metric.		*/
+	u32	snd_up;		/* Urgent pointer		*/
+
+	u8	keepalive_probes; /* num of allowed keep alive probes	*/
 /*
  *      Options received (usually on last packet, some only on SYN packets).
  */
@@ -342,7 +345,6 @@
 	struct sk_buff* lost_skb_hint;
 	struct sk_buff *scoreboard_skb_hint;
 	struct sk_buff *retransmit_skb_hint;
-	struct sk_buff *forward_skb_hint;
 
 	struct sk_buff_head	out_of_order_queue; /* Out of order segments go here */
 
@@ -358,12 +360,10 @@
 					 */
 
 	int     lost_cnt_hint;
-	int     retransmit_cnt_hint;
+	u32     retransmit_high;	/* L-bits may be on up to this seqno */
 
 	u32	lost_retrans_low;	/* Sent seq after any rxmit (lowest) */
 
-	u8	reordering;	/* Packet reordering metric.		*/
-	u8	keepalive_probes; /* num of allowed keep alive probes	*/
 	u32	prior_ssthresh; /* ssthresh saved at recovery start	*/
 	u32	high_seq;	/* snd_nxt at onset of congestion	*/
 
@@ -375,8 +375,6 @@
 	u32	total_retrans;	/* Total retransmits for entire connection */
 
 	u32	urg_seq;	/* Seq of received urgent pointer */
-	u32	snd_up;		/* Urgent pointer		*/
-
 	unsigned int		keepalive_time;	  /* time before keep alive takes place */
 	unsigned int		keepalive_intvl;  /* time interval between keep alive probes */
 
diff --git a/include/linux/termios.h b/include/linux/termios.h
index 4786628..2acd0c1 100644
--- a/include/linux/termios.h
+++ b/include/linux/termios.h
@@ -4,4 +4,19 @@
 #include <linux/types.h>
 #include <asm/termios.h>
 
+#define NFF	5
+
+struct termiox
+{
+	__u16	x_hflag;
+	__u16	x_cflag;
+	__u16	x_rflag[NFF];
+	__u16	x_sflag;
+};
+
+#define	RTSXOFF		0x0001		/* RTS flow control on input */
+#define	CTSXON		0x0002		/* CTS flow control on output */
+#define	DTRXOFF		0x0004		/* DTR flow control on input */
+#define DSRXON		0x0008		/* DCD flow control on output */
+
 #endif
diff --git a/include/linux/tick.h b/include/linux/tick.h
index 8cf8cfe..98921a3 100644
--- a/include/linux/tick.h
+++ b/include/linux/tick.h
@@ -126,7 +126,7 @@
 	return len;
 }
 static inline void tick_nohz_stop_idle(int cpu) { }
-static inline u64 get_cpu_idle_time_us(int cpu, u64 *unused) { return 0; }
+static inline u64 get_cpu_idle_time_us(int cpu, u64 *unused) { return -1; }
 # endif /* !NO_HZ */
 
 #endif
diff --git a/include/linux/tty.h b/include/linux/tty.h
index 0cbec74..3b8121d 100644
--- a/include/linux/tty.h
+++ b/include/linux/tty.h
@@ -23,7 +23,7 @@
  */
 #define NR_UNIX98_PTY_DEFAULT	4096      /* Default maximum for Unix98 ptys */
 #define NR_UNIX98_PTY_MAX	(1 << MINORBITS) /* Absolute limit */
-#define NR_LDISCS		18
+#define NR_LDISCS		19
 
 /* line disciplines */
 #define N_TTY		0
@@ -45,6 +45,7 @@
 #define N_HCI		15	/* Bluetooth HCI UART */
 #define N_GIGASET_M101	16	/* Siemens Gigaset M101 serial DECT adapter */
 #define N_SLCAN		17	/* Serial / USB serial CAN Adaptors */
+#define N_PPS		18	/* Pulse per Second */
 
 /*
  * This character is the same as _POSIX_VDISABLE: it cannot be used as
@@ -181,6 +182,7 @@
 
 struct tty_port {
 	struct tty_struct	*tty;		/* Back pointer */
+	spinlock_t		lock;		/* Lock protecting tty field */
 	int			blocked_open;	/* Waiting to open */
 	int			count;		/* Usage count */
 	wait_queue_head_t	open_wait;	/* Open waiters */
@@ -208,6 +210,7 @@
 
 struct tty_struct {
 	int	magic;
+	struct kref kref;
 	struct tty_driver *driver;
 	const struct tty_operations *ops;
 	int index;
@@ -217,6 +220,7 @@
 	spinlock_t ctrl_lock;
 	/* Termios values are protected by the termios mutex */
 	struct ktermios *termios, *termios_locked;
+	struct termiox *termiox;	/* May be NULL for unsupported */
 	char name[64];
 	struct pid *pgrp;		/* Protected by ctrl lock */
 	struct pid *session;
@@ -310,6 +314,25 @@
 extern void console_init(void);
 extern int vcs_init(void);
 
+extern struct class *tty_class;
+
+/**
+ *	tty_kref_get		-	get a tty reference
+ *	@tty: tty device
+ *
+ *	Return a new reference to a tty object. The caller must hold
+ *	sufficient locks/counts to ensure that their existing reference cannot
+ *	go away
+ */
+
+extern inline struct tty_struct *tty_kref_get(struct tty_struct *tty)
+{
+	if (tty)
+		kref_get(&tty->kref);
+	return tty;
+}
+extern void tty_kref_put(struct tty_struct *tty);
+
 extern int tty_paranoia_check(struct tty_struct *tty, struct inode *inode,
 			      const char *routine);
 extern char *tty_name(struct tty_struct *tty, char *buf);
@@ -333,13 +356,15 @@
 extern void tty_unthrottle(struct tty_struct *tty);
 extern int tty_do_resize(struct tty_struct *tty, struct tty_struct *real_tty,
 						struct winsize *ws);
-
+extern void tty_shutdown(struct tty_struct *tty);
+extern void tty_free_termios(struct tty_struct *tty);
 extern int is_current_pgrp_orphaned(void);
 extern struct pid *tty_get_pgrp(struct tty_struct *tty);
 extern int is_ignored(int sig);
 extern int tty_signal(int sig, struct tty_struct *tty);
 extern void tty_hangup(struct tty_struct *tty);
 extern void tty_vhangup(struct tty_struct *tty);
+extern void tty_vhangup_self(void);
 extern void tty_unhangup(struct file *filp);
 extern int tty_hung_up_p(struct file *filp);
 extern void do_SAK(struct tty_struct *tty);
@@ -347,6 +372,9 @@
 extern void disassociate_ctty(int priv);
 extern void no_tty(void);
 extern void tty_flip_buffer_push(struct tty_struct *tty);
+extern void tty_buffer_free_all(struct tty_struct *tty);
+extern void tty_buffer_flush(struct tty_struct *tty);
+extern void tty_buffer_init(struct tty_struct *tty);
 extern speed_t tty_get_baud_rate(struct tty_struct *tty);
 extern speed_t tty_termios_baud_rate(struct ktermios *termios);
 extern speed_t tty_termios_input_baud_rate(struct ktermios *termios);
@@ -372,6 +400,15 @@
 extern dev_t tty_devnum(struct tty_struct *tty);
 extern void proc_clear_tty(struct task_struct *p);
 extern struct tty_struct *get_current_tty(void);
+extern void tty_default_fops(struct file_operations *fops);
+extern struct tty_struct *alloc_tty_struct(void);
+extern void free_tty_struct(struct tty_struct *tty);
+extern void initialize_tty_struct(struct tty_struct *tty,
+		struct tty_driver *driver, int idx);
+extern struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx,
+								int first_ok);
+extern void tty_release_dev(struct file *filp);
+extern int tty_init_termios(struct tty_struct *tty);
 
 extern struct mutex tty_mutex;
 
@@ -382,6 +419,8 @@
 extern void tty_port_init(struct tty_port *port);
 extern int tty_port_alloc_xmit_buf(struct tty_port *port);
 extern void tty_port_free_xmit_buf(struct tty_port *port);
+extern struct tty_struct *tty_port_tty_get(struct tty_port *port);
+extern void tty_port_tty_set(struct tty_port *port, struct tty_struct *tty);
 
 extern int tty_register_ldisc(int disc, struct tty_ldisc_ops *new_ldisc);
 extern int tty_unregister_ldisc(int disc);
@@ -427,7 +466,7 @@
 #endif
 
 /* tty_ioctl.c */
-extern int n_tty_ioctl(struct tty_struct *tty, struct file *file,
+extern int n_tty_ioctl_helper(struct tty_struct *tty, struct file *file,
 		       unsigned int cmd, unsigned long arg);
 
 /* serial.c */
diff --git a/include/linux/tty_driver.h b/include/linux/tty_driver.h
index 16d2794..78416b9 100644
--- a/include/linux/tty_driver.h
+++ b/include/linux/tty_driver.h
@@ -7,6 +7,28 @@
  * defined; unless noted otherwise, they are optional, and can be
  * filled in with a null pointer.
  *
+ * struct tty_struct * (*lookup)(struct tty_driver *self, int idx)
+ *
+ *	Return the tty device corresponding to idx, NULL if there is not
+ *	one currently in use and an ERR_PTR value on error. Called under
+ *	tty_mutex (for now!)
+ *
+ *	Optional method. Default behaviour is to use the ttys array
+ *
+ * int (*install)(struct tty_driver *self, struct tty_struct *tty)
+ *
+ *	Install a new tty into the tty driver internal tables. Used in
+ *	conjunction with lookup and remove methods.
+ *
+ *	Optional method. Default behaviour is to use the ttys array
+ *
+ * void (*remove)(struct tty_driver *self, struct tty_struct *tty)
+ *
+ *	Remove a closed tty from the tty driver internal tables. Used in
+ *	conjunction with lookup and remove methods.
+ *
+ *	Optional method. Default behaviour is to use the ttys array
+ *
  * int  (*open)(struct tty_struct * tty, struct file * filp);
  *
  * 	This routine is called when a particular tty device is opened.
@@ -21,6 +43,11 @@
  *
  *	Required method.
  *
+ * void (*shutdown)(struct tty_struct * tty);
+ *
+ * 	This routine is called when a particular tty device is closed for
+ *	the last time freeing up the resources.
+ *
  * int (*write)(struct tty_struct * tty,
  * 		 const unsigned char *buf, int count);
  *
@@ -180,6 +207,14 @@
  *	not force errors here if they are not resizable objects (eg a serial
  *	line). See tty_do_resize() if you need to wrap the standard method
  *	in your own logic - the usual case.
+ *
+ * void (*set_termiox)(struct tty_struct *tty, struct termiox *new);
+ *
+ *	Called when the device receives a termiox based ioctl. Passes down
+ *	the requested data from user space. This method will not be invoked
+ *	unless the tty also has a valid tty->termiox pointer.
+ *
+ *	Optional: Called under the termios lock
  */
 
 #include <linux/fs.h>
@@ -190,8 +225,13 @@
 struct tty_driver;
 
 struct tty_operations {
+	struct tty_struct * (*lookup)(struct tty_driver *driver,
+			struct inode *inode, int idx);
+	int  (*install)(struct tty_driver *driver, struct tty_struct *tty);
+	void (*remove)(struct tty_driver *driver, struct tty_struct *tty);
 	int  (*open)(struct tty_struct * tty, struct file * filp);
 	void (*close)(struct tty_struct * tty, struct file * filp);
+	void (*shutdown)(struct tty_struct *tty);
 	int  (*write)(struct tty_struct * tty,
 		      const unsigned char *buf, int count);
 	int  (*put_char)(struct tty_struct *tty, unsigned char ch);
@@ -220,6 +260,7 @@
 			unsigned int set, unsigned int clear);
 	int (*resize)(struct tty_struct *tty, struct tty_struct *real_tty,
 				struct winsize *ws);
+	int (*set_termiox)(struct tty_struct *tty, struct termiox *tnew);
 #ifdef CONFIG_CONSOLE_POLL
 	int (*poll_init)(struct tty_driver *driver, int line, char *options);
 	int (*poll_get_char)(struct tty_driver *driver, int line);
@@ -229,6 +270,7 @@
 
 struct tty_driver {
 	int	magic;		/* magic number for this structure */
+	struct kref kref;	/* Reference management */
 	struct cdev cdev;
 	struct module	*owner;
 	const char	*driver_name;
@@ -242,7 +284,6 @@
 	short	subtype;	/* subtype of tty driver */
 	struct ktermios init_termios; /* Initial termios */
 	int	flags;		/* tty driver flags */
-	int	refcount;	/* for loadable tty drivers */
 	struct proc_dir_entry *proc_entry; /* /proc fs entry */
 	struct tty_driver *other; /* only used for the PTY driver */
 
@@ -264,12 +305,19 @@
 
 extern struct list_head tty_drivers;
 
-struct tty_driver *alloc_tty_driver(int lines);
-void put_tty_driver(struct tty_driver *driver);
-void tty_set_operations(struct tty_driver *driver,
+extern struct tty_driver *alloc_tty_driver(int lines);
+extern void put_tty_driver(struct tty_driver *driver);
+extern void tty_set_operations(struct tty_driver *driver,
 			const struct tty_operations *op);
 extern struct tty_driver *tty_find_polling_driver(char *name, int *line);
 
+extern void tty_driver_kref_put(struct tty_driver *driver);
+extern inline struct tty_driver *tty_driver_kref_get(struct tty_driver *d)
+{
+	kref_get(&d->kref);
+	return d;
+}
+
 /* tty driver magic number */
 #define TTY_DRIVER_MAGIC		0x5402
 
diff --git a/include/linux/types.h b/include/linux/types.h
index d4a9ce6..f24f7be 100644
--- a/include/linux/types.h
+++ b/include/linux/types.h
@@ -191,12 +191,14 @@
 #ifdef __KERNEL__
 typedef unsigned __bitwise__ gfp_t;
 
-#ifdef CONFIG_RESOURCES_64BIT
-typedef u64 resource_size_t;
+#ifdef CONFIG_PHYS_ADDR_T_64BIT
+typedef u64 phys_addr_t;
 #else
-typedef u32 resource_size_t;
+typedef u32 phys_addr_t;
 #endif
 
+typedef phys_addr_t resource_size_t;
+
 struct ustat {
 	__kernel_daddr_t	f_tfree;
 	__kernel_ino_t		f_tinode;
diff --git a/include/linux/ucb1400.h b/include/linux/ucb1400.h
new file mode 100644
index 0000000..970473b
--- /dev/null
+++ b/include/linux/ucb1400.h
@@ -0,0 +1,161 @@
+/*
+ * Register definitions and functions for:
+ *  Philips UCB1400 driver
+ *
+ * Based on ucb1400_ts:
+ *  Author:	Nicolas Pitre
+ *  Created:	September 25, 2006
+ *  Copyright:	MontaVista Software, Inc.
+ *
+ * Spliting done by: Marek Vasut <marek.vasut@gmail.com>
+ * If something doesnt work and it worked before spliting, e-mail me,
+ * dont bother Nicolas please ;-)
+ *
+ * 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 code is heavily based on ucb1x00-*.c copyrighted by Russell King
+ * covering the UCB1100, UCB1200 and UCB1300..  Support for the UCB1400 has
+ * been made separate from ucb1x00-core/ucb1x00-ts on Russell's request.
+ */
+
+#ifndef _LINUX__UCB1400_H
+#define _LINUX__UCB1400_H
+
+#include <sound/ac97_codec.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+
+/*
+ * UCB1400 AC-link registers
+ */
+
+#define UCB_IO_DATA		0x5a
+#define UCB_IO_DIR		0x5c
+#define UCB_IE_RIS		0x5e
+#define UCB_IE_FAL		0x60
+#define UCB_IE_STATUS		0x62
+#define UCB_IE_CLEAR		0x62
+#define UCB_IE_ADC		(1 << 11)
+#define UCB_IE_TSPX		(1 << 12)
+
+#define UCB_TS_CR		0x64
+#define UCB_TS_CR_TSMX_POW	(1 << 0)
+#define UCB_TS_CR_TSPX_POW	(1 << 1)
+#define UCB_TS_CR_TSMY_POW	(1 << 2)
+#define UCB_TS_CR_TSPY_POW	(1 << 3)
+#define UCB_TS_CR_TSMX_GND	(1 << 4)
+#define UCB_TS_CR_TSPX_GND	(1 << 5)
+#define UCB_TS_CR_TSMY_GND	(1 << 6)
+#define UCB_TS_CR_TSPY_GND	(1 << 7)
+#define UCB_TS_CR_MODE_INT	(0 << 8)
+#define UCB_TS_CR_MODE_PRES	(1 << 8)
+#define UCB_TS_CR_MODE_POS	(2 << 8)
+#define UCB_TS_CR_BIAS_ENA	(1 << 11)
+#define UCB_TS_CR_TSPX_LOW	(1 << 12)
+#define UCB_TS_CR_TSMX_LOW	(1 << 13)
+
+#define UCB_ADC_CR		0x66
+#define UCB_ADC_SYNC_ENA	(1 << 0)
+#define UCB_ADC_VREFBYP_CON	(1 << 1)
+#define UCB_ADC_INP_TSPX	(0 << 2)
+#define UCB_ADC_INP_TSMX	(1 << 2)
+#define UCB_ADC_INP_TSPY	(2 << 2)
+#define UCB_ADC_INP_TSMY	(3 << 2)
+#define UCB_ADC_INP_AD0		(4 << 2)
+#define UCB_ADC_INP_AD1		(5 << 2)
+#define UCB_ADC_INP_AD2		(6 << 2)
+#define UCB_ADC_INP_AD3		(7 << 2)
+#define UCB_ADC_EXT_REF		(1 << 5)
+#define UCB_ADC_START		(1 << 7)
+#define UCB_ADC_ENA		(1 << 15)
+
+#define UCB_ADC_DATA		0x68
+#define UCB_ADC_DAT_VALID	(1 << 15)
+#define UCB_ADC_DAT_MASK	0x3ff
+
+#define UCB_ID			0x7e
+#define UCB_ID_1400             0x4304
+
+struct ucb1400_ts {
+	struct input_dev	*ts_idev;
+	struct task_struct	*ts_task;
+	int			id;
+	wait_queue_head_t	ts_wait;
+	unsigned int		ts_restart:1;
+	int			irq;
+	unsigned int		irq_pending;	/* not bit field shared */
+	struct snd_ac97		*ac97;
+};
+
+struct ucb1400 {
+	struct platform_device	*ucb1400_ts;
+};
+
+static inline u16 ucb1400_reg_read(struct snd_ac97 *ac97, u16 reg)
+{
+	return ac97->bus->ops->read(ac97, reg);
+}
+
+static inline void ucb1400_reg_write(struct snd_ac97 *ac97, u16 reg, u16 val)
+{
+	ac97->bus->ops->write(ac97, reg, val);
+}
+
+static inline u16 ucb1400_gpio_get_value(struct snd_ac97 *ac97, u16 gpio)
+{
+	return ucb1400_reg_read(ac97, UCB_IO_DATA) & (1 << gpio);
+}
+
+static inline void ucb1400_gpio_set_value(struct snd_ac97 *ac97, u16 gpio,
+						u16 val)
+{
+	ucb1400_reg_write(ac97, UCB_IO_DATA, val ?
+			ucb1400_reg_read(ac97, UCB_IO_DATA) | (1 << gpio) :
+			ucb1400_reg_read(ac97, UCB_IO_DATA) & ~(1 << gpio));
+}
+
+static inline u16 ucb1400_gpio_get_direction(struct snd_ac97 *ac97, u16 gpio)
+{
+	return ucb1400_reg_read(ac97, UCB_IO_DIR) & (1 << gpio);
+}
+
+static inline void ucb1400_gpio_set_direction(struct snd_ac97 *ac97, u16 gpio,
+						u16 dir)
+{
+	ucb1400_reg_write(ac97, UCB_IO_DIR, dir ?
+			ucb1400_reg_read(ac97, UCB_IO_DIR) | (1 << gpio) :
+			ucb1400_reg_read(ac97, UCB_IO_DIR) & ~(1 << gpio));
+}
+
+static inline void ucb1400_adc_enable(struct snd_ac97 *ac97)
+{
+	ucb1400_reg_write(ac97, UCB_ADC_CR, UCB_ADC_ENA);
+}
+
+static unsigned int ucb1400_adc_read(struct snd_ac97 *ac97, u16 adc_channel,
+					int adcsync)
+{
+	unsigned int val;
+
+	if (adcsync)
+		adc_channel |= UCB_ADC_SYNC_ENA;
+
+	ucb1400_reg_write(ac97, UCB_ADC_CR, UCB_ADC_ENA | adc_channel);
+	ucb1400_reg_write(ac97, UCB_ADC_CR, UCB_ADC_ENA | adc_channel |
+				UCB_ADC_START);
+
+	while (!((val = ucb1400_reg_read(ac97, UCB_ADC_DATA))
+			& UCB_ADC_DAT_VALID))
+		schedule_timeout_uninterruptible(1);
+
+	return val & UCB_ADC_DAT_MASK;
+}
+
+static inline void ucb1400_adc_disable(struct snd_ac97 *ac97)
+{
+	ucb1400_reg_write(ac97, UCB_ADC_CR, 0);
+}
+
+#endif
diff --git a/include/linux/usb/ehci_def.h b/include/linux/usb/ehci_def.h
new file mode 100644
index 0000000..5b88e36
--- /dev/null
+++ b/include/linux/usb/ehci_def.h
@@ -0,0 +1,160 @@
+/*
+ * Copyright (c) 2001-2002 by David Brownell
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __LINUX_USB_EHCI_DEF_H
+#define __LINUX_USB_EHCI_DEF_H
+
+/* EHCI register interface, corresponds to EHCI Revision 0.95 specification */
+
+/* Section 2.2 Host Controller Capability Registers */
+struct ehci_caps {
+	/* these fields are specified as 8 and 16 bit registers,
+	 * but some hosts can't perform 8 or 16 bit PCI accesses.
+	 */
+	u32		hc_capbase;
+#define HC_LENGTH(p)		(((p)>>00)&0x00ff)	/* bits 7:0 */
+#define HC_VERSION(p)		(((p)>>16)&0xffff)	/* bits 31:16 */
+	u32		hcs_params;     /* HCSPARAMS - offset 0x4 */
+#define HCS_DEBUG_PORT(p)	(((p)>>20)&0xf)	/* bits 23:20, debug port? */
+#define HCS_INDICATOR(p)	((p)&(1 << 16))	/* true: has port indicators */
+#define HCS_N_CC(p)		(((p)>>12)&0xf)	/* bits 15:12, #companion HCs */
+#define HCS_N_PCC(p)		(((p)>>8)&0xf)	/* bits 11:8, ports per CC */
+#define HCS_PORTROUTED(p)	((p)&(1 << 7))	/* true: port routing */
+#define HCS_PPC(p)		((p)&(1 << 4))	/* true: port power control */
+#define HCS_N_PORTS(p)		(((p)>>0)&0xf)	/* bits 3:0, ports on HC */
+
+	u32		hcc_params;      /* HCCPARAMS - offset 0x8 */
+#define HCC_EXT_CAPS(p)		(((p)>>8)&0xff)	/* for pci extended caps */
+#define HCC_ISOC_CACHE(p)       ((p)&(1 << 7))  /* true: can cache isoc frame */
+#define HCC_ISOC_THRES(p)       (((p)>>4)&0x7)  /* bits 6:4, uframes cached */
+#define HCC_CANPARK(p)		((p)&(1 << 2))  /* true: can park on async qh */
+#define HCC_PGM_FRAMELISTLEN(p) ((p)&(1 << 1))  /* true: periodic_size changes*/
+#define HCC_64BIT_ADDR(p)       ((p)&(1))       /* true: can use 64-bit addr */
+	u8		portroute [8];	 /* nibbles for routing - offset 0xC */
+} __attribute__ ((packed));
+
+
+/* Section 2.3 Host Controller Operational Registers */
+struct ehci_regs {
+
+	/* USBCMD: offset 0x00 */
+	u32		command;
+/* 23:16 is r/w intr rate, in microframes; default "8" == 1/msec */
+#define CMD_PARK	(1<<11)		/* enable "park" on async qh */
+#define CMD_PARK_CNT(c)	(((c)>>8)&3)	/* how many transfers to park for */
+#define CMD_LRESET	(1<<7)		/* partial reset (no ports, etc) */
+#define CMD_IAAD	(1<<6)		/* "doorbell" interrupt async advance */
+#define CMD_ASE		(1<<5)		/* async schedule enable */
+#define CMD_PSE		(1<<4)		/* periodic schedule enable */
+/* 3:2 is periodic frame list size */
+#define CMD_RESET	(1<<1)		/* reset HC not bus */
+#define CMD_RUN		(1<<0)		/* start/stop HC */
+
+	/* USBSTS: offset 0x04 */
+	u32		status;
+#define STS_ASS		(1<<15)		/* Async Schedule Status */
+#define STS_PSS		(1<<14)		/* Periodic Schedule Status */
+#define STS_RECL	(1<<13)		/* Reclamation */
+#define STS_HALT	(1<<12)		/* Not running (any reason) */
+/* some bits reserved */
+	/* these STS_* flags are also intr_enable bits (USBINTR) */
+#define STS_IAA		(1<<5)		/* Interrupted on async advance */
+#define STS_FATAL	(1<<4)		/* such as some PCI access errors */
+#define STS_FLR		(1<<3)		/* frame list rolled over */
+#define STS_PCD		(1<<2)		/* port change detect */
+#define STS_ERR		(1<<1)		/* "error" completion (overflow, ...) */
+#define STS_INT		(1<<0)		/* "normal" completion (short, ...) */
+
+	/* USBINTR: offset 0x08 */
+	u32		intr_enable;
+
+	/* FRINDEX: offset 0x0C */
+	u32		frame_index;	/* current microframe number */
+	/* CTRLDSSEGMENT: offset 0x10 */
+	u32		segment;	/* address bits 63:32 if needed */
+	/* PERIODICLISTBASE: offset 0x14 */
+	u32		frame_list;	/* points to periodic list */
+	/* ASYNCLISTADDR: offset 0x18 */
+	u32		async_next;	/* address of next async queue head */
+
+	u32		reserved [9];
+
+	/* CONFIGFLAG: offset 0x40 */
+	u32		configured_flag;
+#define FLAG_CF		(1<<0)		/* true: we'll support "high speed" */
+
+	/* PORTSC: offset 0x44 */
+	u32		port_status [0];	/* up to N_PORTS */
+/* 31:23 reserved */
+#define PORT_WKOC_E	(1<<22)		/* wake on overcurrent (enable) */
+#define PORT_WKDISC_E	(1<<21)		/* wake on disconnect (enable) */
+#define PORT_WKCONN_E	(1<<20)		/* wake on connect (enable) */
+/* 19:16 for port testing */
+#define PORT_LED_OFF	(0<<14)
+#define PORT_LED_AMBER	(1<<14)
+#define PORT_LED_GREEN	(2<<14)
+#define PORT_LED_MASK	(3<<14)
+#define PORT_OWNER	(1<<13)		/* true: companion hc owns this port */
+#define PORT_POWER	(1<<12)		/* true: has power (see PPC) */
+#define PORT_USB11(x) (((x)&(3<<10)) == (1<<10))	/* USB 1.1 device */
+/* 11:10 for detecting lowspeed devices (reset vs release ownership) */
+/* 9 reserved */
+#define PORT_RESET	(1<<8)		/* reset port */
+#define PORT_SUSPEND	(1<<7)		/* suspend port */
+#define PORT_RESUME	(1<<6)		/* resume it */
+#define PORT_OCC	(1<<5)		/* over current change */
+#define PORT_OC		(1<<4)		/* over current active */
+#define PORT_PEC	(1<<3)		/* port enable change */
+#define PORT_PE		(1<<2)		/* port enable */
+#define PORT_CSC	(1<<1)		/* connect status change */
+#define PORT_CONNECT	(1<<0)		/* device connected */
+#define PORT_RWC_BITS   (PORT_CSC | PORT_PEC | PORT_OCC)
+} __attribute__ ((packed));
+
+#define USBMODE		0x68		/* USB Device mode */
+#define USBMODE_SDIS	(1<<3)		/* Stream disable */
+#define USBMODE_BE	(1<<2)		/* BE/LE endianness select */
+#define USBMODE_CM_HC	(3<<0)		/* host controller mode */
+#define USBMODE_CM_IDLE	(0<<0)		/* idle state */
+
+/* Appendix C, Debug port ... intended for use with special "debug devices"
+ * that can help if there's no serial console.  (nonstandard enumeration.)
+ */
+struct ehci_dbg_port {
+	u32	control;
+#define DBGP_OWNER	(1<<30)
+#define DBGP_ENABLED	(1<<28)
+#define DBGP_DONE	(1<<16)
+#define DBGP_INUSE	(1<<10)
+#define DBGP_ERRCODE(x)	(((x)>>7)&0x07)
+#	define DBGP_ERR_BAD	1
+#	define DBGP_ERR_SIGNAL	2
+#define DBGP_ERROR	(1<<6)
+#define DBGP_GO		(1<<5)
+#define DBGP_OUT	(1<<4)
+#define DBGP_LEN(x)	(((x)>>0)&0x0f)
+	u32	pids;
+#define DBGP_PID_GET(x)		(((x)>>16)&0xff)
+#define DBGP_PID_SET(data, tok)	(((data)<<8)|(tok))
+	u32	data03;
+	u32	data47;
+	u32	address;
+#define DBGP_EPADDR(dev, ep)	(((dev)<<8)|(ep))
+} __attribute__ ((packed));
+
+#endif /* __LINUX_USB_EHCI_DEF_H */
diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
index 303d93f..d4b0303 100644
--- a/include/linux/videodev2.h
+++ b/include/linux/videodev2.h
@@ -910,6 +910,8 @@
 	V4L2_MPEG_AUDIO_ENCODING_LAYER_1 = 0,
 	V4L2_MPEG_AUDIO_ENCODING_LAYER_2 = 1,
 	V4L2_MPEG_AUDIO_ENCODING_LAYER_3 = 2,
+	V4L2_MPEG_AUDIO_ENCODING_AAC     = 3,
+	V4L2_MPEG_AUDIO_ENCODING_AC3     = 4,
 };
 #define V4L2_CID_MPEG_AUDIO_L1_BITRATE 		(V4L2_CID_MPEG_BASE+102)
 enum v4l2_mpeg_audio_l1_bitrate {
@@ -988,12 +990,36 @@
 	V4L2_MPEG_AUDIO_CRC_CRC16 = 1,
 };
 #define V4L2_CID_MPEG_AUDIO_MUTE 		(V4L2_CID_MPEG_BASE+109)
+#define V4L2_CID_MPEG_AUDIO_AAC_BITRATE		(V4L2_CID_MPEG_BASE+110)
+#define V4L2_CID_MPEG_AUDIO_AC3_BITRATE		(V4L2_CID_MPEG_BASE+111)
+enum v4l2_mpeg_audio_ac3_bitrate {
+	V4L2_MPEG_AUDIO_AC3_BITRATE_32K  = 0,
+	V4L2_MPEG_AUDIO_AC3_BITRATE_40K  = 1,
+	V4L2_MPEG_AUDIO_AC3_BITRATE_48K  = 2,
+	V4L2_MPEG_AUDIO_AC3_BITRATE_56K  = 3,
+	V4L2_MPEG_AUDIO_AC3_BITRATE_64K  = 4,
+	V4L2_MPEG_AUDIO_AC3_BITRATE_80K  = 5,
+	V4L2_MPEG_AUDIO_AC3_BITRATE_96K  = 6,
+	V4L2_MPEG_AUDIO_AC3_BITRATE_112K = 7,
+	V4L2_MPEG_AUDIO_AC3_BITRATE_128K = 8,
+	V4L2_MPEG_AUDIO_AC3_BITRATE_160K = 9,
+	V4L2_MPEG_AUDIO_AC3_BITRATE_192K = 10,
+	V4L2_MPEG_AUDIO_AC3_BITRATE_224K = 11,
+	V4L2_MPEG_AUDIO_AC3_BITRATE_256K = 12,
+	V4L2_MPEG_AUDIO_AC3_BITRATE_320K = 13,
+	V4L2_MPEG_AUDIO_AC3_BITRATE_384K = 14,
+	V4L2_MPEG_AUDIO_AC3_BITRATE_448K = 15,
+	V4L2_MPEG_AUDIO_AC3_BITRATE_512K = 16,
+	V4L2_MPEG_AUDIO_AC3_BITRATE_576K = 17,
+	V4L2_MPEG_AUDIO_AC3_BITRATE_640K = 18,
+};
 
 /*  MPEG video */
 #define V4L2_CID_MPEG_VIDEO_ENCODING 		(V4L2_CID_MPEG_BASE+200)
 enum v4l2_mpeg_video_encoding {
-	V4L2_MPEG_VIDEO_ENCODING_MPEG_1 = 0,
-	V4L2_MPEG_VIDEO_ENCODING_MPEG_2 = 1,
+	V4L2_MPEG_VIDEO_ENCODING_MPEG_1     = 0,
+	V4L2_MPEG_VIDEO_ENCODING_MPEG_2     = 1,
+	V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC = 2,
 };
 #define V4L2_CID_MPEG_VIDEO_ASPECT 		(V4L2_CID_MPEG_BASE+201)
 enum v4l2_mpeg_video_aspect {
diff --git a/include/linux/vt_kern.h b/include/linux/vt_kern.h
index 1cbd0a7..2f11134 100644
--- a/include/linux/vt_kern.h
+++ b/include/linux/vt_kern.h
@@ -96,7 +96,7 @@
 void reset_vc(struct vc_data *vc);
 extern int unbind_con_driver(const struct consw *csw, int first, int last,
 			     int deflt);
-int vty_init(void);
+int vty_init(const struct file_operations *console_fops);
 
 /*
  * vc_screen.c shares this temporary buffer with the console write code so that
diff --git a/include/linux/wm97xx_batt.h b/include/linux/wm97xx_batt.h
new file mode 100644
index 0000000..9681d1a
--- /dev/null
+++ b/include/linux/wm97xx_batt.h
@@ -0,0 +1,26 @@
+#ifndef _LINUX_WM97XX_BAT_H
+#define _LINUX_WM97XX_BAT_H
+
+#include <linux/wm97xx.h>
+
+struct wm97xx_batt_info {
+	int	batt_aux;
+	int	temp_aux;
+	int	charge_gpio;
+	int	min_voltage;
+	int	max_voltage;
+	int	batt_div;
+	int	batt_mult;
+	int	temp_div;
+	int	temp_mult;
+	int	batt_tech;
+	char	*batt_name;
+};
+
+#ifdef CONFIG_BATTERY_WM97XX
+void __init wm97xx_bat_set_pdata(struct wm97xx_batt_info *data);
+#else
+static inline void wm97xx_bat_set_pdata(struct wm97xx_batt_info *data) {}
+#endif
+
+#endif
diff --git a/include/linux/xfrm.h b/include/linux/xfrm.h
index fb0c215..4bc1e6b 100644
--- a/include/linux/xfrm.h
+++ b/include/linux/xfrm.h
@@ -279,6 +279,7 @@
 	XFRMA_POLICY_TYPE,	/* struct xfrm_userpolicy_type */
 	XFRMA_MIGRATE,
 	XFRMA_ALG_AEAD,		/* struct xfrm_algo_aead */
+	XFRMA_KMADDRESS,        /* struct xfrm_user_kmaddress */
 	__XFRMA_MAX
 
 #define XFRMA_MAX (__XFRMA_MAX - 1)
@@ -415,6 +416,15 @@
 	struct xfrm_selector		sel;
 };
 
+/* Used by MIGRATE to pass addresses IKE should use to perform
+ * SA negotiation with the peer */
+struct xfrm_user_kmaddress {
+	xfrm_address_t                  local;
+	xfrm_address_t                  remote;
+	__u32				reserved;
+	__u16				family;
+};
+
 struct xfrm_user_migrate {
 	xfrm_address_t			old_daddr;
 	xfrm_address_t			old_saddr;
diff --git a/include/media/ir-common.h b/include/media/ir-common.h
index b8e8aa9..38f2d93 100644
--- a/include/media/ir-common.h
+++ b/include/media/ir-common.h
@@ -25,6 +25,7 @@
 
 #include <linux/input.h>
 #include <linux/workqueue.h>
+#include <linux/interrupt.h>
 
 #define IR_TYPE_RC5     1
 #define IR_TYPE_PD      2 /* Pulse distance encoded IR */
@@ -85,6 +86,10 @@
 	u32 code;			/* raw code under construction */
 	struct timeval base_time;	/* time of last seen code */
 	int active;			/* building raw code */
+
+	/* NEC decoding */
+	u32			nec_gpio;
+	struct tasklet_struct   tlet;
 };
 
 void ir_input_init(struct input_dev *dev, struct ir_input_state *ir,
@@ -105,6 +110,7 @@
 extern IR_KEYTAB_TYPE ir_codes_empty[IR_KEYTAB_SIZE];
 extern IR_KEYTAB_TYPE ir_codes_avermedia[IR_KEYTAB_SIZE];
 extern IR_KEYTAB_TYPE ir_codes_avermedia_dvbt[IR_KEYTAB_SIZE];
+extern IR_KEYTAB_TYPE ir_codes_avermedia_m135a[IR_KEYTAB_SIZE];
 extern IR_KEYTAB_TYPE ir_codes_apac_viewcomp[IR_KEYTAB_SIZE];
 extern IR_KEYTAB_TYPE ir_codes_pixelview[IR_KEYTAB_SIZE];
 extern IR_KEYTAB_TYPE ir_codes_pixelview_new[IR_KEYTAB_SIZE];
@@ -139,6 +145,7 @@
 extern IR_KEYTAB_TYPE ir_codes_budget_ci_old[IR_KEYTAB_SIZE];
 extern IR_KEYTAB_TYPE ir_codes_asus_pc39[IR_KEYTAB_SIZE];
 extern IR_KEYTAB_TYPE ir_codes_encore_enltv[IR_KEYTAB_SIZE];
+extern IR_KEYTAB_TYPE ir_codes_encore_enltv2[IR_KEYTAB_SIZE];
 extern IR_KEYTAB_TYPE ir_codes_tt_1500[IR_KEYTAB_SIZE];
 extern IR_KEYTAB_TYPE ir_codes_fusionhdtv_mce[IR_KEYTAB_SIZE];
 extern IR_KEYTAB_TYPE ir_codes_behold[IR_KEYTAB_SIZE];
@@ -147,7 +154,9 @@
 extern IR_KEYTAB_TYPE ir_codes_genius_tvgo_a11mce[IR_KEYTAB_SIZE];
 extern IR_KEYTAB_TYPE ir_codes_powercolor_real_angel[IR_KEYTAB_SIZE];
 extern IR_KEYTAB_TYPE ir_codes_avermedia_a16d[IR_KEYTAB_SIZE];
-
+extern IR_KEYTAB_TYPE ir_codes_encore_enltv_fm53[IR_KEYTAB_SIZE];
+extern IR_KEYTAB_TYPE ir_codes_real_audio_220_32_keys[IR_KEYTAB_SIZE];
+extern IR_KEYTAB_TYPE ir_codes_msi_tvanywhere_plus[IR_KEYTAB_SIZE];
 #endif
 
 /*
diff --git a/include/media/saa7115.h b/include/media/saa7115.h
index f677dfb..bab2127 100644
--- a/include/media/saa7115.h
+++ b/include/media/saa7115.h
@@ -1,5 +1,5 @@
 /*
-    saa7115.h - definition for saa7113/4/5 inputs and frequency flags
+    saa7115.h - definition for saa7111/3/4/5 inputs and frequency flags
 
     Copyright (C) 2006 Hans Verkuil (hverkuil@xs4all.nl)
 
@@ -21,13 +21,13 @@
 #ifndef _SAA7115_H_
 #define _SAA7115_H_
 
-/* SAA7113/4/5 HW inputs */
+/* SAA7111/3/4/5 HW inputs */
 #define SAA7115_COMPOSITE0 0
 #define SAA7115_COMPOSITE1 1
 #define SAA7115_COMPOSITE2 2
 #define SAA7115_COMPOSITE3 3
-#define SAA7115_COMPOSITE4 4 /* not available for the saa7113 */
-#define SAA7115_COMPOSITE5 5 /* not available for the saa7113 */
+#define SAA7115_COMPOSITE4 4 /* not available for the saa7111/3 */
+#define SAA7115_COMPOSITE5 5 /* not available for the saa7111/3 */
 #define SAA7115_SVIDEO0    6
 #define SAA7115_SVIDEO1    7
 #define SAA7115_SVIDEO2    8
@@ -42,8 +42,15 @@
 #define SAA7115_FREQ_FL_CGCDIV (1 << 1)	   /* SA 3A[6], CGCDIV, SAA7115 only */
 #define SAA7115_FREQ_FL_APLL   (1 << 2)	   /* SA 3A[3], APLL, SAA7114/5 only */
 
-#define SAA7115_IPORT_ON    1
-#define SAA7115_IPORT_OFF   0
+#define SAA7115_IPORT_ON    	1
+#define SAA7115_IPORT_OFF   	0
+
+/* SAA7111 specific output flags */
+#define SAA7111_VBI_BYPASS 	2
+#define SAA7111_FMT_YUV422      0x00
+#define SAA7111_FMT_RGB 	0x40
+#define SAA7111_FMT_CCIR 	0x80
+#define SAA7111_FMT_YUV411 	0xc0
 
 #endif
 
diff --git a/include/media/saa7146.h b/include/media/saa7146.h
index 2f68f4c..64a2ec7 100644
--- a/include/media/saa7146.h
+++ b/include/media/saa7146.h
@@ -30,7 +30,7 @@
 	#define DEBUG_VARIABLE saa7146_debug
 #endif
 
-#define DEBUG_PROLOG printk("%s: %s(): ",KBUILD_MODNAME,__FUNCTION__)
+#define DEBUG_PROLOG printk("%s: %s(): ",KBUILD_MODNAME, __func__)
 #define INFO(x) { printk("%s: ",KBUILD_MODNAME); printk x; }
 
 #define ERR(x) { DEBUG_PROLOG; printk x; }
diff --git a/include/media/sh_mobile_ceu.h b/include/media/sh_mobile_ceu.h
index 234a471..b5dbefe 100644
--- a/include/media/sh_mobile_ceu.h
+++ b/include/media/sh_mobile_ceu.h
@@ -5,8 +5,6 @@
 
 struct sh_mobile_ceu_info {
 	unsigned long flags; /* SOCAM_... */
-	void (*enable_camera)(void);
-	void (*disable_camera)(void);
 };
 
 #endif /* __ASM_SH_MOBILE_CEU_H__ */
diff --git a/include/media/soc_camera.h b/include/media/soc_camera.h
index d548de3..c5de7bb 100644
--- a/include/media/soc_camera.h
+++ b/include/media/soc_camera.h
@@ -83,6 +83,9 @@
 	int bus_id;
 	/* GPIO number to switch between 8 and 10 bit modes */
 	unsigned int gpio;
+	/* Optional callbacks to power on or off and reset the sensor */
+	int (*power)(struct device *, int);
+	int (*reset)(struct device *);
 };
 
 static inline struct soc_camera_device *to_soc_camera_dev(struct device *dev)
diff --git a/include/media/tuner.h b/include/media/tuner.h
index 77068fc..67c1f51 100644
--- a/include/media/tuner.h
+++ b/include/media/tuner.h
@@ -122,6 +122,7 @@
 #define TUNER_TDA9887                   74      /* This tuner should be used only internally */
 #define TUNER_TEA5761			75	/* Only FM Radio Tuner */
 #define TUNER_XC5000			76	/* Xceive Silicon Tuner */
+#define TUNER_TCL_MF02GIP_5N		77	/* TCL MF02GIP_5N */
 
 /* tv card specific */
 #define TDA9887_PRESENT 		(1<<0)
@@ -178,7 +179,7 @@
 	unsigned int	type;   /* Tuner type */
 	unsigned int	mode_mask;  /* Allowed tuner modes */
 	unsigned int	config; /* configuraion for more complex tuners */
-	int (*tuner_callback) (void *dev, int command,int arg);
+	int (*tuner_callback) (void *dev, int component, int cmd, int arg);
 };
 
 #endif /* __KERNEL__ */
diff --git a/include/media/v4l2-chip-ident.h b/include/media/v4l2-chip-ident.h
index 41b509b..d73a8e9 100644
--- a/include/media/v4l2-chip-ident.h
+++ b/include/media/v4l2-chip-ident.h
@@ -72,6 +72,10 @@
 	/* module cs5345: just ident 5345 */
 	V4L2_IDENT_CS5345 = 5345,
 
+	/* module saa6752hs: reserved range 6750-6759 */
+	V4L2_IDENT_SAA6752HS = 6752,
+	V4L2_IDENT_SAA6752HS_AC3 = 6753,
+
 	/* module wm8739: just ident 8739 */
 	V4L2_IDENT_WM8739 = 8739,
 
@@ -161,6 +165,7 @@
 	/* Micron CMOS sensor chips: 45000-45099 */
 	V4L2_IDENT_MT9M001C12ST		= 45000,
 	V4L2_IDENT_MT9M001C12STM	= 45005,
+	V4L2_IDENT_MT9M111		= 45007,
 	V4L2_IDENT_MT9V022IX7ATC	= 45010, /* No way to detect "normal" I77ATx */
 	V4L2_IDENT_MT9V022IX7ATM	= 45015, /* and "lead free" IA7ATx chips */
 };
diff --git a/include/media/v4l2-common.h b/include/media/v4l2-common.h
index 07d3a9a..2f8719a 100644
--- a/include/media/v4l2-common.h
+++ b/include/media/v4l2-common.h
@@ -76,11 +76,14 @@
 
 int v4l2_ctrl_check(struct v4l2_ext_control *ctrl, struct v4l2_queryctrl *qctrl,
 		const char **menu_items);
+const char *v4l2_ctrl_get_name(u32 id);
 const char **v4l2_ctrl_get_menu(u32 id);
 int v4l2_ctrl_query_fill(struct v4l2_queryctrl *qctrl, s32 min, s32 max, s32 step, s32 def);
 int v4l2_ctrl_query_fill_std(struct v4l2_queryctrl *qctrl);
 int v4l2_ctrl_query_menu(struct v4l2_querymenu *qmenu,
 		struct v4l2_queryctrl *qctrl, const char **menu_items);
+#define V4L2_CTRL_MENU_IDS_END (0xffffffff)
+int v4l2_ctrl_query_menu_valid_items(struct v4l2_querymenu *qmenu, const u32 *ids);
 u32 v4l2_ctrl_next(const u32 * const *ctrl_classes, u32 id);
 
 /* ------------------------------------------------------------------------- */
@@ -222,18 +225,22 @@
    An extra flags field allows device specific configuration regarding
    clock frequency dividers, etc. If not used, then set flags to 0.
    If the frequency is not supported, then -EINVAL is returned. */
-#define VIDIOC_INT_S_CRYSTAL_FREQ 	_IOW ('d', 113, struct v4l2_crystal_freq)
+#define VIDIOC_INT_S_CRYSTAL_FREQ 	_IOW('d', 113, struct v4l2_crystal_freq)
 
 /* Initialize the sensor registors to some sort of reasonable
    default values. */
-#define VIDIOC_INT_INIT			_IOW ('d', 114, u32)
+#define VIDIOC_INT_INIT			_IOW('d', 114, u32)
 
 /* Set v4l2_std_id for video OUTPUT devices. This is ignored by
    video input devices. */
-#define VIDIOC_INT_S_STD_OUTPUT		_IOW  ('d', 115, v4l2_std_id)
+#define VIDIOC_INT_S_STD_OUTPUT		_IOW('d', 115, v4l2_std_id)
 
 /* Get v4l2_std_id for video OUTPUT devices. This is ignored by
    video input devices. */
-#define VIDIOC_INT_G_STD_OUTPUT		_IOW  ('d', 116, v4l2_std_id)
+#define VIDIOC_INT_G_STD_OUTPUT		_IOW('d', 116, v4l2_std_id)
+
+/* Set GPIO pins. Very simple right now, might need to be extended with
+   a v4l2_gpio struct if a direction is also needed. */
+#define VIDIOC_INT_S_GPIO		_IOW('d', 117, u32)
 
 #endif /* V4L2_COMMON_H_ */
diff --git a/include/media/v4l2-dev.h b/include/media/v4l2-dev.h
index 2745e1a..a0a6b41 100644
--- a/include/media/v4l2-dev.h
+++ b/include/media/v4l2-dev.h
@@ -9,30 +9,20 @@
 #ifndef _V4L2_DEV_H
 #define _V4L2_DEV_H
 
-#define OBSOLETE_DEVDATA 1 /* to be removed soon */
-
 #include <linux/poll.h>
 #include <linux/fs.h>
 #include <linux/device.h>
+#include <linux/cdev.h>
 #include <linux/mutex.h>
-#include <linux/compiler.h> /* need __user */
 #include <linux/videodev2.h>
 
 #define VIDEO_MAJOR	81
-/* Minor device allocation */
-#define MINOR_VFL_TYPE_GRABBER_MIN   0
-#define MINOR_VFL_TYPE_GRABBER_MAX  63
-#define MINOR_VFL_TYPE_RADIO_MIN    64
-#define MINOR_VFL_TYPE_RADIO_MAX   127
-#define MINOR_VFL_TYPE_VTX_MIN     192
-#define MINOR_VFL_TYPE_VTX_MAX     223
-#define MINOR_VFL_TYPE_VBI_MIN     224
-#define MINOR_VFL_TYPE_VBI_MAX     255
 
 #define VFL_TYPE_GRABBER	0
 #define VFL_TYPE_VBI		1
 #define VFL_TYPE_RADIO		2
 #define VFL_TYPE_VTX		3
+#define VFL_TYPE_MAX		4
 
 struct v4l2_ioctl_callbacks;
 
@@ -49,12 +39,15 @@
 
 	/* sysfs */
 	struct device dev;		/* v4l device */
+	struct cdev cdev;		/* character device */
+	void (*cdev_release)(struct kobject *kobj);
 	struct device *parent;		/* device parent */
 
 	/* device info */
 	char name[32];
 	int vfl_type;
 	int minor;
+	u16 num;
 	/* attribute to differentiate multiple indices on one physical device */
 	int index;
 
@@ -69,50 +62,50 @@
 
 	/* ioctl callbacks */
 	const struct v4l2_ioctl_ops *ioctl_ops;
-
-#ifdef OBSOLETE_DEVDATA /* to be removed soon */
-	/* dev->driver_data will be used instead some day.
-	 * Use the video_{get|set}_drvdata() helper functions,
-	 * so the switch over will be transparent for you.
-	 * Or use {pci|usb}_{get|set}_drvdata() directly. */
-	void *priv;
-#endif
-
-	/* for videodev.c internal usage -- please don't touch */
-	int users;                     /* video_exclusive_{open|close} ... */
-	struct mutex lock;             /* ... helper function uses these   */
 };
 
-/* Class-dev to video-device */
+/* dev to video-device */
 #define to_video_device(cd) container_of(cd, struct video_device, dev)
 
-/* Version 2 functions */
-extern int video_register_device(struct video_device *vfd, int type, int nr);
-int video_register_device_index(struct video_device *vfd, int type, int nr,
-					int index);
-void video_unregister_device(struct video_device *);
+/* Register and unregister devices. Note that if video_register_device fails,
+   the release() callback of the video_device structure is *not* called, so
+   the caller is responsible for freeing any data. Usually that means that
+   you call video_device_release() on failure. */
+int __must_check video_register_device(struct video_device *vfd, int type, int nr);
+int __must_check video_register_device_index(struct video_device *vfd,
+						int type, int nr, int index);
+void video_unregister_device(struct video_device *vfd);
 
-/* helper functions to alloc / release struct video_device, the
-   later can be used for video_device->release() */
-struct video_device *video_device_alloc(void);
+/* helper functions to alloc/release struct video_device, the
+   latter can also be used for video_device->release(). */
+struct video_device * __must_check video_device_alloc(void);
+
+/* this release function frees the vfd pointer */
 void video_device_release(struct video_device *vfd);
 
-#ifdef OBSOLETE_DEVDATA /* to be removed soon */
+/* this release function does nothing, use when the video_device is a
+   static global struct. Note that having a static video_device is
+   a dubious construction at best. */
+void video_device_release_empty(struct video_device *vfd);
+
 /* helper functions to access driver private data. */
 static inline void *video_get_drvdata(struct video_device *dev)
 {
-	return dev->priv;
+	return dev_get_drvdata(&dev->dev);
 }
 
 static inline void video_set_drvdata(struct video_device *dev, void *data)
 {
-	dev->priv = data;
+	dev_set_drvdata(&dev->dev, data);
 }
 
-/* Obsolete stuff - Still needed for radio devices and obsolete drivers */
-extern struct video_device* video_devdata(struct file*);
-extern int video_exclusive_open(struct inode *inode, struct file *file);
-extern int video_exclusive_release(struct inode *inode, struct file *file);
-#endif
+struct video_device *video_devdata(struct file *file);
+
+/* Combine video_get_drvdata and video_devdata as this is
+   used very often. */
+static inline void *video_drvdata(struct file *file)
+{
+	return video_get_drvdata(video_devdata(file));
+}
 
 #endif /* _V4L2_DEV_H */
diff --git a/include/media/v4l2-ioctl.h b/include/media/v4l2-ioctl.h
index dc64046..0bef03a 100644
--- a/include/media/v4l2-ioctl.h
+++ b/include/media/v4l2-ioctl.h
@@ -39,11 +39,6 @@
 					    struct v4l2_fmtdesc *f);
 	int (*vidioc_enum_fmt_vid_out)     (struct file *file, void *fh,
 					    struct v4l2_fmtdesc *f);
-#if 1
-	/* deprecated, will be removed in 2.6.28 */
-	int (*vidioc_enum_fmt_vbi_cap)     (struct file *file, void *fh,
-					    struct v4l2_fmtdesc *f);
-#endif
 	int (*vidioc_enum_fmt_type_private)(struct file *file, void *fh,
 					    struct v4l2_fmtdesc *f);
 
diff --git a/include/net/9p/9p.h b/include/net/9p/9p.h
index b3d3e27..c3626c0 100644
--- a/include/net/9p/9p.h
+++ b/include/net/9p/9p.h
@@ -596,4 +596,5 @@
 int p9_error_init(void);
 int p9_errstr2errno(char *, int);
 int p9_trans_fd_init(void);
+void p9_trans_fd_exit(void);
 #endif /* NET_9P_H */
diff --git a/include/net/9p/transport.h b/include/net/9p/transport.h
index 0db3a40..3ca7371 100644
--- a/include/net/9p/transport.h
+++ b/include/net/9p/transport.h
@@ -26,6 +26,8 @@
 #ifndef NET_9P_TRANSPORT_H
 #define NET_9P_TRANSPORT_H
 
+#include <linux/module.h>
+
 /**
  * enum p9_trans_status - different states of underlying transports
  * @Connected: transport is connected and healthy
@@ -91,9 +93,12 @@
 	int maxsize;		/* max message size of transport */
 	int def;		/* this transport should be default */
 	struct p9_trans * (*create)(const char *, char *, int, unsigned char);
+	struct module *owner;
 };
 
 void v9fs_register_trans(struct p9_trans_module *m);
-struct p9_trans_module *v9fs_match_trans(const substring_t *name);
-struct p9_trans_module *v9fs_default_trans(void);
+void v9fs_unregister_trans(struct p9_trans_module *m);
+struct p9_trans_module *v9fs_get_trans_by_name(const substring_t *name);
+struct p9_trans_module *v9fs_get_default_trans(void);
+void v9fs_put_trans(struct p9_trans_module *m);
 #endif /* NET_9P_TRANSPORT_H */
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index e007508..0e85ec3 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -152,6 +152,7 @@
 	u16 aid;
 	u8 supported_rates_len;
 	u8 plink_action;
+	struct ieee80211_ht_cap *ht_capa;
 };
 
 /**
@@ -268,6 +269,83 @@
 	u8 flags;
 };
 
+/**
+ * struct bss_parameters - BSS parameters
+ *
+ * Used to change BSS parameters (mainly for AP mode).
+ *
+ * @use_cts_prot: Whether to use CTS protection
+ *	(0 = no, 1 = yes, -1 = do not change)
+ * @use_short_preamble: Whether the use of short preambles is allowed
+ *	(0 = no, 1 = yes, -1 = do not change)
+ * @use_short_slot_time: Whether the use of short slot time is allowed
+ *	(0 = no, 1 = yes, -1 = do not change)
+ */
+struct bss_parameters {
+	int use_cts_prot;
+	int use_short_preamble;
+	int use_short_slot_time;
+};
+
+/**
+ * enum reg_set_by - Indicates who is trying to set the regulatory domain
+ * @REGDOM_SET_BY_INIT: regulatory domain was set by initialization. We will be
+ * 	using a static world regulatory domain by default.
+ * @REGDOM_SET_BY_CORE: Core queried CRDA for a dynamic world regulatory domain.
+ * @REGDOM_SET_BY_USER: User asked the wireless core to set the
+ * 	regulatory domain.
+ * @REGDOM_SET_BY_DRIVER: a wireless drivers has hinted to the wireless core
+ *	it thinks its knows the regulatory domain we should be in.
+ * @REGDOM_SET_BY_COUNTRY_IE: the wireless core has received an 802.11 country
+ *	information element with regulatory information it thinks we
+ *	should consider.
+ */
+enum reg_set_by {
+	REGDOM_SET_BY_INIT,
+	REGDOM_SET_BY_CORE,
+	REGDOM_SET_BY_USER,
+	REGDOM_SET_BY_DRIVER,
+	REGDOM_SET_BY_COUNTRY_IE,
+};
+
+struct ieee80211_freq_range {
+	u32 start_freq_khz;
+	u32 end_freq_khz;
+	u32 max_bandwidth_khz;
+};
+
+struct ieee80211_power_rule {
+	u32 max_antenna_gain;
+	u32 max_eirp;
+};
+
+struct ieee80211_reg_rule {
+	struct ieee80211_freq_range freq_range;
+	struct ieee80211_power_rule power_rule;
+	u32 flags;
+};
+
+struct ieee80211_regdomain {
+	u32 n_reg_rules;
+	char alpha2[2];
+	struct ieee80211_reg_rule reg_rules[];
+};
+
+#define MHZ_TO_KHZ(freq) (freq * 1000)
+#define KHZ_TO_MHZ(freq) (freq / 1000)
+#define DBI_TO_MBI(gain) (gain * 100)
+#define MBI_TO_DBI(gain) (gain / 100)
+#define DBM_TO_MBM(gain) (gain * 100)
+#define MBM_TO_DBM(gain) (gain / 100)
+
+#define REG_RULE(start, end, bw, gain, eirp, reg_flags) { \
+	.freq_range.start_freq_khz = (start) * 1000, \
+	.freq_range.end_freq_khz = (end) * 1000, \
+	.freq_range.max_bandwidth_khz = (bw) * 1000, \
+	.power_rule.max_antenna_gain = (gain) * 100, \
+	.power_rule.max_eirp = (eirp) * 100, \
+	.flags = reg_flags, \
+	}
 
 /* from net/wireless.h */
 struct wiphy;
@@ -285,11 +363,13 @@
  * wireless extensions but this is subject to reevaluation as soon as this
  * code is used more widely and we have a first user without wext.
  *
- * @add_virtual_intf: create a new virtual interface with the given name
+ * @add_virtual_intf: create a new virtual interface with the given name,
+ *	must set the struct wireless_dev's iftype.
  *
  * @del_virtual_intf: remove the virtual interface determined by ifindex.
  *
- * @change_virtual_intf: change type of virtual interface
+ * @change_virtual_intf: change type/configuration of virtual interface,
+ *	keep the struct wireless_dev's iftype updated.
  *
  * @add_key: add a key with the given parameters. @mac_addr will be %NULL
  *	when adding a group key.
@@ -318,6 +398,8 @@
  * @change_station: Modify a given station.
  *
  * @set_mesh_cfg: set mesh parameters (by now, just mesh id)
+ *
+ * @change_bss: Modify parameters for a given BSS.
  */
 struct cfg80211_ops {
 	int	(*add_virtual_intf)(struct wiphy *wiphy, char *name,
@@ -370,6 +452,9 @@
 	int	(*dump_mpath)(struct wiphy *wiphy, struct net_device *dev,
 			       int idx, u8 *dst, u8 *next_hop,
 			       struct mpath_info *pinfo);
+
+	int	(*change_bss)(struct wiphy *wiphy, struct net_device *dev,
+			      struct bss_parameters *params);
 };
 
 #endif /* __NET_CFG80211_H */
diff --git a/include/net/cipso_ipv4.h b/include/net/cipso_ipv4.h
index a6bb945..9909774 100644
--- a/include/net/cipso_ipv4.h
+++ b/include/net/cipso_ipv4.h
@@ -40,11 +40,12 @@
 #include <linux/net.h>
 #include <linux/skbuff.h>
 #include <net/netlabel.h>
+#include <asm/atomic.h>
 
 /* known doi values */
 #define CIPSO_V4_DOI_UNKNOWN          0x00000000
 
-/* tag types */
+/* standard tag types */
 #define CIPSO_V4_TAG_INVALID          0
 #define CIPSO_V4_TAG_RBITMAP          1
 #define CIPSO_V4_TAG_ENUM             2
@@ -52,10 +53,14 @@
 #define CIPSO_V4_TAG_PBITMAP          6
 #define CIPSO_V4_TAG_FREEFORM         7
 
+/* non-standard tag types (tags > 127) */
+#define CIPSO_V4_TAG_LOCAL            128
+
 /* doi mapping types */
 #define CIPSO_V4_MAP_UNKNOWN          0
-#define CIPSO_V4_MAP_STD              1
+#define CIPSO_V4_MAP_TRANS            1
 #define CIPSO_V4_MAP_PASS             2
+#define CIPSO_V4_MAP_LOCAL            3
 
 /* limits */
 #define CIPSO_V4_MAX_REM_LVLS         255
@@ -79,10 +84,9 @@
 	} map;
 	u8 tags[CIPSO_V4_TAG_MAXCNT];
 
-	u32 valid;
+	atomic_t refcount;
 	struct list_head list;
 	struct rcu_head rcu;
-	struct list_head dom_list;
 };
 
 /* Standard CIPSO mapping table */
@@ -128,25 +132,26 @@
 
 #ifdef CONFIG_NETLABEL
 int cipso_v4_doi_add(struct cipso_v4_doi *doi_def);
-int cipso_v4_doi_remove(u32 doi,
-			struct netlbl_audit *audit_info,
-			void (*callback) (struct rcu_head * head));
+void cipso_v4_doi_free(struct cipso_v4_doi *doi_def);
+int cipso_v4_doi_remove(u32 doi, struct netlbl_audit *audit_info);
 struct cipso_v4_doi *cipso_v4_doi_getdef(u32 doi);
+void cipso_v4_doi_putdef(struct cipso_v4_doi *doi_def);
 int cipso_v4_doi_walk(u32 *skip_cnt,
 		     int (*callback) (struct cipso_v4_doi *doi_def, void *arg),
 	             void *cb_arg);
-int cipso_v4_doi_domhsh_add(struct cipso_v4_doi *doi_def, const char *domain);
-int cipso_v4_doi_domhsh_remove(struct cipso_v4_doi *doi_def,
-			       const char *domain);
 #else
 static inline int cipso_v4_doi_add(struct cipso_v4_doi *doi_def)
 {
 	return -ENOSYS;
 }
 
+static inline void cipso_v4_doi_free(struct cipso_v4_doi *doi_def)
+{
+	return;
+}
+
 static inline int cipso_v4_doi_remove(u32 doi,
-				    struct netlbl_audit *audit_info,
-				    void (*callback) (struct rcu_head * head))
+				      struct netlbl_audit *audit_info)
 {
 	return 0;
 }
@@ -206,10 +211,15 @@
 int cipso_v4_sock_setattr(struct sock *sk,
 			  const struct cipso_v4_doi *doi_def,
 			  const struct netlbl_lsm_secattr *secattr);
+void cipso_v4_sock_delattr(struct sock *sk);
 int cipso_v4_sock_getattr(struct sock *sk, struct netlbl_lsm_secattr *secattr);
+int cipso_v4_skbuff_setattr(struct sk_buff *skb,
+			    const struct cipso_v4_doi *doi_def,
+			    const struct netlbl_lsm_secattr *secattr);
+int cipso_v4_skbuff_delattr(struct sk_buff *skb);
 int cipso_v4_skbuff_getattr(const struct sk_buff *skb,
 			    struct netlbl_lsm_secattr *secattr);
-int cipso_v4_validate(unsigned char **option);
+int cipso_v4_validate(const struct sk_buff *skb, unsigned char **option);
 #else
 static inline void cipso_v4_error(struct sk_buff *skb,
 				  int error,
@@ -225,19 +235,36 @@
 	return -ENOSYS;
 }
 
+static inline void cipso_v4_sock_delattr(struct sock *sk)
+{
+}
+
 static inline int cipso_v4_sock_getattr(struct sock *sk,
 					struct netlbl_lsm_secattr *secattr)
 {
 	return -ENOSYS;
 }
 
+static inline int cipso_v4_skbuff_setattr(struct sk_buff *skb,
+				      const struct cipso_v4_doi *doi_def,
+				      const struct netlbl_lsm_secattr *secattr)
+{
+	return -ENOSYS;
+}
+
+static inline int cipso_v4_skbuff_delattr(struct sk_buff *skb)
+{
+	return -ENOSYS;
+}
+
 static inline int cipso_v4_skbuff_getattr(const struct sk_buff *skb,
 					  struct netlbl_lsm_secattr *secattr)
 {
 	return -ENOSYS;
 }
 
-static inline int cipso_v4_validate(unsigned char **option)
+static inline int cipso_v4_validate(const struct sk_buff *skb,
+				    unsigned char **option)
 {
 	return -ENOSYS;
 }
diff --git a/include/net/dsa.h b/include/net/dsa.h
new file mode 100644
index 0000000..52e97bf
--- /dev/null
+++ b/include/net/dsa.h
@@ -0,0 +1,37 @@
+/*
+ * include/net/dsa.h - Driver for Distributed Switch Architecture switch chips
+ * Copyright (c) 2008 Marvell Semiconductor
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef __LINUX_NET_DSA_H
+#define __LINUX_NET_DSA_H
+
+#define DSA_MAX_PORTS	12
+
+struct dsa_platform_data {
+	/*
+	 * Reference to a Linux network interface that connects
+	 * to the switch chip.
+	 */
+	struct device	*netdev;
+
+	/*
+	 * How to access the switch configuration registers, and
+	 * the names of the switch ports (use "cpu" to designate
+	 * the switch port that the cpu is connected to).
+	 */
+	struct device	*mii_bus;
+	int		sw_addr;
+	char		*port_names[DSA_MAX_PORTS];
+};
+
+extern bool dsa_uses_dsa_tags(void *dsa_ptr);
+extern bool dsa_uses_trailer_tags(void *dsa_ptr);
+
+
+#endif
diff --git a/include/net/flow.h b/include/net/flow.h
index 228b247..b45a5e4 100644
--- a/include/net/flow.h
+++ b/include/net/flow.h
@@ -47,6 +47,8 @@
 #define fl4_scope	nl_u.ip4_u.scope
 
 	__u8	proto;
+	__u8	flags;
+#define FLOWI_FLAG_ANYSRC 0x01
 	union {
 		struct {
 			__be16	sport;
diff --git a/include/net/ieee80211.h b/include/net/ieee80211.h
index b31399e..6048579 100644
--- a/include/net/ieee80211.h
+++ b/include/net/ieee80211.h
@@ -190,10 +190,6 @@
 #endif
 #include <net/iw_handler.h>	/* new driver API */
 
-#ifndef ETH_P_PAE
-#define ETH_P_PAE 0x888E	/* Port Access Entity (IEEE 802.1X) */
-#endif				/* ETH_P_PAE */
-
 #define ETH_P_PREAUTH 0x88C7	/* IEEE 802.11i pre-authentication */
 
 #ifndef ETH_P_80211_RAW
diff --git a/include/net/inet6_hashtables.h b/include/net/inet6_hashtables.h
index e48989f..f74665d 100644
--- a/include/net/inet6_hashtables.h
+++ b/include/net/inet6_hashtables.h
@@ -91,6 +91,21 @@
 	return inet6_lookup_listener(net, hashinfo, daddr, hnum, dif);
 }
 
+static inline struct sock *__inet6_lookup_skb(struct inet_hashinfo *hashinfo,
+					      struct sk_buff *skb,
+					      const __be16 sport,
+					      const __be16 dport)
+{
+	struct sock *sk;
+
+	if (unlikely(sk = skb_steal_sock(skb)))
+		return sk;
+	else return __inet6_lookup(dev_net(skb->dst->dev), hashinfo,
+				   &ipv6_hdr(skb)->saddr, sport,
+				   &ipv6_hdr(skb)->daddr, ntohs(dport),
+				   inet6_iif(skb));
+}
+
 extern struct sock *inet6_lookup(struct net *net, struct inet_hashinfo *hashinfo,
 				 const struct in6_addr *saddr, const __be16 sport,
 				 const struct in6_addr *daddr, const __be16 dport,
diff --git a/include/net/inet_connection_sock.h b/include/net/inet_connection_sock.h
index 2ff545a..03cffd9 100644
--- a/include/net/inet_connection_sock.h
+++ b/include/net/inet_connection_sock.h
@@ -51,12 +51,14 @@
 				  char __user *optval, int optlen);
 	int	    (*getsockopt)(struct sock *sk, int level, int optname, 
 				  char __user *optval, int __user *optlen);
+#ifdef CONFIG_COMPAT
 	int	    (*compat_setsockopt)(struct sock *sk,
 				int level, int optname,
 				char __user *optval, int optlen);
 	int	    (*compat_getsockopt)(struct sock *sk,
 				int level, int optname,
 				char __user *optval, int __user *optlen);
+#endif
 	void	    (*addr2sockaddr)(struct sock *sk, struct sockaddr *);
 	int	    (*bind_conflict)(const struct sock *sk,
 				     const struct inet_bind_bucket *tb);
diff --git a/include/net/inet_hashtables.h b/include/net/inet_hashtables.h
index bb619d8..5cc182f 100644
--- a/include/net/inet_hashtables.h
+++ b/include/net/inet_hashtables.h
@@ -16,6 +16,7 @@
 
 
 #include <linux/interrupt.h>
+#include <linux/ip.h>
 #include <linux/ipv6.h>
 #include <linux/list.h>
 #include <linux/slab.h>
@@ -28,6 +29,7 @@
 #include <net/inet_connection_sock.h>
 #include <net/inet_sock.h>
 #include <net/sock.h>
+#include <net/route.h>
 #include <net/tcp_states.h>
 #include <net/netns/hash.h>
 
@@ -371,6 +373,22 @@
 	return sk;
 }
 
+static inline struct sock *__inet_lookup_skb(struct inet_hashinfo *hashinfo,
+					     struct sk_buff *skb,
+					     const __be16 sport,
+					     const __be16 dport)
+{
+	struct sock *sk;
+	const struct iphdr *iph = ip_hdr(skb);
+
+	if (unlikely(sk = skb_steal_sock(skb)))
+		return sk;
+	else
+		return __inet_lookup(dev_net(skb->dst->dev), hashinfo,
+				     iph->saddr, sport,
+				     iph->daddr, dport, inet_iif(skb));
+}
+
 extern int __inet_hash_connect(struct inet_timewait_death_row *death_row,
 		struct sock *sk, u32 port_offset,
 		int (*check_established)(struct inet_timewait_death_row *,
diff --git a/include/net/inet_sock.h b/include/net/inet_sock.h
index 643e26b..de0ecc7 100644
--- a/include/net/inet_sock.h
+++ b/include/net/inet_sock.h
@@ -24,7 +24,6 @@
 #include <net/flow.h>
 #include <net/sock.h>
 #include <net/request_sock.h>
-#include <net/route.h>
 #include <net/netns/hash.h>
 
 /** struct ip_options - IP Options
@@ -62,8 +61,8 @@
 	struct request_sock	req;
 #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
 	u16			inet6_rsk_offset;
-	/* 2 bytes hole, try to pack */
 #endif
+	__be16			loc_port;
 	__be32			loc_addr;
 	__be32			rmt_addr;
 	__be16			rmt_port;
@@ -73,7 +72,8 @@
 				sack_ok	   : 1,
 				wscale_ok  : 1,
 				ecn_ok	   : 1,
-				acked	   : 1;
+				acked	   : 1,
+				no_srccheck: 1;
 	struct ip_options	*opt;
 };
 
@@ -129,7 +129,8 @@
 				is_icsk:1,
 				freebind:1,
 				hdrincl:1,
-				mc_loop:1;
+				mc_loop:1,
+				transparent:1;
 	int			mc_index;
 	__be32			mc_addr;
 	struct ip_mc_socklist	*mc_list;
@@ -194,12 +195,6 @@
 	return inet_ehashfn(net, laddr, lport, faddr, fport);
 }
 
-
-static inline int inet_iif(const struct sk_buff *skb)
-{
-	return skb->rtable->rt_iif;
-}
-
 static inline struct request_sock *inet_reqsk_alloc(struct request_sock_ops *ops)
 {
 	struct request_sock *req = reqsk_alloc(ops);
@@ -210,4 +205,9 @@
 	return req;
 }
 
+static inline __u8 inet_sk_flowi_flags(const struct sock *sk)
+{
+	return inet_sk(sk)->transparent ? FLOWI_FLAG_ANYSRC : 0;
+}
+
 #endif	/* _INET_SOCK_H */
diff --git a/include/net/inet_timewait_sock.h b/include/net/inet_timewait_sock.h
index 9132490..80e4977 100644
--- a/include/net/inet_timewait_sock.h
+++ b/include/net/inet_timewait_sock.h
@@ -128,7 +128,8 @@
 	__be16			tw_dport;
 	__u16			tw_num;
 	/* And these are ours. */
-	__u8			tw_ipv6only:1;
+	__u8			tw_ipv6only:1,
+				tw_transparent:1;
 	/* 15 bits hole, try to pack */
 	__u16			tw_ipv6_offset;
 	unsigned long		tw_ttd;
diff --git a/include/net/ip.h b/include/net/ip.h
index 250e6ef..1cbccaf 100644
--- a/include/net/ip.h
+++ b/include/net/ip.h
@@ -29,6 +29,7 @@
 
 #include <net/inet_sock.h>
 #include <net/snmp.h>
+#include <net/flow.h>
 
 struct sock;
 
@@ -140,12 +141,20 @@
 
 struct ip_reply_arg {
 	struct kvec iov[1];   
+	int	    flags;
 	__wsum 	    csum;
 	int	    csumoffset; /* u16 offset of csum in iov[0].iov_base */
 				/* -1 if not needed */ 
 	int	    bound_dev_if;
 }; 
 
+#define IP_REPLY_ARG_NOSRCCHECK 1
+
+static inline __u8 ip_reply_arg_flowi_flags(const struct ip_reply_arg *arg)
+{
+	return (arg->flags & IP_REPLY_ARG_NOSRCCHECK) ? FLOWI_FLAG_ANYSRC : 0;
+}
+
 void ip_send_reply(struct sock *sk, struct sk_buff *skb, struct ip_reply_arg *arg,
 		   unsigned int len); 
 
@@ -169,6 +178,10 @@
 extern int snmp_mib_init(void *ptr[2], size_t mibsize);
 extern void snmp_mib_free(void *ptr[2]);
 
+extern struct local_ports {
+	seqlock_t	lock;
+	int		range[2];
+} sysctl_local_ports;
 extern void inet_get_local_port_range(int *low, int *high);
 
 extern int sysctl_ip_default_ttl;
diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h
index 7312c3d..0b2071d 100644
--- a/include/net/ip_vs.h
+++ b/include/net/ip_vs.h
@@ -21,11 +21,104 @@
 #include <linux/timer.h>
 
 #include <net/checksum.h>
+#include <linux/netfilter.h>		/* for union nf_inet_addr */
+#include <linux/ip.h>
+#include <linux/ipv6.h>			/* for struct ipv6hdr */
+#include <net/ipv6.h>			/* for ipv6_addr_copy */
+
+struct ip_vs_iphdr {
+	int len;
+	__u8 protocol;
+	union nf_inet_addr saddr;
+	union nf_inet_addr daddr;
+};
+
+static inline void
+ip_vs_fill_iphdr(int af, const void *nh, struct ip_vs_iphdr *iphdr)
+{
+#ifdef CONFIG_IP_VS_IPV6
+	if (af == AF_INET6) {
+		const struct ipv6hdr *iph = nh;
+		iphdr->len = sizeof(struct ipv6hdr);
+		iphdr->protocol = iph->nexthdr;
+		ipv6_addr_copy(&iphdr->saddr.in6, &iph->saddr);
+		ipv6_addr_copy(&iphdr->daddr.in6, &iph->daddr);
+	} else
+#endif
+	{
+		const struct iphdr *iph = nh;
+		iphdr->len = iph->ihl * 4;
+		iphdr->protocol = iph->protocol;
+		iphdr->saddr.ip = iph->saddr;
+		iphdr->daddr.ip = iph->daddr;
+	}
+}
+
+static inline void ip_vs_addr_copy(int af, union nf_inet_addr *dst,
+				   const union nf_inet_addr *src)
+{
+#ifdef CONFIG_IP_VS_IPV6
+	if (af == AF_INET6)
+		ipv6_addr_copy(&dst->in6, &src->in6);
+	else
+#endif
+	dst->ip = src->ip;
+}
+
+static inline int ip_vs_addr_equal(int af, const union nf_inet_addr *a,
+				   const union nf_inet_addr *b)
+{
+#ifdef CONFIG_IP_VS_IPV6
+	if (af == AF_INET6)
+		return ipv6_addr_equal(&a->in6, &b->in6);
+#endif
+	return a->ip == b->ip;
+}
 
 #ifdef CONFIG_IP_VS_DEBUG
 #include <linux/net.h>
 
 extern int ip_vs_get_debug_level(void);
+
+static inline const char *ip_vs_dbg_addr(int af, char *buf, size_t buf_len,
+					 const union nf_inet_addr *addr,
+					 int *idx)
+{
+	int len;
+#ifdef CONFIG_IP_VS_IPV6
+	if (af == AF_INET6)
+		len = snprintf(&buf[*idx], buf_len - *idx, "[" NIP6_FMT "]",
+			       NIP6(addr->in6)) + 1;
+	else
+#endif
+		len = snprintf(&buf[*idx], buf_len - *idx, NIPQUAD_FMT,
+			       NIPQUAD(addr->ip)) + 1;
+
+	*idx += len;
+	BUG_ON(*idx > buf_len + 1);
+	return &buf[*idx - len];
+}
+
+#define IP_VS_DBG_BUF(level, msg...)			\
+    do {						\
+	    char ip_vs_dbg_buf[160];			\
+	    int ip_vs_dbg_idx = 0;			\
+	    if (level <= ip_vs_get_debug_level())	\
+		    printk(KERN_DEBUG "IPVS: " msg);	\
+    } while (0)
+#define IP_VS_ERR_BUF(msg...)				\
+    do {						\
+	    char ip_vs_dbg_buf[160];			\
+	    int ip_vs_dbg_idx = 0;			\
+	    printk(KERN_ERR "IPVS: " msg);		\
+    } while (0)
+
+/* Only use from within IP_VS_DBG_BUF() or IP_VS_ERR_BUF macros */
+#define IP_VS_DBG_ADDR(af, addr)			\
+    ip_vs_dbg_addr(af, ip_vs_dbg_buf,			\
+		   sizeof(ip_vs_dbg_buf), addr,		\
+		   &ip_vs_dbg_idx)
+
 #define IP_VS_DBG(level, msg...)			\
     do {						\
 	    if (level <= ip_vs_get_debug_level())	\
@@ -48,6 +141,8 @@
 		pp->debug_packet(pp, skb, ofs, msg);	\
     } while (0)
 #else	/* NO DEBUGGING at ALL */
+#define IP_VS_DBG_BUF(level, msg...)  do {} while (0)
+#define IP_VS_ERR_BUF(msg...)  do {} while (0)
 #define IP_VS_DBG(level, msg...)  do {} while (0)
 #define IP_VS_DBG_RL(msg...)  do {} while (0)
 #define IP_VS_DBG_PKT(level, pp, skb, ofs, msg)		do {} while (0)
@@ -160,27 +255,10 @@
 
 struct ip_vs_stats
 {
-	__u32                   conns;          /* connections scheduled */
-	__u32                   inpkts;         /* incoming packets */
-	__u32                   outpkts;        /* outgoing packets */
-	__u64                   inbytes;        /* incoming bytes */
-	__u64                   outbytes;       /* outgoing bytes */
-
-	__u32			cps;		/* current connection rate */
-	__u32			inpps;		/* current in packet rate */
-	__u32			outpps;		/* current out packet rate */
-	__u32			inbps;		/* current in byte rate */
-	__u32			outbps;		/* current out byte rate */
-
-	/*
-	 * Don't add anything before the lock, because we use memcpy() to copy
-	 * the members before the lock to struct ip_vs_stats_user in
-	 * ip_vs_ctl.c.
-	 */
+	struct ip_vs_stats_user	ustats;         /* statistics */
+	struct ip_vs_estimator	est;		/* estimator */
 
 	spinlock_t              lock;           /* spin lock */
-
-	struct ip_vs_estimator	est;		/* estimator */
 };
 
 struct dst_entry;
@@ -202,21 +280,23 @@
 
 	void (*exit)(struct ip_vs_protocol *pp);
 
-	int (*conn_schedule)(struct sk_buff *skb,
+	int (*conn_schedule)(int af, struct sk_buff *skb,
 			     struct ip_vs_protocol *pp,
 			     int *verdict, struct ip_vs_conn **cpp);
 
 	struct ip_vs_conn *
-	(*conn_in_get)(const struct sk_buff *skb,
+	(*conn_in_get)(int af,
+		       const struct sk_buff *skb,
 		       struct ip_vs_protocol *pp,
-		       const struct iphdr *iph,
+		       const struct ip_vs_iphdr *iph,
 		       unsigned int proto_off,
 		       int inverse);
 
 	struct ip_vs_conn *
-	(*conn_out_get)(const struct sk_buff *skb,
+	(*conn_out_get)(int af,
+			const struct sk_buff *skb,
 			struct ip_vs_protocol *pp,
-			const struct iphdr *iph,
+			const struct ip_vs_iphdr *iph,
 			unsigned int proto_off,
 			int inverse);
 
@@ -226,7 +306,8 @@
 	int (*dnat_handler)(struct sk_buff *skb,
 			    struct ip_vs_protocol *pp, struct ip_vs_conn *cp);
 
-	int (*csum_check)(struct sk_buff *skb, struct ip_vs_protocol *pp);
+	int (*csum_check)(int af, struct sk_buff *skb,
+			  struct ip_vs_protocol *pp);
 
 	const char *(*state_name)(int state);
 
@@ -259,9 +340,10 @@
 	struct list_head        c_list;         /* hashed list heads */
 
 	/* Protocol, addresses and port numbers */
-	__be32                   caddr;          /* client address */
-	__be32                   vaddr;          /* virtual address */
-	__be32                   daddr;          /* destination address */
+	u16                      af;		/* address family */
+	union nf_inet_addr       caddr;          /* client address */
+	union nf_inet_addr       vaddr;          /* virtual address */
+	union nf_inet_addr       daddr;          /* destination address */
 	__be16                   cport;
 	__be16                   vport;
 	__be16                   dport;
@@ -305,6 +387,45 @@
 
 
 /*
+ *	Extended internal versions of struct ip_vs_service_user and
+ *	ip_vs_dest_user for IPv6 support.
+ *
+ *	We need these to conveniently pass around service and destination
+ *	options, but unfortunately, we also need to keep the old definitions to
+ *	maintain userspace backwards compatibility for the setsockopt interface.
+ */
+struct ip_vs_service_user_kern {
+	/* virtual service addresses */
+	u16			af;
+	u16			protocol;
+	union nf_inet_addr	addr;		/* virtual ip address */
+	u16			port;
+	u32			fwmark;		/* firwall mark of service */
+
+	/* virtual service options */
+	char			*sched_name;
+	unsigned		flags;		/* virtual service flags */
+	unsigned		timeout;	/* persistent timeout in sec */
+	u32			netmask;	/* persistent netmask */
+};
+
+
+struct ip_vs_dest_user_kern {
+	/* destination server address */
+	union nf_inet_addr	addr;
+	u16			port;
+
+	/* real server options */
+	unsigned		conn_flags;	/* connection flags */
+	int			weight;		/* destination weight */
+
+	/* thresholds for active connections */
+	u32			u_threshold;	/* upper threshold */
+	u32			l_threshold;	/* lower threshold */
+};
+
+
+/*
  *	The information about the virtual service offered to the net
  *	and the forwarding entries
  */
@@ -314,8 +435,9 @@
 	atomic_t		refcnt;   /* reference counter */
 	atomic_t		usecnt;   /* use counter */
 
+	u16			af;       /* address family */
 	__u16			protocol; /* which protocol (TCP/UDP) */
-	__be32			addr;	  /* IP address for virtual service */
+	union nf_inet_addr	addr;	  /* IP address for virtual service */
 	__be16			port;	  /* port number for the service */
 	__u32                   fwmark;   /* firewall mark of the service */
 	unsigned		flags;	  /* service status flags */
@@ -342,7 +464,8 @@
 	struct list_head	n_list;   /* for the dests in the service */
 	struct list_head	d_list;   /* for table with all the dests */
 
-	__be32			addr;		/* IP address of the server */
+	u16			af;		/* address family */
+	union nf_inet_addr	addr;		/* IP address of the server */
 	__be16			port;		/* port number of the server */
 	volatile unsigned	flags;		/* dest status flags */
 	atomic_t		conn_flags;	/* flags to copy to conn */
@@ -366,7 +489,7 @@
 	/* for virtual service */
 	struct ip_vs_service	*svc;		/* service it belongs to */
 	__u16			protocol;	/* which protocol (TCP/UDP) */
-	__be32			vaddr;		/* virtual IP address */
+	union nf_inet_addr	vaddr;		/* virtual IP address */
 	__be16			vport;		/* virtual port number */
 	__u32			vfwmark;	/* firewall mark of service */
 };
@@ -380,6 +503,9 @@
 	char			*name;		/* scheduler name */
 	atomic_t		refcnt;		/* reference counter */
 	struct module		*module;	/* THIS_MODULE/NULL */
+#ifdef CONFIG_IP_VS_IPV6
+	int			supports_ipv6;	/* scheduler has IPv6 support */
+#endif
 
 	/* scheduler initializing service */
 	int (*init_service)(struct ip_vs_service *svc);
@@ -479,16 +605,8 @@
 #ifndef CONFIG_IP_VS_TAB_BITS
 #define CONFIG_IP_VS_TAB_BITS   12
 #endif
-/* make sure that IP_VS_CONN_TAB_BITS is located in [8, 20] */
-#if CONFIG_IP_VS_TAB_BITS < 8
-#define IP_VS_CONN_TAB_BITS	8
-#endif
-#if CONFIG_IP_VS_TAB_BITS > 20
-#define IP_VS_CONN_TAB_BITS	20
-#endif
-#if 8 <= CONFIG_IP_VS_TAB_BITS && CONFIG_IP_VS_TAB_BITS <= 20
+
 #define IP_VS_CONN_TAB_BITS	CONFIG_IP_VS_TAB_BITS
-#endif
 #define IP_VS_CONN_TAB_SIZE     (1 << IP_VS_CONN_TAB_BITS)
 #define IP_VS_CONN_TAB_MASK     (IP_VS_CONN_TAB_SIZE - 1)
 
@@ -500,11 +618,16 @@
 };
 
 extern struct ip_vs_conn *ip_vs_conn_in_get
-(int protocol, __be32 s_addr, __be16 s_port, __be32 d_addr, __be16 d_port);
+(int af, int protocol, const union nf_inet_addr *s_addr, __be16 s_port,
+ const union nf_inet_addr *d_addr, __be16 d_port);
+
 extern struct ip_vs_conn *ip_vs_ct_in_get
-(int protocol, __be32 s_addr, __be16 s_port, __be32 d_addr, __be16 d_port);
+(int af, int protocol, const union nf_inet_addr *s_addr, __be16 s_port,
+ const union nf_inet_addr *d_addr, __be16 d_port);
+
 extern struct ip_vs_conn *ip_vs_conn_out_get
-(int protocol, __be32 s_addr, __be16 s_port, __be32 d_addr, __be16 d_port);
+(int af, int protocol, const union nf_inet_addr *s_addr, __be16 s_port,
+ const union nf_inet_addr *d_addr, __be16 d_port);
 
 /* put back the conn without restarting its timer */
 static inline void __ip_vs_conn_put(struct ip_vs_conn *cp)
@@ -515,8 +638,9 @@
 extern void ip_vs_conn_fill_cport(struct ip_vs_conn *cp, __be16 cport);
 
 extern struct ip_vs_conn *
-ip_vs_conn_new(int proto, __be32 caddr, __be16 cport, __be32 vaddr, __be16 vport,
-	       __be32 daddr, __be16 dport, unsigned flags,
+ip_vs_conn_new(int af, int proto, const union nf_inet_addr *caddr, __be16 cport,
+	       const union nf_inet_addr *vaddr, __be16 vport,
+	       const union nf_inet_addr *daddr, __be16 dport, unsigned flags,
 	       struct ip_vs_dest *dest);
 extern void ip_vs_conn_expire_now(struct ip_vs_conn *cp);
 
@@ -532,24 +656,32 @@
 {
 	struct ip_vs_conn *ctl_cp = cp->control;
 	if (!ctl_cp) {
-		IP_VS_ERR("request control DEL for uncontrolled: "
-			  "%d.%d.%d.%d:%d to %d.%d.%d.%d:%d\n",
-			  NIPQUAD(cp->caddr),ntohs(cp->cport),
-			  NIPQUAD(cp->vaddr),ntohs(cp->vport));
+		IP_VS_ERR_BUF("request control DEL for uncontrolled: "
+			      "%s:%d to %s:%d\n",
+			      IP_VS_DBG_ADDR(cp->af, &cp->caddr),
+			      ntohs(cp->cport),
+			      IP_VS_DBG_ADDR(cp->af, &cp->vaddr),
+			      ntohs(cp->vport));
+
 		return;
 	}
 
-	IP_VS_DBG(7, "DELeting control for: "
-		  "cp.dst=%d.%d.%d.%d:%d ctl_cp.dst=%d.%d.%d.%d:%d\n",
-		  NIPQUAD(cp->caddr),ntohs(cp->cport),
-		  NIPQUAD(ctl_cp->caddr),ntohs(ctl_cp->cport));
+	IP_VS_DBG_BUF(7, "DELeting control for: "
+		      "cp.dst=%s:%d ctl_cp.dst=%s:%d\n",
+		      IP_VS_DBG_ADDR(cp->af, &cp->caddr),
+		      ntohs(cp->cport),
+		      IP_VS_DBG_ADDR(cp->af, &ctl_cp->caddr),
+		      ntohs(ctl_cp->cport));
 
 	cp->control = NULL;
 	if (atomic_read(&ctl_cp->n_control) == 0) {
-		IP_VS_ERR("BUG control DEL with n=0 : "
-			  "%d.%d.%d.%d:%d to %d.%d.%d.%d:%d\n",
-			  NIPQUAD(cp->caddr),ntohs(cp->cport),
-			  NIPQUAD(cp->vaddr),ntohs(cp->vport));
+		IP_VS_ERR_BUF("BUG control DEL with n=0 : "
+			      "%s:%d to %s:%d\n",
+			      IP_VS_DBG_ADDR(cp->af, &cp->caddr),
+			      ntohs(cp->cport),
+			      IP_VS_DBG_ADDR(cp->af, &cp->vaddr),
+			      ntohs(cp->vport));
+
 		return;
 	}
 	atomic_dec(&ctl_cp->n_control);
@@ -559,17 +691,22 @@
 ip_vs_control_add(struct ip_vs_conn *cp, struct ip_vs_conn *ctl_cp)
 {
 	if (cp->control) {
-		IP_VS_ERR("request control ADD for already controlled: "
-			  "%d.%d.%d.%d:%d to %d.%d.%d.%d:%d\n",
-			  NIPQUAD(cp->caddr),ntohs(cp->cport),
-			  NIPQUAD(cp->vaddr),ntohs(cp->vport));
+		IP_VS_ERR_BUF("request control ADD for already controlled: "
+			      "%s:%d to %s:%d\n",
+			      IP_VS_DBG_ADDR(cp->af, &cp->caddr),
+			      ntohs(cp->cport),
+			      IP_VS_DBG_ADDR(cp->af, &cp->vaddr),
+			      ntohs(cp->vport));
+
 		ip_vs_control_del(cp);
 	}
 
-	IP_VS_DBG(7, "ADDing control for: "
-		  "cp.dst=%d.%d.%d.%d:%d ctl_cp.dst=%d.%d.%d.%d:%d\n",
-		  NIPQUAD(cp->caddr),ntohs(cp->cport),
-		  NIPQUAD(ctl_cp->caddr),ntohs(ctl_cp->cport));
+	IP_VS_DBG_BUF(7, "ADDing control for: "
+		      "cp.dst=%s:%d ctl_cp.dst=%s:%d\n",
+		      IP_VS_DBG_ADDR(cp->af, &cp->caddr),
+		      ntohs(cp->cport),
+		      IP_VS_DBG_ADDR(cp->af, &ctl_cp->caddr),
+		      ntohs(ctl_cp->cport));
 
 	cp->control = ctl_cp;
 	atomic_inc(&ctl_cp->n_control);
@@ -647,7 +784,8 @@
 extern const struct ctl_path net_vs_ctl_path[];
 
 extern struct ip_vs_service *
-ip_vs_service_get(__u32 fwmark, __u16 protocol, __be32 vaddr, __be16 vport);
+ip_vs_service_get(int af, __u32 fwmark, __u16 protocol,
+		  const union nf_inet_addr *vaddr, __be16 vport);
 
 static inline void ip_vs_service_put(struct ip_vs_service *svc)
 {
@@ -655,14 +793,16 @@
 }
 
 extern struct ip_vs_dest *
-ip_vs_lookup_real_service(__u16 protocol, __be32 daddr, __be16 dport);
+ip_vs_lookup_real_service(int af, __u16 protocol,
+			  const union nf_inet_addr *daddr, __be16 dport);
+
 extern int ip_vs_use_count_inc(void);
 extern void ip_vs_use_count_dec(void);
 extern int ip_vs_control_init(void);
 extern void ip_vs_control_cleanup(void);
 extern struct ip_vs_dest *
-ip_vs_find_dest(__be32 daddr, __be16 dport,
-		 __be32 vaddr, __be16 vport, __u16 protocol);
+ip_vs_find_dest(int af, const union nf_inet_addr *daddr, __be16 dport,
+		const union nf_inet_addr *vaddr, __be16 vport, __u16 protocol);
 extern struct ip_vs_dest *ip_vs_try_bind_dest(struct ip_vs_conn *cp);
 
 
@@ -683,6 +823,8 @@
 /*
  *      IPVS rate estimator prototypes (from ip_vs_est.c)
  */
+extern int ip_vs_estimator_init(void);
+extern void ip_vs_estimator_cleanup(void);
 extern void ip_vs_new_estimator(struct ip_vs_stats *stats);
 extern void ip_vs_kill_estimator(struct ip_vs_stats *stats);
 extern void ip_vs_zero_estimator(struct ip_vs_stats *stats);
@@ -704,6 +846,19 @@
 (struct sk_buff *skb, struct ip_vs_conn *cp, struct ip_vs_protocol *pp, int offset);
 extern void ip_vs_dst_reset(struct ip_vs_dest *dest);
 
+#ifdef CONFIG_IP_VS_IPV6
+extern int ip_vs_bypass_xmit_v6
+(struct sk_buff *skb, struct ip_vs_conn *cp, struct ip_vs_protocol *pp);
+extern int ip_vs_nat_xmit_v6
+(struct sk_buff *skb, struct ip_vs_conn *cp, struct ip_vs_protocol *pp);
+extern int ip_vs_tunnel_xmit_v6
+(struct sk_buff *skb, struct ip_vs_conn *cp, struct ip_vs_protocol *pp);
+extern int ip_vs_dr_xmit_v6
+(struct sk_buff *skb, struct ip_vs_conn *cp, struct ip_vs_protocol *pp);
+extern int ip_vs_icmp_xmit_v6
+(struct sk_buff *skb, struct ip_vs_conn *cp, struct ip_vs_protocol *pp,
+ int offset);
+#endif
 
 /*
  *	This is a simple mechanism to ignore packets when
@@ -748,7 +903,12 @@
 }
 
 extern void ip_vs_nat_icmp(struct sk_buff *skb, struct ip_vs_protocol *pp,
-		struct ip_vs_conn *cp, int dir);
+			   struct ip_vs_conn *cp, int dir);
+
+#ifdef CONFIG_IP_VS_IPV6
+extern void ip_vs_nat_icmp_v6(struct sk_buff *skb, struct ip_vs_protocol *pp,
+			      struct ip_vs_conn *cp, int dir);
+#endif
 
 extern __sum16 ip_vs_checksum_complete(struct sk_buff *skb, int offset);
 
@@ -759,6 +919,17 @@
 	return csum_partial((char *) diff, sizeof(diff), oldsum);
 }
 
+#ifdef CONFIG_IP_VS_IPV6
+static inline __wsum ip_vs_check_diff16(const __be32 *old, const __be32 *new,
+					__wsum oldsum)
+{
+	__be32 diff[8] = { ~old[3], ~old[2], ~old[1], ~old[0],
+			    new[3],  new[2],  new[1],  new[0] };
+
+	return csum_partial((char *) diff, sizeof(diff), oldsum);
+}
+#endif
+
 static inline __wsum ip_vs_check_diff2(__be16 old, __be16 new, __wsum oldsum)
 {
 	__be16 diff[2] = { ~old, new };
diff --git a/include/net/ipip.h b/include/net/ipip.h
index a85bda6..fdf9bd7 100644
--- a/include/net/ipip.h
+++ b/include/net/ipip.h
@@ -37,7 +37,7 @@
 
 #define IPTUNNEL_XMIT() do {						\
 	int err;							\
-	int pkt_len = skb->len;						\
+	int pkt_len = skb->len - skb_transport_offset(skb);		\
 									\
 	skb->ip_summed = CHECKSUM_NONE;					\
 	ip_select_ident(iph, &rt->u.dst, NULL);				\
diff --git a/include/net/ipv6.h b/include/net/ipv6.h
index 113028f..6d5b58a 100644
--- a/include/net/ipv6.h
+++ b/include/net/ipv6.h
@@ -110,43 +110,42 @@
 extern int sysctl_mld_max_msf;
 extern struct ctl_path net_ipv6_ctl_path[];
 
-#define _DEVINC(statname, modifier, idev, field)			\
+#define _DEVINC(net, statname, modifier, idev, field)			\
 ({									\
 	struct inet6_dev *_idev = (idev);				\
 	if (likely(_idev != NULL))					\
 		SNMP_INC_STATS##modifier((_idev)->stats.statname, (field)); \
-	SNMP_INC_STATS##modifier(statname##_statistics, (field));	\
+	SNMP_INC_STATS##modifier((net)->mib.statname##_statistics, (field));\
 })
 
-#define _DEVADD(statname, modifier, idev, field, val)			\
+#define _DEVADD(net, statname, modifier, idev, field, val)		\
 ({									\
 	struct inet6_dev *_idev = (idev);				\
 	if (likely(_idev != NULL))					\
 		SNMP_ADD_STATS##modifier((_idev)->stats.statname, (field), (val)); \
-	SNMP_ADD_STATS##modifier(statname##_statistics, (field), (val));\
+	SNMP_ADD_STATS##modifier((net)->mib.statname##_statistics, (field), (val));\
 })
 
 /* MIBs */
-DECLARE_SNMP_STAT(struct ipstats_mib, ipv6_statistics);
 
-#define IP6_INC_STATS(idev,field)	_DEVINC(ipv6, , idev, field)
-#define IP6_INC_STATS_BH(idev,field)	_DEVINC(ipv6, _BH, idev, field)
-#define IP6_ADD_STATS_BH(idev,field,val) _DEVADD(ipv6, _BH, idev, field, val)
+#define IP6_INC_STATS(net, idev,field)		\
+		_DEVINC(net, ipv6, , idev, field)
+#define IP6_INC_STATS_BH(net, idev,field)	\
+		_DEVINC(net, ipv6, _BH, idev, field)
+#define IP6_ADD_STATS_BH(net, idev,field,val)	\
+		_DEVADD(net, ipv6, _BH, idev, field, val)
 
-DECLARE_SNMP_STAT(struct icmpv6_mib, icmpv6_statistics);
-DECLARE_SNMP_STAT(struct icmpv6msg_mib, icmpv6msg_statistics);
+#define ICMP6_INC_STATS(net, idev, field)	\
+		_DEVINC(net, icmpv6, , idev, field)
+#define ICMP6_INC_STATS_BH(net, idev, field)	\
+		_DEVINC(net, icmpv6, _BH, idev, field)
 
-#define ICMP6_INC_STATS(idev, field)	_DEVINC(icmpv6, , idev, field)
-#define ICMP6_INC_STATS_BH(idev, field)	_DEVINC(icmpv6, _BH, idev, field)
-
-#define ICMP6MSGOUT_INC_STATS(idev, field) \
-	_DEVINC(icmpv6msg, , idev, field +256)
-#define ICMP6MSGOUT_INC_STATS_BH(idev, field) \
-	_DEVINC(icmpv6msg, _BH, idev, field +256)
-#define ICMP6MSGIN_INC_STATS(idev, field) \
-	 _DEVINC(icmpv6msg, , idev, field)
-#define ICMP6MSGIN_INC_STATS_BH(idev, field) \
-	_DEVINC(icmpv6msg, _BH, idev, field)
+#define ICMP6MSGOUT_INC_STATS(net, idev, field)		\
+	_DEVINC(net, icmpv6msg, , idev, field +256)
+#define ICMP6MSGOUT_INC_STATS_BH(net, idev, field)	\
+	_DEVINC(net, icmpv6msg, _BH, idev, field +256)
+#define ICMP6MSGIN_INC_STATS_BH(net, idev, field)	\
+	_DEVINC(net, icmpv6msg, _BH, idev, field)
 
 struct ip6_ra_chain
 {
@@ -576,6 +575,8 @@
 extern int ip6_mc_msfget(struct sock *sk, struct group_filter *gsf,
 			 struct group_filter __user *optval,
 			 int __user *optlen);
+extern unsigned int inet6_hash_frag(__be32 id, const struct in6_addr *saddr,
+				    const struct in6_addr *daddr, u32 rnd);
 
 #ifdef CONFIG_PROC_FS
 extern int  ac6_proc_init(struct net *net);
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index ff137fd..5617a16 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -158,13 +158,17 @@
  *	also implies a change in the AID.
  * @BSS_CHANGED_ERP_CTS_PROT: CTS protection changed
  * @BSS_CHANGED_ERP_PREAMBLE: preamble changed
+ * @BSS_CHANGED_ERP_SLOT: slot timing changed
  * @BSS_CHANGED_HT: 802.11n parameters changed
+ * @BSS_CHANGED_BASIC_RATES: Basic rateset changed
  */
 enum ieee80211_bss_change {
 	BSS_CHANGED_ASSOC		= 1<<0,
 	BSS_CHANGED_ERP_CTS_PROT	= 1<<1,
 	BSS_CHANGED_ERP_PREAMBLE	= 1<<2,
+	BSS_CHANGED_ERP_SLOT		= 1<<3,
 	BSS_CHANGED_HT                  = 1<<4,
+	BSS_CHANGED_BASIC_RATES		= 1<<5,
 };
 
 /**
@@ -177,6 +181,7 @@
  * @aid: association ID number, valid only when @assoc is true
  * @use_cts_prot: use CTS protection
  * @use_short_preamble: use 802.11b short preamble
+ * @use_short_slot: use short slot time (only relevant for ERP)
  * @dtim_period: num of beacons before the next DTIM, for PSM
  * @timestamp: beacon timestamp
  * @beacon_int: beacon interval
@@ -184,6 +189,9 @@
  * @assoc_ht: association in HT mode
  * @ht_conf: ht capabilities
  * @ht_bss_conf: ht extended capabilities
+ * @basic_rates: bitmap of basic rates, each bit stands for an
+ *	index into the rate table configured by the driver in
+ *	the current band.
  */
 struct ieee80211_bss_conf {
 	/* association related data */
@@ -192,10 +200,12 @@
 	/* erp related data */
 	bool use_cts_prot;
 	bool use_short_preamble;
+	bool use_short_slot;
 	u8 dtim_period;
 	u16 beacon_int;
 	u16 assoc_capability;
 	u64 timestamp;
+	u64 basic_rates;
 	/* ht related data */
 	bool assoc_ht;
 	struct ieee80211_ht_info *ht_conf;
@@ -282,6 +292,20 @@
 #define IEEE80211_TX_INFO_DRIVER_DATA_PTRS \
 	(IEEE80211_TX_INFO_DRIVER_DATA_SIZE / sizeof(void *))
 
+/* maximum number of alternate rate retry stages */
+#define IEEE80211_TX_MAX_ALTRATE	3
+
+/**
+ * struct ieee80211_tx_altrate - alternate rate selection/status
+ *
+ * @rate_idx: rate index to attempt to send with
+ * @limit: number of retries before fallback
+ */
+struct ieee80211_tx_altrate {
+	s8 rate_idx;
+	u8 limit;
+};
+
 /**
  * struct ieee80211_tx_info - skb transmit information
  *
@@ -290,6 +314,9 @@
  *  (2) driver internal use (if applicable)
  *  (3) TX status information - driver tells mac80211 what happened
  *
+ * The TX control's sta pointer is only valid during the ->tx call,
+ * it may be NULL.
+ *
  * @flags: transmit info flags, defined above
  * @band: TBD
  * @tx_rate_idx: TBD
@@ -317,18 +344,19 @@
 
 	union {
 		struct {
+			/* NB: vif can be NULL for injected frames */
 			struct ieee80211_vif *vif;
 			struct ieee80211_key_conf *hw_key;
+			struct ieee80211_sta *sta;
 			unsigned long jiffies;
-			u16 aid;
-			s8 rts_cts_rate_idx, alt_retry_rate_idx;
+			s8 rts_cts_rate_idx;
 			u8 retry_limit;
-			u8 icv_len;
-			u8 iv_len;
+			struct ieee80211_tx_altrate retries[IEEE80211_TX_MAX_ALTRATE];
 		} control;
 		struct {
 			u64 ampdu_ack_map;
 			int ack_signal;
+			struct ieee80211_tx_altrate retries[IEEE80211_TX_MAX_ALTRATE + 1];
 			u8 retry_count;
 			bool excessive_retries;
 			u8 ampdu_ack_len;
@@ -363,6 +391,7 @@
  * @RX_FLAG_TSFT: The timestamp passed in the RX status (@mactime field)
  *	is valid. This is useful in monitor mode and necessary for beacon frames
  *	to enable IBSS merging.
+ * @RX_FLAG_SHORTPRE: Short preamble was used for this frame
  */
 enum mac80211_rx_flags {
 	RX_FLAG_MMIC_ERROR	= 1<<0,
@@ -373,6 +402,7 @@
 	RX_FLAG_FAILED_FCS_CRC	= 1<<5,
 	RX_FLAG_FAILED_PLCP_CRC = 1<<6,
 	RX_FLAG_TSFT		= 1<<7,
+	RX_FLAG_SHORTPRE	= 1<<8
 };
 
 /**
@@ -418,6 +448,11 @@
  * @IEEE80211_CONF_PS: Enable 802.11 power save mode
  */
 enum ieee80211_conf_flags {
+	/*
+	 * TODO: IEEE80211_CONF_SHORT_SLOT_TIME will be removed once drivers
+	 * have been converted to use bss_info_changed() for slot time
+	 * configuration
+	 */
 	IEEE80211_CONF_SHORT_SLOT_TIME	= (1<<0),
 	IEEE80211_CONF_RADIOTAP		= (1<<1),
 	IEEE80211_CONF_SUPPORT_HT_MODE	= (1<<2),
@@ -461,33 +496,6 @@
 };
 
 /**
- * enum ieee80211_if_types - types of 802.11 network interfaces
- *
- * @IEEE80211_IF_TYPE_INVALID: invalid interface type, not used
- *	by mac80211 itself
- * @IEEE80211_IF_TYPE_AP: interface in AP mode.
- * @IEEE80211_IF_TYPE_MGMT: special interface for communication with hostap
- *	daemon. Drivers should never see this type.
- * @IEEE80211_IF_TYPE_STA: interface in STA (client) mode.
- * @IEEE80211_IF_TYPE_IBSS: interface in IBSS (ad-hoc) mode.
- * @IEEE80211_IF_TYPE_MNTR: interface in monitor (rfmon) mode.
- * @IEEE80211_IF_TYPE_WDS: interface in WDS mode.
- * @IEEE80211_IF_TYPE_VLAN: VLAN interface bound to an AP, drivers
- *	will never see this type.
- * @IEEE80211_IF_TYPE_MESH_POINT: 802.11s mesh point
- */
-enum ieee80211_if_types {
-	IEEE80211_IF_TYPE_INVALID,
-	IEEE80211_IF_TYPE_AP,
-	IEEE80211_IF_TYPE_STA,
-	IEEE80211_IF_TYPE_IBSS,
-	IEEE80211_IF_TYPE_MESH_POINT,
-	IEEE80211_IF_TYPE_MNTR,
-	IEEE80211_IF_TYPE_WDS,
-	IEEE80211_IF_TYPE_VLAN,
-};
-
-/**
  * struct ieee80211_vif - per-interface data
  *
  * Data in this structure is continually present for driver
@@ -498,7 +506,7 @@
  *	sizeof(void *).
  */
 struct ieee80211_vif {
-	enum ieee80211_if_types type;
+	enum nl80211_iftype type;
 	/* must be last */
 	u8 drv_priv[0] __attribute__((__aligned__(sizeof(void *))));
 };
@@ -506,7 +514,7 @@
 static inline bool ieee80211_vif_is_mesh(struct ieee80211_vif *vif)
 {
 #ifdef CONFIG_MAC80211_MESH
-	return vif->type == IEEE80211_IF_TYPE_MESH_POINT;
+	return vif->type == NL80211_IFTYPE_MESH_POINT;
 #endif
 	return false;
 }
@@ -517,7 +525,7 @@
  * @vif: pointer to a driver-use per-interface structure. The pointer
  *	itself is also used for various functions including
  *	ieee80211_beacon_get() and ieee80211_get_buffered_bc().
- * @type: one of &enum ieee80211_if_types constants. Determines the type of
+ * @type: one of &enum nl80211_iftype constants. Determines the type of
  *	added/removed interface.
  * @mac_addr: pointer to MAC address of the interface. This pointer is valid
  *	until the interface is removed (i.e. it cannot be used after
@@ -533,7 +541,7 @@
  * in pure monitor mode.
  */
 struct ieee80211_if_init_conf {
-	enum ieee80211_if_types type;
+	enum nl80211_iftype type;
 	struct ieee80211_vif *vif;
 	void *mac_addr;
 };
@@ -641,6 +649,8 @@
  */
 struct ieee80211_key_conf {
 	enum ieee80211_key_alg alg;
+	u8 icv_len;
+	u8 iv_len;
 	u8 hw_key_idx;
 	u8 flags;
 	s8 keyidx;
@@ -662,6 +672,33 @@
 };
 
 /**
+ * struct ieee80211_sta - station table entry
+ *
+ * A station table entry represents a station we are possibly
+ * communicating with. Since stations are RCU-managed in
+ * mac80211, any ieee80211_sta pointer you get access to must
+ * either be protected by rcu_read_lock() explicitly or implicitly,
+ * or you must take good care to not use such a pointer after a
+ * call to your sta_notify callback that removed it.
+ *
+ * @addr: MAC address
+ * @aid: AID we assigned to the station if we're an AP
+ * @supp_rates: Bitmap of supported rates (per band)
+ * @ht_info: HT capabilities of this STA
+ * @drv_priv: data area for driver use, will always be aligned to
+ *	sizeof(void *), size is determined in hw information.
+ */
+struct ieee80211_sta {
+	u64 supp_rates[IEEE80211_NUM_BANDS];
+	u8 addr[ETH_ALEN];
+	u16 aid;
+	struct ieee80211_ht_info ht_info;
+
+	/* must be last */
+	u8 drv_priv[0] __attribute__((__aligned__(sizeof(void *))));
+};
+
+/**
  * enum sta_notify_cmd - sta notify command
  *
  * Used with the sta_notify() callback in &struct ieee80211_ops, this
@@ -805,6 +842,11 @@
  *
  * @vif_data_size: size (in bytes) of the drv_priv data area
  *	within &struct ieee80211_vif.
+ * @sta_data_size: size (in bytes) of the drv_priv data area
+ *	within &struct ieee80211_sta.
+ *
+ * @max_altrates: maximum number of alternate rate retry stages
+ * @max_altrate_tries: maximum number of tries for each stage
  */
 struct ieee80211_hw {
 	struct ieee80211_conf conf;
@@ -816,12 +858,17 @@
 	unsigned int extra_tx_headroom;
 	int channel_change_time;
 	int vif_data_size;
+	int sta_data_size;
 	u16 queues;
 	u16 ampdu_queues;
 	u16 max_listen_interval;
 	s8 max_signal;
+	u8 max_altrates;
+	u8 max_altrate_tries;
 };
 
+struct ieee80211_hw *wiphy_to_hw(struct wiphy *wiphy);
+
 /**
  * SET_IEEE80211_DEV - set device for 802.11 hardware
  *
@@ -874,11 +921,11 @@
 
 static inline struct ieee80211_rate *
 ieee80211_get_alt_retry_rate(const struct ieee80211_hw *hw,
-			     const struct ieee80211_tx_info *c)
+			     const struct ieee80211_tx_info *c, int idx)
 {
-	if (c->control.alt_retry_rate_idx < 0)
+	if (c->control.retries[idx].rate_idx < 0)
 		return NULL;
-	return &hw->wiphy->bands[c->band]->bitrates[c->control.alt_retry_rate_idx];
+	return &hw->wiphy->bands[c->band]->bitrates[c->control.retries[idx].rate_idx];
 }
 
 /**
@@ -1097,7 +1144,7 @@
  *	This callback must be implemented and atomic.
  *
  * @set_tim: Set TIM bit. mac80211 calls this function when a TIM bit
- * 	must be set or cleared for a given AID. Must be atomic.
+ * 	must be set or cleared for a given STA. Must be atomic.
  *
  * @set_key: See the section "Hardware crypto acceleration"
  *	This callback can sleep, and is only called between add_interface
@@ -1111,7 +1158,9 @@
  * @hw_scan: Ask the hardware to service the scan request, no need to start
  *	the scan state machine in stack. The scan must honour the channel
  *	configuration done by the regulatory agent in the wiphy's registered
- *	bands.
+ *	bands. When the scan finishes, ieee80211_scan_completed() must be
+ *	called; note that it also must be called when the scan cannot finish
+ *	because the hardware is turned off! Anything else is a bug!
  *
  * @get_stats: return low-level statistics
  *
@@ -1131,7 +1180,7 @@
  *	of assocaited station or AP.
  *
  * @conf_tx: Configure TX queue parameters (EDCF (aifs, cw_min, cw_max),
- *	bursting) for a hardware TX queue. Must be atomic.
+ *	bursting) for a hardware TX queue.
  *
  * @get_tx_stats: Get statistics of the current TX queue status. This is used
  *	to get number of currently queued packets (queue length), maximum queue
@@ -1181,7 +1230,8 @@
 				 unsigned int changed_flags,
 				 unsigned int *total_flags,
 				 int mc_count, struct dev_addr_list *mc_list);
-	int (*set_tim)(struct ieee80211_hw *hw, int aid, int set);
+	int (*set_tim)(struct ieee80211_hw *hw, struct ieee80211_sta *sta,
+		       bool set);
 	int (*set_key)(struct ieee80211_hw *hw, enum set_key_cmd cmd,
 		       const u8 *local_address, const u8 *address,
 		       struct ieee80211_key_conf *key);
@@ -1198,7 +1248,7 @@
 	int (*set_retry_limit)(struct ieee80211_hw *hw,
 			       u32 short_retry, u32 long_retr);
 	void (*sta_notify)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
-			enum sta_notify_cmd, const u8 *addr);
+			enum sta_notify_cmd, struct ieee80211_sta *sta);
 	int (*conf_tx)(struct ieee80211_hw *hw, u16 queue,
 		       const struct ieee80211_tx_queue_params *params);
 	int (*get_tx_stats)(struct ieee80211_hw *hw,
@@ -1208,7 +1258,7 @@
 	int (*tx_last_beacon)(struct ieee80211_hw *hw);
 	int (*ampdu_action)(struct ieee80211_hw *hw,
 			    enum ieee80211_ampdu_mlme_action action,
-			    const u8 *addr, u16 tid, u16 *ssn);
+			    struct ieee80211_sta *sta, u16 tid, u16 *ssn);
 };
 
 /**
@@ -1557,16 +1607,6 @@
 unsigned int ieee80211_get_hdrlen_from_skb(const struct sk_buff *skb);
 
 /**
- * ieee80211_get_hdrlen - get header length from frame control
- *
- * This function returns the 802.11 header length in bytes (not including
- * encryption headers.)
- *
- * @fc: the frame control field (in CPU endianness)
- */
-int ieee80211_get_hdrlen(u16 fc);
-
-/**
  * ieee80211_hdrlen - get header length in bytes from frame control
  * @fc: frame control field in little-endian format
  */
@@ -1608,6 +1648,16 @@
 void ieee80211_stop_queue(struct ieee80211_hw *hw, int queue);
 
 /**
+ * ieee80211_queue_stopped - test status of the queue
+ * @hw: pointer as obtained from ieee80211_alloc_hw().
+ * @queue: queue number (counted from zero).
+ *
+ * Drivers should use this function instead of netif_stop_queue.
+ */
+
+int ieee80211_queue_stopped(struct ieee80211_hw *hw, int queue);
+
+/**
  * ieee80211_stop_queues - stop all queues
  * @hw: pointer as obtained from ieee80211_alloc_hw().
  *
@@ -1758,4 +1808,85 @@
  */
 void ieee80211_notify_mac(struct ieee80211_hw *hw,
 			  enum ieee80211_notification_types  notif_type);
+
+/**
+ * ieee80211_find_sta - find a station
+ *
+ * @hw: pointer as obtained from ieee80211_alloc_hw()
+ * @addr: station's address
+ *
+ * This function must be called under RCU lock and the
+ * resulting pointer is only valid under RCU lock as well.
+ */
+struct ieee80211_sta *ieee80211_find_sta(struct ieee80211_hw *hw,
+					 const u8 *addr);
+
+
+/* Rate control API */
+/**
+ * struct rate_selection - rate information for/from rate control algorithms
+ *
+ * @rate_idx: selected transmission rate index
+ * @nonerp_idx: Non-ERP rate to use instead if ERP cannot be used
+ * @probe_idx: rate for probing (or -1)
+ * @max_rate_idx: maximum rate index that can be used, this is
+ *	input to the algorithm and will be enforced
+ */
+struct rate_selection {
+	s8 rate_idx, nonerp_idx, probe_idx, max_rate_idx;
+};
+
+struct rate_control_ops {
+	struct module *module;
+	const char *name;
+	void *(*alloc)(struct ieee80211_hw *hw, struct dentry *debugfsdir);
+	void (*clear)(void *priv);
+	void (*free)(void *priv);
+
+	void *(*alloc_sta)(void *priv, struct ieee80211_sta *sta, gfp_t gfp);
+	void (*rate_init)(void *priv, struct ieee80211_supported_band *sband,
+			  struct ieee80211_sta *sta, void *priv_sta);
+	void (*free_sta)(void *priv, struct ieee80211_sta *sta,
+			 void *priv_sta);
+
+	void (*tx_status)(void *priv, struct ieee80211_supported_band *sband,
+			  struct ieee80211_sta *sta, void *priv_sta,
+			  struct sk_buff *skb);
+	void (*get_rate)(void *priv, struct ieee80211_supported_band *sband,
+			 struct ieee80211_sta *sta, void *priv_sta,
+			 struct sk_buff *skb,
+			 struct rate_selection *sel);
+
+	void (*add_sta_debugfs)(void *priv, void *priv_sta,
+				struct dentry *dir);
+	void (*remove_sta_debugfs)(void *priv, void *priv_sta);
+};
+
+static inline int rate_supported(struct ieee80211_sta *sta,
+				 enum ieee80211_band band,
+				 int index)
+{
+	return (sta == NULL || sta->supp_rates[band] & BIT(index));
+}
+
+static inline s8
+rate_lowest_index(struct ieee80211_supported_band *sband,
+		  struct ieee80211_sta *sta)
+{
+	int i;
+
+	for (i = 0; i < sband->n_bitrates; i++)
+		if (rate_supported(sta, sband->band, i))
+			return i;
+
+	/* warn when we cannot find a rate. */
+	WARN_ON(1);
+
+	return 0;
+}
+
+
+int ieee80211_rate_control_register(struct rate_control_ops *ops);
+void ieee80211_rate_control_unregister(struct rate_control_ops *ops);
+
 #endif /* MAC80211_H */
diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h
index a8eb43c..708009b 100644
--- a/include/net/net_namespace.h
+++ b/include/net/net_namespace.h
@@ -16,6 +16,9 @@
 #include <net/netns/ipv6.h>
 #include <net/netns/dccp.h>
 #include <net/netns/x_tables.h>
+#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
+#include <net/netns/conntrack.h>
+#endif
 
 struct proc_dir_entry;
 struct net_device;
@@ -67,6 +70,9 @@
 #endif
 #ifdef CONFIG_NETFILTER
 	struct netns_xt		xt;
+#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
+	struct netns_ct		ct;
+#endif
 #endif
 	struct net_generic	*gen;
 };
diff --git a/include/net/netfilter/ipv4/nf_defrag_ipv4.h b/include/net/netfilter/ipv4/nf_defrag_ipv4.h
new file mode 100644
index 0000000..6b00ea3
--- /dev/null
+++ b/include/net/netfilter/ipv4/nf_defrag_ipv4.h
@@ -0,0 +1,6 @@
+#ifndef _NF_DEFRAG_IPV4_H
+#define _NF_DEFRAG_IPV4_H
+
+extern void nf_defrag_ipv4_enable(void);
+
+#endif /* _NF_DEFRAG_IPV4_H */
diff --git a/include/net/netfilter/nf_conntrack.h b/include/net/netfilter/nf_conntrack.h
index 0741ad5..b76a868 100644
--- a/include/net/netfilter/nf_conntrack.h
+++ b/include/net/netfilter/nf_conntrack.h
@@ -123,7 +123,9 @@
 
 	/* Extensions */
 	struct nf_ct_ext *ext;
-
+#ifdef CONFIG_NET_NS
+	struct net *ct_net;
+#endif
 	struct rcu_head rcu;
 };
 
@@ -147,6 +149,17 @@
 /* get master conntrack via master expectation */
 #define master_ct(conntr) (conntr->master)
 
+extern struct net init_net;
+
+static inline struct net *nf_ct_net(const struct nf_conn *ct)
+{
+#ifdef CONFIG_NET_NS
+	return ct->ct_net;
+#else
+	return &init_net;
+#endif
+}
+
 /* Alter reply tuple (maybe alter helper). */
 extern void
 nf_conntrack_alter_reply(struct nf_conn *ct,
@@ -182,11 +195,11 @@
 				 unsigned int size);
 
 extern struct nf_conntrack_tuple_hash *
-__nf_conntrack_find(const struct nf_conntrack_tuple *tuple);
+__nf_conntrack_find(struct net *net, const struct nf_conntrack_tuple *tuple);
 
 extern void nf_conntrack_hash_insert(struct nf_conn *ct);
 
-extern void nf_conntrack_flush(void);
+extern void nf_conntrack_flush(struct net *net);
 
 extern bool nf_ct_get_tuplepr(const struct sk_buff *skb,
 			      unsigned int nhoff, u_int16_t l3num,
@@ -248,10 +261,11 @@
 
 /* Iterate over all conntracks: if iter returns true, it's deleted. */
 extern void
-nf_ct_iterate_cleanup(int (*iter)(struct nf_conn *i, void *data), void *data);
+nf_ct_iterate_cleanup(struct net *net, int (*iter)(struct nf_conn *i, void *data), void *data);
 extern void nf_conntrack_free(struct nf_conn *ct);
 extern struct nf_conn *
-nf_conntrack_alloc(const struct nf_conntrack_tuple *orig,
+nf_conntrack_alloc(struct net *net,
+		   const struct nf_conntrack_tuple *orig,
 		   const struct nf_conntrack_tuple *repl,
 		   gfp_t gfp);
 
@@ -273,16 +287,14 @@
 
 extern int nf_conntrack_set_hashsize(const char *val, struct kernel_param *kp);
 extern unsigned int nf_conntrack_htable_size;
-extern int nf_conntrack_checksum;
-extern atomic_t nf_conntrack_count;
 extern int nf_conntrack_max;
 
-DECLARE_PER_CPU(struct ip_conntrack_stat, nf_conntrack_stat);
-#define NF_CT_STAT_INC(count) (__get_cpu_var(nf_conntrack_stat).count++)
-#define NF_CT_STAT_INC_ATOMIC(count)			\
+#define NF_CT_STAT_INC(net, count)	\
+	(per_cpu_ptr((net)->ct.stat, raw_smp_processor_id())->count++)
+#define NF_CT_STAT_INC_ATOMIC(net, count)		\
 do {							\
 	local_bh_disable();				\
-	__get_cpu_var(nf_conntrack_stat).count++;	\
+	per_cpu_ptr((net)->ct.stat, raw_smp_processor_id())->count++;	\
 	local_bh_enable();				\
 } while (0)
 
diff --git a/include/net/netfilter/nf_conntrack_acct.h b/include/net/netfilter/nf_conntrack_acct.h
index 5d5ae55..03e218f 100644
--- a/include/net/netfilter/nf_conntrack_acct.h
+++ b/include/net/netfilter/nf_conntrack_acct.h
@@ -8,6 +8,7 @@
 
 #ifndef _NF_CONNTRACK_ACCT_H
 #define _NF_CONNTRACK_ACCT_H
+#include <net/net_namespace.h>
 #include <linux/netfilter/nf_conntrack_common.h>
 #include <linux/netfilter/nf_conntrack_tuple_common.h>
 #include <net/netfilter/nf_conntrack.h>
@@ -18,8 +19,6 @@
 	u_int64_t bytes;
 };
 
-extern int nf_ct_acct;
-
 static inline
 struct nf_conn_counter *nf_conn_acct_find(const struct nf_conn *ct)
 {
@@ -29,9 +28,10 @@
 static inline
 struct nf_conn_counter *nf_ct_acct_ext_add(struct nf_conn *ct, gfp_t gfp)
 {
+	struct net *net = nf_ct_net(ct);
 	struct nf_conn_counter *acct;
 
-	if (!nf_ct_acct)
+	if (!net->ct.sysctl_acct)
 		return NULL;
 
 	acct = nf_ct_ext_add(ct, NF_CT_EXT_ACCT, gfp);
@@ -45,7 +45,7 @@
 extern unsigned int
 seq_print_acct(struct seq_file *s, const struct nf_conn *ct, int dir);
 
-extern int nf_conntrack_acct_init(void);
-extern void nf_conntrack_acct_fini(void);
+extern int nf_conntrack_acct_init(struct net *net);
+extern void nf_conntrack_acct_fini(struct net *net);
 
 #endif /* _NF_CONNTRACK_ACCT_H */
diff --git a/include/net/netfilter/nf_conntrack_core.h b/include/net/netfilter/nf_conntrack_core.h
index a817712..e78afe7 100644
--- a/include/net/netfilter/nf_conntrack_core.h
+++ b/include/net/netfilter/nf_conntrack_core.h
@@ -20,12 +20,13 @@
 /* This header is used to share core functionality between the
    standalone connection tracking module, and the compatibility layer's use
    of connection tracking. */
-extern unsigned int nf_conntrack_in(int pf,
+extern unsigned int nf_conntrack_in(struct net *net,
+				    u_int8_t pf,
 				    unsigned int hooknum,
 				    struct sk_buff *skb);
 
-extern int nf_conntrack_init(void);
-extern void nf_conntrack_cleanup(void);
+extern int nf_conntrack_init(struct net *net);
+extern void nf_conntrack_cleanup(struct net *net);
 
 extern int nf_conntrack_proto_init(void);
 extern void nf_conntrack_proto_fini(void);
@@ -48,7 +49,7 @@
 
 /* Find a connection corresponding to a tuple. */
 extern struct nf_conntrack_tuple_hash *
-nf_conntrack_find_get(const struct nf_conntrack_tuple *tuple);
+nf_conntrack_find_get(struct net *net, const struct nf_conntrack_tuple *tuple);
 
 extern int __nf_conntrack_confirm(struct sk_buff *skb);
 
@@ -71,8 +72,6 @@
             const struct nf_conntrack_l3proto *l3proto,
             const struct nf_conntrack_l4proto *proto);
 
-extern struct hlist_head *nf_conntrack_hash;
 extern spinlock_t nf_conntrack_lock ;
-extern struct hlist_head unconfirmed;
 
 #endif /* _NF_CONNTRACK_CORE_H */
diff --git a/include/net/netfilter/nf_conntrack_ecache.h b/include/net/netfilter/nf_conntrack_ecache.h
index f0b9078..1285ff2 100644
--- a/include/net/netfilter/nf_conntrack_ecache.h
+++ b/include/net/netfilter/nf_conntrack_ecache.h
@@ -8,6 +8,7 @@
 
 #include <linux/notifier.h>
 #include <linux/interrupt.h>
+#include <net/net_namespace.h>
 #include <net/netfilter/nf_conntrack_expect.h>
 
 #ifdef CONFIG_NF_CONNTRACK_EVENTS
@@ -15,9 +16,6 @@
 	struct nf_conn *ct;
 	unsigned int events;
 };
-DECLARE_PER_CPU(struct nf_conntrack_ecache, nf_conntrack_ecache);
-
-#define CONNTRACK_ECACHE(x)	(__get_cpu_var(nf_conntrack_ecache).x)
 
 extern struct atomic_notifier_head nf_conntrack_chain;
 extern int nf_conntrack_register_notifier(struct notifier_block *nb);
@@ -25,17 +23,16 @@
 
 extern void nf_ct_deliver_cached_events(const struct nf_conn *ct);
 extern void __nf_ct_event_cache_init(struct nf_conn *ct);
-extern void nf_ct_event_cache_flush(void);
+extern void nf_ct_event_cache_flush(struct net *net);
 
 static inline void
-nf_conntrack_event_cache(enum ip_conntrack_events event,
-			 const struct sk_buff *skb)
+nf_conntrack_event_cache(enum ip_conntrack_events event, struct nf_conn *ct)
 {
-	struct nf_conn *ct = (struct nf_conn *)skb->nfct;
+	struct net *net = nf_ct_net(ct);
 	struct nf_conntrack_ecache *ecache;
 
 	local_bh_disable();
-	ecache = &__get_cpu_var(nf_conntrack_ecache);
+	ecache = per_cpu_ptr(net->ct.ecache, raw_smp_processor_id());
 	if (ct != ecache->ct)
 		__nf_ct_event_cache_init(ct);
 	ecache->events |= event;
@@ -60,16 +57,28 @@
 	atomic_notifier_call_chain(&nf_ct_expect_chain, event, exp);
 }
 
+extern int nf_conntrack_ecache_init(struct net *net);
+extern void nf_conntrack_ecache_fini(struct net *net);
+
 #else /* CONFIG_NF_CONNTRACK_EVENTS */
 
 static inline void nf_conntrack_event_cache(enum ip_conntrack_events event,
-					    const struct sk_buff *skb) {}
+					    struct nf_conn *ct) {}
 static inline void nf_conntrack_event(enum ip_conntrack_events event,
 				      struct nf_conn *ct) {}
 static inline void nf_ct_deliver_cached_events(const struct nf_conn *ct) {}
 static inline void nf_ct_expect_event(enum ip_conntrack_expect_events event,
 				      struct nf_conntrack_expect *exp) {}
-static inline void nf_ct_event_cache_flush(void) {}
+static inline void nf_ct_event_cache_flush(struct net *net) {}
+
+static inline int nf_conntrack_ecache_init(struct net *net)
+{
+	return 0;
+}
+
+static inline void nf_conntrack_ecache_fini(struct net *net)
+{
+}
 #endif /* CONFIG_NF_CONNTRACK_EVENTS */
 
 #endif /*_NF_CONNTRACK_ECACHE_H*/
diff --git a/include/net/netfilter/nf_conntrack_expect.h b/include/net/netfilter/nf_conntrack_expect.h
index dfdf4b4..37a7fc1 100644
--- a/include/net/netfilter/nf_conntrack_expect.h
+++ b/include/net/netfilter/nf_conntrack_expect.h
@@ -6,7 +6,6 @@
 #define _NF_CONNTRACK_EXPECT_H
 #include <net/netfilter/nf_conntrack.h>
 
-extern struct hlist_head *nf_ct_expect_hash;
 extern unsigned int nf_ct_expect_hsize;
 extern unsigned int nf_ct_expect_max;
 
@@ -56,6 +55,15 @@
 	struct rcu_head rcu;
 };
 
+static inline struct net *nf_ct_exp_net(struct nf_conntrack_expect *exp)
+{
+#ifdef CONFIG_NET_NS
+	return exp->master->ct_net;	/* by definition */
+#else
+	return &init_net;
+#endif
+}
+
 struct nf_conntrack_expect_policy
 {
 	unsigned int	max_expected;
@@ -67,17 +75,17 @@
 #define NF_CT_EXPECT_PERMANENT	0x1
 #define NF_CT_EXPECT_INACTIVE	0x2
 
-int nf_conntrack_expect_init(void);
-void nf_conntrack_expect_fini(void);
+int nf_conntrack_expect_init(struct net *net);
+void nf_conntrack_expect_fini(struct net *net);
 
 struct nf_conntrack_expect *
-__nf_ct_expect_find(const struct nf_conntrack_tuple *tuple);
+__nf_ct_expect_find(struct net *net, const struct nf_conntrack_tuple *tuple);
 
 struct nf_conntrack_expect *
-nf_ct_expect_find_get(const struct nf_conntrack_tuple *tuple);
+nf_ct_expect_find_get(struct net *net, const struct nf_conntrack_tuple *tuple);
 
 struct nf_conntrack_expect *
-nf_ct_find_expectation(const struct nf_conntrack_tuple *tuple);
+nf_ct_find_expectation(struct net *net, const struct nf_conntrack_tuple *tuple);
 
 void nf_ct_unlink_expect(struct nf_conntrack_expect *exp);
 void nf_ct_remove_expectations(struct nf_conn *ct);
@@ -86,7 +94,7 @@
 /* Allocate space for an expectation: this is mandatory before calling
    nf_ct_expect_related.  You will have to call put afterwards. */
 struct nf_conntrack_expect *nf_ct_expect_alloc(struct nf_conn *me);
-void nf_ct_expect_init(struct nf_conntrack_expect *, unsigned int, int,
+void nf_ct_expect_init(struct nf_conntrack_expect *, unsigned int, u_int8_t,
 		       const union nf_inet_addr *,
 		       const union nf_inet_addr *,
 		       u_int8_t, const __be16 *, const __be16 *);
diff --git a/include/net/netfilter/nf_conntrack_l4proto.h b/include/net/netfilter/nf_conntrack_l4proto.h
index 723df9d..7f2f43c 100644
--- a/include/net/netfilter/nf_conntrack_l4proto.h
+++ b/include/net/netfilter/nf_conntrack_l4proto.h
@@ -39,7 +39,7 @@
 		      const struct sk_buff *skb,
 		      unsigned int dataoff,
 		      enum ip_conntrack_info ctinfo,
-		      int pf,
+		      u_int8_t pf,
 		      unsigned int hooknum);
 
 	/* Called when a new connection for this protocol found;
@@ -50,9 +50,9 @@
 	/* Called when a conntrack entry is destroyed */
 	void (*destroy)(struct nf_conn *ct);
 
-	int (*error)(struct sk_buff *skb, unsigned int dataoff,
+	int (*error)(struct net *net, struct sk_buff *skb, unsigned int dataoff,
 		     enum ip_conntrack_info *ctinfo,
-		     int pf, unsigned int hooknum);
+		     u_int8_t pf, unsigned int hooknum);
 
 	/* Print out the per-protocol part of the tuple. Return like seq_* */
 	int (*print_tuple)(struct seq_file *s,
@@ -117,20 +117,19 @@
 				      struct nf_conntrack_tuple *t);
 extern const struct nla_policy nf_ct_port_nla_policy[];
 
-/* Log invalid packets */
-extern unsigned int nf_ct_log_invalid;
-
 #ifdef CONFIG_SYSCTL
 #ifdef DEBUG_INVALID_PACKETS
-#define LOG_INVALID(proto) \
-	(nf_ct_log_invalid == (proto) || nf_ct_log_invalid == IPPROTO_RAW)
+#define LOG_INVALID(net, proto)				\
+	((net)->ct.sysctl_log_invalid == (proto) ||	\
+	 (net)->ct.sysctl_log_invalid == IPPROTO_RAW)
 #else
-#define LOG_INVALID(proto) \
-	((nf_ct_log_invalid == (proto) || nf_ct_log_invalid == IPPROTO_RAW) \
+#define LOG_INVALID(net, proto)				\
+	(((net)->ct.sysctl_log_invalid == (proto) ||	\
+	  (net)->ct.sysctl_log_invalid == IPPROTO_RAW)	\
 	 && net_ratelimit())
 #endif
 #else
-#define LOG_INVALID(proto) 0
+#define LOG_INVALID(net, proto) 0
 #endif /* CONFIG_SYSCTL */
 
 #endif /*_NF_CONNTRACK_PROTOCOL_H*/
diff --git a/include/net/netfilter/nf_log.h b/include/net/netfilter/nf_log.h
index 8c6b5ae..7182c06 100644
--- a/include/net/netfilter/nf_log.h
+++ b/include/net/netfilter/nf_log.h
@@ -28,7 +28,7 @@
 	} u;
 };
 
-typedef void nf_logfn(unsigned int pf,
+typedef void nf_logfn(u_int8_t pf,
 		      unsigned int hooknum,
 		      const struct sk_buff *skb,
 		      const struct net_device *in,
@@ -43,12 +43,12 @@
 };
 
 /* Function to register/unregister log function. */
-int nf_log_register(int pf, const struct nf_logger *logger);
+int nf_log_register(u_int8_t pf, const struct nf_logger *logger);
 void nf_log_unregister(const struct nf_logger *logger);
-void nf_log_unregister_pf(int pf);
+void nf_log_unregister_pf(u_int8_t pf);
 
 /* Calls the registered backend logging function */
-void nf_log_packet(int pf,
+void nf_log_packet(u_int8_t pf,
 		   unsigned int hooknum,
 		   const struct sk_buff *skb,
 		   const struct net_device *in,
diff --git a/include/net/netfilter/nf_queue.h b/include/net/netfilter/nf_queue.h
index d030044..252fd10 100644
--- a/include/net/netfilter/nf_queue.h
+++ b/include/net/netfilter/nf_queue.h
@@ -8,7 +8,7 @@
 	unsigned int		id;
 
 	struct nf_hook_ops	*elem;
-	int			pf;
+	u_int8_t		pf;
 	unsigned int		hook;
 	struct net_device	*indev;
 	struct net_device	*outdev;
@@ -24,9 +24,9 @@
 	char			*name;
 };
 
-extern int nf_register_queue_handler(int pf,
+extern int nf_register_queue_handler(u_int8_t pf,
 				     const struct nf_queue_handler *qh);
-extern int nf_unregister_queue_handler(int pf,
+extern int nf_unregister_queue_handler(u_int8_t pf,
 				       const struct nf_queue_handler *qh);
 extern void nf_unregister_queue_handlers(const struct nf_queue_handler *qh);
 extern void nf_reinject(struct nf_queue_entry *entry, unsigned int verdict);
diff --git a/include/net/netfilter/nf_tproxy_core.h b/include/net/netfilter/nf_tproxy_core.h
new file mode 100644
index 0000000..208b46f
--- /dev/null
+++ b/include/net/netfilter/nf_tproxy_core.h
@@ -0,0 +1,32 @@
+#ifndef _NF_TPROXY_CORE_H
+#define _NF_TPROXY_CORE_H
+
+#include <linux/types.h>
+#include <linux/in.h>
+#include <linux/skbuff.h>
+#include <net/sock.h>
+#include <net/inet_sock.h>
+#include <net/tcp.h>
+
+/* look up and get a reference to a matching socket */
+extern struct sock *
+nf_tproxy_get_sock_v4(struct net *net, const u8 protocol,
+		      const __be32 saddr, const __be32 daddr,
+		      const __be16 sport, const __be16 dport,
+		      const struct net_device *in, bool listening);
+
+static inline void
+nf_tproxy_put_sock(struct sock *sk)
+{
+	/* TIME_WAIT inet sockets have to be handled differently */
+	if ((sk->sk_protocol == IPPROTO_TCP) && (sk->sk_state == TCP_TIME_WAIT))
+		inet_twsk_put(inet_twsk(sk));
+	else
+		sock_put(sk);
+}
+
+/* assign a socket to the skb -- consumes sk */
+int
+nf_tproxy_assign_sock(struct sk_buff *skb, struct sock *sk);
+
+#endif
diff --git a/include/net/netlabel.h b/include/net/netlabel.h
index e4d2d6b..17c442a 100644
--- a/include/net/netlabel.h
+++ b/include/net/netlabel.h
@@ -9,7 +9,7 @@
  */
 
 /*
- * (c) Copyright Hewlett-Packard Development Company, L.P., 2006
+ * (c) Copyright Hewlett-Packard Development Company, L.P., 2006, 2008
  *
  * This program is free software;  you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -72,8 +72,10 @@
 /* NetLabel NETLINK protocol version
  *  1: initial version
  *  2: added static labels for unlabeled connections
+ *  3: network selectors added to the NetLabel/LSM domain mapping and the
+ *     CIPSO_V4_MAP_LOCAL CIPSO mapping was added
  */
-#define NETLBL_PROTO_VERSION            2
+#define NETLBL_PROTO_VERSION            3
 
 /* NetLabel NETLINK types/families */
 #define NETLBL_NLTYPE_NONE              0
@@ -87,6 +89,8 @@
 #define NETLBL_NLTYPE_CIPSOV6_NAME      "NLBL_CIPSOv6"
 #define NETLBL_NLTYPE_UNLABELED         5
 #define NETLBL_NLTYPE_UNLABELED_NAME    "NLBL_UNLBL"
+#define NETLBL_NLTYPE_ADDRSELECT        6
+#define NETLBL_NLTYPE_ADDRSELECT_NAME   "NLBL_ADRSEL"
 
 /*
  * NetLabel - Kernel API for accessing the network packet label mappings.
@@ -200,7 +204,7 @@
 	u32 type;
 	char *domain;
 	struct netlbl_lsm_cache *cache;
-	union {
+	struct {
 		struct {
 			struct netlbl_lsm_secattr_catmap *cat;
 			u32 lvl;
@@ -352,12 +356,9 @@
 int netlbl_cfg_map_del(const char *domain, struct netlbl_audit *audit_info);
 int netlbl_cfg_unlbl_add_map(const char *domain,
 			     struct netlbl_audit *audit_info);
-int netlbl_cfg_cipsov4_add(struct cipso_v4_doi *doi_def,
-			   struct netlbl_audit *audit_info);
 int netlbl_cfg_cipsov4_add_map(struct cipso_v4_doi *doi_def,
 			       const char *domain,
 			       struct netlbl_audit *audit_info);
-int netlbl_cfg_cipsov4_del(u32 doi, struct netlbl_audit *audit_info);
 
 /*
  * LSM security attribute operations
@@ -380,12 +381,19 @@
 int netlbl_enabled(void);
 int netlbl_sock_setattr(struct sock *sk,
 			const struct netlbl_lsm_secattr *secattr);
+void netlbl_sock_delattr(struct sock *sk);
 int netlbl_sock_getattr(struct sock *sk,
 			struct netlbl_lsm_secattr *secattr);
+int netlbl_conn_setattr(struct sock *sk,
+			struct sockaddr *addr,
+			const struct netlbl_lsm_secattr *secattr);
+int netlbl_skbuff_setattr(struct sk_buff *skb,
+			  u16 family,
+			  const struct netlbl_lsm_secattr *secattr);
 int netlbl_skbuff_getattr(const struct sk_buff *skb,
 			  u16 family,
 			  struct netlbl_lsm_secattr *secattr);
-void netlbl_skbuff_err(struct sk_buff *skb, int error);
+void netlbl_skbuff_err(struct sk_buff *skb, int error, int gateway);
 
 /*
  * LSM label mapping cache operations
@@ -404,22 +412,12 @@
 {
 	return -ENOSYS;
 }
-static inline int netlbl_cfg_cipsov4_add(struct cipso_v4_doi *doi_def,
-					 struct netlbl_audit *audit_info)
-{
-	return -ENOSYS;
-}
 static inline int netlbl_cfg_cipsov4_add_map(struct cipso_v4_doi *doi_def,
 					     const char *domain,
 					     struct netlbl_audit *audit_info)
 {
 	return -ENOSYS;
 }
-static inline int netlbl_cfg_cipsov4_del(u32 doi,
-					 struct netlbl_audit *audit_info)
-{
-	return -ENOSYS;
-}
 static inline int netlbl_secattr_catmap_walk(
 	                              struct netlbl_lsm_secattr_catmap *catmap,
 				      u32 offset)
@@ -456,18 +454,35 @@
 {
 	return -ENOSYS;
 }
+static inline void netlbl_sock_delattr(struct sock *sk)
+{
+}
 static inline int netlbl_sock_getattr(struct sock *sk,
 				      struct netlbl_lsm_secattr *secattr)
 {
 	return -ENOSYS;
 }
+static inline int netlbl_conn_setattr(struct sock *sk,
+				      struct sockaddr *addr,
+				      const struct netlbl_lsm_secattr *secattr)
+{
+	return -ENOSYS;
+}
+static inline int netlbl_skbuff_setattr(struct sk_buff *skb,
+				      u16 family,
+				      const struct netlbl_lsm_secattr *secattr)
+{
+	return -ENOSYS;
+}
 static inline int netlbl_skbuff_getattr(const struct sk_buff *skb,
 					u16 family,
 					struct netlbl_lsm_secattr *secattr)
 {
 	return -ENOSYS;
 }
-static inline void netlbl_skbuff_err(struct sk_buff *skb, int error)
+static inline void netlbl_skbuff_err(struct sk_buff *skb,
+				     int error,
+				     int gateway)
 {
 	return;
 }
diff --git a/include/net/netlink.h b/include/net/netlink.h
index 208fe5a..3643bbb 100644
--- a/include/net/netlink.h
+++ b/include/net/netlink.h
@@ -119,9 +119,6 @@
  * Nested Attributes Construction:
  *   nla_nest_start(skb, type)		start a nested attribute
  *   nla_nest_end(skb, nla)		finalize a nested attribute
- *   nla_nest_compat_start(skb, type,	start a nested compat attribute
- *			   len, data)
- *   nla_nest_compat_end(skb, type)	finalize a nested compat attribute
  *   nla_nest_cancel(skb, nla)		cancel nested attribute construction
  *
  * Attribute Length Calculations:
@@ -156,7 +153,6 @@
  *   nla_find_nested()			find attribute in nested attributes
  *   nla_parse()			parse and validate stream of attrs
  *   nla_parse_nested()			parse nested attribuets
- *   nla_parse_nested_compat()		parse nested compat attributes
  *   nla_for_each_attr()		loop over all attributes
  *   nla_for_each_nested()		loop over the nested attributes
  *=========================================================================
@@ -752,39 +748,6 @@
 }
 
 /**
- * nla_parse_nested_compat - parse nested compat attributes
- * @tb: destination array with maxtype+1 elements
- * @maxtype: maximum attribute type to be expected
- * @nla: attribute containing the nested attributes
- * @data: pointer to point to contained structure
- * @len: length of contained structure
- * @policy: validation policy
- *
- * Parse a nested compat attribute. The compat attribute contains a structure
- * and optionally a set of nested attributes. On success the data pointer
- * points to the nested data and tb contains the parsed attributes
- * (see nla_parse).
- */
-static inline int __nla_parse_nested_compat(struct nlattr *tb[], int maxtype,
-					    struct nlattr *nla,
-					    const struct nla_policy *policy,
-					    int len)
-{
-	int nested_len = nla_len(nla) - NLA_ALIGN(len);
-
-	if (nested_len < 0)
-		return -EINVAL;
-	if (nested_len >= nla_attr_size(0))
-		return nla_parse(tb, maxtype, nla_data(nla) + NLA_ALIGN(len),
-				 nested_len, policy);
-	memset(tb, 0, sizeof(struct nlattr *) * (maxtype + 1));
-	return 0;
-}
-
-#define nla_parse_nested_compat(tb, maxtype, nla, policy, data, len) \
-({	data = nla_len(nla) >= len ? nla_data(nla) : NULL; \
-	__nla_parse_nested_compat(tb, maxtype, nla, policy, len); })
-/**
  * nla_put_u8 - Add a u8 netlink attribute to a socket buffer
  * @skb: socket buffer to add attribute to
  * @attrtype: attribute type
@@ -1031,51 +994,6 @@
 }
 
 /**
- * nla_nest_compat_start - Start a new level of nested compat attributes
- * @skb: socket buffer to add attributes to
- * @attrtype: attribute type of container
- * @attrlen: length of structure
- * @data: pointer to structure
- *
- * Start a nested compat attribute that contains both a structure and
- * a set of nested attributes.
- *
- * Returns the container attribute
- */
-static inline struct nlattr *nla_nest_compat_start(struct sk_buff *skb,
-						   int attrtype, int attrlen,
-						   const void *data)
-{
-	struct nlattr *start = (struct nlattr *)skb_tail_pointer(skb);
-
-	if (nla_put(skb, attrtype, attrlen, data) < 0)
-		return NULL;
-	if (nla_nest_start(skb, attrtype) == NULL) {
-		nlmsg_trim(skb, start);
-		return NULL;
-	}
-	return start;
-}
-
-/**
- * nla_nest_compat_end - Finalize nesting of compat attributes
- * @skb: socket buffer the attributes are stored in
- * @start: container attribute
- *
- * Corrects the container attribute header to include the all
- * appeneded attributes.
- *
- * Returns the total data length of the skb.
- */
-static inline int nla_nest_compat_end(struct sk_buff *skb, struct nlattr *start)
-{
-	struct nlattr *nest = (void *)start + NLMSG_ALIGN(start->nla_len);
-
-	start->nla_len = skb_tail_pointer(skb) - (unsigned char *)start;
-	return nla_nest_end(skb, nest);
-}
-
-/**
  * nla_nest_cancel - Cancel nesting of attributes
  * @skb: socket buffer the message is stored in
  * @start: container attribute
diff --git a/include/net/netns/conntrack.h b/include/net/netns/conntrack.h
new file mode 100644
index 0000000..f4498a6
--- /dev/null
+++ b/include/net/netns/conntrack.h
@@ -0,0 +1,30 @@
+#ifndef __NETNS_CONNTRACK_H
+#define __NETNS_CONNTRACK_H
+
+#include <linux/list.h>
+#include <asm/atomic.h>
+
+struct ctl_table_header;
+struct nf_conntrack_ecache;
+
+struct netns_ct {
+	atomic_t		count;
+	unsigned int		expect_count;
+	struct hlist_head	*hash;
+	struct hlist_head	*expect_hash;
+	struct hlist_head	unconfirmed;
+	struct ip_conntrack_stat *stat;
+#ifdef CONFIG_NF_CONNTRACK_EVENTS
+	struct nf_conntrack_ecache *ecache;
+#endif
+	int			sysctl_acct;
+	int			sysctl_checksum;
+	unsigned int		sysctl_log_invalid; /* Log invalid packets */
+#ifdef CONFIG_SYSCTL
+	struct ctl_table_header	*sysctl_header;
+	struct ctl_table_header	*acct_sysctl_header;
+#endif
+	int			hash_vmalloc;
+	int			expect_vmalloc;
+};
+#endif
diff --git a/include/net/netns/ipv4.h b/include/net/netns/ipv4.h
index a6ed838..ece1c92 100644
--- a/include/net/netns/ipv4.h
+++ b/include/net/netns/ipv4.h
@@ -38,6 +38,9 @@
 	struct xt_table		*iptable_raw;
 	struct xt_table		*arptable_filter;
 	struct xt_table		*iptable_security;
+	struct xt_table		*nat_table;
+	struct hlist_head	*nat_bysource;
+	int			nat_vmalloced;
 #endif
 
 	int sysctl_icmp_echo_ignore_all;
diff --git a/include/net/netns/mib.h b/include/net/netns/mib.h
index 4491476..10cb7c3 100644
--- a/include/net/netns/mib.h
+++ b/include/net/netns/mib.h
@@ -11,6 +11,15 @@
 	DEFINE_SNMP_STAT(struct udp_mib, udplite_statistics);
 	DEFINE_SNMP_STAT(struct icmp_mib, icmp_statistics);
 	DEFINE_SNMP_STAT(struct icmpmsg_mib, icmpmsg_statistics);
+
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+	struct proc_dir_entry *proc_net_devsnmp6;
+	DEFINE_SNMP_STAT(struct udp_mib, udp_stats_in6);
+	DEFINE_SNMP_STAT(struct udp_mib, udplite_stats_in6);
+	DEFINE_SNMP_STAT(struct ipstats_mib, ipv6_statistics);
+	DEFINE_SNMP_STAT(struct icmpv6_mib, icmpv6_statistics);
+	DEFINE_SNMP_STAT(struct icmpv6msg_mib, icmpv6msg_statistics);
+#endif
 };
 
 #endif
diff --git a/include/net/phonet/gprs.h b/include/net/phonet/gprs.h
new file mode 100644
index 0000000..928daf5
--- /dev/null
+++ b/include/net/phonet/gprs.h
@@ -0,0 +1,38 @@
+/*
+ * File: pep_gprs.h
+ *
+ * GPRS over Phonet pipe end point socket
+ *
+ * Copyright (C) 2008 Nokia Corporation.
+ *
+ * Author: Rémi Denis-Courmont <remi.denis-courmont@nokia.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.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#ifndef NET_PHONET_GPRS_H
+#define NET_PHONET_GPRS_H
+
+struct sock;
+struct sk_buff;
+
+int pep_writeable(struct sock *sk);
+int pep_write(struct sock *sk, struct sk_buff *skb);
+struct sk_buff *pep_read(struct sock *sk);
+
+int gprs_attach(struct sock *sk);
+void gprs_detach(struct sock *sk);
+
+#endif
diff --git a/include/net/phonet/pep.h b/include/net/phonet/pep.h
new file mode 100644
index 0000000..fcd7930
--- /dev/null
+++ b/include/net/phonet/pep.h
@@ -0,0 +1,160 @@
+/*
+ * File: pep.h
+ *
+ * Phonet Pipe End Point sockets definitions
+ *
+ * Copyright (C) 2008 Nokia Corporation.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#ifndef NET_PHONET_PEP_H
+#define NET_PHONET_PEP_H
+
+struct pep_sock {
+	struct pn_sock		pn_sk;
+
+	/* XXX: union-ify listening vs connected stuff ? */
+	/* Listening socket stuff: */
+	struct hlist_head	ackq;
+	struct hlist_head	hlist;
+
+	/* Connected socket stuff: */
+	struct sock		*listener;
+	struct sk_buff_head	ctrlreq_queue;
+#define PNPIPE_CTRLREQ_MAX	10
+	int			ifindex;
+	u16			peer_type;	/* peer type/subtype */
+	u8			pipe_handle;
+
+	u8			rx_credits;
+	u8			tx_credits;
+	u8			rx_fc;	/* RX flow control */
+	u8			tx_fc;	/* TX flow control */
+	u8			init_enable;	/* auto-enable at creation */
+};
+
+static inline struct pep_sock *pep_sk(struct sock *sk)
+{
+	return (struct pep_sock *)sk;
+}
+
+extern const struct proto_ops phonet_stream_ops;
+
+/* Pipe protocol definitions */
+struct pnpipehdr {
+	u8			utid; /* transaction ID */
+	u8			message_id;
+	u8			pipe_handle;
+	union {
+		u8		state_after_connect;	/* connect request */
+		u8		state_after_reset;	/* reset request */
+		u8		error_code;		/* any response */
+		u8		pep_type;		/* status indication */
+		u8		data[1];
+	};
+};
+#define other_pep_type		data[1]
+
+static inline struct pnpipehdr *pnp_hdr(struct sk_buff *skb)
+{
+	return (struct pnpipehdr *)skb_transport_header(skb);
+}
+
+#define MAX_PNPIPE_HEADER (MAX_PHONET_HEADER + 4)
+
+enum {
+	PNS_PIPE_DATA = 0x20,
+
+	PNS_PEP_CONNECT_REQ = 0x40,
+	PNS_PEP_CONNECT_RESP,
+	PNS_PEP_DISCONNECT_REQ,
+	PNS_PEP_DISCONNECT_RESP,
+	PNS_PEP_RESET_REQ,
+	PNS_PEP_RESET_RESP,
+	PNS_PEP_ENABLE_REQ,
+	PNS_PEP_ENABLE_RESP,
+	PNS_PEP_CTRL_REQ,
+	PNS_PEP_CTRL_RESP,
+	PNS_PEP_DISABLE_REQ = 0x4C,
+	PNS_PEP_DISABLE_RESP,
+
+	PNS_PEP_STATUS_IND = 0x60,
+	PNS_PIPE_CREATED_IND,
+	PNS_PIPE_RESET_IND = 0x63,
+	PNS_PIPE_ENABLED_IND,
+	PNS_PIPE_REDIRECTED_IND,
+	PNS_PIPE_DISABLED_IND = 0x66,
+};
+
+#define PN_PIPE_INVALID_HANDLE	0xff
+#define PN_PEP_TYPE_COMMON	0x00
+
+/* Phonet pipe status indication */
+enum {
+	PN_PEP_IND_FLOW_CONTROL,
+	PN_PEP_IND_ID_MCFC_GRANT_CREDITS,
+};
+
+/* Phonet pipe error codes */
+enum {
+	PN_PIPE_NO_ERROR,
+	PN_PIPE_ERR_INVALID_PARAM,
+	PN_PIPE_ERR_INVALID_HANDLE,
+	PN_PIPE_ERR_INVALID_CTRL_ID,
+	PN_PIPE_ERR_NOT_ALLOWED,
+	PN_PIPE_ERR_PEP_IN_USE,
+	PN_PIPE_ERR_OVERLOAD,
+	PN_PIPE_ERR_DEV_DISCONNECTED,
+	PN_PIPE_ERR_TIMEOUT,
+	PN_PIPE_ERR_ALL_PIPES_IN_USE,
+	PN_PIPE_ERR_GENERAL,
+	PN_PIPE_ERR_NOT_SUPPORTED,
+};
+
+/* Phonet pipe states */
+enum {
+	PN_PIPE_DISABLE,
+	PN_PIPE_ENABLE,
+};
+
+/* Phonet pipe sub-block types */
+enum {
+	PN_PIPE_SB_CREATE_REQ_PEP_SUB_TYPE,
+	PN_PIPE_SB_CONNECT_REQ_PEP_SUB_TYPE,
+	PN_PIPE_SB_REDIRECT_REQ_PEP_SUB_TYPE,
+	PN_PIPE_SB_NEGOTIATED_FC,
+	PN_PIPE_SB_REQUIRED_FC_TX,
+	PN_PIPE_SB_PREFERRED_FC_RX,
+};
+
+/* Phonet pipe flow control models */
+enum {
+	PN_NO_FLOW_CONTROL,
+	PN_LEGACY_FLOW_CONTROL,
+	PN_ONE_CREDIT_FLOW_CONTROL,
+	PN_MULTI_CREDIT_FLOW_CONTROL,
+};
+
+#define pn_flow_safe(fc) ((fc) >> 1)
+
+/* Phonet pipe flow control states */
+enum {
+	PEP_IND_EMPTY,
+	PEP_IND_BUSY,
+	PEP_IND_READY,
+};
+
+#endif
diff --git a/include/net/phonet/phonet.h b/include/net/phonet/phonet.h
new file mode 100644
index 0000000..d4e7250
--- /dev/null
+++ b/include/net/phonet/phonet.h
@@ -0,0 +1,112 @@
+/*
+ * File: af_phonet.h
+ *
+ * Phonet sockets kernel definitions
+ *
+ * Copyright (C) 2008 Nokia Corporation.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#ifndef AF_PHONET_H
+#define AF_PHONET_H
+
+/*
+ * The lower layers may not require more space, ever. Make sure it's
+ * enough.
+ */
+#define MAX_PHONET_HEADER	8
+
+/*
+ * Every Phonet* socket has this structure first in its
+ * protocol-specific structure under name c.
+ */
+struct pn_sock {
+	struct sock	sk;
+	u16		sobject;
+	u8		resource;
+};
+
+static inline struct pn_sock *pn_sk(struct sock *sk)
+{
+	return (struct pn_sock *)sk;
+}
+
+extern const struct proto_ops phonet_dgram_ops;
+
+struct sock *pn_find_sock_by_sa(const struct sockaddr_pn *sa);
+void phonet_get_local_port_range(int *min, int *max);
+void pn_sock_hash(struct sock *sk);
+void pn_sock_unhash(struct sock *sk);
+int pn_sock_get_port(struct sock *sk, unsigned short sport);
+
+int pn_skb_send(struct sock *sk, struct sk_buff *skb,
+		const struct sockaddr_pn *target);
+
+static inline struct phonethdr *pn_hdr(struct sk_buff *skb)
+{
+	return (struct phonethdr *)skb_network_header(skb);
+}
+
+static inline struct phonetmsg *pn_msg(struct sk_buff *skb)
+{
+	return (struct phonetmsg *)skb_transport_header(skb);
+}
+
+/*
+ * Get the other party's sockaddr from received skb. The skb begins
+ * with a Phonet header.
+ */
+static inline
+void pn_skb_get_src_sockaddr(struct sk_buff *skb, struct sockaddr_pn *sa)
+{
+	struct phonethdr *ph = pn_hdr(skb);
+	u16 obj = pn_object(ph->pn_sdev, ph->pn_sobj);
+
+	sa->spn_family = AF_PHONET;
+	pn_sockaddr_set_object(sa, obj);
+	pn_sockaddr_set_resource(sa, ph->pn_res);
+	memset(sa->spn_zero, 0, sizeof(sa->spn_zero));
+}
+
+static inline
+void pn_skb_get_dst_sockaddr(struct sk_buff *skb, struct sockaddr_pn *sa)
+{
+	struct phonethdr *ph = pn_hdr(skb);
+	u16 obj = pn_object(ph->pn_rdev, ph->pn_robj);
+
+	sa->spn_family = AF_PHONET;
+	pn_sockaddr_set_object(sa, obj);
+	pn_sockaddr_set_resource(sa, ph->pn_res);
+	memset(sa->spn_zero, 0, sizeof(sa->spn_zero));
+}
+
+/* Protocols in Phonet protocol family. */
+struct phonet_protocol {
+	const struct proto_ops	*ops;
+	struct proto		*prot;
+	int			sock_type;
+};
+
+int phonet_proto_register(int protocol, struct phonet_protocol *pp);
+void phonet_proto_unregister(int protocol, struct phonet_protocol *pp);
+
+int phonet_sysctl_init(void);
+void phonet_sysctl_exit(void);
+void phonet_netlink_register(void);
+int isi_register(void);
+void isi_unregister(void);
+
+#endif
diff --git a/include/net/phonet/pn_dev.h b/include/net/phonet/pn_dev.h
new file mode 100644
index 0000000..bbd2a83
--- /dev/null
+++ b/include/net/phonet/pn_dev.h
@@ -0,0 +1,50 @@
+/*
+ * File: pn_dev.h
+ *
+ * Phonet network device
+ *
+ * Copyright (C) 2008 Nokia Corporation.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#ifndef PN_DEV_H
+#define PN_DEV_H
+
+struct phonet_device_list {
+	struct list_head list;
+	spinlock_t lock;
+};
+
+extern struct phonet_device_list pndevs;
+
+struct phonet_device {
+	struct list_head list;
+	struct net_device *netdev;
+	DECLARE_BITMAP(addrs, 64);
+};
+
+void phonet_device_init(void);
+void phonet_device_exit(void);
+struct net_device *phonet_device_get(struct net *net);
+
+int phonet_address_add(struct net_device *dev, u8 addr);
+int phonet_address_del(struct net_device *dev, u8 addr);
+u8 phonet_address_get(struct net_device *dev, u8 addr);
+int phonet_address_lookup(u8 addr);
+
+#define PN_NO_ADDR	0xff
+
+#endif
diff --git a/include/net/pkt_sched.h b/include/net/pkt_sched.h
index b786a5b..4082f39 100644
--- a/include/net/pkt_sched.h
+++ b/include/net/pkt_sched.h
@@ -90,10 +90,7 @@
 
 static inline void qdisc_run(struct Qdisc *q)
 {
-	struct netdev_queue *txq = q->dev_queue;
-
-	if (!netif_tx_queue_stopped(txq) &&
-	    !test_and_set_bit(__QDISC_STATE_RUNNING, &q->state))
+	if (!test_and_set_bit(__QDISC_STATE_RUNNING, &q->state))
 		__qdisc_run(q);
 }
 
diff --git a/include/net/route.h b/include/net/route.h
index 4f0d8c1..4e8cae0 100644
--- a/include/net/route.h
+++ b/include/net/route.h
@@ -27,7 +27,7 @@
 #include <net/dst.h>
 #include <net/inetpeer.h>
 #include <net/flow.h>
-#include <net/sock.h>
+#include <net/inet_sock.h>
 #include <linux/in_route.h>
 #include <linux/rtnetlink.h>
 #include <linux/route.h>
@@ -161,6 +161,10 @@
 
 	int err;
 	struct net *net = sock_net(sk);
+
+	if (inet_sk(sk)->transparent)
+		fl.flags |= FLOWI_FLAG_ANYSRC;
+
 	if (!dst || !src) {
 		err = __ip_route_output_key(net, rp, &fl);
 		if (err)
@@ -204,4 +208,9 @@
 	return rt->peer;
 }
 
+static inline int inet_iif(const struct sk_buff *skb)
+{
+	return skb->rtable->rt_iif;
+}
+
 #endif	/* _ROUTE_H */
diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h
index e556962..3fe49d8 100644
--- a/include/net/sch_generic.h
+++ b/include/net/sch_generic.h
@@ -53,6 +53,7 @@
 	atomic_t		refcnt;
 	unsigned long		state;
 	struct sk_buff		*gso_skb;
+	struct sk_buff_head	requeue;
 	struct sk_buff_head	q;
 	struct netdev_queue	*dev_queue;
 	struct Qdisc		*next_sched;
diff --git a/include/net/sctp/constants.h b/include/net/sctp/constants.h
index c32ddf0..b05b055 100644
--- a/include/net/sctp/constants.h
+++ b/include/net/sctp/constants.h
@@ -261,7 +261,9 @@
  * must be less than 65535 (2^16 - 1), or we will have overflow
  * problems creating SACK's.
  */
-#define SCTP_TSN_MAP_SIZE 2048
+#define SCTP_TSN_MAP_INITIAL BITS_PER_LONG
+#define SCTP_TSN_MAP_INCREMENT SCTP_TSN_MAP_INITIAL
+#define SCTP_TSN_MAP_SIZE 4096
 #define SCTP_TSN_MAX_GAP  65535
 
 /* We will not record more than this many duplicate TSNs between two
diff --git a/include/net/sctp/sctp.h b/include/net/sctp/sctp.h
index 17b932b..703305d 100644
--- a/include/net/sctp/sctp.h
+++ b/include/net/sctp/sctp.h
@@ -406,10 +406,7 @@
 
 /* A macro to walk a list of skbs.  */
 #define sctp_skb_for_each(pos, head, tmp) \
-for (pos = (head)->next;\
-     tmp = (pos)->next, pos != ((struct sk_buff *)(head));\
-     pos = tmp)
-
+	skb_queue_walk_safe(head, pos, tmp)
 
 /* A helper to append an entire skb list (list) to another (head). */
 static inline void sctp_skb_list_tail(struct sk_buff_head *list,
@@ -420,10 +417,7 @@
 	sctp_spin_lock_irqsave(&head->lock, flags);
 	sctp_spin_lock(&list->lock);
 
-	list_splice((struct list_head *)list, (struct list_head *)head->prev);
-
-	head->qlen += list->qlen;
-	list->qlen = 0;
+	skb_queue_splice_tail_init(list, head);
 
 	sctp_spin_unlock(&list->lock);
 	sctp_spin_unlock_irqrestore(&head->lock, flags);
diff --git a/include/net/sctp/sm.h b/include/net/sctp/sm.h
index 2481173..029a54a 100644
--- a/include/net/sctp/sm.h
+++ b/include/net/sctp/sm.h
@@ -227,6 +227,9 @@
 				   const struct sctp_chunk *,
 				   const __u8 *,
 				   const size_t );
+struct sctp_chunk *sctp_make_violation_paramlen(const struct sctp_association *,
+				   const struct sctp_chunk *,
+				   struct sctp_paramhdr *);
 struct sctp_chunk *sctp_make_heartbeat(const struct sctp_association *,
 				  const struct sctp_transport *,
 				  const void *payload,
diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h
index ab1c472..9661d7b 100644
--- a/include/net/sctp/structs.h
+++ b/include/net/sctp/structs.h
@@ -731,20 +731,23 @@
 	 */
 	struct sk_buff *auth_chunk;
 
-	__u8 rtt_in_progress;	/* Is this chunk used for RTT calculation? */
-	__u8 resent;		/* Has this chunk ever been retransmitted. */
-	__u8 has_tsn;		/* Does this chunk have a TSN yet? */
-	__u8 has_ssn;		/* Does this chunk have a SSN yet? */
-	__u8 singleton;		/* Was this the only chunk in the packet? */
-	__u8 end_of_packet;	/* Was this the last chunk in the packet? */
-	__u8 ecn_ce_done;	/* Have we processed the ECN CE bit? */
-	__u8 pdiscard;		/* Discard the whole packet now? */
-	__u8 tsn_gap_acked;	/* Is this chunk acked by a GAP ACK? */
-	__s8 fast_retransmit;	 /* Is this chunk fast retransmitted? */
-	__u8 tsn_missing_report; /* Data chunk missing counter. */
-	__u8 data_accepted; 	/* At least 1 chunk in this packet accepted */
-	__u8 auth;		/* IN: was auth'ed | OUT: needs auth */
-	__u8 has_asconf;	/* IN: have seen an asconf before */
+#define SCTP_CAN_FRTX 0x0
+#define SCTP_NEED_FRTX 0x1
+#define SCTP_DONT_FRTX 0x2
+	__u16	rtt_in_progress:1,	/* This chunk used for RTT calc? */
+		resent:1,		/* Has this chunk ever been resent. */
+		has_tsn:1,		/* Does this chunk have a TSN yet? */
+		has_ssn:1,		/* Does this chunk have a SSN yet? */
+		singleton:1,		/* Only chunk in the packet? */
+		end_of_packet:1,	/* Last chunk in the packet? */
+		ecn_ce_done:1,		/* Have we processed the ECN CE bit? */
+		pdiscard:1,		/* Discard the whole packet now? */
+		tsn_gap_acked:1,	/* Is this chunk acked by a GAP ACK? */
+		data_accepted:1,	/* At least 1 chunk accepted */
+		auth:1,			/* IN: was auth'ed | OUT: needs auth */
+		has_asconf:1,		/* IN: have seen an asconf before */
+		tsn_missing_report:2,	/* Data chunk missing counter. */
+		fast_retransmit:2;	/* Is this chunk fast retransmitted? */
 };
 
 void sctp_chunk_hold(struct sctp_chunk *);
@@ -1225,7 +1228,7 @@
 
 sctp_scope_t sctp_scope(const union sctp_addr *);
 int sctp_in_scope(const union sctp_addr *addr, const sctp_scope_t scope);
-int sctp_is_any(const union sctp_addr *addr);
+int sctp_is_any(struct sock *sk, const union sctp_addr *addr);
 int sctp_addr_is_valid(const union sctp_addr *addr);
 
 
@@ -1542,7 +1545,6 @@
 		 * in tsn_map--we get it by calling sctp_tsnmap_get_ctsn().
 		 */
 		struct sctp_tsnmap tsn_map;
-		__u8 _map[sctp_tsnmap_storage_size(SCTP_TSN_MAP_SIZE)];
 
 		/* Ack State   : This flag indicates if the next received
 		 *             : packet is to be responded to with a
diff --git a/include/net/sctp/tsnmap.h b/include/net/sctp/tsnmap.h
index 099211b..4aabc5a 100644
--- a/include/net/sctp/tsnmap.h
+++ b/include/net/sctp/tsnmap.h
@@ -60,18 +60,7 @@
 	 * It points at one of the two buffers with which we will
 	 * ping-pong between.
 	 */
-	__u8 *tsn_map;
-
-	/* This marks the tsn which overflows the tsn_map, when the
-	 * cumulative ack point reaches this point we know we can switch
-	 * maps (tsn_map and overflow_map swap).
-	 */
-	__u32 overflow_tsn;
-
-	/* This is the overflow array for tsn_map.
-	 * It points at one of the other ping-pong buffers.
-	 */
-	__u8 *overflow_map;
+	unsigned long *tsn_map;
 
 	/* This is the TSN at tsn_map[0].  */
 	__u32 base_tsn;
@@ -89,15 +78,15 @@
 	 */
 	__u32 cumulative_tsn_ack_point;
 
+	/* This is the highest TSN we've marked.  */
+	__u32 max_tsn_seen;
+
 	/* This is the minimum number of TSNs we can track.  This corresponds
 	 * to the size of tsn_map.   Note: the overflow_map allows us to
 	 * potentially track more than this quantity.
 	 */
 	__u16 len;
 
-	/* This is the highest TSN we've marked.  */
-	__u32 max_tsn_seen;
-
 	/* Data chunks pending receipt. used by SCTP_STATUS sockopt */
 	__u16 pending_data;
 
@@ -105,29 +94,19 @@
 	 * every SACK.  Store up to SCTP_MAX_DUP_TSNS worth of
 	 * information.
 	 */
-	__be32 dup_tsns[SCTP_MAX_DUP_TSNS];
 	__u16 num_dup_tsns;
-
-	/* Record gap ack block information here.  */
-	struct sctp_gap_ack_block gabs[SCTP_MAX_GABS];
-
-	int malloced;
-
-	__u8 raw_map[0];
+	__be32 dup_tsns[SCTP_MAX_DUP_TSNS];
 };
 
 struct sctp_tsnmap_iter {
 	__u32 start;
 };
 
-/* This macro assists in creation of external storage for variable length
- * internal buffers.  We double allocate so the overflow map works.
- */
-#define sctp_tsnmap_storage_size(count) (sizeof(__u8) * (count) * 2)
-
 /* Initialize a block of memory as a tsnmap.  */
 struct sctp_tsnmap *sctp_tsnmap_init(struct sctp_tsnmap *, __u16 len,
-				     __u32 initial_tsn);
+				     __u32 initial_tsn, gfp_t gfp);
+
+void sctp_tsnmap_free(struct sctp_tsnmap *map);
 
 /* Test the tracking state of this TSN.
  * Returns:
@@ -138,7 +117,7 @@
 int sctp_tsnmap_check(const struct sctp_tsnmap *, __u32 tsn);
 
 /* Mark this TSN as seen.  */
-void sctp_tsnmap_mark(struct sctp_tsnmap *, __u32 tsn);
+int sctp_tsnmap_mark(struct sctp_tsnmap *, __u32 tsn);
 
 /* Mark this TSN and all lower as seen. */
 void sctp_tsnmap_skip(struct sctp_tsnmap *map, __u32 tsn);
@@ -169,24 +148,16 @@
 }
 
 /* How many gap ack blocks do we have recorded? */
-__u16 sctp_tsnmap_num_gabs(struct sctp_tsnmap *map);
+__u16 sctp_tsnmap_num_gabs(struct sctp_tsnmap *map,
+			   struct sctp_gap_ack_block *gabs);
 
 /* Refresh the count on pending data. */
 __u16 sctp_tsnmap_pending(struct sctp_tsnmap *map);
 
-/* Return pointer to gap ack blocks as needed by SACK. */
-static inline struct sctp_gap_ack_block *sctp_tsnmap_get_gabs(struct sctp_tsnmap *map)
-{
-	return map->gabs;
-}
-
 /* Is there a gap in the TSN map?  */
 static inline int sctp_tsnmap_has_gap(const struct sctp_tsnmap *map)
 {
-	int has_gap;
-
-	has_gap = (map->cumulative_tsn_ack_point != map->max_tsn_seen);
-	return has_gap;
+	return (map->cumulative_tsn_ack_point != map->max_tsn_seen);
 }
 
 /* Mark a duplicate TSN.  Note:  limit the storage of duplicate TSN
diff --git a/include/net/sock.h b/include/net/sock.h
index 06c5259..ada50c0 100644
--- a/include/net/sock.h
+++ b/include/net/sock.h
@@ -482,6 +482,11 @@
 	skb->next = NULL;
 }
 
+static inline int sk_backlog_rcv(struct sock *sk, struct sk_buff *skb)
+{
+	return sk->sk_backlog_rcv(sk, skb);
+}
+
 #define sk_wait_event(__sk, __timeo, __condition)			\
 	({	int __rc;						\
 		release_sock(__sk);					\
@@ -532,6 +537,7 @@
 	int			(*getsockopt)(struct sock *sk, int level, 
 					int optname, char __user *optval, 
 					int __user *option);  	 
+#ifdef CONFIG_COMPAT
 	int			(*compat_setsockopt)(struct sock *sk,
 					int level,
 					int optname, char __user *optval,
@@ -540,6 +546,7 @@
 					int level,
 					int optname, char __user *optval,
 					int __user *option);
+#endif
 	int			(*sendmsg)(struct kiocb *iocb, struct sock *sk,
 					   struct msghdr *msg, size_t len);
 	int			(*recvmsg)(struct kiocb *iocb, struct sock *sk,
@@ -1322,6 +1329,18 @@
 	sock_net_set(sk, hold_net(net));
 }
 
+static inline struct sock *skb_steal_sock(struct sk_buff *skb)
+{
+	if (unlikely(skb->sk)) {
+		struct sock *sk = skb->sk;
+
+		skb->destructor = NULL;
+		skb->sk = NULL;
+		return sk;
+	}
+	return NULL;
+}
+
 extern void sock_enable_timestamp(struct sock *sk);
 extern int sock_get_timestamp(struct sock *, struct timeval __user *);
 extern int sock_get_timestampns(struct sock *, struct timespec __user *);
diff --git a/include/net/tc_act/tc_skbedit.h b/include/net/tc_act/tc_skbedit.h
new file mode 100644
index 0000000..6abb3ed
--- /dev/null
+++ b/include/net/tc_act/tc_skbedit.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2008, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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.
+ *
+ * Author: Alexander Duyck <alexander.h.duyck@intel.com>
+ */
+
+#ifndef __NET_TC_SKBEDIT_H
+#define __NET_TC_SKBEDIT_H
+
+#include <net/act_api.h>
+
+struct tcf_skbedit {
+	struct tcf_common	common;
+	u32			flags;
+	u32     		priority;
+	u16			queue_mapping;
+};
+#define to_skbedit(pc) \
+	container_of(pc, struct tcf_skbedit, common)
+
+#endif /* __NET_TC_SKBEDIT_H */
diff --git a/include/net/tcp.h b/include/net/tcp.h
index 8983386..438014d 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -472,6 +472,8 @@
 
 /* tcp_input.c */
 extern void tcp_cwnd_application_limited(struct sock *sk);
+extern void tcp_skb_mark_lost_uncond_verify(struct tcp_sock *tp,
+					    struct sk_buff *skb);
 
 /* tcp_timer.c */
 extern void tcp_init_xmit_timers(struct sock *);
@@ -894,7 +896,7 @@
 			BUG_ON(sock_owned_by_user(sk));
 
 			while ((skb1 = __skb_dequeue(&tp->ucopy.prequeue)) != NULL) {
-				sk->sk_backlog_rcv(sk, skb1);
+				sk_backlog_rcv(sk, skb1);
 				NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPPREQUEUEDROPPED);
 			}
 
@@ -974,6 +976,7 @@
 	ireq->acked = 0;
 	ireq->ecn_ok = 0;
 	ireq->rmt_port = tcp_hdr(skb)->source;
+	ireq->loc_port = tcp_hdr(skb)->dest;
 }
 
 extern void tcp_enter_memory_pressure(struct sock *sk);
@@ -1039,13 +1042,12 @@
 {
 	tp->lost_skb_hint = NULL;
 	tp->scoreboard_skb_hint = NULL;
-	tp->retransmit_skb_hint = NULL;
-	tp->forward_skb_hint = NULL;
 }
 
 static inline void tcp_clear_all_retrans_hints(struct tcp_sock *tp)
 {
 	tcp_clear_retrans_hints_partial(tp);
+	tp->retransmit_skb_hint = NULL;
 }
 
 /* MD5 Signature */
@@ -1180,49 +1182,45 @@
 
 static inline struct sk_buff *tcp_write_queue_head(struct sock *sk)
 {
-	struct sk_buff *skb = sk->sk_write_queue.next;
-	if (skb == (struct sk_buff *) &sk->sk_write_queue)
-		return NULL;
-	return skb;
+	return skb_peek(&sk->sk_write_queue);
 }
 
 static inline struct sk_buff *tcp_write_queue_tail(struct sock *sk)
 {
-	struct sk_buff *skb = sk->sk_write_queue.prev;
-	if (skb == (struct sk_buff *) &sk->sk_write_queue)
-		return NULL;
-	return skb;
+	return skb_peek_tail(&sk->sk_write_queue);
 }
 
 static inline struct sk_buff *tcp_write_queue_next(struct sock *sk, struct sk_buff *skb)
 {
-	return skb->next;
+	return skb_queue_next(&sk->sk_write_queue, skb);
 }
 
 #define tcp_for_write_queue(skb, sk)					\
-		for (skb = (sk)->sk_write_queue.next;			\
-		     (skb != (struct sk_buff *)&(sk)->sk_write_queue);	\
-		     skb = skb->next)
+	skb_queue_walk(&(sk)->sk_write_queue, skb)
 
 #define tcp_for_write_queue_from(skb, sk)				\
-		for (; (skb != (struct sk_buff *)&(sk)->sk_write_queue);\
-		     skb = skb->next)
+	skb_queue_walk_from(&(sk)->sk_write_queue, skb)
 
 #define tcp_for_write_queue_from_safe(skb, tmp, sk)			\
-		for (tmp = skb->next;					\
-		     (skb != (struct sk_buff *)&(sk)->sk_write_queue);	\
-		     skb = tmp, tmp = skb->next)
+	skb_queue_walk_from_safe(&(sk)->sk_write_queue, skb, tmp)
 
 static inline struct sk_buff *tcp_send_head(struct sock *sk)
 {
 	return sk->sk_send_head;
 }
 
+static inline bool tcp_skb_is_last(const struct sock *sk,
+				   const struct sk_buff *skb)
+{
+	return skb_queue_is_last(&sk->sk_write_queue, skb);
+}
+
 static inline void tcp_advance_send_head(struct sock *sk, struct sk_buff *skb)
 {
-	sk->sk_send_head = skb->next;
-	if (sk->sk_send_head == (struct sk_buff *)&sk->sk_write_queue)
+	if (tcp_skb_is_last(sk, skb))
 		sk->sk_send_head = NULL;
+	else
+		sk->sk_send_head = tcp_write_queue_next(sk, skb);
 }
 
 static inline void tcp_check_send_head(struct sock *sk, struct sk_buff *skb_unlinked)
@@ -1267,12 +1265,12 @@
 	__skb_queue_after(&sk->sk_write_queue, skb, buff);
 }
 
-/* Insert skb between prev and next on the write queue of sk.  */
+/* Insert new before skb on the write queue of sk.  */
 static inline void tcp_insert_write_queue_before(struct sk_buff *new,
 						  struct sk_buff *skb,
 						  struct sock *sk)
 {
-	__skb_insert(new, skb->prev, skb, &sk->sk_write_queue);
+	__skb_queue_before(&sk->sk_write_queue, skb, new);
 
 	if (sk->sk_send_head == skb)
 		sk->sk_send_head = new;
@@ -1283,12 +1281,6 @@
 	__skb_unlink(skb, &sk->sk_write_queue);
 }
 
-static inline int tcp_skb_is_last(const struct sock *sk,
-				  const struct sk_buff *skb)
-{
-	return skb->next == (struct sk_buff *)&sk->sk_write_queue;
-}
-
 static inline int tcp_write_queue_empty(struct sock *sk)
 {
 	return skb_queue_empty(&sk->sk_write_queue);
diff --git a/include/net/udp.h b/include/net/udp.h
index addcdc6..1e20509 100644
--- a/include/net/udp.h
+++ b/include/net/udp.h
@@ -148,10 +148,9 @@
 				   char __user *optval, int optlen,
 				   int (*push_pending_frames)(struct sock *));
 
-DECLARE_SNMP_STAT(struct udp_mib, udp_stats_in6);
-
-/* UDP-Lite does not have a standardized MIB yet, so we inherit from UDP */
-DECLARE_SNMP_STAT(struct udp_mib, udplite_stats_in6);
+extern struct sock *udp4_lib_lookup(struct net *net, __be32 saddr, __be16 sport,
+				    __be32 daddr, __be16 dport,
+				    int dif);
 
 /*
  * 	SNMP statistics for UDP and UDP-Lite
@@ -163,12 +162,14 @@
 	if (is_udplite) SNMP_INC_STATS_BH((net)->mib.udplite_statistics, field);         \
 	else		SNMP_INC_STATS_BH((net)->mib.udp_statistics, field);    }  while(0)
 
-#define UDP6_INC_STATS_BH(net, field, is_udplite) 	    do { (void)net;  \
-	if (is_udplite) SNMP_INC_STATS_BH(udplite_stats_in6, field);         \
-	else		SNMP_INC_STATS_BH(udp_stats_in6, field);    } while(0)
-#define UDP6_INC_STATS_USER(net, field, is_udplite)	    do { (void)net;    \
-	if (is_udplite) SNMP_INC_STATS_USER(udplite_stats_in6, field);         \
-	else		SNMP_INC_STATS_USER(udp_stats_in6, field);    } while(0)
+#define UDP6_INC_STATS_BH(net, field, is_udplite) 	    do { \
+	if (is_udplite) SNMP_INC_STATS_BH((net)->mib.udplite_stats_in6, field);\
+	else		SNMP_INC_STATS_BH((net)->mib.udp_stats_in6, field);  \
+} while(0)
+#define UDP6_INC_STATS_USER(net, field, __lite)		    do { \
+	if (__lite) SNMP_INC_STATS_USER((net)->mib.udplite_stats_in6, field);  \
+	else	    SNMP_INC_STATS_USER((net)->mib.udp_stats_in6, field);      \
+} while(0)
 
 #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
 #define UDPX_INC_STATS_BH(sk, field) \
diff --git a/include/net/wireless.h b/include/net/wireless.h
index 9324f8d..721efb3 100644
--- a/include/net/wireless.h
+++ b/include/net/wireless.h
@@ -60,6 +60,7 @@
  * with cfg80211.
  *
  * @center_freq: center frequency in MHz
+ * @max_bandwidth: maximum allowed bandwidth for this channel, in MHz
  * @hw_value: hardware-specific value for the channel
  * @flags: channel flags from &enum ieee80211_channel_flags.
  * @orig_flags: channel flags at registration time, used by regulatory
@@ -73,6 +74,7 @@
 struct ieee80211_channel {
 	enum ieee80211_band band;
 	u16 center_freq;
+	u8 max_bandwidth;
 	u16 hw_value;
 	u32 flags;
 	int max_antenna_gain;
@@ -178,6 +180,7 @@
  * struct wiphy - wireless hardware description
  * @idx: the wiphy index assigned to this item
  * @class_dev: the class device representing /sys/class/ieee80211/<wiphy-name>
+ * @reg_notifier: the driver's regulatory notification callback
  */
 struct wiphy {
 	/* assign these fields before you register the wiphy */
@@ -185,6 +188,9 @@
 	/* permanent MAC address */
 	u8 perm_addr[ETH_ALEN];
 
+	/* Supported interface modes, OR together BIT(NL80211_IFTYPE_...) */
+	u16 interface_modes;
+
 	/* If multiple wiphys are registered and you're handed e.g.
 	 * a regular netdev with assigned ieee80211_ptr, you won't
 	 * know whether it points to a wiphy your driver has registered
@@ -194,6 +200,9 @@
 
 	struct ieee80211_supported_band *bands[IEEE80211_NUM_BANDS];
 
+	/* Lets us get back the wiphy on the callback */
+	int (*reg_notifier)(struct wiphy *wiphy, enum reg_set_by setby);
+
 	/* fields below are read-only, assigned by cfg80211 */
 
 	/* the item in /sys/class/ieee80211/ points to this,
@@ -214,9 +223,11 @@
  * the netdev.)
  *
  * @wiphy: pointer to hardware description
+ * @iftype: interface type
  */
 struct wireless_dev {
 	struct wiphy *wiphy;
+	enum nl80211_iftype iftype;
 
 	/* private to the generic wireless code */
 	struct list_head list;
@@ -319,7 +330,6 @@
  */
 extern struct ieee80211_channel *__ieee80211_get_channel(struct wiphy *wiphy,
 							 int freq);
-
 /**
  * ieee80211_get_channel - get channel struct from wiphy for specified frequency
  */
@@ -328,4 +338,57 @@
 {
 	return __ieee80211_get_channel(wiphy, freq);
 }
+
+/**
+ * __regulatory_hint - hint to the wireless core a regulatory domain
+ * @wiphy: if a driver is providing the hint this is the driver's very
+ * 	own &struct wiphy
+ * @alpha2: the ISO/IEC 3166 alpha2 being claimed the regulatory domain
+ * 	should be in. If @rd is set this should be NULL
+ * @rd: a complete regulatory domain, if passed the caller need not worry
+ * 	about freeing it
+ *
+ * The Wireless subsystem can use this function to hint to the wireless core
+ * what it believes should be the current regulatory domain by
+ * giving it an ISO/IEC 3166 alpha2 country code it knows its regulatory
+ * domain should be in or by providing a completely build regulatory domain.
+ *
+ * Returns -EALREADY if *a regulatory domain* has already been set. Note that
+ * this could be by another driver. It is safe for drivers to continue if
+ * -EALREADY is returned, if drivers are not capable of world roaming they
+ * should not register more channels than they support. Right now we only
+ * support listening to the first driver hint. If the driver is capable
+ * of world roaming but wants to respect its own EEPROM mappings for
+ * specific regulatory domains it should register the @reg_notifier callback
+ * on the &struct wiphy. Returns 0 if the hint went through fine or through an
+ * intersection operation. Otherwise a standard error code is returned.
+ *
+ */
+extern int __regulatory_hint(struct wiphy *wiphy, enum reg_set_by set_by,
+		const char *alpha2, struct ieee80211_regdomain *rd);
+/**
+ * regulatory_hint - driver hint to the wireless core a regulatory domain
+ * @wiphy: the driver's very own &struct wiphy
+ * @alpha2: the ISO/IEC 3166 alpha2 the driver claims its regulatory domain
+ * 	should be in. If @rd is set this should be NULL. Note that if you
+ * 	set this to NULL you should still set rd->alpha2 to some accepted
+ * 	alpha2.
+ * @rd: a complete regulatory domain provided by the driver. If passed
+ * 	the driver does not need to worry about freeing it.
+ *
+ * Wireless drivers can use this function to hint to the wireless core
+ * what it believes should be the current regulatory domain by
+ * giving it an ISO/IEC 3166 alpha2 country code it knows its regulatory
+ * domain should be in or by providing a completely build regulatory domain.
+ * If the driver provides an ISO/IEC 3166 alpha2 userspace will be queried
+ * for a regulatory domain structure for the respective country. If
+ * a regulatory domain is build and passed you should set the alpha2
+ * if possible, otherwise set it to the special value of "99" which tells
+ * the wireless core it is unknown. If you pass a built regulatory domain
+ * and we return non zero you are in charge of kfree()'ing the structure.
+ *
+ * See __regulatory_hint() documentation for possible return values.
+ */
+extern int regulatory_hint(struct wiphy *wiphy,
+		const char *alpha2, struct ieee80211_regdomain *rd);
 #endif /* __NET_WIRELESS_H */
diff --git a/include/net/xfrm.h b/include/net/xfrm.h
index 2933d747..11c890a 100644
--- a/include/net/xfrm.h
+++ b/include/net/xfrm.h
@@ -117,12 +117,23 @@
       metrics. Plus, it will be made via sk->sk_dst_cache. Solved.
  */
 
+struct xfrm_state_walk {
+	struct list_head	all;
+	u8			state;
+	union {
+		u8		dying;
+		u8		proto;
+	};
+	u32			seq;
+};
+
 /* Full description of state of transformer. */
 struct xfrm_state
 {
-	/* Note: bydst is re-used during gc */
-	struct list_head	all;
-	struct hlist_node	bydst;
+	union {
+		struct hlist_node	gclist;
+		struct hlist_node	bydst;
+	};
 	struct hlist_node	bysrc;
 	struct hlist_node	byspi;
 
@@ -134,12 +145,8 @@
 
 	u32			genid;
 
-	/* Key manger bits */
-	struct {
-		u8		state;
-		u8		dying;
-		u32		seq;
-	} km;
+	/* Key manager bits */
+	struct xfrm_state_walk	km;
 
 	/* Parameters of this state. */
 	struct {
@@ -447,10 +454,20 @@
 
 #define XFRM_MAX_DEPTH		6
 
+struct xfrm_policy_walk_entry {
+	struct list_head	all;
+	u8			dead;
+};
+
+struct xfrm_policy_walk {
+	struct xfrm_policy_walk_entry walk;
+	u8 type;
+	u32 seq;
+};
+
 struct xfrm_policy
 {
 	struct xfrm_policy	*next;
-	struct list_head	bytype;
 	struct hlist_node	bydst;
 	struct hlist_node	byidx;
 
@@ -465,17 +482,23 @@
 	struct xfrm_lifetime_cfg lft;
 	struct xfrm_lifetime_cur curlft;
 	struct dst_entry       *bundles;
-	u16			family;
+	struct xfrm_policy_walk_entry walk;
 	u8			type;
 	u8			action;
 	u8			flags;
-	u8			dead;
 	u8			xfrm_nr;
-	/* XXX 1 byte hole, try to pack */
+	u16			family;
 	struct xfrm_sec_ctx	*security;
 	struct xfrm_tmpl       	xfrm_vec[XFRM_MAX_DEPTH];
 };
 
+struct xfrm_kmaddress {
+	xfrm_address_t          local;
+	xfrm_address_t          remote;
+	u32			reserved;
+	u16			family;
+};
+
 struct xfrm_migrate {
 	xfrm_address_t		old_daddr;
 	xfrm_address_t		old_saddr;
@@ -515,7 +538,7 @@
 	int			(*new_mapping)(struct xfrm_state *x, xfrm_address_t *ipaddr, __be16 sport);
 	int			(*notify_policy)(struct xfrm_policy *x, int dir, struct km_event *c);
 	int			(*report)(u8 proto, struct xfrm_selector *sel, xfrm_address_t *addr);
-	int			(*migrate)(struct xfrm_selector *sel, u8 dir, u8 type, struct xfrm_migrate *m, int num_bundles);
+	int			(*migrate)(struct xfrm_selector *sel, u8 dir, u8 type, struct xfrm_migrate *m, int num_bundles, struct xfrm_kmaddress *k);
 };
 
 extern int xfrm_register_km(struct xfrm_mgr *km);
@@ -1243,18 +1266,6 @@
 	int priority;
 };
 
-struct xfrm_state_walk {
-	struct xfrm_state *state;
-	int count;
-	u8 proto;
-};
-
-struct xfrm_policy_walk {
-	struct xfrm_policy *policy;
-	int count;
-	u8 type, cur_type;
-};
-
 extern void xfrm_init(void);
 extern void xfrm4_init(void);
 extern void xfrm_state_init(void);
@@ -1279,23 +1290,10 @@
 extern int xfrm_proc_init(void);
 #endif
 
-static inline void xfrm_state_walk_init(struct xfrm_state_walk *walk, u8 proto)
-{
-	walk->proto = proto;
-	walk->state = NULL;
-	walk->count = 0;
-}
-
-static inline void xfrm_state_walk_done(struct xfrm_state_walk *walk)
-{
-	if (walk->state != NULL) {
-		xfrm_state_put(walk->state);
-		walk->state = NULL;
-	}
-}
-
+extern void xfrm_state_walk_init(struct xfrm_state_walk *walk, u8 proto);
 extern int xfrm_state_walk(struct xfrm_state_walk *walk,
 			   int (*func)(struct xfrm_state *, int, void*), void *);
+extern void xfrm_state_walk_done(struct xfrm_state_walk *walk);
 extern struct xfrm_state *xfrm_state_alloc(void);
 extern struct xfrm_state *xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr, 
 					  struct flowi *fl, struct xfrm_tmpl *tmpl,
@@ -1419,24 +1417,10 @@
 
 struct xfrm_policy *xfrm_policy_alloc(gfp_t gfp);
 
-static inline void xfrm_policy_walk_init(struct xfrm_policy_walk *walk, u8 type)
-{
-	walk->cur_type = XFRM_POLICY_TYPE_MAIN;
-	walk->type = type;
-	walk->policy = NULL;
-	walk->count = 0;
-}
-
-static inline void xfrm_policy_walk_done(struct xfrm_policy_walk *walk)
-{
-	if (walk->policy != NULL) {
-		xfrm_pol_put(walk->policy);
-		walk->policy = NULL;
-	}
-}
-
+extern void xfrm_policy_walk_init(struct xfrm_policy_walk *walk, u8 type);
 extern int xfrm_policy_walk(struct xfrm_policy_walk *walk,
 	int (*func)(struct xfrm_policy *, int, int, void*), void *);
+extern void xfrm_policy_walk_done(struct xfrm_policy_walk *walk);
 int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl);
 struct xfrm_policy *xfrm_policy_bysel_ctx(u8 type, int dir,
 					  struct xfrm_selector *sel,
@@ -1455,12 +1439,14 @@
 
 #ifdef CONFIG_XFRM_MIGRATE
 extern int km_migrate(struct xfrm_selector *sel, u8 dir, u8 type,
-		      struct xfrm_migrate *m, int num_bundles);
+		      struct xfrm_migrate *m, int num_bundles,
+		      struct xfrm_kmaddress *k);
 extern struct xfrm_state * xfrm_migrate_state_find(struct xfrm_migrate *m);
 extern struct xfrm_state * xfrm_state_migrate(struct xfrm_state *x,
 					      struct xfrm_migrate *m);
 extern int xfrm_migrate(struct xfrm_selector *sel, u8 dir, u8 type,
-			struct xfrm_migrate *m, int num_bundles);
+			struct xfrm_migrate *m, int num_bundles,
+			struct xfrm_kmaddress *k);
 #endif
 
 extern wait_queue_head_t km_waitq;
diff --git a/include/pcmcia/ciscode.h b/include/pcmcia/ciscode.h
index ad6e278..b417985 100644
--- a/include/pcmcia/ciscode.h
+++ b/include/pcmcia/ciscode.h
@@ -119,7 +119,7 @@
 
 #define MANFID_TOSHIBA			0x0098
 
-#define MANFID_UNGERMANN 0x02c0
+#define MANFID_UNGERMANN		0x02c0
 
 #define MANFID_XIRCOM			0x0105
 
diff --git a/include/pcmcia/cistpl.h b/include/pcmcia/cistpl.h
index e2e10c1..cfdd5af 100644
--- a/include/pcmcia/cistpl.h
+++ b/include/pcmcia/cistpl.h
@@ -573,44 +573,6 @@
 #define TUPLE_RETURN_LINK	0x01
 #define TUPLE_RETURN_COMMON	0x02
 
-/* For ValidateCIS */
-typedef struct cisinfo_t {
-    u_int	Chains;
-} cisinfo_t;
-
 #define CISTPL_MAX_CIS_SIZE	0x200
 
-/* For ReplaceCIS */
-typedef struct cisdump_t {
-    u_int	Length;
-    cisdata_t	Data[CISTPL_MAX_CIS_SIZE];
-} cisdump_t;
-
-
-int pcmcia_replace_cis(struct pcmcia_socket *s, cisdump_t *cis);
-
-/* don't use outside of PCMCIA core yet */
-int pccard_get_next_tuple(struct pcmcia_socket *s, unsigned int func, tuple_t *tuple);
-int pccard_get_first_tuple(struct pcmcia_socket *s, unsigned int function, tuple_t *tuple);
-int pccard_get_tuple_data(struct pcmcia_socket *s, tuple_t *tuple);
-int pccard_parse_tuple(tuple_t *tuple, cisparse_t *parse);
-
-int pccard_validate_cis(struct pcmcia_socket *s, unsigned int function, unsigned int *count);
-
-/* ... but use these wrappers instead */
-#define pcmcia_get_first_tuple(p_dev, tuple) \
-		pccard_get_first_tuple(p_dev->socket, p_dev->func, tuple)
-
-#define pcmcia_get_next_tuple(p_dev, tuple) \
-		pccard_get_next_tuple(p_dev->socket, p_dev->func, tuple)
-
-#define pcmcia_get_tuple_data(p_dev, tuple) \
-		pccard_get_tuple_data(p_dev->socket, tuple)
-
-#define pcmcia_parse_tuple(p_dev, tuple, parse) \
-		pccard_parse_tuple(tuple, parse)
-
-#define pcmcia_validate_cis(p_dev, info) \
-		pccard_validate_cis(p_dev->socket, p_dev->func, info)
-
 #endif /* LINUX_CISTPL_H */
diff --git a/include/pcmcia/cs.h b/include/pcmcia/cs.h
index 45d84b2..904468a 100644
--- a/include/pcmcia/cs.h
+++ b/include/pcmcia/cs.h
@@ -28,72 +28,16 @@
 #define CS_WRITE	2
 
 /* for AdjustResourceInfo */
-typedef struct adjust_t {
-    u_int	Action;
-    u_int	Resource;
-    u_int	Attributes;
-    union {
-	struct memory {
-	    u_long	Base;
-	    u_long	Size;
-	} memory;
-	struct io {
-	    ioaddr_t	BasePort;
-	    ioaddr_t	NumPorts;
-	    u_int	IOAddrLines;
-	} io;
-	struct irq {
-	    u_int	IRQ;
-	} irq;
-    } resource;
-} adjust_t;
-
 /* Action field */
 #define REMOVE_MANAGED_RESOURCE		1
 #define ADD_MANAGED_RESOURCE		2
-#define GET_FIRST_MANAGED_RESOURCE	3
-#define GET_NEXT_MANAGED_RESOURCE	4
-/* Resource field */
-#define RES_MEMORY_RANGE		1
-#define RES_IO_RANGE			2
-#define RES_IRQ				3
-/* Attribute field */
-#define RES_IRQ_TYPE			0x03
-#define RES_IRQ_TYPE_EXCLUSIVE		0
-#define RES_IRQ_TYPE_TIME		1
-#define RES_IRQ_TYPE_DYNAMIC		2
-#define RES_IRQ_CSC			0x04
-#define RES_SHARED			0x08
-#define RES_RESERVED			0x10
-#define RES_ALLOCATED			0x20
-#define RES_REMOVED			0x40
+
 
 typedef struct event_callback_args_t {
 	struct pcmcia_device	*client_handle;
 	void			*client_data;
 } event_callback_args_t;
 
-/* for GetConfigurationInfo */
-typedef struct config_info_t {
-    u_char	Function;
-    u_int	Attributes;
-    u_int	Vcc, Vpp1, Vpp2;
-    u_int	IntType;
-    u_int	ConfigBase;
-    u_char	Status, Pin, Copy, Option, ExtStatus;
-    u_int	Present;
-    u_int	CardValues;
-    u_int	AssignedIRQ;
-    u_int	IRQAttributes;
-    ioaddr_t	BasePort1;
-    ioaddr_t	NumPorts1;
-    u_int	Attributes1;
-    ioaddr_t	BasePort2;
-    ioaddr_t	NumPorts2;
-    u_int	Attributes2;
-    u_int	IOAddrLines;
-} config_info_t;
-
 /* For CardValues field */
 #define CV_OPTION_VALUE		0x01
 #define CV_STATUS_VALUE		0x02
@@ -257,22 +201,6 @@
 #define WIN_BAR_MASK		0xe000
 #define WIN_BAR_SHIFT		13
 
-/* Attributes for RegisterClient -- UNUSED -- */
-#define INFO_MASTER_CLIENT	0x01
-#define INFO_IO_CLIENT		0x02
-#define INFO_MTD_CLIENT		0x04
-#define INFO_MEM_CLIENT		0x08
-#define MAX_NUM_CLIENTS		3
-
-#define INFO_CARD_SHARE		0x10
-#define INFO_CARD_EXCL		0x20
-
-typedef struct cs_status_t {
-    u_char	Function;
-    event_t 	CardState;
-    event_t	SocketState;
-} cs_status_t;
-
 typedef struct error_info_t {
     int		func;
     int		retcode;
@@ -308,95 +236,4 @@
 #define CS_EVENT_3VCARD			0x200000
 #define CS_EVENT_XVCARD			0x400000
 
-/* Return codes */
-#define CS_SUCCESS		0x00
-#define CS_BAD_ADAPTER		0x01
-#define CS_BAD_ATTRIBUTE	0x02
-#define CS_BAD_BASE		0x03
-#define CS_BAD_EDC		0x04
-#define CS_BAD_IRQ		0x06
-#define CS_BAD_OFFSET		0x07
-#define CS_BAD_PAGE		0x08
-#define CS_READ_FAILURE		0x09
-#define CS_BAD_SIZE		0x0a
-#define CS_BAD_SOCKET		0x0b
-#define CS_BAD_TYPE		0x0d
-#define CS_BAD_VCC		0x0e
-#define CS_BAD_VPP		0x0f
-#define CS_BAD_WINDOW		0x11
-#define CS_WRITE_FAILURE	0x12
-#define CS_NO_CARD		0x14
-#define CS_UNSUPPORTED_FUNCTION	0x15
-#define CS_UNSUPPORTED_MODE	0x16
-#define CS_BAD_SPEED		0x17
-#define CS_BUSY			0x18
-#define CS_GENERAL_FAILURE	0x19
-#define CS_WRITE_PROTECTED	0x1a
-#define CS_BAD_ARG_LENGTH	0x1b
-#define CS_BAD_ARGS		0x1c
-#define CS_CONFIGURATION_LOCKED	0x1d
-#define CS_IN_USE		0x1e
-#define CS_NO_MORE_ITEMS	0x1f
-#define CS_OUT_OF_RESOURCE	0x20
-#define CS_BAD_HANDLE		0x21
-
-#define CS_BAD_TUPLE		0x40
-
-#ifdef __KERNEL__
-
-/*
- *  The main Card Services entry point
- */
-
-enum service {
-    AccessConfigurationRegister, AddSocketServices,
-    AdjustResourceInfo, CheckEraseQueue, CloseMemory, CopyMemory,
-    DeregisterClient, DeregisterEraseQueue, GetCardServicesInfo,
-    GetClientInfo, GetConfigurationInfo, GetEventMask,
-    GetFirstClient, GetFirstPartion, GetFirstRegion, GetFirstTuple,
-    GetNextClient, GetNextPartition, GetNextRegion, GetNextTuple,
-    GetStatus, GetTupleData, MapLogSocket, MapLogWindow, MapMemPage,
-    MapPhySocket, MapPhyWindow, ModifyConfiguration, ModifyWindow,
-    OpenMemory, ParseTuple, ReadMemory, RegisterClient,
-    RegisterEraseQueue, RegisterMTD, RegisterTimer,
-    ReleaseConfiguration, ReleaseExclusive, ReleaseIO, ReleaseIRQ,
-    ReleaseSocketMask, ReleaseWindow, ReplaceSocketServices,
-    RequestConfiguration, RequestExclusive, RequestIO, RequestIRQ,
-    RequestSocketMask, RequestWindow, ResetCard, ReturnSSEntry,
-    SetEventMask, SetRegion, ValidateCIS, VendorSpecific,
-    WriteMemory, BindDevice, BindMTD, ReportError,
-    SuspendCard, ResumeCard, EjectCard, InsertCard, ReplaceCIS,
-    GetFirstWindow, GetNextWindow, GetMemPage
-};
-
-struct pcmcia_socket;
-
-int pcmcia_access_configuration_register(struct pcmcia_device *p_dev, conf_reg_t *reg);
-int pcmcia_get_configuration_info(struct pcmcia_device *p_dev, config_info_t *config);
-int pcmcia_get_mem_page(window_handle_t win, memreq_t *req);
-int pcmcia_map_mem_page(window_handle_t win, memreq_t *req);
-int pcmcia_modify_configuration(struct pcmcia_device *p_dev, modconf_t *mod);
-int pcmcia_release_window(window_handle_t win);
-int pcmcia_request_configuration(struct pcmcia_device *p_dev, config_req_t *req);
-int pcmcia_request_io(struct pcmcia_device *p_dev, io_req_t *req);
-int pcmcia_request_irq(struct pcmcia_device *p_dev, irq_req_t *req);
-int pcmcia_request_window(struct pcmcia_device **p_dev, win_req_t *req, window_handle_t *wh);
-int pcmcia_suspend_card(struct pcmcia_socket *skt);
-int pcmcia_resume_card(struct pcmcia_socket *skt);
-int pcmcia_eject_card(struct pcmcia_socket *skt);
-int pcmcia_insert_card(struct pcmcia_socket *skt);
-int pccard_reset_card(struct pcmcia_socket *skt);
-
-struct pcmcia_device * pcmcia_dev_present(struct pcmcia_device *p_dev);
-void pcmcia_disable_device(struct pcmcia_device *p_dev);
-
-struct pcmcia_socket * pcmcia_get_socket(struct pcmcia_socket *skt);
-void pcmcia_put_socket(struct pcmcia_socket *skt);
-
-/* compatibility functions */
-#define pcmcia_reset_card(p_dev, req) \
-		pccard_reset_card(p_dev->socket)
-
-#endif /* __KERNEL__ */
-
 #endif /* _LINUX_CS_H */
diff --git a/include/pcmcia/cs_types.h b/include/pcmcia/cs_types.h
index f402a0f..315965a 100644
--- a/include/pcmcia/cs_types.h
+++ b/include/pcmcia/cs_types.h
@@ -21,14 +21,6 @@
 #include <sys/types.h>
 #endif
 
-#if defined(__arm__) || defined(__mips__) || defined(__avr32__) || \
-	defined(__bfin__)
-/* This (ioaddr_t) is exposed to userspace & hence cannot be changed. */
-typedef u_int   ioaddr_t;
-#else
-typedef u_short	ioaddr_t;
-#endif
-
 typedef u_short	socket_t;
 typedef u_int	event_t;
 typedef u_char	cisdata_t;
diff --git a/include/pcmcia/device_id.h b/include/pcmcia/device_id.h
index e04e0b0..c33ea08 100644
--- a/include/pcmcia/device_id.h
+++ b/include/pcmcia/device_id.h
@@ -1,10 +1,19 @@
 /*
- * Copyright (2003-2004) 	Dominik Brodowski <linux@brodo.de>
- *				David Woodhouse
+ * device_id.h -- PCMCIA driver matching helpers
  *
- * License: GPL v2
+ * 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.
+ *
+ * (C) 2003 - 2004	David Woodhouse
+ * (C) 2003 - 2004	Dominik Brodowski
  */
 
+#ifndef _LINUX_PCMCIA_DEVICE_ID_H
+#define _LINUX_PCMCIA_DEVICE_ID_H
+
+#ifdef __KERNEL__
+
 #define PCMCIA_DEVICE_MANF_CARD(manf, card) { \
 	.match_flags = PCMCIA_DEV_ID_MATCH_MANF_ID| \
 			PCMCIA_DEV_ID_MATCH_CARD_ID, \
@@ -256,3 +265,6 @@
 
 
 #define PCMCIA_DEVICE_NULL { .match_flags = 0, }
+
+#endif /* __KERNEL__ */
+#endif /* _LINUX_PCMCIA_DEVICE_ID_H */
diff --git a/include/pcmcia/ds.h b/include/pcmcia/ds.h
index b316027..a2be80b 100644
--- a/include/pcmcia/ds.h
+++ b/include/pcmcia/ds.h
@@ -10,7 +10,7 @@
  * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
  *
  * (C) 1999		David A. Hinds
- * (C) 2003 - 2004	Dominik Brodowski
+ * (C) 2003 - 2008	Dominik Brodowski
  */
 
 #ifndef _LINUX_DS_H
@@ -23,108 +23,21 @@
 #include <pcmcia/cs_types.h>
 #include <pcmcia/device_id.h>
 
-typedef struct tuple_parse_t {
-    tuple_t		tuple;
-    cisdata_t		data[255];
-    cisparse_t		parse;
-} tuple_parse_t;
-
-typedef struct win_info_t {
-    window_handle_t	handle;
-    win_req_t		window;
-    memreq_t		map;
-} win_info_t;
-    
-typedef struct bind_info_t {
-    dev_info_t		dev_info;
-    u_char		function;
-    struct pcmcia_device *instance;
-    char		name[DEV_NAME_LEN];
-    u_short		major, minor;
-    void		*next;
-} bind_info_t;
-
-typedef struct mtd_info_t {
-    dev_info_t		dev_info;
-    u_int		Attributes;
-    u_int		CardOffset;
-} mtd_info_t;
-
-typedef struct region_info_t {
-    u_int		Attributes;
-    u_int		CardOffset;
-    u_int		RegionSize;
-    u_int		AccessSpeed;
-    u_int		BlockSize;
-    u_int		PartMultiple;
-    u_char		JedecMfr, JedecInfo;
-    memory_handle_t	next;
-} region_info_t;
-#define REGION_TYPE		0x0001
-#define REGION_TYPE_CM		0x0000
-#define REGION_TYPE_AM		0x0001
-#define REGION_PREFETCH		0x0008
-#define REGION_CACHEABLE	0x0010
-#define REGION_BAR_MASK		0xe000
-#define REGION_BAR_SHIFT	13
-
-typedef union ds_ioctl_arg_t {
-    adjust_t		adjust;
-    config_info_t	config;
-    tuple_t		tuple;
-    tuple_parse_t	tuple_parse;
-    client_req_t	client_req;
-    cs_status_t		status;
-    conf_reg_t		conf_reg;
-    cisinfo_t		cisinfo;
-    region_info_t	region;
-    bind_info_t		bind_info;
-    mtd_info_t		mtd_info;
-    win_info_t		win_info;
-    cisdump_t		cisdump;
-} ds_ioctl_arg_t;
-
-#define DS_ADJUST_RESOURCE_INFO		_IOWR('d', 2, adjust_t)
-#define DS_GET_CONFIGURATION_INFO	_IOWR('d', 3, config_info_t)
-#define DS_GET_FIRST_TUPLE		_IOWR('d', 4, tuple_t)
-#define DS_GET_NEXT_TUPLE		_IOWR('d', 5, tuple_t)
-#define DS_GET_TUPLE_DATA		_IOWR('d', 6, tuple_parse_t)
-#define DS_PARSE_TUPLE			_IOWR('d', 7, tuple_parse_t)
-#define DS_RESET_CARD			_IO  ('d', 8)
-#define DS_GET_STATUS			_IOWR('d', 9, cs_status_t)
-#define DS_ACCESS_CONFIGURATION_REGISTER _IOWR('d', 10, conf_reg_t)
-#define DS_VALIDATE_CIS			_IOR ('d', 11, cisinfo_t)
-#define DS_SUSPEND_CARD			_IO  ('d', 12)
-#define DS_RESUME_CARD			_IO  ('d', 13)
-#define DS_EJECT_CARD			_IO  ('d', 14)
-#define DS_INSERT_CARD			_IO  ('d', 15)
-#define DS_GET_FIRST_REGION		_IOWR('d', 16, region_info_t)
-#define DS_GET_NEXT_REGION		_IOWR('d', 17, region_info_t)
-#define DS_REPLACE_CIS			_IOWR('d', 18, cisdump_t)
-#define DS_GET_FIRST_WINDOW		_IOR ('d', 19, win_info_t)
-#define DS_GET_NEXT_WINDOW		_IOWR('d', 20, win_info_t)
-#define DS_GET_MEM_PAGE			_IOWR('d', 21, win_info_t)
-
-#define DS_BIND_REQUEST			_IOWR('d', 60, bind_info_t)
-#define DS_GET_DEVICE_INFO		_IOWR('d', 61, bind_info_t) 
-#define DS_GET_NEXT_DEVICE		_IOWR('d', 62, bind_info_t) 
-#define DS_UNBIND_REQUEST		_IOW ('d', 63, bind_info_t)
-#define DS_BIND_MTD			_IOWR('d', 64, mtd_info_t)
-
 #ifdef __KERNEL__
 #include <linux/device.h>
 #include <pcmcia/ss.h>
 
-typedef struct dev_node_t {
-    char		dev_name[DEV_NAME_LEN];
-    u_short		major, minor;
-    struct dev_node_t	*next;
-} dev_node_t;
-
-
+/*
+ * PCMCIA device drivers (16-bit cards only; 32-bit cards require CardBus
+ * a.k.a. PCI drivers
+ */
 struct pcmcia_socket;
+struct pcmcia_device;
 struct config_t;
 
+/* dynamic device IDs for PCMCIA device drivers. See
+ * Documentation/pcmcia/driver.txt for details.
+*/
 struct pcmcia_dynids {
 	spinlock_t		lock;
 	struct list_head	list;
@@ -147,6 +60,14 @@
 int pcmcia_register_driver(struct pcmcia_driver *driver);
 void pcmcia_unregister_driver(struct pcmcia_driver *driver);
 
+/* Some drivers use dev_node_t to store char or block device information.
+ * Don't use this in new drivers, though.
+ */
+typedef struct dev_node_t {
+	char			dev_name[DEV_NAME_LEN];
+	u_short			major, minor;
+	struct dev_node_t	*next;
+} dev_node_t;
 
 struct pcmcia_device {
 	/* the socket and the device_no [for multifunction devices]
@@ -216,10 +137,304 @@
 #define to_pcmcia_dev(n) container_of(n, struct pcmcia_device, dev)
 #define to_pcmcia_drv(n) container_of(n, struct pcmcia_driver, drv)
 
+/* deprecated -- don't use! */
 #define handle_to_dev(handle) (handle->dev)
 
-/* error reporting */
-void cs_error(struct pcmcia_device *handle, int func, int ret);
+
+/* (deprecated) error reporting by PCMCIA devices. Use dev_printk()
+ * or dev_dbg() directly in the driver, without referring to pcmcia_error_func()
+ * and/or pcmcia_error_ret() for those functions will go away soon.
+ */
+enum service {
+    AccessConfigurationRegister, AddSocketServices,
+    AdjustResourceInfo, CheckEraseQueue, CloseMemory, CopyMemory,
+    DeregisterClient, DeregisterEraseQueue, GetCardServicesInfo,
+    GetClientInfo, GetConfigurationInfo, GetEventMask,
+    GetFirstClient, GetFirstPartion, GetFirstRegion, GetFirstTuple,
+    GetNextClient, GetNextPartition, GetNextRegion, GetNextTuple,
+    GetStatus, GetTupleData, MapLogSocket, MapLogWindow, MapMemPage,
+    MapPhySocket, MapPhyWindow, ModifyConfiguration, ModifyWindow,
+    OpenMemory, ParseTuple, ReadMemory, RegisterClient,
+    RegisterEraseQueue, RegisterMTD, RegisterTimer,
+    ReleaseConfiguration, ReleaseExclusive, ReleaseIO, ReleaseIRQ,
+    ReleaseSocketMask, ReleaseWindow, ReplaceSocketServices,
+    RequestConfiguration, RequestExclusive, RequestIO, RequestIRQ,
+    RequestSocketMask, RequestWindow, ResetCard, ReturnSSEntry,
+    SetEventMask, SetRegion, ValidateCIS, VendorSpecific,
+    WriteMemory, BindDevice, BindMTD, ReportError,
+    SuspendCard, ResumeCard, EjectCard, InsertCard, ReplaceCIS,
+    GetFirstWindow, GetNextWindow, GetMemPage
+};
+const char *pcmcia_error_func(int func);
+const char *pcmcia_error_ret(int ret);
+
+#define cs_error(p_dev, func, ret)			\
+	{						\
+		dev_printk(KERN_NOTICE, &p_dev->dev,	\
+			   "%s : %s\n",			\
+			   pcmcia_error_func(func),	\
+			   pcmcia_error_ret(ret));	\
+	}
+
+/* CIS access.
+ * Use the pcmcia_* versions in PCMCIA drivers
+ */
+int pcmcia_parse_tuple(tuple_t *tuple, cisparse_t *parse);
+
+int pccard_get_first_tuple(struct pcmcia_socket *s, unsigned int function,
+			   tuple_t *tuple);
+#define pcmcia_get_first_tuple(p_dev, tuple) \
+		pccard_get_first_tuple(p_dev->socket, p_dev->func, tuple)
+
+int pccard_get_next_tuple(struct pcmcia_socket *s, unsigned int function,
+			  tuple_t *tuple);
+#define pcmcia_get_next_tuple(p_dev, tuple) \
+		pccard_get_next_tuple(p_dev->socket, p_dev->func, tuple)
+
+int pccard_get_tuple_data(struct pcmcia_socket *s, tuple_t *tuple);
+#define pcmcia_get_tuple_data(p_dev, tuple) \
+		pccard_get_tuple_data(p_dev->socket, tuple)
+
+
+/* loop CIS entries for valid configuration */
+int pcmcia_loop_config(struct pcmcia_device *p_dev,
+		       int	(*conf_check)	(struct pcmcia_device *p_dev,
+						 cistpl_cftable_entry_t *cf,
+						 cistpl_cftable_entry_t *dflt,
+						 unsigned int vcc,
+						 void *priv_data),
+		       void *priv_data);
+
+/* is the device still there? */
+struct pcmcia_device *pcmcia_dev_present(struct pcmcia_device *p_dev);
+
+/* low-level interface reset */
+int pcmcia_reset_card(struct pcmcia_socket *skt);
+
+/* CIS config */
+int pcmcia_access_configuration_register(struct pcmcia_device *p_dev,
+					 conf_reg_t *reg);
+
+/* device configuration */
+int pcmcia_request_io(struct pcmcia_device *p_dev, io_req_t *req);
+int pcmcia_request_irq(struct pcmcia_device *p_dev, irq_req_t *req);
+int pcmcia_request_configuration(struct pcmcia_device *p_dev,
+				 config_req_t *req);
+
+int pcmcia_request_window(struct pcmcia_device **p_dev, win_req_t *req,
+			  window_handle_t *wh);
+int pcmcia_release_window(window_handle_t win);
+
+int pcmcia_get_mem_page(window_handle_t win, memreq_t *req);
+int pcmcia_map_mem_page(window_handle_t win, memreq_t *req);
+
+int pcmcia_modify_configuration(struct pcmcia_device *p_dev, modconf_t *mod);
+void pcmcia_disable_device(struct pcmcia_device *p_dev);
 
 #endif /* __KERNEL__ */
+
+
+
+/* Below, there are only definitions which are used by
+ * - the PCMCIA ioctl
+ * - deprecated PCMCIA userspace tools only
+ *
+ * here be dragons ... here be dragons ... here be dragons ... here be drag
+ */
+
+#if defined(CONFIG_PCMCIA_IOCTL) || !defined(__KERNEL__)
+
+#if defined(__arm__) || defined(__mips__) || defined(__avr32__) || \
+	defined(__bfin__)
+/* This (ioaddr_t) is exposed to userspace & hence cannot be changed. */
+typedef u_int   ioaddr_t;
+#else
+typedef u_short	ioaddr_t;
+#endif
+
+/* for AdjustResourceInfo */
+typedef struct adjust_t {
+	u_int			Action;
+	u_int			Resource;
+	u_int			Attributes;
+	union {
+		struct memory {
+			u_long		Base;
+			u_long		Size;
+		} memory;
+		struct io {
+			ioaddr_t	BasePort;
+			ioaddr_t	NumPorts;
+			u_int		IOAddrLines;
+		} io;
+		struct irq {
+			u_int		IRQ;
+		} irq;
+	} resource;
+} adjust_t;
+
+/* Action field */
+#define REMOVE_MANAGED_RESOURCE		1
+#define ADD_MANAGED_RESOURCE		2
+#define GET_FIRST_MANAGED_RESOURCE	3
+#define GET_NEXT_MANAGED_RESOURCE	4
+/* Resource field */
+#define RES_MEMORY_RANGE		1
+#define RES_IO_RANGE			2
+#define RES_IRQ				3
+/* Attribute field */
+#define RES_IRQ_TYPE			0x03
+#define RES_IRQ_TYPE_EXCLUSIVE		0
+#define RES_IRQ_TYPE_TIME		1
+#define RES_IRQ_TYPE_DYNAMIC		2
+#define RES_IRQ_CSC			0x04
+#define RES_SHARED			0x08
+#define RES_RESERVED			0x10
+#define RES_ALLOCATED			0x20
+#define RES_REMOVED			0x40
+
+
+typedef struct tuple_parse_t {
+	tuple_t			tuple;
+	cisdata_t		data[255];
+	cisparse_t		parse;
+} tuple_parse_t;
+
+typedef struct win_info_t {
+	window_handle_t		handle;
+	win_req_t		window;
+	memreq_t		map;
+} win_info_t;
+
+typedef struct bind_info_t {
+	dev_info_t		dev_info;
+	u_char			function;
+	struct pcmcia_device	*instance;
+	char			name[DEV_NAME_LEN];
+	u_short			major, minor;
+	void			*next;
+} bind_info_t;
+
+typedef struct mtd_info_t {
+	dev_info_t     		dev_info;
+	u_int			Attributes;
+	u_int			CardOffset;
+} mtd_info_t;
+
+typedef struct region_info_t {
+	u_int			Attributes;
+	u_int			CardOffset;
+	u_int			RegionSize;
+	u_int			AccessSpeed;
+	u_int			BlockSize;
+	u_int			PartMultiple;
+	u_char			JedecMfr, JedecInfo;
+	memory_handle_t		next;
+} region_info_t;
+
+#define REGION_TYPE		0x0001
+#define REGION_TYPE_CM		0x0000
+#define REGION_TYPE_AM		0x0001
+#define REGION_PREFETCH		0x0008
+#define REGION_CACHEABLE	0x0010
+#define REGION_BAR_MASK		0xe000
+#define REGION_BAR_SHIFT	13
+
+/* For ReplaceCIS */
+typedef struct cisdump_t {
+	u_int			Length;
+	cisdata_t		Data[CISTPL_MAX_CIS_SIZE];
+} cisdump_t;
+
+/* for GetConfigurationInfo */
+typedef struct config_info_t {
+	u_char			Function;
+	u_int			Attributes;
+	u_int			Vcc, Vpp1, Vpp2;
+	u_int			IntType;
+	u_int			ConfigBase;
+	u_char			Status, Pin, Copy, Option, ExtStatus;
+	u_int			Present;
+	u_int			CardValues;
+	u_int			AssignedIRQ;
+	u_int			IRQAttributes;
+	ioaddr_t		BasePort1;
+	ioaddr_t		NumPorts1;
+	u_int			Attributes1;
+	ioaddr_t		BasePort2;
+	ioaddr_t		NumPorts2;
+	u_int			Attributes2;
+	u_int			IOAddrLines;
+} config_info_t;
+
+/* For ValidateCIS */
+typedef struct cisinfo_t {
+	u_int			Chains;
+} cisinfo_t;
+
+typedef struct cs_status_t {
+	u_char			Function;
+	event_t 		CardState;
+	event_t			SocketState;
+} cs_status_t;
+
+typedef union ds_ioctl_arg_t {
+	adjust_t		adjust;
+	config_info_t		config;
+	tuple_t			tuple;
+	tuple_parse_t		tuple_parse;
+	client_req_t		client_req;
+	cs_status_t		status;
+	conf_reg_t		conf_reg;
+	cisinfo_t		cisinfo;
+	region_info_t		region;
+	bind_info_t		bind_info;
+	mtd_info_t		mtd_info;
+	win_info_t		win_info;
+	cisdump_t		cisdump;
+} ds_ioctl_arg_t;
+
+#define DS_ADJUST_RESOURCE_INFO			_IOWR('d',  2, adjust_t)
+#define DS_GET_CONFIGURATION_INFO		_IOWR('d',  3, config_info_t)
+#define DS_GET_FIRST_TUPLE			_IOWR('d',  4, tuple_t)
+#define DS_GET_NEXT_TUPLE			_IOWR('d',  5, tuple_t)
+#define DS_GET_TUPLE_DATA			_IOWR('d',  6, tuple_parse_t)
+#define DS_PARSE_TUPLE				_IOWR('d',  7, tuple_parse_t)
+#define DS_RESET_CARD				_IO  ('d',  8)
+#define DS_GET_STATUS				_IOWR('d',  9, cs_status_t)
+#define DS_ACCESS_CONFIGURATION_REGISTER	_IOWR('d', 10, conf_reg_t)
+#define DS_VALIDATE_CIS				_IOR ('d', 11, cisinfo_t)
+#define DS_SUSPEND_CARD				_IO  ('d', 12)
+#define DS_RESUME_CARD				_IO  ('d', 13)
+#define DS_EJECT_CARD				_IO  ('d', 14)
+#define DS_INSERT_CARD				_IO  ('d', 15)
+#define DS_GET_FIRST_REGION			_IOWR('d', 16, region_info_t)
+#define DS_GET_NEXT_REGION			_IOWR('d', 17, region_info_t)
+#define DS_REPLACE_CIS				_IOWR('d', 18, cisdump_t)
+#define DS_GET_FIRST_WINDOW			_IOR ('d', 19, win_info_t)
+#define DS_GET_NEXT_WINDOW			_IOWR('d', 20, win_info_t)
+#define DS_GET_MEM_PAGE				_IOWR('d', 21, win_info_t)
+
+#define DS_BIND_REQUEST				_IOWR('d', 60, bind_info_t)
+#define DS_GET_DEVICE_INFO			_IOWR('d', 61, bind_info_t)
+#define DS_GET_NEXT_DEVICE			_IOWR('d', 62, bind_info_t)
+#define DS_UNBIND_REQUEST			_IOW ('d', 63, bind_info_t)
+#define DS_BIND_MTD				_IOWR('d', 64, mtd_info_t)
+
+
+/* used in userspace only */
+#define CS_IN_USE			0x1e
+
+#define INFO_MASTER_CLIENT	0x01
+#define INFO_IO_CLIENT		0x02
+#define INFO_MTD_CLIENT		0x04
+#define INFO_MEM_CLIENT		0x08
+#define MAX_NUM_CLIENTS		3
+
+#define INFO_CARD_SHARE		0x10
+#define INFO_CARD_EXCL		0x20
+
+
+#endif /* !defined(__KERNEL__) || defined(CONFIG_PCMCIA_IOCTL) */
+
 #endif /* _LINUX_DS_H */
diff --git a/include/pcmcia/ss.h b/include/pcmcia/ss.h
index ed919dd..9b4ac93 100644
--- a/include/pcmcia/ss.h
+++ b/include/pcmcia/ss.h
@@ -53,10 +53,10 @@
 
 /* for GetSocket, SetSocket */
 typedef struct socket_state_t {
-    u_int	flags;
-    u_int	csc_mask;
-    u_char	Vcc, Vpp;
-    u_char	io_irq;
+	u_int	flags;
+	u_int	csc_mask;
+	u_char	Vcc, Vpp;
+	u_char	io_irq;
 } socket_state_t;
 
 extern socket_state_t dead_socket;
@@ -86,79 +86,22 @@
 #define HOOK_POWER_PRE	0x01
 #define HOOK_POWER_POST	0x02
 
-
 typedef struct pccard_io_map {
-    u_char	map;
-    u_char	flags;
-    u_short	speed;
-    u_int	start, stop;
+	u_char	map;
+	u_char	flags;
+	u_short	speed;
+	u_int	start, stop;
 } pccard_io_map;
 
 typedef struct pccard_mem_map {
-    u_char	map;
-    u_char	flags;
-    u_short	speed;
-    u_long	static_start;
-    u_int	card_start;
-    struct resource *res;
+	u_char		map;
+	u_char		flags;
+	u_short		speed;
+	u_long		static_start;
+	u_int		card_start;
+	struct resource	*res;
 } pccard_mem_map;
 
-typedef struct cb_bridge_map {
-    u_char	map;
-    u_char	flags;
-    u_int	start, stop;
-} cb_bridge_map;
-
-/*
- * Socket operations.
- */
-struct pcmcia_socket;
-
-struct pccard_operations {
-	int (*init)(struct pcmcia_socket *sock);
-	int (*suspend)(struct pcmcia_socket *sock);
-	int (*get_status)(struct pcmcia_socket *sock, u_int *value);
-	int (*set_socket)(struct pcmcia_socket *sock, socket_state_t *state);
-	int (*set_io_map)(struct pcmcia_socket *sock, struct pccard_io_map *io);
-	int (*set_mem_map)(struct pcmcia_socket *sock, struct pccard_mem_map *mem);
-};
-
-struct pccard_resource_ops {
-	int	(*validate_mem)		(struct pcmcia_socket *s);
-	int	(*adjust_io_region)	(struct resource *res,
-					 unsigned long r_start,
-					 unsigned long r_end,
-					 struct pcmcia_socket *s);
-	struct resource* (*find_io)	(unsigned long base, int num,
-					 unsigned long align,
-					 struct pcmcia_socket *s);
-	struct resource* (*find_mem)	(unsigned long base, unsigned long num,
-					 unsigned long align, int low,
-					 struct pcmcia_socket *s);
-	int	(*add_io)		(struct pcmcia_socket *s,
-					 unsigned int action,
-					 unsigned long r_start,
-					 unsigned long r_end);
-	int	(*add_mem)		(struct pcmcia_socket *s,
-					 unsigned int action,
-					 unsigned long r_start,
-					 unsigned long r_end);
-	int	(*init)			(struct pcmcia_socket *s);
-	void	(*exit)			(struct pcmcia_socket *s);
-};
-/* SS_CAP_STATIC_MAP */
-extern struct pccard_resource_ops pccard_static_ops;
-/* !SS_CAP_STATIC_MAP */
-extern struct pccard_resource_ops pccard_nonstatic_ops;
-
-/* static mem, dynamic IO sockets */
-extern struct pccard_resource_ops pccard_iodyn_ops;
-
-/*
- *  Calls to set up low-level "Socket Services" drivers
- */
-struct pcmcia_socket;
-
 typedef struct io_window_t {
 	u_int			InUse, Config;
 	struct resource		*res;
@@ -179,10 +122,25 @@
 /* Maximum number of memory windows per socket */
 #define MAX_WIN 4
 
+
+/*
+ * Socket operations.
+ */
+struct pcmcia_socket;
+struct pccard_resource_ops;
 struct config_t;
 struct pcmcia_callback;
 struct user_info_t;
 
+struct pccard_operations {
+	int (*init)(struct pcmcia_socket *s);
+	int (*suspend)(struct pcmcia_socket *s);
+	int (*get_status)(struct pcmcia_socket *s, u_int *value);
+	int (*set_socket)(struct pcmcia_socket *s, socket_state_t *state);
+	int (*set_io_map)(struct pcmcia_socket *s, struct pccard_io_map *io);
+	int (*set_mem_map)(struct pcmcia_socket *s, struct pccard_mem_map *mem);
+};
+
 struct pcmcia_socket {
 	struct module			*owner;
 	spinlock_t			lock;
@@ -199,8 +157,8 @@
 	io_window_t			io[MAX_IO_WIN];
 	window_t			win[MAX_WIN];
 	struct list_head		cis_cache;
-	u_int				fake_cis_len;
-	char				*fake_cis;
+	size_t				fake_cis_len;
+	u8				*fake_cis;
 
 	struct list_head		socket_list;
 	struct completion		socket_released;
@@ -218,12 +176,12 @@
 	struct pci_dev *		cb_dev;
 
 
-	/* socket setup is done so resources should be able to be allocated. Only
-	 * if set to 1, calls to find_{io,mem}_region are handled, and insertion
-	 * events are actually managed by the PCMCIA layer.*/
+	/* socket setup is done so resources should be able to be allocated.
+	 * Only if set to 1, calls to find_{io,mem}_region are handled, and
+	 * insertio events are actually managed by the PCMCIA layer.*/
 	u8				resource_setup_done:1;
 
-	/* is set to one if resource setup is done using adjust_resource_info() */
+	/* It's old if resource setup is done using adjust_resource_info() */
 	u8				resource_setup_old:1;
 	u8				resource_setup_new:1;
 
@@ -236,75 +194,101 @@
 
 	/* Zoom video behaviour is so chip specific its not worth adding
 	   this to _ops */
-	void 				(*zoom_video)(struct pcmcia_socket *, int);
+	void 				(*zoom_video)(struct pcmcia_socket *,
+						      int);
 
 	/* so is power hook */
 	int (*power_hook)(struct pcmcia_socket *sock, int operation);
-#ifdef CONFIG_CARDBUS
+
 	/* allows tuning the CB bridge before loading driver for the CB card */
+#ifdef CONFIG_CARDBUS
 	void (*tune_bridge)(struct pcmcia_socket *sock, struct pci_bus *bus);
 #endif
 
 	/* state thread */
-	struct mutex			skt_mutex;	/* protects socket h/w state */
-
 	struct task_struct		*thread;
 	struct completion		thread_done;
-	spinlock_t			thread_lock;	/* protects thread_events */
 	unsigned int			thread_events;
+	/* protects socket h/w state */
+	struct mutex			skt_mutex;
+	/* protects thread_events */
+	spinlock_t			thread_lock;
 
 	/* pcmcia (16-bit) */
 	struct pcmcia_callback		*callback;
 
 #if defined(CONFIG_PCMCIA) || defined(CONFIG_PCMCIA_MODULE)
-	struct list_head		devices_list;	/*  PCMCIA devices */
-	u8				device_count;	/* the number of devices, used
-							 * only internally and subject
-							 * to incorrectness and change */
+	/* The following elements refer to 16-bit PCMCIA devices inserted
+	 * into the socket */
+	struct list_head		devices_list;
 
+	/* the number of devices, used only internally and subject to
+	 * incorrectness and change */
+	u8				device_count;
+
+	/* 16-bit state: */
 	struct {
-		u8			present:1,	/* PCMCIA card is present in socket */
-					busy:1,		/* "master" ioctl is used */
-					dead:1,		/* pcmcia module is being unloaded */
-					device_add_pending:1, /* a multifunction-device
-							       * add event is pending */
-					mfc_pfc:1,	/* the pending event adds a mfc (1) or pfc (0) */
-					reserved:3;
-	} 				pcmcia_state;
+		/* PCMCIA card is present in socket */
+		u8			present:1;
+		/* "master" ioctl is used */
+		u8			busy:1;
+		/* pcmcia module is being unloaded */
+		u8			dead:1;
+		/* a multifunction-device add event is pending */
+		u8			device_add_pending:1;
+		/* the pending event adds a mfc (1) or pfc (0) */
+		u8			mfc_pfc:1;
 
-	struct work_struct		device_add;	/* for adding further pseudo-multifunction
-							 * devices */
+		u8			reserved:3;
+	} pcmcia_state;
+
+
+	/* for adding further pseudo-multifunction devices */
+	struct work_struct		device_add;
 
 #ifdef CONFIG_PCMCIA_IOCTL
 	struct user_info_t		*user;
 	wait_queue_head_t		queue;
-#endif
-#endif
+#endif /* CONFIG_PCMCIA_IOCTL */
+#endif /* CONFIG_PCMCIA */
 
 	/* cardbus (32-bit) */
 #ifdef CONFIG_CARDBUS
 	struct resource *		cb_cis_res;
 	void __iomem			*cb_cis_virt;
-#endif
+#endif /* CONFIG_CARDBUS */
 
 	/* socket device */
 	struct device			dev;
-	void				*driver_data;	/* data internal to the socket driver */
-
+	/* data internal to the socket driver */
+	void				*driver_data;
 };
 
-struct pcmcia_socket * pcmcia_get_socket_by_nr(unsigned int nr);
 
-
-
-extern void pcmcia_parse_events(struct pcmcia_socket *socket, unsigned int events);
-extern int pcmcia_register_socket(struct pcmcia_socket *socket);
-extern void pcmcia_unregister_socket(struct pcmcia_socket *socket);
-
-extern struct class pcmcia_socket_class;
+/* socket drivers must define the resource operations type they use. There
+ * are three options:
+ * - pccard_static_ops		iomem and ioport areas are assigned statically
+ * - pccard_iodyn_ops		iomem areas is assigned statically, ioport
+ *				areas dynamically
+ * - pccard_nonstatic_ops	iomem and ioport areas are assigned dynamically.
+ *				If this option is selected, use
+ *				"select PCCARD_NONSTATIC" in Kconfig.
+ */
+extern struct pccard_resource_ops pccard_static_ops;
+extern struct pccard_resource_ops pccard_iodyn_ops;
+extern struct pccard_resource_ops pccard_nonstatic_ops;
 
 /* socket drivers are expected to use these callbacks in their .drv struct */
 extern int pcmcia_socket_dev_suspend(struct device *dev, pm_message_t state);
 extern int pcmcia_socket_dev_resume(struct device *dev);
 
+/* socket drivers use this callback in their IRQ handler */
+extern void pcmcia_parse_events(struct pcmcia_socket *socket,
+				unsigned int events);
+
+/* to register and unregister a socket */
+extern int pcmcia_register_socket(struct pcmcia_socket *socket);
+extern void pcmcia_unregister_socket(struct pcmcia_socket *socket);
+
+
 #endif /* _LINUX_SS_H */
diff --git a/include/scsi/scsi_cmnd.h b/include/scsi/scsi_cmnd.h
index f9f6e79..855bf95 100644
--- a/include/scsi/scsi_cmnd.h
+++ b/include/scsi/scsi_cmnd.h
@@ -75,7 +75,6 @@
 
 	int retries;
 	int allowed;
-	int timeout_per_command;
 
 	unsigned char prot_op;
 	unsigned char prot_type;
@@ -86,7 +85,6 @@
 	/* These elements define the operation we are about to perform */
 	unsigned char *cmnd;
 
-	struct timer_list eh_timeout;	/* Used to time out the command. */
 
 	/* These elements define the operation we ultimately want to perform */
 	struct scsi_data_buffer sdb;
@@ -139,7 +137,6 @@
 extern void __scsi_put_command(struct Scsi_Host *, struct scsi_cmnd *,
 			       struct device *);
 extern void scsi_finish_command(struct scsi_cmnd *cmd);
-extern void scsi_req_abort_cmd(struct scsi_cmnd *cmd);
 
 extern void *scsi_kmap_atomic_sg(struct scatterlist *sg, int sg_count,
 				 size_t *offset, size_t *len);
diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h
index 80b2e93..b49e725 100644
--- a/include/scsi/scsi_device.h
+++ b/include/scsi/scsi_device.h
@@ -42,9 +42,11 @@
 				 * originate in the mid-layer) */
 	SDEV_OFFLINE,		/* Device offlined (by error handling or
 				 * user request */
-	SDEV_BLOCK,		/* Device blocked by scsi lld.  No scsi 
-				 * commands from user or midlayer should be issued
-				 * to the scsi lld. */
+	SDEV_BLOCK,		/* Device blocked by scsi lld.  No
+				 * scsi commands from user or midlayer
+				 * should be issued to the scsi
+				 * lld. */
+	SDEV_CREATED_BLOCK,	/* same as above but for created devices */
 };
 
 enum scsi_device_event {
@@ -384,10 +386,23 @@
 #define scmd_id(scmd) sdev_id((scmd)->device)
 #define scmd_channel(scmd) sdev_channel((scmd)->device)
 
+/*
+ * checks for positions of the SCSI state machine
+ */
 static inline int scsi_device_online(struct scsi_device *sdev)
 {
 	return sdev->sdev_state != SDEV_OFFLINE;
 }
+static inline int scsi_device_blocked(struct scsi_device *sdev)
+{
+	return sdev->sdev_state == SDEV_BLOCK ||
+		sdev->sdev_state == SDEV_CREATED_BLOCK;
+}
+static inline int scsi_device_created(struct scsi_device *sdev)
+{
+	return sdev->sdev_state == SDEV_CREATED ||
+		sdev->sdev_state == SDEV_CREATED_BLOCK;
+}
 
 /* accessor functions for the SCSI parameters */
 static inline int scsi_device_sync(struct scsi_device *sdev)
diff --git a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h
index 44a55d1..d123ca8 100644
--- a/include/scsi/scsi_host.h
+++ b/include/scsi/scsi_host.h
@@ -43,13 +43,6 @@
 #define DISABLE_CLUSTERING 0
 #define ENABLE_CLUSTERING 1
 
-enum scsi_eh_timer_return {
-	EH_NOT_HANDLED,
-	EH_HANDLED,
-	EH_RESET_TIMER,
-};
-
-
 struct scsi_host_template {
 	struct module *module;
 	const char *name;
@@ -347,7 +340,7 @@
 	 *
 	 * Status: OPTIONAL
 	 */
-	enum scsi_eh_timer_return (* eh_timed_out)(struct scsi_cmnd *);
+	enum blk_eh_timer_return (*eh_timed_out)(struct scsi_cmnd *);
 
 	/*
 	 * Name of proc directory
diff --git a/include/scsi/scsi_netlink.h b/include/scsi/scsi_netlink.h
index 8c1470c..536752c 100644
--- a/include/scsi/scsi_netlink.h
+++ b/include/scsi/scsi_netlink.h
@@ -22,6 +22,9 @@
 #ifndef SCSI_NETLINK_H
 #define SCSI_NETLINK_H
 
+#include <linux/netlink.h>
+
+
 /*
  * This file intended to be included by both kernel and user space
  */
@@ -55,7 +58,41 @@
 #define SCSI_NL_TRANSPORT_FC			1
 #define SCSI_NL_MAX_TRANSPORTS			2
 
-/* scsi_nl_hdr->msgtype values are defined in each transport */
+/* Transport-based scsi_nl_hdr->msgtype values are defined in each transport */
+
+/*
+ * GENERIC SCSI scsi_nl_hdr->msgtype Values
+ */
+	/* kernel -> user */
+#define SCSI_NL_SHOST_VENDOR			0x0001
+	/* user -> kernel */
+/* SCSI_NL_SHOST_VENDOR msgtype is kernel->user and user->kernel */
+
+
+/*
+ * Message Structures :
+ */
+
+/* macro to round up message lengths to 8byte boundary */
+#define SCSI_NL_MSGALIGN(len)		(((len) + 7) & ~7)
+
+
+/*
+ * SCSI HOST Vendor Unique messages :
+ *   SCSI_NL_SHOST_VENDOR
+ *
+ * Note: The Vendor Unique message payload will begin directly after
+ * 	 this structure, with the length of the payload per vmsg_datalen.
+ *
+ * Note: When specifying vendor_id, be sure to read the Vendor Type and ID
+ *   formatting requirements specified below
+ */
+struct scsi_nl_host_vendor_msg {
+	struct scsi_nl_hdr snlh;		/* must be 1st element ! */
+	uint64_t vendor_id;
+	uint16_t host_no;
+	uint16_t vmsg_datalen;
+} __attribute__((aligned(sizeof(uint64_t))));
 
 
 /*
@@ -83,5 +120,28 @@
 	}
 
 
+#ifdef __KERNEL__
+
+#include <scsi/scsi_host.h>
+
+/* Exported Kernel Interfaces */
+int scsi_nl_add_transport(u8 tport,
+	 int (*msg_handler)(struct sk_buff *),
+	void (*event_handler)(struct notifier_block *, unsigned long, void *));
+void scsi_nl_remove_transport(u8 tport);
+
+int scsi_nl_add_driver(u64 vendor_id, struct scsi_host_template *hostt,
+	int (*nlmsg_handler)(struct Scsi_Host *shost, void *payload,
+				 u32 len, u32 pid),
+	void (*nlevt_handler)(struct notifier_block *nb,
+				 unsigned long event, void *notify_ptr));
+void scsi_nl_remove_driver(u64 vendor_id);
+
+void scsi_nl_send_transport_msg(u32 pid, struct scsi_nl_hdr *hdr);
+int scsi_nl_send_vendor_msg(u32 pid, unsigned short host_no, u64 vendor_id,
+			 char *data_buf, u32 data_len);
+
+#endif /* __KERNEL__ */
+
 #endif /* SCSI_NETLINK_H */
 
diff --git a/include/scsi/scsi_transport.h b/include/scsi/scsi_transport.h
index 490bd13..0de32cd 100644
--- a/include/scsi/scsi_transport.h
+++ b/include/scsi/scsi_transport.h
@@ -21,6 +21,7 @@
 #define SCSI_TRANSPORT_H
 
 #include <linux/transport_class.h>
+#include <linux/blkdev.h>
 #include <scsi/scsi_host.h>
 #include <scsi/scsi_device.h>
 
@@ -64,7 +65,7 @@
 	 *			begin counting again
 	 * EH_NOT_HANDLED	Begin normal error recovery
 	 */
-	enum scsi_eh_timer_return (* eh_timed_out)(struct scsi_cmnd *);
+	enum blk_eh_timer_return (*eh_timed_out)(struct scsi_cmnd *);
 
 	/*
 	 * Used as callback for the completion of i_t_nexus request
diff --git a/include/scsi/scsi_transport_fc.h b/include/scsi/scsi_transport_fc.h
index 878373c..21018a4 100644
--- a/include/scsi/scsi_transport_fc.h
+++ b/include/scsi/scsi_transport_fc.h
@@ -167,6 +167,26 @@
 struct device_attribute dev_attr_vport_##_name = 	\
 	__ATTR(_name,_mode,_show,_store)
 
+/*
+ * fc_vport_identifiers: This set of data contains all elements
+ * to uniquely identify and instantiate a FC virtual port.
+ *
+ * Notes:
+ *   symbolic_name: The driver is to append the symbolic_name string data
+ *      to the symbolic_node_name data that it generates by default.
+ *      the resulting combination should then be registered with the switch.
+ *      It is expected that things like Xen may stuff a VM title into
+ *      this field.
+ */
+#define FC_VPORT_SYMBOLIC_NAMELEN		64
+struct fc_vport_identifiers {
+	u64 node_name;
+	u64 port_name;
+	u32 roles;
+	bool disable;
+	enum fc_port_type vport_type;	/* only FC_PORTTYPE_NPIV allowed */
+	char symbolic_name[FC_VPORT_SYMBOLIC_NAMELEN];
+};
 
 /*
  * FC Virtual Port Attributes
@@ -197,7 +217,6 @@
  * managed by the transport w/o driver interaction.
  */
 
-#define FC_VPORT_SYMBOLIC_NAMELEN		64
 struct fc_vport {
 	/* Fixed Attributes */
 
@@ -732,6 +751,8 @@
 	 *   be sure to read the Vendor Type and ID formatting requirements
 	 *   specified in scsi_netlink.h
 	 */
+struct fc_vport *fc_vport_create(struct Scsi_Host *shost, int channel,
+		struct fc_vport_identifiers *);
 int fc_vport_terminate(struct fc_vport *vport);
 
 #endif /* SCSI_TRANSPORT_FC_H */
diff --git a/include/sound/ad1848.h b/include/sound/ad1848.h
deleted file mode 100644
index d9aebdf..0000000
--- a/include/sound/ad1848.h
+++ /dev/null
@@ -1,218 +0,0 @@
-#ifndef __SOUND_AD1848_H
-#define __SOUND_AD1848_H
-
-/*
- *  Copyright (c) by Jaroslav Kysela <perex@perex.cz>
- *  Definitions for AD1847/AD1848/CS4248 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
- *
- */
-
-#include "pcm.h"
-#include <linux/interrupt.h>
-
-/* IO ports */
-
-#define AD1848P( chip, x ) ( (chip) -> port + c_d_c_AD1848##x )
-
-#define c_d_c_AD1848REGSEL	0
-#define c_d_c_AD1848REG		1
-#define c_d_c_AD1848STATUS	2
-#define c_d_c_AD1848PIO		3
-
-/* codec registers */
-
-#define AD1848_LEFT_INPUT	0x00	/* left input control */
-#define AD1848_RIGHT_INPUT	0x01	/* right input control */
-#define AD1848_AUX1_LEFT_INPUT	0x02	/* left AUX1 input control */
-#define AD1848_AUX1_RIGHT_INPUT	0x03	/* right AUX1 input control */
-#define AD1848_AUX2_LEFT_INPUT	0x04	/* left AUX2 input control */
-#define AD1848_AUX2_RIGHT_INPUT	0x05	/* right AUX2 input control */
-#define AD1848_LEFT_OUTPUT	0x06	/* left output control register */
-#define AD1848_RIGHT_OUTPUT	0x07	/* right output control register */
-#define AD1848_DATA_FORMAT	0x08	/* clock and data format - playback/capture - bits 7-0 MCE */
-#define AD1848_IFACE_CTRL	0x09	/* interface control - bits 7-2 MCE */
-#define AD1848_PIN_CTRL		0x0a	/* pin control */
-#define AD1848_TEST_INIT	0x0b	/* test and initialization */
-#define AD1848_MISC_INFO	0x0c	/* miscellaneous information */
-#define AD1848_LOOPBACK		0x0d	/* loopback control */
-#define AD1848_DATA_UPR_CNT	0x0e	/* playback/capture upper base count */
-#define AD1848_DATA_LWR_CNT	0x0f	/* playback/capture lower base count */
-
-/* definitions for codec register select port - CODECP( REGSEL ) */
-
-#define AD1848_INIT		0x80	/* CODEC is initializing */
-#define AD1848_MCE		0x40	/* mode change enable */
-#define AD1848_TRD		0x20	/* transfer request disable */
-
-/* definitions for codec status register - CODECP( STATUS ) */
-
-#define AD1848_GLOBALIRQ	0x01	/* IRQ is active */
-
-/* definitions for AD1848_LEFT_INPUT and AD1848_RIGHT_INPUT registers */
-
-#define AD1848_ENABLE_MIC_GAIN	0x20
-
-#define AD1848_MIXS_LINE1	0x00
-#define AD1848_MIXS_AUX1	0x40
-#define AD1848_MIXS_LINE2	0x80
-#define AD1848_MIXS_ALL		0xc0
-
-/* definitions for clock and data format register - AD1848_PLAYBK_FORMAT */
-
-#define AD1848_LINEAR_8		0x00	/* 8-bit unsigned data */
-#define AD1848_ALAW_8		0x60	/* 8-bit A-law companded */
-#define AD1848_ULAW_8		0x20	/* 8-bit U-law companded */
-#define AD1848_LINEAR_16	0x40	/* 16-bit twos complement data - little endian */
-#define AD1848_STEREO		0x10	/* stereo mode */
-/* bits 3-1 define frequency divisor */
-#define AD1848_XTAL1		0x00	/* 24.576 crystal */
-#define AD1848_XTAL2		0x01	/* 16.9344 crystal */
-
-/* definitions for interface control register - AD1848_IFACE_CTRL */
-
-#define AD1848_CAPTURE_PIO	0x80	/* capture PIO enable */
-#define AD1848_PLAYBACK_PIO	0x40	/* playback PIO enable */
-#define AD1848_CALIB_MODE	0x18	/* calibration mode bits */
-#define AD1848_AUTOCALIB	0x08	/* auto calibrate */
-#define AD1848_SINGLE_DMA	0x04	/* use single DMA channel */
-#define AD1848_CAPTURE_ENABLE	0x02	/* capture enable */
-#define AD1848_PLAYBACK_ENABLE	0x01	/* playback enable */
-
-/* definitions for pin control register - AD1848_PIN_CTRL */
-
-#define AD1848_IRQ_ENABLE	0x02	/* enable IRQ */
-#define AD1848_XCTL1		0x40	/* external control #1 */
-#define AD1848_XCTL0		0x80	/* external control #0 */
-
-/* definitions for test and init register - AD1848_TEST_INIT */
-
-#define AD1848_CALIB_IN_PROGRESS 0x20	/* auto calibrate in progress */
-#define AD1848_DMA_REQUEST	0x10	/* DMA request in progress */
-
-/* defines for codec.mode */
-
-#define AD1848_MODE_NONE	0x0000
-#define AD1848_MODE_PLAY	0x0001
-#define AD1848_MODE_CAPTURE	0x0002
-#define AD1848_MODE_TIMER	0x0004
-#define AD1848_MODE_OPEN	(AD1848_MODE_PLAY|AD1848_MODE_CAPTURE|AD1848_MODE_TIMER)
-#define AD1848_MODE_RUNNING	0x0010
-
-/* defines for codec.hardware */
-
-#define AD1848_HW_DETECT	0x0000	/* let AD1848 driver detect chip */
-#define AD1848_HW_AD1847	0x0001	/* AD1847 chip */
-#define AD1848_HW_AD1848	0x0002	/* AD1848 chip */
-#define AD1848_HW_CS4248	0x0003	/* CS4248 chip */
-#define AD1848_HW_CMI8330	0x0004	/* CMI8330 chip */
-#define AD1848_HW_THINKPAD	0x0005	/* Thinkpad 360/750/755 */
-
-/* IBM Thinkpad specific stuff */
-#define AD1848_THINKPAD_CTL_PORT1		0x15e8
-#define AD1848_THINKPAD_CTL_PORT2		0x15e9
-#define AD1848_THINKPAD_CS4248_ENABLE_BIT	0x02
-
-struct snd_ad1848 {
-	unsigned long port;		/* i/o port */
-	struct resource *res_port;
-	int irq;			/* IRQ line */
-	int dma;			/* data DMA */
-	unsigned short version;		/* version of CODEC chip */
-	unsigned short mode;		/* see to AD1848_MODE_XXXX */
-	unsigned short hardware;	/* see to AD1848_HW_XXXX */
-	unsigned short single_dma:1;	/* forced single DMA mode (GUS 16-bit daughter board) or dma1 == dma2 */
-
-	struct snd_pcm *pcm;
-	struct snd_pcm_substream *playback_substream;
-	struct snd_pcm_substream *capture_substream;
-	struct snd_card *card;
-
-	unsigned char image[32];	/* SGalaxy needs an access to extended registers */
-	int mce_bit;
-	int calibrate_mute;
-	int dma_size;
-	int thinkpad_flag;		/* Thinkpad CS4248 needs some extra help */
-
-#ifdef CONFIG_PM
-	void (*suspend)(struct snd_ad1848 *chip);
-	void (*resume)(struct snd_ad1848 *chip);
-#endif
-
-	spinlock_t reg_lock;
-};
-
-/* exported functions */
-
-void snd_ad1848_out(struct snd_ad1848 *chip, unsigned char reg, unsigned char value);
-
-int snd_ad1848_create(struct snd_card *card,
-		      unsigned long port,
-		      int irq, int dma,
-		      unsigned short hardware,
-		      struct snd_ad1848 ** chip);
-
-int snd_ad1848_pcm(struct snd_ad1848 * chip, int device, struct snd_pcm **rpcm);
-const struct snd_pcm_ops *snd_ad1848_get_pcm_ops(int direction);
-int snd_ad1848_mixer(struct snd_ad1848 * chip);
-
-/* exported mixer stuffs */
-enum { AD1848_MIX_SINGLE, AD1848_MIX_DOUBLE, AD1848_MIX_CAPTURE };
-
-#define AD1848_MIXVAL_SINGLE(reg, shift, mask, invert) \
-	((reg) | ((shift) << 8) | ((mask) << 16) | ((invert) << 24))
-#define AD1848_MIXVAL_DOUBLE(left_reg, right_reg, shift_left, shift_right, mask, invert) \
-	((left_reg) | ((right_reg) << 8) | ((shift_left) << 16) | ((shift_right) << 19) | ((mask) << 24) | ((invert) << 22))
-
-/* for ease of use */
-struct ad1848_mix_elem {
-	const char *name;
-	int index;
-	int type;
-	unsigned long private_value;
-	const unsigned int *tlv;
-};
-
-#define AD1848_SINGLE(xname, xindex, reg, shift, mask, invert) \
-{ .name = xname, \
-  .index = xindex, \
-  .type = AD1848_MIX_SINGLE, \
-  .private_value = AD1848_MIXVAL_SINGLE(reg, shift, mask, invert) }
-
-#define AD1848_SINGLE_TLV(xname, xindex, reg, shift, mask, invert, xtlv) \
-{ .name = xname, \
-  .index = xindex, \
-  .type = AD1848_MIX_SINGLE, \
-  .private_value = AD1848_MIXVAL_SINGLE(reg, shift, mask, invert), \
-  .tlv = xtlv }
-
-#define AD1848_DOUBLE(xname, xindex, left_reg, right_reg, shift_left, shift_right, mask, invert) \
-{ .name = xname, \
-  .index = xindex, \
-  .type = AD1848_MIX_DOUBLE, \
-  .private_value = AD1848_MIXVAL_DOUBLE(left_reg, right_reg, shift_left, shift_right, mask, invert) }
-
-#define AD1848_DOUBLE_TLV(xname, xindex, left_reg, right_reg, shift_left, shift_right, mask, invert, xtlv) \
-{ .name = xname, \
-  .index = xindex, \
-  .type = AD1848_MIX_DOUBLE, \
-  .private_value = AD1848_MIXVAL_DOUBLE(left_reg, right_reg, shift_left, shift_right, mask, invert), \
-  .tlv = xtlv }
-
-int snd_ad1848_add_ctl_elem(struct snd_ad1848 *chip, const struct ad1848_mix_elem *c);
-
-#endif /* __SOUND_AD1848_H */
diff --git a/include/sound/asound.h b/include/sound/asound.h
index 3eaf155..2c4dc90 100644
--- a/include/sound/asound.h
+++ b/include/sound/asound.h
@@ -93,9 +93,10 @@
 	SNDRV_HWDEP_IFACE_PCXHR,	/* Digigram PCXHR */
 	SNDRV_HWDEP_IFACE_SB_RC,	/* SB Extigy/Audigy2NX remote control */
 	SNDRV_HWDEP_IFACE_HDA,		/* HD-audio */
+	SNDRV_HWDEP_IFACE_USB_STREAM,	/* direct access to usb stream */
 
 	/* Don't forget to change the following: */
-	SNDRV_HWDEP_IFACE_LAST = SNDRV_HWDEP_IFACE_HDA
+	SNDRV_HWDEP_IFACE_LAST = SNDRV_HWDEP_IFACE_USB_STREAM
 };
 
 struct snd_hwdep_info {
@@ -296,29 +297,39 @@
 	unsigned char reserved[64];	/* reserved for future... */
 };
 
-typedef int __bitwise snd_pcm_hw_param_t;
-#define	SNDRV_PCM_HW_PARAM_ACCESS	((__force snd_pcm_hw_param_t) 0) /* Access type */
-#define	SNDRV_PCM_HW_PARAM_FORMAT	((__force snd_pcm_hw_param_t) 1) /* Format */
-#define	SNDRV_PCM_HW_PARAM_SUBFORMAT	((__force snd_pcm_hw_param_t) 2) /* Subformat */
+typedef int snd_pcm_hw_param_t;
+#define	SNDRV_PCM_HW_PARAM_ACCESS	0	/* Access type */
+#define	SNDRV_PCM_HW_PARAM_FORMAT	1	/* Format */
+#define	SNDRV_PCM_HW_PARAM_SUBFORMAT	2	/* Subformat */
 #define	SNDRV_PCM_HW_PARAM_FIRST_MASK	SNDRV_PCM_HW_PARAM_ACCESS
 #define	SNDRV_PCM_HW_PARAM_LAST_MASK	SNDRV_PCM_HW_PARAM_SUBFORMAT
 
-#define	SNDRV_PCM_HW_PARAM_SAMPLE_BITS	((__force snd_pcm_hw_param_t) 8) /* Bits per sample */
-#define	SNDRV_PCM_HW_PARAM_FRAME_BITS	((__force snd_pcm_hw_param_t) 9) /* Bits per frame */
-#define	SNDRV_PCM_HW_PARAM_CHANNELS	((__force snd_pcm_hw_param_t) 10) /* Channels */
-#define	SNDRV_PCM_HW_PARAM_RATE		((__force snd_pcm_hw_param_t) 11) /* Approx rate */
-#define	SNDRV_PCM_HW_PARAM_PERIOD_TIME	((__force snd_pcm_hw_param_t) 12) /* Approx distance between interrupts in us */
-#define	SNDRV_PCM_HW_PARAM_PERIOD_SIZE	((__force snd_pcm_hw_param_t) 13) /* Approx frames between interrupts */
-#define	SNDRV_PCM_HW_PARAM_PERIOD_BYTES	((__force snd_pcm_hw_param_t) 14) /* Approx bytes between interrupts */
-#define	SNDRV_PCM_HW_PARAM_PERIODS	((__force snd_pcm_hw_param_t) 15) /* Approx interrupts per buffer */
-#define	SNDRV_PCM_HW_PARAM_BUFFER_TIME	((__force snd_pcm_hw_param_t) 16) /* Approx duration of buffer in us */
-#define	SNDRV_PCM_HW_PARAM_BUFFER_SIZE	((__force snd_pcm_hw_param_t) 17) /* Size of buffer in frames */
-#define	SNDRV_PCM_HW_PARAM_BUFFER_BYTES	((__force snd_pcm_hw_param_t) 18) /* Size of buffer in bytes */
-#define	SNDRV_PCM_HW_PARAM_TICK_TIME	((__force snd_pcm_hw_param_t) 19) /* Approx tick duration in us */
+#define	SNDRV_PCM_HW_PARAM_SAMPLE_BITS	8	/* Bits per sample */
+#define	SNDRV_PCM_HW_PARAM_FRAME_BITS	9	/* Bits per frame */
+#define	SNDRV_PCM_HW_PARAM_CHANNELS	10	/* Channels */
+#define	SNDRV_PCM_HW_PARAM_RATE		11	/* Approx rate */
+#define	SNDRV_PCM_HW_PARAM_PERIOD_TIME	12	/* Approx distance between
+						 * interrupts in us
+						 */
+#define	SNDRV_PCM_HW_PARAM_PERIOD_SIZE	13	/* Approx frames between
+						 * interrupts
+						 */
+#define	SNDRV_PCM_HW_PARAM_PERIOD_BYTES	14	/* Approx bytes between
+						 * interrupts
+						 */
+#define	SNDRV_PCM_HW_PARAM_PERIODS	15	/* Approx interrupts per
+						 * buffer
+						 */
+#define	SNDRV_PCM_HW_PARAM_BUFFER_TIME	16	/* Approx duration of buffer
+						 * in us
+						 */
+#define	SNDRV_PCM_HW_PARAM_BUFFER_SIZE	17	/* Size of buffer in frames */
+#define	SNDRV_PCM_HW_PARAM_BUFFER_BYTES	18	/* Size of buffer in bytes */
+#define	SNDRV_PCM_HW_PARAM_TICK_TIME	19	/* Approx tick duration in us */
 #define	SNDRV_PCM_HW_PARAM_FIRST_INTERVAL	SNDRV_PCM_HW_PARAM_SAMPLE_BITS
 #define	SNDRV_PCM_HW_PARAM_LAST_INTERVAL	SNDRV_PCM_HW_PARAM_TICK_TIME
 
-#define SNDRV_PCM_HW_PARAMS_NORESAMPLE		(1<<0)	/* avoid rate resampling */
+#define SNDRV_PCM_HW_PARAMS_NORESAMPLE	(1<<0)	/* avoid rate resampling */
 
 struct snd_interval {
 	unsigned int min, max;
@@ -696,7 +707,7 @@
  *                                                                          *
  ****************************************************************************/
 
-#define SNDRV_CTL_VERSION		SNDRV_PROTOCOL_VERSION(2, 0, 5)
+#define SNDRV_CTL_VERSION		SNDRV_PROTOCOL_VERSION(2, 0, 6)
 
 struct snd_ctl_card_info {
 	int card;			/* card number */
@@ -707,8 +718,7 @@
 	unsigned char longname[80];	/* name + info text about soundcard */
 	unsigned char reserved_[16];	/* reserved for future (was ID of mixer) */
 	unsigned char mixername[80];	/* visual mixer identification */
-	unsigned char components[80];	/* card components / fine identification, delimited with one space (AC97 etc..) */
-	unsigned char reserved[48];	/* reserved for future */
+	unsigned char components[128];	/* card components / fine identification, delimited with one space (AC97 etc..) */
 };
 
 typedef int __bitwise snd_ctl_elem_type_t;
diff --git a/include/sound/asoundef.h b/include/sound/asoundef.h
index a6e0fac..20ebf32 100644
--- a/include/sound/asoundef.h
+++ b/include/sound/asoundef.h
@@ -60,35 +60,56 @@
 #define IEC958_AES1_PRO_USERBITS_UDEF	(12<<4)	/* user defined application */
 #define IEC958_AES1_CON_CATEGORY	0x7f
 #define IEC958_AES1_CON_GENERAL		0x00
-#define IEC958_AES1_CON_EXPERIMENTAL	0x40
-#define IEC958_AES1_CON_SOLIDMEM_MASK	0x0f
-#define IEC958_AES1_CON_SOLIDMEM_ID	0x08
-#define IEC958_AES1_CON_BROADCAST1_MASK 0x07
-#define IEC958_AES1_CON_BROADCAST1_ID	0x04
-#define IEC958_AES1_CON_DIGDIGCONV_MASK 0x07
-#define IEC958_AES1_CON_DIGDIGCONV_ID	0x02
-#define IEC958_AES1_CON_ADC_COPYRIGHT_MASK 0x1f
-#define IEC958_AES1_CON_ADC_COPYRIGHT_ID 0x06
-#define IEC958_AES1_CON_ADC_MASK	0x1f
-#define IEC958_AES1_CON_ADC_ID		0x16
-#define IEC958_AES1_CON_BROADCAST2_MASK 0x0f
-#define IEC958_AES1_CON_BROADCAST2_ID	0x0e
 #define IEC958_AES1_CON_LASEROPT_MASK	0x07
 #define IEC958_AES1_CON_LASEROPT_ID	0x01
-#define IEC958_AES1_CON_MUSICAL_MASK	0x07
-#define IEC958_AES1_CON_MUSICAL_ID	0x05
-#define IEC958_AES1_CON_MAGNETIC_MASK	0x07
-#define IEC958_AES1_CON_MAGNETIC_ID	0x03
 #define IEC958_AES1_CON_IEC908_CD	(IEC958_AES1_CON_LASEROPT_ID|0x00)
 #define IEC958_AES1_CON_NON_IEC908_CD	(IEC958_AES1_CON_LASEROPT_ID|0x08)
+#define IEC958_AES1_CON_MINI_DISC	(IEC958_AES1_CON_LASEROPT_ID|0x48)
+#define IEC958_AES1_CON_DVD		(IEC958_AES1_CON_LASEROPT_ID|0x18)
+#define IEC958_AES1_CON_LASTEROPT_OTHER	(IEC958_AES1_CON_LASEROPT_ID|0x78)
+#define IEC958_AES1_CON_DIGDIGCONV_MASK 0x07
+#define IEC958_AES1_CON_DIGDIGCONV_ID	0x02
 #define IEC958_AES1_CON_PCM_CODER	(IEC958_AES1_CON_DIGDIGCONV_ID|0x00)
-#define IEC958_AES1_CON_SAMPLER		(IEC958_AES1_CON_DIGDIGCONV_ID|0x20)
 #define IEC958_AES1_CON_MIXER		(IEC958_AES1_CON_DIGDIGCONV_ID|0x10)
 #define IEC958_AES1_CON_RATE_CONVERTER	(IEC958_AES1_CON_DIGDIGCONV_ID|0x18)
-#define IEC958_AES1_CON_SYNTHESIZER	(IEC958_AES1_CON_MUSICAL_ID|0x00)
-#define IEC958_AES1_CON_MICROPHONE	(IEC958_AES1_CON_MUSICAL_ID|0x08)
+#define IEC958_AES1_CON_SAMPLER		(IEC958_AES1_CON_DIGDIGCONV_ID|0x20)
+#define IEC958_AES1_CON_DSP		(IEC958_AES1_CON_DIGDIGCONV_ID|0x28)
+#define IEC958_AES1_CON_DIGDIGCONV_OTHER (IEC958_AES1_CON_DIGDIGCONV_ID|0x78)
+#define IEC958_AES1_CON_MAGNETIC_MASK	0x07
+#define IEC958_AES1_CON_MAGNETIC_ID	0x03
 #define IEC958_AES1_CON_DAT		(IEC958_AES1_CON_MAGNETIC_ID|0x00)
 #define IEC958_AES1_CON_VCR		(IEC958_AES1_CON_MAGNETIC_ID|0x08)
+#define IEC958_AES1_CON_DCC		(IEC958_AES1_CON_MAGNETIC_ID|0x40)
+#define IEC958_AES1_CON_MAGNETIC_DISC	(IEC958_AES1_CON_MAGNETIC_ID|0x18)
+#define IEC958_AES1_CON_MAGNETIC_OTHER	(IEC958_AES1_CON_MAGNETIC_ID|0x78)
+#define IEC958_AES1_CON_BROADCAST1_MASK 0x07
+#define IEC958_AES1_CON_BROADCAST1_ID	0x04
+#define IEC958_AES1_CON_DAB_JAPAN	(IEC958_AES1_CON_BROADCAST1_ID|0x00)
+#define IEC958_AES1_CON_DAB_EUROPE	(IEC958_AES1_CON_BROADCAST1_ID|0x08)
+#define IEC958_AES1_CON_DAB_USA		(IEC958_AES1_CON_BROADCAST1_ID|0x60)
+#define IEC958_AES1_CON_SOFTWARE	(IEC958_AES1_CON_BROADCAST1_ID|0x40)
+#define IEC958_AES1_CON_IEC62105	(IEC958_AES1_CON_BROADCAST1_ID|0x20)
+#define IEC958_AES1_CON_BROADCAST1_OTHER (IEC958_AES1_CON_BROADCAST1_ID|0x78)
+#define IEC958_AES1_CON_BROADCAST2_MASK 0x0f
+#define IEC958_AES1_CON_BROADCAST2_ID	0x0e
+#define IEC958_AES1_CON_MUSICAL_MASK	0x07
+#define IEC958_AES1_CON_MUSICAL_ID	0x05
+#define IEC958_AES1_CON_SYNTHESIZER	(IEC958_AES1_CON_MUSICAL_ID|0x00)
+#define IEC958_AES1_CON_MICROPHONE	(IEC958_AES1_CON_MUSICAL_ID|0x08)
+#define IEC958_AES1_CON_MUSICAL_OTHER	(IEC958_AES1_CON_MUSICAL_ID|0x78)
+#define IEC958_AES1_CON_ADC_MASK	0x1f
+#define IEC958_AES1_CON_ADC_ID		0x06
+#define IEC958_AES1_CON_ADC		(IEC958_AES1_CON_ADC_ID|0x00)
+#define IEC958_AES1_CON_ADC_OTHER	(IEC958_AES1_CON_ADC_ID|0x60)
+#define IEC958_AES1_CON_ADC_COPYRIGHT_MASK 0x1f
+#define IEC958_AES1_CON_ADC_COPYRIGHT_ID 0x16
+#define IEC958_AES1_CON_ADC_COPYRIGHT	(IEC958_AES1_CON_ADC_COPYRIGHT_ID|0x00)
+#define IEC958_AES1_CON_ADC_COPYRIGHT_OTHER (IEC958_AES1_CON_ADC_COPYRIGHT_ID|0x60)
+#define IEC958_AES1_CON_SOLIDMEM_MASK	0x0f
+#define IEC958_AES1_CON_SOLIDMEM_ID	0x08
+#define IEC958_AES1_CON_SOLIDMEM_DIGITAL_RECORDER_PLAYER (IEC958_AES1_CON_SOLIDMEM_ID|0x00)
+#define IEC958_AES1_CON_SOLIDMEM_OTHER	(IEC958_AES1_CON_SOLIDMEM_ID|0x70)
+#define IEC958_AES1_CON_EXPERIMENTAL	0x40
 #define IEC958_AES1_CON_ORIGINAL	(1<<7)	/* this bits depends on the category code */
 #define IEC958_AES2_PRO_SBITS		(7<<0)	/* mask - sample bits */
 #define IEC958_AES2_PRO_SBITS_20	(2<<0)	/* 20-bit - coordination */
@@ -106,8 +127,16 @@
 #define IEC958_AES2_CON_CHANNEL_UNSPEC	(0<<4)	/* unspecified */
 #define IEC958_AES3_CON_FS		(15<<0)	/* mask - sample frequency */
 #define IEC958_AES3_CON_FS_44100	(0<<0)	/* 44.1kHz */
+#define IEC958_AES3_CON_FS_NOTID	(1<<0)	/* non indicated */
 #define IEC958_AES3_CON_FS_48000	(2<<0)	/* 48kHz */
 #define IEC958_AES3_CON_FS_32000	(3<<0)	/* 32kHz */
+#define IEC958_AES3_CON_FS_22050	(4<<0)	/* 22.05kHz */
+#define IEC958_AES3_CON_FS_24000	(6<<0)	/* 24kHz */
+#define IEC958_AES3_CON_FS_88200	(8<<0)	/* 88.2kHz */
+#define IEC958_AES3_CON_FS_768000	(9<<0)	/* 768kHz */
+#define IEC958_AES3_CON_FS_96000	(10<<0)	/* 96kHz */
+#define IEC958_AES3_CON_FS_176400	(12<<0)	/* 176.4kHz */
+#define IEC958_AES3_CON_FS_192000	(14<<0)	/* 192kHz */
 #define IEC958_AES3_CON_CLOCK		(3<<4)	/* mask - clock accuracy */
 #define IEC958_AES3_CON_CLOCK_1000PPM	(0<<4)	/* 1000 ppm */
 #define IEC958_AES3_CON_CLOCK_50PPM	(1<<4)	/* 50 ppm */
@@ -120,6 +149,26 @@
 #define IEC958_AES4_CON_WORDLEN_23_19	(4<<1)	/* 23-bit or 19-bit */
 #define IEC958_AES4_CON_WORDLEN_24_20	(5<<1)	/* 24-bit or 20-bit */
 #define IEC958_AES4_CON_WORDLEN_21_17	(6<<1)	/* 21-bit or 17-bit */
+#define IEC958_AES4_CON_ORIGFS		(15<<4)	/* mask - original sample frequency */
+#define IEC958_AES4_CON_ORIGFS_NOTID	(0<<4)	/* not indicated */
+#define IEC958_AES4_CON_ORIGFS_192000	(1<<4)	/* 192kHz */
+#define IEC958_AES4_CON_ORIGFS_12000	(2<<4)	/* 12kHz */
+#define IEC958_AES4_CON_ORIGFS_176400	(3<<4)	/* 176.4kHz */
+#define IEC958_AES4_CON_ORIGFS_96000	(5<<4)	/* 96kHz */
+#define IEC958_AES4_CON_ORIGFS_8000	(6<<4)	/* 8kHz */
+#define IEC958_AES4_CON_ORIGFS_88200	(7<<4)	/* 88.2kHz */
+#define IEC958_AES4_CON_ORIGFS_16000	(8<<4)	/* 16kHz */
+#define IEC958_AES4_CON_ORIGFS_24000	(9<<4)	/* 24kHz */
+#define IEC958_AES4_CON_ORIGFS_11025	(10<<4)	/* 11.025kHz */
+#define IEC958_AES4_CON_ORIGFS_22050	(11<<4)	/* 22.05kHz */
+#define IEC958_AES4_CON_ORIGFS_32000	(12<<4)	/* 32kHz */
+#define IEC958_AES4_CON_ORIGFS_48000	(13<<4)	/* 48kHz */
+#define IEC958_AES4_CON_ORIGFS_44100	(15<<4)	/* 44.1kHz */
+#define IEC958_AES5_CON_CGMSA		(3<<0)	/* mask - CGMS-A */
+#define IEC958_AES5_CON_CGMSA_COPYFREELY (0<<0)	/* copying is permitted without restriction */
+#define IEC958_AES5_CON_CGMSA_COPYONCE	(1<<0)	/* one generation of copies may be made */
+#define IEC958_AES5_CON_CGMSA_COPYNOMORE (2<<0)	/* condition not be used */
+#define IEC958_AES5_CON_CGMSA_COPYNEVER	(3<<0)	/* no copying is permitted */
 
 /*****************************************************************************
  *                                                                           *
diff --git a/include/sound/core.h b/include/sound/core.h
index 558b962..35424a9 100644
--- a/include/sound/core.h
+++ b/include/sound/core.h
@@ -28,6 +28,7 @@
 #include <linux/rwsem.h>		/* struct rw_semaphore */
 #include <linux/pm.h>			/* pm_message_t */
 #include <linux/device.h>
+#include <linux/stringify.h>
 
 /* number of supported soundcards */
 #ifdef CONFIG_SND_DYNAMIC_MINORS
@@ -42,9 +43,6 @@
 #ifdef CONFIG_PCI
 struct pci_dev;
 #endif
-#ifdef CONFIG_SBUS
-struct sbus_dev;
-#endif
 
 /* device allocation stuff */
 
@@ -63,6 +61,7 @@
 #define	SNDRV_DEV_INFO		((__force snd_device_type_t) 0x1006)
 #define	SNDRV_DEV_BUS		((__force snd_device_type_t) 0x1007)
 #define	SNDRV_DEV_CODEC		((__force snd_device_type_t) 0x1008)
+#define	SNDRV_DEV_JACK          ((__force snd_device_type_t) 0x1009)
 #define	SNDRV_DEV_LOWLEVEL	((__force snd_device_type_t) 0x2000)
 
 typedef int __bitwise snd_device_state_t;
@@ -114,7 +113,7 @@
 	char shortname[32];		/* short name of this soundcard */
 	char longname[80];		/* name of this soundcard */
 	char mixername[80];		/* mixer name */
-	char components[80];		/* card components delimited with
+	char components[128];		/* card components delimited with
 								space */
 	struct module *module;		/* top-level module */
 
@@ -366,8 +365,6 @@
 
 #ifdef CONFIG_SND_DEBUG
 
-#define __ASTRING__(x) #x
-
 #ifdef CONFIG_SND_VERBOSE_PRINTK
 /**
  * snd_printd - debug printk
@@ -382,33 +379,15 @@
 #define snd_printd(fmt, args...) \
 	printk(fmt ,##args)
 #endif
-/**
- * snd_assert - run-time assertion macro
- * @expr: expression
- *
- * This macro checks the expression in run-time and invokes the commands
- * given in the rest arguments if the assertion is failed.
- * When CONFIG_SND_DEBUG is not set, the expression is executed but
- * not checked.
- */
-#define snd_assert(expr, args...) do {					\
-	if (unlikely(!(expr))) {					\
-		snd_printk(KERN_ERR "BUG? (%s)\n", __ASTRING__(expr));	\
-		dump_stack();						\
-		args;							\
-	}								\
-} while (0)
 
-#define snd_BUG() do {				\
-	snd_printk(KERN_ERR "BUG?\n");		\
-	dump_stack();				\
-} while (0)
+#define snd_BUG()		WARN(1, "BUG?\n")
+#define snd_BUG_ON(cond)	WARN((cond), "BUG? (%s)\n", __stringify(cond))
 
 #else /* !CONFIG_SND_DEBUG */
 
 #define snd_printd(fmt, args...)	/* nothing */
-#define snd_assert(expr, args...)	(void)(expr)
 #define snd_BUG()			/* nothing */
+#define snd_BUG_ON(cond)	({/*(void)(cond);*/ 0;})  /* always false */
 
 #endif /* CONFIG_SND_DEBUG */
 
diff --git a/include/sound/cs4231.h b/include/sound/cs4231.h
deleted file mode 100644
index f0785f9..0000000
--- a/include/sound/cs4231.h
+++ /dev/null
@@ -1,175 +0,0 @@
-#ifndef __SOUND_CS4231_H
-#define __SOUND_CS4231_H
-
-/*
- *  Copyright (c) by Jaroslav Kysela <perex@perex.cz>
- *  Definitions for CS4231 & InterWave chips & compatible 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
- *
- */
-
-#include "control.h"
-#include "pcm.h"
-#include "timer.h"
-
-#include "cs4231-regs.h"
-
-/* defines for codec.mode */
-
-#define CS4231_MODE_NONE	0x0000
-#define CS4231_MODE_PLAY	0x0001
-#define CS4231_MODE_RECORD	0x0002
-#define CS4231_MODE_TIMER	0x0004
-#define CS4231_MODE_OPEN	(CS4231_MODE_PLAY|CS4231_MODE_RECORD|CS4231_MODE_TIMER)
-
-/* defines for codec.hardware */
-
-#define CS4231_HW_DETECT        0x0000	/* let CS4231 driver detect chip */
-#define CS4231_HW_DETECT3	0x0001	/* allow mode 3 */
-#define CS4231_HW_TYPE_MASK	0xff00	/* type mask */
-#define CS4231_HW_CS4231_MASK   0x0100	/* CS4231 serie */
-#define CS4231_HW_CS4231        0x0100	/* CS4231 chip */
-#define CS4231_HW_CS4231A       0x0101	/* CS4231A chip */
-#define CS4231_HW_AD1845	0x0102	/* AD1845 chip */
-#define CS4231_HW_CS4232_MASK   0x0200	/* CS4232 serie (has control ports) */
-#define CS4231_HW_CS4232        0x0200	/* CS4232 */
-#define CS4231_HW_CS4232A       0x0201	/* CS4232A */
-#define CS4231_HW_CS4236	0x0202	/* CS4236 */
-#define CS4231_HW_CS4236B_MASK	0x0400	/* CS4236B serie (has extended control regs) */
-#define CS4231_HW_CS4235	0x0400	/* CS4235 - Crystal Clear (tm) stereo enhancement */
-#define CS4231_HW_CS4236B       0x0401	/* CS4236B */
-#define CS4231_HW_CS4237B       0x0402	/* CS4237B - SRS 3D */
-#define CS4231_HW_CS4238B	0x0403	/* CS4238B - QSOUND 3D */
-#define CS4231_HW_CS4239	0x0404	/* CS4239 - Crystal Clear (tm) stereo enhancement */
-/* compatible, but clones */
-#define CS4231_HW_INTERWAVE     0x1000	/* InterWave chip */
-#define CS4231_HW_OPL3SA2       0x1101	/* OPL3-SA2 chip, similar to cs4231 */
-#define CS4231_HW_OPTI93X 	0x1102	/* Opti 930/931/933 */
-
-/* defines for codec.hwshare */
-#define CS4231_HWSHARE_IRQ	(1<<0)
-#define CS4231_HWSHARE_DMA1	(1<<1)
-#define CS4231_HWSHARE_DMA2	(1<<2)
-
-struct snd_cs4231 {
-	unsigned long port;		/* base i/o port */
-	struct resource *res_port;
-	unsigned long cport;		/* control base i/o port (CS4236) */
-	struct resource *res_cport;
-	int irq;			/* IRQ line */
-	int dma1;			/* playback DMA */
-	int dma2;			/* record DMA */
-	unsigned short version;		/* version of CODEC chip */
-	unsigned short mode;		/* see to CS4231_MODE_XXXX */
-	unsigned short hardware;	/* see to CS4231_HW_XXXX */
-	unsigned short hwshare;		/* shared resources */
-	unsigned short single_dma:1,	/* forced single DMA mode (GUS 16-bit daughter board) or dma1 == dma2 */
-		       ebus_flag:1;	/* SPARC: EBUS present */
-
-	struct snd_card *card;
-	struct snd_pcm *pcm;
-	struct snd_pcm_substream *playback_substream;
-	struct snd_pcm_substream *capture_substream;
-	struct snd_timer *timer;
-
-	unsigned char image[32];	/* registers image */
-	unsigned char eimage[32];	/* extended registers image */
-	unsigned char cimage[16];	/* control registers image */
-	int mce_bit;
-	int calibrate_mute;
-	int sw_3d_bit;
-	unsigned int p_dma_size;
-	unsigned int c_dma_size;
-
-	spinlock_t reg_lock;
-	struct mutex mce_mutex;
-	struct mutex open_mutex;
-
-	int (*rate_constraint) (struct snd_pcm_runtime *runtime);
-	void (*set_playback_format) (struct snd_cs4231 *chip, struct snd_pcm_hw_params *hw_params, unsigned char pdfr);
-	void (*set_capture_format) (struct snd_cs4231 *chip, struct snd_pcm_hw_params *hw_params, unsigned char cdfr);
-	void (*trigger) (struct snd_cs4231 *chip, unsigned int what, int start);
-#ifdef CONFIG_PM
-	void (*suspend) (struct snd_cs4231 *chip);
-	void (*resume) (struct snd_cs4231 *chip);
-#endif
-	void *dma_private_data;
-	int (*claim_dma) (struct snd_cs4231 *chip, void *dma_private_data, int dma);
-	int (*release_dma) (struct snd_cs4231 *chip, void *dma_private_data, int dma);
-};
-
-/* exported functions */
-
-void snd_cs4231_out(struct snd_cs4231 *chip, unsigned char reg, unsigned char val);
-unsigned char snd_cs4231_in(struct snd_cs4231 *chip, unsigned char reg);
-void snd_cs4236_ext_out(struct snd_cs4231 *chip, unsigned char reg, unsigned char val);
-unsigned char snd_cs4236_ext_in(struct snd_cs4231 *chip, unsigned char reg);
-void snd_cs4231_mce_up(struct snd_cs4231 *chip);
-void snd_cs4231_mce_down(struct snd_cs4231 *chip);
-
-void snd_cs4231_overrange(struct snd_cs4231 *chip);
-
-irqreturn_t snd_cs4231_interrupt(int irq, void *dev_id);
-
-const char *snd_cs4231_chip_id(struct snd_cs4231 *chip);
-
-int snd_cs4231_create(struct snd_card *card,
-		      unsigned long port,
-		      unsigned long cport,
-		      int irq, int dma1, int dma2,
-		      unsigned short hardware,
-		      unsigned short hwshare,
-		      struct snd_cs4231 ** rchip);
-int snd_cs4231_pcm(struct snd_cs4231 * chip, int device, struct snd_pcm **rpcm);
-int snd_cs4231_timer(struct snd_cs4231 * chip, int device, struct snd_timer **rtimer);
-int snd_cs4231_mixer(struct snd_cs4231 * chip);
-
-int snd_cs4236_create(struct snd_card *card,
-		      unsigned long port,
-		      unsigned long cport,
-		      int irq, int dma1, int dma2,
-		      unsigned short hardware,
-		      unsigned short hwshare,
-		      struct snd_cs4231 ** rchip);
-int snd_cs4236_pcm(struct snd_cs4231 * chip, int device, struct snd_pcm **rpcm);
-int snd_cs4236_mixer(struct snd_cs4231 * chip);
-
-/*
- *  mixer library
- */
-
-#define CS4231_SINGLE(xname, xindex, reg, shift, mask, invert) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
-  .info = snd_cs4231_info_single, \
-  .get = snd_cs4231_get_single, .put = snd_cs4231_put_single, \
-  .private_value = reg | (shift << 8) | (mask << 16) | (invert << 24) }
-
-int snd_cs4231_info_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo);
-int snd_cs4231_get_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol);
-int snd_cs4231_put_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol);
-
-#define CS4231_DOUBLE(xname, xindex, left_reg, right_reg, shift_left, shift_right, mask, invert) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
-  .info = snd_cs4231_info_double, \
-  .get = snd_cs4231_get_double, .put = snd_cs4231_put_double, \
-  .private_value = left_reg | (right_reg << 8) | (shift_left << 16) | (shift_right << 19) | (mask << 24) | (invert << 22) }
-
-int snd_cs4231_info_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo);
-int snd_cs4231_get_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol);
-int snd_cs4231_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol);
-
-#endif /* __SOUND_CS4231_H */
diff --git a/include/sound/jack.h b/include/sound/jack.h
new file mode 100644
index 0000000..b1b2b8b
--- /dev/null
+++ b/include/sound/jack.h
@@ -0,0 +1,75 @@
+#ifndef __SOUND_JACK_H
+#define __SOUND_JACK_H
+
+/*
+ *  Jack abstraction layer
+ *
+ *  Copyright 2008 Wolfson Microelectronics plc
+ *
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ *
+ */
+
+#include <sound/core.h>
+
+struct input_dev;
+
+/**
+ * Jack types which can be reported.  These values are used as a
+ * bitmask.
+ */
+enum snd_jack_types {
+	SND_JACK_HEADPHONE	= 0x0001,
+	SND_JACK_MICROPHONE	= 0x0002,
+	SND_JACK_HEADSET	= SND_JACK_HEADPHONE | SND_JACK_MICROPHONE,
+};
+
+struct snd_jack {
+	struct input_dev *input_dev;
+	int registered;
+	int type;
+	const char *id;
+	char name[100];
+};
+
+#ifdef CONFIG_SND_JACK
+
+int snd_jack_new(struct snd_card *card, const char *id, int type,
+		 struct snd_jack **jack);
+void snd_jack_set_parent(struct snd_jack *jack, struct device *parent);
+
+void snd_jack_report(struct snd_jack *jack, int status);
+
+#else
+
+static inline int snd_jack_new(struct snd_card *card, const char *id, int type,
+			       struct snd_jack **jack)
+{
+	return 0;
+}
+
+static inline void snd_jack_set_parent(struct snd_jack *jack,
+				       struct device *parent)
+{
+}
+
+static inline void snd_jack_report(struct snd_jack *jack, int status)
+{
+}
+
+#endif
+
+#endif
diff --git a/include/sound/memalloc.h b/include/sound/memalloc.h
index ae2921d..7ccce94 100644
--- a/include/sound/memalloc.h
+++ b/include/sound/memalloc.h
@@ -37,7 +37,6 @@
 #ifndef snd_dma_pci_data
 #define snd_dma_pci_data(pci)	(&(pci)->dev)
 #define snd_dma_isa_data()	NULL
-#define snd_dma_sbus_data(sbus)	((struct device *)(sbus))
 #define snd_dma_continuous_data(x)	((struct device *)(unsigned long)(x))
 #endif
 
@@ -49,7 +48,6 @@
 #define SNDRV_DMA_TYPE_CONTINUOUS	1	/* continuous no-DMA memory */
 #define SNDRV_DMA_TYPE_DEV		2	/* generic device continuous */
 #define SNDRV_DMA_TYPE_DEV_SG		3	/* generic device SG-buffer */
-#define SNDRV_DMA_TYPE_SBUS		4	/* SBUS continuous */
 
 /*
  * info for buffer allocation
@@ -65,6 +63,11 @@
 /*
  * Scatter-Gather generic device pages
  */
+void *snd_malloc_sgbuf_pages(struct device *device,
+			     size_t size, struct snd_dma_buffer *dmab,
+			     size_t *res_size);
+int snd_free_sgbuf_pages(struct snd_dma_buffer *dmab);
+
 struct snd_sg_page {
 	void *buf;
 	dma_addr_t addr;
@@ -92,9 +95,18 @@
  */
 static inline dma_addr_t snd_sgbuf_get_addr(struct snd_sg_buf *sgbuf, size_t offset)
 {
-	return sgbuf->table[offset >> PAGE_SHIFT].addr + offset % PAGE_SIZE;
+	dma_addr_t addr = sgbuf->table[offset >> PAGE_SHIFT].addr;
+	addr &= PAGE_MASK;
+	return addr + offset % PAGE_SIZE;
 }
 
+/*
+ * return the virtual address at the corresponding offset
+ */
+static inline void *snd_sgbuf_get_ptr(struct snd_sg_buf *sgbuf, size_t offset)
+{
+	return sgbuf->table[offset >> PAGE_SHIFT].buf + offset % PAGE_SIZE;
+}
 
 /* allocate/release a buffer */
 int snd_dma_alloc_pages(int type, struct device *dev, size_t size,
diff --git a/include/sound/minors.h b/include/sound/minors.h
index 46bcd20..a81798a 100644
--- a/include/sound/minors.h
+++ b/include/sound/minors.h
@@ -21,6 +21,8 @@
  *
  */
 
+#define SNDRV_OS_MINORS			256
+
 #define SNDRV_MINOR_DEVICES		32
 #define SNDRV_MINOR_CARD(minor)		((minor) >> 5)
 #define SNDRV_MINOR_DEVICE(minor)	((minor) & 0x001f)
diff --git a/include/sound/pcm.h b/include/sound/pcm.h
index 51d58cc..40c5a6f 100644
--- a/include/sound/pcm.h
+++ b/include/sound/pcm.h
@@ -25,6 +25,7 @@
 
 #include <sound/asound.h>
 #include <sound/memalloc.h>
+#include <sound/minors.h>
 #include <linux/poll.h>
 #include <linux/mm.h>
 #include <linux/bitops.h>
@@ -84,7 +85,11 @@
  *
  */
 
-#define SNDRV_PCM_DEVICES		8
+#if defined(CONFIG_SND_DYNAMIC_MINORS)
+#define SNDRV_PCM_DEVICES	(SNDRV_OS_MINORS-2)
+#else
+#define SNDRV_PCM_DEVICES	8
+#endif
 
 #define SNDRV_PCM_IOCTL1_FALSE		((void *)0)
 #define SNDRV_PCM_IOCTL1_TRUE		((void *)1)
@@ -416,7 +421,7 @@
 struct snd_pcm {
 	struct snd_card *card;
 	struct list_head list;
-	unsigned int device;	/* device number */
+	int device; /* device number */
 	unsigned int info_flags;
 	unsigned short dev_class;
 	unsigned short dev_subclass;
@@ -969,10 +974,30 @@
 int snd_pcm_lib_malloc_pages(struct snd_pcm_substream *substream, size_t size);
 int snd_pcm_lib_free_pages(struct snd_pcm_substream *substream);
 
-#define snd_pcm_substream_sgbuf(substream) ((substream)->runtime->dma_buffer_p->private_data)
-#define snd_pcm_sgbuf_pages(size) snd_sgbuf_aligned_pages(size)
-#define snd_pcm_sgbuf_get_addr(sgbuf,ofs) snd_sgbuf_get_addr(sgbuf,ofs)
-struct page *snd_pcm_sgbuf_ops_page(struct snd_pcm_substream *substream, unsigned long offset);
+/*
+ * SG-buffer handling
+ */
+#define snd_pcm_substream_sgbuf(substream) \
+	((substream)->runtime->dma_buffer_p->private_data)
+
+static inline dma_addr_t
+snd_pcm_sgbuf_get_addr(struct snd_pcm_substream *substream, unsigned int ofs)
+{
+	struct snd_sg_buf *sg = snd_pcm_substream_sgbuf(substream);
+	return snd_sgbuf_get_addr(sg, ofs);
+}
+
+static inline void *
+snd_pcm_sgbuf_get_ptr(struct snd_pcm_substream *substream, unsigned int ofs)
+{
+	struct snd_sg_buf *sg = snd_pcm_substream_sgbuf(substream);
+	return snd_sgbuf_get_ptr(sg, ofs);
+}
+
+struct page *snd_pcm_sgbuf_ops_page(struct snd_pcm_substream *substream,
+				    unsigned long offset);
+unsigned int snd_pcm_sgbuf_get_chunk_size(struct snd_pcm_substream *substream,
+					  unsigned int ofs, unsigned int size);
 
 /* handle mmap counter - PCM mmap callback should handle this counter properly */
 static inline void snd_pcm_mmap_data_open(struct vm_area_struct *area)
@@ -1010,4 +1035,6 @@
 					 (IEC958_AES1_CON_PCM_CODER<<8)|\
 					 (IEC958_AES3_CON_FS_48000<<24))
 
+#define PCM_RUNTIME_CHECK(sub) snd_BUG_ON(!(sub) || !(sub)->runtime)
+
 #endif /* __SOUND_PCM_H */
diff --git a/include/sound/pxa2xx-lib.h b/include/sound/pxa2xx-lib.h
new file mode 100644
index 0000000..2fd3d25
--- /dev/null
+++ b/include/sound/pxa2xx-lib.h
@@ -0,0 +1,45 @@
+#ifndef PXA2XX_LIB_H
+#define PXA2XX_LIB_H
+
+#include <linux/platform_device.h>
+#include <sound/ac97_codec.h>
+
+/* PCM */
+
+struct pxa2xx_pcm_dma_params {
+	char *name;			/* stream identifier */
+	u32 dcmd;			/* DMA descriptor dcmd field */
+	volatile u32 *drcmr;		/* the DMA request channel to use */
+	u32 dev_addr;			/* device physical address for DMA */
+};
+
+extern int __pxa2xx_pcm_hw_params(struct snd_pcm_substream *substream,
+				struct snd_pcm_hw_params *params);
+extern int __pxa2xx_pcm_hw_free(struct snd_pcm_substream *substream);
+extern int pxa2xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd);
+extern snd_pcm_uframes_t pxa2xx_pcm_pointer(struct snd_pcm_substream *substream);
+extern int __pxa2xx_pcm_prepare(struct snd_pcm_substream *substream);
+extern void pxa2xx_pcm_dma_irq(int dma_ch, void *dev_id);
+extern int __pxa2xx_pcm_open(struct snd_pcm_substream *substream);
+extern int __pxa2xx_pcm_close(struct snd_pcm_substream *substream);
+extern int pxa2xx_pcm_mmap(struct snd_pcm_substream *substream,
+	struct vm_area_struct *vma);
+extern int pxa2xx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream);
+extern void pxa2xx_pcm_free_dma_buffers(struct snd_pcm *pcm);
+
+/* AC97 */
+
+extern unsigned short pxa2xx_ac97_read(struct snd_ac97 *ac97, unsigned short reg);
+extern void pxa2xx_ac97_write(struct snd_ac97 *ac97, unsigned short reg, unsigned short val);
+
+extern bool pxa2xx_ac97_try_warm_reset(struct snd_ac97 *ac97);
+extern bool pxa2xx_ac97_try_cold_reset(struct snd_ac97 *ac97);
+extern void pxa2xx_ac97_finish_reset(struct snd_ac97 *ac97);
+
+extern int pxa2xx_ac97_hw_suspend(void);
+extern int pxa2xx_ac97_hw_resume(void);
+
+extern int pxa2xx_ac97_hw_probe(struct platform_device *dev);
+extern void pxa2xx_ac97_hw_remove(struct platform_device *dev);
+
+#endif
diff --git a/include/sound/sb.h b/include/sound/sb.h
index d0c9ed3..85f93c5 100644
--- a/include/sound/sb.h
+++ b/include/sound/sb.h
@@ -240,11 +240,15 @@
 #define SB_DT019X_CAP_MAIN	0x07
 
 #define SB_ALS4000_MONO_IO_CTRL	0x4b
+#define SB_ALS4000_OUT_MIXER_CTRL_2	0x4c
 #define SB_ALS4000_MIC_IN_GAIN	0x4d
+#define SB_ALS4000_ANALOG_REFRNC_VOLT_CTRL 0x4e
 #define SB_ALS4000_FMDAC	0x4f
 #define SB_ALS4000_3D_SND_FX	0x50
 #define SB_ALS4000_3D_TIME_DELAY	0x51
 #define SB_ALS4000_3D_AUTO_MUTE	0x52
+#define SB_ALS4000_ANALOG_BLOCK_CTRL 0x53
+#define SB_ALS4000_3D_DELAYLINE_PATTERN 0x54
 #define SB_ALS4000_QSOUND	0xdb
 
 /* IRQ setting bitmap */
@@ -257,6 +261,7 @@
 #define SB_IRQTYPE_8BIT		0x01
 #define SB_IRQTYPE_16BIT	0x02
 #define SB_IRQTYPE_MPUIN	0x04
+#define ALS4K_IRQTYPE_CR1E_DMA	0x20
 
 /* DMA setting bitmap */
 #define SB_DMASETUP_DMA0	0x01
diff --git a/include/sound/snd_wavefront.h b/include/sound/snd_wavefront.h
index 9688d4b..fa149ca 100644
--- a/include/sound/snd_wavefront.h
+++ b/include/sound/snd_wavefront.h
@@ -1,7 +1,6 @@
 #ifndef __SOUND_SND_WAVEFRONT_H__
 #define __SOUND_SND_WAVEFRONT_H__
 
-#include "cs4231.h"
 #include "mpu401.h"
 #include "hwdep.h"
 #include "rawmidi.h"
diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h
index c1b26fc..ca699a3 100644
--- a/include/sound/soc-dapm.h
+++ b/include/sound/soc-dapm.h
@@ -240,6 +240,7 @@
 /* dapm audio pin control and status */
 int snd_soc_dapm_enable_pin(struct snd_soc_codec *codec, char *pin);
 int snd_soc_dapm_disable_pin(struct snd_soc_codec *codec, char *pin);
+int snd_soc_dapm_nc_pin(struct snd_soc_codec *codec, char *pin);
 int snd_soc_dapm_get_pin_status(struct snd_soc_codec *codec, char *pin);
 int snd_soc_dapm_sync(struct snd_soc_codec *codec);
 
diff --git a/include/sound/soc-of-simple.h b/include/sound/soc-of-simple.h
new file mode 100644
index 0000000..a064e19
--- /dev/null
+++ b/include/sound/soc-of-simple.h
@@ -0,0 +1,25 @@
+/*
+ * OF helpers for ALSA SoC
+ *
+ * Copyright (C) 2008, Secret Lab Technologies Ltd.
+ */
+
+#ifndef _INCLUDE_SOC_OF_H_
+#define _INCLUDE_SOC_OF_H_
+
+#if defined(CONFIG_SND_SOC_OF_SIMPLE) || defined(CONFIG_SND_SOC_OF_SIMPLE_MODULE)
+
+#include <linux/of.h>
+#include <sound/soc.h>
+
+int of_snd_soc_register_codec(struct snd_soc_codec_device *codec_dev,
+			      void *codec_data, struct snd_soc_dai *dai,
+			      struct device_node *node);
+
+int of_snd_soc_register_platform(struct snd_soc_platform *platform,
+				 struct device_node *node,
+				 struct snd_soc_dai *cpu_dai);
+
+#endif
+
+#endif /* _INCLUDE_SOC_OF_H_ */
diff --git a/include/sound/soc.h b/include/sound/soc.h
index 1890d87..a1e0357 100644
--- a/include/sound/soc.h
+++ b/include/sound/soc.h
@@ -26,10 +26,12 @@
 /*
  * Convenience kcontrol builders
  */
-#define SOC_SINGLE_VALUE(reg, shift, max, invert) ((reg) | ((shift) << 8) |\
-	((shift) << 12) | ((max) << 16) | ((invert) << 24))
-#define SOC_SINGLE_VALUE_EXT(reg, max, invert) ((reg) | ((max) << 16) |\
-	((invert) << 31))
+#define SOC_SINGLE_VALUE(xreg, xshift, xmax, xinvert) \
+	((unsigned long)&(struct soc_mixer_control) \
+	{.reg = xreg, .shift = xshift, .max = xmax, .invert = xinvert})
+#define SOC_SINGLE_VALUE_EXT(xreg, xmax, xinvert) \
+	((unsigned long)&(struct soc_mixer_control) \
+	{.reg = xreg, .max = xmax, .invert = xinvert})
 #define SOC_SINGLE(xname, reg, shift, max, invert) \
 {	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
 	.info = snd_soc_info_volsw, .get = snd_soc_get_volsw,\
@@ -43,64 +45,68 @@
 	.info = snd_soc_info_volsw, .get = snd_soc_get_volsw,\
 	.put = snd_soc_put_volsw, \
 	.private_value =  SOC_SINGLE_VALUE(reg, shift, max, invert) }
-#define SOC_DOUBLE(xname, reg, shift_left, shift_right, max, invert) \
+#define SOC_DOUBLE(xname, xreg, shift_left, shift_right, xmax, xinvert) \
 {	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\
 	.info = snd_soc_info_volsw, .get = snd_soc_get_volsw, \
 	.put = snd_soc_put_volsw, \
-	.private_value = (reg) | ((shift_left) << 8) | \
-		((shift_right) << 12) | ((max) << 16) | ((invert) << 24) }
-#define SOC_DOUBLE_R(xname, reg_left, reg_right, shift, max, invert) \
+	.private_value = (unsigned long)&(struct soc_mixer_control) \
+		{.reg = xreg, .shift = shift_left, .rshift = shift_right, \
+		 .max = xmax, .invert = xinvert} }
+#define SOC_DOUBLE_R(xname, reg_left, reg_right, xshift, xmax, xinvert) \
 {	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
 	.info = snd_soc_info_volsw_2r, \
 	.get = snd_soc_get_volsw_2r, .put = snd_soc_put_volsw_2r, \
-	.private_value = (reg_left) | ((shift) << 8)  | \
-		((max) << 12) | ((invert) << 20) | ((reg_right) << 24) }
-#define SOC_DOUBLE_TLV(xname, reg, shift_left, shift_right, max, invert, tlv_array) \
+	.private_value = (unsigned long)&(struct soc_mixer_control) \
+		{.reg = reg_left, .rreg = reg_right, .shift = xshift, \
+		.max = xmax, .invert = xinvert} }
+#define SOC_DOUBLE_TLV(xname, xreg, shift_left, shift_right, xmax, xinvert, tlv_array) \
 {	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\
 	.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\
 		 SNDRV_CTL_ELEM_ACCESS_READWRITE,\
 	.tlv.p = (tlv_array), \
 	.info = snd_soc_info_volsw, .get = snd_soc_get_volsw, \
 	.put = snd_soc_put_volsw, \
-	.private_value = (reg) | ((shift_left) << 8) | \
-		((shift_right) << 12) | ((max) << 16) | ((invert) << 24) }
-#define SOC_DOUBLE_R_TLV(xname, reg_left, reg_right, shift, max, invert, tlv_array) \
+	.private_value = (unsigned long)&(struct soc_mixer_control) \
+		{.reg = xreg, .shift = shift_left, .rshift = shift_right,\
+		 .max = xmax, .invert = xinvert} }
+#define SOC_DOUBLE_R_TLV(xname, reg_left, reg_right, xshift, xmax, xinvert, tlv_array) \
 {	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\
 	.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\
 		 SNDRV_CTL_ELEM_ACCESS_READWRITE,\
 	.tlv.p = (tlv_array), \
 	.info = snd_soc_info_volsw_2r, \
 	.get = snd_soc_get_volsw_2r, .put = snd_soc_put_volsw_2r, \
-	.private_value = (reg_left) | ((shift) << 8)  | \
-		((max) << 12) | ((invert) << 20) | ((reg_right) << 24) }
-#define SOC_DOUBLE_S8_TLV(xname, reg, min, max, tlv_array) \
+	.private_value = (unsigned long)&(struct soc_mixer_control) \
+		{.reg = reg_left, .rreg = reg_right, .shift = xshift, \
+		.max = xmax, .invert = xinvert} }
+#define SOC_DOUBLE_S8_TLV(xname, xreg, xmin, xmax, tlv_array) \
 {	.iface  = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
 	.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
 		  SNDRV_CTL_ELEM_ACCESS_READWRITE, \
 	.tlv.p  = (tlv_array), \
 	.info   = snd_soc_info_volsw_s8, .get = snd_soc_get_volsw_s8, \
 	.put    = snd_soc_put_volsw_s8, \
-	.private_value = (reg) | (((signed char)max) << 16) | \
-			 (((signed char)min) << 24) }
-#define SOC_ENUM_DOUBLE(xreg, xshift_l, xshift_r, xmask, xtexts) \
+	.private_value = (unsigned long)&(struct soc_mixer_control) \
+		{.reg = xreg, .min = xmin, .max = xmax} }
+#define SOC_ENUM_DOUBLE(xreg, xshift_l, xshift_r, xmax, xtexts) \
 {	.reg = xreg, .shift_l = xshift_l, .shift_r = xshift_r, \
-	.mask = xmask, .texts = xtexts }
-#define SOC_ENUM_SINGLE(xreg, xshift, xmask, xtexts) \
-	SOC_ENUM_DOUBLE(xreg, xshift, xshift, xmask, xtexts)
-#define SOC_ENUM_SINGLE_EXT(xmask, xtexts) \
-{	.mask = xmask, .texts = xtexts }
+	.max = xmax, .texts = xtexts }
+#define SOC_ENUM_SINGLE(xreg, xshift, xmax, xtexts) \
+	SOC_ENUM_DOUBLE(xreg, xshift, xshift, xmax, xtexts)
+#define SOC_ENUM_SINGLE_EXT(xmax, xtexts) \
+{	.max = xmax, .texts = xtexts }
 #define SOC_ENUM(xname, xenum) \
 {	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname,\
 	.info = snd_soc_info_enum_double, \
 	.get = snd_soc_get_enum_double, .put = snd_soc_put_enum_double, \
 	.private_value = (unsigned long)&xenum }
-#define SOC_SINGLE_EXT(xname, xreg, xshift, xmask, xinvert,\
+#define SOC_SINGLE_EXT(xname, xreg, xshift, xmax, xinvert,\
 	 xhandler_get, xhandler_put) \
 {	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
 	.info = snd_soc_info_volsw, \
 	.get = xhandler_get, .put = xhandler_put, \
-	.private_value = SOC_SINGLE_VALUE(xreg, xshift, xmask, xinvert) }
-#define SOC_SINGLE_EXT_TLV(xname, xreg, xshift, xmask, xinvert,\
+	.private_value = SOC_SINGLE_VALUE(xreg, xshift, xmax, xinvert) }
+#define SOC_SINGLE_EXT_TLV(xname, xreg, xshift, xmax, xinvert,\
 	 xhandler_get, xhandler_put, tlv_array) \
 {	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
 	.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\
@@ -108,7 +114,7 @@
 	.tlv.p = (tlv_array), \
 	.info = snd_soc_info_volsw, \
 	.get = xhandler_get, .put = xhandler_put, \
-	.private_value = SOC_SINGLE_VALUE(xreg, xshift, xmask, xinvert) }
+	.private_value = SOC_SINGLE_VALUE(xreg, xshift, xmax, xinvert) }
 #define SOC_SINGLE_BOOL_EXT(xname, xdata, xhandler_get, xhandler_put) \
 {	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
 	.info = snd_soc_info_bool_ext, \
@@ -410,6 +416,8 @@
 	void *control_data; /* codec control (i2c/3wire) data */
 	unsigned int (*read)(struct snd_soc_codec *, unsigned int);
 	int (*write)(struct snd_soc_codec *, unsigned int, unsigned int);
+	int (*display_register)(struct snd_soc_codec *, char *,
+				size_t, unsigned int);
 	hw_write_t hw_write;
 	hw_read_t hw_read;
 	void *reg_cache;
@@ -516,13 +524,19 @@
 	struct snd_soc_device *socdev;
 };
 
+/* mixer control */
+struct soc_mixer_control {
+	int min, max;
+	unsigned int reg, rreg, shift, rshift, invert;
+};
+
 /* enumerated kcontrol */
 struct soc_enum {
 	unsigned short reg;
 	unsigned short reg2;
 	unsigned char shift_l;
 	unsigned char shift_r;
-	unsigned int mask;
+	unsigned int max;
 	const char **texts;
 	void *dapm;
 };
diff --git a/include/sound/tea575x-tuner.h b/include/sound/tea575x-tuner.h
index b62ce3e..b6870cb 100644
--- a/include/sound/tea575x-tuner.h
+++ b/include/sound/tea575x-tuner.h
@@ -43,6 +43,7 @@
 	unsigned int freq_fixup;	/* crystal onboard */
 	unsigned int val;		/* hw value */
 	unsigned long freq;		/* frequency */
+	unsigned long in_use;		/* set if the device is in use */
 	struct snd_tea575x_ops *ops;
 	void *private_data;
 };
diff --git a/include/sound/version.h b/include/sound/version.h
index 6b78aff..4aafeda 100644
--- a/include/sound/version.h
+++ b/include/sound/version.h
@@ -1,3 +1,3 @@
 /* include/version.h */
-#define CONFIG_SND_VERSION "1.0.17"
+#define CONFIG_SND_VERSION "1.0.18rc3"
 #define CONFIG_SND_DATE ""
diff --git a/include/sound/vx_core.h b/include/sound/vx_core.h
index 4830651..5456343 100644
--- a/include/sound/vx_core.h
+++ b/include/sound/vx_core.h
@@ -235,37 +235,31 @@
  */
 static inline int vx_test_and_ack(struct vx_core *chip)
 {
-	snd_assert(chip->ops->test_and_ack, return -ENXIO);
 	return chip->ops->test_and_ack(chip);
 }
 
 static inline void vx_validate_irq(struct vx_core *chip, int enable)
 {
-	snd_assert(chip->ops->validate_irq, return);
 	chip->ops->validate_irq(chip, enable);
 }
 
 static inline unsigned char snd_vx_inb(struct vx_core *chip, int reg)
 {
-	snd_assert(chip->ops->in8, return 0);
 	return chip->ops->in8(chip, reg);
 }
 
 static inline unsigned int snd_vx_inl(struct vx_core *chip, int reg)
 {
-	snd_assert(chip->ops->in32, return 0);
 	return chip->ops->in32(chip, reg);
 }
 
 static inline void snd_vx_outb(struct vx_core *chip, int reg, unsigned char val)
 {
-	snd_assert(chip->ops->out8, return);
 	chip->ops->out8(chip, reg, val);
 }
 
 static inline void snd_vx_outl(struct vx_core *chip, int reg, unsigned int val)
 {
-	snd_assert(chip->ops->out32, return);
 	chip->ops->out32(chip, reg, val);
 }
 
@@ -276,7 +270,6 @@
 
 static inline void vx_reset_dsp(struct vx_core *chip)
 {
-	snd_assert(chip->ops->reset_dsp, return);
 	chip->ops->reset_dsp(chip);
 }
 
@@ -304,14 +297,12 @@
 static inline void vx_pseudo_dma_write(struct vx_core *chip, struct snd_pcm_runtime *runtime,
 				       struct vx_pipe *pipe, int count)
 {
-	snd_assert(chip->ops->dma_write, return);
 	chip->ops->dma_write(chip, runtime, pipe, count);
 }
 
 static inline void vx_pseudo_dma_read(struct vx_core *chip, struct snd_pcm_runtime *runtime,
 				      struct vx_pipe *pipe, int count)
 {
-	snd_assert(chip->ops->dma_read, return);
 	chip->ops->dma_read(chip, runtime, pipe, count);
 }
 
diff --git a/include/sound/wss.h b/include/sound/wss.h
new file mode 100644
index 0000000..fd01f22
--- /dev/null
+++ b/include/sound/wss.h
@@ -0,0 +1,235 @@
+#ifndef __SOUND_WSS_H
+#define __SOUND_WSS_H
+
+/*
+ *  Copyright (c) by Jaroslav Kysela <perex@perex.cz>
+ *  Definitions for CS4231 & InterWave chips & compatible 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ *
+ */
+
+#include "control.h"
+#include "pcm.h"
+#include "timer.h"
+
+#include "cs4231-regs.h"
+
+/* defines for codec.mode */
+
+#define WSS_MODE_NONE	0x0000
+#define WSS_MODE_PLAY	0x0001
+#define WSS_MODE_RECORD	0x0002
+#define WSS_MODE_TIMER	0x0004
+#define WSS_MODE_OPEN	(WSS_MODE_PLAY|WSS_MODE_RECORD|WSS_MODE_TIMER)
+
+/* defines for codec.hardware */
+
+#define WSS_HW_DETECT        0x0000	/* let CS4231 driver detect chip */
+#define WSS_HW_DETECT3	0x0001	/* allow mode 3 */
+#define WSS_HW_TYPE_MASK	0xff00	/* type mask */
+#define WSS_HW_CS4231_MASK   0x0100	/* CS4231 serie */
+#define WSS_HW_CS4231        0x0100	/* CS4231 chip */
+#define WSS_HW_CS4231A       0x0101	/* CS4231A chip */
+#define WSS_HW_AD1845	0x0102	/* AD1845 chip */
+#define WSS_HW_CS4232_MASK   0x0200	/* CS4232 serie (has control ports) */
+#define WSS_HW_CS4232        0x0200	/* CS4232 */
+#define WSS_HW_CS4232A       0x0201	/* CS4232A */
+#define WSS_HW_CS4236	0x0202	/* CS4236 */
+#define WSS_HW_CS4236B_MASK	0x0400	/* CS4236B serie (has extended control regs) */
+#define WSS_HW_CS4235	0x0400	/* CS4235 - Crystal Clear (tm) stereo enhancement */
+#define WSS_HW_CS4236B       0x0401	/* CS4236B */
+#define WSS_HW_CS4237B       0x0402	/* CS4237B - SRS 3D */
+#define WSS_HW_CS4238B	0x0403	/* CS4238B - QSOUND 3D */
+#define WSS_HW_CS4239	0x0404	/* CS4239 - Crystal Clear (tm) stereo enhancement */
+#define WSS_HW_AD1848_MASK	0x0800	/* AD1848 serie (half duplex) */
+#define WSS_HW_AD1847		0x0801	/* AD1847 chip */
+#define WSS_HW_AD1848		0x0802	/* AD1848 chip */
+#define WSS_HW_CS4248		0x0803	/* CS4248 chip */
+#define WSS_HW_CMI8330		0x0804	/* CMI8330 chip */
+#define WSS_HW_THINKPAD		0x0805	/* Thinkpad 360/750/755 */
+/* compatible, but clones */
+#define WSS_HW_INTERWAVE     0x1000	/* InterWave chip */
+#define WSS_HW_OPL3SA2       0x1101	/* OPL3-SA2 chip, similar to cs4231 */
+#define WSS_HW_OPTI93X 	0x1102	/* Opti 930/931/933 */
+
+/* defines for codec.hwshare */
+#define WSS_HWSHARE_IRQ	(1<<0)
+#define WSS_HWSHARE_DMA1	(1<<1)
+#define WSS_HWSHARE_DMA2	(1<<2)
+
+/* IBM Thinkpad specific stuff */
+#define AD1848_THINKPAD_CTL_PORT1		0x15e8
+#define AD1848_THINKPAD_CTL_PORT2		0x15e9
+#define AD1848_THINKPAD_CS4248_ENABLE_BIT	0x02
+
+struct snd_wss {
+	unsigned long port;		/* base i/o port */
+	struct resource *res_port;
+	unsigned long cport;		/* control base i/o port (CS4236) */
+	struct resource *res_cport;
+	int irq;			/* IRQ line */
+	int dma1;			/* playback DMA */
+	int dma2;			/* record DMA */
+	unsigned short version;		/* version of CODEC chip */
+	unsigned short mode;		/* see to WSS_MODE_XXXX */
+	unsigned short hardware;	/* see to WSS_HW_XXXX */
+	unsigned short hwshare;		/* shared resources */
+	unsigned short single_dma:1,	/* forced single DMA mode (GUS 16-bit */
+					/* daughter board) or dma1 == dma2 */
+		       ebus_flag:1,	/* SPARC: EBUS present */
+		       thinkpad_flag:1;	/* Thinkpad CS4248 needs extra help */
+
+	struct snd_card *card;
+	struct snd_pcm *pcm;
+	struct snd_pcm_substream *playback_substream;
+	struct snd_pcm_substream *capture_substream;
+	struct snd_timer *timer;
+
+	unsigned char image[32];	/* registers image */
+	unsigned char eimage[32];	/* extended registers image */
+	unsigned char cimage[16];	/* control registers image */
+	int mce_bit;
+	int calibrate_mute;
+	int sw_3d_bit;
+	unsigned int p_dma_size;
+	unsigned int c_dma_size;
+
+	spinlock_t reg_lock;
+	struct mutex mce_mutex;
+	struct mutex open_mutex;
+
+	int (*rate_constraint) (struct snd_pcm_runtime *runtime);
+	void (*set_playback_format) (struct snd_wss *chip,
+				     struct snd_pcm_hw_params *hw_params,
+				     unsigned char pdfr);
+	void (*set_capture_format) (struct snd_wss *chip,
+				    struct snd_pcm_hw_params *hw_params,
+				    unsigned char cdfr);
+	void (*trigger) (struct snd_wss *chip, unsigned int what, int start);
+#ifdef CONFIG_PM
+	void (*suspend) (struct snd_wss *chip);
+	void (*resume) (struct snd_wss *chip);
+#endif
+	void *dma_private_data;
+	int (*claim_dma) (struct snd_wss *chip,
+			  void *dma_private_data, int dma);
+	int (*release_dma) (struct snd_wss *chip,
+			    void *dma_private_data, int dma);
+};
+
+/* exported functions */
+
+void snd_wss_out(struct snd_wss *chip, unsigned char reg, unsigned char val);
+unsigned char snd_wss_in(struct snd_wss *chip, unsigned char reg);
+void snd_cs4236_ext_out(struct snd_wss *chip,
+			unsigned char reg, unsigned char val);
+unsigned char snd_cs4236_ext_in(struct snd_wss *chip, unsigned char reg);
+void snd_wss_mce_up(struct snd_wss *chip);
+void snd_wss_mce_down(struct snd_wss *chip);
+
+void snd_wss_overrange(struct snd_wss *chip);
+
+irqreturn_t snd_wss_interrupt(int irq, void *dev_id);
+
+const char *snd_wss_chip_id(struct snd_wss *chip);
+
+int snd_wss_create(struct snd_card *card,
+		      unsigned long port,
+		      unsigned long cport,
+		      int irq, int dma1, int dma2,
+		      unsigned short hardware,
+		      unsigned short hwshare,
+		      struct snd_wss **rchip);
+int snd_wss_pcm(struct snd_wss *chip, int device, struct snd_pcm **rpcm);
+int snd_wss_timer(struct snd_wss *chip, int device, struct snd_timer **rtimer);
+int snd_wss_mixer(struct snd_wss *chip);
+
+const struct snd_pcm_ops *snd_wss_get_pcm_ops(int direction);
+
+int snd_cs4236_create(struct snd_card *card,
+		      unsigned long port,
+		      unsigned long cport,
+		      int irq, int dma1, int dma2,
+		      unsigned short hardware,
+		      unsigned short hwshare,
+		      struct snd_wss **rchip);
+int snd_cs4236_pcm(struct snd_wss *chip, int device, struct snd_pcm **rpcm);
+int snd_cs4236_mixer(struct snd_wss *chip);
+
+/*
+ *  mixer library
+ */
+
+#define WSS_SINGLE(xname, xindex, reg, shift, mask, invert) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+  .name = xname, \
+  .index = xindex, \
+  .info = snd_wss_info_single, \
+  .get = snd_wss_get_single, \
+  .put = snd_wss_put_single, \
+  .private_value = reg | (shift << 8) | (mask << 16) | (invert << 24) }
+
+int snd_wss_info_single(struct snd_kcontrol *kcontrol,
+			struct snd_ctl_elem_info *uinfo);
+int snd_wss_get_single(struct snd_kcontrol *kcontrol,
+			struct snd_ctl_elem_value *ucontrol);
+int snd_wss_put_single(struct snd_kcontrol *kcontrol,
+			struct snd_ctl_elem_value *ucontrol);
+
+#define WSS_DOUBLE(xname, xindex, left_reg, right_reg, shift_left, shift_right, mask, invert) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+  .name = xname, \
+  .index = xindex, \
+  .info = snd_wss_info_double, \
+  .get = snd_wss_get_double, \
+  .put = snd_wss_put_double, \
+  .private_value = left_reg | (right_reg << 8) | (shift_left << 16) | \
+		   (shift_right << 19) | (mask << 24) | (invert << 22) }
+
+#define WSS_SINGLE_TLV(xname, xindex, reg, shift, mask, invert, xtlv) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+  .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \
+  .name = xname, \
+  .index = xindex, \
+  .info = snd_wss_info_single, \
+  .get = snd_wss_get_single, \
+  .put = snd_wss_put_single, \
+  .private_value = reg | (shift << 8) | (mask << 16) | (invert << 24), \
+  .tlv = { .p = (xtlv) } }
+
+#define WSS_DOUBLE_TLV(xname, xindex, left_reg, right_reg, \
+			shift_left, shift_right, mask, invert, xtlv) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+  .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \
+  .name = xname, \
+  .index = xindex, \
+  .info = snd_wss_info_double, \
+  .get = snd_wss_get_double, \
+  .put = snd_wss_put_double, \
+  .private_value = left_reg | (right_reg << 8) | (shift_left << 16) | \
+		   (shift_right << 19) | (mask << 24) | (invert << 22), \
+  .tlv = { .p = (xtlv) } }
+
+
+int snd_wss_info_double(struct snd_kcontrol *kcontrol,
+			struct snd_ctl_elem_info *uinfo);
+int snd_wss_get_double(struct snd_kcontrol *kcontrol,
+			struct snd_ctl_elem_value *ucontrol);
+int snd_wss_put_double(struct snd_kcontrol *kcontrol,
+			struct snd_ctl_elem_value *ucontrol);
+
+#endif /* __SOUND_WSS_H */
diff --git a/include/video/atmel_lcdc.h b/include/video/atmel_lcdc.h
index 920c4e9..6ad87f4 100644
--- a/include/video/atmel_lcdc.h
+++ b/include/video/atmel_lcdc.h
@@ -30,6 +30,7 @@
  */
 #define ATMEL_LCDC_WIRING_BGR	0
 #define ATMEL_LCDC_WIRING_RGB	1
+#define ATMEL_LCDC_WIRING_RGB555	2
 
 
  /* LCD Controller info data structure, stored in device platform_data */
diff --git a/include/video/metronomefb.h b/include/video/metronomefb.h
index dab04b4..9863f4b 100644
--- a/include/video/metronomefb.h
+++ b/include/video/metronomefb.h
@@ -12,14 +12,6 @@
 #ifndef _LINUX_METRONOMEFB_H_
 #define _LINUX_METRONOMEFB_H_
 
-/* address and control descriptors used by metronome controller */
-struct metromem_desc {
-	u32 mFDADR0;
-	u32 mFSADR0;
-	u32 mFIDR0;
-	u32 mLDCMD0;
-};
-
 /* command structure used by metronome controller */
 struct metromem_cmd {
 	u16 opcode;
@@ -29,34 +21,37 @@
 
 /* struct used by metronome. board specific stuff comes from *board */
 struct metronomefb_par {
-	unsigned char *metromem;
-	struct metromem_desc *metromem_desc;
 	struct metromem_cmd *metromem_cmd;
 	unsigned char *metromem_wfm;
 	unsigned char *metromem_img;
 	u16 *metromem_img_csum;
 	u16 *csum_table;
-	int metromemsize;
 	dma_addr_t metromem_dma;
-	dma_addr_t metromem_desc_dma;
 	struct fb_info *info;
 	struct metronome_board *board;
 	wait_queue_head_t waitq;
 	u8 frame_count;
+	int extra_size;
+	int dt;
 };
 
-/* board specific routines */
+/* board specific routines and data */
 struct metronome_board {
-	struct module *owner;
-	void (*free_irq)(struct fb_info *);
-	void (*init_gpio_regs)(struct metronomefb_par *);
-	void (*init_lcdc_regs)(struct metronomefb_par *);
-	void (*post_dma_setup)(struct metronomefb_par *);
+	struct module *owner; /* the platform device */
 	void (*set_rst)(struct metronomefb_par *, int);
 	void (*set_stdby)(struct metronomefb_par *, int);
+	void (*cleanup)(struct metronomefb_par *);
 	int (*met_wait_event)(struct metronomefb_par *);
 	int (*met_wait_event_intr)(struct metronomefb_par *);
 	int (*setup_irq)(struct fb_info *);
+	int (*setup_fb)(struct metronomefb_par *);
+	int (*setup_io)(struct metronomefb_par *);
+	int (*get_panel_type)(void);
+	unsigned char *metromem;
+	int fw;
+	int fh;
+	int wfm_size;
+	struct fb_info *host_fbinfo; /* the host LCD controller's fbi */
 };
 
 #endif
diff --git a/include/xen/balloon.h b/include/xen/balloon.h
deleted file mode 100644
index fe43b0f..0000000
--- a/include/xen/balloon.h
+++ /dev/null
@@ -1,61 +0,0 @@
-/******************************************************************************
- * balloon.h
- *
- * Xen balloon driver - enables returning/claiming memory to/from Xen.
- *
- * Copyright (c) 2003, B Dragovic
- * Copyright (c) 2003-2004, M Williamson, K Fraser
- *
- * 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; or, when distributed
- * separately from the Linux kernel or incorporated into other
- * software packages, subject to the following license:
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this source file (the "Software"), to deal in the Software without
- * restriction, including without limitation the rights to use, copy, modify,
- * merge, publish, distribute, sublicense, and/or sell copies of the Software,
- * and to permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- * IN THE SOFTWARE.
- */
-
-#ifndef __XEN_BALLOON_H__
-#define __XEN_BALLOON_H__
-
-#include <linux/spinlock.h>
-
-#if 0
-/*
- * Inform the balloon driver that it should allow some slop for device-driver
- * memory activities.
- */
-void balloon_update_driver_allowance(long delta);
-
-/* Allocate/free a set of empty pages in low memory (i.e., no RAM mapped). */
-struct page **alloc_empty_pages_and_pagevec(int nr_pages);
-void free_empty_pages_and_pagevec(struct page **pagevec, int nr_pages);
-
-void balloon_release_driver_page(struct page *page);
-
-/*
- * Prevent the balloon driver from changing the memory reservation during
- * a driver critical region.
- */
-extern spinlock_t balloon_lock;
-#define balloon_lock(__flags)   spin_lock_irqsave(&balloon_lock, __flags)
-#define balloon_unlock(__flags) spin_unlock_irqrestore(&balloon_lock, __flags)
-#endif
-
-#endif /* __XEN_BALLOON_H__ */
diff --git a/include/xen/events.h b/include/xen/events.h
index 4680ff3..0d5f1ad 100644
--- a/include/xen/events.h
+++ b/include/xen/events.h
@@ -46,6 +46,8 @@
 
 /* Clear an irq's pending state, in preparation for polling on it */
 void xen_clear_irq_pending(int irq);
+void xen_set_irq_pending(int irq);
+bool xen_test_irq_pending(int irq);
 
 /* Poll waiting for an irq to become pending.  In the usual case, the
    irq will be disabled so it won't deliver an interrupt. */
diff --git a/init/Kconfig b/init/Kconfig
index c11da38..8a8e2d0 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -779,16 +779,6 @@
 
 source "arch/Kconfig"
 
-config PROC_PAGE_MONITOR
- 	default y
-	depends on PROC_FS && MMU
-	bool "Enable /proc page monitoring" if EMBEDDED
- 	help
-	  Various /proc files exist to monitor process memory utilization:
-	  /proc/pid/smaps, /proc/pid/clear_refs, /proc/pid/pagemap,
-	  /proc/kpagecount, and /proc/kpageflags. Disabling these
-          interfaces will reduce the size of the kernel by approximately 4kb.
-
 endmenu		# General setup
 
 config HAVE_GENERIC_DMA_COHERENT
diff --git a/init/do_mounts.c b/init/do_mounts.c
index 3715feb..d055b19 100644
--- a/init/do_mounts.c
+++ b/init/do_mounts.c
@@ -263,6 +263,10 @@
 		printk("Please append a correct \"root=\" boot option; here are the available partitions:\n");
 
 		printk_all_partitions();
+#ifdef CONFIG_DEBUG_BLOCK_EXT_DEVT
+		printk("DEBUG_BLOCK_EXT_DEVT is enabled, you need to specify "
+		       "explicit textual name for \"root=\" boot option.\n");
+#endif
 		panic("VFS: Unable to mount root fs on %s", b);
 	}
 
diff --git a/init/do_mounts_md.c b/init/do_mounts_md.c
index 693d246..48b3fad 100644
--- a/init/do_mounts_md.c
+++ b/init/do_mounts_md.c
@@ -12,7 +12,12 @@
  * The code for that is here.
  */
 
-static int __initdata raid_noautodetect, raid_autopart;
+#ifdef CONFIG_MD_AUTODETECT
+static int __initdata raid_noautodetect;
+#else
+static int __initdata raid_noautodetect=1;
+#endif
+static int __initdata raid_autopart;
 
 static struct {
 	int minor;
@@ -252,6 +257,8 @@
 
 		if (!strncmp(str, "noautodetect", wlen))
 			raid_noautodetect = 1;
+		if (!strncmp(str, "autodetect", wlen))
+			raid_noautodetect = 0;
 		if (strncmp(str, "partitionable", wlen)==0)
 			raid_autopart = 1;
 		if (strncmp(str, "part", wlen)==0)
@@ -264,17 +271,32 @@
 __setup("raid=", raid_setup);
 __setup("md=", md_setup);
 
+static void autodetect_raid(void)
+{
+	int fd;
+
+	/*
+	 * Since we don't want to detect and use half a raid array, we need to
+	 * wait for the known devices to complete their probing
+	 */
+	printk(KERN_INFO "md: Waiting for all devices to be available before autodetect\n");
+	printk(KERN_INFO "md: If you don't use raid, use raid=noautodetect\n");
+	while (driver_probe_done() < 0)
+		msleep(100);
+	fd = sys_open("/dev/md0", 0, 0);
+	if (fd >= 0) {
+		sys_ioctl(fd, RAID_AUTORUN, raid_autopart);
+		sys_close(fd);
+	}
+}
+
 void __init md_run_setup(void)
 {
 	create_dev("/dev/md0", MKDEV(MD_MAJOR, 0));
+
 	if (raid_noautodetect)
-		printk(KERN_INFO "md: Skipping autodetection of RAID arrays. (raid=noautodetect)\n");
-	else {
-		int fd = sys_open("/dev/md0", 0, 0);
-		if (fd >= 0) {
-			sys_ioctl(fd, RAID_AUTORUN, raid_autopart);
-			sys_close(fd);
-		}
-	}
+		printk(KERN_INFO "md: Skipping autodetection of RAID arrays. (raid=autodetect will force)\n");
+	else
+		autodetect_raid();
 	md_setup_drive();
 }
diff --git a/init/main.c b/init/main.c
index f6f7042..27f6bf6 100644
--- a/init/main.c
+++ b/init/main.c
@@ -708,7 +708,7 @@
 	int result;
 
 	if (initcall_debug) {
-		print_fn_descriptor_symbol("calling  %s\n", fn);
+		printk("calling  %pF @ %i\n", fn, task_pid_nr(current));
 		t0 = ktime_get();
 	}
 
@@ -718,8 +718,8 @@
 		t1 = ktime_get();
 		delta = ktime_sub(t1, t0);
 
-		print_fn_descriptor_symbol("initcall %s", fn);
-		printk(" returned %d after %Ld msecs\n", result,
+		printk("initcall %pF returned %d after %Ld msecs\n",
+			fn, result,
 			(unsigned long long) delta.tv64 >> 20);
 	}
 
@@ -737,8 +737,7 @@
 		local_irq_enable();
 	}
 	if (msgbuf[0]) {
-		print_fn_descriptor_symbol(KERN_WARNING "initcall %s", fn);
-		printk(" returned with %s\n", msgbuf);
+		printk("initcall %pF returned with %s\n", fn, msgbuf);
 	}
 
 	return result;
diff --git a/kernel/acct.c b/kernel/acct.c
index dd68b90..f6006a6 100644
--- a/kernel/acct.c
+++ b/kernel/acct.c
@@ -548,7 +548,7 @@
 #endif
 
 	spin_lock_irq(&current->sighand->siglock);
-	tty = current->signal->tty;
+	tty = current->signal->tty;	/* Safe as we hold the siglock */
 	ac.ac_tty = tty ? old_encode_dev(tty_devnum(tty)) : 0;
 	ac.ac_utime = encode_comp_t(jiffies_to_AHZ(cputime_to_jiffies(pacct->ac_utime)));
 	ac.ac_stime = encode_comp_t(jiffies_to_AHZ(cputime_to_jiffies(pacct->ac_stime)));
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index 59cedfb..cf5bc2f 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -246,8 +246,8 @@
 	unsigned n;
 	if (unlikely(!ctx))
 		return 0;
-
 	n = ctx->major;
+
 	switch (audit_classify_syscall(ctx->arch, n)) {
 	case 0:	/* native */
 		if ((mask & AUDIT_PERM_WRITE) &&
@@ -1204,13 +1204,13 @@
 				 (context->return_valid==AUDITSC_SUCCESS)?"yes":"no",
 				 context->return_code);
 
-	mutex_lock(&tty_mutex);
-	read_lock(&tasklist_lock);
+	spin_lock_irq(&tsk->sighand->siglock);
 	if (tsk->signal && tsk->signal->tty && tsk->signal->tty->name)
 		tty = tsk->signal->tty->name;
 	else
 		tty = "(none)";
-	read_unlock(&tasklist_lock);
+	spin_unlock_irq(&tsk->sighand->siglock);
+
 	audit_log_format(ab,
 		  " a0=%lx a1=%lx a2=%lx a3=%lx items=%d"
 		  " ppid=%d pid=%d auid=%u uid=%u gid=%u"
@@ -1230,7 +1230,6 @@
 		  context->egid, context->sgid, context->fsgid, tty,
 		  tsk->sessionid);
 
-	mutex_unlock(&tty_mutex);
 
 	audit_log_task_info(ab, tsk);
 	if (context->filterkey) {
diff --git a/kernel/cgroup.c b/kernel/cgroup.c
index 13932abd..a0123d7 100644
--- a/kernel/cgroup.c
+++ b/kernel/cgroup.c
@@ -2738,14 +2738,15 @@
  */
 void cgroup_mm_owner_callbacks(struct task_struct *old, struct task_struct *new)
 {
-	struct cgroup *oldcgrp, *newcgrp;
+	struct cgroup *oldcgrp, *newcgrp = NULL;
 
 	if (need_mm_owner_callback) {
 		int i;
 		for (i = 0; i < CGROUP_SUBSYS_COUNT; i++) {
 			struct cgroup_subsys *ss = subsys[i];
 			oldcgrp = task_cgroup(old, ss->subsys_id);
-			newcgrp = task_cgroup(new, ss->subsys_id);
+			if (new)
+				newcgrp = task_cgroup(new, ss->subsys_id);
 			if (oldcgrp == newcgrp)
 				continue;
 			if (ss->mm_owner_changed)
diff --git a/kernel/cpu.c b/kernel/cpu.c
index f17e985..86d4904 100644
--- a/kernel/cpu.c
+++ b/kernel/cpu.c
@@ -199,13 +199,14 @@
 	struct take_cpu_down_param *param = _param;
 	int err;
 
-	raw_notifier_call_chain(&cpu_chain, CPU_DYING | param->mod,
-				param->hcpu);
 	/* Ensure this CPU doesn't handle any more interrupts. */
 	err = __cpu_disable();
 	if (err < 0)
 		return err;
 
+	raw_notifier_call_chain(&cpu_chain, CPU_DYING | param->mod,
+				param->hcpu);
+
 	/* Force idle task to run as soon as we yield: it should
 	   immediately notice cpu is offline and die quickly. */
 	sched_idle_next();
@@ -453,6 +454,25 @@
 }
 #endif /* CONFIG_PM_SLEEP_SMP */
 
+/**
+ * notify_cpu_starting(cpu) - call the CPU_STARTING notifiers
+ * @cpu: cpu that just started
+ *
+ * This function calls the cpu_chain notifiers with CPU_STARTING.
+ * It must be called by the arch code on the new cpu, before the new cpu
+ * enables interrupts and before the "boot" cpu returns from __cpu_up().
+ */
+void notify_cpu_starting(unsigned int cpu)
+{
+	unsigned long val = CPU_STARTING;
+
+#ifdef CONFIG_PM_SLEEP_SMP
+	if (cpu_isset(cpu, frozen_cpus))
+		val = CPU_STARTING_FROZEN;
+#endif /* CONFIG_PM_SLEEP_SMP */
+	raw_notifier_call_chain(&cpu_chain, val, (void *)(long)cpu);
+}
+
 #endif /* CONFIG_SMP */
 
 /*
diff --git a/kernel/cpuset.c b/kernel/cpuset.c
index 827cd9ad..eab7bd66 100644
--- a/kernel/cpuset.c
+++ b/kernel/cpuset.c
@@ -1921,7 +1921,7 @@
  * that has tasks along with an empty 'mems'.  But if we did see such
  * a cpuset, we'd handle it just like we do if its 'cpus' was empty.
  */
-static void scan_for_empty_cpusets(const struct cpuset *root)
+static void scan_for_empty_cpusets(struct cpuset *root)
 {
 	LIST_HEAD(queue);
 	struct cpuset *cp;	/* scans cpusets being updated */
diff --git a/kernel/dma-coherent.c b/kernel/dma-coherent.c
index c1d4d5b..f013a0c 100644
--- a/kernel/dma-coherent.c
+++ b/kernel/dma-coherent.c
@@ -124,6 +124,7 @@
 	}
 	return (mem != NULL);
 }
+EXPORT_SYMBOL(dma_alloc_from_coherent);
 
 /**
  * dma_release_from_coherent() - try to free the memory allocated from per-device coherent memory pool
@@ -151,3 +152,4 @@
 	}
 	return 0;
 }
+EXPORT_SYMBOL(dma_release_from_coherent);
diff --git a/kernel/exit.c b/kernel/exit.c
index 1639564..85a83c8 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -583,8 +583,6 @@
 	 * If there are other users of the mm and the owner (us) is exiting
 	 * we need to find a new owner to take on the responsibility.
 	 */
-	if (!mm)
-		return 0;
 	if (atomic_read(&mm->mm_users) <= 1)
 		return 0;
 	if (mm->owner != p)
@@ -627,6 +625,16 @@
 	} while_each_thread(g, c);
 
 	read_unlock(&tasklist_lock);
+	/*
+	 * We found no owner yet mm_users > 1: this implies that we are
+	 * most likely racing with swapoff (try_to_unuse()) or /proc or
+	 * ptrace or page migration (get_task_mm()).  Mark owner as NULL,
+	 * so that subsystems can understand the callback and take action.
+	 */
+	down_write(&mm->mmap_sem);
+	cgroup_mm_owner_callbacks(mm->owner, NULL);
+	mm->owner = NULL;
+	up_write(&mm->mmap_sem);
 	return;
 
 assign_new_owner:
diff --git a/kernel/fork.c b/kernel/fork.c
index 7ce2ebe..30de644 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -802,6 +802,7 @@
 
 	sig->leader = 0;	/* session leadership doesn't inherit */
 	sig->tty_old_pgrp = NULL;
+	sig->tty = NULL;
 
 	sig->utime = sig->stime = sig->cutime = sig->cstime = cputime_zero;
 	sig->gtime = cputime_zero;
@@ -838,6 +839,7 @@
 void __cleanup_signal(struct signal_struct *sig)
 {
 	exit_thread_group_keys(sig);
+	tty_kref_put(sig->tty);
 	kmem_cache_free(signal_cachep, sig);
 }
 
@@ -1227,7 +1229,8 @@
 				p->nsproxy->pid_ns->child_reaper = p;
 
 			p->signal->leader_pid = pid;
-			p->signal->tty = current->signal->tty;
+			tty_kref_put(p->signal->tty);
+			p->signal->tty = tty_kref_get(current->signal->tty);
 			set_task_pgrp(p, task_pgrp_nr(current));
 			set_task_session(p, task_session_nr(current));
 			attach_pid(p, PIDTYPE_PGID, task_pgrp(current));
diff --git a/kernel/hrtimer.c b/kernel/hrtimer.c
index b8e4dce..cdec83e 100644
--- a/kernel/hrtimer.c
+++ b/kernel/hrtimer.c
@@ -672,13 +672,14 @@
 			 */
 			BUG_ON(timer->function(timer) != HRTIMER_NORESTART);
 			return 1;
-		case HRTIMER_CB_IRQSAFE_NO_SOFTIRQ:
+		case HRTIMER_CB_IRQSAFE_PERCPU:
+		case HRTIMER_CB_IRQSAFE_UNLOCKED:
 			/*
 			 * This is solely for the sched tick emulation with
 			 * dynamic tick support to ensure that we do not
 			 * restart the tick right on the edge and end up with
 			 * the tick timer in the softirq ! The calling site
-			 * takes care of this.
+			 * takes care of this. Also used for hrtimer sleeper !
 			 */
 			debug_hrtimer_deactivate(timer);
 			return 1;
@@ -1245,7 +1246,8 @@
 	timer_stats_account_hrtimer(timer);
 
 	fn = timer->function;
-	if (timer->cb_mode == HRTIMER_CB_IRQSAFE_NO_SOFTIRQ) {
+	if (timer->cb_mode == HRTIMER_CB_IRQSAFE_PERCPU ||
+	    timer->cb_mode == HRTIMER_CB_IRQSAFE_UNLOCKED) {
 		/*
 		 * Used for scheduler timers, avoid lock inversion with
 		 * rq->lock and tasklist_lock.
@@ -1452,7 +1454,7 @@
 	sl->timer.function = hrtimer_wakeup;
 	sl->task = task;
 #ifdef CONFIG_HIGH_RES_TIMERS
-	sl->timer.cb_mode = HRTIMER_CB_IRQSAFE_NO_SOFTIRQ;
+	sl->timer.cb_mode = HRTIMER_CB_IRQSAFE_UNLOCKED;
 #endif
 }
 
@@ -1591,29 +1593,95 @@
 
 #ifdef CONFIG_HOTPLUG_CPU
 
-static void migrate_hrtimer_list(struct hrtimer_clock_base *old_base,
-				struct hrtimer_clock_base *new_base)
+static int migrate_hrtimer_list(struct hrtimer_clock_base *old_base,
+				struct hrtimer_clock_base *new_base, int dcpu)
 {
 	struct hrtimer *timer;
 	struct rb_node *node;
+	int raise = 0;
 
 	while ((node = rb_first(&old_base->active))) {
 		timer = rb_entry(node, struct hrtimer, node);
 		BUG_ON(hrtimer_callback_running(timer));
 		debug_hrtimer_deactivate(timer);
-		__remove_hrtimer(timer, old_base, HRTIMER_STATE_INACTIVE, 0);
+
+		/*
+		 * Should not happen. Per CPU timers should be
+		 * canceled _before_ the migration code is called
+		 */
+		if (timer->cb_mode == HRTIMER_CB_IRQSAFE_PERCPU) {
+			__remove_hrtimer(timer, old_base,
+					 HRTIMER_STATE_INACTIVE, 0);
+			WARN(1, "hrtimer (%p %p)active but cpu %d dead\n",
+			     timer, timer->function, dcpu);
+			continue;
+		}
+
+		/*
+		 * Mark it as STATE_MIGRATE not INACTIVE otherwise the
+		 * timer could be seen as !active and just vanish away
+		 * under us on another CPU
+		 */
+		__remove_hrtimer(timer, old_base, HRTIMER_STATE_MIGRATE, 0);
 		timer->base = new_base;
 		/*
 		 * Enqueue the timer. Allow reprogramming of the event device
 		 */
 		enqueue_hrtimer(timer, new_base, 1);
+
+#ifdef CONFIG_HIGH_RES_TIMERS
+		/*
+		 * Happens with high res enabled when the timer was
+		 * already expired and the callback mode is
+		 * HRTIMER_CB_IRQSAFE_UNLOCKED (hrtimer_sleeper). The
+		 * enqueue code does not move them to the soft irq
+		 * pending list for performance/latency reasons, but
+		 * in the migration state, we need to do that
+		 * otherwise we end up with a stale timer.
+		 */
+		if (timer->state == HRTIMER_STATE_MIGRATE) {
+			timer->state = HRTIMER_STATE_PENDING;
+			list_add_tail(&timer->cb_entry,
+				      &new_base->cpu_base->cb_pending);
+			raise = 1;
+		}
+#endif
+		/* Clear the migration state bit */
+		timer->state &= ~HRTIMER_STATE_MIGRATE;
 	}
+	return raise;
 }
 
+#ifdef CONFIG_HIGH_RES_TIMERS
+static int migrate_hrtimer_pending(struct hrtimer_cpu_base *old_base,
+				   struct hrtimer_cpu_base *new_base)
+{
+	struct hrtimer *timer;
+	int raise = 0;
+
+	while (!list_empty(&old_base->cb_pending)) {
+		timer = list_entry(old_base->cb_pending.next,
+				   struct hrtimer, cb_entry);
+
+		__remove_hrtimer(timer, timer->base, HRTIMER_STATE_PENDING, 0);
+		timer->base = &new_base->clock_base[timer->base->index];
+		list_add_tail(&timer->cb_entry, &new_base->cb_pending);
+		raise = 1;
+	}
+	return raise;
+}
+#else
+static int migrate_hrtimer_pending(struct hrtimer_cpu_base *old_base,
+				   struct hrtimer_cpu_base *new_base)
+{
+	return 0;
+}
+#endif
+
 static void migrate_hrtimers(int cpu)
 {
 	struct hrtimer_cpu_base *old_base, *new_base;
-	int i;
+	int i, raise = 0;
 
 	BUG_ON(cpu_online(cpu));
 	old_base = &per_cpu(hrtimer_bases, cpu);
@@ -1626,14 +1694,21 @@
 	spin_lock_nested(&old_base->lock, SINGLE_DEPTH_NESTING);
 
 	for (i = 0; i < HRTIMER_MAX_CLOCK_BASES; i++) {
-		migrate_hrtimer_list(&old_base->clock_base[i],
-				     &new_base->clock_base[i]);
+		if (migrate_hrtimer_list(&old_base->clock_base[i],
+					 &new_base->clock_base[i], cpu))
+			raise = 1;
 	}
 
+	if (migrate_hrtimer_pending(old_base, new_base))
+		raise = 1;
+
 	spin_unlock(&old_base->lock);
 	spin_unlock(&new_base->lock);
 	local_irq_enable();
 	put_cpu_var(hrtimer_bases);
+
+	if (raise)
+		hrtimer_raise_softirq();
 }
 #endif /* CONFIG_HOTPLUG_CPU */
 
diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c
index 0314074..60c49e3 100644
--- a/kernel/irq/manage.c
+++ b/kernel/irq/manage.c
@@ -89,7 +89,14 @@
 	set_balance_irq_affinity(irq, cpumask);
 
 #ifdef CONFIG_GENERIC_PENDING_IRQ
-	set_pending_irq(irq, cpumask);
+	if (desc->status & IRQ_MOVE_PCNTXT) {
+		unsigned long flags;
+
+		spin_lock_irqsave(&desc->lock, flags);
+		desc->chip->set_affinity(irq, cpumask);
+		spin_unlock_irqrestore(&desc->lock, flags);
+	} else
+		set_pending_irq(irq, cpumask);
 #else
 	desc->affinity = cpumask;
 	desc->chip->set_affinity(irq, cpumask);
diff --git a/kernel/kexec.c b/kernel/kexec.c
index 59f3f0df3..aef2653 100644
--- a/kernel/kexec.c
+++ b/kernel/kexec.c
@@ -753,8 +753,14 @@
 			*old = addr | (*old & ~PAGE_MASK);
 
 			/* The old page I have found cannot be a
-			 * destination page, so return it.
+			 * destination page, so return it if it's
+			 * gfp_flags honor the ones passed in.
 			 */
+			if (!(gfp_mask & __GFP_HIGHMEM) &&
+			    PageHighMem(old_page)) {
+				kimage_free_pages(old_page);
+				continue;
+			}
 			addr = old_addr;
 			page = old_page;
 			break;
diff --git a/kernel/kgdb.c b/kernel/kgdb.c
index eaa21fc..e4dcfb2 100644
--- a/kernel/kgdb.c
+++ b/kernel/kgdb.c
@@ -488,7 +488,7 @@
 		if (err)
 			return err;
 		if (CACHE_FLUSH_IS_SAFE)
-			flush_icache_range(addr, addr + length + 1);
+			flush_icache_range(addr, addr + length);
 		return 0;
 	}
 
@@ -590,6 +590,7 @@
 
 	/* Signal the primary CPU that we are done: */
 	atomic_set(&cpu_in_kgdb[cpu], 0);
+	touch_softlockup_watchdog();
 	clocksource_touch_watchdog();
 	local_irq_restore(flags);
 }
@@ -1432,6 +1433,7 @@
 	    atomic_read(&kgdb_cpu_doing_single_step) != cpu) {
 
 		atomic_set(&kgdb_active, -1);
+		touch_softlockup_watchdog();
 		clocksource_touch_watchdog();
 		local_irq_restore(flags);
 
@@ -1462,7 +1464,7 @@
 	 * Get the passive CPU lock which will hold all the non-primary
 	 * CPU in a spin state while the debugger is active
 	 */
-	if (!kgdb_single_step || !kgdb_contthread) {
+	if (!kgdb_single_step) {
 		for (i = 0; i < NR_CPUS; i++)
 			atomic_set(&passive_cpu_wait[i], 1);
 	}
@@ -1475,7 +1477,7 @@
 
 #ifdef CONFIG_SMP
 	/* Signal the other CPUs to enter kgdb_wait() */
-	if ((!kgdb_single_step || !kgdb_contthread) && kgdb_do_roundup)
+	if ((!kgdb_single_step) && kgdb_do_roundup)
 		kgdb_roundup_cpus(flags);
 #endif
 
@@ -1494,7 +1496,7 @@
 	kgdb_post_primary_code(ks->linux_regs, ks->ex_vector, ks->err_code);
 	kgdb_deactivate_sw_breakpoints();
 	kgdb_single_step = 0;
-	kgdb_contthread = NULL;
+	kgdb_contthread = current;
 	exception_level = 0;
 
 	/* Talk to debugger with gdbserial protocol */
@@ -1508,7 +1510,7 @@
 	kgdb_info[ks->cpu].task = NULL;
 	atomic_set(&cpu_in_kgdb[ks->cpu], 0);
 
-	if (!kgdb_single_step || !kgdb_contthread) {
+	if (!kgdb_single_step) {
 		for (i = NR_CPUS-1; i >= 0; i--)
 			atomic_set(&passive_cpu_wait[i], 0);
 		/*
@@ -1524,6 +1526,7 @@
 kgdb_restore:
 	/* Free kgdb_active */
 	atomic_set(&kgdb_active, -1);
+	touch_softlockup_watchdog();
 	clocksource_touch_watchdog();
 	local_irq_restore(flags);
 
diff --git a/kernel/posix-timers.c b/kernel/posix-timers.c
index e36d579..5131e54 100644
--- a/kernel/posix-timers.c
+++ b/kernel/posix-timers.c
@@ -441,7 +441,7 @@
 		return tmr;
 	if (unlikely(!(tmr->sigq = sigqueue_alloc()))) {
 		kmem_cache_free(posix_timers_cache, tmr);
-		tmr = NULL;
+		return NULL;
 	}
 	memset(&tmr->sigq->info, 0, sizeof(siginfo_t));
 	return tmr;
diff --git a/kernel/printk.c b/kernel/printk.c
index b51b156..aee891a 100644
--- a/kernel/printk.c
+++ b/kernel/printk.c
@@ -577,9 +577,6 @@
  * @fmt: format string
  *
  * This is printk().  It can be called from any context.  We want it to work.
- * Be aware of the fact that if oops_in_progress is not set, we might try to
- * wake klogd up which could deadlock on runqueue lock if printk() is called
- * from scheduler code.
  *
  * We try to grab the console_sem.  If we succeed, it's easy - we log the output and
  * call the console drivers.  If we fail to get the semaphore we place the output
@@ -982,10 +979,25 @@
 	return console_locked;
 }
 
+static DEFINE_PER_CPU(int, printk_pending);
+
+void printk_tick(void)
+{
+	if (__get_cpu_var(printk_pending)) {
+		__get_cpu_var(printk_pending) = 0;
+		wake_up_interruptible(&log_wait);
+	}
+}
+
+int printk_needs_cpu(int cpu)
+{
+	return per_cpu(printk_pending, cpu);
+}
+
 void wake_up_klogd(void)
 {
-	if (!oops_in_progress && waitqueue_active(&log_wait))
-		wake_up_interruptible(&log_wait);
+	if (waitqueue_active(&log_wait))
+		__raw_get_cpu_var(printk_pending) = 1;
 }
 
 /**
@@ -1291,22 +1303,6 @@
 }
 late_initcall(disable_boot_consoles);
 
-/**
- * tty_write_message - write a message to a certain tty, not just the console.
- * @tty: the destination tty_struct
- * @msg: the message to write
- *
- * This is used for messages that need to be redirected to a specific tty.
- * We don't put it into the syslog queue right now maybe in the future if
- * really needed.
- */
-void tty_write_message(struct tty_struct *tty, char *msg)
-{
-	if (tty && tty->ops->write)
-		tty->ops->write(tty, msg, strlen(msg));
-	return;
-}
-
 #if defined CONFIG_PRINTK
 
 /*
diff --git a/kernel/rcuclassic.c b/kernel/rcuclassic.c
index aad93cd..37f72e551 100644
--- a/kernel/rcuclassic.c
+++ b/kernel/rcuclassic.c
@@ -47,6 +47,7 @@
 #include <linux/notifier.h>
 #include <linux/cpu.h>
 #include <linux/mutex.h>
+#include <linux/time.h>
 
 #ifdef CONFIG_DEBUG_LOCK_ALLOC
 static struct lock_class_key rcu_lock_key;
@@ -60,12 +61,14 @@
 static struct rcu_ctrlblk rcu_ctrlblk = {
 	.cur = -300,
 	.completed = -300,
+	.pending = -300,
 	.lock = __SPIN_LOCK_UNLOCKED(&rcu_ctrlblk.lock),
 	.cpumask = CPU_MASK_NONE,
 };
 static struct rcu_ctrlblk rcu_bh_ctrlblk = {
 	.cur = -300,
 	.completed = -300,
+	.pending = -300,
 	.lock = __SPIN_LOCK_UNLOCKED(&rcu_bh_ctrlblk.lock),
 	.cpumask = CPU_MASK_NONE,
 };
@@ -83,7 +86,10 @@
 {
 	int cpu;
 	cpumask_t cpumask;
+	unsigned long flags;
+
 	set_need_resched();
+	spin_lock_irqsave(&rcp->lock, flags);
 	if (unlikely(!rcp->signaled)) {
 		rcp->signaled = 1;
 		/*
@@ -109,6 +115,7 @@
 		for_each_cpu_mask_nr(cpu, cpumask)
 			smp_send_reschedule(cpu);
 	}
+	spin_unlock_irqrestore(&rcp->lock, flags);
 }
 #else
 static inline void force_quiescent_state(struct rcu_data *rdp,
@@ -118,6 +125,126 @@
 }
 #endif
 
+static void __call_rcu(struct rcu_head *head, struct rcu_ctrlblk *rcp,
+		struct rcu_data *rdp)
+{
+	long batch;
+
+	head->next = NULL;
+	smp_mb(); /* Read of rcu->cur must happen after any change by caller. */
+
+	/*
+	 * Determine the batch number of this callback.
+	 *
+	 * Using ACCESS_ONCE to avoid the following error when gcc eliminates
+	 * local variable "batch" and emits codes like this:
+	 *	1) rdp->batch = rcp->cur + 1 # gets old value
+	 *	......
+	 *	2)rcu_batch_after(rcp->cur + 1, rdp->batch) # gets new value
+	 * then [*nxttail[0], *nxttail[1]) may contain callbacks
+	 * that batch# = rdp->batch, see the comment of struct rcu_data.
+	 */
+	batch = ACCESS_ONCE(rcp->cur) + 1;
+
+	if (rdp->nxtlist && rcu_batch_after(batch, rdp->batch)) {
+		/* process callbacks */
+		rdp->nxttail[0] = rdp->nxttail[1];
+		rdp->nxttail[1] = rdp->nxttail[2];
+		if (rcu_batch_after(batch - 1, rdp->batch))
+			rdp->nxttail[0] = rdp->nxttail[2];
+	}
+
+	rdp->batch = batch;
+	*rdp->nxttail[2] = head;
+	rdp->nxttail[2] = &head->next;
+
+	if (unlikely(++rdp->qlen > qhimark)) {
+		rdp->blimit = INT_MAX;
+		force_quiescent_state(rdp, &rcu_ctrlblk);
+	}
+}
+
+#ifdef CONFIG_RCU_CPU_STALL_DETECTOR
+
+static void record_gp_stall_check_time(struct rcu_ctrlblk *rcp)
+{
+	rcp->gp_start = jiffies;
+	rcp->jiffies_stall = jiffies + RCU_SECONDS_TILL_STALL_CHECK;
+}
+
+static void print_other_cpu_stall(struct rcu_ctrlblk *rcp)
+{
+	int cpu;
+	long delta;
+	unsigned long flags;
+
+	/* Only let one CPU complain about others per time interval. */
+
+	spin_lock_irqsave(&rcp->lock, flags);
+	delta = jiffies - rcp->jiffies_stall;
+	if (delta < 2 || rcp->cur != rcp->completed) {
+		spin_unlock_irqrestore(&rcp->lock, flags);
+		return;
+	}
+	rcp->jiffies_stall = jiffies + RCU_SECONDS_TILL_STALL_RECHECK;
+	spin_unlock_irqrestore(&rcp->lock, flags);
+
+	/* OK, time to rat on our buddy... */
+
+	printk(KERN_ERR "RCU detected CPU stalls:");
+	for_each_possible_cpu(cpu) {
+		if (cpu_isset(cpu, rcp->cpumask))
+			printk(" %d", cpu);
+	}
+	printk(" (detected by %d, t=%ld jiffies)\n",
+	       smp_processor_id(), (long)(jiffies - rcp->gp_start));
+}
+
+static void print_cpu_stall(struct rcu_ctrlblk *rcp)
+{
+	unsigned long flags;
+
+	printk(KERN_ERR "RCU detected CPU %d stall (t=%lu/%lu jiffies)\n",
+			smp_processor_id(), jiffies,
+			jiffies - rcp->gp_start);
+	dump_stack();
+	spin_lock_irqsave(&rcp->lock, flags);
+	if ((long)(jiffies - rcp->jiffies_stall) >= 0)
+		rcp->jiffies_stall =
+			jiffies + RCU_SECONDS_TILL_STALL_RECHECK;
+	spin_unlock_irqrestore(&rcp->lock, flags);
+	set_need_resched();  /* kick ourselves to get things going. */
+}
+
+static void check_cpu_stall(struct rcu_ctrlblk *rcp)
+{
+	long delta;
+
+	delta = jiffies - rcp->jiffies_stall;
+	if (cpu_isset(smp_processor_id(), rcp->cpumask) && delta >= 0) {
+
+		/* We haven't checked in, so go dump stack. */
+		print_cpu_stall(rcp);
+
+	} else if (rcp->cur != rcp->completed && delta >= 2) {
+
+		/* They had two seconds to dump stack, so complain. */
+		print_other_cpu_stall(rcp);
+	}
+}
+
+#else /* #ifdef CONFIG_RCU_CPU_STALL_DETECTOR */
+
+static void record_gp_stall_check_time(struct rcu_ctrlblk *rcp)
+{
+}
+
+static inline void check_cpu_stall(struct rcu_ctrlblk *rcp)
+{
+}
+
+#endif /* #else #ifdef CONFIG_RCU_CPU_STALL_DETECTOR */
+
 /**
  * call_rcu - Queue an RCU callback for invocation after a grace period.
  * @head: structure to be used for queueing the RCU updates.
@@ -133,18 +260,10 @@
 				void (*func)(struct rcu_head *rcu))
 {
 	unsigned long flags;
-	struct rcu_data *rdp;
 
 	head->func = func;
-	head->next = NULL;
 	local_irq_save(flags);
-	rdp = &__get_cpu_var(rcu_data);
-	*rdp->nxttail = head;
-	rdp->nxttail = &head->next;
-	if (unlikely(++rdp->qlen > qhimark)) {
-		rdp->blimit = INT_MAX;
-		force_quiescent_state(rdp, &rcu_ctrlblk);
-	}
+	__call_rcu(head, &rcu_ctrlblk, &__get_cpu_var(rcu_data));
 	local_irq_restore(flags);
 }
 EXPORT_SYMBOL_GPL(call_rcu);
@@ -169,20 +288,10 @@
 				void (*func)(struct rcu_head *rcu))
 {
 	unsigned long flags;
-	struct rcu_data *rdp;
 
 	head->func = func;
-	head->next = NULL;
 	local_irq_save(flags);
-	rdp = &__get_cpu_var(rcu_bh_data);
-	*rdp->nxttail = head;
-	rdp->nxttail = &head->next;
-
-	if (unlikely(++rdp->qlen > qhimark)) {
-		rdp->blimit = INT_MAX;
-		force_quiescent_state(rdp, &rcu_bh_ctrlblk);
-	}
-
+	__call_rcu(head, &rcu_bh_ctrlblk, &__get_cpu_var(rcu_bh_data));
 	local_irq_restore(flags);
 }
 EXPORT_SYMBOL_GPL(call_rcu_bh);
@@ -211,12 +320,6 @@
 static inline void raise_rcu_softirq(void)
 {
 	raise_softirq(RCU_SOFTIRQ);
-	/*
-	 * The smp_mb() here is required to ensure that this cpu's
-	 * __rcu_process_callbacks() reads the most recently updated
-	 * value of rcu->cur.
-	 */
-	smp_mb();
 }
 
 /*
@@ -225,6 +328,7 @@
  */
 static void rcu_do_batch(struct rcu_data *rdp)
 {
+	unsigned long flags;
 	struct rcu_head *next, *list;
 	int count = 0;
 
@@ -239,9 +343,9 @@
 	}
 	rdp->donelist = list;
 
-	local_irq_disable();
+	local_irq_save(flags);
 	rdp->qlen -= count;
-	local_irq_enable();
+	local_irq_restore(flags);
 	if (rdp->blimit == INT_MAX && rdp->qlen <= qlowmark)
 		rdp->blimit = blimit;
 
@@ -269,6 +373,7 @@
  *   rcu_check_quiescent_state calls rcu_start_batch(0) to start the next grace
  *   period (if necessary).
  */
+
 /*
  * Register a new batch of callbacks, and start it up if there is currently no
  * active batch and the batch to be registered has not already occurred.
@@ -276,15 +381,10 @@
  */
 static void rcu_start_batch(struct rcu_ctrlblk *rcp)
 {
-	if (rcp->next_pending &&
+	if (rcp->cur != rcp->pending &&
 			rcp->completed == rcp->cur) {
-		rcp->next_pending = 0;
-		/*
-		 * next_pending == 0 must be visible in
-		 * __rcu_process_callbacks() before it can see new value of cur.
-		 */
-		smp_wmb();
 		rcp->cur++;
+		record_gp_stall_check_time(rcp);
 
 		/*
 		 * Accessing nohz_cpu_mask before incrementing rcp->cur needs a
@@ -322,6 +422,8 @@
 static void rcu_check_quiescent_state(struct rcu_ctrlblk *rcp,
 					struct rcu_data *rdp)
 {
+	unsigned long flags;
+
 	if (rdp->quiescbatch != rcp->cur) {
 		/* start new grace period: */
 		rdp->qs_pending = 1;
@@ -345,7 +447,7 @@
 		return;
 	rdp->qs_pending = 0;
 
-	spin_lock(&rcp->lock);
+	spin_lock_irqsave(&rcp->lock, flags);
 	/*
 	 * rdp->quiescbatch/rcp->cur and the cpu bitmap can come out of sync
 	 * during cpu startup. Ignore the quiescent state.
@@ -353,7 +455,7 @@
 	if (likely(rdp->quiescbatch == rcp->cur))
 		cpu_quiet(rdp->cpu, rcp);
 
-	spin_unlock(&rcp->lock);
+	spin_unlock_irqrestore(&rcp->lock, flags);
 }
 
 
@@ -364,33 +466,38 @@
  * which is dead and hence not processing interrupts.
  */
 static void rcu_move_batch(struct rcu_data *this_rdp, struct rcu_head *list,
-				struct rcu_head **tail)
+				struct rcu_head **tail, long batch)
 {
-	local_irq_disable();
-	*this_rdp->nxttail = list;
-	if (list)
-		this_rdp->nxttail = tail;
-	local_irq_enable();
+	unsigned long flags;
+
+	if (list) {
+		local_irq_save(flags);
+		this_rdp->batch = batch;
+		*this_rdp->nxttail[2] = list;
+		this_rdp->nxttail[2] = tail;
+		local_irq_restore(flags);
+	}
 }
 
 static void __rcu_offline_cpu(struct rcu_data *this_rdp,
 				struct rcu_ctrlblk *rcp, struct rcu_data *rdp)
 {
-	/* if the cpu going offline owns the grace period
+	unsigned long flags;
+
+	/*
+	 * if the cpu going offline owns the grace period
 	 * we can block indefinitely waiting for it, so flush
 	 * it here
 	 */
-	spin_lock_bh(&rcp->lock);
+	spin_lock_irqsave(&rcp->lock, flags);
 	if (rcp->cur != rcp->completed)
 		cpu_quiet(rdp->cpu, rcp);
-	spin_unlock_bh(&rcp->lock);
-	rcu_move_batch(this_rdp, rdp->donelist, rdp->donetail);
-	rcu_move_batch(this_rdp, rdp->curlist, rdp->curtail);
-	rcu_move_batch(this_rdp, rdp->nxtlist, rdp->nxttail);
+	rcu_move_batch(this_rdp, rdp->donelist, rdp->donetail, rcp->cur + 1);
+	rcu_move_batch(this_rdp, rdp->nxtlist, rdp->nxttail[2], rcp->cur + 1);
+	spin_unlock(&rcp->lock);
 
-	local_irq_disable();
 	this_rdp->qlen += rdp->qlen;
-	local_irq_enable();
+	local_irq_restore(flags);
 }
 
 static void rcu_offline_cpu(int cpu)
@@ -420,38 +527,52 @@
 static void __rcu_process_callbacks(struct rcu_ctrlblk *rcp,
 					struct rcu_data *rdp)
 {
-	if (rdp->curlist && !rcu_batch_before(rcp->completed, rdp->batch)) {
-		*rdp->donetail = rdp->curlist;
-		rdp->donetail = rdp->curtail;
-		rdp->curlist = NULL;
-		rdp->curtail = &rdp->curlist;
-	}
+	unsigned long flags;
+	long completed_snap;
 
-	if (rdp->nxtlist && !rdp->curlist) {
-		local_irq_disable();
-		rdp->curlist = rdp->nxtlist;
-		rdp->curtail = rdp->nxttail;
-		rdp->nxtlist = NULL;
-		rdp->nxttail = &rdp->nxtlist;
-		local_irq_enable();
+	if (rdp->nxtlist) {
+		local_irq_save(flags);
+		completed_snap = ACCESS_ONCE(rcp->completed);
 
 		/*
-		 * start the next batch of callbacks
+		 * move the other grace-period-completed entries to
+		 * [rdp->nxtlist, *rdp->nxttail[0]) temporarily
 		 */
+		if (!rcu_batch_before(completed_snap, rdp->batch))
+			rdp->nxttail[0] = rdp->nxttail[1] = rdp->nxttail[2];
+		else if (!rcu_batch_before(completed_snap, rdp->batch - 1))
+			rdp->nxttail[0] = rdp->nxttail[1];
 
-		/* determine batch number */
-		rdp->batch = rcp->cur + 1;
-		/* see the comment and corresponding wmb() in
-		 * the rcu_start_batch()
+		/*
+		 * the grace period for entries in
+		 * [rdp->nxtlist, *rdp->nxttail[0]) has completed and
+		 * move these entries to donelist
 		 */
-		smp_rmb();
+		if (rdp->nxttail[0] != &rdp->nxtlist) {
+			*rdp->donetail = rdp->nxtlist;
+			rdp->donetail = rdp->nxttail[0];
+			rdp->nxtlist = *rdp->nxttail[0];
+			*rdp->donetail = NULL;
 
-		if (!rcp->next_pending) {
+			if (rdp->nxttail[1] == rdp->nxttail[0])
+				rdp->nxttail[1] = &rdp->nxtlist;
+			if (rdp->nxttail[2] == rdp->nxttail[0])
+				rdp->nxttail[2] = &rdp->nxtlist;
+			rdp->nxttail[0] = &rdp->nxtlist;
+		}
+
+		local_irq_restore(flags);
+
+		if (rcu_batch_after(rdp->batch, rcp->pending)) {
+			unsigned long flags2;
+
 			/* and start it/schedule start if it's a new batch */
-			spin_lock(&rcp->lock);
-			rcp->next_pending = 1;
-			rcu_start_batch(rcp);
-			spin_unlock(&rcp->lock);
+			spin_lock_irqsave(&rcp->lock, flags2);
+			if (rcu_batch_after(rdp->batch, rcp->pending)) {
+				rcp->pending = rdp->batch;
+				rcu_start_batch(rcp);
+			}
+			spin_unlock_irqrestore(&rcp->lock, flags2);
 		}
 	}
 
@@ -462,21 +583,53 @@
 
 static void rcu_process_callbacks(struct softirq_action *unused)
 {
+	/*
+	 * Memory references from any prior RCU read-side critical sections
+	 * executed by the interrupted code must be see before any RCU
+	 * grace-period manupulations below.
+	 */
+
+	smp_mb(); /* See above block comment. */
+
 	__rcu_process_callbacks(&rcu_ctrlblk, &__get_cpu_var(rcu_data));
 	__rcu_process_callbacks(&rcu_bh_ctrlblk, &__get_cpu_var(rcu_bh_data));
+
+	/*
+	 * Memory references from any later RCU read-side critical sections
+	 * executed by the interrupted code must be see after any RCU
+	 * grace-period manupulations above.
+	 */
+
+	smp_mb(); /* See above block comment. */
 }
 
 static int __rcu_pending(struct rcu_ctrlblk *rcp, struct rcu_data *rdp)
 {
-	/* This cpu has pending rcu entries and the grace period
-	 * for them has completed.
-	 */
-	if (rdp->curlist && !rcu_batch_before(rcp->completed, rdp->batch))
-		return 1;
+	/* Check for CPU stalls, if enabled. */
+	check_cpu_stall(rcp);
 
-	/* This cpu has no pending entries, but there are new entries */
-	if (!rdp->curlist && rdp->nxtlist)
-		return 1;
+	if (rdp->nxtlist) {
+		long completed_snap = ACCESS_ONCE(rcp->completed);
+
+		/*
+		 * This cpu has pending rcu entries and the grace period
+		 * for them has completed.
+		 */
+		if (!rcu_batch_before(completed_snap, rdp->batch))
+			return 1;
+		if (!rcu_batch_before(completed_snap, rdp->batch - 1) &&
+				rdp->nxttail[0] != rdp->nxttail[1])
+			return 1;
+		if (rdp->nxttail[0] != &rdp->nxtlist)
+			return 1;
+
+		/*
+		 * This cpu has pending rcu entries and the new batch
+		 * for then hasn't been started nor scheduled start
+		 */
+		if (rcu_batch_after(rdp->batch, rcp->pending))
+			return 1;
+	}
 
 	/* This cpu has finished callbacks to invoke */
 	if (rdp->donelist)
@@ -512,9 +665,15 @@
 	struct rcu_data *rdp = &per_cpu(rcu_data, cpu);
 	struct rcu_data *rdp_bh = &per_cpu(rcu_bh_data, cpu);
 
-	return (!!rdp->curlist || !!rdp_bh->curlist || rcu_pending(cpu));
+	return !!rdp->nxtlist || !!rdp_bh->nxtlist || rcu_pending(cpu);
 }
 
+/*
+ * Top-level function driving RCU grace-period detection, normally
+ * invoked from the scheduler-clock interrupt.  This function simply
+ * increments counters that are read only from softirq by this same
+ * CPU, so there are no memory barriers required.
+ */
 void rcu_check_callbacks(int cpu, int user)
 {
 	if (user ||
@@ -558,14 +717,17 @@
 static void rcu_init_percpu_data(int cpu, struct rcu_ctrlblk *rcp,
 						struct rcu_data *rdp)
 {
+	unsigned long flags;
+
+	spin_lock_irqsave(&rcp->lock, flags);
 	memset(rdp, 0, sizeof(*rdp));
-	rdp->curtail = &rdp->curlist;
-	rdp->nxttail = &rdp->nxtlist;
+	rdp->nxttail[0] = rdp->nxttail[1] = rdp->nxttail[2] = &rdp->nxtlist;
 	rdp->donetail = &rdp->donelist;
 	rdp->quiescbatch = rcp->completed;
 	rdp->qs_pending = 0;
 	rdp->cpu = cpu;
 	rdp->blimit = blimit;
+	spin_unlock_irqrestore(&rcp->lock, flags);
 }
 
 static void __cpuinit rcu_online_cpu(int cpu)
@@ -610,6 +772,9 @@
  */
 void __init __rcu_init(void)
 {
+#ifdef CONFIG_RCU_CPU_STALL_DETECTOR
+	printk(KERN_INFO "RCU-based detection of stalled CPUs is enabled.\n");
+#endif /* #ifdef CONFIG_RCU_CPU_STALL_DETECTOR */
 	rcu_cpu_notify(&rcu_nb, CPU_UP_PREPARE,
 			(void *)(long)smp_processor_id());
 	/* Register notifier for non-boot CPUs */
diff --git a/kernel/rcupreempt.c b/kernel/rcupreempt.c
index 2782793..ca4bbbe 100644
--- a/kernel/rcupreempt.c
+++ b/kernel/rcupreempt.c
@@ -59,14 +59,6 @@
 #include <linux/rcupreempt_trace.h>
 
 /*
- * Macro that prevents the compiler from reordering accesses, but does
- * absolutely -nothing- to prevent CPUs from reordering.  This is used
- * only to mediate communication between mainline code and hardware
- * interrupt and NMI handlers.
- */
-#define ACCESS_ONCE(x) (*(volatile typeof(x) *)&(x))
-
-/*
  * PREEMPT_RCU data structures.
  */
 
diff --git a/kernel/rcupreempt_trace.c b/kernel/rcupreempt_trace.c
index 5edf82c..35c2d33 100644
--- a/kernel/rcupreempt_trace.c
+++ b/kernel/rcupreempt_trace.c
@@ -308,11 +308,16 @@
 
 static int __init rcupreempt_trace_init(void)
 {
+	int ret;
+
 	mutex_init(&rcupreempt_trace_mutex);
 	rcupreempt_trace_buf = kmalloc(RCUPREEMPT_TRACE_BUF_SIZE, GFP_KERNEL);
 	if (!rcupreempt_trace_buf)
 		return 1;
-	return rcupreempt_debugfs_init();
+	ret = rcupreempt_debugfs_init();
+	if (ret)
+		kfree(rcupreempt_trace_buf);
+	return ret;
 }
 
 static void __exit rcupreempt_trace_cleanup(void)
diff --git a/kernel/resource.c b/kernel/resource.c
index 03d796c..7797dae 100644
--- a/kernel/resource.c
+++ b/kernel/resource.c
@@ -38,10 +38,6 @@
 
 static DEFINE_RWLOCK(resource_lock);
 
-#ifdef CONFIG_PROC_FS
-
-enum { MAX_IORES_LEVEL = 5 };
-
 static void *r_next(struct seq_file *m, void *v, loff_t *pos)
 {
 	struct resource *p = v;
@@ -53,6 +49,10 @@
 	return p->sibling;
 }
 
+#ifdef CONFIG_PROC_FS
+
+enum { MAX_IORES_LEVEL = 5 };
+
 static void *r_start(struct seq_file *m, loff_t *pos)
 	__acquires(resource_lock)
 {
@@ -516,6 +516,70 @@
 	return result;
 }
 
+static void __init __reserve_region_with_split(struct resource *root,
+		resource_size_t start, resource_size_t end,
+		const char *name)
+{
+	struct resource *parent = root;
+	struct resource *conflict;
+	struct resource *res = kzalloc(sizeof(*res), GFP_KERNEL);
+
+	if (!res)
+		return;
+
+	res->name = name;
+	res->start = start;
+	res->end = end;
+	res->flags = IORESOURCE_BUSY;
+
+	for (;;) {
+		conflict = __request_resource(parent, res);
+		if (!conflict)
+			break;
+		if (conflict != parent) {
+			parent = conflict;
+			if (!(conflict->flags & IORESOURCE_BUSY))
+				continue;
+		}
+
+		/* Uhhuh, that didn't work out.. */
+		kfree(res);
+		res = NULL;
+		break;
+	}
+
+	if (!res) {
+		/* failed, split and try again */
+
+		/* conflict covered whole area */
+		if (conflict->start <= start && conflict->end >= end)
+			return;
+
+		if (conflict->start > start)
+			__reserve_region_with_split(root, start, conflict->start-1, name);
+		if (!(conflict->flags & IORESOURCE_BUSY)) {
+			resource_size_t common_start, common_end;
+
+			common_start = max(conflict->start, start);
+			common_end = min(conflict->end, end);
+			if (common_start < common_end)
+				__reserve_region_with_split(root, common_start, common_end, name);
+		}
+		if (conflict->end < end)
+			__reserve_region_with_split(root, conflict->end+1, end, name);
+	}
+
+}
+
+void reserve_region_with_split(struct resource *root,
+		resource_size_t start, resource_size_t end,
+		const char *name)
+{
+	write_lock(&resource_lock);
+	__reserve_region_with_split(root, start, end, name);
+	write_unlock(&resource_lock);
+}
+
 EXPORT_SYMBOL(adjust_resource);
 
 /**
@@ -763,3 +827,40 @@
 }
 
 __setup("reserve=", reserve_setup);
+
+/*
+ * Check if the requested addr and size spans more than any slot in the
+ * iomem resource tree.
+ */
+int iomem_map_sanity_check(resource_size_t addr, unsigned long size)
+{
+	struct resource *p = &iomem_resource;
+	int err = 0;
+	loff_t l;
+
+	read_lock(&resource_lock);
+	for (p = p->child; p ; p = r_next(NULL, p, &l)) {
+		/*
+		 * We can probably skip the resources without
+		 * IORESOURCE_IO attribute?
+		 */
+		if (p->start >= addr + size)
+			continue;
+		if (p->end < addr)
+			continue;
+		if (p->start <= addr && (p->end >= addr + size - 1))
+			continue;
+		printk(KERN_WARNING "resource map sanity check conflict: "
+		       "0x%llx 0x%llx 0x%llx 0x%llx %s\n",
+		       (unsigned long long)addr,
+		       (unsigned long long)(addr + size - 1),
+		       (unsigned long long)p->start,
+		       (unsigned long long)p->end,
+		       p->name);
+		err = -1;
+		break;
+	}
+	read_unlock(&resource_lock);
+
+	return err;
+}
diff --git a/kernel/sched.c b/kernel/sched.c
index cc1f81b..6f23059 100644
--- a/kernel/sched.c
+++ b/kernel/sched.c
@@ -201,14 +201,19 @@
 	hrtimer_init(&rt_b->rt_period_timer,
 			CLOCK_MONOTONIC, HRTIMER_MODE_REL);
 	rt_b->rt_period_timer.function = sched_rt_period_timer;
-	rt_b->rt_period_timer.cb_mode = HRTIMER_CB_IRQSAFE_NO_SOFTIRQ;
+	rt_b->rt_period_timer.cb_mode = HRTIMER_CB_IRQSAFE_UNLOCKED;
+}
+
+static inline int rt_bandwidth_enabled(void)
+{
+	return sysctl_sched_rt_runtime >= 0;
 }
 
 static void start_rt_bandwidth(struct rt_bandwidth *rt_b)
 {
 	ktime_t now;
 
-	if (rt_b->rt_runtime == RUNTIME_INF)
+	if (rt_bandwidth_enabled() && rt_b->rt_runtime == RUNTIME_INF)
 		return;
 
 	if (hrtimer_active(&rt_b->rt_period_timer))
@@ -298,9 +303,9 @@
 static DEFINE_PER_CPU(struct sched_rt_entity, init_sched_rt_entity);
 static DEFINE_PER_CPU(struct rt_rq, init_rt_rq) ____cacheline_aligned_in_smp;
 #endif /* CONFIG_RT_GROUP_SCHED */
-#else /* !CONFIG_FAIR_GROUP_SCHED */
+#else /* !CONFIG_USER_SCHED */
 #define root_task_group init_task_group
-#endif /* CONFIG_FAIR_GROUP_SCHED */
+#endif /* CONFIG_USER_SCHED */
 
 /* task_group_lock serializes add/remove of task groups and also changes to
  * a task group's cpu shares.
@@ -604,9 +609,9 @@
 
 static DEFINE_PER_CPU_SHARED_ALIGNED(struct rq, runqueues);
 
-static inline void check_preempt_curr(struct rq *rq, struct task_struct *p)
+static inline void check_preempt_curr(struct rq *rq, struct task_struct *p, int sync)
 {
-	rq->curr->sched_class->check_preempt_curr(rq, p);
+	rq->curr->sched_class->check_preempt_curr(rq, p, sync);
 }
 
 static inline int cpu_of(struct rq *rq)
@@ -1087,7 +1092,7 @@
 	return NOTIFY_DONE;
 }
 
-static void init_hrtick(void)
+static __init void init_hrtick(void)
 {
 	hotcpu_notifier(hotplug_hrtick, 0);
 }
@@ -1102,7 +1107,7 @@
 	hrtimer_start(&rq->hrtick_timer, ns_to_ktime(delay), HRTIMER_MODE_REL);
 }
 
-static void init_hrtick(void)
+static inline void init_hrtick(void)
 {
 }
 #endif /* CONFIG_SMP */
@@ -1119,9 +1124,9 @@
 
 	hrtimer_init(&rq->hrtick_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
 	rq->hrtick_timer.function = hrtick;
-	rq->hrtick_timer.cb_mode = HRTIMER_CB_IRQSAFE_NO_SOFTIRQ;
+	rq->hrtick_timer.cb_mode = HRTIMER_CB_IRQSAFE_PERCPU;
 }
-#else
+#else	/* CONFIG_SCHED_HRTICK */
 static inline void hrtick_clear(struct rq *rq)
 {
 }
@@ -1133,7 +1138,7 @@
 static inline void init_hrtick(void)
 {
 }
-#endif
+#endif	/* CONFIG_SCHED_HRTICK */
 
 /*
  * resched_task - mark a task 'to be rescheduled now'.
@@ -1380,6 +1385,51 @@
 	update_load_sub(&rq->load, load);
 }
 
+#if (defined(CONFIG_SMP) && defined(CONFIG_FAIR_GROUP_SCHED)) || defined(CONFIG_RT_GROUP_SCHED)
+typedef int (*tg_visitor)(struct task_group *, void *);
+
+/*
+ * Iterate the full tree, calling @down when first entering a node and @up when
+ * leaving it for the final time.
+ */
+static int walk_tg_tree(tg_visitor down, tg_visitor up, void *data)
+{
+	struct task_group *parent, *child;
+	int ret;
+
+	rcu_read_lock();
+	parent = &root_task_group;
+down:
+	ret = (*down)(parent, data);
+	if (ret)
+		goto out_unlock;
+	list_for_each_entry_rcu(child, &parent->children, siblings) {
+		parent = child;
+		goto down;
+
+up:
+		continue;
+	}
+	ret = (*up)(parent, data);
+	if (ret)
+		goto out_unlock;
+
+	child = parent;
+	parent = parent->parent;
+	if (parent)
+		goto up;
+out_unlock:
+	rcu_read_unlock();
+
+	return ret;
+}
+
+static int tg_nop(struct task_group *tg, void *data)
+{
+	return 0;
+}
+#endif
+
 #ifdef CONFIG_SMP
 static unsigned long source_load(int cpu, int type);
 static unsigned long target_load(int cpu, int type);
@@ -1397,37 +1447,6 @@
 
 #ifdef CONFIG_FAIR_GROUP_SCHED
 
-typedef void (*tg_visitor)(struct task_group *, int, struct sched_domain *);
-
-/*
- * Iterate the full tree, calling @down when first entering a node and @up when
- * leaving it for the final time.
- */
-static void
-walk_tg_tree(tg_visitor down, tg_visitor up, int cpu, struct sched_domain *sd)
-{
-	struct task_group *parent, *child;
-
-	rcu_read_lock();
-	parent = &root_task_group;
-down:
-	(*down)(parent, cpu, sd);
-	list_for_each_entry_rcu(child, &parent->children, siblings) {
-		parent = child;
-		goto down;
-
-up:
-		continue;
-	}
-	(*up)(parent, cpu, sd);
-
-	child = parent;
-	parent = parent->parent;
-	if (parent)
-		goto up;
-	rcu_read_unlock();
-}
-
 static void __set_se_shares(struct sched_entity *se, unsigned long shares);
 
 /*
@@ -1486,11 +1505,11 @@
  * This needs to be done in a bottom-up fashion because the rq weight of a
  * parent group depends on the shares of its child groups.
  */
-static void
-tg_shares_up(struct task_group *tg, int cpu, struct sched_domain *sd)
+static int tg_shares_up(struct task_group *tg, void *data)
 {
 	unsigned long rq_weight = 0;
 	unsigned long shares = 0;
+	struct sched_domain *sd = data;
 	int i;
 
 	for_each_cpu_mask(i, sd->span) {
@@ -1515,6 +1534,8 @@
 		__update_group_shares_cpu(tg, i, shares, rq_weight);
 		spin_unlock_irqrestore(&rq->lock, flags);
 	}
+
+	return 0;
 }
 
 /*
@@ -1522,10 +1543,10 @@
  * This needs to be done in a top-down fashion because the load of a child
  * group is a fraction of its parents load.
  */
-static void
-tg_load_down(struct task_group *tg, int cpu, struct sched_domain *sd)
+static int tg_load_down(struct task_group *tg, void *data)
 {
 	unsigned long load;
+	long cpu = (long)data;
 
 	if (!tg->parent) {
 		load = cpu_rq(cpu)->load.weight;
@@ -1536,11 +1557,8 @@
 	}
 
 	tg->cfs_rq[cpu]->h_load = load;
-}
 
-static void
-tg_nop(struct task_group *tg, int cpu, struct sched_domain *sd)
-{
+	return 0;
 }
 
 static void update_shares(struct sched_domain *sd)
@@ -1550,7 +1568,7 @@
 
 	if (elapsed >= (s64)(u64)sysctl_sched_shares_ratelimit) {
 		sd->last_update = now;
-		walk_tg_tree(tg_nop, tg_shares_up, 0, sd);
+		walk_tg_tree(tg_nop, tg_shares_up, sd);
 	}
 }
 
@@ -1561,9 +1579,9 @@
 	spin_lock(&rq->lock);
 }
 
-static void update_h_load(int cpu)
+static void update_h_load(long cpu)
 {
-	walk_tg_tree(tg_load_down, tg_nop, cpu, NULL);
+	walk_tg_tree(tg_load_down, tg_nop, (void *)cpu);
 }
 
 #else
@@ -1921,11 +1939,8 @@
 		running = task_running(rq, p);
 		on_rq = p->se.on_rq;
 		ncsw = 0;
-		if (!match_state || p->state == match_state) {
-			ncsw = p->nivcsw + p->nvcsw;
-			if (unlikely(!ncsw))
-				ncsw = 1;
-		}
+		if (!match_state || p->state == match_state)
+			ncsw = p->nvcsw | LONG_MIN; /* sets MSB */
 		task_rq_unlock(rq, &flags);
 
 		/*
@@ -2285,7 +2300,7 @@
 	trace_mark(kernel_sched_wakeup,
 		"pid %d state %ld ## rq %p task %p rq->curr %p",
 		p->pid, p->state, rq, p, rq->curr);
-	check_preempt_curr(rq, p);
+	check_preempt_curr(rq, p, sync);
 
 	p->state = TASK_RUNNING;
 #ifdef CONFIG_SMP
@@ -2420,7 +2435,7 @@
 	trace_mark(kernel_sched_wakeup_new,
 		"pid %d state %ld ## rq %p task %p rq->curr %p",
 		p->pid, p->state, rq, p, rq->curr);
-	check_preempt_curr(rq, p);
+	check_preempt_curr(rq, p, 0);
 #ifdef CONFIG_SMP
 	if (p->sched_class->task_wake_up)
 		p->sched_class->task_wake_up(rq, p);
@@ -2880,7 +2895,7 @@
 	 * Note that idle threads have a prio of MAX_PRIO, for this test
 	 * to be always true for them.
 	 */
-	check_preempt_curr(this_rq, p);
+	check_preempt_curr(this_rq, p, 0);
 }
 
 /*
@@ -4627,6 +4642,15 @@
 }
 EXPORT_SYMBOL_GPL(__wake_up_sync);	/* For internal use only */
 
+/**
+ * complete: - signals a single thread waiting on this completion
+ * @x:  holds the state of this particular completion
+ *
+ * This will wake up a single thread waiting on this completion. Threads will be
+ * awakened in the same order in which they were queued.
+ *
+ * See also complete_all(), wait_for_completion() and related routines.
+ */
 void complete(struct completion *x)
 {
 	unsigned long flags;
@@ -4638,6 +4662,12 @@
 }
 EXPORT_SYMBOL(complete);
 
+/**
+ * complete_all: - signals all threads waiting on this completion
+ * @x:  holds the state of this particular completion
+ *
+ * This will wake up all threads waiting on this particular completion event.
+ */
 void complete_all(struct completion *x)
 {
 	unsigned long flags;
@@ -4658,10 +4688,7 @@
 		wait.flags |= WQ_FLAG_EXCLUSIVE;
 		__add_wait_queue_tail(&x->wait, &wait);
 		do {
-			if ((state == TASK_INTERRUPTIBLE &&
-			     signal_pending(current)) ||
-			    (state == TASK_KILLABLE &&
-			     fatal_signal_pending(current))) {
+			if (signal_pending_state(state, current)) {
 				timeout = -ERESTARTSYS;
 				break;
 			}
@@ -4689,12 +4716,31 @@
 	return timeout;
 }
 
+/**
+ * wait_for_completion: - waits for completion of a task
+ * @x:  holds the state of this particular completion
+ *
+ * This waits to be signaled for completion of a specific task. It is NOT
+ * interruptible and there is no timeout.
+ *
+ * See also similar routines (i.e. wait_for_completion_timeout()) with timeout
+ * and interrupt capability. Also see complete().
+ */
 void __sched wait_for_completion(struct completion *x)
 {
 	wait_for_common(x, MAX_SCHEDULE_TIMEOUT, TASK_UNINTERRUPTIBLE);
 }
 EXPORT_SYMBOL(wait_for_completion);
 
+/**
+ * wait_for_completion_timeout: - waits for completion of a task (w/timeout)
+ * @x:  holds the state of this particular completion
+ * @timeout:  timeout value in jiffies
+ *
+ * This waits for either a completion of a specific task to be signaled or for a
+ * specified timeout to expire. The timeout is in jiffies. It is not
+ * interruptible.
+ */
 unsigned long __sched
 wait_for_completion_timeout(struct completion *x, unsigned long timeout)
 {
@@ -4702,6 +4748,13 @@
 }
 EXPORT_SYMBOL(wait_for_completion_timeout);
 
+/**
+ * wait_for_completion_interruptible: - waits for completion of a task (w/intr)
+ * @x:  holds the state of this particular completion
+ *
+ * This waits for completion of a specific task to be signaled. It is
+ * interruptible.
+ */
 int __sched wait_for_completion_interruptible(struct completion *x)
 {
 	long t = wait_for_common(x, MAX_SCHEDULE_TIMEOUT, TASK_INTERRUPTIBLE);
@@ -4711,6 +4764,14 @@
 }
 EXPORT_SYMBOL(wait_for_completion_interruptible);
 
+/**
+ * wait_for_completion_interruptible_timeout: - waits for completion (w/(to,intr))
+ * @x:  holds the state of this particular completion
+ * @timeout:  timeout value in jiffies
+ *
+ * This waits for either a completion of a specific task to be signaled or for a
+ * specified timeout to expire. It is interruptible. The timeout is in jiffies.
+ */
 unsigned long __sched
 wait_for_completion_interruptible_timeout(struct completion *x,
 					  unsigned long timeout)
@@ -4719,6 +4780,13 @@
 }
 EXPORT_SYMBOL(wait_for_completion_interruptible_timeout);
 
+/**
+ * wait_for_completion_killable: - waits for completion of a task (killable)
+ * @x:  holds the state of this particular completion
+ *
+ * This waits to be signaled for completion of a specific task. It can be
+ * interrupted by a kill signal.
+ */
 int __sched wait_for_completion_killable(struct completion *x)
 {
 	long t = wait_for_common(x, MAX_SCHEDULE_TIMEOUT, TASK_KILLABLE);
@@ -5121,7 +5189,8 @@
 		 * Do not allow realtime tasks into groups that have no runtime
 		 * assigned.
 		 */
-		if (rt_policy(policy) && task_group(p)->rt_bandwidth.rt_runtime == 0)
+		if (rt_bandwidth_enabled() && rt_policy(policy) &&
+				task_group(p)->rt_bandwidth.rt_runtime == 0)
 			return -EPERM;
 #endif
 
@@ -5957,7 +6026,7 @@
 	set_task_cpu(p, dest_cpu);
 	if (on_rq) {
 		activate_task(rq_dest, p, 0);
-		check_preempt_curr(rq_dest, p);
+		check_preempt_curr(rq_dest, p, 0);
 	}
 done:
 	ret = 1;
@@ -6282,7 +6351,7 @@
 static struct ctl_table *
 sd_alloc_ctl_domain_table(struct sched_domain *sd)
 {
-	struct ctl_table *table = sd_alloc_ctl_entry(12);
+	struct ctl_table *table = sd_alloc_ctl_entry(13);
 
 	if (table == NULL)
 		return NULL;
@@ -6310,7 +6379,9 @@
 		sizeof(int), 0644, proc_dointvec_minmax);
 	set_table_entry(&table[10], "flags", &sd->flags,
 		sizeof(int), 0644, proc_dointvec_minmax);
-	/* &table[11] is terminator */
+	set_table_entry(&table[11], "name", sd->name,
+		CORENAME_MAX_SIZE, 0444, proc_dostring);
+	/* &table[12] is terminator */
 
 	return table;
 }
@@ -7194,13 +7265,21 @@
  * Non-inlined to reduce accumulated stack pressure in build_sched_domains()
  */
 
+#ifdef CONFIG_SCHED_DEBUG
+# define SD_INIT_NAME(sd, type)		sd->name = #type
+#else
+# define SD_INIT_NAME(sd, type)		do { } while (0)
+#endif
+
 #define	SD_INIT(sd, type)	sd_init_##type(sd)
+
 #define SD_INIT_FUNC(type)	\
 static noinline void sd_init_##type(struct sched_domain *sd)	\
 {								\
 	memset(sd, 0, sizeof(*sd));				\
 	*sd = SD_##type##_INIT;					\
 	sd->level = SD_LV_##type;				\
+	SD_INIT_NAME(sd, type);					\
 }
 
 SD_INIT_FUNC(CPU)
@@ -8242,20 +8321,25 @@
 #ifdef in_atomic
 	static unsigned long prev_jiffy;	/* ratelimiting */
 
-	if ((in_atomic() || irqs_disabled()) &&
-	    system_state == SYSTEM_RUNNING && !oops_in_progress) {
-		if (time_before(jiffies, prev_jiffy + HZ) && prev_jiffy)
-			return;
-		prev_jiffy = jiffies;
-		printk(KERN_ERR "BUG: sleeping function called from invalid"
-				" context at %s:%d\n", file, line);
-		printk("in_atomic():%d, irqs_disabled():%d\n",
-			in_atomic(), irqs_disabled());
-		debug_show_held_locks(current);
-		if (irqs_disabled())
-			print_irqtrace_events(current);
-		dump_stack();
-	}
+	if ((!in_atomic() && !irqs_disabled()) ||
+		    system_state != SYSTEM_RUNNING || oops_in_progress)
+		return;
+	if (time_before(jiffies, prev_jiffy + HZ) && prev_jiffy)
+		return;
+	prev_jiffy = jiffies;
+
+	printk(KERN_ERR
+		"BUG: sleeping function called from invalid context at %s:%d\n",
+			file, line);
+	printk(KERN_ERR
+		"in_atomic(): %d, irqs_disabled(): %d, pid: %d, name: %s\n",
+			in_atomic(), irqs_disabled(),
+			current->pid, current->comm);
+
+	debug_show_held_locks(current);
+	if (irqs_disabled())
+		print_irqtrace_events(current);
+	dump_stack();
 #endif
 }
 EXPORT_SYMBOL(__might_sleep);
@@ -8753,75 +8837,97 @@
 static unsigned long to_ratio(u64 period, u64 runtime)
 {
 	if (runtime == RUNTIME_INF)
-		return 1ULL << 16;
+		return 1ULL << 20;
 
-	return div64_u64(runtime << 16, period);
+	return div64_u64(runtime << 20, period);
 }
 
-#ifdef CONFIG_CGROUP_SCHED
-static int __rt_schedulable(struct task_group *tg, u64 period, u64 runtime)
-{
-	struct task_group *tgi, *parent = tg->parent;
-	unsigned long total = 0;
-
-	if (!parent) {
-		if (global_rt_period() < period)
-			return 0;
-
-		return to_ratio(period, runtime) <
-			to_ratio(global_rt_period(), global_rt_runtime());
-	}
-
-	if (ktime_to_ns(parent->rt_bandwidth.rt_period) < period)
-		return 0;
-
-	rcu_read_lock();
-	list_for_each_entry_rcu(tgi, &parent->children, siblings) {
-		if (tgi == tg)
-			continue;
-
-		total += to_ratio(ktime_to_ns(tgi->rt_bandwidth.rt_period),
-				tgi->rt_bandwidth.rt_runtime);
-	}
-	rcu_read_unlock();
-
-	return total + to_ratio(period, runtime) <=
-		to_ratio(ktime_to_ns(parent->rt_bandwidth.rt_period),
-				parent->rt_bandwidth.rt_runtime);
-}
-#elif defined CONFIG_USER_SCHED
-static int __rt_schedulable(struct task_group *tg, u64 period, u64 runtime)
-{
-	struct task_group *tgi;
-	unsigned long total = 0;
-	unsigned long global_ratio =
-		to_ratio(global_rt_period(), global_rt_runtime());
-
-	rcu_read_lock();
-	list_for_each_entry_rcu(tgi, &task_groups, list) {
-		if (tgi == tg)
-			continue;
-
-		total += to_ratio(ktime_to_ns(tgi->rt_bandwidth.rt_period),
-				tgi->rt_bandwidth.rt_runtime);
-	}
-	rcu_read_unlock();
-
-	return total + to_ratio(period, runtime) < global_ratio;
-}
-#endif
-
 /* Must be called with tasklist_lock held */
 static inline int tg_has_rt_tasks(struct task_group *tg)
 {
 	struct task_struct *g, *p;
+
 	do_each_thread(g, p) {
 		if (rt_task(p) && rt_rq_of_se(&p->rt)->tg == tg)
 			return 1;
 	} while_each_thread(g, p);
+
 	return 0;
 }
 
+struct rt_schedulable_data {
+	struct task_group *tg;
+	u64 rt_period;
+	u64 rt_runtime;
+};
+
+static int tg_schedulable(struct task_group *tg, void *data)
+{
+	struct rt_schedulable_data *d = data;
+	struct task_group *child;
+	unsigned long total, sum = 0;
+	u64 period, runtime;
+
+	period = ktime_to_ns(tg->rt_bandwidth.rt_period);
+	runtime = tg->rt_bandwidth.rt_runtime;
+
+	if (tg == d->tg) {
+		period = d->rt_period;
+		runtime = d->rt_runtime;
+	}
+
+	/*
+	 * Cannot have more runtime than the period.
+	 */
+	if (runtime > period && runtime != RUNTIME_INF)
+		return -EINVAL;
+
+	/*
+	 * Ensure we don't starve existing RT tasks.
+	 */
+	if (rt_bandwidth_enabled() && !runtime && tg_has_rt_tasks(tg))
+		return -EBUSY;
+
+	total = to_ratio(period, runtime);
+
+	/*
+	 * Nobody can have more than the global setting allows.
+	 */
+	if (total > to_ratio(global_rt_period(), global_rt_runtime()))
+		return -EINVAL;
+
+	/*
+	 * The sum of our children's runtime should not exceed our own.
+	 */
+	list_for_each_entry_rcu(child, &tg->children, siblings) {
+		period = ktime_to_ns(child->rt_bandwidth.rt_period);
+		runtime = child->rt_bandwidth.rt_runtime;
+
+		if (child == d->tg) {
+			period = d->rt_period;
+			runtime = d->rt_runtime;
+		}
+
+		sum += to_ratio(period, runtime);
+	}
+
+	if (sum > total)
+		return -EINVAL;
+
+	return 0;
+}
+
+static int __rt_schedulable(struct task_group *tg, u64 period, u64 runtime)
+{
+	struct rt_schedulable_data data = {
+		.tg = tg,
+		.rt_period = period,
+		.rt_runtime = runtime,
+	};
+
+	return walk_tg_tree(tg_schedulable, tg_nop, &data);
+}
+
 static int tg_set_bandwidth(struct task_group *tg,
 		u64 rt_period, u64 rt_runtime)
 {
@@ -8829,14 +8935,9 @@
 
 	mutex_lock(&rt_constraints_mutex);
 	read_lock(&tasklist_lock);
-	if (rt_runtime == 0 && tg_has_rt_tasks(tg)) {
-		err = -EBUSY;
+	err = __rt_schedulable(tg, rt_period, rt_runtime);
+	if (err)
 		goto unlock;
-	}
-	if (!__rt_schedulable(tg, rt_period, rt_runtime)) {
-		err = -EINVAL;
-		goto unlock;
-	}
 
 	spin_lock_irq(&tg->rt_bandwidth.rt_runtime_lock);
 	tg->rt_bandwidth.rt_period = ns_to_ktime(rt_period);
@@ -8905,16 +9006,25 @@
 
 static int sched_rt_global_constraints(void)
 {
-	struct task_group *tg = &root_task_group;
-	u64 rt_runtime, rt_period;
+	u64 runtime, period;
 	int ret = 0;
 
-	rt_period = ktime_to_ns(tg->rt_bandwidth.rt_period);
-	rt_runtime = tg->rt_bandwidth.rt_runtime;
+	if (sysctl_sched_rt_period <= 0)
+		return -EINVAL;
+
+	runtime = global_rt_runtime();
+	period = global_rt_period();
+
+	/*
+	 * Sanity check on the sysctl variables.
+	 */
+	if (runtime > period && runtime != RUNTIME_INF)
+		return -EINVAL;
 
 	mutex_lock(&rt_constraints_mutex);
-	if (!__rt_schedulable(tg, rt_period, rt_runtime))
-		ret = -EINVAL;
+	read_lock(&tasklist_lock);
+	ret = __rt_schedulable(NULL, 0, 0);
+	read_unlock(&tasklist_lock);
 	mutex_unlock(&rt_constraints_mutex);
 
 	return ret;
@@ -8925,6 +9035,9 @@
 	unsigned long flags;
 	int i;
 
+	if (sysctl_sched_rt_period <= 0)
+		return -EINVAL;
+
 	spin_lock_irqsave(&def_rt_bandwidth.rt_runtime_lock, flags);
 	for_each_possible_cpu(i) {
 		struct rt_rq *rt_rq = &cpu_rq(i)->rt;
@@ -8985,7 +9098,6 @@
 
 	if (!cgrp->parent) {
 		/* This is early initialization for the top cgroup */
-		init_task_group.css.cgroup = cgrp;
 		return &init_task_group.css;
 	}
 
@@ -8994,9 +9106,6 @@
 	if (IS_ERR(tg))
 		return ERR_PTR(-ENOMEM);
 
-	/* Bind the cgroup to task_group object we just created */
-	tg->css.cgroup = cgrp;
-
 	return &tg->css;
 }
 
diff --git a/kernel/sched_debug.c b/kernel/sched_debug.c
index bbe6b31..ad958c1 100644
--- a/kernel/sched_debug.c
+++ b/kernel/sched_debug.c
@@ -333,12 +333,10 @@
 	unsigned long flags;
 	int num_threads = 1;
 
-	rcu_read_lock();
 	if (lock_task_sighand(p, &flags)) {
 		num_threads = atomic_read(&p->signal->count);
 		unlock_task_sighand(p, &flags);
 	}
-	rcu_read_unlock();
 
 	SEQ_printf(m, "%s (%d, #threads: %d)\n", p->comm, p->pid, num_threads);
 	SEQ_printf(m,
diff --git a/kernel/sched_fair.c b/kernel/sched_fair.c
index fb8994c..18fd171 100644
--- a/kernel/sched_fair.c
+++ b/kernel/sched_fair.c
@@ -409,64 +409,6 @@
 }
 
 /*
- * The goal of calc_delta_asym() is to be asymmetrically around NICE_0_LOAD, in
- * that it favours >=0 over <0.
- *
- *   -20         |
- *               |
- *     0 --------+-------
- *             .'
- *    19     .'
- *
- */
-static unsigned long
-calc_delta_asym(unsigned long delta, struct sched_entity *se)
-{
-	struct load_weight lw = {
-		.weight = NICE_0_LOAD,
-		.inv_weight = 1UL << (WMULT_SHIFT-NICE_0_SHIFT)
-	};
-
-	for_each_sched_entity(se) {
-		struct load_weight *se_lw = &se->load;
-		unsigned long rw = cfs_rq_of(se)->load.weight;
-
-#ifdef CONFIG_FAIR_SCHED_GROUP
-		struct cfs_rq *cfs_rq = se->my_q;
-		struct task_group *tg = NULL
-
-		if (cfs_rq)
-			tg = cfs_rq->tg;
-
-		if (tg && tg->shares < NICE_0_LOAD) {
-			/*
-			 * scale shares to what it would have been had
-			 * tg->weight been NICE_0_LOAD:
-			 *
-			 *   weight = 1024 * shares / tg->weight
-			 */
-			lw.weight *= se->load.weight;
-			lw.weight /= tg->shares;
-
-			lw.inv_weight = 0;
-
-			se_lw = &lw;
-			rw += lw.weight - se->load.weight;
-		} else
-#endif
-
-		if (se->load.weight < NICE_0_LOAD) {
-			se_lw = &lw;
-			rw += NICE_0_LOAD - se->load.weight;
-		}
-
-		delta = calc_delta_mine(delta, rw, se_lw);
-	}
-
-	return delta;
-}
-
-/*
  * Update the current task's runtime statistics. Skip current tasks that
  * are not in our scheduling class.
  */
@@ -586,11 +528,12 @@
 	update_load_add(&cfs_rq->load, se->load.weight);
 	if (!parent_entity(se))
 		inc_cpu_load(rq_of(cfs_rq), se->load.weight);
-	if (entity_is_task(se))
+	if (entity_is_task(se)) {
 		add_cfs_task_weight(cfs_rq, se->load.weight);
+		list_add(&se->group_node, &cfs_rq->tasks);
+	}
 	cfs_rq->nr_running++;
 	se->on_rq = 1;
-	list_add(&se->group_node, &cfs_rq->tasks);
 }
 
 static void
@@ -599,11 +542,12 @@
 	update_load_sub(&cfs_rq->load, se->load.weight);
 	if (!parent_entity(se))
 		dec_cpu_load(rq_of(cfs_rq), se->load.weight);
-	if (entity_is_task(se))
+	if (entity_is_task(se)) {
 		add_cfs_task_weight(cfs_rq, -se->load.weight);
+		list_del_init(&se->group_node);
+	}
 	cfs_rq->nr_running--;
 	se->on_rq = 0;
-	list_del_init(&se->group_node);
 }
 
 static void enqueue_sleeper(struct cfs_rq *cfs_rq, struct sched_entity *se)
@@ -1085,7 +1029,6 @@
 		long wl, long wg)
 {
 	struct sched_entity *se = tg->se[cpu];
-	long more_w;
 
 	if (!tg->parent)
 		return wl;
@@ -1097,18 +1040,17 @@
 	if (!wl && sched_feat(ASYM_EFF_LOAD))
 		return wl;
 
-	/*
-	 * Instead of using this increment, also add the difference
-	 * between when the shares were last updated and now.
-	 */
-	more_w = se->my_q->load.weight - se->my_q->rq_weight;
-	wl += more_w;
-	wg += more_w;
-
 	for_each_sched_entity(se) {
-#define D(n) (likely(n) ? (n) : 1)
-
 		long S, rw, s, a, b;
+		long more_w;
+
+		/*
+		 * Instead of using this increment, also add the difference
+		 * between when the shares were last updated and now.
+		 */
+		more_w = se->my_q->load.weight - se->my_q->rq_weight;
+		wl += more_w;
+		wg += more_w;
 
 		S = se->my_q->tg->shares;
 		s = se->my_q->shares;
@@ -1117,7 +1059,11 @@
 		a = S*(rw + wl);
 		b = S*rw + s*wg;
 
-		wl = s*(a-b)/D(b);
+		wl = s*(a-b);
+
+		if (likely(b))
+			wl /= b;
+
 		/*
 		 * Assume the group is already running and will
 		 * thus already be accounted for in the weight.
@@ -1126,7 +1072,6 @@
 		 * alter the group weight.
 		 */
 		wg = 0;
-#undef D
 	}
 
 	return wl;
@@ -1143,7 +1088,7 @@
 #endif
 
 static int
-wake_affine(struct rq *rq, struct sched_domain *this_sd, struct rq *this_rq,
+wake_affine(struct sched_domain *this_sd, struct rq *this_rq,
 	    struct task_struct *p, int prev_cpu, int this_cpu, int sync,
 	    int idx, unsigned long load, unsigned long this_load,
 	    unsigned int imbalance)
@@ -1158,6 +1103,11 @@
 	if (!(this_sd->flags & SD_WAKE_AFFINE) || !sched_feat(AFFINE_WAKEUPS))
 		return 0;
 
+	if (!sync && sched_feat(SYNC_WAKEUPS) &&
+	    curr->se.avg_overlap < sysctl_sched_migration_cost &&
+	    p->se.avg_overlap < sysctl_sched_migration_cost)
+		sync = 1;
+
 	/*
 	 * If sync wakeup then subtract the (maximum possible)
 	 * effect of the currently running task from the load
@@ -1182,17 +1132,14 @@
 	 * a reasonable amount of time then attract this newly
 	 * woken task:
 	 */
-	if (sync && balanced) {
-		if (curr->se.avg_overlap < sysctl_sched_migration_cost &&
-		    p->se.avg_overlap < sysctl_sched_migration_cost)
-			return 1;
-	}
+	if (sync && balanced)
+		return 1;
 
 	schedstat_inc(p, se.nr_wakeups_affine_attempts);
 	tl_per_task = cpu_avg_load_per_task(this_cpu);
 
-	if ((tl <= load && tl + target_load(prev_cpu, idx) <= tl_per_task) ||
-			balanced) {
+	if (balanced || (tl <= load && tl + target_load(prev_cpu, idx) <=
+			tl_per_task)) {
 		/*
 		 * This domain has SD_WAKE_AFFINE and
 		 * p is cache cold in this domain, and
@@ -1211,16 +1158,17 @@
 	struct sched_domain *sd, *this_sd = NULL;
 	int prev_cpu, this_cpu, new_cpu;
 	unsigned long load, this_load;
-	struct rq *rq, *this_rq;
+	struct rq *this_rq;
 	unsigned int imbalance;
 	int idx;
 
 	prev_cpu	= task_cpu(p);
-	rq		= task_rq(p);
 	this_cpu	= smp_processor_id();
 	this_rq		= cpu_rq(this_cpu);
 	new_cpu		= prev_cpu;
 
+	if (prev_cpu == this_cpu)
+		goto out;
 	/*
 	 * 'this_sd' is the first domain that both
 	 * this_cpu and prev_cpu are present in:
@@ -1248,13 +1196,10 @@
 	load = source_load(prev_cpu, idx);
 	this_load = target_load(this_cpu, idx);
 
-	if (wake_affine(rq, this_sd, this_rq, p, prev_cpu, this_cpu, sync, idx,
+	if (wake_affine(this_sd, this_rq, p, prev_cpu, this_cpu, sync, idx,
 				     load, this_load, imbalance))
 		return this_cpu;
 
-	if (prev_cpu == this_cpu)
-		goto out;
-
 	/*
 	 * Start passive balancing when half the imbalance_pct
 	 * limit is reached.
@@ -1281,62 +1226,20 @@
 	 * + nice tasks.
 	 */
 	if (sched_feat(ASYM_GRAN))
-		gran = calc_delta_asym(sysctl_sched_wakeup_granularity, se);
-	else
-		gran = calc_delta_fair(sysctl_sched_wakeup_granularity, se);
+		gran = calc_delta_mine(gran, NICE_0_LOAD, &se->load);
 
 	return gran;
 }
 
 /*
- * Should 'se' preempt 'curr'.
- *
- *             |s1
- *        |s2
- *   |s3
- *         g
- *      |<--->|c
- *
- *  w(c, s1) = -1
- *  w(c, s2) =  0
- *  w(c, s3) =  1
- *
- */
-static int
-wakeup_preempt_entity(struct sched_entity *curr, struct sched_entity *se)
-{
-	s64 gran, vdiff = curr->vruntime - se->vruntime;
-
-	if (vdiff < 0)
-		return -1;
-
-	gran = wakeup_gran(curr);
-	if (vdiff > gran)
-		return 1;
-
-	return 0;
-}
-
-/* return depth at which a sched entity is present in the hierarchy */
-static inline int depth_se(struct sched_entity *se)
-{
-	int depth = 0;
-
-	for_each_sched_entity(se)
-		depth++;
-
-	return depth;
-}
-
-/*
  * Preempt the current task with a newly woken task if needed:
  */
-static void check_preempt_wakeup(struct rq *rq, struct task_struct *p)
+static void check_preempt_wakeup(struct rq *rq, struct task_struct *p, int sync)
 {
 	struct task_struct *curr = rq->curr;
 	struct cfs_rq *cfs_rq = task_cfs_rq(curr);
 	struct sched_entity *se = &curr->se, *pse = &p->se;
-	int se_depth, pse_depth;
+	s64 delta_exec;
 
 	if (unlikely(rt_prio(p->prio))) {
 		update_rq_clock(rq);
@@ -1351,6 +1254,13 @@
 	cfs_rq_of(pse)->next = pse;
 
 	/*
+	 * We can come here with TIF_NEED_RESCHED already set from new task
+	 * wake up path.
+	 */
+	if (test_tsk_need_resched(curr))
+		return;
+
+	/*
 	 * Batch tasks do not preempt (their preemption is driven by
 	 * the tick):
 	 */
@@ -1360,33 +1270,15 @@
 	if (!sched_feat(WAKEUP_PREEMPT))
 		return;
 
-	/*
-	 * preemption test can be made between sibling entities who are in the
-	 * same cfs_rq i.e who have a common parent. Walk up the hierarchy of
-	 * both tasks until we find their ancestors who are siblings of common
-	 * parent.
-	 */
-
-	/* First walk up until both entities are at same depth */
-	se_depth = depth_se(se);
-	pse_depth = depth_se(pse);
-
-	while (se_depth > pse_depth) {
-		se_depth--;
-		se = parent_entity(se);
+	if (sched_feat(WAKEUP_OVERLAP) && (sync ||
+			(se->avg_overlap < sysctl_sched_migration_cost &&
+			 pse->avg_overlap < sysctl_sched_migration_cost))) {
+		resched_task(curr);
+		return;
 	}
 
-	while (pse_depth > se_depth) {
-		pse_depth--;
-		pse = parent_entity(pse);
-	}
-
-	while (!is_same_group(se, pse)) {
-		se = parent_entity(se);
-		pse = parent_entity(pse);
-	}
-
-	if (wakeup_preempt_entity(se, pse) == 1)
+	delta_exec = se->sum_exec_runtime - se->prev_sum_exec_runtime;
+	if (delta_exec > wakeup_gran(pse))
 		resched_task(curr);
 }
 
@@ -1445,19 +1337,9 @@
 	if (next == &cfs_rq->tasks)
 		return NULL;
 
-	/* Skip over entities that are not tasks */
-	do {
-		se = list_entry(next, struct sched_entity, group_node);
-		next = next->next;
-	} while (next != &cfs_rq->tasks && !entity_is_task(se));
-
-	if (next == &cfs_rq->tasks)
-		return NULL;
-
-	cfs_rq->balance_iterator = next;
-
-	if (entity_is_task(se))
-		p = task_of(se);
+	se = list_entry(next, struct sched_entity, group_node);
+	p = task_of(se);
+	cfs_rq->balance_iterator = next->next;
 
 	return p;
 }
@@ -1507,7 +1389,7 @@
 	rcu_read_lock();
 	update_h_load(busiest_cpu);
 
-	list_for_each_entry(tg, &task_groups, list) {
+	list_for_each_entry_rcu(tg, &task_groups, list) {
 		struct cfs_rq *busiest_cfs_rq = tg->cfs_rq[busiest_cpu];
 		unsigned long busiest_h_load = busiest_cfs_rq->h_load;
 		unsigned long busiest_weight = busiest_cfs_rq->load.weight;
@@ -1620,10 +1502,10 @@
 		 * 'current' within the tree based on its new key value.
 		 */
 		swap(curr->vruntime, se->vruntime);
+		resched_task(rq->curr);
 	}
 
 	enqueue_task_fair(rq, p, 0);
-	resched_task(rq->curr);
 }
 
 /*
@@ -1642,7 +1524,7 @@
 		if (p->prio > oldprio)
 			resched_task(rq->curr);
 	} else
-		check_preempt_curr(rq, p);
+		check_preempt_curr(rq, p, 0);
 }
 
 /*
@@ -1659,7 +1541,7 @@
 	if (running)
 		resched_task(rq->curr);
 	else
-		check_preempt_curr(rq, p);
+		check_preempt_curr(rq, p, 0);
 }
 
 /* Account for a task changing its policy or group.
diff --git a/kernel/sched_features.h b/kernel/sched_features.h
index 9353ca7..7c9e8f4 100644
--- a/kernel/sched_features.h
+++ b/kernel/sched_features.h
@@ -11,3 +11,4 @@
 SCHED_FEAT(LB_BIAS, 1)
 SCHED_FEAT(LB_WAKEUP_UPDATE, 1)
 SCHED_FEAT(ASYM_EFF_LOAD, 1)
+SCHED_FEAT(WAKEUP_OVERLAP, 0)
diff --git a/kernel/sched_idletask.c b/kernel/sched_idletask.c
index 3a4f92d..dec4cca 100644
--- a/kernel/sched_idletask.c
+++ b/kernel/sched_idletask.c
@@ -14,7 +14,7 @@
 /*
  * Idle tasks are unconditionally rescheduled:
  */
-static void check_preempt_curr_idle(struct rq *rq, struct task_struct *p)
+static void check_preempt_curr_idle(struct rq *rq, struct task_struct *p, int sync)
 {
 	resched_task(rq->idle);
 }
@@ -76,7 +76,7 @@
 	if (running)
 		resched_task(rq->curr);
 	else
-		check_preempt_curr(rq, p);
+		check_preempt_curr(rq, p, 0);
 }
 
 static void prio_changed_idle(struct rq *rq, struct task_struct *p,
@@ -93,7 +93,7 @@
 		if (p->prio > oldprio)
 			resched_task(rq->curr);
 	} else
-		check_preempt_curr(rq, p);
+		check_preempt_curr(rq, p, 0);
 }
 
 /*
diff --git a/kernel/sched_rt.c b/kernel/sched_rt.c
index 5523107..cdf5740 100644
--- a/kernel/sched_rt.c
+++ b/kernel/sched_rt.c
@@ -102,12 +102,12 @@
 
 static void sched_rt_rq_enqueue(struct rt_rq *rt_rq)
 {
+	struct task_struct *curr = rq_of_rt_rq(rt_rq)->curr;
 	struct sched_rt_entity *rt_se = rt_rq->rt_se;
 
-	if (rt_se && !on_rt_rq(rt_se) && rt_rq->rt_nr_running) {
-		struct task_struct *curr = rq_of_rt_rq(rt_rq)->curr;
-
-		enqueue_rt_entity(rt_se);
+	if (rt_rq->rt_nr_running) {
+		if (rt_se && !on_rt_rq(rt_se))
+			enqueue_rt_entity(rt_se);
 		if (rt_rq->highest_prio < curr->prio)
 			resched_task(curr);
 	}
@@ -231,6 +231,9 @@
 #endif /* CONFIG_RT_GROUP_SCHED */
 
 #ifdef CONFIG_SMP
+/*
+ * We ran out of runtime, see if we can borrow some from our neighbours.
+ */
 static int do_balance_runtime(struct rt_rq *rt_rq)
 {
 	struct rt_bandwidth *rt_b = sched_rt_bandwidth(rt_rq);
@@ -250,9 +253,18 @@
 			continue;
 
 		spin_lock(&iter->rt_runtime_lock);
+		/*
+		 * Either all rqs have inf runtime and there's nothing to steal
+		 * or __disable_runtime() below sets a specific rq to inf to
+		 * indicate its been disabled and disalow stealing.
+		 */
 		if (iter->rt_runtime == RUNTIME_INF)
 			goto next;
 
+		/*
+		 * From runqueues with spare time, take 1/n part of their
+		 * spare time, but no more than our period.
+		 */
 		diff = iter->rt_runtime - iter->rt_time;
 		if (diff > 0) {
 			diff = div_u64((u64)diff, weight);
@@ -274,6 +286,9 @@
 	return more;
 }
 
+/*
+ * Ensure this RQ takes back all the runtime it lend to its neighbours.
+ */
 static void __disable_runtime(struct rq *rq)
 {
 	struct root_domain *rd = rq->rd;
@@ -289,17 +304,33 @@
 
 		spin_lock(&rt_b->rt_runtime_lock);
 		spin_lock(&rt_rq->rt_runtime_lock);
+		/*
+		 * Either we're all inf and nobody needs to borrow, or we're
+		 * already disabled and thus have nothing to do, or we have
+		 * exactly the right amount of runtime to take out.
+		 */
 		if (rt_rq->rt_runtime == RUNTIME_INF ||
 				rt_rq->rt_runtime == rt_b->rt_runtime)
 			goto balanced;
 		spin_unlock(&rt_rq->rt_runtime_lock);
 
+		/*
+		 * Calculate the difference between what we started out with
+		 * and what we current have, that's the amount of runtime
+		 * we lend and now have to reclaim.
+		 */
 		want = rt_b->rt_runtime - rt_rq->rt_runtime;
 
+		/*
+		 * Greedy reclaim, take back as much as we can.
+		 */
 		for_each_cpu_mask(i, rd->span) {
 			struct rt_rq *iter = sched_rt_period_rt_rq(rt_b, i);
 			s64 diff;
 
+			/*
+			 * Can't reclaim from ourselves or disabled runqueues.
+			 */
 			if (iter == rt_rq || iter->rt_runtime == RUNTIME_INF)
 				continue;
 
@@ -319,8 +350,16 @@
 		}
 
 		spin_lock(&rt_rq->rt_runtime_lock);
+		/*
+		 * We cannot be left wanting - that would mean some runtime
+		 * leaked out of the system.
+		 */
 		BUG_ON(want);
 balanced:
+		/*
+		 * Disable all the borrow logic by pretending we have inf
+		 * runtime - in which case borrowing doesn't make sense.
+		 */
 		rt_rq->rt_runtime = RUNTIME_INF;
 		spin_unlock(&rt_rq->rt_runtime_lock);
 		spin_unlock(&rt_b->rt_runtime_lock);
@@ -343,6 +382,9 @@
 	if (unlikely(!scheduler_running))
 		return;
 
+	/*
+	 * Reset each runqueue's bandwidth settings
+	 */
 	for_each_leaf_rt_rq(rt_rq, rq) {
 		struct rt_bandwidth *rt_b = sched_rt_bandwidth(rt_rq);
 
@@ -350,6 +392,7 @@
 		spin_lock(&rt_rq->rt_runtime_lock);
 		rt_rq->rt_runtime = rt_b->rt_runtime;
 		rt_rq->rt_time = 0;
+		rt_rq->rt_throttled = 0;
 		spin_unlock(&rt_rq->rt_runtime_lock);
 		spin_unlock(&rt_b->rt_runtime_lock);
 	}
@@ -388,7 +431,7 @@
 	int i, idle = 1;
 	cpumask_t span;
 
-	if (rt_b->rt_runtime == RUNTIME_INF)
+	if (!rt_bandwidth_enabled() || rt_b->rt_runtime == RUNTIME_INF)
 		return 1;
 
 	span = sched_rt_period_mask();
@@ -486,6 +529,9 @@
 	curr->se.exec_start = rq->clock;
 	cpuacct_charge(curr, delta_exec);
 
+	if (!rt_bandwidth_enabled())
+		return;
+
 	for_each_sched_rt_entity(rt_se) {
 		rt_rq = rt_rq_of_se(rt_se);
 
@@ -783,7 +829,7 @@
 /*
  * Preempt the current task with a newly woken task if needed:
  */
-static void check_preempt_curr_rt(struct rq *rq, struct task_struct *p)
+static void check_preempt_curr_rt(struct rq *rq, struct task_struct *p, int sync)
 {
 	if (p->prio < rq->curr->prio) {
 		resched_task(rq->curr);
diff --git a/kernel/softirq.c b/kernel/softirq.c
index c506f26..be7a829 100644
--- a/kernel/softirq.c
+++ b/kernel/softirq.c
@@ -46,7 +46,7 @@
 EXPORT_SYMBOL(irq_stat);
 #endif
 
-static struct softirq_action softirq_vec[32] __cacheline_aligned_in_smp;
+static struct softirq_action softirq_vec[NR_SOFTIRQS] __cacheline_aligned_in_smp;
 
 static DEFINE_PER_CPU(struct task_struct *, ksoftirqd);
 
@@ -205,7 +205,18 @@
 
 	do {
 		if (pending & 1) {
+			int prev_count = preempt_count();
+
 			h->action(h);
+
+			if (unlikely(prev_count != preempt_count())) {
+				printk(KERN_ERR "huh, entered softirq %d %p"
+				       "with preempt_count %08x,"
+				       " exited with %08x?\n", h - softirq_vec,
+				       h->action, prev_count, preempt_count());
+				preempt_count() = prev_count;
+			}
+
 			rcu_bh_qsctr_inc(cpu);
 		}
 		h++;
diff --git a/kernel/sys.c b/kernel/sys.c
index 038a7bc..234d945 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -1060,9 +1060,7 @@
 	group_leader->signal->leader = 1;
 	__set_special_pids(sid);
 
-	spin_lock(&group_leader->sighand->siglock);
-	group_leader->signal->tty = NULL;
-	spin_unlock(&group_leader->sighand->siglock);
+	proc_clear_tty(group_leader);
 
 	err = session;
 out:
diff --git a/kernel/sys_ni.c b/kernel/sys_ni.c
index 08d6e1b..503d8d4 100644
--- a/kernel/sys_ni.c
+++ b/kernel/sys_ni.c
@@ -125,6 +125,7 @@
 cond_syscall(sys_vm86);
 cond_syscall(compat_sys_ipc);
 cond_syscall(compat_sys_sysctl);
+cond_syscall(sys_flock);
 
 /* arch-specific weak syscall entries */
 cond_syscall(sys_pciconfig_read);
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index 50ec088..cfc5295 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -80,7 +80,6 @@
 extern int sysctl_drop_caches;
 extern int percpu_pagelist_fraction;
 extern int compat_log;
-extern int maps_protect;
 extern int latencytop_enabled;
 extern int sysctl_nr_open_min, sysctl_nr_open_max;
 #ifdef CONFIG_RCU_TORTURE_TEST
@@ -97,7 +96,7 @@
 static int neg_one = -1;
 #endif
 
-#ifdef CONFIG_MMU
+#if defined(CONFIG_MMU) && defined(CONFIG_FILE_LOCKING)
 static int two = 2;
 #endif
 
@@ -118,10 +117,8 @@
 extern int sg_big_buff;
 #endif
 
-#ifdef __sparc__
-extern char reboot_command [];
-extern int stop_a_enabled;
-extern int scons_pwroff;
+#ifdef CONFIG_SPARC
+#include <asm/system.h>
 #endif
 
 #ifdef __hppa__
@@ -415,7 +412,7 @@
 		.mode		= 0644,
 		.proc_handler	= &proc_dointvec,
 	},
-#ifdef __sparc__
+#ifdef CONFIG_SPARC
 	{
 		.ctl_name	= KERN_SPARC_REBOOT,
 		.procname	= "reboot-cmd",
@@ -810,16 +807,6 @@
 		.proc_handler	= &proc_dointvec,
 	},
 #endif
-#ifdef CONFIG_PROC_FS
-	{
-		.ctl_name       = CTL_UNNUMBERED,
-		.procname       = "maps_protect",
-		.data           = &maps_protect,
-		.maxlen         = sizeof(int),
-		.mode           = 0644,
-		.proc_handler   = &proc_dointvec,
-	},
-#endif
 	{
 		.ctl_name	= CTL_UNNUMBERED,
 		.procname	= "poweroff_cmd",
@@ -1261,6 +1248,7 @@
 		.extra1		= &minolduid,
 		.extra2		= &maxolduid,
 	},
+#ifdef CONFIG_FILE_LOCKING
 	{
 		.ctl_name	= FS_LEASES,
 		.procname	= "leases-enable",
@@ -1269,6 +1257,7 @@
 		.mode		= 0644,
 		.proc_handler	= &proc_dointvec,
 	},
+#endif
 #ifdef CONFIG_DNOTIFY
 	{
 		.ctl_name	= FS_DIR_NOTIFY,
@@ -1280,6 +1269,7 @@
 	},
 #endif
 #ifdef CONFIG_MMU
+#ifdef CONFIG_FILE_LOCKING
 	{
 		.ctl_name	= FS_LEASE_TIME,
 		.procname	= "lease-break-time",
@@ -1291,6 +1281,7 @@
 		.extra1		= &zero,
 		.extra2		= &two,
 	},
+#endif
 	{
 		.procname	= "aio-nr",
 		.data		= &aio_nr,
diff --git a/kernel/time/clockevents.c b/kernel/time/clockevents.c
index 1876b52..f8d9680 100644
--- a/kernel/time/clockevents.c
+++ b/kernel/time/clockevents.c
@@ -72,6 +72,16 @@
 }
 
 /**
+ * clockevents_shutdown - shutdown the device and clear next_event
+ * @dev:	device to shutdown
+ */
+void clockevents_shutdown(struct clock_event_device *dev)
+{
+	clockevents_set_mode(dev, CLOCK_EVT_MODE_SHUTDOWN);
+	dev->next_event.tv64 = KTIME_MAX;
+}
+
+/**
  * clockevents_program_event - Reprogram the clock event device.
  * @expires:	absolute expiry time (monotonic clock)
  *
@@ -206,7 +216,7 @@
 
 	if (new) {
 		BUG_ON(new->mode != CLOCK_EVT_MODE_UNUSED);
-		clockevents_set_mode(new, CLOCK_EVT_MODE_SHUTDOWN);
+		clockevents_shutdown(new);
 	}
 	local_irq_restore(flags);
 }
diff --git a/kernel/time/tick-broadcast.c b/kernel/time/tick-broadcast.c
index 2f5a382..cb01cd8 100644
--- a/kernel/time/tick-broadcast.c
+++ b/kernel/time/tick-broadcast.c
@@ -235,9 +235,9 @@
 	case CLOCK_EVT_NOTIFY_BROADCAST_FORCE:
 		if (!cpu_isset(cpu, tick_broadcast_mask)) {
 			cpu_set(cpu, tick_broadcast_mask);
-			if (td->mode == TICKDEV_MODE_PERIODIC)
-				clockevents_set_mode(dev,
-						     CLOCK_EVT_MODE_SHUTDOWN);
+			if (tick_broadcast_device.mode ==
+			    TICKDEV_MODE_PERIODIC)
+				clockevents_shutdown(dev);
 		}
 		if (*reason == CLOCK_EVT_NOTIFY_BROADCAST_FORCE)
 			tick_broadcast_force = 1;
@@ -246,7 +246,8 @@
 		if (!tick_broadcast_force &&
 		    cpu_isset(cpu, tick_broadcast_mask)) {
 			cpu_clear(cpu, tick_broadcast_mask);
-			if (td->mode == TICKDEV_MODE_PERIODIC)
+			if (tick_broadcast_device.mode ==
+			    TICKDEV_MODE_PERIODIC)
 				tick_setup_periodic(dev, 0);
 		}
 		break;
@@ -254,7 +255,7 @@
 
 	if (cpus_empty(tick_broadcast_mask)) {
 		if (!bc_stopped)
-			clockevents_set_mode(bc, CLOCK_EVT_MODE_SHUTDOWN);
+			clockevents_shutdown(bc);
 	} else if (bc_stopped) {
 		if (tick_broadcast_device.mode == TICKDEV_MODE_PERIODIC)
 			tick_broadcast_start_periodic(bc);
@@ -306,7 +307,7 @@
 
 	if (tick_broadcast_device.mode == TICKDEV_MODE_PERIODIC) {
 		if (bc && cpus_empty(tick_broadcast_mask))
-			clockevents_set_mode(bc, CLOCK_EVT_MODE_SHUTDOWN);
+			clockevents_shutdown(bc);
 	}
 
 	spin_unlock_irqrestore(&tick_broadcast_lock, flags);
@@ -321,7 +322,7 @@
 
 	bc = tick_broadcast_device.evtdev;
 	if (bc)
-		clockevents_set_mode(bc, CLOCK_EVT_MODE_SHUTDOWN);
+		clockevents_shutdown(bc);
 
 	spin_unlock_irqrestore(&tick_broadcast_lock, flags);
 }
@@ -576,4 +577,12 @@
 	spin_unlock_irqrestore(&tick_broadcast_lock, flags);
 }
 
+/*
+ * Check, whether the broadcast device is in one shot mode
+ */
+int tick_broadcast_oneshot_active(void)
+{
+	return tick_broadcast_device.mode == TICKDEV_MODE_ONESHOT;
+}
+
 #endif
diff --git a/kernel/time/tick-common.c b/kernel/time/tick-common.c
index c477719..df12434 100644
--- a/kernel/time/tick-common.c
+++ b/kernel/time/tick-common.c
@@ -33,7 +33,7 @@
  */
 ktime_t tick_next_period;
 ktime_t tick_period;
-int tick_do_timer_cpu __read_mostly = -1;
+int tick_do_timer_cpu __read_mostly = TICK_DO_TIMER_BOOT;
 DEFINE_SPINLOCK(tick_device_lock);
 
 /*
@@ -109,7 +109,8 @@
 	if (!tick_device_is_functional(dev))
 		return;
 
-	if (dev->features & CLOCK_EVT_FEAT_PERIODIC) {
+	if ((dev->features & CLOCK_EVT_FEAT_PERIODIC) &&
+	    !tick_broadcast_oneshot_active()) {
 		clockevents_set_mode(dev, CLOCK_EVT_MODE_PERIODIC);
 	} else {
 		unsigned long seq;
@@ -148,7 +149,7 @@
 		 * If no cpu took the do_timer update, assign it to
 		 * this cpu:
 		 */
-		if (tick_do_timer_cpu == -1) {
+		if (tick_do_timer_cpu == TICK_DO_TIMER_BOOT) {
 			tick_do_timer_cpu = cpu;
 			tick_next_period = ktime_get();
 			tick_period = ktime_set(0, NSEC_PER_SEC / HZ);
@@ -249,7 +250,7 @@
 	 * not give it back to the clockevents layer !
 	 */
 	if (tick_is_broadcast_device(curdev)) {
-		clockevents_set_mode(curdev, CLOCK_EVT_MODE_SHUTDOWN);
+		clockevents_shutdown(curdev);
 		curdev = NULL;
 	}
 	clockevents_exchange_device(curdev, newdev);
@@ -300,7 +301,8 @@
 	if (*cpup == tick_do_timer_cpu) {
 		int cpu = first_cpu(cpu_online_map);
 
-		tick_do_timer_cpu = (cpu != NR_CPUS) ? cpu : -1;
+		tick_do_timer_cpu = (cpu != NR_CPUS) ? cpu :
+			TICK_DO_TIMER_NONE;
 	}
 	spin_unlock_irqrestore(&tick_device_lock, flags);
 }
@@ -311,7 +313,7 @@
 	unsigned long flags;
 
 	spin_lock_irqsave(&tick_device_lock, flags);
-	clockevents_set_mode(td->evtdev, CLOCK_EVT_MODE_SHUTDOWN);
+	clockevents_shutdown(td->evtdev);
 	spin_unlock_irqrestore(&tick_device_lock, flags);
 }
 
diff --git a/kernel/time/tick-internal.h b/kernel/time/tick-internal.h
index 0ffc291..4692487 100644
--- a/kernel/time/tick-internal.h
+++ b/kernel/time/tick-internal.h
@@ -1,6 +1,10 @@
 /*
  * tick internal variable and functions used by low/high res code
  */
+
+#define TICK_DO_TIMER_NONE	-1
+#define TICK_DO_TIMER_BOOT	-2
+
 DECLARE_PER_CPU(struct tick_device, tick_cpu_device);
 extern spinlock_t tick_device_lock;
 extern ktime_t tick_next_period;
@@ -10,6 +14,8 @@
 extern void tick_setup_periodic(struct clock_event_device *dev, int broadcast);
 extern void tick_handle_periodic(struct clock_event_device *dev);
 
+extern void clockevents_shutdown(struct clock_event_device *dev);
+
 /*
  * NO_HZ / high resolution timer shared code
  */
@@ -29,6 +35,7 @@
 extern void tick_broadcast_switch_to_oneshot(void);
 extern void tick_shutdown_broadcast_oneshot(unsigned int *cpup);
 extern int tick_resume_broadcast_oneshot(struct clock_event_device *bc);
+extern int tick_broadcast_oneshot_active(void);
 # else /* BROADCAST */
 static inline void tick_broadcast_setup_oneshot(struct clock_event_device *bc)
 {
@@ -37,6 +44,7 @@
 static inline void tick_broadcast_oneshot_control(unsigned long reason) { }
 static inline void tick_broadcast_switch_to_oneshot(void) { }
 static inline void tick_shutdown_broadcast_oneshot(unsigned int *cpup) { }
+static inline int tick_broadcast_oneshot_active(void) { return 0; }
 # endif /* !BROADCAST */
 
 #else /* !ONESHOT */
@@ -66,6 +74,7 @@
 {
 	return 0;
 }
+static inline int tick_broadcast_oneshot_active(void) { return 0; }
 #endif /* !TICK_ONESHOT */
 
 /*
diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c
index a87b046..b711ffc 100644
--- a/kernel/time/tick-sched.c
+++ b/kernel/time/tick-sched.c
@@ -20,6 +20,7 @@
 #include <linux/profile.h>
 #include <linux/sched.h>
 #include <linux/tick.h>
+#include <linux/module.h>
 
 #include <asm/irq_regs.h>
 
@@ -75,6 +76,9 @@
 							   incr * ticks);
 		}
 		do_timer(++ticks);
+
+		/* Keep the tick_next_period variable up to date */
+		tick_next_period = ktime_add(last_jiffies_update, tick_period);
 	}
 	write_sequnlock(&xtime_lock);
 }
@@ -187,9 +191,17 @@
 {
 	struct tick_sched *ts = &per_cpu(tick_cpu_sched, cpu);
 
-	*last_update_time = ktime_to_us(ts->idle_lastupdate);
+	if (!tick_nohz_enabled)
+		return -1;
+
+	if (ts->idle_active)
+		*last_update_time = ktime_to_us(ts->idle_lastupdate);
+	else
+		*last_update_time = ktime_to_us(ktime_get());
+
 	return ktime_to_us(ts->idle_sleeptime);
 }
+EXPORT_SYMBOL_GPL(get_cpu_idle_time_us);
 
 /**
  * tick_nohz_stop_sched_tick - stop the idle tick from the idle task
@@ -221,7 +233,7 @@
 	 */
 	if (unlikely(!cpu_online(cpu))) {
 		if (cpu == tick_do_timer_cpu)
-			tick_do_timer_cpu = -1;
+			tick_do_timer_cpu = TICK_DO_TIMER_NONE;
 	}
 
 	if (unlikely(ts->nohz_mode == NOHZ_MODE_INACTIVE))
@@ -258,7 +270,7 @@
 	next_jiffies = get_next_timer_interrupt(last_jiffies);
 	delta_jiffies = next_jiffies - last_jiffies;
 
-	if (rcu_needs_cpu(cpu))
+	if (rcu_needs_cpu(cpu) || printk_needs_cpu(cpu))
 		delta_jiffies = 1;
 	/*
 	 * Do not stop the tick, if we are only one off
@@ -303,7 +315,7 @@
 		 * invoked.
 		 */
 		if (cpu == tick_do_timer_cpu)
-			tick_do_timer_cpu = -1;
+			tick_do_timer_cpu = TICK_DO_TIMER_NONE;
 
 		ts->idle_sleeps++;
 
@@ -468,7 +480,7 @@
 	 * this duty, then the jiffies update is still serialized by
 	 * xtime_lock.
 	 */
-	if (unlikely(tick_do_timer_cpu == -1))
+	if (unlikely(tick_do_timer_cpu == TICK_DO_TIMER_NONE))
 		tick_do_timer_cpu = cpu;
 
 	/* Check, if the jiffies need an update */
@@ -570,7 +582,7 @@
 	 * this duty, then the jiffies update is still serialized by
 	 * xtime_lock.
 	 */
-	if (unlikely(tick_do_timer_cpu == -1))
+	if (unlikely(tick_do_timer_cpu == TICK_DO_TIMER_NONE))
 		tick_do_timer_cpu = cpu;
 #endif
 
@@ -622,7 +634,7 @@
 	 */
 	hrtimer_init(&ts->sched_timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
 	ts->sched_timer.function = tick_sched_timer;
-	ts->sched_timer.cb_mode = HRTIMER_CB_IRQSAFE_NO_SOFTIRQ;
+	ts->sched_timer.cb_mode = HRTIMER_CB_IRQSAFE_PERCPU;
 
 	/* Get the next period (per cpu) */
 	ts->sched_timer.expires = tick_init_jiffy_update();
diff --git a/kernel/timer.c b/kernel/timer.c
index 03bc7f1..510fe69 100644
--- a/kernel/timer.c
+++ b/kernel/timer.c
@@ -978,6 +978,7 @@
 	run_local_timers();
 	if (rcu_pending(cpu))
 		rcu_check_callbacks(cpu, user_tick);
+	printk_tick();
 	scheduler_tick();
 	run_posix_cpu_timers(p);
 }
diff --git a/kernel/trace/trace_sysprof.c b/kernel/trace/trace_sysprof.c
index bb948e52..db58fb6 100644
--- a/kernel/trace/trace_sysprof.c
+++ b/kernel/trace/trace_sysprof.c
@@ -202,7 +202,7 @@
 
 	hrtimer_init(hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
 	hrtimer->function = stack_trace_timer_fn;
-	hrtimer->cb_mode = HRTIMER_CB_IRQSAFE_NO_SOFTIRQ;
+	hrtimer->cb_mode = HRTIMER_CB_IRQSAFE_PERCPU;
 
 	hrtimer_start(hrtimer, ns_to_ktime(sample_period), HRTIMER_MODE_REL);
 }
diff --git a/kernel/user.c b/kernel/user.c
index 865ecf57..39d6159 100644
--- a/kernel/user.c
+++ b/kernel/user.c
@@ -169,7 +169,7 @@
 {
 	struct user_struct *up = container_of(kobj, struct user_struct, kobj);
 
-	return sprintf(buf, "%lu\n", sched_group_rt_runtime(up->tg));
+	return sprintf(buf, "%ld\n", sched_group_rt_runtime(up->tg));
 }
 
 static ssize_t cpu_rt_runtime_store(struct kobject *kobj,
@@ -180,7 +180,7 @@
 	unsigned long rt_runtime;
 	int rc;
 
-	sscanf(buf, "%lu", &rt_runtime);
+	sscanf(buf, "%ld", &rt_runtime);
 
 	rc = sched_group_set_rt_runtime(up->tg, rt_runtime);
 
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index 0b50481..aa81d28 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -495,6 +495,15 @@
 
 	  If unsure, say N.
 
+config DEBUG_VIRTUAL
+	bool "Debug VM translations"
+	depends on DEBUG_KERNEL && X86
+	help
+	  Enable some costly sanity checks in virtual to page code. This can
+	  catch mistakes with virt_to_page() and friends.
+
+	  If unsure, say N.
+
 config DEBUG_WRITECOUNT
 	bool "Debug filesystem writers count"
 	depends on DEBUG_KERNEL
@@ -597,6 +606,19 @@
 	  Say N here if you want the RCU torture tests to start only
 	  after being manually enabled via /proc.
 
+config RCU_CPU_STALL_DETECTOR
+	bool "Check for stalled CPUs delaying RCU grace periods"
+	depends on CLASSIC_RCU
+	default n
+	help
+	  This option causes RCU to printk information on which
+	  CPUs are delaying the current grace period, but only when
+	  the grace period extends for excessive time periods.
+
+	  Say Y if you want RCU to perform such checks.
+
+	  Say N if you are unsure.
+
 config KPROBES_SANITY_TEST
 	bool "Kprobes sanity tests"
 	depends on DEBUG_KERNEL
@@ -624,6 +646,28 @@
 
 	  Say N if you are unsure.
 
+config DEBUG_BLOCK_EXT_DEVT
+        bool "Force extended block device numbers and spread them"
+	depends on DEBUG_KERNEL
+	depends on BLOCK
+	default n
+	help
+	  Conventionally, block device numbers are allocated from
+	  predetermined contiguous area.  However, extended block area
+	  may introduce non-contiguous block device numbers.  This
+	  option forces most block device numbers to be allocated from
+	  the extended space and spreads them to discover kernel or
+	  userland code paths which assume predetermined contiguous
+	  device number allocation.
+
+	  Note that turning on this debug option shuffles all the
+	  device numbers for all IDE and SCSI devices including libata
+	  ones, so root partition specified using device number
+	  directly (via rdev or root=MAJ:MIN) won't work anymore.
+	  Textual device names (root=/dev/sdXn) will continue to work.
+
+	  Say N if you are unsure.
+
 config LKDTM
 	tristate "Linux Kernel Dump Test Tool Module"
 	depends on DEBUG_KERNEL
@@ -661,10 +705,21 @@
 
 config FAIL_MAKE_REQUEST
 	bool "Fault-injection capability for disk IO"
-	depends on FAULT_INJECTION
+	depends on FAULT_INJECTION && BLOCK
 	help
 	  Provide fault-injection capability for disk IO.
 
+config FAIL_IO_TIMEOUT
+	bool "Faul-injection capability for faking disk interrupts"
+	depends on FAULT_INJECTION && BLOCK
+	help
+	  Provide fault-injection capability on end IO handling. This
+	  will make the block layer "forget" an interrupt as configured,
+	  thus exercising the error handling.
+
+	  Only works with drivers that use the generic timeout handling,
+	  for others it wont do anything.
+
 config FAULT_INJECTION_DEBUG_FS
 	bool "Debugfs entries for fault-injection capabilities"
 	depends on FAULT_INJECTION && SYSFS && DEBUG_FS
diff --git a/lib/Makefile b/lib/Makefile
index 3b1f94b..44001af 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -19,7 +19,8 @@
 lib-y	+= kobject.o kref.o klist.o
 
 obj-y += bcd.o div64.o sort.o parser.o halfmd4.o debug_locks.o random32.o \
-	 bust_spinlocks.o hexdump.o kasprintf.o bitmap.o scatterlist.o
+	 bust_spinlocks.o hexdump.o kasprintf.o bitmap.o scatterlist.o \
+	 string_helpers.o
 
 ifeq ($(CONFIG_DEBUG_KOBJECT),y)
 CFLAGS_kobject.o += -DDEBUG
diff --git a/lib/cmdline.c b/lib/cmdline.c
index 5ba8a94..f5f3ad8 100644
--- a/lib/cmdline.c
+++ b/lib/cmdline.c
@@ -126,7 +126,7 @@
  *	megabyte, or one gigabyte, respectively.
  */
 
-unsigned long long memparse(char *ptr, char **retptr)
+unsigned long long memparse(const char *ptr, char **retptr)
 {
 	char *endptr;	/* local pointer to end of parsed string */
 
diff --git a/lib/iommu-helper.c b/lib/iommu-helper.c
index a3b8d4c..5d90074 100644
--- a/lib/iommu-helper.c
+++ b/lib/iommu-helper.c
@@ -30,8 +30,7 @@
 	return index;
 }
 
-static inline void set_bit_area(unsigned long *map, unsigned long i,
-				int len)
+void iommu_area_reserve(unsigned long *map, unsigned long i, int len)
 {
 	unsigned long end = i + len;
 	while (i < end) {
@@ -64,7 +63,7 @@
 			start = index + 1;
 			goto again;
 		}
-		set_bit_area(map, index, nr);
+		iommu_area_reserve(map, index, nr);
 	}
 	return index;
 }
diff --git a/lib/klist.c b/lib/klist.c
index cca37f9..bbdd301 100644
--- a/lib/klist.c
+++ b/lib/klist.c
@@ -37,6 +37,37 @@
 #include <linux/klist.h>
 #include <linux/module.h>
 
+/*
+ * Use the lowest bit of n_klist to mark deleted nodes and exclude
+ * dead ones from iteration.
+ */
+#define KNODE_DEAD		1LU
+#define KNODE_KLIST_MASK	~KNODE_DEAD
+
+static struct klist *knode_klist(struct klist_node *knode)
+{
+	return (struct klist *)
+		((unsigned long)knode->n_klist & KNODE_KLIST_MASK);
+}
+
+static bool knode_dead(struct klist_node *knode)
+{
+	return (unsigned long)knode->n_klist & KNODE_DEAD;
+}
+
+static void knode_set_klist(struct klist_node *knode, struct klist *klist)
+{
+	knode->n_klist = klist;
+	/* no knode deserves to start its life dead */
+	WARN_ON(knode_dead(knode));
+}
+
+static void knode_kill(struct klist_node *knode)
+{
+	/* and no knode should die twice ever either, see we're very humane */
+	WARN_ON(knode_dead(knode));
+	*(unsigned long *)&knode->n_klist |= KNODE_DEAD;
+}
 
 /**
  * klist_init - Initialize a klist structure.
@@ -79,7 +110,7 @@
 	INIT_LIST_HEAD(&n->n_node);
 	init_completion(&n->n_removed);
 	kref_init(&n->n_ref);
-	n->n_klist = k;
+	knode_set_klist(n, k);
 	if (k->get)
 		k->get(n);
 }
@@ -115,7 +146,7 @@
  */
 void klist_add_after(struct klist_node *n, struct klist_node *pos)
 {
-	struct klist *k = pos->n_klist;
+	struct klist *k = knode_klist(pos);
 
 	klist_node_init(k, n);
 	spin_lock(&k->k_lock);
@@ -131,7 +162,7 @@
  */
 void klist_add_before(struct klist_node *n, struct klist_node *pos)
 {
-	struct klist *k = pos->n_klist;
+	struct klist *k = knode_klist(pos);
 
 	klist_node_init(k, n);
 	spin_lock(&k->k_lock);
@@ -144,9 +175,10 @@
 {
 	struct klist_node *n = container_of(kref, struct klist_node, n_ref);
 
+	WARN_ON(!knode_dead(n));
 	list_del(&n->n_node);
 	complete(&n->n_removed);
-	n->n_klist = NULL;
+	knode_set_klist(n, NULL);
 }
 
 static int klist_dec_and_del(struct klist_node *n)
@@ -154,21 +186,28 @@
 	return kref_put(&n->n_ref, klist_release);
 }
 
+static void klist_put(struct klist_node *n, bool kill)
+{
+	struct klist *k = knode_klist(n);
+	void (*put)(struct klist_node *) = k->put;
+
+	spin_lock(&k->k_lock);
+	if (kill)
+		knode_kill(n);
+	if (!klist_dec_and_del(n))
+		put = NULL;
+	spin_unlock(&k->k_lock);
+	if (put)
+		put(n);
+}
+
 /**
  * klist_del - Decrement the reference count of node and try to remove.
  * @n: node we're deleting.
  */
 void klist_del(struct klist_node *n)
 {
-	struct klist *k = n->n_klist;
-	void (*put)(struct klist_node *) = k->put;
-
-	spin_lock(&k->k_lock);
-	if (!klist_dec_and_del(n))
-		put = NULL;
-	spin_unlock(&k->k_lock);
-	if (put)
-		put(n);
+	klist_put(n, true);
 }
 EXPORT_SYMBOL_GPL(klist_del);
 
@@ -206,7 +245,6 @@
 			  struct klist_node *n)
 {
 	i->i_klist = k;
-	i->i_head = &k->k_list;
 	i->i_cur = n;
 	if (n)
 		kref_get(&n->n_ref);
@@ -237,7 +275,7 @@
 void klist_iter_exit(struct klist_iter *i)
 {
 	if (i->i_cur) {
-		klist_del(i->i_cur);
+		klist_put(i->i_cur, false);
 		i->i_cur = NULL;
 	}
 }
@@ -258,27 +296,33 @@
  */
 struct klist_node *klist_next(struct klist_iter *i)
 {
-	struct list_head *next;
-	struct klist_node *lnode = i->i_cur;
-	struct klist_node *knode = NULL;
 	void (*put)(struct klist_node *) = i->i_klist->put;
+	struct klist_node *last = i->i_cur;
+	struct klist_node *next;
 
 	spin_lock(&i->i_klist->k_lock);
-	if (lnode) {
-		next = lnode->n_node.next;
-		if (!klist_dec_and_del(lnode))
+
+	if (last) {
+		next = to_klist_node(last->n_node.next);
+		if (!klist_dec_and_del(last))
 			put = NULL;
 	} else
-		next = i->i_head->next;
+		next = to_klist_node(i->i_klist->k_list.next);
 
-	if (next != i->i_head) {
-		knode = to_klist_node(next);
-		kref_get(&knode->n_ref);
+	i->i_cur = NULL;
+	while (next != to_klist_node(&i->i_klist->k_list)) {
+		if (likely(!knode_dead(next))) {
+			kref_get(&next->n_ref);
+			i->i_cur = next;
+			break;
+		}
+		next = to_klist_node(next->n_node.next);
 	}
-	i->i_cur = knode;
+
 	spin_unlock(&i->i_klist->k_lock);
-	if (put && lnode)
-		put(lnode);
-	return knode;
+
+	if (put && last)
+		put(last);
+	return i->i_cur;
 }
 EXPORT_SYMBOL_GPL(klist_next);
diff --git a/lib/parser.c b/lib/parser.c
index 4f0cbc0..b00d020 100644
--- a/lib/parser.c
+++ b/lib/parser.c
@@ -100,7 +100,7 @@
  * format identifiers which will be taken into account when matching the
  * tokens, and whose locations will be returned in the @args array.
  */
-int match_token(char *s, match_table_t table, substring_t args[])
+int match_token(char *s, const match_table_t table, substring_t args[])
 {
 	const struct match_token *p;
 
diff --git a/lib/percpu_counter.c b/lib/percpu_counter.c
index 4a8ba4b..a866389 100644
--- a/lib/percpu_counter.c
+++ b/lib/percpu_counter.c
@@ -52,7 +52,7 @@
  * Add up all the per-cpu counts, return the result.  This is a more accurate
  * but much slower version of percpu_counter_read_positive()
  */
-s64 __percpu_counter_sum(struct percpu_counter *fbc, int set)
+s64 __percpu_counter_sum(struct percpu_counter *fbc)
 {
 	s64 ret;
 	int cpu;
@@ -62,11 +62,9 @@
 	for_each_online_cpu(cpu) {
 		s32 *pcount = per_cpu_ptr(fbc->counters, cpu);
 		ret += *pcount;
-		if (set)
-			*pcount = 0;
+		*pcount = 0;
 	}
-	if (set)
-		fbc->count = ret;
+	fbc->count = ret;
 
 	spin_unlock(&fbc->lock);
 	return ret;
diff --git a/lib/string_helpers.c b/lib/string_helpers.c
new file mode 100644
index 0000000..8347925
--- /dev/null
+++ b/lib/string_helpers.c
@@ -0,0 +1,64 @@
+/*
+ * Helpers for formatting and printing strings
+ *
+ * Copyright 31 August 2008 James Bottomley
+ */
+#include <linux/kernel.h>
+#include <linux/math64.h>
+#include <linux/module.h>
+#include <linux/string_helpers.h>
+
+/**
+ * string_get_size - get the size in the specified units
+ * @size:	The size to be converted
+ * @units:	units to use (powers of 1000 or 1024)
+ * @buf:	buffer to format to
+ * @len:	length of buffer
+ *
+ * This function returns a string formatted to 3 significant figures
+ * giving the size in the required units.  Returns 0 on success or
+ * error on failure.  @buf is always zero terminated.
+ *
+ */
+int string_get_size(u64 size, const enum string_size_units units,
+		    char *buf, int len)
+{
+	const char *units_10[] = { "B", "KB", "MB", "GB", "TB", "PB",
+				   "EB", "ZB", "YB", NULL};
+	const char *units_2[] = {"B", "KiB", "MiB", "GiB", "TiB", "PiB",
+				 "EiB", "ZiB", "YiB", NULL };
+	const char **units_str[] = {
+		[STRING_UNITS_10] =  units_10,
+		[STRING_UNITS_2] = units_2,
+	};
+	const int divisor[] = {
+		[STRING_UNITS_10] = 1000,
+		[STRING_UNITS_2] = 1024,
+	};
+	int i, j;
+	u64 remainder = 0, sf_cap;
+	char tmp[8];
+
+	tmp[0] = '\0';
+
+	for (i = 0; size > divisor[units] && units_str[units][i]; i++)
+		remainder = do_div(size, divisor[units]);
+
+	sf_cap = size;
+	for (j = 0; sf_cap*10 < 1000; j++)
+		sf_cap *= 10;
+
+	if (j) {
+		remainder *= 1000;
+		do_div(remainder, divisor[units]);
+		snprintf(tmp, sizeof(tmp), ".%03lld",
+			 (unsigned long long)remainder);
+		tmp[j+1] = '\0';
+	}
+
+	snprintf(buf, len, "%lld%s%s", (unsigned long long)size,
+		 tmp, units_str[units][i]);
+
+	return 0;
+}
+EXPORT_SYMBOL(string_get_size);
diff --git a/lib/swiotlb.c b/lib/swiotlb.c
index 8826fdf..f8eebd48 100644
--- a/lib/swiotlb.c
+++ b/lib/swiotlb.c
@@ -274,13 +274,14 @@
 }
 
 static int
-address_needs_mapping(struct device *hwdev, dma_addr_t addr)
+address_needs_mapping(struct device *hwdev, dma_addr_t addr, size_t size)
 {
-	dma_addr_t mask = 0xffffffff;
-	/* If the device has a mask, use it, otherwise default to 32 bits */
-	if (hwdev && hwdev->dma_mask)
-		mask = *hwdev->dma_mask;
-	return (addr & ~mask) != 0;
+	return !is_buffer_dma_capable(dma_get_mask(hwdev), addr, size);
+}
+
+static int is_swiotlb_buffer(char *addr)
+{
+	return addr >= io_tlb_start && addr < io_tlb_end;
 }
 
 /*
@@ -467,15 +468,8 @@
 	void *ret;
 	int order = get_order(size);
 
-	/*
-	 * XXX fix me: the DMA API should pass us an explicit DMA mask
-	 * instead, or use ZONE_DMA32 (ia64 overloads ZONE_DMA to be a ~32
-	 * bit range instead of a 16MB one).
-	 */
-	flags |= GFP_DMA;
-
 	ret = (void *)__get_free_pages(flags, order);
-	if (ret && address_needs_mapping(hwdev, virt_to_bus(ret))) {
+	if (ret && address_needs_mapping(hwdev, virt_to_bus(ret), size)) {
 		/*
 		 * The allocated memory isn't reachable by the device.
 		 * Fall back on swiotlb_map_single().
@@ -490,19 +484,16 @@
 		 * swiotlb_map_single(), which will grab memory from
 		 * the lowest available address range.
 		 */
-		dma_addr_t handle;
-		handle = swiotlb_map_single(hwdev, NULL, size, DMA_FROM_DEVICE);
-		if (swiotlb_dma_mapping_error(hwdev, handle))
+		ret = map_single(hwdev, NULL, size, DMA_FROM_DEVICE);
+		if (!ret)
 			return NULL;
-
-		ret = bus_to_virt(handle);
 	}
 
 	memset(ret, 0, size);
 	dev_addr = virt_to_bus(ret);
 
 	/* Confirm address can be DMA'd by device */
-	if (address_needs_mapping(hwdev, dev_addr)) {
+	if (address_needs_mapping(hwdev, dev_addr, size)) {
 		printk("hwdev DMA mask = 0x%016Lx, dev_addr = 0x%016Lx\n",
 		       (unsigned long long)*hwdev->dma_mask,
 		       (unsigned long long)dev_addr);
@@ -518,12 +509,11 @@
 		      dma_addr_t dma_handle)
 {
 	WARN_ON(irqs_disabled());
-	if (!(vaddr >= (void *)io_tlb_start
-                    && vaddr < (void *)io_tlb_end))
+	if (!is_swiotlb_buffer(vaddr))
 		free_pages((unsigned long) vaddr, get_order(size));
 	else
 		/* DMA_TO_DEVICE to avoid memcpy in unmap_single */
-		swiotlb_unmap_single (hwdev, dma_handle, size, DMA_TO_DEVICE);
+		unmap_single(hwdev, vaddr, size, DMA_TO_DEVICE);
 }
 
 static void
@@ -567,7 +557,7 @@
 	 * we can safely return the device addr and not worry about bounce
 	 * buffering it.
 	 */
-	if (!address_needs_mapping(hwdev, dev_addr) && !swiotlb_force)
+	if (!address_needs_mapping(hwdev, dev_addr, size) && !swiotlb_force)
 		return dev_addr;
 
 	/*
@@ -584,7 +574,7 @@
 	/*
 	 * Ensure that the address returned is DMA'ble
 	 */
-	if (address_needs_mapping(hwdev, dev_addr))
+	if (address_needs_mapping(hwdev, dev_addr, size))
 		panic("map_single: bounce buffer is not DMA'ble");
 
 	return dev_addr;
@@ -612,7 +602,7 @@
 	char *dma_addr = bus_to_virt(dev_addr);
 
 	BUG_ON(dir == DMA_NONE);
-	if (dma_addr >= io_tlb_start && dma_addr < io_tlb_end)
+	if (is_swiotlb_buffer(dma_addr))
 		unmap_single(hwdev, dma_addr, size, dir);
 	else if (dir == DMA_FROM_DEVICE)
 		dma_mark_clean(dma_addr, size);
@@ -642,7 +632,7 @@
 	char *dma_addr = bus_to_virt(dev_addr);
 
 	BUG_ON(dir == DMA_NONE);
-	if (dma_addr >= io_tlb_start && dma_addr < io_tlb_end)
+	if (is_swiotlb_buffer(dma_addr))
 		sync_single(hwdev, dma_addr, size, dir, target);
 	else if (dir == DMA_FROM_DEVICE)
 		dma_mark_clean(dma_addr, size);
@@ -673,7 +663,7 @@
 	char *dma_addr = bus_to_virt(dev_addr) + offset;
 
 	BUG_ON(dir == DMA_NONE);
-	if (dma_addr >= io_tlb_start && dma_addr < io_tlb_end)
+	if (is_swiotlb_buffer(dma_addr))
 		sync_single(hwdev, dma_addr, size, dir, target);
 	else if (dir == DMA_FROM_DEVICE)
 		dma_mark_clean(dma_addr, size);
@@ -727,7 +717,8 @@
 	for_each_sg(sgl, sg, nelems, i) {
 		addr = SG_ENT_VIRT_ADDRESS(sg);
 		dev_addr = virt_to_bus(addr);
-		if (swiotlb_force || address_needs_mapping(hwdev, dev_addr)) {
+		if (swiotlb_force ||
+		    address_needs_mapping(hwdev, dev_addr, sg->length)) {
 			void *map = map_single(hwdev, addr, sg->length, dir);
 			if (!map) {
 				/* Don't panic here, we expect map_sg users
diff --git a/mm/Kconfig b/mm/Kconfig
index 0bd9c2d..91ee392 100644
--- a/mm/Kconfig
+++ b/mm/Kconfig
@@ -187,6 +187,9 @@
 	help
 	  This option allows memory and IO resources to be 64 bit.
 
+config PHYS_ADDR_T_64BIT
+	def_bool 64BIT || ARCH_PHYS_ADDR_T_64BIT
+
 config ZONE_DMA_FLAG
 	int
 	default "0" if !ZONE_DMA
diff --git a/mm/bounce.c b/mm/bounce.c
index b6d2d0f..06722c4 100644
--- a/mm/bounce.c
+++ b/mm/bounce.c
@@ -267,7 +267,7 @@
 	/*
 	 * Data-less bio, nothing to bounce
 	 */
-	if (bio_empty_barrier(*bio_orig))
+	if (!bio_has_data(*bio_orig))
 		return;
 
 	/*
diff --git a/mm/filemap.c b/mm/filemap.c
index 876bc59..494ff20 100644
--- a/mm/filemap.c
+++ b/mm/filemap.c
@@ -1100,8 +1100,9 @@
 
 page_not_up_to_date:
 		/* Get exclusive access to the page ... */
-		if (lock_page_killable(page))
-			goto readpage_eio;
+		error = lock_page_killable(page);
+		if (unlikely(error))
+			goto readpage_error;
 
 page_not_up_to_date_locked:
 		/* Did it get truncated before we got the lock? */
@@ -1130,8 +1131,9 @@
 		}
 
 		if (!PageUptodate(page)) {
-			if (lock_page_killable(page))
-				goto readpage_eio;
+			error = lock_page_killable(page);
+			if (unlikely(error))
+				goto readpage_error;
 			if (!PageUptodate(page)) {
 				if (page->mapping == NULL) {
 					/*
@@ -1143,15 +1145,14 @@
 				}
 				unlock_page(page);
 				shrink_readahead_size_eio(filp, ra);
-				goto readpage_eio;
+				error = -EIO;
+				goto readpage_error;
 			}
 			unlock_page(page);
 		}
 
 		goto page_ok;
 
-readpage_eio:
-		error = -EIO;
 readpage_error:
 		/* UHHUH! A synchronous read error occurred. Report it */
 		desc->error = error;
diff --git a/mm/highmem.c b/mm/highmem.c
index e16e152..b36b83b 100644
--- a/mm/highmem.c
+++ b/mm/highmem.c
@@ -70,6 +70,7 @@
 static void flush_all_zero_pkmaps(void)
 {
 	int i;
+	int need_flush = 0;
 
 	flush_cache_kmaps();
 
@@ -101,8 +102,10 @@
 			  &pkmap_page_table[i]);
 
 		set_page_address(page, NULL);
+		need_flush = 1;
 	}
-	flush_tlb_kernel_range(PKMAP_ADDR(0), PKMAP_ADDR(LAST_PKMAP));
+	if (need_flush)
+		flush_tlb_kernel_range(PKMAP_ADDR(0), PKMAP_ADDR(LAST_PKMAP));
 }
 
 /**
diff --git a/mm/memcontrol.c b/mm/memcontrol.c
index 0f1f7a7..36896f3 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -250,6 +250,14 @@
 
 struct mem_cgroup *mem_cgroup_from_task(struct task_struct *p)
 {
+	/*
+	 * mm_update_next_owner() may clear mm->owner to NULL
+	 * if it races with swapoff, page migration, etc.
+	 * So this can be called with p == NULL.
+	 */
+	if (unlikely(!p))
+		return NULL;
+
 	return container_of(task_subsys_state(p, mem_cgroup_subsys_id),
 				struct mem_cgroup, css);
 }
@@ -549,6 +557,11 @@
 	if (likely(!memcg)) {
 		rcu_read_lock();
 		mem = mem_cgroup_from_task(rcu_dereference(mm->owner));
+		if (unlikely(!mem)) {
+			rcu_read_unlock();
+			kmem_cache_free(page_cgroup_cache, pc);
+			return 0;
+		}
 		/*
 		 * For every charge from the cgroup, increment reference count
 		 */
@@ -801,11 +814,16 @@
 
 	rcu_read_lock();
 	mem = mem_cgroup_from_task(rcu_dereference(mm->owner));
+	if (unlikely(!mem)) {
+		rcu_read_unlock();
+		return 0;
+	}
 	css_get(&mem->css);
 	rcu_read_unlock();
 
 	do {
 		progress = try_to_free_mem_cgroup_pages(mem, gfp_mask);
+		progress += res_counter_check_under_limit(&mem->res);
 	} while (!progress && --retry);
 
 	css_put(&mem->css);
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index e293c58..27b8681 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -268,13 +268,14 @@
 {
 	int i;
 	int nr_pages = 1 << order;
+	struct page *p = page + 1;
 
 	set_compound_page_dtor(page, free_compound_page);
 	set_compound_order(page, order);
 	__SetPageHead(page);
-	for (i = 1; i < nr_pages; i++) {
-		struct page *p = page + i;
-
+	for (i = 1; i < nr_pages; i++, p++) {
+		if (unlikely((i & (MAX_ORDER_NR_PAGES - 1)) == 0))
+			p = pfn_to_page(page_to_pfn(page) + i);
 		__SetPageTail(p);
 		p->first_page = page;
 	}
@@ -284,6 +285,7 @@
 {
 	int i;
 	int nr_pages = 1 << order;
+	struct page *p = page + 1;
 
 	if (unlikely(compound_order(page) != order))
 		bad_page(page);
@@ -291,8 +293,9 @@
 	if (unlikely(!PageHead(page)))
 			bad_page(page);
 	__ClearPageHead(page);
-	for (i = 1; i < nr_pages; i++) {
-		struct page *p = page + i;
+	for (i = 1; i < nr_pages; i++, p++) {
+		if (unlikely((i & (MAX_ORDER_NR_PAGES - 1)) == 0))
+			p = pfn_to_page(page_to_pfn(page) + i);
 
 		if (unlikely(!PageTail(p) |
 				(p->first_page != page)))
diff --git a/mm/page_isolation.c b/mm/page_isolation.c
index c69f84f..b70a7fe 100644
--- a/mm/page_isolation.c
+++ b/mm/page_isolation.c
@@ -114,8 +114,10 @@
 
 int test_pages_isolated(unsigned long start_pfn, unsigned long end_pfn)
 {
-	unsigned long pfn;
+	unsigned long pfn, flags;
 	struct page *page;
+	struct zone *zone;
+	int ret;
 
 	pfn = start_pfn;
 	/*
@@ -131,7 +133,9 @@
 	if (pfn < end_pfn)
 		return -EBUSY;
 	/* Check all pages are free or Marked as ISOLATED */
-	if (__test_page_isolated_in_pageblock(start_pfn, end_pfn))
-		return 0;
-	return -EBUSY;
+	zone = page_zone(pfn_to_page(pfn));
+	spin_lock_irqsave(&zone->lock, flags);
+	ret = __test_page_isolated_in_pageblock(start_pfn, end_pfn);
+	spin_unlock_irqrestore(&zone->lock, flags);
+	return ret ? 0 : -EBUSY;
 }
diff --git a/mm/shmem.c b/mm/shmem.c
index 04fb4f1..bf66d01 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -50,14 +50,12 @@
 #include <linux/migrate.h>
 #include <linux/highmem.h>
 #include <linux/seq_file.h>
+#include <linux/magic.h>
 
 #include <asm/uaccess.h>
 #include <asm/div64.h>
 #include <asm/pgtable.h>
 
-/* This magic number is used in glibc for posix shared memory */
-#define TMPFS_MAGIC	0x01021994
-
 #define ENTRIES_PER_PAGE (PAGE_CACHE_SIZE/sizeof(unsigned long))
 #define ENTRIES_PER_PAGEPAGE (ENTRIES_PER_PAGE*ENTRIES_PER_PAGE)
 #define BLOCKS_PER_PAGE  (PAGE_CACHE_SIZE/512)
diff --git a/mm/slob.c b/mm/slob.c
index 4c82dd4..cb675d1 100644
--- a/mm/slob.c
+++ b/mm/slob.c
@@ -514,9 +514,11 @@
 		return 0;
 
 	sp = (struct slob_page *)virt_to_page(block);
-	if (slob_page(sp))
-		return ((slob_t *)block - 1)->units + SLOB_UNIT;
-	else
+	if (slob_page(sp)) {
+		int align = max(ARCH_KMALLOC_MINALIGN, ARCH_SLAB_MINALIGN);
+		unsigned int *m = (unsigned int *)(block - align);
+		return SLOB_UNITS(*m) * SLOB_UNIT;
+	} else
 		return sp->page.private;
 }
 
diff --git a/mm/slub.c b/mm/slub.c
index fb486d5..0c83e6a 100644
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -1932,6 +1932,7 @@
 	INIT_LIST_HEAD(&n->partial);
 #ifdef CONFIG_SLUB_DEBUG
 	atomic_long_set(&n->nr_slabs, 0);
+	atomic_long_set(&n->total_objects, 0);
 	INIT_LIST_HEAD(&n->full);
 #endif
 }
diff --git a/mm/tiny-shmem.c b/mm/tiny-shmem.c
index ae532f5..8d7a27a 100644
--- a/mm/tiny-shmem.c
+++ b/mm/tiny-shmem.c
@@ -65,31 +65,31 @@
 	if (!dentry)
 		goto put_memory;
 
-	error = -ENOSPC;
-	inode = ramfs_get_inode(root->d_sb, S_IFREG | S_IRWXUGO, 0);
-	if (!inode)
-		goto put_dentry;
-
-	d_instantiate(dentry, inode);
 	error = -ENFILE;
-	file = alloc_file(shm_mnt, dentry, FMODE_WRITE | FMODE_READ,
-			&ramfs_file_operations);
+	file = get_empty_filp();
 	if (!file)
 		goto put_dentry;
 
-	inode->i_nlink = 0;	/* It is unlinked */
-
-	/* notify everyone as to the change of file size */
-	error = do_truncate(dentry, size, 0, file);
-	if (error < 0)
+	error = -ENOSPC;
+	inode = ramfs_get_inode(root->d_sb, S_IFREG | S_IRWXUGO, 0);
+	if (!inode)
 		goto close_file;
 
+	d_instantiate(dentry, inode);
+	inode->i_size = size;
+	inode->i_nlink = 0;	/* It is unlinked */
+	init_file(file, shm_mnt, dentry, FMODE_WRITE | FMODE_READ,
+			&ramfs_file_operations);
+
+#ifndef CONFIG_MMU
+	error = ramfs_nommu_expand_for_mapping(inode, size);
+	if (error)
+		goto close_file;
+#endif
 	return file;
 
 close_file:
 	put_filp(file);
-	return ERR_PTR(error);
-
 put_dentry:
 	dput(dentry);
 put_memory:
diff --git a/mm/vmalloc.c b/mm/vmalloc.c
index 85b9a0d..bba06c4 100644
--- a/mm/vmalloc.c
+++ b/mm/vmalloc.c
@@ -180,6 +180,13 @@
 	pmd_t *pmd;
 	pte_t *ptep, pte;
 
+	/*
+	 * XXX we might need to change this if we add VIRTUAL_BUG_ON for
+	 * architectures that do not vmalloc module space
+	 */
+	VIRTUAL_BUG_ON(!is_vmalloc_addr(vmalloc_addr) &&
+			!is_module_address(addr));
+
 	if (!pgd_none(*pgd)) {
 		pud = pud_offset(pgd, addr);
 		if (!pud_none(*pud)) {
diff --git a/net/802/psnap.c b/net/802/psnap.c
index b3cfe5a..70980ba 100644
--- a/net/802/psnap.c
+++ b/net/802/psnap.c
@@ -1,7 +1,7 @@
 /*
  *	SNAP data link layer. Derived from 802.2
  *
- *		Alan Cox <Alan.Cox@linux.org>,
+ *		Alan Cox <alan@lxorguk.ukuu.org.uk>,
  *		from the 802.2 layer by Greg Page.
  *		Merged in additions from Greg Page's psnap.c.
  *
diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c
index b661f47..f0e335a 100644
--- a/net/8021q/vlan.c
+++ b/net/8021q/vlan.c
@@ -394,6 +394,7 @@
 
 	vlandev->features &= ~dev->vlan_features;
 	vlandev->features |= dev->features & dev->vlan_features;
+	vlandev->gso_max_size = dev->gso_max_size;
 
 	if (old_features != vlandev->features)
 		netdev_features_change(vlandev);
diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c
index 4bf014e..8883e9c 100644
--- a/net/8021q/vlan_dev.c
+++ b/net/8021q/vlan_dev.c
@@ -48,7 +48,7 @@
 
 	switch (veth->h_vlan_encapsulated_proto) {
 #ifdef CONFIG_INET
-	case __constant_htons(ETH_P_IP):
+	case htons(ETH_P_IP):
 
 		/* TODO:  Confirm this will work with VLAN headers... */
 		return arp_find(veth->h_dest, skb);
@@ -607,6 +607,7 @@
 		      (1<<__LINK_STATE_PRESENT);
 
 	dev->features |= real_dev->features & real_dev->vlan_features;
+	dev->gso_max_size = real_dev->gso_max_size;
 
 	/* ipv6 shared card related stuff */
 	dev->dev_id = real_dev->dev_id;
diff --git a/net/9p/client.c b/net/9p/client.c
index 2ffe40c..e053e06 100644
--- a/net/9p/client.c
+++ b/net/9p/client.c
@@ -52,7 +52,7 @@
 	Opt_err,
 };
 
-static match_table_t tokens = {
+static const match_table_t tokens = {
 	{Opt_msize, "msize=%u"},
 	{Opt_legacy, "noextend"},
 	{Opt_trans, "trans=%s"},
@@ -75,7 +75,6 @@
 	int option;
 	int ret = 0;
 
-	clnt->trans_mod = v9fs_default_trans();
 	clnt->dotu = 1;
 	clnt->msize = 8192;
 
@@ -108,7 +107,7 @@
 			clnt->msize = option;
 			break;
 		case Opt_trans:
-			clnt->trans_mod = v9fs_match_trans(&args[0]);
+			clnt->trans_mod = v9fs_get_trans_by_name(&args[0]);
 			break;
 		case Opt_legacy:
 			clnt->dotu = 0;
@@ -117,6 +116,10 @@
 			continue;
 		}
 	}
+
+	if (!clnt->trans_mod)
+		clnt->trans_mod = v9fs_get_default_trans();
+
 	kfree(options);
 	return ret;
 }
@@ -150,6 +153,7 @@
 	if (!clnt)
 		return ERR_PTR(-ENOMEM);
 
+	clnt->trans_mod = NULL;
 	clnt->trans = NULL;
 	spin_lock_init(&clnt->lock);
 	INIT_LIST_HEAD(&clnt->fidlist);
@@ -235,6 +239,8 @@
 		clnt->trans = NULL;
 	}
 
+	v9fs_put_trans(clnt->trans_mod);
+
 	list_for_each_entry_safe(fid, fidptr, &clnt->fidlist, flist)
 		p9_fid_destroy(fid);
 
diff --git a/net/9p/conv.c b/net/9p/conv.c
index 4454720..5ad3a3b 100644
--- a/net/9p/conv.c
+++ b/net/9p/conv.c
@@ -451,8 +451,10 @@
 		   unsigned char **pdata)
 {
 	*pdata = buf_alloc(bufp, count);
+	if (*pdata == NULL)
+		return -ENOMEM;
 	memmove(*pdata, data, count);
-	return count;
+	return 0;
 }
 
 static int
@@ -460,6 +462,8 @@
 		   unsigned char **pdata)
 {
 	*pdata = buf_alloc(bufp, count);
+	if (*pdata == NULL)
+		return -ENOMEM;
 	return copy_from_user(*pdata, data, count);
 }
 
diff --git a/net/9p/mod.c b/net/9p/mod.c
index bdee1fb..1084feb 100644
--- a/net/9p/mod.c
+++ b/net/9p/mod.c
@@ -31,6 +31,7 @@
 #include <linux/parser.h>
 #include <net/9p/transport.h>
 #include <linux/list.h>
+#include <linux/spinlock.h>
 
 #ifdef CONFIG_NET_9P_DEBUG
 unsigned int p9_debug_level = 0;	/* feature-rific global debug level  */
@@ -44,8 +45,8 @@
  *
  */
 
+static DEFINE_SPINLOCK(v9fs_trans_lock);
 static LIST_HEAD(v9fs_trans_list);
-static struct p9_trans_module *v9fs_default_transport;
 
 /**
  * v9fs_register_trans - register a new transport with 9p
@@ -54,48 +55,87 @@
  */
 void v9fs_register_trans(struct p9_trans_module *m)
 {
+	spin_lock(&v9fs_trans_lock);
 	list_add_tail(&m->list, &v9fs_trans_list);
-	if (m->def)
-		v9fs_default_transport = m;
+	spin_unlock(&v9fs_trans_lock);
 }
 EXPORT_SYMBOL(v9fs_register_trans);
 
 /**
- * v9fs_match_trans - match transport versus registered transports
+ * v9fs_unregister_trans - unregister a 9p transport
+ * @m: the transport to remove
+ *
+ */
+void v9fs_unregister_trans(struct p9_trans_module *m)
+{
+	spin_lock(&v9fs_trans_lock);
+	list_del_init(&m->list);
+	spin_unlock(&v9fs_trans_lock);
+}
+EXPORT_SYMBOL(v9fs_unregister_trans);
+
+/**
+ * v9fs_get_trans_by_name - get transport with the matching name
  * @name: string identifying transport
  *
  */
-struct p9_trans_module *v9fs_match_trans(const substring_t *name)
+struct p9_trans_module *v9fs_get_trans_by_name(const substring_t *name)
 {
-	struct list_head *p;
-	struct p9_trans_module *t = NULL;
+	struct p9_trans_module *t, *found = NULL;
 
-	list_for_each(p, &v9fs_trans_list) {
-		t = list_entry(p, struct p9_trans_module, list);
-		if (strncmp(t->name, name->from, name->to-name->from) == 0)
-			return t;
-	}
-	return NULL;
+	spin_lock(&v9fs_trans_lock);
+
+	list_for_each_entry(t, &v9fs_trans_list, list)
+		if (strncmp(t->name, name->from, name->to-name->from) == 0 &&
+		    try_module_get(t->owner)) {
+			found = t;
+			break;
+		}
+
+	spin_unlock(&v9fs_trans_lock);
+	return found;
 }
-EXPORT_SYMBOL(v9fs_match_trans);
+EXPORT_SYMBOL(v9fs_get_trans_by_name);
 
 /**
- * v9fs_default_trans - returns pointer to default transport
+ * v9fs_get_default_trans - get the default transport
  *
  */
 
-struct p9_trans_module *v9fs_default_trans(void)
+struct p9_trans_module *v9fs_get_default_trans(void)
 {
-	if (v9fs_default_transport)
-		return v9fs_default_transport;
-	else if (!list_empty(&v9fs_trans_list))
-		return list_first_entry(&v9fs_trans_list,
-					struct p9_trans_module, list);
-	else
-		return NULL;
-}
-EXPORT_SYMBOL(v9fs_default_trans);
+	struct p9_trans_module *t, *found = NULL;
 
+	spin_lock(&v9fs_trans_lock);
+
+	list_for_each_entry(t, &v9fs_trans_list, list)
+		if (t->def && try_module_get(t->owner)) {
+			found = t;
+			break;
+		}
+
+	if (!found)
+		list_for_each_entry(t, &v9fs_trans_list, list)
+			if (try_module_get(t->owner)) {
+				found = t;
+				break;
+			}
+
+	spin_unlock(&v9fs_trans_lock);
+	return found;
+}
+EXPORT_SYMBOL(v9fs_get_default_trans);
+
+/**
+ * v9fs_put_trans - put trans
+ * @m: transport to put
+ *
+ */
+void v9fs_put_trans(struct p9_trans_module *m)
+{
+	if (m)
+		module_put(m->owner);
+}
 
 /**
  * v9fs_init - Initialize module
@@ -120,6 +160,8 @@
 static void __exit exit_p9(void)
 {
 	printk(KERN_INFO "Unloading 9P2000 support\n");
+
+	p9_trans_fd_exit();
 }
 
 module_init(init_p9)
diff --git a/net/9p/trans_fd.c b/net/9p/trans_fd.c
index cdf137a..6dabbdb 100644
--- a/net/9p/trans_fd.c
+++ b/net/9p/trans_fd.c
@@ -86,7 +86,7 @@
 	Opt_port, Opt_rfdno, Opt_wfdno, Opt_err,
 };
 
-static match_table_t tokens = {
+static const match_table_t tokens = {
 	{Opt_port, "port=%u"},
 	{Opt_rfdno, "rfdno=%u"},
 	{Opt_wfdno, "wfdno=%u"},
@@ -151,7 +151,6 @@
  * @trans: reference to transport instance for this connection
  * @tagpool: id accounting for transactions
  * @err: error state
- * @equeue: event wait_q (?)
  * @req_list: accounting for requests which have been sent
  * @unsent_req_list: accounting for requests that haven't been sent
  * @rcall: current response &p9_fcall structure
@@ -178,7 +177,6 @@
 	struct p9_trans *trans;
 	struct p9_idpool *tagpool;
 	int err;
-	wait_queue_head_t equeue;
 	struct list_head req_list;
 	struct list_head unsent_req_list;
 	struct p9_fcall *rcall;
@@ -240,22 +238,6 @@
 
 static void p9_conn_cancel(struct p9_conn *m, int err);
 
-static int p9_mux_global_init(void)
-{
-	int i;
-
-	for (i = 0; i < ARRAY_SIZE(p9_mux_poll_tasks); i++)
-		p9_mux_poll_tasks[i].task = NULL;
-
-	p9_mux_wq = create_workqueue("v9fs");
-	if (!p9_mux_wq) {
-		printk(KERN_WARNING "v9fs: mux: creating workqueue failed\n");
-		return -ENOMEM;
-	}
-
-	return 0;
-}
-
 static u16 p9_mux_get_tag(struct p9_conn *m)
 {
 	int tag;
@@ -409,11 +391,11 @@
 static struct p9_conn *p9_conn_create(struct p9_trans *trans)
 {
 	int i, n;
-	struct p9_conn *m, *mtmp;
+	struct p9_conn *m;
 
 	P9_DPRINTK(P9_DEBUG_MUX, "transport %p msize %d\n", trans,
 								trans->msize);
-	m = kmalloc(sizeof(struct p9_conn), GFP_KERNEL);
+	m = kzalloc(sizeof(struct p9_conn), GFP_KERNEL);
 	if (!m)
 		return ERR_PTR(-ENOMEM);
 
@@ -424,25 +406,14 @@
 	m->trans = trans;
 	m->tagpool = p9_idpool_create();
 	if (IS_ERR(m->tagpool)) {
-		mtmp = ERR_PTR(-ENOMEM);
 		kfree(m);
-		return mtmp;
+		return ERR_PTR(-ENOMEM);
 	}
 
-	m->err = 0;
-	init_waitqueue_head(&m->equeue);
 	INIT_LIST_HEAD(&m->req_list);
 	INIT_LIST_HEAD(&m->unsent_req_list);
-	m->rcall = NULL;
-	m->rpos = 0;
-	m->rbuf = NULL;
-	m->wpos = m->wsize = 0;
-	m->wbuf = NULL;
 	INIT_WORK(&m->rq, p9_read_work);
 	INIT_WORK(&m->wq, p9_write_work);
-	m->wsched = 0;
-	memset(&m->poll_waddr, 0, sizeof(m->poll_waddr));
-	m->poll_task = NULL;
 	n = p9_mux_poll_start(m);
 	if (n) {
 		kfree(m);
@@ -463,10 +434,8 @@
 	for (i = 0; i < ARRAY_SIZE(m->poll_waddr); i++) {
 		if (IS_ERR(m->poll_waddr[i])) {
 			p9_mux_poll_stop(m);
-			mtmp = (void *)m->poll_waddr;	/* the error code */
 			kfree(m);
-			m = mtmp;
-			break;
+			return (void *)m->poll_waddr;	/* the error code */
 		}
 	}
 
@@ -483,18 +452,13 @@
 {
 	P9_DPRINTK(P9_DEBUG_MUX, "mux %p prev %p next %p\n", m,
 		m->mux_list.prev, m->mux_list.next);
-	p9_conn_cancel(m, -ECONNRESET);
-
-	if (!list_empty(&m->req_list)) {
-		/* wait until all processes waiting on this session exit */
-		P9_DPRINTK(P9_DEBUG_MUX,
-			"mux %p waiting for empty request queue\n", m);
-		wait_event_timeout(m->equeue, (list_empty(&m->req_list)), 5000);
-		P9_DPRINTK(P9_DEBUG_MUX, "mux %p request queue empty: %d\n", m,
-			list_empty(&m->req_list));
-	}
 
 	p9_mux_poll_stop(m);
+	cancel_work_sync(&m->rq);
+	cancel_work_sync(&m->wq);
+
+	p9_conn_cancel(m, -ECONNRESET);
+
 	m->trans = NULL;
 	p9_idpool_destroy(m->tagpool);
 	kfree(m);
@@ -840,8 +804,6 @@
 					(*req->cb) (req, req->cba);
 				else
 					kfree(req->rcall);
-
-				wake_up(&m->equeue);
 			}
 		} else {
 			if (err >= 0 && rcall->id != P9_RFLUSH)
@@ -908,8 +870,10 @@
 	else
 		n = p9_mux_get_tag(m);
 
-	if (n < 0)
+	if (n < 0) {
+		kfree(req);
 		return ERR_PTR(-ENOMEM);
+	}
 
 	p9_set_tag(tc, n);
 
@@ -984,8 +948,6 @@
 			(*req->cb) (req, req->cba);
 		else
 			kfree(req->rcall);
-
-		wake_up(&m->equeue);
 	}
 
 	kfree(freq->tcall);
@@ -1191,8 +1153,6 @@
 		else
 			kfree(req->rcall);
 	}
-
-	wake_up(&m->equeue);
 }
 
 /**
@@ -1370,7 +1330,6 @@
 {
 	int ret, n;
 	struct p9_trans_fd *ts = NULL;
-	mm_segment_t oldfs;
 
 	if (trans && trans->status == Connected)
 		ts = trans->priv;
@@ -1384,24 +1343,17 @@
 	if (!ts->wr->f_op || !ts->wr->f_op->poll)
 		return -EIO;
 
-	oldfs = get_fs();
-	set_fs(get_ds());
-
 	ret = ts->rd->f_op->poll(ts->rd, pt);
 	if (ret < 0)
-		goto end;
+		return ret;
 
 	if (ts->rd != ts->wr) {
 		n = ts->wr->f_op->poll(ts->wr, pt);
-		if (n < 0) {
-			ret = n;
-			goto end;
-		}
+		if (n < 0)
+			return n;
 		ret = (ret & ~POLLOUT) | (n & ~POLLIN);
 	}
 
-end:
-	set_fs(oldfs);
 	return ret;
 }
 
@@ -1629,6 +1581,7 @@
 	.maxsize = MAX_SOCK_BUF,
 	.def = 1,
 	.create = p9_trans_create_tcp,
+	.owner = THIS_MODULE,
 };
 
 static struct p9_trans_module p9_unix_trans = {
@@ -1636,6 +1589,7 @@
 	.maxsize = MAX_SOCK_BUF,
 	.def = 0,
 	.create = p9_trans_create_unix,
+	.owner = THIS_MODULE,
 };
 
 static struct p9_trans_module p9_fd_trans = {
@@ -1643,14 +1597,20 @@
 	.maxsize = MAX_SOCK_BUF,
 	.def = 0,
 	.create = p9_trans_create_fd,
+	.owner = THIS_MODULE,
 };
 
 int p9_trans_fd_init(void)
 {
-	int ret = p9_mux_global_init();
-	if (ret) {
-		printk(KERN_WARNING "9p: starting mux failed\n");
-		return ret;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(p9_mux_poll_tasks); i++)
+		p9_mux_poll_tasks[i].task = NULL;
+
+	p9_mux_wq = create_workqueue("v9fs");
+	if (!p9_mux_wq) {
+		printk(KERN_WARNING "v9fs: mux: creating workqueue failed\n");
+		return -ENOMEM;
 	}
 
 	v9fs_register_trans(&p9_tcp_trans);
@@ -1659,4 +1619,12 @@
 
 	return 0;
 }
-EXPORT_SYMBOL(p9_trans_fd_init);
+
+void p9_trans_fd_exit(void)
+{
+	v9fs_unregister_trans(&p9_tcp_trans);
+	v9fs_unregister_trans(&p9_unix_trans);
+	v9fs_unregister_trans(&p9_fd_trans);
+
+	destroy_workqueue(p9_mux_wq);
+}
diff --git a/net/9p/trans_virtio.c b/net/9p/trans_virtio.c
index 42adc05..94912e0 100644
--- a/net/9p/trans_virtio.c
+++ b/net/9p/trans_virtio.c
@@ -528,6 +528,7 @@
 	.create = p9_virtio_create,
 	.maxsize = PAGE_SIZE*16,
 	.def = 0,
+	.owner = THIS_MODULE,
 };
 
 /* The standard init function */
@@ -545,6 +546,7 @@
 static void __exit p9_virtio_cleanup(void)
 {
 	unregister_virtio_driver(&p9_virtio_drv);
+	v9fs_unregister_trans(&p9_virtio_trans);
 }
 
 module_init(p9_virtio_init);
diff --git a/net/Kconfig b/net/Kconfig
index 7612cc8..d789d79 100644
--- a/net/Kconfig
+++ b/net/Kconfig
@@ -180,6 +180,7 @@
 source "net/atm/Kconfig"
 source "net/802/Kconfig"
 source "net/bridge/Kconfig"
+source "net/dsa/Kconfig"
 source "net/8021q/Kconfig"
 source "net/decnet/Kconfig"
 source "net/llc/Kconfig"
@@ -232,18 +233,23 @@
 source "net/irda/Kconfig"
 source "net/bluetooth/Kconfig"
 source "net/rxrpc/Kconfig"
+source "net/phonet/Kconfig"
 
 config FIB_RULES
 	bool
 
-menu "Wireless"
+menuconfig WIRELESS
+	bool "Wireless"
 	depends on !S390
+	default y
+
+if WIRELESS
 
 source "net/wireless/Kconfig"
 source "net/mac80211/Kconfig"
 source "net/ieee80211/Kconfig"
 
-endmenu
+endif # WIRELESS
 
 source "net/rfkill/Kconfig"
 source "net/9p/Kconfig"
diff --git a/net/Makefile b/net/Makefile
index 4f43e7f..27d1f10 100644
--- a/net/Makefile
+++ b/net/Makefile
@@ -26,6 +26,7 @@
 obj-$(CONFIG_NET_KEY)		+= key/
 obj-$(CONFIG_NET_SCHED)		+= sched/
 obj-$(CONFIG_BRIDGE)		+= bridge/
+obj-$(CONFIG_NET_DSA)		+= dsa/
 obj-$(CONFIG_IPX)		+= ipx/
 obj-$(CONFIG_ATALK)		+= appletalk/
 obj-$(CONFIG_WAN_ROUTER)	+= wanrouter/
@@ -42,6 +43,7 @@
 obj-$(CONFIG_ATM)		+= atm/
 obj-$(CONFIG_DECNET)		+= decnet/
 obj-$(CONFIG_ECONET)		+= econet/
+obj-$(CONFIG_PHONET)		+= phonet/
 ifneq ($(CONFIG_VLAN_8021Q),)
 obj-y				+= 8021q/
 endif
diff --git a/net/appletalk/ddp.c b/net/appletalk/ddp.c
index 0c85042..d3134e7 100644
--- a/net/appletalk/ddp.c
+++ b/net/appletalk/ddp.c
@@ -2,7 +2,7 @@
  *	DDP:	An implementation of the AppleTalk DDP protocol for
  *		Ethernet 'ELAP'.
  *
- *		Alan Cox  <Alan.Cox@linux.org>
+ *		Alan Cox  <alan@lxorguk.ukuu.org.uk>
  *
  *		With more than a little assistance from
  *
@@ -1934,6 +1934,6 @@
 module_exit(atalk_exit);
 
 MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Alan Cox <Alan.Cox@linux.org>");
+MODULE_AUTHOR("Alan Cox <alan@lxorguk.ukuu.org.uk>");
 MODULE_DESCRIPTION("AppleTalk 0.20\n");
 MODULE_ALIAS_NETPROTO(PF_APPLETALK);
diff --git a/net/atm/br2684.c b/net/atm/br2684.c
index 8d9a6f1..280de48 100644
--- a/net/atm/br2684.c
+++ b/net/atm/br2684.c
@@ -375,11 +375,11 @@
 			if (memcmp
 			    (skb->data + 6, ethertype_ipv6,
 			     sizeof(ethertype_ipv6)) == 0)
-				skb->protocol = __constant_htons(ETH_P_IPV6);
+				skb->protocol = htons(ETH_P_IPV6);
 			else if (memcmp
 				 (skb->data + 6, ethertype_ipv4,
 				  sizeof(ethertype_ipv4)) == 0)
-				skb->protocol = __constant_htons(ETH_P_IP);
+				skb->protocol = htons(ETH_P_IP);
 			else
 				goto error;
 			skb_pull(skb, sizeof(llc_oui_ipv4));
@@ -404,9 +404,9 @@
 			skb_reset_network_header(skb);
 			iph = ip_hdr(skb);
 			if (iph->version == 4)
-				skb->protocol = __constant_htons(ETH_P_IP);
+				skb->protocol = htons(ETH_P_IP);
 			else if (iph->version == 6)
-				skb->protocol = __constant_htons(ETH_P_IPV6);
+				skb->protocol = htons(ETH_P_IPV6);
 			else
 				goto error;
 			skb->pkt_type = PACKET_HOST;
diff --git a/net/atm/lec.c b/net/atm/lec.c
index 5799fb5..8f701cd 100644
--- a/net/atm/lec.c
+++ b/net/atm/lec.c
@@ -1931,7 +1931,6 @@
 		switch (priv->lane_version) {
 		case 1:
 			return priv->mcast_vcc;
-			break;
 		case 2:	/* LANE2 wants arp for multicast addresses */
 			if (!compare_ether_addr(mac_to_find, bus_mac))
 				return priv->mcast_vcc;
diff --git a/net/ax25/af_ax25.c b/net/ax25/af_ax25.c
index 01c83e2..28c7157 100644
--- a/net/ax25/af_ax25.c
+++ b/net/ax25/af_ax25.c
@@ -317,6 +317,9 @@
 				/* Queue the unaccepted socket for death */
 				sock_orphan(skb->sk);
 
+				/* 9A4GL: hack to release unaccepted sockets */
+				skb->sk->sk_state = TCP_LISTEN;
+
 				ax25_start_heartbeat(sax25);
 				sax25->state = AX25_STATE_0;
 			}
diff --git a/net/ax25/ax25_std_timer.c b/net/ax25/ax25_std_timer.c
index cdc7e75..96e4b92 100644
--- a/net/ax25/ax25_std_timer.c
+++ b/net/ax25/ax25_std_timer.c
@@ -39,9 +39,11 @@
 
 	switch (ax25->state) {
 	case AX25_STATE_0:
-		if (!sk ||
-		    sock_flag(sk, SOCK_DESTROY) ||
-		    sock_flag(sk, SOCK_DEAD)) {
+		/* Magic here: If we listen() and a new link dies before it
+		   is accepted() it isn't 'dead' so doesn't get removed. */
+		if (!sk || sock_flag(sk, SOCK_DESTROY) ||
+		    (sk->sk_state == TCP_LISTEN &&
+		     sock_flag(sk, SOCK_DEAD))) {
 			if (sk) {
 				sock_hold(sk);
 				ax25_destroy_socket(ax25);
diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c
index 96434d7..acdeab3 100644
--- a/net/bluetooth/hidp/core.c
+++ b/net/bluetooth/hidp/core.c
@@ -578,7 +578,7 @@
 	if (session->hid) {
 		if (session->hid->claimed & HID_CLAIMED_INPUT)
 			hidinput_disconnect(session->hid);
-		hid_free_device(session->hid);
+		hid_destroy_device(session->hid);
 	}
 
 	/* Wakeup user-space polling for socket errors */
@@ -623,9 +623,15 @@
 static int hidp_setup_input(struct hidp_session *session,
 				struct hidp_connadd_req *req)
 {
-	struct input_dev *input = session->input;
+	struct input_dev *input;
 	int i;
 
+	input = input_allocate_device();
+	if (!input)
+		return -ENOMEM;
+
+	session->input = input;
+
 	input_set_drvdata(input, session);
 
 	input->name = "Bluetooth HID Boot Protocol Device";
@@ -677,67 +683,114 @@
 {
 }
 
-static const struct {
-	__u16 idVendor;
-	__u16 idProduct;
-	unsigned quirks;
-} hidp_blacklist[] = {
-	/* Apple wireless Mighty Mouse */
-	{ 0x05ac, 0x030c, HID_QUIRK_MIGHTYMOUSE | HID_QUIRK_INVERT_HWHEEL },
-
-	{ }	/* Terminating entry */
-};
-
-static void hidp_setup_quirks(struct hid_device *hid)
+static int hidp_parse(struct hid_device *hid)
 {
-	unsigned int n;
+	struct hidp_session *session = hid->driver_data;
+	struct hidp_connadd_req *req = session->req;
+	unsigned char *buf;
+	int ret;
 
-	for (n = 0; hidp_blacklist[n].idVendor; n++)
-		if (hidp_blacklist[n].idVendor == le16_to_cpu(hid->vendor) &&
-				hidp_blacklist[n].idProduct == le16_to_cpu(hid->product))
-			hid->quirks = hidp_blacklist[n].quirks;
+	buf = kmalloc(req->rd_size, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	if (copy_from_user(buf, req->rd_data, req->rd_size)) {
+		kfree(buf);
+		return -EFAULT;
+	}
+
+	ret = hid_parse_report(session->hid, buf, req->rd_size);
+
+	kfree(buf);
+
+	if (ret)
+		return ret;
+
+	session->req = NULL;
+
+	return 0;
 }
 
-static void hidp_setup_hid(struct hidp_session *session,
+static int hidp_start(struct hid_device *hid)
+{
+	struct hidp_session *session = hid->driver_data;
+	struct hid_report *report;
+
+	list_for_each_entry(report, &hid->report_enum[HID_INPUT_REPORT].
+			report_list, list)
+		hidp_send_report(session, report);
+
+	list_for_each_entry(report, &hid->report_enum[HID_FEATURE_REPORT].
+			report_list, list)
+		hidp_send_report(session, report);
+
+	return 0;
+}
+
+static void hidp_stop(struct hid_device *hid)
+{
+	struct hidp_session *session = hid->driver_data;
+
+	skb_queue_purge(&session->ctrl_transmit);
+	skb_queue_purge(&session->intr_transmit);
+
+	if (hid->claimed & HID_CLAIMED_INPUT)
+		hidinput_disconnect(hid);
+	hid->claimed = 0;
+}
+
+static struct hid_ll_driver hidp_hid_driver = {
+	.parse = hidp_parse,
+	.start = hidp_start,
+	.stop = hidp_stop,
+	.open  = hidp_open,
+	.close = hidp_close,
+	.hidinput_input_event = hidp_hidinput_event,
+};
+
+static int hidp_setup_hid(struct hidp_session *session,
 				struct hidp_connadd_req *req)
 {
-	struct hid_device *hid = session->hid;
-	struct hid_report *report;
+	struct hid_device *hid;
 	bdaddr_t src, dst;
+	int ret;
+
+	hid = hid_allocate_device();
+	if (IS_ERR(hid)) {
+		ret = PTR_ERR(session->hid);
+		goto err;
+	}
+
+	session->hid = hid;
+	session->req = req;
+	hid->driver_data = session;
 
 	baswap(&src, &bt_sk(session->ctrl_sock->sk)->src);
 	baswap(&dst, &bt_sk(session->ctrl_sock->sk)->dst);
 
-	hid->driver_data = session;
-
-	hid->country = req->country;
-
 	hid->bus     = BUS_BLUETOOTH;
 	hid->vendor  = req->vendor;
 	hid->product = req->product;
 	hid->version = req->version;
+	hid->country = req->country;
 
 	strncpy(hid->name, req->name, 128);
 	strncpy(hid->phys, batostr(&src), 64);
 	strncpy(hid->uniq, batostr(&dst), 64);
 
-	hid->dev = hidp_get_device(session);
+	hid->dev.parent = hidp_get_device(session);
+	hid->ll_driver = &hidp_hid_driver;
 
-	hid->hid_open  = hidp_open;
-	hid->hid_close = hidp_close;
+	ret = hid_add_device(hid);
+	if (ret)
+		goto err_hid;
 
-	hid->hidinput_input_event = hidp_hidinput_event;
-
-	hidp_setup_quirks(hid);
-
-	list_for_each_entry(report, &hid->report_enum[HID_INPUT_REPORT].report_list, list)
-		hidp_send_report(session, report);
-
-	list_for_each_entry(report, &hid->report_enum[HID_FEATURE_REPORT].report_list, list)
-		hidp_send_report(session, report);
-
-	if (hidinput_connect(hid) == 0)
-		hid->claimed |= HID_CLAIMED_INPUT;
+	return 0;
+err_hid:
+	hid_destroy_device(hid);
+	session->hid = NULL;
+err:
+	return ret;
 }
 
 int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock, struct socket *intr_sock)
@@ -757,38 +810,6 @@
 
 	BT_DBG("rd_data %p rd_size %d", req->rd_data, req->rd_size);
 
-	if (req->rd_size > 0) {
-		unsigned char *buf = kmalloc(req->rd_size, GFP_KERNEL);
-
-		if (!buf) {
-			kfree(session);
-			return -ENOMEM;
-		}
-
-		if (copy_from_user(buf, req->rd_data, req->rd_size)) {
-			kfree(buf);
-			kfree(session);
-			return -EFAULT;
-		}
-
-		session->hid = hid_parse_report(buf, req->rd_size);
-
-		kfree(buf);
-
-		if (!session->hid) {
-			kfree(session);
-			return -EINVAL;
-		}
-	}
-
-	if (!session->hid) {
-		session->input = input_allocate_device();
-		if (!session->input) {
-			kfree(session);
-			return -ENOMEM;
-		}
-	}
-
 	down_write(&hidp_session_sem);
 
 	s = __hidp_get_session(&bt_sk(ctrl_sock->sk)->dst);
@@ -816,14 +837,17 @@
 	session->flags   = req->flags & (1 << HIDP_BLUETOOTH_VENDOR_ID);
 	session->idle_to = req->idle_to;
 
-	if (session->input) {
-		err = hidp_setup_input(session, req);
-		if (err < 0)
-			goto failed;
+	if (req->rd_size > 0) {
+		err = hidp_setup_hid(session, req);
+		if (err && err != -ENODEV)
+			goto err_skb;
 	}
 
-	if (session->hid)
-		hidp_setup_hid(session, req);
+	if (!session->hid) {
+		err = hidp_setup_input(session, req);
+		if (err < 0)
+			goto err_skb;
+	}
 
 	__hidp_link_session(session);
 
@@ -850,17 +874,16 @@
 
 	__hidp_unlink_session(session);
 
-	if (session->input) {
+	if (session->input)
 		input_unregister_device(session->input);
-		session->input = NULL; /* don't try to free it here */
-	}
-
+	if (session->hid)
+		hid_destroy_device(session->hid);
+err_skb:
+	skb_queue_purge(&session->ctrl_transmit);
+	skb_queue_purge(&session->intr_transmit);
 failed:
 	up_write(&hidp_session_sem);
 
-	if (session->hid)
-		hid_free_device(session->hid);
-
 	input_free_device(session->input);
 	kfree(session);
 	return err;
@@ -950,18 +973,43 @@
 	return err;
 }
 
+static const struct hid_device_id hidp_table[] = {
+	{ HID_BLUETOOTH_DEVICE(HID_ANY_ID, HID_ANY_ID) },
+	{ }
+};
+
+static struct hid_driver hidp_driver = {
+	.name = "generic-bluetooth",
+	.id_table = hidp_table,
+};
+
 static int __init hidp_init(void)
 {
+	int ret;
+
 	l2cap_load();
 
 	BT_INFO("HIDP (Human Interface Emulation) ver %s", VERSION);
 
-	return hidp_init_sockets();
+	ret = hid_register_driver(&hidp_driver);
+	if (ret)
+		goto err;
+
+	ret = hidp_init_sockets();
+	if (ret)
+		goto err_drv;
+
+	return 0;
+err_drv:
+	hid_unregister_driver(&hidp_driver);
+err:
+	return ret;
 }
 
 static void __exit hidp_exit(void)
 {
 	hidp_cleanup_sockets();
+	hid_unregister_driver(&hidp_driver);
 }
 
 module_init(hidp_init);
diff --git a/net/bluetooth/hidp/hidp.h b/net/bluetooth/hidp/hidp.h
index 343fb05..e503c89 100644
--- a/net/bluetooth/hidp/hidp.h
+++ b/net/bluetooth/hidp/hidp.h
@@ -151,6 +151,8 @@
 
 	struct sk_buff_head ctrl_transmit;
 	struct sk_buff_head intr_transmit;
+
+	struct hidp_connadd_req *req;
 };
 
 static inline void hidp_schedule(struct hidp_session *session)
diff --git a/net/bridge/br.c b/net/bridge/br.c
index 573acdf..4d2c1f1 100644
--- a/net/bridge/br.c
+++ b/net/bridge/br.c
@@ -28,6 +28,10 @@
 	.rcv	= br_stp_rcv,
 };
 
+static struct pernet_operations br_net_ops = {
+	.exit	= br_net_exit,
+};
+
 static int __init br_init(void)
 {
 	int err;
@@ -42,18 +46,22 @@
 	if (err)
 		goto err_out;
 
-	err = br_netfilter_init();
+	err = register_pernet_subsys(&br_net_ops);
 	if (err)
 		goto err_out1;
 
-	err = register_netdevice_notifier(&br_device_notifier);
+	err = br_netfilter_init();
 	if (err)
 		goto err_out2;
 
-	err = br_netlink_init();
+	err = register_netdevice_notifier(&br_device_notifier);
 	if (err)
 		goto err_out3;
 
+	err = br_netlink_init();
+	if (err)
+		goto err_out4;
+
 	brioctl_set(br_ioctl_deviceless_stub);
 	br_handle_frame_hook = br_handle_frame;
 
@@ -61,10 +69,12 @@
 	br_fdb_put_hook = br_fdb_put;
 
 	return 0;
-err_out3:
+err_out4:
 	unregister_netdevice_notifier(&br_device_notifier);
-err_out2:
+err_out3:
 	br_netfilter_fini();
+err_out2:
+	unregister_pernet_subsys(&br_net_ops);
 err_out1:
 	br_fdb_fini();
 err_out:
@@ -80,7 +90,7 @@
 	unregister_netdevice_notifier(&br_device_notifier);
 	brioctl_set(NULL);
 
-	br_cleanup_bridges();
+	unregister_pernet_subsys(&br_net_ops);
 
 	synchronize_net();
 
diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c
index 4f52c3d..22ba863 100644
--- a/net/bridge/br_device.c
+++ b/net/bridge/br_device.c
@@ -178,5 +178,6 @@
 	dev->priv_flags = IFF_EBRIDGE;
 
 	dev->features = NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_HIGHDMA |
-			NETIF_F_GSO_MASK | NETIF_F_NO_CSUM | NETIF_F_LLTX;
+			NETIF_F_GSO_MASK | NETIF_F_NO_CSUM | NETIF_F_LLTX |
+			NETIF_F_NETNS_LOCAL;
 }
diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c
index 63c18aa..573e20f 100644
--- a/net/bridge/br_if.c
+++ b/net/bridge/br_if.c
@@ -168,7 +168,7 @@
 	unregister_netdevice(br->dev);
 }
 
-static struct net_device *new_bridge_dev(const char *name)
+static struct net_device *new_bridge_dev(struct net *net, const char *name)
 {
 	struct net_bridge *br;
 	struct net_device *dev;
@@ -178,6 +178,7 @@
 
 	if (!dev)
 		return NULL;
+	dev_net_set(dev, net);
 
 	br = netdev_priv(dev);
 	br->dev = dev;
@@ -262,12 +263,12 @@
 	return p;
 }
 
-int br_add_bridge(const char *name)
+int br_add_bridge(struct net *net, const char *name)
 {
 	struct net_device *dev;
 	int ret;
 
-	dev = new_bridge_dev(name);
+	dev = new_bridge_dev(net, name);
 	if (!dev)
 		return -ENOMEM;
 
@@ -294,13 +295,13 @@
 	goto out;
 }
 
-int br_del_bridge(const char *name)
+int br_del_bridge(struct net *net, const char *name)
 {
 	struct net_device *dev;
 	int ret = 0;
 
 	rtnl_lock();
-	dev = __dev_get_by_name(&init_net, name);
+	dev = __dev_get_by_name(net, name);
 	if (dev == NULL)
 		ret =  -ENXIO; 	/* Could not find device */
 
@@ -445,13 +446,13 @@
 	return 0;
 }
 
-void __exit br_cleanup_bridges(void)
+void br_net_exit(struct net *net)
 {
 	struct net_device *dev;
 
 	rtnl_lock();
 restart:
-	for_each_netdev(&init_net, dev) {
+	for_each_netdev(net, dev) {
 		if (dev->priv_flags & IFF_EBRIDGE) {
 			del_br(dev->priv);
 			goto restart;
diff --git a/net/bridge/br_ioctl.c b/net/bridge/br_ioctl.c
index 5bbf073..6a6433d 100644
--- a/net/bridge/br_ioctl.c
+++ b/net/bridge/br_ioctl.c
@@ -21,12 +21,12 @@
 #include "br_private.h"
 
 /* called with RTNL */
-static int get_bridge_ifindices(int *indices, int num)
+static int get_bridge_ifindices(struct net *net, int *indices, int num)
 {
 	struct net_device *dev;
 	int i = 0;
 
-	for_each_netdev(&init_net, dev) {
+	for_each_netdev(net, dev) {
 		if (i >= num)
 			break;
 		if (dev->priv_flags & IFF_EBRIDGE)
@@ -89,7 +89,7 @@
 	if (!capable(CAP_NET_ADMIN))
 		return -EPERM;
 
-	dev = dev_get_by_index(&init_net, ifindex);
+	dev = dev_get_by_index(dev_net(br->dev), ifindex);
 	if (dev == NULL)
 		return -EINVAL;
 
@@ -315,7 +315,7 @@
 	return -EOPNOTSUPP;
 }
 
-static int old_deviceless(void __user *uarg)
+static int old_deviceless(struct net *net, void __user *uarg)
 {
 	unsigned long args[3];
 
@@ -337,7 +337,7 @@
 		if (indices == NULL)
 			return -ENOMEM;
 
-		args[2] = get_bridge_ifindices(indices, args[2]);
+		args[2] = get_bridge_ifindices(net, indices, args[2]);
 
 		ret = copy_to_user((void __user *)args[1], indices, args[2]*sizeof(int))
 			? -EFAULT : args[2];
@@ -360,9 +360,9 @@
 		buf[IFNAMSIZ-1] = 0;
 
 		if (args[0] == BRCTL_ADD_BRIDGE)
-			return br_add_bridge(buf);
+			return br_add_bridge(net, buf);
 
-		return br_del_bridge(buf);
+		return br_del_bridge(net, buf);
 	}
 	}
 
@@ -374,7 +374,7 @@
 	switch (cmd) {
 	case SIOCGIFBR:
 	case SIOCSIFBR:
-		return old_deviceless(uarg);
+		return old_deviceless(net, uarg);
 
 	case SIOCBRADDBR:
 	case SIOCBRDELBR:
@@ -389,9 +389,9 @@
 
 		buf[IFNAMSIZ-1] = 0;
 		if (cmd == SIOCBRADDBR)
-			return br_add_bridge(buf);
+			return br_add_bridge(net, buf);
 
-		return br_del_bridge(buf);
+		return br_del_bridge(net, buf);
 	}
 	}
 	return -EOPNOTSUPP;
diff --git a/net/bridge/br_netfilter.c b/net/bridge/br_netfilter.c
index 6a9a6cd..a4abed5 100644
--- a/net/bridge/br_netfilter.c
+++ b/net/bridge/br_netfilter.c
@@ -657,7 +657,7 @@
 {
 	struct nf_bridge_info *nf_bridge;
 	struct net_device *parent;
-	int pf;
+	u_int8_t pf;
 
 	if (!skb->nf_bridge)
 		return NF_ACCEPT;
@@ -791,7 +791,7 @@
 {
 	struct nf_bridge_info *nf_bridge = skb->nf_bridge;
 	struct net_device *realoutdev = bridge_parent(skb->dev);
-	int pf;
+	u_int8_t pf;
 
 #ifdef CONFIG_NETFILTER_DEBUG
 	/* Be very paranoid. This probably won't happen anymore, but let's
diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c
index f155e6c..ba7be19 100644
--- a/net/bridge/br_netlink.c
+++ b/net/bridge/br_netlink.c
@@ -82,6 +82,7 @@
  */
 void br_ifinfo_notify(int event, struct net_bridge_port *port)
 {
+	struct net *net = dev_net(port->dev);
 	struct sk_buff *skb;
 	int err = -ENOBUFS;
 
@@ -97,10 +98,10 @@
 		kfree_skb(skb);
 		goto errout;
 	}
-	err = rtnl_notify(skb, &init_net,0, RTNLGRP_LINK, NULL, GFP_ATOMIC);
+	err = rtnl_notify(skb, net, 0, RTNLGRP_LINK, NULL, GFP_ATOMIC);
 errout:
 	if (err < 0)
-		rtnl_set_sk_err(&init_net, RTNLGRP_LINK, err);
+		rtnl_set_sk_err(net, RTNLGRP_LINK, err);
 }
 
 /*
@@ -112,11 +113,8 @@
 	struct net_device *dev;
 	int idx;
 
-	if (net != &init_net)
-		return 0;
-
 	idx = 0;
-	for_each_netdev(&init_net, dev) {
+	for_each_netdev(net, dev) {
 		/* not a bridge port */
 		if (dev->br_port == NULL || idx < cb->args[0])
 			goto skip;
@@ -147,9 +145,6 @@
 	struct net_bridge_port *p;
 	u8 new_state;
 
-	if (net != &init_net)
-		return -EINVAL;
-
 	if (nlmsg_len(nlh) < sizeof(*ifm))
 		return -EINVAL;
 
@@ -165,7 +160,7 @@
 	if (new_state > BR_STATE_BLOCKING)
 		return -EINVAL;
 
-	dev = __dev_get_by_index(&init_net, ifm->ifi_index);
+	dev = __dev_get_by_index(net, ifm->ifi_index);
 	if (!dev)
 		return -ENODEV;
 
diff --git a/net/bridge/br_notify.c b/net/bridge/br_notify.c
index 76340bd..763a3ec 100644
--- a/net/bridge/br_notify.c
+++ b/net/bridge/br_notify.c
@@ -35,9 +35,6 @@
 	struct net_bridge_port *p = dev->br_port;
 	struct net_bridge *br;
 
-	if (!net_eq(dev_net(dev), &init_net))
-		return NOTIFY_DONE;
-
 	/* not a port of a bridge */
 	if (p == NULL)
 		return NOTIFY_DONE;
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
index c3dc18d..b6c3b71 100644
--- a/net/bridge/br_private.h
+++ b/net/bridge/br_private.h
@@ -178,9 +178,9 @@
 
 /* br_if.c */
 extern void br_port_carrier_check(struct net_bridge_port *p);
-extern int br_add_bridge(const char *name);
-extern int br_del_bridge(const char *name);
-extern void br_cleanup_bridges(void);
+extern int br_add_bridge(struct net *net, const char *name);
+extern int br_del_bridge(struct net *net, const char *name);
+extern void br_net_exit(struct net *net);
 extern int br_add_if(struct net_bridge *br,
 	      struct net_device *dev);
 extern int br_del_if(struct net_bridge *br,
diff --git a/net/bridge/br_stp_bpdu.c b/net/bridge/br_stp_bpdu.c
index 8b200f9..81ae40b 100644
--- a/net/bridge/br_stp_bpdu.c
+++ b/net/bridge/br_stp_bpdu.c
@@ -140,9 +140,6 @@
 	struct net_bridge *br;
 	const unsigned char *buf;
 
-	if (!net_eq(dev_net(dev), &init_net))
-		goto err;
-
 	if (!p)
 		goto err;
 
diff --git a/net/bridge/netfilter/Kconfig b/net/bridge/netfilter/Kconfig
index 9094797..366d3e9 100644
--- a/net/bridge/netfilter/Kconfig
+++ b/net/bridge/netfilter/Kconfig
@@ -2,21 +2,21 @@
 # Bridge netfilter configuration
 #
 
-menu "Bridge: Netfilter Configuration"
-	depends on BRIDGE && BRIDGE_NETFILTER
-
-config BRIDGE_NF_EBTABLES
+menuconfig BRIDGE_NF_EBTABLES
 	tristate "Ethernet Bridge tables (ebtables) support"
+	select NETFILTER_XTABLES
 	help
 	  ebtables is a general, extensible frame/packet identification
 	  framework. Say 'Y' or 'M' here if you want to do Ethernet
 	  filtering/NAT/brouting on the Ethernet bridge.
+
+if BRIDGE_NF_EBTABLES
+
 #
 # tables
 #
 config BRIDGE_EBT_BROUTE
 	tristate "ebt: broute table support"
-	depends on BRIDGE_NF_EBTABLES
 	help
 	  The ebtables broute table is used to define rules that decide between
 	  bridging and routing frames, giving Linux the functionality of a
@@ -27,7 +27,6 @@
 
 config BRIDGE_EBT_T_FILTER
 	tristate "ebt: filter table support"
-	depends on BRIDGE_NF_EBTABLES
 	help
 	  The ebtables filter table is used to define frame filtering rules at
 	  local input, forwarding and local output. See the man page for
@@ -37,7 +36,6 @@
 
 config BRIDGE_EBT_T_NAT
 	tristate "ebt: nat table support"
-	depends on BRIDGE_NF_EBTABLES
 	help
 	  The ebtables nat table is used to define rules that alter the MAC
 	  source address (MAC SNAT) or the MAC destination address (MAC DNAT).
@@ -49,7 +47,6 @@
 #
 config BRIDGE_EBT_802_3
 	tristate "ebt: 802.3 filter support"
-	depends on BRIDGE_NF_EBTABLES
 	help
 	  This option adds matching support for 802.3 Ethernet frames.
 
@@ -57,7 +54,6 @@
 
 config BRIDGE_EBT_AMONG
 	tristate "ebt: among filter support"
-	depends on BRIDGE_NF_EBTABLES
 	help
 	  This option adds the among match, which allows matching the MAC source
 	  and/or destination address on a list of addresses. Optionally,
@@ -67,7 +63,6 @@
 
 config BRIDGE_EBT_ARP
 	tristate "ebt: ARP filter support"
-	depends on BRIDGE_NF_EBTABLES
 	help
 	  This option adds the ARP match, which allows ARP and RARP header field
 	  filtering.
@@ -76,7 +71,6 @@
 
 config BRIDGE_EBT_IP
 	tristate "ebt: IP filter support"
-	depends on BRIDGE_NF_EBTABLES
 	help
 	  This option adds the IP match, which allows basic IP header field
 	  filtering.
@@ -94,7 +88,6 @@
 
 config BRIDGE_EBT_LIMIT
 	tristate "ebt: limit match support"
-	depends on BRIDGE_NF_EBTABLES
 	help
 	  This option adds the limit match, which allows you to control
 	  the rate at which a rule can be matched. This match is the
@@ -105,7 +98,6 @@
 
 config BRIDGE_EBT_MARK
 	tristate "ebt: mark filter support"
-	depends on BRIDGE_NF_EBTABLES
 	help
 	  This option adds the mark match, which allows matching frames based on
 	  the 'nfmark' value in the frame. This can be set by the mark target.
@@ -116,7 +108,6 @@
 
 config BRIDGE_EBT_PKTTYPE
 	tristate "ebt: packet type filter support"
-	depends on BRIDGE_NF_EBTABLES
 	help
 	  This option adds the packet type match, which allows matching on the
 	  type of packet based on its Ethernet "class" (as determined by
@@ -127,7 +118,6 @@
 
 config BRIDGE_EBT_STP
 	tristate "ebt: STP filter support"
-	depends on BRIDGE_NF_EBTABLES
 	help
 	  This option adds the Spanning Tree Protocol match, which
 	  allows STP header field filtering.
@@ -136,7 +126,6 @@
 
 config BRIDGE_EBT_VLAN
 	tristate "ebt: 802.1Q VLAN filter support"
-	depends on BRIDGE_NF_EBTABLES
 	help
 	  This option adds the 802.1Q vlan match, which allows the filtering of
 	  802.1Q vlan fields.
@@ -156,7 +145,6 @@
 
 config BRIDGE_EBT_DNAT
 	tristate "ebt: dnat target support"
-	depends on BRIDGE_NF_EBTABLES
 	help
 	  This option adds the MAC DNAT target, which allows altering the MAC
 	  destination address of frames.
@@ -165,7 +153,6 @@
 
 config BRIDGE_EBT_MARK_T
 	tristate "ebt: mark target support"
-	depends on BRIDGE_NF_EBTABLES
 	help
 	  This option adds the mark target, which allows marking frames by
 	  setting the 'nfmark' value in the frame.
@@ -176,7 +163,6 @@
 
 config BRIDGE_EBT_REDIRECT
 	tristate "ebt: redirect target support"
-	depends on BRIDGE_NF_EBTABLES
 	help
 	  This option adds the MAC redirect target, which allows altering the MAC
 	  destination address of a frame to that of the device it arrived on.
@@ -185,7 +171,6 @@
 
 config BRIDGE_EBT_SNAT
 	tristate "ebt: snat target support"
-	depends on BRIDGE_NF_EBTABLES
 	help
 	  This option adds the MAC SNAT target, which allows altering the MAC
 	  source address of frames.
@@ -196,7 +181,6 @@
 #
 config BRIDGE_EBT_LOG
 	tristate "ebt: log support"
-	depends on BRIDGE_NF_EBTABLES
 	help
 	  This option adds the log watcher, that you can use in any rule
 	  in any ebtables table. It records info about the frame header
@@ -206,7 +190,6 @@
 
 config BRIDGE_EBT_ULOG
 	tristate "ebt: ulog support (OBSOLETE)"
-	depends on BRIDGE_NF_EBTABLES
 	help
 	  This option enables the old bridge-specific "ebt_ulog" implementation
 	  which has been obsoleted by the new "nfnetlink_log" code (see
@@ -223,7 +206,6 @@
 
 config BRIDGE_EBT_NFLOG
 	tristate "ebt: nflog support"
-	depends on BRIDGE_NF_EBTABLES
 	help
 	  This option enables the nflog watcher, which allows to LOG
 	  messages through the netfilter logging API, which can use
@@ -235,4 +217,4 @@
 
 	  To compile it as a module, choose M here.  If unsure, say N.
 
-endmenu
+endif # BRIDGE_NF_EBTABLES
diff --git a/net/bridge/netfilter/ebt_802_3.c b/net/bridge/netfilter/ebt_802_3.c
index 9853402..bd91dc5 100644
--- a/net/bridge/netfilter/ebt_802_3.c
+++ b/net/bridge/netfilter/ebt_802_3.c
@@ -7,64 +7,63 @@
  * May 2003
  *
  */
-
+#include <linux/module.h>
+#include <linux/netfilter/x_tables.h>
 #include <linux/netfilter_bridge/ebtables.h>
 #include <linux/netfilter_bridge/ebt_802_3.h>
-#include <linux/module.h>
 
-static int ebt_filter_802_3(const struct sk_buff *skb, const struct net_device *in,
-   const struct net_device *out, const void *data, unsigned int datalen)
+static bool
+ebt_802_3_mt(const struct sk_buff *skb, const struct xt_match_param *par)
 {
-	const struct ebt_802_3_info *info = data;
+	const struct ebt_802_3_info *info = par->matchinfo;
 	const struct ebt_802_3_hdr *hdr = ebt_802_3_hdr(skb);
 	__be16 type = hdr->llc.ui.ctrl & IS_UI ? hdr->llc.ui.type : hdr->llc.ni.type;
 
 	if (info->bitmask & EBT_802_3_SAP) {
 		if (FWINV(info->sap != hdr->llc.ui.ssap, EBT_802_3_SAP))
-				return EBT_NOMATCH;
+			return false;
 		if (FWINV(info->sap != hdr->llc.ui.dsap, EBT_802_3_SAP))
-				return EBT_NOMATCH;
+			return false;
 	}
 
 	if (info->bitmask & EBT_802_3_TYPE) {
 		if (!(hdr->llc.ui.dsap == CHECK_TYPE && hdr->llc.ui.ssap == CHECK_TYPE))
-			return EBT_NOMATCH;
+			return false;
 		if (FWINV(info->type != type, EBT_802_3_TYPE))
-			return EBT_NOMATCH;
+			return false;
 	}
 
-	return EBT_MATCH;
+	return true;
 }
 
-static struct ebt_match filter_802_3;
-static int ebt_802_3_check(const char *tablename, unsigned int hookmask,
-   const struct ebt_entry *e, void *data, unsigned int datalen)
+static bool ebt_802_3_mt_check(const struct xt_mtchk_param *par)
 {
-	const struct ebt_802_3_info *info = data;
+	const struct ebt_802_3_info *info = par->matchinfo;
 
-	if (datalen < sizeof(struct ebt_802_3_info))
-		return -EINVAL;
 	if (info->bitmask & ~EBT_802_3_MASK || info->invflags & ~EBT_802_3_MASK)
-		return -EINVAL;
+		return false;
 
-	return 0;
+	return true;
 }
 
-static struct ebt_match filter_802_3 __read_mostly = {
-	.name		= EBT_802_3_MATCH,
-	.match		= ebt_filter_802_3,
-	.check		= ebt_802_3_check,
+static struct xt_match ebt_802_3_mt_reg __read_mostly = {
+	.name		= "802_3",
+	.revision	= 0,
+	.family		= NFPROTO_BRIDGE,
+	.match		= ebt_802_3_mt,
+	.checkentry	= ebt_802_3_mt_check,
+	.matchsize	= XT_ALIGN(sizeof(struct ebt_802_3_info)),
 	.me		= THIS_MODULE,
 };
 
 static int __init ebt_802_3_init(void)
 {
-	return ebt_register_match(&filter_802_3);
+	return xt_register_match(&ebt_802_3_mt_reg);
 }
 
 static void __exit ebt_802_3_fini(void)
 {
-	ebt_unregister_match(&filter_802_3);
+	xt_unregister_match(&ebt_802_3_mt_reg);
 }
 
 module_init(ebt_802_3_init);
diff --git a/net/bridge/netfilter/ebt_among.c b/net/bridge/netfilter/ebt_among.c
index 70b6dca..b595f09 100644
--- a/net/bridge/netfilter/ebt_among.c
+++ b/net/bridge/netfilter/ebt_among.c
@@ -7,15 +7,15 @@
  *  August, 2003
  *
  */
-
-#include <linux/netfilter_bridge/ebtables.h>
-#include <linux/netfilter_bridge/ebt_among.h>
 #include <linux/ip.h>
 #include <linux/if_arp.h>
 #include <linux/module.h>
+#include <linux/netfilter/x_tables.h>
+#include <linux/netfilter_bridge/ebtables.h>
+#include <linux/netfilter_bridge/ebt_among.h>
 
-static int ebt_mac_wormhash_contains(const struct ebt_mac_wormhash *wh,
-				     const char *mac, __be32 ip)
+static bool ebt_mac_wormhash_contains(const struct ebt_mac_wormhash *wh,
+				      const char *mac, __be32 ip)
 {
 	/* You may be puzzled as to how this code works.
 	 * Some tricks were used, refer to
@@ -33,23 +33,19 @@
 	if (ip) {
 		for (i = start; i < limit; i++) {
 			p = &wh->pool[i];
-			if (cmp[1] == p->cmp[1] && cmp[0] == p->cmp[0]) {
-				if (p->ip == 0 || p->ip == ip) {
-					return 1;
-				}
-			}
+			if (cmp[1] == p->cmp[1] && cmp[0] == p->cmp[0])
+				if (p->ip == 0 || p->ip == ip)
+					return true;
 		}
 	} else {
 		for (i = start; i < limit; i++) {
 			p = &wh->pool[i];
-			if (cmp[1] == p->cmp[1] && cmp[0] == p->cmp[0]) {
-				if (p->ip == 0) {
-					return 1;
-				}
-			}
+			if (cmp[1] == p->cmp[1] && cmp[0] == p->cmp[0])
+				if (p->ip == 0)
+					return true;
 		}
 	}
-	return 0;
+	return false;
 }
 
 static int ebt_mac_wormhash_check_integrity(const struct ebt_mac_wormhash
@@ -131,12 +127,10 @@
 	return 0;
 }
 
-static int ebt_filter_among(const struct sk_buff *skb,
-			    const struct net_device *in,
-			    const struct net_device *out, const void *data,
-			    unsigned int datalen)
+static bool
+ebt_among_mt(const struct sk_buff *skb, const struct xt_match_param *par)
 {
-	const struct ebt_among_info *info = data;
+	const struct ebt_among_info *info = par->matchinfo;
 	const char *dmac, *smac;
 	const struct ebt_mac_wormhash *wh_dst, *wh_src;
 	__be32 dip = 0, sip = 0;
@@ -147,41 +141,41 @@
 	if (wh_src) {
 		smac = eth_hdr(skb)->h_source;
 		if (get_ip_src(skb, &sip))
-			return EBT_NOMATCH;
+			return false;
 		if (!(info->bitmask & EBT_AMONG_SRC_NEG)) {
 			/* we match only if it contains */
 			if (!ebt_mac_wormhash_contains(wh_src, smac, sip))
-				return EBT_NOMATCH;
+				return false;
 		} else {
 			/* we match only if it DOES NOT contain */
 			if (ebt_mac_wormhash_contains(wh_src, smac, sip))
-				return EBT_NOMATCH;
+				return false;
 		}
 	}
 
 	if (wh_dst) {
 		dmac = eth_hdr(skb)->h_dest;
 		if (get_ip_dst(skb, &dip))
-			return EBT_NOMATCH;
+			return false;
 		if (!(info->bitmask & EBT_AMONG_DST_NEG)) {
 			/* we match only if it contains */
 			if (!ebt_mac_wormhash_contains(wh_dst, dmac, dip))
-				return EBT_NOMATCH;
+				return false;
 		} else {
 			/* we match only if it DOES NOT contain */
 			if (ebt_mac_wormhash_contains(wh_dst, dmac, dip))
-				return EBT_NOMATCH;
+				return false;
 		}
 	}
 
-	return EBT_MATCH;
+	return true;
 }
 
-static int ebt_among_check(const char *tablename, unsigned int hookmask,
-			   const struct ebt_entry *e, void *data,
-			   unsigned int datalen)
+static bool ebt_among_mt_check(const struct xt_mtchk_param *par)
 {
-	const struct ebt_among_info *info = data;
+	const struct ebt_among_info *info = par->matchinfo;
+	const struct ebt_entry_match *em =
+		container_of(par->matchinfo, const struct ebt_entry_match, data);
 	int expected_length = sizeof(struct ebt_among_info);
 	const struct ebt_mac_wormhash *wh_dst, *wh_src;
 	int err;
@@ -191,42 +185,45 @@
 	expected_length += ebt_mac_wormhash_size(wh_dst);
 	expected_length += ebt_mac_wormhash_size(wh_src);
 
-	if (datalen != EBT_ALIGN(expected_length)) {
+	if (em->match_size != EBT_ALIGN(expected_length)) {
 		printk(KERN_WARNING
 		       "ebtables: among: wrong size: %d "
 		       "against expected %d, rounded to %Zd\n",
-		       datalen, expected_length,
+		       em->match_size, expected_length,
 		       EBT_ALIGN(expected_length));
-		return -EINVAL;
+		return false;
 	}
 	if (wh_dst && (err = ebt_mac_wormhash_check_integrity(wh_dst))) {
 		printk(KERN_WARNING
 		       "ebtables: among: dst integrity fail: %x\n", -err);
-		return -EINVAL;
+		return false;
 	}
 	if (wh_src && (err = ebt_mac_wormhash_check_integrity(wh_src))) {
 		printk(KERN_WARNING
 		       "ebtables: among: src integrity fail: %x\n", -err);
-		return -EINVAL;
+		return false;
 	}
-	return 0;
+	return true;
 }
 
-static struct ebt_match filter_among __read_mostly = {
-	.name		= EBT_AMONG_MATCH,
-	.match		= ebt_filter_among,
-	.check		= ebt_among_check,
+static struct xt_match ebt_among_mt_reg __read_mostly = {
+	.name		= "among",
+	.revision	= 0,
+	.family		= NFPROTO_BRIDGE,
+	.match		= ebt_among_mt,
+	.checkentry	= ebt_among_mt_check,
+	.matchsize	= -1, /* special case */
 	.me		= THIS_MODULE,
 };
 
 static int __init ebt_among_init(void)
 {
-	return ebt_register_match(&filter_among);
+	return xt_register_match(&ebt_among_mt_reg);
 }
 
 static void __exit ebt_among_fini(void)
 {
-	ebt_unregister_match(&filter_among);
+	xt_unregister_match(&ebt_among_mt_reg);
 }
 
 module_init(ebt_among_init);
diff --git a/net/bridge/netfilter/ebt_arp.c b/net/bridge/netfilter/ebt_arp.c
index 7c535be..b7ad604 100644
--- a/net/bridge/netfilter/ebt_arp.c
+++ b/net/bridge/netfilter/ebt_arp.c
@@ -8,58 +8,58 @@
  *  April, 2002
  *
  */
-
-#include <linux/netfilter_bridge/ebtables.h>
-#include <linux/netfilter_bridge/ebt_arp.h>
 #include <linux/if_arp.h>
 #include <linux/if_ether.h>
 #include <linux/module.h>
+#include <linux/netfilter/x_tables.h>
+#include <linux/netfilter_bridge/ebtables.h>
+#include <linux/netfilter_bridge/ebt_arp.h>
 
-static int ebt_filter_arp(const struct sk_buff *skb, const struct net_device *in,
-   const struct net_device *out, const void *data, unsigned int datalen)
+static bool
+ebt_arp_mt(const struct sk_buff *skb, const struct xt_match_param *par)
 {
-	const struct ebt_arp_info *info = data;
+	const struct ebt_arp_info *info = par->matchinfo;
 	const struct arphdr *ah;
 	struct arphdr _arph;
 
 	ah = skb_header_pointer(skb, 0, sizeof(_arph), &_arph);
 	if (ah == NULL)
-		return EBT_NOMATCH;
+		return false;
 	if (info->bitmask & EBT_ARP_OPCODE && FWINV(info->opcode !=
 	   ah->ar_op, EBT_ARP_OPCODE))
-		return EBT_NOMATCH;
+		return false;
 	if (info->bitmask & EBT_ARP_HTYPE && FWINV(info->htype !=
 	   ah->ar_hrd, EBT_ARP_HTYPE))
-		return EBT_NOMATCH;
+		return false;
 	if (info->bitmask & EBT_ARP_PTYPE && FWINV(info->ptype !=
 	   ah->ar_pro, EBT_ARP_PTYPE))
-		return EBT_NOMATCH;
+		return false;
 
 	if (info->bitmask & (EBT_ARP_SRC_IP | EBT_ARP_DST_IP | EBT_ARP_GRAT)) {
 		const __be32 *sap, *dap;
 		__be32 saddr, daddr;
 
 		if (ah->ar_pln != sizeof(__be32) || ah->ar_pro != htons(ETH_P_IP))
-			return EBT_NOMATCH;
+			return false;
 		sap = skb_header_pointer(skb, sizeof(struct arphdr) +
 					ah->ar_hln, sizeof(saddr),
 					&saddr);
 		if (sap == NULL)
-			return EBT_NOMATCH;
+			return false;
 		dap = skb_header_pointer(skb, sizeof(struct arphdr) +
 					2*ah->ar_hln+sizeof(saddr),
 					sizeof(daddr), &daddr);
 		if (dap == NULL)
-			return EBT_NOMATCH;
+			return false;
 		if (info->bitmask & EBT_ARP_SRC_IP &&
 		    FWINV(info->saddr != (*sap & info->smsk), EBT_ARP_SRC_IP))
-			return EBT_NOMATCH;
+			return false;
 		if (info->bitmask & EBT_ARP_DST_IP &&
 		    FWINV(info->daddr != (*dap & info->dmsk), EBT_ARP_DST_IP))
-			return EBT_NOMATCH;
+			return false;
 		if (info->bitmask & EBT_ARP_GRAT &&
 		    FWINV(*dap != *sap, EBT_ARP_GRAT))
-			return EBT_NOMATCH;
+			return false;
 	}
 
 	if (info->bitmask & (EBT_ARP_SRC_MAC | EBT_ARP_DST_MAC)) {
@@ -68,18 +68,18 @@
 		uint8_t verdict, i;
 
 		if (ah->ar_hln != ETH_ALEN || ah->ar_hrd != htons(ARPHRD_ETHER))
-			return EBT_NOMATCH;
+			return false;
 		if (info->bitmask & EBT_ARP_SRC_MAC) {
 			mp = skb_header_pointer(skb, sizeof(struct arphdr),
 						sizeof(_mac), &_mac);
 			if (mp == NULL)
-				return EBT_NOMATCH;
+				return false;
 			verdict = 0;
 			for (i = 0; i < 6; i++)
 				verdict |= (mp[i] ^ info->smaddr[i]) &
 				       info->smmsk[i];
 			if (FWINV(verdict != 0, EBT_ARP_SRC_MAC))
-				return EBT_NOMATCH;
+				return false;
 		}
 
 		if (info->bitmask & EBT_ARP_DST_MAC) {
@@ -87,50 +87,51 @@
 						ah->ar_hln + ah->ar_pln,
 						sizeof(_mac), &_mac);
 			if (mp == NULL)
-				return EBT_NOMATCH;
+				return false;
 			verdict = 0;
 			for (i = 0; i < 6; i++)
 				verdict |= (mp[i] ^ info->dmaddr[i]) &
 					info->dmmsk[i];
 			if (FWINV(verdict != 0, EBT_ARP_DST_MAC))
-				return EBT_NOMATCH;
+				return false;
 		}
 	}
 
-	return EBT_MATCH;
+	return true;
 }
 
-static int ebt_arp_check(const char *tablename, unsigned int hookmask,
-   const struct ebt_entry *e, void *data, unsigned int datalen)
+static bool ebt_arp_mt_check(const struct xt_mtchk_param *par)
 {
-	const struct ebt_arp_info *info = data;
+	const struct ebt_arp_info *info = par->matchinfo;
+	const struct ebt_entry *e = par->entryinfo;
 
-	if (datalen != EBT_ALIGN(sizeof(struct ebt_arp_info)))
-		return -EINVAL;
 	if ((e->ethproto != htons(ETH_P_ARP) &&
 	   e->ethproto != htons(ETH_P_RARP)) ||
 	   e->invflags & EBT_IPROTO)
-		return -EINVAL;
+		return false;
 	if (info->bitmask & ~EBT_ARP_MASK || info->invflags & ~EBT_ARP_MASK)
-		return -EINVAL;
-	return 0;
+		return false;
+	return true;
 }
 
-static struct ebt_match filter_arp __read_mostly = {
-	.name		= EBT_ARP_MATCH,
-	.match		= ebt_filter_arp,
-	.check		= ebt_arp_check,
+static struct xt_match ebt_arp_mt_reg __read_mostly = {
+	.name		= "arp",
+	.revision	= 0,
+	.family		= NFPROTO_BRIDGE,
+	.match		= ebt_arp_mt,
+	.checkentry	= ebt_arp_mt_check,
+	.matchsize	= XT_ALIGN(sizeof(struct ebt_arp_info)),
 	.me		= THIS_MODULE,
 };
 
 static int __init ebt_arp_init(void)
 {
-	return ebt_register_match(&filter_arp);
+	return xt_register_match(&ebt_arp_mt_reg);
 }
 
 static void __exit ebt_arp_fini(void)
 {
-	ebt_unregister_match(&filter_arp);
+	xt_unregister_match(&ebt_arp_mt_reg);
 }
 
 module_init(ebt_arp_init);
diff --git a/net/bridge/netfilter/ebt_arpreply.c b/net/bridge/netfilter/ebt_arpreply.c
index 0c42795..76584cd 100644
--- a/net/bridge/netfilter/ebt_arpreply.c
+++ b/net/bridge/netfilter/ebt_arpreply.c
@@ -8,18 +8,17 @@
  *  August, 2003
  *
  */
-
-#include <linux/netfilter_bridge/ebtables.h>
-#include <linux/netfilter_bridge/ebt_arpreply.h>
 #include <linux/if_arp.h>
 #include <net/arp.h>
 #include <linux/module.h>
+#include <linux/netfilter/x_tables.h>
+#include <linux/netfilter_bridge/ebtables.h>
+#include <linux/netfilter_bridge/ebt_arpreply.h>
 
-static int ebt_target_reply(struct sk_buff *skb, unsigned int hooknr,
-   const struct net_device *in, const struct net_device *out,
-   const void *data, unsigned int datalen)
+static unsigned int
+ebt_arpreply_tg(struct sk_buff *skb, const struct xt_target_param *par)
 {
-	struct ebt_arpreply_info *info = (void *)data;
+	const struct ebt_arpreply_info *info = par->targinfo;
 	const __be32 *siptr, *diptr;
 	__be32 _sip, _dip;
 	const struct arphdr *ap;
@@ -52,45 +51,45 @@
 	if (diptr == NULL)
 		return EBT_DROP;
 
-	arp_send(ARPOP_REPLY, ETH_P_ARP, *siptr, (struct net_device *)in,
+	arp_send(ARPOP_REPLY, ETH_P_ARP, *siptr, (struct net_device *)par->in,
 		 *diptr, shp, info->mac, shp);
 
 	return info->target;
 }
 
-static int ebt_target_reply_check(const char *tablename, unsigned int hookmask,
-   const struct ebt_entry *e, void *data, unsigned int datalen)
+static bool ebt_arpreply_tg_check(const struct xt_tgchk_param *par)
 {
-	const struct ebt_arpreply_info *info = data;
+	const struct ebt_arpreply_info *info = par->targinfo;
+	const struct ebt_entry *e = par->entryinfo;
 
-	if (datalen != EBT_ALIGN(sizeof(struct ebt_arpreply_info)))
-		return -EINVAL;
 	if (BASE_CHAIN && info->target == EBT_RETURN)
-		return -EINVAL;
+		return false;
 	if (e->ethproto != htons(ETH_P_ARP) ||
 	    e->invflags & EBT_IPROTO)
-		return -EINVAL;
-	CLEAR_BASE_CHAIN_BIT;
-	if (strcmp(tablename, "nat") || hookmask & ~(1 << NF_BR_PRE_ROUTING))
-		return -EINVAL;
-	return 0;
+		return false;
+	return true;
 }
 
-static struct ebt_target reply_target __read_mostly = {
-	.name		= EBT_ARPREPLY_TARGET,
-	.target		= ebt_target_reply,
-	.check		= ebt_target_reply_check,
+static struct xt_target ebt_arpreply_tg_reg __read_mostly = {
+	.name		= "arpreply",
+	.revision	= 0,
+	.family		= NFPROTO_BRIDGE,
+	.table		= "nat",
+	.hooks		= (1 << NF_BR_NUMHOOKS) | (1 << NF_BR_PRE_ROUTING),
+	.target		= ebt_arpreply_tg,
+	.checkentry	= ebt_arpreply_tg_check,
+	.targetsize	= XT_ALIGN(sizeof(struct ebt_arpreply_info)),
 	.me		= THIS_MODULE,
 };
 
 static int __init ebt_arpreply_init(void)
 {
-	return ebt_register_target(&reply_target);
+	return xt_register_target(&ebt_arpreply_tg_reg);
 }
 
 static void __exit ebt_arpreply_fini(void)
 {
-	ebt_unregister_target(&reply_target);
+	xt_unregister_target(&ebt_arpreply_tg_reg);
 }
 
 module_init(ebt_arpreply_init);
diff --git a/net/bridge/netfilter/ebt_dnat.c b/net/bridge/netfilter/ebt_dnat.c
index ca64c1c..6b49ea9 100644
--- a/net/bridge/netfilter/ebt_dnat.c
+++ b/net/bridge/netfilter/ebt_dnat.c
@@ -7,18 +7,17 @@
  *  June, 2002
  *
  */
-
-#include <linux/netfilter.h>
-#include <linux/netfilter_bridge/ebtables.h>
-#include <linux/netfilter_bridge/ebt_nat.h>
 #include <linux/module.h>
 #include <net/sock.h>
+#include <linux/netfilter.h>
+#include <linux/netfilter/x_tables.h>
+#include <linux/netfilter_bridge/ebtables.h>
+#include <linux/netfilter_bridge/ebt_nat.h>
 
-static int ebt_target_dnat(struct sk_buff *skb, unsigned int hooknr,
-   const struct net_device *in, const struct net_device *out,
-   const void *data, unsigned int datalen)
+static unsigned int
+ebt_dnat_tg(struct sk_buff *skb, const struct xt_target_param *par)
 {
-	const struct ebt_nat_info *info = data;
+	const struct ebt_nat_info *info = par->targinfo;
 
 	if (!skb_make_writable(skb, 0))
 		return EBT_DROP;
@@ -27,40 +26,46 @@
 	return info->target;
 }
 
-static int ebt_target_dnat_check(const char *tablename, unsigned int hookmask,
-   const struct ebt_entry *e, void *data, unsigned int datalen)
+static bool ebt_dnat_tg_check(const struct xt_tgchk_param *par)
 {
-	const struct ebt_nat_info *info = data;
+	const struct ebt_nat_info *info = par->targinfo;
+	unsigned int hook_mask;
 
 	if (BASE_CHAIN && info->target == EBT_RETURN)
-		return -EINVAL;
-	CLEAR_BASE_CHAIN_BIT;
-	if ( (strcmp(tablename, "nat") ||
-	   (hookmask & ~((1 << NF_BR_PRE_ROUTING) | (1 << NF_BR_LOCAL_OUT)))) &&
-	   (strcmp(tablename, "broute") || hookmask & ~(1 << NF_BR_BROUTING)) )
-		return -EINVAL;
-	if (datalen != EBT_ALIGN(sizeof(struct ebt_nat_info)))
-		return -EINVAL;
+		return false;
+
+	hook_mask = par->hook_mask & ~(1 << NF_BR_NUMHOOKS);
+	if ((strcmp(par->table, "nat") != 0 ||
+	    (hook_mask & ~((1 << NF_BR_PRE_ROUTING) |
+	    (1 << NF_BR_LOCAL_OUT)))) &&
+	    (strcmp(par->table, "broute") != 0 ||
+	    hook_mask & ~(1 << NF_BR_BROUTING)))
+		return false;
 	if (INVALID_TARGET)
-		return -EINVAL;
-	return 0;
+		return false;
+	return true;
 }
 
-static struct ebt_target dnat __read_mostly = {
-	.name		= EBT_DNAT_TARGET,
-	.target		= ebt_target_dnat,
-	.check		= ebt_target_dnat_check,
+static struct xt_target ebt_dnat_tg_reg __read_mostly = {
+	.name		= "dnat",
+	.revision	= 0,
+	.family		= NFPROTO_BRIDGE,
+	.hooks		= (1 << NF_BR_NUMHOOKS) | (1 << NF_BR_PRE_ROUTING) |
+			  (1 << NF_BR_LOCAL_OUT) | (1 << NF_BR_BROUTING),
+	.target		= ebt_dnat_tg,
+	.checkentry	= ebt_dnat_tg_check,
+	.targetsize	= XT_ALIGN(sizeof(struct ebt_nat_info)),
 	.me		= THIS_MODULE,
 };
 
 static int __init ebt_dnat_init(void)
 {
-	return ebt_register_target(&dnat);
+	return xt_register_target(&ebt_dnat_tg_reg);
 }
 
 static void __exit ebt_dnat_fini(void)
 {
-	ebt_unregister_target(&dnat);
+	xt_unregister_target(&ebt_dnat_tg_reg);
 }
 
 module_init(ebt_dnat_init);
diff --git a/net/bridge/netfilter/ebt_ip.c b/net/bridge/netfilter/ebt_ip.c
index 65caa00..d771bbf 100644
--- a/net/bridge/netfilter/ebt_ip.c
+++ b/net/bridge/netfilter/ebt_ip.c
@@ -11,24 +11,23 @@
  *    Innominate Security Technologies AG <mhopf@innominate.com>
  *    September, 2002
  */
-
-#include <linux/netfilter_bridge/ebtables.h>
-#include <linux/netfilter_bridge/ebt_ip.h>
 #include <linux/ip.h>
 #include <net/ip.h>
 #include <linux/in.h>
 #include <linux/module.h>
+#include <linux/netfilter/x_tables.h>
+#include <linux/netfilter_bridge/ebtables.h>
+#include <linux/netfilter_bridge/ebt_ip.h>
 
 struct tcpudphdr {
 	__be16 src;
 	__be16 dst;
 };
 
-static int ebt_filter_ip(const struct sk_buff *skb, const struct net_device *in,
-   const struct net_device *out, const void *data,
-   unsigned int datalen)
+static bool
+ebt_ip_mt(const struct sk_buff *skb, const struct xt_match_param *par)
 {
-	const struct ebt_ip_info *info = data;
+	const struct ebt_ip_info *info = par->matchinfo;
 	const struct iphdr *ih;
 	struct iphdr _iph;
 	const struct tcpudphdr *pptr;
@@ -36,92 +35,93 @@
 
 	ih = skb_header_pointer(skb, 0, sizeof(_iph), &_iph);
 	if (ih == NULL)
-		return EBT_NOMATCH;
+		return false;
 	if (info->bitmask & EBT_IP_TOS &&
 	   FWINV(info->tos != ih->tos, EBT_IP_TOS))
-		return EBT_NOMATCH;
+		return false;
 	if (info->bitmask & EBT_IP_SOURCE &&
 	   FWINV((ih->saddr & info->smsk) !=
 	   info->saddr, EBT_IP_SOURCE))
-		return EBT_NOMATCH;
+		return false;
 	if ((info->bitmask & EBT_IP_DEST) &&
 	   FWINV((ih->daddr & info->dmsk) !=
 	   info->daddr, EBT_IP_DEST))
-		return EBT_NOMATCH;
+		return false;
 	if (info->bitmask & EBT_IP_PROTO) {
 		if (FWINV(info->protocol != ih->protocol, EBT_IP_PROTO))
-			return EBT_NOMATCH;
+			return false;
 		if (!(info->bitmask & EBT_IP_DPORT) &&
 		    !(info->bitmask & EBT_IP_SPORT))
-			return EBT_MATCH;
+			return true;
 		if (ntohs(ih->frag_off) & IP_OFFSET)
-			return EBT_NOMATCH;
+			return false;
 		pptr = skb_header_pointer(skb, ih->ihl*4,
 					  sizeof(_ports), &_ports);
 		if (pptr == NULL)
-			return EBT_NOMATCH;
+			return false;
 		if (info->bitmask & EBT_IP_DPORT) {
 			u32 dst = ntohs(pptr->dst);
 			if (FWINV(dst < info->dport[0] ||
 				  dst > info->dport[1],
 				  EBT_IP_DPORT))
-			return EBT_NOMATCH;
+			return false;
 		}
 		if (info->bitmask & EBT_IP_SPORT) {
 			u32 src = ntohs(pptr->src);
 			if (FWINV(src < info->sport[0] ||
 				  src > info->sport[1],
 				  EBT_IP_SPORT))
-			return EBT_NOMATCH;
+			return false;
 		}
 	}
-	return EBT_MATCH;
+	return true;
 }
 
-static int ebt_ip_check(const char *tablename, unsigned int hookmask,
-   const struct ebt_entry *e, void *data, unsigned int datalen)
+static bool ebt_ip_mt_check(const struct xt_mtchk_param *par)
 {
-	const struct ebt_ip_info *info = data;
+	const struct ebt_ip_info *info = par->matchinfo;
+	const struct ebt_entry *e = par->entryinfo;
 
-	if (datalen != EBT_ALIGN(sizeof(struct ebt_ip_info)))
-		return -EINVAL;
 	if (e->ethproto != htons(ETH_P_IP) ||
 	   e->invflags & EBT_IPROTO)
-		return -EINVAL;
+		return false;
 	if (info->bitmask & ~EBT_IP_MASK || info->invflags & ~EBT_IP_MASK)
-		return -EINVAL;
+		return false;
 	if (info->bitmask & (EBT_IP_DPORT | EBT_IP_SPORT)) {
 		if (info->invflags & EBT_IP_PROTO)
-			return -EINVAL;
+			return false;
 		if (info->protocol != IPPROTO_TCP &&
 		    info->protocol != IPPROTO_UDP &&
 		    info->protocol != IPPROTO_UDPLITE &&
 		    info->protocol != IPPROTO_SCTP &&
 		    info->protocol != IPPROTO_DCCP)
-			 return -EINVAL;
+			 return false;
 	}
 	if (info->bitmask & EBT_IP_DPORT && info->dport[0] > info->dport[1])
-		return -EINVAL;
+		return false;
 	if (info->bitmask & EBT_IP_SPORT && info->sport[0] > info->sport[1])
-		return -EINVAL;
-	return 0;
+		return false;
+	return true;
 }
 
-static struct ebt_match filter_ip __read_mostly = {
-	.name		= EBT_IP_MATCH,
-	.match		= ebt_filter_ip,
-	.check		= ebt_ip_check,
+static struct xt_match ebt_ip_mt_reg __read_mostly = {
+	.name		= "ip",
+	.revision	= 0,
+	.family		= NFPROTO_BRIDGE,
+	.match		= ebt_ip_mt,
+	.checkentry	= ebt_ip_mt_check,
+	.matchsize	= XT_ALIGN(sizeof(struct ebt_ip_info)),
 	.me		= THIS_MODULE,
 };
 
 static int __init ebt_ip_init(void)
 {
-	return ebt_register_match(&filter_ip);
+	return xt_register_match(&ebt_ip_mt_reg);
 }
 
 static void __exit ebt_ip_fini(void)
 {
-	ebt_unregister_match(&filter_ip);
+	xt_unregister_match(&ebt_ip_mt_reg);
 }
 
 module_init(ebt_ip_init);
diff --git a/net/bridge/netfilter/ebt_ip6.c b/net/bridge/netfilter/ebt_ip6.c
index 36efb3a..784a657 100644
--- a/net/bridge/netfilter/ebt_ip6.c
+++ b/net/bridge/netfilter/ebt_ip6.c
@@ -13,26 +13,24 @@
  *
  *  Jan, 2008
  */
-
-#include <linux/netfilter_bridge/ebtables.h>
-#include <linux/netfilter_bridge/ebt_ip6.h>
 #include <linux/ipv6.h>
 #include <net/ipv6.h>
 #include <linux/in.h>
 #include <linux/module.h>
 #include <net/dsfield.h>
+#include <linux/netfilter/x_tables.h>
+#include <linux/netfilter_bridge/ebtables.h>
+#include <linux/netfilter_bridge/ebt_ip6.h>
 
 struct tcpudphdr {
 	__be16 src;
 	__be16 dst;
 };
 
-static int ebt_filter_ip6(const struct sk_buff *skb,
-   const struct net_device *in,
-   const struct net_device *out, const void *data,
-   unsigned int datalen)
+static bool
+ebt_ip6_mt(const struct sk_buff *skb, const struct xt_match_param *par)
 {
-	const struct ebt_ip6_info *info = (struct ebt_ip6_info *)data;
+	const struct ebt_ip6_info *info = par->matchinfo;
 	const struct ipv6hdr *ih6;
 	struct ipv6hdr _ip6h;
 	const struct tcpudphdr *pptr;
@@ -42,100 +40,100 @@
 
 	ih6 = skb_header_pointer(skb, 0, sizeof(_ip6h), &_ip6h);
 	if (ih6 == NULL)
-		return EBT_NOMATCH;
+		return false;
 	if (info->bitmask & EBT_IP6_TCLASS &&
 	   FWINV(info->tclass != ipv6_get_dsfield(ih6), EBT_IP6_TCLASS))
-		return EBT_NOMATCH;
+		return false;
 	for (i = 0; i < 4; i++)
 		tmp_addr.in6_u.u6_addr32[i] = ih6->saddr.in6_u.u6_addr32[i] &
 			info->smsk.in6_u.u6_addr32[i];
 	if (info->bitmask & EBT_IP6_SOURCE &&
 		FWINV((ipv6_addr_cmp(&tmp_addr, &info->saddr) != 0),
 			EBT_IP6_SOURCE))
-		return EBT_NOMATCH;
+		return false;
 	for (i = 0; i < 4; i++)
 		tmp_addr.in6_u.u6_addr32[i] = ih6->daddr.in6_u.u6_addr32[i] &
 			info->dmsk.in6_u.u6_addr32[i];
 	if (info->bitmask & EBT_IP6_DEST &&
 	   FWINV((ipv6_addr_cmp(&tmp_addr, &info->daddr) != 0), EBT_IP6_DEST))
-		return EBT_NOMATCH;
+		return false;
 	if (info->bitmask & EBT_IP6_PROTO) {
 		uint8_t nexthdr = ih6->nexthdr;
 		int offset_ph;
 
 		offset_ph = ipv6_skip_exthdr(skb, sizeof(_ip6h), &nexthdr);
 		if (offset_ph == -1)
-			return EBT_NOMATCH;
+			return false;
 		if (FWINV(info->protocol != nexthdr, EBT_IP6_PROTO))
-			return EBT_NOMATCH;
+			return false;
 		if (!(info->bitmask & EBT_IP6_DPORT) &&
 		    !(info->bitmask & EBT_IP6_SPORT))
-			return EBT_MATCH;
+			return true;
 		pptr = skb_header_pointer(skb, offset_ph, sizeof(_ports),
 					  &_ports);
 		if (pptr == NULL)
-			return EBT_NOMATCH;
+			return false;
 		if (info->bitmask & EBT_IP6_DPORT) {
 			u32 dst = ntohs(pptr->dst);
 			if (FWINV(dst < info->dport[0] ||
 				  dst > info->dport[1], EBT_IP6_DPORT))
-				return EBT_NOMATCH;
+				return false;
 		}
 		if (info->bitmask & EBT_IP6_SPORT) {
 			u32 src = ntohs(pptr->src);
 			if (FWINV(src < info->sport[0] ||
 				  src > info->sport[1], EBT_IP6_SPORT))
-			return EBT_NOMATCH;
+			return false;
 		}
-		return EBT_MATCH;
+		return true;
 	}
-	return EBT_MATCH;
+	return true;
 }
 
-static int ebt_ip6_check(const char *tablename, unsigned int hookmask,
-   const struct ebt_entry *e, void *data, unsigned int datalen)
+static bool ebt_ip6_mt_check(const struct xt_mtchk_param *par)
 {
-	struct ebt_ip6_info *info = (struct ebt_ip6_info *)data;
+	const struct ebt_entry *e = par->entryinfo;
+	struct ebt_ip6_info *info = par->matchinfo;
 
-	if (datalen != EBT_ALIGN(sizeof(struct ebt_ip6_info)))
-		return -EINVAL;
 	if (e->ethproto != htons(ETH_P_IPV6) || e->invflags & EBT_IPROTO)
-		return -EINVAL;
+		return false;
 	if (info->bitmask & ~EBT_IP6_MASK || info->invflags & ~EBT_IP6_MASK)
-		return -EINVAL;
+		return false;
 	if (info->bitmask & (EBT_IP6_DPORT | EBT_IP6_SPORT)) {
 		if (info->invflags & EBT_IP6_PROTO)
-			return -EINVAL;
+			return false;
 		if (info->protocol != IPPROTO_TCP &&
 		    info->protocol != IPPROTO_UDP &&
 		    info->protocol != IPPROTO_UDPLITE &&
 		    info->protocol != IPPROTO_SCTP &&
 		    info->protocol != IPPROTO_DCCP)
-			 return -EINVAL;
+			return false;
 	}
 	if (info->bitmask & EBT_IP6_DPORT && info->dport[0] > info->dport[1])
-		return -EINVAL;
+		return false;
 	if (info->bitmask & EBT_IP6_SPORT && info->sport[0] > info->sport[1])
-		return -EINVAL;
-	return 0;
+		return false;
+	return true;
 }
 
-static struct ebt_match filter_ip6 =
-{
-	.name		= EBT_IP6_MATCH,
-	.match		= ebt_filter_ip6,
-	.check		= ebt_ip6_check,
+static struct xt_match ebt_ip6_mt_reg __read_mostly = {
+	.name		= "ip6",
+	.revision	= 0,
+	.family		= NFPROTO_BRIDGE,
+	.match		= ebt_ip6_mt,
+	.checkentry	= ebt_ip6_mt_check,
+	.matchsize	= XT_ALIGN(sizeof(struct ebt_ip6_info)),
 	.me		= THIS_MODULE,
 };
 
 static int __init ebt_ip6_init(void)
 {
-	return ebt_register_match(&filter_ip6);
+	return xt_register_match(&ebt_ip6_mt_reg);
 }
 
 static void __exit ebt_ip6_fini(void)
 {
-	ebt_unregister_match(&filter_ip6);
+	xt_unregister_match(&ebt_ip6_mt_reg);
 }
 
 module_init(ebt_ip6_init);
diff --git a/net/bridge/netfilter/ebt_limit.c b/net/bridge/netfilter/ebt_limit.c
index 8cbdc01c..f7bd919 100644
--- a/net/bridge/netfilter/ebt_limit.c
+++ b/net/bridge/netfilter/ebt_limit.c
@@ -10,13 +10,12 @@
  *  September, 2003
  *
  */
-
-#include <linux/netfilter_bridge/ebtables.h>
-#include <linux/netfilter_bridge/ebt_limit.h>
 #include <linux/module.h>
-
 #include <linux/netdevice.h>
 #include <linux/spinlock.h>
+#include <linux/netfilter/x_tables.h>
+#include <linux/netfilter_bridge/ebtables.h>
+#include <linux/netfilter_bridge/ebt_limit.h>
 
 static DEFINE_SPINLOCK(limit_lock);
 
@@ -31,11 +30,10 @@
 
 #define CREDITS_PER_JIFFY POW2_BELOW32(MAX_CPJ)
 
-static int ebt_limit_match(const struct sk_buff *skb,
-   const struct net_device *in, const struct net_device *out,
-   const void *data, unsigned int datalen)
+static bool
+ebt_limit_mt(const struct sk_buff *skb, const struct xt_match_param *par)
 {
-	struct ebt_limit_info *info = (struct ebt_limit_info *)data;
+	struct ebt_limit_info *info = (void *)par->matchinfo;
 	unsigned long now = jiffies;
 
 	spin_lock_bh(&limit_lock);
@@ -47,11 +45,11 @@
 		/* We're not limited. */
 		info->credit -= info->cost;
 		spin_unlock_bh(&limit_lock);
-		return EBT_MATCH;
+		return true;
 	}
 
 	spin_unlock_bh(&limit_lock);
-	return EBT_NOMATCH;
+	return false;
 }
 
 /* Precision saver. */
@@ -66,20 +64,16 @@
 	return (user * HZ * CREDITS_PER_JIFFY) / EBT_LIMIT_SCALE;
 }
 
-static int ebt_limit_check(const char *tablename, unsigned int hookmask,
-   const struct ebt_entry *e, void *data, unsigned int datalen)
+static bool ebt_limit_mt_check(const struct xt_mtchk_param *par)
 {
-	struct ebt_limit_info *info = data;
-
-	if (datalen != EBT_ALIGN(sizeof(struct ebt_limit_info)))
-		return -EINVAL;
+	struct ebt_limit_info *info = par->matchinfo;
 
 	/* Check for overflow. */
 	if (info->burst == 0 ||
 	    user2credits(info->avg * info->burst) < user2credits(info->avg)) {
 		printk("Overflow in ebt_limit, try lower: %u/%u\n",
 			info->avg, info->burst);
-		return -EINVAL;
+		return false;
 	}
 
 	/* User avg in seconds * EBT_LIMIT_SCALE: convert to jiffies * 128. */
@@ -87,24 +81,27 @@
 	info->credit = user2credits(info->avg * info->burst);
 	info->credit_cap = user2credits(info->avg * info->burst);
 	info->cost = user2credits(info->avg);
-	return 0;
+	return true;
 }
 
-static struct ebt_match ebt_limit_reg __read_mostly = {
-	.name		= EBT_LIMIT_MATCH,
-	.match		= ebt_limit_match,
-	.check		= ebt_limit_check,
+static struct xt_match ebt_limit_mt_reg __read_mostly = {
+	.name		= "limit",
+	.revision	= 0,
+	.family		= NFPROTO_BRIDGE,
+	.match		= ebt_limit_mt,
+	.checkentry	= ebt_limit_mt_check,
+	.matchsize	= XT_ALIGN(sizeof(struct ebt_limit_info)),
 	.me		= THIS_MODULE,
 };
 
 static int __init ebt_limit_init(void)
 {
-	return ebt_register_match(&ebt_limit_reg);
+	return xt_register_match(&ebt_limit_mt_reg);
 }
 
 static void __exit ebt_limit_fini(void)
 {
-	ebt_unregister_match(&ebt_limit_reg);
+	xt_unregister_match(&ebt_limit_mt_reg);
 }
 
 module_init(ebt_limit_init);
diff --git a/net/bridge/netfilter/ebt_log.c b/net/bridge/netfilter/ebt_log.c
index 2f430d4..3d33c60 100644
--- a/net/bridge/netfilter/ebt_log.c
+++ b/net/bridge/netfilter/ebt_log.c
@@ -8,10 +8,6 @@
  *  April, 2002
  *
  */
-
-#include <linux/netfilter_bridge/ebtables.h>
-#include <linux/netfilter_bridge/ebt_log.h>
-#include <linux/netfilter.h>
 #include <linux/module.h>
 #include <linux/ip.h>
 #include <linux/in.h>
@@ -21,22 +17,23 @@
 #include <linux/ipv6.h>
 #include <net/ipv6.h>
 #include <linux/in6.h>
+#include <linux/netfilter/x_tables.h>
+#include <linux/netfilter_bridge/ebtables.h>
+#include <linux/netfilter_bridge/ebt_log.h>
+#include <linux/netfilter.h>
 
 static DEFINE_SPINLOCK(ebt_log_lock);
 
-static int ebt_log_check(const char *tablename, unsigned int hookmask,
-   const struct ebt_entry *e, void *data, unsigned int datalen)
+static bool ebt_log_tg_check(const struct xt_tgchk_param *par)
 {
-	struct ebt_log_info *info = data;
+	struct ebt_log_info *info = par->targinfo;
 
-	if (datalen != EBT_ALIGN(sizeof(struct ebt_log_info)))
-		return -EINVAL;
 	if (info->bitmask & ~EBT_LOG_MASK)
-		return -EINVAL;
+		return false;
 	if (info->loglevel >= 8)
-		return -EINVAL;
+		return false;
 	info->prefix[EBT_LOG_PREFIX_SIZE - 1] = '\0';
-	return 0;
+	return true;
 }
 
 struct tcpudphdr
@@ -84,7 +81,7 @@
 
 #define myNIPQUAD(a) a[0], a[1], a[2], a[3]
 static void
-ebt_log_packet(unsigned int pf, unsigned int hooknum,
+ebt_log_packet(u_int8_t pf, unsigned int hooknum,
    const struct sk_buff *skb, const struct net_device *in,
    const struct net_device *out, const struct nf_loginfo *loginfo,
    const char *prefix)
@@ -194,11 +191,10 @@
 
 }
 
-static void ebt_log(const struct sk_buff *skb, unsigned int hooknr,
-   const struct net_device *in, const struct net_device *out,
-   const void *data, unsigned int datalen)
+static unsigned int
+ebt_log_tg(struct sk_buff *skb, const struct xt_target_param *par)
 {
-	const struct ebt_log_info *info = data;
+	const struct ebt_log_info *info = par->targinfo;
 	struct nf_loginfo li;
 
 	li.type = NF_LOG_TYPE_LOG;
@@ -206,18 +202,21 @@
 	li.u.log.logflags = info->bitmask;
 
 	if (info->bitmask & EBT_LOG_NFLOG)
-		nf_log_packet(PF_BRIDGE, hooknr, skb, in, out, &li,
-			      "%s", info->prefix);
+		nf_log_packet(NFPROTO_BRIDGE, par->hooknum, skb, par->in,
+		              par->out, &li, "%s", info->prefix);
 	else
-		ebt_log_packet(PF_BRIDGE, hooknr, skb, in, out, &li,
-			       info->prefix);
+		ebt_log_packet(NFPROTO_BRIDGE, par->hooknum, skb, par->in,
+		               par->out, &li, info->prefix);
+	return EBT_CONTINUE;
 }
 
-static struct ebt_watcher log =
-{
-	.name		= EBT_LOG_WATCHER,
-	.watcher	= ebt_log,
-	.check		= ebt_log_check,
+static struct xt_target ebt_log_tg_reg __read_mostly = {
+	.name		= "log",
+	.revision	= 0,
+	.family		= NFPROTO_BRIDGE,
+	.target		= ebt_log_tg,
+	.checkentry	= ebt_log_tg_check,
+	.targetsize	= XT_ALIGN(sizeof(struct ebt_log_info)),
 	.me		= THIS_MODULE,
 };
 
@@ -231,17 +230,17 @@
 {
 	int ret;
 
-	ret = ebt_register_watcher(&log);
+	ret = xt_register_target(&ebt_log_tg_reg);
 	if (ret < 0)
 		return ret;
-	nf_log_register(PF_BRIDGE, &ebt_log_logger);
+	nf_log_register(NFPROTO_BRIDGE, &ebt_log_logger);
 	return 0;
 }
 
 static void __exit ebt_log_fini(void)
 {
 	nf_log_unregister(&ebt_log_logger);
-	ebt_unregister_watcher(&log);
+	xt_unregister_target(&ebt_log_tg_reg);
 }
 
 module_init(ebt_log_init);
diff --git a/net/bridge/netfilter/ebt_mark.c b/net/bridge/netfilter/ebt_mark.c
index 36723f4..2fee7e8 100644
--- a/net/bridge/netfilter/ebt_mark.c
+++ b/net/bridge/netfilter/ebt_mark.c
@@ -13,15 +13,15 @@
  * Marking a frame doesn't really change anything in the frame anyway.
  */
 
+#include <linux/module.h>
+#include <linux/netfilter/x_tables.h>
 #include <linux/netfilter_bridge/ebtables.h>
 #include <linux/netfilter_bridge/ebt_mark_t.h>
-#include <linux/module.h>
 
-static int ebt_target_mark(struct sk_buff *skb, unsigned int hooknr,
-   const struct net_device *in, const struct net_device *out,
-   const void *data, unsigned int datalen)
+static unsigned int
+ebt_mark_tg(struct sk_buff *skb, const struct xt_target_param *par)
 {
-	const struct ebt_mark_t_info *info = data;
+	const struct ebt_mark_t_info *info = par->targinfo;
 	int action = info->target & -16;
 
 	if (action == MARK_SET_VALUE)
@@ -36,42 +36,41 @@
 	return info->target | ~EBT_VERDICT_BITS;
 }
 
-static int ebt_target_mark_check(const char *tablename, unsigned int hookmask,
-   const struct ebt_entry *e, void *data, unsigned int datalen)
+static bool ebt_mark_tg_check(const struct xt_tgchk_param *par)
 {
-	const struct ebt_mark_t_info *info = data;
+	const struct ebt_mark_t_info *info = par->targinfo;
 	int tmp;
 
-	if (datalen != EBT_ALIGN(sizeof(struct ebt_mark_t_info)))
-		return -EINVAL;
 	tmp = info->target | ~EBT_VERDICT_BITS;
 	if (BASE_CHAIN && tmp == EBT_RETURN)
-		return -EINVAL;
-	CLEAR_BASE_CHAIN_BIT;
+		return false;
 	if (tmp < -NUM_STANDARD_TARGETS || tmp >= 0)
-		return -EINVAL;
+		return false;
 	tmp = info->target & ~EBT_VERDICT_BITS;
 	if (tmp != MARK_SET_VALUE && tmp != MARK_OR_VALUE &&
 	    tmp != MARK_AND_VALUE && tmp != MARK_XOR_VALUE)
-		return -EINVAL;
-	return 0;
+		return false;
+	return true;
 }
 
-static struct ebt_target mark_target __read_mostly = {
-	.name		= EBT_MARK_TARGET,
-	.target		= ebt_target_mark,
-	.check		= ebt_target_mark_check,
+static struct xt_target ebt_mark_tg_reg __read_mostly = {
+	.name		= "mark",
+	.revision	= 0,
+	.family		= NFPROTO_BRIDGE,
+	.target		= ebt_mark_tg,
+	.checkentry	= ebt_mark_tg_check,
+	.targetsize	= XT_ALIGN(sizeof(struct ebt_mark_t_info)),
 	.me		= THIS_MODULE,
 };
 
 static int __init ebt_mark_init(void)
 {
-	return ebt_register_target(&mark_target);
+	return xt_register_target(&ebt_mark_tg_reg);
 }
 
 static void __exit ebt_mark_fini(void)
 {
-	ebt_unregister_target(&mark_target);
+	xt_unregister_target(&ebt_mark_tg_reg);
 }
 
 module_init(ebt_mark_init);
diff --git a/net/bridge/netfilter/ebt_mark_m.c b/net/bridge/netfilter/ebt_mark_m.c
index 9b0a454..ea570f2 100644
--- a/net/bridge/netfilter/ebt_mark_m.c
+++ b/net/bridge/netfilter/ebt_mark_m.c
@@ -7,53 +7,52 @@
  *  July, 2002
  *
  */
-
+#include <linux/module.h>
+#include <linux/netfilter/x_tables.h>
 #include <linux/netfilter_bridge/ebtables.h>
 #include <linux/netfilter_bridge/ebt_mark_m.h>
-#include <linux/module.h>
 
-static int ebt_filter_mark(const struct sk_buff *skb,
-   const struct net_device *in, const struct net_device *out, const void *data,
-   unsigned int datalen)
+static bool
+ebt_mark_mt(const struct sk_buff *skb, const struct xt_match_param *par)
 {
-	const struct ebt_mark_m_info *info = data;
+	const struct ebt_mark_m_info *info = par->matchinfo;
 
 	if (info->bitmask & EBT_MARK_OR)
-		return !(!!(skb->mark & info->mask) ^ info->invert);
-	return !(((skb->mark & info->mask) == info->mark) ^ info->invert);
+		return !!(skb->mark & info->mask) ^ info->invert;
+	return ((skb->mark & info->mask) == info->mark) ^ info->invert;
 }
 
-static int ebt_mark_check(const char *tablename, unsigned int hookmask,
-   const struct ebt_entry *e, void *data, unsigned int datalen)
+static bool ebt_mark_mt_check(const struct xt_mtchk_param *par)
 {
-	const struct ebt_mark_m_info *info = data;
+	const struct ebt_mark_m_info *info = par->matchinfo;
 
-	if (datalen != EBT_ALIGN(sizeof(struct ebt_mark_m_info)))
-		return -EINVAL;
 	if (info->bitmask & ~EBT_MARK_MASK)
-		return -EINVAL;
+		return false;
 	if ((info->bitmask & EBT_MARK_OR) && (info->bitmask & EBT_MARK_AND))
-		return -EINVAL;
+		return false;
 	if (!info->bitmask)
-		return -EINVAL;
-	return 0;
+		return false;
+	return true;
 }
 
-static struct ebt_match filter_mark __read_mostly = {
-	.name		= EBT_MARK_MATCH,
-	.match		= ebt_filter_mark,
-	.check		= ebt_mark_check,
+static struct xt_match ebt_mark_mt_reg __read_mostly = {
+	.name		= "mark_m",
+	.revision	= 0,
+	.family		= NFPROTO_BRIDGE,
+	.match		= ebt_mark_mt,
+	.checkentry	= ebt_mark_mt_check,
+	.matchsize	= XT_ALIGN(sizeof(struct ebt_mark_m_info)),
 	.me		= THIS_MODULE,
 };
 
 static int __init ebt_mark_m_init(void)
 {
-	return ebt_register_match(&filter_mark);
+	return xt_register_match(&ebt_mark_mt_reg);
 }
 
 static void __exit ebt_mark_m_fini(void)
 {
-	ebt_unregister_match(&filter_mark);
+	xt_unregister_match(&ebt_mark_mt_reg);
 }
 
 module_init(ebt_mark_m_init);
diff --git a/net/bridge/netfilter/ebt_nflog.c b/net/bridge/netfilter/ebt_nflog.c
index 8e799aa..2a63d996 100644
--- a/net/bridge/netfilter/ebt_nflog.c
+++ b/net/bridge/netfilter/ebt_nflog.c
@@ -14,17 +14,15 @@
 
 #include <linux/module.h>
 #include <linux/spinlock.h>
+#include <linux/netfilter/x_tables.h>
 #include <linux/netfilter_bridge/ebtables.h>
 #include <linux/netfilter_bridge/ebt_nflog.h>
 #include <net/netfilter/nf_log.h>
 
-static void ebt_nflog(const struct sk_buff *skb,
-		      unsigned int hooknr,
-		      const struct net_device *in,
-		      const struct net_device *out,
-		      const void *data, unsigned int datalen)
+static unsigned int
+ebt_nflog_tg(struct sk_buff *skb, const struct xt_target_param *par)
 {
-	struct ebt_nflog_info *info = (struct ebt_nflog_info *)data;
+	const struct ebt_nflog_info *info = par->targinfo;
 	struct nf_loginfo li;
 
 	li.type = NF_LOG_TYPE_ULOG;
@@ -32,39 +30,39 @@
 	li.u.ulog.group = info->group;
 	li.u.ulog.qthreshold = info->threshold;
 
-	nf_log_packet(PF_BRIDGE, hooknr, skb, in, out, &li, "%s", info->prefix);
+	nf_log_packet(PF_BRIDGE, par->hooknum, skb, par->in, par->out,
+	              &li, "%s", info->prefix);
+	return EBT_CONTINUE;
 }
 
-static int ebt_nflog_check(const char *tablename,
-			   unsigned int hookmask,
-			   const struct ebt_entry *e,
-			   void *data, unsigned int datalen)
+static bool ebt_nflog_tg_check(const struct xt_tgchk_param *par)
 {
-	struct ebt_nflog_info *info = (struct ebt_nflog_info *)data;
+	struct ebt_nflog_info *info = par->targinfo;
 
-	if (datalen != EBT_ALIGN(sizeof(struct ebt_nflog_info)))
-		return -EINVAL;
 	if (info->flags & ~EBT_NFLOG_MASK)
-		return -EINVAL;
+		return false;
 	info->prefix[EBT_NFLOG_PREFIX_SIZE - 1] = '\0';
-	return 0;
+	return true;
 }
 
-static struct ebt_watcher nflog __read_mostly = {
-	.name = EBT_NFLOG_WATCHER,
-	.watcher = ebt_nflog,
-	.check = ebt_nflog_check,
-	.me = THIS_MODULE,
+static struct xt_target ebt_nflog_tg_reg __read_mostly = {
+	.name       = "nflog",
+	.revision   = 0,
+	.family     = NFPROTO_BRIDGE,
+	.target     = ebt_nflog_tg,
+	.checkentry = ebt_nflog_tg_check,
+	.targetsize = XT_ALIGN(sizeof(struct ebt_nflog_info)),
+	.me         = THIS_MODULE,
 };
 
 static int __init ebt_nflog_init(void)
 {
-	return ebt_register_watcher(&nflog);
+	return xt_register_target(&ebt_nflog_tg_reg);
 }
 
 static void __exit ebt_nflog_fini(void)
 {
-	ebt_unregister_watcher(&nflog);
+	xt_unregister_target(&ebt_nflog_tg_reg);
 }
 
 module_init(ebt_nflog_init);
diff --git a/net/bridge/netfilter/ebt_pkttype.c b/net/bridge/netfilter/ebt_pkttype.c
index 676db32..883e96e 100644
--- a/net/bridge/netfilter/ebt_pkttype.c
+++ b/net/bridge/netfilter/ebt_pkttype.c
@@ -7,50 +7,47 @@
  *  April, 2003
  *
  */
-
+#include <linux/module.h>
+#include <linux/netfilter/x_tables.h>
 #include <linux/netfilter_bridge/ebtables.h>
 #include <linux/netfilter_bridge/ebt_pkttype.h>
-#include <linux/module.h>
 
-static int ebt_filter_pkttype(const struct sk_buff *skb,
-   const struct net_device *in,
-   const struct net_device *out,
-   const void *data,
-   unsigned int datalen)
+static bool
+ebt_pkttype_mt(const struct sk_buff *skb, const struct xt_match_param *par)
 {
-	const struct ebt_pkttype_info *info = data;
+	const struct ebt_pkttype_info *info = par->matchinfo;
 
-	return (skb->pkt_type != info->pkt_type) ^ info->invert;
+	return (skb->pkt_type == info->pkt_type) ^ info->invert;
 }
 
-static int ebt_pkttype_check(const char *tablename, unsigned int hookmask,
-   const struct ebt_entry *e, void *data, unsigned int datalen)
+static bool ebt_pkttype_mt_check(const struct xt_mtchk_param *par)
 {
-	const struct ebt_pkttype_info *info = data;
+	const struct ebt_pkttype_info *info = par->matchinfo;
 
-	if (datalen != EBT_ALIGN(sizeof(struct ebt_pkttype_info)))
-		return -EINVAL;
 	if (info->invert != 0 && info->invert != 1)
-		return -EINVAL;
+		return false;
 	/* Allow any pkt_type value */
-	return 0;
+	return true;
 }
 
-static struct ebt_match filter_pkttype __read_mostly = {
-	.name		= EBT_PKTTYPE_MATCH,
-	.match		= ebt_filter_pkttype,
-	.check		= ebt_pkttype_check,
+static struct xt_match ebt_pkttype_mt_reg __read_mostly = {
+	.name		= "pkttype",
+	.revision	= 0,
+	.family		= NFPROTO_BRIDGE,
+	.match		= ebt_pkttype_mt,
+	.checkentry	= ebt_pkttype_mt_check,
+	.matchsize	= XT_ALIGN(sizeof(struct ebt_pkttype_info)),
 	.me		= THIS_MODULE,
 };
 
 static int __init ebt_pkttype_init(void)
 {
-	return ebt_register_match(&filter_pkttype);
+	return xt_register_match(&ebt_pkttype_mt_reg);
 }
 
 static void __exit ebt_pkttype_fini(void)
 {
-	ebt_unregister_match(&filter_pkttype);
+	xt_unregister_match(&ebt_pkttype_mt_reg);
 }
 
 module_init(ebt_pkttype_init);
diff --git a/net/bridge/netfilter/ebt_redirect.c b/net/bridge/netfilter/ebt_redirect.c
index b8afe85..c8a49f7 100644
--- a/net/bridge/netfilter/ebt_redirect.c
+++ b/net/bridge/netfilter/ebt_redirect.c
@@ -7,65 +7,70 @@
  *  April, 2002
  *
  */
-
-#include <linux/netfilter.h>
-#include <linux/netfilter_bridge/ebtables.h>
-#include <linux/netfilter_bridge/ebt_redirect.h>
 #include <linux/module.h>
 #include <net/sock.h>
 #include "../br_private.h"
+#include <linux/netfilter.h>
+#include <linux/netfilter/x_tables.h>
+#include <linux/netfilter_bridge/ebtables.h>
+#include <linux/netfilter_bridge/ebt_redirect.h>
 
-static int ebt_target_redirect(struct sk_buff *skb, unsigned int hooknr,
-   const struct net_device *in, const struct net_device *out,
-   const void *data, unsigned int datalen)
+static unsigned int
+ebt_redirect_tg(struct sk_buff *skb, const struct xt_target_param *par)
 {
-	const struct ebt_redirect_info *info = data;
+	const struct ebt_redirect_info *info = par->targinfo;
 
 	if (!skb_make_writable(skb, 0))
 		return EBT_DROP;
 
-	if (hooknr != NF_BR_BROUTING)
+	if (par->hooknum != NF_BR_BROUTING)
 		memcpy(eth_hdr(skb)->h_dest,
-		       in->br_port->br->dev->dev_addr, ETH_ALEN);
+		       par->in->br_port->br->dev->dev_addr, ETH_ALEN);
 	else
-		memcpy(eth_hdr(skb)->h_dest, in->dev_addr, ETH_ALEN);
+		memcpy(eth_hdr(skb)->h_dest, par->in->dev_addr, ETH_ALEN);
 	skb->pkt_type = PACKET_HOST;
 	return info->target;
 }
 
-static int ebt_target_redirect_check(const char *tablename, unsigned int hookmask,
-   const struct ebt_entry *e, void *data, unsigned int datalen)
+static bool ebt_redirect_tg_check(const struct xt_tgchk_param *par)
 {
-	const struct ebt_redirect_info *info = data;
+	const struct ebt_redirect_info *info = par->targinfo;
+	unsigned int hook_mask;
 
-	if (datalen != EBT_ALIGN(sizeof(struct ebt_redirect_info)))
-		return -EINVAL;
 	if (BASE_CHAIN && info->target == EBT_RETURN)
-		return -EINVAL;
-	CLEAR_BASE_CHAIN_BIT;
-	if ( (strcmp(tablename, "nat") || hookmask & ~(1 << NF_BR_PRE_ROUTING)) &&
-	     (strcmp(tablename, "broute") || hookmask & ~(1 << NF_BR_BROUTING)) )
-		return -EINVAL;
+		return false;
+
+	hook_mask = par->hook_mask & ~(1 << NF_BR_NUMHOOKS);
+	if ((strcmp(par->table, "nat") != 0 ||
+	    hook_mask & ~(1 << NF_BR_PRE_ROUTING)) &&
+	    (strcmp(par->table, "broute") != 0 ||
+	    hook_mask & ~(1 << NF_BR_BROUTING)))
+		return false;
 	if (INVALID_TARGET)
-		return -EINVAL;
-	return 0;
+		return false;
+	return true;
 }
 
-static struct ebt_target redirect_target __read_mostly = {
-	.name		= EBT_REDIRECT_TARGET,
-	.target		= ebt_target_redirect,
-	.check		= ebt_target_redirect_check,
+static struct xt_target ebt_redirect_tg_reg __read_mostly = {
+	.name		= "redirect",
+	.revision	= 0,
+	.family		= NFPROTO_BRIDGE,
+	.hooks		= (1 << NF_BR_NUMHOOKS) | (1 << NF_BR_PRE_ROUTING) |
+			  (1 << NF_BR_BROUTING),
+	.target		= ebt_redirect_tg,
+	.checkentry	= ebt_redirect_tg_check,
+	.targetsize	= XT_ALIGN(sizeof(struct ebt_redirect_info)),
 	.me		= THIS_MODULE,
 };
 
 static int __init ebt_redirect_init(void)
 {
-	return ebt_register_target(&redirect_target);
+	return xt_register_target(&ebt_redirect_tg_reg);
 }
 
 static void __exit ebt_redirect_fini(void)
 {
-	ebt_unregister_target(&redirect_target);
+	xt_unregister_target(&ebt_redirect_tg_reg);
 }
 
 module_init(ebt_redirect_init);
diff --git a/net/bridge/netfilter/ebt_snat.c b/net/bridge/netfilter/ebt_snat.c
index 5425333..8d04d4c 100644
--- a/net/bridge/netfilter/ebt_snat.c
+++ b/net/bridge/netfilter/ebt_snat.c
@@ -7,20 +7,19 @@
  *  June, 2002
  *
  */
-
-#include <linux/netfilter.h>
-#include <linux/netfilter_bridge/ebtables.h>
-#include <linux/netfilter_bridge/ebt_nat.h>
 #include <linux/module.h>
 #include <net/sock.h>
 #include <linux/if_arp.h>
 #include <net/arp.h>
+#include <linux/netfilter.h>
+#include <linux/netfilter/x_tables.h>
+#include <linux/netfilter_bridge/ebtables.h>
+#include <linux/netfilter_bridge/ebt_nat.h>
 
-static int ebt_target_snat(struct sk_buff *skb, unsigned int hooknr,
-   const struct net_device *in, const struct net_device *out,
-   const void *data, unsigned int datalen)
+static unsigned int
+ebt_snat_tg(struct sk_buff *skb, const struct xt_target_param *par)
 {
-	const struct ebt_nat_info *info = data;
+	const struct ebt_nat_info *info = par->targinfo;
 
 	if (!skb_make_writable(skb, 0))
 		return EBT_DROP;
@@ -43,46 +42,43 @@
 	return info->target | ~EBT_VERDICT_BITS;
 }
 
-static int ebt_target_snat_check(const char *tablename, unsigned int hookmask,
-   const struct ebt_entry *e, void *data, unsigned int datalen)
+static bool ebt_snat_tg_check(const struct xt_tgchk_param *par)
 {
-	const struct ebt_nat_info *info = data;
+	const struct ebt_nat_info *info = par->targinfo;
 	int tmp;
 
-	if (datalen != EBT_ALIGN(sizeof(struct ebt_nat_info)))
-		return -EINVAL;
 	tmp = info->target | ~EBT_VERDICT_BITS;
 	if (BASE_CHAIN && tmp == EBT_RETURN)
-		return -EINVAL;
-	CLEAR_BASE_CHAIN_BIT;
-	if (strcmp(tablename, "nat"))
-		return -EINVAL;
-	if (hookmask & ~(1 << NF_BR_POST_ROUTING))
-		return -EINVAL;
+		return false;
 
 	if (tmp < -NUM_STANDARD_TARGETS || tmp >= 0)
-		return -EINVAL;
+		return false;
 	tmp = info->target | EBT_VERDICT_BITS;
 	if ((tmp & ~NAT_ARP_BIT) != ~NAT_ARP_BIT)
-		return -EINVAL;
-	return 0;
+		return false;
+	return true;
 }
 
-static struct ebt_target snat __read_mostly = {
-	.name		= EBT_SNAT_TARGET,
-	.target		= ebt_target_snat,
-	.check		= ebt_target_snat_check,
+static struct xt_target ebt_snat_tg_reg __read_mostly = {
+	.name		= "snat",
+	.revision	= 0,
+	.family		= NFPROTO_BRIDGE,
+	.table		= "nat",
+	.hooks		= (1 << NF_BR_NUMHOOKS) | (1 << NF_BR_POST_ROUTING),
+	.target		= ebt_snat_tg,
+	.checkentry	= ebt_snat_tg_check,
+	.targetsize	= XT_ALIGN(sizeof(struct ebt_nat_info)),
 	.me		= THIS_MODULE,
 };
 
 static int __init ebt_snat_init(void)
 {
-	return ebt_register_target(&snat);
+	return xt_register_target(&ebt_snat_tg_reg);
 }
 
 static void __exit ebt_snat_fini(void)
 {
-	ebt_unregister_target(&snat);
+	xt_unregister_target(&ebt_snat_tg_reg);
 }
 
 module_init(ebt_snat_init);
diff --git a/net/bridge/netfilter/ebt_stp.c b/net/bridge/netfilter/ebt_stp.c
index 40f36d3..48527e6 100644
--- a/net/bridge/netfilter/ebt_stp.c
+++ b/net/bridge/netfilter/ebt_stp.c
@@ -7,11 +7,11 @@
  *
  *  July, 2003
  */
-
-#include <linux/netfilter_bridge/ebtables.h>
-#include <linux/netfilter_bridge/ebt_stp.h>
 #include <linux/etherdevice.h>
 #include <linux/module.h>
+#include <linux/netfilter/x_tables.h>
+#include <linux/netfilter_bridge/ebtables.h>
+#include <linux/netfilter_bridge/ebt_stp.h>
 
 #define BPDU_TYPE_CONFIG 0
 #define BPDU_TYPE_TCN 0x80
@@ -40,7 +40,7 @@
 #define NR16(p) (p[0] << 8 | p[1])
 #define NR32(p) ((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3])
 
-static int ebt_filter_config(const struct ebt_stp_info *info,
+static bool ebt_filter_config(const struct ebt_stp_info *info,
    const struct stp_config_pdu *stpc)
 {
 	const struct ebt_stp_config_info *c;
@@ -51,12 +51,12 @@
 	c = &info->config;
 	if ((info->bitmask & EBT_STP_FLAGS) &&
 	    FWINV(c->flags != stpc->flags, EBT_STP_FLAGS))
-		return EBT_NOMATCH;
+		return false;
 	if (info->bitmask & EBT_STP_ROOTPRIO) {
 		v16 = NR16(stpc->root);
 		if (FWINV(v16 < c->root_priol ||
 		    v16 > c->root_priou, EBT_STP_ROOTPRIO))
-			return EBT_NOMATCH;
+			return false;
 	}
 	if (info->bitmask & EBT_STP_ROOTADDR) {
 		verdict = 0;
@@ -64,19 +64,19 @@
 			verdict |= (stpc->root[2+i] ^ c->root_addr[i]) &
 				   c->root_addrmsk[i];
 		if (FWINV(verdict != 0, EBT_STP_ROOTADDR))
-			return EBT_NOMATCH;
+			return false;
 	}
 	if (info->bitmask & EBT_STP_ROOTCOST) {
 		v32 = NR32(stpc->root_cost);
 		if (FWINV(v32 < c->root_costl ||
 		    v32 > c->root_costu, EBT_STP_ROOTCOST))
-			return EBT_NOMATCH;
+			return false;
 	}
 	if (info->bitmask & EBT_STP_SENDERPRIO) {
 		v16 = NR16(stpc->sender);
 		if (FWINV(v16 < c->sender_priol ||
 		    v16 > c->sender_priou, EBT_STP_SENDERPRIO))
-			return EBT_NOMATCH;
+			return false;
 	}
 	if (info->bitmask & EBT_STP_SENDERADDR) {
 		verdict = 0;
@@ -84,60 +84,60 @@
 			verdict |= (stpc->sender[2+i] ^ c->sender_addr[i]) &
 				   c->sender_addrmsk[i];
 		if (FWINV(verdict != 0, EBT_STP_SENDERADDR))
-			return EBT_NOMATCH;
+			return false;
 	}
 	if (info->bitmask & EBT_STP_PORT) {
 		v16 = NR16(stpc->port);
 		if (FWINV(v16 < c->portl ||
 		    v16 > c->portu, EBT_STP_PORT))
-			return EBT_NOMATCH;
+			return false;
 	}
 	if (info->bitmask & EBT_STP_MSGAGE) {
 		v16 = NR16(stpc->msg_age);
 		if (FWINV(v16 < c->msg_agel ||
 		    v16 > c->msg_ageu, EBT_STP_MSGAGE))
-			return EBT_NOMATCH;
+			return false;
 	}
 	if (info->bitmask & EBT_STP_MAXAGE) {
 		v16 = NR16(stpc->max_age);
 		if (FWINV(v16 < c->max_agel ||
 		    v16 > c->max_ageu, EBT_STP_MAXAGE))
-			return EBT_NOMATCH;
+			return false;
 	}
 	if (info->bitmask & EBT_STP_HELLOTIME) {
 		v16 = NR16(stpc->hello_time);
 		if (FWINV(v16 < c->hello_timel ||
 		    v16 > c->hello_timeu, EBT_STP_HELLOTIME))
-			return EBT_NOMATCH;
+			return false;
 	}
 	if (info->bitmask & EBT_STP_FWDD) {
 		v16 = NR16(stpc->forward_delay);
 		if (FWINV(v16 < c->forward_delayl ||
 		    v16 > c->forward_delayu, EBT_STP_FWDD))
-			return EBT_NOMATCH;
+			return false;
 	}
-	return EBT_MATCH;
+	return true;
 }
 
-static int ebt_filter_stp(const struct sk_buff *skb, const struct net_device *in,
-   const struct net_device *out, const void *data, unsigned int datalen)
+static bool
+ebt_stp_mt(const struct sk_buff *skb, const struct xt_match_param *par)
 {
-	const struct ebt_stp_info *info = data;
+	const struct ebt_stp_info *info = par->matchinfo;
 	const struct stp_header *sp;
 	struct stp_header _stph;
 	const uint8_t header[6] = {0x42, 0x42, 0x03, 0x00, 0x00, 0x00};
 
 	sp = skb_header_pointer(skb, 0, sizeof(_stph), &_stph);
 	if (sp == NULL)
-		return EBT_NOMATCH;
+		return false;
 
 	/* The stp code only considers these */
 	if (memcmp(sp, header, sizeof(header)))
-		return EBT_NOMATCH;
+		return false;
 
 	if (info->bitmask & EBT_STP_TYPE
 	    && FWINV(info->type != sp->type, EBT_STP_TYPE))
-		return EBT_NOMATCH;
+		return false;
 
 	if (sp->type == BPDU_TYPE_CONFIG &&
 	    info->bitmask & EBT_STP_CONFIG_MASK) {
@@ -147,48 +147,48 @@
 		st = skb_header_pointer(skb, sizeof(_stph),
 					sizeof(_stpc), &_stpc);
 		if (st == NULL)
-			return EBT_NOMATCH;
+			return false;
 		return ebt_filter_config(info, st);
 	}
-	return EBT_MATCH;
+	return true;
 }
 
-static int ebt_stp_check(const char *tablename, unsigned int hookmask,
-   const struct ebt_entry *e, void *data, unsigned int datalen)
+static bool ebt_stp_mt_check(const struct xt_mtchk_param *par)
 {
-	const struct ebt_stp_info *info = data;
-	const unsigned int len = EBT_ALIGN(sizeof(struct ebt_stp_info));
+	const struct ebt_stp_info *info = par->matchinfo;
 	const uint8_t bridge_ula[6] = {0x01, 0x80, 0xc2, 0x00, 0x00, 0x00};
 	const uint8_t msk[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+	const struct ebt_entry *e = par->entryinfo;
 
 	if (info->bitmask & ~EBT_STP_MASK || info->invflags & ~EBT_STP_MASK ||
 	    !(info->bitmask & EBT_STP_MASK))
-		return -EINVAL;
-	if (datalen != len)
-		return -EINVAL;
+		return false;
 	/* Make sure the match only receives stp frames */
 	if (compare_ether_addr(e->destmac, bridge_ula) ||
 	    compare_ether_addr(e->destmsk, msk) || !(e->bitmask & EBT_DESTMAC))
-		return -EINVAL;
+		return false;
 
-	return 0;
+	return true;
 }
 
-static struct ebt_match filter_stp __read_mostly = {
-	.name		= EBT_STP_MATCH,
-	.match		= ebt_filter_stp,
-	.check		= ebt_stp_check,
+static struct xt_match ebt_stp_mt_reg __read_mostly = {
+	.name		= "stp",
+	.revision	= 0,
+	.family		= NFPROTO_BRIDGE,
+	.match		= ebt_stp_mt,
+	.checkentry	= ebt_stp_mt_check,
+	.matchsize	= XT_ALIGN(sizeof(struct ebt_stp_info)),
 	.me		= THIS_MODULE,
 };
 
 static int __init ebt_stp_init(void)
 {
-	return ebt_register_match(&filter_stp);
+	return xt_register_match(&ebt_stp_mt_reg);
 }
 
 static void __exit ebt_stp_fini(void)
 {
-	ebt_unregister_match(&filter_stp);
+	xt_unregister_match(&ebt_stp_mt_reg);
 }
 
 module_init(ebt_stp_init);
diff --git a/net/bridge/netfilter/ebt_ulog.c b/net/bridge/netfilter/ebt_ulog.c
index 2d4c9ef..2c6d682 100644
--- a/net/bridge/netfilter/ebt_ulog.c
+++ b/net/bridge/netfilter/ebt_ulog.c
@@ -36,6 +36,7 @@
 #include <linux/timer.h>
 #include <linux/netlink.h>
 #include <linux/netdevice.h>
+#include <linux/netfilter/x_tables.h>
 #include <linux/netfilter_bridge/ebtables.h>
 #include <linux/netfilter_bridge/ebt_ulog.h>
 #include <net/netfilter/nf_log.h>
@@ -223,7 +224,7 @@
 }
 
 /* this function is registered with the netfilter core */
-static void ebt_log_packet(unsigned int pf, unsigned int hooknum,
+static void ebt_log_packet(u_int8_t pf, unsigned int hooknum,
    const struct sk_buff *skb, const struct net_device *in,
    const struct net_device *out, const struct nf_loginfo *li,
    const char *prefix)
@@ -245,24 +246,20 @@
 	ebt_ulog_packet(hooknum, skb, in, out, &loginfo, prefix);
 }
 
-static void ebt_ulog(const struct sk_buff *skb, unsigned int hooknr,
-   const struct net_device *in, const struct net_device *out,
-   const void *data, unsigned int datalen)
+static unsigned int
+ebt_ulog_tg(struct sk_buff *skb, const struct xt_target_param *par)
 {
-	const struct ebt_ulog_info *uloginfo = data;
-
-	ebt_ulog_packet(hooknr, skb, in, out, uloginfo, NULL);
+	ebt_ulog_packet(par->hooknum, skb, par->in, par->out,
+	                par->targinfo, NULL);
+	return EBT_CONTINUE;
 }
 
-
-static int ebt_ulog_check(const char *tablename, unsigned int hookmask,
-   const struct ebt_entry *e, void *data, unsigned int datalen)
+static bool ebt_ulog_tg_check(const struct xt_tgchk_param *par)
 {
-	struct ebt_ulog_info *uloginfo = data;
+	struct ebt_ulog_info *uloginfo = par->targinfo;
 
-	if (datalen != EBT_ALIGN(sizeof(struct ebt_ulog_info)) ||
-	    uloginfo->nlgroup > 31)
-		return -EINVAL;
+	if (uloginfo->nlgroup > 31)
+		return false;
 
 	uloginfo->prefix[EBT_ULOG_PREFIX_LEN - 1] = '\0';
 
@@ -272,27 +269,31 @@
 	return 0;
 }
 
-static struct ebt_watcher ulog __read_mostly = {
-	.name		= EBT_ULOG_WATCHER,
-	.watcher	= ebt_ulog,
-	.check		= ebt_ulog_check,
+static struct xt_target ebt_ulog_tg_reg __read_mostly = {
+	.name		= "ulog",
+	.revision	= 0,
+	.family		= NFPROTO_BRIDGE,
+	.target		= ebt_ulog_tg,
+	.checkentry	= ebt_ulog_tg_check,
+	.targetsize	= XT_ALIGN(sizeof(struct ebt_ulog_info)),
 	.me		= THIS_MODULE,
 };
 
 static const struct nf_logger ebt_ulog_logger = {
-	.name		= EBT_ULOG_WATCHER,
+	.name		= "ulog",
 	.logfn		= &ebt_log_packet,
 	.me		= THIS_MODULE,
 };
 
 static int __init ebt_ulog_init(void)
 {
-	int i, ret = 0;
+	bool ret = true;
+	int i;
 
 	if (nlbufsiz >= 128*1024) {
 		printk(KERN_NOTICE "ebt_ulog: Netlink buffer has to be <= 128kB,"
 		       " please try a smaller nlbufsiz parameter.\n");
-		return -EINVAL;
+		return false;
 	}
 
 	/* initialize ulog_buffers */
@@ -304,13 +305,16 @@
 	ebtulognl = netlink_kernel_create(&init_net, NETLINK_NFLOG,
 					  EBT_ULOG_MAXNLGROUPS, NULL, NULL,
 					  THIS_MODULE);
-	if (!ebtulognl)
-		ret = -ENOMEM;
-	else if ((ret = ebt_register_watcher(&ulog)))
+	if (!ebtulognl) {
+		printk(KERN_WARNING KBUILD_MODNAME ": out of memory trying to "
+		       "call netlink_kernel_create\n");
+		ret = false;
+	} else if (xt_register_target(&ebt_ulog_tg_reg) != 0) {
 		netlink_kernel_release(ebtulognl);
+	}
 
-	if (ret == 0)
-		nf_log_register(PF_BRIDGE, &ebt_ulog_logger);
+	if (ret)
+		nf_log_register(NFPROTO_BRIDGE, &ebt_ulog_logger);
 
 	return ret;
 }
@@ -321,7 +325,7 @@
 	int i;
 
 	nf_log_unregister(&ebt_ulog_logger);
-	ebt_unregister_watcher(&ulog);
+	xt_unregister_target(&ebt_ulog_tg_reg);
 	for (i = 0; i < EBT_ULOG_MAXNLGROUPS; i++) {
 		ub = &ulog_buffers[i];
 		if (timer_pending(&ub->timer))
diff --git a/net/bridge/netfilter/ebt_vlan.c b/net/bridge/netfilter/ebt_vlan.c
index ab60b0d..3dddd48 100644
--- a/net/bridge/netfilter/ebt_vlan.c
+++ b/net/bridge/netfilter/ebt_vlan.c
@@ -22,6 +22,7 @@
 #include <linux/if_vlan.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
+#include <linux/netfilter/x_tables.h>
 #include <linux/netfilter_bridge/ebtables.h>
 #include <linux/netfilter_bridge/ebt_vlan.h>
 
@@ -37,15 +38,12 @@
 
 #define DEBUG_MSG(args...) if (debug) printk (KERN_DEBUG "ebt_vlan: " args)
 #define GET_BITMASK(_BIT_MASK_) info->bitmask & _BIT_MASK_
-#define EXIT_ON_MISMATCH(_MATCH_,_MASK_) {if (!((info->_MATCH_ == _MATCH_)^!!(info->invflags & _MASK_))) return EBT_NOMATCH;}
+#define EXIT_ON_MISMATCH(_MATCH_,_MASK_) {if (!((info->_MATCH_ == _MATCH_)^!!(info->invflags & _MASK_))) return false; }
 
-static int
-ebt_filter_vlan(const struct sk_buff *skb,
-		const struct net_device *in,
-		const struct net_device *out,
-		const void *data, unsigned int datalen)
+static bool
+ebt_vlan_mt(const struct sk_buff *skb, const struct xt_match_param *par)
 {
-	const struct ebt_vlan_info *info = data;
+	const struct ebt_vlan_info *info = par->matchinfo;
 	const struct vlan_hdr *fp;
 	struct vlan_hdr _frame;
 
@@ -57,7 +55,7 @@
 
 	fp = skb_header_pointer(skb, 0, sizeof(_frame), &_frame);
 	if (fp == NULL)
-		return EBT_NOMATCH;
+		return false;
 
 	/* Tag Control Information (TCI) consists of the following elements:
 	 * - User_priority. The user_priority field is three bits in length,
@@ -83,30 +81,20 @@
 	if (GET_BITMASK(EBT_VLAN_ENCAP))
 		EXIT_ON_MISMATCH(encap, EBT_VLAN_ENCAP);
 
-	return EBT_MATCH;
+	return true;
 }
 
-static int
-ebt_check_vlan(const char *tablename,
-	       unsigned int hooknr,
-	       const struct ebt_entry *e, void *data, unsigned int datalen)
+static bool ebt_vlan_mt_check(const struct xt_mtchk_param *par)
 {
-	struct ebt_vlan_info *info = data;
-
-	/* Parameters buffer overflow check */
-	if (datalen != EBT_ALIGN(sizeof(struct ebt_vlan_info))) {
-		DEBUG_MSG
-		    ("passed size %d is not eq to ebt_vlan_info (%Zd)\n",
-		     datalen, sizeof(struct ebt_vlan_info));
-		return -EINVAL;
-	}
+	struct ebt_vlan_info *info = par->matchinfo;
+	const struct ebt_entry *e = par->entryinfo;
 
 	/* Is it 802.1Q frame checked? */
 	if (e->ethproto != htons(ETH_P_8021Q)) {
 		DEBUG_MSG
 		    ("passed entry proto %2.4X is not 802.1Q (8100)\n",
 		     (unsigned short) ntohs(e->ethproto));
-		return -EINVAL;
+		return false;
 	}
 
 	/* Check for bitmask range
@@ -114,14 +102,14 @@
 	if (info->bitmask & ~EBT_VLAN_MASK) {
 		DEBUG_MSG("bitmask %2X is out of mask (%2X)\n",
 			  info->bitmask, EBT_VLAN_MASK);
-		return -EINVAL;
+		return false;
 	}
 
 	/* Check for inversion flags range */
 	if (info->invflags & ~EBT_VLAN_MASK) {
 		DEBUG_MSG("inversion flags %2X is out of mask (%2X)\n",
 			  info->invflags, EBT_VLAN_MASK);
-		return -EINVAL;
+		return false;
 	}
 
 	/* Reserved VLAN ID (VID) values
@@ -136,7 +124,7 @@
 				DEBUG_MSG
 				    ("id %d is out of range (1-4096)\n",
 				     info->id);
-				return -EINVAL;
+				return false;
 			}
 			/* Note: This is valid VLAN-tagged frame point.
 			 * Any value of user_priority are acceptable,
@@ -151,7 +139,7 @@
 		if ((unsigned char) info->prio > 7) {
 			DEBUG_MSG("prio %d is out of range (0-7)\n",
 			     info->prio);
-			return -EINVAL;
+			return false;
 		}
 	}
 	/* Check for encapsulated proto range - it is possible to be
@@ -162,17 +150,20 @@
 			DEBUG_MSG
 			    ("encap frame length %d is less than minimal\n",
 			     ntohs(info->encap));
-			return -EINVAL;
+			return false;
 		}
 	}
 
-	return 0;
+	return true;
 }
 
-static struct ebt_match filter_vlan __read_mostly = {
-	.name		= EBT_VLAN_MATCH,
-	.match		= ebt_filter_vlan,
-	.check		= ebt_check_vlan,
+static struct xt_match ebt_vlan_mt_reg __read_mostly = {
+	.name		= "vlan",
+	.revision	= 0,
+	.family		= NFPROTO_BRIDGE,
+	.match		= ebt_vlan_mt,
+	.checkentry	= ebt_vlan_mt_check,
+	.matchsize	= XT_ALIGN(sizeof(struct ebt_vlan_info)),
 	.me		= THIS_MODULE,
 };
 
@@ -181,12 +172,12 @@
 	DEBUG_MSG("ebtables 802.1Q extension module v"
 		  MODULE_VERS "\n");
 	DEBUG_MSG("module debug=%d\n", !!debug);
-	return ebt_register_match(&filter_vlan);
+	return xt_register_match(&ebt_vlan_mt_reg);
 }
 
 static void __exit ebt_vlan_fini(void)
 {
-	ebt_unregister_match(&filter_vlan);
+	xt_unregister_match(&ebt_vlan_mt_reg);
 }
 
 module_init(ebt_vlan_init);
diff --git a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c
index 32afff8..5bb88eb 100644
--- a/net/bridge/netfilter/ebtables.c
+++ b/net/bridge/netfilter/ebtables.c
@@ -19,6 +19,7 @@
 #include <linux/kmod.h>
 #include <linux/module.h>
 #include <linux/vmalloc.h>
+#include <linux/netfilter/x_tables.h>
 #include <linux/netfilter_bridge/ebtables.h>
 #include <linux/spinlock.h>
 #include <linux/mutex.h>
@@ -55,29 +56,31 @@
 
 static DEFINE_MUTEX(ebt_mutex);
 static LIST_HEAD(ebt_tables);
-static LIST_HEAD(ebt_targets);
-static LIST_HEAD(ebt_matches);
-static LIST_HEAD(ebt_watchers);
 
-static struct ebt_target ebt_standard_target =
-{ {NULL, NULL}, EBT_STANDARD_TARGET, NULL, NULL, NULL, NULL};
+static struct xt_target ebt_standard_target = {
+	.name       = "standard",
+	.revision   = 0,
+	.family     = NFPROTO_BRIDGE,
+	.targetsize = sizeof(int),
+};
 
-static inline int ebt_do_watcher (struct ebt_entry_watcher *w,
-   const struct sk_buff *skb, unsigned int hooknr, const struct net_device *in,
-   const struct net_device *out)
+static inline int
+ebt_do_watcher(const struct ebt_entry_watcher *w, struct sk_buff *skb,
+	       struct xt_target_param *par)
 {
-	w->u.watcher->watcher(skb, hooknr, in, out, w->data,
-	   w->watcher_size);
+	par->target   = w->u.watcher;
+	par->targinfo = w->data;
+	w->u.watcher->target(skb, par);
 	/* watchers don't give a verdict */
 	return 0;
 }
 
 static inline int ebt_do_match (struct ebt_entry_match *m,
-   const struct sk_buff *skb, const struct net_device *in,
-   const struct net_device *out)
+   const struct sk_buff *skb, struct xt_match_param *par)
 {
-	return m->u.match->match(skb, in, out, m->data,
-	   m->match_size);
+	par->match     = m->u.match;
+	par->matchinfo = m->data;
+	return m->u.match->match(skb, par);
 }
 
 static inline int ebt_dev_check(char *entry, const struct net_device *device)
@@ -153,6 +156,15 @@
 	struct ebt_entries *chaininfo;
 	char *base;
 	struct ebt_table_info *private;
+	bool hotdrop = false;
+	struct xt_match_param mtpar;
+	struct xt_target_param tgpar;
+
+	mtpar.family  = tgpar.family = NFPROTO_BRIDGE;
+	mtpar.in      = tgpar.in  = in;
+	mtpar.out     = tgpar.out = out;
+	mtpar.hotdrop = &hotdrop;
+	tgpar.hooknum = hook;
 
 	read_lock_bh(&table->lock);
 	private = table->private;
@@ -173,8 +185,12 @@
 		if (ebt_basic_match(point, eth_hdr(skb), in, out))
 			goto letscontinue;
 
-		if (EBT_MATCH_ITERATE(point, ebt_do_match, skb, in, out) != 0)
+		if (EBT_MATCH_ITERATE(point, ebt_do_match, skb, &mtpar) != 0)
 			goto letscontinue;
+		if (hotdrop) {
+			read_unlock_bh(&table->lock);
+			return NF_DROP;
+		}
 
 		/* increase counter */
 		(*(counter_base + i)).pcnt++;
@@ -182,17 +198,18 @@
 
 		/* these should only watch: not modify, nor tell us
 		   what to do with the packet */
-		EBT_WATCHER_ITERATE(point, ebt_do_watcher, skb, hook, in,
-		   out);
+		EBT_WATCHER_ITERATE(point, ebt_do_watcher, skb, &tgpar);
 
 		t = (struct ebt_entry_target *)
 		   (((char *)point) + point->target_offset);
 		/* standard target */
 		if (!t->u.target->target)
 			verdict = ((struct ebt_standard_target *)t)->verdict;
-		else
-			verdict = t->u.target->target(skb, hook,
-			   in, out, t->data, t->target_size);
+		else {
+			tgpar.target   = t->u.target;
+			tgpar.targinfo = t->data;
+			verdict = t->u.target->target(skb, &tgpar);
+		}
 		if (verdict == EBT_ACCEPT) {
 			read_unlock_bh(&table->lock);
 			return NF_ACCEPT;
@@ -312,80 +329,71 @@
 	return find_inlist_lock(&ebt_tables, name, "ebtable_", error, mutex);
 }
 
-static inline struct ebt_match *
-find_match_lock(const char *name, int *error, struct mutex *mutex)
-{
-	return find_inlist_lock(&ebt_matches, name, "ebt_", error, mutex);
-}
-
-static inline struct ebt_watcher *
-find_watcher_lock(const char *name, int *error, struct mutex *mutex)
-{
-	return find_inlist_lock(&ebt_watchers, name, "ebt_", error, mutex);
-}
-
-static inline struct ebt_target *
-find_target_lock(const char *name, int *error, struct mutex *mutex)
-{
-	return find_inlist_lock(&ebt_targets, name, "ebt_", error, mutex);
-}
-
 static inline int
-ebt_check_match(struct ebt_entry_match *m, struct ebt_entry *e,
-   const char *name, unsigned int hookmask, unsigned int *cnt)
+ebt_check_match(struct ebt_entry_match *m, struct xt_mtchk_param *par,
+		unsigned int *cnt)
 {
-	struct ebt_match *match;
+	const struct ebt_entry *e = par->entryinfo;
+	struct xt_match *match;
 	size_t left = ((char *)e + e->watchers_offset) - (char *)m;
 	int ret;
 
 	if (left < sizeof(struct ebt_entry_match) ||
 	    left - sizeof(struct ebt_entry_match) < m->match_size)
 		return -EINVAL;
-	match = find_match_lock(m->u.name, &ret, &ebt_mutex);
-	if (!match)
-		return ret;
-	m->u.match = match;
-	if (!try_module_get(match->me)) {
-		mutex_unlock(&ebt_mutex);
+
+	match = try_then_request_module(xt_find_match(NFPROTO_BRIDGE,
+		m->u.name, 0), "ebt_%s", m->u.name);
+	if (IS_ERR(match))
+		return PTR_ERR(match);
+	if (match == NULL)
 		return -ENOENT;
-	}
-	mutex_unlock(&ebt_mutex);
-	if (match->check &&
-	   match->check(name, hookmask, e, m->data, m->match_size) != 0) {
-		BUGPRINT("match->check failed\n");
+	m->u.match = match;
+
+	par->match     = match;
+	par->matchinfo = m->data;
+	ret = xt_check_match(par, m->match_size,
+	      e->ethproto, e->invflags & EBT_IPROTO);
+	if (ret < 0) {
 		module_put(match->me);
-		return -EINVAL;
+		return ret;
 	}
+
 	(*cnt)++;
 	return 0;
 }
 
 static inline int
-ebt_check_watcher(struct ebt_entry_watcher *w, struct ebt_entry *e,
-   const char *name, unsigned int hookmask, unsigned int *cnt)
+ebt_check_watcher(struct ebt_entry_watcher *w, struct xt_tgchk_param *par,
+		  unsigned int *cnt)
 {
-	struct ebt_watcher *watcher;
+	const struct ebt_entry *e = par->entryinfo;
+	struct xt_target *watcher;
 	size_t left = ((char *)e + e->target_offset) - (char *)w;
 	int ret;
 
 	if (left < sizeof(struct ebt_entry_watcher) ||
 	   left - sizeof(struct ebt_entry_watcher) < w->watcher_size)
 		return -EINVAL;
-	watcher = find_watcher_lock(w->u.name, &ret, &ebt_mutex);
-	if (!watcher)
-		return ret;
-	w->u.watcher = watcher;
-	if (!try_module_get(watcher->me)) {
-		mutex_unlock(&ebt_mutex);
+
+	watcher = try_then_request_module(
+		  xt_find_target(NFPROTO_BRIDGE, w->u.name, 0),
+		  "ebt_%s", w->u.name);
+	if (IS_ERR(watcher))
+		return PTR_ERR(watcher);
+	if (watcher == NULL)
 		return -ENOENT;
-	}
-	mutex_unlock(&ebt_mutex);
-	if (watcher->check &&
-	   watcher->check(name, hookmask, e, w->data, w->watcher_size) != 0) {
-		BUGPRINT("watcher->check failed\n");
+	w->u.watcher = watcher;
+
+	par->target   = watcher;
+	par->targinfo = w->data;
+	ret = xt_check_target(par, w->watcher_size,
+	      e->ethproto, e->invflags & EBT_IPROTO);
+	if (ret < 0) {
 		module_put(watcher->me);
-		return -EINVAL;
+		return ret;
 	}
+
 	(*cnt)++;
 	return 0;
 }
@@ -558,30 +566,41 @@
 static inline int
 ebt_cleanup_match(struct ebt_entry_match *m, unsigned int *i)
 {
+	struct xt_mtdtor_param par;
+
 	if (i && (*i)-- == 0)
 		return 1;
-	if (m->u.match->destroy)
-		m->u.match->destroy(m->data, m->match_size);
-	module_put(m->u.match->me);
 
+	par.match     = m->u.match;
+	par.matchinfo = m->data;
+	par.family    = NFPROTO_BRIDGE;
+	if (par.match->destroy != NULL)
+		par.match->destroy(&par);
+	module_put(par.match->me);
 	return 0;
 }
 
 static inline int
 ebt_cleanup_watcher(struct ebt_entry_watcher *w, unsigned int *i)
 {
+	struct xt_tgdtor_param par;
+
 	if (i && (*i)-- == 0)
 		return 1;
-	if (w->u.watcher->destroy)
-		w->u.watcher->destroy(w->data, w->watcher_size);
-	module_put(w->u.watcher->me);
 
+	par.target   = w->u.watcher;
+	par.targinfo = w->data;
+	par.family   = NFPROTO_BRIDGE;
+	if (par.target->destroy != NULL)
+		par.target->destroy(&par);
+	module_put(par.target->me);
 	return 0;
 }
 
 static inline int
 ebt_cleanup_entry(struct ebt_entry *e, unsigned int *cnt)
 {
+	struct xt_tgdtor_param par;
 	struct ebt_entry_target *t;
 
 	if (e->bitmask == 0)
@@ -592,10 +611,13 @@
 	EBT_WATCHER_ITERATE(e, ebt_cleanup_watcher, NULL);
 	EBT_MATCH_ITERATE(e, ebt_cleanup_match, NULL);
 	t = (struct ebt_entry_target *)(((char *)e) + e->target_offset);
-	if (t->u.target->destroy)
-		t->u.target->destroy(t->data, t->target_size);
-	module_put(t->u.target->me);
 
+	par.target   = t->u.target;
+	par.targinfo = t->data;
+	par.family   = NFPROTO_BRIDGE;
+	if (par.target->destroy != NULL)
+		par.target->destroy(&par);
+	module_put(par.target->me);
 	return 0;
 }
 
@@ -605,10 +627,12 @@
    struct ebt_cl_stack *cl_s, unsigned int udc_cnt)
 {
 	struct ebt_entry_target *t;
-	struct ebt_target *target;
+	struct xt_target *target;
 	unsigned int i, j, hook = 0, hookmask = 0;
 	size_t gap;
 	int ret;
+	struct xt_mtchk_param mtpar;
+	struct xt_tgchk_param tgpar;
 
 	/* don't mess with the struct ebt_entries */
 	if (e->bitmask == 0)
@@ -649,24 +673,31 @@
 			hookmask = cl_s[i - 1].hookmask;
 	}
 	i = 0;
-	ret = EBT_MATCH_ITERATE(e, ebt_check_match, e, name, hookmask, &i);
+
+	mtpar.table     = tgpar.table     = name;
+	mtpar.entryinfo = tgpar.entryinfo = e;
+	mtpar.hook_mask = tgpar.hook_mask = hookmask;
+	mtpar.family    = tgpar.family    = NFPROTO_BRIDGE;
+	ret = EBT_MATCH_ITERATE(e, ebt_check_match, &mtpar, &i);
 	if (ret != 0)
 		goto cleanup_matches;
 	j = 0;
-	ret = EBT_WATCHER_ITERATE(e, ebt_check_watcher, e, name, hookmask, &j);
+	ret = EBT_WATCHER_ITERATE(e, ebt_check_watcher, &tgpar, &j);
 	if (ret != 0)
 		goto cleanup_watchers;
 	t = (struct ebt_entry_target *)(((char *)e) + e->target_offset);
 	gap = e->next_offset - e->target_offset;
-	target = find_target_lock(t->u.name, &ret, &ebt_mutex);
-	if (!target)
+
+	target = try_then_request_module(
+		 xt_find_target(NFPROTO_BRIDGE, t->u.name, 0),
+		 "ebt_%s", t->u.name);
+	if (IS_ERR(target)) {
+		ret = PTR_ERR(target);
 		goto cleanup_watchers;
-	if (!try_module_get(target->me)) {
-		mutex_unlock(&ebt_mutex);
+	} else if (target == NULL) {
 		ret = -ENOENT;
 		goto cleanup_watchers;
 	}
-	mutex_unlock(&ebt_mutex);
 
 	t->u.target = target;
 	if (t->u.target == &ebt_standard_target) {
@@ -681,13 +712,20 @@
 			ret = -EFAULT;
 			goto cleanup_watchers;
 		}
-	} else if (t->target_size > gap - sizeof(struct ebt_entry_target) ||
-	   (t->u.target->check &&
-	   t->u.target->check(name, hookmask, e, t->data, t->target_size) != 0)){
+	} else if (t->target_size > gap - sizeof(struct ebt_entry_target)) {
 		module_put(t->u.target->me);
 		ret = -EFAULT;
 		goto cleanup_watchers;
 	}
+
+	tgpar.target   = target;
+	tgpar.targinfo = t->data;
+	ret = xt_check_target(&tgpar, t->target_size,
+	      e->ethproto, e->invflags & EBT_IPROTO);
+	if (ret < 0) {
+		module_put(target->me);
+		goto cleanup_watchers;
+	}
 	(*cnt)++;
 	return 0;
 cleanup_watchers:
@@ -1068,87 +1106,6 @@
 	return ret;
 }
 
-int ebt_register_target(struct ebt_target *target)
-{
-	struct ebt_target *t;
-	int ret;
-
-	ret = mutex_lock_interruptible(&ebt_mutex);
-	if (ret != 0)
-		return ret;
-	list_for_each_entry(t, &ebt_targets, list) {
-		if (strcmp(t->name, target->name) == 0) {
-			mutex_unlock(&ebt_mutex);
-			return -EEXIST;
-		}
-	}
-	list_add(&target->list, &ebt_targets);
-	mutex_unlock(&ebt_mutex);
-
-	return 0;
-}
-
-void ebt_unregister_target(struct ebt_target *target)
-{
-	mutex_lock(&ebt_mutex);
-	list_del(&target->list);
-	mutex_unlock(&ebt_mutex);
-}
-
-int ebt_register_match(struct ebt_match *match)
-{
-	struct ebt_match *m;
-	int ret;
-
-	ret = mutex_lock_interruptible(&ebt_mutex);
-	if (ret != 0)
-		return ret;
-	list_for_each_entry(m, &ebt_matches, list) {
-		if (strcmp(m->name, match->name) == 0) {
-			mutex_unlock(&ebt_mutex);
-			return -EEXIST;
-		}
-	}
-	list_add(&match->list, &ebt_matches);
-	mutex_unlock(&ebt_mutex);
-
-	return 0;
-}
-
-void ebt_unregister_match(struct ebt_match *match)
-{
-	mutex_lock(&ebt_mutex);
-	list_del(&match->list);
-	mutex_unlock(&ebt_mutex);
-}
-
-int ebt_register_watcher(struct ebt_watcher *watcher)
-{
-	struct ebt_watcher *w;
-	int ret;
-
-	ret = mutex_lock_interruptible(&ebt_mutex);
-	if (ret != 0)
-		return ret;
-	list_for_each_entry(w, &ebt_watchers, list) {
-		if (strcmp(w->name, watcher->name) == 0) {
-			mutex_unlock(&ebt_mutex);
-			return -EEXIST;
-		}
-	}
-	list_add(&watcher->list, &ebt_watchers);
-	mutex_unlock(&ebt_mutex);
-
-	return 0;
-}
-
-void ebt_unregister_watcher(struct ebt_watcher *watcher)
-{
-	mutex_lock(&ebt_mutex);
-	list_del(&watcher->list);
-	mutex_unlock(&ebt_mutex);
-}
-
 int ebt_register_table(struct ebt_table *table)
 {
 	struct ebt_table_info *newinfo;
@@ -1518,11 +1475,14 @@
 {
 	int ret;
 
-	mutex_lock(&ebt_mutex);
-	list_add(&ebt_standard_target.list, &ebt_targets);
-	mutex_unlock(&ebt_mutex);
-	if ((ret = nf_register_sockopt(&ebt_sockopts)) < 0)
+	ret = xt_register_target(&ebt_standard_target);
+	if (ret < 0)
 		return ret;
+	ret = nf_register_sockopt(&ebt_sockopts);
+	if (ret < 0) {
+		xt_unregister_target(&ebt_standard_target);
+		return ret;
+	}
 
 	printk(KERN_INFO "Ebtables v2.0 registered\n");
 	return 0;
@@ -1531,17 +1491,12 @@
 static void __exit ebtables_fini(void)
 {
 	nf_unregister_sockopt(&ebt_sockopts);
+	xt_unregister_target(&ebt_standard_target);
 	printk(KERN_INFO "Ebtables v2.0 unregistered\n");
 }
 
 EXPORT_SYMBOL(ebt_register_table);
 EXPORT_SYMBOL(ebt_unregister_table);
-EXPORT_SYMBOL(ebt_register_match);
-EXPORT_SYMBOL(ebt_unregister_match);
-EXPORT_SYMBOL(ebt_register_watcher);
-EXPORT_SYMBOL(ebt_unregister_watcher);
-EXPORT_SYMBOL(ebt_register_target);
-EXPORT_SYMBOL(ebt_unregister_target);
 EXPORT_SYMBOL(ebt_do_table);
 module_init(ebtables_init);
 module_exit(ebtables_fini);
diff --git a/net/core/Makefile b/net/core/Makefile
index b1332f6..26a37cb 100644
--- a/net/core/Makefile
+++ b/net/core/Makefile
@@ -6,6 +6,7 @@
 	 gen_stats.o gen_estimator.o net_namespace.o
 
 obj-$(CONFIG_SYSCTL) += sysctl_net_core.o
+obj-$(CONFIG_HAS_DMA) += skb_dma_map.o
 
 obj-y		     += dev.o ethtool.o dev_mcast.o dst.o netevent.o \
 			neighbour.o rtnetlink.o utils.o link_watch.o filter.o
diff --git a/net/core/datagram.c b/net/core/datagram.c
index 52f577a..ee63184 100644
--- a/net/core/datagram.c
+++ b/net/core/datagram.c
@@ -9,7 +9,7 @@
  *	identical recvmsg() code. So we share it here. The poll was
  *	shared before but buried in udp.c so I moved it.
  *
- *	Authors:	Alan Cox <alan@redhat.com>. (datagram_poll() from old
+ *	Authors:	Alan Cox <alan@lxorguk.ukuu.org.uk>. (datagram_poll() from old
  *						     udp.c code)
  *
  *	Fixes:
diff --git a/net/core/dev.c b/net/core/dev.c
index e719ed2..1408a083 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -122,6 +122,7 @@
 #include <linux/if_arp.h>
 #include <linux/if_vlan.h>
 #include <linux/ip.h>
+#include <net/ip.h>
 #include <linux/ipv6.h>
 #include <linux/in.h>
 #include <linux/jhash.h>
@@ -890,7 +891,7 @@
  *	Change name of a device, can pass format strings "eth%d".
  *	for wildcarding.
  */
-int dev_change_name(struct net_device *dev, char *newname)
+int dev_change_name(struct net_device *dev, const char *newname)
 {
 	char oldname[IFNAMSIZ];
 	int err = 0;
@@ -916,7 +917,6 @@
 		err = dev_alloc_name(dev, newname);
 		if (err < 0)
 			return err;
-		strcpy(newname, dev->name);
 	}
 	else if (__dev_get_by_name(net, newname))
 		return -EEXIST;
@@ -954,6 +954,38 @@
 }
 
 /**
+ *	dev_set_alias - change ifalias of a device
+ *	@dev: device
+ *	@alias: name up to IFALIASZ
+ *	@len: limit of bytes to copy from info
+ *
+ *	Set ifalias for a device,
+ */
+int dev_set_alias(struct net_device *dev, const char *alias, size_t len)
+{
+	ASSERT_RTNL();
+
+	if (len >= IFALIASZ)
+		return -EINVAL;
+
+	if (!len) {
+		if (dev->ifalias) {
+			kfree(dev->ifalias);
+			dev->ifalias = NULL;
+		}
+		return 0;
+	}
+
+	dev->ifalias = krealloc(dev->ifalias, len+1, GFP_KERNEL);
+	if (!dev->ifalias)
+		return -ENOMEM;
+
+	strlcpy(dev->ifalias, alias, len+1);
+	return len;
+}
+
+
+/**
  *	netdev_features_change - device changes features
  *	@dev: device to cause notification
  *
@@ -1667,7 +1699,7 @@
 {
 	u32 addr1, addr2, ports;
 	u32 hash, ihl;
-	u8 ip_proto;
+	u8 ip_proto = 0;
 
 	if (unlikely(!simple_tx_hashrnd_initialized)) {
 		get_random_bytes(&simple_tx_hashrnd, 4);
@@ -1675,13 +1707,14 @@
 	}
 
 	switch (skb->protocol) {
-	case __constant_htons(ETH_P_IP):
-		ip_proto = ip_hdr(skb)->protocol;
+	case htons(ETH_P_IP):
+		if (!(ip_hdr(skb)->frag_off & htons(IP_MF | IP_OFFSET)))
+			ip_proto = ip_hdr(skb)->protocol;
 		addr1 = ip_hdr(skb)->saddr;
 		addr2 = ip_hdr(skb)->daddr;
 		ihl = ip_hdr(skb)->ihl;
 		break;
-	case __constant_htons(ETH_P_IPV6):
+	case htons(ETH_P_IPV6):
 		ip_proto = ipv6_hdr(skb)->nexthdr;
 		addr1 = ipv6_hdr(skb)->saddr.s6_addr32[3];
 		addr2 = ipv6_hdr(skb)->daddr.s6_addr32[3];
@@ -2916,6 +2949,12 @@
 	return 0;
 }
 
+static void dev_change_rx_flags(struct net_device *dev, int flags)
+{
+	if (dev->flags & IFF_UP && dev->change_rx_flags)
+		dev->change_rx_flags(dev, flags);
+}
+
 static int __dev_set_promiscuity(struct net_device *dev, int inc)
 {
 	unsigned short old_flags = dev->flags;
@@ -2953,8 +2992,7 @@
 				current->uid, current->gid,
 				audit_get_sessionid(current));
 
-		if (dev->change_rx_flags)
-			dev->change_rx_flags(dev, IFF_PROMISC);
+		dev_change_rx_flags(dev, IFF_PROMISC);
 	}
 	return 0;
 }
@@ -3020,8 +3058,7 @@
 		}
 	}
 	if (dev->flags ^ old_flags) {
-		if (dev->change_rx_flags)
-			dev->change_rx_flags(dev, IFF_ALLMULTI);
+		dev_change_rx_flags(dev, IFF_ALLMULTI);
 		dev_set_rx_mode(dev);
 	}
 	return 0;
@@ -3300,6 +3337,12 @@
 	netif_addr_unlock_bh(dev);
 }
 
+/**
+ *	dev_get_flags - get flags reported to userspace
+ *	@dev: device
+ *
+ *	Get the combination of flag bits exported through APIs to userspace.
+ */
 unsigned dev_get_flags(const struct net_device *dev)
 {
 	unsigned flags;
@@ -3324,6 +3367,14 @@
 	return flags;
 }
 
+/**
+ *	dev_change_flags - change device settings
+ *	@dev: device
+ *	@flags: device state flags
+ *
+ *	Change settings on device based state flags. The flags are
+ *	in the userspace exported format.
+ */
 int dev_change_flags(struct net_device *dev, unsigned flags)
 {
 	int ret, changes;
@@ -3345,8 +3396,8 @@
 	 *	Load in the correct multicast list now the flags have changed.
 	 */
 
-	if (dev->change_rx_flags && (old_flags ^ flags) & IFF_MULTICAST)
-		dev->change_rx_flags(dev, IFF_MULTICAST);
+	if ((old_flags ^ flags) & IFF_MULTICAST)
+		dev_change_rx_flags(dev, IFF_MULTICAST);
 
 	dev_set_rx_mode(dev);
 
@@ -3393,6 +3444,13 @@
 	return ret;
 }
 
+/**
+ *	dev_set_mtu - Change maximum transfer unit
+ *	@dev: device
+ *	@new_mtu: new transfer unit
+ *
+ *	Change the maximum transfer size of the network device.
+ */
 int dev_set_mtu(struct net_device *dev, int new_mtu)
 {
 	int err;
@@ -3417,6 +3475,13 @@
 	return err;
 }
 
+/**
+ *	dev_set_mac_address - Change Media Access Control Address
+ *	@dev: device
+ *	@sa: new address
+ *
+ *	Change the hardware (MAC) address of the device
+ */
 int dev_set_mac_address(struct net_device *dev, struct sockaddr *sa)
 {
 	int err;
@@ -3806,14 +3871,11 @@
 }
 
 /* Delayed registration/unregisteration */
-static DEFINE_SPINLOCK(net_todo_list_lock);
 static LIST_HEAD(net_todo_list);
 
 static void net_set_todo(struct net_device *dev)
 {
-	spin_lock(&net_todo_list_lock);
 	list_add_tail(&dev->todo_list, &net_todo_list);
-	spin_unlock(&net_todo_list_lock);
 }
 
 static void rollback_registered(struct net_device *dev)
@@ -4140,33 +4202,24 @@
  *	free_netdev(y1);
  *	free_netdev(y2);
  *
- * We are invoked by rtnl_unlock() after it drops the semaphore.
+ * We are invoked by rtnl_unlock().
  * This allows us to deal with problems:
  * 1) We can delete sysfs objects which invoke hotplug
  *    without deadlocking with linkwatch via keventd.
  * 2) Since we run with the RTNL semaphore not held, we can sleep
  *    safely in order to wait for the netdev refcnt to drop to zero.
+ *
+ * We must not return until all unregister events added during
+ * the interval the lock was held have been completed.
  */
-static DEFINE_MUTEX(net_todo_run_mutex);
 void netdev_run_todo(void)
 {
 	struct list_head list;
 
-	/* Need to guard against multiple cpu's getting out of order. */
-	mutex_lock(&net_todo_run_mutex);
-
-	/* Not safe to do outside the semaphore.  We must not return
-	 * until all unregister events invoked by the local processor
-	 * have been completed (either by this todo run, or one on
-	 * another cpu).
-	 */
-	if (list_empty(&net_todo_list))
-		goto out;
-
 	/* Snapshot list, allow later requests */
-	spin_lock(&net_todo_list_lock);
 	list_replace_init(&net_todo_list, &list);
-	spin_unlock(&net_todo_list_lock);
+
+	__rtnl_unlock();
 
 	while (!list_empty(&list)) {
 		struct net_device *dev
@@ -4198,9 +4251,6 @@
 		/* Free network device */
 		kobject_put(&dev->dev.kobj);
 	}
-
-out:
-	mutex_unlock(&net_todo_run_mutex);
 }
 
 static struct net_device_stats *internal_stats(struct net_device *dev)
@@ -4320,7 +4370,12 @@
 	put_device(&dev->dev);
 }
 
-/* Synchronize with packet receive processing. */
+/**
+ *	synchronize_net -  Synchronize with packet receive processing
+ *
+ *	Wait for packets currently being received to be done.
+ *	Does not block later packets from starting.
+ */
 void synchronize_net(void)
 {
 	might_sleep();
@@ -4622,7 +4677,7 @@
 }
 
 /**
- * netdev_dma_regiser - register the networking subsystem as a DMA client
+ * netdev_dma_register - register the networking subsystem as a DMA client
  */
 static int __init netdev_dma_register(void)
 {
@@ -4668,6 +4723,12 @@
 		one |= NETIF_F_GSO_SOFTWARE;
 	one |= NETIF_F_GSO;
 
+	/*
+	 * If even one device supports a GSO protocol with software fallback,
+	 * enable it for all.
+	 */
+	all |= one & NETIF_F_GSO_SOFTWARE;
+
 	/* If even one device supports robust GSO, enable it for all. */
 	if (one & NETIF_F_GSO_ROBUST)
 		all |= NETIF_F_GSO_ROBUST;
@@ -4717,10 +4778,18 @@
 	return -ENOMEM;
 }
 
-char *netdev_drivername(struct net_device *dev, char *buffer, int len)
+/**
+ *	netdev_drivername - network driver for the device
+ *	@dev: network device
+ *	@buffer: buffer for resulting name
+ *	@len: size of buffer
+ *
+ *	Determine network driver for device.
+ */
+char *netdev_drivername(const struct net_device *dev, char *buffer, int len)
 {
-	struct device_driver *driver;
-	struct device *parent;
+	const struct device_driver *driver;
+	const struct device *parent;
 
 	if (len <= 0 || !buffer)
 		return buffer;
diff --git a/net/core/dev_mcast.c b/net/core/dev_mcast.c
index 5402b3b..9e2fa39 100644
--- a/net/core/dev_mcast.c
+++ b/net/core/dev_mcast.c
@@ -6,7 +6,7 @@
  *		Richard Underwood <richard@wuzz.demon.co.uk>
  *
  *	Stir fried together from the IP multicast and CAP patches above
- *		Alan Cox <Alan.Cox@linux.org>
+ *		Alan Cox <alan@lxorguk.ukuu.org.uk>
  *
  *	Fixes:
  *		Alan Cox	:	Update the device on a real delete
diff --git a/net/core/dst.c b/net/core/dst.c
index fe03266..09c1530 100644
--- a/net/core/dst.c
+++ b/net/core/dst.c
@@ -203,6 +203,7 @@
 	if (dst_garbage.timer_inc > DST_GC_INC) {
 		dst_garbage.timer_inc = DST_GC_INC;
 		dst_garbage.timer_expires = DST_GC_MIN;
+		cancel_delayed_work(&dst_gc_work);
 		schedule_delayed_work(&dst_gc_work, dst_garbage.timer_expires);
 	}
 	spin_unlock_bh(&dst_garbage.lock);
diff --git a/net/core/neighbour.c b/net/core/neighbour.c
index 9d92e41..1dc728b 100644
--- a/net/core/neighbour.c
+++ b/net/core/neighbour.c
@@ -927,8 +927,7 @@
 			if (skb_queue_len(&neigh->arp_queue) >=
 			    neigh->parms->queue_len) {
 				struct sk_buff *buff;
-				buff = neigh->arp_queue.next;
-				__skb_unlink(buff, &neigh->arp_queue);
+				buff = __skb_dequeue(&neigh->arp_queue);
 				kfree_skb(buff);
 				NEIGH_CACHE_STAT_INC(neigh->tbl, unres_discards);
 			}
@@ -1259,24 +1258,20 @@
 	struct neigh_table *tbl = (struct neigh_table *)arg;
 	long sched_next = 0;
 	unsigned long now = jiffies;
-	struct sk_buff *skb;
+	struct sk_buff *skb, *n;
 
 	spin_lock(&tbl->proxy_queue.lock);
 
-	skb = tbl->proxy_queue.next;
+	skb_queue_walk_safe(&tbl->proxy_queue, skb, n) {
+		long tdif = NEIGH_CB(skb)->sched_next - now;
 
-	while (skb != (struct sk_buff *)&tbl->proxy_queue) {
-		struct sk_buff *back = skb;
-		long tdif = NEIGH_CB(back)->sched_next - now;
-
-		skb = skb->next;
 		if (tdif <= 0) {
-			struct net_device *dev = back->dev;
-			__skb_unlink(back, &tbl->proxy_queue);
+			struct net_device *dev = skb->dev;
+			__skb_unlink(skb, &tbl->proxy_queue);
 			if (tbl->proxy_redo && netif_running(dev))
-				tbl->proxy_redo(back);
+				tbl->proxy_redo(skb);
 			else
-				kfree_skb(back);
+				kfree_skb(skb);
 
 			dev_put(dev);
 		} else if (!sched_next || tdif < sched_next)
diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c
index c1f4e0d..92d6b94 100644
--- a/net/core/net-sysfs.c
+++ b/net/core/net-sysfs.c
@@ -209,9 +209,44 @@
 	return netdev_store(dev, attr, buf, len, change_tx_queue_len);
 }
 
+static ssize_t store_ifalias(struct device *dev, struct device_attribute *attr,
+			     const char *buf, size_t len)
+{
+	struct net_device *netdev = to_net_dev(dev);
+	size_t count = len;
+	ssize_t ret;
+
+	if (!capable(CAP_NET_ADMIN))
+		return -EPERM;
+
+	/* ignore trailing newline */
+	if (len >  0 && buf[len - 1] == '\n')
+		--count;
+
+	rtnl_lock();
+	ret = dev_set_alias(netdev, buf, count);
+	rtnl_unlock();
+
+	return ret < 0 ? ret : len;
+}
+
+static ssize_t show_ifalias(struct device *dev,
+			    struct device_attribute *attr, char *buf)
+{
+	const struct net_device *netdev = to_net_dev(dev);
+	ssize_t ret = 0;
+
+	rtnl_lock();
+	if (netdev->ifalias)
+		ret = sprintf(buf, "%s\n", netdev->ifalias);
+	rtnl_unlock();
+	return ret;
+}
+
 static struct device_attribute net_class_attributes[] = {
 	__ATTR(addr_len, S_IRUGO, show_addr_len, NULL),
 	__ATTR(dev_id, S_IRUGO, show_dev_id, NULL),
+	__ATTR(ifalias, S_IRUGO | S_IWUSR, show_ifalias, store_ifalias),
 	__ATTR(iflink, S_IRUGO, show_iflink, NULL),
 	__ATTR(ifindex, S_IRUGO, show_ifindex, NULL),
 	__ATTR(features, S_IRUGO, show_features, NULL),
@@ -418,6 +453,7 @@
 
 	BUG_ON(dev->reg_state != NETREG_RELEASED);
 
+	kfree(dev->ifalias);
 	kfree((char *)dev - dev->padded);
 }
 
diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c
index 7c52fe2..b0dc818 100644
--- a/net/core/net_namespace.c
+++ b/net/core/net_namespace.c
@@ -18,6 +18,7 @@
 static DEFINE_MUTEX(net_mutex);
 
 LIST_HEAD(net_namespace_list);
+EXPORT_SYMBOL_GPL(net_namespace_list);
 
 struct net init_net;
 EXPORT_SYMBOL(init_net);
diff --git a/net/core/pktgen.c b/net/core/pktgen.c
index a756847..99f656d 100644
--- a/net/core/pktgen.c
+++ b/net/core/pktgen.c
@@ -2474,7 +2474,7 @@
 				if (ret < 0) {
 					printk(KERN_ERR "Error expanding "
 					       "ipsec packet %d\n",ret);
-					return 0;
+					goto err;
 				}
 			}
 
@@ -2484,8 +2484,7 @@
 			if (ret) {
 				printk(KERN_ERR "Error creating ipsec "
 				       "packet %d\n",ret);
-				kfree_skb(skb);
-				return 0;
+				goto err;
 			}
 			/* restore ll */
 			eth = (__u8 *) skb_push(skb, ETH_HLEN);
@@ -2494,6 +2493,9 @@
 		}
 	}
 	return 1;
+err:
+	kfree_skb(skb);
+	return 0;
 }
 #endif
 
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index 71edb8b..3630131 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -73,7 +73,7 @@
 
 void rtnl_unlock(void)
 {
-	mutex_unlock(&rtnl_mutex);
+	/* This fellow will unlock it for us. */
 	netdev_run_todo();
 }
 
@@ -586,6 +586,7 @@
 {
 	return NLMSG_ALIGN(sizeof(struct ifinfomsg))
 	       + nla_total_size(IFNAMSIZ) /* IFLA_IFNAME */
+	       + nla_total_size(IFALIASZ) /* IFLA_IFALIAS */
 	       + nla_total_size(IFNAMSIZ) /* IFLA_QDISC */
 	       + nla_total_size(sizeof(struct rtnl_link_ifmap))
 	       + nla_total_size(sizeof(struct rtnl_link_stats))
@@ -640,6 +641,9 @@
 	if (txq->qdisc_sleeping)
 		NLA_PUT_STRING(skb, IFLA_QDISC, txq->qdisc_sleeping->ops->id);
 
+	if (dev->ifalias)
+		NLA_PUT_STRING(skb, IFLA_IFALIAS, dev->ifalias);
+
 	if (1) {
 		struct rtnl_link_ifmap map = {
 			.mem_start   = dev->mem_start,
@@ -713,6 +717,7 @@
 	[IFLA_LINKMODE]		= { .type = NLA_U8 },
 	[IFLA_LINKINFO]		= { .type = NLA_NESTED },
 	[IFLA_NET_NS_PID]	= { .type = NLA_U32 },
+	[IFLA_IFALIAS]	        = { .type = NLA_STRING, .len = IFALIASZ-1 },
 };
 
 static const struct nla_policy ifla_info_policy[IFLA_INFO_MAX+1] = {
@@ -853,6 +858,14 @@
 		modified = 1;
 	}
 
+	if (tb[IFLA_IFALIAS]) {
+		err = dev_set_alias(dev, nla_data(tb[IFLA_IFALIAS]),
+				    nla_len(tb[IFLA_IFALIAS]));
+		if (err < 0)
+			goto errout;
+		modified = 1;
+	}
+
 	if (tb[IFLA_BROADCAST]) {
 		nla_memcpy(dev->broadcast, tb[IFLA_BROADCAST], dev->addr_len);
 		send_addr_notify = 1;
diff --git a/net/core/skb_dma_map.c b/net/core/skb_dma_map.c
new file mode 100644
index 0000000..8623492
--- /dev/null
+++ b/net/core/skb_dma_map.c
@@ -0,0 +1,66 @@
+/* skb_dma_map.c: DMA mapping helpers for socket buffers.
+ *
+ * Copyright (C) David S. Miller <davem@davemloft.net>
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/dma-mapping.h>
+#include <linux/skbuff.h>
+
+int skb_dma_map(struct device *dev, struct sk_buff *skb,
+		enum dma_data_direction dir)
+{
+	struct skb_shared_info *sp = skb_shinfo(skb);
+	dma_addr_t map;
+	int i;
+
+	map = dma_map_single(dev, skb->data,
+			     skb_headlen(skb), dir);
+	if (dma_mapping_error(dev, map))
+		goto out_err;
+
+	sp->dma_maps[0] = map;
+	for (i = 0; i < sp->nr_frags; i++) {
+		skb_frag_t *fp = &sp->frags[i];
+
+		map = dma_map_page(dev, fp->page, fp->page_offset,
+				   fp->size, dir);
+		if (dma_mapping_error(dev, map))
+			goto unwind;
+		sp->dma_maps[i + 1] = map;
+	}
+	sp->num_dma_maps = i + 1;
+
+	return 0;
+
+unwind:
+	while (--i >= 0) {
+		skb_frag_t *fp = &sp->frags[i];
+
+		dma_unmap_page(dev, sp->dma_maps[i + 1],
+			       fp->size, dir);
+	}
+	dma_unmap_single(dev, sp->dma_maps[0],
+			 skb_headlen(skb), dir);
+out_err:
+	return -ENOMEM;
+}
+EXPORT_SYMBOL(skb_dma_map);
+
+void skb_dma_unmap(struct device *dev, struct sk_buff *skb,
+		   enum dma_data_direction dir)
+{
+	struct skb_shared_info *sp = skb_shinfo(skb);
+	int i;
+
+	dma_unmap_single(dev, sp->dma_maps[0],
+			 skb_headlen(skb), dir);
+	for (i = 0; i < sp->nr_frags; i++) {
+		skb_frag_t *fp = &sp->frags[i];
+
+		dma_unmap_page(dev, sp->dma_maps[i + 1],
+			       fp->size, dir);
+	}
+}
+EXPORT_SYMBOL(skb_dma_unmap);
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index ca1ccdf..4e22e3a 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -1,7 +1,7 @@
 /*
  *	Routines having to do with the 'struct sk_buff' memory handlers.
  *
- *	Authors:	Alan Cox <iiitac@pyr.swan.ac.uk>
+ *	Authors:	Alan Cox <alan@lxorguk.ukuu.org.uk>
  *			Florian La Roche <rzsfl@rz.uni-sb.de>
  *
  *	Fixes:
@@ -263,6 +263,26 @@
 	return skb;
 }
 
+struct page *__netdev_alloc_page(struct net_device *dev, gfp_t gfp_mask)
+{
+	int node = dev->dev.parent ? dev_to_node(dev->dev.parent) : -1;
+	struct page *page;
+
+	page = alloc_pages_node(node, gfp_mask, 0);
+	return page;
+}
+EXPORT_SYMBOL(__netdev_alloc_page);
+
+void skb_add_rx_frag(struct sk_buff *skb, int i, struct page *page, int off,
+		int size)
+{
+	skb_fill_page_desc(skb, i, page, off, size);
+	skb->len += size;
+	skb->data_len += size;
+	skb->truesize += size;
+}
+EXPORT_SYMBOL(skb_add_rx_frag);
+
 /**
  *	dev_alloc_skb - allocate an skbuff for receiving
  *	@length: length to allocate
@@ -363,8 +383,7 @@
 	}
 }
 
-/* Free everything but the sk_buff shell. */
-static void skb_release_all(struct sk_buff *skb)
+static void skb_release_head_state(struct sk_buff *skb)
 {
 	dst_release(skb->dst);
 #ifdef CONFIG_XFRM
@@ -388,6 +407,12 @@
 	skb->tc_verd = 0;
 #endif
 #endif
+}
+
+/* Free everything but the sk_buff shell. */
+static void skb_release_all(struct sk_buff *skb)
+{
+	skb_release_head_state(skb);
 	skb_release_data(skb);
 }
 
@@ -424,6 +449,38 @@
 	__kfree_skb(skb);
 }
 
+int skb_recycle_check(struct sk_buff *skb, int skb_size)
+{
+	struct skb_shared_info *shinfo;
+
+	if (skb_is_nonlinear(skb) || skb->fclone != SKB_FCLONE_UNAVAILABLE)
+		return 0;
+
+	skb_size = SKB_DATA_ALIGN(skb_size + NET_SKB_PAD);
+	if (skb_end_pointer(skb) - skb->head < skb_size)
+		return 0;
+
+	if (skb_shared(skb) || skb_cloned(skb))
+		return 0;
+
+	skb_release_head_state(skb);
+	shinfo = skb_shinfo(skb);
+	atomic_set(&shinfo->dataref, 1);
+	shinfo->nr_frags = 0;
+	shinfo->gso_size = 0;
+	shinfo->gso_segs = 0;
+	shinfo->gso_type = 0;
+	shinfo->ip6_frag_id = 0;
+	shinfo->frag_list = NULL;
+
+	memset(skb, 0, offsetof(struct sk_buff, tail));
+	skb_reset_tail_pointer(skb);
+	skb->data = skb->head + NET_SKB_PAD;
+
+	return 1;
+}
+EXPORT_SYMBOL(skb_recycle_check);
+
 static void __copy_skb_header(struct sk_buff *new, const struct sk_buff *old)
 {
 	new->tstamp		= old->tstamp;
@@ -701,6 +758,8 @@
 #endif
 	long off;
 
+	BUG_ON(nhead < 0);
+
 	if (skb_shared(skb))
 		BUG();
 
diff --git a/net/core/sock.c b/net/core/sock.c
index 91f8bbc..5e2a313 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -154,7 +154,8 @@
   "sk_lock-AF_PPPOX" , "sk_lock-AF_WANPIPE"  , "sk_lock-AF_LLC"      ,
   "sk_lock-27"       , "sk_lock-28"          , "sk_lock-AF_CAN"      ,
   "sk_lock-AF_TIPC"  , "sk_lock-AF_BLUETOOTH", "sk_lock-IUCV"        ,
-  "sk_lock-AF_RXRPC" , "sk_lock-AF_MAX"
+  "sk_lock-AF_RXRPC" , "sk_lock-AF_ISDN"     , "sk_lock-AF_PHONET"   ,
+  "sk_lock-AF_MAX"
 };
 static const char *af_family_slock_key_strings[AF_MAX+1] = {
   "slock-AF_UNSPEC", "slock-AF_UNIX"     , "slock-AF_INET"     ,
@@ -168,7 +169,8 @@
   "slock-AF_PPPOX" , "slock-AF_WANPIPE"  , "slock-AF_LLC"      ,
   "slock-27"       , "slock-28"          , "slock-AF_CAN"      ,
   "slock-AF_TIPC"  , "slock-AF_BLUETOOTH", "slock-AF_IUCV"     ,
-  "slock-AF_RXRPC" , "slock-AF_MAX"
+  "slock-AF_RXRPC" , "slock-AF_ISDN"     , "slock-AF_PHONET"   ,
+  "slock-AF_MAX"
 };
 static const char *af_family_clock_key_strings[AF_MAX+1] = {
   "clock-AF_UNSPEC", "clock-AF_UNIX"     , "clock-AF_INET"     ,
@@ -182,7 +184,8 @@
   "clock-AF_PPPOX" , "clock-AF_WANPIPE"  , "clock-AF_LLC"      ,
   "clock-27"       , "clock-28"          , "clock-AF_CAN"      ,
   "clock-AF_TIPC"  , "clock-AF_BLUETOOTH", "clock-AF_IUCV"     ,
-  "clock-AF_RXRPC" , "clock-AF_MAX"
+  "clock-AF_RXRPC" , "clock-AF_ISDN"     , "clock-AF_PHONET"   ,
+  "clock-AF_MAX"
 };
 #endif
 
@@ -324,7 +327,7 @@
 		 */
 		mutex_acquire(&sk->sk_lock.dep_map, 0, 1, _RET_IP_);
 
-		rc = sk->sk_backlog_rcv(sk, skb);
+		rc = sk_backlog_rcv(sk, skb);
 
 		mutex_release(&sk->sk_lock.dep_map, 1, _RET_IP_);
 	} else
@@ -1371,7 +1374,7 @@
 			struct sk_buff *next = skb->next;
 
 			skb->next = NULL;
-			sk->sk_backlog_rcv(sk, skb);
+			sk_backlog_rcv(sk, skb);
 
 			/*
 			 * We are in process context here with softirqs
diff --git a/net/core/stream.c b/net/core/stream.c
index a6b3437..8727cea 100644
--- a/net/core/stream.c
+++ b/net/core/stream.c
@@ -9,7 +9,7 @@
  *
  *     Authors:        Arnaldo Carvalho de Melo <acme@conectiva.com.br>
  *                     (from old tcp.c code)
- *                     Alan Cox <alan@redhat.com> (Borrowed comments 8-))
+ *                     Alan Cox <alan@lxorguk.ukuu.org.uk> (Borrowed comments 8-))
  */
 
 #include <linux/module.h>
diff --git a/net/dccp/ccids/ccid2.c b/net/dccp/ccids/ccid2.c
index 8e95808..9a43073 100644
--- a/net/dccp/ccids/ccid2.c
+++ b/net/dccp/ccids/ccid2.c
@@ -783,7 +783,7 @@
 };
 
 #ifdef CONFIG_IP_DCCP_CCID2_DEBUG
-module_param(ccid2_debug, bool, 0444);
+module_param(ccid2_debug, bool, 0644);
 MODULE_PARM_DESC(ccid2_debug, "Enable debug messages");
 #endif
 
diff --git a/net/dccp/ccids/ccid3.c b/net/dccp/ccids/ccid3.c
index f6756e0..3b8bd7c 100644
--- a/net/dccp/ccids/ccid3.c
+++ b/net/dccp/ccids/ccid3.c
@@ -963,7 +963,7 @@
 };
 
 #ifdef CONFIG_IP_DCCP_CCID3_DEBUG
-module_param(ccid3_debug, bool, 0444);
+module_param(ccid3_debug, bool, 0644);
 MODULE_PARM_DESC(ccid3_debug, "Enable debug messages");
 #endif
 
diff --git a/net/dccp/ccids/lib/loss_interval.c b/net/dccp/ccids/lib/loss_interval.c
index bcd6ac4..5b3ce06 100644
--- a/net/dccp/ccids/lib/loss_interval.c
+++ b/net/dccp/ccids/lib/loss_interval.c
@@ -67,7 +67,10 @@
 	u32 i_i, i_tot0 = 0, i_tot1 = 0, w_tot = 0;
 	int i, k = tfrc_lh_length(lh) - 1; /* k is as in rfc3448bis, 5.4 */
 
-	for (i=0; i <= k; i++) {
+	if (k <= 0)
+		return;
+
+	for (i = 0; i <= k; i++) {
 		i_i = tfrc_lh_get_interval(lh, i);
 
 		if (i < k) {
@@ -78,7 +81,6 @@
 			i_tot1 += i_i * tfrc_lh_weights[i-1];
 	}
 
-	BUG_ON(w_tot == 0);
 	lh->i_mean = max(i_tot0, i_tot1) / w_tot;
 }
 
diff --git a/net/dccp/ccids/lib/tfrc.c b/net/dccp/ccids/lib/tfrc.c
index 97ecec0..1859162 100644
--- a/net/dccp/ccids/lib/tfrc.c
+++ b/net/dccp/ccids/lib/tfrc.c
@@ -10,7 +10,7 @@
 
 #ifdef CONFIG_IP_DCCP_TFRC_DEBUG
 int tfrc_debug;
-module_param(tfrc_debug, bool, 0444);
+module_param(tfrc_debug, bool, 0644);
 MODULE_PARM_DESC(tfrc_debug, "Enable debug messages");
 #endif
 
diff --git a/net/dccp/input.c b/net/dccp/input.c
index 803933a..779d0ed 100644
--- a/net/dccp/input.c
+++ b/net/dccp/input.c
@@ -370,7 +370,7 @@
 		goto discard;
 
 	if (dccp_parse_options(sk, NULL, skb))
-		goto discard;
+		return 1;
 
 	if (DCCP_SKB_CB(skb)->dccpd_ack_seq != DCCP_PKT_WITHOUT_ACK_SEQ)
 		dccp_event_ack_recv(sk, skb);
@@ -610,7 +610,7 @@
 		 * Step 8: Process options and mark acknowledgeable
 		 */
 		if (dccp_parse_options(sk, NULL, skb))
-			goto discard;
+			return 1;
 
 		if (dcb->dccpd_ack_seq != DCCP_PKT_WITHOUT_ACK_SEQ)
 			dccp_event_ack_recv(sk, skb);
diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c
index 882c5c4..e3dfdda 100644
--- a/net/dccp/ipv4.c
+++ b/net/dccp/ipv4.c
@@ -811,9 +811,8 @@
 
 	/* Step 2:
 	 *	Look up flow ID in table and get corresponding socket */
-	sk = __inet_lookup(dev_net(skb->dst->dev), &dccp_hashinfo,
-			   iph->saddr, dh->dccph_sport,
-			   iph->daddr, dh->dccph_dport, inet_iif(skb));
+	sk = __inet_lookup_skb(&dccp_hashinfo, skb,
+			       dh->dccph_sport, dh->dccph_dport);
 	/*
 	 * Step 2:
 	 *	If no socket ...
diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c
index 5e1ee0d..1106278 100644
--- a/net/dccp/ipv6.c
+++ b/net/dccp/ipv6.c
@@ -98,7 +98,8 @@
 
 	if (skb->len < offset + sizeof(*dh) ||
 	    skb->len < offset + __dccp_basic_hdr_len(dh)) {
-		ICMP6_INC_STATS_BH(__in6_dev_get(skb->dev), ICMP6_MIB_INERRORS);
+		ICMP6_INC_STATS_BH(net, __in6_dev_get(skb->dev),
+				   ICMP6_MIB_INERRORS);
 		return;
 	}
 
@@ -107,7 +108,8 @@
 			&hdr->saddr, dh->dccph_sport, inet6_iif(skb));
 
 	if (sk == NULL) {
-		ICMP6_INC_STATS_BH(__in6_dev_get(skb->dev), ICMP6_MIB_INERRORS);
+		ICMP6_INC_STATS_BH(net, __in6_dev_get(skb->dev),
+				   ICMP6_MIB_INERRORS);
 		return;
 	}
 
@@ -805,10 +807,8 @@
 
 	/* Step 2:
 	 *	Look up flow ID in table and get corresponding socket */
-	sk = __inet6_lookup(dev_net(skb->dst->dev), &dccp_hashinfo,
-			    &ipv6_hdr(skb)->saddr, dh->dccph_sport,
-			    &ipv6_hdr(skb)->daddr, ntohs(dh->dccph_dport),
-			    inet6_iif(skb));
+	sk = __inet6_lookup_skb(&dccp_hashinfo, skb,
+			        dh->dccph_sport, dh->dccph_dport);
 	/*
 	 * Step 2:
 	 *	If no socket ...
diff --git a/net/dccp/options.c b/net/dccp/options.c
index dc7c158..0809b63 100644
--- a/net/dccp/options.c
+++ b/net/dccp/options.c
@@ -81,11 +81,11 @@
 		/* Check if this isn't a single byte option */
 		if (opt > DCCPO_MAX_RESERVED) {
 			if (opt_ptr == opt_end)
-				goto out_invalid_option;
+				goto out_nonsensical_length;
 
 			len = *opt_ptr++;
-			if (len < 3)
-				goto out_invalid_option;
+			if (len < 2)
+				goto out_nonsensical_length;
 			/*
 			 * Remove the type and len fields, leaving
 			 * just the value size
@@ -95,7 +95,7 @@
 			opt_ptr += len;
 
 			if (opt_ptr > opt_end)
-				goto out_invalid_option;
+				goto out_nonsensical_length;
 		}
 
 		/*
@@ -283,12 +283,17 @@
 	if (mandatory)
 		goto out_invalid_option;
 
+out_nonsensical_length:
+	/* RFC 4340, 5.8: ignore option and all remaining option space */
 	return 0;
 
 out_invalid_option:
 	DCCP_INC_STATS_BH(DCCP_MIB_INVALIDOPT);
 	DCCP_SKB_CB(skb)->dccpd_reset_code = DCCP_RESET_CODE_OPTION_ERROR;
 	DCCP_WARN("DCCP(%p): invalid option %d, len=%d", sk, opt, len);
+	DCCP_SKB_CB(skb)->dccpd_reset_data[0] = opt;
+	DCCP_SKB_CB(skb)->dccpd_reset_data[1] = len > 0 ? value[0] : 0;
+	DCCP_SKB_CB(skb)->dccpd_reset_data[2] = len > 1 ? value[1] : 0;
 	return -1;
 }
 
diff --git a/net/dccp/proto.c b/net/dccp/proto.c
index 1ca3b26..d0bd348 100644
--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -309,7 +309,9 @@
 		sk->sk_err = ECONNRESET;
 
 	dccp_clear_xmit_timers(sk);
+
 	__skb_queue_purge(&sk->sk_receive_queue);
+	__skb_queue_purge(&sk->sk_write_queue);
 	if (sk->sk_send_head != NULL) {
 		__kfree_skb(sk->sk_send_head);
 		sk->sk_send_head = NULL;
@@ -1028,7 +1030,7 @@
 
 #ifdef CONFIG_IP_DCCP_DEBUG
 int dccp_debug;
-module_param(dccp_debug, bool, 0444);
+module_param(dccp_debug, bool, 0644);
 MODULE_PARM_DESC(dccp_debug, "Enable debug messages");
 
 EXPORT_SYMBOL_GPL(dccp_debug);
diff --git a/net/dsa/Kconfig b/net/dsa/Kconfig
new file mode 100644
index 0000000..49211b3
--- /dev/null
+++ b/net/dsa/Kconfig
@@ -0,0 +1,60 @@
+menuconfig NET_DSA
+	bool "Distributed Switch Architecture support"
+	default n
+	depends on EXPERIMENTAL && !S390
+	select PHYLIB
+	---help---
+	  This allows you to use hardware switch chips that use
+	  the Distributed Switch Architecture.
+
+
+if NET_DSA
+
+# tagging formats
+config NET_DSA_TAG_DSA
+	bool
+	default n
+
+config NET_DSA_TAG_EDSA
+	bool
+	default n
+
+config NET_DSA_TAG_TRAILER
+	bool
+	default n
+
+
+# switch drivers
+config NET_DSA_MV88E6XXX
+	bool
+	default n
+
+config NET_DSA_MV88E6060
+	bool "Marvell 88E6060 ethernet switch chip support"
+	select NET_DSA_TAG_TRAILER
+	---help---
+	  This enables support for the Marvell 88E6060 ethernet switch
+	  chip.
+
+config NET_DSA_MV88E6XXX_NEED_PPU
+	bool
+	default n
+
+config NET_DSA_MV88E6131
+	bool "Marvell 88E6131 ethernet switch chip support"
+	select NET_DSA_MV88E6XXX
+	select NET_DSA_MV88E6XXX_NEED_PPU
+	select NET_DSA_TAG_DSA
+	---help---
+	  This enables support for the Marvell 88E6131 ethernet switch
+	  chip.
+
+config NET_DSA_MV88E6123_61_65
+	bool "Marvell 88E6123/6161/6165 ethernet switch chip support"
+	select NET_DSA_MV88E6XXX
+	select NET_DSA_TAG_EDSA
+	---help---
+	  This enables support for the Marvell 88E6123/6161/6165
+	  ethernet switch chips.
+
+endif
diff --git a/net/dsa/Makefile b/net/dsa/Makefile
new file mode 100644
index 0000000..2374faf
--- /dev/null
+++ b/net/dsa/Makefile
@@ -0,0 +1,13 @@
+# tagging formats
+obj-$(CONFIG_NET_DSA_TAG_DSA) += tag_dsa.o
+obj-$(CONFIG_NET_DSA_TAG_EDSA) += tag_edsa.o
+obj-$(CONFIG_NET_DSA_TAG_TRAILER) += tag_trailer.o
+
+# switch drivers
+obj-$(CONFIG_NET_DSA_MV88E6XXX) += mv88e6xxx.o
+obj-$(CONFIG_NET_DSA_MV88E6060) += mv88e6060.o
+obj-$(CONFIG_NET_DSA_MV88E6123_61_65) += mv88e6123_61_65.o
+obj-$(CONFIG_NET_DSA_MV88E6131) += mv88e6131.o
+
+# the core
+obj-$(CONFIG_NET_DSA) += dsa.o slave.o
diff --git a/net/dsa/dsa.c b/net/dsa/dsa.c
new file mode 100644
index 0000000..33e9946
--- /dev/null
+++ b/net/dsa/dsa.c
@@ -0,0 +1,392 @@
+/*
+ * net/dsa/dsa.c - Hardware switch handling
+ * Copyright (c) 2008 Marvell Semiconductor
+ *
+ * This program is free software; you can redistribute it and/or 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/list.h>
+#include <linux/netdevice.h>
+#include <linux/platform_device.h>
+#include <net/dsa.h>
+#include "dsa_priv.h"
+
+char dsa_driver_version[] = "0.1";
+
+
+/* switch driver registration ***********************************************/
+static DEFINE_MUTEX(dsa_switch_drivers_mutex);
+static LIST_HEAD(dsa_switch_drivers);
+
+void register_switch_driver(struct dsa_switch_driver *drv)
+{
+	mutex_lock(&dsa_switch_drivers_mutex);
+	list_add_tail(&drv->list, &dsa_switch_drivers);
+	mutex_unlock(&dsa_switch_drivers_mutex);
+}
+
+void unregister_switch_driver(struct dsa_switch_driver *drv)
+{
+	mutex_lock(&dsa_switch_drivers_mutex);
+	list_del_init(&drv->list);
+	mutex_unlock(&dsa_switch_drivers_mutex);
+}
+
+static struct dsa_switch_driver *
+dsa_switch_probe(struct mii_bus *bus, int sw_addr, char **_name)
+{
+	struct dsa_switch_driver *ret;
+	struct list_head *list;
+	char *name;
+
+	ret = NULL;
+	name = NULL;
+
+	mutex_lock(&dsa_switch_drivers_mutex);
+	list_for_each(list, &dsa_switch_drivers) {
+		struct dsa_switch_driver *drv;
+
+		drv = list_entry(list, struct dsa_switch_driver, list);
+
+		name = drv->probe(bus, sw_addr);
+		if (name != NULL) {
+			ret = drv;
+			break;
+		}
+	}
+	mutex_unlock(&dsa_switch_drivers_mutex);
+
+	*_name = name;
+
+	return ret;
+}
+
+
+/* basic switch operations **************************************************/
+static struct dsa_switch *
+dsa_switch_setup(struct device *parent, struct dsa_platform_data *pd,
+		 struct mii_bus *bus, struct net_device *dev)
+{
+	struct dsa_switch *ds;
+	int ret;
+	struct dsa_switch_driver *drv;
+	char *name;
+	int i;
+
+	/*
+	 * Probe for switch model.
+	 */
+	drv = dsa_switch_probe(bus, pd->sw_addr, &name);
+	if (drv == NULL) {
+		printk(KERN_ERR "%s: could not detect attached switch\n",
+		       dev->name);
+		return ERR_PTR(-EINVAL);
+	}
+	printk(KERN_INFO "%s: detected a %s switch\n", dev->name, name);
+
+
+	/*
+	 * Allocate and initialise switch state.
+	 */
+	ds = kzalloc(sizeof(*ds) + drv->priv_size, GFP_KERNEL);
+	if (ds == NULL)
+		return ERR_PTR(-ENOMEM);
+
+	ds->pd = pd;
+	ds->master_netdev = dev;
+	ds->master_mii_bus = bus;
+
+	ds->drv = drv;
+	ds->tag_protocol = drv->tag_protocol;
+
+
+	/*
+	 * Validate supplied switch configuration.
+	 */
+	ds->cpu_port = -1;
+	for (i = 0; i < DSA_MAX_PORTS; i++) {
+		char *name;
+
+		name = pd->port_names[i];
+		if (name == NULL)
+			continue;
+
+		if (!strcmp(name, "cpu")) {
+			if (ds->cpu_port != -1) {
+				printk(KERN_ERR "multiple cpu ports?!\n");
+				ret = -EINVAL;
+				goto out;
+			}
+			ds->cpu_port = i;
+		} else {
+			ds->valid_port_mask |= 1 << i;
+		}
+	}
+
+	if (ds->cpu_port == -1) {
+		printk(KERN_ERR "no cpu port?!\n");
+		ret = -EINVAL;
+		goto out;
+	}
+
+
+	/*
+	 * If we use a tagging format that doesn't have an ethertype
+	 * field, make sure that all packets from this point on get
+	 * sent to the tag format's receive function.  (Which will
+	 * discard received packets until we set ds->ports[] below.)
+	 */
+	wmb();
+	dev->dsa_ptr = (void *)ds;
+
+
+	/*
+	 * Do basic register setup.
+	 */
+	ret = drv->setup(ds);
+	if (ret < 0)
+		goto out;
+
+	ret = drv->set_addr(ds, dev->dev_addr);
+	if (ret < 0)
+		goto out;
+
+	ds->slave_mii_bus = mdiobus_alloc();
+	if (ds->slave_mii_bus == NULL) {
+		ret = -ENOMEM;
+		goto out;
+	}
+	dsa_slave_mii_bus_init(ds);
+
+	ret = mdiobus_register(ds->slave_mii_bus);
+	if (ret < 0)
+		goto out_free;
+
+
+	/*
+	 * Create network devices for physical switch ports.
+	 */
+	wmb();
+	for (i = 0; i < DSA_MAX_PORTS; i++) {
+		struct net_device *slave_dev;
+
+		if (!(ds->valid_port_mask & (1 << i)))
+			continue;
+
+		slave_dev = dsa_slave_create(ds, parent, i, pd->port_names[i]);
+		if (slave_dev == NULL) {
+			printk(KERN_ERR "%s: can't create dsa slave "
+			       "device for port %d(%s)\n",
+			       dev->name, i, pd->port_names[i]);
+			continue;
+		}
+
+		ds->ports[i] = slave_dev;
+	}
+
+	return ds;
+
+out_free:
+	mdiobus_free(ds->slave_mii_bus);
+out:
+	dev->dsa_ptr = NULL;
+	kfree(ds);
+	return ERR_PTR(ret);
+}
+
+static void dsa_switch_destroy(struct dsa_switch *ds)
+{
+}
+
+
+/* hooks for ethertype-less tagging formats *********************************/
+/*
+ * The original DSA tag format and some other tag formats have no
+ * ethertype, which means that we need to add a little hack to the
+ * networking receive path to make sure that received frames get
+ * the right ->protocol assigned to them when one of those tag
+ * formats is in use.
+ */
+bool dsa_uses_dsa_tags(void *dsa_ptr)
+{
+	struct dsa_switch *ds = dsa_ptr;
+
+	return !!(ds->tag_protocol == htons(ETH_P_DSA));
+}
+
+bool dsa_uses_trailer_tags(void *dsa_ptr)
+{
+	struct dsa_switch *ds = dsa_ptr;
+
+	return !!(ds->tag_protocol == htons(ETH_P_TRAILER));
+}
+
+
+/* link polling *************************************************************/
+static void dsa_link_poll_work(struct work_struct *ugly)
+{
+	struct dsa_switch *ds;
+
+	ds = container_of(ugly, struct dsa_switch, link_poll_work);
+
+	ds->drv->poll_link(ds);
+	mod_timer(&ds->link_poll_timer, round_jiffies(jiffies + HZ));
+}
+
+static void dsa_link_poll_timer(unsigned long _ds)
+{
+	struct dsa_switch *ds = (void *)_ds;
+
+	schedule_work(&ds->link_poll_work);
+}
+
+
+/* platform driver init and cleanup *****************************************/
+static int dev_is_class(struct device *dev, void *class)
+{
+	if (dev->class != NULL && !strcmp(dev->class->name, class))
+		return 1;
+
+	return 0;
+}
+
+static struct device *dev_find_class(struct device *parent, char *class)
+{
+	if (dev_is_class(parent, class)) {
+		get_device(parent);
+		return parent;
+	}
+
+	return device_find_child(parent, class, dev_is_class);
+}
+
+static struct mii_bus *dev_to_mii_bus(struct device *dev)
+{
+	struct device *d;
+
+	d = dev_find_class(dev, "mdio_bus");
+	if (d != NULL) {
+		struct mii_bus *bus;
+
+		bus = to_mii_bus(d);
+		put_device(d);
+
+		return bus;
+	}
+
+	return NULL;
+}
+
+static struct net_device *dev_to_net_device(struct device *dev)
+{
+	struct device *d;
+
+	d = dev_find_class(dev, "net");
+	if (d != NULL) {
+		struct net_device *nd;
+
+		nd = to_net_dev(d);
+		dev_hold(nd);
+		put_device(d);
+
+		return nd;
+	}
+
+	return NULL;
+}
+
+static int dsa_probe(struct platform_device *pdev)
+{
+	static int dsa_version_printed;
+	struct dsa_platform_data *pd = pdev->dev.platform_data;
+	struct net_device *dev;
+	struct mii_bus *bus;
+	struct dsa_switch *ds;
+
+	if (!dsa_version_printed++)
+		printk(KERN_NOTICE "Distributed Switch Architecture "
+			"driver version %s\n", dsa_driver_version);
+
+	if (pd == NULL || pd->mii_bus == NULL || pd->netdev == NULL)
+		return -EINVAL;
+
+	bus = dev_to_mii_bus(pd->mii_bus);
+	if (bus == NULL)
+		return -EINVAL;
+
+	dev = dev_to_net_device(pd->netdev);
+	if (dev == NULL)
+		return -EINVAL;
+
+	if (dev->dsa_ptr != NULL) {
+		dev_put(dev);
+		return -EEXIST;
+	}
+
+	ds = dsa_switch_setup(&pdev->dev, pd, bus, dev);
+	if (IS_ERR(ds)) {
+		dev_put(dev);
+		return PTR_ERR(ds);
+	}
+
+	if (ds->drv->poll_link != NULL) {
+		INIT_WORK(&ds->link_poll_work, dsa_link_poll_work);
+		init_timer(&ds->link_poll_timer);
+		ds->link_poll_timer.data = (unsigned long)ds;
+		ds->link_poll_timer.function = dsa_link_poll_timer;
+		ds->link_poll_timer.expires = round_jiffies(jiffies + HZ);
+		add_timer(&ds->link_poll_timer);
+	}
+
+	platform_set_drvdata(pdev, ds);
+
+	return 0;
+}
+
+static int dsa_remove(struct platform_device *pdev)
+{
+	struct dsa_switch *ds = platform_get_drvdata(pdev);
+
+	if (ds->drv->poll_link != NULL)
+		del_timer_sync(&ds->link_poll_timer);
+
+	flush_scheduled_work();
+
+	dsa_switch_destroy(ds);
+
+	return 0;
+}
+
+static void dsa_shutdown(struct platform_device *pdev)
+{
+}
+
+static struct platform_driver dsa_driver = {
+	.probe		= dsa_probe,
+	.remove		= dsa_remove,
+	.shutdown	= dsa_shutdown,
+	.driver = {
+		.name	= "dsa",
+		.owner	= THIS_MODULE,
+	},
+};
+
+static int __init dsa_init_module(void)
+{
+	return platform_driver_register(&dsa_driver);
+}
+module_init(dsa_init_module);
+
+static void __exit dsa_cleanup_module(void)
+{
+	platform_driver_unregister(&dsa_driver);
+}
+module_exit(dsa_cleanup_module);
+
+MODULE_AUTHOR("Lennert Buytenhek <buytenh@wantstofly.org>")
+MODULE_DESCRIPTION("Driver for Distributed Switch Architecture switch chips");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:dsa");
diff --git a/net/dsa/dsa_priv.h b/net/dsa/dsa_priv.h
new file mode 100644
index 0000000..7063378
--- /dev/null
+++ b/net/dsa/dsa_priv.h
@@ -0,0 +1,116 @@
+/*
+ * net/dsa/dsa_priv.h - Hardware switch handling
+ * Copyright (c) 2008 Marvell Semiconductor
+ *
+ * This program is free software; you can redistribute it and/or 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 __DSA_PRIV_H
+#define __DSA_PRIV_H
+
+#include <linux/list.h>
+#include <linux/phy.h>
+#include <linux/timer.h>
+#include <linux/workqueue.h>
+#include <net/dsa.h>
+
+struct dsa_switch {
+	/*
+	 * Configuration data for the platform device that owns
+	 * this dsa switch instance.
+	 */
+	struct dsa_platform_data	*pd;
+
+	/*
+	 * References to network device and mii bus to use.
+	 */
+	struct net_device		*master_netdev;
+	struct mii_bus			*master_mii_bus;
+
+	/*
+	 * The used switch driver and frame tagging type.
+	 */
+	struct dsa_switch_driver	*drv;
+	__be16				tag_protocol;
+
+	/*
+	 * Slave mii_bus and devices for the individual ports.
+	 */
+	int				cpu_port;
+	u32				valid_port_mask;
+	struct mii_bus			*slave_mii_bus;
+	struct net_device		*ports[DSA_MAX_PORTS];
+
+	/*
+	 * Link state polling.
+	 */
+	struct work_struct		link_poll_work;
+	struct timer_list		link_poll_timer;
+};
+
+struct dsa_slave_priv {
+	struct net_device	*dev;
+	struct dsa_switch	*parent;
+	int			port;
+	struct phy_device	*phy;
+};
+
+struct dsa_switch_driver {
+	struct list_head	list;
+
+	__be16			tag_protocol;
+	int			priv_size;
+
+	/*
+	 * Probing and setup.
+	 */
+	char	*(*probe)(struct mii_bus *bus, int sw_addr);
+	int	(*setup)(struct dsa_switch *ds);
+	int	(*set_addr)(struct dsa_switch *ds, u8 *addr);
+
+	/*
+	 * Access to the switch's PHY registers.
+	 */
+	int	(*phy_read)(struct dsa_switch *ds, int port, int regnum);
+	int	(*phy_write)(struct dsa_switch *ds, int port,
+			     int regnum, u16 val);
+
+	/*
+	 * Link state polling and IRQ handling.
+	 */
+	void	(*poll_link)(struct dsa_switch *ds);
+
+	/*
+	 * ethtool hardware statistics.
+	 */
+	void	(*get_strings)(struct dsa_switch *ds, int port, uint8_t *data);
+	void	(*get_ethtool_stats)(struct dsa_switch *ds,
+				     int port, uint64_t *data);
+	int	(*get_sset_count)(struct dsa_switch *ds);
+};
+
+/* dsa.c */
+extern char dsa_driver_version[];
+void register_switch_driver(struct dsa_switch_driver *type);
+void unregister_switch_driver(struct dsa_switch_driver *type);
+
+/* slave.c */
+void dsa_slave_mii_bus_init(struct dsa_switch *ds);
+struct net_device *dsa_slave_create(struct dsa_switch *ds,
+				    struct device *parent,
+				    int port, char *name);
+
+/* tag_dsa.c */
+int dsa_xmit(struct sk_buff *skb, struct net_device *dev);
+
+/* tag_edsa.c */
+int edsa_xmit(struct sk_buff *skb, struct net_device *dev);
+
+/* tag_trailer.c */
+int trailer_xmit(struct sk_buff *skb, struct net_device *dev);
+
+
+#endif
diff --git a/net/dsa/mv88e6060.c b/net/dsa/mv88e6060.c
new file mode 100644
index 0000000..54068ef
--- /dev/null
+++ b/net/dsa/mv88e6060.c
@@ -0,0 +1,287 @@
+/*
+ * net/dsa/mv88e6060.c - Driver for Marvell 88e6060 switch chips
+ * Copyright (c) 2008 Marvell Semiconductor
+ *
+ * This program is free software; you can redistribute it and/or 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/list.h>
+#include <linux/netdevice.h>
+#include <linux/phy.h>
+#include "dsa_priv.h"
+
+#define REG_PORT(p)		(8 + (p))
+#define REG_GLOBAL		0x0f
+
+static int reg_read(struct dsa_switch *ds, int addr, int reg)
+{
+	return mdiobus_read(ds->master_mii_bus, addr, reg);
+}
+
+#define REG_READ(addr, reg)					\
+	({							\
+		int __ret;					\
+								\
+		__ret = reg_read(ds, addr, reg);		\
+		if (__ret < 0)					\
+			return __ret;				\
+		__ret;						\
+	})
+
+
+static int reg_write(struct dsa_switch *ds, int addr, int reg, u16 val)
+{
+	return mdiobus_write(ds->master_mii_bus, addr, reg, val);
+}
+
+#define REG_WRITE(addr, reg, val)				\
+	({							\
+		int __ret;					\
+								\
+		__ret = reg_write(ds, addr, reg, val);		\
+		if (__ret < 0)					\
+			return __ret;				\
+	})
+
+static char *mv88e6060_probe(struct mii_bus *bus, int sw_addr)
+{
+	int ret;
+
+	ret = mdiobus_read(bus, REG_PORT(0), 0x03);
+	if (ret >= 0) {
+		ret &= 0xfff0;
+		if (ret == 0x0600)
+			return "Marvell 88E6060";
+	}
+
+	return NULL;
+}
+
+static int mv88e6060_switch_reset(struct dsa_switch *ds)
+{
+	int i;
+	int ret;
+
+	/*
+	 * Set all ports to the disabled state.
+	 */
+	for (i = 0; i < 6; i++) {
+		ret = REG_READ(REG_PORT(i), 0x04);
+		REG_WRITE(REG_PORT(i), 0x04, ret & 0xfffc);
+	}
+
+	/*
+	 * Wait for transmit queues to drain.
+	 */
+	msleep(2);
+
+	/*
+	 * Reset the switch.
+	 */
+	REG_WRITE(REG_GLOBAL, 0x0A, 0xa130);
+
+	/*
+	 * Wait up to one second for reset to complete.
+	 */
+	for (i = 0; i < 1000; i++) {
+		ret = REG_READ(REG_GLOBAL, 0x00);
+		if ((ret & 0x8000) == 0x0000)
+			break;
+
+		msleep(1);
+	}
+	if (i == 1000)
+		return -ETIMEDOUT;
+
+	return 0;
+}
+
+static int mv88e6060_setup_global(struct dsa_switch *ds)
+{
+	/*
+	 * Disable discarding of frames with excessive collisions,
+	 * set the maximum frame size to 1536 bytes, and mask all
+	 * interrupt sources.
+	 */
+	REG_WRITE(REG_GLOBAL, 0x04, 0x0800);
+
+	/*
+	 * Enable automatic address learning, set the address
+	 * database size to 1024 entries, and set the default aging
+	 * time to 5 minutes.
+	 */
+	REG_WRITE(REG_GLOBAL, 0x0a, 0x2130);
+
+	return 0;
+}
+
+static int mv88e6060_setup_port(struct dsa_switch *ds, int p)
+{
+	int addr = REG_PORT(p);
+
+	/*
+	 * Do not force flow control, disable Ingress and Egress
+	 * Header tagging, disable VLAN tunneling, and set the port
+	 * state to Forwarding.  Additionally, if this is the CPU
+	 * port, enable Ingress and Egress Trailer tagging mode.
+	 */
+	REG_WRITE(addr, 0x04, (p == ds->cpu_port) ? 0x4103 : 0x0003);
+
+	/*
+	 * Port based VLAN map: give each port its own address
+	 * database, allow the CPU port to talk to each of the 'real'
+	 * ports, and allow each of the 'real' ports to only talk to
+	 * the CPU port.
+	 */
+	REG_WRITE(addr, 0x06,
+			((p & 0xf) << 12) |
+			 ((p == ds->cpu_port) ?
+				ds->valid_port_mask :
+				(1 << ds->cpu_port)));
+
+	/*
+	 * Port Association Vector: when learning source addresses
+	 * of packets, add the address to the address database using
+	 * a port bitmap that has only the bit for this port set and
+	 * the other bits clear.
+	 */
+	REG_WRITE(addr, 0x0b, 1 << p);
+
+	return 0;
+}
+
+static int mv88e6060_setup(struct dsa_switch *ds)
+{
+	int i;
+	int ret;
+
+	ret = mv88e6060_switch_reset(ds);
+	if (ret < 0)
+		return ret;
+
+	/* @@@ initialise atu */
+
+	ret = mv88e6060_setup_global(ds);
+	if (ret < 0)
+		return ret;
+
+	for (i = 0; i < 6; i++) {
+		ret = mv88e6060_setup_port(ds, i);
+		if (ret < 0)
+			return ret;
+	}
+
+	return 0;
+}
+
+static int mv88e6060_set_addr(struct dsa_switch *ds, u8 *addr)
+{
+	REG_WRITE(REG_GLOBAL, 0x01, (addr[0] << 8) | addr[1]);
+	REG_WRITE(REG_GLOBAL, 0x02, (addr[2] << 8) | addr[3]);
+	REG_WRITE(REG_GLOBAL, 0x03, (addr[4] << 8) | addr[5]);
+
+	return 0;
+}
+
+static int mv88e6060_port_to_phy_addr(int port)
+{
+	if (port >= 0 && port <= 5)
+		return port;
+	return -1;
+}
+
+static int mv88e6060_phy_read(struct dsa_switch *ds, int port, int regnum)
+{
+	int addr;
+
+	addr = mv88e6060_port_to_phy_addr(port);
+	if (addr == -1)
+		return 0xffff;
+
+	return reg_read(ds, addr, regnum);
+}
+
+static int
+mv88e6060_phy_write(struct dsa_switch *ds, int port, int regnum, u16 val)
+{
+	int addr;
+
+	addr = mv88e6060_port_to_phy_addr(port);
+	if (addr == -1)
+		return 0xffff;
+
+	return reg_write(ds, addr, regnum, val);
+}
+
+static void mv88e6060_poll_link(struct dsa_switch *ds)
+{
+	int i;
+
+	for (i = 0; i < DSA_MAX_PORTS; i++) {
+		struct net_device *dev;
+		int port_status;
+		int link;
+		int speed;
+		int duplex;
+		int fc;
+
+		dev = ds->ports[i];
+		if (dev == NULL)
+			continue;
+
+		link = 0;
+		if (dev->flags & IFF_UP) {
+			port_status = reg_read(ds, REG_PORT(i), 0x00);
+			if (port_status < 0)
+				continue;
+
+			link = !!(port_status & 0x1000);
+		}
+
+		if (!link) {
+			if (netif_carrier_ok(dev)) {
+				printk(KERN_INFO "%s: link down\n", dev->name);
+				netif_carrier_off(dev);
+			}
+			continue;
+		}
+
+		speed = (port_status & 0x0100) ? 100 : 10;
+		duplex = (port_status & 0x0200) ? 1 : 0;
+		fc = ((port_status & 0xc000) == 0xc000) ? 1 : 0;
+
+		if (!netif_carrier_ok(dev)) {
+			printk(KERN_INFO "%s: link up, %d Mb/s, %s duplex, "
+					 "flow control %sabled\n", dev->name,
+					 speed, duplex ? "full" : "half",
+					 fc ? "en" : "dis");
+			netif_carrier_on(dev);
+		}
+	}
+}
+
+static struct dsa_switch_driver mv88e6060_switch_driver = {
+	.tag_protocol	= htons(ETH_P_TRAILER),
+	.probe		= mv88e6060_probe,
+	.setup		= mv88e6060_setup,
+	.set_addr	= mv88e6060_set_addr,
+	.phy_read	= mv88e6060_phy_read,
+	.phy_write	= mv88e6060_phy_write,
+	.poll_link	= mv88e6060_poll_link,
+};
+
+int __init mv88e6060_init(void)
+{
+	register_switch_driver(&mv88e6060_switch_driver);
+	return 0;
+}
+module_init(mv88e6060_init);
+
+void __exit mv88e6060_cleanup(void)
+{
+	unregister_switch_driver(&mv88e6060_switch_driver);
+}
+module_exit(mv88e6060_cleanup);
diff --git a/net/dsa/mv88e6123_61_65.c b/net/dsa/mv88e6123_61_65.c
new file mode 100644
index 0000000..555b164
--- /dev/null
+++ b/net/dsa/mv88e6123_61_65.c
@@ -0,0 +1,421 @@
+/*
+ * net/dsa/mv88e6123_61_65.c - Marvell 88e6123/6161/6165 switch chip support
+ * Copyright (c) 2008 Marvell Semiconductor
+ *
+ * This program is free software; you can redistribute it and/or 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/list.h>
+#include <linux/netdevice.h>
+#include <linux/phy.h>
+#include "dsa_priv.h"
+#include "mv88e6xxx.h"
+
+static char *mv88e6123_61_65_probe(struct mii_bus *bus, int sw_addr)
+{
+	int ret;
+
+	ret = __mv88e6xxx_reg_read(bus, sw_addr, REG_PORT(0), 0x03);
+	if (ret >= 0) {
+		ret &= 0xfff0;
+		if (ret == 0x1210)
+			return "Marvell 88E6123";
+		if (ret == 0x1610)
+			return "Marvell 88E6161";
+		if (ret == 0x1650)
+			return "Marvell 88E6165";
+	}
+
+	return NULL;
+}
+
+static int mv88e6123_61_65_switch_reset(struct dsa_switch *ds)
+{
+	int i;
+	int ret;
+
+	/*
+	 * Set all ports to the disabled state.
+	 */
+	for (i = 0; i < 8; i++) {
+		ret = REG_READ(REG_PORT(i), 0x04);
+		REG_WRITE(REG_PORT(i), 0x04, ret & 0xfffc);
+	}
+
+	/*
+	 * Wait for transmit queues to drain.
+	 */
+	msleep(2);
+
+	/*
+	 * Reset the switch.
+	 */
+	REG_WRITE(REG_GLOBAL, 0x04, 0xc400);
+
+	/*
+	 * Wait up to one second for reset to complete.
+	 */
+	for (i = 0; i < 1000; i++) {
+		ret = REG_READ(REG_GLOBAL, 0x00);
+		if ((ret & 0xc800) == 0xc800)
+			break;
+
+		msleep(1);
+	}
+	if (i == 1000)
+		return -ETIMEDOUT;
+
+	return 0;
+}
+
+static int mv88e6123_61_65_setup_global(struct dsa_switch *ds)
+{
+	int ret;
+	int i;
+
+	/*
+	 * Disable the PHY polling unit (since there won't be any
+	 * external PHYs to poll), don't discard packets with
+	 * excessive collisions, and mask all interrupt sources.
+	 */
+	REG_WRITE(REG_GLOBAL, 0x04, 0x0000);
+
+	/*
+	 * Set the default address aging time to 5 minutes, and
+	 * enable address learn messages to be sent to all message
+	 * ports.
+	 */
+	REG_WRITE(REG_GLOBAL, 0x0a, 0x0148);
+
+	/*
+	 * Configure the priority mapping registers.
+	 */
+	ret = mv88e6xxx_config_prio(ds);
+	if (ret < 0)
+		return ret;
+
+	/*
+	 * Configure the cpu port, and configure the cpu port as the
+	 * port to which ingress and egress monitor frames are to be
+	 * sent.
+	 */
+	REG_WRITE(REG_GLOBAL, 0x1a, (ds->cpu_port * 0x1110));
+
+	/*
+	 * Disable remote management for now, and set the switch's
+	 * DSA device number to zero.
+	 */
+	REG_WRITE(REG_GLOBAL, 0x1c, 0x0000);
+
+	/*
+	 * Send all frames with destination addresses matching
+	 * 01:80:c2:00:00:2x to the CPU port.
+	 */
+	REG_WRITE(REG_GLOBAL2, 0x02, 0xffff);
+
+	/*
+	 * Send all frames with destination addresses matching
+	 * 01:80:c2:00:00:0x to the CPU port.
+	 */
+	REG_WRITE(REG_GLOBAL2, 0x03, 0xffff);
+
+	/*
+	 * Disable the loopback filter, disable flow control
+	 * messages, disable flood broadcast override, disable
+	 * removing of provider tags, disable ATU age violation
+	 * interrupts, disable tag flow control, force flow
+	 * control priority to the highest, and send all special
+	 * multicast frames to the CPU at the highest priority.
+	 */
+	REG_WRITE(REG_GLOBAL2, 0x05, 0x00ff);
+
+	/*
+	 * Map all DSA device IDs to the CPU port.
+	 */
+	for (i = 0; i < 32; i++)
+		REG_WRITE(REG_GLOBAL2, 0x06, 0x8000 | (i << 8) | ds->cpu_port);
+
+	/*
+	 * Clear all trunk masks.
+	 */
+	for (i = 0; i < 8; i++)
+		REG_WRITE(REG_GLOBAL2, 0x07, 0x8000 | (i << 12) | 0xff);
+
+	/*
+	 * Clear all trunk mappings.
+	 */
+	for (i = 0; i < 16; i++)
+		REG_WRITE(REG_GLOBAL2, 0x08, 0x8000 | (i << 11));
+
+	/*
+	 * Disable ingress rate limiting by resetting all ingress
+	 * rate limit registers to their initial state.
+	 */
+	for (i = 0; i < 6; i++)
+		REG_WRITE(REG_GLOBAL2, 0x09, 0x9000 | (i << 8));
+
+	/*
+	 * Initialise cross-chip port VLAN table to reset defaults.
+	 */
+	REG_WRITE(REG_GLOBAL2, 0x0b, 0x9000);
+
+	/*
+	 * Clear the priority override table.
+	 */
+	for (i = 0; i < 16; i++)
+		REG_WRITE(REG_GLOBAL2, 0x0f, 0x8000 | (i << 8));
+
+	/* @@@ initialise AVB (22/23) watchdog (27) sdet (29) registers */
+
+	return 0;
+}
+
+static int mv88e6123_61_65_setup_port(struct dsa_switch *ds, int p)
+{
+	int addr = REG_PORT(p);
+
+	/*
+	 * MAC Forcing register: don't force link, speed, duplex
+	 * or flow control state to any particular values.
+	 */
+	REG_WRITE(addr, 0x01, 0x0003);
+
+	/*
+	 * Do not limit the period of time that this port can be
+	 * paused for by the remote end or the period of time that
+	 * this port can pause the remote end.
+	 */
+	REG_WRITE(addr, 0x02, 0x0000);
+
+	/*
+	 * Port Control: disable Drop-on-Unlock, disable Drop-on-Lock,
+	 * configure the requested (DSA/EDSA) tagging mode if this is
+	 * the CPU port, disable Header mode, enable IGMP/MLD snooping,
+	 * disable VLAN tunneling, determine priority by looking at
+	 * 802.1p and IP priority fields (IP prio has precedence), and
+	 * set STP state to Forwarding.  Finally, if this is the CPU
+	 * port, additionally enable forwarding of unknown unicast and
+	 * multicast addresses.
+	 */
+	REG_WRITE(addr, 0x04,
+			(p == ds->cpu_port) ?
+			 (ds->tag_protocol == htons(ETH_P_DSA)) ?
+			  0x053f : 0x373f :
+			 0x0433);
+
+	/*
+	 * Port Control 1: disable trunking.  Also, if this is the
+	 * CPU port, enable learn messages to be sent to this port.
+	 */
+	REG_WRITE(addr, 0x05, (p == ds->cpu_port) ? 0x8000 : 0x0000);
+
+	/*
+	 * Port based VLAN map: give each port its own address
+	 * database, allow the CPU port to talk to each of the 'real'
+	 * ports, and allow each of the 'real' ports to only talk to
+	 * the CPU port.
+	 */
+	REG_WRITE(addr, 0x06,
+			((p & 0xf) << 12) |
+			 ((p == ds->cpu_port) ?
+				ds->valid_port_mask :
+				(1 << ds->cpu_port)));
+
+	/*
+	 * Default VLAN ID and priority: don't set a default VLAN
+	 * ID, and set the default packet priority to zero.
+	 */
+	REG_WRITE(addr, 0x07, 0x0000);
+
+	/*
+	 * Port Control 2: don't force a good FCS, set the maximum
+	 * frame size to 10240 bytes, don't let the switch add or
+	 * strip 802.1q tags, don't discard tagged or untagged frames
+	 * on this port, do a destination address lookup on all
+	 * received packets as usual, disable ARP mirroring and don't
+	 * send a copy of all transmitted/received frames on this port
+	 * to the CPU.
+	 */
+	REG_WRITE(addr, 0x08, 0x2080);
+
+	/*
+	 * Egress rate control: disable egress rate control.
+	 */
+	REG_WRITE(addr, 0x09, 0x0001);
+
+	/*
+	 * Egress rate control 2: disable egress rate control.
+	 */
+	REG_WRITE(addr, 0x0a, 0x0000);
+
+	/*
+	 * Port Association Vector: when learning source addresses
+	 * of packets, add the address to the address database using
+	 * a port bitmap that has only the bit for this port set and
+	 * the other bits clear.
+	 */
+	REG_WRITE(addr, 0x0b, 1 << p);
+
+	/*
+	 * Port ATU control: disable limiting the number of address
+	 * database entries that this port is allowed to use.
+	 */
+	REG_WRITE(addr, 0x0c, 0x0000);
+
+	/*
+	 * Priorit Override: disable DA, SA and VTU priority override.
+	 */
+	REG_WRITE(addr, 0x0d, 0x0000);
+
+	/*
+	 * Port Ethertype: use the Ethertype DSA Ethertype value.
+	 */
+	REG_WRITE(addr, 0x0f, ETH_P_EDSA);
+
+	/*
+	 * Tag Remap: use an identity 802.1p prio -> switch prio
+	 * mapping.
+	 */
+	REG_WRITE(addr, 0x18, 0x3210);
+
+	/*
+	 * Tag Remap 2: use an identity 802.1p prio -> switch prio
+	 * mapping.
+	 */
+	REG_WRITE(addr, 0x19, 0x7654);
+
+	return 0;
+}
+
+static int mv88e6123_61_65_setup(struct dsa_switch *ds)
+{
+	struct mv88e6xxx_priv_state *ps = (void *)(ds + 1);
+	int i;
+	int ret;
+
+	mutex_init(&ps->smi_mutex);
+	mutex_init(&ps->stats_mutex);
+
+	ret = mv88e6123_61_65_switch_reset(ds);
+	if (ret < 0)
+		return ret;
+
+	/* @@@ initialise vtu and atu */
+
+	ret = mv88e6123_61_65_setup_global(ds);
+	if (ret < 0)
+		return ret;
+
+	for (i = 0; i < 6; i++) {
+		ret = mv88e6123_61_65_setup_port(ds, i);
+		if (ret < 0)
+			return ret;
+	}
+
+	return 0;
+}
+
+static int mv88e6123_61_65_port_to_phy_addr(int port)
+{
+	if (port >= 0 && port <= 4)
+		return port;
+	return -1;
+}
+
+static int
+mv88e6123_61_65_phy_read(struct dsa_switch *ds, int port, int regnum)
+{
+	int addr = mv88e6123_61_65_port_to_phy_addr(port);
+	return mv88e6xxx_phy_read(ds, addr, regnum);
+}
+
+static int
+mv88e6123_61_65_phy_write(struct dsa_switch *ds,
+			      int port, int regnum, u16 val)
+{
+	int addr = mv88e6123_61_65_port_to_phy_addr(port);
+	return mv88e6xxx_phy_write(ds, addr, regnum, val);
+}
+
+static struct mv88e6xxx_hw_stat mv88e6123_61_65_hw_stats[] = {
+	{ "in_good_octets", 8, 0x00, },
+	{ "in_bad_octets", 4, 0x02, },
+	{ "in_unicast", 4, 0x04, },
+	{ "in_broadcasts", 4, 0x06, },
+	{ "in_multicasts", 4, 0x07, },
+	{ "in_pause", 4, 0x16, },
+	{ "in_undersize", 4, 0x18, },
+	{ "in_fragments", 4, 0x19, },
+	{ "in_oversize", 4, 0x1a, },
+	{ "in_jabber", 4, 0x1b, },
+	{ "in_rx_error", 4, 0x1c, },
+	{ "in_fcs_error", 4, 0x1d, },
+	{ "out_octets", 8, 0x0e, },
+	{ "out_unicast", 4, 0x10, },
+	{ "out_broadcasts", 4, 0x13, },
+	{ "out_multicasts", 4, 0x12, },
+	{ "out_pause", 4, 0x15, },
+	{ "excessive", 4, 0x11, },
+	{ "collisions", 4, 0x1e, },
+	{ "deferred", 4, 0x05, },
+	{ "single", 4, 0x14, },
+	{ "multiple", 4, 0x17, },
+	{ "out_fcs_error", 4, 0x03, },
+	{ "late", 4, 0x1f, },
+	{ "hist_64bytes", 4, 0x08, },
+	{ "hist_65_127bytes", 4, 0x09, },
+	{ "hist_128_255bytes", 4, 0x0a, },
+	{ "hist_256_511bytes", 4, 0x0b, },
+	{ "hist_512_1023bytes", 4, 0x0c, },
+	{ "hist_1024_max_bytes", 4, 0x0d, },
+};
+
+static void
+mv88e6123_61_65_get_strings(struct dsa_switch *ds, int port, uint8_t *data)
+{
+	mv88e6xxx_get_strings(ds, ARRAY_SIZE(mv88e6123_61_65_hw_stats),
+			      mv88e6123_61_65_hw_stats, port, data);
+}
+
+static void
+mv88e6123_61_65_get_ethtool_stats(struct dsa_switch *ds,
+				  int port, uint64_t *data)
+{
+	mv88e6xxx_get_ethtool_stats(ds, ARRAY_SIZE(mv88e6123_61_65_hw_stats),
+				    mv88e6123_61_65_hw_stats, port, data);
+}
+
+static int mv88e6123_61_65_get_sset_count(struct dsa_switch *ds)
+{
+	return ARRAY_SIZE(mv88e6123_61_65_hw_stats);
+}
+
+static struct dsa_switch_driver mv88e6123_61_65_switch_driver = {
+	.tag_protocol		= __constant_htons(ETH_P_EDSA),
+	.priv_size		= sizeof(struct mv88e6xxx_priv_state),
+	.probe			= mv88e6123_61_65_probe,
+	.setup			= mv88e6123_61_65_setup,
+	.set_addr		= mv88e6xxx_set_addr_indirect,
+	.phy_read		= mv88e6123_61_65_phy_read,
+	.phy_write		= mv88e6123_61_65_phy_write,
+	.poll_link		= mv88e6xxx_poll_link,
+	.get_strings		= mv88e6123_61_65_get_strings,
+	.get_ethtool_stats	= mv88e6123_61_65_get_ethtool_stats,
+	.get_sset_count		= mv88e6123_61_65_get_sset_count,
+};
+
+int __init mv88e6123_61_65_init(void)
+{
+	register_switch_driver(&mv88e6123_61_65_switch_driver);
+	return 0;
+}
+module_init(mv88e6123_61_65_init);
+
+void __exit mv88e6123_61_65_cleanup(void)
+{
+	unregister_switch_driver(&mv88e6123_61_65_switch_driver);
+}
+module_exit(mv88e6123_61_65_cleanup);
diff --git a/net/dsa/mv88e6131.c b/net/dsa/mv88e6131.c
new file mode 100644
index 0000000..36e01eb
--- /dev/null
+++ b/net/dsa/mv88e6131.c
@@ -0,0 +1,380 @@
+/*
+ * net/dsa/mv88e6131.c - Marvell 88e6131 switch chip support
+ * Copyright (c) 2008 Marvell Semiconductor
+ *
+ * This program is free software; you can redistribute it and/or 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/list.h>
+#include <linux/netdevice.h>
+#include <linux/phy.h>
+#include "dsa_priv.h"
+#include "mv88e6xxx.h"
+
+static char *mv88e6131_probe(struct mii_bus *bus, int sw_addr)
+{
+	int ret;
+
+	ret = __mv88e6xxx_reg_read(bus, sw_addr, REG_PORT(0), 0x03);
+	if (ret >= 0) {
+		ret &= 0xfff0;
+		if (ret == 0x1060)
+			return "Marvell 88E6131";
+	}
+
+	return NULL;
+}
+
+static int mv88e6131_switch_reset(struct dsa_switch *ds)
+{
+	int i;
+	int ret;
+
+	/*
+	 * Set all ports to the disabled state.
+	 */
+	for (i = 0; i < 8; i++) {
+		ret = REG_READ(REG_PORT(i), 0x04);
+		REG_WRITE(REG_PORT(i), 0x04, ret & 0xfffc);
+	}
+
+	/*
+	 * Wait for transmit queues to drain.
+	 */
+	msleep(2);
+
+	/*
+	 * Reset the switch.
+	 */
+	REG_WRITE(REG_GLOBAL, 0x04, 0xc400);
+
+	/*
+	 * Wait up to one second for reset to complete.
+	 */
+	for (i = 0; i < 1000; i++) {
+		ret = REG_READ(REG_GLOBAL, 0x00);
+		if ((ret & 0xc800) == 0xc800)
+			break;
+
+		msleep(1);
+	}
+	if (i == 1000)
+		return -ETIMEDOUT;
+
+	return 0;
+}
+
+static int mv88e6131_setup_global(struct dsa_switch *ds)
+{
+	int ret;
+	int i;
+
+	/*
+	 * Enable the PHY polling unit, don't discard packets with
+	 * excessive collisions, use a weighted fair queueing scheme
+	 * to arbitrate between packet queues, set the maximum frame
+	 * size to 1632, and mask all interrupt sources.
+	 */
+	REG_WRITE(REG_GLOBAL, 0x04, 0x4400);
+
+	/*
+	 * Set the default address aging time to 5 minutes, and
+	 * enable address learn messages to be sent to all message
+	 * ports.
+	 */
+	REG_WRITE(REG_GLOBAL, 0x0a, 0x0148);
+
+	/*
+	 * Configure the priority mapping registers.
+	 */
+	ret = mv88e6xxx_config_prio(ds);
+	if (ret < 0)
+		return ret;
+
+	/*
+	 * Set the VLAN ethertype to 0x8100.
+	 */
+	REG_WRITE(REG_GLOBAL, 0x19, 0x8100);
+
+	/*
+	 * Disable ARP mirroring, and configure the cpu port as the
+	 * port to which ingress and egress monitor frames are to be
+	 * sent.
+	 */
+	REG_WRITE(REG_GLOBAL, 0x1a, (ds->cpu_port * 0x1100) | 0x00f0);
+
+	/*
+	 * Disable cascade port functionality, and set the switch's
+	 * DSA device number to zero.
+	 */
+	REG_WRITE(REG_GLOBAL, 0x1c, 0xe000);
+
+	/*
+	 * Send all frames with destination addresses matching
+	 * 01:80:c2:00:00:0x to the CPU port.
+	 */
+	REG_WRITE(REG_GLOBAL2, 0x03, 0xffff);
+
+	/*
+	 * Ignore removed tag data on doubly tagged packets, disable
+	 * flow control messages, force flow control priority to the
+	 * highest, and send all special multicast frames to the CPU
+	 * port at the higest priority.
+	 */
+	REG_WRITE(REG_GLOBAL2, 0x05, 0x00ff);
+
+	/*
+	 * Map all DSA device IDs to the CPU port.
+	 */
+	for (i = 0; i < 32; i++)
+		REG_WRITE(REG_GLOBAL2, 0x06, 0x8000 | (i << 8) | ds->cpu_port);
+
+	/*
+	 * Clear all trunk masks.
+	 */
+	for (i = 0; i < 8; i++)
+		REG_WRITE(REG_GLOBAL2, 0x07, 0x8000 | (i << 12) | 0xff);
+
+	/*
+	 * Clear all trunk mappings.
+	 */
+	for (i = 0; i < 16; i++)
+		REG_WRITE(REG_GLOBAL2, 0x08, 0x8000 | (i << 11));
+
+	/*
+	 * Force the priority of IGMP/MLD snoop frames and ARP frames
+	 * to the highest setting.
+	 */
+	REG_WRITE(REG_GLOBAL2, 0x0f, 0x00ff);
+
+	return 0;
+}
+
+static int mv88e6131_setup_port(struct dsa_switch *ds, int p)
+{
+	int addr = REG_PORT(p);
+
+	/*
+	 * MAC Forcing register: don't force link, speed, duplex
+	 * or flow control state to any particular values.
+	 */
+	REG_WRITE(addr, 0x01, 0x0003);
+
+	/*
+	 * Port Control: disable Core Tag, disable Drop-on-Lock,
+	 * transmit frames unmodified, disable Header mode,
+	 * enable IGMP/MLD snoop, disable DoubleTag, disable VLAN
+	 * tunneling, determine priority by looking at 802.1p and
+	 * IP priority fields (IP prio has precedence), and set STP
+	 * state to Forwarding.  Finally, if this is the CPU port,
+	 * additionally enable DSA tagging and forwarding of unknown
+	 * unicast addresses.
+	 */
+	REG_WRITE(addr, 0x04, (p == ds->cpu_port) ? 0x0537 : 0x0433);
+
+	/*
+	 * Port Control 1: disable trunking.  Also, if this is the
+	 * CPU port, enable learn messages to be sent to this port.
+	 */
+	REG_WRITE(addr, 0x05, (p == ds->cpu_port) ? 0x8000 : 0x0000);
+
+	/*
+	 * Port based VLAN map: give each port its own address
+	 * database, allow the CPU port to talk to each of the 'real'
+	 * ports, and allow each of the 'real' ports to only talk to
+	 * the CPU port.
+	 */
+	REG_WRITE(addr, 0x06,
+			((p & 0xf) << 12) |
+			 ((p == ds->cpu_port) ?
+				ds->valid_port_mask :
+				(1 << ds->cpu_port)));
+
+	/*
+	 * Default VLAN ID and priority: don't set a default VLAN
+	 * ID, and set the default packet priority to zero.
+	 */
+	REG_WRITE(addr, 0x07, 0x0000);
+
+	/*
+	 * Port Control 2: don't force a good FCS, don't use
+	 * VLAN-based, source address-based or destination
+	 * address-based priority overrides, don't let the switch
+	 * add or strip 802.1q tags, don't discard tagged or
+	 * untagged frames on this port, do a destination address
+	 * lookup on received packets as usual, don't send a copy
+	 * of all transmitted/received frames on this port to the
+	 * CPU, and configure the CPU port number.  Also, if this
+	 * is the CPU port, enable forwarding of unknown multicast
+	 * addresses.
+	 */
+	REG_WRITE(addr, 0x08,
+			((p == ds->cpu_port) ? 0x00c0 : 0x0080) |
+			 ds->cpu_port);
+
+	/*
+	 * Rate Control: disable ingress rate limiting.
+	 */
+	REG_WRITE(addr, 0x09, 0x0000);
+
+	/*
+	 * Rate Control 2: disable egress rate limiting.
+	 */
+	REG_WRITE(addr, 0x0a, 0x0000);
+
+	/*
+	 * Port Association Vector: when learning source addresses
+	 * of packets, add the address to the address database using
+	 * a port bitmap that has only the bit for this port set and
+	 * the other bits clear.
+	 */
+	REG_WRITE(addr, 0x0b, 1 << p);
+
+	/*
+	 * Tag Remap: use an identity 802.1p prio -> switch prio
+	 * mapping.
+	 */
+	REG_WRITE(addr, 0x18, 0x3210);
+
+	/*
+	 * Tag Remap 2: use an identity 802.1p prio -> switch prio
+	 * mapping.
+	 */
+	REG_WRITE(addr, 0x19, 0x7654);
+
+	return 0;
+}
+
+static int mv88e6131_setup(struct dsa_switch *ds)
+{
+	struct mv88e6xxx_priv_state *ps = (void *)(ds + 1);
+	int i;
+	int ret;
+
+	mutex_init(&ps->smi_mutex);
+	mv88e6xxx_ppu_state_init(ds);
+	mutex_init(&ps->stats_mutex);
+
+	ret = mv88e6131_switch_reset(ds);
+	if (ret < 0)
+		return ret;
+
+	/* @@@ initialise vtu and atu */
+
+	ret = mv88e6131_setup_global(ds);
+	if (ret < 0)
+		return ret;
+
+	for (i = 0; i < 6; i++) {
+		ret = mv88e6131_setup_port(ds, i);
+		if (ret < 0)
+			return ret;
+	}
+
+	return 0;
+}
+
+static int mv88e6131_port_to_phy_addr(int port)
+{
+	if (port >= 0 && port != 3 && port <= 7)
+		return port;
+	return -1;
+}
+
+static int
+mv88e6131_phy_read(struct dsa_switch *ds, int port, int regnum)
+{
+	int addr = mv88e6131_port_to_phy_addr(port);
+	return mv88e6xxx_phy_read_ppu(ds, addr, regnum);
+}
+
+static int
+mv88e6131_phy_write(struct dsa_switch *ds,
+			      int port, int regnum, u16 val)
+{
+	int addr = mv88e6131_port_to_phy_addr(port);
+	return mv88e6xxx_phy_write_ppu(ds, addr, regnum, val);
+}
+
+static struct mv88e6xxx_hw_stat mv88e6131_hw_stats[] = {
+	{ "in_good_octets", 8, 0x00, },
+	{ "in_bad_octets", 4, 0x02, },
+	{ "in_unicast", 4, 0x04, },
+	{ "in_broadcasts", 4, 0x06, },
+	{ "in_multicasts", 4, 0x07, },
+	{ "in_pause", 4, 0x16, },
+	{ "in_undersize", 4, 0x18, },
+	{ "in_fragments", 4, 0x19, },
+	{ "in_oversize", 4, 0x1a, },
+	{ "in_jabber", 4, 0x1b, },
+	{ "in_rx_error", 4, 0x1c, },
+	{ "in_fcs_error", 4, 0x1d, },
+	{ "out_octets", 8, 0x0e, },
+	{ "out_unicast", 4, 0x10, },
+	{ "out_broadcasts", 4, 0x13, },
+	{ "out_multicasts", 4, 0x12, },
+	{ "out_pause", 4, 0x15, },
+	{ "excessive", 4, 0x11, },
+	{ "collisions", 4, 0x1e, },
+	{ "deferred", 4, 0x05, },
+	{ "single", 4, 0x14, },
+	{ "multiple", 4, 0x17, },
+	{ "out_fcs_error", 4, 0x03, },
+	{ "late", 4, 0x1f, },
+	{ "hist_64bytes", 4, 0x08, },
+	{ "hist_65_127bytes", 4, 0x09, },
+	{ "hist_128_255bytes", 4, 0x0a, },
+	{ "hist_256_511bytes", 4, 0x0b, },
+	{ "hist_512_1023bytes", 4, 0x0c, },
+	{ "hist_1024_max_bytes", 4, 0x0d, },
+};
+
+static void
+mv88e6131_get_strings(struct dsa_switch *ds, int port, uint8_t *data)
+{
+	mv88e6xxx_get_strings(ds, ARRAY_SIZE(mv88e6131_hw_stats),
+			      mv88e6131_hw_stats, port, data);
+}
+
+static void
+mv88e6131_get_ethtool_stats(struct dsa_switch *ds,
+				  int port, uint64_t *data)
+{
+	mv88e6xxx_get_ethtool_stats(ds, ARRAY_SIZE(mv88e6131_hw_stats),
+				    mv88e6131_hw_stats, port, data);
+}
+
+static int mv88e6131_get_sset_count(struct dsa_switch *ds)
+{
+	return ARRAY_SIZE(mv88e6131_hw_stats);
+}
+
+static struct dsa_switch_driver mv88e6131_switch_driver = {
+	.tag_protocol		= __constant_htons(ETH_P_DSA),
+	.priv_size		= sizeof(struct mv88e6xxx_priv_state),
+	.probe			= mv88e6131_probe,
+	.setup			= mv88e6131_setup,
+	.set_addr		= mv88e6xxx_set_addr_direct,
+	.phy_read		= mv88e6131_phy_read,
+	.phy_write		= mv88e6131_phy_write,
+	.poll_link		= mv88e6xxx_poll_link,
+	.get_strings		= mv88e6131_get_strings,
+	.get_ethtool_stats	= mv88e6131_get_ethtool_stats,
+	.get_sset_count		= mv88e6131_get_sset_count,
+};
+
+int __init mv88e6131_init(void)
+{
+	register_switch_driver(&mv88e6131_switch_driver);
+	return 0;
+}
+module_init(mv88e6131_init);
+
+void __exit mv88e6131_cleanup(void)
+{
+	unregister_switch_driver(&mv88e6131_switch_driver);
+}
+module_exit(mv88e6131_cleanup);
diff --git a/net/dsa/mv88e6xxx.c b/net/dsa/mv88e6xxx.c
new file mode 100644
index 0000000..aa6c609
--- /dev/null
+++ b/net/dsa/mv88e6xxx.c
@@ -0,0 +1,522 @@
+/*
+ * net/dsa/mv88e6xxx.c - Marvell 88e6xxx switch chip support
+ * Copyright (c) 2008 Marvell Semiconductor
+ *
+ * This program is free software; you can redistribute it and/or 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/list.h>
+#include <linux/netdevice.h>
+#include <linux/phy.h>
+#include "dsa_priv.h"
+#include "mv88e6xxx.h"
+
+/*
+ * If the switch's ADDR[4:0] strap pins are strapped to zero, it will
+ * use all 32 SMI bus addresses on its SMI bus, and all switch registers
+ * will be directly accessible on some {device address,register address}
+ * pair.  If the ADDR[4:0] pins are not strapped to zero, the switch
+ * will only respond to SMI transactions to that specific address, and
+ * an indirect addressing mechanism needs to be used to access its
+ * registers.
+ */
+static int mv88e6xxx_reg_wait_ready(struct mii_bus *bus, int sw_addr)
+{
+	int ret;
+	int i;
+
+	for (i = 0; i < 16; i++) {
+		ret = mdiobus_read(bus, sw_addr, 0);
+		if (ret < 0)
+			return ret;
+
+		if ((ret & 0x8000) == 0)
+			return 0;
+	}
+
+	return -ETIMEDOUT;
+}
+
+int __mv88e6xxx_reg_read(struct mii_bus *bus, int sw_addr, int addr, int reg)
+{
+	int ret;
+
+	if (sw_addr == 0)
+		return mdiobus_read(bus, addr, reg);
+
+	/*
+	 * Wait for the bus to become free.
+	 */
+	ret = mv88e6xxx_reg_wait_ready(bus, sw_addr);
+	if (ret < 0)
+		return ret;
+
+	/*
+	 * Transmit the read command.
+	 */
+	ret = mdiobus_write(bus, sw_addr, 0, 0x9800 | (addr << 5) | reg);
+	if (ret < 0)
+		return ret;
+
+	/*
+	 * Wait for the read command to complete.
+	 */
+	ret = mv88e6xxx_reg_wait_ready(bus, sw_addr);
+	if (ret < 0)
+		return ret;
+
+	/*
+	 * Read the data.
+	 */
+	ret = mdiobus_read(bus, sw_addr, 1);
+	if (ret < 0)
+		return ret;
+
+	return ret & 0xffff;
+}
+
+int mv88e6xxx_reg_read(struct dsa_switch *ds, int addr, int reg)
+{
+	struct mv88e6xxx_priv_state *ps = (void *)(ds + 1);
+	int ret;
+
+	mutex_lock(&ps->smi_mutex);
+	ret = __mv88e6xxx_reg_read(ds->master_mii_bus,
+				   ds->pd->sw_addr, addr, reg);
+	mutex_unlock(&ps->smi_mutex);
+
+	return ret;
+}
+
+int __mv88e6xxx_reg_write(struct mii_bus *bus, int sw_addr, int addr,
+			  int reg, u16 val)
+{
+	int ret;
+
+	if (sw_addr == 0)
+		return mdiobus_write(bus, addr, reg, val);
+
+	/*
+	 * Wait for the bus to become free.
+	 */
+	ret = mv88e6xxx_reg_wait_ready(bus, sw_addr);
+	if (ret < 0)
+		return ret;
+
+	/*
+	 * Transmit the data to write.
+	 */
+	ret = mdiobus_write(bus, sw_addr, 1, val);
+	if (ret < 0)
+		return ret;
+
+	/*
+	 * Transmit the write command.
+	 */
+	ret = mdiobus_write(bus, sw_addr, 0, 0x9400 | (addr << 5) | reg);
+	if (ret < 0)
+		return ret;
+
+	/*
+	 * Wait for the write command to complete.
+	 */
+	ret = mv88e6xxx_reg_wait_ready(bus, sw_addr);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+int mv88e6xxx_reg_write(struct dsa_switch *ds, int addr, int reg, u16 val)
+{
+	struct mv88e6xxx_priv_state *ps = (void *)(ds + 1);
+	int ret;
+
+	mutex_lock(&ps->smi_mutex);
+	ret = __mv88e6xxx_reg_write(ds->master_mii_bus,
+				    ds->pd->sw_addr, addr, reg, val);
+	mutex_unlock(&ps->smi_mutex);
+
+	return ret;
+}
+
+int mv88e6xxx_config_prio(struct dsa_switch *ds)
+{
+	/*
+	 * Configure the IP ToS mapping registers.
+	 */
+	REG_WRITE(REG_GLOBAL, 0x10, 0x0000);
+	REG_WRITE(REG_GLOBAL, 0x11, 0x0000);
+	REG_WRITE(REG_GLOBAL, 0x12, 0x5555);
+	REG_WRITE(REG_GLOBAL, 0x13, 0x5555);
+	REG_WRITE(REG_GLOBAL, 0x14, 0xaaaa);
+	REG_WRITE(REG_GLOBAL, 0x15, 0xaaaa);
+	REG_WRITE(REG_GLOBAL, 0x16, 0xffff);
+	REG_WRITE(REG_GLOBAL, 0x17, 0xffff);
+
+	/*
+	 * Configure the IEEE 802.1p priority mapping register.
+	 */
+	REG_WRITE(REG_GLOBAL, 0x18, 0xfa41);
+
+	return 0;
+}
+
+int mv88e6xxx_set_addr_direct(struct dsa_switch *ds, u8 *addr)
+{
+	REG_WRITE(REG_GLOBAL, 0x01, (addr[0] << 8) | addr[1]);
+	REG_WRITE(REG_GLOBAL, 0x02, (addr[2] << 8) | addr[3]);
+	REG_WRITE(REG_GLOBAL, 0x03, (addr[4] << 8) | addr[5]);
+
+	return 0;
+}
+
+int mv88e6xxx_set_addr_indirect(struct dsa_switch *ds, u8 *addr)
+{
+	int i;
+	int ret;
+
+	for (i = 0; i < 6; i++) {
+		int j;
+
+		/*
+		 * Write the MAC address byte.
+		 */
+		REG_WRITE(REG_GLOBAL2, 0x0d, 0x8000 | (i << 8) | addr[i]);
+
+		/*
+		 * Wait for the write to complete.
+		 */
+		for (j = 0; j < 16; j++) {
+			ret = REG_READ(REG_GLOBAL2, 0x0d);
+			if ((ret & 0x8000) == 0)
+				break;
+		}
+		if (j == 16)
+			return -ETIMEDOUT;
+	}
+
+	return 0;
+}
+
+int mv88e6xxx_phy_read(struct dsa_switch *ds, int addr, int regnum)
+{
+	if (addr >= 0)
+		return mv88e6xxx_reg_read(ds, addr, regnum);
+	return 0xffff;
+}
+
+int mv88e6xxx_phy_write(struct dsa_switch *ds, int addr, int regnum, u16 val)
+{
+	if (addr >= 0)
+		return mv88e6xxx_reg_write(ds, addr, regnum, val);
+	return 0;
+}
+
+#ifdef CONFIG_NET_DSA_MV88E6XXX_NEED_PPU
+static int mv88e6xxx_ppu_disable(struct dsa_switch *ds)
+{
+	int ret;
+	int i;
+
+	ret = REG_READ(REG_GLOBAL, 0x04);
+	REG_WRITE(REG_GLOBAL, 0x04, ret & ~0x4000);
+
+	for (i = 0; i < 1000; i++) {
+	        ret = REG_READ(REG_GLOBAL, 0x00);
+	        msleep(1);
+	        if ((ret & 0xc000) != 0xc000)
+	                return 0;
+	}
+
+	return -ETIMEDOUT;
+}
+
+static int mv88e6xxx_ppu_enable(struct dsa_switch *ds)
+{
+	int ret;
+	int i;
+
+	ret = REG_READ(REG_GLOBAL, 0x04);
+	REG_WRITE(REG_GLOBAL, 0x04, ret | 0x4000);
+
+	for (i = 0; i < 1000; i++) {
+	        ret = REG_READ(REG_GLOBAL, 0x00);
+	        msleep(1);
+	        if ((ret & 0xc000) == 0xc000)
+	                return 0;
+	}
+
+	return -ETIMEDOUT;
+}
+
+static void mv88e6xxx_ppu_reenable_work(struct work_struct *ugly)
+{
+	struct mv88e6xxx_priv_state *ps;
+
+	ps = container_of(ugly, struct mv88e6xxx_priv_state, ppu_work);
+	if (mutex_trylock(&ps->ppu_mutex)) {
+	        struct dsa_switch *ds = ((struct dsa_switch *)ps) - 1;
+
+	        if (mv88e6xxx_ppu_enable(ds) == 0)
+	                ps->ppu_disabled = 0;
+	        mutex_unlock(&ps->ppu_mutex);
+	}
+}
+
+static void mv88e6xxx_ppu_reenable_timer(unsigned long _ps)
+{
+	struct mv88e6xxx_priv_state *ps = (void *)_ps;
+
+	schedule_work(&ps->ppu_work);
+}
+
+static int mv88e6xxx_ppu_access_get(struct dsa_switch *ds)
+{
+	struct mv88e6xxx_priv_state *ps = (void *)(ds + 1);
+	int ret;
+
+	mutex_lock(&ps->ppu_mutex);
+
+	/*
+	 * If the PHY polling unit is enabled, disable it so that
+	 * we can access the PHY registers.  If it was already
+	 * disabled, cancel the timer that is going to re-enable
+	 * it.
+	 */
+	if (!ps->ppu_disabled) {
+	        ret = mv88e6xxx_ppu_disable(ds);
+	        if (ret < 0) {
+	                mutex_unlock(&ps->ppu_mutex);
+	                return ret;
+	        }
+	        ps->ppu_disabled = 1;
+	} else {
+	        del_timer(&ps->ppu_timer);
+	        ret = 0;
+	}
+
+	return ret;
+}
+
+static void mv88e6xxx_ppu_access_put(struct dsa_switch *ds)
+{
+	struct mv88e6xxx_priv_state *ps = (void *)(ds + 1);
+
+	/*
+	 * Schedule a timer to re-enable the PHY polling unit.
+	 */
+	mod_timer(&ps->ppu_timer, jiffies + msecs_to_jiffies(10));
+	mutex_unlock(&ps->ppu_mutex);
+}
+
+void mv88e6xxx_ppu_state_init(struct dsa_switch *ds)
+{
+	struct mv88e6xxx_priv_state *ps = (void *)(ds + 1);
+
+	mutex_init(&ps->ppu_mutex);
+	INIT_WORK(&ps->ppu_work, mv88e6xxx_ppu_reenable_work);
+	init_timer(&ps->ppu_timer);
+	ps->ppu_timer.data = (unsigned long)ps;
+	ps->ppu_timer.function = mv88e6xxx_ppu_reenable_timer;
+}
+
+int mv88e6xxx_phy_read_ppu(struct dsa_switch *ds, int addr, int regnum)
+{
+	int ret;
+
+	ret = mv88e6xxx_ppu_access_get(ds);
+	if (ret >= 0) {
+	        ret = mv88e6xxx_reg_read(ds, addr, regnum);
+	        mv88e6xxx_ppu_access_put(ds);
+	}
+
+	return ret;
+}
+
+int mv88e6xxx_phy_write_ppu(struct dsa_switch *ds, int addr,
+			    int regnum, u16 val)
+{
+	int ret;
+
+	ret = mv88e6xxx_ppu_access_get(ds);
+	if (ret >= 0) {
+	        ret = mv88e6xxx_reg_write(ds, addr, regnum, val);
+	        mv88e6xxx_ppu_access_put(ds);
+	}
+
+	return ret;
+}
+#endif
+
+void mv88e6xxx_poll_link(struct dsa_switch *ds)
+{
+	int i;
+
+	for (i = 0; i < DSA_MAX_PORTS; i++) {
+		struct net_device *dev;
+		int port_status;
+		int link;
+		int speed;
+		int duplex;
+		int fc;
+
+		dev = ds->ports[i];
+		if (dev == NULL)
+			continue;
+
+		link = 0;
+		if (dev->flags & IFF_UP) {
+			port_status = mv88e6xxx_reg_read(ds, REG_PORT(i), 0x00);
+			if (port_status < 0)
+				continue;
+
+			link = !!(port_status & 0x0800);
+		}
+
+		if (!link) {
+			if (netif_carrier_ok(dev)) {
+				printk(KERN_INFO "%s: link down\n", dev->name);
+				netif_carrier_off(dev);
+			}
+			continue;
+		}
+
+		switch (port_status & 0x0300) {
+		case 0x0000:
+			speed = 10;
+			break;
+		case 0x0100:
+			speed = 100;
+			break;
+		case 0x0200:
+			speed = 1000;
+			break;
+		default:
+			speed = -1;
+			break;
+		}
+		duplex = (port_status & 0x0400) ? 1 : 0;
+		fc = (port_status & 0x8000) ? 1 : 0;
+
+		if (!netif_carrier_ok(dev)) {
+			printk(KERN_INFO "%s: link up, %d Mb/s, %s duplex, "
+					 "flow control %sabled\n", dev->name,
+					 speed, duplex ? "full" : "half",
+					 fc ? "en" : "dis");
+			netif_carrier_on(dev);
+		}
+	}
+}
+
+static int mv88e6xxx_stats_wait(struct dsa_switch *ds)
+{
+	int ret;
+	int i;
+
+	for (i = 0; i < 10; i++) {
+		ret = REG_READ(REG_GLOBAL2, 0x1d);
+		if ((ret & 0x8000) == 0)
+			return 0;
+	}
+
+	return -ETIMEDOUT;
+}
+
+static int mv88e6xxx_stats_snapshot(struct dsa_switch *ds, int port)
+{
+	int ret;
+
+	/*
+	 * Snapshot the hardware statistics counters for this port.
+	 */
+	REG_WRITE(REG_GLOBAL, 0x1d, 0xdc00 | port);
+
+	/*
+	 * Wait for the snapshotting to complete.
+	 */
+	ret = mv88e6xxx_stats_wait(ds);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static void mv88e6xxx_stats_read(struct dsa_switch *ds, int stat, u32 *val)
+{
+	u32 _val;
+	int ret;
+
+	*val = 0;
+
+	ret = mv88e6xxx_reg_write(ds, REG_GLOBAL, 0x1d, 0xcc00 | stat);
+	if (ret < 0)
+		return;
+
+	ret = mv88e6xxx_stats_wait(ds);
+	if (ret < 0)
+		return;
+
+	ret = mv88e6xxx_reg_read(ds, REG_GLOBAL, 0x1e);
+	if (ret < 0)
+		return;
+
+	_val = ret << 16;
+
+	ret = mv88e6xxx_reg_read(ds, REG_GLOBAL, 0x1f);
+	if (ret < 0)
+		return;
+
+	*val = _val | ret;
+}
+
+void mv88e6xxx_get_strings(struct dsa_switch *ds,
+			   int nr_stats, struct mv88e6xxx_hw_stat *stats,
+			   int port, uint8_t *data)
+{
+	int i;
+
+	for (i = 0; i < nr_stats; i++) {
+		memcpy(data + i * ETH_GSTRING_LEN,
+		       stats[i].string, ETH_GSTRING_LEN);
+	}
+}
+
+void mv88e6xxx_get_ethtool_stats(struct dsa_switch *ds,
+				 int nr_stats, struct mv88e6xxx_hw_stat *stats,
+				 int port, uint64_t *data)
+{
+	struct mv88e6xxx_priv_state *ps = (void *)(ds + 1);
+	int ret;
+	int i;
+
+	mutex_lock(&ps->stats_mutex);
+
+	ret = mv88e6xxx_stats_snapshot(ds, port);
+	if (ret < 0) {
+		mutex_unlock(&ps->stats_mutex);
+		return;
+	}
+
+	/*
+	 * Read each of the counters.
+	 */
+	for (i = 0; i < nr_stats; i++) {
+		struct mv88e6xxx_hw_stat *s = stats + i;
+		u32 low;
+		u32 high;
+
+		mv88e6xxx_stats_read(ds, s->reg, &low);
+		if (s->sizeof_stat == 8)
+			mv88e6xxx_stats_read(ds, s->reg + 1, &high);
+		else
+			high = 0;
+
+		data[i] = (((u64)high) << 32) | low;
+	}
+
+	mutex_unlock(&ps->stats_mutex);
+}
diff --git a/net/dsa/mv88e6xxx.h b/net/dsa/mv88e6xxx.h
new file mode 100644
index 0000000..eb0e0aa
--- /dev/null
+++ b/net/dsa/mv88e6xxx.h
@@ -0,0 +1,93 @@
+/*
+ * net/dsa/mv88e6xxx.h - Marvell 88e6xxx switch chip support
+ * Copyright (c) 2008 Marvell Semiconductor
+ *
+ * This program is free software; you can redistribute it and/or 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 __MV88E6XXX_H
+#define __MV88E6XXX_H
+
+#define REG_PORT(p)		(0x10 + (p))
+#define REG_GLOBAL		0x1b
+#define REG_GLOBAL2		0x1c
+
+struct mv88e6xxx_priv_state {
+	/*
+	 * When using multi-chip addressing, this mutex protects
+	 * access to the indirect access registers.  (In single-chip
+	 * mode, this mutex is effectively useless.)
+	 */
+	struct mutex	smi_mutex;
+
+#ifdef CONFIG_NET_DSA_MV88E6XXX_NEED_PPU
+	/*
+	 * Handles automatic disabling and re-enabling of the PHY
+	 * polling unit.
+	 */
+	struct mutex		ppu_mutex;
+	int			ppu_disabled;
+	struct work_struct	ppu_work;
+	struct timer_list	ppu_timer;
+#endif
+
+	/*
+	 * This mutex serialises access to the statistics unit.
+	 * Hold this mutex over snapshot + dump sequences.
+	 */
+	struct mutex	stats_mutex;
+};
+
+struct mv88e6xxx_hw_stat {
+	char string[ETH_GSTRING_LEN];
+	int sizeof_stat;
+	int reg;
+};
+
+int __mv88e6xxx_reg_read(struct mii_bus *bus, int sw_addr, int addr, int reg);
+int mv88e6xxx_reg_read(struct dsa_switch *ds, int addr, int reg);
+int __mv88e6xxx_reg_write(struct mii_bus *bus, int sw_addr, int addr,
+                          int reg, u16 val);
+int mv88e6xxx_reg_write(struct dsa_switch *ds, int addr, int reg, u16 val);
+int mv88e6xxx_config_prio(struct dsa_switch *ds);
+int mv88e6xxx_set_addr_direct(struct dsa_switch *ds, u8 *addr);
+int mv88e6xxx_set_addr_indirect(struct dsa_switch *ds, u8 *addr);
+int mv88e6xxx_phy_read(struct dsa_switch *ds, int addr, int regnum);
+int mv88e6xxx_phy_write(struct dsa_switch *ds, int addr, int regnum, u16 val);
+void mv88e6xxx_ppu_state_init(struct dsa_switch *ds);
+int mv88e6xxx_phy_read_ppu(struct dsa_switch *ds, int addr, int regnum);
+int mv88e6xxx_phy_write_ppu(struct dsa_switch *ds, int addr,
+			    int regnum, u16 val);
+void mv88e6xxx_poll_link(struct dsa_switch *ds);
+void mv88e6xxx_get_strings(struct dsa_switch *ds,
+			   int nr_stats, struct mv88e6xxx_hw_stat *stats,
+			   int port, uint8_t *data);
+void mv88e6xxx_get_ethtool_stats(struct dsa_switch *ds,
+				 int nr_stats, struct mv88e6xxx_hw_stat *stats,
+				 int port, uint64_t *data);
+
+#define REG_READ(addr, reg)						\
+	({								\
+		int __ret;						\
+									\
+		__ret = mv88e6xxx_reg_read(ds, addr, reg);		\
+		if (__ret < 0)						\
+			return __ret;					\
+		__ret;							\
+	})
+
+#define REG_WRITE(addr, reg, val)					\
+	({								\
+		int __ret;						\
+									\
+		__ret = mv88e6xxx_reg_write(ds, addr, reg, val);	\
+		if (__ret < 0)						\
+			return __ret;					\
+	})
+
+
+
+#endif
diff --git a/net/dsa/slave.c b/net/dsa/slave.c
new file mode 100644
index 0000000..3761688
--- /dev/null
+++ b/net/dsa/slave.c
@@ -0,0 +1,298 @@
+/*
+ * net/dsa/slave.c - Slave device handling
+ * Copyright (c) 2008 Marvell Semiconductor
+ *
+ * This program is free software; you can redistribute it and/or 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/list.h>
+#include <linux/netdevice.h>
+#include <linux/phy.h>
+#include "dsa_priv.h"
+
+/* slave mii_bus handling ***************************************************/
+static int dsa_slave_phy_read(struct mii_bus *bus, int addr, int reg)
+{
+	struct dsa_switch *ds = bus->priv;
+
+	if (ds->valid_port_mask & (1 << addr))
+		return ds->drv->phy_read(ds, addr, reg);
+
+	return 0xffff;
+}
+
+static int dsa_slave_phy_write(struct mii_bus *bus, int addr, int reg, u16 val)
+{
+	struct dsa_switch *ds = bus->priv;
+
+	if (ds->valid_port_mask & (1 << addr))
+		return ds->drv->phy_write(ds, addr, reg, val);
+
+	return 0;
+}
+
+void dsa_slave_mii_bus_init(struct dsa_switch *ds)
+{
+	ds->slave_mii_bus->priv = (void *)ds;
+	ds->slave_mii_bus->name = "dsa slave smi";
+	ds->slave_mii_bus->read = dsa_slave_phy_read;
+	ds->slave_mii_bus->write = dsa_slave_phy_write;
+	snprintf(ds->slave_mii_bus->id, MII_BUS_ID_SIZE, "%s:%.2x",
+			ds->master_mii_bus->id, ds->pd->sw_addr);
+	ds->slave_mii_bus->parent = &(ds->master_mii_bus->dev);
+}
+
+
+/* slave device handling ****************************************************/
+static int dsa_slave_open(struct net_device *dev)
+{
+	return 0;
+}
+
+static int dsa_slave_close(struct net_device *dev)
+{
+	return 0;
+}
+
+static void dsa_slave_change_rx_flags(struct net_device *dev, int change)
+{
+	struct dsa_slave_priv *p = netdev_priv(dev);
+	struct net_device *master = p->parent->master_netdev;
+
+	if (change & IFF_ALLMULTI)
+		dev_set_allmulti(master, dev->flags & IFF_ALLMULTI ? 1 : -1);
+	if (change & IFF_PROMISC)
+		dev_set_promiscuity(master, dev->flags & IFF_PROMISC ? 1 : -1);
+}
+
+static void dsa_slave_set_rx_mode(struct net_device *dev)
+{
+	struct dsa_slave_priv *p = netdev_priv(dev);
+	struct net_device *master = p->parent->master_netdev;
+
+	dev_mc_sync(master, dev);
+	dev_unicast_sync(master, dev);
+}
+
+static int dsa_slave_set_mac_address(struct net_device *dev, void *addr)
+{
+	memcpy(dev->dev_addr, addr + 2, 6);
+
+	return 0;
+}
+
+static int dsa_slave_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+	struct dsa_slave_priv *p = netdev_priv(dev);
+	struct mii_ioctl_data *mii_data = if_mii(ifr);
+
+	if (p->phy != NULL)
+		return phy_mii_ioctl(p->phy, mii_data, cmd);
+
+	return -EOPNOTSUPP;
+}
+
+
+/* ethtool operations *******************************************************/
+static int
+dsa_slave_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+	struct dsa_slave_priv *p = netdev_priv(dev);
+	int err;
+
+	err = -EOPNOTSUPP;
+	if (p->phy != NULL) {
+		err = phy_read_status(p->phy);
+		if (err == 0)
+			err = phy_ethtool_gset(p->phy, cmd);
+	}
+
+	return err;
+}
+
+static int
+dsa_slave_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+	struct dsa_slave_priv *p = netdev_priv(dev);
+
+	if (p->phy != NULL)
+		return phy_ethtool_sset(p->phy, cmd);
+
+	return -EOPNOTSUPP;
+}
+
+static void dsa_slave_get_drvinfo(struct net_device *dev,
+				  struct ethtool_drvinfo *drvinfo)
+{
+	strncpy(drvinfo->driver, "dsa", 32);
+	strncpy(drvinfo->version, dsa_driver_version, 32);
+	strncpy(drvinfo->fw_version, "N/A", 32);
+	strncpy(drvinfo->bus_info, "platform", 32);
+}
+
+static int dsa_slave_nway_reset(struct net_device *dev)
+{
+	struct dsa_slave_priv *p = netdev_priv(dev);
+
+	if (p->phy != NULL)
+		return genphy_restart_aneg(p->phy);
+
+	return -EOPNOTSUPP;
+}
+
+static u32 dsa_slave_get_link(struct net_device *dev)
+{
+	struct dsa_slave_priv *p = netdev_priv(dev);
+
+	if (p->phy != NULL) {
+		genphy_update_link(p->phy);
+		return p->phy->link;
+	}
+
+	return -EOPNOTSUPP;
+}
+
+static void dsa_slave_get_strings(struct net_device *dev,
+				  uint32_t stringset, uint8_t *data)
+{
+	struct dsa_slave_priv *p = netdev_priv(dev);
+	struct dsa_switch *ds = p->parent;
+
+	if (stringset == ETH_SS_STATS) {
+		int len = ETH_GSTRING_LEN;
+
+		strncpy(data, "tx_packets", len);
+		strncpy(data + len, "tx_bytes", len);
+		strncpy(data + 2 * len, "rx_packets", len);
+		strncpy(data + 3 * len, "rx_bytes", len);
+		if (ds->drv->get_strings != NULL)
+			ds->drv->get_strings(ds, p->port, data + 4 * len);
+	}
+}
+
+static void dsa_slave_get_ethtool_stats(struct net_device *dev,
+					struct ethtool_stats *stats,
+					uint64_t *data)
+{
+	struct dsa_slave_priv *p = netdev_priv(dev);
+	struct dsa_switch *ds = p->parent;
+
+	data[0] = p->dev->stats.tx_packets;
+	data[1] = p->dev->stats.tx_bytes;
+	data[2] = p->dev->stats.rx_packets;
+	data[3] = p->dev->stats.rx_bytes;
+	if (ds->drv->get_ethtool_stats != NULL)
+		ds->drv->get_ethtool_stats(ds, p->port, data + 4);
+}
+
+static int dsa_slave_get_sset_count(struct net_device *dev, int sset)
+{
+	struct dsa_slave_priv *p = netdev_priv(dev);
+	struct dsa_switch *ds = p->parent;
+
+	if (sset == ETH_SS_STATS) {
+		int count;
+
+		count = 4;
+		if (ds->drv->get_sset_count != NULL)
+			count += ds->drv->get_sset_count(ds);
+
+		return count;
+	}
+
+	return -EOPNOTSUPP;
+}
+
+static const struct ethtool_ops dsa_slave_ethtool_ops = {
+	.get_settings		= dsa_slave_get_settings,
+	.set_settings		= dsa_slave_set_settings,
+	.get_drvinfo		= dsa_slave_get_drvinfo,
+	.nway_reset		= dsa_slave_nway_reset,
+	.get_link		= dsa_slave_get_link,
+	.set_sg			= ethtool_op_set_sg,
+	.get_strings		= dsa_slave_get_strings,
+	.get_ethtool_stats	= dsa_slave_get_ethtool_stats,
+	.get_sset_count		= dsa_slave_get_sset_count,
+};
+
+
+/* slave device setup *******************************************************/
+struct net_device *
+dsa_slave_create(struct dsa_switch *ds, struct device *parent,
+		 int port, char *name)
+{
+	struct net_device *master = ds->master_netdev;
+	struct net_device *slave_dev;
+	struct dsa_slave_priv *p;
+	int ret;
+
+	slave_dev = alloc_netdev(sizeof(struct dsa_slave_priv),
+				 name, ether_setup);
+	if (slave_dev == NULL)
+		return slave_dev;
+
+	slave_dev->features = master->vlan_features;
+	SET_ETHTOOL_OPS(slave_dev, &dsa_slave_ethtool_ops);
+	memcpy(slave_dev->dev_addr, master->dev_addr, ETH_ALEN);
+	slave_dev->tx_queue_len = 0;
+	switch (ds->tag_protocol) {
+#ifdef CONFIG_NET_DSA_TAG_DSA
+	case htons(ETH_P_DSA):
+		slave_dev->hard_start_xmit = dsa_xmit;
+		break;
+#endif
+#ifdef CONFIG_NET_DSA_TAG_EDSA
+	case htons(ETH_P_EDSA):
+		slave_dev->hard_start_xmit = edsa_xmit;
+		break;
+#endif
+#ifdef CONFIG_NET_DSA_TAG_TRAILER
+	case htons(ETH_P_TRAILER):
+		slave_dev->hard_start_xmit = trailer_xmit;
+		break;
+#endif
+	default:
+		BUG();
+	}
+	slave_dev->open = dsa_slave_open;
+	slave_dev->stop = dsa_slave_close;
+	slave_dev->change_rx_flags = dsa_slave_change_rx_flags;
+	slave_dev->set_rx_mode = dsa_slave_set_rx_mode;
+	slave_dev->set_multicast_list = dsa_slave_set_rx_mode;
+	slave_dev->set_mac_address = dsa_slave_set_mac_address;
+	slave_dev->do_ioctl = dsa_slave_ioctl;
+	SET_NETDEV_DEV(slave_dev, parent);
+	slave_dev->vlan_features = master->vlan_features;
+
+	p = netdev_priv(slave_dev);
+	p->dev = slave_dev;
+	p->parent = ds;
+	p->port = port;
+	p->phy = ds->slave_mii_bus->phy_map[port];
+
+	ret = register_netdev(slave_dev);
+	if (ret) {
+		printk(KERN_ERR "%s: error %d registering interface %s\n",
+				master->name, ret, slave_dev->name);
+		free_netdev(slave_dev);
+		return NULL;
+	}
+
+	netif_carrier_off(slave_dev);
+
+	if (p->phy != NULL) {
+		phy_attach(slave_dev, p->phy->dev.bus_id,
+			   0, PHY_INTERFACE_MODE_GMII);
+
+		p->phy->autoneg = AUTONEG_ENABLE;
+		p->phy->speed = 0;
+		p->phy->duplex = 0;
+		p->phy->advertising = p->phy->supported | ADVERTISED_Autoneg;
+		phy_start_aneg(p->phy);
+	}
+
+	return slave_dev;
+}
diff --git a/net/dsa/tag_dsa.c b/net/dsa/tag_dsa.c
new file mode 100644
index 0000000..bdc0510
--- /dev/null
+++ b/net/dsa/tag_dsa.c
@@ -0,0 +1,194 @@
+/*
+ * net/dsa/tag_dsa.c - (Non-ethertype) DSA tagging
+ * Copyright (c) 2008 Marvell Semiconductor
+ *
+ * This program is free software; you can redistribute it and/or 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/etherdevice.h>
+#include <linux/list.h>
+#include <linux/netdevice.h>
+#include "dsa_priv.h"
+
+#define DSA_HLEN	4
+
+int dsa_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	struct dsa_slave_priv *p = netdev_priv(dev);
+	u8 *dsa_header;
+
+	dev->stats.tx_packets++;
+	dev->stats.tx_bytes += skb->len;
+
+	/*
+	 * Convert the outermost 802.1q tag to a DSA tag for tagged
+	 * packets, or insert a DSA tag between the addresses and
+	 * the ethertype field for untagged packets.
+	 */
+	if (skb->protocol == htons(ETH_P_8021Q)) {
+		if (skb_cow_head(skb, 0) < 0)
+			goto out_free;
+
+		/*
+		 * Construct tagged FROM_CPU DSA tag from 802.1q tag.
+		 */
+		dsa_header = skb->data + 2 * ETH_ALEN;
+		dsa_header[0] = 0x60;
+		dsa_header[1] = p->port << 3;
+
+		/*
+		 * Move CFI field from byte 2 to byte 1.
+		 */
+		if (dsa_header[2] & 0x10) {
+			dsa_header[1] |= 0x01;
+			dsa_header[2] &= ~0x10;
+		}
+	} else {
+		if (skb_cow_head(skb, DSA_HLEN) < 0)
+			goto out_free;
+		skb_push(skb, DSA_HLEN);
+
+		memmove(skb->data, skb->data + DSA_HLEN, 2 * ETH_ALEN);
+
+		/*
+		 * Construct untagged FROM_CPU DSA tag.
+		 */
+		dsa_header = skb->data + 2 * ETH_ALEN;
+		dsa_header[0] = 0x40;
+		dsa_header[1] = p->port << 3;
+		dsa_header[2] = 0x00;
+		dsa_header[3] = 0x00;
+	}
+
+	skb->protocol = htons(ETH_P_DSA);
+
+	skb->dev = p->parent->master_netdev;
+	dev_queue_xmit(skb);
+
+	return NETDEV_TX_OK;
+
+out_free:
+	kfree_skb(skb);
+	return NETDEV_TX_OK;
+}
+
+static int dsa_rcv(struct sk_buff *skb, struct net_device *dev,
+		   struct packet_type *pt, struct net_device *orig_dev)
+{
+	struct dsa_switch *ds = dev->dsa_ptr;
+	u8 *dsa_header;
+	int source_port;
+
+	if (unlikely(ds == NULL))
+		goto out_drop;
+
+	skb = skb_unshare(skb, GFP_ATOMIC);
+	if (skb == NULL)
+		goto out;
+
+	if (unlikely(!pskb_may_pull(skb, DSA_HLEN)))
+		goto out_drop;
+
+	/*
+	 * The ethertype field is part of the DSA header.
+	 */
+	dsa_header = skb->data - 2;
+
+	/*
+	 * Check that frame type is either TO_CPU or FORWARD, and
+	 * that the source device is zero.
+	 */
+	if ((dsa_header[0] & 0xdf) != 0x00 && (dsa_header[0] & 0xdf) != 0xc0)
+		goto out_drop;
+
+	/*
+	 * Check that the source port is a registered DSA port.
+	 */
+	source_port = (dsa_header[1] >> 3) & 0x1f;
+	if (source_port >= DSA_MAX_PORTS || ds->ports[source_port] == NULL)
+		goto out_drop;
+
+	/*
+	 * Convert the DSA header to an 802.1q header if the 'tagged'
+	 * bit in the DSA header is set.  If the 'tagged' bit is clear,
+	 * delete the DSA header entirely.
+	 */
+	if (dsa_header[0] & 0x20) {
+		u8 new_header[4];
+
+		/*
+		 * Insert 802.1q ethertype and copy the VLAN-related
+		 * fields, but clear the bit that will hold CFI (since
+		 * DSA uses that bit location for another purpose).
+		 */
+		new_header[0] = (ETH_P_8021Q >> 8) & 0xff;
+		new_header[1] = ETH_P_8021Q & 0xff;
+		new_header[2] = dsa_header[2] & ~0x10;
+		new_header[3] = dsa_header[3];
+
+		/*
+		 * Move CFI bit from its place in the DSA header to
+		 * its 802.1q-designated place.
+		 */
+		if (dsa_header[1] & 0x01)
+			new_header[2] |= 0x10;
+
+		/*
+		 * Update packet checksum if skb is CHECKSUM_COMPLETE.
+		 */
+		if (skb->ip_summed == CHECKSUM_COMPLETE) {
+			__wsum c = skb->csum;
+			c = csum_add(c, csum_partial(new_header + 2, 2, 0));
+			c = csum_sub(c, csum_partial(dsa_header + 2, 2, 0));
+			skb->csum = c;
+		}
+
+		memcpy(dsa_header, new_header, DSA_HLEN);
+	} else {
+		/*
+		 * Remove DSA tag and update checksum.
+		 */
+		skb_pull_rcsum(skb, DSA_HLEN);
+		memmove(skb->data - ETH_HLEN,
+			skb->data - ETH_HLEN - DSA_HLEN,
+			2 * ETH_ALEN);
+	}
+
+	skb->dev = ds->ports[source_port];
+	skb_push(skb, ETH_HLEN);
+	skb->protocol = eth_type_trans(skb, skb->dev);
+
+	skb->dev->last_rx = jiffies;
+	skb->dev->stats.rx_packets++;
+	skb->dev->stats.rx_bytes += skb->len;
+
+	netif_receive_skb(skb);
+
+	return 0;
+
+out_drop:
+	kfree_skb(skb);
+out:
+	return 0;
+}
+
+static struct packet_type dsa_packet_type = {
+	.type	= __constant_htons(ETH_P_DSA),
+	.func	= dsa_rcv,
+};
+
+static int __init dsa_init_module(void)
+{
+	dev_add_pack(&dsa_packet_type);
+	return 0;
+}
+module_init(dsa_init_module);
+
+static void __exit dsa_cleanup_module(void)
+{
+	dev_remove_pack(&dsa_packet_type);
+}
+module_exit(dsa_cleanup_module);
diff --git a/net/dsa/tag_edsa.c b/net/dsa/tag_edsa.c
new file mode 100644
index 0000000..f985ea9
--- /dev/null
+++ b/net/dsa/tag_edsa.c
@@ -0,0 +1,213 @@
+/*
+ * net/dsa/tag_edsa.c - Ethertype DSA tagging
+ * Copyright (c) 2008 Marvell Semiconductor
+ *
+ * This program is free software; you can redistribute it and/or 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/etherdevice.h>
+#include <linux/list.h>
+#include <linux/netdevice.h>
+#include "dsa_priv.h"
+
+#define DSA_HLEN	4
+#define EDSA_HLEN	8
+
+int edsa_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	struct dsa_slave_priv *p = netdev_priv(dev);
+	u8 *edsa_header;
+
+	dev->stats.tx_packets++;
+	dev->stats.tx_bytes += skb->len;
+
+	/*
+	 * Convert the outermost 802.1q tag to a DSA tag and prepend
+	 * a DSA ethertype field is the packet is tagged, or insert
+	 * a DSA ethertype plus DSA tag between the addresses and the
+	 * current ethertype field if the packet is untagged.
+	 */
+	if (skb->protocol == htons(ETH_P_8021Q)) {
+		if (skb_cow_head(skb, DSA_HLEN) < 0)
+			goto out_free;
+		skb_push(skb, DSA_HLEN);
+
+		memmove(skb->data, skb->data + DSA_HLEN, 2 * ETH_ALEN);
+
+		/*
+		 * Construct tagged FROM_CPU DSA tag from 802.1q tag.
+		 */
+		edsa_header = skb->data + 2 * ETH_ALEN;
+		edsa_header[0] = (ETH_P_EDSA >> 8) & 0xff;
+		edsa_header[1] = ETH_P_EDSA & 0xff;
+		edsa_header[2] = 0x00;
+		edsa_header[3] = 0x00;
+		edsa_header[4] = 0x60;
+		edsa_header[5] = p->port << 3;
+
+		/*
+		 * Move CFI field from byte 6 to byte 5.
+		 */
+		if (edsa_header[6] & 0x10) {
+			edsa_header[5] |= 0x01;
+			edsa_header[6] &= ~0x10;
+		}
+	} else {
+		if (skb_cow_head(skb, EDSA_HLEN) < 0)
+			goto out_free;
+		skb_push(skb, EDSA_HLEN);
+
+		memmove(skb->data, skb->data + EDSA_HLEN, 2 * ETH_ALEN);
+
+		/*
+		 * Construct untagged FROM_CPU DSA tag.
+		 */
+		edsa_header = skb->data + 2 * ETH_ALEN;
+		edsa_header[0] = (ETH_P_EDSA >> 8) & 0xff;
+		edsa_header[1] = ETH_P_EDSA & 0xff;
+		edsa_header[2] = 0x00;
+		edsa_header[3] = 0x00;
+		edsa_header[4] = 0x40;
+		edsa_header[5] = p->port << 3;
+		edsa_header[6] = 0x00;
+		edsa_header[7] = 0x00;
+	}
+
+	skb->protocol = htons(ETH_P_EDSA);
+
+	skb->dev = p->parent->master_netdev;
+	dev_queue_xmit(skb);
+
+	return NETDEV_TX_OK;
+
+out_free:
+	kfree_skb(skb);
+	return NETDEV_TX_OK;
+}
+
+static int edsa_rcv(struct sk_buff *skb, struct net_device *dev,
+		    struct packet_type *pt, struct net_device *orig_dev)
+{
+	struct dsa_switch *ds = dev->dsa_ptr;
+	u8 *edsa_header;
+	int source_port;
+
+	if (unlikely(ds == NULL))
+		goto out_drop;
+
+	skb = skb_unshare(skb, GFP_ATOMIC);
+	if (skb == NULL)
+		goto out;
+
+	if (unlikely(!pskb_may_pull(skb, EDSA_HLEN)))
+		goto out_drop;
+
+	/*
+	 * Skip the two null bytes after the ethertype.
+	 */
+	edsa_header = skb->data + 2;
+
+	/*
+	 * Check that frame type is either TO_CPU or FORWARD, and
+	 * that the source device is zero.
+	 */
+	if ((edsa_header[0] & 0xdf) != 0x00 && (edsa_header[0] & 0xdf) != 0xc0)
+		goto out_drop;
+
+	/*
+	 * Check that the source port is a registered DSA port.
+	 */
+	source_port = (edsa_header[1] >> 3) & 0x1f;
+	if (source_port >= DSA_MAX_PORTS || ds->ports[source_port] == NULL)
+		goto out_drop;
+
+	/*
+	 * If the 'tagged' bit is set, convert the DSA tag to a 802.1q
+	 * tag and delete the ethertype part.  If the 'tagged' bit is
+	 * clear, delete the ethertype and the DSA tag parts.
+	 */
+	if (edsa_header[0] & 0x20) {
+		u8 new_header[4];
+
+		/*
+		 * Insert 802.1q ethertype and copy the VLAN-related
+		 * fields, but clear the bit that will hold CFI (since
+		 * DSA uses that bit location for another purpose).
+		 */
+		new_header[0] = (ETH_P_8021Q >> 8) & 0xff;
+		new_header[1] = ETH_P_8021Q & 0xff;
+		new_header[2] = edsa_header[2] & ~0x10;
+		new_header[3] = edsa_header[3];
+
+		/*
+		 * Move CFI bit from its place in the DSA header to
+		 * its 802.1q-designated place.
+		 */
+		if (edsa_header[1] & 0x01)
+			new_header[2] |= 0x10;
+
+		skb_pull_rcsum(skb, DSA_HLEN);
+
+		/*
+		 * Update packet checksum if skb is CHECKSUM_COMPLETE.
+		 */
+		if (skb->ip_summed == CHECKSUM_COMPLETE) {
+			__wsum c = skb->csum;
+			c = csum_add(c, csum_partial(new_header + 2, 2, 0));
+			c = csum_sub(c, csum_partial(edsa_header + 2, 2, 0));
+			skb->csum = c;
+		}
+
+		memcpy(edsa_header, new_header, DSA_HLEN);
+
+		memmove(skb->data - ETH_HLEN,
+			skb->data - ETH_HLEN - DSA_HLEN,
+			2 * ETH_ALEN);
+	} else {
+		/*
+		 * Remove DSA tag and update checksum.
+		 */
+		skb_pull_rcsum(skb, EDSA_HLEN);
+		memmove(skb->data - ETH_HLEN,
+			skb->data - ETH_HLEN - EDSA_HLEN,
+			2 * ETH_ALEN);
+	}
+
+	skb->dev = ds->ports[source_port];
+	skb_push(skb, ETH_HLEN);
+	skb->protocol = eth_type_trans(skb, skb->dev);
+
+	skb->dev->last_rx = jiffies;
+	skb->dev->stats.rx_packets++;
+	skb->dev->stats.rx_bytes += skb->len;
+
+	netif_receive_skb(skb);
+
+	return 0;
+
+out_drop:
+	kfree_skb(skb);
+out:
+	return 0;
+}
+
+static struct packet_type edsa_packet_type = {
+	.type	= __constant_htons(ETH_P_EDSA),
+	.func	= edsa_rcv,
+};
+
+static int __init edsa_init_module(void)
+{
+	dev_add_pack(&edsa_packet_type);
+	return 0;
+}
+module_init(edsa_init_module);
+
+static void __exit edsa_cleanup_module(void)
+{
+	dev_remove_pack(&edsa_packet_type);
+}
+module_exit(edsa_cleanup_module);
diff --git a/net/dsa/tag_trailer.c b/net/dsa/tag_trailer.c
new file mode 100644
index 0000000..d311776
--- /dev/null
+++ b/net/dsa/tag_trailer.c
@@ -0,0 +1,130 @@
+/*
+ * net/dsa/tag_trailer.c - Trailer tag format handling
+ * Copyright (c) 2008 Marvell Semiconductor
+ *
+ * This program is free software; you can redistribute it and/or 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/etherdevice.h>
+#include <linux/list.h>
+#include <linux/netdevice.h>
+#include "dsa_priv.h"
+
+int trailer_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	struct dsa_slave_priv *p = netdev_priv(dev);
+	struct sk_buff *nskb;
+	int padlen;
+	u8 *trailer;
+
+	dev->stats.tx_packets++;
+	dev->stats.tx_bytes += skb->len;
+
+	/*
+	 * We have to make sure that the trailer ends up as the very
+	 * last 4 bytes of the packet.  This means that we have to pad
+	 * the packet to the minimum ethernet frame size, if necessary,
+	 * before adding the trailer.
+	 */
+	padlen = 0;
+	if (skb->len < 60)
+		padlen = 60 - skb->len;
+
+	nskb = alloc_skb(NET_IP_ALIGN + skb->len + padlen + 4, GFP_ATOMIC);
+	if (nskb == NULL) {
+		kfree_skb(skb);
+		return NETDEV_TX_OK;
+	}
+	skb_reserve(nskb, NET_IP_ALIGN);
+
+	skb_reset_mac_header(nskb);
+	skb_set_network_header(nskb, skb_network_header(skb) - skb->head);
+	skb_set_transport_header(nskb, skb_transport_header(skb) - skb->head);
+	skb_copy_and_csum_dev(skb, skb_put(nskb, skb->len));
+	kfree_skb(skb);
+
+	if (padlen) {
+		u8 *pad = skb_put(nskb, padlen);
+		memset(pad, 0, padlen);
+	}
+
+	trailer = skb_put(nskb, 4);
+	trailer[0] = 0x80;
+	trailer[1] = 1 << p->port;
+	trailer[2] = 0x10;
+	trailer[3] = 0x00;
+
+	nskb->protocol = htons(ETH_P_TRAILER);
+
+	nskb->dev = p->parent->master_netdev;
+	dev_queue_xmit(nskb);
+
+	return NETDEV_TX_OK;
+}
+
+static int trailer_rcv(struct sk_buff *skb, struct net_device *dev,
+		       struct packet_type *pt, struct net_device *orig_dev)
+{
+	struct dsa_switch *ds = dev->dsa_ptr;
+	u8 *trailer;
+	int source_port;
+
+	if (unlikely(ds == NULL))
+		goto out_drop;
+
+	skb = skb_unshare(skb, GFP_ATOMIC);
+	if (skb == NULL)
+		goto out;
+
+	if (skb_linearize(skb))
+		goto out_drop;
+
+	trailer = skb_tail_pointer(skb) - 4;
+	if (trailer[0] != 0x80 || (trailer[1] & 0xf8) != 0x00 ||
+	    (trailer[3] & 0xef) != 0x00 || trailer[3] != 0x00)
+		goto out_drop;
+
+	source_port = trailer[1] & 7;
+	if (source_port >= DSA_MAX_PORTS || ds->ports[source_port] == NULL)
+		goto out_drop;
+
+	pskb_trim_rcsum(skb, skb->len - 4);
+
+	skb->dev = ds->ports[source_port];
+	skb_push(skb, ETH_HLEN);
+	skb->protocol = eth_type_trans(skb, skb->dev);
+
+	skb->dev->last_rx = jiffies;
+	skb->dev->stats.rx_packets++;
+	skb->dev->stats.rx_bytes += skb->len;
+
+	netif_receive_skb(skb);
+
+	return 0;
+
+out_drop:
+	kfree_skb(skb);
+out:
+	return 0;
+}
+
+static struct packet_type trailer_packet_type = {
+	.type	= __constant_htons(ETH_P_TRAILER),
+	.func	= trailer_rcv,
+};
+
+static int __init trailer_init_module(void)
+{
+	dev_add_pack(&trailer_packet_type);
+	return 0;
+}
+module_init(trailer_init_module);
+
+static void __exit trailer_cleanup_module(void)
+{
+	dev_remove_pack(&trailer_packet_type);
+}
+module_exit(trailer_cleanup_module);
diff --git a/net/ethernet/eth.c b/net/ethernet/eth.c
index a80839b..b9d85af 100644
--- a/net/ethernet/eth.c
+++ b/net/ethernet/eth.c
@@ -57,6 +57,7 @@
 #include <net/sock.h>
 #include <net/ipv6.h>
 #include <net/ip.h>
+#include <net/dsa.h>
 #include <asm/uaccess.h>
 #include <asm/system.h>
 
@@ -129,7 +130,7 @@
 
 	switch (eth->h_proto) {
 #ifdef CONFIG_INET
-	case __constant_htons(ETH_P_IP):
+	case htons(ETH_P_IP):
 		return arp_find(eth->h_dest, skb);
 #endif
 	default:
@@ -184,6 +185,17 @@
 			skb->pkt_type = PACKET_OTHERHOST;
 	}
 
+	/*
+	 * Some variants of DSA tagging don't have an ethertype field
+	 * at all, so we check here whether one of those tagging
+	 * variants has been configured on the receiving interface,
+	 * and if so, set skb->protocol without looking at the packet.
+	 */
+	if (netdev_uses_dsa_tags(dev))
+		return htons(ETH_P_DSA);
+	if (netdev_uses_trailer_tags(dev))
+		return htons(ETH_P_TRAILER);
+
 	if (ntohs(eth->h_proto) >= 1536)
 		return eth->h_proto;
 
diff --git a/net/ieee80211/ieee80211_module.c b/net/ieee80211/ieee80211_module.c
index 3bca97f..949772a 100644
--- a/net/ieee80211/ieee80211_module.c
+++ b/net/ieee80211/ieee80211_module.c
@@ -157,7 +157,7 @@
 	err = ieee80211_networks_allocate(ieee);
 	if (err) {
 		IEEE80211_ERROR("Unable to allocate beacon storage: %d\n", err);
-		goto failed;
+		goto failed_free_netdev;
 	}
 	ieee80211_networks_initialize(ieee);
 
@@ -193,9 +193,9 @@
 
 	return dev;
 
-      failed:
-	if (dev)
-		free_netdev(dev);
+failed_free_netdev:
+	free_netdev(dev);
+failed:
 	return NULL;
 }
 
diff --git a/net/ipv4/Kconfig b/net/ipv4/Kconfig
index 591ea23..691268f 100644
--- a/net/ipv4/Kconfig
+++ b/net/ipv4/Kconfig
@@ -630,5 +630,3 @@
 
 	  If unsure, say N.
 
-source "net/ipv4/ipvs/Kconfig"
-
diff --git a/net/ipv4/Makefile b/net/ipv4/Makefile
index ad40ef3..80ff87c 100644
--- a/net/ipv4/Makefile
+++ b/net/ipv4/Makefile
@@ -33,7 +33,6 @@
 obj-$(CONFIG_INET_XFRM_MODE_TUNNEL) += xfrm4_mode_tunnel.o
 obj-$(CONFIG_IP_PNP) += ipconfig.o
 obj-$(CONFIG_NETFILTER)	+= netfilter.o netfilter/
-obj-$(CONFIG_IP_VS) += ipvs/
 obj-$(CONFIG_INET_DIAG) += inet_diag.o 
 obj-$(CONFIG_INET_TCP_DIAG) += tcp_diag.o
 obj-$(CONFIG_NET_TCPPROBE) += tcp_probe.o
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
index 8a3ac1f..1fbff5f 100644
--- a/net/ipv4/af_inet.c
+++ b/net/ipv4/af_inet.c
@@ -469,7 +469,7 @@
 	 */
 	err = -EADDRNOTAVAIL;
 	if (!sysctl_ip_nonlocal_bind &&
-	    !inet->freebind &&
+	    !(inet->freebind || inet->transparent) &&
 	    addr->sin_addr.s_addr != htonl(INADDR_ANY) &&
 	    chk_addr_ret != RTN_LOCAL &&
 	    chk_addr_ret != RTN_MULTICAST &&
diff --git a/net/ipv4/cipso_ipv4.c b/net/ipv4/cipso_ipv4.c
index 2c0e457..490e035c 100644
--- a/net/ipv4/cipso_ipv4.c
+++ b/net/ipv4/cipso_ipv4.c
@@ -13,7 +13,7 @@
  */
 
 /*
- * (c) Copyright Hewlett-Packard Development Company, L.P., 2006
+ * (c) Copyright Hewlett-Packard Development Company, L.P., 2006, 2008
  *
  * This program is free software;  you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -47,17 +47,7 @@
 #include <asm/bug.h>
 #include <asm/unaligned.h>
 
-struct cipso_v4_domhsh_entry {
-	char *domain;
-	u32 valid;
-	struct list_head list;
-	struct rcu_head rcu;
-};
-
 /* List of available DOI definitions */
-/* XXX - Updates should be minimal so having a single lock for the
- * cipso_v4_doi_list and the cipso_v4_doi_list->dom_list should be
- * okay. */
 /* XXX - This currently assumes a minimal number of different DOIs in use,
  * if in practice there are a lot of different DOIs this list should
  * probably be turned into a hash table or something similar so we
@@ -119,6 +109,19 @@
  * be omitted. */
 #define CIPSO_V4_TAG_RNG_CAT_MAX      8
 
+/* Base length of the local tag (non-standard tag).
+ *  Tag definition (may change between kernel versions)
+ *
+ * 0          8          16         24         32
+ * +----------+----------+----------+----------+
+ * | 10000000 | 00000110 | 32-bit secid value  |
+ * +----------+----------+----------+----------+
+ * | in (host byte order)|
+ * +----------+----------+
+ *
+ */
+#define CIPSO_V4_TAG_LOC_BLEN         6
+
 /*
  * Helper Functions
  */
@@ -194,25 +197,6 @@
 }
 
 /**
- * cipso_v4_doi_domhsh_free - Frees a domain list entry
- * @entry: the entry's RCU field
- *
- * Description:
- * This function is designed to be used as a callback to the call_rcu()
- * function so that the memory allocated to a domain list entry can be released
- * safely.
- *
- */
-static void cipso_v4_doi_domhsh_free(struct rcu_head *entry)
-{
-	struct cipso_v4_domhsh_entry *ptr;
-
-	ptr = container_of(entry, struct cipso_v4_domhsh_entry, rcu);
-	kfree(ptr->domain);
-	kfree(ptr);
-}
-
-/**
  * cipso_v4_cache_entry_free - Frees a cache entry
  * @entry: the entry to free
  *
@@ -457,7 +441,7 @@
 	struct cipso_v4_doi *iter;
 
 	list_for_each_entry_rcu(iter, &cipso_v4_doi_list, list)
-		if (iter->doi == doi && iter->valid)
+		if (iter->doi == doi && atomic_read(&iter->refcount))
 			return iter;
 	return NULL;
 }
@@ -496,14 +480,17 @@
 			if (doi_def->type != CIPSO_V4_MAP_PASS)
 				return -EINVAL;
 			break;
+		case CIPSO_V4_TAG_LOCAL:
+			if (doi_def->type != CIPSO_V4_MAP_LOCAL)
+				return -EINVAL;
+			break;
 		default:
 			return -EINVAL;
 		}
 	}
 
-	doi_def->valid = 1;
+	atomic_set(&doi_def->refcount, 1);
 	INIT_RCU_HEAD(&doi_def->rcu);
-	INIT_LIST_HEAD(&doi_def->dom_list);
 
 	spin_lock(&cipso_v4_doi_list_lock);
 	if (cipso_v4_doi_search(doi_def->doi) != NULL)
@@ -519,59 +506,129 @@
 }
 
 /**
- * cipso_v4_doi_remove - Remove an existing DOI from the CIPSO protocol engine
- * @doi: the DOI value
- * @audit_secid: the LSM secid to use in the audit message
- * @callback: the DOI cleanup/free callback
+ * cipso_v4_doi_free - Frees a DOI definition
+ * @entry: the entry's RCU field
  *
  * Description:
- * Removes a DOI definition from the CIPSO engine, @callback is called to
- * free any memory.  The NetLabel routines will be called to release their own
- * LSM domain mappings as well as our own domain list.  Returns zero on
- * success and negative values on failure.
+ * This function frees all of the memory associated with a DOI definition.
  *
  */
-int cipso_v4_doi_remove(u32 doi,
-			struct netlbl_audit *audit_info,
-			void (*callback) (struct rcu_head * head))
+void cipso_v4_doi_free(struct cipso_v4_doi *doi_def)
 {
-	struct cipso_v4_doi *doi_def;
-	struct cipso_v4_domhsh_entry *dom_iter;
+	if (doi_def == NULL)
+		return;
 
-	spin_lock(&cipso_v4_doi_list_lock);
-	doi_def = cipso_v4_doi_search(doi);
-	if (doi_def != NULL) {
-		doi_def->valid = 0;
-		list_del_rcu(&doi_def->list);
-		spin_unlock(&cipso_v4_doi_list_lock);
-		rcu_read_lock();
-		list_for_each_entry_rcu(dom_iter, &doi_def->dom_list, list)
-			if (dom_iter->valid)
-				netlbl_cfg_map_del(dom_iter->domain,
-						   audit_info);
-		rcu_read_unlock();
-		cipso_v4_cache_invalidate();
-		call_rcu(&doi_def->rcu, callback);
-		return 0;
+	switch (doi_def->type) {
+	case CIPSO_V4_MAP_TRANS:
+		kfree(doi_def->map.std->lvl.cipso);
+		kfree(doi_def->map.std->lvl.local);
+		kfree(doi_def->map.std->cat.cipso);
+		kfree(doi_def->map.std->cat.local);
+		break;
 	}
-	spin_unlock(&cipso_v4_doi_list_lock);
-
-	return -ENOENT;
+	kfree(doi_def);
 }
 
 /**
- * cipso_v4_doi_getdef - Returns a pointer to a valid DOI definition
+ * cipso_v4_doi_free_rcu - Frees a DOI definition via the RCU pointer
+ * @entry: the entry's RCU field
+ *
+ * Description:
+ * This function is designed to be used as a callback to the call_rcu()
+ * function so that the memory allocated to the DOI definition can be released
+ * safely.
+ *
+ */
+static void cipso_v4_doi_free_rcu(struct rcu_head *entry)
+{
+	struct cipso_v4_doi *doi_def;
+
+	doi_def = container_of(entry, struct cipso_v4_doi, rcu);
+	cipso_v4_doi_free(doi_def);
+}
+
+/**
+ * cipso_v4_doi_remove - Remove an existing DOI from the CIPSO protocol engine
+ * @doi: the DOI value
+ * @audit_secid: the LSM secid to use in the audit message
+ *
+ * Description:
+ * Removes a DOI definition from the CIPSO engine.  The NetLabel routines will
+ * be called to release their own LSM domain mappings as well as our own
+ * domain list.  Returns zero on success and negative values on failure.
+ *
+ */
+int cipso_v4_doi_remove(u32 doi, struct netlbl_audit *audit_info)
+{
+	struct cipso_v4_doi *doi_def;
+
+	spin_lock(&cipso_v4_doi_list_lock);
+	doi_def = cipso_v4_doi_search(doi);
+	if (doi_def == NULL) {
+		spin_unlock(&cipso_v4_doi_list_lock);
+		return -ENOENT;
+	}
+	if (!atomic_dec_and_test(&doi_def->refcount)) {
+		spin_unlock(&cipso_v4_doi_list_lock);
+		return -EBUSY;
+	}
+	list_del_rcu(&doi_def->list);
+	spin_unlock(&cipso_v4_doi_list_lock);
+
+	cipso_v4_cache_invalidate();
+	call_rcu(&doi_def->rcu, cipso_v4_doi_free_rcu);
+
+	return 0;
+}
+
+/**
+ * cipso_v4_doi_getdef - Returns a reference to a valid DOI definition
  * @doi: the DOI value
  *
  * Description:
  * Searches for a valid DOI definition and if one is found it is returned to
  * the caller.  Otherwise NULL is returned.  The caller must ensure that
- * rcu_read_lock() is held while accessing the returned definition.
+ * rcu_read_lock() is held while accessing the returned definition and the DOI
+ * definition reference count is decremented when the caller is done.
  *
  */
 struct cipso_v4_doi *cipso_v4_doi_getdef(u32 doi)
 {
-	return cipso_v4_doi_search(doi);
+	struct cipso_v4_doi *doi_def;
+
+	rcu_read_lock();
+	doi_def = cipso_v4_doi_search(doi);
+	if (doi_def == NULL)
+		goto doi_getdef_return;
+	if (!atomic_inc_not_zero(&doi_def->refcount))
+		doi_def = NULL;
+
+doi_getdef_return:
+	rcu_read_unlock();
+	return doi_def;
+}
+
+/**
+ * cipso_v4_doi_putdef - Releases a reference for the given DOI definition
+ * @doi_def: the DOI definition
+ *
+ * Description:
+ * Releases a DOI definition reference obtained from cipso_v4_doi_getdef().
+ *
+ */
+void cipso_v4_doi_putdef(struct cipso_v4_doi *doi_def)
+{
+	if (doi_def == NULL)
+		return;
+
+	if (!atomic_dec_and_test(&doi_def->refcount))
+		return;
+	spin_lock(&cipso_v4_doi_list_lock);
+	list_del_rcu(&doi_def->list);
+	spin_unlock(&cipso_v4_doi_list_lock);
+
+	cipso_v4_cache_invalidate();
+	call_rcu(&doi_def->rcu, cipso_v4_doi_free_rcu);
 }
 
 /**
@@ -597,7 +654,7 @@
 
 	rcu_read_lock();
 	list_for_each_entry_rcu(iter_doi, &cipso_v4_doi_list, list)
-		if (iter_doi->valid) {
+		if (atomic_read(&iter_doi->refcount) > 0) {
 			if (doi_cnt++ < *skip_cnt)
 				continue;
 			ret_val = callback(iter_doi, cb_arg);
@@ -613,85 +670,6 @@
 	return ret_val;
 }
 
-/**
- * cipso_v4_doi_domhsh_add - Adds a domain entry to a DOI definition
- * @doi_def: the DOI definition
- * @domain: the domain to add
- *
- * Description:
- * Adds the @domain to the DOI specified by @doi_def, this function
- * should only be called by external functions (i.e. NetLabel).  This function
- * does allocate memory.  Returns zero on success, negative values on failure.
- *
- */
-int cipso_v4_doi_domhsh_add(struct cipso_v4_doi *doi_def, const char *domain)
-{
-	struct cipso_v4_domhsh_entry *iter;
-	struct cipso_v4_domhsh_entry *new_dom;
-
-	new_dom = kzalloc(sizeof(*new_dom), GFP_KERNEL);
-	if (new_dom == NULL)
-		return -ENOMEM;
-	if (domain) {
-		new_dom->domain = kstrdup(domain, GFP_KERNEL);
-		if (new_dom->domain == NULL) {
-			kfree(new_dom);
-			return -ENOMEM;
-		}
-	}
-	new_dom->valid = 1;
-	INIT_RCU_HEAD(&new_dom->rcu);
-
-	spin_lock(&cipso_v4_doi_list_lock);
-	list_for_each_entry(iter, &doi_def->dom_list, list)
-		if (iter->valid &&
-		    ((domain != NULL && iter->domain != NULL &&
-		      strcmp(iter->domain, domain) == 0) ||
-		     (domain == NULL && iter->domain == NULL))) {
-			spin_unlock(&cipso_v4_doi_list_lock);
-			kfree(new_dom->domain);
-			kfree(new_dom);
-			return -EEXIST;
-		}
-	list_add_tail_rcu(&new_dom->list, &doi_def->dom_list);
-	spin_unlock(&cipso_v4_doi_list_lock);
-
-	return 0;
-}
-
-/**
- * cipso_v4_doi_domhsh_remove - Removes a domain entry from a DOI definition
- * @doi_def: the DOI definition
- * @domain: the domain to remove
- *
- * Description:
- * Removes the @domain from the DOI specified by @doi_def, this function
- * should only be called by external functions (i.e. NetLabel).   Returns zero
- * on success and negative values on error.
- *
- */
-int cipso_v4_doi_domhsh_remove(struct cipso_v4_doi *doi_def,
-			       const char *domain)
-{
-	struct cipso_v4_domhsh_entry *iter;
-
-	spin_lock(&cipso_v4_doi_list_lock);
-	list_for_each_entry(iter, &doi_def->dom_list, list)
-		if (iter->valid &&
-		    ((domain != NULL && iter->domain != NULL &&
-		      strcmp(iter->domain, domain) == 0) ||
-		     (domain == NULL && iter->domain == NULL))) {
-			iter->valid = 0;
-			list_del_rcu(&iter->list);
-			spin_unlock(&cipso_v4_doi_list_lock);
-			call_rcu(&iter->rcu, cipso_v4_doi_domhsh_free);
-			return 0;
-		}
-	spin_unlock(&cipso_v4_doi_list_lock);
-
-	return -ENOENT;
-}
-
 /*
  * Label Mapping Functions
  */
@@ -712,7 +690,7 @@
 	switch (doi_def->type) {
 	case CIPSO_V4_MAP_PASS:
 		return 0;
-	case CIPSO_V4_MAP_STD:
+	case CIPSO_V4_MAP_TRANS:
 		if (doi_def->map.std->lvl.cipso[level] < CIPSO_V4_INV_LVL)
 			return 0;
 		break;
@@ -741,7 +719,7 @@
 	case CIPSO_V4_MAP_PASS:
 		*net_lvl = host_lvl;
 		return 0;
-	case CIPSO_V4_MAP_STD:
+	case CIPSO_V4_MAP_TRANS:
 		if (host_lvl < doi_def->map.std->lvl.local_size &&
 		    doi_def->map.std->lvl.local[host_lvl] < CIPSO_V4_INV_LVL) {
 			*net_lvl = doi_def->map.std->lvl.local[host_lvl];
@@ -775,7 +753,7 @@
 	case CIPSO_V4_MAP_PASS:
 		*host_lvl = net_lvl;
 		return 0;
-	case CIPSO_V4_MAP_STD:
+	case CIPSO_V4_MAP_TRANS:
 		map_tbl = doi_def->map.std;
 		if (net_lvl < map_tbl->lvl.cipso_size &&
 		    map_tbl->lvl.cipso[net_lvl] < CIPSO_V4_INV_LVL) {
@@ -812,7 +790,7 @@
 	switch (doi_def->type) {
 	case CIPSO_V4_MAP_PASS:
 		return 0;
-	case CIPSO_V4_MAP_STD:
+	case CIPSO_V4_MAP_TRANS:
 		cipso_cat_size = doi_def->map.std->cat.cipso_size;
 		cipso_array = doi_def->map.std->cat.cipso;
 		for (;;) {
@@ -860,7 +838,7 @@
 	u32 host_cat_size = 0;
 	u32 *host_cat_array = NULL;
 
-	if (doi_def->type == CIPSO_V4_MAP_STD) {
+	if (doi_def->type == CIPSO_V4_MAP_TRANS) {
 		host_cat_size = doi_def->map.std->cat.local_size;
 		host_cat_array = doi_def->map.std->cat.local;
 	}
@@ -875,7 +853,7 @@
 		case CIPSO_V4_MAP_PASS:
 			net_spot = host_spot;
 			break;
-		case CIPSO_V4_MAP_STD:
+		case CIPSO_V4_MAP_TRANS:
 			if (host_spot >= host_cat_size)
 				return -EPERM;
 			net_spot = host_cat_array[host_spot];
@@ -921,7 +899,7 @@
 	u32 net_cat_size = 0;
 	u32 *net_cat_array = NULL;
 
-	if (doi_def->type == CIPSO_V4_MAP_STD) {
+	if (doi_def->type == CIPSO_V4_MAP_TRANS) {
 		net_cat_size = doi_def->map.std->cat.cipso_size;
 		net_cat_array = doi_def->map.std->cat.cipso;
 	}
@@ -941,7 +919,7 @@
 		case CIPSO_V4_MAP_PASS:
 			host_spot = net_spot;
 			break;
-		case CIPSO_V4_MAP_STD:
+		case CIPSO_V4_MAP_TRANS:
 			if (net_spot >= net_cat_size)
 				return -EPERM;
 			host_spot = net_cat_array[net_spot];
@@ -1277,7 +1255,7 @@
 	} else
 		tag_len = 4;
 
-	buffer[0] = 0x01;
+	buffer[0] = CIPSO_V4_TAG_RBITMAP;
 	buffer[1] = tag_len;
 	buffer[3] = level;
 
@@ -1373,7 +1351,7 @@
 	} else
 		tag_len = 4;
 
-	buffer[0] = 0x02;
+	buffer[0] = CIPSO_V4_TAG_ENUM;
 	buffer[1] = tag_len;
 	buffer[3] = level;
 
@@ -1469,7 +1447,7 @@
 	} else
 		tag_len = 4;
 
-	buffer[0] = 0x05;
+	buffer[0] = CIPSO_V4_TAG_RANGE;
 	buffer[1] = tag_len;
 	buffer[3] = level;
 
@@ -1523,6 +1501,54 @@
 }
 
 /**
+ * cipso_v4_gentag_loc - Generate a CIPSO local tag (non-standard)
+ * @doi_def: the DOI definition
+ * @secattr: the security attributes
+ * @buffer: the option buffer
+ * @buffer_len: length of buffer in bytes
+ *
+ * Description:
+ * Generate a CIPSO option using the local tag.  Returns the size of the tag
+ * on success, negative values on failure.
+ *
+ */
+static int cipso_v4_gentag_loc(const struct cipso_v4_doi *doi_def,
+			       const struct netlbl_lsm_secattr *secattr,
+			       unsigned char *buffer,
+			       u32 buffer_len)
+{
+	if (!(secattr->flags & NETLBL_SECATTR_SECID))
+		return -EPERM;
+
+	buffer[0] = CIPSO_V4_TAG_LOCAL;
+	buffer[1] = CIPSO_V4_TAG_LOC_BLEN;
+	*(u32 *)&buffer[2] = secattr->attr.secid;
+
+	return CIPSO_V4_TAG_LOC_BLEN;
+}
+
+/**
+ * cipso_v4_parsetag_loc - Parse a CIPSO local tag
+ * @doi_def: the DOI definition
+ * @tag: the CIPSO tag
+ * @secattr: the security attributes
+ *
+ * Description:
+ * Parse a CIPSO local tag and return the security attributes in @secattr.
+ * Return zero on success, negatives values on failure.
+ *
+ */
+static int cipso_v4_parsetag_loc(const struct cipso_v4_doi *doi_def,
+				 const unsigned char *tag,
+				 struct netlbl_lsm_secattr *secattr)
+{
+	secattr->attr.secid = *(u32 *)&tag[2];
+	secattr->flags |= NETLBL_SECATTR_SECID;
+
+	return 0;
+}
+
+/**
  * cipso_v4_validate - Validate a CIPSO option
  * @option: the start of the option, on error it is set to point to the error
  *
@@ -1541,7 +1567,7 @@
  *   that is unrecognized."
  *
  */
-int cipso_v4_validate(unsigned char **option)
+int cipso_v4_validate(const struct sk_buff *skb, unsigned char **option)
 {
 	unsigned char *opt = *option;
 	unsigned char *tag;
@@ -1566,7 +1592,7 @@
 		goto validate_return_locked;
 	}
 
-	opt_iter = 6;
+	opt_iter = CIPSO_V4_HDR_LEN;
 	tag = opt + opt_iter;
 	while (opt_iter < opt_len) {
 		for (tag_iter = 0; doi_def->tags[tag_iter] != tag[0];)
@@ -1584,7 +1610,7 @@
 
 		switch (tag[0]) {
 		case CIPSO_V4_TAG_RBITMAP:
-			if (tag_len < 4) {
+			if (tag_len < CIPSO_V4_TAG_RBM_BLEN) {
 				err_offset = opt_iter + 1;
 				goto validate_return_locked;
 			}
@@ -1602,7 +1628,7 @@
 					err_offset = opt_iter + 3;
 					goto validate_return_locked;
 				}
-				if (tag_len > 4 &&
+				if (tag_len > CIPSO_V4_TAG_RBM_BLEN &&
 				    cipso_v4_map_cat_rbm_valid(doi_def,
 							    &tag[4],
 							    tag_len - 4) < 0) {
@@ -1612,7 +1638,7 @@
 			}
 			break;
 		case CIPSO_V4_TAG_ENUM:
-			if (tag_len < 4) {
+			if (tag_len < CIPSO_V4_TAG_ENUM_BLEN) {
 				err_offset = opt_iter + 1;
 				goto validate_return_locked;
 			}
@@ -1622,7 +1648,7 @@
 				err_offset = opt_iter + 3;
 				goto validate_return_locked;
 			}
-			if (tag_len > 4 &&
+			if (tag_len > CIPSO_V4_TAG_ENUM_BLEN &&
 			    cipso_v4_map_cat_enum_valid(doi_def,
 							&tag[4],
 							tag_len - 4) < 0) {
@@ -1631,7 +1657,7 @@
 			}
 			break;
 		case CIPSO_V4_TAG_RANGE:
-			if (tag_len < 4) {
+			if (tag_len < CIPSO_V4_TAG_RNG_BLEN) {
 				err_offset = opt_iter + 1;
 				goto validate_return_locked;
 			}
@@ -1641,7 +1667,7 @@
 				err_offset = opt_iter + 3;
 				goto validate_return_locked;
 			}
-			if (tag_len > 4 &&
+			if (tag_len > CIPSO_V4_TAG_RNG_BLEN &&
 			    cipso_v4_map_cat_rng_valid(doi_def,
 						       &tag[4],
 						       tag_len - 4) < 0) {
@@ -1649,6 +1675,19 @@
 				goto validate_return_locked;
 			}
 			break;
+		case CIPSO_V4_TAG_LOCAL:
+			/* This is a non-standard tag that we only allow for
+			 * local connections, so if the incoming interface is
+			 * not the loopback device drop the packet. */
+			if (!(skb->dev->flags & IFF_LOOPBACK)) {
+				err_offset = opt_iter;
+				goto validate_return_locked;
+			}
+			if (tag_len != CIPSO_V4_TAG_LOC_BLEN) {
+				err_offset = opt_iter + 1;
+				goto validate_return_locked;
+			}
+			break;
 		default:
 			err_offset = opt_iter;
 			goto validate_return_locked;
@@ -1704,48 +1743,27 @@
 }
 
 /**
- * cipso_v4_sock_setattr - Add a CIPSO option to a socket
- * @sk: the socket
+ * cipso_v4_genopt - Generate a CIPSO option
+ * @buf: the option buffer
+ * @buf_len: the size of opt_buf
  * @doi_def: the CIPSO DOI to use
- * @secattr: the specific security attributes of the socket
+ * @secattr: the security attributes
  *
  * Description:
- * Set the CIPSO option on the given socket using the DOI definition and
- * security attributes passed to the function.  This function requires
- * exclusive access to @sk, which means it either needs to be in the
- * process of being created or locked.  Returns zero on success and negative
- * values on failure.
+ * Generate a CIPSO option using the DOI definition and security attributes
+ * passed to the function.  Returns the length of the option on success and
+ * negative values on failure.
  *
  */
-int cipso_v4_sock_setattr(struct sock *sk,
-			  const struct cipso_v4_doi *doi_def,
-			  const struct netlbl_lsm_secattr *secattr)
+static int cipso_v4_genopt(unsigned char *buf, u32 buf_len,
+			   const struct cipso_v4_doi *doi_def,
+			   const struct netlbl_lsm_secattr *secattr)
 {
-	int ret_val = -EPERM;
+	int ret_val;
 	u32 iter;
-	unsigned char *buf;
-	u32 buf_len = 0;
-	u32 opt_len;
-	struct ip_options *opt = NULL;
-	struct inet_sock *sk_inet;
-	struct inet_connection_sock *sk_conn;
 
-	/* In the case of sock_create_lite(), the sock->sk field is not
-	 * defined yet but it is not a problem as the only users of these
-	 * "lite" PF_INET sockets are functions which do an accept() call
-	 * afterwards so we will label the socket as part of the accept(). */
-	if (sk == NULL)
-		return 0;
-
-	/* We allocate the maximum CIPSO option size here so we are probably
-	 * being a little wasteful, but it makes our life _much_ easier later
-	 * on and after all we are only talking about 40 bytes. */
-	buf_len = CIPSO_V4_OPT_LEN_MAX;
-	buf = kmalloc(buf_len, GFP_ATOMIC);
-	if (buf == NULL) {
-		ret_val = -ENOMEM;
-		goto socket_setattr_failure;
-	}
+	if (buf_len <= CIPSO_V4_HDR_LEN)
+		return -ENOSPC;
 
 	/* XXX - This code assumes only one tag per CIPSO option which isn't
 	 * really a good assumption to make but since we only support the MAC
@@ -1772,9 +1790,14 @@
 						   &buf[CIPSO_V4_HDR_LEN],
 						   buf_len - CIPSO_V4_HDR_LEN);
 			break;
+		case CIPSO_V4_TAG_LOCAL:
+			ret_val = cipso_v4_gentag_loc(doi_def,
+						   secattr,
+						   &buf[CIPSO_V4_HDR_LEN],
+						   buf_len - CIPSO_V4_HDR_LEN);
+			break;
 		default:
-			ret_val = -EPERM;
-			goto socket_setattr_failure;
+			return -EPERM;
 		}
 
 		iter++;
@@ -1782,9 +1805,58 @@
 		 iter < CIPSO_V4_TAG_MAXCNT &&
 		 doi_def->tags[iter] != CIPSO_V4_TAG_INVALID);
 	if (ret_val < 0)
-		goto socket_setattr_failure;
+		return ret_val;
 	cipso_v4_gentag_hdr(doi_def, buf, ret_val);
-	buf_len = CIPSO_V4_HDR_LEN + ret_val;
+	return CIPSO_V4_HDR_LEN + ret_val;
+}
+
+/**
+ * cipso_v4_sock_setattr - Add a CIPSO option to a socket
+ * @sk: the socket
+ * @doi_def: the CIPSO DOI to use
+ * @secattr: the specific security attributes of the socket
+ *
+ * Description:
+ * Set the CIPSO option on the given socket using the DOI definition and
+ * security attributes passed to the function.  This function requires
+ * exclusive access to @sk, which means it either needs to be in the
+ * process of being created or locked.  Returns zero on success and negative
+ * values on failure.
+ *
+ */
+int cipso_v4_sock_setattr(struct sock *sk,
+			  const struct cipso_v4_doi *doi_def,
+			  const struct netlbl_lsm_secattr *secattr)
+{
+	int ret_val = -EPERM;
+	unsigned char *buf = NULL;
+	u32 buf_len;
+	u32 opt_len;
+	struct ip_options *opt = NULL;
+	struct inet_sock *sk_inet;
+	struct inet_connection_sock *sk_conn;
+
+	/* In the case of sock_create_lite(), the sock->sk field is not
+	 * defined yet but it is not a problem as the only users of these
+	 * "lite" PF_INET sockets are functions which do an accept() call
+	 * afterwards so we will label the socket as part of the accept(). */
+	if (sk == NULL)
+		return 0;
+
+	/* We allocate the maximum CIPSO option size here so we are probably
+	 * being a little wasteful, but it makes our life _much_ easier later
+	 * on and after all we are only talking about 40 bytes. */
+	buf_len = CIPSO_V4_OPT_LEN_MAX;
+	buf = kmalloc(buf_len, GFP_ATOMIC);
+	if (buf == NULL) {
+		ret_val = -ENOMEM;
+		goto socket_setattr_failure;
+	}
+
+	ret_val = cipso_v4_genopt(buf, buf_len, doi_def, secattr);
+	if (ret_val < 0)
+		goto socket_setattr_failure;
+	buf_len = ret_val;
 
 	/* We can't use ip_options_get() directly because it makes a call to
 	 * ip_options_get_alloc() which allocates memory with GFP_KERNEL and
@@ -1822,6 +1894,80 @@
 }
 
 /**
+ * cipso_v4_sock_delattr - Delete the CIPSO option from a socket
+ * @sk: the socket
+ *
+ * Description:
+ * Removes the CIPSO option from a socket, if present.
+ *
+ */
+void cipso_v4_sock_delattr(struct sock *sk)
+{
+	u8 hdr_delta;
+	struct ip_options *opt;
+	struct inet_sock *sk_inet;
+
+	sk_inet = inet_sk(sk);
+	opt = sk_inet->opt;
+	if (opt == NULL || opt->cipso == 0)
+		return;
+
+	if (opt->srr || opt->rr || opt->ts || opt->router_alert) {
+		u8 cipso_len;
+		u8 cipso_off;
+		unsigned char *cipso_ptr;
+		int iter;
+		int optlen_new;
+
+		cipso_off = opt->cipso - sizeof(struct iphdr);
+		cipso_ptr = &opt->__data[cipso_off];
+		cipso_len = cipso_ptr[1];
+
+		if (opt->srr > opt->cipso)
+			opt->srr -= cipso_len;
+		if (opt->rr > opt->cipso)
+			opt->rr -= cipso_len;
+		if (opt->ts > opt->cipso)
+			opt->ts -= cipso_len;
+		if (opt->router_alert > opt->cipso)
+			opt->router_alert -= cipso_len;
+		opt->cipso = 0;
+
+		memmove(cipso_ptr, cipso_ptr + cipso_len,
+			opt->optlen - cipso_off - cipso_len);
+
+		/* determining the new total option length is tricky because of
+		 * the padding necessary, the only thing i can think to do at
+		 * this point is walk the options one-by-one, skipping the
+		 * padding at the end to determine the actual option size and
+		 * from there we can determine the new total option length */
+		iter = 0;
+		optlen_new = 0;
+		while (iter < opt->optlen)
+			if (opt->__data[iter] != IPOPT_NOP) {
+				iter += opt->__data[iter + 1];
+				optlen_new = iter;
+			} else
+				iter++;
+		hdr_delta = opt->optlen;
+		opt->optlen = (optlen_new + 3) & ~3;
+		hdr_delta -= opt->optlen;
+	} else {
+		/* only the cipso option was present on the socket so we can
+		 * remove the entire option struct */
+		sk_inet->opt = NULL;
+		hdr_delta = opt->optlen;
+		kfree(opt);
+	}
+
+	if (sk_inet->is_icsk && hdr_delta > 0) {
+		struct inet_connection_sock *sk_conn = inet_csk(sk);
+		sk_conn->icsk_ext_hdr_len -= hdr_delta;
+		sk_conn->icsk_sync_mss(sk, sk_conn->icsk_pmtu_cookie);
+	}
+}
+
+/**
  * cipso_v4_getattr - Helper function for the cipso_v4_*_getattr functions
  * @cipso: the CIPSO v4 option
  * @secattr: the security attributes
@@ -1859,6 +2005,9 @@
 	case CIPSO_V4_TAG_RANGE:
 		ret_val = cipso_v4_parsetag_rng(doi_def, &cipso[6], secattr);
 		break;
+	case CIPSO_V4_TAG_LOCAL:
+		ret_val = cipso_v4_parsetag_loc(doi_def, &cipso[6], secattr);
+		break;
 	}
 	if (ret_val == 0)
 		secattr->type = NETLBL_NLTYPE_CIPSOV4;
@@ -1893,6 +2042,123 @@
 }
 
 /**
+ * cipso_v4_skbuff_setattr - Set the CIPSO option on a packet
+ * @skb: the packet
+ * @secattr: the security attributes
+ *
+ * Description:
+ * Set the CIPSO option on the given packet based on the security attributes.
+ * Returns a pointer to the IP header on success and NULL on failure.
+ *
+ */
+int cipso_v4_skbuff_setattr(struct sk_buff *skb,
+			    const struct cipso_v4_doi *doi_def,
+			    const struct netlbl_lsm_secattr *secattr)
+{
+	int ret_val;
+	struct iphdr *iph;
+	struct ip_options *opt = &IPCB(skb)->opt;
+	unsigned char buf[CIPSO_V4_OPT_LEN_MAX];
+	u32 buf_len = CIPSO_V4_OPT_LEN_MAX;
+	u32 opt_len;
+	int len_delta;
+
+	buf_len = cipso_v4_genopt(buf, buf_len, doi_def, secattr);
+	if (buf_len < 0)
+		return buf_len;
+	opt_len = (buf_len + 3) & ~3;
+
+	/* we overwrite any existing options to ensure that we have enough
+	 * room for the CIPSO option, the reason is that we _need_ to guarantee
+	 * that the security label is applied to the packet - we do the same
+	 * thing when using the socket options and it hasn't caused a problem,
+	 * if we need to we can always revisit this choice later */
+
+	len_delta = opt_len - opt->optlen;
+	/* if we don't ensure enough headroom we could panic on the skb_push()
+	 * call below so make sure we have enough, we are also "mangling" the
+	 * packet so we should probably do a copy-on-write call anyway */
+	ret_val = skb_cow(skb, skb_headroom(skb) + len_delta);
+	if (ret_val < 0)
+		return ret_val;
+
+	if (len_delta > 0) {
+		/* we assume that the header + opt->optlen have already been
+		 * "pushed" in ip_options_build() or similar */
+		iph = ip_hdr(skb);
+		skb_push(skb, len_delta);
+		memmove((char *)iph - len_delta, iph, iph->ihl << 2);
+		skb_reset_network_header(skb);
+		iph = ip_hdr(skb);
+	} else if (len_delta < 0) {
+		iph = ip_hdr(skb);
+		memset(iph + 1, IPOPT_NOP, opt->optlen);
+	} else
+		iph = ip_hdr(skb);
+
+	if (opt->optlen > 0)
+		memset(opt, 0, sizeof(*opt));
+	opt->optlen = opt_len;
+	opt->cipso = sizeof(struct iphdr);
+	opt->is_changed = 1;
+
+	/* we have to do the following because we are being called from a
+	 * netfilter hook which means the packet already has had the header
+	 * fields populated and the checksum calculated - yes this means we
+	 * are doing more work than needed but we do it to keep the core
+	 * stack clean and tidy */
+	memcpy(iph + 1, buf, buf_len);
+	if (opt_len > buf_len)
+		memset((char *)(iph + 1) + buf_len, 0, opt_len - buf_len);
+	if (len_delta != 0) {
+		iph->ihl = 5 + (opt_len >> 2);
+		iph->tot_len = htons(skb->len);
+	}
+	ip_send_check(iph);
+
+	return 0;
+}
+
+/**
+ * cipso_v4_skbuff_delattr - Delete any CIPSO options from a packet
+ * @skb: the packet
+ *
+ * Description:
+ * Removes any and all CIPSO options from the given packet.  Returns zero on
+ * success, negative values on failure.
+ *
+ */
+int cipso_v4_skbuff_delattr(struct sk_buff *skb)
+{
+	int ret_val;
+	struct iphdr *iph;
+	struct ip_options *opt = &IPCB(skb)->opt;
+	unsigned char *cipso_ptr;
+
+	if (opt->cipso == 0)
+		return 0;
+
+	/* since we are changing the packet we should make a copy */
+	ret_val = skb_cow(skb, skb_headroom(skb));
+	if (ret_val < 0)
+		return ret_val;
+
+	/* the easiest thing to do is just replace the cipso option with noop
+	 * options since we don't change the size of the packet, although we
+	 * still need to recalculate the checksum */
+
+	iph = ip_hdr(skb);
+	cipso_ptr = (unsigned char *)iph + opt->cipso;
+	memset(cipso_ptr, IPOPT_NOOP, cipso_ptr[1]);
+	opt->cipso = 0;
+	opt->is_changed = 1;
+
+	ip_send_check(iph);
+
+	return 0;
+}
+
+/**
  * cipso_v4_skbuff_getattr - Get the security attributes from the CIPSO option
  * @skb: the packet
  * @secattr: the security attributes
diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c
index 55c355e..72b2de7 100644
--- a/net/ipv4/icmp.c
+++ b/net/ipv4/icmp.c
@@ -1,7 +1,7 @@
 /*
  *	NET3:	Implementation of the ICMP protocol layer.
  *
- *		Alan Cox, <alan@redhat.com>
+ *		Alan Cox, <alan@lxorguk.ukuu.org.uk>
  *
  *	This program is free software; you can redistribute it and/or
  *	modify it under the terms of the GNU General Public License
diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c
index f70fac6..a0d8645 100644
--- a/net/ipv4/igmp.c
+++ b/net/ipv4/igmp.c
@@ -9,7 +9,7 @@
  *	seems to fall out with gcc 2.6.2.
  *
  *	Authors:
- *		Alan Cox <Alan.Cox@linux.org>
+ *		Alan Cox <alan@lxorguk.ukuu.org.uk>
  *
  *	This program is free software; you can redistribute it and/or
  *	modify it under the terms of the GNU General Public License
@@ -1234,6 +1234,7 @@
 	write_lock_bh(&in_dev->mc_list_lock);
 	im->next=in_dev->mc_list;
 	in_dev->mc_list=im;
+	in_dev->mc_count++;
 	write_unlock_bh(&in_dev->mc_list_lock);
 #ifdef CONFIG_IP_MULTICAST
 	igmpv3_del_delrec(in_dev, im->multiaddr);
@@ -1282,6 +1283,7 @@
 			if (--i->users == 0) {
 				write_lock_bh(&in_dev->mc_list_lock);
 				*ip = i->next;
+				in_dev->mc_count--;
 				write_unlock_bh(&in_dev->mc_list_lock);
 				igmp_group_dropped(i);
 
@@ -1330,6 +1332,7 @@
 	setup_timer(&in_dev->mr_gq_timer, igmp_gq_timer_expire,
 			(unsigned long)in_dev);
 	in_dev->mr_ifc_count = 0;
+	in_dev->mc_count     = 0;
 	setup_timer(&in_dev->mr_ifc_timer, igmp_ifc_timer_expire,
 			(unsigned long)in_dev);
 	in_dev->mr_qrv = IGMP_Unsolicited_Report_Count;
@@ -1369,8 +1372,8 @@
 	write_lock_bh(&in_dev->mc_list_lock);
 	while ((i = in_dev->mc_list) != NULL) {
 		in_dev->mc_list = i->next;
+		in_dev->mc_count--;
 		write_unlock_bh(&in_dev->mc_list_lock);
-
 		igmp_group_dropped(i);
 		ip_ma_put(i);
 
@@ -2383,7 +2386,7 @@
 
 		if (state->in_dev->mc_list == im) {
 			seq_printf(seq, "%d\t%-10s: %5d %7s\n",
-				   state->dev->ifindex, state->dev->name, state->dev->mc_count, querier);
+				   state->dev->ifindex, state->dev->name, state->in_dev->mc_count, querier);
 		}
 
 		seq_printf(seq,
diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c
index 0c1ae68e..bd1278a 100644
--- a/net/ipv4/inet_connection_sock.c
+++ b/net/ipv4/inet_connection_sock.c
@@ -30,20 +30,22 @@
 #endif
 
 /*
- * This array holds the first and last local port number.
+ * This struct holds the first and last local port number.
  */
-int sysctl_local_port_range[2] = { 32768, 61000 };
-DEFINE_SEQLOCK(sysctl_port_range_lock);
+struct local_ports sysctl_local_ports __read_mostly = {
+	.lock = SEQLOCK_UNLOCKED,
+	.range = { 32768, 61000 },
+};
 
 void inet_get_local_port_range(int *low, int *high)
 {
 	unsigned seq;
 	do {
-		seq = read_seqbegin(&sysctl_port_range_lock);
+		seq = read_seqbegin(&sysctl_local_ports.lock);
 
-		*low = sysctl_local_port_range[0];
-		*high = sysctl_local_port_range[1];
-	} while (read_seqretry(&sysctl_port_range_lock, seq));
+		*low = sysctl_local_ports.range[0];
+		*high = sysctl_local_ports.range[1];
+	} while (read_seqretry(&sysctl_local_ports.lock, seq));
 }
 EXPORT_SYMBOL(inet_get_local_port_range);
 
@@ -335,6 +337,7 @@
 					.saddr = ireq->loc_addr,
 					.tos = RT_CONN_FLAGS(sk) } },
 			    .proto = sk->sk_protocol,
+			    .flags = inet_sk_flowi_flags(sk),
 			    .uli_u = { .ports =
 				       { .sport = inet_sk(sk)->sport,
 					 .dport = ireq->rmt_port } } };
@@ -515,6 +518,8 @@
 		newicsk->icsk_bind_hash = NULL;
 
 		inet_sk(newsk)->dport = inet_rsk(req)->rmt_port;
+		inet_sk(newsk)->num = ntohs(inet_rsk(req)->loc_port);
+		inet_sk(newsk)->sport = inet_rsk(req)->loc_port;
 		newsk->sk_write_space = sk_stream_write_space;
 
 		newicsk->icsk_retransmits = 0;
diff --git a/net/ipv4/inet_diag.c b/net/ipv4/inet_diag.c
index c10036e..89cb047 100644
--- a/net/ipv4/inet_diag.c
+++ b/net/ipv4/inet_diag.c
@@ -782,11 +782,15 @@
 		struct sock *sk;
 		struct hlist_node *node;
 
+		num = 0;
+
+		if (hlist_empty(&head->chain) && hlist_empty(&head->twchain))
+			continue;
+
 		if (i > s_i)
 			s_num = 0;
 
 		read_lock_bh(lock);
-		num = 0;
 		sk_for_each(sk, node, &head->chain) {
 			struct inet_sock *inet = inet_sk(sk);
 
diff --git a/net/ipv4/inet_timewait_sock.c b/net/ipv4/inet_timewait_sock.c
index 743f011..1c5fd38 100644
--- a/net/ipv4/inet_timewait_sock.c
+++ b/net/ipv4/inet_timewait_sock.c
@@ -126,6 +126,7 @@
 		tw->tw_reuse	    = sk->sk_reuse;
 		tw->tw_hash	    = sk->sk_hash;
 		tw->tw_ipv6only	    = 0;
+		tw->tw_transparent  = inet->transparent;
 		tw->tw_prot	    = sk->sk_prot_creator;
 		twsk_net_set(tw, hold_net(sock_net(sk)));
 		atomic_set(&tw->tw_refcnt, 1);
diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c
index 2152d22..e4f81f5 100644
--- a/net/ipv4/ip_fragment.c
+++ b/net/ipv4/ip_fragment.c
@@ -6,7 +6,7 @@
  *		The IP fragmentation functionality.
  *
  * Authors:	Fred N. van Kempen <waltje@uWalt.NL.Mugnet.ORG>
- *		Alan Cox <Alan.Cox@linux.org>
+ *		Alan Cox <alan@lxorguk.ukuu.org.uk>
  *
  * Fixes:
  *		Alan Cox	:	Split from ip.c , see ip_input.c for history.
diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c
index 2a61158..85c487b 100644
--- a/net/ipv4/ip_gre.c
+++ b/net/ipv4/ip_gre.c
@@ -27,6 +27,7 @@
 #include <linux/inetdevice.h>
 #include <linux/igmp.h>
 #include <linux/netfilter_ipv4.h>
+#include <linux/etherdevice.h>
 #include <linux/if_ether.h>
 
 #include <net/sock.h>
@@ -41,6 +42,7 @@
 #include <net/xfrm.h>
 #include <net/net_namespace.h>
 #include <net/netns/generic.h>
+#include <net/rtnetlink.h>
 
 #ifdef CONFIG_IPV6
 #include <net/ipv6.h>
@@ -117,8 +119,10 @@
    Alexey Kuznetsov.
  */
 
+static struct rtnl_link_ops ipgre_link_ops __read_mostly;
 static int ipgre_tunnel_init(struct net_device *dev);
 static void ipgre_tunnel_setup(struct net_device *dev);
+static int ipgre_tunnel_bind_dev(struct net_device *dev);
 
 /* Fallback tunnel: no source, no destination, no key, no options */
 
@@ -163,38 +167,64 @@
 /* Given src, dst and key, find appropriate for input tunnel. */
 
 static struct ip_tunnel * ipgre_tunnel_lookup(struct net *net,
-		__be32 remote, __be32 local, __be32 key)
+					      __be32 remote, __be32 local,
+					      __be32 key, __be16 gre_proto)
 {
 	unsigned h0 = HASH(remote);
 	unsigned h1 = HASH(key);
 	struct ip_tunnel *t;
+	struct ip_tunnel *t2 = NULL;
 	struct ipgre_net *ign = net_generic(net, ipgre_net_id);
+	int dev_type = (gre_proto == htons(ETH_P_TEB)) ?
+		       ARPHRD_ETHER : ARPHRD_IPGRE;
 
 	for (t = ign->tunnels_r_l[h0^h1]; t; t = t->next) {
 		if (local == t->parms.iph.saddr && remote == t->parms.iph.daddr) {
-			if (t->parms.i_key == key && (t->dev->flags&IFF_UP))
-				return t;
+			if (t->parms.i_key == key && t->dev->flags & IFF_UP) {
+				if (t->dev->type == dev_type)
+					return t;
+				if (t->dev->type == ARPHRD_IPGRE && !t2)
+					t2 = t;
+			}
 		}
 	}
+
 	for (t = ign->tunnels_r[h0^h1]; t; t = t->next) {
 		if (remote == t->parms.iph.daddr) {
-			if (t->parms.i_key == key && (t->dev->flags&IFF_UP))
-				return t;
+			if (t->parms.i_key == key && t->dev->flags & IFF_UP) {
+				if (t->dev->type == dev_type)
+					return t;
+				if (t->dev->type == ARPHRD_IPGRE && !t2)
+					t2 = t;
+			}
 		}
 	}
+
 	for (t = ign->tunnels_l[h1]; t; t = t->next) {
 		if (local == t->parms.iph.saddr ||
 		     (local == t->parms.iph.daddr &&
 		      ipv4_is_multicast(local))) {
-			if (t->parms.i_key == key && (t->dev->flags&IFF_UP))
-				return t;
+			if (t->parms.i_key == key && t->dev->flags & IFF_UP) {
+				if (t->dev->type == dev_type)
+					return t;
+				if (t->dev->type == ARPHRD_IPGRE && !t2)
+					t2 = t;
+			}
 		}
 	}
+
 	for (t = ign->tunnels_wc[h1]; t; t = t->next) {
-		if (t->parms.i_key == key && (t->dev->flags&IFF_UP))
-			return t;
+		if (t->parms.i_key == key && t->dev->flags & IFF_UP) {
+			if (t->dev->type == dev_type)
+				return t;
+			if (t->dev->type == ARPHRD_IPGRE && !t2)
+				t2 = t;
+		}
 	}
 
+	if (t2)
+		return t2;
+
 	if (ign->fb_tunnel_dev->flags&IFF_UP)
 		return netdev_priv(ign->fb_tunnel_dev);
 	return NULL;
@@ -249,25 +279,37 @@
 	}
 }
 
-static struct ip_tunnel * ipgre_tunnel_locate(struct net *net,
-		struct ip_tunnel_parm *parms, int create)
+static struct ip_tunnel *ipgre_tunnel_find(struct net *net,
+					   struct ip_tunnel_parm *parms,
+					   int type)
 {
 	__be32 remote = parms->iph.daddr;
 	__be32 local = parms->iph.saddr;
 	__be32 key = parms->i_key;
-	struct ip_tunnel *t, **tp, *nt;
+	struct ip_tunnel *t, **tp;
+	struct ipgre_net *ign = net_generic(net, ipgre_net_id);
+
+	for (tp = __ipgre_bucket(ign, parms); (t = *tp) != NULL; tp = &t->next)
+		if (local == t->parms.iph.saddr &&
+		    remote == t->parms.iph.daddr &&
+		    key == t->parms.i_key &&
+		    type == t->dev->type)
+			break;
+
+	return t;
+}
+
+static struct ip_tunnel * ipgre_tunnel_locate(struct net *net,
+		struct ip_tunnel_parm *parms, int create)
+{
+	struct ip_tunnel *t, *nt;
 	struct net_device *dev;
 	char name[IFNAMSIZ];
 	struct ipgre_net *ign = net_generic(net, ipgre_net_id);
 
-	for (tp = __ipgre_bucket(ign, parms); (t = *tp) != NULL; tp = &t->next) {
-		if (local == t->parms.iph.saddr && remote == t->parms.iph.daddr) {
-			if (key == t->parms.i_key)
-				return t;
-		}
-	}
-	if (!create)
-		return NULL;
+	t = ipgre_tunnel_find(net, parms, ARPHRD_IPGRE);
+	if (t || !create)
+		return t;
 
 	if (parms->name[0])
 		strlcpy(name, parms->name, IFNAMSIZ);
@@ -285,9 +327,11 @@
 			goto failed_free;
 	}
 
-	dev->init = ipgre_tunnel_init;
 	nt = netdev_priv(dev);
 	nt->parms = *parms;
+	dev->rtnl_link_ops = &ipgre_link_ops;
+
+	dev->mtu = ipgre_tunnel_bind_dev(dev);
 
 	if (register_netdevice(dev) < 0)
 		goto failed_free;
@@ -380,8 +424,9 @@
 
 	read_lock(&ipgre_lock);
 	t = ipgre_tunnel_lookup(dev_net(skb->dev), iph->daddr, iph->saddr,
-			(flags&GRE_KEY) ?
-			*(((__be32*)p) + (grehlen>>2) - 1) : 0);
+				flags & GRE_KEY ?
+				*(((__be32 *)p) + (grehlen / 4) - 1) : 0,
+				p[1]);
 	if (t == NULL || t->parms.iph.daddr == 0 ||
 	    ipv4_is_multicast(t->parms.iph.daddr))
 		goto out;
@@ -431,6 +476,8 @@
 	u32    seqno = 0;
 	struct ip_tunnel *tunnel;
 	int    offset = 4;
+	__be16 gre_proto;
+	unsigned int len;
 
 	if (!pskb_may_pull(skb, 16))
 		goto drop_nolock;
@@ -470,20 +517,22 @@
 		}
 	}
 
+	gre_proto = *(__be16 *)(h + 2);
+
 	read_lock(&ipgre_lock);
 	if ((tunnel = ipgre_tunnel_lookup(dev_net(skb->dev),
-					iph->saddr, iph->daddr, key)) != NULL) {
+					  iph->saddr, iph->daddr, key,
+					  gre_proto))) {
 		struct net_device_stats *stats = &tunnel->dev->stats;
 
 		secpath_reset(skb);
 
-		skb->protocol = *(__be16*)(h + 2);
+		skb->protocol = gre_proto;
 		/* WCCP version 1 and 2 protocol decoding.
 		 * - Change protocol to IP
 		 * - When dealing with WCCPv2, Skip extra 4 bytes in GRE header
 		 */
-		if (flags == 0 &&
-		    skb->protocol == htons(ETH_P_WCCP)) {
+		if (flags == 0 && gre_proto == htons(ETH_P_WCCP)) {
 			skb->protocol = htons(ETH_P_IP);
 			if ((*(h + offset) & 0xF0) != 0x40)
 				offset += 4;
@@ -491,7 +540,6 @@
 
 		skb->mac_header = skb->network_header;
 		__pskb_pull(skb, offset);
-		skb_reset_network_header(skb);
 		skb_postpull_rcsum(skb, skb_transport_header(skb), offset);
 		skb->pkt_type = PACKET_HOST;
 #ifdef CONFIG_NET_IPGRE_BROADCAST
@@ -519,13 +567,32 @@
 			}
 			tunnel->i_seqno = seqno + 1;
 		}
+
+		len = skb->len;
+
+		/* Warning: All skb pointers will be invalidated! */
+		if (tunnel->dev->type == ARPHRD_ETHER) {
+			if (!pskb_may_pull(skb, ETH_HLEN)) {
+				stats->rx_length_errors++;
+				stats->rx_errors++;
+				goto drop;
+			}
+
+			iph = ip_hdr(skb);
+			skb->protocol = eth_type_trans(skb, tunnel->dev);
+			skb_postpull_rcsum(skb, eth_hdr(skb), ETH_HLEN);
+		}
+
 		stats->rx_packets++;
-		stats->rx_bytes += skb->len;
+		stats->rx_bytes += len;
 		skb->dev = tunnel->dev;
 		dst_release(skb->dst);
 		skb->dst = NULL;
 		nf_reset(skb);
+
+		skb_reset_network_header(skb);
 		ipgre_ecn_decapsulate(iph, skb);
+
 		netif_rx(skb);
 		read_unlock(&ipgre_lock);
 		return(0);
@@ -560,7 +627,10 @@
 		goto tx_error;
 	}
 
-	if (dev->header_ops) {
+	if (dev->type == ARPHRD_ETHER)
+		IPCB(skb)->flags = 0;
+
+	if (dev->header_ops && dev->type == ARPHRD_IPGRE) {
 		gre_hlen = 0;
 		tiph = (struct iphdr*)skb->data;
 	} else {
@@ -637,7 +707,7 @@
 
 	df = tiph->frag_off;
 	if (df)
-		mtu = dst_mtu(&rt->u.dst) - tunnel->hlen;
+		mtu = dst_mtu(&rt->u.dst) - dev->hard_header_len - tunnel->hlen;
 	else
 		mtu = skb->dst ? dst_mtu(skb->dst) : dev->mtu;
 
@@ -703,7 +773,7 @@
 		old_iph = ip_hdr(skb);
 	}
 
-	skb->transport_header = skb->network_header;
+	skb_reset_transport_header(skb);
 	skb_push(skb, gre_hlen);
 	skb_reset_network_header(skb);
 	memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
@@ -736,8 +806,9 @@
 			iph->ttl = dst_metric(&rt->u.dst, RTAX_HOPLIMIT);
 	}
 
-	((__be16*)(iph+1))[0] = tunnel->parms.o_flags;
-	((__be16*)(iph+1))[1] = skb->protocol;
+	((__be16 *)(iph + 1))[0] = tunnel->parms.o_flags;
+	((__be16 *)(iph + 1))[1] = (dev->type == ARPHRD_ETHER) ?
+				   htons(ETH_P_TEB) : skb->protocol;
 
 	if (tunnel->parms.o_flags&(GRE_KEY|GRE_CSUM|GRE_SEQ)) {
 		__be32 *ptr = (__be32*)(((u8*)iph) + tunnel->hlen - 4);
@@ -773,7 +844,7 @@
 	return 0;
 }
 
-static void ipgre_tunnel_bind_dev(struct net_device *dev)
+static int ipgre_tunnel_bind_dev(struct net_device *dev)
 {
 	struct net_device *tdev = NULL;
 	struct ip_tunnel *tunnel;
@@ -785,7 +856,7 @@
 	tunnel = netdev_priv(dev);
 	iph = &tunnel->parms.iph;
 
-	/* Guess output device to choose reasonable mtu and hard_header_len */
+	/* Guess output device to choose reasonable mtu and needed_headroom */
 
 	if (iph->daddr) {
 		struct flowi fl = { .oif = tunnel->parms.link,
@@ -799,14 +870,16 @@
 			tdev = rt->u.dst.dev;
 			ip_rt_put(rt);
 		}
-		dev->flags |= IFF_POINTOPOINT;
+
+		if (dev->type != ARPHRD_ETHER)
+			dev->flags |= IFF_POINTOPOINT;
 	}
 
 	if (!tdev && tunnel->parms.link)
 		tdev = __dev_get_by_index(dev_net(dev), tunnel->parms.link);
 
 	if (tdev) {
-		hlen = tdev->hard_header_len;
+		hlen = tdev->hard_header_len + tdev->needed_headroom;
 		mtu = tdev->mtu;
 	}
 	dev->iflink = tunnel->parms.link;
@@ -820,10 +893,15 @@
 		if (tunnel->parms.o_flags&GRE_SEQ)
 			addend += 4;
 	}
-	dev->hard_header_len = hlen + addend;
-	dev->mtu = mtu - addend;
+	dev->needed_headroom = addend + hlen;
+	mtu -= dev->hard_header_len - addend;
+
+	if (mtu < 68)
+		mtu = 68;
+
 	tunnel->hlen = addend;
 
+	return mtu;
 }
 
 static int
@@ -917,7 +995,7 @@
 				t->parms.iph.frag_off = p.iph.frag_off;
 				if (t->parms.link != p.link) {
 					t->parms.link = p.link;
-					ipgre_tunnel_bind_dev(dev);
+					dev->mtu = ipgre_tunnel_bind_dev(dev);
 					netdev_state_change(dev);
 				}
 			}
@@ -959,7 +1037,8 @@
 static int ipgre_tunnel_change_mtu(struct net_device *dev, int new_mtu)
 {
 	struct ip_tunnel *tunnel = netdev_priv(dev);
-	if (new_mtu < 68 || new_mtu > 0xFFF8 - tunnel->hlen)
+	if (new_mtu < 68 ||
+	    new_mtu > 0xFFF8 - dev->hard_header_len - tunnel->hlen)
 		return -EINVAL;
 	dev->mtu = new_mtu;
 	return 0;
@@ -1078,6 +1157,7 @@
 
 static void ipgre_tunnel_setup(struct net_device *dev)
 {
+	dev->init		= ipgre_tunnel_init;
 	dev->uninit		= ipgre_tunnel_uninit;
 	dev->destructor 	= free_netdev;
 	dev->hard_start_xmit	= ipgre_tunnel_xmit;
@@ -1085,7 +1165,7 @@
 	dev->change_mtu		= ipgre_tunnel_change_mtu;
 
 	dev->type		= ARPHRD_IPGRE;
-	dev->hard_header_len 	= LL_MAX_HEADER + sizeof(struct iphdr) + 4;
+	dev->needed_headroom 	= LL_MAX_HEADER + sizeof(struct iphdr) + 4;
 	dev->mtu		= ETH_DATA_LEN - sizeof(struct iphdr) - 4;
 	dev->flags		= IFF_NOARP;
 	dev->iflink		= 0;
@@ -1107,8 +1187,6 @@
 	memcpy(dev->dev_addr, &tunnel->parms.iph.saddr, 4);
 	memcpy(dev->broadcast, &tunnel->parms.iph.daddr, 4);
 
-	ipgre_tunnel_bind_dev(dev);
-
 	if (iph->daddr) {
 #ifdef CONFIG_NET_IPGRE_BROADCAST
 		if (ipv4_is_multicast(iph->daddr)) {
@@ -1189,6 +1267,7 @@
 
 	ign->fb_tunnel_dev->init = ipgre_fb_tunnel_init;
 	dev_net_set(ign->fb_tunnel_dev, net);
+	ign->fb_tunnel_dev->rtnl_link_ops = &ipgre_link_ops;
 
 	if ((err = register_netdev(ign->fb_tunnel_dev)))
 		goto err_reg_dev;
@@ -1221,6 +1300,298 @@
 	.exit = ipgre_exit_net,
 };
 
+static int ipgre_tunnel_validate(struct nlattr *tb[], struct nlattr *data[])
+{
+	__be16 flags;
+
+	if (!data)
+		return 0;
+
+	flags = 0;
+	if (data[IFLA_GRE_IFLAGS])
+		flags |= nla_get_be16(data[IFLA_GRE_IFLAGS]);
+	if (data[IFLA_GRE_OFLAGS])
+		flags |= nla_get_be16(data[IFLA_GRE_OFLAGS]);
+	if (flags & (GRE_VERSION|GRE_ROUTING))
+		return -EINVAL;
+
+	return 0;
+}
+
+static int ipgre_tap_validate(struct nlattr *tb[], struct nlattr *data[])
+{
+	__be32 daddr;
+
+	if (tb[IFLA_ADDRESS]) {
+		if (nla_len(tb[IFLA_ADDRESS]) != ETH_ALEN)
+			return -EINVAL;
+		if (!is_valid_ether_addr(nla_data(tb[IFLA_ADDRESS])))
+			return -EADDRNOTAVAIL;
+	}
+
+	if (!data)
+		goto out;
+
+	if (data[IFLA_GRE_REMOTE]) {
+		memcpy(&daddr, nla_data(data[IFLA_GRE_REMOTE]), 4);
+		if (!daddr)
+			return -EINVAL;
+	}
+
+out:
+	return ipgre_tunnel_validate(tb, data);
+}
+
+static void ipgre_netlink_parms(struct nlattr *data[],
+				struct ip_tunnel_parm *parms)
+{
+	memset(parms, 0, sizeof(*parms));
+
+	parms->iph.protocol = IPPROTO_GRE;
+
+	if (!data)
+		return;
+
+	if (data[IFLA_GRE_LINK])
+		parms->link = nla_get_u32(data[IFLA_GRE_LINK]);
+
+	if (data[IFLA_GRE_IFLAGS])
+		parms->i_flags = nla_get_be16(data[IFLA_GRE_IFLAGS]);
+
+	if (data[IFLA_GRE_OFLAGS])
+		parms->o_flags = nla_get_be16(data[IFLA_GRE_OFLAGS]);
+
+	if (data[IFLA_GRE_IKEY])
+		parms->i_key = nla_get_be32(data[IFLA_GRE_IKEY]);
+
+	if (data[IFLA_GRE_OKEY])
+		parms->o_key = nla_get_be32(data[IFLA_GRE_OKEY]);
+
+	if (data[IFLA_GRE_LOCAL])
+		parms->iph.saddr = nla_get_be32(data[IFLA_GRE_LOCAL]);
+
+	if (data[IFLA_GRE_REMOTE])
+		parms->iph.daddr = nla_get_be32(data[IFLA_GRE_REMOTE]);
+
+	if (data[IFLA_GRE_TTL])
+		parms->iph.ttl = nla_get_u8(data[IFLA_GRE_TTL]);
+
+	if (data[IFLA_GRE_TOS])
+		parms->iph.tos = nla_get_u8(data[IFLA_GRE_TOS]);
+
+	if (!data[IFLA_GRE_PMTUDISC] || nla_get_u8(data[IFLA_GRE_PMTUDISC]))
+		parms->iph.frag_off = htons(IP_DF);
+}
+
+static int ipgre_tap_init(struct net_device *dev)
+{
+	struct ip_tunnel *tunnel;
+
+	tunnel = netdev_priv(dev);
+
+	tunnel->dev = dev;
+	strcpy(tunnel->parms.name, dev->name);
+
+	ipgre_tunnel_bind_dev(dev);
+
+	return 0;
+}
+
+static void ipgre_tap_setup(struct net_device *dev)
+{
+
+	ether_setup(dev);
+
+	dev->init		= ipgre_tap_init;
+	dev->uninit		= ipgre_tunnel_uninit;
+	dev->destructor 	= free_netdev;
+	dev->hard_start_xmit	= ipgre_tunnel_xmit;
+	dev->change_mtu		= ipgre_tunnel_change_mtu;
+
+	dev->iflink		= 0;
+	dev->features		|= NETIF_F_NETNS_LOCAL;
+}
+
+static int ipgre_newlink(struct net_device *dev, struct nlattr *tb[],
+			 struct nlattr *data[])
+{
+	struct ip_tunnel *nt;
+	struct net *net = dev_net(dev);
+	struct ipgre_net *ign = net_generic(net, ipgre_net_id);
+	int mtu;
+	int err;
+
+	nt = netdev_priv(dev);
+	ipgre_netlink_parms(data, &nt->parms);
+
+	if (ipgre_tunnel_find(net, &nt->parms, dev->type))
+		return -EEXIST;
+
+	if (dev->type == ARPHRD_ETHER && !tb[IFLA_ADDRESS])
+		random_ether_addr(dev->dev_addr);
+
+	mtu = ipgre_tunnel_bind_dev(dev);
+	if (!tb[IFLA_MTU])
+		dev->mtu = mtu;
+
+	err = register_netdevice(dev);
+	if (err)
+		goto out;
+
+	dev_hold(dev);
+	ipgre_tunnel_link(ign, nt);
+
+out:
+	return err;
+}
+
+static int ipgre_changelink(struct net_device *dev, struct nlattr *tb[],
+			    struct nlattr *data[])
+{
+	struct ip_tunnel *t, *nt;
+	struct net *net = dev_net(dev);
+	struct ipgre_net *ign = net_generic(net, ipgre_net_id);
+	struct ip_tunnel_parm p;
+	int mtu;
+
+	if (dev == ign->fb_tunnel_dev)
+		return -EINVAL;
+
+	nt = netdev_priv(dev);
+	ipgre_netlink_parms(data, &p);
+
+	t = ipgre_tunnel_locate(net, &p, 0);
+
+	if (t) {
+		if (t->dev != dev)
+			return -EEXIST;
+	} else {
+		unsigned nflags = 0;
+
+		t = nt;
+
+		if (ipv4_is_multicast(p.iph.daddr))
+			nflags = IFF_BROADCAST;
+		else if (p.iph.daddr)
+			nflags = IFF_POINTOPOINT;
+
+		if ((dev->flags ^ nflags) &
+		    (IFF_POINTOPOINT | IFF_BROADCAST))
+			return -EINVAL;
+
+		ipgre_tunnel_unlink(ign, t);
+		t->parms.iph.saddr = p.iph.saddr;
+		t->parms.iph.daddr = p.iph.daddr;
+		t->parms.i_key = p.i_key;
+		memcpy(dev->dev_addr, &p.iph.saddr, 4);
+		memcpy(dev->broadcast, &p.iph.daddr, 4);
+		ipgre_tunnel_link(ign, t);
+		netdev_state_change(dev);
+	}
+
+	t->parms.o_key = p.o_key;
+	t->parms.iph.ttl = p.iph.ttl;
+	t->parms.iph.tos = p.iph.tos;
+	t->parms.iph.frag_off = p.iph.frag_off;
+
+	if (t->parms.link != p.link) {
+		t->parms.link = p.link;
+		mtu = ipgre_tunnel_bind_dev(dev);
+		if (!tb[IFLA_MTU])
+			dev->mtu = mtu;
+		netdev_state_change(dev);
+	}
+
+	return 0;
+}
+
+static size_t ipgre_get_size(const struct net_device *dev)
+{
+	return
+		/* IFLA_GRE_LINK */
+		nla_total_size(4) +
+		/* IFLA_GRE_IFLAGS */
+		nla_total_size(2) +
+		/* IFLA_GRE_OFLAGS */
+		nla_total_size(2) +
+		/* IFLA_GRE_IKEY */
+		nla_total_size(4) +
+		/* IFLA_GRE_OKEY */
+		nla_total_size(4) +
+		/* IFLA_GRE_LOCAL */
+		nla_total_size(4) +
+		/* IFLA_GRE_REMOTE */
+		nla_total_size(4) +
+		/* IFLA_GRE_TTL */
+		nla_total_size(1) +
+		/* IFLA_GRE_TOS */
+		nla_total_size(1) +
+		/* IFLA_GRE_PMTUDISC */
+		nla_total_size(1) +
+		0;
+}
+
+static int ipgre_fill_info(struct sk_buff *skb, const struct net_device *dev)
+{
+	struct ip_tunnel *t = netdev_priv(dev);
+	struct ip_tunnel_parm *p = &t->parms;
+
+	NLA_PUT_U32(skb, IFLA_GRE_LINK, p->link);
+	NLA_PUT_BE16(skb, IFLA_GRE_IFLAGS, p->i_flags);
+	NLA_PUT_BE16(skb, IFLA_GRE_OFLAGS, p->o_flags);
+	NLA_PUT_BE32(skb, IFLA_GRE_IKEY, p->i_key);
+	NLA_PUT_BE32(skb, IFLA_GRE_OKEY, p->o_key);
+	NLA_PUT_BE32(skb, IFLA_GRE_LOCAL, p->iph.saddr);
+	NLA_PUT_BE32(skb, IFLA_GRE_REMOTE, p->iph.daddr);
+	NLA_PUT_U8(skb, IFLA_GRE_TTL, p->iph.ttl);
+	NLA_PUT_U8(skb, IFLA_GRE_TOS, p->iph.tos);
+	NLA_PUT_U8(skb, IFLA_GRE_PMTUDISC, !!(p->iph.frag_off & htons(IP_DF)));
+
+	return 0;
+
+nla_put_failure:
+	return -EMSGSIZE;
+}
+
+static const struct nla_policy ipgre_policy[IFLA_GRE_MAX + 1] = {
+	[IFLA_GRE_LINK]		= { .type = NLA_U32 },
+	[IFLA_GRE_IFLAGS]	= { .type = NLA_U16 },
+	[IFLA_GRE_OFLAGS]	= { .type = NLA_U16 },
+	[IFLA_GRE_IKEY]		= { .type = NLA_U32 },
+	[IFLA_GRE_OKEY]		= { .type = NLA_U32 },
+	[IFLA_GRE_LOCAL]	= { .len = FIELD_SIZEOF(struct iphdr, saddr) },
+	[IFLA_GRE_REMOTE]	= { .len = FIELD_SIZEOF(struct iphdr, daddr) },
+	[IFLA_GRE_TTL]		= { .type = NLA_U8 },
+	[IFLA_GRE_TOS]		= { .type = NLA_U8 },
+	[IFLA_GRE_PMTUDISC]	= { .type = NLA_U8 },
+};
+
+static struct rtnl_link_ops ipgre_link_ops __read_mostly = {
+	.kind		= "gre",
+	.maxtype	= IFLA_GRE_MAX,
+	.policy		= ipgre_policy,
+	.priv_size	= sizeof(struct ip_tunnel),
+	.setup		= ipgre_tunnel_setup,
+	.validate	= ipgre_tunnel_validate,
+	.newlink	= ipgre_newlink,
+	.changelink	= ipgre_changelink,
+	.get_size	= ipgre_get_size,
+	.fill_info	= ipgre_fill_info,
+};
+
+static struct rtnl_link_ops ipgre_tap_ops __read_mostly = {
+	.kind		= "gretap",
+	.maxtype	= IFLA_GRE_MAX,
+	.policy		= ipgre_policy,
+	.priv_size	= sizeof(struct ip_tunnel),
+	.setup		= ipgre_tap_setup,
+	.validate	= ipgre_tap_validate,
+	.newlink	= ipgre_newlink,
+	.changelink	= ipgre_changelink,
+	.get_size	= ipgre_get_size,
+	.fill_info	= ipgre_fill_info,
+};
+
 /*
  *	And now the modules code and kernel interface.
  */
@@ -1238,19 +1609,39 @@
 
 	err = register_pernet_gen_device(&ipgre_net_id, &ipgre_net_ops);
 	if (err < 0)
-		inet_del_protocol(&ipgre_protocol, IPPROTO_GRE);
+		goto gen_device_failed;
 
+	err = rtnl_link_register(&ipgre_link_ops);
+	if (err < 0)
+		goto rtnl_link_failed;
+
+	err = rtnl_link_register(&ipgre_tap_ops);
+	if (err < 0)
+		goto tap_ops_failed;
+
+out:
 	return err;
+
+tap_ops_failed:
+	rtnl_link_unregister(&ipgre_link_ops);
+rtnl_link_failed:
+	unregister_pernet_gen_device(ipgre_net_id, &ipgre_net_ops);
+gen_device_failed:
+	inet_del_protocol(&ipgre_protocol, IPPROTO_GRE);
+	goto out;
 }
 
 static void __exit ipgre_fini(void)
 {
+	rtnl_link_unregister(&ipgre_tap_ops);
+	rtnl_link_unregister(&ipgre_link_ops);
+	unregister_pernet_gen_device(ipgre_net_id, &ipgre_net_ops);
 	if (inet_del_protocol(&ipgre_protocol, IPPROTO_GRE) < 0)
 		printk(KERN_INFO "ipgre close: can't remove protocol\n");
-
-	unregister_pernet_gen_device(ipgre_net_id, &ipgre_net_ops);
 }
 
 module_init(ipgre_init);
 module_exit(ipgre_fini);
 MODULE_LICENSE("GPL");
+MODULE_ALIAS_RTNL_LINK("gre");
+MODULE_ALIAS_RTNL_LINK("gretap");
diff --git a/net/ipv4/ip_input.c b/net/ipv4/ip_input.c
index e0bed56..861978a 100644
--- a/net/ipv4/ip_input.c
+++ b/net/ipv4/ip_input.c
@@ -8,7 +8,7 @@
  * Authors:	Ross Biro
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
  *		Donald Becker, <becker@super.org>
- *		Alan Cox, <Alan.Cox@linux.org>
+ *		Alan Cox, <alan@lxorguk.ukuu.org.uk>
  *		Richard Underwood
  *		Stefan Becker, <stefanb@yello.ping.de>
  *		Jorge Cwik, <jorge@laser.satlink.net>
diff --git a/net/ipv4/ip_options.c b/net/ipv4/ip_options.c
index be3f18a..2c88da6 100644
--- a/net/ipv4/ip_options.c
+++ b/net/ipv4/ip_options.c
@@ -438,7 +438,7 @@
 				goto error;
 			}
 			opt->cipso = optptr - iph;
-			if (cipso_v4_validate(&optptr)) {
+			if (cipso_v4_validate(skb, &optptr)) {
 				pp_ptr = optptr;
 				goto error;
 			}
diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c
index d533a89..d2a8f8b 100644
--- a/net/ipv4/ip_output.c
+++ b/net/ipv4/ip_output.c
@@ -340,6 +340,7 @@
 							.saddr = inet->saddr,
 							.tos = RT_CONN_FLAGS(sk) } },
 					    .proto = sk->sk_protocol,
+					    .flags = inet_sk_flowi_flags(sk),
 					    .uli_u = { .ports =
 						       { .sport = inet->sport,
 							 .dport = inet->dport } } };
@@ -1371,7 +1372,8 @@
 				    .uli_u = { .ports =
 					       { .sport = tcp_hdr(skb)->dest,
 						 .dport = tcp_hdr(skb)->source } },
-				    .proto = sk->sk_protocol };
+				    .proto = sk->sk_protocol,
+				    .flags = ip_reply_arg_flowi_flags(arg) };
 		security_skb_classify_flow(skb, &fl);
 		if (ip_route_output_key(sock_net(sk), &rt, &fl))
 			return;
diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c
index 105d92a..465abf0 100644
--- a/net/ipv4/ip_sockglue.c
+++ b/net/ipv4/ip_sockglue.c
@@ -419,7 +419,7 @@
 			     (1<<IP_TTL) | (1<<IP_HDRINCL) |
 			     (1<<IP_MTU_DISCOVER) | (1<<IP_RECVERR) |
 			     (1<<IP_ROUTER_ALERT) | (1<<IP_FREEBIND) |
-			     (1<<IP_PASSSEC))) ||
+			     (1<<IP_PASSSEC) | (1<<IP_TRANSPARENT))) ||
 	    optname == IP_MULTICAST_TTL ||
 	    optname == IP_MULTICAST_LOOP) {
 		if (optlen >= sizeof(int)) {
@@ -878,6 +878,16 @@
 		err = xfrm_user_policy(sk, optname, optval, optlen);
 		break;
 
+	case IP_TRANSPARENT:
+		if (!capable(CAP_NET_ADMIN)) {
+			err = -EPERM;
+			break;
+		}
+		if (optlen < 1)
+			goto e_inval;
+		inet->transparent = !!val;
+		break;
+
 	default:
 		err = -ENOPROTOOPT;
 		break;
@@ -1130,6 +1140,9 @@
 	case IP_FREEBIND:
 		val = inet->freebind;
 		break;
+	case IP_TRANSPARENT:
+		val = inet->transparent;
+		break;
 	default:
 		release_sock(sk);
 		return -ENOPROTOOPT;
diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c
index 4c6d2ca..29609d2 100644
--- a/net/ipv4/ipip.c
+++ b/net/ipv4/ipip.c
@@ -41,7 +41,7 @@
 		Made the tunnels use dev->name not tunnel: when error reporting.
 		Added tx_dropped stat
 
-		-Alan Cox	(Alan.Cox@linux.org) 21 March 95
+		-Alan Cox	(alan@lxorguk.ukuu.org.uk) 21 March 95
 
 	Reworked:
 		Changed to tunnel to destination gateway in addition to the
diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c
index c519b8d..b42e082 100644
--- a/net/ipv4/ipmr.c
+++ b/net/ipv4/ipmr.c
@@ -1,7 +1,7 @@
 /*
  *	IP multicast routing support for mrouted 3.6/3.8
  *
- *		(c) 1995 Alan Cox, <alan@redhat.com>
+ *		(c) 1995 Alan Cox, <alan@lxorguk.ukuu.org.uk>
  *	  Linux Consultancy and Custom Driver Development
  *
  *	This program is free software; you can redistribute it and/or
diff --git a/net/ipv4/ipvs/Kconfig b/net/ipv4/ipvs/Kconfig
deleted file mode 100644
index 09d0c3f..0000000
--- a/net/ipv4/ipvs/Kconfig
+++ /dev/null
@@ -1,224 +0,0 @@
-#
-# IP Virtual Server configuration
-#
-menuconfig IP_VS
-	tristate "IP virtual server support (EXPERIMENTAL)"
-	depends on NETFILTER
-	---help---
-	  IP Virtual Server support will let you build a high-performance
-	  virtual server based on cluster of two or more real servers. This
-	  option must be enabled for at least one of the clustered computers
-	  that will take care of intercepting incoming connections to a
-	  single IP address and scheduling them to real servers.
-
-	  Three request dispatching techniques are implemented, they are
-	  virtual server via NAT, virtual server via tunneling and virtual
-	  server via direct routing. The several scheduling algorithms can
-	  be used to choose which server the connection is directed to,
-	  thus load balancing can be achieved among the servers.  For more
-	  information and its administration program, please visit the
-	  following URL: <http://www.linuxvirtualserver.org/>.
-
-	  If you want to compile it in kernel, say Y. To compile it as a
-	  module, choose M here. If unsure, say N.
-
-if IP_VS
-
-config	IP_VS_DEBUG
-	bool "IP virtual server debugging"
-	---help---
-	  Say Y here if you want to get additional messages useful in
-	  debugging the IP virtual server code. You can change the debug
-	  level in /proc/sys/net/ipv4/vs/debug_level
-
-config	IP_VS_TAB_BITS
-	int "IPVS connection table size (the Nth power of 2)"
-	default "12" 
-	---help---
-	  The IPVS connection hash table uses the chaining scheme to handle
-	  hash collisions. Using a big IPVS connection hash table will greatly
-	  reduce conflicts when there are hundreds of thousands of connections
-	  in the hash table.
-
-	  Note the table size must be power of 2. The table size will be the
-	  value of 2 to the your input number power. The number to choose is
-	  from 8 to 20, the default number is 12, which means the table size
-	  is 4096. Don't input the number too small, otherwise you will lose
-	  performance on it. You can adapt the table size yourself, according
-	  to your virtual server application. It is good to set the table size
-	  not far less than the number of connections per second multiplying
-	  average lasting time of connection in the table.  For example, your
-	  virtual server gets 200 connections per second, the connection lasts
-	  for 200 seconds in average in the connection table, the table size
-	  should be not far less than 200x200, it is good to set the table
-	  size 32768 (2**15).
-
-	  Another note that each connection occupies 128 bytes effectively and
-	  each hash entry uses 8 bytes, so you can estimate how much memory is
-	  needed for your box.
-
-comment "IPVS transport protocol load balancing support"
-
-config	IP_VS_PROTO_TCP
-	bool "TCP load balancing support"
-	---help---
-	  This option enables support for load balancing TCP transport
-	  protocol. Say Y if unsure.
-
-config	IP_VS_PROTO_UDP
-	bool "UDP load balancing support"
-	---help---
-	  This option enables support for load balancing UDP transport
-	  protocol. Say Y if unsure.
-
-config	IP_VS_PROTO_ESP
-	bool "ESP load balancing support"
-	---help---
-	  This option enables support for load balancing ESP (Encapsulation
-	  Security Payload) transport protocol. Say Y if unsure.
-
-config	IP_VS_PROTO_AH
-	bool "AH load balancing support"
-	---help---
-	  This option enables support for load balancing AH (Authentication
-	  Header) transport protocol. Say Y if unsure.
-
-comment "IPVS scheduler"
-
-config	IP_VS_RR
-	tristate "round-robin scheduling"
-	---help---
-	  The robin-robin scheduling algorithm simply directs network
-	  connections to different real servers in a round-robin manner.
-
-	  If you want to compile it in kernel, say Y. To compile it as a
-	  module, choose M here. If unsure, say N.
- 
-config	IP_VS_WRR
-        tristate "weighted round-robin scheduling" 
-	---help---
-	  The weighted robin-robin scheduling algorithm directs network
-	  connections to different real servers based on server weights
-	  in a round-robin manner. Servers with higher weights receive
-	  new connections first than those with less weights, and servers
-	  with higher weights get more connections than those with less
-	  weights and servers with equal weights get equal connections.
-
-	  If you want to compile it in kernel, say Y. To compile it as a
-	  module, choose M here. If unsure, say N.
-
-config	IP_VS_LC
-        tristate "least-connection scheduling"
-	---help---
-	  The least-connection scheduling algorithm directs network
-	  connections to the server with the least number of active 
-	  connections.
-
-	  If you want to compile it in kernel, say Y. To compile it as a
-	  module, choose M here. If unsure, say N.
-
-config	IP_VS_WLC
-        tristate "weighted least-connection scheduling"
-	---help---
-	  The weighted least-connection scheduling algorithm directs network
-	  connections to the server with the least active connections
-	  normalized by the server weight.
-
-	  If you want to compile it in kernel, say Y. To compile it as a
-	  module, choose M here. If unsure, say N.
-
-config	IP_VS_LBLC
-	tristate "locality-based least-connection scheduling"
-	---help---
-	  The locality-based least-connection scheduling algorithm is for
-	  destination IP load balancing. It is usually used in cache cluster.
-	  This algorithm usually directs packet destined for an IP address to
-	  its server if the server is alive and under load. If the server is
-	  overloaded (its active connection numbers is larger than its weight)
-	  and there is a server in its half load, then allocate the weighted
-	  least-connection server to this IP address.
-
-	  If you want to compile it in kernel, say Y. To compile it as a
-	  module, choose M here. If unsure, say N.
-
-config  IP_VS_LBLCR
-	tristate "locality-based least-connection with replication scheduling"
-	---help---
-	  The locality-based least-connection with replication scheduling
-	  algorithm is also for destination IP load balancing. It is 
-	  usually used in cache cluster. It differs from the LBLC scheduling
-	  as follows: the load balancer maintains mappings from a target
-	  to a set of server nodes that can serve the target. Requests for
-	  a target are assigned to the least-connection node in the target's
-	  server set. If all the node in the server set are over loaded,
-	  it picks up a least-connection node in the cluster and adds it
-	  in the sever set for the target. If the server set has not been
-	  modified for the specified time, the most loaded node is removed
-	  from the server set, in order to avoid high degree of replication.
-
-	  If you want to compile it in kernel, say Y. To compile it as a
-	  module, choose M here. If unsure, say N.
-
-config	IP_VS_DH
-	tristate "destination hashing scheduling"
-	---help---
-	  The destination hashing scheduling algorithm assigns network
-	  connections to the servers through looking up a statically assigned
-	  hash table by their destination IP addresses.
-
-	  If you want to compile it in kernel, say Y. To compile it as a
-	  module, choose M here. If unsure, say N.
-
-config	IP_VS_SH
-	tristate "source hashing scheduling"
-	---help---
-	  The source hashing scheduling algorithm assigns network
-	  connections to the servers through looking up a statically assigned
-	  hash table by their source IP addresses.
-
-	  If you want to compile it in kernel, say Y. To compile it as a
-	  module, choose M here. If unsure, say N.
-
-config	IP_VS_SED
-	tristate "shortest expected delay scheduling"
-	---help---
-	  The shortest expected delay scheduling algorithm assigns network
-	  connections to the server with the shortest expected delay. The 
-	  expected delay that the job will experience is (Ci + 1) / Ui if 
-	  sent to the ith server, in which Ci is the number of connections
-	  on the ith server and Ui is the fixed service rate (weight)
-	  of the ith server.
-
-	  If you want to compile it in kernel, say Y. To compile it as a
-	  module, choose M here. If unsure, say N.
-
-config	IP_VS_NQ
-	tristate "never queue scheduling"
-	---help---
-	  The never queue scheduling algorithm adopts a two-speed model.
-	  When there is an idle server available, the job will be sent to
-	  the idle server, instead of waiting for a fast one. When there
-	  is no idle server available, the job will be sent to the server
-	  that minimize its expected delay (The Shortest Expected Delay
-	  scheduling algorithm).
-
-	  If you want to compile it in kernel, say Y. To compile it as a
-	  module, choose M here. If unsure, say N.
-
-comment 'IPVS application helper'
-
-config	IP_VS_FTP
-  	tristate "FTP protocol helper"
-        depends on IP_VS_PROTO_TCP
-	---help---
-	  FTP is a protocol that transfers IP address and/or port number in
-	  the payload. In the virtual server via Network Address Translation,
-	  the IP address and port number of real servers cannot be sent to
-	  clients in ftp connections directly, so FTP protocol helper is
-	  required for tracking the connection and mangling it back to that of
-	  virtual service.
-
-	  If you want to compile it in kernel, say Y. To compile it as a
-	  module, choose M here. If unsure, say N.
-
-endif # IP_VS
diff --git a/net/ipv4/ipvs/Makefile b/net/ipv4/ipvs/Makefile
deleted file mode 100644
index 30e85de..0000000
--- a/net/ipv4/ipvs/Makefile
+++ /dev/null
@@ -1,34 +0,0 @@
-#
-# Makefile for the IPVS modules on top of IPv4.
-#
-
-# IPVS transport protocol load balancing support
-ip_vs_proto-objs-y :=
-ip_vs_proto-objs-$(CONFIG_IP_VS_PROTO_TCP) += ip_vs_proto_tcp.o
-ip_vs_proto-objs-$(CONFIG_IP_VS_PROTO_UDP) += ip_vs_proto_udp.o
-ip_vs_proto-objs-$(CONFIG_IP_VS_PROTO_ESP) += ip_vs_proto_esp.o
-ip_vs_proto-objs-$(CONFIG_IP_VS_PROTO_AH) += ip_vs_proto_ah.o
-
-ip_vs-objs :=	ip_vs_conn.o ip_vs_core.o ip_vs_ctl.o ip_vs_sched.o	   \
-		ip_vs_xmit.o ip_vs_app.o ip_vs_sync.o	   		   \
-		ip_vs_est.o ip_vs_proto.o 				   \
-		$(ip_vs_proto-objs-y)
-
-
-# IPVS core
-obj-$(CONFIG_IP_VS) += ip_vs.o
-
-# IPVS schedulers
-obj-$(CONFIG_IP_VS_RR) += ip_vs_rr.o
-obj-$(CONFIG_IP_VS_WRR) += ip_vs_wrr.o
-obj-$(CONFIG_IP_VS_LC) += ip_vs_lc.o
-obj-$(CONFIG_IP_VS_WLC) += ip_vs_wlc.o
-obj-$(CONFIG_IP_VS_LBLC) += ip_vs_lblc.o
-obj-$(CONFIG_IP_VS_LBLCR) += ip_vs_lblcr.o
-obj-$(CONFIG_IP_VS_DH) += ip_vs_dh.o
-obj-$(CONFIG_IP_VS_SH) += ip_vs_sh.o
-obj-$(CONFIG_IP_VS_SED) += ip_vs_sed.o
-obj-$(CONFIG_IP_VS_NQ) += ip_vs_nq.o
-
-# IPVS application helpers
-obj-$(CONFIG_IP_VS_FTP) += ip_vs_ftp.o
diff --git a/net/ipv4/ipvs/ip_vs_conn.c b/net/ipv4/ipvs/ip_vs_conn.c
deleted file mode 100644
index 44a6872..0000000
--- a/net/ipv4/ipvs/ip_vs_conn.c
+++ /dev/null
@@ -1,1023 +0,0 @@
-/*
- * IPVS         An implementation of the IP virtual server support for the
- *              LINUX operating system.  IPVS is now implemented as a module
- *              over the Netfilter framework. IPVS can be used to build a
- *              high-performance and highly available server based on a
- *              cluster of servers.
- *
- * Authors:     Wensong Zhang <wensong@linuxvirtualserver.org>
- *              Peter Kese <peter.kese@ijs.si>
- *              Julian Anastasov <ja@ssi.bg>
- *
- *              This program is free software; you can redistribute it and/or
- *              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.
- *
- * The IPVS code for kernel 2.2 was done by Wensong Zhang and Peter Kese,
- * with changes/fixes from Julian Anastasov, Lars Marowsky-Bree, Horms
- * and others. Many code here is taken from IP MASQ code of kernel 2.2.
- *
- * Changes:
- *
- */
-
-#include <linux/interrupt.h>
-#include <linux/in.h>
-#include <linux/net.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/vmalloc.h>
-#include <linux/proc_fs.h>		/* for proc_net_* */
-#include <linux/seq_file.h>
-#include <linux/jhash.h>
-#include <linux/random.h>
-
-#include <net/net_namespace.h>
-#include <net/ip_vs.h>
-
-
-/*
- *  Connection hash table: for input and output packets lookups of IPVS
- */
-static struct list_head *ip_vs_conn_tab;
-
-/*  SLAB cache for IPVS connections */
-static struct kmem_cache *ip_vs_conn_cachep __read_mostly;
-
-/*  counter for current IPVS connections */
-static atomic_t ip_vs_conn_count = ATOMIC_INIT(0);
-
-/*  counter for no client port connections */
-static atomic_t ip_vs_conn_no_cport_cnt = ATOMIC_INIT(0);
-
-/* random value for IPVS connection hash */
-static unsigned int ip_vs_conn_rnd;
-
-/*
- *  Fine locking granularity for big connection hash table
- */
-#define CT_LOCKARRAY_BITS  4
-#define CT_LOCKARRAY_SIZE  (1<<CT_LOCKARRAY_BITS)
-#define CT_LOCKARRAY_MASK  (CT_LOCKARRAY_SIZE-1)
-
-struct ip_vs_aligned_lock
-{
-	rwlock_t	l;
-} __attribute__((__aligned__(SMP_CACHE_BYTES)));
-
-/* lock array for conn table */
-static struct ip_vs_aligned_lock
-__ip_vs_conntbl_lock_array[CT_LOCKARRAY_SIZE] __cacheline_aligned;
-
-static inline void ct_read_lock(unsigned key)
-{
-	read_lock(&__ip_vs_conntbl_lock_array[key&CT_LOCKARRAY_MASK].l);
-}
-
-static inline void ct_read_unlock(unsigned key)
-{
-	read_unlock(&__ip_vs_conntbl_lock_array[key&CT_LOCKARRAY_MASK].l);
-}
-
-static inline void ct_write_lock(unsigned key)
-{
-	write_lock(&__ip_vs_conntbl_lock_array[key&CT_LOCKARRAY_MASK].l);
-}
-
-static inline void ct_write_unlock(unsigned key)
-{
-	write_unlock(&__ip_vs_conntbl_lock_array[key&CT_LOCKARRAY_MASK].l);
-}
-
-static inline void ct_read_lock_bh(unsigned key)
-{
-	read_lock_bh(&__ip_vs_conntbl_lock_array[key&CT_LOCKARRAY_MASK].l);
-}
-
-static inline void ct_read_unlock_bh(unsigned key)
-{
-	read_unlock_bh(&__ip_vs_conntbl_lock_array[key&CT_LOCKARRAY_MASK].l);
-}
-
-static inline void ct_write_lock_bh(unsigned key)
-{
-	write_lock_bh(&__ip_vs_conntbl_lock_array[key&CT_LOCKARRAY_MASK].l);
-}
-
-static inline void ct_write_unlock_bh(unsigned key)
-{
-	write_unlock_bh(&__ip_vs_conntbl_lock_array[key&CT_LOCKARRAY_MASK].l);
-}
-
-
-/*
- *	Returns hash value for IPVS connection entry
- */
-static unsigned int ip_vs_conn_hashkey(unsigned proto, __be32 addr, __be16 port)
-{
-	return jhash_3words((__force u32)addr, (__force u32)port, proto, ip_vs_conn_rnd)
-		& IP_VS_CONN_TAB_MASK;
-}
-
-
-/*
- *	Hashes ip_vs_conn in ip_vs_conn_tab by proto,addr,port.
- *	returns bool success.
- */
-static inline int ip_vs_conn_hash(struct ip_vs_conn *cp)
-{
-	unsigned hash;
-	int ret;
-
-	/* Hash by protocol, client address and port */
-	hash = ip_vs_conn_hashkey(cp->protocol, cp->caddr, cp->cport);
-
-	ct_write_lock(hash);
-
-	if (!(cp->flags & IP_VS_CONN_F_HASHED)) {
-		list_add(&cp->c_list, &ip_vs_conn_tab[hash]);
-		cp->flags |= IP_VS_CONN_F_HASHED;
-		atomic_inc(&cp->refcnt);
-		ret = 1;
-	} else {
-		IP_VS_ERR("ip_vs_conn_hash(): request for already hashed, "
-			  "called from %p\n", __builtin_return_address(0));
-		ret = 0;
-	}
-
-	ct_write_unlock(hash);
-
-	return ret;
-}
-
-
-/*
- *	UNhashes ip_vs_conn from ip_vs_conn_tab.
- *	returns bool success.
- */
-static inline int ip_vs_conn_unhash(struct ip_vs_conn *cp)
-{
-	unsigned hash;
-	int ret;
-
-	/* unhash it and decrease its reference counter */
-	hash = ip_vs_conn_hashkey(cp->protocol, cp->caddr, cp->cport);
-
-	ct_write_lock(hash);
-
-	if (cp->flags & IP_VS_CONN_F_HASHED) {
-		list_del(&cp->c_list);
-		cp->flags &= ~IP_VS_CONN_F_HASHED;
-		atomic_dec(&cp->refcnt);
-		ret = 1;
-	} else
-		ret = 0;
-
-	ct_write_unlock(hash);
-
-	return ret;
-}
-
-
-/*
- *  Gets ip_vs_conn associated with supplied parameters in the ip_vs_conn_tab.
- *  Called for pkts coming from OUTside-to-INside.
- *	s_addr, s_port: pkt source address (foreign host)
- *	d_addr, d_port: pkt dest address (load balancer)
- */
-static inline struct ip_vs_conn *__ip_vs_conn_in_get
-(int protocol, __be32 s_addr, __be16 s_port, __be32 d_addr, __be16 d_port)
-{
-	unsigned hash;
-	struct ip_vs_conn *cp;
-
-	hash = ip_vs_conn_hashkey(protocol, s_addr, s_port);
-
-	ct_read_lock(hash);
-
-	list_for_each_entry(cp, &ip_vs_conn_tab[hash], c_list) {
-		if (s_addr==cp->caddr && s_port==cp->cport &&
-		    d_port==cp->vport && d_addr==cp->vaddr &&
-		    ((!s_port) ^ (!(cp->flags & IP_VS_CONN_F_NO_CPORT))) &&
-		    protocol==cp->protocol) {
-			/* HIT */
-			atomic_inc(&cp->refcnt);
-			ct_read_unlock(hash);
-			return cp;
-		}
-	}
-
-	ct_read_unlock(hash);
-
-	return NULL;
-}
-
-struct ip_vs_conn *ip_vs_conn_in_get
-(int protocol, __be32 s_addr, __be16 s_port, __be32 d_addr, __be16 d_port)
-{
-	struct ip_vs_conn *cp;
-
-	cp = __ip_vs_conn_in_get(protocol, s_addr, s_port, d_addr, d_port);
-	if (!cp && atomic_read(&ip_vs_conn_no_cport_cnt))
-		cp = __ip_vs_conn_in_get(protocol, s_addr, 0, d_addr, d_port);
-
-	IP_VS_DBG(9, "lookup/in %s %u.%u.%u.%u:%d->%u.%u.%u.%u:%d %s\n",
-		  ip_vs_proto_name(protocol),
-		  NIPQUAD(s_addr), ntohs(s_port),
-		  NIPQUAD(d_addr), ntohs(d_port),
-		  cp?"hit":"not hit");
-
-	return cp;
-}
-
-/* Get reference to connection template */
-struct ip_vs_conn *ip_vs_ct_in_get
-(int protocol, __be32 s_addr, __be16 s_port, __be32 d_addr, __be16 d_port)
-{
-	unsigned hash;
-	struct ip_vs_conn *cp;
-
-	hash = ip_vs_conn_hashkey(protocol, s_addr, s_port);
-
-	ct_read_lock(hash);
-
-	list_for_each_entry(cp, &ip_vs_conn_tab[hash], c_list) {
-		if (s_addr==cp->caddr && s_port==cp->cport &&
-		    d_port==cp->vport && d_addr==cp->vaddr &&
-		    cp->flags & IP_VS_CONN_F_TEMPLATE &&
-		    protocol==cp->protocol) {
-			/* HIT */
-			atomic_inc(&cp->refcnt);
-			goto out;
-		}
-	}
-	cp = NULL;
-
-  out:
-	ct_read_unlock(hash);
-
-	IP_VS_DBG(9, "template lookup/in %s %u.%u.%u.%u:%d->%u.%u.%u.%u:%d %s\n",
-		  ip_vs_proto_name(protocol),
-		  NIPQUAD(s_addr), ntohs(s_port),
-		  NIPQUAD(d_addr), ntohs(d_port),
-		  cp?"hit":"not hit");
-
-	return cp;
-}
-
-/*
- *  Gets ip_vs_conn associated with supplied parameters in the ip_vs_conn_tab.
- *  Called for pkts coming from inside-to-OUTside.
- *	s_addr, s_port: pkt source address (inside host)
- *	d_addr, d_port: pkt dest address (foreign host)
- */
-struct ip_vs_conn *ip_vs_conn_out_get
-(int protocol, __be32 s_addr, __be16 s_port, __be32 d_addr, __be16 d_port)
-{
-	unsigned hash;
-	struct ip_vs_conn *cp, *ret=NULL;
-
-	/*
-	 *	Check for "full" addressed entries
-	 */
-	hash = ip_vs_conn_hashkey(protocol, d_addr, d_port);
-
-	ct_read_lock(hash);
-
-	list_for_each_entry(cp, &ip_vs_conn_tab[hash], c_list) {
-		if (d_addr == cp->caddr && d_port == cp->cport &&
-		    s_port == cp->dport && s_addr == cp->daddr &&
-		    protocol == cp->protocol) {
-			/* HIT */
-			atomic_inc(&cp->refcnt);
-			ret = cp;
-			break;
-		}
-	}
-
-	ct_read_unlock(hash);
-
-	IP_VS_DBG(9, "lookup/out %s %u.%u.%u.%u:%d->%u.%u.%u.%u:%d %s\n",
-		  ip_vs_proto_name(protocol),
-		  NIPQUAD(s_addr), ntohs(s_port),
-		  NIPQUAD(d_addr), ntohs(d_port),
-		  ret?"hit":"not hit");
-
-	return ret;
-}
-
-
-/*
- *      Put back the conn and restart its timer with its timeout
- */
-void ip_vs_conn_put(struct ip_vs_conn *cp)
-{
-	/* reset it expire in its timeout */
-	mod_timer(&cp->timer, jiffies+cp->timeout);
-
-	__ip_vs_conn_put(cp);
-}
-
-
-/*
- *	Fill a no_client_port connection with a client port number
- */
-void ip_vs_conn_fill_cport(struct ip_vs_conn *cp, __be16 cport)
-{
-	if (ip_vs_conn_unhash(cp)) {
-		spin_lock(&cp->lock);
-		if (cp->flags & IP_VS_CONN_F_NO_CPORT) {
-			atomic_dec(&ip_vs_conn_no_cport_cnt);
-			cp->flags &= ~IP_VS_CONN_F_NO_CPORT;
-			cp->cport = cport;
-		}
-		spin_unlock(&cp->lock);
-
-		/* hash on new dport */
-		ip_vs_conn_hash(cp);
-	}
-}
-
-
-/*
- *	Bind a connection entry with the corresponding packet_xmit.
- *	Called by ip_vs_conn_new.
- */
-static inline void ip_vs_bind_xmit(struct ip_vs_conn *cp)
-{
-	switch (IP_VS_FWD_METHOD(cp)) {
-	case IP_VS_CONN_F_MASQ:
-		cp->packet_xmit = ip_vs_nat_xmit;
-		break;
-
-	case IP_VS_CONN_F_TUNNEL:
-		cp->packet_xmit = ip_vs_tunnel_xmit;
-		break;
-
-	case IP_VS_CONN_F_DROUTE:
-		cp->packet_xmit = ip_vs_dr_xmit;
-		break;
-
-	case IP_VS_CONN_F_LOCALNODE:
-		cp->packet_xmit = ip_vs_null_xmit;
-		break;
-
-	case IP_VS_CONN_F_BYPASS:
-		cp->packet_xmit = ip_vs_bypass_xmit;
-		break;
-	}
-}
-
-
-static inline int ip_vs_dest_totalconns(struct ip_vs_dest *dest)
-{
-	return atomic_read(&dest->activeconns)
-		+ atomic_read(&dest->inactconns);
-}
-
-/*
- *	Bind a connection entry with a virtual service destination
- *	Called just after a new connection entry is created.
- */
-static inline void
-ip_vs_bind_dest(struct ip_vs_conn *cp, struct ip_vs_dest *dest)
-{
-	/* if dest is NULL, then return directly */
-	if (!dest)
-		return;
-
-	/* Increase the refcnt counter of the dest */
-	atomic_inc(&dest->refcnt);
-
-	/* Bind with the destination and its corresponding transmitter */
-	if ((cp->flags & IP_VS_CONN_F_SYNC) &&
-	    (!(cp->flags & IP_VS_CONN_F_TEMPLATE)))
-		/* if the connection is not template and is created
-		 * by sync, preserve the activity flag.
-		 */
-		cp->flags |= atomic_read(&dest->conn_flags) &
-			     (~IP_VS_CONN_F_INACTIVE);
-	else
-		cp->flags |= atomic_read(&dest->conn_flags);
-	cp->dest = dest;
-
-	IP_VS_DBG(7, "Bind-dest %s c:%u.%u.%u.%u:%d v:%u.%u.%u.%u:%d "
-		  "d:%u.%u.%u.%u:%d fwd:%c s:%u conn->flags:%X conn->refcnt:%d "
-		  "dest->refcnt:%d\n",
-		  ip_vs_proto_name(cp->protocol),
-		  NIPQUAD(cp->caddr), ntohs(cp->cport),
-		  NIPQUAD(cp->vaddr), ntohs(cp->vport),
-		  NIPQUAD(cp->daddr), ntohs(cp->dport),
-		  ip_vs_fwd_tag(cp), cp->state,
-		  cp->flags, atomic_read(&cp->refcnt),
-		  atomic_read(&dest->refcnt));
-
-	/* Update the connection counters */
-	if (!(cp->flags & IP_VS_CONN_F_TEMPLATE)) {
-		/* It is a normal connection, so increase the inactive
-		   connection counter because it is in TCP SYNRECV
-		   state (inactive) or other protocol inacive state */
-		if ((cp->flags & IP_VS_CONN_F_SYNC) &&
-		    (!(cp->flags & IP_VS_CONN_F_INACTIVE)))
-			atomic_inc(&dest->activeconns);
-		else
-			atomic_inc(&dest->inactconns);
-	} else {
-		/* It is a persistent connection/template, so increase
-		   the peristent connection counter */
-		atomic_inc(&dest->persistconns);
-	}
-
-	if (dest->u_threshold != 0 &&
-	    ip_vs_dest_totalconns(dest) >= dest->u_threshold)
-		dest->flags |= IP_VS_DEST_F_OVERLOAD;
-}
-
-
-/*
- * Check if there is a destination for the connection, if so
- * bind the connection to the destination.
- */
-struct ip_vs_dest *ip_vs_try_bind_dest(struct ip_vs_conn *cp)
-{
-	struct ip_vs_dest *dest;
-
-	if ((cp) && (!cp->dest)) {
-		dest = ip_vs_find_dest(cp->daddr, cp->dport,
-				       cp->vaddr, cp->vport, cp->protocol);
-		ip_vs_bind_dest(cp, dest);
-		return dest;
-	} else
-		return NULL;
-}
-
-
-/*
- *	Unbind a connection entry with its VS destination
- *	Called by the ip_vs_conn_expire function.
- */
-static inline void ip_vs_unbind_dest(struct ip_vs_conn *cp)
-{
-	struct ip_vs_dest *dest = cp->dest;
-
-	if (!dest)
-		return;
-
-	IP_VS_DBG(7, "Unbind-dest %s c:%u.%u.%u.%u:%d v:%u.%u.%u.%u:%d "
-		  "d:%u.%u.%u.%u:%d fwd:%c s:%u conn->flags:%X conn->refcnt:%d "
-		  "dest->refcnt:%d\n",
-		  ip_vs_proto_name(cp->protocol),
-		  NIPQUAD(cp->caddr), ntohs(cp->cport),
-		  NIPQUAD(cp->vaddr), ntohs(cp->vport),
-		  NIPQUAD(cp->daddr), ntohs(cp->dport),
-		  ip_vs_fwd_tag(cp), cp->state,
-		  cp->flags, atomic_read(&cp->refcnt),
-		  atomic_read(&dest->refcnt));
-
-	/* Update the connection counters */
-	if (!(cp->flags & IP_VS_CONN_F_TEMPLATE)) {
-		/* It is a normal connection, so decrease the inactconns
-		   or activeconns counter */
-		if (cp->flags & IP_VS_CONN_F_INACTIVE) {
-			atomic_dec(&dest->inactconns);
-		} else {
-			atomic_dec(&dest->activeconns);
-		}
-	} else {
-		/* It is a persistent connection/template, so decrease
-		   the peristent connection counter */
-		atomic_dec(&dest->persistconns);
-	}
-
-	if (dest->l_threshold != 0) {
-		if (ip_vs_dest_totalconns(dest) < dest->l_threshold)
-			dest->flags &= ~IP_VS_DEST_F_OVERLOAD;
-	} else if (dest->u_threshold != 0) {
-		if (ip_vs_dest_totalconns(dest) * 4 < dest->u_threshold * 3)
-			dest->flags &= ~IP_VS_DEST_F_OVERLOAD;
-	} else {
-		if (dest->flags & IP_VS_DEST_F_OVERLOAD)
-			dest->flags &= ~IP_VS_DEST_F_OVERLOAD;
-	}
-
-	/*
-	 * Simply decrease the refcnt of the dest, because the
-	 * dest will be either in service's destination list
-	 * or in the trash.
-	 */
-	atomic_dec(&dest->refcnt);
-}
-
-
-/*
- *	Checking if the destination of a connection template is available.
- *	If available, return 1, otherwise invalidate this connection
- *	template and return 0.
- */
-int ip_vs_check_template(struct ip_vs_conn *ct)
-{
-	struct ip_vs_dest *dest = ct->dest;
-
-	/*
-	 * Checking the dest server status.
-	 */
-	if ((dest == NULL) ||
-	    !(dest->flags & IP_VS_DEST_F_AVAILABLE) ||
-	    (sysctl_ip_vs_expire_quiescent_template &&
-	     (atomic_read(&dest->weight) == 0))) {
-		IP_VS_DBG(9, "check_template: dest not available for "
-			  "protocol %s s:%u.%u.%u.%u:%d v:%u.%u.%u.%u:%d "
-			  "-> d:%u.%u.%u.%u:%d\n",
-			  ip_vs_proto_name(ct->protocol),
-			  NIPQUAD(ct->caddr), ntohs(ct->cport),
-			  NIPQUAD(ct->vaddr), ntohs(ct->vport),
-			  NIPQUAD(ct->daddr), ntohs(ct->dport));
-
-		/*
-		 * Invalidate the connection template
-		 */
-		if (ct->vport != htons(0xffff)) {
-			if (ip_vs_conn_unhash(ct)) {
-				ct->dport = htons(0xffff);
-				ct->vport = htons(0xffff);
-				ct->cport = 0;
-				ip_vs_conn_hash(ct);
-			}
-		}
-
-		/*
-		 * Simply decrease the refcnt of the template,
-		 * don't restart its timer.
-		 */
-		atomic_dec(&ct->refcnt);
-		return 0;
-	}
-	return 1;
-}
-
-static void ip_vs_conn_expire(unsigned long data)
-{
-	struct ip_vs_conn *cp = (struct ip_vs_conn *)data;
-
-	cp->timeout = 60*HZ;
-
-	/*
-	 *	hey, I'm using it
-	 */
-	atomic_inc(&cp->refcnt);
-
-	/*
-	 *	do I control anybody?
-	 */
-	if (atomic_read(&cp->n_control))
-		goto expire_later;
-
-	/*
-	 *	unhash it if it is hashed in the conn table
-	 */
-	if (!ip_vs_conn_unhash(cp))
-		goto expire_later;
-
-	/*
-	 *	refcnt==1 implies I'm the only one referrer
-	 */
-	if (likely(atomic_read(&cp->refcnt) == 1)) {
-		/* delete the timer if it is activated by other users */
-		if (timer_pending(&cp->timer))
-			del_timer(&cp->timer);
-
-		/* does anybody control me? */
-		if (cp->control)
-			ip_vs_control_del(cp);
-
-		if (unlikely(cp->app != NULL))
-			ip_vs_unbind_app(cp);
-		ip_vs_unbind_dest(cp);
-		if (cp->flags & IP_VS_CONN_F_NO_CPORT)
-			atomic_dec(&ip_vs_conn_no_cport_cnt);
-		atomic_dec(&ip_vs_conn_count);
-
-		kmem_cache_free(ip_vs_conn_cachep, cp);
-		return;
-	}
-
-	/* hash it back to the table */
-	ip_vs_conn_hash(cp);
-
-  expire_later:
-	IP_VS_DBG(7, "delayed: conn->refcnt-1=%d conn->n_control=%d\n",
-		  atomic_read(&cp->refcnt)-1,
-		  atomic_read(&cp->n_control));
-
-	ip_vs_conn_put(cp);
-}
-
-
-void ip_vs_conn_expire_now(struct ip_vs_conn *cp)
-{
-	if (del_timer(&cp->timer))
-		mod_timer(&cp->timer, jiffies);
-}
-
-
-/*
- *	Create a new connection entry and hash it into the ip_vs_conn_tab
- */
-struct ip_vs_conn *
-ip_vs_conn_new(int proto, __be32 caddr, __be16 cport, __be32 vaddr, __be16 vport,
-	       __be32 daddr, __be16 dport, unsigned flags,
-	       struct ip_vs_dest *dest)
-{
-	struct ip_vs_conn *cp;
-	struct ip_vs_protocol *pp = ip_vs_proto_get(proto);
-
-	cp = kmem_cache_zalloc(ip_vs_conn_cachep, GFP_ATOMIC);
-	if (cp == NULL) {
-		IP_VS_ERR_RL("ip_vs_conn_new: no memory available.\n");
-		return NULL;
-	}
-
-	INIT_LIST_HEAD(&cp->c_list);
-	setup_timer(&cp->timer, ip_vs_conn_expire, (unsigned long)cp);
-	cp->protocol	   = proto;
-	cp->caddr	   = caddr;
-	cp->cport	   = cport;
-	cp->vaddr	   = vaddr;
-	cp->vport	   = vport;
-	cp->daddr          = daddr;
-	cp->dport          = dport;
-	cp->flags	   = flags;
-	spin_lock_init(&cp->lock);
-
-	/*
-	 * Set the entry is referenced by the current thread before hashing
-	 * it in the table, so that other thread run ip_vs_random_dropentry
-	 * but cannot drop this entry.
-	 */
-	atomic_set(&cp->refcnt, 1);
-
-	atomic_set(&cp->n_control, 0);
-	atomic_set(&cp->in_pkts, 0);
-
-	atomic_inc(&ip_vs_conn_count);
-	if (flags & IP_VS_CONN_F_NO_CPORT)
-		atomic_inc(&ip_vs_conn_no_cport_cnt);
-
-	/* Bind the connection with a destination server */
-	ip_vs_bind_dest(cp, dest);
-
-	/* Set its state and timeout */
-	cp->state = 0;
-	cp->timeout = 3*HZ;
-
-	/* Bind its packet transmitter */
-	ip_vs_bind_xmit(cp);
-
-	if (unlikely(pp && atomic_read(&pp->appcnt)))
-		ip_vs_bind_app(cp, pp);
-
-	/* Hash it in the ip_vs_conn_tab finally */
-	ip_vs_conn_hash(cp);
-
-	return cp;
-}
-
-
-/*
- *	/proc/net/ip_vs_conn entries
- */
-#ifdef CONFIG_PROC_FS
-
-static void *ip_vs_conn_array(struct seq_file *seq, loff_t pos)
-{
-	int idx;
-	struct ip_vs_conn *cp;
-
-	for(idx = 0; idx < IP_VS_CONN_TAB_SIZE; idx++) {
-		ct_read_lock_bh(idx);
-		list_for_each_entry(cp, &ip_vs_conn_tab[idx], c_list) {
-			if (pos-- == 0) {
-				seq->private = &ip_vs_conn_tab[idx];
-				return cp;
-			}
-		}
-		ct_read_unlock_bh(idx);
-	}
-
-	return NULL;
-}
-
-static void *ip_vs_conn_seq_start(struct seq_file *seq, loff_t *pos)
-{
-	seq->private = NULL;
-	return *pos ? ip_vs_conn_array(seq, *pos - 1) :SEQ_START_TOKEN;
-}
-
-static void *ip_vs_conn_seq_next(struct seq_file *seq, void *v, loff_t *pos)
-{
-	struct ip_vs_conn *cp = v;
-	struct list_head *e, *l = seq->private;
-	int idx;
-
-	++*pos;
-	if (v == SEQ_START_TOKEN)
-		return ip_vs_conn_array(seq, 0);
-
-	/* more on same hash chain? */
-	if ((e = cp->c_list.next) != l)
-		return list_entry(e, struct ip_vs_conn, c_list);
-
-	idx = l - ip_vs_conn_tab;
-	ct_read_unlock_bh(idx);
-
-	while (++idx < IP_VS_CONN_TAB_SIZE) {
-		ct_read_lock_bh(idx);
-		list_for_each_entry(cp, &ip_vs_conn_tab[idx], c_list) {
-			seq->private = &ip_vs_conn_tab[idx];
-			return cp;
-		}
-		ct_read_unlock_bh(idx);
-	}
-	seq->private = NULL;
-	return NULL;
-}
-
-static void ip_vs_conn_seq_stop(struct seq_file *seq, void *v)
-{
-	struct list_head *l = seq->private;
-
-	if (l)
-		ct_read_unlock_bh(l - ip_vs_conn_tab);
-}
-
-static int ip_vs_conn_seq_show(struct seq_file *seq, void *v)
-{
-
-	if (v == SEQ_START_TOKEN)
-		seq_puts(seq,
-   "Pro FromIP   FPrt ToIP     TPrt DestIP   DPrt State       Expires\n");
-	else {
-		const struct ip_vs_conn *cp = v;
-
-		seq_printf(seq,
-			"%-3s %08X %04X %08X %04X %08X %04X %-11s %7lu\n",
-				ip_vs_proto_name(cp->protocol),
-				ntohl(cp->caddr), ntohs(cp->cport),
-				ntohl(cp->vaddr), ntohs(cp->vport),
-				ntohl(cp->daddr), ntohs(cp->dport),
-				ip_vs_state_name(cp->protocol, cp->state),
-				(cp->timer.expires-jiffies)/HZ);
-	}
-	return 0;
-}
-
-static const struct seq_operations ip_vs_conn_seq_ops = {
-	.start = ip_vs_conn_seq_start,
-	.next  = ip_vs_conn_seq_next,
-	.stop  = ip_vs_conn_seq_stop,
-	.show  = ip_vs_conn_seq_show,
-};
-
-static int ip_vs_conn_open(struct inode *inode, struct file *file)
-{
-	return seq_open(file, &ip_vs_conn_seq_ops);
-}
-
-static const struct file_operations ip_vs_conn_fops = {
-	.owner	 = THIS_MODULE,
-	.open    = ip_vs_conn_open,
-	.read    = seq_read,
-	.llseek  = seq_lseek,
-	.release = seq_release,
-};
-
-static const char *ip_vs_origin_name(unsigned flags)
-{
-	if (flags & IP_VS_CONN_F_SYNC)
-		return "SYNC";
-	else
-		return "LOCAL";
-}
-
-static int ip_vs_conn_sync_seq_show(struct seq_file *seq, void *v)
-{
-
-	if (v == SEQ_START_TOKEN)
-		seq_puts(seq,
-   "Pro FromIP   FPrt ToIP     TPrt DestIP   DPrt State       Origin Expires\n");
-	else {
-		const struct ip_vs_conn *cp = v;
-
-		seq_printf(seq,
-			"%-3s %08X %04X %08X %04X %08X %04X %-11s %-6s %7lu\n",
-				ip_vs_proto_name(cp->protocol),
-				ntohl(cp->caddr), ntohs(cp->cport),
-				ntohl(cp->vaddr), ntohs(cp->vport),
-				ntohl(cp->daddr), ntohs(cp->dport),
-				ip_vs_state_name(cp->protocol, cp->state),
-				ip_vs_origin_name(cp->flags),
-				(cp->timer.expires-jiffies)/HZ);
-	}
-	return 0;
-}
-
-static const struct seq_operations ip_vs_conn_sync_seq_ops = {
-	.start = ip_vs_conn_seq_start,
-	.next  = ip_vs_conn_seq_next,
-	.stop  = ip_vs_conn_seq_stop,
-	.show  = ip_vs_conn_sync_seq_show,
-};
-
-static int ip_vs_conn_sync_open(struct inode *inode, struct file *file)
-{
-	return seq_open(file, &ip_vs_conn_sync_seq_ops);
-}
-
-static const struct file_operations ip_vs_conn_sync_fops = {
-	.owner	 = THIS_MODULE,
-	.open    = ip_vs_conn_sync_open,
-	.read    = seq_read,
-	.llseek  = seq_lseek,
-	.release = seq_release,
-};
-
-#endif
-
-
-/*
- *      Randomly drop connection entries before running out of memory
- */
-static inline int todrop_entry(struct ip_vs_conn *cp)
-{
-	/*
-	 * The drop rate array needs tuning for real environments.
-	 * Called from timer bh only => no locking
-	 */
-	static const char todrop_rate[9] = {0, 1, 2, 3, 4, 5, 6, 7, 8};
-	static char todrop_counter[9] = {0};
-	int i;
-
-	/* if the conn entry hasn't lasted for 60 seconds, don't drop it.
-	   This will leave enough time for normal connection to get
-	   through. */
-	if (time_before(cp->timeout + jiffies, cp->timer.expires + 60*HZ))
-		return 0;
-
-	/* Don't drop the entry if its number of incoming packets is not
-	   located in [0, 8] */
-	i = atomic_read(&cp->in_pkts);
-	if (i > 8 || i < 0) return 0;
-
-	if (!todrop_rate[i]) return 0;
-	if (--todrop_counter[i] > 0) return 0;
-
-	todrop_counter[i] = todrop_rate[i];
-	return 1;
-}
-
-/* Called from keventd and must protect itself from softirqs */
-void ip_vs_random_dropentry(void)
-{
-	int idx;
-	struct ip_vs_conn *cp;
-
-	/*
-	 * Randomly scan 1/32 of the whole table every second
-	 */
-	for (idx = 0; idx < (IP_VS_CONN_TAB_SIZE>>5); idx++) {
-		unsigned hash = net_random() & IP_VS_CONN_TAB_MASK;
-
-		/*
-		 *  Lock is actually needed in this loop.
-		 */
-		ct_write_lock_bh(hash);
-
-		list_for_each_entry(cp, &ip_vs_conn_tab[hash], c_list) {
-			if (cp->flags & IP_VS_CONN_F_TEMPLATE)
-				/* connection template */
-				continue;
-
-			if (cp->protocol == IPPROTO_TCP) {
-				switch(cp->state) {
-				case IP_VS_TCP_S_SYN_RECV:
-				case IP_VS_TCP_S_SYNACK:
-					break;
-
-				case IP_VS_TCP_S_ESTABLISHED:
-					if (todrop_entry(cp))
-						break;
-					continue;
-
-				default:
-					continue;
-				}
-			} else {
-				if (!todrop_entry(cp))
-					continue;
-			}
-
-			IP_VS_DBG(4, "del connection\n");
-			ip_vs_conn_expire_now(cp);
-			if (cp->control) {
-				IP_VS_DBG(4, "del conn template\n");
-				ip_vs_conn_expire_now(cp->control);
-			}
-		}
-		ct_write_unlock_bh(hash);
-	}
-}
-
-
-/*
- *      Flush all the connection entries in the ip_vs_conn_tab
- */
-static void ip_vs_conn_flush(void)
-{
-	int idx;
-	struct ip_vs_conn *cp;
-
-  flush_again:
-	for (idx=0; idx<IP_VS_CONN_TAB_SIZE; idx++) {
-		/*
-		 *  Lock is actually needed in this loop.
-		 */
-		ct_write_lock_bh(idx);
-
-		list_for_each_entry(cp, &ip_vs_conn_tab[idx], c_list) {
-
-			IP_VS_DBG(4, "del connection\n");
-			ip_vs_conn_expire_now(cp);
-			if (cp->control) {
-				IP_VS_DBG(4, "del conn template\n");
-				ip_vs_conn_expire_now(cp->control);
-			}
-		}
-		ct_write_unlock_bh(idx);
-	}
-
-	/* the counter may be not NULL, because maybe some conn entries
-	   are run by slow timer handler or unhashed but still referred */
-	if (atomic_read(&ip_vs_conn_count) != 0) {
-		schedule();
-		goto flush_again;
-	}
-}
-
-
-int __init ip_vs_conn_init(void)
-{
-	int idx;
-
-	/*
-	 * Allocate the connection hash table and initialize its list heads
-	 */
-	ip_vs_conn_tab = vmalloc(IP_VS_CONN_TAB_SIZE*sizeof(struct list_head));
-	if (!ip_vs_conn_tab)
-		return -ENOMEM;
-
-	/* Allocate ip_vs_conn slab cache */
-	ip_vs_conn_cachep = kmem_cache_create("ip_vs_conn",
-					      sizeof(struct ip_vs_conn), 0,
-					      SLAB_HWCACHE_ALIGN, NULL);
-	if (!ip_vs_conn_cachep) {
-		vfree(ip_vs_conn_tab);
-		return -ENOMEM;
-	}
-
-	IP_VS_INFO("Connection hash table configured "
-		   "(size=%d, memory=%ldKbytes)\n",
-		   IP_VS_CONN_TAB_SIZE,
-		   (long)(IP_VS_CONN_TAB_SIZE*sizeof(struct list_head))/1024);
-	IP_VS_DBG(0, "Each connection entry needs %Zd bytes at least\n",
-		  sizeof(struct ip_vs_conn));
-
-	for (idx = 0; idx < IP_VS_CONN_TAB_SIZE; idx++) {
-		INIT_LIST_HEAD(&ip_vs_conn_tab[idx]);
-	}
-
-	for (idx = 0; idx < CT_LOCKARRAY_SIZE; idx++)  {
-		rwlock_init(&__ip_vs_conntbl_lock_array[idx].l);
-	}
-
-	proc_net_fops_create(&init_net, "ip_vs_conn", 0, &ip_vs_conn_fops);
-	proc_net_fops_create(&init_net, "ip_vs_conn_sync", 0, &ip_vs_conn_sync_fops);
-
-	/* calculate the random value for connection hash */
-	get_random_bytes(&ip_vs_conn_rnd, sizeof(ip_vs_conn_rnd));
-
-	return 0;
-}
-
-
-void ip_vs_conn_cleanup(void)
-{
-	/* flush all the connection entries first */
-	ip_vs_conn_flush();
-
-	/* Release the empty cache */
-	kmem_cache_destroy(ip_vs_conn_cachep);
-	proc_net_remove(&init_net, "ip_vs_conn");
-	proc_net_remove(&init_net, "ip_vs_conn_sync");
-	vfree(ip_vs_conn_tab);
-}
diff --git a/net/ipv4/ipvs/ip_vs_core.c b/net/ipv4/ipvs/ip_vs_core.c
deleted file mode 100644
index a7879eafc..0000000
--- a/net/ipv4/ipvs/ip_vs_core.c
+++ /dev/null
@@ -1,1125 +0,0 @@
-/*
- * IPVS         An implementation of the IP virtual server support for the
- *              LINUX operating system.  IPVS is now implemented as a module
- *              over the Netfilter framework. IPVS can be used to build a
- *              high-performance and highly available server based on a
- *              cluster of servers.
- *
- * Authors:     Wensong Zhang <wensong@linuxvirtualserver.org>
- *              Peter Kese <peter.kese@ijs.si>
- *              Julian Anastasov <ja@ssi.bg>
- *
- *              This program is free software; you can redistribute it and/or
- *              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.
- *
- * The IPVS code for kernel 2.2 was done by Wensong Zhang and Peter Kese,
- * with changes/fixes from Julian Anastasov, Lars Marowsky-Bree, Horms
- * and others.
- *
- * Changes:
- *	Paul `Rusty' Russell		properly handle non-linear skbs
- *	Harald Welte			don't use nfcache
- *
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/ip.h>
-#include <linux/tcp.h>
-#include <linux/icmp.h>
-
-#include <net/ip.h>
-#include <net/tcp.h>
-#include <net/udp.h>
-#include <net/icmp.h>                   /* for icmp_send */
-#include <net/route.h>
-
-#include <linux/netfilter.h>
-#include <linux/netfilter_ipv4.h>
-
-#include <net/ip_vs.h>
-
-
-EXPORT_SYMBOL(register_ip_vs_scheduler);
-EXPORT_SYMBOL(unregister_ip_vs_scheduler);
-EXPORT_SYMBOL(ip_vs_skb_replace);
-EXPORT_SYMBOL(ip_vs_proto_name);
-EXPORT_SYMBOL(ip_vs_conn_new);
-EXPORT_SYMBOL(ip_vs_conn_in_get);
-EXPORT_SYMBOL(ip_vs_conn_out_get);
-#ifdef CONFIG_IP_VS_PROTO_TCP
-EXPORT_SYMBOL(ip_vs_tcp_conn_listen);
-#endif
-EXPORT_SYMBOL(ip_vs_conn_put);
-#ifdef CONFIG_IP_VS_DEBUG
-EXPORT_SYMBOL(ip_vs_get_debug_level);
-#endif
-
-
-/* ID used in ICMP lookups */
-#define icmp_id(icmph)          (((icmph)->un).echo.id)
-
-const char *ip_vs_proto_name(unsigned proto)
-{
-	static char buf[20];
-
-	switch (proto) {
-	case IPPROTO_IP:
-		return "IP";
-	case IPPROTO_UDP:
-		return "UDP";
-	case IPPROTO_TCP:
-		return "TCP";
-	case IPPROTO_ICMP:
-		return "ICMP";
-	default:
-		sprintf(buf, "IP_%d", proto);
-		return buf;
-	}
-}
-
-void ip_vs_init_hash_table(struct list_head *table, int rows)
-{
-	while (--rows >= 0)
-		INIT_LIST_HEAD(&table[rows]);
-}
-
-static inline void
-ip_vs_in_stats(struct ip_vs_conn *cp, struct sk_buff *skb)
-{
-	struct ip_vs_dest *dest = cp->dest;
-	if (dest && (dest->flags & IP_VS_DEST_F_AVAILABLE)) {
-		spin_lock(&dest->stats.lock);
-		dest->stats.inpkts++;
-		dest->stats.inbytes += skb->len;
-		spin_unlock(&dest->stats.lock);
-
-		spin_lock(&dest->svc->stats.lock);
-		dest->svc->stats.inpkts++;
-		dest->svc->stats.inbytes += skb->len;
-		spin_unlock(&dest->svc->stats.lock);
-
-		spin_lock(&ip_vs_stats.lock);
-		ip_vs_stats.inpkts++;
-		ip_vs_stats.inbytes += skb->len;
-		spin_unlock(&ip_vs_stats.lock);
-	}
-}
-
-
-static inline void
-ip_vs_out_stats(struct ip_vs_conn *cp, struct sk_buff *skb)
-{
-	struct ip_vs_dest *dest = cp->dest;
-	if (dest && (dest->flags & IP_VS_DEST_F_AVAILABLE)) {
-		spin_lock(&dest->stats.lock);
-		dest->stats.outpkts++;
-		dest->stats.outbytes += skb->len;
-		spin_unlock(&dest->stats.lock);
-
-		spin_lock(&dest->svc->stats.lock);
-		dest->svc->stats.outpkts++;
-		dest->svc->stats.outbytes += skb->len;
-		spin_unlock(&dest->svc->stats.lock);
-
-		spin_lock(&ip_vs_stats.lock);
-		ip_vs_stats.outpkts++;
-		ip_vs_stats.outbytes += skb->len;
-		spin_unlock(&ip_vs_stats.lock);
-	}
-}
-
-
-static inline void
-ip_vs_conn_stats(struct ip_vs_conn *cp, struct ip_vs_service *svc)
-{
-	spin_lock(&cp->dest->stats.lock);
-	cp->dest->stats.conns++;
-	spin_unlock(&cp->dest->stats.lock);
-
-	spin_lock(&svc->stats.lock);
-	svc->stats.conns++;
-	spin_unlock(&svc->stats.lock);
-
-	spin_lock(&ip_vs_stats.lock);
-	ip_vs_stats.conns++;
-	spin_unlock(&ip_vs_stats.lock);
-}
-
-
-static inline int
-ip_vs_set_state(struct ip_vs_conn *cp, int direction,
-		const struct sk_buff *skb,
-		struct ip_vs_protocol *pp)
-{
-	if (unlikely(!pp->state_transition))
-		return 0;
-	return pp->state_transition(cp, direction, skb, pp);
-}
-
-
-/*
- *  IPVS persistent scheduling function
- *  It creates a connection entry according to its template if exists,
- *  or selects a server and creates a connection entry plus a template.
- *  Locking: we are svc user (svc->refcnt), so we hold all dests too
- *  Protocols supported: TCP, UDP
- */
-static struct ip_vs_conn *
-ip_vs_sched_persist(struct ip_vs_service *svc,
-		    const struct sk_buff *skb,
-		    __be16 ports[2])
-{
-	struct ip_vs_conn *cp = NULL;
-	struct iphdr *iph = ip_hdr(skb);
-	struct ip_vs_dest *dest;
-	struct ip_vs_conn *ct;
-	__be16  dport;	 /* destination port to forward */
-	__be32  snet;	 /* source network of the client, after masking */
-
-	/* Mask saddr with the netmask to adjust template granularity */
-	snet = iph->saddr & svc->netmask;
-
-	IP_VS_DBG(6, "p-schedule: src %u.%u.%u.%u:%u dest %u.%u.%u.%u:%u "
-		  "mnet %u.%u.%u.%u\n",
-		  NIPQUAD(iph->saddr), ntohs(ports[0]),
-		  NIPQUAD(iph->daddr), ntohs(ports[1]),
-		  NIPQUAD(snet));
-
-	/*
-	 * As far as we know, FTP is a very complicated network protocol, and
-	 * it uses control connection and data connections. For active FTP,
-	 * FTP server initialize data connection to the client, its source port
-	 * is often 20. For passive FTP, FTP server tells the clients the port
-	 * that it passively listens to,  and the client issues the data
-	 * connection. In the tunneling or direct routing mode, the load
-	 * balancer is on the client-to-server half of connection, the port
-	 * number is unknown to the load balancer. So, a conn template like
-	 * <caddr, 0, vaddr, 0, daddr, 0> is created for persistent FTP
-	 * service, and a template like <caddr, 0, vaddr, vport, daddr, dport>
-	 * is created for other persistent services.
-	 */
-	if (ports[1] == svc->port) {
-		/* Check if a template already exists */
-		if (svc->port != FTPPORT)
-			ct = ip_vs_ct_in_get(iph->protocol, snet, 0,
-					       iph->daddr, ports[1]);
-		else
-			ct = ip_vs_ct_in_get(iph->protocol, snet, 0,
-					       iph->daddr, 0);
-
-		if (!ct || !ip_vs_check_template(ct)) {
-			/*
-			 * No template found or the dest of the connection
-			 * template is not available.
-			 */
-			dest = svc->scheduler->schedule(svc, skb);
-			if (dest == NULL) {
-				IP_VS_DBG(1, "p-schedule: no dest found.\n");
-				return NULL;
-			}
-
-			/*
-			 * Create a template like <protocol,caddr,0,
-			 * vaddr,vport,daddr,dport> for non-ftp service,
-			 * and <protocol,caddr,0,vaddr,0,daddr,0>
-			 * for ftp service.
-			 */
-			if (svc->port != FTPPORT)
-				ct = ip_vs_conn_new(iph->protocol,
-						    snet, 0,
-						    iph->daddr,
-						    ports[1],
-						    dest->addr, dest->port,
-						    IP_VS_CONN_F_TEMPLATE,
-						    dest);
-			else
-				ct = ip_vs_conn_new(iph->protocol,
-						    snet, 0,
-						    iph->daddr, 0,
-						    dest->addr, 0,
-						    IP_VS_CONN_F_TEMPLATE,
-						    dest);
-			if (ct == NULL)
-				return NULL;
-
-			ct->timeout = svc->timeout;
-		} else {
-			/* set destination with the found template */
-			dest = ct->dest;
-		}
-		dport = dest->port;
-	} else {
-		/*
-		 * Note: persistent fwmark-based services and persistent
-		 * port zero service are handled here.
-		 * fwmark template: <IPPROTO_IP,caddr,0,fwmark,0,daddr,0>
-		 * port zero template: <protocol,caddr,0,vaddr,0,daddr,0>
-		 */
-		if (svc->fwmark)
-			ct = ip_vs_ct_in_get(IPPROTO_IP, snet, 0,
-					       htonl(svc->fwmark), 0);
-		else
-			ct = ip_vs_ct_in_get(iph->protocol, snet, 0,
-					       iph->daddr, 0);
-
-		if (!ct || !ip_vs_check_template(ct)) {
-			/*
-			 * If it is not persistent port zero, return NULL,
-			 * otherwise create a connection template.
-			 */
-			if (svc->port)
-				return NULL;
-
-			dest = svc->scheduler->schedule(svc, skb);
-			if (dest == NULL) {
-				IP_VS_DBG(1, "p-schedule: no dest found.\n");
-				return NULL;
-			}
-
-			/*
-			 * Create a template according to the service
-			 */
-			if (svc->fwmark)
-				ct = ip_vs_conn_new(IPPROTO_IP,
-						    snet, 0,
-						    htonl(svc->fwmark), 0,
-						    dest->addr, 0,
-						    IP_VS_CONN_F_TEMPLATE,
-						    dest);
-			else
-				ct = ip_vs_conn_new(iph->protocol,
-						    snet, 0,
-						    iph->daddr, 0,
-						    dest->addr, 0,
-						    IP_VS_CONN_F_TEMPLATE,
-						    dest);
-			if (ct == NULL)
-				return NULL;
-
-			ct->timeout = svc->timeout;
-		} else {
-			/* set destination with the found template */
-			dest = ct->dest;
-		}
-		dport = ports[1];
-	}
-
-	/*
-	 *    Create a new connection according to the template
-	 */
-	cp = ip_vs_conn_new(iph->protocol,
-			    iph->saddr, ports[0],
-			    iph->daddr, ports[1],
-			    dest->addr, dport,
-			    0,
-			    dest);
-	if (cp == NULL) {
-		ip_vs_conn_put(ct);
-		return NULL;
-	}
-
-	/*
-	 *    Add its control
-	 */
-	ip_vs_control_add(cp, ct);
-	ip_vs_conn_put(ct);
-
-	ip_vs_conn_stats(cp, svc);
-	return cp;
-}
-
-
-/*
- *  IPVS main scheduling function
- *  It selects a server according to the virtual service, and
- *  creates a connection entry.
- *  Protocols supported: TCP, UDP
- */
-struct ip_vs_conn *
-ip_vs_schedule(struct ip_vs_service *svc, const struct sk_buff *skb)
-{
-	struct ip_vs_conn *cp = NULL;
-	struct iphdr *iph = ip_hdr(skb);
-	struct ip_vs_dest *dest;
-	__be16 _ports[2], *pptr;
-
-	pptr = skb_header_pointer(skb, iph->ihl*4,
-				  sizeof(_ports), _ports);
-	if (pptr == NULL)
-		return NULL;
-
-	/*
-	 *    Persistent service
-	 */
-	if (svc->flags & IP_VS_SVC_F_PERSISTENT)
-		return ip_vs_sched_persist(svc, skb, pptr);
-
-	/*
-	 *    Non-persistent service
-	 */
-	if (!svc->fwmark && pptr[1] != svc->port) {
-		if (!svc->port)
-			IP_VS_ERR("Schedule: port zero only supported "
-				  "in persistent services, "
-				  "check your ipvs configuration\n");
-		return NULL;
-	}
-
-	dest = svc->scheduler->schedule(svc, skb);
-	if (dest == NULL) {
-		IP_VS_DBG(1, "Schedule: no dest found.\n");
-		return NULL;
-	}
-
-	/*
-	 *    Create a connection entry.
-	 */
-	cp = ip_vs_conn_new(iph->protocol,
-			    iph->saddr, pptr[0],
-			    iph->daddr, pptr[1],
-			    dest->addr, dest->port?dest->port:pptr[1],
-			    0,
-			    dest);
-	if (cp == NULL)
-		return NULL;
-
-	IP_VS_DBG(6, "Schedule fwd:%c c:%u.%u.%u.%u:%u v:%u.%u.%u.%u:%u "
-		  "d:%u.%u.%u.%u:%u conn->flags:%X conn->refcnt:%d\n",
-		  ip_vs_fwd_tag(cp),
-		  NIPQUAD(cp->caddr), ntohs(cp->cport),
-		  NIPQUAD(cp->vaddr), ntohs(cp->vport),
-		  NIPQUAD(cp->daddr), ntohs(cp->dport),
-		  cp->flags, atomic_read(&cp->refcnt));
-
-	ip_vs_conn_stats(cp, svc);
-	return cp;
-}
-
-
-/*
- *  Pass or drop the packet.
- *  Called by ip_vs_in, when the virtual service is available but
- *  no destination is available for a new connection.
- */
-int ip_vs_leave(struct ip_vs_service *svc, struct sk_buff *skb,
-		struct ip_vs_protocol *pp)
-{
-	__be16 _ports[2], *pptr;
-	struct iphdr *iph = ip_hdr(skb);
-
-	pptr = skb_header_pointer(skb, iph->ihl*4,
-				  sizeof(_ports), _ports);
-	if (pptr == NULL) {
-		ip_vs_service_put(svc);
-		return NF_DROP;
-	}
-
-	/* if it is fwmark-based service, the cache_bypass sysctl is up
-	   and the destination is RTN_UNICAST (and not local), then create
-	   a cache_bypass connection entry */
-	if (sysctl_ip_vs_cache_bypass && svc->fwmark
-	    && (inet_addr_type(&init_net, iph->daddr) == RTN_UNICAST)) {
-		int ret, cs;
-		struct ip_vs_conn *cp;
-
-		ip_vs_service_put(svc);
-
-		/* create a new connection entry */
-		IP_VS_DBG(6, "ip_vs_leave: create a cache_bypass entry\n");
-		cp = ip_vs_conn_new(iph->protocol,
-				    iph->saddr, pptr[0],
-				    iph->daddr, pptr[1],
-				    0, 0,
-				    IP_VS_CONN_F_BYPASS,
-				    NULL);
-		if (cp == NULL)
-			return NF_DROP;
-
-		/* statistics */
-		ip_vs_in_stats(cp, skb);
-
-		/* set state */
-		cs = ip_vs_set_state(cp, IP_VS_DIR_INPUT, skb, pp);
-
-		/* transmit the first SYN packet */
-		ret = cp->packet_xmit(skb, cp, pp);
-		/* do not touch skb anymore */
-
-		atomic_inc(&cp->in_pkts);
-		ip_vs_conn_put(cp);
-		return ret;
-	}
-
-	/*
-	 * When the virtual ftp service is presented, packets destined
-	 * for other services on the VIP may get here (except services
-	 * listed in the ipvs table), pass the packets, because it is
-	 * not ipvs job to decide to drop the packets.
-	 */
-	if ((svc->port == FTPPORT) && (pptr[1] != FTPPORT)) {
-		ip_vs_service_put(svc);
-		return NF_ACCEPT;
-	}
-
-	ip_vs_service_put(svc);
-
-	/*
-	 * Notify the client that the destination is unreachable, and
-	 * release the socket buffer.
-	 * Since it is in IP layer, the TCP socket is not actually
-	 * created, the TCP RST packet cannot be sent, instead that
-	 * ICMP_PORT_UNREACH is sent here no matter it is TCP/UDP. --WZ
-	 */
-	icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);
-	return NF_DROP;
-}
-
-
-/*
- *      It is hooked before NF_IP_PRI_NAT_SRC at the NF_INET_POST_ROUTING
- *      chain, and is used for VS/NAT.
- *      It detects packets for VS/NAT connections and sends the packets
- *      immediately. This can avoid that iptable_nat mangles the packets
- *      for VS/NAT.
- */
-static unsigned int ip_vs_post_routing(unsigned int hooknum,
-				       struct sk_buff *skb,
-				       const struct net_device *in,
-				       const struct net_device *out,
-				       int (*okfn)(struct sk_buff *))
-{
-	if (!skb->ipvs_property)
-		return NF_ACCEPT;
-	/* The packet was sent from IPVS, exit this chain */
-	return NF_STOP;
-}
-
-__sum16 ip_vs_checksum_complete(struct sk_buff *skb, int offset)
-{
-	return csum_fold(skb_checksum(skb, offset, skb->len - offset, 0));
-}
-
-static inline int ip_vs_gather_frags(struct sk_buff *skb, u_int32_t user)
-{
-	int err = ip_defrag(skb, user);
-
-	if (!err)
-		ip_send_check(ip_hdr(skb));
-
-	return err;
-}
-
-/*
- * Packet has been made sufficiently writable in caller
- * - inout: 1=in->out, 0=out->in
- */
-void ip_vs_nat_icmp(struct sk_buff *skb, struct ip_vs_protocol *pp,
-		    struct ip_vs_conn *cp, int inout)
-{
-	struct iphdr *iph	 = ip_hdr(skb);
-	unsigned int icmp_offset = iph->ihl*4;
-	struct icmphdr *icmph	 = (struct icmphdr *)(skb_network_header(skb) +
-						      icmp_offset);
-	struct iphdr *ciph	 = (struct iphdr *)(icmph + 1);
-
-	if (inout) {
-		iph->saddr = cp->vaddr;
-		ip_send_check(iph);
-		ciph->daddr = cp->vaddr;
-		ip_send_check(ciph);
-	} else {
-		iph->daddr = cp->daddr;
-		ip_send_check(iph);
-		ciph->saddr = cp->daddr;
-		ip_send_check(ciph);
-	}
-
-	/* the TCP/UDP port */
-	if (IPPROTO_TCP == ciph->protocol || IPPROTO_UDP == ciph->protocol) {
-		__be16 *ports = (void *)ciph + ciph->ihl*4;
-
-		if (inout)
-			ports[1] = cp->vport;
-		else
-			ports[0] = cp->dport;
-	}
-
-	/* And finally the ICMP checksum */
-	icmph->checksum = 0;
-	icmph->checksum = ip_vs_checksum_complete(skb, icmp_offset);
-	skb->ip_summed = CHECKSUM_UNNECESSARY;
-
-	if (inout)
-		IP_VS_DBG_PKT(11, pp, skb, (void *)ciph - (void *)iph,
-			"Forwarding altered outgoing ICMP");
-	else
-		IP_VS_DBG_PKT(11, pp, skb, (void *)ciph - (void *)iph,
-			"Forwarding altered incoming ICMP");
-}
-
-/*
- *	Handle ICMP messages in the inside-to-outside direction (outgoing).
- *	Find any that might be relevant, check against existing connections,
- *	forward to the right destination host if relevant.
- *	Currently handles error types - unreachable, quench, ttl exceeded.
- *	(Only used in VS/NAT)
- */
-static int ip_vs_out_icmp(struct sk_buff *skb, int *related)
-{
-	struct iphdr *iph;
-	struct icmphdr	_icmph, *ic;
-	struct iphdr	_ciph, *cih;	/* The ip header contained within the ICMP */
-	struct ip_vs_conn *cp;
-	struct ip_vs_protocol *pp;
-	unsigned int offset, ihl, verdict;
-
-	*related = 1;
-
-	/* reassemble IP fragments */
-	if (ip_hdr(skb)->frag_off & htons(IP_MF | IP_OFFSET)) {
-		if (ip_vs_gather_frags(skb, IP_DEFRAG_VS_OUT))
-			return NF_STOLEN;
-	}
-
-	iph = ip_hdr(skb);
-	offset = ihl = iph->ihl * 4;
-	ic = skb_header_pointer(skb, offset, sizeof(_icmph), &_icmph);
-	if (ic == NULL)
-		return NF_DROP;
-
-	IP_VS_DBG(12, "Outgoing ICMP (%d,%d) %u.%u.%u.%u->%u.%u.%u.%u\n",
-		  ic->type, ntohs(icmp_id(ic)),
-		  NIPQUAD(iph->saddr), NIPQUAD(iph->daddr));
-
-	/*
-	 * Work through seeing if this is for us.
-	 * These checks are supposed to be in an order that means easy
-	 * things are checked first to speed up processing.... however
-	 * this means that some packets will manage to get a long way
-	 * down this stack and then be rejected, but that's life.
-	 */
-	if ((ic->type != ICMP_DEST_UNREACH) &&
-	    (ic->type != ICMP_SOURCE_QUENCH) &&
-	    (ic->type != ICMP_TIME_EXCEEDED)) {
-		*related = 0;
-		return NF_ACCEPT;
-	}
-
-	/* Now find the contained IP header */
-	offset += sizeof(_icmph);
-	cih = skb_header_pointer(skb, offset, sizeof(_ciph), &_ciph);
-	if (cih == NULL)
-		return NF_ACCEPT; /* The packet looks wrong, ignore */
-
-	pp = ip_vs_proto_get(cih->protocol);
-	if (!pp)
-		return NF_ACCEPT;
-
-	/* Is the embedded protocol header present? */
-	if (unlikely(cih->frag_off & htons(IP_OFFSET) &&
-		     pp->dont_defrag))
-		return NF_ACCEPT;
-
-	IP_VS_DBG_PKT(11, pp, skb, offset, "Checking outgoing ICMP for");
-
-	offset += cih->ihl * 4;
-
-	/* The embedded headers contain source and dest in reverse order */
-	cp = pp->conn_out_get(skb, pp, cih, offset, 1);
-	if (!cp)
-		return NF_ACCEPT;
-
-	verdict = NF_DROP;
-
-	if (IP_VS_FWD_METHOD(cp) != 0) {
-		IP_VS_ERR("shouldn't reach here, because the box is on the "
-			  "half connection in the tun/dr module.\n");
-	}
-
-	/* Ensure the checksum is correct */
-	if (!skb_csum_unnecessary(skb) && ip_vs_checksum_complete(skb, ihl)) {
-		/* Failed checksum! */
-		IP_VS_DBG(1, "Forward ICMP: failed checksum from %d.%d.%d.%d!\n",
-			  NIPQUAD(iph->saddr));
-		goto out;
-	}
-
-	if (IPPROTO_TCP == cih->protocol || IPPROTO_UDP == cih->protocol)
-		offset += 2 * sizeof(__u16);
-	if (!skb_make_writable(skb, offset))
-		goto out;
-
-	ip_vs_nat_icmp(skb, pp, cp, 1);
-
-	/* do the statistics and put it back */
-	ip_vs_out_stats(cp, skb);
-
-	skb->ipvs_property = 1;
-	verdict = NF_ACCEPT;
-
-  out:
-	__ip_vs_conn_put(cp);
-
-	return verdict;
-}
-
-static inline int is_tcp_reset(const struct sk_buff *skb)
-{
-	struct tcphdr _tcph, *th;
-
-	th = skb_header_pointer(skb, ip_hdrlen(skb), sizeof(_tcph), &_tcph);
-	if (th == NULL)
-		return 0;
-	return th->rst;
-}
-
-/*
- *	It is hooked at the NF_INET_FORWARD chain, used only for VS/NAT.
- *	Check if outgoing packet belongs to the established ip_vs_conn,
- *      rewrite addresses of the packet and send it on its way...
- */
-static unsigned int
-ip_vs_out(unsigned int hooknum, struct sk_buff *skb,
-	  const struct net_device *in, const struct net_device *out,
-	  int (*okfn)(struct sk_buff *))
-{
-	struct iphdr	*iph;
-	struct ip_vs_protocol *pp;
-	struct ip_vs_conn *cp;
-	int ihl;
-
-	EnterFunction(11);
-
-	if (skb->ipvs_property)
-		return NF_ACCEPT;
-
-	iph = ip_hdr(skb);
-	if (unlikely(iph->protocol == IPPROTO_ICMP)) {
-		int related, verdict = ip_vs_out_icmp(skb, &related);
-
-		if (related)
-			return verdict;
-		iph = ip_hdr(skb);
-	}
-
-	pp = ip_vs_proto_get(iph->protocol);
-	if (unlikely(!pp))
-		return NF_ACCEPT;
-
-	/* reassemble IP fragments */
-	if (unlikely(iph->frag_off & htons(IP_MF|IP_OFFSET) &&
-		     !pp->dont_defrag)) {
-		if (ip_vs_gather_frags(skb, IP_DEFRAG_VS_OUT))
-			return NF_STOLEN;
-		iph = ip_hdr(skb);
-	}
-
-	ihl = iph->ihl << 2;
-
-	/*
-	 * Check if the packet belongs to an existing entry
-	 */
-	cp = pp->conn_out_get(skb, pp, iph, ihl, 0);
-
-	if (unlikely(!cp)) {
-		if (sysctl_ip_vs_nat_icmp_send &&
-		    (pp->protocol == IPPROTO_TCP ||
-		     pp->protocol == IPPROTO_UDP)) {
-			__be16 _ports[2], *pptr;
-
-			pptr = skb_header_pointer(skb, ihl,
-						  sizeof(_ports), _ports);
-			if (pptr == NULL)
-				return NF_ACCEPT;	/* Not for me */
-			if (ip_vs_lookup_real_service(iph->protocol,
-						      iph->saddr, pptr[0])) {
-				/*
-				 * Notify the real server: there is no
-				 * existing entry if it is not RST
-				 * packet or not TCP packet.
-				 */
-				if (iph->protocol != IPPROTO_TCP
-				    || !is_tcp_reset(skb)) {
-					icmp_send(skb,ICMP_DEST_UNREACH,
-						  ICMP_PORT_UNREACH, 0);
-					return NF_DROP;
-				}
-			}
-		}
-		IP_VS_DBG_PKT(12, pp, skb, 0,
-			      "packet continues traversal as normal");
-		return NF_ACCEPT;
-	}
-
-	IP_VS_DBG_PKT(11, pp, skb, 0, "Outgoing packet");
-
-	if (!skb_make_writable(skb, ihl))
-		goto drop;
-
-	/* mangle the packet */
-	if (pp->snat_handler && !pp->snat_handler(skb, pp, cp))
-		goto drop;
-	ip_hdr(skb)->saddr = cp->vaddr;
-	ip_send_check(ip_hdr(skb));
-
-	/* 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(skb, RTN_LOCAL) != 0)
-		goto drop;
-
-	IP_VS_DBG_PKT(10, pp, skb, 0, "After SNAT");
-
-	ip_vs_out_stats(cp, skb);
-	ip_vs_set_state(cp, IP_VS_DIR_OUTPUT, skb, pp);
-	ip_vs_conn_put(cp);
-
-	skb->ipvs_property = 1;
-
-	LeaveFunction(11);
-	return NF_ACCEPT;
-
-  drop:
-	ip_vs_conn_put(cp);
-	kfree_skb(skb);
-	return NF_STOLEN;
-}
-
-
-/*
- *	Handle ICMP messages in the outside-to-inside direction (incoming).
- *	Find any that might be relevant, check against existing connections,
- *	forward to the right destination host if relevant.
- *	Currently handles error types - unreachable, quench, ttl exceeded.
- */
-static int
-ip_vs_in_icmp(struct sk_buff *skb, int *related, unsigned int hooknum)
-{
-	struct iphdr *iph;
-	struct icmphdr	_icmph, *ic;
-	struct iphdr	_ciph, *cih;	/* The ip header contained within the ICMP */
-	struct ip_vs_conn *cp;
-	struct ip_vs_protocol *pp;
-	unsigned int offset, ihl, verdict;
-
-	*related = 1;
-
-	/* reassemble IP fragments */
-	if (ip_hdr(skb)->frag_off & htons(IP_MF | IP_OFFSET)) {
-		if (ip_vs_gather_frags(skb, hooknum == NF_INET_LOCAL_IN ?
-					    IP_DEFRAG_VS_IN : IP_DEFRAG_VS_FWD))
-			return NF_STOLEN;
-	}
-
-	iph = ip_hdr(skb);
-	offset = ihl = iph->ihl * 4;
-	ic = skb_header_pointer(skb, offset, sizeof(_icmph), &_icmph);
-	if (ic == NULL)
-		return NF_DROP;
-
-	IP_VS_DBG(12, "Incoming ICMP (%d,%d) %u.%u.%u.%u->%u.%u.%u.%u\n",
-		  ic->type, ntohs(icmp_id(ic)),
-		  NIPQUAD(iph->saddr), NIPQUAD(iph->daddr));
-
-	/*
-	 * Work through seeing if this is for us.
-	 * These checks are supposed to be in an order that means easy
-	 * things are checked first to speed up processing.... however
-	 * this means that some packets will manage to get a long way
-	 * down this stack and then be rejected, but that's life.
-	 */
-	if ((ic->type != ICMP_DEST_UNREACH) &&
-	    (ic->type != ICMP_SOURCE_QUENCH) &&
-	    (ic->type != ICMP_TIME_EXCEEDED)) {
-		*related = 0;
-		return NF_ACCEPT;
-	}
-
-	/* Now find the contained IP header */
-	offset += sizeof(_icmph);
-	cih = skb_header_pointer(skb, offset, sizeof(_ciph), &_ciph);
-	if (cih == NULL)
-		return NF_ACCEPT; /* The packet looks wrong, ignore */
-
-	pp = ip_vs_proto_get(cih->protocol);
-	if (!pp)
-		return NF_ACCEPT;
-
-	/* Is the embedded protocol header present? */
-	if (unlikely(cih->frag_off & htons(IP_OFFSET) &&
-		     pp->dont_defrag))
-		return NF_ACCEPT;
-
-	IP_VS_DBG_PKT(11, pp, skb, offset, "Checking incoming ICMP for");
-
-	offset += cih->ihl * 4;
-
-	/* The embedded headers contain source and dest in reverse order */
-	cp = pp->conn_in_get(skb, pp, cih, offset, 1);
-	if (!cp)
-		return NF_ACCEPT;
-
-	verdict = NF_DROP;
-
-	/* Ensure the checksum is correct */
-	if (!skb_csum_unnecessary(skb) && ip_vs_checksum_complete(skb, ihl)) {
-		/* Failed checksum! */
-		IP_VS_DBG(1, "Incoming ICMP: failed checksum from %d.%d.%d.%d!\n",
-			  NIPQUAD(iph->saddr));
-		goto out;
-	}
-
-	/* do the statistics and put it back */
-	ip_vs_in_stats(cp, skb);
-	if (IPPROTO_TCP == cih->protocol || IPPROTO_UDP == cih->protocol)
-		offset += 2 * sizeof(__u16);
-	verdict = ip_vs_icmp_xmit(skb, cp, pp, offset);
-	/* do not touch skb anymore */
-
-  out:
-	__ip_vs_conn_put(cp);
-
-	return verdict;
-}
-
-/*
- *	Check if it's for virtual services, look it up,
- *	and send it on its way...
- */
-static unsigned int
-ip_vs_in(unsigned int hooknum, struct sk_buff *skb,
-	 const struct net_device *in, const struct net_device *out,
-	 int (*okfn)(struct sk_buff *))
-{
-	struct iphdr	*iph;
-	struct ip_vs_protocol *pp;
-	struct ip_vs_conn *cp;
-	int ret, restart;
-	int ihl;
-
-	/*
-	 *	Big tappo: only PACKET_HOST (neither loopback nor mcasts)
-	 *	... don't know why 1st test DOES NOT include 2nd (?)
-	 */
-	if (unlikely(skb->pkt_type != PACKET_HOST
-		     || skb->dev->flags & IFF_LOOPBACK || skb->sk)) {
-		IP_VS_DBG(12, "packet type=%d proto=%d daddr=%d.%d.%d.%d ignored\n",
-			  skb->pkt_type,
-			  ip_hdr(skb)->protocol,
-			  NIPQUAD(ip_hdr(skb)->daddr));
-		return NF_ACCEPT;
-	}
-
-	iph = ip_hdr(skb);
-	if (unlikely(iph->protocol == IPPROTO_ICMP)) {
-		int related, verdict = ip_vs_in_icmp(skb, &related, hooknum);
-
-		if (related)
-			return verdict;
-		iph = ip_hdr(skb);
-	}
-
-	/* Protocol supported? */
-	pp = ip_vs_proto_get(iph->protocol);
-	if (unlikely(!pp))
-		return NF_ACCEPT;
-
-	ihl = iph->ihl << 2;
-
-	/*
-	 * Check if the packet belongs to an existing connection entry
-	 */
-	cp = pp->conn_in_get(skb, pp, iph, ihl, 0);
-
-	if (unlikely(!cp)) {
-		int v;
-
-		if (!pp->conn_schedule(skb, pp, &v, &cp))
-			return v;
-	}
-
-	if (unlikely(!cp)) {
-		/* sorry, all this trouble for a no-hit :) */
-		IP_VS_DBG_PKT(12, pp, skb, 0,
-			      "packet continues traversal as normal");
-		return NF_ACCEPT;
-	}
-
-	IP_VS_DBG_PKT(11, pp, skb, 0, "Incoming packet");
-
-	/* Check the server status */
-	if (cp->dest && !(cp->dest->flags & IP_VS_DEST_F_AVAILABLE)) {
-		/* the destination server is not available */
-
-		if (sysctl_ip_vs_expire_nodest_conn) {
-			/* try to expire the connection immediately */
-			ip_vs_conn_expire_now(cp);
-		}
-		/* don't restart its timer, and silently
-		   drop the packet. */
-		__ip_vs_conn_put(cp);
-		return NF_DROP;
-	}
-
-	ip_vs_in_stats(cp, skb);
-	restart = ip_vs_set_state(cp, IP_VS_DIR_INPUT, skb, pp);
-	if (cp->packet_xmit)
-		ret = cp->packet_xmit(skb, cp, pp);
-		/* do not touch skb anymore */
-	else {
-		IP_VS_DBG_RL("warning: packet_xmit is null");
-		ret = NF_ACCEPT;
-	}
-
-	/* Increase its packet counter and check if it is needed
-	 * to be synchronized
-	 *
-	 * Sync connection if it is about to close to
-	 * encorage the standby servers to update the connections timeout
-	 */
-	atomic_inc(&cp->in_pkts);
-	if ((ip_vs_sync_state & IP_VS_STATE_MASTER) &&
-	    (((cp->protocol != IPPROTO_TCP ||
-	       cp->state == IP_VS_TCP_S_ESTABLISHED) &&
-	      (atomic_read(&cp->in_pkts) % sysctl_ip_vs_sync_threshold[1]
-	       == sysctl_ip_vs_sync_threshold[0])) ||
-	     ((cp->protocol == IPPROTO_TCP) && (cp->old_state != cp->state) &&
-	      ((cp->state == IP_VS_TCP_S_FIN_WAIT) ||
-	       (cp->state == IP_VS_TCP_S_CLOSE_WAIT) ||
-	       (cp->state == IP_VS_TCP_S_TIME_WAIT)))))
-		ip_vs_sync_conn(cp);
-	cp->old_state = cp->state;
-
-	ip_vs_conn_put(cp);
-	return ret;
-}
-
-
-/*
- *	It is hooked at the NF_INET_FORWARD chain, in order to catch ICMP
- *      related packets destined for 0.0.0.0/0.
- *      When fwmark-based virtual service is used, such as transparent
- *      cache cluster, TCP packets can be marked and routed to ip_vs_in,
- *      but ICMP destined for 0.0.0.0/0 cannot not be easily marked and
- *      sent to ip_vs_in_icmp. So, catch them at the NF_INET_FORWARD chain
- *      and send them to ip_vs_in_icmp.
- */
-static unsigned int
-ip_vs_forward_icmp(unsigned int hooknum, struct sk_buff *skb,
-		   const struct net_device *in, const struct net_device *out,
-		   int (*okfn)(struct sk_buff *))
-{
-	int r;
-
-	if (ip_hdr(skb)->protocol != IPPROTO_ICMP)
-		return NF_ACCEPT;
-
-	return ip_vs_in_icmp(skb, &r, hooknum);
-}
-
-
-static struct nf_hook_ops ip_vs_ops[] __read_mostly = {
-	/* After packet filtering, forward packet through VS/DR, VS/TUN,
-	 * or VS/NAT(change destination), so that filtering rules can be
-	 * applied to IPVS. */
-	{
-		.hook		= ip_vs_in,
-		.owner		= THIS_MODULE,
-		.pf		= PF_INET,
-		.hooknum        = NF_INET_LOCAL_IN,
-		.priority       = 100,
-	},
-	/* After packet filtering, change source only for VS/NAT */
-	{
-		.hook		= ip_vs_out,
-		.owner		= THIS_MODULE,
-		.pf		= PF_INET,
-		.hooknum        = NF_INET_FORWARD,
-		.priority       = 100,
-	},
-	/* After packet filtering (but before ip_vs_out_icmp), catch icmp
-	 * destined for 0.0.0.0/0, which is for incoming IPVS connections */
-	{
-		.hook		= ip_vs_forward_icmp,
-		.owner		= THIS_MODULE,
-		.pf		= PF_INET,
-		.hooknum        = NF_INET_FORWARD,
-		.priority       = 99,
-	},
-	/* Before the netfilter connection tracking, exit from POST_ROUTING */
-	{
-		.hook		= ip_vs_post_routing,
-		.owner		= THIS_MODULE,
-		.pf		= PF_INET,
-		.hooknum        = NF_INET_POST_ROUTING,
-		.priority       = NF_IP_PRI_NAT_SRC-1,
-	},
-};
-
-
-/*
- *	Initialize IP Virtual Server
- */
-static int __init ip_vs_init(void)
-{
-	int ret;
-
-	ret = ip_vs_control_init();
-	if (ret < 0) {
-		IP_VS_ERR("can't setup control.\n");
-		goto cleanup_nothing;
-	}
-
-	ip_vs_protocol_init();
-
-	ret = ip_vs_app_init();
-	if (ret < 0) {
-		IP_VS_ERR("can't setup application helper.\n");
-		goto cleanup_protocol;
-	}
-
-	ret = ip_vs_conn_init();
-	if (ret < 0) {
-		IP_VS_ERR("can't setup connection table.\n");
-		goto cleanup_app;
-	}
-
-	ret = nf_register_hooks(ip_vs_ops, ARRAY_SIZE(ip_vs_ops));
-	if (ret < 0) {
-		IP_VS_ERR("can't register hooks.\n");
-		goto cleanup_conn;
-	}
-
-	IP_VS_INFO("ipvs loaded.\n");
-	return ret;
-
-  cleanup_conn:
-	ip_vs_conn_cleanup();
-  cleanup_app:
-	ip_vs_app_cleanup();
-  cleanup_protocol:
-	ip_vs_protocol_cleanup();
-	ip_vs_control_cleanup();
-  cleanup_nothing:
-	return ret;
-}
-
-static void __exit ip_vs_cleanup(void)
-{
-	nf_unregister_hooks(ip_vs_ops, ARRAY_SIZE(ip_vs_ops));
-	ip_vs_conn_cleanup();
-	ip_vs_app_cleanup();
-	ip_vs_protocol_cleanup();
-	ip_vs_control_cleanup();
-	IP_VS_INFO("ipvs unloaded.\n");
-}
-
-module_init(ip_vs_init);
-module_exit(ip_vs_cleanup);
-MODULE_LICENSE("GPL");
diff --git a/net/ipv4/ipvs/ip_vs_ctl.c b/net/ipv4/ipvs/ip_vs_ctl.c
deleted file mode 100644
index 6379705..0000000
--- a/net/ipv4/ipvs/ip_vs_ctl.c
+++ /dev/null
@@ -1,2373 +0,0 @@
-/*
- * IPVS         An implementation of the IP virtual server support for the
- *              LINUX operating system.  IPVS is now implemented as a module
- *              over the NetFilter framework. IPVS can be used to build a
- *              high-performance and highly available server based on a
- *              cluster of servers.
- *
- * Authors:     Wensong Zhang <wensong@linuxvirtualserver.org>
- *              Peter Kese <peter.kese@ijs.si>
- *              Julian Anastasov <ja@ssi.bg>
- *
- *              This program is free software; you can redistribute it and/or
- *              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.
- *
- * Changes:
- *
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/types.h>
-#include <linux/capability.h>
-#include <linux/fs.h>
-#include <linux/sysctl.h>
-#include <linux/proc_fs.h>
-#include <linux/workqueue.h>
-#include <linux/swap.h>
-#include <linux/seq_file.h>
-
-#include <linux/netfilter.h>
-#include <linux/netfilter_ipv4.h>
-#include <linux/mutex.h>
-
-#include <net/net_namespace.h>
-#include <net/ip.h>
-#include <net/route.h>
-#include <net/sock.h>
-
-#include <asm/uaccess.h>
-
-#include <net/ip_vs.h>
-
-/* semaphore for IPVS sockopts. And, [gs]etsockopt may sleep. */
-static DEFINE_MUTEX(__ip_vs_mutex);
-
-/* lock for service table */
-static DEFINE_RWLOCK(__ip_vs_svc_lock);
-
-/* lock for table with the real services */
-static DEFINE_RWLOCK(__ip_vs_rs_lock);
-
-/* lock for state and timeout tables */
-static DEFINE_RWLOCK(__ip_vs_securetcp_lock);
-
-/* lock for drop entry handling */
-static DEFINE_SPINLOCK(__ip_vs_dropentry_lock);
-
-/* lock for drop packet handling */
-static DEFINE_SPINLOCK(__ip_vs_droppacket_lock);
-
-/* 1/rate drop and drop-entry variables */
-int ip_vs_drop_rate = 0;
-int ip_vs_drop_counter = 0;
-static atomic_t ip_vs_dropentry = ATOMIC_INIT(0);
-
-/* number of virtual services */
-static int ip_vs_num_services = 0;
-
-/* sysctl variables */
-static int sysctl_ip_vs_drop_entry = 0;
-static int sysctl_ip_vs_drop_packet = 0;
-static int sysctl_ip_vs_secure_tcp = 0;
-static int sysctl_ip_vs_amemthresh = 1024;
-static int sysctl_ip_vs_am_droprate = 10;
-int sysctl_ip_vs_cache_bypass = 0;
-int sysctl_ip_vs_expire_nodest_conn = 0;
-int sysctl_ip_vs_expire_quiescent_template = 0;
-int sysctl_ip_vs_sync_threshold[2] = { 3, 50 };
-int sysctl_ip_vs_nat_icmp_send = 0;
-
-
-#ifdef CONFIG_IP_VS_DEBUG
-static int sysctl_ip_vs_debug_level = 0;
-
-int ip_vs_get_debug_level(void)
-{
-	return sysctl_ip_vs_debug_level;
-}
-#endif
-
-/*
- *	update_defense_level is called from keventd and from sysctl,
- *	so it needs to protect itself from softirqs
- */
-static void update_defense_level(void)
-{
-	struct sysinfo i;
-	static int old_secure_tcp = 0;
-	int availmem;
-	int nomem;
-	int to_change = -1;
-
-	/* we only count free and buffered memory (in pages) */
-	si_meminfo(&i);
-	availmem = i.freeram + i.bufferram;
-	/* however in linux 2.5 the i.bufferram is total page cache size,
-	   we need adjust it */
-	/* si_swapinfo(&i); */
-	/* availmem = availmem - (i.totalswap - i.freeswap); */
-
-	nomem = (availmem < sysctl_ip_vs_amemthresh);
-
-	local_bh_disable();
-
-	/* drop_entry */
-	spin_lock(&__ip_vs_dropentry_lock);
-	switch (sysctl_ip_vs_drop_entry) {
-	case 0:
-		atomic_set(&ip_vs_dropentry, 0);
-		break;
-	case 1:
-		if (nomem) {
-			atomic_set(&ip_vs_dropentry, 1);
-			sysctl_ip_vs_drop_entry = 2;
-		} else {
-			atomic_set(&ip_vs_dropentry, 0);
-		}
-		break;
-	case 2:
-		if (nomem) {
-			atomic_set(&ip_vs_dropentry, 1);
-		} else {
-			atomic_set(&ip_vs_dropentry, 0);
-			sysctl_ip_vs_drop_entry = 1;
-		};
-		break;
-	case 3:
-		atomic_set(&ip_vs_dropentry, 1);
-		break;
-	}
-	spin_unlock(&__ip_vs_dropentry_lock);
-
-	/* drop_packet */
-	spin_lock(&__ip_vs_droppacket_lock);
-	switch (sysctl_ip_vs_drop_packet) {
-	case 0:
-		ip_vs_drop_rate = 0;
-		break;
-	case 1:
-		if (nomem) {
-			ip_vs_drop_rate = ip_vs_drop_counter
-				= sysctl_ip_vs_amemthresh /
-				(sysctl_ip_vs_amemthresh-availmem);
-			sysctl_ip_vs_drop_packet = 2;
-		} else {
-			ip_vs_drop_rate = 0;
-		}
-		break;
-	case 2:
-		if (nomem) {
-			ip_vs_drop_rate = ip_vs_drop_counter
-				= sysctl_ip_vs_amemthresh /
-				(sysctl_ip_vs_amemthresh-availmem);
-		} else {
-			ip_vs_drop_rate = 0;
-			sysctl_ip_vs_drop_packet = 1;
-		}
-		break;
-	case 3:
-		ip_vs_drop_rate = sysctl_ip_vs_am_droprate;
-		break;
-	}
-	spin_unlock(&__ip_vs_droppacket_lock);
-
-	/* secure_tcp */
-	write_lock(&__ip_vs_securetcp_lock);
-	switch (sysctl_ip_vs_secure_tcp) {
-	case 0:
-		if (old_secure_tcp >= 2)
-			to_change = 0;
-		break;
-	case 1:
-		if (nomem) {
-			if (old_secure_tcp < 2)
-				to_change = 1;
-			sysctl_ip_vs_secure_tcp = 2;
-		} else {
-			if (old_secure_tcp >= 2)
-				to_change = 0;
-		}
-		break;
-	case 2:
-		if (nomem) {
-			if (old_secure_tcp < 2)
-				to_change = 1;
-		} else {
-			if (old_secure_tcp >= 2)
-				to_change = 0;
-			sysctl_ip_vs_secure_tcp = 1;
-		}
-		break;
-	case 3:
-		if (old_secure_tcp < 2)
-			to_change = 1;
-		break;
-	}
-	old_secure_tcp = sysctl_ip_vs_secure_tcp;
-	if (to_change >= 0)
-		ip_vs_protocol_timeout_change(sysctl_ip_vs_secure_tcp>1);
-	write_unlock(&__ip_vs_securetcp_lock);
-
-	local_bh_enable();
-}
-
-
-/*
- *	Timer for checking the defense
- */
-#define DEFENSE_TIMER_PERIOD	1*HZ
-static void defense_work_handler(struct work_struct *work);
-static DECLARE_DELAYED_WORK(defense_work, defense_work_handler);
-
-static void defense_work_handler(struct work_struct *work)
-{
-	update_defense_level();
-	if (atomic_read(&ip_vs_dropentry))
-		ip_vs_random_dropentry();
-
-	schedule_delayed_work(&defense_work, DEFENSE_TIMER_PERIOD);
-}
-
-int
-ip_vs_use_count_inc(void)
-{
-	return try_module_get(THIS_MODULE);
-}
-
-void
-ip_vs_use_count_dec(void)
-{
-	module_put(THIS_MODULE);
-}
-
-
-/*
- *	Hash table: for virtual service lookups
- */
-#define IP_VS_SVC_TAB_BITS 8
-#define IP_VS_SVC_TAB_SIZE (1 << IP_VS_SVC_TAB_BITS)
-#define IP_VS_SVC_TAB_MASK (IP_VS_SVC_TAB_SIZE - 1)
-
-/* the service table hashed by <protocol, addr, port> */
-static struct list_head ip_vs_svc_table[IP_VS_SVC_TAB_SIZE];
-/* the service table hashed by fwmark */
-static struct list_head ip_vs_svc_fwm_table[IP_VS_SVC_TAB_SIZE];
-
-/*
- *	Hash table: for real service lookups
- */
-#define IP_VS_RTAB_BITS 4
-#define IP_VS_RTAB_SIZE (1 << IP_VS_RTAB_BITS)
-#define IP_VS_RTAB_MASK (IP_VS_RTAB_SIZE - 1)
-
-static struct list_head ip_vs_rtable[IP_VS_RTAB_SIZE];
-
-/*
- *	Trash for destinations
- */
-static LIST_HEAD(ip_vs_dest_trash);
-
-/*
- *	FTP & NULL virtual service counters
- */
-static atomic_t ip_vs_ftpsvc_counter = ATOMIC_INIT(0);
-static atomic_t ip_vs_nullsvc_counter = ATOMIC_INIT(0);
-
-
-/*
- *	Returns hash value for virtual service
- */
-static __inline__ unsigned
-ip_vs_svc_hashkey(unsigned proto, __be32 addr, __be16 port)
-{
-	register unsigned porth = ntohs(port);
-
-	return (proto^ntohl(addr)^(porth>>IP_VS_SVC_TAB_BITS)^porth)
-		& IP_VS_SVC_TAB_MASK;
-}
-
-/*
- *	Returns hash value of fwmark for virtual service lookup
- */
-static __inline__ unsigned ip_vs_svc_fwm_hashkey(__u32 fwmark)
-{
-	return fwmark & IP_VS_SVC_TAB_MASK;
-}
-
-/*
- *	Hashes a service in the ip_vs_svc_table by <proto,addr,port>
- *	or in the ip_vs_svc_fwm_table by fwmark.
- *	Should be called with locked tables.
- */
-static int ip_vs_svc_hash(struct ip_vs_service *svc)
-{
-	unsigned hash;
-
-	if (svc->flags & IP_VS_SVC_F_HASHED) {
-		IP_VS_ERR("ip_vs_svc_hash(): request for already hashed, "
-			  "called from %p\n", __builtin_return_address(0));
-		return 0;
-	}
-
-	if (svc->fwmark == 0) {
-		/*
-		 *  Hash it by <protocol,addr,port> in ip_vs_svc_table
-		 */
-		hash = ip_vs_svc_hashkey(svc->protocol, svc->addr, svc->port);
-		list_add(&svc->s_list, &ip_vs_svc_table[hash]);
-	} else {
-		/*
-		 *  Hash it by fwmark in ip_vs_svc_fwm_table
-		 */
-		hash = ip_vs_svc_fwm_hashkey(svc->fwmark);
-		list_add(&svc->f_list, &ip_vs_svc_fwm_table[hash]);
-	}
-
-	svc->flags |= IP_VS_SVC_F_HASHED;
-	/* increase its refcnt because it is referenced by the svc table */
-	atomic_inc(&svc->refcnt);
-	return 1;
-}
-
-
-/*
- *	Unhashes a service from ip_vs_svc_table/ip_vs_svc_fwm_table.
- *	Should be called with locked tables.
- */
-static int ip_vs_svc_unhash(struct ip_vs_service *svc)
-{
-	if (!(svc->flags & IP_VS_SVC_F_HASHED)) {
-		IP_VS_ERR("ip_vs_svc_unhash(): request for unhash flagged, "
-			  "called from %p\n", __builtin_return_address(0));
-		return 0;
-	}
-
-	if (svc->fwmark == 0) {
-		/* Remove it from the ip_vs_svc_table table */
-		list_del(&svc->s_list);
-	} else {
-		/* Remove it from the ip_vs_svc_fwm_table table */
-		list_del(&svc->f_list);
-	}
-
-	svc->flags &= ~IP_VS_SVC_F_HASHED;
-	atomic_dec(&svc->refcnt);
-	return 1;
-}
-
-
-/*
- *	Get service by {proto,addr,port} in the service table.
- */
-static __inline__ struct ip_vs_service *
-__ip_vs_service_get(__u16 protocol, __be32 vaddr, __be16 vport)
-{
-	unsigned hash;
-	struct ip_vs_service *svc;
-
-	/* Check for "full" addressed entries */
-	hash = ip_vs_svc_hashkey(protocol, vaddr, vport);
-
-	list_for_each_entry(svc, &ip_vs_svc_table[hash], s_list){
-		if ((svc->addr == vaddr)
-		    && (svc->port == vport)
-		    && (svc->protocol == protocol)) {
-			/* HIT */
-			atomic_inc(&svc->usecnt);
-			return svc;
-		}
-	}
-
-	return NULL;
-}
-
-
-/*
- *	Get service by {fwmark} in the service table.
- */
-static __inline__ struct ip_vs_service *__ip_vs_svc_fwm_get(__u32 fwmark)
-{
-	unsigned hash;
-	struct ip_vs_service *svc;
-
-	/* Check for fwmark addressed entries */
-	hash = ip_vs_svc_fwm_hashkey(fwmark);
-
-	list_for_each_entry(svc, &ip_vs_svc_fwm_table[hash], f_list) {
-		if (svc->fwmark == fwmark) {
-			/* HIT */
-			atomic_inc(&svc->usecnt);
-			return svc;
-		}
-	}
-
-	return NULL;
-}
-
-struct ip_vs_service *
-ip_vs_service_get(__u32 fwmark, __u16 protocol, __be32 vaddr, __be16 vport)
-{
-	struct ip_vs_service *svc;
-
-	read_lock(&__ip_vs_svc_lock);
-
-	/*
-	 *	Check the table hashed by fwmark first
-	 */
-	if (fwmark && (svc = __ip_vs_svc_fwm_get(fwmark)))
-		goto out;
-
-	/*
-	 *	Check the table hashed by <protocol,addr,port>
-	 *	for "full" addressed entries
-	 */
-	svc = __ip_vs_service_get(protocol, vaddr, vport);
-
-	if (svc == NULL
-	    && protocol == IPPROTO_TCP
-	    && atomic_read(&ip_vs_ftpsvc_counter)
-	    && (vport == FTPDATA || ntohs(vport) >= PROT_SOCK)) {
-		/*
-		 * Check if ftp service entry exists, the packet
-		 * might belong to FTP data connections.
-		 */
-		svc = __ip_vs_service_get(protocol, vaddr, FTPPORT);
-	}
-
-	if (svc == NULL
-	    && atomic_read(&ip_vs_nullsvc_counter)) {
-		/*
-		 * Check if the catch-all port (port zero) exists
-		 */
-		svc = __ip_vs_service_get(protocol, vaddr, 0);
-	}
-
-  out:
-	read_unlock(&__ip_vs_svc_lock);
-
-	IP_VS_DBG(9, "lookup service: fwm %u %s %u.%u.%u.%u:%u %s\n",
-		  fwmark, ip_vs_proto_name(protocol),
-		  NIPQUAD(vaddr), ntohs(vport),
-		  svc?"hit":"not hit");
-
-	return svc;
-}
-
-
-static inline void
-__ip_vs_bind_svc(struct ip_vs_dest *dest, struct ip_vs_service *svc)
-{
-	atomic_inc(&svc->refcnt);
-	dest->svc = svc;
-}
-
-static inline void
-__ip_vs_unbind_svc(struct ip_vs_dest *dest)
-{
-	struct ip_vs_service *svc = dest->svc;
-
-	dest->svc = NULL;
-	if (atomic_dec_and_test(&svc->refcnt))
-		kfree(svc);
-}
-
-
-/*
- *	Returns hash value for real service
- */
-static __inline__ unsigned ip_vs_rs_hashkey(__be32 addr, __be16 port)
-{
-	register unsigned porth = ntohs(port);
-
-	return (ntohl(addr)^(porth>>IP_VS_RTAB_BITS)^porth)
-		& IP_VS_RTAB_MASK;
-}
-
-/*
- *	Hashes ip_vs_dest in ip_vs_rtable by <proto,addr,port>.
- *	should be called with locked tables.
- */
-static int ip_vs_rs_hash(struct ip_vs_dest *dest)
-{
-	unsigned hash;
-
-	if (!list_empty(&dest->d_list)) {
-		return 0;
-	}
-
-	/*
-	 *	Hash by proto,addr,port,
-	 *	which are the parameters of the real service.
-	 */
-	hash = ip_vs_rs_hashkey(dest->addr, dest->port);
-	list_add(&dest->d_list, &ip_vs_rtable[hash]);
-
-	return 1;
-}
-
-/*
- *	UNhashes ip_vs_dest from ip_vs_rtable.
- *	should be called with locked tables.
- */
-static int ip_vs_rs_unhash(struct ip_vs_dest *dest)
-{
-	/*
-	 * Remove it from the ip_vs_rtable table.
-	 */
-	if (!list_empty(&dest->d_list)) {
-		list_del(&dest->d_list);
-		INIT_LIST_HEAD(&dest->d_list);
-	}
-
-	return 1;
-}
-
-/*
- *	Lookup real service by <proto,addr,port> in the real service table.
- */
-struct ip_vs_dest *
-ip_vs_lookup_real_service(__u16 protocol, __be32 daddr, __be16 dport)
-{
-	unsigned hash;
-	struct ip_vs_dest *dest;
-
-	/*
-	 *	Check for "full" addressed entries
-	 *	Return the first found entry
-	 */
-	hash = ip_vs_rs_hashkey(daddr, dport);
-
-	read_lock(&__ip_vs_rs_lock);
-	list_for_each_entry(dest, &ip_vs_rtable[hash], d_list) {
-		if ((dest->addr == daddr)
-		    && (dest->port == dport)
-		    && ((dest->protocol == protocol) ||
-			dest->vfwmark)) {
-			/* HIT */
-			read_unlock(&__ip_vs_rs_lock);
-			return dest;
-		}
-	}
-	read_unlock(&__ip_vs_rs_lock);
-
-	return NULL;
-}
-
-/*
- *	Lookup destination by {addr,port} in the given service
- */
-static struct ip_vs_dest *
-ip_vs_lookup_dest(struct ip_vs_service *svc, __be32 daddr, __be16 dport)
-{
-	struct ip_vs_dest *dest;
-
-	/*
-	 * Find the destination for the given service
-	 */
-	list_for_each_entry(dest, &svc->destinations, n_list) {
-		if ((dest->addr == daddr) && (dest->port == dport)) {
-			/* HIT */
-			return dest;
-		}
-	}
-
-	return NULL;
-}
-
-/*
- * Find destination by {daddr,dport,vaddr,protocol}
- * Cretaed to be used in ip_vs_process_message() in
- * the backup synchronization daemon. It finds the
- * destination to be bound to the received connection
- * on the backup.
- *
- * ip_vs_lookup_real_service() looked promissing, but
- * seems not working as expected.
- */
-struct ip_vs_dest *ip_vs_find_dest(__be32 daddr, __be16 dport,
-				    __be32 vaddr, __be16 vport, __u16 protocol)
-{
-	struct ip_vs_dest *dest;
-	struct ip_vs_service *svc;
-
-	svc = ip_vs_service_get(0, protocol, vaddr, vport);
-	if (!svc)
-		return NULL;
-	dest = ip_vs_lookup_dest(svc, daddr, dport);
-	if (dest)
-		atomic_inc(&dest->refcnt);
-	ip_vs_service_put(svc);
-	return dest;
-}
-
-/*
- *  Lookup dest by {svc,addr,port} in the destination trash.
- *  The destination trash is used to hold the destinations that are removed
- *  from the service table but are still referenced by some conn entries.
- *  The reason to add the destination trash is when the dest is temporary
- *  down (either by administrator or by monitor program), the dest can be
- *  picked back from the trash, the remaining connections to the dest can
- *  continue, and the counting information of the dest is also useful for
- *  scheduling.
- */
-static struct ip_vs_dest *
-ip_vs_trash_get_dest(struct ip_vs_service *svc, __be32 daddr, __be16 dport)
-{
-	struct ip_vs_dest *dest, *nxt;
-
-	/*
-	 * Find the destination in trash
-	 */
-	list_for_each_entry_safe(dest, nxt, &ip_vs_dest_trash, n_list) {
-		IP_VS_DBG(3, "Destination %u/%u.%u.%u.%u:%u still in trash, "
-			  "dest->refcnt=%d\n",
-			  dest->vfwmark,
-			  NIPQUAD(dest->addr), ntohs(dest->port),
-			  atomic_read(&dest->refcnt));
-		if (dest->addr == daddr &&
-		    dest->port == dport &&
-		    dest->vfwmark == svc->fwmark &&
-		    dest->protocol == svc->protocol &&
-		    (svc->fwmark ||
-		     (dest->vaddr == svc->addr &&
-		      dest->vport == svc->port))) {
-			/* HIT */
-			return dest;
-		}
-
-		/*
-		 * Try to purge the destination from trash if not referenced
-		 */
-		if (atomic_read(&dest->refcnt) == 1) {
-			IP_VS_DBG(3, "Removing destination %u/%u.%u.%u.%u:%u "
-				  "from trash\n",
-				  dest->vfwmark,
-				  NIPQUAD(dest->addr), ntohs(dest->port));
-			list_del(&dest->n_list);
-			ip_vs_dst_reset(dest);
-			__ip_vs_unbind_svc(dest);
-			kfree(dest);
-		}
-	}
-
-	return NULL;
-}
-
-
-/*
- *  Clean up all the destinations in the trash
- *  Called by the ip_vs_control_cleanup()
- *
- *  When the ip_vs_control_clearup is activated by ipvs module exit,
- *  the service tables must have been flushed and all the connections
- *  are expired, and the refcnt of each destination in the trash must
- *  be 1, so we simply release them here.
- */
-static void ip_vs_trash_cleanup(void)
-{
-	struct ip_vs_dest *dest, *nxt;
-
-	list_for_each_entry_safe(dest, nxt, &ip_vs_dest_trash, n_list) {
-		list_del(&dest->n_list);
-		ip_vs_dst_reset(dest);
-		__ip_vs_unbind_svc(dest);
-		kfree(dest);
-	}
-}
-
-
-static void
-ip_vs_zero_stats(struct ip_vs_stats *stats)
-{
-	spin_lock_bh(&stats->lock);
-
-	stats->conns = 0;
-	stats->inpkts = 0;
-	stats->outpkts = 0;
-	stats->inbytes = 0;
-	stats->outbytes = 0;
-
-	stats->cps = 0;
-	stats->inpps = 0;
-	stats->outpps = 0;
-	stats->inbps = 0;
-	stats->outbps = 0;
-
-	ip_vs_zero_estimator(stats);
-
-	spin_unlock_bh(&stats->lock);
-}
-
-/*
- *	Update a destination in the given service
- */
-static void
-__ip_vs_update_dest(struct ip_vs_service *svc,
-		    struct ip_vs_dest *dest, struct ip_vs_dest_user *udest)
-{
-	int conn_flags;
-
-	/* set the weight and the flags */
-	atomic_set(&dest->weight, udest->weight);
-	conn_flags = udest->conn_flags | IP_VS_CONN_F_INACTIVE;
-
-	/* check if local node and update the flags */
-	if (inet_addr_type(&init_net, udest->addr) == RTN_LOCAL) {
-		conn_flags = (conn_flags & ~IP_VS_CONN_F_FWD_MASK)
-			| IP_VS_CONN_F_LOCALNODE;
-	}
-
-	/* set the IP_VS_CONN_F_NOOUTPUT flag if not masquerading/NAT */
-	if ((conn_flags & IP_VS_CONN_F_FWD_MASK) != 0) {
-		conn_flags |= IP_VS_CONN_F_NOOUTPUT;
-	} else {
-		/*
-		 *    Put the real service in ip_vs_rtable if not present.
-		 *    For now only for NAT!
-		 */
-		write_lock_bh(&__ip_vs_rs_lock);
-		ip_vs_rs_hash(dest);
-		write_unlock_bh(&__ip_vs_rs_lock);
-	}
-	atomic_set(&dest->conn_flags, conn_flags);
-
-	/* bind the service */
-	if (!dest->svc) {
-		__ip_vs_bind_svc(dest, svc);
-	} else {
-		if (dest->svc != svc) {
-			__ip_vs_unbind_svc(dest);
-			ip_vs_zero_stats(&dest->stats);
-			__ip_vs_bind_svc(dest, svc);
-		}
-	}
-
-	/* set the dest status flags */
-	dest->flags |= IP_VS_DEST_F_AVAILABLE;
-
-	if (udest->u_threshold == 0 || udest->u_threshold > dest->u_threshold)
-		dest->flags &= ~IP_VS_DEST_F_OVERLOAD;
-	dest->u_threshold = udest->u_threshold;
-	dest->l_threshold = udest->l_threshold;
-}
-
-
-/*
- *	Create a destination for the given service
- */
-static int
-ip_vs_new_dest(struct ip_vs_service *svc, struct ip_vs_dest_user *udest,
-	       struct ip_vs_dest **dest_p)
-{
-	struct ip_vs_dest *dest;
-	unsigned atype;
-
-	EnterFunction(2);
-
-	atype = inet_addr_type(&init_net, udest->addr);
-	if (atype != RTN_LOCAL && atype != RTN_UNICAST)
-		return -EINVAL;
-
-	dest = kzalloc(sizeof(struct ip_vs_dest), GFP_ATOMIC);
-	if (dest == NULL) {
-		IP_VS_ERR("ip_vs_new_dest: kmalloc failed.\n");
-		return -ENOMEM;
-	}
-
-	dest->protocol = svc->protocol;
-	dest->vaddr = svc->addr;
-	dest->vport = svc->port;
-	dest->vfwmark = svc->fwmark;
-	dest->addr = udest->addr;
-	dest->port = udest->port;
-
-	atomic_set(&dest->activeconns, 0);
-	atomic_set(&dest->inactconns, 0);
-	atomic_set(&dest->persistconns, 0);
-	atomic_set(&dest->refcnt, 0);
-
-	INIT_LIST_HEAD(&dest->d_list);
-	spin_lock_init(&dest->dst_lock);
-	spin_lock_init(&dest->stats.lock);
-	__ip_vs_update_dest(svc, dest, udest);
-	ip_vs_new_estimator(&dest->stats);
-
-	*dest_p = dest;
-
-	LeaveFunction(2);
-	return 0;
-}
-
-
-/*
- *	Add a destination into an existing service
- */
-static int
-ip_vs_add_dest(struct ip_vs_service *svc, struct ip_vs_dest_user *udest)
-{
-	struct ip_vs_dest *dest;
-	__be32 daddr = udest->addr;
-	__be16 dport = udest->port;
-	int ret;
-
-	EnterFunction(2);
-
-	if (udest->weight < 0) {
-		IP_VS_ERR("ip_vs_add_dest(): server weight less than zero\n");
-		return -ERANGE;
-	}
-
-	if (udest->l_threshold > udest->u_threshold) {
-		IP_VS_ERR("ip_vs_add_dest(): lower threshold is higher than "
-			  "upper threshold\n");
-		return -ERANGE;
-	}
-
-	/*
-	 * Check if the dest already exists in the list
-	 */
-	dest = ip_vs_lookup_dest(svc, daddr, dport);
-	if (dest != NULL) {
-		IP_VS_DBG(1, "ip_vs_add_dest(): dest already exists\n");
-		return -EEXIST;
-	}
-
-	/*
-	 * Check if the dest already exists in the trash and
-	 * is from the same service
-	 */
-	dest = ip_vs_trash_get_dest(svc, daddr, dport);
-	if (dest != NULL) {
-		IP_VS_DBG(3, "Get destination %u.%u.%u.%u:%u from trash, "
-			  "dest->refcnt=%d, service %u/%u.%u.%u.%u:%u\n",
-			  NIPQUAD(daddr), ntohs(dport),
-			  atomic_read(&dest->refcnt),
-			  dest->vfwmark,
-			  NIPQUAD(dest->vaddr),
-			  ntohs(dest->vport));
-		__ip_vs_update_dest(svc, dest, udest);
-
-		/*
-		 * Get the destination from the trash
-		 */
-		list_del(&dest->n_list);
-
-		ip_vs_new_estimator(&dest->stats);
-
-		write_lock_bh(&__ip_vs_svc_lock);
-
-		/*
-		 * Wait until all other svc users go away.
-		 */
-		IP_VS_WAIT_WHILE(atomic_read(&svc->usecnt) > 1);
-
-		list_add(&dest->n_list, &svc->destinations);
-		svc->num_dests++;
-
-		/* call the update_service function of its scheduler */
-		svc->scheduler->update_service(svc);
-
-		write_unlock_bh(&__ip_vs_svc_lock);
-		return 0;
-	}
-
-	/*
-	 * Allocate and initialize the dest structure
-	 */
-	ret = ip_vs_new_dest(svc, udest, &dest);
-	if (ret) {
-		return ret;
-	}
-
-	/*
-	 * Add the dest entry into the list
-	 */
-	atomic_inc(&dest->refcnt);
-
-	write_lock_bh(&__ip_vs_svc_lock);
-
-	/*
-	 * Wait until all other svc users go away.
-	 */
-	IP_VS_WAIT_WHILE(atomic_read(&svc->usecnt) > 1);
-
-	list_add(&dest->n_list, &svc->destinations);
-	svc->num_dests++;
-
-	/* call the update_service function of its scheduler */
-	svc->scheduler->update_service(svc);
-
-	write_unlock_bh(&__ip_vs_svc_lock);
-
-	LeaveFunction(2);
-
-	return 0;
-}
-
-
-/*
- *	Edit a destination in the given service
- */
-static int
-ip_vs_edit_dest(struct ip_vs_service *svc, struct ip_vs_dest_user *udest)
-{
-	struct ip_vs_dest *dest;
-	__be32 daddr = udest->addr;
-	__be16 dport = udest->port;
-
-	EnterFunction(2);
-
-	if (udest->weight < 0) {
-		IP_VS_ERR("ip_vs_edit_dest(): server weight less than zero\n");
-		return -ERANGE;
-	}
-
-	if (udest->l_threshold > udest->u_threshold) {
-		IP_VS_ERR("ip_vs_edit_dest(): lower threshold is higher than "
-			  "upper threshold\n");
-		return -ERANGE;
-	}
-
-	/*
-	 *  Lookup the destination list
-	 */
-	dest = ip_vs_lookup_dest(svc, daddr, dport);
-	if (dest == NULL) {
-		IP_VS_DBG(1, "ip_vs_edit_dest(): dest doesn't exist\n");
-		return -ENOENT;
-	}
-
-	__ip_vs_update_dest(svc, dest, udest);
-
-	write_lock_bh(&__ip_vs_svc_lock);
-
-	/* Wait until all other svc users go away */
-	IP_VS_WAIT_WHILE(atomic_read(&svc->usecnt) > 1);
-
-	/* call the update_service, because server weight may be changed */
-	svc->scheduler->update_service(svc);
-
-	write_unlock_bh(&__ip_vs_svc_lock);
-
-	LeaveFunction(2);
-
-	return 0;
-}
-
-
-/*
- *	Delete a destination (must be already unlinked from the service)
- */
-static void __ip_vs_del_dest(struct ip_vs_dest *dest)
-{
-	ip_vs_kill_estimator(&dest->stats);
-
-	/*
-	 *  Remove it from the d-linked list with the real services.
-	 */
-	write_lock_bh(&__ip_vs_rs_lock);
-	ip_vs_rs_unhash(dest);
-	write_unlock_bh(&__ip_vs_rs_lock);
-
-	/*
-	 *  Decrease the refcnt of the dest, and free the dest
-	 *  if nobody refers to it (refcnt=0). Otherwise, throw
-	 *  the destination into the trash.
-	 */
-	if (atomic_dec_and_test(&dest->refcnt)) {
-		ip_vs_dst_reset(dest);
-		/* simply decrease svc->refcnt here, let the caller check
-		   and release the service if nobody refers to it.
-		   Only user context can release destination and service,
-		   and only one user context can update virtual service at a
-		   time, so the operation here is OK */
-		atomic_dec(&dest->svc->refcnt);
-		kfree(dest);
-	} else {
-		IP_VS_DBG(3, "Moving dest %u.%u.%u.%u:%u into trash, "
-			  "dest->refcnt=%d\n",
-			  NIPQUAD(dest->addr), ntohs(dest->port),
-			  atomic_read(&dest->refcnt));
-		list_add(&dest->n_list, &ip_vs_dest_trash);
-		atomic_inc(&dest->refcnt);
-	}
-}
-
-
-/*
- *	Unlink a destination from the given service
- */
-static void __ip_vs_unlink_dest(struct ip_vs_service *svc,
-				struct ip_vs_dest *dest,
-				int svcupd)
-{
-	dest->flags &= ~IP_VS_DEST_F_AVAILABLE;
-
-	/*
-	 *  Remove it from the d-linked destination list.
-	 */
-	list_del(&dest->n_list);
-	svc->num_dests--;
-	if (svcupd) {
-		/*
-		 *  Call the update_service function of its scheduler
-		 */
-		svc->scheduler->update_service(svc);
-	}
-}
-
-
-/*
- *	Delete a destination server in the given service
- */
-static int
-ip_vs_del_dest(struct ip_vs_service *svc,struct ip_vs_dest_user *udest)
-{
-	struct ip_vs_dest *dest;
-	__be32 daddr = udest->addr;
-	__be16 dport = udest->port;
-
-	EnterFunction(2);
-
-	dest = ip_vs_lookup_dest(svc, daddr, dport);
-	if (dest == NULL) {
-		IP_VS_DBG(1, "ip_vs_del_dest(): destination not found!\n");
-		return -ENOENT;
-	}
-
-	write_lock_bh(&__ip_vs_svc_lock);
-
-	/*
-	 *	Wait until all other svc users go away.
-	 */
-	IP_VS_WAIT_WHILE(atomic_read(&svc->usecnt) > 1);
-
-	/*
-	 *	Unlink dest from the service
-	 */
-	__ip_vs_unlink_dest(svc, dest, 1);
-
-	write_unlock_bh(&__ip_vs_svc_lock);
-
-	/*
-	 *	Delete the destination
-	 */
-	__ip_vs_del_dest(dest);
-
-	LeaveFunction(2);
-
-	return 0;
-}
-
-
-/*
- *	Add a service into the service hash table
- */
-static int
-ip_vs_add_service(struct ip_vs_service_user *u, struct ip_vs_service **svc_p)
-{
-	int ret = 0;
-	struct ip_vs_scheduler *sched = NULL;
-	struct ip_vs_service *svc = NULL;
-
-	/* increase the module use count */
-	ip_vs_use_count_inc();
-
-	/* Lookup the scheduler by 'u->sched_name' */
-	sched = ip_vs_scheduler_get(u->sched_name);
-	if (sched == NULL) {
-		IP_VS_INFO("Scheduler module ip_vs_%s not found\n",
-			   u->sched_name);
-		ret = -ENOENT;
-		goto out_mod_dec;
-	}
-
-	svc = kzalloc(sizeof(struct ip_vs_service), GFP_ATOMIC);
-	if (svc == NULL) {
-		IP_VS_DBG(1, "ip_vs_add_service: kmalloc failed.\n");
-		ret = -ENOMEM;
-		goto out_err;
-	}
-
-	/* I'm the first user of the service */
-	atomic_set(&svc->usecnt, 1);
-	atomic_set(&svc->refcnt, 0);
-
-	svc->protocol = u->protocol;
-	svc->addr = u->addr;
-	svc->port = u->port;
-	svc->fwmark = u->fwmark;
-	svc->flags = u->flags;
-	svc->timeout = u->timeout * HZ;
-	svc->netmask = u->netmask;
-
-	INIT_LIST_HEAD(&svc->destinations);
-	rwlock_init(&svc->sched_lock);
-	spin_lock_init(&svc->stats.lock);
-
-	/* Bind the scheduler */
-	ret = ip_vs_bind_scheduler(svc, sched);
-	if (ret)
-		goto out_err;
-	sched = NULL;
-
-	/* Update the virtual service counters */
-	if (svc->port == FTPPORT)
-		atomic_inc(&ip_vs_ftpsvc_counter);
-	else if (svc->port == 0)
-		atomic_inc(&ip_vs_nullsvc_counter);
-
-	ip_vs_new_estimator(&svc->stats);
-	ip_vs_num_services++;
-
-	/* Hash the service into the service table */
-	write_lock_bh(&__ip_vs_svc_lock);
-	ip_vs_svc_hash(svc);
-	write_unlock_bh(&__ip_vs_svc_lock);
-
-	*svc_p = svc;
-	return 0;
-
-  out_err:
-	if (svc != NULL) {
-		if (svc->scheduler)
-			ip_vs_unbind_scheduler(svc);
-		if (svc->inc) {
-			local_bh_disable();
-			ip_vs_app_inc_put(svc->inc);
-			local_bh_enable();
-		}
-		kfree(svc);
-	}
-	ip_vs_scheduler_put(sched);
-
-  out_mod_dec:
-	/* decrease the module use count */
-	ip_vs_use_count_dec();
-
-	return ret;
-}
-
-
-/*
- *	Edit a service and bind it with a new scheduler
- */
-static int
-ip_vs_edit_service(struct ip_vs_service *svc, struct ip_vs_service_user *u)
-{
-	struct ip_vs_scheduler *sched, *old_sched;
-	int ret = 0;
-
-	/*
-	 * Lookup the scheduler, by 'u->sched_name'
-	 */
-	sched = ip_vs_scheduler_get(u->sched_name);
-	if (sched == NULL) {
-		IP_VS_INFO("Scheduler module ip_vs_%s not found\n",
-			   u->sched_name);
-		return -ENOENT;
-	}
-	old_sched = sched;
-
-	write_lock_bh(&__ip_vs_svc_lock);
-
-	/*
-	 * Wait until all other svc users go away.
-	 */
-	IP_VS_WAIT_WHILE(atomic_read(&svc->usecnt) > 1);
-
-	/*
-	 * Set the flags and timeout value
-	 */
-	svc->flags = u->flags | IP_VS_SVC_F_HASHED;
-	svc->timeout = u->timeout * HZ;
-	svc->netmask = u->netmask;
-
-	old_sched = svc->scheduler;
-	if (sched != old_sched) {
-		/*
-		 * Unbind the old scheduler
-		 */
-		if ((ret = ip_vs_unbind_scheduler(svc))) {
-			old_sched = sched;
-			goto out;
-		}
-
-		/*
-		 * Bind the new scheduler
-		 */
-		if ((ret = ip_vs_bind_scheduler(svc, sched))) {
-			/*
-			 * If ip_vs_bind_scheduler fails, restore the old
-			 * scheduler.
-			 * The main reason of failure is out of memory.
-			 *
-			 * The question is if the old scheduler can be
-			 * restored all the time. TODO: if it cannot be
-			 * restored some time, we must delete the service,
-			 * otherwise the system may crash.
-			 */
-			ip_vs_bind_scheduler(svc, old_sched);
-			old_sched = sched;
-			goto out;
-		}
-	}
-
-  out:
-	write_unlock_bh(&__ip_vs_svc_lock);
-
-	if (old_sched)
-		ip_vs_scheduler_put(old_sched);
-
-	return ret;
-}
-
-
-/*
- *	Delete a service from the service list
- *	- The service must be unlinked, unlocked and not referenced!
- *	- We are called under _bh lock
- */
-static void __ip_vs_del_service(struct ip_vs_service *svc)
-{
-	struct ip_vs_dest *dest, *nxt;
-	struct ip_vs_scheduler *old_sched;
-
-	ip_vs_num_services--;
-	ip_vs_kill_estimator(&svc->stats);
-
-	/* Unbind scheduler */
-	old_sched = svc->scheduler;
-	ip_vs_unbind_scheduler(svc);
-	if (old_sched)
-		ip_vs_scheduler_put(old_sched);
-
-	/* Unbind app inc */
-	if (svc->inc) {
-		ip_vs_app_inc_put(svc->inc);
-		svc->inc = NULL;
-	}
-
-	/*
-	 *    Unlink the whole destination list
-	 */
-	list_for_each_entry_safe(dest, nxt, &svc->destinations, n_list) {
-		__ip_vs_unlink_dest(svc, dest, 0);
-		__ip_vs_del_dest(dest);
-	}
-
-	/*
-	 *    Update the virtual service counters
-	 */
-	if (svc->port == FTPPORT)
-		atomic_dec(&ip_vs_ftpsvc_counter);
-	else if (svc->port == 0)
-		atomic_dec(&ip_vs_nullsvc_counter);
-
-	/*
-	 *    Free the service if nobody refers to it
-	 */
-	if (atomic_read(&svc->refcnt) == 0)
-		kfree(svc);
-
-	/* decrease the module use count */
-	ip_vs_use_count_dec();
-}
-
-/*
- *	Delete a service from the service list
- */
-static int ip_vs_del_service(struct ip_vs_service *svc)
-{
-	if (svc == NULL)
-		return -EEXIST;
-
-	/*
-	 * Unhash it from the service table
-	 */
-	write_lock_bh(&__ip_vs_svc_lock);
-
-	ip_vs_svc_unhash(svc);
-
-	/*
-	 * Wait until all the svc users go away.
-	 */
-	IP_VS_WAIT_WHILE(atomic_read(&svc->usecnt) > 1);
-
-	__ip_vs_del_service(svc);
-
-	write_unlock_bh(&__ip_vs_svc_lock);
-
-	return 0;
-}
-
-
-/*
- *	Flush all the virtual services
- */
-static int ip_vs_flush(void)
-{
-	int idx;
-	struct ip_vs_service *svc, *nxt;
-
-	/*
-	 * Flush the service table hashed by <protocol,addr,port>
-	 */
-	for(idx = 0; idx < IP_VS_SVC_TAB_SIZE; idx++) {
-		list_for_each_entry_safe(svc, nxt, &ip_vs_svc_table[idx], s_list) {
-			write_lock_bh(&__ip_vs_svc_lock);
-			ip_vs_svc_unhash(svc);
-			/*
-			 * Wait until all the svc users go away.
-			 */
-			IP_VS_WAIT_WHILE(atomic_read(&svc->usecnt) > 0);
-			__ip_vs_del_service(svc);
-			write_unlock_bh(&__ip_vs_svc_lock);
-		}
-	}
-
-	/*
-	 * Flush the service table hashed by fwmark
-	 */
-	for(idx = 0; idx < IP_VS_SVC_TAB_SIZE; idx++) {
-		list_for_each_entry_safe(svc, nxt,
-					 &ip_vs_svc_fwm_table[idx], f_list) {
-			write_lock_bh(&__ip_vs_svc_lock);
-			ip_vs_svc_unhash(svc);
-			/*
-			 * Wait until all the svc users go away.
-			 */
-			IP_VS_WAIT_WHILE(atomic_read(&svc->usecnt) > 0);
-			__ip_vs_del_service(svc);
-			write_unlock_bh(&__ip_vs_svc_lock);
-		}
-	}
-
-	return 0;
-}
-
-
-/*
- *	Zero counters in a service or all services
- */
-static int ip_vs_zero_service(struct ip_vs_service *svc)
-{
-	struct ip_vs_dest *dest;
-
-	write_lock_bh(&__ip_vs_svc_lock);
-	list_for_each_entry(dest, &svc->destinations, n_list) {
-		ip_vs_zero_stats(&dest->stats);
-	}
-	ip_vs_zero_stats(&svc->stats);
-	write_unlock_bh(&__ip_vs_svc_lock);
-	return 0;
-}
-
-static int ip_vs_zero_all(void)
-{
-	int idx;
-	struct ip_vs_service *svc;
-
-	for(idx = 0; idx < IP_VS_SVC_TAB_SIZE; idx++) {
-		list_for_each_entry(svc, &ip_vs_svc_table[idx], s_list) {
-			ip_vs_zero_service(svc);
-		}
-	}
-
-	for(idx = 0; idx < IP_VS_SVC_TAB_SIZE; idx++) {
-		list_for_each_entry(svc, &ip_vs_svc_fwm_table[idx], f_list) {
-			ip_vs_zero_service(svc);
-		}
-	}
-
-	ip_vs_zero_stats(&ip_vs_stats);
-	return 0;
-}
-
-
-static int
-proc_do_defense_mode(ctl_table *table, int write, struct file * filp,
-		     void __user *buffer, size_t *lenp, loff_t *ppos)
-{
-	int *valp = table->data;
-	int val = *valp;
-	int rc;
-
-	rc = proc_dointvec(table, write, filp, buffer, lenp, ppos);
-	if (write && (*valp != val)) {
-		if ((*valp < 0) || (*valp > 3)) {
-			/* Restore the correct value */
-			*valp = val;
-		} else {
-			update_defense_level();
-		}
-	}
-	return rc;
-}
-
-
-static int
-proc_do_sync_threshold(ctl_table *table, int write, struct file *filp,
-		       void __user *buffer, size_t *lenp, loff_t *ppos)
-{
-	int *valp = table->data;
-	int val[2];
-	int rc;
-
-	/* backup the value first */
-	memcpy(val, valp, sizeof(val));
-
-	rc = proc_dointvec(table, write, filp, buffer, lenp, ppos);
-	if (write && (valp[0] < 0 || valp[1] < 0 || valp[0] >= valp[1])) {
-		/* Restore the correct value */
-		memcpy(valp, val, sizeof(val));
-	}
-	return rc;
-}
-
-
-/*
- *	IPVS sysctl table (under the /proc/sys/net/ipv4/vs/)
- */
-
-static struct ctl_table vs_vars[] = {
-	{
-		.procname	= "amemthresh",
-		.data		= &sysctl_ip_vs_amemthresh,
-		.maxlen		= sizeof(int),
-		.mode		= 0644,
-		.proc_handler	= &proc_dointvec,
-	},
-#ifdef CONFIG_IP_VS_DEBUG
-	{
-		.procname	= "debug_level",
-		.data		= &sysctl_ip_vs_debug_level,
-		.maxlen		= sizeof(int),
-		.mode		= 0644,
-		.proc_handler	= &proc_dointvec,
-	},
-#endif
-	{
-		.procname	= "am_droprate",
-		.data		= &sysctl_ip_vs_am_droprate,
-		.maxlen		= sizeof(int),
-		.mode		= 0644,
-		.proc_handler	= &proc_dointvec,
-	},
-	{
-		.procname	= "drop_entry",
-		.data		= &sysctl_ip_vs_drop_entry,
-		.maxlen		= sizeof(int),
-		.mode		= 0644,
-		.proc_handler	= &proc_do_defense_mode,
-	},
-	{
-		.procname	= "drop_packet",
-		.data		= &sysctl_ip_vs_drop_packet,
-		.maxlen		= sizeof(int),
-		.mode		= 0644,
-		.proc_handler	= &proc_do_defense_mode,
-	},
-	{
-		.procname	= "secure_tcp",
-		.data		= &sysctl_ip_vs_secure_tcp,
-		.maxlen		= sizeof(int),
-		.mode		= 0644,
-		.proc_handler	= &proc_do_defense_mode,
-	},
-#if 0
-	{
-		.procname	= "timeout_established",
-		.data	= &vs_timeout_table_dos.timeout[IP_VS_S_ESTABLISHED],
-		.maxlen		= sizeof(int),
-		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_jiffies,
-	},
-	{
-		.procname	= "timeout_synsent",
-		.data	= &vs_timeout_table_dos.timeout[IP_VS_S_SYN_SENT],
-		.maxlen		= sizeof(int),
-		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_jiffies,
-	},
-	{
-		.procname	= "timeout_synrecv",
-		.data	= &vs_timeout_table_dos.timeout[IP_VS_S_SYN_RECV],
-		.maxlen		= sizeof(int),
-		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_jiffies,
-	},
-	{
-		.procname	= "timeout_finwait",
-		.data	= &vs_timeout_table_dos.timeout[IP_VS_S_FIN_WAIT],
-		.maxlen		= sizeof(int),
-		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_jiffies,
-	},
-	{
-		.procname	= "timeout_timewait",
-		.data	= &vs_timeout_table_dos.timeout[IP_VS_S_TIME_WAIT],
-		.maxlen		= sizeof(int),
-		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_jiffies,
-	},
-	{
-		.procname	= "timeout_close",
-		.data	= &vs_timeout_table_dos.timeout[IP_VS_S_CLOSE],
-		.maxlen		= sizeof(int),
-		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_jiffies,
-	},
-	{
-		.procname	= "timeout_closewait",
-		.data	= &vs_timeout_table_dos.timeout[IP_VS_S_CLOSE_WAIT],
-		.maxlen		= sizeof(int),
-		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_jiffies,
-	},
-	{
-		.procname	= "timeout_lastack",
-		.data	= &vs_timeout_table_dos.timeout[IP_VS_S_LAST_ACK],
-		.maxlen		= sizeof(int),
-		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_jiffies,
-	},
-	{
-		.procname	= "timeout_listen",
-		.data	= &vs_timeout_table_dos.timeout[IP_VS_S_LISTEN],
-		.maxlen		= sizeof(int),
-		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_jiffies,
-	},
-	{
-		.procname	= "timeout_synack",
-		.data	= &vs_timeout_table_dos.timeout[IP_VS_S_SYNACK],
-		.maxlen		= sizeof(int),
-		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_jiffies,
-	},
-	{
-		.procname	= "timeout_udp",
-		.data	= &vs_timeout_table_dos.timeout[IP_VS_S_UDP],
-		.maxlen		= sizeof(int),
-		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_jiffies,
-	},
-	{
-		.procname	= "timeout_icmp",
-		.data	= &vs_timeout_table_dos.timeout[IP_VS_S_ICMP],
-		.maxlen		= sizeof(int),
-		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_jiffies,
-	},
-#endif
-	{
-		.procname	= "cache_bypass",
-		.data		= &sysctl_ip_vs_cache_bypass,
-		.maxlen		= sizeof(int),
-		.mode		= 0644,
-		.proc_handler	= &proc_dointvec,
-	},
-	{
-		.procname	= "expire_nodest_conn",
-		.data		= &sysctl_ip_vs_expire_nodest_conn,
-		.maxlen		= sizeof(int),
-		.mode		= 0644,
-		.proc_handler	= &proc_dointvec,
-	},
-	{
-		.procname	= "expire_quiescent_template",
-		.data		= &sysctl_ip_vs_expire_quiescent_template,
-		.maxlen		= sizeof(int),
-		.mode		= 0644,
-		.proc_handler	= &proc_dointvec,
-	},
-	{
-		.procname	= "sync_threshold",
-		.data		= &sysctl_ip_vs_sync_threshold,
-		.maxlen		= sizeof(sysctl_ip_vs_sync_threshold),
-		.mode		= 0644,
-		.proc_handler	= &proc_do_sync_threshold,
-	},
-	{
-		.procname	= "nat_icmp_send",
-		.data		= &sysctl_ip_vs_nat_icmp_send,
-		.maxlen		= sizeof(int),
-		.mode		= 0644,
-		.proc_handler	= &proc_dointvec,
-	},
-	{ .ctl_name = 0 }
-};
-
-const struct ctl_path net_vs_ctl_path[] = {
-	{ .procname = "net", .ctl_name = CTL_NET, },
-	{ .procname = "ipv4", .ctl_name = NET_IPV4, },
-	{ .procname = "vs", },
-	{ }
-};
-EXPORT_SYMBOL_GPL(net_vs_ctl_path);
-
-static struct ctl_table_header * sysctl_header;
-
-#ifdef CONFIG_PROC_FS
-
-struct ip_vs_iter {
-	struct list_head *table;
-	int bucket;
-};
-
-/*
- *	Write the contents of the VS rule table to a PROCfs file.
- *	(It is kept just for backward compatibility)
- */
-static inline const char *ip_vs_fwd_name(unsigned flags)
-{
-	switch (flags & IP_VS_CONN_F_FWD_MASK) {
-	case IP_VS_CONN_F_LOCALNODE:
-		return "Local";
-	case IP_VS_CONN_F_TUNNEL:
-		return "Tunnel";
-	case IP_VS_CONN_F_DROUTE:
-		return "Route";
-	default:
-		return "Masq";
-	}
-}
-
-
-/* Get the Nth entry in the two lists */
-static struct ip_vs_service *ip_vs_info_array(struct seq_file *seq, loff_t pos)
-{
-	struct ip_vs_iter *iter = seq->private;
-	int idx;
-	struct ip_vs_service *svc;
-
-	/* look in hash by protocol */
-	for (idx = 0; idx < IP_VS_SVC_TAB_SIZE; idx++) {
-		list_for_each_entry(svc, &ip_vs_svc_table[idx], s_list) {
-			if (pos-- == 0){
-				iter->table = ip_vs_svc_table;
-				iter->bucket = idx;
-				return svc;
-			}
-		}
-	}
-
-	/* keep looking in fwmark */
-	for (idx = 0; idx < IP_VS_SVC_TAB_SIZE; idx++) {
-		list_for_each_entry(svc, &ip_vs_svc_fwm_table[idx], f_list) {
-			if (pos-- == 0) {
-				iter->table = ip_vs_svc_fwm_table;
-				iter->bucket = idx;
-				return svc;
-			}
-		}
-	}
-
-	return NULL;
-}
-
-static void *ip_vs_info_seq_start(struct seq_file *seq, loff_t *pos)
-{
-
-	read_lock_bh(&__ip_vs_svc_lock);
-	return *pos ? ip_vs_info_array(seq, *pos - 1) : SEQ_START_TOKEN;
-}
-
-
-static void *ip_vs_info_seq_next(struct seq_file *seq, void *v, loff_t *pos)
-{
-	struct list_head *e;
-	struct ip_vs_iter *iter;
-	struct ip_vs_service *svc;
-
-	++*pos;
-	if (v == SEQ_START_TOKEN)
-		return ip_vs_info_array(seq,0);
-
-	svc = v;
-	iter = seq->private;
-
-	if (iter->table == ip_vs_svc_table) {
-		/* next service in table hashed by protocol */
-		if ((e = svc->s_list.next) != &ip_vs_svc_table[iter->bucket])
-			return list_entry(e, struct ip_vs_service, s_list);
-
-
-		while (++iter->bucket < IP_VS_SVC_TAB_SIZE) {
-			list_for_each_entry(svc,&ip_vs_svc_table[iter->bucket],
-					    s_list) {
-				return svc;
-			}
-		}
-
-		iter->table = ip_vs_svc_fwm_table;
-		iter->bucket = -1;
-		goto scan_fwmark;
-	}
-
-	/* next service in hashed by fwmark */
-	if ((e = svc->f_list.next) != &ip_vs_svc_fwm_table[iter->bucket])
-		return list_entry(e, struct ip_vs_service, f_list);
-
- scan_fwmark:
-	while (++iter->bucket < IP_VS_SVC_TAB_SIZE) {
-		list_for_each_entry(svc, &ip_vs_svc_fwm_table[iter->bucket],
-				    f_list)
-			return svc;
-	}
-
-	return NULL;
-}
-
-static void ip_vs_info_seq_stop(struct seq_file *seq, void *v)
-{
-	read_unlock_bh(&__ip_vs_svc_lock);
-}
-
-
-static int ip_vs_info_seq_show(struct seq_file *seq, void *v)
-{
-	if (v == SEQ_START_TOKEN) {
-		seq_printf(seq,
-			"IP Virtual Server version %d.%d.%d (size=%d)\n",
-			NVERSION(IP_VS_VERSION_CODE), IP_VS_CONN_TAB_SIZE);
-		seq_puts(seq,
-			 "Prot LocalAddress:Port Scheduler Flags\n");
-		seq_puts(seq,
-			 "  -> RemoteAddress:Port Forward Weight ActiveConn InActConn\n");
-	} else {
-		const struct ip_vs_service *svc = v;
-		const struct ip_vs_iter *iter = seq->private;
-		const struct ip_vs_dest *dest;
-
-		if (iter->table == ip_vs_svc_table)
-			seq_printf(seq, "%s  %08X:%04X %s ",
-				   ip_vs_proto_name(svc->protocol),
-				   ntohl(svc->addr),
-				   ntohs(svc->port),
-				   svc->scheduler->name);
-		else
-			seq_printf(seq, "FWM  %08X %s ",
-				   svc->fwmark, svc->scheduler->name);
-
-		if (svc->flags & IP_VS_SVC_F_PERSISTENT)
-			seq_printf(seq, "persistent %d %08X\n",
-				svc->timeout,
-				ntohl(svc->netmask));
-		else
-			seq_putc(seq, '\n');
-
-		list_for_each_entry(dest, &svc->destinations, n_list) {
-			seq_printf(seq,
-				   "  -> %08X:%04X      %-7s %-6d %-10d %-10d\n",
-				   ntohl(dest->addr), ntohs(dest->port),
-				   ip_vs_fwd_name(atomic_read(&dest->conn_flags)),
-				   atomic_read(&dest->weight),
-				   atomic_read(&dest->activeconns),
-				   atomic_read(&dest->inactconns));
-		}
-	}
-	return 0;
-}
-
-static const struct seq_operations ip_vs_info_seq_ops = {
-	.start = ip_vs_info_seq_start,
-	.next  = ip_vs_info_seq_next,
-	.stop  = ip_vs_info_seq_stop,
-	.show  = ip_vs_info_seq_show,
-};
-
-static int ip_vs_info_open(struct inode *inode, struct file *file)
-{
-	return seq_open_private(file, &ip_vs_info_seq_ops,
-			sizeof(struct ip_vs_iter));
-}
-
-static const struct file_operations ip_vs_info_fops = {
-	.owner	 = THIS_MODULE,
-	.open    = ip_vs_info_open,
-	.read    = seq_read,
-	.llseek  = seq_lseek,
-	.release = seq_release_private,
-};
-
-#endif
-
-struct ip_vs_stats ip_vs_stats = {
-	.lock = __SPIN_LOCK_UNLOCKED(ip_vs_stats.lock),
-};
-
-#ifdef CONFIG_PROC_FS
-static int ip_vs_stats_show(struct seq_file *seq, void *v)
-{
-
-/*               01234567 01234567 01234567 0123456701234567 0123456701234567 */
-	seq_puts(seq,
-		 "   Total Incoming Outgoing         Incoming         Outgoing\n");
-	seq_printf(seq,
-		   "   Conns  Packets  Packets            Bytes            Bytes\n");
-
-	spin_lock_bh(&ip_vs_stats.lock);
-	seq_printf(seq, "%8X %8X %8X %16LX %16LX\n\n", ip_vs_stats.conns,
-		   ip_vs_stats.inpkts, ip_vs_stats.outpkts,
-		   (unsigned long long) ip_vs_stats.inbytes,
-		   (unsigned long long) ip_vs_stats.outbytes);
-
-/*                 01234567 01234567 01234567 0123456701234567 0123456701234567 */
-	seq_puts(seq,
-		   " Conns/s   Pkts/s   Pkts/s          Bytes/s          Bytes/s\n");
-	seq_printf(seq,"%8X %8X %8X %16X %16X\n",
-			ip_vs_stats.cps,
-			ip_vs_stats.inpps,
-			ip_vs_stats.outpps,
-			ip_vs_stats.inbps,
-			ip_vs_stats.outbps);
-	spin_unlock_bh(&ip_vs_stats.lock);
-
-	return 0;
-}
-
-static int ip_vs_stats_seq_open(struct inode *inode, struct file *file)
-{
-	return single_open(file, ip_vs_stats_show, NULL);
-}
-
-static const struct file_operations ip_vs_stats_fops = {
-	.owner = THIS_MODULE,
-	.open = ip_vs_stats_seq_open,
-	.read = seq_read,
-	.llseek = seq_lseek,
-	.release = single_release,
-};
-
-#endif
-
-/*
- *	Set timeout values for tcp tcpfin udp in the timeout_table.
- */
-static int ip_vs_set_timeout(struct ip_vs_timeout_user *u)
-{
-	IP_VS_DBG(2, "Setting timeout tcp:%d tcpfin:%d udp:%d\n",
-		  u->tcp_timeout,
-		  u->tcp_fin_timeout,
-		  u->udp_timeout);
-
-#ifdef CONFIG_IP_VS_PROTO_TCP
-	if (u->tcp_timeout) {
-		ip_vs_protocol_tcp.timeout_table[IP_VS_TCP_S_ESTABLISHED]
-			= u->tcp_timeout * HZ;
-	}
-
-	if (u->tcp_fin_timeout) {
-		ip_vs_protocol_tcp.timeout_table[IP_VS_TCP_S_FIN_WAIT]
-			= u->tcp_fin_timeout * HZ;
-	}
-#endif
-
-#ifdef CONFIG_IP_VS_PROTO_UDP
-	if (u->udp_timeout) {
-		ip_vs_protocol_udp.timeout_table[IP_VS_UDP_S_NORMAL]
-			= u->udp_timeout * HZ;
-	}
-#endif
-	return 0;
-}
-
-
-#define SET_CMDID(cmd)		(cmd - IP_VS_BASE_CTL)
-#define SERVICE_ARG_LEN		(sizeof(struct ip_vs_service_user))
-#define SVCDEST_ARG_LEN		(sizeof(struct ip_vs_service_user) +	\
-				 sizeof(struct ip_vs_dest_user))
-#define TIMEOUT_ARG_LEN		(sizeof(struct ip_vs_timeout_user))
-#define DAEMON_ARG_LEN		(sizeof(struct ip_vs_daemon_user))
-#define MAX_ARG_LEN		SVCDEST_ARG_LEN
-
-static const unsigned char set_arglen[SET_CMDID(IP_VS_SO_SET_MAX)+1] = {
-	[SET_CMDID(IP_VS_SO_SET_ADD)]		= SERVICE_ARG_LEN,
-	[SET_CMDID(IP_VS_SO_SET_EDIT)]		= SERVICE_ARG_LEN,
-	[SET_CMDID(IP_VS_SO_SET_DEL)]		= SERVICE_ARG_LEN,
-	[SET_CMDID(IP_VS_SO_SET_FLUSH)]		= 0,
-	[SET_CMDID(IP_VS_SO_SET_ADDDEST)]	= SVCDEST_ARG_LEN,
-	[SET_CMDID(IP_VS_SO_SET_DELDEST)]	= SVCDEST_ARG_LEN,
-	[SET_CMDID(IP_VS_SO_SET_EDITDEST)]	= SVCDEST_ARG_LEN,
-	[SET_CMDID(IP_VS_SO_SET_TIMEOUT)]	= TIMEOUT_ARG_LEN,
-	[SET_CMDID(IP_VS_SO_SET_STARTDAEMON)]	= DAEMON_ARG_LEN,
-	[SET_CMDID(IP_VS_SO_SET_STOPDAEMON)]	= DAEMON_ARG_LEN,
-	[SET_CMDID(IP_VS_SO_SET_ZERO)]		= SERVICE_ARG_LEN,
-};
-
-static int
-do_ip_vs_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
-{
-	int ret;
-	unsigned char arg[MAX_ARG_LEN];
-	struct ip_vs_service_user *usvc;
-	struct ip_vs_service *svc;
-	struct ip_vs_dest_user *udest;
-
-	if (!capable(CAP_NET_ADMIN))
-		return -EPERM;
-
-	if (len != set_arglen[SET_CMDID(cmd)]) {
-		IP_VS_ERR("set_ctl: len %u != %u\n",
-			  len, set_arglen[SET_CMDID(cmd)]);
-		return -EINVAL;
-	}
-
-	if (copy_from_user(arg, user, len) != 0)
-		return -EFAULT;
-
-	/* increase the module use count */
-	ip_vs_use_count_inc();
-
-	if (mutex_lock_interruptible(&__ip_vs_mutex)) {
-		ret = -ERESTARTSYS;
-		goto out_dec;
-	}
-
-	if (cmd == IP_VS_SO_SET_FLUSH) {
-		/* Flush the virtual service */
-		ret = ip_vs_flush();
-		goto out_unlock;
-	} else if (cmd == IP_VS_SO_SET_TIMEOUT) {
-		/* Set timeout values for (tcp tcpfin udp) */
-		ret = ip_vs_set_timeout((struct ip_vs_timeout_user *)arg);
-		goto out_unlock;
-	} else if (cmd == IP_VS_SO_SET_STARTDAEMON) {
-		struct ip_vs_daemon_user *dm = (struct ip_vs_daemon_user *)arg;
-		ret = start_sync_thread(dm->state, dm->mcast_ifn, dm->syncid);
-		goto out_unlock;
-	} else if (cmd == IP_VS_SO_SET_STOPDAEMON) {
-		struct ip_vs_daemon_user *dm = (struct ip_vs_daemon_user *)arg;
-		ret = stop_sync_thread(dm->state);
-		goto out_unlock;
-	}
-
-	usvc = (struct ip_vs_service_user *)arg;
-	udest = (struct ip_vs_dest_user *)(usvc + 1);
-
-	if (cmd == IP_VS_SO_SET_ZERO) {
-		/* if no service address is set, zero counters in all */
-		if (!usvc->fwmark && !usvc->addr && !usvc->port) {
-			ret = ip_vs_zero_all();
-			goto out_unlock;
-		}
-	}
-
-	/* Check for valid protocol: TCP or UDP, even for fwmark!=0 */
-	if (usvc->protocol!=IPPROTO_TCP && usvc->protocol!=IPPROTO_UDP) {
-		IP_VS_ERR("set_ctl: invalid protocol: %d %d.%d.%d.%d:%d %s\n",
-			  usvc->protocol, NIPQUAD(usvc->addr),
-			  ntohs(usvc->port), usvc->sched_name);
-		ret = -EFAULT;
-		goto out_unlock;
-	}
-
-	/* Lookup the exact service by <protocol, addr, port> or fwmark */
-	if (usvc->fwmark == 0)
-		svc = __ip_vs_service_get(usvc->protocol,
-					  usvc->addr, usvc->port);
-	else
-		svc = __ip_vs_svc_fwm_get(usvc->fwmark);
-
-	if (cmd != IP_VS_SO_SET_ADD
-	    && (svc == NULL || svc->protocol != usvc->protocol)) {
-		ret = -ESRCH;
-		goto out_unlock;
-	}
-
-	switch (cmd) {
-	case IP_VS_SO_SET_ADD:
-		if (svc != NULL)
-			ret = -EEXIST;
-		else
-			ret = ip_vs_add_service(usvc, &svc);
-		break;
-	case IP_VS_SO_SET_EDIT:
-		ret = ip_vs_edit_service(svc, usvc);
-		break;
-	case IP_VS_SO_SET_DEL:
-		ret = ip_vs_del_service(svc);
-		if (!ret)
-			goto out_unlock;
-		break;
-	case IP_VS_SO_SET_ZERO:
-		ret = ip_vs_zero_service(svc);
-		break;
-	case IP_VS_SO_SET_ADDDEST:
-		ret = ip_vs_add_dest(svc, udest);
-		break;
-	case IP_VS_SO_SET_EDITDEST:
-		ret = ip_vs_edit_dest(svc, udest);
-		break;
-	case IP_VS_SO_SET_DELDEST:
-		ret = ip_vs_del_dest(svc, udest);
-		break;
-	default:
-		ret = -EINVAL;
-	}
-
-	if (svc)
-		ip_vs_service_put(svc);
-
-  out_unlock:
-	mutex_unlock(&__ip_vs_mutex);
-  out_dec:
-	/* decrease the module use count */
-	ip_vs_use_count_dec();
-
-	return ret;
-}
-
-
-static void
-ip_vs_copy_stats(struct ip_vs_stats_user *dst, struct ip_vs_stats *src)
-{
-	spin_lock_bh(&src->lock);
-	memcpy(dst, src, (char*)&src->lock - (char*)src);
-	spin_unlock_bh(&src->lock);
-}
-
-static void
-ip_vs_copy_service(struct ip_vs_service_entry *dst, struct ip_vs_service *src)
-{
-	dst->protocol = src->protocol;
-	dst->addr = src->addr;
-	dst->port = src->port;
-	dst->fwmark = src->fwmark;
-	strlcpy(dst->sched_name, src->scheduler->name, sizeof(dst->sched_name));
-	dst->flags = src->flags;
-	dst->timeout = src->timeout / HZ;
-	dst->netmask = src->netmask;
-	dst->num_dests = src->num_dests;
-	ip_vs_copy_stats(&dst->stats, &src->stats);
-}
-
-static inline int
-__ip_vs_get_service_entries(const struct ip_vs_get_services *get,
-			    struct ip_vs_get_services __user *uptr)
-{
-	int idx, count=0;
-	struct ip_vs_service *svc;
-	struct ip_vs_service_entry entry;
-	int ret = 0;
-
-	for (idx = 0; idx < IP_VS_SVC_TAB_SIZE; idx++) {
-		list_for_each_entry(svc, &ip_vs_svc_table[idx], s_list) {
-			if (count >= get->num_services)
-				goto out;
-			memset(&entry, 0, sizeof(entry));
-			ip_vs_copy_service(&entry, svc);
-			if (copy_to_user(&uptr->entrytable[count],
-					 &entry, sizeof(entry))) {
-				ret = -EFAULT;
-				goto out;
-			}
-			count++;
-		}
-	}
-
-	for (idx = 0; idx < IP_VS_SVC_TAB_SIZE; idx++) {
-		list_for_each_entry(svc, &ip_vs_svc_fwm_table[idx], f_list) {
-			if (count >= get->num_services)
-				goto out;
-			memset(&entry, 0, sizeof(entry));
-			ip_vs_copy_service(&entry, svc);
-			if (copy_to_user(&uptr->entrytable[count],
-					 &entry, sizeof(entry))) {
-				ret = -EFAULT;
-				goto out;
-			}
-			count++;
-		}
-	}
-  out:
-	return ret;
-}
-
-static inline int
-__ip_vs_get_dest_entries(const struct ip_vs_get_dests *get,
-			 struct ip_vs_get_dests __user *uptr)
-{
-	struct ip_vs_service *svc;
-	int ret = 0;
-
-	if (get->fwmark)
-		svc = __ip_vs_svc_fwm_get(get->fwmark);
-	else
-		svc = __ip_vs_service_get(get->protocol,
-					  get->addr, get->port);
-	if (svc) {
-		int count = 0;
-		struct ip_vs_dest *dest;
-		struct ip_vs_dest_entry entry;
-
-		list_for_each_entry(dest, &svc->destinations, n_list) {
-			if (count >= get->num_dests)
-				break;
-
-			entry.addr = dest->addr;
-			entry.port = dest->port;
-			entry.conn_flags = atomic_read(&dest->conn_flags);
-			entry.weight = atomic_read(&dest->weight);
-			entry.u_threshold = dest->u_threshold;
-			entry.l_threshold = dest->l_threshold;
-			entry.activeconns = atomic_read(&dest->activeconns);
-			entry.inactconns = atomic_read(&dest->inactconns);
-			entry.persistconns = atomic_read(&dest->persistconns);
-			ip_vs_copy_stats(&entry.stats, &dest->stats);
-			if (copy_to_user(&uptr->entrytable[count],
-					 &entry, sizeof(entry))) {
-				ret = -EFAULT;
-				break;
-			}
-			count++;
-		}
-		ip_vs_service_put(svc);
-	} else
-		ret = -ESRCH;
-	return ret;
-}
-
-static inline void
-__ip_vs_get_timeouts(struct ip_vs_timeout_user *u)
-{
-#ifdef CONFIG_IP_VS_PROTO_TCP
-	u->tcp_timeout =
-		ip_vs_protocol_tcp.timeout_table[IP_VS_TCP_S_ESTABLISHED] / HZ;
-	u->tcp_fin_timeout =
-		ip_vs_protocol_tcp.timeout_table[IP_VS_TCP_S_FIN_WAIT] / HZ;
-#endif
-#ifdef CONFIG_IP_VS_PROTO_UDP
-	u->udp_timeout =
-		ip_vs_protocol_udp.timeout_table[IP_VS_UDP_S_NORMAL] / HZ;
-#endif
-}
-
-
-#define GET_CMDID(cmd)		(cmd - IP_VS_BASE_CTL)
-#define GET_INFO_ARG_LEN	(sizeof(struct ip_vs_getinfo))
-#define GET_SERVICES_ARG_LEN	(sizeof(struct ip_vs_get_services))
-#define GET_SERVICE_ARG_LEN	(sizeof(struct ip_vs_service_entry))
-#define GET_DESTS_ARG_LEN	(sizeof(struct ip_vs_get_dests))
-#define GET_TIMEOUT_ARG_LEN	(sizeof(struct ip_vs_timeout_user))
-#define GET_DAEMON_ARG_LEN	(sizeof(struct ip_vs_daemon_user) * 2)
-
-static const unsigned char get_arglen[GET_CMDID(IP_VS_SO_GET_MAX)+1] = {
-	[GET_CMDID(IP_VS_SO_GET_VERSION)]	= 64,
-	[GET_CMDID(IP_VS_SO_GET_INFO)]		= GET_INFO_ARG_LEN,
-	[GET_CMDID(IP_VS_SO_GET_SERVICES)]	= GET_SERVICES_ARG_LEN,
-	[GET_CMDID(IP_VS_SO_GET_SERVICE)]	= GET_SERVICE_ARG_LEN,
-	[GET_CMDID(IP_VS_SO_GET_DESTS)]		= GET_DESTS_ARG_LEN,
-	[GET_CMDID(IP_VS_SO_GET_TIMEOUT)]	= GET_TIMEOUT_ARG_LEN,
-	[GET_CMDID(IP_VS_SO_GET_DAEMON)]	= GET_DAEMON_ARG_LEN,
-};
-
-static int
-do_ip_vs_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
-{
-	unsigned char arg[128];
-	int ret = 0;
-
-	if (!capable(CAP_NET_ADMIN))
-		return -EPERM;
-
-	if (*len < get_arglen[GET_CMDID(cmd)]) {
-		IP_VS_ERR("get_ctl: len %u < %u\n",
-			  *len, get_arglen[GET_CMDID(cmd)]);
-		return -EINVAL;
-	}
-
-	if (copy_from_user(arg, user, get_arglen[GET_CMDID(cmd)]) != 0)
-		return -EFAULT;
-
-	if (mutex_lock_interruptible(&__ip_vs_mutex))
-		return -ERESTARTSYS;
-
-	switch (cmd) {
-	case IP_VS_SO_GET_VERSION:
-	{
-		char buf[64];
-
-		sprintf(buf, "IP Virtual Server version %d.%d.%d (size=%d)",
-			NVERSION(IP_VS_VERSION_CODE), IP_VS_CONN_TAB_SIZE);
-		if (copy_to_user(user, buf, strlen(buf)+1) != 0) {
-			ret = -EFAULT;
-			goto out;
-		}
-		*len = strlen(buf)+1;
-	}
-	break;
-
-	case IP_VS_SO_GET_INFO:
-	{
-		struct ip_vs_getinfo info;
-		info.version = IP_VS_VERSION_CODE;
-		info.size = IP_VS_CONN_TAB_SIZE;
-		info.num_services = ip_vs_num_services;
-		if (copy_to_user(user, &info, sizeof(info)) != 0)
-			ret = -EFAULT;
-	}
-	break;
-
-	case IP_VS_SO_GET_SERVICES:
-	{
-		struct ip_vs_get_services *get;
-		int size;
-
-		get = (struct ip_vs_get_services *)arg;
-		size = sizeof(*get) +
-			sizeof(struct ip_vs_service_entry) * get->num_services;
-		if (*len != size) {
-			IP_VS_ERR("length: %u != %u\n", *len, size);
-			ret = -EINVAL;
-			goto out;
-		}
-		ret = __ip_vs_get_service_entries(get, user);
-	}
-	break;
-
-	case IP_VS_SO_GET_SERVICE:
-	{
-		struct ip_vs_service_entry *entry;
-		struct ip_vs_service *svc;
-
-		entry = (struct ip_vs_service_entry *)arg;
-		if (entry->fwmark)
-			svc = __ip_vs_svc_fwm_get(entry->fwmark);
-		else
-			svc = __ip_vs_service_get(entry->protocol,
-						  entry->addr, entry->port);
-		if (svc) {
-			ip_vs_copy_service(entry, svc);
-			if (copy_to_user(user, entry, sizeof(*entry)) != 0)
-				ret = -EFAULT;
-			ip_vs_service_put(svc);
-		} else
-			ret = -ESRCH;
-	}
-	break;
-
-	case IP_VS_SO_GET_DESTS:
-	{
-		struct ip_vs_get_dests *get;
-		int size;
-
-		get = (struct ip_vs_get_dests *)arg;
-		size = sizeof(*get) +
-			sizeof(struct ip_vs_dest_entry) * get->num_dests;
-		if (*len != size) {
-			IP_VS_ERR("length: %u != %u\n", *len, size);
-			ret = -EINVAL;
-			goto out;
-		}
-		ret = __ip_vs_get_dest_entries(get, user);
-	}
-	break;
-
-	case IP_VS_SO_GET_TIMEOUT:
-	{
-		struct ip_vs_timeout_user t;
-
-		__ip_vs_get_timeouts(&t);
-		if (copy_to_user(user, &t, sizeof(t)) != 0)
-			ret = -EFAULT;
-	}
-	break;
-
-	case IP_VS_SO_GET_DAEMON:
-	{
-		struct ip_vs_daemon_user d[2];
-
-		memset(&d, 0, sizeof(d));
-		if (ip_vs_sync_state & IP_VS_STATE_MASTER) {
-			d[0].state = IP_VS_STATE_MASTER;
-			strlcpy(d[0].mcast_ifn, ip_vs_master_mcast_ifn, sizeof(d[0].mcast_ifn));
-			d[0].syncid = ip_vs_master_syncid;
-		}
-		if (ip_vs_sync_state & IP_VS_STATE_BACKUP) {
-			d[1].state = IP_VS_STATE_BACKUP;
-			strlcpy(d[1].mcast_ifn, ip_vs_backup_mcast_ifn, sizeof(d[1].mcast_ifn));
-			d[1].syncid = ip_vs_backup_syncid;
-		}
-		if (copy_to_user(user, &d, sizeof(d)) != 0)
-			ret = -EFAULT;
-	}
-	break;
-
-	default:
-		ret = -EINVAL;
-	}
-
-  out:
-	mutex_unlock(&__ip_vs_mutex);
-	return ret;
-}
-
-
-static struct nf_sockopt_ops ip_vs_sockopts = {
-	.pf		= PF_INET,
-	.set_optmin	= IP_VS_BASE_CTL,
-	.set_optmax	= IP_VS_SO_SET_MAX+1,
-	.set		= do_ip_vs_set_ctl,
-	.get_optmin	= IP_VS_BASE_CTL,
-	.get_optmax	= IP_VS_SO_GET_MAX+1,
-	.get		= do_ip_vs_get_ctl,
-	.owner		= THIS_MODULE,
-};
-
-
-int __init ip_vs_control_init(void)
-{
-	int ret;
-	int idx;
-
-	EnterFunction(2);
-
-	ret = nf_register_sockopt(&ip_vs_sockopts);
-	if (ret) {
-		IP_VS_ERR("cannot register sockopt.\n");
-		return ret;
-	}
-
-	proc_net_fops_create(&init_net, "ip_vs", 0, &ip_vs_info_fops);
-	proc_net_fops_create(&init_net, "ip_vs_stats",0, &ip_vs_stats_fops);
-
-	sysctl_header = register_sysctl_paths(net_vs_ctl_path, vs_vars);
-
-	/* Initialize ip_vs_svc_table, ip_vs_svc_fwm_table, ip_vs_rtable */
-	for(idx = 0; idx < IP_VS_SVC_TAB_SIZE; idx++)  {
-		INIT_LIST_HEAD(&ip_vs_svc_table[idx]);
-		INIT_LIST_HEAD(&ip_vs_svc_fwm_table[idx]);
-	}
-	for(idx = 0; idx < IP_VS_RTAB_SIZE; idx++)  {
-		INIT_LIST_HEAD(&ip_vs_rtable[idx]);
-	}
-
-	ip_vs_new_estimator(&ip_vs_stats);
-
-	/* Hook the defense timer */
-	schedule_delayed_work(&defense_work, DEFENSE_TIMER_PERIOD);
-
-	LeaveFunction(2);
-	return 0;
-}
-
-
-void ip_vs_control_cleanup(void)
-{
-	EnterFunction(2);
-	ip_vs_trash_cleanup();
-	cancel_rearming_delayed_work(&defense_work);
-	cancel_work_sync(&defense_work.work);
-	ip_vs_kill_estimator(&ip_vs_stats);
-	unregister_sysctl_table(sysctl_header);
-	proc_net_remove(&init_net, "ip_vs_stats");
-	proc_net_remove(&init_net, "ip_vs");
-	nf_unregister_sockopt(&ip_vs_sockopts);
-	LeaveFunction(2);
-}
diff --git a/net/ipv4/ipvs/ip_vs_dh.c b/net/ipv4/ipvs/ip_vs_dh.c
deleted file mode 100644
index fa66824..0000000
--- a/net/ipv4/ipvs/ip_vs_dh.c
+++ /dev/null
@@ -1,258 +0,0 @@
-/*
- * IPVS:        Destination Hashing scheduling module
- *
- * Authors:     Wensong Zhang <wensong@gnuchina.org>
- *
- *              Inspired by the consistent hashing scheduler patch from
- *              Thomas Proell <proellt@gmx.de>
- *
- *              This program is free software; you can redistribute it and/or
- *              modify it under the terms of the GNU General Public License
- *              as published by the Free Software Foundation; either version
- *              2 of the License, or (at your option) any later version.
- *
- * Changes:
- *
- */
-
-/*
- * The dh algorithm is to select server by the hash key of destination IP
- * address. The pseudo code is as follows:
- *
- *       n <- servernode[dest_ip];
- *       if (n is dead) OR
- *          (n is overloaded) OR (n.weight <= 0) then
- *                 return NULL;
- *
- *       return n;
- *
- * Notes that servernode is a 256-bucket hash table that maps the hash
- * index derived from packet destination IP address to the current server
- * array. If the dh scheduler is used in cache cluster, it is good to
- * combine it with cache_bypass feature. When the statically assigned
- * server is dead or overloaded, the load balancer can bypass the cache
- * server and send requests to the original server directly.
- *
- */
-
-#include <linux/ip.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/skbuff.h>
-
-#include <net/ip_vs.h>
-
-
-/*
- *      IPVS DH bucket
- */
-struct ip_vs_dh_bucket {
-	struct ip_vs_dest       *dest;          /* real server (cache) */
-};
-
-/*
- *     for IPVS DH entry hash table
- */
-#ifndef CONFIG_IP_VS_DH_TAB_BITS
-#define CONFIG_IP_VS_DH_TAB_BITS        8
-#endif
-#define IP_VS_DH_TAB_BITS               CONFIG_IP_VS_DH_TAB_BITS
-#define IP_VS_DH_TAB_SIZE               (1 << IP_VS_DH_TAB_BITS)
-#define IP_VS_DH_TAB_MASK               (IP_VS_DH_TAB_SIZE - 1)
-
-
-/*
- *	Returns hash value for IPVS DH entry
- */
-static inline unsigned ip_vs_dh_hashkey(__be32 addr)
-{
-	return (ntohl(addr)*2654435761UL) & IP_VS_DH_TAB_MASK;
-}
-
-
-/*
- *      Get ip_vs_dest associated with supplied parameters.
- */
-static inline struct ip_vs_dest *
-ip_vs_dh_get(struct ip_vs_dh_bucket *tbl, __be32 addr)
-{
-	return (tbl[ip_vs_dh_hashkey(addr)]).dest;
-}
-
-
-/*
- *      Assign all the hash buckets of the specified table with the service.
- */
-static int
-ip_vs_dh_assign(struct ip_vs_dh_bucket *tbl, struct ip_vs_service *svc)
-{
-	int i;
-	struct ip_vs_dh_bucket *b;
-	struct list_head *p;
-	struct ip_vs_dest *dest;
-
-	b = tbl;
-	p = &svc->destinations;
-	for (i=0; i<IP_VS_DH_TAB_SIZE; i++) {
-		if (list_empty(p)) {
-			b->dest = NULL;
-		} else {
-			if (p == &svc->destinations)
-				p = p->next;
-
-			dest = list_entry(p, struct ip_vs_dest, n_list);
-			atomic_inc(&dest->refcnt);
-			b->dest = dest;
-
-			p = p->next;
-		}
-		b++;
-	}
-	return 0;
-}
-
-
-/*
- *      Flush all the hash buckets of the specified table.
- */
-static void ip_vs_dh_flush(struct ip_vs_dh_bucket *tbl)
-{
-	int i;
-	struct ip_vs_dh_bucket *b;
-
-	b = tbl;
-	for (i=0; i<IP_VS_DH_TAB_SIZE; i++) {
-		if (b->dest) {
-			atomic_dec(&b->dest->refcnt);
-			b->dest = NULL;
-		}
-		b++;
-	}
-}
-
-
-static int ip_vs_dh_init_svc(struct ip_vs_service *svc)
-{
-	struct ip_vs_dh_bucket *tbl;
-
-	/* allocate the DH table for this service */
-	tbl = kmalloc(sizeof(struct ip_vs_dh_bucket)*IP_VS_DH_TAB_SIZE,
-		      GFP_ATOMIC);
-	if (tbl == NULL) {
-		IP_VS_ERR("ip_vs_dh_init_svc(): no memory\n");
-		return -ENOMEM;
-	}
-	svc->sched_data = tbl;
-	IP_VS_DBG(6, "DH hash table (memory=%Zdbytes) allocated for "
-		  "current service\n",
-		  sizeof(struct ip_vs_dh_bucket)*IP_VS_DH_TAB_SIZE);
-
-	/* assign the hash buckets with the updated service */
-	ip_vs_dh_assign(tbl, svc);
-
-	return 0;
-}
-
-
-static int ip_vs_dh_done_svc(struct ip_vs_service *svc)
-{
-	struct ip_vs_dh_bucket *tbl = svc->sched_data;
-
-	/* got to clean up hash buckets here */
-	ip_vs_dh_flush(tbl);
-
-	/* release the table itself */
-	kfree(svc->sched_data);
-	IP_VS_DBG(6, "DH hash table (memory=%Zdbytes) released\n",
-		  sizeof(struct ip_vs_dh_bucket)*IP_VS_DH_TAB_SIZE);
-
-	return 0;
-}
-
-
-static int ip_vs_dh_update_svc(struct ip_vs_service *svc)
-{
-	struct ip_vs_dh_bucket *tbl = svc->sched_data;
-
-	/* got to clean up hash buckets here */
-	ip_vs_dh_flush(tbl);
-
-	/* assign the hash buckets with the updated service */
-	ip_vs_dh_assign(tbl, svc);
-
-	return 0;
-}
-
-
-/*
- *      If the dest flags is set with IP_VS_DEST_F_OVERLOAD,
- *      consider that the server is overloaded here.
- */
-static inline int is_overloaded(struct ip_vs_dest *dest)
-{
-	return dest->flags & IP_VS_DEST_F_OVERLOAD;
-}
-
-
-/*
- *      Destination hashing scheduling
- */
-static struct ip_vs_dest *
-ip_vs_dh_schedule(struct ip_vs_service *svc, const struct sk_buff *skb)
-{
-	struct ip_vs_dest *dest;
-	struct ip_vs_dh_bucket *tbl;
-	struct iphdr *iph = ip_hdr(skb);
-
-	IP_VS_DBG(6, "ip_vs_dh_schedule(): Scheduling...\n");
-
-	tbl = (struct ip_vs_dh_bucket *)svc->sched_data;
-	dest = ip_vs_dh_get(tbl, iph->daddr);
-	if (!dest
-	    || !(dest->flags & IP_VS_DEST_F_AVAILABLE)
-	    || atomic_read(&dest->weight) <= 0
-	    || is_overloaded(dest)) {
-		return NULL;
-	}
-
-	IP_VS_DBG(6, "DH: destination IP address %u.%u.%u.%u "
-		  "--> server %u.%u.%u.%u:%d\n",
-		  NIPQUAD(iph->daddr),
-		  NIPQUAD(dest->addr),
-		  ntohs(dest->port));
-
-	return dest;
-}
-
-
-/*
- *      IPVS DH Scheduler structure
- */
-static struct ip_vs_scheduler ip_vs_dh_scheduler =
-{
-	.name =			"dh",
-	.refcnt =		ATOMIC_INIT(0),
-	.module =		THIS_MODULE,
-	.n_list =		LIST_HEAD_INIT(ip_vs_dh_scheduler.n_list),
-	.init_service =		ip_vs_dh_init_svc,
-	.done_service =		ip_vs_dh_done_svc,
-	.update_service =	ip_vs_dh_update_svc,
-	.schedule =		ip_vs_dh_schedule,
-};
-
-
-static int __init ip_vs_dh_init(void)
-{
-	return register_ip_vs_scheduler(&ip_vs_dh_scheduler);
-}
-
-
-static void __exit ip_vs_dh_cleanup(void)
-{
-	unregister_ip_vs_scheduler(&ip_vs_dh_scheduler);
-}
-
-
-module_init(ip_vs_dh_init);
-module_exit(ip_vs_dh_cleanup);
-MODULE_LICENSE("GPL");
diff --git a/net/ipv4/ipvs/ip_vs_est.c b/net/ipv4/ipvs/ip_vs_est.c
deleted file mode 100644
index 5a20f93..0000000
--- a/net/ipv4/ipvs/ip_vs_est.c
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
- * ip_vs_est.c: simple rate estimator for IPVS
- *
- * Authors:     Wensong Zhang <wensong@linuxvirtualserver.org>
- *
- *              This program is free software; you can redistribute it and/or
- *              modify it under the terms of the GNU General Public License
- *              as published by the Free Software Foundation; either version
- *              2 of the License, or (at your option) any later version.
- *
- * Changes:
- *
- */
-#include <linux/kernel.h>
-#include <linux/jiffies.h>
-#include <linux/slab.h>
-#include <linux/types.h>
-#include <linux/interrupt.h>
-#include <linux/sysctl.h>
-#include <linux/list.h>
-
-#include <net/ip_vs.h>
-
-/*
-  This code is to estimate rate in a shorter interval (such as 8
-  seconds) for virtual services and real servers. For measure rate in a
-  long interval, it is easy to implement a user level daemon which
-  periodically reads those statistical counters and measure rate.
-
-  Currently, the measurement is activated by slow timer handler. Hope
-  this measurement will not introduce too much load.
-
-  We measure rate during the last 8 seconds every 2 seconds:
-
-    avgrate = avgrate*(1-W) + rate*W
-
-    where W = 2^(-2)
-
-  NOTES.
-
-  * The stored value for average bps is scaled by 2^5, so that maximal
-    rate is ~2.15Gbits/s, average pps and cps are scaled by 2^10.
-
-  * A lot code is taken from net/sched/estimator.c
- */
-
-
-static void estimation_timer(unsigned long arg);
-
-static LIST_HEAD(est_list);
-static DEFINE_SPINLOCK(est_lock);
-static DEFINE_TIMER(est_timer, estimation_timer, 0, 0);
-
-static void estimation_timer(unsigned long arg)
-{
-	struct ip_vs_estimator *e;
-	struct ip_vs_stats *s;
-	u32 n_conns;
-	u32 n_inpkts, n_outpkts;
-	u64 n_inbytes, n_outbytes;
-	u32 rate;
-
-	spin_lock(&est_lock);
-	list_for_each_entry(e, &est_list, list) {
-		s = container_of(e, struct ip_vs_stats, est);
-
-		spin_lock(&s->lock);
-		n_conns = s->conns;
-		n_inpkts = s->inpkts;
-		n_outpkts = s->outpkts;
-		n_inbytes = s->inbytes;
-		n_outbytes = s->outbytes;
-
-		/* scaled by 2^10, but divided 2 seconds */
-		rate = (n_conns - e->last_conns)<<9;
-		e->last_conns = n_conns;
-		e->cps += ((long)rate - (long)e->cps)>>2;
-		s->cps = (e->cps+0x1FF)>>10;
-
-		rate = (n_inpkts - e->last_inpkts)<<9;
-		e->last_inpkts = n_inpkts;
-		e->inpps += ((long)rate - (long)e->inpps)>>2;
-		s->inpps = (e->inpps+0x1FF)>>10;
-
-		rate = (n_outpkts - e->last_outpkts)<<9;
-		e->last_outpkts = n_outpkts;
-		e->outpps += ((long)rate - (long)e->outpps)>>2;
-		s->outpps = (e->outpps+0x1FF)>>10;
-
-		rate = (n_inbytes - e->last_inbytes)<<4;
-		e->last_inbytes = n_inbytes;
-		e->inbps += ((long)rate - (long)e->inbps)>>2;
-		s->inbps = (e->inbps+0xF)>>5;
-
-		rate = (n_outbytes - e->last_outbytes)<<4;
-		e->last_outbytes = n_outbytes;
-		e->outbps += ((long)rate - (long)e->outbps)>>2;
-		s->outbps = (e->outbps+0xF)>>5;
-		spin_unlock(&s->lock);
-	}
-	spin_unlock(&est_lock);
-	mod_timer(&est_timer, jiffies + 2*HZ);
-}
-
-void ip_vs_new_estimator(struct ip_vs_stats *stats)
-{
-	struct ip_vs_estimator *est = &stats->est;
-
-	INIT_LIST_HEAD(&est->list);
-
-	est->last_conns = stats->conns;
-	est->cps = stats->cps<<10;
-
-	est->last_inpkts = stats->inpkts;
-	est->inpps = stats->inpps<<10;
-
-	est->last_outpkts = stats->outpkts;
-	est->outpps = stats->outpps<<10;
-
-	est->last_inbytes = stats->inbytes;
-	est->inbps = stats->inbps<<5;
-
-	est->last_outbytes = stats->outbytes;
-	est->outbps = stats->outbps<<5;
-
-	spin_lock_bh(&est_lock);
-	if (list_empty(&est_list))
-		mod_timer(&est_timer, jiffies + 2 * HZ);
-	list_add(&est->list, &est_list);
-	spin_unlock_bh(&est_lock);
-}
-
-void ip_vs_kill_estimator(struct ip_vs_stats *stats)
-{
-	struct ip_vs_estimator *est = &stats->est;
-
-	spin_lock_bh(&est_lock);
-	list_del(&est->list);
-	while (list_empty(&est_list) && try_to_del_timer_sync(&est_timer) < 0) {
-		spin_unlock_bh(&est_lock);
-		cpu_relax();
-		spin_lock_bh(&est_lock);
-	}
-	spin_unlock_bh(&est_lock);
-}
-
-void ip_vs_zero_estimator(struct ip_vs_stats *stats)
-{
-	struct ip_vs_estimator *est = &stats->est;
-
-	/* set counters zero, caller must hold the stats->lock lock */
-	est->last_inbytes = 0;
-	est->last_outbytes = 0;
-	est->last_conns = 0;
-	est->last_inpkts = 0;
-	est->last_outpkts = 0;
-	est->cps = 0;
-	est->inpps = 0;
-	est->outpps = 0;
-	est->inbps = 0;
-	est->outbps = 0;
-}
diff --git a/net/ipv4/ipvs/ip_vs_ftp.c b/net/ipv4/ipvs/ip_vs_ftp.c
deleted file mode 100644
index c1c758e..0000000
--- a/net/ipv4/ipvs/ip_vs_ftp.c
+++ /dev/null
@@ -1,393 +0,0 @@
-/*
- * ip_vs_ftp.c: IPVS ftp application module
- *
- * Authors:	Wensong Zhang <wensong@linuxvirtualserver.org>
- *
- * Changes:
- *
- *
- *	This program is free software; you can redistribute it and/or
- *	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.
- *
- * Most code here is taken from ip_masq_ftp.c in kernel 2.2. The difference
- * is that ip_vs_ftp module handles the reverse direction to ip_masq_ftp.
- *
- *		IP_MASQ_FTP ftp masquerading module
- *
- * Version:	@(#)ip_masq_ftp.c 0.04   02/05/96
- *
- * Author:	Wouter Gadeyne
- *
- */
-
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/kernel.h>
-#include <linux/skbuff.h>
-#include <linux/in.h>
-#include <linux/ip.h>
-#include <linux/netfilter.h>
-#include <net/protocol.h>
-#include <net/tcp.h>
-#include <asm/unaligned.h>
-
-#include <net/ip_vs.h>
-
-
-#define SERVER_STRING "227 Entering Passive Mode ("
-#define CLIENT_STRING "PORT "
-
-
-/*
- * List of ports (up to IP_VS_APP_MAX_PORTS) to be handled by helper
- * First port is set to the default port.
- */
-static unsigned short ports[IP_VS_APP_MAX_PORTS] = {21, 0};
-module_param_array(ports, ushort, NULL, 0);
-MODULE_PARM_DESC(ports, "Ports to monitor for FTP control commands");
-
-
-/*	Dummy variable */
-static int ip_vs_ftp_pasv;
-
-
-static int
-ip_vs_ftp_init_conn(struct ip_vs_app *app, struct ip_vs_conn *cp)
-{
-	return 0;
-}
-
-
-static int
-ip_vs_ftp_done_conn(struct ip_vs_app *app, struct ip_vs_conn *cp)
-{
-	return 0;
-}
-
-
-/*
- * Get <addr,port> from the string "xxx.xxx.xxx.xxx,ppp,ppp", started
- * with the "pattern" and terminated with the "term" character.
- * <addr,port> is in network order.
- */
-static int ip_vs_ftp_get_addrport(char *data, char *data_limit,
-				  const char *pattern, size_t plen, char term,
-				  __be32 *addr, __be16 *port,
-				  char **start, char **end)
-{
-	unsigned char p[6];
-	int i = 0;
-
-	if (data_limit - data < plen) {
-		/* check if there is partial match */
-		if (strnicmp(data, pattern, data_limit - data) == 0)
-			return -1;
-		else
-			return 0;
-	}
-
-	if (strnicmp(data, pattern, plen) != 0) {
-		return 0;
-	}
-	*start = data + plen;
-
-	for (data = *start; *data != term; data++) {
-		if (data == data_limit)
-			return -1;
-	}
-	*end = data;
-
-	memset(p, 0, sizeof(p));
-	for (data = *start; data != *end; data++) {
-		if (*data >= '0' && *data <= '9') {
-			p[i] = p[i]*10 + *data - '0';
-		} else if (*data == ',' && i < 5) {
-			i++;
-		} else {
-			/* unexpected character */
-			return -1;
-		}
-	}
-
-	if (i != 5)
-		return -1;
-
-	*addr = get_unaligned((__be32 *)p);
-	*port = get_unaligned((__be16 *)(p + 4));
-	return 1;
-}
-
-
-/*
- * Look at outgoing ftp packets to catch the response to a PASV command
- * from the server (inside-to-outside).
- * When we see one, we build a connection entry with the client address,
- * client port 0 (unknown at the moment), the server address and the
- * server port.  Mark the current connection entry as a control channel
- * of the new entry. All this work is just to make the data connection
- * can be scheduled to the right server later.
- *
- * The outgoing packet should be something like
- *   "227 Entering Passive Mode (xxx,xxx,xxx,xxx,ppp,ppp)".
- * xxx,xxx,xxx,xxx is the server address, ppp,ppp is the server port number.
- */
-static int ip_vs_ftp_out(struct ip_vs_app *app, struct ip_vs_conn *cp,
-			 struct sk_buff *skb, int *diff)
-{
-	struct iphdr *iph;
-	struct tcphdr *th;
-	char *data, *data_limit;
-	char *start, *end;
-	__be32 from;
-	__be16 port;
-	struct ip_vs_conn *n_cp;
-	char buf[24];		/* xxx.xxx.xxx.xxx,ppp,ppp\000 */
-	unsigned buf_len;
-	int ret;
-
-	*diff = 0;
-
-	/* Only useful for established sessions */
-	if (cp->state != IP_VS_TCP_S_ESTABLISHED)
-		return 1;
-
-	/* Linear packets are much easier to deal with. */
-	if (!skb_make_writable(skb, skb->len))
-		return 0;
-
-	if (cp->app_data == &ip_vs_ftp_pasv) {
-		iph = ip_hdr(skb);
-		th = (struct tcphdr *)&(((char *)iph)[iph->ihl*4]);
-		data = (char *)th + (th->doff << 2);
-		data_limit = skb_tail_pointer(skb);
-
-		if (ip_vs_ftp_get_addrport(data, data_limit,
-					   SERVER_STRING,
-					   sizeof(SERVER_STRING)-1, ')',
-					   &from, &port,
-					   &start, &end) != 1)
-			return 1;
-
-		IP_VS_DBG(7, "PASV response (%u.%u.%u.%u:%d) -> "
-			  "%u.%u.%u.%u:%d detected\n",
-			  NIPQUAD(from), ntohs(port), NIPQUAD(cp->caddr), 0);
-
-		/*
-		 * Now update or create an connection entry for it
-		 */
-		n_cp = ip_vs_conn_out_get(iph->protocol, from, port,
-					  cp->caddr, 0);
-		if (!n_cp) {
-			n_cp = ip_vs_conn_new(IPPROTO_TCP,
-					      cp->caddr, 0,
-					      cp->vaddr, port,
-					      from, port,
-					      IP_VS_CONN_F_NO_CPORT,
-					      cp->dest);
-			if (!n_cp)
-				return 0;
-
-			/* add its controller */
-			ip_vs_control_add(n_cp, cp);
-		}
-
-		/*
-		 * Replace the old passive address with the new one
-		 */
-		from = n_cp->vaddr;
-		port = n_cp->vport;
-		sprintf(buf,"%d,%d,%d,%d,%d,%d", NIPQUAD(from),
-			(ntohs(port)>>8)&255, ntohs(port)&255);
-		buf_len = strlen(buf);
-
-		/*
-		 * Calculate required delta-offset to keep TCP happy
-		 */
-		*diff = buf_len - (end-start);
-
-		if (*diff == 0) {
-			/* simply replace it with new passive address */
-			memcpy(start, buf, buf_len);
-			ret = 1;
-		} else {
-			ret = !ip_vs_skb_replace(skb, GFP_ATOMIC, start,
-					  end-start, buf, buf_len);
-		}
-
-		cp->app_data = NULL;
-		ip_vs_tcp_conn_listen(n_cp);
-		ip_vs_conn_put(n_cp);
-		return ret;
-	}
-	return 1;
-}
-
-
-/*
- * Look at incoming ftp packets to catch the PASV/PORT command
- * (outside-to-inside).
- *
- * The incoming packet having the PORT command should be something like
- *      "PORT xxx,xxx,xxx,xxx,ppp,ppp\n".
- * xxx,xxx,xxx,xxx is the client address, ppp,ppp is the client port number.
- * In this case, we create a connection entry using the client address and
- * port, so that the active ftp data connection from the server can reach
- * the client.
- */
-static int ip_vs_ftp_in(struct ip_vs_app *app, struct ip_vs_conn *cp,
-			struct sk_buff *skb, int *diff)
-{
-	struct iphdr *iph;
-	struct tcphdr *th;
-	char *data, *data_start, *data_limit;
-	char *start, *end;
-	__be32 to;
-	__be16 port;
-	struct ip_vs_conn *n_cp;
-
-	/* no diff required for incoming packets */
-	*diff = 0;
-
-	/* Only useful for established sessions */
-	if (cp->state != IP_VS_TCP_S_ESTABLISHED)
-		return 1;
-
-	/* Linear packets are much easier to deal with. */
-	if (!skb_make_writable(skb, skb->len))
-		return 0;
-
-	/*
-	 * Detecting whether it is passive
-	 */
-	iph = ip_hdr(skb);
-	th = (struct tcphdr *)&(((char *)iph)[iph->ihl*4]);
-
-	/* Since there may be OPTIONS in the TCP packet and the HLEN is
-	   the length of the header in 32-bit multiples, it is accurate
-	   to calculate data address by th+HLEN*4 */
-	data = data_start = (char *)th + (th->doff << 2);
-	data_limit = skb_tail_pointer(skb);
-
-	while (data <= data_limit - 6) {
-		if (strnicmp(data, "PASV\r\n", 6) == 0) {
-			/* Passive mode on */
-			IP_VS_DBG(7, "got PASV at %td of %td\n",
-				  data - data_start,
-				  data_limit - data_start);
-			cp->app_data = &ip_vs_ftp_pasv;
-			return 1;
-		}
-		data++;
-	}
-
-	/*
-	 * To support virtual FTP server, the scenerio is as follows:
-	 *       FTP client ----> Load Balancer ----> FTP server
-	 * First detect the port number in the application data,
-	 * then create a new connection entry for the coming data
-	 * connection.
-	 */
-	if (ip_vs_ftp_get_addrport(data_start, data_limit,
-				   CLIENT_STRING, sizeof(CLIENT_STRING)-1,
-				   '\r', &to, &port,
-				   &start, &end) != 1)
-		return 1;
-
-	IP_VS_DBG(7, "PORT %u.%u.%u.%u:%d detected\n",
-		  NIPQUAD(to), ntohs(port));
-
-	/* Passive mode off */
-	cp->app_data = NULL;
-
-	/*
-	 * Now update or create a connection entry for it
-	 */
-	IP_VS_DBG(7, "protocol %s %u.%u.%u.%u:%d %u.%u.%u.%u:%d\n",
-		  ip_vs_proto_name(iph->protocol),
-		  NIPQUAD(to), ntohs(port), NIPQUAD(cp->vaddr), 0);
-
-	n_cp = ip_vs_conn_in_get(iph->protocol,
-				 to, port,
-				 cp->vaddr, htons(ntohs(cp->vport)-1));
-	if (!n_cp) {
-		n_cp = ip_vs_conn_new(IPPROTO_TCP,
-				      to, port,
-				      cp->vaddr, htons(ntohs(cp->vport)-1),
-				      cp->daddr, htons(ntohs(cp->dport)-1),
-				      0,
-				      cp->dest);
-		if (!n_cp)
-			return 0;
-
-		/* add its controller */
-		ip_vs_control_add(n_cp, cp);
-	}
-
-	/*
-	 *	Move tunnel to listen state
-	 */
-	ip_vs_tcp_conn_listen(n_cp);
-	ip_vs_conn_put(n_cp);
-
-	return 1;
-}
-
-
-static struct ip_vs_app ip_vs_ftp = {
-	.name =		"ftp",
-	.type =		IP_VS_APP_TYPE_FTP,
-	.protocol =	IPPROTO_TCP,
-	.module =	THIS_MODULE,
-	.incs_list =	LIST_HEAD_INIT(ip_vs_ftp.incs_list),
-	.init_conn =	ip_vs_ftp_init_conn,
-	.done_conn =	ip_vs_ftp_done_conn,
-	.bind_conn =	NULL,
-	.unbind_conn =	NULL,
-	.pkt_out =	ip_vs_ftp_out,
-	.pkt_in =	ip_vs_ftp_in,
-};
-
-
-/*
- *	ip_vs_ftp initialization
- */
-static int __init ip_vs_ftp_init(void)
-{
-	int i, ret;
-	struct ip_vs_app *app = &ip_vs_ftp;
-
-	ret = register_ip_vs_app(app);
-	if (ret)
-		return ret;
-
-	for (i=0; i<IP_VS_APP_MAX_PORTS; i++) {
-		if (!ports[i])
-			continue;
-		ret = register_ip_vs_app_inc(app, app->protocol, ports[i]);
-		if (ret)
-			break;
-		IP_VS_INFO("%s: loaded support on port[%d] = %d\n",
-			   app->name, i, ports[i]);
-	}
-
-	if (ret)
-		unregister_ip_vs_app(app);
-
-	return ret;
-}
-
-
-/*
- *	ip_vs_ftp finish.
- */
-static void __exit ip_vs_ftp_exit(void)
-{
-	unregister_ip_vs_app(&ip_vs_ftp);
-}
-
-
-module_init(ip_vs_ftp_init);
-module_exit(ip_vs_ftp_exit);
-MODULE_LICENSE("GPL");
diff --git a/net/ipv4/ipvs/ip_vs_lblc.c b/net/ipv4/ipvs/ip_vs_lblc.c
deleted file mode 100644
index 7a6a319..0000000
--- a/net/ipv4/ipvs/ip_vs_lblc.c
+++ /dev/null
@@ -1,571 +0,0 @@
-/*
- * IPVS:        Locality-Based Least-Connection scheduling module
- *
- * Authors:     Wensong Zhang <wensong@gnuchina.org>
- *
- *              This program is free software; you can redistribute it and/or
- *              modify it under the terms of the GNU General Public License
- *              as published by the Free Software Foundation; either version
- *              2 of the License, or (at your option) any later version.
- *
- * Changes:
- *     Martin Hamilton         :    fixed the terrible locking bugs
- *                                   *lock(tbl->lock) ==> *lock(&tbl->lock)
- *     Wensong Zhang           :    fixed the uninitilized tbl->lock bug
- *     Wensong Zhang           :    added doing full expiration check to
- *                                   collect stale entries of 24+ hours when
- *                                   no partial expire check in a half hour
- *     Julian Anastasov        :    replaced del_timer call with del_timer_sync
- *                                   to avoid the possible race between timer
- *                                   handler and del_timer thread in SMP
- *
- */
-
-/*
- * The lblc algorithm is as follows (pseudo code):
- *
- *       if cachenode[dest_ip] is null then
- *               n, cachenode[dest_ip] <- {weighted least-conn node};
- *       else
- *               n <- cachenode[dest_ip];
- *               if (n is dead) OR
- *                  (n.conns>n.weight AND
- *                   there is a node m with m.conns<m.weight/2) then
- *                 n, cachenode[dest_ip] <- {weighted least-conn node};
- *
- *       return n;
- *
- * Thanks must go to Wenzhuo Zhang for talking WCCP to me and pushing
- * me to write this module.
- */
-
-#include <linux/ip.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/skbuff.h>
-#include <linux/jiffies.h>
-
-/* for sysctl */
-#include <linux/fs.h>
-#include <linux/sysctl.h>
-
-#include <net/ip_vs.h>
-
-
-/*
- *    It is for garbage collection of stale IPVS lblc entries,
- *    when the table is full.
- */
-#define CHECK_EXPIRE_INTERVAL   (60*HZ)
-#define ENTRY_TIMEOUT           (6*60*HZ)
-
-/*
- *    It is for full expiration check.
- *    When there is no partial expiration check (garbage collection)
- *    in a half hour, do a full expiration check to collect stale
- *    entries that haven't been touched for a day.
- */
-#define COUNT_FOR_FULL_EXPIRATION   30
-static int sysctl_ip_vs_lblc_expiration = 24*60*60*HZ;
-
-
-/*
- *     for IPVS lblc entry hash table
- */
-#ifndef CONFIG_IP_VS_LBLC_TAB_BITS
-#define CONFIG_IP_VS_LBLC_TAB_BITS      10
-#endif
-#define IP_VS_LBLC_TAB_BITS     CONFIG_IP_VS_LBLC_TAB_BITS
-#define IP_VS_LBLC_TAB_SIZE     (1 << IP_VS_LBLC_TAB_BITS)
-#define IP_VS_LBLC_TAB_MASK     (IP_VS_LBLC_TAB_SIZE - 1)
-
-
-/*
- *      IPVS lblc entry represents an association between destination
- *      IP address and its destination server
- */
-struct ip_vs_lblc_entry {
-	struct list_head        list;
-	__be32                  addr;           /* destination IP address */
-	struct ip_vs_dest       *dest;          /* real server (cache) */
-	unsigned long           lastuse;        /* last used time */
-};
-
-
-/*
- *      IPVS lblc hash table
- */
-struct ip_vs_lblc_table {
-	rwlock_t	        lock;           /* lock for this table */
-	struct list_head        bucket[IP_VS_LBLC_TAB_SIZE];  /* hash bucket */
-	atomic_t                entries;        /* number of entries */
-	int                     max_size;       /* maximum size of entries */
-	struct timer_list       periodic_timer; /* collect stale entries */
-	int                     rover;          /* rover for expire check */
-	int                     counter;        /* counter for no expire */
-};
-
-
-/*
- *      IPVS LBLC sysctl table
- */
-
-static ctl_table vs_vars_table[] = {
-	{
-		.procname	= "lblc_expiration",
-		.data		= &sysctl_ip_vs_lblc_expiration,
-		.maxlen		= sizeof(int),
-		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_jiffies,
-	},
-	{ .ctl_name = 0 }
-};
-
-static struct ctl_table_header * sysctl_header;
-
-/*
- *      new/free a ip_vs_lblc_entry, which is a mapping of a destionation
- *      IP address to a server.
- */
-static inline struct ip_vs_lblc_entry *
-ip_vs_lblc_new(__be32 daddr, struct ip_vs_dest *dest)
-{
-	struct ip_vs_lblc_entry *en;
-
-	en = kmalloc(sizeof(struct ip_vs_lblc_entry), GFP_ATOMIC);
-	if (en == NULL) {
-		IP_VS_ERR("ip_vs_lblc_new(): no memory\n");
-		return NULL;
-	}
-
-	INIT_LIST_HEAD(&en->list);
-	en->addr = daddr;
-
-	atomic_inc(&dest->refcnt);
-	en->dest = dest;
-
-	return en;
-}
-
-
-static inline void ip_vs_lblc_free(struct ip_vs_lblc_entry *en)
-{
-	list_del(&en->list);
-	/*
-	 * We don't kfree dest because it is refered either by its service
-	 * or the trash dest list.
-	 */
-	atomic_dec(&en->dest->refcnt);
-	kfree(en);
-}
-
-
-/*
- *	Returns hash value for IPVS LBLC entry
- */
-static inline unsigned ip_vs_lblc_hashkey(__be32 addr)
-{
-	return (ntohl(addr)*2654435761UL) & IP_VS_LBLC_TAB_MASK;
-}
-
-
-/*
- *	Hash an entry in the ip_vs_lblc_table.
- *	returns bool success.
- */
-static int
-ip_vs_lblc_hash(struct ip_vs_lblc_table *tbl, struct ip_vs_lblc_entry *en)
-{
-	unsigned hash;
-
-	if (!list_empty(&en->list)) {
-		IP_VS_ERR("ip_vs_lblc_hash(): request for already hashed, "
-			  "called from %p\n", __builtin_return_address(0));
-		return 0;
-	}
-
-	/*
-	 *	Hash by destination IP address
-	 */
-	hash = ip_vs_lblc_hashkey(en->addr);
-
-	write_lock(&tbl->lock);
-	list_add(&en->list, &tbl->bucket[hash]);
-	atomic_inc(&tbl->entries);
-	write_unlock(&tbl->lock);
-
-	return 1;
-}
-
-
-/*
- *  Get ip_vs_lblc_entry associated with supplied parameters.
- */
-static inline struct ip_vs_lblc_entry *
-ip_vs_lblc_get(struct ip_vs_lblc_table *tbl, __be32 addr)
-{
-	unsigned hash;
-	struct ip_vs_lblc_entry *en;
-
-	hash = ip_vs_lblc_hashkey(addr);
-
-	read_lock(&tbl->lock);
-
-	list_for_each_entry(en, &tbl->bucket[hash], list) {
-		if (en->addr == addr) {
-			/* HIT */
-			read_unlock(&tbl->lock);
-			return en;
-		}
-	}
-
-	read_unlock(&tbl->lock);
-
-	return NULL;
-}
-
-
-/*
- *      Flush all the entries of the specified table.
- */
-static void ip_vs_lblc_flush(struct ip_vs_lblc_table *tbl)
-{
-	int i;
-	struct ip_vs_lblc_entry *en, *nxt;
-
-	for (i=0; i<IP_VS_LBLC_TAB_SIZE; i++) {
-		write_lock(&tbl->lock);
-		list_for_each_entry_safe(en, nxt, &tbl->bucket[i], list) {
-			ip_vs_lblc_free(en);
-			atomic_dec(&tbl->entries);
-		}
-		write_unlock(&tbl->lock);
-	}
-}
-
-
-static inline void ip_vs_lblc_full_check(struct ip_vs_lblc_table *tbl)
-{
-	unsigned long now = jiffies;
-	int i, j;
-	struct ip_vs_lblc_entry *en, *nxt;
-
-	for (i=0, j=tbl->rover; i<IP_VS_LBLC_TAB_SIZE; i++) {
-		j = (j + 1) & IP_VS_LBLC_TAB_MASK;
-
-		write_lock(&tbl->lock);
-		list_for_each_entry_safe(en, nxt, &tbl->bucket[j], list) {
-			if (time_before(now,
-					en->lastuse + sysctl_ip_vs_lblc_expiration))
-				continue;
-
-			ip_vs_lblc_free(en);
-			atomic_dec(&tbl->entries);
-		}
-		write_unlock(&tbl->lock);
-	}
-	tbl->rover = j;
-}
-
-
-/*
- *      Periodical timer handler for IPVS lblc table
- *      It is used to collect stale entries when the number of entries
- *      exceeds the maximum size of the table.
- *
- *      Fixme: we probably need more complicated algorithm to collect
- *             entries that have not been used for a long time even
- *             if the number of entries doesn't exceed the maximum size
- *             of the table.
- *      The full expiration check is for this purpose now.
- */
-static void ip_vs_lblc_check_expire(unsigned long data)
-{
-	struct ip_vs_lblc_table *tbl;
-	unsigned long now = jiffies;
-	int goal;
-	int i, j;
-	struct ip_vs_lblc_entry *en, *nxt;
-
-	tbl = (struct ip_vs_lblc_table *)data;
-
-	if ((tbl->counter % COUNT_FOR_FULL_EXPIRATION) == 0) {
-		/* do full expiration check */
-		ip_vs_lblc_full_check(tbl);
-		tbl->counter = 1;
-		goto out;
-	}
-
-	if (atomic_read(&tbl->entries) <= tbl->max_size) {
-		tbl->counter++;
-		goto out;
-	}
-
-	goal = (atomic_read(&tbl->entries) - tbl->max_size)*4/3;
-	if (goal > tbl->max_size/2)
-		goal = tbl->max_size/2;
-
-	for (i=0, j=tbl->rover; i<IP_VS_LBLC_TAB_SIZE; i++) {
-		j = (j + 1) & IP_VS_LBLC_TAB_MASK;
-
-		write_lock(&tbl->lock);
-		list_for_each_entry_safe(en, nxt, &tbl->bucket[j], list) {
-			if (time_before(now, en->lastuse + ENTRY_TIMEOUT))
-				continue;
-
-			ip_vs_lblc_free(en);
-			atomic_dec(&tbl->entries);
-			goal--;
-		}
-		write_unlock(&tbl->lock);
-		if (goal <= 0)
-			break;
-	}
-	tbl->rover = j;
-
-  out:
-	mod_timer(&tbl->periodic_timer, jiffies+CHECK_EXPIRE_INTERVAL);
-}
-
-
-static int ip_vs_lblc_init_svc(struct ip_vs_service *svc)
-{
-	int i;
-	struct ip_vs_lblc_table *tbl;
-
-	/*
-	 *    Allocate the ip_vs_lblc_table for this service
-	 */
-	tbl = kmalloc(sizeof(struct ip_vs_lblc_table), GFP_ATOMIC);
-	if (tbl == NULL) {
-		IP_VS_ERR("ip_vs_lblc_init_svc(): no memory\n");
-		return -ENOMEM;
-	}
-	svc->sched_data = tbl;
-	IP_VS_DBG(6, "LBLC hash table (memory=%Zdbytes) allocated for "
-		  "current service\n",
-		  sizeof(struct ip_vs_lblc_table));
-
-	/*
-	 *    Initialize the hash buckets
-	 */
-	for (i=0; i<IP_VS_LBLC_TAB_SIZE; i++) {
-		INIT_LIST_HEAD(&tbl->bucket[i]);
-	}
-	rwlock_init(&tbl->lock);
-	tbl->max_size = IP_VS_LBLC_TAB_SIZE*16;
-	tbl->rover = 0;
-	tbl->counter = 1;
-
-	/*
-	 *    Hook periodic timer for garbage collection
-	 */
-	setup_timer(&tbl->periodic_timer, ip_vs_lblc_check_expire,
-			(unsigned long)tbl);
-	tbl->periodic_timer.expires = jiffies+CHECK_EXPIRE_INTERVAL;
-	add_timer(&tbl->periodic_timer);
-
-	return 0;
-}
-
-
-static int ip_vs_lblc_done_svc(struct ip_vs_service *svc)
-{
-	struct ip_vs_lblc_table *tbl = svc->sched_data;
-
-	/* remove periodic timer */
-	del_timer_sync(&tbl->periodic_timer);
-
-	/* got to clean up table entries here */
-	ip_vs_lblc_flush(tbl);
-
-	/* release the table itself */
-	kfree(svc->sched_data);
-	IP_VS_DBG(6, "LBLC hash table (memory=%Zdbytes) released\n",
-		  sizeof(struct ip_vs_lblc_table));
-
-	return 0;
-}
-
-
-static int ip_vs_lblc_update_svc(struct ip_vs_service *svc)
-{
-	return 0;
-}
-
-
-static inline struct ip_vs_dest *
-__ip_vs_wlc_schedule(struct ip_vs_service *svc, struct iphdr *iph)
-{
-	struct ip_vs_dest *dest, *least;
-	int loh, doh;
-
-	/*
-	 * We think the overhead of processing active connections is fifty
-	 * times higher than that of inactive connections in average. (This
-	 * fifty times might not be accurate, we will change it later.) We
-	 * use the following formula to estimate the overhead:
-	 *                dest->activeconns*50 + dest->inactconns
-	 * and the load:
-	 *                (dest overhead) / dest->weight
-	 *
-	 * Remember -- no floats in kernel mode!!!
-	 * The comparison of h1*w2 > h2*w1 is equivalent to that of
-	 *                h1/w1 > h2/w2
-	 * if every weight is larger than zero.
-	 *
-	 * The server with weight=0 is quiesced and will not receive any
-	 * new connection.
-	 */
-	list_for_each_entry(dest, &svc->destinations, n_list) {
-		if (dest->flags & IP_VS_DEST_F_OVERLOAD)
-			continue;
-		if (atomic_read(&dest->weight) > 0) {
-			least = dest;
-			loh = atomic_read(&least->activeconns) * 50
-				+ atomic_read(&least->inactconns);
-			goto nextstage;
-		}
-	}
-	return NULL;
-
-	/*
-	 *    Find the destination with the least load.
-	 */
-  nextstage:
-	list_for_each_entry_continue(dest, &svc->destinations, n_list) {
-		if (dest->flags & IP_VS_DEST_F_OVERLOAD)
-			continue;
-
-		doh = atomic_read(&dest->activeconns) * 50
-			+ atomic_read(&dest->inactconns);
-		if (loh * atomic_read(&dest->weight) >
-		    doh * atomic_read(&least->weight)) {
-			least = dest;
-			loh = doh;
-		}
-	}
-
-	IP_VS_DBG(6, "LBLC: server %d.%d.%d.%d:%d "
-		  "activeconns %d refcnt %d weight %d overhead %d\n",
-		  NIPQUAD(least->addr), ntohs(least->port),
-		  atomic_read(&least->activeconns),
-		  atomic_read(&least->refcnt),
-		  atomic_read(&least->weight), loh);
-
-	return least;
-}
-
-
-/*
- *   If this destination server is overloaded and there is a less loaded
- *   server, then return true.
- */
-static inline int
-is_overloaded(struct ip_vs_dest *dest, struct ip_vs_service *svc)
-{
-	if (atomic_read(&dest->activeconns) > atomic_read(&dest->weight)) {
-		struct ip_vs_dest *d;
-
-		list_for_each_entry(d, &svc->destinations, n_list) {
-			if (atomic_read(&d->activeconns)*2
-			    < atomic_read(&d->weight)) {
-				return 1;
-			}
-		}
-	}
-	return 0;
-}
-
-
-/*
- *    Locality-Based (weighted) Least-Connection scheduling
- */
-static struct ip_vs_dest *
-ip_vs_lblc_schedule(struct ip_vs_service *svc, const struct sk_buff *skb)
-{
-	struct ip_vs_dest *dest;
-	struct ip_vs_lblc_table *tbl;
-	struct ip_vs_lblc_entry *en;
-	struct iphdr *iph = ip_hdr(skb);
-
-	IP_VS_DBG(6, "ip_vs_lblc_schedule(): Scheduling...\n");
-
-	tbl = (struct ip_vs_lblc_table *)svc->sched_data;
-	en = ip_vs_lblc_get(tbl, iph->daddr);
-	if (en == NULL) {
-		dest = __ip_vs_wlc_schedule(svc, iph);
-		if (dest == NULL) {
-			IP_VS_DBG(1, "no destination available\n");
-			return NULL;
-		}
-		en = ip_vs_lblc_new(iph->daddr, dest);
-		if (en == NULL) {
-			return NULL;
-		}
-		ip_vs_lblc_hash(tbl, en);
-	} else {
-		dest = en->dest;
-		if (!(dest->flags & IP_VS_DEST_F_AVAILABLE)
-		    || atomic_read(&dest->weight) <= 0
-		    || is_overloaded(dest, svc)) {
-			dest = __ip_vs_wlc_schedule(svc, iph);
-			if (dest == NULL) {
-				IP_VS_DBG(1, "no destination available\n");
-				return NULL;
-			}
-			atomic_dec(&en->dest->refcnt);
-			atomic_inc(&dest->refcnt);
-			en->dest = dest;
-		}
-	}
-	en->lastuse = jiffies;
-
-	IP_VS_DBG(6, "LBLC: destination IP address %u.%u.%u.%u "
-		  "--> server %u.%u.%u.%u:%d\n",
-		  NIPQUAD(en->addr),
-		  NIPQUAD(dest->addr),
-		  ntohs(dest->port));
-
-	return dest;
-}
-
-
-/*
- *      IPVS LBLC Scheduler structure
- */
-static struct ip_vs_scheduler ip_vs_lblc_scheduler =
-{
-	.name =			"lblc",
-	.refcnt =		ATOMIC_INIT(0),
-	.module =		THIS_MODULE,
-	.n_list =		LIST_HEAD_INIT(ip_vs_lblc_scheduler.n_list),
-	.init_service =		ip_vs_lblc_init_svc,
-	.done_service =		ip_vs_lblc_done_svc,
-	.update_service =	ip_vs_lblc_update_svc,
-	.schedule =		ip_vs_lblc_schedule,
-};
-
-
-static int __init ip_vs_lblc_init(void)
-{
-	int ret;
-
-	sysctl_header = register_sysctl_paths(net_vs_ctl_path, vs_vars_table);
-	ret = register_ip_vs_scheduler(&ip_vs_lblc_scheduler);
-	if (ret)
-		unregister_sysctl_table(sysctl_header);
-	return ret;
-}
-
-
-static void __exit ip_vs_lblc_cleanup(void)
-{
-	unregister_sysctl_table(sysctl_header);
-	unregister_ip_vs_scheduler(&ip_vs_lblc_scheduler);
-}
-
-
-module_init(ip_vs_lblc_init);
-module_exit(ip_vs_lblc_cleanup);
-MODULE_LICENSE("GPL");
diff --git a/net/ipv4/ipvs/ip_vs_lblcr.c b/net/ipv4/ipvs/ip_vs_lblcr.c
deleted file mode 100644
index c234e73..0000000
--- a/net/ipv4/ipvs/ip_vs_lblcr.c
+++ /dev/null
@@ -1,760 +0,0 @@
-/*
- * IPVS:        Locality-Based Least-Connection with Replication scheduler
- *
- * Authors:     Wensong Zhang <wensong@gnuchina.org>
- *
- *              This program is free software; you can redistribute it and/or
- *              modify it under the terms of the GNU General Public License
- *              as published by the Free Software Foundation; either version
- *              2 of the License, or (at your option) any later version.
- *
- * Changes:
- *     Julian Anastasov        :    Added the missing (dest->weight>0)
- *                                  condition in the ip_vs_dest_set_max.
- *
- */
-
-/*
- * The lblc/r algorithm is as follows (pseudo code):
- *
- *       if serverSet[dest_ip] is null then
- *               n, serverSet[dest_ip] <- {weighted least-conn node};
- *       else
- *               n <- {least-conn (alive) node in serverSet[dest_ip]};
- *               if (n is null) OR
- *                  (n.conns>n.weight AND
- *                   there is a node m with m.conns<m.weight/2) then
- *                   n <- {weighted least-conn node};
- *                   add n to serverSet[dest_ip];
- *               if |serverSet[dest_ip]| > 1 AND
- *                   now - serverSet[dest_ip].lastMod > T then
- *                   m <- {most conn node in serverSet[dest_ip]};
- *                   remove m from serverSet[dest_ip];
- *       if serverSet[dest_ip] changed then
- *               serverSet[dest_ip].lastMod <- now;
- *
- *       return n;
- *
- */
-
-#include <linux/ip.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/skbuff.h>
-#include <linux/jiffies.h>
-
-/* for sysctl */
-#include <linux/fs.h>
-#include <linux/sysctl.h>
-#include <net/net_namespace.h>
-
-#include <net/ip_vs.h>
-
-
-/*
- *    It is for garbage collection of stale IPVS lblcr entries,
- *    when the table is full.
- */
-#define CHECK_EXPIRE_INTERVAL   (60*HZ)
-#define ENTRY_TIMEOUT           (6*60*HZ)
-
-/*
- *    It is for full expiration check.
- *    When there is no partial expiration check (garbage collection)
- *    in a half hour, do a full expiration check to collect stale
- *    entries that haven't been touched for a day.
- */
-#define COUNT_FOR_FULL_EXPIRATION   30
-static int sysctl_ip_vs_lblcr_expiration = 24*60*60*HZ;
-
-
-/*
- *     for IPVS lblcr entry hash table
- */
-#ifndef CONFIG_IP_VS_LBLCR_TAB_BITS
-#define CONFIG_IP_VS_LBLCR_TAB_BITS      10
-#endif
-#define IP_VS_LBLCR_TAB_BITS     CONFIG_IP_VS_LBLCR_TAB_BITS
-#define IP_VS_LBLCR_TAB_SIZE     (1 << IP_VS_LBLCR_TAB_BITS)
-#define IP_VS_LBLCR_TAB_MASK     (IP_VS_LBLCR_TAB_SIZE - 1)
-
-
-/*
- *      IPVS destination set structure and operations
- */
-struct ip_vs_dest_list {
-	struct ip_vs_dest_list  *next;          /* list link */
-	struct ip_vs_dest       *dest;          /* destination server */
-};
-
-struct ip_vs_dest_set {
-	atomic_t                size;           /* set size */
-	unsigned long           lastmod;        /* last modified time */
-	struct ip_vs_dest_list  *list;          /* destination list */
-	rwlock_t	        lock;           /* lock for this list */
-};
-
-
-static struct ip_vs_dest_list *
-ip_vs_dest_set_insert(struct ip_vs_dest_set *set, struct ip_vs_dest *dest)
-{
-	struct ip_vs_dest_list *e;
-
-	for (e=set->list; e!=NULL; e=e->next) {
-		if (e->dest == dest)
-			/* already existed */
-			return NULL;
-	}
-
-	e = kmalloc(sizeof(struct ip_vs_dest_list), GFP_ATOMIC);
-	if (e == NULL) {
-		IP_VS_ERR("ip_vs_dest_set_insert(): no memory\n");
-		return NULL;
-	}
-
-	atomic_inc(&dest->refcnt);
-	e->dest = dest;
-
-	/* link it to the list */
-	write_lock(&set->lock);
-	e->next = set->list;
-	set->list = e;
-	atomic_inc(&set->size);
-	write_unlock(&set->lock);
-
-	set->lastmod = jiffies;
-	return e;
-}
-
-static void
-ip_vs_dest_set_erase(struct ip_vs_dest_set *set, struct ip_vs_dest *dest)
-{
-	struct ip_vs_dest_list *e, **ep;
-
-	write_lock(&set->lock);
-	for (ep=&set->list, e=*ep; e!=NULL; e=*ep) {
-		if (e->dest == dest) {
-			/* HIT */
-			*ep = e->next;
-			atomic_dec(&set->size);
-			set->lastmod = jiffies;
-			atomic_dec(&e->dest->refcnt);
-			kfree(e);
-			break;
-		}
-		ep = &e->next;
-	}
-	write_unlock(&set->lock);
-}
-
-static void ip_vs_dest_set_eraseall(struct ip_vs_dest_set *set)
-{
-	struct ip_vs_dest_list *e, **ep;
-
-	write_lock(&set->lock);
-	for (ep=&set->list, e=*ep; e!=NULL; e=*ep) {
-		*ep = e->next;
-		/*
-		 * We don't kfree dest because it is refered either
-		 * by its service or by the trash dest list.
-		 */
-		atomic_dec(&e->dest->refcnt);
-		kfree(e);
-	}
-	write_unlock(&set->lock);
-}
-
-/* get weighted least-connection node in the destination set */
-static inline struct ip_vs_dest *ip_vs_dest_set_min(struct ip_vs_dest_set *set)
-{
-	register struct ip_vs_dest_list *e;
-	struct ip_vs_dest *dest, *least;
-	int loh, doh;
-
-	if (set == NULL)
-		return NULL;
-
-	read_lock(&set->lock);
-	/* select the first destination server, whose weight > 0 */
-	for (e=set->list; e!=NULL; e=e->next) {
-		least = e->dest;
-		if (least->flags & IP_VS_DEST_F_OVERLOAD)
-			continue;
-
-		if ((atomic_read(&least->weight) > 0)
-		    && (least->flags & IP_VS_DEST_F_AVAILABLE)) {
-			loh = atomic_read(&least->activeconns) * 50
-				+ atomic_read(&least->inactconns);
-			goto nextstage;
-		}
-	}
-	read_unlock(&set->lock);
-	return NULL;
-
-	/* find the destination with the weighted least load */
-  nextstage:
-	for (e=e->next; e!=NULL; e=e->next) {
-		dest = e->dest;
-		if (dest->flags & IP_VS_DEST_F_OVERLOAD)
-			continue;
-
-		doh = atomic_read(&dest->activeconns) * 50
-			+ atomic_read(&dest->inactconns);
-		if ((loh * atomic_read(&dest->weight) >
-		     doh * atomic_read(&least->weight))
-		    && (dest->flags & IP_VS_DEST_F_AVAILABLE)) {
-			least = dest;
-			loh = doh;
-		}
-	}
-	read_unlock(&set->lock);
-
-	IP_VS_DBG(6, "ip_vs_dest_set_min: server %d.%d.%d.%d:%d "
-		  "activeconns %d refcnt %d weight %d overhead %d\n",
-		  NIPQUAD(least->addr), ntohs(least->port),
-		  atomic_read(&least->activeconns),
-		  atomic_read(&least->refcnt),
-		  atomic_read(&least->weight), loh);
-	return least;
-}
-
-
-/* get weighted most-connection node in the destination set */
-static inline struct ip_vs_dest *ip_vs_dest_set_max(struct ip_vs_dest_set *set)
-{
-	register struct ip_vs_dest_list *e;
-	struct ip_vs_dest *dest, *most;
-	int moh, doh;
-
-	if (set == NULL)
-		return NULL;
-
-	read_lock(&set->lock);
-	/* select the first destination server, whose weight > 0 */
-	for (e=set->list; e!=NULL; e=e->next) {
-		most = e->dest;
-		if (atomic_read(&most->weight) > 0) {
-			moh = atomic_read(&most->activeconns) * 50
-				+ atomic_read(&most->inactconns);
-			goto nextstage;
-		}
-	}
-	read_unlock(&set->lock);
-	return NULL;
-
-	/* find the destination with the weighted most load */
-  nextstage:
-	for (e=e->next; e!=NULL; e=e->next) {
-		dest = e->dest;
-		doh = atomic_read(&dest->activeconns) * 50
-			+ atomic_read(&dest->inactconns);
-		/* moh/mw < doh/dw ==> moh*dw < doh*mw, where mw,dw>0 */
-		if ((moh * atomic_read(&dest->weight) <
-		     doh * atomic_read(&most->weight))
-		    && (atomic_read(&dest->weight) > 0)) {
-			most = dest;
-			moh = doh;
-		}
-	}
-	read_unlock(&set->lock);
-
-	IP_VS_DBG(6, "ip_vs_dest_set_max: server %d.%d.%d.%d:%d "
-		  "activeconns %d refcnt %d weight %d overhead %d\n",
-		  NIPQUAD(most->addr), ntohs(most->port),
-		  atomic_read(&most->activeconns),
-		  atomic_read(&most->refcnt),
-		  atomic_read(&most->weight), moh);
-	return most;
-}
-
-
-/*
- *      IPVS lblcr entry represents an association between destination
- *      IP address and its destination server set
- */
-struct ip_vs_lblcr_entry {
-	struct list_head        list;
-	__be32                   addr;           /* destination IP address */
-	struct ip_vs_dest_set   set;            /* destination server set */
-	unsigned long           lastuse;        /* last used time */
-};
-
-
-/*
- *      IPVS lblcr hash table
- */
-struct ip_vs_lblcr_table {
-	rwlock_t	        lock;           /* lock for this table */
-	struct list_head        bucket[IP_VS_LBLCR_TAB_SIZE];  /* hash bucket */
-	atomic_t                entries;        /* number of entries */
-	int                     max_size;       /* maximum size of entries */
-	struct timer_list       periodic_timer; /* collect stale entries */
-	int                     rover;          /* rover for expire check */
-	int                     counter;        /* counter for no expire */
-};
-
-
-/*
- *      IPVS LBLCR sysctl table
- */
-
-static ctl_table vs_vars_table[] = {
-	{
-		.procname	= "lblcr_expiration",
-		.data		= &sysctl_ip_vs_lblcr_expiration,
-		.maxlen		= sizeof(int),
-		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_jiffies,
-	},
-	{ .ctl_name = 0 }
-};
-
-static struct ctl_table_header * sysctl_header;
-
-/*
- *      new/free a ip_vs_lblcr_entry, which is a mapping of a destination
- *      IP address to a server.
- */
-static inline struct ip_vs_lblcr_entry *ip_vs_lblcr_new(__be32 daddr)
-{
-	struct ip_vs_lblcr_entry *en;
-
-	en = kmalloc(sizeof(struct ip_vs_lblcr_entry), GFP_ATOMIC);
-	if (en == NULL) {
-		IP_VS_ERR("ip_vs_lblcr_new(): no memory\n");
-		return NULL;
-	}
-
-	INIT_LIST_HEAD(&en->list);
-	en->addr = daddr;
-
-	/* initilize its dest set */
-	atomic_set(&(en->set.size), 0);
-	en->set.list = NULL;
-	rwlock_init(&en->set.lock);
-
-	return en;
-}
-
-
-static inline void ip_vs_lblcr_free(struct ip_vs_lblcr_entry *en)
-{
-	list_del(&en->list);
-	ip_vs_dest_set_eraseall(&en->set);
-	kfree(en);
-}
-
-
-/*
- *	Returns hash value for IPVS LBLCR entry
- */
-static inline unsigned ip_vs_lblcr_hashkey(__be32 addr)
-{
-	return (ntohl(addr)*2654435761UL) & IP_VS_LBLCR_TAB_MASK;
-}
-
-
-/*
- *	Hash an entry in the ip_vs_lblcr_table.
- *	returns bool success.
- */
-static int
-ip_vs_lblcr_hash(struct ip_vs_lblcr_table *tbl, struct ip_vs_lblcr_entry *en)
-{
-	unsigned hash;
-
-	if (!list_empty(&en->list)) {
-		IP_VS_ERR("ip_vs_lblcr_hash(): request for already hashed, "
-			  "called from %p\n", __builtin_return_address(0));
-		return 0;
-	}
-
-	/*
-	 *	Hash by destination IP address
-	 */
-	hash = ip_vs_lblcr_hashkey(en->addr);
-
-	write_lock(&tbl->lock);
-	list_add(&en->list, &tbl->bucket[hash]);
-	atomic_inc(&tbl->entries);
-	write_unlock(&tbl->lock);
-
-	return 1;
-}
-
-
-/*
- *  Get ip_vs_lblcr_entry associated with supplied parameters.
- */
-static inline struct ip_vs_lblcr_entry *
-ip_vs_lblcr_get(struct ip_vs_lblcr_table *tbl, __be32 addr)
-{
-	unsigned hash;
-	struct ip_vs_lblcr_entry *en;
-
-	hash = ip_vs_lblcr_hashkey(addr);
-
-	read_lock(&tbl->lock);
-
-	list_for_each_entry(en, &tbl->bucket[hash], list) {
-		if (en->addr == addr) {
-			/* HIT */
-			read_unlock(&tbl->lock);
-			return en;
-		}
-	}
-
-	read_unlock(&tbl->lock);
-
-	return NULL;
-}
-
-
-/*
- *      Flush all the entries of the specified table.
- */
-static void ip_vs_lblcr_flush(struct ip_vs_lblcr_table *tbl)
-{
-	int i;
-	struct ip_vs_lblcr_entry *en, *nxt;
-
-	for (i=0; i<IP_VS_LBLCR_TAB_SIZE; i++) {
-		write_lock(&tbl->lock);
-		list_for_each_entry_safe(en, nxt, &tbl->bucket[i], list) {
-			ip_vs_lblcr_free(en);
-			atomic_dec(&tbl->entries);
-		}
-		write_unlock(&tbl->lock);
-	}
-}
-
-
-static inline void ip_vs_lblcr_full_check(struct ip_vs_lblcr_table *tbl)
-{
-	unsigned long now = jiffies;
-	int i, j;
-	struct ip_vs_lblcr_entry *en, *nxt;
-
-	for (i=0, j=tbl->rover; i<IP_VS_LBLCR_TAB_SIZE; i++) {
-		j = (j + 1) & IP_VS_LBLCR_TAB_MASK;
-
-		write_lock(&tbl->lock);
-		list_for_each_entry_safe(en, nxt, &tbl->bucket[j], list) {
-			if (time_after(en->lastuse+sysctl_ip_vs_lblcr_expiration,
-				       now))
-				continue;
-
-			ip_vs_lblcr_free(en);
-			atomic_dec(&tbl->entries);
-		}
-		write_unlock(&tbl->lock);
-	}
-	tbl->rover = j;
-}
-
-
-/*
- *      Periodical timer handler for IPVS lblcr table
- *      It is used to collect stale entries when the number of entries
- *      exceeds the maximum size of the table.
- *
- *      Fixme: we probably need more complicated algorithm to collect
- *             entries that have not been used for a long time even
- *             if the number of entries doesn't exceed the maximum size
- *             of the table.
- *      The full expiration check is for this purpose now.
- */
-static void ip_vs_lblcr_check_expire(unsigned long data)
-{
-	struct ip_vs_lblcr_table *tbl;
-	unsigned long now = jiffies;
-	int goal;
-	int i, j;
-	struct ip_vs_lblcr_entry *en, *nxt;
-
-	tbl = (struct ip_vs_lblcr_table *)data;
-
-	if ((tbl->counter % COUNT_FOR_FULL_EXPIRATION) == 0) {
-		/* do full expiration check */
-		ip_vs_lblcr_full_check(tbl);
-		tbl->counter = 1;
-		goto out;
-	}
-
-	if (atomic_read(&tbl->entries) <= tbl->max_size) {
-		tbl->counter++;
-		goto out;
-	}
-
-	goal = (atomic_read(&tbl->entries) - tbl->max_size)*4/3;
-	if (goal > tbl->max_size/2)
-		goal = tbl->max_size/2;
-
-	for (i=0, j=tbl->rover; i<IP_VS_LBLCR_TAB_SIZE; i++) {
-		j = (j + 1) & IP_VS_LBLCR_TAB_MASK;
-
-		write_lock(&tbl->lock);
-		list_for_each_entry_safe(en, nxt, &tbl->bucket[j], list) {
-			if (time_before(now, en->lastuse+ENTRY_TIMEOUT))
-				continue;
-
-			ip_vs_lblcr_free(en);
-			atomic_dec(&tbl->entries);
-			goal--;
-		}
-		write_unlock(&tbl->lock);
-		if (goal <= 0)
-			break;
-	}
-	tbl->rover = j;
-
-  out:
-	mod_timer(&tbl->periodic_timer, jiffies+CHECK_EXPIRE_INTERVAL);
-}
-
-static int ip_vs_lblcr_init_svc(struct ip_vs_service *svc)
-{
-	int i;
-	struct ip_vs_lblcr_table *tbl;
-
-	/*
-	 *    Allocate the ip_vs_lblcr_table for this service
-	 */
-	tbl = kmalloc(sizeof(struct ip_vs_lblcr_table), GFP_ATOMIC);
-	if (tbl == NULL) {
-		IP_VS_ERR("ip_vs_lblcr_init_svc(): no memory\n");
-		return -ENOMEM;
-	}
-	svc->sched_data = tbl;
-	IP_VS_DBG(6, "LBLCR hash table (memory=%Zdbytes) allocated for "
-		  "current service\n",
-		  sizeof(struct ip_vs_lblcr_table));
-
-	/*
-	 *    Initialize the hash buckets
-	 */
-	for (i=0; i<IP_VS_LBLCR_TAB_SIZE; i++) {
-		INIT_LIST_HEAD(&tbl->bucket[i]);
-	}
-	rwlock_init(&tbl->lock);
-	tbl->max_size = IP_VS_LBLCR_TAB_SIZE*16;
-	tbl->rover = 0;
-	tbl->counter = 1;
-
-	/*
-	 *    Hook periodic timer for garbage collection
-	 */
-	setup_timer(&tbl->periodic_timer, ip_vs_lblcr_check_expire,
-			(unsigned long)tbl);
-	tbl->periodic_timer.expires = jiffies+CHECK_EXPIRE_INTERVAL;
-	add_timer(&tbl->periodic_timer);
-
-	return 0;
-}
-
-
-static int ip_vs_lblcr_done_svc(struct ip_vs_service *svc)
-{
-	struct ip_vs_lblcr_table *tbl = svc->sched_data;
-
-	/* remove periodic timer */
-	del_timer_sync(&tbl->periodic_timer);
-
-	/* got to clean up table entries here */
-	ip_vs_lblcr_flush(tbl);
-
-	/* release the table itself */
-	kfree(svc->sched_data);
-	IP_VS_DBG(6, "LBLCR hash table (memory=%Zdbytes) released\n",
-		  sizeof(struct ip_vs_lblcr_table));
-
-	return 0;
-}
-
-
-static int ip_vs_lblcr_update_svc(struct ip_vs_service *svc)
-{
-	return 0;
-}
-
-
-static inline struct ip_vs_dest *
-__ip_vs_wlc_schedule(struct ip_vs_service *svc, struct iphdr *iph)
-{
-	struct ip_vs_dest *dest, *least;
-	int loh, doh;
-
-	/*
-	 * We think the overhead of processing active connections is fifty
-	 * times higher than that of inactive connections in average. (This
-	 * fifty times might not be accurate, we will change it later.) We
-	 * use the following formula to estimate the overhead:
-	 *                dest->activeconns*50 + dest->inactconns
-	 * and the load:
-	 *                (dest overhead) / dest->weight
-	 *
-	 * Remember -- no floats in kernel mode!!!
-	 * The comparison of h1*w2 > h2*w1 is equivalent to that of
-	 *                h1/w1 > h2/w2
-	 * if every weight is larger than zero.
-	 *
-	 * The server with weight=0 is quiesced and will not receive any
-	 * new connection.
-	 */
-	list_for_each_entry(dest, &svc->destinations, n_list) {
-		if (dest->flags & IP_VS_DEST_F_OVERLOAD)
-			continue;
-
-		if (atomic_read(&dest->weight) > 0) {
-			least = dest;
-			loh = atomic_read(&least->activeconns) * 50
-				+ atomic_read(&least->inactconns);
-			goto nextstage;
-		}
-	}
-	return NULL;
-
-	/*
-	 *    Find the destination with the least load.
-	 */
-  nextstage:
-	list_for_each_entry_continue(dest, &svc->destinations, n_list) {
-		if (dest->flags & IP_VS_DEST_F_OVERLOAD)
-			continue;
-
-		doh = atomic_read(&dest->activeconns) * 50
-			+ atomic_read(&dest->inactconns);
-		if (loh * atomic_read(&dest->weight) >
-		    doh * atomic_read(&least->weight)) {
-			least = dest;
-			loh = doh;
-		}
-	}
-
-	IP_VS_DBG(6, "LBLCR: server %d.%d.%d.%d:%d "
-		  "activeconns %d refcnt %d weight %d overhead %d\n",
-		  NIPQUAD(least->addr), ntohs(least->port),
-		  atomic_read(&least->activeconns),
-		  atomic_read(&least->refcnt),
-		  atomic_read(&least->weight), loh);
-
-	return least;
-}
-
-
-/*
- *   If this destination server is overloaded and there is a less loaded
- *   server, then return true.
- */
-static inline int
-is_overloaded(struct ip_vs_dest *dest, struct ip_vs_service *svc)
-{
-	if (atomic_read(&dest->activeconns) > atomic_read(&dest->weight)) {
-		struct ip_vs_dest *d;
-
-		list_for_each_entry(d, &svc->destinations, n_list) {
-			if (atomic_read(&d->activeconns)*2
-			    < atomic_read(&d->weight)) {
-				return 1;
-			}
-		}
-	}
-	return 0;
-}
-
-
-/*
- *    Locality-Based (weighted) Least-Connection scheduling
- */
-static struct ip_vs_dest *
-ip_vs_lblcr_schedule(struct ip_vs_service *svc, const struct sk_buff *skb)
-{
-	struct ip_vs_dest *dest;
-	struct ip_vs_lblcr_table *tbl;
-	struct ip_vs_lblcr_entry *en;
-	struct iphdr *iph = ip_hdr(skb);
-
-	IP_VS_DBG(6, "ip_vs_lblcr_schedule(): Scheduling...\n");
-
-	tbl = (struct ip_vs_lblcr_table *)svc->sched_data;
-	en = ip_vs_lblcr_get(tbl, iph->daddr);
-	if (en == NULL) {
-		dest = __ip_vs_wlc_schedule(svc, iph);
-		if (dest == NULL) {
-			IP_VS_DBG(1, "no destination available\n");
-			return NULL;
-		}
-		en = ip_vs_lblcr_new(iph->daddr);
-		if (en == NULL) {
-			return NULL;
-		}
-		ip_vs_dest_set_insert(&en->set, dest);
-		ip_vs_lblcr_hash(tbl, en);
-	} else {
-		dest = ip_vs_dest_set_min(&en->set);
-		if (!dest || is_overloaded(dest, svc)) {
-			dest = __ip_vs_wlc_schedule(svc, iph);
-			if (dest == NULL) {
-				IP_VS_DBG(1, "no destination available\n");
-				return NULL;
-			}
-			ip_vs_dest_set_insert(&en->set, dest);
-		}
-		if (atomic_read(&en->set.size) > 1 &&
-		    jiffies-en->set.lastmod > sysctl_ip_vs_lblcr_expiration) {
-			struct ip_vs_dest *m;
-			m = ip_vs_dest_set_max(&en->set);
-			if (m)
-				ip_vs_dest_set_erase(&en->set, m);
-		}
-	}
-	en->lastuse = jiffies;
-
-	IP_VS_DBG(6, "LBLCR: destination IP address %u.%u.%u.%u "
-		  "--> server %u.%u.%u.%u:%d\n",
-		  NIPQUAD(en->addr),
-		  NIPQUAD(dest->addr),
-		  ntohs(dest->port));
-
-	return dest;
-}
-
-
-/*
- *      IPVS LBLCR Scheduler structure
- */
-static struct ip_vs_scheduler ip_vs_lblcr_scheduler =
-{
-	.name =			"lblcr",
-	.refcnt =		ATOMIC_INIT(0),
-	.module =		THIS_MODULE,
-	.n_list =		LIST_HEAD_INIT(ip_vs_lblcr_scheduler.n_list),
-	.init_service =		ip_vs_lblcr_init_svc,
-	.done_service =		ip_vs_lblcr_done_svc,
-	.update_service =	ip_vs_lblcr_update_svc,
-	.schedule =		ip_vs_lblcr_schedule,
-};
-
-
-static int __init ip_vs_lblcr_init(void)
-{
-	int ret;
-
-	sysctl_header = register_sysctl_paths(net_vs_ctl_path, vs_vars_table);
-	ret = register_ip_vs_scheduler(&ip_vs_lblcr_scheduler);
-	if (ret)
-		unregister_sysctl_table(sysctl_header);
-	return ret;
-}
-
-
-static void __exit ip_vs_lblcr_cleanup(void)
-{
-	unregister_sysctl_table(sysctl_header);
-	unregister_ip_vs_scheduler(&ip_vs_lblcr_scheduler);
-}
-
-
-module_init(ip_vs_lblcr_init);
-module_exit(ip_vs_lblcr_cleanup);
-MODULE_LICENSE("GPL");
diff --git a/net/ipv4/ipvs/ip_vs_lc.c b/net/ipv4/ipvs/ip_vs_lc.c
deleted file mode 100644
index ebcdbf7..0000000
--- a/net/ipv4/ipvs/ip_vs_lc.c
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * IPVS:        Least-Connection Scheduling module
- *
- * Authors:     Wensong Zhang <wensong@linuxvirtualserver.org>
- *
- *              This program is free software; you can redistribute it and/or
- *              modify it under the terms of the GNU General Public License
- *              as published by the Free Software Foundation; either version
- *              2 of the License, or (at your option) any later version.
- *
- * Changes:
- *     Wensong Zhang            :     added the ip_vs_lc_update_svc
- *     Wensong Zhang            :     added any dest with weight=0 is quiesced
- *
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-
-#include <net/ip_vs.h>
-
-
-static int ip_vs_lc_init_svc(struct ip_vs_service *svc)
-{
-	return 0;
-}
-
-
-static int ip_vs_lc_done_svc(struct ip_vs_service *svc)
-{
-	return 0;
-}
-
-
-static int ip_vs_lc_update_svc(struct ip_vs_service *svc)
-{
-	return 0;
-}
-
-
-static inline unsigned int
-ip_vs_lc_dest_overhead(struct ip_vs_dest *dest)
-{
-	/*
-	 * We think the overhead of processing active connections is 256
-	 * times higher than that of inactive connections in average. (This
-	 * 256 times might not be accurate, we will change it later) We
-	 * use the following formula to estimate the overhead now:
-	 *		  dest->activeconns*256 + dest->inactconns
-	 */
-	return (atomic_read(&dest->activeconns) << 8) +
-		atomic_read(&dest->inactconns);
-}
-
-
-/*
- *	Least Connection scheduling
- */
-static struct ip_vs_dest *
-ip_vs_lc_schedule(struct ip_vs_service *svc, const struct sk_buff *skb)
-{
-	struct ip_vs_dest *dest, *least = NULL;
-	unsigned int loh = 0, doh;
-
-	IP_VS_DBG(6, "ip_vs_lc_schedule(): Scheduling...\n");
-
-	/*
-	 * Simply select the server with the least number of
-	 *        (activeconns<<5) + inactconns
-	 * Except whose weight is equal to zero.
-	 * If the weight is equal to zero, it means that the server is
-	 * quiesced, the existing connections to the server still get
-	 * served, but no new connection is assigned to the server.
-	 */
-
-	list_for_each_entry(dest, &svc->destinations, n_list) {
-		if ((dest->flags & IP_VS_DEST_F_OVERLOAD) ||
-		    atomic_read(&dest->weight) == 0)
-			continue;
-		doh = ip_vs_lc_dest_overhead(dest);
-		if (!least || doh < loh) {
-			least = dest;
-			loh = doh;
-		}
-	}
-
-	if (least)
-	IP_VS_DBG(6, "LC: server %u.%u.%u.%u:%u activeconns %d inactconns %d\n",
-		  NIPQUAD(least->addr), ntohs(least->port),
-		  atomic_read(&least->activeconns),
-		  atomic_read(&least->inactconns));
-
-	return least;
-}
-
-
-static struct ip_vs_scheduler ip_vs_lc_scheduler = {
-	.name =			"lc",
-	.refcnt =		ATOMIC_INIT(0),
-	.module =		THIS_MODULE,
-	.n_list =		LIST_HEAD_INIT(ip_vs_lc_scheduler.n_list),
-	.init_service =		ip_vs_lc_init_svc,
-	.done_service =		ip_vs_lc_done_svc,
-	.update_service =	ip_vs_lc_update_svc,
-	.schedule =		ip_vs_lc_schedule,
-};
-
-
-static int __init ip_vs_lc_init(void)
-{
-	return register_ip_vs_scheduler(&ip_vs_lc_scheduler) ;
-}
-
-static void __exit ip_vs_lc_cleanup(void)
-{
-	unregister_ip_vs_scheduler(&ip_vs_lc_scheduler);
-}
-
-module_init(ip_vs_lc_init);
-module_exit(ip_vs_lc_cleanup);
-MODULE_LICENSE("GPL");
diff --git a/net/ipv4/ipvs/ip_vs_nq.c b/net/ipv4/ipvs/ip_vs_nq.c
deleted file mode 100644
index 92f3a67..0000000
--- a/net/ipv4/ipvs/ip_vs_nq.c
+++ /dev/null
@@ -1,159 +0,0 @@
-/*
- * IPVS:        Never Queue scheduling module
- *
- * Authors:     Wensong Zhang <wensong@linuxvirtualserver.org>
- *
- *              This program is free software; you can redistribute it and/or
- *              modify it under the terms of the GNU General Public License
- *              as published by the Free Software Foundation; either version
- *              2 of the License, or (at your option) any later version.
- *
- * Changes:
- *
- */
-
-/*
- * The NQ algorithm adopts a two-speed model. When there is an idle server
- * available, the job will be sent to the idle server, instead of waiting
- * for a fast one. When there is no idle server available, the job will be
- * sent to the server that minimize its expected delay (The Shortest
- * Expected Delay scheduling algorithm).
- *
- * See the following paper for more information:
- * A. Weinrib and S. Shenker, Greed is not enough: Adaptive load sharing
- * in large heterogeneous systems. In Proceedings IEEE INFOCOM'88,
- * pages 986-994, 1988.
- *
- * Thanks must go to Marko Buuri <marko@buuri.name> for talking NQ to me.
- *
- * The difference between NQ and SED is that NQ can improve overall
- * system utilization.
- *
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-
-#include <net/ip_vs.h>
-
-
-static int
-ip_vs_nq_init_svc(struct ip_vs_service *svc)
-{
-	return 0;
-}
-
-
-static int
-ip_vs_nq_done_svc(struct ip_vs_service *svc)
-{
-	return 0;
-}
-
-
-static int
-ip_vs_nq_update_svc(struct ip_vs_service *svc)
-{
-	return 0;
-}
-
-
-static inline unsigned int
-ip_vs_nq_dest_overhead(struct ip_vs_dest *dest)
-{
-	/*
-	 * We only use the active connection number in the cost
-	 * calculation here.
-	 */
-	return atomic_read(&dest->activeconns) + 1;
-}
-
-
-/*
- *	Weighted Least Connection scheduling
- */
-static struct ip_vs_dest *
-ip_vs_nq_schedule(struct ip_vs_service *svc, const struct sk_buff *skb)
-{
-	struct ip_vs_dest *dest, *least = NULL;
-	unsigned int loh = 0, doh;
-
-	IP_VS_DBG(6, "ip_vs_nq_schedule(): Scheduling...\n");
-
-	/*
-	 * We calculate the load of each dest server as follows:
-	 *	(server expected overhead) / dest->weight
-	 *
-	 * Remember -- no floats in kernel mode!!!
-	 * The comparison of h1*w2 > h2*w1 is equivalent to that of
-	 *		  h1/w1 > h2/w2
-	 * if every weight is larger than zero.
-	 *
-	 * The server with weight=0 is quiesced and will not receive any
-	 * new connections.
-	 */
-
-	list_for_each_entry(dest, &svc->destinations, n_list) {
-
-		if (dest->flags & IP_VS_DEST_F_OVERLOAD ||
-		    !atomic_read(&dest->weight))
-			continue;
-
-		doh = ip_vs_nq_dest_overhead(dest);
-
-		/* return the server directly if it is idle */
-		if (atomic_read(&dest->activeconns) == 0) {
-			least = dest;
-			loh = doh;
-			goto out;
-		}
-
-		if (!least ||
-		    (loh * atomic_read(&dest->weight) >
-		     doh * atomic_read(&least->weight))) {
-			least = dest;
-			loh = doh;
-		}
-	}
-
-	if (!least)
-		return NULL;
-
-  out:
-	IP_VS_DBG(6, "NQ: server %u.%u.%u.%u:%u "
-		  "activeconns %d refcnt %d weight %d overhead %d\n",
-		  NIPQUAD(least->addr), ntohs(least->port),
-		  atomic_read(&least->activeconns),
-		  atomic_read(&least->refcnt),
-		  atomic_read(&least->weight), loh);
-
-	return least;
-}
-
-
-static struct ip_vs_scheduler ip_vs_nq_scheduler =
-{
-	.name =			"nq",
-	.refcnt =		ATOMIC_INIT(0),
-	.module =		THIS_MODULE,
-	.n_list =		LIST_HEAD_INIT(ip_vs_nq_scheduler.n_list),
-	.init_service =		ip_vs_nq_init_svc,
-	.done_service =		ip_vs_nq_done_svc,
-	.update_service =	ip_vs_nq_update_svc,
-	.schedule =		ip_vs_nq_schedule,
-};
-
-
-static int __init ip_vs_nq_init(void)
-{
-	return register_ip_vs_scheduler(&ip_vs_nq_scheduler);
-}
-
-static void __exit ip_vs_nq_cleanup(void)
-{
-	unregister_ip_vs_scheduler(&ip_vs_nq_scheduler);
-}
-
-module_init(ip_vs_nq_init);
-module_exit(ip_vs_nq_cleanup);
-MODULE_LICENSE("GPL");
diff --git a/net/ipv4/ipvs/ip_vs_proto.c b/net/ipv4/ipvs/ip_vs_proto.c
deleted file mode 100644
index 6099a88..0000000
--- a/net/ipv4/ipvs/ip_vs_proto.c
+++ /dev/null
@@ -1,233 +0,0 @@
-/*
- * ip_vs_proto.c: transport protocol load balancing support for IPVS
- *
- * Authors:     Wensong Zhang <wensong@linuxvirtualserver.org>
- *              Julian Anastasov <ja@ssi.bg>
- *
- *              This program is free software; you can redistribute it and/or
- *              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.
- *
- * Changes:
- *
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/skbuff.h>
-#include <linux/in.h>
-#include <linux/ip.h>
-#include <net/protocol.h>
-#include <net/tcp.h>
-#include <net/udp.h>
-#include <asm/system.h>
-#include <linux/stat.h>
-#include <linux/proc_fs.h>
-
-#include <net/ip_vs.h>
-
-
-/*
- * IPVS protocols can only be registered/unregistered when the ipvs
- * module is loaded/unloaded, so no lock is needed in accessing the
- * ipvs protocol table.
- */
-
-#define IP_VS_PROTO_TAB_SIZE		32	/* must be power of 2 */
-#define IP_VS_PROTO_HASH(proto)		((proto) & (IP_VS_PROTO_TAB_SIZE-1))
-
-static struct ip_vs_protocol *ip_vs_proto_table[IP_VS_PROTO_TAB_SIZE];
-
-
-/*
- *	register an ipvs protocol
- */
-static int __used __init register_ip_vs_protocol(struct ip_vs_protocol *pp)
-{
-	unsigned hash = IP_VS_PROTO_HASH(pp->protocol);
-
-	pp->next = ip_vs_proto_table[hash];
-	ip_vs_proto_table[hash] = pp;
-
-	if (pp->init != NULL)
-		pp->init(pp);
-
-	return 0;
-}
-
-
-/*
- *	unregister an ipvs protocol
- */
-static int unregister_ip_vs_protocol(struct ip_vs_protocol *pp)
-{
-	struct ip_vs_protocol **pp_p;
-	unsigned hash = IP_VS_PROTO_HASH(pp->protocol);
-
-	pp_p = &ip_vs_proto_table[hash];
-	for (; *pp_p; pp_p = &(*pp_p)->next) {
-		if (*pp_p == pp) {
-			*pp_p = pp->next;
-			if (pp->exit != NULL)
-				pp->exit(pp);
-			return 0;
-		}
-	}
-
-	return -ESRCH;
-}
-
-
-/*
- *	get ip_vs_protocol object by its proto.
- */
-struct ip_vs_protocol * ip_vs_proto_get(unsigned short proto)
-{
-	struct ip_vs_protocol *pp;
-	unsigned hash = IP_VS_PROTO_HASH(proto);
-
-	for (pp = ip_vs_proto_table[hash]; pp; pp = pp->next) {
-		if (pp->protocol == proto)
-			return pp;
-	}
-
-	return NULL;
-}
-
-
-/*
- *	Propagate event for state change to all protocols
- */
-void ip_vs_protocol_timeout_change(int flags)
-{
-	struct ip_vs_protocol *pp;
-	int i;
-
-	for (i = 0; i < IP_VS_PROTO_TAB_SIZE; i++) {
-		for (pp = ip_vs_proto_table[i]; pp; pp = pp->next) {
-			if (pp->timeout_change)
-				pp->timeout_change(pp, flags);
-		}
-	}
-}
-
-
-int *
-ip_vs_create_timeout_table(int *table, int size)
-{
-	return kmemdup(table, size, GFP_ATOMIC);
-}
-
-
-/*
- *	Set timeout value for state specified by name
- */
-int
-ip_vs_set_state_timeout(int *table, int num, char **names, char *name, int to)
-{
-	int i;
-
-	if (!table || !name || !to)
-		return -EINVAL;
-
-	for (i = 0; i < num; i++) {
-		if (strcmp(names[i], name))
-			continue;
-		table[i] = to * HZ;
-		return 0;
-	}
-	return -ENOENT;
-}
-
-
-const char * ip_vs_state_name(__u16 proto, int state)
-{
-	struct ip_vs_protocol *pp = ip_vs_proto_get(proto);
-
-	if (pp == NULL || pp->state_name == NULL)
-		return (IPPROTO_IP == proto) ? "NONE" : "ERR!";
-	return pp->state_name(state);
-}
-
-
-void
-ip_vs_tcpudp_debug_packet(struct ip_vs_protocol *pp,
-			  const struct sk_buff *skb,
-			  int offset,
-			  const char *msg)
-{
-	char buf[128];
-	struct iphdr _iph, *ih;
-
-	ih = skb_header_pointer(skb, offset, sizeof(_iph), &_iph);
-	if (ih == NULL)
-		sprintf(buf, "%s TRUNCATED", pp->name);
-	else if (ih->frag_off & htons(IP_OFFSET))
-		sprintf(buf, "%s %u.%u.%u.%u->%u.%u.%u.%u frag",
-			pp->name, NIPQUAD(ih->saddr),
-			NIPQUAD(ih->daddr));
-	else {
-		__be16 _ports[2], *pptr
-;
-		pptr = skb_header_pointer(skb, offset + ih->ihl*4,
-					  sizeof(_ports), _ports);
-		if (pptr == NULL)
-			sprintf(buf, "%s TRUNCATED %u.%u.%u.%u->%u.%u.%u.%u",
-				pp->name,
-				NIPQUAD(ih->saddr),
-				NIPQUAD(ih->daddr));
-		else
-			sprintf(buf, "%s %u.%u.%u.%u:%u->%u.%u.%u.%u:%u",
-				pp->name,
-				NIPQUAD(ih->saddr),
-				ntohs(pptr[0]),
-				NIPQUAD(ih->daddr),
-				ntohs(pptr[1]));
-	}
-
-	printk(KERN_DEBUG "IPVS: %s: %s\n", msg, buf);
-}
-
-
-int __init ip_vs_protocol_init(void)
-{
-	char protocols[64];
-#define REGISTER_PROTOCOL(p)			\
-	do {					\
-		register_ip_vs_protocol(p);	\
-		strcat(protocols, ", ");	\
-		strcat(protocols, (p)->name);	\
-	} while (0)
-
-	protocols[0] = '\0';
-	protocols[2] = '\0';
-#ifdef CONFIG_IP_VS_PROTO_TCP
-	REGISTER_PROTOCOL(&ip_vs_protocol_tcp);
-#endif
-#ifdef CONFIG_IP_VS_PROTO_UDP
-	REGISTER_PROTOCOL(&ip_vs_protocol_udp);
-#endif
-#ifdef CONFIG_IP_VS_PROTO_AH
-	REGISTER_PROTOCOL(&ip_vs_protocol_ah);
-#endif
-#ifdef CONFIG_IP_VS_PROTO_ESP
-	REGISTER_PROTOCOL(&ip_vs_protocol_esp);
-#endif
-	IP_VS_INFO("Registered protocols (%s)\n", &protocols[2]);
-
-	return 0;
-}
-
-
-void ip_vs_protocol_cleanup(void)
-{
-	struct ip_vs_protocol *pp;
-	int i;
-
-	/* unregister all the ipvs protocols */
-	for (i = 0; i < IP_VS_PROTO_TAB_SIZE; i++) {
-		while ((pp = ip_vs_proto_table[i]) != NULL)
-			unregister_ip_vs_protocol(pp);
-	}
-}
diff --git a/net/ipv4/ipvs/ip_vs_proto_ah.c b/net/ipv4/ipvs/ip_vs_proto_ah.c
deleted file mode 100644
index 73e0ea8..0000000
--- a/net/ipv4/ipvs/ip_vs_proto_ah.c
+++ /dev/null
@@ -1,178 +0,0 @@
-/*
- * ip_vs_proto_ah.c:	AH IPSec load balancing support for IPVS
- *
- * Authors:	Julian Anastasov <ja@ssi.bg>, February 2002
- *		Wensong Zhang <wensong@linuxvirtualserver.org>
- *
- *		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/in.h>
-#include <linux/ip.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/netfilter.h>
-#include <linux/netfilter_ipv4.h>
-
-#include <net/ip_vs.h>
-
-
-/* TODO:
-
-struct isakmp_hdr {
-	__u8		icookie[8];
-	__u8		rcookie[8];
-	__u8		np;
-	__u8		version;
-	__u8		xchgtype;
-	__u8		flags;
-	__u32		msgid;
-	__u32		length;
-};
-
-*/
-
-#define PORT_ISAKMP	500
-
-
-static struct ip_vs_conn *
-ah_conn_in_get(const struct sk_buff *skb,
-	       struct ip_vs_protocol *pp,
-	       const struct iphdr *iph,
-	       unsigned int proto_off,
-	       int inverse)
-{
-	struct ip_vs_conn *cp;
-
-	if (likely(!inverse)) {
-		cp = ip_vs_conn_in_get(IPPROTO_UDP,
-				       iph->saddr,
-				       htons(PORT_ISAKMP),
-				       iph->daddr,
-				       htons(PORT_ISAKMP));
-	} else {
-		cp = ip_vs_conn_in_get(IPPROTO_UDP,
-				       iph->daddr,
-				       htons(PORT_ISAKMP),
-				       iph->saddr,
-				       htons(PORT_ISAKMP));
-	}
-
-	if (!cp) {
-		/*
-		 * We are not sure if the packet is from our
-		 * service, so our conn_schedule hook should return NF_ACCEPT
-		 */
-		IP_VS_DBG(12, "Unknown ISAKMP entry for outin packet "
-			  "%s%s %u.%u.%u.%u->%u.%u.%u.%u\n",
-			  inverse ? "ICMP+" : "",
-			  pp->name,
-			  NIPQUAD(iph->saddr),
-			  NIPQUAD(iph->daddr));
-	}
-
-	return cp;
-}
-
-
-static struct ip_vs_conn *
-ah_conn_out_get(const struct sk_buff *skb, struct ip_vs_protocol *pp,
-		const struct iphdr *iph, unsigned int proto_off, int inverse)
-{
-	struct ip_vs_conn *cp;
-
-	if (likely(!inverse)) {
-		cp = ip_vs_conn_out_get(IPPROTO_UDP,
-					iph->saddr,
-					htons(PORT_ISAKMP),
-					iph->daddr,
-					htons(PORT_ISAKMP));
-	} else {
-		cp = ip_vs_conn_out_get(IPPROTO_UDP,
-					iph->daddr,
-					htons(PORT_ISAKMP),
-					iph->saddr,
-					htons(PORT_ISAKMP));
-	}
-
-	if (!cp) {
-		IP_VS_DBG(12, "Unknown ISAKMP entry for inout packet "
-			  "%s%s %u.%u.%u.%u->%u.%u.%u.%u\n",
-			  inverse ? "ICMP+" : "",
-			  pp->name,
-			  NIPQUAD(iph->saddr),
-			  NIPQUAD(iph->daddr));
-	}
-
-	return cp;
-}
-
-
-static int
-ah_conn_schedule(struct sk_buff *skb,
-		 struct ip_vs_protocol *pp,
-		 int *verdict, struct ip_vs_conn **cpp)
-{
-	/*
-	 * AH is only related traffic. Pass the packet to IP stack.
-	 */
-	*verdict = NF_ACCEPT;
-	return 0;
-}
-
-
-static void
-ah_debug_packet(struct ip_vs_protocol *pp, const struct sk_buff *skb,
-		int offset, const char *msg)
-{
-	char buf[256];
-	struct iphdr _iph, *ih;
-
-	ih = skb_header_pointer(skb, offset, sizeof(_iph), &_iph);
-	if (ih == NULL)
-		sprintf(buf, "%s TRUNCATED", pp->name);
-	else
-		sprintf(buf, "%s %u.%u.%u.%u->%u.%u.%u.%u",
-			pp->name, NIPQUAD(ih->saddr),
-			NIPQUAD(ih->daddr));
-
-	printk(KERN_DEBUG "IPVS: %s: %s\n", msg, buf);
-}
-
-
-static void ah_init(struct ip_vs_protocol *pp)
-{
-	/* nothing to do now */
-}
-
-
-static void ah_exit(struct ip_vs_protocol *pp)
-{
-	/* nothing to do now */
-}
-
-
-struct ip_vs_protocol ip_vs_protocol_ah = {
-	.name =			"AH",
-	.protocol =		IPPROTO_AH,
-	.num_states =		1,
-	.dont_defrag =		1,
-	.init =			ah_init,
-	.exit =			ah_exit,
-	.conn_schedule =	ah_conn_schedule,
-	.conn_in_get =		ah_conn_in_get,
-	.conn_out_get =		ah_conn_out_get,
-	.snat_handler =		NULL,
-	.dnat_handler =		NULL,
-	.csum_check =		NULL,
-	.state_transition =	NULL,
-	.register_app =		NULL,
-	.unregister_app =	NULL,
-	.app_conn_bind =	NULL,
-	.debug_packet =		ah_debug_packet,
-	.timeout_change =	NULL,		/* ISAKMP */
-	.set_state_timeout =	NULL,
-};
diff --git a/net/ipv4/ipvs/ip_vs_proto_esp.c b/net/ipv4/ipvs/ip_vs_proto_esp.c
deleted file mode 100644
index 21d70c8..0000000
--- a/net/ipv4/ipvs/ip_vs_proto_esp.c
+++ /dev/null
@@ -1,176 +0,0 @@
-/*
- * ip_vs_proto_esp.c:	ESP IPSec load balancing support for IPVS
- *
- * Authors:	Julian Anastasov <ja@ssi.bg>, February 2002
- *		Wensong Zhang <wensong@linuxvirtualserver.org>
- *
- *		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/in.h>
-#include <linux/ip.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/netfilter.h>
-#include <linux/netfilter_ipv4.h>
-
-#include <net/ip_vs.h>
-
-
-/* TODO:
-
-struct isakmp_hdr {
-	__u8		icookie[8];
-	__u8		rcookie[8];
-	__u8		np;
-	__u8		version;
-	__u8		xchgtype;
-	__u8		flags;
-	__u32		msgid;
-	__u32		length;
-};
-
-*/
-
-#define PORT_ISAKMP	500
-
-
-static struct ip_vs_conn *
-esp_conn_in_get(const struct sk_buff *skb,
-		struct ip_vs_protocol *pp,
-		const struct iphdr *iph,
-		unsigned int proto_off,
-		int inverse)
-{
-	struct ip_vs_conn *cp;
-
-	if (likely(!inverse)) {
-		cp = ip_vs_conn_in_get(IPPROTO_UDP,
-				       iph->saddr,
-				       htons(PORT_ISAKMP),
-				       iph->daddr,
-				       htons(PORT_ISAKMP));
-	} else {
-		cp = ip_vs_conn_in_get(IPPROTO_UDP,
-				       iph->daddr,
-				       htons(PORT_ISAKMP),
-				       iph->saddr,
-				       htons(PORT_ISAKMP));
-	}
-
-	if (!cp) {
-		/*
-		 * We are not sure if the packet is from our
-		 * service, so our conn_schedule hook should return NF_ACCEPT
-		 */
-		IP_VS_DBG(12, "Unknown ISAKMP entry for outin packet "
-			  "%s%s %u.%u.%u.%u->%u.%u.%u.%u\n",
-			  inverse ? "ICMP+" : "",
-			  pp->name,
-			  NIPQUAD(iph->saddr),
-			  NIPQUAD(iph->daddr));
-	}
-
-	return cp;
-}
-
-
-static struct ip_vs_conn *
-esp_conn_out_get(const struct sk_buff *skb, struct ip_vs_protocol *pp,
-		 const struct iphdr *iph, unsigned int proto_off, int inverse)
-{
-	struct ip_vs_conn *cp;
-
-	if (likely(!inverse)) {
-		cp = ip_vs_conn_out_get(IPPROTO_UDP,
-					iph->saddr,
-					htons(PORT_ISAKMP),
-					iph->daddr,
-					htons(PORT_ISAKMP));
-	} else {
-		cp = ip_vs_conn_out_get(IPPROTO_UDP,
-					iph->daddr,
-					htons(PORT_ISAKMP),
-					iph->saddr,
-					htons(PORT_ISAKMP));
-	}
-
-	if (!cp) {
-		IP_VS_DBG(12, "Unknown ISAKMP entry for inout packet "
-			  "%s%s %u.%u.%u.%u->%u.%u.%u.%u\n",
-			  inverse ? "ICMP+" : "",
-			  pp->name,
-			  NIPQUAD(iph->saddr),
-			  NIPQUAD(iph->daddr));
-	}
-
-	return cp;
-}
-
-
-static int
-esp_conn_schedule(struct sk_buff *skb, struct ip_vs_protocol *pp,
-		  int *verdict, struct ip_vs_conn **cpp)
-{
-	/*
-	 * ESP is only related traffic. Pass the packet to IP stack.
-	 */
-	*verdict = NF_ACCEPT;
-	return 0;
-}
-
-
-static void
-esp_debug_packet(struct ip_vs_protocol *pp, const struct sk_buff *skb,
-		 int offset, const char *msg)
-{
-	char buf[256];
-	struct iphdr _iph, *ih;
-
-	ih = skb_header_pointer(skb, offset, sizeof(_iph), &_iph);
-	if (ih == NULL)
-		sprintf(buf, "%s TRUNCATED", pp->name);
-	else
-		sprintf(buf, "%s %u.%u.%u.%u->%u.%u.%u.%u",
-			pp->name, NIPQUAD(ih->saddr),
-			NIPQUAD(ih->daddr));
-
-	printk(KERN_DEBUG "IPVS: %s: %s\n", msg, buf);
-}
-
-
-static void esp_init(struct ip_vs_protocol *pp)
-{
-	/* nothing to do now */
-}
-
-
-static void esp_exit(struct ip_vs_protocol *pp)
-{
-	/* nothing to do now */
-}
-
-
-struct ip_vs_protocol ip_vs_protocol_esp = {
-	.name =			"ESP",
-	.protocol =		IPPROTO_ESP,
-	.num_states =		1,
-	.dont_defrag =		1,
-	.init =			esp_init,
-	.exit =			esp_exit,
-	.conn_schedule =	esp_conn_schedule,
-	.conn_in_get =		esp_conn_in_get,
-	.conn_out_get =		esp_conn_out_get,
-	.snat_handler =		NULL,
-	.dnat_handler =		NULL,
-	.csum_check =		NULL,
-	.state_transition =	NULL,
-	.register_app =		NULL,
-	.unregister_app =	NULL,
-	.app_conn_bind =	NULL,
-	.debug_packet =		esp_debug_packet,
-	.timeout_change =	NULL,		/* ISAKMP */
-};
diff --git a/net/ipv4/ipvs/ip_vs_proto_tcp.c b/net/ipv4/ipvs/ip_vs_proto_tcp.c
deleted file mode 100644
index d0ea467..0000000
--- a/net/ipv4/ipvs/ip_vs_proto_tcp.c
+++ /dev/null
@@ -1,614 +0,0 @@
-/*
- * ip_vs_proto_tcp.c:	TCP load balancing support for IPVS
- *
- * Authors:     Wensong Zhang <wensong@linuxvirtualserver.org>
- *              Julian Anastasov <ja@ssi.bg>
- *
- *              This program is free software; you can redistribute it and/or
- *              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.
- *
- * Changes:
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/ip.h>
-#include <linux/tcp.h>                  /* for tcphdr */
-#include <net/ip.h>
-#include <net/tcp.h>                    /* for csum_tcpudp_magic */
-#include <linux/netfilter.h>
-#include <linux/netfilter_ipv4.h>
-
-#include <net/ip_vs.h>
-
-
-static struct ip_vs_conn *
-tcp_conn_in_get(const struct sk_buff *skb, struct ip_vs_protocol *pp,
-		const struct iphdr *iph, unsigned int proto_off, int inverse)
-{
-	__be16 _ports[2], *pptr;
-
-	pptr = skb_header_pointer(skb, proto_off, sizeof(_ports), _ports);
-	if (pptr == NULL)
-		return NULL;
-
-	if (likely(!inverse)) {
-		return ip_vs_conn_in_get(iph->protocol,
-					 iph->saddr, pptr[0],
-					 iph->daddr, pptr[1]);
-	} else {
-		return ip_vs_conn_in_get(iph->protocol,
-					 iph->daddr, pptr[1],
-					 iph->saddr, pptr[0]);
-	}
-}
-
-static struct ip_vs_conn *
-tcp_conn_out_get(const struct sk_buff *skb, struct ip_vs_protocol *pp,
-		 const struct iphdr *iph, unsigned int proto_off, int inverse)
-{
-	__be16 _ports[2], *pptr;
-
-	pptr = skb_header_pointer(skb, proto_off, sizeof(_ports), _ports);
-	if (pptr == NULL)
-		return NULL;
-
-	if (likely(!inverse)) {
-		return ip_vs_conn_out_get(iph->protocol,
-					  iph->saddr, pptr[0],
-					  iph->daddr, pptr[1]);
-	} else {
-		return ip_vs_conn_out_get(iph->protocol,
-					  iph->daddr, pptr[1],
-					  iph->saddr, pptr[0]);
-	}
-}
-
-
-static int
-tcp_conn_schedule(struct sk_buff *skb,
-		  struct ip_vs_protocol *pp,
-		  int *verdict, struct ip_vs_conn **cpp)
-{
-	struct ip_vs_service *svc;
-	struct tcphdr _tcph, *th;
-
-	th = skb_header_pointer(skb, ip_hdrlen(skb), sizeof(_tcph), &_tcph);
-	if (th == NULL) {
-		*verdict = NF_DROP;
-		return 0;
-	}
-
-	if (th->syn &&
-	    (svc = ip_vs_service_get(skb->mark, ip_hdr(skb)->protocol,
-				     ip_hdr(skb)->daddr, th->dest))) {
-		if (ip_vs_todrop()) {
-			/*
-			 * It seems that we are very loaded.
-			 * We have to drop this packet :(
-			 */
-			ip_vs_service_put(svc);
-			*verdict = NF_DROP;
-			return 0;
-		}
-
-		/*
-		 * Let the virtual server select a real server for the
-		 * incoming connection, and create a connection entry.
-		 */
-		*cpp = ip_vs_schedule(svc, skb);
-		if (!*cpp) {
-			*verdict = ip_vs_leave(svc, skb, pp);
-			return 0;
-		}
-		ip_vs_service_put(svc);
-	}
-	return 1;
-}
-
-
-static inline void
-tcp_fast_csum_update(struct tcphdr *tcph, __be32 oldip, __be32 newip,
-		     __be16 oldport, __be16 newport)
-{
-	tcph->check =
-		csum_fold(ip_vs_check_diff4(oldip, newip,
-				 ip_vs_check_diff2(oldport, newport,
-						~csum_unfold(tcph->check))));
-}
-
-
-static int
-tcp_snat_handler(struct sk_buff *skb,
-		 struct ip_vs_protocol *pp, struct ip_vs_conn *cp)
-{
-	struct tcphdr *tcph;
-	const unsigned int tcphoff = ip_hdrlen(skb);
-
-	/* csum_check requires unshared skb */
-	if (!skb_make_writable(skb, tcphoff+sizeof(*tcph)))
-		return 0;
-
-	if (unlikely(cp->app != NULL)) {
-		/* Some checks before mangling */
-		if (pp->csum_check && !pp->csum_check(skb, pp))
-			return 0;
-
-		/* Call application helper if needed */
-		if (!ip_vs_app_pkt_out(cp, skb))
-			return 0;
-	}
-
-	tcph = (void *)ip_hdr(skb) + tcphoff;
-	tcph->source = cp->vport;
-
-	/* Adjust TCP checksums */
-	if (!cp->app) {
-		/* Only port and addr are changed, do fast csum update */
-		tcp_fast_csum_update(tcph, cp->daddr, cp->vaddr,
-				     cp->dport, cp->vport);
-		if (skb->ip_summed == CHECKSUM_COMPLETE)
-			skb->ip_summed = CHECKSUM_NONE;
-	} else {
-		/* full checksum calculation */
-		tcph->check = 0;
-		skb->csum = skb_checksum(skb, tcphoff, skb->len - tcphoff, 0);
-		tcph->check = csum_tcpudp_magic(cp->vaddr, cp->caddr,
-						skb->len - tcphoff,
-						cp->protocol, skb->csum);
-		IP_VS_DBG(11, "O-pkt: %s O-csum=%d (+%zd)\n",
-			  pp->name, tcph->check,
-			  (char*)&(tcph->check) - (char*)tcph);
-	}
-	return 1;
-}
-
-
-static int
-tcp_dnat_handler(struct sk_buff *skb,
-		 struct ip_vs_protocol *pp, struct ip_vs_conn *cp)
-{
-	struct tcphdr *tcph;
-	const unsigned int tcphoff = ip_hdrlen(skb);
-
-	/* csum_check requires unshared skb */
-	if (!skb_make_writable(skb, tcphoff+sizeof(*tcph)))
-		return 0;
-
-	if (unlikely(cp->app != NULL)) {
-		/* Some checks before mangling */
-		if (pp->csum_check && !pp->csum_check(skb, pp))
-			return 0;
-
-		/*
-		 *	Attempt ip_vs_app call.
-		 *	It will fix ip_vs_conn and iph ack_seq stuff
-		 */
-		if (!ip_vs_app_pkt_in(cp, skb))
-			return 0;
-	}
-
-	tcph = (void *)ip_hdr(skb) + tcphoff;
-	tcph->dest = cp->dport;
-
-	/*
-	 *	Adjust TCP checksums
-	 */
-	if (!cp->app) {
-		/* Only port and addr are changed, do fast csum update */
-		tcp_fast_csum_update(tcph, cp->vaddr, cp->daddr,
-				     cp->vport, cp->dport);
-		if (skb->ip_summed == CHECKSUM_COMPLETE)
-			skb->ip_summed = CHECKSUM_NONE;
-	} else {
-		/* full checksum calculation */
-		tcph->check = 0;
-		skb->csum = skb_checksum(skb, tcphoff, skb->len - tcphoff, 0);
-		tcph->check = csum_tcpudp_magic(cp->caddr, cp->daddr,
-						skb->len - tcphoff,
-						cp->protocol, skb->csum);
-		skb->ip_summed = CHECKSUM_UNNECESSARY;
-	}
-	return 1;
-}
-
-
-static int
-tcp_csum_check(struct sk_buff *skb, struct ip_vs_protocol *pp)
-{
-	const unsigned int tcphoff = ip_hdrlen(skb);
-
-	switch (skb->ip_summed) {
-	case CHECKSUM_NONE:
-		skb->csum = skb_checksum(skb, tcphoff, skb->len - tcphoff, 0);
-	case CHECKSUM_COMPLETE:
-		if (csum_tcpudp_magic(ip_hdr(skb)->saddr, ip_hdr(skb)->daddr,
-				      skb->len - tcphoff,
-				      ip_hdr(skb)->protocol, skb->csum)) {
-			IP_VS_DBG_RL_PKT(0, pp, skb, 0,
-					 "Failed checksum for");
-			return 0;
-		}
-		break;
-	default:
-		/* No need to checksum. */
-		break;
-	}
-
-	return 1;
-}
-
-
-#define TCP_DIR_INPUT		0
-#define TCP_DIR_OUTPUT		4
-#define TCP_DIR_INPUT_ONLY	8
-
-static const int tcp_state_off[IP_VS_DIR_LAST] = {
-	[IP_VS_DIR_INPUT]		=	TCP_DIR_INPUT,
-	[IP_VS_DIR_OUTPUT]		=	TCP_DIR_OUTPUT,
-	[IP_VS_DIR_INPUT_ONLY]		=	TCP_DIR_INPUT_ONLY,
-};
-
-/*
- *	Timeout table[state]
- */
-static int tcp_timeouts[IP_VS_TCP_S_LAST+1] = {
-	[IP_VS_TCP_S_NONE]		=	2*HZ,
-	[IP_VS_TCP_S_ESTABLISHED]	=	15*60*HZ,
-	[IP_VS_TCP_S_SYN_SENT]		=	2*60*HZ,
-	[IP_VS_TCP_S_SYN_RECV]		=	1*60*HZ,
-	[IP_VS_TCP_S_FIN_WAIT]		=	2*60*HZ,
-	[IP_VS_TCP_S_TIME_WAIT]		=	2*60*HZ,
-	[IP_VS_TCP_S_CLOSE]		=	10*HZ,
-	[IP_VS_TCP_S_CLOSE_WAIT]	=	60*HZ,
-	[IP_VS_TCP_S_LAST_ACK]		=	30*HZ,
-	[IP_VS_TCP_S_LISTEN]		=	2*60*HZ,
-	[IP_VS_TCP_S_SYNACK]		=	120*HZ,
-	[IP_VS_TCP_S_LAST]		=	2*HZ,
-};
-
-static char * tcp_state_name_table[IP_VS_TCP_S_LAST+1] = {
-	[IP_VS_TCP_S_NONE]		=	"NONE",
-	[IP_VS_TCP_S_ESTABLISHED]	=	"ESTABLISHED",
-	[IP_VS_TCP_S_SYN_SENT]		=	"SYN_SENT",
-	[IP_VS_TCP_S_SYN_RECV]		=	"SYN_RECV",
-	[IP_VS_TCP_S_FIN_WAIT]		=	"FIN_WAIT",
-	[IP_VS_TCP_S_TIME_WAIT]		=	"TIME_WAIT",
-	[IP_VS_TCP_S_CLOSE]		=	"CLOSE",
-	[IP_VS_TCP_S_CLOSE_WAIT]	=	"CLOSE_WAIT",
-	[IP_VS_TCP_S_LAST_ACK]		=	"LAST_ACK",
-	[IP_VS_TCP_S_LISTEN]		=	"LISTEN",
-	[IP_VS_TCP_S_SYNACK]		=	"SYNACK",
-	[IP_VS_TCP_S_LAST]		=	"BUG!",
-};
-
-#define sNO IP_VS_TCP_S_NONE
-#define sES IP_VS_TCP_S_ESTABLISHED
-#define sSS IP_VS_TCP_S_SYN_SENT
-#define sSR IP_VS_TCP_S_SYN_RECV
-#define sFW IP_VS_TCP_S_FIN_WAIT
-#define sTW IP_VS_TCP_S_TIME_WAIT
-#define sCL IP_VS_TCP_S_CLOSE
-#define sCW IP_VS_TCP_S_CLOSE_WAIT
-#define sLA IP_VS_TCP_S_LAST_ACK
-#define sLI IP_VS_TCP_S_LISTEN
-#define sSA IP_VS_TCP_S_SYNACK
-
-struct tcp_states_t {
-	int next_state[IP_VS_TCP_S_LAST];
-};
-
-static const char * tcp_state_name(int state)
-{
-	if (state >= IP_VS_TCP_S_LAST)
-		return "ERR!";
-	return tcp_state_name_table[state] ? tcp_state_name_table[state] : "?";
-}
-
-static struct tcp_states_t tcp_states [] = {
-/*	INPUT */
-/*        sNO, sES, sSS, sSR, sFW, sTW, sCL, sCW, sLA, sLI, sSA	*/
-/*syn*/ {{sSR, sES, sES, sSR, sSR, sSR, sSR, sSR, sSR, sSR, sSR }},
-/*fin*/ {{sCL, sCW, sSS, sTW, sTW, sTW, sCL, sCW, sLA, sLI, sTW }},
-/*ack*/ {{sCL, sES, sSS, sES, sFW, sTW, sCL, sCW, sCL, sLI, sES }},
-/*rst*/ {{sCL, sCL, sCL, sSR, sCL, sCL, sCL, sCL, sLA, sLI, sSR }},
-
-/*	OUTPUT */
-/*        sNO, sES, sSS, sSR, sFW, sTW, sCL, sCW, sLA, sLI, sSA	*/
-/*syn*/ {{sSS, sES, sSS, sSR, sSS, sSS, sSS, sSS, sSS, sLI, sSR }},
-/*fin*/ {{sTW, sFW, sSS, sTW, sFW, sTW, sCL, sTW, sLA, sLI, sTW }},
-/*ack*/ {{sES, sES, sSS, sES, sFW, sTW, sCL, sCW, sLA, sES, sES }},
-/*rst*/ {{sCL, sCL, sSS, sCL, sCL, sTW, sCL, sCL, sCL, sCL, sCL }},
-
-/*	INPUT-ONLY */
-/*        sNO, sES, sSS, sSR, sFW, sTW, sCL, sCW, sLA, sLI, sSA	*/
-/*syn*/ {{sSR, sES, sES, sSR, sSR, sSR, sSR, sSR, sSR, sSR, sSR }},
-/*fin*/ {{sCL, sFW, sSS, sTW, sFW, sTW, sCL, sCW, sLA, sLI, sTW }},
-/*ack*/ {{sCL, sES, sSS, sES, sFW, sTW, sCL, sCW, sCL, sLI, sES }},
-/*rst*/ {{sCL, sCL, sCL, sSR, sCL, sCL, sCL, sCL, sLA, sLI, sCL }},
-};
-
-static struct tcp_states_t tcp_states_dos [] = {
-/*	INPUT */
-/*        sNO, sES, sSS, sSR, sFW, sTW, sCL, sCW, sLA, sLI, sSA	*/
-/*syn*/ {{sSR, sES, sES, sSR, sSR, sSR, sSR, sSR, sSR, sSR, sSA }},
-/*fin*/ {{sCL, sCW, sSS, sTW, sTW, sTW, sCL, sCW, sLA, sLI, sSA }},
-/*ack*/ {{sCL, sES, sSS, sSR, sFW, sTW, sCL, sCW, sCL, sLI, sSA }},
-/*rst*/ {{sCL, sCL, sCL, sSR, sCL, sCL, sCL, sCL, sLA, sLI, sCL }},
-
-/*	OUTPUT */
-/*        sNO, sES, sSS, sSR, sFW, sTW, sCL, sCW, sLA, sLI, sSA	*/
-/*syn*/ {{sSS, sES, sSS, sSA, sSS, sSS, sSS, sSS, sSS, sLI, sSA }},
-/*fin*/ {{sTW, sFW, sSS, sTW, sFW, sTW, sCL, sTW, sLA, sLI, sTW }},
-/*ack*/ {{sES, sES, sSS, sES, sFW, sTW, sCL, sCW, sLA, sES, sES }},
-/*rst*/ {{sCL, sCL, sSS, sCL, sCL, sTW, sCL, sCL, sCL, sCL, sCL }},
-
-/*	INPUT-ONLY */
-/*        sNO, sES, sSS, sSR, sFW, sTW, sCL, sCW, sLA, sLI, sSA	*/
-/*syn*/ {{sSA, sES, sES, sSR, sSA, sSA, sSA, sSA, sSA, sSA, sSA }},
-/*fin*/ {{sCL, sFW, sSS, sTW, sFW, sTW, sCL, sCW, sLA, sLI, sTW }},
-/*ack*/ {{sCL, sES, sSS, sES, sFW, sTW, sCL, sCW, sCL, sLI, sES }},
-/*rst*/ {{sCL, sCL, sCL, sSR, sCL, sCL, sCL, sCL, sLA, sLI, sCL }},
-};
-
-static struct tcp_states_t *tcp_state_table = tcp_states;
-
-
-static void tcp_timeout_change(struct ip_vs_protocol *pp, int flags)
-{
-	int on = (flags & 1);		/* secure_tcp */
-
-	/*
-	** FIXME: change secure_tcp to independent sysctl var
-	** or make it per-service or per-app because it is valid
-	** for most if not for all of the applications. Something
-	** like "capabilities" (flags) for each object.
-	*/
-	tcp_state_table = (on? tcp_states_dos : tcp_states);
-}
-
-static int
-tcp_set_state_timeout(struct ip_vs_protocol *pp, char *sname, int to)
-{
-	return ip_vs_set_state_timeout(pp->timeout_table, IP_VS_TCP_S_LAST,
-				       tcp_state_name_table, sname, to);
-}
-
-static inline int tcp_state_idx(struct tcphdr *th)
-{
-	if (th->rst)
-		return 3;
-	if (th->syn)
-		return 0;
-	if (th->fin)
-		return 1;
-	if (th->ack)
-		return 2;
-	return -1;
-}
-
-static inline void
-set_tcp_state(struct ip_vs_protocol *pp, struct ip_vs_conn *cp,
-	      int direction, struct tcphdr *th)
-{
-	int state_idx;
-	int new_state = IP_VS_TCP_S_CLOSE;
-	int state_off = tcp_state_off[direction];
-
-	/*
-	 *    Update state offset to INPUT_ONLY if necessary
-	 *    or delete NO_OUTPUT flag if output packet detected
-	 */
-	if (cp->flags & IP_VS_CONN_F_NOOUTPUT) {
-		if (state_off == TCP_DIR_OUTPUT)
-			cp->flags &= ~IP_VS_CONN_F_NOOUTPUT;
-		else
-			state_off = TCP_DIR_INPUT_ONLY;
-	}
-
-	if ((state_idx = tcp_state_idx(th)) < 0) {
-		IP_VS_DBG(8, "tcp_state_idx=%d!!!\n", state_idx);
-		goto tcp_state_out;
-	}
-
-	new_state = tcp_state_table[state_off+state_idx].next_state[cp->state];
-
-  tcp_state_out:
-	if (new_state != cp->state) {
-		struct ip_vs_dest *dest = cp->dest;
-
-		IP_VS_DBG(8, "%s %s [%c%c%c%c] %u.%u.%u.%u:%d->"
-			  "%u.%u.%u.%u:%d state: %s->%s conn->refcnt:%d\n",
-			  pp->name,
-			  (state_off==TCP_DIR_OUTPUT)?"output ":"input ",
-			  th->syn? 'S' : '.',
-			  th->fin? 'F' : '.',
-			  th->ack? 'A' : '.',
-			  th->rst? 'R' : '.',
-			  NIPQUAD(cp->daddr), ntohs(cp->dport),
-			  NIPQUAD(cp->caddr), ntohs(cp->cport),
-			  tcp_state_name(cp->state),
-			  tcp_state_name(new_state),
-			  atomic_read(&cp->refcnt));
-		if (dest) {
-			if (!(cp->flags & IP_VS_CONN_F_INACTIVE) &&
-			    (new_state != IP_VS_TCP_S_ESTABLISHED)) {
-				atomic_dec(&dest->activeconns);
-				atomic_inc(&dest->inactconns);
-				cp->flags |= IP_VS_CONN_F_INACTIVE;
-			} else if ((cp->flags & IP_VS_CONN_F_INACTIVE) &&
-				   (new_state == IP_VS_TCP_S_ESTABLISHED)) {
-				atomic_inc(&dest->activeconns);
-				atomic_dec(&dest->inactconns);
-				cp->flags &= ~IP_VS_CONN_F_INACTIVE;
-			}
-		}
-	}
-
-	cp->timeout = pp->timeout_table[cp->state = new_state];
-}
-
-
-/*
- *	Handle state transitions
- */
-static int
-tcp_state_transition(struct ip_vs_conn *cp, int direction,
-		     const struct sk_buff *skb,
-		     struct ip_vs_protocol *pp)
-{
-	struct tcphdr _tcph, *th;
-
-	th = skb_header_pointer(skb, ip_hdrlen(skb), sizeof(_tcph), &_tcph);
-	if (th == NULL)
-		return 0;
-
-	spin_lock(&cp->lock);
-	set_tcp_state(pp, cp, direction, th);
-	spin_unlock(&cp->lock);
-
-	return 1;
-}
-
-
-/*
- *	Hash table for TCP application incarnations
- */
-#define	TCP_APP_TAB_BITS	4
-#define	TCP_APP_TAB_SIZE	(1 << TCP_APP_TAB_BITS)
-#define	TCP_APP_TAB_MASK	(TCP_APP_TAB_SIZE - 1)
-
-static struct list_head tcp_apps[TCP_APP_TAB_SIZE];
-static DEFINE_SPINLOCK(tcp_app_lock);
-
-static inline __u16 tcp_app_hashkey(__be16 port)
-{
-	return (((__force u16)port >> TCP_APP_TAB_BITS) ^ (__force u16)port)
-		& TCP_APP_TAB_MASK;
-}
-
-
-static int tcp_register_app(struct ip_vs_app *inc)
-{
-	struct ip_vs_app *i;
-	__u16 hash;
-	__be16 port = inc->port;
-	int ret = 0;
-
-	hash = tcp_app_hashkey(port);
-
-	spin_lock_bh(&tcp_app_lock);
-	list_for_each_entry(i, &tcp_apps[hash], p_list) {
-		if (i->port == port) {
-			ret = -EEXIST;
-			goto out;
-		}
-	}
-	list_add(&inc->p_list, &tcp_apps[hash]);
-	atomic_inc(&ip_vs_protocol_tcp.appcnt);
-
-  out:
-	spin_unlock_bh(&tcp_app_lock);
-	return ret;
-}
-
-
-static void
-tcp_unregister_app(struct ip_vs_app *inc)
-{
-	spin_lock_bh(&tcp_app_lock);
-	atomic_dec(&ip_vs_protocol_tcp.appcnt);
-	list_del(&inc->p_list);
-	spin_unlock_bh(&tcp_app_lock);
-}
-
-
-static int
-tcp_app_conn_bind(struct ip_vs_conn *cp)
-{
-	int hash;
-	struct ip_vs_app *inc;
-	int result = 0;
-
-	/* Default binding: bind app only for NAT */
-	if (IP_VS_FWD_METHOD(cp) != IP_VS_CONN_F_MASQ)
-		return 0;
-
-	/* Lookup application incarnations and bind the right one */
-	hash = tcp_app_hashkey(cp->vport);
-
-	spin_lock(&tcp_app_lock);
-	list_for_each_entry(inc, &tcp_apps[hash], p_list) {
-		if (inc->port == cp->vport) {
-			if (unlikely(!ip_vs_app_inc_get(inc)))
-				break;
-			spin_unlock(&tcp_app_lock);
-
-			IP_VS_DBG(9, "%s: Binding conn %u.%u.%u.%u:%u->"
-				  "%u.%u.%u.%u:%u to app %s on port %u\n",
-				  __func__,
-				  NIPQUAD(cp->caddr), ntohs(cp->cport),
-				  NIPQUAD(cp->vaddr), ntohs(cp->vport),
-				  inc->name, ntohs(inc->port));
-			cp->app = inc;
-			if (inc->init_conn)
-				result = inc->init_conn(inc, cp);
-			goto out;
-		}
-	}
-	spin_unlock(&tcp_app_lock);
-
-  out:
-	return result;
-}
-
-
-/*
- *	Set LISTEN timeout. (ip_vs_conn_put will setup timer)
- */
-void ip_vs_tcp_conn_listen(struct ip_vs_conn *cp)
-{
-	spin_lock(&cp->lock);
-	cp->state = IP_VS_TCP_S_LISTEN;
-	cp->timeout = ip_vs_protocol_tcp.timeout_table[IP_VS_TCP_S_LISTEN];
-	spin_unlock(&cp->lock);
-}
-
-
-static void ip_vs_tcp_init(struct ip_vs_protocol *pp)
-{
-	IP_VS_INIT_HASH_TABLE(tcp_apps);
-	pp->timeout_table = tcp_timeouts;
-}
-
-
-static void ip_vs_tcp_exit(struct ip_vs_protocol *pp)
-{
-}
-
-
-struct ip_vs_protocol ip_vs_protocol_tcp = {
-	.name =			"TCP",
-	.protocol =		IPPROTO_TCP,
-	.num_states =		IP_VS_TCP_S_LAST,
-	.dont_defrag =		0,
-	.appcnt =		ATOMIC_INIT(0),
-	.init =			ip_vs_tcp_init,
-	.exit =			ip_vs_tcp_exit,
-	.register_app =		tcp_register_app,
-	.unregister_app =	tcp_unregister_app,
-	.conn_schedule =	tcp_conn_schedule,
-	.conn_in_get =		tcp_conn_in_get,
-	.conn_out_get =		tcp_conn_out_get,
-	.snat_handler =		tcp_snat_handler,
-	.dnat_handler =		tcp_dnat_handler,
-	.csum_check =		tcp_csum_check,
-	.state_name =		tcp_state_name,
-	.state_transition =	tcp_state_transition,
-	.app_conn_bind =	tcp_app_conn_bind,
-	.debug_packet =		ip_vs_tcpudp_debug_packet,
-	.timeout_change =	tcp_timeout_change,
-	.set_state_timeout =	tcp_set_state_timeout,
-};
diff --git a/net/ipv4/ipvs/ip_vs_proto_udp.c b/net/ipv4/ipvs/ip_vs_proto_udp.c
deleted file mode 100644
index c6be5d5..0000000
--- a/net/ipv4/ipvs/ip_vs_proto_udp.c
+++ /dev/null
@@ -1,428 +0,0 @@
-/*
- * ip_vs_proto_udp.c:	UDP load balancing support for IPVS
- *
- * Authors:     Wensong Zhang <wensong@linuxvirtualserver.org>
- *              Julian Anastasov <ja@ssi.bg>
- *
- *              This program is free software; you can redistribute it and/or
- *              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.
- *
- * Changes:
- *
- */
-
-#include <linux/in.h>
-#include <linux/ip.h>
-#include <linux/kernel.h>
-#include <linux/netfilter.h>
-#include <linux/netfilter_ipv4.h>
-#include <linux/udp.h>
-
-#include <net/ip_vs.h>
-#include <net/ip.h>
-
-static struct ip_vs_conn *
-udp_conn_in_get(const struct sk_buff *skb, struct ip_vs_protocol *pp,
-		const struct iphdr *iph, unsigned int proto_off, int inverse)
-{
-	struct ip_vs_conn *cp;
-	__be16 _ports[2], *pptr;
-
-	pptr = skb_header_pointer(skb, proto_off, sizeof(_ports), _ports);
-	if (pptr == NULL)
-		return NULL;
-
-	if (likely(!inverse)) {
-		cp = ip_vs_conn_in_get(iph->protocol,
-				       iph->saddr, pptr[0],
-				       iph->daddr, pptr[1]);
-	} else {
-		cp = ip_vs_conn_in_get(iph->protocol,
-				       iph->daddr, pptr[1],
-				       iph->saddr, pptr[0]);
-	}
-
-	return cp;
-}
-
-
-static struct ip_vs_conn *
-udp_conn_out_get(const struct sk_buff *skb, struct ip_vs_protocol *pp,
-		 const struct iphdr *iph, unsigned int proto_off, int inverse)
-{
-	struct ip_vs_conn *cp;
-	__be16 _ports[2], *pptr;
-
-	pptr = skb_header_pointer(skb, ip_hdrlen(skb),
-				  sizeof(_ports), _ports);
-	if (pptr == NULL)
-		return NULL;
-
-	if (likely(!inverse)) {
-		cp = ip_vs_conn_out_get(iph->protocol,
-					iph->saddr, pptr[0],
-					iph->daddr, pptr[1]);
-	} else {
-		cp = ip_vs_conn_out_get(iph->protocol,
-					iph->daddr, pptr[1],
-					iph->saddr, pptr[0]);
-	}
-
-	return cp;
-}
-
-
-static int
-udp_conn_schedule(struct sk_buff *skb, struct ip_vs_protocol *pp,
-		  int *verdict, struct ip_vs_conn **cpp)
-{
-	struct ip_vs_service *svc;
-	struct udphdr _udph, *uh;
-
-	uh = skb_header_pointer(skb, ip_hdrlen(skb),
-				sizeof(_udph), &_udph);
-	if (uh == NULL) {
-		*verdict = NF_DROP;
-		return 0;
-	}
-
-	if ((svc = ip_vs_service_get(skb->mark, ip_hdr(skb)->protocol,
-				     ip_hdr(skb)->daddr, uh->dest))) {
-		if (ip_vs_todrop()) {
-			/*
-			 * It seems that we are very loaded.
-			 * We have to drop this packet :(
-			 */
-			ip_vs_service_put(svc);
-			*verdict = NF_DROP;
-			return 0;
-		}
-
-		/*
-		 * Let the virtual server select a real server for the
-		 * incoming connection, and create a connection entry.
-		 */
-		*cpp = ip_vs_schedule(svc, skb);
-		if (!*cpp) {
-			*verdict = ip_vs_leave(svc, skb, pp);
-			return 0;
-		}
-		ip_vs_service_put(svc);
-	}
-	return 1;
-}
-
-
-static inline void
-udp_fast_csum_update(struct udphdr *uhdr, __be32 oldip, __be32 newip,
-		     __be16 oldport, __be16 newport)
-{
-	uhdr->check =
-		csum_fold(ip_vs_check_diff4(oldip, newip,
-				 ip_vs_check_diff2(oldport, newport,
-					~csum_unfold(uhdr->check))));
-	if (!uhdr->check)
-		uhdr->check = CSUM_MANGLED_0;
-}
-
-static int
-udp_snat_handler(struct sk_buff *skb,
-		 struct ip_vs_protocol *pp, struct ip_vs_conn *cp)
-{
-	struct udphdr *udph;
-	const unsigned int udphoff = ip_hdrlen(skb);
-
-	/* csum_check requires unshared skb */
-	if (!skb_make_writable(skb, udphoff+sizeof(*udph)))
-		return 0;
-
-	if (unlikely(cp->app != NULL)) {
-		/* Some checks before mangling */
-		if (pp->csum_check && !pp->csum_check(skb, pp))
-			return 0;
-
-		/*
-		 *	Call application helper if needed
-		 */
-		if (!ip_vs_app_pkt_out(cp, skb))
-			return 0;
-	}
-
-	udph = (void *)ip_hdr(skb) + udphoff;
-	udph->source = cp->vport;
-
-	/*
-	 *	Adjust UDP checksums
-	 */
-	if (!cp->app && (udph->check != 0)) {
-		/* Only port and addr are changed, do fast csum update */
-		udp_fast_csum_update(udph, cp->daddr, cp->vaddr,
-				     cp->dport, cp->vport);
-		if (skb->ip_summed == CHECKSUM_COMPLETE)
-			skb->ip_summed = CHECKSUM_NONE;
-	} else {
-		/* full checksum calculation */
-		udph->check = 0;
-		skb->csum = skb_checksum(skb, udphoff, skb->len - udphoff, 0);
-		udph->check = csum_tcpudp_magic(cp->vaddr, cp->caddr,
-						skb->len - udphoff,
-						cp->protocol, skb->csum);
-		if (udph->check == 0)
-			udph->check = CSUM_MANGLED_0;
-		IP_VS_DBG(11, "O-pkt: %s O-csum=%d (+%zd)\n",
-			  pp->name, udph->check,
-			  (char*)&(udph->check) - (char*)udph);
-	}
-	return 1;
-}
-
-
-static int
-udp_dnat_handler(struct sk_buff *skb,
-		 struct ip_vs_protocol *pp, struct ip_vs_conn *cp)
-{
-	struct udphdr *udph;
-	unsigned int udphoff = ip_hdrlen(skb);
-
-	/* csum_check requires unshared skb */
-	if (!skb_make_writable(skb, udphoff+sizeof(*udph)))
-		return 0;
-
-	if (unlikely(cp->app != NULL)) {
-		/* Some checks before mangling */
-		if (pp->csum_check && !pp->csum_check(skb, pp))
-			return 0;
-
-		/*
-		 *	Attempt ip_vs_app call.
-		 *	It will fix ip_vs_conn
-		 */
-		if (!ip_vs_app_pkt_in(cp, skb))
-			return 0;
-	}
-
-	udph = (void *)ip_hdr(skb) + udphoff;
-	udph->dest = cp->dport;
-
-	/*
-	 *	Adjust UDP checksums
-	 */
-	if (!cp->app && (udph->check != 0)) {
-		/* Only port and addr are changed, do fast csum update */
-		udp_fast_csum_update(udph, cp->vaddr, cp->daddr,
-				     cp->vport, cp->dport);
-		if (skb->ip_summed == CHECKSUM_COMPLETE)
-			skb->ip_summed = CHECKSUM_NONE;
-	} else {
-		/* full checksum calculation */
-		udph->check = 0;
-		skb->csum = skb_checksum(skb, udphoff, skb->len - udphoff, 0);
-		udph->check = csum_tcpudp_magic(cp->caddr, cp->daddr,
-						skb->len - udphoff,
-						cp->protocol, skb->csum);
-		if (udph->check == 0)
-			udph->check = CSUM_MANGLED_0;
-		skb->ip_summed = CHECKSUM_UNNECESSARY;
-	}
-	return 1;
-}
-
-
-static int
-udp_csum_check(struct sk_buff *skb, struct ip_vs_protocol *pp)
-{
-	struct udphdr _udph, *uh;
-	const unsigned int udphoff = ip_hdrlen(skb);
-
-	uh = skb_header_pointer(skb, udphoff, sizeof(_udph), &_udph);
-	if (uh == NULL)
-		return 0;
-
-	if (uh->check != 0) {
-		switch (skb->ip_summed) {
-		case CHECKSUM_NONE:
-			skb->csum = skb_checksum(skb, udphoff,
-						 skb->len - udphoff, 0);
-		case CHECKSUM_COMPLETE:
-			if (csum_tcpudp_magic(ip_hdr(skb)->saddr,
-					      ip_hdr(skb)->daddr,
-					      skb->len - udphoff,
-					      ip_hdr(skb)->protocol,
-					      skb->csum)) {
-				IP_VS_DBG_RL_PKT(0, pp, skb, 0,
-						 "Failed checksum for");
-				return 0;
-			}
-			break;
-		default:
-			/* No need to checksum. */
-			break;
-		}
-	}
-	return 1;
-}
-
-
-/*
- *	Note: the caller guarantees that only one of register_app,
- *	unregister_app or app_conn_bind is called each time.
- */
-
-#define	UDP_APP_TAB_BITS	4
-#define	UDP_APP_TAB_SIZE	(1 << UDP_APP_TAB_BITS)
-#define	UDP_APP_TAB_MASK	(UDP_APP_TAB_SIZE - 1)
-
-static struct list_head udp_apps[UDP_APP_TAB_SIZE];
-static DEFINE_SPINLOCK(udp_app_lock);
-
-static inline __u16 udp_app_hashkey(__be16 port)
-{
-	return (((__force u16)port >> UDP_APP_TAB_BITS) ^ (__force u16)port)
-		& UDP_APP_TAB_MASK;
-}
-
-
-static int udp_register_app(struct ip_vs_app *inc)
-{
-	struct ip_vs_app *i;
-	__u16 hash;
-	__be16 port = inc->port;
-	int ret = 0;
-
-	hash = udp_app_hashkey(port);
-
-
-	spin_lock_bh(&udp_app_lock);
-	list_for_each_entry(i, &udp_apps[hash], p_list) {
-		if (i->port == port) {
-			ret = -EEXIST;
-			goto out;
-		}
-	}
-	list_add(&inc->p_list, &udp_apps[hash]);
-	atomic_inc(&ip_vs_protocol_udp.appcnt);
-
-  out:
-	spin_unlock_bh(&udp_app_lock);
-	return ret;
-}
-
-
-static void
-udp_unregister_app(struct ip_vs_app *inc)
-{
-	spin_lock_bh(&udp_app_lock);
-	atomic_dec(&ip_vs_protocol_udp.appcnt);
-	list_del(&inc->p_list);
-	spin_unlock_bh(&udp_app_lock);
-}
-
-
-static int udp_app_conn_bind(struct ip_vs_conn *cp)
-{
-	int hash;
-	struct ip_vs_app *inc;
-	int result = 0;
-
-	/* Default binding: bind app only for NAT */
-	if (IP_VS_FWD_METHOD(cp) != IP_VS_CONN_F_MASQ)
-		return 0;
-
-	/* Lookup application incarnations and bind the right one */
-	hash = udp_app_hashkey(cp->vport);
-
-	spin_lock(&udp_app_lock);
-	list_for_each_entry(inc, &udp_apps[hash], p_list) {
-		if (inc->port == cp->vport) {
-			if (unlikely(!ip_vs_app_inc_get(inc)))
-				break;
-			spin_unlock(&udp_app_lock);
-
-			IP_VS_DBG(9, "%s: Binding conn %u.%u.%u.%u:%u->"
-				  "%u.%u.%u.%u:%u to app %s on port %u\n",
-				  __func__,
-				  NIPQUAD(cp->caddr), ntohs(cp->cport),
-				  NIPQUAD(cp->vaddr), ntohs(cp->vport),
-				  inc->name, ntohs(inc->port));
-			cp->app = inc;
-			if (inc->init_conn)
-				result = inc->init_conn(inc, cp);
-			goto out;
-		}
-	}
-	spin_unlock(&udp_app_lock);
-
-  out:
-	return result;
-}
-
-
-static int udp_timeouts[IP_VS_UDP_S_LAST+1] = {
-	[IP_VS_UDP_S_NORMAL]		=	5*60*HZ,
-	[IP_VS_UDP_S_LAST]		=	2*HZ,
-};
-
-static char * udp_state_name_table[IP_VS_UDP_S_LAST+1] = {
-	[IP_VS_UDP_S_NORMAL]		=	"UDP",
-	[IP_VS_UDP_S_LAST]		=	"BUG!",
-};
-
-
-static int
-udp_set_state_timeout(struct ip_vs_protocol *pp, char *sname, int to)
-{
-	return ip_vs_set_state_timeout(pp->timeout_table, IP_VS_UDP_S_LAST,
-				       udp_state_name_table, sname, to);
-}
-
-static const char * udp_state_name(int state)
-{
-	if (state >= IP_VS_UDP_S_LAST)
-		return "ERR!";
-	return udp_state_name_table[state] ? udp_state_name_table[state] : "?";
-}
-
-static int
-udp_state_transition(struct ip_vs_conn *cp, int direction,
-		     const struct sk_buff *skb,
-		     struct ip_vs_protocol *pp)
-{
-	cp->timeout = pp->timeout_table[IP_VS_UDP_S_NORMAL];
-	return 1;
-}
-
-static void udp_init(struct ip_vs_protocol *pp)
-{
-	IP_VS_INIT_HASH_TABLE(udp_apps);
-	pp->timeout_table = udp_timeouts;
-}
-
-static void udp_exit(struct ip_vs_protocol *pp)
-{
-}
-
-
-struct ip_vs_protocol ip_vs_protocol_udp = {
-	.name =			"UDP",
-	.protocol =		IPPROTO_UDP,
-	.num_states =		IP_VS_UDP_S_LAST,
-	.dont_defrag =		0,
-	.init =			udp_init,
-	.exit =			udp_exit,
-	.conn_schedule =	udp_conn_schedule,
-	.conn_in_get =		udp_conn_in_get,
-	.conn_out_get =		udp_conn_out_get,
-	.snat_handler =		udp_snat_handler,
-	.dnat_handler =		udp_dnat_handler,
-	.csum_check =		udp_csum_check,
-	.state_transition =	udp_state_transition,
-	.state_name =		udp_state_name,
-	.register_app =		udp_register_app,
-	.unregister_app =	udp_unregister_app,
-	.app_conn_bind =	udp_app_conn_bind,
-	.debug_packet =		ip_vs_tcpudp_debug_packet,
-	.timeout_change =	NULL,
-	.set_state_timeout =	udp_set_state_timeout,
-};
diff --git a/net/ipv4/ipvs/ip_vs_rr.c b/net/ipv4/ipvs/ip_vs_rr.c
deleted file mode 100644
index 358110d..0000000
--- a/net/ipv4/ipvs/ip_vs_rr.c
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * IPVS:        Round-Robin Scheduling module
- *
- * Authors:     Wensong Zhang <wensong@linuxvirtualserver.org>
- *              Peter Kese <peter.kese@ijs.si>
- *
- *              This program is free software; you can redistribute it and/or
- *              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.
- *
- * Fixes/Changes:
- *     Wensong Zhang            :     changed the ip_vs_rr_schedule to return dest
- *     Julian Anastasov         :     fixed the NULL pointer access bug in debugging
- *     Wensong Zhang            :     changed some comestics things for debugging
- *     Wensong Zhang            :     changed for the d-linked destination list
- *     Wensong Zhang            :     added the ip_vs_rr_update_svc
- *     Wensong Zhang            :     added any dest with weight=0 is quiesced
- *
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-
-#include <net/ip_vs.h>
-
-
-static int ip_vs_rr_init_svc(struct ip_vs_service *svc)
-{
-	svc->sched_data = &svc->destinations;
-	return 0;
-}
-
-
-static int ip_vs_rr_done_svc(struct ip_vs_service *svc)
-{
-	return 0;
-}
-
-
-static int ip_vs_rr_update_svc(struct ip_vs_service *svc)
-{
-	svc->sched_data = &svc->destinations;
-	return 0;
-}
-
-
-/*
- * Round-Robin Scheduling
- */
-static struct ip_vs_dest *
-ip_vs_rr_schedule(struct ip_vs_service *svc, const struct sk_buff *skb)
-{
-	struct list_head *p, *q;
-	struct ip_vs_dest *dest;
-
-	IP_VS_DBG(6, "ip_vs_rr_schedule(): Scheduling...\n");
-
-	write_lock(&svc->sched_lock);
-	p = (struct list_head *)svc->sched_data;
-	p = p->next;
-	q = p;
-	do {
-		/* skip list head */
-		if (q == &svc->destinations) {
-			q = q->next;
-			continue;
-		}
-
-		dest = list_entry(q, struct ip_vs_dest, n_list);
-		if (!(dest->flags & IP_VS_DEST_F_OVERLOAD) &&
-		    atomic_read(&dest->weight) > 0)
-			/* HIT */
-			goto out;
-		q = q->next;
-	} while (q != p);
-	write_unlock(&svc->sched_lock);
-	return NULL;
-
-  out:
-	svc->sched_data = q;
-	write_unlock(&svc->sched_lock);
-	IP_VS_DBG(6, "RR: server %u.%u.%u.%u:%u "
-		  "activeconns %d refcnt %d weight %d\n",
-		  NIPQUAD(dest->addr), ntohs(dest->port),
-		  atomic_read(&dest->activeconns),
-		  atomic_read(&dest->refcnt), atomic_read(&dest->weight));
-
-	return dest;
-}
-
-
-static struct ip_vs_scheduler ip_vs_rr_scheduler = {
-	.name =			"rr",			/* name */
-	.refcnt =		ATOMIC_INIT(0),
-	.module =		THIS_MODULE,
-	.n_list =		LIST_HEAD_INIT(ip_vs_rr_scheduler.n_list),
-	.init_service =		ip_vs_rr_init_svc,
-	.done_service =		ip_vs_rr_done_svc,
-	.update_service =	ip_vs_rr_update_svc,
-	.schedule =		ip_vs_rr_schedule,
-};
-
-static int __init ip_vs_rr_init(void)
-{
-	return register_ip_vs_scheduler(&ip_vs_rr_scheduler);
-}
-
-static void __exit ip_vs_rr_cleanup(void)
-{
-	unregister_ip_vs_scheduler(&ip_vs_rr_scheduler);
-}
-
-module_init(ip_vs_rr_init);
-module_exit(ip_vs_rr_cleanup);
-MODULE_LICENSE("GPL");
diff --git a/net/ipv4/ipvs/ip_vs_sed.c b/net/ipv4/ipvs/ip_vs_sed.c
deleted file mode 100644
index 77663d8..0000000
--- a/net/ipv4/ipvs/ip_vs_sed.c
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- * IPVS:        Shortest Expected Delay scheduling module
- *
- * Authors:     Wensong Zhang <wensong@linuxvirtualserver.org>
- *
- *              This program is free software; you can redistribute it and/or
- *              modify it under the terms of the GNU General Public License
- *              as published by the Free Software Foundation; either version
- *              2 of the License, or (at your option) any later version.
- *
- * Changes:
- *
- */
-
-/*
- * The SED algorithm attempts to minimize each job's expected delay until
- * completion. The expected delay that the job will experience is
- * (Ci + 1) / Ui if sent to the ith server, in which Ci is the number of
- * jobs on the ith server and Ui is the fixed service rate (weight) of
- * the ith server. The SED algorithm adopts a greedy policy that each does
- * what is in its own best interest, i.e. to join the queue which would
- * minimize its expected delay of completion.
- *
- * See the following paper for more information:
- * A. Weinrib and S. Shenker, Greed is not enough: Adaptive load sharing
- * in large heterogeneous systems. In Proceedings IEEE INFOCOM'88,
- * pages 986-994, 1988.
- *
- * Thanks must go to Marko Buuri <marko@buuri.name> for talking SED to me.
- *
- * The difference between SED and WLC is that SED includes the incoming
- * job in the cost function (the increment of 1). SED may outperform
- * WLC, while scheduling big jobs under larger heterogeneous systems
- * (the server weight varies a lot).
- *
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-
-#include <net/ip_vs.h>
-
-
-static int
-ip_vs_sed_init_svc(struct ip_vs_service *svc)
-{
-	return 0;
-}
-
-
-static int
-ip_vs_sed_done_svc(struct ip_vs_service *svc)
-{
-	return 0;
-}
-
-
-static int
-ip_vs_sed_update_svc(struct ip_vs_service *svc)
-{
-	return 0;
-}
-
-
-static inline unsigned int
-ip_vs_sed_dest_overhead(struct ip_vs_dest *dest)
-{
-	/*
-	 * We only use the active connection number in the cost
-	 * calculation here.
-	 */
-	return atomic_read(&dest->activeconns) + 1;
-}
-
-
-/*
- *	Weighted Least Connection scheduling
- */
-static struct ip_vs_dest *
-ip_vs_sed_schedule(struct ip_vs_service *svc, const struct sk_buff *skb)
-{
-	struct ip_vs_dest *dest, *least;
-	unsigned int loh, doh;
-
-	IP_VS_DBG(6, "ip_vs_sed_schedule(): Scheduling...\n");
-
-	/*
-	 * We calculate the load of each dest server as follows:
-	 *	(server expected overhead) / dest->weight
-	 *
-	 * Remember -- no floats in kernel mode!!!
-	 * The comparison of h1*w2 > h2*w1 is equivalent to that of
-	 *		  h1/w1 > h2/w2
-	 * if every weight is larger than zero.
-	 *
-	 * The server with weight=0 is quiesced and will not receive any
-	 * new connections.
-	 */
-
-	list_for_each_entry(dest, &svc->destinations, n_list) {
-		if (!(dest->flags & IP_VS_DEST_F_OVERLOAD) &&
-		    atomic_read(&dest->weight) > 0) {
-			least = dest;
-			loh = ip_vs_sed_dest_overhead(least);
-			goto nextstage;
-		}
-	}
-	return NULL;
-
-	/*
-	 *    Find the destination with the least load.
-	 */
-  nextstage:
-	list_for_each_entry_continue(dest, &svc->destinations, n_list) {
-		if (dest->flags & IP_VS_DEST_F_OVERLOAD)
-			continue;
-		doh = ip_vs_sed_dest_overhead(dest);
-		if (loh * atomic_read(&dest->weight) >
-		    doh * atomic_read(&least->weight)) {
-			least = dest;
-			loh = doh;
-		}
-	}
-
-	IP_VS_DBG(6, "SED: server %u.%u.%u.%u:%u "
-		  "activeconns %d refcnt %d weight %d overhead %d\n",
-		  NIPQUAD(least->addr), ntohs(least->port),
-		  atomic_read(&least->activeconns),
-		  atomic_read(&least->refcnt),
-		  atomic_read(&least->weight), loh);
-
-	return least;
-}
-
-
-static struct ip_vs_scheduler ip_vs_sed_scheduler =
-{
-	.name =			"sed",
-	.refcnt =		ATOMIC_INIT(0),
-	.module =		THIS_MODULE,
-	.n_list =		LIST_HEAD_INIT(ip_vs_sed_scheduler.n_list),
-	.init_service =		ip_vs_sed_init_svc,
-	.done_service =		ip_vs_sed_done_svc,
-	.update_service =	ip_vs_sed_update_svc,
-	.schedule =		ip_vs_sed_schedule,
-};
-
-
-static int __init ip_vs_sed_init(void)
-{
-	return register_ip_vs_scheduler(&ip_vs_sed_scheduler);
-}
-
-static void __exit ip_vs_sed_cleanup(void)
-{
-	unregister_ip_vs_scheduler(&ip_vs_sed_scheduler);
-}
-
-module_init(ip_vs_sed_init);
-module_exit(ip_vs_sed_cleanup);
-MODULE_LICENSE("GPL");
diff --git a/net/ipv4/ipvs/ip_vs_sh.c b/net/ipv4/ipvs/ip_vs_sh.c
deleted file mode 100644
index 7b979e2..0000000
--- a/net/ipv4/ipvs/ip_vs_sh.c
+++ /dev/null
@@ -1,255 +0,0 @@
-/*
- * IPVS:        Source Hashing scheduling module
- *
- * Authors:     Wensong Zhang <wensong@gnuchina.org>
- *
- *              This program is free software; you can redistribute it and/or
- *              modify it under the terms of the GNU General Public License
- *              as published by the Free Software Foundation; either version
- *              2 of the License, or (at your option) any later version.
- *
- * Changes:
- *
- */
-
-/*
- * The sh algorithm is to select server by the hash key of source IP
- * address. The pseudo code is as follows:
- *
- *       n <- servernode[src_ip];
- *       if (n is dead) OR
- *          (n is overloaded) or (n.weight <= 0) then
- *                 return NULL;
- *
- *       return n;
- *
- * Notes that servernode is a 256-bucket hash table that maps the hash
- * index derived from packet source IP address to the current server
- * array. If the sh scheduler is used in cache cluster, it is good to
- * combine it with cache_bypass feature. When the statically assigned
- * server is dead or overloaded, the load balancer can bypass the cache
- * server and send requests to the original server directly.
- *
- */
-
-#include <linux/ip.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/skbuff.h>
-
-#include <net/ip_vs.h>
-
-
-/*
- *      IPVS SH bucket
- */
-struct ip_vs_sh_bucket {
-	struct ip_vs_dest       *dest;          /* real server (cache) */
-};
-
-/*
- *     for IPVS SH entry hash table
- */
-#ifndef CONFIG_IP_VS_SH_TAB_BITS
-#define CONFIG_IP_VS_SH_TAB_BITS        8
-#endif
-#define IP_VS_SH_TAB_BITS               CONFIG_IP_VS_SH_TAB_BITS
-#define IP_VS_SH_TAB_SIZE               (1 << IP_VS_SH_TAB_BITS)
-#define IP_VS_SH_TAB_MASK               (IP_VS_SH_TAB_SIZE - 1)
-
-
-/*
- *	Returns hash value for IPVS SH entry
- */
-static inline unsigned ip_vs_sh_hashkey(__be32 addr)
-{
-	return (ntohl(addr)*2654435761UL) & IP_VS_SH_TAB_MASK;
-}
-
-
-/*
- *      Get ip_vs_dest associated with supplied parameters.
- */
-static inline struct ip_vs_dest *
-ip_vs_sh_get(struct ip_vs_sh_bucket *tbl, __be32 addr)
-{
-	return (tbl[ip_vs_sh_hashkey(addr)]).dest;
-}
-
-
-/*
- *      Assign all the hash buckets of the specified table with the service.
- */
-static int
-ip_vs_sh_assign(struct ip_vs_sh_bucket *tbl, struct ip_vs_service *svc)
-{
-	int i;
-	struct ip_vs_sh_bucket *b;
-	struct list_head *p;
-	struct ip_vs_dest *dest;
-
-	b = tbl;
-	p = &svc->destinations;
-	for (i=0; i<IP_VS_SH_TAB_SIZE; i++) {
-		if (list_empty(p)) {
-			b->dest = NULL;
-		} else {
-			if (p == &svc->destinations)
-				p = p->next;
-
-			dest = list_entry(p, struct ip_vs_dest, n_list);
-			atomic_inc(&dest->refcnt);
-			b->dest = dest;
-
-			p = p->next;
-		}
-		b++;
-	}
-	return 0;
-}
-
-
-/*
- *      Flush all the hash buckets of the specified table.
- */
-static void ip_vs_sh_flush(struct ip_vs_sh_bucket *tbl)
-{
-	int i;
-	struct ip_vs_sh_bucket *b;
-
-	b = tbl;
-	for (i=0; i<IP_VS_SH_TAB_SIZE; i++) {
-		if (b->dest) {
-			atomic_dec(&b->dest->refcnt);
-			b->dest = NULL;
-		}
-		b++;
-	}
-}
-
-
-static int ip_vs_sh_init_svc(struct ip_vs_service *svc)
-{
-	struct ip_vs_sh_bucket *tbl;
-
-	/* allocate the SH table for this service */
-	tbl = kmalloc(sizeof(struct ip_vs_sh_bucket)*IP_VS_SH_TAB_SIZE,
-		      GFP_ATOMIC);
-	if (tbl == NULL) {
-		IP_VS_ERR("ip_vs_sh_init_svc(): no memory\n");
-		return -ENOMEM;
-	}
-	svc->sched_data = tbl;
-	IP_VS_DBG(6, "SH hash table (memory=%Zdbytes) allocated for "
-		  "current service\n",
-		  sizeof(struct ip_vs_sh_bucket)*IP_VS_SH_TAB_SIZE);
-
-	/* assign the hash buckets with the updated service */
-	ip_vs_sh_assign(tbl, svc);
-
-	return 0;
-}
-
-
-static int ip_vs_sh_done_svc(struct ip_vs_service *svc)
-{
-	struct ip_vs_sh_bucket *tbl = svc->sched_data;
-
-	/* got to clean up hash buckets here */
-	ip_vs_sh_flush(tbl);
-
-	/* release the table itself */
-	kfree(svc->sched_data);
-	IP_VS_DBG(6, "SH hash table (memory=%Zdbytes) released\n",
-		  sizeof(struct ip_vs_sh_bucket)*IP_VS_SH_TAB_SIZE);
-
-	return 0;
-}
-
-
-static int ip_vs_sh_update_svc(struct ip_vs_service *svc)
-{
-	struct ip_vs_sh_bucket *tbl = svc->sched_data;
-
-	/* got to clean up hash buckets here */
-	ip_vs_sh_flush(tbl);
-
-	/* assign the hash buckets with the updated service */
-	ip_vs_sh_assign(tbl, svc);
-
-	return 0;
-}
-
-
-/*
- *      If the dest flags is set with IP_VS_DEST_F_OVERLOAD,
- *      consider that the server is overloaded here.
- */
-static inline int is_overloaded(struct ip_vs_dest *dest)
-{
-	return dest->flags & IP_VS_DEST_F_OVERLOAD;
-}
-
-
-/*
- *      Source Hashing scheduling
- */
-static struct ip_vs_dest *
-ip_vs_sh_schedule(struct ip_vs_service *svc, const struct sk_buff *skb)
-{
-	struct ip_vs_dest *dest;
-	struct ip_vs_sh_bucket *tbl;
-	struct iphdr *iph = ip_hdr(skb);
-
-	IP_VS_DBG(6, "ip_vs_sh_schedule(): Scheduling...\n");
-
-	tbl = (struct ip_vs_sh_bucket *)svc->sched_data;
-	dest = ip_vs_sh_get(tbl, iph->saddr);
-	if (!dest
-	    || !(dest->flags & IP_VS_DEST_F_AVAILABLE)
-	    || atomic_read(&dest->weight) <= 0
-	    || is_overloaded(dest)) {
-		return NULL;
-	}
-
-	IP_VS_DBG(6, "SH: source IP address %u.%u.%u.%u "
-		  "--> server %u.%u.%u.%u:%d\n",
-		  NIPQUAD(iph->saddr),
-		  NIPQUAD(dest->addr),
-		  ntohs(dest->port));
-
-	return dest;
-}
-
-
-/*
- *      IPVS SH Scheduler structure
- */
-static struct ip_vs_scheduler ip_vs_sh_scheduler =
-{
-	.name =			"sh",
-	.refcnt =		ATOMIC_INIT(0),
-	.module =		THIS_MODULE,
-	.n_list	 =		LIST_HEAD_INIT(ip_vs_sh_scheduler.n_list),
-	.init_service =		ip_vs_sh_init_svc,
-	.done_service =		ip_vs_sh_done_svc,
-	.update_service =	ip_vs_sh_update_svc,
-	.schedule =		ip_vs_sh_schedule,
-};
-
-
-static int __init ip_vs_sh_init(void)
-{
-	return register_ip_vs_scheduler(&ip_vs_sh_scheduler);
-}
-
-
-static void __exit ip_vs_sh_cleanup(void)
-{
-	unregister_ip_vs_scheduler(&ip_vs_sh_scheduler);
-}
-
-
-module_init(ip_vs_sh_init);
-module_exit(ip_vs_sh_cleanup);
-MODULE_LICENSE("GPL");
diff --git a/net/ipv4/ipvs/ip_vs_sync.c b/net/ipv4/ipvs/ip_vs_sync.c
deleted file mode 100644
index a652da2..0000000
--- a/net/ipv4/ipvs/ip_vs_sync.c
+++ /dev/null
@@ -1,930 +0,0 @@
-/*
- * IPVS         An implementation of the IP virtual server support for the
- *              LINUX operating system.  IPVS is now implemented as a module
- *              over the NetFilter framework. IPVS can be used to build a
- *              high-performance and highly available server based on a
- *              cluster of servers.
- *
- * Authors:     Wensong Zhang <wensong@linuxvirtualserver.org>
- *
- * ip_vs_sync:  sync connection info from master load balancer to backups
- *              through multicast
- *
- * Changes:
- *	Alexandre Cassen	:	Added master & backup support at a time.
- *	Alexandre Cassen	:	Added SyncID support for incoming sync
- *					messages filtering.
- *	Justin Ossevoort	:	Fix endian problem on sync message size.
- */
-
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/inetdevice.h>
-#include <linux/net.h>
-#include <linux/completion.h>
-#include <linux/delay.h>
-#include <linux/skbuff.h>
-#include <linux/in.h>
-#include <linux/igmp.h>                 /* for ip_mc_join_group */
-#include <linux/udp.h>
-#include <linux/err.h>
-#include <linux/kthread.h>
-#include <linux/wait.h>
-
-#include <net/ip.h>
-#include <net/sock.h>
-
-#include <net/ip_vs.h>
-
-#define IP_VS_SYNC_GROUP 0xe0000051    /* multicast addr - 224.0.0.81 */
-#define IP_VS_SYNC_PORT  8848          /* multicast port */
-
-
-/*
- *	IPVS sync connection entry
- */
-struct ip_vs_sync_conn {
-	__u8			reserved;
-
-	/* Protocol, addresses and port numbers */
-	__u8			protocol;       /* Which protocol (TCP/UDP) */
-	__be16			cport;
-	__be16                  vport;
-	__be16                  dport;
-	__be32                  caddr;          /* client address */
-	__be32                  vaddr;          /* virtual address */
-	__be32                  daddr;          /* destination address */
-
-	/* Flags and state transition */
-	__be16                  flags;          /* status flags */
-	__be16                  state;          /* state info */
-
-	/* The sequence options start here */
-};
-
-struct ip_vs_sync_conn_options {
-	struct ip_vs_seq        in_seq;         /* incoming seq. struct */
-	struct ip_vs_seq        out_seq;        /* outgoing seq. struct */
-};
-
-struct ip_vs_sync_thread_data {
-	struct socket *sock;
-	char *buf;
-};
-
-#define SIMPLE_CONN_SIZE  (sizeof(struct ip_vs_sync_conn))
-#define FULL_CONN_SIZE  \
-(sizeof(struct ip_vs_sync_conn) + sizeof(struct ip_vs_sync_conn_options))
-
-
-/*
-  The master mulitcasts messages to the backup load balancers in the
-  following format.
-
-       0                   1                   2                   3
-       0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
-      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-      |  Count Conns  |    SyncID     |            Size               |
-      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-      |                                                               |
-      |                    IPVS Sync Connection (1)                   |
-      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-      |                            .                                  |
-      |                            .                                  |
-      |                            .                                  |
-      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-      |                                                               |
-      |                    IPVS Sync Connection (n)                   |
-      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-*/
-
-#define SYNC_MESG_HEADER_LEN	4
-
-struct ip_vs_sync_mesg {
-	__u8                    nr_conns;
-	__u8                    syncid;
-	__u16                   size;
-
-	/* ip_vs_sync_conn entries start here */
-};
-
-/* the maximum length of sync (sending/receiving) message */
-static int sync_send_mesg_maxlen;
-static int sync_recv_mesg_maxlen;
-
-struct ip_vs_sync_buff {
-	struct list_head        list;
-	unsigned long           firstuse;
-
-	/* pointers for the message data */
-	struct ip_vs_sync_mesg  *mesg;
-	unsigned char           *head;
-	unsigned char           *end;
-};
-
-
-/* the sync_buff list head and the lock */
-static LIST_HEAD(ip_vs_sync_queue);
-static DEFINE_SPINLOCK(ip_vs_sync_lock);
-
-/* current sync_buff for accepting new conn entries */
-static struct ip_vs_sync_buff   *curr_sb = NULL;
-static DEFINE_SPINLOCK(curr_sb_lock);
-
-/* ipvs sync daemon state */
-volatile int ip_vs_sync_state = IP_VS_STATE_NONE;
-volatile int ip_vs_master_syncid = 0;
-volatile int ip_vs_backup_syncid = 0;
-
-/* multicast interface name */
-char ip_vs_master_mcast_ifn[IP_VS_IFNAME_MAXLEN];
-char ip_vs_backup_mcast_ifn[IP_VS_IFNAME_MAXLEN];
-
-/* sync daemon tasks */
-static struct task_struct *sync_master_thread;
-static struct task_struct *sync_backup_thread;
-
-/* multicast addr */
-static struct sockaddr_in mcast_addr = {
-	.sin_family		= AF_INET,
-	.sin_port		= __constant_htons(IP_VS_SYNC_PORT),
-	.sin_addr.s_addr	= __constant_htonl(IP_VS_SYNC_GROUP),
-};
-
-
-static inline struct ip_vs_sync_buff *sb_dequeue(void)
-{
-	struct ip_vs_sync_buff *sb;
-
-	spin_lock_bh(&ip_vs_sync_lock);
-	if (list_empty(&ip_vs_sync_queue)) {
-		sb = NULL;
-	} else {
-		sb = list_entry(ip_vs_sync_queue.next,
-				struct ip_vs_sync_buff,
-				list);
-		list_del(&sb->list);
-	}
-	spin_unlock_bh(&ip_vs_sync_lock);
-
-	return sb;
-}
-
-static inline struct ip_vs_sync_buff * ip_vs_sync_buff_create(void)
-{
-	struct ip_vs_sync_buff *sb;
-
-	if (!(sb=kmalloc(sizeof(struct ip_vs_sync_buff), GFP_ATOMIC)))
-		return NULL;
-
-	if (!(sb->mesg=kmalloc(sync_send_mesg_maxlen, GFP_ATOMIC))) {
-		kfree(sb);
-		return NULL;
-	}
-	sb->mesg->nr_conns = 0;
-	sb->mesg->syncid = ip_vs_master_syncid;
-	sb->mesg->size = 4;
-	sb->head = (unsigned char *)sb->mesg + 4;
-	sb->end = (unsigned char *)sb->mesg + sync_send_mesg_maxlen;
-	sb->firstuse = jiffies;
-	return sb;
-}
-
-static inline void ip_vs_sync_buff_release(struct ip_vs_sync_buff *sb)
-{
-	kfree(sb->mesg);
-	kfree(sb);
-}
-
-static inline void sb_queue_tail(struct ip_vs_sync_buff *sb)
-{
-	spin_lock(&ip_vs_sync_lock);
-	if (ip_vs_sync_state & IP_VS_STATE_MASTER)
-		list_add_tail(&sb->list, &ip_vs_sync_queue);
-	else
-		ip_vs_sync_buff_release(sb);
-	spin_unlock(&ip_vs_sync_lock);
-}
-
-/*
- *	Get the current sync buffer if it has been created for more
- *	than the specified time or the specified time is zero.
- */
-static inline struct ip_vs_sync_buff *
-get_curr_sync_buff(unsigned long time)
-{
-	struct ip_vs_sync_buff *sb;
-
-	spin_lock_bh(&curr_sb_lock);
-	if (curr_sb && (time == 0 ||
-			time_before(jiffies - curr_sb->firstuse, time))) {
-		sb = curr_sb;
-		curr_sb = NULL;
-	} else
-		sb = NULL;
-	spin_unlock_bh(&curr_sb_lock);
-	return sb;
-}
-
-
-/*
- *      Add an ip_vs_conn information into the current sync_buff.
- *      Called by ip_vs_in.
- */
-void ip_vs_sync_conn(struct ip_vs_conn *cp)
-{
-	struct ip_vs_sync_mesg *m;
-	struct ip_vs_sync_conn *s;
-	int len;
-
-	spin_lock(&curr_sb_lock);
-	if (!curr_sb) {
-		if (!(curr_sb=ip_vs_sync_buff_create())) {
-			spin_unlock(&curr_sb_lock);
-			IP_VS_ERR("ip_vs_sync_buff_create failed.\n");
-			return;
-		}
-	}
-
-	len = (cp->flags & IP_VS_CONN_F_SEQ_MASK) ? FULL_CONN_SIZE :
-		SIMPLE_CONN_SIZE;
-	m = curr_sb->mesg;
-	s = (struct ip_vs_sync_conn *)curr_sb->head;
-
-	/* copy members */
-	s->protocol = cp->protocol;
-	s->cport = cp->cport;
-	s->vport = cp->vport;
-	s->dport = cp->dport;
-	s->caddr = cp->caddr;
-	s->vaddr = cp->vaddr;
-	s->daddr = cp->daddr;
-	s->flags = htons(cp->flags & ~IP_VS_CONN_F_HASHED);
-	s->state = htons(cp->state);
-	if (cp->flags & IP_VS_CONN_F_SEQ_MASK) {
-		struct ip_vs_sync_conn_options *opt =
-			(struct ip_vs_sync_conn_options *)&s[1];
-		memcpy(opt, &cp->in_seq, sizeof(*opt));
-	}
-
-	m->nr_conns++;
-	m->size += len;
-	curr_sb->head += len;
-
-	/* check if there is a space for next one */
-	if (curr_sb->head+FULL_CONN_SIZE > curr_sb->end) {
-		sb_queue_tail(curr_sb);
-		curr_sb = NULL;
-	}
-	spin_unlock(&curr_sb_lock);
-
-	/* synchronize its controller if it has */
-	if (cp->control)
-		ip_vs_sync_conn(cp->control);
-}
-
-
-/*
- *      Process received multicast message and create the corresponding
- *      ip_vs_conn entries.
- */
-static void ip_vs_process_message(const char *buffer, const size_t buflen)
-{
-	struct ip_vs_sync_mesg *m = (struct ip_vs_sync_mesg *)buffer;
-	struct ip_vs_sync_conn *s;
-	struct ip_vs_sync_conn_options *opt;
-	struct ip_vs_conn *cp;
-	struct ip_vs_protocol *pp;
-	struct ip_vs_dest *dest;
-	char *p;
-	int i;
-
-	if (buflen < sizeof(struct ip_vs_sync_mesg)) {
-		IP_VS_ERR_RL("sync message header too short\n");
-		return;
-	}
-
-	/* Convert size back to host byte order */
-	m->size = ntohs(m->size);
-
-	if (buflen != m->size) {
-		IP_VS_ERR_RL("bogus sync message size\n");
-		return;
-	}
-
-	/* SyncID sanity check */
-	if (ip_vs_backup_syncid != 0 && m->syncid != ip_vs_backup_syncid) {
-		IP_VS_DBG(7, "Ignoring incoming msg with syncid = %d\n",
-			  m->syncid);
-		return;
-	}
-
-	p = (char *)buffer + sizeof(struct ip_vs_sync_mesg);
-	for (i=0; i<m->nr_conns; i++) {
-		unsigned flags, state;
-
-		if (p + SIMPLE_CONN_SIZE > buffer+buflen) {
-			IP_VS_ERR_RL("bogus conn in sync message\n");
-			return;
-		}
-		s = (struct ip_vs_sync_conn *) p;
-		flags = ntohs(s->flags) | IP_VS_CONN_F_SYNC;
-		flags &= ~IP_VS_CONN_F_HASHED;
-		if (flags & IP_VS_CONN_F_SEQ_MASK) {
-			opt = (struct ip_vs_sync_conn_options *)&s[1];
-			p += FULL_CONN_SIZE;
-			if (p > buffer+buflen) {
-				IP_VS_ERR_RL("bogus conn options in sync message\n");
-				return;
-			}
-		} else {
-			opt = NULL;
-			p += SIMPLE_CONN_SIZE;
-		}
-
-		state = ntohs(s->state);
-		if (!(flags & IP_VS_CONN_F_TEMPLATE)) {
-			pp = ip_vs_proto_get(s->protocol);
-			if (!pp) {
-				IP_VS_ERR_RL("Unsupported protocol %u in sync msg\n",
-					s->protocol);
-				continue;
-			}
-			if (state >= pp->num_states) {
-				IP_VS_DBG(2, "Invalid %s state %u in sync msg\n",
-					pp->name, state);
-				continue;
-			}
-		} else {
-			/* protocol in templates is not used for state/timeout */
-			pp = NULL;
-			if (state > 0) {
-				IP_VS_DBG(2, "Invalid template state %u in sync msg\n",
-					state);
-				state = 0;
-			}
-		}
-
-		if (!(flags & IP_VS_CONN_F_TEMPLATE))
-			cp = ip_vs_conn_in_get(s->protocol,
-					       s->caddr, s->cport,
-					       s->vaddr, s->vport);
-		else
-			cp = ip_vs_ct_in_get(s->protocol,
-					       s->caddr, s->cport,
-					       s->vaddr, s->vport);
-		if (!cp) {
-			/*
-			 * Find the appropriate destination for the connection.
-			 * If it is not found the connection will remain unbound
-			 * but still handled.
-			 */
-			dest = ip_vs_find_dest(s->daddr, s->dport,
-					       s->vaddr, s->vport,
-					       s->protocol);
-			/*  Set the approprite ativity flag */
-			if (s->protocol == IPPROTO_TCP) {
-				if (state != IP_VS_TCP_S_ESTABLISHED)
-					flags |= IP_VS_CONN_F_INACTIVE;
-				else
-					flags &= ~IP_VS_CONN_F_INACTIVE;
-			}
-			cp = ip_vs_conn_new(s->protocol,
-					    s->caddr, s->cport,
-					    s->vaddr, s->vport,
-					    s->daddr, s->dport,
-					    flags, dest);
-			if (dest)
-				atomic_dec(&dest->refcnt);
-			if (!cp) {
-				IP_VS_ERR("ip_vs_conn_new failed\n");
-				return;
-			}
-		} else if (!cp->dest) {
-			dest = ip_vs_try_bind_dest(cp);
-			if (dest)
-				atomic_dec(&dest->refcnt);
-		} else if ((cp->dest) && (cp->protocol == IPPROTO_TCP) &&
-			   (cp->state != state)) {
-			/* update active/inactive flag for the connection */
-			dest = cp->dest;
-			if (!(cp->flags & IP_VS_CONN_F_INACTIVE) &&
-				(state != IP_VS_TCP_S_ESTABLISHED)) {
-				atomic_dec(&dest->activeconns);
-				atomic_inc(&dest->inactconns);
-				cp->flags |= IP_VS_CONN_F_INACTIVE;
-			} else if ((cp->flags & IP_VS_CONN_F_INACTIVE) &&
-				(state == IP_VS_TCP_S_ESTABLISHED)) {
-				atomic_inc(&dest->activeconns);
-				atomic_dec(&dest->inactconns);
-				cp->flags &= ~IP_VS_CONN_F_INACTIVE;
-			}
-		}
-
-		if (opt)
-			memcpy(&cp->in_seq, opt, sizeof(*opt));
-		atomic_set(&cp->in_pkts, sysctl_ip_vs_sync_threshold[0]);
-		cp->state = state;
-		cp->old_state = cp->state;
-		/*
-		 * We can not recover the right timeout for templates
-		 * in all cases, we can not find the right fwmark
-		 * virtual service. If needed, we can do it for
-		 * non-fwmark persistent services.
-		 */
-		if (!(flags & IP_VS_CONN_F_TEMPLATE) && pp->timeout_table)
-			cp->timeout = pp->timeout_table[state];
-		else
-			cp->timeout = (3*60*HZ);
-		ip_vs_conn_put(cp);
-	}
-}
-
-
-/*
- *      Setup loopback of outgoing multicasts on a sending socket
- */
-static void set_mcast_loop(struct sock *sk, u_char loop)
-{
-	struct inet_sock *inet = inet_sk(sk);
-
-	/* setsockopt(sock, SOL_IP, IP_MULTICAST_LOOP, &loop, sizeof(loop)); */
-	lock_sock(sk);
-	inet->mc_loop = loop ? 1 : 0;
-	release_sock(sk);
-}
-
-/*
- *      Specify TTL for outgoing multicasts on a sending socket
- */
-static void set_mcast_ttl(struct sock *sk, u_char ttl)
-{
-	struct inet_sock *inet = inet_sk(sk);
-
-	/* setsockopt(sock, SOL_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)); */
-	lock_sock(sk);
-	inet->mc_ttl = ttl;
-	release_sock(sk);
-}
-
-/*
- *      Specifiy default interface for outgoing multicasts
- */
-static int set_mcast_if(struct sock *sk, char *ifname)
-{
-	struct net_device *dev;
-	struct inet_sock *inet = inet_sk(sk);
-
-	if ((dev = __dev_get_by_name(&init_net, ifname)) == NULL)
-		return -ENODEV;
-
-	if (sk->sk_bound_dev_if && dev->ifindex != sk->sk_bound_dev_if)
-		return -EINVAL;
-
-	lock_sock(sk);
-	inet->mc_index = dev->ifindex;
-	/*  inet->mc_addr  = 0; */
-	release_sock(sk);
-
-	return 0;
-}
-
-
-/*
- *	Set the maximum length of sync message according to the
- *	specified interface's MTU.
- */
-static int set_sync_mesg_maxlen(int sync_state)
-{
-	struct net_device *dev;
-	int num;
-
-	if (sync_state == IP_VS_STATE_MASTER) {
-		if ((dev = __dev_get_by_name(&init_net, ip_vs_master_mcast_ifn)) == NULL)
-			return -ENODEV;
-
-		num = (dev->mtu - sizeof(struct iphdr) -
-		       sizeof(struct udphdr) -
-		       SYNC_MESG_HEADER_LEN - 20) / SIMPLE_CONN_SIZE;
-		sync_send_mesg_maxlen =
-			SYNC_MESG_HEADER_LEN + SIMPLE_CONN_SIZE * num;
-		IP_VS_DBG(7, "setting the maximum length of sync sending "
-			  "message %d.\n", sync_send_mesg_maxlen);
-	} else if (sync_state == IP_VS_STATE_BACKUP) {
-		if ((dev = __dev_get_by_name(&init_net, ip_vs_backup_mcast_ifn)) == NULL)
-			return -ENODEV;
-
-		sync_recv_mesg_maxlen = dev->mtu -
-			sizeof(struct iphdr) - sizeof(struct udphdr);
-		IP_VS_DBG(7, "setting the maximum length of sync receiving "
-			  "message %d.\n", sync_recv_mesg_maxlen);
-	}
-
-	return 0;
-}
-
-
-/*
- *      Join a multicast group.
- *      the group is specified by a class D multicast address 224.0.0.0/8
- *      in the in_addr structure passed in as a parameter.
- */
-static int
-join_mcast_group(struct sock *sk, struct in_addr *addr, char *ifname)
-{
-	struct ip_mreqn mreq;
-	struct net_device *dev;
-	int ret;
-
-	memset(&mreq, 0, sizeof(mreq));
-	memcpy(&mreq.imr_multiaddr, addr, sizeof(struct in_addr));
-
-	if ((dev = __dev_get_by_name(&init_net, ifname)) == NULL)
-		return -ENODEV;
-	if (sk->sk_bound_dev_if && dev->ifindex != sk->sk_bound_dev_if)
-		return -EINVAL;
-
-	mreq.imr_ifindex = dev->ifindex;
-
-	lock_sock(sk);
-	ret = ip_mc_join_group(sk, &mreq);
-	release_sock(sk);
-
-	return ret;
-}
-
-
-static int bind_mcastif_addr(struct socket *sock, char *ifname)
-{
-	struct net_device *dev;
-	__be32 addr;
-	struct sockaddr_in sin;
-
-	if ((dev = __dev_get_by_name(&init_net, ifname)) == NULL)
-		return -ENODEV;
-
-	addr = inet_select_addr(dev, 0, RT_SCOPE_UNIVERSE);
-	if (!addr)
-		IP_VS_ERR("You probably need to specify IP address on "
-			  "multicast interface.\n");
-
-	IP_VS_DBG(7, "binding socket with (%s) %u.%u.%u.%u\n",
-		  ifname, NIPQUAD(addr));
-
-	/* Now bind the socket with the address of multicast interface */
-	sin.sin_family	     = AF_INET;
-	sin.sin_addr.s_addr  = addr;
-	sin.sin_port         = 0;
-
-	return sock->ops->bind(sock, (struct sockaddr*)&sin, sizeof(sin));
-}
-
-/*
- *      Set up sending multicast socket over UDP
- */
-static struct socket * make_send_sock(void)
-{
-	struct socket *sock;
-	int result;
-
-	/* First create a socket */
-	result = sock_create_kern(PF_INET, SOCK_DGRAM, IPPROTO_UDP, &sock);
-	if (result < 0) {
-		IP_VS_ERR("Error during creation of socket; terminating\n");
-		return ERR_PTR(result);
-	}
-
-	result = set_mcast_if(sock->sk, ip_vs_master_mcast_ifn);
-	if (result < 0) {
-		IP_VS_ERR("Error setting outbound mcast interface\n");
-		goto error;
-	}
-
-	set_mcast_loop(sock->sk, 0);
-	set_mcast_ttl(sock->sk, 1);
-
-	result = bind_mcastif_addr(sock, ip_vs_master_mcast_ifn);
-	if (result < 0) {
-		IP_VS_ERR("Error binding address of the mcast interface\n");
-		goto error;
-	}
-
-	result = sock->ops->connect(sock, (struct sockaddr *) &mcast_addr,
-			sizeof(struct sockaddr), 0);
-	if (result < 0) {
-		IP_VS_ERR("Error connecting to the multicast addr\n");
-		goto error;
-	}
-
-	return sock;
-
-  error:
-	sock_release(sock);
-	return ERR_PTR(result);
-}
-
-
-/*
- *      Set up receiving multicast socket over UDP
- */
-static struct socket * make_receive_sock(void)
-{
-	struct socket *sock;
-	int result;
-
-	/* First create a socket */
-	result = sock_create_kern(PF_INET, SOCK_DGRAM, IPPROTO_UDP, &sock);
-	if (result < 0) {
-		IP_VS_ERR("Error during creation of socket; terminating\n");
-		return ERR_PTR(result);
-	}
-
-	/* it is equivalent to the REUSEADDR option in user-space */
-	sock->sk->sk_reuse = 1;
-
-	result = sock->ops->bind(sock, (struct sockaddr *) &mcast_addr,
-			sizeof(struct sockaddr));
-	if (result < 0) {
-		IP_VS_ERR("Error binding to the multicast addr\n");
-		goto error;
-	}
-
-	/* join the multicast group */
-	result = join_mcast_group(sock->sk,
-			(struct in_addr *) &mcast_addr.sin_addr,
-			ip_vs_backup_mcast_ifn);
-	if (result < 0) {
-		IP_VS_ERR("Error joining to the multicast group\n");
-		goto error;
-	}
-
-	return sock;
-
-  error:
-	sock_release(sock);
-	return ERR_PTR(result);
-}
-
-
-static int
-ip_vs_send_async(struct socket *sock, const char *buffer, const size_t length)
-{
-	struct msghdr	msg = {.msg_flags = MSG_DONTWAIT|MSG_NOSIGNAL};
-	struct kvec	iov;
-	int		len;
-
-	EnterFunction(7);
-	iov.iov_base     = (void *)buffer;
-	iov.iov_len      = length;
-
-	len = kernel_sendmsg(sock, &msg, &iov, 1, (size_t)(length));
-
-	LeaveFunction(7);
-	return len;
-}
-
-static void
-ip_vs_send_sync_msg(struct socket *sock, struct ip_vs_sync_mesg *msg)
-{
-	int msize;
-
-	msize = msg->size;
-
-	/* Put size in network byte order */
-	msg->size = htons(msg->size);
-
-	if (ip_vs_send_async(sock, (char *)msg, msize) != msize)
-		IP_VS_ERR("ip_vs_send_async error\n");
-}
-
-static int
-ip_vs_receive(struct socket *sock, char *buffer, const size_t buflen)
-{
-	struct msghdr		msg = {NULL,};
-	struct kvec		iov;
-	int			len;
-
-	EnterFunction(7);
-
-	/* Receive a packet */
-	iov.iov_base     = buffer;
-	iov.iov_len      = (size_t)buflen;
-
-	len = kernel_recvmsg(sock, &msg, &iov, 1, buflen, 0);
-
-	if (len < 0)
-		return -1;
-
-	LeaveFunction(7);
-	return len;
-}
-
-
-static int sync_thread_master(void *data)
-{
-	struct ip_vs_sync_thread_data *tinfo = data;
-	struct ip_vs_sync_buff *sb;
-
-	IP_VS_INFO("sync thread started: state = MASTER, mcast_ifn = %s, "
-		   "syncid = %d\n",
-		   ip_vs_master_mcast_ifn, ip_vs_master_syncid);
-
-	while (!kthread_should_stop()) {
-		while ((sb = sb_dequeue())) {
-			ip_vs_send_sync_msg(tinfo->sock, sb->mesg);
-			ip_vs_sync_buff_release(sb);
-		}
-
-		/* check if entries stay in curr_sb for 2 seconds */
-		sb = get_curr_sync_buff(2 * HZ);
-		if (sb) {
-			ip_vs_send_sync_msg(tinfo->sock, sb->mesg);
-			ip_vs_sync_buff_release(sb);
-		}
-
-		schedule_timeout_interruptible(HZ);
-	}
-
-	/* clean up the sync_buff queue */
-	while ((sb=sb_dequeue())) {
-		ip_vs_sync_buff_release(sb);
-	}
-
-	/* clean up the current sync_buff */
-	if ((sb = get_curr_sync_buff(0))) {
-		ip_vs_sync_buff_release(sb);
-	}
-
-	/* release the sending multicast socket */
-	sock_release(tinfo->sock);
-	kfree(tinfo);
-
-	return 0;
-}
-
-
-static int sync_thread_backup(void *data)
-{
-	struct ip_vs_sync_thread_data *tinfo = data;
-	int len;
-
-	IP_VS_INFO("sync thread started: state = BACKUP, mcast_ifn = %s, "
-		   "syncid = %d\n",
-		   ip_vs_backup_mcast_ifn, ip_vs_backup_syncid);
-
-	while (!kthread_should_stop()) {
-		wait_event_interruptible(*tinfo->sock->sk->sk_sleep,
-			 !skb_queue_empty(&tinfo->sock->sk->sk_receive_queue)
-			 || kthread_should_stop());
-
-		/* do we have data now? */
-		while (!skb_queue_empty(&(tinfo->sock->sk->sk_receive_queue))) {
-			len = ip_vs_receive(tinfo->sock, tinfo->buf,
-					sync_recv_mesg_maxlen);
-			if (len <= 0) {
-				IP_VS_ERR("receiving message error\n");
-				break;
-			}
-
-			/* disable bottom half, because it accesses the data
-			   shared by softirq while getting/creating conns */
-			local_bh_disable();
-			ip_vs_process_message(tinfo->buf, len);
-			local_bh_enable();
-		}
-	}
-
-	/* release the sending multicast socket */
-	sock_release(tinfo->sock);
-	kfree(tinfo->buf);
-	kfree(tinfo);
-
-	return 0;
-}
-
-
-int start_sync_thread(int state, char *mcast_ifn, __u8 syncid)
-{
-	struct ip_vs_sync_thread_data *tinfo;
-	struct task_struct **realtask, *task;
-	struct socket *sock;
-	char *name, *buf = NULL;
-	int (*threadfn)(void *data);
-	int result = -ENOMEM;
-
-	IP_VS_DBG(7, "%s: pid %d\n", __func__, task_pid_nr(current));
-	IP_VS_DBG(7, "Each ip_vs_sync_conn entry needs %Zd bytes\n",
-		  sizeof(struct ip_vs_sync_conn));
-
-	if (state == IP_VS_STATE_MASTER) {
-		if (sync_master_thread)
-			return -EEXIST;
-
-		strlcpy(ip_vs_master_mcast_ifn, mcast_ifn,
-			sizeof(ip_vs_master_mcast_ifn));
-		ip_vs_master_syncid = syncid;
-		realtask = &sync_master_thread;
-		name = "ipvs_syncmaster";
-		threadfn = sync_thread_master;
-		sock = make_send_sock();
-	} else if (state == IP_VS_STATE_BACKUP) {
-		if (sync_backup_thread)
-			return -EEXIST;
-
-		strlcpy(ip_vs_backup_mcast_ifn, mcast_ifn,
-			sizeof(ip_vs_backup_mcast_ifn));
-		ip_vs_backup_syncid = syncid;
-		realtask = &sync_backup_thread;
-		name = "ipvs_syncbackup";
-		threadfn = sync_thread_backup;
-		sock = make_receive_sock();
-	} else {
-		return -EINVAL;
-	}
-
-	if (IS_ERR(sock)) {
-		result = PTR_ERR(sock);
-		goto out;
-	}
-
-	set_sync_mesg_maxlen(state);
-	if (state == IP_VS_STATE_BACKUP) {
-		buf = kmalloc(sync_recv_mesg_maxlen, GFP_KERNEL);
-		if (!buf)
-			goto outsocket;
-	}
-
-	tinfo = kmalloc(sizeof(*tinfo), GFP_KERNEL);
-	if (!tinfo)
-		goto outbuf;
-
-	tinfo->sock = sock;
-	tinfo->buf = buf;
-
-	task = kthread_run(threadfn, tinfo, name);
-	if (IS_ERR(task)) {
-		result = PTR_ERR(task);
-		goto outtinfo;
-	}
-
-	/* mark as active */
-	*realtask = task;
-	ip_vs_sync_state |= state;
-
-	/* increase the module use count */
-	ip_vs_use_count_inc();
-
-	return 0;
-
-outtinfo:
-	kfree(tinfo);
-outbuf:
-	kfree(buf);
-outsocket:
-	sock_release(sock);
-out:
-	return result;
-}
-
-
-int stop_sync_thread(int state)
-{
-	IP_VS_DBG(7, "%s: pid %d\n", __func__, task_pid_nr(current));
-
-	if (state == IP_VS_STATE_MASTER) {
-		if (!sync_master_thread)
-			return -ESRCH;
-
-		IP_VS_INFO("stopping master sync thread %d ...\n",
-			   task_pid_nr(sync_master_thread));
-
-		/*
-		 * The lock synchronizes with sb_queue_tail(), so that we don't
-		 * add sync buffers to the queue, when we are already in
-		 * progress of stopping the master sync daemon.
-		 */
-
-		spin_lock_bh(&ip_vs_sync_lock);
-		ip_vs_sync_state &= ~IP_VS_STATE_MASTER;
-		spin_unlock_bh(&ip_vs_sync_lock);
-		kthread_stop(sync_master_thread);
-		sync_master_thread = NULL;
-	} else if (state == IP_VS_STATE_BACKUP) {
-		if (!sync_backup_thread)
-			return -ESRCH;
-
-		IP_VS_INFO("stopping backup sync thread %d ...\n",
-			   task_pid_nr(sync_backup_thread));
-
-		ip_vs_sync_state &= ~IP_VS_STATE_BACKUP;
-		kthread_stop(sync_backup_thread);
-		sync_backup_thread = NULL;
-	} else {
-		return -EINVAL;
-	}
-
-	/* decrease the module use count */
-	ip_vs_use_count_dec();
-
-	return 0;
-}
diff --git a/net/ipv4/ipvs/ip_vs_wlc.c b/net/ipv4/ipvs/ip_vs_wlc.c
deleted file mode 100644
index 9b0ef86..0000000
--- a/net/ipv4/ipvs/ip_vs_wlc.c
+++ /dev/null
@@ -1,149 +0,0 @@
-/*
- * IPVS:        Weighted Least-Connection Scheduling module
- *
- * Authors:     Wensong Zhang <wensong@linuxvirtualserver.org>
- *              Peter Kese <peter.kese@ijs.si>
- *
- *              This program is free software; you can redistribute it and/or
- *              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.
- *
- * Changes:
- *     Wensong Zhang            :     changed the ip_vs_wlc_schedule to return dest
- *     Wensong Zhang            :     changed to use the inactconns in scheduling
- *     Wensong Zhang            :     changed some comestics things for debugging
- *     Wensong Zhang            :     changed for the d-linked destination list
- *     Wensong Zhang            :     added the ip_vs_wlc_update_svc
- *     Wensong Zhang            :     added any dest with weight=0 is quiesced
- *
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-
-#include <net/ip_vs.h>
-
-
-static int
-ip_vs_wlc_init_svc(struct ip_vs_service *svc)
-{
-	return 0;
-}
-
-
-static int
-ip_vs_wlc_done_svc(struct ip_vs_service *svc)
-{
-	return 0;
-}
-
-
-static int
-ip_vs_wlc_update_svc(struct ip_vs_service *svc)
-{
-	return 0;
-}
-
-
-static inline unsigned int
-ip_vs_wlc_dest_overhead(struct ip_vs_dest *dest)
-{
-	/*
-	 * We think the overhead of processing active connections is 256
-	 * times higher than that of inactive connections in average. (This
-	 * 256 times might not be accurate, we will change it later) We
-	 * use the following formula to estimate the overhead now:
-	 *		  dest->activeconns*256 + dest->inactconns
-	 */
-	return (atomic_read(&dest->activeconns) << 8) +
-		atomic_read(&dest->inactconns);
-}
-
-
-/*
- *	Weighted Least Connection scheduling
- */
-static struct ip_vs_dest *
-ip_vs_wlc_schedule(struct ip_vs_service *svc, const struct sk_buff *skb)
-{
-	struct ip_vs_dest *dest, *least;
-	unsigned int loh, doh;
-
-	IP_VS_DBG(6, "ip_vs_wlc_schedule(): Scheduling...\n");
-
-	/*
-	 * We calculate the load of each dest server as follows:
-	 *		  (dest overhead) / dest->weight
-	 *
-	 * Remember -- no floats in kernel mode!!!
-	 * The comparison of h1*w2 > h2*w1 is equivalent to that of
-	 *		  h1/w1 > h2/w2
-	 * if every weight is larger than zero.
-	 *
-	 * The server with weight=0 is quiesced and will not receive any
-	 * new connections.
-	 */
-
-	list_for_each_entry(dest, &svc->destinations, n_list) {
-		if (!(dest->flags & IP_VS_DEST_F_OVERLOAD) &&
-		    atomic_read(&dest->weight) > 0) {
-			least = dest;
-			loh = ip_vs_wlc_dest_overhead(least);
-			goto nextstage;
-		}
-	}
-	return NULL;
-
-	/*
-	 *    Find the destination with the least load.
-	 */
-  nextstage:
-	list_for_each_entry_continue(dest, &svc->destinations, n_list) {
-		if (dest->flags & IP_VS_DEST_F_OVERLOAD)
-			continue;
-		doh = ip_vs_wlc_dest_overhead(dest);
-		if (loh * atomic_read(&dest->weight) >
-		    doh * atomic_read(&least->weight)) {
-			least = dest;
-			loh = doh;
-		}
-	}
-
-	IP_VS_DBG(6, "WLC: server %u.%u.%u.%u:%u "
-		  "activeconns %d refcnt %d weight %d overhead %d\n",
-		  NIPQUAD(least->addr), ntohs(least->port),
-		  atomic_read(&least->activeconns),
-		  atomic_read(&least->refcnt),
-		  atomic_read(&least->weight), loh);
-
-	return least;
-}
-
-
-static struct ip_vs_scheduler ip_vs_wlc_scheduler =
-{
-	.name =			"wlc",
-	.refcnt =		ATOMIC_INIT(0),
-	.module =		THIS_MODULE,
-	.n_list =		LIST_HEAD_INIT(ip_vs_wlc_scheduler.n_list),
-	.init_service =		ip_vs_wlc_init_svc,
-	.done_service =		ip_vs_wlc_done_svc,
-	.update_service =	ip_vs_wlc_update_svc,
-	.schedule =		ip_vs_wlc_schedule,
-};
-
-
-static int __init ip_vs_wlc_init(void)
-{
-	return register_ip_vs_scheduler(&ip_vs_wlc_scheduler);
-}
-
-static void __exit ip_vs_wlc_cleanup(void)
-{
-	unregister_ip_vs_scheduler(&ip_vs_wlc_scheduler);
-}
-
-module_init(ip_vs_wlc_init);
-module_exit(ip_vs_wlc_cleanup);
-MODULE_LICENSE("GPL");
diff --git a/net/ipv4/ipvs/ip_vs_wrr.c b/net/ipv4/ipvs/ip_vs_wrr.c
deleted file mode 100644
index 0d86a79..0000000
--- a/net/ipv4/ipvs/ip_vs_wrr.c
+++ /dev/null
@@ -1,234 +0,0 @@
-/*
- * IPVS:        Weighted Round-Robin Scheduling module
- *
- * Authors:     Wensong Zhang <wensong@linuxvirtualserver.org>
- *
- *              This program is free software; you can redistribute it and/or
- *              modify it under the terms of the GNU General Public License
- *              as published by the Free Software Foundation; either version
- *              2 of the License, or (at your option) any later version.
- *
- * Changes:
- *     Wensong Zhang            :     changed the ip_vs_wrr_schedule to return dest
- *     Wensong Zhang            :     changed some comestics things for debugging
- *     Wensong Zhang            :     changed for the d-linked destination list
- *     Wensong Zhang            :     added the ip_vs_wrr_update_svc
- *     Julian Anastasov         :     fixed the bug of returning destination
- *                                    with weight 0 when all weights are zero
- *
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/net.h>
-
-#include <net/ip_vs.h>
-
-/*
- * current destination pointer for weighted round-robin scheduling
- */
-struct ip_vs_wrr_mark {
-	struct list_head *cl;	/* current list head */
-	int cw;			/* current weight */
-	int mw;			/* maximum weight */
-	int di;			/* decreasing interval */
-};
-
-
-/*
- *    Get the gcd of server weights
- */
-static int gcd(int a, int b)
-{
-	int c;
-
-	while ((c = a % b)) {
-		a = b;
-		b = c;
-	}
-	return b;
-}
-
-static int ip_vs_wrr_gcd_weight(struct ip_vs_service *svc)
-{
-	struct ip_vs_dest *dest;
-	int weight;
-	int g = 0;
-
-	list_for_each_entry(dest, &svc->destinations, n_list) {
-		weight = atomic_read(&dest->weight);
-		if (weight > 0) {
-			if (g > 0)
-				g = gcd(weight, g);
-			else
-				g = weight;
-		}
-	}
-	return g ? g : 1;
-}
-
-
-/*
- *    Get the maximum weight of the service destinations.
- */
-static int ip_vs_wrr_max_weight(struct ip_vs_service *svc)
-{
-	struct ip_vs_dest *dest;
-	int weight = 0;
-
-	list_for_each_entry(dest, &svc->destinations, n_list) {
-		if (atomic_read(&dest->weight) > weight)
-			weight = atomic_read(&dest->weight);
-	}
-
-	return weight;
-}
-
-
-static int ip_vs_wrr_init_svc(struct ip_vs_service *svc)
-{
-	struct ip_vs_wrr_mark *mark;
-
-	/*
-	 *    Allocate the mark variable for WRR scheduling
-	 */
-	mark = kmalloc(sizeof(struct ip_vs_wrr_mark), GFP_ATOMIC);
-	if (mark == NULL) {
-		IP_VS_ERR("ip_vs_wrr_init_svc(): no memory\n");
-		return -ENOMEM;
-	}
-	mark->cl = &svc->destinations;
-	mark->cw = 0;
-	mark->mw = ip_vs_wrr_max_weight(svc);
-	mark->di = ip_vs_wrr_gcd_weight(svc);
-	svc->sched_data = mark;
-
-	return 0;
-}
-
-
-static int ip_vs_wrr_done_svc(struct ip_vs_service *svc)
-{
-	/*
-	 *    Release the mark variable
-	 */
-	kfree(svc->sched_data);
-
-	return 0;
-}
-
-
-static int ip_vs_wrr_update_svc(struct ip_vs_service *svc)
-{
-	struct ip_vs_wrr_mark *mark = svc->sched_data;
-
-	mark->cl = &svc->destinations;
-	mark->mw = ip_vs_wrr_max_weight(svc);
-	mark->di = ip_vs_wrr_gcd_weight(svc);
-	if (mark->cw > mark->mw)
-		mark->cw = 0;
-	return 0;
-}
-
-
-/*
- *    Weighted Round-Robin Scheduling
- */
-static struct ip_vs_dest *
-ip_vs_wrr_schedule(struct ip_vs_service *svc, const struct sk_buff *skb)
-{
-	struct ip_vs_dest *dest;
-	struct ip_vs_wrr_mark *mark = svc->sched_data;
-	struct list_head *p;
-
-	IP_VS_DBG(6, "ip_vs_wrr_schedule(): Scheduling...\n");
-
-	/*
-	 * This loop will always terminate, because mark->cw in (0, max_weight]
-	 * and at least one server has its weight equal to max_weight.
-	 */
-	write_lock(&svc->sched_lock);
-	p = mark->cl;
-	while (1) {
-		if (mark->cl == &svc->destinations) {
-			/* it is at the head of the destination list */
-
-			if (mark->cl == mark->cl->next) {
-				/* no dest entry */
-				dest = NULL;
-				goto out;
-			}
-
-			mark->cl = svc->destinations.next;
-			mark->cw -= mark->di;
-			if (mark->cw <= 0) {
-				mark->cw = mark->mw;
-				/*
-				 * Still zero, which means no available servers.
-				 */
-				if (mark->cw == 0) {
-					mark->cl = &svc->destinations;
-					IP_VS_ERR_RL("ip_vs_wrr_schedule(): "
-						   "no available servers\n");
-					dest = NULL;
-					goto out;
-				}
-			}
-		} else
-			mark->cl = mark->cl->next;
-
-		if (mark->cl != &svc->destinations) {
-			/* not at the head of the list */
-			dest = list_entry(mark->cl, struct ip_vs_dest, n_list);
-			if (!(dest->flags & IP_VS_DEST_F_OVERLOAD) &&
-			    atomic_read(&dest->weight) >= mark->cw) {
-				/* got it */
-				break;
-			}
-		}
-
-		if (mark->cl == p && mark->cw == mark->di) {
-			/* back to the start, and no dest is found.
-			   It is only possible when all dests are OVERLOADED */
-			dest = NULL;
-			goto out;
-		}
-	}
-
-	IP_VS_DBG(6, "WRR: server %u.%u.%u.%u:%u "
-		  "activeconns %d refcnt %d weight %d\n",
-		  NIPQUAD(dest->addr), ntohs(dest->port),
-		  atomic_read(&dest->activeconns),
-		  atomic_read(&dest->refcnt),
-		  atomic_read(&dest->weight));
-
-  out:
-	write_unlock(&svc->sched_lock);
-	return dest;
-}
-
-
-static struct ip_vs_scheduler ip_vs_wrr_scheduler = {
-	.name =			"wrr",
-	.refcnt =		ATOMIC_INIT(0),
-	.module =		THIS_MODULE,
-	.n_list =		LIST_HEAD_INIT(ip_vs_wrr_scheduler.n_list),
-	.init_service =		ip_vs_wrr_init_svc,
-	.done_service =		ip_vs_wrr_done_svc,
-	.update_service =	ip_vs_wrr_update_svc,
-	.schedule =		ip_vs_wrr_schedule,
-};
-
-static int __init ip_vs_wrr_init(void)
-{
-	return register_ip_vs_scheduler(&ip_vs_wrr_scheduler) ;
-}
-
-static void __exit ip_vs_wrr_cleanup(void)
-{
-	unregister_ip_vs_scheduler(&ip_vs_wrr_scheduler);
-}
-
-module_init(ip_vs_wrr_init);
-module_exit(ip_vs_wrr_cleanup);
-MODULE_LICENSE("GPL");
diff --git a/net/ipv4/ipvs/ip_vs_xmit.c b/net/ipv4/ipvs/ip_vs_xmit.c
deleted file mode 100644
index 9892d4a..0000000
--- a/net/ipv4/ipvs/ip_vs_xmit.c
+++ /dev/null
@@ -1,559 +0,0 @@
-/*
- * ip_vs_xmit.c: various packet transmitters for IPVS
- *
- * Authors:     Wensong Zhang <wensong@linuxvirtualserver.org>
- *              Julian Anastasov <ja@ssi.bg>
- *
- *              This program is free software; you can redistribute it and/or
- *              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.
- *
- * Changes:
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/tcp.h>                  /* for tcphdr */
-#include <net/ip.h>
-#include <net/tcp.h>                    /* for csum_tcpudp_magic */
-#include <net/udp.h>
-#include <net/icmp.h>                   /* for icmp_send */
-#include <net/route.h>                  /* for ip_route_output */
-#include <linux/netfilter.h>
-#include <linux/netfilter_ipv4.h>
-
-#include <net/ip_vs.h>
-
-
-/*
- *      Destination cache to speed up outgoing route lookup
- */
-static inline void
-__ip_vs_dst_set(struct ip_vs_dest *dest, u32 rtos, struct dst_entry *dst)
-{
-	struct dst_entry *old_dst;
-
-	old_dst = dest->dst_cache;
-	dest->dst_cache = dst;
-	dest->dst_rtos = rtos;
-	dst_release(old_dst);
-}
-
-static inline struct dst_entry *
-__ip_vs_dst_check(struct ip_vs_dest *dest, u32 rtos, u32 cookie)
-{
-	struct dst_entry *dst = dest->dst_cache;
-
-	if (!dst)
-		return NULL;
-	if ((dst->obsolete || rtos != dest->dst_rtos) &&
-	    dst->ops->check(dst, cookie) == NULL) {
-		dest->dst_cache = NULL;
-		dst_release(dst);
-		return NULL;
-	}
-	dst_hold(dst);
-	return dst;
-}
-
-static struct rtable *
-__ip_vs_get_out_rt(struct ip_vs_conn *cp, u32 rtos)
-{
-	struct rtable *rt;			/* Route to the other host */
-	struct ip_vs_dest *dest = cp->dest;
-
-	if (dest) {
-		spin_lock(&dest->dst_lock);
-		if (!(rt = (struct rtable *)
-		      __ip_vs_dst_check(dest, rtos, 0))) {
-			struct flowi fl = {
-				.oif = 0,
-				.nl_u = {
-					.ip4_u = {
-						.daddr = dest->addr,
-						.saddr = 0,
-						.tos = rtos, } },
-			};
-
-			if (ip_route_output_key(&init_net, &rt, &fl)) {
-				spin_unlock(&dest->dst_lock);
-				IP_VS_DBG_RL("ip_route_output error, "
-					     "dest: %u.%u.%u.%u\n",
-					     NIPQUAD(dest->addr));
-				return NULL;
-			}
-			__ip_vs_dst_set(dest, rtos, dst_clone(&rt->u.dst));
-			IP_VS_DBG(10, "new dst %u.%u.%u.%u, refcnt=%d, rtos=%X\n",
-				  NIPQUAD(dest->addr),
-				  atomic_read(&rt->u.dst.__refcnt), rtos);
-		}
-		spin_unlock(&dest->dst_lock);
-	} else {
-		struct flowi fl = {
-			.oif = 0,
-			.nl_u = {
-				.ip4_u = {
-					.daddr = cp->daddr,
-					.saddr = 0,
-					.tos = rtos, } },
-		};
-
-		if (ip_route_output_key(&init_net, &rt, &fl)) {
-			IP_VS_DBG_RL("ip_route_output error, dest: "
-				     "%u.%u.%u.%u\n", NIPQUAD(cp->daddr));
-			return NULL;
-		}
-	}
-
-	return rt;
-}
-
-
-/*
- *	Release dest->dst_cache before a dest is removed
- */
-void
-ip_vs_dst_reset(struct ip_vs_dest *dest)
-{
-	struct dst_entry *old_dst;
-
-	old_dst = dest->dst_cache;
-	dest->dst_cache = NULL;
-	dst_release(old_dst);
-}
-
-#define IP_VS_XMIT(skb, rt)				\
-do {							\
-	(skb)->ipvs_property = 1;			\
-	skb_forward_csum(skb);				\
-	NF_HOOK(PF_INET, NF_INET_LOCAL_OUT, (skb), NULL,	\
-		(rt)->u.dst.dev, dst_output);		\
-} while (0)
-
-
-/*
- *      NULL transmitter (do nothing except return NF_ACCEPT)
- */
-int
-ip_vs_null_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
-		struct ip_vs_protocol *pp)
-{
-	/* we do not touch skb and do not need pskb ptr */
-	return NF_ACCEPT;
-}
-
-
-/*
- *      Bypass transmitter
- *      Let packets bypass the destination when the destination is not
- *      available, it may be only used in transparent cache cluster.
- */
-int
-ip_vs_bypass_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
-		  struct ip_vs_protocol *pp)
-{
-	struct rtable *rt;			/* Route to the other host */
-	struct iphdr  *iph = ip_hdr(skb);
-	u8     tos = iph->tos;
-	int    mtu;
-	struct flowi fl = {
-		.oif = 0,
-		.nl_u = {
-			.ip4_u = {
-				.daddr = iph->daddr,
-				.saddr = 0,
-				.tos = RT_TOS(tos), } },
-	};
-
-	EnterFunction(10);
-
-	if (ip_route_output_key(&init_net, &rt, &fl)) {
-		IP_VS_DBG_RL("ip_vs_bypass_xmit(): ip_route_output error, "
-			     "dest: %u.%u.%u.%u\n", NIPQUAD(iph->daddr));
-		goto tx_error_icmp;
-	}
-
-	/* MTU checking */
-	mtu = dst_mtu(&rt->u.dst);
-	if ((skb->len > mtu) && (iph->frag_off & htons(IP_DF))) {
-		ip_rt_put(rt);
-		icmp_send(skb, ICMP_DEST_UNREACH,ICMP_FRAG_NEEDED, htonl(mtu));
-		IP_VS_DBG_RL("ip_vs_bypass_xmit(): frag needed\n");
-		goto tx_error;
-	}
-
-	/*
-	 * Call ip_send_check because we are not sure it is called
-	 * after ip_defrag. Is copy-on-write needed?
-	 */
-	if (unlikely((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL)) {
-		ip_rt_put(rt);
-		return NF_STOLEN;
-	}
-	ip_send_check(ip_hdr(skb));
-
-	/* drop old route */
-	dst_release(skb->dst);
-	skb->dst = &rt->u.dst;
-
-	/* Another hack: avoid icmp_send in ip_fragment */
-	skb->local_df = 1;
-
-	IP_VS_XMIT(skb, rt);
-
-	LeaveFunction(10);
-	return NF_STOLEN;
-
- tx_error_icmp:
-	dst_link_failure(skb);
- tx_error:
-	kfree_skb(skb);
-	LeaveFunction(10);
-	return NF_STOLEN;
-}
-
-
-/*
- *      NAT transmitter (only for outside-to-inside nat forwarding)
- *      Not used for related ICMP
- */
-int
-ip_vs_nat_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
-	       struct ip_vs_protocol *pp)
-{
-	struct rtable *rt;		/* Route to the other host */
-	int mtu;
-	struct iphdr *iph = ip_hdr(skb);
-
-	EnterFunction(10);
-
-	/* check if it is a connection of no-client-port */
-	if (unlikely(cp->flags & IP_VS_CONN_F_NO_CPORT)) {
-		__be16 _pt, *p;
-		p = skb_header_pointer(skb, iph->ihl*4, sizeof(_pt), &_pt);
-		if (p == NULL)
-			goto tx_error;
-		ip_vs_conn_fill_cport(cp, *p);
-		IP_VS_DBG(10, "filled cport=%d\n", ntohs(*p));
-	}
-
-	if (!(rt = __ip_vs_get_out_rt(cp, RT_TOS(iph->tos))))
-		goto tx_error_icmp;
-
-	/* MTU checking */
-	mtu = dst_mtu(&rt->u.dst);
-	if ((skb->len > mtu) && (iph->frag_off & htons(IP_DF))) {
-		ip_rt_put(rt);
-		icmp_send(skb, ICMP_DEST_UNREACH,ICMP_FRAG_NEEDED, htonl(mtu));
-		IP_VS_DBG_RL_PKT(0, pp, skb, 0, "ip_vs_nat_xmit(): frag needed for");
-		goto tx_error;
-	}
-
-	/* copy-on-write the packet before mangling it */
-	if (!skb_make_writable(skb, sizeof(struct iphdr)))
-		goto tx_error_put;
-
-	if (skb_cow(skb, rt->u.dst.dev->hard_header_len))
-		goto tx_error_put;
-
-	/* drop old route */
-	dst_release(skb->dst);
-	skb->dst = &rt->u.dst;
-
-	/* mangle the packet */
-	if (pp->dnat_handler && !pp->dnat_handler(skb, pp, cp))
-		goto tx_error;
-	ip_hdr(skb)->daddr = cp->daddr;
-	ip_send_check(ip_hdr(skb));
-
-	IP_VS_DBG_PKT(10, pp, skb, 0, "After DNAT");
-
-	/* FIXME: when application helper enlarges the packet and the length
-	   is larger than the MTU of outgoing device, there will be still
-	   MTU problem. */
-
-	/* Another hack: avoid icmp_send in ip_fragment */
-	skb->local_df = 1;
-
-	IP_VS_XMIT(skb, rt);
-
-	LeaveFunction(10);
-	return NF_STOLEN;
-
-  tx_error_icmp:
-	dst_link_failure(skb);
-  tx_error:
-	LeaveFunction(10);
-	kfree_skb(skb);
-	return NF_STOLEN;
-  tx_error_put:
-	ip_rt_put(rt);
-	goto tx_error;
-}
-
-
-/*
- *   IP Tunneling transmitter
- *
- *   This function encapsulates the packet in a new IP packet, its
- *   destination will be set to cp->daddr. Most code of this function
- *   is taken from ipip.c.
- *
- *   It is used in VS/TUN cluster. The load balancer selects a real
- *   server from a cluster based on a scheduling algorithm,
- *   encapsulates the request packet and forwards it to the selected
- *   server. For example, all real servers are configured with
- *   "ifconfig tunl0 <Virtual IP Address> up". When the server receives
- *   the encapsulated packet, it will decapsulate the packet, processe
- *   the request and return the response packets directly to the client
- *   without passing the load balancer. This can greatly increase the
- *   scalability of virtual server.
- *
- *   Used for ANY protocol
- */
-int
-ip_vs_tunnel_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
-		  struct ip_vs_protocol *pp)
-{
-	struct rtable *rt;			/* Route to the other host */
-	struct net_device *tdev;		/* Device to other host */
-	struct iphdr  *old_iph = ip_hdr(skb);
-	u8     tos = old_iph->tos;
-	__be16 df = old_iph->frag_off;
-	sk_buff_data_t old_transport_header = skb->transport_header;
-	struct iphdr  *iph;			/* Our new IP header */
-	unsigned int max_headroom;		/* The extra header space needed */
-	int    mtu;
-
-	EnterFunction(10);
-
-	if (skb->protocol != htons(ETH_P_IP)) {
-		IP_VS_DBG_RL("ip_vs_tunnel_xmit(): protocol error, "
-			     "ETH_P_IP: %d, skb protocol: %d\n",
-			     htons(ETH_P_IP), skb->protocol);
-		goto tx_error;
-	}
-
-	if (!(rt = __ip_vs_get_out_rt(cp, RT_TOS(tos))))
-		goto tx_error_icmp;
-
-	tdev = rt->u.dst.dev;
-
-	mtu = dst_mtu(&rt->u.dst) - sizeof(struct iphdr);
-	if (mtu < 68) {
-		ip_rt_put(rt);
-		IP_VS_DBG_RL("ip_vs_tunnel_xmit(): mtu less than 68\n");
-		goto tx_error;
-	}
-	if (skb->dst)
-		skb->dst->ops->update_pmtu(skb->dst, mtu);
-
-	df |= (old_iph->frag_off & htons(IP_DF));
-
-	if ((old_iph->frag_off & htons(IP_DF))
-	    && mtu < ntohs(old_iph->tot_len)) {
-		icmp_send(skb, ICMP_DEST_UNREACH,ICMP_FRAG_NEEDED, htonl(mtu));
-		ip_rt_put(rt);
-		IP_VS_DBG_RL("ip_vs_tunnel_xmit(): frag needed\n");
-		goto tx_error;
-	}
-
-	/*
-	 * Okay, now see if we can stuff it in the buffer as-is.
-	 */
-	max_headroom = LL_RESERVED_SPACE(tdev) + sizeof(struct iphdr);
-
-	if (skb_headroom(skb) < max_headroom
-	    || skb_cloned(skb) || skb_shared(skb)) {
-		struct sk_buff *new_skb =
-			skb_realloc_headroom(skb, max_headroom);
-		if (!new_skb) {
-			ip_rt_put(rt);
-			kfree_skb(skb);
-			IP_VS_ERR_RL("ip_vs_tunnel_xmit(): no memory\n");
-			return NF_STOLEN;
-		}
-		kfree_skb(skb);
-		skb = new_skb;
-		old_iph = ip_hdr(skb);
-	}
-
-	skb->transport_header = old_transport_header;
-
-	/* fix old IP header checksum */
-	ip_send_check(old_iph);
-
-	skb_push(skb, sizeof(struct iphdr));
-	skb_reset_network_header(skb);
-	memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
-
-	/* drop old route */
-	dst_release(skb->dst);
-	skb->dst = &rt->u.dst;
-
-	/*
-	 *	Push down and install the IPIP header.
-	 */
-	iph			=	ip_hdr(skb);
-	iph->version		=	4;
-	iph->ihl		=	sizeof(struct iphdr)>>2;
-	iph->frag_off		=	df;
-	iph->protocol		=	IPPROTO_IPIP;
-	iph->tos		=	tos;
-	iph->daddr		=	rt->rt_dst;
-	iph->saddr		=	rt->rt_src;
-	iph->ttl		=	old_iph->ttl;
-	ip_select_ident(iph, &rt->u.dst, NULL);
-
-	/* Another hack: avoid icmp_send in ip_fragment */
-	skb->local_df = 1;
-
-	ip_local_out(skb);
-
-	LeaveFunction(10);
-
-	return NF_STOLEN;
-
-  tx_error_icmp:
-	dst_link_failure(skb);
-  tx_error:
-	kfree_skb(skb);
-	LeaveFunction(10);
-	return NF_STOLEN;
-}
-
-
-/*
- *      Direct Routing transmitter
- *      Used for ANY protocol
- */
-int
-ip_vs_dr_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
-	      struct ip_vs_protocol *pp)
-{
-	struct rtable *rt;			/* Route to the other host */
-	struct iphdr  *iph = ip_hdr(skb);
-	int    mtu;
-
-	EnterFunction(10);
-
-	if (!(rt = __ip_vs_get_out_rt(cp, RT_TOS(iph->tos))))
-		goto tx_error_icmp;
-
-	/* MTU checking */
-	mtu = dst_mtu(&rt->u.dst);
-	if ((iph->frag_off & htons(IP_DF)) && skb->len > mtu) {
-		icmp_send(skb, ICMP_DEST_UNREACH,ICMP_FRAG_NEEDED, htonl(mtu));
-		ip_rt_put(rt);
-		IP_VS_DBG_RL("ip_vs_dr_xmit(): frag needed\n");
-		goto tx_error;
-	}
-
-	/*
-	 * Call ip_send_check because we are not sure it is called
-	 * after ip_defrag. Is copy-on-write needed?
-	 */
-	if (unlikely((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL)) {
-		ip_rt_put(rt);
-		return NF_STOLEN;
-	}
-	ip_send_check(ip_hdr(skb));
-
-	/* drop old route */
-	dst_release(skb->dst);
-	skb->dst = &rt->u.dst;
-
-	/* Another hack: avoid icmp_send in ip_fragment */
-	skb->local_df = 1;
-
-	IP_VS_XMIT(skb, rt);
-
-	LeaveFunction(10);
-	return NF_STOLEN;
-
-  tx_error_icmp:
-	dst_link_failure(skb);
-  tx_error:
-	kfree_skb(skb);
-	LeaveFunction(10);
-	return NF_STOLEN;
-}
-
-
-/*
- *	ICMP packet transmitter
- *	called by the ip_vs_in_icmp
- */
-int
-ip_vs_icmp_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
-		struct ip_vs_protocol *pp, int offset)
-{
-	struct rtable	*rt;	/* Route to the other host */
-	int mtu;
-	int rc;
-
-	EnterFunction(10);
-
-	/* The ICMP packet for VS/TUN, VS/DR and LOCALNODE will be
-	   forwarded directly here, because there is no need to
-	   translate address/port back */
-	if (IP_VS_FWD_METHOD(cp) != IP_VS_CONN_F_MASQ) {
-		if (cp->packet_xmit)
-			rc = cp->packet_xmit(skb, cp, pp);
-		else
-			rc = NF_ACCEPT;
-		/* do not touch skb anymore */
-		atomic_inc(&cp->in_pkts);
-		goto out;
-	}
-
-	/*
-	 * mangle and send the packet here (only for VS/NAT)
-	 */
-
-	if (!(rt = __ip_vs_get_out_rt(cp, RT_TOS(ip_hdr(skb)->tos))))
-		goto tx_error_icmp;
-
-	/* MTU checking */
-	mtu = dst_mtu(&rt->u.dst);
-	if ((skb->len > mtu) && (ip_hdr(skb)->frag_off & htons(IP_DF))) {
-		ip_rt_put(rt);
-		icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, htonl(mtu));
-		IP_VS_DBG_RL("ip_vs_in_icmp(): frag needed\n");
-		goto tx_error;
-	}
-
-	/* copy-on-write the packet before mangling it */
-	if (!skb_make_writable(skb, offset))
-		goto tx_error_put;
-
-	if (skb_cow(skb, rt->u.dst.dev->hard_header_len))
-		goto tx_error_put;
-
-	/* drop the old route when skb is not shared */
-	dst_release(skb->dst);
-	skb->dst = &rt->u.dst;
-
-	ip_vs_nat_icmp(skb, pp, cp, 0);
-
-	/* Another hack: avoid icmp_send in ip_fragment */
-	skb->local_df = 1;
-
-	IP_VS_XMIT(skb, rt);
-
-	rc = NF_STOLEN;
-	goto out;
-
-  tx_error_icmp:
-	dst_link_failure(skb);
-  tx_error:
-	dev_kfree_skb(skb);
-	rc = NF_STOLEN;
-  out:
-	LeaveFunction(10);
-	return rc;
-  tx_error_put:
-	ip_rt_put(rt);
-	goto tx_error;
-}
diff --git a/net/ipv4/netfilter.c b/net/ipv4/netfilter.c
index f8edacd..6efdb70 100644
--- a/net/ipv4/netfilter.c
+++ b/net/ipv4/netfilter.c
@@ -12,6 +12,7 @@
 /* route_me_harder function, used by iptable_nat, iptable_mangle + ip_queue */
 int ip_route_me_harder(struct sk_buff *skb, unsigned addr_type)
 {
+	struct net *net = dev_net(skb->dst->dev);
 	const struct iphdr *iph = ip_hdr(skb);
 	struct rtable *rt;
 	struct flowi fl = {};
@@ -19,7 +20,9 @@
 	unsigned int hh_len;
 	unsigned int type;
 
-	type = inet_addr_type(&init_net, iph->saddr);
+	type = inet_addr_type(net, iph->saddr);
+	if (skb->sk && inet_sk(skb->sk)->transparent)
+		type = RTN_LOCAL;
 	if (addr_type == RTN_UNSPEC)
 		addr_type = type;
 
@@ -33,7 +36,8 @@
 		fl.nl_u.ip4_u.tos = RT_TOS(iph->tos);
 		fl.oif = skb->sk ? skb->sk->sk_bound_dev_if : 0;
 		fl.mark = skb->mark;
-		if (ip_route_output_key(&init_net, &rt, &fl) != 0)
+		fl.flags = skb->sk ? inet_sk_flowi_flags(skb->sk) : 0;
+		if (ip_route_output_key(net, &rt, &fl) != 0)
 			return -1;
 
 		/* Drop old route. */
@@ -43,7 +47,7 @@
 		/* non-local src, find valid iif to satisfy
 		 * rp-filter when calling ip_route_input. */
 		fl.nl_u.ip4_u.daddr = iph->saddr;
-		if (ip_route_output_key(&init_net, &rt, &fl) != 0)
+		if (ip_route_output_key(net, &rt, &fl) != 0)
 			return -1;
 
 		odst = skb->dst;
diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig
index 90eb7cb..3816e1d 100644
--- a/net/ipv4/netfilter/Kconfig
+++ b/net/ipv4/netfilter/Kconfig
@@ -5,10 +5,15 @@
 menu "IP: Netfilter Configuration"
 	depends on INET && NETFILTER
 
+config NF_DEFRAG_IPV4
+	tristate
+	default n
+
 config NF_CONNTRACK_IPV4
 	tristate "IPv4 connection tracking support (required for NAT)"
 	depends on NF_CONNTRACK
 	default m if NETFILTER_ADVANCED=n
+	select NF_DEFRAG_IPV4
 	---help---
 	  Connection tracking keeps a record of what packets have passed
 	  through your machine, in order to figure out how they are related
@@ -56,53 +61,11 @@
 
 	  To compile it as a module, choose M here.  If unsure, say N.
 
+if IP_NF_IPTABLES
+
 # The matches.
-config IP_NF_MATCH_RECENT
-	tristate '"recent" match support'
-	depends on IP_NF_IPTABLES
-	depends on NETFILTER_ADVANCED
-	help
-	  This match is used for creating one or many lists of recently
-	  used addresses and then matching against that/those list(s).
-
-	  Short options are available by using 'iptables -m recent -h'
-	  Official Website: <http://snowman.net/projects/ipt_recent/>
-
-	  To compile it as a module, choose M here.  If unsure, say N.
-
-config IP_NF_MATCH_ECN
-	tristate '"ecn" match support'
-	depends on IP_NF_IPTABLES
-	depends on NETFILTER_ADVANCED
-	help
-	  This option adds a `ECN' match, which allows you to match against
-	  the IPv4 and TCP header ECN fields.
-
-	  To compile it as a module, choose M here.  If unsure, say N.
-
-config IP_NF_MATCH_AH
-	tristate '"ah" match support'
-	depends on IP_NF_IPTABLES
-	depends on NETFILTER_ADVANCED
-	help
-	  This match extension allows you to match a range of SPIs
-	  inside AH header of IPSec packets.
-
-	  To compile it as a module, choose M here.  If unsure, say N.
-
-config IP_NF_MATCH_TTL
-	tristate '"ttl" match support'
-	depends on IP_NF_IPTABLES
-	depends on NETFILTER_ADVANCED
-	help
-	  This adds CONFIG_IP_NF_MATCH_TTL option, which enabled the user
-	  to match packets by their TTL value.
-
-	  To compile it as a module, choose M here.  If unsure, say N.
-
 config IP_NF_MATCH_ADDRTYPE
 	tristate '"addrtype" address type match support'
-	depends on IP_NF_IPTABLES
 	depends on NETFILTER_ADVANCED
 	help
 	  This option allows you to match what routing thinks of an address,
@@ -111,10 +74,36 @@
 	  If you want to compile it as a module, say M here and read
 	  <file:Documentation/kbuild/modules.txt>.  If unsure, say `N'.
 
+config IP_NF_MATCH_AH
+	tristate '"ah" match support'
+	depends on NETFILTER_ADVANCED
+	help
+	  This match extension allows you to match a range of SPIs
+	  inside AH header of IPSec packets.
+
+	  To compile it as a module, choose M here.  If unsure, say N.
+
+config IP_NF_MATCH_ECN
+	tristate '"ecn" match support'
+	depends on NETFILTER_ADVANCED
+	help
+	  This option adds a `ECN' match, which allows you to match against
+	  the IPv4 and TCP header ECN fields.
+
+	  To compile it as a module, choose M here.  If unsure, say N.
+
+config IP_NF_MATCH_TTL
+	tristate '"ttl" match support'
+	depends on NETFILTER_ADVANCED
+	help
+	  This adds CONFIG_IP_NF_MATCH_TTL option, which enabled the user
+	  to match packets by their TTL value.
+
+	  To compile it as a module, choose M here.  If unsure, say N.
+
 # `filter', generic and specific targets
 config IP_NF_FILTER
 	tristate "Packet filtering"
-	depends on IP_NF_IPTABLES
 	default m if NETFILTER_ADVANCED=n
 	help
 	  Packet filtering defines a table `filter', which has a series of
@@ -136,7 +125,6 @@
 
 config IP_NF_TARGET_LOG
 	tristate "LOG target support"
-	depends on IP_NF_IPTABLES
 	default m if NETFILTER_ADVANCED=n
 	help
 	  This option adds a `LOG' target, which allows you to create rules in
@@ -146,7 +134,6 @@
 
 config IP_NF_TARGET_ULOG
 	tristate "ULOG target support"
-	depends on IP_NF_IPTABLES
 	default m if NETFILTER_ADVANCED=n
 	---help---
 
@@ -167,7 +154,7 @@
 # NAT + specific targets: nf_conntrack
 config NF_NAT
 	tristate "Full NAT"
-	depends on IP_NF_IPTABLES && NF_CONNTRACK_IPV4
+	depends on NF_CONNTRACK_IPV4
 	default m if NETFILTER_ADVANCED=n
 	help
 	  The Full NAT option allows masquerading, port forwarding and other
@@ -194,6 +181,17 @@
 
 	  To compile it as a module, choose M here.  If unsure, say N.
 
+config IP_NF_TARGET_NETMAP
+	tristate "NETMAP target support"
+	depends on NF_NAT
+	depends on NETFILTER_ADVANCED
+	help
+	  NETMAP is an implementation of static 1:1 NAT mapping of network
+	  addresses. It maps the network address part, while keeping the host
+	  address part intact.
+
+	  To compile it as a module, choose M here.  If unsure, say N.
+
 config IP_NF_TARGET_REDIRECT
 	tristate "REDIRECT target support"
 	depends on NF_NAT
@@ -206,17 +204,6 @@
 
 	  To compile it as a module, choose M here.  If unsure, say N.
 
-config IP_NF_TARGET_NETMAP
-	tristate "NETMAP target support"
-	depends on NF_NAT
-	depends on NETFILTER_ADVANCED
-	help
-	  NETMAP is an implementation of static 1:1 NAT mapping of network
-	  addresses. It maps the network address part, while keeping the host
-	  address part intact.
-
-	  To compile it as a module, choose M here.  If unsure, say N.
-
 config NF_NAT_SNMP_BASIC
 	tristate "Basic SNMP-ALG support"
 	depends on NF_NAT
@@ -262,44 +249,43 @@
 
 config NF_NAT_FTP
 	tristate
-	depends on IP_NF_IPTABLES && NF_CONNTRACK && NF_NAT
+	depends on NF_CONNTRACK && NF_NAT
 	default NF_NAT && NF_CONNTRACK_FTP
 
 config NF_NAT_IRC
 	tristate
-	depends on IP_NF_IPTABLES && NF_CONNTRACK && NF_NAT
+	depends on NF_CONNTRACK && NF_NAT
 	default NF_NAT && NF_CONNTRACK_IRC
 
 config NF_NAT_TFTP
 	tristate
-	depends on IP_NF_IPTABLES && NF_CONNTRACK && NF_NAT
+	depends on NF_CONNTRACK && NF_NAT
 	default NF_NAT && NF_CONNTRACK_TFTP
 
 config NF_NAT_AMANDA
 	tristate
-	depends on IP_NF_IPTABLES && NF_CONNTRACK && NF_NAT
+	depends on NF_CONNTRACK && NF_NAT
 	default NF_NAT && NF_CONNTRACK_AMANDA
 
 config NF_NAT_PPTP
 	tristate
-	depends on IP_NF_IPTABLES && NF_CONNTRACK && NF_NAT
+	depends on NF_CONNTRACK && NF_NAT
 	default NF_NAT && NF_CONNTRACK_PPTP
 	select NF_NAT_PROTO_GRE
 
 config NF_NAT_H323
 	tristate
-	depends on IP_NF_IPTABLES && NF_CONNTRACK && NF_NAT
+	depends on NF_CONNTRACK && NF_NAT
 	default NF_NAT && NF_CONNTRACK_H323
 
 config NF_NAT_SIP
 	tristate
-	depends on IP_NF_IPTABLES && NF_CONNTRACK && NF_NAT
+	depends on NF_CONNTRACK && NF_NAT
 	default NF_NAT && NF_CONNTRACK_SIP
 
 # mangle + specific targets
 config IP_NF_MANGLE
 	tristate "Packet mangling"
-	depends on IP_NF_IPTABLES
 	default m if NETFILTER_ADVANCED=n
 	help
 	  This option adds a `mangle' table to iptables: see the man page for
@@ -308,6 +294,19 @@
 
 	  To compile it as a module, choose M here.  If unsure, say N.
 
+config IP_NF_TARGET_CLUSTERIP
+	tristate "CLUSTERIP target support (EXPERIMENTAL)"
+	depends on IP_NF_MANGLE && EXPERIMENTAL
+	depends on NF_CONNTRACK_IPV4
+	depends on NETFILTER_ADVANCED
+	select NF_CONNTRACK_MARK
+	help
+	  The CLUSTERIP target allows you to build load-balancing clusters of
+	  network servers without having a dedicated load-balancing
+	  router/server/switch.
+	
+	  To compile it as a module, choose M here.  If unsure, say N.
+
 config IP_NF_TARGET_ECN
 	tristate "ECN target support"
 	depends on IP_NF_MANGLE
@@ -338,23 +337,9 @@
 
 	  To compile it as a module, choose M here.  If unsure, say N.
 
-config IP_NF_TARGET_CLUSTERIP
-	tristate "CLUSTERIP target support (EXPERIMENTAL)"
-	depends on IP_NF_MANGLE && EXPERIMENTAL
-	depends on NF_CONNTRACK_IPV4
-	depends on NETFILTER_ADVANCED
-	select NF_CONNTRACK_MARK
-	help
-	  The CLUSTERIP target allows you to build load-balancing clusters of
-	  network servers without having a dedicated load-balancing
-	  router/server/switch.
-	
-	  To compile it as a module, choose M here.  If unsure, say N.
-
 # raw + specific targets
 config IP_NF_RAW
 	tristate  'raw table support (required for NOTRACK/TRACE)'
-	depends on IP_NF_IPTABLES
 	depends on NETFILTER_ADVANCED
 	help
 	  This option adds a `raw' table to iptables. This table is the very
@@ -367,7 +352,6 @@
 # security table for MAC policy
 config IP_NF_SECURITY
 	tristate "Security table"
-	depends on IP_NF_IPTABLES
 	depends on SECURITY
 	depends on NETFILTER_ADVANCED
 	help
@@ -376,6 +360,8 @@
 	 
 	  If unsure, say N.
 
+endif # IP_NF_IPTABLES
+
 # ARP tables
 config IP_NF_ARPTABLES
 	tristate "ARP tables support"
@@ -388,9 +374,10 @@
 
 	  To compile it as a module, choose M here.  If unsure, say N.
 
+if IP_NF_ARPTABLES
+
 config IP_NF_ARPFILTER
 	tristate "ARP packet filtering"
-	depends on IP_NF_ARPTABLES
 	help
 	  ARP packet filtering defines a table `filter', which has a series of
 	  rules for simple ARP packet filtering at local input and
@@ -401,10 +388,11 @@
 
 config IP_NF_ARP_MANGLE
 	tristate "ARP payload mangling"
-	depends on IP_NF_ARPTABLES
 	help
 	  Allows altering the ARP packet payload: source and destination
 	  hardware and network addresses.
 
+endif # IP_NF_ARPTABLES
+
 endmenu
 
diff --git a/net/ipv4/netfilter/Makefile b/net/ipv4/netfilter/Makefile
index 3f31291f..5f9b650 100644
--- a/net/ipv4/netfilter/Makefile
+++ b/net/ipv4/netfilter/Makefile
@@ -18,6 +18,9 @@
 
 obj-$(CONFIG_NF_NAT) += nf_nat.o
 
+# defrag
+obj-$(CONFIG_NF_DEFRAG_IPV4) += nf_defrag_ipv4.o
+
 # NAT helpers (nf_conntrack)
 obj-$(CONFIG_NF_NAT_AMANDA) += nf_nat_amanda.o
 obj-$(CONFIG_NF_NAT_FTP) += nf_nat_ftp.o
@@ -48,7 +51,6 @@
 obj-$(CONFIG_IP_NF_MATCH_ADDRTYPE) += ipt_addrtype.o
 obj-$(CONFIG_IP_NF_MATCH_AH) += ipt_ah.o
 obj-$(CONFIG_IP_NF_MATCH_ECN) += ipt_ecn.o
-obj-$(CONFIG_IP_NF_MATCH_RECENT) += ipt_recent.o
 obj-$(CONFIG_IP_NF_MATCH_TTL) += ipt_ttl.o
 
 # targets
diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c
index 03e83a6..8d70d29 100644
--- a/net/ipv4/netfilter/arp_tables.c
+++ b/net/ipv4/netfilter/arp_tables.c
@@ -200,15 +200,12 @@
 	return 1;
 }
 
-static unsigned int arpt_error(struct sk_buff *skb,
-			       const struct net_device *in,
-			       const struct net_device *out,
-			       unsigned int hooknum,
-			       const struct xt_target *target,
-			       const void *targinfo)
+static unsigned int
+arpt_error(struct sk_buff *skb, const struct xt_target_param *par)
 {
 	if (net_ratelimit())
-		printk("arp_tables: error: '%s'\n", (char *)targinfo);
+		printk("arp_tables: error: '%s'\n",
+		       (const char *)par->targinfo);
 
 	return NF_DROP;
 }
@@ -232,6 +229,7 @@
 	const char *indev, *outdev;
 	void *table_base;
 	const struct xt_table_info *private;
+	struct xt_target_param tgpar;
 
 	if (!pskb_may_pull(skb, arp_hdr_len(skb->dev)))
 		return NF_DROP;
@@ -245,6 +243,11 @@
 	e = get_entry(table_base, private->hook_entry[hook]);
 	back = get_entry(table_base, private->underflow[hook]);
 
+	tgpar.in      = in;
+	tgpar.out     = out;
+	tgpar.hooknum = hook;
+	tgpar.family  = NFPROTO_ARP;
+
 	arp = arp_hdr(skb);
 	do {
 		if (arp_packet_match(arp, skb->dev, indev, outdev, &e->arp)) {
@@ -290,11 +293,10 @@
 				/* Targets which reenter must return
 				 * abs. verdicts
 				 */
+				tgpar.target   = t->u.kernel.target;
+				tgpar.targinfo = t->data;
 				verdict = t->u.kernel.target->target(skb,
-								     in, out,
-								     hook,
-								     t->u.kernel.target,
-								     t->data);
+								     &tgpar);
 
 				/* Target might have changed stuff. */
 				arp = arp_hdr(skb);
@@ -456,23 +458,24 @@
 
 static inline int check_target(struct arpt_entry *e, const char *name)
 {
-	struct arpt_entry_target *t;
-	struct xt_target *target;
+	struct arpt_entry_target *t = arpt_get_target(e);
 	int ret;
+	struct xt_tgchk_param par = {
+		.table     = name,
+		.entryinfo = e,
+		.target    = t->u.kernel.target,
+		.targinfo  = t->data,
+		.hook_mask = e->comefrom,
+		.family    = NFPROTO_ARP,
+	};
 
-	t = arpt_get_target(e);
-	target = t->u.kernel.target;
-
-	ret = xt_check_target(target, NF_ARP, t->u.target_size - sizeof(*t),
-			      name, e->comefrom, 0, 0);
-	if (!ret && t->u.kernel.target->checkentry
-	    && !t->u.kernel.target->checkentry(name, e, target, t->data,
-					       e->comefrom)) {
+	ret = xt_check_target(&par, t->u.target_size - sizeof(*t), 0, false);
+	if (ret < 0) {
 		duprintf("arp_tables: check failed for `%s'.\n",
 			 t->u.kernel.target->name);
-		ret = -EINVAL;
+		return ret;
 	}
-	return ret;
+	return 0;
 }
 
 static inline int
@@ -488,7 +491,8 @@
 		return ret;
 
 	t = arpt_get_target(e);
-	target = try_then_request_module(xt_find_target(NF_ARP, t->u.user.name,
+	target = try_then_request_module(xt_find_target(NFPROTO_ARP,
+							t->u.user.name,
 							t->u.user.revision),
 					 "arpt_%s", t->u.user.name);
 	if (IS_ERR(target) || !target) {
@@ -554,15 +558,19 @@
 
 static inline int cleanup_entry(struct arpt_entry *e, unsigned int *i)
 {
+	struct xt_tgdtor_param par;
 	struct arpt_entry_target *t;
 
 	if (i && (*i)-- == 0)
 		return 1;
 
 	t = arpt_get_target(e);
-	if (t->u.kernel.target->destroy)
-		t->u.kernel.target->destroy(t->u.kernel.target, t->data);
-	module_put(t->u.kernel.target->me);
+	par.target   = t->u.kernel.target;
+	par.targinfo = t->data;
+	par.family   = NFPROTO_ARP;
+	if (par.target->destroy != NULL)
+		par.target->destroy(&par);
+	module_put(par.target->me);
 	return 0;
 }
 
@@ -788,7 +796,7 @@
 	int v = *(compat_int_t *)src;
 
 	if (v > 0)
-		v += xt_compat_calc_jump(NF_ARP, v);
+		v += xt_compat_calc_jump(NFPROTO_ARP, v);
 	memcpy(dst, &v, sizeof(v));
 }
 
@@ -797,7 +805,7 @@
 	compat_int_t cv = *(int *)src;
 
 	if (cv > 0)
-		cv -= xt_compat_calc_jump(NF_ARP, cv);
+		cv -= xt_compat_calc_jump(NFPROTO_ARP, cv);
 	return copy_to_user(dst, &cv, sizeof(cv)) ? -EFAULT : 0;
 }
 
@@ -815,7 +823,7 @@
 	t = arpt_get_target(e);
 	off += xt_compat_target_offset(t->u.kernel.target);
 	newinfo->size -= off;
-	ret = xt_compat_add_offset(NF_ARP, entry_offset, off);
+	ret = xt_compat_add_offset(NFPROTO_ARP, entry_offset, off);
 	if (ret)
 		return ret;
 
@@ -866,9 +874,9 @@
 	name[ARPT_TABLE_MAXNAMELEN-1] = '\0';
 #ifdef CONFIG_COMPAT
 	if (compat)
-		xt_compat_lock(NF_ARP);
+		xt_compat_lock(NFPROTO_ARP);
 #endif
-	t = try_then_request_module(xt_find_table_lock(net, NF_ARP, name),
+	t = try_then_request_module(xt_find_table_lock(net, NFPROTO_ARP, name),
 				    "arptable_%s", name);
 	if (t && !IS_ERR(t)) {
 		struct arpt_getinfo info;
@@ -878,7 +886,7 @@
 		if (compat) {
 			struct xt_table_info tmp;
 			ret = compat_table_info(private, &tmp);
-			xt_compat_flush_offsets(NF_ARP);
+			xt_compat_flush_offsets(NFPROTO_ARP);
 			private = &tmp;
 		}
 #endif
@@ -901,7 +909,7 @@
 		ret = t ? PTR_ERR(t) : -ENOENT;
 #ifdef CONFIG_COMPAT
 	if (compat)
-		xt_compat_unlock(NF_ARP);
+		xt_compat_unlock(NFPROTO_ARP);
 #endif
 	return ret;
 }
@@ -925,7 +933,7 @@
 		return -EINVAL;
 	}
 
-	t = xt_find_table_lock(net, NF_ARP, get.name);
+	t = xt_find_table_lock(net, NFPROTO_ARP, get.name);
 	if (t && !IS_ERR(t)) {
 		const struct xt_table_info *private = t->private;
 
@@ -967,7 +975,7 @@
 		goto out;
 	}
 
-	t = try_then_request_module(xt_find_table_lock(net, NF_ARP, name),
+	t = try_then_request_module(xt_find_table_lock(net, NFPROTO_ARP, name),
 				    "arptable_%s", name);
 	if (!t || IS_ERR(t)) {
 		ret = t ? PTR_ERR(t) : -ENOENT;
@@ -1134,7 +1142,7 @@
 		goto free;
 	}
 
-	t = xt_find_table_lock(net, NF_ARP, name);
+	t = xt_find_table_lock(net, NFPROTO_ARP, name);
 	if (!t || IS_ERR(t)) {
 		ret = t ? PTR_ERR(t) : -ENOENT;
 		goto free;
@@ -1218,7 +1226,7 @@
 	entry_offset = (void *)e - (void *)base;
 
 	t = compat_arpt_get_target(e);
-	target = try_then_request_module(xt_find_target(NF_ARP,
+	target = try_then_request_module(xt_find_target(NFPROTO_ARP,
 							t->u.user.name,
 							t->u.user.revision),
 					 "arpt_%s", t->u.user.name);
@@ -1232,7 +1240,7 @@
 
 	off += xt_compat_target_offset(target);
 	*size += off;
-	ret = xt_compat_add_offset(NF_ARP, entry_offset, off);
+	ret = xt_compat_add_offset(NFPROTO_ARP, entry_offset, off);
 	if (ret)
 		goto release_target;
 
@@ -1333,7 +1341,7 @@
 
 	duprintf("translate_compat_table: size %u\n", info->size);
 	j = 0;
-	xt_compat_lock(NF_ARP);
+	xt_compat_lock(NFPROTO_ARP);
 	/* Walk through entries, checking offsets. */
 	ret = COMPAT_ARPT_ENTRY_ITERATE(entry0, total_size,
 					check_compat_entry_size_and_hooks,
@@ -1383,8 +1391,8 @@
 	ret = COMPAT_ARPT_ENTRY_ITERATE(entry0, total_size,
 					compat_copy_entry_from_user,
 					&pos, &size, name, newinfo, entry1);
-	xt_compat_flush_offsets(NF_ARP);
-	xt_compat_unlock(NF_ARP);
+	xt_compat_flush_offsets(NFPROTO_ARP);
+	xt_compat_unlock(NFPROTO_ARP);
 	if (ret)
 		goto free_newinfo;
 
@@ -1420,8 +1428,8 @@
 	COMPAT_ARPT_ENTRY_ITERATE(entry0, total_size, compat_release_entry, &j);
 	return ret;
 out_unlock:
-	xt_compat_flush_offsets(NF_ARP);
-	xt_compat_unlock(NF_ARP);
+	xt_compat_flush_offsets(NFPROTO_ARP);
+	xt_compat_unlock(NFPROTO_ARP);
 	goto out;
 }
 
@@ -1607,8 +1615,8 @@
 		return -EINVAL;
 	}
 
-	xt_compat_lock(NF_ARP);
-	t = xt_find_table_lock(net, NF_ARP, get.name);
+	xt_compat_lock(NFPROTO_ARP);
+	t = xt_find_table_lock(net, NFPROTO_ARP, get.name);
 	if (t && !IS_ERR(t)) {
 		const struct xt_table_info *private = t->private;
 		struct xt_table_info info;
@@ -1623,13 +1631,13 @@
 				 private->size, get.size);
 			ret = -EAGAIN;
 		}
-		xt_compat_flush_offsets(NF_ARP);
+		xt_compat_flush_offsets(NFPROTO_ARP);
 		module_put(t->me);
 		xt_table_unlock(t);
 	} else
 		ret = t ? PTR_ERR(t) : -ENOENT;
 
-	xt_compat_unlock(NF_ARP);
+	xt_compat_unlock(NFPROTO_ARP);
 	return ret;
 }
 
@@ -1709,7 +1717,7 @@
 			break;
 		}
 
-		try_then_request_module(xt_find_revision(NF_ARP, rev.name,
+		try_then_request_module(xt_find_revision(NFPROTO_ARP, rev.name,
 							 rev.revision, 1, &ret),
 					"arpt_%s", rev.name);
 		break;
@@ -1787,7 +1795,7 @@
 static struct xt_target arpt_standard_target __read_mostly = {
 	.name		= ARPT_STANDARD_TARGET,
 	.targetsize	= sizeof(int),
-	.family		= NF_ARP,
+	.family		= NFPROTO_ARP,
 #ifdef CONFIG_COMPAT
 	.compatsize	= sizeof(compat_int_t),
 	.compat_from_user = compat_standard_from_user,
@@ -1799,7 +1807,7 @@
 	.name		= ARPT_ERROR_TARGET,
 	.target		= arpt_error,
 	.targetsize	= ARPT_FUNCTION_MAXNAMELEN,
-	.family		= NF_ARP,
+	.family		= NFPROTO_ARP,
 };
 
 static struct nf_sockopt_ops arpt_sockopts = {
@@ -1821,12 +1829,12 @@
 
 static int __net_init arp_tables_net_init(struct net *net)
 {
-	return xt_proto_init(net, NF_ARP);
+	return xt_proto_init(net, NFPROTO_ARP);
 }
 
 static void __net_exit arp_tables_net_exit(struct net *net)
 {
-	xt_proto_fini(net, NF_ARP);
+	xt_proto_fini(net, NFPROTO_ARP);
 }
 
 static struct pernet_operations arp_tables_net_ops = {
diff --git a/net/ipv4/netfilter/arpt_mangle.c b/net/ipv4/netfilter/arpt_mangle.c
index a385959..b0d5b1d 100644
--- a/net/ipv4/netfilter/arpt_mangle.c
+++ b/net/ipv4/netfilter/arpt_mangle.c
@@ -9,12 +9,9 @@
 MODULE_DESCRIPTION("arptables arp payload mangle target");
 
 static unsigned int
-target(struct sk_buff *skb,
-       const struct net_device *in, const struct net_device *out,
-       unsigned int hooknum, const struct xt_target *target,
-       const void *targinfo)
+target(struct sk_buff *skb, const struct xt_target_param *par)
 {
-	const struct arpt_mangle *mangle = targinfo;
+	const struct arpt_mangle *mangle = par->targinfo;
 	const struct arphdr *arp;
 	unsigned char *arpptr;
 	int pln, hln;
@@ -57,11 +54,9 @@
 	return mangle->target;
 }
 
-static bool
-checkentry(const char *tablename, const void *e, const struct xt_target *target,
-	   void *targinfo, unsigned int hook_mask)
+static bool checkentry(const struct xt_tgchk_param *par)
 {
-	const struct arpt_mangle *mangle = targinfo;
+	const struct arpt_mangle *mangle = par->targinfo;
 
 	if (mangle->flags & ~ARPT_MANGLE_MASK ||
 	    !(mangle->flags & ARPT_MANGLE_MASK))
@@ -75,7 +70,7 @@
 
 static struct xt_target arpt_mangle_reg __read_mostly = {
 	.name		= "mangle",
-	.family		= NF_ARP,
+	.family		= NFPROTO_ARP,
 	.target		= target,
 	.targetsize	= sizeof(struct arpt_mangle),
 	.checkentry	= checkentry,
diff --git a/net/ipv4/netfilter/arptable_filter.c b/net/ipv4/netfilter/arptable_filter.c
index 082f5dd..bee3d11 100644
--- a/net/ipv4/netfilter/arptable_filter.c
+++ b/net/ipv4/netfilter/arptable_filter.c
@@ -51,7 +51,7 @@
 	.lock		= __RW_LOCK_UNLOCKED(packet_filter.lock),
 	.private	= NULL,
 	.me		= THIS_MODULE,
-	.af		= NF_ARP,
+	.af		= NFPROTO_ARP,
 };
 
 /* The work comes in here from netfilter.c */
@@ -89,21 +89,21 @@
 	{
 		.hook		= arpt_in_hook,
 		.owner		= THIS_MODULE,
-		.pf		= NF_ARP,
+		.pf		= NFPROTO_ARP,
 		.hooknum	= NF_ARP_IN,
 		.priority	= NF_IP_PRI_FILTER,
 	},
 	{
 		.hook		= arpt_out_hook,
 		.owner		= THIS_MODULE,
-		.pf		= NF_ARP,
+		.pf		= NFPROTO_ARP,
 		.hooknum	= NF_ARP_OUT,
 		.priority	= NF_IP_PRI_FILTER,
 	},
 	{
 		.hook		= arpt_forward_hook,
 		.owner		= THIS_MODULE,
-		.pf		= NF_ARP,
+		.pf		= NFPROTO_ARP,
 		.hooknum	= NF_ARP_FORWARD,
 		.priority	= NF_IP_PRI_FILTER,
 	},
diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c
index 4e7c719..213fb27 100644
--- a/net/ipv4/netfilter/ip_tables.c
+++ b/net/ipv4/netfilter/ip_tables.c
@@ -171,31 +171,25 @@
 }
 
 static unsigned int
-ipt_error(struct sk_buff *skb,
-	  const struct net_device *in,
-	  const struct net_device *out,
-	  unsigned int hooknum,
-	  const struct xt_target *target,
-	  const void *targinfo)
+ipt_error(struct sk_buff *skb, const struct xt_target_param *par)
 {
 	if (net_ratelimit())
-		printk("ip_tables: error: `%s'\n", (char *)targinfo);
+		printk("ip_tables: error: `%s'\n",
+		       (const char *)par->targinfo);
 
 	return NF_DROP;
 }
 
 /* Performance critical - called for every packet */
 static inline bool
-do_match(struct ipt_entry_match *m,
-	      const struct sk_buff *skb,
-	      const struct net_device *in,
-	      const struct net_device *out,
-	      int offset,
-	      bool *hotdrop)
+do_match(struct ipt_entry_match *m, const struct sk_buff *skb,
+	 struct xt_match_param *par)
 {
+	par->match     = m->u.kernel.match;
+	par->matchinfo = m->data;
+
 	/* Stop iteration if it doesn't match */
-	if (!m->u.kernel.match->match(skb, in, out, m->u.kernel.match, m->data,
-				      offset, ip_hdrlen(skb), hotdrop))
+	if (!m->u.kernel.match->match(skb, par))
 		return true;
 	else
 		return false;
@@ -326,7 +320,6 @@
 	     struct xt_table *table)
 {
 	static const char nulldevname[IFNAMSIZ] __attribute__((aligned(sizeof(long))));
-	u_int16_t offset;
 	const struct iphdr *ip;
 	u_int16_t datalen;
 	bool hotdrop = false;
@@ -336,6 +329,8 @@
 	void *table_base;
 	struct ipt_entry *e, *back;
 	struct xt_table_info *private;
+	struct xt_match_param mtpar;
+	struct xt_target_param tgpar;
 
 	/* Initialization */
 	ip = ip_hdr(skb);
@@ -348,7 +343,13 @@
 	 * things we don't know, ie. tcp syn flag or ports).  If the
 	 * rule is also a fragment-specific rule, non-fragments won't
 	 * match it. */
-	offset = ntohs(ip->frag_off) & IP_OFFSET;
+	mtpar.fragoff = ntohs(ip->frag_off) & IP_OFFSET;
+	mtpar.thoff   = ip_hdrlen(skb);
+	mtpar.hotdrop = &hotdrop;
+	mtpar.in      = tgpar.in  = in;
+	mtpar.out     = tgpar.out = out;
+	mtpar.family  = tgpar.family = NFPROTO_IPV4;
+	tgpar.hooknum = hook;
 
 	read_lock_bh(&table->lock);
 	IP_NF_ASSERT(table->valid_hooks & (1 << hook));
@@ -362,12 +363,11 @@
 	do {
 		IP_NF_ASSERT(e);
 		IP_NF_ASSERT(back);
-		if (ip_packet_match(ip, indev, outdev, &e->ip, offset)) {
+		if (ip_packet_match(ip, indev, outdev,
+		    &e->ip, mtpar.fragoff)) {
 			struct ipt_entry_target *t;
 
-			if (IPT_MATCH_ITERATE(e, do_match,
-					      skb, in, out,
-					      offset, &hotdrop) != 0)
+			if (IPT_MATCH_ITERATE(e, do_match, skb, &mtpar) != 0)
 				goto no_match;
 
 			ADD_COUNTER(e->counters, ntohs(ip->tot_len), 1);
@@ -413,16 +413,14 @@
 			} else {
 				/* Targets which reenter must return
 				   abs. verdicts */
+				tgpar.target   = t->u.kernel.target;
+				tgpar.targinfo = t->data;
 #ifdef CONFIG_NETFILTER_DEBUG
 				((struct ipt_entry *)table_base)->comefrom
 					= 0xeeeeeeec;
 #endif
 				verdict = t->u.kernel.target->target(skb,
-								     in, out,
-								     hook,
-								     t->u.kernel.target,
-								     t->data);
-
+								     &tgpar);
 #ifdef CONFIG_NETFILTER_DEBUG
 				if (((struct ipt_entry *)table_base)->comefrom
 				    != 0xeeeeeeec
@@ -575,12 +573,17 @@
 static int
 cleanup_match(struct ipt_entry_match *m, unsigned int *i)
 {
+	struct xt_mtdtor_param par;
+
 	if (i && (*i)-- == 0)
 		return 1;
 
-	if (m->u.kernel.match->destroy)
-		m->u.kernel.match->destroy(m->u.kernel.match, m->data);
-	module_put(m->u.kernel.match->me);
+	par.match     = m->u.kernel.match;
+	par.matchinfo = m->data;
+	par.family    = NFPROTO_IPV4;
+	if (par.match->destroy != NULL)
+		par.match->destroy(&par);
+	module_put(par.match->me);
 	return 0;
 }
 
@@ -606,34 +609,28 @@
 }
 
 static int
-check_match(struct ipt_entry_match *m, const char *name,
-			      const struct ipt_ip *ip,
-			      unsigned int hookmask, unsigned int *i)
+check_match(struct ipt_entry_match *m, struct xt_mtchk_param *par,
+	    unsigned int *i)
 {
-	struct xt_match *match;
+	const struct ipt_ip *ip = par->entryinfo;
 	int ret;
 
-	match = m->u.kernel.match;
-	ret = xt_check_match(match, AF_INET, m->u.match_size - sizeof(*m),
-			     name, hookmask, ip->proto,
-			     ip->invflags & IPT_INV_PROTO);
-	if (!ret && m->u.kernel.match->checkentry
-	    && !m->u.kernel.match->checkentry(name, ip, match, m->data,
-					      hookmask)) {
+	par->match     = m->u.kernel.match;
+	par->matchinfo = m->data;
+
+	ret = xt_check_match(par, m->u.match_size - sizeof(*m),
+	      ip->proto, ip->invflags & IPT_INV_PROTO);
+	if (ret < 0) {
 		duprintf("ip_tables: check failed for `%s'.\n",
-			 m->u.kernel.match->name);
-		ret = -EINVAL;
+			 par.match->name);
+		return ret;
 	}
-	if (!ret)
-		(*i)++;
-	return ret;
+	++*i;
+	return 0;
 }
 
 static int
-find_check_match(struct ipt_entry_match *m,
-		 const char *name,
-		 const struct ipt_ip *ip,
-		 unsigned int hookmask,
+find_check_match(struct ipt_entry_match *m, struct xt_mtchk_param *par,
 		 unsigned int *i)
 {
 	struct xt_match *match;
@@ -648,7 +645,7 @@
 	}
 	m->u.kernel.match = match;
 
-	ret = check_match(m, name, ip, hookmask, i);
+	ret = check_match(m, par, i);
 	if (ret)
 		goto err;
 
@@ -660,23 +657,25 @@
 
 static int check_target(struct ipt_entry *e, const char *name)
 {
-	struct ipt_entry_target *t;
-	struct xt_target *target;
+	struct ipt_entry_target *t = ipt_get_target(e);
+	struct xt_tgchk_param par = {
+		.table     = name,
+		.entryinfo = e,
+		.target    = t->u.kernel.target,
+		.targinfo  = t->data,
+		.hook_mask = e->comefrom,
+		.family    = NFPROTO_IPV4,
+	};
 	int ret;
 
-	t = ipt_get_target(e);
-	target = t->u.kernel.target;
-	ret = xt_check_target(target, AF_INET, t->u.target_size - sizeof(*t),
-			      name, e->comefrom, e->ip.proto,
-			      e->ip.invflags & IPT_INV_PROTO);
-	if (!ret && t->u.kernel.target->checkentry
-	    && !t->u.kernel.target->checkentry(name, e, target, t->data,
-					       e->comefrom)) {
+	ret = xt_check_target(&par, t->u.target_size - sizeof(*t),
+	      e->ip.proto, e->ip.invflags & IPT_INV_PROTO);
+	if (ret < 0) {
 		duprintf("ip_tables: check failed for `%s'.\n",
 			 t->u.kernel.target->name);
-		ret = -EINVAL;
+		return ret;
 	}
-	return ret;
+	return 0;
 }
 
 static int
@@ -687,14 +686,18 @@
 	struct xt_target *target;
 	int ret;
 	unsigned int j;
+	struct xt_mtchk_param mtpar;
 
 	ret = check_entry(e, name);
 	if (ret)
 		return ret;
 
 	j = 0;
-	ret = IPT_MATCH_ITERATE(e, find_check_match, name, &e->ip,
-				e->comefrom, &j);
+	mtpar.table     = name;
+	mtpar.entryinfo = &e->ip;
+	mtpar.hook_mask = e->comefrom;
+	mtpar.family    = NFPROTO_IPV4;
+	ret = IPT_MATCH_ITERATE(e, find_check_match, &mtpar, &j);
 	if (ret != 0)
 		goto cleanup_matches;
 
@@ -769,6 +772,7 @@
 static int
 cleanup_entry(struct ipt_entry *e, unsigned int *i)
 {
+	struct xt_tgdtor_param par;
 	struct ipt_entry_target *t;
 
 	if (i && (*i)-- == 0)
@@ -777,9 +781,13 @@
 	/* Cleanup all matches */
 	IPT_MATCH_ITERATE(e, cleanup_match, NULL);
 	t = ipt_get_target(e);
-	if (t->u.kernel.target->destroy)
-		t->u.kernel.target->destroy(t->u.kernel.target, t->data);
-	module_put(t->u.kernel.target->me);
+
+	par.target   = t->u.kernel.target;
+	par.targinfo = t->data;
+	par.family   = NFPROTO_IPV4;
+	if (par.target->destroy != NULL)
+		par.target->destroy(&par);
+	module_put(par.target->me);
 	return 0;
 }
 
@@ -1648,12 +1656,16 @@
 compat_check_entry(struct ipt_entry *e, const char *name,
 				     unsigned int *i)
 {
+	struct xt_mtchk_param mtpar;
 	unsigned int j;
 	int ret;
 
 	j = 0;
-	ret = IPT_MATCH_ITERATE(e, check_match, name, &e->ip,
-				e->comefrom, &j);
+	mtpar.table     = name;
+	mtpar.entryinfo = &e->ip;
+	mtpar.hook_mask = e->comefrom;
+	mtpar.family    = NFPROTO_IPV4;
+	ret = IPT_MATCH_ITERATE(e, check_match, &mtpar, &j);
 	if (ret)
 		goto cleanup_matches;
 
@@ -2121,30 +2133,23 @@
 }
 
 static bool
-icmp_match(const struct sk_buff *skb,
-	   const struct net_device *in,
-	   const struct net_device *out,
-	   const struct xt_match *match,
-	   const void *matchinfo,
-	   int offset,
-	   unsigned int protoff,
-	   bool *hotdrop)
+icmp_match(const struct sk_buff *skb, const struct xt_match_param *par)
 {
 	const struct icmphdr *ic;
 	struct icmphdr _icmph;
-	const struct ipt_icmp *icmpinfo = matchinfo;
+	const struct ipt_icmp *icmpinfo = par->matchinfo;
 
 	/* Must not be a fragment. */
-	if (offset)
+	if (par->fragoff != 0)
 		return false;
 
-	ic = skb_header_pointer(skb, protoff, sizeof(_icmph), &_icmph);
+	ic = skb_header_pointer(skb, par->thoff, sizeof(_icmph), &_icmph);
 	if (ic == NULL) {
 		/* We've been asked to examine this packet, and we
 		 * can't.  Hence, no choice but to drop.
 		 */
 		duprintf("Dropping evil ICMP tinygram.\n");
-		*hotdrop = true;
+		*par->hotdrop = true;
 		return false;
 	}
 
@@ -2155,15 +2160,9 @@
 				    !!(icmpinfo->invflags&IPT_ICMP_INV));
 }
 
-/* Called when user tries to insert an entry of this type. */
-static bool
-icmp_checkentry(const char *tablename,
-	   const void *entry,
-	   const struct xt_match *match,
-	   void *matchinfo,
-	   unsigned int hook_mask)
+static bool icmp_checkentry(const struct xt_mtchk_param *par)
 {
-	const struct ipt_icmp *icmpinfo = matchinfo;
+	const struct ipt_icmp *icmpinfo = par->matchinfo;
 
 	/* Must specify no unknown invflags */
 	return !(icmpinfo->invflags & ~IPT_ICMP_INV);
diff --git a/net/ipv4/netfilter/ipt_CLUSTERIP.c b/net/ipv4/netfilter/ipt_CLUSTERIP.c
index fafe8eb..7ac1677 100644
--- a/net/ipv4/netfilter/ipt_CLUSTERIP.c
+++ b/net/ipv4/netfilter/ipt_CLUSTERIP.c
@@ -281,11 +281,9 @@
  ***********************************************************************/
 
 static unsigned int
-clusterip_tg(struct sk_buff *skb, const struct net_device *in,
-             const struct net_device *out, unsigned int hooknum,
-             const struct xt_target *target, const void *targinfo)
+clusterip_tg(struct sk_buff *skb, const struct xt_target_param *par)
 {
-	const struct ipt_clusterip_tgt_info *cipinfo = targinfo;
+	const struct ipt_clusterip_tgt_info *cipinfo = par->targinfo;
 	struct nf_conn *ct;
 	enum ip_conntrack_info ctinfo;
 	u_int32_t hash;
@@ -349,13 +347,10 @@
 	return XT_CONTINUE;
 }
 
-static bool
-clusterip_tg_check(const char *tablename, const void *e_void,
-                   const struct xt_target *target, void *targinfo,
-                   unsigned int hook_mask)
+static bool clusterip_tg_check(const struct xt_tgchk_param *par)
 {
-	struct ipt_clusterip_tgt_info *cipinfo = targinfo;
-	const struct ipt_entry *e = e_void;
+	struct ipt_clusterip_tgt_info *cipinfo = par->targinfo;
+	const struct ipt_entry *e = par->entryinfo;
 
 	struct clusterip_config *config;
 
@@ -406,9 +401,9 @@
 	}
 	cipinfo->config = config;
 
-	if (nf_ct_l3proto_try_module_get(target->family) < 0) {
+	if (nf_ct_l3proto_try_module_get(par->target->family) < 0) {
 		printk(KERN_WARNING "can't load conntrack support for "
-				    "proto=%u\n", target->family);
+				    "proto=%u\n", par->target->family);
 		return false;
 	}
 
@@ -416,9 +411,9 @@
 }
 
 /* drop reference count of cluster config when rule is deleted */
-static void clusterip_tg_destroy(const struct xt_target *target, void *targinfo)
+static void clusterip_tg_destroy(const struct xt_tgdtor_param *par)
 {
-	const struct ipt_clusterip_tgt_info *cipinfo = targinfo;
+	const struct ipt_clusterip_tgt_info *cipinfo = par->targinfo;
 
 	/* if no more entries are referencing the config, remove it
 	 * from the list and destroy the proc entry */
@@ -426,7 +421,7 @@
 
 	clusterip_config_put(cipinfo->config);
 
-	nf_ct_l3proto_module_put(target->family);
+	nf_ct_l3proto_module_put(par->target->family);
 }
 
 #ifdef CONFIG_COMPAT
@@ -445,7 +440,7 @@
 
 static struct xt_target clusterip_tg_reg __read_mostly = {
 	.name		= "CLUSTERIP",
-	.family		= AF_INET,
+	.family		= NFPROTO_IPV4,
 	.target		= clusterip_tg,
 	.checkentry	= clusterip_tg_check,
 	.destroy	= clusterip_tg_destroy,
@@ -546,7 +541,7 @@
 
 static struct nf_hook_ops cip_arp_ops __read_mostly = {
 	.hook = arp_mangle,
-	.pf = NF_ARP,
+	.pf = NFPROTO_ARP,
 	.hooknum = NF_ARP_OUT,
 	.priority = -1
 };
diff --git a/net/ipv4/netfilter/ipt_ECN.c b/net/ipv4/netfilter/ipt_ECN.c
index d60139c..f7e2fa0 100644
--- a/net/ipv4/netfilter/ipt_ECN.c
+++ b/net/ipv4/netfilter/ipt_ECN.c
@@ -77,11 +77,9 @@
 }
 
 static unsigned int
-ecn_tg(struct sk_buff *skb, const struct net_device *in,
-       const struct net_device *out, unsigned int hooknum,
-       const struct xt_target *target, const void *targinfo)
+ecn_tg(struct sk_buff *skb, const struct xt_target_param *par)
 {
-	const struct ipt_ECN_info *einfo = targinfo;
+	const struct ipt_ECN_info *einfo = par->targinfo;
 
 	if (einfo->operation & IPT_ECN_OP_SET_IP)
 		if (!set_ect_ip(skb, einfo))
@@ -95,13 +93,10 @@
 	return XT_CONTINUE;
 }
 
-static bool
-ecn_tg_check(const char *tablename, const void *e_void,
-             const struct xt_target *target, void *targinfo,
-             unsigned int hook_mask)
+static bool ecn_tg_check(const struct xt_tgchk_param *par)
 {
-	const struct ipt_ECN_info *einfo = targinfo;
-	const struct ipt_entry *e = e_void;
+	const struct ipt_ECN_info *einfo = par->targinfo;
+	const struct ipt_entry *e = par->entryinfo;
 
 	if (einfo->operation & IPT_ECN_OP_MASK) {
 		printk(KERN_WARNING "ECN: unsupported ECN operation %x\n",
@@ -124,7 +119,7 @@
 
 static struct xt_target ecn_tg_reg __read_mostly = {
 	.name		= "ECN",
-	.family		= AF_INET,
+	.family		= NFPROTO_IPV4,
 	.target		= ecn_tg,
 	.targetsize	= sizeof(struct ipt_ECN_info),
 	.table		= "mangle",
diff --git a/net/ipv4/netfilter/ipt_LOG.c b/net/ipv4/netfilter/ipt_LOG.c
index 0af1413..fc6ce04 100644
--- a/net/ipv4/netfilter/ipt_LOG.c
+++ b/net/ipv4/netfilter/ipt_LOG.c
@@ -375,7 +375,7 @@
 };
 
 static void
-ipt_log_packet(unsigned int pf,
+ipt_log_packet(u_int8_t pf,
 	       unsigned int hooknum,
 	       const struct sk_buff *skb,
 	       const struct net_device *in,
@@ -426,28 +426,23 @@
 }
 
 static unsigned int
-log_tg(struct sk_buff *skb, const struct net_device *in,
-       const struct net_device *out, unsigned int hooknum,
-       const struct xt_target *target, const void *targinfo)
+log_tg(struct sk_buff *skb, const struct xt_target_param *par)
 {
-	const struct ipt_log_info *loginfo = targinfo;
+	const struct ipt_log_info *loginfo = par->targinfo;
 	struct nf_loginfo li;
 
 	li.type = NF_LOG_TYPE_LOG;
 	li.u.log.level = loginfo->level;
 	li.u.log.logflags = loginfo->logflags;
 
-	ipt_log_packet(PF_INET, hooknum, skb, in, out, &li,
+	ipt_log_packet(NFPROTO_IPV4, par->hooknum, skb, par->in, par->out, &li,
 		       loginfo->prefix);
 	return XT_CONTINUE;
 }
 
-static bool
-log_tg_check(const char *tablename, const void *e,
-             const struct xt_target *target, void *targinfo,
-             unsigned int hook_mask)
+static bool log_tg_check(const struct xt_tgchk_param *par)
 {
-	const struct ipt_log_info *loginfo = targinfo;
+	const struct ipt_log_info *loginfo = par->targinfo;
 
 	if (loginfo->level >= 8) {
 		pr_debug("LOG: level %u >= 8\n", loginfo->level);
@@ -463,7 +458,7 @@
 
 static struct xt_target log_tg_reg __read_mostly = {
 	.name		= "LOG",
-	.family		= AF_INET,
+	.family		= NFPROTO_IPV4,
 	.target		= log_tg,
 	.targetsize	= sizeof(struct ipt_log_info),
 	.checkentry	= log_tg_check,
@@ -483,7 +478,7 @@
 	ret = xt_register_target(&log_tg_reg);
 	if (ret < 0)
 		return ret;
-	nf_log_register(PF_INET, &ipt_log_logger);
+	nf_log_register(NFPROTO_IPV4, &ipt_log_logger);
 	return 0;
 }
 
diff --git a/net/ipv4/netfilter/ipt_MASQUERADE.c b/net/ipv4/netfilter/ipt_MASQUERADE.c
index 0841aef..f389f60 100644
--- a/net/ipv4/netfilter/ipt_MASQUERADE.c
+++ b/net/ipv4/netfilter/ipt_MASQUERADE.c
@@ -31,12 +31,9 @@
 static DEFINE_RWLOCK(masq_lock);
 
 /* FIXME: Multiple targets. --RR */
-static bool
-masquerade_tg_check(const char *tablename, const void *e,
-                    const struct xt_target *target, void *targinfo,
-                    unsigned int hook_mask)
+static bool masquerade_tg_check(const struct xt_tgchk_param *par)
 {
-	const struct nf_nat_multi_range_compat *mr = targinfo;
+	const struct nf_nat_multi_range_compat *mr = par->targinfo;
 
 	if (mr->range[0].flags & IP_NAT_RANGE_MAP_IPS) {
 		pr_debug("masquerade_check: bad MAP_IPS.\n");
@@ -50,9 +47,7 @@
 }
 
 static unsigned int
-masquerade_tg(struct sk_buff *skb, const struct net_device *in,
-              const struct net_device *out, unsigned int hooknum,
-              const struct xt_target *target, const void *targinfo)
+masquerade_tg(struct sk_buff *skb, const struct xt_target_param *par)
 {
 	struct nf_conn *ct;
 	struct nf_conn_nat *nat;
@@ -62,7 +57,7 @@
 	const struct rtable *rt;
 	__be32 newsrc;
 
-	NF_CT_ASSERT(hooknum == NF_INET_POST_ROUTING);
+	NF_CT_ASSERT(par->hooknum == NF_INET_POST_ROUTING);
 
 	ct = nf_ct_get(skb, &ctinfo);
 	nat = nfct_nat(ct);
@@ -76,16 +71,16 @@
 	if (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip == 0)
 		return NF_ACCEPT;
 
-	mr = targinfo;
+	mr = par->targinfo;
 	rt = skb->rtable;
-	newsrc = inet_select_addr(out, rt->rt_gateway, RT_SCOPE_UNIVERSE);
+	newsrc = inet_select_addr(par->out, rt->rt_gateway, RT_SCOPE_UNIVERSE);
 	if (!newsrc) {
-		printk("MASQUERADE: %s ate my IP address\n", out->name);
+		printk("MASQUERADE: %s ate my IP address\n", par->out->name);
 		return NF_DROP;
 	}
 
 	write_lock_bh(&masq_lock);
-	nat->masq_index = out->ifindex;
+	nat->masq_index = par->out->ifindex;
 	write_unlock_bh(&masq_lock);
 
 	/* Transfer from original range. */
@@ -119,9 +114,7 @@
 			     void *ptr)
 {
 	const struct net_device *dev = ptr;
-
-	if (!net_eq(dev_net(dev), &init_net))
-		return NOTIFY_DONE;
+	struct net *net = dev_net(dev);
 
 	if (event == NETDEV_DOWN) {
 		/* Device was downed.  Search entire table for
@@ -129,7 +122,8 @@
 		   and forget them. */
 		NF_CT_ASSERT(dev->ifindex != 0);
 
-		nf_ct_iterate_cleanup(device_cmp, (void *)(long)dev->ifindex);
+		nf_ct_iterate_cleanup(net, device_cmp,
+				      (void *)(long)dev->ifindex);
 	}
 
 	return NOTIFY_DONE;
@@ -153,7 +147,7 @@
 
 static struct xt_target masquerade_tg_reg __read_mostly = {
 	.name		= "MASQUERADE",
-	.family		= AF_INET,
+	.family		= NFPROTO_IPV4,
 	.target		= masquerade_tg,
 	.targetsize	= sizeof(struct nf_nat_multi_range_compat),
 	.table		= "nat",
diff --git a/net/ipv4/netfilter/ipt_NETMAP.c b/net/ipv4/netfilter/ipt_NETMAP.c
index 6739abf..7c29582 100644
--- a/net/ipv4/netfilter/ipt_NETMAP.c
+++ b/net/ipv4/netfilter/ipt_NETMAP.c
@@ -22,12 +22,9 @@
 MODULE_AUTHOR("Svenning Soerensen <svenning@post5.tele.dk>");
 MODULE_DESCRIPTION("Xtables: 1:1 NAT mapping of IPv4 subnets");
 
-static bool
-netmap_tg_check(const char *tablename, const void *e,
-                const struct xt_target *target, void *targinfo,
-                unsigned int hook_mask)
+static bool netmap_tg_check(const struct xt_tgchk_param *par)
 {
-	const struct nf_nat_multi_range_compat *mr = targinfo;
+	const struct nf_nat_multi_range_compat *mr = par->targinfo;
 
 	if (!(mr->range[0].flags & IP_NAT_RANGE_MAP_IPS)) {
 		pr_debug("NETMAP:check: bad MAP_IPS.\n");
@@ -41,24 +38,23 @@
 }
 
 static unsigned int
-netmap_tg(struct sk_buff *skb, const struct net_device *in,
-          const struct net_device *out, unsigned int hooknum,
-          const struct xt_target *target, const void *targinfo)
+netmap_tg(struct sk_buff *skb, const struct xt_target_param *par)
 {
 	struct nf_conn *ct;
 	enum ip_conntrack_info ctinfo;
 	__be32 new_ip, netmask;
-	const struct nf_nat_multi_range_compat *mr = targinfo;
+	const struct nf_nat_multi_range_compat *mr = par->targinfo;
 	struct nf_nat_range newrange;
 
-	NF_CT_ASSERT(hooknum == NF_INET_PRE_ROUTING
-		     || hooknum == NF_INET_POST_ROUTING
-		     || hooknum == NF_INET_LOCAL_OUT);
+	NF_CT_ASSERT(par->hooknum == NF_INET_PRE_ROUTING ||
+		     par->hooknum == NF_INET_POST_ROUTING ||
+		     par->hooknum == NF_INET_LOCAL_OUT);
 	ct = nf_ct_get(skb, &ctinfo);
 
 	netmask = ~(mr->range[0].min_ip ^ mr->range[0].max_ip);
 
-	if (hooknum == NF_INET_PRE_ROUTING || hooknum == NF_INET_LOCAL_OUT)
+	if (par->hooknum == NF_INET_PRE_ROUTING ||
+	    par->hooknum == NF_INET_LOCAL_OUT)
 		new_ip = ip_hdr(skb)->daddr & ~netmask;
 	else
 		new_ip = ip_hdr(skb)->saddr & ~netmask;
@@ -70,12 +66,12 @@
 		  mr->range[0].min, mr->range[0].max });
 
 	/* Hand modified range to generic setup. */
-	return nf_nat_setup_info(ct, &newrange, HOOK2MANIP(hooknum));
+	return nf_nat_setup_info(ct, &newrange, HOOK2MANIP(par->hooknum));
 }
 
 static struct xt_target netmap_tg_reg __read_mostly = {
 	.name 		= "NETMAP",
-	.family		= AF_INET,
+	.family		= NFPROTO_IPV4,
 	.target 	= netmap_tg,
 	.targetsize	= sizeof(struct nf_nat_multi_range_compat),
 	.table		= "nat",
diff --git a/net/ipv4/netfilter/ipt_REDIRECT.c b/net/ipv4/netfilter/ipt_REDIRECT.c
index 5c62924..698e5e7 100644
--- a/net/ipv4/netfilter/ipt_REDIRECT.c
+++ b/net/ipv4/netfilter/ipt_REDIRECT.c
@@ -26,12 +26,9 @@
 MODULE_DESCRIPTION("Xtables: Connection redirection to localhost");
 
 /* FIXME: Take multiple ranges --RR */
-static bool
-redirect_tg_check(const char *tablename, const void *e,
-                  const struct xt_target *target, void *targinfo,
-                  unsigned int hook_mask)
+static bool redirect_tg_check(const struct xt_tgchk_param *par)
 {
-	const struct nf_nat_multi_range_compat *mr = targinfo;
+	const struct nf_nat_multi_range_compat *mr = par->targinfo;
 
 	if (mr->range[0].flags & IP_NAT_RANGE_MAP_IPS) {
 		pr_debug("redirect_check: bad MAP_IPS.\n");
@@ -45,24 +42,22 @@
 }
 
 static unsigned int
-redirect_tg(struct sk_buff *skb, const struct net_device *in,
-            const struct net_device *out, unsigned int hooknum,
-            const struct xt_target *target, const void *targinfo)
+redirect_tg(struct sk_buff *skb, const struct xt_target_param *par)
 {
 	struct nf_conn *ct;
 	enum ip_conntrack_info ctinfo;
 	__be32 newdst;
-	const struct nf_nat_multi_range_compat *mr = targinfo;
+	const struct nf_nat_multi_range_compat *mr = par->targinfo;
 	struct nf_nat_range newrange;
 
-	NF_CT_ASSERT(hooknum == NF_INET_PRE_ROUTING
-		     || hooknum == NF_INET_LOCAL_OUT);
+	NF_CT_ASSERT(par->hooknum == NF_INET_PRE_ROUTING ||
+		     par->hooknum == NF_INET_LOCAL_OUT);
 
 	ct = nf_ct_get(skb, &ctinfo);
 	NF_CT_ASSERT(ct && (ctinfo == IP_CT_NEW || ctinfo == IP_CT_RELATED));
 
 	/* Local packets: make them go to loopback */
-	if (hooknum == NF_INET_LOCAL_OUT)
+	if (par->hooknum == NF_INET_LOCAL_OUT)
 		newdst = htonl(0x7F000001);
 	else {
 		struct in_device *indev;
@@ -92,7 +87,7 @@
 
 static struct xt_target redirect_tg_reg __read_mostly = {
 	.name		= "REDIRECT",
-	.family		= AF_INET,
+	.family		= NFPROTO_IPV4,
 	.target		= redirect_tg,
 	.targetsize	= sizeof(struct nf_nat_multi_range_compat),
 	.table		= "nat",
diff --git a/net/ipv4/netfilter/ipt_REJECT.c b/net/ipv4/netfilter/ipt_REJECT.c
index 2639872..0b4b6e0 100644
--- a/net/ipv4/netfilter/ipt_REJECT.c
+++ b/net/ipv4/netfilter/ipt_REJECT.c
@@ -136,11 +136,9 @@
 }
 
 static unsigned int
-reject_tg(struct sk_buff *skb, const struct net_device *in,
-          const struct net_device *out, unsigned int hooknum,
-          const struct xt_target *target, const void *targinfo)
+reject_tg(struct sk_buff *skb, const struct xt_target_param *par)
 {
-	const struct ipt_reject_info *reject = targinfo;
+	const struct ipt_reject_info *reject = par->targinfo;
 
 	/* WARNING: This code causes reentry within iptables.
 	   This means that the iptables jump stack is now crap.  We
@@ -168,7 +166,7 @@
 		send_unreach(skb, ICMP_PKT_FILTERED);
 		break;
 	case IPT_TCP_RESET:
-		send_reset(skb, hooknum);
+		send_reset(skb, par->hooknum);
 	case IPT_ICMP_ECHOREPLY:
 		/* Doesn't happen. */
 		break;
@@ -177,13 +175,10 @@
 	return NF_DROP;
 }
 
-static bool
-reject_tg_check(const char *tablename, const void *e_void,
-                const struct xt_target *target, void *targinfo,
-                unsigned int hook_mask)
+static bool reject_tg_check(const struct xt_tgchk_param *par)
 {
-	const struct ipt_reject_info *rejinfo = targinfo;
-	const struct ipt_entry *e = e_void;
+	const struct ipt_reject_info *rejinfo = par->targinfo;
+	const struct ipt_entry *e = par->entryinfo;
 
 	if (rejinfo->with == IPT_ICMP_ECHOREPLY) {
 		printk("ipt_REJECT: ECHOREPLY no longer supported.\n");
@@ -201,7 +196,7 @@
 
 static struct xt_target reject_tg_reg __read_mostly = {
 	.name		= "REJECT",
-	.family		= AF_INET,
+	.family		= NFPROTO_IPV4,
 	.target		= reject_tg,
 	.targetsize	= sizeof(struct ipt_reject_info),
 	.table		= "filter",
diff --git a/net/ipv4/netfilter/ipt_TTL.c b/net/ipv4/netfilter/ipt_TTL.c
index 30eed65..6d76aae 100644
--- a/net/ipv4/netfilter/ipt_TTL.c
+++ b/net/ipv4/netfilter/ipt_TTL.c
@@ -20,12 +20,10 @@
 MODULE_LICENSE("GPL");
 
 static unsigned int
-ttl_tg(struct sk_buff *skb, const struct net_device *in,
-       const struct net_device *out, unsigned int hooknum,
-       const struct xt_target *target, const void *targinfo)
+ttl_tg(struct sk_buff *skb, const struct xt_target_param *par)
 {
 	struct iphdr *iph;
-	const struct ipt_TTL_info *info = targinfo;
+	const struct ipt_TTL_info *info = par->targinfo;
 	int new_ttl;
 
 	if (!skb_make_writable(skb, skb->len))
@@ -61,12 +59,9 @@
 	return XT_CONTINUE;
 }
 
-static bool
-ttl_tg_check(const char *tablename, const void *e,
-             const struct xt_target *target, void *targinfo,
-             unsigned int hook_mask)
+static bool ttl_tg_check(const struct xt_tgchk_param *par)
 {
-	const struct ipt_TTL_info *info = targinfo;
+	const struct ipt_TTL_info *info = par->targinfo;
 
 	if (info->mode > IPT_TTL_MAXMODE) {
 		printk(KERN_WARNING "ipt_TTL: invalid or unknown Mode %u\n",
@@ -80,7 +75,7 @@
 
 static struct xt_target ttl_tg_reg __read_mostly = {
 	.name 		= "TTL",
-	.family		= AF_INET,
+	.family		= NFPROTO_IPV4,
 	.target 	= ttl_tg,
 	.targetsize	= sizeof(struct ipt_TTL_info),
 	.table		= "mangle",
diff --git a/net/ipv4/netfilter/ipt_ULOG.c b/net/ipv4/netfilter/ipt_ULOG.c
index b192756..18a2826 100644
--- a/net/ipv4/netfilter/ipt_ULOG.c
+++ b/net/ipv4/netfilter/ipt_ULOG.c
@@ -281,18 +281,14 @@
 }
 
 static unsigned int
-ulog_tg(struct sk_buff *skb, const struct net_device *in,
-        const struct net_device *out, unsigned int hooknum,
-        const struct xt_target *target, const void *targinfo)
+ulog_tg(struct sk_buff *skb, const struct xt_target_param *par)
 {
-	struct ipt_ulog_info *loginfo = (struct ipt_ulog_info *) targinfo;
-
-	ipt_ulog_packet(hooknum, skb, in, out, loginfo, NULL);
-
+	ipt_ulog_packet(par->hooknum, skb, par->in, par->out,
+	                par->targinfo, NULL);
 	return XT_CONTINUE;
 }
 
-static void ipt_logfn(unsigned int pf,
+static void ipt_logfn(u_int8_t pf,
 		      unsigned int hooknum,
 		      const struct sk_buff *skb,
 		      const struct net_device *in,
@@ -317,12 +313,9 @@
 	ipt_ulog_packet(hooknum, skb, in, out, &loginfo, prefix);
 }
 
-static bool
-ulog_tg_check(const char *tablename, const void *e,
-              const struct xt_target *target, void *targinfo,
-              unsigned int hookmask)
+static bool ulog_tg_check(const struct xt_tgchk_param *par)
 {
-	const struct ipt_ulog_info *loginfo = targinfo;
+	const struct ipt_ulog_info *loginfo = par->targinfo;
 
 	if (loginfo->prefix[sizeof(loginfo->prefix) - 1] != '\0') {
 		pr_debug("ipt_ULOG: prefix term %i\n",
@@ -374,7 +367,7 @@
 
 static struct xt_target ulog_tg_reg __read_mostly = {
 	.name		= "ULOG",
-	.family		= AF_INET,
+	.family		= NFPROTO_IPV4,
 	.target		= ulog_tg,
 	.targetsize	= sizeof(struct ipt_ulog_info),
 	.checkentry	= ulog_tg_check,
@@ -419,7 +412,7 @@
 		return ret;
 	}
 	if (nflog)
-		nf_log_register(PF_INET, &ipt_ulog_logger);
+		nf_log_register(NFPROTO_IPV4, &ipt_ulog_logger);
 
 	return 0;
 }
diff --git a/net/ipv4/netfilter/ipt_addrtype.c b/net/ipv4/netfilter/ipt_addrtype.c
index 462a22c..88762f0 100644
--- a/net/ipv4/netfilter/ipt_addrtype.c
+++ b/net/ipv4/netfilter/ipt_addrtype.c
@@ -30,12 +30,9 @@
 }
 
 static bool
-addrtype_mt_v0(const struct sk_buff *skb, const struct net_device *in,
-	       const struct net_device *out, const struct xt_match *match,
-	       const void *matchinfo, int offset, unsigned int protoff,
-	       bool *hotdrop)
+addrtype_mt_v0(const struct sk_buff *skb, const struct xt_match_param *par)
 {
-	const struct ipt_addrtype_info *info = matchinfo;
+	const struct ipt_addrtype_info *info = par->matchinfo;
 	const struct iphdr *iph = ip_hdr(skb);
 	bool ret = true;
 
@@ -50,20 +47,17 @@
 }
 
 static bool
-addrtype_mt_v1(const struct sk_buff *skb, const struct net_device *in,
-	       const struct net_device *out, const struct xt_match *match,
-	       const void *matchinfo, int offset, unsigned int protoff,
-	       bool *hotdrop)
+addrtype_mt_v1(const struct sk_buff *skb, const struct xt_match_param *par)
 {
-	const struct ipt_addrtype_info_v1 *info = matchinfo;
+	const struct ipt_addrtype_info_v1 *info = par->matchinfo;
 	const struct iphdr *iph = ip_hdr(skb);
 	const struct net_device *dev = NULL;
 	bool ret = true;
 
 	if (info->flags & IPT_ADDRTYPE_LIMIT_IFACE_IN)
-		dev = in;
+		dev = par->in;
 	else if (info->flags & IPT_ADDRTYPE_LIMIT_IFACE_OUT)
-		dev = out;
+		dev = par->out;
 
 	if (info->source)
 		ret &= match_type(dev, iph->saddr, info->source) ^
@@ -74,12 +68,9 @@
 	return ret;
 }
 
-static bool
-addrtype_mt_checkentry_v1(const char *tablename, const void *ip_void,
-			  const struct xt_match *match, void *matchinfo,
-			  unsigned int hook_mask)
+static bool addrtype_mt_checkentry_v1(const struct xt_mtchk_param *par)
 {
-	struct ipt_addrtype_info_v1 *info = matchinfo;
+	struct ipt_addrtype_info_v1 *info = par->matchinfo;
 
 	if (info->flags & IPT_ADDRTYPE_LIMIT_IFACE_IN &&
 	    info->flags & IPT_ADDRTYPE_LIMIT_IFACE_OUT) {
@@ -88,14 +79,16 @@
 		return false;
 	}
 
-	if (hook_mask & (1 << NF_INET_PRE_ROUTING | 1 << NF_INET_LOCAL_IN) &&
+	if (par->hook_mask & ((1 << NF_INET_PRE_ROUTING) |
+	    (1 << NF_INET_LOCAL_IN)) &&
 	    info->flags & IPT_ADDRTYPE_LIMIT_IFACE_OUT) {
 		printk(KERN_ERR "ipt_addrtype: output interface limitation "
 				"not valid in PRE_ROUTING and INPUT\n");
 		return false;
 	}
 
-	if (hook_mask & (1 << NF_INET_POST_ROUTING | 1 << NF_INET_LOCAL_OUT) &&
+	if (par->hook_mask & ((1 << NF_INET_POST_ROUTING) |
+	    (1 << NF_INET_LOCAL_OUT)) &&
 	    info->flags & IPT_ADDRTYPE_LIMIT_IFACE_IN) {
 		printk(KERN_ERR "ipt_addrtype: input interface limitation "
 				"not valid in POST_ROUTING and OUTPUT\n");
@@ -108,14 +101,14 @@
 static struct xt_match addrtype_mt_reg[] __read_mostly = {
 	{
 		.name		= "addrtype",
-		.family		= AF_INET,
+		.family		= NFPROTO_IPV4,
 		.match		= addrtype_mt_v0,
 		.matchsize	= sizeof(struct ipt_addrtype_info),
 		.me		= THIS_MODULE
 	},
 	{
 		.name		= "addrtype",
-		.family		= AF_INET,
+		.family		= NFPROTO_IPV4,
 		.revision	= 1,
 		.match		= addrtype_mt_v1,
 		.checkentry	= addrtype_mt_checkentry_v1,
diff --git a/net/ipv4/netfilter/ipt_ah.c b/net/ipv4/netfilter/ipt_ah.c
index e977989..0104c0b 100644
--- a/net/ipv4/netfilter/ipt_ah.c
+++ b/net/ipv4/netfilter/ipt_ah.c
@@ -36,27 +36,23 @@
 	return r;
 }
 
-static bool
-ah_mt(const struct sk_buff *skb, const struct net_device *in,
-      const struct net_device *out, const struct xt_match *match,
-      const void *matchinfo, int offset, unsigned int protoff, bool *hotdrop)
+static bool ah_mt(const struct sk_buff *skb, const struct xt_match_param *par)
 {
 	struct ip_auth_hdr _ahdr;
 	const struct ip_auth_hdr *ah;
-	const struct ipt_ah *ahinfo = matchinfo;
+	const struct ipt_ah *ahinfo = par->matchinfo;
 
 	/* Must not be a fragment. */
-	if (offset)
+	if (par->fragoff != 0)
 		return false;
 
-	ah = skb_header_pointer(skb, protoff,
-				sizeof(_ahdr), &_ahdr);
+	ah = skb_header_pointer(skb, par->thoff, sizeof(_ahdr), &_ahdr);
 	if (ah == NULL) {
 		/* We've been asked to examine this packet, and we
 		 * can't.  Hence, no choice but to drop.
 		 */
 		duprintf("Dropping evil AH tinygram.\n");
-		*hotdrop = true;
+		*par->hotdrop = true;
 		return 0;
 	}
 
@@ -65,13 +61,9 @@
 			 !!(ahinfo->invflags & IPT_AH_INV_SPI));
 }
 
-/* Called when user tries to insert an entry of this type. */
-static bool
-ah_mt_check(const char *tablename, const void *ip_void,
-            const struct xt_match *match, void *matchinfo,
-            unsigned int hook_mask)
+static bool ah_mt_check(const struct xt_mtchk_param *par)
 {
-	const struct ipt_ah *ahinfo = matchinfo;
+	const struct ipt_ah *ahinfo = par->matchinfo;
 
 	/* Must specify no unknown invflags */
 	if (ahinfo->invflags & ~IPT_AH_INV_MASK) {
@@ -83,7 +75,7 @@
 
 static struct xt_match ah_mt_reg __read_mostly = {
 	.name		= "ah",
-	.family		= AF_INET,
+	.family		= NFPROTO_IPV4,
 	.match		= ah_mt,
 	.matchsize	= sizeof(struct ipt_ah),
 	.proto		= IPPROTO_AH,
diff --git a/net/ipv4/netfilter/ipt_ecn.c b/net/ipv4/netfilter/ipt_ecn.c
index 749de82..6289b64 100644
--- a/net/ipv4/netfilter/ipt_ecn.c
+++ b/net/ipv4/netfilter/ipt_ecn.c
@@ -67,12 +67,9 @@
 	return true;
 }
 
-static bool
-ecn_mt(const struct sk_buff *skb, const struct net_device *in,
-       const struct net_device *out, const struct xt_match *match,
-       const void *matchinfo, int offset, unsigned int protoff, bool *hotdrop)
+static bool ecn_mt(const struct sk_buff *skb, const struct xt_match_param *par)
 {
-	const struct ipt_ecn_info *info = matchinfo;
+	const struct ipt_ecn_info *info = par->matchinfo;
 
 	if (info->operation & IPT_ECN_OP_MATCH_IP)
 		if (!match_ip(skb, info))
@@ -81,20 +78,17 @@
 	if (info->operation & (IPT_ECN_OP_MATCH_ECE|IPT_ECN_OP_MATCH_CWR)) {
 		if (ip_hdr(skb)->protocol != IPPROTO_TCP)
 			return false;
-		if (!match_tcp(skb, info, hotdrop))
+		if (!match_tcp(skb, info, par->hotdrop))
 			return false;
 	}
 
 	return true;
 }
 
-static bool
-ecn_mt_check(const char *tablename, const void *ip_void,
-             const struct xt_match *match, void *matchinfo,
-             unsigned int hook_mask)
+static bool ecn_mt_check(const struct xt_mtchk_param *par)
 {
-	const struct ipt_ecn_info *info = matchinfo;
-	const struct ipt_ip *ip = ip_void;
+	const struct ipt_ecn_info *info = par->matchinfo;
+	const struct ipt_ip *ip = par->entryinfo;
 
 	if (info->operation & IPT_ECN_OP_MATCH_MASK)
 		return false;
@@ -114,7 +108,7 @@
 
 static struct xt_match ecn_mt_reg __read_mostly = {
 	.name		= "ecn",
-	.family		= AF_INET,
+	.family		= NFPROTO_IPV4,
 	.match		= ecn_mt,
 	.matchsize	= sizeof(struct ipt_ecn_info),
 	.checkentry	= ecn_mt_check,
diff --git a/net/ipv4/netfilter/ipt_recent.c b/net/ipv4/netfilter/ipt_recent.c
deleted file mode 100644
index 3974d7c..0000000
--- a/net/ipv4/netfilter/ipt_recent.c
+++ /dev/null
@@ -1,501 +0,0 @@
-/*
- * Copyright (c) 2006 Patrick McHardy <kaber@trash.net>
- *
- * 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 is a replacement of the old ipt_recent module, which carried the
- * following copyright notice:
- *
- * Author: Stephen Frost <sfrost@snowman.net>
- * Copyright 2002-2003, Stephen Frost, 2.5.x port by laforge@netfilter.org
- */
-#include <linux/init.h>
-#include <linux/ip.h>
-#include <linux/moduleparam.h>
-#include <linux/proc_fs.h>
-#include <linux/seq_file.h>
-#include <linux/string.h>
-#include <linux/ctype.h>
-#include <linux/list.h>
-#include <linux/random.h>
-#include <linux/jhash.h>
-#include <linux/bitops.h>
-#include <linux/skbuff.h>
-#include <linux/inet.h>
-#include <net/net_namespace.h>
-
-#include <linux/netfilter/x_tables.h>
-#include <linux/netfilter_ipv4/ipt_recent.h>
-
-MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
-MODULE_DESCRIPTION("Xtables: \"recently-seen\" host matching for IPv4");
-MODULE_LICENSE("GPL");
-
-static unsigned int ip_list_tot = 100;
-static unsigned int ip_pkt_list_tot = 20;
-static unsigned int ip_list_hash_size = 0;
-static unsigned int ip_list_perms = 0644;
-static unsigned int ip_list_uid = 0;
-static unsigned int ip_list_gid = 0;
-module_param(ip_list_tot, uint, 0400);
-module_param(ip_pkt_list_tot, uint, 0400);
-module_param(ip_list_hash_size, uint, 0400);
-module_param(ip_list_perms, uint, 0400);
-module_param(ip_list_uid, uint, 0400);
-module_param(ip_list_gid, uint, 0400);
-MODULE_PARM_DESC(ip_list_tot, "number of IPs to remember per list");
-MODULE_PARM_DESC(ip_pkt_list_tot, "number of packets per IP to remember (max. 255)");
-MODULE_PARM_DESC(ip_list_hash_size, "size of hash table used to look up IPs");
-MODULE_PARM_DESC(ip_list_perms, "permissions on /proc/net/ipt_recent/* files");
-MODULE_PARM_DESC(ip_list_uid,"owner of /proc/net/ipt_recent/* files");
-MODULE_PARM_DESC(ip_list_gid,"owning group of /proc/net/ipt_recent/* files");
-
-struct recent_entry {
-	struct list_head	list;
-	struct list_head	lru_list;
-	__be32			addr;
-	u_int8_t		ttl;
-	u_int8_t		index;
-	u_int16_t		nstamps;
-	unsigned long		stamps[0];
-};
-
-struct recent_table {
-	struct list_head	list;
-	char			name[IPT_RECENT_NAME_LEN];
-#ifdef CONFIG_PROC_FS
-	struct proc_dir_entry	*proc;
-#endif
-	unsigned int		refcnt;
-	unsigned int		entries;
-	struct list_head	lru_list;
-	struct list_head	iphash[0];
-};
-
-static LIST_HEAD(tables);
-static DEFINE_SPINLOCK(recent_lock);
-static DEFINE_MUTEX(recent_mutex);
-
-#ifdef CONFIG_PROC_FS
-static struct proc_dir_entry	*proc_dir;
-static const struct file_operations	recent_fops;
-#endif
-
-static u_int32_t hash_rnd;
-static int hash_rnd_initted;
-
-static unsigned int recent_entry_hash(__be32 addr)
-{
-	if (!hash_rnd_initted) {
-		get_random_bytes(&hash_rnd, 4);
-		hash_rnd_initted = 1;
-	}
-	return jhash_1word((__force u32)addr, hash_rnd) & (ip_list_hash_size - 1);
-}
-
-static struct recent_entry *
-recent_entry_lookup(const struct recent_table *table, __be32 addr, u_int8_t ttl)
-{
-	struct recent_entry *e;
-	unsigned int h;
-
-	h = recent_entry_hash(addr);
-	list_for_each_entry(e, &table->iphash[h], list)
-		if (e->addr == addr && (ttl == e->ttl || !ttl || !e->ttl))
-			return e;
-	return NULL;
-}
-
-static void recent_entry_remove(struct recent_table *t, struct recent_entry *e)
-{
-	list_del(&e->list);
-	list_del(&e->lru_list);
-	kfree(e);
-	t->entries--;
-}
-
-static struct recent_entry *
-recent_entry_init(struct recent_table *t, __be32 addr, u_int8_t ttl)
-{
-	struct recent_entry *e;
-
-	if (t->entries >= ip_list_tot) {
-		e = list_entry(t->lru_list.next, struct recent_entry, lru_list);
-		recent_entry_remove(t, e);
-	}
-	e = kmalloc(sizeof(*e) + sizeof(e->stamps[0]) * ip_pkt_list_tot,
-		    GFP_ATOMIC);
-	if (e == NULL)
-		return NULL;
-	e->addr      = addr;
-	e->ttl       = ttl;
-	e->stamps[0] = jiffies;
-	e->nstamps   = 1;
-	e->index     = 1;
-	list_add_tail(&e->list, &t->iphash[recent_entry_hash(addr)]);
-	list_add_tail(&e->lru_list, &t->lru_list);
-	t->entries++;
-	return e;
-}
-
-static void recent_entry_update(struct recent_table *t, struct recent_entry *e)
-{
-	e->stamps[e->index++] = jiffies;
-	if (e->index > e->nstamps)
-		e->nstamps = e->index;
-	e->index %= ip_pkt_list_tot;
-	list_move_tail(&e->lru_list, &t->lru_list);
-}
-
-static struct recent_table *recent_table_lookup(const char *name)
-{
-	struct recent_table *t;
-
-	list_for_each_entry(t, &tables, list)
-		if (!strcmp(t->name, name))
-			return t;
-	return NULL;
-}
-
-static void recent_table_flush(struct recent_table *t)
-{
-	struct recent_entry *e, *next;
-	unsigned int i;
-
-	for (i = 0; i < ip_list_hash_size; i++)
-		list_for_each_entry_safe(e, next, &t->iphash[i], list)
-			recent_entry_remove(t, e);
-}
-
-static bool
-recent_mt(const struct sk_buff *skb, const struct net_device *in,
-          const struct net_device *out, const struct xt_match *match,
-          const void *matchinfo, int offset, unsigned int protoff,
-          bool *hotdrop)
-{
-	const struct ipt_recent_info *info = matchinfo;
-	struct recent_table *t;
-	struct recent_entry *e;
-	__be32 addr;
-	u_int8_t ttl;
-	bool ret = info->invert;
-
-	if (info->side == IPT_RECENT_DEST)
-		addr = ip_hdr(skb)->daddr;
-	else
-		addr = ip_hdr(skb)->saddr;
-
-	ttl = ip_hdr(skb)->ttl;
-	/* use TTL as seen before forwarding */
-	if (out && !skb->sk)
-		ttl++;
-
-	spin_lock_bh(&recent_lock);
-	t = recent_table_lookup(info->name);
-	e = recent_entry_lookup(t, addr,
-				info->check_set & IPT_RECENT_TTL ? ttl : 0);
-	if (e == NULL) {
-		if (!(info->check_set & IPT_RECENT_SET))
-			goto out;
-		e = recent_entry_init(t, addr, ttl);
-		if (e == NULL)
-			*hotdrop = true;
-		ret = !ret;
-		goto out;
-	}
-
-	if (info->check_set & IPT_RECENT_SET)
-		ret = !ret;
-	else if (info->check_set & IPT_RECENT_REMOVE) {
-		recent_entry_remove(t, e);
-		ret = !ret;
-	} else if (info->check_set & (IPT_RECENT_CHECK | IPT_RECENT_UPDATE)) {
-		unsigned long time = jiffies - info->seconds * HZ;
-		unsigned int i, hits = 0;
-
-		for (i = 0; i < e->nstamps; i++) {
-			if (info->seconds && time_after(time, e->stamps[i]))
-				continue;
-			if (++hits >= info->hit_count) {
-				ret = !ret;
-				break;
-			}
-		}
-	}
-
-	if (info->check_set & IPT_RECENT_SET ||
-	    (info->check_set & IPT_RECENT_UPDATE && ret)) {
-		recent_entry_update(t, e);
-		e->ttl = ttl;
-	}
-out:
-	spin_unlock_bh(&recent_lock);
-	return ret;
-}
-
-static bool
-recent_mt_check(const char *tablename, const void *ip,
-                const struct xt_match *match, void *matchinfo,
-                unsigned int hook_mask)
-{
-	const struct ipt_recent_info *info = matchinfo;
-	struct recent_table *t;
-	unsigned i;
-	bool ret = false;
-
-	if (hweight8(info->check_set &
-		     (IPT_RECENT_SET | IPT_RECENT_REMOVE |
-		      IPT_RECENT_CHECK | IPT_RECENT_UPDATE)) != 1)
-		return false;
-	if ((info->check_set & (IPT_RECENT_SET | IPT_RECENT_REMOVE)) &&
-	    (info->seconds || info->hit_count))
-		return false;
-	if (info->hit_count > ip_pkt_list_tot)
-		return false;
-	if (info->name[0] == '\0' ||
-	    strnlen(info->name, IPT_RECENT_NAME_LEN) == IPT_RECENT_NAME_LEN)
-		return false;
-
-	mutex_lock(&recent_mutex);
-	t = recent_table_lookup(info->name);
-	if (t != NULL) {
-		t->refcnt++;
-		ret = true;
-		goto out;
-	}
-
-	t = kzalloc(sizeof(*t) + sizeof(t->iphash[0]) * ip_list_hash_size,
-		    GFP_KERNEL);
-	if (t == NULL)
-		goto out;
-	t->refcnt = 1;
-	strcpy(t->name, info->name);
-	INIT_LIST_HEAD(&t->lru_list);
-	for (i = 0; i < ip_list_hash_size; i++)
-		INIT_LIST_HEAD(&t->iphash[i]);
-#ifdef CONFIG_PROC_FS
-	t->proc = proc_create(t->name, ip_list_perms, proc_dir, &recent_fops);
-	if (t->proc == NULL) {
-		kfree(t);
-		goto out;
-	}
-	t->proc->uid       = ip_list_uid;
-	t->proc->gid       = ip_list_gid;
-	t->proc->data      = t;
-#endif
-	spin_lock_bh(&recent_lock);
-	list_add_tail(&t->list, &tables);
-	spin_unlock_bh(&recent_lock);
-	ret = true;
-out:
-	mutex_unlock(&recent_mutex);
-	return ret;
-}
-
-static void recent_mt_destroy(const struct xt_match *match, void *matchinfo)
-{
-	const struct ipt_recent_info *info = matchinfo;
-	struct recent_table *t;
-
-	mutex_lock(&recent_mutex);
-	t = recent_table_lookup(info->name);
-	if (--t->refcnt == 0) {
-		spin_lock_bh(&recent_lock);
-		list_del(&t->list);
-		spin_unlock_bh(&recent_lock);
-#ifdef CONFIG_PROC_FS
-		remove_proc_entry(t->name, proc_dir);
-#endif
-		recent_table_flush(t);
-		kfree(t);
-	}
-	mutex_unlock(&recent_mutex);
-}
-
-#ifdef CONFIG_PROC_FS
-struct recent_iter_state {
-	struct recent_table	*table;
-	unsigned int		bucket;
-};
-
-static void *recent_seq_start(struct seq_file *seq, loff_t *pos)
-	__acquires(recent_lock)
-{
-	struct recent_iter_state *st = seq->private;
-	const struct recent_table *t = st->table;
-	struct recent_entry *e;
-	loff_t p = *pos;
-
-	spin_lock_bh(&recent_lock);
-
-	for (st->bucket = 0; st->bucket < ip_list_hash_size; st->bucket++)
-		list_for_each_entry(e, &t->iphash[st->bucket], list)
-			if (p-- == 0)
-				return e;
-	return NULL;
-}
-
-static void *recent_seq_next(struct seq_file *seq, void *v, loff_t *pos)
-{
-	struct recent_iter_state *st = seq->private;
-	const struct recent_table *t = st->table;
-	struct recent_entry *e = v;
-	struct list_head *head = e->list.next;
-
-	while (head == &t->iphash[st->bucket]) {
-		if (++st->bucket >= ip_list_hash_size)
-			return NULL;
-		head = t->iphash[st->bucket].next;
-	}
-	(*pos)++;
-	return list_entry(head, struct recent_entry, list);
-}
-
-static void recent_seq_stop(struct seq_file *s, void *v)
-	__releases(recent_lock)
-{
-	spin_unlock_bh(&recent_lock);
-}
-
-static int recent_seq_show(struct seq_file *seq, void *v)
-{
-	const struct recent_entry *e = v;
-	unsigned int i;
-
-	i = (e->index - 1) % ip_pkt_list_tot;
-	seq_printf(seq, "src=%u.%u.%u.%u ttl: %u last_seen: %lu oldest_pkt: %u",
-		   NIPQUAD(e->addr), e->ttl, e->stamps[i], e->index);
-	for (i = 0; i < e->nstamps; i++)
-		seq_printf(seq, "%s %lu", i ? "," : "", e->stamps[i]);
-	seq_printf(seq, "\n");
-	return 0;
-}
-
-static const struct seq_operations recent_seq_ops = {
-	.start		= recent_seq_start,
-	.next		= recent_seq_next,
-	.stop		= recent_seq_stop,
-	.show		= recent_seq_show,
-};
-
-static int recent_seq_open(struct inode *inode, struct file *file)
-{
-	struct proc_dir_entry *pde = PDE(inode);
-	struct recent_iter_state *st;
-
-	st = __seq_open_private(file, &recent_seq_ops, sizeof(*st));
-	if (st == NULL)
-		return -ENOMEM;
-
-	st->table    = pde->data;
-	return 0;
-}
-
-static ssize_t recent_proc_write(struct file *file, const char __user *input,
-				 size_t size, loff_t *loff)
-{
-	const struct proc_dir_entry *pde = PDE(file->f_path.dentry->d_inode);
-	struct recent_table *t = pde->data;
-	struct recent_entry *e;
-	char buf[sizeof("+255.255.255.255")], *c = buf;
-	__be32 addr;
-	int add;
-
-	if (size > sizeof(buf))
-		size = sizeof(buf);
-	if (copy_from_user(buf, input, size))
-		return -EFAULT;
-	while (isspace(*c))
-		c++;
-
-	if (size - (c - buf) < 5)
-		return c - buf;
-	if (!strncmp(c, "clear", 5)) {
-		c += 5;
-		spin_lock_bh(&recent_lock);
-		recent_table_flush(t);
-		spin_unlock_bh(&recent_lock);
-		return c - buf;
-	}
-
-	switch (*c) {
-	case '-':
-		add = 0;
-		c++;
-		break;
-	case '+':
-		c++;
-	default:
-		add = 1;
-		break;
-	}
-	addr = in_aton(c);
-
-	spin_lock_bh(&recent_lock);
-	e = recent_entry_lookup(t, addr, 0);
-	if (e == NULL) {
-		if (add)
-			recent_entry_init(t, addr, 0);
-	} else {
-		if (add)
-			recent_entry_update(t, e);
-		else
-			recent_entry_remove(t, e);
-	}
-	spin_unlock_bh(&recent_lock);
-	return size;
-}
-
-static const struct file_operations recent_fops = {
-	.open		= recent_seq_open,
-	.read		= seq_read,
-	.write		= recent_proc_write,
-	.release	= seq_release_private,
-	.owner		= THIS_MODULE,
-};
-#endif /* CONFIG_PROC_FS */
-
-static struct xt_match recent_mt_reg __read_mostly = {
-	.name		= "recent",
-	.family		= AF_INET,
-	.match		= recent_mt,
-	.matchsize	= sizeof(struct ipt_recent_info),
-	.checkentry	= recent_mt_check,
-	.destroy	= recent_mt_destroy,
-	.me		= THIS_MODULE,
-};
-
-static int __init recent_mt_init(void)
-{
-	int err;
-
-	if (!ip_list_tot || !ip_pkt_list_tot || ip_pkt_list_tot > 255)
-		return -EINVAL;
-	ip_list_hash_size = 1 << fls(ip_list_tot);
-
-	err = xt_register_match(&recent_mt_reg);
-#ifdef CONFIG_PROC_FS
-	if (err)
-		return err;
-	proc_dir = proc_mkdir("ipt_recent", init_net.proc_net);
-	if (proc_dir == NULL) {
-		xt_unregister_match(&recent_mt_reg);
-		err = -ENOMEM;
-	}
-#endif
-	return err;
-}
-
-static void __exit recent_mt_exit(void)
-{
-	BUG_ON(!list_empty(&tables));
-	xt_unregister_match(&recent_mt_reg);
-#ifdef CONFIG_PROC_FS
-	remove_proc_entry("ipt_recent", init_net.proc_net);
-#endif
-}
-
-module_init(recent_mt_init);
-module_exit(recent_mt_exit);
diff --git a/net/ipv4/netfilter/ipt_ttl.c b/net/ipv4/netfilter/ipt_ttl.c
index e0b8cae..297f1cb 100644
--- a/net/ipv4/netfilter/ipt_ttl.c
+++ b/net/ipv4/netfilter/ipt_ttl.c
@@ -18,12 +18,9 @@
 MODULE_DESCRIPTION("Xtables: IPv4 TTL field match");
 MODULE_LICENSE("GPL");
 
-static bool
-ttl_mt(const struct sk_buff *skb, const struct net_device *in,
-       const struct net_device *out, const struct xt_match *match,
-       const void *matchinfo, int offset, unsigned int protoff, bool *hotdrop)
+static bool ttl_mt(const struct sk_buff *skb, const struct xt_match_param *par)
 {
-	const struct ipt_ttl_info *info = matchinfo;
+	const struct ipt_ttl_info *info = par->matchinfo;
 	const u8 ttl = ip_hdr(skb)->ttl;
 
 	switch (info->mode) {
@@ -46,7 +43,7 @@
 
 static struct xt_match ttl_mt_reg __read_mostly = {
 	.name		= "ttl",
-	.family		= AF_INET,
+	.family		= NFPROTO_IPV4,
 	.match		= ttl_mt,
 	.matchsize	= sizeof(struct ipt_ttl_info),
 	.me		= THIS_MODULE,
diff --git a/net/ipv4/netfilter/iptable_filter.c b/net/ipv4/netfilter/iptable_filter.c
index 1ea677d..c922431 100644
--- a/net/ipv4/netfilter/iptable_filter.c
+++ b/net/ipv4/netfilter/iptable_filter.c
@@ -70,7 +70,7 @@
 		  int (*okfn)(struct sk_buff *))
 {
 	return ipt_do_table(skb, hook, in, out,
-			    nf_local_in_net(in, out)->ipv4.iptable_filter);
+			    dev_net(in)->ipv4.iptable_filter);
 }
 
 static unsigned int
@@ -81,7 +81,7 @@
 	 int (*okfn)(struct sk_buff *))
 {
 	return ipt_do_table(skb, hook, in, out,
-			    nf_forward_net(in, out)->ipv4.iptable_filter);
+			    dev_net(in)->ipv4.iptable_filter);
 }
 
 static unsigned int
@@ -101,7 +101,7 @@
 	}
 
 	return ipt_do_table(skb, hook, in, out,
-			    nf_local_out_net(in, out)->ipv4.iptable_filter);
+			    dev_net(out)->ipv4.iptable_filter);
 }
 
 static struct nf_hook_ops ipt_ops[] __read_mostly = {
diff --git a/net/ipv4/netfilter/iptable_mangle.c b/net/ipv4/netfilter/iptable_mangle.c
index da59182..69f2c42 100644
--- a/net/ipv4/netfilter/iptable_mangle.c
+++ b/net/ipv4/netfilter/iptable_mangle.c
@@ -81,7 +81,7 @@
 		     int (*okfn)(struct sk_buff *))
 {
 	return ipt_do_table(skb, hook, in, out,
-			    nf_pre_routing_net(in, out)->ipv4.iptable_mangle);
+			    dev_net(in)->ipv4.iptable_mangle);
 }
 
 static unsigned int
@@ -92,7 +92,7 @@
 		      int (*okfn)(struct sk_buff *))
 {
 	return ipt_do_table(skb, hook, in, out,
-			    nf_post_routing_net(in, out)->ipv4.iptable_mangle);
+			    dev_net(out)->ipv4.iptable_mangle);
 }
 
 static unsigned int
@@ -103,7 +103,7 @@
 		  int (*okfn)(struct sk_buff *))
 {
 	return ipt_do_table(skb, hook, in, out,
-			    nf_local_in_net(in, out)->ipv4.iptable_mangle);
+			    dev_net(in)->ipv4.iptable_mangle);
 }
 
 static unsigned int
@@ -114,7 +114,7 @@
 	 int (*okfn)(struct sk_buff *))
 {
 	return ipt_do_table(skb, hook, in, out,
-			    nf_forward_net(in, out)->ipv4.iptable_mangle);
+			    dev_net(in)->ipv4.iptable_mangle);
 }
 
 static unsigned int
@@ -147,7 +147,7 @@
 	tos = iph->tos;
 
 	ret = ipt_do_table(skb, hook, in, out,
-			   nf_local_out_net(in, out)->ipv4.iptable_mangle);
+			   dev_net(out)->ipv4.iptable_mangle);
 	/* Reroute for ANY change. */
 	if (ret != NF_DROP && ret != NF_STOLEN && ret != NF_QUEUE) {
 		iph = ip_hdr(skb);
diff --git a/net/ipv4/netfilter/iptable_raw.c b/net/ipv4/netfilter/iptable_raw.c
index fddce77..8faebfe 100644
--- a/net/ipv4/netfilter/iptable_raw.c
+++ b/net/ipv4/netfilter/iptable_raw.c
@@ -53,7 +53,7 @@
 	 int (*okfn)(struct sk_buff *))
 {
 	return ipt_do_table(skb, hook, in, out,
-			    nf_pre_routing_net(in, out)->ipv4.iptable_raw);
+			    dev_net(in)->ipv4.iptable_raw);
 }
 
 static unsigned int
@@ -72,7 +72,7 @@
 		return NF_ACCEPT;
 	}
 	return ipt_do_table(skb, hook, in, out,
-			    nf_local_out_net(in, out)->ipv4.iptable_raw);
+			    dev_net(out)->ipv4.iptable_raw);
 }
 
 /* 'raw' is the very first table. */
diff --git a/net/ipv4/netfilter/iptable_security.c b/net/ipv4/netfilter/iptable_security.c
index db6d312..36f3be3 100644
--- a/net/ipv4/netfilter/iptable_security.c
+++ b/net/ipv4/netfilter/iptable_security.c
@@ -73,7 +73,7 @@
 		  int (*okfn)(struct sk_buff *))
 {
 	return ipt_do_table(skb, hook, in, out,
-			    nf_local_in_net(in, out)->ipv4.iptable_security);
+			    dev_net(in)->ipv4.iptable_security);
 }
 
 static unsigned int
@@ -84,7 +84,7 @@
 		 int (*okfn)(struct sk_buff *))
 {
 	return ipt_do_table(skb, hook, in, out,
-			    nf_forward_net(in, out)->ipv4.iptable_security);
+			    dev_net(in)->ipv4.iptable_security);
 }
 
 static unsigned int
@@ -103,7 +103,7 @@
 		return NF_ACCEPT;
 	}
 	return ipt_do_table(skb, hook, in, out,
-			    nf_local_out_net(in, out)->ipv4.iptable_security);
+			    dev_net(out)->ipv4.iptable_security);
 }
 
 static struct nf_hook_ops ipt_ops[] __read_mostly = {
diff --git a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
index 5a955c4..4a7c352 100644
--- a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
+++ b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
@@ -1,3 +1,4 @@
+
 /* (C) 1999-2001 Paul `Rusty' Russell
  * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org>
  *
@@ -24,6 +25,7 @@
 #include <net/netfilter/nf_conntrack_core.h>
 #include <net/netfilter/ipv4/nf_conntrack_ipv4.h>
 #include <net/netfilter/nf_nat_helper.h>
+#include <net/netfilter/ipv4/nf_defrag_ipv4.h>
 
 int (*nf_nat_seq_adjust_hook)(struct sk_buff *skb,
 			      struct nf_conn *ct,
@@ -63,23 +65,6 @@
 			  NIPQUAD(tuple->dst.u3.ip));
 }
 
-/* Returns new sk_buff, or NULL */
-static int nf_ct_ipv4_gather_frags(struct sk_buff *skb, u_int32_t user)
-{
-	int err;
-
-	skb_orphan(skb);
-
-	local_bh_disable();
-	err = ip_defrag(skb, user);
-	local_bh_enable();
-
-	if (!err)
-		ip_send_check(ip_hdr(skb));
-
-	return err;
-}
-
 static int ipv4_get_l4proto(const struct sk_buff *skb, unsigned int nhoff,
 			    unsigned int *dataoff, u_int8_t *protonum)
 {
@@ -144,35 +129,13 @@
 	return nf_conntrack_confirm(skb);
 }
 
-static unsigned int ipv4_conntrack_defrag(unsigned int hooknum,
-					  struct sk_buff *skb,
-					  const struct net_device *in,
-					  const struct net_device *out,
-					  int (*okfn)(struct sk_buff *))
-{
-	/* Previously seen (loopback)?  Ignore.  Do this before
-	   fragment check. */
-	if (skb->nfct)
-		return NF_ACCEPT;
-
-	/* Gather fragments. */
-	if (ip_hdr(skb)->frag_off & htons(IP_MF | IP_OFFSET)) {
-		if (nf_ct_ipv4_gather_frags(skb,
-					    hooknum == NF_INET_PRE_ROUTING ?
-					    IP_DEFRAG_CONNTRACK_IN :
-					    IP_DEFRAG_CONNTRACK_OUT))
-			return NF_STOLEN;
-	}
-	return NF_ACCEPT;
-}
-
 static unsigned int ipv4_conntrack_in(unsigned int hooknum,
 				      struct sk_buff *skb,
 				      const struct net_device *in,
 				      const struct net_device *out,
 				      int (*okfn)(struct sk_buff *))
 {
-	return nf_conntrack_in(PF_INET, hooknum, skb);
+	return nf_conntrack_in(dev_net(in), PF_INET, hooknum, skb);
 }
 
 static unsigned int ipv4_conntrack_local(unsigned int hooknum,
@@ -188,20 +151,13 @@
 			printk("ipt_hook: happy cracking.\n");
 		return NF_ACCEPT;
 	}
-	return nf_conntrack_in(PF_INET, hooknum, skb);
+	return nf_conntrack_in(dev_net(out), PF_INET, hooknum, skb);
 }
 
 /* Connection tracking may drop packets, but never alters them, so
    make it the first hook. */
 static struct nf_hook_ops ipv4_conntrack_ops[] __read_mostly = {
 	{
-		.hook		= ipv4_conntrack_defrag,
-		.owner		= THIS_MODULE,
-		.pf		= PF_INET,
-		.hooknum	= NF_INET_PRE_ROUTING,
-		.priority	= NF_IP_PRI_CONNTRACK_DEFRAG,
-	},
-	{
 		.hook		= ipv4_conntrack_in,
 		.owner		= THIS_MODULE,
 		.pf		= PF_INET,
@@ -209,13 +165,6 @@
 		.priority	= NF_IP_PRI_CONNTRACK,
 	},
 	{
-		.hook           = ipv4_conntrack_defrag,
-		.owner          = THIS_MODULE,
-		.pf             = PF_INET,
-		.hooknum        = NF_INET_LOCAL_OUT,
-		.priority       = NF_IP_PRI_CONNTRACK_DEFRAG,
-	},
-	{
 		.hook		= ipv4_conntrack_local,
 		.owner		= THIS_MODULE,
 		.pf		= PF_INET,
@@ -254,7 +203,7 @@
 	{
 		.ctl_name	= NET_IPV4_NF_CONNTRACK_COUNT,
 		.procname	= "ip_conntrack_count",
-		.data		= &nf_conntrack_count,
+		.data		= &init_net.ct.count,
 		.maxlen		= sizeof(int),
 		.mode		= 0444,
 		.proc_handler	= &proc_dointvec,
@@ -270,7 +219,7 @@
 	{
 		.ctl_name	= NET_IPV4_NF_CONNTRACK_CHECKSUM,
 		.procname	= "ip_conntrack_checksum",
-		.data		= &nf_conntrack_checksum,
+		.data		= &init_net.ct.sysctl_checksum,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
 		.proc_handler	= &proc_dointvec,
@@ -278,7 +227,7 @@
 	{
 		.ctl_name	= NET_IPV4_NF_CONNTRACK_LOG_INVALID,
 		.procname	= "ip_conntrack_log_invalid",
-		.data		= &nf_ct_log_invalid,
+		.data		= &init_net.ct.sysctl_log_invalid,
 		.maxlen		= sizeof(unsigned int),
 		.mode		= 0644,
 		.proc_handler	= &proc_dointvec_minmax,
@@ -323,7 +272,7 @@
 		return -EINVAL;
 	}
 
-	h = nf_conntrack_find_get(&tuple);
+	h = nf_conntrack_find_get(sock_net(sk), &tuple);
 	if (h) {
 		struct sockaddr_in sin;
 		struct nf_conn *ct = nf_ct_tuplehash_to_ctrack(h);
@@ -422,6 +371,7 @@
 	int ret = 0;
 
 	need_conntrack();
+	nf_defrag_ipv4_enable();
 
 	ret = nf_register_sockopt(&so_getorigdst);
 	if (ret < 0) {
diff --git a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4_compat.c b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4_compat.c
index 3a02072..313ebf0 100644
--- a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4_compat.c
+++ b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4_compat.c
@@ -21,18 +21,20 @@
 #include <net/netfilter/nf_conntrack_acct.h>
 
 struct ct_iter_state {
+	struct seq_net_private p;
 	unsigned int bucket;
 };
 
 static struct hlist_node *ct_get_first(struct seq_file *seq)
 {
+	struct net *net = seq_file_net(seq);
 	struct ct_iter_state *st = seq->private;
 	struct hlist_node *n;
 
 	for (st->bucket = 0;
 	     st->bucket < nf_conntrack_htable_size;
 	     st->bucket++) {
-		n = rcu_dereference(nf_conntrack_hash[st->bucket].first);
+		n = rcu_dereference(net->ct.hash[st->bucket].first);
 		if (n)
 			return n;
 	}
@@ -42,13 +44,14 @@
 static struct hlist_node *ct_get_next(struct seq_file *seq,
 				      struct hlist_node *head)
 {
+	struct net *net = seq_file_net(seq);
 	struct ct_iter_state *st = seq->private;
 
 	head = rcu_dereference(head->next);
 	while (head == NULL) {
 		if (++st->bucket >= nf_conntrack_htable_size)
 			return NULL;
-		head = rcu_dereference(nf_conntrack_hash[st->bucket].first);
+		head = rcu_dereference(net->ct.hash[st->bucket].first);
 	}
 	return head;
 }
@@ -158,8 +161,8 @@
 
 static int ct_open(struct inode *inode, struct file *file)
 {
-	return seq_open_private(file, &ct_seq_ops,
-			sizeof(struct ct_iter_state));
+	return seq_open_net(inode, file, &ct_seq_ops,
+			    sizeof(struct ct_iter_state));
 }
 
 static const struct file_operations ct_file_ops = {
@@ -167,21 +170,23 @@
 	.open    = ct_open,
 	.read    = seq_read,
 	.llseek  = seq_lseek,
-	.release = seq_release_private,
+	.release = seq_release_net,
 };
 
 /* expects */
 struct ct_expect_iter_state {
+	struct seq_net_private p;
 	unsigned int bucket;
 };
 
 static struct hlist_node *ct_expect_get_first(struct seq_file *seq)
 {
+	struct net *net = seq_file_net(seq);
 	struct ct_expect_iter_state *st = seq->private;
 	struct hlist_node *n;
 
 	for (st->bucket = 0; st->bucket < nf_ct_expect_hsize; st->bucket++) {
-		n = rcu_dereference(nf_ct_expect_hash[st->bucket].first);
+		n = rcu_dereference(net->ct.expect_hash[st->bucket].first);
 		if (n)
 			return n;
 	}
@@ -191,13 +196,14 @@
 static struct hlist_node *ct_expect_get_next(struct seq_file *seq,
 					     struct hlist_node *head)
 {
+	struct net *net = seq_file_net(seq);
 	struct ct_expect_iter_state *st = seq->private;
 
 	head = rcu_dereference(head->next);
 	while (head == NULL) {
 		if (++st->bucket >= nf_ct_expect_hsize)
 			return NULL;
-		head = rcu_dereference(nf_ct_expect_hash[st->bucket].first);
+		head = rcu_dereference(net->ct.expect_hash[st->bucket].first);
 	}
 	return head;
 }
@@ -265,8 +271,8 @@
 
 static int exp_open(struct inode *inode, struct file *file)
 {
-	return seq_open_private(file, &exp_seq_ops,
-			sizeof(struct ct_expect_iter_state));
+	return seq_open_net(inode, file, &exp_seq_ops,
+			    sizeof(struct ct_expect_iter_state));
 }
 
 static const struct file_operations ip_exp_file_ops = {
@@ -274,11 +280,12 @@
 	.open    = exp_open,
 	.read    = seq_read,
 	.llseek  = seq_lseek,
-	.release = seq_release_private,
+	.release = seq_release_net,
 };
 
 static void *ct_cpu_seq_start(struct seq_file *seq, loff_t *pos)
 {
+	struct net *net = seq_file_net(seq);
 	int cpu;
 
 	if (*pos == 0)
@@ -288,7 +295,7 @@
 		if (!cpu_possible(cpu))
 			continue;
 		*pos = cpu+1;
-		return &per_cpu(nf_conntrack_stat, cpu);
+		return per_cpu_ptr(net->ct.stat, cpu);
 	}
 
 	return NULL;
@@ -296,13 +303,14 @@
 
 static void *ct_cpu_seq_next(struct seq_file *seq, void *v, loff_t *pos)
 {
+	struct net *net = seq_file_net(seq);
 	int cpu;
 
 	for (cpu = *pos; cpu < NR_CPUS; ++cpu) {
 		if (!cpu_possible(cpu))
 			continue;
 		*pos = cpu+1;
-		return &per_cpu(nf_conntrack_stat, cpu);
+		return per_cpu_ptr(net->ct.stat, cpu);
 	}
 
 	return NULL;
@@ -314,7 +322,8 @@
 
 static int ct_cpu_seq_show(struct seq_file *seq, void *v)
 {
-	unsigned int nr_conntracks = atomic_read(&nf_conntrack_count);
+	struct net *net = seq_file_net(seq);
+	unsigned int nr_conntracks = atomic_read(&net->ct.count);
 	const struct ip_conntrack_stat *st = v;
 
 	if (v == SEQ_START_TOKEN) {
@@ -354,7 +363,8 @@
 
 static int ct_cpu_seq_open(struct inode *inode, struct file *file)
 {
-	return seq_open(file, &ct_cpu_seq_ops);
+	return seq_open_net(inode, file, &ct_cpu_seq_ops,
+			    sizeof(struct seq_net_private));
 }
 
 static const struct file_operations ct_cpu_seq_fops = {
@@ -362,39 +372,54 @@
 	.open    = ct_cpu_seq_open,
 	.read    = seq_read,
 	.llseek  = seq_lseek,
-	.release = seq_release,
+	.release = seq_release_net,
 };
 
-int __init nf_conntrack_ipv4_compat_init(void)
+static int __net_init ip_conntrack_net_init(struct net *net)
 {
 	struct proc_dir_entry *proc, *proc_exp, *proc_stat;
 
-	proc = proc_net_fops_create(&init_net, "ip_conntrack", 0440, &ct_file_ops);
+	proc = proc_net_fops_create(net, "ip_conntrack", 0440, &ct_file_ops);
 	if (!proc)
 		goto err1;
 
-	proc_exp = proc_net_fops_create(&init_net, "ip_conntrack_expect", 0440,
+	proc_exp = proc_net_fops_create(net, "ip_conntrack_expect", 0440,
 					&ip_exp_file_ops);
 	if (!proc_exp)
 		goto err2;
 
 	proc_stat = proc_create("ip_conntrack", S_IRUGO,
-				init_net.proc_net_stat, &ct_cpu_seq_fops);
+				net->proc_net_stat, &ct_cpu_seq_fops);
 	if (!proc_stat)
 		goto err3;
 	return 0;
 
 err3:
-	proc_net_remove(&init_net, "ip_conntrack_expect");
+	proc_net_remove(net, "ip_conntrack_expect");
 err2:
-	proc_net_remove(&init_net, "ip_conntrack");
+	proc_net_remove(net, "ip_conntrack");
 err1:
 	return -ENOMEM;
 }
 
+static void __net_exit ip_conntrack_net_exit(struct net *net)
+{
+	remove_proc_entry("ip_conntrack", net->proc_net_stat);
+	proc_net_remove(net, "ip_conntrack_expect");
+	proc_net_remove(net, "ip_conntrack");
+}
+
+static struct pernet_operations ip_conntrack_net_ops = {
+	.init = ip_conntrack_net_init,
+	.exit = ip_conntrack_net_exit,
+};
+
+int __init nf_conntrack_ipv4_compat_init(void)
+{
+	return register_pernet_subsys(&ip_conntrack_net_ops);
+}
+
 void __exit nf_conntrack_ipv4_compat_fini(void)
 {
-	remove_proc_entry("ip_conntrack", init_net.proc_net_stat);
-	proc_net_remove(&init_net, "ip_conntrack_expect");
-	proc_net_remove(&init_net, "ip_conntrack");
+	unregister_pernet_subsys(&ip_conntrack_net_ops);
 }
diff --git a/net/ipv4/netfilter/nf_conntrack_proto_icmp.c b/net/ipv4/netfilter/nf_conntrack_proto_icmp.c
index 9779104..4e88792 100644
--- a/net/ipv4/netfilter/nf_conntrack_proto_icmp.c
+++ b/net/ipv4/netfilter/nf_conntrack_proto_icmp.c
@@ -79,7 +79,7 @@
 		       const struct sk_buff *skb,
 		       unsigned int dataoff,
 		       enum ip_conntrack_info ctinfo,
-		       int pf,
+		       u_int8_t pf,
 		       unsigned int hooknum)
 {
 	/* Try to delete connection immediately after all replies:
@@ -91,7 +91,7 @@
 			nf_ct_kill_acct(ct, ctinfo, skb);
 	} else {
 		atomic_inc(&ct->proto.icmp.count);
-		nf_conntrack_event_cache(IPCT_PROTOINFO_VOLATILE, skb);
+		nf_conntrack_event_cache(IPCT_PROTOINFO_VOLATILE, ct);
 		nf_ct_refresh_acct(ct, ctinfo, skb, nf_ct_icmp_timeout);
 	}
 
@@ -123,7 +123,7 @@
 
 /* Returns conntrack if it dealt with ICMP, and filled in skb fields */
 static int
-icmp_error_message(struct sk_buff *skb,
+icmp_error_message(struct net *net, struct sk_buff *skb,
 		 enum ip_conntrack_info *ctinfo,
 		 unsigned int hooknum)
 {
@@ -155,7 +155,7 @@
 
 	*ctinfo = IP_CT_RELATED;
 
-	h = nf_conntrack_find_get(&innertuple);
+	h = nf_conntrack_find_get(net, &innertuple);
 	if (!h) {
 		pr_debug("icmp_error_message: no match\n");
 		return -NF_ACCEPT;
@@ -172,8 +172,8 @@
 
 /* Small and modified version of icmp_rcv */
 static int
-icmp_error(struct sk_buff *skb, unsigned int dataoff,
-	   enum ip_conntrack_info *ctinfo, int pf, unsigned int hooknum)
+icmp_error(struct net *net, struct sk_buff *skb, unsigned int dataoff,
+	   enum ip_conntrack_info *ctinfo, u_int8_t pf, unsigned int hooknum)
 {
 	const struct icmphdr *icmph;
 	struct icmphdr _ih;
@@ -181,16 +181,16 @@
 	/* Not enough header? */
 	icmph = skb_header_pointer(skb, ip_hdrlen(skb), sizeof(_ih), &_ih);
 	if (icmph == NULL) {
-		if (LOG_INVALID(IPPROTO_ICMP))
+		if (LOG_INVALID(net, IPPROTO_ICMP))
 			nf_log_packet(PF_INET, 0, skb, NULL, NULL, NULL,
 				      "nf_ct_icmp: short packet ");
 		return -NF_ACCEPT;
 	}
 
 	/* See ip_conntrack_proto_tcp.c */
-	if (nf_conntrack_checksum && hooknum == NF_INET_PRE_ROUTING &&
+	if (net->ct.sysctl_checksum && hooknum == NF_INET_PRE_ROUTING &&
 	    nf_ip_checksum(skb, hooknum, dataoff, 0)) {
-		if (LOG_INVALID(IPPROTO_ICMP))
+		if (LOG_INVALID(net, IPPROTO_ICMP))
 			nf_log_packet(PF_INET, 0, skb, NULL, NULL, NULL,
 				      "nf_ct_icmp: bad HW ICMP checksum ");
 		return -NF_ACCEPT;
@@ -203,7 +203,7 @@
 	 *		  discarded.
 	 */
 	if (icmph->type > NR_ICMP_TYPES) {
-		if (LOG_INVALID(IPPROTO_ICMP))
+		if (LOG_INVALID(net, IPPROTO_ICMP))
 			nf_log_packet(PF_INET, 0, skb, NULL, NULL, NULL,
 				      "nf_ct_icmp: invalid ICMP type ");
 		return -NF_ACCEPT;
@@ -217,7 +217,7 @@
 	    && icmph->type != ICMP_REDIRECT)
 		return NF_ACCEPT;
 
-	return icmp_error_message(skb, ctinfo, hooknum);
+	return icmp_error_message(net, skb, ctinfo, hooknum);
 }
 
 #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE)
diff --git a/net/ipv4/netfilter/nf_defrag_ipv4.c b/net/ipv4/netfilter/nf_defrag_ipv4.c
new file mode 100644
index 0000000..aa2c50a
--- /dev/null
+++ b/net/ipv4/netfilter/nf_defrag_ipv4.c
@@ -0,0 +1,96 @@
+/* (C) 1999-2001 Paul `Rusty' Russell
+ * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org>
+ *
+ * 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/types.h>
+#include <linux/ip.h>
+#include <linux/netfilter.h>
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <net/route.h>
+#include <net/ip.h>
+
+#include <linux/netfilter_ipv4.h>
+#include <net/netfilter/ipv4/nf_defrag_ipv4.h>
+
+/* Returns new sk_buff, or NULL */
+static int nf_ct_ipv4_gather_frags(struct sk_buff *skb, u_int32_t user)
+{
+	int err;
+
+	skb_orphan(skb);
+
+	local_bh_disable();
+	err = ip_defrag(skb, user);
+	local_bh_enable();
+
+	if (!err)
+		ip_send_check(ip_hdr(skb));
+
+	return err;
+}
+
+static unsigned int ipv4_conntrack_defrag(unsigned int hooknum,
+					  struct sk_buff *skb,
+					  const struct net_device *in,
+					  const struct net_device *out,
+					  int (*okfn)(struct sk_buff *))
+{
+#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
+	/* Previously seen (loopback)?  Ignore.  Do this before
+	   fragment check. */
+	if (skb->nfct)
+		return NF_ACCEPT;
+#endif
+
+	/* Gather fragments. */
+	if (ip_hdr(skb)->frag_off & htons(IP_MF | IP_OFFSET)) {
+		if (nf_ct_ipv4_gather_frags(skb,
+					    hooknum == NF_INET_PRE_ROUTING ?
+					    IP_DEFRAG_CONNTRACK_IN :
+					    IP_DEFRAG_CONNTRACK_OUT))
+			return NF_STOLEN;
+	}
+	return NF_ACCEPT;
+}
+
+static struct nf_hook_ops ipv4_defrag_ops[] = {
+	{
+		.hook		= ipv4_conntrack_defrag,
+		.owner		= THIS_MODULE,
+		.pf		= PF_INET,
+		.hooknum	= NF_INET_PRE_ROUTING,
+		.priority	= NF_IP_PRI_CONNTRACK_DEFRAG,
+	},
+	{
+		.hook           = ipv4_conntrack_defrag,
+		.owner          = THIS_MODULE,
+		.pf             = PF_INET,
+		.hooknum        = NF_INET_LOCAL_OUT,
+		.priority       = NF_IP_PRI_CONNTRACK_DEFRAG,
+	},
+};
+
+static int __init nf_defrag_init(void)
+{
+	return nf_register_hooks(ipv4_defrag_ops, ARRAY_SIZE(ipv4_defrag_ops));
+}
+
+static void __exit nf_defrag_fini(void)
+{
+	nf_unregister_hooks(ipv4_defrag_ops, ARRAY_SIZE(ipv4_defrag_ops));
+}
+
+void nf_defrag_ipv4_enable(void)
+{
+}
+EXPORT_SYMBOL_GPL(nf_defrag_ipv4_enable);
+
+module_init(nf_defrag_init);
+module_exit(nf_defrag_fini);
+
+MODULE_LICENSE("GPL");
diff --git a/net/ipv4/netfilter/nf_nat_core.c b/net/ipv4/netfilter/nf_nat_core.c
index 6c6a3cb..2ac9eaf 100644
--- a/net/ipv4/netfilter/nf_nat_core.c
+++ b/net/ipv4/netfilter/nf_nat_core.c
@@ -37,9 +37,6 @@
 
 /* Calculated at init based on memory size */
 static unsigned int nf_nat_htable_size __read_mostly;
-static int nf_nat_vmalloced;
-
-static struct hlist_head *bysource __read_mostly;
 
 #define MAX_IP_NAT_PROTO 256
 static const struct nf_nat_protocol *nf_nat_protos[MAX_IP_NAT_PROTO]
@@ -145,7 +142,8 @@
 
 /* Only called for SRC manip */
 static int
-find_appropriate_src(const struct nf_conntrack_tuple *tuple,
+find_appropriate_src(struct net *net,
+		     const struct nf_conntrack_tuple *tuple,
 		     struct nf_conntrack_tuple *result,
 		     const struct nf_nat_range *range)
 {
@@ -155,7 +153,7 @@
 	const struct hlist_node *n;
 
 	rcu_read_lock();
-	hlist_for_each_entry_rcu(nat, n, &bysource[h], bysource) {
+	hlist_for_each_entry_rcu(nat, n, &net->ipv4.nat_bysource[h], bysource) {
 		ct = nat->ct;
 		if (same_src(ct, tuple)) {
 			/* Copy source part from reply tuple. */
@@ -231,6 +229,7 @@
 		 struct nf_conn *ct,
 		 enum nf_nat_manip_type maniptype)
 {
+	struct net *net = nf_ct_net(ct);
 	const struct nf_nat_protocol *proto;
 
 	/* 1) If this srcip/proto/src-proto-part is currently mapped,
@@ -242,7 +241,7 @@
 	   manips not an issue.  */
 	if (maniptype == IP_NAT_MANIP_SRC &&
 	    !(range->flags & IP_NAT_RANGE_PROTO_RANDOM)) {
-		if (find_appropriate_src(orig_tuple, tuple, range)) {
+		if (find_appropriate_src(net, orig_tuple, tuple, range)) {
 			pr_debug("get_unique_tuple: Found current src map\n");
 			if (!nf_nat_used_tuple(tuple, ct))
 				return;
@@ -283,6 +282,7 @@
 		  const struct nf_nat_range *range,
 		  enum nf_nat_manip_type maniptype)
 {
+	struct net *net = nf_ct_net(ct);
 	struct nf_conntrack_tuple curr_tuple, new_tuple;
 	struct nf_conn_nat *nat;
 	int have_to_hash = !(ct->status & IPS_NAT_DONE_MASK);
@@ -334,7 +334,8 @@
 		/* nf_conntrack_alter_reply might re-allocate exntension aera */
 		nat = nfct_nat(ct);
 		nat->ct = ct;
-		hlist_add_head_rcu(&nat->bysource, &bysource[srchash]);
+		hlist_add_head_rcu(&nat->bysource,
+				   &net->ipv4.nat_bysource[srchash]);
 		spin_unlock_bh(&nf_nat_lock);
 	}
 
@@ -583,6 +584,40 @@
 	.flags		= NF_CT_EXT_F_PREALLOC,
 };
 
+static int __net_init nf_nat_net_init(struct net *net)
+{
+	net->ipv4.nat_bysource = nf_ct_alloc_hashtable(&nf_nat_htable_size,
+						      &net->ipv4.nat_vmalloced);
+	if (!net->ipv4.nat_bysource)
+		return -ENOMEM;
+	return 0;
+}
+
+/* Clear NAT section of all conntracks, in case we're loaded again. */
+static int clean_nat(struct nf_conn *i, void *data)
+{
+	struct nf_conn_nat *nat = nfct_nat(i);
+
+	if (!nat)
+		return 0;
+	memset(nat, 0, sizeof(*nat));
+	i->status &= ~(IPS_NAT_MASK | IPS_NAT_DONE_MASK | IPS_SEQ_ADJUST);
+	return 0;
+}
+
+static void __net_exit nf_nat_net_exit(struct net *net)
+{
+	nf_ct_iterate_cleanup(net, &clean_nat, NULL);
+	synchronize_rcu();
+	nf_ct_free_hashtable(net->ipv4.nat_bysource, net->ipv4.nat_vmalloced,
+			     nf_nat_htable_size);
+}
+
+static struct pernet_operations nf_nat_net_ops = {
+	.init = nf_nat_net_init,
+	.exit = nf_nat_net_exit,
+};
+
 static int __init nf_nat_init(void)
 {
 	size_t i;
@@ -599,12 +634,9 @@
 	/* Leave them the same for the moment. */
 	nf_nat_htable_size = nf_conntrack_htable_size;
 
-	bysource = nf_ct_alloc_hashtable(&nf_nat_htable_size,
-					 &nf_nat_vmalloced);
-	if (!bysource) {
-		ret = -ENOMEM;
+	ret = register_pernet_subsys(&nf_nat_net_ops);
+	if (ret < 0)
 		goto cleanup_extend;
-	}
 
 	/* Sew in builtin protocols. */
 	spin_lock_bh(&nf_nat_lock);
@@ -629,23 +661,9 @@
 	return ret;
 }
 
-/* Clear NAT section of all conntracks, in case we're loaded again. */
-static int clean_nat(struct nf_conn *i, void *data)
-{
-	struct nf_conn_nat *nat = nfct_nat(i);
-
-	if (!nat)
-		return 0;
-	memset(nat, 0, sizeof(*nat));
-	i->status &= ~(IPS_NAT_MASK | IPS_NAT_DONE_MASK | IPS_SEQ_ADJUST);
-	return 0;
-}
-
 static void __exit nf_nat_cleanup(void)
 {
-	nf_ct_iterate_cleanup(&clean_nat, NULL);
-	synchronize_rcu();
-	nf_ct_free_hashtable(bysource, nf_nat_vmalloced, nf_nat_htable_size);
+	unregister_pernet_subsys(&nf_nat_net_ops);
 	nf_ct_l3proto_put(l3proto);
 	nf_ct_extend_unregister(&nat_extend);
 	rcu_assign_pointer(nf_nat_seq_adjust_hook, NULL);
diff --git a/net/ipv4/netfilter/nf_nat_helper.c b/net/ipv4/netfilter/nf_nat_helper.c
index 11976ea..cf7a42b 100644
--- a/net/ipv4/netfilter/nf_nat_helper.c
+++ b/net/ipv4/netfilter/nf_nat_helper.c
@@ -16,6 +16,7 @@
 #include <linux/udp.h>
 #include <net/checksum.h>
 #include <net/tcp.h>
+#include <net/route.h>
 
 #include <linux/netfilter_ipv4.h>
 #include <net/netfilter/nf_conntrack.h>
@@ -192,7 +193,7 @@
 		nf_conntrack_tcp_update(skb, ip_hdrlen(skb),
 					ct, CTINFO2DIR(ctinfo));
 
-		nf_conntrack_event_cache(IPCT_NATSEQADJ, skb);
+		nf_conntrack_event_cache(IPCT_NATSEQADJ, ct);
 	}
 	return 1;
 }
diff --git a/net/ipv4/netfilter/nf_nat_pptp.c b/net/ipv4/netfilter/nf_nat_pptp.c
index da3d91a..9eb1710 100644
--- a/net/ipv4/netfilter/nf_nat_pptp.c
+++ b/net/ipv4/netfilter/nf_nat_pptp.c
@@ -40,6 +40,7 @@
 static void pptp_nat_expected(struct nf_conn *ct,
 			      struct nf_conntrack_expect *exp)
 {
+	struct net *net = nf_ct_net(ct);
 	const struct nf_conn *master = ct->master;
 	struct nf_conntrack_expect *other_exp;
 	struct nf_conntrack_tuple t;
@@ -73,7 +74,7 @@
 
 	pr_debug("trying to unexpect other dir: ");
 	nf_ct_dump_tuple_ip(&t);
-	other_exp = nf_ct_expect_find_get(&t);
+	other_exp = nf_ct_expect_find_get(net, &t);
 	if (other_exp) {
 		nf_ct_unexpect_related(other_exp);
 		nf_ct_expect_put(other_exp);
diff --git a/net/ipv4/netfilter/nf_nat_rule.c b/net/ipv4/netfilter/nf_nat_rule.c
index e8b4d0d..bea54a6 100644
--- a/net/ipv4/netfilter/nf_nat_rule.c
+++ b/net/ipv4/netfilter/nf_nat_rule.c
@@ -33,7 +33,7 @@
 	struct ipt_replace repl;
 	struct ipt_standard entries[3];
 	struct ipt_error term;
-} nat_initial_table __initdata = {
+} nat_initial_table __net_initdata = {
 	.repl = {
 		.name = "nat",
 		.valid_hooks = NAT_VALID_HOOKS,
@@ -58,47 +58,42 @@
 	.term = IPT_ERROR_INIT,			/* ERROR */
 };
 
-static struct xt_table __nat_table = {
+static struct xt_table nat_table = {
 	.name		= "nat",
 	.valid_hooks	= NAT_VALID_HOOKS,
 	.lock		= __RW_LOCK_UNLOCKED(__nat_table.lock),
 	.me		= THIS_MODULE,
 	.af		= AF_INET,
 };
-static struct xt_table *nat_table;
 
 /* Source NAT */
-static unsigned int ipt_snat_target(struct sk_buff *skb,
-				    const struct net_device *in,
-				    const struct net_device *out,
-				    unsigned int hooknum,
-				    const struct xt_target *target,
-				    const void *targinfo)
+static unsigned int
+ipt_snat_target(struct sk_buff *skb, const struct xt_target_param *par)
 {
 	struct nf_conn *ct;
 	enum ip_conntrack_info ctinfo;
-	const struct nf_nat_multi_range_compat *mr = targinfo;
+	const struct nf_nat_multi_range_compat *mr = par->targinfo;
 
-	NF_CT_ASSERT(hooknum == NF_INET_POST_ROUTING);
+	NF_CT_ASSERT(par->hooknum == NF_INET_POST_ROUTING);
 
 	ct = nf_ct_get(skb, &ctinfo);
 
 	/* Connection must be valid and new. */
 	NF_CT_ASSERT(ct && (ctinfo == IP_CT_NEW || ctinfo == IP_CT_RELATED ||
 			    ctinfo == IP_CT_RELATED + IP_CT_IS_REPLY));
-	NF_CT_ASSERT(out);
+	NF_CT_ASSERT(par->out != NULL);
 
 	return nf_nat_setup_info(ct, &mr->range[0], IP_NAT_MANIP_SRC);
 }
 
 /* Before 2.6.11 we did implicit source NAT if required. Warn about change. */
-static void warn_if_extra_mangle(__be32 dstip, __be32 srcip)
+static void warn_if_extra_mangle(struct net *net, __be32 dstip, __be32 srcip)
 {
 	static int warned = 0;
 	struct flowi fl = { .nl_u = { .ip4_u = { .daddr = dstip } } };
 	struct rtable *rt;
 
-	if (ip_route_output_key(&init_net, &rt, &fl) != 0)
+	if (ip_route_output_key(net, &rt, &fl) != 0)
 		return;
 
 	if (rt->rt_src != srcip && !warned) {
@@ -110,40 +105,32 @@
 	ip_rt_put(rt);
 }
 
-static unsigned int ipt_dnat_target(struct sk_buff *skb,
-				    const struct net_device *in,
-				    const struct net_device *out,
-				    unsigned int hooknum,
-				    const struct xt_target *target,
-				    const void *targinfo)
+static unsigned int
+ipt_dnat_target(struct sk_buff *skb, const struct xt_target_param *par)
 {
 	struct nf_conn *ct;
 	enum ip_conntrack_info ctinfo;
-	const struct nf_nat_multi_range_compat *mr = targinfo;
+	const struct nf_nat_multi_range_compat *mr = par->targinfo;
 
-	NF_CT_ASSERT(hooknum == NF_INET_PRE_ROUTING ||
-		     hooknum == NF_INET_LOCAL_OUT);
+	NF_CT_ASSERT(par->hooknum == NF_INET_PRE_ROUTING ||
+		     par->hooknum == NF_INET_LOCAL_OUT);
 
 	ct = nf_ct_get(skb, &ctinfo);
 
 	/* Connection must be valid and new. */
 	NF_CT_ASSERT(ct && (ctinfo == IP_CT_NEW || ctinfo == IP_CT_RELATED));
 
-	if (hooknum == NF_INET_LOCAL_OUT &&
+	if (par->hooknum == NF_INET_LOCAL_OUT &&
 	    mr->range[0].flags & IP_NAT_RANGE_MAP_IPS)
-		warn_if_extra_mangle(ip_hdr(skb)->daddr,
+		warn_if_extra_mangle(dev_net(par->out), ip_hdr(skb)->daddr,
 				     mr->range[0].min_ip);
 
 	return nf_nat_setup_info(ct, &mr->range[0], IP_NAT_MANIP_DST);
 }
 
-static bool ipt_snat_checkentry(const char *tablename,
-				const void *entry,
-				const struct xt_target *target,
-				void *targinfo,
-				unsigned int hook_mask)
+static bool ipt_snat_checkentry(const struct xt_tgchk_param *par)
 {
-	const struct nf_nat_multi_range_compat *mr = targinfo;
+	const struct nf_nat_multi_range_compat *mr = par->targinfo;
 
 	/* Must be a valid range */
 	if (mr->rangesize != 1) {
@@ -153,13 +140,9 @@
 	return true;
 }
 
-static bool ipt_dnat_checkentry(const char *tablename,
-				const void *entry,
-				const struct xt_target *target,
-				void *targinfo,
-				unsigned int hook_mask)
+static bool ipt_dnat_checkentry(const struct xt_tgchk_param *par)
 {
-	const struct nf_nat_multi_range_compat *mr = targinfo;
+	const struct nf_nat_multi_range_compat *mr = par->targinfo;
 
 	/* Must be a valid range */
 	if (mr->rangesize != 1) {
@@ -194,9 +177,10 @@
 		     const struct net_device *out,
 		     struct nf_conn *ct)
 {
+	struct net *net = nf_ct_net(ct);
 	int ret;
 
-	ret = ipt_do_table(skb, hooknum, in, out, nat_table);
+	ret = ipt_do_table(skb, hooknum, in, out, net->ipv4.nat_table);
 
 	if (ret == NF_ACCEPT) {
 		if (!nf_nat_initialized(ct, HOOK2MANIP(hooknum)))
@@ -226,14 +210,32 @@
 	.family		= AF_INET,
 };
 
+static int __net_init nf_nat_rule_net_init(struct net *net)
+{
+	net->ipv4.nat_table = ipt_register_table(net, &nat_table,
+						 &nat_initial_table.repl);
+	if (IS_ERR(net->ipv4.nat_table))
+		return PTR_ERR(net->ipv4.nat_table);
+	return 0;
+}
+
+static void __net_exit nf_nat_rule_net_exit(struct net *net)
+{
+	ipt_unregister_table(net->ipv4.nat_table);
+}
+
+static struct pernet_operations nf_nat_rule_net_ops = {
+	.init = nf_nat_rule_net_init,
+	.exit = nf_nat_rule_net_exit,
+};
+
 int __init nf_nat_rule_init(void)
 {
 	int ret;
 
-	nat_table = ipt_register_table(&init_net, &__nat_table,
-				       &nat_initial_table.repl);
-	if (IS_ERR(nat_table))
-		return PTR_ERR(nat_table);
+	ret = register_pernet_subsys(&nf_nat_rule_net_ops);
+	if (ret != 0)
+		goto out;
 	ret = xt_register_target(&ipt_snat_reg);
 	if (ret != 0)
 		goto unregister_table;
@@ -247,8 +249,8 @@
  unregister_snat:
 	xt_unregister_target(&ipt_snat_reg);
  unregister_table:
-	ipt_unregister_table(nat_table);
-
+	unregister_pernet_subsys(&nf_nat_rule_net_ops);
+ out:
 	return ret;
 }
 
@@ -256,5 +258,5 @@
 {
 	xt_unregister_target(&ipt_dnat_reg);
 	xt_unregister_target(&ipt_snat_reg);
-	ipt_unregister_table(nat_table);
+	unregister_pernet_subsys(&nf_nat_rule_net_ops);
 }
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index 6ee5354..a6d7c58 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -282,6 +282,8 @@
 	struct rtable *r = NULL;
 
 	for (st->bucket = rt_hash_mask; st->bucket >= 0; --st->bucket) {
+		if (!rt_hash_table[st->bucket].chain)
+			continue;
 		rcu_read_lock_bh();
 		r = rcu_dereference(rt_hash_table[st->bucket].chain);
 		while (r) {
@@ -299,11 +301,14 @@
 					  struct rtable *r)
 {
 	struct rt_cache_iter_state *st = seq->private;
+
 	r = r->u.dst.rt_next;
 	while (!r) {
 		rcu_read_unlock_bh();
-		if (--st->bucket < 0)
-			break;
+		do {
+			if (--st->bucket < 0)
+				return NULL;
+		} while (!rt_hash_table[st->bucket].chain);
 		rcu_read_lock_bh();
 		r = rt_hash_table[st->bucket].chain;
 	}
@@ -2356,11 +2361,6 @@
 		    ipv4_is_zeronet(oldflp->fl4_src))
 			goto out;
 
-		/* It is equivalent to inet_addr_type(saddr) == RTN_LOCAL */
-		dev_out = ip_dev_find(net, oldflp->fl4_src);
-		if (dev_out == NULL)
-			goto out;
-
 		/* I removed check for oif == dev_out->oif here.
 		   It was wrong for two reasons:
 		   1. ip_dev_find(net, saddr) can return wrong iface, if saddr
@@ -2372,6 +2372,11 @@
 		if (oldflp->oif == 0
 		    && (ipv4_is_multicast(oldflp->fl4_dst) ||
 			oldflp->fl4_dst == htonl(0xFFFFFFFF))) {
+			/* It is equivalent to inet_addr_type(saddr) == RTN_LOCAL */
+			dev_out = ip_dev_find(net, oldflp->fl4_src);
+			if (dev_out == NULL)
+				goto out;
+
 			/* Special hack: user can direct multicasts
 			   and limited broadcast via necessary interface
 			   without fiddling with IP_MULTICAST_IF or IP_PKTINFO.
@@ -2390,9 +2395,15 @@
 			fl.oif = dev_out->ifindex;
 			goto make_route;
 		}
-		if (dev_out)
+
+		if (!(oldflp->flags & FLOWI_FLAG_ANYSRC)) {
+			/* It is equivalent to inet_addr_type(saddr) == RTN_LOCAL */
+			dev_out = ip_dev_find(net, oldflp->fl4_src);
+			if (dev_out == NULL)
+				goto out;
 			dev_put(dev_out);
-		dev_out = NULL;
+			dev_out = NULL;
+		}
 	}
 
 
@@ -2840,7 +2851,9 @@
 	if (s_h < 0)
 		s_h = 0;
 	s_idx = idx = cb->args[1];
-	for (h = s_h; h <= rt_hash_mask; h++) {
+	for (h = s_h; h <= rt_hash_mask; h++, s_idx = 0) {
+		if (!rt_hash_table[h].chain)
+			continue;
 		rcu_read_lock_bh();
 		for (rt = rcu_dereference(rt_hash_table[h].chain), idx = 0; rt;
 		     rt = rcu_dereference(rt->u.dst.rt_next), idx++) {
@@ -2859,7 +2872,6 @@
 			dst_release(xchg(&skb->dst, NULL));
 		}
 		rcu_read_unlock_bh();
-		s_idx = 0;
 	}
 
 done:
diff --git a/net/ipv4/syncookies.c b/net/ipv4/syncookies.c
index 9d38005..d346c22 100644
--- a/net/ipv4/syncookies.c
+++ b/net/ipv4/syncookies.c
@@ -16,6 +16,7 @@
 #include <linux/cryptohash.h>
 #include <linux/kernel.h>
 #include <net/tcp.h>
+#include <net/route.h>
 
 /* Timestamps: lowest 9 bits store TCP options */
 #define TSBITS 9
@@ -296,6 +297,7 @@
 	treq->rcv_isn		= ntohl(th->seq) - 1;
 	treq->snt_isn		= cookie;
 	req->mss		= mss;
+	ireq->loc_port		= th->dest;
 	ireq->rmt_port		= th->source;
 	ireq->loc_addr		= ip_hdr(skb)->daddr;
 	ireq->rmt_addr		= ip_hdr(skb)->saddr;
@@ -337,6 +339,7 @@
 						.saddr = ireq->loc_addr,
 						.tos = RT_CONN_FLAGS(sk) } },
 				    .proto = IPPROTO_TCP,
+				    .flags = inet_sk_flowi_flags(sk),
 				    .uli_u = { .ports =
 					       { .sport = th->dest,
 						 .dport = th->source } } };
diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c
index e0689fd..276d047 100644
--- a/net/ipv4/sysctl_net_ipv4.c
+++ b/net/ipv4/sysctl_net_ipv4.c
@@ -26,16 +26,13 @@
 static int ip_local_port_range_min[] = { 1, 1 };
 static int ip_local_port_range_max[] = { 65535, 65535 };
 
-extern seqlock_t sysctl_port_range_lock;
-extern int sysctl_local_port_range[2];
-
 /* Update system visible IP port range */
 static void set_local_port_range(int range[2])
 {
-	write_seqlock(&sysctl_port_range_lock);
-	sysctl_local_port_range[0] = range[0];
-	sysctl_local_port_range[1] = range[1];
-	write_sequnlock(&sysctl_port_range_lock);
+	write_seqlock(&sysctl_local_ports.lock);
+	sysctl_local_ports.range[0] = range[0];
+	sysctl_local_ports.range[1] = range[1];
+	write_sequnlock(&sysctl_local_ports.lock);
 }
 
 /* Validate changes from /proc interface. */
@@ -44,8 +41,7 @@
 				 size_t *lenp, loff_t *ppos)
 {
 	int ret;
-	int range[2] = { sysctl_local_port_range[0],
-			 sysctl_local_port_range[1] };
+	int range[2];
 	ctl_table tmp = {
 		.data = &range,
 		.maxlen = sizeof(range),
@@ -54,6 +50,7 @@
 		.extra2 = &ip_local_port_range_max,
 	};
 
+	inet_get_local_port_range(range, range + 1);
 	ret = proc_dointvec_minmax(&tmp, write, filp, buffer, lenp, ppos);
 
 	if (write && ret == 0) {
@@ -73,8 +70,7 @@
 					void __user *newval, size_t newlen)
 {
 	int ret;
-	int range[2] = { sysctl_local_port_range[0],
-			 sysctl_local_port_range[1] };
+	int range[2];
 	ctl_table tmp = {
 		.data = &range,
 		.maxlen = sizeof(range),
@@ -83,6 +79,7 @@
 		.extra2 = &ip_local_port_range_max,
 	};
 
+	inet_get_local_port_range(range, range + 1);
 	ret = sysctl_intvec(&tmp, name, nlen, oldval, oldlenp, newval, newlen);
 	if (ret == 0 && newval && newlen) {
 		if (range[1] < range[0])
@@ -396,8 +393,8 @@
 	{
 		.ctl_name	= NET_IPV4_LOCAL_PORT_RANGE,
 		.procname	= "ip_local_port_range",
-		.data		= &sysctl_local_port_range,
-		.maxlen		= sizeof(sysctl_local_port_range),
+		.data		= &sysctl_local_ports.range,
+		.maxlen		= sizeof(sysctl_local_ports.range),
 		.mode		= 0644,
 		.proc_handler	= &ipv4_local_port_range,
 		.strategy	= &ipv4_sysctl_local_port_range,
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index 1ab341e..eccb716 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -384,13 +384,17 @@
 
 	/* Connected? */
 	if ((1 << sk->sk_state) & ~(TCPF_SYN_SENT | TCPF_SYN_RECV)) {
+		int target = sock_rcvlowat(sk, 0, INT_MAX);
+
+		if (tp->urg_seq == tp->copied_seq &&
+		    !sock_flag(sk, SOCK_URGINLINE) &&
+		    tp->urg_data)
+			target--;
+
 		/* Potential race condition. If read of tp below will
 		 * escape above sk->sk_state, we can be illegally awaken
 		 * in SYN_* states. */
-		if ((tp->rcv_nxt != tp->copied_seq) &&
-		    (tp->urg_seq != tp->copied_seq ||
-		     tp->rcv_nxt != tp->copied_seq + 1 ||
-		     sock_flag(sk, SOCK_URGINLINE) || !tp->urg_data))
+		if (tp->rcv_nxt - tp->copied_seq >= target)
 			mask |= POLLIN | POLLRDNORM;
 
 		if (!(sk->sk_shutdown & SEND_SHUTDOWN)) {
@@ -493,10 +497,8 @@
 static inline void tcp_mark_urg(struct tcp_sock *tp, int flags,
 				struct sk_buff *skb)
 {
-	if (flags & MSG_OOB) {
-		tp->urg_mode = 1;
+	if (flags & MSG_OOB)
 		tp->snd_up = tp->write_seq;
-	}
 }
 
 static inline void tcp_push(struct sock *sk, int flags, int mss_now,
@@ -1157,7 +1159,7 @@
 	 * necessary */
 	local_bh_disable();
 	while ((skb = __skb_dequeue(&tp->ucopy.prequeue)) != NULL)
-		sk->sk_backlog_rcv(sk, skb);
+		sk_backlog_rcv(sk, skb);
 	local_bh_enable();
 
 	/* Clear memory counter. */
diff --git a/net/ipv4/tcp_hybla.c b/net/ipv4/tcp_hybla.c
index bfcbd14..c209e05 100644
--- a/net/ipv4/tcp_hybla.c
+++ b/net/ipv4/tcp_hybla.c
@@ -150,7 +150,11 @@
 		ca->snd_cwnd_cents -= 128;
 		tp->snd_cwnd_cnt = 0;
 	}
-
+	/* check when cwnd has not been incremented for a while */
+	if (increment == 0 && odd == 0 && tp->snd_cwnd_cnt >= tp->snd_cwnd) {
+		tp->snd_cwnd++;
+		tp->snd_cwnd_cnt = 0;
+	}
 	/* clamp down slowstart cwnd to ssthresh value. */
 	if (is_slowstart)
 		tp->snd_cwnd = min(tp->snd_cwnd, tp->snd_ssthresh);
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index 67ccce2..d77c0d2 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -979,6 +979,39 @@
 	}
 }
 
+/* This must be called before lost_out is incremented */
+static void tcp_verify_retransmit_hint(struct tcp_sock *tp, struct sk_buff *skb)
+{
+	if ((tp->retransmit_skb_hint == NULL) ||
+	    before(TCP_SKB_CB(skb)->seq,
+		   TCP_SKB_CB(tp->retransmit_skb_hint)->seq))
+		tp->retransmit_skb_hint = skb;
+
+	if (!tp->lost_out ||
+	    after(TCP_SKB_CB(skb)->end_seq, tp->retransmit_high))
+		tp->retransmit_high = TCP_SKB_CB(skb)->end_seq;
+}
+
+static void tcp_skb_mark_lost(struct tcp_sock *tp, struct sk_buff *skb)
+{
+	if (!(TCP_SKB_CB(skb)->sacked & (TCPCB_LOST|TCPCB_SACKED_ACKED))) {
+		tcp_verify_retransmit_hint(tp, skb);
+
+		tp->lost_out += tcp_skb_pcount(skb);
+		TCP_SKB_CB(skb)->sacked |= TCPCB_LOST;
+	}
+}
+
+void tcp_skb_mark_lost_uncond_verify(struct tcp_sock *tp, struct sk_buff *skb)
+{
+	tcp_verify_retransmit_hint(tp, skb);
+
+	if (!(TCP_SKB_CB(skb)->sacked & (TCPCB_LOST|TCPCB_SACKED_ACKED))) {
+		tp->lost_out += tcp_skb_pcount(skb);
+		TCP_SKB_CB(skb)->sacked |= TCPCB_LOST;
+	}
+}
+
 /* This procedure tags the retransmission queue when SACKs arrive.
  *
  * We have three tag bits: SACKED(S), RETRANS(R) and LOST(L).
@@ -1155,13 +1188,7 @@
 			TCP_SKB_CB(skb)->sacked &= ~TCPCB_SACKED_RETRANS;
 			tp->retrans_out -= tcp_skb_pcount(skb);
 
-			/* clear lost hint */
-			tp->retransmit_skb_hint = NULL;
-
-			if (!(TCP_SKB_CB(skb)->sacked & (TCPCB_LOST|TCPCB_SACKED_ACKED))) {
-				tp->lost_out += tcp_skb_pcount(skb);
-				TCP_SKB_CB(skb)->sacked |= TCPCB_LOST;
-			}
+			tcp_skb_mark_lost_uncond_verify(tp, skb);
 			NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPLOSTRETRANSMIT);
 		} else {
 			if (before(ack_seq, new_low_seq))
@@ -1271,9 +1298,6 @@
 					~(TCPCB_LOST|TCPCB_SACKED_RETRANS);
 				tp->lost_out -= tcp_skb_pcount(skb);
 				tp->retrans_out -= tcp_skb_pcount(skb);
-
-				/* clear lost hint */
-				tp->retransmit_skb_hint = NULL;
 			}
 		} else {
 			if (!(sacked & TCPCB_RETRANS)) {
@@ -1292,9 +1316,6 @@
 			if (sacked & TCPCB_LOST) {
 				TCP_SKB_CB(skb)->sacked &= ~TCPCB_LOST;
 				tp->lost_out -= tcp_skb_pcount(skb);
-
-				/* clear lost hint */
-				tp->retransmit_skb_hint = NULL;
 			}
 		}
 
@@ -1324,7 +1345,6 @@
 	if (dup_sack && (TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_RETRANS)) {
 		TCP_SKB_CB(skb)->sacked &= ~TCPCB_SACKED_RETRANS;
 		tp->retrans_out -= tcp_skb_pcount(skb);
-		tp->retransmit_skb_hint = NULL;
 	}
 
 	return flag;
@@ -1726,6 +1746,8 @@
 		return 0;
 
 	skb = tcp_write_queue_head(sk);
+	if (tcp_skb_is_last(sk, skb))
+		return 1;
 	skb = tcp_write_queue_next(sk, skb);	/* Skips head */
 	tcp_for_write_queue_from(skb, sk) {
 		if (skb == tcp_send_head(sk))
@@ -1867,6 +1889,7 @@
 		if (!(TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_ACKED)) {
 			TCP_SKB_CB(skb)->sacked |= TCPCB_LOST;
 			tp->lost_out += tcp_skb_pcount(skb);
+			tp->retransmit_high = TCP_SKB_CB(skb)->end_seq;
 		}
 	}
 	tcp_verify_left_out(tp);
@@ -1883,7 +1906,7 @@
 	tp->high_seq = tp->snd_nxt;
 	TCP_ECN_queue_cwr(tp);
 
-	tcp_clear_retrans_hints_partial(tp);
+	tcp_clear_all_retrans_hints(tp);
 }
 
 static void tcp_clear_retrans_partial(struct tcp_sock *tp)
@@ -1934,12 +1957,11 @@
 		/* Push undo marker, if it was plain RTO and nothing
 		 * was retransmitted. */
 		tp->undo_marker = tp->snd_una;
-		tcp_clear_retrans_hints_partial(tp);
 	} else {
 		tp->sacked_out = 0;
 		tp->fackets_out = 0;
-		tcp_clear_all_retrans_hints(tp);
 	}
+	tcp_clear_all_retrans_hints(tp);
 
 	tcp_for_write_queue(skb, sk) {
 		if (skb == tcp_send_head(sk))
@@ -1952,6 +1974,7 @@
 			TCP_SKB_CB(skb)->sacked &= ~TCPCB_SACKED_ACKED;
 			TCP_SKB_CB(skb)->sacked |= TCPCB_LOST;
 			tp->lost_out += tcp_skb_pcount(skb);
+			tp->retransmit_high = TCP_SKB_CB(skb)->end_seq;
 		}
 	}
 	tcp_verify_left_out(tp);
@@ -2157,19 +2180,6 @@
 	return 0;
 }
 
-/* RFC: This is from the original, I doubt that this is necessary at all:
- * clear xmit_retrans hint if seq of this skb is beyond hint. How could we
- * retransmitted past LOST markings in the first place? I'm not fully sure
- * about undo and end of connection cases, which can cause R without L?
- */
-static void tcp_verify_retransmit_hint(struct tcp_sock *tp, struct sk_buff *skb)
-{
-	if ((tp->retransmit_skb_hint != NULL) &&
-	    before(TCP_SKB_CB(skb)->seq,
-		   TCP_SKB_CB(tp->retransmit_skb_hint)->seq))
-		tp->retransmit_skb_hint = NULL;
-}
-
 /* Mark head of queue up as lost. With RFC3517 SACK, the packets is
  * is against sacked "cnt", otherwise it's against facked "cnt"
  */
@@ -2217,11 +2227,7 @@
 			cnt = packets;
 		}
 
-		if (!(TCP_SKB_CB(skb)->sacked & (TCPCB_SACKED_ACKED|TCPCB_LOST))) {
-			TCP_SKB_CB(skb)->sacked |= TCPCB_LOST;
-			tp->lost_out += tcp_skb_pcount(skb);
-			tcp_verify_retransmit_hint(tp, skb);
-		}
+		tcp_skb_mark_lost(tp, skb);
 	}
 	tcp_verify_left_out(tp);
 }
@@ -2263,11 +2269,7 @@
 			if (!tcp_skb_timedout(sk, skb))
 				break;
 
-			if (!(TCP_SKB_CB(skb)->sacked & (TCPCB_SACKED_ACKED|TCPCB_LOST))) {
-				TCP_SKB_CB(skb)->sacked |= TCPCB_LOST;
-				tp->lost_out += tcp_skb_pcount(skb);
-				tcp_verify_retransmit_hint(tp, skb);
-			}
+			tcp_skb_mark_lost(tp, skb);
 		}
 
 		tp->scoreboard_skb_hint = skb;
@@ -2378,10 +2380,6 @@
 	}
 	tcp_moderate_cwnd(tp);
 	tp->snd_cwnd_stamp = tcp_time_stamp;
-
-	/* There is something screwy going on with the retrans hints after
-	   an undo */
-	tcp_clear_all_retrans_hints(tp);
 }
 
 static inline int tcp_may_undo(struct tcp_sock *tp)
@@ -2838,7 +2836,8 @@
  * is before the ack sequence we can discard it as it's confirmed to have
  * arrived at the other end.
  */
-static int tcp_clean_rtx_queue(struct sock *sk, int prior_fackets)
+static int tcp_clean_rtx_queue(struct sock *sk, int prior_fackets,
+			       u32 prior_snd_una)
 {
 	struct tcp_sock *tp = tcp_sk(sk);
 	const struct inet_connection_sock *icsk = inet_csk(sk);
@@ -2848,6 +2847,7 @@
 	int flag = 0;
 	u32 pkts_acked = 0;
 	u32 reord = tp->packets_out;
+	u32 prior_sacked = tp->sacked_out;
 	s32 seq_rtt = -1;
 	s32 ca_seq_rtt = -1;
 	ktime_t last_ackt = net_invalid_timestamp();
@@ -2904,9 +2904,6 @@
 		if (sacked & TCPCB_LOST)
 			tp->lost_out -= acked_pcount;
 
-		if (unlikely(tp->urg_mode && !before(end_seq, tp->snd_up)))
-			tp->urg_mode = 0;
-
 		tp->packets_out -= acked_pcount;
 		pkts_acked += acked_pcount;
 
@@ -2929,9 +2926,16 @@
 
 		tcp_unlink_write_queue(skb, sk);
 		sk_wmem_free_skb(sk, skb);
-		tcp_clear_all_retrans_hints(tp);
+		tp->scoreboard_skb_hint = NULL;
+		if (skb == tp->retransmit_skb_hint)
+			tp->retransmit_skb_hint = NULL;
+		if (skb == tp->lost_skb_hint)
+			tp->lost_skb_hint = NULL;
 	}
 
+	if (likely(between(tp->snd_up, prior_snd_una, tp->snd_una)))
+		tp->snd_up = tp->snd_una;
+
 	if (skb && (TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_ACKED))
 		flag |= FLAG_SACK_RENEGING;
 
@@ -2948,6 +2952,15 @@
 			/* Non-retransmitted hole got filled? That's reordering */
 			if (reord < prior_fackets)
 				tcp_update_reordering(sk, tp->fackets_out - reord, 0);
+
+			/* No need to care for underflows here because
+			 * the lost_skb_hint gets NULLed if we're past it
+			 * (or something non-trivial happened)
+			 */
+			if (tcp_is_fack(tp))
+				tp->lost_cnt_hint -= pkts_acked;
+			else
+				tp->lost_cnt_hint -= prior_sacked - tp->sacked_out;
 		}
 
 		tp->fackets_out -= min(pkts_acked, tp->fackets_out);
@@ -3299,7 +3312,7 @@
 		goto no_queue;
 
 	/* See if we can take anything off of the retransmit queue. */
-	flag |= tcp_clean_rtx_queue(sk, prior_fackets);
+	flag |= tcp_clean_rtx_queue(sk, prior_fackets, prior_snd_una);
 
 	if (tp->frto_counter)
 		frto_cwnd = tcp_process_frto(sk, flag);
@@ -3442,6 +3455,22 @@
 	}
 }
 
+static int tcp_parse_aligned_timestamp(struct tcp_sock *tp, struct tcphdr *th)
+{
+	__be32 *ptr = (__be32 *)(th + 1);
+
+	if (*ptr == htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16)
+			  | (TCPOPT_TIMESTAMP << 8) | TCPOLEN_TIMESTAMP)) {
+		tp->rx_opt.saw_tstamp = 1;
+		++ptr;
+		tp->rx_opt.rcv_tsval = ntohl(*ptr);
+		++ptr;
+		tp->rx_opt.rcv_tsecr = ntohl(*ptr);
+		return 1;
+	}
+	return 0;
+}
+
 /* Fast parse options. This hopes to only see timestamps.
  * If it is wrong it falls back on tcp_parse_options().
  */
@@ -3453,16 +3482,8 @@
 		return 0;
 	} else if (tp->rx_opt.tstamp_ok &&
 		   th->doff == (sizeof(struct tcphdr)>>2)+(TCPOLEN_TSTAMP_ALIGNED>>2)) {
-		__be32 *ptr = (__be32 *)(th + 1);
-		if (*ptr == htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16)
-				  | (TCPOPT_TIMESTAMP << 8) | TCPOLEN_TIMESTAMP)) {
-			tp->rx_opt.saw_tstamp = 1;
-			++ptr;
-			tp->rx_opt.rcv_tsval = ntohl(*ptr);
-			++ptr;
-			tp->rx_opt.rcv_tsecr = ntohl(*ptr);
+		if (tcp_parse_aligned_timestamp(tp, th))
 			return 1;
-		}
 	}
 	tcp_parse_options(skb, &tp->rx_opt, 1);
 	return 1;
@@ -4138,7 +4159,7 @@
 				skb1 = skb1->prev;
 			}
 		}
-		__skb_insert(skb, skb1, skb1->next, &tp->out_of_order_queue);
+		__skb_queue_after(&tp->out_of_order_queue, skb1, skb);
 
 		/* And clean segments covered by new one as whole. */
 		while ((skb1 = skb->next) !=
@@ -4161,6 +4182,18 @@
 	}
 }
 
+static struct sk_buff *tcp_collapse_one(struct sock *sk, struct sk_buff *skb,
+					struct sk_buff_head *list)
+{
+	struct sk_buff *next = skb->next;
+
+	__skb_unlink(skb, list);
+	__kfree_skb(skb);
+	NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPRCVCOLLAPSED);
+
+	return next;
+}
+
 /* Collapse contiguous sequence of skbs head..tail with
  * sequence numbers start..end.
  * Segments with FIN/SYN are not collapsed (only because this
@@ -4178,11 +4211,7 @@
 	for (skb = head; skb != tail;) {
 		/* No new bits? It is possible on ofo queue. */
 		if (!before(start, TCP_SKB_CB(skb)->end_seq)) {
-			struct sk_buff *next = skb->next;
-			__skb_unlink(skb, list);
-			__kfree_skb(skb);
-			NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPRCVCOLLAPSED);
-			skb = next;
+			skb = tcp_collapse_one(sk, skb, list);
 			continue;
 		}
 
@@ -4228,7 +4257,7 @@
 		memcpy(nskb->head, skb->head, header);
 		memcpy(nskb->cb, skb->cb, sizeof(skb->cb));
 		TCP_SKB_CB(nskb)->seq = TCP_SKB_CB(nskb)->end_seq = start;
-		__skb_insert(nskb, skb->prev, skb, list);
+		__skb_queue_before(list, skb, nskb);
 		skb_set_owner_r(nskb, sk);
 
 		/* Copy data, releasing collapsed skbs. */
@@ -4246,11 +4275,7 @@
 				start += size;
 			}
 			if (!before(start, TCP_SKB_CB(skb)->end_seq)) {
-				struct sk_buff *next = skb->next;
-				__skb_unlink(skb, list);
-				__kfree_skb(skb);
-				NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPRCVCOLLAPSED);
-				skb = next;
+				skb = tcp_collapse_one(sk, skb, list);
 				if (skb == tail ||
 				    tcp_hdr(skb)->syn ||
 				    tcp_hdr(skb)->fin)
@@ -4436,8 +4461,8 @@
 
 	if (tcp_should_expand_sndbuf(sk)) {
 		int sndmem = max_t(u32, tp->rx_opt.mss_clamp, tp->mss_cache) +
-			MAX_TCP_HEADER + 16 + sizeof(struct sk_buff),
-		    demanded = max_t(unsigned int, tp->snd_cwnd,
+			MAX_TCP_HEADER + 16 + sizeof(struct sk_buff);
+		int demanded = max_t(unsigned int, tp->snd_cwnd,
 				     tp->reordering + 1);
 		sndmem *= 2 * demanded;
 		if (sndmem > sk->sk_sndbuf)
@@ -4691,6 +4716,67 @@
 }
 #endif /* CONFIG_NET_DMA */
 
+/* Does PAWS and seqno based validation of an incoming segment, flags will
+ * play significant role here.
+ */
+static int tcp_validate_incoming(struct sock *sk, struct sk_buff *skb,
+			      struct tcphdr *th, int syn_inerr)
+{
+	struct tcp_sock *tp = tcp_sk(sk);
+
+	/* RFC1323: H1. Apply PAWS check first. */
+	if (tcp_fast_parse_options(skb, th, tp) && tp->rx_opt.saw_tstamp &&
+	    tcp_paws_discard(sk, skb)) {
+		if (!th->rst) {
+			NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_PAWSESTABREJECTED);
+			tcp_send_dupack(sk, skb);
+			goto discard;
+		}
+		/* Reset is accepted even if it did not pass PAWS. */
+	}
+
+	/* Step 1: check sequence number */
+	if (!tcp_sequence(tp, TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->end_seq)) {
+		/* RFC793, page 37: "In all states except SYN-SENT, all reset
+		 * (RST) segments are validated by checking their SEQ-fields."
+		 * And page 69: "If an incoming segment is not acceptable,
+		 * an acknowledgment should be sent in reply (unless the RST
+		 * bit is set, if so drop the segment and return)".
+		 */
+		if (!th->rst)
+			tcp_send_dupack(sk, skb);
+		goto discard;
+	}
+
+	/* Step 2: check RST bit */
+	if (th->rst) {
+		tcp_reset(sk);
+		goto discard;
+	}
+
+	/* ts_recent update must be made after we are sure that the packet
+	 * is in window.
+	 */
+	tcp_replace_ts_recent(tp, TCP_SKB_CB(skb)->seq);
+
+	/* step 3: check security and precedence [ignored] */
+
+	/* step 4: Check for a SYN in window. */
+	if (th->syn && !before(TCP_SKB_CB(skb)->seq, tp->rcv_nxt)) {
+		if (syn_inerr)
+			TCP_INC_STATS_BH(sock_net(sk), TCP_MIB_INERRS);
+		NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPABORTONSYN);
+		tcp_reset(sk);
+		return -1;
+	}
+
+	return 1;
+
+discard:
+	__kfree_skb(skb);
+	return 0;
+}
+
 /*
  *	TCP receive function for the ESTABLISHED state.
  *
@@ -4718,6 +4804,7 @@
 			struct tcphdr *th, unsigned len)
 {
 	struct tcp_sock *tp = tcp_sk(sk);
+	int res;
 
 	/*
 	 *	Header prediction.
@@ -4756,19 +4843,10 @@
 
 		/* Check timestamp */
 		if (tcp_header_len == sizeof(struct tcphdr) + TCPOLEN_TSTAMP_ALIGNED) {
-			__be32 *ptr = (__be32 *)(th + 1);
-
 			/* No? Slow path! */
-			if (*ptr != htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16)
-					  | (TCPOPT_TIMESTAMP << 8) | TCPOLEN_TIMESTAMP))
+			if (!tcp_parse_aligned_timestamp(tp, th))
 				goto slow_path;
 
-			tp->rx_opt.saw_tstamp = 1;
-			++ptr;
-			tp->rx_opt.rcv_tsval = ntohl(*ptr);
-			++ptr;
-			tp->rx_opt.rcv_tsecr = ntohl(*ptr);
-
 			/* If PAWS failed, check it more carefully in slow path */
 			if ((s32)(tp->rx_opt.rcv_tsval - tp->rx_opt.ts_recent) < 0)
 				goto slow_path;
@@ -4879,7 +4957,8 @@
 					goto no_ack;
 			}
 
-			__tcp_ack_snd_check(sk, 0);
+			if (!copied_early || tp->rcv_nxt != tp->rcv_wup)
+				__tcp_ack_snd_check(sk, 0);
 no_ack:
 #ifdef CONFIG_NET_DMA
 			if (copied_early)
@@ -4899,51 +4978,12 @@
 		goto csum_error;
 
 	/*
-	 * RFC1323: H1. Apply PAWS check first.
-	 */
-	if (tcp_fast_parse_options(skb, th, tp) && tp->rx_opt.saw_tstamp &&
-	    tcp_paws_discard(sk, skb)) {
-		if (!th->rst) {
-			NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_PAWSESTABREJECTED);
-			tcp_send_dupack(sk, skb);
-			goto discard;
-		}
-		/* Resets are accepted even if PAWS failed.
-
-		   ts_recent update must be made after we are sure
-		   that the packet is in window.
-		 */
-	}
-
-	/*
 	 *	Standard slow path.
 	 */
 
-	if (!tcp_sequence(tp, TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->end_seq)) {
-		/* RFC793, page 37: "In all states except SYN-SENT, all reset
-		 * (RST) segments are validated by checking their SEQ-fields."
-		 * And page 69: "If an incoming segment is not acceptable,
-		 * an acknowledgment should be sent in reply (unless the RST bit
-		 * is set, if so drop the segment and return)".
-		 */
-		if (!th->rst)
-			tcp_send_dupack(sk, skb);
-		goto discard;
-	}
-
-	if (th->rst) {
-		tcp_reset(sk);
-		goto discard;
-	}
-
-	tcp_replace_ts_recent(tp, TCP_SKB_CB(skb)->seq);
-
-	if (th->syn && !before(TCP_SKB_CB(skb)->seq, tp->rcv_nxt)) {
-		TCP_INC_STATS_BH(sock_net(sk), TCP_MIB_INERRS);
-		NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPABORTONSYN);
-		tcp_reset(sk);
-		return 1;
-	}
+	res = tcp_validate_incoming(sk, skb, th, 1);
+	if (res <= 0)
+		return -res;
 
 step5:
 	if (th->ack)
@@ -5225,6 +5265,7 @@
 	struct tcp_sock *tp = tcp_sk(sk);
 	struct inet_connection_sock *icsk = inet_csk(sk);
 	int queued = 0;
+	int res;
 
 	tp->rx_opt.saw_tstamp = 0;
 
@@ -5277,42 +5318,9 @@
 		return 0;
 	}
 
-	if (tcp_fast_parse_options(skb, th, tp) && tp->rx_opt.saw_tstamp &&
-	    tcp_paws_discard(sk, skb)) {
-		if (!th->rst) {
-			NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_PAWSESTABREJECTED);
-			tcp_send_dupack(sk, skb);
-			goto discard;
-		}
-		/* Reset is accepted even if it did not pass PAWS. */
-	}
-
-	/* step 1: check sequence number */
-	if (!tcp_sequence(tp, TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->end_seq)) {
-		if (!th->rst)
-			tcp_send_dupack(sk, skb);
-		goto discard;
-	}
-
-	/* step 2: check RST bit */
-	if (th->rst) {
-		tcp_reset(sk);
-		goto discard;
-	}
-
-	tcp_replace_ts_recent(tp, TCP_SKB_CB(skb)->seq);
-
-	/* step 3: check security and precedence [ignored] */
-
-	/*	step 4:
-	 *
-	 *	Check for a SYN in window.
-	 */
-	if (th->syn && !before(TCP_SKB_CB(skb)->seq, tp->rcv_nxt)) {
-		NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPABORTONSYN);
-		tcp_reset(sk);
-		return 1;
-	}
+	res = tcp_validate_incoming(sk, skb, th, 0);
+	if (res <= 0)
+		return -res;
 
 	/* step 5: check the ACK field */
 	if (th->ack) {
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index 1b4fee2..5c8fa7f 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -583,14 +583,15 @@
 		rep.th.doff = arg.iov[0].iov_len / 4;
 
 		tcp_v4_md5_hash_hdr((__u8 *) &rep.opt[1],
-				     key, ip_hdr(skb)->daddr,
-				     ip_hdr(skb)->saddr, &rep.th);
+				     key, ip_hdr(skb)->saddr,
+				     ip_hdr(skb)->daddr, &rep.th);
 	}
 #endif
 	arg.csum = csum_tcpudp_nofold(ip_hdr(skb)->daddr,
 				      ip_hdr(skb)->saddr, /* XXX */
-				      sizeof(struct tcphdr), IPPROTO_TCP, 0);
+				      arg.iov[0].iov_len, IPPROTO_TCP, 0);
 	arg.csumoffset = offsetof(struct tcphdr, check) / 2;
+	arg.flags = (sk && inet_sk(sk)->transparent) ? IP_REPLY_ARG_NOSRCCHECK : 0;
 
 	net = dev_net(skb->dst->dev);
 	ip_send_reply(net->ipv4.tcp_sock, skb,
@@ -606,7 +607,8 @@
 
 static void tcp_v4_send_ack(struct sk_buff *skb, u32 seq, u32 ack,
 			    u32 win, u32 ts, int oif,
-			    struct tcp_md5sig_key *key)
+			    struct tcp_md5sig_key *key,
+			    int reply_flags)
 {
 	struct tcphdr *th = tcp_hdr(skb);
 	struct {
@@ -618,7 +620,7 @@
 			];
 	} rep;
 	struct ip_reply_arg arg;
-	struct net *net = dev_net(skb->dev);
+	struct net *net = dev_net(skb->dst->dev);
 
 	memset(&rep.th, 0, sizeof(struct tcphdr));
 	memset(&arg, 0, sizeof(arg));
@@ -659,6 +661,7 @@
 				    ip_hdr(skb)->daddr, &rep.th);
 	}
 #endif
+	arg.flags = reply_flags;
 	arg.csum = csum_tcpudp_nofold(ip_hdr(skb)->daddr,
 				      ip_hdr(skb)->saddr, /* XXX */
 				      arg.iov[0].iov_len, IPPROTO_TCP, 0);
@@ -681,7 +684,8 @@
 			tcptw->tw_rcv_wnd >> tw->tw_rcv_wscale,
 			tcptw->tw_ts_recent,
 			tw->tw_bound_dev_if,
-			tcp_twsk_md5_key(tcptw)
+			tcp_twsk_md5_key(tcptw),
+			tw->tw_transparent ? IP_REPLY_ARG_NOSRCCHECK : 0
 			);
 
 	inet_twsk_put(tw);
@@ -694,7 +698,8 @@
 			tcp_rsk(req)->rcv_isn + 1, req->rcv_wnd,
 			req->ts_recent,
 			0,
-			tcp_v4_md5_do_lookup(sk, ip_hdr(skb)->daddr));
+			tcp_v4_md5_do_lookup(sk, ip_hdr(skb)->daddr),
+			inet_rsk(req)->no_srccheck ? IP_REPLY_ARG_NOSRCCHECK : 0);
 }
 
 /*
@@ -1244,6 +1249,7 @@
 	ireq = inet_rsk(req);
 	ireq->loc_addr = daddr;
 	ireq->rmt_addr = saddr;
+	ireq->no_srccheck = inet_sk(sk)->transparent;
 	ireq->opt = tcp_v4_save_options(sk, skb);
 	if (!want_cookie)
 		TCP_ECN_create_request(req, tcp_hdr(skb));
@@ -1364,6 +1370,10 @@
 	tcp_mtup_init(newsk);
 	tcp_sync_mss(newsk, dst_mtu(dst));
 	newtp->advmss = dst_metric(dst, RTAX_ADVMSS);
+	if (tcp_sk(sk)->rx_opt.user_mss &&
+	    tcp_sk(sk)->rx_opt.user_mss < newtp->advmss)
+		newtp->advmss = tcp_sk(sk)->rx_opt.user_mss;
+
 	tcp_initialize_rcv_mss(newsk);
 
 #ifdef CONFIG_TCP_MD5SIG
@@ -1567,8 +1577,7 @@
 	TCP_SKB_CB(skb)->flags	 = iph->tos;
 	TCP_SKB_CB(skb)->sacked	 = 0;
 
-	sk = __inet_lookup(net, &tcp_hashinfo, iph->saddr,
-			th->source, iph->daddr, th->dest, inet_iif(skb));
+	sk = __inet_lookup_skb(&tcp_hashinfo, skb, th->source, th->dest);
 	if (!sk)
 		goto no_tcp_socket;
 
@@ -1946,6 +1955,12 @@
 	return rc;
 }
 
+static inline int empty_bucket(struct tcp_iter_state *st)
+{
+	return hlist_empty(&tcp_hashinfo.ehash[st->bucket].chain) &&
+		hlist_empty(&tcp_hashinfo.ehash[st->bucket].twchain);
+}
+
 static void *established_get_first(struct seq_file *seq)
 {
 	struct tcp_iter_state* st = seq->private;
@@ -1958,6 +1973,10 @@
 		struct inet_timewait_sock *tw;
 		rwlock_t *lock = inet_ehash_lockp(&tcp_hashinfo, st->bucket);
 
+		/* Lockless fast path for the common case of empty buckets */
+		if (empty_bucket(st))
+			continue;
+
 		read_lock_bh(lock);
 		sk_for_each(sk, node, &tcp_hashinfo.ehash[st->bucket].chain) {
 			if (sk->sk_family != st->family ||
@@ -2008,13 +2027,15 @@
 		read_unlock_bh(inet_ehash_lockp(&tcp_hashinfo, st->bucket));
 		st->state = TCP_SEQ_STATE_ESTABLISHED;
 
-		if (++st->bucket < tcp_hashinfo.ehash_size) {
-			read_lock_bh(inet_ehash_lockp(&tcp_hashinfo, st->bucket));
-			sk = sk_head(&tcp_hashinfo.ehash[st->bucket].chain);
-		} else {
-			cur = NULL;
-			goto out;
-		}
+		/* Look for next non empty bucket */
+		while (++st->bucket < tcp_hashinfo.ehash_size &&
+				empty_bucket(st))
+			;
+		if (st->bucket >= tcp_hashinfo.ehash_size)
+			return NULL;
+
+		read_lock_bh(inet_ehash_lockp(&tcp_hashinfo, st->bucket));
+		sk = sk_head(&tcp_hashinfo.ehash[st->bucket].chain);
 	} else
 		sk = sk_next(sk);
 
diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c
index f976fc5..779f2e9 100644
--- a/net/ipv4/tcp_minisocks.c
+++ b/net/ipv4/tcp_minisocks.c
@@ -395,6 +395,7 @@
 		newtp->pred_flags = 0;
 		newtp->rcv_wup = newtp->copied_seq = newtp->rcv_nxt = treq->rcv_isn + 1;
 		newtp->snd_sml = newtp->snd_una = newtp->snd_nxt = treq->snt_isn + 1;
+		newtp->snd_up = treq->snt_isn + 1;
 
 		tcp_prequeue_init(newtp);
 
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
index 8165f5a..990a584 100644
--- a/net/ipv4/tcp_output.c
+++ b/net/ipv4/tcp_output.c
@@ -345,6 +345,11 @@
 	TCP_SKB_CB(skb)->end_seq = seq;
 }
 
+static inline int tcp_urg_mode(const struct tcp_sock *tp)
+{
+	return tp->snd_una != tp->snd_up;
+}
+
 #define OPTION_SACK_ADVERTISE	(1 << 0)
 #define OPTION_TS		(1 << 1)
 #define OPTION_MD5		(1 << 2)
@@ -646,7 +651,8 @@
 	th->check		= 0;
 	th->urg_ptr		= 0;
 
-	if (unlikely(tp->urg_mode &&
+	/* The urg_mode check is necessary during a below snd_una win probe */
+	if (unlikely(tcp_urg_mode(tp) &&
 		     between(tp->snd_up, tcb->seq + 1, tcb->seq + 0xFFFF))) {
 		th->urg_ptr		= htons(tp->snd_up - tcb->seq);
 		th->urg			= 1;
@@ -1012,7 +1018,7 @@
 /* Compute the current effective MSS, taking SACKs and IP options,
  * and even PMTU discovery events into account.
  *
- * LARGESEND note: !urg_mode is overkill, only frames up to snd_up
+ * LARGESEND note: !tcp_urg_mode is overkill, only frames up to snd_up
  * cannot be large. However, taking into account rare use of URG, this
  * is not a big flaw.
  */
@@ -1029,7 +1035,7 @@
 
 	mss_now = tp->mss_cache;
 
-	if (large_allowed && sk_can_gso(sk) && !tp->urg_mode)
+	if (large_allowed && sk_can_gso(sk) && !tcp_urg_mode(tp))
 		doing_tso = 1;
 
 	if (dst) {
@@ -1193,7 +1199,7 @@
 	/* Don't use the nagle rule for urgent data (or for the final FIN).
 	 * Nagle can be ignored during F-RTO too (see RFC4138).
 	 */
-	if (tp->urg_mode || (tp->frto_counter == 2) ||
+	if (tcp_urg_mode(tp) || (tp->frto_counter == 2) ||
 	    (TCP_SKB_CB(skb)->flags & TCPCB_FLAG_FIN))
 		return 1;
 
@@ -1824,6 +1830,8 @@
 
 	/* changed transmit queue under us so clear hints */
 	tcp_clear_retrans_hints_partial(tp);
+	if (next_skb == tp->retransmit_skb_hint)
+		tp->retransmit_skb_hint = skb;
 
 	sk_wmem_free_skb(sk, next_skb);
 }
@@ -1838,7 +1846,7 @@
 	struct tcp_sock *tp = tcp_sk(sk);
 	struct sk_buff *skb;
 	unsigned int mss = tcp_current_mss(sk, 0);
-	int lost = 0;
+	u32 prior_lost = tp->lost_out;
 
 	tcp_for_write_queue(skb, sk) {
 		if (skb == tcp_send_head(sk))
@@ -1849,17 +1857,13 @@
 				TCP_SKB_CB(skb)->sacked &= ~TCPCB_SACKED_RETRANS;
 				tp->retrans_out -= tcp_skb_pcount(skb);
 			}
-			if (!(TCP_SKB_CB(skb)->sacked & TCPCB_LOST)) {
-				TCP_SKB_CB(skb)->sacked |= TCPCB_LOST;
-				tp->lost_out += tcp_skb_pcount(skb);
-				lost = 1;
-			}
+			tcp_skb_mark_lost_uncond_verify(tp, skb);
 		}
 	}
 
-	tcp_clear_all_retrans_hints(tp);
+	tcp_clear_retrans_hints_partial(tp);
 
-	if (!lost)
+	if (prior_lost == tp->lost_out)
 		return;
 
 	if (tcp_is_reno(tp))
@@ -1934,8 +1938,8 @@
 	/* Collapse two adjacent packets if worthwhile and we can. */
 	if (!(TCP_SKB_CB(skb)->flags & TCPCB_FLAG_SYN) &&
 	    (skb->len < (cur_mss >> 1)) &&
-	    (tcp_write_queue_next(sk, skb) != tcp_send_head(sk)) &&
 	    (!tcp_skb_is_last(sk, skb)) &&
+	    (tcp_write_queue_next(sk, skb) != tcp_send_head(sk)) &&
 	    (skb_shinfo(skb)->nr_frags == 0 &&
 	     skb_shinfo(tcp_write_queue_next(sk, skb))->nr_frags == 0) &&
 	    (tcp_skb_pcount(skb) == 1 &&
@@ -1996,6 +2000,33 @@
 	return err;
 }
 
+static int tcp_can_forward_retransmit(struct sock *sk)
+{
+	const struct inet_connection_sock *icsk = inet_csk(sk);
+	struct tcp_sock *tp = tcp_sk(sk);
+
+	/* Forward retransmissions are possible only during Recovery. */
+	if (icsk->icsk_ca_state != TCP_CA_Recovery)
+		return 0;
+
+	/* No forward retransmissions in Reno are possible. */
+	if (tcp_is_reno(tp))
+		return 0;
+
+	/* Yeah, we have to make difficult choice between forward transmission
+	 * and retransmission... Both ways have their merits...
+	 *
+	 * For now we do not retransmit anything, while we have some new
+	 * segments to send. In the other cases, follow rule 3 for
+	 * NextSeg() specified in RFC3517.
+	 */
+
+	if (tcp_may_send_now(sk))
+		return 0;
+
+	return 1;
+}
+
 /* This gets called after a retransmit timeout, and the initially
  * retransmitted data is acknowledged.  It tries to continue
  * resending the rest of the retransmit queue, until either
@@ -2009,120 +2040,86 @@
 	const struct inet_connection_sock *icsk = inet_csk(sk);
 	struct tcp_sock *tp = tcp_sk(sk);
 	struct sk_buff *skb;
-	int packet_cnt;
+	struct sk_buff *hole = NULL;
+	u32 last_lost;
+	int mib_idx;
+	int fwd_rexmitting = 0;
+
+	if (!tp->lost_out)
+		tp->retransmit_high = tp->snd_una;
 
 	if (tp->retransmit_skb_hint) {
 		skb = tp->retransmit_skb_hint;
-		packet_cnt = tp->retransmit_cnt_hint;
+		last_lost = TCP_SKB_CB(skb)->end_seq;
+		if (after(last_lost, tp->retransmit_high))
+			last_lost = tp->retransmit_high;
 	} else {
 		skb = tcp_write_queue_head(sk);
-		packet_cnt = 0;
+		last_lost = tp->snd_una;
 	}
 
 	/* First pass: retransmit lost packets. */
-	if (tp->lost_out) {
-		tcp_for_write_queue_from(skb, sk) {
-			__u8 sacked = TCP_SKB_CB(skb)->sacked;
-
-			if (skb == tcp_send_head(sk))
-				break;
-			/* we could do better than to assign each time */
-			tp->retransmit_skb_hint = skb;
-			tp->retransmit_cnt_hint = packet_cnt;
-
-			/* Assume this retransmit will generate
-			 * only one packet for congestion window
-			 * calculation purposes.  This works because
-			 * tcp_retransmit_skb() will chop up the
-			 * packet to be MSS sized and all the
-			 * packet counting works out.
-			 */
-			if (tcp_packets_in_flight(tp) >= tp->snd_cwnd)
-				return;
-
-			if (sacked & TCPCB_LOST) {
-				if (!(sacked & (TCPCB_SACKED_ACKED|TCPCB_SACKED_RETRANS))) {
-					int mib_idx;
-
-					if (tcp_retransmit_skb(sk, skb)) {
-						tp->retransmit_skb_hint = NULL;
-						return;
-					}
-					if (icsk->icsk_ca_state != TCP_CA_Loss)
-						mib_idx = LINUX_MIB_TCPFASTRETRANS;
-					else
-						mib_idx = LINUX_MIB_TCPSLOWSTARTRETRANS;
-					NET_INC_STATS_BH(sock_net(sk), mib_idx);
-
-					if (skb == tcp_write_queue_head(sk))
-						inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS,
-									  inet_csk(sk)->icsk_rto,
-									  TCP_RTO_MAX);
-				}
-
-				packet_cnt += tcp_skb_pcount(skb);
-				if (packet_cnt >= tp->lost_out)
-					break;
-			}
-		}
-	}
-
-	/* OK, demanded retransmission is finished. */
-
-	/* Forward retransmissions are possible only during Recovery. */
-	if (icsk->icsk_ca_state != TCP_CA_Recovery)
-		return;
-
-	/* No forward retransmissions in Reno are possible. */
-	if (tcp_is_reno(tp))
-		return;
-
-	/* Yeah, we have to make difficult choice between forward transmission
-	 * and retransmission... Both ways have their merits...
-	 *
-	 * For now we do not retransmit anything, while we have some new
-	 * segments to send. In the other cases, follow rule 3 for
-	 * NextSeg() specified in RFC3517.
-	 */
-
-	if (tcp_may_send_now(sk))
-		return;
-
-	/* If nothing is SACKed, highest_sack in the loop won't be valid */
-	if (!tp->sacked_out)
-		return;
-
-	if (tp->forward_skb_hint)
-		skb = tp->forward_skb_hint;
-	else
-		skb = tcp_write_queue_head(sk);
-
 	tcp_for_write_queue_from(skb, sk) {
+		__u8 sacked = TCP_SKB_CB(skb)->sacked;
+
 		if (skb == tcp_send_head(sk))
 			break;
-		tp->forward_skb_hint = skb;
+		/* we could do better than to assign each time */
+		if (hole == NULL)
+			tp->retransmit_skb_hint = skb;
 
-		if (!before(TCP_SKB_CB(skb)->seq, tcp_highest_sack_seq(tp)))
-			break;
-
+		/* Assume this retransmit will generate
+		 * only one packet for congestion window
+		 * calculation purposes.  This works because
+		 * tcp_retransmit_skb() will chop up the
+		 * packet to be MSS sized and all the
+		 * packet counting works out.
+		 */
 		if (tcp_packets_in_flight(tp) >= tp->snd_cwnd)
-			break;
+			return;
 
-		if (TCP_SKB_CB(skb)->sacked & TCPCB_TAGBITS)
+		if (fwd_rexmitting) {
+begin_fwd:
+			if (!before(TCP_SKB_CB(skb)->seq, tcp_highest_sack_seq(tp)))
+				break;
+			mib_idx = LINUX_MIB_TCPFORWARDRETRANS;
+
+		} else if (!before(TCP_SKB_CB(skb)->seq, tp->retransmit_high)) {
+			tp->retransmit_high = last_lost;
+			if (!tcp_can_forward_retransmit(sk))
+				break;
+			/* Backtrack if necessary to non-L'ed skb */
+			if (hole != NULL) {
+				skb = hole;
+				hole = NULL;
+			}
+			fwd_rexmitting = 1;
+			goto begin_fwd;
+
+		} else if (!(sacked & TCPCB_LOST)) {
+			if (hole == NULL && !(sacked & TCPCB_SACKED_RETRANS))
+				hole = skb;
 			continue;
 
-		/* Ok, retransmit it. */
-		if (tcp_retransmit_skb(sk, skb)) {
-			tp->forward_skb_hint = NULL;
-			break;
+		} else {
+			last_lost = TCP_SKB_CB(skb)->end_seq;
+			if (icsk->icsk_ca_state != TCP_CA_Loss)
+				mib_idx = LINUX_MIB_TCPFASTRETRANS;
+			else
+				mib_idx = LINUX_MIB_TCPSLOWSTARTRETRANS;
 		}
 
+		if (sacked & (TCPCB_SACKED_ACKED|TCPCB_SACKED_RETRANS))
+			continue;
+
+		if (tcp_retransmit_skb(sk, skb))
+			return;
+		NET_INC_STATS_BH(sock_net(sk), mib_idx);
+
 		if (skb == tcp_write_queue_head(sk))
 			inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS,
 						  inet_csk(sk)->icsk_rto,
 						  TCP_RTO_MAX);
-
-		NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPFORWARDRETRANS);
 	}
 }
 
@@ -2241,6 +2238,7 @@
 	struct sk_buff *skb;
 	struct tcp_md5sig_key *md5;
 	__u8 *md5_hash_location;
+	int mss;
 
 	skb = sock_wmalloc(sk, MAX_TCP_HEADER + 15, 1, GFP_ATOMIC);
 	if (skb == NULL)
@@ -2251,13 +2249,17 @@
 
 	skb->dst = dst_clone(dst);
 
+	mss = dst_metric(dst, RTAX_ADVMSS);
+	if (tp->rx_opt.user_mss && tp->rx_opt.user_mss < mss)
+		mss = tp->rx_opt.user_mss;
+
 	if (req->rcv_wnd == 0) { /* ignored for retransmitted syns */
 		__u8 rcv_wscale;
 		/* Set this up on the first call only */
 		req->window_clamp = tp->window_clamp ? : dst_metric(dst, RTAX_WINDOW);
 		/* tcp_full_space because it is guaranteed to be the first packet */
 		tcp_select_initial_window(tcp_full_space(sk),
-			dst_metric(dst, RTAX_ADVMSS) - (ireq->tstamp_ok ? TCPOLEN_TSTAMP_ALIGNED : 0),
+			mss - (ireq->tstamp_ok ? TCPOLEN_TSTAMP_ALIGNED : 0),
 			&req->rcv_wnd,
 			&req->window_clamp,
 			ireq->wscale_ok,
@@ -2267,8 +2269,7 @@
 
 	memset(&opts, 0, sizeof(opts));
 	TCP_SKB_CB(skb)->when = tcp_time_stamp;
-	tcp_header_size = tcp_synack_options(sk, req,
-					     dst_metric(dst, RTAX_ADVMSS),
+	tcp_header_size = tcp_synack_options(sk, req, mss,
 					     skb, &opts, &md5) +
 			  sizeof(struct tcphdr);
 
@@ -2280,7 +2281,7 @@
 	th->syn = 1;
 	th->ack = 1;
 	TCP_ECN_make_synack(req, th);
-	th->source = inet_sk(sk)->sport;
+	th->source = ireq->loc_port;
 	th->dest = ireq->rmt_port;
 	/* Setting of flags are superfluous here for callers (and ECE is
 	 * not even correctly set)
@@ -2342,6 +2343,9 @@
 	if (!tp->window_clamp)
 		tp->window_clamp = dst_metric(dst, RTAX_WINDOW);
 	tp->advmss = dst_metric(dst, RTAX_ADVMSS);
+	if (tp->rx_opt.user_mss && tp->rx_opt.user_mss < tp->advmss)
+		tp->advmss = tp->rx_opt.user_mss;
+
 	tcp_initialize_rcv_mss(sk);
 
 	tcp_select_initial_window(tcp_full_space(sk),
@@ -2360,6 +2364,7 @@
 	tcp_init_wl(tp, tp->write_seq, 0);
 	tp->snd_una = tp->write_seq;
 	tp->snd_sml = tp->write_seq;
+	tp->snd_up = tp->write_seq;
 	tp->rcv_nxt = 0;
 	tp->rcv_wup = 0;
 	tp->copied_seq = 0;
@@ -2569,8 +2574,7 @@
 			tcp_event_new_data_sent(sk, skb);
 		return err;
 	} else {
-		if (tp->urg_mode &&
-		    between(tp->snd_up, tp->snd_una + 1, tp->snd_una + 0xFFFF))
+		if (between(tp->snd_up, tp->snd_una + 1, tp->snd_una + 0xFFFF))
 			tcp_xmit_probe_skb(sk, 1);
 		return tcp_xmit_probe_skb(sk, 0);
 	}
diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c
index 5ab6ba1..6b6dff1 100644
--- a/net/ipv4/tcp_timer.c
+++ b/net/ipv4/tcp_timer.c
@@ -201,7 +201,7 @@
 		NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPSCHEDULERFAILED);
 
 		while ((skb = __skb_dequeue(&tp->ucopy.prequeue)) != NULL)
-			sk->sk_backlog_rcv(sk, skb);
+			sk_backlog_rcv(sk, skb);
 
 		tp->ucopy.memory = 0;
 	}
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index 8e42fbb..2095abc 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -8,7 +8,7 @@
  * Authors:	Ross Biro
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
  *		Arnt Gulbrandsen, <agulbra@nvg.unit.no>
- *		Alan Cox, <Alan.Cox@linux.org>
+ *		Alan Cox, <alan@lxorguk.ukuu.org.uk>
  *		Hirokazu Takahashi, <taka@valinux.co.jp>
  *
  * Fixes:
@@ -108,9 +108,6 @@
  *	Snmp MIB for the UDP layer
  */
 
-DEFINE_SNMP_STAT(struct udp_mib, udp_stats_in6) __read_mostly;
-EXPORT_SYMBOL(udp_stats_in6);
-
 struct hlist_head udp_hash[UDP_HTABLE_SIZE];
 DEFINE_RWLOCK(udp_hash_lock);
 
@@ -125,14 +122,23 @@
 atomic_t udp_memory_allocated;
 EXPORT_SYMBOL(udp_memory_allocated);
 
-static inline int __udp_lib_lport_inuse(struct net *net, __u16 num,
-					const struct hlist_head udptable[])
+static int udp_lib_lport_inuse(struct net *net, __u16 num,
+			       const struct hlist_head udptable[],
+			       struct sock *sk,
+			       int (*saddr_comp)(const struct sock *sk1,
+						 const struct sock *sk2))
 {
-	struct sock *sk;
+	struct sock *sk2;
 	struct hlist_node *node;
 
-	sk_for_each(sk, node, &udptable[udp_hashfn(net, num)])
-		if (net_eq(sock_net(sk), net) && sk->sk_hash == num)
+	sk_for_each(sk2, node, &udptable[udp_hashfn(net, num)])
+		if (net_eq(sock_net(sk2), net)			&&
+		    sk2 != sk					&&
+		    sk2->sk_hash == num				&&
+		    (!sk2->sk_reuse || !sk->sk_reuse)		&&
+		    (!sk2->sk_bound_dev_if || !sk->sk_bound_dev_if
+			|| sk2->sk_bound_dev_if == sk->sk_bound_dev_if) &&
+		    (*saddr_comp)(sk, sk2))
 			return 1;
 	return 0;
 }
@@ -149,83 +155,37 @@
 					 const struct sock *sk2 )    )
 {
 	struct hlist_head *udptable = sk->sk_prot->h.udp_hash;
-	struct hlist_node *node;
-	struct hlist_head *head;
-	struct sock *sk2;
 	int    error = 1;
 	struct net *net = sock_net(sk);
 
 	write_lock_bh(&udp_hash_lock);
 
 	if (!snum) {
-		int i, low, high, remaining;
-		unsigned rover, best, best_size_so_far;
+		int low, high, remaining;
+		unsigned rand;
+		unsigned short first;
 
 		inet_get_local_port_range(&low, &high);
 		remaining = (high - low) + 1;
 
-		best_size_so_far = UINT_MAX;
-		best = rover = net_random() % remaining + low;
-
-		/* 1st pass: look for empty (or shortest) hash chain */
-		for (i = 0; i < UDP_HTABLE_SIZE; i++) {
-			int size = 0;
-
-			head = &udptable[udp_hashfn(net, rover)];
-			if (hlist_empty(head))
-				goto gotit;
-
-			sk_for_each(sk2, node, head) {
-				if (++size >= best_size_so_far)
-					goto next;
-			}
-			best_size_so_far = size;
-			best = rover;
-		next:
-			/* fold back if end of range */
-			if (++rover > high)
-				rover = low + ((rover - low)
-					       & (UDP_HTABLE_SIZE - 1));
-
-
-		}
-
-		/* 2nd pass: find hole in shortest hash chain */
-		rover = best;
-		for (i = 0; i < (1 << 16) / UDP_HTABLE_SIZE; i++) {
-			if (! __udp_lib_lport_inuse(net, rover, udptable))
-				goto gotit;
-			rover += UDP_HTABLE_SIZE;
-			if (rover > high)
-				rover = low + ((rover - low)
-					       & (UDP_HTABLE_SIZE - 1));
-		}
-
-
-		/* All ports in use! */
-		goto fail;
-
-gotit:
-		snum = rover;
-	} else {
-		head = &udptable[udp_hashfn(net, snum)];
-
-		sk_for_each(sk2, node, head)
-			if (sk2->sk_hash == snum                             &&
-			    sk2 != sk                                        &&
-			    net_eq(sock_net(sk2), net)			     &&
-			    (!sk2->sk_reuse        || !sk->sk_reuse)         &&
-			    (!sk2->sk_bound_dev_if || !sk->sk_bound_dev_if
-			     || sk2->sk_bound_dev_if == sk->sk_bound_dev_if) &&
-			    (*saddr_comp)(sk, sk2)                             )
+		rand = net_random();
+		snum = first = rand % remaining + low;
+		rand |= 1;
+		while (udp_lib_lport_inuse(net, snum, udptable, sk,
+					   saddr_comp)) {
+			do {
+				snum = snum + rand;
+			} while (snum < low || snum > high);
+			if (snum == first)
 				goto fail;
-	}
+		}
+	} else if (udp_lib_lport_inuse(net, snum, udptable, sk, saddr_comp))
+		goto fail;
 
 	inet_sk(sk)->num = snum;
 	sk->sk_hash = snum;
 	if (sk_unhashed(sk)) {
-		head = &udptable[udp_hashfn(net, snum)];
-		sk_add_node(sk, head);
+		sk_add_node(sk, &udptable[udp_hashfn(net, snum)]);
 		sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1);
 	}
 	error = 0;
@@ -302,6 +262,28 @@
 	return result;
 }
 
+static inline struct sock *__udp4_lib_lookup_skb(struct sk_buff *skb,
+						 __be16 sport, __be16 dport,
+						 struct hlist_head udptable[])
+{
+	struct sock *sk;
+	const struct iphdr *iph = ip_hdr(skb);
+
+	if (unlikely(sk = skb_steal_sock(skb)))
+		return sk;
+	else
+		return __udp4_lib_lookup(dev_net(skb->dst->dev), iph->saddr, sport,
+					 iph->daddr, dport, inet_iif(skb),
+					 udptable);
+}
+
+struct sock *udp4_lib_lookup(struct net *net, __be32 saddr, __be16 sport,
+			     __be32 daddr, __be16 dport, int dif)
+{
+	return __udp4_lib_lookup(net, saddr, sport, daddr, dport, dif, udp_hash);
+}
+EXPORT_SYMBOL_GPL(udp4_lib_lookup);
+
 static inline struct sock *udp_v4_mcast_next(struct sock *sk,
 					     __be16 loc_port, __be32 loc_addr,
 					     __be16 rmt_port, __be32 rmt_addr,
@@ -951,6 +933,27 @@
 	return 0;
 }
 
+static int __udp_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
+{
+	int is_udplite = IS_UDPLITE(sk);
+	int rc;
+
+	if ((rc = sock_queue_rcv_skb(sk, skb)) < 0) {
+		/* Note that an ENOMEM error is charged twice */
+		if (rc == -ENOMEM)
+			UDP_INC_STATS_BH(sock_net(sk), UDP_MIB_RCVBUFERRORS,
+					 is_udplite);
+		goto drop;
+	}
+
+	return 0;
+
+drop:
+	UDP_INC_STATS_BH(sock_net(sk), UDP_MIB_INERRORS, is_udplite);
+	kfree_skb(skb);
+	return -1;
+}
+
 /* returns:
  *  -1: error
  *   0: success
@@ -989,9 +992,7 @@
 		    up->encap_rcv != NULL) {
 			int ret;
 
-			bh_unlock_sock(sk);
 			ret = (*up->encap_rcv)(sk, skb);
-			bh_lock_sock(sk);
 			if (ret <= 0) {
 				UDP_INC_STATS_BH(sock_net(sk),
 						 UDP_MIB_INDATAGRAMS,
@@ -1044,17 +1045,16 @@
 			goto drop;
 	}
 
-	if ((rc = sock_queue_rcv_skb(sk,skb)) < 0) {
-		/* Note that an ENOMEM error is charged twice */
-		if (rc == -ENOMEM) {
-			UDP_INC_STATS_BH(sock_net(sk),
-					UDP_MIB_RCVBUFERRORS, is_udplite);
-			atomic_inc(&sk->sk_drops);
-		}
-		goto drop;
-	}
+	rc = 0;
 
-	return 0;
+	bh_lock_sock(sk);
+	if (!sock_owned_by_user(sk))
+		rc = __udp_queue_rcv_skb(sk, skb);
+	else
+		sk_add_backlog(sk, skb);
+	bh_unlock_sock(sk);
+
+	return rc;
 
 drop:
 	UDP_INC_STATS_BH(sock_net(sk), UDP_MIB_INERRORS, is_udplite);
@@ -1092,15 +1092,7 @@
 				skb1 = skb_clone(skb, GFP_ATOMIC);
 
 			if (skb1) {
-				int ret = 0;
-
-				bh_lock_sock(sk);
-				if (!sock_owned_by_user(sk))
-					ret = udp_queue_rcv_skb(sk, skb1);
-				else
-					sk_add_backlog(sk, skb1);
-				bh_unlock_sock(sk);
-
+				int ret = udp_queue_rcv_skb(sk, skb1);
 				if (ret > 0)
 					/* we should probably re-process instead
 					 * of dropping packets here. */
@@ -1191,17 +1183,10 @@
 		return __udp4_lib_mcast_deliver(net, skb, uh,
 				saddr, daddr, udptable);
 
-	sk = __udp4_lib_lookup(net, saddr, uh->source, daddr,
-			uh->dest, inet_iif(skb), udptable);
+	sk = __udp4_lib_lookup_skb(skb, uh->source, uh->dest, udptable);
 
 	if (sk != NULL) {
-		int ret = 0;
-		bh_lock_sock(sk);
-		if (!sock_owned_by_user(sk))
-			ret = udp_queue_rcv_skb(sk, skb);
-		else
-			sk_add_backlog(sk, skb);
-		bh_unlock_sock(sk);
+		int ret = udp_queue_rcv_skb(sk, skb);
 		sock_put(sk);
 
 		/* a return value > 0 means to resubmit the input, but
@@ -1494,7 +1479,7 @@
 	.sendmsg	   = udp_sendmsg,
 	.recvmsg	   = udp_recvmsg,
 	.sendpage	   = udp_sendpage,
-	.backlog_rcv	   = udp_queue_rcv_skb,
+	.backlog_rcv	   = __udp_queue_rcv_skb,
 	.hash		   = udp_lib_hash,
 	.unhash		   = udp_lib_unhash,
 	.get_port	   = udp_v4_get_port,
diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c
index 95055f8..01edac8 100644
--- a/net/ipv6/af_inet6.c
+++ b/net/ipv6/af_inet6.c
@@ -50,6 +50,7 @@
 #include <net/ipip.h>
 #include <net/protocol.h>
 #include <net/inet_common.h>
+#include <net/route.h>
 #include <net/transp_v6.h>
 #include <net/ip6_route.h>
 #include <net/addrconf.h>
@@ -794,61 +795,55 @@
 	dev_remove_pack(&ipv6_packet_type);
 }
 
-static int __init init_ipv6_mibs(void)
+static int __net_init ipv6_init_mibs(struct net *net)
 {
-	if (snmp_mib_init((void **)ipv6_statistics,
-			  sizeof(struct ipstats_mib)) < 0)
-		goto err_ip_mib;
-	if (snmp_mib_init((void **)icmpv6_statistics,
-			  sizeof(struct icmpv6_mib)) < 0)
-		goto err_icmp_mib;
-	if (snmp_mib_init((void **)icmpv6msg_statistics,
-			  sizeof(struct icmpv6msg_mib)) < 0)
-		goto err_icmpmsg_mib;
-	if (snmp_mib_init((void **)udp_stats_in6, sizeof (struct udp_mib)) < 0)
-		goto err_udp_mib;
-	if (snmp_mib_init((void **)udplite_stats_in6,
+	if (snmp_mib_init((void **)net->mib.udp_stats_in6,
+			  sizeof (struct udp_mib)) < 0)
+		return -ENOMEM;
+	if (snmp_mib_init((void **)net->mib.udplite_stats_in6,
 			  sizeof (struct udp_mib)) < 0)
 		goto err_udplite_mib;
+	if (snmp_mib_init((void **)net->mib.ipv6_statistics,
+			  sizeof(struct ipstats_mib)) < 0)
+		goto err_ip_mib;
+	if (snmp_mib_init((void **)net->mib.icmpv6_statistics,
+			  sizeof(struct icmpv6_mib)) < 0)
+		goto err_icmp_mib;
+	if (snmp_mib_init((void **)net->mib.icmpv6msg_statistics,
+			  sizeof(struct icmpv6msg_mib)) < 0)
+		goto err_icmpmsg_mib;
 	return 0;
 
-err_udplite_mib:
-	snmp_mib_free((void **)udp_stats_in6);
-err_udp_mib:
-	snmp_mib_free((void **)icmpv6msg_statistics);
 err_icmpmsg_mib:
-	snmp_mib_free((void **)icmpv6_statistics);
+	snmp_mib_free((void **)net->mib.icmpv6_statistics);
 err_icmp_mib:
-	snmp_mib_free((void **)ipv6_statistics);
+	snmp_mib_free((void **)net->mib.ipv6_statistics);
 err_ip_mib:
+	snmp_mib_free((void **)net->mib.udplite_stats_in6);
+err_udplite_mib:
+	snmp_mib_free((void **)net->mib.udp_stats_in6);
 	return -ENOMEM;
-
 }
 
-static void cleanup_ipv6_mibs(void)
+static void __net_exit ipv6_cleanup_mibs(struct net *net)
 {
-	snmp_mib_free((void **)ipv6_statistics);
-	snmp_mib_free((void **)icmpv6_statistics);
-	snmp_mib_free((void **)icmpv6msg_statistics);
-	snmp_mib_free((void **)udp_stats_in6);
-	snmp_mib_free((void **)udplite_stats_in6);
+	snmp_mib_free((void **)net->mib.udp_stats_in6);
+	snmp_mib_free((void **)net->mib.udplite_stats_in6);
+	snmp_mib_free((void **)net->mib.ipv6_statistics);
+	snmp_mib_free((void **)net->mib.icmpv6_statistics);
+	snmp_mib_free((void **)net->mib.icmpv6msg_statistics);
 }
 
-static int inet6_net_init(struct net *net)
+static int __net_init inet6_net_init(struct net *net)
 {
 	int err = 0;
 
 	net->ipv6.sysctl.bindv6only = 0;
-	net->ipv6.sysctl.flush_delay = 0;
-	net->ipv6.sysctl.ip6_rt_max_size = 4096;
-	net->ipv6.sysctl.ip6_rt_gc_min_interval = HZ / 2;
-	net->ipv6.sysctl.ip6_rt_gc_timeout = 60*HZ;
-	net->ipv6.sysctl.ip6_rt_gc_interval = 30*HZ;
-	net->ipv6.sysctl.ip6_rt_gc_elasticity = 9;
-	net->ipv6.sysctl.ip6_rt_mtu_expires = 10*60*HZ;
-	net->ipv6.sysctl.ip6_rt_min_advmss = IPV6_MIN_MTU - 20 - 40;
 	net->ipv6.sysctl.icmpv6_time = 1*HZ;
 
+	err = ipv6_init_mibs(net);
+	if (err)
+		return err;
 #ifdef CONFIG_PROC_FS
 	err = udp6_proc_init(net);
 	if (err)
@@ -859,7 +854,6 @@
 	err = ac6_proc_init(net);
 	if (err)
 		goto proc_ac6_fail;
-out:
 #endif
 	return err;
 
@@ -868,7 +862,9 @@
 	tcp6_proc_exit(net);
 proc_tcp6_fail:
 	udp6_proc_exit(net);
-	goto out;
+out:
+	ipv6_cleanup_mibs(net);
+	return err;
 #endif
 }
 
@@ -879,6 +875,7 @@
 	tcp6_proc_exit(net);
 	ac6_proc_exit(net);
 #endif
+	ipv6_cleanup_mibs(net);
 }
 
 static struct pernet_operations inet6_net_ops = {
@@ -929,11 +926,6 @@
 	if (err)
 		goto out_sock_register_fail;
 
-	/* Initialise ipv6 mibs */
-	err = init_ipv6_mibs();
-	if (err)
-		goto out_unregister_sock;
-
 #ifdef CONFIG_SYSCTL
 	err = ipv6_static_sysctl_register();
 	if (err)
@@ -1067,8 +1059,6 @@
 	ipv6_static_sysctl_unregister();
 static_sysctl_fail:
 #endif
-	cleanup_ipv6_mibs();
-out_unregister_sock:
 	sock_unregister(PF_INET6);
 	rtnl_unregister_all(PF_INET6);
 out_sock_register_fail:
@@ -1125,7 +1115,6 @@
 #ifdef CONFIG_SYSCTL
 	ipv6_static_sysctl_unregister();
 #endif
-	cleanup_ipv6_mibs();
 	proto_unregister(&rawv6_prot);
 	proto_unregister(&udplitev6_prot);
 	proto_unregister(&udpv6_prot);
diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c
index 837c830..6bfffec 100644
--- a/net/ipv6/exthdrs.c
+++ b/net/ipv6/exthdrs.c
@@ -277,7 +277,7 @@
 	if (!pskb_may_pull(skb, skb_transport_offset(skb) + 8) ||
 	    !pskb_may_pull(skb, (skb_transport_offset(skb) +
 				 ((skb_transport_header(skb)[1] + 1) << 3)))) {
-		IP6_INC_STATS_BH(ip6_dst_idev(skb->dst),
+		IP6_INC_STATS_BH(dev_net(skb->dst->dev), ip6_dst_idev(skb->dst),
 				 IPSTATS_MIB_INHDRERRORS);
 		kfree_skb(skb);
 		return -1;
@@ -301,7 +301,8 @@
 		return 1;
 	}
 
-	IP6_INC_STATS_BH(ip6_dst_idev(dst), IPSTATS_MIB_INHDRERRORS);
+	IP6_INC_STATS_BH(dev_net(dst->dev),
+			 ip6_dst_idev(dst), IPSTATS_MIB_INHDRERRORS);
 	dst_release(dst);
 	return -1;
 }
@@ -319,7 +320,8 @@
 	int n, i;
 	struct ipv6_rt_hdr *hdr;
 	struct rt0_hdr *rthdr;
-	int accept_source_route = dev_net(skb->dev)->ipv6.devconf_all->accept_source_route;
+	struct net *net = dev_net(skb->dev);
+	int accept_source_route = net->ipv6.devconf_all->accept_source_route;
 
 	idev = in6_dev_get(skb->dev);
 	if (idev) {
@@ -331,7 +333,7 @@
 	if (!pskb_may_pull(skb, skb_transport_offset(skb) + 8) ||
 	    !pskb_may_pull(skb, (skb_transport_offset(skb) +
 				 ((skb_transport_header(skb)[1] + 1) << 3)))) {
-		IP6_INC_STATS_BH(ip6_dst_idev(skb->dst),
+		IP6_INC_STATS_BH(net, ip6_dst_idev(skb->dst),
 				 IPSTATS_MIB_INHDRERRORS);
 		kfree_skb(skb);
 		return -1;
@@ -341,7 +343,7 @@
 
 	if (ipv6_addr_is_multicast(&ipv6_hdr(skb)->daddr) ||
 	    skb->pkt_type != PACKET_HOST) {
-		IP6_INC_STATS_BH(ip6_dst_idev(skb->dst),
+		IP6_INC_STATS_BH(net, ip6_dst_idev(skb->dst),
 				 IPSTATS_MIB_INADDRERRORS);
 		kfree_skb(skb);
 		return -1;
@@ -356,7 +358,7 @@
 			 * processed by own
 			 */
 			if (!addr) {
-				IP6_INC_STATS_BH(ip6_dst_idev(skb->dst),
+				IP6_INC_STATS_BH(net, ip6_dst_idev(skb->dst),
 						 IPSTATS_MIB_INADDRERRORS);
 				kfree_skb(skb);
 				return -1;
@@ -382,7 +384,7 @@
 			goto unknown_rh;
 		/* Silently discard invalid RTH type 2 */
 		if (hdr->hdrlen != 2 || hdr->segments_left != 1) {
-			IP6_INC_STATS_BH(ip6_dst_idev(skb->dst),
+			IP6_INC_STATS_BH(net, ip6_dst_idev(skb->dst),
 					 IPSTATS_MIB_INHDRERRORS);
 			kfree_skb(skb);
 			return -1;
@@ -401,7 +403,7 @@
 	n = hdr->hdrlen >> 1;
 
 	if (hdr->segments_left > n) {
-		IP6_INC_STATS_BH(ip6_dst_idev(skb->dst),
+		IP6_INC_STATS_BH(net, ip6_dst_idev(skb->dst),
 				 IPSTATS_MIB_INHDRERRORS);
 		icmpv6_param_prob(skb, ICMPV6_HDR_FIELD,
 				  ((&hdr->segments_left) -
@@ -415,7 +417,7 @@
 	if (skb_cloned(skb)) {
 		/* the copy is a forwarded packet */
 		if (pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) {
-			IP6_INC_STATS_BH(ip6_dst_idev(skb->dst),
+			IP6_INC_STATS_BH(net, ip6_dst_idev(skb->dst),
 					 IPSTATS_MIB_OUTDISCARDS);
 			kfree_skb(skb);
 			return -1;
@@ -438,13 +440,13 @@
 		if (xfrm6_input_addr(skb, (xfrm_address_t *)addr,
 				     (xfrm_address_t *)&ipv6_hdr(skb)->saddr,
 				     IPPROTO_ROUTING) < 0) {
-			IP6_INC_STATS_BH(ip6_dst_idev(skb->dst),
+			IP6_INC_STATS_BH(net, ip6_dst_idev(skb->dst),
 					 IPSTATS_MIB_INADDRERRORS);
 			kfree_skb(skb);
 			return -1;
 		}
 		if (!ipv6_chk_home_addr(dev_net(skb->dst->dev), addr)) {
-			IP6_INC_STATS_BH(ip6_dst_idev(skb->dst),
+			IP6_INC_STATS_BH(net, ip6_dst_idev(skb->dst),
 					 IPSTATS_MIB_INADDRERRORS);
 			kfree_skb(skb);
 			return -1;
@@ -456,7 +458,7 @@
 	}
 
 	if (ipv6_addr_is_multicast(addr)) {
-		IP6_INC_STATS_BH(ip6_dst_idev(skb->dst),
+		IP6_INC_STATS_BH(net, ip6_dst_idev(skb->dst),
 				 IPSTATS_MIB_INADDRERRORS);
 		kfree_skb(skb);
 		return -1;
@@ -476,7 +478,7 @@
 
 	if (skb->dst->dev->flags&IFF_LOOPBACK) {
 		if (ipv6_hdr(skb)->hop_limit <= 1) {
-			IP6_INC_STATS_BH(ip6_dst_idev(skb->dst),
+			IP6_INC_STATS_BH(net, ip6_dst_idev(skb->dst),
 					 IPSTATS_MIB_INHDRERRORS);
 			icmpv6_send(skb, ICMPV6_TIME_EXCEED, ICMPV6_EXC_HOPLIMIT,
 				    0, skb->dev);
@@ -492,7 +494,7 @@
 	return -1;
 
 unknown_rh:
-	IP6_INC_STATS_BH(ip6_dst_idev(skb->dst), IPSTATS_MIB_INHDRERRORS);
+	IP6_INC_STATS_BH(net, ip6_dst_idev(skb->dst), IPSTATS_MIB_INHDRERRORS);
 	icmpv6_param_prob(skb, ICMPV6_HDR_FIELD,
 			  (&hdr->type) - skb_network_header(skb));
 	return -1;
@@ -579,29 +581,33 @@
 {
 	const unsigned char *nh = skb_network_header(skb);
 	u32 pkt_len;
+	struct net *net = dev_net(skb->dst->dev);
 
 	if (nh[optoff + 1] != 4 || (optoff & 3) != 2) {
 		LIMIT_NETDEBUG(KERN_DEBUG "ipv6_hop_jumbo: wrong jumbo opt length/alignment %d\n",
 			       nh[optoff+1]);
-		IP6_INC_STATS_BH(ipv6_skb_idev(skb),
+		IP6_INC_STATS_BH(net, ipv6_skb_idev(skb),
 				 IPSTATS_MIB_INHDRERRORS);
 		goto drop;
 	}
 
 	pkt_len = ntohl(*(__be32 *)(nh + optoff + 2));
 	if (pkt_len <= IPV6_MAXPLEN) {
-		IP6_INC_STATS_BH(ipv6_skb_idev(skb), IPSTATS_MIB_INHDRERRORS);
+		IP6_INC_STATS_BH(net, ipv6_skb_idev(skb),
+				 IPSTATS_MIB_INHDRERRORS);
 		icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, optoff+2);
 		return 0;
 	}
 	if (ipv6_hdr(skb)->payload_len) {
-		IP6_INC_STATS_BH(ipv6_skb_idev(skb), IPSTATS_MIB_INHDRERRORS);
+		IP6_INC_STATS_BH(net, ipv6_skb_idev(skb),
+				 IPSTATS_MIB_INHDRERRORS);
 		icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, optoff);
 		return 0;
 	}
 
 	if (pkt_len > skb->len - sizeof(struct ipv6hdr)) {
-		IP6_INC_STATS_BH(ipv6_skb_idev(skb), IPSTATS_MIB_INTRUNCATEDPKTS);
+		IP6_INC_STATS_BH(net, ipv6_skb_idev(skb),
+				 IPSTATS_MIB_INTRUNCATEDPKTS);
 		goto drop;
 	}
 
diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c
index b3157a0..9b7d19a 100644
--- a/net/ipv6/icmp.c
+++ b/net/ipv6/icmp.c
@@ -183,7 +183,7 @@
 	 */
 	dst = ip6_route_output(net, sk, fl);
 	if (dst->error) {
-		IP6_INC_STATS(ip6_dst_idev(dst),
+		IP6_INC_STATS(net, ip6_dst_idev(dst),
 			      IPSTATS_MIB_OUTNOROUTES);
 	} else if (dst->dev && (dst->dev->flags&IFF_LOOPBACK)) {
 		res = 1;
@@ -664,7 +664,7 @@
 		skb_set_network_header(skb, nh);
 	}
 
-	ICMP6_INC_STATS_BH(idev, ICMP6_MIB_INMSGS);
+	ICMP6_INC_STATS_BH(dev_net(dev), idev, ICMP6_MIB_INMSGS);
 
 	saddr = &ipv6_hdr(skb)->saddr;
 	daddr = &ipv6_hdr(skb)->daddr;
@@ -693,7 +693,7 @@
 
 	type = hdr->icmp6_type;
 
-	ICMP6MSGIN_INC_STATS_BH(idev, type);
+	ICMP6MSGIN_INC_STATS_BH(dev_net(dev), idev, type);
 
 	switch (type) {
 	case ICMPV6_ECHO_REQUEST:
@@ -772,7 +772,7 @@
 	return 0;
 
 discard_it:
-	ICMP6_INC_STATS_BH(idev, ICMP6_MIB_INERRORS);
+	ICMP6_INC_STATS_BH(dev_net(dev), idev, ICMP6_MIB_INERRORS);
 drop_no_count:
 	kfree_skb(skb);
 	return 0;
diff --git a/net/ipv6/ip6_input.c b/net/ipv6/ip6_input.c
index 7e14ccc..936f489 100644
--- a/net/ipv6/ip6_input.c
+++ b/net/ipv6/ip6_input.c
@@ -59,6 +59,7 @@
 	struct ipv6hdr *hdr;
 	u32 		pkt_len;
 	struct inet6_dev *idev;
+	struct net *net = dev_net(skb->dev);
 
 	if (skb->pkt_type == PACKET_OTHERHOST) {
 		kfree_skb(skb);
@@ -69,11 +70,11 @@
 
 	idev = __in6_dev_get(skb->dev);
 
-	IP6_INC_STATS_BH(idev, IPSTATS_MIB_INRECEIVES);
+	IP6_INC_STATS_BH(net, idev, IPSTATS_MIB_INRECEIVES);
 
 	if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL ||
 	    !idev || unlikely(idev->cnf.disable_ipv6)) {
-		IP6_INC_STATS_BH(idev, IPSTATS_MIB_INDISCARDS);
+		IP6_INC_STATS_BH(net, idev, IPSTATS_MIB_INDISCARDS);
 		rcu_read_unlock();
 		goto out;
 	}
@@ -118,11 +119,12 @@
 	/* pkt_len may be zero if Jumbo payload option is present */
 	if (pkt_len || hdr->nexthdr != NEXTHDR_HOP) {
 		if (pkt_len + sizeof(struct ipv6hdr) > skb->len) {
-			IP6_INC_STATS_BH(idev, IPSTATS_MIB_INTRUNCATEDPKTS);
+			IP6_INC_STATS_BH(net,
+					 idev, IPSTATS_MIB_INTRUNCATEDPKTS);
 			goto drop;
 		}
 		if (pskb_trim_rcsum(skb, pkt_len + sizeof(struct ipv6hdr))) {
-			IP6_INC_STATS_BH(idev, IPSTATS_MIB_INHDRERRORS);
+			IP6_INC_STATS_BH(net, idev, IPSTATS_MIB_INHDRERRORS);
 			goto drop;
 		}
 		hdr = ipv6_hdr(skb);
@@ -130,7 +132,7 @@
 
 	if (hdr->nexthdr == NEXTHDR_HOP) {
 		if (ipv6_parse_hopopts(skb) < 0) {
-			IP6_INC_STATS_BH(idev, IPSTATS_MIB_INHDRERRORS);
+			IP6_INC_STATS_BH(net, idev, IPSTATS_MIB_INHDRERRORS);
 			rcu_read_unlock();
 			return 0;
 		}
@@ -141,7 +143,7 @@
 	return NF_HOOK(PF_INET6, NF_INET_PRE_ROUTING, skb, dev, NULL,
 		       ip6_rcv_finish);
 err:
-	IP6_INC_STATS_BH(idev, IPSTATS_MIB_INHDRERRORS);
+	IP6_INC_STATS_BH(net, idev, IPSTATS_MIB_INHDRERRORS);
 drop:
 	rcu_read_unlock();
 	kfree_skb(skb);
@@ -161,6 +163,7 @@
 	int nexthdr, raw;
 	u8 hash;
 	struct inet6_dev *idev;
+	struct net *net = dev_net(skb->dst->dev);
 
 	/*
 	 *	Parse extension headers
@@ -205,24 +208,25 @@
 		if (ret > 0)
 			goto resubmit;
 		else if (ret == 0)
-			IP6_INC_STATS_BH(idev, IPSTATS_MIB_INDELIVERS);
+			IP6_INC_STATS_BH(net, idev, IPSTATS_MIB_INDELIVERS);
 	} else {
 		if (!raw) {
 			if (xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) {
-				IP6_INC_STATS_BH(idev, IPSTATS_MIB_INUNKNOWNPROTOS);
+				IP6_INC_STATS_BH(net, idev,
+						 IPSTATS_MIB_INUNKNOWNPROTOS);
 				icmpv6_send(skb, ICMPV6_PARAMPROB,
 					    ICMPV6_UNK_NEXTHDR, nhoff,
 					    skb->dev);
 			}
 		} else
-			IP6_INC_STATS_BH(idev, IPSTATS_MIB_INDELIVERS);
+			IP6_INC_STATS_BH(net, idev, IPSTATS_MIB_INDELIVERS);
 		kfree_skb(skb);
 	}
 	rcu_read_unlock();
 	return 0;
 
 discard:
-	IP6_INC_STATS_BH(idev, IPSTATS_MIB_INDISCARDS);
+	IP6_INC_STATS_BH(net, idev, IPSTATS_MIB_INDISCARDS);
 	rcu_read_unlock();
 	kfree_skb(skb);
 	return 0;
@@ -240,7 +244,8 @@
 	struct ipv6hdr *hdr;
 	int deliver;
 
-	IP6_INC_STATS_BH(ip6_dst_idev(skb->dst), IPSTATS_MIB_INMCASTPKTS);
+	IP6_INC_STATS_BH(dev_net(skb->dst->dev),
+			 ip6_dst_idev(skb->dst), IPSTATS_MIB_INMCASTPKTS);
 
 	hdr = ipv6_hdr(skb);
 	deliver = ipv6_chk_mcast_addr(skb->dev, &hdr->daddr, NULL);
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index 3df2c44..c77db0b 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -103,7 +103,8 @@
 	else if (dst->neighbour)
 		return dst->neighbour->output(skb);
 
-	IP6_INC_STATS_BH(ip6_dst_idev(dst), IPSTATS_MIB_OUTNOROUTES);
+	IP6_INC_STATS_BH(dev_net(dst->dev),
+			 ip6_dst_idev(dst), IPSTATS_MIB_OUTNOROUTES);
 	kfree_skb(skb);
 	return -EINVAL;
 
@@ -150,13 +151,14 @@
 					ip6_dev_loopback_xmit);
 
 			if (ipv6_hdr(skb)->hop_limit == 0) {
-				IP6_INC_STATS(idev, IPSTATS_MIB_OUTDISCARDS);
+				IP6_INC_STATS(dev_net(dev), idev,
+					      IPSTATS_MIB_OUTDISCARDS);
 				kfree_skb(skb);
 				return 0;
 			}
 		}
 
-		IP6_INC_STATS(idev, IPSTATS_MIB_OUTMCASTPKTS);
+		IP6_INC_STATS(dev_net(dev), idev, IPSTATS_MIB_OUTMCASTPKTS);
 	}
 
 	return NF_HOOK(PF_INET6, NF_INET_POST_ROUTING, skb, NULL, skb->dev,
@@ -175,7 +177,8 @@
 {
 	struct inet6_dev *idev = ip6_dst_idev(skb->dst);
 	if (unlikely(idev->cnf.disable_ipv6)) {
-		IP6_INC_STATS(idev, IPSTATS_MIB_OUTDISCARDS);
+		IP6_INC_STATS(dev_net(skb->dst->dev), idev,
+			      IPSTATS_MIB_OUTDISCARDS);
 		kfree_skb(skb);
 		return 0;
 	}
@@ -194,6 +197,7 @@
 int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl,
 	     struct ipv6_txoptions *opt, int ipfragok)
 {
+	struct net *net = sock_net(sk);
 	struct ipv6_pinfo *np = inet6_sk(sk);
 	struct in6_addr *first_hop = &fl->fl6_dst;
 	struct dst_entry *dst = skb->dst;
@@ -216,7 +220,7 @@
 		if (skb_headroom(skb) < head_room) {
 			struct sk_buff *skb2 = skb_realloc_headroom(skb, head_room);
 			if (skb2 == NULL) {
-				IP6_INC_STATS(ip6_dst_idev(skb->dst),
+				IP6_INC_STATS(net, ip6_dst_idev(skb->dst),
 					      IPSTATS_MIB_OUTDISCARDS);
 				kfree_skb(skb);
 				return -ENOBUFS;
@@ -270,7 +274,7 @@
 
 	mtu = dst_mtu(dst);
 	if ((skb->len <= mtu) || skb->local_df || skb_is_gso(skb)) {
-		IP6_INC_STATS(ip6_dst_idev(skb->dst),
+		IP6_INC_STATS(net, ip6_dst_idev(skb->dst),
 			      IPSTATS_MIB_OUTREQUESTS);
 		return NF_HOOK(PF_INET6, NF_INET_LOCAL_OUT, skb, NULL, dst->dev,
 				dst_output);
@@ -280,7 +284,7 @@
 		printk(KERN_DEBUG "IPv6: sending pkt_too_big to self\n");
 	skb->dev = dst->dev;
 	icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu, skb->dev);
-	IP6_INC_STATS(ip6_dst_idev(skb->dst), IPSTATS_MIB_FRAGFAILS);
+	IP6_INC_STATS(net, ip6_dst_idev(skb->dst), IPSTATS_MIB_FRAGFAILS);
 	kfree_skb(skb);
 	return -EMSGSIZE;
 }
@@ -422,7 +426,7 @@
 		goto drop;
 
 	if (!xfrm6_policy_check(NULL, XFRM_POLICY_FWD, skb)) {
-		IP6_INC_STATS(ip6_dst_idev(dst), IPSTATS_MIB_INDISCARDS);
+		IP6_INC_STATS(net, ip6_dst_idev(dst), IPSTATS_MIB_INDISCARDS);
 		goto drop;
 	}
 
@@ -455,7 +459,8 @@
 		skb->dev = dst->dev;
 		icmpv6_send(skb, ICMPV6_TIME_EXCEED, ICMPV6_EXC_HOPLIMIT,
 			    0, skb->dev);
-		IP6_INC_STATS_BH(ip6_dst_idev(dst), IPSTATS_MIB_INHDRERRORS);
+		IP6_INC_STATS_BH(net,
+				 ip6_dst_idev(dst), IPSTATS_MIB_INHDRERRORS);
 
 		kfree_skb(skb);
 		return -ETIMEDOUT;
@@ -468,13 +473,14 @@
 		if (proxied > 0)
 			return ip6_input(skb);
 		else if (proxied < 0) {
-			IP6_INC_STATS(ip6_dst_idev(dst), IPSTATS_MIB_INDISCARDS);
+			IP6_INC_STATS(net, ip6_dst_idev(dst),
+				      IPSTATS_MIB_INDISCARDS);
 			goto drop;
 		}
 	}
 
 	if (!xfrm6_route_forward(skb)) {
-		IP6_INC_STATS(ip6_dst_idev(dst), IPSTATS_MIB_INDISCARDS);
+		IP6_INC_STATS(net, ip6_dst_idev(dst), IPSTATS_MIB_INDISCARDS);
 		goto drop;
 	}
 	dst = skb->dst;
@@ -523,14 +529,16 @@
 		/* Again, force OUTPUT device used as source address */
 		skb->dev = dst->dev;
 		icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, dst_mtu(dst), skb->dev);
-		IP6_INC_STATS_BH(ip6_dst_idev(dst), IPSTATS_MIB_INTOOBIGERRORS);
-		IP6_INC_STATS_BH(ip6_dst_idev(dst), IPSTATS_MIB_FRAGFAILS);
+		IP6_INC_STATS_BH(net,
+				 ip6_dst_idev(dst), IPSTATS_MIB_INTOOBIGERRORS);
+		IP6_INC_STATS_BH(net,
+				 ip6_dst_idev(dst), IPSTATS_MIB_FRAGFAILS);
 		kfree_skb(skb);
 		return -EMSGSIZE;
 	}
 
 	if (skb_cow(skb, dst->dev->hard_header_len)) {
-		IP6_INC_STATS(ip6_dst_idev(dst), IPSTATS_MIB_OUTDISCARDS);
+		IP6_INC_STATS(net, ip6_dst_idev(dst), IPSTATS_MIB_OUTDISCARDS);
 		goto drop;
 	}
 
@@ -540,12 +548,12 @@
 
 	hdr->hop_limit--;
 
-	IP6_INC_STATS_BH(ip6_dst_idev(dst), IPSTATS_MIB_OUTFORWDATAGRAMS);
+	IP6_INC_STATS_BH(net, ip6_dst_idev(dst), IPSTATS_MIB_OUTFORWDATAGRAMS);
 	return NF_HOOK(PF_INET6, NF_INET_FORWARD, skb, skb->dev, dst->dev,
 		       ip6_forward_finish);
 
 error:
-	IP6_INC_STATS_BH(ip6_dst_idev(dst), IPSTATS_MIB_INADDRERRORS);
+	IP6_INC_STATS_BH(net, ip6_dst_idev(dst), IPSTATS_MIB_INADDRERRORS);
 drop:
 	kfree_skb(skb);
 	return -EINVAL;
@@ -613,7 +621,6 @@
 
 static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
 {
-	struct net_device *dev;
 	struct sk_buff *frag;
 	struct rt6_info *rt = (struct rt6_info*)skb->dst;
 	struct ipv6_pinfo *np = skb->sk ? inet6_sk(skb->sk) : NULL;
@@ -623,8 +630,8 @@
 	__be32 frag_id = 0;
 	int ptr, offset = 0, err=0;
 	u8 *prevhdr, nexthdr = 0;
+	struct net *net = dev_net(skb->dst->dev);
 
-	dev = rt->u.dst.dev;
 	hlen = ip6_find_1stfragopt(skb, &prevhdr);
 	nexthdr = *prevhdr;
 
@@ -637,7 +644,8 @@
 	if (!skb->local_df) {
 		skb->dev = skb->dst->dev;
 		icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu, skb->dev);
-		IP6_INC_STATS(ip6_dst_idev(skb->dst), IPSTATS_MIB_FRAGFAILS);
+		IP6_INC_STATS(net, ip6_dst_idev(skb->dst),
+			      IPSTATS_MIB_FRAGFAILS);
 		kfree_skb(skb);
 		return -EMSGSIZE;
 	}
@@ -686,7 +694,8 @@
 		*prevhdr = NEXTHDR_FRAGMENT;
 		tmp_hdr = kmemdup(skb_network_header(skb), hlen, GFP_ATOMIC);
 		if (!tmp_hdr) {
-			IP6_INC_STATS(ip6_dst_idev(skb->dst), IPSTATS_MIB_FRAGFAILS);
+			IP6_INC_STATS(net, ip6_dst_idev(skb->dst),
+				      IPSTATS_MIB_FRAGFAILS);
 			return -ENOMEM;
 		}
 
@@ -737,7 +746,8 @@
 
 			err = output(skb);
 			if(!err)
-				IP6_INC_STATS(ip6_dst_idev(&rt->u.dst), IPSTATS_MIB_FRAGCREATES);
+				IP6_INC_STATS(net, ip6_dst_idev(&rt->u.dst),
+					      IPSTATS_MIB_FRAGCREATES);
 
 			if (err || !frag)
 				break;
@@ -750,7 +760,8 @@
 		kfree(tmp_hdr);
 
 		if (err == 0) {
-			IP6_INC_STATS(ip6_dst_idev(&rt->u.dst), IPSTATS_MIB_FRAGOKS);
+			IP6_INC_STATS(net, ip6_dst_idev(&rt->u.dst),
+				      IPSTATS_MIB_FRAGOKS);
 			dst_release(&rt->u.dst);
 			return 0;
 		}
@@ -761,7 +772,8 @@
 			frag = skb;
 		}
 
-		IP6_INC_STATS(ip6_dst_idev(&rt->u.dst), IPSTATS_MIB_FRAGFAILS);
+		IP6_INC_STATS(net, ip6_dst_idev(&rt->u.dst),
+			      IPSTATS_MIB_FRAGFAILS);
 		dst_release(&rt->u.dst);
 		return err;
 	}
@@ -795,7 +807,7 @@
 
 		if ((frag = alloc_skb(len+hlen+sizeof(struct frag_hdr)+LL_ALLOCATED_SPACE(rt->u.dst.dev), GFP_ATOMIC)) == NULL) {
 			NETDEBUG(KERN_INFO "IPv6: frag: no memory for new fragment!\n");
-			IP6_INC_STATS(ip6_dst_idev(skb->dst),
+			IP6_INC_STATS(net, ip6_dst_idev(skb->dst),
 				      IPSTATS_MIB_FRAGFAILS);
 			err = -ENOMEM;
 			goto fail;
@@ -859,15 +871,16 @@
 		if (err)
 			goto fail;
 
-		IP6_INC_STATS(ip6_dst_idev(skb->dst), IPSTATS_MIB_FRAGCREATES);
+		IP6_INC_STATS(net, ip6_dst_idev(skb->dst),
+			      IPSTATS_MIB_FRAGCREATES);
 	}
-	IP6_INC_STATS(ip6_dst_idev(skb->dst),
+	IP6_INC_STATS(net, ip6_dst_idev(skb->dst),
 		      IPSTATS_MIB_FRAGOKS);
 	kfree_skb(skb);
 	return err;
 
 fail:
-	IP6_INC_STATS(ip6_dst_idev(skb->dst),
+	IP6_INC_STATS(net, ip6_dst_idev(skb->dst),
 		      IPSTATS_MIB_FRAGFAILS);
 	kfree_skb(skb);
 	return err;
@@ -982,7 +995,7 @@
 
 out_err_release:
 	if (err == -ENETUNREACH)
-		IP6_INC_STATS_BH(NULL, IPSTATS_MIB_OUTNOROUTES);
+		IP6_INC_STATS_BH(net, NULL, IPSTATS_MIB_OUTNOROUTES);
 	dst_release(*dst);
 	*dst = NULL;
 	return err;
@@ -1387,7 +1400,7 @@
 	return 0;
 error:
 	inet->cork.length -= length;
-	IP6_INC_STATS(rt->rt6i_idev, IPSTATS_MIB_OUTDISCARDS);
+	IP6_INC_STATS(sock_net(sk), rt->rt6i_idev, IPSTATS_MIB_OUTDISCARDS);
 	return err;
 }
 
@@ -1411,6 +1424,7 @@
 	struct in6_addr final_dst_buf, *final_dst = &final_dst_buf;
 	struct inet_sock *inet = inet_sk(sk);
 	struct ipv6_pinfo *np = inet6_sk(sk);
+	struct net *net = sock_net(sk);
 	struct ipv6hdr *hdr;
 	struct ipv6_txoptions *opt = np->cork.opt;
 	struct rt6_info *rt = (struct rt6_info *)inet->cork.dst;
@@ -1464,12 +1478,12 @@
 	skb->mark = sk->sk_mark;
 
 	skb->dst = dst_clone(&rt->u.dst);
-	IP6_INC_STATS(rt->rt6i_idev, IPSTATS_MIB_OUTREQUESTS);
+	IP6_INC_STATS(net, rt->rt6i_idev, IPSTATS_MIB_OUTREQUESTS);
 	if (proto == IPPROTO_ICMPV6) {
 		struct inet6_dev *idev = ip6_dst_idev(skb->dst);
 
-		ICMP6MSGOUT_INC_STATS_BH(idev, icmp6_hdr(skb)->icmp6_type);
-		ICMP6_INC_STATS_BH(idev, ICMP6_MIB_OUTMSGS);
+		ICMP6MSGOUT_INC_STATS_BH(net, idev, icmp6_hdr(skb)->icmp6_type);
+		ICMP6_INC_STATS_BH(net, idev, ICMP6_MIB_OUTMSGS);
 	}
 
 	err = ip6_local_out(skb);
@@ -1493,7 +1507,7 @@
 
 	while ((skb = __skb_dequeue_tail(&sk->sk_write_queue)) != NULL) {
 		if (skb->dst)
-			IP6_INC_STATS(ip6_dst_idev(skb->dst),
+			IP6_INC_STATS(sock_net(sk), ip6_dst_idev(skb->dst),
 				      IPSTATS_MIB_OUTDISCARDS);
 		kfree_skb(skb);
 	}
diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c
index 17c7b09..64ce3d3 100644
--- a/net/ipv6/ip6_tunnel.c
+++ b/net/ipv6/ip6_tunnel.c
@@ -1050,10 +1050,10 @@
 	}
 
 	switch (skb->protocol) {
-	case __constant_htons(ETH_P_IP):
+	case htons(ETH_P_IP):
 		ret = ip4ip6_tnl_xmit(skb, dev);
 		break;
-	case __constant_htons(ETH_P_IPV6):
+	case htons(ETH_P_IPV6):
 		ret = ip6ip6_tnl_xmit(skb, dev);
 		break;
 	default:
diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c
index 095bc45..182f8a1 100644
--- a/net/ipv6/ip6mr.c
+++ b/net/ipv6/ip6mr.c
@@ -1383,7 +1383,8 @@
 
 static inline int ip6mr_forward2_finish(struct sk_buff *skb)
 {
-	IP6_INC_STATS_BH(ip6_dst_idev(skb->dst), IPSTATS_MIB_OUTFORWDATAGRAMS);
+	IP6_INC_STATS_BH(dev_net(skb->dst->dev), ip6_dst_idev(skb->dst),
+			 IPSTATS_MIB_OUTFORWDATAGRAMS);
 	return dst_output(skb);
 }
 
diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c
index e7c03bc..d7b3c6d 100644
--- a/net/ipv6/mcast.c
+++ b/net/ipv6/mcast.c
@@ -1446,7 +1446,7 @@
 	int err;
 	struct flowi fl;
 
-	IP6_INC_STATS(idev, IPSTATS_MIB_OUTREQUESTS);
+	IP6_INC_STATS(net, idev, IPSTATS_MIB_OUTREQUESTS);
 	payload_len = (skb->tail - skb->network_header) - sizeof(*pip6);
 	mldlen = skb->tail - skb->transport_header;
 	pip6->payload_len = htons(payload_len);
@@ -1474,11 +1474,11 @@
 		      dst_output);
 out:
 	if (!err) {
-		ICMP6MSGOUT_INC_STATS_BH(idev, ICMPV6_MLD2_REPORT);
-		ICMP6_INC_STATS_BH(idev, ICMP6_MIB_OUTMSGS);
-		IP6_INC_STATS_BH(idev, IPSTATS_MIB_OUTMCASTPKTS);
+		ICMP6MSGOUT_INC_STATS_BH(net, idev, ICMPV6_MLD2_REPORT);
+		ICMP6_INC_STATS_BH(net, idev, ICMP6_MIB_OUTMSGS);
+		IP6_INC_STATS_BH(net, idev, IPSTATS_MIB_OUTMCASTPKTS);
 	} else
-		IP6_INC_STATS_BH(idev, IPSTATS_MIB_OUTDISCARDS);
+		IP6_INC_STATS_BH(net, idev, IPSTATS_MIB_OUTDISCARDS);
 
 	if (likely(idev != NULL))
 		in6_dev_put(idev);
@@ -1771,7 +1771,7 @@
 	struct flowi fl;
 
 	rcu_read_lock();
-	IP6_INC_STATS(__in6_dev_get(dev),
+	IP6_INC_STATS(net, __in6_dev_get(dev),
 		      IPSTATS_MIB_OUTREQUESTS);
 	rcu_read_unlock();
 	if (type == ICMPV6_MGM_REDUCTION)
@@ -1787,7 +1787,7 @@
 
 	if (skb == NULL) {
 		rcu_read_lock();
-		IP6_INC_STATS(__in6_dev_get(dev),
+		IP6_INC_STATS(net, __in6_dev_get(dev),
 			      IPSTATS_MIB_OUTDISCARDS);
 		rcu_read_unlock();
 		return;
@@ -1839,11 +1839,11 @@
 		      dst_output);
 out:
 	if (!err) {
-		ICMP6MSGOUT_INC_STATS(idev, type);
-		ICMP6_INC_STATS(idev, ICMP6_MIB_OUTMSGS);
-		IP6_INC_STATS(idev, IPSTATS_MIB_OUTMCASTPKTS);
+		ICMP6MSGOUT_INC_STATS(net, idev, type);
+		ICMP6_INC_STATS(net, idev, ICMP6_MIB_OUTMSGS);
+		IP6_INC_STATS(net, idev, IPSTATS_MIB_OUTMCASTPKTS);
 	} else
-		IP6_INC_STATS(idev, IPSTATS_MIB_OUTDISCARDS);
+		IP6_INC_STATS(net, idev, IPSTATS_MIB_OUTDISCARDS);
 
 	if (likely(idev != NULL))
 		in6_dev_put(idev);
diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c
index f1c62ba..840b157 100644
--- a/net/ipv6/ndisc.c
+++ b/net/ipv6/ndisc.c
@@ -516,13 +516,13 @@
 	skb->dst = dst;
 
 	idev = in6_dev_get(dst->dev);
-	IP6_INC_STATS(idev, IPSTATS_MIB_OUTREQUESTS);
+	IP6_INC_STATS(net, idev, IPSTATS_MIB_OUTREQUESTS);
 
 	err = NF_HOOK(PF_INET6, NF_INET_LOCAL_OUT, skb, NULL, dst->dev,
 		      dst_output);
 	if (!err) {
-		ICMP6MSGOUT_INC_STATS(idev, type);
-		ICMP6_INC_STATS(idev, ICMP6_MIB_OUTMSGS);
+		ICMP6MSGOUT_INC_STATS(net, idev, type);
+		ICMP6_INC_STATS(net, idev, ICMP6_MIB_OUTMSGS);
 	}
 
 	if (likely(idev != NULL))
@@ -1581,12 +1581,12 @@
 
 	buff->dst = dst;
 	idev = in6_dev_get(dst->dev);
-	IP6_INC_STATS(idev, IPSTATS_MIB_OUTREQUESTS);
+	IP6_INC_STATS(net, idev, IPSTATS_MIB_OUTREQUESTS);
 	err = NF_HOOK(PF_INET6, NF_INET_LOCAL_OUT, buff, NULL, dst->dev,
 		      dst_output);
 	if (!err) {
-		ICMP6MSGOUT_INC_STATS(idev, NDISC_REDIRECT);
-		ICMP6_INC_STATS(idev, ICMP6_MIB_OUTMSGS);
+		ICMP6MSGOUT_INC_STATS(net, idev, NDISC_REDIRECT);
+		ICMP6_INC_STATS(net, idev, ICMP6_MIB_OUTMSGS);
 	}
 
 	if (likely(idev != NULL))
diff --git a/net/ipv6/netfilter.c b/net/ipv6/netfilter.c
index 8c6c5e7..6b29b03 100644
--- a/net/ipv6/netfilter.c
+++ b/net/ipv6/netfilter.c
@@ -23,7 +23,7 @@
 		    .saddr = iph->saddr, } },
 	};
 
-	dst = ip6_route_output(&init_net, skb->sk, &fl);
+	dst = ip6_route_output(dev_net(skb->dst->dev), skb->sk, &fl);
 
 #ifdef CONFIG_XFRM
 	if (!(IP6CB(skb)->flags & IP6SKB_XFRM_TRANSFORMED) &&
@@ -33,7 +33,8 @@
 #endif
 
 	if (dst->error) {
-		IP6_INC_STATS(ip6_dst_idev(dst), IPSTATS_MIB_OUTNOROUTES);
+		IP6_INC_STATS(&init_net, ip6_dst_idev(dst),
+			      IPSTATS_MIB_OUTNOROUTES);
 		LIMIT_NETDEBUG(KERN_DEBUG "ip6_route_me_harder: No more route.\n");
 		dst_release(dst);
 		return -EINVAL;
diff --git a/net/ipv6/netfilter/Kconfig b/net/ipv6/netfilter/Kconfig
index 0cfcce7..53ea512 100644
--- a/net/ipv6/netfilter/Kconfig
+++ b/net/ipv6/netfilter/Kconfig
@@ -55,30 +55,29 @@
 
 	  To compile it as a module, choose M here.  If unsure, say N.
 
+if IP6_NF_IPTABLES
+
 # The simple matches.
-config IP6_NF_MATCH_RT
-	tristate '"rt" Routing header match support'
-	depends on IP6_NF_IPTABLES
+config IP6_NF_MATCH_AH
+	tristate '"ah" match support'
 	depends on NETFILTER_ADVANCED
 	help
-	  rt matching allows you to match packets based on the routing
-	  header of the packet.
+	  This module allows one to match AH packets.
 
 	  To compile it as a module, choose M here.  If unsure, say N.
 
-config IP6_NF_MATCH_OPTS
-	tristate '"hopbyhop" and "dst" opts header match support'
-	depends on IP6_NF_IPTABLES
+config IP6_NF_MATCH_EUI64
+	tristate '"eui64" address check'
 	depends on NETFILTER_ADVANCED
 	help
-	  This allows one to match packets based on the hop-by-hop
-	  and destination options headers of a packet.
+	  This module performs checking on the IPv6 source address
+	  Compares the last 64 bits with the EUI64 (delivered
+	  from the MAC address) address
 
 	  To compile it as a module, choose M here.  If unsure, say N.
 
 config IP6_NF_MATCH_FRAG
 	tristate '"frag" Fragmentation header match support'
-	depends on IP6_NF_IPTABLES
 	depends on NETFILTER_ADVANCED
 	help
 	  frag matching allows you to match packets based on the fragmentation
@@ -86,9 +85,17 @@
 
 	  To compile it as a module, choose M here.  If unsure, say N.
 
+config IP6_NF_MATCH_OPTS
+	tristate '"hbh" hop-by-hop and "dst" opts header match support'
+	depends on NETFILTER_ADVANCED
+	help
+	  This allows one to match packets based on the hop-by-hop
+	  and destination options headers of a packet.
+
+	  To compile it as a module, choose M here.  If unsure, say N.
+
 config IP6_NF_MATCH_HL
 	tristate '"hl" match support'
-	depends on IP6_NF_IPTABLES
 	depends on NETFILTER_ADVANCED
 	help
 	  HL matching allows you to match packets based on the hop
@@ -98,7 +105,6 @@
 
 config IP6_NF_MATCH_IPV6HEADER
 	tristate '"ipv6header" IPv6 Extension Headers Match'
-	depends on IP6_NF_IPTABLES
 	default m if NETFILTER_ADVANCED=n
 	help
 	  This module allows one to match packets based upon
@@ -106,39 +112,35 @@
 
 	  To compile it as a module, choose M here.  If unsure, say N.
 
-config IP6_NF_MATCH_AH
-	tristate '"ah" match support'
-	depends on IP6_NF_IPTABLES
-	depends on NETFILTER_ADVANCED
-	help
-	  This module allows one to match AH packets.
-
-	  To compile it as a module, choose M here.  If unsure, say N.
-
 config IP6_NF_MATCH_MH
 	tristate '"mh" match support'
-	depends on IP6_NF_IPTABLES
 	depends on NETFILTER_ADVANCED
 	help
 	  This module allows one to match MH packets.
 
 	  To compile it as a module, choose M here.  If unsure, say N.
 
-config IP6_NF_MATCH_EUI64
-	tristate '"eui64" address check'
-	depends on IP6_NF_IPTABLES
+config IP6_NF_MATCH_RT
+	tristate '"rt" Routing header match support'
 	depends on NETFILTER_ADVANCED
 	help
-	  This module performs checking on the IPv6 source address
-	  Compares the last 64 bits with the EUI64 (delivered
-	  from the MAC address) address
+	  rt matching allows you to match packets based on the routing
+	  header of the packet.
 
 	  To compile it as a module, choose M here.  If unsure, say N.
 
 # The targets
+config IP6_NF_TARGET_LOG
+	tristate "LOG target support"
+	default m if NETFILTER_ADVANCED=n
+	help
+	  This option adds a `LOG' target, which allows you to create rules in
+	  any iptables table which records the packet header to the syslog.
+
+	  To compile it as a module, choose M here.  If unsure, say N.
+
 config IP6_NF_FILTER
 	tristate "Packet filtering"
-	depends on IP6_NF_IPTABLES
 	default m if NETFILTER_ADVANCED=n
 	help
 	  Packet filtering defines a table `filter', which has a series of
@@ -147,16 +149,6 @@
 
 	  To compile it as a module, choose M here.  If unsure, say N.
 
-config IP6_NF_TARGET_LOG
-	tristate "LOG target support"
-	depends on IP6_NF_FILTER
-	default m if NETFILTER_ADVANCED=n
-	help
-	  This option adds a `LOG' target, which allows you to create rules in
-	  any iptables table which records the packet header to the syslog.
-
-	  To compile it as a module, choose M here.  If unsure, say N.
-
 config IP6_NF_TARGET_REJECT
 	tristate "REJECT target support"
 	depends on IP6_NF_FILTER
@@ -170,7 +162,6 @@
 
 config IP6_NF_MANGLE
 	tristate "Packet mangling"
-	depends on IP6_NF_IPTABLES
 	default m if NETFILTER_ADVANCED=n
 	help
 	  This option adds a `mangle' table to iptables: see the man page for
@@ -198,7 +189,6 @@
 
 config IP6_NF_RAW
 	tristate  'raw table support (required for TRACE)'
-	depends on IP6_NF_IPTABLES
 	depends on NETFILTER_ADVANCED
 	help
 	  This option adds a `raw' table to ip6tables. This table is the very
@@ -211,7 +201,6 @@
 # security table for MAC policy
 config IP6_NF_SECURITY
        tristate "Security table"
-       depends on IP6_NF_IPTABLES
        depends on SECURITY
        depends on NETFILTER_ADVANCED
        help
@@ -220,5 +209,7 @@
         
          If unsure, say N.
 
+endif # IP6_NF_IPTABLES
+
 endmenu
 
diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c
index 0b4557e..a33485d 100644
--- a/net/ipv6/netfilter/ip6_tables.c
+++ b/net/ipv6/netfilter/ip6_tables.c
@@ -200,32 +200,25 @@
 }
 
 static unsigned int
-ip6t_error(struct sk_buff *skb,
-	  const struct net_device *in,
-	  const struct net_device *out,
-	  unsigned int hooknum,
-	  const struct xt_target *target,
-	  const void *targinfo)
+ip6t_error(struct sk_buff *skb, const struct xt_target_param *par)
 {
 	if (net_ratelimit())
-		printk("ip6_tables: error: `%s'\n", (char *)targinfo);
+		printk("ip6_tables: error: `%s'\n",
+		       (const char *)par->targinfo);
 
 	return NF_DROP;
 }
 
 /* Performance critical - called for every packet */
 static inline bool
-do_match(struct ip6t_entry_match *m,
-	      const struct sk_buff *skb,
-	      const struct net_device *in,
-	      const struct net_device *out,
-	      int offset,
-	      unsigned int protoff,
-	      bool *hotdrop)
+do_match(struct ip6t_entry_match *m, const struct sk_buff *skb,
+	 struct xt_match_param *par)
 {
+	par->match     = m->u.kernel.match;
+	par->matchinfo = m->data;
+
 	/* Stop iteration if it doesn't match */
-	if (!m->u.kernel.match->match(skb, in, out, m->u.kernel.match, m->data,
-				      offset, protoff, hotdrop))
+	if (!m->u.kernel.match->match(skb, par))
 		return true;
 	else
 		return false;
@@ -355,8 +348,6 @@
 	      struct xt_table *table)
 {
 	static const char nulldevname[IFNAMSIZ] __attribute__((aligned(sizeof(long))));
-	int offset = 0;
-	unsigned int protoff = 0;
 	bool hotdrop = false;
 	/* Initializing verdict to NF_DROP keeps gcc happy. */
 	unsigned int verdict = NF_DROP;
@@ -364,6 +355,8 @@
 	void *table_base;
 	struct ip6t_entry *e, *back;
 	struct xt_table_info *private;
+	struct xt_match_param mtpar;
+	struct xt_target_param tgpar;
 
 	/* Initialization */
 	indev = in ? in->name : nulldevname;
@@ -374,6 +367,11 @@
 	 * things we don't know, ie. tcp syn flag or ports).  If the
 	 * rule is also a fragment-specific rule, non-fragments won't
 	 * match it. */
+	mtpar.hotdrop = &hotdrop;
+	mtpar.in      = tgpar.in  = in;
+	mtpar.out     = tgpar.out = out;
+	mtpar.family  = tgpar.family = NFPROTO_IPV6;
+	tgpar.hooknum = hook;
 
 	read_lock_bh(&table->lock);
 	IP_NF_ASSERT(table->valid_hooks & (1 << hook));
@@ -388,12 +386,10 @@
 		IP_NF_ASSERT(e);
 		IP_NF_ASSERT(back);
 		if (ip6_packet_match(skb, indev, outdev, &e->ipv6,
-			&protoff, &offset, &hotdrop)) {
+			&mtpar.thoff, &mtpar.fragoff, &hotdrop)) {
 			struct ip6t_entry_target *t;
 
-			if (IP6T_MATCH_ITERATE(e, do_match,
-					       skb, in, out,
-					       offset, protoff, &hotdrop) != 0)
+			if (IP6T_MATCH_ITERATE(e, do_match, skb, &mtpar) != 0)
 				goto no_match;
 
 			ADD_COUNTER(e->counters,
@@ -441,15 +437,15 @@
 			} else {
 				/* Targets which reenter must return
 				   abs. verdicts */
+				tgpar.target   = t->u.kernel.target;
+				tgpar.targinfo = t->data;
+
 #ifdef CONFIG_NETFILTER_DEBUG
 				((struct ip6t_entry *)table_base)->comefrom
 					= 0xeeeeeeec;
 #endif
 				verdict = t->u.kernel.target->target(skb,
-								     in, out,
-								     hook,
-								     t->u.kernel.target,
-								     t->data);
+								     &tgpar);
 
 #ifdef CONFIG_NETFILTER_DEBUG
 				if (((struct ip6t_entry *)table_base)->comefrom
@@ -602,12 +598,17 @@
 static int
 cleanup_match(struct ip6t_entry_match *m, unsigned int *i)
 {
+	struct xt_mtdtor_param par;
+
 	if (i && (*i)-- == 0)
 		return 1;
 
-	if (m->u.kernel.match->destroy)
-		m->u.kernel.match->destroy(m->u.kernel.match, m->data);
-	module_put(m->u.kernel.match->me);
+	par.match     = m->u.kernel.match;
+	par.matchinfo = m->data;
+	par.family    = NFPROTO_IPV6;
+	if (par.match->destroy != NULL)
+		par.match->destroy(&par);
+	module_put(par.match->me);
 	return 0;
 }
 
@@ -632,34 +633,28 @@
 	return 0;
 }
 
-static int check_match(struct ip6t_entry_match *m, const char *name,
-			      const struct ip6t_ip6 *ipv6,
-			      unsigned int hookmask, unsigned int *i)
+static int check_match(struct ip6t_entry_match *m, struct xt_mtchk_param *par,
+		       unsigned int *i)
 {
-	struct xt_match *match;
+	const struct ip6t_ip6 *ipv6 = par->entryinfo;
 	int ret;
 
-	match = m->u.kernel.match;
-	ret = xt_check_match(match, AF_INET6, m->u.match_size - sizeof(*m),
-			     name, hookmask, ipv6->proto,
-			     ipv6->invflags & IP6T_INV_PROTO);
-	if (!ret && m->u.kernel.match->checkentry
-	    && !m->u.kernel.match->checkentry(name, ipv6, match, m->data,
-					      hookmask)) {
+	par->match     = m->u.kernel.match;
+	par->matchinfo = m->data;
+
+	ret = xt_check_match(par, m->u.match_size - sizeof(*m),
+			     ipv6->proto, ipv6->invflags & IP6T_INV_PROTO);
+	if (ret < 0) {
 		duprintf("ip_tables: check failed for `%s'.\n",
-			 m->u.kernel.match->name);
-		ret = -EINVAL;
+			 par.match->name);
+		return ret;
 	}
-	if (!ret)
-		(*i)++;
-	return ret;
+	++*i;
+	return 0;
 }
 
 static int
-find_check_match(struct ip6t_entry_match *m,
-		 const char *name,
-		 const struct ip6t_ip6 *ipv6,
-		 unsigned int hookmask,
+find_check_match(struct ip6t_entry_match *m, struct xt_mtchk_param *par,
 		 unsigned int *i)
 {
 	struct xt_match *match;
@@ -674,7 +669,7 @@
 	}
 	m->u.kernel.match = match;
 
-	ret = check_match(m, name, ipv6, hookmask, i);
+	ret = check_match(m, par, i);
 	if (ret)
 		goto err;
 
@@ -686,23 +681,26 @@
 
 static int check_target(struct ip6t_entry *e, const char *name)
 {
-	struct ip6t_entry_target *t;
-	struct xt_target *target;
+	struct ip6t_entry_target *t = ip6t_get_target(e);
+	struct xt_tgchk_param par = {
+		.table     = name,
+		.entryinfo = e,
+		.target    = t->u.kernel.target,
+		.targinfo  = t->data,
+		.hook_mask = e->comefrom,
+		.family    = NFPROTO_IPV6,
+	};
 	int ret;
 
 	t = ip6t_get_target(e);
-	target = t->u.kernel.target;
-	ret = xt_check_target(target, AF_INET6, t->u.target_size - sizeof(*t),
-			      name, e->comefrom, e->ipv6.proto,
-			      e->ipv6.invflags & IP6T_INV_PROTO);
-	if (!ret && t->u.kernel.target->checkentry
-	    && !t->u.kernel.target->checkentry(name, e, target, t->data,
-					       e->comefrom)) {
+	ret = xt_check_target(&par, t->u.target_size - sizeof(*t),
+	      e->ipv6.proto, e->ipv6.invflags & IP6T_INV_PROTO);
+	if (ret < 0) {
 		duprintf("ip_tables: check failed for `%s'.\n",
 			 t->u.kernel.target->name);
-		ret = -EINVAL;
+		return ret;
 	}
-	return ret;
+	return 0;
 }
 
 static int
@@ -713,14 +711,18 @@
 	struct xt_target *target;
 	int ret;
 	unsigned int j;
+	struct xt_mtchk_param mtpar;
 
 	ret = check_entry(e, name);
 	if (ret)
 		return ret;
 
 	j = 0;
-	ret = IP6T_MATCH_ITERATE(e, find_check_match, name, &e->ipv6,
-				 e->comefrom, &j);
+	mtpar.table     = name;
+	mtpar.entryinfo = &e->ipv6;
+	mtpar.hook_mask = e->comefrom;
+	mtpar.family    = NFPROTO_IPV6;
+	ret = IP6T_MATCH_ITERATE(e, find_check_match, &mtpar, &j);
 	if (ret != 0)
 		goto cleanup_matches;
 
@@ -795,6 +797,7 @@
 static int
 cleanup_entry(struct ip6t_entry *e, unsigned int *i)
 {
+	struct xt_tgdtor_param par;
 	struct ip6t_entry_target *t;
 
 	if (i && (*i)-- == 0)
@@ -803,9 +806,13 @@
 	/* Cleanup all matches */
 	IP6T_MATCH_ITERATE(e, cleanup_match, NULL);
 	t = ip6t_get_target(e);
-	if (t->u.kernel.target->destroy)
-		t->u.kernel.target->destroy(t->u.kernel.target, t->data);
-	module_put(t->u.kernel.target->me);
+
+	par.target   = t->u.kernel.target;
+	par.targinfo = t->data;
+	par.family   = NFPROTO_IPV6;
+	if (par.target->destroy != NULL)
+		par.target->destroy(&par);
+	module_put(par.target->me);
 	return 0;
 }
 
@@ -1677,10 +1684,14 @@
 {
 	unsigned int j;
 	int ret;
+	struct xt_mtchk_param mtpar;
 
 	j = 0;
-	ret = IP6T_MATCH_ITERATE(e, check_match, name, &e->ipv6,
-				 e->comefrom, &j);
+	mtpar.table     = name;
+	mtpar.entryinfo = &e->ipv6;
+	mtpar.hook_mask = e->comefrom;
+	mtpar.family    = NFPROTO_IPV6;
+	ret = IP6T_MATCH_ITERATE(e, check_match, &mtpar, &j);
 	if (ret)
 		goto cleanup_matches;
 
@@ -2146,30 +2157,23 @@
 }
 
 static bool
-icmp6_match(const struct sk_buff *skb,
-	   const struct net_device *in,
-	   const struct net_device *out,
-	   const struct xt_match *match,
-	   const void *matchinfo,
-	   int offset,
-	   unsigned int protoff,
-	   bool *hotdrop)
+icmp6_match(const struct sk_buff *skb, const struct xt_match_param *par)
 {
 	const struct icmp6hdr *ic;
 	struct icmp6hdr _icmph;
-	const struct ip6t_icmp *icmpinfo = matchinfo;
+	const struct ip6t_icmp *icmpinfo = par->matchinfo;
 
 	/* Must not be a fragment. */
-	if (offset)
+	if (par->fragoff != 0)
 		return false;
 
-	ic = skb_header_pointer(skb, protoff, sizeof(_icmph), &_icmph);
+	ic = skb_header_pointer(skb, par->thoff, sizeof(_icmph), &_icmph);
 	if (ic == NULL) {
 		/* We've been asked to examine this packet, and we
 		 * can't.  Hence, no choice but to drop.
 		 */
 		duprintf("Dropping evil ICMP tinygram.\n");
-		*hotdrop = true;
+		*par->hotdrop = true;
 		return false;
 	}
 
@@ -2181,14 +2185,9 @@
 }
 
 /* Called when user tries to insert an entry of this type. */
-static bool
-icmp6_checkentry(const char *tablename,
-	   const void *entry,
-	   const struct xt_match *match,
-	   void *matchinfo,
-	   unsigned int hook_mask)
+static bool icmp6_checkentry(const struct xt_mtchk_param *par)
 {
-	const struct ip6t_icmp *icmpinfo = matchinfo;
+	const struct ip6t_icmp *icmpinfo = par->matchinfo;
 
 	/* Must specify no unknown invflags */
 	return !(icmpinfo->invflags & ~IP6T_ICMP_INV);
diff --git a/net/ipv6/netfilter/ip6t_HL.c b/net/ipv6/netfilter/ip6t_HL.c
index d5f8fd5..27b5adf 100644
--- a/net/ipv6/netfilter/ip6t_HL.c
+++ b/net/ipv6/netfilter/ip6t_HL.c
@@ -19,12 +19,10 @@
 MODULE_LICENSE("GPL");
 
 static unsigned int
-hl_tg6(struct sk_buff *skb, const struct net_device *in,
-       const struct net_device *out, unsigned int hooknum,
-       const struct xt_target *target, const void *targinfo)
+hl_tg6(struct sk_buff *skb, const struct xt_target_param *par)
 {
 	struct ipv6hdr *ip6h;
-	const struct ip6t_HL_info *info = targinfo;
+	const struct ip6t_HL_info *info = par->targinfo;
 	int new_hl;
 
 	if (!skb_make_writable(skb, skb->len))
@@ -56,12 +54,9 @@
 	return XT_CONTINUE;
 }
 
-static bool
-hl_tg6_check(const char *tablename, const void *entry,
-             const struct xt_target *target, void *targinfo,
-             unsigned int hook_mask)
+static bool hl_tg6_check(const struct xt_tgchk_param *par)
 {
-	const struct ip6t_HL_info *info = targinfo;
+	const struct ip6t_HL_info *info = par->targinfo;
 
 	if (info->mode > IP6T_HL_MAXMODE) {
 		printk(KERN_WARNING "ip6t_HL: invalid or unknown Mode %u\n",
@@ -78,7 +73,7 @@
 
 static struct xt_target hl_tg6_reg __read_mostly = {
 	.name 		= "HL",
-	.family		= AF_INET6,
+	.family		= NFPROTO_IPV6,
 	.target		= hl_tg6,
 	.targetsize	= sizeof(struct ip6t_HL_info),
 	.table		= "mangle",
diff --git a/net/ipv6/netfilter/ip6t_LOG.c b/net/ipv6/netfilter/ip6t_LOG.c
index 3a23169..caa441d 100644
--- a/net/ipv6/netfilter/ip6t_LOG.c
+++ b/net/ipv6/netfilter/ip6t_LOG.c
@@ -385,7 +385,7 @@
 };
 
 static void
-ip6t_log_packet(unsigned int pf,
+ip6t_log_packet(u_int8_t pf,
 		unsigned int hooknum,
 		const struct sk_buff *skb,
 		const struct net_device *in,
@@ -438,28 +438,24 @@
 }
 
 static unsigned int
-log_tg6(struct sk_buff *skb, const struct net_device *in,
-        const struct net_device *out, unsigned int hooknum,
-        const struct xt_target *target, const void *targinfo)
+log_tg6(struct sk_buff *skb, const struct xt_target_param *par)
 {
-	const struct ip6t_log_info *loginfo = targinfo;
+	const struct ip6t_log_info *loginfo = par->targinfo;
 	struct nf_loginfo li;
 
 	li.type = NF_LOG_TYPE_LOG;
 	li.u.log.level = loginfo->level;
 	li.u.log.logflags = loginfo->logflags;
 
-	ip6t_log_packet(PF_INET6, hooknum, skb, in, out, &li, loginfo->prefix);
+	ip6t_log_packet(NFPROTO_IPV6, par->hooknum, skb, par->in, par->out,
+			&li, loginfo->prefix);
 	return XT_CONTINUE;
 }
 
 
-static bool
-log_tg6_check(const char *tablename, const void *entry,
-              const struct xt_target *target, void *targinfo,
-              unsigned int hook_mask)
+static bool log_tg6_check(const struct xt_tgchk_param *par)
 {
-	const struct ip6t_log_info *loginfo = targinfo;
+	const struct ip6t_log_info *loginfo = par->targinfo;
 
 	if (loginfo->level >= 8) {
 		pr_debug("LOG: level %u >= 8\n", loginfo->level);
@@ -475,7 +471,7 @@
 
 static struct xt_target log_tg6_reg __read_mostly = {
 	.name 		= "LOG",
-	.family		= AF_INET6,
+	.family		= NFPROTO_IPV6,
 	.target 	= log_tg6,
 	.targetsize	= sizeof(struct ip6t_log_info),
 	.checkentry	= log_tg6_check,
@@ -495,7 +491,7 @@
 	ret = xt_register_target(&log_tg6_reg);
 	if (ret < 0)
 		return ret;
-	nf_log_register(PF_INET6, &ip6t_logger);
+	nf_log_register(NFPROTO_IPV6, &ip6t_logger);
 	return 0;
 }
 
diff --git a/net/ipv6/netfilter/ip6t_REJECT.c b/net/ipv6/netfilter/ip6t_REJECT.c
index 44c8d65..0981b4c 100644
--- a/net/ipv6/netfilter/ip6t_REJECT.c
+++ b/net/ipv6/netfilter/ip6t_REJECT.c
@@ -35,7 +35,7 @@
 MODULE_LICENSE("GPL");
 
 /* Send RST reply */
-static void send_reset(struct sk_buff *oldskb)
+static void send_reset(struct net *net, struct sk_buff *oldskb)
 {
 	struct sk_buff *nskb;
 	struct tcphdr otcph, *tcph;
@@ -94,7 +94,7 @@
 	fl.fl_ip_sport = otcph.dest;
 	fl.fl_ip_dport = otcph.source;
 	security_skb_classify_flow(oldskb, &fl);
-	dst = ip6_route_output(&init_net, NULL, &fl);
+	dst = ip6_route_output(net, NULL, &fl);
 	if (dst == NULL)
 		return;
 	if (dst->error || xfrm_lookup(&dst, &fl, NULL, 0))
@@ -163,20 +163,20 @@
 }
 
 static inline void
-send_unreach(struct sk_buff *skb_in, unsigned char code, unsigned int hooknum)
+send_unreach(struct net *net, struct sk_buff *skb_in, unsigned char code,
+	     unsigned int hooknum)
 {
 	if (hooknum == NF_INET_LOCAL_OUT && skb_in->dev == NULL)
-		skb_in->dev = init_net.loopback_dev;
+		skb_in->dev = net->loopback_dev;
 
 	icmpv6_send(skb_in, ICMPV6_DEST_UNREACH, code, 0, NULL);
 }
 
 static unsigned int
-reject_tg6(struct sk_buff *skb, const struct net_device *in,
-           const struct net_device *out, unsigned int hooknum,
-           const struct xt_target *target, const void *targinfo)
+reject_tg6(struct sk_buff *skb, const struct xt_target_param *par)
 {
-	const struct ip6t_reject_info *reject = targinfo;
+	const struct ip6t_reject_info *reject = par->targinfo;
+	struct net *net = dev_net((par->in != NULL) ? par->in : par->out);
 
 	pr_debug("%s: medium point\n", __func__);
 	/* WARNING: This code causes reentry within ip6tables.
@@ -184,25 +184,25 @@
 	   must return an absolute verdict. --RR */
 	switch (reject->with) {
 	case IP6T_ICMP6_NO_ROUTE:
-		send_unreach(skb, ICMPV6_NOROUTE, hooknum);
+		send_unreach(net, skb, ICMPV6_NOROUTE, par->hooknum);
 		break;
 	case IP6T_ICMP6_ADM_PROHIBITED:
-		send_unreach(skb, ICMPV6_ADM_PROHIBITED, hooknum);
+		send_unreach(net, skb, ICMPV6_ADM_PROHIBITED, par->hooknum);
 		break;
 	case IP6T_ICMP6_NOT_NEIGHBOUR:
-		send_unreach(skb, ICMPV6_NOT_NEIGHBOUR, hooknum);
+		send_unreach(net, skb, ICMPV6_NOT_NEIGHBOUR, par->hooknum);
 		break;
 	case IP6T_ICMP6_ADDR_UNREACH:
-		send_unreach(skb, ICMPV6_ADDR_UNREACH, hooknum);
+		send_unreach(net, skb, ICMPV6_ADDR_UNREACH, par->hooknum);
 		break;
 	case IP6T_ICMP6_PORT_UNREACH:
-		send_unreach(skb, ICMPV6_PORT_UNREACH, hooknum);
+		send_unreach(net, skb, ICMPV6_PORT_UNREACH, par->hooknum);
 		break;
 	case IP6T_ICMP6_ECHOREPLY:
 		/* Do nothing */
 		break;
 	case IP6T_TCP_RESET:
-		send_reset(skb);
+		send_reset(net, skb);
 		break;
 	default:
 		if (net_ratelimit())
@@ -213,13 +213,10 @@
 	return NF_DROP;
 }
 
-static bool
-reject_tg6_check(const char *tablename, const void *entry,
-                 const struct xt_target *target, void *targinfo,
-                 unsigned int hook_mask)
+static bool reject_tg6_check(const struct xt_tgchk_param *par)
 {
-	const struct ip6t_reject_info *rejinfo = targinfo;
-	const struct ip6t_entry *e = entry;
+	const struct ip6t_reject_info *rejinfo = par->targinfo;
+	const struct ip6t_entry *e = par->entryinfo;
 
 	if (rejinfo->with == IP6T_ICMP6_ECHOREPLY) {
 		printk("ip6t_REJECT: ECHOREPLY is not supported.\n");
@@ -237,7 +234,7 @@
 
 static struct xt_target reject_tg6_reg __read_mostly = {
 	.name		= "REJECT",
-	.family		= AF_INET6,
+	.family		= NFPROTO_IPV6,
 	.target		= reject_tg6,
 	.targetsize	= sizeof(struct ip6t_reject_info),
 	.table		= "filter",
diff --git a/net/ipv6/netfilter/ip6t_ah.c b/net/ipv6/netfilter/ip6t_ah.c
index 429629f..3a82f24 100644
--- a/net/ipv6/netfilter/ip6t_ah.c
+++ b/net/ipv6/netfilter/ip6t_ah.c
@@ -36,14 +36,11 @@
 	return r;
 }
 
-static bool
-ah_mt6(const struct sk_buff *skb, const struct net_device *in,
-       const struct net_device *out, const struct xt_match *match,
-       const void *matchinfo, int offset, unsigned int protoff, bool *hotdrop)
+static bool ah_mt6(const struct sk_buff *skb, const struct xt_match_param *par)
 {
 	struct ip_auth_hdr _ah;
 	const struct ip_auth_hdr *ah;
-	const struct ip6t_ah *ahinfo = matchinfo;
+	const struct ip6t_ah *ahinfo = par->matchinfo;
 	unsigned int ptr;
 	unsigned int hdrlen = 0;
 	int err;
@@ -51,13 +48,13 @@
 	err = ipv6_find_hdr(skb, &ptr, NEXTHDR_AUTH, NULL);
 	if (err < 0) {
 		if (err != -ENOENT)
-			*hotdrop = true;
+			*par->hotdrop = true;
 		return false;
 	}
 
 	ah = skb_header_pointer(skb, ptr, sizeof(_ah), &_ah);
 	if (ah == NULL) {
-		*hotdrop = true;
+		*par->hotdrop = true;
 		return false;
 	}
 
@@ -93,13 +90,9 @@
 	       !(ahinfo->hdrres && ah->reserved);
 }
 
-/* Called when user tries to insert an entry of this type. */
-static bool
-ah_mt6_check(const char *tablename, const void *entry,
-             const struct xt_match *match, void *matchinfo,
-             unsigned int hook_mask)
+static bool ah_mt6_check(const struct xt_mtchk_param *par)
 {
-	const struct ip6t_ah *ahinfo = matchinfo;
+	const struct ip6t_ah *ahinfo = par->matchinfo;
 
 	if (ahinfo->invflags & ~IP6T_AH_INV_MASK) {
 		pr_debug("ip6t_ah: unknown flags %X\n", ahinfo->invflags);
@@ -110,7 +103,7 @@
 
 static struct xt_match ah_mt6_reg __read_mostly = {
 	.name		= "ah",
-	.family		= AF_INET6,
+	.family		= NFPROTO_IPV6,
 	.match		= ah_mt6,
 	.matchsize	= sizeof(struct ip6t_ah),
 	.checkentry	= ah_mt6_check,
diff --git a/net/ipv6/netfilter/ip6t_eui64.c b/net/ipv6/netfilter/ip6t_eui64.c
index 8f331f1..db610ba 100644
--- a/net/ipv6/netfilter/ip6t_eui64.c
+++ b/net/ipv6/netfilter/ip6t_eui64.c
@@ -20,18 +20,15 @@
 MODULE_AUTHOR("Andras Kis-Szabo <kisza@sch.bme.hu>");
 
 static bool
-eui64_mt6(const struct sk_buff *skb, const struct net_device *in,
-          const struct net_device *out, const struct xt_match *match,
-          const void *matchinfo, int offset, unsigned int protoff,
-          bool *hotdrop)
+eui64_mt6(const struct sk_buff *skb, const struct xt_match_param *par)
 {
 	unsigned char eui64[8];
 	int i = 0;
 
 	if (!(skb_mac_header(skb) >= skb->head &&
 	      skb_mac_header(skb) + ETH_HLEN <= skb->data) &&
-	    offset != 0) {
-		*hotdrop = true;
+	    par->fragoff != 0) {
+		*par->hotdrop = true;
 		return false;
 	}
 
@@ -60,7 +57,7 @@
 
 static struct xt_match eui64_mt6_reg __read_mostly = {
 	.name		= "eui64",
-	.family		= AF_INET6,
+	.family		= NFPROTO_IPV6,
 	.match		= eui64_mt6,
 	.matchsize	= sizeof(int),
 	.hooks		= (1 << NF_INET_PRE_ROUTING) | (1 << NF_INET_LOCAL_IN) |
diff --git a/net/ipv6/netfilter/ip6t_frag.c b/net/ipv6/netfilter/ip6t_frag.c
index e2bbc63..673aa0a 100644
--- a/net/ipv6/netfilter/ip6t_frag.c
+++ b/net/ipv6/netfilter/ip6t_frag.c
@@ -35,27 +35,24 @@
 }
 
 static bool
-frag_mt6(const struct sk_buff *skb, const struct net_device *in,
-         const struct net_device *out, const struct xt_match *match,
-         const void *matchinfo, int offset, unsigned int protoff,
-         bool *hotdrop)
+frag_mt6(const struct sk_buff *skb, const struct xt_match_param *par)
 {
 	struct frag_hdr _frag;
 	const struct frag_hdr *fh;
-	const struct ip6t_frag *fraginfo = matchinfo;
+	const struct ip6t_frag *fraginfo = par->matchinfo;
 	unsigned int ptr;
 	int err;
 
 	err = ipv6_find_hdr(skb, &ptr, NEXTHDR_FRAGMENT, NULL);
 	if (err < 0) {
 		if (err != -ENOENT)
-			*hotdrop = true;
+			*par->hotdrop = true;
 		return false;
 	}
 
 	fh = skb_header_pointer(skb, ptr, sizeof(_frag), &_frag);
 	if (fh == NULL) {
-		*hotdrop = true;
+		*par->hotdrop = true;
 		return false;
 	}
 
@@ -110,13 +107,9 @@
 		 && (ntohs(fh->frag_off) & IP6_MF));
 }
 
-/* Called when user tries to insert an entry of this type. */
-static bool
-frag_mt6_check(const char *tablename, const void *ip,
-               const struct xt_match *match, void *matchinfo,
-               unsigned int hook_mask)
+static bool frag_mt6_check(const struct xt_mtchk_param *par)
 {
-	const struct ip6t_frag *fraginfo = matchinfo;
+	const struct ip6t_frag *fraginfo = par->matchinfo;
 
 	if (fraginfo->invflags & ~IP6T_FRAG_INV_MASK) {
 		pr_debug("ip6t_frag: unknown flags %X\n", fraginfo->invflags);
@@ -127,7 +120,7 @@
 
 static struct xt_match frag_mt6_reg __read_mostly = {
 	.name		= "frag",
-	.family		= AF_INET6,
+	.family		= NFPROTO_IPV6,
 	.match		= frag_mt6,
 	.matchsize	= sizeof(struct ip6t_frag),
 	.checkentry	= frag_mt6_check,
diff --git a/net/ipv6/netfilter/ip6t_hbh.c b/net/ipv6/netfilter/ip6t_hbh.c
index 62e39ac..cbe8dec 100644
--- a/net/ipv6/netfilter/ip6t_hbh.c
+++ b/net/ipv6/netfilter/ip6t_hbh.c
@@ -42,14 +42,11 @@
  */
 
 static bool
-hbh_mt6(const struct sk_buff *skb, const struct net_device *in,
-        const struct net_device *out, const struct xt_match *match,
-        const void *matchinfo, int offset, unsigned int protoff,
-        bool *hotdrop)
+hbh_mt6(const struct sk_buff *skb, const struct xt_match_param *par)
 {
 	struct ipv6_opt_hdr _optsh;
 	const struct ipv6_opt_hdr *oh;
-	const struct ip6t_opts *optinfo = matchinfo;
+	const struct ip6t_opts *optinfo = par->matchinfo;
 	unsigned int temp;
 	unsigned int ptr;
 	unsigned int hdrlen = 0;
@@ -61,16 +58,16 @@
 	unsigned int optlen;
 	int err;
 
-	err = ipv6_find_hdr(skb, &ptr, match->data, NULL);
+	err = ipv6_find_hdr(skb, &ptr, par->match->data, NULL);
 	if (err < 0) {
 		if (err != -ENOENT)
-			*hotdrop = true;
+			*par->hotdrop = true;
 		return false;
 	}
 
 	oh = skb_header_pointer(skb, ptr, sizeof(_optsh), &_optsh);
 	if (oh == NULL) {
-		*hotdrop = true;
+		*par->hotdrop = true;
 		return false;
 	}
 
@@ -97,8 +94,6 @@
 	hdrlen -= 2;
 	if (!(optinfo->flags & IP6T_OPTS_OPTS)) {
 		return ret;
-	} else if (optinfo->flags & IP6T_OPTS_NSTRICT) {
-		pr_debug("Not strict - not implemented");
 	} else {
 		pr_debug("Strict ");
 		pr_debug("#%d ", optinfo->optsnr);
@@ -165,25 +160,27 @@
 	return false;
 }
 
-/* Called when user tries to insert an entry of this type. */
-static bool
-hbh_mt6_check(const char *tablename, const void *entry,
-              const struct xt_match *match, void *matchinfo,
-              unsigned int hook_mask)
+static bool hbh_mt6_check(const struct xt_mtchk_param *par)
 {
-	const struct ip6t_opts *optsinfo = matchinfo;
+	const struct ip6t_opts *optsinfo = par->matchinfo;
 
 	if (optsinfo->invflags & ~IP6T_OPTS_INV_MASK) {
 		pr_debug("ip6t_opts: unknown flags %X\n", optsinfo->invflags);
 		return false;
 	}
+
+	if (optsinfo->flags & IP6T_OPTS_NSTRICT) {
+		pr_debug("ip6t_opts: Not strict - not implemented");
+		return false;
+	}
+
 	return true;
 }
 
 static struct xt_match hbh_mt6_reg[] __read_mostly = {
 	{
 		.name		= "hbh",
-		.family		= AF_INET6,
+		.family		= NFPROTO_IPV6,
 		.match		= hbh_mt6,
 		.matchsize	= sizeof(struct ip6t_opts),
 		.checkentry	= hbh_mt6_check,
@@ -192,7 +189,7 @@
 	},
 	{
 		.name		= "dst",
-		.family		= AF_INET6,
+		.family		= NFPROTO_IPV6,
 		.match		= hbh_mt6,
 		.matchsize	= sizeof(struct ip6t_opts),
 		.checkentry	= hbh_mt6_check,
diff --git a/net/ipv6/netfilter/ip6t_hl.c b/net/ipv6/netfilter/ip6t_hl.c
index 3456716..c964dca 100644
--- a/net/ipv6/netfilter/ip6t_hl.c
+++ b/net/ipv6/netfilter/ip6t_hl.c
@@ -19,12 +19,9 @@
 MODULE_DESCRIPTION("Xtables: IPv6 Hop Limit field match");
 MODULE_LICENSE("GPL");
 
-static bool
-hl_mt6(const struct sk_buff *skb, const struct net_device *in,
-       const struct net_device *out, const struct xt_match *match,
-       const void *matchinfo, int offset, unsigned int protoff, bool *hotdrop)
+static bool hl_mt6(const struct sk_buff *skb, const struct xt_match_param *par)
 {
-	const struct ip6t_hl_info *info = matchinfo;
+	const struct ip6t_hl_info *info = par->matchinfo;
 	const struct ipv6hdr *ip6h = ipv6_hdr(skb);
 
 	switch (info->mode) {
@@ -51,7 +48,7 @@
 
 static struct xt_match hl_mt6_reg __read_mostly = {
 	.name		= "hl",
-	.family		= AF_INET6,
+	.family		= NFPROTO_IPV6,
 	.match		= hl_mt6,
 	.matchsize	= sizeof(struct ip6t_hl_info),
 	.me		= THIS_MODULE,
diff --git a/net/ipv6/netfilter/ip6t_ipv6header.c b/net/ipv6/netfilter/ip6t_ipv6header.c
index 317a896..14e6724 100644
--- a/net/ipv6/netfilter/ip6t_ipv6header.c
+++ b/net/ipv6/netfilter/ip6t_ipv6header.c
@@ -27,12 +27,9 @@
 MODULE_AUTHOR("Andras Kis-Szabo <kisza@sch.bme.hu>");
 
 static bool
-ipv6header_mt6(const struct sk_buff *skb, const struct net_device *in,
-               const struct net_device *out, const struct xt_match *match,
-               const void *matchinfo, int offset, unsigned int protoff,
-               bool *hotdrop)
+ipv6header_mt6(const struct sk_buff *skb, const struct xt_match_param *par)
 {
-	const struct ip6t_ipv6header_info *info = matchinfo;
+	const struct ip6t_ipv6header_info *info = par->matchinfo;
 	unsigned int temp;
 	int len;
 	u8 nexthdr;
@@ -121,12 +118,9 @@
 	}
 }
 
-static bool
-ipv6header_mt6_check(const char *tablename, const void *ip,
-                     const struct xt_match *match, void *matchinfo,
-                     unsigned int hook_mask)
+static bool ipv6header_mt6_check(const struct xt_mtchk_param *par)
 {
-	const struct ip6t_ipv6header_info *info = matchinfo;
+	const struct ip6t_ipv6header_info *info = par->matchinfo;
 
 	/* invflags is 0 or 0xff in hard mode */
 	if ((!info->modeflag) && info->invflags != 0x00 &&
@@ -138,7 +132,7 @@
 
 static struct xt_match ipv6header_mt6_reg __read_mostly = {
 	.name		= "ipv6header",
-	.family		= AF_INET6,
+	.family		= NFPROTO_IPV6,
 	.match		= ipv6header_mt6,
 	.matchsize	= sizeof(struct ip6t_ipv6header_info),
 	.checkentry	= ipv6header_mt6_check,
diff --git a/net/ipv6/netfilter/ip6t_mh.c b/net/ipv6/netfilter/ip6t_mh.c
index e06678d..aafe4e6 100644
--- a/net/ipv6/netfilter/ip6t_mh.c
+++ b/net/ipv6/netfilter/ip6t_mh.c
@@ -37,32 +37,29 @@
 	return (type >= min && type <= max) ^ invert;
 }
 
-static bool
-mh_mt6(const struct sk_buff *skb, const struct net_device *in,
-       const struct net_device *out, const struct xt_match *match,
-       const void *matchinfo, int offset, unsigned int protoff, bool *hotdrop)
+static bool mh_mt6(const struct sk_buff *skb, const struct xt_match_param *par)
 {
 	struct ip6_mh _mh;
 	const struct ip6_mh *mh;
-	const struct ip6t_mh *mhinfo = matchinfo;
+	const struct ip6t_mh *mhinfo = par->matchinfo;
 
 	/* Must not be a fragment. */
-	if (offset)
+	if (par->fragoff != 0)
 		return false;
 
-	mh = skb_header_pointer(skb, protoff, sizeof(_mh), &_mh);
+	mh = skb_header_pointer(skb, par->thoff, sizeof(_mh), &_mh);
 	if (mh == NULL) {
 		/* We've been asked to examine this packet, and we
 		   can't.  Hence, no choice but to drop. */
 		duprintf("Dropping evil MH tinygram.\n");
-		*hotdrop = true;
+		*par->hotdrop = true;
 		return false;
 	}
 
 	if (mh->ip6mh_proto != IPPROTO_NONE) {
 		duprintf("Dropping invalid MH Payload Proto: %u\n",
 			 mh->ip6mh_proto);
-		*hotdrop = true;
+		*par->hotdrop = true;
 		return false;
 	}
 
@@ -70,13 +67,9 @@
 			  !!(mhinfo->invflags & IP6T_MH_INV_TYPE));
 }
 
-/* Called when user tries to insert an entry of this type. */
-static bool
-mh_mt6_check(const char *tablename, const void *entry,
-             const struct xt_match *match, void *matchinfo,
-             unsigned int hook_mask)
+static bool mh_mt6_check(const struct xt_mtchk_param *par)
 {
-	const struct ip6t_mh *mhinfo = matchinfo;
+	const struct ip6t_mh *mhinfo = par->matchinfo;
 
 	/* Must specify no unknown invflags */
 	return !(mhinfo->invflags & ~IP6T_MH_INV_MASK);
@@ -84,7 +77,7 @@
 
 static struct xt_match mh_mt6_reg __read_mostly = {
 	.name		= "mh",
-	.family		= AF_INET6,
+	.family		= NFPROTO_IPV6,
 	.checkentry	= mh_mt6_check,
 	.match		= mh_mt6,
 	.matchsize	= sizeof(struct ip6t_mh),
diff --git a/net/ipv6/netfilter/ip6t_rt.c b/net/ipv6/netfilter/ip6t_rt.c
index 81aaf7a..356b8d6 100644
--- a/net/ipv6/netfilter/ip6t_rt.c
+++ b/net/ipv6/netfilter/ip6t_rt.c
@@ -36,14 +36,11 @@
 	return r;
 }
 
-static bool
-rt_mt6(const struct sk_buff *skb, const struct net_device *in,
-       const struct net_device *out, const struct xt_match *match,
-       const void *matchinfo, int offset, unsigned int protoff, bool *hotdrop)
+static bool rt_mt6(const struct sk_buff *skb, const struct xt_match_param *par)
 {
 	struct ipv6_rt_hdr _route;
 	const struct ipv6_rt_hdr *rh;
-	const struct ip6t_rt *rtinfo = matchinfo;
+	const struct ip6t_rt *rtinfo = par->matchinfo;
 	unsigned int temp;
 	unsigned int ptr;
 	unsigned int hdrlen = 0;
@@ -55,13 +52,13 @@
 	err = ipv6_find_hdr(skb, &ptr, NEXTHDR_ROUTING, NULL);
 	if (err < 0) {
 		if (err != -ENOENT)
-			*hotdrop = true;
+			*par->hotdrop = true;
 		return false;
 	}
 
 	rh = skb_header_pointer(skb, ptr, sizeof(_route), &_route);
 	if (rh == NULL) {
-		*hotdrop = true;
+		*par->hotdrop = true;
 		return false;
 	}
 
@@ -189,13 +186,9 @@
 	return false;
 }
 
-/* Called when user tries to insert an entry of this type. */
-static bool
-rt_mt6_check(const char *tablename, const void *entry,
-             const struct xt_match *match, void *matchinfo,
-             unsigned int hook_mask)
+static bool rt_mt6_check(const struct xt_mtchk_param *par)
 {
-	const struct ip6t_rt *rtinfo = matchinfo;
+	const struct ip6t_rt *rtinfo = par->matchinfo;
 
 	if (rtinfo->invflags & ~IP6T_RT_INV_MASK) {
 		pr_debug("ip6t_rt: unknown flags %X\n", rtinfo->invflags);
@@ -214,7 +207,7 @@
 
 static struct xt_match rt_mt6_reg __read_mostly = {
 	.name		= "rt",
-	.family		= AF_INET6,
+	.family		= NFPROTO_IPV6,
 	.match		= rt_mt6,
 	.matchsize	= sizeof(struct ip6t_rt),
 	.checkentry	= rt_mt6_check,
diff --git a/net/ipv6/netfilter/ip6table_filter.c b/net/ipv6/netfilter/ip6table_filter.c
index 55a2c29..b110a8a8 100644
--- a/net/ipv6/netfilter/ip6table_filter.c
+++ b/net/ipv6/netfilter/ip6table_filter.c
@@ -68,7 +68,7 @@
 		   int (*okfn)(struct sk_buff *))
 {
 	return ip6t_do_table(skb, hook, in, out,
-			     nf_local_in_net(in, out)->ipv6.ip6table_filter);
+			     dev_net(in)->ipv6.ip6table_filter);
 }
 
 static unsigned int
@@ -79,7 +79,7 @@
 		  int (*okfn)(struct sk_buff *))
 {
 	return ip6t_do_table(skb, hook, in, out,
-			     nf_forward_net(in, out)->ipv6.ip6table_filter);
+			     dev_net(in)->ipv6.ip6table_filter);
 }
 
 static unsigned int
@@ -100,7 +100,7 @@
 #endif
 
 	return ip6t_do_table(skb, hook, in, out,
-			     nf_local_out_net(in, out)->ipv6.ip6table_filter);
+			     dev_net(out)->ipv6.ip6table_filter);
 }
 
 static struct nf_hook_ops ip6t_ops[] __read_mostly = {
diff --git a/net/ipv6/netfilter/ip6table_mangle.c b/net/ipv6/netfilter/ip6table_mangle.c
index f405cea..d0b31b2 100644
--- a/net/ipv6/netfilter/ip6table_mangle.c
+++ b/net/ipv6/netfilter/ip6table_mangle.c
@@ -67,17 +67,29 @@
 
 /* The work comes in here from netfilter.c. */
 static unsigned int
-ip6t_route_hook(unsigned int hook,
+ip6t_in_hook(unsigned int hook,
 	 struct sk_buff *skb,
 	 const struct net_device *in,
 	 const struct net_device *out,
 	 int (*okfn)(struct sk_buff *))
 {
-	return ip6t_do_table(skb, hook, in, out, init_net.ipv6.ip6table_mangle);
+	return ip6t_do_table(skb, hook, in, out,
+			     dev_net(in)->ipv6.ip6table_mangle);
 }
 
 static unsigned int
-ip6t_local_hook(unsigned int hook,
+ip6t_post_routing_hook(unsigned int hook,
+		struct sk_buff *skb,
+		const struct net_device *in,
+		const struct net_device *out,
+		int (*okfn)(struct sk_buff *))
+{
+	return ip6t_do_table(skb, hook, in, out,
+			     dev_net(out)->ipv6.ip6table_mangle);
+}
+
+static unsigned int
+ip6t_local_out_hook(unsigned int hook,
 		   struct sk_buff *skb,
 		   const struct net_device *in,
 		   const struct net_device *out,
@@ -108,7 +120,8 @@
 	/* flowlabel and prio (includes version, which shouldn't change either */
 	flowlabel = *((u_int32_t *)ipv6_hdr(skb));
 
-	ret = ip6t_do_table(skb, hook, in, out, init_net.ipv6.ip6table_mangle);
+	ret = ip6t_do_table(skb, hook, in, out,
+			    dev_net(out)->ipv6.ip6table_mangle);
 
 	if (ret != NF_DROP && ret != NF_STOLEN
 		&& (memcmp(&ipv6_hdr(skb)->saddr, &saddr, sizeof(saddr))
@@ -122,35 +135,35 @@
 
 static struct nf_hook_ops ip6t_ops[] __read_mostly = {
 	{
-		.hook		= ip6t_route_hook,
+		.hook		= ip6t_in_hook,
 		.owner		= THIS_MODULE,
 		.pf		= PF_INET6,
 		.hooknum	= NF_INET_PRE_ROUTING,
 		.priority	= NF_IP6_PRI_MANGLE,
 	},
 	{
-		.hook		= ip6t_route_hook,
+		.hook		= ip6t_in_hook,
 		.owner		= THIS_MODULE,
 		.pf		= PF_INET6,
 		.hooknum	= NF_INET_LOCAL_IN,
 		.priority	= NF_IP6_PRI_MANGLE,
 	},
 	{
-		.hook		= ip6t_route_hook,
+		.hook		= ip6t_in_hook,
 		.owner		= THIS_MODULE,
 		.pf		= PF_INET6,
 		.hooknum	= NF_INET_FORWARD,
 		.priority	= NF_IP6_PRI_MANGLE,
 	},
 	{
-		.hook		= ip6t_local_hook,
+		.hook		= ip6t_local_out_hook,
 		.owner		= THIS_MODULE,
 		.pf		= PF_INET6,
 		.hooknum	= NF_INET_LOCAL_OUT,
 		.priority	= NF_IP6_PRI_MANGLE,
 	},
 	{
-		.hook		= ip6t_route_hook,
+		.hook		= ip6t_post_routing_hook,
 		.owner		= THIS_MODULE,
 		.pf		= PF_INET6,
 		.hooknum	= NF_INET_POST_ROUTING,
diff --git a/net/ipv6/netfilter/ip6table_raw.c b/net/ipv6/netfilter/ip6table_raw.c
index 92b9107..109fab6 100644
--- a/net/ipv6/netfilter/ip6table_raw.c
+++ b/net/ipv6/netfilter/ip6table_raw.c
@@ -45,25 +45,37 @@
 
 /* The work comes in here from netfilter.c. */
 static unsigned int
-ip6t_hook(unsigned int hook,
+ip6t_pre_routing_hook(unsigned int hook,
 	 struct sk_buff *skb,
 	 const struct net_device *in,
 	 const struct net_device *out,
 	 int (*okfn)(struct sk_buff *))
 {
-	return ip6t_do_table(skb, hook, in, out, init_net.ipv6.ip6table_raw);
+	return ip6t_do_table(skb, hook, in, out,
+			     dev_net(in)->ipv6.ip6table_raw);
+}
+
+static unsigned int
+ip6t_local_out_hook(unsigned int hook,
+	 struct sk_buff *skb,
+	 const struct net_device *in,
+	 const struct net_device *out,
+	 int (*okfn)(struct sk_buff *))
+{
+	return ip6t_do_table(skb, hook, in, out,
+			     dev_net(out)->ipv6.ip6table_raw);
 }
 
 static struct nf_hook_ops ip6t_ops[] __read_mostly = {
 	{
-	  .hook = ip6t_hook,
+	  .hook = ip6t_pre_routing_hook,
 	  .pf = PF_INET6,
 	  .hooknum = NF_INET_PRE_ROUTING,
 	  .priority = NF_IP6_PRI_FIRST,
 	  .owner = THIS_MODULE,
 	},
 	{
-	  .hook = ip6t_hook,
+	  .hook = ip6t_local_out_hook,
 	  .pf = PF_INET6,
 	  .hooknum = NF_INET_LOCAL_OUT,
 	  .priority = NF_IP6_PRI_FIRST,
diff --git a/net/ipv6/netfilter/ip6table_security.c b/net/ipv6/netfilter/ip6table_security.c
index 6e71310..20bc52f 100644
--- a/net/ipv6/netfilter/ip6table_security.c
+++ b/net/ipv6/netfilter/ip6table_security.c
@@ -72,7 +72,7 @@
 		   int (*okfn)(struct sk_buff *))
 {
 	return ip6t_do_table(skb, hook, in, out,
-			     nf_local_in_net(in, out)->ipv6.ip6table_security);
+			     dev_net(in)->ipv6.ip6table_security);
 }
 
 static unsigned int
@@ -83,7 +83,7 @@
 		  int (*okfn)(struct sk_buff *))
 {
 	return ip6t_do_table(skb, hook, in, out,
-			     nf_forward_net(in, out)->ipv6.ip6table_security);
+			     dev_net(in)->ipv6.ip6table_security);
 }
 
 static unsigned int
@@ -95,7 +95,7 @@
 {
 	/* TBD: handle short packets via raw socket */
 	return ip6t_do_table(skb, hook, in, out,
-			     nf_local_out_net(in, out)->ipv6.ip6table_security);
+			     dev_net(out)->ipv6.ip6table_security);
 }
 
 static struct nf_hook_ops ip6t_ops[] __read_mostly = {
diff --git a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
index 85050c0..e91db16 100644
--- a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
+++ b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
@@ -211,11 +211,10 @@
 	return NF_STOLEN;
 }
 
-static unsigned int ipv6_conntrack_in(unsigned int hooknum,
-				      struct sk_buff *skb,
-				      const struct net_device *in,
-				      const struct net_device *out,
-				      int (*okfn)(struct sk_buff *))
+static unsigned int __ipv6_conntrack_in(struct net *net,
+					unsigned int hooknum,
+					struct sk_buff *skb,
+					int (*okfn)(struct sk_buff *))
 {
 	struct sk_buff *reasm = skb->nfct_reasm;
 
@@ -225,7 +224,7 @@
 		if (!reasm->nfct) {
 			unsigned int ret;
 
-			ret = nf_conntrack_in(PF_INET6, hooknum, reasm);
+			ret = nf_conntrack_in(net, PF_INET6, hooknum, reasm);
 			if (ret != NF_ACCEPT)
 				return ret;
 		}
@@ -235,7 +234,16 @@
 		return NF_ACCEPT;
 	}
 
-	return nf_conntrack_in(PF_INET6, hooknum, skb);
+	return nf_conntrack_in(net, PF_INET6, hooknum, skb);
+}
+
+static unsigned int ipv6_conntrack_in(unsigned int hooknum,
+				      struct sk_buff *skb,
+				      const struct net_device *in,
+				      const struct net_device *out,
+				      int (*okfn)(struct sk_buff *))
+{
+	return __ipv6_conntrack_in(dev_net(in), hooknum, skb, okfn);
 }
 
 static unsigned int ipv6_conntrack_local(unsigned int hooknum,
@@ -250,7 +258,7 @@
 			printk("ipv6_conntrack_local: packet too short\n");
 		return NF_ACCEPT;
 	}
-	return ipv6_conntrack_in(hooknum, skb, in, out, okfn);
+	return __ipv6_conntrack_in(dev_net(out), hooknum, skb, okfn);
 }
 
 static struct nf_hook_ops ipv6_conntrack_ops[] __read_mostly = {
diff --git a/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c b/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c
index 14d47d8..0572617 100644
--- a/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c
+++ b/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c
@@ -81,7 +81,7 @@
 		       const struct sk_buff *skb,
 		       unsigned int dataoff,
 		       enum ip_conntrack_info ctinfo,
-		       int pf,
+		       u_int8_t pf,
 		       unsigned int hooknum)
 {
 	/* Try to delete connection immediately after all replies:
@@ -93,7 +93,7 @@
 			nf_ct_kill_acct(ct, ctinfo, skb);
 	} else {
 		atomic_inc(&ct->proto.icmp.count);
-		nf_conntrack_event_cache(IPCT_PROTOINFO_VOLATILE, skb);
+		nf_conntrack_event_cache(IPCT_PROTOINFO_VOLATILE, ct);
 		nf_ct_refresh_acct(ct, ctinfo, skb, nf_ct_icmpv6_timeout);
 	}
 
@@ -122,7 +122,8 @@
 }
 
 static int
-icmpv6_error_message(struct sk_buff *skb,
+icmpv6_error_message(struct net *net,
+		     struct sk_buff *skb,
 		     unsigned int icmp6off,
 		     enum ip_conntrack_info *ctinfo,
 		     unsigned int hooknum)
@@ -156,7 +157,7 @@
 
 	*ctinfo = IP_CT_RELATED;
 
-	h = nf_conntrack_find_get(&intuple);
+	h = nf_conntrack_find_get(net, &intuple);
 	if (!h) {
 		pr_debug("icmpv6_error: no match\n");
 		return -NF_ACCEPT;
@@ -172,21 +173,21 @@
 }
 
 static int
-icmpv6_error(struct sk_buff *skb, unsigned int dataoff,
-	     enum ip_conntrack_info *ctinfo, int pf, unsigned int hooknum)
+icmpv6_error(struct net *net, struct sk_buff *skb, unsigned int dataoff,
+	     enum ip_conntrack_info *ctinfo, u_int8_t pf, unsigned int hooknum)
 {
 	const struct icmp6hdr *icmp6h;
 	struct icmp6hdr _ih;
 
 	icmp6h = skb_header_pointer(skb, dataoff, sizeof(_ih), &_ih);
 	if (icmp6h == NULL) {
-		if (LOG_INVALID(IPPROTO_ICMPV6))
+		if (LOG_INVALID(net, IPPROTO_ICMPV6))
 		nf_log_packet(PF_INET6, 0, skb, NULL, NULL, NULL,
 			      "nf_ct_icmpv6: short packet ");
 		return -NF_ACCEPT;
 	}
 
-	if (nf_conntrack_checksum && hooknum == NF_INET_PRE_ROUTING &&
+	if (net->ct.sysctl_checksum && hooknum == NF_INET_PRE_ROUTING &&
 	    nf_ip6_checksum(skb, hooknum, dataoff, IPPROTO_ICMPV6)) {
 		nf_log_packet(PF_INET6, 0, skb, NULL, NULL, NULL,
 			      "nf_ct_icmpv6: ICMPv6 checksum failed\n");
@@ -197,7 +198,7 @@
 	if (icmp6h->icmp6_type >= 128)
 		return NF_ACCEPT;
 
-	return icmpv6_error_message(skb, dataoff, ctinfo, hooknum);
+	return icmpv6_error_message(net, skb, dataoff, ctinfo, hooknum);
 }
 
 #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE)
diff --git a/net/ipv6/netfilter/nf_conntrack_reasm.c b/net/ipv6/netfilter/nf_conntrack_reasm.c
index 52d06dd..9967ac7 100644
--- a/net/ipv6/netfilter/nf_conntrack_reasm.c
+++ b/net/ipv6/netfilter/nf_conntrack_reasm.c
@@ -27,7 +27,6 @@
 #include <linux/ipv6.h>
 #include <linux/icmpv6.h>
 #include <linux/random.h>
-#include <linux/jhash.h>
 
 #include <net/sock.h>
 #include <net/snmp.h>
@@ -103,39 +102,12 @@
 };
 #endif
 
-static unsigned int ip6qhashfn(__be32 id, const struct in6_addr *saddr,
-			       const struct in6_addr *daddr)
-{
-	u32 a, b, c;
-
-	a = (__force u32)saddr->s6_addr32[0];
-	b = (__force u32)saddr->s6_addr32[1];
-	c = (__force u32)saddr->s6_addr32[2];
-
-	a += JHASH_GOLDEN_RATIO;
-	b += JHASH_GOLDEN_RATIO;
-	c += nf_frags.rnd;
-	__jhash_mix(a, b, c);
-
-	a += (__force u32)saddr->s6_addr32[3];
-	b += (__force u32)daddr->s6_addr32[0];
-	c += (__force u32)daddr->s6_addr32[1];
-	__jhash_mix(a, b, c);
-
-	a += (__force u32)daddr->s6_addr32[2];
-	b += (__force u32)daddr->s6_addr32[3];
-	c += (__force u32)id;
-	__jhash_mix(a, b, c);
-
-	return c & (INETFRAGS_HASHSZ - 1);
-}
-
 static unsigned int nf_hashfn(struct inet_frag_queue *q)
 {
 	const struct nf_ct_frag6_queue *nq;
 
 	nq = container_of(q, struct nf_ct_frag6_queue, q);
-	return ip6qhashfn(nq->id, &nq->saddr, &nq->daddr);
+	return inet6_hash_frag(nq->id, &nq->saddr, &nq->daddr, nf_frags.rnd);
 }
 
 static void nf_skb_free(struct sk_buff *skb)
@@ -209,7 +181,7 @@
 	arg.dst = dst;
 
 	read_lock_bh(&nf_frags.lock);
-	hash = ip6qhashfn(id, src, dst);
+	hash = inet6_hash_frag(id, src, dst, nf_frags.rnd);
 
 	q = inet_frag_find(&nf_init_frags, &nf_frags, &arg, hash);
 	local_bh_enable();
diff --git a/net/ipv6/proc.c b/net/ipv6/proc.c
index 0179b66..07f0b76 100644
--- a/net/ipv6/proc.c
+++ b/net/ipv6/proc.c
@@ -29,8 +29,6 @@
 #include <net/transp_v6.h>
 #include <net/ipv6.h>
 
-static struct proc_dir_entry *proc_net_devsnmp6;
-
 static int sockstat6_seq_show(struct seq_file *seq, void *v)
 {
 	struct net *net = seq->private;
@@ -48,6 +46,19 @@
 	return 0;
 }
 
+static int sockstat6_seq_open(struct inode *inode, struct file *file)
+{
+	return single_open_net(inode, file, sockstat6_seq_show);
+}
+
+static const struct file_operations sockstat6_seq_fops = {
+	.owner	 = THIS_MODULE,
+	.open	 = sockstat6_seq_open,
+	.read	 = seq_read,
+	.llseek	 = seq_lseek,
+	.release = single_release_net,
+};
+
 static struct snmp_mib snmp6_ipstats_list[] = {
 /* ipv6 mib according to RFC 2465 */
 	SNMP_MIB_ITEM("Ip6InReceives", IPSTATS_MIB_INRECEIVES),
@@ -164,39 +175,23 @@
 
 static int snmp6_seq_show(struct seq_file *seq, void *v)
 {
-	struct inet6_dev *idev = (struct inet6_dev *)seq->private;
+	struct net *net = (struct net *)seq->private;
 
-	if (idev) {
-		seq_printf(seq, "%-32s\t%u\n", "ifIndex", idev->dev->ifindex);
-		snmp6_seq_show_item(seq, (void **)idev->stats.ipv6, snmp6_ipstats_list);
-		snmp6_seq_show_item(seq, (void **)idev->stats.icmpv6, snmp6_icmp6_list);
-		snmp6_seq_show_icmpv6msg(seq, (void **)idev->stats.icmpv6msg);
-	} else {
-		snmp6_seq_show_item(seq, (void **)ipv6_statistics, snmp6_ipstats_list);
-		snmp6_seq_show_item(seq, (void **)icmpv6_statistics, snmp6_icmp6_list);
-		snmp6_seq_show_icmpv6msg(seq, (void **)icmpv6msg_statistics);
-		snmp6_seq_show_item(seq, (void **)udp_stats_in6, snmp6_udp6_list);
-		snmp6_seq_show_item(seq, (void **)udplite_stats_in6, snmp6_udplite6_list);
-	}
+	snmp6_seq_show_item(seq, (void **)net->mib.ipv6_statistics,
+			    snmp6_ipstats_list);
+	snmp6_seq_show_item(seq, (void **)net->mib.icmpv6_statistics,
+			    snmp6_icmp6_list);
+	snmp6_seq_show_icmpv6msg(seq, (void **)net->mib.icmpv6msg_statistics);
+	snmp6_seq_show_item(seq, (void **)net->mib.udp_stats_in6,
+			    snmp6_udp6_list);
+	snmp6_seq_show_item(seq, (void **)net->mib.udplite_stats_in6,
+			    snmp6_udplite6_list);
 	return 0;
 }
 
-static int sockstat6_seq_open(struct inode *inode, struct file *file)
-{
-	return single_open_net(inode, file, sockstat6_seq_show);
-}
-
-static const struct file_operations sockstat6_seq_fops = {
-	.owner	 = THIS_MODULE,
-	.open	 = sockstat6_seq_open,
-	.read	 = seq_read,
-	.llseek	 = seq_lseek,
-	.release = single_release_net,
-};
-
 static int snmp6_seq_open(struct inode *inode, struct file *file)
 {
-	return single_open(file, snmp6_seq_show, PDE(inode)->data);
+	return single_open_net(inode, file, snmp6_seq_show);
 }
 
 static const struct file_operations snmp6_seq_fops = {
@@ -204,24 +199,48 @@
 	.open	 = snmp6_seq_open,
 	.read	 = seq_read,
 	.llseek	 = seq_lseek,
+	.release = single_release_net,
+};
+
+static int snmp6_dev_seq_show(struct seq_file *seq, void *v)
+{
+	struct inet6_dev *idev = (struct inet6_dev *)seq->private;
+
+	seq_printf(seq, "%-32s\t%u\n", "ifIndex", idev->dev->ifindex);
+	snmp6_seq_show_item(seq, (void **)idev->stats.ipv6, snmp6_ipstats_list);
+	snmp6_seq_show_item(seq, (void **)idev->stats.icmpv6, snmp6_icmp6_list);
+	snmp6_seq_show_icmpv6msg(seq, (void **)idev->stats.icmpv6msg);
+	return 0;
+}
+
+static int snmp6_dev_seq_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, snmp6_dev_seq_show, PDE(inode)->data);
+}
+
+static const struct file_operations snmp6_dev_seq_fops = {
+	.owner	 = THIS_MODULE,
+	.open	 = snmp6_dev_seq_open,
+	.read	 = seq_read,
+	.llseek	 = seq_lseek,
 	.release = single_release,
 };
 
 int snmp6_register_dev(struct inet6_dev *idev)
 {
 	struct proc_dir_entry *p;
+	struct net *net;
 
 	if (!idev || !idev->dev)
 		return -EINVAL;
 
-	if (!net_eq(dev_net(idev->dev), &init_net))
-		return 0;
-
-	if (!proc_net_devsnmp6)
+	net = dev_net(idev->dev);
+	if (!net->mib.proc_net_devsnmp6)
 		return -ENOENT;
 
 	p = proc_create_data(idev->dev->name, S_IRUGO,
-			     proc_net_devsnmp6, &snmp6_seq_fops, idev);
+			     net->mib.proc_net_devsnmp6,
+			     &snmp6_dev_seq_fops, idev);
 	if (!p)
 		return -ENOMEM;
 
@@ -231,12 +250,13 @@
 
 int snmp6_unregister_dev(struct inet6_dev *idev)
 {
-	if (!proc_net_devsnmp6)
+	struct net *net = dev_net(idev->dev);
+	if (!net->mib.proc_net_devsnmp6)
 		return -ENOENT;
 	if (!idev || !idev->stats.proc_dir_entry)
 		return -EINVAL;
 	remove_proc_entry(idev->stats.proc_dir_entry->name,
-			  proc_net_devsnmp6);
+			  net->mib.proc_net_devsnmp6);
 	idev->stats.proc_dir_entry = NULL;
 	return 0;
 }
@@ -246,12 +266,27 @@
 	if (!proc_net_fops_create(net, "sockstat6", S_IRUGO,
 			&sockstat6_seq_fops))
 		return -ENOMEM;
+
+	if (!proc_net_fops_create(net, "snmp6", S_IRUGO, &snmp6_seq_fops))
+		goto proc_snmp6_fail;
+
+	net->mib.proc_net_devsnmp6 = proc_mkdir("dev_snmp6", net->proc_net);
+	if (!net->mib.proc_net_devsnmp6)
+		goto proc_dev_snmp6_fail;
 	return 0;
+
+proc_snmp6_fail:
+	proc_net_remove(net, "sockstat6");
+proc_dev_snmp6_fail:
+	proc_net_remove(net, "dev_snmp6");
+	return -ENOMEM;
 }
 
 static void ipv6_proc_exit_net(struct net *net)
 {
 	proc_net_remove(net, "sockstat6");
+	proc_net_remove(net, "dev_snmp6");
+	proc_net_remove(net, "snmp6");
 }
 
 static struct pernet_operations ipv6_proc_ops = {
@@ -261,33 +296,11 @@
 
 int __init ipv6_misc_proc_init(void)
 {
-	int rc = 0;
-
-	if (register_pernet_subsys(&ipv6_proc_ops))
-		goto proc_net_fail;
-
-	if (!proc_net_fops_create(&init_net, "snmp6", S_IRUGO, &snmp6_seq_fops))
-		goto proc_snmp6_fail;
-
-	proc_net_devsnmp6 = proc_mkdir("dev_snmp6", init_net.proc_net);
-	if (!proc_net_devsnmp6)
-		goto proc_dev_snmp6_fail;
-out:
-	return rc;
-
-proc_dev_snmp6_fail:
-	proc_net_remove(&init_net, "snmp6");
-proc_snmp6_fail:
-	unregister_pernet_subsys(&ipv6_proc_ops);
-proc_net_fail:
-	rc = -ENOMEM;
-	goto out;
+	return register_pernet_subsys(&ipv6_proc_ops);
 }
 
 void ipv6_misc_proc_exit(void)
 {
-	proc_net_remove(&init_net, "dev_snmp6");
-	proc_net_remove(&init_net, "snmp6");
 	unregister_pernet_subsys(&ipv6_proc_ops);
 }
 
diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c
index e53e493..2ba04d4 100644
--- a/net/ipv6/raw.c
+++ b/net/ipv6/raw.c
@@ -638,7 +638,7 @@
 	if (err)
 		goto error_fault;
 
-	IP6_INC_STATS(rt->rt6i_idev, IPSTATS_MIB_OUTREQUESTS);
+	IP6_INC_STATS(sock_net(sk), rt->rt6i_idev, IPSTATS_MIB_OUTREQUESTS);
 	err = NF_HOOK(PF_INET6, NF_INET_LOCAL_OUT, skb, NULL, rt->u.dst.dev,
 		      dst_output);
 	if (err > 0)
@@ -652,7 +652,7 @@
 	err = -EFAULT;
 	kfree_skb(skb);
 error:
-	IP6_INC_STATS(rt->rt6i_idev, IPSTATS_MIB_OUTDISCARDS);
+	IP6_INC_STATS(sock_net(sk), rt->rt6i_idev, IPSTATS_MIB_OUTDISCARDS);
 	return err;
 }
 
diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c
index 89184b5..af12de0 100644
--- a/net/ipv6/reassembly.c
+++ b/net/ipv6/reassembly.c
@@ -99,8 +99,8 @@
  * callers should be careful not to use the hash value outside the ipfrag_lock
  * as doing so could race with ipfrag_hash_rnd being recalculated.
  */
-static unsigned int ip6qhashfn(__be32 id, struct in6_addr *saddr,
-			       struct in6_addr *daddr)
+unsigned int inet6_hash_frag(__be32 id, const struct in6_addr *saddr,
+			     const struct in6_addr *daddr, u32 rnd)
 {
 	u32 a, b, c;
 
@@ -110,7 +110,7 @@
 
 	a += JHASH_GOLDEN_RATIO;
 	b += JHASH_GOLDEN_RATIO;
-	c += ip6_frags.rnd;
+	c += rnd;
 	__jhash_mix(a, b, c);
 
 	a += (__force u32)saddr->s6_addr32[3];
@@ -125,13 +125,14 @@
 
 	return c & (INETFRAGS_HASHSZ - 1);
 }
+EXPORT_SYMBOL_GPL(inet6_hash_frag);
 
 static unsigned int ip6_hashfn(struct inet_frag_queue *q)
 {
 	struct frag_queue *fq;
 
 	fq = container_of(q, struct frag_queue, q);
-	return ip6qhashfn(fq->id, &fq->saddr, &fq->daddr);
+	return inet6_hash_frag(fq->id, &fq->saddr, &fq->daddr, ip6_frags.rnd);
 }
 
 int ip6_frag_match(struct inet_frag_queue *q, void *a)
@@ -188,7 +189,7 @@
 
 	evicted = inet_frag_evictor(&net->ipv6.frags, &ip6_frags);
 	if (evicted)
-		IP6_ADD_STATS_BH(idev, IPSTATS_MIB_REASMFAILS, evicted);
+		IP6_ADD_STATS_BH(net, idev, IPSTATS_MIB_REASMFAILS, evicted);
 }
 
 static void ip6_frag_expire(unsigned long data)
@@ -212,8 +213,8 @@
 		goto out;
 
 	rcu_read_lock();
-	IP6_INC_STATS_BH(__in6_dev_get(dev), IPSTATS_MIB_REASMTIMEOUT);
-	IP6_INC_STATS_BH(__in6_dev_get(dev), IPSTATS_MIB_REASMFAILS);
+	IP6_INC_STATS_BH(net, __in6_dev_get(dev), IPSTATS_MIB_REASMTIMEOUT);
+	IP6_INC_STATS_BH(net, __in6_dev_get(dev), IPSTATS_MIB_REASMFAILS);
 	rcu_read_unlock();
 
 	/* Don't send error if the first segment did not arrive. */
@@ -247,7 +248,7 @@
 	arg.dst = dst;
 
 	read_lock(&ip6_frags.lock);
-	hash = ip6qhashfn(id, src, dst);
+	hash = inet6_hash_frag(id, src, dst, ip6_frags.rnd);
 
 	q = inet_frag_find(&net->ipv6.frags, &ip6_frags, &arg, hash);
 	if (q == NULL)
@@ -256,7 +257,7 @@
 	return container_of(q, struct frag_queue, q);
 
 oom:
-	IP6_INC_STATS_BH(idev, IPSTATS_MIB_REASMFAILS);
+	IP6_INC_STATS_BH(net, idev, IPSTATS_MIB_REASMFAILS);
 	return NULL;
 }
 
@@ -266,6 +267,7 @@
 	struct sk_buff *prev, *next;
 	struct net_device *dev;
 	int offset, end;
+	struct net *net = dev_net(skb->dst->dev);
 
 	if (fq->q.last_in & INET_FRAG_COMPLETE)
 		goto err;
@@ -275,7 +277,7 @@
 			((u8 *)(fhdr + 1) - (u8 *)(ipv6_hdr(skb) + 1)));
 
 	if ((unsigned int)end > IPV6_MAXPLEN) {
-		IP6_INC_STATS_BH(ip6_dst_idev(skb->dst),
+		IP6_INC_STATS_BH(net, ip6_dst_idev(skb->dst),
 				 IPSTATS_MIB_INHDRERRORS);
 		icmpv6_param_prob(skb, ICMPV6_HDR_FIELD,
 				  ((u8 *)&fhdr->frag_off -
@@ -308,7 +310,7 @@
 			/* RFC2460 says always send parameter problem in
 			 * this case. -DaveM
 			 */
-			IP6_INC_STATS_BH(ip6_dst_idev(skb->dst),
+			IP6_INC_STATS_BH(net, ip6_dst_idev(skb->dst),
 					 IPSTATS_MIB_INHDRERRORS);
 			icmpv6_param_prob(skb, ICMPV6_HDR_FIELD,
 					  offsetof(struct ipv6hdr, payload_len));
@@ -432,7 +434,8 @@
 	return -1;
 
 err:
-	IP6_INC_STATS(ip6_dst_idev(skb->dst), IPSTATS_MIB_REASMFAILS);
+	IP6_INC_STATS(net, ip6_dst_idev(skb->dst),
+		      IPSTATS_MIB_REASMFAILS);
 	kfree_skb(skb);
 	return -1;
 }
@@ -548,7 +551,8 @@
 					  head->csum);
 
 	rcu_read_lock();
-	IP6_INC_STATS_BH(__in6_dev_get(dev), IPSTATS_MIB_REASMOKS);
+	IP6_INC_STATS_BH(dev_net(dev),
+			 __in6_dev_get(dev), IPSTATS_MIB_REASMOKS);
 	rcu_read_unlock();
 	fq->q.fragments = NULL;
 	return 1;
@@ -562,7 +566,8 @@
 		printk(KERN_DEBUG "ip6_frag_reasm: no memory for reassembly\n");
 out_fail:
 	rcu_read_lock();
-	IP6_INC_STATS_BH(__in6_dev_get(dev), IPSTATS_MIB_REASMFAILS);
+	IP6_INC_STATS_BH(dev_net(dev),
+			 __in6_dev_get(dev), IPSTATS_MIB_REASMFAILS);
 	rcu_read_unlock();
 	return -1;
 }
@@ -572,24 +577,17 @@
 	struct frag_hdr *fhdr;
 	struct frag_queue *fq;
 	struct ipv6hdr *hdr = ipv6_hdr(skb);
-	struct net *net;
+	struct net *net = dev_net(skb->dst->dev);
 
-	IP6_INC_STATS_BH(ip6_dst_idev(skb->dst), IPSTATS_MIB_REASMREQDS);
+	IP6_INC_STATS_BH(net, ip6_dst_idev(skb->dst), IPSTATS_MIB_REASMREQDS);
 
 	/* Jumbo payload inhibits frag. header */
-	if (hdr->payload_len==0) {
-		IP6_INC_STATS(ip6_dst_idev(skb->dst), IPSTATS_MIB_INHDRERRORS);
-		icmpv6_param_prob(skb, ICMPV6_HDR_FIELD,
-				  skb_network_header_len(skb));
-		return -1;
-	}
+	if (hdr->payload_len==0)
+		goto fail_hdr;
+
 	if (!pskb_may_pull(skb, (skb_transport_offset(skb) +
-				 sizeof(struct frag_hdr)))) {
-		IP6_INC_STATS(ip6_dst_idev(skb->dst), IPSTATS_MIB_INHDRERRORS);
-		icmpv6_param_prob(skb, ICMPV6_HDR_FIELD,
-				  skb_network_header_len(skb));
-		return -1;
-	}
+				 sizeof(struct frag_hdr))))
+		goto fail_hdr;
 
 	hdr = ipv6_hdr(skb);
 	fhdr = (struct frag_hdr *)skb_transport_header(skb);
@@ -597,13 +595,13 @@
 	if (!(fhdr->frag_off & htons(0xFFF9))) {
 		/* It is not a fragmented frame */
 		skb->transport_header += sizeof(struct frag_hdr);
-		IP6_INC_STATS_BH(ip6_dst_idev(skb->dst), IPSTATS_MIB_REASMOKS);
+		IP6_INC_STATS_BH(net,
+				 ip6_dst_idev(skb->dst), IPSTATS_MIB_REASMOKS);
 
 		IP6CB(skb)->nhoff = (u8 *)fhdr - skb_network_header(skb);
 		return 1;
 	}
 
-	net = dev_net(skb->dev);
 	if (atomic_read(&net->ipv6.frags.mem) > net->ipv6.frags.high_thresh)
 		ip6_evictor(net, ip6_dst_idev(skb->dst));
 
@@ -620,9 +618,14 @@
 		return ret;
 	}
 
-	IP6_INC_STATS_BH(ip6_dst_idev(skb->dst), IPSTATS_MIB_REASMFAILS);
+	IP6_INC_STATS_BH(net, ip6_dst_idev(skb->dst), IPSTATS_MIB_REASMFAILS);
 	kfree_skb(skb);
 	return -1;
+
+fail_hdr:
+	IP6_INC_STATS(net, ip6_dst_idev(skb->dst), IPSTATS_MIB_INHDRERRORS);
+	icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, skb_network_header_len(skb));
+	return -1;
 }
 
 static struct inet6_protocol frag_protocol =
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index 9af6115..89dc699 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -1003,6 +1003,25 @@
 	return more;
 }
 
+static void icmp6_clean_all(int (*func)(struct rt6_info *rt, void *arg),
+			    void *arg)
+{
+	struct dst_entry *dst, **pprev;
+
+	spin_lock_bh(&icmp6_dst_lock);
+	pprev = &icmp6_dst_gc_list;
+	while ((dst = *pprev) != NULL) {
+		struct rt6_info *rt = (struct rt6_info *) dst;
+		if (func(rt, arg)) {
+			*pprev = dst->next;
+			dst_free(dst);
+		} else {
+			pprev = &dst->next;
+		}
+	}
+	spin_unlock_bh(&icmp6_dst_lock);
+}
+
 static int ip6_dst_gc(struct dst_ops *ops)
 {
 	unsigned long now = jiffies;
@@ -1814,16 +1833,19 @@
 static int ip6_pkt_drop(struct sk_buff *skb, int code, int ipstats_mib_noroutes)
 {
 	int type;
+	struct dst_entry *dst = skb->dst;
 	switch (ipstats_mib_noroutes) {
 	case IPSTATS_MIB_INNOROUTES:
 		type = ipv6_addr_type(&ipv6_hdr(skb)->daddr);
 		if (type == IPV6_ADDR_ANY || type == IPV6_ADDR_RESERVED) {
-			IP6_INC_STATS(ip6_dst_idev(skb->dst), IPSTATS_MIB_INADDRERRORS);
+			IP6_INC_STATS(dev_net(dst->dev), ip6_dst_idev(dst),
+				      IPSTATS_MIB_INADDRERRORS);
 			break;
 		}
 		/* FALLTHROUGH */
 	case IPSTATS_MIB_OUTNOROUTES:
-		IP6_INC_STATS(ip6_dst_idev(skb->dst), ipstats_mib_noroutes);
+		IP6_INC_STATS(dev_net(dst->dev), ip6_dst_idev(dst),
+			      ipstats_mib_noroutes);
 		break;
 	}
 	icmpv6_send(skb, ICMPV6_DEST_UNREACH, code, 0, skb->dev);
@@ -1930,6 +1952,7 @@
 	};
 
 	fib6_clean_all(net, fib6_ifdown, 0, &adn);
+	icmp6_clean_all(fib6_ifdown, &adn);
 }
 
 struct rt6_mtu_change_arg
@@ -2611,10 +2634,8 @@
 	net->ipv6.ip6_prohibit_entry = kmemdup(&ip6_prohibit_entry_template,
 					       sizeof(*net->ipv6.ip6_prohibit_entry),
 					       GFP_KERNEL);
-	if (!net->ipv6.ip6_prohibit_entry) {
-		kfree(net->ipv6.ip6_null_entry);
-		goto out;
-	}
+	if (!net->ipv6.ip6_prohibit_entry)
+		goto out_ip6_null_entry;
 	net->ipv6.ip6_prohibit_entry->u.dst.path =
 		(struct dst_entry *)net->ipv6.ip6_prohibit_entry;
 	net->ipv6.ip6_prohibit_entry->u.dst.ops = net->ipv6.ip6_dst_ops;
@@ -2622,16 +2643,22 @@
 	net->ipv6.ip6_blk_hole_entry = kmemdup(&ip6_blk_hole_entry_template,
 					       sizeof(*net->ipv6.ip6_blk_hole_entry),
 					       GFP_KERNEL);
-	if (!net->ipv6.ip6_blk_hole_entry) {
-		kfree(net->ipv6.ip6_null_entry);
-		kfree(net->ipv6.ip6_prohibit_entry);
-		goto out;
-	}
+	if (!net->ipv6.ip6_blk_hole_entry)
+		goto out_ip6_prohibit_entry;
 	net->ipv6.ip6_blk_hole_entry->u.dst.path =
 		(struct dst_entry *)net->ipv6.ip6_blk_hole_entry;
 	net->ipv6.ip6_blk_hole_entry->u.dst.ops = net->ipv6.ip6_dst_ops;
 #endif
 
+	net->ipv6.sysctl.flush_delay = 0;
+	net->ipv6.sysctl.ip6_rt_max_size = 4096;
+	net->ipv6.sysctl.ip6_rt_gc_min_interval = HZ / 2;
+	net->ipv6.sysctl.ip6_rt_gc_timeout = 60*HZ;
+	net->ipv6.sysctl.ip6_rt_gc_interval = 30*HZ;
+	net->ipv6.sysctl.ip6_rt_gc_elasticity = 9;
+	net->ipv6.sysctl.ip6_rt_mtu_expires = 10*60*HZ;
+	net->ipv6.sysctl.ip6_rt_min_advmss = IPV6_MIN_MTU - 20 - 40;
+
 #ifdef CONFIG_PROC_FS
 	proc_net_fops_create(net, "ipv6_route", 0, &ipv6_route_proc_fops);
 	proc_net_fops_create(net, "rt6_stats", S_IRUGO, &rt6_stats_seq_fops);
@@ -2642,6 +2669,12 @@
 out:
 	return ret;
 
+#ifdef CONFIG_IPV6_MULTIPLE_TABLES
+out_ip6_prohibit_entry:
+	kfree(net->ipv6.ip6_prohibit_entry);
+out_ip6_null_entry:
+	kfree(net->ipv6.ip6_null_entry);
+#endif
 out_ip6_dst_ops:
 	release_net(net->ipv6.ip6_dst_ops->dst_net);
 	kfree(net->ipv6.ip6_dst_ops);
@@ -2688,6 +2721,8 @@
 	if (ret)
 		goto out_kmem_cache;
 
+	ip6_dst_blackhole_ops.kmem_cachep = ip6_dst_ops_template.kmem_cachep;
+
 	/* Registering of the loopback is done before this portion of code,
 	 * the loopback reference in rt6_info will not be taken, do it
 	 * manually for init_net */
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index b585c85..e5310c9b 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -330,7 +330,8 @@
 			th->dest, &hdr->saddr, th->source, skb->dev->ifindex);
 
 	if (sk == NULL) {
-		ICMP6_INC_STATS_BH(__in6_dev_get(skb->dev), ICMP6_MIB_INERRORS);
+		ICMP6_INC_STATS_BH(net, __in6_dev_get(skb->dev),
+				   ICMP6_MIB_INERRORS);
 		return;
 	}
 
@@ -941,117 +942,14 @@
 	return 0;
 }
 
-static void tcp_v6_send_reset(struct sock *sk, struct sk_buff *skb)
+static void tcp_v6_send_response(struct sk_buff *skb, u32 seq, u32 ack, u32 win,
+				 u32 ts, struct tcp_md5sig_key *key, int rst)
 {
 	struct tcphdr *th = tcp_hdr(skb), *t1;
 	struct sk_buff *buff;
 	struct flowi fl;
 	struct net *net = dev_net(skb->dst->dev);
 	struct sock *ctl_sk = net->ipv6.tcp_sk;
-	unsigned int tot_len = sizeof(*th);
-#ifdef CONFIG_TCP_MD5SIG
-	struct tcp_md5sig_key *key;
-#endif
-
-	if (th->rst)
-		return;
-
-	if (!ipv6_unicast_destination(skb))
-		return;
-
-#ifdef CONFIG_TCP_MD5SIG
-	if (sk)
-		key = tcp_v6_md5_do_lookup(sk, &ipv6_hdr(skb)->daddr);
-	else
-		key = NULL;
-
-	if (key)
-		tot_len += TCPOLEN_MD5SIG_ALIGNED;
-#endif
-
-	/*
-	 * We need to grab some memory, and put together an RST,
-	 * and then put it into the queue to be sent.
-	 */
-
-	buff = alloc_skb(MAX_HEADER + sizeof(struct ipv6hdr) + tot_len,
-			 GFP_ATOMIC);
-	if (buff == NULL)
-		return;
-
-	skb_reserve(buff, MAX_HEADER + sizeof(struct ipv6hdr) + tot_len);
-
-	t1 = (struct tcphdr *) skb_push(buff, tot_len);
-
-	/* Swap the send and the receive. */
-	memset(t1, 0, sizeof(*t1));
-	t1->dest = th->source;
-	t1->source = th->dest;
-	t1->doff = tot_len / 4;
-	t1->rst = 1;
-
-	if(th->ack) {
-		t1->seq = th->ack_seq;
-	} else {
-		t1->ack = 1;
-		t1->ack_seq = htonl(ntohl(th->seq) + th->syn + th->fin
-				    + skb->len - (th->doff<<2));
-	}
-
-#ifdef CONFIG_TCP_MD5SIG
-	if (key) {
-		__be32 *opt = (__be32*)(t1 + 1);
-		opt[0] = htonl((TCPOPT_NOP << 24) |
-			       (TCPOPT_NOP << 16) |
-			       (TCPOPT_MD5SIG << 8) |
-			       TCPOLEN_MD5SIG);
-		tcp_v6_md5_hash_hdr((__u8 *)&opt[1], key,
-				    &ipv6_hdr(skb)->daddr,
-				    &ipv6_hdr(skb)->saddr, t1);
-	}
-#endif
-
-	buff->csum = csum_partial((char *)t1, sizeof(*t1), 0);
-
-	memset(&fl, 0, sizeof(fl));
-	ipv6_addr_copy(&fl.fl6_dst, &ipv6_hdr(skb)->saddr);
-	ipv6_addr_copy(&fl.fl6_src, &ipv6_hdr(skb)->daddr);
-
-	t1->check = csum_ipv6_magic(&fl.fl6_src, &fl.fl6_dst,
-				    sizeof(*t1), IPPROTO_TCP,
-				    buff->csum);
-
-	fl.proto = IPPROTO_TCP;
-	fl.oif = inet6_iif(skb);
-	fl.fl_ip_dport = t1->dest;
-	fl.fl_ip_sport = t1->source;
-	security_skb_classify_flow(skb, &fl);
-
-	/* Pass a socket to ip6_dst_lookup either it is for RST
-	 * Underlying function will use this to retrieve the network
-	 * namespace
-	 */
-	if (!ip6_dst_lookup(ctl_sk, &buff->dst, &fl)) {
-
-		if (xfrm_lookup(&buff->dst, &fl, NULL, 0) >= 0) {
-			ip6_xmit(ctl_sk, buff, &fl, NULL, 0);
-			TCP_INC_STATS_BH(net, TCP_MIB_OUTSEGS);
-			TCP_INC_STATS_BH(net, TCP_MIB_OUTRSTS);
-			return;
-		}
-	}
-
-	kfree_skb(buff);
-}
-
-static void tcp_v6_send_ack(struct sk_buff *skb, u32 seq, u32 ack, u32 win, u32 ts,
-			    struct tcp_md5sig_key *key)
-{
-	struct tcphdr *th = tcp_hdr(skb), *t1;
-	struct sk_buff *buff;
-	struct flowi fl;
-	struct net *net = dev_net(skb->dev);
-	struct sock *ctl_sk = net->ipv6.tcp_sk;
 	unsigned int tot_len = sizeof(struct tcphdr);
 	__be32 *topt;
 
@@ -1069,16 +967,17 @@
 
 	skb_reserve(buff, MAX_HEADER + sizeof(struct ipv6hdr) + tot_len);
 
-	t1 = (struct tcphdr *) skb_push(buff,tot_len);
+	t1 = (struct tcphdr *) skb_push(buff, tot_len);
 
 	/* Swap the send and the receive. */
 	memset(t1, 0, sizeof(*t1));
 	t1->dest = th->source;
 	t1->source = th->dest;
-	t1->doff = tot_len/4;
+	t1->doff = tot_len / 4;
 	t1->seq = htonl(seq);
 	t1->ack_seq = htonl(ack);
-	t1->ack = 1;
+	t1->ack = !rst || !th->ack;
+	t1->rst = rst;
 	t1->window = htons(win);
 
 	topt = (__be32 *)(t1 + 1);
@@ -1087,7 +986,7 @@
 		*topt++ = htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) |
 				(TCPOPT_TIMESTAMP << 8) | TCPOLEN_TIMESTAMP);
 		*topt++ = htonl(tcp_time_stamp);
-		*topt = htonl(ts);
+		*topt++ = htonl(ts);
 	}
 
 #ifdef CONFIG_TCP_MD5SIG
@@ -1116,10 +1015,16 @@
 	fl.fl_ip_sport = t1->source;
 	security_skb_classify_flow(skb, &fl);
 
+	/* Pass a socket to ip6_dst_lookup either it is for RST
+	 * Underlying function will use this to retrieve the network
+	 * namespace
+	 */
 	if (!ip6_dst_lookup(ctl_sk, &buff->dst, &fl)) {
 		if (xfrm_lookup(&buff->dst, &fl, NULL, 0) >= 0) {
 			ip6_xmit(ctl_sk, buff, &fl, NULL, 0);
 			TCP_INC_STATS_BH(net, TCP_MIB_OUTSEGS);
+			if (rst)
+				TCP_INC_STATS_BH(net, TCP_MIB_OUTRSTS);
 			return;
 		}
 	}
@@ -1127,6 +1032,38 @@
 	kfree_skb(buff);
 }
 
+static void tcp_v6_send_reset(struct sock *sk, struct sk_buff *skb)
+{
+	struct tcphdr *th = tcp_hdr(skb);
+	u32 seq = 0, ack_seq = 0;
+	struct tcp_md5sig_key *key = NULL;
+
+	if (th->rst)
+		return;
+
+	if (!ipv6_unicast_destination(skb))
+		return;
+
+#ifdef CONFIG_TCP_MD5SIG
+	if (sk)
+		key = tcp_v6_md5_do_lookup(sk, &ipv6_hdr(skb)->daddr);
+#endif
+
+	if (th->ack)
+		seq = ntohl(th->ack_seq);
+	else
+		ack_seq = ntohl(th->seq) + th->syn + th->fin + skb->len -
+			  (th->doff << 2);
+
+	tcp_v6_send_response(skb, seq, ack_seq, 0, 0, key, 1);
+}
+
+static void tcp_v6_send_ack(struct sk_buff *skb, u32 seq, u32 ack, u32 win, u32 ts,
+			    struct tcp_md5sig_key *key)
+{
+	tcp_v6_send_response(skb, seq, ack, win, ts, key, 0);
+}
+
 static void tcp_v6_timewait_ack(struct sock *sk, struct sk_buff *skb)
 {
 	struct inet_timewait_sock *tw = inet_twsk(sk);
@@ -1286,7 +1223,7 @@
 					  struct request_sock *req,
 					  struct dst_entry *dst)
 {
-	struct inet6_request_sock *treq = inet6_rsk(req);
+	struct inet6_request_sock *treq;
 	struct ipv6_pinfo *newnp, *np = inet6_sk(sk);
 	struct tcp6_sock *newtcp6sk;
 	struct inet_sock *newinet;
@@ -1350,6 +1287,7 @@
 		return newsk;
 	}
 
+	treq = inet6_rsk(req);
 	opt = np->opt;
 
 	if (sk_acceptq_is_full(sk))
@@ -1680,11 +1618,7 @@
 	TCP_SKB_CB(skb)->flags = ipv6_get_dsfield(ipv6_hdr(skb));
 	TCP_SKB_CB(skb)->sacked = 0;
 
-	sk = __inet6_lookup(net, &tcp_hashinfo,
-			&ipv6_hdr(skb)->saddr, th->source,
-			&ipv6_hdr(skb)->daddr, ntohs(th->dest),
-			inet6_iif(skb));
-
+	sk = __inet6_lookup_skb(&tcp_hashinfo, skb, th->source, th->dest);
 	if (!sk)
 		goto no_tcp_socket;
 
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
index a6aecf7..e51da8c 100644
--- a/net/ipv6/udp.c
+++ b/net/ipv6/udp.c
@@ -107,6 +107,21 @@
 	return result;
 }
 
+static struct sock *__udp6_lib_lookup_skb(struct sk_buff *skb,
+					  __be16 sport, __be16 dport,
+					  struct hlist_head udptable[])
+{
+	struct sock *sk;
+	struct ipv6hdr *iph = ipv6_hdr(skb);
+
+	if (unlikely(sk = skb_steal_sock(skb)))
+		return sk;
+	else
+		return __udp6_lib_lookup(dev_net(skb->dst->dev), &iph->saddr, sport,
+					 &iph->daddr, dport, inet6_iif(skb),
+					 udptable);
+}
+
 /*
  * 	This should be easy, if there is something there we
  * 	return it, otherwise we block.
@@ -488,8 +503,7 @@
 	 * check socket cache ... must talk to Alan about his plans
 	 * for sock caches... i'll skip this for now.
 	 */
-	sk = __udp6_lib_lookup(net, saddr, uh->source,
-			       daddr, uh->dest, inet6_iif(skb), udptable);
+	sk = __udp6_lib_lookup_skb(skb, uh->source, uh->dest, udptable);
 
 	if (sk == NULL) {
 		if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb))
diff --git a/net/ipv6/udplite.c b/net/ipv6/udplite.c
index f6cdcb3..3cd1a1a 100644
--- a/net/ipv6/udplite.c
+++ b/net/ipv6/udplite.c
@@ -13,8 +13,6 @@
  */
 #include "udp_impl.h"
 
-DEFINE_SNMP_STAT(struct udp_mib, udplite_stats_in6) __read_mostly;
-
 static int udplitev6_rcv(struct sk_buff *skb)
 {
 	return __udp6_lib_rcv(skb, udplite_hash, IPPROTO_UDPLITE);
diff --git a/net/iucv/iucv.c b/net/iucv/iucv.c
index 705959b..d7b54b5 100644
--- a/net/iucv/iucv.c
+++ b/net/iucv/iucv.c
@@ -524,7 +524,6 @@
 	get_online_cpus();
 	for_each_online_cpu(cpu)
 		smp_call_function_single(cpu, iucv_declare_cpu, NULL, 1);
-	preempt_enable();
 	if (cpus_empty(iucv_buffer_cpumask))
 		/* No cpu could declare an iucv buffer. */
 		goto out_path;
@@ -547,7 +546,9 @@
  */
 static void iucv_disable(void)
 {
+	get_online_cpus();
 	on_each_cpu(iucv_retrieve_cpu, NULL, 1);
+	put_online_cpus();
 	kfree(iucv_path_table);
 }
 
diff --git a/net/key/af_key.c b/net/key/af_key.c
index d628df9..e55e044 100644
--- a/net/key/af_key.c
+++ b/net/key/af_key.c
@@ -58,6 +58,7 @@
 			struct xfrm_policy_walk	policy;
 			struct xfrm_state_walk	state;
 		} u;
+		struct sk_buff	*skb;
 	} dump;
 };
 
@@ -73,22 +74,22 @@
 	return 0;
 }
 
-static int pfkey_do_dump(struct pfkey_sock *pfk)
+static void pfkey_terminate_dump(struct pfkey_sock *pfk)
 {
-	int rc;
-
-	rc = pfk->dump.dump(pfk);
-	if (rc == -ENOBUFS)
-		return 0;
-
-	pfk->dump.done(pfk);
-	pfk->dump.dump = NULL;
-	pfk->dump.done = NULL;
-	return rc;
+	if (pfk->dump.dump) {
+		if (pfk->dump.skb) {
+			kfree_skb(pfk->dump.skb);
+			pfk->dump.skb = NULL;
+		}
+		pfk->dump.done(pfk);
+		pfk->dump.dump = NULL;
+		pfk->dump.done = NULL;
+	}
 }
 
 static void pfkey_sock_destruct(struct sock *sk)
 {
+	pfkey_terminate_dump(pfkey_sk(sk));
 	skb_queue_purge(&sk->sk_receive_queue);
 
 	if (!sock_flag(sk, SOCK_DEAD)) {
@@ -310,6 +311,31 @@
 	return err;
 }
 
+static int pfkey_do_dump(struct pfkey_sock *pfk)
+{
+	struct sadb_msg *hdr;
+	int rc;
+
+	rc = pfk->dump.dump(pfk);
+	if (rc == -ENOBUFS)
+		return 0;
+
+	if (pfk->dump.skb) {
+		if (!pfkey_can_dump(&pfk->sk))
+			return 0;
+
+		hdr = (struct sadb_msg *) pfk->dump.skb->data;
+		hdr->sadb_msg_seq = 0;
+		hdr->sadb_msg_errno = rc;
+		pfkey_broadcast(pfk->dump.skb, GFP_ATOMIC, BROADCAST_ONE,
+				&pfk->sk);
+		pfk->dump.skb = NULL;
+	}
+
+	pfkey_terminate_dump(pfk);
+	return rc;
+}
+
 static inline void pfkey_hdr_dup(struct sadb_msg *new, struct sadb_msg *orig)
 {
 	*new = *orig;
@@ -372,6 +398,7 @@
 	[SADB_X_EXT_NAT_T_DPORT]	= (u8) sizeof(struct sadb_x_nat_t_port),
 	[SADB_X_EXT_NAT_T_OA]		= (u8) sizeof(struct sadb_address),
 	[SADB_X_EXT_SEC_CTX]		= (u8) sizeof(struct sadb_x_sec_ctx),
+	[SADB_X_EXT_KMADDRESS]		= (u8) sizeof(struct sadb_x_kmaddress),
 };
 
 /* Verify sadb_address_{len,prefixlen} against sa_family.  */
@@ -1736,9 +1763,14 @@
 	out_hdr->sadb_msg_satype = pfkey_proto2satype(x->id.proto);
 	out_hdr->sadb_msg_errno = 0;
 	out_hdr->sadb_msg_reserved = 0;
-	out_hdr->sadb_msg_seq = count;
+	out_hdr->sadb_msg_seq = count + 1;
 	out_hdr->sadb_msg_pid = pfk->dump.msg_pid;
-	pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ONE, &pfk->sk);
+
+	if (pfk->dump.skb)
+		pfkey_broadcast(pfk->dump.skb, GFP_ATOMIC, BROADCAST_ONE,
+				&pfk->sk);
+	pfk->dump.skb = out_skb;
+
 	return 0;
 }
 
@@ -2237,7 +2269,7 @@
 	return 0;
 
 out:
-	xp->dead = 1;
+	xp->walk.dead = 1;
 	xfrm_policy_destroy(xp);
 	return err;
 }
@@ -2309,6 +2341,7 @@
 
 	c.seq = hdr->sadb_msg_seq;
 	c.pid = hdr->sadb_msg_pid;
+	c.data.byid = 0;
 	c.event = XFRM_MSG_DELPOLICY;
 	km_policy_notify(xp, pol->sadb_x_policy_dir-1, &c);
 
@@ -2353,24 +2386,21 @@
 	return PFKEY_ALIGN8(pfkey_sockaddr_len(family) * 2);
 }
 
-static int parse_sockaddr_pair(struct sadb_x_ipsecrequest *rq,
+static int parse_sockaddr_pair(struct sockaddr *sa, int ext_len,
 			       xfrm_address_t *saddr, xfrm_address_t *daddr,
 			       u16 *family)
 {
-	u8 *sa = (u8 *) (rq + 1);
 	int af, socklen;
 
-	if (rq->sadb_x_ipsecrequest_len <
-	    pfkey_sockaddr_pair_size(((struct sockaddr *)sa)->sa_family))
+	if (ext_len < pfkey_sockaddr_pair_size(sa->sa_family))
 		return -EINVAL;
 
-	af = pfkey_sockaddr_extract((struct sockaddr *) sa,
-				    saddr);
+	af = pfkey_sockaddr_extract(sa, saddr);
 	if (!af)
 		return -EINVAL;
 
 	socklen = pfkey_sockaddr_len(af);
-	if (pfkey_sockaddr_extract((struct sockaddr *) (sa + socklen),
+	if (pfkey_sockaddr_extract((struct sockaddr *) (((u8 *)sa) + socklen),
 				   daddr) != af)
 		return -EINVAL;
 
@@ -2390,7 +2420,9 @@
 		return -EINVAL;
 
 	/* old endoints */
-	err = parse_sockaddr_pair(rq1, &m->old_saddr, &m->old_daddr,
+	err = parse_sockaddr_pair((struct sockaddr *)(rq1 + 1),
+				  rq1->sadb_x_ipsecrequest_len,
+				  &m->old_saddr, &m->old_daddr,
 				  &m->old_family);
 	if (err)
 		return err;
@@ -2403,7 +2435,9 @@
 		return -EINVAL;
 
 	/* new endpoints */
-	err = parse_sockaddr_pair(rq2, &m->new_saddr, &m->new_daddr,
+	err = parse_sockaddr_pair((struct sockaddr *)(rq2 + 1),
+				  rq2->sadb_x_ipsecrequest_len,
+				  &m->new_saddr, &m->new_daddr,
 				  &m->new_family);
 	if (err)
 		return err;
@@ -2429,29 +2463,40 @@
 	int i, len, ret, err = -EINVAL;
 	u8 dir;
 	struct sadb_address *sa;
+	struct sadb_x_kmaddress *kma;
 	struct sadb_x_policy *pol;
 	struct sadb_x_ipsecrequest *rq;
 	struct xfrm_selector sel;
 	struct xfrm_migrate m[XFRM_MAX_DEPTH];
+	struct xfrm_kmaddress k;
 
 	if (!present_and_same_family(ext_hdrs[SADB_EXT_ADDRESS_SRC - 1],
-	    ext_hdrs[SADB_EXT_ADDRESS_DST - 1]) ||
+				     ext_hdrs[SADB_EXT_ADDRESS_DST - 1]) ||
 	    !ext_hdrs[SADB_X_EXT_POLICY - 1]) {
 		err = -EINVAL;
 		goto out;
 	}
 
+	kma = ext_hdrs[SADB_X_EXT_KMADDRESS - 1];
 	pol = ext_hdrs[SADB_X_EXT_POLICY - 1];
-	if (!pol) {
-		err = -EINVAL;
-		goto out;
-	}
 
 	if (pol->sadb_x_policy_dir >= IPSEC_DIR_MAX) {
 		err = -EINVAL;
 		goto out;
 	}
 
+	if (kma) {
+		/* convert sadb_x_kmaddress to xfrm_kmaddress */
+		k.reserved = kma->sadb_x_kmaddress_reserved;
+		ret = parse_sockaddr_pair((struct sockaddr *)(kma + 1),
+					  8*(kma->sadb_x_kmaddress_len) - sizeof(*kma),
+					  &k.local, &k.remote, &k.family);
+		if (ret < 0) {
+			err = ret;
+			goto out;
+		}
+	}
+
 	dir = pol->sadb_x_policy_dir - 1;
 	memset(&sel, 0, sizeof(sel));
 
@@ -2496,7 +2541,8 @@
 		goto out;
 	}
 
-	return xfrm_migrate(&sel, dir, XFRM_POLICY_TYPE_MAIN, m, i);
+	return xfrm_migrate(&sel, dir, XFRM_POLICY_TYPE_MAIN, m, i,
+			    kma ? &k : NULL);
 
  out:
 	return err;
@@ -2575,9 +2621,14 @@
 	out_hdr->sadb_msg_type = SADB_X_SPDDUMP;
 	out_hdr->sadb_msg_satype = SADB_SATYPE_UNSPEC;
 	out_hdr->sadb_msg_errno = 0;
-	out_hdr->sadb_msg_seq = count;
+	out_hdr->sadb_msg_seq = count + 1;
 	out_hdr->sadb_msg_pid = pfk->dump.msg_pid;
-	pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ONE, &pfk->sk);
+
+	if (pfk->dump.skb)
+		pfkey_broadcast(pfk->dump.skb, GFP_ATOMIC, BROADCAST_ONE,
+				&pfk->sk);
+	pfk->dump.skb = out_skb;
+
 	return 0;
 }
 
@@ -3283,6 +3334,32 @@
 	return 0;
 }
 
+
+static int set_sadb_kmaddress(struct sk_buff *skb, struct xfrm_kmaddress *k)
+{
+	struct sadb_x_kmaddress *kma;
+	u8 *sa;
+	int family = k->family;
+	int socklen = pfkey_sockaddr_len(family);
+	int size_req;
+
+	size_req = (sizeof(struct sadb_x_kmaddress) +
+		    pfkey_sockaddr_pair_size(family));
+
+	kma = (struct sadb_x_kmaddress *)skb_put(skb, size_req);
+	memset(kma, 0, size_req);
+	kma->sadb_x_kmaddress_len = size_req / 8;
+	kma->sadb_x_kmaddress_exttype = SADB_X_EXT_KMADDRESS;
+	kma->sadb_x_kmaddress_reserved = k->reserved;
+
+	sa = (u8 *)(kma + 1);
+	if (!pfkey_sockaddr_fill(&k->local, 0, (struct sockaddr *)sa, family) ||
+	    !pfkey_sockaddr_fill(&k->remote, 0, (struct sockaddr *)(sa+socklen), family))
+		return -EINVAL;
+
+	return 0;
+}
+
 static int set_ipsecrequest(struct sk_buff *skb,
 			    uint8_t proto, uint8_t mode, int level,
 			    uint32_t reqid, uint8_t family,
@@ -3315,7 +3392,8 @@
 
 #ifdef CONFIG_NET_KEY_MIGRATE
 static int pfkey_send_migrate(struct xfrm_selector *sel, u8 dir, u8 type,
-			      struct xfrm_migrate *m, int num_bundles)
+			      struct xfrm_migrate *m, int num_bundles,
+			      struct xfrm_kmaddress *k)
 {
 	int i;
 	int sasize_sel;
@@ -3332,6 +3410,12 @@
 	if (num_bundles <= 0 || num_bundles > XFRM_MAX_DEPTH)
 		return -EINVAL;
 
+	if (k != NULL) {
+		/* addresses for KM */
+		size += PFKEY_ALIGN8(sizeof(struct sadb_x_kmaddress) +
+				     pfkey_sockaddr_pair_size(k->family));
+	}
+
 	/* selector */
 	sasize_sel = pfkey_sockaddr_size(sel->family);
 	if (!sasize_sel)
@@ -3368,6 +3452,10 @@
 	hdr->sadb_msg_seq = 0;
 	hdr->sadb_msg_pid = 0;
 
+	/* Addresses to be used by KM for negotiation, if ext is available */
+	if (k != NULL && (set_sadb_kmaddress(skb, k) < 0))
+		return -EINVAL;
+
 	/* selector src */
 	set_sadb_address(skb, sasize_sel, SADB_EXT_ADDRESS_SRC, sel);
 
@@ -3413,7 +3501,8 @@
 }
 #else
 static int pfkey_send_migrate(struct xfrm_selector *sel, u8 dir, u8 type,
-			      struct xfrm_migrate *m, int num_bundles)
+			      struct xfrm_migrate *m, int num_bundles,
+			      struct xfrm_kmaddress *k)
 {
 	return -ENOPROTOOPT;
 }
diff --git a/net/mac80211/Kconfig b/net/mac80211/Kconfig
index 80d6933..7f710a2 100644
--- a/net/mac80211/Kconfig
+++ b/net/mac80211/Kconfig
@@ -22,6 +22,11 @@
 	  mac80211 that uses a PID controller to select the TX
 	  rate.
 
+config MAC80211_RC_MINSTREL
+	bool "Minstrel"
+	---help---
+	  This option enables the 'minstrel' TX rate control algorithm
+
 choice
 	prompt "Default rate control algorithm"
 	default MAC80211_RC_DEFAULT_PID
@@ -39,11 +44,19 @@
 	  default rate control algorithm. You should choose
 	  this unless you know what you are doing.
 
+config MAC80211_RC_DEFAULT_MINSTREL
+	bool "Minstrel"
+	depends on MAC80211_RC_MINSTREL
+	---help---
+	  Select Minstrel as the default rate control algorithm.
+
+
 endchoice
 
 config MAC80211_RC_DEFAULT
 	string
 	default "pid" if MAC80211_RC_DEFAULT_PID
+	default "minstrel" if MAC80211_RC_DEFAULT_MINSTREL
 	default ""
 
 endmenu
@@ -179,19 +192,6 @@
 
 	  Do not select this option.
 
-config MAC80211_LOWTX_FRAME_DUMP
-	bool "Debug frame dumping"
-	depends on MAC80211_DEBUG_MENU
-	---help---
-	  Selecting this option will cause the stack to
-	  print a message for each frame that is handed
-	  to the lowlevel driver for transmission. This
-	  message includes all MAC addresses and the
-	  frame control field.
-
-	  If unsure, say N and insert the debugging code
-	  you require into the driver you are debugging.
-
 config MAC80211_DEBUG_COUNTERS
 	bool "Extra statistics for TX/RX debugging"
 	depends on MAC80211_DEBUG_MENU
diff --git a/net/mac80211/Makefile b/net/mac80211/Makefile
index a169b02..31cfd1f 100644
--- a/net/mac80211/Makefile
+++ b/net/mac80211/Makefile
@@ -7,6 +7,8 @@
 	sta_info.o \
 	wep.o \
 	wpa.o \
+	scan.o \
+	ht.o \
 	mlme.o \
 	iface.o \
 	rate.o \
@@ -15,6 +17,7 @@
 	aes_ccm.o \
 	cfg.o \
 	rx.o \
+	spectmgmt.o \
 	tx.o \
 	key.o \
 	util.o \
@@ -38,4 +41,8 @@
 rc80211_pid-y := rc80211_pid_algo.o
 rc80211_pid-$(CONFIG_MAC80211_DEBUGFS) += rc80211_pid_debugfs.o
 
+rc80211_minstrel-y := rc80211_minstrel.o
+rc80211_minstrel-$(CONFIG_MAC80211_DEBUGFS) += rc80211_minstrel_debugfs.o
+
 mac80211-$(CONFIG_MAC80211_RC_PID) += $(rc80211_pid-y)
+mac80211-$(CONFIG_MAC80211_RC_MINSTREL) += $(rc80211_minstrel-y)
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 297c257..855126a 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -17,26 +17,26 @@
 #include "rate.h"
 #include "mesh.h"
 
-static enum ieee80211_if_types
-nl80211_type_to_mac80211_type(enum nl80211_iftype type)
+struct ieee80211_hw *wiphy_to_hw(struct wiphy *wiphy)
+{
+	struct ieee80211_local *local = wiphy_priv(wiphy);
+	return &local->hw;
+}
+EXPORT_SYMBOL(wiphy_to_hw);
+
+static bool nl80211_type_check(enum nl80211_iftype type)
 {
 	switch (type) {
-	case NL80211_IFTYPE_UNSPECIFIED:
-		return IEEE80211_IF_TYPE_STA;
 	case NL80211_IFTYPE_ADHOC:
-		return IEEE80211_IF_TYPE_IBSS;
 	case NL80211_IFTYPE_STATION:
-		return IEEE80211_IF_TYPE_STA;
 	case NL80211_IFTYPE_MONITOR:
-		return IEEE80211_IF_TYPE_MNTR;
 #ifdef CONFIG_MAC80211_MESH
 	case NL80211_IFTYPE_MESH_POINT:
-		return IEEE80211_IF_TYPE_MESH_POINT;
 #endif
 	case NL80211_IFTYPE_WDS:
-		return IEEE80211_IF_TYPE_WDS;
+		return true;
 	default:
-		return IEEE80211_IF_TYPE_INVALID;
+		return false;
 	}
 }
 
@@ -45,17 +45,15 @@
 			       struct vif_params *params)
 {
 	struct ieee80211_local *local = wiphy_priv(wiphy);
-	enum ieee80211_if_types itype;
 	struct net_device *dev;
 	struct ieee80211_sub_if_data *sdata;
 	int err;
 
-	itype = nl80211_type_to_mac80211_type(type);
-	if (itype == IEEE80211_IF_TYPE_INVALID)
+	if (!nl80211_type_check(type))
 		return -EINVAL;
 
-	err = ieee80211_if_add(local, name, &dev, itype, params);
-	if (err || itype != IEEE80211_IF_TYPE_MNTR || !flags)
+	err = ieee80211_if_add(local, name, &dev, type, params);
+	if (err || type != NL80211_IFTYPE_MONITOR || !flags)
 		return err;
 
 	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
@@ -66,13 +64,16 @@
 static int ieee80211_del_iface(struct wiphy *wiphy, int ifindex)
 {
 	struct net_device *dev;
+	struct ieee80211_sub_if_data *sdata;
 
 	/* we're under RTNL */
 	dev = __dev_get_by_index(&init_net, ifindex);
 	if (!dev)
 		return -ENODEV;
 
-	ieee80211_if_remove(dev);
+	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+	ieee80211_if_remove(sdata);
 
 	return 0;
 }
@@ -81,9 +82,7 @@
 				  enum nl80211_iftype type, u32 *flags,
 				  struct vif_params *params)
 {
-	struct ieee80211_local *local = wiphy_priv(wiphy);
 	struct net_device *dev;
-	enum ieee80211_if_types itype;
 	struct ieee80211_sub_if_data *sdata;
 	int ret;
 
@@ -92,25 +91,24 @@
 	if (!dev)
 		return -ENODEV;
 
-	itype = nl80211_type_to_mac80211_type(type);
-	if (itype == IEEE80211_IF_TYPE_INVALID)
+	if (!nl80211_type_check(type))
 		return -EINVAL;
 
-	if (dev == local->mdev)
-		return -EOPNOTSUPP;
-
 	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 
-	ret = ieee80211_if_change_type(sdata, itype);
+	ret = ieee80211_if_change_type(sdata, type);
 	if (ret)
 		return ret;
 
-	if (ieee80211_vif_is_mesh(&sdata->vif) && params->mesh_id_len)
-		ieee80211_if_sta_set_mesh_id(&sdata->u.sta,
-					     params->mesh_id_len,
-					     params->mesh_id);
+	if (netif_running(sdata->dev))
+		return -EBUSY;
 
-	if (sdata->vif.type != IEEE80211_IF_TYPE_MNTR || !flags)
+	if (ieee80211_vif_is_mesh(&sdata->vif) && params->mesh_id_len)
+		ieee80211_sdata_set_mesh_id(sdata,
+					    params->mesh_id_len,
+					    params->mesh_id);
+
+	if (sdata->vif.type != NL80211_IFTYPE_MONITOR || !flags)
 		return 0;
 
 	sdata->u.mntr_flags = *flags;
@@ -121,16 +119,12 @@
 			     u8 key_idx, u8 *mac_addr,
 			     struct key_params *params)
 {
-	struct ieee80211_local *local = wiphy_priv(wiphy);
 	struct ieee80211_sub_if_data *sdata;
 	struct sta_info *sta = NULL;
 	enum ieee80211_key_alg alg;
 	struct ieee80211_key *key;
 	int err;
 
-	if (dev == local->mdev)
-		return -EOPNOTSUPP;
-
 	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 
 	switch (params->cipher) {
@@ -175,14 +169,10 @@
 static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev,
 			     u8 key_idx, u8 *mac_addr)
 {
-	struct ieee80211_local *local = wiphy_priv(wiphy);
 	struct ieee80211_sub_if_data *sdata;
 	struct sta_info *sta;
 	int ret;
 
-	if (dev == local->mdev)
-		return -EOPNOTSUPP;
-
 	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 
 	rcu_read_lock();
@@ -223,7 +213,6 @@
 			     void (*callback)(void *cookie,
 					      struct key_params *params))
 {
-	struct ieee80211_local *local = wiphy_priv(wiphy);
 	struct ieee80211_sub_if_data *sdata;
 	struct sta_info *sta = NULL;
 	u8 seq[6] = {0};
@@ -233,9 +222,6 @@
 	u16 iv16;
 	int err = -ENOENT;
 
-	if (dev == local->mdev)
-		return -EOPNOTSUPP;
-
 	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 
 	rcu_read_lock();
@@ -311,12 +297,8 @@
 					struct net_device *dev,
 					u8 key_idx)
 {
-	struct ieee80211_local *local = wiphy_priv(wiphy);
 	struct ieee80211_sub_if_data *sdata;
 
-	if (dev == local->mdev)
-		return -EOPNOTSUPP;
-
 	rcu_read_lock();
 
 	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
@@ -365,7 +347,7 @@
 	sta = sta_info_get_by_idx(local, idx, dev);
 	if (sta) {
 		ret = 0;
-		memcpy(mac, sta->addr, ETH_ALEN);
+		memcpy(mac, sta->sta.addr, ETH_ALEN);
 		sta_set_sinfo(sta, sinfo);
 	}
 
@@ -497,16 +479,12 @@
 static int ieee80211_add_beacon(struct wiphy *wiphy, struct net_device *dev,
 				struct beacon_parameters *params)
 {
-	struct ieee80211_local *local = wiphy_priv(wiphy);
 	struct ieee80211_sub_if_data *sdata;
 	struct beacon_data *old;
 
-	if (dev == local->mdev)
-		return -EOPNOTSUPP;
-
 	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 
-	if (sdata->vif.type != IEEE80211_IF_TYPE_AP)
+	if (sdata->vif.type != NL80211_IFTYPE_AP)
 		return -EINVAL;
 
 	old = sdata->u.ap.beacon;
@@ -520,16 +498,12 @@
 static int ieee80211_set_beacon(struct wiphy *wiphy, struct net_device *dev,
 				struct beacon_parameters *params)
 {
-	struct ieee80211_local *local = wiphy_priv(wiphy);
 	struct ieee80211_sub_if_data *sdata;
 	struct beacon_data *old;
 
-	if (dev == local->mdev)
-		return -EOPNOTSUPP;
-
 	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 
-	if (sdata->vif.type != IEEE80211_IF_TYPE_AP)
+	if (sdata->vif.type != NL80211_IFTYPE_AP)
 		return -EINVAL;
 
 	old = sdata->u.ap.beacon;
@@ -542,16 +516,12 @@
 
 static int ieee80211_del_beacon(struct wiphy *wiphy, struct net_device *dev)
 {
-	struct ieee80211_local *local = wiphy_priv(wiphy);
 	struct ieee80211_sub_if_data *sdata;
 	struct beacon_data *old;
 
-	if (dev == local->mdev)
-		return -EOPNOTSUPP;
-
 	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 
-	if (sdata->vif.type != IEEE80211_IF_TYPE_AP)
+	if (sdata->vif.type != NL80211_IFTYPE_AP)
 		return -EINVAL;
 
 	old = sdata->u.ap.beacon;
@@ -594,7 +564,7 @@
 	 * Update response frame; IEEE Std 802.2-1998, 5.4.1.2.1 */
 
 	memset(msg->da, 0xff, ETH_ALEN);
-	memcpy(msg->sa, sta->addr, ETH_ALEN);
+	memcpy(msg->sa, sta->sta.addr, ETH_ALEN);
 	msg->len = htons(6);
 	msg->dsap = 0;
 	msg->ssap = 0x01;	/* NULL LSAP, CR Bit: Response */
@@ -649,9 +619,9 @@
 	 */
 
 	if (params->aid) {
-		sta->aid = params->aid;
-		if (sta->aid > IEEE80211_MAX_AID)
-			sta->aid = 0; /* XXX: should this be an error? */
+		sta->sta.aid = params->aid;
+		if (sta->sta.aid > IEEE80211_MAX_AID)
+			sta->sta.aid = 0; /* XXX: should this be an error? */
 	}
 
 	if (params->listen_interval >= 0)
@@ -668,7 +638,12 @@
 					rates |= BIT(j);
 			}
 		}
-		sta->supp_rates[local->oper_channel->band] = rates;
+		sta->sta.supp_rates[local->oper_channel->band] = rates;
+	}
+
+	if (params->ht_capa) {
+		ieee80211_ht_cap_ie_to_ht_info(params->ht_capa,
+					       &sta->sta.ht_info);
 	}
 
 	if (ieee80211_vif_is_mesh(&sdata->vif) && params->plink_action) {
@@ -691,9 +666,6 @@
 	struct ieee80211_sub_if_data *sdata;
 	int err;
 
-	if (dev == local->mdev || params->vlan == local->mdev)
-		return -EOPNOTSUPP;
-
 	/* Prevent a race with changing the rate control algorithm */
 	if (!netif_running(dev))
 		return -ENETDOWN;
@@ -701,8 +673,8 @@
 	if (params->vlan) {
 		sdata = IEEE80211_DEV_TO_SUB_IF(params->vlan);
 
-		if (sdata->vif.type != IEEE80211_IF_TYPE_VLAN &&
-		    sdata->vif.type != IEEE80211_IF_TYPE_AP)
+		if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
+		    sdata->vif.type != NL80211_IFTYPE_AP)
 			return -EINVAL;
 	} else
 		sdata = IEEE80211_DEV_TO_SUB_IF(dev);
@@ -721,7 +693,7 @@
 
 	sta_apply_parameters(local, sta, params);
 
-	rate_control_rate_init(sta, local);
+	rate_control_rate_init(sta);
 
 	rcu_read_lock();
 
@@ -732,8 +704,8 @@
 		return err;
 	}
 
-	if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN ||
-	    sdata->vif.type == IEEE80211_IF_TYPE_AP)
+	if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN ||
+	    sdata->vif.type == NL80211_IFTYPE_AP)
 		ieee80211_send_layer2_update(sta);
 
 	rcu_read_unlock();
@@ -748,9 +720,6 @@
 	struct ieee80211_sub_if_data *sdata;
 	struct sta_info *sta;
 
-	if (dev == local->mdev)
-		return -EOPNOTSUPP;
-
 	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 
 	if (mac) {
@@ -782,9 +751,6 @@
 	struct sta_info *sta;
 	struct ieee80211_sub_if_data *vlansdata;
 
-	if (dev == local->mdev || params->vlan == local->mdev)
-		return -EOPNOTSUPP;
-
 	rcu_read_lock();
 
 	/* XXX: get sta belonging to dev */
@@ -797,8 +763,8 @@
 	if (params->vlan && params->vlan != sta->sdata->dev) {
 		vlansdata = IEEE80211_DEV_TO_SUB_IF(params->vlan);
 
-		if (vlansdata->vif.type != IEEE80211_IF_TYPE_VLAN &&
-		    vlansdata->vif.type != IEEE80211_IF_TYPE_AP) {
+		if (vlansdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
+		    vlansdata->vif.type != NL80211_IFTYPE_AP) {
 			rcu_read_unlock();
 			return -EINVAL;
 		}
@@ -824,15 +790,12 @@
 	struct sta_info *sta;
 	int err;
 
-	if (dev == local->mdev)
-		return -EOPNOTSUPP;
-
 	if (!netif_running(dev))
 		return -ENETDOWN;
 
 	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 
-	if (sdata->vif.type != IEEE80211_IF_TYPE_MESH_POINT)
+	if (sdata->vif.type != NL80211_IFTYPE_MESH_POINT)
 		return -ENOTSUPP;
 
 	rcu_read_lock();
@@ -842,13 +805,13 @@
 		return -ENOENT;
 	}
 
-	err = mesh_path_add(dst, dev);
+	err = mesh_path_add(dst, sdata);
 	if (err) {
 		rcu_read_unlock();
 		return err;
 	}
 
-	mpath = mesh_path_lookup(dst, dev);
+	mpath = mesh_path_lookup(dst, sdata);
 	if (!mpath) {
 		rcu_read_unlock();
 		return -ENXIO;
@@ -862,10 +825,12 @@
 static int ieee80211_del_mpath(struct wiphy *wiphy, struct net_device *dev,
 				 u8 *dst)
 {
-	if (dst)
-		return mesh_path_del(dst, dev);
+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 
-	mesh_path_flush(dev);
+	if (dst)
+		return mesh_path_del(dst, sdata);
+
+	mesh_path_flush(sdata);
 	return 0;
 }
 
@@ -878,15 +843,12 @@
 	struct mesh_path *mpath;
 	struct sta_info *sta;
 
-	if (dev == local->mdev)
-		return -EOPNOTSUPP;
-
 	if (!netif_running(dev))
 		return -ENETDOWN;
 
 	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 
-	if (sdata->vif.type != IEEE80211_IF_TYPE_MESH_POINT)
+	if (sdata->vif.type != NL80211_IFTYPE_MESH_POINT)
 		return -ENOTSUPP;
 
 	rcu_read_lock();
@@ -897,7 +859,7 @@
 		return -ENOENT;
 	}
 
-	mpath = mesh_path_lookup(dst, dev);
+	mpath = mesh_path_lookup(dst, sdata);
 	if (!mpath) {
 		rcu_read_unlock();
 		return -ENOENT;
@@ -913,7 +875,7 @@
 			    struct mpath_info *pinfo)
 {
 	if (mpath->next_hop)
-		memcpy(next_hop, mpath->next_hop->addr, ETH_ALEN);
+		memcpy(next_hop, mpath->next_hop->sta.addr, ETH_ALEN);
 	else
 		memset(next_hop, 0, ETH_ALEN);
 
@@ -952,20 +914,16 @@
 			       u8 *dst, u8 *next_hop, struct mpath_info *pinfo)
 
 {
-	struct ieee80211_local *local = wiphy_priv(wiphy);
 	struct ieee80211_sub_if_data *sdata;
 	struct mesh_path *mpath;
 
-	if (dev == local->mdev)
-		return -EOPNOTSUPP;
-
 	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 
-	if (sdata->vif.type != IEEE80211_IF_TYPE_MESH_POINT)
+	if (sdata->vif.type != NL80211_IFTYPE_MESH_POINT)
 		return -ENOTSUPP;
 
 	rcu_read_lock();
-	mpath = mesh_path_lookup(dst, dev);
+	mpath = mesh_path_lookup(dst, sdata);
 	if (!mpath) {
 		rcu_read_unlock();
 		return -ENOENT;
@@ -980,20 +938,16 @@
 				 int idx, u8 *dst, u8 *next_hop,
 				 struct mpath_info *pinfo)
 {
-	struct ieee80211_local *local = wiphy_priv(wiphy);
 	struct ieee80211_sub_if_data *sdata;
 	struct mesh_path *mpath;
 
-	if (dev == local->mdev)
-		return -EOPNOTSUPP;
-
 	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 
-	if (sdata->vif.type != IEEE80211_IF_TYPE_MESH_POINT)
+	if (sdata->vif.type != NL80211_IFTYPE_MESH_POINT)
 		return -ENOTSUPP;
 
 	rcu_read_lock();
-	mpath = mesh_path_lookup_by_idx(idx, dev);
+	mpath = mesh_path_lookup_by_idx(idx, sdata);
 	if (!mpath) {
 		rcu_read_unlock();
 		return -ENOENT;
@@ -1005,6 +959,38 @@
 }
 #endif
 
+static int ieee80211_change_bss(struct wiphy *wiphy,
+				struct net_device *dev,
+				struct bss_parameters *params)
+{
+	struct ieee80211_sub_if_data *sdata;
+	u32 changed = 0;
+
+	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+	if (sdata->vif.type != NL80211_IFTYPE_AP)
+		return -EINVAL;
+
+	if (params->use_cts_prot >= 0) {
+		sdata->bss_conf.use_cts_prot = params->use_cts_prot;
+		changed |= BSS_CHANGED_ERP_CTS_PROT;
+	}
+	if (params->use_short_preamble >= 0) {
+		sdata->bss_conf.use_short_preamble =
+			params->use_short_preamble;
+		changed |= BSS_CHANGED_ERP_PREAMBLE;
+	}
+	if (params->use_short_slot_time >= 0) {
+		sdata->bss_conf.use_short_slot =
+			params->use_short_slot_time;
+		changed |= BSS_CHANGED_ERP_SLOT;
+	}
+
+	ieee80211_bss_info_change_notify(sdata, changed);
+
+	return 0;
+}
+
 struct cfg80211_ops mac80211_config_ops = {
 	.add_virtual_intf = ieee80211_add_iface,
 	.del_virtual_intf = ieee80211_del_iface,
@@ -1028,4 +1014,5 @@
 	.get_mpath = ieee80211_get_mpath,
 	.dump_mpath = ieee80211_dump_mpath,
 #endif
+	.change_bss = ieee80211_change_bss,
 };
diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c
index ee509f1..24ce544 100644
--- a/net/mac80211/debugfs.c
+++ b/net/mac80211/debugfs.c
@@ -51,8 +51,6 @@
 		      local->hw.conf.antenna_sel_tx);
 DEBUGFS_READONLY_FILE(antenna_sel_rx, 20, "%d",
 		      local->hw.conf.antenna_sel_rx);
-DEBUGFS_READONLY_FILE(bridge_packets, 20, "%d",
-		      local->bridge_packets);
 DEBUGFS_READONLY_FILE(rts_threshold, 20, "%d",
 		      local->rts_threshold);
 DEBUGFS_READONLY_FILE(fragmentation_threshold, 20, "%d",
@@ -206,7 +204,6 @@
 	DEBUGFS_ADD(frequency);
 	DEBUGFS_ADD(antenna_sel_tx);
 	DEBUGFS_ADD(antenna_sel_rx);
-	DEBUGFS_ADD(bridge_packets);
 	DEBUGFS_ADD(rts_threshold);
 	DEBUGFS_ADD(fragmentation_threshold);
 	DEBUGFS_ADD(short_retry_limit);
@@ -263,7 +260,6 @@
 	DEBUGFS_DEL(frequency);
 	DEBUGFS_DEL(antenna_sel_tx);
 	DEBUGFS_DEL(antenna_sel_rx);
-	DEBUGFS_DEL(bridge_packets);
 	DEBUGFS_DEL(rts_threshold);
 	DEBUGFS_DEL(fragmentation_threshold);
 	DEBUGFS_DEL(short_retry_limit);
diff --git a/net/mac80211/debugfs_key.c b/net/mac80211/debugfs_key.c
index cf82ace..a3294d1 100644
--- a/net/mac80211/debugfs_key.c
+++ b/net/mac80211/debugfs_key.c
@@ -206,7 +206,8 @@
 	rcu_read_lock();
 	sta = rcu_dereference(key->sta);
 	if (sta)
-		sprintf(buf, "../../stations/%s", print_mac(mac, sta->addr));
+		sprintf(buf, "../../stations/%s",
+			print_mac(mac, sta->sta.addr));
 	rcu_read_unlock();
 
 	/* using sta as a boolean is fine outside RCU lock */
diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c
index 8165df5..2a45156 100644
--- a/net/mac80211/debugfs_netdev.c
+++ b/net/mac80211/debugfs_netdev.c
@@ -173,7 +173,6 @@
 IEEE80211_IF_FILE(auth_algs, u.sta.auth_algs, HEX);
 IEEE80211_IF_FILE(auth_alg, u.sta.auth_alg, DEC);
 IEEE80211_IF_FILE(auth_transaction, u.sta.auth_transaction, DEC);
-IEEE80211_IF_FILE(num_beacons_sta, u.sta.num_beacons, DEC);
 
 static ssize_t ieee80211_if_fmt_flags(
 	const struct ieee80211_sub_if_data *sdata, char *buf, int buflen)
@@ -192,7 +191,6 @@
 /* AP attributes */
 IEEE80211_IF_FILE(num_sta_ps, u.ap.num_sta_ps, ATOMIC);
 IEEE80211_IF_FILE(dtim_count, u.ap.dtim_count, DEC);
-IEEE80211_IF_FILE(num_beacons, u.ap.num_beacons, DEC);
 
 static ssize_t ieee80211_if_fmt_num_buffered_multicast(
 	const struct ieee80211_sub_if_data *sdata, char *buf, int buflen)
@@ -207,37 +205,37 @@
 
 #ifdef CONFIG_MAC80211_MESH
 /* Mesh stats attributes */
-IEEE80211_IF_FILE(fwded_frames, u.sta.mshstats.fwded_frames, DEC);
-IEEE80211_IF_FILE(dropped_frames_ttl, u.sta.mshstats.dropped_frames_ttl, DEC);
+IEEE80211_IF_FILE(fwded_frames, u.mesh.mshstats.fwded_frames, DEC);
+IEEE80211_IF_FILE(dropped_frames_ttl, u.mesh.mshstats.dropped_frames_ttl, DEC);
 IEEE80211_IF_FILE(dropped_frames_no_route,
-		u.sta.mshstats.dropped_frames_no_route, DEC);
-IEEE80211_IF_FILE(estab_plinks, u.sta.mshstats.estab_plinks, ATOMIC);
+		u.mesh.mshstats.dropped_frames_no_route, DEC);
+IEEE80211_IF_FILE(estab_plinks, u.mesh.mshstats.estab_plinks, ATOMIC);
 
 /* Mesh parameters */
 IEEE80211_IF_WFILE(dot11MeshMaxRetries,
-		u.sta.mshcfg.dot11MeshMaxRetries, DEC, u8);
+		u.mesh.mshcfg.dot11MeshMaxRetries, DEC, u8);
 IEEE80211_IF_WFILE(dot11MeshRetryTimeout,
-		u.sta.mshcfg.dot11MeshRetryTimeout, DEC, u16);
+		u.mesh.mshcfg.dot11MeshRetryTimeout, DEC, u16);
 IEEE80211_IF_WFILE(dot11MeshConfirmTimeout,
-		u.sta.mshcfg.dot11MeshConfirmTimeout, DEC, u16);
+		u.mesh.mshcfg.dot11MeshConfirmTimeout, DEC, u16);
 IEEE80211_IF_WFILE(dot11MeshHoldingTimeout,
-		u.sta.mshcfg.dot11MeshHoldingTimeout, DEC, u16);
-IEEE80211_IF_WFILE(dot11MeshTTL, u.sta.mshcfg.dot11MeshTTL, DEC, u8);
-IEEE80211_IF_WFILE(auto_open_plinks, u.sta.mshcfg.auto_open_plinks, DEC, u8);
+		u.mesh.mshcfg.dot11MeshHoldingTimeout, DEC, u16);
+IEEE80211_IF_WFILE(dot11MeshTTL, u.mesh.mshcfg.dot11MeshTTL, DEC, u8);
+IEEE80211_IF_WFILE(auto_open_plinks, u.mesh.mshcfg.auto_open_plinks, DEC, u8);
 IEEE80211_IF_WFILE(dot11MeshMaxPeerLinks,
-		u.sta.mshcfg.dot11MeshMaxPeerLinks, DEC, u16);
+		u.mesh.mshcfg.dot11MeshMaxPeerLinks, DEC, u16);
 IEEE80211_IF_WFILE(dot11MeshHWMPactivePathTimeout,
-		u.sta.mshcfg.dot11MeshHWMPactivePathTimeout, DEC, u32);
+		u.mesh.mshcfg.dot11MeshHWMPactivePathTimeout, DEC, u32);
 IEEE80211_IF_WFILE(dot11MeshHWMPpreqMinInterval,
-		u.sta.mshcfg.dot11MeshHWMPpreqMinInterval, DEC, u16);
+		u.mesh.mshcfg.dot11MeshHWMPpreqMinInterval, DEC, u16);
 IEEE80211_IF_WFILE(dot11MeshHWMPnetDiameterTraversalTime,
-		u.sta.mshcfg.dot11MeshHWMPnetDiameterTraversalTime, DEC, u16);
+		u.mesh.mshcfg.dot11MeshHWMPnetDiameterTraversalTime, DEC, u16);
 IEEE80211_IF_WFILE(dot11MeshHWMPmaxPREQretries,
-		u.sta.mshcfg.dot11MeshHWMPmaxPREQretries, DEC, u8);
+		u.mesh.mshcfg.dot11MeshHWMPmaxPREQretries, DEC, u8);
 IEEE80211_IF_WFILE(path_refresh_time,
-		u.sta.mshcfg.path_refresh_time, DEC, u32);
+		u.mesh.mshcfg.path_refresh_time, DEC, u32);
 IEEE80211_IF_WFILE(min_discovery_timeout,
-		u.sta.mshcfg.min_discovery_timeout, DEC, u16);
+		u.mesh.mshcfg.min_discovery_timeout, DEC, u16);
 #endif
 
 
@@ -265,7 +263,6 @@
 	DEBUGFS_ADD(auth_alg, sta);
 	DEBUGFS_ADD(auth_transaction, sta);
 	DEBUGFS_ADD(flags, sta);
-	DEBUGFS_ADD(num_beacons_sta, sta);
 }
 
 static void add_ap_files(struct ieee80211_sub_if_data *sdata)
@@ -276,7 +273,6 @@
 
 	DEBUGFS_ADD(num_sta_ps, ap);
 	DEBUGFS_ADD(dtim_count, ap);
-	DEBUGFS_ADD(num_beacons, ap);
 	DEBUGFS_ADD(num_buffered_multicast, ap);
 }
 
@@ -345,26 +341,26 @@
 		return;
 
 	switch (sdata->vif.type) {
-	case IEEE80211_IF_TYPE_MESH_POINT:
+	case NL80211_IFTYPE_MESH_POINT:
 #ifdef CONFIG_MAC80211_MESH
 		add_mesh_stats(sdata);
 		add_mesh_config(sdata);
 #endif
-		/* fall through */
-	case IEEE80211_IF_TYPE_STA:
-	case IEEE80211_IF_TYPE_IBSS:
+		break;
+	case NL80211_IFTYPE_STATION:
+	case NL80211_IFTYPE_ADHOC:
 		add_sta_files(sdata);
 		break;
-	case IEEE80211_IF_TYPE_AP:
+	case NL80211_IFTYPE_AP:
 		add_ap_files(sdata);
 		break;
-	case IEEE80211_IF_TYPE_WDS:
+	case NL80211_IFTYPE_WDS:
 		add_wds_files(sdata);
 		break;
-	case IEEE80211_IF_TYPE_MNTR:
+	case NL80211_IFTYPE_MONITOR:
 		add_monitor_files(sdata);
 		break;
-	case IEEE80211_IF_TYPE_VLAN:
+	case NL80211_IFTYPE_AP_VLAN:
 		add_vlan_files(sdata);
 		break;
 	default:
@@ -398,7 +394,6 @@
 	DEBUGFS_DEL(auth_alg, sta);
 	DEBUGFS_DEL(auth_transaction, sta);
 	DEBUGFS_DEL(flags, sta);
-	DEBUGFS_DEL(num_beacons_sta, sta);
 }
 
 static void del_ap_files(struct ieee80211_sub_if_data *sdata)
@@ -409,7 +404,6 @@
 
 	DEBUGFS_DEL(num_sta_ps, ap);
 	DEBUGFS_DEL(dtim_count, ap);
-	DEBUGFS_DEL(num_beacons, ap);
 	DEBUGFS_DEL(num_buffered_multicast, ap);
 }
 
@@ -482,26 +476,26 @@
 		return;
 
 	switch (sdata->vif.type) {
-	case IEEE80211_IF_TYPE_MESH_POINT:
+	case NL80211_IFTYPE_MESH_POINT:
 #ifdef CONFIG_MAC80211_MESH
 		del_mesh_stats(sdata);
 		del_mesh_config(sdata);
 #endif
-		/* fall through */
-	case IEEE80211_IF_TYPE_STA:
-	case IEEE80211_IF_TYPE_IBSS:
+		break;
+	case NL80211_IFTYPE_STATION:
+	case NL80211_IFTYPE_ADHOC:
 		del_sta_files(sdata);
 		break;
-	case IEEE80211_IF_TYPE_AP:
+	case NL80211_IFTYPE_AP:
 		del_ap_files(sdata);
 		break;
-	case IEEE80211_IF_TYPE_WDS:
+	case NL80211_IFTYPE_WDS:
 		del_wds_files(sdata);
 		break;
-	case IEEE80211_IF_TYPE_MNTR:
+	case NL80211_IFTYPE_MONITOR:
 		del_monitor_files(sdata);
 		break;
-	case IEEE80211_IF_TYPE_VLAN:
+	case NL80211_IFTYPE_AP_VLAN:
 		del_vlan_files(sdata);
 		break;
 	default:
diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c
index 79a0627..b9902e4 100644
--- a/net/mac80211/debugfs_sta.c
+++ b/net/mac80211/debugfs_sta.c
@@ -50,7 +50,7 @@
 		STA_READ_##format(name, field)				\
 		STA_OPS(name)
 
-STA_FILE(aid, aid, D);
+STA_FILE(aid, sta.aid, D);
 STA_FILE(dev, sdata->dev->name, S);
 STA_FILE(rx_packets, rx_packets, LU);
 STA_FILE(tx_packets, tx_packets, LU);
@@ -173,10 +173,9 @@
 		const char __user *user_buf, size_t count, loff_t *ppos)
 {
 	struct sta_info *sta = file->private_data;
-	struct net_device *dev = sta->sdata->dev;
-	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct ieee80211_local *local = sta->sdata->local;
 	struct ieee80211_hw *hw = &local->hw;
-	u8 *da = sta->addr;
+	u8 *da = sta->sta.addr;
 	static int tid_static_tx[16] = {0, 0, 0, 0, 0, 0, 0, 0,
 					0, 0, 0, 0, 0, 0, 0, 0};
 	static int tid_static_rx[16] = {1, 1, 1, 1, 1, 1, 1, 1,
@@ -201,7 +200,7 @@
 		tid_num = tid_num - 100;
 		if (tid_static_rx[tid_num] == 1) {
 			strcpy(state, "off ");
-			ieee80211_sta_stop_rx_ba_session(dev, da, tid_num, 0,
+			ieee80211_sta_stop_rx_ba_session(sta->sdata, da, tid_num, 0,
 					WLAN_REASON_QSTA_REQUIRE_SETUP);
 			sta->ampdu_mlme.tid_state_rx[tid_num] |=
 					HT_AGG_STATE_DEBUGFS_CTL;
@@ -253,7 +252,7 @@
 	if (!stations_dir)
 		return;
 
-	mac = print_mac(mbuf, sta->addr);
+	mac = print_mac(mbuf, sta->sta.addr);
 
 	sta->debugfs.dir = debugfs_create_dir(mac, stations_dir);
 	if (!sta->debugfs.dir)
diff --git a/net/mac80211/event.c b/net/mac80211/event.c
index 2280f40..8de60de 100644
--- a/net/mac80211/event.c
+++ b/net/mac80211/event.c
@@ -8,7 +8,6 @@
  * mac80211 - events
  */
 
-#include <linux/netdevice.h>
 #include <net/iw_handler.h>
 #include "ieee80211_i.h"
 
@@ -17,7 +16,7 @@
  * (in the variable hdr) must be long enough to extract the TKIP
  * fields like TSC
  */
-void mac80211_ev_michael_mic_failure(struct net_device *dev, int keyidx,
+void mac80211_ev_michael_mic_failure(struct ieee80211_sub_if_data *sdata, int keyidx,
 				     struct ieee80211_hdr *hdr)
 {
 	union iwreq_data wrqu;
@@ -32,7 +31,7 @@
 			print_mac(mac, hdr->addr2));
 		memset(&wrqu, 0, sizeof(wrqu));
 		wrqu.data.length = strlen(buf);
-		wireless_send_event(dev, IWEVCUSTOM, &wrqu, buf);
+		wireless_send_event(sdata->dev, IWEVCUSTOM, &wrqu, buf);
 		kfree(buf);
 	}
 
diff --git a/net/mac80211/ht.c b/net/mac80211/ht.c
new file mode 100644
index 0000000..dc7d9a3
--- /dev/null
+++ b/net/mac80211/ht.c
@@ -0,0 +1,992 @@
+/*
+ * HT handling
+ *
+ * Copyright 2003, Jouni Malinen <jkmaline@cc.hut.fi>
+ * Copyright 2002-2005, Instant802 Networks, Inc.
+ * Copyright 2005-2006, Devicescape Software, Inc.
+ * Copyright 2006-2007	Jiri Benc <jbenc@suse.cz>
+ * Copyright 2007, Michael Wu <flamingice@sourmilk.net>
+ * Copyright 2007-2008, Intel Corporation
+ *
+ * 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/ieee80211.h>
+#include <net/wireless.h>
+#include <net/mac80211.h>
+#include "ieee80211_i.h"
+#include "sta_info.h"
+#include "wme.h"
+
+int ieee80211_ht_cap_ie_to_ht_info(struct ieee80211_ht_cap *ht_cap_ie,
+				   struct ieee80211_ht_info *ht_info)
+{
+
+	if (ht_info == NULL)
+		return -EINVAL;
+
+	memset(ht_info, 0, sizeof(*ht_info));
+
+	if (ht_cap_ie) {
+		u8 ampdu_info = ht_cap_ie->ampdu_params_info;
+
+		ht_info->ht_supported = 1;
+		ht_info->cap = le16_to_cpu(ht_cap_ie->cap_info);
+		ht_info->ampdu_factor =
+			ampdu_info & IEEE80211_HT_CAP_AMPDU_FACTOR;
+		ht_info->ampdu_density =
+			(ampdu_info & IEEE80211_HT_CAP_AMPDU_DENSITY) >> 2;
+		memcpy(ht_info->supp_mcs_set, ht_cap_ie->supp_mcs_set, 16);
+	} else
+		ht_info->ht_supported = 0;
+
+	return 0;
+}
+
+int ieee80211_ht_addt_info_ie_to_ht_bss_info(
+			struct ieee80211_ht_addt_info *ht_add_info_ie,
+			struct ieee80211_ht_bss_info *bss_info)
+{
+	if (bss_info == NULL)
+		return -EINVAL;
+
+	memset(bss_info, 0, sizeof(*bss_info));
+
+	if (ht_add_info_ie) {
+		u16 op_mode;
+		op_mode = le16_to_cpu(ht_add_info_ie->operation_mode);
+
+		bss_info->primary_channel = ht_add_info_ie->control_chan;
+		bss_info->bss_cap = ht_add_info_ie->ht_param;
+		bss_info->bss_op_mode = (u8)(op_mode & 0xff);
+	}
+
+	return 0;
+}
+
+static void ieee80211_send_addba_request(struct ieee80211_sub_if_data *sdata,
+					 const u8 *da, u16 tid,
+					 u8 dialog_token, u16 start_seq_num,
+					 u16 agg_size, u16 timeout)
+{
+	struct ieee80211_local *local = sdata->local;
+	struct ieee80211_if_sta *ifsta = &sdata->u.sta;
+	struct sk_buff *skb;
+	struct ieee80211_mgmt *mgmt;
+	u16 capab;
+
+	skb = dev_alloc_skb(sizeof(*mgmt) + local->hw.extra_tx_headroom);
+
+	if (!skb) {
+		printk(KERN_ERR "%s: failed to allocate buffer "
+				"for addba request frame\n", sdata->dev->name);
+		return;
+	}
+	skb_reserve(skb, local->hw.extra_tx_headroom);
+	mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24);
+	memset(mgmt, 0, 24);
+	memcpy(mgmt->da, da, ETH_ALEN);
+	memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
+	if (sdata->vif.type == NL80211_IFTYPE_AP)
+		memcpy(mgmt->bssid, sdata->dev->dev_addr, ETH_ALEN);
+	else
+		memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN);
+
+	mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
+					  IEEE80211_STYPE_ACTION);
+
+	skb_put(skb, 1 + sizeof(mgmt->u.action.u.addba_req));
+
+	mgmt->u.action.category = WLAN_CATEGORY_BACK;
+	mgmt->u.action.u.addba_req.action_code = WLAN_ACTION_ADDBA_REQ;
+
+	mgmt->u.action.u.addba_req.dialog_token = dialog_token;
+	capab = (u16)(1 << 1);		/* bit 1 aggregation policy */
+	capab |= (u16)(tid << 2); 	/* bit 5:2 TID number */
+	capab |= (u16)(agg_size << 6);	/* bit 15:6 max size of aggergation */
+
+	mgmt->u.action.u.addba_req.capab = cpu_to_le16(capab);
+
+	mgmt->u.action.u.addba_req.timeout = cpu_to_le16(timeout);
+	mgmt->u.action.u.addba_req.start_seq_num =
+					cpu_to_le16(start_seq_num << 4);
+
+	ieee80211_tx_skb(sdata, skb, 0);
+}
+
+static void ieee80211_send_addba_resp(struct ieee80211_sub_if_data *sdata, u8 *da, u16 tid,
+				      u8 dialog_token, u16 status, u16 policy,
+				      u16 buf_size, u16 timeout)
+{
+	struct ieee80211_if_sta *ifsta = &sdata->u.sta;
+	struct ieee80211_local *local = sdata->local;
+	struct sk_buff *skb;
+	struct ieee80211_mgmt *mgmt;
+	u16 capab;
+
+	skb = dev_alloc_skb(sizeof(*mgmt) + local->hw.extra_tx_headroom);
+
+	if (!skb) {
+		printk(KERN_DEBUG "%s: failed to allocate buffer "
+		       "for addba resp frame\n", sdata->dev->name);
+		return;
+	}
+
+	skb_reserve(skb, local->hw.extra_tx_headroom);
+	mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24);
+	memset(mgmt, 0, 24);
+	memcpy(mgmt->da, da, ETH_ALEN);
+	memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
+	if (sdata->vif.type == NL80211_IFTYPE_AP)
+		memcpy(mgmt->bssid, sdata->dev->dev_addr, ETH_ALEN);
+	else
+		memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN);
+	mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
+					  IEEE80211_STYPE_ACTION);
+
+	skb_put(skb, 1 + sizeof(mgmt->u.action.u.addba_resp));
+	mgmt->u.action.category = WLAN_CATEGORY_BACK;
+	mgmt->u.action.u.addba_resp.action_code = WLAN_ACTION_ADDBA_RESP;
+	mgmt->u.action.u.addba_resp.dialog_token = dialog_token;
+
+	capab = (u16)(policy << 1);	/* bit 1 aggregation policy */
+	capab |= (u16)(tid << 2); 	/* bit 5:2 TID number */
+	capab |= (u16)(buf_size << 6);	/* bit 15:6 max size of aggregation */
+
+	mgmt->u.action.u.addba_resp.capab = cpu_to_le16(capab);
+	mgmt->u.action.u.addba_resp.timeout = cpu_to_le16(timeout);
+	mgmt->u.action.u.addba_resp.status = cpu_to_le16(status);
+
+	ieee80211_tx_skb(sdata, skb, 0);
+}
+
+static void ieee80211_send_delba(struct ieee80211_sub_if_data *sdata,
+				 const u8 *da, u16 tid,
+				 u16 initiator, u16 reason_code)
+{
+	struct ieee80211_local *local = sdata->local;
+	struct ieee80211_if_sta *ifsta = &sdata->u.sta;
+	struct sk_buff *skb;
+	struct ieee80211_mgmt *mgmt;
+	u16 params;
+
+	skb = dev_alloc_skb(sizeof(*mgmt) + local->hw.extra_tx_headroom);
+
+	if (!skb) {
+		printk(KERN_ERR "%s: failed to allocate buffer "
+					"for delba frame\n", sdata->dev->name);
+		return;
+	}
+
+	skb_reserve(skb, local->hw.extra_tx_headroom);
+	mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24);
+	memset(mgmt, 0, 24);
+	memcpy(mgmt->da, da, ETH_ALEN);
+	memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
+	if (sdata->vif.type == NL80211_IFTYPE_AP)
+		memcpy(mgmt->bssid, sdata->dev->dev_addr, ETH_ALEN);
+	else
+		memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN);
+	mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
+					  IEEE80211_STYPE_ACTION);
+
+	skb_put(skb, 1 + sizeof(mgmt->u.action.u.delba));
+
+	mgmt->u.action.category = WLAN_CATEGORY_BACK;
+	mgmt->u.action.u.delba.action_code = WLAN_ACTION_DELBA;
+	params = (u16)(initiator << 11); 	/* bit 11 initiator */
+	params |= (u16)(tid << 12); 		/* bit 15:12 TID number */
+
+	mgmt->u.action.u.delba.params = cpu_to_le16(params);
+	mgmt->u.action.u.delba.reason_code = cpu_to_le16(reason_code);
+
+	ieee80211_tx_skb(sdata, skb, 0);
+}
+
+void ieee80211_send_bar(struct ieee80211_sub_if_data *sdata, u8 *ra, u16 tid, u16 ssn)
+{
+	struct ieee80211_local *local = sdata->local;
+	struct sk_buff *skb;
+	struct ieee80211_bar *bar;
+	u16 bar_control = 0;
+
+	skb = dev_alloc_skb(sizeof(*bar) + local->hw.extra_tx_headroom);
+	if (!skb) {
+		printk(KERN_ERR "%s: failed to allocate buffer for "
+			"bar frame\n", sdata->dev->name);
+		return;
+	}
+	skb_reserve(skb, local->hw.extra_tx_headroom);
+	bar = (struct ieee80211_bar *)skb_put(skb, sizeof(*bar));
+	memset(bar, 0, sizeof(*bar));
+	bar->frame_control = cpu_to_le16(IEEE80211_FTYPE_CTL |
+					 IEEE80211_STYPE_BACK_REQ);
+	memcpy(bar->ra, ra, ETH_ALEN);
+	memcpy(bar->ta, sdata->dev->dev_addr, ETH_ALEN);
+	bar_control |= (u16)IEEE80211_BAR_CTRL_ACK_POLICY_NORMAL;
+	bar_control |= (u16)IEEE80211_BAR_CTRL_CBMTID_COMPRESSED_BA;
+	bar_control |= (u16)(tid << 12);
+	bar->control = cpu_to_le16(bar_control);
+	bar->start_seq_num = cpu_to_le16(ssn);
+
+	ieee80211_tx_skb(sdata, skb, 0);
+}
+
+void ieee80211_sta_stop_rx_ba_session(struct ieee80211_sub_if_data *sdata, u8 *ra, u16 tid,
+					u16 initiator, u16 reason)
+{
+	struct ieee80211_local *local = sdata->local;
+	struct ieee80211_hw *hw = &local->hw;
+	struct sta_info *sta;
+	int ret, i;
+	DECLARE_MAC_BUF(mac);
+
+	rcu_read_lock();
+
+	sta = sta_info_get(local, ra);
+	if (!sta) {
+		rcu_read_unlock();
+		return;
+	}
+
+	/* check if TID is in operational state */
+	spin_lock_bh(&sta->lock);
+	if (sta->ampdu_mlme.tid_state_rx[tid]
+				!= HT_AGG_STATE_OPERATIONAL) {
+		spin_unlock_bh(&sta->lock);
+		rcu_read_unlock();
+		return;
+	}
+	sta->ampdu_mlme.tid_state_rx[tid] =
+		HT_AGG_STATE_REQ_STOP_BA_MSK |
+		(initiator << HT_AGG_STATE_INITIATOR_SHIFT);
+	spin_unlock_bh(&sta->lock);
+
+	/* stop HW Rx aggregation. ampdu_action existence
+	 * already verified in session init so we add the BUG_ON */
+	BUG_ON(!local->ops->ampdu_action);
+
+#ifdef CONFIG_MAC80211_HT_DEBUG
+	printk(KERN_DEBUG "Rx BA session stop requested for %s tid %u\n",
+				print_mac(mac, ra), tid);
+#endif /* CONFIG_MAC80211_HT_DEBUG */
+
+	ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_RX_STOP,
+				       &sta->sta, tid, NULL);
+	if (ret)
+		printk(KERN_DEBUG "HW problem - can not stop rx "
+				"aggregation for tid %d\n", tid);
+
+	/* shutdown timer has not expired */
+	if (initiator != WLAN_BACK_TIMER)
+		del_timer_sync(&sta->ampdu_mlme.tid_rx[tid]->session_timer);
+
+	/* check if this is a self generated aggregation halt */
+	if (initiator == WLAN_BACK_RECIPIENT || initiator == WLAN_BACK_TIMER)
+		ieee80211_send_delba(sdata, ra, tid, 0, reason);
+
+	/* free the reordering buffer */
+	for (i = 0; i < sta->ampdu_mlme.tid_rx[tid]->buf_size; i++) {
+		if (sta->ampdu_mlme.tid_rx[tid]->reorder_buf[i]) {
+			/* release the reordered frames */
+			dev_kfree_skb(sta->ampdu_mlme.tid_rx[tid]->reorder_buf[i]);
+			sta->ampdu_mlme.tid_rx[tid]->stored_mpdu_num--;
+			sta->ampdu_mlme.tid_rx[tid]->reorder_buf[i] = NULL;
+		}
+	}
+	/* free resources */
+	kfree(sta->ampdu_mlme.tid_rx[tid]->reorder_buf);
+	kfree(sta->ampdu_mlme.tid_rx[tid]);
+	sta->ampdu_mlme.tid_rx[tid] = NULL;
+	sta->ampdu_mlme.tid_state_rx[tid] = HT_AGG_STATE_IDLE;
+
+	rcu_read_unlock();
+}
+
+
+/*
+ * After sending add Block Ack request we activated a timer until
+ * add Block Ack response will arrive from the recipient.
+ * If this timer expires sta_addba_resp_timer_expired will be executed.
+ */
+static void sta_addba_resp_timer_expired(unsigned long data)
+{
+	/* not an elegant detour, but there is no choice as the timer passes
+	 * only one argument, and both sta_info and TID are needed, so init
+	 * flow in sta_info_create gives the TID as data, while the timer_to_id
+	 * array gives the sta through container_of */
+	u16 tid = *(u8 *)data;
+	struct sta_info *temp_sta = container_of((void *)data,
+		struct sta_info, timer_to_tid[tid]);
+
+	struct ieee80211_local *local = temp_sta->local;
+	struct ieee80211_hw *hw = &local->hw;
+	struct sta_info *sta;
+	u8 *state;
+
+	rcu_read_lock();
+
+	sta = sta_info_get(local, temp_sta->sta.addr);
+	if (!sta) {
+		rcu_read_unlock();
+		return;
+	}
+
+	state = &sta->ampdu_mlme.tid_state_tx[tid];
+	/* check if the TID waits for addBA response */
+	spin_lock_bh(&sta->lock);
+	if (!(*state & HT_ADDBA_REQUESTED_MSK)) {
+		spin_unlock_bh(&sta->lock);
+		*state = HT_AGG_STATE_IDLE;
+#ifdef CONFIG_MAC80211_HT_DEBUG
+		printk(KERN_DEBUG "timer expired on tid %d but we are not "
+				"expecting addBA response there", tid);
+#endif
+		goto timer_expired_exit;
+	}
+
+#ifdef CONFIG_MAC80211_HT_DEBUG
+	printk(KERN_DEBUG "addBA response timer expired on tid %d\n", tid);
+#endif
+
+	/* go through the state check in stop_BA_session */
+	*state = HT_AGG_STATE_OPERATIONAL;
+	spin_unlock_bh(&sta->lock);
+	ieee80211_stop_tx_ba_session(hw, temp_sta->sta.addr, tid,
+				     WLAN_BACK_INITIATOR);
+
+timer_expired_exit:
+	rcu_read_unlock();
+}
+
+void ieee80211_sta_tear_down_BA_sessions(struct ieee80211_sub_if_data *sdata, u8 *addr)
+{
+	struct ieee80211_local *local = sdata->local;
+	int i;
+
+	for (i = 0; i <  STA_TID_NUM; i++) {
+		ieee80211_stop_tx_ba_session(&local->hw, addr, i,
+					     WLAN_BACK_INITIATOR);
+		ieee80211_sta_stop_rx_ba_session(sdata, addr, i,
+						 WLAN_BACK_RECIPIENT,
+						 WLAN_REASON_QSTA_LEAVE_QBSS);
+	}
+}
+
+int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid)
+{
+	struct ieee80211_local *local = hw_to_local(hw);
+	struct sta_info *sta;
+	struct ieee80211_sub_if_data *sdata;
+	u16 start_seq_num;
+	u8 *state;
+	int ret;
+	DECLARE_MAC_BUF(mac);
+
+	if (tid >= STA_TID_NUM)
+		return -EINVAL;
+
+#ifdef CONFIG_MAC80211_HT_DEBUG
+	printk(KERN_DEBUG "Open BA session requested for %s tid %u\n",
+				print_mac(mac, ra), tid);
+#endif /* CONFIG_MAC80211_HT_DEBUG */
+
+	rcu_read_lock();
+
+	sta = sta_info_get(local, ra);
+	if (!sta) {
+#ifdef CONFIG_MAC80211_HT_DEBUG
+		printk(KERN_DEBUG "Could not find the station\n");
+#endif
+		ret = -ENOENT;
+		goto exit;
+	}
+
+	spin_lock_bh(&sta->lock);
+
+	/* we have tried too many times, receiver does not want A-MPDU */
+	if (sta->ampdu_mlme.addba_req_num[tid] > HT_AGG_MAX_RETRIES) {
+		ret = -EBUSY;
+		goto err_unlock_sta;
+	}
+
+	state = &sta->ampdu_mlme.tid_state_tx[tid];
+	/* check if the TID is not in aggregation flow already */
+	if (*state != HT_AGG_STATE_IDLE) {
+#ifdef CONFIG_MAC80211_HT_DEBUG
+		printk(KERN_DEBUG "BA request denied - session is not "
+				 "idle on tid %u\n", tid);
+#endif /* CONFIG_MAC80211_HT_DEBUG */
+		ret = -EAGAIN;
+		goto err_unlock_sta;
+	}
+
+	/* prepare A-MPDU MLME for Tx aggregation */
+	sta->ampdu_mlme.tid_tx[tid] =
+			kmalloc(sizeof(struct tid_ampdu_tx), GFP_ATOMIC);
+	if (!sta->ampdu_mlme.tid_tx[tid]) {
+#ifdef CONFIG_MAC80211_HT_DEBUG
+		if (net_ratelimit())
+			printk(KERN_ERR "allocate tx mlme to tid %d failed\n",
+					tid);
+#endif
+		ret = -ENOMEM;
+		goto err_unlock_sta;
+	}
+	/* Tx timer */
+	sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer.function =
+			sta_addba_resp_timer_expired;
+	sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer.data =
+			(unsigned long)&sta->timer_to_tid[tid];
+	init_timer(&sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer);
+
+	/* create a new queue for this aggregation */
+	ret = ieee80211_ht_agg_queue_add(local, sta, tid);
+
+	/* case no queue is available to aggregation
+	 * don't switch to aggregation */
+	if (ret) {
+#ifdef CONFIG_MAC80211_HT_DEBUG
+		printk(KERN_DEBUG "BA request denied - queue unavailable for"
+					" tid %d\n", tid);
+#endif /* CONFIG_MAC80211_HT_DEBUG */
+		goto err_unlock_queue;
+	}
+	sdata = sta->sdata;
+
+	/* Ok, the Addba frame hasn't been sent yet, but if the driver calls the
+	 * call back right away, it must see that the flow has begun */
+	*state |= HT_ADDBA_REQUESTED_MSK;
+
+	/* This is slightly racy because the queue isn't stopped */
+	start_seq_num = sta->tid_seq[tid];
+
+	if (local->ops->ampdu_action)
+		ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_TX_START,
+					       &sta->sta, tid, &start_seq_num);
+
+	if (ret) {
+		/* No need to requeue the packets in the agg queue, since we
+		 * held the tx lock: no packet could be enqueued to the newly
+		 * allocated queue */
+		ieee80211_ht_agg_queue_remove(local, sta, tid, 0);
+#ifdef CONFIG_MAC80211_HT_DEBUG
+		printk(KERN_DEBUG "BA request denied - HW unavailable for"
+					" tid %d\n", tid);
+#endif /* CONFIG_MAC80211_HT_DEBUG */
+		*state = HT_AGG_STATE_IDLE;
+		goto err_unlock_queue;
+	}
+
+	/* Will put all the packets in the new SW queue */
+	ieee80211_requeue(local, ieee802_1d_to_ac[tid]);
+	spin_unlock_bh(&sta->lock);
+
+	/* send an addBA request */
+	sta->ampdu_mlme.dialog_token_allocator++;
+	sta->ampdu_mlme.tid_tx[tid]->dialog_token =
+			sta->ampdu_mlme.dialog_token_allocator;
+	sta->ampdu_mlme.tid_tx[tid]->ssn = start_seq_num;
+
+
+	ieee80211_send_addba_request(sta->sdata, ra, tid,
+			 sta->ampdu_mlme.tid_tx[tid]->dialog_token,
+			 sta->ampdu_mlme.tid_tx[tid]->ssn,
+			 0x40, 5000);
+	/* activate the timer for the recipient's addBA response */
+	sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer.expires =
+				jiffies + ADDBA_RESP_INTERVAL;
+	add_timer(&sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer);
+#ifdef CONFIG_MAC80211_HT_DEBUG
+	printk(KERN_DEBUG "activated addBA response timer on tid %d\n", tid);
+#endif
+	goto exit;
+
+err_unlock_queue:
+	kfree(sta->ampdu_mlme.tid_tx[tid]);
+	sta->ampdu_mlme.tid_tx[tid] = NULL;
+	ret = -EBUSY;
+err_unlock_sta:
+	spin_unlock_bh(&sta->lock);
+exit:
+	rcu_read_unlock();
+	return ret;
+}
+EXPORT_SYMBOL(ieee80211_start_tx_ba_session);
+
+int ieee80211_stop_tx_ba_session(struct ieee80211_hw *hw,
+				 u8 *ra, u16 tid,
+				 enum ieee80211_back_parties initiator)
+{
+	struct ieee80211_local *local = hw_to_local(hw);
+	struct sta_info *sta;
+	u8 *state;
+	int ret = 0;
+	DECLARE_MAC_BUF(mac);
+
+	if (tid >= STA_TID_NUM)
+		return -EINVAL;
+
+	rcu_read_lock();
+	sta = sta_info_get(local, ra);
+	if (!sta) {
+		rcu_read_unlock();
+		return -ENOENT;
+	}
+
+	/* check if the TID is in aggregation */
+	state = &sta->ampdu_mlme.tid_state_tx[tid];
+	spin_lock_bh(&sta->lock);
+
+	if (*state != HT_AGG_STATE_OPERATIONAL) {
+		ret = -ENOENT;
+		goto stop_BA_exit;
+	}
+
+#ifdef CONFIG_MAC80211_HT_DEBUG
+	printk(KERN_DEBUG "Tx BA session stop requested for %s tid %u\n",
+				print_mac(mac, ra), tid);
+#endif /* CONFIG_MAC80211_HT_DEBUG */
+
+	ieee80211_stop_queue(hw, sta->tid_to_tx_q[tid]);
+
+	*state = HT_AGG_STATE_REQ_STOP_BA_MSK |
+		(initiator << HT_AGG_STATE_INITIATOR_SHIFT);
+
+	if (local->ops->ampdu_action)
+		ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_TX_STOP,
+					       &sta->sta, tid, NULL);
+
+	/* case HW denied going back to legacy */
+	if (ret) {
+		WARN_ON(ret != -EBUSY);
+		*state = HT_AGG_STATE_OPERATIONAL;
+		ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]);
+		goto stop_BA_exit;
+	}
+
+stop_BA_exit:
+	spin_unlock_bh(&sta->lock);
+	rcu_read_unlock();
+	return ret;
+}
+EXPORT_SYMBOL(ieee80211_stop_tx_ba_session);
+
+void ieee80211_start_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u16 tid)
+{
+	struct ieee80211_local *local = hw_to_local(hw);
+	struct sta_info *sta;
+	u8 *state;
+	DECLARE_MAC_BUF(mac);
+
+	if (tid >= STA_TID_NUM) {
+#ifdef CONFIG_MAC80211_HT_DEBUG
+		printk(KERN_DEBUG "Bad TID value: tid = %d (>= %d)\n",
+				tid, STA_TID_NUM);
+#endif
+		return;
+	}
+
+	rcu_read_lock();
+	sta = sta_info_get(local, ra);
+	if (!sta) {
+		rcu_read_unlock();
+#ifdef CONFIG_MAC80211_HT_DEBUG
+		printk(KERN_DEBUG "Could not find station: %s\n",
+				print_mac(mac, ra));
+#endif
+		return;
+	}
+
+	state = &sta->ampdu_mlme.tid_state_tx[tid];
+	spin_lock_bh(&sta->lock);
+
+	if (!(*state & HT_ADDBA_REQUESTED_MSK)) {
+#ifdef CONFIG_MAC80211_HT_DEBUG
+		printk(KERN_DEBUG "addBA was not requested yet, state is %d\n",
+				*state);
+#endif
+		spin_unlock_bh(&sta->lock);
+		rcu_read_unlock();
+		return;
+	}
+
+	WARN_ON_ONCE(*state & HT_ADDBA_DRV_READY_MSK);
+
+	*state |= HT_ADDBA_DRV_READY_MSK;
+
+	if (*state == HT_AGG_STATE_OPERATIONAL) {
+#ifdef CONFIG_MAC80211_HT_DEBUG
+		printk(KERN_DEBUG "Aggregation is on for tid %d \n", tid);
+#endif
+		ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]);
+	}
+	spin_unlock_bh(&sta->lock);
+	rcu_read_unlock();
+}
+EXPORT_SYMBOL(ieee80211_start_tx_ba_cb);
+
+void ieee80211_stop_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u8 tid)
+{
+	struct ieee80211_local *local = hw_to_local(hw);
+	struct sta_info *sta;
+	u8 *state;
+	int agg_queue;
+	DECLARE_MAC_BUF(mac);
+
+	if (tid >= STA_TID_NUM) {
+#ifdef CONFIG_MAC80211_HT_DEBUG
+		printk(KERN_DEBUG "Bad TID value: tid = %d (>= %d)\n",
+				tid, STA_TID_NUM);
+#endif
+		return;
+	}
+
+#ifdef CONFIG_MAC80211_HT_DEBUG
+	printk(KERN_DEBUG "Stopping Tx BA session for %s tid %d\n",
+				print_mac(mac, ra), tid);
+#endif /* CONFIG_MAC80211_HT_DEBUG */
+
+	rcu_read_lock();
+	sta = sta_info_get(local, ra);
+	if (!sta) {
+#ifdef CONFIG_MAC80211_HT_DEBUG
+		printk(KERN_DEBUG "Could not find station: %s\n",
+				print_mac(mac, ra));
+#endif
+		rcu_read_unlock();
+		return;
+	}
+	state = &sta->ampdu_mlme.tid_state_tx[tid];
+
+	/* NOTE: no need to use sta->lock in this state check, as
+	 * ieee80211_stop_tx_ba_session will let only one stop call to
+	 * pass through per sta/tid
+	 */
+	if ((*state & HT_AGG_STATE_REQ_STOP_BA_MSK) == 0) {
+#ifdef CONFIG_MAC80211_HT_DEBUG
+		printk(KERN_DEBUG "unexpected callback to A-MPDU stop\n");
+#endif
+		rcu_read_unlock();
+		return;
+	}
+
+	if (*state & HT_AGG_STATE_INITIATOR_MSK)
+		ieee80211_send_delba(sta->sdata, ra, tid,
+			WLAN_BACK_INITIATOR, WLAN_REASON_QSTA_NOT_USE);
+
+	agg_queue = sta->tid_to_tx_q[tid];
+
+	ieee80211_ht_agg_queue_remove(local, sta, tid, 1);
+
+	/* We just requeued the all the frames that were in the
+	 * removed queue, and since we might miss a softirq we do
+	 * netif_schedule_queue.  ieee80211_wake_queue is not used
+	 * here as this queue is not necessarily stopped
+	 */
+	netif_schedule_queue(netdev_get_tx_queue(local->mdev, agg_queue));
+	spin_lock_bh(&sta->lock);
+	*state = HT_AGG_STATE_IDLE;
+	sta->ampdu_mlme.addba_req_num[tid] = 0;
+	kfree(sta->ampdu_mlme.tid_tx[tid]);
+	sta->ampdu_mlme.tid_tx[tid] = NULL;
+	spin_unlock_bh(&sta->lock);
+
+	rcu_read_unlock();
+}
+EXPORT_SYMBOL(ieee80211_stop_tx_ba_cb);
+
+void ieee80211_start_tx_ba_cb_irqsafe(struct ieee80211_hw *hw,
+				      const u8 *ra, u16 tid)
+{
+	struct ieee80211_local *local = hw_to_local(hw);
+	struct ieee80211_ra_tid *ra_tid;
+	struct sk_buff *skb = dev_alloc_skb(0);
+
+	if (unlikely(!skb)) {
+#ifdef CONFIG_MAC80211_HT_DEBUG
+		if (net_ratelimit())
+			printk(KERN_WARNING "%s: Not enough memory, "
+			       "dropping start BA session", skb->dev->name);
+#endif
+		return;
+	}
+	ra_tid = (struct ieee80211_ra_tid *) &skb->cb;
+	memcpy(&ra_tid->ra, ra, ETH_ALEN);
+	ra_tid->tid = tid;
+
+	skb->pkt_type = IEEE80211_ADDBA_MSG;
+	skb_queue_tail(&local->skb_queue, skb);
+	tasklet_schedule(&local->tasklet);
+}
+EXPORT_SYMBOL(ieee80211_start_tx_ba_cb_irqsafe);
+
+void ieee80211_stop_tx_ba_cb_irqsafe(struct ieee80211_hw *hw,
+				     const u8 *ra, u16 tid)
+{
+	struct ieee80211_local *local = hw_to_local(hw);
+	struct ieee80211_ra_tid *ra_tid;
+	struct sk_buff *skb = dev_alloc_skb(0);
+
+	if (unlikely(!skb)) {
+#ifdef CONFIG_MAC80211_HT_DEBUG
+		if (net_ratelimit())
+			printk(KERN_WARNING "%s: Not enough memory, "
+			       "dropping stop BA session", skb->dev->name);
+#endif
+		return;
+	}
+	ra_tid = (struct ieee80211_ra_tid *) &skb->cb;
+	memcpy(&ra_tid->ra, ra, ETH_ALEN);
+	ra_tid->tid = tid;
+
+	skb->pkt_type = IEEE80211_DELBA_MSG;
+	skb_queue_tail(&local->skb_queue, skb);
+	tasklet_schedule(&local->tasklet);
+}
+EXPORT_SYMBOL(ieee80211_stop_tx_ba_cb_irqsafe);
+
+/*
+ * After accepting the AddBA Request we activated a timer,
+ * resetting it after each frame that arrives from the originator.
+ * if this timer expires ieee80211_sta_stop_rx_ba_session will be executed.
+ */
+static void sta_rx_agg_session_timer_expired(unsigned long data)
+{
+	/* not an elegant detour, but there is no choice as the timer passes
+	 * only one argument, and various sta_info are needed here, so init
+	 * flow in sta_info_create gives the TID as data, while the timer_to_id
+	 * array gives the sta through container_of */
+	u8 *ptid = (u8 *)data;
+	u8 *timer_to_id = ptid - *ptid;
+	struct sta_info *sta = container_of(timer_to_id, struct sta_info,
+					 timer_to_tid[0]);
+
+#ifdef CONFIG_MAC80211_HT_DEBUG
+	printk(KERN_DEBUG "rx session timer expired on tid %d\n", (u16)*ptid);
+#endif
+	ieee80211_sta_stop_rx_ba_session(sta->sdata, sta->sta.addr,
+					 (u16)*ptid, WLAN_BACK_TIMER,
+					 WLAN_REASON_QSTA_TIMEOUT);
+}
+
+void ieee80211_process_addba_request(struct ieee80211_local *local,
+				     struct sta_info *sta,
+				     struct ieee80211_mgmt *mgmt,
+				     size_t len)
+{
+	struct ieee80211_hw *hw = &local->hw;
+	struct ieee80211_conf *conf = &hw->conf;
+	struct tid_ampdu_rx *tid_agg_rx;
+	u16 capab, tid, timeout, ba_policy, buf_size, start_seq_num, status;
+	u8 dialog_token;
+	int ret = -EOPNOTSUPP;
+	DECLARE_MAC_BUF(mac);
+
+	/* extract session parameters from addba request frame */
+	dialog_token = mgmt->u.action.u.addba_req.dialog_token;
+	timeout = le16_to_cpu(mgmt->u.action.u.addba_req.timeout);
+	start_seq_num =
+		le16_to_cpu(mgmt->u.action.u.addba_req.start_seq_num) >> 4;
+
+	capab = le16_to_cpu(mgmt->u.action.u.addba_req.capab);
+	ba_policy = (capab & IEEE80211_ADDBA_PARAM_POLICY_MASK) >> 1;
+	tid = (capab & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2;
+	buf_size = (capab & IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK) >> 6;
+
+	status = WLAN_STATUS_REQUEST_DECLINED;
+
+	/* sanity check for incoming parameters:
+	 * check if configuration can support the BA policy
+	 * and if buffer size does not exceeds max value */
+	if (((ba_policy != 1)
+		&& (!(conf->ht_conf.cap & IEEE80211_HT_CAP_DELAY_BA)))
+		|| (buf_size > IEEE80211_MAX_AMPDU_BUF)) {
+		status = WLAN_STATUS_INVALID_QOS_PARAM;
+#ifdef CONFIG_MAC80211_HT_DEBUG
+		if (net_ratelimit())
+			printk(KERN_DEBUG "AddBA Req with bad params from "
+				"%s on tid %u. policy %d, buffer size %d\n",
+				print_mac(mac, mgmt->sa), tid, ba_policy,
+				buf_size);
+#endif /* CONFIG_MAC80211_HT_DEBUG */
+		goto end_no_lock;
+	}
+	/* determine default buffer size */
+	if (buf_size == 0) {
+		struct ieee80211_supported_band *sband;
+
+		sband = local->hw.wiphy->bands[conf->channel->band];
+		buf_size = IEEE80211_MIN_AMPDU_BUF;
+		buf_size = buf_size << sband->ht_info.ampdu_factor;
+	}
+
+
+	/* examine state machine */
+	spin_lock_bh(&sta->lock);
+
+	if (sta->ampdu_mlme.tid_state_rx[tid] != HT_AGG_STATE_IDLE) {
+#ifdef CONFIG_MAC80211_HT_DEBUG
+		if (net_ratelimit())
+			printk(KERN_DEBUG "unexpected AddBA Req from "
+				"%s on tid %u\n",
+				print_mac(mac, mgmt->sa), tid);
+#endif /* CONFIG_MAC80211_HT_DEBUG */
+		goto end;
+	}
+
+	/* prepare A-MPDU MLME for Rx aggregation */
+	sta->ampdu_mlme.tid_rx[tid] =
+			kmalloc(sizeof(struct tid_ampdu_rx), GFP_ATOMIC);
+	if (!sta->ampdu_mlme.tid_rx[tid]) {
+#ifdef CONFIG_MAC80211_HT_DEBUG
+		if (net_ratelimit())
+			printk(KERN_ERR "allocate rx mlme to tid %d failed\n",
+					tid);
+#endif
+		goto end;
+	}
+	/* rx timer */
+	sta->ampdu_mlme.tid_rx[tid]->session_timer.function =
+				sta_rx_agg_session_timer_expired;
+	sta->ampdu_mlme.tid_rx[tid]->session_timer.data =
+				(unsigned long)&sta->timer_to_tid[tid];
+	init_timer(&sta->ampdu_mlme.tid_rx[tid]->session_timer);
+
+	tid_agg_rx = sta->ampdu_mlme.tid_rx[tid];
+
+	/* prepare reordering buffer */
+	tid_agg_rx->reorder_buf =
+		kmalloc(buf_size * sizeof(struct sk_buff *), GFP_ATOMIC);
+	if (!tid_agg_rx->reorder_buf) {
+#ifdef CONFIG_MAC80211_HT_DEBUG
+		if (net_ratelimit())
+			printk(KERN_ERR "can not allocate reordering buffer "
+			       "to tid %d\n", tid);
+#endif
+		kfree(sta->ampdu_mlme.tid_rx[tid]);
+		goto end;
+	}
+	memset(tid_agg_rx->reorder_buf, 0,
+		buf_size * sizeof(struct sk_buff *));
+
+	if (local->ops->ampdu_action)
+		ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_RX_START,
+					       &sta->sta, tid, &start_seq_num);
+#ifdef CONFIG_MAC80211_HT_DEBUG
+	printk(KERN_DEBUG "Rx A-MPDU request on tid %d result %d\n", tid, ret);
+#endif /* CONFIG_MAC80211_HT_DEBUG */
+
+	if (ret) {
+		kfree(tid_agg_rx->reorder_buf);
+		kfree(tid_agg_rx);
+		sta->ampdu_mlme.tid_rx[tid] = NULL;
+		goto end;
+	}
+
+	/* change state and send addba resp */
+	sta->ampdu_mlme.tid_state_rx[tid] = HT_AGG_STATE_OPERATIONAL;
+	tid_agg_rx->dialog_token = dialog_token;
+	tid_agg_rx->ssn = start_seq_num;
+	tid_agg_rx->head_seq_num = start_seq_num;
+	tid_agg_rx->buf_size = buf_size;
+	tid_agg_rx->timeout = timeout;
+	tid_agg_rx->stored_mpdu_num = 0;
+	status = WLAN_STATUS_SUCCESS;
+end:
+	spin_unlock_bh(&sta->lock);
+
+end_no_lock:
+	ieee80211_send_addba_resp(sta->sdata, sta->sta.addr, tid,
+				  dialog_token, status, 1, buf_size, timeout);
+}
+
+void ieee80211_process_addba_resp(struct ieee80211_local *local,
+				  struct sta_info *sta,
+				  struct ieee80211_mgmt *mgmt,
+				  size_t len)
+{
+	struct ieee80211_hw *hw = &local->hw;
+	u16 capab;
+	u16 tid;
+	u8 *state;
+
+	capab = le16_to_cpu(mgmt->u.action.u.addba_resp.capab);
+	tid = (capab & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2;
+
+	state = &sta->ampdu_mlme.tid_state_tx[tid];
+
+	spin_lock_bh(&sta->lock);
+
+	if (!(*state & HT_ADDBA_REQUESTED_MSK)) {
+		spin_unlock_bh(&sta->lock);
+		return;
+	}
+
+	if (mgmt->u.action.u.addba_resp.dialog_token !=
+		sta->ampdu_mlme.tid_tx[tid]->dialog_token) {
+		spin_unlock_bh(&sta->lock);
+#ifdef CONFIG_MAC80211_HT_DEBUG
+		printk(KERN_DEBUG "wrong addBA response token, tid %d\n", tid);
+#endif /* CONFIG_MAC80211_HT_DEBUG */
+		return;
+	}
+
+	del_timer_sync(&sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer);
+#ifdef CONFIG_MAC80211_HT_DEBUG
+	printk(KERN_DEBUG "switched off addBA timer for tid %d \n", tid);
+#endif /* CONFIG_MAC80211_HT_DEBUG */
+	if (le16_to_cpu(mgmt->u.action.u.addba_resp.status)
+			== WLAN_STATUS_SUCCESS) {
+		*state |= HT_ADDBA_RECEIVED_MSK;
+		sta->ampdu_mlme.addba_req_num[tid] = 0;
+
+		if (*state == HT_AGG_STATE_OPERATIONAL)
+			ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]);
+
+		spin_unlock_bh(&sta->lock);
+	} else {
+		sta->ampdu_mlme.addba_req_num[tid]++;
+		/* this will allow the state check in stop_BA_session */
+		*state = HT_AGG_STATE_OPERATIONAL;
+		spin_unlock_bh(&sta->lock);
+		ieee80211_stop_tx_ba_session(hw, sta->sta.addr, tid,
+					     WLAN_BACK_INITIATOR);
+	}
+}
+
+void ieee80211_process_delba(struct ieee80211_sub_if_data *sdata,
+			     struct sta_info *sta,
+			     struct ieee80211_mgmt *mgmt, size_t len)
+{
+	struct ieee80211_local *local = sdata->local;
+	u16 tid, params;
+	u16 initiator;
+	DECLARE_MAC_BUF(mac);
+
+	params = le16_to_cpu(mgmt->u.action.u.delba.params);
+	tid = (params & IEEE80211_DELBA_PARAM_TID_MASK) >> 12;
+	initiator = (params & IEEE80211_DELBA_PARAM_INITIATOR_MASK) >> 11;
+
+#ifdef CONFIG_MAC80211_HT_DEBUG
+	if (net_ratelimit())
+		printk(KERN_DEBUG "delba from %s (%s) tid %d reason code %d\n",
+			print_mac(mac, mgmt->sa),
+			initiator ? "initiator" : "recipient", tid,
+			mgmt->u.action.u.delba.reason_code);
+#endif /* CONFIG_MAC80211_HT_DEBUG */
+
+	if (initiator == WLAN_BACK_INITIATOR)
+		ieee80211_sta_stop_rx_ba_session(sdata, sta->sta.addr, tid,
+						 WLAN_BACK_INITIATOR, 0);
+	else { /* WLAN_BACK_RECIPIENT */
+		spin_lock_bh(&sta->lock);
+		sta->ampdu_mlme.tid_state_tx[tid] =
+				HT_AGG_STATE_OPERATIONAL;
+		spin_unlock_bh(&sta->lock);
+		ieee80211_stop_tx_ba_session(&local->hw, sta->sta.addr, tid,
+					     WLAN_BACK_RECIPIENT);
+	}
+}
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 4498d87..8025b29 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -29,17 +29,6 @@
 #include "key.h"
 #include "sta_info.h"
 
-/* ieee80211.o internal definitions, etc. These are not included into
- * low-level drivers. */
-
-#ifndef ETH_P_PAE
-#define ETH_P_PAE 0x888E /* Port Access Entity (IEEE 802.1X) */
-#endif /* ETH_P_PAE */
-
-#define WLAN_FC_DATA_PRESENT(fc) (((fc) & 0x4c) == 0x08)
-
-#define IEEE80211_FC(type, subtype) cpu_to_le16(type | subtype)
-
 struct ieee80211_local;
 
 /* Maximum number of broadcast/multicast frames to buffer when some of the
@@ -61,6 +50,12 @@
  * increased memory use (about 2 kB of RAM per entry). */
 #define IEEE80211_FRAGMENT_MAX 4
 
+/*
+ * Time after which we ignore scan results and no longer report/use
+ * them in any way.
+ */
+#define IEEE80211_SCAN_RESULT_EXPIRE (10 * HZ)
+
 struct ieee80211_fragment_entry {
 	unsigned long first_frag_time;
 	unsigned int seq;
@@ -73,9 +68,9 @@
 };
 
 
-struct ieee80211_sta_bss {
+struct ieee80211_bss {
 	struct list_head list;
-	struct ieee80211_sta_bss *hnext;
+	struct ieee80211_bss *hnext;
 	size_t ssid_len;
 
 	atomic_t users;
@@ -87,16 +82,11 @@
 	enum ieee80211_band band;
 	int freq;
 	int signal, noise, qual;
-	u8 *wpa_ie;
-	size_t wpa_ie_len;
-	u8 *rsn_ie;
-	size_t rsn_ie_len;
-	u8 *wmm_ie;
-	size_t wmm_ie_len;
-	u8 *ht_ie;
-	size_t ht_ie_len;
-	u8 *ht_add_ie;
-	size_t ht_add_ie_len;
+	u8 *ies; /* all information elements from the last Beacon or Probe
+		  * Response frames; note Beacon frame is not allowed to
+		  * override values from Probe Response */
+	size_t ies_len;
+	bool wmm_used;
 #ifdef CONFIG_MAC80211_MESH
 	u8 *mesh_id;
 	size_t mesh_id_len;
@@ -108,7 +98,7 @@
 	u64 timestamp;
 	int beacon_int;
 
-	bool probe_resp;
+	unsigned long last_probe_resp;
 	unsigned long last_update;
 
 	/* during assocation, we save an ERP value from a probe response so
@@ -119,7 +109,7 @@
 	u8 erp_value;
 };
 
-static inline u8 *bss_mesh_cfg(struct ieee80211_sta_bss *bss)
+static inline u8 *bss_mesh_cfg(struct ieee80211_bss *bss)
 {
 #ifdef CONFIG_MAC80211_MESH
 	return bss->mesh_cfg;
@@ -127,7 +117,7 @@
 	return NULL;
 }
 
-static inline u8 *bss_mesh_id(struct ieee80211_sta_bss *bss)
+static inline u8 *bss_mesh_id(struct ieee80211_bss *bss)
 {
 #ifdef CONFIG_MAC80211_MESH
 	return bss->mesh_id;
@@ -135,7 +125,7 @@
 	return NULL;
 }
 
-static inline u8 bss_mesh_id_len(struct ieee80211_sta_bss *bss)
+static inline u8 bss_mesh_id_len(struct ieee80211_bss *bss)
 {
 #ifdef CONFIG_MAC80211_MESH
 	return bss->mesh_id_len;
@@ -174,7 +164,7 @@
 	struct sk_buff **extra_frag;
 	int num_extra_frag;
 
-	u16 fc, ethertype;
+	u16 ethertype;
 	unsigned int flags;
 };
 
@@ -202,7 +192,7 @@
 	struct ieee80211_rx_status *status;
 	struct ieee80211_rate *rate;
 
-	u16 fc, ethertype;
+	u16 ethertype;
 	unsigned int flags;
 	int sent_ps_buffered;
 	int queue;
@@ -239,7 +229,6 @@
 	struct sk_buff_head ps_bc_buf;
 	atomic_t num_sta_ps; /* number of stations in PS mode */
 	int dtim_count;
-	int num_beacons; /* number of TXed beacon frames for this BSS */
 };
 
 struct ieee80211_if_wds {
@@ -300,22 +289,78 @@
 #define IEEE80211_STA_AUTO_BSSID_SEL	BIT(11)
 #define IEEE80211_STA_AUTO_CHANNEL_SEL	BIT(12)
 #define IEEE80211_STA_PRIVACY_INVOKED	BIT(13)
+/* flags for MLME request */
+#define IEEE80211_STA_REQ_SCAN 0
+#define IEEE80211_STA_REQ_DIRECT_PROBE 1
+#define IEEE80211_STA_REQ_AUTH 2
+#define IEEE80211_STA_REQ_RUN  3
+
+/* STA/IBSS MLME states */
+enum ieee80211_sta_mlme_state {
+	IEEE80211_STA_MLME_DISABLED,
+	IEEE80211_STA_MLME_DIRECT_PROBE,
+	IEEE80211_STA_MLME_AUTHENTICATE,
+	IEEE80211_STA_MLME_ASSOCIATE,
+	IEEE80211_STA_MLME_ASSOCIATED,
+	IEEE80211_STA_MLME_IBSS_SEARCH,
+	IEEE80211_STA_MLME_IBSS_JOINED,
+};
+
+/* bitfield of allowed auth algs */
+#define IEEE80211_AUTH_ALG_OPEN BIT(0)
+#define IEEE80211_AUTH_ALG_SHARED_KEY BIT(1)
+#define IEEE80211_AUTH_ALG_LEAP BIT(2)
+
 struct ieee80211_if_sta {
 	struct timer_list timer;
 	struct work_struct work;
 	u8 bssid[ETH_ALEN], prev_bssid[ETH_ALEN];
 	u8 ssid[IEEE80211_MAX_SSID_LEN];
-	enum {
-		IEEE80211_DISABLED, IEEE80211_AUTHENTICATE,
-		IEEE80211_ASSOCIATE, IEEE80211_ASSOCIATED,
-		IEEE80211_IBSS_SEARCH, IEEE80211_IBSS_JOINED,
-		IEEE80211_MESH_UP
-	} state;
+	enum ieee80211_sta_mlme_state state;
 	size_t ssid_len;
 	u8 scan_ssid[IEEE80211_MAX_SSID_LEN];
 	size_t scan_ssid_len;
-#ifdef CONFIG_MAC80211_MESH
+	u16 aid;
+	u16 ap_capab, capab;
+	u8 *extra_ie; /* to be added to the end of AssocReq */
+	size_t extra_ie_len;
+
+	/* The last AssocReq/Resp IEs */
+	u8 *assocreq_ies, *assocresp_ies;
+	size_t assocreq_ies_len, assocresp_ies_len;
+
+	struct sk_buff_head skb_queue;
+
+	int assoc_scan_tries; /* number of scans done pre-association */
+	int direct_probe_tries; /* retries for direct probes */
+	int auth_tries; /* retries for auth req */
+	int assoc_tries; /* retries for assoc req */
+
+	unsigned long request;
+
+	unsigned long last_probe;
+
+	unsigned int flags;
+
+	unsigned int auth_algs; /* bitfield of allowed auth algs */
+	int auth_alg; /* currently used IEEE 802.11 authentication algorithm */
+	int auth_transaction;
+
+	unsigned long ibss_join_req;
+	struct sk_buff *probe_resp; /* ProbeResp template for IBSS */
+	u32 supp_rates_bits[IEEE80211_NUM_BANDS];
+
+	int wmm_last_param_set;
+};
+
+struct ieee80211_if_mesh {
+	struct work_struct work;
+	struct timer_list housekeeping_timer;
 	struct timer_list mesh_path_timer;
+	struct sk_buff_head skb_queue;
+
+	bool housekeeping;
+
 	u8 mesh_id[IEEE80211_MAX_MESH_ID_LEN];
 	size_t mesh_id_len;
 	/* Active Path Selection Protocol Identifier */
@@ -341,66 +386,35 @@
 	struct mesh_config mshcfg;
 	u32 mesh_seqnum;
 	bool accepting_plinks;
-#endif
-	u16 aid;
-	u16 ap_capab, capab;
-	u8 *extra_ie; /* to be added to the end of AssocReq */
-	size_t extra_ie_len;
-
-	/* The last AssocReq/Resp IEs */
-	u8 *assocreq_ies, *assocresp_ies;
-	size_t assocreq_ies_len, assocresp_ies_len;
-
-	struct sk_buff_head skb_queue;
-
-	int auth_tries, assoc_tries;
-
-	unsigned long request;
-
-	unsigned long last_probe;
-
-	unsigned int flags;
-#define IEEE80211_STA_REQ_SCAN 0
-#define IEEE80211_STA_REQ_AUTH 1
-#define IEEE80211_STA_REQ_RUN  2
-
-#define IEEE80211_AUTH_ALG_OPEN BIT(0)
-#define IEEE80211_AUTH_ALG_SHARED_KEY BIT(1)
-#define IEEE80211_AUTH_ALG_LEAP BIT(2)
-	unsigned int auth_algs; /* bitfield of allowed auth algs */
-	int auth_alg; /* currently used IEEE 802.11 authentication algorithm */
-	int auth_transaction;
-
-	unsigned long ibss_join_req;
-	struct sk_buff *probe_resp; /* ProbeResp template for IBSS */
-	u32 supp_rates_bits[IEEE80211_NUM_BANDS];
-
-	int wmm_last_param_set;
-	int num_beacons; /* number of TXed beacon frames by this STA */
 };
 
-static inline void ieee80211_if_sta_set_mesh_id(struct ieee80211_if_sta *ifsta,
-						u8 mesh_id_len, u8 *mesh_id)
-{
 #ifdef CONFIG_MAC80211_MESH
-	ifsta->mesh_id_len = mesh_id_len;
-	memcpy(ifsta->mesh_id, mesh_id, mesh_id_len);
-#endif
-}
-
-#ifdef CONFIG_MAC80211_MESH
-#define IEEE80211_IFSTA_MESH_CTR_INC(sta, name)	\
-	do { (sta)->mshstats.name++; } while (0)
+#define IEEE80211_IFSTA_MESH_CTR_INC(msh, name)	\
+	do { (msh)->mshstats.name++; } while (0)
 #else
-#define IEEE80211_IFSTA_MESH_CTR_INC(sta, name) \
+#define IEEE80211_IFSTA_MESH_CTR_INC(msh, name) \
 	do { } while (0)
 #endif
 
-/* flags used in struct ieee80211_sub_if_data.flags */
-#define IEEE80211_SDATA_ALLMULTI	BIT(0)
-#define IEEE80211_SDATA_PROMISC		BIT(1)
-#define IEEE80211_SDATA_USERSPACE_MLME	BIT(2)
-#define IEEE80211_SDATA_OPERATING_GMODE	BIT(3)
+/**
+ * enum ieee80211_sub_if_data_flags - virtual interface flags
+ *
+ * @IEEE80211_SDATA_ALLMULTI: interface wants all multicast packets
+ * @IEEE80211_SDATA_PROMISC: interface is promisc
+ * @IEEE80211_SDATA_USERSPACE_MLME: userspace MLME is active
+ * @IEEE80211_SDATA_OPERATING_GMODE: operating in G-only mode
+ * @IEEE80211_SDATA_DONT_BRIDGE_PACKETS: bridge packets between
+ *	associated stations and deliver multicast frames both
+ *	back to wireless media and to the local net stack.
+ */
+enum ieee80211_sub_if_data_flags {
+	IEEE80211_SDATA_ALLMULTI		= BIT(0),
+	IEEE80211_SDATA_PROMISC			= BIT(1),
+	IEEE80211_SDATA_USERSPACE_MLME		= BIT(2),
+	IEEE80211_SDATA_OPERATING_GMODE		= BIT(3),
+	IEEE80211_SDATA_DONT_BRIDGE_PACKETS	= BIT(4),
+};
+
 struct ieee80211_sub_if_data {
 	struct list_head list;
 
@@ -416,11 +430,6 @@
 
 	int drop_unencrypted;
 
-	/*
-	 * basic rates of this AP or the AP we're associated to
-	 */
-	u64 basic_rates;
-
 	/* Fragment table for host-based reassembly */
 	struct ieee80211_fragment_entry	fragments[IEEE80211_FRAGMENT_MAX];
 	unsigned int fragment_next;
@@ -447,6 +456,9 @@
 		struct ieee80211_if_wds wds;
 		struct ieee80211_if_vlan vlan;
 		struct ieee80211_if_sta sta;
+#ifdef CONFIG_MAC80211_MESH
+		struct ieee80211_if_mesh mesh;
+#endif
 		u32 mntr_flags;
 	} u;
 
@@ -469,7 +481,6 @@
 			struct dentry *auth_alg;
 			struct dentry *auth_transaction;
 			struct dentry *flags;
-			struct dentry *num_beacons_sta;
 			struct dentry *force_unicast_rateidx;
 			struct dentry *max_ratectrl_rateidx;
 		} sta;
@@ -477,7 +488,6 @@
 			struct dentry *drop_unencrypted;
 			struct dentry *num_sta_ps;
 			struct dentry *dtim_count;
-			struct dentry *num_beacons;
 			struct dentry *force_unicast_rateidx;
 			struct dentry *max_ratectrl_rateidx;
 			struct dentry *num_buffered_multicast;
@@ -540,6 +550,19 @@
 	return container_of(p, struct ieee80211_sub_if_data, vif);
 }
 
+static inline void
+ieee80211_sdata_set_mesh_id(struct ieee80211_sub_if_data *sdata,
+			    u8 mesh_id_len, u8 *mesh_id)
+{
+#ifdef CONFIG_MAC80211_MESH
+	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
+	ifmsh->mesh_id_len = mesh_id_len;
+	memcpy(ifmsh->mesh_id, mesh_id, mesh_id_len);
+#else
+	WARN_ON(1);
+#endif
+}
+
 enum {
 	IEEE80211_RX_MSG	= 1,
 	IEEE80211_TX_STATUS_MSG	= 2,
@@ -550,6 +573,10 @@
 /* maximum number of hardware queues we support. */
 #define QD_MAX_QUEUES (IEEE80211_MAX_AMPDU_QUEUES + IEEE80211_MAX_QUEUES)
 
+struct ieee80211_master_priv {
+	struct ieee80211_local *local;
+};
+
 struct ieee80211_local {
 	/* embed the driver visible part.
 	 * don't cast (use the static inlines below), but we keep
@@ -613,10 +640,6 @@
 	struct crypto_blkcipher *wep_rx_tfm;
 	u32 wep_iv;
 
-	int bridge_packets; /* bridge packets between associated stations and
-			     * deliver multicast frames both back to wireless
-			     * media and to the local net stack */
-
 	struct list_head interfaces;
 
 	/*
@@ -626,21 +649,21 @@
 	spinlock_t key_lock;
 
 
-	bool sta_sw_scanning;
-	bool sta_hw_scanning;
+	/* Scanning and BSS list */
+	bool sw_scanning, hw_scanning;
 	int scan_channel_idx;
 	enum ieee80211_band scan_band;
 
 	enum { SCAN_SET_CHANNEL, SCAN_SEND_PROBE } scan_state;
 	unsigned long last_scan_completed;
 	struct delayed_work scan_work;
-	struct net_device *scan_dev;
+	struct ieee80211_sub_if_data *scan_sdata;
 	struct ieee80211_channel *oper_channel, *scan_channel;
 	u8 scan_ssid[IEEE80211_MAX_SSID_LEN];
 	size_t scan_ssid_len;
-	struct list_head sta_bss_list;
-	struct ieee80211_sta_bss *sta_bss_hash[STA_HASH_SIZE];
-	spinlock_t sta_bss_lock;
+	struct list_head bss_list;
+	struct ieee80211_bss *bss_hash[STA_HASH_SIZE];
+	spinlock_t bss_lock;
 
 	/* SNMP counters */
 	/* dot11CountersTable */
@@ -701,10 +724,11 @@
 
 #ifdef CONFIG_MAC80211_DEBUGFS
 	struct local_debugfsdentries {
+		struct dentry *rcdir;
+		struct dentry *rcname;
 		struct dentry *frequency;
 		struct dentry *antenna_sel_tx;
 		struct dentry *antenna_sel_rx;
-		struct dentry *bridge_packets;
 		struct dentry *rts_threshold;
 		struct dentry *fragmentation_threshold;
 		struct dentry *short_retry_limit;
@@ -774,6 +798,9 @@
 
 /* Parsed Information Elements */
 struct ieee802_11_elems {
+	u8 *ie_start;
+	size_t total_len;
+
 	/* pointers to IEs */
 	u8 *ssid;
 	u8 *supp_rates;
@@ -857,86 +884,82 @@
 }
 
 
-/* ieee80211.c */
 int ieee80211_hw_config(struct ieee80211_local *local);
 int ieee80211_if_config(struct ieee80211_sub_if_data *sdata, u32 changed);
 void ieee80211_tx_set_protected(struct ieee80211_tx_data *tx);
 u32 ieee80211_handle_ht(struct ieee80211_local *local, int enable_ht,
 			struct ieee80211_ht_info *req_ht_cap,
 			struct ieee80211_ht_bss_info *req_bss_cap);
-
-/* ieee80211_ioctl.c */
-extern const struct iw_handler_def ieee80211_iw_handler_def;
-int ieee80211_set_freq(struct net_device *dev, int freq);
-
-/* ieee80211_sta.c */
-void ieee80211_sta_timer(unsigned long data);
-void ieee80211_sta_work(struct work_struct *work);
-void ieee80211_sta_scan_work(struct work_struct *work);
-void ieee80211_sta_rx_mgmt(struct net_device *dev, struct sk_buff *skb,
-			   struct ieee80211_rx_status *rx_status);
-int ieee80211_sta_set_ssid(struct net_device *dev, char *ssid, size_t len);
-int ieee80211_sta_get_ssid(struct net_device *dev, char *ssid, size_t *len);
-int ieee80211_sta_set_bssid(struct net_device *dev, u8 *bssid);
-int ieee80211_sta_req_scan(struct net_device *dev, u8 *ssid, size_t ssid_len);
-void ieee80211_sta_req_auth(struct net_device *dev,
-			    struct ieee80211_if_sta *ifsta);
-int ieee80211_sta_scan_results(struct net_device *dev,
-			       struct iw_request_info *info,
-			       char *buf, size_t len);
-ieee80211_rx_result ieee80211_sta_rx_scan(
-	struct net_device *dev, struct sk_buff *skb,
-	struct ieee80211_rx_status *rx_status);
-void ieee80211_rx_bss_list_init(struct ieee80211_local *local);
-void ieee80211_rx_bss_list_deinit(struct ieee80211_local *local);
-int ieee80211_sta_set_extra_ie(struct net_device *dev, char *ie, size_t len);
-struct sta_info *ieee80211_ibss_add_sta(struct net_device *dev,
-					struct sk_buff *skb, u8 *bssid,
-					u8 *addr, u64 supp_rates);
-int ieee80211_sta_deauthenticate(struct net_device *dev, u16 reason);
-int ieee80211_sta_disassociate(struct net_device *dev, u16 reason);
 void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata,
 				      u32 changed);
-u32 ieee80211_reset_erp_info(struct net_device *dev);
-int ieee80211_ht_cap_ie_to_ht_info(struct ieee80211_ht_cap *ht_cap_ie,
-				   struct ieee80211_ht_info *ht_info);
-int ieee80211_ht_addt_info_ie_to_ht_bss_info(
-			struct ieee80211_ht_addt_info *ht_add_info_ie,
-			struct ieee80211_ht_bss_info *bss_info);
-void ieee80211_send_addba_request(struct net_device *dev, const u8 *da,
-				  u16 tid, u8 dialog_token, u16 start_seq_num,
-				  u16 agg_size, u16 timeout);
-void ieee80211_send_delba(struct net_device *dev, const u8 *da, u16 tid,
-				u16 initiator, u16 reason_code);
-void ieee80211_send_bar(struct net_device *dev, u8 *ra, u16 tid, u16 ssn);
+void ieee80211_configure_filter(struct ieee80211_local *local);
 
-void ieee80211_sta_stop_rx_ba_session(struct net_device *dev, u8 *da,
-				u16 tid, u16 initiator, u16 reason);
-void sta_addba_resp_timer_expired(unsigned long data);
-void ieee80211_sta_tear_down_BA_sessions(struct net_device *dev, u8 *addr);
+/* wireless extensions */
+extern const struct iw_handler_def ieee80211_iw_handler_def;
+
+/* STA/IBSS code */
+void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata);
+void ieee80211_scan_work(struct work_struct *work);
+void ieee80211_sta_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb,
+			   struct ieee80211_rx_status *rx_status);
+int ieee80211_sta_set_ssid(struct ieee80211_sub_if_data *sdata, char *ssid, size_t len);
+int ieee80211_sta_get_ssid(struct ieee80211_sub_if_data *sdata, char *ssid, size_t *len);
+int ieee80211_sta_set_bssid(struct ieee80211_sub_if_data *sdata, u8 *bssid);
+void ieee80211_sta_req_auth(struct ieee80211_sub_if_data *sdata,
+			    struct ieee80211_if_sta *ifsta);
+struct sta_info *ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata,
+					struct sk_buff *skb, u8 *bssid,
+					u8 *addr, u64 supp_rates);
+int ieee80211_sta_deauthenticate(struct ieee80211_sub_if_data *sdata, u16 reason);
+int ieee80211_sta_disassociate(struct ieee80211_sub_if_data *sdata, u16 reason);
+u32 ieee80211_reset_erp_info(struct ieee80211_sub_if_data *sdata);
 u64 ieee80211_sta_get_rates(struct ieee80211_local *local,
 			    struct ieee802_11_elems *elems,
 			    enum ieee80211_band band);
-void ieee80211_sta_tx(struct net_device *dev, struct sk_buff *skb,
-		int encrypt);
-void ieee802_11_parse_elems(u8 *start, size_t len,
-				   struct ieee802_11_elems *elems);
+void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst,
+			      u8 *ssid, size_t ssid_len);
 
-#ifdef CONFIG_MAC80211_MESH
-void ieee80211_start_mesh(struct net_device *dev);
-#else
-static inline void ieee80211_start_mesh(struct net_device *dev)
-{}
-#endif
+/* scan/BSS handling */
+int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata,
+			   u8 *ssid, size_t ssid_len);
+int ieee80211_scan_results(struct ieee80211_local *local,
+			   struct iw_request_info *info,
+			   char *buf, size_t len);
+ieee80211_rx_result
+ieee80211_scan_rx(struct ieee80211_sub_if_data *sdata,
+		  struct sk_buff *skb,
+		  struct ieee80211_rx_status *rx_status);
+void ieee80211_rx_bss_list_init(struct ieee80211_local *local);
+void ieee80211_rx_bss_list_deinit(struct ieee80211_local *local);
+int ieee80211_sta_set_extra_ie(struct ieee80211_sub_if_data *sdata,
+			       char *ie, size_t len);
+
+void ieee80211_mlme_notify_scan_completed(struct ieee80211_local *local);
+int ieee80211_start_scan(struct ieee80211_sub_if_data *scan_sdata,
+			 u8 *ssid, size_t ssid_len);
+struct ieee80211_bss *
+ieee80211_bss_info_update(struct ieee80211_local *local,
+			  struct ieee80211_rx_status *rx_status,
+			  struct ieee80211_mgmt *mgmt,
+			  size_t len,
+			  struct ieee802_11_elems *elems,
+			  int freq, bool beacon);
+struct ieee80211_bss *
+ieee80211_rx_bss_add(struct ieee80211_local *local, u8 *bssid, int freq,
+		     u8 *ssid, u8 ssid_len);
+struct ieee80211_bss *
+ieee80211_rx_bss_get(struct ieee80211_local *local, u8 *bssid, int freq,
+		     u8 *ssid, u8 ssid_len);
+void ieee80211_rx_bss_put(struct ieee80211_local *local,
+			  struct ieee80211_bss *bss);
 
 /* interface handling */
-void ieee80211_if_setup(struct net_device *dev);
 int ieee80211_if_add(struct ieee80211_local *local, const char *name,
-		     struct net_device **new_dev, enum ieee80211_if_types type,
+		     struct net_device **new_dev, enum nl80211_iftype type,
 		     struct vif_params *params);
 int ieee80211_if_change_type(struct ieee80211_sub_if_data *sdata,
-			     enum ieee80211_if_types type);
-void ieee80211_if_remove(struct net_device *dev);
+			     enum nl80211_iftype type);
+void ieee80211_if_remove(struct ieee80211_sub_if_data *sdata);
 void ieee80211_remove_interfaces(struct ieee80211_local *local);
 
 /* tx handling */
@@ -946,16 +969,52 @@
 int ieee80211_monitor_start_xmit(struct sk_buff *skb, struct net_device *dev);
 int ieee80211_subif_start_xmit(struct sk_buff *skb, struct net_device *dev);
 
+/* HT */
+int ieee80211_ht_cap_ie_to_ht_info(struct ieee80211_ht_cap *ht_cap_ie,
+				   struct ieee80211_ht_info *ht_info);
+int ieee80211_ht_addt_info_ie_to_ht_bss_info(
+			struct ieee80211_ht_addt_info *ht_add_info_ie,
+			struct ieee80211_ht_bss_info *bss_info);
+void ieee80211_send_bar(struct ieee80211_sub_if_data *sdata, u8 *ra, u16 tid, u16 ssn);
+
+void ieee80211_sta_stop_rx_ba_session(struct ieee80211_sub_if_data *sdata, u8 *da,
+				u16 tid, u16 initiator, u16 reason);
+void ieee80211_sta_tear_down_BA_sessions(struct ieee80211_sub_if_data *sdata, u8 *addr);
+void ieee80211_process_delba(struct ieee80211_sub_if_data *sdata,
+			     struct sta_info *sta,
+			     struct ieee80211_mgmt *mgmt, size_t len);
+void ieee80211_process_addba_resp(struct ieee80211_local *local,
+				  struct sta_info *sta,
+				  struct ieee80211_mgmt *mgmt,
+				  size_t len);
+void ieee80211_process_addba_request(struct ieee80211_local *local,
+				     struct sta_info *sta,
+				     struct ieee80211_mgmt *mgmt,
+				     size_t len);
+
+/* Spectrum management */
+void ieee80211_process_measurement_req(struct ieee80211_sub_if_data *sdata,
+				       struct ieee80211_mgmt *mgmt,
+				       size_t len);
+
 /* utility functions/constants */
 extern void *mac80211_wiphy_privid; /* for wiphy privid */
 extern const unsigned char rfc1042_header[6];
 extern const unsigned char bridge_tunnel_header[6];
 u8 *ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len,
-			enum ieee80211_if_types type);
+			enum nl80211_iftype type);
 int ieee80211_frame_duration(struct ieee80211_local *local, size_t len,
 			     int rate, int erp, int short_preamble);
-void mac80211_ev_michael_mic_failure(struct net_device *dev, int keyidx,
+void mac80211_ev_michael_mic_failure(struct ieee80211_sub_if_data *sdata, int keyidx,
 				     struct ieee80211_hdr *hdr);
+void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata);
+void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb,
+		      int encrypt);
+void ieee802_11_parse_elems(u8 *start, size_t len,
+			    struct ieee802_11_elems *elems);
+int ieee80211_set_freq(struct ieee80211_sub_if_data *sdata, int freq);
+u64 ieee80211_mandatory_rates(struct ieee80211_local *local,
+			      enum ieee80211_band band);
 
 #ifdef CONFIG_MAC80211_NOINLINE
 #define debug_noinline noinline
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index 610ed1d..8336fee 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -1,4 +1,6 @@
 /*
+ * Interface handling (except master interface)
+ *
  * Copyright 2002-2005, Instant802 Networks, Inc.
  * Copyright 2005-2006, Devicescape Software, Inc.
  * Copyright (c) 2006 Jiri Benc <jbenc@suse.cz>
@@ -17,7 +19,539 @@
 #include "sta_info.h"
 #include "debugfs_netdev.h"
 #include "mesh.h"
+#include "led.h"
 
+static int ieee80211_change_mtu(struct net_device *dev, int new_mtu)
+{
+	int meshhdrlen;
+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+	meshhdrlen = (sdata->vif.type == NL80211_IFTYPE_MESH_POINT) ? 5 : 0;
+
+	/* FIX: what would be proper limits for MTU?
+	 * This interface uses 802.3 frames. */
+	if (new_mtu < 256 ||
+	    new_mtu > IEEE80211_MAX_DATA_LEN - 24 - 6 - meshhdrlen) {
+		return -EINVAL;
+	}
+
+#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
+	printk(KERN_DEBUG "%s: setting MTU %d\n", dev->name, new_mtu);
+#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
+	dev->mtu = new_mtu;
+	return 0;
+}
+
+static inline int identical_mac_addr_allowed(int type1, int type2)
+{
+	return type1 == NL80211_IFTYPE_MONITOR ||
+		type2 == NL80211_IFTYPE_MONITOR ||
+		(type1 == NL80211_IFTYPE_AP && type2 == NL80211_IFTYPE_WDS) ||
+		(type1 == NL80211_IFTYPE_WDS &&
+			(type2 == NL80211_IFTYPE_WDS ||
+			 type2 == NL80211_IFTYPE_AP)) ||
+		(type1 == NL80211_IFTYPE_AP && type2 == NL80211_IFTYPE_AP_VLAN) ||
+		(type1 == NL80211_IFTYPE_AP_VLAN &&
+			(type2 == NL80211_IFTYPE_AP ||
+			 type2 == NL80211_IFTYPE_AP_VLAN));
+}
+
+static int ieee80211_open(struct net_device *dev)
+{
+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	struct ieee80211_sub_if_data *nsdata;
+	struct ieee80211_local *local = sdata->local;
+	struct sta_info *sta;
+	struct ieee80211_if_init_conf conf;
+	u32 changed = 0;
+	int res;
+	bool need_hw_reconfig = 0;
+	u8 null_addr[ETH_ALEN] = {0};
+
+	/* fail early if user set an invalid address */
+	if (compare_ether_addr(dev->dev_addr, null_addr) &&
+	    !is_valid_ether_addr(dev->dev_addr))
+		return -EADDRNOTAVAIL;
+
+	/* we hold the RTNL here so can safely walk the list */
+	list_for_each_entry(nsdata, &local->interfaces, list) {
+		struct net_device *ndev = nsdata->dev;
+
+		if (ndev != dev && netif_running(ndev)) {
+			/*
+			 * Allow only a single IBSS interface to be up at any
+			 * time. This is restricted because beacon distribution
+			 * cannot work properly if both are in the same IBSS.
+			 *
+			 * To remove this restriction we'd have to disallow them
+			 * from setting the same SSID on different IBSS interfaces
+			 * belonging to the same hardware. Then, however, we're
+			 * faced with having to adopt two different TSF timers...
+			 */
+			if (sdata->vif.type == NL80211_IFTYPE_ADHOC &&
+			    nsdata->vif.type == NL80211_IFTYPE_ADHOC)
+				return -EBUSY;
+
+			/*
+			 * The remaining checks are only performed for interfaces
+			 * with the same MAC address.
+			 */
+			if (compare_ether_addr(dev->dev_addr, ndev->dev_addr))
+				continue;
+
+			/*
+			 * check whether it may have the same address
+			 */
+			if (!identical_mac_addr_allowed(sdata->vif.type,
+							nsdata->vif.type))
+				return -ENOTUNIQ;
+
+			/*
+			 * can only add VLANs to enabled APs
+			 */
+			if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN &&
+			    nsdata->vif.type == NL80211_IFTYPE_AP)
+				sdata->bss = &nsdata->u.ap;
+		}
+	}
+
+	switch (sdata->vif.type) {
+	case NL80211_IFTYPE_WDS:
+		if (!is_valid_ether_addr(sdata->u.wds.remote_addr))
+			return -ENOLINK;
+		break;
+	case NL80211_IFTYPE_AP_VLAN:
+		if (!sdata->bss)
+			return -ENOLINK;
+		list_add(&sdata->u.vlan.list, &sdata->bss->vlans);
+		break;
+	case NL80211_IFTYPE_AP:
+		sdata->bss = &sdata->u.ap;
+		break;
+	case NL80211_IFTYPE_MESH_POINT:
+		if (!ieee80211_vif_is_mesh(&sdata->vif))
+			break;
+		/* mesh ifaces must set allmulti to forward mcast traffic */
+		atomic_inc(&local->iff_allmultis);
+		break;
+	case NL80211_IFTYPE_STATION:
+	case NL80211_IFTYPE_MONITOR:
+	case NL80211_IFTYPE_ADHOC:
+		/* no special treatment */
+		break;
+	case NL80211_IFTYPE_UNSPECIFIED:
+	case __NL80211_IFTYPE_AFTER_LAST:
+		/* cannot happen */
+		WARN_ON(1);
+		break;
+	}
+
+	if (local->open_count == 0) {
+		res = 0;
+		if (local->ops->start)
+			res = local->ops->start(local_to_hw(local));
+		if (res)
+			goto err_del_bss;
+		need_hw_reconfig = 1;
+		ieee80211_led_radio(local, local->hw.conf.radio_enabled);
+	}
+
+	/*
+	 * Check all interfaces and copy the hopefully now-present
+	 * MAC address to those that have the special null one.
+	 */
+	list_for_each_entry(nsdata, &local->interfaces, list) {
+		struct net_device *ndev = nsdata->dev;
+
+		/*
+		 * No need to check netif_running since we do not allow
+		 * it to start up with this invalid address.
+		 */
+		if (compare_ether_addr(null_addr, ndev->dev_addr) == 0)
+			memcpy(ndev->dev_addr,
+			       local->hw.wiphy->perm_addr,
+			       ETH_ALEN);
+	}
+
+	if (compare_ether_addr(null_addr, local->mdev->dev_addr) == 0)
+		memcpy(local->mdev->dev_addr, local->hw.wiphy->perm_addr,
+		       ETH_ALEN);
+
+	/*
+	 * Validate the MAC address for this device.
+	 */
+	if (!is_valid_ether_addr(dev->dev_addr)) {
+		if (!local->open_count && local->ops->stop)
+			local->ops->stop(local_to_hw(local));
+		return -EADDRNOTAVAIL;
+	}
+
+	switch (sdata->vif.type) {
+	case NL80211_IFTYPE_AP_VLAN:
+		/* no need to tell driver */
+		break;
+	case NL80211_IFTYPE_MONITOR:
+		if (sdata->u.mntr_flags & MONITOR_FLAG_COOK_FRAMES) {
+			local->cooked_mntrs++;
+			break;
+		}
+
+		/* must be before the call to ieee80211_configure_filter */
+		local->monitors++;
+		if (local->monitors == 1)
+			local->hw.conf.flags |= IEEE80211_CONF_RADIOTAP;
+
+		if (sdata->u.mntr_flags & MONITOR_FLAG_FCSFAIL)
+			local->fif_fcsfail++;
+		if (sdata->u.mntr_flags & MONITOR_FLAG_PLCPFAIL)
+			local->fif_plcpfail++;
+		if (sdata->u.mntr_flags & MONITOR_FLAG_CONTROL)
+			local->fif_control++;
+		if (sdata->u.mntr_flags & MONITOR_FLAG_OTHER_BSS)
+			local->fif_other_bss++;
+
+		netif_addr_lock_bh(local->mdev);
+		ieee80211_configure_filter(local);
+		netif_addr_unlock_bh(local->mdev);
+		break;
+	case NL80211_IFTYPE_STATION:
+	case NL80211_IFTYPE_ADHOC:
+		sdata->u.sta.flags &= ~IEEE80211_STA_PREV_BSSID_SET;
+		/* fall through */
+	default:
+		conf.vif = &sdata->vif;
+		conf.type = sdata->vif.type;
+		conf.mac_addr = dev->dev_addr;
+		res = local->ops->add_interface(local_to_hw(local), &conf);
+		if (res)
+			goto err_stop;
+
+		if (ieee80211_vif_is_mesh(&sdata->vif))
+			ieee80211_start_mesh(sdata);
+		changed |= ieee80211_reset_erp_info(sdata);
+		ieee80211_bss_info_change_notify(sdata, changed);
+		ieee80211_enable_keys(sdata);
+
+		if (sdata->vif.type == NL80211_IFTYPE_STATION &&
+		    !(sdata->flags & IEEE80211_SDATA_USERSPACE_MLME))
+			netif_carrier_off(dev);
+		else
+			netif_carrier_on(dev);
+	}
+
+	if (sdata->vif.type == NL80211_IFTYPE_WDS) {
+		/* Create STA entry for the WDS peer */
+		sta = sta_info_alloc(sdata, sdata->u.wds.remote_addr,
+				     GFP_KERNEL);
+		if (!sta) {
+			res = -ENOMEM;
+			goto err_del_interface;
+		}
+
+		/* no locking required since STA is not live yet */
+		sta->flags |= WLAN_STA_AUTHORIZED;
+
+		res = sta_info_insert(sta);
+		if (res) {
+			/* STA has been freed */
+			goto err_del_interface;
+		}
+	}
+
+	if (local->open_count == 0) {
+		res = dev_open(local->mdev);
+		WARN_ON(res);
+		if (res)
+			goto err_del_interface;
+		tasklet_enable(&local->tx_pending_tasklet);
+		tasklet_enable(&local->tasklet);
+	}
+
+	/*
+	 * set_multicast_list will be invoked by the networking core
+	 * which will check whether any increments here were done in
+	 * error and sync them down to the hardware as filter flags.
+	 */
+	if (sdata->flags & IEEE80211_SDATA_ALLMULTI)
+		atomic_inc(&local->iff_allmultis);
+
+	if (sdata->flags & IEEE80211_SDATA_PROMISC)
+		atomic_inc(&local->iff_promiscs);
+
+	local->open_count++;
+	if (need_hw_reconfig) {
+		ieee80211_hw_config(local);
+		/*
+		 * set default queue parameters so drivers don't
+		 * need to initialise the hardware if the hardware
+		 * doesn't start up with sane defaults
+		 */
+		ieee80211_set_wmm_default(sdata);
+	}
+
+	/*
+	 * ieee80211_sta_work is disabled while network interface
+	 * is down. Therefore, some configuration changes may not
+	 * yet be effective. Trigger execution of ieee80211_sta_work
+	 * to fix this.
+	 */
+	if (sdata->vif.type == NL80211_IFTYPE_STATION ||
+	    sdata->vif.type == NL80211_IFTYPE_ADHOC) {
+		struct ieee80211_if_sta *ifsta = &sdata->u.sta;
+		queue_work(local->hw.workqueue, &ifsta->work);
+	}
+
+	netif_tx_start_all_queues(dev);
+
+	return 0;
+ err_del_interface:
+	local->ops->remove_interface(local_to_hw(local), &conf);
+ err_stop:
+	if (!local->open_count && local->ops->stop)
+		local->ops->stop(local_to_hw(local));
+ err_del_bss:
+	sdata->bss = NULL;
+	if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
+		list_del(&sdata->u.vlan.list);
+	return res;
+}
+
+static int ieee80211_stop(struct net_device *dev)
+{
+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	struct ieee80211_local *local = sdata->local;
+	struct ieee80211_if_init_conf conf;
+	struct sta_info *sta;
+
+	/*
+	 * Stop TX on this interface first.
+	 */
+	netif_tx_stop_all_queues(dev);
+
+	/*
+	 * Now delete all active aggregation sessions.
+	 */
+	rcu_read_lock();
+
+	list_for_each_entry_rcu(sta, &local->sta_list, list) {
+		if (sta->sdata == sdata)
+			ieee80211_sta_tear_down_BA_sessions(sdata,
+							    sta->sta.addr);
+	}
+
+	rcu_read_unlock();
+
+	/*
+	 * Remove all stations associated with this interface.
+	 *
+	 * This must be done before calling ops->remove_interface()
+	 * because otherwise we can later invoke ops->sta_notify()
+	 * whenever the STAs are removed, and that invalidates driver
+	 * assumptions about always getting a vif pointer that is valid
+	 * (because if we remove a STA after ops->remove_interface()
+	 * the driver will have removed the vif info already!)
+	 *
+	 * We could relax this and only unlink the stations from the
+	 * hash table and list but keep them on a per-sdata list that
+	 * will be inserted back again when the interface is brought
+	 * up again, but I don't currently see a use case for that,
+	 * except with WDS which gets a STA entry created when it is
+	 * brought up.
+	 */
+	sta_info_flush(local, sdata);
+
+	/*
+	 * Don't count this interface for promisc/allmulti while it
+	 * is down. dev_mc_unsync() will invoke set_multicast_list
+	 * on the master interface which will sync these down to the
+	 * hardware as filter flags.
+	 */
+	if (sdata->flags & IEEE80211_SDATA_ALLMULTI)
+		atomic_dec(&local->iff_allmultis);
+
+	if (sdata->flags & IEEE80211_SDATA_PROMISC)
+		atomic_dec(&local->iff_promiscs);
+
+	dev_mc_unsync(local->mdev, dev);
+
+	/* APs need special treatment */
+	if (sdata->vif.type == NL80211_IFTYPE_AP) {
+		struct ieee80211_sub_if_data *vlan, *tmp;
+		struct beacon_data *old_beacon = sdata->u.ap.beacon;
+
+		/* remove beacon */
+		rcu_assign_pointer(sdata->u.ap.beacon, NULL);
+		synchronize_rcu();
+		kfree(old_beacon);
+
+		/* down all dependent devices, that is VLANs */
+		list_for_each_entry_safe(vlan, tmp, &sdata->u.ap.vlans,
+					 u.vlan.list)
+			dev_close(vlan->dev);
+		WARN_ON(!list_empty(&sdata->u.ap.vlans));
+	}
+
+	local->open_count--;
+
+	switch (sdata->vif.type) {
+	case NL80211_IFTYPE_AP_VLAN:
+		list_del(&sdata->u.vlan.list);
+		/* no need to tell driver */
+		break;
+	case NL80211_IFTYPE_MONITOR:
+		if (sdata->u.mntr_flags & MONITOR_FLAG_COOK_FRAMES) {
+			local->cooked_mntrs--;
+			break;
+		}
+
+		local->monitors--;
+		if (local->monitors == 0)
+			local->hw.conf.flags &= ~IEEE80211_CONF_RADIOTAP;
+
+		if (sdata->u.mntr_flags & MONITOR_FLAG_FCSFAIL)
+			local->fif_fcsfail--;
+		if (sdata->u.mntr_flags & MONITOR_FLAG_PLCPFAIL)
+			local->fif_plcpfail--;
+		if (sdata->u.mntr_flags & MONITOR_FLAG_CONTROL)
+			local->fif_control--;
+		if (sdata->u.mntr_flags & MONITOR_FLAG_OTHER_BSS)
+			local->fif_other_bss--;
+
+		netif_addr_lock_bh(local->mdev);
+		ieee80211_configure_filter(local);
+		netif_addr_unlock_bh(local->mdev);
+		break;
+	case NL80211_IFTYPE_STATION:
+	case NL80211_IFTYPE_ADHOC:
+		sdata->u.sta.state = IEEE80211_STA_MLME_DISABLED;
+		memset(sdata->u.sta.bssid, 0, ETH_ALEN);
+		del_timer_sync(&sdata->u.sta.timer);
+		/*
+		 * If the timer fired while we waited for it, it will have
+		 * requeued the work. Now the work will be running again
+		 * but will not rearm the timer again because it checks
+		 * whether the interface is running, which, at this point,
+		 * it no longer is.
+		 */
+		cancel_work_sync(&sdata->u.sta.work);
+		/*
+		 * When we get here, the interface is marked down.
+		 * Call synchronize_rcu() to wait for the RX path
+		 * should it be using the interface and enqueuing
+		 * frames at this very time on another CPU.
+		 */
+		synchronize_rcu();
+		skb_queue_purge(&sdata->u.sta.skb_queue);
+
+		sdata->u.sta.flags &= ~IEEE80211_STA_PRIVACY_INVOKED;
+		kfree(sdata->u.sta.extra_ie);
+		sdata->u.sta.extra_ie = NULL;
+		sdata->u.sta.extra_ie_len = 0;
+		/* fall through */
+	case NL80211_IFTYPE_MESH_POINT:
+		if (ieee80211_vif_is_mesh(&sdata->vif)) {
+			/* allmulti is always set on mesh ifaces */
+			atomic_dec(&local->iff_allmultis);
+			ieee80211_stop_mesh(sdata);
+		}
+		/* fall through */
+	default:
+		if (local->scan_sdata == sdata) {
+			if (!local->ops->hw_scan)
+				cancel_delayed_work_sync(&local->scan_work);
+			/*
+			 * The software scan can no longer run now, so we can
+			 * clear out the scan_sdata reference. However, the
+			 * hardware scan may still be running. The complete
+			 * function must be prepared to handle a NULL value.
+			 */
+			local->scan_sdata = NULL;
+			/*
+			 * The memory barrier guarantees that another CPU
+			 * that is hardware-scanning will now see the fact
+			 * that this interface is gone.
+			 */
+			smp_mb();
+			/*
+			 * If software scanning, complete the scan but since
+			 * the scan_sdata is NULL already don't send out a
+			 * scan event to userspace -- the scan is incomplete.
+			 */
+			if (local->sw_scanning)
+				ieee80211_scan_completed(&local->hw);
+		}
+
+		conf.vif = &sdata->vif;
+		conf.type = sdata->vif.type;
+		conf.mac_addr = dev->dev_addr;
+		/* disable all keys for as long as this netdev is down */
+		ieee80211_disable_keys(sdata);
+		local->ops->remove_interface(local_to_hw(local), &conf);
+	}
+
+	sdata->bss = NULL;
+
+	if (local->open_count == 0) {
+		if (netif_running(local->mdev))
+			dev_close(local->mdev);
+
+		if (local->ops->stop)
+			local->ops->stop(local_to_hw(local));
+
+		ieee80211_led_radio(local, 0);
+
+		flush_workqueue(local->hw.workqueue);
+
+		tasklet_disable(&local->tx_pending_tasklet);
+		tasklet_disable(&local->tasklet);
+	}
+
+	return 0;
+}
+
+static void ieee80211_set_multicast_list(struct net_device *dev)
+{
+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	struct ieee80211_local *local = sdata->local;
+	int allmulti, promisc, sdata_allmulti, sdata_promisc;
+
+	allmulti = !!(dev->flags & IFF_ALLMULTI);
+	promisc = !!(dev->flags & IFF_PROMISC);
+	sdata_allmulti = !!(sdata->flags & IEEE80211_SDATA_ALLMULTI);
+	sdata_promisc = !!(sdata->flags & IEEE80211_SDATA_PROMISC);
+
+	if (allmulti != sdata_allmulti) {
+		if (dev->flags & IFF_ALLMULTI)
+			atomic_inc(&local->iff_allmultis);
+		else
+			atomic_dec(&local->iff_allmultis);
+		sdata->flags ^= IEEE80211_SDATA_ALLMULTI;
+	}
+
+	if (promisc != sdata_promisc) {
+		if (dev->flags & IFF_PROMISC)
+			atomic_inc(&local->iff_promiscs);
+		else
+			atomic_dec(&local->iff_promiscs);
+		sdata->flags ^= IEEE80211_SDATA_PROMISC;
+	}
+
+	dev_mc_sync(local->mdev, dev);
+}
+
+static void ieee80211_if_setup(struct net_device *dev)
+{
+	ether_setup(dev);
+	dev->hard_start_xmit = ieee80211_subif_start_xmit;
+	dev->wireless_handlers = &ieee80211_iw_handler_def;
+	dev->set_multicast_list = ieee80211_set_multicast_list;
+	dev->change_mtu = ieee80211_change_mtu;
+	dev->open = ieee80211_open;
+	dev->stop = ieee80211_stop;
+	dev->destructor = free_netdev;
+	/* we will validate the address ourselves in ->open */
+	dev->validate_addr = NULL;
+}
 /*
  * Called when the netdev is removed or, by the code below, before
  * the interface type changes.
@@ -31,17 +565,17 @@
 	int flushed;
 	int i;
 
-	ieee80211_debugfs_remove_netdev(sdata);
-
 	/* free extra data */
 	ieee80211_free_keys(sdata);
 
+	ieee80211_debugfs_remove_netdev(sdata);
+
 	for (i = 0; i < IEEE80211_FRAGMENT_MAX; i++)
 		__skb_queue_purge(&sdata->fragments[i].skb_list);
 	sdata->fragment_next = 0;
 
 	switch (sdata->vif.type) {
-	case IEEE80211_IF_TYPE_AP:
+	case NL80211_IFTYPE_AP:
 		beacon = sdata->u.ap.beacon;
 		rcu_assign_pointer(sdata->u.ap.beacon, NULL);
 		synchronize_rcu();
@@ -53,23 +587,23 @@
 		}
 
 		break;
-	case IEEE80211_IF_TYPE_MESH_POINT:
-		/* Allow compiler to elide mesh_rmc_free call. */
+	case NL80211_IFTYPE_MESH_POINT:
 		if (ieee80211_vif_is_mesh(&sdata->vif))
-			mesh_rmc_free(dev);
-		/* fall through */
-	case IEEE80211_IF_TYPE_STA:
-	case IEEE80211_IF_TYPE_IBSS:
+			mesh_rmc_free(sdata);
+		break;
+	case NL80211_IFTYPE_STATION:
+	case NL80211_IFTYPE_ADHOC:
 		kfree(sdata->u.sta.extra_ie);
 		kfree(sdata->u.sta.assocreq_ies);
 		kfree(sdata->u.sta.assocresp_ies);
 		kfree_skb(sdata->u.sta.probe_resp);
 		break;
-	case IEEE80211_IF_TYPE_WDS:
-	case IEEE80211_IF_TYPE_VLAN:
-	case IEEE80211_IF_TYPE_MNTR:
+	case NL80211_IFTYPE_WDS:
+	case NL80211_IFTYPE_AP_VLAN:
+	case NL80211_IFTYPE_MONITOR:
 		break;
-	case IEEE80211_IF_TYPE_INVALID:
+	case NL80211_IFTYPE_UNSPECIFIED:
+	case __NL80211_IFTYPE_AFTER_LAST:
 		BUG();
 		break;
 	}
@@ -82,55 +616,43 @@
  * Helper function to initialise an interface to a specific type.
  */
 static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata,
-				  enum ieee80211_if_types type)
+				  enum nl80211_iftype type)
 {
-	struct ieee80211_if_sta *ifsta;
-
 	/* clear type-dependent union */
 	memset(&sdata->u, 0, sizeof(sdata->u));
 
 	/* and set some type-dependent values */
 	sdata->vif.type = type;
+	sdata->dev->hard_start_xmit = ieee80211_subif_start_xmit;
+	sdata->wdev.iftype = type;
 
 	/* only monitor differs */
 	sdata->dev->type = ARPHRD_ETHER;
 
 	switch (type) {
-	case IEEE80211_IF_TYPE_AP:
+	case NL80211_IFTYPE_AP:
 		skb_queue_head_init(&sdata->u.ap.ps_bc_buf);
 		INIT_LIST_HEAD(&sdata->u.ap.vlans);
 		break;
-	case IEEE80211_IF_TYPE_MESH_POINT:
-	case IEEE80211_IF_TYPE_STA:
-	case IEEE80211_IF_TYPE_IBSS:
-		ifsta = &sdata->u.sta;
-		INIT_WORK(&ifsta->work, ieee80211_sta_work);
-		setup_timer(&ifsta->timer, ieee80211_sta_timer,
-			    (unsigned long) sdata);
-		skb_queue_head_init(&ifsta->skb_queue);
-
-		ifsta->capab = WLAN_CAPABILITY_ESS;
-		ifsta->auth_algs = IEEE80211_AUTH_ALG_OPEN |
-			IEEE80211_AUTH_ALG_SHARED_KEY;
-		ifsta->flags |= IEEE80211_STA_CREATE_IBSS |
-			IEEE80211_STA_AUTO_BSSID_SEL |
-			IEEE80211_STA_AUTO_CHANNEL_SEL;
-		if (ieee80211_num_regular_queues(&sdata->local->hw) >= 4)
-			ifsta->flags |= IEEE80211_STA_WMM_ENABLED;
-
+	case NL80211_IFTYPE_STATION:
+	case NL80211_IFTYPE_ADHOC:
+		ieee80211_sta_setup_sdata(sdata);
+		break;
+	case NL80211_IFTYPE_MESH_POINT:
 		if (ieee80211_vif_is_mesh(&sdata->vif))
 			ieee80211_mesh_init_sdata(sdata);
 		break;
-	case IEEE80211_IF_TYPE_MNTR:
+	case NL80211_IFTYPE_MONITOR:
 		sdata->dev->type = ARPHRD_IEEE80211_RADIOTAP;
 		sdata->dev->hard_start_xmit = ieee80211_monitor_start_xmit;
 		sdata->u.mntr_flags = MONITOR_FLAG_CONTROL |
 				      MONITOR_FLAG_OTHER_BSS;
 		break;
-	case IEEE80211_IF_TYPE_WDS:
-	case IEEE80211_IF_TYPE_VLAN:
+	case NL80211_IFTYPE_WDS:
+	case NL80211_IFTYPE_AP_VLAN:
 		break;
-	case IEEE80211_IF_TYPE_INVALID:
+	case NL80211_IFTYPE_UNSPECIFIED:
+	case __NL80211_IFTYPE_AFTER_LAST:
 		BUG();
 		break;
 	}
@@ -139,7 +661,7 @@
 }
 
 int ieee80211_if_change_type(struct ieee80211_sub_if_data *sdata,
-			     enum ieee80211_if_types type)
+			     enum nl80211_iftype type)
 {
 	ASSERT_RTNL();
 
@@ -160,14 +682,16 @@
 	ieee80211_setup_sdata(sdata, type);
 
 	/* reset some values that shouldn't be kept across type changes */
-	sdata->basic_rates = 0;
+	sdata->bss_conf.basic_rates =
+		ieee80211_mandatory_rates(sdata->local,
+			sdata->local->hw.conf.channel->band);
 	sdata->drop_unencrypted = 0;
 
 	return 0;
 }
 
 int ieee80211_if_add(struct ieee80211_local *local, const char *name,
-		     struct net_device **new_dev, enum ieee80211_if_types type,
+		     struct net_device **new_dev, enum nl80211_iftype type,
 		     struct vif_params *params)
 {
 	struct net_device *ndev;
@@ -225,9 +749,9 @@
 
 	if (ieee80211_vif_is_mesh(&sdata->vif) &&
 	    params && params->mesh_id_len)
-		ieee80211_if_sta_set_mesh_id(&sdata->u.sta,
-					     params->mesh_id_len,
-					     params->mesh_id);
+		ieee80211_sdata_set_mesh_id(sdata,
+					    params->mesh_id_len,
+					    params->mesh_id);
 
 	list_add_tail_rcu(&sdata->list, &local->interfaces);
 
@@ -241,15 +765,13 @@
 	return ret;
 }
 
-void ieee80211_if_remove(struct net_device *dev)
+void ieee80211_if_remove(struct ieee80211_sub_if_data *sdata)
 {
-	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-
 	ASSERT_RTNL();
 
 	list_del_rcu(&sdata->list);
 	synchronize_rcu();
-	unregister_netdevice(dev);
+	unregister_netdevice(sdata->dev);
 }
 
 /*
diff --git a/net/mac80211/key.c b/net/mac80211/key.c
index 6597c77..a5b06fe 100644
--- a/net/mac80211/key.c
+++ b/net/mac80211/key.c
@@ -118,12 +118,12 @@
 	 * address to indicate a transmit-only key.
 	 */
 	if (key->conf.alg != ALG_WEP &&
-	    (key->sdata->vif.type == IEEE80211_IF_TYPE_AP ||
-	     key->sdata->vif.type == IEEE80211_IF_TYPE_VLAN))
+	    (key->sdata->vif.type == NL80211_IFTYPE_AP ||
+	     key->sdata->vif.type == NL80211_IFTYPE_AP_VLAN))
 		addr = zero_addr;
 
 	if (key->sta)
-		addr = key->sta->addr;
+		addr = key->sta->sta.addr;
 
 	return addr;
 }
@@ -281,6 +281,20 @@
 	key->conf.alg = alg;
 	key->conf.keyidx = idx;
 	key->conf.keylen = key_len;
+	switch (alg) {
+	case ALG_WEP:
+		key->conf.iv_len = WEP_IV_LEN;
+		key->conf.icv_len = WEP_ICV_LEN;
+		break;
+	case ALG_TKIP:
+		key->conf.iv_len = TKIP_IV_LEN;
+		key->conf.icv_len = TKIP_ICV_LEN;
+		break;
+	case ALG_CCMP:
+		key->conf.iv_len = CCMP_HDR_LEN;
+		key->conf.icv_len = CCMP_MIC_LEN;
+		break;
+	}
 	memcpy(key->conf.key, key_data, key_len);
 	INIT_LIST_HEAD(&key->list);
 	INIT_LIST_HEAD(&key->todo);
@@ -331,7 +345,7 @@
 		 */
 		key->conf.flags |= IEEE80211_KEY_FLAG_PAIRWISE;
 	} else {
-		if (sdata->vif.type == IEEE80211_IF_TYPE_STA) {
+		if (sdata->vif.type == NL80211_IFTYPE_STATION) {
 			struct sta_info *ap;
 
 			/*
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index aa5a191..ae62ad40 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -45,16 +45,9 @@
 	u8 data_retries;
 } __attribute__ ((packed));
 
-/* common interface routines */
-
-static int header_parse_80211(const struct sk_buff *skb, unsigned char *haddr)
-{
-	memcpy(haddr, skb_mac_header(skb) + 10, ETH_ALEN); /* addr2 */
-	return ETH_ALEN;
-}
 
 /* must be called under mdev tx lock */
-static void ieee80211_configure_filter(struct ieee80211_local *local)
+void ieee80211_configure_filter(struct ieee80211_local *local)
 {
 	unsigned int changed_flags;
 	unsigned int new_flags = 0;
@@ -97,9 +90,24 @@
 
 /* master interface */
 
+static int header_parse_80211(const struct sk_buff *skb, unsigned char *haddr)
+{
+	memcpy(haddr, skb_mac_header(skb) + 10, ETH_ALEN); /* addr2 */
+	return ETH_ALEN;
+}
+
+static const struct header_ops ieee80211_header_ops = {
+	.create		= eth_header,
+	.parse		= header_parse_80211,
+	.rebuild	= eth_rebuild_header,
+	.cache		= eth_header_cache,
+	.cache_update	= eth_header_cache_update,
+};
+
 static int ieee80211_master_open(struct net_device *dev)
 {
-	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct ieee80211_master_priv *mpriv = netdev_priv(dev);
+	struct ieee80211_local *local = mpriv->local;
 	struct ieee80211_sub_if_data *sdata;
 	int res = -EOPNOTSUPP;
 
@@ -121,7 +129,8 @@
 
 static int ieee80211_master_stop(struct net_device *dev)
 {
-	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct ieee80211_master_priv *mpriv = netdev_priv(dev);
+	struct ieee80211_local *local = mpriv->local;
 	struct ieee80211_sub_if_data *sdata;
 
 	/* we hold the RTNL here so can safely walk the list */
@@ -134,849 +143,12 @@
 
 static void ieee80211_master_set_multicast_list(struct net_device *dev)
 {
-	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct ieee80211_master_priv *mpriv = netdev_priv(dev);
+	struct ieee80211_local *local = mpriv->local;
 
 	ieee80211_configure_filter(local);
 }
 
-/* regular interfaces */
-
-static int ieee80211_change_mtu(struct net_device *dev, int new_mtu)
-{
-	int meshhdrlen;
-	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-
-	meshhdrlen = (sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT) ? 5 : 0;
-
-	/* FIX: what would be proper limits for MTU?
-	 * This interface uses 802.3 frames. */
-	if (new_mtu < 256 ||
-	    new_mtu > IEEE80211_MAX_DATA_LEN - 24 - 6 - meshhdrlen) {
-		return -EINVAL;
-	}
-
-#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
-	printk(KERN_DEBUG "%s: setting MTU %d\n", dev->name, new_mtu);
-#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
-	dev->mtu = new_mtu;
-	return 0;
-}
-
-static inline int identical_mac_addr_allowed(int type1, int type2)
-{
-	return (type1 == IEEE80211_IF_TYPE_MNTR ||
-		type2 == IEEE80211_IF_TYPE_MNTR ||
-		(type1 == IEEE80211_IF_TYPE_AP &&
-		 type2 == IEEE80211_IF_TYPE_WDS) ||
-		(type1 == IEEE80211_IF_TYPE_WDS &&
-		 (type2 == IEEE80211_IF_TYPE_WDS ||
-		  type2 == IEEE80211_IF_TYPE_AP)) ||
-		(type1 == IEEE80211_IF_TYPE_AP &&
-		 type2 == IEEE80211_IF_TYPE_VLAN) ||
-		(type1 == IEEE80211_IF_TYPE_VLAN &&
-		 (type2 == IEEE80211_IF_TYPE_AP ||
-		  type2 == IEEE80211_IF_TYPE_VLAN)));
-}
-
-static int ieee80211_open(struct net_device *dev)
-{
-	struct ieee80211_sub_if_data *sdata, *nsdata;
-	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-	struct sta_info *sta;
-	struct ieee80211_if_init_conf conf;
-	u32 changed = 0;
-	int res;
-	bool need_hw_reconfig = 0;
-
-	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-
-	/* we hold the RTNL here so can safely walk the list */
-	list_for_each_entry(nsdata, &local->interfaces, list) {
-		struct net_device *ndev = nsdata->dev;
-
-		if (ndev != dev && netif_running(ndev)) {
-			/*
-			 * Allow only a single IBSS interface to be up at any
-			 * time. This is restricted because beacon distribution
-			 * cannot work properly if both are in the same IBSS.
-			 *
-			 * To remove this restriction we'd have to disallow them
-			 * from setting the same SSID on different IBSS interfaces
-			 * belonging to the same hardware. Then, however, we're
-			 * faced with having to adopt two different TSF timers...
-			 */
-			if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS &&
-			    nsdata->vif.type == IEEE80211_IF_TYPE_IBSS)
-				return -EBUSY;
-
-			/*
-			 * The remaining checks are only performed for interfaces
-			 * with the same MAC address.
-			 */
-			if (compare_ether_addr(dev->dev_addr, ndev->dev_addr))
-				continue;
-
-			/*
-			 * check whether it may have the same address
-			 */
-			if (!identical_mac_addr_allowed(sdata->vif.type,
-							nsdata->vif.type))
-				return -ENOTUNIQ;
-
-			/*
-			 * can only add VLANs to enabled APs
-			 */
-			if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN &&
-			    nsdata->vif.type == IEEE80211_IF_TYPE_AP)
-				sdata->bss = &nsdata->u.ap;
-		}
-	}
-
-	switch (sdata->vif.type) {
-	case IEEE80211_IF_TYPE_WDS:
-		if (!is_valid_ether_addr(sdata->u.wds.remote_addr))
-			return -ENOLINK;
-		break;
-	case IEEE80211_IF_TYPE_VLAN:
-		if (!sdata->bss)
-			return -ENOLINK;
-		list_add(&sdata->u.vlan.list, &sdata->bss->vlans);
-		break;
-	case IEEE80211_IF_TYPE_AP:
-		sdata->bss = &sdata->u.ap;
-		break;
-	case IEEE80211_IF_TYPE_MESH_POINT:
-		/* mesh ifaces must set allmulti to forward mcast traffic */
-		atomic_inc(&local->iff_allmultis);
-		break;
-	case IEEE80211_IF_TYPE_STA:
-	case IEEE80211_IF_TYPE_MNTR:
-	case IEEE80211_IF_TYPE_IBSS:
-		/* no special treatment */
-		break;
-	case IEEE80211_IF_TYPE_INVALID:
-		/* cannot happen */
-		WARN_ON(1);
-		break;
-	}
-
-	if (local->open_count == 0) {
-		res = 0;
-		if (local->ops->start)
-			res = local->ops->start(local_to_hw(local));
-		if (res)
-			goto err_del_bss;
-		need_hw_reconfig = 1;
-		ieee80211_led_radio(local, local->hw.conf.radio_enabled);
-	}
-
-	switch (sdata->vif.type) {
-	case IEEE80211_IF_TYPE_VLAN:
-		/* no need to tell driver */
-		break;
-	case IEEE80211_IF_TYPE_MNTR:
-		if (sdata->u.mntr_flags & MONITOR_FLAG_COOK_FRAMES) {
-			local->cooked_mntrs++;
-			break;
-		}
-
-		/* must be before the call to ieee80211_configure_filter */
-		local->monitors++;
-		if (local->monitors == 1)
-			local->hw.conf.flags |= IEEE80211_CONF_RADIOTAP;
-
-		if (sdata->u.mntr_flags & MONITOR_FLAG_FCSFAIL)
-			local->fif_fcsfail++;
-		if (sdata->u.mntr_flags & MONITOR_FLAG_PLCPFAIL)
-			local->fif_plcpfail++;
-		if (sdata->u.mntr_flags & MONITOR_FLAG_CONTROL)
-			local->fif_control++;
-		if (sdata->u.mntr_flags & MONITOR_FLAG_OTHER_BSS)
-			local->fif_other_bss++;
-
-		netif_addr_lock_bh(local->mdev);
-		ieee80211_configure_filter(local);
-		netif_addr_unlock_bh(local->mdev);
-		break;
-	case IEEE80211_IF_TYPE_STA:
-	case IEEE80211_IF_TYPE_IBSS:
-		sdata->u.sta.flags &= ~IEEE80211_STA_PREV_BSSID_SET;
-		/* fall through */
-	default:
-		conf.vif = &sdata->vif;
-		conf.type = sdata->vif.type;
-		conf.mac_addr = dev->dev_addr;
-		res = local->ops->add_interface(local_to_hw(local), &conf);
-		if (res)
-			goto err_stop;
-
-		if (ieee80211_vif_is_mesh(&sdata->vif))
-			ieee80211_start_mesh(sdata->dev);
-		changed |= ieee80211_reset_erp_info(dev);
-		ieee80211_bss_info_change_notify(sdata, changed);
-		ieee80211_enable_keys(sdata);
-
-		if (sdata->vif.type == IEEE80211_IF_TYPE_STA &&
-		    !(sdata->flags & IEEE80211_SDATA_USERSPACE_MLME))
-			netif_carrier_off(dev);
-		else
-			netif_carrier_on(dev);
-	}
-
-	if (sdata->vif.type == IEEE80211_IF_TYPE_WDS) {
-		/* Create STA entry for the WDS peer */
-		sta = sta_info_alloc(sdata, sdata->u.wds.remote_addr,
-				     GFP_KERNEL);
-		if (!sta) {
-			res = -ENOMEM;
-			goto err_del_interface;
-		}
-
-		/* no locking required since STA is not live yet */
-		sta->flags |= WLAN_STA_AUTHORIZED;
-
-		res = sta_info_insert(sta);
-		if (res) {
-			/* STA has been freed */
-			goto err_del_interface;
-		}
-	}
-
-	if (local->open_count == 0) {
-		res = dev_open(local->mdev);
-		WARN_ON(res);
-		if (res)
-			goto err_del_interface;
-		tasklet_enable(&local->tx_pending_tasklet);
-		tasklet_enable(&local->tasklet);
-	}
-
-	/*
-	 * set_multicast_list will be invoked by the networking core
-	 * which will check whether any increments here were done in
-	 * error and sync them down to the hardware as filter flags.
-	 */
-	if (sdata->flags & IEEE80211_SDATA_ALLMULTI)
-		atomic_inc(&local->iff_allmultis);
-
-	if (sdata->flags & IEEE80211_SDATA_PROMISC)
-		atomic_inc(&local->iff_promiscs);
-
-	local->open_count++;
-	if (need_hw_reconfig)
-		ieee80211_hw_config(local);
-
-	/*
-	 * ieee80211_sta_work is disabled while network interface
-	 * is down. Therefore, some configuration changes may not
-	 * yet be effective. Trigger execution of ieee80211_sta_work
-	 * to fix this.
-	 */
-	if (sdata->vif.type == IEEE80211_IF_TYPE_STA ||
-	    sdata->vif.type == IEEE80211_IF_TYPE_IBSS) {
-		struct ieee80211_if_sta *ifsta = &sdata->u.sta;
-		queue_work(local->hw.workqueue, &ifsta->work);
-	}
-
-	netif_tx_start_all_queues(dev);
-
-	return 0;
- err_del_interface:
-	local->ops->remove_interface(local_to_hw(local), &conf);
- err_stop:
-	if (!local->open_count && local->ops->stop)
-		local->ops->stop(local_to_hw(local));
- err_del_bss:
-	sdata->bss = NULL;
-	if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN)
-		list_del(&sdata->u.vlan.list);
-	return res;
-}
-
-static int ieee80211_stop(struct net_device *dev)
-{
-	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-	struct ieee80211_local *local = sdata->local;
-	struct ieee80211_if_init_conf conf;
-	struct sta_info *sta;
-
-	/*
-	 * Stop TX on this interface first.
-	 */
-	netif_tx_stop_all_queues(dev);
-
-	/*
-	 * Now delete all active aggregation sessions.
-	 */
-	rcu_read_lock();
-
-	list_for_each_entry_rcu(sta, &local->sta_list, list) {
-		if (sta->sdata == sdata)
-			ieee80211_sta_tear_down_BA_sessions(dev, sta->addr);
-	}
-
-	rcu_read_unlock();
-
-	/*
-	 * Remove all stations associated with this interface.
-	 *
-	 * This must be done before calling ops->remove_interface()
-	 * because otherwise we can later invoke ops->sta_notify()
-	 * whenever the STAs are removed, and that invalidates driver
-	 * assumptions about always getting a vif pointer that is valid
-	 * (because if we remove a STA after ops->remove_interface()
-	 * the driver will have removed the vif info already!)
-	 *
-	 * We could relax this and only unlink the stations from the
-	 * hash table and list but keep them on a per-sdata list that
-	 * will be inserted back again when the interface is brought
-	 * up again, but I don't currently see a use case for that,
-	 * except with WDS which gets a STA entry created when it is
-	 * brought up.
-	 */
-	sta_info_flush(local, sdata);
-
-	/*
-	 * Don't count this interface for promisc/allmulti while it
-	 * is down. dev_mc_unsync() will invoke set_multicast_list
-	 * on the master interface which will sync these down to the
-	 * hardware as filter flags.
-	 */
-	if (sdata->flags & IEEE80211_SDATA_ALLMULTI)
-		atomic_dec(&local->iff_allmultis);
-
-	if (sdata->flags & IEEE80211_SDATA_PROMISC)
-		atomic_dec(&local->iff_promiscs);
-
-	dev_mc_unsync(local->mdev, dev);
-
-	/* APs need special treatment */
-	if (sdata->vif.type == IEEE80211_IF_TYPE_AP) {
-		struct ieee80211_sub_if_data *vlan, *tmp;
-		struct beacon_data *old_beacon = sdata->u.ap.beacon;
-
-		/* remove beacon */
-		rcu_assign_pointer(sdata->u.ap.beacon, NULL);
-		synchronize_rcu();
-		kfree(old_beacon);
-
-		/* down all dependent devices, that is VLANs */
-		list_for_each_entry_safe(vlan, tmp, &sdata->u.ap.vlans,
-					 u.vlan.list)
-			dev_close(vlan->dev);
-		WARN_ON(!list_empty(&sdata->u.ap.vlans));
-	}
-
-	local->open_count--;
-
-	switch (sdata->vif.type) {
-	case IEEE80211_IF_TYPE_VLAN:
-		list_del(&sdata->u.vlan.list);
-		/* no need to tell driver */
-		break;
-	case IEEE80211_IF_TYPE_MNTR:
-		if (sdata->u.mntr_flags & MONITOR_FLAG_COOK_FRAMES) {
-			local->cooked_mntrs--;
-			break;
-		}
-
-		local->monitors--;
-		if (local->monitors == 0)
-			local->hw.conf.flags &= ~IEEE80211_CONF_RADIOTAP;
-
-		if (sdata->u.mntr_flags & MONITOR_FLAG_FCSFAIL)
-			local->fif_fcsfail--;
-		if (sdata->u.mntr_flags & MONITOR_FLAG_PLCPFAIL)
-			local->fif_plcpfail--;
-		if (sdata->u.mntr_flags & MONITOR_FLAG_CONTROL)
-			local->fif_control--;
-		if (sdata->u.mntr_flags & MONITOR_FLAG_OTHER_BSS)
-			local->fif_other_bss--;
-
-		netif_addr_lock_bh(local->mdev);
-		ieee80211_configure_filter(local);
-		netif_addr_unlock_bh(local->mdev);
-		break;
-	case IEEE80211_IF_TYPE_MESH_POINT:
-		/* allmulti is always set on mesh ifaces */
-		atomic_dec(&local->iff_allmultis);
-		/* fall through */
-	case IEEE80211_IF_TYPE_STA:
-	case IEEE80211_IF_TYPE_IBSS:
-		sdata->u.sta.state = IEEE80211_DISABLED;
-		memset(sdata->u.sta.bssid, 0, ETH_ALEN);
-		del_timer_sync(&sdata->u.sta.timer);
-		/*
-		 * When we get here, the interface is marked down.
-		 * Call synchronize_rcu() to wait for the RX path
-		 * should it be using the interface and enqueuing
-		 * frames at this very time on another CPU.
-		 */
-		synchronize_rcu();
-		skb_queue_purge(&sdata->u.sta.skb_queue);
-
-		if (local->scan_dev == sdata->dev) {
-			if (!local->ops->hw_scan) {
-				local->sta_sw_scanning = 0;
-				cancel_delayed_work(&local->scan_work);
-			} else
-				local->sta_hw_scanning = 0;
-		}
-
-		sdata->u.sta.flags &= ~IEEE80211_STA_PRIVACY_INVOKED;
-		kfree(sdata->u.sta.extra_ie);
-		sdata->u.sta.extra_ie = NULL;
-		sdata->u.sta.extra_ie_len = 0;
-		/* fall through */
-	default:
-		conf.vif = &sdata->vif;
-		conf.type = sdata->vif.type;
-		conf.mac_addr = dev->dev_addr;
-		/* disable all keys for as long as this netdev is down */
-		ieee80211_disable_keys(sdata);
-		local->ops->remove_interface(local_to_hw(local), &conf);
-	}
-
-	sdata->bss = NULL;
-
-	if (local->open_count == 0) {
-		if (netif_running(local->mdev))
-			dev_close(local->mdev);
-
-		if (local->ops->stop)
-			local->ops->stop(local_to_hw(local));
-
-		ieee80211_led_radio(local, 0);
-
-		flush_workqueue(local->hw.workqueue);
-
-		tasklet_disable(&local->tx_pending_tasklet);
-		tasklet_disable(&local->tasklet);
-	}
-
-	return 0;
-}
-
-int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid)
-{
-	struct ieee80211_local *local = hw_to_local(hw);
-	struct sta_info *sta;
-	struct ieee80211_sub_if_data *sdata;
-	u16 start_seq_num = 0;
-	u8 *state;
-	int ret;
-	DECLARE_MAC_BUF(mac);
-
-	if (tid >= STA_TID_NUM)
-		return -EINVAL;
-
-#ifdef CONFIG_MAC80211_HT_DEBUG
-	printk(KERN_DEBUG "Open BA session requested for %s tid %u\n",
-				print_mac(mac, ra), tid);
-#endif /* CONFIG_MAC80211_HT_DEBUG */
-
-	rcu_read_lock();
-
-	sta = sta_info_get(local, ra);
-	if (!sta) {
-#ifdef CONFIG_MAC80211_HT_DEBUG
-		printk(KERN_DEBUG "Could not find the station\n");
-#endif
-		ret = -ENOENT;
-		goto exit;
-	}
-
-	spin_lock_bh(&sta->lock);
-
-	/* we have tried too many times, receiver does not want A-MPDU */
-	if (sta->ampdu_mlme.addba_req_num[tid] > HT_AGG_MAX_RETRIES) {
-		ret = -EBUSY;
-		goto err_unlock_sta;
-	}
-
-	state = &sta->ampdu_mlme.tid_state_tx[tid];
-	/* check if the TID is not in aggregation flow already */
-	if (*state != HT_AGG_STATE_IDLE) {
-#ifdef CONFIG_MAC80211_HT_DEBUG
-		printk(KERN_DEBUG "BA request denied - session is not "
-				 "idle on tid %u\n", tid);
-#endif /* CONFIG_MAC80211_HT_DEBUG */
-		ret = -EAGAIN;
-		goto err_unlock_sta;
-	}
-
-	/* prepare A-MPDU MLME for Tx aggregation */
-	sta->ampdu_mlme.tid_tx[tid] =
-			kmalloc(sizeof(struct tid_ampdu_tx), GFP_ATOMIC);
-	if (!sta->ampdu_mlme.tid_tx[tid]) {
-#ifdef CONFIG_MAC80211_HT_DEBUG
-		if (net_ratelimit())
-			printk(KERN_ERR "allocate tx mlme to tid %d failed\n",
-					tid);
-#endif
-		ret = -ENOMEM;
-		goto err_unlock_sta;
-	}
-	/* Tx timer */
-	sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer.function =
-			sta_addba_resp_timer_expired;
-	sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer.data =
-			(unsigned long)&sta->timer_to_tid[tid];
-	init_timer(&sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer);
-
-	/* create a new queue for this aggregation */
-	ret = ieee80211_ht_agg_queue_add(local, sta, tid);
-
-	/* case no queue is available to aggregation
-	 * don't switch to aggregation */
-	if (ret) {
-#ifdef CONFIG_MAC80211_HT_DEBUG
-		printk(KERN_DEBUG "BA request denied - queue unavailable for"
-					" tid %d\n", tid);
-#endif /* CONFIG_MAC80211_HT_DEBUG */
-		goto err_unlock_queue;
-	}
-	sdata = sta->sdata;
-
-	/* Ok, the Addba frame hasn't been sent yet, but if the driver calls the
-	 * call back right away, it must see that the flow has begun */
-	*state |= HT_ADDBA_REQUESTED_MSK;
-
-	if (local->ops->ampdu_action)
-		ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_TX_START,
-						ra, tid, &start_seq_num);
-
-	if (ret) {
-		/* No need to requeue the packets in the agg queue, since we
-		 * held the tx lock: no packet could be enqueued to the newly
-		 * allocated queue */
-		ieee80211_ht_agg_queue_remove(local, sta, tid, 0);
-#ifdef CONFIG_MAC80211_HT_DEBUG
-		printk(KERN_DEBUG "BA request denied - HW unavailable for"
-					" tid %d\n", tid);
-#endif /* CONFIG_MAC80211_HT_DEBUG */
-		*state = HT_AGG_STATE_IDLE;
-		goto err_unlock_queue;
-	}
-
-	/* Will put all the packets in the new SW queue */
-	ieee80211_requeue(local, ieee802_1d_to_ac[tid]);
-	spin_unlock_bh(&sta->lock);
-
-	/* send an addBA request */
-	sta->ampdu_mlme.dialog_token_allocator++;
-	sta->ampdu_mlme.tid_tx[tid]->dialog_token =
-			sta->ampdu_mlme.dialog_token_allocator;
-	sta->ampdu_mlme.tid_tx[tid]->ssn = start_seq_num;
-
-
-	ieee80211_send_addba_request(sta->sdata->dev, ra, tid,
-			 sta->ampdu_mlme.tid_tx[tid]->dialog_token,
-			 sta->ampdu_mlme.tid_tx[tid]->ssn,
-			 0x40, 5000);
-	/* activate the timer for the recipient's addBA response */
-	sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer.expires =
-				jiffies + ADDBA_RESP_INTERVAL;
-	add_timer(&sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer);
-#ifdef CONFIG_MAC80211_HT_DEBUG
-	printk(KERN_DEBUG "activated addBA response timer on tid %d\n", tid);
-#endif
-	goto exit;
-
-err_unlock_queue:
-	kfree(sta->ampdu_mlme.tid_tx[tid]);
-	sta->ampdu_mlme.tid_tx[tid] = NULL;
-	ret = -EBUSY;
-err_unlock_sta:
-	spin_unlock_bh(&sta->lock);
-exit:
-	rcu_read_unlock();
-	return ret;
-}
-EXPORT_SYMBOL(ieee80211_start_tx_ba_session);
-
-int ieee80211_stop_tx_ba_session(struct ieee80211_hw *hw,
-				 u8 *ra, u16 tid,
-				 enum ieee80211_back_parties initiator)
-{
-	struct ieee80211_local *local = hw_to_local(hw);
-	struct sta_info *sta;
-	u8 *state;
-	int ret = 0;
-	DECLARE_MAC_BUF(mac);
-
-	if (tid >= STA_TID_NUM)
-		return -EINVAL;
-
-	rcu_read_lock();
-	sta = sta_info_get(local, ra);
-	if (!sta) {
-		rcu_read_unlock();
-		return -ENOENT;
-	}
-
-	/* check if the TID is in aggregation */
-	state = &sta->ampdu_mlme.tid_state_tx[tid];
-	spin_lock_bh(&sta->lock);
-
-	if (*state != HT_AGG_STATE_OPERATIONAL) {
-		ret = -ENOENT;
-		goto stop_BA_exit;
-	}
-
-#ifdef CONFIG_MAC80211_HT_DEBUG
-	printk(KERN_DEBUG "Tx BA session stop requested for %s tid %u\n",
-				print_mac(mac, ra), tid);
-#endif /* CONFIG_MAC80211_HT_DEBUG */
-
-	ieee80211_stop_queue(hw, sta->tid_to_tx_q[tid]);
-
-	*state = HT_AGG_STATE_REQ_STOP_BA_MSK |
-		(initiator << HT_AGG_STATE_INITIATOR_SHIFT);
-
-	if (local->ops->ampdu_action)
-		ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_TX_STOP,
-						ra, tid, NULL);
-
-	/* case HW denied going back to legacy */
-	if (ret) {
-		WARN_ON(ret != -EBUSY);
-		*state = HT_AGG_STATE_OPERATIONAL;
-		ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]);
-		goto stop_BA_exit;
-	}
-
-stop_BA_exit:
-	spin_unlock_bh(&sta->lock);
-	rcu_read_unlock();
-	return ret;
-}
-EXPORT_SYMBOL(ieee80211_stop_tx_ba_session);
-
-void ieee80211_start_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u16 tid)
-{
-	struct ieee80211_local *local = hw_to_local(hw);
-	struct sta_info *sta;
-	u8 *state;
-	DECLARE_MAC_BUF(mac);
-
-	if (tid >= STA_TID_NUM) {
-#ifdef CONFIG_MAC80211_HT_DEBUG
-		printk(KERN_DEBUG "Bad TID value: tid = %d (>= %d)\n",
-				tid, STA_TID_NUM);
-#endif
-		return;
-	}
-
-	rcu_read_lock();
-	sta = sta_info_get(local, ra);
-	if (!sta) {
-		rcu_read_unlock();
-#ifdef CONFIG_MAC80211_HT_DEBUG
-		printk(KERN_DEBUG "Could not find station: %s\n",
-				print_mac(mac, ra));
-#endif
-		return;
-	}
-
-	state = &sta->ampdu_mlme.tid_state_tx[tid];
-	spin_lock_bh(&sta->lock);
-
-	if (!(*state & HT_ADDBA_REQUESTED_MSK)) {
-#ifdef CONFIG_MAC80211_HT_DEBUG
-		printk(KERN_DEBUG "addBA was not requested yet, state is %d\n",
-				*state);
-#endif
-		spin_unlock_bh(&sta->lock);
-		rcu_read_unlock();
-		return;
-	}
-
-	WARN_ON_ONCE(*state & HT_ADDBA_DRV_READY_MSK);
-
-	*state |= HT_ADDBA_DRV_READY_MSK;
-
-	if (*state == HT_AGG_STATE_OPERATIONAL) {
-#ifdef CONFIG_MAC80211_HT_DEBUG
-		printk(KERN_DEBUG "Aggregation is on for tid %d \n", tid);
-#endif
-		ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]);
-	}
-	spin_unlock_bh(&sta->lock);
-	rcu_read_unlock();
-}
-EXPORT_SYMBOL(ieee80211_start_tx_ba_cb);
-
-void ieee80211_stop_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u8 tid)
-{
-	struct ieee80211_local *local = hw_to_local(hw);
-	struct sta_info *sta;
-	u8 *state;
-	int agg_queue;
-	DECLARE_MAC_BUF(mac);
-
-	if (tid >= STA_TID_NUM) {
-#ifdef CONFIG_MAC80211_HT_DEBUG
-		printk(KERN_DEBUG "Bad TID value: tid = %d (>= %d)\n",
-				tid, STA_TID_NUM);
-#endif
-		return;
-	}
-
-#ifdef CONFIG_MAC80211_HT_DEBUG
-	printk(KERN_DEBUG "Stopping Tx BA session for %s tid %d\n",
-				print_mac(mac, ra), tid);
-#endif /* CONFIG_MAC80211_HT_DEBUG */
-
-	rcu_read_lock();
-	sta = sta_info_get(local, ra);
-	if (!sta) {
-#ifdef CONFIG_MAC80211_HT_DEBUG
-		printk(KERN_DEBUG "Could not find station: %s\n",
-				print_mac(mac, ra));
-#endif
-		rcu_read_unlock();
-		return;
-	}
-	state = &sta->ampdu_mlme.tid_state_tx[tid];
-
-	/* NOTE: no need to use sta->lock in this state check, as
-	 * ieee80211_stop_tx_ba_session will let only one stop call to
-	 * pass through per sta/tid
-	 */
-	if ((*state & HT_AGG_STATE_REQ_STOP_BA_MSK) == 0) {
-#ifdef CONFIG_MAC80211_HT_DEBUG
-		printk(KERN_DEBUG "unexpected callback to A-MPDU stop\n");
-#endif
-		rcu_read_unlock();
-		return;
-	}
-
-	if (*state & HT_AGG_STATE_INITIATOR_MSK)
-		ieee80211_send_delba(sta->sdata->dev, ra, tid,
-			WLAN_BACK_INITIATOR, WLAN_REASON_QSTA_NOT_USE);
-
-	agg_queue = sta->tid_to_tx_q[tid];
-
-	ieee80211_ht_agg_queue_remove(local, sta, tid, 1);
-
-	/* We just requeued the all the frames that were in the
-	 * removed queue, and since we might miss a softirq we do
-	 * netif_schedule_queue.  ieee80211_wake_queue is not used
-	 * here as this queue is not necessarily stopped
-	 */
-	netif_schedule_queue(netdev_get_tx_queue(local->mdev, agg_queue));
-	spin_lock_bh(&sta->lock);
-	*state = HT_AGG_STATE_IDLE;
-	sta->ampdu_mlme.addba_req_num[tid] = 0;
-	kfree(sta->ampdu_mlme.tid_tx[tid]);
-	sta->ampdu_mlme.tid_tx[tid] = NULL;
-	spin_unlock_bh(&sta->lock);
-
-	rcu_read_unlock();
-}
-EXPORT_SYMBOL(ieee80211_stop_tx_ba_cb);
-
-void ieee80211_start_tx_ba_cb_irqsafe(struct ieee80211_hw *hw,
-				      const u8 *ra, u16 tid)
-{
-	struct ieee80211_local *local = hw_to_local(hw);
-	struct ieee80211_ra_tid *ra_tid;
-	struct sk_buff *skb = dev_alloc_skb(0);
-
-	if (unlikely(!skb)) {
-#ifdef CONFIG_MAC80211_HT_DEBUG
-		if (net_ratelimit())
-			printk(KERN_WARNING "%s: Not enough memory, "
-			       "dropping start BA session", skb->dev->name);
-#endif
-		return;
-	}
-	ra_tid = (struct ieee80211_ra_tid *) &skb->cb;
-	memcpy(&ra_tid->ra, ra, ETH_ALEN);
-	ra_tid->tid = tid;
-
-	skb->pkt_type = IEEE80211_ADDBA_MSG;
-	skb_queue_tail(&local->skb_queue, skb);
-	tasklet_schedule(&local->tasklet);
-}
-EXPORT_SYMBOL(ieee80211_start_tx_ba_cb_irqsafe);
-
-void ieee80211_stop_tx_ba_cb_irqsafe(struct ieee80211_hw *hw,
-				     const u8 *ra, u16 tid)
-{
-	struct ieee80211_local *local = hw_to_local(hw);
-	struct ieee80211_ra_tid *ra_tid;
-	struct sk_buff *skb = dev_alloc_skb(0);
-
-	if (unlikely(!skb)) {
-#ifdef CONFIG_MAC80211_HT_DEBUG
-		if (net_ratelimit())
-			printk(KERN_WARNING "%s: Not enough memory, "
-			       "dropping stop BA session", skb->dev->name);
-#endif
-		return;
-	}
-	ra_tid = (struct ieee80211_ra_tid *) &skb->cb;
-	memcpy(&ra_tid->ra, ra, ETH_ALEN);
-	ra_tid->tid = tid;
-
-	skb->pkt_type = IEEE80211_DELBA_MSG;
-	skb_queue_tail(&local->skb_queue, skb);
-	tasklet_schedule(&local->tasklet);
-}
-EXPORT_SYMBOL(ieee80211_stop_tx_ba_cb_irqsafe);
-
-static void ieee80211_set_multicast_list(struct net_device *dev)
-{
-	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-	int allmulti, promisc, sdata_allmulti, sdata_promisc;
-
-	allmulti = !!(dev->flags & IFF_ALLMULTI);
-	promisc = !!(dev->flags & IFF_PROMISC);
-	sdata_allmulti = !!(sdata->flags & IEEE80211_SDATA_ALLMULTI);
-	sdata_promisc = !!(sdata->flags & IEEE80211_SDATA_PROMISC);
-
-	if (allmulti != sdata_allmulti) {
-		if (dev->flags & IFF_ALLMULTI)
-			atomic_inc(&local->iff_allmultis);
-		else
-			atomic_dec(&local->iff_allmultis);
-		sdata->flags ^= IEEE80211_SDATA_ALLMULTI;
-	}
-
-	if (promisc != sdata_promisc) {
-		if (dev->flags & IFF_PROMISC)
-			atomic_inc(&local->iff_promiscs);
-		else
-			atomic_dec(&local->iff_promiscs);
-		sdata->flags ^= IEEE80211_SDATA_PROMISC;
-	}
-
-	dev_mc_sync(local->mdev, dev);
-}
-
-static const struct header_ops ieee80211_header_ops = {
-	.create		= eth_header,
-	.parse		= header_parse_80211,
-	.rebuild	= eth_rebuild_header,
-	.cache		= eth_header_cache,
-	.cache_update	= eth_header_cache_update,
-};
-
-void ieee80211_if_setup(struct net_device *dev)
-{
-	ether_setup(dev);
-	dev->hard_start_xmit = ieee80211_subif_start_xmit;
-	dev->wireless_handlers = &ieee80211_iw_handler_def;
-	dev->set_multicast_list = ieee80211_set_multicast_list;
-	dev->change_mtu = ieee80211_change_mtu;
-	dev->open = ieee80211_open;
-	dev->stop = ieee80211_stop;
-	dev->destructor = free_netdev;
-}
-
 /* everything else */
 
 int ieee80211_if_config(struct ieee80211_sub_if_data *sdata, u32 changed)
@@ -987,18 +159,21 @@
 	if (WARN_ON(!netif_running(sdata->dev)))
 		return 0;
 
+	if (WARN_ON(sdata->vif.type == NL80211_IFTYPE_AP_VLAN))
+		return -EINVAL;
+
 	if (!local->ops->config_interface)
 		return 0;
 
 	memset(&conf, 0, sizeof(conf));
 	conf.changed = changed;
 
-	if (sdata->vif.type == IEEE80211_IF_TYPE_STA ||
-	    sdata->vif.type == IEEE80211_IF_TYPE_IBSS) {
+	if (sdata->vif.type == NL80211_IFTYPE_STATION ||
+	    sdata->vif.type == NL80211_IFTYPE_ADHOC) {
 		conf.bssid = sdata->u.sta.bssid;
 		conf.ssid = sdata->u.sta.ssid;
 		conf.ssid_len = sdata->u.sta.ssid_len;
-	} else if (sdata->vif.type == IEEE80211_IF_TYPE_AP) {
+	} else if (sdata->vif.type == NL80211_IFTYPE_AP) {
 		conf.bssid = sdata->dev->dev_addr;
 		conf.ssid = sdata->u.ap.ssid;
 		conf.ssid_len = sdata->u.ap.ssid_len;
@@ -1027,7 +202,7 @@
 	struct ieee80211_channel *chan;
 	int ret = 0;
 
-	if (local->sta_sw_scanning)
+	if (local->sw_scanning)
 		chan = local->scan_channel;
 	else
 		chan = local->oper_channel;
@@ -1099,8 +274,8 @@
 	ht_conf.ht_supported = 1;
 
 	ht_conf.cap = req_ht_cap->cap & sband->ht_info.cap;
-	ht_conf.cap &= ~(IEEE80211_HT_CAP_MIMO_PS);
-	ht_conf.cap |= sband->ht_info.cap & IEEE80211_HT_CAP_MIMO_PS;
+	ht_conf.cap &= ~(IEEE80211_HT_CAP_SM_PS);
+	ht_conf.cap |= sband->ht_info.cap & IEEE80211_HT_CAP_SM_PS;
 	ht_bss_conf.primary_channel = req_bss_cap->primary_channel;
 	ht_bss_conf.bss_cap = req_bss_cap->bss_cap;
 	ht_bss_conf.bss_op_mode = req_bss_cap->bss_op_mode;
@@ -1152,6 +327,9 @@
 {
 	struct ieee80211_local *local = sdata->local;
 
+	if (WARN_ON(sdata->vif.type == NL80211_IFTYPE_AP_VLAN))
+		return;
+
 	if (!changed)
 		return;
 
@@ -1162,10 +340,8 @@
 					     changed);
 }
 
-u32 ieee80211_reset_erp_info(struct net_device *dev)
+u32 ieee80211_reset_erp_info(struct ieee80211_sub_if_data *sdata)
 {
-	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-
 	sdata->bss_conf.use_cts_prot = 0;
 	sdata->bss_conf.use_short_preamble = 0;
 	return BSS_CHANGED_ERP_CTS_PROT | BSS_CHANGED_ERP_PREAMBLE;
@@ -1244,9 +420,10 @@
 				      struct ieee80211_key *key,
 				      struct sk_buff *skb)
 {
-	int hdrlen, iv_len, mic_len;
+	unsigned int hdrlen, iv_len, mic_len;
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
 
-	hdrlen = ieee80211_get_hdrlen_from_skb(skb);
+	hdrlen = ieee80211_hdrlen(hdr->frame_control);
 
 	if (!key)
 		goto no_key;
@@ -1268,24 +445,20 @@
 		goto no_key;
 	}
 
-	if (skb->len >= mic_len &&
+	if (skb->len >= hdrlen + mic_len &&
 	    !(key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE))
 		skb_trim(skb, skb->len - mic_len);
-	if (skb->len >= iv_len && skb->len > hdrlen) {
+	if (skb->len >= hdrlen + iv_len) {
 		memmove(skb->data + iv_len, skb->data, hdrlen);
-		skb_pull(skb, iv_len);
+		hdr = (struct ieee80211_hdr *)skb_pull(skb, iv_len);
 	}
 
 no_key:
-	{
-		struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
-		u16 fc = le16_to_cpu(hdr->frame_control);
-		if ((fc & 0x8C) == 0x88) /* QoS Control Field */ {
-			fc &= ~IEEE80211_STYPE_QOS_DATA;
-			hdr->frame_control = cpu_to_le16(fc);
-			memmove(skb->data + 2, skb->data, hdrlen - 2);
-			skb_pull(skb, 2);
-		}
+	if (ieee80211_is_data_qos(hdr->frame_control)) {
+		hdr->frame_control &= ~cpu_to_le16(IEEE80211_STYPE_QOS_DATA);
+		memmove(skb->data + IEEE80211_QOS_CTL_LEN, skb->data,
+			hdrlen - IEEE80211_QOS_CTL_LEN);
+		skb_pull(skb, IEEE80211_QOS_CTL_LEN);
 	}
 }
 
@@ -1369,6 +542,7 @@
 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
 	u16 frag, type;
 	__le16 fc;
+	struct ieee80211_supported_band *sband;
 	struct ieee80211_tx_status_rtap_hdr *rthdr;
 	struct ieee80211_sub_if_data *sdata;
 	struct net_device *prev_dev = NULL;
@@ -1376,47 +550,48 @@
 
 	rcu_read_lock();
 
-	if (info->status.excessive_retries) {
-		sta = sta_info_get(local, hdr->addr1);
-		if (sta) {
-			if (test_sta_flags(sta, WLAN_STA_PS)) {
-				/*
-				 * The STA is in power save mode, so assume
-				 * that this TX packet failed because of that.
-				 */
-				ieee80211_handle_filtered_frame(local, sta, skb);
-				rcu_read_unlock();
-				return;
-			}
-		}
-	}
+	sta = sta_info_get(local, hdr->addr1);
 
-	fc = hdr->frame_control;
-
-	if ((info->flags & IEEE80211_TX_STAT_AMPDU_NO_BACK) &&
-	    (ieee80211_is_data_qos(fc))) {
-		u16 tid, ssn;
-		u8 *qc;
-		sta = sta_info_get(local, hdr->addr1);
-		if (sta) {
-			qc = ieee80211_get_qos_ctl(hdr);
-			tid = qc[0] & 0xf;
-			ssn = ((le16_to_cpu(hdr->seq_ctrl) + 0x10)
-						& IEEE80211_SCTL_SEQ);
-			ieee80211_send_bar(sta->sdata->dev, hdr->addr1,
-					   tid, ssn);
-		}
-	}
-
-	if (info->flags & IEEE80211_TX_STAT_TX_FILTERED) {
-		sta = sta_info_get(local, hdr->addr1);
-		if (sta) {
+	if (sta) {
+		if (info->status.excessive_retries &&
+		    test_sta_flags(sta, WLAN_STA_PS)) {
+			/*
+			 * The STA is in power save mode, so assume
+			 * that this TX packet failed because of that.
+			 */
 			ieee80211_handle_filtered_frame(local, sta, skb);
 			rcu_read_unlock();
 			return;
 		}
-	} else
-		rate_control_tx_status(local->mdev, skb);
+
+		fc = hdr->frame_control;
+
+		if ((info->flags & IEEE80211_TX_STAT_AMPDU_NO_BACK) &&
+		    (ieee80211_is_data_qos(fc))) {
+			u16 tid, ssn;
+			u8 *qc;
+
+			qc = ieee80211_get_qos_ctl(hdr);
+			tid = qc[0] & 0xf;
+			ssn = ((le16_to_cpu(hdr->seq_ctrl) + 0x10)
+						& IEEE80211_SCTL_SEQ);
+			ieee80211_send_bar(sta->sdata, hdr->addr1,
+					   tid, ssn);
+		}
+
+		if (info->flags & IEEE80211_TX_STAT_TX_FILTERED) {
+			ieee80211_handle_filtered_frame(local, sta, skb);
+			rcu_read_unlock();
+			return;
+		} else {
+			if (info->status.excessive_retries)
+				sta->tx_retry_failed++;
+			sta->tx_retry_count += info->status.retry_count;
+		}
+
+		sband = local->hw.wiphy->bands[info->band];
+		rate_control_tx_status(local, sband, sta, skb);
+	}
 
 	rcu_read_unlock();
 
@@ -1504,7 +679,7 @@
 
 	rcu_read_lock();
 	list_for_each_entry_rcu(sdata, &local->interfaces, list) {
-		if (sdata->vif.type == IEEE80211_IF_TYPE_MNTR) {
+		if (sdata->vif.type == NL80211_IFTYPE_MONITOR) {
 			if (!netif_running(sdata->dev))
 				continue;
 
@@ -1580,8 +755,6 @@
 
 	local->hw.queues = 1; /* default */
 
-	local->bridge_packets = 1;
-
 	local->rts_threshold = IEEE80211_MAX_RTS_THRESHOLD;
 	local->fragmentation_threshold = IEEE80211_MAX_FRAG_THRESHOLD;
 	local->short_retry_limit = 7;
@@ -1592,7 +765,7 @@
 
 	spin_lock_init(&local->key_lock);
 
-	INIT_DELAYED_WORK(&local->scan_work, ieee80211_sta_scan_work);
+	INIT_DELAYED_WORK(&local->scan_work, ieee80211_scan_work);
 
 	sta_info_init(local);
 
@@ -1619,7 +792,7 @@
 	int result;
 	enum ieee80211_band band;
 	struct net_device *mdev;
-	struct wireless_dev *mwdev;
+	struct ieee80211_master_priv *mpriv;
 
 	/*
 	 * generic code guarantees at least one band,
@@ -1639,6 +812,13 @@
 		}
 	}
 
+	/* if low-level driver supports AP, we also support VLAN */
+	if (local->hw.wiphy->interface_modes & BIT(NL80211_IFTYPE_AP))
+		local->hw.wiphy->interface_modes |= BIT(NL80211_IFTYPE_AP_VLAN);
+
+	/* mac80211 always supports monitor */
+	local->hw.wiphy->interface_modes |= BIT(NL80211_IFTYPE_MONITOR);
+
 	result = wiphy_register(local->hw.wiphy);
 	if (result < 0)
 		return result;
@@ -1654,16 +834,14 @@
 	if (hw->queues < 4)
 		hw->ampdu_queues = 0;
 
-	mdev = alloc_netdev_mq(sizeof(struct wireless_dev),
+	mdev = alloc_netdev_mq(sizeof(struct ieee80211_master_priv),
 			       "wmaster%d", ether_setup,
 			       ieee80211_num_queues(hw));
 	if (!mdev)
 		goto fail_mdev_alloc;
 
-	mwdev = netdev_priv(mdev);
-	mdev->ieee80211_ptr = mwdev;
-	mwdev->wiphy = local->hw.wiphy;
-
+	mpriv = netdev_priv(mdev);
+	mpriv->local = local;
 	local->mdev = mdev;
 
 	ieee80211_rx_bss_list_init(local);
@@ -1745,7 +923,7 @@
 
 	/* add one default STA interface */
 	result = ieee80211_if_add(local, "wlan%d", NULL,
-				  IEEE80211_IF_TYPE_STA, NULL);
+				  NL80211_IFTYPE_STATION, NULL);
 	if (result)
 		printk(KERN_WARNING "%s: Failed to add default virtual iface\n",
 		       wiphy_name(local->hw.wiphy));
@@ -1837,6 +1015,10 @@
 	BUILD_BUG_ON(offsetof(struct ieee80211_tx_info, driver_data) +
 	             IEEE80211_TX_INFO_DRIVER_DATA_SIZE > sizeof(skb->cb));
 
+	ret = rc80211_minstrel_init();
+	if (ret)
+		return ret;
+
 	ret = rc80211_pid_init();
 	if (ret)
 		return ret;
@@ -1849,6 +1031,7 @@
 static void __exit ieee80211_exit(void)
 {
 	rc80211_pid_exit();
+	rc80211_minstrel_exit();
 
 	/*
 	 * For key todo, it'll be empty by now but the work
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index 35f2f95..8013277 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -12,6 +12,9 @@
 #include "ieee80211_i.h"
 #include "mesh.h"
 
+#define IEEE80211_MESH_PEER_INACTIVITY_LIMIT (1800 * HZ)
+#define IEEE80211_MESH_HOUSEKEEPING_INTERVAL (60 * HZ)
+
 #define PP_OFFSET 	1		/* Path Selection Protocol */
 #define PM_OFFSET	5		/* Path Selection Metric   */
 #define CC_OFFSET	9		/* Congestion Control Mode */
@@ -35,19 +38,28 @@
 	kmem_cache_destroy(rm_cache);
 }
 
+static void ieee80211_mesh_housekeeping_timer(unsigned long data)
+{
+	struct ieee80211_sub_if_data *sdata = (void *) data;
+	struct ieee80211_local *local = sdata->local;
+	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
+
+	ifmsh->housekeeping = true;
+	queue_work(local->hw.workqueue, &ifmsh->work);
+}
+
 /**
  * mesh_matches_local - check if the config of a mesh point matches ours
  *
  * @ie: information elements of a management frame from the mesh peer
- * @dev: local mesh interface
+ * @sdata: local mesh subif
  *
  * This function checks if the mesh configuration of a mesh point matches the
  * local mesh configuration, i.e. if both nodes belong to the same mesh network.
  */
-bool mesh_matches_local(struct ieee802_11_elems *ie, struct net_device *dev)
+bool mesh_matches_local(struct ieee802_11_elems *ie, struct ieee80211_sub_if_data *sdata)
 {
-	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-	struct ieee80211_if_sta *sta = &sdata->u.sta;
+	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
 
 	/*
 	 * As support for each feature is added, check for matching
@@ -59,11 +71,11 @@
 	 *   - MDA enabled
 	 * - Power management control on fc
 	 */
-	if (sta->mesh_id_len == ie->mesh_id_len &&
-		memcmp(sta->mesh_id, ie->mesh_id, ie->mesh_id_len) == 0 &&
-		memcmp(sta->mesh_pp_id, ie->mesh_config + PP_OFFSET, 4) == 0 &&
-		memcmp(sta->mesh_pm_id, ie->mesh_config + PM_OFFSET, 4) == 0 &&
-		memcmp(sta->mesh_cc_id, ie->mesh_config + CC_OFFSET, 4) == 0)
+	if (ifmsh->mesh_id_len == ie->mesh_id_len &&
+		memcmp(ifmsh->mesh_id, ie->mesh_id, ie->mesh_id_len) == 0 &&
+		memcmp(ifmsh->mesh_pp_id, ie->mesh_config + PP_OFFSET, 4) == 0 &&
+		memcmp(ifmsh->mesh_pm_id, ie->mesh_config + PM_OFFSET, 4) == 0 &&
+		memcmp(ifmsh->mesh_cc_id, ie->mesh_config + CC_OFFSET, 4) == 0)
 		return true;
 
 	return false;
@@ -73,10 +85,8 @@
  * mesh_peer_accepts_plinks - check if an mp is willing to establish peer links
  *
  * @ie: information elements of a management frame from the mesh peer
- * @dev: local mesh interface
  */
-bool mesh_peer_accepts_plinks(struct ieee802_11_elems *ie,
-			      struct net_device *dev)
+bool mesh_peer_accepts_plinks(struct ieee802_11_elems *ie)
 {
 	return (*(ie->mesh_config + CAPAB_OFFSET) & ACCEPT_PLINKS) != 0;
 }
@@ -98,11 +108,11 @@
 	 */
 	free_plinks = mesh_plink_availables(sdata);
 
-	if (free_plinks != sdata->u.sta.accepting_plinks)
-		ieee80211_sta_timer((unsigned long) sdata);
+	if (free_plinks != sdata->u.mesh.accepting_plinks)
+		ieee80211_mesh_housekeeping_timer((unsigned long) sdata);
 }
 
-void mesh_ids_set_default(struct ieee80211_if_sta *sta)
+void mesh_ids_set_default(struct ieee80211_if_mesh *sta)
 {
 	u8 def_id[4] = {0x00, 0x0F, 0xAC, 0xff};
 
@@ -111,28 +121,26 @@
 	memcpy(sta->mesh_cc_id, def_id, 4);
 }
 
-int mesh_rmc_init(struct net_device *dev)
+int mesh_rmc_init(struct ieee80211_sub_if_data *sdata)
 {
-	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 	int i;
 
-	sdata->u.sta.rmc = kmalloc(sizeof(struct mesh_rmc), GFP_KERNEL);
-	if (!sdata->u.sta.rmc)
+	sdata->u.mesh.rmc = kmalloc(sizeof(struct mesh_rmc), GFP_KERNEL);
+	if (!sdata->u.mesh.rmc)
 		return -ENOMEM;
-	sdata->u.sta.rmc->idx_mask = RMC_BUCKETS - 1;
+	sdata->u.mesh.rmc->idx_mask = RMC_BUCKETS - 1;
 	for (i = 0; i < RMC_BUCKETS; i++)
-		INIT_LIST_HEAD(&sdata->u.sta.rmc->bucket[i].list);
+		INIT_LIST_HEAD(&sdata->u.mesh.rmc->bucket[i].list);
 	return 0;
 }
 
-void mesh_rmc_free(struct net_device *dev)
+void mesh_rmc_free(struct ieee80211_sub_if_data *sdata)
 {
-	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-	struct mesh_rmc *rmc = sdata->u.sta.rmc;
+	struct mesh_rmc *rmc = sdata->u.mesh.rmc;
 	struct rmc_entry *p, *n;
 	int i;
 
-	if (!sdata->u.sta.rmc)
+	if (!sdata->u.mesh.rmc)
 		return;
 
 	for (i = 0; i < RMC_BUCKETS; i++)
@@ -142,7 +150,7 @@
 		}
 
 	kfree(rmc);
-	sdata->u.sta.rmc = NULL;
+	sdata->u.mesh.rmc = NULL;
 }
 
 /**
@@ -158,10 +166,9 @@
  * it.
  */
 int mesh_rmc_check(u8 *sa, struct ieee80211s_hdr *mesh_hdr,
-		   struct net_device *dev)
+		   struct ieee80211_sub_if_data *sdata)
 {
-	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-	struct mesh_rmc *rmc = sdata->u.sta.rmc;
+	struct mesh_rmc *rmc = sdata->u.mesh.rmc;
 	u32 seqnum = 0;
 	int entries = 0;
 	u8 idx;
@@ -194,10 +201,9 @@
 	return 0;
 }
 
-void mesh_mgmt_ies_add(struct sk_buff *skb, struct net_device *dev)
+void mesh_mgmt_ies_add(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata)
 {
-	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	struct ieee80211_local *local = sdata->local;
 	struct ieee80211_supported_band *sband;
 	u8 *pos;
 	int len, i, rate;
@@ -224,11 +230,11 @@
 		}
 	}
 
-	pos = skb_put(skb, 2 + sdata->u.sta.mesh_id_len);
+	pos = skb_put(skb, 2 + sdata->u.mesh.mesh_id_len);
 	*pos++ = WLAN_EID_MESH_ID;
-	*pos++ = sdata->u.sta.mesh_id_len;
-	if (sdata->u.sta.mesh_id_len)
-		memcpy(pos, sdata->u.sta.mesh_id, sdata->u.sta.mesh_id_len);
+	*pos++ = sdata->u.mesh.mesh_id_len;
+	if (sdata->u.mesh.mesh_id_len)
+		memcpy(pos, sdata->u.mesh.mesh_id, sdata->u.mesh.mesh_id_len);
 
 	pos = skb_put(skb, 21);
 	*pos++ = WLAN_EID_MESH_CONFIG;
@@ -237,15 +243,15 @@
 	*pos++ = 1;
 
 	/* Active path selection protocol ID */
-	memcpy(pos, sdata->u.sta.mesh_pp_id, 4);
+	memcpy(pos, sdata->u.mesh.mesh_pp_id, 4);
 	pos += 4;
 
 	/* Active path selection metric ID   */
-	memcpy(pos, sdata->u.sta.mesh_pm_id, 4);
+	memcpy(pos, sdata->u.mesh.mesh_pm_id, 4);
 	pos += 4;
 
 	/* Congestion control mode identifier */
-	memcpy(pos, sdata->u.sta.mesh_cc_id, 4);
+	memcpy(pos, sdata->u.mesh.mesh_cc_id, 4);
 	pos += 4;
 
 	/* Channel precedence:
@@ -255,17 +261,17 @@
 	pos += 4;
 
 	/* Mesh capability */
-	sdata->u.sta.accepting_plinks = mesh_plink_availables(sdata);
-	*pos++ = sdata->u.sta.accepting_plinks ? ACCEPT_PLINKS : 0x00;
+	sdata->u.mesh.accepting_plinks = mesh_plink_availables(sdata);
+	*pos++ = sdata->u.mesh.accepting_plinks ? ACCEPT_PLINKS : 0x00;
 	*pos++ = 0x00;
 
 	return;
 }
 
-u32 mesh_table_hash(u8 *addr, struct net_device *dev, struct mesh_table *tbl)
+u32 mesh_table_hash(u8 *addr, struct ieee80211_sub_if_data *sdata, struct mesh_table *tbl)
 {
 	/* Use last four bytes of hw addr and interface index as hash index */
-	return jhash_2words(*(u32 *)(addr+2), dev->ifindex, tbl->hash_rnd)
+	return jhash_2words(*(u32 *)(addr+2), sdata->dev->ifindex, tbl->hash_rnd)
 		& tbl->hash_mask;
 }
 
@@ -344,10 +350,10 @@
 {
 	struct ieee80211_sub_if_data *sdata =
 		(struct ieee80211_sub_if_data *) data;
-	struct ieee80211_if_sta *ifsta = &sdata->u.sta;
-	struct ieee80211_local *local = wdev_priv(&sdata->wdev);
+	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
+	struct ieee80211_local *local = sdata->local;
 
-	queue_work(local->hw.workqueue, &ifsta->work);
+	queue_work(local->hw.workqueue, &ifmsh->work);
 }
 
 struct mesh_table *mesh_table_grow(struct mesh_table *tbl)
@@ -399,50 +405,264 @@
 		struct ieee80211_sub_if_data *sdata)
 {
 	meshhdr->flags = 0;
-	meshhdr->ttl = sdata->u.sta.mshcfg.dot11MeshTTL;
-	put_unaligned(cpu_to_le32(sdata->u.sta.mesh_seqnum), &meshhdr->seqnum);
-	sdata->u.sta.mesh_seqnum++;
+	meshhdr->ttl = sdata->u.mesh.mshcfg.dot11MeshTTL;
+	put_unaligned(cpu_to_le32(sdata->u.mesh.mesh_seqnum), &meshhdr->seqnum);
+	sdata->u.mesh.mesh_seqnum++;
 
 	return 6;
 }
 
+static void ieee80211_mesh_housekeeping(struct ieee80211_sub_if_data *sdata,
+			   struct ieee80211_if_mesh *ifmsh)
+{
+	bool free_plinks;
+
+#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
+	printk(KERN_DEBUG "%s: running mesh housekeeping\n",
+	       sdata->dev->name);
+#endif
+
+	ieee80211_sta_expire(sdata, IEEE80211_MESH_PEER_INACTIVITY_LIMIT);
+	mesh_path_expire(sdata);
+
+	free_plinks = mesh_plink_availables(sdata);
+	if (free_plinks != sdata->u.mesh.accepting_plinks)
+		ieee80211_if_config(sdata, IEEE80211_IFCC_BEACON);
+
+	ifmsh->housekeeping = false;
+	mod_timer(&ifmsh->housekeeping_timer,
+		  round_jiffies(jiffies + IEEE80211_MESH_HOUSEKEEPING_INTERVAL));
+}
+
+
+void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata)
+{
+	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
+	struct ieee80211_local *local = sdata->local;
+
+	ifmsh->housekeeping = true;
+	queue_work(local->hw.workqueue, &ifmsh->work);
+	ieee80211_if_config(sdata, IEEE80211_IFCC_BEACON);
+}
+
+void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata)
+{
+	del_timer_sync(&sdata->u.mesh.housekeeping_timer);
+	/*
+	 * If the timer fired while we waited for it, it will have
+	 * requeued the work. Now the work will be running again
+	 * but will not rearm the timer again because it checks
+	 * whether the interface is running, which, at this point,
+	 * it no longer is.
+	 */
+	cancel_work_sync(&sdata->u.mesh.work);
+
+	/*
+	 * When we get here, the interface is marked down.
+	 * Call synchronize_rcu() to wait for the RX path
+	 * should it be using the interface and enqueuing
+	 * frames at this very time on another CPU.
+	 */
+	synchronize_rcu();
+	skb_queue_purge(&sdata->u.mesh.skb_queue);
+}
+
+static void ieee80211_mesh_rx_bcn_presp(struct ieee80211_sub_if_data *sdata,
+					u16 stype,
+					struct ieee80211_mgmt *mgmt,
+					size_t len,
+					struct ieee80211_rx_status *rx_status)
+{
+	struct ieee80211_local *local= sdata->local;
+	struct ieee802_11_elems elems;
+	struct ieee80211_channel *channel;
+	u64 supp_rates = 0;
+	size_t baselen;
+	int freq;
+	enum ieee80211_band band = rx_status->band;
+
+	/* ignore ProbeResp to foreign address */
+	if (stype == IEEE80211_STYPE_PROBE_RESP &&
+	    compare_ether_addr(mgmt->da, sdata->dev->dev_addr))
+		return;
+
+	baselen = (u8 *) mgmt->u.probe_resp.variable - (u8 *) mgmt;
+	if (baselen > len)
+		return;
+
+	ieee802_11_parse_elems(mgmt->u.probe_resp.variable, len - baselen,
+			       &elems);
+
+	if (elems.ds_params && elems.ds_params_len == 1)
+		freq = ieee80211_channel_to_frequency(elems.ds_params[0]);
+	else
+		freq = rx_status->freq;
+
+	channel = ieee80211_get_channel(local->hw.wiphy, freq);
+
+	if (!channel || channel->flags & IEEE80211_CHAN_DISABLED)
+		return;
+
+	if (elems.mesh_id && elems.mesh_config &&
+	    mesh_matches_local(&elems, sdata)) {
+		supp_rates = ieee80211_sta_get_rates(local, &elems, band);
+
+		mesh_neighbour_update(mgmt->sa, supp_rates, sdata,
+				      mesh_peer_accepts_plinks(&elems));
+	}
+}
+
+static void ieee80211_mesh_rx_mgmt_action(struct ieee80211_sub_if_data *sdata,
+					  struct ieee80211_mgmt *mgmt,
+					  size_t len,
+					  struct ieee80211_rx_status *rx_status)
+{
+	switch (mgmt->u.action.category) {
+	case PLINK_CATEGORY:
+		mesh_rx_plink_frame(sdata, mgmt, len, rx_status);
+		break;
+	case MESH_PATH_SEL_CATEGORY:
+		mesh_rx_path_sel_frame(sdata, mgmt, len);
+		break;
+	}
+}
+
+static void ieee80211_mesh_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
+					  struct sk_buff *skb)
+{
+	struct ieee80211_rx_status *rx_status;
+	struct ieee80211_if_mesh *ifmsh;
+	struct ieee80211_mgmt *mgmt;
+	u16 stype;
+
+	ifmsh = &sdata->u.mesh;
+
+	rx_status = (struct ieee80211_rx_status *) skb->cb;
+	mgmt = (struct ieee80211_mgmt *) skb->data;
+	stype = le16_to_cpu(mgmt->frame_control) & IEEE80211_FCTL_STYPE;
+
+	switch (stype) {
+	case IEEE80211_STYPE_PROBE_RESP:
+	case IEEE80211_STYPE_BEACON:
+		ieee80211_mesh_rx_bcn_presp(sdata, stype, mgmt, skb->len,
+					    rx_status);
+		break;
+	case IEEE80211_STYPE_ACTION:
+		ieee80211_mesh_rx_mgmt_action(sdata, mgmt, skb->len, rx_status);
+		break;
+	}
+
+	kfree_skb(skb);
+}
+
+static void ieee80211_mesh_work(struct work_struct *work)
+{
+	struct ieee80211_sub_if_data *sdata =
+		container_of(work, struct ieee80211_sub_if_data, u.mesh.work);
+	struct ieee80211_local *local = sdata->local;
+	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
+	struct sk_buff *skb;
+
+	if (!netif_running(sdata->dev))
+		return;
+
+	if (local->sw_scanning || local->hw_scanning)
+		return;
+
+	while ((skb = skb_dequeue(&ifmsh->skb_queue)))
+		ieee80211_mesh_rx_queued_mgmt(sdata, skb);
+
+	if (ifmsh->preq_queue_len &&
+	    time_after(jiffies,
+		       ifmsh->last_preq + msecs_to_jiffies(ifmsh->mshcfg.dot11MeshHWMPpreqMinInterval)))
+		mesh_path_start_discovery(sdata);
+
+	if (ifmsh->housekeeping)
+		ieee80211_mesh_housekeeping(sdata, ifmsh);
+}
+
+void ieee80211_mesh_notify_scan_completed(struct ieee80211_local *local)
+{
+	struct ieee80211_sub_if_data *sdata;
+
+	rcu_read_lock();
+	list_for_each_entry_rcu(sdata, &local->interfaces, list)
+		if (ieee80211_vif_is_mesh(&sdata->vif))
+			queue_work(local->hw.workqueue, &sdata->u.mesh.work);
+	rcu_read_unlock();
+}
+
 void ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata)
 {
-	struct ieee80211_if_sta *ifsta = &sdata->u.sta;
+	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
 
-	ifsta->mshcfg.dot11MeshRetryTimeout = MESH_RET_T;
-	ifsta->mshcfg.dot11MeshConfirmTimeout = MESH_CONF_T;
-	ifsta->mshcfg.dot11MeshHoldingTimeout = MESH_HOLD_T;
-	ifsta->mshcfg.dot11MeshMaxRetries = MESH_MAX_RETR;
-	ifsta->mshcfg.dot11MeshTTL = MESH_TTL;
-	ifsta->mshcfg.auto_open_plinks = true;
-	ifsta->mshcfg.dot11MeshMaxPeerLinks =
+	INIT_WORK(&ifmsh->work, ieee80211_mesh_work);
+	setup_timer(&ifmsh->housekeeping_timer,
+		    ieee80211_mesh_housekeeping_timer,
+		    (unsigned long) sdata);
+	skb_queue_head_init(&sdata->u.mesh.skb_queue);
+
+	ifmsh->mshcfg.dot11MeshRetryTimeout = MESH_RET_T;
+	ifmsh->mshcfg.dot11MeshConfirmTimeout = MESH_CONF_T;
+	ifmsh->mshcfg.dot11MeshHoldingTimeout = MESH_HOLD_T;
+	ifmsh->mshcfg.dot11MeshMaxRetries = MESH_MAX_RETR;
+	ifmsh->mshcfg.dot11MeshTTL = MESH_TTL;
+	ifmsh->mshcfg.auto_open_plinks = true;
+	ifmsh->mshcfg.dot11MeshMaxPeerLinks =
 		MESH_MAX_ESTAB_PLINKS;
-	ifsta->mshcfg.dot11MeshHWMPactivePathTimeout =
+	ifmsh->mshcfg.dot11MeshHWMPactivePathTimeout =
 		MESH_PATH_TIMEOUT;
-	ifsta->mshcfg.dot11MeshHWMPpreqMinInterval =
+	ifmsh->mshcfg.dot11MeshHWMPpreqMinInterval =
 		MESH_PREQ_MIN_INT;
-	ifsta->mshcfg.dot11MeshHWMPnetDiameterTraversalTime =
+	ifmsh->mshcfg.dot11MeshHWMPnetDiameterTraversalTime =
 		MESH_DIAM_TRAVERSAL_TIME;
-	ifsta->mshcfg.dot11MeshHWMPmaxPREQretries =
+	ifmsh->mshcfg.dot11MeshHWMPmaxPREQretries =
 		MESH_MAX_PREQ_RETRIES;
-	ifsta->mshcfg.path_refresh_time =
+	ifmsh->mshcfg.path_refresh_time =
 		MESH_PATH_REFRESH_TIME;
-	ifsta->mshcfg.min_discovery_timeout =
+	ifmsh->mshcfg.min_discovery_timeout =
 		MESH_MIN_DISCOVERY_TIMEOUT;
-	ifsta->accepting_plinks = true;
-	ifsta->preq_id = 0;
-	ifsta->dsn = 0;
-	atomic_set(&ifsta->mpaths, 0);
-	mesh_rmc_init(sdata->dev);
-	ifsta->last_preq = jiffies;
+	ifmsh->accepting_plinks = true;
+	ifmsh->preq_id = 0;
+	ifmsh->dsn = 0;
+	atomic_set(&ifmsh->mpaths, 0);
+	mesh_rmc_init(sdata);
+	ifmsh->last_preq = jiffies;
 	/* Allocate all mesh structures when creating the first mesh interface. */
 	if (!mesh_allocated)
 		ieee80211s_init();
-	mesh_ids_set_default(ifsta);
-	setup_timer(&ifsta->mesh_path_timer,
+	mesh_ids_set_default(ifmsh);
+	setup_timer(&ifmsh->mesh_path_timer,
 		    ieee80211_mesh_path_timer,
 		    (unsigned long) sdata);
-	INIT_LIST_HEAD(&ifsta->preq_queue.list);
-	spin_lock_init(&ifsta->mesh_preq_queue_lock);
+	INIT_LIST_HEAD(&ifmsh->preq_queue.list);
+	spin_lock_init(&ifmsh->mesh_preq_queue_lock);
+}
+
+ieee80211_rx_result
+ieee80211_mesh_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb,
+		       struct ieee80211_rx_status *rx_status)
+{
+	struct ieee80211_local *local = sdata->local;
+	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
+	struct ieee80211_mgmt *mgmt;
+	u16 fc;
+
+	if (skb->len < 24)
+		return RX_DROP_MONITOR;
+
+	mgmt = (struct ieee80211_mgmt *) skb->data;
+	fc = le16_to_cpu(mgmt->frame_control);
+
+	switch (fc & IEEE80211_FCTL_STYPE) {
+	case IEEE80211_STYPE_PROBE_RESP:
+	case IEEE80211_STYPE_BEACON:
+	case IEEE80211_STYPE_ACTION:
+		memcpy(skb->cb, rx_status, sizeof(*rx_status));
+		skb_queue_tail(&ifmsh->skb_queue, skb);
+		queue_work(local->hw.workqueue, &ifmsh->work);
+		return RX_QUEUED;
+	}
+
+	return RX_CONTINUE;
 }
diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h
index 7495fbb..e10471c 100644
--- a/net/mac80211/mesh.h
+++ b/net/mac80211/mesh.h
@@ -47,7 +47,7 @@
  * struct mesh_path - mac80211 mesh path structure
  *
  * @dst: mesh path destination mac address
- * @dev: mesh path device
+ * @sdata: mesh subif
  * @next_hop: mesh neighbor to which frames for this destination will be
  * 	forwarded
  * @timer: mesh path discovery timer
@@ -64,14 +64,15 @@
  * @state_lock: mesh pat state lock
  *
  *
- * The combination of dst and dev is unique in the mesh path table. Since the
+ * The combination of dst and sdata is unique in the mesh path table. Since the
  * next_hop STA is only protected by RCU as well, deleting the STA must also
  * remove/substitute the mesh_path structure and wait until that is no longer
  * reachable before destroying the STA completely.
  */
 struct mesh_path {
 	u8 dst[ETH_ALEN];
-	struct net_device *dev;
+	u8 mpp[ETH_ALEN];	/* used for MPP or MAP */
+	struct ieee80211_sub_if_data *sdata;
 	struct sta_info *next_hop;
 	struct timer_list timer;
 	struct sk_buff_head frame_queue;
@@ -203,67 +204,82 @@
 int ieee80211_new_mesh_header(struct ieee80211s_hdr *meshhdr,
 		struct ieee80211_sub_if_data *sdata);
 int mesh_rmc_check(u8 *addr, struct ieee80211s_hdr *mesh_hdr,
-		struct net_device *dev);
-bool mesh_matches_local(struct ieee802_11_elems *ie, struct net_device *dev);
-void mesh_ids_set_default(struct ieee80211_if_sta *sta);
-void mesh_mgmt_ies_add(struct sk_buff *skb, struct net_device *dev);
-void mesh_rmc_free(struct net_device *dev);
-int mesh_rmc_init(struct net_device *dev);
+		struct ieee80211_sub_if_data *sdata);
+bool mesh_matches_local(struct ieee802_11_elems *ie,
+		struct ieee80211_sub_if_data *sdata);
+void mesh_ids_set_default(struct ieee80211_if_mesh *mesh);
+void mesh_mgmt_ies_add(struct sk_buff *skb,
+		struct ieee80211_sub_if_data *sdata);
+void mesh_rmc_free(struct ieee80211_sub_if_data *sdata);
+int mesh_rmc_init(struct ieee80211_sub_if_data *sdata);
 void ieee80211s_init(void);
 void ieee80211s_stop(void);
 void ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata);
+ieee80211_rx_result
+ieee80211_mesh_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb,
+		       struct ieee80211_rx_status *rx_status);
+void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata);
+void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata);
 
 /* Mesh paths */
-int mesh_nexthop_lookup(struct sk_buff *skb, struct net_device *dev);
-void mesh_path_start_discovery(struct net_device *dev);
-struct mesh_path *mesh_path_lookup(u8 *dst, struct net_device *dev);
-struct mesh_path *mesh_path_lookup_by_idx(int idx, struct net_device *dev);
+int mesh_nexthop_lookup(struct sk_buff *skb,
+		struct ieee80211_sub_if_data *sdata);
+void mesh_path_start_discovery(struct ieee80211_sub_if_data *sdata);
+struct mesh_path *mesh_path_lookup(u8 *dst,
+		struct ieee80211_sub_if_data *sdata);
+struct mesh_path *mpp_path_lookup(u8 *dst,
+				  struct ieee80211_sub_if_data *sdata);
+int mpp_path_add(u8 *dst, u8 *mpp, struct ieee80211_sub_if_data *sdata);
+struct mesh_path *mesh_path_lookup_by_idx(int idx,
+		struct ieee80211_sub_if_data *sdata);
 void mesh_path_fix_nexthop(struct mesh_path *mpath, struct sta_info *next_hop);
-void mesh_path_expire(struct net_device *dev);
-void mesh_path_flush(struct net_device *dev);
-void mesh_rx_path_sel_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt,
-		size_t len);
-int mesh_path_add(u8 *dst, struct net_device *dev);
+void mesh_path_expire(struct ieee80211_sub_if_data *sdata);
+void mesh_path_flush(struct ieee80211_sub_if_data *sdata);
+void mesh_rx_path_sel_frame(struct ieee80211_sub_if_data *sdata,
+		struct ieee80211_mgmt *mgmt, size_t len);
+int mesh_path_add(u8 *dst, struct ieee80211_sub_if_data *sdata);
 /* Mesh plinks */
-void mesh_neighbour_update(u8 *hw_addr, u64 rates, struct net_device *dev,
-		bool add);
-bool mesh_peer_accepts_plinks(struct ieee802_11_elems *ie,
-			      struct net_device *dev);
+void mesh_neighbour_update(u8 *hw_addr, u64 rates,
+		struct ieee80211_sub_if_data *sdata, bool add);
+bool mesh_peer_accepts_plinks(struct ieee802_11_elems *ie);
 void mesh_accept_plinks_update(struct ieee80211_sub_if_data *sdata);
 void mesh_plink_broken(struct sta_info *sta);
 void mesh_plink_deactivate(struct sta_info *sta);
 int mesh_plink_open(struct sta_info *sta);
 int mesh_plink_close(struct sta_info *sta);
 void mesh_plink_block(struct sta_info *sta);
-void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt,
-			 size_t len, struct ieee80211_rx_status *rx_status);
+void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata,
+			 struct ieee80211_mgmt *mgmt, size_t len,
+			 struct ieee80211_rx_status *rx_status);
 
 /* Private interfaces */
 /* Mesh tables */
 struct mesh_table *mesh_table_alloc(int size_order);
 void mesh_table_free(struct mesh_table *tbl, bool free_leafs);
 struct mesh_table *mesh_table_grow(struct mesh_table *tbl);
-u32 mesh_table_hash(u8 *addr, struct net_device *dev, struct mesh_table *tbl);
+u32 mesh_table_hash(u8 *addr, struct ieee80211_sub_if_data *sdata,
+		struct mesh_table *tbl);
 /* Mesh paths */
 int mesh_path_error_tx(u8 *dest, __le32 dest_dsn, u8 *ra,
-		struct net_device *dev);
+		struct ieee80211_sub_if_data *sdata);
 void mesh_path_assign_nexthop(struct mesh_path *mpath, struct sta_info *sta);
 void mesh_path_flush_pending(struct mesh_path *mpath);
 void mesh_path_tx_pending(struct mesh_path *mpath);
 int mesh_pathtbl_init(void);
 void mesh_pathtbl_unregister(void);
-int mesh_path_del(u8 *addr, struct net_device *dev);
+int mesh_path_del(u8 *addr, struct ieee80211_sub_if_data *sdata);
 void mesh_path_timer(unsigned long data);
 void mesh_path_flush_by_nexthop(struct sta_info *sta);
-void mesh_path_discard_frame(struct sk_buff *skb, struct net_device *dev);
+void mesh_path_discard_frame(struct sk_buff *skb,
+		struct ieee80211_sub_if_data *sdata);
 
 #ifdef CONFIG_MAC80211_MESH
 extern int mesh_allocated;
 
 static inline int mesh_plink_free_count(struct ieee80211_sub_if_data *sdata)
 {
-	return sdata->u.sta.mshcfg.dot11MeshMaxPeerLinks -
-	       atomic_read(&sdata->u.sta.mshstats.estab_plinks);
+	return sdata->u.mesh.mshcfg.dot11MeshMaxPeerLinks -
+	       atomic_read(&sdata->u.mesh.mshstats.estab_plinks);
 }
 
 static inline bool mesh_plink_availables(struct ieee80211_sub_if_data *sdata)
@@ -281,8 +297,12 @@
 	for (i = 0; i <= x->hash_mask; i++) \
 		hlist_for_each_entry_rcu(node, p, &x->hash_buckets[i], list)
 
+void ieee80211_mesh_notify_scan_completed(struct ieee80211_local *local);
+
 #else
 #define mesh_allocated	0
+static inline void
+ieee80211_mesh_notify_scan_completed(struct ieee80211_local *local) {}
 #endif
 
 #endif /* IEEE80211S_H */
diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c
index 08aca44..501c783 100644
--- a/net/mac80211/mesh_hwmp.c
+++ b/net/mac80211/mesh_hwmp.c
@@ -64,14 +64,14 @@
 #define DSN_LT(x, y) ((long) (x) - (long) (y) < 0)
 
 #define net_traversal_jiffies(s) \
-	msecs_to_jiffies(s->u.sta.mshcfg.dot11MeshHWMPnetDiameterTraversalTime)
+	msecs_to_jiffies(s->u.mesh.mshcfg.dot11MeshHWMPnetDiameterTraversalTime)
 #define default_lifetime(s) \
-	MSEC_TO_TU(s->u.sta.mshcfg.dot11MeshHWMPactivePathTimeout)
+	MSEC_TO_TU(s->u.mesh.mshcfg.dot11MeshHWMPactivePathTimeout)
 #define min_preq_int_jiff(s) \
-	(msecs_to_jiffies(s->u.sta.mshcfg.dot11MeshHWMPpreqMinInterval))
-#define max_preq_retries(s) (s->u.sta.mshcfg.dot11MeshHWMPmaxPREQretries)
+	(msecs_to_jiffies(s->u.mesh.mshcfg.dot11MeshHWMPpreqMinInterval))
+#define max_preq_retries(s) (s->u.mesh.mshcfg.dot11MeshHWMPmaxPREQretries)
 #define disc_timeout_jiff(s) \
-	msecs_to_jiffies(sdata->u.sta.mshcfg.min_discovery_timeout)
+	msecs_to_jiffies(sdata->u.mesh.mshcfg.min_discovery_timeout)
 
 enum mpath_frame_type {
 	MPATH_PREQ = 0,
@@ -82,9 +82,9 @@
 static int mesh_path_sel_frame_tx(enum mpath_frame_type action, u8 flags,
 		u8 *orig_addr, __le32 orig_dsn, u8 dst_flags, u8 *dst,
 		__le32 dst_dsn, u8 *da, u8 hop_count, u8 ttl, __le32 lifetime,
-		__le32 metric, __le32 preq_id, struct net_device *dev)
+		__le32 metric, __le32 preq_id, struct ieee80211_sub_if_data *sdata)
 {
-	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct ieee80211_local *local = sdata->local;
 	struct sk_buff *skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400);
 	struct ieee80211_mgmt *mgmt;
 	u8 *pos;
@@ -99,11 +99,11 @@
 	mgmt = (struct ieee80211_mgmt *)
 		skb_put(skb, 25 + sizeof(mgmt->u.action.u.mesh_action));
 	memset(mgmt, 0, 25 + sizeof(mgmt->u.action.u.mesh_action));
-	mgmt->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT,
-					   IEEE80211_STYPE_ACTION);
+	mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
+					  IEEE80211_STYPE_ACTION);
 
 	memcpy(mgmt->da, da, ETH_ALEN);
-	memcpy(mgmt->sa, dev->dev_addr, ETH_ALEN);
+	memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
 	/* BSSID is left zeroed, wildcard value */
 	mgmt->u.action.category = MESH_PATH_SEL_CATEGORY;
 	mgmt->u.action.u.mesh_action.action_code = action;
@@ -149,7 +149,7 @@
 	pos += ETH_ALEN;
 	memcpy(pos, &dst_dsn, 4);
 
-	ieee80211_sta_tx(dev, skb, 0);
+	ieee80211_tx_skb(sdata, skb, 0);
 	return 0;
 }
 
@@ -161,9 +161,9 @@
  * @ra: node this frame is addressed to
  */
 int mesh_path_error_tx(u8 *dst, __le32 dst_dsn, u8 *ra,
-		struct net_device *dev)
+		struct ieee80211_sub_if_data *sdata)
 {
-	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct ieee80211_local *local = sdata->local;
 	struct sk_buff *skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400);
 	struct ieee80211_mgmt *mgmt;
 	u8 *pos;
@@ -178,11 +178,11 @@
 	mgmt = (struct ieee80211_mgmt *)
 		skb_put(skb, 25 + sizeof(mgmt->u.action.u.mesh_action));
 	memset(mgmt, 0, 25 + sizeof(mgmt->u.action.u.mesh_action));
-	mgmt->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT,
-					   IEEE80211_STYPE_ACTION);
+	mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
+					  IEEE80211_STYPE_ACTION);
 
 	memcpy(mgmt->da, ra, ETH_ALEN);
-	memcpy(mgmt->sa, dev->dev_addr, ETH_ALEN);
+	memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
 	/* BSSID is left zeroed, wildcard value */
 	mgmt->u.action.category = MESH_PATH_SEL_CATEGORY;
 	mgmt->u.action.u.mesh_action.action_code = MPATH_PERR;
@@ -198,7 +198,7 @@
 	pos += ETH_ALEN;
 	memcpy(pos, &dst_dsn, 4);
 
-	ieee80211_sta_tx(dev, skb, 0);
+	ieee80211_tx_skb(sdata, skb, 0);
 	return 0;
 }
 
@@ -223,7 +223,7 @@
 	/* bitrate is in units of 100 Kbps, while we need rate in units of
 	 * 1Mbps. This will be corrected on tx_time computation.
 	 */
-	rate = sband->bitrates[sta->txrate_idx].bitrate;
+	rate = sband->bitrates[sta->last_txrate_idx].bitrate;
 	tx_time = (device_constant + 10 * test_frame_len / rate);
 	estimated_retx = ((1 << (2 * ARITH_SHIFT)) / (s_unit - err));
 	result = (tx_time * estimated_retx) >> (2 * ARITH_SHIFT) ;
@@ -233,7 +233,7 @@
 /**
  * hwmp_route_info_get - Update routing info to originator and transmitter
  *
- * @dev: local mesh interface
+ * @sdata: local mesh subif
  * @mgmt: mesh management frame
  * @hwmp_ie: hwmp information element (PREP or PREQ)
  *
@@ -246,11 +246,11 @@
  * Notes: this function is the only place (besides user-provided info) where
  * path routing information is updated.
  */
-static u32 hwmp_route_info_get(struct net_device *dev,
+static u32 hwmp_route_info_get(struct ieee80211_sub_if_data *sdata,
 			    struct ieee80211_mgmt *mgmt,
 			    u8 *hwmp_ie)
 {
-	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct ieee80211_local *local = sdata->local;
 	struct mesh_path *mpath;
 	struct sta_info *sta;
 	bool fresh_info;
@@ -301,14 +301,14 @@
 		new_metric = MAX_METRIC;
 	exp_time = TU_TO_EXP_TIME(orig_lifetime);
 
-	if (memcmp(orig_addr, dev->dev_addr, ETH_ALEN) == 0) {
+	if (memcmp(orig_addr, sdata->dev->dev_addr, ETH_ALEN) == 0) {
 		/* This MP is the originator, we are not interested in this
 		 * frame, except for updating transmitter's path info.
 		 */
 		process = false;
 		fresh_info = false;
 	} else {
-		mpath = mesh_path_lookup(orig_addr, dev);
+		mpath = mesh_path_lookup(orig_addr, sdata);
 		if (mpath) {
 			spin_lock_bh(&mpath->state_lock);
 			if (mpath->flags & MESH_PATH_FIXED)
@@ -324,8 +324,8 @@
 				}
 			}
 		} else {
-			mesh_path_add(orig_addr, dev);
-			mpath = mesh_path_lookup(orig_addr, dev);
+			mesh_path_add(orig_addr, sdata);
+			mpath = mesh_path_lookup(orig_addr, sdata);
 			if (!mpath) {
 				rcu_read_unlock();
 				return 0;
@@ -357,7 +357,7 @@
 	else {
 		fresh_info = true;
 
-		mpath = mesh_path_lookup(ta, dev);
+		mpath = mesh_path_lookup(ta, sdata);
 		if (mpath) {
 			spin_lock_bh(&mpath->state_lock);
 			if ((mpath->flags & MESH_PATH_FIXED) ||
@@ -365,8 +365,8 @@
 					(last_hop_metric > mpath->metric)))
 				fresh_info = false;
 		} else {
-			mesh_path_add(ta, dev);
-			mpath = mesh_path_lookup(ta, dev);
+			mesh_path_add(ta, sdata);
+			mpath = mesh_path_lookup(ta, sdata);
 			if (!mpath) {
 				rcu_read_unlock();
 				return 0;
@@ -392,11 +392,10 @@
 	return process ? new_metric : 0;
 }
 
-static void hwmp_preq_frame_process(struct net_device *dev,
+static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata,
 				    struct ieee80211_mgmt *mgmt,
 				    u8 *preq_elem, u32 metric) {
-	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-	struct ieee80211_if_sta *ifsta = &sdata->u.sta;
+	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
 	struct mesh_path *mpath;
 	u8 *dst_addr, *orig_addr;
 	u8 dst_flags, ttl;
@@ -411,19 +410,19 @@
 	orig_dsn = PREQ_IE_ORIG_DSN(preq_elem);
 	dst_flags = PREQ_IE_DST_F(preq_elem);
 
-	if (memcmp(dst_addr, dev->dev_addr, ETH_ALEN) == 0) {
+	if (memcmp(dst_addr, sdata->dev->dev_addr, ETH_ALEN) == 0) {
 		forward = false;
 		reply = true;
 		metric = 0;
-		if (time_after(jiffies, ifsta->last_dsn_update +
+		if (time_after(jiffies, ifmsh->last_dsn_update +
 					net_traversal_jiffies(sdata)) ||
-		    time_before(jiffies, ifsta->last_dsn_update)) {
-			dst_dsn = ++ifsta->dsn;
-			ifsta->last_dsn_update = jiffies;
+		    time_before(jiffies, ifmsh->last_dsn_update)) {
+			dst_dsn = ++ifmsh->dsn;
+			ifmsh->last_dsn_update = jiffies;
 		}
 	} else {
 		rcu_read_lock();
-		mpath = mesh_path_lookup(dst_addr, dev);
+		mpath = mesh_path_lookup(dst_addr, sdata);
 		if (mpath) {
 			if ((!(mpath->flags & MESH_PATH_DSN_VALID)) ||
 					DSN_LT(mpath->dsn, dst_dsn)) {
@@ -445,15 +444,15 @@
 
 	if (reply) {
 		lifetime = PREQ_IE_LIFETIME(preq_elem);
-		ttl = ifsta->mshcfg.dot11MeshTTL;
+		ttl = ifmsh->mshcfg.dot11MeshTTL;
 		if (ttl != 0)
 			mesh_path_sel_frame_tx(MPATH_PREP, 0, dst_addr,
 				cpu_to_le32(dst_dsn), 0, orig_addr,
 				cpu_to_le32(orig_dsn), mgmt->sa, 0, ttl,
 				cpu_to_le32(lifetime), cpu_to_le32(metric),
-				0, dev);
+				0, sdata);
 		else
-			ifsta->mshstats.dropped_frames_ttl++;
+			ifmsh->mshstats.dropped_frames_ttl++;
 	}
 
 	if (forward) {
@@ -463,7 +462,7 @@
 		ttl = PREQ_IE_TTL(preq_elem);
 		lifetime = PREQ_IE_LIFETIME(preq_elem);
 		if (ttl <= 1) {
-			ifsta->mshstats.dropped_frames_ttl++;
+			ifmsh->mshstats.dropped_frames_ttl++;
 			return;
 		}
 		--ttl;
@@ -472,20 +471,19 @@
 		hopcount = PREQ_IE_HOPCOUNT(preq_elem) + 1;
 		mesh_path_sel_frame_tx(MPATH_PREQ, flags, orig_addr,
 				cpu_to_le32(orig_dsn), dst_flags, dst_addr,
-				cpu_to_le32(dst_dsn), dev->broadcast,
+				cpu_to_le32(dst_dsn), sdata->dev->broadcast,
 				hopcount, ttl, cpu_to_le32(lifetime),
 				cpu_to_le32(metric), cpu_to_le32(preq_id),
-				dev);
-		ifsta->mshstats.fwded_frames++;
+				sdata);
+		ifmsh->mshstats.fwded_frames++;
 	}
 }
 
 
-static void hwmp_prep_frame_process(struct net_device *dev,
+static void hwmp_prep_frame_process(struct ieee80211_sub_if_data *sdata,
 				    struct ieee80211_mgmt *mgmt,
 				    u8 *prep_elem, u32 metric)
 {
-	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 	struct mesh_path *mpath;
 	u8 *dst_addr, *orig_addr;
 	u8 ttl, hopcount, flags;
@@ -499,18 +497,18 @@
 	 * replies
 	 */
 	dst_addr = PREP_IE_DST_ADDR(prep_elem);
-	if (memcmp(dst_addr, dev->dev_addr, ETH_ALEN) == 0)
+	if (memcmp(dst_addr, sdata->dev->dev_addr, ETH_ALEN) == 0)
 		/* destination, no forwarding required */
 		return;
 
 	ttl = PREP_IE_TTL(prep_elem);
 	if (ttl <= 1) {
-		sdata->u.sta.mshstats.dropped_frames_ttl++;
+		sdata->u.mesh.mshstats.dropped_frames_ttl++;
 		return;
 	}
 
 	rcu_read_lock();
-	mpath = mesh_path_lookup(dst_addr, dev);
+	mpath = mesh_path_lookup(dst_addr, sdata);
 	if (mpath)
 		spin_lock_bh(&mpath->state_lock);
 	else
@@ -519,7 +517,7 @@
 		spin_unlock_bh(&mpath->state_lock);
 		goto fail;
 	}
-	memcpy(next_hop, mpath->next_hop->addr, ETH_ALEN);
+	memcpy(next_hop, mpath->next_hop->sta.addr, ETH_ALEN);
 	spin_unlock_bh(&mpath->state_lock);
 	--ttl;
 	flags = PREP_IE_FLAGS(prep_elem);
@@ -531,20 +529,20 @@
 
 	mesh_path_sel_frame_tx(MPATH_PREP, flags, orig_addr,
 		cpu_to_le32(orig_dsn), 0, dst_addr,
-		cpu_to_le32(dst_dsn), mpath->next_hop->addr, hopcount, ttl,
+		cpu_to_le32(dst_dsn), mpath->next_hop->sta.addr, hopcount, ttl,
 		cpu_to_le32(lifetime), cpu_to_le32(metric),
-		0, dev);
+		0, sdata);
 	rcu_read_unlock();
-	sdata->u.sta.mshstats.fwded_frames++;
+	sdata->u.mesh.mshstats.fwded_frames++;
 	return;
 
 fail:
 	rcu_read_unlock();
-	sdata->u.sta.mshstats.dropped_frames_no_route++;
+	sdata->u.mesh.mshstats.dropped_frames_no_route++;
 	return;
 }
 
-static void hwmp_perr_frame_process(struct net_device *dev,
+static void hwmp_perr_frame_process(struct ieee80211_sub_if_data *sdata,
 			     struct ieee80211_mgmt *mgmt, u8 *perr_elem)
 {
 	struct mesh_path *mpath;
@@ -555,18 +553,18 @@
 	dst_addr = PERR_IE_DST_ADDR(perr_elem);
 	dst_dsn = PERR_IE_DST_DSN(perr_elem);
 	rcu_read_lock();
-	mpath = mesh_path_lookup(dst_addr, dev);
+	mpath = mesh_path_lookup(dst_addr, sdata);
 	if (mpath) {
 		spin_lock_bh(&mpath->state_lock);
 		if (mpath->flags & MESH_PATH_ACTIVE &&
-		    memcmp(ta, mpath->next_hop->addr, ETH_ALEN) == 0 &&
+		    memcmp(ta, mpath->next_hop->sta.addr, ETH_ALEN) == 0 &&
 		    (!(mpath->flags & MESH_PATH_DSN_VALID) ||
 		    DSN_GT(dst_dsn, mpath->dsn))) {
 			mpath->flags &= ~MESH_PATH_ACTIVE;
 			mpath->dsn = dst_dsn;
 			spin_unlock_bh(&mpath->state_lock);
 			mesh_path_error_tx(dst_addr, cpu_to_le32(dst_dsn),
-					   dev->broadcast, dev);
+					   sdata->dev->broadcast, sdata);
 		} else
 			spin_unlock_bh(&mpath->state_lock);
 	}
@@ -575,7 +573,7 @@
 
 
 
-void mesh_rx_path_sel_frame(struct net_device *dev,
+void mesh_rx_path_sel_frame(struct ieee80211_sub_if_data *sdata,
 			    struct ieee80211_mgmt *mgmt,
 			    size_t len)
 {
@@ -583,6 +581,10 @@
 	size_t baselen;
 	u32 last_hop_metric;
 
+	/* need action_code */
+	if (len < IEEE80211_MIN_ACTION_SIZE + 1)
+		return;
+
 	baselen = (u8 *) mgmt->u.action.u.mesh_action.variable - (u8 *) mgmt;
 	ieee802_11_parse_elems(mgmt->u.action.u.mesh_action.variable,
 			len - baselen, &elems);
@@ -592,25 +594,25 @@
 		if (!elems.preq || elems.preq_len != 37)
 			/* Right now we support just 1 destination and no AE */
 			return;
-		last_hop_metric = hwmp_route_info_get(dev, mgmt, elems.preq);
+		last_hop_metric = hwmp_route_info_get(sdata, mgmt, elems.preq);
 		if (!last_hop_metric)
 			return;
-		hwmp_preq_frame_process(dev, mgmt, elems.preq, last_hop_metric);
+		hwmp_preq_frame_process(sdata, mgmt, elems.preq, last_hop_metric);
 		break;
 	case MPATH_PREP:
 		if (!elems.prep || elems.prep_len != 31)
 			/* Right now we support no AE */
 			return;
-		last_hop_metric = hwmp_route_info_get(dev, mgmt, elems.prep);
+		last_hop_metric = hwmp_route_info_get(sdata, mgmt, elems.prep);
 		if (!last_hop_metric)
 			return;
-		hwmp_prep_frame_process(dev, mgmt, elems.prep, last_hop_metric);
+		hwmp_prep_frame_process(sdata, mgmt, elems.prep, last_hop_metric);
 		break;
 	case MPATH_PERR:
 		if (!elems.perr || elems.perr_len != 12)
 			/* Right now we support only one destination per PERR */
 			return;
-		hwmp_perr_frame_process(dev, mgmt, elems.perr);
+		hwmp_perr_frame_process(sdata, mgmt, elems.perr);
 	default:
 		return;
 	}
@@ -628,9 +630,8 @@
  */
 static void mesh_queue_preq(struct mesh_path *mpath, u8 flags)
 {
-	struct ieee80211_sub_if_data *sdata =
-		IEEE80211_DEV_TO_SUB_IF(mpath->dev);
-	struct ieee80211_if_sta *ifsta = &sdata->u.sta;
+	struct ieee80211_sub_if_data *sdata = mpath->sdata;
+	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
 	struct mesh_preq_queue *preq_node;
 
 	preq_node = kmalloc(sizeof(struct mesh_preq_queue), GFP_KERNEL);
@@ -639,9 +640,9 @@
 		return;
 	}
 
-	spin_lock(&ifsta->mesh_preq_queue_lock);
-	if (ifsta->preq_queue_len == MAX_PREQ_QUEUE_LEN) {
-		spin_unlock(&ifsta->mesh_preq_queue_lock);
+	spin_lock(&ifmsh->mesh_preq_queue_lock);
+	if (ifmsh->preq_queue_len == MAX_PREQ_QUEUE_LEN) {
+		spin_unlock(&ifmsh->mesh_preq_queue_lock);
 		kfree(preq_node);
 		if (printk_ratelimit())
 			printk(KERN_DEBUG "Mesh HWMP: PREQ node queue full\n");
@@ -651,55 +652,53 @@
 	memcpy(preq_node->dst, mpath->dst, ETH_ALEN);
 	preq_node->flags = flags;
 
-	list_add_tail(&preq_node->list, &ifsta->preq_queue.list);
-	++ifsta->preq_queue_len;
-	spin_unlock(&ifsta->mesh_preq_queue_lock);
+	list_add_tail(&preq_node->list, &ifmsh->preq_queue.list);
+	++ifmsh->preq_queue_len;
+	spin_unlock(&ifmsh->mesh_preq_queue_lock);
 
-	if (time_after(jiffies, ifsta->last_preq + min_preq_int_jiff(sdata)))
-		queue_work(sdata->local->hw.workqueue, &ifsta->work);
+	if (time_after(jiffies, ifmsh->last_preq + min_preq_int_jiff(sdata)))
+		queue_work(sdata->local->hw.workqueue, &ifmsh->work);
 
-	else if (time_before(jiffies, ifsta->last_preq)) {
+	else if (time_before(jiffies, ifmsh->last_preq)) {
 		/* avoid long wait if did not send preqs for a long time
 		 * and jiffies wrapped around
 		 */
-		ifsta->last_preq = jiffies - min_preq_int_jiff(sdata) - 1;
-		queue_work(sdata->local->hw.workqueue, &ifsta->work);
+		ifmsh->last_preq = jiffies - min_preq_int_jiff(sdata) - 1;
+		queue_work(sdata->local->hw.workqueue, &ifmsh->work);
 	} else
-		mod_timer(&ifsta->mesh_path_timer, ifsta->last_preq +
+		mod_timer(&ifmsh->mesh_path_timer, ifmsh->last_preq +
 						min_preq_int_jiff(sdata));
 }
 
 /**
  * mesh_path_start_discovery - launch a path discovery from the PREQ queue
  *
- * @dev: local mesh interface
+ * @sdata: local mesh subif
  */
-void mesh_path_start_discovery(struct net_device *dev)
+void mesh_path_start_discovery(struct ieee80211_sub_if_data *sdata)
 {
-	struct ieee80211_sub_if_data *sdata =
-		IEEE80211_DEV_TO_SUB_IF(dev);
-	struct ieee80211_if_sta *ifsta = &sdata->u.sta;
+	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
 	struct mesh_preq_queue *preq_node;
 	struct mesh_path *mpath;
 	u8 ttl, dst_flags;
 	u32 lifetime;
 
-	spin_lock(&ifsta->mesh_preq_queue_lock);
-	if (!ifsta->preq_queue_len ||
-		time_before(jiffies, ifsta->last_preq +
+	spin_lock(&ifmsh->mesh_preq_queue_lock);
+	if (!ifmsh->preq_queue_len ||
+		time_before(jiffies, ifmsh->last_preq +
 				min_preq_int_jiff(sdata))) {
-		spin_unlock(&ifsta->mesh_preq_queue_lock);
+		spin_unlock(&ifmsh->mesh_preq_queue_lock);
 		return;
 	}
 
-	preq_node = list_first_entry(&ifsta->preq_queue.list,
+	preq_node = list_first_entry(&ifmsh->preq_queue.list,
 			struct mesh_preq_queue, list);
 	list_del(&preq_node->list);
-	--ifsta->preq_queue_len;
-	spin_unlock(&ifsta->mesh_preq_queue_lock);
+	--ifmsh->preq_queue_len;
+	spin_unlock(&ifmsh->mesh_preq_queue_lock);
 
 	rcu_read_lock();
-	mpath = mesh_path_lookup(preq_node->dst, dev);
+	mpath = mesh_path_lookup(preq_node->dst, sdata);
 	if (!mpath)
 		goto enddiscovery;
 
@@ -721,18 +720,18 @@
 		goto enddiscovery;
 	}
 
-	ifsta->last_preq = jiffies;
+	ifmsh->last_preq = jiffies;
 
-	if (time_after(jiffies, ifsta->last_dsn_update +
+	if (time_after(jiffies, ifmsh->last_dsn_update +
 				net_traversal_jiffies(sdata)) ||
-	    time_before(jiffies, ifsta->last_dsn_update)) {
-		++ifsta->dsn;
-		sdata->u.sta.last_dsn_update = jiffies;
+	    time_before(jiffies, ifmsh->last_dsn_update)) {
+		++ifmsh->dsn;
+		sdata->u.mesh.last_dsn_update = jiffies;
 	}
 	lifetime = default_lifetime(sdata);
-	ttl = sdata->u.sta.mshcfg.dot11MeshTTL;
+	ttl = sdata->u.mesh.mshcfg.dot11MeshTTL;
 	if (ttl == 0) {
-		sdata->u.sta.mshstats.dropped_frames_ttl++;
+		sdata->u.mesh.mshstats.dropped_frames_ttl++;
 		spin_unlock_bh(&mpath->state_lock);
 		goto enddiscovery;
 	}
@@ -743,11 +742,11 @@
 		dst_flags = MP_F_RF;
 
 	spin_unlock_bh(&mpath->state_lock);
-	mesh_path_sel_frame_tx(MPATH_PREQ, 0, dev->dev_addr,
-			cpu_to_le32(ifsta->dsn), dst_flags, mpath->dst,
-			cpu_to_le32(mpath->dsn), dev->broadcast, 0,
+	mesh_path_sel_frame_tx(MPATH_PREQ, 0, sdata->dev->dev_addr,
+			cpu_to_le32(ifmsh->dsn), dst_flags, mpath->dst,
+			cpu_to_le32(mpath->dsn), sdata->dev->broadcast, 0,
 			ttl, cpu_to_le32(lifetime), 0,
-			cpu_to_le32(ifsta->preq_id++), dev);
+			cpu_to_le32(ifmsh->preq_id++), sdata);
 	mod_timer(&mpath->timer, jiffies + mpath->discovery_timeout);
 
 enddiscovery:
@@ -759,7 +758,7 @@
  * ieee80211s_lookup_nexthop - put the appropriate next hop on a mesh frame
  *
  * @skb: 802.11 frame to be sent
- * @dev: network device the frame will be sent through
+ * @sdata: network subif the frame will be sent through
  * @fwd_frame: true if this frame was originally from a different host
  *
  * Returns: 0 if the next hop was found. Nonzero otherwise. If no next hop is
@@ -767,9 +766,9 @@
  * sent when the path is resolved. This means the caller must not free the skb
  * in this case.
  */
-int mesh_nexthop_lookup(struct sk_buff *skb, struct net_device *dev)
+int mesh_nexthop_lookup(struct sk_buff *skb,
+			struct ieee80211_sub_if_data *sdata)
 {
-	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 	struct sk_buff *skb_to_free = NULL;
 	struct mesh_path *mpath;
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
@@ -777,14 +776,14 @@
 	int err = 0;
 
 	rcu_read_lock();
-	mpath = mesh_path_lookup(dst_addr, dev);
+	mpath = mesh_path_lookup(dst_addr, sdata);
 
 	if (!mpath) {
-		mesh_path_add(dst_addr, dev);
-		mpath = mesh_path_lookup(dst_addr, dev);
+		mesh_path_add(dst_addr, sdata);
+		mpath = mesh_path_lookup(dst_addr, sdata);
 		if (!mpath) {
 			dev_kfree_skb(skb);
-			sdata->u.sta.mshstats.dropped_frames_no_route++;
+			sdata->u.mesh.mshstats.dropped_frames_no_route++;
 			err = -ENOSPC;
 			goto endlookup;
 		}
@@ -792,14 +791,15 @@
 
 	if (mpath->flags & MESH_PATH_ACTIVE) {
 		if (time_after(jiffies, mpath->exp_time -
-			msecs_to_jiffies(sdata->u.sta.mshcfg.path_refresh_time))
-				&& !memcmp(dev->dev_addr, hdr->addr4, ETH_ALEN)
+			msecs_to_jiffies(sdata->u.mesh.mshcfg.path_refresh_time))
+				&& !memcmp(sdata->dev->dev_addr, hdr->addr4,
+					   ETH_ALEN)
 				&& !(mpath->flags & MESH_PATH_RESOLVING)
 				&& !(mpath->flags & MESH_PATH_FIXED)) {
 			mesh_queue_preq(mpath,
 					PREQ_Q_F_START | PREQ_Q_F_REFRESH);
 		}
-		memcpy(hdr->addr1, mpath->next_hop->addr,
+		memcpy(hdr->addr1, mpath->next_hop->sta.addr,
 				ETH_ALEN);
 	} else {
 		if (!(mpath->flags & MESH_PATH_RESOLVING)) {
@@ -815,7 +815,7 @@
 
 		skb_queue_tail(&mpath->frame_queue, skb);
 		if (skb_to_free)
-			mesh_path_discard_frame(skb_to_free, dev);
+			mesh_path_discard_frame(skb_to_free, sdata);
 		err = -ENOENT;
 	}
 
@@ -835,7 +835,7 @@
 	if (!mpath)
 		goto endmpathtimer;
 	spin_lock_bh(&mpath->state_lock);
-	sdata = IEEE80211_DEV_TO_SUB_IF(mpath->dev);
+	sdata = mpath->sdata;
 	if (mpath->flags & MESH_PATH_RESOLVED ||
 			(!(mpath->flags & MESH_PATH_RESOLVING)))
 		mpath->flags &= ~(MESH_PATH_RESOLVING | MESH_PATH_RESOLVED);
diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c
index 838ee60..3c72557 100644
--- a/net/mac80211/mesh_pathtbl.c
+++ b/net/mac80211/mesh_pathtbl.c
@@ -9,7 +9,6 @@
 
 #include <linux/etherdevice.h>
 #include <linux/list.h>
-#include <linux/netdevice.h>
 #include <linux/random.h>
 #include <linux/spinlock.h>
 #include <linux/string.h>
@@ -37,6 +36,7 @@
 };
 
 static struct mesh_table *mesh_paths;
+static struct mesh_table *mpp_paths; /* Store paths for MPP&MAP */
 
 /* This lock will have the grow table function as writer and add / delete nodes
  * as readers. When reading the table (i.e. doing lookups) we are well protected
@@ -62,13 +62,13 @@
 /**
  * mesh_path_lookup - look up a path in the mesh path table
  * @dst: hardware address (ETH_ALEN length) of destination
- * @dev: local interface
+ * @sdata: local subif
  *
  * Returns: pointer to the mesh path structure, or NULL if not found
  *
  * Locking: must be called within a read rcu section.
  */
-struct mesh_path *mesh_path_lookup(u8 *dst, struct net_device *dev)
+struct mesh_path *mesh_path_lookup(u8 *dst, struct ieee80211_sub_if_data *sdata)
 {
 	struct mesh_path *mpath;
 	struct hlist_node *n;
@@ -78,10 +78,10 @@
 
 	tbl = rcu_dereference(mesh_paths);
 
-	bucket = &tbl->hash_buckets[mesh_table_hash(dst, dev, tbl)];
+	bucket = &tbl->hash_buckets[mesh_table_hash(dst, sdata, tbl)];
 	hlist_for_each_entry_rcu(node, n, bucket, list) {
 		mpath = node->mpath;
-		if (mpath->dev == dev &&
+		if (mpath->sdata == sdata &&
 				memcmp(dst, mpath->dst, ETH_ALEN) == 0) {
 			if (MPATH_EXPIRED(mpath)) {
 				spin_lock_bh(&mpath->state_lock);
@@ -95,16 +95,44 @@
 	return NULL;
 }
 
+struct mesh_path *mpp_path_lookup(u8 *dst, struct ieee80211_sub_if_data *sdata)
+{
+	struct mesh_path *mpath;
+	struct hlist_node *n;
+	struct hlist_head *bucket;
+	struct mesh_table *tbl;
+	struct mpath_node *node;
+
+	tbl = rcu_dereference(mpp_paths);
+
+	bucket = &tbl->hash_buckets[mesh_table_hash(dst, sdata, tbl)];
+	hlist_for_each_entry_rcu(node, n, bucket, list) {
+		mpath = node->mpath;
+		if (mpath->sdata == sdata &&
+		    memcmp(dst, mpath->dst, ETH_ALEN) == 0) {
+			if (MPATH_EXPIRED(mpath)) {
+				spin_lock_bh(&mpath->state_lock);
+				if (MPATH_EXPIRED(mpath))
+					mpath->flags &= ~MESH_PATH_ACTIVE;
+				spin_unlock_bh(&mpath->state_lock);
+			}
+			return mpath;
+		}
+	}
+	return NULL;
+}
+
+
 /**
  * mesh_path_lookup_by_idx - look up a path in the mesh path table by its index
  * @idx: index
- * @dev: local interface, or NULL for all entries
+ * @sdata: local subif, or NULL for all entries
  *
  * Returns: pointer to the mesh path structure, or NULL if not found.
  *
  * Locking: must be called within a read rcu section.
  */
-struct mesh_path *mesh_path_lookup_by_idx(int idx, struct net_device *dev)
+struct mesh_path *mesh_path_lookup_by_idx(int idx, struct ieee80211_sub_if_data *sdata)
 {
 	struct mpath_node *node;
 	struct hlist_node *p;
@@ -112,7 +140,7 @@
 	int j = 0;
 
 	for_each_mesh_entry(mesh_paths, p, node, i) {
-		if (dev && node->mpath->dev != dev)
+		if (sdata && node->mpath->sdata != sdata)
 			continue;
 		if (j++ == idx) {
 			if (MPATH_EXPIRED(node->mpath)) {
@@ -131,15 +159,14 @@
 /**
  * mesh_path_add - allocate and add a new path to the mesh path table
  * @addr: destination address of the path (ETH_ALEN length)
- * @dev: local interface
+ * @sdata: local subif
  *
  * Returns: 0 on sucess
  *
  * State: the initial state of the new path is set to 0
  */
-int mesh_path_add(u8 *dst, struct net_device *dev)
+int mesh_path_add(u8 *dst, struct ieee80211_sub_if_data *sdata)
 {
-	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 	struct mesh_path *mpath, *new_mpath;
 	struct mpath_node *node, *new_node;
 	struct hlist_head *bucket;
@@ -148,14 +175,14 @@
 	int err = 0;
 	u32 hash_idx;
 
-	if (memcmp(dst, dev->dev_addr, ETH_ALEN) == 0)
+	if (memcmp(dst, sdata->dev->dev_addr, ETH_ALEN) == 0)
 		/* never add ourselves as neighbours */
 		return -ENOTSUPP;
 
 	if (is_multicast_ether_addr(dst))
 		return -ENOTSUPP;
 
-	if (atomic_add_unless(&sdata->u.sta.mpaths, 1, MESH_MAX_MPATHS) == 0)
+	if (atomic_add_unless(&sdata->u.mesh.mpaths, 1, MESH_MAX_MPATHS) == 0)
 		return -ENOSPC;
 
 	err = -ENOMEM;
@@ -169,7 +196,7 @@
 
 	read_lock(&pathtbl_resize_lock);
 	memcpy(new_mpath->dst, dst, ETH_ALEN);
-	new_mpath->dev = dev;
+	new_mpath->sdata = sdata;
 	new_mpath->flags = 0;
 	skb_queue_head_init(&new_mpath->frame_queue);
 	new_node->mpath = new_mpath;
@@ -179,7 +206,7 @@
 	spin_lock_init(&new_mpath->state_lock);
 	init_timer(&new_mpath->timer);
 
-	hash_idx = mesh_table_hash(dst, dev, mesh_paths);
+	hash_idx = mesh_table_hash(dst, sdata, mesh_paths);
 	bucket = &mesh_paths->hash_buckets[hash_idx];
 
 	spin_lock(&mesh_paths->hashwlock[hash_idx]);
@@ -187,7 +214,7 @@
 	err = -EEXIST;
 	hlist_for_each_entry(node, n, bucket, list) {
 		mpath = node->mpath;
-		if (mpath->dev == dev && memcmp(dst, mpath->dst, ETH_ALEN) == 0)
+		if (mpath->sdata == sdata && memcmp(dst, mpath->dst, ETH_ALEN) == 0)
 			goto err_exists;
 	}
 
@@ -223,7 +250,92 @@
 err_node_alloc:
 	kfree(new_mpath);
 err_path_alloc:
-	atomic_dec(&sdata->u.sta.mpaths);
+	atomic_dec(&sdata->u.mesh.mpaths);
+	return err;
+}
+
+
+int mpp_path_add(u8 *dst, u8 *mpp, struct ieee80211_sub_if_data *sdata)
+{
+	struct mesh_path *mpath, *new_mpath;
+	struct mpath_node *node, *new_node;
+	struct hlist_head *bucket;
+	struct hlist_node *n;
+	int grow = 0;
+	int err = 0;
+	u32 hash_idx;
+
+
+	if (memcmp(dst, sdata->dev->dev_addr, ETH_ALEN) == 0)
+		/* never add ourselves as neighbours */
+		return -ENOTSUPP;
+
+	if (is_multicast_ether_addr(dst))
+		return -ENOTSUPP;
+
+	err = -ENOMEM;
+	new_mpath = kzalloc(sizeof(struct mesh_path), GFP_KERNEL);
+	if (!new_mpath)
+		goto err_path_alloc;
+
+	new_node = kmalloc(sizeof(struct mpath_node), GFP_KERNEL);
+	if (!new_node)
+		goto err_node_alloc;
+
+	read_lock(&pathtbl_resize_lock);
+	memcpy(new_mpath->dst, dst, ETH_ALEN);
+	memcpy(new_mpath->mpp, mpp, ETH_ALEN);
+	new_mpath->sdata = sdata;
+	new_mpath->flags = 0;
+	skb_queue_head_init(&new_mpath->frame_queue);
+	new_node->mpath = new_mpath;
+	new_mpath->exp_time = jiffies;
+	spin_lock_init(&new_mpath->state_lock);
+
+	hash_idx = mesh_table_hash(dst, sdata, mpp_paths);
+	bucket = &mpp_paths->hash_buckets[hash_idx];
+
+	spin_lock(&mpp_paths->hashwlock[hash_idx]);
+
+	err = -EEXIST;
+	hlist_for_each_entry(node, n, bucket, list) {
+		mpath = node->mpath;
+		if (mpath->sdata == sdata && memcmp(dst, mpath->dst, ETH_ALEN) == 0)
+			goto err_exists;
+	}
+
+	hlist_add_head_rcu(&new_node->list, bucket);
+	if (atomic_inc_return(&mpp_paths->entries) >=
+		mpp_paths->mean_chain_len * (mpp_paths->hash_mask + 1))
+		grow = 1;
+
+	spin_unlock(&mpp_paths->hashwlock[hash_idx]);
+	read_unlock(&pathtbl_resize_lock);
+	if (grow) {
+		struct mesh_table *oldtbl, *newtbl;
+
+		write_lock(&pathtbl_resize_lock);
+		oldtbl = mpp_paths;
+		newtbl = mesh_table_grow(mpp_paths);
+		if (!newtbl) {
+			write_unlock(&pathtbl_resize_lock);
+			return 0;
+		}
+		rcu_assign_pointer(mpp_paths, newtbl);
+		write_unlock(&pathtbl_resize_lock);
+
+		synchronize_rcu();
+		mesh_table_free(oldtbl, false);
+	}
+	return 0;
+
+err_exists:
+	spin_unlock(&mpp_paths->hashwlock[hash_idx]);
+	read_unlock(&pathtbl_resize_lock);
+	kfree(new_node);
+err_node_alloc:
+	kfree(new_mpath);
+err_path_alloc:
 	return err;
 }
 
@@ -241,7 +353,7 @@
 	struct mesh_path *mpath;
 	struct mpath_node *node;
 	struct hlist_node *p;
-	struct net_device *dev = sta->sdata->dev;
+	struct ieee80211_sub_if_data *sdata = sta->sdata;
 	int i;
 
 	rcu_read_lock();
@@ -256,7 +368,7 @@
 			spin_unlock_bh(&mpath->state_lock);
 			mesh_path_error_tx(mpath->dst,
 					cpu_to_le32(mpath->dsn),
-					dev->broadcast, dev);
+					sdata->dev->broadcast, sdata);
 		} else
 		spin_unlock_bh(&mpath->state_lock);
 	}
@@ -284,11 +396,11 @@
 	for_each_mesh_entry(mesh_paths, p, node, i) {
 		mpath = node->mpath;
 		if (mpath->next_hop == sta)
-			mesh_path_del(mpath->dst, mpath->dev);
+			mesh_path_del(mpath->dst, mpath->sdata);
 	}
 }
 
-void mesh_path_flush(struct net_device *dev)
+void mesh_path_flush(struct ieee80211_sub_if_data *sdata)
 {
 	struct mesh_path *mpath;
 	struct mpath_node *node;
@@ -297,19 +409,18 @@
 
 	for_each_mesh_entry(mesh_paths, p, node, i) {
 		mpath = node->mpath;
-		if (mpath->dev == dev)
-			mesh_path_del(mpath->dst, mpath->dev);
+		if (mpath->sdata == sdata)
+			mesh_path_del(mpath->dst, mpath->sdata);
 	}
 }
 
 static void mesh_path_node_reclaim(struct rcu_head *rp)
 {
 	struct mpath_node *node = container_of(rp, struct mpath_node, rcu);
-	struct ieee80211_sub_if_data *sdata =
-		IEEE80211_DEV_TO_SUB_IF(node->mpath->dev);
+	struct ieee80211_sub_if_data *sdata = node->mpath->sdata;
 
 	del_timer_sync(&node->mpath->timer);
-	atomic_dec(&sdata->u.sta.mpaths);
+	atomic_dec(&sdata->u.mesh.mpaths);
 	kfree(node->mpath);
 	kfree(node);
 }
@@ -318,11 +429,11 @@
  * mesh_path_del - delete a mesh path from the table
  *
  * @addr: dst address (ETH_ALEN length)
- * @dev: local interface
+ * @sdata: local subif
  *
  * Returns: 0 if succesful
  */
-int mesh_path_del(u8 *addr, struct net_device *dev)
+int mesh_path_del(u8 *addr, struct ieee80211_sub_if_data *sdata)
 {
 	struct mesh_path *mpath;
 	struct mpath_node *node;
@@ -332,13 +443,13 @@
 	int err = 0;
 
 	read_lock(&pathtbl_resize_lock);
-	hash_idx = mesh_table_hash(addr, dev, mesh_paths);
+	hash_idx = mesh_table_hash(addr, sdata, mesh_paths);
 	bucket = &mesh_paths->hash_buckets[hash_idx];
 
 	spin_lock(&mesh_paths->hashwlock[hash_idx]);
 	hlist_for_each_entry(node, n, bucket, list) {
 		mpath = node->mpath;
-		if (mpath->dev == dev &&
+		if (mpath->sdata == sdata &&
 				memcmp(addr, mpath->dst, ETH_ALEN) == 0) {
 			spin_lock_bh(&mpath->state_lock);
 			mpath->flags |= MESH_PATH_RESOLVING;
@@ -378,33 +489,33 @@
  * mesh_path_discard_frame - discard a frame whose path could not be resolved
  *
  * @skb: frame to discard
- * @dev: network device the frame was to be sent through
+ * @sdata: network subif the frame was to be sent through
  *
  * If the frame was beign forwarded from another MP, a PERR frame will be sent
  * to the precursor.
  *
  * Locking: the function must me called within a rcu_read_lock region
  */
-void mesh_path_discard_frame(struct sk_buff *skb, struct net_device *dev)
+void mesh_path_discard_frame(struct sk_buff *skb,
+			     struct ieee80211_sub_if_data *sdata)
 {
-	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
 	struct mesh_path *mpath;
 	u32 dsn = 0;
 
-	if (memcmp(hdr->addr4, dev->dev_addr, ETH_ALEN) != 0) {
+	if (memcmp(hdr->addr4, sdata->dev->dev_addr, ETH_ALEN) != 0) {
 		u8 *ra, *da;
 
 		da = hdr->addr3;
 		ra = hdr->addr2;
-		mpath = mesh_path_lookup(da, dev);
+		mpath = mesh_path_lookup(da, sdata);
 		if (mpath)
 			dsn = ++mpath->dsn;
-		mesh_path_error_tx(skb->data, cpu_to_le32(dsn), ra, dev);
+		mesh_path_error_tx(skb->data, cpu_to_le32(dsn), ra, sdata);
 	}
 
 	kfree_skb(skb);
-	sdata->u.sta.mshstats.dropped_frames_no_route++;
+	sdata->u.mesh.mshstats.dropped_frames_no_route++;
 }
 
 /**
@@ -416,14 +527,11 @@
  */
 void mesh_path_flush_pending(struct mesh_path *mpath)
 {
-	struct ieee80211_sub_if_data *sdata;
 	struct sk_buff *skb;
 
-	sdata = IEEE80211_DEV_TO_SUB_IF(mpath->dev);
-
 	while ((skb = skb_dequeue(&mpath->frame_queue)) &&
 			(mpath->flags & MESH_PATH_ACTIVE))
-		mesh_path_discard_frame(skb, mpath->dev);
+		mesh_path_discard_frame(skb, mpath->sdata);
 }
 
 /**
@@ -472,7 +580,7 @@
 	node = hlist_entry(p, struct mpath_node, list);
 	mpath = node->mpath;
 	new_node->mpath = mpath;
-	hash_idx = mesh_table_hash(mpath->dst, mpath->dev, newtbl);
+	hash_idx = mesh_table_hash(mpath->dst, mpath->sdata, newtbl);
 	hlist_add_head(&new_node->list,
 			&newtbl->hash_buckets[hash_idx]);
 	return 0;
@@ -481,15 +589,25 @@
 int mesh_pathtbl_init(void)
 {
 	mesh_paths = mesh_table_alloc(INIT_PATHS_SIZE_ORDER);
+	if (!mesh_paths)
+		return -ENOMEM;
 	mesh_paths->free_node = &mesh_path_node_free;
 	mesh_paths->copy_node = &mesh_path_node_copy;
 	mesh_paths->mean_chain_len = MEAN_CHAIN_LEN;
-	if (!mesh_paths)
+
+	mpp_paths = mesh_table_alloc(INIT_PATHS_SIZE_ORDER);
+	if (!mpp_paths) {
+		mesh_table_free(mesh_paths, true);
 		return -ENOMEM;
+	}
+	mpp_paths->free_node = &mesh_path_node_free;
+	mpp_paths->copy_node = &mesh_path_node_copy;
+	mpp_paths->mean_chain_len = MEAN_CHAIN_LEN;
+
 	return 0;
 }
 
-void mesh_path_expire(struct net_device *dev)
+void mesh_path_expire(struct ieee80211_sub_if_data *sdata)
 {
 	struct mesh_path *mpath;
 	struct mpath_node *node;
@@ -498,7 +616,7 @@
 
 	read_lock(&pathtbl_resize_lock);
 	for_each_mesh_entry(mesh_paths, p, node, i) {
-		if (node->mpath->dev != dev)
+		if (node->mpath->sdata != sdata)
 			continue;
 		mpath = node->mpath;
 		spin_lock_bh(&mpath->state_lock);
@@ -507,7 +625,7 @@
 			time_after(jiffies,
 			 mpath->exp_time + MESH_PATH_EXPIRE)) {
 			spin_unlock_bh(&mpath->state_lock);
-			mesh_path_del(mpath->dst, mpath->dev);
+			mesh_path_del(mpath->dst, mpath->sdata);
 		} else
 			spin_unlock_bh(&mpath->state_lock);
 	}
@@ -517,4 +635,5 @@
 void mesh_pathtbl_unregister(void)
 {
 	mesh_table_free(mesh_paths, true);
+	mesh_table_free(mpp_paths, true);
 }
diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c
index 9efeb1f..faac101 100644
--- a/net/mac80211/mesh_plink.c
+++ b/net/mac80211/mesh_plink.c
@@ -36,11 +36,11 @@
 #define MESH_SECURITY_AUTHENTICATION_IMPOSSIBLE	9
 #define MESH_SECURITY_FAILED_VERIFICATION	10
 
-#define dot11MeshMaxRetries(s) (s->u.sta.mshcfg.dot11MeshMaxRetries)
-#define dot11MeshRetryTimeout(s) (s->u.sta.mshcfg.dot11MeshRetryTimeout)
-#define dot11MeshConfirmTimeout(s) (s->u.sta.mshcfg.dot11MeshConfirmTimeout)
-#define dot11MeshHoldingTimeout(s) (s->u.sta.mshcfg.dot11MeshHoldingTimeout)
-#define dot11MeshMaxPeerLinks(s) (s->u.sta.mshcfg.dot11MeshMaxPeerLinks)
+#define dot11MeshMaxRetries(s) (s->u.mesh.mshcfg.dot11MeshMaxRetries)
+#define dot11MeshRetryTimeout(s) (s->u.mesh.mshcfg.dot11MeshRetryTimeout)
+#define dot11MeshConfirmTimeout(s) (s->u.mesh.mshcfg.dot11MeshConfirmTimeout)
+#define dot11MeshHoldingTimeout(s) (s->u.mesh.mshcfg.dot11MeshHoldingTimeout)
+#define dot11MeshMaxPeerLinks(s) (s->u.mesh.mshcfg.dot11MeshMaxPeerLinks)
 
 enum plink_frame_type {
 	PLINK_OPEN = 0,
@@ -63,14 +63,14 @@
 static inline
 void mesh_plink_inc_estab_count(struct ieee80211_sub_if_data *sdata)
 {
-	atomic_inc(&sdata->u.sta.mshstats.estab_plinks);
+	atomic_inc(&sdata->u.mesh.mshstats.estab_plinks);
 	mesh_accept_plinks_update(sdata);
 }
 
 static inline
 void mesh_plink_dec_estab_count(struct ieee80211_sub_if_data *sdata)
 {
-	atomic_dec(&sdata->u.sta.mshstats.estab_plinks);
+	atomic_dec(&sdata->u.mesh.mshstats.estab_plinks);
 	mesh_accept_plinks_update(sdata);
 }
 
@@ -106,7 +106,7 @@
 		return NULL;
 
 	sta->flags = WLAN_STA_AUTHORIZED;
-	sta->supp_rates[local->hw.conf.channel->band] = rates;
+	sta->sta.supp_rates[local->hw.conf.channel->band] = rates;
 
 	return sta;
 }
@@ -144,10 +144,10 @@
 	spin_unlock_bh(&sta->lock);
 }
 
-static int mesh_plink_frame_tx(struct net_device *dev,
+static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata,
 		enum plink_frame_type action, u8 *da, __le16 llid, __le16 plid,
 		__le16 reason) {
-	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct ieee80211_local *local = sdata->local;
 	struct sk_buff *skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400);
 	struct ieee80211_mgmt *mgmt;
 	bool include_plid = false;
@@ -163,10 +163,10 @@
 	mgmt = (struct ieee80211_mgmt *)
 		skb_put(skb, 25 + sizeof(mgmt->u.action.u.plink_action));
 	memset(mgmt, 0, 25 + sizeof(mgmt->u.action.u.plink_action));
-	mgmt->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT,
-					   IEEE80211_STYPE_ACTION);
+	mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
+					  IEEE80211_STYPE_ACTION);
 	memcpy(mgmt->da, da, ETH_ALEN);
-	memcpy(mgmt->sa, dev->dev_addr, ETH_ALEN);
+	memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
 	/* BSSID is left zeroed, wildcard value */
 	mgmt->u.action.category = PLINK_CATEGORY;
 	mgmt->u.action.u.plink_action.action_code = action;
@@ -180,7 +180,7 @@
 			/* two-byte status code followed by two-byte AID */
 			memset(pos, 0, 4);
 		}
-		mesh_mgmt_ies_add(skb, dev);
+		mesh_mgmt_ies_add(skb, sdata);
 	}
 
 	/* Add Peer Link Management element */
@@ -217,15 +217,14 @@
 		memcpy(pos, &reason, 2);
 	}
 
-	ieee80211_sta_tx(dev, skb, 0);
+	ieee80211_tx_skb(sdata, skb, 0);
 	return 0;
 }
 
-void mesh_neighbour_update(u8 *hw_addr, u64 rates, struct net_device *dev,
+void mesh_neighbour_update(u8 *hw_addr, u64 rates, struct ieee80211_sub_if_data *sdata,
 			   bool peer_accepting_plinks)
 {
-	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct ieee80211_local *local = sdata->local;
 	struct sta_info *sta;
 
 	rcu_read_lock();
@@ -244,10 +243,10 @@
 	}
 
 	sta->last_rx = jiffies;
-	sta->supp_rates[local->hw.conf.channel->band] = rates;
+	sta->sta.supp_rates[local->hw.conf.channel->band] = rates;
 	if (peer_accepting_plinks && sta->plink_state == PLINK_LISTEN &&
-			sdata->u.sta.accepting_plinks &&
-			sdata->u.sta.mshcfg.auto_open_plinks)
+			sdata->u.mesh.accepting_plinks &&
+			sdata->u.mesh.mshcfg.auto_open_plinks)
 		mesh_plink_open(sta);
 
 	rcu_read_unlock();
@@ -257,7 +256,6 @@
 {
 	struct sta_info *sta;
 	__le16 llid, plid, reason;
-	struct net_device *dev = NULL;
 	struct ieee80211_sub_if_data *sdata;
 #ifdef CONFIG_MAC80211_VERBOSE_MPL_DEBUG
 	DECLARE_MAC_BUF(mac);
@@ -277,12 +275,11 @@
 		return;
 	}
 	mpl_dbg("Mesh plink timer for %s fired on state %d\n",
-			print_mac(mac, sta->addr), sta->plink_state);
+			print_mac(mac, sta->sta.addr), sta->plink_state);
 	reason = 0;
 	llid = sta->llid;
 	plid = sta->plid;
 	sdata = sta->sdata;
-	dev = sdata->dev;
 
 	switch (sta->plink_state) {
 	case PLINK_OPN_RCVD:
@@ -291,7 +288,7 @@
 		if (sta->plink_retries < dot11MeshMaxRetries(sdata)) {
 			u32 rand;
 			mpl_dbg("Mesh plink for %s (retry, timeout): %d %d\n",
-					print_mac(mac, sta->addr),
+					print_mac(mac, sta->sta.addr),
 					sta->plink_retries, sta->plink_timeout);
 			get_random_bytes(&rand, sizeof(u32));
 			sta->plink_timeout = sta->plink_timeout +
@@ -299,7 +296,7 @@
 			++sta->plink_retries;
 			mod_plink_timer(sta, sta->plink_timeout);
 			spin_unlock_bh(&sta->lock);
-			mesh_plink_frame_tx(dev, PLINK_OPEN, sta->addr, llid,
+			mesh_plink_frame_tx(sdata, PLINK_OPEN, sta->sta.addr, llid,
 					    0, 0);
 			break;
 		}
@@ -312,7 +309,7 @@
 		sta->plink_state = PLINK_HOLDING;
 		mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata));
 		spin_unlock_bh(&sta->lock);
-		mesh_plink_frame_tx(dev, PLINK_CLOSE, sta->addr, llid, plid,
+		mesh_plink_frame_tx(sdata, PLINK_CLOSE, sta->sta.addr, llid, plid,
 				    reason);
 		break;
 	case PLINK_HOLDING:
@@ -355,10 +352,10 @@
 	mesh_plink_timer_set(sta, dot11MeshRetryTimeout(sdata));
 	spin_unlock_bh(&sta->lock);
 	mpl_dbg("Mesh plink: starting establishment with %s\n",
-		print_mac(mac, sta->addr));
+		print_mac(mac, sta->sta.addr));
 
-	return mesh_plink_frame_tx(sdata->dev, PLINK_OPEN,
-				   sta->addr, llid, 0, 0);
+	return mesh_plink_frame_tx(sdata, PLINK_OPEN,
+				   sta->sta.addr, llid, 0, 0);
 }
 
 void mesh_plink_block(struct sta_info *sta)
@@ -382,7 +379,7 @@
 #endif
 
 	mpl_dbg("Mesh plink: closing link with %s\n",
-			print_mac(mac, sta->addr));
+			print_mac(mac, sta->sta.addr));
 	spin_lock_bh(&sta->lock);
 	sta->reason = cpu_to_le16(MESH_LINK_CANCELLED);
 	reason = sta->reason;
@@ -403,15 +400,14 @@
 	llid = sta->llid;
 	plid = sta->plid;
 	spin_unlock_bh(&sta->lock);
-	mesh_plink_frame_tx(sta->sdata->dev, PLINK_CLOSE, sta->addr, llid,
+	mesh_plink_frame_tx(sta->sdata, PLINK_CLOSE, sta->sta.addr, llid,
 			    plid, reason);
 	return 0;
 }
 
-void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt,
+void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_mgmt *mgmt,
 			 size_t len, struct ieee80211_rx_status *rx_status)
 {
-	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 	struct ieee80211_local *local = sdata->local;
 	struct ieee802_11_elems elems;
 	struct sta_info *sta;
@@ -425,6 +421,10 @@
 	DECLARE_MAC_BUF(mac);
 #endif
 
+	/* need action_code, aux */
+	if (len < IEEE80211_MIN_ACTION_SIZE + 3)
+		return;
+
 	if (is_multicast_ether_addr(mgmt->da)) {
 		mpl_dbg("Mesh plink: ignore frame from multicast address");
 		return;
@@ -478,7 +478,7 @@
 
 	/* Now we will figure out the appropriate event... */
 	event = PLINK_UNDEFINED;
-	if (ftype != PLINK_CLOSE && (!mesh_matches_local(&elems, dev))) {
+	if (ftype != PLINK_CLOSE && (!mesh_matches_local(&elems, sdata))) {
 		switch (ftype) {
 		case PLINK_OPEN:
 			event = OPN_RJCT;
@@ -577,9 +577,9 @@
 			sta->llid = llid;
 			mesh_plink_timer_set(sta, dot11MeshRetryTimeout(sdata));
 			spin_unlock_bh(&sta->lock);
-			mesh_plink_frame_tx(dev, PLINK_OPEN, sta->addr, llid,
+			mesh_plink_frame_tx(sdata, PLINK_OPEN, sta->sta.addr, llid,
 					    0, 0);
-			mesh_plink_frame_tx(dev, PLINK_CONFIRM, sta->addr,
+			mesh_plink_frame_tx(sdata, PLINK_CONFIRM, sta->sta.addr,
 					    llid, plid, 0);
 			break;
 		default:
@@ -604,7 +604,7 @@
 
 			llid = sta->llid;
 			spin_unlock_bh(&sta->lock);
-			mesh_plink_frame_tx(dev, PLINK_CLOSE, sta->addr, llid,
+			mesh_plink_frame_tx(sdata, PLINK_CLOSE, sta->sta.addr, llid,
 					    plid, reason);
 			break;
 		case OPN_ACPT:
@@ -613,7 +613,7 @@
 			sta->plid = plid;
 			llid = sta->llid;
 			spin_unlock_bh(&sta->lock);
-			mesh_plink_frame_tx(dev, PLINK_CONFIRM, sta->addr, llid,
+			mesh_plink_frame_tx(sdata, PLINK_CONFIRM, sta->sta.addr, llid,
 					    plid, 0);
 			break;
 		case CNF_ACPT:
@@ -646,13 +646,13 @@
 
 			llid = sta->llid;
 			spin_unlock_bh(&sta->lock);
-			mesh_plink_frame_tx(dev, PLINK_CLOSE, sta->addr, llid,
+			mesh_plink_frame_tx(sdata, PLINK_CLOSE, sta->sta.addr, llid,
 					    plid, reason);
 			break;
 		case OPN_ACPT:
 			llid = sta->llid;
 			spin_unlock_bh(&sta->lock);
-			mesh_plink_frame_tx(dev, PLINK_CONFIRM, sta->addr, llid,
+			mesh_plink_frame_tx(sdata, PLINK_CONFIRM, sta->sta.addr, llid,
 					    plid, 0);
 			break;
 		case CNF_ACPT:
@@ -661,7 +661,7 @@
 			mesh_plink_inc_estab_count(sdata);
 			spin_unlock_bh(&sta->lock);
 			mpl_dbg("Mesh plink with %s ESTABLISHED\n",
-					print_mac(mac, sta->addr));
+					print_mac(mac, sta->sta.addr));
 			break;
 		default:
 			spin_unlock_bh(&sta->lock);
@@ -685,7 +685,7 @@
 
 			llid = sta->llid;
 			spin_unlock_bh(&sta->lock);
-			mesh_plink_frame_tx(dev, PLINK_CLOSE, sta->addr, llid,
+			mesh_plink_frame_tx(sdata, PLINK_CLOSE, sta->sta.addr, llid,
 					    plid, reason);
 			break;
 		case OPN_ACPT:
@@ -694,8 +694,8 @@
 			mesh_plink_inc_estab_count(sdata);
 			spin_unlock_bh(&sta->lock);
 			mpl_dbg("Mesh plink with %s ESTABLISHED\n",
-					print_mac(mac, sta->addr));
-			mesh_plink_frame_tx(dev, PLINK_CONFIRM, sta->addr, llid,
+					print_mac(mac, sta->sta.addr));
+			mesh_plink_frame_tx(sdata, PLINK_CONFIRM, sta->sta.addr, llid,
 					    plid, 0);
 			break;
 		default:
@@ -714,13 +714,13 @@
 			llid = sta->llid;
 			mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata));
 			spin_unlock_bh(&sta->lock);
-			mesh_plink_frame_tx(dev, PLINK_CLOSE, sta->addr, llid,
+			mesh_plink_frame_tx(sdata, PLINK_CLOSE, sta->sta.addr, llid,
 					    plid, reason);
 			break;
 		case OPN_ACPT:
 			llid = sta->llid;
 			spin_unlock_bh(&sta->lock);
-			mesh_plink_frame_tx(dev, PLINK_CONFIRM, sta->addr, llid,
+			mesh_plink_frame_tx(sdata, PLINK_CONFIRM, sta->sta.addr, llid,
 					    plid, 0);
 			break;
 		default:
@@ -743,8 +743,8 @@
 			llid = sta->llid;
 			reason = sta->reason;
 			spin_unlock_bh(&sta->lock);
-			mesh_plink_frame_tx(dev, PLINK_CLOSE, sta->addr, llid,
-					    plid, reason);
+			mesh_plink_frame_tx(sdata, PLINK_CLOSE, sta->sta.addr,
+					    llid, plid, reason);
 			break;
 		default:
 			spin_unlock_bh(&sta->lock);
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 902cac1..49f86fa 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -11,11 +11,6 @@
  * published by the Free Software Foundation.
  */
 
-/* TODO:
- * order BSS list by RSSI(?) ("quality of AP")
- * scan result table filtering (by capability (privacy, IBSS/BSS, WPA/RSN IE,
- *    SSID)
- */
 #include <linux/delay.h>
 #include <linux/if_ether.h>
 #include <linux/skbuff.h>
@@ -26,663 +21,58 @@
 #include <linux/etherdevice.h>
 #include <linux/rtnetlink.h>
 #include <net/iw_handler.h>
-#include <asm/types.h>
-
 #include <net/mac80211.h>
+#include <asm/unaligned.h>
+
 #include "ieee80211_i.h"
 #include "rate.h"
 #include "led.h"
-#include "mesh.h"
 
+#define IEEE80211_ASSOC_SCANS_MAX_TRIES 2
 #define IEEE80211_AUTH_TIMEOUT (HZ / 5)
 #define IEEE80211_AUTH_MAX_TRIES 3
 #define IEEE80211_ASSOC_TIMEOUT (HZ / 5)
 #define IEEE80211_ASSOC_MAX_TRIES 3
 #define IEEE80211_MONITORING_INTERVAL (2 * HZ)
-#define IEEE80211_MESH_HOUSEKEEPING_INTERVAL (60 * HZ)
 #define IEEE80211_PROBE_INTERVAL (60 * HZ)
 #define IEEE80211_RETRY_AUTH_INTERVAL (1 * HZ)
 #define IEEE80211_SCAN_INTERVAL (2 * HZ)
 #define IEEE80211_SCAN_INTERVAL_SLOW (15 * HZ)
 #define IEEE80211_IBSS_JOIN_TIMEOUT (7 * HZ)
 
-#define IEEE80211_PROBE_DELAY (HZ / 33)
-#define IEEE80211_CHANNEL_TIME (HZ / 33)
-#define IEEE80211_PASSIVE_CHANNEL_TIME (HZ / 5)
-#define IEEE80211_SCAN_RESULT_EXPIRE (10 * HZ)
 #define IEEE80211_IBSS_MERGE_INTERVAL (30 * HZ)
 #define IEEE80211_IBSS_INACTIVITY_LIMIT (60 * HZ)
-#define IEEE80211_MESH_PEER_INACTIVITY_LIMIT (1800 * HZ)
 
 #define IEEE80211_IBSS_MAX_STA_ENTRIES 128
 
 
-#define ERP_INFO_USE_PROTECTION BIT(1)
-
-/* mgmt header + 1 byte action code */
-#define IEEE80211_MIN_ACTION_SIZE (24 + 1)
-
-#define IEEE80211_ADDBA_PARAM_POLICY_MASK 0x0002
-#define IEEE80211_ADDBA_PARAM_TID_MASK 0x003C
-#define IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK 0xFFA0
-#define IEEE80211_DELBA_PARAM_TID_MASK 0xF000
-#define IEEE80211_DELBA_PARAM_INITIATOR_MASK 0x0800
-
-/* next values represent the buffer size for A-MPDU frame.
- * According to IEEE802.11n spec size varies from 8K to 64K (in powers of 2) */
-#define IEEE80211_MIN_AMPDU_BUF 0x8
-#define IEEE80211_MAX_AMPDU_BUF 0x40
-
-static void ieee80211_send_probe_req(struct net_device *dev, u8 *dst,
-				     u8 *ssid, size_t ssid_len);
-static struct ieee80211_sta_bss *
-ieee80211_rx_bss_get(struct net_device *dev, u8 *bssid, int freq,
-		     u8 *ssid, u8 ssid_len);
-static void ieee80211_rx_bss_put(struct ieee80211_local *local,
-				 struct ieee80211_sta_bss *bss);
-static int ieee80211_sta_find_ibss(struct net_device *dev,
-				   struct ieee80211_if_sta *ifsta);
-static int ieee80211_sta_wep_configured(struct net_device *dev);
-static int ieee80211_sta_start_scan(struct net_device *dev,
-				    u8 *ssid, size_t ssid_len);
-static int ieee80211_sta_config_auth(struct net_device *dev,
-				     struct ieee80211_if_sta *ifsta);
-static void sta_rx_agg_session_timer_expired(unsigned long data);
-
-
-void ieee802_11_parse_elems(u8 *start, size_t len,
-			    struct ieee802_11_elems *elems)
-{
-	size_t left = len;
-	u8 *pos = start;
-
-	memset(elems, 0, sizeof(*elems));
-
-	while (left >= 2) {
-		u8 id, elen;
-
-		id = *pos++;
-		elen = *pos++;
-		left -= 2;
-
-		if (elen > left)
-			return;
-
-		switch (id) {
-		case WLAN_EID_SSID:
-			elems->ssid = pos;
-			elems->ssid_len = elen;
-			break;
-		case WLAN_EID_SUPP_RATES:
-			elems->supp_rates = pos;
-			elems->supp_rates_len = elen;
-			break;
-		case WLAN_EID_FH_PARAMS:
-			elems->fh_params = pos;
-			elems->fh_params_len = elen;
-			break;
-		case WLAN_EID_DS_PARAMS:
-			elems->ds_params = pos;
-			elems->ds_params_len = elen;
-			break;
-		case WLAN_EID_CF_PARAMS:
-			elems->cf_params = pos;
-			elems->cf_params_len = elen;
-			break;
-		case WLAN_EID_TIM:
-			elems->tim = pos;
-			elems->tim_len = elen;
-			break;
-		case WLAN_EID_IBSS_PARAMS:
-			elems->ibss_params = pos;
-			elems->ibss_params_len = elen;
-			break;
-		case WLAN_EID_CHALLENGE:
-			elems->challenge = pos;
-			elems->challenge_len = elen;
-			break;
-		case WLAN_EID_WPA:
-			if (elen >= 4 && pos[0] == 0x00 && pos[1] == 0x50 &&
-			    pos[2] == 0xf2) {
-				/* Microsoft OUI (00:50:F2) */
-				if (pos[3] == 1) {
-					/* OUI Type 1 - WPA IE */
-					elems->wpa = pos;
-					elems->wpa_len = elen;
-				} else if (elen >= 5 && pos[3] == 2) {
-					if (pos[4] == 0) {
-						elems->wmm_info = pos;
-						elems->wmm_info_len = elen;
-					} else if (pos[4] == 1) {
-						elems->wmm_param = pos;
-						elems->wmm_param_len = elen;
-					}
-				}
-			}
-			break;
-		case WLAN_EID_RSN:
-			elems->rsn = pos;
-			elems->rsn_len = elen;
-			break;
-		case WLAN_EID_ERP_INFO:
-			elems->erp_info = pos;
-			elems->erp_info_len = elen;
-			break;
-		case WLAN_EID_EXT_SUPP_RATES:
-			elems->ext_supp_rates = pos;
-			elems->ext_supp_rates_len = elen;
-			break;
-		case WLAN_EID_HT_CAPABILITY:
-			elems->ht_cap_elem = pos;
-			elems->ht_cap_elem_len = elen;
-			break;
-		case WLAN_EID_HT_EXTRA_INFO:
-			elems->ht_info_elem = pos;
-			elems->ht_info_elem_len = elen;
-			break;
-		case WLAN_EID_MESH_ID:
-			elems->mesh_id = pos;
-			elems->mesh_id_len = elen;
-			break;
-		case WLAN_EID_MESH_CONFIG:
-			elems->mesh_config = pos;
-			elems->mesh_config_len = elen;
-			break;
-		case WLAN_EID_PEER_LINK:
-			elems->peer_link = pos;
-			elems->peer_link_len = elen;
-			break;
-		case WLAN_EID_PREQ:
-			elems->preq = pos;
-			elems->preq_len = elen;
-			break;
-		case WLAN_EID_PREP:
-			elems->prep = pos;
-			elems->prep_len = elen;
-			break;
-		case WLAN_EID_PERR:
-			elems->perr = pos;
-			elems->perr_len = elen;
-			break;
-		case WLAN_EID_CHANNEL_SWITCH:
-			elems->ch_switch_elem = pos;
-			elems->ch_switch_elem_len = elen;
-			break;
-		case WLAN_EID_QUIET:
-			if (!elems->quiet_elem) {
-				elems->quiet_elem = pos;
-				elems->quiet_elem_len = elen;
-			}
-			elems->num_of_quiet_elem++;
-			break;
-		case WLAN_EID_COUNTRY:
-			elems->country_elem = pos;
-			elems->country_elem_len = elen;
-			break;
-		case WLAN_EID_PWR_CONSTRAINT:
-			elems->pwr_constr_elem = pos;
-			elems->pwr_constr_elem_len = elen;
-			break;
-		default:
-			break;
-		}
-
-		left -= elen;
-		pos += elen;
-	}
-}
-
-
+/* utils */
 static int ecw2cw(int ecw)
 {
 	return (1 << ecw) - 1;
 }
 
-
-static void ieee80211_sta_def_wmm_params(struct net_device *dev,
-					 struct ieee80211_sta_bss *bss,
-					 int ibss)
+static u8 *ieee80211_bss_get_ie(struct ieee80211_bss *bss, u8 ie)
 {
-	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-	struct ieee80211_local *local = sdata->local;
-	int i, have_higher_than_11mbit = 0;
+	u8 *end, *pos;
 
+	pos = bss->ies;
+	if (pos == NULL)
+		return NULL;
+	end = pos + bss->ies_len;
 
-	/* cf. IEEE 802.11 9.2.12 */
-	for (i = 0; i < bss->supp_rates_len; i++)
-		if ((bss->supp_rates[i] & 0x7f) * 5 > 110)
-			have_higher_than_11mbit = 1;
-
-	if (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ &&
-	    have_higher_than_11mbit)
-		sdata->flags |= IEEE80211_SDATA_OPERATING_GMODE;
-	else
-		sdata->flags &= ~IEEE80211_SDATA_OPERATING_GMODE;
-
-
-	if (local->ops->conf_tx) {
-		struct ieee80211_tx_queue_params qparam;
-
-		memset(&qparam, 0, sizeof(qparam));
-
-		qparam.aifs = 2;
-
-		if (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ &&
-		    !(sdata->flags & IEEE80211_SDATA_OPERATING_GMODE))
-			qparam.cw_min = 31;
-		else
-			qparam.cw_min = 15;
-
-		qparam.cw_max = 1023;
-		qparam.txop = 0;
-
-		for (i = 0; i < local_to_hw(local)->queues; i++)
-			local->ops->conf_tx(local_to_hw(local), i, &qparam);
-	}
-}
-
-static void ieee80211_sta_wmm_params(struct net_device *dev,
-				     struct ieee80211_if_sta *ifsta,
-				     u8 *wmm_param, size_t wmm_param_len)
-{
-	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-	struct ieee80211_tx_queue_params params;
-	size_t left;
-	int count;
-	u8 *pos;
-
-	if (!(ifsta->flags & IEEE80211_STA_WMM_ENABLED))
-		return;
-
-	if (!wmm_param)
-		return;
-
-	if (wmm_param_len < 8 || wmm_param[5] /* version */ != 1)
-		return;
-	count = wmm_param[6] & 0x0f;
-	if (count == ifsta->wmm_last_param_set)
-		return;
-	ifsta->wmm_last_param_set = count;
-
-	pos = wmm_param + 8;
-	left = wmm_param_len - 8;
-
-	memset(&params, 0, sizeof(params));
-
-	if (!local->ops->conf_tx)
-		return;
-
-	local->wmm_acm = 0;
-	for (; left >= 4; left -= 4, pos += 4) {
-		int aci = (pos[0] >> 5) & 0x03;
-		int acm = (pos[0] >> 4) & 0x01;
-		int queue;
-
-		switch (aci) {
-		case 1:
-			queue = 3;
-			if (acm)
-				local->wmm_acm |= BIT(0) | BIT(3);
+	while (pos + 1 < end) {
+		if (pos + 2 + pos[1] > end)
 			break;
-		case 2:
-			queue = 1;
-			if (acm)
-				local->wmm_acm |= BIT(4) | BIT(5);
-			break;
-		case 3:
-			queue = 0;
-			if (acm)
-				local->wmm_acm |= BIT(6) | BIT(7);
-			break;
-		case 0:
-		default:
-			queue = 2;
-			if (acm)
-				local->wmm_acm |= BIT(1) | BIT(2);
-			break;
-		}
-
-		params.aifs = pos[0] & 0x0f;
-		params.cw_max = ecw2cw((pos[1] & 0xf0) >> 4);
-		params.cw_min = ecw2cw(pos[1] & 0x0f);
-		params.txop = get_unaligned_le16(pos + 2);
-#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
-		printk(KERN_DEBUG "%s: WMM queue=%d aci=%d acm=%d aifs=%d "
-		       "cWmin=%d cWmax=%d txop=%d\n",
-		       dev->name, queue, aci, acm, params.aifs, params.cw_min,
-		       params.cw_max, params.txop);
-#endif
-		/* TODO: handle ACM (block TX, fallback to next lowest allowed
-		 * AC for now) */
-		if (local->ops->conf_tx(local_to_hw(local), queue, &params)) {
-			printk(KERN_DEBUG "%s: failed to set TX queue "
-			       "parameters for queue %d\n", dev->name, queue);
-		}
-	}
-}
-
-static u32 ieee80211_handle_protect_preamb(struct ieee80211_sub_if_data *sdata,
-					   bool use_protection,
-					   bool use_short_preamble)
-{
-	struct ieee80211_bss_conf *bss_conf = &sdata->bss_conf;
-#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
-	struct ieee80211_if_sta *ifsta = &sdata->u.sta;
-	DECLARE_MAC_BUF(mac);
-#endif
-	u32 changed = 0;
-
-	if (use_protection != bss_conf->use_cts_prot) {
-#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
-		if (net_ratelimit()) {
-			printk(KERN_DEBUG "%s: CTS protection %s (BSSID="
-			       "%s)\n",
-			       sdata->dev->name,
-			       use_protection ? "enabled" : "disabled",
-			       print_mac(mac, ifsta->bssid));
-		}
-#endif
-		bss_conf->use_cts_prot = use_protection;
-		changed |= BSS_CHANGED_ERP_CTS_PROT;
+		if (pos[0] == ie)
+			return pos;
+		pos += 2 + pos[1];
 	}
 
-	if (use_short_preamble != bss_conf->use_short_preamble) {
-#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
-		if (net_ratelimit()) {
-			printk(KERN_DEBUG "%s: switched to %s barker preamble"
-			       " (BSSID=%s)\n",
-			       sdata->dev->name,
-			       use_short_preamble ? "short" : "long",
-			       print_mac(mac, ifsta->bssid));
-		}
-#endif
-		bss_conf->use_short_preamble = use_short_preamble;
-		changed |= BSS_CHANGED_ERP_PREAMBLE;
-	}
-
-	return changed;
+	return NULL;
 }
 
-static u32 ieee80211_handle_erp_ie(struct ieee80211_sub_if_data *sdata,
-				   u8 erp_value)
-{
-	bool use_protection = (erp_value & WLAN_ERP_USE_PROTECTION) != 0;
-	bool use_short_preamble = (erp_value & WLAN_ERP_BARKER_PREAMBLE) == 0;
-
-	return ieee80211_handle_protect_preamb(sdata,
-			use_protection, use_short_preamble);
-}
-
-static u32 ieee80211_handle_bss_capability(struct ieee80211_sub_if_data *sdata,
-					   struct ieee80211_sta_bss *bss)
-{
-	u32 changed = 0;
-
-	if (bss->has_erp_value)
-		changed |= ieee80211_handle_erp_ie(sdata, bss->erp_value);
-	else {
-		u16 capab = bss->capability;
-		changed |= ieee80211_handle_protect_preamb(sdata, false,
-				(capab & WLAN_CAPABILITY_SHORT_PREAMBLE) != 0);
-	}
-
-	return changed;
-}
-
-int ieee80211_ht_cap_ie_to_ht_info(struct ieee80211_ht_cap *ht_cap_ie,
-				   struct ieee80211_ht_info *ht_info)
-{
-
-	if (ht_info == NULL)
-		return -EINVAL;
-
-	memset(ht_info, 0, sizeof(*ht_info));
-
-	if (ht_cap_ie) {
-		u8 ampdu_info = ht_cap_ie->ampdu_params_info;
-
-		ht_info->ht_supported = 1;
-		ht_info->cap = le16_to_cpu(ht_cap_ie->cap_info);
-		ht_info->ampdu_factor =
-			ampdu_info & IEEE80211_HT_CAP_AMPDU_FACTOR;
-		ht_info->ampdu_density =
-			(ampdu_info & IEEE80211_HT_CAP_AMPDU_DENSITY) >> 2;
-		memcpy(ht_info->supp_mcs_set, ht_cap_ie->supp_mcs_set, 16);
-	} else
-		ht_info->ht_supported = 0;
-
-	return 0;
-}
-
-int ieee80211_ht_addt_info_ie_to_ht_bss_info(
-			struct ieee80211_ht_addt_info *ht_add_info_ie,
-			struct ieee80211_ht_bss_info *bss_info)
-{
-	if (bss_info == NULL)
-		return -EINVAL;
-
-	memset(bss_info, 0, sizeof(*bss_info));
-
-	if (ht_add_info_ie) {
-		u16 op_mode;
-		op_mode = le16_to_cpu(ht_add_info_ie->operation_mode);
-
-		bss_info->primary_channel = ht_add_info_ie->control_chan;
-		bss_info->bss_cap = ht_add_info_ie->ht_param;
-		bss_info->bss_op_mode = (u8)(op_mode & 0xff);
-	}
-
-	return 0;
-}
-
-static void ieee80211_sta_send_associnfo(struct net_device *dev,
-					 struct ieee80211_if_sta *ifsta)
-{
-	char *buf;
-	size_t len;
-	int i;
-	union iwreq_data wrqu;
-
-	if (!ifsta->assocreq_ies && !ifsta->assocresp_ies)
-		return;
-
-	buf = kmalloc(50 + 2 * (ifsta->assocreq_ies_len +
-				ifsta->assocresp_ies_len), GFP_KERNEL);
-	if (!buf)
-		return;
-
-	len = sprintf(buf, "ASSOCINFO(");
-	if (ifsta->assocreq_ies) {
-		len += sprintf(buf + len, "ReqIEs=");
-		for (i = 0; i < ifsta->assocreq_ies_len; i++) {
-			len += sprintf(buf + len, "%02x",
-				       ifsta->assocreq_ies[i]);
-		}
-	}
-	if (ifsta->assocresp_ies) {
-		if (ifsta->assocreq_ies)
-			len += sprintf(buf + len, " ");
-		len += sprintf(buf + len, "RespIEs=");
-		for (i = 0; i < ifsta->assocresp_ies_len; i++) {
-			len += sprintf(buf + len, "%02x",
-				       ifsta->assocresp_ies[i]);
-		}
-	}
-	len += sprintf(buf + len, ")");
-
-	if (len > IW_CUSTOM_MAX) {
-		len = sprintf(buf, "ASSOCRESPIE=");
-		for (i = 0; i < ifsta->assocresp_ies_len; i++) {
-			len += sprintf(buf + len, "%02x",
-				       ifsta->assocresp_ies[i]);
-		}
-	}
-
-	memset(&wrqu, 0, sizeof(wrqu));
-	wrqu.data.length = len;
-	wireless_send_event(dev, IWEVCUSTOM, &wrqu, buf);
-
-	kfree(buf);
-}
-
-
-static void ieee80211_set_associated(struct net_device *dev,
-				     struct ieee80211_if_sta *ifsta,
-				     bool assoc)
-{
-	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-	struct ieee80211_local *local = sdata->local;
-	struct ieee80211_conf *conf = &local_to_hw(local)->conf;
-	union iwreq_data wrqu;
-	u32 changed = BSS_CHANGED_ASSOC;
-
-	if (assoc) {
-		struct ieee80211_sta_bss *bss;
-
-		ifsta->flags |= IEEE80211_STA_ASSOCIATED;
-
-		if (sdata->vif.type != IEEE80211_IF_TYPE_STA)
-			return;
-
-		bss = ieee80211_rx_bss_get(dev, ifsta->bssid,
-					   conf->channel->center_freq,
-					   ifsta->ssid, ifsta->ssid_len);
-		if (bss) {
-			/* set timing information */
-			sdata->bss_conf.beacon_int = bss->beacon_int;
-			sdata->bss_conf.timestamp = bss->timestamp;
-			sdata->bss_conf.dtim_period = bss->dtim_period;
-
-			changed |= ieee80211_handle_bss_capability(sdata, bss);
-
-			ieee80211_rx_bss_put(local, bss);
-		}
-
-		if (conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) {
-			changed |= BSS_CHANGED_HT;
-			sdata->bss_conf.assoc_ht = 1;
-			sdata->bss_conf.ht_conf = &conf->ht_conf;
-			sdata->bss_conf.ht_bss_conf = &conf->ht_bss_conf;
-		}
-
-		ifsta->flags |= IEEE80211_STA_PREV_BSSID_SET;
-		memcpy(ifsta->prev_bssid, sdata->u.sta.bssid, ETH_ALEN);
-		memcpy(wrqu.ap_addr.sa_data, sdata->u.sta.bssid, ETH_ALEN);
-		ieee80211_sta_send_associnfo(dev, ifsta);
-	} else {
-		netif_carrier_off(dev);
-		ieee80211_sta_tear_down_BA_sessions(dev, ifsta->bssid);
-		ifsta->flags &= ~IEEE80211_STA_ASSOCIATED;
-		changed |= ieee80211_reset_erp_info(dev);
-
-		sdata->bss_conf.assoc_ht = 0;
-		sdata->bss_conf.ht_conf = NULL;
-		sdata->bss_conf.ht_bss_conf = NULL;
-
-		memset(wrqu.ap_addr.sa_data, 0, ETH_ALEN);
-	}
-	ifsta->last_probe = jiffies;
-	ieee80211_led_assoc(local, assoc);
-
-	sdata->bss_conf.assoc = assoc;
-	ieee80211_bss_info_change_notify(sdata, changed);
-
-	if (assoc)
-		netif_carrier_on(dev);
-
-	wrqu.ap_addr.sa_family = ARPHRD_ETHER;
-	wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL);
-}
-
-static void ieee80211_set_disassoc(struct net_device *dev,
-				   struct ieee80211_if_sta *ifsta, int deauth)
-{
-	if (deauth)
-		ifsta->auth_tries = 0;
-	ifsta->assoc_tries = 0;
-	ieee80211_set_associated(dev, ifsta, 0);
-}
-
-void ieee80211_sta_tx(struct net_device *dev, struct sk_buff *skb,
-		      int encrypt)
-{
-	struct ieee80211_sub_if_data *sdata;
-
-	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-	skb->dev = sdata->local->mdev;
-	skb_set_mac_header(skb, 0);
-	skb_set_network_header(skb, 0);
-	skb_set_transport_header(skb, 0);
-
-	skb->iif = sdata->dev->ifindex;
-	skb->do_not_encrypt = !encrypt;
-
-	dev_queue_xmit(skb);
-}
-
-
-static void ieee80211_send_auth(struct net_device *dev,
-				struct ieee80211_if_sta *ifsta,
-				int transaction, u8 *extra, size_t extra_len,
-				int encrypt)
-{
-	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-	struct sk_buff *skb;
-	struct ieee80211_mgmt *mgmt;
-
-	skb = dev_alloc_skb(local->hw.extra_tx_headroom +
-			    sizeof(*mgmt) + 6 + extra_len);
-	if (!skb) {
-		printk(KERN_DEBUG "%s: failed to allocate buffer for auth "
-		       "frame\n", dev->name);
-		return;
-	}
-	skb_reserve(skb, local->hw.extra_tx_headroom);
-
-	mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24 + 6);
-	memset(mgmt, 0, 24 + 6);
-	mgmt->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT,
-					   IEEE80211_STYPE_AUTH);
-	if (encrypt)
-		mgmt->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED);
-	memcpy(mgmt->da, ifsta->bssid, ETH_ALEN);
-	memcpy(mgmt->sa, dev->dev_addr, ETH_ALEN);
-	memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN);
-	mgmt->u.auth.auth_alg = cpu_to_le16(ifsta->auth_alg);
-	mgmt->u.auth.auth_transaction = cpu_to_le16(transaction);
-	ifsta->auth_transaction = transaction + 1;
-	mgmt->u.auth.status_code = cpu_to_le16(0);
-	if (extra)
-		memcpy(skb_put(skb, extra_len), extra, extra_len);
-
-	ieee80211_sta_tx(dev, skb, encrypt);
-}
-
-
-static void ieee80211_authenticate(struct net_device *dev,
-				   struct ieee80211_if_sta *ifsta)
-{
-	DECLARE_MAC_BUF(mac);
-
-	ifsta->auth_tries++;
-	if (ifsta->auth_tries > IEEE80211_AUTH_MAX_TRIES) {
-		printk(KERN_DEBUG "%s: authentication with AP %s"
-		       " timed out\n",
-		       dev->name, print_mac(mac, ifsta->bssid));
-		ifsta->state = IEEE80211_DISABLED;
-		return;
-	}
-
-	ifsta->state = IEEE80211_AUTHENTICATE;
-	printk(KERN_DEBUG "%s: authenticate with AP %s\n",
-	       dev->name, print_mac(mac, ifsta->bssid));
-
-	ieee80211_send_auth(dev, ifsta, 1, NULL, 0, 0);
-
-	mod_timer(&ifsta->timer, jiffies + IEEE80211_AUTH_TIMEOUT);
-}
-
-static int ieee80211_compatible_rates(struct ieee80211_sta_bss *bss,
+static int ieee80211_compatible_rates(struct ieee80211_bss *bss,
 				      struct ieee80211_supported_band *sband,
 				      u64 *rates)
 {
@@ -703,16 +93,153 @@
 	return count;
 }
 
-static void ieee80211_send_assoc(struct net_device *dev,
-				 struct ieee80211_if_sta *ifsta)
+/* also used by mesh code */
+u64 ieee80211_sta_get_rates(struct ieee80211_local *local,
+			    struct ieee802_11_elems *elems,
+			    enum ieee80211_band band)
 {
-	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct ieee80211_supported_band *sband;
+	struct ieee80211_rate *bitrates;
+	size_t num_rates;
+	u64 supp_rates;
+	int i, j;
+	sband = local->hw.wiphy->bands[band];
+
+	if (!sband) {
+		WARN_ON(1);
+		sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
+	}
+
+	bitrates = sband->bitrates;
+	num_rates = sband->n_bitrates;
+	supp_rates = 0;
+	for (i = 0; i < elems->supp_rates_len +
+		     elems->ext_supp_rates_len; i++) {
+		u8 rate = 0;
+		int own_rate;
+		if (i < elems->supp_rates_len)
+			rate = elems->supp_rates[i];
+		else if (elems->ext_supp_rates)
+			rate = elems->ext_supp_rates
+				[i - elems->supp_rates_len];
+		own_rate = 5 * (rate & 0x7f);
+		for (j = 0; j < num_rates; j++)
+			if (bitrates[j].bitrate == own_rate)
+				supp_rates |= BIT(j);
+	}
+	return supp_rates;
+}
+
+/* frame sending functions */
+
+/* also used by scanning code */
+void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst,
+			      u8 *ssid, size_t ssid_len)
+{
+	struct ieee80211_local *local = sdata->local;
+	struct ieee80211_supported_band *sband;
 	struct sk_buff *skb;
 	struct ieee80211_mgmt *mgmt;
-	u8 *pos, *ies;
+	u8 *pos, *supp_rates, *esupp_rates = NULL;
+	int i;
+
+	skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*mgmt) + 200);
+	if (!skb) {
+		printk(KERN_DEBUG "%s: failed to allocate buffer for probe "
+		       "request\n", sdata->dev->name);
+		return;
+	}
+	skb_reserve(skb, local->hw.extra_tx_headroom);
+
+	mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24);
+	memset(mgmt, 0, 24);
+	mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
+					  IEEE80211_STYPE_PROBE_REQ);
+	memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
+	if (dst) {
+		memcpy(mgmt->da, dst, ETH_ALEN);
+		memcpy(mgmt->bssid, dst, ETH_ALEN);
+	} else {
+		memset(mgmt->da, 0xff, ETH_ALEN);
+		memset(mgmt->bssid, 0xff, ETH_ALEN);
+	}
+	pos = skb_put(skb, 2 + ssid_len);
+	*pos++ = WLAN_EID_SSID;
+	*pos++ = ssid_len;
+	memcpy(pos, ssid, ssid_len);
+
+	supp_rates = skb_put(skb, 2);
+	supp_rates[0] = WLAN_EID_SUPP_RATES;
+	supp_rates[1] = 0;
+	sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
+
+	for (i = 0; i < sband->n_bitrates; i++) {
+		struct ieee80211_rate *rate = &sband->bitrates[i];
+		if (esupp_rates) {
+			pos = skb_put(skb, 1);
+			esupp_rates[1]++;
+		} else if (supp_rates[1] == 8) {
+			esupp_rates = skb_put(skb, 3);
+			esupp_rates[0] = WLAN_EID_EXT_SUPP_RATES;
+			esupp_rates[1] = 1;
+			pos = &esupp_rates[2];
+		} else {
+			pos = skb_put(skb, 1);
+			supp_rates[1]++;
+		}
+		*pos = rate->bitrate / 5;
+	}
+
+	ieee80211_tx_skb(sdata, skb, 0);
+}
+
+static void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata,
+				struct ieee80211_if_sta *ifsta,
+				int transaction, u8 *extra, size_t extra_len,
+				int encrypt)
+{
+	struct ieee80211_local *local = sdata->local;
+	struct sk_buff *skb;
+	struct ieee80211_mgmt *mgmt;
+
+	skb = dev_alloc_skb(local->hw.extra_tx_headroom +
+			    sizeof(*mgmt) + 6 + extra_len);
+	if (!skb) {
+		printk(KERN_DEBUG "%s: failed to allocate buffer for auth "
+		       "frame\n", sdata->dev->name);
+		return;
+	}
+	skb_reserve(skb, local->hw.extra_tx_headroom);
+
+	mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24 + 6);
+	memset(mgmt, 0, 24 + 6);
+	mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
+					  IEEE80211_STYPE_AUTH);
+	if (encrypt)
+		mgmt->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED);
+	memcpy(mgmt->da, ifsta->bssid, ETH_ALEN);
+	memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
+	memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN);
+	mgmt->u.auth.auth_alg = cpu_to_le16(ifsta->auth_alg);
+	mgmt->u.auth.auth_transaction = cpu_to_le16(transaction);
+	ifsta->auth_transaction = transaction + 1;
+	mgmt->u.auth.status_code = cpu_to_le16(0);
+	if (extra)
+		memcpy(skb_put(skb, extra_len), extra, extra_len);
+
+	ieee80211_tx_skb(sdata, skb, encrypt);
+}
+
+static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata,
+				 struct ieee80211_if_sta *ifsta)
+{
+	struct ieee80211_local *local = sdata->local;
+	struct sk_buff *skb;
+	struct ieee80211_mgmt *mgmt;
+	u8 *pos, *ies, *ht_add_ie;
 	int i, len, count, rates_len, supp_rates_len;
 	u16 capab;
-	struct ieee80211_sta_bss *bss;
+	struct ieee80211_bss *bss;
 	int wmm = 0;
 	struct ieee80211_supported_band *sband;
 	u64 rates = 0;
@@ -722,7 +249,7 @@
 			    ifsta->ssid_len);
 	if (!skb) {
 		printk(KERN_DEBUG "%s: failed to allocate buffer for assoc "
-		       "frame\n", dev->name);
+		       "frame\n", sdata->dev->name);
 		return;
 	}
 	skb_reserve(skb, local->hw.extra_tx_headroom);
@@ -738,13 +265,13 @@
 			capab |= WLAN_CAPABILITY_SHORT_PREAMBLE;
 	}
 
-	bss = ieee80211_rx_bss_get(dev, ifsta->bssid,
+	bss = ieee80211_rx_bss_get(local, ifsta->bssid,
 				   local->hw.conf.channel->center_freq,
 				   ifsta->ssid, ifsta->ssid_len);
 	if (bss) {
 		if (bss->capability & WLAN_CAPABILITY_PRIVACY)
 			capab |= WLAN_CAPABILITY_PRIVACY;
-		if (bss->wmm_ie)
+		if (bss->wmm_used)
 			wmm = 1;
 
 		/* get all rates supported by the device and the AP as
@@ -766,13 +293,13 @@
 	mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24);
 	memset(mgmt, 0, 24);
 	memcpy(mgmt->da, ifsta->bssid, ETH_ALEN);
-	memcpy(mgmt->sa, dev->dev_addr, ETH_ALEN);
+	memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
 	memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN);
 
 	if (ifsta->flags & IEEE80211_STA_PREV_BSSID_SET) {
 		skb_put(skb, 10);
-		mgmt->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT,
-						   IEEE80211_STYPE_REASSOC_REQ);
+		mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
+						  IEEE80211_STYPE_REASSOC_REQ);
 		mgmt->u.reassoc_req.capab_info = cpu_to_le16(capab);
 		mgmt->u.reassoc_req.listen_interval =
 				cpu_to_le16(local->hw.conf.listen_interval);
@@ -780,8 +307,8 @@
 		       ETH_ALEN);
 	} else {
 		skb_put(skb, 4);
-		mgmt->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT,
-						   IEEE80211_STYPE_ASSOC_REQ);
+		mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
+						  IEEE80211_STYPE_ASSOC_REQ);
 		mgmt->u.assoc_req.capab_info = cpu_to_le16(capab);
 		mgmt->u.reassoc_req.listen_interval =
 				cpu_to_le16(local->hw.conf.listen_interval);
@@ -866,9 +393,10 @@
 
 	/* wmm support is a must to HT */
 	if (wmm && (ifsta->flags & IEEE80211_STA_WMM_ENABLED) &&
-	    sband->ht_info.ht_supported && bss->ht_add_ie) {
+	    sband->ht_info.ht_supported &&
+	    (ht_add_ie = ieee80211_bss_get_ie(bss, WLAN_EID_HT_EXTRA_INFO))) {
 		struct ieee80211_ht_addt_info *ht_add_info =
-			(struct ieee80211_ht_addt_info *)bss->ht_add_ie;
+			(struct ieee80211_ht_addt_info *)ht_add_ie;
 		u16 cap = sband->ht_info.cap;
 		__le16 tmp;
 		u32 flags = local->hw.conf.channel->flags;
@@ -907,21 +435,22 @@
 	if (ifsta->assocreq_ies)
 		memcpy(ifsta->assocreq_ies, ies, ifsta->assocreq_ies_len);
 
-	ieee80211_sta_tx(dev, skb, 0);
+	ieee80211_tx_skb(sdata, skb, 0);
 }
 
 
-static void ieee80211_send_deauth(struct net_device *dev,
-				  struct ieee80211_if_sta *ifsta, u16 reason)
+static void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata,
+					   u16 stype, u16 reason)
 {
-	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct ieee80211_local *local = sdata->local;
+	struct ieee80211_if_sta *ifsta = &sdata->u.sta;
 	struct sk_buff *skb;
 	struct ieee80211_mgmt *mgmt;
 
 	skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*mgmt));
 	if (!skb) {
-		printk(KERN_DEBUG "%s: failed to allocate buffer for deauth "
-		       "frame\n", dev->name);
+		printk(KERN_DEBUG "%s: failed to allocate buffer for "
+		       "deauth/disassoc frame\n", sdata->dev->name);
 		return;
 	}
 	skb_reserve(skb, local->hw.extra_tx_headroom);
@@ -929,51 +458,434 @@
 	mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24);
 	memset(mgmt, 0, 24);
 	memcpy(mgmt->da, ifsta->bssid, ETH_ALEN);
-	memcpy(mgmt->sa, dev->dev_addr, ETH_ALEN);
+	memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
 	memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN);
-	mgmt->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT,
-					   IEEE80211_STYPE_DEAUTH);
+	mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | stype);
 	skb_put(skb, 2);
+	/* u.deauth.reason_code == u.disassoc.reason_code */
 	mgmt->u.deauth.reason_code = cpu_to_le16(reason);
 
-	ieee80211_sta_tx(dev, skb, 0);
+	ieee80211_tx_skb(sdata, skb, 0);
+}
+
+/* MLME */
+static void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata,
+					 struct ieee80211_bss *bss)
+{
+	struct ieee80211_local *local = sdata->local;
+	int i, have_higher_than_11mbit = 0;
+
+	/* cf. IEEE 802.11 9.2.12 */
+	for (i = 0; i < bss->supp_rates_len; i++)
+		if ((bss->supp_rates[i] & 0x7f) * 5 > 110)
+			have_higher_than_11mbit = 1;
+
+	if (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ &&
+	    have_higher_than_11mbit)
+		sdata->flags |= IEEE80211_SDATA_OPERATING_GMODE;
+	else
+		sdata->flags &= ~IEEE80211_SDATA_OPERATING_GMODE;
+
+	ieee80211_set_wmm_default(sdata);
+}
+
+static void ieee80211_sta_wmm_params(struct ieee80211_local *local,
+				     struct ieee80211_if_sta *ifsta,
+				     u8 *wmm_param, size_t wmm_param_len)
+{
+	struct ieee80211_tx_queue_params params;
+	size_t left;
+	int count;
+	u8 *pos;
+
+	if (!(ifsta->flags & IEEE80211_STA_WMM_ENABLED))
+		return;
+
+	if (!wmm_param)
+		return;
+
+	if (wmm_param_len < 8 || wmm_param[5] /* version */ != 1)
+		return;
+	count = wmm_param[6] & 0x0f;
+	if (count == ifsta->wmm_last_param_set)
+		return;
+	ifsta->wmm_last_param_set = count;
+
+	pos = wmm_param + 8;
+	left = wmm_param_len - 8;
+
+	memset(&params, 0, sizeof(params));
+
+	if (!local->ops->conf_tx)
+		return;
+
+	local->wmm_acm = 0;
+	for (; left >= 4; left -= 4, pos += 4) {
+		int aci = (pos[0] >> 5) & 0x03;
+		int acm = (pos[0] >> 4) & 0x01;
+		int queue;
+
+		switch (aci) {
+		case 1:
+			queue = 3;
+			if (acm)
+				local->wmm_acm |= BIT(0) | BIT(3);
+			break;
+		case 2:
+			queue = 1;
+			if (acm)
+				local->wmm_acm |= BIT(4) | BIT(5);
+			break;
+		case 3:
+			queue = 0;
+			if (acm)
+				local->wmm_acm |= BIT(6) | BIT(7);
+			break;
+		case 0:
+		default:
+			queue = 2;
+			if (acm)
+				local->wmm_acm |= BIT(1) | BIT(2);
+			break;
+		}
+
+		params.aifs = pos[0] & 0x0f;
+		params.cw_max = ecw2cw((pos[1] & 0xf0) >> 4);
+		params.cw_min = ecw2cw(pos[1] & 0x0f);
+		params.txop = get_unaligned_le16(pos + 2);
+#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
+		printk(KERN_DEBUG "%s: WMM queue=%d aci=%d acm=%d aifs=%d "
+		       "cWmin=%d cWmax=%d txop=%d\n",
+		       local->mdev->name, queue, aci, acm, params.aifs, params.cw_min,
+		       params.cw_max, params.txop);
+#endif
+		/* TODO: handle ACM (block TX, fallback to next lowest allowed
+		 * AC for now) */
+		if (local->ops->conf_tx(local_to_hw(local), queue, &params)) {
+			printk(KERN_DEBUG "%s: failed to set TX queue "
+			       "parameters for queue %d\n", local->mdev->name, queue);
+		}
+	}
+}
+
+static u32 ieee80211_handle_protect_preamb(struct ieee80211_sub_if_data *sdata,
+					   bool use_protection,
+					   bool use_short_preamble)
+{
+	struct ieee80211_bss_conf *bss_conf = &sdata->bss_conf;
+#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
+	struct ieee80211_if_sta *ifsta = &sdata->u.sta;
+	DECLARE_MAC_BUF(mac);
+#endif
+	u32 changed = 0;
+
+	if (use_protection != bss_conf->use_cts_prot) {
+#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
+		if (net_ratelimit()) {
+			printk(KERN_DEBUG "%s: CTS protection %s (BSSID="
+			       "%s)\n",
+			       sdata->dev->name,
+			       use_protection ? "enabled" : "disabled",
+			       print_mac(mac, ifsta->bssid));
+		}
+#endif
+		bss_conf->use_cts_prot = use_protection;
+		changed |= BSS_CHANGED_ERP_CTS_PROT;
+	}
+
+	if (use_short_preamble != bss_conf->use_short_preamble) {
+#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
+		if (net_ratelimit()) {
+			printk(KERN_DEBUG "%s: switched to %s barker preamble"
+			       " (BSSID=%s)\n",
+			       sdata->dev->name,
+			       use_short_preamble ? "short" : "long",
+			       print_mac(mac, ifsta->bssid));
+		}
+#endif
+		bss_conf->use_short_preamble = use_short_preamble;
+		changed |= BSS_CHANGED_ERP_PREAMBLE;
+	}
+
+	return changed;
+}
+
+static u32 ieee80211_handle_erp_ie(struct ieee80211_sub_if_data *sdata,
+				   u8 erp_value)
+{
+	bool use_protection = (erp_value & WLAN_ERP_USE_PROTECTION) != 0;
+	bool use_short_preamble = (erp_value & WLAN_ERP_BARKER_PREAMBLE) == 0;
+
+	return ieee80211_handle_protect_preamb(sdata,
+			use_protection, use_short_preamble);
+}
+
+static u32 ieee80211_handle_bss_capability(struct ieee80211_sub_if_data *sdata,
+					   struct ieee80211_bss *bss)
+{
+	u32 changed = 0;
+
+	if (bss->has_erp_value)
+		changed |= ieee80211_handle_erp_ie(sdata, bss->erp_value);
+	else {
+		u16 capab = bss->capability;
+		changed |= ieee80211_handle_protect_preamb(sdata, false,
+				(capab & WLAN_CAPABILITY_SHORT_PREAMBLE) != 0);
+	}
+
+	return changed;
+}
+
+static void ieee80211_sta_send_apinfo(struct ieee80211_sub_if_data *sdata,
+					struct ieee80211_if_sta *ifsta)
+{
+	union iwreq_data wrqu;
+	memset(&wrqu, 0, sizeof(wrqu));
+	if (ifsta->flags & IEEE80211_STA_ASSOCIATED)
+		memcpy(wrqu.ap_addr.sa_data, sdata->u.sta.bssid, ETH_ALEN);
+	wrqu.ap_addr.sa_family = ARPHRD_ETHER;
+	wireless_send_event(sdata->dev, SIOCGIWAP, &wrqu, NULL);
+}
+
+static void ieee80211_sta_send_associnfo(struct ieee80211_sub_if_data *sdata,
+					 struct ieee80211_if_sta *ifsta)
+{
+	char *buf;
+	size_t len;
+	int i;
+	union iwreq_data wrqu;
+
+	if (!ifsta->assocreq_ies && !ifsta->assocresp_ies)
+		return;
+
+	buf = kmalloc(50 + 2 * (ifsta->assocreq_ies_len +
+				ifsta->assocresp_ies_len), GFP_KERNEL);
+	if (!buf)
+		return;
+
+	len = sprintf(buf, "ASSOCINFO(");
+	if (ifsta->assocreq_ies) {
+		len += sprintf(buf + len, "ReqIEs=");
+		for (i = 0; i < ifsta->assocreq_ies_len; i++) {
+			len += sprintf(buf + len, "%02x",
+				       ifsta->assocreq_ies[i]);
+		}
+	}
+	if (ifsta->assocresp_ies) {
+		if (ifsta->assocreq_ies)
+			len += sprintf(buf + len, " ");
+		len += sprintf(buf + len, "RespIEs=");
+		for (i = 0; i < ifsta->assocresp_ies_len; i++) {
+			len += sprintf(buf + len, "%02x",
+				       ifsta->assocresp_ies[i]);
+		}
+	}
+	len += sprintf(buf + len, ")");
+
+	if (len > IW_CUSTOM_MAX) {
+		len = sprintf(buf, "ASSOCRESPIE=");
+		for (i = 0; i < ifsta->assocresp_ies_len; i++) {
+			len += sprintf(buf + len, "%02x",
+				       ifsta->assocresp_ies[i]);
+		}
+	}
+
+	if (len <= IW_CUSTOM_MAX) {
+		memset(&wrqu, 0, sizeof(wrqu));
+		wrqu.data.length = len;
+		wireless_send_event(sdata->dev, IWEVCUSTOM, &wrqu, buf);
+	}
+
+	kfree(buf);
 }
 
 
-static void ieee80211_send_disassoc(struct net_device *dev,
-				    struct ieee80211_if_sta *ifsta, u16 reason)
+static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,
+				     struct ieee80211_if_sta *ifsta)
 {
-	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-	struct sk_buff *skb;
-	struct ieee80211_mgmt *mgmt;
+	struct ieee80211_local *local = sdata->local;
+	struct ieee80211_conf *conf = &local_to_hw(local)->conf;
+	u32 changed = BSS_CHANGED_ASSOC;
 
-	skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*mgmt));
-	if (!skb) {
-		printk(KERN_DEBUG "%s: failed to allocate buffer for disassoc "
-		       "frame\n", dev->name);
+	struct ieee80211_bss *bss;
+
+	ifsta->flags |= IEEE80211_STA_ASSOCIATED;
+
+	if (sdata->vif.type != NL80211_IFTYPE_STATION)
+		return;
+
+	bss = ieee80211_rx_bss_get(local, ifsta->bssid,
+				   conf->channel->center_freq,
+				   ifsta->ssid, ifsta->ssid_len);
+	if (bss) {
+		/* set timing information */
+		sdata->bss_conf.beacon_int = bss->beacon_int;
+		sdata->bss_conf.timestamp = bss->timestamp;
+		sdata->bss_conf.dtim_period = bss->dtim_period;
+
+		changed |= ieee80211_handle_bss_capability(sdata, bss);
+
+		ieee80211_rx_bss_put(local, bss);
+	}
+
+	if (conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) {
+		changed |= BSS_CHANGED_HT;
+		sdata->bss_conf.assoc_ht = 1;
+		sdata->bss_conf.ht_conf = &conf->ht_conf;
+		sdata->bss_conf.ht_bss_conf = &conf->ht_bss_conf;
+	}
+
+	ifsta->flags |= IEEE80211_STA_PREV_BSSID_SET;
+	memcpy(ifsta->prev_bssid, sdata->u.sta.bssid, ETH_ALEN);
+	ieee80211_sta_send_associnfo(sdata, ifsta);
+
+	ifsta->last_probe = jiffies;
+	ieee80211_led_assoc(local, 1);
+
+	sdata->bss_conf.assoc = 1;
+	/*
+	 * For now just always ask the driver to update the basic rateset
+	 * when we have associated, we aren't checking whether it actually
+	 * changed or not.
+	 */
+	changed |= BSS_CHANGED_BASIC_RATES;
+	ieee80211_bss_info_change_notify(sdata, changed);
+
+	netif_tx_start_all_queues(sdata->dev);
+	netif_carrier_on(sdata->dev);
+
+	ieee80211_sta_send_apinfo(sdata, ifsta);
+}
+
+static void ieee80211_direct_probe(struct ieee80211_sub_if_data *sdata,
+				   struct ieee80211_if_sta *ifsta)
+{
+	DECLARE_MAC_BUF(mac);
+
+	ifsta->direct_probe_tries++;
+	if (ifsta->direct_probe_tries > IEEE80211_AUTH_MAX_TRIES) {
+		printk(KERN_DEBUG "%s: direct probe to AP %s timed out\n",
+		       sdata->dev->name, print_mac(mac, ifsta->bssid));
+		ifsta->state = IEEE80211_STA_MLME_DISABLED;
 		return;
 	}
-	skb_reserve(skb, local->hw.extra_tx_headroom);
 
-	mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24);
-	memset(mgmt, 0, 24);
-	memcpy(mgmt->da, ifsta->bssid, ETH_ALEN);
-	memcpy(mgmt->sa, dev->dev_addr, ETH_ALEN);
-	memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN);
-	mgmt->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT,
-					   IEEE80211_STYPE_DISASSOC);
-	skb_put(skb, 2);
-	mgmt->u.disassoc.reason_code = cpu_to_le16(reason);
+	printk(KERN_DEBUG "%s: direct probe to AP %s try %d\n",
+			sdata->dev->name, print_mac(mac, ifsta->bssid),
+			ifsta->direct_probe_tries);
 
-	ieee80211_sta_tx(dev, skb, 0);
+	ifsta->state = IEEE80211_STA_MLME_DIRECT_PROBE;
+
+	set_bit(IEEE80211_STA_REQ_DIRECT_PROBE, &ifsta->request);
+
+	/* Direct probe is sent to broadcast address as some APs
+	 * will not answer to direct packet in unassociated state.
+	 */
+	ieee80211_send_probe_req(sdata, NULL,
+				 ifsta->ssid, ifsta->ssid_len);
+
+	mod_timer(&ifsta->timer, jiffies + IEEE80211_AUTH_TIMEOUT);
 }
 
 
-static int ieee80211_privacy_mismatch(struct net_device *dev,
+static void ieee80211_authenticate(struct ieee80211_sub_if_data *sdata,
+				   struct ieee80211_if_sta *ifsta)
+{
+	DECLARE_MAC_BUF(mac);
+
+	ifsta->auth_tries++;
+	if (ifsta->auth_tries > IEEE80211_AUTH_MAX_TRIES) {
+		printk(KERN_DEBUG "%s: authentication with AP %s"
+		       " timed out\n",
+		       sdata->dev->name, print_mac(mac, ifsta->bssid));
+		ifsta->state = IEEE80211_STA_MLME_DISABLED;
+		return;
+	}
+
+	ifsta->state = IEEE80211_STA_MLME_AUTHENTICATE;
+	printk(KERN_DEBUG "%s: authenticate with AP %s\n",
+	       sdata->dev->name, print_mac(mac, ifsta->bssid));
+
+	ieee80211_send_auth(sdata, ifsta, 1, NULL, 0, 0);
+
+	mod_timer(&ifsta->timer, jiffies + IEEE80211_AUTH_TIMEOUT);
+}
+
+static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
+				   struct ieee80211_if_sta *ifsta, bool deauth,
+				   bool self_disconnected, u16 reason)
+{
+	struct ieee80211_local *local = sdata->local;
+	struct sta_info *sta;
+	u32 changed = BSS_CHANGED_ASSOC;
+
+	rcu_read_lock();
+
+	sta = sta_info_get(local, ifsta->bssid);
+	if (!sta) {
+		rcu_read_unlock();
+		return;
+	}
+
+	if (deauth) {
+		ifsta->direct_probe_tries = 0;
+		ifsta->auth_tries = 0;
+	}
+	ifsta->assoc_scan_tries = 0;
+	ifsta->assoc_tries = 0;
+
+	netif_tx_stop_all_queues(sdata->dev);
+	netif_carrier_off(sdata->dev);
+
+	ieee80211_sta_tear_down_BA_sessions(sdata, sta->sta.addr);
+
+	if (self_disconnected) {
+		if (deauth)
+			ieee80211_send_deauth_disassoc(sdata,
+				IEEE80211_STYPE_DEAUTH, reason);
+		else
+			ieee80211_send_deauth_disassoc(sdata,
+				IEEE80211_STYPE_DISASSOC, reason);
+	}
+
+	ifsta->flags &= ~IEEE80211_STA_ASSOCIATED;
+	changed |= ieee80211_reset_erp_info(sdata);
+
+	if (sdata->bss_conf.assoc_ht)
+		changed |= BSS_CHANGED_HT;
+
+	sdata->bss_conf.assoc_ht = 0;
+	sdata->bss_conf.ht_conf = NULL;
+	sdata->bss_conf.ht_bss_conf = NULL;
+
+	ieee80211_led_assoc(local, 0);
+	sdata->bss_conf.assoc = 0;
+
+	ieee80211_sta_send_apinfo(sdata, ifsta);
+
+	if (self_disconnected)
+		ifsta->state = IEEE80211_STA_MLME_DISABLED;
+
+	sta_info_unlink(&sta);
+
+	rcu_read_unlock();
+
+	sta_info_destroy(sta);
+}
+
+static int ieee80211_sta_wep_configured(struct ieee80211_sub_if_data *sdata)
+{
+	if (!sdata || !sdata->default_key ||
+	    sdata->default_key->conf.alg != ALG_WEP)
+		return 0;
+	return 1;
+}
+
+static int ieee80211_privacy_mismatch(struct ieee80211_sub_if_data *sdata,
 				      struct ieee80211_if_sta *ifsta)
 {
-	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-	struct ieee80211_sta_bss *bss;
+	struct ieee80211_local *local = sdata->local;
+	struct ieee80211_bss *bss;
 	int bss_privacy;
 	int wep_privacy;
 	int privacy_invoked;
@@ -981,14 +893,14 @@
 	if (!ifsta || (ifsta->flags & IEEE80211_STA_MIXED_CELL))
 		return 0;
 
-	bss = ieee80211_rx_bss_get(dev, ifsta->bssid,
+	bss = ieee80211_rx_bss_get(local, ifsta->bssid,
 				   local->hw.conf.channel->center_freq,
 				   ifsta->ssid, ifsta->ssid_len);
 	if (!bss)
 		return 0;
 
 	bss_privacy = !!(bss->capability & WLAN_CAPABILITY_PRIVACY);
-	wep_privacy = !!ieee80211_sta_wep_configured(dev);
+	wep_privacy = !!ieee80211_sta_wep_configured(sdata);
 	privacy_invoked = !!(ifsta->flags & IEEE80211_STA_PRIVACY_INVOKED);
 
 	ieee80211_rx_bss_put(local, bss);
@@ -999,8 +911,7 @@
 	return 1;
 }
 
-
-static void ieee80211_associate(struct net_device *dev,
+static void ieee80211_associate(struct ieee80211_sub_if_data *sdata,
 				struct ieee80211_if_sta *ifsta)
 {
 	DECLARE_MAC_BUF(mac);
@@ -1009,31 +920,31 @@
 	if (ifsta->assoc_tries > IEEE80211_ASSOC_MAX_TRIES) {
 		printk(KERN_DEBUG "%s: association with AP %s"
 		       " timed out\n",
-		       dev->name, print_mac(mac, ifsta->bssid));
-		ifsta->state = IEEE80211_DISABLED;
+		       sdata->dev->name, print_mac(mac, ifsta->bssid));
+		ifsta->state = IEEE80211_STA_MLME_DISABLED;
 		return;
 	}
 
-	ifsta->state = IEEE80211_ASSOCIATE;
+	ifsta->state = IEEE80211_STA_MLME_ASSOCIATE;
 	printk(KERN_DEBUG "%s: associate with AP %s\n",
-	       dev->name, print_mac(mac, ifsta->bssid));
-	if (ieee80211_privacy_mismatch(dev, ifsta)) {
+	       sdata->dev->name, print_mac(mac, ifsta->bssid));
+	if (ieee80211_privacy_mismatch(sdata, ifsta)) {
 		printk(KERN_DEBUG "%s: mismatch in privacy configuration and "
-		       "mixed-cell disabled - abort association\n", dev->name);
-		ifsta->state = IEEE80211_DISABLED;
+		       "mixed-cell disabled - abort association\n", sdata->dev->name);
+		ifsta->state = IEEE80211_STA_MLME_DISABLED;
 		return;
 	}
 
-	ieee80211_send_assoc(dev, ifsta);
+	ieee80211_send_assoc(sdata, ifsta);
 
 	mod_timer(&ifsta->timer, jiffies + IEEE80211_ASSOC_TIMEOUT);
 }
 
 
-static void ieee80211_associated(struct net_device *dev,
+static void ieee80211_associated(struct ieee80211_sub_if_data *sdata,
 				 struct ieee80211_if_sta *ifsta)
 {
-	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct ieee80211_local *local = sdata->local;
 	struct sta_info *sta;
 	int disassoc;
 	DECLARE_MAC_BUF(mac);
@@ -1043,14 +954,14 @@
 	 * for better APs. */
 	/* TODO: remove expired BSSes */
 
-	ifsta->state = IEEE80211_ASSOCIATED;
+	ifsta->state = IEEE80211_STA_MLME_ASSOCIATED;
 
 	rcu_read_lock();
 
 	sta = sta_info_get(local, ifsta->bssid);
 	if (!sta) {
 		printk(KERN_DEBUG "%s: No STA entry for own AP %s\n",
-		       dev->name, print_mac(mac, ifsta->bssid));
+		       sdata->dev->name, print_mac(mac, ifsta->bssid));
 		disassoc = 1;
 	} else {
 		disassoc = 0;
@@ -1060,20 +971,19 @@
 				printk(KERN_DEBUG "%s: No ProbeResp from "
 				       "current AP %s - assume out of "
 				       "range\n",
-				       dev->name, print_mac(mac, ifsta->bssid));
+				       sdata->dev->name, print_mac(mac, ifsta->bssid));
 				disassoc = 1;
-				sta_info_unlink(&sta);
 			} else
-				ieee80211_send_probe_req(dev, ifsta->bssid,
-							 local->scan_ssid,
-							 local->scan_ssid_len);
+				ieee80211_send_probe_req(sdata, ifsta->bssid,
+							 ifsta->ssid,
+							 ifsta->ssid_len);
 			ifsta->flags ^= IEEE80211_STA_PROBEREQ_POLL;
 		} else {
 			ifsta->flags &= ~IEEE80211_STA_PROBEREQ_POLL;
 			if (time_after(jiffies, ifsta->last_probe +
 				       IEEE80211_PROBE_INTERVAL)) {
 				ifsta->last_probe = jiffies;
-				ieee80211_send_probe_req(dev, ifsta->bssid,
+				ieee80211_send_probe_req(sdata, ifsta->bssid,
 							 ifsta->ssid,
 							 ifsta->ssid_len);
 			}
@@ -1082,100 +992,25 @@
 
 	rcu_read_unlock();
 
-	if (disassoc && sta)
-		sta_info_destroy(sta);
-
-	if (disassoc) {
-		ifsta->state = IEEE80211_DISABLED;
-		ieee80211_set_associated(dev, ifsta, 0);
-	} else {
+	if (disassoc)
+		ieee80211_set_disassoc(sdata, ifsta, true, true,
+					WLAN_REASON_PREV_AUTH_NOT_VALID);
+	else
 		mod_timer(&ifsta->timer, jiffies +
 				      IEEE80211_MONITORING_INTERVAL);
-	}
 }
 
 
-static void ieee80211_send_probe_req(struct net_device *dev, u8 *dst,
-				     u8 *ssid, size_t ssid_len)
-{
-	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-	struct ieee80211_supported_band *sband;
-	struct sk_buff *skb;
-	struct ieee80211_mgmt *mgmt;
-	u8 *pos, *supp_rates, *esupp_rates = NULL;
-	int i;
-
-	skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*mgmt) + 200);
-	if (!skb) {
-		printk(KERN_DEBUG "%s: failed to allocate buffer for probe "
-		       "request\n", dev->name);
-		return;
-	}
-	skb_reserve(skb, local->hw.extra_tx_headroom);
-
-	mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24);
-	memset(mgmt, 0, 24);
-	mgmt->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT,
-					   IEEE80211_STYPE_PROBE_REQ);
-	memcpy(mgmt->sa, dev->dev_addr, ETH_ALEN);
-	if (dst) {
-		memcpy(mgmt->da, dst, ETH_ALEN);
-		memcpy(mgmt->bssid, dst, ETH_ALEN);
-	} else {
-		memset(mgmt->da, 0xff, ETH_ALEN);
-		memset(mgmt->bssid, 0xff, ETH_ALEN);
-	}
-	pos = skb_put(skb, 2 + ssid_len);
-	*pos++ = WLAN_EID_SSID;
-	*pos++ = ssid_len;
-	memcpy(pos, ssid, ssid_len);
-
-	supp_rates = skb_put(skb, 2);
-	supp_rates[0] = WLAN_EID_SUPP_RATES;
-	supp_rates[1] = 0;
-	sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
-
-	for (i = 0; i < sband->n_bitrates; i++) {
-		struct ieee80211_rate *rate = &sband->bitrates[i];
-		if (esupp_rates) {
-			pos = skb_put(skb, 1);
-			esupp_rates[1]++;
-		} else if (supp_rates[1] == 8) {
-			esupp_rates = skb_put(skb, 3);
-			esupp_rates[0] = WLAN_EID_EXT_SUPP_RATES;
-			esupp_rates[1] = 1;
-			pos = &esupp_rates[2];
-		} else {
-			pos = skb_put(skb, 1);
-			supp_rates[1]++;
-		}
-		*pos = rate->bitrate / 5;
-	}
-
-	ieee80211_sta_tx(dev, skb, 0);
-}
-
-
-static int ieee80211_sta_wep_configured(struct net_device *dev)
-{
-	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-	if (!sdata || !sdata->default_key ||
-	    sdata->default_key->conf.alg != ALG_WEP)
-		return 0;
-	return 1;
-}
-
-
-static void ieee80211_auth_completed(struct net_device *dev,
+static void ieee80211_auth_completed(struct ieee80211_sub_if_data *sdata,
 				     struct ieee80211_if_sta *ifsta)
 {
-	printk(KERN_DEBUG "%s: authenticated\n", dev->name);
+	printk(KERN_DEBUG "%s: authenticated\n", sdata->dev->name);
 	ifsta->flags |= IEEE80211_STA_AUTHENTICATED;
-	ieee80211_associate(dev, ifsta);
+	ieee80211_associate(sdata, ifsta);
 }
 
 
-static void ieee80211_auth_challenge(struct net_device *dev,
+static void ieee80211_auth_challenge(struct ieee80211_sub_if_data *sdata,
 				     struct ieee80211_if_sta *ifsta,
 				     struct ieee80211_mgmt *mgmt,
 				     size_t len)
@@ -1187,682 +1022,30 @@
 	ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems);
 	if (!elems.challenge)
 		return;
-	ieee80211_send_auth(dev, ifsta, 3, elems.challenge - 2,
+	ieee80211_send_auth(sdata, ifsta, 3, elems.challenge - 2,
 			    elems.challenge_len + 2, 1);
 }
 
-static void ieee80211_send_addba_resp(struct net_device *dev, u8 *da, u16 tid,
-					u8 dialog_token, u16 status, u16 policy,
-					u16 buf_size, u16 timeout)
-{
-	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-	struct ieee80211_if_sta *ifsta = &sdata->u.sta;
-	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-	struct sk_buff *skb;
-	struct ieee80211_mgmt *mgmt;
-	u16 capab;
-
-	skb = dev_alloc_skb(sizeof(*mgmt) + local->hw.extra_tx_headroom);
-
-	if (!skb) {
-		printk(KERN_DEBUG "%s: failed to allocate buffer "
-		       "for addba resp frame\n", dev->name);
-		return;
-	}
-
-	skb_reserve(skb, local->hw.extra_tx_headroom);
-	mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24);
-	memset(mgmt, 0, 24);
-	memcpy(mgmt->da, da, ETH_ALEN);
-	memcpy(mgmt->sa, dev->dev_addr, ETH_ALEN);
-	if (sdata->vif.type == IEEE80211_IF_TYPE_AP)
-		memcpy(mgmt->bssid, dev->dev_addr, ETH_ALEN);
-	else
-		memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN);
-	mgmt->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT,
-					   IEEE80211_STYPE_ACTION);
-
-	skb_put(skb, 1 + sizeof(mgmt->u.action.u.addba_resp));
-	mgmt->u.action.category = WLAN_CATEGORY_BACK;
-	mgmt->u.action.u.addba_resp.action_code = WLAN_ACTION_ADDBA_RESP;
-	mgmt->u.action.u.addba_resp.dialog_token = dialog_token;
-
-	capab = (u16)(policy << 1);	/* bit 1 aggregation policy */
-	capab |= (u16)(tid << 2); 	/* bit 5:2 TID number */
-	capab |= (u16)(buf_size << 6);	/* bit 15:6 max size of aggregation */
-
-	mgmt->u.action.u.addba_resp.capab = cpu_to_le16(capab);
-	mgmt->u.action.u.addba_resp.timeout = cpu_to_le16(timeout);
-	mgmt->u.action.u.addba_resp.status = cpu_to_le16(status);
-
-	ieee80211_sta_tx(dev, skb, 0);
-
-	return;
-}
-
-void ieee80211_send_addba_request(struct net_device *dev, const u8 *da,
-				u16 tid, u8 dialog_token, u16 start_seq_num,
-				u16 agg_size, u16 timeout)
-{
-	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-	struct ieee80211_if_sta *ifsta = &sdata->u.sta;
-	struct sk_buff *skb;
-	struct ieee80211_mgmt *mgmt;
-	u16 capab;
-
-	skb = dev_alloc_skb(sizeof(*mgmt) + local->hw.extra_tx_headroom);
-
-	if (!skb) {
-		printk(KERN_ERR "%s: failed to allocate buffer "
-				"for addba request frame\n", dev->name);
-		return;
-	}
-	skb_reserve(skb, local->hw.extra_tx_headroom);
-	mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24);
-	memset(mgmt, 0, 24);
-	memcpy(mgmt->da, da, ETH_ALEN);
-	memcpy(mgmt->sa, dev->dev_addr, ETH_ALEN);
-	if (sdata->vif.type == IEEE80211_IF_TYPE_AP)
-		memcpy(mgmt->bssid, dev->dev_addr, ETH_ALEN);
-	else
-		memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN);
-
-	mgmt->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT,
-					IEEE80211_STYPE_ACTION);
-
-	skb_put(skb, 1 + sizeof(mgmt->u.action.u.addba_req));
-
-	mgmt->u.action.category = WLAN_CATEGORY_BACK;
-	mgmt->u.action.u.addba_req.action_code = WLAN_ACTION_ADDBA_REQ;
-
-	mgmt->u.action.u.addba_req.dialog_token = dialog_token;
-	capab = (u16)(1 << 1);		/* bit 1 aggregation policy */
-	capab |= (u16)(tid << 2); 	/* bit 5:2 TID number */
-	capab |= (u16)(agg_size << 6);	/* bit 15:6 max size of aggergation */
-
-	mgmt->u.action.u.addba_req.capab = cpu_to_le16(capab);
-
-	mgmt->u.action.u.addba_req.timeout = cpu_to_le16(timeout);
-	mgmt->u.action.u.addba_req.start_seq_num =
-					cpu_to_le16(start_seq_num << 4);
-
-	ieee80211_sta_tx(dev, skb, 0);
-}
-
-static void ieee80211_sta_process_addba_request(struct net_device *dev,
-						struct ieee80211_mgmt *mgmt,
-						size_t len)
-{
-	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-	struct ieee80211_hw *hw = &local->hw;
-	struct ieee80211_conf *conf = &hw->conf;
-	struct sta_info *sta;
-	struct tid_ampdu_rx *tid_agg_rx;
-	u16 capab, tid, timeout, ba_policy, buf_size, start_seq_num, status;
-	u8 dialog_token;
-	int ret = -EOPNOTSUPP;
-	DECLARE_MAC_BUF(mac);
-
-	rcu_read_lock();
-
-	sta = sta_info_get(local, mgmt->sa);
-	if (!sta) {
-		rcu_read_unlock();
-		return;
-	}
-
-	/* extract session parameters from addba request frame */
-	dialog_token = mgmt->u.action.u.addba_req.dialog_token;
-	timeout = le16_to_cpu(mgmt->u.action.u.addba_req.timeout);
-	start_seq_num =
-		le16_to_cpu(mgmt->u.action.u.addba_req.start_seq_num) >> 4;
-
-	capab = le16_to_cpu(mgmt->u.action.u.addba_req.capab);
-	ba_policy = (capab & IEEE80211_ADDBA_PARAM_POLICY_MASK) >> 1;
-	tid = (capab & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2;
-	buf_size = (capab & IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK) >> 6;
-
-	status = WLAN_STATUS_REQUEST_DECLINED;
-
-	/* sanity check for incoming parameters:
-	 * check if configuration can support the BA policy
-	 * and if buffer size does not exceeds max value */
-	if (((ba_policy != 1)
-		&& (!(conf->ht_conf.cap & IEEE80211_HT_CAP_DELAY_BA)))
-		|| (buf_size > IEEE80211_MAX_AMPDU_BUF)) {
-		status = WLAN_STATUS_INVALID_QOS_PARAM;
-#ifdef CONFIG_MAC80211_HT_DEBUG
-		if (net_ratelimit())
-			printk(KERN_DEBUG "AddBA Req with bad params from "
-				"%s on tid %u. policy %d, buffer size %d\n",
-				print_mac(mac, mgmt->sa), tid, ba_policy,
-				buf_size);
-#endif /* CONFIG_MAC80211_HT_DEBUG */
-		goto end_no_lock;
-	}
-	/* determine default buffer size */
-	if (buf_size == 0) {
-		struct ieee80211_supported_band *sband;
-
-		sband = local->hw.wiphy->bands[conf->channel->band];
-		buf_size = IEEE80211_MIN_AMPDU_BUF;
-		buf_size = buf_size << sband->ht_info.ampdu_factor;
-	}
-
-
-	/* examine state machine */
-	spin_lock_bh(&sta->lock);
-
-	if (sta->ampdu_mlme.tid_state_rx[tid] != HT_AGG_STATE_IDLE) {
-#ifdef CONFIG_MAC80211_HT_DEBUG
-		if (net_ratelimit())
-			printk(KERN_DEBUG "unexpected AddBA Req from "
-				"%s on tid %u\n",
-				print_mac(mac, mgmt->sa), tid);
-#endif /* CONFIG_MAC80211_HT_DEBUG */
-		goto end;
-	}
-
-	/* prepare A-MPDU MLME for Rx aggregation */
-	sta->ampdu_mlme.tid_rx[tid] =
-			kmalloc(sizeof(struct tid_ampdu_rx), GFP_ATOMIC);
-	if (!sta->ampdu_mlme.tid_rx[tid]) {
-#ifdef CONFIG_MAC80211_HT_DEBUG
-		if (net_ratelimit())
-			printk(KERN_ERR "allocate rx mlme to tid %d failed\n",
-					tid);
-#endif
-		goto end;
-	}
-	/* rx timer */
-	sta->ampdu_mlme.tid_rx[tid]->session_timer.function =
-				sta_rx_agg_session_timer_expired;
-	sta->ampdu_mlme.tid_rx[tid]->session_timer.data =
-				(unsigned long)&sta->timer_to_tid[tid];
-	init_timer(&sta->ampdu_mlme.tid_rx[tid]->session_timer);
-
-	tid_agg_rx = sta->ampdu_mlme.tid_rx[tid];
-
-	/* prepare reordering buffer */
-	tid_agg_rx->reorder_buf =
-		kmalloc(buf_size * sizeof(struct sk_buff *), GFP_ATOMIC);
-	if (!tid_agg_rx->reorder_buf) {
-#ifdef CONFIG_MAC80211_HT_DEBUG
-		if (net_ratelimit())
-			printk(KERN_ERR "can not allocate reordering buffer "
-			       "to tid %d\n", tid);
-#endif
-		kfree(sta->ampdu_mlme.tid_rx[tid]);
-		goto end;
-	}
-	memset(tid_agg_rx->reorder_buf, 0,
-		buf_size * sizeof(struct sk_buff *));
-
-	if (local->ops->ampdu_action)
-		ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_RX_START,
-					       sta->addr, tid, &start_seq_num);
-#ifdef CONFIG_MAC80211_HT_DEBUG
-	printk(KERN_DEBUG "Rx A-MPDU request on tid %d result %d\n", tid, ret);
-#endif /* CONFIG_MAC80211_HT_DEBUG */
-
-	if (ret) {
-		kfree(tid_agg_rx->reorder_buf);
-		kfree(tid_agg_rx);
-		sta->ampdu_mlme.tid_rx[tid] = NULL;
-		goto end;
-	}
-
-	/* change state and send addba resp */
-	sta->ampdu_mlme.tid_state_rx[tid] = HT_AGG_STATE_OPERATIONAL;
-	tid_agg_rx->dialog_token = dialog_token;
-	tid_agg_rx->ssn = start_seq_num;
-	tid_agg_rx->head_seq_num = start_seq_num;
-	tid_agg_rx->buf_size = buf_size;
-	tid_agg_rx->timeout = timeout;
-	tid_agg_rx->stored_mpdu_num = 0;
-	status = WLAN_STATUS_SUCCESS;
-end:
-	spin_unlock_bh(&sta->lock);
-
-end_no_lock:
-	ieee80211_send_addba_resp(sta->sdata->dev, sta->addr, tid,
-				  dialog_token, status, 1, buf_size, timeout);
-	rcu_read_unlock();
-}
-
-static void ieee80211_sta_process_addba_resp(struct net_device *dev,
-					     struct ieee80211_mgmt *mgmt,
-					     size_t len)
-{
-	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-	struct ieee80211_hw *hw = &local->hw;
-	struct sta_info *sta;
-	u16 capab;
-	u16 tid;
-	u8 *state;
-
-	rcu_read_lock();
-
-	sta = sta_info_get(local, mgmt->sa);
-	if (!sta) {
-		rcu_read_unlock();
-		return;
-	}
-
-	capab = le16_to_cpu(mgmt->u.action.u.addba_resp.capab);
-	tid = (capab & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2;
-
-	state = &sta->ampdu_mlme.tid_state_tx[tid];
-
-	spin_lock_bh(&sta->lock);
-
-	if (!(*state & HT_ADDBA_REQUESTED_MSK)) {
-		spin_unlock_bh(&sta->lock);
-		goto addba_resp_exit;
-	}
-
-	if (mgmt->u.action.u.addba_resp.dialog_token !=
-		sta->ampdu_mlme.tid_tx[tid]->dialog_token) {
-		spin_unlock_bh(&sta->lock);
-#ifdef CONFIG_MAC80211_HT_DEBUG
-		printk(KERN_DEBUG "wrong addBA response token, tid %d\n", tid);
-#endif /* CONFIG_MAC80211_HT_DEBUG */
-		goto addba_resp_exit;
-	}
-
-	del_timer_sync(&sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer);
-#ifdef CONFIG_MAC80211_HT_DEBUG
-	printk(KERN_DEBUG "switched off addBA timer for tid %d \n", tid);
-#endif /* CONFIG_MAC80211_HT_DEBUG */
-	if (le16_to_cpu(mgmt->u.action.u.addba_resp.status)
-			== WLAN_STATUS_SUCCESS) {
-		*state |= HT_ADDBA_RECEIVED_MSK;
-		sta->ampdu_mlme.addba_req_num[tid] = 0;
-
-		if (*state == HT_AGG_STATE_OPERATIONAL)
-			ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]);
-
-		spin_unlock_bh(&sta->lock);
-	} else {
-		sta->ampdu_mlme.addba_req_num[tid]++;
-		/* this will allow the state check in stop_BA_session */
-		*state = HT_AGG_STATE_OPERATIONAL;
-		spin_unlock_bh(&sta->lock);
-		ieee80211_stop_tx_ba_session(hw, sta->addr, tid,
-					     WLAN_BACK_INITIATOR);
-	}
-
-addba_resp_exit:
-	rcu_read_unlock();
-}
-
-void ieee80211_send_delba(struct net_device *dev, const u8 *da, u16 tid,
-			  u16 initiator, u16 reason_code)
-{
-	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-	struct ieee80211_if_sta *ifsta = &sdata->u.sta;
-	struct sk_buff *skb;
-	struct ieee80211_mgmt *mgmt;
-	u16 params;
-
-	skb = dev_alloc_skb(sizeof(*mgmt) + local->hw.extra_tx_headroom);
-
-	if (!skb) {
-		printk(KERN_ERR "%s: failed to allocate buffer "
-					"for delba frame\n", dev->name);
-		return;
-	}
-
-	skb_reserve(skb, local->hw.extra_tx_headroom);
-	mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24);
-	memset(mgmt, 0, 24);
-	memcpy(mgmt->da, da, ETH_ALEN);
-	memcpy(mgmt->sa, dev->dev_addr, ETH_ALEN);
-	if (sdata->vif.type == IEEE80211_IF_TYPE_AP)
-		memcpy(mgmt->bssid, dev->dev_addr, ETH_ALEN);
-	else
-		memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN);
-	mgmt->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT,
-					IEEE80211_STYPE_ACTION);
-
-	skb_put(skb, 1 + sizeof(mgmt->u.action.u.delba));
-
-	mgmt->u.action.category = WLAN_CATEGORY_BACK;
-	mgmt->u.action.u.delba.action_code = WLAN_ACTION_DELBA;
-	params = (u16)(initiator << 11); 	/* bit 11 initiator */
-	params |= (u16)(tid << 12); 		/* bit 15:12 TID number */
-
-	mgmt->u.action.u.delba.params = cpu_to_le16(params);
-	mgmt->u.action.u.delba.reason_code = cpu_to_le16(reason_code);
-
-	ieee80211_sta_tx(dev, skb, 0);
-}
-
-void ieee80211_send_bar(struct net_device *dev, u8 *ra, u16 tid, u16 ssn)
-{
-	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-	struct sk_buff *skb;
-	struct ieee80211_bar *bar;
-	u16 bar_control = 0;
-
-	skb = dev_alloc_skb(sizeof(*bar) + local->hw.extra_tx_headroom);
-	if (!skb) {
-		printk(KERN_ERR "%s: failed to allocate buffer for "
-			"bar frame\n", dev->name);
-		return;
-	}
-	skb_reserve(skb, local->hw.extra_tx_headroom);
-	bar = (struct ieee80211_bar *)skb_put(skb, sizeof(*bar));
-	memset(bar, 0, sizeof(*bar));
-	bar->frame_control = IEEE80211_FC(IEEE80211_FTYPE_CTL,
-					IEEE80211_STYPE_BACK_REQ);
-	memcpy(bar->ra, ra, ETH_ALEN);
-	memcpy(bar->ta, dev->dev_addr, ETH_ALEN);
-	bar_control |= (u16)IEEE80211_BAR_CTRL_ACK_POLICY_NORMAL;
-	bar_control |= (u16)IEEE80211_BAR_CTRL_CBMTID_COMPRESSED_BA;
-	bar_control |= (u16)(tid << 12);
-	bar->control = cpu_to_le16(bar_control);
-	bar->start_seq_num = cpu_to_le16(ssn);
-
-	ieee80211_sta_tx(dev, skb, 0);
-}
-
-void ieee80211_sta_stop_rx_ba_session(struct net_device *dev, u8 *ra, u16 tid,
-					u16 initiator, u16 reason)
-{
-	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-	struct ieee80211_hw *hw = &local->hw;
-	struct sta_info *sta;
-	int ret, i;
-	DECLARE_MAC_BUF(mac);
-
-	rcu_read_lock();
-
-	sta = sta_info_get(local, ra);
-	if (!sta) {
-		rcu_read_unlock();
-		return;
-	}
-
-	/* check if TID is in operational state */
-	spin_lock_bh(&sta->lock);
-	if (sta->ampdu_mlme.tid_state_rx[tid]
-				!= HT_AGG_STATE_OPERATIONAL) {
-		spin_unlock_bh(&sta->lock);
-		rcu_read_unlock();
-		return;
-	}
-	sta->ampdu_mlme.tid_state_rx[tid] =
-		HT_AGG_STATE_REQ_STOP_BA_MSK |
-		(initiator << HT_AGG_STATE_INITIATOR_SHIFT);
-	spin_unlock_bh(&sta->lock);
-
-	/* stop HW Rx aggregation. ampdu_action existence
-	 * already verified in session init so we add the BUG_ON */
-	BUG_ON(!local->ops->ampdu_action);
-
-#ifdef CONFIG_MAC80211_HT_DEBUG
-	printk(KERN_DEBUG "Rx BA session stop requested for %s tid %u\n",
-				print_mac(mac, ra), tid);
-#endif /* CONFIG_MAC80211_HT_DEBUG */
-
-	ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_RX_STOP,
-					ra, tid, NULL);
-	if (ret)
-		printk(KERN_DEBUG "HW problem - can not stop rx "
-				"aggregation for tid %d\n", tid);
-
-	/* shutdown timer has not expired */
-	if (initiator != WLAN_BACK_TIMER)
-		del_timer_sync(&sta->ampdu_mlme.tid_rx[tid]->session_timer);
-
-	/* check if this is a self generated aggregation halt */
-	if (initiator == WLAN_BACK_RECIPIENT || initiator == WLAN_BACK_TIMER)
-		ieee80211_send_delba(dev, ra, tid, 0, reason);
-
-	/* free the reordering buffer */
-	for (i = 0; i < sta->ampdu_mlme.tid_rx[tid]->buf_size; i++) {
-		if (sta->ampdu_mlme.tid_rx[tid]->reorder_buf[i]) {
-			/* release the reordered frames */
-			dev_kfree_skb(sta->ampdu_mlme.tid_rx[tid]->reorder_buf[i]);
-			sta->ampdu_mlme.tid_rx[tid]->stored_mpdu_num--;
-			sta->ampdu_mlme.tid_rx[tid]->reorder_buf[i] = NULL;
-		}
-	}
-	/* free resources */
-	kfree(sta->ampdu_mlme.tid_rx[tid]->reorder_buf);
-	kfree(sta->ampdu_mlme.tid_rx[tid]);
-	sta->ampdu_mlme.tid_rx[tid] = NULL;
-	sta->ampdu_mlme.tid_state_rx[tid] = HT_AGG_STATE_IDLE;
-
-	rcu_read_unlock();
-}
-
-
-static void ieee80211_sta_process_delba(struct net_device *dev,
-			struct ieee80211_mgmt *mgmt, size_t len)
-{
-	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-	struct sta_info *sta;
-	u16 tid, params;
-	u16 initiator;
-	DECLARE_MAC_BUF(mac);
-
-	rcu_read_lock();
-
-	sta = sta_info_get(local, mgmt->sa);
-	if (!sta) {
-		rcu_read_unlock();
-		return;
-	}
-
-	params = le16_to_cpu(mgmt->u.action.u.delba.params);
-	tid = (params & IEEE80211_DELBA_PARAM_TID_MASK) >> 12;
-	initiator = (params & IEEE80211_DELBA_PARAM_INITIATOR_MASK) >> 11;
-
-#ifdef CONFIG_MAC80211_HT_DEBUG
-	if (net_ratelimit())
-		printk(KERN_DEBUG "delba from %s (%s) tid %d reason code %d\n",
-			print_mac(mac, mgmt->sa),
-			initiator ? "initiator" : "recipient", tid,
-			mgmt->u.action.u.delba.reason_code);
-#endif /* CONFIG_MAC80211_HT_DEBUG */
-
-	if (initiator == WLAN_BACK_INITIATOR)
-		ieee80211_sta_stop_rx_ba_session(dev, sta->addr, tid,
-						 WLAN_BACK_INITIATOR, 0);
-	else { /* WLAN_BACK_RECIPIENT */
-		spin_lock_bh(&sta->lock);
-		sta->ampdu_mlme.tid_state_tx[tid] =
-				HT_AGG_STATE_OPERATIONAL;
-		spin_unlock_bh(&sta->lock);
-		ieee80211_stop_tx_ba_session(&local->hw, sta->addr, tid,
-					     WLAN_BACK_RECIPIENT);
-	}
-	rcu_read_unlock();
-}
-
-/*
- * After sending add Block Ack request we activated a timer until
- * add Block Ack response will arrive from the recipient.
- * If this timer expires sta_addba_resp_timer_expired will be executed.
- */
-void sta_addba_resp_timer_expired(unsigned long data)
-{
-	/* not an elegant detour, but there is no choice as the timer passes
-	 * only one argument, and both sta_info and TID are needed, so init
-	 * flow in sta_info_create gives the TID as data, while the timer_to_id
-	 * array gives the sta through container_of */
-	u16 tid = *(u8 *)data;
-	struct sta_info *temp_sta = container_of((void *)data,
-		struct sta_info, timer_to_tid[tid]);
-
-	struct ieee80211_local *local = temp_sta->local;
-	struct ieee80211_hw *hw = &local->hw;
-	struct sta_info *sta;
-	u8 *state;
-
-	rcu_read_lock();
-
-	sta = sta_info_get(local, temp_sta->addr);
-	if (!sta) {
-		rcu_read_unlock();
-		return;
-	}
-
-	state = &sta->ampdu_mlme.tid_state_tx[tid];
-	/* check if the TID waits for addBA response */
-	spin_lock_bh(&sta->lock);
-	if (!(*state & HT_ADDBA_REQUESTED_MSK)) {
-		spin_unlock_bh(&sta->lock);
-		*state = HT_AGG_STATE_IDLE;
-#ifdef CONFIG_MAC80211_HT_DEBUG
-		printk(KERN_DEBUG "timer expired on tid %d but we are not "
-				"expecting addBA response there", tid);
-#endif
-		goto timer_expired_exit;
-	}
-
-#ifdef CONFIG_MAC80211_HT_DEBUG
-	printk(KERN_DEBUG "addBA response timer expired on tid %d\n", tid);
-#endif
-
-	/* go through the state check in stop_BA_session */
-	*state = HT_AGG_STATE_OPERATIONAL;
-	spin_unlock_bh(&sta->lock);
-	ieee80211_stop_tx_ba_session(hw, temp_sta->addr, tid,
-				     WLAN_BACK_INITIATOR);
-
-timer_expired_exit:
-	rcu_read_unlock();
-}
-
-/*
- * After accepting the AddBA Request we activated a timer,
- * resetting it after each frame that arrives from the originator.
- * if this timer expires ieee80211_sta_stop_rx_ba_session will be executed.
- */
-static void sta_rx_agg_session_timer_expired(unsigned long data)
-{
-	/* not an elegant detour, but there is no choice as the timer passes
-	 * only one argument, and various sta_info are needed here, so init
-	 * flow in sta_info_create gives the TID as data, while the timer_to_id
-	 * array gives the sta through container_of */
-	u8 *ptid = (u8 *)data;
-	u8 *timer_to_id = ptid - *ptid;
-	struct sta_info *sta = container_of(timer_to_id, struct sta_info,
-					 timer_to_tid[0]);
-
-#ifdef CONFIG_MAC80211_HT_DEBUG
-	printk(KERN_DEBUG "rx session timer expired on tid %d\n", (u16)*ptid);
-#endif
-	ieee80211_sta_stop_rx_ba_session(sta->sdata->dev, sta->addr,
-					 (u16)*ptid, WLAN_BACK_TIMER,
-					 WLAN_REASON_QSTA_TIMEOUT);
-}
-
-void ieee80211_sta_tear_down_BA_sessions(struct net_device *dev, u8 *addr)
-{
-	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-	int i;
-
-	for (i = 0; i <  STA_TID_NUM; i++) {
-		ieee80211_stop_tx_ba_session(&local->hw, addr, i,
-					     WLAN_BACK_INITIATOR);
-		ieee80211_sta_stop_rx_ba_session(dev, addr, i,
-						 WLAN_BACK_RECIPIENT,
-						 WLAN_REASON_QSTA_LEAVE_QBSS);
-	}
-}
-
-static void ieee80211_send_refuse_measurement_request(struct net_device *dev,
-					struct ieee80211_msrment_ie *request_ie,
-					const u8 *da, const u8 *bssid,
-					u8 dialog_token)
-{
-	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-	struct sk_buff *skb;
-	struct ieee80211_mgmt *msr_report;
-
-	skb = dev_alloc_skb(sizeof(*msr_report) + local->hw.extra_tx_headroom +
-				sizeof(struct ieee80211_msrment_ie));
-
-	if (!skb) {
-		printk(KERN_ERR "%s: failed to allocate buffer for "
-				"measurement report frame\n", dev->name);
-		return;
-	}
-
-	skb_reserve(skb, local->hw.extra_tx_headroom);
-	msr_report = (struct ieee80211_mgmt *)skb_put(skb, 24);
-	memset(msr_report, 0, 24);
-	memcpy(msr_report->da, da, ETH_ALEN);
-	memcpy(msr_report->sa, dev->dev_addr, ETH_ALEN);
-	memcpy(msr_report->bssid, bssid, ETH_ALEN);
-	msr_report->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT,
-						IEEE80211_STYPE_ACTION);
-
-	skb_put(skb, 1 + sizeof(msr_report->u.action.u.measurement));
-	msr_report->u.action.category = WLAN_CATEGORY_SPECTRUM_MGMT;
-	msr_report->u.action.u.measurement.action_code =
-				WLAN_ACTION_SPCT_MSR_RPRT;
-	msr_report->u.action.u.measurement.dialog_token = dialog_token;
-
-	msr_report->u.action.u.measurement.element_id = WLAN_EID_MEASURE_REPORT;
-	msr_report->u.action.u.measurement.length =
-			sizeof(struct ieee80211_msrment_ie);
-
-	memset(&msr_report->u.action.u.measurement.msr_elem, 0,
-		sizeof(struct ieee80211_msrment_ie));
-	msr_report->u.action.u.measurement.msr_elem.token = request_ie->token;
-	msr_report->u.action.u.measurement.msr_elem.mode |=
-			IEEE80211_SPCT_MSR_RPRT_MODE_REFUSED;
-	msr_report->u.action.u.measurement.msr_elem.type = request_ie->type;
-
-	ieee80211_sta_tx(dev, skb, 0);
-}
-
-static void ieee80211_sta_process_measurement_req(struct net_device *dev,
-						struct ieee80211_mgmt *mgmt,
-						size_t len)
-{
-	/*
-	 * Ignoring measurement request is spec violation.
-	 * Mandatory measurements must be reported optional
-	 * measurements might be refused or reported incapable
-	 * For now just refuse
-	 * TODO: Answer basic measurement as unmeasured
-	 */
-	ieee80211_send_refuse_measurement_request(dev,
-			&mgmt->u.action.u.measurement.msr_elem,
-			mgmt->sa, mgmt->bssid,
-			mgmt->u.action.u.measurement.dialog_token);
-}
-
-
-static void ieee80211_rx_mgmt_auth(struct net_device *dev,
+static void ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata,
 				   struct ieee80211_if_sta *ifsta,
 				   struct ieee80211_mgmt *mgmt,
 				   size_t len)
 {
-	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 	u16 auth_alg, auth_transaction, status_code;
 	DECLARE_MAC_BUF(mac);
 
-	if (ifsta->state != IEEE80211_AUTHENTICATE &&
-	    sdata->vif.type != IEEE80211_IF_TYPE_IBSS)
+	if (ifsta->state != IEEE80211_STA_MLME_AUTHENTICATE &&
+	    sdata->vif.type != NL80211_IFTYPE_ADHOC)
 		return;
 
 	if (len < 24 + 6)
 		return;
 
-	if (sdata->vif.type != IEEE80211_IF_TYPE_IBSS &&
+	if (sdata->vif.type != NL80211_IFTYPE_ADHOC &&
 	    memcmp(ifsta->bssid, mgmt->sa, ETH_ALEN) != 0)
 		return;
 
-	if (sdata->vif.type != IEEE80211_IF_TYPE_IBSS &&
+	if (sdata->vif.type != NL80211_IFTYPE_ADHOC &&
 	    memcmp(ifsta->bssid, mgmt->bssid, ETH_ALEN) != 0)
 		return;
 
@@ -1870,7 +1053,7 @@
 	auth_transaction = le16_to_cpu(mgmt->u.auth.auth_transaction);
 	status_code = le16_to_cpu(mgmt->u.auth.status_code);
 
-	if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS) {
+	if (sdata->vif.type == NL80211_IFTYPE_ADHOC) {
 		/*
 		 * IEEE 802.11 standard does not require authentication in IBSS
 		 * networks and most implementations do not seem to use it.
@@ -1879,7 +1062,7 @@
 		 */
 		if (auth_alg != WLAN_AUTH_OPEN || auth_transaction != 1)
 			return;
-		ieee80211_send_auth(dev, ifsta, 2, NULL, 0, 0);
+		ieee80211_send_auth(sdata, ifsta, 2, NULL, 0, 0);
 	}
 
 	if (auth_alg != ifsta->auth_alg ||
@@ -1912,7 +1095,7 @@
 				    algs[pos] == 0xff)
 					continue;
 				if (algs[pos] == WLAN_AUTH_SHARED_KEY &&
-				    !ieee80211_sta_wep_configured(dev))
+				    !ieee80211_sta_wep_configured(sdata))
 					continue;
 				ifsta->auth_alg = algs[pos];
 				break;
@@ -1924,19 +1107,19 @@
 	switch (ifsta->auth_alg) {
 	case WLAN_AUTH_OPEN:
 	case WLAN_AUTH_LEAP:
-		ieee80211_auth_completed(dev, ifsta);
+		ieee80211_auth_completed(sdata, ifsta);
 		break;
 	case WLAN_AUTH_SHARED_KEY:
 		if (ifsta->auth_transaction == 4)
-			ieee80211_auth_completed(dev, ifsta);
+			ieee80211_auth_completed(sdata, ifsta);
 		else
-			ieee80211_auth_challenge(dev, ifsta, mgmt, len);
+			ieee80211_auth_challenge(sdata, ifsta, mgmt, len);
 		break;
 	}
 }
 
 
-static void ieee80211_rx_mgmt_deauth(struct net_device *dev,
+static void ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata,
 				     struct ieee80211_if_sta *ifsta,
 				     struct ieee80211_mgmt *mgmt,
 				     size_t len)
@@ -1953,22 +1136,22 @@
 	reason_code = le16_to_cpu(mgmt->u.deauth.reason_code);
 
 	if (ifsta->flags & IEEE80211_STA_AUTHENTICATED)
-		printk(KERN_DEBUG "%s: deauthenticated\n", dev->name);
+		printk(KERN_DEBUG "%s: deauthenticated\n", sdata->dev->name);
 
-	if (ifsta->state == IEEE80211_AUTHENTICATE ||
-	    ifsta->state == IEEE80211_ASSOCIATE ||
-	    ifsta->state == IEEE80211_ASSOCIATED) {
-		ifsta->state = IEEE80211_AUTHENTICATE;
+	if (ifsta->state == IEEE80211_STA_MLME_AUTHENTICATE ||
+	    ifsta->state == IEEE80211_STA_MLME_ASSOCIATE ||
+	    ifsta->state == IEEE80211_STA_MLME_ASSOCIATED) {
+		ifsta->state = IEEE80211_STA_MLME_DIRECT_PROBE;
 		mod_timer(&ifsta->timer, jiffies +
 				      IEEE80211_RETRY_AUTH_INTERVAL);
 	}
 
-	ieee80211_set_disassoc(dev, ifsta, 1);
+	ieee80211_set_disassoc(sdata, ifsta, true, false, 0);
 	ifsta->flags &= ~IEEE80211_STA_AUTHENTICATED;
 }
 
 
-static void ieee80211_rx_mgmt_disassoc(struct net_device *dev,
+static void ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata,
 				       struct ieee80211_if_sta *ifsta,
 				       struct ieee80211_mgmt *mgmt,
 				       size_t len)
@@ -1985,15 +1168,15 @@
 	reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code);
 
 	if (ifsta->flags & IEEE80211_STA_ASSOCIATED)
-		printk(KERN_DEBUG "%s: disassociated\n", dev->name);
+		printk(KERN_DEBUG "%s: disassociated\n", sdata->dev->name);
 
-	if (ifsta->state == IEEE80211_ASSOCIATED) {
-		ifsta->state = IEEE80211_ASSOCIATE;
+	if (ifsta->state == IEEE80211_STA_MLME_ASSOCIATED) {
+		ifsta->state = IEEE80211_STA_MLME_ASSOCIATE;
 		mod_timer(&ifsta->timer, jiffies +
 				      IEEE80211_RETRY_AUTH_INTERVAL);
 	}
 
-	ieee80211_set_disassoc(dev, ifsta, 0);
+	ieee80211_set_disassoc(sdata, ifsta, false, false, 0);
 }
 
 
@@ -2004,7 +1187,6 @@
 					 int reassoc)
 {
 	struct ieee80211_local *local = sdata->local;
-	struct net_device *dev = sdata->dev;
 	struct ieee80211_supported_band *sband;
 	struct sta_info *sta;
 	u64 rates, basic_rates;
@@ -2019,7 +1201,7 @@
 	/* AssocResp and ReassocResp have identical structure, so process both
 	 * of them in this function. */
 
-	if (ifsta->state != IEEE80211_ASSOCIATE)
+	if (ifsta->state != IEEE80211_STA_MLME_ASSOCIATE)
 		return;
 
 	if (len < 24 + 6)
@@ -2034,12 +1216,12 @@
 
 	printk(KERN_DEBUG "%s: RX %sssocResp from %s (capab=0x%x "
 	       "status=%d aid=%d)\n",
-	       dev->name, reassoc ? "Rea" : "A", print_mac(mac, mgmt->sa),
+	       sdata->dev->name, reassoc ? "Rea" : "A", print_mac(mac, mgmt->sa),
 	       capab_info, status_code, (u16)(aid & ~(BIT(15) | BIT(14))));
 
 	if (status_code != WLAN_STATUS_SUCCESS) {
 		printk(KERN_DEBUG "%s: AP denied association (code=%d)\n",
-		       dev->name, status_code);
+		       sdata->dev->name, status_code);
 		/* if this was a reassociation, ensure we try a "full"
 		 * association next time. This works around some broken APs
 		 * which do not correctly reject reassociation requests. */
@@ -2049,7 +1231,7 @@
 
 	if ((aid & (BIT(15) | BIT(14))) != (BIT(15) | BIT(14)))
 		printk(KERN_DEBUG "%s: invalid aid value %d; bits 15:14 not "
-		       "set\n", dev->name, aid);
+		       "set\n", sdata->dev->name, aid);
 	aid &= ~(BIT(15) | BIT(14));
 
 	pos = mgmt->u.assoc_resp.variable;
@@ -2057,11 +1239,11 @@
 
 	if (!elems.supp_rates) {
 		printk(KERN_DEBUG "%s: no SuppRates element in AssocResp\n",
-		       dev->name);
+		       sdata->dev->name);
 		return;
 	}
 
-	printk(KERN_DEBUG "%s: associated\n", dev->name);
+	printk(KERN_DEBUG "%s: associated\n", sdata->dev->name);
 	ifsta->aid = aid;
 	ifsta->ap_capab = capab_info;
 
@@ -2076,17 +1258,17 @@
 	/* Add STA entry for the AP */
 	sta = sta_info_get(local, ifsta->bssid);
 	if (!sta) {
-		struct ieee80211_sta_bss *bss;
+		struct ieee80211_bss *bss;
 		int err;
 
 		sta = sta_info_alloc(sdata, ifsta->bssid, GFP_ATOMIC);
 		if (!sta) {
 			printk(KERN_DEBUG "%s: failed to alloc STA entry for"
-			       " the AP\n", dev->name);
+			       " the AP\n", sdata->dev->name);
 			rcu_read_unlock();
 			return;
 		}
-		bss = ieee80211_rx_bss_get(dev, ifsta->bssid,
+		bss = ieee80211_rx_bss_get(local, ifsta->bssid,
 					   local->hw.conf.channel->center_freq,
 					   ifsta->ssid, ifsta->ssid_len);
 		if (bss) {
@@ -2099,7 +1281,7 @@
 		err = sta_info_insert(sta);
 		if (err) {
 			printk(KERN_DEBUG "%s: failed to insert STA entry for"
-			       " the AP (error %d)\n", dev->name, err);
+			       " the AP (error %d)\n", sdata->dev->name, err);
 			rcu_read_unlock();
 			return;
 		}
@@ -2152,8 +1334,8 @@
 		}
 	}
 
-	sta->supp_rates[local->hw.conf.channel->band] = rates;
-	sdata->basic_rates = basic_rates;
+	sta->sta.supp_rates[local->hw.conf.channel->band] = rates;
+	sdata->bss_conf.basic_rates = basic_rates;
 
 	/* cf. IEEE 802.11 9.2.12 */
 	if (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ &&
@@ -2167,19 +1349,19 @@
 		struct ieee80211_ht_bss_info bss_info;
 		ieee80211_ht_cap_ie_to_ht_info(
 				(struct ieee80211_ht_cap *)
-				elems.ht_cap_elem, &sta->ht_info);
+				elems.ht_cap_elem, &sta->sta.ht_info);
 		ieee80211_ht_addt_info_ie_to_ht_bss_info(
 				(struct ieee80211_ht_addt_info *)
 				elems.ht_info_elem, &bss_info);
-		ieee80211_handle_ht(local, 1, &sta->ht_info, &bss_info);
+		ieee80211_handle_ht(local, 1, &sta->sta.ht_info, &bss_info);
 	}
 
-	rate_control_rate_init(sta, local);
+	rate_control_rate_init(sta);
 
 	if (elems.wmm_param) {
 		set_sta_flags(sta, WLAN_STA_WME);
 		rcu_read_unlock();
-		ieee80211_sta_wmm_params(dev, ifsta, elems.wmm_param,
+		ieee80211_sta_wmm_params(local, ifsta, elems.wmm_param,
 					 elems.wmm_param_len);
 	} else
 		rcu_read_unlock();
@@ -2188,234 +1370,26 @@
 	 * ieee80211_set_associated() will tell the driver */
 	bss_conf->aid = aid;
 	bss_conf->assoc_capability = capab_info;
-	ieee80211_set_associated(dev, ifsta, 1);
+	ieee80211_set_associated(sdata, ifsta);
 
-	ieee80211_associated(dev, ifsta);
+	ieee80211_associated(sdata, ifsta);
 }
 
 
-/* Caller must hold local->sta_bss_lock */
-static void __ieee80211_rx_bss_hash_add(struct net_device *dev,
-					struct ieee80211_sta_bss *bss)
-{
-	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-	u8 hash_idx;
-
-	if (bss_mesh_cfg(bss))
-		hash_idx = mesh_id_hash(bss_mesh_id(bss),
-					bss_mesh_id_len(bss));
-	else
-		hash_idx = STA_HASH(bss->bssid);
-
-	bss->hnext = local->sta_bss_hash[hash_idx];
-	local->sta_bss_hash[hash_idx] = bss;
-}
-
-
-/* Caller must hold local->sta_bss_lock */
-static void __ieee80211_rx_bss_hash_del(struct ieee80211_local *local,
-					struct ieee80211_sta_bss *bss)
-{
-	struct ieee80211_sta_bss *b, *prev = NULL;
-	b = local->sta_bss_hash[STA_HASH(bss->bssid)];
-	while (b) {
-		if (b == bss) {
-			if (!prev)
-				local->sta_bss_hash[STA_HASH(bss->bssid)] =
-					bss->hnext;
-			else
-				prev->hnext = bss->hnext;
-			break;
-		}
-		prev = b;
-		b = b->hnext;
-	}
-}
-
-
-static struct ieee80211_sta_bss *
-ieee80211_rx_bss_add(struct net_device *dev, u8 *bssid, int freq,
-		     u8 *ssid, u8 ssid_len)
-{
-	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-	struct ieee80211_sta_bss *bss;
-
-	bss = kzalloc(sizeof(*bss), GFP_ATOMIC);
-	if (!bss)
-		return NULL;
-	atomic_inc(&bss->users);
-	atomic_inc(&bss->users);
-	memcpy(bss->bssid, bssid, ETH_ALEN);
-	bss->freq = freq;
-	if (ssid && ssid_len <= IEEE80211_MAX_SSID_LEN) {
-		memcpy(bss->ssid, ssid, ssid_len);
-		bss->ssid_len = ssid_len;
-	}
-
-	spin_lock_bh(&local->sta_bss_lock);
-	/* TODO: order by RSSI? */
-	list_add_tail(&bss->list, &local->sta_bss_list);
-	__ieee80211_rx_bss_hash_add(dev, bss);
-	spin_unlock_bh(&local->sta_bss_lock);
-	return bss;
-}
-
-static struct ieee80211_sta_bss *
-ieee80211_rx_bss_get(struct net_device *dev, u8 *bssid, int freq,
-		     u8 *ssid, u8 ssid_len)
-{
-	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-	struct ieee80211_sta_bss *bss;
-
-	spin_lock_bh(&local->sta_bss_lock);
-	bss = local->sta_bss_hash[STA_HASH(bssid)];
-	while (bss) {
-		if (!bss_mesh_cfg(bss) &&
-		    !memcmp(bss->bssid, bssid, ETH_ALEN) &&
-		    bss->freq == freq &&
-		    bss->ssid_len == ssid_len &&
-		    (ssid_len == 0 || !memcmp(bss->ssid, ssid, ssid_len))) {
-			atomic_inc(&bss->users);
-			break;
-		}
-		bss = bss->hnext;
-	}
-	spin_unlock_bh(&local->sta_bss_lock);
-	return bss;
-}
-
-#ifdef CONFIG_MAC80211_MESH
-static struct ieee80211_sta_bss *
-ieee80211_rx_mesh_bss_get(struct net_device *dev, u8 *mesh_id, int mesh_id_len,
-			  u8 *mesh_cfg, int freq)
-{
-	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-	struct ieee80211_sta_bss *bss;
-
-	spin_lock_bh(&local->sta_bss_lock);
-	bss = local->sta_bss_hash[mesh_id_hash(mesh_id, mesh_id_len)];
-	while (bss) {
-		if (bss_mesh_cfg(bss) &&
-		    !memcmp(bss_mesh_cfg(bss), mesh_cfg, MESH_CFG_CMP_LEN) &&
-		    bss->freq == freq &&
-		    mesh_id_len == bss->mesh_id_len &&
-		    (mesh_id_len == 0 || !memcmp(bss->mesh_id, mesh_id,
-						 mesh_id_len))) {
-			atomic_inc(&bss->users);
-			break;
-		}
-		bss = bss->hnext;
-	}
-	spin_unlock_bh(&local->sta_bss_lock);
-	return bss;
-}
-
-static struct ieee80211_sta_bss *
-ieee80211_rx_mesh_bss_add(struct net_device *dev, u8 *mesh_id, int mesh_id_len,
-			  u8 *mesh_cfg, int mesh_config_len, int freq)
-{
-	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-	struct ieee80211_sta_bss *bss;
-
-	if (mesh_config_len != MESH_CFG_LEN)
-		return NULL;
-
-	bss = kzalloc(sizeof(*bss), GFP_ATOMIC);
-	if (!bss)
-		return NULL;
-
-	bss->mesh_cfg = kmalloc(MESH_CFG_CMP_LEN, GFP_ATOMIC);
-	if (!bss->mesh_cfg) {
-		kfree(bss);
-		return NULL;
-	}
-
-	if (mesh_id_len && mesh_id_len <= IEEE80211_MAX_MESH_ID_LEN) {
-		bss->mesh_id = kmalloc(mesh_id_len, GFP_ATOMIC);
-		if (!bss->mesh_id) {
-			kfree(bss->mesh_cfg);
-			kfree(bss);
-			return NULL;
-		}
-		memcpy(bss->mesh_id, mesh_id, mesh_id_len);
-	}
-
-	atomic_inc(&bss->users);
-	atomic_inc(&bss->users);
-	memcpy(bss->mesh_cfg, mesh_cfg, MESH_CFG_CMP_LEN);
-	bss->mesh_id_len = mesh_id_len;
-	bss->freq = freq;
-	spin_lock_bh(&local->sta_bss_lock);
-	/* TODO: order by RSSI? */
-	list_add_tail(&bss->list, &local->sta_bss_list);
-	__ieee80211_rx_bss_hash_add(dev, bss);
-	spin_unlock_bh(&local->sta_bss_lock);
-	return bss;
-}
-#endif
-
-static void ieee80211_rx_bss_free(struct ieee80211_sta_bss *bss)
-{
-	kfree(bss->wpa_ie);
-	kfree(bss->rsn_ie);
-	kfree(bss->wmm_ie);
-	kfree(bss->ht_ie);
-	kfree(bss->ht_add_ie);
-	kfree(bss_mesh_id(bss));
-	kfree(bss_mesh_cfg(bss));
-	kfree(bss);
-}
-
-
-static void ieee80211_rx_bss_put(struct ieee80211_local *local,
-				 struct ieee80211_sta_bss *bss)
-{
-	local_bh_disable();
-	if (!atomic_dec_and_lock(&bss->users, &local->sta_bss_lock)) {
-		local_bh_enable();
-		return;
-	}
-
-	__ieee80211_rx_bss_hash_del(local, bss);
-	list_del(&bss->list);
-	spin_unlock_bh(&local->sta_bss_lock);
-	ieee80211_rx_bss_free(bss);
-}
-
-
-void ieee80211_rx_bss_list_init(struct ieee80211_local *local)
-{
-	spin_lock_init(&local->sta_bss_lock);
-	INIT_LIST_HEAD(&local->sta_bss_list);
-}
-
-
-void ieee80211_rx_bss_list_deinit(struct ieee80211_local *local)
-{
-	struct ieee80211_sta_bss *bss, *tmp;
-
-	list_for_each_entry_safe(bss, tmp, &local->sta_bss_list, list)
-		ieee80211_rx_bss_put(local, bss);
-}
-
-
-static int ieee80211_sta_join_ibss(struct net_device *dev,
+static int ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
 				   struct ieee80211_if_sta *ifsta,
-				   struct ieee80211_sta_bss *bss)
+				   struct ieee80211_bss *bss)
 {
-	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct ieee80211_local *local = sdata->local;
 	int res, rates, i, j;
 	struct sk_buff *skb;
 	struct ieee80211_mgmt *mgmt;
 	u8 *pos;
-	struct ieee80211_sub_if_data *sdata;
 	struct ieee80211_supported_band *sband;
 	union iwreq_data wrqu;
 
 	sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
 
-	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-
 	/* Remove possible STA entries from other IBSS networks. */
 	sta_info_flush_delayed(sdata);
 
@@ -2433,7 +1407,7 @@
 	sdata->drop_unencrypted = bss->capability &
 		WLAN_CAPABILITY_PRIVACY ? 1 : 0;
 
-	res = ieee80211_set_freq(dev, bss->freq);
+	res = ieee80211_set_freq(sdata, bss->freq);
 
 	if (res)
 		return res;
@@ -2446,10 +1420,10 @@
 		mgmt = (struct ieee80211_mgmt *)
 			skb_put(skb, 24 + sizeof(mgmt->u.beacon));
 		memset(mgmt, 0, 24 + sizeof(mgmt->u.beacon));
-		mgmt->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT,
-						   IEEE80211_STYPE_PROBE_RESP);
+		mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
+						  IEEE80211_STYPE_PROBE_RESP);
 		memset(mgmt->da, 0xff, ETH_ALEN);
-		memcpy(mgmt->sa, dev->dev_addr, ETH_ALEN);
+		memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
 		memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN);
 		mgmt->u.beacon.beacon_int =
 			cpu_to_le16(local->hw.conf.beacon_int);
@@ -2506,108 +1480,38 @@
 	}
 	ifsta->supp_rates_bits[local->hw.conf.channel->band] = rates;
 
-	ieee80211_sta_def_wmm_params(dev, bss, 1);
+	ieee80211_sta_def_wmm_params(sdata, bss);
 
-	ifsta->state = IEEE80211_IBSS_JOINED;
+	ifsta->state = IEEE80211_STA_MLME_IBSS_JOINED;
 	mod_timer(&ifsta->timer, jiffies + IEEE80211_IBSS_MERGE_INTERVAL);
 
+	ieee80211_led_assoc(local, true);
+
 	memset(&wrqu, 0, sizeof(wrqu));
 	memcpy(wrqu.ap_addr.sa_data, bss->bssid, ETH_ALEN);
-	wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL);
+	wireless_send_event(sdata->dev, SIOCGIWAP, &wrqu, NULL);
 
 	return res;
 }
 
-u64 ieee80211_sta_get_rates(struct ieee80211_local *local,
-			    struct ieee802_11_elems *elems,
-			    enum ieee80211_band band)
-{
-	struct ieee80211_supported_band *sband;
-	struct ieee80211_rate *bitrates;
-	size_t num_rates;
-	u64 supp_rates;
-	int i, j;
-	sband = local->hw.wiphy->bands[band];
-
-	if (!sband) {
-		WARN_ON(1);
-		sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
-	}
-
-	bitrates = sband->bitrates;
-	num_rates = sband->n_bitrates;
-	supp_rates = 0;
-	for (i = 0; i < elems->supp_rates_len +
-		     elems->ext_supp_rates_len; i++) {
-		u8 rate = 0;
-		int own_rate;
-		if (i < elems->supp_rates_len)
-			rate = elems->supp_rates[i];
-		else if (elems->ext_supp_rates)
-			rate = elems->ext_supp_rates
-				[i - elems->supp_rates_len];
-		own_rate = 5 * (rate & 0x7f);
-		for (j = 0; j < num_rates; j++)
-			if (bitrates[j].bitrate == own_rate)
-				supp_rates |= BIT(j);
-	}
-	return supp_rates;
-}
-
-
-static void ieee80211_rx_bss_info(struct net_device *dev,
+static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
 				  struct ieee80211_mgmt *mgmt,
 				  size_t len,
 				  struct ieee80211_rx_status *rx_status,
 				  struct ieee802_11_elems *elems,
-				  int beacon)
+				  bool beacon)
 {
-	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-	int freq, clen;
-	struct ieee80211_sta_bss *bss;
+	struct ieee80211_local *local = sdata->local;
+	int freq;
+	struct ieee80211_bss *bss;
 	struct sta_info *sta;
-	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-	u64 beacon_timestamp, rx_timestamp;
 	struct ieee80211_channel *channel;
+	u64 beacon_timestamp, rx_timestamp;
+	u64 supp_rates = 0;
+	enum ieee80211_band band = rx_status->band;
 	DECLARE_MAC_BUF(mac);
 	DECLARE_MAC_BUF(mac2);
 
-	if (!beacon && memcmp(mgmt->da, dev->dev_addr, ETH_ALEN))
-		return; /* ignore ProbeResp to foreign address */
-
-	beacon_timestamp = le64_to_cpu(mgmt->u.beacon.timestamp);
-
-	if (ieee80211_vif_is_mesh(&sdata->vif) && elems->mesh_id &&
-	    elems->mesh_config && mesh_matches_local(elems, dev)) {
-		u64 rates = ieee80211_sta_get_rates(local, elems,
-						rx_status->band);
-
-		mesh_neighbour_update(mgmt->sa, rates, dev,
-				      mesh_peer_accepts_plinks(elems, dev));
-	}
-
-	rcu_read_lock();
-
-	if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS && elems->supp_rates &&
-	    memcmp(mgmt->bssid, sdata->u.sta.bssid, ETH_ALEN) == 0 &&
-	    (sta = sta_info_get(local, mgmt->sa))) {
-		u64 prev_rates;
-		u64 supp_rates = ieee80211_sta_get_rates(local, elems,
-							rx_status->band);
-
-		prev_rates = sta->supp_rates[rx_status->band];
-		sta->supp_rates[rx_status->band] &= supp_rates;
-		if (sta->supp_rates[rx_status->band] == 0) {
-			/* No matching rates - this should not really happen.
-			 * Make sure that at least one rate is marked
-			 * supported to avoid issues with TX rate ctrl. */
-			sta->supp_rates[rx_status->band] =
-				sdata->u.sta.supp_rates_bits[rx_status->band];
-		}
-	}
-
-	rcu_read_unlock();
-
 	if (elems->ds_params && elems->ds_params_len == 1)
 		freq = ieee80211_channel_to_frequency(elems->ds_params[0]);
 	else
@@ -2618,215 +1522,60 @@
 	if (!channel || channel->flags & IEEE80211_CHAN_DISABLED)
 		return;
 
-#ifdef CONFIG_MAC80211_MESH
-	if (elems->mesh_config)
-		bss = ieee80211_rx_mesh_bss_get(dev, elems->mesh_id,
-				elems->mesh_id_len, elems->mesh_config, freq);
-	else
+	if (sdata->vif.type == NL80211_IFTYPE_ADHOC && elems->supp_rates &&
+	    memcmp(mgmt->bssid, sdata->u.sta.bssid, ETH_ALEN) == 0) {
+		supp_rates = ieee80211_sta_get_rates(local, elems, band);
+
+		rcu_read_lock();
+
+		sta = sta_info_get(local, mgmt->sa);
+		if (sta) {
+			u64 prev_rates;
+
+			prev_rates = sta->sta.supp_rates[band];
+			/* make sure mandatory rates are always added */
+			sta->sta.supp_rates[band] = supp_rates |
+				ieee80211_mandatory_rates(local, band);
+
+#ifdef CONFIG_MAC80211_IBSS_DEBUG
+			if (sta->sta.supp_rates[band] != prev_rates)
+				printk(KERN_DEBUG "%s: updated supp_rates set "
+				    "for %s based on beacon info (0x%llx | "
+				    "0x%llx -> 0x%llx)\n",
+				    sdata->dev->name,
+				    print_mac(mac, sta->sta.addr),
+				    (unsigned long long) prev_rates,
+				    (unsigned long long) supp_rates,
+				    (unsigned long long) sta->sta.supp_rates[band]);
 #endif
-		bss = ieee80211_rx_bss_get(dev, mgmt->bssid, freq,
-					   elems->ssid, elems->ssid_len);
-	if (!bss) {
-#ifdef CONFIG_MAC80211_MESH
-		if (elems->mesh_config)
-			bss = ieee80211_rx_mesh_bss_add(dev, elems->mesh_id,
-				elems->mesh_id_len, elems->mesh_config,
-				elems->mesh_config_len, freq);
-		else
-#endif
-			bss = ieee80211_rx_bss_add(dev, mgmt->bssid, freq,
-						  elems->ssid, elems->ssid_len);
-		if (!bss)
-			return;
-	} else {
-#if 0
-		/* TODO: order by RSSI? */
-		spin_lock_bh(&local->sta_bss_lock);
-		list_move_tail(&bss->list, &local->sta_bss_list);
-		spin_unlock_bh(&local->sta_bss_lock);
-#endif
+		} else {
+			ieee80211_ibss_add_sta(sdata, NULL, mgmt->bssid,
+					       mgmt->sa, supp_rates);
+		}
+
+		rcu_read_unlock();
 	}
 
-	/* save the ERP value so that it is available at association time */
-	if (elems->erp_info && elems->erp_info_len >= 1) {
-		bss->erp_value = elems->erp_info[0];
-		bss->has_erp_value = 1;
-	}
+	bss = ieee80211_bss_info_update(local, rx_status, mgmt, len, elems,
+					freq, beacon);
+	if (!bss)
+		return;
 
-	if (elems->ht_cap_elem &&
-	     (!bss->ht_ie || bss->ht_ie_len != elems->ht_cap_elem_len ||
-	     memcmp(bss->ht_ie, elems->ht_cap_elem, elems->ht_cap_elem_len))) {
-		kfree(bss->ht_ie);
-		bss->ht_ie = kmalloc(elems->ht_cap_elem_len + 2, GFP_ATOMIC);
-		if (bss->ht_ie) {
-			memcpy(bss->ht_ie, elems->ht_cap_elem - 2,
-				elems->ht_cap_elem_len + 2);
-			bss->ht_ie_len = elems->ht_cap_elem_len + 2;
-		} else
-			bss->ht_ie_len = 0;
-	} else if (!elems->ht_cap_elem && bss->ht_ie) {
-		kfree(bss->ht_ie);
-		bss->ht_ie = NULL;
-		bss->ht_ie_len = 0;
-	}
-
-	if (elems->ht_info_elem &&
-	     (!bss->ht_add_ie ||
-	     bss->ht_add_ie_len != elems->ht_info_elem_len ||
-	     memcmp(bss->ht_add_ie, elems->ht_info_elem,
-			elems->ht_info_elem_len))) {
-		kfree(bss->ht_add_ie);
-		bss->ht_add_ie =
-			kmalloc(elems->ht_info_elem_len + 2, GFP_ATOMIC);
-		if (bss->ht_add_ie) {
-			memcpy(bss->ht_add_ie, elems->ht_info_elem - 2,
-				elems->ht_info_elem_len + 2);
-			bss->ht_add_ie_len = elems->ht_info_elem_len + 2;
-		} else
-			bss->ht_add_ie_len = 0;
-	} else if (!elems->ht_info_elem && bss->ht_add_ie) {
-		kfree(bss->ht_add_ie);
-		bss->ht_add_ie = NULL;
-		bss->ht_add_ie_len = 0;
-	}
-
-	bss->beacon_int = le16_to_cpu(mgmt->u.beacon.beacon_int);
-	bss->capability = le16_to_cpu(mgmt->u.beacon.capab_info);
-
-	if (elems->tim) {
-		struct ieee80211_tim_ie *tim_ie =
-			(struct ieee80211_tim_ie *)elems->tim;
-		bss->dtim_period = tim_ie->dtim_period;
-	}
-
-	/* set default value for buggy APs */
-	if (!elems->tim || bss->dtim_period == 0)
-		bss->dtim_period = 1;
-
-	bss->supp_rates_len = 0;
-	if (elems->supp_rates) {
-		clen = IEEE80211_MAX_SUPP_RATES - bss->supp_rates_len;
-		if (clen > elems->supp_rates_len)
-			clen = elems->supp_rates_len;
-		memcpy(&bss->supp_rates[bss->supp_rates_len], elems->supp_rates,
-		       clen);
-		bss->supp_rates_len += clen;
-	}
-	if (elems->ext_supp_rates) {
-		clen = IEEE80211_MAX_SUPP_RATES - bss->supp_rates_len;
-		if (clen > elems->ext_supp_rates_len)
-			clen = elems->ext_supp_rates_len;
-		memcpy(&bss->supp_rates[bss->supp_rates_len],
-		       elems->ext_supp_rates, clen);
-		bss->supp_rates_len += clen;
-	}
-
-	bss->band = rx_status->band;
-
-	bss->timestamp = beacon_timestamp;
-	bss->last_update = jiffies;
-	bss->signal = rx_status->signal;
-	bss->noise = rx_status->noise;
-	bss->qual = rx_status->qual;
-	if (!beacon && !bss->probe_resp)
-		bss->probe_resp = true;
+	/* was just updated in ieee80211_bss_info_update */
+	beacon_timestamp = bss->timestamp;
 
 	/*
 	 * In STA mode, the remaining parameters should not be overridden
 	 * by beacons because they're not necessarily accurate there.
 	 */
-	if (sdata->vif.type != IEEE80211_IF_TYPE_IBSS &&
-	    bss->probe_resp && beacon) {
+	if (sdata->vif.type != NL80211_IFTYPE_ADHOC &&
+	    bss->last_probe_resp && beacon) {
 		ieee80211_rx_bss_put(local, bss);
 		return;
 	}
 
-	if (elems->wpa &&
-	    (!bss->wpa_ie || bss->wpa_ie_len != elems->wpa_len ||
-	     memcmp(bss->wpa_ie, elems->wpa, elems->wpa_len))) {
-		kfree(bss->wpa_ie);
-		bss->wpa_ie = kmalloc(elems->wpa_len + 2, GFP_ATOMIC);
-		if (bss->wpa_ie) {
-			memcpy(bss->wpa_ie, elems->wpa - 2, elems->wpa_len + 2);
-			bss->wpa_ie_len = elems->wpa_len + 2;
-		} else
-			bss->wpa_ie_len = 0;
-	} else if (!elems->wpa && bss->wpa_ie) {
-		kfree(bss->wpa_ie);
-		bss->wpa_ie = NULL;
-		bss->wpa_ie_len = 0;
-	}
-
-	if (elems->rsn &&
-	    (!bss->rsn_ie || bss->rsn_ie_len != elems->rsn_len ||
-	     memcmp(bss->rsn_ie, elems->rsn, elems->rsn_len))) {
-		kfree(bss->rsn_ie);
-		bss->rsn_ie = kmalloc(elems->rsn_len + 2, GFP_ATOMIC);
-		if (bss->rsn_ie) {
-			memcpy(bss->rsn_ie, elems->rsn - 2, elems->rsn_len + 2);
-			bss->rsn_ie_len = elems->rsn_len + 2;
-		} else
-			bss->rsn_ie_len = 0;
-	} else if (!elems->rsn && bss->rsn_ie) {
-		kfree(bss->rsn_ie);
-		bss->rsn_ie = NULL;
-		bss->rsn_ie_len = 0;
-	}
-
-	/*
-	 * Cf.
-	 * http://www.wipo.int/pctdb/en/wo.jsp?wo=2007047181&IA=WO2007047181&DISPLAY=DESC
-	 *
-	 * quoting:
-	 *
-	 * In particular, "Wi-Fi CERTIFIED for WMM - Support for Multimedia
-	 * Applications with Quality of Service in Wi-Fi Networks," Wi- Fi
-	 * Alliance (September 1, 2004) is incorporated by reference herein.
-	 * The inclusion of the WMM Parameters in probe responses and
-	 * association responses is mandatory for WMM enabled networks. The
-	 * inclusion of the WMM Parameters in beacons, however, is optional.
-	 */
-
-	if (elems->wmm_param &&
-	    (!bss->wmm_ie || bss->wmm_ie_len != elems->wmm_param_len ||
-	     memcmp(bss->wmm_ie, elems->wmm_param, elems->wmm_param_len))) {
-		kfree(bss->wmm_ie);
-		bss->wmm_ie = kmalloc(elems->wmm_param_len + 2, GFP_ATOMIC);
-		if (bss->wmm_ie) {
-			memcpy(bss->wmm_ie, elems->wmm_param - 2,
-			       elems->wmm_param_len + 2);
-			bss->wmm_ie_len = elems->wmm_param_len + 2;
-		} else
-			bss->wmm_ie_len = 0;
-	} else if (elems->wmm_info &&
-		    (!bss->wmm_ie || bss->wmm_ie_len != elems->wmm_info_len ||
-		     memcmp(bss->wmm_ie, elems->wmm_info,
-						elems->wmm_info_len))) {
-		 /* As for certain AP's Fifth bit is not set in WMM IE in
-		  * beacon frames.So while parsing the beacon frame the
-		  * wmm_info structure is used instead of wmm_param.
-		  * wmm_info structure was never used to set bss->wmm_ie.
-		  * This code fixes this problem by copying the WME
-		  * information from wmm_info to bss->wmm_ie and enabling
-		  * n-band association.
-		  */
-		kfree(bss->wmm_ie);
-		bss->wmm_ie = kmalloc(elems->wmm_info_len + 2, GFP_ATOMIC);
-		if (bss->wmm_ie) {
-			memcpy(bss->wmm_ie, elems->wmm_info - 2,
-			       elems->wmm_info_len + 2);
-			bss->wmm_ie_len = elems->wmm_info_len + 2;
-		} else
-			bss->wmm_ie_len = 0;
-	} else if (!elems->wmm_param && !elems->wmm_info && bss->wmm_ie) {
-		kfree(bss->wmm_ie);
-		bss->wmm_ie = NULL;
-		bss->wmm_ie_len = 0;
-	}
-
 	/* check if we need to merge IBSS */
-	if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS && beacon &&
-	    !local->sta_sw_scanning && !local->sta_hw_scanning &&
+	if (sdata->vif.type == NL80211_IFTYPE_ADHOC && beacon &&
 	    bss->capability & WLAN_CAPABILITY_IBSS &&
 	    bss->freq == local->oper_channel->center_freq &&
 	    elems->ssid_len == sdata->u.sta.ssid_len &&
@@ -2848,7 +1597,7 @@
 			 * e.g: at 1 MBit that means mactime is 192 usec earlier
 			 * (=24 bytes * 8 usecs/byte) than the beacon timestamp.
 			 */
-			int rate = local->hw.wiphy->bands[rx_status->band]->
+			int rate = local->hw.wiphy->bands[band]->
 					bitrates[rx_status->rate_idx].bitrate;
 			rx_timestamp = rx_status->mactime + (24 * 8 * 10 / rate);
 		} else if (local && local->ops && local->ops->get_tsf)
@@ -2871,12 +1620,12 @@
 #ifdef CONFIG_MAC80211_IBSS_DEBUG
 			printk(KERN_DEBUG "%s: beacon TSF higher than "
 			       "local TSF - IBSS merge with BSSID %s\n",
-			       dev->name, print_mac(mac, mgmt->bssid));
+			       sdata->dev->name, print_mac(mac, mgmt->bssid));
 #endif
-			ieee80211_sta_join_ibss(dev, &sdata->u.sta, bss);
-			ieee80211_ibss_add_sta(dev, NULL,
+			ieee80211_sta_join_ibss(sdata, &sdata->u.sta, bss);
+			ieee80211_ibss_add_sta(sdata, NULL,
 					       mgmt->bssid, mgmt->sa,
-					       BIT(rx_status->rate_idx));
+					       supp_rates);
 		}
 	}
 
@@ -2884,13 +1633,17 @@
 }
 
 
-static void ieee80211_rx_mgmt_probe_resp(struct net_device *dev,
+static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata,
 					 struct ieee80211_mgmt *mgmt,
 					 size_t len,
 					 struct ieee80211_rx_status *rx_status)
 {
 	size_t baselen;
 	struct ieee802_11_elems elems;
+	struct ieee80211_if_sta *ifsta = &sdata->u.sta;
+
+	if (memcmp(mgmt->da, sdata->dev->dev_addr, ETH_ALEN))
+		return; /* ignore ProbeResp to foreign address */
 
 	baselen = (u8 *) mgmt->u.probe_resp.variable - (u8 *) mgmt;
 	if (baselen > len)
@@ -2899,20 +1652,27 @@
 	ieee802_11_parse_elems(mgmt->u.probe_resp.variable, len - baselen,
 				&elems);
 
-	ieee80211_rx_bss_info(dev, mgmt, len, rx_status, &elems, 0);
+	ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems, false);
+
+	/* direct probe may be part of the association flow */
+	if (test_and_clear_bit(IEEE80211_STA_REQ_DIRECT_PROBE,
+							&ifsta->request)) {
+		printk(KERN_DEBUG "%s direct probe responded\n",
+		       sdata->dev->name);
+		ieee80211_authenticate(sdata, ifsta);
+	}
 }
 
 
-static void ieee80211_rx_mgmt_beacon(struct net_device *dev,
+static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
 				     struct ieee80211_mgmt *mgmt,
 				     size_t len,
 				     struct ieee80211_rx_status *rx_status)
 {
-	struct ieee80211_sub_if_data *sdata;
 	struct ieee80211_if_sta *ifsta;
 	size_t baselen;
 	struct ieee802_11_elems elems;
-	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct ieee80211_local *local = sdata->local;
 	struct ieee80211_conf *conf = &local->hw.conf;
 	u32 changed = 0;
 
@@ -2923,10 +1683,9 @@
 
 	ieee802_11_parse_elems(mgmt->u.beacon.variable, len - baselen, &elems);
 
-	ieee80211_rx_bss_info(dev, mgmt, len, rx_status, &elems, 1);
+	ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems, true);
 
-	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-	if (sdata->vif.type != IEEE80211_IF_TYPE_STA)
+	if (sdata->vif.type != NL80211_IFTYPE_STATION)
 		return;
 	ifsta = &sdata->u.sta;
 
@@ -2934,15 +1693,9 @@
 	    memcmp(ifsta->bssid, mgmt->bssid, ETH_ALEN) != 0)
 		return;
 
-	ieee80211_sta_wmm_params(dev, ifsta, elems.wmm_param,
+	ieee80211_sta_wmm_params(local, ifsta, elems.wmm_param,
 				 elems.wmm_param_len);
 
-	/* Do not send changes to driver if we are scanning. This removes
-	 * requirement that driver's bss_info_changed function needs to be
-	 * atomic. */
-	if (local->sta_sw_scanning || local->sta_hw_scanning)
-		return;
-
 	if (elems.erp_info && elems.erp_info_len >= 1)
 		changed |= ieee80211_handle_erp_ie(sdata, elems.erp_info[0]);
 	else {
@@ -2966,14 +1719,13 @@
 }
 
 
-static void ieee80211_rx_mgmt_probe_req(struct net_device *dev,
+static void ieee80211_rx_mgmt_probe_req(struct ieee80211_sub_if_data *sdata,
 					struct ieee80211_if_sta *ifsta,
 					struct ieee80211_mgmt *mgmt,
 					size_t len,
 					struct ieee80211_rx_status *rx_status)
 {
-	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	struct ieee80211_local *local = sdata->local;
 	int tx_last_beacon;
 	struct sk_buff *skb;
 	struct ieee80211_mgmt *resp;
@@ -2984,8 +1736,8 @@
 	DECLARE_MAC_BUF(mac3);
 #endif
 
-	if (sdata->vif.type != IEEE80211_IF_TYPE_IBSS ||
-	    ifsta->state != IEEE80211_IBSS_JOINED ||
+	if (sdata->vif.type != NL80211_IFTYPE_ADHOC ||
+	    ifsta->state != IEEE80211_STA_MLME_IBSS_JOINED ||
 	    len < 24 + 2 || !ifsta->probe_resp)
 		return;
 
@@ -2997,7 +1749,7 @@
 #ifdef CONFIG_MAC80211_IBSS_DEBUG
 	printk(KERN_DEBUG "%s: RX ProbeReq SA=%s DA=%s BSSID="
 	       "%s (tx_last_beacon=%d)\n",
-	       dev->name, print_mac(mac, mgmt->sa), print_mac(mac2, mgmt->da),
+	       sdata->dev->name, print_mac(mac, mgmt->sa), print_mac(mac2, mgmt->da),
 	       print_mac(mac3, mgmt->bssid), tx_last_beacon);
 #endif /* CONFIG_MAC80211_IBSS_DEBUG */
 
@@ -3015,7 +1767,7 @@
 #ifdef CONFIG_MAC80211_IBSS_DEBUG
 		printk(KERN_DEBUG "%s: Invalid SSID IE in ProbeReq "
 		       "from %s\n",
-		       dev->name, print_mac(mac, mgmt->sa));
+		       sdata->dev->name, print_mac(mac, mgmt->sa));
 #endif
 		return;
 	}
@@ -3035,74 +1787,15 @@
 	memcpy(resp->da, mgmt->sa, ETH_ALEN);
 #ifdef CONFIG_MAC80211_IBSS_DEBUG
 	printk(KERN_DEBUG "%s: Sending ProbeResp to %s\n",
-	       dev->name, print_mac(mac, resp->da));
+	       sdata->dev->name, print_mac(mac, resp->da));
 #endif /* CONFIG_MAC80211_IBSS_DEBUG */
-	ieee80211_sta_tx(dev, skb, 0);
+	ieee80211_tx_skb(sdata, skb, 0);
 }
 
-static void ieee80211_rx_mgmt_action(struct net_device *dev,
-				     struct ieee80211_if_sta *ifsta,
-				     struct ieee80211_mgmt *mgmt,
-				     size_t len,
-				     struct ieee80211_rx_status *rx_status)
-{
-	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-
-	if (len < IEEE80211_MIN_ACTION_SIZE)
-		return;
-
-	switch (mgmt->u.action.category) {
-	case WLAN_CATEGORY_SPECTRUM_MGMT:
-		if (local->hw.conf.channel->band != IEEE80211_BAND_5GHZ)
-			break;
-		switch (mgmt->u.action.u.chan_switch.action_code) {
-		case WLAN_ACTION_SPCT_MSR_REQ:
-			if (len < (IEEE80211_MIN_ACTION_SIZE +
-				   sizeof(mgmt->u.action.u.measurement)))
-				break;
-			ieee80211_sta_process_measurement_req(dev, mgmt, len);
-			break;
-		}
-		break;
-	case WLAN_CATEGORY_BACK:
-		switch (mgmt->u.action.u.addba_req.action_code) {
-		case WLAN_ACTION_ADDBA_REQ:
-			if (len < (IEEE80211_MIN_ACTION_SIZE +
-				   sizeof(mgmt->u.action.u.addba_req)))
-				break;
-			ieee80211_sta_process_addba_request(dev, mgmt, len);
-			break;
-		case WLAN_ACTION_ADDBA_RESP:
-			if (len < (IEEE80211_MIN_ACTION_SIZE +
-				   sizeof(mgmt->u.action.u.addba_resp)))
-				break;
-			ieee80211_sta_process_addba_resp(dev, mgmt, len);
-			break;
-		case WLAN_ACTION_DELBA:
-			if (len < (IEEE80211_MIN_ACTION_SIZE +
-				   sizeof(mgmt->u.action.u.delba)))
-				break;
-			ieee80211_sta_process_delba(dev, mgmt, len);
-			break;
-		}
-		break;
-	case PLINK_CATEGORY:
-		if (ieee80211_vif_is_mesh(&sdata->vif))
-			mesh_rx_plink_frame(dev, mgmt, len, rx_status);
-		break;
-	case MESH_PATH_SEL_CATEGORY:
-		if (ieee80211_vif_is_mesh(&sdata->vif))
-			mesh_rx_path_sel_frame(dev, mgmt, len);
-		break;
-	}
-}
-
-void ieee80211_sta_rx_mgmt(struct net_device *dev, struct sk_buff *skb,
+void ieee80211_sta_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb,
 			   struct ieee80211_rx_status *rx_status)
 {
-	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-	struct ieee80211_sub_if_data *sdata;
+	struct ieee80211_local *local = sdata->local;
 	struct ieee80211_if_sta *ifsta;
 	struct ieee80211_mgmt *mgmt;
 	u16 fc;
@@ -3110,7 +1803,6 @@
 	if (skb->len < 24)
 		goto fail;
 
-	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 	ifsta = &sdata->u.sta;
 
 	mgmt = (struct ieee80211_mgmt *) skb->data;
@@ -3120,7 +1812,6 @@
 	case IEEE80211_STYPE_PROBE_REQ:
 	case IEEE80211_STYPE_PROBE_RESP:
 	case IEEE80211_STYPE_BEACON:
-	case IEEE80211_STYPE_ACTION:
 		memcpy(skb->cb, rx_status, sizeof(*rx_status));
 	case IEEE80211_STYPE_AUTH:
 	case IEEE80211_STYPE_ASSOC_RESP:
@@ -3136,17 +1827,14 @@
 	kfree_skb(skb);
 }
 
-
-static void ieee80211_sta_rx_queued_mgmt(struct net_device *dev,
+static void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
 					 struct sk_buff *skb)
 {
 	struct ieee80211_rx_status *rx_status;
-	struct ieee80211_sub_if_data *sdata;
 	struct ieee80211_if_sta *ifsta;
 	struct ieee80211_mgmt *mgmt;
 	u16 fc;
 
-	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 	ifsta = &sdata->u.sta;
 
 	rx_status = (struct ieee80211_rx_status *) skb->cb;
@@ -3155,17 +1843,17 @@
 
 	switch (fc & IEEE80211_FCTL_STYPE) {
 	case IEEE80211_STYPE_PROBE_REQ:
-		ieee80211_rx_mgmt_probe_req(dev, ifsta, mgmt, skb->len,
+		ieee80211_rx_mgmt_probe_req(sdata, ifsta, mgmt, skb->len,
 					    rx_status);
 		break;
 	case IEEE80211_STYPE_PROBE_RESP:
-		ieee80211_rx_mgmt_probe_resp(dev, mgmt, skb->len, rx_status);
+		ieee80211_rx_mgmt_probe_resp(sdata, mgmt, skb->len, rx_status);
 		break;
 	case IEEE80211_STYPE_BEACON:
-		ieee80211_rx_mgmt_beacon(dev, mgmt, skb->len, rx_status);
+		ieee80211_rx_mgmt_beacon(sdata, mgmt, skb->len, rx_status);
 		break;
 	case IEEE80211_STYPE_AUTH:
-		ieee80211_rx_mgmt_auth(dev, ifsta, mgmt, skb->len);
+		ieee80211_rx_mgmt_auth(sdata, ifsta, mgmt, skb->len);
 		break;
 	case IEEE80211_STYPE_ASSOC_RESP:
 		ieee80211_rx_mgmt_assoc_resp(sdata, ifsta, mgmt, skb->len, 0);
@@ -3174,13 +1862,10 @@
 		ieee80211_rx_mgmt_assoc_resp(sdata, ifsta, mgmt, skb->len, 1);
 		break;
 	case IEEE80211_STYPE_DEAUTH:
-		ieee80211_rx_mgmt_deauth(dev, ifsta, mgmt, skb->len);
+		ieee80211_rx_mgmt_deauth(sdata, ifsta, mgmt, skb->len);
 		break;
 	case IEEE80211_STYPE_DISASSOC:
-		ieee80211_rx_mgmt_disassoc(dev, ifsta, mgmt, skb->len);
-		break;
-	case IEEE80211_STYPE_ACTION:
-		ieee80211_rx_mgmt_action(dev, ifsta, mgmt, skb->len, rx_status);
+		ieee80211_rx_mgmt_disassoc(sdata, ifsta, mgmt, skb->len);
 		break;
 	}
 
@@ -3188,47 +1873,11 @@
 }
 
 
-ieee80211_rx_result
-ieee80211_sta_rx_scan(struct net_device *dev, struct sk_buff *skb,
-		      struct ieee80211_rx_status *rx_status)
+static int ieee80211_sta_active_ibss(struct ieee80211_sub_if_data *sdata)
 {
-	struct ieee80211_mgmt *mgmt;
-	__le16 fc;
-
-	if (skb->len < 2)
-		return RX_DROP_UNUSABLE;
-
-	mgmt = (struct ieee80211_mgmt *) skb->data;
-	fc = mgmt->frame_control;
-
-	if (ieee80211_is_ctl(fc))
-		return RX_CONTINUE;
-
-	if (skb->len < 24)
-		return RX_DROP_MONITOR;
-
-	if (ieee80211_is_probe_resp(fc)) {
-		ieee80211_rx_mgmt_probe_resp(dev, mgmt, skb->len, rx_status);
-		dev_kfree_skb(skb);
-		return RX_QUEUED;
-	}
-
-	if (ieee80211_is_beacon(fc)) {
-		ieee80211_rx_mgmt_beacon(dev, mgmt, skb->len, rx_status);
-		dev_kfree_skb(skb);
-		return RX_QUEUED;
-	}
-
-	return RX_CONTINUE;
-}
-
-
-static int ieee80211_sta_active_ibss(struct net_device *dev)
-{
-	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct ieee80211_local *local = sdata->local;
 	int active = 0;
 	struct sta_info *sta;
-	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 
 	rcu_read_lock();
 
@@ -3247,179 +1896,36 @@
 }
 
 
-static void ieee80211_sta_expire(struct net_device *dev, unsigned long exp_time)
-{
-	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-	struct sta_info *sta, *tmp;
-	LIST_HEAD(tmp_list);
-	DECLARE_MAC_BUF(mac);
-	unsigned long flags;
-
-	spin_lock_irqsave(&local->sta_lock, flags);
-	list_for_each_entry_safe(sta, tmp, &local->sta_list, list)
-		if (time_after(jiffies, sta->last_rx + exp_time)) {
-#ifdef CONFIG_MAC80211_IBSS_DEBUG
-			printk(KERN_DEBUG "%s: expiring inactive STA %s\n",
-			       dev->name, print_mac(mac, sta->addr));
-#endif
-			__sta_info_unlink(&sta);
-			if (sta)
-				list_add(&sta->list, &tmp_list);
-		}
-	spin_unlock_irqrestore(&local->sta_lock, flags);
-
-	list_for_each_entry_safe(sta, tmp, &tmp_list, list)
-		sta_info_destroy(sta);
-}
-
-
-static void ieee80211_sta_merge_ibss(struct net_device *dev,
+static void ieee80211_sta_merge_ibss(struct ieee80211_sub_if_data *sdata,
 				     struct ieee80211_if_sta *ifsta)
 {
 	mod_timer(&ifsta->timer, jiffies + IEEE80211_IBSS_MERGE_INTERVAL);
 
-	ieee80211_sta_expire(dev, IEEE80211_IBSS_INACTIVITY_LIMIT);
-	if (ieee80211_sta_active_ibss(dev))
+	ieee80211_sta_expire(sdata, IEEE80211_IBSS_INACTIVITY_LIMIT);
+	if (ieee80211_sta_active_ibss(sdata))
 		return;
 
 	printk(KERN_DEBUG "%s: No active IBSS STAs - trying to scan for other "
-	       "IBSS networks with same SSID (merge)\n", dev->name);
-	ieee80211_sta_req_scan(dev, ifsta->ssid, ifsta->ssid_len);
+	       "IBSS networks with same SSID (merge)\n", sdata->dev->name);
+	ieee80211_request_scan(sdata, ifsta->ssid, ifsta->ssid_len);
 }
 
 
-#ifdef CONFIG_MAC80211_MESH
-static void ieee80211_mesh_housekeeping(struct net_device *dev,
-			   struct ieee80211_if_sta *ifsta)
-{
-	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-	bool free_plinks;
-
-	ieee80211_sta_expire(dev, IEEE80211_MESH_PEER_INACTIVITY_LIMIT);
-	mesh_path_expire(dev);
-
-	free_plinks = mesh_plink_availables(sdata);
-	if (free_plinks != sdata->u.sta.accepting_plinks)
-		ieee80211_if_config(sdata, IEEE80211_IFCC_BEACON);
-
-	mod_timer(&ifsta->timer, jiffies +
-			IEEE80211_MESH_HOUSEKEEPING_INTERVAL);
-}
-
-
-void ieee80211_start_mesh(struct net_device *dev)
-{
-	struct ieee80211_if_sta *ifsta;
-	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-	ifsta = &sdata->u.sta;
-	ifsta->state = IEEE80211_MESH_UP;
-	ieee80211_sta_timer((unsigned long)sdata);
-	ieee80211_if_config(sdata, IEEE80211_IFCC_BEACON);
-}
-#endif
-
-
-void ieee80211_sta_timer(unsigned long data)
+static void ieee80211_sta_timer(unsigned long data)
 {
 	struct ieee80211_sub_if_data *sdata =
 		(struct ieee80211_sub_if_data *) data;
 	struct ieee80211_if_sta *ifsta = &sdata->u.sta;
-	struct ieee80211_local *local = wdev_priv(&sdata->wdev);
+	struct ieee80211_local *local = sdata->local;
 
 	set_bit(IEEE80211_STA_REQ_RUN, &ifsta->request);
 	queue_work(local->hw.workqueue, &ifsta->work);
 }
 
-void ieee80211_sta_work(struct work_struct *work)
-{
-	struct ieee80211_sub_if_data *sdata =
-		container_of(work, struct ieee80211_sub_if_data, u.sta.work);
-	struct net_device *dev = sdata->dev;
-	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-	struct ieee80211_if_sta *ifsta;
-	struct sk_buff *skb;
-
-	if (!netif_running(dev))
-		return;
-
-	if (local->sta_sw_scanning || local->sta_hw_scanning)
-		return;
-
-	if (WARN_ON(sdata->vif.type != IEEE80211_IF_TYPE_STA &&
-		    sdata->vif.type != IEEE80211_IF_TYPE_IBSS &&
-		    sdata->vif.type != IEEE80211_IF_TYPE_MESH_POINT))
-		return;
-	ifsta = &sdata->u.sta;
-
-	while ((skb = skb_dequeue(&ifsta->skb_queue)))
-		ieee80211_sta_rx_queued_mgmt(dev, skb);
-
-#ifdef CONFIG_MAC80211_MESH
-	if (ifsta->preq_queue_len &&
-	    time_after(jiffies,
-		       ifsta->last_preq + msecs_to_jiffies(ifsta->mshcfg.dot11MeshHWMPpreqMinInterval)))
-		mesh_path_start_discovery(dev);
-#endif
-
-	if (ifsta->state != IEEE80211_AUTHENTICATE &&
-	    ifsta->state != IEEE80211_ASSOCIATE &&
-	    test_and_clear_bit(IEEE80211_STA_REQ_SCAN, &ifsta->request)) {
-		if (ifsta->scan_ssid_len)
-			ieee80211_sta_start_scan(dev, ifsta->scan_ssid, ifsta->scan_ssid_len);
-		else
-			ieee80211_sta_start_scan(dev, NULL, 0);
-		return;
-	}
-
-	if (test_and_clear_bit(IEEE80211_STA_REQ_AUTH, &ifsta->request)) {
-		if (ieee80211_sta_config_auth(dev, ifsta))
-			return;
-		clear_bit(IEEE80211_STA_REQ_RUN, &ifsta->request);
-	} else if (!test_and_clear_bit(IEEE80211_STA_REQ_RUN, &ifsta->request))
-		return;
-
-	switch (ifsta->state) {
-	case IEEE80211_DISABLED:
-		break;
-	case IEEE80211_AUTHENTICATE:
-		ieee80211_authenticate(dev, ifsta);
-		break;
-	case IEEE80211_ASSOCIATE:
-		ieee80211_associate(dev, ifsta);
-		break;
-	case IEEE80211_ASSOCIATED:
-		ieee80211_associated(dev, ifsta);
-		break;
-	case IEEE80211_IBSS_SEARCH:
-		ieee80211_sta_find_ibss(dev, ifsta);
-		break;
-	case IEEE80211_IBSS_JOINED:
-		ieee80211_sta_merge_ibss(dev, ifsta);
-		break;
-#ifdef CONFIG_MAC80211_MESH
-	case IEEE80211_MESH_UP:
-		ieee80211_mesh_housekeeping(dev, ifsta);
-		break;
-#endif
-	default:
-		WARN_ON(1);
-		break;
-	}
-
-	if (ieee80211_privacy_mismatch(dev, ifsta)) {
-		printk(KERN_DEBUG "%s: privacy configuration mismatch and "
-		       "mixed-cell disabled - disassociate\n", dev->name);
-
-		ieee80211_send_disassoc(dev, ifsta, WLAN_REASON_UNSPECIFIED);
-		ieee80211_set_disassoc(dev, ifsta, 0);
-	}
-}
-
-
-static void ieee80211_sta_reset_auth(struct net_device *dev,
+static void ieee80211_sta_reset_auth(struct ieee80211_sub_if_data *sdata,
 				     struct ieee80211_if_sta *ifsta)
 {
-	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct ieee80211_local *local = sdata->local;
 
 	if (local->ops->reset_tsf) {
 		/* Reset own TSF to allow time synchronization work. */
@@ -3439,29 +1945,15 @@
 		ifsta->auth_alg = WLAN_AUTH_OPEN;
 	ifsta->auth_transaction = -1;
 	ifsta->flags &= ~IEEE80211_STA_ASSOCIATED;
-	ifsta->auth_tries = ifsta->assoc_tries = 0;
-	netif_carrier_off(dev);
+	ifsta->assoc_scan_tries = 0;
+	ifsta->direct_probe_tries = 0;
+	ifsta->auth_tries = 0;
+	ifsta->assoc_tries = 0;
+	netif_tx_stop_all_queues(sdata->dev);
+	netif_carrier_off(sdata->dev);
 }
 
 
-void ieee80211_sta_req_auth(struct net_device *dev,
-			    struct ieee80211_if_sta *ifsta)
-{
-	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-
-	if (sdata->vif.type != IEEE80211_IF_TYPE_STA)
-		return;
-
-	if ((ifsta->flags & (IEEE80211_STA_BSSID_SET |
-				IEEE80211_STA_AUTO_BSSID_SEL)) &&
-	    (ifsta->flags & (IEEE80211_STA_SSID_SET |
-				IEEE80211_STA_AUTO_SSID_SEL))) {
-		set_bit(IEEE80211_STA_REQ_AUTH, &ifsta->request);
-		queue_work(local->hw.workqueue, &ifsta->work);
-	}
-}
-
 static int ieee80211_sta_match_ssid(struct ieee80211_if_sta *ifsta,
 				    const char *ssid, int ssid_len)
 {
@@ -3492,17 +1984,187 @@
 	return 0;
 }
 
-static int ieee80211_sta_config_auth(struct net_device *dev,
+static int ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata,
 				     struct ieee80211_if_sta *ifsta)
 {
-	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-	struct ieee80211_sta_bss *bss, *selected = NULL;
+	struct ieee80211_local *local = sdata->local;
+	struct ieee80211_bss *bss;
+	struct ieee80211_supported_band *sband;
+	u8 bssid[ETH_ALEN], *pos;
+	int i;
+	int ret;
+	DECLARE_MAC_BUF(mac);
+
+#if 0
+	/* Easier testing, use fixed BSSID. */
+	memset(bssid, 0xfe, ETH_ALEN);
+#else
+	/* Generate random, not broadcast, locally administered BSSID. Mix in
+	 * own MAC address to make sure that devices that do not have proper
+	 * random number generator get different BSSID. */
+	get_random_bytes(bssid, ETH_ALEN);
+	for (i = 0; i < ETH_ALEN; i++)
+		bssid[i] ^= sdata->dev->dev_addr[i];
+	bssid[0] &= ~0x01;
+	bssid[0] |= 0x02;
+#endif
+
+	printk(KERN_DEBUG "%s: Creating new IBSS network, BSSID %s\n",
+	       sdata->dev->name, print_mac(mac, bssid));
+
+	bss = ieee80211_rx_bss_add(local, bssid,
+				   local->hw.conf.channel->center_freq,
+				   sdata->u.sta.ssid, sdata->u.sta.ssid_len);
+	if (!bss)
+		return -ENOMEM;
+
+	bss->band = local->hw.conf.channel->band;
+	sband = local->hw.wiphy->bands[bss->band];
+
+	if (local->hw.conf.beacon_int == 0)
+		local->hw.conf.beacon_int = 100;
+	bss->beacon_int = local->hw.conf.beacon_int;
+	bss->last_update = jiffies;
+	bss->capability = WLAN_CAPABILITY_IBSS;
+
+	if (sdata->default_key)
+		bss->capability |= WLAN_CAPABILITY_PRIVACY;
+	else
+		sdata->drop_unencrypted = 0;
+
+	bss->supp_rates_len = sband->n_bitrates;
+	pos = bss->supp_rates;
+	for (i = 0; i < sband->n_bitrates; i++) {
+		int rate = sband->bitrates[i].bitrate;
+		*pos++ = (u8) (rate / 5);
+	}
+
+	ret = ieee80211_sta_join_ibss(sdata, ifsta, bss);
+	ieee80211_rx_bss_put(local, bss);
+	return ret;
+}
+
+
+static int ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata,
+				   struct ieee80211_if_sta *ifsta)
+{
+	struct ieee80211_local *local = sdata->local;
+	struct ieee80211_bss *bss;
+	int found = 0;
+	u8 bssid[ETH_ALEN];
+	int active_ibss;
+	DECLARE_MAC_BUF(mac);
+	DECLARE_MAC_BUF(mac2);
+
+	if (ifsta->ssid_len == 0)
+		return -EINVAL;
+
+	active_ibss = ieee80211_sta_active_ibss(sdata);
+#ifdef CONFIG_MAC80211_IBSS_DEBUG
+	printk(KERN_DEBUG "%s: sta_find_ibss (active_ibss=%d)\n",
+	       sdata->dev->name, active_ibss);
+#endif /* CONFIG_MAC80211_IBSS_DEBUG */
+	spin_lock_bh(&local->bss_lock);
+	list_for_each_entry(bss, &local->bss_list, list) {
+		if (ifsta->ssid_len != bss->ssid_len ||
+		    memcmp(ifsta->ssid, bss->ssid, bss->ssid_len) != 0
+		    || !(bss->capability & WLAN_CAPABILITY_IBSS))
+			continue;
+#ifdef CONFIG_MAC80211_IBSS_DEBUG
+		printk(KERN_DEBUG "   bssid=%s found\n",
+		       print_mac(mac, bss->bssid));
+#endif /* CONFIG_MAC80211_IBSS_DEBUG */
+		memcpy(bssid, bss->bssid, ETH_ALEN);
+		found = 1;
+		if (active_ibss || memcmp(bssid, ifsta->bssid, ETH_ALEN) != 0)
+			break;
+	}
+	spin_unlock_bh(&local->bss_lock);
+
+#ifdef CONFIG_MAC80211_IBSS_DEBUG
+	if (found)
+		printk(KERN_DEBUG "   sta_find_ibss: selected %s current "
+		       "%s\n", print_mac(mac, bssid),
+		       print_mac(mac2, ifsta->bssid));
+#endif /* CONFIG_MAC80211_IBSS_DEBUG */
+
+	if (found && memcmp(ifsta->bssid, bssid, ETH_ALEN) != 0) {
+		int ret;
+		int search_freq;
+
+		if (ifsta->flags & IEEE80211_STA_AUTO_CHANNEL_SEL)
+			search_freq = bss->freq;
+		else
+			search_freq = local->hw.conf.channel->center_freq;
+
+		bss = ieee80211_rx_bss_get(local, bssid, search_freq,
+					   ifsta->ssid, ifsta->ssid_len);
+		if (!bss)
+			goto dont_join;
+
+		printk(KERN_DEBUG "%s: Selected IBSS BSSID %s"
+		       " based on configured SSID\n",
+		       sdata->dev->name, print_mac(mac, bssid));
+		ret = ieee80211_sta_join_ibss(sdata, ifsta, bss);
+		ieee80211_rx_bss_put(local, bss);
+		return ret;
+	}
+
+dont_join:
+#ifdef CONFIG_MAC80211_IBSS_DEBUG
+	printk(KERN_DEBUG "   did not try to join ibss\n");
+#endif /* CONFIG_MAC80211_IBSS_DEBUG */
+
+	/* Selected IBSS not found in current scan results - try to scan */
+	if (ifsta->state == IEEE80211_STA_MLME_IBSS_JOINED &&
+	    !ieee80211_sta_active_ibss(sdata)) {
+		mod_timer(&ifsta->timer, jiffies +
+				      IEEE80211_IBSS_MERGE_INTERVAL);
+	} else if (time_after(jiffies, local->last_scan_completed +
+			      IEEE80211_SCAN_INTERVAL)) {
+		printk(KERN_DEBUG "%s: Trigger new scan to find an IBSS to "
+		       "join\n", sdata->dev->name);
+		return ieee80211_request_scan(sdata, ifsta->ssid,
+					      ifsta->ssid_len);
+	} else if (ifsta->state != IEEE80211_STA_MLME_IBSS_JOINED) {
+		int interval = IEEE80211_SCAN_INTERVAL;
+
+		if (time_after(jiffies, ifsta->ibss_join_req +
+			       IEEE80211_IBSS_JOIN_TIMEOUT)) {
+			if ((ifsta->flags & IEEE80211_STA_CREATE_IBSS) &&
+			    (!(local->oper_channel->flags &
+					IEEE80211_CHAN_NO_IBSS)))
+				return ieee80211_sta_create_ibss(sdata, ifsta);
+			if (ifsta->flags & IEEE80211_STA_CREATE_IBSS) {
+				printk(KERN_DEBUG "%s: IBSS not allowed on"
+				       " %d MHz\n", sdata->dev->name,
+				       local->hw.conf.channel->center_freq);
+			}
+
+			/* No IBSS found - decrease scan interval and continue
+			 * scanning. */
+			interval = IEEE80211_SCAN_INTERVAL_SLOW;
+		}
+
+		ifsta->state = IEEE80211_STA_MLME_IBSS_SEARCH;
+		mod_timer(&ifsta->timer, jiffies + interval);
+		return 0;
+	}
+
+	return 0;
+}
+
+
+static int ieee80211_sta_config_auth(struct ieee80211_sub_if_data *sdata,
+				     struct ieee80211_if_sta *ifsta)
+{
+	struct ieee80211_local *local = sdata->local;
+	struct ieee80211_bss *bss, *selected = NULL;
 	int top_rssi = 0, freq;
 
-	spin_lock_bh(&local->sta_bss_lock);
+	spin_lock_bh(&local->bss_lock);
 	freq = local->oper_channel->center_freq;
-	list_for_each_entry(bss, &local->sta_bss_list, list) {
+	list_for_each_entry(bss, &local->bss_list, list) {
 		if (!(bss->capability & WLAN_CAPABILITY_ESS))
 			continue;
 
@@ -3532,210 +2194,222 @@
 	}
 	if (selected)
 		atomic_inc(&selected->users);
-	spin_unlock_bh(&local->sta_bss_lock);
+	spin_unlock_bh(&local->bss_lock);
 
 	if (selected) {
-		ieee80211_set_freq(dev, selected->freq);
+		ieee80211_set_freq(sdata, selected->freq);
 		if (!(ifsta->flags & IEEE80211_STA_SSID_SET))
-			ieee80211_sta_set_ssid(dev, selected->ssid,
+			ieee80211_sta_set_ssid(sdata, selected->ssid,
 					       selected->ssid_len);
-		ieee80211_sta_set_bssid(dev, selected->bssid);
-		ieee80211_sta_def_wmm_params(dev, selected, 0);
+		ieee80211_sta_set_bssid(sdata, selected->bssid);
+		ieee80211_sta_def_wmm_params(sdata, selected);
+
+		/* Send out direct probe if no probe resp was received or
+		 * the one we have is outdated
+		 */
+		if (!selected->last_probe_resp ||
+		    time_after(jiffies, selected->last_probe_resp
+					+ IEEE80211_SCAN_RESULT_EXPIRE))
+			ifsta->state = IEEE80211_STA_MLME_DIRECT_PROBE;
+		else
+			ifsta->state = IEEE80211_STA_MLME_AUTHENTICATE;
+
 		ieee80211_rx_bss_put(local, selected);
-		ifsta->state = IEEE80211_AUTHENTICATE;
-		ieee80211_sta_reset_auth(dev, ifsta);
+		ieee80211_sta_reset_auth(sdata, ifsta);
 		return 0;
 	} else {
-		if (ifsta->state != IEEE80211_AUTHENTICATE) {
+		if (ifsta->assoc_scan_tries < IEEE80211_ASSOC_SCANS_MAX_TRIES) {
+			ifsta->assoc_scan_tries++;
 			if (ifsta->flags & IEEE80211_STA_AUTO_SSID_SEL)
-				ieee80211_sta_start_scan(dev, NULL, 0);
+				ieee80211_start_scan(sdata, NULL, 0);
 			else
-				ieee80211_sta_start_scan(dev, ifsta->ssid,
+				ieee80211_start_scan(sdata, ifsta->ssid,
 							 ifsta->ssid_len);
-			ifsta->state = IEEE80211_AUTHENTICATE;
+			ifsta->state = IEEE80211_STA_MLME_AUTHENTICATE;
 			set_bit(IEEE80211_STA_REQ_AUTH, &ifsta->request);
 		} else
-			ifsta->state = IEEE80211_DISABLED;
+			ifsta->state = IEEE80211_STA_MLME_DISABLED;
 	}
 	return -1;
 }
 
 
-static int ieee80211_sta_create_ibss(struct net_device *dev,
-				     struct ieee80211_if_sta *ifsta)
+static void ieee80211_sta_work(struct work_struct *work)
 {
-	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-	struct ieee80211_sta_bss *bss;
-	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-	struct ieee80211_supported_band *sband;
-	u8 bssid[ETH_ALEN], *pos;
-	int i;
-	int ret;
-	DECLARE_MAC_BUF(mac);
+	struct ieee80211_sub_if_data *sdata =
+		container_of(work, struct ieee80211_sub_if_data, u.sta.work);
+	struct ieee80211_local *local = sdata->local;
+	struct ieee80211_if_sta *ifsta;
+	struct sk_buff *skb;
 
-#if 0
-	/* Easier testing, use fixed BSSID. */
-	memset(bssid, 0xfe, ETH_ALEN);
-#else
-	/* Generate random, not broadcast, locally administered BSSID. Mix in
-	 * own MAC address to make sure that devices that do not have proper
-	 * random number generator get different BSSID. */
-	get_random_bytes(bssid, ETH_ALEN);
-	for (i = 0; i < ETH_ALEN; i++)
-		bssid[i] ^= dev->dev_addr[i];
-	bssid[0] &= ~0x01;
-	bssid[0] |= 0x02;
+	if (!netif_running(sdata->dev))
+		return;
+
+	if (local->sw_scanning || local->hw_scanning)
+		return;
+
+	if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION &&
+		    sdata->vif.type != NL80211_IFTYPE_ADHOC))
+		return;
+	ifsta = &sdata->u.sta;
+
+	while ((skb = skb_dequeue(&ifsta->skb_queue)))
+		ieee80211_sta_rx_queued_mgmt(sdata, skb);
+
+	if (ifsta->state != IEEE80211_STA_MLME_DIRECT_PROBE &&
+	    ifsta->state != IEEE80211_STA_MLME_AUTHENTICATE &&
+	    ifsta->state != IEEE80211_STA_MLME_ASSOCIATE &&
+	    test_and_clear_bit(IEEE80211_STA_REQ_SCAN, &ifsta->request)) {
+		ieee80211_start_scan(sdata, ifsta->scan_ssid,
+				     ifsta->scan_ssid_len);
+		return;
+	}
+
+	if (test_and_clear_bit(IEEE80211_STA_REQ_AUTH, &ifsta->request)) {
+		if (ieee80211_sta_config_auth(sdata, ifsta))
+			return;
+		clear_bit(IEEE80211_STA_REQ_RUN, &ifsta->request);
+	} else if (!test_and_clear_bit(IEEE80211_STA_REQ_RUN, &ifsta->request))
+		return;
+
+	switch (ifsta->state) {
+	case IEEE80211_STA_MLME_DISABLED:
+		break;
+	case IEEE80211_STA_MLME_DIRECT_PROBE:
+		ieee80211_direct_probe(sdata, ifsta);
+		break;
+	case IEEE80211_STA_MLME_AUTHENTICATE:
+		ieee80211_authenticate(sdata, ifsta);
+		break;
+	case IEEE80211_STA_MLME_ASSOCIATE:
+		ieee80211_associate(sdata, ifsta);
+		break;
+	case IEEE80211_STA_MLME_ASSOCIATED:
+		ieee80211_associated(sdata, ifsta);
+		break;
+	case IEEE80211_STA_MLME_IBSS_SEARCH:
+		ieee80211_sta_find_ibss(sdata, ifsta);
+		break;
+	case IEEE80211_STA_MLME_IBSS_JOINED:
+		ieee80211_sta_merge_ibss(sdata, ifsta);
+		break;
+	default:
+		WARN_ON(1);
+		break;
+	}
+
+	if (ieee80211_privacy_mismatch(sdata, ifsta)) {
+		printk(KERN_DEBUG "%s: privacy configuration mismatch and "
+		       "mixed-cell disabled - disassociate\n", sdata->dev->name);
+
+		ieee80211_set_disassoc(sdata, ifsta, false, true,
+					WLAN_REASON_UNSPECIFIED);
+	}
+}
+
+static void ieee80211_restart_sta_timer(struct ieee80211_sub_if_data *sdata)
+{
+	if (sdata->vif.type == NL80211_IFTYPE_STATION)
+		queue_work(sdata->local->hw.workqueue,
+			   &sdata->u.sta.work);
+}
+
+/* interface setup */
+void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata)
+{
+	struct ieee80211_if_sta *ifsta;
+
+	ifsta = &sdata->u.sta;
+	INIT_WORK(&ifsta->work, ieee80211_sta_work);
+	setup_timer(&ifsta->timer, ieee80211_sta_timer,
+		    (unsigned long) sdata);
+	skb_queue_head_init(&ifsta->skb_queue);
+
+	ifsta->capab = WLAN_CAPABILITY_ESS;
+	ifsta->auth_algs = IEEE80211_AUTH_ALG_OPEN |
+		IEEE80211_AUTH_ALG_SHARED_KEY;
+	ifsta->flags |= IEEE80211_STA_CREATE_IBSS |
+		IEEE80211_STA_AUTO_BSSID_SEL |
+		IEEE80211_STA_AUTO_CHANNEL_SEL;
+	if (ieee80211_num_regular_queues(&sdata->local->hw) >= 4)
+		ifsta->flags |= IEEE80211_STA_WMM_ENABLED;
+}
+
+/*
+ * Add a new IBSS station, will also be called by the RX code when,
+ * in IBSS mode, receiving a frame from a yet-unknown station, hence
+ * must be callable in atomic context.
+ */
+struct sta_info *ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata,
+					struct sk_buff *skb, u8 *bssid,
+					u8 *addr, u64 supp_rates)
+{
+	struct ieee80211_local *local = sdata->local;
+	struct sta_info *sta;
+	DECLARE_MAC_BUF(mac);
+	int band = local->hw.conf.channel->band;
+
+	/* TODO: Could consider removing the least recently used entry and
+	 * allow new one to be added. */
+	if (local->num_sta >= IEEE80211_IBSS_MAX_STA_ENTRIES) {
+		if (net_ratelimit()) {
+			printk(KERN_DEBUG "%s: No room for a new IBSS STA "
+			       "entry %s\n", sdata->dev->name, print_mac(mac, addr));
+		}
+		return NULL;
+	}
+
+	if (compare_ether_addr(bssid, sdata->u.sta.bssid))
+		return NULL;
+
+#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
+	printk(KERN_DEBUG "%s: Adding new IBSS station %s (dev=%s)\n",
+	       wiphy_name(local->hw.wiphy), print_mac(mac, addr), sdata->dev->name);
 #endif
 
-	printk(KERN_DEBUG "%s: Creating new IBSS network, BSSID %s\n",
-	       dev->name, print_mac(mac, bssid));
+	sta = sta_info_alloc(sdata, addr, GFP_ATOMIC);
+	if (!sta)
+		return NULL;
 
-	bss = ieee80211_rx_bss_add(dev, bssid,
-				   local->hw.conf.channel->center_freq,
-				   sdata->u.sta.ssid, sdata->u.sta.ssid_len);
-	if (!bss)
-		return -ENOMEM;
+	set_sta_flags(sta, WLAN_STA_AUTHORIZED);
 
-	bss->band = local->hw.conf.channel->band;
-	sband = local->hw.wiphy->bands[bss->band];
+	/* make sure mandatory rates are always added */
+	sta->sta.supp_rates[band] = supp_rates |
+			ieee80211_mandatory_rates(local, band);
 
-	if (local->hw.conf.beacon_int == 0)
-		local->hw.conf.beacon_int = 100;
-	bss->beacon_int = local->hw.conf.beacon_int;
-	bss->last_update = jiffies;
-	bss->capability = WLAN_CAPABILITY_IBSS;
+	rate_control_rate_init(sta);
 
-	if (sdata->default_key)
-		bss->capability |= WLAN_CAPABILITY_PRIVACY;
-	else
-		sdata->drop_unencrypted = 0;
+	if (sta_info_insert(sta))
+		return NULL;
 
-	bss->supp_rates_len = sband->n_bitrates;
-	pos = bss->supp_rates;
-	for (i = 0; i < sband->n_bitrates; i++) {
-		int rate = sband->bitrates[i].bitrate;
-		*pos++ = (u8) (rate / 5);
-	}
-
-	ret = ieee80211_sta_join_ibss(dev, ifsta, bss);
-	ieee80211_rx_bss_put(local, bss);
-	return ret;
+	return sta;
 }
 
-
-static int ieee80211_sta_find_ibss(struct net_device *dev,
-				   struct ieee80211_if_sta *ifsta)
+/* configuration hooks */
+void ieee80211_sta_req_auth(struct ieee80211_sub_if_data *sdata,
+			    struct ieee80211_if_sta *ifsta)
 {
-	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-	struct ieee80211_sta_bss *bss;
-	int found = 0;
-	u8 bssid[ETH_ALEN];
-	int active_ibss;
-	DECLARE_MAC_BUF(mac);
-	DECLARE_MAC_BUF(mac2);
+	struct ieee80211_local *local = sdata->local;
 
-	if (ifsta->ssid_len == 0)
-		return -EINVAL;
+	if (sdata->vif.type != NL80211_IFTYPE_STATION)
+		return;
 
-	active_ibss = ieee80211_sta_active_ibss(dev);
-#ifdef CONFIG_MAC80211_IBSS_DEBUG
-	printk(KERN_DEBUG "%s: sta_find_ibss (active_ibss=%d)\n",
-	       dev->name, active_ibss);
-#endif /* CONFIG_MAC80211_IBSS_DEBUG */
-	spin_lock_bh(&local->sta_bss_lock);
-	list_for_each_entry(bss, &local->sta_bss_list, list) {
-		if (ifsta->ssid_len != bss->ssid_len ||
-		    memcmp(ifsta->ssid, bss->ssid, bss->ssid_len) != 0
-		    || !(bss->capability & WLAN_CAPABILITY_IBSS))
-			continue;
-#ifdef CONFIG_MAC80211_IBSS_DEBUG
-		printk(KERN_DEBUG "   bssid=%s found\n",
-		       print_mac(mac, bss->bssid));
-#endif /* CONFIG_MAC80211_IBSS_DEBUG */
-		memcpy(bssid, bss->bssid, ETH_ALEN);
-		found = 1;
-		if (active_ibss || memcmp(bssid, ifsta->bssid, ETH_ALEN) != 0)
-			break;
+	if ((ifsta->flags & (IEEE80211_STA_BSSID_SET |
+			     IEEE80211_STA_AUTO_BSSID_SEL)) &&
+	    (ifsta->flags & (IEEE80211_STA_SSID_SET |
+			     IEEE80211_STA_AUTO_SSID_SEL))) {
+
+		if (ifsta->state == IEEE80211_STA_MLME_ASSOCIATED)
+			ieee80211_set_disassoc(sdata, ifsta, true, true,
+					       WLAN_REASON_DEAUTH_LEAVING);
+
+		set_bit(IEEE80211_STA_REQ_AUTH, &ifsta->request);
+		queue_work(local->hw.workqueue, &ifsta->work);
 	}
-	spin_unlock_bh(&local->sta_bss_lock);
-
-#ifdef CONFIG_MAC80211_IBSS_DEBUG
-	if (found)
-		printk(KERN_DEBUG "   sta_find_ibss: selected %s current "
-		       "%s\n", print_mac(mac, bssid),
-		       print_mac(mac2, ifsta->bssid));
-#endif /* CONFIG_MAC80211_IBSS_DEBUG */
-
-	if (found && memcmp(ifsta->bssid, bssid, ETH_ALEN) != 0) {
-		int ret;
-		int search_freq;
-
-		if (ifsta->flags & IEEE80211_STA_AUTO_CHANNEL_SEL)
-			search_freq = bss->freq;
-		else
-			search_freq = local->hw.conf.channel->center_freq;
-
-		bss = ieee80211_rx_bss_get(dev, bssid, search_freq,
-					   ifsta->ssid, ifsta->ssid_len);
-		if (!bss)
-			goto dont_join;
-
-		printk(KERN_DEBUG "%s: Selected IBSS BSSID %s"
-		       " based on configured SSID\n",
-		       dev->name, print_mac(mac, bssid));
-		ret = ieee80211_sta_join_ibss(dev, ifsta, bss);
-		ieee80211_rx_bss_put(local, bss);
-		return ret;
-	}
-
-dont_join:
-#ifdef CONFIG_MAC80211_IBSS_DEBUG
-	printk(KERN_DEBUG "   did not try to join ibss\n");
-#endif /* CONFIG_MAC80211_IBSS_DEBUG */
-
-	/* Selected IBSS not found in current scan results - try to scan */
-	if (ifsta->state == IEEE80211_IBSS_JOINED &&
-	    !ieee80211_sta_active_ibss(dev)) {
-		mod_timer(&ifsta->timer, jiffies +
-				      IEEE80211_IBSS_MERGE_INTERVAL);
-	} else if (time_after(jiffies, local->last_scan_completed +
-			      IEEE80211_SCAN_INTERVAL)) {
-		printk(KERN_DEBUG "%s: Trigger new scan to find an IBSS to "
-		       "join\n", dev->name);
-		return ieee80211_sta_req_scan(dev, ifsta->ssid,
-					      ifsta->ssid_len);
-	} else if (ifsta->state != IEEE80211_IBSS_JOINED) {
-		int interval = IEEE80211_SCAN_INTERVAL;
-
-		if (time_after(jiffies, ifsta->ibss_join_req +
-			       IEEE80211_IBSS_JOIN_TIMEOUT)) {
-			if ((ifsta->flags & IEEE80211_STA_CREATE_IBSS) &&
-			    (!(local->oper_channel->flags &
-					IEEE80211_CHAN_NO_IBSS)))
-				return ieee80211_sta_create_ibss(dev, ifsta);
-			if (ifsta->flags & IEEE80211_STA_CREATE_IBSS) {
-				printk(KERN_DEBUG "%s: IBSS not allowed on"
-				       " %d MHz\n", dev->name,
-				       local->hw.conf.channel->center_freq);
-			}
-
-			/* No IBSS found - decrease scan interval and continue
-			 * scanning. */
-			interval = IEEE80211_SCAN_INTERVAL_SLOW;
-		}
-
-		ifsta->state = IEEE80211_IBSS_SEARCH;
-		mod_timer(&ifsta->timer, jiffies + interval);
-		return 0;
-	}
-
-	return 0;
 }
 
-
-int ieee80211_sta_set_ssid(struct net_device *dev, char *ssid, size_t len)
+int ieee80211_sta_set_ssid(struct ieee80211_sub_if_data *sdata, char *ssid, size_t len)
 {
-	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 	struct ieee80211_if_sta *ifsta;
 	int res;
 
@@ -3759,7 +2433,7 @@
 			res = ieee80211_if_config(sdata, IEEE80211_IFCC_SSID);
 		if (res) {
 			printk(KERN_DEBUG "%s: Failed to config new SSID to "
-			       "the low-level driver\n", dev->name);
+			       "the low-level driver\n", sdata->dev->name);
 			return res;
 		}
 	}
@@ -3769,34 +2443,29 @@
 	else
 		ifsta->flags &= ~IEEE80211_STA_SSID_SET;
 
-	if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS &&
+	if (sdata->vif.type == NL80211_IFTYPE_ADHOC &&
 	    !(ifsta->flags & IEEE80211_STA_BSSID_SET)) {
 		ifsta->ibss_join_req = jiffies;
-		ifsta->state = IEEE80211_IBSS_SEARCH;
-		return ieee80211_sta_find_ibss(dev, ifsta);
+		ifsta->state = IEEE80211_STA_MLME_IBSS_SEARCH;
+		return ieee80211_sta_find_ibss(sdata, ifsta);
 	}
 
 	return 0;
 }
 
-
-int ieee80211_sta_get_ssid(struct net_device *dev, char *ssid, size_t *len)
+int ieee80211_sta_get_ssid(struct ieee80211_sub_if_data *sdata, char *ssid, size_t *len)
 {
-	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 	struct ieee80211_if_sta *ifsta = &sdata->u.sta;
 	memcpy(ssid, ifsta->ssid, ifsta->ssid_len);
 	*len = ifsta->ssid_len;
 	return 0;
 }
 
-
-int ieee80211_sta_set_bssid(struct net_device *dev, u8 *bssid)
+int ieee80211_sta_set_bssid(struct ieee80211_sub_if_data *sdata, u8 *bssid)
 {
-	struct ieee80211_sub_if_data *sdata;
 	struct ieee80211_if_sta *ifsta;
 	int res;
 
-	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 	ifsta = &sdata->u.sta;
 
 	if (memcmp(ifsta->bssid, bssid, ETH_ALEN) != 0) {
@@ -3809,7 +2478,7 @@
 			res = ieee80211_if_config(sdata, IEEE80211_IFCC_BSSID);
 		if (res) {
 			printk(KERN_DEBUG "%s: Failed to config new BSSID to "
-			       "the low-level driver\n", dev->name);
+			       "the low-level driver\n", sdata->dev->name);
 			return res;
 		}
 	}
@@ -3822,531 +2491,8 @@
 	return 0;
 }
 
-
-static void ieee80211_send_nullfunc(struct ieee80211_local *local,
-				    struct ieee80211_sub_if_data *sdata,
-				    int powersave)
+int ieee80211_sta_set_extra_ie(struct ieee80211_sub_if_data *sdata, char *ie, size_t len)
 {
-	struct sk_buff *skb;
-	struct ieee80211_hdr *nullfunc;
-	__le16 fc;
-
-	skb = dev_alloc_skb(local->hw.extra_tx_headroom + 24);
-	if (!skb) {
-		printk(KERN_DEBUG "%s: failed to allocate buffer for nullfunc "
-		       "frame\n", sdata->dev->name);
-		return;
-	}
-	skb_reserve(skb, local->hw.extra_tx_headroom);
-
-	nullfunc = (struct ieee80211_hdr *) skb_put(skb, 24);
-	memset(nullfunc, 0, 24);
-	fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_NULLFUNC |
-			 IEEE80211_FCTL_TODS);
-	if (powersave)
-		fc |= cpu_to_le16(IEEE80211_FCTL_PM);
-	nullfunc->frame_control = fc;
-	memcpy(nullfunc->addr1, sdata->u.sta.bssid, ETH_ALEN);
-	memcpy(nullfunc->addr2, sdata->dev->dev_addr, ETH_ALEN);
-	memcpy(nullfunc->addr3, sdata->u.sta.bssid, ETH_ALEN);
-
-	ieee80211_sta_tx(sdata->dev, skb, 0);
-}
-
-
-static void ieee80211_restart_sta_timer(struct ieee80211_sub_if_data *sdata)
-{
-	if (sdata->vif.type == IEEE80211_IF_TYPE_STA ||
-	    ieee80211_vif_is_mesh(&sdata->vif))
-		ieee80211_sta_timer((unsigned long)sdata);
-}
-
-void ieee80211_scan_completed(struct ieee80211_hw *hw)
-{
-	struct ieee80211_local *local = hw_to_local(hw);
-	struct net_device *dev = local->scan_dev;
-	struct ieee80211_sub_if_data *sdata;
-	union iwreq_data wrqu;
-
-	local->last_scan_completed = jiffies;
-	memset(&wrqu, 0, sizeof(wrqu));
-	wireless_send_event(dev, SIOCGIWSCAN, &wrqu, NULL);
-
-	if (local->sta_hw_scanning) {
-		local->sta_hw_scanning = 0;
-		if (ieee80211_hw_config(local))
-			printk(KERN_DEBUG "%s: failed to restore operational "
-			       "channel after scan\n", dev->name);
-		/* Restart STA timer for HW scan case */
-		rcu_read_lock();
-		list_for_each_entry_rcu(sdata, &local->interfaces, list)
-			ieee80211_restart_sta_timer(sdata);
-		rcu_read_unlock();
-
-		goto done;
-	}
-
-	local->sta_sw_scanning = 0;
-	if (ieee80211_hw_config(local))
-		printk(KERN_DEBUG "%s: failed to restore operational "
-		       "channel after scan\n", dev->name);
-
-
-	netif_tx_lock_bh(local->mdev);
-	netif_addr_lock(local->mdev);
-	local->filter_flags &= ~FIF_BCN_PRBRESP_PROMISC;
-	local->ops->configure_filter(local_to_hw(local),
-				     FIF_BCN_PRBRESP_PROMISC,
-				     &local->filter_flags,
-				     local->mdev->mc_count,
-				     local->mdev->mc_list);
-
-	netif_addr_unlock(local->mdev);
-	netif_tx_unlock_bh(local->mdev);
-
-	rcu_read_lock();
-	list_for_each_entry_rcu(sdata, &local->interfaces, list) {
-		/* Tell AP we're back */
-		if (sdata->vif.type == IEEE80211_IF_TYPE_STA &&
-		    sdata->u.sta.flags & IEEE80211_STA_ASSOCIATED)
-			ieee80211_send_nullfunc(local, sdata, 0);
-
-		ieee80211_restart_sta_timer(sdata);
-
-		netif_wake_queue(sdata->dev);
-	}
-	rcu_read_unlock();
-
-done:
-	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-	if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS) {
-		struct ieee80211_if_sta *ifsta = &sdata->u.sta;
-		if (!(ifsta->flags & IEEE80211_STA_BSSID_SET) ||
-		    (!(ifsta->state == IEEE80211_IBSS_JOINED) &&
-		    !ieee80211_sta_active_ibss(dev)))
-			ieee80211_sta_find_ibss(dev, ifsta);
-	}
-}
-EXPORT_SYMBOL(ieee80211_scan_completed);
-
-void ieee80211_sta_scan_work(struct work_struct *work)
-{
-	struct ieee80211_local *local =
-		container_of(work, struct ieee80211_local, scan_work.work);
-	struct net_device *dev = local->scan_dev;
-	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-	struct ieee80211_supported_band *sband;
-	struct ieee80211_channel *chan;
-	int skip;
-	unsigned long next_delay = 0;
-
-	if (!local->sta_sw_scanning)
-		return;
-
-	switch (local->scan_state) {
-	case SCAN_SET_CHANNEL:
-		/*
-		 * Get current scan band. scan_band may be IEEE80211_NUM_BANDS
-		 * after we successfully scanned the last channel of the last
-		 * band (and the last band is supported by the hw)
-		 */
-		if (local->scan_band < IEEE80211_NUM_BANDS)
-			sband = local->hw.wiphy->bands[local->scan_band];
-		else
-			sband = NULL;
-
-		/*
-		 * If we are at an unsupported band and have more bands
-		 * left to scan, advance to the next supported one.
-		 */
-		while (!sband && local->scan_band < IEEE80211_NUM_BANDS - 1) {
-			local->scan_band++;
-			sband = local->hw.wiphy->bands[local->scan_band];
-			local->scan_channel_idx = 0;
-		}
-
-		/* if no more bands/channels left, complete scan */
-		if (!sband || local->scan_channel_idx >= sband->n_channels) {
-			ieee80211_scan_completed(local_to_hw(local));
-			return;
-		}
-		skip = 0;
-		chan = &sband->channels[local->scan_channel_idx];
-
-		if (chan->flags & IEEE80211_CHAN_DISABLED ||
-		    (sdata->vif.type == IEEE80211_IF_TYPE_IBSS &&
-		     chan->flags & IEEE80211_CHAN_NO_IBSS))
-			skip = 1;
-
-		if (!skip) {
-			local->scan_channel = chan;
-			if (ieee80211_hw_config(local)) {
-				printk(KERN_DEBUG "%s: failed to set freq to "
-				       "%d MHz for scan\n", dev->name,
-				       chan->center_freq);
-				skip = 1;
-			}
-		}
-
-		/* advance state machine to next channel/band */
-		local->scan_channel_idx++;
-		if (local->scan_channel_idx >= sband->n_channels) {
-			/*
-			 * scan_band may end up == IEEE80211_NUM_BANDS, but
-			 * we'll catch that case above and complete the scan
-			 * if that is the case.
-			 */
-			local->scan_band++;
-			local->scan_channel_idx = 0;
-		}
-
-		if (skip)
-			break;
-
-		next_delay = IEEE80211_PROBE_DELAY +
-			     usecs_to_jiffies(local->hw.channel_change_time);
-		local->scan_state = SCAN_SEND_PROBE;
-		break;
-	case SCAN_SEND_PROBE:
-		next_delay = IEEE80211_PASSIVE_CHANNEL_TIME;
-		local->scan_state = SCAN_SET_CHANNEL;
-
-		if (local->scan_channel->flags & IEEE80211_CHAN_PASSIVE_SCAN)
-			break;
-		ieee80211_send_probe_req(dev, NULL, local->scan_ssid,
-					 local->scan_ssid_len);
-		next_delay = IEEE80211_CHANNEL_TIME;
-		break;
-	}
-
-	if (local->sta_sw_scanning)
-		queue_delayed_work(local->hw.workqueue, &local->scan_work,
-				   next_delay);
-}
-
-
-static int ieee80211_sta_start_scan(struct net_device *dev,
-				    u8 *ssid, size_t ssid_len)
-{
-	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-	struct ieee80211_sub_if_data *sdata;
-
-	if (ssid_len > IEEE80211_MAX_SSID_LEN)
-		return -EINVAL;
-
-	/* MLME-SCAN.request (page 118)  page 144 (11.1.3.1)
-	 * BSSType: INFRASTRUCTURE, INDEPENDENT, ANY_BSS
-	 * BSSID: MACAddress
-	 * SSID
-	 * ScanType: ACTIVE, PASSIVE
-	 * ProbeDelay: delay (in microseconds) to be used prior to transmitting
-	 *    a Probe frame during active scanning
-	 * ChannelList
-	 * MinChannelTime (>= ProbeDelay), in TU
-	 * MaxChannelTime: (>= MinChannelTime), in TU
-	 */
-
-	 /* MLME-SCAN.confirm
-	  * BSSDescriptionSet
-	  * ResultCode: SUCCESS, INVALID_PARAMETERS
-	 */
-
-	if (local->sta_sw_scanning || local->sta_hw_scanning) {
-		if (local->scan_dev == dev)
-			return 0;
-		return -EBUSY;
-	}
-
-	if (local->ops->hw_scan) {
-		int rc = local->ops->hw_scan(local_to_hw(local),
-					     ssid, ssid_len);
-		if (!rc) {
-			local->sta_hw_scanning = 1;
-			local->scan_dev = dev;
-		}
-		return rc;
-	}
-
-	local->sta_sw_scanning = 1;
-
-	rcu_read_lock();
-	list_for_each_entry_rcu(sdata, &local->interfaces, list) {
-		netif_stop_queue(sdata->dev);
-		if (sdata->vif.type == IEEE80211_IF_TYPE_STA &&
-		    (sdata->u.sta.flags & IEEE80211_STA_ASSOCIATED))
-			ieee80211_send_nullfunc(local, sdata, 1);
-	}
-	rcu_read_unlock();
-
-	if (ssid) {
-		local->scan_ssid_len = ssid_len;
-		memcpy(local->scan_ssid, ssid, ssid_len);
-	} else
-		local->scan_ssid_len = 0;
-	local->scan_state = SCAN_SET_CHANNEL;
-	local->scan_channel_idx = 0;
-	local->scan_band = IEEE80211_BAND_2GHZ;
-	local->scan_dev = dev;
-
-	netif_addr_lock_bh(local->mdev);
-	local->filter_flags |= FIF_BCN_PRBRESP_PROMISC;
-	local->ops->configure_filter(local_to_hw(local),
-				     FIF_BCN_PRBRESP_PROMISC,
-				     &local->filter_flags,
-				     local->mdev->mc_count,
-				     local->mdev->mc_list);
-	netif_addr_unlock_bh(local->mdev);
-
-	/* TODO: start scan as soon as all nullfunc frames are ACKed */
-	queue_delayed_work(local->hw.workqueue, &local->scan_work,
-			   IEEE80211_CHANNEL_TIME);
-
-	return 0;
-}
-
-
-int ieee80211_sta_req_scan(struct net_device *dev, u8 *ssid, size_t ssid_len)
-{
-	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-	struct ieee80211_if_sta *ifsta = &sdata->u.sta;
-	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-
-	if (sdata->vif.type != IEEE80211_IF_TYPE_STA)
-		return ieee80211_sta_start_scan(dev, ssid, ssid_len);
-
-	if (local->sta_sw_scanning || local->sta_hw_scanning) {
-		if (local->scan_dev == dev)
-			return 0;
-		return -EBUSY;
-	}
-
-	ifsta->scan_ssid_len = ssid_len;
-	if (ssid_len)
-		memcpy(ifsta->scan_ssid, ssid, ssid_len);
-	set_bit(IEEE80211_STA_REQ_SCAN, &ifsta->request);
-	queue_work(local->hw.workqueue, &ifsta->work);
-	return 0;
-}
-
-static char *
-ieee80211_sta_scan_result(struct net_device *dev,
-			  struct iw_request_info *info,
-			  struct ieee80211_sta_bss *bss,
-			  char *current_ev, char *end_buf)
-{
-	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-	struct iw_event iwe;
-
-	if (time_after(jiffies,
-		       bss->last_update + IEEE80211_SCAN_RESULT_EXPIRE))
-		return current_ev;
-
-	memset(&iwe, 0, sizeof(iwe));
-	iwe.cmd = SIOCGIWAP;
-	iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
-	memcpy(iwe.u.ap_addr.sa_data, bss->bssid, ETH_ALEN);
-	current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe,
-					  IW_EV_ADDR_LEN);
-
-	memset(&iwe, 0, sizeof(iwe));
-	iwe.cmd = SIOCGIWESSID;
-	if (bss_mesh_cfg(bss)) {
-		iwe.u.data.length = bss_mesh_id_len(bss);
-		iwe.u.data.flags = 1;
-		current_ev = iwe_stream_add_point(info, current_ev, end_buf,
-						  &iwe, bss_mesh_id(bss));
-	} else {
-		iwe.u.data.length = bss->ssid_len;
-		iwe.u.data.flags = 1;
-		current_ev = iwe_stream_add_point(info, current_ev, end_buf,
-						  &iwe, bss->ssid);
-	}
-
-	if (bss->capability & (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS)
-	    || bss_mesh_cfg(bss)) {
-		memset(&iwe, 0, sizeof(iwe));
-		iwe.cmd = SIOCGIWMODE;
-		if (bss_mesh_cfg(bss))
-			iwe.u.mode = IW_MODE_MESH;
-		else if (bss->capability & WLAN_CAPABILITY_ESS)
-			iwe.u.mode = IW_MODE_MASTER;
-		else
-			iwe.u.mode = IW_MODE_ADHOC;
-		current_ev = iwe_stream_add_event(info, current_ev, end_buf,
-						  &iwe, IW_EV_UINT_LEN);
-	}
-
-	memset(&iwe, 0, sizeof(iwe));
-	iwe.cmd = SIOCGIWFREQ;
-	iwe.u.freq.m = ieee80211_frequency_to_channel(bss->freq);
-	iwe.u.freq.e = 0;
-	current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe,
-					  IW_EV_FREQ_LEN);
-
-	memset(&iwe, 0, sizeof(iwe));
-	iwe.cmd = SIOCGIWFREQ;
-	iwe.u.freq.m = bss->freq;
-	iwe.u.freq.e = 6;
-	current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe,
-					  IW_EV_FREQ_LEN);
-	memset(&iwe, 0, sizeof(iwe));
-	iwe.cmd = IWEVQUAL;
-	iwe.u.qual.qual = bss->qual;
-	iwe.u.qual.level = bss->signal;
-	iwe.u.qual.noise = bss->noise;
-	iwe.u.qual.updated = local->wstats_flags;
-	current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe,
-					  IW_EV_QUAL_LEN);
-
-	memset(&iwe, 0, sizeof(iwe));
-	iwe.cmd = SIOCGIWENCODE;
-	if (bss->capability & WLAN_CAPABILITY_PRIVACY)
-		iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
-	else
-		iwe.u.data.flags = IW_ENCODE_DISABLED;
-	iwe.u.data.length = 0;
-	current_ev = iwe_stream_add_point(info, current_ev, end_buf,
-					  &iwe, "");
-
-	if (bss && bss->wpa_ie) {
-		memset(&iwe, 0, sizeof(iwe));
-		iwe.cmd = IWEVGENIE;
-		iwe.u.data.length = bss->wpa_ie_len;
-		current_ev = iwe_stream_add_point(info, current_ev, end_buf,
-						  &iwe, bss->wpa_ie);
-	}
-
-	if (bss && bss->rsn_ie) {
-		memset(&iwe, 0, sizeof(iwe));
-		iwe.cmd = IWEVGENIE;
-		iwe.u.data.length = bss->rsn_ie_len;
-		current_ev = iwe_stream_add_point(info, current_ev, end_buf,
-						  &iwe, bss->rsn_ie);
-	}
-
-	if (bss && bss->ht_ie) {
-		memset(&iwe, 0, sizeof(iwe));
-		iwe.cmd = IWEVGENIE;
-		iwe.u.data.length = bss->ht_ie_len;
-		current_ev = iwe_stream_add_point(info, current_ev, end_buf,
-						  &iwe, bss->ht_ie);
-	}
-
-	if (bss && bss->supp_rates_len > 0) {
-		/* display all supported rates in readable format */
-		char *p = current_ev + iwe_stream_lcp_len(info);
-		int i;
-
-		memset(&iwe, 0, sizeof(iwe));
-		iwe.cmd = SIOCGIWRATE;
-		/* Those two flags are ignored... */
-		iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
-
-		for (i = 0; i < bss->supp_rates_len; i++) {
-			iwe.u.bitrate.value = ((bss->supp_rates[i] &
-							0x7f) * 500000);
-			p = iwe_stream_add_value(info, current_ev, p,
-					end_buf, &iwe, IW_EV_PARAM_LEN);
-		}
-		current_ev = p;
-	}
-
-	if (bss) {
-		char *buf;
-		buf = kmalloc(30, GFP_ATOMIC);
-		if (buf) {
-			memset(&iwe, 0, sizeof(iwe));
-			iwe.cmd = IWEVCUSTOM;
-			sprintf(buf, "tsf=%016llx", (unsigned long long)(bss->timestamp));
-			iwe.u.data.length = strlen(buf);
-			current_ev = iwe_stream_add_point(info, current_ev,
-							  end_buf,
-							  &iwe, buf);
-			memset(&iwe, 0, sizeof(iwe));
-			iwe.cmd = IWEVCUSTOM;
-			sprintf(buf, " Last beacon: %dms ago",
-				jiffies_to_msecs(jiffies - bss->last_update));
-			iwe.u.data.length = strlen(buf);
-			current_ev = iwe_stream_add_point(info, current_ev,
-							  end_buf, &iwe, buf);
-			kfree(buf);
-		}
-	}
-
-	if (bss_mesh_cfg(bss)) {
-		char *buf;
-		u8 *cfg = bss_mesh_cfg(bss);
-		buf = kmalloc(50, GFP_ATOMIC);
-		if (buf) {
-			memset(&iwe, 0, sizeof(iwe));
-			iwe.cmd = IWEVCUSTOM;
-			sprintf(buf, "Mesh network (version %d)", cfg[0]);
-			iwe.u.data.length = strlen(buf);
-			current_ev = iwe_stream_add_point(info, current_ev,
-							  end_buf,
-							  &iwe, buf);
-			sprintf(buf, "Path Selection Protocol ID: "
-				"0x%02X%02X%02X%02X", cfg[1], cfg[2], cfg[3],
-							cfg[4]);
-			iwe.u.data.length = strlen(buf);
-			current_ev = iwe_stream_add_point(info, current_ev,
-							  end_buf,
-							  &iwe, buf);
-			sprintf(buf, "Path Selection Metric ID: "
-				"0x%02X%02X%02X%02X", cfg[5], cfg[6], cfg[7],
-							cfg[8]);
-			iwe.u.data.length = strlen(buf);
-			current_ev = iwe_stream_add_point(info, current_ev,
-							  end_buf,
-							  &iwe, buf);
-			sprintf(buf, "Congestion Control Mode ID: "
-				"0x%02X%02X%02X%02X", cfg[9], cfg[10],
-							cfg[11], cfg[12]);
-			iwe.u.data.length = strlen(buf);
-			current_ev = iwe_stream_add_point(info, current_ev,
-							  end_buf,
-							  &iwe, buf);
-			sprintf(buf, "Channel Precedence: "
-				"0x%02X%02X%02X%02X", cfg[13], cfg[14],
-							cfg[15], cfg[16]);
-			iwe.u.data.length = strlen(buf);
-			current_ev = iwe_stream_add_point(info, current_ev,
-							  end_buf,
-							  &iwe, buf);
-			kfree(buf);
-		}
-	}
-
-	return current_ev;
-}
-
-
-int ieee80211_sta_scan_results(struct net_device *dev,
-			       struct iw_request_info *info,
-			       char *buf, size_t len)
-{
-	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-	char *current_ev = buf;
-	char *end_buf = buf + len;
-	struct ieee80211_sta_bss *bss;
-
-	spin_lock_bh(&local->sta_bss_lock);
-	list_for_each_entry(bss, &local->sta_bss_list, list) {
-		if (buf + len - current_ev <= IW_EV_ADDR_LEN) {
-			spin_unlock_bh(&local->sta_bss_lock);
-			return -E2BIG;
-		}
-		current_ev = ieee80211_sta_scan_result(dev, info, bss,
-						       current_ev, end_buf);
-	}
-	spin_unlock_bh(&local->sta_bss_lock);
-	return current_ev - buf;
-}
-
-
-int ieee80211_sta_set_extra_ie(struct net_device *dev, char *ie, size_t len)
-{
-	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 	struct ieee80211_if_sta *ifsta = &sdata->u.sta;
 
 	kfree(ifsta->extra_ie);
@@ -4365,92 +2511,60 @@
 	return 0;
 }
 
-
-struct sta_info *ieee80211_ibss_add_sta(struct net_device *dev,
-					struct sk_buff *skb, u8 *bssid,
-					u8 *addr, u64 supp_rates)
+int ieee80211_sta_deauthenticate(struct ieee80211_sub_if_data *sdata, u16 reason)
 {
-	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-	struct sta_info *sta;
-	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-	DECLARE_MAC_BUF(mac);
-	int band = local->hw.conf.channel->band;
-
-	/* TODO: Could consider removing the least recently used entry and
-	 * allow new one to be added. */
-	if (local->num_sta >= IEEE80211_IBSS_MAX_STA_ENTRIES) {
-		if (net_ratelimit()) {
-			printk(KERN_DEBUG "%s: No room for a new IBSS STA "
-			       "entry %s\n", dev->name, print_mac(mac, addr));
-		}
-		return NULL;
-	}
-
-	if (compare_ether_addr(bssid, sdata->u.sta.bssid))
-		return NULL;
-
-#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
-	printk(KERN_DEBUG "%s: Adding new IBSS station %s (dev=%s)\n",
-	       wiphy_name(local->hw.wiphy), print_mac(mac, addr), dev->name);
-#endif
-
-	sta = sta_info_alloc(sdata, addr, GFP_ATOMIC);
-	if (!sta)
-		return NULL;
-
-	set_sta_flags(sta, WLAN_STA_AUTHORIZED);
-
-	if (supp_rates)
-		sta->supp_rates[band] = supp_rates;
-	else
-		sta->supp_rates[band] = sdata->u.sta.supp_rates_bits[band];
-
-	rate_control_rate_init(sta, local);
-
-	if (sta_info_insert(sta))
-		return NULL;
-
-	return sta;
-}
-
-
-int ieee80211_sta_deauthenticate(struct net_device *dev, u16 reason)
-{
-	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 	struct ieee80211_if_sta *ifsta = &sdata->u.sta;
 
 	printk(KERN_DEBUG "%s: deauthenticating by local choice (reason=%d)\n",
-	       dev->name, reason);
+	       sdata->dev->name, reason);
 
-	if (sdata->vif.type != IEEE80211_IF_TYPE_STA &&
-	    sdata->vif.type != IEEE80211_IF_TYPE_IBSS)
+	if (sdata->vif.type != NL80211_IFTYPE_STATION &&
+	    sdata->vif.type != NL80211_IFTYPE_ADHOC)
 		return -EINVAL;
 
-	ieee80211_send_deauth(dev, ifsta, reason);
-	ieee80211_set_disassoc(dev, ifsta, 1);
+	ieee80211_set_disassoc(sdata, ifsta, true, true, reason);
 	return 0;
 }
 
-
-int ieee80211_sta_disassociate(struct net_device *dev, u16 reason)
+int ieee80211_sta_disassociate(struct ieee80211_sub_if_data *sdata, u16 reason)
 {
-	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 	struct ieee80211_if_sta *ifsta = &sdata->u.sta;
 
 	printk(KERN_DEBUG "%s: disassociating by local choice (reason=%d)\n",
-	       dev->name, reason);
+	       sdata->dev->name, reason);
 
-	if (sdata->vif.type != IEEE80211_IF_TYPE_STA)
+	if (sdata->vif.type != NL80211_IFTYPE_STATION)
 		return -EINVAL;
 
 	if (!(ifsta->flags & IEEE80211_STA_ASSOCIATED))
 		return -1;
 
-	ieee80211_send_disassoc(dev, ifsta, reason);
-	ieee80211_set_disassoc(dev, ifsta, 0);
+	ieee80211_set_disassoc(sdata, ifsta, false, true, reason);
 	return 0;
 }
 
+/* scan finished notification */
+void ieee80211_mlme_notify_scan_completed(struct ieee80211_local *local)
+{
+	struct ieee80211_sub_if_data *sdata = local->scan_sdata;
+	struct ieee80211_if_sta *ifsta;
+
+	if (sdata && sdata->vif.type == NL80211_IFTYPE_ADHOC) {
+		ifsta = &sdata->u.sta;
+		if (!(ifsta->flags & IEEE80211_STA_BSSID_SET) ||
+		    (!(ifsta->state == IEEE80211_STA_MLME_IBSS_JOINED) &&
+		    !ieee80211_sta_active_ibss(sdata)))
+			ieee80211_sta_find_ibss(sdata, ifsta);
+	}
+
+	/* Restart STA timers */
+	rcu_read_lock();
+	list_for_each_entry_rcu(sdata, &local->interfaces, list)
+		ieee80211_restart_sta_timer(sdata);
+	rcu_read_unlock();
+}
+
+/* driver notification call */
 void ieee80211_notify_mac(struct ieee80211_hw *hw,
 			  enum ieee80211_notification_types  notif_type)
 {
@@ -4461,10 +2575,10 @@
 	case IEEE80211_NOTIFY_RE_ASSOC:
 		rcu_read_lock();
 		list_for_each_entry_rcu(sdata, &local->interfaces, list) {
-			if (sdata->vif.type != IEEE80211_IF_TYPE_STA)
+			if (sdata->vif.type != NL80211_IFTYPE_STATION)
 				continue;
 
-			ieee80211_sta_req_auth(sdata->dev, &sdata->u.sta);
+			ieee80211_sta_req_auth(sdata, &sdata->u.sta);
 		}
 		rcu_read_unlock();
 		break;
diff --git a/net/mac80211/rate.c b/net/mac80211/rate.c
index 0388c09..5d78672 100644
--- a/net/mac80211/rate.c
+++ b/net/mac80211/rate.c
@@ -12,6 +12,7 @@
 #include <linux/rtnetlink.h>
 #include "rate.h"
 #include "ieee80211_i.h"
+#include "debugfs.h"
 
 struct rate_control_alg {
 	struct list_head list;
@@ -127,19 +128,46 @@
 	module_put(ops->module);
 }
 
+#ifdef CONFIG_MAC80211_DEBUGFS
+static ssize_t rcname_read(struct file *file, char __user *userbuf,
+			   size_t count, loff_t *ppos)
+{
+	struct rate_control_ref *ref = file->private_data;
+	int len = strlen(ref->ops->name);
+
+	return simple_read_from_buffer(userbuf, count, ppos,
+				       ref->ops->name, len);
+}
+
+static const struct file_operations rcname_ops = {
+	.read = rcname_read,
+	.open = mac80211_open_file_generic,
+};
+#endif
+
 struct rate_control_ref *rate_control_alloc(const char *name,
 					    struct ieee80211_local *local)
 {
+	struct dentry *debugfsdir = NULL;
 	struct rate_control_ref *ref;
 
 	ref = kmalloc(sizeof(struct rate_control_ref), GFP_KERNEL);
 	if (!ref)
 		goto fail_ref;
 	kref_init(&ref->kref);
+	ref->local = local;
 	ref->ops = ieee80211_rate_control_ops_get(name);
 	if (!ref->ops)
 		goto fail_ops;
-	ref->priv = ref->ops->alloc(local);
+
+#ifdef CONFIG_MAC80211_DEBUGFS
+	debugfsdir = debugfs_create_dir("rc", local->hw.wiphy->debugfsdir);
+	local->debugfs.rcdir = debugfsdir;
+	local->debugfs.rcname = debugfs_create_file("name", 0400, debugfsdir,
+						    ref, &rcname_ops);
+#endif
+
+	ref->priv = ref->ops->alloc(&local->hw, debugfsdir);
 	if (!ref->priv)
 		goto fail_priv;
 	return ref;
@@ -158,29 +186,46 @@
 
 	ctrl_ref = container_of(kref, struct rate_control_ref, kref);
 	ctrl_ref->ops->free(ctrl_ref->priv);
+
+#ifdef CONFIG_MAC80211_DEBUGFS
+	debugfs_remove(ctrl_ref->local->debugfs.rcname);
+	ctrl_ref->local->debugfs.rcname = NULL;
+	debugfs_remove(ctrl_ref->local->debugfs.rcdir);
+	ctrl_ref->local->debugfs.rcdir = NULL;
+#endif
+
 	ieee80211_rate_control_ops_put(ctrl_ref->ops);
 	kfree(ctrl_ref);
 }
 
-void rate_control_get_rate(struct net_device *dev,
+void rate_control_get_rate(struct ieee80211_sub_if_data *sdata,
 			   struct ieee80211_supported_band *sband,
-			   struct sk_buff *skb,
+			   struct sta_info *sta, struct sk_buff *skb,
 			   struct rate_selection *sel)
 {
-	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-	struct rate_control_ref *ref = local->rate_ctrl;
-	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
-	struct sta_info *sta;
+	struct rate_control_ref *ref = sdata->local->rate_ctrl;
+	void *priv_sta = NULL;
+	struct ieee80211_sta *ista = NULL;
 	int i;
 
-	rcu_read_lock();
-	sta = sta_info_get(local, hdr->addr1);
-
 	sel->rate_idx = -1;
 	sel->nonerp_idx = -1;
 	sel->probe_idx = -1;
+	sel->max_rate_idx = sdata->max_ratectrl_rateidx;
 
-	ref->ops->get_rate(ref->priv, dev, sband, skb, sel);
+	if (sta) {
+		ista = &sta->sta;
+		priv_sta = sta->rate_ctrl_priv;
+	}
+
+	if (sta && sdata->force_unicast_rateidx > -1)
+		sel->rate_idx = sdata->force_unicast_rateidx;
+	else
+		ref->ops->get_rate(ref->priv, sband, ista, priv_sta, skb, sel);
+
+	if (sdata->max_ratectrl_rateidx > -1 &&
+	    sel->rate_idx > sdata->max_ratectrl_rateidx)
+		sel->rate_idx = sdata->max_ratectrl_rateidx;
 
 	BUG_ON(sel->rate_idx < 0);
 
@@ -191,13 +236,11 @@
 			if (sband->bitrates[sel->rate_idx].bitrate < rate->bitrate)
 				break;
 
-			if (rate_supported(sta, sband->band, i) &&
+			if (rate_supported(ista, sband->band, i) &&
 			    !(rate->flags & IEEE80211_RATE_ERP_G))
 				sel->nonerp_idx = i;
 		}
 	}
-
-	rcu_read_unlock();
 }
 
 struct rate_control_ref *rate_control_get(struct rate_control_ref *ref)
diff --git a/net/mac80211/rate.h b/net/mac80211/rate.h
index ede7ab5..d0092f8 100644
--- a/net/mac80211/rate.h
+++ b/net/mac80211/rate.h
@@ -19,77 +19,48 @@
 #include "ieee80211_i.h"
 #include "sta_info.h"
 
-/**
- * struct rate_selection - rate selection for rate control algos
- * @rate: selected transmission rate index
- * @nonerp: Non-ERP rate to use instead if ERP cannot be used
- * @probe: rate for probing (or -1)
- *
- */
-struct rate_selection {
-	s8 rate_idx, nonerp_idx, probe_idx;
-};
-
-struct rate_control_ops {
-	struct module *module;
-	const char *name;
-	void (*tx_status)(void *priv, struct net_device *dev,
-			  struct sk_buff *skb);
-	void (*get_rate)(void *priv, struct net_device *dev,
-			 struct ieee80211_supported_band *band,
-			 struct sk_buff *skb,
-			 struct rate_selection *sel);
-	void (*rate_init)(void *priv, void *priv_sta,
-			  struct ieee80211_local *local, struct sta_info *sta);
-	void (*clear)(void *priv);
-
-	void *(*alloc)(struct ieee80211_local *local);
-	void (*free)(void *priv);
-	void *(*alloc_sta)(void *priv, gfp_t gfp);
-	void (*free_sta)(void *priv, void *priv_sta);
-
-	int (*add_attrs)(void *priv, struct kobject *kobj);
-	void (*remove_attrs)(void *priv, struct kobject *kobj);
-	void (*add_sta_debugfs)(void *priv, void *priv_sta,
-				struct dentry *dir);
-	void (*remove_sta_debugfs)(void *priv, void *priv_sta);
-};
-
 struct rate_control_ref {
+	struct ieee80211_local *local;
 	struct rate_control_ops *ops;
 	void *priv;
 	struct kref kref;
 };
 
-int ieee80211_rate_control_register(struct rate_control_ops *ops);
-void ieee80211_rate_control_unregister(struct rate_control_ops *ops);
-
 /* Get a reference to the rate control algorithm. If `name' is NULL, get the
  * first available algorithm. */
 struct rate_control_ref *rate_control_alloc(const char *name,
 					    struct ieee80211_local *local);
-void rate_control_get_rate(struct net_device *dev,
+void rate_control_get_rate(struct ieee80211_sub_if_data *sdata,
 			   struct ieee80211_supported_band *sband,
-			   struct sk_buff *skb,
+			   struct sta_info *sta, struct sk_buff *skb,
 			   struct rate_selection *sel);
 struct rate_control_ref *rate_control_get(struct rate_control_ref *ref);
 void rate_control_put(struct rate_control_ref *ref);
 
-static inline void rate_control_tx_status(struct net_device *dev,
+static inline void rate_control_tx_status(struct ieee80211_local *local,
+					  struct ieee80211_supported_band *sband,
+					  struct sta_info *sta,
 					  struct sk_buff *skb)
 {
-	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
 	struct rate_control_ref *ref = local->rate_ctrl;
+	struct ieee80211_sta *ista = &sta->sta;
+	void *priv_sta = sta->rate_ctrl_priv;
 
-	ref->ops->tx_status(ref->priv, dev, skb);
+	ref->ops->tx_status(ref->priv, sband, ista, priv_sta, skb);
 }
 
 
-static inline void rate_control_rate_init(struct sta_info *sta,
-					  struct ieee80211_local *local)
+static inline void rate_control_rate_init(struct sta_info *sta)
 {
+	struct ieee80211_local *local = sta->sdata->local;
 	struct rate_control_ref *ref = sta->rate_ctrl;
-	ref->ops->rate_init(ref->priv, sta->rate_ctrl_priv, local, sta);
+	struct ieee80211_sta *ista = &sta->sta;
+	void *priv_sta = sta->rate_ctrl_priv;
+	struct ieee80211_supported_band *sband;
+
+	sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
+
+	ref->ops->rate_init(ref->priv, sband, ista, priv_sta);
 }
 
 
@@ -100,15 +71,19 @@
 }
 
 static inline void *rate_control_alloc_sta(struct rate_control_ref *ref,
+					   struct ieee80211_sta *sta,
 					   gfp_t gfp)
 {
-	return ref->ops->alloc_sta(ref->priv, gfp);
+	return ref->ops->alloc_sta(ref->priv, sta, gfp);
 }
 
-static inline void rate_control_free_sta(struct rate_control_ref *ref,
-					 void *priv)
+static inline void rate_control_free_sta(struct sta_info *sta)
 {
-	ref->ops->free_sta(ref->priv, priv);
+	struct rate_control_ref *ref = sta->rate_ctrl;
+	struct ieee80211_sta *ista = &sta->sta;
+	void *priv_sta = sta->rate_ctrl_priv;
+
+	ref->ops->free_sta(ref->priv, ista, priv_sta);
 }
 
 static inline void rate_control_add_sta_debugfs(struct sta_info *sta)
@@ -130,31 +105,6 @@
 #endif
 }
 
-static inline int rate_supported(struct sta_info *sta,
-				 enum ieee80211_band band,
-				 int index)
-{
-	return (sta == NULL || sta->supp_rates[band] & BIT(index));
-}
-
-static inline s8
-rate_lowest_index(struct ieee80211_local *local,
-		  struct ieee80211_supported_band *sband,
-		  struct sta_info *sta)
-{
-	int i;
-
-	for (i = 0; i < sband->n_bitrates; i++)
-		if (rate_supported(sta, sband->band, i))
-			return i;
-
-	/* warn when we cannot find a rate. */
-	WARN_ON(1);
-
-	return 0;
-}
-
-
 /* functions for rate control related to a device */
 int ieee80211_init_rate_ctrl_alg(struct ieee80211_local *local,
 				 const char *name);
@@ -175,4 +125,18 @@
 }
 #endif
 
+#ifdef CONFIG_MAC80211_RC_MINSTREL
+extern int rc80211_minstrel_init(void);
+extern void rc80211_minstrel_exit(void);
+#else
+static inline int rc80211_minstrel_init(void)
+{
+	return 0;
+}
+static inline void rc80211_minstrel_exit(void)
+{
+}
+#endif
+
+
 #endif /* IEEE80211_RATE_H */
diff --git a/net/mac80211/rc80211_minstrel.c b/net/mac80211/rc80211_minstrel.c
new file mode 100644
index 0000000..f6d69da
--- /dev/null
+++ b/net/mac80211/rc80211_minstrel.c
@@ -0,0 +1,583 @@
+/*
+ * Copyright (C) 2008 Felix Fietkau <nbd@openwrt.org>
+ *
+ * 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.
+ *
+ * Based on minstrel.c:
+ *   Copyright (C) 2005-2007 Derek Smithies <derek@indranet.co.nz>
+ *   Sponsored by Indranet Technologies Ltd
+ *
+ * Based on sample.c:
+ *   Copyright (c) 2005 John Bicket
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer,
+ *      without modification.
+ *   2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *      similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
+ *      redistribution must be conditioned upon including a substantially
+ *      similar Disclaimer requirement for further binary redistribution.
+ *   3. Neither the names of the above-listed copyright holders nor the names
+ *      of any contributors may be used to endorse or promote products derived
+ *      from this software without specific prior written permission.
+ *
+ *   Alternatively, this software may be distributed under the terms of the
+ *   GNU General Public License ("GPL") version 2 as published by the Free
+ *   Software Foundation.
+ *
+ *   NO WARRANTY
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
+ *   AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ *   THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
+ */
+#include <linux/netdevice.h>
+#include <linux/types.h>
+#include <linux/skbuff.h>
+#include <linux/debugfs.h>
+#include <linux/random.h>
+#include <linux/ieee80211.h>
+#include <net/mac80211.h>
+#include "rate.h"
+#include "rc80211_minstrel.h"
+
+#define SAMPLE_COLUMNS	10
+#define SAMPLE_TBL(_mi, _idx, _col) \
+		_mi->sample_table[(_idx * SAMPLE_COLUMNS) + _col]
+
+/* convert mac80211 rate index to local array index */
+static inline int
+rix_to_ndx(struct minstrel_sta_info *mi, int rix)
+{
+	int i = rix;
+	for (i = rix; i >= 0; i--)
+		if (mi->r[i].rix == rix)
+			break;
+	WARN_ON(mi->r[i].rix != rix);
+	return i;
+}
+
+static inline bool
+use_low_rate(struct sk_buff *skb)
+{
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+	u16 fc;
+
+	fc = le16_to_cpu(hdr->frame_control);
+
+	return ((info->flags & IEEE80211_TX_CTL_NO_ACK) ||
+		(fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA ||
+		is_multicast_ether_addr(hdr->addr1));
+}
+
+
+static void
+minstrel_update_stats(struct minstrel_priv *mp, struct minstrel_sta_info *mi)
+{
+	u32 max_tp = 0, index_max_tp = 0, index_max_tp2 = 0;
+	u32 max_prob = 0, index_max_prob = 0;
+	u32 usecs;
+	u32 p;
+	int i;
+
+	mi->stats_update = jiffies;
+	for (i = 0; i < mi->n_rates; i++) {
+		struct minstrel_rate *mr = &mi->r[i];
+
+		usecs = mr->perfect_tx_time;
+		if (!usecs)
+			usecs = 1000000;
+
+		/* To avoid rounding issues, probabilities scale from 0 (0%)
+		 * to 18000 (100%) */
+		if (mr->attempts) {
+			p = (mr->success * 18000) / mr->attempts;
+			mr->succ_hist += mr->success;
+			mr->att_hist += mr->attempts;
+			mr->cur_prob = p;
+			p = ((p * (100 - mp->ewma_level)) + (mr->probability *
+				mp->ewma_level)) / 100;
+			mr->probability = p;
+			mr->cur_tp = p * (1000000 / usecs);
+		}
+
+		mr->last_success = mr->success;
+		mr->last_attempts = mr->attempts;
+		mr->success = 0;
+		mr->attempts = 0;
+
+		/* Sample less often below the 10% chance of success.
+		 * Sample less often above the 95% chance of success. */
+		if ((mr->probability > 17100) || (mr->probability < 1800)) {
+			mr->adjusted_retry_count = mr->retry_count >> 1;
+			if (mr->adjusted_retry_count > 2)
+				mr->adjusted_retry_count = 2;
+		} else {
+			mr->adjusted_retry_count = mr->retry_count;
+		}
+		if (!mr->adjusted_retry_count)
+			mr->adjusted_retry_count = 2;
+	}
+
+	for (i = 0; i < mi->n_rates; i++) {
+		struct minstrel_rate *mr = &mi->r[i];
+		if (max_tp < mr->cur_tp) {
+			index_max_tp = i;
+			max_tp = mr->cur_tp;
+		}
+		if (max_prob < mr->probability) {
+			index_max_prob = i;
+			max_prob = mr->probability;
+		}
+	}
+
+	max_tp = 0;
+	for (i = 0; i < mi->n_rates; i++) {
+		struct minstrel_rate *mr = &mi->r[i];
+
+		if (i == index_max_tp)
+			continue;
+
+		if (max_tp < mr->cur_tp) {
+			index_max_tp2 = i;
+			max_tp = mr->cur_tp;
+		}
+	}
+	mi->max_tp_rate = index_max_tp;
+	mi->max_tp_rate2 = index_max_tp2;
+	mi->max_prob_rate = index_max_prob;
+}
+
+static void
+minstrel_tx_status(void *priv, struct ieee80211_supported_band *sband,
+                   struct ieee80211_sta *sta, void *priv_sta,
+		   struct sk_buff *skb)
+{
+	struct minstrel_sta_info *mi = priv_sta;
+	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+	struct ieee80211_tx_altrate *ar = info->status.retries;
+	struct minstrel_priv *mp = priv;
+	int i, ndx, tries;
+	int success = 0;
+
+	if (!info->status.excessive_retries)
+		success = 1;
+
+	if (!mp->has_mrr || (ar[0].rate_idx < 0)) {
+		ndx = rix_to_ndx(mi, info->tx_rate_idx);
+		tries = info->status.retry_count + 1;
+		mi->r[ndx].success += success;
+		mi->r[ndx].attempts += tries;
+		return;
+	}
+
+	for (i = 0; i < 4; i++) {
+		if (ar[i].rate_idx < 0)
+			break;
+
+		ndx = rix_to_ndx(mi, ar[i].rate_idx);
+		mi->r[ndx].attempts += ar[i].limit + 1;
+
+		if ((i != 3) && (ar[i + 1].rate_idx < 0))
+			mi->r[ndx].success += success;
+	}
+
+	if ((info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) && (i >= 0))
+		mi->sample_count++;
+
+	if (mi->sample_deferred > 0)
+		mi->sample_deferred--;
+}
+
+
+static inline unsigned int
+minstrel_get_retry_count(struct minstrel_rate *mr,
+                         struct ieee80211_tx_info *info)
+{
+	unsigned int retry = mr->adjusted_retry_count;
+
+	if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS)
+		retry = max(2U, min(mr->retry_count_rtscts, retry));
+	else if (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT)
+		retry = max(2U, min(mr->retry_count_cts, retry));
+	return retry;
+}
+
+
+static int
+minstrel_get_next_sample(struct minstrel_sta_info *mi)
+{
+	unsigned int sample_ndx;
+	sample_ndx = SAMPLE_TBL(mi, mi->sample_idx, mi->sample_column);
+	mi->sample_idx++;
+	if (mi->sample_idx > (mi->n_rates - 2)) {
+		mi->sample_idx = 0;
+		mi->sample_column++;
+		if (mi->sample_column >= SAMPLE_COLUMNS)
+			mi->sample_column = 0;
+	}
+	return sample_ndx;
+}
+
+void
+minstrel_get_rate(void *priv, struct ieee80211_supported_band *sband,
+                  struct ieee80211_sta *sta, void *priv_sta,
+                  struct sk_buff *skb, struct rate_selection *sel)
+{
+	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+	struct minstrel_sta_info *mi = priv_sta;
+	struct minstrel_priv *mp = priv;
+	struct ieee80211_tx_altrate *ar = info->control.retries;
+	unsigned int ndx, sample_ndx = 0;
+	bool mrr;
+	bool sample_slower = false;
+	bool sample = false;
+	int i, delta;
+	int mrr_ndx[3];
+	int sample_rate;
+
+	if (!sta || !mi || use_low_rate(skb)) {
+		sel->rate_idx = rate_lowest_index(sband, sta);
+		return;
+	}
+
+	mrr = mp->has_mrr;
+
+	/* mac80211 does not allow mrr for RTS/CTS */
+	if ((info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) ||
+	    (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT))
+		mrr = false;
+
+	if (time_after(jiffies, mi->stats_update + (mp->update_interval *
+			HZ) / 1000))
+		minstrel_update_stats(mp, mi);
+
+	ndx = mi->max_tp_rate;
+
+	if (mrr)
+		sample_rate = mp->lookaround_rate_mrr;
+	else
+		sample_rate = mp->lookaround_rate;
+
+	mi->packet_count++;
+	delta = (mi->packet_count * sample_rate / 100) -
+			(mi->sample_count + mi->sample_deferred / 2);
+
+	/* delta > 0: sampling required */
+	if (delta > 0) {
+		if (mi->packet_count >= 10000) {
+			mi->sample_deferred = 0;
+			mi->sample_count = 0;
+			mi->packet_count = 0;
+		} else if (delta > mi->n_rates * 2) {
+			/* With multi-rate retry, not every planned sample
+			 * attempt actually gets used, due to the way the retry
+			 * chain is set up - [max_tp,sample,prob,lowest] for
+			 * sample_rate < max_tp.
+			 *
+			 * If there's too much sampling backlog and the link
+			 * starts getting worse, minstrel would start bursting
+			 * out lots of sampling frames, which would result
+			 * in a large throughput loss. */
+			mi->sample_count += (delta - mi->n_rates * 2);
+		}
+
+		sample_ndx = minstrel_get_next_sample(mi);
+		sample = true;
+		sample_slower = mrr && (mi->r[sample_ndx].perfect_tx_time >
+			mi->r[ndx].perfect_tx_time);
+
+		if (!sample_slower) {
+			ndx = sample_ndx;
+			mi->sample_count++;
+		} else {
+			/* Only use IEEE80211_TX_CTL_RATE_CTRL_PROBE to mark
+			 * packets that have the sampling rate deferred to the
+			 * second MRR stage. Increase the sample counter only
+			 * if the deferred sample rate was actually used.
+			 * Use the sample_deferred counter to make sure that
+			 * the sampling is not done in large bursts */
+			info->flags |= IEEE80211_TX_CTL_RATE_CTRL_PROBE;
+			mi->sample_deferred++;
+		}
+	}
+	sel->rate_idx = mi->r[ndx].rix;
+	info->control.retry_limit = minstrel_get_retry_count(&mi->r[ndx], info);
+
+	if (!mrr) {
+		ar[0].rate_idx = mi->lowest_rix;
+		ar[0].limit = mp->max_retry;
+		ar[1].rate_idx = -1;
+		return;
+	}
+
+	/* MRR setup */
+	if (sample) {
+		if (sample_slower)
+			mrr_ndx[0] = sample_ndx;
+		else
+			mrr_ndx[0] = mi->max_tp_rate;
+	} else {
+		mrr_ndx[0] = mi->max_tp_rate2;
+	}
+	mrr_ndx[1] = mi->max_prob_rate;
+	mrr_ndx[2] = 0;
+	for (i = 0; i < 3; i++) {
+		ar[i].rate_idx = mi->r[mrr_ndx[i]].rix;
+		ar[i].limit = mi->r[mrr_ndx[i]].adjusted_retry_count;
+	}
+}
+
+
+static void
+calc_rate_durations(struct minstrel_sta_info *mi, struct ieee80211_local *local,
+                    struct minstrel_rate *d, struct ieee80211_rate *rate)
+{
+	int erp = !!(rate->flags & IEEE80211_RATE_ERP_G);
+
+	d->perfect_tx_time = ieee80211_frame_duration(local, 1200,
+			rate->bitrate, erp, 1);
+	d->ack_time = ieee80211_frame_duration(local, 10,
+			rate->bitrate, erp, 1);
+}
+
+static void
+init_sample_table(struct minstrel_sta_info *mi)
+{
+	unsigned int i, col, new_idx;
+	unsigned int n_srates = mi->n_rates - 1;
+	u8 rnd[8];
+
+	mi->sample_column = 0;
+	mi->sample_idx = 0;
+	memset(mi->sample_table, 0, SAMPLE_COLUMNS * mi->n_rates);
+
+	for (col = 0; col < SAMPLE_COLUMNS; col++) {
+		for (i = 0; i < n_srates; i++) {
+			get_random_bytes(rnd, sizeof(rnd));
+			new_idx = (i + rnd[i & 7]) % n_srates;
+
+			while (SAMPLE_TBL(mi, new_idx, col) != 0)
+				new_idx = (new_idx + 1) % n_srates;
+
+			/* Don't sample the slowest rate (i.e. slowest base
+			 * rate). We must presume that the slowest rate works
+			 * fine, or else other management frames will also be
+			 * failing and the link will break */
+			SAMPLE_TBL(mi, new_idx, col) = i + 1;
+		}
+	}
+}
+
+static void
+minstrel_rate_init(void *priv, struct ieee80211_supported_band *sband,
+               struct ieee80211_sta *sta, void *priv_sta)
+{
+	struct minstrel_sta_info *mi = priv_sta;
+	struct minstrel_priv *mp = priv;
+	struct minstrel_rate *mr_ctl;
+	unsigned int i, n = 0;
+	unsigned int t_slot = 9; /* FIXME: get real slot time */
+
+	mi->lowest_rix = rate_lowest_index(sband, sta);
+	mr_ctl = &mi->r[rix_to_ndx(mi, mi->lowest_rix)];
+	mi->sp_ack_dur = mr_ctl->ack_time;
+
+	for (i = 0; i < sband->n_bitrates; i++) {
+		struct minstrel_rate *mr = &mi->r[n];
+		unsigned int tx_time = 0, tx_time_cts = 0, tx_time_rtscts = 0;
+		unsigned int tx_time_single;
+		unsigned int cw = mp->cw_min;
+
+		if (!rate_supported(sta, sband->band, i))
+			continue;
+		n++;
+		memset(mr, 0, sizeof(*mr));
+
+		mr->rix = i;
+		mr->bitrate = sband->bitrates[i].bitrate / 5;
+		calc_rate_durations(mi, hw_to_local(mp->hw), mr,
+				&sband->bitrates[i]);
+
+		/* calculate maximum number of retransmissions before
+		 * fallback (based on maximum segment size) */
+		mr->retry_count = 1;
+		mr->retry_count_cts = 1;
+		mr->retry_count_rtscts = 1;
+		tx_time = mr->perfect_tx_time + mi->sp_ack_dur;
+		do {
+			/* add one retransmission */
+			tx_time_single = mr->ack_time + mr->perfect_tx_time;
+
+			/* contention window */
+			tx_time_single += t_slot + min(cw, mp->cw_max);
+			cw = (cw + 1) << 1;
+
+			tx_time += tx_time_single;
+			tx_time_cts += tx_time_single + mi->sp_ack_dur;
+			tx_time_rtscts += tx_time_single + 2 * mi->sp_ack_dur;
+			if ((tx_time_cts < mp->segment_size) &&
+				(mr->retry_count_cts < mp->max_retry))
+				mr->retry_count_cts++;
+			if ((tx_time_rtscts < mp->segment_size) &&
+				(mr->retry_count_rtscts < mp->max_retry))
+				mr->retry_count_rtscts++;
+		} while ((tx_time < mp->segment_size) &&
+				(++mr->retry_count < mp->max_retry));
+		mr->adjusted_retry_count = mr->retry_count;
+	}
+
+	for (i = n; i < sband->n_bitrates; i++) {
+		struct minstrel_rate *mr = &mi->r[i];
+		mr->rix = -1;
+	}
+
+	mi->n_rates = n;
+	mi->stats_update = jiffies;
+
+	init_sample_table(mi);
+}
+
+static void *
+minstrel_alloc_sta(void *priv, struct ieee80211_sta *sta, gfp_t gfp)
+{
+	struct ieee80211_supported_band *sband;
+	struct minstrel_sta_info *mi;
+	struct minstrel_priv *mp = priv;
+	struct ieee80211_hw *hw = mp->hw;
+	int max_rates = 0;
+	int i;
+
+	mi = kzalloc(sizeof(struct minstrel_sta_info), gfp);
+	if (!mi)
+		return NULL;
+
+	for (i = 0; i < IEEE80211_NUM_BANDS; i++) {
+		sband = hw->wiphy->bands[hw->conf.channel->band];
+		if (sband->n_bitrates > max_rates)
+			max_rates = sband->n_bitrates;
+	}
+
+	mi->r = kzalloc(sizeof(struct minstrel_rate) * max_rates, gfp);
+	if (!mi->r)
+		goto error;
+
+	mi->sample_table = kmalloc(SAMPLE_COLUMNS * max_rates, gfp);
+	if (!mi->sample_table)
+		goto error1;
+
+	mi->stats_update = jiffies;
+	return mi;
+
+error1:
+	kfree(mi->r);
+error:
+	kfree(mi);
+	return NULL;
+}
+
+static void
+minstrel_free_sta(void *priv, struct ieee80211_sta *sta, void *priv_sta)
+{
+	struct minstrel_sta_info *mi = priv_sta;
+
+	kfree(mi->sample_table);
+	kfree(mi->r);
+	kfree(mi);
+}
+
+static void
+minstrel_clear(void *priv)
+{
+}
+
+static void *
+minstrel_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir)
+{
+	struct minstrel_priv *mp;
+
+	mp = kzalloc(sizeof(struct minstrel_priv), GFP_ATOMIC);
+	if (!mp)
+		return NULL;
+
+	/* contention window settings
+	 * Just an approximation. Using the per-queue values would complicate
+	 * the calculations and is probably unnecessary */
+	mp->cw_min = 15;
+	mp->cw_max = 1023;
+
+	/* number of packets (in %) to use for sampling other rates
+	 * sample less often for non-mrr packets, because the overhead
+	 * is much higher than with mrr */
+	mp->lookaround_rate = 5;
+	mp->lookaround_rate_mrr = 10;
+
+	/* moving average weight for EWMA */
+	mp->ewma_level = 75;
+
+	/* maximum time that the hw is allowed to stay in one MRR segment */
+	mp->segment_size = 6000;
+
+	if (hw->max_altrate_tries > 0)
+		mp->max_retry = hw->max_altrate_tries;
+	else
+		/* safe default, does not necessarily have to match hw properties */
+		mp->max_retry = 7;
+
+	if (hw->max_altrates >= 3)
+		mp->has_mrr = true;
+
+	mp->hw = hw;
+	mp->update_interval = 100;
+
+	return mp;
+}
+
+static void
+minstrel_free(void *priv)
+{
+	kfree(priv);
+}
+
+static struct rate_control_ops mac80211_minstrel = {
+	.name = "minstrel",
+	.tx_status = minstrel_tx_status,
+	.get_rate = minstrel_get_rate,
+	.rate_init = minstrel_rate_init,
+	.clear = minstrel_clear,
+	.alloc = minstrel_alloc,
+	.free = minstrel_free,
+	.alloc_sta = minstrel_alloc_sta,
+	.free_sta = minstrel_free_sta,
+#ifdef CONFIG_MAC80211_DEBUGFS
+	.add_sta_debugfs = minstrel_add_sta_debugfs,
+	.remove_sta_debugfs = minstrel_remove_sta_debugfs,
+#endif
+};
+
+int __init
+rc80211_minstrel_init(void)
+{
+	return ieee80211_rate_control_register(&mac80211_minstrel);
+}
+
+void
+rc80211_minstrel_exit(void)
+{
+	ieee80211_rate_control_unregister(&mac80211_minstrel);
+}
+
diff --git a/net/mac80211/rc80211_minstrel.h b/net/mac80211/rc80211_minstrel.h
new file mode 100644
index 0000000..9a90a6a
--- /dev/null
+++ b/net/mac80211/rc80211_minstrel.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2008 Felix Fietkau <nbd@openwrt.org>
+ *
+ * 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 __RC_MINSTREL_H
+#define __RC_MINSTREL_H
+
+struct minstrel_rate {
+	int bitrate;
+	int rix;
+
+	unsigned int perfect_tx_time;
+	unsigned int ack_time;
+
+	unsigned int retry_count;
+	unsigned int retry_count_cts;
+	unsigned int retry_count_rtscts;
+	unsigned int adjusted_retry_count;
+
+	u32 success;
+	u32 attempts;
+	u32 last_attempts;
+	u32 last_success;
+
+	/* parts per thousand */
+	u32 cur_prob;
+	u32 probability;
+
+	/* per-rate throughput */
+	u32 cur_tp;
+	u32 throughput;
+
+	u64 succ_hist;
+	u64 att_hist;
+};
+
+struct minstrel_sta_info {
+	unsigned long stats_update;
+	unsigned int sp_ack_dur;
+	unsigned int rate_avg;
+
+	unsigned int lowest_rix;
+
+	unsigned int max_tp_rate;
+	unsigned int max_tp_rate2;
+	unsigned int max_prob_rate;
+	unsigned int packet_count;
+	unsigned int sample_count;
+	int sample_deferred;
+
+	unsigned int sample_idx;
+	unsigned int sample_column;
+
+	int n_rates;
+	struct minstrel_rate *r;
+
+	/* sampling table */
+	u8 *sample_table;
+
+#ifdef CONFIG_MAC80211_DEBUGFS
+	struct dentry *dbg_stats;
+#endif
+};
+
+struct minstrel_priv {
+	struct ieee80211_hw *hw;
+	bool has_mrr;
+	unsigned int cw_min;
+	unsigned int cw_max;
+	unsigned int max_retry;
+	unsigned int ewma_level;
+	unsigned int segment_size;
+	unsigned int update_interval;
+	unsigned int lookaround_rate;
+	unsigned int lookaround_rate_mrr;
+};
+
+void minstrel_add_sta_debugfs(void *priv, void *priv_sta, struct dentry *dir);
+void minstrel_remove_sta_debugfs(void *priv, void *priv_sta);
+
+#endif
diff --git a/net/mac80211/rc80211_minstrel_debugfs.c b/net/mac80211/rc80211_minstrel_debugfs.c
new file mode 100644
index 0000000..0b024cd
--- /dev/null
+++ b/net/mac80211/rc80211_minstrel_debugfs.c
@@ -0,0 +1,164 @@
+/*
+ * Copyright (C) 2008 Felix Fietkau <nbd@openwrt.org>
+ *
+ * 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.
+ *
+ * Based on minstrel.c:
+ *   Copyright (C) 2005-2007 Derek Smithies <derek@indranet.co.nz>
+ *   Sponsored by Indranet Technologies Ltd
+ *
+ * Based on sample.c:
+ *   Copyright (c) 2005 John Bicket
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer,
+ *      without modification.
+ *   2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *      similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
+ *      redistribution must be conditioned upon including a substantially
+ *      similar Disclaimer requirement for further binary redistribution.
+ *   3. Neither the names of the above-listed copyright holders nor the names
+ *      of any contributors may be used to endorse or promote products derived
+ *      from this software without specific prior written permission.
+ *
+ *   Alternatively, this software may be distributed under the terms of the
+ *   GNU General Public License ("GPL") version 2 as published by the Free
+ *   Software Foundation.
+ *
+ *   NO WARRANTY
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
+ *   AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ *   THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
+ */
+#include <linux/netdevice.h>
+#include <linux/types.h>
+#include <linux/skbuff.h>
+#include <linux/debugfs.h>
+#include <linux/ieee80211.h>
+#include <net/mac80211.h>
+#include "rc80211_minstrel.h"
+
+struct minstrel_stats_info {
+	struct minstrel_sta_info *mi;
+	char buf[4096];
+	size_t len;
+};
+
+static int
+minstrel_stats_open(struct inode *inode, struct file *file)
+{
+	struct minstrel_sta_info *mi = inode->i_private;
+	struct minstrel_stats_info *ms;
+	unsigned int i, tp, prob, eprob;
+	char *p;
+
+	ms = kmalloc(sizeof(*ms), GFP_KERNEL);
+	if (!ms)
+		return -ENOMEM;
+
+	file->private_data = ms;
+	p = ms->buf;
+	p += sprintf(p, "rate     throughput  ewma prob   this prob  "
+			"this succ/attempt   success    attempts\n");
+	for (i = 0; i < mi->n_rates; i++) {
+		struct minstrel_rate *mr = &mi->r[i];
+
+		*(p++) = (i == mi->max_tp_rate) ? 'T' : ' ';
+		*(p++) = (i == mi->max_tp_rate2) ? 't' : ' ';
+		*(p++) = (i == mi->max_prob_rate) ? 'P' : ' ';
+		p += sprintf(p, "%3u%s", mr->bitrate / 2,
+				(mr->bitrate & 1 ? ".5" : "  "));
+
+		tp = ((mr->cur_tp * 96) / 18000) >> 10;
+		prob = mr->cur_prob / 18;
+		eprob = mr->probability / 18;
+
+		p += sprintf(p, "  %6u.%1u   %6u.%1u   %6u.%1u        "
+				"%3u(%3u)   %8llu    %8llu\n",
+				tp / 10, tp % 10,
+				eprob / 10, eprob % 10,
+				prob / 10, prob % 10,
+				mr->last_success,
+				mr->last_attempts,
+				mr->succ_hist,
+				mr->att_hist);
+	}
+	p += sprintf(p, "\nTotal packet count::    ideal %d      "
+			"lookaround %d\n\n",
+			mi->packet_count - mi->sample_count,
+			mi->sample_count);
+	ms->len = p - ms->buf;
+
+	return 0;
+}
+
+static int
+minstrel_stats_read(struct file *file, char __user *buf, size_t len, loff_t *o)
+{
+	struct minstrel_stats_info *ms;
+	char *src;
+
+	ms = file->private_data;
+	src = ms->buf;
+
+	len = min(len, ms->len);
+	if (len <= *o)
+		return 0;
+
+	src += *o;
+	len -= *o;
+	*o += len;
+
+	if (copy_to_user(buf, src, len))
+		return -EFAULT;
+
+	return len;
+}
+
+static int
+minstrel_stats_release(struct inode *inode, struct file *file)
+{
+	struct minstrel_stats_info *ms = file->private_data;
+
+	kfree(ms);
+
+	return 0;
+}
+
+static struct file_operations minstrel_stat_fops = {
+	.owner = THIS_MODULE,
+	.open = minstrel_stats_open,
+	.read = minstrel_stats_read,
+	.release = minstrel_stats_release,
+};
+
+void
+minstrel_add_sta_debugfs(void *priv, void *priv_sta, struct dentry *dir)
+{
+	struct minstrel_sta_info *mi = priv_sta;
+
+	mi->dbg_stats = debugfs_create_file("rc_stats", S_IRUGO, dir, mi,
+			&minstrel_stat_fops);
+}
+
+void
+minstrel_remove_sta_debugfs(void *priv, void *priv_sta)
+{
+	struct minstrel_sta_info *mi = priv_sta;
+
+	debugfs_remove(mi->dbg_stats);
+}
diff --git a/net/mac80211/rc80211_pid.h b/net/mac80211/rc80211_pid.h
index 0a9135b..01d64d5 100644
--- a/net/mac80211/rc80211_pid.h
+++ b/net/mac80211/rc80211_pid.h
@@ -124,7 +124,6 @@
  * struct rc_pid_debugfs_entries - tunable parameters
  *
  * Algorithm parameters, tunable via debugfs.
- * @dir: the debugfs directory for a specific phy
  * @target: target percentage for failed frames
  * @sampling_period: error sampling interval in milliseconds
  * @coeff_p: absolute value of the proportional coefficient
@@ -143,7 +142,6 @@
  *	ordering of rates)
  */
 struct rc_pid_debugfs_entries {
-	struct dentry *dir;
 	struct dentry *target;
 	struct dentry *sampling_period;
 	struct dentry *coeff_p;
@@ -180,6 +178,8 @@
 	u32 tx_num_failed;
 	u32 tx_num_xmit;
 
+	int txrate_idx;
+
 	/* Average failed frames percentage error (i.e. actual vs. target
 	 * percentage), scaled by RC_PID_SMOOTHING. This value is computed
 	 * using using an exponential weighted average technique:
diff --git a/net/mac80211/rc80211_pid_algo.c b/net/mac80211/rc80211_pid_algo.c
index a914ba7..86eb374 100644
--- a/net/mac80211/rc80211_pid_algo.c
+++ b/net/mac80211/rc80211_pid_algo.c
@@ -68,17 +68,14 @@
  * exhibited a worse failed frames behaviour and we'll choose the highest rate
  * whose failed frames behaviour is not worse than the one of the original rate
  * target. While at it, check that the new rate is valid. */
-static void rate_control_pid_adjust_rate(struct ieee80211_local *local,
-					 struct sta_info *sta, int adj,
+static void rate_control_pid_adjust_rate(struct ieee80211_supported_band *sband,
+					 struct ieee80211_sta *sta,
+					 struct rc_pid_sta_info *spinfo, int adj,
 					 struct rc_pid_rateinfo *rinfo)
 {
-	struct ieee80211_sub_if_data *sdata;
-	struct ieee80211_supported_band *sband;
 	int cur_sorted, new_sorted, probe, tmp, n_bitrates, band;
-	int cur = sta->txrate_idx;
+	int cur = spinfo->txrate_idx;
 
-	sdata = sta->sdata;
-	sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
 	band = sband->band;
 	n_bitrates = sband->n_bitrates;
 
@@ -111,7 +108,7 @@
 	/* Fit the rate found to the nearest supported rate. */
 	do {
 		if (rate_supported(sta, band, rinfo[tmp].index)) {
-			sta->txrate_idx = rinfo[tmp].index;
+			spinfo->txrate_idx = rinfo[tmp].index;
 			break;
 		}
 		if (adj < 0)
@@ -121,9 +118,9 @@
 	} while (tmp < n_bitrates && tmp >= 0);
 
 #ifdef CONFIG_MAC80211_DEBUGFS
-	rate_control_pid_event_rate_change(
-		&((struct rc_pid_sta_info *)sta->rate_ctrl_priv)->events,
-		sta->txrate_idx, sband->bitrates[sta->txrate_idx].bitrate);
+	rate_control_pid_event_rate_change(&spinfo->events,
+		spinfo->txrate_idx,
+		sband->bitrates[spinfo->txrate_idx].bitrate);
 #endif
 }
 
@@ -145,15 +142,11 @@
 }
 
 static void rate_control_pid_sample(struct rc_pid_info *pinfo,
-				    struct ieee80211_local *local,
-				    struct sta_info *sta)
+				    struct ieee80211_supported_band *sband,
+				    struct ieee80211_sta *sta,
+				    struct rc_pid_sta_info *spinfo)
 {
-#ifdef CONFIG_MAC80211_MESH
-	struct ieee80211_sub_if_data *sdata = sta->sdata;
-#endif
-	struct rc_pid_sta_info *spinfo = sta->rate_ctrl_priv;
 	struct rc_pid_rateinfo *rinfo = pinfo->rinfo;
-	struct ieee80211_supported_band *sband;
 	u32 pf;
 	s32 err_avg;
 	u32 err_prop;
@@ -162,9 +155,6 @@
 	int adj, i, j, tmp;
 	unsigned long period;
 
-	sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
-	spinfo = sta->rate_ctrl_priv;
-
 	/* In case nothing happened during the previous control interval, turn
 	 * the sharpening factor on. */
 	period = (HZ * pinfo->sampling_period + 500) / 1000;
@@ -180,14 +170,15 @@
 	if (unlikely(spinfo->tx_num_xmit == 0))
 		pf = spinfo->last_pf;
 	else {
+		/* XXX: BAD HACK!!! */
+		struct sta_info *si = container_of(sta, struct sta_info, sta);
+
 		pf = spinfo->tx_num_failed * 100 / spinfo->tx_num_xmit;
-#ifdef CONFIG_MAC80211_MESH
-		if (pf == 100 &&
-		    sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT)
-			mesh_plink_broken(sta);
-#endif
+
+		if (ieee80211_vif_is_mesh(&si->sdata->vif) && pf == 100)
+			mesh_plink_broken(si);
 		pf <<= RC_PID_ARITH_SHIFT;
-		sta->fail_avg = ((pf + (spinfo->last_pf << 3)) / 9)
+		si->fail_avg = ((pf + (spinfo->last_pf << 3)) / 9)
 					>> RC_PID_ARITH_SHIFT;
 	}
 
@@ -195,16 +186,16 @@
 	spinfo->tx_num_failed = 0;
 
 	/* If we just switched rate, update the rate behaviour info. */
-	if (pinfo->oldrate != sta->txrate_idx) {
+	if (pinfo->oldrate != spinfo->txrate_idx) {
 
 		i = rinfo[pinfo->oldrate].rev_index;
-		j = rinfo[sta->txrate_idx].rev_index;
+		j = rinfo[spinfo->txrate_idx].rev_index;
 
 		tmp = (pf - spinfo->last_pf);
 		tmp = RC_PID_DO_ARITH_RIGHT_SHIFT(tmp, RC_PID_ARITH_SHIFT);
 
 		rinfo[j].diff = rinfo[i].diff + tmp;
-		pinfo->oldrate = sta->txrate_idx;
+		pinfo->oldrate = spinfo->txrate_idx;
 	}
 	rate_control_pid_normalize(pinfo, sband->n_bitrates);
 
@@ -233,43 +224,26 @@
 
 	/* Change rate. */
 	if (adj)
-		rate_control_pid_adjust_rate(local, sta, adj, rinfo);
+		rate_control_pid_adjust_rate(sband, sta, spinfo, adj, rinfo);
 }
 
-static void rate_control_pid_tx_status(void *priv, struct net_device *dev,
+static void rate_control_pid_tx_status(void *priv, struct ieee80211_supported_band *sband,
+				       struct ieee80211_sta *sta, void *priv_sta,
 				       struct sk_buff *skb)
 {
-	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
-	struct ieee80211_sub_if_data *sdata;
 	struct rc_pid_info *pinfo = priv;
-	struct sta_info *sta;
-	struct rc_pid_sta_info *spinfo;
+	struct rc_pid_sta_info *spinfo = priv_sta;
 	unsigned long period;
-	struct ieee80211_supported_band *sband;
 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
 
-	rcu_read_lock();
-
-	sta = sta_info_get(local, hdr->addr1);
-	sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
-
-	if (!sta)
-		goto unlock;
-
-	/* Don't update the state if we're not controlling the rate. */
-	sdata = sta->sdata;
-	if (sdata->force_unicast_rateidx > -1) {
-		sta->txrate_idx = sdata->max_ratectrl_rateidx;
-		goto unlock;
-	}
+	if (!spinfo)
+		return;
 
 	/* Ignore all frames that were sent with a different rate than the rate
 	 * we currently advise mac80211 to use. */
-	if (info->tx_rate_idx != sta->txrate_idx)
-		goto unlock;
+	if (info->tx_rate_idx != spinfo->txrate_idx)
+		return;
 
-	spinfo = sta->rate_ctrl_priv;
 	spinfo->tx_num_xmit++;
 
 #ifdef CONFIG_MAC80211_DEBUGFS
@@ -287,93 +261,68 @@
 		spinfo->tx_num_xmit++;
 	}
 
-	if (info->status.excessive_retries) {
-		sta->tx_retry_failed++;
-		sta->tx_num_consecutive_failures++;
-		sta->tx_num_mpdu_fail++;
-	} else {
-		sta->tx_num_consecutive_failures = 0;
-		sta->tx_num_mpdu_ok++;
-	}
-	sta->tx_retry_count += info->status.retry_count;
-	sta->tx_num_mpdu_fail += info->status.retry_count;
-
 	/* Update PID controller state. */
 	period = (HZ * pinfo->sampling_period + 500) / 1000;
 	if (!period)
 		period = 1;
 	if (time_after(jiffies, spinfo->last_sample + period))
-		rate_control_pid_sample(pinfo, local, sta);
-
- unlock:
-	rcu_read_unlock();
+		rate_control_pid_sample(pinfo, sband, sta, spinfo);
 }
 
-static void rate_control_pid_get_rate(void *priv, struct net_device *dev,
-				      struct ieee80211_supported_band *sband,
-				      struct sk_buff *skb,
-				      struct rate_selection *sel)
+static void
+rate_control_pid_get_rate(void *priv, struct ieee80211_supported_band *sband,
+			  struct ieee80211_sta *sta, void *priv_sta,
+			  struct sk_buff *skb,
+			  struct rate_selection *sel)
 {
-	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
-	struct ieee80211_sub_if_data *sdata;
-	struct sta_info *sta;
+	struct rc_pid_sta_info *spinfo = priv_sta;
 	int rateidx;
 	u16 fc;
 
-	rcu_read_lock();
-
-	sta = sta_info_get(local, hdr->addr1);
-
 	/* Send management frames and broadcast/multicast data using lowest
 	 * rate. */
 	fc = le16_to_cpu(hdr->frame_control);
-	if ((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA ||
-	    is_multicast_ether_addr(hdr->addr1) || !sta) {
-		sel->rate_idx = rate_lowest_index(local, sband, sta);
-		rcu_read_unlock();
+	if (!sta || !spinfo ||
+	    (fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA ||
+	    is_multicast_ether_addr(hdr->addr1)) {
+		sel->rate_idx = rate_lowest_index(sband, sta);
 		return;
 	}
 
-	/* If a forced rate is in effect, select it. */
-	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-	if (sdata->force_unicast_rateidx > -1)
-		sta->txrate_idx = sdata->force_unicast_rateidx;
-
-	rateidx = sta->txrate_idx;
+	rateidx = spinfo->txrate_idx;
 
 	if (rateidx >= sband->n_bitrates)
 		rateidx = sband->n_bitrates - 1;
 
-	sta->last_txrate_idx = rateidx;
-
-	rcu_read_unlock();
-
 	sel->rate_idx = rateidx;
 
 #ifdef CONFIG_MAC80211_DEBUGFS
-	rate_control_pid_event_tx_rate(
-		&((struct rc_pid_sta_info *) sta->rate_ctrl_priv)->events,
+	rate_control_pid_event_tx_rate(&spinfo->events,
 		rateidx, sband->bitrates[rateidx].bitrate);
 #endif
 }
 
-static void rate_control_pid_rate_init(void *priv, void *priv_sta,
-					  struct ieee80211_local *local,
-					  struct sta_info *sta)
+static void
+rate_control_pid_rate_init(void *priv, struct ieee80211_supported_band *sband,
+			   struct ieee80211_sta *sta, void *priv_sta)
 {
+	struct rc_pid_sta_info *spinfo = priv_sta;
+	struct sta_info *si;
+
 	/* TODO: This routine should consider using RSSI from previous packets
 	 * as we need to have IEEE 802.1X auth succeed immediately after assoc..
 	 * Until that method is implemented, we will use the lowest supported
 	 * rate as a workaround. */
-	struct ieee80211_supported_band *sband;
 
-	sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
-	sta->txrate_idx = rate_lowest_index(local, sband, sta);
-	sta->fail_avg = 0;
+	spinfo->txrate_idx = rate_lowest_index(sband, sta);
+	/* HACK */
+	si = container_of(sta, struct sta_info, sta);
+	si->fail_avg = 0;
 }
 
-static void *rate_control_pid_alloc(struct ieee80211_local *local)
+static void *rate_control_pid_alloc(struct ieee80211_hw *hw,
+				    struct dentry *debugfsdir)
 {
 	struct rc_pid_info *pinfo;
 	struct rc_pid_rateinfo *rinfo;
@@ -384,7 +333,7 @@
 	struct rc_pid_debugfs_entries *de;
 #endif
 
-	sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
+	sband = hw->wiphy->bands[hw->conf.channel->band];
 
 	pinfo = kmalloc(sizeof(*pinfo), GFP_ATOMIC);
 	if (!pinfo)
@@ -439,30 +388,28 @@
 
 #ifdef CONFIG_MAC80211_DEBUGFS
 	de = &pinfo->dentries;
-	de->dir = debugfs_create_dir("rc80211_pid",
-				     local->hw.wiphy->debugfsdir);
 	de->target = debugfs_create_u32("target_pf", S_IRUSR | S_IWUSR,
-					de->dir, &pinfo->target);
+					debugfsdir, &pinfo->target);
 	de->sampling_period = debugfs_create_u32("sampling_period",
-						 S_IRUSR | S_IWUSR, de->dir,
+						 S_IRUSR | S_IWUSR, debugfsdir,
 						 &pinfo->sampling_period);
 	de->coeff_p = debugfs_create_u32("coeff_p", S_IRUSR | S_IWUSR,
-					 de->dir, &pinfo->coeff_p);
+					 debugfsdir, &pinfo->coeff_p);
 	de->coeff_i = debugfs_create_u32("coeff_i", S_IRUSR | S_IWUSR,
-					 de->dir, &pinfo->coeff_i);
+					 debugfsdir, &pinfo->coeff_i);
 	de->coeff_d = debugfs_create_u32("coeff_d", S_IRUSR | S_IWUSR,
-					 de->dir, &pinfo->coeff_d);
+					 debugfsdir, &pinfo->coeff_d);
 	de->smoothing_shift = debugfs_create_u32("smoothing_shift",
-						 S_IRUSR | S_IWUSR, de->dir,
+						 S_IRUSR | S_IWUSR, debugfsdir,
 						 &pinfo->smoothing_shift);
 	de->sharpen_factor = debugfs_create_u32("sharpen_factor",
-					       S_IRUSR | S_IWUSR, de->dir,
+					       S_IRUSR | S_IWUSR, debugfsdir,
 					       &pinfo->sharpen_factor);
 	de->sharpen_duration = debugfs_create_u32("sharpen_duration",
-						  S_IRUSR | S_IWUSR, de->dir,
+						  S_IRUSR | S_IWUSR, debugfsdir,
 						  &pinfo->sharpen_duration);
 	de->norm_offset = debugfs_create_u32("norm_offset",
-					     S_IRUSR | S_IWUSR, de->dir,
+					     S_IRUSR | S_IWUSR, debugfsdir,
 					     &pinfo->norm_offset);
 #endif
 
@@ -484,7 +431,6 @@
 	debugfs_remove(de->coeff_p);
 	debugfs_remove(de->sampling_period);
 	debugfs_remove(de->target);
-	debugfs_remove(de->dir);
 #endif
 
 	kfree(pinfo->rinfo);
@@ -495,7 +441,8 @@
 {
 }
 
-static void *rate_control_pid_alloc_sta(void *priv, gfp_t gfp)
+static void *rate_control_pid_alloc_sta(void *priv, struct ieee80211_sta *sta,
+					gfp_t gfp)
 {
 	struct rc_pid_sta_info *spinfo;
 
@@ -513,10 +460,10 @@
 	return spinfo;
 }
 
-static void rate_control_pid_free_sta(void *priv, void *priv_sta)
+static void rate_control_pid_free_sta(void *priv, struct ieee80211_sta *sta,
+				      void *priv_sta)
 {
-	struct rc_pid_sta_info *spinfo = priv_sta;
-	kfree(spinfo);
+	kfree(priv_sta);
 }
 
 static struct rate_control_ops mac80211_rcpid = {
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 6db8545..cf6b121 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -143,6 +143,8 @@
 	/* IEEE80211_RADIOTAP_FLAGS */
 	if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS)
 		*pos |= IEEE80211_RADIOTAP_F_FCS;
+	if (status->flag & RX_FLAG_SHORTPRE)
+		*pos |= IEEE80211_RADIOTAP_F_SHORTPRE;
 	pos++;
 
 	/* IEEE80211_RADIOTAP_RATE */
@@ -155,8 +157,11 @@
 	if (status->band == IEEE80211_BAND_5GHZ)
 		*(__le16 *)pos = cpu_to_le16(IEEE80211_CHAN_OFDM |
 					     IEEE80211_CHAN_5GHZ);
+	else if (rate->flags & IEEE80211_RATE_ERP_G)
+		*(__le16 *)pos = cpu_to_le16(IEEE80211_CHAN_OFDM |
+					     IEEE80211_CHAN_2GHZ);
 	else
-		*(__le16 *)pos = cpu_to_le16(IEEE80211_CHAN_DYN |
+		*(__le16 *)pos = cpu_to_le16(IEEE80211_CHAN_CCK |
 					     IEEE80211_CHAN_2GHZ);
 	pos += 2;
 
@@ -290,7 +295,7 @@
 		if (!netif_running(sdata->dev))
 			continue;
 
-		if (sdata->vif.type != IEEE80211_IF_TYPE_MNTR)
+		if (sdata->vif.type != NL80211_IFTYPE_MONITOR)
 			continue;
 
 		if (sdata->u.mntr_flags & MONITOR_FLAG_COOK_FRAMES)
@@ -398,12 +403,12 @@
 	struct ieee80211_local *local = rx->local;
 	struct sk_buff *skb = rx->skb;
 
-	if (unlikely(local->sta_hw_scanning))
-		return ieee80211_sta_rx_scan(rx->dev, skb, rx->status);
+	if (unlikely(local->hw_scanning))
+		return ieee80211_scan_rx(rx->sdata, skb, rx->status);
 
-	if (unlikely(local->sta_sw_scanning)) {
+	if (unlikely(local->sw_scanning)) {
 		/* drop all the other packets during a software scan anyway */
-		if (ieee80211_sta_rx_scan(rx->dev, skb, rx->status)
+		if (ieee80211_scan_rx(rx->sdata, skb, rx->status)
 		    != RX_QUEUED)
 			dev_kfree_skb(skb);
 		return RX_QUEUED;
@@ -461,7 +466,7 @@
 
 	if (ieee80211_is_data(hdr->frame_control) &&
 	    is_multicast_ether_addr(hdr->addr1) &&
-	    mesh_rmc_check(hdr->addr4, msh_h_get(hdr, hdrlen), rx->dev))
+	    mesh_rmc_check(hdr->addr4, msh_h_get(hdr, hdrlen), rx->sdata))
 		return RX_DROP_MONITOR;
 #undef msh_h_get
 
@@ -496,8 +501,8 @@
 	/* Drop disallowed frame classes based on STA auth/assoc state;
 	 * IEEE 802.11, Chap 5.5.
 	 *
-	 * 80211.o does filtering only based on association state, i.e., it
-	 * drops Class 3 frames from not associated stations. hostapd sends
+	 * mac80211 filters only based on association state, i.e. it drops
+	 * Class 3 frames from not associated stations. hostapd sends
 	 * deauth/disassoc frames when needed. In addition, hostapd is
 	 * responsible for filtering on both auth and assoc states.
 	 */
@@ -507,7 +512,7 @@
 
 	if (unlikely((ieee80211_is_data(hdr->frame_control) ||
 		      ieee80211_is_pspoll(hdr->frame_control)) &&
-		     rx->sdata->vif.type != IEEE80211_IF_TYPE_IBSS &&
+		     rx->sdata->vif.type != NL80211_IFTYPE_ADHOC &&
 		     (!rx->sta || !test_sta_flags(rx->sta, WLAN_STA_ASSOC)))) {
 		if ((!ieee80211_has_fromds(hdr->frame_control) &&
 		     !ieee80211_has_tods(hdr->frame_control) &&
@@ -645,32 +650,28 @@
 	return result;
 }
 
-static void ap_sta_ps_start(struct net_device *dev, struct sta_info *sta)
+static void ap_sta_ps_start(struct sta_info *sta)
 {
-	struct ieee80211_sub_if_data *sdata;
+	struct ieee80211_sub_if_data *sdata = sta->sdata;
 	DECLARE_MAC_BUF(mac);
 
-	sdata = sta->sdata;
-
 	atomic_inc(&sdata->bss->num_sta_ps);
 	set_and_clear_sta_flags(sta, WLAN_STA_PS, WLAN_STA_PSPOLL);
 #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
 	printk(KERN_DEBUG "%s: STA %s aid %d enters power save mode\n",
-	       dev->name, print_mac(mac, sta->addr), sta->aid);
+	       sdata->dev->name, print_mac(mac, sta->sta.addr), sta->sta.aid);
 #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
 }
 
-static int ap_sta_ps_end(struct net_device *dev, struct sta_info *sta)
+static int ap_sta_ps_end(struct sta_info *sta)
 {
-	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct ieee80211_sub_if_data *sdata = sta->sdata;
+	struct ieee80211_local *local = sdata->local;
 	struct sk_buff *skb;
 	int sent = 0;
-	struct ieee80211_sub_if_data *sdata;
 	struct ieee80211_tx_info *info;
 	DECLARE_MAC_BUF(mac);
 
-	sdata = sta->sdata;
-
 	atomic_dec(&sdata->bss->num_sta_ps);
 
 	clear_sta_flags(sta, WLAN_STA_PS | WLAN_STA_PSPOLL);
@@ -680,7 +681,7 @@
 
 #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
 	printk(KERN_DEBUG "%s: STA %s aid %d exits power save mode\n",
-	       dev->name, print_mac(mac, sta->addr), sta->aid);
+	       sdata->dev->name, print_mac(mac, sta->sta.addr), sta->sta.aid);
 #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
 
 	/* Send all buffered frames to the station */
@@ -696,8 +697,8 @@
 		sent++;
 #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
 		printk(KERN_DEBUG "%s: STA %s aid %d send PS frame "
-		       "since STA not sleeping anymore\n", dev->name,
-		       print_mac(mac, sta->addr), sta->aid);
+		       "since STA not sleeping anymore\n", sdata->dev->name,
+		       print_mac(mac, sta->sta.addr), sta->sta.aid);
 #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
 		info->flags |= IEEE80211_TX_CTL_REQUEUE;
 		dev_queue_xmit(skb);
@@ -710,7 +711,6 @@
 ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx)
 {
 	struct sta_info *sta = rx->sta;
-	struct net_device *dev = rx->dev;
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
 
 	if (!sta)
@@ -719,14 +719,14 @@
 	/* Update last_rx only for IBSS packets which are for the current
 	 * BSSID to avoid keeping the current IBSS network alive in cases where
 	 * other STAs are using different BSSID. */
-	if (rx->sdata->vif.type == IEEE80211_IF_TYPE_IBSS) {
+	if (rx->sdata->vif.type == NL80211_IFTYPE_ADHOC) {
 		u8 *bssid = ieee80211_get_bssid(hdr, rx->skb->len,
-						IEEE80211_IF_TYPE_IBSS);
+						NL80211_IFTYPE_ADHOC);
 		if (compare_ether_addr(bssid, rx->sdata->u.sta.bssid) == 0)
 			sta->last_rx = jiffies;
 	} else
 	if (!is_multicast_ether_addr(hdr->addr1) ||
-	    rx->sdata->vif.type == IEEE80211_IF_TYPE_STA) {
+	    rx->sdata->vif.type == NL80211_IFTYPE_STATION) {
 		/* Update last_rx only for unicast frames in order to prevent
 		 * the Probe Request frames (the only broadcast frames from a
 		 * STA in infrastructure mode) from keeping a connection alive.
@@ -746,16 +746,16 @@
 	sta->last_noise = rx->status->noise;
 
 	if (!ieee80211_has_morefrags(hdr->frame_control) &&
-	    (rx->sdata->vif.type == IEEE80211_IF_TYPE_AP ||
-	     rx->sdata->vif.type == IEEE80211_IF_TYPE_VLAN)) {
+	    (rx->sdata->vif.type == NL80211_IFTYPE_AP ||
+	     rx->sdata->vif.type == NL80211_IFTYPE_AP_VLAN)) {
 		/* Change STA power saving mode only in the end of a frame
 		 * exchange sequence */
 		if (test_sta_flags(sta, WLAN_STA_PS) &&
 		    !ieee80211_has_pm(hdr->frame_control))
-			rx->sent_ps_buffered += ap_sta_ps_end(dev, sta);
+			rx->sent_ps_buffered += ap_sta_ps_end(sta);
 		else if (!test_sta_flags(sta, WLAN_STA_PS) &&
 			 ieee80211_has_pm(hdr->frame_control))
-			ap_sta_ps_start(dev, sta);
+			ap_sta_ps_start(sta);
 	}
 
 	/* Drop data::nullfunc frames silently, since they are used only to
@@ -816,7 +816,7 @@
 
 static inline struct ieee80211_fragment_entry *
 ieee80211_reassemble_find(struct ieee80211_sub_if_data *sdata,
-			  u16 fc, unsigned int frag, unsigned int seq,
+			  unsigned int frag, unsigned int seq,
 			  int rx_queue, struct ieee80211_hdr *hdr)
 {
 	struct ieee80211_fragment_entry *entry;
@@ -825,7 +825,6 @@
 	idx = sdata->fragment_next;
 	for (i = 0; i < IEEE80211_FRAGMENT_MAX; i++) {
 		struct ieee80211_hdr *f_hdr;
-		u16 f_fc;
 
 		idx--;
 		if (idx < 0)
@@ -837,10 +836,13 @@
 		    entry->last_frag + 1 != frag)
 			continue;
 
-		f_hdr = (struct ieee80211_hdr *) entry->skb_list.next->data;
-		f_fc = le16_to_cpu(f_hdr->frame_control);
+		f_hdr = (struct ieee80211_hdr *)entry->skb_list.next->data;
 
-		if ((fc & IEEE80211_FCTL_FTYPE) != (f_fc & IEEE80211_FCTL_FTYPE) ||
+		/*
+		 * Check ftype and addresses are equal, else check next fragment
+		 */
+		if (((hdr->frame_control ^ f_hdr->frame_control) &
+		     cpu_to_le16(IEEE80211_FCTL_FTYPE)) ||
 		    compare_ether_addr(hdr->addr1, f_hdr->addr1) != 0 ||
 		    compare_ether_addr(hdr->addr2, f_hdr->addr2) != 0)
 			continue;
@@ -860,16 +862,18 @@
 {
 	struct ieee80211_hdr *hdr;
 	u16 sc;
+	__le16 fc;
 	unsigned int frag, seq;
 	struct ieee80211_fragment_entry *entry;
 	struct sk_buff *skb;
 	DECLARE_MAC_BUF(mac);
 
-	hdr = (struct ieee80211_hdr *) rx->skb->data;
+	hdr = (struct ieee80211_hdr *)rx->skb->data;
+	fc = hdr->frame_control;
 	sc = le16_to_cpu(hdr->seq_ctrl);
 	frag = sc & IEEE80211_SCTL_FRAG;
 
-	if (likely((!(rx->fc & IEEE80211_FCTL_MOREFRAGS) && frag == 0) ||
+	if (likely((!ieee80211_has_morefrags(fc) && frag == 0) ||
 		   (rx->skb)->len < 24 ||
 		   is_multicast_ether_addr(hdr->addr1))) {
 		/* not fragmented */
@@ -884,7 +888,7 @@
 		entry = ieee80211_reassemble_add(rx->sdata, frag, seq,
 						 rx->queue, &(rx->skb));
 		if (rx->key && rx->key->conf.alg == ALG_CCMP &&
-		    (rx->fc & IEEE80211_FCTL_PROTECTED)) {
+		    ieee80211_has_protected(fc)) {
 			/* Store CCMP PN so that we can verify that the next
 			 * fragment has a sequential PN value. */
 			entry->ccmp = 1;
@@ -898,8 +902,7 @@
 	/* This is a fragment for a frame that should already be pending in
 	 * fragment cache. Add this fragment to the end of the pending entry.
 	 */
-	entry = ieee80211_reassemble_find(rx->sdata, rx->fc, frag, seq,
-					  rx->queue, hdr);
+	entry = ieee80211_reassemble_find(rx->sdata, frag, seq, rx->queue, hdr);
 	if (!entry) {
 		I802_DEBUG_INC(rx->local->rx_handlers_drop_defrag);
 		return RX_DROP_MONITOR;
@@ -924,11 +927,11 @@
 		memcpy(entry->last_pn, pn, CCMP_PN_LEN);
 	}
 
-	skb_pull(rx->skb, ieee80211_get_hdrlen(rx->fc));
+	skb_pull(rx->skb, ieee80211_hdrlen(fc));
 	__skb_queue_tail(&entry->skb_list, rx->skb);
 	entry->last_frag = frag;
 	entry->extra_len += rx->skb->len;
-	if (rx->fc & IEEE80211_FCTL_MOREFRAGS) {
+	if (ieee80211_has_morefrags(fc)) {
 		rx->skb = NULL;
 		return RX_QUEUED;
 	}
@@ -968,15 +971,14 @@
 	struct sk_buff *skb;
 	int no_pending_pkts;
 	DECLARE_MAC_BUF(mac);
+	__le16 fc = ((struct ieee80211_hdr *)rx->skb->data)->frame_control;
 
-	if (likely(!rx->sta ||
-		   (rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_CTL ||
-		   (rx->fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_PSPOLL ||
+	if (likely(!rx->sta || !ieee80211_is_pspoll(fc) ||
 		   !(rx->flags & IEEE80211_RX_RA_MATCH)))
 		return RX_CONTINUE;
 
-	if ((sdata->vif.type != IEEE80211_IF_TYPE_AP) &&
-	    (sdata->vif.type != IEEE80211_IF_TYPE_VLAN))
+	if ((sdata->vif.type != NL80211_IFTYPE_AP) &&
+	    (sdata->vif.type != NL80211_IFTYPE_AP_VLAN))
 		return RX_DROP_UNUSABLE;
 
 	skb = skb_dequeue(&rx->sta->tx_filtered);
@@ -1000,7 +1002,7 @@
 
 #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
 		printk(KERN_DEBUG "STA %s aid %d: PS Poll (entries after %d)\n",
-		       print_mac(mac, rx->sta->addr), rx->sta->aid,
+		       print_mac(mac, rx->sta->sta.addr), rx->sta->sta.aid,
 		       skb_queue_len(&rx->sta->ps_tx_buf));
 #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
 
@@ -1025,7 +1027,7 @@
 		 */
 		printk(KERN_DEBUG "%s: STA %s sent PS Poll even "
 		       "though there are no buffered frames for it\n",
-		       rx->dev->name, print_mac(mac, rx->sta->addr));
+		       rx->dev->name, print_mac(mac, rx->sta->sta.addr));
 #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
 	}
 
@@ -1050,7 +1052,6 @@
 		ieee80211_hdrlen(hdr->frame_control) - IEEE80211_QOS_CTL_LEN);
 	hdr = (struct ieee80211_hdr *)skb_pull(rx->skb, IEEE80211_QOS_CTL_LEN);
 	/* change frame type to non QOS */
-	rx->fc &= ~IEEE80211_STYPE_QOS_DATA;
 	hdr->frame_control &= ~cpu_to_le16(IEEE80211_STYPE_QOS_DATA);
 
 	return RX_CONTINUE;
@@ -1067,7 +1068,7 @@
 }
 
 static int
-ieee80211_drop_unencrypted(struct ieee80211_rx_data *rx)
+ieee80211_drop_unencrypted(struct ieee80211_rx_data *rx, __le16 fc)
 {
 	/*
 	 * Pass through unencrypted frames if the hardware has
@@ -1077,9 +1078,8 @@
 		return 0;
 
 	/* Drop unencrypted frames if key is set. */
-	if (unlikely(!(rx->fc & IEEE80211_FCTL_PROTECTED) &&
-		     (rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA &&
-		     (rx->fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_NULLFUNC &&
+	if (unlikely(!ieee80211_has_protected(fc) &&
+		     !ieee80211_is_nullfunc(fc) &&
 		     (rx->key || rx->sdata->drop_unencrypted)))
 		return -EACCES;
 
@@ -1091,7 +1091,7 @@
 {
 	struct net_device *dev = rx->dev;
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data;
-	u16 fc, hdrlen, ethertype;
+	u16 hdrlen, ethertype;
 	u8 *payload;
 	u8 dst[ETH_ALEN];
 	u8 src[ETH_ALEN] __aligned(2);
@@ -1102,16 +1102,10 @@
 	DECLARE_MAC_BUF(mac3);
 	DECLARE_MAC_BUF(mac4);
 
-	fc = rx->fc;
-
-	if (unlikely(!WLAN_FC_DATA_PRESENT(fc)))
+	if (unlikely(!ieee80211_is_data_present(hdr->frame_control)))
 		return -1;
 
-	hdrlen = ieee80211_get_hdrlen(fc);
-
-	if (ieee80211_vif_is_mesh(&sdata->vif))
-		hdrlen += ieee80211_get_mesh_hdrlen(
-				(struct ieee80211s_hdr *) (skb->data + hdrlen));
+	hdrlen = ieee80211_hdrlen(hdr->frame_control);
 
 	/* convert IEEE 802.11 header + possible LLC headers into Ethernet
 	 * header
@@ -1122,42 +1116,38 @@
 	 *   1     0   BSSID SA    DA    n/a
 	 *   1     1   RA    TA    DA    SA
 	 */
+	memcpy(dst, ieee80211_get_DA(hdr), ETH_ALEN);
+	memcpy(src, ieee80211_get_SA(hdr), ETH_ALEN);
 
-	switch (fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) {
-	case IEEE80211_FCTL_TODS:
-		/* BSSID SA DA */
-		memcpy(dst, hdr->addr3, ETH_ALEN);
-		memcpy(src, hdr->addr2, ETH_ALEN);
-
-		if (unlikely(sdata->vif.type != IEEE80211_IF_TYPE_AP &&
-			     sdata->vif.type != IEEE80211_IF_TYPE_VLAN))
+	switch (hdr->frame_control &
+		cpu_to_le16(IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) {
+	case __constant_cpu_to_le16(IEEE80211_FCTL_TODS):
+		if (unlikely(sdata->vif.type != NL80211_IFTYPE_AP &&
+			     sdata->vif.type != NL80211_IFTYPE_AP_VLAN))
 			return -1;
 		break;
-	case (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS):
-		/* RA TA DA SA */
-		memcpy(dst, hdr->addr3, ETH_ALEN);
-		memcpy(src, hdr->addr4, ETH_ALEN);
-
-		 if (unlikely(sdata->vif.type != IEEE80211_IF_TYPE_WDS &&
-			     sdata->vif.type != IEEE80211_IF_TYPE_MESH_POINT))
+	case __constant_cpu_to_le16(IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS):
+		if (unlikely(sdata->vif.type != NL80211_IFTYPE_WDS &&
+			     sdata->vif.type != NL80211_IFTYPE_MESH_POINT))
 			return -1;
+		if (ieee80211_vif_is_mesh(&sdata->vif)) {
+			struct ieee80211s_hdr *meshdr = (struct ieee80211s_hdr *)
+				(skb->data + hdrlen);
+			hdrlen += ieee80211_get_mesh_hdrlen(meshdr);
+			if (meshdr->flags & MESH_FLAGS_AE_A5_A6) {
+				memcpy(dst, meshdr->eaddr1, ETH_ALEN);
+				memcpy(src, meshdr->eaddr2, ETH_ALEN);
+			}
+		}
 		break;
-	case IEEE80211_FCTL_FROMDS:
-		/* DA BSSID SA */
-		memcpy(dst, hdr->addr1, ETH_ALEN);
-		memcpy(src, hdr->addr3, ETH_ALEN);
-
-		if (sdata->vif.type != IEEE80211_IF_TYPE_STA ||
+	case __constant_cpu_to_le16(IEEE80211_FCTL_FROMDS):
+		if (sdata->vif.type != NL80211_IFTYPE_STATION ||
 		    (is_multicast_ether_addr(dst) &&
 		     !compare_ether_addr(src, dev->dev_addr)))
 			return -1;
 		break;
-	case 0:
-		/* DA SA BSSID */
-		memcpy(dst, hdr->addr1, ETH_ALEN);
-		memcpy(src, hdr->addr2, ETH_ALEN);
-
-		if (sdata->vif.type != IEEE80211_IF_TYPE_IBSS)
+	case __constant_cpu_to_le16(0):
+		if (sdata->vif.type != NL80211_IFTYPE_ADHOC)
 			return -1;
 		break;
 	}
@@ -1193,7 +1183,7 @@
 /*
  * requires that rx->skb is a frame with ethernet header
  */
-static bool ieee80211_frame_allowed(struct ieee80211_rx_data *rx)
+static bool ieee80211_frame_allowed(struct ieee80211_rx_data *rx, __le16 fc)
 {
 	static const u8 pae_group_addr[ETH_ALEN] __aligned(2)
 		= { 0x01, 0x80, 0xC2, 0x00, 0x00, 0x03 };
@@ -1209,7 +1199,7 @@
 		return true;
 
 	if (ieee80211_802_1x_port_control(rx) ||
-	    ieee80211_drop_unencrypted(rx))
+	    ieee80211_drop_unencrypted(rx, fc))
 		return false;
 
 	return true;
@@ -1231,8 +1221,9 @@
 	skb = rx->skb;
 	xmit_skb = NULL;
 
-	if (local->bridge_packets && (sdata->vif.type == IEEE80211_IF_TYPE_AP ||
-				      sdata->vif.type == IEEE80211_IF_TYPE_VLAN) &&
+	if ((sdata->vif.type == NL80211_IFTYPE_AP ||
+	     sdata->vif.type == NL80211_IFTYPE_AP_VLAN) &&
+	    !(sdata->flags & IEEE80211_SDATA_DONT_BRIDGE_PACKETS) &&
 	    (rx->flags & IEEE80211_RX_RA_MATCH)) {
 		if (is_multicast_ether_addr(ehdr->h_dest)) {
 			/*
@@ -1279,20 +1270,21 @@
 {
 	struct net_device *dev = rx->dev;
 	struct ieee80211_local *local = rx->local;
-	u16 fc, ethertype;
+	u16 ethertype;
 	u8 *payload;
 	struct sk_buff *skb = rx->skb, *frame = NULL;
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+	__le16 fc = hdr->frame_control;
 	const struct ethhdr *eth;
 	int remaining, err;
 	u8 dst[ETH_ALEN];
 	u8 src[ETH_ALEN];
 	DECLARE_MAC_BUF(mac);
 
-	fc = rx->fc;
-	if (unlikely((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA))
+	if (unlikely(!ieee80211_is_data(fc)))
 		return RX_CONTINUE;
 
-	if (unlikely(!WLAN_FC_DATA_PRESENT(fc)))
+	if (unlikely(!ieee80211_is_data_present(fc)))
 		return RX_DROP_MONITOR;
 
 	if (!(rx->flags & IEEE80211_RX_AMSDU))
@@ -1374,7 +1366,7 @@
 			memcpy(skb_push(frame, ETH_ALEN), dst, ETH_ALEN);
 		}
 
-		if (!ieee80211_frame_allowed(rx)) {
+		if (!ieee80211_frame_allowed(rx, fc)) {
 			if (skb == frame) /* last frame */
 				return RX_DROP_UNUSABLE;
 			dev_kfree_skb(frame);
@@ -1387,7 +1379,8 @@
 	return RX_QUEUED;
 }
 
-static ieee80211_rx_result debug_noinline
+#ifdef CONFIG_MAC80211_MESH
+static ieee80211_rx_result
 ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
 {
 	struct ieee80211_hdr *hdr;
@@ -1406,6 +1399,25 @@
 		/* illegal frame */
 		return RX_DROP_MONITOR;
 
+	if (mesh_hdr->flags & MESH_FLAGS_AE_A5_A6){
+		struct ieee80211_sub_if_data *sdata;
+		struct mesh_path *mppath;
+
+		sdata = IEEE80211_DEV_TO_SUB_IF(rx->dev);
+		rcu_read_lock();
+		mppath = mpp_path_lookup(mesh_hdr->eaddr2, sdata);
+		if (!mppath) {
+			mpp_path_add(mesh_hdr->eaddr2, hdr->addr4, sdata);
+		} else {
+			spin_lock_bh(&mppath->state_lock);
+			mppath->exp_time = jiffies;
+			if (compare_ether_addr(mppath->mpp, hdr->addr4) != 0)
+				memcpy(mppath->mpp, hdr->addr4, ETH_ALEN);
+			spin_unlock_bh(&mppath->state_lock);
+		}
+		rcu_read_unlock();
+	}
+
 	if (compare_ether_addr(rx->dev->dev_addr, hdr->addr3) == 0)
 		return RX_CONTINUE;
 
@@ -1413,7 +1425,7 @@
 
 	if (rx->flags & IEEE80211_RX_RA_MATCH) {
 		if (!mesh_hdr->ttl)
-			IEEE80211_IFSTA_MESH_CTR_INC(&rx->sdata->u.sta,
+			IEEE80211_IFSTA_MESH_CTR_INC(&rx->sdata->u.mesh,
 						     dropped_frames_ttl);
 		else {
 			struct ieee80211_hdr *fwd_hdr;
@@ -1442,27 +1454,27 @@
 	else
 		return RX_DROP_MONITOR;
 }
-
+#endif
 
 static ieee80211_rx_result debug_noinline
 ieee80211_rx_h_data(struct ieee80211_rx_data *rx)
 {
 	struct net_device *dev = rx->dev;
-	u16 fc;
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
+	__le16 fc = hdr->frame_control;
 	int err;
 
-	fc = rx->fc;
-	if (unlikely((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA))
+	if (unlikely(!ieee80211_is_data(hdr->frame_control)))
 		return RX_CONTINUE;
 
-	if (unlikely(!WLAN_FC_DATA_PRESENT(fc)))
+	if (unlikely(!ieee80211_is_data_present(hdr->frame_control)))
 		return RX_DROP_MONITOR;
 
 	err = ieee80211_data_to_8023(rx);
 	if (unlikely(err))
 		return RX_DROP_UNUSABLE;
 
-	if (!ieee80211_frame_allowed(rx))
+	if (!ieee80211_frame_allowed(rx, fc))
 		return RX_DROP_MONITOR;
 
 	rx->skb->dev = dev;
@@ -1520,22 +1532,97 @@
 }
 
 static ieee80211_rx_result debug_noinline
-ieee80211_rx_h_mgmt(struct ieee80211_rx_data *rx)
+ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
 {
-	struct ieee80211_sub_if_data *sdata;
+	struct ieee80211_local *local = rx->local;
+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(rx->dev);
+	struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) rx->skb->data;
+	int len = rx->skb->len;
+
+	if (!ieee80211_is_action(mgmt->frame_control))
+		return RX_CONTINUE;
+
+	if (!rx->sta)
+		return RX_DROP_MONITOR;
 
 	if (!(rx->flags & IEEE80211_RX_RA_MATCH))
 		return RX_DROP_MONITOR;
 
-	sdata = IEEE80211_DEV_TO_SUB_IF(rx->dev);
-	if ((sdata->vif.type == IEEE80211_IF_TYPE_STA ||
-	     sdata->vif.type == IEEE80211_IF_TYPE_IBSS ||
-	     sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT) &&
-	    !(sdata->flags & IEEE80211_SDATA_USERSPACE_MLME))
-		ieee80211_sta_rx_mgmt(rx->dev, rx->skb, rx->status);
-	else
+	/* all categories we currently handle have action_code */
+	if (len < IEEE80211_MIN_ACTION_SIZE + 1)
 		return RX_DROP_MONITOR;
 
+	/*
+	 * FIXME: revisit this, I'm sure we should handle most
+	 *	  of these frames in other modes as well!
+	 */
+	if (sdata->vif.type != NL80211_IFTYPE_STATION &&
+	    sdata->vif.type != NL80211_IFTYPE_ADHOC)
+		return RX_CONTINUE;
+
+	switch (mgmt->u.action.category) {
+	case WLAN_CATEGORY_BACK:
+		switch (mgmt->u.action.u.addba_req.action_code) {
+		case WLAN_ACTION_ADDBA_REQ:
+			if (len < (IEEE80211_MIN_ACTION_SIZE +
+				   sizeof(mgmt->u.action.u.addba_req)))
+				return RX_DROP_MONITOR;
+			ieee80211_process_addba_request(local, rx->sta, mgmt, len);
+			break;
+		case WLAN_ACTION_ADDBA_RESP:
+			if (len < (IEEE80211_MIN_ACTION_SIZE +
+				   sizeof(mgmt->u.action.u.addba_resp)))
+				return RX_DROP_MONITOR;
+			ieee80211_process_addba_resp(local, rx->sta, mgmt, len);
+			break;
+		case WLAN_ACTION_DELBA:
+			if (len < (IEEE80211_MIN_ACTION_SIZE +
+				   sizeof(mgmt->u.action.u.delba)))
+				return RX_DROP_MONITOR;
+			ieee80211_process_delba(sdata, rx->sta, mgmt, len);
+			break;
+		}
+		break;
+	case WLAN_CATEGORY_SPECTRUM_MGMT:
+		if (local->hw.conf.channel->band != IEEE80211_BAND_5GHZ)
+			return RX_DROP_MONITOR;
+		switch (mgmt->u.action.u.measurement.action_code) {
+		case WLAN_ACTION_SPCT_MSR_REQ:
+			if (len < (IEEE80211_MIN_ACTION_SIZE +
+				   sizeof(mgmt->u.action.u.measurement)))
+				return RX_DROP_MONITOR;
+			ieee80211_process_measurement_req(sdata, mgmt, len);
+			break;
+		}
+		break;
+	default:
+		return RX_CONTINUE;
+	}
+
+	rx->sta->rx_packets++;
+	dev_kfree_skb(rx->skb);
+	return RX_QUEUED;
+}
+
+static ieee80211_rx_result debug_noinline
+ieee80211_rx_h_mgmt(struct ieee80211_rx_data *rx)
+{
+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(rx->dev);
+
+	if (!(rx->flags & IEEE80211_RX_RA_MATCH))
+		return RX_DROP_MONITOR;
+
+	if (ieee80211_vif_is_mesh(&sdata->vif))
+		return ieee80211_mesh_rx_mgmt(sdata, rx->skb, rx->status);
+
+	if (sdata->vif.type != NL80211_IFTYPE_STATION &&
+	    sdata->vif.type != NL80211_IFTYPE_ADHOC)
+		return RX_DROP_MONITOR;
+
+	if (sdata->flags & IEEE80211_SDATA_USERSPACE_MLME)
+		return RX_DROP_MONITOR;
+
+	ieee80211_sta_rx_mgmt(sdata, rx->skb, rx->status);
 	return RX_QUEUED;
 }
 
@@ -1565,7 +1652,7 @@
 	if (!ieee80211_has_protected(hdr->frame_control))
 		goto ignore;
 
-	if (rx->sdata->vif.type == IEEE80211_IF_TYPE_AP && keyidx) {
+	if (rx->sdata->vif.type == NL80211_IFTYPE_AP && keyidx) {
 		/*
 		 * APs with pairwise keys should never receive Michael MIC
 		 * errors for non-zero keyidx because these are reserved for
@@ -1579,7 +1666,7 @@
 	    !ieee80211_is_auth(hdr->frame_control))
 		goto ignore;
 
-	mac80211_ev_michael_mic_failure(rx->dev, keyidx, hdr);
+	mac80211_ev_michael_mic_failure(rx->sdata, keyidx, hdr);
  ignore:
 	dev_kfree_skb(rx->skb);
 	rx->skb = NULL;
@@ -1635,7 +1722,7 @@
 		if (!netif_running(sdata->dev))
 			continue;
 
-		if (sdata->vif.type != IEEE80211_IF_TYPE_MNTR ||
+		if (sdata->vif.type != NL80211_IFTYPE_MONITOR ||
 		    !(sdata->u.mntr_flags & MONITOR_FLAG_COOK_FRAMES))
 			continue;
 
@@ -1694,10 +1781,13 @@
 	/* must be after MMIC verify so header is counted in MPDU mic */
 	CALL_RXH(ieee80211_rx_h_remove_qos_control)
 	CALL_RXH(ieee80211_rx_h_amsdu)
+#ifdef CONFIG_MAC80211_MESH
 	if (ieee80211_vif_is_mesh(&sdata->vif))
 		CALL_RXH(ieee80211_rx_h_mesh_fwding);
+#endif
 	CALL_RXH(ieee80211_rx_h_data)
 	CALL_RXH(ieee80211_rx_h_ctrl)
+	CALL_RXH(ieee80211_rx_h_action)
 	CALL_RXH(ieee80211_rx_h_mgmt)
 
 #undef CALL_RXH
@@ -1733,7 +1823,7 @@
 	int multicast = is_multicast_ether_addr(hdr->addr1);
 
 	switch (sdata->vif.type) {
-	case IEEE80211_IF_TYPE_STA:
+	case NL80211_IFTYPE_STATION:
 		if (!bssid)
 			return 0;
 		if (!ieee80211_bssid_match(bssid, sdata->u.sta.bssid)) {
@@ -1748,14 +1838,10 @@
 			rx->flags &= ~IEEE80211_RX_RA_MATCH;
 		}
 		break;
-	case IEEE80211_IF_TYPE_IBSS:
+	case NL80211_IFTYPE_ADHOC:
 		if (!bssid)
 			return 0;
 		if (ieee80211_is_beacon(hdr->frame_control)) {
-			if (!rx->sta)
-				rx->sta = ieee80211_ibss_add_sta(sdata->dev,
-						rx->skb, bssid, hdr->addr2,
-						BIT(rx->status->rate_idx));
 			return 1;
 		}
 		else if (!ieee80211_bssid_match(bssid, sdata->u.sta.bssid)) {
@@ -1769,11 +1855,11 @@
 				return 0;
 			rx->flags &= ~IEEE80211_RX_RA_MATCH;
 		} else if (!rx->sta)
-			rx->sta = ieee80211_ibss_add_sta(sdata->dev, rx->skb,
+			rx->sta = ieee80211_ibss_add_sta(sdata, rx->skb,
 						bssid, hdr->addr2,
 						BIT(rx->status->rate_idx));
 		break;
-	case IEEE80211_IF_TYPE_MESH_POINT:
+	case NL80211_IFTYPE_MESH_POINT:
 		if (!multicast &&
 		    compare_ether_addr(sdata->dev->dev_addr,
 				       hdr->addr1) != 0) {
@@ -1783,8 +1869,8 @@
 			rx->flags &= ~IEEE80211_RX_RA_MATCH;
 		}
 		break;
-	case IEEE80211_IF_TYPE_VLAN:
-	case IEEE80211_IF_TYPE_AP:
+	case NL80211_IFTYPE_AP_VLAN:
+	case NL80211_IFTYPE_AP:
 		if (!bssid) {
 			if (compare_ether_addr(sdata->dev->dev_addr,
 					       hdr->addr1))
@@ -1796,16 +1882,17 @@
 			rx->flags &= ~IEEE80211_RX_RA_MATCH;
 		}
 		break;
-	case IEEE80211_IF_TYPE_WDS:
+	case NL80211_IFTYPE_WDS:
 		if (bssid || !ieee80211_is_data(hdr->frame_control))
 			return 0;
 		if (compare_ether_addr(sdata->u.wds.remote_addr, hdr->addr2))
 			return 0;
 		break;
-	case IEEE80211_IF_TYPE_MNTR:
+	case NL80211_IFTYPE_MONITOR:
 		/* take everything */
 		break;
-	case IEEE80211_IF_TYPE_INVALID:
+	case NL80211_IFTYPE_UNSPECIFIED:
+	case __NL80211_IFTYPE_AFTER_LAST:
 		/* should never get here */
 		WARN_ON(1);
 		break;
@@ -1827,23 +1914,20 @@
 	struct ieee80211_sub_if_data *sdata;
 	struct ieee80211_hdr *hdr;
 	struct ieee80211_rx_data rx;
-	u16 type;
 	int prepares;
 	struct ieee80211_sub_if_data *prev = NULL;
 	struct sk_buff *skb_new;
 	u8 *bssid;
 
-	hdr = (struct ieee80211_hdr *) skb->data;
+	hdr = (struct ieee80211_hdr *)skb->data;
 	memset(&rx, 0, sizeof(rx));
 	rx.skb = skb;
 	rx.local = local;
 
 	rx.status = status;
 	rx.rate = rate;
-	rx.fc = le16_to_cpu(hdr->frame_control);
-	type = rx.fc & IEEE80211_FCTL_FTYPE;
 
-	if (type == IEEE80211_FTYPE_DATA || type == IEEE80211_FTYPE_MGMT)
+	if (ieee80211_is_data(hdr->frame_control) || ieee80211_is_mgmt(hdr->frame_control))
 		local->dot11ReceivedFragmentCount++;
 
 	rx.sta = sta_info_get(local, hdr->addr2);
@@ -1857,7 +1941,7 @@
 		return;
 	}
 
-	if (unlikely(local->sta_sw_scanning || local->sta_hw_scanning))
+	if (unlikely(local->sw_scanning || local->hw_scanning))
 		rx.flags |= IEEE80211_RX_IN_SCAN;
 
 	ieee80211_parse_qos(&rx);
@@ -1869,7 +1953,7 @@
 		if (!netif_running(sdata->dev))
 			continue;
 
-		if (sdata->vif.type == IEEE80211_IF_TYPE_MNTR)
+		if (sdata->vif.type == NL80211_IFTYPE_MONITOR)
 			continue;
 
 		bssid = ieee80211_get_bssid(hdr, skb->len, sdata->vif.type);
@@ -1904,14 +1988,12 @@
 				       prev->dev->name);
 			continue;
 		}
-		rx.fc = le16_to_cpu(hdr->frame_control);
 		ieee80211_invoke_rx_handlers(prev, &rx, skb_new);
 		prev = sdata;
 	}
-	if (prev) {
-		rx.fc = le16_to_cpu(hdr->frame_control);
+	if (prev)
 		ieee80211_invoke_rx_handlers(prev, &rx, skb);
-	} else
+	else
 		dev_kfree_skb(skb);
 }
 
@@ -2080,7 +2162,7 @@
 	/* if this mpdu is fragmented - terminate rx aggregation session */
 	sc = le16_to_cpu(hdr->seq_ctrl);
 	if (sc & IEEE80211_SCTL_FRAG) {
-		ieee80211_sta_stop_rx_ba_session(sta->sdata->dev, sta->addr,
+		ieee80211_sta_stop_rx_ba_session(sta->sdata, sta->sta.addr,
 			tid, 0, WLAN_REASON_QSTA_REQUIRE_SETUP);
 		ret = 1;
 		goto end_reorder;
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c
new file mode 100644
index 0000000..8e6685e
--- /dev/null
+++ b/net/mac80211/scan.c
@@ -0,0 +1,937 @@
+/*
+ * Scanning implementation
+ *
+ * Copyright 2003, Jouni Malinen <jkmaline@cc.hut.fi>
+ * Copyright 2004, Instant802 Networks, Inc.
+ * Copyright 2005, Devicescape Software, Inc.
+ * Copyright 2006-2007	Jiri Benc <jbenc@suse.cz>
+ * Copyright 2007, Michael Wu <flamingice@sourmilk.net>
+ *
+ * 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.
+ */
+
+/* TODO:
+ * order BSS list by RSSI(?) ("quality of AP")
+ * scan result table filtering (by capability (privacy, IBSS/BSS, WPA/RSN IE,
+ *    SSID)
+ */
+
+#include <linux/wireless.h>
+#include <linux/if_arp.h>
+#include <net/mac80211.h>
+#include <net/iw_handler.h>
+
+#include "ieee80211_i.h"
+#include "mesh.h"
+
+#define IEEE80211_PROBE_DELAY (HZ / 33)
+#define IEEE80211_CHANNEL_TIME (HZ / 33)
+#define IEEE80211_PASSIVE_CHANNEL_TIME (HZ / 5)
+
+void ieee80211_rx_bss_list_init(struct ieee80211_local *local)
+{
+	spin_lock_init(&local->bss_lock);
+	INIT_LIST_HEAD(&local->bss_list);
+}
+
+void ieee80211_rx_bss_list_deinit(struct ieee80211_local *local)
+{
+	struct ieee80211_bss *bss, *tmp;
+
+	list_for_each_entry_safe(bss, tmp, &local->bss_list, list)
+		ieee80211_rx_bss_put(local, bss);
+}
+
+struct ieee80211_bss *
+ieee80211_rx_bss_get(struct ieee80211_local *local, u8 *bssid, int freq,
+		     u8 *ssid, u8 ssid_len)
+{
+	struct ieee80211_bss *bss;
+
+	spin_lock_bh(&local->bss_lock);
+	bss = local->bss_hash[STA_HASH(bssid)];
+	while (bss) {
+		if (!bss_mesh_cfg(bss) &&
+		    !memcmp(bss->bssid, bssid, ETH_ALEN) &&
+		    bss->freq == freq &&
+		    bss->ssid_len == ssid_len &&
+		    (ssid_len == 0 || !memcmp(bss->ssid, ssid, ssid_len))) {
+			atomic_inc(&bss->users);
+			break;
+		}
+		bss = bss->hnext;
+	}
+	spin_unlock_bh(&local->bss_lock);
+	return bss;
+}
+
+/* Caller must hold local->bss_lock */
+static void __ieee80211_rx_bss_hash_add(struct ieee80211_local *local,
+					struct ieee80211_bss *bss)
+{
+	u8 hash_idx;
+
+	if (bss_mesh_cfg(bss))
+		hash_idx = mesh_id_hash(bss_mesh_id(bss),
+					bss_mesh_id_len(bss));
+	else
+		hash_idx = STA_HASH(bss->bssid);
+
+	bss->hnext = local->bss_hash[hash_idx];
+	local->bss_hash[hash_idx] = bss;
+}
+
+/* Caller must hold local->bss_lock */
+static void __ieee80211_rx_bss_hash_del(struct ieee80211_local *local,
+					struct ieee80211_bss *bss)
+{
+	struct ieee80211_bss *b, *prev = NULL;
+	b = local->bss_hash[STA_HASH(bss->bssid)];
+	while (b) {
+		if (b == bss) {
+			if (!prev)
+				local->bss_hash[STA_HASH(bss->bssid)] =
+					bss->hnext;
+			else
+				prev->hnext = bss->hnext;
+			break;
+		}
+		prev = b;
+		b = b->hnext;
+	}
+}
+
+struct ieee80211_bss *
+ieee80211_rx_bss_add(struct ieee80211_local *local, u8 *bssid, int freq,
+		     u8 *ssid, u8 ssid_len)
+{
+	struct ieee80211_bss *bss;
+
+	bss = kzalloc(sizeof(*bss), GFP_ATOMIC);
+	if (!bss)
+		return NULL;
+	atomic_set(&bss->users, 2);
+	memcpy(bss->bssid, bssid, ETH_ALEN);
+	bss->freq = freq;
+	if (ssid && ssid_len <= IEEE80211_MAX_SSID_LEN) {
+		memcpy(bss->ssid, ssid, ssid_len);
+		bss->ssid_len = ssid_len;
+	}
+
+	spin_lock_bh(&local->bss_lock);
+	/* TODO: order by RSSI? */
+	list_add_tail(&bss->list, &local->bss_list);
+	__ieee80211_rx_bss_hash_add(local, bss);
+	spin_unlock_bh(&local->bss_lock);
+	return bss;
+}
+
+#ifdef CONFIG_MAC80211_MESH
+static struct ieee80211_bss *
+ieee80211_rx_mesh_bss_get(struct ieee80211_local *local, u8 *mesh_id, int mesh_id_len,
+			  u8 *mesh_cfg, int freq)
+{
+	struct ieee80211_bss *bss;
+
+	spin_lock_bh(&local->bss_lock);
+	bss = local->bss_hash[mesh_id_hash(mesh_id, mesh_id_len)];
+	while (bss) {
+		if (bss_mesh_cfg(bss) &&
+		    !memcmp(bss_mesh_cfg(bss), mesh_cfg, MESH_CFG_CMP_LEN) &&
+		    bss->freq == freq &&
+		    mesh_id_len == bss->mesh_id_len &&
+		    (mesh_id_len == 0 || !memcmp(bss->mesh_id, mesh_id,
+						 mesh_id_len))) {
+			atomic_inc(&bss->users);
+			break;
+		}
+		bss = bss->hnext;
+	}
+	spin_unlock_bh(&local->bss_lock);
+	return bss;
+}
+
+static struct ieee80211_bss *
+ieee80211_rx_mesh_bss_add(struct ieee80211_local *local, u8 *mesh_id, int mesh_id_len,
+			  u8 *mesh_cfg, int mesh_config_len, int freq)
+{
+	struct ieee80211_bss *bss;
+
+	if (mesh_config_len != MESH_CFG_LEN)
+		return NULL;
+
+	bss = kzalloc(sizeof(*bss), GFP_ATOMIC);
+	if (!bss)
+		return NULL;
+
+	bss->mesh_cfg = kmalloc(MESH_CFG_CMP_LEN, GFP_ATOMIC);
+	if (!bss->mesh_cfg) {
+		kfree(bss);
+		return NULL;
+	}
+
+	if (mesh_id_len && mesh_id_len <= IEEE80211_MAX_MESH_ID_LEN) {
+		bss->mesh_id = kmalloc(mesh_id_len, GFP_ATOMIC);
+		if (!bss->mesh_id) {
+			kfree(bss->mesh_cfg);
+			kfree(bss);
+			return NULL;
+		}
+		memcpy(bss->mesh_id, mesh_id, mesh_id_len);
+	}
+
+	atomic_set(&bss->users, 2);
+	memcpy(bss->mesh_cfg, mesh_cfg, MESH_CFG_CMP_LEN);
+	bss->mesh_id_len = mesh_id_len;
+	bss->freq = freq;
+	spin_lock_bh(&local->bss_lock);
+	/* TODO: order by RSSI? */
+	list_add_tail(&bss->list, &local->bss_list);
+	__ieee80211_rx_bss_hash_add(local, bss);
+	spin_unlock_bh(&local->bss_lock);
+	return bss;
+}
+#endif
+
+static void ieee80211_rx_bss_free(struct ieee80211_bss *bss)
+{
+	kfree(bss->ies);
+	kfree(bss_mesh_id(bss));
+	kfree(bss_mesh_cfg(bss));
+	kfree(bss);
+}
+
+void ieee80211_rx_bss_put(struct ieee80211_local *local,
+			  struct ieee80211_bss *bss)
+{
+	local_bh_disable();
+	if (!atomic_dec_and_lock(&bss->users, &local->bss_lock)) {
+		local_bh_enable();
+		return;
+	}
+
+	__ieee80211_rx_bss_hash_del(local, bss);
+	list_del(&bss->list);
+	spin_unlock_bh(&local->bss_lock);
+	ieee80211_rx_bss_free(bss);
+}
+
+struct ieee80211_bss *
+ieee80211_bss_info_update(struct ieee80211_local *local,
+			  struct ieee80211_rx_status *rx_status,
+			  struct ieee80211_mgmt *mgmt,
+			  size_t len,
+			  struct ieee802_11_elems *elems,
+			  int freq, bool beacon)
+{
+	struct ieee80211_bss *bss;
+	int clen;
+
+#ifdef CONFIG_MAC80211_MESH
+	if (elems->mesh_config)
+		bss = ieee80211_rx_mesh_bss_get(local, elems->mesh_id,
+				elems->mesh_id_len, elems->mesh_config, freq);
+	else
+#endif
+		bss = ieee80211_rx_bss_get(local, mgmt->bssid, freq,
+					   elems->ssid, elems->ssid_len);
+	if (!bss) {
+#ifdef CONFIG_MAC80211_MESH
+		if (elems->mesh_config)
+			bss = ieee80211_rx_mesh_bss_add(local, elems->mesh_id,
+				elems->mesh_id_len, elems->mesh_config,
+				elems->mesh_config_len, freq);
+		else
+#endif
+			bss = ieee80211_rx_bss_add(local, mgmt->bssid, freq,
+						  elems->ssid, elems->ssid_len);
+		if (!bss)
+			return NULL;
+	} else {
+#if 0
+		/* TODO: order by RSSI? */
+		spin_lock_bh(&local->bss_lock);
+		list_move_tail(&bss->list, &local->bss_list);
+		spin_unlock_bh(&local->bss_lock);
+#endif
+	}
+
+	/* save the ERP value so that it is available at association time */
+	if (elems->erp_info && elems->erp_info_len >= 1) {
+		bss->erp_value = elems->erp_info[0];
+		bss->has_erp_value = 1;
+	}
+
+	bss->beacon_int = le16_to_cpu(mgmt->u.beacon.beacon_int);
+	bss->capability = le16_to_cpu(mgmt->u.beacon.capab_info);
+
+	if (elems->tim) {
+		struct ieee80211_tim_ie *tim_ie =
+			(struct ieee80211_tim_ie *)elems->tim;
+		bss->dtim_period = tim_ie->dtim_period;
+	}
+
+	/* set default value for buggy APs */
+	if (!elems->tim || bss->dtim_period == 0)
+		bss->dtim_period = 1;
+
+	bss->supp_rates_len = 0;
+	if (elems->supp_rates) {
+		clen = IEEE80211_MAX_SUPP_RATES - bss->supp_rates_len;
+		if (clen > elems->supp_rates_len)
+			clen = elems->supp_rates_len;
+		memcpy(&bss->supp_rates[bss->supp_rates_len], elems->supp_rates,
+		       clen);
+		bss->supp_rates_len += clen;
+	}
+	if (elems->ext_supp_rates) {
+		clen = IEEE80211_MAX_SUPP_RATES - bss->supp_rates_len;
+		if (clen > elems->ext_supp_rates_len)
+			clen = elems->ext_supp_rates_len;
+		memcpy(&bss->supp_rates[bss->supp_rates_len],
+		       elems->ext_supp_rates, clen);
+		bss->supp_rates_len += clen;
+	}
+
+	bss->band = rx_status->band;
+
+	bss->timestamp = le64_to_cpu(mgmt->u.beacon.timestamp);
+	bss->last_update = jiffies;
+	bss->signal = rx_status->signal;
+	bss->noise = rx_status->noise;
+	bss->qual = rx_status->qual;
+	bss->wmm_used = elems->wmm_param || elems->wmm_info;
+
+	if (!beacon)
+		bss->last_probe_resp = jiffies;
+
+	/*
+	 * For probe responses, or if we don't have any information yet,
+	 * use the IEs from the beacon.
+	 */
+	if (!bss->ies || !beacon) {
+		if (bss->ies == NULL || bss->ies_len < elems->total_len) {
+			kfree(bss->ies);
+			bss->ies = kmalloc(elems->total_len, GFP_ATOMIC);
+		}
+		if (bss->ies) {
+			memcpy(bss->ies, elems->ie_start, elems->total_len);
+			bss->ies_len = elems->total_len;
+		} else
+			bss->ies_len = 0;
+	}
+
+	return bss;
+}
+
+ieee80211_rx_result
+ieee80211_scan_rx(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb,
+		  struct ieee80211_rx_status *rx_status)
+{
+	struct ieee80211_mgmt *mgmt;
+	struct ieee80211_bss *bss;
+	u8 *elements;
+	struct ieee80211_channel *channel;
+	size_t baselen;
+	int freq;
+	__le16 fc;
+	bool presp, beacon = false;
+	struct ieee802_11_elems elems;
+
+	if (skb->len < 2)
+		return RX_DROP_UNUSABLE;
+
+	mgmt = (struct ieee80211_mgmt *) skb->data;
+	fc = mgmt->frame_control;
+
+	if (ieee80211_is_ctl(fc))
+		return RX_CONTINUE;
+
+	if (skb->len < 24)
+		return RX_DROP_MONITOR;
+
+	presp = ieee80211_is_probe_resp(fc);
+	if (presp) {
+		/* ignore ProbeResp to foreign address */
+		if (memcmp(mgmt->da, sdata->dev->dev_addr, ETH_ALEN))
+			return RX_DROP_MONITOR;
+
+		presp = true;
+		elements = mgmt->u.probe_resp.variable;
+		baselen = offsetof(struct ieee80211_mgmt, u.probe_resp.variable);
+	} else {
+		beacon = ieee80211_is_beacon(fc);
+		baselen = offsetof(struct ieee80211_mgmt, u.beacon.variable);
+		elements = mgmt->u.beacon.variable;
+	}
+
+	if (!presp && !beacon)
+		return RX_CONTINUE;
+
+	if (baselen > skb->len)
+		return RX_DROP_MONITOR;
+
+	ieee802_11_parse_elems(elements, skb->len - baselen, &elems);
+
+	if (elems.ds_params && elems.ds_params_len == 1)
+		freq = ieee80211_channel_to_frequency(elems.ds_params[0]);
+	else
+		freq = rx_status->freq;
+
+	channel = ieee80211_get_channel(sdata->local->hw.wiphy, freq);
+
+	if (!channel || channel->flags & IEEE80211_CHAN_DISABLED)
+		return RX_DROP_MONITOR;
+
+	bss = ieee80211_bss_info_update(sdata->local, rx_status,
+					mgmt, skb->len, &elems,
+					freq, beacon);
+	ieee80211_rx_bss_put(sdata->local, bss);
+
+	dev_kfree_skb(skb);
+	return RX_QUEUED;
+}
+
+static void ieee80211_send_nullfunc(struct ieee80211_local *local,
+				    struct ieee80211_sub_if_data *sdata,
+				    int powersave)
+{
+	struct sk_buff *skb;
+	struct ieee80211_hdr *nullfunc;
+	__le16 fc;
+
+	skb = dev_alloc_skb(local->hw.extra_tx_headroom + 24);
+	if (!skb) {
+		printk(KERN_DEBUG "%s: failed to allocate buffer for nullfunc "
+		       "frame\n", sdata->dev->name);
+		return;
+	}
+	skb_reserve(skb, local->hw.extra_tx_headroom);
+
+	nullfunc = (struct ieee80211_hdr *) skb_put(skb, 24);
+	memset(nullfunc, 0, 24);
+	fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_NULLFUNC |
+			 IEEE80211_FCTL_TODS);
+	if (powersave)
+		fc |= cpu_to_le16(IEEE80211_FCTL_PM);
+	nullfunc->frame_control = fc;
+	memcpy(nullfunc->addr1, sdata->u.sta.bssid, ETH_ALEN);
+	memcpy(nullfunc->addr2, sdata->dev->dev_addr, ETH_ALEN);
+	memcpy(nullfunc->addr3, sdata->u.sta.bssid, ETH_ALEN);
+
+	ieee80211_tx_skb(sdata, skb, 0);
+}
+
+void ieee80211_scan_completed(struct ieee80211_hw *hw)
+{
+	struct ieee80211_local *local = hw_to_local(hw);
+	struct ieee80211_sub_if_data *sdata;
+	union iwreq_data wrqu;
+
+	if (WARN_ON(!local->hw_scanning && !local->sw_scanning))
+		return;
+
+	local->last_scan_completed = jiffies;
+	memset(&wrqu, 0, sizeof(wrqu));
+
+	/*
+	 * local->scan_sdata could have been NULLed by the interface
+	 * down code in case we were scanning on an interface that is
+	 * being taken down.
+	 */
+	sdata = local->scan_sdata;
+	if (sdata)
+		wireless_send_event(sdata->dev, SIOCGIWSCAN, &wrqu, NULL);
+
+	if (local->hw_scanning) {
+		local->hw_scanning = false;
+		if (ieee80211_hw_config(local))
+			printk(KERN_DEBUG "%s: failed to restore operational "
+			       "channel after scan\n", wiphy_name(local->hw.wiphy));
+
+		goto done;
+	}
+
+	local->sw_scanning = false;
+	if (ieee80211_hw_config(local))
+		printk(KERN_DEBUG "%s: failed to restore operational "
+		       "channel after scan\n", wiphy_name(local->hw.wiphy));
+
+
+	netif_tx_lock_bh(local->mdev);
+	netif_addr_lock(local->mdev);
+	local->filter_flags &= ~FIF_BCN_PRBRESP_PROMISC;
+	local->ops->configure_filter(local_to_hw(local),
+				     FIF_BCN_PRBRESP_PROMISC,
+				     &local->filter_flags,
+				     local->mdev->mc_count,
+				     local->mdev->mc_list);
+
+	netif_addr_unlock(local->mdev);
+	netif_tx_unlock_bh(local->mdev);
+
+	rcu_read_lock();
+	list_for_each_entry_rcu(sdata, &local->interfaces, list) {
+		/* Tell AP we're back */
+		if (sdata->vif.type == NL80211_IFTYPE_STATION) {
+			if (sdata->u.sta.flags & IEEE80211_STA_ASSOCIATED) {
+				ieee80211_send_nullfunc(local, sdata, 0);
+				netif_tx_wake_all_queues(sdata->dev);
+			}
+		} else
+			netif_tx_wake_all_queues(sdata->dev);
+	}
+	rcu_read_unlock();
+
+ done:
+	ieee80211_mlme_notify_scan_completed(local);
+	ieee80211_mesh_notify_scan_completed(local);
+}
+EXPORT_SYMBOL(ieee80211_scan_completed);
+
+
+void ieee80211_scan_work(struct work_struct *work)
+{
+	struct ieee80211_local *local =
+		container_of(work, struct ieee80211_local, scan_work.work);
+	struct ieee80211_sub_if_data *sdata = local->scan_sdata;
+	struct ieee80211_supported_band *sband;
+	struct ieee80211_channel *chan;
+	int skip;
+	unsigned long next_delay = 0;
+
+	/*
+	 * Avoid re-scheduling when the sdata is going away.
+	 */
+	if (!netif_running(sdata->dev))
+		return;
+
+	switch (local->scan_state) {
+	case SCAN_SET_CHANNEL:
+		/*
+		 * Get current scan band. scan_band may be IEEE80211_NUM_BANDS
+		 * after we successfully scanned the last channel of the last
+		 * band (and the last band is supported by the hw)
+		 */
+		if (local->scan_band < IEEE80211_NUM_BANDS)
+			sband = local->hw.wiphy->bands[local->scan_band];
+		else
+			sband = NULL;
+
+		/*
+		 * If we are at an unsupported band and have more bands
+		 * left to scan, advance to the next supported one.
+		 */
+		while (!sband && local->scan_band < IEEE80211_NUM_BANDS - 1) {
+			local->scan_band++;
+			sband = local->hw.wiphy->bands[local->scan_band];
+			local->scan_channel_idx = 0;
+		}
+
+		/* if no more bands/channels left, complete scan */
+		if (!sband || local->scan_channel_idx >= sband->n_channels) {
+			ieee80211_scan_completed(local_to_hw(local));
+			return;
+		}
+		skip = 0;
+		chan = &sband->channels[local->scan_channel_idx];
+
+		if (chan->flags & IEEE80211_CHAN_DISABLED ||
+		    (sdata->vif.type == NL80211_IFTYPE_ADHOC &&
+		     chan->flags & IEEE80211_CHAN_NO_IBSS))
+			skip = 1;
+
+		if (!skip) {
+			local->scan_channel = chan;
+			if (ieee80211_hw_config(local)) {
+				printk(KERN_DEBUG "%s: failed to set freq to "
+				       "%d MHz for scan\n", wiphy_name(local->hw.wiphy),
+				       chan->center_freq);
+				skip = 1;
+			}
+		}
+
+		/* advance state machine to next channel/band */
+		local->scan_channel_idx++;
+		if (local->scan_channel_idx >= sband->n_channels) {
+			/*
+			 * scan_band may end up == IEEE80211_NUM_BANDS, but
+			 * we'll catch that case above and complete the scan
+			 * if that is the case.
+			 */
+			local->scan_band++;
+			local->scan_channel_idx = 0;
+		}
+
+		if (skip)
+			break;
+
+		next_delay = IEEE80211_PROBE_DELAY +
+			     usecs_to_jiffies(local->hw.channel_change_time);
+		local->scan_state = SCAN_SEND_PROBE;
+		break;
+	case SCAN_SEND_PROBE:
+		next_delay = IEEE80211_PASSIVE_CHANNEL_TIME;
+		local->scan_state = SCAN_SET_CHANNEL;
+
+		if (local->scan_channel->flags & IEEE80211_CHAN_PASSIVE_SCAN)
+			break;
+		ieee80211_send_probe_req(sdata, NULL, local->scan_ssid,
+					 local->scan_ssid_len);
+		next_delay = IEEE80211_CHANNEL_TIME;
+		break;
+	}
+
+	queue_delayed_work(local->hw.workqueue, &local->scan_work,
+			   next_delay);
+}
+
+
+int ieee80211_start_scan(struct ieee80211_sub_if_data *scan_sdata,
+			 u8 *ssid, size_t ssid_len)
+{
+	struct ieee80211_local *local = scan_sdata->local;
+	struct ieee80211_sub_if_data *sdata;
+
+	if (ssid_len > IEEE80211_MAX_SSID_LEN)
+		return -EINVAL;
+
+	/* MLME-SCAN.request (page 118)  page 144 (11.1.3.1)
+	 * BSSType: INFRASTRUCTURE, INDEPENDENT, ANY_BSS
+	 * BSSID: MACAddress
+	 * SSID
+	 * ScanType: ACTIVE, PASSIVE
+	 * ProbeDelay: delay (in microseconds) to be used prior to transmitting
+	 *    a Probe frame during active scanning
+	 * ChannelList
+	 * MinChannelTime (>= ProbeDelay), in TU
+	 * MaxChannelTime: (>= MinChannelTime), in TU
+	 */
+
+	 /* MLME-SCAN.confirm
+	  * BSSDescriptionSet
+	  * ResultCode: SUCCESS, INVALID_PARAMETERS
+	 */
+
+	if (local->sw_scanning || local->hw_scanning) {
+		if (local->scan_sdata == scan_sdata)
+			return 0;
+		return -EBUSY;
+	}
+
+	if (local->ops->hw_scan) {
+		int rc;
+
+		local->hw_scanning = true;
+		rc = local->ops->hw_scan(local_to_hw(local), ssid, ssid_len);
+		if (rc) {
+			local->hw_scanning = false;
+			return rc;
+		}
+		local->scan_sdata = scan_sdata;
+		return 0;
+	}
+
+	local->sw_scanning = true;
+
+	rcu_read_lock();
+	list_for_each_entry_rcu(sdata, &local->interfaces, list) {
+		if (sdata->vif.type == NL80211_IFTYPE_STATION) {
+			if (sdata->u.sta.flags & IEEE80211_STA_ASSOCIATED) {
+				netif_tx_stop_all_queues(sdata->dev);
+				ieee80211_send_nullfunc(local, sdata, 1);
+			}
+		} else
+			netif_tx_stop_all_queues(sdata->dev);
+	}
+	rcu_read_unlock();
+
+	if (ssid) {
+		local->scan_ssid_len = ssid_len;
+		memcpy(local->scan_ssid, ssid, ssid_len);
+	} else
+		local->scan_ssid_len = 0;
+	local->scan_state = SCAN_SET_CHANNEL;
+	local->scan_channel_idx = 0;
+	local->scan_band = IEEE80211_BAND_2GHZ;
+	local->scan_sdata = scan_sdata;
+
+	netif_addr_lock_bh(local->mdev);
+	local->filter_flags |= FIF_BCN_PRBRESP_PROMISC;
+	local->ops->configure_filter(local_to_hw(local),
+				     FIF_BCN_PRBRESP_PROMISC,
+				     &local->filter_flags,
+				     local->mdev->mc_count,
+				     local->mdev->mc_list);
+	netif_addr_unlock_bh(local->mdev);
+
+	/* TODO: start scan as soon as all nullfunc frames are ACKed */
+	queue_delayed_work(local->hw.workqueue, &local->scan_work,
+			   IEEE80211_CHANNEL_TIME);
+
+	return 0;
+}
+
+
+int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata,
+			   u8 *ssid, size_t ssid_len)
+{
+	struct ieee80211_local *local = sdata->local;
+	struct ieee80211_if_sta *ifsta;
+
+	if (sdata->vif.type != NL80211_IFTYPE_STATION)
+		return ieee80211_start_scan(sdata, ssid, ssid_len);
+
+	/*
+	 * STA has a state machine that might need to defer scanning
+	 * while it's trying to associate/authenticate, therefore we
+	 * queue it up to the state machine in that case.
+	 */
+
+	if (local->sw_scanning || local->hw_scanning) {
+		if (local->scan_sdata == sdata)
+			return 0;
+		return -EBUSY;
+	}
+
+	ifsta = &sdata->u.sta;
+
+	ifsta->scan_ssid_len = ssid_len;
+	if (ssid_len)
+		memcpy(ifsta->scan_ssid, ssid, ssid_len);
+	set_bit(IEEE80211_STA_REQ_SCAN, &ifsta->request);
+	queue_work(local->hw.workqueue, &ifsta->work);
+
+	return 0;
+}
+
+
+static void ieee80211_scan_add_ies(struct iw_request_info *info,
+				   struct ieee80211_bss *bss,
+				   char **current_ev, char *end_buf)
+{
+	u8 *pos, *end, *next;
+	struct iw_event iwe;
+
+	if (bss == NULL || bss->ies == NULL)
+		return;
+
+	/*
+	 * If needed, fragment the IEs buffer (at IE boundaries) into short
+	 * enough fragments to fit into IW_GENERIC_IE_MAX octet messages.
+	 */
+	pos = bss->ies;
+	end = pos + bss->ies_len;
+
+	while (end - pos > IW_GENERIC_IE_MAX) {
+		next = pos + 2 + pos[1];
+		while (next + 2 + next[1] - pos < IW_GENERIC_IE_MAX)
+			next = next + 2 + next[1];
+
+		memset(&iwe, 0, sizeof(iwe));
+		iwe.cmd = IWEVGENIE;
+		iwe.u.data.length = next - pos;
+		*current_ev = iwe_stream_add_point(info, *current_ev,
+						   end_buf, &iwe, pos);
+
+		pos = next;
+	}
+
+	if (end > pos) {
+		memset(&iwe, 0, sizeof(iwe));
+		iwe.cmd = IWEVGENIE;
+		iwe.u.data.length = end - pos;
+		*current_ev = iwe_stream_add_point(info, *current_ev,
+						   end_buf, &iwe, pos);
+	}
+}
+
+
+static char *
+ieee80211_scan_result(struct ieee80211_local *local,
+		      struct iw_request_info *info,
+		      struct ieee80211_bss *bss,
+		      char *current_ev, char *end_buf)
+{
+	struct iw_event iwe;
+	char *buf;
+
+	if (time_after(jiffies,
+		       bss->last_update + IEEE80211_SCAN_RESULT_EXPIRE))
+		return current_ev;
+
+	memset(&iwe, 0, sizeof(iwe));
+	iwe.cmd = SIOCGIWAP;
+	iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
+	memcpy(iwe.u.ap_addr.sa_data, bss->bssid, ETH_ALEN);
+	current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe,
+					  IW_EV_ADDR_LEN);
+
+	memset(&iwe, 0, sizeof(iwe));
+	iwe.cmd = SIOCGIWESSID;
+	if (bss_mesh_cfg(bss)) {
+		iwe.u.data.length = bss_mesh_id_len(bss);
+		iwe.u.data.flags = 1;
+		current_ev = iwe_stream_add_point(info, current_ev, end_buf,
+						  &iwe, bss_mesh_id(bss));
+	} else {
+		iwe.u.data.length = bss->ssid_len;
+		iwe.u.data.flags = 1;
+		current_ev = iwe_stream_add_point(info, current_ev, end_buf,
+						  &iwe, bss->ssid);
+	}
+
+	if (bss->capability & (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS)
+	    || bss_mesh_cfg(bss)) {
+		memset(&iwe, 0, sizeof(iwe));
+		iwe.cmd = SIOCGIWMODE;
+		if (bss_mesh_cfg(bss))
+			iwe.u.mode = IW_MODE_MESH;
+		else if (bss->capability & WLAN_CAPABILITY_ESS)
+			iwe.u.mode = IW_MODE_MASTER;
+		else
+			iwe.u.mode = IW_MODE_ADHOC;
+		current_ev = iwe_stream_add_event(info, current_ev, end_buf,
+						  &iwe, IW_EV_UINT_LEN);
+	}
+
+	memset(&iwe, 0, sizeof(iwe));
+	iwe.cmd = SIOCGIWFREQ;
+	iwe.u.freq.m = ieee80211_frequency_to_channel(bss->freq);
+	iwe.u.freq.e = 0;
+	current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe,
+					  IW_EV_FREQ_LEN);
+
+	memset(&iwe, 0, sizeof(iwe));
+	iwe.cmd = SIOCGIWFREQ;
+	iwe.u.freq.m = bss->freq;
+	iwe.u.freq.e = 6;
+	current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe,
+					  IW_EV_FREQ_LEN);
+	memset(&iwe, 0, sizeof(iwe));
+	iwe.cmd = IWEVQUAL;
+	iwe.u.qual.qual = bss->qual;
+	iwe.u.qual.level = bss->signal;
+	iwe.u.qual.noise = bss->noise;
+	iwe.u.qual.updated = local->wstats_flags;
+	current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe,
+					  IW_EV_QUAL_LEN);
+
+	memset(&iwe, 0, sizeof(iwe));
+	iwe.cmd = SIOCGIWENCODE;
+	if (bss->capability & WLAN_CAPABILITY_PRIVACY)
+		iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
+	else
+		iwe.u.data.flags = IW_ENCODE_DISABLED;
+	iwe.u.data.length = 0;
+	current_ev = iwe_stream_add_point(info, current_ev, end_buf,
+					  &iwe, "");
+
+	ieee80211_scan_add_ies(info, bss, &current_ev, end_buf);
+
+	if (bss->supp_rates_len > 0) {
+		/* display all supported rates in readable format */
+		char *p = current_ev + iwe_stream_lcp_len(info);
+		int i;
+
+		memset(&iwe, 0, sizeof(iwe));
+		iwe.cmd = SIOCGIWRATE;
+		/* Those two flags are ignored... */
+		iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
+
+		for (i = 0; i < bss->supp_rates_len; i++) {
+			iwe.u.bitrate.value = ((bss->supp_rates[i] &
+							0x7f) * 500000);
+			p = iwe_stream_add_value(info, current_ev, p,
+					end_buf, &iwe, IW_EV_PARAM_LEN);
+		}
+		current_ev = p;
+	}
+
+	buf = kmalloc(30, GFP_ATOMIC);
+	if (buf) {
+		memset(&iwe, 0, sizeof(iwe));
+		iwe.cmd = IWEVCUSTOM;
+		sprintf(buf, "tsf=%016llx", (unsigned long long)(bss->timestamp));
+		iwe.u.data.length = strlen(buf);
+		current_ev = iwe_stream_add_point(info, current_ev, end_buf,
+						  &iwe, buf);
+		memset(&iwe, 0, sizeof(iwe));
+		iwe.cmd = IWEVCUSTOM;
+		sprintf(buf, " Last beacon: %dms ago",
+			jiffies_to_msecs(jiffies - bss->last_update));
+		iwe.u.data.length = strlen(buf);
+		current_ev = iwe_stream_add_point(info, current_ev,
+						  end_buf, &iwe, buf);
+		kfree(buf);
+	}
+
+	if (bss_mesh_cfg(bss)) {
+		u8 *cfg = bss_mesh_cfg(bss);
+		buf = kmalloc(50, GFP_ATOMIC);
+		if (buf) {
+			memset(&iwe, 0, sizeof(iwe));
+			iwe.cmd = IWEVCUSTOM;
+			sprintf(buf, "Mesh network (version %d)", cfg[0]);
+			iwe.u.data.length = strlen(buf);
+			current_ev = iwe_stream_add_point(info, current_ev,
+							  end_buf,
+							  &iwe, buf);
+			sprintf(buf, "Path Selection Protocol ID: "
+				"0x%02X%02X%02X%02X", cfg[1], cfg[2], cfg[3],
+							cfg[4]);
+			iwe.u.data.length = strlen(buf);
+			current_ev = iwe_stream_add_point(info, current_ev,
+							  end_buf,
+							  &iwe, buf);
+			sprintf(buf, "Path Selection Metric ID: "
+				"0x%02X%02X%02X%02X", cfg[5], cfg[6], cfg[7],
+							cfg[8]);
+			iwe.u.data.length = strlen(buf);
+			current_ev = iwe_stream_add_point(info, current_ev,
+							  end_buf,
+							  &iwe, buf);
+			sprintf(buf, "Congestion Control Mode ID: "
+				"0x%02X%02X%02X%02X", cfg[9], cfg[10],
+							cfg[11], cfg[12]);
+			iwe.u.data.length = strlen(buf);
+			current_ev = iwe_stream_add_point(info, current_ev,
+							  end_buf,
+							  &iwe, buf);
+			sprintf(buf, "Channel Precedence: "
+				"0x%02X%02X%02X%02X", cfg[13], cfg[14],
+							cfg[15], cfg[16]);
+			iwe.u.data.length = strlen(buf);
+			current_ev = iwe_stream_add_point(info, current_ev,
+							  end_buf,
+							  &iwe, buf);
+			kfree(buf);
+		}
+	}
+
+	return current_ev;
+}
+
+
+int ieee80211_scan_results(struct ieee80211_local *local,
+			   struct iw_request_info *info,
+			   char *buf, size_t len)
+{
+	char *current_ev = buf;
+	char *end_buf = buf + len;
+	struct ieee80211_bss *bss;
+
+	spin_lock_bh(&local->bss_lock);
+	list_for_each_entry(bss, &local->bss_list, list) {
+		if (buf + len - current_ev <= IW_EV_ADDR_LEN) {
+			spin_unlock_bh(&local->bss_lock);
+			return -E2BIG;
+		}
+		current_ev = ieee80211_scan_result(local, info, bss,
+						       current_ev, end_buf);
+	}
+	spin_unlock_bh(&local->bss_lock);
+	return current_ev - buf;
+}
diff --git a/net/mac80211/spectmgmt.c b/net/mac80211/spectmgmt.c
new file mode 100644
index 0000000..f72bad6
--- /dev/null
+++ b/net/mac80211/spectmgmt.c
@@ -0,0 +1,86 @@
+/*
+ * spectrum management
+ *
+ * Copyright 2003, Jouni Malinen <jkmaline@cc.hut.fi>
+ * Copyright 2002-2005, Instant802 Networks, Inc.
+ * Copyright 2005-2006, Devicescape Software, Inc.
+ * Copyright 2006-2007  Jiri Benc <jbenc@suse.cz>
+ * Copyright 2007, Michael Wu <flamingice@sourmilk.net>
+ * Copyright 2007-2008, Intel Corporation
+ * Copyright 2008, Johannes Berg <johannes@sipsolutions.net>
+ *
+ * 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/ieee80211.h>
+#include <net/wireless.h>
+#include <net/mac80211.h>
+#include "ieee80211_i.h"
+#include "sta_info.h"
+#include "wme.h"
+
+static void ieee80211_send_refuse_measurement_request(struct ieee80211_sub_if_data *sdata,
+					struct ieee80211_msrment_ie *request_ie,
+					const u8 *da, const u8 *bssid,
+					u8 dialog_token)
+{
+	struct ieee80211_local *local = sdata->local;
+	struct sk_buff *skb;
+	struct ieee80211_mgmt *msr_report;
+
+	skb = dev_alloc_skb(sizeof(*msr_report) + local->hw.extra_tx_headroom +
+				sizeof(struct ieee80211_msrment_ie));
+
+	if (!skb) {
+		printk(KERN_ERR "%s: failed to allocate buffer for "
+				"measurement report frame\n", sdata->dev->name);
+		return;
+	}
+
+	skb_reserve(skb, local->hw.extra_tx_headroom);
+	msr_report = (struct ieee80211_mgmt *)skb_put(skb, 24);
+	memset(msr_report, 0, 24);
+	memcpy(msr_report->da, da, ETH_ALEN);
+	memcpy(msr_report->sa, sdata->dev->dev_addr, ETH_ALEN);
+	memcpy(msr_report->bssid, bssid, ETH_ALEN);
+	msr_report->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
+						IEEE80211_STYPE_ACTION);
+
+	skb_put(skb, 1 + sizeof(msr_report->u.action.u.measurement));
+	msr_report->u.action.category = WLAN_CATEGORY_SPECTRUM_MGMT;
+	msr_report->u.action.u.measurement.action_code =
+				WLAN_ACTION_SPCT_MSR_RPRT;
+	msr_report->u.action.u.measurement.dialog_token = dialog_token;
+
+	msr_report->u.action.u.measurement.element_id = WLAN_EID_MEASURE_REPORT;
+	msr_report->u.action.u.measurement.length =
+			sizeof(struct ieee80211_msrment_ie);
+
+	memset(&msr_report->u.action.u.measurement.msr_elem, 0,
+		sizeof(struct ieee80211_msrment_ie));
+	msr_report->u.action.u.measurement.msr_elem.token = request_ie->token;
+	msr_report->u.action.u.measurement.msr_elem.mode |=
+			IEEE80211_SPCT_MSR_RPRT_MODE_REFUSED;
+	msr_report->u.action.u.measurement.msr_elem.type = request_ie->type;
+
+	ieee80211_tx_skb(sdata, skb, 0);
+}
+
+void ieee80211_process_measurement_req(struct ieee80211_sub_if_data *sdata,
+				       struct ieee80211_mgmt *mgmt,
+				       size_t len)
+{
+	/*
+	 * Ignoring measurement request is spec violation.
+	 * Mandatory measurements must be reported optional
+	 * measurements might be refused or reported incapable
+	 * For now just refuse
+	 * TODO: Answer basic measurement as unmeasured
+	 */
+	ieee80211_send_refuse_measurement_request(sdata,
+			&mgmt->u.action.u.measurement.msr_elem,
+			mgmt->sa, mgmt->bssid,
+			mgmt->u.action.u.measurement.dialog_token);
+}
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index f2ba653..9b72d15 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -73,11 +73,11 @@
 {
 	struct sta_info *s;
 
-	s = local->sta_hash[STA_HASH(sta->addr)];
+	s = local->sta_hash[STA_HASH(sta->sta.addr)];
 	if (!s)
 		return -ENOENT;
 	if (s == sta) {
-		rcu_assign_pointer(local->sta_hash[STA_HASH(sta->addr)],
+		rcu_assign_pointer(local->sta_hash[STA_HASH(sta->sta.addr)],
 				   s->hnext);
 		return 0;
 	}
@@ -93,26 +93,19 @@
 }
 
 /* protected by RCU */
-static struct sta_info *__sta_info_find(struct ieee80211_local *local,
-					u8 *addr)
+struct sta_info *sta_info_get(struct ieee80211_local *local, const u8 *addr)
 {
 	struct sta_info *sta;
 
 	sta = rcu_dereference(local->sta_hash[STA_HASH(addr)]);
 	while (sta) {
-		if (compare_ether_addr(sta->addr, addr) == 0)
+		if (compare_ether_addr(sta->sta.addr, addr) == 0)
 			break;
 		sta = rcu_dereference(sta->hnext);
 	}
 	return sta;
 }
 
-struct sta_info *sta_info_get(struct ieee80211_local *local, u8 *addr)
-{
-	return __sta_info_find(local, addr);
-}
-EXPORT_SYMBOL(sta_info_get);
-
 struct sta_info *sta_info_get_by_idx(struct ieee80211_local *local, int idx,
 				     struct net_device *dev)
 {
@@ -146,12 +139,12 @@
 {
 	DECLARE_MAC_BUF(mbuf);
 
-	rate_control_free_sta(sta->rate_ctrl, sta->rate_ctrl_priv);
+	rate_control_free_sta(sta);
 	rate_control_put(sta->rate_ctrl);
 
 #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
 	printk(KERN_DEBUG "%s: Destroyed STA %s\n",
-	       wiphy_name(local->hw.wiphy), print_mac(mbuf, sta->addr));
+	       wiphy_name(local->hw.wiphy), print_mac(mbuf, sta->sta.addr));
 #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
 
 	kfree(sta);
@@ -219,8 +212,8 @@
 static void sta_info_hash_add(struct ieee80211_local *local,
 			      struct sta_info *sta)
 {
-	sta->hnext = local->sta_hash[STA_HASH(sta->addr)];
-	rcu_assign_pointer(local->sta_hash[STA_HASH(sta->addr)], sta);
+	sta->hnext = local->sta_hash[STA_HASH(sta->sta.addr)];
+	rcu_assign_pointer(local->sta_hash[STA_HASH(sta->sta.addr)], sta);
 }
 
 struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
@@ -231,20 +224,20 @@
 	int i;
 	DECLARE_MAC_BUF(mbuf);
 
-	sta = kzalloc(sizeof(*sta), gfp);
+	sta = kzalloc(sizeof(*sta) + local->hw.sta_data_size, gfp);
 	if (!sta)
 		return NULL;
 
 	spin_lock_init(&sta->lock);
 	spin_lock_init(&sta->flaglock);
 
-	memcpy(sta->addr, addr, ETH_ALEN);
+	memcpy(sta->sta.addr, addr, ETH_ALEN);
 	sta->local = local;
 	sta->sdata = sdata;
 
 	sta->rate_ctrl = rate_control_get(local->rate_ctrl);
 	sta->rate_ctrl_priv = rate_control_alloc_sta(sta->rate_ctrl,
-						     gfp);
+						     &sta->sta, gfp);
 	if (!sta->rate_ctrl_priv) {
 		rate_control_put(sta->rate_ctrl);
 		kfree(sta);
@@ -271,7 +264,7 @@
 
 #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
 	printk(KERN_DEBUG "%s: Allocated STA %s\n",
-	       wiphy_name(local->hw.wiphy), print_mac(mbuf, sta->addr));
+	       wiphy_name(local->hw.wiphy), print_mac(mbuf, sta->sta.addr));
 #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
 
 #ifdef CONFIG_MAC80211_MESH
@@ -300,15 +293,15 @@
 		goto out_free;
 	}
 
-	if (WARN_ON(compare_ether_addr(sta->addr, sdata->dev->dev_addr) == 0 ||
-	            is_multicast_ether_addr(sta->addr))) {
+	if (WARN_ON(compare_ether_addr(sta->sta.addr, sdata->dev->dev_addr) == 0 ||
+	            is_multicast_ether_addr(sta->sta.addr))) {
 		err = -EINVAL;
 		goto out_free;
 	}
 
 	spin_lock_irqsave(&local->sta_lock, flags);
 	/* check if STA exists already */
-	if (__sta_info_find(local, sta->addr)) {
+	if (sta_info_get(local, sta->sta.addr)) {
 		spin_unlock_irqrestore(&local->sta_lock, flags);
 		err = -EEXIST;
 		goto out_free;
@@ -319,18 +312,18 @@
 
 	/* notify driver */
 	if (local->ops->sta_notify) {
-		if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN)
+		if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
 			sdata = container_of(sdata->bss,
 					     struct ieee80211_sub_if_data,
 					     u.ap);
 
 		local->ops->sta_notify(local_to_hw(local), &sdata->vif,
-				       STA_NOTIFY_ADD, sta->addr);
+				       STA_NOTIFY_ADD, &sta->sta);
 	}
 
 #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
 	printk(KERN_DEBUG "%s: Inserted STA %s\n",
-	       wiphy_name(local->hw.wiphy), print_mac(mac, sta->addr));
+	       wiphy_name(local->hw.wiphy), print_mac(mac, sta->sta.addr));
 #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
 
 	spin_unlock_irqrestore(&local->sta_lock, flags);
@@ -379,11 +372,12 @@
 {
 	BUG_ON(!bss);
 
-	__bss_tim_set(bss, sta->aid);
+	__bss_tim_set(bss, sta->sta.aid);
 
 	if (sta->local->ops->set_tim) {
 		sta->local->tim_in_locked_section = true;
-		sta->local->ops->set_tim(local_to_hw(sta->local), sta->aid, 1);
+		sta->local->ops->set_tim(local_to_hw(sta->local),
+					 &sta->sta, true);
 		sta->local->tim_in_locked_section = false;
 	}
 }
@@ -404,11 +398,12 @@
 {
 	BUG_ON(!bss);
 
-	__bss_tim_clear(bss, sta->aid);
+	__bss_tim_clear(bss, sta->sta.aid);
 
 	if (sta->local->ops->set_tim) {
 		sta->local->tim_in_locked_section = true;
-		sta->local->ops->set_tim(local_to_hw(sta->local), sta->aid, 0);
+		sta->local->ops->set_tim(local_to_hw(sta->local),
+					 &sta->sta, false);
 		sta->local->tim_in_locked_section = false;
 	}
 }
@@ -424,7 +419,7 @@
 	spin_unlock_irqrestore(&sta->local->sta_lock, flags);
 }
 
-void __sta_info_unlink(struct sta_info **sta)
+static void __sta_info_unlink(struct sta_info **sta)
 {
 	struct ieee80211_local *local = (*sta)->local;
 	struct ieee80211_sub_if_data *sdata = (*sta)->sdata;
@@ -456,13 +451,13 @@
 	local->num_sta--;
 
 	if (local->ops->sta_notify) {
-		if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN)
+		if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
 			sdata = container_of(sdata->bss,
 					     struct ieee80211_sub_if_data,
 					     u.ap);
 
 		local->ops->sta_notify(local_to_hw(local), &sdata->vif,
-				       STA_NOTIFY_REMOVE, (*sta)->addr);
+				       STA_NOTIFY_REMOVE, &(*sta)->sta);
 	}
 
 	if (ieee80211_vif_is_mesh(&sdata->vif)) {
@@ -474,7 +469,7 @@
 
 #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
 	printk(KERN_DEBUG "%s: Removed STA %s\n",
-	       wiphy_name(local->hw.wiphy), print_mac(mbuf, (*sta)->addr));
+	       wiphy_name(local->hw.wiphy), print_mac(mbuf, (*sta)->sta.addr));
 #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
 
 	/*
@@ -570,7 +565,7 @@
 		local->total_ps_buffered--;
 #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
 		printk(KERN_DEBUG "Buffered frame expired (STA "
-		       "%s)\n", print_mac(mac, sta->addr));
+		       "%s)\n", print_mac(mac, sta->sta.addr));
 #endif
 		dev_kfree_skb(skb);
 
@@ -802,3 +797,40 @@
 		schedule_work(&local->sta_flush_work);
 	spin_unlock_irqrestore(&local->sta_lock, flags);
 }
+
+void ieee80211_sta_expire(struct ieee80211_sub_if_data *sdata,
+			  unsigned long exp_time)
+{
+	struct ieee80211_local *local = sdata->local;
+	struct sta_info *sta, *tmp;
+	LIST_HEAD(tmp_list);
+	DECLARE_MAC_BUF(mac);
+	unsigned long flags;
+
+	spin_lock_irqsave(&local->sta_lock, flags);
+	list_for_each_entry_safe(sta, tmp, &local->sta_list, list)
+		if (time_after(jiffies, sta->last_rx + exp_time)) {
+#ifdef CONFIG_MAC80211_IBSS_DEBUG
+			printk(KERN_DEBUG "%s: expiring inactive STA %s\n",
+			       sdata->dev->name, print_mac(mac, sta->sta.addr));
+#endif
+			__sta_info_unlink(&sta);
+			if (sta)
+				list_add(&sta->list, &tmp_list);
+		}
+	spin_unlock_irqrestore(&local->sta_lock, flags);
+
+	list_for_each_entry_safe(sta, tmp, &tmp_list, list)
+		sta_info_destroy(sta);
+}
+
+struct ieee80211_sta *ieee80211_find_sta(struct ieee80211_hw *hw,
+                                         const u8 *addr)
+{
+	struct sta_info *sta = sta_info_get(hw_to_local(hw), addr);
+
+	if (!sta)
+		return NULL;
+	return &sta->sta;
+}
+EXPORT_SYMBOL(ieee80211_find_sta);
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h
index 109db78..a6b5186 100644
--- a/net/mac80211/sta_info.h
+++ b/net/mac80211/sta_info.h
@@ -167,8 +167,6 @@
  * @lock: used for locking all fields that require locking, see comments
  *	in the header file.
  * @flaglock: spinlock for flags accesses
- * @ht_info: HT capabilities of this STA
- * @supp_rates: Bitmap of supported rates (per band)
  * @addr: MAC address of this STA
  * @aid: STA's unique AID (1..2007, 0 = not assigned yet),
  *	only used in AP (and IBSS?) mode
@@ -191,20 +189,15 @@
  * @last_qual: qual of last received frame from this STA
  * @last_noise: noise of last received frame from this STA
  * @last_seq_ctrl: last received seq/frag number from this STA (per RX queue)
- * @wme_rx_queue: TBD
  * @tx_filtered_count: TBD
  * @tx_retry_failed: TBD
  * @tx_retry_count: TBD
- * @tx_num_consecutive_failures: TBD
- * @tx_num_mpdu_ok: TBD
- * @tx_num_mpdu_fail: TBD
  * @fail_avg: moving percentage of failed MSDUs
  * @tx_packets: number of RX/TX MSDUs
  * @tx_bytes: TBD
  * @tx_fragments: number of transmitted MPDUs
- * @txrate_idx: TBD
- * @last_txrate_idx: TBD
- * @wme_tx_queue: TBD
+ * @last_txrate_idx: Index of the last used transmit rate
+ * @tid_seq: TBD
  * @ampdu_mlme: TBD
  * @timer_to_tid: identity mapping to ID timers
  * @tid_to_tx_q: map tid to tx queue
@@ -217,6 +210,7 @@
  * @plink_timeout: TBD
  * @plink_timer: TBD
  * @debugfs: debug filesystem info
+ * @sta: station information we share with the driver
  */
 struct sta_info {
 	/* General information, mostly static */
@@ -229,10 +223,7 @@
 	void *rate_ctrl_priv;
 	spinlock_t lock;
 	spinlock_t flaglock;
-	struct ieee80211_ht_info ht_info;
-	u64 supp_rates[IEEE80211_NUM_BANDS];
-	u8 addr[ETH_ALEN];
-	u16 aid;
+
 	u16 listen_interval;
 
 	/*
@@ -265,17 +256,10 @@
 	int last_qual;
 	int last_noise;
 	__le16 last_seq_ctrl[NUM_RX_DATA_QUEUES];
-#ifdef CONFIG_MAC80211_DEBUG_COUNTERS
-	unsigned int wme_rx_queue[NUM_RX_DATA_QUEUES];
-#endif
 
 	/* Updated from TX status path only, no locking requirements */
 	unsigned long tx_filtered_count;
 	unsigned long tx_retry_failed, tx_retry_count;
-	/* TODO: update in generic code not rate control? */
-	u32 tx_num_consecutive_failures;
-	u32 tx_num_mpdu_ok;
-	u32 tx_num_mpdu_fail;
 	/* moving percentage of failed MSDUs */
 	unsigned int fail_avg;
 
@@ -283,12 +267,8 @@
 	unsigned long tx_packets;
 	unsigned long tx_bytes;
 	unsigned long tx_fragments;
-	int txrate_idx;
-	int last_txrate_idx;
+	unsigned int last_txrate_idx;
 	u16 tid_seq[IEEE80211_QOS_CTL_TID_MASK + 1];
-#ifdef CONFIG_MAC80211_DEBUG_COUNTERS
-	unsigned int wme_tx_queue[NUM_RX_DATA_QUEUES];
-#endif
 
 	/*
 	 * Aggregation information, locked with lock.
@@ -319,13 +299,12 @@
 		struct dentry *num_ps_buf_frames;
 		struct dentry *inactive_ms;
 		struct dentry *last_seq_ctrl;
-#ifdef CONFIG_MAC80211_DEBUG_COUNTERS
-		struct dentry *wme_rx_queue;
-		struct dentry *wme_tx_queue;
-#endif
 		struct dentry *agg_status;
 	} debugfs;
 #endif
+
+	/* keep last! */
+	struct ieee80211_sta sta;
 };
 
 static inline enum plink_state sta_plink_state(struct sta_info *sta)
@@ -425,7 +404,7 @@
 /*
  * Get a STA info, must have be under RCU read lock.
  */
-struct sta_info *sta_info_get(struct ieee80211_local *local, u8 *addr);
+struct sta_info *sta_info_get(struct ieee80211_local *local, const u8 *addr);
 /*
  * Get STA info by index, BROKEN!
  */
@@ -451,7 +430,6 @@
  * has already unlinked it.
  */
 void sta_info_unlink(struct sta_info **sta);
-void __sta_info_unlink(struct sta_info **sta);
 
 void sta_info_destroy(struct sta_info *sta);
 void sta_info_set_tim_bit(struct sta_info *sta);
@@ -463,5 +441,7 @@
 int sta_info_flush(struct ieee80211_local *local,
 		    struct ieee80211_sub_if_data *sdata);
 void sta_info_flush_delayed(struct ieee80211_sub_if_data *sdata);
+void ieee80211_sta_expire(struct ieee80211_sub_if_data *sdata,
+			  unsigned long exp_time);
 
 #endif /* STA_INFO_H */
diff --git a/net/mac80211/tkip.c b/net/mac80211/tkip.c
index 995f7af..34b32bc 100644
--- a/net/mac80211/tkip.c
+++ b/net/mac80211/tkip.c
@@ -304,7 +304,7 @@
 			key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) {
 			u8 bcast[ETH_ALEN] =
 				{0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
-			u8 *sta_addr = key->sta->addr;
+			u8 *sta_addr = key->sta->sta.addr;
 
 			if (is_multicast_ether_addr(ra))
 				sta_addr = bcast;
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 4788f7b..1460537 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -38,43 +38,6 @@
 
 /* misc utils */
 
-#ifdef CONFIG_MAC80211_LOWTX_FRAME_DUMP
-static void ieee80211_dump_frame(const char *ifname, const char *title,
-				 const struct sk_buff *skb)
-{
-	const struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
-	unsigned int hdrlen;
-	DECLARE_MAC_BUF(mac);
-
-	printk(KERN_DEBUG "%s: %s (len=%d)", ifname, title, skb->len);
-	if (skb->len < 4) {
-		printk("\n");
-		return;
-	}
-
-	hdrlen = ieee80211_hdrlen(hdr->frame_control);
-	if (hdrlen > skb->len)
-		hdrlen = skb->len;
-	if (hdrlen >= 4)
-		printk(" FC=0x%04x DUR=0x%04x",
-		    le16_to_cpu(hdr->frame_control), le16_to_cpu(hdr->duration_id));
-	if (hdrlen >= 10)
-		printk(" A1=%s", print_mac(mac, hdr->addr1));
-	if (hdrlen >= 16)
-		printk(" A2=%s", print_mac(mac, hdr->addr2));
-	if (hdrlen >= 24)
-		printk(" A3=%s", print_mac(mac, hdr->addr3));
-	if (hdrlen >= 30)
-		printk(" A4=%s", print_mac(mac, hdr->addr4));
-	printk("\n");
-}
-#else /* CONFIG_MAC80211_LOWTX_FRAME_DUMP */
-static inline void ieee80211_dump_frame(const char *ifname, const char *title,
-					struct sk_buff *skb)
-{
-}
-#endif /* CONFIG_MAC80211_LOWTX_FRAME_DUMP */
-
 static __le16 ieee80211_duration(struct ieee80211_tx_data *tx, int group_addr,
 				 int next_frag_len)
 {
@@ -82,6 +45,7 @@
 	struct ieee80211_rate *txrate;
 	struct ieee80211_local *local = tx->local;
 	struct ieee80211_supported_band *sband;
+	struct ieee80211_hdr *hdr;
 
 	sband = local->hw.wiphy->bands[tx->channel->band];
 	txrate = &sband->bitrates[tx->rate_idx];
@@ -107,10 +71,10 @@
 	 *   at the highest possible rate belonging to the PHY rates in the
 	 *   BSSBasicRateSet
 	 */
-
-	if ((tx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL) {
+	hdr = (struct ieee80211_hdr *)tx->skb->data;
+	if (ieee80211_is_ctl(hdr->frame_control)) {
 		/* TODO: These control frames are not currently sent by
-		 * 80211.o, but should they be implemented, this function
+		 * mac80211, but should they be implemented, this function
 		 * needs to be updated to support duration field calculation.
 		 *
 		 * RTS: time needed to transmit pending data/mgmt frame plus
@@ -152,7 +116,7 @@
 		if (r->bitrate > txrate->bitrate)
 			break;
 
-		if (tx->sdata->basic_rates & BIT(i))
+		if (tx->sdata->bss_conf.basic_rates & BIT(i))
 			rate = r->bitrate;
 
 		switch (sband->band) {
@@ -201,11 +165,10 @@
 	return cpu_to_le16(dur);
 }
 
-static int inline is_ieee80211_device(struct net_device *dev,
-				      struct net_device *master)
+static int inline is_ieee80211_device(struct ieee80211_local *local,
+				      struct net_device *dev)
 {
-	return (wdev_priv(dev->ieee80211_ptr) ==
-		wdev_priv(master->ieee80211_ptr));
+	return local == wdev_priv(dev->ieee80211_ptr);
 }
 
 /* tx handlers */
@@ -213,21 +176,19 @@
 static ieee80211_tx_result debug_noinline
 ieee80211_tx_h_check_assoc(struct ieee80211_tx_data *tx)
 {
-#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
+
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data;
-#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
 	u32 sta_flags;
 
 	if (unlikely(info->flags & IEEE80211_TX_CTL_INJECTED))
 		return TX_CONTINUE;
 
-	if (unlikely(tx->local->sta_sw_scanning) &&
-	    ((tx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_MGMT ||
-	     (tx->fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_PROBE_REQ))
+	if (unlikely(tx->local->sw_scanning) &&
+	    !ieee80211_is_probe_req(hdr->frame_control))
 		return TX_DROP;
 
-	if (tx->sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT)
+	if (tx->sdata->vif.type == NL80211_IFTYPE_MESH_POINT)
 		return TX_CONTINUE;
 
 	if (tx->flags & IEEE80211_TX_PS_BUFFERED)
@@ -237,8 +198,8 @@
 
 	if (likely(tx->flags & IEEE80211_TX_UNICAST)) {
 		if (unlikely(!(sta_flags & WLAN_STA_ASSOC) &&
-			     tx->sdata->vif.type != IEEE80211_IF_TYPE_IBSS &&
-			     (tx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA)) {
+			     tx->sdata->vif.type != NL80211_IFTYPE_ADHOC &&
+			     ieee80211_is_data(hdr->frame_control))) {
 #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
 			DECLARE_MAC_BUF(mac);
 			printk(KERN_DEBUG "%s: dropped data frame to not "
@@ -249,9 +210,9 @@
 			return TX_DROP;
 		}
 	} else {
-		if (unlikely((tx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA &&
+		if (unlikely(ieee80211_is_data(hdr->frame_control) &&
 			     tx->local->num_sta == 0 &&
-			     tx->sdata->vif.type != IEEE80211_IF_TYPE_IBSS)) {
+			     tx->sdata->vif.type != NL80211_IFTYPE_ADHOC)) {
 			/*
 			 * No associated STAs - no need to send multicast
 			 * frames.
@@ -282,7 +243,7 @@
 
 	list_for_each_entry_rcu(sdata, &local->interfaces, list) {
 		struct ieee80211_if_ap *ap;
-		if (sdata->vif.type != IEEE80211_IF_TYPE_AP)
+		if (sdata->vif.type != NL80211_IFTYPE_AP)
 			continue;
 		ap = &sdata->u.ap;
 		skb = skb_dequeue(&ap->ps_bc_buf);
@@ -315,6 +276,7 @@
 ieee80211_tx_h_multicast_ps_buf(struct ieee80211_tx_data *tx)
 {
 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data;
 
 	/*
 	 * broadcast/multicast frame
@@ -329,7 +291,7 @@
 		return TX_CONTINUE;
 
 	/* no buffering for ordered frames */
-	if (tx->fc & IEEE80211_FCTL_ORDER)
+	if (ieee80211_has_order(hdr->frame_control))
 		return TX_CONTINUE;
 
 	/* no stations in PS mode */
@@ -367,12 +329,11 @@
 {
 	struct sta_info *sta = tx->sta;
 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data;
 	u32 staflags;
 	DECLARE_MAC_BUF(mac);
 
-	if (unlikely(!sta ||
-		     ((tx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT &&
-		      (tx->fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PROBE_RESP)))
+	if (unlikely(!sta || ieee80211_is_probe_resp(hdr->frame_control)))
 		return TX_CONTINUE;
 
 	staflags = get_sta_flags(sta);
@@ -382,7 +343,7 @@
 #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
 		printk(KERN_DEBUG "STA %s aid %d: PS buffer (entries "
 		       "before %d)\n",
-		       print_mac(mac, sta->addr), sta->aid,
+		       print_mac(mac, sta->sta.addr), sta->sta.aid,
 		       skb_queue_len(&sta->ps_tx_buf));
 #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
 		if (tx->local->total_ps_buffered >= TOTAL_MAX_TX_BUFFER)
@@ -393,7 +354,7 @@
 			if (net_ratelimit()) {
 				printk(KERN_DEBUG "%s: STA %s TX "
 				       "buffer full - dropping oldest frame\n",
-				       tx->dev->name, print_mac(mac, sta->addr));
+				       tx->dev->name, print_mac(mac, sta->sta.addr));
 			}
 #endif
 			dev_kfree_skb(old);
@@ -412,7 +373,7 @@
 	else if (unlikely(test_sta_flags(sta, WLAN_STA_PS))) {
 		printk(KERN_DEBUG "%s: STA %s in PS mode, but pspoll "
 		       "set -> send frame\n", tx->dev->name,
-		       print_mac(mac, sta->addr));
+		       print_mac(mac, sta->sta.addr));
 	}
 #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
 	clear_sta_flags(sta, WLAN_STA_PSPOLL);
@@ -437,7 +398,7 @@
 {
 	struct ieee80211_key *key;
 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
-	u16 fc = tx->fc;
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data;
 
 	if (unlikely(tx->skb->do_not_encrypt))
 		tx->key = NULL;
@@ -454,22 +415,16 @@
 		tx->key = NULL;
 
 	if (tx->key) {
-		u16 ftype, stype;
-
 		tx->key->tx_rx_count++;
 		/* TODO: add threshold stuff again */
 
 		switch (tx->key->conf.alg) {
 		case ALG_WEP:
-			ftype = fc & IEEE80211_FCTL_FTYPE;
-			stype = fc & IEEE80211_FCTL_STYPE;
-
-			if (ftype == IEEE80211_FTYPE_MGMT &&
-			    stype == IEEE80211_STYPE_AUTH)
+			if (ieee80211_is_auth(hdr->frame_control))
 				break;
 		case ALG_TKIP:
 		case ALG_CCMP:
-			if (!WLAN_FC_DATA_PRESENT(fc))
+			if (!ieee80211_is_data_present(hdr->frame_control))
 				tx->key = NULL;
 			break;
 		}
@@ -491,20 +446,24 @@
 	sband = tx->local->hw.wiphy->bands[tx->channel->band];
 
 	if (likely(tx->rate_idx < 0)) {
-		rate_control_get_rate(tx->dev, sband, tx->skb, &rsel);
+		rate_control_get_rate(tx->sdata, sband, tx->sta,
+				      tx->skb, &rsel);
+		if (tx->sta)
+			tx->sta->last_txrate_idx = rsel.rate_idx;
 		tx->rate_idx = rsel.rate_idx;
 		if (unlikely(rsel.probe_idx >= 0)) {
 			info->flags |= IEEE80211_TX_CTL_RATE_CTRL_PROBE;
 			tx->flags |= IEEE80211_TX_PROBE_LAST_FRAG;
-			info->control.alt_retry_rate_idx = tx->rate_idx;
+			info->control.retries[0].rate_idx = tx->rate_idx;
+			info->control.retries[0].limit = tx->local->hw.max_altrate_tries;
 			tx->rate_idx = rsel.probe_idx;
-		} else
-			info->control.alt_retry_rate_idx = -1;
+		} else if (info->control.retries[0].limit == 0)
+			info->control.retries[0].rate_idx = -1;
 
 		if (unlikely(tx->rate_idx < 0))
 			return TX_DROP;
 	} else
-		info->control.alt_retry_rate_idx = -1;
+		info->control.retries[0].rate_idx = -1;
 
 	if (tx->sdata->bss_conf.use_cts_prot &&
 	    (tx->flags & IEEE80211_TX_FRAGMENTED) && (rsel.nonerp_idx >= 0)) {
@@ -535,7 +494,7 @@
 	sband = tx->local->hw.wiphy->bands[tx->channel->band];
 
 	if (tx->sta)
-		info->control.aid = tx->sta->aid;
+		info->control.sta = &tx->sta->sta;
 
 	if (!info->control.retry_limit) {
 		if (!is_multicast_ether_addr(hdr->addr1)) {
@@ -563,7 +522,7 @@
 		 * frames.
 		 * TODO: The last fragment could still use multiple retry
 		 * rates. */
-		info->control.alt_retry_rate_idx = -1;
+		info->control.retries[0].rate_idx = -1;
 	}
 
 	/* Use CTS protection for unicast frames sent using extended rates if
@@ -593,7 +552,7 @@
 		int idx;
 
 		/* Do not use multiple retry rates when using RTS/CTS */
-		info->control.alt_retry_rate_idx = -1;
+		info->control.retries[0].rate_idx = -1;
 
 		/* Use min(data rate, max base rate) as CTS/RTS rate */
 		rate = &sband->bitrates[tx->rate_idx];
@@ -601,7 +560,7 @@
 		for (idx = 0; idx < sband->n_bitrates; idx++) {
 			if (sband->bitrates[idx].bitrate > rate->bitrate)
 				continue;
-			if (tx->sdata->basic_rates & BIT(idx) &&
+			if (tx->sdata->bss_conf.basic_rates & BIT(idx) &&
 			    (baserate < 0 ||
 			     (sband->bitrates[baserate].bitrate
 			      < sband->bitrates[idx].bitrate)))
@@ -615,7 +574,7 @@
 	}
 
 	if (tx->sta)
-		info->control.aid = tx->sta->aid;
+		info->control.sta = &tx->sta->sta;
 
 	return TX_CONTINUE;
 }
@@ -629,7 +588,14 @@
 	u8 *qc;
 	int tid;
 
-	/* only for injected frames */
+	/*
+	 * Packet injection may want to control the sequence
+	 * number, if we have no matching interface then we
+	 * neither assign one ourselves nor ask the driver to.
+	 */
+	if (unlikely(!info->control.vif))
+		return TX_CONTINUE;
+
 	if (unlikely(ieee80211_is_ctl(hdr->frame_control)))
 		return TX_CONTINUE;
 
@@ -854,7 +820,6 @@
 	sband = tx->local->hw.wiphy->bands[tx->channel->band];
 
 	skb->do_not_encrypt = 1;
-	info->flags |= IEEE80211_TX_CTL_INJECTED;
 	tx->flags &= ~IEEE80211_TX_FRAGMENTED;
 
 	/*
@@ -986,7 +951,7 @@
 
 	/* process and remove the injection radiotap header */
 	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-	if (unlikely(sdata->vif.type == IEEE80211_IF_TYPE_MNTR)) {
+	if (unlikely(info->flags & IEEE80211_TX_CTL_INJECTED)) {
 		if (__ieee80211_parse_tx_radiotap(tx, skb) == TX_DROP)
 			return TX_DROP;
 
@@ -1000,7 +965,6 @@
 	hdr = (struct ieee80211_hdr *) skb->data;
 
 	tx->sta = sta_info_get(local, hdr->addr1);
-	tx->fc = le16_to_cpu(hdr->frame_control);
 
 	if (is_multicast_ether_addr(hdr->addr1)) {
 		tx->flags &= ~IEEE80211_TX_UNICAST;
@@ -1025,7 +989,7 @@
 	else if (test_and_clear_sta_flags(tx->sta, WLAN_STA_CLEAR_PS_FILT))
 		info->flags |= IEEE80211_TX_CTL_CLEAR_PS_FILT;
 
-	hdrlen = ieee80211_get_hdrlen(tx->fc);
+	hdrlen = ieee80211_hdrlen(hdr->frame_control);
 	if (skb->len > hdrlen + sizeof(rfc1042_header) + 2) {
 		u8 *pos = &skb->data[hdrlen + sizeof(rfc1042_header)];
 		tx->ethertype = (pos[0] << 8) | pos[1];
@@ -1038,14 +1002,14 @@
 /*
  * NB: @tx is uninitialised when passed in here
  */
-static int ieee80211_tx_prepare(struct ieee80211_tx_data *tx,
-				struct sk_buff *skb,
-				struct net_device *mdev)
+static int ieee80211_tx_prepare(struct ieee80211_local *local,
+				struct ieee80211_tx_data *tx,
+				struct sk_buff *skb)
 {
 	struct net_device *dev;
 
 	dev = dev_get_by_index(&init_net, skb->iif);
-	if (unlikely(dev && !is_ieee80211_device(dev, mdev))) {
+	if (unlikely(dev && !is_ieee80211_device(local, dev))) {
 		dev_put(dev);
 		dev = NULL;
 	}
@@ -1068,8 +1032,6 @@
 			return IEEE80211_TX_AGAIN;
 		info =  IEEE80211_SKB_CB(skb);
 
-		ieee80211_dump_frame(wiphy_name(local->hw.wiphy),
-				     "TX to low-level driver", skb);
 		ret = local->ops->tx(local_to_hw(local), skb);
 		if (ret)
 			return IEEE80211_TX_AGAIN;
@@ -1099,9 +1061,6 @@
 						~IEEE80211_TX_CTL_RATE_CTRL_PROBE;
 			}
 
-			ieee80211_dump_frame(wiphy_name(local->hw.wiphy),
-					     "TX to low-level driver",
-					     tx->extra_frag[i]);
 			ret = local->ops->tx(local_to_hw(local),
 					    tx->extra_frag[i]);
 			if (ret)
@@ -1297,20 +1256,26 @@
 	return 0;
 }
 
-int ieee80211_master_start_xmit(struct sk_buff *skb,
-				struct net_device *dev)
+int ieee80211_master_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
+	struct ieee80211_master_priv *mpriv = netdev_priv(dev);
+	struct ieee80211_local *local = mpriv->local;
 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
 	struct net_device *odev = NULL;
 	struct ieee80211_sub_if_data *osdata;
 	int headroom;
 	bool may_encrypt;
+	enum {
+		NOT_MONITOR,
+		FOUND_SDATA,
+		UNKNOWN_ADDRESS,
+	} monitor_iface = NOT_MONITOR;
 	int ret;
 
 	if (skb->iif)
 		odev = dev_get_by_index(&init_net, skb->iif);
-	if (unlikely(odev && !is_ieee80211_device(odev, dev))) {
+	if (unlikely(odev && !is_ieee80211_device(local, odev))) {
 		dev_put(odev);
 		odev = NULL;
 	}
@@ -1331,15 +1296,55 @@
 
 	if (ieee80211_vif_is_mesh(&osdata->vif) &&
 	    ieee80211_is_data(hdr->frame_control)) {
-		if (ieee80211_is_data(hdr->frame_control)) {
-			if (is_multicast_ether_addr(hdr->addr3))
-				memcpy(hdr->addr1, hdr->addr3, ETH_ALEN);
-			else
-				if (mesh_nexthop_lookup(skb, odev))
-					return  0;
-			if (memcmp(odev->dev_addr, hdr->addr4, ETH_ALEN) != 0)
-				IEEE80211_IFSTA_MESH_CTR_INC(&osdata->u.sta,
-							     fwded_frames);
+		if (is_multicast_ether_addr(hdr->addr3))
+			memcpy(hdr->addr1, hdr->addr3, ETH_ALEN);
+		else
+			if (mesh_nexthop_lookup(skb, osdata))
+				return  0;
+		if (memcmp(odev->dev_addr, hdr->addr4, ETH_ALEN) != 0)
+			IEEE80211_IFSTA_MESH_CTR_INC(&osdata->u.mesh,
+							    fwded_frames);
+	} else if (unlikely(osdata->vif.type == NL80211_IFTYPE_MONITOR)) {
+		struct ieee80211_sub_if_data *sdata;
+		int hdrlen;
+		u16 len_rthdr;
+
+		info->flags |= IEEE80211_TX_CTL_INJECTED;
+		monitor_iface = UNKNOWN_ADDRESS;
+
+		len_rthdr = ieee80211_get_radiotap_len(skb->data);
+		hdr = (struct ieee80211_hdr *)skb->data + len_rthdr;
+		hdrlen = ieee80211_hdrlen(hdr->frame_control);
+
+		/* check the header is complete in the frame */
+		if (likely(skb->len >= len_rthdr + hdrlen)) {
+			/*
+			 * We process outgoing injected frames that have a
+			 * local address we handle as though they are our
+			 * own frames.
+			 * This code here isn't entirely correct, the local
+			 * MAC address is not necessarily enough to find
+			 * the interface to use; for that proper VLAN/WDS
+			 * support we will need a different mechanism.
+			 */
+
+			rcu_read_lock();
+			list_for_each_entry_rcu(sdata, &local->interfaces,
+						list) {
+				if (!netif_running(sdata->dev))
+					continue;
+				if (compare_ether_addr(sdata->dev->dev_addr,
+						       hdr->addr2)) {
+					dev_hold(sdata->dev);
+					dev_put(odev);
+					osdata = sdata;
+					odev = osdata->dev;
+					skb->iif = sdata->dev->ifindex;
+					monitor_iface = FOUND_SDATA;
+					break;
+				}
+			}
+			rcu_read_unlock();
 		}
 	}
 
@@ -1357,7 +1362,12 @@
 		return 0;
 	}
 
-	info->control.vif = &osdata->vif;
+	if (osdata->vif.type == NL80211_IFTYPE_AP_VLAN)
+		osdata = container_of(osdata->bss,
+				      struct ieee80211_sub_if_data,
+				      u.ap);
+	if (likely(monitor_iface != UNKNOWN_ADDRESS))
+		info->control.vif = &osdata->vif;
 	ret = ieee80211_tx(odev, skb);
 	dev_put(odev);
 
@@ -1437,8 +1447,8 @@
 int ieee80211_subif_start_xmit(struct sk_buff *skb,
 			       struct net_device *dev)
 {
-	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-	struct ieee80211_sub_if_data *sdata;
+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	struct ieee80211_local *local = sdata->local;
 	int ret = 1, head_need;
 	u16 ethertype, hdrlen,  meshhdrlen = 0;
 	__le16 fc;
@@ -1450,7 +1460,6 @@
 	struct sta_info *sta;
 	u32 sta_flags = 0;
 
-	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 	if (unlikely(skb->len < ETH_HLEN)) {
 		ret = 0;
 		goto fail;
@@ -1465,8 +1474,8 @@
 	fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA);
 
 	switch (sdata->vif.type) {
-	case IEEE80211_IF_TYPE_AP:
-	case IEEE80211_IF_TYPE_VLAN:
+	case NL80211_IFTYPE_AP:
+	case NL80211_IFTYPE_AP_VLAN:
 		fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS);
 		/* DA BSSID SA */
 		memcpy(hdr.addr1, skb->data, ETH_ALEN);
@@ -1474,7 +1483,7 @@
 		memcpy(hdr.addr3, skb->data + ETH_ALEN, ETH_ALEN);
 		hdrlen = 24;
 		break;
-	case IEEE80211_IF_TYPE_WDS:
+	case NL80211_IFTYPE_WDS:
 		fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS);
 		/* RA TA DA SA */
 		memcpy(hdr.addr1, sdata->u.wds.remote_addr, ETH_ALEN);
@@ -1484,24 +1493,56 @@
 		hdrlen = 30;
 		break;
 #ifdef CONFIG_MAC80211_MESH
-	case IEEE80211_IF_TYPE_MESH_POINT:
+	case NL80211_IFTYPE_MESH_POINT:
 		fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS);
-		/* RA TA DA SA */
-		memset(hdr.addr1, 0, ETH_ALEN);
-		memcpy(hdr.addr2, dev->dev_addr, ETH_ALEN);
-		memcpy(hdr.addr3, skb->data, ETH_ALEN);
-		memcpy(hdr.addr4, skb->data + ETH_ALEN, ETH_ALEN);
-		if (!sdata->u.sta.mshcfg.dot11MeshTTL) {
+		if (!sdata->u.mesh.mshcfg.dot11MeshTTL) {
 			/* Do not send frames with mesh_ttl == 0 */
-			sdata->u.sta.mshstats.dropped_frames_ttl++;
+			sdata->u.mesh.mshstats.dropped_frames_ttl++;
 			ret = 0;
 			goto fail;
 		}
-		meshhdrlen = ieee80211_new_mesh_header(&mesh_hdr, sdata);
+		memset(&mesh_hdr, 0, sizeof(mesh_hdr));
+
+		if (compare_ether_addr(dev->dev_addr,
+					  skb->data + ETH_ALEN) == 0) {
+			/* RA TA DA SA */
+			memset(hdr.addr1, 0, ETH_ALEN);
+			memcpy(hdr.addr2, dev->dev_addr, ETH_ALEN);
+			memcpy(hdr.addr3, skb->data, ETH_ALEN);
+			memcpy(hdr.addr4, skb->data + ETH_ALEN, ETH_ALEN);
+			meshhdrlen = ieee80211_new_mesh_header(&mesh_hdr, sdata);
+		} else {
+			/* packet from other interface */
+			struct mesh_path *mppath;
+
+			memset(hdr.addr1, 0, ETH_ALEN);
+			memcpy(hdr.addr2, dev->dev_addr, ETH_ALEN);
+			memcpy(hdr.addr4, dev->dev_addr, ETH_ALEN);
+
+			if (is_multicast_ether_addr(skb->data))
+				memcpy(hdr.addr3, skb->data, ETH_ALEN);
+			else {
+				rcu_read_lock();
+				mppath = mpp_path_lookup(skb->data, sdata);
+				if (mppath)
+					memcpy(hdr.addr3, mppath->mpp, ETH_ALEN);
+				else
+					memset(hdr.addr3, 0xff, ETH_ALEN);
+				rcu_read_unlock();
+			}
+
+			mesh_hdr.flags |= MESH_FLAGS_AE_A5_A6;
+			mesh_hdr.ttl = sdata->u.mesh.mshcfg.dot11MeshTTL;
+			put_unaligned(cpu_to_le32(sdata->u.mesh.mesh_seqnum), &mesh_hdr.seqnum);
+			memcpy(mesh_hdr.eaddr1, skb->data, ETH_ALEN);
+			memcpy(mesh_hdr.eaddr2, skb->data + ETH_ALEN, ETH_ALEN);
+			sdata->u.mesh.mesh_seqnum++;
+			meshhdrlen = 18;
+		}
 		hdrlen = 30;
 		break;
 #endif
-	case IEEE80211_IF_TYPE_STA:
+	case NL80211_IFTYPE_STATION:
 		fc |= cpu_to_le16(IEEE80211_FCTL_TODS);
 		/* BSSID SA DA */
 		memcpy(hdr.addr1, sdata->u.sta.bssid, ETH_ALEN);
@@ -1509,7 +1550,7 @@
 		memcpy(hdr.addr3, skb->data, ETH_ALEN);
 		hdrlen = 24;
 		break;
-	case IEEE80211_IF_TYPE_IBSS:
+	case NL80211_IFTYPE_ADHOC:
 		/* DA SA BSSID */
 		memcpy(hdr.addr1, skb->data, ETH_ALEN);
 		memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN);
@@ -1588,19 +1629,6 @@
 	nh_pos -= skip_header_bytes;
 	h_pos -= skip_header_bytes;
 
-	/* TODO: implement support for fragments so that there is no need to
-	 * reallocate and copy payload; it might be enough to support one
-	 * extra fragment that would be copied in the beginning of the frame
-	 * data.. anyway, it would be nice to include this into skb structure
-	 * somehow
-	 *
-	 * There are few options for this:
-	 * use skb->cb as an extra space for 802.11 header
-	 * allocate new buffer if not enough headroom
-	 * make sure that there is enough headroom in every skb by increasing
-	 * build in headroom in __dev_alloc_skb() (linux/skbuff.h) and
-	 * alloc_skb() (net/core/skbuff.c)
-	 */
 	head_need = hdrlen + encaps_len + meshhdrlen - skb_headroom(skb);
 
 	/*
@@ -1823,10 +1851,7 @@
 	struct rate_selection rsel;
 	struct beacon_data *beacon;
 	struct ieee80211_supported_band *sband;
-	struct ieee80211_mgmt *mgmt;
-	int *num_beacons;
 	enum ieee80211_band band = local->hw.conf.channel->band;
-	u8 *pos;
 
 	sband = local->hw.wiphy->bands[band];
 
@@ -1835,7 +1860,7 @@
 	sdata = vif_to_sdata(vif);
 	bdev = sdata->dev;
 
-	if (sdata->vif.type == IEEE80211_IF_TYPE_AP) {
+	if (sdata->vif.type == NL80211_IFTYPE_AP) {
 		ap = &sdata->u.ap;
 		beacon = rcu_dereference(ap->beacon);
 		if (ap && beacon) {
@@ -1873,11 +1898,9 @@
 			if (beacon->tail)
 				memcpy(skb_put(skb, beacon->tail_len),
 				       beacon->tail, beacon->tail_len);
-
-			num_beacons = &ap->num_beacons;
 		} else
 			goto out;
-	} else if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS) {
+	} else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) {
 		struct ieee80211_hdr *hdr;
 		ifsta = &sdata->u.sta;
 
@@ -1889,11 +1912,13 @@
 			goto out;
 
 		hdr = (struct ieee80211_hdr *) skb->data;
-		hdr->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT,
-						  IEEE80211_STYPE_BEACON);
+		hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
+						 IEEE80211_STYPE_BEACON);
 
-		num_beacons = &ifsta->num_beacons;
 	} else if (ieee80211_vif_is_mesh(&sdata->vif)) {
+		struct ieee80211_mgmt *mgmt;
+		u8 *pos;
+
 		/* headroom, head length, tail length and maximum TIM length */
 		skb = dev_alloc_skb(local->tx_headroom + 400);
 		if (!skb)
@@ -1916,9 +1941,7 @@
 		*pos++ = WLAN_EID_SSID;
 		*pos++ = 0x0;
 
-		mesh_mgmt_ies_add(skb, sdata->dev);
-
-		num_beacons = &sdata->u.sta.num_beacons;
+		mesh_mgmt_ies_add(skb, sdata);
 	} else {
 		WARN_ON(1);
 		goto out;
@@ -1929,7 +1952,7 @@
 	skb->do_not_encrypt = 1;
 
 	info->band = band;
-	rate_control_get_rate(local->mdev, sband, skb, &rsel);
+	rate_control_get_rate(sdata, sband, NULL, skb, &rsel);
 
 	if (unlikely(rsel.rate_idx < 0)) {
 		if (net_ratelimit()) {
@@ -1955,7 +1978,6 @@
 	info->antenna_sel_tx = local->hw.conf.antenna_sel_tx;
 	info->control.retry_limit = 1;
 
-	(*num_beacons)++;
 out:
 	rcu_read_unlock();
 	return skb;
@@ -2017,7 +2039,7 @@
 	rcu_read_lock();
 	beacon = rcu_dereference(bss->beacon);
 
-	if (sdata->vif.type != IEEE80211_IF_TYPE_AP || !beacon || !beacon->head)
+	if (sdata->vif.type != NL80211_IFTYPE_AP || !beacon || !beacon->head)
 		goto out;
 
 	if (bss->dtim_count != 0)
@@ -2039,7 +2061,7 @@
 				cpu_to_le16(IEEE80211_FCTL_MOREDATA);
 		}
 
-		if (!ieee80211_tx_prepare(&tx, skb, local->mdev))
+		if (!ieee80211_tx_prepare(local, &tx, skb))
 			break;
 		dev_kfree_skb_any(skb);
 	}
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 0d463c8..f32561e 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -43,7 +43,7 @@
 
 
 u8 *ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len,
-			enum ieee80211_if_types type)
+			enum nl80211_iftype type)
 {
 	__le16 fc = hdr->frame_control;
 
@@ -77,10 +77,10 @@
 
 		if (ieee80211_is_back_req(fc)) {
 			switch (type) {
-			case IEEE80211_IF_TYPE_STA:
+			case NL80211_IFTYPE_STATION:
 				return hdr->addr2;
-			case IEEE80211_IF_TYPE_AP:
-			case IEEE80211_IF_TYPE_VLAN:
+			case NL80211_IFTYPE_AP:
+			case NL80211_IFTYPE_AP_VLAN:
 				return hdr->addr1;
 			default:
 				break; /* fall through to the return */
@@ -91,45 +91,6 @@
 	return NULL;
 }
 
-int ieee80211_get_hdrlen(u16 fc)
-{
-	int hdrlen = 24;
-
-	switch (fc & IEEE80211_FCTL_FTYPE) {
-	case IEEE80211_FTYPE_DATA:
-		if ((fc & IEEE80211_FCTL_FROMDS) && (fc & IEEE80211_FCTL_TODS))
-			hdrlen = 30; /* Addr4 */
-		/*
-		 * The QoS Control field is two bytes and its presence is
-		 * indicated by the IEEE80211_STYPE_QOS_DATA bit. Add 2 to
-		 * hdrlen if that bit is set.
-		 * This works by masking out the bit and shifting it to
-		 * bit position 1 so the result has the value 0 or 2.
-		 */
-		hdrlen += (fc & IEEE80211_STYPE_QOS_DATA)
-				>> (ilog2(IEEE80211_STYPE_QOS_DATA)-1);
-		break;
-	case IEEE80211_FTYPE_CTL:
-		/*
-		 * ACK and CTS are 10 bytes, all others 16. To see how
-		 * to get this condition consider
-		 *   subtype mask:   0b0000000011110000 (0x00F0)
-		 *   ACK subtype:    0b0000000011010000 (0x00D0)
-		 *   CTS subtype:    0b0000000011000000 (0x00C0)
-		 *   bits that matter:         ^^^      (0x00E0)
-		 *   value of those: 0b0000000011000000 (0x00C0)
-		 */
-		if ((fc & 0xE0) == 0xC0)
-			hdrlen = 10;
-		else
-			hdrlen = 16;
-		break;
-	}
-
-	return hdrlen;
-}
-EXPORT_SYMBOL(ieee80211_get_hdrlen);
-
 unsigned int ieee80211_hdrlen(__le16 fc)
 {
 	unsigned int hdrlen = 24;
@@ -270,16 +231,21 @@
 					struct ieee80211_rate *rate)
 {
 	struct ieee80211_local *local = hw_to_local(hw);
-	struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
+	struct ieee80211_sub_if_data *sdata;
 	u16 dur;
 	int erp;
+	bool short_preamble = false;
 
 	erp = 0;
-	if (sdata->flags & IEEE80211_SDATA_OPERATING_GMODE)
-		erp = rate->flags & IEEE80211_RATE_ERP_G;
+	if (vif) {
+		sdata = vif_to_sdata(vif);
+		short_preamble = sdata->bss_conf.use_short_preamble;
+		if (sdata->flags & IEEE80211_SDATA_OPERATING_GMODE)
+			erp = rate->flags & IEEE80211_RATE_ERP_G;
+	}
 
 	dur = ieee80211_frame_duration(local, frame_len, rate->bitrate, erp,
-				       sdata->bss_conf.use_short_preamble);
+				       short_preamble);
 
 	return cpu_to_le16(dur);
 }
@@ -291,7 +257,7 @@
 {
 	struct ieee80211_local *local = hw_to_local(hw);
 	struct ieee80211_rate *rate;
-	struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
+	struct ieee80211_sub_if_data *sdata;
 	bool short_preamble;
 	int erp;
 	u16 dur;
@@ -299,13 +265,17 @@
 
 	sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
 
-	short_preamble = sdata->bss_conf.use_short_preamble;
+	short_preamble = false;
 
 	rate = &sband->bitrates[frame_txctl->control.rts_cts_rate_idx];
 
 	erp = 0;
-	if (sdata->flags & IEEE80211_SDATA_OPERATING_GMODE)
-		erp = rate->flags & IEEE80211_RATE_ERP_G;
+	if (vif) {
+		sdata = vif_to_sdata(vif);
+		short_preamble = sdata->bss_conf.use_short_preamble;
+		if (sdata->flags & IEEE80211_SDATA_OPERATING_GMODE)
+			erp = rate->flags & IEEE80211_RATE_ERP_G;
+	}
 
 	/* CTS duration */
 	dur = ieee80211_frame_duration(local, 10, rate->bitrate,
@@ -328,7 +298,7 @@
 {
 	struct ieee80211_local *local = hw_to_local(hw);
 	struct ieee80211_rate *rate;
-	struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
+	struct ieee80211_sub_if_data *sdata;
 	bool short_preamble;
 	int erp;
 	u16 dur;
@@ -336,12 +306,16 @@
 
 	sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
 
-	short_preamble = sdata->bss_conf.use_short_preamble;
+	short_preamble = false;
 
 	rate = &sband->bitrates[frame_txctl->control.rts_cts_rate_idx];
 	erp = 0;
-	if (sdata->flags & IEEE80211_SDATA_OPERATING_GMODE)
-		erp = rate->flags & IEEE80211_RATE_ERP_G;
+	if (vif) {
+		sdata = vif_to_sdata(vif);
+		short_preamble = sdata->bss_conf.use_short_preamble;
+		if (sdata->flags & IEEE80211_SDATA_OPERATING_GMODE)
+			erp = rate->flags & IEEE80211_RATE_ERP_G;
+	}
 
 	/* Data frame duration */
 	dur = ieee80211_frame_duration(local, frame_len, rate->bitrate,
@@ -386,6 +360,13 @@
 }
 EXPORT_SYMBOL(ieee80211_stop_queues);
 
+int ieee80211_queue_stopped(struct ieee80211_hw *hw, int queue)
+{
+	struct ieee80211_local *local = hw_to_local(hw);
+	return __netif_subqueue_stopped(local->mdev, queue);
+}
+EXPORT_SYMBOL(ieee80211_queue_stopped);
+
 void ieee80211_wake_queues(struct ieee80211_hw *hw)
 {
 	int i;
@@ -408,15 +389,16 @@
 
 	list_for_each_entry(sdata, &local->interfaces, list) {
 		switch (sdata->vif.type) {
-		case IEEE80211_IF_TYPE_INVALID:
-		case IEEE80211_IF_TYPE_MNTR:
-		case IEEE80211_IF_TYPE_VLAN:
+		case __NL80211_IFTYPE_AFTER_LAST:
+		case NL80211_IFTYPE_UNSPECIFIED:
+		case NL80211_IFTYPE_MONITOR:
+		case NL80211_IFTYPE_AP_VLAN:
 			continue;
-		case IEEE80211_IF_TYPE_AP:
-		case IEEE80211_IF_TYPE_STA:
-		case IEEE80211_IF_TYPE_IBSS:
-		case IEEE80211_IF_TYPE_WDS:
-		case IEEE80211_IF_TYPE_MESH_POINT:
+		case NL80211_IFTYPE_AP:
+		case NL80211_IFTYPE_STATION:
+		case NL80211_IFTYPE_ADHOC:
+		case NL80211_IFTYPE_WDS:
+		case NL80211_IFTYPE_MESH_POINT:
 			break;
 		}
 		if (netif_running(sdata->dev))
@@ -441,15 +423,16 @@
 
 	list_for_each_entry_rcu(sdata, &local->interfaces, list) {
 		switch (sdata->vif.type) {
-		case IEEE80211_IF_TYPE_INVALID:
-		case IEEE80211_IF_TYPE_MNTR:
-		case IEEE80211_IF_TYPE_VLAN:
+		case __NL80211_IFTYPE_AFTER_LAST:
+		case NL80211_IFTYPE_UNSPECIFIED:
+		case NL80211_IFTYPE_MONITOR:
+		case NL80211_IFTYPE_AP_VLAN:
 			continue;
-		case IEEE80211_IF_TYPE_AP:
-		case IEEE80211_IF_TYPE_STA:
-		case IEEE80211_IF_TYPE_IBSS:
-		case IEEE80211_IF_TYPE_WDS:
-		case IEEE80211_IF_TYPE_MESH_POINT:
+		case NL80211_IFTYPE_AP:
+		case NL80211_IFTYPE_STATION:
+		case NL80211_IFTYPE_ADHOC:
+		case NL80211_IFTYPE_WDS:
+		case NL80211_IFTYPE_MESH_POINT:
 			break;
 		}
 		if (netif_running(sdata->dev))
@@ -460,3 +443,243 @@
 	rcu_read_unlock();
 }
 EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces_atomic);
+
+void ieee802_11_parse_elems(u8 *start, size_t len,
+			    struct ieee802_11_elems *elems)
+{
+	size_t left = len;
+	u8 *pos = start;
+
+	memset(elems, 0, sizeof(*elems));
+	elems->ie_start = start;
+	elems->total_len = len;
+
+	while (left >= 2) {
+		u8 id, elen;
+
+		id = *pos++;
+		elen = *pos++;
+		left -= 2;
+
+		if (elen > left)
+			return;
+
+		switch (id) {
+		case WLAN_EID_SSID:
+			elems->ssid = pos;
+			elems->ssid_len = elen;
+			break;
+		case WLAN_EID_SUPP_RATES:
+			elems->supp_rates = pos;
+			elems->supp_rates_len = elen;
+			break;
+		case WLAN_EID_FH_PARAMS:
+			elems->fh_params = pos;
+			elems->fh_params_len = elen;
+			break;
+		case WLAN_EID_DS_PARAMS:
+			elems->ds_params = pos;
+			elems->ds_params_len = elen;
+			break;
+		case WLAN_EID_CF_PARAMS:
+			elems->cf_params = pos;
+			elems->cf_params_len = elen;
+			break;
+		case WLAN_EID_TIM:
+			elems->tim = pos;
+			elems->tim_len = elen;
+			break;
+		case WLAN_EID_IBSS_PARAMS:
+			elems->ibss_params = pos;
+			elems->ibss_params_len = elen;
+			break;
+		case WLAN_EID_CHALLENGE:
+			elems->challenge = pos;
+			elems->challenge_len = elen;
+			break;
+		case WLAN_EID_WPA:
+			if (elen >= 4 && pos[0] == 0x00 && pos[1] == 0x50 &&
+			    pos[2] == 0xf2) {
+				/* Microsoft OUI (00:50:F2) */
+				if (pos[3] == 1) {
+					/* OUI Type 1 - WPA IE */
+					elems->wpa = pos;
+					elems->wpa_len = elen;
+				} else if (elen >= 5 && pos[3] == 2) {
+					if (pos[4] == 0) {
+						elems->wmm_info = pos;
+						elems->wmm_info_len = elen;
+					} else if (pos[4] == 1) {
+						elems->wmm_param = pos;
+						elems->wmm_param_len = elen;
+					}
+				}
+			}
+			break;
+		case WLAN_EID_RSN:
+			elems->rsn = pos;
+			elems->rsn_len = elen;
+			break;
+		case WLAN_EID_ERP_INFO:
+			elems->erp_info = pos;
+			elems->erp_info_len = elen;
+			break;
+		case WLAN_EID_EXT_SUPP_RATES:
+			elems->ext_supp_rates = pos;
+			elems->ext_supp_rates_len = elen;
+			break;
+		case WLAN_EID_HT_CAPABILITY:
+			elems->ht_cap_elem = pos;
+			elems->ht_cap_elem_len = elen;
+			break;
+		case WLAN_EID_HT_EXTRA_INFO:
+			elems->ht_info_elem = pos;
+			elems->ht_info_elem_len = elen;
+			break;
+		case WLAN_EID_MESH_ID:
+			elems->mesh_id = pos;
+			elems->mesh_id_len = elen;
+			break;
+		case WLAN_EID_MESH_CONFIG:
+			elems->mesh_config = pos;
+			elems->mesh_config_len = elen;
+			break;
+		case WLAN_EID_PEER_LINK:
+			elems->peer_link = pos;
+			elems->peer_link_len = elen;
+			break;
+		case WLAN_EID_PREQ:
+			elems->preq = pos;
+			elems->preq_len = elen;
+			break;
+		case WLAN_EID_PREP:
+			elems->prep = pos;
+			elems->prep_len = elen;
+			break;
+		case WLAN_EID_PERR:
+			elems->perr = pos;
+			elems->perr_len = elen;
+			break;
+		case WLAN_EID_CHANNEL_SWITCH:
+			elems->ch_switch_elem = pos;
+			elems->ch_switch_elem_len = elen;
+			break;
+		case WLAN_EID_QUIET:
+			if (!elems->quiet_elem) {
+				elems->quiet_elem = pos;
+				elems->quiet_elem_len = elen;
+			}
+			elems->num_of_quiet_elem++;
+			break;
+		case WLAN_EID_COUNTRY:
+			elems->country_elem = pos;
+			elems->country_elem_len = elen;
+			break;
+		case WLAN_EID_PWR_CONSTRAINT:
+			elems->pwr_constr_elem = pos;
+			elems->pwr_constr_elem_len = elen;
+			break;
+		default:
+			break;
+		}
+
+		left -= elen;
+		pos += elen;
+	}
+}
+
+void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata)
+{
+	struct ieee80211_local *local = sdata->local;
+	struct ieee80211_tx_queue_params qparam;
+	int i;
+
+	if (!local->ops->conf_tx)
+		return;
+
+	memset(&qparam, 0, sizeof(qparam));
+
+	qparam.aifs = 2;
+
+	if (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ &&
+	    !(sdata->flags & IEEE80211_SDATA_OPERATING_GMODE))
+		qparam.cw_min = 31;
+	else
+		qparam.cw_min = 15;
+
+	qparam.cw_max = 1023;
+	qparam.txop = 0;
+
+	for (i = 0; i < local_to_hw(local)->queues; i++)
+		local->ops->conf_tx(local_to_hw(local), i, &qparam);
+}
+
+void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb,
+		      int encrypt)
+{
+	skb->dev = sdata->local->mdev;
+	skb_set_mac_header(skb, 0);
+	skb_set_network_header(skb, 0);
+	skb_set_transport_header(skb, 0);
+
+	skb->iif = sdata->dev->ifindex;
+	skb->do_not_encrypt = !encrypt;
+
+	dev_queue_xmit(skb);
+}
+
+int ieee80211_set_freq(struct ieee80211_sub_if_data *sdata, int freqMHz)
+{
+	int ret = -EINVAL;
+	struct ieee80211_channel *chan;
+	struct ieee80211_local *local = sdata->local;
+
+	chan = ieee80211_get_channel(local->hw.wiphy, freqMHz);
+
+	if (chan && !(chan->flags & IEEE80211_CHAN_DISABLED)) {
+		if (sdata->vif.type == NL80211_IFTYPE_ADHOC &&
+		    chan->flags & IEEE80211_CHAN_NO_IBSS) {
+			printk(KERN_DEBUG "%s: IBSS not allowed on frequency "
+				"%d MHz\n", sdata->dev->name, chan->center_freq);
+			return ret;
+		}
+		local->oper_channel = chan;
+
+		if (local->sw_scanning || local->hw_scanning)
+			ret = 0;
+		else
+			ret = ieee80211_hw_config(local);
+
+		rate_control_clear(local);
+	}
+
+	return ret;
+}
+
+u64 ieee80211_mandatory_rates(struct ieee80211_local *local,
+			      enum ieee80211_band band)
+{
+	struct ieee80211_supported_band *sband;
+	struct ieee80211_rate *bitrates;
+	u64 mandatory_rates;
+	enum ieee80211_rate_flags mandatory_flag;
+	int i;
+
+	sband = local->hw.wiphy->bands[band];
+	if (!sband) {
+		WARN_ON(1);
+		sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
+	}
+
+	if (band == IEEE80211_BAND_2GHZ)
+		mandatory_flag = IEEE80211_RATE_MANDATORY_B;
+	else
+		mandatory_flag = IEEE80211_RATE_MANDATORY_A;
+
+	bitrates = sband->bitrates;
+	mandatory_rates = 0;
+	for (i = 0; i < sband->n_bitrates; i++)
+		if (bitrates[i].flags & mandatory_flag)
+			mandatory_rates |= BIT(i);
+	return mandatory_rates;
+}
diff --git a/net/mac80211/wep.c b/net/mac80211/wep.c
index 5c2bf0a..f0e2d3e 100644
--- a/net/mac80211/wep.c
+++ b/net/mac80211/wep.c
@@ -228,11 +228,10 @@
 		return -1;
 
 	hdrlen = ieee80211_hdrlen(hdr->frame_control);
-
-	if (skb->len < 8 + hdrlen)
+	if (skb->len < hdrlen + WEP_IV_LEN + WEP_ICV_LEN)
 		return -1;
 
-	len = skb->len - hdrlen - 8;
+	len = skb->len - hdrlen - WEP_IV_LEN - WEP_ICV_LEN;
 
 	keyidx = skb->data[hdrlen + 3] >> 6;
 
@@ -292,9 +291,10 @@
 ieee80211_rx_result
 ieee80211_crypto_wep_decrypt(struct ieee80211_rx_data *rx)
 {
-	if ((rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA &&
-	    ((rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_MGMT ||
-	     (rx->fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_AUTH))
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
+
+	if (!ieee80211_is_data(hdr->frame_control) &&
+	    !ieee80211_is_auth(hdr->frame_control))
 		return RX_CONTINUE;
 
 	if (!(rx->status->flag & RX_FLAG_DECRYPTED)) {
@@ -303,7 +303,7 @@
 	} else if (!(rx->status->flag & RX_FLAG_IV_STRIPPED)) {
 		ieee80211_wep_remove_iv(rx->local, rx->skb, rx->key);
 		/* remove ICV */
-		skb_trim(rx->skb, rx->skb->len - 4);
+		skb_trim(rx->skb, rx->skb->len - WEP_ICV_LEN);
 	}
 
 	return RX_CONTINUE;
@@ -313,9 +313,6 @@
 {
 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
 
-	info->control.iv_len = WEP_IV_LEN;
-	info->control.icv_len = WEP_ICV_LEN;
-
 	if (!(tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)) {
 		if (ieee80211_wep_encrypt(tx->local, skb, tx->key))
 			return -1;
diff --git a/net/mac80211/wext.c b/net/mac80211/wext.c
index 34fa8ed..7e0d53a 100644
--- a/net/mac80211/wext.c
+++ b/net/mac80211/wext.c
@@ -27,22 +27,19 @@
 #include "aes_ccm.h"
 
 
-static int ieee80211_set_encryption(struct net_device *dev, u8 *sta_addr,
+static int ieee80211_set_encryption(struct ieee80211_sub_if_data *sdata, u8 *sta_addr,
 				    int idx, int alg, int remove,
 				    int set_tx_key, const u8 *_key,
 				    size_t key_len)
 {
-	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct ieee80211_local *local = sdata->local;
 	struct sta_info *sta;
 	struct ieee80211_key *key;
-	struct ieee80211_sub_if_data *sdata;
 	int err;
 
-	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-
 	if (idx < 0 || idx >= NUM_DEFAULT_KEYS) {
 		printk(KERN_DEBUG "%s: set_encrypt - invalid idx=%d\n",
-		       dev->name, idx);
+		       sdata->dev->name, idx);
 		return -EINVAL;
 	}
 
@@ -125,13 +122,13 @@
 	if (sdata->flags & IEEE80211_SDATA_USERSPACE_MLME)
 		return -EOPNOTSUPP;
 
-	if (sdata->vif.type == IEEE80211_IF_TYPE_STA ||
-	    sdata->vif.type == IEEE80211_IF_TYPE_IBSS) {
-		int ret = ieee80211_sta_set_extra_ie(dev, extra, data->length);
+	if (sdata->vif.type == NL80211_IFTYPE_STATION ||
+	    sdata->vif.type == NL80211_IFTYPE_ADHOC) {
+		int ret = ieee80211_sta_set_extra_ie(sdata, extra, data->length);
 		if (ret)
 			return ret;
 		sdata->u.sta.flags &= ~IEEE80211_STA_AUTO_BSSID_SEL;
-		ieee80211_sta_req_auth(dev, &sdata->u.sta);
+		ieee80211_sta_req_auth(sdata, &sdata->u.sta);
 		return 0;
 	}
 
@@ -276,21 +273,21 @@
 	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 	int type;
 
-	if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN)
+	if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
 		return -EOPNOTSUPP;
 
 	switch (*mode) {
 	case IW_MODE_INFRA:
-		type = IEEE80211_IF_TYPE_STA;
+		type = NL80211_IFTYPE_STATION;
 		break;
 	case IW_MODE_ADHOC:
-		type = IEEE80211_IF_TYPE_IBSS;
+		type = NL80211_IFTYPE_ADHOC;
 		break;
 	case IW_MODE_REPEAT:
-		type = IEEE80211_IF_TYPE_WDS;
+		type = NL80211_IFTYPE_WDS;
 		break;
 	case IW_MODE_MONITOR:
-		type = IEEE80211_IF_TYPE_MNTR;
+		type = NL80211_IFTYPE_MONITOR;
 		break;
 	default:
 		return -EINVAL;
@@ -308,22 +305,22 @@
 
 	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 	switch (sdata->vif.type) {
-	case IEEE80211_IF_TYPE_AP:
+	case NL80211_IFTYPE_AP:
 		*mode = IW_MODE_MASTER;
 		break;
-	case IEEE80211_IF_TYPE_STA:
+	case NL80211_IFTYPE_STATION:
 		*mode = IW_MODE_INFRA;
 		break;
-	case IEEE80211_IF_TYPE_IBSS:
+	case NL80211_IFTYPE_ADHOC:
 		*mode = IW_MODE_ADHOC;
 		break;
-	case IEEE80211_IF_TYPE_MNTR:
+	case NL80211_IFTYPE_MONITOR:
 		*mode = IW_MODE_MONITOR;
 		break;
-	case IEEE80211_IF_TYPE_WDS:
+	case NL80211_IFTYPE_WDS:
 		*mode = IW_MODE_REPEAT;
 		break;
-	case IEEE80211_IF_TYPE_VLAN:
+	case NL80211_IFTYPE_AP_VLAN:
 		*mode = IW_MODE_SECOND;		/* FIXME */
 		break;
 	default:
@@ -333,60 +330,31 @@
 	return 0;
 }
 
-int ieee80211_set_freq(struct net_device *dev, int freqMHz)
-{
-	int ret = -EINVAL;
-	struct ieee80211_channel *chan;
-	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-
-	chan = ieee80211_get_channel(local->hw.wiphy, freqMHz);
-
-	if (chan && !(chan->flags & IEEE80211_CHAN_DISABLED)) {
-		if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS &&
-		    chan->flags & IEEE80211_CHAN_NO_IBSS) {
-			printk(KERN_DEBUG "%s: IBSS not allowed on frequency "
-				"%d MHz\n", dev->name, chan->center_freq);
-			return ret;
-		}
-		local->oper_channel = chan;
-
-		if (local->sta_sw_scanning || local->sta_hw_scanning)
-			ret = 0;
-		else
-			ret = ieee80211_hw_config(local);
-
-		rate_control_clear(local);
-	}
-
-	return ret;
-}
-
 static int ieee80211_ioctl_siwfreq(struct net_device *dev,
 				   struct iw_request_info *info,
 				   struct iw_freq *freq, char *extra)
 {
 	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 
-	if (sdata->vif.type == IEEE80211_IF_TYPE_STA)
+	if (sdata->vif.type == NL80211_IFTYPE_STATION)
 		sdata->u.sta.flags &= ~IEEE80211_STA_AUTO_CHANNEL_SEL;
 
 	/* freq->e == 0: freq->m = channel; otherwise freq = m * 10^e */
 	if (freq->e == 0) {
 		if (freq->m < 0) {
-			if (sdata->vif.type == IEEE80211_IF_TYPE_STA)
+			if (sdata->vif.type == NL80211_IFTYPE_STATION)
 				sdata->u.sta.flags |=
 					IEEE80211_STA_AUTO_CHANNEL_SEL;
 			return 0;
 		} else
-			return ieee80211_set_freq(dev,
+			return ieee80211_set_freq(sdata,
 				ieee80211_channel_to_frequency(freq->m));
 	} else {
 		int i, div = 1000000;
 		for (i = 0; i < freq->e; i++)
 			div /= 10;
 		if (div > 0)
-			return ieee80211_set_freq(dev, freq->m / div);
+			return ieee80211_set_freq(sdata, freq->m / div);
 		else
 			return -EINVAL;
 	}
@@ -418,8 +386,8 @@
 		len--;
 
 	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-	if (sdata->vif.type == IEEE80211_IF_TYPE_STA ||
-	    sdata->vif.type == IEEE80211_IF_TYPE_IBSS) {
+	if (sdata->vif.type == NL80211_IFTYPE_STATION ||
+	    sdata->vif.type == NL80211_IFTYPE_ADHOC) {
 		int ret;
 		if (sdata->flags & IEEE80211_SDATA_USERSPACE_MLME) {
 			if (len > IEEE80211_MAX_SSID_LEN)
@@ -432,14 +400,14 @@
 			sdata->u.sta.flags &= ~IEEE80211_STA_AUTO_SSID_SEL;
 		else
 			sdata->u.sta.flags |= IEEE80211_STA_AUTO_SSID_SEL;
-		ret = ieee80211_sta_set_ssid(dev, ssid, len);
+		ret = ieee80211_sta_set_ssid(sdata, ssid, len);
 		if (ret)
 			return ret;
-		ieee80211_sta_req_auth(dev, &sdata->u.sta);
+		ieee80211_sta_req_auth(sdata, &sdata->u.sta);
 		return 0;
 	}
 
-	if (sdata->vif.type == IEEE80211_IF_TYPE_AP) {
+	if (sdata->vif.type == NL80211_IFTYPE_AP) {
 		memcpy(sdata->u.ap.ssid, ssid, len);
 		memset(sdata->u.ap.ssid + len, 0,
 		       IEEE80211_MAX_SSID_LEN - len);
@@ -458,9 +426,9 @@
 
 	struct ieee80211_sub_if_data *sdata;
 	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-	if (sdata->vif.type == IEEE80211_IF_TYPE_STA ||
-	    sdata->vif.type == IEEE80211_IF_TYPE_IBSS) {
-		int res = ieee80211_sta_get_ssid(dev, ssid, &len);
+	if (sdata->vif.type == NL80211_IFTYPE_STATION ||
+	    sdata->vif.type == NL80211_IFTYPE_ADHOC) {
+		int res = ieee80211_sta_get_ssid(sdata, ssid, &len);
 		if (res == 0) {
 			data->length = len;
 			data->flags = 1;
@@ -469,7 +437,7 @@
 		return res;
 	}
 
-	if (sdata->vif.type == IEEE80211_IF_TYPE_AP) {
+	if (sdata->vif.type == NL80211_IFTYPE_AP) {
 		len = sdata->u.ap.ssid_len;
 		if (len > IW_ESSID_MAX_SIZE)
 			len = IW_ESSID_MAX_SIZE;
@@ -489,8 +457,8 @@
 	struct ieee80211_sub_if_data *sdata;
 
 	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-	if (sdata->vif.type == IEEE80211_IF_TYPE_STA ||
-	    sdata->vif.type == IEEE80211_IF_TYPE_IBSS) {
+	if (sdata->vif.type == NL80211_IFTYPE_STATION ||
+	    sdata->vif.type == NL80211_IFTYPE_ADHOC) {
 		int ret;
 		if (sdata->flags & IEEE80211_SDATA_USERSPACE_MLME) {
 			memcpy(sdata->u.sta.bssid, (u8 *) &ap_addr->sa_data,
@@ -504,12 +472,12 @@
 			sdata->u.sta.flags |= IEEE80211_STA_AUTO_BSSID_SEL;
 		else
 			sdata->u.sta.flags &= ~IEEE80211_STA_AUTO_BSSID_SEL;
-		ret = ieee80211_sta_set_bssid(dev, (u8 *) &ap_addr->sa_data);
+		ret = ieee80211_sta_set_bssid(sdata, (u8 *) &ap_addr->sa_data);
 		if (ret)
 			return ret;
-		ieee80211_sta_req_auth(dev, &sdata->u.sta);
+		ieee80211_sta_req_auth(sdata, &sdata->u.sta);
 		return 0;
-	} else if (sdata->vif.type == IEEE80211_IF_TYPE_WDS) {
+	} else if (sdata->vif.type == NL80211_IFTYPE_WDS) {
 		/*
 		 * If it is necessary to update the WDS peer address
 		 * while the interface is running, then we need to do
@@ -537,10 +505,10 @@
 	struct ieee80211_sub_if_data *sdata;
 
 	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-	if (sdata->vif.type == IEEE80211_IF_TYPE_STA ||
-	    sdata->vif.type == IEEE80211_IF_TYPE_IBSS) {
-		if (sdata->u.sta.state == IEEE80211_ASSOCIATED ||
-		    sdata->u.sta.state == IEEE80211_IBSS_JOINED) {
+	if (sdata->vif.type == NL80211_IFTYPE_STATION ||
+	    sdata->vif.type == NL80211_IFTYPE_ADHOC) {
+		if (sdata->u.sta.state == IEEE80211_STA_MLME_ASSOCIATED ||
+		    sdata->u.sta.state == IEEE80211_STA_MLME_IBSS_JOINED) {
 			ap_addr->sa_family = ARPHRD_ETHER;
 			memcpy(&ap_addr->sa_data, sdata->u.sta.bssid, ETH_ALEN);
 			return 0;
@@ -548,7 +516,7 @@
 			memset(&ap_addr->sa_data, 0, ETH_ALEN);
 			return 0;
 		}
-	} else if (sdata->vif.type == IEEE80211_IF_TYPE_WDS) {
+	} else if (sdata->vif.type == NL80211_IFTYPE_WDS) {
 		ap_addr->sa_family = ARPHRD_ETHER;
 		memcpy(&ap_addr->sa_data, sdata->u.wds.remote_addr, ETH_ALEN);
 		return 0;
@@ -570,10 +538,10 @@
 	if (!netif_running(dev))
 		return -ENETDOWN;
 
-	if (sdata->vif.type != IEEE80211_IF_TYPE_STA &&
-	    sdata->vif.type != IEEE80211_IF_TYPE_IBSS &&
-	    sdata->vif.type != IEEE80211_IF_TYPE_MESH_POINT &&
-	    sdata->vif.type != IEEE80211_IF_TYPE_AP)
+	if (sdata->vif.type != NL80211_IFTYPE_STATION &&
+	    sdata->vif.type != NL80211_IFTYPE_ADHOC &&
+	    sdata->vif.type != NL80211_IFTYPE_MESH_POINT &&
+	    sdata->vif.type != NL80211_IFTYPE_AP)
 		return -EOPNOTSUPP;
 
 	/* if SSID was specified explicitly then use that */
@@ -584,7 +552,7 @@
 		ssid_len = req->essid_len;
 	}
 
-	return ieee80211_sta_req_scan(dev, ssid, ssid_len);
+	return ieee80211_request_scan(sdata, ssid, ssid_len);
 }
 
 
@@ -594,11 +562,14 @@
 {
 	int res;
 	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct ieee80211_sub_if_data *sdata;
 
-	if (local->sta_sw_scanning || local->sta_hw_scanning)
+	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+	if (local->sw_scanning || local->hw_scanning)
 		return -EAGAIN;
 
-	res = ieee80211_sta_scan_results(dev, info, extra, data->length);
+	res = ieee80211_scan_results(local, info, extra, data->length);
 	if (res >= 0) {
 		data->length = res;
 		return 0;
@@ -656,7 +627,7 @@
 
 	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 
-	if (sdata->vif.type != IEEE80211_IF_TYPE_STA)
+	if (sdata->vif.type != NL80211_IFTYPE_STATION)
 		return -EOPNOTSUPP;
 
 	sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
@@ -665,8 +636,8 @@
 
 	sta = sta_info_get(local, sdata->u.sta.bssid);
 
-	if (sta && sta->txrate_idx < sband->n_bitrates)
-		rate->value = sband->bitrates[sta->txrate_idx].bitrate;
+	if (sta && sta->last_txrate_idx < sband->n_bitrates)
+		rate->value = sband->bitrates[sta->last_txrate_idx].bitrate;
 	else
 		rate->value = 0;
 
@@ -887,17 +858,17 @@
 	struct iw_mlme *mlme = (struct iw_mlme *) extra;
 
 	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-	if (sdata->vif.type != IEEE80211_IF_TYPE_STA &&
-	    sdata->vif.type != IEEE80211_IF_TYPE_IBSS)
+	if (sdata->vif.type != NL80211_IFTYPE_STATION &&
+	    sdata->vif.type != NL80211_IFTYPE_ADHOC)
 		return -EINVAL;
 
 	switch (mlme->cmd) {
 	case IW_MLME_DEAUTH:
 		/* TODO: mlme->addr.sa_data */
-		return ieee80211_sta_deauthenticate(dev, mlme->reason_code);
+		return ieee80211_sta_deauthenticate(sdata, mlme->reason_code);
 	case IW_MLME_DISASSOC:
 		/* TODO: mlme->addr.sa_data */
-		return ieee80211_sta_disassociate(dev, mlme->reason_code);
+		return ieee80211_sta_disassociate(sdata, mlme->reason_code);
 	default:
 		return -EOPNOTSUPP;
 	}
@@ -938,7 +909,7 @@
 	}
 
 	return ieee80211_set_encryption(
-		dev, bcaddr,
+		sdata, bcaddr,
 		idx, alg, remove,
 		!sdata->default_key,
 		keybuf, erq->length);
@@ -983,7 +954,7 @@
 	erq->length = sdata->keys[idx]->conf.keylen;
 	erq->flags |= IW_ENCODE_ENABLED;
 
-	if (sdata->vif.type == IEEE80211_IF_TYPE_STA) {
+	if (sdata->vif.type == NL80211_IFTYPE_STATION) {
 		struct ieee80211_if_sta *ifsta = &sdata->u.sta;
 		switch (ifsta->auth_alg) {
 		case WLAN_AUTH_OPEN:
@@ -1057,7 +1028,7 @@
 		sdata->drop_unencrypted = !!data->value;
 		break;
 	case IW_AUTH_PRIVACY_INVOKED:
-		if (sdata->vif.type != IEEE80211_IF_TYPE_STA)
+		if (sdata->vif.type != NL80211_IFTYPE_STATION)
 			ret = -EINVAL;
 		else {
 			sdata->u.sta.flags &= ~IEEE80211_STA_PRIVACY_INVOKED;
@@ -1072,8 +1043,8 @@
 		}
 		break;
 	case IW_AUTH_80211_AUTH_ALG:
-		if (sdata->vif.type == IEEE80211_IF_TYPE_STA ||
-		    sdata->vif.type == IEEE80211_IF_TYPE_IBSS)
+		if (sdata->vif.type == NL80211_IFTYPE_STATION ||
+		    sdata->vif.type == NL80211_IFTYPE_ADHOC)
 			sdata->u.sta.auth_algs = data->value;
 		else
 			ret = -EOPNOTSUPP;
@@ -1095,8 +1066,8 @@
 
 	rcu_read_lock();
 
-	if (sdata->vif.type == IEEE80211_IF_TYPE_STA ||
-	    sdata->vif.type == IEEE80211_IF_TYPE_IBSS)
+	if (sdata->vif.type == NL80211_IFTYPE_STATION ||
+	    sdata->vif.type == NL80211_IFTYPE_ADHOC)
 		sta = sta_info_get(local, sdata->u.sta.bssid);
 	if (!sta) {
 		wstats->discard.fragment = 0;
@@ -1126,8 +1097,8 @@
 
 	switch (data->flags & IW_AUTH_INDEX) {
 	case IW_AUTH_80211_AUTH_ALG:
-		if (sdata->vif.type == IEEE80211_IF_TYPE_STA ||
-		    sdata->vif.type == IEEE80211_IF_TYPE_IBSS)
+		if (sdata->vif.type == NL80211_IFTYPE_STATION ||
+		    sdata->vif.type == NL80211_IFTYPE_ADHOC)
 			data->value = sdata->u.sta.auth_algs;
 		else
 			ret = -EOPNOTSUPP;
@@ -1184,7 +1155,7 @@
 	} else
 		idx--;
 
-	return ieee80211_set_encryption(dev, ext->addr.sa_data, idx, alg,
+	return ieee80211_set_encryption(sdata, ext->addr.sa_data, idx, alg,
 					remove,
 					ext->ext_flags &
 					IW_ENCODE_EXT_SET_TX_KEY,
diff --git a/net/mac80211/wme.c b/net/mac80211/wme.c
index 4310e2f..139b5f2 100644
--- a/net/mac80211/wme.c
+++ b/net/mac80211/wme.c
@@ -39,7 +39,7 @@
 		return skb->priority - 256;
 
 	switch (skb->protocol) {
-	case __constant_htons(ETH_P_IP):
+	case htons(ETH_P_IP):
 		dscp = ip_hdr(skb)->tos & 0xfc;
 		break;
 
@@ -47,8 +47,6 @@
 		return 0;
 	}
 
-	if (dscp & 0x1c)
-		return 0;
 	return dscp >> 5;
 }
 
@@ -75,9 +73,8 @@
 
 
 /* Indicate which queue to use.  */
-static u16 classify80211(struct sk_buff *skb, struct net_device *dev)
+static u16 classify80211(struct ieee80211_local *local, struct sk_buff *skb)
 {
-	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
 
 	if (!ieee80211_is_data(hdr->frame_control)) {
@@ -115,14 +112,15 @@
 
 u16 ieee80211_select_queue(struct net_device *dev, struct sk_buff *skb)
 {
+	struct ieee80211_master_priv *mpriv = netdev_priv(dev);
+	struct ieee80211_local *local = mpriv->local;
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
-	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
 	struct sta_info *sta;
 	u16 queue;
 	u8 tid;
 
-	queue = classify80211(skb, dev);
+	queue = classify80211(local, skb);
 	if (unlikely(queue >= local->hw.queues))
 		queue = local->hw.queues - 1;
 
@@ -212,7 +210,7 @@
 				DECLARE_MAC_BUF(mac);
 				printk(KERN_DEBUG "allocated aggregation queue"
 					" %d tid %d addr %s pool=0x%lX\n",
-					i, tid, print_mac(mac, sta->addr),
+					i, tid, print_mac(mac, sta->sta.addr),
 					local->queue_pool[0]);
 			}
 #endif /* CONFIG_MAC80211_HT_DEBUG */
diff --git a/net/mac80211/wme.h b/net/mac80211/wme.h
index 04de28c..bc62f28 100644
--- a/net/mac80211/wme.h
+++ b/net/mac80211/wme.h
@@ -1,5 +1,4 @@
 /*
- * IEEE 802.11 driver (80211.o) - QoS datatypes
  * Copyright 2004, Instant802 Networks, Inc.
  * Copyright 2005, Devicescape Software, Inc.
  *
@@ -14,8 +13,6 @@
 #include <linux/netdevice.h>
 #include "ieee80211_i.h"
 
-#define QOS_CONTROL_LEN 2
-
 #define QOS_CONTROL_ACK_POLICY_NORMAL 0
 #define QOS_CONTROL_ACK_POLICY_NOACK 1
 
diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c
index 2f33df0..6db6494 100644
--- a/net/mac80211/wpa.c
+++ b/net/mac80211/wpa.c
@@ -127,7 +127,7 @@
 		if (!(rx->flags & IEEE80211_RX_RA_MATCH))
 			return RX_DROP_UNUSABLE;
 
-		mac80211_ev_michael_mic_failure(rx->dev, rx->key->conf.keyidx,
+		mac80211_ev_michael_mic_failure(rx->sdata, rx->key->conf.keyidx,
 						(void *) skb->data);
 		return RX_DROP_UNUSABLE;
 	}
@@ -152,9 +152,6 @@
 	int len, tail;
 	u8 *pos;
 
-	info->control.icv_len = TKIP_ICV_LEN;
-	info->control.iv_len = TKIP_IV_LEN;
-
 	if ((tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) &&
 	    !(tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV)) {
 		/* hwaccel - with no need for preallocated room for IV/ICV */
@@ -256,7 +253,7 @@
 
 	res = ieee80211_tkip_decrypt_data(rx->local->wep_rx_tfm,
 					  key, skb->data + hdrlen,
-					  skb->len - hdrlen, rx->sta->addr,
+					  skb->len - hdrlen, rx->sta->sta.addr,
 					  hdr->addr1, hwaccel, rx->queue,
 					  &rx->tkip_iv32,
 					  &rx->tkip_iv16);
@@ -374,9 +371,6 @@
 	u8 *pos, *pn;
 	int i;
 
-	info->control.icv_len = CCMP_MIC_LEN;
-	info->control.iv_len = CCMP_HDR_LEN;
-
 	if ((tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) &&
 	    !(tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV)) {
 		/* hwaccel - with no need for preallocated room for CCMP "
diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig
index ee898e7..78892cf 100644
--- a/net/netfilter/Kconfig
+++ b/net/netfilter/Kconfig
@@ -38,10 +38,11 @@
 
 	  To compile it as a module, choose M here.  If unsure, say N.
 
+if NF_CONNTRACK
+
 config NF_CT_ACCT
 	bool "Connection tracking flow accounting"
 	depends on NETFILTER_ADVANCED
-	depends on NF_CONNTRACK
 	help
 	  If this option is enabled, the connection tracking code will
 	  keep per-flow packet and byte counters.
@@ -63,7 +64,6 @@
 config NF_CONNTRACK_MARK
 	bool  'Connection mark tracking support'
 	depends on NETFILTER_ADVANCED
-	depends on NF_CONNTRACK
 	help
 	  This option enables support for connection marks, used by the
 	  `CONNMARK' target and `connmark' match. Similar to the mark value
@@ -72,7 +72,7 @@
 
 config NF_CONNTRACK_SECMARK
 	bool  'Connection tracking security mark support'
-	depends on NF_CONNTRACK && NETWORK_SECMARK
+	depends on NETWORK_SECMARK
 	default m if NETFILTER_ADVANCED=n
 	help
 	  This option enables security markings to be applied to
@@ -85,7 +85,6 @@
 
 config NF_CONNTRACK_EVENTS
 	bool "Connection tracking events"
-	depends on NF_CONNTRACK
 	depends on NETFILTER_ADVANCED
 	help
 	  If this option is enabled, the connection tracking code will
@@ -96,7 +95,7 @@
 
 config NF_CT_PROTO_DCCP
 	tristate 'DCCP protocol connection tracking support (EXPERIMENTAL)'
-	depends on EXPERIMENTAL && NF_CONNTRACK
+	depends on EXPERIMENTAL
 	depends on NETFILTER_ADVANCED
 	default IP_DCCP
 	help
@@ -107,11 +106,10 @@
 
 config NF_CT_PROTO_GRE
 	tristate
-	depends on NF_CONNTRACK
 
 config NF_CT_PROTO_SCTP
 	tristate 'SCTP protocol connection tracking support (EXPERIMENTAL)'
-	depends on EXPERIMENTAL && NF_CONNTRACK
+	depends on EXPERIMENTAL
 	depends on NETFILTER_ADVANCED
 	default IP_SCTP
 	help
@@ -123,7 +121,6 @@
 
 config NF_CT_PROTO_UDPLITE
 	tristate 'UDP-Lite protocol connection tracking support'
-	depends on NF_CONNTRACK
 	depends on NETFILTER_ADVANCED
 	help
 	  With this option enabled, the layer 3 independent connection
@@ -134,7 +131,6 @@
 
 config NF_CONNTRACK_AMANDA
 	tristate "Amanda backup protocol support"
-	depends on NF_CONNTRACK
 	depends on NETFILTER_ADVANCED
 	select TEXTSEARCH
 	select TEXTSEARCH_KMP
@@ -150,7 +146,6 @@
 
 config NF_CONNTRACK_FTP
 	tristate "FTP protocol support"
-	depends on NF_CONNTRACK
 	default m if NETFILTER_ADVANCED=n
 	help
 	  Tracking FTP connections is problematic: special helpers are
@@ -165,7 +160,7 @@
 
 config NF_CONNTRACK_H323
 	tristate "H.323 protocol support"
-	depends on NF_CONNTRACK && (IPV6 || IPV6=n)
+	depends on (IPV6 || IPV6=n)
 	depends on NETFILTER_ADVANCED
 	help
 	  H.323 is a VoIP signalling protocol from ITU-T. As one of the most
@@ -185,7 +180,6 @@
 
 config NF_CONNTRACK_IRC
 	tristate "IRC protocol support"
-	depends on NF_CONNTRACK
 	default m if NETFILTER_ADVANCED=n
 	help
 	  There is a commonly-used extension to IRC called
@@ -201,7 +195,6 @@
 
 config NF_CONNTRACK_NETBIOS_NS
 	tristate "NetBIOS name service protocol support"
-	depends on NF_CONNTRACK
 	depends on NETFILTER_ADVANCED
 	help
 	  NetBIOS name service requests are sent as broadcast messages from an
@@ -221,7 +214,6 @@
 
 config NF_CONNTRACK_PPTP
 	tristate "PPtP protocol support"
-	depends on NF_CONNTRACK
 	depends on NETFILTER_ADVANCED
 	select NF_CT_PROTO_GRE
 	help
@@ -241,7 +233,7 @@
 
 config NF_CONNTRACK_SANE
 	tristate "SANE protocol support (EXPERIMENTAL)"
-	depends on EXPERIMENTAL && NF_CONNTRACK
+	depends on EXPERIMENTAL
 	depends on NETFILTER_ADVANCED
 	help
 	  SANE is a protocol for remote access to scanners as implemented
@@ -255,7 +247,6 @@
 
 config NF_CONNTRACK_SIP
 	tristate "SIP protocol support"
-	depends on NF_CONNTRACK
 	default m if NETFILTER_ADVANCED=n
 	help
 	  SIP is an application-layer control protocol that can establish,
@@ -268,7 +259,6 @@
 
 config NF_CONNTRACK_TFTP
 	tristate "TFTP protocol support"
-	depends on NF_CONNTRACK
 	depends on NETFILTER_ADVANCED
 	help
 	  TFTP connection tracking helper, this is required depending
@@ -280,13 +270,29 @@
 
 config NF_CT_NETLINK
 	tristate 'Connection tracking netlink interface'
-	depends on NF_CONNTRACK
 	select NETFILTER_NETLINK
 	depends on NF_NAT=n || NF_NAT
 	default m if NETFILTER_ADVANCED=n
 	help
 	  This option enables support for a netlink-based userspace interface
 
+# transparent proxy support
+config NETFILTER_TPROXY
+	tristate "Transparent proxying support (EXPERIMENTAL)"
+	depends on EXPERIMENTAL
+	depends on IP_NF_MANGLE
+	depends on NETFILTER_ADVANCED
+	help
+	  This option enables transparent proxying support, that is,
+	  support for handling non-locally bound IPv4 TCP and UDP sockets.
+	  For it to work you will have to configure certain iptables rules
+	  and use policy routing. For more information on how to set it up
+	  see Documentation/networking/tproxy.txt.
+
+	  To compile it as a module, choose M here.  If unsure, say N.
+
+endif # NF_CONNTRACK
+
 config NETFILTER_XTABLES
 	tristate "Netfilter Xtables support (required for ip_tables)"
 	default m if NETFILTER_ADVANCED=n
@@ -294,11 +300,12 @@
 	  This is required if you intend to use any of ip_tables,
 	  ip6_tables or arp_tables.
 
+if NETFILTER_XTABLES
+
 # alphabetically ordered list of targets
 
 config NETFILTER_XT_TARGET_CLASSIFY
 	tristate '"CLASSIFY" target support'
-	depends on NETFILTER_XTABLES
 	depends on NETFILTER_ADVANCED
 	help
 	  This option adds a `CLASSIFY' target, which enables the user to set
@@ -311,8 +318,6 @@
 
 config NETFILTER_XT_TARGET_CONNMARK
 	tristate  '"CONNMARK" target support'
-	depends on NETFILTER_XTABLES
-	depends on IP_NF_MANGLE || IP6_NF_MANGLE
 	depends on NF_CONNTRACK
 	depends on NETFILTER_ADVANCED
 	select NF_CONNTRACK_MARK
@@ -325,9 +330,20 @@
 	  <file:Documentation/kbuild/modules.txt>.  The module will be called
 	  ipt_CONNMARK.ko.  If unsure, say `N'.
 
+config NETFILTER_XT_TARGET_CONNSECMARK
+	tristate '"CONNSECMARK" target support'
+	depends on NF_CONNTRACK && NF_CONNTRACK_SECMARK
+	default m if NETFILTER_ADVANCED=n
+	help
+	  The CONNSECMARK target copies security markings from packets
+	  to connections, and restores security markings from connections
+	  to packets (if the packets are not already marked).  This would
+	  normally be used in conjunction with the SECMARK target.
+
+	  To compile it as a module, choose M here.  If unsure, say N.
+
 config NETFILTER_XT_TARGET_DSCP
 	tristate '"DSCP" and "TOS" target support'
-	depends on NETFILTER_XTABLES
 	depends on IP_NF_MANGLE || IP6_NF_MANGLE
 	depends on NETFILTER_ADVANCED
 	help
@@ -344,7 +360,6 @@
 
 config NETFILTER_XT_TARGET_MARK
 	tristate '"MARK" target support'
-	depends on NETFILTER_XTABLES
 	default m if NETFILTER_ADVANCED=n
 	help
 	  This option adds a `MARK' target, which allows you to create rules
@@ -356,21 +371,8 @@
 
 	  To compile it as a module, choose M here.  If unsure, say N.
 
-config NETFILTER_XT_TARGET_NFQUEUE
-	tristate '"NFQUEUE" target Support'
-	depends on NETFILTER_XTABLES
-	depends on NETFILTER_ADVANCED
-	help
-	  This target replaced the old obsolete QUEUE target.
-
-	  As opposed to QUEUE, it supports 65535 different queues,
-	  not just one.
-
-	  To compile it as a module, choose M here.  If unsure, say N.
-
 config NETFILTER_XT_TARGET_NFLOG
 	tristate '"NFLOG" target support'
-	depends on NETFILTER_XTABLES
 	default m if NETFILTER_ADVANCED=n
 	help
 	  This option enables the NFLOG target, which allows to LOG
@@ -380,9 +382,19 @@
 
 	  To compile it as a module, choose M here.  If unsure, say N.
 
+config NETFILTER_XT_TARGET_NFQUEUE
+	tristate '"NFQUEUE" target Support'
+	depends on NETFILTER_ADVANCED
+	help
+	  This target replaced the old obsolete QUEUE target.
+
+	  As opposed to QUEUE, it supports 65535 different queues,
+	  not just one.
+
+	  To compile it as a module, choose M here.  If unsure, say N.
+
 config NETFILTER_XT_TARGET_NOTRACK
 	tristate  '"NOTRACK" target support'
-	depends on NETFILTER_XTABLES
 	depends on IP_NF_RAW || IP6_NF_RAW
 	depends on NF_CONNTRACK
 	depends on NETFILTER_ADVANCED
@@ -397,7 +409,6 @@
 
 config NETFILTER_XT_TARGET_RATEEST
 	tristate '"RATEEST" target support'
-	depends on NETFILTER_XTABLES
 	depends on NETFILTER_ADVANCED
 	help
 	  This option adds a `RATEEST' target, which allows to measure
@@ -406,9 +417,23 @@
 
 	  To compile it as a module, choose M here.  If unsure, say N.
 
+config NETFILTER_XT_TARGET_TPROXY
+	tristate '"TPROXY" target support (EXPERIMENTAL)'
+	depends on EXPERIMENTAL
+	depends on NETFILTER_TPROXY
+	depends on NETFILTER_XTABLES
+	depends on NETFILTER_ADVANCED
+	select NF_DEFRAG_IPV4
+	help
+	  This option adds a `TPROXY' target, which is somewhat similar to
+	  REDIRECT.  It can only be used in the mangle table and is useful
+	  to redirect traffic to a transparent proxy.  It does _not_ depend
+	  on Netfilter connection tracking and NAT, unlike REDIRECT.
+
+	  To compile it as a module, choose M here.  If unsure, say N.
+
 config NETFILTER_XT_TARGET_TRACE
 	tristate  '"TRACE" target support'
-	depends on NETFILTER_XTABLES
 	depends on IP_NF_RAW || IP6_NF_RAW
 	depends on NETFILTER_ADVANCED
 	help
@@ -421,7 +446,7 @@
 
 config NETFILTER_XT_TARGET_SECMARK
 	tristate '"SECMARK" target support'
-	depends on NETFILTER_XTABLES && NETWORK_SECMARK
+	depends on NETWORK_SECMARK
 	default m if NETFILTER_ADVANCED=n
 	help
 	  The SECMARK target allows security marking of network
@@ -429,21 +454,9 @@
 
 	  To compile it as a module, choose M here.  If unsure, say N.
 
-config NETFILTER_XT_TARGET_CONNSECMARK
-	tristate '"CONNSECMARK" target support'
-	depends on NETFILTER_XTABLES && NF_CONNTRACK && NF_CONNTRACK_SECMARK
-	default m if NETFILTER_ADVANCED=n
-	help
-	  The CONNSECMARK target copies security markings from packets
-	  to connections, and restores security markings from connections
-	  to packets (if the packets are not already marked).  This would
-	  normally be used in conjunction with the SECMARK target.
-
-	  To compile it as a module, choose M here.  If unsure, say N.
-
 config NETFILTER_XT_TARGET_TCPMSS
 	tristate '"TCPMSS" target support'
-	depends on NETFILTER_XTABLES && (IPV6 || IPV6=n)
+	depends on (IPV6 || IPV6=n)
 	default m if NETFILTER_ADVANCED=n
 	---help---
 	  This option adds a `TCPMSS' target, which allows you to alter the
@@ -470,7 +483,7 @@
 
 config NETFILTER_XT_TARGET_TCPOPTSTRIP
 	tristate '"TCPOPTSTRIP" target support (EXPERIMENTAL)'
-	depends on EXPERIMENTAL && NETFILTER_XTABLES
+	depends on EXPERIMENTAL
 	depends on IP_NF_MANGLE || IP6_NF_MANGLE
 	depends on NETFILTER_ADVANCED
 	help
@@ -479,7 +492,6 @@
 
 config NETFILTER_XT_MATCH_COMMENT
 	tristate  '"comment" match support'
-	depends on NETFILTER_XTABLES
 	depends on NETFILTER_ADVANCED
 	help
 	  This option adds a `comment' dummy-match, which allows you to put
@@ -490,7 +502,6 @@
 
 config NETFILTER_XT_MATCH_CONNBYTES
 	tristate  '"connbytes" per-connection counter match support'
-	depends on NETFILTER_XTABLES
 	depends on NF_CONNTRACK
 	depends on NETFILTER_ADVANCED
 	select NF_CT_ACCT
@@ -503,7 +514,6 @@
 
 config NETFILTER_XT_MATCH_CONNLIMIT
 	tristate '"connlimit" match support"'
-	depends on NETFILTER_XTABLES
 	depends on NF_CONNTRACK
 	depends on NETFILTER_ADVANCED
 	---help---
@@ -512,7 +522,6 @@
 
 config NETFILTER_XT_MATCH_CONNMARK
 	tristate  '"connmark" connection mark match support'
-	depends on NETFILTER_XTABLES
 	depends on NF_CONNTRACK
 	depends on NETFILTER_ADVANCED
 	select NF_CONNTRACK_MARK
@@ -526,7 +535,6 @@
 
 config NETFILTER_XT_MATCH_CONNTRACK
 	tristate '"conntrack" connection tracking match support'
-	depends on NETFILTER_XTABLES
 	depends on NF_CONNTRACK
 	default m if NETFILTER_ADVANCED=n
 	help
@@ -540,7 +548,6 @@
 
 config NETFILTER_XT_MATCH_DCCP
 	tristate '"dccp" protocol match support'
-	depends on NETFILTER_XTABLES
 	depends on NETFILTER_ADVANCED
 	default IP_DCCP
 	help
@@ -553,7 +560,6 @@
 
 config NETFILTER_XT_MATCH_DSCP
 	tristate '"dscp" and "tos" match support'
-	depends on NETFILTER_XTABLES
 	depends on NETFILTER_ADVANCED
 	help
 	  This option adds a `DSCP' match, which allows you to match against
@@ -569,7 +575,6 @@
 
 config NETFILTER_XT_MATCH_ESP
 	tristate '"esp" match support'
-	depends on NETFILTER_XTABLES
 	depends on NETFILTER_ADVANCED
 	help
 	  This match extension allows you to match a range of SPIs
@@ -577,9 +582,23 @@
 
 	  To compile it as a module, choose M here.  If unsure, say N.
 
+config NETFILTER_XT_MATCH_HASHLIMIT
+	tristate '"hashlimit" match support'
+	depends on (IP6_NF_IPTABLES || IP6_NF_IPTABLES=n)
+	depends on NETFILTER_ADVANCED
+	help
+	  This option adds a `hashlimit' match.
+
+	  As opposed to `limit', this match dynamically creates a hash table
+	  of limit buckets, based on your selection of source/destination
+	  addresses and/or ports.
+
+	  It enables you to express policies like `10kpps for any given
+	  destination address' or `500pps from any given source address'
+	  with a single rule.
+
 config NETFILTER_XT_MATCH_HELPER
 	tristate '"helper" match support'
-	depends on NETFILTER_XTABLES
 	depends on NF_CONNTRACK
 	depends on NETFILTER_ADVANCED
 	help
@@ -590,7 +609,6 @@
 
 config NETFILTER_XT_MATCH_IPRANGE
 	tristate '"iprange" address range match support'
-	depends on NETFILTER_XTABLES
 	depends on NETFILTER_ADVANCED
 	---help---
 	This option adds a "iprange" match, which allows you to match based on
@@ -601,7 +619,6 @@
 
 config NETFILTER_XT_MATCH_LENGTH
 	tristate '"length" match support'
-	depends on NETFILTER_XTABLES
 	depends on NETFILTER_ADVANCED
 	help
 	  This option allows you to match the length of a packet against a
@@ -611,7 +628,6 @@
 
 config NETFILTER_XT_MATCH_LIMIT
 	tristate '"limit" match support'
-	depends on NETFILTER_XTABLES
 	depends on NETFILTER_ADVANCED
 	help
 	  limit matching allows you to control the rate at which a rule can be
@@ -622,7 +638,6 @@
 
 config NETFILTER_XT_MATCH_MAC
 	tristate '"mac" address match support'
-	depends on NETFILTER_XTABLES
 	depends on NETFILTER_ADVANCED
 	help
 	  MAC matching allows you to match packets based on the source
@@ -632,7 +647,6 @@
 
 config NETFILTER_XT_MATCH_MARK
 	tristate '"mark" match support'
-	depends on NETFILTER_XTABLES
 	default m if NETFILTER_ADVANCED=n
 	help
 	  Netfilter mark matching allows you to match packets based on the
@@ -641,29 +655,8 @@
 
 	  To compile it as a module, choose M here.  If unsure, say N.
 
-config NETFILTER_XT_MATCH_OWNER
-	tristate '"owner" match support'
-	depends on NETFILTER_XTABLES
-	depends on NETFILTER_ADVANCED
-	---help---
-	Socket owner matching allows you to match locally-generated packets
-	based on who created the socket: the user or group. It is also
-	possible to check whether a socket actually exists.
-
-config NETFILTER_XT_MATCH_POLICY
-	tristate 'IPsec "policy" match support'
-	depends on NETFILTER_XTABLES && XFRM
-	default m if NETFILTER_ADVANCED=n
-	help
-	  Policy matching allows you to match packets based on the
-	  IPsec policy that was used during decapsulation/will
-	  be used during encapsulation.
-
-	  To compile it as a module, choose M here.  If unsure, say N.
-
 config NETFILTER_XT_MATCH_MULTIPORT
 	tristate '"multiport" Multiple port match support'
-	depends on NETFILTER_XTABLES
 	depends on NETFILTER_ADVANCED
 	help
 	  Multiport matching allows you to match TCP or UDP packets based on
@@ -672,9 +665,28 @@
 
 	  To compile it as a module, choose M here.  If unsure, say N.
 
+config NETFILTER_XT_MATCH_OWNER
+	tristate '"owner" match support'
+	depends on NETFILTER_ADVANCED
+	---help---
+	Socket owner matching allows you to match locally-generated packets
+	based on who created the socket: the user or group. It is also
+	possible to check whether a socket actually exists.
+
+config NETFILTER_XT_MATCH_POLICY
+	tristate 'IPsec "policy" match support'
+	depends on XFRM
+	default m if NETFILTER_ADVANCED=n
+	help
+	  Policy matching allows you to match packets based on the
+	  IPsec policy that was used during decapsulation/will
+	  be used during encapsulation.
+
+	  To compile it as a module, choose M here.  If unsure, say N.
+
 config NETFILTER_XT_MATCH_PHYSDEV
 	tristate '"physdev" match support'
-	depends on NETFILTER_XTABLES && BRIDGE && BRIDGE_NETFILTER
+	depends on BRIDGE && BRIDGE_NETFILTER
 	depends on NETFILTER_ADVANCED
 	help
 	  Physdev packet matching matches against the physical bridge ports
@@ -684,7 +696,6 @@
 
 config NETFILTER_XT_MATCH_PKTTYPE
 	tristate '"pkttype" packet type match support'
-	depends on NETFILTER_XTABLES
 	depends on NETFILTER_ADVANCED
 	help
 	  Packet type matching allows you to match a packet by
@@ -697,7 +708,6 @@
 
 config NETFILTER_XT_MATCH_QUOTA
 	tristate '"quota" match support'
-	depends on NETFILTER_XTABLES
 	depends on NETFILTER_ADVANCED
 	help
 	  This option adds a `quota' match, which allows to match on a
@@ -708,7 +718,6 @@
 
 config NETFILTER_XT_MATCH_RATEEST
 	tristate '"rateest" match support'
-	depends on NETFILTER_XTABLES
 	depends on NETFILTER_ADVANCED
 	select NETFILTER_XT_TARGET_RATEEST
 	help
@@ -719,7 +728,6 @@
 
 config NETFILTER_XT_MATCH_REALM
 	tristate  '"realm" match support'
-	depends on NETFILTER_XTABLES
 	depends on NETFILTER_ADVANCED
 	select NET_CLS_ROUTE
 	help
@@ -732,9 +740,26 @@
 	  If you want to compile it as a module, say M here and read
 	  <file:Documentation/kbuild/modules.txt>.  If unsure, say `N'.
 
+config NETFILTER_XT_MATCH_RECENT
+	tristate '"recent" match support'
+	depends on NETFILTER_ADVANCED
+	---help---
+	This match is used for creating one or many lists of recently
+	used addresses and then matching against that/those list(s).
+
+	Short options are available by using 'iptables -m recent -h'
+	Official Website: <http://snowman.net/projects/ipt_recent/>
+
+config NETFILTER_XT_MATCH_RECENT_PROC_COMPAT
+	bool 'Enable obsolete /proc/net/ipt_recent'
+	depends on NETFILTER_XT_MATCH_RECENT && PROC_FS
+	---help---
+	This option enables the old /proc/net/ipt_recent interface,
+	which has been obsoleted by /proc/net/xt_recent.
+
 config NETFILTER_XT_MATCH_SCTP
 	tristate  '"sctp" protocol match support (EXPERIMENTAL)'
-	depends on NETFILTER_XTABLES && EXPERIMENTAL
+	depends on EXPERIMENTAL
 	depends on NETFILTER_ADVANCED
 	default IP_SCTP
 	help
@@ -745,9 +770,23 @@
 	  If you want to compile it as a module, say M here and read
 	  <file:Documentation/kbuild/modules.txt>.  If unsure, say `N'.
 
+config NETFILTER_XT_MATCH_SOCKET
+	tristate '"socket" match support (EXPERIMENTAL)'
+	depends on EXPERIMENTAL
+	depends on NETFILTER_TPROXY
+	depends on NETFILTER_XTABLES
+	depends on NETFILTER_ADVANCED
+	select NF_DEFRAG_IPV4
+	help
+	  This option adds a `socket' match, which can be used to match
+	  packets for which a TCP or UDP socket lookup finds a valid socket.
+	  It can be used in combination with the MARK target and policy
+	  routing to implement full featured non-locally bound sockets.
+
+	  To compile it as a module, choose M here.  If unsure, say N.
+
 config NETFILTER_XT_MATCH_STATE
 	tristate '"state" match support'
-	depends on NETFILTER_XTABLES
 	depends on NF_CONNTRACK
 	default m if NETFILTER_ADVANCED=n
 	help
@@ -759,7 +798,6 @@
 
 config NETFILTER_XT_MATCH_STATISTIC
 	tristate '"statistic" match support'
-	depends on NETFILTER_XTABLES
 	depends on NETFILTER_ADVANCED
 	help
 	  This option adds a `statistic' match, which allows you to match
@@ -769,7 +807,6 @@
 
 config NETFILTER_XT_MATCH_STRING
 	tristate  '"string" match support'
-	depends on NETFILTER_XTABLES
 	depends on NETFILTER_ADVANCED
 	select TEXTSEARCH
 	select TEXTSEARCH_KMP
@@ -783,7 +820,6 @@
 
 config NETFILTER_XT_MATCH_TCPMSS
 	tristate '"tcpmss" match support'
-	depends on NETFILTER_XTABLES
 	depends on NETFILTER_ADVANCED
 	help
 	  This option adds a `tcpmss' match, which allows you to examine the
@@ -794,7 +830,6 @@
 
 config NETFILTER_XT_MATCH_TIME
 	tristate '"time" match support'
-	depends on NETFILTER_XTABLES
 	depends on NETFILTER_ADVANCED
 	---help---
 	  This option adds a "time" match, which allows you to match based on
@@ -809,7 +844,6 @@
 
 config NETFILTER_XT_MATCH_U32
 	tristate '"u32" match support'
-	depends on NETFILTER_XTABLES
 	depends on NETFILTER_ADVANCED
 	---help---
 	  u32 allows you to extract quantities of up to 4 bytes from a packet,
@@ -821,20 +855,8 @@
 
 	  Details and examples are in the kernel module source.
 
-config NETFILTER_XT_MATCH_HASHLIMIT
-	tristate '"hashlimit" match support'
-	depends on NETFILTER_XTABLES && (IP6_NF_IPTABLES || IP6_NF_IPTABLES=n)
-	depends on NETFILTER_ADVANCED
-	help
-	  This option adds a `hashlimit' match.
-
-	  As opposed to `limit', this match dynamically creates a hash table
-	  of limit buckets, based on your selection of source/destination
-	  addresses and/or ports.
-
-	  It enables you to express policies like `10kpps for any given
-	  destination address' or `500pps from any given source address'
-	  with a single rule.
+endif # NETFILTER_XTABLES
 
 endmenu
 
+source "net/netfilter/ipvs/Kconfig"
diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile
index 3bd2cc5..da3d909 100644
--- a/net/netfilter/Makefile
+++ b/net/netfilter/Makefile
@@ -34,6 +34,9 @@
 obj-$(CONFIG_NF_CONNTRACK_SIP) += nf_conntrack_sip.o
 obj-$(CONFIG_NF_CONNTRACK_TFTP) += nf_conntrack_tftp.o
 
+# transparent proxy support
+obj-$(CONFIG_NETFILTER_TPROXY) += nf_tproxy_core.o
+
 # generic X tables 
 obj-$(CONFIG_NETFILTER_XTABLES) += x_tables.o xt_tcpudp.o
 
@@ -48,6 +51,7 @@
 obj-$(CONFIG_NETFILTER_XT_TARGET_NOTRACK) += xt_NOTRACK.o
 obj-$(CONFIG_NETFILTER_XT_TARGET_RATEEST) += xt_RATEEST.o
 obj-$(CONFIG_NETFILTER_XT_TARGET_SECMARK) += xt_SECMARK.o
+obj-$(CONFIG_NETFILTER_XT_TARGET_TPROXY) += xt_TPROXY.o
 obj-$(CONFIG_NETFILTER_XT_TARGET_TCPMSS) += xt_TCPMSS.o
 obj-$(CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP) += xt_TCPOPTSTRIP.o
 obj-$(CONFIG_NETFILTER_XT_TARGET_TRACE) += xt_TRACE.o
@@ -76,10 +80,15 @@
 obj-$(CONFIG_NETFILTER_XT_MATCH_QUOTA) += xt_quota.o
 obj-$(CONFIG_NETFILTER_XT_MATCH_RATEEST) += xt_rateest.o
 obj-$(CONFIG_NETFILTER_XT_MATCH_REALM) += xt_realm.o
+obj-$(CONFIG_NETFILTER_XT_MATCH_RECENT) += xt_recent.o
 obj-$(CONFIG_NETFILTER_XT_MATCH_SCTP) += xt_sctp.o
+obj-$(CONFIG_NETFILTER_XT_MATCH_SOCKET) += xt_socket.o
 obj-$(CONFIG_NETFILTER_XT_MATCH_STATE) += xt_state.o
 obj-$(CONFIG_NETFILTER_XT_MATCH_STATISTIC) += xt_statistic.o
 obj-$(CONFIG_NETFILTER_XT_MATCH_STRING) += xt_string.o
 obj-$(CONFIG_NETFILTER_XT_MATCH_TCPMSS) += xt_tcpmss.o
 obj-$(CONFIG_NETFILTER_XT_MATCH_TIME) += xt_time.o
 obj-$(CONFIG_NETFILTER_XT_MATCH_U32) += xt_u32.o
+
+# IPVS
+obj-$(CONFIG_IP_VS) += ipvs/
diff --git a/net/netfilter/core.c b/net/netfilter/core.c
index 292fa28..a90ac83 100644
--- a/net/netfilter/core.c
+++ b/net/netfilter/core.c
@@ -26,7 +26,7 @@
 
 static DEFINE_MUTEX(afinfo_mutex);
 
-const struct nf_afinfo *nf_afinfo[NPROTO] __read_mostly;
+const struct nf_afinfo *nf_afinfo[NFPROTO_NUMPROTO] __read_mostly;
 EXPORT_SYMBOL(nf_afinfo);
 
 int nf_register_afinfo(const struct nf_afinfo *afinfo)
@@ -51,7 +51,7 @@
 }
 EXPORT_SYMBOL_GPL(nf_unregister_afinfo);
 
-struct list_head nf_hooks[NPROTO][NF_MAX_HOOKS] __read_mostly;
+struct list_head nf_hooks[NFPROTO_NUMPROTO][NF_MAX_HOOKS] __read_mostly;
 EXPORT_SYMBOL(nf_hooks);
 static DEFINE_MUTEX(nf_hook_mutex);
 
@@ -113,7 +113,7 @@
 
 unsigned int nf_iterate(struct list_head *head,
 			struct sk_buff *skb,
-			int hook,
+			unsigned int hook,
 			const struct net_device *indev,
 			const struct net_device *outdev,
 			struct list_head **i,
@@ -155,7 +155,7 @@
 
 /* Returns 1 if okfn() needs to be executed by the caller,
  * -EPERM for NF_DROP, 0 otherwise. */
-int nf_hook_slow(int pf, unsigned int hook, struct sk_buff *skb,
+int nf_hook_slow(u_int8_t pf, unsigned int hook, struct sk_buff *skb,
 		 struct net_device *indev,
 		 struct net_device *outdev,
 		 int (*okfn)(struct sk_buff *),
@@ -165,14 +165,6 @@
 	unsigned int verdict;
 	int ret = 0;
 
-#ifdef CONFIG_NET_NS
-	struct net *net;
-
-	net = indev == NULL ? dev_net(outdev) : dev_net(indev);
-	if (net != &init_net)
-		return 1;
-#endif
-
 	/* We may already have this, but read-locks nest anyway */
 	rcu_read_lock();
 
@@ -264,7 +256,7 @@
 void __init netfilter_init(void)
 {
 	int i, h;
-	for (i = 0; i < NPROTO; i++) {
+	for (i = 0; i < ARRAY_SIZE(nf_hooks); i++) {
 		for (h = 0; h < NF_MAX_HOOKS; h++)
 			INIT_LIST_HEAD(&nf_hooks[i][h]);
 	}
diff --git a/net/netfilter/ipvs/Kconfig b/net/netfilter/ipvs/Kconfig
new file mode 100644
index 0000000..05048e4
--- /dev/null
+++ b/net/netfilter/ipvs/Kconfig
@@ -0,0 +1,239 @@
+#
+# IP Virtual Server configuration
+#
+menuconfig IP_VS
+	tristate "IP virtual server support"
+	depends on NET && INET && NETFILTER
+	---help---
+	  IP Virtual Server support will let you build a high-performance
+	  virtual server based on cluster of two or more real servers. This
+	  option must be enabled for at least one of the clustered computers
+	  that will take care of intercepting incoming connections to a
+	  single IP address and scheduling them to real servers.
+
+	  Three request dispatching techniques are implemented, they are
+	  virtual server via NAT, virtual server via tunneling and virtual
+	  server via direct routing. The several scheduling algorithms can
+	  be used to choose which server the connection is directed to,
+	  thus load balancing can be achieved among the servers.  For more
+	  information and its administration program, please visit the
+	  following URL: <http://www.linuxvirtualserver.org/>.
+
+	  If you want to compile it in kernel, say Y. To compile it as a
+	  module, choose M here. If unsure, say N.
+
+if IP_VS
+
+config	IP_VS_IPV6
+	bool "IPv6 support for IPVS (DANGEROUS)"
+	depends on EXPERIMENTAL && (IPV6 = y || IP_VS = IPV6)
+	---help---
+	  Add IPv6 support to IPVS. This is incomplete and might be dangerous.
+
+	  Say N if unsure.
+
+config	IP_VS_DEBUG
+	bool "IP virtual server debugging"
+	---help---
+	  Say Y here if you want to get additional messages useful in
+	  debugging the IP virtual server code. You can change the debug
+	  level in /proc/sys/net/ipv4/vs/debug_level
+
+config	IP_VS_TAB_BITS
+	int "IPVS connection table size (the Nth power of 2)"
+	range 8 20
+	default 12
+	---help---
+	  The IPVS connection hash table uses the chaining scheme to handle
+	  hash collisions. Using a big IPVS connection hash table will greatly
+	  reduce conflicts when there are hundreds of thousands of connections
+	  in the hash table.
+
+	  Note the table size must be power of 2. The table size will be the
+	  value of 2 to the your input number power. The number to choose is
+	  from 8 to 20, the default number is 12, which means the table size
+	  is 4096. Don't input the number too small, otherwise you will lose
+	  performance on it. You can adapt the table size yourself, according
+	  to your virtual server application. It is good to set the table size
+	  not far less than the number of connections per second multiplying
+	  average lasting time of connection in the table.  For example, your
+	  virtual server gets 200 connections per second, the connection lasts
+	  for 200 seconds in average in the connection table, the table size
+	  should be not far less than 200x200, it is good to set the table
+	  size 32768 (2**15).
+
+	  Another note that each connection occupies 128 bytes effectively and
+	  each hash entry uses 8 bytes, so you can estimate how much memory is
+	  needed for your box.
+
+comment "IPVS transport protocol load balancing support"
+
+config	IP_VS_PROTO_TCP
+	bool "TCP load balancing support"
+	---help---
+	  This option enables support for load balancing TCP transport
+	  protocol. Say Y if unsure.
+
+config	IP_VS_PROTO_UDP
+	bool "UDP load balancing support"
+	---help---
+	  This option enables support for load balancing UDP transport
+	  protocol. Say Y if unsure.
+
+config	IP_VS_PROTO_AH_ESP
+	bool
+	depends on UNDEFINED
+
+config	IP_VS_PROTO_ESP
+	bool "ESP load balancing support"
+	select IP_VS_PROTO_AH_ESP
+	---help---
+	  This option enables support for load balancing ESP (Encapsulation
+	  Security Payload) transport protocol. Say Y if unsure.
+
+config	IP_VS_PROTO_AH
+	bool "AH load balancing support"
+	select IP_VS_PROTO_AH_ESP
+	---help---
+	  This option enables support for load balancing AH (Authentication
+	  Header) transport protocol. Say Y if unsure.
+
+comment "IPVS scheduler"
+
+config	IP_VS_RR
+	tristate "round-robin scheduling"
+	---help---
+	  The robin-robin scheduling algorithm simply directs network
+	  connections to different real servers in a round-robin manner.
+
+	  If you want to compile it in kernel, say Y. To compile it as a
+	  module, choose M here. If unsure, say N.
+ 
+config	IP_VS_WRR
+        tristate "weighted round-robin scheduling" 
+	---help---
+	  The weighted robin-robin scheduling algorithm directs network
+	  connections to different real servers based on server weights
+	  in a round-robin manner. Servers with higher weights receive
+	  new connections first than those with less weights, and servers
+	  with higher weights get more connections than those with less
+	  weights and servers with equal weights get equal connections.
+
+	  If you want to compile it in kernel, say Y. To compile it as a
+	  module, choose M here. If unsure, say N.
+
+config	IP_VS_LC
+        tristate "least-connection scheduling"
+	---help---
+	  The least-connection scheduling algorithm directs network
+	  connections to the server with the least number of active 
+	  connections.
+
+	  If you want to compile it in kernel, say Y. To compile it as a
+	  module, choose M here. If unsure, say N.
+
+config	IP_VS_WLC
+        tristate "weighted least-connection scheduling"
+	---help---
+	  The weighted least-connection scheduling algorithm directs network
+	  connections to the server with the least active connections
+	  normalized by the server weight.
+
+	  If you want to compile it in kernel, say Y. To compile it as a
+	  module, choose M here. If unsure, say N.
+
+config	IP_VS_LBLC
+	tristate "locality-based least-connection scheduling"
+	---help---
+	  The locality-based least-connection scheduling algorithm is for
+	  destination IP load balancing. It is usually used in cache cluster.
+	  This algorithm usually directs packet destined for an IP address to
+	  its server if the server is alive and under load. If the server is
+	  overloaded (its active connection numbers is larger than its weight)
+	  and there is a server in its half load, then allocate the weighted
+	  least-connection server to this IP address.
+
+	  If you want to compile it in kernel, say Y. To compile it as a
+	  module, choose M here. If unsure, say N.
+
+config  IP_VS_LBLCR
+	tristate "locality-based least-connection with replication scheduling"
+	---help---
+	  The locality-based least-connection with replication scheduling
+	  algorithm is also for destination IP load balancing. It is 
+	  usually used in cache cluster. It differs from the LBLC scheduling
+	  as follows: the load balancer maintains mappings from a target
+	  to a set of server nodes that can serve the target. Requests for
+	  a target are assigned to the least-connection node in the target's
+	  server set. If all the node in the server set are over loaded,
+	  it picks up a least-connection node in the cluster and adds it
+	  in the sever set for the target. If the server set has not been
+	  modified for the specified time, the most loaded node is removed
+	  from the server set, in order to avoid high degree of replication.
+
+	  If you want to compile it in kernel, say Y. To compile it as a
+	  module, choose M here. If unsure, say N.
+
+config	IP_VS_DH
+	tristate "destination hashing scheduling"
+	---help---
+	  The destination hashing scheduling algorithm assigns network
+	  connections to the servers through looking up a statically assigned
+	  hash table by their destination IP addresses.
+
+	  If you want to compile it in kernel, say Y. To compile it as a
+	  module, choose M here. If unsure, say N.
+
+config	IP_VS_SH
+	tristate "source hashing scheduling"
+	---help---
+	  The source hashing scheduling algorithm assigns network
+	  connections to the servers through looking up a statically assigned
+	  hash table by their source IP addresses.
+
+	  If you want to compile it in kernel, say Y. To compile it as a
+	  module, choose M here. If unsure, say N.
+
+config	IP_VS_SED
+	tristate "shortest expected delay scheduling"
+	---help---
+	  The shortest expected delay scheduling algorithm assigns network
+	  connections to the server with the shortest expected delay. The 
+	  expected delay that the job will experience is (Ci + 1) / Ui if 
+	  sent to the ith server, in which Ci is the number of connections
+	  on the ith server and Ui is the fixed service rate (weight)
+	  of the ith server.
+
+	  If you want to compile it in kernel, say Y. To compile it as a
+	  module, choose M here. If unsure, say N.
+
+config	IP_VS_NQ
+	tristate "never queue scheduling"
+	---help---
+	  The never queue scheduling algorithm adopts a two-speed model.
+	  When there is an idle server available, the job will be sent to
+	  the idle server, instead of waiting for a fast one. When there
+	  is no idle server available, the job will be sent to the server
+	  that minimize its expected delay (The Shortest Expected Delay
+	  scheduling algorithm).
+
+	  If you want to compile it in kernel, say Y. To compile it as a
+	  module, choose M here. If unsure, say N.
+
+comment 'IPVS application helper'
+
+config	IP_VS_FTP
+  	tristate "FTP protocol helper"
+        depends on IP_VS_PROTO_TCP
+	---help---
+	  FTP is a protocol that transfers IP address and/or port number in
+	  the payload. In the virtual server via Network Address Translation,
+	  the IP address and port number of real servers cannot be sent to
+	  clients in ftp connections directly, so FTP protocol helper is
+	  required for tracking the connection and mangling it back to that of
+	  virtual service.
+
+	  If you want to compile it in kernel, say Y. To compile it as a
+	  module, choose M here. If unsure, say N.
+
+endif # IP_VS
diff --git a/net/netfilter/ipvs/Makefile b/net/netfilter/ipvs/Makefile
new file mode 100644
index 0000000..73a46fe
--- /dev/null
+++ b/net/netfilter/ipvs/Makefile
@@ -0,0 +1,33 @@
+#
+# Makefile for the IPVS modules on top of IPv4.
+#
+
+# IPVS transport protocol load balancing support
+ip_vs_proto-objs-y :=
+ip_vs_proto-objs-$(CONFIG_IP_VS_PROTO_TCP) += ip_vs_proto_tcp.o
+ip_vs_proto-objs-$(CONFIG_IP_VS_PROTO_UDP) += ip_vs_proto_udp.o
+ip_vs_proto-objs-$(CONFIG_IP_VS_PROTO_AH_ESP) += ip_vs_proto_ah_esp.o
+
+ip_vs-objs :=	ip_vs_conn.o ip_vs_core.o ip_vs_ctl.o ip_vs_sched.o	   \
+		ip_vs_xmit.o ip_vs_app.o ip_vs_sync.o	   		   \
+		ip_vs_est.o ip_vs_proto.o 				   \
+		$(ip_vs_proto-objs-y)
+
+
+# IPVS core
+obj-$(CONFIG_IP_VS) += ip_vs.o
+
+# IPVS schedulers
+obj-$(CONFIG_IP_VS_RR) += ip_vs_rr.o
+obj-$(CONFIG_IP_VS_WRR) += ip_vs_wrr.o
+obj-$(CONFIG_IP_VS_LC) += ip_vs_lc.o
+obj-$(CONFIG_IP_VS_WLC) += ip_vs_wlc.o
+obj-$(CONFIG_IP_VS_LBLC) += ip_vs_lblc.o
+obj-$(CONFIG_IP_VS_LBLCR) += ip_vs_lblcr.o
+obj-$(CONFIG_IP_VS_DH) += ip_vs_dh.o
+obj-$(CONFIG_IP_VS_SH) += ip_vs_sh.o
+obj-$(CONFIG_IP_VS_SED) += ip_vs_sed.o
+obj-$(CONFIG_IP_VS_NQ) += ip_vs_nq.o
+
+# IPVS application helpers
+obj-$(CONFIG_IP_VS_FTP) += ip_vs_ftp.o
diff --git a/net/ipv4/ipvs/ip_vs_app.c b/net/netfilter/ipvs/ip_vs_app.c
similarity index 100%
rename from net/ipv4/ipvs/ip_vs_app.c
rename to net/netfilter/ipvs/ip_vs_app.c
diff --git a/net/netfilter/ipvs/ip_vs_conn.c b/net/netfilter/ipvs/ip_vs_conn.c
new file mode 100644
index 0000000..9a24332
--- /dev/null
+++ b/net/netfilter/ipvs/ip_vs_conn.c
@@ -0,0 +1,1110 @@
+/*
+ * IPVS         An implementation of the IP virtual server support for the
+ *              LINUX operating system.  IPVS is now implemented as a module
+ *              over the Netfilter framework. IPVS can be used to build a
+ *              high-performance and highly available server based on a
+ *              cluster of servers.
+ *
+ * Authors:     Wensong Zhang <wensong@linuxvirtualserver.org>
+ *              Peter Kese <peter.kese@ijs.si>
+ *              Julian Anastasov <ja@ssi.bg>
+ *
+ *              This program is free software; you can redistribute it and/or
+ *              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.
+ *
+ * The IPVS code for kernel 2.2 was done by Wensong Zhang and Peter Kese,
+ * with changes/fixes from Julian Anastasov, Lars Marowsky-Bree, Horms
+ * and others. Many code here is taken from IP MASQ code of kernel 2.2.
+ *
+ * Changes:
+ *
+ */
+
+#include <linux/interrupt.h>
+#include <linux/in.h>
+#include <linux/net.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/vmalloc.h>
+#include <linux/proc_fs.h>		/* for proc_net_* */
+#include <linux/seq_file.h>
+#include <linux/jhash.h>
+#include <linux/random.h>
+
+#include <net/net_namespace.h>
+#include <net/ip_vs.h>
+
+
+/*
+ *  Connection hash table: for input and output packets lookups of IPVS
+ */
+static struct list_head *ip_vs_conn_tab;
+
+/*  SLAB cache for IPVS connections */
+static struct kmem_cache *ip_vs_conn_cachep __read_mostly;
+
+/*  counter for current IPVS connections */
+static atomic_t ip_vs_conn_count = ATOMIC_INIT(0);
+
+/*  counter for no client port connections */
+static atomic_t ip_vs_conn_no_cport_cnt = ATOMIC_INIT(0);
+
+/* random value for IPVS connection hash */
+static unsigned int ip_vs_conn_rnd;
+
+/*
+ *  Fine locking granularity for big connection hash table
+ */
+#define CT_LOCKARRAY_BITS  4
+#define CT_LOCKARRAY_SIZE  (1<<CT_LOCKARRAY_BITS)
+#define CT_LOCKARRAY_MASK  (CT_LOCKARRAY_SIZE-1)
+
+struct ip_vs_aligned_lock
+{
+	rwlock_t	l;
+} __attribute__((__aligned__(SMP_CACHE_BYTES)));
+
+/* lock array for conn table */
+static struct ip_vs_aligned_lock
+__ip_vs_conntbl_lock_array[CT_LOCKARRAY_SIZE] __cacheline_aligned;
+
+static inline void ct_read_lock(unsigned key)
+{
+	read_lock(&__ip_vs_conntbl_lock_array[key&CT_LOCKARRAY_MASK].l);
+}
+
+static inline void ct_read_unlock(unsigned key)
+{
+	read_unlock(&__ip_vs_conntbl_lock_array[key&CT_LOCKARRAY_MASK].l);
+}
+
+static inline void ct_write_lock(unsigned key)
+{
+	write_lock(&__ip_vs_conntbl_lock_array[key&CT_LOCKARRAY_MASK].l);
+}
+
+static inline void ct_write_unlock(unsigned key)
+{
+	write_unlock(&__ip_vs_conntbl_lock_array[key&CT_LOCKARRAY_MASK].l);
+}
+
+static inline void ct_read_lock_bh(unsigned key)
+{
+	read_lock_bh(&__ip_vs_conntbl_lock_array[key&CT_LOCKARRAY_MASK].l);
+}
+
+static inline void ct_read_unlock_bh(unsigned key)
+{
+	read_unlock_bh(&__ip_vs_conntbl_lock_array[key&CT_LOCKARRAY_MASK].l);
+}
+
+static inline void ct_write_lock_bh(unsigned key)
+{
+	write_lock_bh(&__ip_vs_conntbl_lock_array[key&CT_LOCKARRAY_MASK].l);
+}
+
+static inline void ct_write_unlock_bh(unsigned key)
+{
+	write_unlock_bh(&__ip_vs_conntbl_lock_array[key&CT_LOCKARRAY_MASK].l);
+}
+
+
+/*
+ *	Returns hash value for IPVS connection entry
+ */
+static unsigned int ip_vs_conn_hashkey(int af, unsigned proto,
+				       const union nf_inet_addr *addr,
+				       __be16 port)
+{
+#ifdef CONFIG_IP_VS_IPV6
+	if (af == AF_INET6)
+		return jhash_3words(jhash(addr, 16, ip_vs_conn_rnd),
+				    (__force u32)port, proto, ip_vs_conn_rnd)
+			& IP_VS_CONN_TAB_MASK;
+#endif
+	return jhash_3words((__force u32)addr->ip, (__force u32)port, proto,
+			    ip_vs_conn_rnd)
+		& IP_VS_CONN_TAB_MASK;
+}
+
+
+/*
+ *	Hashes ip_vs_conn in ip_vs_conn_tab by proto,addr,port.
+ *	returns bool success.
+ */
+static inline int ip_vs_conn_hash(struct ip_vs_conn *cp)
+{
+	unsigned hash;
+	int ret;
+
+	/* Hash by protocol, client address and port */
+	hash = ip_vs_conn_hashkey(cp->af, cp->protocol, &cp->caddr, cp->cport);
+
+	ct_write_lock(hash);
+
+	if (!(cp->flags & IP_VS_CONN_F_HASHED)) {
+		list_add(&cp->c_list, &ip_vs_conn_tab[hash]);
+		cp->flags |= IP_VS_CONN_F_HASHED;
+		atomic_inc(&cp->refcnt);
+		ret = 1;
+	} else {
+		IP_VS_ERR("ip_vs_conn_hash(): request for already hashed, "
+			  "called from %p\n", __builtin_return_address(0));
+		ret = 0;
+	}
+
+	ct_write_unlock(hash);
+
+	return ret;
+}
+
+
+/*
+ *	UNhashes ip_vs_conn from ip_vs_conn_tab.
+ *	returns bool success.
+ */
+static inline int ip_vs_conn_unhash(struct ip_vs_conn *cp)
+{
+	unsigned hash;
+	int ret;
+
+	/* unhash it and decrease its reference counter */
+	hash = ip_vs_conn_hashkey(cp->af, cp->protocol, &cp->caddr, cp->cport);
+
+	ct_write_lock(hash);
+
+	if (cp->flags & IP_VS_CONN_F_HASHED) {
+		list_del(&cp->c_list);
+		cp->flags &= ~IP_VS_CONN_F_HASHED;
+		atomic_dec(&cp->refcnt);
+		ret = 1;
+	} else
+		ret = 0;
+
+	ct_write_unlock(hash);
+
+	return ret;
+}
+
+
+/*
+ *  Gets ip_vs_conn associated with supplied parameters in the ip_vs_conn_tab.
+ *  Called for pkts coming from OUTside-to-INside.
+ *	s_addr, s_port: pkt source address (foreign host)
+ *	d_addr, d_port: pkt dest address (load balancer)
+ */
+static inline struct ip_vs_conn *__ip_vs_conn_in_get
+(int af, int protocol, const union nf_inet_addr *s_addr, __be16 s_port,
+ const union nf_inet_addr *d_addr, __be16 d_port)
+{
+	unsigned hash;
+	struct ip_vs_conn *cp;
+
+	hash = ip_vs_conn_hashkey(af, protocol, s_addr, s_port);
+
+	ct_read_lock(hash);
+
+	list_for_each_entry(cp, &ip_vs_conn_tab[hash], c_list) {
+		if (cp->af == af &&
+		    ip_vs_addr_equal(af, s_addr, &cp->caddr) &&
+		    ip_vs_addr_equal(af, d_addr, &cp->vaddr) &&
+		    s_port == cp->cport && d_port == cp->vport &&
+		    ((!s_port) ^ (!(cp->flags & IP_VS_CONN_F_NO_CPORT))) &&
+		    protocol == cp->protocol) {
+			/* HIT */
+			atomic_inc(&cp->refcnt);
+			ct_read_unlock(hash);
+			return cp;
+		}
+	}
+
+	ct_read_unlock(hash);
+
+	return NULL;
+}
+
+struct ip_vs_conn *ip_vs_conn_in_get
+(int af, int protocol, const union nf_inet_addr *s_addr, __be16 s_port,
+ const union nf_inet_addr *d_addr, __be16 d_port)
+{
+	struct ip_vs_conn *cp;
+
+	cp = __ip_vs_conn_in_get(af, protocol, s_addr, s_port, d_addr, d_port);
+	if (!cp && atomic_read(&ip_vs_conn_no_cport_cnt))
+		cp = __ip_vs_conn_in_get(af, protocol, s_addr, 0, d_addr,
+					 d_port);
+
+	IP_VS_DBG_BUF(9, "lookup/in %s %s:%d->%s:%d %s\n",
+		      ip_vs_proto_name(protocol),
+		      IP_VS_DBG_ADDR(af, s_addr), ntohs(s_port),
+		      IP_VS_DBG_ADDR(af, d_addr), ntohs(d_port),
+		      cp ? "hit" : "not hit");
+
+	return cp;
+}
+
+/* Get reference to connection template */
+struct ip_vs_conn *ip_vs_ct_in_get
+(int af, int protocol, const union nf_inet_addr *s_addr, __be16 s_port,
+ const union nf_inet_addr *d_addr, __be16 d_port)
+{
+	unsigned hash;
+	struct ip_vs_conn *cp;
+
+	hash = ip_vs_conn_hashkey(af, protocol, s_addr, s_port);
+
+	ct_read_lock(hash);
+
+	list_for_each_entry(cp, &ip_vs_conn_tab[hash], c_list) {
+		if (cp->af == af &&
+		    ip_vs_addr_equal(af, s_addr, &cp->caddr) &&
+		    ip_vs_addr_equal(af, d_addr, &cp->vaddr) &&
+		    s_port == cp->cport && d_port == cp->vport &&
+		    cp->flags & IP_VS_CONN_F_TEMPLATE &&
+		    protocol == cp->protocol) {
+			/* HIT */
+			atomic_inc(&cp->refcnt);
+			goto out;
+		}
+	}
+	cp = NULL;
+
+  out:
+	ct_read_unlock(hash);
+
+	IP_VS_DBG_BUF(9, "template lookup/in %s %s:%d->%s:%d %s\n",
+		      ip_vs_proto_name(protocol),
+		      IP_VS_DBG_ADDR(af, s_addr), ntohs(s_port),
+		      IP_VS_DBG_ADDR(af, d_addr), ntohs(d_port),
+		      cp ? "hit" : "not hit");
+
+	return cp;
+}
+
+/*
+ *  Gets ip_vs_conn associated with supplied parameters in the ip_vs_conn_tab.
+ *  Called for pkts coming from inside-to-OUTside.
+ *	s_addr, s_port: pkt source address (inside host)
+ *	d_addr, d_port: pkt dest address (foreign host)
+ */
+struct ip_vs_conn *ip_vs_conn_out_get
+(int af, int protocol, const union nf_inet_addr *s_addr, __be16 s_port,
+ const union nf_inet_addr *d_addr, __be16 d_port)
+{
+	unsigned hash;
+	struct ip_vs_conn *cp, *ret=NULL;
+
+	/*
+	 *	Check for "full" addressed entries
+	 */
+	hash = ip_vs_conn_hashkey(af, protocol, d_addr, d_port);
+
+	ct_read_lock(hash);
+
+	list_for_each_entry(cp, &ip_vs_conn_tab[hash], c_list) {
+		if (cp->af == af &&
+		    ip_vs_addr_equal(af, d_addr, &cp->caddr) &&
+		    ip_vs_addr_equal(af, s_addr, &cp->daddr) &&
+		    d_port == cp->cport && s_port == cp->dport &&
+		    protocol == cp->protocol) {
+			/* HIT */
+			atomic_inc(&cp->refcnt);
+			ret = cp;
+			break;
+		}
+	}
+
+	ct_read_unlock(hash);
+
+	IP_VS_DBG_BUF(9, "lookup/out %s %s:%d->%s:%d %s\n",
+		      ip_vs_proto_name(protocol),
+		      IP_VS_DBG_ADDR(af, s_addr), ntohs(s_port),
+		      IP_VS_DBG_ADDR(af, d_addr), ntohs(d_port),
+		      ret ? "hit" : "not hit");
+
+	return ret;
+}
+
+
+/*
+ *      Put back the conn and restart its timer with its timeout
+ */
+void ip_vs_conn_put(struct ip_vs_conn *cp)
+{
+	/* reset it expire in its timeout */
+	mod_timer(&cp->timer, jiffies+cp->timeout);
+
+	__ip_vs_conn_put(cp);
+}
+
+
+/*
+ *	Fill a no_client_port connection with a client port number
+ */
+void ip_vs_conn_fill_cport(struct ip_vs_conn *cp, __be16 cport)
+{
+	if (ip_vs_conn_unhash(cp)) {
+		spin_lock(&cp->lock);
+		if (cp->flags & IP_VS_CONN_F_NO_CPORT) {
+			atomic_dec(&ip_vs_conn_no_cport_cnt);
+			cp->flags &= ~IP_VS_CONN_F_NO_CPORT;
+			cp->cport = cport;
+		}
+		spin_unlock(&cp->lock);
+
+		/* hash on new dport */
+		ip_vs_conn_hash(cp);
+	}
+}
+
+
+/*
+ *	Bind a connection entry with the corresponding packet_xmit.
+ *	Called by ip_vs_conn_new.
+ */
+static inline void ip_vs_bind_xmit(struct ip_vs_conn *cp)
+{
+	switch (IP_VS_FWD_METHOD(cp)) {
+	case IP_VS_CONN_F_MASQ:
+		cp->packet_xmit = ip_vs_nat_xmit;
+		break;
+
+	case IP_VS_CONN_F_TUNNEL:
+		cp->packet_xmit = ip_vs_tunnel_xmit;
+		break;
+
+	case IP_VS_CONN_F_DROUTE:
+		cp->packet_xmit = ip_vs_dr_xmit;
+		break;
+
+	case IP_VS_CONN_F_LOCALNODE:
+		cp->packet_xmit = ip_vs_null_xmit;
+		break;
+
+	case IP_VS_CONN_F_BYPASS:
+		cp->packet_xmit = ip_vs_bypass_xmit;
+		break;
+	}
+}
+
+#ifdef CONFIG_IP_VS_IPV6
+static inline void ip_vs_bind_xmit_v6(struct ip_vs_conn *cp)
+{
+	switch (IP_VS_FWD_METHOD(cp)) {
+	case IP_VS_CONN_F_MASQ:
+		cp->packet_xmit = ip_vs_nat_xmit_v6;
+		break;
+
+	case IP_VS_CONN_F_TUNNEL:
+		cp->packet_xmit = ip_vs_tunnel_xmit_v6;
+		break;
+
+	case IP_VS_CONN_F_DROUTE:
+		cp->packet_xmit = ip_vs_dr_xmit_v6;
+		break;
+
+	case IP_VS_CONN_F_LOCALNODE:
+		cp->packet_xmit = ip_vs_null_xmit;
+		break;
+
+	case IP_VS_CONN_F_BYPASS:
+		cp->packet_xmit = ip_vs_bypass_xmit_v6;
+		break;
+	}
+}
+#endif
+
+
+static inline int ip_vs_dest_totalconns(struct ip_vs_dest *dest)
+{
+	return atomic_read(&dest->activeconns)
+		+ atomic_read(&dest->inactconns);
+}
+
+/*
+ *	Bind a connection entry with a virtual service destination
+ *	Called just after a new connection entry is created.
+ */
+static inline void
+ip_vs_bind_dest(struct ip_vs_conn *cp, struct ip_vs_dest *dest)
+{
+	/* if dest is NULL, then return directly */
+	if (!dest)
+		return;
+
+	/* Increase the refcnt counter of the dest */
+	atomic_inc(&dest->refcnt);
+
+	/* Bind with the destination and its corresponding transmitter */
+	if ((cp->flags & IP_VS_CONN_F_SYNC) &&
+	    (!(cp->flags & IP_VS_CONN_F_TEMPLATE)))
+		/* if the connection is not template and is created
+		 * by sync, preserve the activity flag.
+		 */
+		cp->flags |= atomic_read(&dest->conn_flags) &
+			     (~IP_VS_CONN_F_INACTIVE);
+	else
+		cp->flags |= atomic_read(&dest->conn_flags);
+	cp->dest = dest;
+
+	IP_VS_DBG_BUF(7, "Bind-dest %s c:%s:%d v:%s:%d "
+		      "d:%s:%d fwd:%c s:%u conn->flags:%X conn->refcnt:%d "
+		      "dest->refcnt:%d\n",
+		      ip_vs_proto_name(cp->protocol),
+		      IP_VS_DBG_ADDR(cp->af, &cp->caddr), ntohs(cp->cport),
+		      IP_VS_DBG_ADDR(cp->af, &cp->vaddr), ntohs(cp->vport),
+		      IP_VS_DBG_ADDR(cp->af, &cp->daddr), ntohs(cp->dport),
+		      ip_vs_fwd_tag(cp), cp->state,
+		      cp->flags, atomic_read(&cp->refcnt),
+		      atomic_read(&dest->refcnt));
+
+	/* Update the connection counters */
+	if (!(cp->flags & IP_VS_CONN_F_TEMPLATE)) {
+		/* It is a normal connection, so increase the inactive
+		   connection counter because it is in TCP SYNRECV
+		   state (inactive) or other protocol inacive state */
+		if ((cp->flags & IP_VS_CONN_F_SYNC) &&
+		    (!(cp->flags & IP_VS_CONN_F_INACTIVE)))
+			atomic_inc(&dest->activeconns);
+		else
+			atomic_inc(&dest->inactconns);
+	} else {
+		/* It is a persistent connection/template, so increase
+		   the peristent connection counter */
+		atomic_inc(&dest->persistconns);
+	}
+
+	if (dest->u_threshold != 0 &&
+	    ip_vs_dest_totalconns(dest) >= dest->u_threshold)
+		dest->flags |= IP_VS_DEST_F_OVERLOAD;
+}
+
+
+/*
+ * Check if there is a destination for the connection, if so
+ * bind the connection to the destination.
+ */
+struct ip_vs_dest *ip_vs_try_bind_dest(struct ip_vs_conn *cp)
+{
+	struct ip_vs_dest *dest;
+
+	if ((cp) && (!cp->dest)) {
+		dest = ip_vs_find_dest(cp->af, &cp->daddr, cp->dport,
+				       &cp->vaddr, cp->vport,
+				       cp->protocol);
+		ip_vs_bind_dest(cp, dest);
+		return dest;
+	} else
+		return NULL;
+}
+
+
+/*
+ *	Unbind a connection entry with its VS destination
+ *	Called by the ip_vs_conn_expire function.
+ */
+static inline void ip_vs_unbind_dest(struct ip_vs_conn *cp)
+{
+	struct ip_vs_dest *dest = cp->dest;
+
+	if (!dest)
+		return;
+
+	IP_VS_DBG_BUF(7, "Unbind-dest %s c:%s:%d v:%s:%d "
+		      "d:%s:%d fwd:%c s:%u conn->flags:%X conn->refcnt:%d "
+		      "dest->refcnt:%d\n",
+		      ip_vs_proto_name(cp->protocol),
+		      IP_VS_DBG_ADDR(cp->af, &cp->caddr), ntohs(cp->cport),
+		      IP_VS_DBG_ADDR(cp->af, &cp->vaddr), ntohs(cp->vport),
+		      IP_VS_DBG_ADDR(cp->af, &cp->daddr), ntohs(cp->dport),
+		      ip_vs_fwd_tag(cp), cp->state,
+		      cp->flags, atomic_read(&cp->refcnt),
+		      atomic_read(&dest->refcnt));
+
+	/* Update the connection counters */
+	if (!(cp->flags & IP_VS_CONN_F_TEMPLATE)) {
+		/* It is a normal connection, so decrease the inactconns
+		   or activeconns counter */
+		if (cp->flags & IP_VS_CONN_F_INACTIVE) {
+			atomic_dec(&dest->inactconns);
+		} else {
+			atomic_dec(&dest->activeconns);
+		}
+	} else {
+		/* It is a persistent connection/template, so decrease
+		   the peristent connection counter */
+		atomic_dec(&dest->persistconns);
+	}
+
+	if (dest->l_threshold != 0) {
+		if (ip_vs_dest_totalconns(dest) < dest->l_threshold)
+			dest->flags &= ~IP_VS_DEST_F_OVERLOAD;
+	} else if (dest->u_threshold != 0) {
+		if (ip_vs_dest_totalconns(dest) * 4 < dest->u_threshold * 3)
+			dest->flags &= ~IP_VS_DEST_F_OVERLOAD;
+	} else {
+		if (dest->flags & IP_VS_DEST_F_OVERLOAD)
+			dest->flags &= ~IP_VS_DEST_F_OVERLOAD;
+	}
+
+	/*
+	 * Simply decrease the refcnt of the dest, because the
+	 * dest will be either in service's destination list
+	 * or in the trash.
+	 */
+	atomic_dec(&dest->refcnt);
+}
+
+
+/*
+ *	Checking if the destination of a connection template is available.
+ *	If available, return 1, otherwise invalidate this connection
+ *	template and return 0.
+ */
+int ip_vs_check_template(struct ip_vs_conn *ct)
+{
+	struct ip_vs_dest *dest = ct->dest;
+
+	/*
+	 * Checking the dest server status.
+	 */
+	if ((dest == NULL) ||
+	    !(dest->flags & IP_VS_DEST_F_AVAILABLE) ||
+	    (sysctl_ip_vs_expire_quiescent_template &&
+	     (atomic_read(&dest->weight) == 0))) {
+		IP_VS_DBG_BUF(9, "check_template: dest not available for "
+			      "protocol %s s:%s:%d v:%s:%d "
+			      "-> d:%s:%d\n",
+			      ip_vs_proto_name(ct->protocol),
+			      IP_VS_DBG_ADDR(ct->af, &ct->caddr),
+			      ntohs(ct->cport),
+			      IP_VS_DBG_ADDR(ct->af, &ct->vaddr),
+			      ntohs(ct->vport),
+			      IP_VS_DBG_ADDR(ct->af, &ct->daddr),
+			      ntohs(ct->dport));
+
+		/*
+		 * Invalidate the connection template
+		 */
+		if (ct->vport != htons(0xffff)) {
+			if (ip_vs_conn_unhash(ct)) {
+				ct->dport = htons(0xffff);
+				ct->vport = htons(0xffff);
+				ct->cport = 0;
+				ip_vs_conn_hash(ct);
+			}
+		}
+
+		/*
+		 * Simply decrease the refcnt of the template,
+		 * don't restart its timer.
+		 */
+		atomic_dec(&ct->refcnt);
+		return 0;
+	}
+	return 1;
+}
+
+static void ip_vs_conn_expire(unsigned long data)
+{
+	struct ip_vs_conn *cp = (struct ip_vs_conn *)data;
+
+	cp->timeout = 60*HZ;
+
+	/*
+	 *	hey, I'm using it
+	 */
+	atomic_inc(&cp->refcnt);
+
+	/*
+	 *	do I control anybody?
+	 */
+	if (atomic_read(&cp->n_control))
+		goto expire_later;
+
+	/*
+	 *	unhash it if it is hashed in the conn table
+	 */
+	if (!ip_vs_conn_unhash(cp))
+		goto expire_later;
+
+	/*
+	 *	refcnt==1 implies I'm the only one referrer
+	 */
+	if (likely(atomic_read(&cp->refcnt) == 1)) {
+		/* delete the timer if it is activated by other users */
+		if (timer_pending(&cp->timer))
+			del_timer(&cp->timer);
+
+		/* does anybody control me? */
+		if (cp->control)
+			ip_vs_control_del(cp);
+
+		if (unlikely(cp->app != NULL))
+			ip_vs_unbind_app(cp);
+		ip_vs_unbind_dest(cp);
+		if (cp->flags & IP_VS_CONN_F_NO_CPORT)
+			atomic_dec(&ip_vs_conn_no_cport_cnt);
+		atomic_dec(&ip_vs_conn_count);
+
+		kmem_cache_free(ip_vs_conn_cachep, cp);
+		return;
+	}
+
+	/* hash it back to the table */
+	ip_vs_conn_hash(cp);
+
+  expire_later:
+	IP_VS_DBG(7, "delayed: conn->refcnt-1=%d conn->n_control=%d\n",
+		  atomic_read(&cp->refcnt)-1,
+		  atomic_read(&cp->n_control));
+
+	ip_vs_conn_put(cp);
+}
+
+
+void ip_vs_conn_expire_now(struct ip_vs_conn *cp)
+{
+	if (del_timer(&cp->timer))
+		mod_timer(&cp->timer, jiffies);
+}
+
+
+/*
+ *	Create a new connection entry and hash it into the ip_vs_conn_tab
+ */
+struct ip_vs_conn *
+ip_vs_conn_new(int af, int proto, const union nf_inet_addr *caddr, __be16 cport,
+	       const union nf_inet_addr *vaddr, __be16 vport,
+	       const union nf_inet_addr *daddr, __be16 dport, unsigned flags,
+	       struct ip_vs_dest *dest)
+{
+	struct ip_vs_conn *cp;
+	struct ip_vs_protocol *pp = ip_vs_proto_get(proto);
+
+	cp = kmem_cache_zalloc(ip_vs_conn_cachep, GFP_ATOMIC);
+	if (cp == NULL) {
+		IP_VS_ERR_RL("ip_vs_conn_new: no memory available.\n");
+		return NULL;
+	}
+
+	INIT_LIST_HEAD(&cp->c_list);
+	setup_timer(&cp->timer, ip_vs_conn_expire, (unsigned long)cp);
+	cp->af		   = af;
+	cp->protocol	   = proto;
+	ip_vs_addr_copy(af, &cp->caddr, caddr);
+	cp->cport	   = cport;
+	ip_vs_addr_copy(af, &cp->vaddr, vaddr);
+	cp->vport	   = vport;
+	ip_vs_addr_copy(af, &cp->daddr, daddr);
+	cp->dport          = dport;
+	cp->flags	   = flags;
+	spin_lock_init(&cp->lock);
+
+	/*
+	 * Set the entry is referenced by the current thread before hashing
+	 * it in the table, so that other thread run ip_vs_random_dropentry
+	 * but cannot drop this entry.
+	 */
+	atomic_set(&cp->refcnt, 1);
+
+	atomic_set(&cp->n_control, 0);
+	atomic_set(&cp->in_pkts, 0);
+
+	atomic_inc(&ip_vs_conn_count);
+	if (flags & IP_VS_CONN_F_NO_CPORT)
+		atomic_inc(&ip_vs_conn_no_cport_cnt);
+
+	/* Bind the connection with a destination server */
+	ip_vs_bind_dest(cp, dest);
+
+	/* Set its state and timeout */
+	cp->state = 0;
+	cp->timeout = 3*HZ;
+
+	/* Bind its packet transmitter */
+#ifdef CONFIG_IP_VS_IPV6
+	if (af == AF_INET6)
+		ip_vs_bind_xmit_v6(cp);
+	else
+#endif
+		ip_vs_bind_xmit(cp);
+
+	if (unlikely(pp && atomic_read(&pp->appcnt)))
+		ip_vs_bind_app(cp, pp);
+
+	/* Hash it in the ip_vs_conn_tab finally */
+	ip_vs_conn_hash(cp);
+
+	return cp;
+}
+
+
+/*
+ *	/proc/net/ip_vs_conn entries
+ */
+#ifdef CONFIG_PROC_FS
+
+static void *ip_vs_conn_array(struct seq_file *seq, loff_t pos)
+{
+	int idx;
+	struct ip_vs_conn *cp;
+
+	for(idx = 0; idx < IP_VS_CONN_TAB_SIZE; idx++) {
+		ct_read_lock_bh(idx);
+		list_for_each_entry(cp, &ip_vs_conn_tab[idx], c_list) {
+			if (pos-- == 0) {
+				seq->private = &ip_vs_conn_tab[idx];
+				return cp;
+			}
+		}
+		ct_read_unlock_bh(idx);
+	}
+
+	return NULL;
+}
+
+static void *ip_vs_conn_seq_start(struct seq_file *seq, loff_t *pos)
+{
+	seq->private = NULL;
+	return *pos ? ip_vs_conn_array(seq, *pos - 1) :SEQ_START_TOKEN;
+}
+
+static void *ip_vs_conn_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+{
+	struct ip_vs_conn *cp = v;
+	struct list_head *e, *l = seq->private;
+	int idx;
+
+	++*pos;
+	if (v == SEQ_START_TOKEN)
+		return ip_vs_conn_array(seq, 0);
+
+	/* more on same hash chain? */
+	if ((e = cp->c_list.next) != l)
+		return list_entry(e, struct ip_vs_conn, c_list);
+
+	idx = l - ip_vs_conn_tab;
+	ct_read_unlock_bh(idx);
+
+	while (++idx < IP_VS_CONN_TAB_SIZE) {
+		ct_read_lock_bh(idx);
+		list_for_each_entry(cp, &ip_vs_conn_tab[idx], c_list) {
+			seq->private = &ip_vs_conn_tab[idx];
+			return cp;
+		}
+		ct_read_unlock_bh(idx);
+	}
+	seq->private = NULL;
+	return NULL;
+}
+
+static void ip_vs_conn_seq_stop(struct seq_file *seq, void *v)
+{
+	struct list_head *l = seq->private;
+
+	if (l)
+		ct_read_unlock_bh(l - ip_vs_conn_tab);
+}
+
+static int ip_vs_conn_seq_show(struct seq_file *seq, void *v)
+{
+
+	if (v == SEQ_START_TOKEN)
+		seq_puts(seq,
+   "Pro FromIP   FPrt ToIP     TPrt DestIP   DPrt State       Expires\n");
+	else {
+		const struct ip_vs_conn *cp = v;
+
+#ifdef CONFIG_IP_VS_IPV6
+		if (cp->af == AF_INET6)
+			seq_printf(seq,
+				"%-3s " NIP6_FMT " %04X " NIP6_FMT
+				" %04X " NIP6_FMT " %04X %-11s %7lu\n",
+				ip_vs_proto_name(cp->protocol),
+				NIP6(cp->caddr.in6), ntohs(cp->cport),
+				NIP6(cp->vaddr.in6), ntohs(cp->vport),
+				NIP6(cp->daddr.in6), ntohs(cp->dport),
+				ip_vs_state_name(cp->protocol, cp->state),
+				(cp->timer.expires-jiffies)/HZ);
+		else
+#endif
+			seq_printf(seq,
+				"%-3s %08X %04X %08X %04X"
+				" %08X %04X %-11s %7lu\n",
+				ip_vs_proto_name(cp->protocol),
+				ntohl(cp->caddr.ip), ntohs(cp->cport),
+				ntohl(cp->vaddr.ip), ntohs(cp->vport),
+				ntohl(cp->daddr.ip), ntohs(cp->dport),
+				ip_vs_state_name(cp->protocol, cp->state),
+				(cp->timer.expires-jiffies)/HZ);
+	}
+	return 0;
+}
+
+static const struct seq_operations ip_vs_conn_seq_ops = {
+	.start = ip_vs_conn_seq_start,
+	.next  = ip_vs_conn_seq_next,
+	.stop  = ip_vs_conn_seq_stop,
+	.show  = ip_vs_conn_seq_show,
+};
+
+static int ip_vs_conn_open(struct inode *inode, struct file *file)
+{
+	return seq_open(file, &ip_vs_conn_seq_ops);
+}
+
+static const struct file_operations ip_vs_conn_fops = {
+	.owner	 = THIS_MODULE,
+	.open    = ip_vs_conn_open,
+	.read    = seq_read,
+	.llseek  = seq_lseek,
+	.release = seq_release,
+};
+
+static const char *ip_vs_origin_name(unsigned flags)
+{
+	if (flags & IP_VS_CONN_F_SYNC)
+		return "SYNC";
+	else
+		return "LOCAL";
+}
+
+static int ip_vs_conn_sync_seq_show(struct seq_file *seq, void *v)
+{
+
+	if (v == SEQ_START_TOKEN)
+		seq_puts(seq,
+   "Pro FromIP   FPrt ToIP     TPrt DestIP   DPrt State       Origin Expires\n");
+	else {
+		const struct ip_vs_conn *cp = v;
+
+#ifdef CONFIG_IP_VS_IPV6
+		if (cp->af == AF_INET6)
+			seq_printf(seq,
+				"%-3s " NIP6_FMT " %04X " NIP6_FMT
+				" %04X " NIP6_FMT " %04X %-11s %-6s %7lu\n",
+				ip_vs_proto_name(cp->protocol),
+				NIP6(cp->caddr.in6), ntohs(cp->cport),
+				NIP6(cp->vaddr.in6), ntohs(cp->vport),
+				NIP6(cp->daddr.in6), ntohs(cp->dport),
+				ip_vs_state_name(cp->protocol, cp->state),
+				ip_vs_origin_name(cp->flags),
+				(cp->timer.expires-jiffies)/HZ);
+		else
+#endif
+			seq_printf(seq,
+				"%-3s %08X %04X %08X %04X "
+				"%08X %04X %-11s %-6s %7lu\n",
+				ip_vs_proto_name(cp->protocol),
+				ntohl(cp->caddr.ip), ntohs(cp->cport),
+				ntohl(cp->vaddr.ip), ntohs(cp->vport),
+				ntohl(cp->daddr.ip), ntohs(cp->dport),
+				ip_vs_state_name(cp->protocol, cp->state),
+				ip_vs_origin_name(cp->flags),
+				(cp->timer.expires-jiffies)/HZ);
+	}
+	return 0;
+}
+
+static const struct seq_operations ip_vs_conn_sync_seq_ops = {
+	.start = ip_vs_conn_seq_start,
+	.next  = ip_vs_conn_seq_next,
+	.stop  = ip_vs_conn_seq_stop,
+	.show  = ip_vs_conn_sync_seq_show,
+};
+
+static int ip_vs_conn_sync_open(struct inode *inode, struct file *file)
+{
+	return seq_open(file, &ip_vs_conn_sync_seq_ops);
+}
+
+static const struct file_operations ip_vs_conn_sync_fops = {
+	.owner	 = THIS_MODULE,
+	.open    = ip_vs_conn_sync_open,
+	.read    = seq_read,
+	.llseek  = seq_lseek,
+	.release = seq_release,
+};
+
+#endif
+
+
+/*
+ *      Randomly drop connection entries before running out of memory
+ */
+static inline int todrop_entry(struct ip_vs_conn *cp)
+{
+	/*
+	 * The drop rate array needs tuning for real environments.
+	 * Called from timer bh only => no locking
+	 */
+	static const char todrop_rate[9] = {0, 1, 2, 3, 4, 5, 6, 7, 8};
+	static char todrop_counter[9] = {0};
+	int i;
+
+	/* if the conn entry hasn't lasted for 60 seconds, don't drop it.
+	   This will leave enough time for normal connection to get
+	   through. */
+	if (time_before(cp->timeout + jiffies, cp->timer.expires + 60*HZ))
+		return 0;
+
+	/* Don't drop the entry if its number of incoming packets is not
+	   located in [0, 8] */
+	i = atomic_read(&cp->in_pkts);
+	if (i > 8 || i < 0) return 0;
+
+	if (!todrop_rate[i]) return 0;
+	if (--todrop_counter[i] > 0) return 0;
+
+	todrop_counter[i] = todrop_rate[i];
+	return 1;
+}
+
+/* Called from keventd and must protect itself from softirqs */
+void ip_vs_random_dropentry(void)
+{
+	int idx;
+	struct ip_vs_conn *cp;
+
+	/*
+	 * Randomly scan 1/32 of the whole table every second
+	 */
+	for (idx = 0; idx < (IP_VS_CONN_TAB_SIZE>>5); idx++) {
+		unsigned hash = net_random() & IP_VS_CONN_TAB_MASK;
+
+		/*
+		 *  Lock is actually needed in this loop.
+		 */
+		ct_write_lock_bh(hash);
+
+		list_for_each_entry(cp, &ip_vs_conn_tab[hash], c_list) {
+			if (cp->flags & IP_VS_CONN_F_TEMPLATE)
+				/* connection template */
+				continue;
+
+			if (cp->protocol == IPPROTO_TCP) {
+				switch(cp->state) {
+				case IP_VS_TCP_S_SYN_RECV:
+				case IP_VS_TCP_S_SYNACK:
+					break;
+
+				case IP_VS_TCP_S_ESTABLISHED:
+					if (todrop_entry(cp))
+						break;
+					continue;
+
+				default:
+					continue;
+				}
+			} else {
+				if (!todrop_entry(cp))
+					continue;
+			}
+
+			IP_VS_DBG(4, "del connection\n");
+			ip_vs_conn_expire_now(cp);
+			if (cp->control) {
+				IP_VS_DBG(4, "del conn template\n");
+				ip_vs_conn_expire_now(cp->control);
+			}
+		}
+		ct_write_unlock_bh(hash);
+	}
+}
+
+
+/*
+ *      Flush all the connection entries in the ip_vs_conn_tab
+ */
+static void ip_vs_conn_flush(void)
+{
+	int idx;
+	struct ip_vs_conn *cp;
+
+  flush_again:
+	for (idx=0; idx<IP_VS_CONN_TAB_SIZE; idx++) {
+		/*
+		 *  Lock is actually needed in this loop.
+		 */
+		ct_write_lock_bh(idx);
+
+		list_for_each_entry(cp, &ip_vs_conn_tab[idx], c_list) {
+
+			IP_VS_DBG(4, "del connection\n");
+			ip_vs_conn_expire_now(cp);
+			if (cp->control) {
+				IP_VS_DBG(4, "del conn template\n");
+				ip_vs_conn_expire_now(cp->control);
+			}
+		}
+		ct_write_unlock_bh(idx);
+	}
+
+	/* the counter may be not NULL, because maybe some conn entries
+	   are run by slow timer handler or unhashed but still referred */
+	if (atomic_read(&ip_vs_conn_count) != 0) {
+		schedule();
+		goto flush_again;
+	}
+}
+
+
+int __init ip_vs_conn_init(void)
+{
+	int idx;
+
+	/*
+	 * Allocate the connection hash table and initialize its list heads
+	 */
+	ip_vs_conn_tab = vmalloc(IP_VS_CONN_TAB_SIZE*sizeof(struct list_head));
+	if (!ip_vs_conn_tab)
+		return -ENOMEM;
+
+	/* Allocate ip_vs_conn slab cache */
+	ip_vs_conn_cachep = kmem_cache_create("ip_vs_conn",
+					      sizeof(struct ip_vs_conn), 0,
+					      SLAB_HWCACHE_ALIGN, NULL);
+	if (!ip_vs_conn_cachep) {
+		vfree(ip_vs_conn_tab);
+		return -ENOMEM;
+	}
+
+	IP_VS_INFO("Connection hash table configured "
+		   "(size=%d, memory=%ldKbytes)\n",
+		   IP_VS_CONN_TAB_SIZE,
+		   (long)(IP_VS_CONN_TAB_SIZE*sizeof(struct list_head))/1024);
+	IP_VS_DBG(0, "Each connection entry needs %Zd bytes at least\n",
+		  sizeof(struct ip_vs_conn));
+
+	for (idx = 0; idx < IP_VS_CONN_TAB_SIZE; idx++) {
+		INIT_LIST_HEAD(&ip_vs_conn_tab[idx]);
+	}
+
+	for (idx = 0; idx < CT_LOCKARRAY_SIZE; idx++)  {
+		rwlock_init(&__ip_vs_conntbl_lock_array[idx].l);
+	}
+
+	proc_net_fops_create(&init_net, "ip_vs_conn", 0, &ip_vs_conn_fops);
+	proc_net_fops_create(&init_net, "ip_vs_conn_sync", 0, &ip_vs_conn_sync_fops);
+
+	/* calculate the random value for connection hash */
+	get_random_bytes(&ip_vs_conn_rnd, sizeof(ip_vs_conn_rnd));
+
+	return 0;
+}
+
+
+void ip_vs_conn_cleanup(void)
+{
+	/* flush all the connection entries first */
+	ip_vs_conn_flush();
+
+	/* Release the empty cache */
+	kmem_cache_destroy(ip_vs_conn_cachep);
+	proc_net_remove(&init_net, "ip_vs_conn");
+	proc_net_remove(&init_net, "ip_vs_conn_sync");
+	vfree(ip_vs_conn_tab);
+}
diff --git a/net/netfilter/ipvs/ip_vs_core.c b/net/netfilter/ipvs/ip_vs_core.c
new file mode 100644
index 0000000..958abf3
--- /dev/null
+++ b/net/netfilter/ipvs/ip_vs_core.c
@@ -0,0 +1,1542 @@
+/*
+ * IPVS         An implementation of the IP virtual server support for the
+ *              LINUX operating system.  IPVS is now implemented as a module
+ *              over the Netfilter framework. IPVS can be used to build a
+ *              high-performance and highly available server based on a
+ *              cluster of servers.
+ *
+ * Authors:     Wensong Zhang <wensong@linuxvirtualserver.org>
+ *              Peter Kese <peter.kese@ijs.si>
+ *              Julian Anastasov <ja@ssi.bg>
+ *
+ *              This program is free software; you can redistribute it and/or
+ *              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.
+ *
+ * The IPVS code for kernel 2.2 was done by Wensong Zhang and Peter Kese,
+ * with changes/fixes from Julian Anastasov, Lars Marowsky-Bree, Horms
+ * and others.
+ *
+ * Changes:
+ *	Paul `Rusty' Russell		properly handle non-linear skbs
+ *	Harald Welte			don't use nfcache
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/ip.h>
+#include <linux/tcp.h>
+#include <linux/icmp.h>
+
+#include <net/ip.h>
+#include <net/tcp.h>
+#include <net/udp.h>
+#include <net/icmp.h>                   /* for icmp_send */
+#include <net/route.h>
+
+#include <linux/netfilter.h>
+#include <linux/netfilter_ipv4.h>
+
+#ifdef CONFIG_IP_VS_IPV6
+#include <net/ipv6.h>
+#include <linux/netfilter_ipv6.h>
+#endif
+
+#include <net/ip_vs.h>
+
+
+EXPORT_SYMBOL(register_ip_vs_scheduler);
+EXPORT_SYMBOL(unregister_ip_vs_scheduler);
+EXPORT_SYMBOL(ip_vs_skb_replace);
+EXPORT_SYMBOL(ip_vs_proto_name);
+EXPORT_SYMBOL(ip_vs_conn_new);
+EXPORT_SYMBOL(ip_vs_conn_in_get);
+EXPORT_SYMBOL(ip_vs_conn_out_get);
+#ifdef CONFIG_IP_VS_PROTO_TCP
+EXPORT_SYMBOL(ip_vs_tcp_conn_listen);
+#endif
+EXPORT_SYMBOL(ip_vs_conn_put);
+#ifdef CONFIG_IP_VS_DEBUG
+EXPORT_SYMBOL(ip_vs_get_debug_level);
+#endif
+
+
+/* ID used in ICMP lookups */
+#define icmp_id(icmph)          (((icmph)->un).echo.id)
+#define icmpv6_id(icmph)        (icmph->icmp6_dataun.u_echo.identifier)
+
+const char *ip_vs_proto_name(unsigned proto)
+{
+	static char buf[20];
+
+	switch (proto) {
+	case IPPROTO_IP:
+		return "IP";
+	case IPPROTO_UDP:
+		return "UDP";
+	case IPPROTO_TCP:
+		return "TCP";
+	case IPPROTO_ICMP:
+		return "ICMP";
+#ifdef CONFIG_IP_VS_IPV6
+	case IPPROTO_ICMPV6:
+		return "ICMPv6";
+#endif
+	default:
+		sprintf(buf, "IP_%d", proto);
+		return buf;
+	}
+}
+
+void ip_vs_init_hash_table(struct list_head *table, int rows)
+{
+	while (--rows >= 0)
+		INIT_LIST_HEAD(&table[rows]);
+}
+
+static inline void
+ip_vs_in_stats(struct ip_vs_conn *cp, struct sk_buff *skb)
+{
+	struct ip_vs_dest *dest = cp->dest;
+	if (dest && (dest->flags & IP_VS_DEST_F_AVAILABLE)) {
+		spin_lock(&dest->stats.lock);
+		dest->stats.ustats.inpkts++;
+		dest->stats.ustats.inbytes += skb->len;
+		spin_unlock(&dest->stats.lock);
+
+		spin_lock(&dest->svc->stats.lock);
+		dest->svc->stats.ustats.inpkts++;
+		dest->svc->stats.ustats.inbytes += skb->len;
+		spin_unlock(&dest->svc->stats.lock);
+
+		spin_lock(&ip_vs_stats.lock);
+		ip_vs_stats.ustats.inpkts++;
+		ip_vs_stats.ustats.inbytes += skb->len;
+		spin_unlock(&ip_vs_stats.lock);
+	}
+}
+
+
+static inline void
+ip_vs_out_stats(struct ip_vs_conn *cp, struct sk_buff *skb)
+{
+	struct ip_vs_dest *dest = cp->dest;
+	if (dest && (dest->flags & IP_VS_DEST_F_AVAILABLE)) {
+		spin_lock(&dest->stats.lock);
+		dest->stats.ustats.outpkts++;
+		dest->stats.ustats.outbytes += skb->len;
+		spin_unlock(&dest->stats.lock);
+
+		spin_lock(&dest->svc->stats.lock);
+		dest->svc->stats.ustats.outpkts++;
+		dest->svc->stats.ustats.outbytes += skb->len;
+		spin_unlock(&dest->svc->stats.lock);
+
+		spin_lock(&ip_vs_stats.lock);
+		ip_vs_stats.ustats.outpkts++;
+		ip_vs_stats.ustats.outbytes += skb->len;
+		spin_unlock(&ip_vs_stats.lock);
+	}
+}
+
+
+static inline void
+ip_vs_conn_stats(struct ip_vs_conn *cp, struct ip_vs_service *svc)
+{
+	spin_lock(&cp->dest->stats.lock);
+	cp->dest->stats.ustats.conns++;
+	spin_unlock(&cp->dest->stats.lock);
+
+	spin_lock(&svc->stats.lock);
+	svc->stats.ustats.conns++;
+	spin_unlock(&svc->stats.lock);
+
+	spin_lock(&ip_vs_stats.lock);
+	ip_vs_stats.ustats.conns++;
+	spin_unlock(&ip_vs_stats.lock);
+}
+
+
+static inline int
+ip_vs_set_state(struct ip_vs_conn *cp, int direction,
+		const struct sk_buff *skb,
+		struct ip_vs_protocol *pp)
+{
+	if (unlikely(!pp->state_transition))
+		return 0;
+	return pp->state_transition(cp, direction, skb, pp);
+}
+
+
+/*
+ *  IPVS persistent scheduling function
+ *  It creates a connection entry according to its template if exists,
+ *  or selects a server and creates a connection entry plus a template.
+ *  Locking: we are svc user (svc->refcnt), so we hold all dests too
+ *  Protocols supported: TCP, UDP
+ */
+static struct ip_vs_conn *
+ip_vs_sched_persist(struct ip_vs_service *svc,
+		    const struct sk_buff *skb,
+		    __be16 ports[2])
+{
+	struct ip_vs_conn *cp = NULL;
+	struct ip_vs_iphdr iph;
+	struct ip_vs_dest *dest;
+	struct ip_vs_conn *ct;
+	__be16  dport;			/* destination port to forward */
+	union nf_inet_addr snet;	/* source network of the client,
+					   after masking */
+
+	ip_vs_fill_iphdr(svc->af, skb_network_header(skb), &iph);
+
+	/* Mask saddr with the netmask to adjust template granularity */
+#ifdef CONFIG_IP_VS_IPV6
+	if (svc->af == AF_INET6)
+		ipv6_addr_prefix(&snet.in6, &iph.saddr.in6, svc->netmask);
+	else
+#endif
+		snet.ip = iph.saddr.ip & svc->netmask;
+
+	IP_VS_DBG_BUF(6, "p-schedule: src %s:%u dest %s:%u "
+		      "mnet %s\n",
+		      IP_VS_DBG_ADDR(svc->af, &iph.saddr), ntohs(ports[0]),
+		      IP_VS_DBG_ADDR(svc->af, &iph.daddr), ntohs(ports[1]),
+		      IP_VS_DBG_ADDR(svc->af, &snet));
+
+	/*
+	 * As far as we know, FTP is a very complicated network protocol, and
+	 * it uses control connection and data connections. For active FTP,
+	 * FTP server initialize data connection to the client, its source port
+	 * is often 20. For passive FTP, FTP server tells the clients the port
+	 * that it passively listens to,  and the client issues the data
+	 * connection. In the tunneling or direct routing mode, the load
+	 * balancer is on the client-to-server half of connection, the port
+	 * number is unknown to the load balancer. So, a conn template like
+	 * <caddr, 0, vaddr, 0, daddr, 0> is created for persistent FTP
+	 * service, and a template like <caddr, 0, vaddr, vport, daddr, dport>
+	 * is created for other persistent services.
+	 */
+	if (ports[1] == svc->port) {
+		/* Check if a template already exists */
+		if (svc->port != FTPPORT)
+			ct = ip_vs_ct_in_get(svc->af, iph.protocol, &snet, 0,
+					     &iph.daddr, ports[1]);
+		else
+			ct = ip_vs_ct_in_get(svc->af, iph.protocol, &snet, 0,
+					     &iph.daddr, 0);
+
+		if (!ct || !ip_vs_check_template(ct)) {
+			/*
+			 * No template found or the dest of the connection
+			 * template is not available.
+			 */
+			dest = svc->scheduler->schedule(svc, skb);
+			if (dest == NULL) {
+				IP_VS_DBG(1, "p-schedule: no dest found.\n");
+				return NULL;
+			}
+
+			/*
+			 * Create a template like <protocol,caddr,0,
+			 * vaddr,vport,daddr,dport> for non-ftp service,
+			 * and <protocol,caddr,0,vaddr,0,daddr,0>
+			 * for ftp service.
+			 */
+			if (svc->port != FTPPORT)
+				ct = ip_vs_conn_new(svc->af, iph.protocol,
+						    &snet, 0,
+						    &iph.daddr,
+						    ports[1],
+						    &dest->addr, dest->port,
+						    IP_VS_CONN_F_TEMPLATE,
+						    dest);
+			else
+				ct = ip_vs_conn_new(svc->af, iph.protocol,
+						    &snet, 0,
+						    &iph.daddr, 0,
+						    &dest->addr, 0,
+						    IP_VS_CONN_F_TEMPLATE,
+						    dest);
+			if (ct == NULL)
+				return NULL;
+
+			ct->timeout = svc->timeout;
+		} else {
+			/* set destination with the found template */
+			dest = ct->dest;
+		}
+		dport = dest->port;
+	} else {
+		/*
+		 * Note: persistent fwmark-based services and persistent
+		 * port zero service are handled here.
+		 * fwmark template: <IPPROTO_IP,caddr,0,fwmark,0,daddr,0>
+		 * port zero template: <protocol,caddr,0,vaddr,0,daddr,0>
+		 */
+		if (svc->fwmark) {
+			union nf_inet_addr fwmark = {
+				.all = { 0, 0, 0, htonl(svc->fwmark) }
+			};
+
+			ct = ip_vs_ct_in_get(svc->af, IPPROTO_IP, &snet, 0,
+					     &fwmark, 0);
+		} else
+			ct = ip_vs_ct_in_get(svc->af, iph.protocol, &snet, 0,
+					     &iph.daddr, 0);
+
+		if (!ct || !ip_vs_check_template(ct)) {
+			/*
+			 * If it is not persistent port zero, return NULL,
+			 * otherwise create a connection template.
+			 */
+			if (svc->port)
+				return NULL;
+
+			dest = svc->scheduler->schedule(svc, skb);
+			if (dest == NULL) {
+				IP_VS_DBG(1, "p-schedule: no dest found.\n");
+				return NULL;
+			}
+
+			/*
+			 * Create a template according to the service
+			 */
+			if (svc->fwmark) {
+				union nf_inet_addr fwmark = {
+					.all = { 0, 0, 0, htonl(svc->fwmark) }
+				};
+
+				ct = ip_vs_conn_new(svc->af, IPPROTO_IP,
+						    &snet, 0,
+						    &fwmark, 0,
+						    &dest->addr, 0,
+						    IP_VS_CONN_F_TEMPLATE,
+						    dest);
+			} else
+				ct = ip_vs_conn_new(svc->af, iph.protocol,
+						    &snet, 0,
+						    &iph.daddr, 0,
+						    &dest->addr, 0,
+						    IP_VS_CONN_F_TEMPLATE,
+						    dest);
+			if (ct == NULL)
+				return NULL;
+
+			ct->timeout = svc->timeout;
+		} else {
+			/* set destination with the found template */
+			dest = ct->dest;
+		}
+		dport = ports[1];
+	}
+
+	/*
+	 *    Create a new connection according to the template
+	 */
+	cp = ip_vs_conn_new(svc->af, iph.protocol,
+			    &iph.saddr, ports[0],
+			    &iph.daddr, ports[1],
+			    &dest->addr, dport,
+			    0,
+			    dest);
+	if (cp == NULL) {
+		ip_vs_conn_put(ct);
+		return NULL;
+	}
+
+	/*
+	 *    Add its control
+	 */
+	ip_vs_control_add(cp, ct);
+	ip_vs_conn_put(ct);
+
+	ip_vs_conn_stats(cp, svc);
+	return cp;
+}
+
+
+/*
+ *  IPVS main scheduling function
+ *  It selects a server according to the virtual service, and
+ *  creates a connection entry.
+ *  Protocols supported: TCP, UDP
+ */
+struct ip_vs_conn *
+ip_vs_schedule(struct ip_vs_service *svc, const struct sk_buff *skb)
+{
+	struct ip_vs_conn *cp = NULL;
+	struct ip_vs_iphdr iph;
+	struct ip_vs_dest *dest;
+	__be16 _ports[2], *pptr;
+
+	ip_vs_fill_iphdr(svc->af, skb_network_header(skb), &iph);
+	pptr = skb_header_pointer(skb, iph.len, sizeof(_ports), _ports);
+	if (pptr == NULL)
+		return NULL;
+
+	/*
+	 *    Persistent service
+	 */
+	if (svc->flags & IP_VS_SVC_F_PERSISTENT)
+		return ip_vs_sched_persist(svc, skb, pptr);
+
+	/*
+	 *    Non-persistent service
+	 */
+	if (!svc->fwmark && pptr[1] != svc->port) {
+		if (!svc->port)
+			IP_VS_ERR("Schedule: port zero only supported "
+				  "in persistent services, "
+				  "check your ipvs configuration\n");
+		return NULL;
+	}
+
+	dest = svc->scheduler->schedule(svc, skb);
+	if (dest == NULL) {
+		IP_VS_DBG(1, "Schedule: no dest found.\n");
+		return NULL;
+	}
+
+	/*
+	 *    Create a connection entry.
+	 */
+	cp = ip_vs_conn_new(svc->af, iph.protocol,
+			    &iph.saddr, pptr[0],
+			    &iph.daddr, pptr[1],
+			    &dest->addr, dest->port ? dest->port : pptr[1],
+			    0,
+			    dest);
+	if (cp == NULL)
+		return NULL;
+
+	IP_VS_DBG_BUF(6, "Schedule fwd:%c c:%s:%u v:%s:%u "
+		      "d:%s:%u conn->flags:%X conn->refcnt:%d\n",
+		      ip_vs_fwd_tag(cp),
+		      IP_VS_DBG_ADDR(svc->af, &cp->caddr), ntohs(cp->cport),
+		      IP_VS_DBG_ADDR(svc->af, &cp->vaddr), ntohs(cp->vport),
+		      IP_VS_DBG_ADDR(svc->af, &cp->daddr), ntohs(cp->dport),
+		      cp->flags, atomic_read(&cp->refcnt));
+
+	ip_vs_conn_stats(cp, svc);
+	return cp;
+}
+
+
+/*
+ *  Pass or drop the packet.
+ *  Called by ip_vs_in, when the virtual service is available but
+ *  no destination is available for a new connection.
+ */
+int ip_vs_leave(struct ip_vs_service *svc, struct sk_buff *skb,
+		struct ip_vs_protocol *pp)
+{
+	__be16 _ports[2], *pptr;
+	struct ip_vs_iphdr iph;
+	int unicast;
+	ip_vs_fill_iphdr(svc->af, skb_network_header(skb), &iph);
+
+	pptr = skb_header_pointer(skb, iph.len, sizeof(_ports), _ports);
+	if (pptr == NULL) {
+		ip_vs_service_put(svc);
+		return NF_DROP;
+	}
+
+#ifdef CONFIG_IP_VS_IPV6
+	if (svc->af == AF_INET6)
+		unicast = ipv6_addr_type(&iph.daddr.in6) & IPV6_ADDR_UNICAST;
+	else
+#endif
+		unicast = (inet_addr_type(&init_net, iph.daddr.ip) == RTN_UNICAST);
+
+	/* if it is fwmark-based service, the cache_bypass sysctl is up
+	   and the destination is a non-local unicast, then create
+	   a cache_bypass connection entry */
+	if (sysctl_ip_vs_cache_bypass && svc->fwmark && unicast) {
+		int ret, cs;
+		struct ip_vs_conn *cp;
+		union nf_inet_addr daddr =  { .all = { 0, 0, 0, 0 } };
+
+		ip_vs_service_put(svc);
+
+		/* create a new connection entry */
+		IP_VS_DBG(6, "ip_vs_leave: create a cache_bypass entry\n");
+		cp = ip_vs_conn_new(svc->af, iph.protocol,
+				    &iph.saddr, pptr[0],
+				    &iph.daddr, pptr[1],
+				    &daddr, 0,
+				    IP_VS_CONN_F_BYPASS,
+				    NULL);
+		if (cp == NULL)
+			return NF_DROP;
+
+		/* statistics */
+		ip_vs_in_stats(cp, skb);
+
+		/* set state */
+		cs = ip_vs_set_state(cp, IP_VS_DIR_INPUT, skb, pp);
+
+		/* transmit the first SYN packet */
+		ret = cp->packet_xmit(skb, cp, pp);
+		/* do not touch skb anymore */
+
+		atomic_inc(&cp->in_pkts);
+		ip_vs_conn_put(cp);
+		return ret;
+	}
+
+	/*
+	 * When the virtual ftp service is presented, packets destined
+	 * for other services on the VIP may get here (except services
+	 * listed in the ipvs table), pass the packets, because it is
+	 * not ipvs job to decide to drop the packets.
+	 */
+	if ((svc->port == FTPPORT) && (pptr[1] != FTPPORT)) {
+		ip_vs_service_put(svc);
+		return NF_ACCEPT;
+	}
+
+	ip_vs_service_put(svc);
+
+	/*
+	 * Notify the client that the destination is unreachable, and
+	 * release the socket buffer.
+	 * Since it is in IP layer, the TCP socket is not actually
+	 * created, the TCP RST packet cannot be sent, instead that
+	 * ICMP_PORT_UNREACH is sent here no matter it is TCP/UDP. --WZ
+	 */
+#ifdef CONFIG_IP_VS_IPV6
+	if (svc->af == AF_INET6)
+		icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_PORT_UNREACH, 0,
+			    skb->dev);
+	else
+#endif
+		icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);
+
+	return NF_DROP;
+}
+
+
+/*
+ *      It is hooked before NF_IP_PRI_NAT_SRC at the NF_INET_POST_ROUTING
+ *      chain, and is used for VS/NAT.
+ *      It detects packets for VS/NAT connections and sends the packets
+ *      immediately. This can avoid that iptable_nat mangles the packets
+ *      for VS/NAT.
+ */
+static unsigned int ip_vs_post_routing(unsigned int hooknum,
+				       struct sk_buff *skb,
+				       const struct net_device *in,
+				       const struct net_device *out,
+				       int (*okfn)(struct sk_buff *))
+{
+	if (!skb->ipvs_property)
+		return NF_ACCEPT;
+	/* The packet was sent from IPVS, exit this chain */
+	return NF_STOP;
+}
+
+__sum16 ip_vs_checksum_complete(struct sk_buff *skb, int offset)
+{
+	return csum_fold(skb_checksum(skb, offset, skb->len - offset, 0));
+}
+
+static inline int ip_vs_gather_frags(struct sk_buff *skb, u_int32_t user)
+{
+	int err = ip_defrag(skb, user);
+
+	if (!err)
+		ip_send_check(ip_hdr(skb));
+
+	return err;
+}
+
+#ifdef CONFIG_IP_VS_IPV6
+static inline int ip_vs_gather_frags_v6(struct sk_buff *skb, u_int32_t user)
+{
+	/* TODO IPv6: Find out what to do here for IPv6 */
+	return 0;
+}
+#endif
+
+/*
+ * Packet has been made sufficiently writable in caller
+ * - inout: 1=in->out, 0=out->in
+ */
+void ip_vs_nat_icmp(struct sk_buff *skb, struct ip_vs_protocol *pp,
+		    struct ip_vs_conn *cp, int inout)
+{
+	struct iphdr *iph	 = ip_hdr(skb);
+	unsigned int icmp_offset = iph->ihl*4;
+	struct icmphdr *icmph	 = (struct icmphdr *)(skb_network_header(skb) +
+						      icmp_offset);
+	struct iphdr *ciph	 = (struct iphdr *)(icmph + 1);
+
+	if (inout) {
+		iph->saddr = cp->vaddr.ip;
+		ip_send_check(iph);
+		ciph->daddr = cp->vaddr.ip;
+		ip_send_check(ciph);
+	} else {
+		iph->daddr = cp->daddr.ip;
+		ip_send_check(iph);
+		ciph->saddr = cp->daddr.ip;
+		ip_send_check(ciph);
+	}
+
+	/* the TCP/UDP port */
+	if (IPPROTO_TCP == ciph->protocol || IPPROTO_UDP == ciph->protocol) {
+		__be16 *ports = (void *)ciph + ciph->ihl*4;
+
+		if (inout)
+			ports[1] = cp->vport;
+		else
+			ports[0] = cp->dport;
+	}
+
+	/* And finally the ICMP checksum */
+	icmph->checksum = 0;
+	icmph->checksum = ip_vs_checksum_complete(skb, icmp_offset);
+	skb->ip_summed = CHECKSUM_UNNECESSARY;
+
+	if (inout)
+		IP_VS_DBG_PKT(11, pp, skb, (void *)ciph - (void *)iph,
+			"Forwarding altered outgoing ICMP");
+	else
+		IP_VS_DBG_PKT(11, pp, skb, (void *)ciph - (void *)iph,
+			"Forwarding altered incoming ICMP");
+}
+
+#ifdef CONFIG_IP_VS_IPV6
+void ip_vs_nat_icmp_v6(struct sk_buff *skb, struct ip_vs_protocol *pp,
+		    struct ip_vs_conn *cp, int inout)
+{
+	struct ipv6hdr *iph	 = ipv6_hdr(skb);
+	unsigned int icmp_offset = sizeof(struct ipv6hdr);
+	struct icmp6hdr *icmph	 = (struct icmp6hdr *)(skb_network_header(skb) +
+						      icmp_offset);
+	struct ipv6hdr *ciph	 = (struct ipv6hdr *)(icmph + 1);
+
+	if (inout) {
+		iph->saddr = cp->vaddr.in6;
+		ciph->daddr = cp->vaddr.in6;
+	} else {
+		iph->daddr = cp->daddr.in6;
+		ciph->saddr = cp->daddr.in6;
+	}
+
+	/* the TCP/UDP port */
+	if (IPPROTO_TCP == ciph->nexthdr || IPPROTO_UDP == ciph->nexthdr) {
+		__be16 *ports = (void *)ciph + sizeof(struct ipv6hdr);
+
+		if (inout)
+			ports[1] = cp->vport;
+		else
+			ports[0] = cp->dport;
+	}
+
+	/* And finally the ICMP checksum */
+	icmph->icmp6_cksum = 0;
+	/* TODO IPv6: is this correct for ICMPv6? */
+	ip_vs_checksum_complete(skb, icmp_offset);
+	skb->ip_summed = CHECKSUM_UNNECESSARY;
+
+	if (inout)
+		IP_VS_DBG_PKT(11, pp, skb, (void *)ciph - (void *)iph,
+			"Forwarding altered outgoing ICMPv6");
+	else
+		IP_VS_DBG_PKT(11, pp, skb, (void *)ciph - (void *)iph,
+			"Forwarding altered incoming ICMPv6");
+}
+#endif
+
+/* Handle relevant response ICMP messages - forward to the right
+ * destination host. Used for NAT and local client.
+ */
+static int handle_response_icmp(int af, struct sk_buff *skb,
+				union nf_inet_addr *snet,
+				__u8 protocol, struct ip_vs_conn *cp,
+				struct ip_vs_protocol *pp,
+				unsigned int offset, unsigned int ihl)
+{
+	unsigned int verdict = NF_DROP;
+
+	if (IP_VS_FWD_METHOD(cp) != 0) {
+		IP_VS_ERR("shouldn't reach here, because the box is on the "
+			  "half connection in the tun/dr module.\n");
+	}
+
+	/* Ensure the checksum is correct */
+	if (!skb_csum_unnecessary(skb) && ip_vs_checksum_complete(skb, ihl)) {
+		/* Failed checksum! */
+		IP_VS_DBG_BUF(1, "Forward ICMP: failed checksum from %s!\n",
+			      IP_VS_DBG_ADDR(af, snet));
+		goto out;
+	}
+
+	if (IPPROTO_TCP == protocol || IPPROTO_UDP == protocol)
+		offset += 2 * sizeof(__u16);
+	if (!skb_make_writable(skb, offset))
+		goto out;
+
+#ifdef CONFIG_IP_VS_IPV6
+	if (af == AF_INET6)
+		ip_vs_nat_icmp_v6(skb, pp, cp, 1);
+	else
+#endif
+		ip_vs_nat_icmp(skb, pp, cp, 1);
+
+	/* do the statistics and put it back */
+	ip_vs_out_stats(cp, skb);
+
+	skb->ipvs_property = 1;
+	verdict = NF_ACCEPT;
+
+out:
+	__ip_vs_conn_put(cp);
+
+	return verdict;
+}
+
+/*
+ *	Handle ICMP messages in the inside-to-outside direction (outgoing).
+ *	Find any that might be relevant, check against existing connections.
+ *	Currently handles error types - unreachable, quench, ttl exceeded.
+ */
+static int ip_vs_out_icmp(struct sk_buff *skb, int *related)
+{
+	struct iphdr *iph;
+	struct icmphdr	_icmph, *ic;
+	struct iphdr	_ciph, *cih;	/* The ip header contained within the ICMP */
+	struct ip_vs_iphdr ciph;
+	struct ip_vs_conn *cp;
+	struct ip_vs_protocol *pp;
+	unsigned int offset, ihl;
+	union nf_inet_addr snet;
+
+	*related = 1;
+
+	/* reassemble IP fragments */
+	if (ip_hdr(skb)->frag_off & htons(IP_MF | IP_OFFSET)) {
+		if (ip_vs_gather_frags(skb, IP_DEFRAG_VS_OUT))
+			return NF_STOLEN;
+	}
+
+	iph = ip_hdr(skb);
+	offset = ihl = iph->ihl * 4;
+	ic = skb_header_pointer(skb, offset, sizeof(_icmph), &_icmph);
+	if (ic == NULL)
+		return NF_DROP;
+
+	IP_VS_DBG(12, "Outgoing ICMP (%d,%d) %u.%u.%u.%u->%u.%u.%u.%u\n",
+		  ic->type, ntohs(icmp_id(ic)),
+		  NIPQUAD(iph->saddr), NIPQUAD(iph->daddr));
+
+	/*
+	 * Work through seeing if this is for us.
+	 * These checks are supposed to be in an order that means easy
+	 * things are checked first to speed up processing.... however
+	 * this means that some packets will manage to get a long way
+	 * down this stack and then be rejected, but that's life.
+	 */
+	if ((ic->type != ICMP_DEST_UNREACH) &&
+	    (ic->type != ICMP_SOURCE_QUENCH) &&
+	    (ic->type != ICMP_TIME_EXCEEDED)) {
+		*related = 0;
+		return NF_ACCEPT;
+	}
+
+	/* Now find the contained IP header */
+	offset += sizeof(_icmph);
+	cih = skb_header_pointer(skb, offset, sizeof(_ciph), &_ciph);
+	if (cih == NULL)
+		return NF_ACCEPT; /* The packet looks wrong, ignore */
+
+	pp = ip_vs_proto_get(cih->protocol);
+	if (!pp)
+		return NF_ACCEPT;
+
+	/* Is the embedded protocol header present? */
+	if (unlikely(cih->frag_off & htons(IP_OFFSET) &&
+		     pp->dont_defrag))
+		return NF_ACCEPT;
+
+	IP_VS_DBG_PKT(11, pp, skb, offset, "Checking outgoing ICMP for");
+
+	offset += cih->ihl * 4;
+
+	ip_vs_fill_iphdr(AF_INET, cih, &ciph);
+	/* The embedded headers contain source and dest in reverse order */
+	cp = pp->conn_out_get(AF_INET, skb, pp, &ciph, offset, 1);
+	if (!cp)
+		return NF_ACCEPT;
+
+	snet.ip = iph->saddr;
+	return handle_response_icmp(AF_INET, skb, &snet, cih->protocol, cp,
+				    pp, offset, ihl);
+}
+
+#ifdef CONFIG_IP_VS_IPV6
+static int ip_vs_out_icmp_v6(struct sk_buff *skb, int *related)
+{
+	struct ipv6hdr *iph;
+	struct icmp6hdr	_icmph, *ic;
+	struct ipv6hdr	_ciph, *cih;	/* The ip header contained
+					   within the ICMP */
+	struct ip_vs_iphdr ciph;
+	struct ip_vs_conn *cp;
+	struct ip_vs_protocol *pp;
+	unsigned int offset;
+	union nf_inet_addr snet;
+
+	*related = 1;
+
+	/* reassemble IP fragments */
+	if (ipv6_hdr(skb)->nexthdr == IPPROTO_FRAGMENT) {
+		if (ip_vs_gather_frags_v6(skb, IP_DEFRAG_VS_OUT))
+			return NF_STOLEN;
+	}
+
+	iph = ipv6_hdr(skb);
+	offset = sizeof(struct ipv6hdr);
+	ic = skb_header_pointer(skb, offset, sizeof(_icmph), &_icmph);
+	if (ic == NULL)
+		return NF_DROP;
+
+	IP_VS_DBG(12, "Outgoing ICMPv6 (%d,%d) " NIP6_FMT "->" NIP6_FMT "\n",
+		  ic->icmp6_type, ntohs(icmpv6_id(ic)),
+		  NIP6(iph->saddr), NIP6(iph->daddr));
+
+	/*
+	 * Work through seeing if this is for us.
+	 * These checks are supposed to be in an order that means easy
+	 * things are checked first to speed up processing.... however
+	 * this means that some packets will manage to get a long way
+	 * down this stack and then be rejected, but that's life.
+	 */
+	if ((ic->icmp6_type != ICMPV6_DEST_UNREACH) &&
+	    (ic->icmp6_type != ICMPV6_PKT_TOOBIG) &&
+	    (ic->icmp6_type != ICMPV6_TIME_EXCEED)) {
+		*related = 0;
+		return NF_ACCEPT;
+	}
+
+	/* Now find the contained IP header */
+	offset += sizeof(_icmph);
+	cih = skb_header_pointer(skb, offset, sizeof(_ciph), &_ciph);
+	if (cih == NULL)
+		return NF_ACCEPT; /* The packet looks wrong, ignore */
+
+	pp = ip_vs_proto_get(cih->nexthdr);
+	if (!pp)
+		return NF_ACCEPT;
+
+	/* Is the embedded protocol header present? */
+	/* TODO: we don't support fragmentation at the moment anyways */
+	if (unlikely(cih->nexthdr == IPPROTO_FRAGMENT && pp->dont_defrag))
+		return NF_ACCEPT;
+
+	IP_VS_DBG_PKT(11, pp, skb, offset, "Checking outgoing ICMPv6 for");
+
+	offset += sizeof(struct ipv6hdr);
+
+	ip_vs_fill_iphdr(AF_INET6, cih, &ciph);
+	/* The embedded headers contain source and dest in reverse order */
+	cp = pp->conn_out_get(AF_INET6, skb, pp, &ciph, offset, 1);
+	if (!cp)
+		return NF_ACCEPT;
+
+	ipv6_addr_copy(&snet.in6, &iph->saddr);
+	return handle_response_icmp(AF_INET6, skb, &snet, cih->nexthdr, cp,
+				    pp, offset, sizeof(struct ipv6hdr));
+}
+#endif
+
+static inline int is_tcp_reset(const struct sk_buff *skb, int nh_len)
+{
+	struct tcphdr _tcph, *th;
+
+	th = skb_header_pointer(skb, nh_len, sizeof(_tcph), &_tcph);
+	if (th == NULL)
+		return 0;
+	return th->rst;
+}
+
+/* Handle response packets: rewrite addresses and send away...
+ * Used for NAT and local client.
+ */
+static unsigned int
+handle_response(int af, struct sk_buff *skb, struct ip_vs_protocol *pp,
+		struct ip_vs_conn *cp, int ihl)
+{
+	IP_VS_DBG_PKT(11, pp, skb, 0, "Outgoing packet");
+
+	if (!skb_make_writable(skb, ihl))
+		goto drop;
+
+	/* mangle the packet */
+	if (pp->snat_handler && !pp->snat_handler(skb, pp, cp))
+		goto drop;
+
+#ifdef CONFIG_IP_VS_IPV6
+	if (af == AF_INET6)
+		ipv6_hdr(skb)->saddr = cp->vaddr.in6;
+	else
+#endif
+	{
+		ip_hdr(skb)->saddr = cp->vaddr.ip;
+		ip_send_check(ip_hdr(skb));
+	}
+
+	/* 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.
+	 */
+#ifdef CONFIG_IP_VS_IPV6
+	if (af == AF_INET6) {
+		if (ip6_route_me_harder(skb) != 0)
+			goto drop;
+	} else
+#endif
+		if (ip_route_me_harder(skb, RTN_LOCAL) != 0)
+			goto drop;
+
+	IP_VS_DBG_PKT(10, pp, skb, 0, "After SNAT");
+
+	ip_vs_out_stats(cp, skb);
+	ip_vs_set_state(cp, IP_VS_DIR_OUTPUT, skb, pp);
+	ip_vs_conn_put(cp);
+
+	skb->ipvs_property = 1;
+
+	LeaveFunction(11);
+	return NF_ACCEPT;
+
+drop:
+	ip_vs_conn_put(cp);
+	kfree_skb(skb);
+	return NF_STOLEN;
+}
+
+/*
+ *	It is hooked at the NF_INET_FORWARD chain, used only for VS/NAT.
+ *	Check if outgoing packet belongs to the established ip_vs_conn.
+ */
+static unsigned int
+ip_vs_out(unsigned int hooknum, struct sk_buff *skb,
+	  const struct net_device *in, const struct net_device *out,
+	  int (*okfn)(struct sk_buff *))
+{
+	struct ip_vs_iphdr iph;
+	struct ip_vs_protocol *pp;
+	struct ip_vs_conn *cp;
+	int af;
+
+	EnterFunction(11);
+
+	af = (skb->protocol == htons(ETH_P_IP)) ? AF_INET : AF_INET6;
+
+	if (skb->ipvs_property)
+		return NF_ACCEPT;
+
+	ip_vs_fill_iphdr(af, skb_network_header(skb), &iph);
+#ifdef CONFIG_IP_VS_IPV6
+	if (af == AF_INET6) {
+		if (unlikely(iph.protocol == IPPROTO_ICMPV6)) {
+			int related, verdict = ip_vs_out_icmp_v6(skb, &related);
+
+			if (related)
+				return verdict;
+			ip_vs_fill_iphdr(af, skb_network_header(skb), &iph);
+		}
+	} else
+#endif
+		if (unlikely(iph.protocol == IPPROTO_ICMP)) {
+			int related, verdict = ip_vs_out_icmp(skb, &related);
+
+			if (related)
+				return verdict;
+			ip_vs_fill_iphdr(af, skb_network_header(skb), &iph);
+		}
+
+	pp = ip_vs_proto_get(iph.protocol);
+	if (unlikely(!pp))
+		return NF_ACCEPT;
+
+	/* reassemble IP fragments */
+#ifdef CONFIG_IP_VS_IPV6
+	if (af == AF_INET6) {
+		if (unlikely(iph.protocol == IPPROTO_ICMPV6)) {
+			int related, verdict = ip_vs_out_icmp_v6(skb, &related);
+
+			if (related)
+				return verdict;
+
+			ip_vs_fill_iphdr(af, skb_network_header(skb), &iph);
+		}
+	} else
+#endif
+		if (unlikely(ip_hdr(skb)->frag_off & htons(IP_MF|IP_OFFSET) &&
+			     !pp->dont_defrag)) {
+			if (ip_vs_gather_frags(skb, IP_DEFRAG_VS_OUT))
+				return NF_STOLEN;
+
+			ip_vs_fill_iphdr(af, skb_network_header(skb), &iph);
+		}
+
+	/*
+	 * Check if the packet belongs to an existing entry
+	 */
+	cp = pp->conn_out_get(af, skb, pp, &iph, iph.len, 0);
+
+	if (unlikely(!cp)) {
+		if (sysctl_ip_vs_nat_icmp_send &&
+		    (pp->protocol == IPPROTO_TCP ||
+		     pp->protocol == IPPROTO_UDP)) {
+			__be16 _ports[2], *pptr;
+
+			pptr = skb_header_pointer(skb, iph.len,
+						  sizeof(_ports), _ports);
+			if (pptr == NULL)
+				return NF_ACCEPT;	/* Not for me */
+			if (ip_vs_lookup_real_service(af, iph.protocol,
+						      &iph.saddr,
+						      pptr[0])) {
+				/*
+				 * Notify the real server: there is no
+				 * existing entry if it is not RST
+				 * packet or not TCP packet.
+				 */
+				if (iph.protocol != IPPROTO_TCP
+				    || !is_tcp_reset(skb, iph.len)) {
+#ifdef CONFIG_IP_VS_IPV6
+					if (af == AF_INET6)
+						icmpv6_send(skb,
+							    ICMPV6_DEST_UNREACH,
+							    ICMPV6_PORT_UNREACH,
+							    0, skb->dev);
+					else
+#endif
+						icmp_send(skb,
+							  ICMP_DEST_UNREACH,
+							  ICMP_PORT_UNREACH, 0);
+					return NF_DROP;
+				}
+			}
+		}
+		IP_VS_DBG_PKT(12, pp, skb, 0,
+			      "packet continues traversal as normal");
+		return NF_ACCEPT;
+	}
+
+	return handle_response(af, skb, pp, cp, iph.len);
+}
+
+
+/*
+ *	Handle ICMP messages in the outside-to-inside direction (incoming).
+ *	Find any that might be relevant, check against existing connections,
+ *	forward to the right destination host if relevant.
+ *	Currently handles error types - unreachable, quench, ttl exceeded.
+ */
+static int
+ip_vs_in_icmp(struct sk_buff *skb, int *related, unsigned int hooknum)
+{
+	struct iphdr *iph;
+	struct icmphdr	_icmph, *ic;
+	struct iphdr	_ciph, *cih;	/* The ip header contained within the ICMP */
+	struct ip_vs_iphdr ciph;
+	struct ip_vs_conn *cp;
+	struct ip_vs_protocol *pp;
+	unsigned int offset, ihl, verdict;
+	union nf_inet_addr snet;
+
+	*related = 1;
+
+	/* reassemble IP fragments */
+	if (ip_hdr(skb)->frag_off & htons(IP_MF | IP_OFFSET)) {
+		if (ip_vs_gather_frags(skb, hooknum == NF_INET_LOCAL_IN ?
+					    IP_DEFRAG_VS_IN : IP_DEFRAG_VS_FWD))
+			return NF_STOLEN;
+	}
+
+	iph = ip_hdr(skb);
+	offset = ihl = iph->ihl * 4;
+	ic = skb_header_pointer(skb, offset, sizeof(_icmph), &_icmph);
+	if (ic == NULL)
+		return NF_DROP;
+
+	IP_VS_DBG(12, "Incoming ICMP (%d,%d) %u.%u.%u.%u->%u.%u.%u.%u\n",
+		  ic->type, ntohs(icmp_id(ic)),
+		  NIPQUAD(iph->saddr), NIPQUAD(iph->daddr));
+
+	/*
+	 * Work through seeing if this is for us.
+	 * These checks are supposed to be in an order that means easy
+	 * things are checked first to speed up processing.... however
+	 * this means that some packets will manage to get a long way
+	 * down this stack and then be rejected, but that's life.
+	 */
+	if ((ic->type != ICMP_DEST_UNREACH) &&
+	    (ic->type != ICMP_SOURCE_QUENCH) &&
+	    (ic->type != ICMP_TIME_EXCEEDED)) {
+		*related = 0;
+		return NF_ACCEPT;
+	}
+
+	/* Now find the contained IP header */
+	offset += sizeof(_icmph);
+	cih = skb_header_pointer(skb, offset, sizeof(_ciph), &_ciph);
+	if (cih == NULL)
+		return NF_ACCEPT; /* The packet looks wrong, ignore */
+
+	pp = ip_vs_proto_get(cih->protocol);
+	if (!pp)
+		return NF_ACCEPT;
+
+	/* Is the embedded protocol header present? */
+	if (unlikely(cih->frag_off & htons(IP_OFFSET) &&
+		     pp->dont_defrag))
+		return NF_ACCEPT;
+
+	IP_VS_DBG_PKT(11, pp, skb, offset, "Checking incoming ICMP for");
+
+	offset += cih->ihl * 4;
+
+	ip_vs_fill_iphdr(AF_INET, cih, &ciph);
+	/* The embedded headers contain source and dest in reverse order */
+	cp = pp->conn_in_get(AF_INET, skb, pp, &ciph, offset, 1);
+	if (!cp) {
+		/* The packet could also belong to a local client */
+		cp = pp->conn_out_get(AF_INET, skb, pp, &ciph, offset, 1);
+		if (cp) {
+			snet.ip = iph->saddr;
+			return handle_response_icmp(AF_INET, skb, &snet,
+						    cih->protocol, cp, pp,
+						    offset, ihl);
+		}
+		return NF_ACCEPT;
+	}
+
+	verdict = NF_DROP;
+
+	/* Ensure the checksum is correct */
+	if (!skb_csum_unnecessary(skb) && ip_vs_checksum_complete(skb, ihl)) {
+		/* Failed checksum! */
+		IP_VS_DBG(1, "Incoming ICMP: failed checksum from %d.%d.%d.%d!\n",
+			  NIPQUAD(iph->saddr));
+		goto out;
+	}
+
+	/* do the statistics and put it back */
+	ip_vs_in_stats(cp, skb);
+	if (IPPROTO_TCP == cih->protocol || IPPROTO_UDP == cih->protocol)
+		offset += 2 * sizeof(__u16);
+	verdict = ip_vs_icmp_xmit(skb, cp, pp, offset);
+	/* do not touch skb anymore */
+
+  out:
+	__ip_vs_conn_put(cp);
+
+	return verdict;
+}
+
+#ifdef CONFIG_IP_VS_IPV6
+static int
+ip_vs_in_icmp_v6(struct sk_buff *skb, int *related, unsigned int hooknum)
+{
+	struct ipv6hdr *iph;
+	struct icmp6hdr	_icmph, *ic;
+	struct ipv6hdr	_ciph, *cih;	/* The ip header contained
+					   within the ICMP */
+	struct ip_vs_iphdr ciph;
+	struct ip_vs_conn *cp;
+	struct ip_vs_protocol *pp;
+	unsigned int offset, verdict;
+	union nf_inet_addr snet;
+
+	*related = 1;
+
+	/* reassemble IP fragments */
+	if (ipv6_hdr(skb)->nexthdr == IPPROTO_FRAGMENT) {
+		if (ip_vs_gather_frags_v6(skb, hooknum == NF_INET_LOCAL_IN ?
+					       IP_DEFRAG_VS_IN :
+					       IP_DEFRAG_VS_FWD))
+			return NF_STOLEN;
+	}
+
+	iph = ipv6_hdr(skb);
+	offset = sizeof(struct ipv6hdr);
+	ic = skb_header_pointer(skb, offset, sizeof(_icmph), &_icmph);
+	if (ic == NULL)
+		return NF_DROP;
+
+	IP_VS_DBG(12, "Incoming ICMPv6 (%d,%d) " NIP6_FMT "->" NIP6_FMT "\n",
+		  ic->icmp6_type, ntohs(icmpv6_id(ic)),
+		  NIP6(iph->saddr), NIP6(iph->daddr));
+
+	/*
+	 * Work through seeing if this is for us.
+	 * These checks are supposed to be in an order that means easy
+	 * things are checked first to speed up processing.... however
+	 * this means that some packets will manage to get a long way
+	 * down this stack and then be rejected, but that's life.
+	 */
+	if ((ic->icmp6_type != ICMPV6_DEST_UNREACH) &&
+	    (ic->icmp6_type != ICMPV6_PKT_TOOBIG) &&
+	    (ic->icmp6_type != ICMPV6_TIME_EXCEED)) {
+		*related = 0;
+		return NF_ACCEPT;
+	}
+
+	/* Now find the contained IP header */
+	offset += sizeof(_icmph);
+	cih = skb_header_pointer(skb, offset, sizeof(_ciph), &_ciph);
+	if (cih == NULL)
+		return NF_ACCEPT; /* The packet looks wrong, ignore */
+
+	pp = ip_vs_proto_get(cih->nexthdr);
+	if (!pp)
+		return NF_ACCEPT;
+
+	/* Is the embedded protocol header present? */
+	/* TODO: we don't support fragmentation at the moment anyways */
+	if (unlikely(cih->nexthdr == IPPROTO_FRAGMENT && pp->dont_defrag))
+		return NF_ACCEPT;
+
+	IP_VS_DBG_PKT(11, pp, skb, offset, "Checking incoming ICMPv6 for");
+
+	offset += sizeof(struct ipv6hdr);
+
+	ip_vs_fill_iphdr(AF_INET6, cih, &ciph);
+	/* The embedded headers contain source and dest in reverse order */
+	cp = pp->conn_in_get(AF_INET6, skb, pp, &ciph, offset, 1);
+	if (!cp) {
+		/* The packet could also belong to a local client */
+		cp = pp->conn_out_get(AF_INET6, skb, pp, &ciph, offset, 1);
+		if (cp) {
+			ipv6_addr_copy(&snet.in6, &iph->saddr);
+			return handle_response_icmp(AF_INET6, skb, &snet,
+						    cih->nexthdr,
+						    cp, pp, offset,
+						    sizeof(struct ipv6hdr));
+		}
+		return NF_ACCEPT;
+	}
+
+	verdict = NF_DROP;
+
+	/* do the statistics and put it back */
+	ip_vs_in_stats(cp, skb);
+	if (IPPROTO_TCP == cih->nexthdr || IPPROTO_UDP == cih->nexthdr)
+		offset += 2 * sizeof(__u16);
+	verdict = ip_vs_icmp_xmit_v6(skb, cp, pp, offset);
+	/* do not touch skb anymore */
+
+	__ip_vs_conn_put(cp);
+
+	return verdict;
+}
+#endif
+
+
+/*
+ *	Check if it's for virtual services, look it up,
+ *	and send it on its way...
+ */
+static unsigned int
+ip_vs_in(unsigned int hooknum, struct sk_buff *skb,
+	 const struct net_device *in, const struct net_device *out,
+	 int (*okfn)(struct sk_buff *))
+{
+	struct ip_vs_iphdr iph;
+	struct ip_vs_protocol *pp;
+	struct ip_vs_conn *cp;
+	int ret, restart, af;
+
+	af = (skb->protocol == htons(ETH_P_IP)) ? AF_INET : AF_INET6;
+
+	ip_vs_fill_iphdr(af, skb_network_header(skb), &iph);
+
+	/*
+	 *	Big tappo: only PACKET_HOST, including loopback for local client
+	 *	Don't handle local packets on IPv6 for now
+	 */
+	if (unlikely(skb->pkt_type != PACKET_HOST)) {
+		IP_VS_DBG_BUF(12, "packet type=%d proto=%d daddr=%s ignored\n",
+			      skb->pkt_type,
+			      iph.protocol,
+			      IP_VS_DBG_ADDR(af, &iph.daddr));
+		return NF_ACCEPT;
+	}
+
+	if (unlikely(iph.protocol == IPPROTO_ICMP)) {
+		int related, verdict = ip_vs_in_icmp(skb, &related, hooknum);
+
+		if (related)
+			return verdict;
+		ip_vs_fill_iphdr(af, skb_network_header(skb), &iph);
+	}
+
+	/* Protocol supported? */
+	pp = ip_vs_proto_get(iph.protocol);
+	if (unlikely(!pp))
+		return NF_ACCEPT;
+
+	/*
+	 * Check if the packet belongs to an existing connection entry
+	 */
+	cp = pp->conn_in_get(af, skb, pp, &iph, iph.len, 0);
+
+	if (unlikely(!cp)) {
+		int v;
+
+		/* For local client packets, it could be a response */
+		cp = pp->conn_out_get(af, skb, pp, &iph, iph.len, 0);
+		if (cp)
+			return handle_response(af, skb, pp, cp, iph.len);
+
+		if (!pp->conn_schedule(af, skb, pp, &v, &cp))
+			return v;
+	}
+
+	if (unlikely(!cp)) {
+		/* sorry, all this trouble for a no-hit :) */
+		IP_VS_DBG_PKT(12, pp, skb, 0,
+			      "packet continues traversal as normal");
+		return NF_ACCEPT;
+	}
+
+	IP_VS_DBG_PKT(11, pp, skb, 0, "Incoming packet");
+
+	/* Check the server status */
+	if (cp->dest && !(cp->dest->flags & IP_VS_DEST_F_AVAILABLE)) {
+		/* the destination server is not available */
+
+		if (sysctl_ip_vs_expire_nodest_conn) {
+			/* try to expire the connection immediately */
+			ip_vs_conn_expire_now(cp);
+		}
+		/* don't restart its timer, and silently
+		   drop the packet. */
+		__ip_vs_conn_put(cp);
+		return NF_DROP;
+	}
+
+	ip_vs_in_stats(cp, skb);
+	restart = ip_vs_set_state(cp, IP_VS_DIR_INPUT, skb, pp);
+	if (cp->packet_xmit)
+		ret = cp->packet_xmit(skb, cp, pp);
+		/* do not touch skb anymore */
+	else {
+		IP_VS_DBG_RL("warning: packet_xmit is null");
+		ret = NF_ACCEPT;
+	}
+
+	/* Increase its packet counter and check if it is needed
+	 * to be synchronized
+	 *
+	 * Sync connection if it is about to close to
+	 * encorage the standby servers to update the connections timeout
+	 */
+	atomic_inc(&cp->in_pkts);
+	if (af == AF_INET &&
+	    (ip_vs_sync_state & IP_VS_STATE_MASTER) &&
+	    (((cp->protocol != IPPROTO_TCP ||
+	       cp->state == IP_VS_TCP_S_ESTABLISHED) &&
+	      (atomic_read(&cp->in_pkts) % sysctl_ip_vs_sync_threshold[1]
+	       == sysctl_ip_vs_sync_threshold[0])) ||
+	     ((cp->protocol == IPPROTO_TCP) && (cp->old_state != cp->state) &&
+	      ((cp->state == IP_VS_TCP_S_FIN_WAIT) ||
+	       (cp->state == IP_VS_TCP_S_CLOSE_WAIT) ||
+	       (cp->state == IP_VS_TCP_S_TIME_WAIT)))))
+		ip_vs_sync_conn(cp);
+	cp->old_state = cp->state;
+
+	ip_vs_conn_put(cp);
+	return ret;
+}
+
+
+/*
+ *	It is hooked at the NF_INET_FORWARD chain, in order to catch ICMP
+ *      related packets destined for 0.0.0.0/0.
+ *      When fwmark-based virtual service is used, such as transparent
+ *      cache cluster, TCP packets can be marked and routed to ip_vs_in,
+ *      but ICMP destined for 0.0.0.0/0 cannot not be easily marked and
+ *      sent to ip_vs_in_icmp. So, catch them at the NF_INET_FORWARD chain
+ *      and send them to ip_vs_in_icmp.
+ */
+static unsigned int
+ip_vs_forward_icmp(unsigned int hooknum, struct sk_buff *skb,
+		   const struct net_device *in, const struct net_device *out,
+		   int (*okfn)(struct sk_buff *))
+{
+	int r;
+
+	if (ip_hdr(skb)->protocol != IPPROTO_ICMP)
+		return NF_ACCEPT;
+
+	return ip_vs_in_icmp(skb, &r, hooknum);
+}
+
+#ifdef CONFIG_IP_VS_IPV6
+static unsigned int
+ip_vs_forward_icmp_v6(unsigned int hooknum, struct sk_buff *skb,
+		      const struct net_device *in, const struct net_device *out,
+		      int (*okfn)(struct sk_buff *))
+{
+	int r;
+
+	if (ipv6_hdr(skb)->nexthdr != IPPROTO_ICMPV6)
+		return NF_ACCEPT;
+
+	return ip_vs_in_icmp_v6(skb, &r, hooknum);
+}
+#endif
+
+
+static struct nf_hook_ops ip_vs_ops[] __read_mostly = {
+	/* After packet filtering, forward packet through VS/DR, VS/TUN,
+	 * or VS/NAT(change destination), so that filtering rules can be
+	 * applied to IPVS. */
+	{
+		.hook		= ip_vs_in,
+		.owner		= THIS_MODULE,
+		.pf		= PF_INET,
+		.hooknum        = NF_INET_LOCAL_IN,
+		.priority       = 100,
+	},
+	/* After packet filtering, change source only for VS/NAT */
+	{
+		.hook		= ip_vs_out,
+		.owner		= THIS_MODULE,
+		.pf		= PF_INET,
+		.hooknum        = NF_INET_FORWARD,
+		.priority       = 100,
+	},
+	/* After packet filtering (but before ip_vs_out_icmp), catch icmp
+	 * destined for 0.0.0.0/0, which is for incoming IPVS connections */
+	{
+		.hook		= ip_vs_forward_icmp,
+		.owner		= THIS_MODULE,
+		.pf		= PF_INET,
+		.hooknum        = NF_INET_FORWARD,
+		.priority       = 99,
+	},
+	/* Before the netfilter connection tracking, exit from POST_ROUTING */
+	{
+		.hook		= ip_vs_post_routing,
+		.owner		= THIS_MODULE,
+		.pf		= PF_INET,
+		.hooknum        = NF_INET_POST_ROUTING,
+		.priority       = NF_IP_PRI_NAT_SRC-1,
+	},
+#ifdef CONFIG_IP_VS_IPV6
+	/* After packet filtering, forward packet through VS/DR, VS/TUN,
+	 * or VS/NAT(change destination), so that filtering rules can be
+	 * applied to IPVS. */
+	{
+		.hook		= ip_vs_in,
+		.owner		= THIS_MODULE,
+		.pf		= PF_INET6,
+		.hooknum        = NF_INET_LOCAL_IN,
+		.priority       = 100,
+	},
+	/* After packet filtering, change source only for VS/NAT */
+	{
+		.hook		= ip_vs_out,
+		.owner		= THIS_MODULE,
+		.pf		= PF_INET6,
+		.hooknum        = NF_INET_FORWARD,
+		.priority       = 100,
+	},
+	/* After packet filtering (but before ip_vs_out_icmp), catch icmp
+	 * destined for 0.0.0.0/0, which is for incoming IPVS connections */
+	{
+		.hook		= ip_vs_forward_icmp_v6,
+		.owner		= THIS_MODULE,
+		.pf		= PF_INET6,
+		.hooknum        = NF_INET_FORWARD,
+		.priority       = 99,
+	},
+	/* Before the netfilter connection tracking, exit from POST_ROUTING */
+	{
+		.hook		= ip_vs_post_routing,
+		.owner		= THIS_MODULE,
+		.pf		= PF_INET6,
+		.hooknum        = NF_INET_POST_ROUTING,
+		.priority       = NF_IP6_PRI_NAT_SRC-1,
+	},
+#endif
+};
+
+
+/*
+ *	Initialize IP Virtual Server
+ */
+static int __init ip_vs_init(void)
+{
+	int ret;
+
+	ip_vs_estimator_init();
+
+	ret = ip_vs_control_init();
+	if (ret < 0) {
+		IP_VS_ERR("can't setup control.\n");
+		goto cleanup_estimator;
+	}
+
+	ip_vs_protocol_init();
+
+	ret = ip_vs_app_init();
+	if (ret < 0) {
+		IP_VS_ERR("can't setup application helper.\n");
+		goto cleanup_protocol;
+	}
+
+	ret = ip_vs_conn_init();
+	if (ret < 0) {
+		IP_VS_ERR("can't setup connection table.\n");
+		goto cleanup_app;
+	}
+
+	ret = nf_register_hooks(ip_vs_ops, ARRAY_SIZE(ip_vs_ops));
+	if (ret < 0) {
+		IP_VS_ERR("can't register hooks.\n");
+		goto cleanup_conn;
+	}
+
+	IP_VS_INFO("ipvs loaded.\n");
+	return ret;
+
+  cleanup_conn:
+	ip_vs_conn_cleanup();
+  cleanup_app:
+	ip_vs_app_cleanup();
+  cleanup_protocol:
+	ip_vs_protocol_cleanup();
+	ip_vs_control_cleanup();
+  cleanup_estimator:
+	ip_vs_estimator_cleanup();
+	return ret;
+}
+
+static void __exit ip_vs_cleanup(void)
+{
+	nf_unregister_hooks(ip_vs_ops, ARRAY_SIZE(ip_vs_ops));
+	ip_vs_conn_cleanup();
+	ip_vs_app_cleanup();
+	ip_vs_protocol_cleanup();
+	ip_vs_control_cleanup();
+	ip_vs_estimator_cleanup();
+	IP_VS_INFO("ipvs unloaded.\n");
+}
+
+module_init(ip_vs_init);
+module_exit(ip_vs_cleanup);
+MODULE_LICENSE("GPL");
diff --git a/net/netfilter/ipvs/ip_vs_ctl.c b/net/netfilter/ipvs/ip_vs_ctl.c
new file mode 100644
index 0000000..0302cf3
--- /dev/null
+++ b/net/netfilter/ipvs/ip_vs_ctl.c
@@ -0,0 +1,3443 @@
+/*
+ * IPVS         An implementation of the IP virtual server support for the
+ *              LINUX operating system.  IPVS is now implemented as a module
+ *              over the NetFilter framework. IPVS can be used to build a
+ *              high-performance and highly available server based on a
+ *              cluster of servers.
+ *
+ * Authors:     Wensong Zhang <wensong@linuxvirtualserver.org>
+ *              Peter Kese <peter.kese@ijs.si>
+ *              Julian Anastasov <ja@ssi.bg>
+ *
+ *              This program is free software; you can redistribute it and/or
+ *              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.
+ *
+ * Changes:
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/capability.h>
+#include <linux/fs.h>
+#include <linux/sysctl.h>
+#include <linux/proc_fs.h>
+#include <linux/workqueue.h>
+#include <linux/swap.h>
+#include <linux/seq_file.h>
+
+#include <linux/netfilter.h>
+#include <linux/netfilter_ipv4.h>
+#include <linux/mutex.h>
+
+#include <net/net_namespace.h>
+#include <net/ip.h>
+#ifdef CONFIG_IP_VS_IPV6
+#include <net/ipv6.h>
+#include <net/ip6_route.h>
+#endif
+#include <net/route.h>
+#include <net/sock.h>
+#include <net/genetlink.h>
+
+#include <asm/uaccess.h>
+
+#include <net/ip_vs.h>
+
+/* semaphore for IPVS sockopts. And, [gs]etsockopt may sleep. */
+static DEFINE_MUTEX(__ip_vs_mutex);
+
+/* lock for service table */
+static DEFINE_RWLOCK(__ip_vs_svc_lock);
+
+/* lock for table with the real services */
+static DEFINE_RWLOCK(__ip_vs_rs_lock);
+
+/* lock for state and timeout tables */
+static DEFINE_RWLOCK(__ip_vs_securetcp_lock);
+
+/* lock for drop entry handling */
+static DEFINE_SPINLOCK(__ip_vs_dropentry_lock);
+
+/* lock for drop packet handling */
+static DEFINE_SPINLOCK(__ip_vs_droppacket_lock);
+
+/* 1/rate drop and drop-entry variables */
+int ip_vs_drop_rate = 0;
+int ip_vs_drop_counter = 0;
+static atomic_t ip_vs_dropentry = ATOMIC_INIT(0);
+
+/* number of virtual services */
+static int ip_vs_num_services = 0;
+
+/* sysctl variables */
+static int sysctl_ip_vs_drop_entry = 0;
+static int sysctl_ip_vs_drop_packet = 0;
+static int sysctl_ip_vs_secure_tcp = 0;
+static int sysctl_ip_vs_amemthresh = 1024;
+static int sysctl_ip_vs_am_droprate = 10;
+int sysctl_ip_vs_cache_bypass = 0;
+int sysctl_ip_vs_expire_nodest_conn = 0;
+int sysctl_ip_vs_expire_quiescent_template = 0;
+int sysctl_ip_vs_sync_threshold[2] = { 3, 50 };
+int sysctl_ip_vs_nat_icmp_send = 0;
+
+
+#ifdef CONFIG_IP_VS_DEBUG
+static int sysctl_ip_vs_debug_level = 0;
+
+int ip_vs_get_debug_level(void)
+{
+	return sysctl_ip_vs_debug_level;
+}
+#endif
+
+#ifdef CONFIG_IP_VS_IPV6
+/* Taken from rt6_fill_node() in net/ipv6/route.c, is there a better way? */
+static int __ip_vs_addr_is_local_v6(const struct in6_addr *addr)
+{
+	struct rt6_info *rt;
+	struct flowi fl = {
+		.oif = 0,
+		.nl_u = {
+			.ip6_u = {
+				.daddr = *addr,
+				.saddr = { .s6_addr32 = {0, 0, 0, 0} }, } },
+	};
+
+	rt = (struct rt6_info *)ip6_route_output(&init_net, NULL, &fl);
+	if (rt && rt->rt6i_dev && (rt->rt6i_dev->flags & IFF_LOOPBACK))
+			return 1;
+
+	return 0;
+}
+#endif
+/*
+ *	update_defense_level is called from keventd and from sysctl,
+ *	so it needs to protect itself from softirqs
+ */
+static void update_defense_level(void)
+{
+	struct sysinfo i;
+	static int old_secure_tcp = 0;
+	int availmem;
+	int nomem;
+	int to_change = -1;
+
+	/* we only count free and buffered memory (in pages) */
+	si_meminfo(&i);
+	availmem = i.freeram + i.bufferram;
+	/* however in linux 2.5 the i.bufferram is total page cache size,
+	   we need adjust it */
+	/* si_swapinfo(&i); */
+	/* availmem = availmem - (i.totalswap - i.freeswap); */
+
+	nomem = (availmem < sysctl_ip_vs_amemthresh);
+
+	local_bh_disable();
+
+	/* drop_entry */
+	spin_lock(&__ip_vs_dropentry_lock);
+	switch (sysctl_ip_vs_drop_entry) {
+	case 0:
+		atomic_set(&ip_vs_dropentry, 0);
+		break;
+	case 1:
+		if (nomem) {
+			atomic_set(&ip_vs_dropentry, 1);
+			sysctl_ip_vs_drop_entry = 2;
+		} else {
+			atomic_set(&ip_vs_dropentry, 0);
+		}
+		break;
+	case 2:
+		if (nomem) {
+			atomic_set(&ip_vs_dropentry, 1);
+		} else {
+			atomic_set(&ip_vs_dropentry, 0);
+			sysctl_ip_vs_drop_entry = 1;
+		};
+		break;
+	case 3:
+		atomic_set(&ip_vs_dropentry, 1);
+		break;
+	}
+	spin_unlock(&__ip_vs_dropentry_lock);
+
+	/* drop_packet */
+	spin_lock(&__ip_vs_droppacket_lock);
+	switch (sysctl_ip_vs_drop_packet) {
+	case 0:
+		ip_vs_drop_rate = 0;
+		break;
+	case 1:
+		if (nomem) {
+			ip_vs_drop_rate = ip_vs_drop_counter
+				= sysctl_ip_vs_amemthresh /
+				(sysctl_ip_vs_amemthresh-availmem);
+			sysctl_ip_vs_drop_packet = 2;
+		} else {
+			ip_vs_drop_rate = 0;
+		}
+		break;
+	case 2:
+		if (nomem) {
+			ip_vs_drop_rate = ip_vs_drop_counter
+				= sysctl_ip_vs_amemthresh /
+				(sysctl_ip_vs_amemthresh-availmem);
+		} else {
+			ip_vs_drop_rate = 0;
+			sysctl_ip_vs_drop_packet = 1;
+		}
+		break;
+	case 3:
+		ip_vs_drop_rate = sysctl_ip_vs_am_droprate;
+		break;
+	}
+	spin_unlock(&__ip_vs_droppacket_lock);
+
+	/* secure_tcp */
+	write_lock(&__ip_vs_securetcp_lock);
+	switch (sysctl_ip_vs_secure_tcp) {
+	case 0:
+		if (old_secure_tcp >= 2)
+			to_change = 0;
+		break;
+	case 1:
+		if (nomem) {
+			if (old_secure_tcp < 2)
+				to_change = 1;
+			sysctl_ip_vs_secure_tcp = 2;
+		} else {
+			if (old_secure_tcp >= 2)
+				to_change = 0;
+		}
+		break;
+	case 2:
+		if (nomem) {
+			if (old_secure_tcp < 2)
+				to_change = 1;
+		} else {
+			if (old_secure_tcp >= 2)
+				to_change = 0;
+			sysctl_ip_vs_secure_tcp = 1;
+		}
+		break;
+	case 3:
+		if (old_secure_tcp < 2)
+			to_change = 1;
+		break;
+	}
+	old_secure_tcp = sysctl_ip_vs_secure_tcp;
+	if (to_change >= 0)
+		ip_vs_protocol_timeout_change(sysctl_ip_vs_secure_tcp>1);
+	write_unlock(&__ip_vs_securetcp_lock);
+
+	local_bh_enable();
+}
+
+
+/*
+ *	Timer for checking the defense
+ */
+#define DEFENSE_TIMER_PERIOD	1*HZ
+static void defense_work_handler(struct work_struct *work);
+static DECLARE_DELAYED_WORK(defense_work, defense_work_handler);
+
+static void defense_work_handler(struct work_struct *work)
+{
+	update_defense_level();
+	if (atomic_read(&ip_vs_dropentry))
+		ip_vs_random_dropentry();
+
+	schedule_delayed_work(&defense_work, DEFENSE_TIMER_PERIOD);
+}
+
+int
+ip_vs_use_count_inc(void)
+{
+	return try_module_get(THIS_MODULE);
+}
+
+void
+ip_vs_use_count_dec(void)
+{
+	module_put(THIS_MODULE);
+}
+
+
+/*
+ *	Hash table: for virtual service lookups
+ */
+#define IP_VS_SVC_TAB_BITS 8
+#define IP_VS_SVC_TAB_SIZE (1 << IP_VS_SVC_TAB_BITS)
+#define IP_VS_SVC_TAB_MASK (IP_VS_SVC_TAB_SIZE - 1)
+
+/* the service table hashed by <protocol, addr, port> */
+static struct list_head ip_vs_svc_table[IP_VS_SVC_TAB_SIZE];
+/* the service table hashed by fwmark */
+static struct list_head ip_vs_svc_fwm_table[IP_VS_SVC_TAB_SIZE];
+
+/*
+ *	Hash table: for real service lookups
+ */
+#define IP_VS_RTAB_BITS 4
+#define IP_VS_RTAB_SIZE (1 << IP_VS_RTAB_BITS)
+#define IP_VS_RTAB_MASK (IP_VS_RTAB_SIZE - 1)
+
+static struct list_head ip_vs_rtable[IP_VS_RTAB_SIZE];
+
+/*
+ *	Trash for destinations
+ */
+static LIST_HEAD(ip_vs_dest_trash);
+
+/*
+ *	FTP & NULL virtual service counters
+ */
+static atomic_t ip_vs_ftpsvc_counter = ATOMIC_INIT(0);
+static atomic_t ip_vs_nullsvc_counter = ATOMIC_INIT(0);
+
+
+/*
+ *	Returns hash value for virtual service
+ */
+static __inline__ unsigned
+ip_vs_svc_hashkey(int af, unsigned proto, const union nf_inet_addr *addr,
+		  __be16 port)
+{
+	register unsigned porth = ntohs(port);
+	__be32 addr_fold = addr->ip;
+
+#ifdef CONFIG_IP_VS_IPV6
+	if (af == AF_INET6)
+		addr_fold = addr->ip6[0]^addr->ip6[1]^
+			    addr->ip6[2]^addr->ip6[3];
+#endif
+
+	return (proto^ntohl(addr_fold)^(porth>>IP_VS_SVC_TAB_BITS)^porth)
+		& IP_VS_SVC_TAB_MASK;
+}
+
+/*
+ *	Returns hash value of fwmark for virtual service lookup
+ */
+static __inline__ unsigned ip_vs_svc_fwm_hashkey(__u32 fwmark)
+{
+	return fwmark & IP_VS_SVC_TAB_MASK;
+}
+
+/*
+ *	Hashes a service in the ip_vs_svc_table by <proto,addr,port>
+ *	or in the ip_vs_svc_fwm_table by fwmark.
+ *	Should be called with locked tables.
+ */
+static int ip_vs_svc_hash(struct ip_vs_service *svc)
+{
+	unsigned hash;
+
+	if (svc->flags & IP_VS_SVC_F_HASHED) {
+		IP_VS_ERR("ip_vs_svc_hash(): request for already hashed, "
+			  "called from %p\n", __builtin_return_address(0));
+		return 0;
+	}
+
+	if (svc->fwmark == 0) {
+		/*
+		 *  Hash it by <protocol,addr,port> in ip_vs_svc_table
+		 */
+		hash = ip_vs_svc_hashkey(svc->af, svc->protocol, &svc->addr,
+					 svc->port);
+		list_add(&svc->s_list, &ip_vs_svc_table[hash]);
+	} else {
+		/*
+		 *  Hash it by fwmark in ip_vs_svc_fwm_table
+		 */
+		hash = ip_vs_svc_fwm_hashkey(svc->fwmark);
+		list_add(&svc->f_list, &ip_vs_svc_fwm_table[hash]);
+	}
+
+	svc->flags |= IP_VS_SVC_F_HASHED;
+	/* increase its refcnt because it is referenced by the svc table */
+	atomic_inc(&svc->refcnt);
+	return 1;
+}
+
+
+/*
+ *	Unhashes a service from ip_vs_svc_table/ip_vs_svc_fwm_table.
+ *	Should be called with locked tables.
+ */
+static int ip_vs_svc_unhash(struct ip_vs_service *svc)
+{
+	if (!(svc->flags & IP_VS_SVC_F_HASHED)) {
+		IP_VS_ERR("ip_vs_svc_unhash(): request for unhash flagged, "
+			  "called from %p\n", __builtin_return_address(0));
+		return 0;
+	}
+
+	if (svc->fwmark == 0) {
+		/* Remove it from the ip_vs_svc_table table */
+		list_del(&svc->s_list);
+	} else {
+		/* Remove it from the ip_vs_svc_fwm_table table */
+		list_del(&svc->f_list);
+	}
+
+	svc->flags &= ~IP_VS_SVC_F_HASHED;
+	atomic_dec(&svc->refcnt);
+	return 1;
+}
+
+
+/*
+ *	Get service by {proto,addr,port} in the service table.
+ */
+static inline struct ip_vs_service *
+__ip_vs_service_get(int af, __u16 protocol, const union nf_inet_addr *vaddr,
+		    __be16 vport)
+{
+	unsigned hash;
+	struct ip_vs_service *svc;
+
+	/* Check for "full" addressed entries */
+	hash = ip_vs_svc_hashkey(af, protocol, vaddr, vport);
+
+	list_for_each_entry(svc, &ip_vs_svc_table[hash], s_list){
+		if ((svc->af == af)
+		    && ip_vs_addr_equal(af, &svc->addr, vaddr)
+		    && (svc->port == vport)
+		    && (svc->protocol == protocol)) {
+			/* HIT */
+			atomic_inc(&svc->usecnt);
+			return svc;
+		}
+	}
+
+	return NULL;
+}
+
+
+/*
+ *	Get service by {fwmark} in the service table.
+ */
+static inline struct ip_vs_service *
+__ip_vs_svc_fwm_get(int af, __u32 fwmark)
+{
+	unsigned hash;
+	struct ip_vs_service *svc;
+
+	/* Check for fwmark addressed entries */
+	hash = ip_vs_svc_fwm_hashkey(fwmark);
+
+	list_for_each_entry(svc, &ip_vs_svc_fwm_table[hash], f_list) {
+		if (svc->fwmark == fwmark && svc->af == af) {
+			/* HIT */
+			atomic_inc(&svc->usecnt);
+			return svc;
+		}
+	}
+
+	return NULL;
+}
+
+struct ip_vs_service *
+ip_vs_service_get(int af, __u32 fwmark, __u16 protocol,
+		  const union nf_inet_addr *vaddr, __be16 vport)
+{
+	struct ip_vs_service *svc;
+
+	read_lock(&__ip_vs_svc_lock);
+
+	/*
+	 *	Check the table hashed by fwmark first
+	 */
+	if (fwmark && (svc = __ip_vs_svc_fwm_get(af, fwmark)))
+		goto out;
+
+	/*
+	 *	Check the table hashed by <protocol,addr,port>
+	 *	for "full" addressed entries
+	 */
+	svc = __ip_vs_service_get(af, protocol, vaddr, vport);
+
+	if (svc == NULL
+	    && protocol == IPPROTO_TCP
+	    && atomic_read(&ip_vs_ftpsvc_counter)
+	    && (vport == FTPDATA || ntohs(vport) >= PROT_SOCK)) {
+		/*
+		 * Check if ftp service entry exists, the packet
+		 * might belong to FTP data connections.
+		 */
+		svc = __ip_vs_service_get(af, protocol, vaddr, FTPPORT);
+	}
+
+	if (svc == NULL
+	    && atomic_read(&ip_vs_nullsvc_counter)) {
+		/*
+		 * Check if the catch-all port (port zero) exists
+		 */
+		svc = __ip_vs_service_get(af, protocol, vaddr, 0);
+	}
+
+  out:
+	read_unlock(&__ip_vs_svc_lock);
+
+	IP_VS_DBG_BUF(9, "lookup service: fwm %u %s %s:%u %s\n",
+		      fwmark, ip_vs_proto_name(protocol),
+		      IP_VS_DBG_ADDR(af, vaddr), ntohs(vport),
+		      svc ? "hit" : "not hit");
+
+	return svc;
+}
+
+
+static inline void
+__ip_vs_bind_svc(struct ip_vs_dest *dest, struct ip_vs_service *svc)
+{
+	atomic_inc(&svc->refcnt);
+	dest->svc = svc;
+}
+
+static inline void
+__ip_vs_unbind_svc(struct ip_vs_dest *dest)
+{
+	struct ip_vs_service *svc = dest->svc;
+
+	dest->svc = NULL;
+	if (atomic_dec_and_test(&svc->refcnt))
+		kfree(svc);
+}
+
+
+/*
+ *	Returns hash value for real service
+ */
+static inline unsigned ip_vs_rs_hashkey(int af,
+					    const union nf_inet_addr *addr,
+					    __be16 port)
+{
+	register unsigned porth = ntohs(port);
+	__be32 addr_fold = addr->ip;
+
+#ifdef CONFIG_IP_VS_IPV6
+	if (af == AF_INET6)
+		addr_fold = addr->ip6[0]^addr->ip6[1]^
+			    addr->ip6[2]^addr->ip6[3];
+#endif
+
+	return (ntohl(addr_fold)^(porth>>IP_VS_RTAB_BITS)^porth)
+		& IP_VS_RTAB_MASK;
+}
+
+/*
+ *	Hashes ip_vs_dest in ip_vs_rtable by <proto,addr,port>.
+ *	should be called with locked tables.
+ */
+static int ip_vs_rs_hash(struct ip_vs_dest *dest)
+{
+	unsigned hash;
+
+	if (!list_empty(&dest->d_list)) {
+		return 0;
+	}
+
+	/*
+	 *	Hash by proto,addr,port,
+	 *	which are the parameters of the real service.
+	 */
+	hash = ip_vs_rs_hashkey(dest->af, &dest->addr, dest->port);
+
+	list_add(&dest->d_list, &ip_vs_rtable[hash]);
+
+	return 1;
+}
+
+/*
+ *	UNhashes ip_vs_dest from ip_vs_rtable.
+ *	should be called with locked tables.
+ */
+static int ip_vs_rs_unhash(struct ip_vs_dest *dest)
+{
+	/*
+	 * Remove it from the ip_vs_rtable table.
+	 */
+	if (!list_empty(&dest->d_list)) {
+		list_del(&dest->d_list);
+		INIT_LIST_HEAD(&dest->d_list);
+	}
+
+	return 1;
+}
+
+/*
+ *	Lookup real service by <proto,addr,port> in the real service table.
+ */
+struct ip_vs_dest *
+ip_vs_lookup_real_service(int af, __u16 protocol,
+			  const union nf_inet_addr *daddr,
+			  __be16 dport)
+{
+	unsigned hash;
+	struct ip_vs_dest *dest;
+
+	/*
+	 *	Check for "full" addressed entries
+	 *	Return the first found entry
+	 */
+	hash = ip_vs_rs_hashkey(af, daddr, dport);
+
+	read_lock(&__ip_vs_rs_lock);
+	list_for_each_entry(dest, &ip_vs_rtable[hash], d_list) {
+		if ((dest->af == af)
+		    && ip_vs_addr_equal(af, &dest->addr, daddr)
+		    && (dest->port == dport)
+		    && ((dest->protocol == protocol) ||
+			dest->vfwmark)) {
+			/* HIT */
+			read_unlock(&__ip_vs_rs_lock);
+			return dest;
+		}
+	}
+	read_unlock(&__ip_vs_rs_lock);
+
+	return NULL;
+}
+
+/*
+ *	Lookup destination by {addr,port} in the given service
+ */
+static struct ip_vs_dest *
+ip_vs_lookup_dest(struct ip_vs_service *svc, const union nf_inet_addr *daddr,
+		  __be16 dport)
+{
+	struct ip_vs_dest *dest;
+
+	/*
+	 * Find the destination for the given service
+	 */
+	list_for_each_entry(dest, &svc->destinations, n_list) {
+		if ((dest->af == svc->af)
+		    && ip_vs_addr_equal(svc->af, &dest->addr, daddr)
+		    && (dest->port == dport)) {
+			/* HIT */
+			return dest;
+		}
+	}
+
+	return NULL;
+}
+
+/*
+ * Find destination by {daddr,dport,vaddr,protocol}
+ * Cretaed to be used in ip_vs_process_message() in
+ * the backup synchronization daemon. It finds the
+ * destination to be bound to the received connection
+ * on the backup.
+ *
+ * ip_vs_lookup_real_service() looked promissing, but
+ * seems not working as expected.
+ */
+struct ip_vs_dest *ip_vs_find_dest(int af, const union nf_inet_addr *daddr,
+				   __be16 dport,
+				   const union nf_inet_addr *vaddr,
+				   __be16 vport, __u16 protocol)
+{
+	struct ip_vs_dest *dest;
+	struct ip_vs_service *svc;
+
+	svc = ip_vs_service_get(af, 0, protocol, vaddr, vport);
+	if (!svc)
+		return NULL;
+	dest = ip_vs_lookup_dest(svc, daddr, dport);
+	if (dest)
+		atomic_inc(&dest->refcnt);
+	ip_vs_service_put(svc);
+	return dest;
+}
+
+/*
+ *  Lookup dest by {svc,addr,port} in the destination trash.
+ *  The destination trash is used to hold the destinations that are removed
+ *  from the service table but are still referenced by some conn entries.
+ *  The reason to add the destination trash is when the dest is temporary
+ *  down (either by administrator or by monitor program), the dest can be
+ *  picked back from the trash, the remaining connections to the dest can
+ *  continue, and the counting information of the dest is also useful for
+ *  scheduling.
+ */
+static struct ip_vs_dest *
+ip_vs_trash_get_dest(struct ip_vs_service *svc, const union nf_inet_addr *daddr,
+		     __be16 dport)
+{
+	struct ip_vs_dest *dest, *nxt;
+
+	/*
+	 * Find the destination in trash
+	 */
+	list_for_each_entry_safe(dest, nxt, &ip_vs_dest_trash, n_list) {
+		IP_VS_DBG_BUF(3, "Destination %u/%s:%u still in trash, "
+			      "dest->refcnt=%d\n",
+			      dest->vfwmark,
+			      IP_VS_DBG_ADDR(svc->af, &dest->addr),
+			      ntohs(dest->port),
+			      atomic_read(&dest->refcnt));
+		if (dest->af == svc->af &&
+		    ip_vs_addr_equal(svc->af, &dest->addr, daddr) &&
+		    dest->port == dport &&
+		    dest->vfwmark == svc->fwmark &&
+		    dest->protocol == svc->protocol &&
+		    (svc->fwmark ||
+		     (ip_vs_addr_equal(svc->af, &dest->vaddr, &svc->addr) &&
+		      dest->vport == svc->port))) {
+			/* HIT */
+			return dest;
+		}
+
+		/*
+		 * Try to purge the destination from trash if not referenced
+		 */
+		if (atomic_read(&dest->refcnt) == 1) {
+			IP_VS_DBG_BUF(3, "Removing destination %u/%s:%u "
+				      "from trash\n",
+				      dest->vfwmark,
+				      IP_VS_DBG_ADDR(svc->af, &dest->addr),
+				      ntohs(dest->port));
+			list_del(&dest->n_list);
+			ip_vs_dst_reset(dest);
+			__ip_vs_unbind_svc(dest);
+			kfree(dest);
+		}
+	}
+
+	return NULL;
+}
+
+
+/*
+ *  Clean up all the destinations in the trash
+ *  Called by the ip_vs_control_cleanup()
+ *
+ *  When the ip_vs_control_clearup is activated by ipvs module exit,
+ *  the service tables must have been flushed and all the connections
+ *  are expired, and the refcnt of each destination in the trash must
+ *  be 1, so we simply release them here.
+ */
+static void ip_vs_trash_cleanup(void)
+{
+	struct ip_vs_dest *dest, *nxt;
+
+	list_for_each_entry_safe(dest, nxt, &ip_vs_dest_trash, n_list) {
+		list_del(&dest->n_list);
+		ip_vs_dst_reset(dest);
+		__ip_vs_unbind_svc(dest);
+		kfree(dest);
+	}
+}
+
+
+static void
+ip_vs_zero_stats(struct ip_vs_stats *stats)
+{
+	spin_lock_bh(&stats->lock);
+
+	memset(&stats->ustats, 0, sizeof(stats->ustats));
+	ip_vs_zero_estimator(stats);
+
+	spin_unlock_bh(&stats->lock);
+}
+
+/*
+ *	Update a destination in the given service
+ */
+static void
+__ip_vs_update_dest(struct ip_vs_service *svc,
+		    struct ip_vs_dest *dest, struct ip_vs_dest_user_kern *udest)
+{
+	int conn_flags;
+
+	/* set the weight and the flags */
+	atomic_set(&dest->weight, udest->weight);
+	conn_flags = udest->conn_flags | IP_VS_CONN_F_INACTIVE;
+
+	/* check if local node and update the flags */
+#ifdef CONFIG_IP_VS_IPV6
+	if (svc->af == AF_INET6) {
+		if (__ip_vs_addr_is_local_v6(&udest->addr.in6)) {
+			conn_flags = (conn_flags & ~IP_VS_CONN_F_FWD_MASK)
+				| IP_VS_CONN_F_LOCALNODE;
+		}
+	} else
+#endif
+		if (inet_addr_type(&init_net, udest->addr.ip) == RTN_LOCAL) {
+			conn_flags = (conn_flags & ~IP_VS_CONN_F_FWD_MASK)
+				| IP_VS_CONN_F_LOCALNODE;
+		}
+
+	/* set the IP_VS_CONN_F_NOOUTPUT flag if not masquerading/NAT */
+	if ((conn_flags & IP_VS_CONN_F_FWD_MASK) != 0) {
+		conn_flags |= IP_VS_CONN_F_NOOUTPUT;
+	} else {
+		/*
+		 *    Put the real service in ip_vs_rtable if not present.
+		 *    For now only for NAT!
+		 */
+		write_lock_bh(&__ip_vs_rs_lock);
+		ip_vs_rs_hash(dest);
+		write_unlock_bh(&__ip_vs_rs_lock);
+	}
+	atomic_set(&dest->conn_flags, conn_flags);
+
+	/* bind the service */
+	if (!dest->svc) {
+		__ip_vs_bind_svc(dest, svc);
+	} else {
+		if (dest->svc != svc) {
+			__ip_vs_unbind_svc(dest);
+			ip_vs_zero_stats(&dest->stats);
+			__ip_vs_bind_svc(dest, svc);
+		}
+	}
+
+	/* set the dest status flags */
+	dest->flags |= IP_VS_DEST_F_AVAILABLE;
+
+	if (udest->u_threshold == 0 || udest->u_threshold > dest->u_threshold)
+		dest->flags &= ~IP_VS_DEST_F_OVERLOAD;
+	dest->u_threshold = udest->u_threshold;
+	dest->l_threshold = udest->l_threshold;
+}
+
+
+/*
+ *	Create a destination for the given service
+ */
+static int
+ip_vs_new_dest(struct ip_vs_service *svc, struct ip_vs_dest_user_kern *udest,
+	       struct ip_vs_dest **dest_p)
+{
+	struct ip_vs_dest *dest;
+	unsigned atype;
+
+	EnterFunction(2);
+
+#ifdef CONFIG_IP_VS_IPV6
+	if (svc->af == AF_INET6) {
+		atype = ipv6_addr_type(&udest->addr.in6);
+		if ((!(atype & IPV6_ADDR_UNICAST) ||
+			atype & IPV6_ADDR_LINKLOCAL) &&
+			!__ip_vs_addr_is_local_v6(&udest->addr.in6))
+			return -EINVAL;
+	} else
+#endif
+	{
+		atype = inet_addr_type(&init_net, udest->addr.ip);
+		if (atype != RTN_LOCAL && atype != RTN_UNICAST)
+			return -EINVAL;
+	}
+
+	dest = kzalloc(sizeof(struct ip_vs_dest), GFP_ATOMIC);
+	if (dest == NULL) {
+		IP_VS_ERR("ip_vs_new_dest: kmalloc failed.\n");
+		return -ENOMEM;
+	}
+
+	dest->af = svc->af;
+	dest->protocol = svc->protocol;
+	dest->vaddr = svc->addr;
+	dest->vport = svc->port;
+	dest->vfwmark = svc->fwmark;
+	ip_vs_addr_copy(svc->af, &dest->addr, &udest->addr);
+	dest->port = udest->port;
+
+	atomic_set(&dest->activeconns, 0);
+	atomic_set(&dest->inactconns, 0);
+	atomic_set(&dest->persistconns, 0);
+	atomic_set(&dest->refcnt, 0);
+
+	INIT_LIST_HEAD(&dest->d_list);
+	spin_lock_init(&dest->dst_lock);
+	spin_lock_init(&dest->stats.lock);
+	__ip_vs_update_dest(svc, dest, udest);
+	ip_vs_new_estimator(&dest->stats);
+
+	*dest_p = dest;
+
+	LeaveFunction(2);
+	return 0;
+}
+
+
+/*
+ *	Add a destination into an existing service
+ */
+static int
+ip_vs_add_dest(struct ip_vs_service *svc, struct ip_vs_dest_user_kern *udest)
+{
+	struct ip_vs_dest *dest;
+	union nf_inet_addr daddr;
+	__be16 dport = udest->port;
+	int ret;
+
+	EnterFunction(2);
+
+	if (udest->weight < 0) {
+		IP_VS_ERR("ip_vs_add_dest(): server weight less than zero\n");
+		return -ERANGE;
+	}
+
+	if (udest->l_threshold > udest->u_threshold) {
+		IP_VS_ERR("ip_vs_add_dest(): lower threshold is higher than "
+			  "upper threshold\n");
+		return -ERANGE;
+	}
+
+	ip_vs_addr_copy(svc->af, &daddr, &udest->addr);
+
+	/*
+	 * Check if the dest already exists in the list
+	 */
+	dest = ip_vs_lookup_dest(svc, &daddr, dport);
+
+	if (dest != NULL) {
+		IP_VS_DBG(1, "ip_vs_add_dest(): dest already exists\n");
+		return -EEXIST;
+	}
+
+	/*
+	 * Check if the dest already exists in the trash and
+	 * is from the same service
+	 */
+	dest = ip_vs_trash_get_dest(svc, &daddr, dport);
+
+	if (dest != NULL) {
+		IP_VS_DBG_BUF(3, "Get destination %s:%u from trash, "
+			      "dest->refcnt=%d, service %u/%s:%u\n",
+			      IP_VS_DBG_ADDR(svc->af, &daddr), ntohs(dport),
+			      atomic_read(&dest->refcnt),
+			      dest->vfwmark,
+			      IP_VS_DBG_ADDR(svc->af, &dest->vaddr),
+			      ntohs(dest->vport));
+
+		__ip_vs_update_dest(svc, dest, udest);
+
+		/*
+		 * Get the destination from the trash
+		 */
+		list_del(&dest->n_list);
+
+		ip_vs_new_estimator(&dest->stats);
+
+		write_lock_bh(&__ip_vs_svc_lock);
+
+		/*
+		 * Wait until all other svc users go away.
+		 */
+		IP_VS_WAIT_WHILE(atomic_read(&svc->usecnt) > 1);
+
+		list_add(&dest->n_list, &svc->destinations);
+		svc->num_dests++;
+
+		/* call the update_service function of its scheduler */
+		if (svc->scheduler->update_service)
+			svc->scheduler->update_service(svc);
+
+		write_unlock_bh(&__ip_vs_svc_lock);
+		return 0;
+	}
+
+	/*
+	 * Allocate and initialize the dest structure
+	 */
+	ret = ip_vs_new_dest(svc, udest, &dest);
+	if (ret) {
+		return ret;
+	}
+
+	/*
+	 * Add the dest entry into the list
+	 */
+	atomic_inc(&dest->refcnt);
+
+	write_lock_bh(&__ip_vs_svc_lock);
+
+	/*
+	 * Wait until all other svc users go away.
+	 */
+	IP_VS_WAIT_WHILE(atomic_read(&svc->usecnt) > 1);
+
+	list_add(&dest->n_list, &svc->destinations);
+	svc->num_dests++;
+
+	/* call the update_service function of its scheduler */
+	if (svc->scheduler->update_service)
+		svc->scheduler->update_service(svc);
+
+	write_unlock_bh(&__ip_vs_svc_lock);
+
+	LeaveFunction(2);
+
+	return 0;
+}
+
+
+/*
+ *	Edit a destination in the given service
+ */
+static int
+ip_vs_edit_dest(struct ip_vs_service *svc, struct ip_vs_dest_user_kern *udest)
+{
+	struct ip_vs_dest *dest;
+	union nf_inet_addr daddr;
+	__be16 dport = udest->port;
+
+	EnterFunction(2);
+
+	if (udest->weight < 0) {
+		IP_VS_ERR("ip_vs_edit_dest(): server weight less than zero\n");
+		return -ERANGE;
+	}
+
+	if (udest->l_threshold > udest->u_threshold) {
+		IP_VS_ERR("ip_vs_edit_dest(): lower threshold is higher than "
+			  "upper threshold\n");
+		return -ERANGE;
+	}
+
+	ip_vs_addr_copy(svc->af, &daddr, &udest->addr);
+
+	/*
+	 *  Lookup the destination list
+	 */
+	dest = ip_vs_lookup_dest(svc, &daddr, dport);
+
+	if (dest == NULL) {
+		IP_VS_DBG(1, "ip_vs_edit_dest(): dest doesn't exist\n");
+		return -ENOENT;
+	}
+
+	__ip_vs_update_dest(svc, dest, udest);
+
+	write_lock_bh(&__ip_vs_svc_lock);
+
+	/* Wait until all other svc users go away */
+	IP_VS_WAIT_WHILE(atomic_read(&svc->usecnt) > 1);
+
+	/* call the update_service, because server weight may be changed */
+	if (svc->scheduler->update_service)
+		svc->scheduler->update_service(svc);
+
+	write_unlock_bh(&__ip_vs_svc_lock);
+
+	LeaveFunction(2);
+
+	return 0;
+}
+
+
+/*
+ *	Delete a destination (must be already unlinked from the service)
+ */
+static void __ip_vs_del_dest(struct ip_vs_dest *dest)
+{
+	ip_vs_kill_estimator(&dest->stats);
+
+	/*
+	 *  Remove it from the d-linked list with the real services.
+	 */
+	write_lock_bh(&__ip_vs_rs_lock);
+	ip_vs_rs_unhash(dest);
+	write_unlock_bh(&__ip_vs_rs_lock);
+
+	/*
+	 *  Decrease the refcnt of the dest, and free the dest
+	 *  if nobody refers to it (refcnt=0). Otherwise, throw
+	 *  the destination into the trash.
+	 */
+	if (atomic_dec_and_test(&dest->refcnt)) {
+		ip_vs_dst_reset(dest);
+		/* simply decrease svc->refcnt here, let the caller check
+		   and release the service if nobody refers to it.
+		   Only user context can release destination and service,
+		   and only one user context can update virtual service at a
+		   time, so the operation here is OK */
+		atomic_dec(&dest->svc->refcnt);
+		kfree(dest);
+	} else {
+		IP_VS_DBG_BUF(3, "Moving dest %s:%u into trash, "
+			      "dest->refcnt=%d\n",
+			      IP_VS_DBG_ADDR(dest->af, &dest->addr),
+			      ntohs(dest->port),
+			      atomic_read(&dest->refcnt));
+		list_add(&dest->n_list, &ip_vs_dest_trash);
+		atomic_inc(&dest->refcnt);
+	}
+}
+
+
+/*
+ *	Unlink a destination from the given service
+ */
+static void __ip_vs_unlink_dest(struct ip_vs_service *svc,
+				struct ip_vs_dest *dest,
+				int svcupd)
+{
+	dest->flags &= ~IP_VS_DEST_F_AVAILABLE;
+
+	/*
+	 *  Remove it from the d-linked destination list.
+	 */
+	list_del(&dest->n_list);
+	svc->num_dests--;
+
+	/*
+	 *  Call the update_service function of its scheduler
+	 */
+	if (svcupd && svc->scheduler->update_service)
+			svc->scheduler->update_service(svc);
+}
+
+
+/*
+ *	Delete a destination server in the given service
+ */
+static int
+ip_vs_del_dest(struct ip_vs_service *svc, struct ip_vs_dest_user_kern *udest)
+{
+	struct ip_vs_dest *dest;
+	__be16 dport = udest->port;
+
+	EnterFunction(2);
+
+	dest = ip_vs_lookup_dest(svc, &udest->addr, dport);
+
+	if (dest == NULL) {
+		IP_VS_DBG(1, "ip_vs_del_dest(): destination not found!\n");
+		return -ENOENT;
+	}
+
+	write_lock_bh(&__ip_vs_svc_lock);
+
+	/*
+	 *	Wait until all other svc users go away.
+	 */
+	IP_VS_WAIT_WHILE(atomic_read(&svc->usecnt) > 1);
+
+	/*
+	 *	Unlink dest from the service
+	 */
+	__ip_vs_unlink_dest(svc, dest, 1);
+
+	write_unlock_bh(&__ip_vs_svc_lock);
+
+	/*
+	 *	Delete the destination
+	 */
+	__ip_vs_del_dest(dest);
+
+	LeaveFunction(2);
+
+	return 0;
+}
+
+
+/*
+ *	Add a service into the service hash table
+ */
+static int
+ip_vs_add_service(struct ip_vs_service_user_kern *u,
+		  struct ip_vs_service **svc_p)
+{
+	int ret = 0;
+	struct ip_vs_scheduler *sched = NULL;
+	struct ip_vs_service *svc = NULL;
+
+	/* increase the module use count */
+	ip_vs_use_count_inc();
+
+	/* Lookup the scheduler by 'u->sched_name' */
+	sched = ip_vs_scheduler_get(u->sched_name);
+	if (sched == NULL) {
+		IP_VS_INFO("Scheduler module ip_vs_%s not found\n",
+			   u->sched_name);
+		ret = -ENOENT;
+		goto out_mod_dec;
+	}
+
+#ifdef CONFIG_IP_VS_IPV6
+	if (u->af == AF_INET6) {
+		if (!sched->supports_ipv6) {
+			ret = -EAFNOSUPPORT;
+			goto out_err;
+		}
+		if ((u->netmask < 1) || (u->netmask > 128)) {
+			ret = -EINVAL;
+			goto out_err;
+		}
+	}
+#endif
+
+	svc = kzalloc(sizeof(struct ip_vs_service), GFP_ATOMIC);
+	if (svc == NULL) {
+		IP_VS_DBG(1, "ip_vs_add_service: kmalloc failed.\n");
+		ret = -ENOMEM;
+		goto out_err;
+	}
+
+	/* I'm the first user of the service */
+	atomic_set(&svc->usecnt, 1);
+	atomic_set(&svc->refcnt, 0);
+
+	svc->af = u->af;
+	svc->protocol = u->protocol;
+	ip_vs_addr_copy(svc->af, &svc->addr, &u->addr);
+	svc->port = u->port;
+	svc->fwmark = u->fwmark;
+	svc->flags = u->flags;
+	svc->timeout = u->timeout * HZ;
+	svc->netmask = u->netmask;
+
+	INIT_LIST_HEAD(&svc->destinations);
+	rwlock_init(&svc->sched_lock);
+	spin_lock_init(&svc->stats.lock);
+
+	/* Bind the scheduler */
+	ret = ip_vs_bind_scheduler(svc, sched);
+	if (ret)
+		goto out_err;
+	sched = NULL;
+
+	/* Update the virtual service counters */
+	if (svc->port == FTPPORT)
+		atomic_inc(&ip_vs_ftpsvc_counter);
+	else if (svc->port == 0)
+		atomic_inc(&ip_vs_nullsvc_counter);
+
+	ip_vs_new_estimator(&svc->stats);
+
+	/* Count only IPv4 services for old get/setsockopt interface */
+	if (svc->af == AF_INET)
+		ip_vs_num_services++;
+
+	/* Hash the service into the service table */
+	write_lock_bh(&__ip_vs_svc_lock);
+	ip_vs_svc_hash(svc);
+	write_unlock_bh(&__ip_vs_svc_lock);
+
+	*svc_p = svc;
+	return 0;
+
+  out_err:
+	if (svc != NULL) {
+		if (svc->scheduler)
+			ip_vs_unbind_scheduler(svc);
+		if (svc->inc) {
+			local_bh_disable();
+			ip_vs_app_inc_put(svc->inc);
+			local_bh_enable();
+		}
+		kfree(svc);
+	}
+	ip_vs_scheduler_put(sched);
+
+  out_mod_dec:
+	/* decrease the module use count */
+	ip_vs_use_count_dec();
+
+	return ret;
+}
+
+
+/*
+ *	Edit a service and bind it with a new scheduler
+ */
+static int
+ip_vs_edit_service(struct ip_vs_service *svc, struct ip_vs_service_user_kern *u)
+{
+	struct ip_vs_scheduler *sched, *old_sched;
+	int ret = 0;
+
+	/*
+	 * Lookup the scheduler, by 'u->sched_name'
+	 */
+	sched = ip_vs_scheduler_get(u->sched_name);
+	if (sched == NULL) {
+		IP_VS_INFO("Scheduler module ip_vs_%s not found\n",
+			   u->sched_name);
+		return -ENOENT;
+	}
+	old_sched = sched;
+
+#ifdef CONFIG_IP_VS_IPV6
+	if (u->af == AF_INET6) {
+		if (!sched->supports_ipv6) {
+			ret = -EAFNOSUPPORT;
+			goto out;
+		}
+		if ((u->netmask < 1) || (u->netmask > 128)) {
+			ret = -EINVAL;
+			goto out;
+		}
+	}
+#endif
+
+	write_lock_bh(&__ip_vs_svc_lock);
+
+	/*
+	 * Wait until all other svc users go away.
+	 */
+	IP_VS_WAIT_WHILE(atomic_read(&svc->usecnt) > 1);
+
+	/*
+	 * Set the flags and timeout value
+	 */
+	svc->flags = u->flags | IP_VS_SVC_F_HASHED;
+	svc->timeout = u->timeout * HZ;
+	svc->netmask = u->netmask;
+
+	old_sched = svc->scheduler;
+	if (sched != old_sched) {
+		/*
+		 * Unbind the old scheduler
+		 */
+		if ((ret = ip_vs_unbind_scheduler(svc))) {
+			old_sched = sched;
+			goto out_unlock;
+		}
+
+		/*
+		 * Bind the new scheduler
+		 */
+		if ((ret = ip_vs_bind_scheduler(svc, sched))) {
+			/*
+			 * If ip_vs_bind_scheduler fails, restore the old
+			 * scheduler.
+			 * The main reason of failure is out of memory.
+			 *
+			 * The question is if the old scheduler can be
+			 * restored all the time. TODO: if it cannot be
+			 * restored some time, we must delete the service,
+			 * otherwise the system may crash.
+			 */
+			ip_vs_bind_scheduler(svc, old_sched);
+			old_sched = sched;
+			goto out_unlock;
+		}
+	}
+
+  out_unlock:
+	write_unlock_bh(&__ip_vs_svc_lock);
+#ifdef CONFIG_IP_VS_IPV6
+  out:
+#endif
+
+	if (old_sched)
+		ip_vs_scheduler_put(old_sched);
+
+	return ret;
+}
+
+
+/*
+ *	Delete a service from the service list
+ *	- The service must be unlinked, unlocked and not referenced!
+ *	- We are called under _bh lock
+ */
+static void __ip_vs_del_service(struct ip_vs_service *svc)
+{
+	struct ip_vs_dest *dest, *nxt;
+	struct ip_vs_scheduler *old_sched;
+
+	/* Count only IPv4 services for old get/setsockopt interface */
+	if (svc->af == AF_INET)
+		ip_vs_num_services--;
+
+	ip_vs_kill_estimator(&svc->stats);
+
+	/* Unbind scheduler */
+	old_sched = svc->scheduler;
+	ip_vs_unbind_scheduler(svc);
+	if (old_sched)
+		ip_vs_scheduler_put(old_sched);
+
+	/* Unbind app inc */
+	if (svc->inc) {
+		ip_vs_app_inc_put(svc->inc);
+		svc->inc = NULL;
+	}
+
+	/*
+	 *    Unlink the whole destination list
+	 */
+	list_for_each_entry_safe(dest, nxt, &svc->destinations, n_list) {
+		__ip_vs_unlink_dest(svc, dest, 0);
+		__ip_vs_del_dest(dest);
+	}
+
+	/*
+	 *    Update the virtual service counters
+	 */
+	if (svc->port == FTPPORT)
+		atomic_dec(&ip_vs_ftpsvc_counter);
+	else if (svc->port == 0)
+		atomic_dec(&ip_vs_nullsvc_counter);
+
+	/*
+	 *    Free the service if nobody refers to it
+	 */
+	if (atomic_read(&svc->refcnt) == 0)
+		kfree(svc);
+
+	/* decrease the module use count */
+	ip_vs_use_count_dec();
+}
+
+/*
+ *	Delete a service from the service list
+ */
+static int ip_vs_del_service(struct ip_vs_service *svc)
+{
+	if (svc == NULL)
+		return -EEXIST;
+
+	/*
+	 * Unhash it from the service table
+	 */
+	write_lock_bh(&__ip_vs_svc_lock);
+
+	ip_vs_svc_unhash(svc);
+
+	/*
+	 * Wait until all the svc users go away.
+	 */
+	IP_VS_WAIT_WHILE(atomic_read(&svc->usecnt) > 1);
+
+	__ip_vs_del_service(svc);
+
+	write_unlock_bh(&__ip_vs_svc_lock);
+
+	return 0;
+}
+
+
+/*
+ *	Flush all the virtual services
+ */
+static int ip_vs_flush(void)
+{
+	int idx;
+	struct ip_vs_service *svc, *nxt;
+
+	/*
+	 * Flush the service table hashed by <protocol,addr,port>
+	 */
+	for(idx = 0; idx < IP_VS_SVC_TAB_SIZE; idx++) {
+		list_for_each_entry_safe(svc, nxt, &ip_vs_svc_table[idx], s_list) {
+			write_lock_bh(&__ip_vs_svc_lock);
+			ip_vs_svc_unhash(svc);
+			/*
+			 * Wait until all the svc users go away.
+			 */
+			IP_VS_WAIT_WHILE(atomic_read(&svc->usecnt) > 0);
+			__ip_vs_del_service(svc);
+			write_unlock_bh(&__ip_vs_svc_lock);
+		}
+	}
+
+	/*
+	 * Flush the service table hashed by fwmark
+	 */
+	for(idx = 0; idx < IP_VS_SVC_TAB_SIZE; idx++) {
+		list_for_each_entry_safe(svc, nxt,
+					 &ip_vs_svc_fwm_table[idx], f_list) {
+			write_lock_bh(&__ip_vs_svc_lock);
+			ip_vs_svc_unhash(svc);
+			/*
+			 * Wait until all the svc users go away.
+			 */
+			IP_VS_WAIT_WHILE(atomic_read(&svc->usecnt) > 0);
+			__ip_vs_del_service(svc);
+			write_unlock_bh(&__ip_vs_svc_lock);
+		}
+	}
+
+	return 0;
+}
+
+
+/*
+ *	Zero counters in a service or all services
+ */
+static int ip_vs_zero_service(struct ip_vs_service *svc)
+{
+	struct ip_vs_dest *dest;
+
+	write_lock_bh(&__ip_vs_svc_lock);
+	list_for_each_entry(dest, &svc->destinations, n_list) {
+		ip_vs_zero_stats(&dest->stats);
+	}
+	ip_vs_zero_stats(&svc->stats);
+	write_unlock_bh(&__ip_vs_svc_lock);
+	return 0;
+}
+
+static int ip_vs_zero_all(void)
+{
+	int idx;
+	struct ip_vs_service *svc;
+
+	for(idx = 0; idx < IP_VS_SVC_TAB_SIZE; idx++) {
+		list_for_each_entry(svc, &ip_vs_svc_table[idx], s_list) {
+			ip_vs_zero_service(svc);
+		}
+	}
+
+	for(idx = 0; idx < IP_VS_SVC_TAB_SIZE; idx++) {
+		list_for_each_entry(svc, &ip_vs_svc_fwm_table[idx], f_list) {
+			ip_vs_zero_service(svc);
+		}
+	}
+
+	ip_vs_zero_stats(&ip_vs_stats);
+	return 0;
+}
+
+
+static int
+proc_do_defense_mode(ctl_table *table, int write, struct file * filp,
+		     void __user *buffer, size_t *lenp, loff_t *ppos)
+{
+	int *valp = table->data;
+	int val = *valp;
+	int rc;
+
+	rc = proc_dointvec(table, write, filp, buffer, lenp, ppos);
+	if (write && (*valp != val)) {
+		if ((*valp < 0) || (*valp > 3)) {
+			/* Restore the correct value */
+			*valp = val;
+		} else {
+			update_defense_level();
+		}
+	}
+	return rc;
+}
+
+
+static int
+proc_do_sync_threshold(ctl_table *table, int write, struct file *filp,
+		       void __user *buffer, size_t *lenp, loff_t *ppos)
+{
+	int *valp = table->data;
+	int val[2];
+	int rc;
+
+	/* backup the value first */
+	memcpy(val, valp, sizeof(val));
+
+	rc = proc_dointvec(table, write, filp, buffer, lenp, ppos);
+	if (write && (valp[0] < 0 || valp[1] < 0 || valp[0] >= valp[1])) {
+		/* Restore the correct value */
+		memcpy(valp, val, sizeof(val));
+	}
+	return rc;
+}
+
+
+/*
+ *	IPVS sysctl table (under the /proc/sys/net/ipv4/vs/)
+ */
+
+static struct ctl_table vs_vars[] = {
+	{
+		.procname	= "amemthresh",
+		.data		= &sysctl_ip_vs_amemthresh,
+		.maxlen		= sizeof(int),
+		.mode		= 0644,
+		.proc_handler	= &proc_dointvec,
+	},
+#ifdef CONFIG_IP_VS_DEBUG
+	{
+		.procname	= "debug_level",
+		.data		= &sysctl_ip_vs_debug_level,
+		.maxlen		= sizeof(int),
+		.mode		= 0644,
+		.proc_handler	= &proc_dointvec,
+	},
+#endif
+	{
+		.procname	= "am_droprate",
+		.data		= &sysctl_ip_vs_am_droprate,
+		.maxlen		= sizeof(int),
+		.mode		= 0644,
+		.proc_handler	= &proc_dointvec,
+	},
+	{
+		.procname	= "drop_entry",
+		.data		= &sysctl_ip_vs_drop_entry,
+		.maxlen		= sizeof(int),
+		.mode		= 0644,
+		.proc_handler	= &proc_do_defense_mode,
+	},
+	{
+		.procname	= "drop_packet",
+		.data		= &sysctl_ip_vs_drop_packet,
+		.maxlen		= sizeof(int),
+		.mode		= 0644,
+		.proc_handler	= &proc_do_defense_mode,
+	},
+	{
+		.procname	= "secure_tcp",
+		.data		= &sysctl_ip_vs_secure_tcp,
+		.maxlen		= sizeof(int),
+		.mode		= 0644,
+		.proc_handler	= &proc_do_defense_mode,
+	},
+#if 0
+	{
+		.procname	= "timeout_established",
+		.data	= &vs_timeout_table_dos.timeout[IP_VS_S_ESTABLISHED],
+		.maxlen		= sizeof(int),
+		.mode		= 0644,
+		.proc_handler	= &proc_dointvec_jiffies,
+	},
+	{
+		.procname	= "timeout_synsent",
+		.data	= &vs_timeout_table_dos.timeout[IP_VS_S_SYN_SENT],
+		.maxlen		= sizeof(int),
+		.mode		= 0644,
+		.proc_handler	= &proc_dointvec_jiffies,
+	},
+	{
+		.procname	= "timeout_synrecv",
+		.data	= &vs_timeout_table_dos.timeout[IP_VS_S_SYN_RECV],
+		.maxlen		= sizeof(int),
+		.mode		= 0644,
+		.proc_handler	= &proc_dointvec_jiffies,
+	},
+	{
+		.procname	= "timeout_finwait",
+		.data	= &vs_timeout_table_dos.timeout[IP_VS_S_FIN_WAIT],
+		.maxlen		= sizeof(int),
+		.mode		= 0644,
+		.proc_handler	= &proc_dointvec_jiffies,
+	},
+	{
+		.procname	= "timeout_timewait",
+		.data	= &vs_timeout_table_dos.timeout[IP_VS_S_TIME_WAIT],
+		.maxlen		= sizeof(int),
+		.mode		= 0644,
+		.proc_handler	= &proc_dointvec_jiffies,
+	},
+	{
+		.procname	= "timeout_close",
+		.data	= &vs_timeout_table_dos.timeout[IP_VS_S_CLOSE],
+		.maxlen		= sizeof(int),
+		.mode		= 0644,
+		.proc_handler	= &proc_dointvec_jiffies,
+	},
+	{
+		.procname	= "timeout_closewait",
+		.data	= &vs_timeout_table_dos.timeout[IP_VS_S_CLOSE_WAIT],
+		.maxlen		= sizeof(int),
+		.mode		= 0644,
+		.proc_handler	= &proc_dointvec_jiffies,
+	},
+	{
+		.procname	= "timeout_lastack",
+		.data	= &vs_timeout_table_dos.timeout[IP_VS_S_LAST_ACK],
+		.maxlen		= sizeof(int),
+		.mode		= 0644,
+		.proc_handler	= &proc_dointvec_jiffies,
+	},
+	{
+		.procname	= "timeout_listen",
+		.data	= &vs_timeout_table_dos.timeout[IP_VS_S_LISTEN],
+		.maxlen		= sizeof(int),
+		.mode		= 0644,
+		.proc_handler	= &proc_dointvec_jiffies,
+	},
+	{
+		.procname	= "timeout_synack",
+		.data	= &vs_timeout_table_dos.timeout[IP_VS_S_SYNACK],
+		.maxlen		= sizeof(int),
+		.mode		= 0644,
+		.proc_handler	= &proc_dointvec_jiffies,
+	},
+	{
+		.procname	= "timeout_udp",
+		.data	= &vs_timeout_table_dos.timeout[IP_VS_S_UDP],
+		.maxlen		= sizeof(int),
+		.mode		= 0644,
+		.proc_handler	= &proc_dointvec_jiffies,
+	},
+	{
+		.procname	= "timeout_icmp",
+		.data	= &vs_timeout_table_dos.timeout[IP_VS_S_ICMP],
+		.maxlen		= sizeof(int),
+		.mode		= 0644,
+		.proc_handler	= &proc_dointvec_jiffies,
+	},
+#endif
+	{
+		.procname	= "cache_bypass",
+		.data		= &sysctl_ip_vs_cache_bypass,
+		.maxlen		= sizeof(int),
+		.mode		= 0644,
+		.proc_handler	= &proc_dointvec,
+	},
+	{
+		.procname	= "expire_nodest_conn",
+		.data		= &sysctl_ip_vs_expire_nodest_conn,
+		.maxlen		= sizeof(int),
+		.mode		= 0644,
+		.proc_handler	= &proc_dointvec,
+	},
+	{
+		.procname	= "expire_quiescent_template",
+		.data		= &sysctl_ip_vs_expire_quiescent_template,
+		.maxlen		= sizeof(int),
+		.mode		= 0644,
+		.proc_handler	= &proc_dointvec,
+	},
+	{
+		.procname	= "sync_threshold",
+		.data		= &sysctl_ip_vs_sync_threshold,
+		.maxlen		= sizeof(sysctl_ip_vs_sync_threshold),
+		.mode		= 0644,
+		.proc_handler	= &proc_do_sync_threshold,
+	},
+	{
+		.procname	= "nat_icmp_send",
+		.data		= &sysctl_ip_vs_nat_icmp_send,
+		.maxlen		= sizeof(int),
+		.mode		= 0644,
+		.proc_handler	= &proc_dointvec,
+	},
+	{ .ctl_name = 0 }
+};
+
+const struct ctl_path net_vs_ctl_path[] = {
+	{ .procname = "net", .ctl_name = CTL_NET, },
+	{ .procname = "ipv4", .ctl_name = NET_IPV4, },
+	{ .procname = "vs", },
+	{ }
+};
+EXPORT_SYMBOL_GPL(net_vs_ctl_path);
+
+static struct ctl_table_header * sysctl_header;
+
+#ifdef CONFIG_PROC_FS
+
+struct ip_vs_iter {
+	struct list_head *table;
+	int bucket;
+};
+
+/*
+ *	Write the contents of the VS rule table to a PROCfs file.
+ *	(It is kept just for backward compatibility)
+ */
+static inline const char *ip_vs_fwd_name(unsigned flags)
+{
+	switch (flags & IP_VS_CONN_F_FWD_MASK) {
+	case IP_VS_CONN_F_LOCALNODE:
+		return "Local";
+	case IP_VS_CONN_F_TUNNEL:
+		return "Tunnel";
+	case IP_VS_CONN_F_DROUTE:
+		return "Route";
+	default:
+		return "Masq";
+	}
+}
+
+
+/* Get the Nth entry in the two lists */
+static struct ip_vs_service *ip_vs_info_array(struct seq_file *seq, loff_t pos)
+{
+	struct ip_vs_iter *iter = seq->private;
+	int idx;
+	struct ip_vs_service *svc;
+
+	/* look in hash by protocol */
+	for (idx = 0; idx < IP_VS_SVC_TAB_SIZE; idx++) {
+		list_for_each_entry(svc, &ip_vs_svc_table[idx], s_list) {
+			if (pos-- == 0){
+				iter->table = ip_vs_svc_table;
+				iter->bucket = idx;
+				return svc;
+			}
+		}
+	}
+
+	/* keep looking in fwmark */
+	for (idx = 0; idx < IP_VS_SVC_TAB_SIZE; idx++) {
+		list_for_each_entry(svc, &ip_vs_svc_fwm_table[idx], f_list) {
+			if (pos-- == 0) {
+				iter->table = ip_vs_svc_fwm_table;
+				iter->bucket = idx;
+				return svc;
+			}
+		}
+	}
+
+	return NULL;
+}
+
+static void *ip_vs_info_seq_start(struct seq_file *seq, loff_t *pos)
+__acquires(__ip_vs_svc_lock)
+{
+
+	read_lock_bh(&__ip_vs_svc_lock);
+	return *pos ? ip_vs_info_array(seq, *pos - 1) : SEQ_START_TOKEN;
+}
+
+
+static void *ip_vs_info_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+{
+	struct list_head *e;
+	struct ip_vs_iter *iter;
+	struct ip_vs_service *svc;
+
+	++*pos;
+	if (v == SEQ_START_TOKEN)
+		return ip_vs_info_array(seq,0);
+
+	svc = v;
+	iter = seq->private;
+
+	if (iter->table == ip_vs_svc_table) {
+		/* next service in table hashed by protocol */
+		if ((e = svc->s_list.next) != &ip_vs_svc_table[iter->bucket])
+			return list_entry(e, struct ip_vs_service, s_list);
+
+
+		while (++iter->bucket < IP_VS_SVC_TAB_SIZE) {
+			list_for_each_entry(svc,&ip_vs_svc_table[iter->bucket],
+					    s_list) {
+				return svc;
+			}
+		}
+
+		iter->table = ip_vs_svc_fwm_table;
+		iter->bucket = -1;
+		goto scan_fwmark;
+	}
+
+	/* next service in hashed by fwmark */
+	if ((e = svc->f_list.next) != &ip_vs_svc_fwm_table[iter->bucket])
+		return list_entry(e, struct ip_vs_service, f_list);
+
+ scan_fwmark:
+	while (++iter->bucket < IP_VS_SVC_TAB_SIZE) {
+		list_for_each_entry(svc, &ip_vs_svc_fwm_table[iter->bucket],
+				    f_list)
+			return svc;
+	}
+
+	return NULL;
+}
+
+static void ip_vs_info_seq_stop(struct seq_file *seq, void *v)
+__releases(__ip_vs_svc_lock)
+{
+	read_unlock_bh(&__ip_vs_svc_lock);
+}
+
+
+static int ip_vs_info_seq_show(struct seq_file *seq, void *v)
+{
+	if (v == SEQ_START_TOKEN) {
+		seq_printf(seq,
+			"IP Virtual Server version %d.%d.%d (size=%d)\n",
+			NVERSION(IP_VS_VERSION_CODE), IP_VS_CONN_TAB_SIZE);
+		seq_puts(seq,
+			 "Prot LocalAddress:Port Scheduler Flags\n");
+		seq_puts(seq,
+			 "  -> RemoteAddress:Port Forward Weight ActiveConn InActConn\n");
+	} else {
+		const struct ip_vs_service *svc = v;
+		const struct ip_vs_iter *iter = seq->private;
+		const struct ip_vs_dest *dest;
+
+		if (iter->table == ip_vs_svc_table) {
+#ifdef CONFIG_IP_VS_IPV6
+			if (svc->af == AF_INET6)
+				seq_printf(seq, "%s  [" NIP6_FMT "]:%04X %s ",
+					   ip_vs_proto_name(svc->protocol),
+					   NIP6(svc->addr.in6),
+					   ntohs(svc->port),
+					   svc->scheduler->name);
+			else
+#endif
+				seq_printf(seq, "%s  %08X:%04X %s ",
+					   ip_vs_proto_name(svc->protocol),
+					   ntohl(svc->addr.ip),
+					   ntohs(svc->port),
+					   svc->scheduler->name);
+		} else {
+			seq_printf(seq, "FWM  %08X %s ",
+				   svc->fwmark, svc->scheduler->name);
+		}
+
+		if (svc->flags & IP_VS_SVC_F_PERSISTENT)
+			seq_printf(seq, "persistent %d %08X\n",
+				svc->timeout,
+				ntohl(svc->netmask));
+		else
+			seq_putc(seq, '\n');
+
+		list_for_each_entry(dest, &svc->destinations, n_list) {
+#ifdef CONFIG_IP_VS_IPV6
+			if (dest->af == AF_INET6)
+				seq_printf(seq,
+					   "  -> [" NIP6_FMT "]:%04X"
+					   "      %-7s %-6d %-10d %-10d\n",
+					   NIP6(dest->addr.in6),
+					   ntohs(dest->port),
+					   ip_vs_fwd_name(atomic_read(&dest->conn_flags)),
+					   atomic_read(&dest->weight),
+					   atomic_read(&dest->activeconns),
+					   atomic_read(&dest->inactconns));
+			else
+#endif
+				seq_printf(seq,
+					   "  -> %08X:%04X      "
+					   "%-7s %-6d %-10d %-10d\n",
+					   ntohl(dest->addr.ip),
+					   ntohs(dest->port),
+					   ip_vs_fwd_name(atomic_read(&dest->conn_flags)),
+					   atomic_read(&dest->weight),
+					   atomic_read(&dest->activeconns),
+					   atomic_read(&dest->inactconns));
+
+		}
+	}
+	return 0;
+}
+
+static const struct seq_operations ip_vs_info_seq_ops = {
+	.start = ip_vs_info_seq_start,
+	.next  = ip_vs_info_seq_next,
+	.stop  = ip_vs_info_seq_stop,
+	.show  = ip_vs_info_seq_show,
+};
+
+static int ip_vs_info_open(struct inode *inode, struct file *file)
+{
+	return seq_open_private(file, &ip_vs_info_seq_ops,
+			sizeof(struct ip_vs_iter));
+}
+
+static const struct file_operations ip_vs_info_fops = {
+	.owner	 = THIS_MODULE,
+	.open    = ip_vs_info_open,
+	.read    = seq_read,
+	.llseek  = seq_lseek,
+	.release = seq_release_private,
+};
+
+#endif
+
+struct ip_vs_stats ip_vs_stats = {
+	.lock = __SPIN_LOCK_UNLOCKED(ip_vs_stats.lock),
+};
+
+#ifdef CONFIG_PROC_FS
+static int ip_vs_stats_show(struct seq_file *seq, void *v)
+{
+
+/*               01234567 01234567 01234567 0123456701234567 0123456701234567 */
+	seq_puts(seq,
+		 "   Total Incoming Outgoing         Incoming         Outgoing\n");
+	seq_printf(seq,
+		   "   Conns  Packets  Packets            Bytes            Bytes\n");
+
+	spin_lock_bh(&ip_vs_stats.lock);
+	seq_printf(seq, "%8X %8X %8X %16LX %16LX\n\n", ip_vs_stats.ustats.conns,
+		   ip_vs_stats.ustats.inpkts, ip_vs_stats.ustats.outpkts,
+		   (unsigned long long) ip_vs_stats.ustats.inbytes,
+		   (unsigned long long) ip_vs_stats.ustats.outbytes);
+
+/*                 01234567 01234567 01234567 0123456701234567 0123456701234567 */
+	seq_puts(seq,
+		   " Conns/s   Pkts/s   Pkts/s          Bytes/s          Bytes/s\n");
+	seq_printf(seq,"%8X %8X %8X %16X %16X\n",
+			ip_vs_stats.ustats.cps,
+			ip_vs_stats.ustats.inpps,
+			ip_vs_stats.ustats.outpps,
+			ip_vs_stats.ustats.inbps,
+			ip_vs_stats.ustats.outbps);
+	spin_unlock_bh(&ip_vs_stats.lock);
+
+	return 0;
+}
+
+static int ip_vs_stats_seq_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, ip_vs_stats_show, NULL);
+}
+
+static const struct file_operations ip_vs_stats_fops = {
+	.owner = THIS_MODULE,
+	.open = ip_vs_stats_seq_open,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = single_release,
+};
+
+#endif
+
+/*
+ *	Set timeout values for tcp tcpfin udp in the timeout_table.
+ */
+static int ip_vs_set_timeout(struct ip_vs_timeout_user *u)
+{
+	IP_VS_DBG(2, "Setting timeout tcp:%d tcpfin:%d udp:%d\n",
+		  u->tcp_timeout,
+		  u->tcp_fin_timeout,
+		  u->udp_timeout);
+
+#ifdef CONFIG_IP_VS_PROTO_TCP
+	if (u->tcp_timeout) {
+		ip_vs_protocol_tcp.timeout_table[IP_VS_TCP_S_ESTABLISHED]
+			= u->tcp_timeout * HZ;
+	}
+
+	if (u->tcp_fin_timeout) {
+		ip_vs_protocol_tcp.timeout_table[IP_VS_TCP_S_FIN_WAIT]
+			= u->tcp_fin_timeout * HZ;
+	}
+#endif
+
+#ifdef CONFIG_IP_VS_PROTO_UDP
+	if (u->udp_timeout) {
+		ip_vs_protocol_udp.timeout_table[IP_VS_UDP_S_NORMAL]
+			= u->udp_timeout * HZ;
+	}
+#endif
+	return 0;
+}
+
+
+#define SET_CMDID(cmd)		(cmd - IP_VS_BASE_CTL)
+#define SERVICE_ARG_LEN		(sizeof(struct ip_vs_service_user))
+#define SVCDEST_ARG_LEN		(sizeof(struct ip_vs_service_user) +	\
+				 sizeof(struct ip_vs_dest_user))
+#define TIMEOUT_ARG_LEN		(sizeof(struct ip_vs_timeout_user))
+#define DAEMON_ARG_LEN		(sizeof(struct ip_vs_daemon_user))
+#define MAX_ARG_LEN		SVCDEST_ARG_LEN
+
+static const unsigned char set_arglen[SET_CMDID(IP_VS_SO_SET_MAX)+1] = {
+	[SET_CMDID(IP_VS_SO_SET_ADD)]		= SERVICE_ARG_LEN,
+	[SET_CMDID(IP_VS_SO_SET_EDIT)]		= SERVICE_ARG_LEN,
+	[SET_CMDID(IP_VS_SO_SET_DEL)]		= SERVICE_ARG_LEN,
+	[SET_CMDID(IP_VS_SO_SET_FLUSH)]		= 0,
+	[SET_CMDID(IP_VS_SO_SET_ADDDEST)]	= SVCDEST_ARG_LEN,
+	[SET_CMDID(IP_VS_SO_SET_DELDEST)]	= SVCDEST_ARG_LEN,
+	[SET_CMDID(IP_VS_SO_SET_EDITDEST)]	= SVCDEST_ARG_LEN,
+	[SET_CMDID(IP_VS_SO_SET_TIMEOUT)]	= TIMEOUT_ARG_LEN,
+	[SET_CMDID(IP_VS_SO_SET_STARTDAEMON)]	= DAEMON_ARG_LEN,
+	[SET_CMDID(IP_VS_SO_SET_STOPDAEMON)]	= DAEMON_ARG_LEN,
+	[SET_CMDID(IP_VS_SO_SET_ZERO)]		= SERVICE_ARG_LEN,
+};
+
+static void ip_vs_copy_usvc_compat(struct ip_vs_service_user_kern *usvc,
+				  struct ip_vs_service_user *usvc_compat)
+{
+	usvc->af		= AF_INET;
+	usvc->protocol		= usvc_compat->protocol;
+	usvc->addr.ip		= usvc_compat->addr;
+	usvc->port		= usvc_compat->port;
+	usvc->fwmark		= usvc_compat->fwmark;
+
+	/* Deep copy of sched_name is not needed here */
+	usvc->sched_name	= usvc_compat->sched_name;
+
+	usvc->flags		= usvc_compat->flags;
+	usvc->timeout		= usvc_compat->timeout;
+	usvc->netmask		= usvc_compat->netmask;
+}
+
+static void ip_vs_copy_udest_compat(struct ip_vs_dest_user_kern *udest,
+				   struct ip_vs_dest_user *udest_compat)
+{
+	udest->addr.ip		= udest_compat->addr;
+	udest->port		= udest_compat->port;
+	udest->conn_flags	= udest_compat->conn_flags;
+	udest->weight		= udest_compat->weight;
+	udest->u_threshold	= udest_compat->u_threshold;
+	udest->l_threshold	= udest_compat->l_threshold;
+}
+
+static int
+do_ip_vs_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
+{
+	int ret;
+	unsigned char arg[MAX_ARG_LEN];
+	struct ip_vs_service_user *usvc_compat;
+	struct ip_vs_service_user_kern usvc;
+	struct ip_vs_service *svc;
+	struct ip_vs_dest_user *udest_compat;
+	struct ip_vs_dest_user_kern udest;
+
+	if (!capable(CAP_NET_ADMIN))
+		return -EPERM;
+
+	if (len != set_arglen[SET_CMDID(cmd)]) {
+		IP_VS_ERR("set_ctl: len %u != %u\n",
+			  len, set_arglen[SET_CMDID(cmd)]);
+		return -EINVAL;
+	}
+
+	if (copy_from_user(arg, user, len) != 0)
+		return -EFAULT;
+
+	/* increase the module use count */
+	ip_vs_use_count_inc();
+
+	if (mutex_lock_interruptible(&__ip_vs_mutex)) {
+		ret = -ERESTARTSYS;
+		goto out_dec;
+	}
+
+	if (cmd == IP_VS_SO_SET_FLUSH) {
+		/* Flush the virtual service */
+		ret = ip_vs_flush();
+		goto out_unlock;
+	} else if (cmd == IP_VS_SO_SET_TIMEOUT) {
+		/* Set timeout values for (tcp tcpfin udp) */
+		ret = ip_vs_set_timeout((struct ip_vs_timeout_user *)arg);
+		goto out_unlock;
+	} else if (cmd == IP_VS_SO_SET_STARTDAEMON) {
+		struct ip_vs_daemon_user *dm = (struct ip_vs_daemon_user *)arg;
+		ret = start_sync_thread(dm->state, dm->mcast_ifn, dm->syncid);
+		goto out_unlock;
+	} else if (cmd == IP_VS_SO_SET_STOPDAEMON) {
+		struct ip_vs_daemon_user *dm = (struct ip_vs_daemon_user *)arg;
+		ret = stop_sync_thread(dm->state);
+		goto out_unlock;
+	}
+
+	usvc_compat = (struct ip_vs_service_user *)arg;
+	udest_compat = (struct ip_vs_dest_user *)(usvc_compat + 1);
+
+	/* We only use the new structs internally, so copy userspace compat
+	 * structs to extended internal versions */
+	ip_vs_copy_usvc_compat(&usvc, usvc_compat);
+	ip_vs_copy_udest_compat(&udest, udest_compat);
+
+	if (cmd == IP_VS_SO_SET_ZERO) {
+		/* if no service address is set, zero counters in all */
+		if (!usvc.fwmark && !usvc.addr.ip && !usvc.port) {
+			ret = ip_vs_zero_all();
+			goto out_unlock;
+		}
+	}
+
+	/* Check for valid protocol: TCP or UDP, even for fwmark!=0 */
+	if (usvc.protocol != IPPROTO_TCP && usvc.protocol != IPPROTO_UDP) {
+		IP_VS_ERR("set_ctl: invalid protocol: %d %d.%d.%d.%d:%d %s\n",
+			  usvc.protocol, NIPQUAD(usvc.addr.ip),
+			  ntohs(usvc.port), usvc.sched_name);
+		ret = -EFAULT;
+		goto out_unlock;
+	}
+
+	/* Lookup the exact service by <protocol, addr, port> or fwmark */
+	if (usvc.fwmark == 0)
+		svc = __ip_vs_service_get(usvc.af, usvc.protocol,
+					  &usvc.addr, usvc.port);
+	else
+		svc = __ip_vs_svc_fwm_get(usvc.af, usvc.fwmark);
+
+	if (cmd != IP_VS_SO_SET_ADD
+	    && (svc == NULL || svc->protocol != usvc.protocol)) {
+		ret = -ESRCH;
+		goto out_unlock;
+	}
+
+	switch (cmd) {
+	case IP_VS_SO_SET_ADD:
+		if (svc != NULL)
+			ret = -EEXIST;
+		else
+			ret = ip_vs_add_service(&usvc, &svc);
+		break;
+	case IP_VS_SO_SET_EDIT:
+		ret = ip_vs_edit_service(svc, &usvc);
+		break;
+	case IP_VS_SO_SET_DEL:
+		ret = ip_vs_del_service(svc);
+		if (!ret)
+			goto out_unlock;
+		break;
+	case IP_VS_SO_SET_ZERO:
+		ret = ip_vs_zero_service(svc);
+		break;
+	case IP_VS_SO_SET_ADDDEST:
+		ret = ip_vs_add_dest(svc, &udest);
+		break;
+	case IP_VS_SO_SET_EDITDEST:
+		ret = ip_vs_edit_dest(svc, &udest);
+		break;
+	case IP_VS_SO_SET_DELDEST:
+		ret = ip_vs_del_dest(svc, &udest);
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+	if (svc)
+		ip_vs_service_put(svc);
+
+  out_unlock:
+	mutex_unlock(&__ip_vs_mutex);
+  out_dec:
+	/* decrease the module use count */
+	ip_vs_use_count_dec();
+
+	return ret;
+}
+
+
+static void
+ip_vs_copy_stats(struct ip_vs_stats_user *dst, struct ip_vs_stats *src)
+{
+	spin_lock_bh(&src->lock);
+	memcpy(dst, &src->ustats, sizeof(*dst));
+	spin_unlock_bh(&src->lock);
+}
+
+static void
+ip_vs_copy_service(struct ip_vs_service_entry *dst, struct ip_vs_service *src)
+{
+	dst->protocol = src->protocol;
+	dst->addr = src->addr.ip;
+	dst->port = src->port;
+	dst->fwmark = src->fwmark;
+	strlcpy(dst->sched_name, src->scheduler->name, sizeof(dst->sched_name));
+	dst->flags = src->flags;
+	dst->timeout = src->timeout / HZ;
+	dst->netmask = src->netmask;
+	dst->num_dests = src->num_dests;
+	ip_vs_copy_stats(&dst->stats, &src->stats);
+}
+
+static inline int
+__ip_vs_get_service_entries(const struct ip_vs_get_services *get,
+			    struct ip_vs_get_services __user *uptr)
+{
+	int idx, count=0;
+	struct ip_vs_service *svc;
+	struct ip_vs_service_entry entry;
+	int ret = 0;
+
+	for (idx = 0; idx < IP_VS_SVC_TAB_SIZE; idx++) {
+		list_for_each_entry(svc, &ip_vs_svc_table[idx], s_list) {
+			/* Only expose IPv4 entries to old interface */
+			if (svc->af != AF_INET)
+				continue;
+
+			if (count >= get->num_services)
+				goto out;
+			memset(&entry, 0, sizeof(entry));
+			ip_vs_copy_service(&entry, svc);
+			if (copy_to_user(&uptr->entrytable[count],
+					 &entry, sizeof(entry))) {
+				ret = -EFAULT;
+				goto out;
+			}
+			count++;
+		}
+	}
+
+	for (idx = 0; idx < IP_VS_SVC_TAB_SIZE; idx++) {
+		list_for_each_entry(svc, &ip_vs_svc_fwm_table[idx], f_list) {
+			/* Only expose IPv4 entries to old interface */
+			if (svc->af != AF_INET)
+				continue;
+
+			if (count >= get->num_services)
+				goto out;
+			memset(&entry, 0, sizeof(entry));
+			ip_vs_copy_service(&entry, svc);
+			if (copy_to_user(&uptr->entrytable[count],
+					 &entry, sizeof(entry))) {
+				ret = -EFAULT;
+				goto out;
+			}
+			count++;
+		}
+	}
+  out:
+	return ret;
+}
+
+static inline int
+__ip_vs_get_dest_entries(const struct ip_vs_get_dests *get,
+			 struct ip_vs_get_dests __user *uptr)
+{
+	struct ip_vs_service *svc;
+	union nf_inet_addr addr = { .ip = get->addr };
+	int ret = 0;
+
+	if (get->fwmark)
+		svc = __ip_vs_svc_fwm_get(AF_INET, get->fwmark);
+	else
+		svc = __ip_vs_service_get(AF_INET, get->protocol, &addr,
+					  get->port);
+
+	if (svc) {
+		int count = 0;
+		struct ip_vs_dest *dest;
+		struct ip_vs_dest_entry entry;
+
+		list_for_each_entry(dest, &svc->destinations, n_list) {
+			if (count >= get->num_dests)
+				break;
+
+			entry.addr = dest->addr.ip;
+			entry.port = dest->port;
+			entry.conn_flags = atomic_read(&dest->conn_flags);
+			entry.weight = atomic_read(&dest->weight);
+			entry.u_threshold = dest->u_threshold;
+			entry.l_threshold = dest->l_threshold;
+			entry.activeconns = atomic_read(&dest->activeconns);
+			entry.inactconns = atomic_read(&dest->inactconns);
+			entry.persistconns = atomic_read(&dest->persistconns);
+			ip_vs_copy_stats(&entry.stats, &dest->stats);
+			if (copy_to_user(&uptr->entrytable[count],
+					 &entry, sizeof(entry))) {
+				ret = -EFAULT;
+				break;
+			}
+			count++;
+		}
+		ip_vs_service_put(svc);
+	} else
+		ret = -ESRCH;
+	return ret;
+}
+
+static inline void
+__ip_vs_get_timeouts(struct ip_vs_timeout_user *u)
+{
+#ifdef CONFIG_IP_VS_PROTO_TCP
+	u->tcp_timeout =
+		ip_vs_protocol_tcp.timeout_table[IP_VS_TCP_S_ESTABLISHED] / HZ;
+	u->tcp_fin_timeout =
+		ip_vs_protocol_tcp.timeout_table[IP_VS_TCP_S_FIN_WAIT] / HZ;
+#endif
+#ifdef CONFIG_IP_VS_PROTO_UDP
+	u->udp_timeout =
+		ip_vs_protocol_udp.timeout_table[IP_VS_UDP_S_NORMAL] / HZ;
+#endif
+}
+
+
+#define GET_CMDID(cmd)		(cmd - IP_VS_BASE_CTL)
+#define GET_INFO_ARG_LEN	(sizeof(struct ip_vs_getinfo))
+#define GET_SERVICES_ARG_LEN	(sizeof(struct ip_vs_get_services))
+#define GET_SERVICE_ARG_LEN	(sizeof(struct ip_vs_service_entry))
+#define GET_DESTS_ARG_LEN	(sizeof(struct ip_vs_get_dests))
+#define GET_TIMEOUT_ARG_LEN	(sizeof(struct ip_vs_timeout_user))
+#define GET_DAEMON_ARG_LEN	(sizeof(struct ip_vs_daemon_user) * 2)
+
+static const unsigned char get_arglen[GET_CMDID(IP_VS_SO_GET_MAX)+1] = {
+	[GET_CMDID(IP_VS_SO_GET_VERSION)]	= 64,
+	[GET_CMDID(IP_VS_SO_GET_INFO)]		= GET_INFO_ARG_LEN,
+	[GET_CMDID(IP_VS_SO_GET_SERVICES)]	= GET_SERVICES_ARG_LEN,
+	[GET_CMDID(IP_VS_SO_GET_SERVICE)]	= GET_SERVICE_ARG_LEN,
+	[GET_CMDID(IP_VS_SO_GET_DESTS)]		= GET_DESTS_ARG_LEN,
+	[GET_CMDID(IP_VS_SO_GET_TIMEOUT)]	= GET_TIMEOUT_ARG_LEN,
+	[GET_CMDID(IP_VS_SO_GET_DAEMON)]	= GET_DAEMON_ARG_LEN,
+};
+
+static int
+do_ip_vs_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
+{
+	unsigned char arg[128];
+	int ret = 0;
+
+	if (!capable(CAP_NET_ADMIN))
+		return -EPERM;
+
+	if (*len < get_arglen[GET_CMDID(cmd)]) {
+		IP_VS_ERR("get_ctl: len %u < %u\n",
+			  *len, get_arglen[GET_CMDID(cmd)]);
+		return -EINVAL;
+	}
+
+	if (copy_from_user(arg, user, get_arglen[GET_CMDID(cmd)]) != 0)
+		return -EFAULT;
+
+	if (mutex_lock_interruptible(&__ip_vs_mutex))
+		return -ERESTARTSYS;
+
+	switch (cmd) {
+	case IP_VS_SO_GET_VERSION:
+	{
+		char buf[64];
+
+		sprintf(buf, "IP Virtual Server version %d.%d.%d (size=%d)",
+			NVERSION(IP_VS_VERSION_CODE), IP_VS_CONN_TAB_SIZE);
+		if (copy_to_user(user, buf, strlen(buf)+1) != 0) {
+			ret = -EFAULT;
+			goto out;
+		}
+		*len = strlen(buf)+1;
+	}
+	break;
+
+	case IP_VS_SO_GET_INFO:
+	{
+		struct ip_vs_getinfo info;
+		info.version = IP_VS_VERSION_CODE;
+		info.size = IP_VS_CONN_TAB_SIZE;
+		info.num_services = ip_vs_num_services;
+		if (copy_to_user(user, &info, sizeof(info)) != 0)
+			ret = -EFAULT;
+	}
+	break;
+
+	case IP_VS_SO_GET_SERVICES:
+	{
+		struct ip_vs_get_services *get;
+		int size;
+
+		get = (struct ip_vs_get_services *)arg;
+		size = sizeof(*get) +
+			sizeof(struct ip_vs_service_entry) * get->num_services;
+		if (*len != size) {
+			IP_VS_ERR("length: %u != %u\n", *len, size);
+			ret = -EINVAL;
+			goto out;
+		}
+		ret = __ip_vs_get_service_entries(get, user);
+	}
+	break;
+
+	case IP_VS_SO_GET_SERVICE:
+	{
+		struct ip_vs_service_entry *entry;
+		struct ip_vs_service *svc;
+		union nf_inet_addr addr;
+
+		entry = (struct ip_vs_service_entry *)arg;
+		addr.ip = entry->addr;
+		if (entry->fwmark)
+			svc = __ip_vs_svc_fwm_get(AF_INET, entry->fwmark);
+		else
+			svc = __ip_vs_service_get(AF_INET, entry->protocol,
+						  &addr, entry->port);
+		if (svc) {
+			ip_vs_copy_service(entry, svc);
+			if (copy_to_user(user, entry, sizeof(*entry)) != 0)
+				ret = -EFAULT;
+			ip_vs_service_put(svc);
+		} else
+			ret = -ESRCH;
+	}
+	break;
+
+	case IP_VS_SO_GET_DESTS:
+	{
+		struct ip_vs_get_dests *get;
+		int size;
+
+		get = (struct ip_vs_get_dests *)arg;
+		size = sizeof(*get) +
+			sizeof(struct ip_vs_dest_entry) * get->num_dests;
+		if (*len != size) {
+			IP_VS_ERR("length: %u != %u\n", *len, size);
+			ret = -EINVAL;
+			goto out;
+		}
+		ret = __ip_vs_get_dest_entries(get, user);
+	}
+	break;
+
+	case IP_VS_SO_GET_TIMEOUT:
+	{
+		struct ip_vs_timeout_user t;
+
+		__ip_vs_get_timeouts(&t);
+		if (copy_to_user(user, &t, sizeof(t)) != 0)
+			ret = -EFAULT;
+	}
+	break;
+
+	case IP_VS_SO_GET_DAEMON:
+	{
+		struct ip_vs_daemon_user d[2];
+
+		memset(&d, 0, sizeof(d));
+		if (ip_vs_sync_state & IP_VS_STATE_MASTER) {
+			d[0].state = IP_VS_STATE_MASTER;
+			strlcpy(d[0].mcast_ifn, ip_vs_master_mcast_ifn, sizeof(d[0].mcast_ifn));
+			d[0].syncid = ip_vs_master_syncid;
+		}
+		if (ip_vs_sync_state & IP_VS_STATE_BACKUP) {
+			d[1].state = IP_VS_STATE_BACKUP;
+			strlcpy(d[1].mcast_ifn, ip_vs_backup_mcast_ifn, sizeof(d[1].mcast_ifn));
+			d[1].syncid = ip_vs_backup_syncid;
+		}
+		if (copy_to_user(user, &d, sizeof(d)) != 0)
+			ret = -EFAULT;
+	}
+	break;
+
+	default:
+		ret = -EINVAL;
+	}
+
+  out:
+	mutex_unlock(&__ip_vs_mutex);
+	return ret;
+}
+
+
+static struct nf_sockopt_ops ip_vs_sockopts = {
+	.pf		= PF_INET,
+	.set_optmin	= IP_VS_BASE_CTL,
+	.set_optmax	= IP_VS_SO_SET_MAX+1,
+	.set		= do_ip_vs_set_ctl,
+	.get_optmin	= IP_VS_BASE_CTL,
+	.get_optmax	= IP_VS_SO_GET_MAX+1,
+	.get		= do_ip_vs_get_ctl,
+	.owner		= THIS_MODULE,
+};
+
+/*
+ * Generic Netlink interface
+ */
+
+/* IPVS genetlink family */
+static struct genl_family ip_vs_genl_family = {
+	.id		= GENL_ID_GENERATE,
+	.hdrsize	= 0,
+	.name		= IPVS_GENL_NAME,
+	.version	= IPVS_GENL_VERSION,
+	.maxattr	= IPVS_CMD_MAX,
+};
+
+/* Policy used for first-level command attributes */
+static const struct nla_policy ip_vs_cmd_policy[IPVS_CMD_ATTR_MAX + 1] = {
+	[IPVS_CMD_ATTR_SERVICE]		= { .type = NLA_NESTED },
+	[IPVS_CMD_ATTR_DEST]		= { .type = NLA_NESTED },
+	[IPVS_CMD_ATTR_DAEMON]		= { .type = NLA_NESTED },
+	[IPVS_CMD_ATTR_TIMEOUT_TCP]	= { .type = NLA_U32 },
+	[IPVS_CMD_ATTR_TIMEOUT_TCP_FIN]	= { .type = NLA_U32 },
+	[IPVS_CMD_ATTR_TIMEOUT_UDP]	= { .type = NLA_U32 },
+};
+
+/* Policy used for attributes in nested attribute IPVS_CMD_ATTR_DAEMON */
+static const struct nla_policy ip_vs_daemon_policy[IPVS_DAEMON_ATTR_MAX + 1] = {
+	[IPVS_DAEMON_ATTR_STATE]	= { .type = NLA_U32 },
+	[IPVS_DAEMON_ATTR_MCAST_IFN]	= { .type = NLA_NUL_STRING,
+					    .len = IP_VS_IFNAME_MAXLEN },
+	[IPVS_DAEMON_ATTR_SYNC_ID]	= { .type = NLA_U32 },
+};
+
+/* Policy used for attributes in nested attribute IPVS_CMD_ATTR_SERVICE */
+static const struct nla_policy ip_vs_svc_policy[IPVS_SVC_ATTR_MAX + 1] = {
+	[IPVS_SVC_ATTR_AF]		= { .type = NLA_U16 },
+	[IPVS_SVC_ATTR_PROTOCOL]	= { .type = NLA_U16 },
+	[IPVS_SVC_ATTR_ADDR]		= { .type = NLA_BINARY,
+					    .len = sizeof(union nf_inet_addr) },
+	[IPVS_SVC_ATTR_PORT]		= { .type = NLA_U16 },
+	[IPVS_SVC_ATTR_FWMARK]		= { .type = NLA_U32 },
+	[IPVS_SVC_ATTR_SCHED_NAME]	= { .type = NLA_NUL_STRING,
+					    .len = IP_VS_SCHEDNAME_MAXLEN },
+	[IPVS_SVC_ATTR_FLAGS]		= { .type = NLA_BINARY,
+					    .len = sizeof(struct ip_vs_flags) },
+	[IPVS_SVC_ATTR_TIMEOUT]		= { .type = NLA_U32 },
+	[IPVS_SVC_ATTR_NETMASK]		= { .type = NLA_U32 },
+	[IPVS_SVC_ATTR_STATS]		= { .type = NLA_NESTED },
+};
+
+/* Policy used for attributes in nested attribute IPVS_CMD_ATTR_DEST */
+static const struct nla_policy ip_vs_dest_policy[IPVS_DEST_ATTR_MAX + 1] = {
+	[IPVS_DEST_ATTR_ADDR]		= { .type = NLA_BINARY,
+					    .len = sizeof(union nf_inet_addr) },
+	[IPVS_DEST_ATTR_PORT]		= { .type = NLA_U16 },
+	[IPVS_DEST_ATTR_FWD_METHOD]	= { .type = NLA_U32 },
+	[IPVS_DEST_ATTR_WEIGHT]		= { .type = NLA_U32 },
+	[IPVS_DEST_ATTR_U_THRESH]	= { .type = NLA_U32 },
+	[IPVS_DEST_ATTR_L_THRESH]	= { .type = NLA_U32 },
+	[IPVS_DEST_ATTR_ACTIVE_CONNS]	= { .type = NLA_U32 },
+	[IPVS_DEST_ATTR_INACT_CONNS]	= { .type = NLA_U32 },
+	[IPVS_DEST_ATTR_PERSIST_CONNS]	= { .type = NLA_U32 },
+	[IPVS_DEST_ATTR_STATS]		= { .type = NLA_NESTED },
+};
+
+static int ip_vs_genl_fill_stats(struct sk_buff *skb, int container_type,
+				 struct ip_vs_stats *stats)
+{
+	struct nlattr *nl_stats = nla_nest_start(skb, container_type);
+	if (!nl_stats)
+		return -EMSGSIZE;
+
+	spin_lock_bh(&stats->lock);
+
+	NLA_PUT_U32(skb, IPVS_STATS_ATTR_CONNS, stats->ustats.conns);
+	NLA_PUT_U32(skb, IPVS_STATS_ATTR_INPKTS, stats->ustats.inpkts);
+	NLA_PUT_U32(skb, IPVS_STATS_ATTR_OUTPKTS, stats->ustats.outpkts);
+	NLA_PUT_U64(skb, IPVS_STATS_ATTR_INBYTES, stats->ustats.inbytes);
+	NLA_PUT_U64(skb, IPVS_STATS_ATTR_OUTBYTES, stats->ustats.outbytes);
+	NLA_PUT_U32(skb, IPVS_STATS_ATTR_CPS, stats->ustats.cps);
+	NLA_PUT_U32(skb, IPVS_STATS_ATTR_INPPS, stats->ustats.inpps);
+	NLA_PUT_U32(skb, IPVS_STATS_ATTR_OUTPPS, stats->ustats.outpps);
+	NLA_PUT_U32(skb, IPVS_STATS_ATTR_INBPS, stats->ustats.inbps);
+	NLA_PUT_U32(skb, IPVS_STATS_ATTR_OUTBPS, stats->ustats.outbps);
+
+	spin_unlock_bh(&stats->lock);
+
+	nla_nest_end(skb, nl_stats);
+
+	return 0;
+
+nla_put_failure:
+	spin_unlock_bh(&stats->lock);
+	nla_nest_cancel(skb, nl_stats);
+	return -EMSGSIZE;
+}
+
+static int ip_vs_genl_fill_service(struct sk_buff *skb,
+				   struct ip_vs_service *svc)
+{
+	struct nlattr *nl_service;
+	struct ip_vs_flags flags = { .flags = svc->flags,
+				     .mask = ~0 };
+
+	nl_service = nla_nest_start(skb, IPVS_CMD_ATTR_SERVICE);
+	if (!nl_service)
+		return -EMSGSIZE;
+
+	NLA_PUT_U16(skb, IPVS_SVC_ATTR_AF, svc->af);
+
+	if (svc->fwmark) {
+		NLA_PUT_U32(skb, IPVS_SVC_ATTR_FWMARK, svc->fwmark);
+	} else {
+		NLA_PUT_U16(skb, IPVS_SVC_ATTR_PROTOCOL, svc->protocol);
+		NLA_PUT(skb, IPVS_SVC_ATTR_ADDR, sizeof(svc->addr), &svc->addr);
+		NLA_PUT_U16(skb, IPVS_SVC_ATTR_PORT, svc->port);
+	}
+
+	NLA_PUT_STRING(skb, IPVS_SVC_ATTR_SCHED_NAME, svc->scheduler->name);
+	NLA_PUT(skb, IPVS_SVC_ATTR_FLAGS, sizeof(flags), &flags);
+	NLA_PUT_U32(skb, IPVS_SVC_ATTR_TIMEOUT, svc->timeout / HZ);
+	NLA_PUT_U32(skb, IPVS_SVC_ATTR_NETMASK, svc->netmask);
+
+	if (ip_vs_genl_fill_stats(skb, IPVS_SVC_ATTR_STATS, &svc->stats))
+		goto nla_put_failure;
+
+	nla_nest_end(skb, nl_service);
+
+	return 0;
+
+nla_put_failure:
+	nla_nest_cancel(skb, nl_service);
+	return -EMSGSIZE;
+}
+
+static int ip_vs_genl_dump_service(struct sk_buff *skb,
+				   struct ip_vs_service *svc,
+				   struct netlink_callback *cb)
+{
+	void *hdr;
+
+	hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).pid, cb->nlh->nlmsg_seq,
+			  &ip_vs_genl_family, NLM_F_MULTI,
+			  IPVS_CMD_NEW_SERVICE);
+	if (!hdr)
+		return -EMSGSIZE;
+
+	if (ip_vs_genl_fill_service(skb, svc) < 0)
+		goto nla_put_failure;
+
+	return genlmsg_end(skb, hdr);
+
+nla_put_failure:
+	genlmsg_cancel(skb, hdr);
+	return -EMSGSIZE;
+}
+
+static int ip_vs_genl_dump_services(struct sk_buff *skb,
+				    struct netlink_callback *cb)
+{
+	int idx = 0, i;
+	int start = cb->args[0];
+	struct ip_vs_service *svc;
+
+	mutex_lock(&__ip_vs_mutex);
+	for (i = 0; i < IP_VS_SVC_TAB_SIZE; i++) {
+		list_for_each_entry(svc, &ip_vs_svc_table[i], s_list) {
+			if (++idx <= start)
+				continue;
+			if (ip_vs_genl_dump_service(skb, svc, cb) < 0) {
+				idx--;
+				goto nla_put_failure;
+			}
+		}
+	}
+
+	for (i = 0; i < IP_VS_SVC_TAB_SIZE; i++) {
+		list_for_each_entry(svc, &ip_vs_svc_fwm_table[i], f_list) {
+			if (++idx <= start)
+				continue;
+			if (ip_vs_genl_dump_service(skb, svc, cb) < 0) {
+				idx--;
+				goto nla_put_failure;
+			}
+		}
+	}
+
+nla_put_failure:
+	mutex_unlock(&__ip_vs_mutex);
+	cb->args[0] = idx;
+
+	return skb->len;
+}
+
+static int ip_vs_genl_parse_service(struct ip_vs_service_user_kern *usvc,
+				    struct nlattr *nla, int full_entry)
+{
+	struct nlattr *attrs[IPVS_SVC_ATTR_MAX + 1];
+	struct nlattr *nla_af, *nla_port, *nla_fwmark, *nla_protocol, *nla_addr;
+
+	/* Parse mandatory identifying service fields first */
+	if (nla == NULL ||
+	    nla_parse_nested(attrs, IPVS_SVC_ATTR_MAX, nla, ip_vs_svc_policy))
+		return -EINVAL;
+
+	nla_af		= attrs[IPVS_SVC_ATTR_AF];
+	nla_protocol	= attrs[IPVS_SVC_ATTR_PROTOCOL];
+	nla_addr	= attrs[IPVS_SVC_ATTR_ADDR];
+	nla_port	= attrs[IPVS_SVC_ATTR_PORT];
+	nla_fwmark	= attrs[IPVS_SVC_ATTR_FWMARK];
+
+	if (!(nla_af && (nla_fwmark || (nla_port && nla_protocol && nla_addr))))
+		return -EINVAL;
+
+	usvc->af = nla_get_u16(nla_af);
+#ifdef CONFIG_IP_VS_IPV6
+	if (usvc->af != AF_INET && usvc->af != AF_INET6)
+#else
+	if (usvc->af != AF_INET)
+#endif
+		return -EAFNOSUPPORT;
+
+	if (nla_fwmark) {
+		usvc->protocol = IPPROTO_TCP;
+		usvc->fwmark = nla_get_u32(nla_fwmark);
+	} else {
+		usvc->protocol = nla_get_u16(nla_protocol);
+		nla_memcpy(&usvc->addr, nla_addr, sizeof(usvc->addr));
+		usvc->port = nla_get_u16(nla_port);
+		usvc->fwmark = 0;
+	}
+
+	/* If a full entry was requested, check for the additional fields */
+	if (full_entry) {
+		struct nlattr *nla_sched, *nla_flags, *nla_timeout,
+			      *nla_netmask;
+		struct ip_vs_flags flags;
+		struct ip_vs_service *svc;
+
+		nla_sched = attrs[IPVS_SVC_ATTR_SCHED_NAME];
+		nla_flags = attrs[IPVS_SVC_ATTR_FLAGS];
+		nla_timeout = attrs[IPVS_SVC_ATTR_TIMEOUT];
+		nla_netmask = attrs[IPVS_SVC_ATTR_NETMASK];
+
+		if (!(nla_sched && nla_flags && nla_timeout && nla_netmask))
+			return -EINVAL;
+
+		nla_memcpy(&flags, nla_flags, sizeof(flags));
+
+		/* prefill flags from service if it already exists */
+		if (usvc->fwmark)
+			svc = __ip_vs_svc_fwm_get(usvc->af, usvc->fwmark);
+		else
+			svc = __ip_vs_service_get(usvc->af, usvc->protocol,
+						  &usvc->addr, usvc->port);
+		if (svc) {
+			usvc->flags = svc->flags;
+			ip_vs_service_put(svc);
+		} else
+			usvc->flags = 0;
+
+		/* set new flags from userland */
+		usvc->flags = (usvc->flags & ~flags.mask) |
+			      (flags.flags & flags.mask);
+		usvc->sched_name = nla_data(nla_sched);
+		usvc->timeout = nla_get_u32(nla_timeout);
+		usvc->netmask = nla_get_u32(nla_netmask);
+	}
+
+	return 0;
+}
+
+static struct ip_vs_service *ip_vs_genl_find_service(struct nlattr *nla)
+{
+	struct ip_vs_service_user_kern usvc;
+	int ret;
+
+	ret = ip_vs_genl_parse_service(&usvc, nla, 0);
+	if (ret)
+		return ERR_PTR(ret);
+
+	if (usvc.fwmark)
+		return __ip_vs_svc_fwm_get(usvc.af, usvc.fwmark);
+	else
+		return __ip_vs_service_get(usvc.af, usvc.protocol,
+					   &usvc.addr, usvc.port);
+}
+
+static int ip_vs_genl_fill_dest(struct sk_buff *skb, struct ip_vs_dest *dest)
+{
+	struct nlattr *nl_dest;
+
+	nl_dest = nla_nest_start(skb, IPVS_CMD_ATTR_DEST);
+	if (!nl_dest)
+		return -EMSGSIZE;
+
+	NLA_PUT(skb, IPVS_DEST_ATTR_ADDR, sizeof(dest->addr), &dest->addr);
+	NLA_PUT_U16(skb, IPVS_DEST_ATTR_PORT, dest->port);
+
+	NLA_PUT_U32(skb, IPVS_DEST_ATTR_FWD_METHOD,
+		    atomic_read(&dest->conn_flags) & IP_VS_CONN_F_FWD_MASK);
+	NLA_PUT_U32(skb, IPVS_DEST_ATTR_WEIGHT, atomic_read(&dest->weight));
+	NLA_PUT_U32(skb, IPVS_DEST_ATTR_U_THRESH, dest->u_threshold);
+	NLA_PUT_U32(skb, IPVS_DEST_ATTR_L_THRESH, dest->l_threshold);
+	NLA_PUT_U32(skb, IPVS_DEST_ATTR_ACTIVE_CONNS,
+		    atomic_read(&dest->activeconns));
+	NLA_PUT_U32(skb, IPVS_DEST_ATTR_INACT_CONNS,
+		    atomic_read(&dest->inactconns));
+	NLA_PUT_U32(skb, IPVS_DEST_ATTR_PERSIST_CONNS,
+		    atomic_read(&dest->persistconns));
+
+	if (ip_vs_genl_fill_stats(skb, IPVS_DEST_ATTR_STATS, &dest->stats))
+		goto nla_put_failure;
+
+	nla_nest_end(skb, nl_dest);
+
+	return 0;
+
+nla_put_failure:
+	nla_nest_cancel(skb, nl_dest);
+	return -EMSGSIZE;
+}
+
+static int ip_vs_genl_dump_dest(struct sk_buff *skb, struct ip_vs_dest *dest,
+				struct netlink_callback *cb)
+{
+	void *hdr;
+
+	hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).pid, cb->nlh->nlmsg_seq,
+			  &ip_vs_genl_family, NLM_F_MULTI,
+			  IPVS_CMD_NEW_DEST);
+	if (!hdr)
+		return -EMSGSIZE;
+
+	if (ip_vs_genl_fill_dest(skb, dest) < 0)
+		goto nla_put_failure;
+
+	return genlmsg_end(skb, hdr);
+
+nla_put_failure:
+	genlmsg_cancel(skb, hdr);
+	return -EMSGSIZE;
+}
+
+static int ip_vs_genl_dump_dests(struct sk_buff *skb,
+				 struct netlink_callback *cb)
+{
+	int idx = 0;
+	int start = cb->args[0];
+	struct ip_vs_service *svc;
+	struct ip_vs_dest *dest;
+	struct nlattr *attrs[IPVS_CMD_ATTR_MAX + 1];
+
+	mutex_lock(&__ip_vs_mutex);
+
+	/* Try to find the service for which to dump destinations */
+	if (nlmsg_parse(cb->nlh, GENL_HDRLEN, attrs,
+			IPVS_CMD_ATTR_MAX, ip_vs_cmd_policy))
+		goto out_err;
+
+	svc = ip_vs_genl_find_service(attrs[IPVS_CMD_ATTR_SERVICE]);
+	if (IS_ERR(svc) || svc == NULL)
+		goto out_err;
+
+	/* Dump the destinations */
+	list_for_each_entry(dest, &svc->destinations, n_list) {
+		if (++idx <= start)
+			continue;
+		if (ip_vs_genl_dump_dest(skb, dest, cb) < 0) {
+			idx--;
+			goto nla_put_failure;
+		}
+	}
+
+nla_put_failure:
+	cb->args[0] = idx;
+	ip_vs_service_put(svc);
+
+out_err:
+	mutex_unlock(&__ip_vs_mutex);
+
+	return skb->len;
+}
+
+static int ip_vs_genl_parse_dest(struct ip_vs_dest_user_kern *udest,
+				 struct nlattr *nla, int full_entry)
+{
+	struct nlattr *attrs[IPVS_DEST_ATTR_MAX + 1];
+	struct nlattr *nla_addr, *nla_port;
+
+	/* Parse mandatory identifying destination fields first */
+	if (nla == NULL ||
+	    nla_parse_nested(attrs, IPVS_DEST_ATTR_MAX, nla, ip_vs_dest_policy))
+		return -EINVAL;
+
+	nla_addr	= attrs[IPVS_DEST_ATTR_ADDR];
+	nla_port	= attrs[IPVS_DEST_ATTR_PORT];
+
+	if (!(nla_addr && nla_port))
+		return -EINVAL;
+
+	nla_memcpy(&udest->addr, nla_addr, sizeof(udest->addr));
+	udest->port = nla_get_u16(nla_port);
+
+	/* If a full entry was requested, check for the additional fields */
+	if (full_entry) {
+		struct nlattr *nla_fwd, *nla_weight, *nla_u_thresh,
+			      *nla_l_thresh;
+
+		nla_fwd		= attrs[IPVS_DEST_ATTR_FWD_METHOD];
+		nla_weight	= attrs[IPVS_DEST_ATTR_WEIGHT];
+		nla_u_thresh	= attrs[IPVS_DEST_ATTR_U_THRESH];
+		nla_l_thresh	= attrs[IPVS_DEST_ATTR_L_THRESH];
+
+		if (!(nla_fwd && nla_weight && nla_u_thresh && nla_l_thresh))
+			return -EINVAL;
+
+		udest->conn_flags = nla_get_u32(nla_fwd)
+				    & IP_VS_CONN_F_FWD_MASK;
+		udest->weight = nla_get_u32(nla_weight);
+		udest->u_threshold = nla_get_u32(nla_u_thresh);
+		udest->l_threshold = nla_get_u32(nla_l_thresh);
+	}
+
+	return 0;
+}
+
+static int ip_vs_genl_fill_daemon(struct sk_buff *skb, __be32 state,
+				  const char *mcast_ifn, __be32 syncid)
+{
+	struct nlattr *nl_daemon;
+
+	nl_daemon = nla_nest_start(skb, IPVS_CMD_ATTR_DAEMON);
+	if (!nl_daemon)
+		return -EMSGSIZE;
+
+	NLA_PUT_U32(skb, IPVS_DAEMON_ATTR_STATE, state);
+	NLA_PUT_STRING(skb, IPVS_DAEMON_ATTR_MCAST_IFN, mcast_ifn);
+	NLA_PUT_U32(skb, IPVS_DAEMON_ATTR_SYNC_ID, syncid);
+
+	nla_nest_end(skb, nl_daemon);
+
+	return 0;
+
+nla_put_failure:
+	nla_nest_cancel(skb, nl_daemon);
+	return -EMSGSIZE;
+}
+
+static int ip_vs_genl_dump_daemon(struct sk_buff *skb, __be32 state,
+				  const char *mcast_ifn, __be32 syncid,
+				  struct netlink_callback *cb)
+{
+	void *hdr;
+	hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).pid, cb->nlh->nlmsg_seq,
+			  &ip_vs_genl_family, NLM_F_MULTI,
+			  IPVS_CMD_NEW_DAEMON);
+	if (!hdr)
+		return -EMSGSIZE;
+
+	if (ip_vs_genl_fill_daemon(skb, state, mcast_ifn, syncid))
+		goto nla_put_failure;
+
+	return genlmsg_end(skb, hdr);
+
+nla_put_failure:
+	genlmsg_cancel(skb, hdr);
+	return -EMSGSIZE;
+}
+
+static int ip_vs_genl_dump_daemons(struct sk_buff *skb,
+				   struct netlink_callback *cb)
+{
+	mutex_lock(&__ip_vs_mutex);
+	if ((ip_vs_sync_state & IP_VS_STATE_MASTER) && !cb->args[0]) {
+		if (ip_vs_genl_dump_daemon(skb, IP_VS_STATE_MASTER,
+					   ip_vs_master_mcast_ifn,
+					   ip_vs_master_syncid, cb) < 0)
+			goto nla_put_failure;
+
+		cb->args[0] = 1;
+	}
+
+	if ((ip_vs_sync_state & IP_VS_STATE_BACKUP) && !cb->args[1]) {
+		if (ip_vs_genl_dump_daemon(skb, IP_VS_STATE_BACKUP,
+					   ip_vs_backup_mcast_ifn,
+					   ip_vs_backup_syncid, cb) < 0)
+			goto nla_put_failure;
+
+		cb->args[1] = 1;
+	}
+
+nla_put_failure:
+	mutex_unlock(&__ip_vs_mutex);
+
+	return skb->len;
+}
+
+static int ip_vs_genl_new_daemon(struct nlattr **attrs)
+{
+	if (!(attrs[IPVS_DAEMON_ATTR_STATE] &&
+	      attrs[IPVS_DAEMON_ATTR_MCAST_IFN] &&
+	      attrs[IPVS_DAEMON_ATTR_SYNC_ID]))
+		return -EINVAL;
+
+	return start_sync_thread(nla_get_u32(attrs[IPVS_DAEMON_ATTR_STATE]),
+				 nla_data(attrs[IPVS_DAEMON_ATTR_MCAST_IFN]),
+				 nla_get_u32(attrs[IPVS_DAEMON_ATTR_SYNC_ID]));
+}
+
+static int ip_vs_genl_del_daemon(struct nlattr **attrs)
+{
+	if (!attrs[IPVS_DAEMON_ATTR_STATE])
+		return -EINVAL;
+
+	return stop_sync_thread(nla_get_u32(attrs[IPVS_DAEMON_ATTR_STATE]));
+}
+
+static int ip_vs_genl_set_config(struct nlattr **attrs)
+{
+	struct ip_vs_timeout_user t;
+
+	__ip_vs_get_timeouts(&t);
+
+	if (attrs[IPVS_CMD_ATTR_TIMEOUT_TCP])
+		t.tcp_timeout = nla_get_u32(attrs[IPVS_CMD_ATTR_TIMEOUT_TCP]);
+
+	if (attrs[IPVS_CMD_ATTR_TIMEOUT_TCP_FIN])
+		t.tcp_fin_timeout =
+			nla_get_u32(attrs[IPVS_CMD_ATTR_TIMEOUT_TCP_FIN]);
+
+	if (attrs[IPVS_CMD_ATTR_TIMEOUT_UDP])
+		t.udp_timeout = nla_get_u32(attrs[IPVS_CMD_ATTR_TIMEOUT_UDP]);
+
+	return ip_vs_set_timeout(&t);
+}
+
+static int ip_vs_genl_set_cmd(struct sk_buff *skb, struct genl_info *info)
+{
+	struct ip_vs_service *svc = NULL;
+	struct ip_vs_service_user_kern usvc;
+	struct ip_vs_dest_user_kern udest;
+	int ret = 0, cmd;
+	int need_full_svc = 0, need_full_dest = 0;
+
+	cmd = info->genlhdr->cmd;
+
+	mutex_lock(&__ip_vs_mutex);
+
+	if (cmd == IPVS_CMD_FLUSH) {
+		ret = ip_vs_flush();
+		goto out;
+	} else if (cmd == IPVS_CMD_SET_CONFIG) {
+		ret = ip_vs_genl_set_config(info->attrs);
+		goto out;
+	} else if (cmd == IPVS_CMD_NEW_DAEMON ||
+		   cmd == IPVS_CMD_DEL_DAEMON) {
+
+		struct nlattr *daemon_attrs[IPVS_DAEMON_ATTR_MAX + 1];
+
+		if (!info->attrs[IPVS_CMD_ATTR_DAEMON] ||
+		    nla_parse_nested(daemon_attrs, IPVS_DAEMON_ATTR_MAX,
+				     info->attrs[IPVS_CMD_ATTR_DAEMON],
+				     ip_vs_daemon_policy)) {
+			ret = -EINVAL;
+			goto out;
+		}
+
+		if (cmd == IPVS_CMD_NEW_DAEMON)
+			ret = ip_vs_genl_new_daemon(daemon_attrs);
+		else
+			ret = ip_vs_genl_del_daemon(daemon_attrs);
+		goto out;
+	} else if (cmd == IPVS_CMD_ZERO &&
+		   !info->attrs[IPVS_CMD_ATTR_SERVICE]) {
+		ret = ip_vs_zero_all();
+		goto out;
+	}
+
+	/* All following commands require a service argument, so check if we
+	 * received a valid one. We need a full service specification when
+	 * adding / editing a service. Only identifying members otherwise. */
+	if (cmd == IPVS_CMD_NEW_SERVICE || cmd == IPVS_CMD_SET_SERVICE)
+		need_full_svc = 1;
+
+	ret = ip_vs_genl_parse_service(&usvc,
+				       info->attrs[IPVS_CMD_ATTR_SERVICE],
+				       need_full_svc);
+	if (ret)
+		goto out;
+
+	/* Lookup the exact service by <protocol, addr, port> or fwmark */
+	if (usvc.fwmark == 0)
+		svc = __ip_vs_service_get(usvc.af, usvc.protocol,
+					  &usvc.addr, usvc.port);
+	else
+		svc = __ip_vs_svc_fwm_get(usvc.af, usvc.fwmark);
+
+	/* Unless we're adding a new service, the service must already exist */
+	if ((cmd != IPVS_CMD_NEW_SERVICE) && (svc == NULL)) {
+		ret = -ESRCH;
+		goto out;
+	}
+
+	/* Destination commands require a valid destination argument. For
+	 * adding / editing a destination, we need a full destination
+	 * specification. */
+	if (cmd == IPVS_CMD_NEW_DEST || cmd == IPVS_CMD_SET_DEST ||
+	    cmd == IPVS_CMD_DEL_DEST) {
+		if (cmd != IPVS_CMD_DEL_DEST)
+			need_full_dest = 1;
+
+		ret = ip_vs_genl_parse_dest(&udest,
+					    info->attrs[IPVS_CMD_ATTR_DEST],
+					    need_full_dest);
+		if (ret)
+			goto out;
+	}
+
+	switch (cmd) {
+	case IPVS_CMD_NEW_SERVICE:
+		if (svc == NULL)
+			ret = ip_vs_add_service(&usvc, &svc);
+		else
+			ret = -EEXIST;
+		break;
+	case IPVS_CMD_SET_SERVICE:
+		ret = ip_vs_edit_service(svc, &usvc);
+		break;
+	case IPVS_CMD_DEL_SERVICE:
+		ret = ip_vs_del_service(svc);
+		break;
+	case IPVS_CMD_NEW_DEST:
+		ret = ip_vs_add_dest(svc, &udest);
+		break;
+	case IPVS_CMD_SET_DEST:
+		ret = ip_vs_edit_dest(svc, &udest);
+		break;
+	case IPVS_CMD_DEL_DEST:
+		ret = ip_vs_del_dest(svc, &udest);
+		break;
+	case IPVS_CMD_ZERO:
+		ret = ip_vs_zero_service(svc);
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+out:
+	if (svc)
+		ip_vs_service_put(svc);
+	mutex_unlock(&__ip_vs_mutex);
+
+	return ret;
+}
+
+static int ip_vs_genl_get_cmd(struct sk_buff *skb, struct genl_info *info)
+{
+	struct sk_buff *msg;
+	void *reply;
+	int ret, cmd, reply_cmd;
+
+	cmd = info->genlhdr->cmd;
+
+	if (cmd == IPVS_CMD_GET_SERVICE)
+		reply_cmd = IPVS_CMD_NEW_SERVICE;
+	else if (cmd == IPVS_CMD_GET_INFO)
+		reply_cmd = IPVS_CMD_SET_INFO;
+	else if (cmd == IPVS_CMD_GET_CONFIG)
+		reply_cmd = IPVS_CMD_SET_CONFIG;
+	else {
+		IP_VS_ERR("unknown Generic Netlink command\n");
+		return -EINVAL;
+	}
+
+	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
+	if (!msg)
+		return -ENOMEM;
+
+	mutex_lock(&__ip_vs_mutex);
+
+	reply = genlmsg_put_reply(msg, info, &ip_vs_genl_family, 0, reply_cmd);
+	if (reply == NULL)
+		goto nla_put_failure;
+
+	switch (cmd) {
+	case IPVS_CMD_GET_SERVICE:
+	{
+		struct ip_vs_service *svc;
+
+		svc = ip_vs_genl_find_service(info->attrs[IPVS_CMD_ATTR_SERVICE]);
+		if (IS_ERR(svc)) {
+			ret = PTR_ERR(svc);
+			goto out_err;
+		} else if (svc) {
+			ret = ip_vs_genl_fill_service(msg, svc);
+			ip_vs_service_put(svc);
+			if (ret)
+				goto nla_put_failure;
+		} else {
+			ret = -ESRCH;
+			goto out_err;
+		}
+
+		break;
+	}
+
+	case IPVS_CMD_GET_CONFIG:
+	{
+		struct ip_vs_timeout_user t;
+
+		__ip_vs_get_timeouts(&t);
+#ifdef CONFIG_IP_VS_PROTO_TCP
+		NLA_PUT_U32(msg, IPVS_CMD_ATTR_TIMEOUT_TCP, t.tcp_timeout);
+		NLA_PUT_U32(msg, IPVS_CMD_ATTR_TIMEOUT_TCP_FIN,
+			    t.tcp_fin_timeout);
+#endif
+#ifdef CONFIG_IP_VS_PROTO_UDP
+		NLA_PUT_U32(msg, IPVS_CMD_ATTR_TIMEOUT_UDP, t.udp_timeout);
+#endif
+
+		break;
+	}
+
+	case IPVS_CMD_GET_INFO:
+		NLA_PUT_U32(msg, IPVS_INFO_ATTR_VERSION, IP_VS_VERSION_CODE);
+		NLA_PUT_U32(msg, IPVS_INFO_ATTR_CONN_TAB_SIZE,
+			    IP_VS_CONN_TAB_SIZE);
+		break;
+	}
+
+	genlmsg_end(msg, reply);
+	ret = genlmsg_unicast(msg, info->snd_pid);
+	goto out;
+
+nla_put_failure:
+	IP_VS_ERR("not enough space in Netlink message\n");
+	ret = -EMSGSIZE;
+
+out_err:
+	nlmsg_free(msg);
+out:
+	mutex_unlock(&__ip_vs_mutex);
+
+	return ret;
+}
+
+
+static struct genl_ops ip_vs_genl_ops[] __read_mostly = {
+	{
+		.cmd	= IPVS_CMD_NEW_SERVICE,
+		.flags	= GENL_ADMIN_PERM,
+		.policy	= ip_vs_cmd_policy,
+		.doit	= ip_vs_genl_set_cmd,
+	},
+	{
+		.cmd	= IPVS_CMD_SET_SERVICE,
+		.flags	= GENL_ADMIN_PERM,
+		.policy	= ip_vs_cmd_policy,
+		.doit	= ip_vs_genl_set_cmd,
+	},
+	{
+		.cmd	= IPVS_CMD_DEL_SERVICE,
+		.flags	= GENL_ADMIN_PERM,
+		.policy	= ip_vs_cmd_policy,
+		.doit	= ip_vs_genl_set_cmd,
+	},
+	{
+		.cmd	= IPVS_CMD_GET_SERVICE,
+		.flags	= GENL_ADMIN_PERM,
+		.doit	= ip_vs_genl_get_cmd,
+		.dumpit	= ip_vs_genl_dump_services,
+		.policy	= ip_vs_cmd_policy,
+	},
+	{
+		.cmd	= IPVS_CMD_NEW_DEST,
+		.flags	= GENL_ADMIN_PERM,
+		.policy	= ip_vs_cmd_policy,
+		.doit	= ip_vs_genl_set_cmd,
+	},
+	{
+		.cmd	= IPVS_CMD_SET_DEST,
+		.flags	= GENL_ADMIN_PERM,
+		.policy	= ip_vs_cmd_policy,
+		.doit	= ip_vs_genl_set_cmd,
+	},
+	{
+		.cmd	= IPVS_CMD_DEL_DEST,
+		.flags	= GENL_ADMIN_PERM,
+		.policy	= ip_vs_cmd_policy,
+		.doit	= ip_vs_genl_set_cmd,
+	},
+	{
+		.cmd	= IPVS_CMD_GET_DEST,
+		.flags	= GENL_ADMIN_PERM,
+		.policy	= ip_vs_cmd_policy,
+		.dumpit	= ip_vs_genl_dump_dests,
+	},
+	{
+		.cmd	= IPVS_CMD_NEW_DAEMON,
+		.flags	= GENL_ADMIN_PERM,
+		.policy	= ip_vs_cmd_policy,
+		.doit	= ip_vs_genl_set_cmd,
+	},
+	{
+		.cmd	= IPVS_CMD_DEL_DAEMON,
+		.flags	= GENL_ADMIN_PERM,
+		.policy	= ip_vs_cmd_policy,
+		.doit	= ip_vs_genl_set_cmd,
+	},
+	{
+		.cmd	= IPVS_CMD_GET_DAEMON,
+		.flags	= GENL_ADMIN_PERM,
+		.dumpit	= ip_vs_genl_dump_daemons,
+	},
+	{
+		.cmd	= IPVS_CMD_SET_CONFIG,
+		.flags	= GENL_ADMIN_PERM,
+		.policy	= ip_vs_cmd_policy,
+		.doit	= ip_vs_genl_set_cmd,
+	},
+	{
+		.cmd	= IPVS_CMD_GET_CONFIG,
+		.flags	= GENL_ADMIN_PERM,
+		.doit	= ip_vs_genl_get_cmd,
+	},
+	{
+		.cmd	= IPVS_CMD_GET_INFO,
+		.flags	= GENL_ADMIN_PERM,
+		.doit	= ip_vs_genl_get_cmd,
+	},
+	{
+		.cmd	= IPVS_CMD_ZERO,
+		.flags	= GENL_ADMIN_PERM,
+		.policy	= ip_vs_cmd_policy,
+		.doit	= ip_vs_genl_set_cmd,
+	},
+	{
+		.cmd	= IPVS_CMD_FLUSH,
+		.flags	= GENL_ADMIN_PERM,
+		.doit	= ip_vs_genl_set_cmd,
+	},
+};
+
+static int __init ip_vs_genl_register(void)
+{
+	int ret, i;
+
+	ret = genl_register_family(&ip_vs_genl_family);
+	if (ret)
+		return ret;
+
+	for (i = 0; i < ARRAY_SIZE(ip_vs_genl_ops); i++) {
+		ret = genl_register_ops(&ip_vs_genl_family, &ip_vs_genl_ops[i]);
+		if (ret)
+			goto err_out;
+	}
+	return 0;
+
+err_out:
+	genl_unregister_family(&ip_vs_genl_family);
+	return ret;
+}
+
+static void ip_vs_genl_unregister(void)
+{
+	genl_unregister_family(&ip_vs_genl_family);
+}
+
+/* End of Generic Netlink interface definitions */
+
+
+int __init ip_vs_control_init(void)
+{
+	int ret;
+	int idx;
+
+	EnterFunction(2);
+
+	ret = nf_register_sockopt(&ip_vs_sockopts);
+	if (ret) {
+		IP_VS_ERR("cannot register sockopt.\n");
+		return ret;
+	}
+
+	ret = ip_vs_genl_register();
+	if (ret) {
+		IP_VS_ERR("cannot register Generic Netlink interface.\n");
+		nf_unregister_sockopt(&ip_vs_sockopts);
+		return ret;
+	}
+
+	proc_net_fops_create(&init_net, "ip_vs", 0, &ip_vs_info_fops);
+	proc_net_fops_create(&init_net, "ip_vs_stats",0, &ip_vs_stats_fops);
+
+	sysctl_header = register_sysctl_paths(net_vs_ctl_path, vs_vars);
+
+	/* Initialize ip_vs_svc_table, ip_vs_svc_fwm_table, ip_vs_rtable */
+	for(idx = 0; idx < IP_VS_SVC_TAB_SIZE; idx++)  {
+		INIT_LIST_HEAD(&ip_vs_svc_table[idx]);
+		INIT_LIST_HEAD(&ip_vs_svc_fwm_table[idx]);
+	}
+	for(idx = 0; idx < IP_VS_RTAB_SIZE; idx++)  {
+		INIT_LIST_HEAD(&ip_vs_rtable[idx]);
+	}
+
+	ip_vs_new_estimator(&ip_vs_stats);
+
+	/* Hook the defense timer */
+	schedule_delayed_work(&defense_work, DEFENSE_TIMER_PERIOD);
+
+	LeaveFunction(2);
+	return 0;
+}
+
+
+void ip_vs_control_cleanup(void)
+{
+	EnterFunction(2);
+	ip_vs_trash_cleanup();
+	cancel_rearming_delayed_work(&defense_work);
+	cancel_work_sync(&defense_work.work);
+	ip_vs_kill_estimator(&ip_vs_stats);
+	unregister_sysctl_table(sysctl_header);
+	proc_net_remove(&init_net, "ip_vs_stats");
+	proc_net_remove(&init_net, "ip_vs");
+	ip_vs_genl_unregister();
+	nf_unregister_sockopt(&ip_vs_sockopts);
+	LeaveFunction(2);
+}
diff --git a/net/netfilter/ipvs/ip_vs_dh.c b/net/netfilter/ipvs/ip_vs_dh.c
new file mode 100644
index 0000000..a16943f
--- /dev/null
+++ b/net/netfilter/ipvs/ip_vs_dh.c
@@ -0,0 +1,261 @@
+/*
+ * IPVS:        Destination Hashing scheduling module
+ *
+ * Authors:     Wensong Zhang <wensong@gnuchina.org>
+ *
+ *              Inspired by the consistent hashing scheduler patch from
+ *              Thomas Proell <proellt@gmx.de>
+ *
+ *              This program is free software; you can redistribute it and/or
+ *              modify it under the terms of the GNU General Public License
+ *              as published by the Free Software Foundation; either version
+ *              2 of the License, or (at your option) any later version.
+ *
+ * Changes:
+ *
+ */
+
+/*
+ * The dh algorithm is to select server by the hash key of destination IP
+ * address. The pseudo code is as follows:
+ *
+ *       n <- servernode[dest_ip];
+ *       if (n is dead) OR
+ *          (n is overloaded) OR (n.weight <= 0) then
+ *                 return NULL;
+ *
+ *       return n;
+ *
+ * Notes that servernode is a 256-bucket hash table that maps the hash
+ * index derived from packet destination IP address to the current server
+ * array. If the dh scheduler is used in cache cluster, it is good to
+ * combine it with cache_bypass feature. When the statically assigned
+ * server is dead or overloaded, the load balancer can bypass the cache
+ * server and send requests to the original server directly.
+ *
+ */
+
+#include <linux/ip.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/skbuff.h>
+
+#include <net/ip_vs.h>
+
+
+/*
+ *      IPVS DH bucket
+ */
+struct ip_vs_dh_bucket {
+	struct ip_vs_dest       *dest;          /* real server (cache) */
+};
+
+/*
+ *     for IPVS DH entry hash table
+ */
+#ifndef CONFIG_IP_VS_DH_TAB_BITS
+#define CONFIG_IP_VS_DH_TAB_BITS        8
+#endif
+#define IP_VS_DH_TAB_BITS               CONFIG_IP_VS_DH_TAB_BITS
+#define IP_VS_DH_TAB_SIZE               (1 << IP_VS_DH_TAB_BITS)
+#define IP_VS_DH_TAB_MASK               (IP_VS_DH_TAB_SIZE - 1)
+
+
+/*
+ *	Returns hash value for IPVS DH entry
+ */
+static inline unsigned ip_vs_dh_hashkey(__be32 addr)
+{
+	return (ntohl(addr)*2654435761UL) & IP_VS_DH_TAB_MASK;
+}
+
+
+/*
+ *      Get ip_vs_dest associated with supplied parameters.
+ */
+static inline struct ip_vs_dest *
+ip_vs_dh_get(struct ip_vs_dh_bucket *tbl, __be32 addr)
+{
+	return (tbl[ip_vs_dh_hashkey(addr)]).dest;
+}
+
+
+/*
+ *      Assign all the hash buckets of the specified table with the service.
+ */
+static int
+ip_vs_dh_assign(struct ip_vs_dh_bucket *tbl, struct ip_vs_service *svc)
+{
+	int i;
+	struct ip_vs_dh_bucket *b;
+	struct list_head *p;
+	struct ip_vs_dest *dest;
+
+	b = tbl;
+	p = &svc->destinations;
+	for (i=0; i<IP_VS_DH_TAB_SIZE; i++) {
+		if (list_empty(p)) {
+			b->dest = NULL;
+		} else {
+			if (p == &svc->destinations)
+				p = p->next;
+
+			dest = list_entry(p, struct ip_vs_dest, n_list);
+			atomic_inc(&dest->refcnt);
+			b->dest = dest;
+
+			p = p->next;
+		}
+		b++;
+	}
+	return 0;
+}
+
+
+/*
+ *      Flush all the hash buckets of the specified table.
+ */
+static void ip_vs_dh_flush(struct ip_vs_dh_bucket *tbl)
+{
+	int i;
+	struct ip_vs_dh_bucket *b;
+
+	b = tbl;
+	for (i=0; i<IP_VS_DH_TAB_SIZE; i++) {
+		if (b->dest) {
+			atomic_dec(&b->dest->refcnt);
+			b->dest = NULL;
+		}
+		b++;
+	}
+}
+
+
+static int ip_vs_dh_init_svc(struct ip_vs_service *svc)
+{
+	struct ip_vs_dh_bucket *tbl;
+
+	/* allocate the DH table for this service */
+	tbl = kmalloc(sizeof(struct ip_vs_dh_bucket)*IP_VS_DH_TAB_SIZE,
+		      GFP_ATOMIC);
+	if (tbl == NULL) {
+		IP_VS_ERR("ip_vs_dh_init_svc(): no memory\n");
+		return -ENOMEM;
+	}
+	svc->sched_data = tbl;
+	IP_VS_DBG(6, "DH hash table (memory=%Zdbytes) allocated for "
+		  "current service\n",
+		  sizeof(struct ip_vs_dh_bucket)*IP_VS_DH_TAB_SIZE);
+
+	/* assign the hash buckets with the updated service */
+	ip_vs_dh_assign(tbl, svc);
+
+	return 0;
+}
+
+
+static int ip_vs_dh_done_svc(struct ip_vs_service *svc)
+{
+	struct ip_vs_dh_bucket *tbl = svc->sched_data;
+
+	/* got to clean up hash buckets here */
+	ip_vs_dh_flush(tbl);
+
+	/* release the table itself */
+	kfree(svc->sched_data);
+	IP_VS_DBG(6, "DH hash table (memory=%Zdbytes) released\n",
+		  sizeof(struct ip_vs_dh_bucket)*IP_VS_DH_TAB_SIZE);
+
+	return 0;
+}
+
+
+static int ip_vs_dh_update_svc(struct ip_vs_service *svc)
+{
+	struct ip_vs_dh_bucket *tbl = svc->sched_data;
+
+	/* got to clean up hash buckets here */
+	ip_vs_dh_flush(tbl);
+
+	/* assign the hash buckets with the updated service */
+	ip_vs_dh_assign(tbl, svc);
+
+	return 0;
+}
+
+
+/*
+ *      If the dest flags is set with IP_VS_DEST_F_OVERLOAD,
+ *      consider that the server is overloaded here.
+ */
+static inline int is_overloaded(struct ip_vs_dest *dest)
+{
+	return dest->flags & IP_VS_DEST_F_OVERLOAD;
+}
+
+
+/*
+ *      Destination hashing scheduling
+ */
+static struct ip_vs_dest *
+ip_vs_dh_schedule(struct ip_vs_service *svc, const struct sk_buff *skb)
+{
+	struct ip_vs_dest *dest;
+	struct ip_vs_dh_bucket *tbl;
+	struct iphdr *iph = ip_hdr(skb);
+
+	IP_VS_DBG(6, "ip_vs_dh_schedule(): Scheduling...\n");
+
+	tbl = (struct ip_vs_dh_bucket *)svc->sched_data;
+	dest = ip_vs_dh_get(tbl, iph->daddr);
+	if (!dest
+	    || !(dest->flags & IP_VS_DEST_F_AVAILABLE)
+	    || atomic_read(&dest->weight) <= 0
+	    || is_overloaded(dest)) {
+		return NULL;
+	}
+
+	IP_VS_DBG(6, "DH: destination IP address %u.%u.%u.%u "
+		  "--> server %u.%u.%u.%u:%d\n",
+		  NIPQUAD(iph->daddr),
+		  NIPQUAD(dest->addr.ip),
+		  ntohs(dest->port));
+
+	return dest;
+}
+
+
+/*
+ *      IPVS DH Scheduler structure
+ */
+static struct ip_vs_scheduler ip_vs_dh_scheduler =
+{
+	.name =			"dh",
+	.refcnt =		ATOMIC_INIT(0),
+	.module =		THIS_MODULE,
+	.n_list =		LIST_HEAD_INIT(ip_vs_dh_scheduler.n_list),
+#ifdef CONFIG_IP_VS_IPV6
+	.supports_ipv6 =	0,
+#endif
+	.init_service =		ip_vs_dh_init_svc,
+	.done_service =		ip_vs_dh_done_svc,
+	.update_service =	ip_vs_dh_update_svc,
+	.schedule =		ip_vs_dh_schedule,
+};
+
+
+static int __init ip_vs_dh_init(void)
+{
+	return register_ip_vs_scheduler(&ip_vs_dh_scheduler);
+}
+
+
+static void __exit ip_vs_dh_cleanup(void)
+{
+	unregister_ip_vs_scheduler(&ip_vs_dh_scheduler);
+}
+
+
+module_init(ip_vs_dh_init);
+module_exit(ip_vs_dh_cleanup);
+MODULE_LICENSE("GPL");
diff --git a/net/netfilter/ipvs/ip_vs_est.c b/net/netfilter/ipvs/ip_vs_est.c
new file mode 100644
index 0000000..2eb2860
--- /dev/null
+++ b/net/netfilter/ipvs/ip_vs_est.c
@@ -0,0 +1,166 @@
+/*
+ * ip_vs_est.c: simple rate estimator for IPVS
+ *
+ * Authors:     Wensong Zhang <wensong@linuxvirtualserver.org>
+ *
+ *              This program is free software; you can redistribute it and/or
+ *              modify it under the terms of the GNU General Public License
+ *              as published by the Free Software Foundation; either version
+ *              2 of the License, or (at your option) any later version.
+ *
+ * Changes:
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/jiffies.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/sysctl.h>
+#include <linux/list.h>
+
+#include <net/ip_vs.h>
+
+/*
+  This code is to estimate rate in a shorter interval (such as 8
+  seconds) for virtual services and real servers. For measure rate in a
+  long interval, it is easy to implement a user level daemon which
+  periodically reads those statistical counters and measure rate.
+
+  Currently, the measurement is activated by slow timer handler. Hope
+  this measurement will not introduce too much load.
+
+  We measure rate during the last 8 seconds every 2 seconds:
+
+    avgrate = avgrate*(1-W) + rate*W
+
+    where W = 2^(-2)
+
+  NOTES.
+
+  * The stored value for average bps is scaled by 2^5, so that maximal
+    rate is ~2.15Gbits/s, average pps and cps are scaled by 2^10.
+
+  * A lot code is taken from net/sched/estimator.c
+ */
+
+
+static void estimation_timer(unsigned long arg);
+
+static LIST_HEAD(est_list);
+static DEFINE_SPINLOCK(est_lock);
+static DEFINE_TIMER(est_timer, estimation_timer, 0, 0);
+
+static void estimation_timer(unsigned long arg)
+{
+	struct ip_vs_estimator *e;
+	struct ip_vs_stats *s;
+	u32 n_conns;
+	u32 n_inpkts, n_outpkts;
+	u64 n_inbytes, n_outbytes;
+	u32 rate;
+
+	spin_lock(&est_lock);
+	list_for_each_entry(e, &est_list, list) {
+		s = container_of(e, struct ip_vs_stats, est);
+
+		spin_lock(&s->lock);
+		n_conns = s->ustats.conns;
+		n_inpkts = s->ustats.inpkts;
+		n_outpkts = s->ustats.outpkts;
+		n_inbytes = s->ustats.inbytes;
+		n_outbytes = s->ustats.outbytes;
+
+		/* scaled by 2^10, but divided 2 seconds */
+		rate = (n_conns - e->last_conns)<<9;
+		e->last_conns = n_conns;
+		e->cps += ((long)rate - (long)e->cps)>>2;
+		s->ustats.cps = (e->cps+0x1FF)>>10;
+
+		rate = (n_inpkts - e->last_inpkts)<<9;
+		e->last_inpkts = n_inpkts;
+		e->inpps += ((long)rate - (long)e->inpps)>>2;
+		s->ustats.inpps = (e->inpps+0x1FF)>>10;
+
+		rate = (n_outpkts - e->last_outpkts)<<9;
+		e->last_outpkts = n_outpkts;
+		e->outpps += ((long)rate - (long)e->outpps)>>2;
+		s->ustats.outpps = (e->outpps+0x1FF)>>10;
+
+		rate = (n_inbytes - e->last_inbytes)<<4;
+		e->last_inbytes = n_inbytes;
+		e->inbps += ((long)rate - (long)e->inbps)>>2;
+		s->ustats.inbps = (e->inbps+0xF)>>5;
+
+		rate = (n_outbytes - e->last_outbytes)<<4;
+		e->last_outbytes = n_outbytes;
+		e->outbps += ((long)rate - (long)e->outbps)>>2;
+		s->ustats.outbps = (e->outbps+0xF)>>5;
+		spin_unlock(&s->lock);
+	}
+	spin_unlock(&est_lock);
+	mod_timer(&est_timer, jiffies + 2*HZ);
+}
+
+void ip_vs_new_estimator(struct ip_vs_stats *stats)
+{
+	struct ip_vs_estimator *est = &stats->est;
+
+	INIT_LIST_HEAD(&est->list);
+
+	est->last_conns = stats->ustats.conns;
+	est->cps = stats->ustats.cps<<10;
+
+	est->last_inpkts = stats->ustats.inpkts;
+	est->inpps = stats->ustats.inpps<<10;
+
+	est->last_outpkts = stats->ustats.outpkts;
+	est->outpps = stats->ustats.outpps<<10;
+
+	est->last_inbytes = stats->ustats.inbytes;
+	est->inbps = stats->ustats.inbps<<5;
+
+	est->last_outbytes = stats->ustats.outbytes;
+	est->outbps = stats->ustats.outbps<<5;
+
+	spin_lock_bh(&est_lock);
+	list_add(&est->list, &est_list);
+	spin_unlock_bh(&est_lock);
+}
+
+void ip_vs_kill_estimator(struct ip_vs_stats *stats)
+{
+	struct ip_vs_estimator *est = &stats->est;
+
+	spin_lock_bh(&est_lock);
+	list_del(&est->list);
+	spin_unlock_bh(&est_lock);
+}
+
+void ip_vs_zero_estimator(struct ip_vs_stats *stats)
+{
+	struct ip_vs_estimator *est = &stats->est;
+
+	/* set counters zero, caller must hold the stats->lock lock */
+	est->last_inbytes = 0;
+	est->last_outbytes = 0;
+	est->last_conns = 0;
+	est->last_inpkts = 0;
+	est->last_outpkts = 0;
+	est->cps = 0;
+	est->inpps = 0;
+	est->outpps = 0;
+	est->inbps = 0;
+	est->outbps = 0;
+}
+
+int __init ip_vs_estimator_init(void)
+{
+	mod_timer(&est_timer, jiffies + 2 * HZ);
+	return 0;
+}
+
+void ip_vs_estimator_cleanup(void)
+{
+	del_timer_sync(&est_timer);
+}
diff --git a/net/netfilter/ipvs/ip_vs_ftp.c b/net/netfilter/ipvs/ip_vs_ftp.c
new file mode 100644
index 0000000..2e7dbd8
--- /dev/null
+++ b/net/netfilter/ipvs/ip_vs_ftp.c
@@ -0,0 +1,410 @@
+/*
+ * ip_vs_ftp.c: IPVS ftp application module
+ *
+ * Authors:	Wensong Zhang <wensong@linuxvirtualserver.org>
+ *
+ * Changes:
+ *
+ *
+ *	This program is free software; you can redistribute it and/or
+ *	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.
+ *
+ * Most code here is taken from ip_masq_ftp.c in kernel 2.2. The difference
+ * is that ip_vs_ftp module handles the reverse direction to ip_masq_ftp.
+ *
+ *		IP_MASQ_FTP ftp masquerading module
+ *
+ * Version:	@(#)ip_masq_ftp.c 0.04   02/05/96
+ *
+ * Author:	Wouter Gadeyne
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/skbuff.h>
+#include <linux/in.h>
+#include <linux/ip.h>
+#include <linux/netfilter.h>
+#include <net/protocol.h>
+#include <net/tcp.h>
+#include <asm/unaligned.h>
+
+#include <net/ip_vs.h>
+
+
+#define SERVER_STRING "227 Entering Passive Mode ("
+#define CLIENT_STRING "PORT "
+
+
+/*
+ * List of ports (up to IP_VS_APP_MAX_PORTS) to be handled by helper
+ * First port is set to the default port.
+ */
+static unsigned short ports[IP_VS_APP_MAX_PORTS] = {21, 0};
+module_param_array(ports, ushort, NULL, 0);
+MODULE_PARM_DESC(ports, "Ports to monitor for FTP control commands");
+
+
+/*	Dummy variable */
+static int ip_vs_ftp_pasv;
+
+
+static int
+ip_vs_ftp_init_conn(struct ip_vs_app *app, struct ip_vs_conn *cp)
+{
+	return 0;
+}
+
+
+static int
+ip_vs_ftp_done_conn(struct ip_vs_app *app, struct ip_vs_conn *cp)
+{
+	return 0;
+}
+
+
+/*
+ * Get <addr,port> from the string "xxx.xxx.xxx.xxx,ppp,ppp", started
+ * with the "pattern" and terminated with the "term" character.
+ * <addr,port> is in network order.
+ */
+static int ip_vs_ftp_get_addrport(char *data, char *data_limit,
+				  const char *pattern, size_t plen, char term,
+				  __be32 *addr, __be16 *port,
+				  char **start, char **end)
+{
+	unsigned char p[6];
+	int i = 0;
+
+	if (data_limit - data < plen) {
+		/* check if there is partial match */
+		if (strnicmp(data, pattern, data_limit - data) == 0)
+			return -1;
+		else
+			return 0;
+	}
+
+	if (strnicmp(data, pattern, plen) != 0) {
+		return 0;
+	}
+	*start = data + plen;
+
+	for (data = *start; *data != term; data++) {
+		if (data == data_limit)
+			return -1;
+	}
+	*end = data;
+
+	memset(p, 0, sizeof(p));
+	for (data = *start; data != *end; data++) {
+		if (*data >= '0' && *data <= '9') {
+			p[i] = p[i]*10 + *data - '0';
+		} else if (*data == ',' && i < 5) {
+			i++;
+		} else {
+			/* unexpected character */
+			return -1;
+		}
+	}
+
+	if (i != 5)
+		return -1;
+
+	*addr = get_unaligned((__be32 *)p);
+	*port = get_unaligned((__be16 *)(p + 4));
+	return 1;
+}
+
+
+/*
+ * Look at outgoing ftp packets to catch the response to a PASV command
+ * from the server (inside-to-outside).
+ * When we see one, we build a connection entry with the client address,
+ * client port 0 (unknown at the moment), the server address and the
+ * server port.  Mark the current connection entry as a control channel
+ * of the new entry. All this work is just to make the data connection
+ * can be scheduled to the right server later.
+ *
+ * The outgoing packet should be something like
+ *   "227 Entering Passive Mode (xxx,xxx,xxx,xxx,ppp,ppp)".
+ * xxx,xxx,xxx,xxx is the server address, ppp,ppp is the server port number.
+ */
+static int ip_vs_ftp_out(struct ip_vs_app *app, struct ip_vs_conn *cp,
+			 struct sk_buff *skb, int *diff)
+{
+	struct iphdr *iph;
+	struct tcphdr *th;
+	char *data, *data_limit;
+	char *start, *end;
+	union nf_inet_addr from;
+	__be16 port;
+	struct ip_vs_conn *n_cp;
+	char buf[24];		/* xxx.xxx.xxx.xxx,ppp,ppp\000 */
+	unsigned buf_len;
+	int ret;
+
+#ifdef CONFIG_IP_VS_IPV6
+	/* This application helper doesn't work with IPv6 yet,
+	 * so turn this into a no-op for IPv6 packets
+	 */
+	if (cp->af == AF_INET6)
+		return 1;
+#endif
+
+	*diff = 0;
+
+	/* Only useful for established sessions */
+	if (cp->state != IP_VS_TCP_S_ESTABLISHED)
+		return 1;
+
+	/* Linear packets are much easier to deal with. */
+	if (!skb_make_writable(skb, skb->len))
+		return 0;
+
+	if (cp->app_data == &ip_vs_ftp_pasv) {
+		iph = ip_hdr(skb);
+		th = (struct tcphdr *)&(((char *)iph)[iph->ihl*4]);
+		data = (char *)th + (th->doff << 2);
+		data_limit = skb_tail_pointer(skb);
+
+		if (ip_vs_ftp_get_addrport(data, data_limit,
+					   SERVER_STRING,
+					   sizeof(SERVER_STRING)-1, ')',
+					   &from.ip, &port,
+					   &start, &end) != 1)
+			return 1;
+
+		IP_VS_DBG(7, "PASV response (%u.%u.%u.%u:%d) -> "
+			  "%u.%u.%u.%u:%d detected\n",
+			  NIPQUAD(from.ip), ntohs(port),
+			  NIPQUAD(cp->caddr.ip), 0);
+
+		/*
+		 * Now update or create an connection entry for it
+		 */
+		n_cp = ip_vs_conn_out_get(AF_INET, iph->protocol, &from, port,
+					  &cp->caddr, 0);
+		if (!n_cp) {
+			n_cp = ip_vs_conn_new(AF_INET, IPPROTO_TCP,
+					      &cp->caddr, 0,
+					      &cp->vaddr, port,
+					      &from, port,
+					      IP_VS_CONN_F_NO_CPORT,
+					      cp->dest);
+			if (!n_cp)
+				return 0;
+
+			/* add its controller */
+			ip_vs_control_add(n_cp, cp);
+		}
+
+		/*
+		 * Replace the old passive address with the new one
+		 */
+		from.ip = n_cp->vaddr.ip;
+		port = n_cp->vport;
+		sprintf(buf, "%d,%d,%d,%d,%d,%d", NIPQUAD(from.ip),
+			(ntohs(port)>>8)&255, ntohs(port)&255);
+		buf_len = strlen(buf);
+
+		/*
+		 * Calculate required delta-offset to keep TCP happy
+		 */
+		*diff = buf_len - (end-start);
+
+		if (*diff == 0) {
+			/* simply replace it with new passive address */
+			memcpy(start, buf, buf_len);
+			ret = 1;
+		} else {
+			ret = !ip_vs_skb_replace(skb, GFP_ATOMIC, start,
+					  end-start, buf, buf_len);
+		}
+
+		cp->app_data = NULL;
+		ip_vs_tcp_conn_listen(n_cp);
+		ip_vs_conn_put(n_cp);
+		return ret;
+	}
+	return 1;
+}
+
+
+/*
+ * Look at incoming ftp packets to catch the PASV/PORT command
+ * (outside-to-inside).
+ *
+ * The incoming packet having the PORT command should be something like
+ *      "PORT xxx,xxx,xxx,xxx,ppp,ppp\n".
+ * xxx,xxx,xxx,xxx is the client address, ppp,ppp is the client port number.
+ * In this case, we create a connection entry using the client address and
+ * port, so that the active ftp data connection from the server can reach
+ * the client.
+ */
+static int ip_vs_ftp_in(struct ip_vs_app *app, struct ip_vs_conn *cp,
+			struct sk_buff *skb, int *diff)
+{
+	struct iphdr *iph;
+	struct tcphdr *th;
+	char *data, *data_start, *data_limit;
+	char *start, *end;
+	union nf_inet_addr to;
+	__be16 port;
+	struct ip_vs_conn *n_cp;
+
+#ifdef CONFIG_IP_VS_IPV6
+	/* This application helper doesn't work with IPv6 yet,
+	 * so turn this into a no-op for IPv6 packets
+	 */
+	if (cp->af == AF_INET6)
+		return 1;
+#endif
+
+	/* no diff required for incoming packets */
+	*diff = 0;
+
+	/* Only useful for established sessions */
+	if (cp->state != IP_VS_TCP_S_ESTABLISHED)
+		return 1;
+
+	/* Linear packets are much easier to deal with. */
+	if (!skb_make_writable(skb, skb->len))
+		return 0;
+
+	/*
+	 * Detecting whether it is passive
+	 */
+	iph = ip_hdr(skb);
+	th = (struct tcphdr *)&(((char *)iph)[iph->ihl*4]);
+
+	/* Since there may be OPTIONS in the TCP packet and the HLEN is
+	   the length of the header in 32-bit multiples, it is accurate
+	   to calculate data address by th+HLEN*4 */
+	data = data_start = (char *)th + (th->doff << 2);
+	data_limit = skb_tail_pointer(skb);
+
+	while (data <= data_limit - 6) {
+		if (strnicmp(data, "PASV\r\n", 6) == 0) {
+			/* Passive mode on */
+			IP_VS_DBG(7, "got PASV at %td of %td\n",
+				  data - data_start,
+				  data_limit - data_start);
+			cp->app_data = &ip_vs_ftp_pasv;
+			return 1;
+		}
+		data++;
+	}
+
+	/*
+	 * To support virtual FTP server, the scenerio is as follows:
+	 *       FTP client ----> Load Balancer ----> FTP server
+	 * First detect the port number in the application data,
+	 * then create a new connection entry for the coming data
+	 * connection.
+	 */
+	if (ip_vs_ftp_get_addrport(data_start, data_limit,
+				   CLIENT_STRING, sizeof(CLIENT_STRING)-1,
+				   '\r', &to.ip, &port,
+				   &start, &end) != 1)
+		return 1;
+
+	IP_VS_DBG(7, "PORT %u.%u.%u.%u:%d detected\n",
+		  NIPQUAD(to.ip), ntohs(port));
+
+	/* Passive mode off */
+	cp->app_data = NULL;
+
+	/*
+	 * Now update or create a connection entry for it
+	 */
+	IP_VS_DBG(7, "protocol %s %u.%u.%u.%u:%d %u.%u.%u.%u:%d\n",
+		  ip_vs_proto_name(iph->protocol),
+		  NIPQUAD(to.ip), ntohs(port), NIPQUAD(cp->vaddr.ip), 0);
+
+	n_cp = ip_vs_conn_in_get(AF_INET, iph->protocol,
+				 &to, port,
+				 &cp->vaddr, htons(ntohs(cp->vport)-1));
+	if (!n_cp) {
+		n_cp = ip_vs_conn_new(AF_INET, IPPROTO_TCP,
+				      &to, port,
+				      &cp->vaddr, htons(ntohs(cp->vport)-1),
+				      &cp->daddr, htons(ntohs(cp->dport)-1),
+				      0,
+				      cp->dest);
+		if (!n_cp)
+			return 0;
+
+		/* add its controller */
+		ip_vs_control_add(n_cp, cp);
+	}
+
+	/*
+	 *	Move tunnel to listen state
+	 */
+	ip_vs_tcp_conn_listen(n_cp);
+	ip_vs_conn_put(n_cp);
+
+	return 1;
+}
+
+
+static struct ip_vs_app ip_vs_ftp = {
+	.name =		"ftp",
+	.type =		IP_VS_APP_TYPE_FTP,
+	.protocol =	IPPROTO_TCP,
+	.module =	THIS_MODULE,
+	.incs_list =	LIST_HEAD_INIT(ip_vs_ftp.incs_list),
+	.init_conn =	ip_vs_ftp_init_conn,
+	.done_conn =	ip_vs_ftp_done_conn,
+	.bind_conn =	NULL,
+	.unbind_conn =	NULL,
+	.pkt_out =	ip_vs_ftp_out,
+	.pkt_in =	ip_vs_ftp_in,
+};
+
+
+/*
+ *	ip_vs_ftp initialization
+ */
+static int __init ip_vs_ftp_init(void)
+{
+	int i, ret;
+	struct ip_vs_app *app = &ip_vs_ftp;
+
+	ret = register_ip_vs_app(app);
+	if (ret)
+		return ret;
+
+	for (i=0; i<IP_VS_APP_MAX_PORTS; i++) {
+		if (!ports[i])
+			continue;
+		ret = register_ip_vs_app_inc(app, app->protocol, ports[i]);
+		if (ret)
+			break;
+		IP_VS_INFO("%s: loaded support on port[%d] = %d\n",
+			   app->name, i, ports[i]);
+	}
+
+	if (ret)
+		unregister_ip_vs_app(app);
+
+	return ret;
+}
+
+
+/*
+ *	ip_vs_ftp finish.
+ */
+static void __exit ip_vs_ftp_exit(void)
+{
+	unregister_ip_vs_app(&ip_vs_ftp);
+}
+
+
+module_init(ip_vs_ftp_init);
+module_exit(ip_vs_ftp_exit);
+MODULE_LICENSE("GPL");
diff --git a/net/netfilter/ipvs/ip_vs_lblc.c b/net/netfilter/ipvs/ip_vs_lblc.c
new file mode 100644
index 0000000..6ecef35
--- /dev/null
+++ b/net/netfilter/ipvs/ip_vs_lblc.c
@@ -0,0 +1,555 @@
+/*
+ * IPVS:        Locality-Based Least-Connection scheduling module
+ *
+ * Authors:     Wensong Zhang <wensong@gnuchina.org>
+ *
+ *              This program is free software; you can redistribute it and/or
+ *              modify it under the terms of the GNU General Public License
+ *              as published by the Free Software Foundation; either version
+ *              2 of the License, or (at your option) any later version.
+ *
+ * Changes:
+ *     Martin Hamilton         :    fixed the terrible locking bugs
+ *                                   *lock(tbl->lock) ==> *lock(&tbl->lock)
+ *     Wensong Zhang           :    fixed the uninitilized tbl->lock bug
+ *     Wensong Zhang           :    added doing full expiration check to
+ *                                   collect stale entries of 24+ hours when
+ *                                   no partial expire check in a half hour
+ *     Julian Anastasov        :    replaced del_timer call with del_timer_sync
+ *                                   to avoid the possible race between timer
+ *                                   handler and del_timer thread in SMP
+ *
+ */
+
+/*
+ * The lblc algorithm is as follows (pseudo code):
+ *
+ *       if cachenode[dest_ip] is null then
+ *               n, cachenode[dest_ip] <- {weighted least-conn node};
+ *       else
+ *               n <- cachenode[dest_ip];
+ *               if (n is dead) OR
+ *                  (n.conns>n.weight AND
+ *                   there is a node m with m.conns<m.weight/2) then
+ *                 n, cachenode[dest_ip] <- {weighted least-conn node};
+ *
+ *       return n;
+ *
+ * Thanks must go to Wenzhuo Zhang for talking WCCP to me and pushing
+ * me to write this module.
+ */
+
+#include <linux/ip.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/skbuff.h>
+#include <linux/jiffies.h>
+
+/* for sysctl */
+#include <linux/fs.h>
+#include <linux/sysctl.h>
+
+#include <net/ip_vs.h>
+
+
+/*
+ *    It is for garbage collection of stale IPVS lblc entries,
+ *    when the table is full.
+ */
+#define CHECK_EXPIRE_INTERVAL   (60*HZ)
+#define ENTRY_TIMEOUT           (6*60*HZ)
+
+/*
+ *    It is for full expiration check.
+ *    When there is no partial expiration check (garbage collection)
+ *    in a half hour, do a full expiration check to collect stale
+ *    entries that haven't been touched for a day.
+ */
+#define COUNT_FOR_FULL_EXPIRATION   30
+static int sysctl_ip_vs_lblc_expiration = 24*60*60*HZ;
+
+
+/*
+ *     for IPVS lblc entry hash table
+ */
+#ifndef CONFIG_IP_VS_LBLC_TAB_BITS
+#define CONFIG_IP_VS_LBLC_TAB_BITS      10
+#endif
+#define IP_VS_LBLC_TAB_BITS     CONFIG_IP_VS_LBLC_TAB_BITS
+#define IP_VS_LBLC_TAB_SIZE     (1 << IP_VS_LBLC_TAB_BITS)
+#define IP_VS_LBLC_TAB_MASK     (IP_VS_LBLC_TAB_SIZE - 1)
+
+
+/*
+ *      IPVS lblc entry represents an association between destination
+ *      IP address and its destination server
+ */
+struct ip_vs_lblc_entry {
+	struct list_head        list;
+	__be32                  addr;           /* destination IP address */
+	struct ip_vs_dest       *dest;          /* real server (cache) */
+	unsigned long           lastuse;        /* last used time */
+};
+
+
+/*
+ *      IPVS lblc hash table
+ */
+struct ip_vs_lblc_table {
+	struct list_head        bucket[IP_VS_LBLC_TAB_SIZE];  /* hash bucket */
+	atomic_t                entries;        /* number of entries */
+	int                     max_size;       /* maximum size of entries */
+	struct timer_list       periodic_timer; /* collect stale entries */
+	int                     rover;          /* rover for expire check */
+	int                     counter;        /* counter for no expire */
+};
+
+
+/*
+ *      IPVS LBLC sysctl table
+ */
+
+static ctl_table vs_vars_table[] = {
+	{
+		.procname	= "lblc_expiration",
+		.data		= &sysctl_ip_vs_lblc_expiration,
+		.maxlen		= sizeof(int),
+		.mode		= 0644,
+		.proc_handler	= &proc_dointvec_jiffies,
+	},
+	{ .ctl_name = 0 }
+};
+
+static struct ctl_table_header * sysctl_header;
+
+static inline void ip_vs_lblc_free(struct ip_vs_lblc_entry *en)
+{
+	list_del(&en->list);
+	/*
+	 * We don't kfree dest because it is refered either by its service
+	 * or the trash dest list.
+	 */
+	atomic_dec(&en->dest->refcnt);
+	kfree(en);
+}
+
+
+/*
+ *	Returns hash value for IPVS LBLC entry
+ */
+static inline unsigned ip_vs_lblc_hashkey(__be32 addr)
+{
+	return (ntohl(addr)*2654435761UL) & IP_VS_LBLC_TAB_MASK;
+}
+
+
+/*
+ *	Hash an entry in the ip_vs_lblc_table.
+ *	returns bool success.
+ */
+static void
+ip_vs_lblc_hash(struct ip_vs_lblc_table *tbl, struct ip_vs_lblc_entry *en)
+{
+	unsigned hash = ip_vs_lblc_hashkey(en->addr);
+
+	list_add(&en->list, &tbl->bucket[hash]);
+	atomic_inc(&tbl->entries);
+}
+
+
+/*
+ *  Get ip_vs_lblc_entry associated with supplied parameters. Called under read
+ *  lock
+ */
+static inline struct ip_vs_lblc_entry *
+ip_vs_lblc_get(struct ip_vs_lblc_table *tbl, __be32 addr)
+{
+	unsigned hash = ip_vs_lblc_hashkey(addr);
+	struct ip_vs_lblc_entry *en;
+
+	list_for_each_entry(en, &tbl->bucket[hash], list)
+		if (en->addr == addr)
+			return en;
+
+	return NULL;
+}
+
+
+/*
+ * Create or update an ip_vs_lblc_entry, which is a mapping of a destination IP
+ * address to a server. Called under write lock.
+ */
+static inline struct ip_vs_lblc_entry *
+ip_vs_lblc_new(struct ip_vs_lblc_table *tbl, __be32 daddr,
+	       struct ip_vs_dest *dest)
+{
+	struct ip_vs_lblc_entry *en;
+
+	en = ip_vs_lblc_get(tbl, daddr);
+	if (!en) {
+		en = kmalloc(sizeof(*en), GFP_ATOMIC);
+		if (!en) {
+			IP_VS_ERR("ip_vs_lblc_new(): no memory\n");
+			return NULL;
+		}
+
+		en->addr = daddr;
+		en->lastuse = jiffies;
+
+		atomic_inc(&dest->refcnt);
+		en->dest = dest;
+
+		ip_vs_lblc_hash(tbl, en);
+	} else if (en->dest != dest) {
+		atomic_dec(&en->dest->refcnt);
+		atomic_inc(&dest->refcnt);
+		en->dest = dest;
+	}
+
+	return en;
+}
+
+
+/*
+ *      Flush all the entries of the specified table.
+ */
+static void ip_vs_lblc_flush(struct ip_vs_lblc_table *tbl)
+{
+	struct ip_vs_lblc_entry *en, *nxt;
+	int i;
+
+	for (i=0; i<IP_VS_LBLC_TAB_SIZE; i++) {
+		list_for_each_entry_safe(en, nxt, &tbl->bucket[i], list) {
+			ip_vs_lblc_free(en);
+			atomic_dec(&tbl->entries);
+		}
+	}
+}
+
+
+static inline void ip_vs_lblc_full_check(struct ip_vs_service *svc)
+{
+	struct ip_vs_lblc_table *tbl = svc->sched_data;
+	struct ip_vs_lblc_entry *en, *nxt;
+	unsigned long now = jiffies;
+	int i, j;
+
+	for (i=0, j=tbl->rover; i<IP_VS_LBLC_TAB_SIZE; i++) {
+		j = (j + 1) & IP_VS_LBLC_TAB_MASK;
+
+		write_lock(&svc->sched_lock);
+		list_for_each_entry_safe(en, nxt, &tbl->bucket[j], list) {
+			if (time_before(now,
+					en->lastuse + sysctl_ip_vs_lblc_expiration))
+				continue;
+
+			ip_vs_lblc_free(en);
+			atomic_dec(&tbl->entries);
+		}
+		write_unlock(&svc->sched_lock);
+	}
+	tbl->rover = j;
+}
+
+
+/*
+ *      Periodical timer handler for IPVS lblc table
+ *      It is used to collect stale entries when the number of entries
+ *      exceeds the maximum size of the table.
+ *
+ *      Fixme: we probably need more complicated algorithm to collect
+ *             entries that have not been used for a long time even
+ *             if the number of entries doesn't exceed the maximum size
+ *             of the table.
+ *      The full expiration check is for this purpose now.
+ */
+static void ip_vs_lblc_check_expire(unsigned long data)
+{
+	struct ip_vs_service *svc = (struct ip_vs_service *) data;
+	struct ip_vs_lblc_table *tbl = svc->sched_data;
+	unsigned long now = jiffies;
+	int goal;
+	int i, j;
+	struct ip_vs_lblc_entry *en, *nxt;
+
+	if ((tbl->counter % COUNT_FOR_FULL_EXPIRATION) == 0) {
+		/* do full expiration check */
+		ip_vs_lblc_full_check(svc);
+		tbl->counter = 1;
+		goto out;
+	}
+
+	if (atomic_read(&tbl->entries) <= tbl->max_size) {
+		tbl->counter++;
+		goto out;
+	}
+
+	goal = (atomic_read(&tbl->entries) - tbl->max_size)*4/3;
+	if (goal > tbl->max_size/2)
+		goal = tbl->max_size/2;
+
+	for (i=0, j=tbl->rover; i<IP_VS_LBLC_TAB_SIZE; i++) {
+		j = (j + 1) & IP_VS_LBLC_TAB_MASK;
+
+		write_lock(&svc->sched_lock);
+		list_for_each_entry_safe(en, nxt, &tbl->bucket[j], list) {
+			if (time_before(now, en->lastuse + ENTRY_TIMEOUT))
+				continue;
+
+			ip_vs_lblc_free(en);
+			atomic_dec(&tbl->entries);
+			goal--;
+		}
+		write_unlock(&svc->sched_lock);
+		if (goal <= 0)
+			break;
+	}
+	tbl->rover = j;
+
+  out:
+	mod_timer(&tbl->periodic_timer, jiffies+CHECK_EXPIRE_INTERVAL);
+}
+
+
+static int ip_vs_lblc_init_svc(struct ip_vs_service *svc)
+{
+	int i;
+	struct ip_vs_lblc_table *tbl;
+
+	/*
+	 *    Allocate the ip_vs_lblc_table for this service
+	 */
+	tbl = kmalloc(sizeof(*tbl), GFP_ATOMIC);
+	if (tbl == NULL) {
+		IP_VS_ERR("ip_vs_lblc_init_svc(): no memory\n");
+		return -ENOMEM;
+	}
+	svc->sched_data = tbl;
+	IP_VS_DBG(6, "LBLC hash table (memory=%Zdbytes) allocated for "
+		  "current service\n", sizeof(*tbl));
+
+	/*
+	 *    Initialize the hash buckets
+	 */
+	for (i=0; i<IP_VS_LBLC_TAB_SIZE; i++) {
+		INIT_LIST_HEAD(&tbl->bucket[i]);
+	}
+	tbl->max_size = IP_VS_LBLC_TAB_SIZE*16;
+	tbl->rover = 0;
+	tbl->counter = 1;
+
+	/*
+	 *    Hook periodic timer for garbage collection
+	 */
+	setup_timer(&tbl->periodic_timer, ip_vs_lblc_check_expire,
+			(unsigned long)svc);
+	mod_timer(&tbl->periodic_timer, jiffies + CHECK_EXPIRE_INTERVAL);
+
+	return 0;
+}
+
+
+static int ip_vs_lblc_done_svc(struct ip_vs_service *svc)
+{
+	struct ip_vs_lblc_table *tbl = svc->sched_data;
+
+	/* remove periodic timer */
+	del_timer_sync(&tbl->periodic_timer);
+
+	/* got to clean up table entries here */
+	ip_vs_lblc_flush(tbl);
+
+	/* release the table itself */
+	kfree(tbl);
+	IP_VS_DBG(6, "LBLC hash table (memory=%Zdbytes) released\n",
+		  sizeof(*tbl));
+
+	return 0;
+}
+
+
+static inline struct ip_vs_dest *
+__ip_vs_lblc_schedule(struct ip_vs_service *svc, struct iphdr *iph)
+{
+	struct ip_vs_dest *dest, *least;
+	int loh, doh;
+
+	/*
+	 * We think the overhead of processing active connections is fifty
+	 * times higher than that of inactive connections in average. (This
+	 * fifty times might not be accurate, we will change it later.) We
+	 * use the following formula to estimate the overhead:
+	 *                dest->activeconns*50 + dest->inactconns
+	 * and the load:
+	 *                (dest overhead) / dest->weight
+	 *
+	 * Remember -- no floats in kernel mode!!!
+	 * The comparison of h1*w2 > h2*w1 is equivalent to that of
+	 *                h1/w1 > h2/w2
+	 * if every weight is larger than zero.
+	 *
+	 * The server with weight=0 is quiesced and will not receive any
+	 * new connection.
+	 */
+	list_for_each_entry(dest, &svc->destinations, n_list) {
+		if (dest->flags & IP_VS_DEST_F_OVERLOAD)
+			continue;
+		if (atomic_read(&dest->weight) > 0) {
+			least = dest;
+			loh = atomic_read(&least->activeconns) * 50
+				+ atomic_read(&least->inactconns);
+			goto nextstage;
+		}
+	}
+	return NULL;
+
+	/*
+	 *    Find the destination with the least load.
+	 */
+  nextstage:
+	list_for_each_entry_continue(dest, &svc->destinations, n_list) {
+		if (dest->flags & IP_VS_DEST_F_OVERLOAD)
+			continue;
+
+		doh = atomic_read(&dest->activeconns) * 50
+			+ atomic_read(&dest->inactconns);
+		if (loh * atomic_read(&dest->weight) >
+		    doh * atomic_read(&least->weight)) {
+			least = dest;
+			loh = doh;
+		}
+	}
+
+	IP_VS_DBG(6, "LBLC: server %d.%d.%d.%d:%d "
+		  "activeconns %d refcnt %d weight %d overhead %d\n",
+		  NIPQUAD(least->addr.ip), ntohs(least->port),
+		  atomic_read(&least->activeconns),
+		  atomic_read(&least->refcnt),
+		  atomic_read(&least->weight), loh);
+
+	return least;
+}
+
+
+/*
+ *   If this destination server is overloaded and there is a less loaded
+ *   server, then return true.
+ */
+static inline int
+is_overloaded(struct ip_vs_dest *dest, struct ip_vs_service *svc)
+{
+	if (atomic_read(&dest->activeconns) > atomic_read(&dest->weight)) {
+		struct ip_vs_dest *d;
+
+		list_for_each_entry(d, &svc->destinations, n_list) {
+			if (atomic_read(&d->activeconns)*2
+			    < atomic_read(&d->weight)) {
+				return 1;
+			}
+		}
+	}
+	return 0;
+}
+
+
+/*
+ *    Locality-Based (weighted) Least-Connection scheduling
+ */
+static struct ip_vs_dest *
+ip_vs_lblc_schedule(struct ip_vs_service *svc, const struct sk_buff *skb)
+{
+	struct ip_vs_lblc_table *tbl = svc->sched_data;
+	struct iphdr *iph = ip_hdr(skb);
+	struct ip_vs_dest *dest = NULL;
+	struct ip_vs_lblc_entry *en;
+
+	IP_VS_DBG(6, "ip_vs_lblc_schedule(): Scheduling...\n");
+
+	/* First look in our cache */
+	read_lock(&svc->sched_lock);
+	en = ip_vs_lblc_get(tbl, iph->daddr);
+	if (en) {
+		/* We only hold a read lock, but this is atomic */
+		en->lastuse = jiffies;
+
+		/*
+		 * If the destination is not available, i.e. it's in the trash,
+		 * we must ignore it, as it may be removed from under our feet,
+		 * if someone drops our reference count. Our caller only makes
+		 * sure that destinations, that are not in the trash, are not
+		 * moved to the trash, while we are scheduling. But anyone can
+		 * free up entries from the trash at any time.
+		 */
+
+		if (en->dest->flags & IP_VS_DEST_F_AVAILABLE)
+			dest = en->dest;
+	}
+	read_unlock(&svc->sched_lock);
+
+	/* If the destination has a weight and is not overloaded, use it */
+	if (dest && atomic_read(&dest->weight) > 0 && !is_overloaded(dest, svc))
+		goto out;
+
+	/* No cache entry or it is invalid, time to schedule */
+	dest = __ip_vs_lblc_schedule(svc, iph);
+	if (!dest) {
+		IP_VS_DBG(1, "no destination available\n");
+		return NULL;
+	}
+
+	/* If we fail to create a cache entry, we'll just use the valid dest */
+	write_lock(&svc->sched_lock);
+	ip_vs_lblc_new(tbl, iph->daddr, dest);
+	write_unlock(&svc->sched_lock);
+
+out:
+	IP_VS_DBG(6, "LBLC: destination IP address %u.%u.%u.%u "
+		  "--> server %u.%u.%u.%u:%d\n",
+		  NIPQUAD(iph->daddr),
+		  NIPQUAD(dest->addr.ip),
+		  ntohs(dest->port));
+
+	return dest;
+}
+
+
+/*
+ *      IPVS LBLC Scheduler structure
+ */
+static struct ip_vs_scheduler ip_vs_lblc_scheduler =
+{
+	.name =			"lblc",
+	.refcnt =		ATOMIC_INIT(0),
+	.module =		THIS_MODULE,
+	.n_list =		LIST_HEAD_INIT(ip_vs_lblc_scheduler.n_list),
+#ifdef CONFIG_IP_VS_IPV6
+	.supports_ipv6 =	0,
+#endif
+	.init_service =		ip_vs_lblc_init_svc,
+	.done_service =		ip_vs_lblc_done_svc,
+	.schedule =		ip_vs_lblc_schedule,
+};
+
+
+static int __init ip_vs_lblc_init(void)
+{
+	int ret;
+
+	sysctl_header = register_sysctl_paths(net_vs_ctl_path, vs_vars_table);
+	ret = register_ip_vs_scheduler(&ip_vs_lblc_scheduler);
+	if (ret)
+		unregister_sysctl_table(sysctl_header);
+	return ret;
+}
+
+
+static void __exit ip_vs_lblc_cleanup(void)
+{
+	unregister_sysctl_table(sysctl_header);
+	unregister_ip_vs_scheduler(&ip_vs_lblc_scheduler);
+}
+
+
+module_init(ip_vs_lblc_init);
+module_exit(ip_vs_lblc_cleanup);
+MODULE_LICENSE("GPL");
diff --git a/net/netfilter/ipvs/ip_vs_lblcr.c b/net/netfilter/ipvs/ip_vs_lblcr.c
new file mode 100644
index 0000000..1f75ea8
--- /dev/null
+++ b/net/netfilter/ipvs/ip_vs_lblcr.c
@@ -0,0 +1,755 @@
+/*
+ * IPVS:        Locality-Based Least-Connection with Replication scheduler
+ *
+ * Authors:     Wensong Zhang <wensong@gnuchina.org>
+ *
+ *              This program is free software; you can redistribute it and/or
+ *              modify it under the terms of the GNU General Public License
+ *              as published by the Free Software Foundation; either version
+ *              2 of the License, or (at your option) any later version.
+ *
+ * Changes:
+ *     Julian Anastasov        :    Added the missing (dest->weight>0)
+ *                                  condition in the ip_vs_dest_set_max.
+ *
+ */
+
+/*
+ * The lblc/r algorithm is as follows (pseudo code):
+ *
+ *       if serverSet[dest_ip] is null then
+ *               n, serverSet[dest_ip] <- {weighted least-conn node};
+ *       else
+ *               n <- {least-conn (alive) node in serverSet[dest_ip]};
+ *               if (n is null) OR
+ *                  (n.conns>n.weight AND
+ *                   there is a node m with m.conns<m.weight/2) then
+ *                   n <- {weighted least-conn node};
+ *                   add n to serverSet[dest_ip];
+ *               if |serverSet[dest_ip]| > 1 AND
+ *                   now - serverSet[dest_ip].lastMod > T then
+ *                   m <- {most conn node in serverSet[dest_ip]};
+ *                   remove m from serverSet[dest_ip];
+ *       if serverSet[dest_ip] changed then
+ *               serverSet[dest_ip].lastMod <- now;
+ *
+ *       return n;
+ *
+ */
+
+#include <linux/ip.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/skbuff.h>
+#include <linux/jiffies.h>
+
+/* for sysctl */
+#include <linux/fs.h>
+#include <linux/sysctl.h>
+#include <net/net_namespace.h>
+
+#include <net/ip_vs.h>
+
+
+/*
+ *    It is for garbage collection of stale IPVS lblcr entries,
+ *    when the table is full.
+ */
+#define CHECK_EXPIRE_INTERVAL   (60*HZ)
+#define ENTRY_TIMEOUT           (6*60*HZ)
+
+/*
+ *    It is for full expiration check.
+ *    When there is no partial expiration check (garbage collection)
+ *    in a half hour, do a full expiration check to collect stale
+ *    entries that haven't been touched for a day.
+ */
+#define COUNT_FOR_FULL_EXPIRATION   30
+static int sysctl_ip_vs_lblcr_expiration = 24*60*60*HZ;
+
+
+/*
+ *     for IPVS lblcr entry hash table
+ */
+#ifndef CONFIG_IP_VS_LBLCR_TAB_BITS
+#define CONFIG_IP_VS_LBLCR_TAB_BITS      10
+#endif
+#define IP_VS_LBLCR_TAB_BITS     CONFIG_IP_VS_LBLCR_TAB_BITS
+#define IP_VS_LBLCR_TAB_SIZE     (1 << IP_VS_LBLCR_TAB_BITS)
+#define IP_VS_LBLCR_TAB_MASK     (IP_VS_LBLCR_TAB_SIZE - 1)
+
+
+/*
+ *      IPVS destination set structure and operations
+ */
+struct ip_vs_dest_list {
+	struct ip_vs_dest_list  *next;          /* list link */
+	struct ip_vs_dest       *dest;          /* destination server */
+};
+
+struct ip_vs_dest_set {
+	atomic_t                size;           /* set size */
+	unsigned long           lastmod;        /* last modified time */
+	struct ip_vs_dest_list  *list;          /* destination list */
+	rwlock_t	        lock;           /* lock for this list */
+};
+
+
+static struct ip_vs_dest_list *
+ip_vs_dest_set_insert(struct ip_vs_dest_set *set, struct ip_vs_dest *dest)
+{
+	struct ip_vs_dest_list *e;
+
+	for (e=set->list; e!=NULL; e=e->next) {
+		if (e->dest == dest)
+			/* already existed */
+			return NULL;
+	}
+
+	e = kmalloc(sizeof(*e), GFP_ATOMIC);
+	if (e == NULL) {
+		IP_VS_ERR("ip_vs_dest_set_insert(): no memory\n");
+		return NULL;
+	}
+
+	atomic_inc(&dest->refcnt);
+	e->dest = dest;
+
+	/* link it to the list */
+	e->next = set->list;
+	set->list = e;
+	atomic_inc(&set->size);
+
+	set->lastmod = jiffies;
+	return e;
+}
+
+static void
+ip_vs_dest_set_erase(struct ip_vs_dest_set *set, struct ip_vs_dest *dest)
+{
+	struct ip_vs_dest_list *e, **ep;
+
+	for (ep=&set->list, e=*ep; e!=NULL; e=*ep) {
+		if (e->dest == dest) {
+			/* HIT */
+			*ep = e->next;
+			atomic_dec(&set->size);
+			set->lastmod = jiffies;
+			atomic_dec(&e->dest->refcnt);
+			kfree(e);
+			break;
+		}
+		ep = &e->next;
+	}
+}
+
+static void ip_vs_dest_set_eraseall(struct ip_vs_dest_set *set)
+{
+	struct ip_vs_dest_list *e, **ep;
+
+	write_lock(&set->lock);
+	for (ep=&set->list, e=*ep; e!=NULL; e=*ep) {
+		*ep = e->next;
+		/*
+		 * We don't kfree dest because it is refered either
+		 * by its service or by the trash dest list.
+		 */
+		atomic_dec(&e->dest->refcnt);
+		kfree(e);
+	}
+	write_unlock(&set->lock);
+}
+
+/* get weighted least-connection node in the destination set */
+static inline struct ip_vs_dest *ip_vs_dest_set_min(struct ip_vs_dest_set *set)
+{
+	register struct ip_vs_dest_list *e;
+	struct ip_vs_dest *dest, *least;
+	int loh, doh;
+
+	if (set == NULL)
+		return NULL;
+
+	/* select the first destination server, whose weight > 0 */
+	for (e=set->list; e!=NULL; e=e->next) {
+		least = e->dest;
+		if (least->flags & IP_VS_DEST_F_OVERLOAD)
+			continue;
+
+		if ((atomic_read(&least->weight) > 0)
+		    && (least->flags & IP_VS_DEST_F_AVAILABLE)) {
+			loh = atomic_read(&least->activeconns) * 50
+				+ atomic_read(&least->inactconns);
+			goto nextstage;
+		}
+	}
+	return NULL;
+
+	/* find the destination with the weighted least load */
+  nextstage:
+	for (e=e->next; e!=NULL; e=e->next) {
+		dest = e->dest;
+		if (dest->flags & IP_VS_DEST_F_OVERLOAD)
+			continue;
+
+		doh = atomic_read(&dest->activeconns) * 50
+			+ atomic_read(&dest->inactconns);
+		if ((loh * atomic_read(&dest->weight) >
+		     doh * atomic_read(&least->weight))
+		    && (dest->flags & IP_VS_DEST_F_AVAILABLE)) {
+			least = dest;
+			loh = doh;
+		}
+	}
+
+	IP_VS_DBG(6, "ip_vs_dest_set_min: server %d.%d.%d.%d:%d "
+		  "activeconns %d refcnt %d weight %d overhead %d\n",
+		  NIPQUAD(least->addr.ip), ntohs(least->port),
+		  atomic_read(&least->activeconns),
+		  atomic_read(&least->refcnt),
+		  atomic_read(&least->weight), loh);
+	return least;
+}
+
+
+/* get weighted most-connection node in the destination set */
+static inline struct ip_vs_dest *ip_vs_dest_set_max(struct ip_vs_dest_set *set)
+{
+	register struct ip_vs_dest_list *e;
+	struct ip_vs_dest *dest, *most;
+	int moh, doh;
+
+	if (set == NULL)
+		return NULL;
+
+	/* select the first destination server, whose weight > 0 */
+	for (e=set->list; e!=NULL; e=e->next) {
+		most = e->dest;
+		if (atomic_read(&most->weight) > 0) {
+			moh = atomic_read(&most->activeconns) * 50
+				+ atomic_read(&most->inactconns);
+			goto nextstage;
+		}
+	}
+	return NULL;
+
+	/* find the destination with the weighted most load */
+  nextstage:
+	for (e=e->next; e!=NULL; e=e->next) {
+		dest = e->dest;
+		doh = atomic_read(&dest->activeconns) * 50
+			+ atomic_read(&dest->inactconns);
+		/* moh/mw < doh/dw ==> moh*dw < doh*mw, where mw,dw>0 */
+		if ((moh * atomic_read(&dest->weight) <
+		     doh * atomic_read(&most->weight))
+		    && (atomic_read(&dest->weight) > 0)) {
+			most = dest;
+			moh = doh;
+		}
+	}
+
+	IP_VS_DBG(6, "ip_vs_dest_set_max: server %d.%d.%d.%d:%d "
+		  "activeconns %d refcnt %d weight %d overhead %d\n",
+		  NIPQUAD(most->addr.ip), ntohs(most->port),
+		  atomic_read(&most->activeconns),
+		  atomic_read(&most->refcnt),
+		  atomic_read(&most->weight), moh);
+	return most;
+}
+
+
+/*
+ *      IPVS lblcr entry represents an association between destination
+ *      IP address and its destination server set
+ */
+struct ip_vs_lblcr_entry {
+	struct list_head        list;
+	__be32                   addr;           /* destination IP address */
+	struct ip_vs_dest_set   set;            /* destination server set */
+	unsigned long           lastuse;        /* last used time */
+};
+
+
+/*
+ *      IPVS lblcr hash table
+ */
+struct ip_vs_lblcr_table {
+	struct list_head        bucket[IP_VS_LBLCR_TAB_SIZE];  /* hash bucket */
+	atomic_t                entries;        /* number of entries */
+	int                     max_size;       /* maximum size of entries */
+	struct timer_list       periodic_timer; /* collect stale entries */
+	int                     rover;          /* rover for expire check */
+	int                     counter;        /* counter for no expire */
+};
+
+
+/*
+ *      IPVS LBLCR sysctl table
+ */
+
+static ctl_table vs_vars_table[] = {
+	{
+		.procname	= "lblcr_expiration",
+		.data		= &sysctl_ip_vs_lblcr_expiration,
+		.maxlen		= sizeof(int),
+		.mode		= 0644,
+		.proc_handler	= &proc_dointvec_jiffies,
+	},
+	{ .ctl_name = 0 }
+};
+
+static struct ctl_table_header * sysctl_header;
+
+static inline void ip_vs_lblcr_free(struct ip_vs_lblcr_entry *en)
+{
+	list_del(&en->list);
+	ip_vs_dest_set_eraseall(&en->set);
+	kfree(en);
+}
+
+
+/*
+ *	Returns hash value for IPVS LBLCR entry
+ */
+static inline unsigned ip_vs_lblcr_hashkey(__be32 addr)
+{
+	return (ntohl(addr)*2654435761UL) & IP_VS_LBLCR_TAB_MASK;
+}
+
+
+/*
+ *	Hash an entry in the ip_vs_lblcr_table.
+ *	returns bool success.
+ */
+static void
+ip_vs_lblcr_hash(struct ip_vs_lblcr_table *tbl, struct ip_vs_lblcr_entry *en)
+{
+	unsigned hash = ip_vs_lblcr_hashkey(en->addr);
+
+	list_add(&en->list, &tbl->bucket[hash]);
+	atomic_inc(&tbl->entries);
+}
+
+
+/*
+ *  Get ip_vs_lblcr_entry associated with supplied parameters. Called under
+ *  read lock.
+ */
+static inline struct ip_vs_lblcr_entry *
+ip_vs_lblcr_get(struct ip_vs_lblcr_table *tbl, __be32 addr)
+{
+	unsigned hash = ip_vs_lblcr_hashkey(addr);
+	struct ip_vs_lblcr_entry *en;
+
+	list_for_each_entry(en, &tbl->bucket[hash], list)
+		if (en->addr == addr)
+			return en;
+
+	return NULL;
+}
+
+
+/*
+ * Create or update an ip_vs_lblcr_entry, which is a mapping of a destination
+ * IP address to a server. Called under write lock.
+ */
+static inline struct ip_vs_lblcr_entry *
+ip_vs_lblcr_new(struct ip_vs_lblcr_table *tbl,  __be32 daddr,
+		struct ip_vs_dest *dest)
+{
+	struct ip_vs_lblcr_entry *en;
+
+	en = ip_vs_lblcr_get(tbl, daddr);
+	if (!en) {
+		en = kmalloc(sizeof(*en), GFP_ATOMIC);
+		if (!en) {
+			IP_VS_ERR("ip_vs_lblcr_new(): no memory\n");
+			return NULL;
+		}
+
+		en->addr = daddr;
+		en->lastuse = jiffies;
+
+		/* initilize its dest set */
+		atomic_set(&(en->set.size), 0);
+		en->set.list = NULL;
+		rwlock_init(&en->set.lock);
+
+		ip_vs_lblcr_hash(tbl, en);
+	}
+
+	write_lock(&en->set.lock);
+	ip_vs_dest_set_insert(&en->set, dest);
+	write_unlock(&en->set.lock);
+
+	return en;
+}
+
+
+/*
+ *      Flush all the entries of the specified table.
+ */
+static void ip_vs_lblcr_flush(struct ip_vs_lblcr_table *tbl)
+{
+	int i;
+	struct ip_vs_lblcr_entry *en, *nxt;
+
+	/* No locking required, only called during cleanup. */
+	for (i=0; i<IP_VS_LBLCR_TAB_SIZE; i++) {
+		list_for_each_entry_safe(en, nxt, &tbl->bucket[i], list) {
+			ip_vs_lblcr_free(en);
+		}
+	}
+}
+
+
+static inline void ip_vs_lblcr_full_check(struct ip_vs_service *svc)
+{
+	struct ip_vs_lblcr_table *tbl = svc->sched_data;
+	unsigned long now = jiffies;
+	int i, j;
+	struct ip_vs_lblcr_entry *en, *nxt;
+
+	for (i=0, j=tbl->rover; i<IP_VS_LBLCR_TAB_SIZE; i++) {
+		j = (j + 1) & IP_VS_LBLCR_TAB_MASK;
+
+		write_lock(&svc->sched_lock);
+		list_for_each_entry_safe(en, nxt, &tbl->bucket[j], list) {
+			if (time_after(en->lastuse+sysctl_ip_vs_lblcr_expiration,
+				       now))
+				continue;
+
+			ip_vs_lblcr_free(en);
+			atomic_dec(&tbl->entries);
+		}
+		write_unlock(&svc->sched_lock);
+	}
+	tbl->rover = j;
+}
+
+
+/*
+ *      Periodical timer handler for IPVS lblcr table
+ *      It is used to collect stale entries when the number of entries
+ *      exceeds the maximum size of the table.
+ *
+ *      Fixme: we probably need more complicated algorithm to collect
+ *             entries that have not been used for a long time even
+ *             if the number of entries doesn't exceed the maximum size
+ *             of the table.
+ *      The full expiration check is for this purpose now.
+ */
+static void ip_vs_lblcr_check_expire(unsigned long data)
+{
+	struct ip_vs_service *svc = (struct ip_vs_service *) data;
+	struct ip_vs_lblcr_table *tbl = svc->sched_data;
+	unsigned long now = jiffies;
+	int goal;
+	int i, j;
+	struct ip_vs_lblcr_entry *en, *nxt;
+
+	if ((tbl->counter % COUNT_FOR_FULL_EXPIRATION) == 0) {
+		/* do full expiration check */
+		ip_vs_lblcr_full_check(svc);
+		tbl->counter = 1;
+		goto out;
+	}
+
+	if (atomic_read(&tbl->entries) <= tbl->max_size) {
+		tbl->counter++;
+		goto out;
+	}
+
+	goal = (atomic_read(&tbl->entries) - tbl->max_size)*4/3;
+	if (goal > tbl->max_size/2)
+		goal = tbl->max_size/2;
+
+	for (i=0, j=tbl->rover; i<IP_VS_LBLCR_TAB_SIZE; i++) {
+		j = (j + 1) & IP_VS_LBLCR_TAB_MASK;
+
+		write_lock(&svc->sched_lock);
+		list_for_each_entry_safe(en, nxt, &tbl->bucket[j], list) {
+			if (time_before(now, en->lastuse+ENTRY_TIMEOUT))
+				continue;
+
+			ip_vs_lblcr_free(en);
+			atomic_dec(&tbl->entries);
+			goal--;
+		}
+		write_unlock(&svc->sched_lock);
+		if (goal <= 0)
+			break;
+	}
+	tbl->rover = j;
+
+  out:
+	mod_timer(&tbl->periodic_timer, jiffies+CHECK_EXPIRE_INTERVAL);
+}
+
+static int ip_vs_lblcr_init_svc(struct ip_vs_service *svc)
+{
+	int i;
+	struct ip_vs_lblcr_table *tbl;
+
+	/*
+	 *    Allocate the ip_vs_lblcr_table for this service
+	 */
+	tbl = kmalloc(sizeof(*tbl), GFP_ATOMIC);
+	if (tbl == NULL) {
+		IP_VS_ERR("ip_vs_lblcr_init_svc(): no memory\n");
+		return -ENOMEM;
+	}
+	svc->sched_data = tbl;
+	IP_VS_DBG(6, "LBLCR hash table (memory=%Zdbytes) allocated for "
+		  "current service\n", sizeof(*tbl));
+
+	/*
+	 *    Initialize the hash buckets
+	 */
+	for (i=0; i<IP_VS_LBLCR_TAB_SIZE; i++) {
+		INIT_LIST_HEAD(&tbl->bucket[i]);
+	}
+	tbl->max_size = IP_VS_LBLCR_TAB_SIZE*16;
+	tbl->rover = 0;
+	tbl->counter = 1;
+
+	/*
+	 *    Hook periodic timer for garbage collection
+	 */
+	setup_timer(&tbl->periodic_timer, ip_vs_lblcr_check_expire,
+			(unsigned long)svc);
+	mod_timer(&tbl->periodic_timer, jiffies + CHECK_EXPIRE_INTERVAL);
+
+	return 0;
+}
+
+
+static int ip_vs_lblcr_done_svc(struct ip_vs_service *svc)
+{
+	struct ip_vs_lblcr_table *tbl = svc->sched_data;
+
+	/* remove periodic timer */
+	del_timer_sync(&tbl->periodic_timer);
+
+	/* got to clean up table entries here */
+	ip_vs_lblcr_flush(tbl);
+
+	/* release the table itself */
+	kfree(tbl);
+	IP_VS_DBG(6, "LBLCR hash table (memory=%Zdbytes) released\n",
+		  sizeof(*tbl));
+
+	return 0;
+}
+
+
+static inline struct ip_vs_dest *
+__ip_vs_lblcr_schedule(struct ip_vs_service *svc, struct iphdr *iph)
+{
+	struct ip_vs_dest *dest, *least;
+	int loh, doh;
+
+	/*
+	 * We think the overhead of processing active connections is fifty
+	 * times higher than that of inactive connections in average. (This
+	 * fifty times might not be accurate, we will change it later.) We
+	 * use the following formula to estimate the overhead:
+	 *                dest->activeconns*50 + dest->inactconns
+	 * and the load:
+	 *                (dest overhead) / dest->weight
+	 *
+	 * Remember -- no floats in kernel mode!!!
+	 * The comparison of h1*w2 > h2*w1 is equivalent to that of
+	 *                h1/w1 > h2/w2
+	 * if every weight is larger than zero.
+	 *
+	 * The server with weight=0 is quiesced and will not receive any
+	 * new connection.
+	 */
+	list_for_each_entry(dest, &svc->destinations, n_list) {
+		if (dest->flags & IP_VS_DEST_F_OVERLOAD)
+			continue;
+
+		if (atomic_read(&dest->weight) > 0) {
+			least = dest;
+			loh = atomic_read(&least->activeconns) * 50
+				+ atomic_read(&least->inactconns);
+			goto nextstage;
+		}
+	}
+	return NULL;
+
+	/*
+	 *    Find the destination with the least load.
+	 */
+  nextstage:
+	list_for_each_entry_continue(dest, &svc->destinations, n_list) {
+		if (dest->flags & IP_VS_DEST_F_OVERLOAD)
+			continue;
+
+		doh = atomic_read(&dest->activeconns) * 50
+			+ atomic_read(&dest->inactconns);
+		if (loh * atomic_read(&dest->weight) >
+		    doh * atomic_read(&least->weight)) {
+			least = dest;
+			loh = doh;
+		}
+	}
+
+	IP_VS_DBG(6, "LBLCR: server %d.%d.%d.%d:%d "
+		  "activeconns %d refcnt %d weight %d overhead %d\n",
+		  NIPQUAD(least->addr.ip), ntohs(least->port),
+		  atomic_read(&least->activeconns),
+		  atomic_read(&least->refcnt),
+		  atomic_read(&least->weight), loh);
+
+	return least;
+}
+
+
+/*
+ *   If this destination server is overloaded and there is a less loaded
+ *   server, then return true.
+ */
+static inline int
+is_overloaded(struct ip_vs_dest *dest, struct ip_vs_service *svc)
+{
+	if (atomic_read(&dest->activeconns) > atomic_read(&dest->weight)) {
+		struct ip_vs_dest *d;
+
+		list_for_each_entry(d, &svc->destinations, n_list) {
+			if (atomic_read(&d->activeconns)*2
+			    < atomic_read(&d->weight)) {
+				return 1;
+			}
+		}
+	}
+	return 0;
+}
+
+
+/*
+ *    Locality-Based (weighted) Least-Connection scheduling
+ */
+static struct ip_vs_dest *
+ip_vs_lblcr_schedule(struct ip_vs_service *svc, const struct sk_buff *skb)
+{
+	struct ip_vs_lblcr_table *tbl = svc->sched_data;
+	struct iphdr *iph = ip_hdr(skb);
+	struct ip_vs_dest *dest = NULL;
+	struct ip_vs_lblcr_entry *en;
+
+	IP_VS_DBG(6, "ip_vs_lblcr_schedule(): Scheduling...\n");
+
+	/* First look in our cache */
+	read_lock(&svc->sched_lock);
+	en = ip_vs_lblcr_get(tbl, iph->daddr);
+	if (en) {
+		/* We only hold a read lock, but this is atomic */
+		en->lastuse = jiffies;
+
+		/* Get the least loaded destination */
+		read_lock(&en->set.lock);
+		dest = ip_vs_dest_set_min(&en->set);
+		read_unlock(&en->set.lock);
+
+		/* More than one destination + enough time passed by, cleanup */
+		if (atomic_read(&en->set.size) > 1 &&
+				time_after(jiffies, en->set.lastmod +
+				sysctl_ip_vs_lblcr_expiration)) {
+			struct ip_vs_dest *m;
+
+			write_lock(&en->set.lock);
+			m = ip_vs_dest_set_max(&en->set);
+			if (m)
+				ip_vs_dest_set_erase(&en->set, m);
+			write_unlock(&en->set.lock);
+		}
+
+		/* If the destination is not overloaded, use it */
+		if (dest && !is_overloaded(dest, svc)) {
+			read_unlock(&svc->sched_lock);
+			goto out;
+		}
+
+		/* The cache entry is invalid, time to schedule */
+		dest = __ip_vs_lblcr_schedule(svc, iph);
+		if (!dest) {
+			IP_VS_DBG(1, "no destination available\n");
+			read_unlock(&svc->sched_lock);
+			return NULL;
+		}
+
+		/* Update our cache entry */
+		write_lock(&en->set.lock);
+		ip_vs_dest_set_insert(&en->set, dest);
+		write_unlock(&en->set.lock);
+	}
+	read_unlock(&svc->sched_lock);
+
+	if (dest)
+		goto out;
+
+	/* No cache entry, time to schedule */
+	dest = __ip_vs_lblcr_schedule(svc, iph);
+	if (!dest) {
+		IP_VS_DBG(1, "no destination available\n");
+		return NULL;
+	}
+
+	/* If we fail to create a cache entry, we'll just use the valid dest */
+	write_lock(&svc->sched_lock);
+	ip_vs_lblcr_new(tbl, iph->daddr, dest);
+	write_unlock(&svc->sched_lock);
+
+out:
+	IP_VS_DBG(6, "LBLCR: destination IP address %u.%u.%u.%u "
+		  "--> server %u.%u.%u.%u:%d\n",
+		  NIPQUAD(iph->daddr),
+		  NIPQUAD(dest->addr.ip),
+		  ntohs(dest->port));
+
+	return dest;
+}
+
+
+/*
+ *      IPVS LBLCR Scheduler structure
+ */
+static struct ip_vs_scheduler ip_vs_lblcr_scheduler =
+{
+	.name =			"lblcr",
+	.refcnt =		ATOMIC_INIT(0),
+	.module =		THIS_MODULE,
+	.n_list =		LIST_HEAD_INIT(ip_vs_lblcr_scheduler.n_list),
+#ifdef CONFIG_IP_VS_IPV6
+	.supports_ipv6 =	0,
+#endif
+	.init_service =		ip_vs_lblcr_init_svc,
+	.done_service =		ip_vs_lblcr_done_svc,
+	.schedule =		ip_vs_lblcr_schedule,
+};
+
+
+static int __init ip_vs_lblcr_init(void)
+{
+	int ret;
+
+	sysctl_header = register_sysctl_paths(net_vs_ctl_path, vs_vars_table);
+	ret = register_ip_vs_scheduler(&ip_vs_lblcr_scheduler);
+	if (ret)
+		unregister_sysctl_table(sysctl_header);
+	return ret;
+}
+
+
+static void __exit ip_vs_lblcr_cleanup(void)
+{
+	unregister_sysctl_table(sysctl_header);
+	unregister_ip_vs_scheduler(&ip_vs_lblcr_scheduler);
+}
+
+
+module_init(ip_vs_lblcr_init);
+module_exit(ip_vs_lblcr_cleanup);
+MODULE_LICENSE("GPL");
diff --git a/net/netfilter/ipvs/ip_vs_lc.c b/net/netfilter/ipvs/ip_vs_lc.c
new file mode 100644
index 0000000..b69f808
--- /dev/null
+++ b/net/netfilter/ipvs/ip_vs_lc.c
@@ -0,0 +1,103 @@
+/*
+ * IPVS:        Least-Connection Scheduling module
+ *
+ * Authors:     Wensong Zhang <wensong@linuxvirtualserver.org>
+ *
+ *              This program is free software; you can redistribute it and/or
+ *              modify it under the terms of the GNU General Public License
+ *              as published by the Free Software Foundation; either version
+ *              2 of the License, or (at your option) any later version.
+ *
+ * Changes:
+ *     Wensong Zhang            :     added the ip_vs_lc_update_svc
+ *     Wensong Zhang            :     added any dest with weight=0 is quiesced
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+
+#include <net/ip_vs.h>
+
+
+static inline unsigned int
+ip_vs_lc_dest_overhead(struct ip_vs_dest *dest)
+{
+	/*
+	 * We think the overhead of processing active connections is 256
+	 * times higher than that of inactive connections in average. (This
+	 * 256 times might not be accurate, we will change it later) We
+	 * use the following formula to estimate the overhead now:
+	 *		  dest->activeconns*256 + dest->inactconns
+	 */
+	return (atomic_read(&dest->activeconns) << 8) +
+		atomic_read(&dest->inactconns);
+}
+
+
+/*
+ *	Least Connection scheduling
+ */
+static struct ip_vs_dest *
+ip_vs_lc_schedule(struct ip_vs_service *svc, const struct sk_buff *skb)
+{
+	struct ip_vs_dest *dest, *least = NULL;
+	unsigned int loh = 0, doh;
+
+	IP_VS_DBG(6, "ip_vs_lc_schedule(): Scheduling...\n");
+
+	/*
+	 * Simply select the server with the least number of
+	 *        (activeconns<<5) + inactconns
+	 * Except whose weight is equal to zero.
+	 * If the weight is equal to zero, it means that the server is
+	 * quiesced, the existing connections to the server still get
+	 * served, but no new connection is assigned to the server.
+	 */
+
+	list_for_each_entry(dest, &svc->destinations, n_list) {
+		if ((dest->flags & IP_VS_DEST_F_OVERLOAD) ||
+		    atomic_read(&dest->weight) == 0)
+			continue;
+		doh = ip_vs_lc_dest_overhead(dest);
+		if (!least || doh < loh) {
+			least = dest;
+			loh = doh;
+		}
+	}
+
+	if (least)
+	IP_VS_DBG_BUF(6, "LC: server %s:%u activeconns %d inactconns %d\n",
+		      IP_VS_DBG_ADDR(svc->af, &least->addr), ntohs(least->port),
+		      atomic_read(&least->activeconns),
+		      atomic_read(&least->inactconns));
+
+	return least;
+}
+
+
+static struct ip_vs_scheduler ip_vs_lc_scheduler = {
+	.name =			"lc",
+	.refcnt =		ATOMIC_INIT(0),
+	.module =		THIS_MODULE,
+	.n_list =		LIST_HEAD_INIT(ip_vs_lc_scheduler.n_list),
+#ifdef CONFIG_IP_VS_IPV6
+	.supports_ipv6 =	1,
+#endif
+	.schedule =		ip_vs_lc_schedule,
+};
+
+
+static int __init ip_vs_lc_init(void)
+{
+	return register_ip_vs_scheduler(&ip_vs_lc_scheduler) ;
+}
+
+static void __exit ip_vs_lc_cleanup(void)
+{
+	unregister_ip_vs_scheduler(&ip_vs_lc_scheduler);
+}
+
+module_init(ip_vs_lc_init);
+module_exit(ip_vs_lc_cleanup);
+MODULE_LICENSE("GPL");
diff --git a/net/netfilter/ipvs/ip_vs_nq.c b/net/netfilter/ipvs/ip_vs_nq.c
new file mode 100644
index 0000000..9a2d803
--- /dev/null
+++ b/net/netfilter/ipvs/ip_vs_nq.c
@@ -0,0 +1,138 @@
+/*
+ * IPVS:        Never Queue scheduling module
+ *
+ * Authors:     Wensong Zhang <wensong@linuxvirtualserver.org>
+ *
+ *              This program is free software; you can redistribute it and/or
+ *              modify it under the terms of the GNU General Public License
+ *              as published by the Free Software Foundation; either version
+ *              2 of the License, or (at your option) any later version.
+ *
+ * Changes:
+ *
+ */
+
+/*
+ * The NQ algorithm adopts a two-speed model. When there is an idle server
+ * available, the job will be sent to the idle server, instead of waiting
+ * for a fast one. When there is no idle server available, the job will be
+ * sent to the server that minimize its expected delay (The Shortest
+ * Expected Delay scheduling algorithm).
+ *
+ * See the following paper for more information:
+ * A. Weinrib and S. Shenker, Greed is not enough: Adaptive load sharing
+ * in large heterogeneous systems. In Proceedings IEEE INFOCOM'88,
+ * pages 986-994, 1988.
+ *
+ * Thanks must go to Marko Buuri <marko@buuri.name> for talking NQ to me.
+ *
+ * The difference between NQ and SED is that NQ can improve overall
+ * system utilization.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+
+#include <net/ip_vs.h>
+
+
+static inline unsigned int
+ip_vs_nq_dest_overhead(struct ip_vs_dest *dest)
+{
+	/*
+	 * We only use the active connection number in the cost
+	 * calculation here.
+	 */
+	return atomic_read(&dest->activeconns) + 1;
+}
+
+
+/*
+ *	Weighted Least Connection scheduling
+ */
+static struct ip_vs_dest *
+ip_vs_nq_schedule(struct ip_vs_service *svc, const struct sk_buff *skb)
+{
+	struct ip_vs_dest *dest, *least = NULL;
+	unsigned int loh = 0, doh;
+
+	IP_VS_DBG(6, "ip_vs_nq_schedule(): Scheduling...\n");
+
+	/*
+	 * We calculate the load of each dest server as follows:
+	 *	(server expected overhead) / dest->weight
+	 *
+	 * Remember -- no floats in kernel mode!!!
+	 * The comparison of h1*w2 > h2*w1 is equivalent to that of
+	 *		  h1/w1 > h2/w2
+	 * if every weight is larger than zero.
+	 *
+	 * The server with weight=0 is quiesced and will not receive any
+	 * new connections.
+	 */
+
+	list_for_each_entry(dest, &svc->destinations, n_list) {
+
+		if (dest->flags & IP_VS_DEST_F_OVERLOAD ||
+		    !atomic_read(&dest->weight))
+			continue;
+
+		doh = ip_vs_nq_dest_overhead(dest);
+
+		/* return the server directly if it is idle */
+		if (atomic_read(&dest->activeconns) == 0) {
+			least = dest;
+			loh = doh;
+			goto out;
+		}
+
+		if (!least ||
+		    (loh * atomic_read(&dest->weight) >
+		     doh * atomic_read(&least->weight))) {
+			least = dest;
+			loh = doh;
+		}
+	}
+
+	if (!least)
+		return NULL;
+
+  out:
+	IP_VS_DBG_BUF(6, "NQ: server %s:%u "
+		      "activeconns %d refcnt %d weight %d overhead %d\n",
+		      IP_VS_DBG_ADDR(svc->af, &least->addr), ntohs(least->port),
+		      atomic_read(&least->activeconns),
+		      atomic_read(&least->refcnt),
+		      atomic_read(&least->weight), loh);
+
+	return least;
+}
+
+
+static struct ip_vs_scheduler ip_vs_nq_scheduler =
+{
+	.name =			"nq",
+	.refcnt =		ATOMIC_INIT(0),
+	.module =		THIS_MODULE,
+	.n_list =		LIST_HEAD_INIT(ip_vs_nq_scheduler.n_list),
+#ifdef CONFIG_IP_VS_IPV6
+	.supports_ipv6 =	1,
+#endif
+	.schedule =		ip_vs_nq_schedule,
+};
+
+
+static int __init ip_vs_nq_init(void)
+{
+	return register_ip_vs_scheduler(&ip_vs_nq_scheduler);
+}
+
+static void __exit ip_vs_nq_cleanup(void)
+{
+	unregister_ip_vs_scheduler(&ip_vs_nq_scheduler);
+}
+
+module_init(ip_vs_nq_init);
+module_exit(ip_vs_nq_cleanup);
+MODULE_LICENSE("GPL");
diff --git a/net/netfilter/ipvs/ip_vs_proto.c b/net/netfilter/ipvs/ip_vs_proto.c
new file mode 100644
index 0000000..0791f9e
--- /dev/null
+++ b/net/netfilter/ipvs/ip_vs_proto.c
@@ -0,0 +1,288 @@
+/*
+ * ip_vs_proto.c: transport protocol load balancing support for IPVS
+ *
+ * Authors:     Wensong Zhang <wensong@linuxvirtualserver.org>
+ *              Julian Anastasov <ja@ssi.bg>
+ *
+ *              This program is free software; you can redistribute it and/or
+ *              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.
+ *
+ * Changes:
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/skbuff.h>
+#include <linux/in.h>
+#include <linux/ip.h>
+#include <net/protocol.h>
+#include <net/tcp.h>
+#include <net/udp.h>
+#include <asm/system.h>
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+#include <net/ip_vs.h>
+
+
+/*
+ * IPVS protocols can only be registered/unregistered when the ipvs
+ * module is loaded/unloaded, so no lock is needed in accessing the
+ * ipvs protocol table.
+ */
+
+#define IP_VS_PROTO_TAB_SIZE		32	/* must be power of 2 */
+#define IP_VS_PROTO_HASH(proto)		((proto) & (IP_VS_PROTO_TAB_SIZE-1))
+
+static struct ip_vs_protocol *ip_vs_proto_table[IP_VS_PROTO_TAB_SIZE];
+
+
+/*
+ *	register an ipvs protocol
+ */
+static int __used __init register_ip_vs_protocol(struct ip_vs_protocol *pp)
+{
+	unsigned hash = IP_VS_PROTO_HASH(pp->protocol);
+
+	pp->next = ip_vs_proto_table[hash];
+	ip_vs_proto_table[hash] = pp;
+
+	if (pp->init != NULL)
+		pp->init(pp);
+
+	return 0;
+}
+
+
+/*
+ *	unregister an ipvs protocol
+ */
+static int unregister_ip_vs_protocol(struct ip_vs_protocol *pp)
+{
+	struct ip_vs_protocol **pp_p;
+	unsigned hash = IP_VS_PROTO_HASH(pp->protocol);
+
+	pp_p = &ip_vs_proto_table[hash];
+	for (; *pp_p; pp_p = &(*pp_p)->next) {
+		if (*pp_p == pp) {
+			*pp_p = pp->next;
+			if (pp->exit != NULL)
+				pp->exit(pp);
+			return 0;
+		}
+	}
+
+	return -ESRCH;
+}
+
+
+/*
+ *	get ip_vs_protocol object by its proto.
+ */
+struct ip_vs_protocol * ip_vs_proto_get(unsigned short proto)
+{
+	struct ip_vs_protocol *pp;
+	unsigned hash = IP_VS_PROTO_HASH(proto);
+
+	for (pp = ip_vs_proto_table[hash]; pp; pp = pp->next) {
+		if (pp->protocol == proto)
+			return pp;
+	}
+
+	return NULL;
+}
+
+
+/*
+ *	Propagate event for state change to all protocols
+ */
+void ip_vs_protocol_timeout_change(int flags)
+{
+	struct ip_vs_protocol *pp;
+	int i;
+
+	for (i = 0; i < IP_VS_PROTO_TAB_SIZE; i++) {
+		for (pp = ip_vs_proto_table[i]; pp; pp = pp->next) {
+			if (pp->timeout_change)
+				pp->timeout_change(pp, flags);
+		}
+	}
+}
+
+
+int *
+ip_vs_create_timeout_table(int *table, int size)
+{
+	return kmemdup(table, size, GFP_ATOMIC);
+}
+
+
+/*
+ *	Set timeout value for state specified by name
+ */
+int
+ip_vs_set_state_timeout(int *table, int num, char **names, char *name, int to)
+{
+	int i;
+
+	if (!table || !name || !to)
+		return -EINVAL;
+
+	for (i = 0; i < num; i++) {
+		if (strcmp(names[i], name))
+			continue;
+		table[i] = to * HZ;
+		return 0;
+	}
+	return -ENOENT;
+}
+
+
+const char * ip_vs_state_name(__u16 proto, int state)
+{
+	struct ip_vs_protocol *pp = ip_vs_proto_get(proto);
+
+	if (pp == NULL || pp->state_name == NULL)
+		return (IPPROTO_IP == proto) ? "NONE" : "ERR!";
+	return pp->state_name(state);
+}
+
+
+static void
+ip_vs_tcpudp_debug_packet_v4(struct ip_vs_protocol *pp,
+			     const struct sk_buff *skb,
+			     int offset,
+			     const char *msg)
+{
+	char buf[128];
+	struct iphdr _iph, *ih;
+
+	ih = skb_header_pointer(skb, offset, sizeof(_iph), &_iph);
+	if (ih == NULL)
+		sprintf(buf, "%s TRUNCATED", pp->name);
+	else if (ih->frag_off & htons(IP_OFFSET))
+		sprintf(buf, "%s %u.%u.%u.%u->%u.%u.%u.%u frag",
+			pp->name, NIPQUAD(ih->saddr),
+			NIPQUAD(ih->daddr));
+	else {
+		__be16 _ports[2], *pptr
+;
+		pptr = skb_header_pointer(skb, offset + ih->ihl*4,
+					  sizeof(_ports), _ports);
+		if (pptr == NULL)
+			sprintf(buf, "%s TRUNCATED %u.%u.%u.%u->%u.%u.%u.%u",
+				pp->name,
+				NIPQUAD(ih->saddr),
+				NIPQUAD(ih->daddr));
+		else
+			sprintf(buf, "%s %u.%u.%u.%u:%u->%u.%u.%u.%u:%u",
+				pp->name,
+				NIPQUAD(ih->saddr),
+				ntohs(pptr[0]),
+				NIPQUAD(ih->daddr),
+				ntohs(pptr[1]));
+	}
+
+	printk(KERN_DEBUG "IPVS: %s: %s\n", msg, buf);
+}
+
+#ifdef CONFIG_IP_VS_IPV6
+static void
+ip_vs_tcpudp_debug_packet_v6(struct ip_vs_protocol *pp,
+			     const struct sk_buff *skb,
+			     int offset,
+			     const char *msg)
+{
+	char buf[192];
+	struct ipv6hdr _iph, *ih;
+
+	ih = skb_header_pointer(skb, offset, sizeof(_iph), &_iph);
+	if (ih == NULL)
+		sprintf(buf, "%s TRUNCATED", pp->name);
+	else if (ih->nexthdr == IPPROTO_FRAGMENT)
+		sprintf(buf, "%s " NIP6_FMT "->" NIP6_FMT " frag",
+			pp->name, NIP6(ih->saddr),
+			NIP6(ih->daddr));
+	else {
+		__be16 _ports[2], *pptr;
+
+		pptr = skb_header_pointer(skb, offset + sizeof(struct ipv6hdr),
+					  sizeof(_ports), _ports);
+		if (pptr == NULL)
+			sprintf(buf, "%s TRUNCATED " NIP6_FMT "->" NIP6_FMT,
+				pp->name,
+				NIP6(ih->saddr),
+				NIP6(ih->daddr));
+		else
+			sprintf(buf, "%s " NIP6_FMT ":%u->" NIP6_FMT ":%u",
+				pp->name,
+				NIP6(ih->saddr),
+				ntohs(pptr[0]),
+				NIP6(ih->daddr),
+				ntohs(pptr[1]));
+	}
+
+	printk(KERN_DEBUG "IPVS: %s: %s\n", msg, buf);
+}
+#endif
+
+
+void
+ip_vs_tcpudp_debug_packet(struct ip_vs_protocol *pp,
+			  const struct sk_buff *skb,
+			  int offset,
+			  const char *msg)
+{
+#ifdef CONFIG_IP_VS_IPV6
+	if (skb->protocol == htons(ETH_P_IPV6))
+		ip_vs_tcpudp_debug_packet_v6(pp, skb, offset, msg);
+	else
+#endif
+		ip_vs_tcpudp_debug_packet_v4(pp, skb, offset, msg);
+}
+
+
+int __init ip_vs_protocol_init(void)
+{
+	char protocols[64];
+#define REGISTER_PROTOCOL(p)			\
+	do {					\
+		register_ip_vs_protocol(p);	\
+		strcat(protocols, ", ");	\
+		strcat(protocols, (p)->name);	\
+	} while (0)
+
+	protocols[0] = '\0';
+	protocols[2] = '\0';
+#ifdef CONFIG_IP_VS_PROTO_TCP
+	REGISTER_PROTOCOL(&ip_vs_protocol_tcp);
+#endif
+#ifdef CONFIG_IP_VS_PROTO_UDP
+	REGISTER_PROTOCOL(&ip_vs_protocol_udp);
+#endif
+#ifdef CONFIG_IP_VS_PROTO_AH
+	REGISTER_PROTOCOL(&ip_vs_protocol_ah);
+#endif
+#ifdef CONFIG_IP_VS_PROTO_ESP
+	REGISTER_PROTOCOL(&ip_vs_protocol_esp);
+#endif
+	IP_VS_INFO("Registered protocols (%s)\n", &protocols[2]);
+
+	return 0;
+}
+
+
+void ip_vs_protocol_cleanup(void)
+{
+	struct ip_vs_protocol *pp;
+	int i;
+
+	/* unregister all the ipvs protocols */
+	for (i = 0; i < IP_VS_PROTO_TAB_SIZE; i++) {
+		while ((pp = ip_vs_proto_table[i]) != NULL)
+			unregister_ip_vs_protocol(pp);
+	}
+}
diff --git a/net/netfilter/ipvs/ip_vs_proto_ah_esp.c b/net/netfilter/ipvs/ip_vs_proto_ah_esp.c
new file mode 100644
index 0000000..80ab0c8
--- /dev/null
+++ b/net/netfilter/ipvs/ip_vs_proto_ah_esp.c
@@ -0,0 +1,235 @@
+/*
+ * ip_vs_proto_ah_esp.c:	AH/ESP IPSec load balancing support for IPVS
+ *
+ * Authors:	Julian Anastasov <ja@ssi.bg>, February 2002
+ *		Wensong Zhang <wensong@linuxvirtualserver.org>
+ *
+ *		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/in.h>
+#include <linux/ip.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/netfilter.h>
+#include <linux/netfilter_ipv4.h>
+
+#include <net/ip_vs.h>
+
+
+/* TODO:
+
+struct isakmp_hdr {
+	__u8		icookie[8];
+	__u8		rcookie[8];
+	__u8		np;
+	__u8		version;
+	__u8		xchgtype;
+	__u8		flags;
+	__u32		msgid;
+	__u32		length;
+};
+
+*/
+
+#define PORT_ISAKMP	500
+
+
+static struct ip_vs_conn *
+ah_esp_conn_in_get(int af, const struct sk_buff *skb, struct ip_vs_protocol *pp,
+		   const struct ip_vs_iphdr *iph, unsigned int proto_off,
+		   int inverse)
+{
+	struct ip_vs_conn *cp;
+
+	if (likely(!inverse)) {
+		cp = ip_vs_conn_in_get(af, IPPROTO_UDP,
+				       &iph->saddr,
+				       htons(PORT_ISAKMP),
+				       &iph->daddr,
+				       htons(PORT_ISAKMP));
+	} else {
+		cp = ip_vs_conn_in_get(af, IPPROTO_UDP,
+				       &iph->daddr,
+				       htons(PORT_ISAKMP),
+				       &iph->saddr,
+				       htons(PORT_ISAKMP));
+	}
+
+	if (!cp) {
+		/*
+		 * We are not sure if the packet is from our
+		 * service, so our conn_schedule hook should return NF_ACCEPT
+		 */
+		IP_VS_DBG_BUF(12, "Unknown ISAKMP entry for outin packet "
+			      "%s%s %s->%s\n",
+			      inverse ? "ICMP+" : "",
+			      pp->name,
+			      IP_VS_DBG_ADDR(af, &iph->saddr),
+			      IP_VS_DBG_ADDR(af, &iph->daddr));
+	}
+
+	return cp;
+}
+
+
+static struct ip_vs_conn *
+ah_esp_conn_out_get(int af, const struct sk_buff *skb,
+		    struct ip_vs_protocol *pp,
+		    const struct ip_vs_iphdr *iph,
+		    unsigned int proto_off,
+		    int inverse)
+{
+	struct ip_vs_conn *cp;
+
+	if (likely(!inverse)) {
+		cp = ip_vs_conn_out_get(af, IPPROTO_UDP,
+					&iph->saddr,
+					htons(PORT_ISAKMP),
+					&iph->daddr,
+					htons(PORT_ISAKMP));
+	} else {
+		cp = ip_vs_conn_out_get(af, IPPROTO_UDP,
+					&iph->daddr,
+					htons(PORT_ISAKMP),
+					&iph->saddr,
+					htons(PORT_ISAKMP));
+	}
+
+	if (!cp) {
+		IP_VS_DBG_BUF(12, "Unknown ISAKMP entry for inout packet "
+			      "%s%s %s->%s\n",
+			      inverse ? "ICMP+" : "",
+			      pp->name,
+			      IP_VS_DBG_ADDR(af, &iph->saddr),
+			      IP_VS_DBG_ADDR(af, &iph->daddr));
+	}
+
+	return cp;
+}
+
+
+static int
+ah_esp_conn_schedule(int af, struct sk_buff *skb, struct ip_vs_protocol *pp,
+		     int *verdict, struct ip_vs_conn **cpp)
+{
+	/*
+	 * AH/ESP is only related traffic. Pass the packet to IP stack.
+	 */
+	*verdict = NF_ACCEPT;
+	return 0;
+}
+
+
+static void
+ah_esp_debug_packet_v4(struct ip_vs_protocol *pp, const struct sk_buff *skb,
+		       int offset, const char *msg)
+{
+	char buf[256];
+	struct iphdr _iph, *ih;
+
+	ih = skb_header_pointer(skb, offset, sizeof(_iph), &_iph);
+	if (ih == NULL)
+		sprintf(buf, "%s TRUNCATED", pp->name);
+	else
+		sprintf(buf, "%s %u.%u.%u.%u->%u.%u.%u.%u",
+			pp->name, NIPQUAD(ih->saddr),
+			NIPQUAD(ih->daddr));
+
+	printk(KERN_DEBUG "IPVS: %s: %s\n", msg, buf);
+}
+
+#ifdef CONFIG_IP_VS_IPV6
+static void
+ah_esp_debug_packet_v6(struct ip_vs_protocol *pp, const struct sk_buff *skb,
+		       int offset, const char *msg)
+{
+	char buf[256];
+	struct ipv6hdr _iph, *ih;
+
+	ih = skb_header_pointer(skb, offset, sizeof(_iph), &_iph);
+	if (ih == NULL)
+		sprintf(buf, "%s TRUNCATED", pp->name);
+	else
+		sprintf(buf, "%s " NIP6_FMT "->" NIP6_FMT,
+			pp->name, NIP6(ih->saddr),
+			NIP6(ih->daddr));
+
+	printk(KERN_DEBUG "IPVS: %s: %s\n", msg, buf);
+}
+#endif
+
+static void
+ah_esp_debug_packet(struct ip_vs_protocol *pp, const struct sk_buff *skb,
+		    int offset, const char *msg)
+{
+#ifdef CONFIG_IP_VS_IPV6
+	if (skb->protocol == htons(ETH_P_IPV6))
+		ah_esp_debug_packet_v6(pp, skb, offset, msg);
+	else
+#endif
+		ah_esp_debug_packet_v4(pp, skb, offset, msg);
+}
+
+
+static void ah_esp_init(struct ip_vs_protocol *pp)
+{
+	/* nothing to do now */
+}
+
+
+static void ah_esp_exit(struct ip_vs_protocol *pp)
+{
+	/* nothing to do now */
+}
+
+
+#ifdef CONFIG_IP_VS_PROTO_AH
+struct ip_vs_protocol ip_vs_protocol_ah = {
+	.name =			"AH",
+	.protocol =		IPPROTO_AH,
+	.num_states =		1,
+	.dont_defrag =		1,
+	.init =			ah_esp_init,
+	.exit =			ah_esp_exit,
+	.conn_schedule =	ah_esp_conn_schedule,
+	.conn_in_get =		ah_esp_conn_in_get,
+	.conn_out_get =		ah_esp_conn_out_get,
+	.snat_handler =		NULL,
+	.dnat_handler =		NULL,
+	.csum_check =		NULL,
+	.state_transition =	NULL,
+	.register_app =		NULL,
+	.unregister_app =	NULL,
+	.app_conn_bind =	NULL,
+	.debug_packet =		ah_esp_debug_packet,
+	.timeout_change =	NULL,		/* ISAKMP */
+	.set_state_timeout =	NULL,
+};
+#endif
+
+#ifdef CONFIG_IP_VS_PROTO_ESP
+struct ip_vs_protocol ip_vs_protocol_esp = {
+	.name =			"ESP",
+	.protocol =		IPPROTO_ESP,
+	.num_states =		1,
+	.dont_defrag =		1,
+	.init =			ah_esp_init,
+	.exit =			ah_esp_exit,
+	.conn_schedule =	ah_esp_conn_schedule,
+	.conn_in_get =		ah_esp_conn_in_get,
+	.conn_out_get =		ah_esp_conn_out_get,
+	.snat_handler =		NULL,
+	.dnat_handler =		NULL,
+	.csum_check =		NULL,
+	.state_transition =	NULL,
+	.register_app =		NULL,
+	.unregister_app =	NULL,
+	.app_conn_bind =	NULL,
+	.debug_packet =		ah_esp_debug_packet,
+	.timeout_change =	NULL,		/* ISAKMP */
+};
+#endif
diff --git a/net/netfilter/ipvs/ip_vs_proto_tcp.c b/net/netfilter/ipvs/ip_vs_proto_tcp.c
new file mode 100644
index 0000000..dd4566e
--- /dev/null
+++ b/net/netfilter/ipvs/ip_vs_proto_tcp.c
@@ -0,0 +1,732 @@
+/*
+ * ip_vs_proto_tcp.c:	TCP load balancing support for IPVS
+ *
+ * Authors:     Wensong Zhang <wensong@linuxvirtualserver.org>
+ *              Julian Anastasov <ja@ssi.bg>
+ *
+ *              This program is free software; you can redistribute it and/or
+ *              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.
+ *
+ * Changes:
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/ip.h>
+#include <linux/tcp.h>                  /* for tcphdr */
+#include <net/ip.h>
+#include <net/tcp.h>                    /* for csum_tcpudp_magic */
+#include <net/ip6_checksum.h>
+#include <linux/netfilter.h>
+#include <linux/netfilter_ipv4.h>
+
+#include <net/ip_vs.h>
+
+
+static struct ip_vs_conn *
+tcp_conn_in_get(int af, const struct sk_buff *skb, struct ip_vs_protocol *pp,
+		const struct ip_vs_iphdr *iph, unsigned int proto_off,
+		int inverse)
+{
+	__be16 _ports[2], *pptr;
+
+	pptr = skb_header_pointer(skb, proto_off, sizeof(_ports), _ports);
+	if (pptr == NULL)
+		return NULL;
+
+	if (likely(!inverse)) {
+		return ip_vs_conn_in_get(af, iph->protocol,
+					 &iph->saddr, pptr[0],
+					 &iph->daddr, pptr[1]);
+	} else {
+		return ip_vs_conn_in_get(af, iph->protocol,
+					 &iph->daddr, pptr[1],
+					 &iph->saddr, pptr[0]);
+	}
+}
+
+static struct ip_vs_conn *
+tcp_conn_out_get(int af, const struct sk_buff *skb, struct ip_vs_protocol *pp,
+		 const struct ip_vs_iphdr *iph, unsigned int proto_off,
+		 int inverse)
+{
+	__be16 _ports[2], *pptr;
+
+	pptr = skb_header_pointer(skb, proto_off, sizeof(_ports), _ports);
+	if (pptr == NULL)
+		return NULL;
+
+	if (likely(!inverse)) {
+		return ip_vs_conn_out_get(af, iph->protocol,
+					  &iph->saddr, pptr[0],
+					  &iph->daddr, pptr[1]);
+	} else {
+		return ip_vs_conn_out_get(af, iph->protocol,
+					  &iph->daddr, pptr[1],
+					  &iph->saddr, pptr[0]);
+	}
+}
+
+
+static int
+tcp_conn_schedule(int af, struct sk_buff *skb, struct ip_vs_protocol *pp,
+		  int *verdict, struct ip_vs_conn **cpp)
+{
+	struct ip_vs_service *svc;
+	struct tcphdr _tcph, *th;
+	struct ip_vs_iphdr iph;
+
+	ip_vs_fill_iphdr(af, skb_network_header(skb), &iph);
+
+	th = skb_header_pointer(skb, iph.len, sizeof(_tcph), &_tcph);
+	if (th == NULL) {
+		*verdict = NF_DROP;
+		return 0;
+	}
+
+	if (th->syn &&
+	    (svc = ip_vs_service_get(af, skb->mark, iph.protocol, &iph.daddr,
+				     th->dest))) {
+		if (ip_vs_todrop()) {
+			/*
+			 * It seems that we are very loaded.
+			 * We have to drop this packet :(
+			 */
+			ip_vs_service_put(svc);
+			*verdict = NF_DROP;
+			return 0;
+		}
+
+		/*
+		 * Let the virtual server select a real server for the
+		 * incoming connection, and create a connection entry.
+		 */
+		*cpp = ip_vs_schedule(svc, skb);
+		if (!*cpp) {
+			*verdict = ip_vs_leave(svc, skb, pp);
+			return 0;
+		}
+		ip_vs_service_put(svc);
+	}
+	return 1;
+}
+
+
+static inline void
+tcp_fast_csum_update(int af, struct tcphdr *tcph,
+		     const union nf_inet_addr *oldip,
+		     const union nf_inet_addr *newip,
+		     __be16 oldport, __be16 newport)
+{
+#ifdef CONFIG_IP_VS_IPV6
+	if (af == AF_INET6)
+		tcph->check =
+			csum_fold(ip_vs_check_diff16(oldip->ip6, newip->ip6,
+					 ip_vs_check_diff2(oldport, newport,
+						~csum_unfold(tcph->check))));
+	else
+#endif
+	tcph->check =
+		csum_fold(ip_vs_check_diff4(oldip->ip, newip->ip,
+				 ip_vs_check_diff2(oldport, newport,
+						~csum_unfold(tcph->check))));
+}
+
+
+static inline void
+tcp_partial_csum_update(int af, struct tcphdr *tcph,
+		     const union nf_inet_addr *oldip,
+		     const union nf_inet_addr *newip,
+		     __be16 oldlen, __be16 newlen)
+{
+#ifdef CONFIG_IP_VS_IPV6
+	if (af == AF_INET6)
+		tcph->check =
+			csum_fold(ip_vs_check_diff16(oldip->ip6, newip->ip6,
+					 ip_vs_check_diff2(oldlen, newlen,
+						~csum_unfold(tcph->check))));
+	else
+#endif
+	tcph->check =
+		csum_fold(ip_vs_check_diff4(oldip->ip, newip->ip,
+				ip_vs_check_diff2(oldlen, newlen,
+						~csum_unfold(tcph->check))));
+}
+
+
+static int
+tcp_snat_handler(struct sk_buff *skb,
+		 struct ip_vs_protocol *pp, struct ip_vs_conn *cp)
+{
+	struct tcphdr *tcph;
+	unsigned int tcphoff;
+	int oldlen;
+
+#ifdef CONFIG_IP_VS_IPV6
+	if (cp->af == AF_INET6)
+		tcphoff = sizeof(struct ipv6hdr);
+	else
+#endif
+		tcphoff = ip_hdrlen(skb);
+	oldlen = skb->len - tcphoff;
+
+	/* csum_check requires unshared skb */
+	if (!skb_make_writable(skb, tcphoff+sizeof(*tcph)))
+		return 0;
+
+	if (unlikely(cp->app != NULL)) {
+		/* Some checks before mangling */
+		if (pp->csum_check && !pp->csum_check(cp->af, skb, pp))
+			return 0;
+
+		/* Call application helper if needed */
+		if (!ip_vs_app_pkt_out(cp, skb))
+			return 0;
+	}
+
+	tcph = (void *)skb_network_header(skb) + tcphoff;
+	tcph->source = cp->vport;
+
+	/* Adjust TCP checksums */
+	if (skb->ip_summed == CHECKSUM_PARTIAL) {
+		tcp_partial_csum_update(cp->af, tcph, &cp->daddr, &cp->vaddr,
+					htonl(oldlen),
+					htonl(skb->len - tcphoff));
+	} else if (!cp->app) {
+		/* Only port and addr are changed, do fast csum update */
+		tcp_fast_csum_update(cp->af, tcph, &cp->daddr, &cp->vaddr,
+				     cp->dport, cp->vport);
+		if (skb->ip_summed == CHECKSUM_COMPLETE)
+			skb->ip_summed = CHECKSUM_NONE;
+	} else {
+		/* full checksum calculation */
+		tcph->check = 0;
+		skb->csum = skb_checksum(skb, tcphoff, skb->len - tcphoff, 0);
+#ifdef CONFIG_IP_VS_IPV6
+		if (cp->af == AF_INET6)
+			tcph->check = csum_ipv6_magic(&cp->vaddr.in6,
+						      &cp->caddr.in6,
+						      skb->len - tcphoff,
+						      cp->protocol, skb->csum);
+		else
+#endif
+			tcph->check = csum_tcpudp_magic(cp->vaddr.ip,
+							cp->caddr.ip,
+							skb->len - tcphoff,
+							cp->protocol,
+							skb->csum);
+
+		IP_VS_DBG(11, "O-pkt: %s O-csum=%d (+%zd)\n",
+			  pp->name, tcph->check,
+			  (char*)&(tcph->check) - (char*)tcph);
+	}
+	return 1;
+}
+
+
+static int
+tcp_dnat_handler(struct sk_buff *skb,
+		 struct ip_vs_protocol *pp, struct ip_vs_conn *cp)
+{
+	struct tcphdr *tcph;
+	unsigned int tcphoff;
+	int oldlen;
+
+#ifdef CONFIG_IP_VS_IPV6
+	if (cp->af == AF_INET6)
+		tcphoff = sizeof(struct ipv6hdr);
+	else
+#endif
+		tcphoff = ip_hdrlen(skb);
+	oldlen = skb->len - tcphoff;
+
+	/* csum_check requires unshared skb */
+	if (!skb_make_writable(skb, tcphoff+sizeof(*tcph)))
+		return 0;
+
+	if (unlikely(cp->app != NULL)) {
+		/* Some checks before mangling */
+		if (pp->csum_check && !pp->csum_check(cp->af, skb, pp))
+			return 0;
+
+		/*
+		 *	Attempt ip_vs_app call.
+		 *	It will fix ip_vs_conn and iph ack_seq stuff
+		 */
+		if (!ip_vs_app_pkt_in(cp, skb))
+			return 0;
+	}
+
+	tcph = (void *)skb_network_header(skb) + tcphoff;
+	tcph->dest = cp->dport;
+
+	/*
+	 *	Adjust TCP checksums
+	 */
+	if (skb->ip_summed == CHECKSUM_PARTIAL) {
+		tcp_partial_csum_update(cp->af, tcph, &cp->daddr, &cp->vaddr,
+					htonl(oldlen),
+					htonl(skb->len - tcphoff));
+	} else if (!cp->app) {
+		/* Only port and addr are changed, do fast csum update */
+		tcp_fast_csum_update(cp->af, tcph, &cp->vaddr, &cp->daddr,
+				     cp->vport, cp->dport);
+		if (skb->ip_summed == CHECKSUM_COMPLETE)
+			skb->ip_summed = CHECKSUM_NONE;
+	} else {
+		/* full checksum calculation */
+		tcph->check = 0;
+		skb->csum = skb_checksum(skb, tcphoff, skb->len - tcphoff, 0);
+#ifdef CONFIG_IP_VS_IPV6
+		if (cp->af == AF_INET6)
+			tcph->check = csum_ipv6_magic(&cp->caddr.in6,
+						      &cp->daddr.in6,
+						      skb->len - tcphoff,
+						      cp->protocol, skb->csum);
+		else
+#endif
+			tcph->check = csum_tcpudp_magic(cp->caddr.ip,
+							cp->daddr.ip,
+							skb->len - tcphoff,
+							cp->protocol,
+							skb->csum);
+		skb->ip_summed = CHECKSUM_UNNECESSARY;
+	}
+	return 1;
+}
+
+
+static int
+tcp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp)
+{
+	unsigned int tcphoff;
+
+#ifdef CONFIG_IP_VS_IPV6
+	if (af == AF_INET6)
+		tcphoff = sizeof(struct ipv6hdr);
+	else
+#endif
+		tcphoff = ip_hdrlen(skb);
+
+	switch (skb->ip_summed) {
+	case CHECKSUM_NONE:
+		skb->csum = skb_checksum(skb, tcphoff, skb->len - tcphoff, 0);
+	case CHECKSUM_COMPLETE:
+#ifdef CONFIG_IP_VS_IPV6
+		if (af == AF_INET6) {
+			if (csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
+					    &ipv6_hdr(skb)->daddr,
+					    skb->len - tcphoff,
+					    ipv6_hdr(skb)->nexthdr,
+					    skb->csum)) {
+				IP_VS_DBG_RL_PKT(0, pp, skb, 0,
+						 "Failed checksum for");
+				return 0;
+			}
+		} else
+#endif
+			if (csum_tcpudp_magic(ip_hdr(skb)->saddr,
+					      ip_hdr(skb)->daddr,
+					      skb->len - tcphoff,
+					      ip_hdr(skb)->protocol,
+					      skb->csum)) {
+				IP_VS_DBG_RL_PKT(0, pp, skb, 0,
+						 "Failed checksum for");
+				return 0;
+			}
+		break;
+	default:
+		/* No need to checksum. */
+		break;
+	}
+
+	return 1;
+}
+
+
+#define TCP_DIR_INPUT		0
+#define TCP_DIR_OUTPUT		4
+#define TCP_DIR_INPUT_ONLY	8
+
+static const int tcp_state_off[IP_VS_DIR_LAST] = {
+	[IP_VS_DIR_INPUT]		=	TCP_DIR_INPUT,
+	[IP_VS_DIR_OUTPUT]		=	TCP_DIR_OUTPUT,
+	[IP_VS_DIR_INPUT_ONLY]		=	TCP_DIR_INPUT_ONLY,
+};
+
+/*
+ *	Timeout table[state]
+ */
+static int tcp_timeouts[IP_VS_TCP_S_LAST+1] = {
+	[IP_VS_TCP_S_NONE]		=	2*HZ,
+	[IP_VS_TCP_S_ESTABLISHED]	=	15*60*HZ,
+	[IP_VS_TCP_S_SYN_SENT]		=	2*60*HZ,
+	[IP_VS_TCP_S_SYN_RECV]		=	1*60*HZ,
+	[IP_VS_TCP_S_FIN_WAIT]		=	2*60*HZ,
+	[IP_VS_TCP_S_TIME_WAIT]		=	2*60*HZ,
+	[IP_VS_TCP_S_CLOSE]		=	10*HZ,
+	[IP_VS_TCP_S_CLOSE_WAIT]	=	60*HZ,
+	[IP_VS_TCP_S_LAST_ACK]		=	30*HZ,
+	[IP_VS_TCP_S_LISTEN]		=	2*60*HZ,
+	[IP_VS_TCP_S_SYNACK]		=	120*HZ,
+	[IP_VS_TCP_S_LAST]		=	2*HZ,
+};
+
+static char * tcp_state_name_table[IP_VS_TCP_S_LAST+1] = {
+	[IP_VS_TCP_S_NONE]		=	"NONE",
+	[IP_VS_TCP_S_ESTABLISHED]	=	"ESTABLISHED",
+	[IP_VS_TCP_S_SYN_SENT]		=	"SYN_SENT",
+	[IP_VS_TCP_S_SYN_RECV]		=	"SYN_RECV",
+	[IP_VS_TCP_S_FIN_WAIT]		=	"FIN_WAIT",
+	[IP_VS_TCP_S_TIME_WAIT]		=	"TIME_WAIT",
+	[IP_VS_TCP_S_CLOSE]		=	"CLOSE",
+	[IP_VS_TCP_S_CLOSE_WAIT]	=	"CLOSE_WAIT",
+	[IP_VS_TCP_S_LAST_ACK]		=	"LAST_ACK",
+	[IP_VS_TCP_S_LISTEN]		=	"LISTEN",
+	[IP_VS_TCP_S_SYNACK]		=	"SYNACK",
+	[IP_VS_TCP_S_LAST]		=	"BUG!",
+};
+
+#define sNO IP_VS_TCP_S_NONE
+#define sES IP_VS_TCP_S_ESTABLISHED
+#define sSS IP_VS_TCP_S_SYN_SENT
+#define sSR IP_VS_TCP_S_SYN_RECV
+#define sFW IP_VS_TCP_S_FIN_WAIT
+#define sTW IP_VS_TCP_S_TIME_WAIT
+#define sCL IP_VS_TCP_S_CLOSE
+#define sCW IP_VS_TCP_S_CLOSE_WAIT
+#define sLA IP_VS_TCP_S_LAST_ACK
+#define sLI IP_VS_TCP_S_LISTEN
+#define sSA IP_VS_TCP_S_SYNACK
+
+struct tcp_states_t {
+	int next_state[IP_VS_TCP_S_LAST];
+};
+
+static const char * tcp_state_name(int state)
+{
+	if (state >= IP_VS_TCP_S_LAST)
+		return "ERR!";
+	return tcp_state_name_table[state] ? tcp_state_name_table[state] : "?";
+}
+
+static struct tcp_states_t tcp_states [] = {
+/*	INPUT */
+/*        sNO, sES, sSS, sSR, sFW, sTW, sCL, sCW, sLA, sLI, sSA	*/
+/*syn*/ {{sSR, sES, sES, sSR, sSR, sSR, sSR, sSR, sSR, sSR, sSR }},
+/*fin*/ {{sCL, sCW, sSS, sTW, sTW, sTW, sCL, sCW, sLA, sLI, sTW }},
+/*ack*/ {{sCL, sES, sSS, sES, sFW, sTW, sCL, sCW, sCL, sLI, sES }},
+/*rst*/ {{sCL, sCL, sCL, sSR, sCL, sCL, sCL, sCL, sLA, sLI, sSR }},
+
+/*	OUTPUT */
+/*        sNO, sES, sSS, sSR, sFW, sTW, sCL, sCW, sLA, sLI, sSA	*/
+/*syn*/ {{sSS, sES, sSS, sSR, sSS, sSS, sSS, sSS, sSS, sLI, sSR }},
+/*fin*/ {{sTW, sFW, sSS, sTW, sFW, sTW, sCL, sTW, sLA, sLI, sTW }},
+/*ack*/ {{sES, sES, sSS, sES, sFW, sTW, sCL, sCW, sLA, sES, sES }},
+/*rst*/ {{sCL, sCL, sSS, sCL, sCL, sTW, sCL, sCL, sCL, sCL, sCL }},
+
+/*	INPUT-ONLY */
+/*        sNO, sES, sSS, sSR, sFW, sTW, sCL, sCW, sLA, sLI, sSA	*/
+/*syn*/ {{sSR, sES, sES, sSR, sSR, sSR, sSR, sSR, sSR, sSR, sSR }},
+/*fin*/ {{sCL, sFW, sSS, sTW, sFW, sTW, sCL, sCW, sLA, sLI, sTW }},
+/*ack*/ {{sCL, sES, sSS, sES, sFW, sTW, sCL, sCW, sCL, sLI, sES }},
+/*rst*/ {{sCL, sCL, sCL, sSR, sCL, sCL, sCL, sCL, sLA, sLI, sCL }},
+};
+
+static struct tcp_states_t tcp_states_dos [] = {
+/*	INPUT */
+/*        sNO, sES, sSS, sSR, sFW, sTW, sCL, sCW, sLA, sLI, sSA	*/
+/*syn*/ {{sSR, sES, sES, sSR, sSR, sSR, sSR, sSR, sSR, sSR, sSA }},
+/*fin*/ {{sCL, sCW, sSS, sTW, sTW, sTW, sCL, sCW, sLA, sLI, sSA }},
+/*ack*/ {{sCL, sES, sSS, sSR, sFW, sTW, sCL, sCW, sCL, sLI, sSA }},
+/*rst*/ {{sCL, sCL, sCL, sSR, sCL, sCL, sCL, sCL, sLA, sLI, sCL }},
+
+/*	OUTPUT */
+/*        sNO, sES, sSS, sSR, sFW, sTW, sCL, sCW, sLA, sLI, sSA	*/
+/*syn*/ {{sSS, sES, sSS, sSA, sSS, sSS, sSS, sSS, sSS, sLI, sSA }},
+/*fin*/ {{sTW, sFW, sSS, sTW, sFW, sTW, sCL, sTW, sLA, sLI, sTW }},
+/*ack*/ {{sES, sES, sSS, sES, sFW, sTW, sCL, sCW, sLA, sES, sES }},
+/*rst*/ {{sCL, sCL, sSS, sCL, sCL, sTW, sCL, sCL, sCL, sCL, sCL }},
+
+/*	INPUT-ONLY */
+/*        sNO, sES, sSS, sSR, sFW, sTW, sCL, sCW, sLA, sLI, sSA	*/
+/*syn*/ {{sSA, sES, sES, sSR, sSA, sSA, sSA, sSA, sSA, sSA, sSA }},
+/*fin*/ {{sCL, sFW, sSS, sTW, sFW, sTW, sCL, sCW, sLA, sLI, sTW }},
+/*ack*/ {{sCL, sES, sSS, sES, sFW, sTW, sCL, sCW, sCL, sLI, sES }},
+/*rst*/ {{sCL, sCL, sCL, sSR, sCL, sCL, sCL, sCL, sLA, sLI, sCL }},
+};
+
+static struct tcp_states_t *tcp_state_table = tcp_states;
+
+
+static void tcp_timeout_change(struct ip_vs_protocol *pp, int flags)
+{
+	int on = (flags & 1);		/* secure_tcp */
+
+	/*
+	** FIXME: change secure_tcp to independent sysctl var
+	** or make it per-service or per-app because it is valid
+	** for most if not for all of the applications. Something
+	** like "capabilities" (flags) for each object.
+	*/
+	tcp_state_table = (on? tcp_states_dos : tcp_states);
+}
+
+static int
+tcp_set_state_timeout(struct ip_vs_protocol *pp, char *sname, int to)
+{
+	return ip_vs_set_state_timeout(pp->timeout_table, IP_VS_TCP_S_LAST,
+				       tcp_state_name_table, sname, to);
+}
+
+static inline int tcp_state_idx(struct tcphdr *th)
+{
+	if (th->rst)
+		return 3;
+	if (th->syn)
+		return 0;
+	if (th->fin)
+		return 1;
+	if (th->ack)
+		return 2;
+	return -1;
+}
+
+static inline void
+set_tcp_state(struct ip_vs_protocol *pp, struct ip_vs_conn *cp,
+	      int direction, struct tcphdr *th)
+{
+	int state_idx;
+	int new_state = IP_VS_TCP_S_CLOSE;
+	int state_off = tcp_state_off[direction];
+
+	/*
+	 *    Update state offset to INPUT_ONLY if necessary
+	 *    or delete NO_OUTPUT flag if output packet detected
+	 */
+	if (cp->flags & IP_VS_CONN_F_NOOUTPUT) {
+		if (state_off == TCP_DIR_OUTPUT)
+			cp->flags &= ~IP_VS_CONN_F_NOOUTPUT;
+		else
+			state_off = TCP_DIR_INPUT_ONLY;
+	}
+
+	if ((state_idx = tcp_state_idx(th)) < 0) {
+		IP_VS_DBG(8, "tcp_state_idx=%d!!!\n", state_idx);
+		goto tcp_state_out;
+	}
+
+	new_state = tcp_state_table[state_off+state_idx].next_state[cp->state];
+
+  tcp_state_out:
+	if (new_state != cp->state) {
+		struct ip_vs_dest *dest = cp->dest;
+
+		IP_VS_DBG_BUF(8, "%s %s [%c%c%c%c] %s:%d->"
+			      "%s:%d state: %s->%s conn->refcnt:%d\n",
+			      pp->name,
+			      ((state_off == TCP_DIR_OUTPUT) ?
+			       "output " : "input "),
+			      th->syn ? 'S' : '.',
+			      th->fin ? 'F' : '.',
+			      th->ack ? 'A' : '.',
+			      th->rst ? 'R' : '.',
+			      IP_VS_DBG_ADDR(cp->af, &cp->daddr),
+			      ntohs(cp->dport),
+			      IP_VS_DBG_ADDR(cp->af, &cp->caddr),
+			      ntohs(cp->cport),
+			      tcp_state_name(cp->state),
+			      tcp_state_name(new_state),
+			      atomic_read(&cp->refcnt));
+
+		if (dest) {
+			if (!(cp->flags & IP_VS_CONN_F_INACTIVE) &&
+			    (new_state != IP_VS_TCP_S_ESTABLISHED)) {
+				atomic_dec(&dest->activeconns);
+				atomic_inc(&dest->inactconns);
+				cp->flags |= IP_VS_CONN_F_INACTIVE;
+			} else if ((cp->flags & IP_VS_CONN_F_INACTIVE) &&
+				   (new_state == IP_VS_TCP_S_ESTABLISHED)) {
+				atomic_inc(&dest->activeconns);
+				atomic_dec(&dest->inactconns);
+				cp->flags &= ~IP_VS_CONN_F_INACTIVE;
+			}
+		}
+	}
+
+	cp->timeout = pp->timeout_table[cp->state = new_state];
+}
+
+
+/*
+ *	Handle state transitions
+ */
+static int
+tcp_state_transition(struct ip_vs_conn *cp, int direction,
+		     const struct sk_buff *skb,
+		     struct ip_vs_protocol *pp)
+{
+	struct tcphdr _tcph, *th;
+
+#ifdef CONFIG_IP_VS_IPV6
+	int ihl = cp->af == AF_INET ? ip_hdrlen(skb) : sizeof(struct ipv6hdr);
+#else
+	int ihl = ip_hdrlen(skb);
+#endif
+
+	th = skb_header_pointer(skb, ihl, sizeof(_tcph), &_tcph);
+	if (th == NULL)
+		return 0;
+
+	spin_lock(&cp->lock);
+	set_tcp_state(pp, cp, direction, th);
+	spin_unlock(&cp->lock);
+
+	return 1;
+}
+
+
+/*
+ *	Hash table for TCP application incarnations
+ */
+#define	TCP_APP_TAB_BITS	4
+#define	TCP_APP_TAB_SIZE	(1 << TCP_APP_TAB_BITS)
+#define	TCP_APP_TAB_MASK	(TCP_APP_TAB_SIZE - 1)
+
+static struct list_head tcp_apps[TCP_APP_TAB_SIZE];
+static DEFINE_SPINLOCK(tcp_app_lock);
+
+static inline __u16 tcp_app_hashkey(__be16 port)
+{
+	return (((__force u16)port >> TCP_APP_TAB_BITS) ^ (__force u16)port)
+		& TCP_APP_TAB_MASK;
+}
+
+
+static int tcp_register_app(struct ip_vs_app *inc)
+{
+	struct ip_vs_app *i;
+	__u16 hash;
+	__be16 port = inc->port;
+	int ret = 0;
+
+	hash = tcp_app_hashkey(port);
+
+	spin_lock_bh(&tcp_app_lock);
+	list_for_each_entry(i, &tcp_apps[hash], p_list) {
+		if (i->port == port) {
+			ret = -EEXIST;
+			goto out;
+		}
+	}
+	list_add(&inc->p_list, &tcp_apps[hash]);
+	atomic_inc(&ip_vs_protocol_tcp.appcnt);
+
+  out:
+	spin_unlock_bh(&tcp_app_lock);
+	return ret;
+}
+
+
+static void
+tcp_unregister_app(struct ip_vs_app *inc)
+{
+	spin_lock_bh(&tcp_app_lock);
+	atomic_dec(&ip_vs_protocol_tcp.appcnt);
+	list_del(&inc->p_list);
+	spin_unlock_bh(&tcp_app_lock);
+}
+
+
+static int
+tcp_app_conn_bind(struct ip_vs_conn *cp)
+{
+	int hash;
+	struct ip_vs_app *inc;
+	int result = 0;
+
+	/* Default binding: bind app only for NAT */
+	if (IP_VS_FWD_METHOD(cp) != IP_VS_CONN_F_MASQ)
+		return 0;
+
+	/* Lookup application incarnations and bind the right one */
+	hash = tcp_app_hashkey(cp->vport);
+
+	spin_lock(&tcp_app_lock);
+	list_for_each_entry(inc, &tcp_apps[hash], p_list) {
+		if (inc->port == cp->vport) {
+			if (unlikely(!ip_vs_app_inc_get(inc)))
+				break;
+			spin_unlock(&tcp_app_lock);
+
+			IP_VS_DBG_BUF(9, "%s: Binding conn %s:%u->"
+				      "%s:%u to app %s on port %u\n",
+				      __func__,
+				      IP_VS_DBG_ADDR(cp->af, &cp->caddr),
+				      ntohs(cp->cport),
+				      IP_VS_DBG_ADDR(cp->af, &cp->vaddr),
+				      ntohs(cp->vport),
+				      inc->name, ntohs(inc->port));
+
+			cp->app = inc;
+			if (inc->init_conn)
+				result = inc->init_conn(inc, cp);
+			goto out;
+		}
+	}
+	spin_unlock(&tcp_app_lock);
+
+  out:
+	return result;
+}
+
+
+/*
+ *	Set LISTEN timeout. (ip_vs_conn_put will setup timer)
+ */
+void ip_vs_tcp_conn_listen(struct ip_vs_conn *cp)
+{
+	spin_lock(&cp->lock);
+	cp->state = IP_VS_TCP_S_LISTEN;
+	cp->timeout = ip_vs_protocol_tcp.timeout_table[IP_VS_TCP_S_LISTEN];
+	spin_unlock(&cp->lock);
+}
+
+
+static void ip_vs_tcp_init(struct ip_vs_protocol *pp)
+{
+	IP_VS_INIT_HASH_TABLE(tcp_apps);
+	pp->timeout_table = tcp_timeouts;
+}
+
+
+static void ip_vs_tcp_exit(struct ip_vs_protocol *pp)
+{
+}
+
+
+struct ip_vs_protocol ip_vs_protocol_tcp = {
+	.name =			"TCP",
+	.protocol =		IPPROTO_TCP,
+	.num_states =		IP_VS_TCP_S_LAST,
+	.dont_defrag =		0,
+	.appcnt =		ATOMIC_INIT(0),
+	.init =			ip_vs_tcp_init,
+	.exit =			ip_vs_tcp_exit,
+	.register_app =		tcp_register_app,
+	.unregister_app =	tcp_unregister_app,
+	.conn_schedule =	tcp_conn_schedule,
+	.conn_in_get =		tcp_conn_in_get,
+	.conn_out_get =		tcp_conn_out_get,
+	.snat_handler =		tcp_snat_handler,
+	.dnat_handler =		tcp_dnat_handler,
+	.csum_check =		tcp_csum_check,
+	.state_name =		tcp_state_name,
+	.state_transition =	tcp_state_transition,
+	.app_conn_bind =	tcp_app_conn_bind,
+	.debug_packet =		ip_vs_tcpudp_debug_packet,
+	.timeout_change =	tcp_timeout_change,
+	.set_state_timeout =	tcp_set_state_timeout,
+};
diff --git a/net/netfilter/ipvs/ip_vs_proto_udp.c b/net/netfilter/ipvs/ip_vs_proto_udp.c
new file mode 100644
index 0000000..6eb6039
--- /dev/null
+++ b/net/netfilter/ipvs/ip_vs_proto_udp.c
@@ -0,0 +1,533 @@
+/*
+ * ip_vs_proto_udp.c:	UDP load balancing support for IPVS
+ *
+ * Authors:     Wensong Zhang <wensong@linuxvirtualserver.org>
+ *              Julian Anastasov <ja@ssi.bg>
+ *
+ *              This program is free software; you can redistribute it and/or
+ *              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.
+ *
+ * Changes:
+ *
+ */
+
+#include <linux/in.h>
+#include <linux/ip.h>
+#include <linux/kernel.h>
+#include <linux/netfilter.h>
+#include <linux/netfilter_ipv4.h>
+#include <linux/udp.h>
+
+#include <net/ip_vs.h>
+#include <net/ip.h>
+#include <net/ip6_checksum.h>
+
+static struct ip_vs_conn *
+udp_conn_in_get(int af, const struct sk_buff *skb, struct ip_vs_protocol *pp,
+		const struct ip_vs_iphdr *iph, unsigned int proto_off,
+		int inverse)
+{
+	struct ip_vs_conn *cp;
+	__be16 _ports[2], *pptr;
+
+	pptr = skb_header_pointer(skb, proto_off, sizeof(_ports), _ports);
+	if (pptr == NULL)
+		return NULL;
+
+	if (likely(!inverse)) {
+		cp = ip_vs_conn_in_get(af, iph->protocol,
+				       &iph->saddr, pptr[0],
+				       &iph->daddr, pptr[1]);
+	} else {
+		cp = ip_vs_conn_in_get(af, iph->protocol,
+				       &iph->daddr, pptr[1],
+				       &iph->saddr, pptr[0]);
+	}
+
+	return cp;
+}
+
+
+static struct ip_vs_conn *
+udp_conn_out_get(int af, const struct sk_buff *skb, struct ip_vs_protocol *pp,
+		 const struct ip_vs_iphdr *iph, unsigned int proto_off,
+		 int inverse)
+{
+	struct ip_vs_conn *cp;
+	__be16 _ports[2], *pptr;
+
+	pptr = skb_header_pointer(skb, proto_off, sizeof(_ports), _ports);
+	if (pptr == NULL)
+		return NULL;
+
+	if (likely(!inverse)) {
+		cp = ip_vs_conn_out_get(af, iph->protocol,
+					&iph->saddr, pptr[0],
+					&iph->daddr, pptr[1]);
+	} else {
+		cp = ip_vs_conn_out_get(af, iph->protocol,
+					&iph->daddr, pptr[1],
+					&iph->saddr, pptr[0]);
+	}
+
+	return cp;
+}
+
+
+static int
+udp_conn_schedule(int af, struct sk_buff *skb, struct ip_vs_protocol *pp,
+		  int *verdict, struct ip_vs_conn **cpp)
+{
+	struct ip_vs_service *svc;
+	struct udphdr _udph, *uh;
+	struct ip_vs_iphdr iph;
+
+	ip_vs_fill_iphdr(af, skb_network_header(skb), &iph);
+
+	uh = skb_header_pointer(skb, iph.len, sizeof(_udph), &_udph);
+	if (uh == NULL) {
+		*verdict = NF_DROP;
+		return 0;
+	}
+
+	svc = ip_vs_service_get(af, skb->mark, iph.protocol,
+				&iph.daddr, uh->dest);
+	if (svc) {
+		if (ip_vs_todrop()) {
+			/*
+			 * It seems that we are very loaded.
+			 * We have to drop this packet :(
+			 */
+			ip_vs_service_put(svc);
+			*verdict = NF_DROP;
+			return 0;
+		}
+
+		/*
+		 * Let the virtual server select a real server for the
+		 * incoming connection, and create a connection entry.
+		 */
+		*cpp = ip_vs_schedule(svc, skb);
+		if (!*cpp) {
+			*verdict = ip_vs_leave(svc, skb, pp);
+			return 0;
+		}
+		ip_vs_service_put(svc);
+	}
+	return 1;
+}
+
+
+static inline void
+udp_fast_csum_update(int af, struct udphdr *uhdr,
+		     const union nf_inet_addr *oldip,
+		     const union nf_inet_addr *newip,
+		     __be16 oldport, __be16 newport)
+{
+#ifdef CONFIG_IP_VS_IPV6
+	if (af == AF_INET6)
+		uhdr->check =
+			csum_fold(ip_vs_check_diff16(oldip->ip6, newip->ip6,
+					 ip_vs_check_diff2(oldport, newport,
+						~csum_unfold(uhdr->check))));
+	else
+#endif
+		uhdr->check =
+			csum_fold(ip_vs_check_diff4(oldip->ip, newip->ip,
+					 ip_vs_check_diff2(oldport, newport,
+						~csum_unfold(uhdr->check))));
+	if (!uhdr->check)
+		uhdr->check = CSUM_MANGLED_0;
+}
+
+static inline void
+udp_partial_csum_update(int af, struct udphdr *uhdr,
+		     const union nf_inet_addr *oldip,
+		     const union nf_inet_addr *newip,
+		     __be16 oldlen, __be16 newlen)
+{
+#ifdef CONFIG_IP_VS_IPV6
+	if (af == AF_INET6)
+		uhdr->check =
+			csum_fold(ip_vs_check_diff16(oldip->ip6, newip->ip6,
+					 ip_vs_check_diff2(oldlen, newlen,
+						~csum_unfold(uhdr->check))));
+	else
+#endif
+	uhdr->check =
+		csum_fold(ip_vs_check_diff4(oldip->ip, newip->ip,
+				ip_vs_check_diff2(oldlen, newlen,
+						~csum_unfold(uhdr->check))));
+}
+
+
+static int
+udp_snat_handler(struct sk_buff *skb,
+		 struct ip_vs_protocol *pp, struct ip_vs_conn *cp)
+{
+	struct udphdr *udph;
+	unsigned int udphoff;
+	int oldlen;
+
+#ifdef CONFIG_IP_VS_IPV6
+	if (cp->af == AF_INET6)
+		udphoff = sizeof(struct ipv6hdr);
+	else
+#endif
+		udphoff = ip_hdrlen(skb);
+	oldlen = skb->len - udphoff;
+
+	/* csum_check requires unshared skb */
+	if (!skb_make_writable(skb, udphoff+sizeof(*udph)))
+		return 0;
+
+	if (unlikely(cp->app != NULL)) {
+		/* Some checks before mangling */
+		if (pp->csum_check && !pp->csum_check(cp->af, skb, pp))
+			return 0;
+
+		/*
+		 *	Call application helper if needed
+		 */
+		if (!ip_vs_app_pkt_out(cp, skb))
+			return 0;
+	}
+
+	udph = (void *)skb_network_header(skb) + udphoff;
+	udph->source = cp->vport;
+
+	/*
+	 *	Adjust UDP checksums
+	 */
+	if (skb->ip_summed == CHECKSUM_PARTIAL) {
+		udp_partial_csum_update(cp->af, udph, &cp->daddr, &cp->vaddr,
+					htonl(oldlen),
+					htonl(skb->len - udphoff));
+	} else if (!cp->app && (udph->check != 0)) {
+		/* Only port and addr are changed, do fast csum update */
+		udp_fast_csum_update(cp->af, udph, &cp->daddr, &cp->vaddr,
+				     cp->dport, cp->vport);
+		if (skb->ip_summed == CHECKSUM_COMPLETE)
+			skb->ip_summed = CHECKSUM_NONE;
+	} else {
+		/* full checksum calculation */
+		udph->check = 0;
+		skb->csum = skb_checksum(skb, udphoff, skb->len - udphoff, 0);
+#ifdef CONFIG_IP_VS_IPV6
+		if (cp->af == AF_INET6)
+			udph->check = csum_ipv6_magic(&cp->vaddr.in6,
+						      &cp->caddr.in6,
+						      skb->len - udphoff,
+						      cp->protocol, skb->csum);
+		else
+#endif
+			udph->check = csum_tcpudp_magic(cp->vaddr.ip,
+							cp->caddr.ip,
+							skb->len - udphoff,
+							cp->protocol,
+							skb->csum);
+		if (udph->check == 0)
+			udph->check = CSUM_MANGLED_0;
+		IP_VS_DBG(11, "O-pkt: %s O-csum=%d (+%zd)\n",
+			  pp->name, udph->check,
+			  (char*)&(udph->check) - (char*)udph);
+	}
+	return 1;
+}
+
+
+static int
+udp_dnat_handler(struct sk_buff *skb,
+		 struct ip_vs_protocol *pp, struct ip_vs_conn *cp)
+{
+	struct udphdr *udph;
+	unsigned int udphoff;
+	int oldlen;
+
+#ifdef CONFIG_IP_VS_IPV6
+	if (cp->af == AF_INET6)
+		udphoff = sizeof(struct ipv6hdr);
+	else
+#endif
+		udphoff = ip_hdrlen(skb);
+	oldlen = skb->len - udphoff;
+
+	/* csum_check requires unshared skb */
+	if (!skb_make_writable(skb, udphoff+sizeof(*udph)))
+		return 0;
+
+	if (unlikely(cp->app != NULL)) {
+		/* Some checks before mangling */
+		if (pp->csum_check && !pp->csum_check(cp->af, skb, pp))
+			return 0;
+
+		/*
+		 *	Attempt ip_vs_app call.
+		 *	It will fix ip_vs_conn
+		 */
+		if (!ip_vs_app_pkt_in(cp, skb))
+			return 0;
+	}
+
+	udph = (void *)skb_network_header(skb) + udphoff;
+	udph->dest = cp->dport;
+
+	/*
+	 *	Adjust UDP checksums
+	 */
+	if (skb->ip_summed == CHECKSUM_PARTIAL) {
+		udp_partial_csum_update(cp->af, udph, &cp->daddr, &cp->vaddr,
+					htonl(oldlen),
+					htonl(skb->len - udphoff));
+	} else if (!cp->app && (udph->check != 0)) {
+		/* Only port and addr are changed, do fast csum update */
+		udp_fast_csum_update(cp->af, udph, &cp->vaddr, &cp->daddr,
+				     cp->vport, cp->dport);
+		if (skb->ip_summed == CHECKSUM_COMPLETE)
+			skb->ip_summed = CHECKSUM_NONE;
+	} else {
+		/* full checksum calculation */
+		udph->check = 0;
+		skb->csum = skb_checksum(skb, udphoff, skb->len - udphoff, 0);
+#ifdef CONFIG_IP_VS_IPV6
+		if (cp->af == AF_INET6)
+			udph->check = csum_ipv6_magic(&cp->caddr.in6,
+						      &cp->daddr.in6,
+						      skb->len - udphoff,
+						      cp->protocol, skb->csum);
+		else
+#endif
+			udph->check = csum_tcpudp_magic(cp->caddr.ip,
+							cp->daddr.ip,
+							skb->len - udphoff,
+							cp->protocol,
+							skb->csum);
+		if (udph->check == 0)
+			udph->check = CSUM_MANGLED_0;
+		skb->ip_summed = CHECKSUM_UNNECESSARY;
+	}
+	return 1;
+}
+
+
+static int
+udp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp)
+{
+	struct udphdr _udph, *uh;
+	unsigned int udphoff;
+
+#ifdef CONFIG_IP_VS_IPV6
+	if (af == AF_INET6)
+		udphoff = sizeof(struct ipv6hdr);
+	else
+#endif
+		udphoff = ip_hdrlen(skb);
+
+	uh = skb_header_pointer(skb, udphoff, sizeof(_udph), &_udph);
+	if (uh == NULL)
+		return 0;
+
+	if (uh->check != 0) {
+		switch (skb->ip_summed) {
+		case CHECKSUM_NONE:
+			skb->csum = skb_checksum(skb, udphoff,
+						 skb->len - udphoff, 0);
+		case CHECKSUM_COMPLETE:
+#ifdef CONFIG_IP_VS_IPV6
+			if (af == AF_INET6) {
+				if (csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
+						    &ipv6_hdr(skb)->daddr,
+						    skb->len - udphoff,
+						    ipv6_hdr(skb)->nexthdr,
+						    skb->csum)) {
+					IP_VS_DBG_RL_PKT(0, pp, skb, 0,
+							 "Failed checksum for");
+					return 0;
+				}
+			} else
+#endif
+				if (csum_tcpudp_magic(ip_hdr(skb)->saddr,
+						      ip_hdr(skb)->daddr,
+						      skb->len - udphoff,
+						      ip_hdr(skb)->protocol,
+						      skb->csum)) {
+					IP_VS_DBG_RL_PKT(0, pp, skb, 0,
+							 "Failed checksum for");
+					return 0;
+				}
+			break;
+		default:
+			/* No need to checksum. */
+			break;
+		}
+	}
+	return 1;
+}
+
+
+/*
+ *	Note: the caller guarantees that only one of register_app,
+ *	unregister_app or app_conn_bind is called each time.
+ */
+
+#define	UDP_APP_TAB_BITS	4
+#define	UDP_APP_TAB_SIZE	(1 << UDP_APP_TAB_BITS)
+#define	UDP_APP_TAB_MASK	(UDP_APP_TAB_SIZE - 1)
+
+static struct list_head udp_apps[UDP_APP_TAB_SIZE];
+static DEFINE_SPINLOCK(udp_app_lock);
+
+static inline __u16 udp_app_hashkey(__be16 port)
+{
+	return (((__force u16)port >> UDP_APP_TAB_BITS) ^ (__force u16)port)
+		& UDP_APP_TAB_MASK;
+}
+
+
+static int udp_register_app(struct ip_vs_app *inc)
+{
+	struct ip_vs_app *i;
+	__u16 hash;
+	__be16 port = inc->port;
+	int ret = 0;
+
+	hash = udp_app_hashkey(port);
+
+
+	spin_lock_bh(&udp_app_lock);
+	list_for_each_entry(i, &udp_apps[hash], p_list) {
+		if (i->port == port) {
+			ret = -EEXIST;
+			goto out;
+		}
+	}
+	list_add(&inc->p_list, &udp_apps[hash]);
+	atomic_inc(&ip_vs_protocol_udp.appcnt);
+
+  out:
+	spin_unlock_bh(&udp_app_lock);
+	return ret;
+}
+
+
+static void
+udp_unregister_app(struct ip_vs_app *inc)
+{
+	spin_lock_bh(&udp_app_lock);
+	atomic_dec(&ip_vs_protocol_udp.appcnt);
+	list_del(&inc->p_list);
+	spin_unlock_bh(&udp_app_lock);
+}
+
+
+static int udp_app_conn_bind(struct ip_vs_conn *cp)
+{
+	int hash;
+	struct ip_vs_app *inc;
+	int result = 0;
+
+	/* Default binding: bind app only for NAT */
+	if (IP_VS_FWD_METHOD(cp) != IP_VS_CONN_F_MASQ)
+		return 0;
+
+	/* Lookup application incarnations and bind the right one */
+	hash = udp_app_hashkey(cp->vport);
+
+	spin_lock(&udp_app_lock);
+	list_for_each_entry(inc, &udp_apps[hash], p_list) {
+		if (inc->port == cp->vport) {
+			if (unlikely(!ip_vs_app_inc_get(inc)))
+				break;
+			spin_unlock(&udp_app_lock);
+
+			IP_VS_DBG_BUF(9, "%s: Binding conn %s:%u->"
+				      "%s:%u to app %s on port %u\n",
+				      __func__,
+				      IP_VS_DBG_ADDR(cp->af, &cp->caddr),
+				      ntohs(cp->cport),
+				      IP_VS_DBG_ADDR(cp->af, &cp->vaddr),
+				      ntohs(cp->vport),
+				      inc->name, ntohs(inc->port));
+
+			cp->app = inc;
+			if (inc->init_conn)
+				result = inc->init_conn(inc, cp);
+			goto out;
+		}
+	}
+	spin_unlock(&udp_app_lock);
+
+  out:
+	return result;
+}
+
+
+static int udp_timeouts[IP_VS_UDP_S_LAST+1] = {
+	[IP_VS_UDP_S_NORMAL]		=	5*60*HZ,
+	[IP_VS_UDP_S_LAST]		=	2*HZ,
+};
+
+static char * udp_state_name_table[IP_VS_UDP_S_LAST+1] = {
+	[IP_VS_UDP_S_NORMAL]		=	"UDP",
+	[IP_VS_UDP_S_LAST]		=	"BUG!",
+};
+
+
+static int
+udp_set_state_timeout(struct ip_vs_protocol *pp, char *sname, int to)
+{
+	return ip_vs_set_state_timeout(pp->timeout_table, IP_VS_UDP_S_LAST,
+				       udp_state_name_table, sname, to);
+}
+
+static const char * udp_state_name(int state)
+{
+	if (state >= IP_VS_UDP_S_LAST)
+		return "ERR!";
+	return udp_state_name_table[state] ? udp_state_name_table[state] : "?";
+}
+
+static int
+udp_state_transition(struct ip_vs_conn *cp, int direction,
+		     const struct sk_buff *skb,
+		     struct ip_vs_protocol *pp)
+{
+	cp->timeout = pp->timeout_table[IP_VS_UDP_S_NORMAL];
+	return 1;
+}
+
+static void udp_init(struct ip_vs_protocol *pp)
+{
+	IP_VS_INIT_HASH_TABLE(udp_apps);
+	pp->timeout_table = udp_timeouts;
+}
+
+static void udp_exit(struct ip_vs_protocol *pp)
+{
+}
+
+
+struct ip_vs_protocol ip_vs_protocol_udp = {
+	.name =			"UDP",
+	.protocol =		IPPROTO_UDP,
+	.num_states =		IP_VS_UDP_S_LAST,
+	.dont_defrag =		0,
+	.init =			udp_init,
+	.exit =			udp_exit,
+	.conn_schedule =	udp_conn_schedule,
+	.conn_in_get =		udp_conn_in_get,
+	.conn_out_get =		udp_conn_out_get,
+	.snat_handler =		udp_snat_handler,
+	.dnat_handler =		udp_dnat_handler,
+	.csum_check =		udp_csum_check,
+	.state_transition =	udp_state_transition,
+	.state_name =		udp_state_name,
+	.register_app =		udp_register_app,
+	.unregister_app =	udp_unregister_app,
+	.app_conn_bind =	udp_app_conn_bind,
+	.debug_packet =		ip_vs_tcpudp_debug_packet,
+	.timeout_change =	NULL,
+	.set_state_timeout =	udp_set_state_timeout,
+};
diff --git a/net/netfilter/ipvs/ip_vs_rr.c b/net/netfilter/ipvs/ip_vs_rr.c
new file mode 100644
index 0000000..a22195f
--- /dev/null
+++ b/net/netfilter/ipvs/ip_vs_rr.c
@@ -0,0 +1,112 @@
+/*
+ * IPVS:        Round-Robin Scheduling module
+ *
+ * Authors:     Wensong Zhang <wensong@linuxvirtualserver.org>
+ *              Peter Kese <peter.kese@ijs.si>
+ *
+ *              This program is free software; you can redistribute it and/or
+ *              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.
+ *
+ * Fixes/Changes:
+ *     Wensong Zhang            :     changed the ip_vs_rr_schedule to return dest
+ *     Julian Anastasov         :     fixed the NULL pointer access bug in debugging
+ *     Wensong Zhang            :     changed some comestics things for debugging
+ *     Wensong Zhang            :     changed for the d-linked destination list
+ *     Wensong Zhang            :     added the ip_vs_rr_update_svc
+ *     Wensong Zhang            :     added any dest with weight=0 is quiesced
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+
+#include <net/ip_vs.h>
+
+
+static int ip_vs_rr_init_svc(struct ip_vs_service *svc)
+{
+	svc->sched_data = &svc->destinations;
+	return 0;
+}
+
+
+static int ip_vs_rr_update_svc(struct ip_vs_service *svc)
+{
+	svc->sched_data = &svc->destinations;
+	return 0;
+}
+
+
+/*
+ * Round-Robin Scheduling
+ */
+static struct ip_vs_dest *
+ip_vs_rr_schedule(struct ip_vs_service *svc, const struct sk_buff *skb)
+{
+	struct list_head *p, *q;
+	struct ip_vs_dest *dest;
+
+	IP_VS_DBG(6, "ip_vs_rr_schedule(): Scheduling...\n");
+
+	write_lock(&svc->sched_lock);
+	p = (struct list_head *)svc->sched_data;
+	p = p->next;
+	q = p;
+	do {
+		/* skip list head */
+		if (q == &svc->destinations) {
+			q = q->next;
+			continue;
+		}
+
+		dest = list_entry(q, struct ip_vs_dest, n_list);
+		if (!(dest->flags & IP_VS_DEST_F_OVERLOAD) &&
+		    atomic_read(&dest->weight) > 0)
+			/* HIT */
+			goto out;
+		q = q->next;
+	} while (q != p);
+	write_unlock(&svc->sched_lock);
+	return NULL;
+
+  out:
+	svc->sched_data = q;
+	write_unlock(&svc->sched_lock);
+	IP_VS_DBG_BUF(6, "RR: server %s:%u "
+		      "activeconns %d refcnt %d weight %d\n",
+		      IP_VS_DBG_ADDR(svc->af, &dest->addr), ntohs(dest->port),
+		      atomic_read(&dest->activeconns),
+		      atomic_read(&dest->refcnt), atomic_read(&dest->weight));
+
+	return dest;
+}
+
+
+static struct ip_vs_scheduler ip_vs_rr_scheduler = {
+	.name =			"rr",			/* name */
+	.refcnt =		ATOMIC_INIT(0),
+	.module =		THIS_MODULE,
+	.n_list =		LIST_HEAD_INIT(ip_vs_rr_scheduler.n_list),
+#ifdef CONFIG_IP_VS_IPV6
+	.supports_ipv6 =	1,
+#endif
+	.init_service =		ip_vs_rr_init_svc,
+	.update_service =	ip_vs_rr_update_svc,
+	.schedule =		ip_vs_rr_schedule,
+};
+
+static int __init ip_vs_rr_init(void)
+{
+	return register_ip_vs_scheduler(&ip_vs_rr_scheduler);
+}
+
+static void __exit ip_vs_rr_cleanup(void)
+{
+	unregister_ip_vs_scheduler(&ip_vs_rr_scheduler);
+}
+
+module_init(ip_vs_rr_init);
+module_exit(ip_vs_rr_cleanup);
+MODULE_LICENSE("GPL");
diff --git a/net/ipv4/ipvs/ip_vs_sched.c b/net/netfilter/ipvs/ip_vs_sched.c
similarity index 100%
rename from net/ipv4/ipvs/ip_vs_sched.c
rename to net/netfilter/ipvs/ip_vs_sched.c
diff --git a/net/netfilter/ipvs/ip_vs_sed.c b/net/netfilter/ipvs/ip_vs_sed.c
new file mode 100644
index 0000000..7d2f22f
--- /dev/null
+++ b/net/netfilter/ipvs/ip_vs_sed.c
@@ -0,0 +1,140 @@
+/*
+ * IPVS:        Shortest Expected Delay scheduling module
+ *
+ * Authors:     Wensong Zhang <wensong@linuxvirtualserver.org>
+ *
+ *              This program is free software; you can redistribute it and/or
+ *              modify it under the terms of the GNU General Public License
+ *              as published by the Free Software Foundation; either version
+ *              2 of the License, or (at your option) any later version.
+ *
+ * Changes:
+ *
+ */
+
+/*
+ * The SED algorithm attempts to minimize each job's expected delay until
+ * completion. The expected delay that the job will experience is
+ * (Ci + 1) / Ui if sent to the ith server, in which Ci is the number of
+ * jobs on the ith server and Ui is the fixed service rate (weight) of
+ * the ith server. The SED algorithm adopts a greedy policy that each does
+ * what is in its own best interest, i.e. to join the queue which would
+ * minimize its expected delay of completion.
+ *
+ * See the following paper for more information:
+ * A. Weinrib and S. Shenker, Greed is not enough: Adaptive load sharing
+ * in large heterogeneous systems. In Proceedings IEEE INFOCOM'88,
+ * pages 986-994, 1988.
+ *
+ * Thanks must go to Marko Buuri <marko@buuri.name> for talking SED to me.
+ *
+ * The difference between SED and WLC is that SED includes the incoming
+ * job in the cost function (the increment of 1). SED may outperform
+ * WLC, while scheduling big jobs under larger heterogeneous systems
+ * (the server weight varies a lot).
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+
+#include <net/ip_vs.h>
+
+
+static inline unsigned int
+ip_vs_sed_dest_overhead(struct ip_vs_dest *dest)
+{
+	/*
+	 * We only use the active connection number in the cost
+	 * calculation here.
+	 */
+	return atomic_read(&dest->activeconns) + 1;
+}
+
+
+/*
+ *	Weighted Least Connection scheduling
+ */
+static struct ip_vs_dest *
+ip_vs_sed_schedule(struct ip_vs_service *svc, const struct sk_buff *skb)
+{
+	struct ip_vs_dest *dest, *least;
+	unsigned int loh, doh;
+
+	IP_VS_DBG(6, "ip_vs_sed_schedule(): Scheduling...\n");
+
+	/*
+	 * We calculate the load of each dest server as follows:
+	 *	(server expected overhead) / dest->weight
+	 *
+	 * Remember -- no floats in kernel mode!!!
+	 * The comparison of h1*w2 > h2*w1 is equivalent to that of
+	 *		  h1/w1 > h2/w2
+	 * if every weight is larger than zero.
+	 *
+	 * The server with weight=0 is quiesced and will not receive any
+	 * new connections.
+	 */
+
+	list_for_each_entry(dest, &svc->destinations, n_list) {
+		if (!(dest->flags & IP_VS_DEST_F_OVERLOAD) &&
+		    atomic_read(&dest->weight) > 0) {
+			least = dest;
+			loh = ip_vs_sed_dest_overhead(least);
+			goto nextstage;
+		}
+	}
+	return NULL;
+
+	/*
+	 *    Find the destination with the least load.
+	 */
+  nextstage:
+	list_for_each_entry_continue(dest, &svc->destinations, n_list) {
+		if (dest->flags & IP_VS_DEST_F_OVERLOAD)
+			continue;
+		doh = ip_vs_sed_dest_overhead(dest);
+		if (loh * atomic_read(&dest->weight) >
+		    doh * atomic_read(&least->weight)) {
+			least = dest;
+			loh = doh;
+		}
+	}
+
+	IP_VS_DBG_BUF(6, "SED: server %s:%u "
+		      "activeconns %d refcnt %d weight %d overhead %d\n",
+		      IP_VS_DBG_ADDR(svc->af, &least->addr), ntohs(least->port),
+		      atomic_read(&least->activeconns),
+		      atomic_read(&least->refcnt),
+		      atomic_read(&least->weight), loh);
+
+	return least;
+}
+
+
+static struct ip_vs_scheduler ip_vs_sed_scheduler =
+{
+	.name =			"sed",
+	.refcnt =		ATOMIC_INIT(0),
+	.module =		THIS_MODULE,
+	.n_list =		LIST_HEAD_INIT(ip_vs_sed_scheduler.n_list),
+#ifdef CONFIG_IP_VS_IPV6
+	.supports_ipv6 =	1,
+#endif
+	.schedule =		ip_vs_sed_schedule,
+};
+
+
+static int __init ip_vs_sed_init(void)
+{
+	return register_ip_vs_scheduler(&ip_vs_sed_scheduler);
+}
+
+static void __exit ip_vs_sed_cleanup(void)
+{
+	unregister_ip_vs_scheduler(&ip_vs_sed_scheduler);
+}
+
+module_init(ip_vs_sed_init);
+module_exit(ip_vs_sed_cleanup);
+MODULE_LICENSE("GPL");
diff --git a/net/netfilter/ipvs/ip_vs_sh.c b/net/netfilter/ipvs/ip_vs_sh.c
new file mode 100644
index 0000000..1d96de2
--- /dev/null
+++ b/net/netfilter/ipvs/ip_vs_sh.c
@@ -0,0 +1,258 @@
+/*
+ * IPVS:        Source Hashing scheduling module
+ *
+ * Authors:     Wensong Zhang <wensong@gnuchina.org>
+ *
+ *              This program is free software; you can redistribute it and/or
+ *              modify it under the terms of the GNU General Public License
+ *              as published by the Free Software Foundation; either version
+ *              2 of the License, or (at your option) any later version.
+ *
+ * Changes:
+ *
+ */
+
+/*
+ * The sh algorithm is to select server by the hash key of source IP
+ * address. The pseudo code is as follows:
+ *
+ *       n <- servernode[src_ip];
+ *       if (n is dead) OR
+ *          (n is overloaded) or (n.weight <= 0) then
+ *                 return NULL;
+ *
+ *       return n;
+ *
+ * Notes that servernode is a 256-bucket hash table that maps the hash
+ * index derived from packet source IP address to the current server
+ * array. If the sh scheduler is used in cache cluster, it is good to
+ * combine it with cache_bypass feature. When the statically assigned
+ * server is dead or overloaded, the load balancer can bypass the cache
+ * server and send requests to the original server directly.
+ *
+ */
+
+#include <linux/ip.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/skbuff.h>
+
+#include <net/ip_vs.h>
+
+
+/*
+ *      IPVS SH bucket
+ */
+struct ip_vs_sh_bucket {
+	struct ip_vs_dest       *dest;          /* real server (cache) */
+};
+
+/*
+ *     for IPVS SH entry hash table
+ */
+#ifndef CONFIG_IP_VS_SH_TAB_BITS
+#define CONFIG_IP_VS_SH_TAB_BITS        8
+#endif
+#define IP_VS_SH_TAB_BITS               CONFIG_IP_VS_SH_TAB_BITS
+#define IP_VS_SH_TAB_SIZE               (1 << IP_VS_SH_TAB_BITS)
+#define IP_VS_SH_TAB_MASK               (IP_VS_SH_TAB_SIZE - 1)
+
+
+/*
+ *	Returns hash value for IPVS SH entry
+ */
+static inline unsigned ip_vs_sh_hashkey(__be32 addr)
+{
+	return (ntohl(addr)*2654435761UL) & IP_VS_SH_TAB_MASK;
+}
+
+
+/*
+ *      Get ip_vs_dest associated with supplied parameters.
+ */
+static inline struct ip_vs_dest *
+ip_vs_sh_get(struct ip_vs_sh_bucket *tbl, __be32 addr)
+{
+	return (tbl[ip_vs_sh_hashkey(addr)]).dest;
+}
+
+
+/*
+ *      Assign all the hash buckets of the specified table with the service.
+ */
+static int
+ip_vs_sh_assign(struct ip_vs_sh_bucket *tbl, struct ip_vs_service *svc)
+{
+	int i;
+	struct ip_vs_sh_bucket *b;
+	struct list_head *p;
+	struct ip_vs_dest *dest;
+
+	b = tbl;
+	p = &svc->destinations;
+	for (i=0; i<IP_VS_SH_TAB_SIZE; i++) {
+		if (list_empty(p)) {
+			b->dest = NULL;
+		} else {
+			if (p == &svc->destinations)
+				p = p->next;
+
+			dest = list_entry(p, struct ip_vs_dest, n_list);
+			atomic_inc(&dest->refcnt);
+			b->dest = dest;
+
+			p = p->next;
+		}
+		b++;
+	}
+	return 0;
+}
+
+
+/*
+ *      Flush all the hash buckets of the specified table.
+ */
+static void ip_vs_sh_flush(struct ip_vs_sh_bucket *tbl)
+{
+	int i;
+	struct ip_vs_sh_bucket *b;
+
+	b = tbl;
+	for (i=0; i<IP_VS_SH_TAB_SIZE; i++) {
+		if (b->dest) {
+			atomic_dec(&b->dest->refcnt);
+			b->dest = NULL;
+		}
+		b++;
+	}
+}
+
+
+static int ip_vs_sh_init_svc(struct ip_vs_service *svc)
+{
+	struct ip_vs_sh_bucket *tbl;
+
+	/* allocate the SH table for this service */
+	tbl = kmalloc(sizeof(struct ip_vs_sh_bucket)*IP_VS_SH_TAB_SIZE,
+		      GFP_ATOMIC);
+	if (tbl == NULL) {
+		IP_VS_ERR("ip_vs_sh_init_svc(): no memory\n");
+		return -ENOMEM;
+	}
+	svc->sched_data = tbl;
+	IP_VS_DBG(6, "SH hash table (memory=%Zdbytes) allocated for "
+		  "current service\n",
+		  sizeof(struct ip_vs_sh_bucket)*IP_VS_SH_TAB_SIZE);
+
+	/* assign the hash buckets with the updated service */
+	ip_vs_sh_assign(tbl, svc);
+
+	return 0;
+}
+
+
+static int ip_vs_sh_done_svc(struct ip_vs_service *svc)
+{
+	struct ip_vs_sh_bucket *tbl = svc->sched_data;
+
+	/* got to clean up hash buckets here */
+	ip_vs_sh_flush(tbl);
+
+	/* release the table itself */
+	kfree(svc->sched_data);
+	IP_VS_DBG(6, "SH hash table (memory=%Zdbytes) released\n",
+		  sizeof(struct ip_vs_sh_bucket)*IP_VS_SH_TAB_SIZE);
+
+	return 0;
+}
+
+
+static int ip_vs_sh_update_svc(struct ip_vs_service *svc)
+{
+	struct ip_vs_sh_bucket *tbl = svc->sched_data;
+
+	/* got to clean up hash buckets here */
+	ip_vs_sh_flush(tbl);
+
+	/* assign the hash buckets with the updated service */
+	ip_vs_sh_assign(tbl, svc);
+
+	return 0;
+}
+
+
+/*
+ *      If the dest flags is set with IP_VS_DEST_F_OVERLOAD,
+ *      consider that the server is overloaded here.
+ */
+static inline int is_overloaded(struct ip_vs_dest *dest)
+{
+	return dest->flags & IP_VS_DEST_F_OVERLOAD;
+}
+
+
+/*
+ *      Source Hashing scheduling
+ */
+static struct ip_vs_dest *
+ip_vs_sh_schedule(struct ip_vs_service *svc, const struct sk_buff *skb)
+{
+	struct ip_vs_dest *dest;
+	struct ip_vs_sh_bucket *tbl;
+	struct iphdr *iph = ip_hdr(skb);
+
+	IP_VS_DBG(6, "ip_vs_sh_schedule(): Scheduling...\n");
+
+	tbl = (struct ip_vs_sh_bucket *)svc->sched_data;
+	dest = ip_vs_sh_get(tbl, iph->saddr);
+	if (!dest
+	    || !(dest->flags & IP_VS_DEST_F_AVAILABLE)
+	    || atomic_read(&dest->weight) <= 0
+	    || is_overloaded(dest)) {
+		return NULL;
+	}
+
+	IP_VS_DBG(6, "SH: source IP address %u.%u.%u.%u "
+		  "--> server %u.%u.%u.%u:%d\n",
+		  NIPQUAD(iph->saddr),
+		  NIPQUAD(dest->addr.ip),
+		  ntohs(dest->port));
+
+	return dest;
+}
+
+
+/*
+ *      IPVS SH Scheduler structure
+ */
+static struct ip_vs_scheduler ip_vs_sh_scheduler =
+{
+	.name =			"sh",
+	.refcnt =		ATOMIC_INIT(0),
+	.module =		THIS_MODULE,
+	.n_list	 =		LIST_HEAD_INIT(ip_vs_sh_scheduler.n_list),
+#ifdef CONFIG_IP_VS_IPV6
+	.supports_ipv6 =	0,
+#endif
+	.init_service =		ip_vs_sh_init_svc,
+	.done_service =		ip_vs_sh_done_svc,
+	.update_service =	ip_vs_sh_update_svc,
+	.schedule =		ip_vs_sh_schedule,
+};
+
+
+static int __init ip_vs_sh_init(void)
+{
+	return register_ip_vs_scheduler(&ip_vs_sh_scheduler);
+}
+
+
+static void __exit ip_vs_sh_cleanup(void)
+{
+	unregister_ip_vs_scheduler(&ip_vs_sh_scheduler);
+}
+
+
+module_init(ip_vs_sh_init);
+module_exit(ip_vs_sh_cleanup);
+MODULE_LICENSE("GPL");
diff --git a/net/netfilter/ipvs/ip_vs_sync.c b/net/netfilter/ipvs/ip_vs_sync.c
new file mode 100644
index 0000000..de5e7e1
--- /dev/null
+++ b/net/netfilter/ipvs/ip_vs_sync.c
@@ -0,0 +1,942 @@
+/*
+ * IPVS         An implementation of the IP virtual server support for the
+ *              LINUX operating system.  IPVS is now implemented as a module
+ *              over the NetFilter framework. IPVS can be used to build a
+ *              high-performance and highly available server based on a
+ *              cluster of servers.
+ *
+ * Authors:     Wensong Zhang <wensong@linuxvirtualserver.org>
+ *
+ * ip_vs_sync:  sync connection info from master load balancer to backups
+ *              through multicast
+ *
+ * Changes:
+ *	Alexandre Cassen	:	Added master & backup support at a time.
+ *	Alexandre Cassen	:	Added SyncID support for incoming sync
+ *					messages filtering.
+ *	Justin Ossevoort	:	Fix endian problem on sync message size.
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/inetdevice.h>
+#include <linux/net.h>
+#include <linux/completion.h>
+#include <linux/delay.h>
+#include <linux/skbuff.h>
+#include <linux/in.h>
+#include <linux/igmp.h>                 /* for ip_mc_join_group */
+#include <linux/udp.h>
+#include <linux/err.h>
+#include <linux/kthread.h>
+#include <linux/wait.h>
+#include <linux/kernel.h>
+
+#include <net/ip.h>
+#include <net/sock.h>
+
+#include <net/ip_vs.h>
+
+#define IP_VS_SYNC_GROUP 0xe0000051    /* multicast addr - 224.0.0.81 */
+#define IP_VS_SYNC_PORT  8848          /* multicast port */
+
+
+/*
+ *	IPVS sync connection entry
+ */
+struct ip_vs_sync_conn {
+	__u8			reserved;
+
+	/* Protocol, addresses and port numbers */
+	__u8			protocol;       /* Which protocol (TCP/UDP) */
+	__be16			cport;
+	__be16                  vport;
+	__be16                  dport;
+	__be32                  caddr;          /* client address */
+	__be32                  vaddr;          /* virtual address */
+	__be32                  daddr;          /* destination address */
+
+	/* Flags and state transition */
+	__be16                  flags;          /* status flags */
+	__be16                  state;          /* state info */
+
+	/* The sequence options start here */
+};
+
+struct ip_vs_sync_conn_options {
+	struct ip_vs_seq        in_seq;         /* incoming seq. struct */
+	struct ip_vs_seq        out_seq;        /* outgoing seq. struct */
+};
+
+struct ip_vs_sync_thread_data {
+	struct socket *sock;
+	char *buf;
+};
+
+#define SIMPLE_CONN_SIZE  (sizeof(struct ip_vs_sync_conn))
+#define FULL_CONN_SIZE  \
+(sizeof(struct ip_vs_sync_conn) + sizeof(struct ip_vs_sync_conn_options))
+
+
+/*
+  The master mulitcasts messages to the backup load balancers in the
+  following format.
+
+       0                   1                   2                   3
+       0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+      |  Count Conns  |    SyncID     |            Size               |
+      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+      |                                                               |
+      |                    IPVS Sync Connection (1)                   |
+      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+      |                            .                                  |
+      |                            .                                  |
+      |                            .                                  |
+      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+      |                                                               |
+      |                    IPVS Sync Connection (n)                   |
+      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+*/
+
+#define SYNC_MESG_HEADER_LEN	4
+#define MAX_CONNS_PER_SYNCBUFF	255 /* nr_conns in ip_vs_sync_mesg is 8 bit */
+
+struct ip_vs_sync_mesg {
+	__u8                    nr_conns;
+	__u8                    syncid;
+	__u16                   size;
+
+	/* ip_vs_sync_conn entries start here */
+};
+
+/* the maximum length of sync (sending/receiving) message */
+static int sync_send_mesg_maxlen;
+static int sync_recv_mesg_maxlen;
+
+struct ip_vs_sync_buff {
+	struct list_head        list;
+	unsigned long           firstuse;
+
+	/* pointers for the message data */
+	struct ip_vs_sync_mesg  *mesg;
+	unsigned char           *head;
+	unsigned char           *end;
+};
+
+
+/* the sync_buff list head and the lock */
+static LIST_HEAD(ip_vs_sync_queue);
+static DEFINE_SPINLOCK(ip_vs_sync_lock);
+
+/* current sync_buff for accepting new conn entries */
+static struct ip_vs_sync_buff   *curr_sb = NULL;
+static DEFINE_SPINLOCK(curr_sb_lock);
+
+/* ipvs sync daemon state */
+volatile int ip_vs_sync_state = IP_VS_STATE_NONE;
+volatile int ip_vs_master_syncid = 0;
+volatile int ip_vs_backup_syncid = 0;
+
+/* multicast interface name */
+char ip_vs_master_mcast_ifn[IP_VS_IFNAME_MAXLEN];
+char ip_vs_backup_mcast_ifn[IP_VS_IFNAME_MAXLEN];
+
+/* sync daemon tasks */
+static struct task_struct *sync_master_thread;
+static struct task_struct *sync_backup_thread;
+
+/* multicast addr */
+static struct sockaddr_in mcast_addr = {
+	.sin_family		= AF_INET,
+	.sin_port		= __constant_htons(IP_VS_SYNC_PORT),
+	.sin_addr.s_addr	= __constant_htonl(IP_VS_SYNC_GROUP),
+};
+
+
+static inline struct ip_vs_sync_buff *sb_dequeue(void)
+{
+	struct ip_vs_sync_buff *sb;
+
+	spin_lock_bh(&ip_vs_sync_lock);
+	if (list_empty(&ip_vs_sync_queue)) {
+		sb = NULL;
+	} else {
+		sb = list_entry(ip_vs_sync_queue.next,
+				struct ip_vs_sync_buff,
+				list);
+		list_del(&sb->list);
+	}
+	spin_unlock_bh(&ip_vs_sync_lock);
+
+	return sb;
+}
+
+static inline struct ip_vs_sync_buff * ip_vs_sync_buff_create(void)
+{
+	struct ip_vs_sync_buff *sb;
+
+	if (!(sb=kmalloc(sizeof(struct ip_vs_sync_buff), GFP_ATOMIC)))
+		return NULL;
+
+	if (!(sb->mesg=kmalloc(sync_send_mesg_maxlen, GFP_ATOMIC))) {
+		kfree(sb);
+		return NULL;
+	}
+	sb->mesg->nr_conns = 0;
+	sb->mesg->syncid = ip_vs_master_syncid;
+	sb->mesg->size = 4;
+	sb->head = (unsigned char *)sb->mesg + 4;
+	sb->end = (unsigned char *)sb->mesg + sync_send_mesg_maxlen;
+	sb->firstuse = jiffies;
+	return sb;
+}
+
+static inline void ip_vs_sync_buff_release(struct ip_vs_sync_buff *sb)
+{
+	kfree(sb->mesg);
+	kfree(sb);
+}
+
+static inline void sb_queue_tail(struct ip_vs_sync_buff *sb)
+{
+	spin_lock(&ip_vs_sync_lock);
+	if (ip_vs_sync_state & IP_VS_STATE_MASTER)
+		list_add_tail(&sb->list, &ip_vs_sync_queue);
+	else
+		ip_vs_sync_buff_release(sb);
+	spin_unlock(&ip_vs_sync_lock);
+}
+
+/*
+ *	Get the current sync buffer if it has been created for more
+ *	than the specified time or the specified time is zero.
+ */
+static inline struct ip_vs_sync_buff *
+get_curr_sync_buff(unsigned long time)
+{
+	struct ip_vs_sync_buff *sb;
+
+	spin_lock_bh(&curr_sb_lock);
+	if (curr_sb && (time == 0 ||
+			time_before(jiffies - curr_sb->firstuse, time))) {
+		sb = curr_sb;
+		curr_sb = NULL;
+	} else
+		sb = NULL;
+	spin_unlock_bh(&curr_sb_lock);
+	return sb;
+}
+
+
+/*
+ *      Add an ip_vs_conn information into the current sync_buff.
+ *      Called by ip_vs_in.
+ */
+void ip_vs_sync_conn(struct ip_vs_conn *cp)
+{
+	struct ip_vs_sync_mesg *m;
+	struct ip_vs_sync_conn *s;
+	int len;
+
+	spin_lock(&curr_sb_lock);
+	if (!curr_sb) {
+		if (!(curr_sb=ip_vs_sync_buff_create())) {
+			spin_unlock(&curr_sb_lock);
+			IP_VS_ERR("ip_vs_sync_buff_create failed.\n");
+			return;
+		}
+	}
+
+	len = (cp->flags & IP_VS_CONN_F_SEQ_MASK) ? FULL_CONN_SIZE :
+		SIMPLE_CONN_SIZE;
+	m = curr_sb->mesg;
+	s = (struct ip_vs_sync_conn *)curr_sb->head;
+
+	/* copy members */
+	s->protocol = cp->protocol;
+	s->cport = cp->cport;
+	s->vport = cp->vport;
+	s->dport = cp->dport;
+	s->caddr = cp->caddr.ip;
+	s->vaddr = cp->vaddr.ip;
+	s->daddr = cp->daddr.ip;
+	s->flags = htons(cp->flags & ~IP_VS_CONN_F_HASHED);
+	s->state = htons(cp->state);
+	if (cp->flags & IP_VS_CONN_F_SEQ_MASK) {
+		struct ip_vs_sync_conn_options *opt =
+			(struct ip_vs_sync_conn_options *)&s[1];
+		memcpy(opt, &cp->in_seq, sizeof(*opt));
+	}
+
+	m->nr_conns++;
+	m->size += len;
+	curr_sb->head += len;
+
+	/* check if there is a space for next one */
+	if (curr_sb->head+FULL_CONN_SIZE > curr_sb->end) {
+		sb_queue_tail(curr_sb);
+		curr_sb = NULL;
+	}
+	spin_unlock(&curr_sb_lock);
+
+	/* synchronize its controller if it has */
+	if (cp->control)
+		ip_vs_sync_conn(cp->control);
+}
+
+
+/*
+ *      Process received multicast message and create the corresponding
+ *      ip_vs_conn entries.
+ */
+static void ip_vs_process_message(const char *buffer, const size_t buflen)
+{
+	struct ip_vs_sync_mesg *m = (struct ip_vs_sync_mesg *)buffer;
+	struct ip_vs_sync_conn *s;
+	struct ip_vs_sync_conn_options *opt;
+	struct ip_vs_conn *cp;
+	struct ip_vs_protocol *pp;
+	struct ip_vs_dest *dest;
+	char *p;
+	int i;
+
+	if (buflen < sizeof(struct ip_vs_sync_mesg)) {
+		IP_VS_ERR_RL("sync message header too short\n");
+		return;
+	}
+
+	/* Convert size back to host byte order */
+	m->size = ntohs(m->size);
+
+	if (buflen != m->size) {
+		IP_VS_ERR_RL("bogus sync message size\n");
+		return;
+	}
+
+	/* SyncID sanity check */
+	if (ip_vs_backup_syncid != 0 && m->syncid != ip_vs_backup_syncid) {
+		IP_VS_DBG(7, "Ignoring incoming msg with syncid = %d\n",
+			  m->syncid);
+		return;
+	}
+
+	p = (char *)buffer + sizeof(struct ip_vs_sync_mesg);
+	for (i=0; i<m->nr_conns; i++) {
+		unsigned flags, state;
+
+		if (p + SIMPLE_CONN_SIZE > buffer+buflen) {
+			IP_VS_ERR_RL("bogus conn in sync message\n");
+			return;
+		}
+		s = (struct ip_vs_sync_conn *) p;
+		flags = ntohs(s->flags) | IP_VS_CONN_F_SYNC;
+		flags &= ~IP_VS_CONN_F_HASHED;
+		if (flags & IP_VS_CONN_F_SEQ_MASK) {
+			opt = (struct ip_vs_sync_conn_options *)&s[1];
+			p += FULL_CONN_SIZE;
+			if (p > buffer+buflen) {
+				IP_VS_ERR_RL("bogus conn options in sync message\n");
+				return;
+			}
+		} else {
+			opt = NULL;
+			p += SIMPLE_CONN_SIZE;
+		}
+
+		state = ntohs(s->state);
+		if (!(flags & IP_VS_CONN_F_TEMPLATE)) {
+			pp = ip_vs_proto_get(s->protocol);
+			if (!pp) {
+				IP_VS_ERR_RL("Unsupported protocol %u in sync msg\n",
+					s->protocol);
+				continue;
+			}
+			if (state >= pp->num_states) {
+				IP_VS_DBG(2, "Invalid %s state %u in sync msg\n",
+					pp->name, state);
+				continue;
+			}
+		} else {
+			/* protocol in templates is not used for state/timeout */
+			pp = NULL;
+			if (state > 0) {
+				IP_VS_DBG(2, "Invalid template state %u in sync msg\n",
+					state);
+				state = 0;
+			}
+		}
+
+		if (!(flags & IP_VS_CONN_F_TEMPLATE))
+			cp = ip_vs_conn_in_get(AF_INET, s->protocol,
+					       (union nf_inet_addr *)&s->caddr,
+					       s->cport,
+					       (union nf_inet_addr *)&s->vaddr,
+					       s->vport);
+		else
+			cp = ip_vs_ct_in_get(AF_INET, s->protocol,
+					     (union nf_inet_addr *)&s->caddr,
+					     s->cport,
+					     (union nf_inet_addr *)&s->vaddr,
+					     s->vport);
+		if (!cp) {
+			/*
+			 * Find the appropriate destination for the connection.
+			 * If it is not found the connection will remain unbound
+			 * but still handled.
+			 */
+			dest = ip_vs_find_dest(AF_INET,
+					       (union nf_inet_addr *)&s->daddr,
+					       s->dport,
+					       (union nf_inet_addr *)&s->vaddr,
+					       s->vport,
+					       s->protocol);
+			/*  Set the approprite ativity flag */
+			if (s->protocol == IPPROTO_TCP) {
+				if (state != IP_VS_TCP_S_ESTABLISHED)
+					flags |= IP_VS_CONN_F_INACTIVE;
+				else
+					flags &= ~IP_VS_CONN_F_INACTIVE;
+			}
+			cp = ip_vs_conn_new(AF_INET, s->protocol,
+					    (union nf_inet_addr *)&s->caddr,
+					    s->cport,
+					    (union nf_inet_addr *)&s->vaddr,
+					    s->vport,
+					    (union nf_inet_addr *)&s->daddr,
+					    s->dport,
+					    flags, dest);
+			if (dest)
+				atomic_dec(&dest->refcnt);
+			if (!cp) {
+				IP_VS_ERR("ip_vs_conn_new failed\n");
+				return;
+			}
+		} else if (!cp->dest) {
+			dest = ip_vs_try_bind_dest(cp);
+			if (dest)
+				atomic_dec(&dest->refcnt);
+		} else if ((cp->dest) && (cp->protocol == IPPROTO_TCP) &&
+			   (cp->state != state)) {
+			/* update active/inactive flag for the connection */
+			dest = cp->dest;
+			if (!(cp->flags & IP_VS_CONN_F_INACTIVE) &&
+				(state != IP_VS_TCP_S_ESTABLISHED)) {
+				atomic_dec(&dest->activeconns);
+				atomic_inc(&dest->inactconns);
+				cp->flags |= IP_VS_CONN_F_INACTIVE;
+			} else if ((cp->flags & IP_VS_CONN_F_INACTIVE) &&
+				(state == IP_VS_TCP_S_ESTABLISHED)) {
+				atomic_inc(&dest->activeconns);
+				atomic_dec(&dest->inactconns);
+				cp->flags &= ~IP_VS_CONN_F_INACTIVE;
+			}
+		}
+
+		if (opt)
+			memcpy(&cp->in_seq, opt, sizeof(*opt));
+		atomic_set(&cp->in_pkts, sysctl_ip_vs_sync_threshold[0]);
+		cp->state = state;
+		cp->old_state = cp->state;
+		/*
+		 * We can not recover the right timeout for templates
+		 * in all cases, we can not find the right fwmark
+		 * virtual service. If needed, we can do it for
+		 * non-fwmark persistent services.
+		 */
+		if (!(flags & IP_VS_CONN_F_TEMPLATE) && pp->timeout_table)
+			cp->timeout = pp->timeout_table[state];
+		else
+			cp->timeout = (3*60*HZ);
+		ip_vs_conn_put(cp);
+	}
+}
+
+
+/*
+ *      Setup loopback of outgoing multicasts on a sending socket
+ */
+static void set_mcast_loop(struct sock *sk, u_char loop)
+{
+	struct inet_sock *inet = inet_sk(sk);
+
+	/* setsockopt(sock, SOL_IP, IP_MULTICAST_LOOP, &loop, sizeof(loop)); */
+	lock_sock(sk);
+	inet->mc_loop = loop ? 1 : 0;
+	release_sock(sk);
+}
+
+/*
+ *      Specify TTL for outgoing multicasts on a sending socket
+ */
+static void set_mcast_ttl(struct sock *sk, u_char ttl)
+{
+	struct inet_sock *inet = inet_sk(sk);
+
+	/* setsockopt(sock, SOL_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)); */
+	lock_sock(sk);
+	inet->mc_ttl = ttl;
+	release_sock(sk);
+}
+
+/*
+ *      Specifiy default interface for outgoing multicasts
+ */
+static int set_mcast_if(struct sock *sk, char *ifname)
+{
+	struct net_device *dev;
+	struct inet_sock *inet = inet_sk(sk);
+
+	if ((dev = __dev_get_by_name(&init_net, ifname)) == NULL)
+		return -ENODEV;
+
+	if (sk->sk_bound_dev_if && dev->ifindex != sk->sk_bound_dev_if)
+		return -EINVAL;
+
+	lock_sock(sk);
+	inet->mc_index = dev->ifindex;
+	/*  inet->mc_addr  = 0; */
+	release_sock(sk);
+
+	return 0;
+}
+
+
+/*
+ *	Set the maximum length of sync message according to the
+ *	specified interface's MTU.
+ */
+static int set_sync_mesg_maxlen(int sync_state)
+{
+	struct net_device *dev;
+	int num;
+
+	if (sync_state == IP_VS_STATE_MASTER) {
+		if ((dev = __dev_get_by_name(&init_net, ip_vs_master_mcast_ifn)) == NULL)
+			return -ENODEV;
+
+		num = (dev->mtu - sizeof(struct iphdr) -
+		       sizeof(struct udphdr) -
+		       SYNC_MESG_HEADER_LEN - 20) / SIMPLE_CONN_SIZE;
+		sync_send_mesg_maxlen = SYNC_MESG_HEADER_LEN +
+			SIMPLE_CONN_SIZE * min(num, MAX_CONNS_PER_SYNCBUFF);
+		IP_VS_DBG(7, "setting the maximum length of sync sending "
+			  "message %d.\n", sync_send_mesg_maxlen);
+	} else if (sync_state == IP_VS_STATE_BACKUP) {
+		if ((dev = __dev_get_by_name(&init_net, ip_vs_backup_mcast_ifn)) == NULL)
+			return -ENODEV;
+
+		sync_recv_mesg_maxlen = dev->mtu -
+			sizeof(struct iphdr) - sizeof(struct udphdr);
+		IP_VS_DBG(7, "setting the maximum length of sync receiving "
+			  "message %d.\n", sync_recv_mesg_maxlen);
+	}
+
+	return 0;
+}
+
+
+/*
+ *      Join a multicast group.
+ *      the group is specified by a class D multicast address 224.0.0.0/8
+ *      in the in_addr structure passed in as a parameter.
+ */
+static int
+join_mcast_group(struct sock *sk, struct in_addr *addr, char *ifname)
+{
+	struct ip_mreqn mreq;
+	struct net_device *dev;
+	int ret;
+
+	memset(&mreq, 0, sizeof(mreq));
+	memcpy(&mreq.imr_multiaddr, addr, sizeof(struct in_addr));
+
+	if ((dev = __dev_get_by_name(&init_net, ifname)) == NULL)
+		return -ENODEV;
+	if (sk->sk_bound_dev_if && dev->ifindex != sk->sk_bound_dev_if)
+		return -EINVAL;
+
+	mreq.imr_ifindex = dev->ifindex;
+
+	lock_sock(sk);
+	ret = ip_mc_join_group(sk, &mreq);
+	release_sock(sk);
+
+	return ret;
+}
+
+
+static int bind_mcastif_addr(struct socket *sock, char *ifname)
+{
+	struct net_device *dev;
+	__be32 addr;
+	struct sockaddr_in sin;
+
+	if ((dev = __dev_get_by_name(&init_net, ifname)) == NULL)
+		return -ENODEV;
+
+	addr = inet_select_addr(dev, 0, RT_SCOPE_UNIVERSE);
+	if (!addr)
+		IP_VS_ERR("You probably need to specify IP address on "
+			  "multicast interface.\n");
+
+	IP_VS_DBG(7, "binding socket with (%s) %u.%u.%u.%u\n",
+		  ifname, NIPQUAD(addr));
+
+	/* Now bind the socket with the address of multicast interface */
+	sin.sin_family	     = AF_INET;
+	sin.sin_addr.s_addr  = addr;
+	sin.sin_port         = 0;
+
+	return sock->ops->bind(sock, (struct sockaddr*)&sin, sizeof(sin));
+}
+
+/*
+ *      Set up sending multicast socket over UDP
+ */
+static struct socket * make_send_sock(void)
+{
+	struct socket *sock;
+	int result;
+
+	/* First create a socket */
+	result = sock_create_kern(PF_INET, SOCK_DGRAM, IPPROTO_UDP, &sock);
+	if (result < 0) {
+		IP_VS_ERR("Error during creation of socket; terminating\n");
+		return ERR_PTR(result);
+	}
+
+	result = set_mcast_if(sock->sk, ip_vs_master_mcast_ifn);
+	if (result < 0) {
+		IP_VS_ERR("Error setting outbound mcast interface\n");
+		goto error;
+	}
+
+	set_mcast_loop(sock->sk, 0);
+	set_mcast_ttl(sock->sk, 1);
+
+	result = bind_mcastif_addr(sock, ip_vs_master_mcast_ifn);
+	if (result < 0) {
+		IP_VS_ERR("Error binding address of the mcast interface\n");
+		goto error;
+	}
+
+	result = sock->ops->connect(sock, (struct sockaddr *) &mcast_addr,
+			sizeof(struct sockaddr), 0);
+	if (result < 0) {
+		IP_VS_ERR("Error connecting to the multicast addr\n");
+		goto error;
+	}
+
+	return sock;
+
+  error:
+	sock_release(sock);
+	return ERR_PTR(result);
+}
+
+
+/*
+ *      Set up receiving multicast socket over UDP
+ */
+static struct socket * make_receive_sock(void)
+{
+	struct socket *sock;
+	int result;
+
+	/* First create a socket */
+	result = sock_create_kern(PF_INET, SOCK_DGRAM, IPPROTO_UDP, &sock);
+	if (result < 0) {
+		IP_VS_ERR("Error during creation of socket; terminating\n");
+		return ERR_PTR(result);
+	}
+
+	/* it is equivalent to the REUSEADDR option in user-space */
+	sock->sk->sk_reuse = 1;
+
+	result = sock->ops->bind(sock, (struct sockaddr *) &mcast_addr,
+			sizeof(struct sockaddr));
+	if (result < 0) {
+		IP_VS_ERR("Error binding to the multicast addr\n");
+		goto error;
+	}
+
+	/* join the multicast group */
+	result = join_mcast_group(sock->sk,
+			(struct in_addr *) &mcast_addr.sin_addr,
+			ip_vs_backup_mcast_ifn);
+	if (result < 0) {
+		IP_VS_ERR("Error joining to the multicast group\n");
+		goto error;
+	}
+
+	return sock;
+
+  error:
+	sock_release(sock);
+	return ERR_PTR(result);
+}
+
+
+static int
+ip_vs_send_async(struct socket *sock, const char *buffer, const size_t length)
+{
+	struct msghdr	msg = {.msg_flags = MSG_DONTWAIT|MSG_NOSIGNAL};
+	struct kvec	iov;
+	int		len;
+
+	EnterFunction(7);
+	iov.iov_base     = (void *)buffer;
+	iov.iov_len      = length;
+
+	len = kernel_sendmsg(sock, &msg, &iov, 1, (size_t)(length));
+
+	LeaveFunction(7);
+	return len;
+}
+
+static void
+ip_vs_send_sync_msg(struct socket *sock, struct ip_vs_sync_mesg *msg)
+{
+	int msize;
+
+	msize = msg->size;
+
+	/* Put size in network byte order */
+	msg->size = htons(msg->size);
+
+	if (ip_vs_send_async(sock, (char *)msg, msize) != msize)
+		IP_VS_ERR("ip_vs_send_async error\n");
+}
+
+static int
+ip_vs_receive(struct socket *sock, char *buffer, const size_t buflen)
+{
+	struct msghdr		msg = {NULL,};
+	struct kvec		iov;
+	int			len;
+
+	EnterFunction(7);
+
+	/* Receive a packet */
+	iov.iov_base     = buffer;
+	iov.iov_len      = (size_t)buflen;
+
+	len = kernel_recvmsg(sock, &msg, &iov, 1, buflen, 0);
+
+	if (len < 0)
+		return -1;
+
+	LeaveFunction(7);
+	return len;
+}
+
+
+static int sync_thread_master(void *data)
+{
+	struct ip_vs_sync_thread_data *tinfo = data;
+	struct ip_vs_sync_buff *sb;
+
+	IP_VS_INFO("sync thread started: state = MASTER, mcast_ifn = %s, "
+		   "syncid = %d\n",
+		   ip_vs_master_mcast_ifn, ip_vs_master_syncid);
+
+	while (!kthread_should_stop()) {
+		while ((sb = sb_dequeue())) {
+			ip_vs_send_sync_msg(tinfo->sock, sb->mesg);
+			ip_vs_sync_buff_release(sb);
+		}
+
+		/* check if entries stay in curr_sb for 2 seconds */
+		sb = get_curr_sync_buff(2 * HZ);
+		if (sb) {
+			ip_vs_send_sync_msg(tinfo->sock, sb->mesg);
+			ip_vs_sync_buff_release(sb);
+		}
+
+		schedule_timeout_interruptible(HZ);
+	}
+
+	/* clean up the sync_buff queue */
+	while ((sb=sb_dequeue())) {
+		ip_vs_sync_buff_release(sb);
+	}
+
+	/* clean up the current sync_buff */
+	if ((sb = get_curr_sync_buff(0))) {
+		ip_vs_sync_buff_release(sb);
+	}
+
+	/* release the sending multicast socket */
+	sock_release(tinfo->sock);
+	kfree(tinfo);
+
+	return 0;
+}
+
+
+static int sync_thread_backup(void *data)
+{
+	struct ip_vs_sync_thread_data *tinfo = data;
+	int len;
+
+	IP_VS_INFO("sync thread started: state = BACKUP, mcast_ifn = %s, "
+		   "syncid = %d\n",
+		   ip_vs_backup_mcast_ifn, ip_vs_backup_syncid);
+
+	while (!kthread_should_stop()) {
+		wait_event_interruptible(*tinfo->sock->sk->sk_sleep,
+			 !skb_queue_empty(&tinfo->sock->sk->sk_receive_queue)
+			 || kthread_should_stop());
+
+		/* do we have data now? */
+		while (!skb_queue_empty(&(tinfo->sock->sk->sk_receive_queue))) {
+			len = ip_vs_receive(tinfo->sock, tinfo->buf,
+					sync_recv_mesg_maxlen);
+			if (len <= 0) {
+				IP_VS_ERR("receiving message error\n");
+				break;
+			}
+
+			/* disable bottom half, because it accesses the data
+			   shared by softirq while getting/creating conns */
+			local_bh_disable();
+			ip_vs_process_message(tinfo->buf, len);
+			local_bh_enable();
+		}
+	}
+
+	/* release the sending multicast socket */
+	sock_release(tinfo->sock);
+	kfree(tinfo->buf);
+	kfree(tinfo);
+
+	return 0;
+}
+
+
+int start_sync_thread(int state, char *mcast_ifn, __u8 syncid)
+{
+	struct ip_vs_sync_thread_data *tinfo;
+	struct task_struct **realtask, *task;
+	struct socket *sock;
+	char *name, *buf = NULL;
+	int (*threadfn)(void *data);
+	int result = -ENOMEM;
+
+	IP_VS_DBG(7, "%s: pid %d\n", __func__, task_pid_nr(current));
+	IP_VS_DBG(7, "Each ip_vs_sync_conn entry needs %Zd bytes\n",
+		  sizeof(struct ip_vs_sync_conn));
+
+	if (state == IP_VS_STATE_MASTER) {
+		if (sync_master_thread)
+			return -EEXIST;
+
+		strlcpy(ip_vs_master_mcast_ifn, mcast_ifn,
+			sizeof(ip_vs_master_mcast_ifn));
+		ip_vs_master_syncid = syncid;
+		realtask = &sync_master_thread;
+		name = "ipvs_syncmaster";
+		threadfn = sync_thread_master;
+		sock = make_send_sock();
+	} else if (state == IP_VS_STATE_BACKUP) {
+		if (sync_backup_thread)
+			return -EEXIST;
+
+		strlcpy(ip_vs_backup_mcast_ifn, mcast_ifn,
+			sizeof(ip_vs_backup_mcast_ifn));
+		ip_vs_backup_syncid = syncid;
+		realtask = &sync_backup_thread;
+		name = "ipvs_syncbackup";
+		threadfn = sync_thread_backup;
+		sock = make_receive_sock();
+	} else {
+		return -EINVAL;
+	}
+
+	if (IS_ERR(sock)) {
+		result = PTR_ERR(sock);
+		goto out;
+	}
+
+	set_sync_mesg_maxlen(state);
+	if (state == IP_VS_STATE_BACKUP) {
+		buf = kmalloc(sync_recv_mesg_maxlen, GFP_KERNEL);
+		if (!buf)
+			goto outsocket;
+	}
+
+	tinfo = kmalloc(sizeof(*tinfo), GFP_KERNEL);
+	if (!tinfo)
+		goto outbuf;
+
+	tinfo->sock = sock;
+	tinfo->buf = buf;
+
+	task = kthread_run(threadfn, tinfo, name);
+	if (IS_ERR(task)) {
+		result = PTR_ERR(task);
+		goto outtinfo;
+	}
+
+	/* mark as active */
+	*realtask = task;
+	ip_vs_sync_state |= state;
+
+	/* increase the module use count */
+	ip_vs_use_count_inc();
+
+	return 0;
+
+outtinfo:
+	kfree(tinfo);
+outbuf:
+	kfree(buf);
+outsocket:
+	sock_release(sock);
+out:
+	return result;
+}
+
+
+int stop_sync_thread(int state)
+{
+	IP_VS_DBG(7, "%s: pid %d\n", __func__, task_pid_nr(current));
+
+	if (state == IP_VS_STATE_MASTER) {
+		if (!sync_master_thread)
+			return -ESRCH;
+
+		IP_VS_INFO("stopping master sync thread %d ...\n",
+			   task_pid_nr(sync_master_thread));
+
+		/*
+		 * The lock synchronizes with sb_queue_tail(), so that we don't
+		 * add sync buffers to the queue, when we are already in
+		 * progress of stopping the master sync daemon.
+		 */
+
+		spin_lock_bh(&ip_vs_sync_lock);
+		ip_vs_sync_state &= ~IP_VS_STATE_MASTER;
+		spin_unlock_bh(&ip_vs_sync_lock);
+		kthread_stop(sync_master_thread);
+		sync_master_thread = NULL;
+	} else if (state == IP_VS_STATE_BACKUP) {
+		if (!sync_backup_thread)
+			return -ESRCH;
+
+		IP_VS_INFO("stopping backup sync thread %d ...\n",
+			   task_pid_nr(sync_backup_thread));
+
+		ip_vs_sync_state &= ~IP_VS_STATE_BACKUP;
+		kthread_stop(sync_backup_thread);
+		sync_backup_thread = NULL;
+	} else {
+		return -EINVAL;
+	}
+
+	/* decrease the module use count */
+	ip_vs_use_count_dec();
+
+	return 0;
+}
diff --git a/net/netfilter/ipvs/ip_vs_wlc.c b/net/netfilter/ipvs/ip_vs_wlc.c
new file mode 100644
index 0000000..8c596e7
--- /dev/null
+++ b/net/netfilter/ipvs/ip_vs_wlc.c
@@ -0,0 +1,128 @@
+/*
+ * IPVS:        Weighted Least-Connection Scheduling module
+ *
+ * Authors:     Wensong Zhang <wensong@linuxvirtualserver.org>
+ *              Peter Kese <peter.kese@ijs.si>
+ *
+ *              This program is free software; you can redistribute it and/or
+ *              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.
+ *
+ * Changes:
+ *     Wensong Zhang            :     changed the ip_vs_wlc_schedule to return dest
+ *     Wensong Zhang            :     changed to use the inactconns in scheduling
+ *     Wensong Zhang            :     changed some comestics things for debugging
+ *     Wensong Zhang            :     changed for the d-linked destination list
+ *     Wensong Zhang            :     added the ip_vs_wlc_update_svc
+ *     Wensong Zhang            :     added any dest with weight=0 is quiesced
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+
+#include <net/ip_vs.h>
+
+
+static inline unsigned int
+ip_vs_wlc_dest_overhead(struct ip_vs_dest *dest)
+{
+	/*
+	 * We think the overhead of processing active connections is 256
+	 * times higher than that of inactive connections in average. (This
+	 * 256 times might not be accurate, we will change it later) We
+	 * use the following formula to estimate the overhead now:
+	 *		  dest->activeconns*256 + dest->inactconns
+	 */
+	return (atomic_read(&dest->activeconns) << 8) +
+		atomic_read(&dest->inactconns);
+}
+
+
+/*
+ *	Weighted Least Connection scheduling
+ */
+static struct ip_vs_dest *
+ip_vs_wlc_schedule(struct ip_vs_service *svc, const struct sk_buff *skb)
+{
+	struct ip_vs_dest *dest, *least;
+	unsigned int loh, doh;
+
+	IP_VS_DBG(6, "ip_vs_wlc_schedule(): Scheduling...\n");
+
+	/*
+	 * We calculate the load of each dest server as follows:
+	 *		  (dest overhead) / dest->weight
+	 *
+	 * Remember -- no floats in kernel mode!!!
+	 * The comparison of h1*w2 > h2*w1 is equivalent to that of
+	 *		  h1/w1 > h2/w2
+	 * if every weight is larger than zero.
+	 *
+	 * The server with weight=0 is quiesced and will not receive any
+	 * new connections.
+	 */
+
+	list_for_each_entry(dest, &svc->destinations, n_list) {
+		if (!(dest->flags & IP_VS_DEST_F_OVERLOAD) &&
+		    atomic_read(&dest->weight) > 0) {
+			least = dest;
+			loh = ip_vs_wlc_dest_overhead(least);
+			goto nextstage;
+		}
+	}
+	return NULL;
+
+	/*
+	 *    Find the destination with the least load.
+	 */
+  nextstage:
+	list_for_each_entry_continue(dest, &svc->destinations, n_list) {
+		if (dest->flags & IP_VS_DEST_F_OVERLOAD)
+			continue;
+		doh = ip_vs_wlc_dest_overhead(dest);
+		if (loh * atomic_read(&dest->weight) >
+		    doh * atomic_read(&least->weight)) {
+			least = dest;
+			loh = doh;
+		}
+	}
+
+	IP_VS_DBG_BUF(6, "WLC: server %s:%u "
+		      "activeconns %d refcnt %d weight %d overhead %d\n",
+		      IP_VS_DBG_ADDR(svc->af, &least->addr), ntohs(least->port),
+		      atomic_read(&least->activeconns),
+		      atomic_read(&least->refcnt),
+		      atomic_read(&least->weight), loh);
+
+	return least;
+}
+
+
+static struct ip_vs_scheduler ip_vs_wlc_scheduler =
+{
+	.name =			"wlc",
+	.refcnt =		ATOMIC_INIT(0),
+	.module =		THIS_MODULE,
+	.n_list =		LIST_HEAD_INIT(ip_vs_wlc_scheduler.n_list),
+#ifdef CONFIG_IP_VS_IPV6
+	.supports_ipv6 =	1,
+#endif
+	.schedule =		ip_vs_wlc_schedule,
+};
+
+
+static int __init ip_vs_wlc_init(void)
+{
+	return register_ip_vs_scheduler(&ip_vs_wlc_scheduler);
+}
+
+static void __exit ip_vs_wlc_cleanup(void)
+{
+	unregister_ip_vs_scheduler(&ip_vs_wlc_scheduler);
+}
+
+module_init(ip_vs_wlc_init);
+module_exit(ip_vs_wlc_cleanup);
+MODULE_LICENSE("GPL");
diff --git a/net/netfilter/ipvs/ip_vs_wrr.c b/net/netfilter/ipvs/ip_vs_wrr.c
new file mode 100644
index 0000000..7ea92fe
--- /dev/null
+++ b/net/netfilter/ipvs/ip_vs_wrr.c
@@ -0,0 +1,237 @@
+/*
+ * IPVS:        Weighted Round-Robin Scheduling module
+ *
+ * Authors:     Wensong Zhang <wensong@linuxvirtualserver.org>
+ *
+ *              This program is free software; you can redistribute it and/or
+ *              modify it under the terms of the GNU General Public License
+ *              as published by the Free Software Foundation; either version
+ *              2 of the License, or (at your option) any later version.
+ *
+ * Changes:
+ *     Wensong Zhang            :     changed the ip_vs_wrr_schedule to return dest
+ *     Wensong Zhang            :     changed some comestics things for debugging
+ *     Wensong Zhang            :     changed for the d-linked destination list
+ *     Wensong Zhang            :     added the ip_vs_wrr_update_svc
+ *     Julian Anastasov         :     fixed the bug of returning destination
+ *                                    with weight 0 when all weights are zero
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/net.h>
+
+#include <net/ip_vs.h>
+
+/*
+ * current destination pointer for weighted round-robin scheduling
+ */
+struct ip_vs_wrr_mark {
+	struct list_head *cl;	/* current list head */
+	int cw;			/* current weight */
+	int mw;			/* maximum weight */
+	int di;			/* decreasing interval */
+};
+
+
+/*
+ *    Get the gcd of server weights
+ */
+static int gcd(int a, int b)
+{
+	int c;
+
+	while ((c = a % b)) {
+		a = b;
+		b = c;
+	}
+	return b;
+}
+
+static int ip_vs_wrr_gcd_weight(struct ip_vs_service *svc)
+{
+	struct ip_vs_dest *dest;
+	int weight;
+	int g = 0;
+
+	list_for_each_entry(dest, &svc->destinations, n_list) {
+		weight = atomic_read(&dest->weight);
+		if (weight > 0) {
+			if (g > 0)
+				g = gcd(weight, g);
+			else
+				g = weight;
+		}
+	}
+	return g ? g : 1;
+}
+
+
+/*
+ *    Get the maximum weight of the service destinations.
+ */
+static int ip_vs_wrr_max_weight(struct ip_vs_service *svc)
+{
+	struct ip_vs_dest *dest;
+	int weight = 0;
+
+	list_for_each_entry(dest, &svc->destinations, n_list) {
+		if (atomic_read(&dest->weight) > weight)
+			weight = atomic_read(&dest->weight);
+	}
+
+	return weight;
+}
+
+
+static int ip_vs_wrr_init_svc(struct ip_vs_service *svc)
+{
+	struct ip_vs_wrr_mark *mark;
+
+	/*
+	 *    Allocate the mark variable for WRR scheduling
+	 */
+	mark = kmalloc(sizeof(struct ip_vs_wrr_mark), GFP_ATOMIC);
+	if (mark == NULL) {
+		IP_VS_ERR("ip_vs_wrr_init_svc(): no memory\n");
+		return -ENOMEM;
+	}
+	mark->cl = &svc->destinations;
+	mark->cw = 0;
+	mark->mw = ip_vs_wrr_max_weight(svc);
+	mark->di = ip_vs_wrr_gcd_weight(svc);
+	svc->sched_data = mark;
+
+	return 0;
+}
+
+
+static int ip_vs_wrr_done_svc(struct ip_vs_service *svc)
+{
+	/*
+	 *    Release the mark variable
+	 */
+	kfree(svc->sched_data);
+
+	return 0;
+}
+
+
+static int ip_vs_wrr_update_svc(struct ip_vs_service *svc)
+{
+	struct ip_vs_wrr_mark *mark = svc->sched_data;
+
+	mark->cl = &svc->destinations;
+	mark->mw = ip_vs_wrr_max_weight(svc);
+	mark->di = ip_vs_wrr_gcd_weight(svc);
+	if (mark->cw > mark->mw)
+		mark->cw = 0;
+	return 0;
+}
+
+
+/*
+ *    Weighted Round-Robin Scheduling
+ */
+static struct ip_vs_dest *
+ip_vs_wrr_schedule(struct ip_vs_service *svc, const struct sk_buff *skb)
+{
+	struct ip_vs_dest *dest;
+	struct ip_vs_wrr_mark *mark = svc->sched_data;
+	struct list_head *p;
+
+	IP_VS_DBG(6, "ip_vs_wrr_schedule(): Scheduling...\n");
+
+	/*
+	 * This loop will always terminate, because mark->cw in (0, max_weight]
+	 * and at least one server has its weight equal to max_weight.
+	 */
+	write_lock(&svc->sched_lock);
+	p = mark->cl;
+	while (1) {
+		if (mark->cl == &svc->destinations) {
+			/* it is at the head of the destination list */
+
+			if (mark->cl == mark->cl->next) {
+				/* no dest entry */
+				dest = NULL;
+				goto out;
+			}
+
+			mark->cl = svc->destinations.next;
+			mark->cw -= mark->di;
+			if (mark->cw <= 0) {
+				mark->cw = mark->mw;
+				/*
+				 * Still zero, which means no available servers.
+				 */
+				if (mark->cw == 0) {
+					mark->cl = &svc->destinations;
+					IP_VS_ERR_RL("ip_vs_wrr_schedule(): "
+						   "no available servers\n");
+					dest = NULL;
+					goto out;
+				}
+			}
+		} else
+			mark->cl = mark->cl->next;
+
+		if (mark->cl != &svc->destinations) {
+			/* not at the head of the list */
+			dest = list_entry(mark->cl, struct ip_vs_dest, n_list);
+			if (!(dest->flags & IP_VS_DEST_F_OVERLOAD) &&
+			    atomic_read(&dest->weight) >= mark->cw) {
+				/* got it */
+				break;
+			}
+		}
+
+		if (mark->cl == p && mark->cw == mark->di) {
+			/* back to the start, and no dest is found.
+			   It is only possible when all dests are OVERLOADED */
+			dest = NULL;
+			goto out;
+		}
+	}
+
+	IP_VS_DBG_BUF(6, "WRR: server %s:%u "
+		      "activeconns %d refcnt %d weight %d\n",
+		      IP_VS_DBG_ADDR(svc->af, &dest->addr), ntohs(dest->port),
+		      atomic_read(&dest->activeconns),
+		      atomic_read(&dest->refcnt),
+		      atomic_read(&dest->weight));
+
+  out:
+	write_unlock(&svc->sched_lock);
+	return dest;
+}
+
+
+static struct ip_vs_scheduler ip_vs_wrr_scheduler = {
+	.name =			"wrr",
+	.refcnt =		ATOMIC_INIT(0),
+	.module =		THIS_MODULE,
+	.n_list =		LIST_HEAD_INIT(ip_vs_wrr_scheduler.n_list),
+#ifdef CONFIG_IP_VS_IPV6
+	.supports_ipv6 =	1,
+#endif
+	.init_service =		ip_vs_wrr_init_svc,
+	.done_service =		ip_vs_wrr_done_svc,
+	.update_service =	ip_vs_wrr_update_svc,
+	.schedule =		ip_vs_wrr_schedule,
+};
+
+static int __init ip_vs_wrr_init(void)
+{
+	return register_ip_vs_scheduler(&ip_vs_wrr_scheduler) ;
+}
+
+static void __exit ip_vs_wrr_cleanup(void)
+{
+	unregister_ip_vs_scheduler(&ip_vs_wrr_scheduler);
+}
+
+module_init(ip_vs_wrr_init);
+module_exit(ip_vs_wrr_cleanup);
+MODULE_LICENSE("GPL");
diff --git a/net/netfilter/ipvs/ip_vs_xmit.c b/net/netfilter/ipvs/ip_vs_xmit.c
new file mode 100644
index 0000000..02ddc2b
--- /dev/null
+++ b/net/netfilter/ipvs/ip_vs_xmit.c
@@ -0,0 +1,1004 @@
+/*
+ * ip_vs_xmit.c: various packet transmitters for IPVS
+ *
+ * Authors:     Wensong Zhang <wensong@linuxvirtualserver.org>
+ *              Julian Anastasov <ja@ssi.bg>
+ *
+ *              This program is free software; you can redistribute it and/or
+ *              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.
+ *
+ * Changes:
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/tcp.h>                  /* for tcphdr */
+#include <net/ip.h>
+#include <net/tcp.h>                    /* for csum_tcpudp_magic */
+#include <net/udp.h>
+#include <net/icmp.h>                   /* for icmp_send */
+#include <net/route.h>                  /* for ip_route_output */
+#include <net/ipv6.h>
+#include <net/ip6_route.h>
+#include <linux/icmpv6.h>
+#include <linux/netfilter.h>
+#include <linux/netfilter_ipv4.h>
+
+#include <net/ip_vs.h>
+
+
+/*
+ *      Destination cache to speed up outgoing route lookup
+ */
+static inline void
+__ip_vs_dst_set(struct ip_vs_dest *dest, u32 rtos, struct dst_entry *dst)
+{
+	struct dst_entry *old_dst;
+
+	old_dst = dest->dst_cache;
+	dest->dst_cache = dst;
+	dest->dst_rtos = rtos;
+	dst_release(old_dst);
+}
+
+static inline struct dst_entry *
+__ip_vs_dst_check(struct ip_vs_dest *dest, u32 rtos, u32 cookie)
+{
+	struct dst_entry *dst = dest->dst_cache;
+
+	if (!dst)
+		return NULL;
+	if ((dst->obsolete
+	     || (dest->af == AF_INET && rtos != dest->dst_rtos)) &&
+	    dst->ops->check(dst, cookie) == NULL) {
+		dest->dst_cache = NULL;
+		dst_release(dst);
+		return NULL;
+	}
+	dst_hold(dst);
+	return dst;
+}
+
+static struct rtable *
+__ip_vs_get_out_rt(struct ip_vs_conn *cp, u32 rtos)
+{
+	struct rtable *rt;			/* Route to the other host */
+	struct ip_vs_dest *dest = cp->dest;
+
+	if (dest) {
+		spin_lock(&dest->dst_lock);
+		if (!(rt = (struct rtable *)
+		      __ip_vs_dst_check(dest, rtos, 0))) {
+			struct flowi fl = {
+				.oif = 0,
+				.nl_u = {
+					.ip4_u = {
+						.daddr = dest->addr.ip,
+						.saddr = 0,
+						.tos = rtos, } },
+			};
+
+			if (ip_route_output_key(&init_net, &rt, &fl)) {
+				spin_unlock(&dest->dst_lock);
+				IP_VS_DBG_RL("ip_route_output error, "
+					     "dest: %u.%u.%u.%u\n",
+					     NIPQUAD(dest->addr.ip));
+				return NULL;
+			}
+			__ip_vs_dst_set(dest, rtos, dst_clone(&rt->u.dst));
+			IP_VS_DBG(10, "new dst %u.%u.%u.%u, refcnt=%d, rtos=%X\n",
+				  NIPQUAD(dest->addr.ip),
+				  atomic_read(&rt->u.dst.__refcnt), rtos);
+		}
+		spin_unlock(&dest->dst_lock);
+	} else {
+		struct flowi fl = {
+			.oif = 0,
+			.nl_u = {
+				.ip4_u = {
+					.daddr = cp->daddr.ip,
+					.saddr = 0,
+					.tos = rtos, } },
+		};
+
+		if (ip_route_output_key(&init_net, &rt, &fl)) {
+			IP_VS_DBG_RL("ip_route_output error, dest: "
+				     "%u.%u.%u.%u\n", NIPQUAD(cp->daddr.ip));
+			return NULL;
+		}
+	}
+
+	return rt;
+}
+
+#ifdef CONFIG_IP_VS_IPV6
+static struct rt6_info *
+__ip_vs_get_out_rt_v6(struct ip_vs_conn *cp)
+{
+	struct rt6_info *rt;			/* Route to the other host */
+	struct ip_vs_dest *dest = cp->dest;
+
+	if (dest) {
+		spin_lock(&dest->dst_lock);
+		rt = (struct rt6_info *)__ip_vs_dst_check(dest, 0, 0);
+		if (!rt) {
+			struct flowi fl = {
+				.oif = 0,
+				.nl_u = {
+					.ip6_u = {
+						.daddr = dest->addr.in6,
+						.saddr = {
+							.s6_addr32 =
+								{ 0, 0, 0, 0 },
+						},
+					},
+				},
+			};
+
+			rt = (struct rt6_info *)ip6_route_output(&init_net,
+								 NULL, &fl);
+			if (!rt) {
+				spin_unlock(&dest->dst_lock);
+				IP_VS_DBG_RL("ip6_route_output error, "
+					     "dest: " NIP6_FMT "\n",
+					     NIP6(dest->addr.in6));
+				return NULL;
+			}
+			__ip_vs_dst_set(dest, 0, dst_clone(&rt->u.dst));
+			IP_VS_DBG(10, "new dst " NIP6_FMT ", refcnt=%d\n",
+				  NIP6(dest->addr.in6),
+				  atomic_read(&rt->u.dst.__refcnt));
+		}
+		spin_unlock(&dest->dst_lock);
+	} else {
+		struct flowi fl = {
+			.oif = 0,
+			.nl_u = {
+				.ip6_u = {
+					.daddr = cp->daddr.in6,
+					.saddr = {
+						.s6_addr32 = { 0, 0, 0, 0 },
+					},
+				},
+			},
+		};
+
+		rt = (struct rt6_info *)ip6_route_output(&init_net, NULL, &fl);
+		if (!rt) {
+			IP_VS_DBG_RL("ip6_route_output error, dest: "
+				     NIP6_FMT "\n", NIP6(cp->daddr.in6));
+			return NULL;
+		}
+	}
+
+	return rt;
+}
+#endif
+
+
+/*
+ *	Release dest->dst_cache before a dest is removed
+ */
+void
+ip_vs_dst_reset(struct ip_vs_dest *dest)
+{
+	struct dst_entry *old_dst;
+
+	old_dst = dest->dst_cache;
+	dest->dst_cache = NULL;
+	dst_release(old_dst);
+}
+
+#define IP_VS_XMIT(pf, skb, rt)				\
+do {							\
+	(skb)->ipvs_property = 1;			\
+	skb_forward_csum(skb);				\
+	NF_HOOK(pf, NF_INET_LOCAL_OUT, (skb), NULL,	\
+		(rt)->u.dst.dev, dst_output);		\
+} while (0)
+
+
+/*
+ *      NULL transmitter (do nothing except return NF_ACCEPT)
+ */
+int
+ip_vs_null_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
+		struct ip_vs_protocol *pp)
+{
+	/* we do not touch skb and do not need pskb ptr */
+	return NF_ACCEPT;
+}
+
+
+/*
+ *      Bypass transmitter
+ *      Let packets bypass the destination when the destination is not
+ *      available, it may be only used in transparent cache cluster.
+ */
+int
+ip_vs_bypass_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
+		  struct ip_vs_protocol *pp)
+{
+	struct rtable *rt;			/* Route to the other host */
+	struct iphdr  *iph = ip_hdr(skb);
+	u8     tos = iph->tos;
+	int    mtu;
+	struct flowi fl = {
+		.oif = 0,
+		.nl_u = {
+			.ip4_u = {
+				.daddr = iph->daddr,
+				.saddr = 0,
+				.tos = RT_TOS(tos), } },
+	};
+
+	EnterFunction(10);
+
+	if (ip_route_output_key(&init_net, &rt, &fl)) {
+		IP_VS_DBG_RL("ip_vs_bypass_xmit(): ip_route_output error, "
+			     "dest: %u.%u.%u.%u\n", NIPQUAD(iph->daddr));
+		goto tx_error_icmp;
+	}
+
+	/* MTU checking */
+	mtu = dst_mtu(&rt->u.dst);
+	if ((skb->len > mtu) && (iph->frag_off & htons(IP_DF))) {
+		ip_rt_put(rt);
+		icmp_send(skb, ICMP_DEST_UNREACH,ICMP_FRAG_NEEDED, htonl(mtu));
+		IP_VS_DBG_RL("ip_vs_bypass_xmit(): frag needed\n");
+		goto tx_error;
+	}
+
+	/*
+	 * Call ip_send_check because we are not sure it is called
+	 * after ip_defrag. Is copy-on-write needed?
+	 */
+	if (unlikely((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL)) {
+		ip_rt_put(rt);
+		return NF_STOLEN;
+	}
+	ip_send_check(ip_hdr(skb));
+
+	/* drop old route */
+	dst_release(skb->dst);
+	skb->dst = &rt->u.dst;
+
+	/* Another hack: avoid icmp_send in ip_fragment */
+	skb->local_df = 1;
+
+	IP_VS_XMIT(PF_INET, skb, rt);
+
+	LeaveFunction(10);
+	return NF_STOLEN;
+
+ tx_error_icmp:
+	dst_link_failure(skb);
+ tx_error:
+	kfree_skb(skb);
+	LeaveFunction(10);
+	return NF_STOLEN;
+}
+
+#ifdef CONFIG_IP_VS_IPV6
+int
+ip_vs_bypass_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
+		     struct ip_vs_protocol *pp)
+{
+	struct rt6_info *rt;			/* Route to the other host */
+	struct ipv6hdr  *iph = ipv6_hdr(skb);
+	int    mtu;
+	struct flowi fl = {
+		.oif = 0,
+		.nl_u = {
+			.ip6_u = {
+				.daddr = iph->daddr,
+				.saddr = { .s6_addr32 = {0, 0, 0, 0} }, } },
+	};
+
+	EnterFunction(10);
+
+	rt = (struct rt6_info *)ip6_route_output(&init_net, NULL, &fl);
+	if (!rt) {
+		IP_VS_DBG_RL("ip_vs_bypass_xmit_v6(): ip6_route_output error, "
+			     "dest: " NIP6_FMT "\n", NIP6(iph->daddr));
+		goto tx_error_icmp;
+	}
+
+	/* MTU checking */
+	mtu = dst_mtu(&rt->u.dst);
+	if (skb->len > mtu) {
+		dst_release(&rt->u.dst);
+		icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu, skb->dev);
+		IP_VS_DBG_RL("ip_vs_bypass_xmit_v6(): frag needed\n");
+		goto tx_error;
+	}
+
+	/*
+	 * Call ip_send_check because we are not sure it is called
+	 * after ip_defrag. Is copy-on-write needed?
+	 */
+	skb = skb_share_check(skb, GFP_ATOMIC);
+	if (unlikely(skb == NULL)) {
+		dst_release(&rt->u.dst);
+		return NF_STOLEN;
+	}
+
+	/* drop old route */
+	dst_release(skb->dst);
+	skb->dst = &rt->u.dst;
+
+	/* Another hack: avoid icmp_send in ip_fragment */
+	skb->local_df = 1;
+
+	IP_VS_XMIT(PF_INET6, skb, rt);
+
+	LeaveFunction(10);
+	return NF_STOLEN;
+
+ tx_error_icmp:
+	dst_link_failure(skb);
+ tx_error:
+	kfree_skb(skb);
+	LeaveFunction(10);
+	return NF_STOLEN;
+}
+#endif
+
+/*
+ *      NAT transmitter (only for outside-to-inside nat forwarding)
+ *      Not used for related ICMP
+ */
+int
+ip_vs_nat_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
+	       struct ip_vs_protocol *pp)
+{
+	struct rtable *rt;		/* Route to the other host */
+	int mtu;
+	struct iphdr *iph = ip_hdr(skb);
+
+	EnterFunction(10);
+
+	/* check if it is a connection of no-client-port */
+	if (unlikely(cp->flags & IP_VS_CONN_F_NO_CPORT)) {
+		__be16 _pt, *p;
+		p = skb_header_pointer(skb, iph->ihl*4, sizeof(_pt), &_pt);
+		if (p == NULL)
+			goto tx_error;
+		ip_vs_conn_fill_cport(cp, *p);
+		IP_VS_DBG(10, "filled cport=%d\n", ntohs(*p));
+	}
+
+	if (!(rt = __ip_vs_get_out_rt(cp, RT_TOS(iph->tos))))
+		goto tx_error_icmp;
+
+	/* MTU checking */
+	mtu = dst_mtu(&rt->u.dst);
+	if ((skb->len > mtu) && (iph->frag_off & htons(IP_DF))) {
+		ip_rt_put(rt);
+		icmp_send(skb, ICMP_DEST_UNREACH,ICMP_FRAG_NEEDED, htonl(mtu));
+		IP_VS_DBG_RL_PKT(0, pp, skb, 0, "ip_vs_nat_xmit(): frag needed for");
+		goto tx_error;
+	}
+
+	/* copy-on-write the packet before mangling it */
+	if (!skb_make_writable(skb, sizeof(struct iphdr)))
+		goto tx_error_put;
+
+	if (skb_cow(skb, rt->u.dst.dev->hard_header_len))
+		goto tx_error_put;
+
+	/* drop old route */
+	dst_release(skb->dst);
+	skb->dst = &rt->u.dst;
+
+	/* mangle the packet */
+	if (pp->dnat_handler && !pp->dnat_handler(skb, pp, cp))
+		goto tx_error;
+	ip_hdr(skb)->daddr = cp->daddr.ip;
+	ip_send_check(ip_hdr(skb));
+
+	IP_VS_DBG_PKT(10, pp, skb, 0, "After DNAT");
+
+	/* FIXME: when application helper enlarges the packet and the length
+	   is larger than the MTU of outgoing device, there will be still
+	   MTU problem. */
+
+	/* Another hack: avoid icmp_send in ip_fragment */
+	skb->local_df = 1;
+
+	IP_VS_XMIT(PF_INET, skb, rt);
+
+	LeaveFunction(10);
+	return NF_STOLEN;
+
+  tx_error_icmp:
+	dst_link_failure(skb);
+  tx_error:
+	LeaveFunction(10);
+	kfree_skb(skb);
+	return NF_STOLEN;
+  tx_error_put:
+	ip_rt_put(rt);
+	goto tx_error;
+}
+
+#ifdef CONFIG_IP_VS_IPV6
+int
+ip_vs_nat_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
+		  struct ip_vs_protocol *pp)
+{
+	struct rt6_info *rt;		/* Route to the other host */
+	int mtu;
+
+	EnterFunction(10);
+
+	/* check if it is a connection of no-client-port */
+	if (unlikely(cp->flags & IP_VS_CONN_F_NO_CPORT)) {
+		__be16 _pt, *p;
+		p = skb_header_pointer(skb, sizeof(struct ipv6hdr),
+				       sizeof(_pt), &_pt);
+		if (p == NULL)
+			goto tx_error;
+		ip_vs_conn_fill_cport(cp, *p);
+		IP_VS_DBG(10, "filled cport=%d\n", ntohs(*p));
+	}
+
+	rt = __ip_vs_get_out_rt_v6(cp);
+	if (!rt)
+		goto tx_error_icmp;
+
+	/* MTU checking */
+	mtu = dst_mtu(&rt->u.dst);
+	if (skb->len > mtu) {
+		dst_release(&rt->u.dst);
+		icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu, skb->dev);
+		IP_VS_DBG_RL_PKT(0, pp, skb, 0,
+				 "ip_vs_nat_xmit_v6(): frag needed for");
+		goto tx_error;
+	}
+
+	/* copy-on-write the packet before mangling it */
+	if (!skb_make_writable(skb, sizeof(struct ipv6hdr)))
+		goto tx_error_put;
+
+	if (skb_cow(skb, rt->u.dst.dev->hard_header_len))
+		goto tx_error_put;
+
+	/* drop old route */
+	dst_release(skb->dst);
+	skb->dst = &rt->u.dst;
+
+	/* mangle the packet */
+	if (pp->dnat_handler && !pp->dnat_handler(skb, pp, cp))
+		goto tx_error;
+	ipv6_hdr(skb)->daddr = cp->daddr.in6;
+
+	IP_VS_DBG_PKT(10, pp, skb, 0, "After DNAT");
+
+	/* FIXME: when application helper enlarges the packet and the length
+	   is larger than the MTU of outgoing device, there will be still
+	   MTU problem. */
+
+	/* Another hack: avoid icmp_send in ip_fragment */
+	skb->local_df = 1;
+
+	IP_VS_XMIT(PF_INET6, skb, rt);
+
+	LeaveFunction(10);
+	return NF_STOLEN;
+
+tx_error_icmp:
+	dst_link_failure(skb);
+tx_error:
+	LeaveFunction(10);
+	kfree_skb(skb);
+	return NF_STOLEN;
+tx_error_put:
+	dst_release(&rt->u.dst);
+	goto tx_error;
+}
+#endif
+
+
+/*
+ *   IP Tunneling transmitter
+ *
+ *   This function encapsulates the packet in a new IP packet, its
+ *   destination will be set to cp->daddr. Most code of this function
+ *   is taken from ipip.c.
+ *
+ *   It is used in VS/TUN cluster. The load balancer selects a real
+ *   server from a cluster based on a scheduling algorithm,
+ *   encapsulates the request packet and forwards it to the selected
+ *   server. For example, all real servers are configured with
+ *   "ifconfig tunl0 <Virtual IP Address> up". When the server receives
+ *   the encapsulated packet, it will decapsulate the packet, processe
+ *   the request and return the response packets directly to the client
+ *   without passing the load balancer. This can greatly increase the
+ *   scalability of virtual server.
+ *
+ *   Used for ANY protocol
+ */
+int
+ip_vs_tunnel_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
+		  struct ip_vs_protocol *pp)
+{
+	struct rtable *rt;			/* Route to the other host */
+	struct net_device *tdev;		/* Device to other host */
+	struct iphdr  *old_iph = ip_hdr(skb);
+	u8     tos = old_iph->tos;
+	__be16 df = old_iph->frag_off;
+	sk_buff_data_t old_transport_header = skb->transport_header;
+	struct iphdr  *iph;			/* Our new IP header */
+	unsigned int max_headroom;		/* The extra header space needed */
+	int    mtu;
+
+	EnterFunction(10);
+
+	if (skb->protocol != htons(ETH_P_IP)) {
+		IP_VS_DBG_RL("ip_vs_tunnel_xmit(): protocol error, "
+			     "ETH_P_IP: %d, skb protocol: %d\n",
+			     htons(ETH_P_IP), skb->protocol);
+		goto tx_error;
+	}
+
+	if (!(rt = __ip_vs_get_out_rt(cp, RT_TOS(tos))))
+		goto tx_error_icmp;
+
+	tdev = rt->u.dst.dev;
+
+	mtu = dst_mtu(&rt->u.dst) - sizeof(struct iphdr);
+	if (mtu < 68) {
+		ip_rt_put(rt);
+		IP_VS_DBG_RL("ip_vs_tunnel_xmit(): mtu less than 68\n");
+		goto tx_error;
+	}
+	if (skb->dst)
+		skb->dst->ops->update_pmtu(skb->dst, mtu);
+
+	df |= (old_iph->frag_off & htons(IP_DF));
+
+	if ((old_iph->frag_off & htons(IP_DF))
+	    && mtu < ntohs(old_iph->tot_len)) {
+		icmp_send(skb, ICMP_DEST_UNREACH,ICMP_FRAG_NEEDED, htonl(mtu));
+		ip_rt_put(rt);
+		IP_VS_DBG_RL("ip_vs_tunnel_xmit(): frag needed\n");
+		goto tx_error;
+	}
+
+	/*
+	 * Okay, now see if we can stuff it in the buffer as-is.
+	 */
+	max_headroom = LL_RESERVED_SPACE(tdev) + sizeof(struct iphdr);
+
+	if (skb_headroom(skb) < max_headroom
+	    || skb_cloned(skb) || skb_shared(skb)) {
+		struct sk_buff *new_skb =
+			skb_realloc_headroom(skb, max_headroom);
+		if (!new_skb) {
+			ip_rt_put(rt);
+			kfree_skb(skb);
+			IP_VS_ERR_RL("ip_vs_tunnel_xmit(): no memory\n");
+			return NF_STOLEN;
+		}
+		kfree_skb(skb);
+		skb = new_skb;
+		old_iph = ip_hdr(skb);
+	}
+
+	skb->transport_header = old_transport_header;
+
+	/* fix old IP header checksum */
+	ip_send_check(old_iph);
+
+	skb_push(skb, sizeof(struct iphdr));
+	skb_reset_network_header(skb);
+	memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
+
+	/* drop old route */
+	dst_release(skb->dst);
+	skb->dst = &rt->u.dst;
+
+	/*
+	 *	Push down and install the IPIP header.
+	 */
+	iph			=	ip_hdr(skb);
+	iph->version		=	4;
+	iph->ihl		=	sizeof(struct iphdr)>>2;
+	iph->frag_off		=	df;
+	iph->protocol		=	IPPROTO_IPIP;
+	iph->tos		=	tos;
+	iph->daddr		=	rt->rt_dst;
+	iph->saddr		=	rt->rt_src;
+	iph->ttl		=	old_iph->ttl;
+	ip_select_ident(iph, &rt->u.dst, NULL);
+
+	/* Another hack: avoid icmp_send in ip_fragment */
+	skb->local_df = 1;
+
+	ip_local_out(skb);
+
+	LeaveFunction(10);
+
+	return NF_STOLEN;
+
+  tx_error_icmp:
+	dst_link_failure(skb);
+  tx_error:
+	kfree_skb(skb);
+	LeaveFunction(10);
+	return NF_STOLEN;
+}
+
+#ifdef CONFIG_IP_VS_IPV6
+int
+ip_vs_tunnel_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
+		     struct ip_vs_protocol *pp)
+{
+	struct rt6_info *rt;		/* Route to the other host */
+	struct net_device *tdev;	/* Device to other host */
+	struct ipv6hdr  *old_iph = ipv6_hdr(skb);
+	sk_buff_data_t old_transport_header = skb->transport_header;
+	struct ipv6hdr  *iph;		/* Our new IP header */
+	unsigned int max_headroom;	/* The extra header space needed */
+	int    mtu;
+
+	EnterFunction(10);
+
+	if (skb->protocol != htons(ETH_P_IPV6)) {
+		IP_VS_DBG_RL("ip_vs_tunnel_xmit_v6(): protocol error, "
+			     "ETH_P_IPV6: %d, skb protocol: %d\n",
+			     htons(ETH_P_IPV6), skb->protocol);
+		goto tx_error;
+	}
+
+	rt = __ip_vs_get_out_rt_v6(cp);
+	if (!rt)
+		goto tx_error_icmp;
+
+	tdev = rt->u.dst.dev;
+
+	mtu = dst_mtu(&rt->u.dst) - sizeof(struct ipv6hdr);
+	/* TODO IPv6: do we need this check in IPv6? */
+	if (mtu < 1280) {
+		dst_release(&rt->u.dst);
+		IP_VS_DBG_RL("ip_vs_tunnel_xmit_v6(): mtu less than 1280\n");
+		goto tx_error;
+	}
+	if (skb->dst)
+		skb->dst->ops->update_pmtu(skb->dst, mtu);
+
+	if (mtu < ntohs(old_iph->payload_len) + sizeof(struct ipv6hdr)) {
+		icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu, skb->dev);
+		dst_release(&rt->u.dst);
+		IP_VS_DBG_RL("ip_vs_tunnel_xmit_v6(): frag needed\n");
+		goto tx_error;
+	}
+
+	/*
+	 * Okay, now see if we can stuff it in the buffer as-is.
+	 */
+	max_headroom = LL_RESERVED_SPACE(tdev) + sizeof(struct ipv6hdr);
+
+	if (skb_headroom(skb) < max_headroom
+	    || skb_cloned(skb) || skb_shared(skb)) {
+		struct sk_buff *new_skb =
+			skb_realloc_headroom(skb, max_headroom);
+		if (!new_skb) {
+			dst_release(&rt->u.dst);
+			kfree_skb(skb);
+			IP_VS_ERR_RL("ip_vs_tunnel_xmit_v6(): no memory\n");
+			return NF_STOLEN;
+		}
+		kfree_skb(skb);
+		skb = new_skb;
+		old_iph = ipv6_hdr(skb);
+	}
+
+	skb->transport_header = old_transport_header;
+
+	skb_push(skb, sizeof(struct ipv6hdr));
+	skb_reset_network_header(skb);
+	memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
+
+	/* drop old route */
+	dst_release(skb->dst);
+	skb->dst = &rt->u.dst;
+
+	/*
+	 *	Push down and install the IPIP header.
+	 */
+	iph			=	ipv6_hdr(skb);
+	iph->version		=	6;
+	iph->nexthdr		=	IPPROTO_IPV6;
+	iph->payload_len	=	old_iph->payload_len + sizeof(old_iph);
+	iph->priority		=	old_iph->priority;
+	memset(&iph->flow_lbl, 0, sizeof(iph->flow_lbl));
+	iph->daddr		=	rt->rt6i_dst.addr;
+	iph->saddr		=	cp->vaddr.in6; /* rt->rt6i_src.addr; */
+	iph->hop_limit		=	old_iph->hop_limit;
+
+	/* Another hack: avoid icmp_send in ip_fragment */
+	skb->local_df = 1;
+
+	ip6_local_out(skb);
+
+	LeaveFunction(10);
+
+	return NF_STOLEN;
+
+tx_error_icmp:
+	dst_link_failure(skb);
+tx_error:
+	kfree_skb(skb);
+	LeaveFunction(10);
+	return NF_STOLEN;
+}
+#endif
+
+
+/*
+ *      Direct Routing transmitter
+ *      Used for ANY protocol
+ */
+int
+ip_vs_dr_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
+	      struct ip_vs_protocol *pp)
+{
+	struct rtable *rt;			/* Route to the other host */
+	struct iphdr  *iph = ip_hdr(skb);
+	int    mtu;
+
+	EnterFunction(10);
+
+	if (!(rt = __ip_vs_get_out_rt(cp, RT_TOS(iph->tos))))
+		goto tx_error_icmp;
+
+	/* MTU checking */
+	mtu = dst_mtu(&rt->u.dst);
+	if ((iph->frag_off & htons(IP_DF)) && skb->len > mtu) {
+		icmp_send(skb, ICMP_DEST_UNREACH,ICMP_FRAG_NEEDED, htonl(mtu));
+		ip_rt_put(rt);
+		IP_VS_DBG_RL("ip_vs_dr_xmit(): frag needed\n");
+		goto tx_error;
+	}
+
+	/*
+	 * Call ip_send_check because we are not sure it is called
+	 * after ip_defrag. Is copy-on-write needed?
+	 */
+	if (unlikely((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL)) {
+		ip_rt_put(rt);
+		return NF_STOLEN;
+	}
+	ip_send_check(ip_hdr(skb));
+
+	/* drop old route */
+	dst_release(skb->dst);
+	skb->dst = &rt->u.dst;
+
+	/* Another hack: avoid icmp_send in ip_fragment */
+	skb->local_df = 1;
+
+	IP_VS_XMIT(PF_INET, skb, rt);
+
+	LeaveFunction(10);
+	return NF_STOLEN;
+
+  tx_error_icmp:
+	dst_link_failure(skb);
+  tx_error:
+	kfree_skb(skb);
+	LeaveFunction(10);
+	return NF_STOLEN;
+}
+
+#ifdef CONFIG_IP_VS_IPV6
+int
+ip_vs_dr_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
+		 struct ip_vs_protocol *pp)
+{
+	struct rt6_info *rt;			/* Route to the other host */
+	int    mtu;
+
+	EnterFunction(10);
+
+	rt = __ip_vs_get_out_rt_v6(cp);
+	if (!rt)
+		goto tx_error_icmp;
+
+	/* MTU checking */
+	mtu = dst_mtu(&rt->u.dst);
+	if (skb->len > mtu) {
+		icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu, skb->dev);
+		dst_release(&rt->u.dst);
+		IP_VS_DBG_RL("ip_vs_dr_xmit_v6(): frag needed\n");
+		goto tx_error;
+	}
+
+	/*
+	 * Call ip_send_check because we are not sure it is called
+	 * after ip_defrag. Is copy-on-write needed?
+	 */
+	skb = skb_share_check(skb, GFP_ATOMIC);
+	if (unlikely(skb == NULL)) {
+		dst_release(&rt->u.dst);
+		return NF_STOLEN;
+	}
+
+	/* drop old route */
+	dst_release(skb->dst);
+	skb->dst = &rt->u.dst;
+
+	/* Another hack: avoid icmp_send in ip_fragment */
+	skb->local_df = 1;
+
+	IP_VS_XMIT(PF_INET6, skb, rt);
+
+	LeaveFunction(10);
+	return NF_STOLEN;
+
+tx_error_icmp:
+	dst_link_failure(skb);
+tx_error:
+	kfree_skb(skb);
+	LeaveFunction(10);
+	return NF_STOLEN;
+}
+#endif
+
+
+/*
+ *	ICMP packet transmitter
+ *	called by the ip_vs_in_icmp
+ */
+int
+ip_vs_icmp_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
+		struct ip_vs_protocol *pp, int offset)
+{
+	struct rtable	*rt;	/* Route to the other host */
+	int mtu;
+	int rc;
+
+	EnterFunction(10);
+
+	/* The ICMP packet for VS/TUN, VS/DR and LOCALNODE will be
+	   forwarded directly here, because there is no need to
+	   translate address/port back */
+	if (IP_VS_FWD_METHOD(cp) != IP_VS_CONN_F_MASQ) {
+		if (cp->packet_xmit)
+			rc = cp->packet_xmit(skb, cp, pp);
+		else
+			rc = NF_ACCEPT;
+		/* do not touch skb anymore */
+		atomic_inc(&cp->in_pkts);
+		goto out;
+	}
+
+	/*
+	 * mangle and send the packet here (only for VS/NAT)
+	 */
+
+	if (!(rt = __ip_vs_get_out_rt(cp, RT_TOS(ip_hdr(skb)->tos))))
+		goto tx_error_icmp;
+
+	/* MTU checking */
+	mtu = dst_mtu(&rt->u.dst);
+	if ((skb->len > mtu) && (ip_hdr(skb)->frag_off & htons(IP_DF))) {
+		ip_rt_put(rt);
+		icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, htonl(mtu));
+		IP_VS_DBG_RL("ip_vs_in_icmp(): frag needed\n");
+		goto tx_error;
+	}
+
+	/* copy-on-write the packet before mangling it */
+	if (!skb_make_writable(skb, offset))
+		goto tx_error_put;
+
+	if (skb_cow(skb, rt->u.dst.dev->hard_header_len))
+		goto tx_error_put;
+
+	/* drop the old route when skb is not shared */
+	dst_release(skb->dst);
+	skb->dst = &rt->u.dst;
+
+	ip_vs_nat_icmp(skb, pp, cp, 0);
+
+	/* Another hack: avoid icmp_send in ip_fragment */
+	skb->local_df = 1;
+
+	IP_VS_XMIT(PF_INET, skb, rt);
+
+	rc = NF_STOLEN;
+	goto out;
+
+  tx_error_icmp:
+	dst_link_failure(skb);
+  tx_error:
+	dev_kfree_skb(skb);
+	rc = NF_STOLEN;
+  out:
+	LeaveFunction(10);
+	return rc;
+  tx_error_put:
+	ip_rt_put(rt);
+	goto tx_error;
+}
+
+#ifdef CONFIG_IP_VS_IPV6
+int
+ip_vs_icmp_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
+		struct ip_vs_protocol *pp, int offset)
+{
+	struct rt6_info	*rt;	/* Route to the other host */
+	int mtu;
+	int rc;
+
+	EnterFunction(10);
+
+	/* The ICMP packet for VS/TUN, VS/DR and LOCALNODE will be
+	   forwarded directly here, because there is no need to
+	   translate address/port back */
+	if (IP_VS_FWD_METHOD(cp) != IP_VS_CONN_F_MASQ) {
+		if (cp->packet_xmit)
+			rc = cp->packet_xmit(skb, cp, pp);
+		else
+			rc = NF_ACCEPT;
+		/* do not touch skb anymore */
+		atomic_inc(&cp->in_pkts);
+		goto out;
+	}
+
+	/*
+	 * mangle and send the packet here (only for VS/NAT)
+	 */
+
+	rt = __ip_vs_get_out_rt_v6(cp);
+	if (!rt)
+		goto tx_error_icmp;
+
+	/* MTU checking */
+	mtu = dst_mtu(&rt->u.dst);
+	if (skb->len > mtu) {
+		dst_release(&rt->u.dst);
+		icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu, skb->dev);
+		IP_VS_DBG_RL("ip_vs_in_icmp(): frag needed\n");
+		goto tx_error;
+	}
+
+	/* copy-on-write the packet before mangling it */
+	if (!skb_make_writable(skb, offset))
+		goto tx_error_put;
+
+	if (skb_cow(skb, rt->u.dst.dev->hard_header_len))
+		goto tx_error_put;
+
+	/* drop the old route when skb is not shared */
+	dst_release(skb->dst);
+	skb->dst = &rt->u.dst;
+
+	ip_vs_nat_icmp_v6(skb, pp, cp, 0);
+
+	/* Another hack: avoid icmp_send in ip_fragment */
+	skb->local_df = 1;
+
+	IP_VS_XMIT(PF_INET6, skb, rt);
+
+	rc = NF_STOLEN;
+	goto out;
+
+tx_error_icmp:
+	dst_link_failure(skb);
+tx_error:
+	dev_kfree_skb(skb);
+	rc = NF_STOLEN;
+out:
+	LeaveFunction(10);
+	return rc;
+tx_error_put:
+	dst_release(&rt->u.dst);
+	goto tx_error;
+}
+#endif
diff --git a/net/netfilter/nf_conntrack_acct.c b/net/netfilter/nf_conntrack_acct.c
index 59bd8b9..03591d3 100644
--- a/net/netfilter/nf_conntrack_acct.c
+++ b/net/netfilter/nf_conntrack_acct.c
@@ -22,19 +22,17 @@
 #define NF_CT_ACCT_DEFAULT 0
 #endif
 
-int nf_ct_acct __read_mostly = NF_CT_ACCT_DEFAULT;
-EXPORT_SYMBOL_GPL(nf_ct_acct);
+static int nf_ct_acct __read_mostly = NF_CT_ACCT_DEFAULT;
 
 module_param_named(acct, nf_ct_acct, bool, 0644);
 MODULE_PARM_DESC(acct, "Enable connection tracking flow accounting.");
 
 #ifdef CONFIG_SYSCTL
-static struct ctl_table_header *acct_sysctl_header;
 static struct ctl_table acct_sysctl_table[] = {
 	{
 		.ctl_name	= CTL_UNNUMBERED,
 		.procname	= "nf_conntrack_acct",
-		.data		= &nf_ct_acct,
+		.data		= &init_net.ct.sysctl_acct,
 		.maxlen		= sizeof(unsigned int),
 		.mode		= 0644,
 		.proc_handler	= &proc_dointvec,
@@ -64,41 +62,87 @@
 	.id	= NF_CT_EXT_ACCT,
 };
 
-int nf_conntrack_acct_init(void)
-{
-	int ret;
-
-#ifdef CONFIG_NF_CT_ACCT
-	printk(KERN_WARNING "CONFIG_NF_CT_ACCT is deprecated and will be removed soon. Plase use\n");
-	printk(KERN_WARNING "nf_conntrack.acct=1 kernel paramater, acct=1 nf_conntrack module option or\n");
-	printk(KERN_WARNING "sysctl net.netfilter.nf_conntrack_acct=1 to enable it.\n");
-#endif
-
-	ret = nf_ct_extend_register(&acct_extend);
-	if (ret < 0) {
-		printk(KERN_ERR "nf_conntrack_acct: Unable to register extension\n");
-		return ret;
-	}
-
 #ifdef CONFIG_SYSCTL
-	acct_sysctl_header = register_sysctl_paths(nf_net_netfilter_sysctl_path,
-				acct_sysctl_table);
+static int nf_conntrack_acct_init_sysctl(struct net *net)
+{
+	struct ctl_table *table;
 
-	if (!acct_sysctl_header) {
-		nf_ct_extend_unregister(&acct_extend);
+	table = kmemdup(acct_sysctl_table, sizeof(acct_sysctl_table),
+			GFP_KERNEL);
+	if (!table)
+		goto out;
 
+	table[0].data = &net->ct.sysctl_acct;
+
+	net->ct.acct_sysctl_header = register_net_sysctl_table(net,
+			nf_net_netfilter_sysctl_path, table);
+	if (!net->ct.acct_sysctl_header) {
 		printk(KERN_ERR "nf_conntrack_acct: can't register to sysctl.\n");
-		return -ENOMEM;
+		goto out_register;
 	}
-#endif
+	return 0;
 
+out_register:
+	kfree(table);
+out:
+	return -ENOMEM;
+}
+
+static void nf_conntrack_acct_fini_sysctl(struct net *net)
+{
+	struct ctl_table *table;
+
+	table = net->ct.acct_sysctl_header->ctl_table_arg;
+	unregister_net_sysctl_table(net->ct.acct_sysctl_header);
+	kfree(table);
+}
+#else
+static int nf_conntrack_acct_init_sysctl(struct net *net)
+{
 	return 0;
 }
 
-void nf_conntrack_acct_fini(void)
+static void nf_conntrack_acct_fini_sysctl(struct net *net)
 {
-#ifdef CONFIG_SYSCTL
-	unregister_sysctl_table(acct_sysctl_header);
+}
 #endif
-	nf_ct_extend_unregister(&acct_extend);
+
+int nf_conntrack_acct_init(struct net *net)
+{
+	int ret;
+
+	net->ct.sysctl_acct = nf_ct_acct;
+
+	if (net_eq(net, &init_net)) {
+#ifdef CONFIG_NF_CT_ACCT
+		printk(KERN_WARNING "CONFIG_NF_CT_ACCT is deprecated and will be removed soon. Plase use\n");
+		printk(KERN_WARNING "nf_conntrack.acct=1 kernel paramater, acct=1 nf_conntrack module option or\n");
+		printk(KERN_WARNING "sysctl net.netfilter.nf_conntrack_acct=1 to enable it.\n");
+#endif
+
+		ret = nf_ct_extend_register(&acct_extend);
+		if (ret < 0) {
+			printk(KERN_ERR "nf_conntrack_acct: Unable to register extension\n");
+			goto out_extend_register;
+		}
+	}
+
+	ret = nf_conntrack_acct_init_sysctl(net);
+	if (ret < 0)
+		goto out_sysctl;
+
+	return 0;
+
+out_sysctl:
+	if (net_eq(net, &init_net))
+		nf_ct_extend_unregister(&acct_extend);
+out_extend_register:
+	return ret;
+}
+
+void nf_conntrack_acct_fini(struct net *net)
+{
+	nf_conntrack_acct_fini_sysctl(net);
+	if (net_eq(net, &init_net))
+		nf_ct_extend_unregister(&acct_extend);
 }
diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c
index 9d1830d..27de3c7 100644
--- a/net/netfilter/nf_conntrack_core.c
+++ b/net/netfilter/nf_conntrack_core.c
@@ -44,30 +44,17 @@
 DEFINE_SPINLOCK(nf_conntrack_lock);
 EXPORT_SYMBOL_GPL(nf_conntrack_lock);
 
-/* nf_conntrack_standalone needs this */
-atomic_t nf_conntrack_count = ATOMIC_INIT(0);
-EXPORT_SYMBOL_GPL(nf_conntrack_count);
-
 unsigned int nf_conntrack_htable_size __read_mostly;
 EXPORT_SYMBOL_GPL(nf_conntrack_htable_size);
 
 int nf_conntrack_max __read_mostly;
 EXPORT_SYMBOL_GPL(nf_conntrack_max);
 
-struct hlist_head *nf_conntrack_hash __read_mostly;
-EXPORT_SYMBOL_GPL(nf_conntrack_hash);
-
 struct nf_conn nf_conntrack_untracked __read_mostly;
 EXPORT_SYMBOL_GPL(nf_conntrack_untracked);
 
-unsigned int nf_ct_log_invalid __read_mostly;
-HLIST_HEAD(unconfirmed);
-static int nf_conntrack_vmalloc __read_mostly;
 static struct kmem_cache *nf_conntrack_cachep __read_mostly;
 
-DEFINE_PER_CPU(struct ip_conntrack_stat, nf_conntrack_stat);
-EXPORT_PER_CPU_SYMBOL(nf_conntrack_stat);
-
 static int nf_conntrack_hash_rnd_initted;
 static unsigned int nf_conntrack_hash_rnd;
 
@@ -180,6 +167,7 @@
 destroy_conntrack(struct nf_conntrack *nfct)
 {
 	struct nf_conn *ct = (struct nf_conn *)nfct;
+	struct net *net = nf_ct_net(ct);
 	struct nf_conntrack_l4proto *l4proto;
 
 	pr_debug("destroy_conntrack(%p)\n", ct);
@@ -212,7 +200,7 @@
 		hlist_del(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnode);
 	}
 
-	NF_CT_STAT_INC(delete);
+	NF_CT_STAT_INC(net, delete);
 	spin_unlock_bh(&nf_conntrack_lock);
 
 	if (ct->master)
@@ -225,6 +213,7 @@
 static void death_by_timeout(unsigned long ul_conntrack)
 {
 	struct nf_conn *ct = (void *)ul_conntrack;
+	struct net *net = nf_ct_net(ct);
 	struct nf_conn_help *help = nfct_help(ct);
 	struct nf_conntrack_helper *helper;
 
@@ -239,14 +228,14 @@
 	spin_lock_bh(&nf_conntrack_lock);
 	/* Inside lock so preempt is disabled on module removal path.
 	 * Otherwise we can get spurious warnings. */
-	NF_CT_STAT_INC(delete_list);
+	NF_CT_STAT_INC(net, delete_list);
 	clean_from_lists(ct);
 	spin_unlock_bh(&nf_conntrack_lock);
 	nf_ct_put(ct);
 }
 
 struct nf_conntrack_tuple_hash *
-__nf_conntrack_find(const struct nf_conntrack_tuple *tuple)
+__nf_conntrack_find(struct net *net, const struct nf_conntrack_tuple *tuple)
 {
 	struct nf_conntrack_tuple_hash *h;
 	struct hlist_node *n;
@@ -256,13 +245,13 @@
 	 * at least once for the stats anyway.
 	 */
 	local_bh_disable();
-	hlist_for_each_entry_rcu(h, n, &nf_conntrack_hash[hash], hnode) {
+	hlist_for_each_entry_rcu(h, n, &net->ct.hash[hash], hnode) {
 		if (nf_ct_tuple_equal(tuple, &h->tuple)) {
-			NF_CT_STAT_INC(found);
+			NF_CT_STAT_INC(net, found);
 			local_bh_enable();
 			return h;
 		}
-		NF_CT_STAT_INC(searched);
+		NF_CT_STAT_INC(net, searched);
 	}
 	local_bh_enable();
 
@@ -272,13 +261,13 @@
 
 /* Find a connection corresponding to a tuple. */
 struct nf_conntrack_tuple_hash *
-nf_conntrack_find_get(const struct nf_conntrack_tuple *tuple)
+nf_conntrack_find_get(struct net *net, const struct nf_conntrack_tuple *tuple)
 {
 	struct nf_conntrack_tuple_hash *h;
 	struct nf_conn *ct;
 
 	rcu_read_lock();
-	h = __nf_conntrack_find(tuple);
+	h = __nf_conntrack_find(net, tuple);
 	if (h) {
 		ct = nf_ct_tuplehash_to_ctrack(h);
 		if (unlikely(!atomic_inc_not_zero(&ct->ct_general.use)))
@@ -294,10 +283,12 @@
 				       unsigned int hash,
 				       unsigned int repl_hash)
 {
+	struct net *net = nf_ct_net(ct);
+
 	hlist_add_head_rcu(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnode,
-			   &nf_conntrack_hash[hash]);
+			   &net->ct.hash[hash]);
 	hlist_add_head_rcu(&ct->tuplehash[IP_CT_DIR_REPLY].hnode,
-			   &nf_conntrack_hash[repl_hash]);
+			   &net->ct.hash[repl_hash]);
 }
 
 void nf_conntrack_hash_insert(struct nf_conn *ct)
@@ -323,8 +314,10 @@
 	struct nf_conn_help *help;
 	struct hlist_node *n;
 	enum ip_conntrack_info ctinfo;
+	struct net *net;
 
 	ct = nf_ct_get(skb, &ctinfo);
+	net = nf_ct_net(ct);
 
 	/* ipt_REJECT uses nf_conntrack_attach to attach related
 	   ICMP/TCP RST packets in other direction.  Actual packet
@@ -351,11 +344,11 @@
 	/* See if there's one in the list already, including reverse:
 	   NAT could have grabbed it without realizing, since we're
 	   not in the hash.  If there is, we lost race. */
-	hlist_for_each_entry(h, n, &nf_conntrack_hash[hash], hnode)
+	hlist_for_each_entry(h, n, &net->ct.hash[hash], hnode)
 		if (nf_ct_tuple_equal(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple,
 				      &h->tuple))
 			goto out;
-	hlist_for_each_entry(h, n, &nf_conntrack_hash[repl_hash], hnode)
+	hlist_for_each_entry(h, n, &net->ct.hash[repl_hash], hnode)
 		if (nf_ct_tuple_equal(&ct->tuplehash[IP_CT_DIR_REPLY].tuple,
 				      &h->tuple))
 			goto out;
@@ -371,22 +364,22 @@
 	add_timer(&ct->timeout);
 	atomic_inc(&ct->ct_general.use);
 	set_bit(IPS_CONFIRMED_BIT, &ct->status);
-	NF_CT_STAT_INC(insert);
+	NF_CT_STAT_INC(net, insert);
 	spin_unlock_bh(&nf_conntrack_lock);
 	help = nfct_help(ct);
 	if (help && help->helper)
-		nf_conntrack_event_cache(IPCT_HELPER, skb);
+		nf_conntrack_event_cache(IPCT_HELPER, ct);
 #ifdef CONFIG_NF_NAT_NEEDED
 	if (test_bit(IPS_SRC_NAT_DONE_BIT, &ct->status) ||
 	    test_bit(IPS_DST_NAT_DONE_BIT, &ct->status))
-		nf_conntrack_event_cache(IPCT_NATINFO, skb);
+		nf_conntrack_event_cache(IPCT_NATINFO, ct);
 #endif
 	nf_conntrack_event_cache(master_ct(ct) ?
-				 IPCT_RELATED : IPCT_NEW, skb);
+				 IPCT_RELATED : IPCT_NEW, ct);
 	return NF_ACCEPT;
 
 out:
-	NF_CT_STAT_INC(insert_failed);
+	NF_CT_STAT_INC(net, insert_failed);
 	spin_unlock_bh(&nf_conntrack_lock);
 	return NF_DROP;
 }
@@ -398,6 +391,7 @@
 nf_conntrack_tuple_taken(const struct nf_conntrack_tuple *tuple,
 			 const struct nf_conn *ignored_conntrack)
 {
+	struct net *net = nf_ct_net(ignored_conntrack);
 	struct nf_conntrack_tuple_hash *h;
 	struct hlist_node *n;
 	unsigned int hash = hash_conntrack(tuple);
@@ -406,14 +400,14 @@
 	 * least once for the stats anyway.
 	 */
 	rcu_read_lock_bh();
-	hlist_for_each_entry_rcu(h, n, &nf_conntrack_hash[hash], hnode) {
+	hlist_for_each_entry_rcu(h, n, &net->ct.hash[hash], hnode) {
 		if (nf_ct_tuplehash_to_ctrack(h) != ignored_conntrack &&
 		    nf_ct_tuple_equal(tuple, &h->tuple)) {
-			NF_CT_STAT_INC(found);
+			NF_CT_STAT_INC(net, found);
 			rcu_read_unlock_bh();
 			return 1;
 		}
-		NF_CT_STAT_INC(searched);
+		NF_CT_STAT_INC(net, searched);
 	}
 	rcu_read_unlock_bh();
 
@@ -425,7 +419,7 @@
 
 /* There's a small race here where we may free a just-assured
    connection.  Too bad: we're in trouble anyway. */
-static noinline int early_drop(unsigned int hash)
+static noinline int early_drop(struct net *net, unsigned int hash)
 {
 	/* Use oldest entry, which is roughly LRU */
 	struct nf_conntrack_tuple_hash *h;
@@ -436,7 +430,7 @@
 
 	rcu_read_lock();
 	for (i = 0; i < nf_conntrack_htable_size; i++) {
-		hlist_for_each_entry_rcu(h, n, &nf_conntrack_hash[hash],
+		hlist_for_each_entry_rcu(h, n, &net->ct.hash[hash],
 					 hnode) {
 			tmp = nf_ct_tuplehash_to_ctrack(h);
 			if (!test_bit(IPS_ASSURED_BIT, &tmp->status))
@@ -458,13 +452,14 @@
 	if (del_timer(&ct->timeout)) {
 		death_by_timeout((unsigned long)ct);
 		dropped = 1;
-		NF_CT_STAT_INC_ATOMIC(early_drop);
+		NF_CT_STAT_INC_ATOMIC(net, early_drop);
 	}
 	nf_ct_put(ct);
 	return dropped;
 }
 
-struct nf_conn *nf_conntrack_alloc(const struct nf_conntrack_tuple *orig,
+struct nf_conn *nf_conntrack_alloc(struct net *net,
+				   const struct nf_conntrack_tuple *orig,
 				   const struct nf_conntrack_tuple *repl,
 				   gfp_t gfp)
 {
@@ -476,13 +471,13 @@
 	}
 
 	/* We don't want any race condition at early drop stage */
-	atomic_inc(&nf_conntrack_count);
+	atomic_inc(&net->ct.count);
 
 	if (nf_conntrack_max &&
-	    unlikely(atomic_read(&nf_conntrack_count) > nf_conntrack_max)) {
+	    unlikely(atomic_read(&net->ct.count) > nf_conntrack_max)) {
 		unsigned int hash = hash_conntrack(orig);
-		if (!early_drop(hash)) {
-			atomic_dec(&nf_conntrack_count);
+		if (!early_drop(net, hash)) {
+			atomic_dec(&net->ct.count);
 			if (net_ratelimit())
 				printk(KERN_WARNING
 				       "nf_conntrack: table full, dropping"
@@ -494,7 +489,7 @@
 	ct = kmem_cache_zalloc(nf_conntrack_cachep, gfp);
 	if (ct == NULL) {
 		pr_debug("nf_conntrack_alloc: Can't alloc conntrack.\n");
-		atomic_dec(&nf_conntrack_count);
+		atomic_dec(&net->ct.count);
 		return ERR_PTR(-ENOMEM);
 	}
 
@@ -503,6 +498,9 @@
 	ct->tuplehash[IP_CT_DIR_REPLY].tuple = *repl;
 	/* Don't set timer yet: wait for confirmation */
 	setup_timer(&ct->timeout, death_by_timeout, (unsigned long)ct);
+#ifdef CONFIG_NET_NS
+	ct->ct_net = net;
+#endif
 	INIT_RCU_HEAD(&ct->rcu);
 
 	return ct;
@@ -512,10 +510,11 @@
 static void nf_conntrack_free_rcu(struct rcu_head *head)
 {
 	struct nf_conn *ct = container_of(head, struct nf_conn, rcu);
+	struct net *net = nf_ct_net(ct);
 
 	nf_ct_ext_free(ct);
 	kmem_cache_free(nf_conntrack_cachep, ct);
-	atomic_dec(&nf_conntrack_count);
+	atomic_dec(&net->ct.count);
 }
 
 void nf_conntrack_free(struct nf_conn *ct)
@@ -528,7 +527,8 @@
 /* Allocate a new conntrack: we return -ENOMEM if classification
    failed due to stress.  Otherwise it really is unclassifiable. */
 static struct nf_conntrack_tuple_hash *
-init_conntrack(const struct nf_conntrack_tuple *tuple,
+init_conntrack(struct net *net,
+	       const struct nf_conntrack_tuple *tuple,
 	       struct nf_conntrack_l3proto *l3proto,
 	       struct nf_conntrack_l4proto *l4proto,
 	       struct sk_buff *skb,
@@ -544,7 +544,7 @@
 		return NULL;
 	}
 
-	ct = nf_conntrack_alloc(tuple, &repl_tuple, GFP_ATOMIC);
+	ct = nf_conntrack_alloc(net, tuple, &repl_tuple, GFP_ATOMIC);
 	if (ct == NULL || IS_ERR(ct)) {
 		pr_debug("Can't allocate conntrack.\n");
 		return (struct nf_conntrack_tuple_hash *)ct;
@@ -559,7 +559,7 @@
 	nf_ct_acct_ext_add(ct, GFP_ATOMIC);
 
 	spin_lock_bh(&nf_conntrack_lock);
-	exp = nf_ct_find_expectation(tuple);
+	exp = nf_ct_find_expectation(net, tuple);
 	if (exp) {
 		pr_debug("conntrack: expectation arrives ct=%p exp=%p\n",
 			 ct, exp);
@@ -579,7 +579,7 @@
 		ct->secmark = exp->master->secmark;
 #endif
 		nf_conntrack_get(&ct->master->ct_general);
-		NF_CT_STAT_INC(expect_new);
+		NF_CT_STAT_INC(net, expect_new);
 	} else {
 		struct nf_conntrack_helper *helper;
 
@@ -589,11 +589,12 @@
 			if (help)
 				rcu_assign_pointer(help->helper, helper);
 		}
-		NF_CT_STAT_INC(new);
+		NF_CT_STAT_INC(net, new);
 	}
 
 	/* Overload tuple linked list to put us in unconfirmed list. */
-	hlist_add_head(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnode, &unconfirmed);
+	hlist_add_head(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnode,
+		       &net->ct.unconfirmed);
 
 	spin_unlock_bh(&nf_conntrack_lock);
 
@@ -608,7 +609,8 @@
 
 /* On success, returns conntrack ptr, sets skb->nfct and ctinfo */
 static inline struct nf_conn *
-resolve_normal_ct(struct sk_buff *skb,
+resolve_normal_ct(struct net *net,
+		  struct sk_buff *skb,
 		  unsigned int dataoff,
 		  u_int16_t l3num,
 		  u_int8_t protonum,
@@ -629,9 +631,9 @@
 	}
 
 	/* look for tuple match */
-	h = nf_conntrack_find_get(&tuple);
+	h = nf_conntrack_find_get(net, &tuple);
 	if (!h) {
-		h = init_conntrack(&tuple, l3proto, l4proto, skb, dataoff);
+		h = init_conntrack(net, &tuple, l3proto, l4proto, skb, dataoff);
 		if (!h)
 			return NULL;
 		if (IS_ERR(h))
@@ -665,7 +667,8 @@
 }
 
 unsigned int
-nf_conntrack_in(int pf, unsigned int hooknum, struct sk_buff *skb)
+nf_conntrack_in(struct net *net, u_int8_t pf, unsigned int hooknum,
+		struct sk_buff *skb)
 {
 	struct nf_conn *ct;
 	enum ip_conntrack_info ctinfo;
@@ -678,44 +681,46 @@
 
 	/* Previously seen (loopback or untracked)?  Ignore. */
 	if (skb->nfct) {
-		NF_CT_STAT_INC_ATOMIC(ignore);
+		NF_CT_STAT_INC_ATOMIC(net, ignore);
 		return NF_ACCEPT;
 	}
 
 	/* rcu_read_lock()ed by nf_hook_slow */
-	l3proto = __nf_ct_l3proto_find((u_int16_t)pf);
+	l3proto = __nf_ct_l3proto_find(pf);
 	ret = l3proto->get_l4proto(skb, skb_network_offset(skb),
 				   &dataoff, &protonum);
 	if (ret <= 0) {
 		pr_debug("not prepared to track yet or error occured\n");
-		NF_CT_STAT_INC_ATOMIC(error);
-		NF_CT_STAT_INC_ATOMIC(invalid);
+		NF_CT_STAT_INC_ATOMIC(net, error);
+		NF_CT_STAT_INC_ATOMIC(net, invalid);
 		return -ret;
 	}
 
-	l4proto = __nf_ct_l4proto_find((u_int16_t)pf, protonum);
+	l4proto = __nf_ct_l4proto_find(pf, protonum);
 
 	/* It may be an special packet, error, unclean...
 	 * inverse of the return code tells to the netfilter
 	 * core what to do with the packet. */
-	if (l4proto->error != NULL &&
-	    (ret = l4proto->error(skb, dataoff, &ctinfo, pf, hooknum)) <= 0) {
-		NF_CT_STAT_INC_ATOMIC(error);
-		NF_CT_STAT_INC_ATOMIC(invalid);
-		return -ret;
+	if (l4proto->error != NULL) {
+		ret = l4proto->error(net, skb, dataoff, &ctinfo, pf, hooknum);
+		if (ret <= 0) {
+			NF_CT_STAT_INC_ATOMIC(net, error);
+			NF_CT_STAT_INC_ATOMIC(net, invalid);
+			return -ret;
+		}
 	}
 
-	ct = resolve_normal_ct(skb, dataoff, pf, protonum, l3proto, l4proto,
-			       &set_reply, &ctinfo);
+	ct = resolve_normal_ct(net, skb, dataoff, pf, protonum,
+			       l3proto, l4proto, &set_reply, &ctinfo);
 	if (!ct) {
 		/* Not valid part of a connection */
-		NF_CT_STAT_INC_ATOMIC(invalid);
+		NF_CT_STAT_INC_ATOMIC(net, invalid);
 		return NF_ACCEPT;
 	}
 
 	if (IS_ERR(ct)) {
 		/* Too stressed to deal. */
-		NF_CT_STAT_INC_ATOMIC(drop);
+		NF_CT_STAT_INC_ATOMIC(net, drop);
 		return NF_DROP;
 	}
 
@@ -728,12 +733,12 @@
 		pr_debug("nf_conntrack_in: Can't track with proto module\n");
 		nf_conntrack_put(skb->nfct);
 		skb->nfct = NULL;
-		NF_CT_STAT_INC_ATOMIC(invalid);
+		NF_CT_STAT_INC_ATOMIC(net, invalid);
 		return -ret;
 	}
 
 	if (set_reply && !test_and_set_bit(IPS_SEEN_REPLY_BIT, &ct->status))
-		nf_conntrack_event_cache(IPCT_STATUS, skb);
+		nf_conntrack_event_cache(IPCT_STATUS, ct);
 
 	return ret;
 }
@@ -846,7 +851,7 @@
 
 	/* must be unlocked when calling event cache */
 	if (event)
-		nf_conntrack_event_cache(event, skb);
+		nf_conntrack_event_cache(event, ct);
 }
 EXPORT_SYMBOL_GPL(__nf_ct_refresh_acct);
 
@@ -938,7 +943,7 @@
 
 /* Bring out ya dead! */
 static struct nf_conn *
-get_next_corpse(int (*iter)(struct nf_conn *i, void *data),
+get_next_corpse(struct net *net, int (*iter)(struct nf_conn *i, void *data),
 		void *data, unsigned int *bucket)
 {
 	struct nf_conntrack_tuple_hash *h;
@@ -947,13 +952,13 @@
 
 	spin_lock_bh(&nf_conntrack_lock);
 	for (; *bucket < nf_conntrack_htable_size; (*bucket)++) {
-		hlist_for_each_entry(h, n, &nf_conntrack_hash[*bucket], hnode) {
+		hlist_for_each_entry(h, n, &net->ct.hash[*bucket], hnode) {
 			ct = nf_ct_tuplehash_to_ctrack(h);
 			if (iter(ct, data))
 				goto found;
 		}
 	}
-	hlist_for_each_entry(h, n, &unconfirmed, hnode) {
+	hlist_for_each_entry(h, n, &net->ct.unconfirmed, hnode) {
 		ct = nf_ct_tuplehash_to_ctrack(h);
 		if (iter(ct, data))
 			set_bit(IPS_DYING_BIT, &ct->status);
@@ -966,13 +971,14 @@
 	return ct;
 }
 
-void
-nf_ct_iterate_cleanup(int (*iter)(struct nf_conn *i, void *data), void *data)
+void nf_ct_iterate_cleanup(struct net *net,
+			   int (*iter)(struct nf_conn *i, void *data),
+			   void *data)
 {
 	struct nf_conn *ct;
 	unsigned int bucket = 0;
 
-	while ((ct = get_next_corpse(iter, data, &bucket)) != NULL) {
+	while ((ct = get_next_corpse(net, iter, data, &bucket)) != NULL) {
 		/* Time to push up daises... */
 		if (del_timer(&ct->timeout))
 			death_by_timeout((unsigned long)ct);
@@ -998,27 +1004,26 @@
 }
 EXPORT_SYMBOL_GPL(nf_ct_free_hashtable);
 
-void nf_conntrack_flush(void)
+void nf_conntrack_flush(struct net *net)
 {
-	nf_ct_iterate_cleanup(kill_all, NULL);
+	nf_ct_iterate_cleanup(net, kill_all, NULL);
 }
 EXPORT_SYMBOL_GPL(nf_conntrack_flush);
 
-/* Mishearing the voices in his head, our hero wonders how he's
-   supposed to kill the mall. */
-void nf_conntrack_cleanup(void)
+static void nf_conntrack_cleanup_init_net(void)
 {
-	rcu_assign_pointer(ip_ct_attach, NULL);
+	nf_conntrack_helper_fini();
+	nf_conntrack_proto_fini();
+	kmem_cache_destroy(nf_conntrack_cachep);
+}
 
-	/* This makes sure all current packets have passed through
-	   netfilter framework.  Roll on, two-stage module
-	   delete... */
-	synchronize_net();
-
-	nf_ct_event_cache_flush();
+static void nf_conntrack_cleanup_net(struct net *net)
+{
+	nf_ct_event_cache_flush(net);
+	nf_conntrack_ecache_fini(net);
  i_see_dead_people:
-	nf_conntrack_flush();
-	if (atomic_read(&nf_conntrack_count) != 0) {
+	nf_conntrack_flush(net);
+	if (atomic_read(&net->ct.count) != 0) {
 		schedule();
 		goto i_see_dead_people;
 	}
@@ -1026,16 +1031,31 @@
 	while (atomic_read(&nf_conntrack_untracked.ct_general.use) > 1)
 		schedule();
 
-	rcu_assign_pointer(nf_ct_destroy, NULL);
-
-	kmem_cache_destroy(nf_conntrack_cachep);
-	nf_ct_free_hashtable(nf_conntrack_hash, nf_conntrack_vmalloc,
+	nf_ct_free_hashtable(net->ct.hash, net->ct.hash_vmalloc,
 			     nf_conntrack_htable_size);
+	nf_conntrack_acct_fini(net);
+	nf_conntrack_expect_fini(net);
+	free_percpu(net->ct.stat);
+}
 
-	nf_conntrack_acct_fini();
-	nf_conntrack_expect_fini();
-	nf_conntrack_helper_fini();
-	nf_conntrack_proto_fini();
+/* Mishearing the voices in his head, our hero wonders how he's
+   supposed to kill the mall. */
+void nf_conntrack_cleanup(struct net *net)
+{
+	if (net_eq(net, &init_net))
+		rcu_assign_pointer(ip_ct_attach, NULL);
+
+	/* This makes sure all current packets have passed through
+	   netfilter framework.  Roll on, two-stage module
+	   delete... */
+	synchronize_net();
+
+	nf_conntrack_cleanup_net(net);
+
+	if (net_eq(net, &init_net)) {
+		rcu_assign_pointer(nf_ct_destroy, NULL);
+		nf_conntrack_cleanup_init_net();
+	}
 }
 
 struct hlist_head *nf_ct_alloc_hashtable(unsigned int *sizep, int *vmalloced)
@@ -1094,8 +1114,8 @@
 	 */
 	spin_lock_bh(&nf_conntrack_lock);
 	for (i = 0; i < nf_conntrack_htable_size; i++) {
-		while (!hlist_empty(&nf_conntrack_hash[i])) {
-			h = hlist_entry(nf_conntrack_hash[i].first,
+		while (!hlist_empty(&init_net.ct.hash[i])) {
+			h = hlist_entry(init_net.ct.hash[i].first,
 					struct nf_conntrack_tuple_hash, hnode);
 			hlist_del_rcu(&h->hnode);
 			bucket = __hash_conntrack(&h->tuple, hashsize, rnd);
@@ -1103,12 +1123,12 @@
 		}
 	}
 	old_size = nf_conntrack_htable_size;
-	old_vmalloced = nf_conntrack_vmalloc;
-	old_hash = nf_conntrack_hash;
+	old_vmalloced = init_net.ct.hash_vmalloc;
+	old_hash = init_net.ct.hash;
 
 	nf_conntrack_htable_size = hashsize;
-	nf_conntrack_vmalloc = vmalloced;
-	nf_conntrack_hash = hash;
+	init_net.ct.hash_vmalloc = vmalloced;
+	init_net.ct.hash = hash;
 	nf_conntrack_hash_rnd = rnd;
 	spin_unlock_bh(&nf_conntrack_lock);
 
@@ -1120,7 +1140,7 @@
 module_param_call(hashsize, nf_conntrack_set_hashsize, param_get_uint,
 		  &nf_conntrack_htable_size, 0600);
 
-int __init nf_conntrack_init(void)
+static int nf_conntrack_init_init_net(void)
 {
 	int max_factor = 8;
 	int ret;
@@ -1142,13 +1162,6 @@
 		 * entries. */
 		max_factor = 4;
 	}
-	nf_conntrack_hash = nf_ct_alloc_hashtable(&nf_conntrack_htable_size,
-						  &nf_conntrack_vmalloc);
-	if (!nf_conntrack_hash) {
-		printk(KERN_ERR "Unable to create nf_conntrack_hash\n");
-		goto err_out;
-	}
-
 	nf_conntrack_max = max_factor * nf_conntrack_htable_size;
 
 	printk("nf_conntrack version %s (%u buckets, %d max)\n",
@@ -1160,48 +1173,103 @@
 						0, 0, NULL);
 	if (!nf_conntrack_cachep) {
 		printk(KERN_ERR "Unable to create nf_conn slab cache\n");
-		goto err_free_hash;
+		ret = -ENOMEM;
+		goto err_cache;
 	}
 
 	ret = nf_conntrack_proto_init();
 	if (ret < 0)
-		goto err_free_conntrack_slab;
-
-	ret = nf_conntrack_expect_init();
-	if (ret < 0)
-		goto out_fini_proto;
+		goto err_proto;
 
 	ret = nf_conntrack_helper_init();
 	if (ret < 0)
-		goto out_fini_expect;
+		goto err_helper;
 
-	ret = nf_conntrack_acct_init();
+	return 0;
+
+err_helper:
+	nf_conntrack_proto_fini();
+err_proto:
+	kmem_cache_destroy(nf_conntrack_cachep);
+err_cache:
+	return ret;
+}
+
+static int nf_conntrack_init_net(struct net *net)
+{
+	int ret;
+
+	atomic_set(&net->ct.count, 0);
+	INIT_HLIST_HEAD(&net->ct.unconfirmed);
+	net->ct.stat = alloc_percpu(struct ip_conntrack_stat);
+	if (!net->ct.stat) {
+		ret = -ENOMEM;
+		goto err_stat;
+	}
+	ret = nf_conntrack_ecache_init(net);
 	if (ret < 0)
-		goto out_fini_helper;
-
-	/* For use by REJECT target */
-	rcu_assign_pointer(ip_ct_attach, nf_conntrack_attach);
-	rcu_assign_pointer(nf_ct_destroy, destroy_conntrack);
+		goto err_ecache;
+	net->ct.hash = nf_ct_alloc_hashtable(&nf_conntrack_htable_size,
+						  &net->ct.hash_vmalloc);
+	if (!net->ct.hash) {
+		ret = -ENOMEM;
+		printk(KERN_ERR "Unable to create nf_conntrack_hash\n");
+		goto err_hash;
+	}
+	ret = nf_conntrack_expect_init(net);
+	if (ret < 0)
+		goto err_expect;
+	ret = nf_conntrack_acct_init(net);
+	if (ret < 0)
+		goto err_acct;
 
 	/* Set up fake conntrack:
 	    - to never be deleted, not in any hashes */
+#ifdef CONFIG_NET_NS
+	nf_conntrack_untracked.ct_net = &init_net;
+#endif
 	atomic_set(&nf_conntrack_untracked.ct_general.use, 1);
 	/*  - and look it like as a confirmed connection */
 	set_bit(IPS_CONFIRMED_BIT, &nf_conntrack_untracked.status);
 
-	return ret;
+	return 0;
 
-out_fini_helper:
-	nf_conntrack_helper_fini();
-out_fini_expect:
-	nf_conntrack_expect_fini();
-out_fini_proto:
-	nf_conntrack_proto_fini();
-err_free_conntrack_slab:
-	kmem_cache_destroy(nf_conntrack_cachep);
-err_free_hash:
-	nf_ct_free_hashtable(nf_conntrack_hash, nf_conntrack_vmalloc,
+err_acct:
+	nf_conntrack_expect_fini(net);
+err_expect:
+	nf_ct_free_hashtable(net->ct.hash, net->ct.hash_vmalloc,
 			     nf_conntrack_htable_size);
-err_out:
-	return -ENOMEM;
+err_hash:
+	nf_conntrack_ecache_fini(net);
+err_ecache:
+	free_percpu(net->ct.stat);
+err_stat:
+	return ret;
+}
+
+int nf_conntrack_init(struct net *net)
+{
+	int ret;
+
+	if (net_eq(net, &init_net)) {
+		ret = nf_conntrack_init_init_net();
+		if (ret < 0)
+			goto out_init_net;
+	}
+	ret = nf_conntrack_init_net(net);
+	if (ret < 0)
+		goto out_net;
+
+	if (net_eq(net, &init_net)) {
+		/* For use by REJECT target */
+		rcu_assign_pointer(ip_ct_attach, nf_conntrack_attach);
+		rcu_assign_pointer(nf_ct_destroy, destroy_conntrack);
+	}
+	return 0;
+
+out_net:
+	if (net_eq(net, &init_net))
+		nf_conntrack_cleanup_init_net();
+out_init_net:
+	return ret;
 }
diff --git a/net/netfilter/nf_conntrack_ecache.c b/net/netfilter/nf_conntrack_ecache.c
index 83c41ac..a5f5e2e 100644
--- a/net/netfilter/nf_conntrack_ecache.c
+++ b/net/netfilter/nf_conntrack_ecache.c
@@ -29,9 +29,6 @@
 ATOMIC_NOTIFIER_HEAD(nf_ct_expect_chain);
 EXPORT_SYMBOL_GPL(nf_ct_expect_chain);
 
-DEFINE_PER_CPU(struct nf_conntrack_ecache, nf_conntrack_ecache);
-EXPORT_PER_CPU_SYMBOL_GPL(nf_conntrack_ecache);
-
 /* deliver cached events and clear cache entry - must be called with locally
  * disabled softirqs */
 static inline void
@@ -51,10 +48,11 @@
  * by code prior to async packet handling for freeing the skb */
 void nf_ct_deliver_cached_events(const struct nf_conn *ct)
 {
+	struct net *net = nf_ct_net(ct);
 	struct nf_conntrack_ecache *ecache;
 
 	local_bh_disable();
-	ecache = &__get_cpu_var(nf_conntrack_ecache);
+	ecache = per_cpu_ptr(net->ct.ecache, raw_smp_processor_id());
 	if (ecache->ct == ct)
 		__nf_ct_deliver_cached_events(ecache);
 	local_bh_enable();
@@ -64,10 +62,11 @@
 /* Deliver cached events for old pending events, if current conntrack != old */
 void __nf_ct_event_cache_init(struct nf_conn *ct)
 {
+	struct net *net = nf_ct_net(ct);
 	struct nf_conntrack_ecache *ecache;
 
 	/* take care of delivering potentially old events */
-	ecache = &__get_cpu_var(nf_conntrack_ecache);
+	ecache = per_cpu_ptr(net->ct.ecache, raw_smp_processor_id());
 	BUG_ON(ecache->ct == ct);
 	if (ecache->ct)
 		__nf_ct_deliver_cached_events(ecache);
@@ -79,18 +78,31 @@
 
 /* flush the event cache - touches other CPU's data and must not be called
  * while packets are still passing through the code */
-void nf_ct_event_cache_flush(void)
+void nf_ct_event_cache_flush(struct net *net)
 {
 	struct nf_conntrack_ecache *ecache;
 	int cpu;
 
 	for_each_possible_cpu(cpu) {
-		ecache = &per_cpu(nf_conntrack_ecache, cpu);
+		ecache = per_cpu_ptr(net->ct.ecache, cpu);
 		if (ecache->ct)
 			nf_ct_put(ecache->ct);
 	}
 }
 
+int nf_conntrack_ecache_init(struct net *net)
+{
+	net->ct.ecache = alloc_percpu(struct nf_conntrack_ecache);
+	if (!net->ct.ecache)
+		return -ENOMEM;
+	return 0;
+}
+
+void nf_conntrack_ecache_fini(struct net *net)
+{
+	free_percpu(net->ct.ecache);
+}
+
 int nf_conntrack_register_notifier(struct notifier_block *nb)
 {
 	return atomic_notifier_chain_register(&nf_conntrack_chain, nb);
diff --git a/net/netfilter/nf_conntrack_expect.c b/net/netfilter/nf_conntrack_expect.c
index e8f0dea..37a703b 100644
--- a/net/netfilter/nf_conntrack_expect.c
+++ b/net/netfilter/nf_conntrack_expect.c
@@ -28,17 +28,12 @@
 #include <net/netfilter/nf_conntrack_helper.h>
 #include <net/netfilter/nf_conntrack_tuple.h>
 
-struct hlist_head *nf_ct_expect_hash __read_mostly;
-EXPORT_SYMBOL_GPL(nf_ct_expect_hash);
-
 unsigned int nf_ct_expect_hsize __read_mostly;
 EXPORT_SYMBOL_GPL(nf_ct_expect_hsize);
 
 static unsigned int nf_ct_expect_hash_rnd __read_mostly;
-static unsigned int nf_ct_expect_count;
 unsigned int nf_ct_expect_max __read_mostly;
 static int nf_ct_expect_hash_rnd_initted __read_mostly;
-static int nf_ct_expect_vmalloc;
 
 static struct kmem_cache *nf_ct_expect_cachep __read_mostly;
 
@@ -46,18 +41,19 @@
 void nf_ct_unlink_expect(struct nf_conntrack_expect *exp)
 {
 	struct nf_conn_help *master_help = nfct_help(exp->master);
+	struct net *net = nf_ct_exp_net(exp);
 
 	NF_CT_ASSERT(master_help);
 	NF_CT_ASSERT(!timer_pending(&exp->timeout));
 
 	hlist_del_rcu(&exp->hnode);
-	nf_ct_expect_count--;
+	net->ct.expect_count--;
 
 	hlist_del(&exp->lnode);
 	master_help->expecting[exp->class]--;
 	nf_ct_expect_put(exp);
 
-	NF_CT_STAT_INC(expect_delete);
+	NF_CT_STAT_INC(net, expect_delete);
 }
 EXPORT_SYMBOL_GPL(nf_ct_unlink_expect);
 
@@ -87,17 +83,17 @@
 }
 
 struct nf_conntrack_expect *
-__nf_ct_expect_find(const struct nf_conntrack_tuple *tuple)
+__nf_ct_expect_find(struct net *net, const struct nf_conntrack_tuple *tuple)
 {
 	struct nf_conntrack_expect *i;
 	struct hlist_node *n;
 	unsigned int h;
 
-	if (!nf_ct_expect_count)
+	if (!net->ct.expect_count)
 		return NULL;
 
 	h = nf_ct_expect_dst_hash(tuple);
-	hlist_for_each_entry_rcu(i, n, &nf_ct_expect_hash[h], hnode) {
+	hlist_for_each_entry_rcu(i, n, &net->ct.expect_hash[h], hnode) {
 		if (nf_ct_tuple_mask_cmp(tuple, &i->tuple, &i->mask))
 			return i;
 	}
@@ -107,12 +103,12 @@
 
 /* Just find a expectation corresponding to a tuple. */
 struct nf_conntrack_expect *
-nf_ct_expect_find_get(const struct nf_conntrack_tuple *tuple)
+nf_ct_expect_find_get(struct net *net, const struct nf_conntrack_tuple *tuple)
 {
 	struct nf_conntrack_expect *i;
 
 	rcu_read_lock();
-	i = __nf_ct_expect_find(tuple);
+	i = __nf_ct_expect_find(net, tuple);
 	if (i && !atomic_inc_not_zero(&i->use))
 		i = NULL;
 	rcu_read_unlock();
@@ -124,17 +120,17 @@
 /* If an expectation for this connection is found, it gets delete from
  * global list then returned. */
 struct nf_conntrack_expect *
-nf_ct_find_expectation(const struct nf_conntrack_tuple *tuple)
+nf_ct_find_expectation(struct net *net, const struct nf_conntrack_tuple *tuple)
 {
 	struct nf_conntrack_expect *i, *exp = NULL;
 	struct hlist_node *n;
 	unsigned int h;
 
-	if (!nf_ct_expect_count)
+	if (!net->ct.expect_count)
 		return NULL;
 
 	h = nf_ct_expect_dst_hash(tuple);
-	hlist_for_each_entry(i, n, &nf_ct_expect_hash[h], hnode) {
+	hlist_for_each_entry(i, n, &net->ct.expect_hash[h], hnode) {
 		if (!(i->flags & NF_CT_EXPECT_INACTIVE) &&
 		    nf_ct_tuple_mask_cmp(tuple, &i->tuple, &i->mask)) {
 			exp = i;
@@ -241,7 +237,7 @@
 EXPORT_SYMBOL_GPL(nf_ct_expect_alloc);
 
 void nf_ct_expect_init(struct nf_conntrack_expect *exp, unsigned int class,
-		       int family,
+		       u_int8_t family,
 		       const union nf_inet_addr *saddr,
 		       const union nf_inet_addr *daddr,
 		       u_int8_t proto, const __be16 *src, const __be16 *dst)
@@ -311,6 +307,7 @@
 static void nf_ct_expect_insert(struct nf_conntrack_expect *exp)
 {
 	struct nf_conn_help *master_help = nfct_help(exp->master);
+	struct net *net = nf_ct_exp_net(exp);
 	const struct nf_conntrack_expect_policy *p;
 	unsigned int h = nf_ct_expect_dst_hash(&exp->tuple);
 
@@ -319,8 +316,8 @@
 	hlist_add_head(&exp->lnode, &master_help->expectations);
 	master_help->expecting[exp->class]++;
 
-	hlist_add_head_rcu(&exp->hnode, &nf_ct_expect_hash[h]);
-	nf_ct_expect_count++;
+	hlist_add_head_rcu(&exp->hnode, &net->ct.expect_hash[h]);
+	net->ct.expect_count++;
 
 	setup_timer(&exp->timeout, nf_ct_expectation_timed_out,
 		    (unsigned long)exp);
@@ -329,7 +326,7 @@
 	add_timer(&exp->timeout);
 
 	atomic_inc(&exp->use);
-	NF_CT_STAT_INC(expect_create);
+	NF_CT_STAT_INC(net, expect_create);
 }
 
 /* Race with expectations being used means we could have none to find; OK. */
@@ -371,6 +368,7 @@
 	struct nf_conntrack_expect *i;
 	struct nf_conn *master = expect->master;
 	struct nf_conn_help *master_help = nfct_help(master);
+	struct net *net = nf_ct_exp_net(expect);
 	struct hlist_node *n;
 	unsigned int h;
 	int ret;
@@ -383,7 +381,7 @@
 		goto out;
 	}
 	h = nf_ct_expect_dst_hash(&expect->tuple);
-	hlist_for_each_entry(i, n, &nf_ct_expect_hash[h], hnode) {
+	hlist_for_each_entry(i, n, &net->ct.expect_hash[h], hnode) {
 		if (expect_matches(i, expect)) {
 			/* Refresh timer: if it's dying, ignore.. */
 			if (refresh_timer(i)) {
@@ -406,7 +404,7 @@
 		}
 	}
 
-	if (nf_ct_expect_count >= nf_ct_expect_max) {
+	if (net->ct.expect_count >= nf_ct_expect_max) {
 		if (net_ratelimit())
 			printk(KERN_WARNING
 			       "nf_conntrack: expectation table full\n");
@@ -425,16 +423,18 @@
 
 #ifdef CONFIG_PROC_FS
 struct ct_expect_iter_state {
+	struct seq_net_private p;
 	unsigned int bucket;
 };
 
 static struct hlist_node *ct_expect_get_first(struct seq_file *seq)
 {
+	struct net *net = seq_file_net(seq);
 	struct ct_expect_iter_state *st = seq->private;
 	struct hlist_node *n;
 
 	for (st->bucket = 0; st->bucket < nf_ct_expect_hsize; st->bucket++) {
-		n = rcu_dereference(nf_ct_expect_hash[st->bucket].first);
+		n = rcu_dereference(net->ct.expect_hash[st->bucket].first);
 		if (n)
 			return n;
 	}
@@ -444,13 +444,14 @@
 static struct hlist_node *ct_expect_get_next(struct seq_file *seq,
 					     struct hlist_node *head)
 {
+	struct net *net = seq_file_net(seq);
 	struct ct_expect_iter_state *st = seq->private;
 
 	head = rcu_dereference(head->next);
 	while (head == NULL) {
 		if (++st->bucket >= nf_ct_expect_hsize)
 			return NULL;
-		head = rcu_dereference(nf_ct_expect_hash[st->bucket].first);
+		head = rcu_dereference(net->ct.expect_hash[st->bucket].first);
 	}
 	return head;
 }
@@ -524,7 +525,7 @@
 
 static int exp_open(struct inode *inode, struct file *file)
 {
-	return seq_open_private(file, &exp_seq_ops,
+	return seq_open_net(inode, file, &exp_seq_ops,
 			sizeof(struct ct_expect_iter_state));
 }
 
@@ -533,72 +534,79 @@
 	.open    = exp_open,
 	.read    = seq_read,
 	.llseek  = seq_lseek,
-	.release = seq_release_private,
+	.release = seq_release_net,
 };
 #endif /* CONFIG_PROC_FS */
 
-static int __init exp_proc_init(void)
+static int exp_proc_init(struct net *net)
 {
 #ifdef CONFIG_PROC_FS
 	struct proc_dir_entry *proc;
 
-	proc = proc_net_fops_create(&init_net, "nf_conntrack_expect", 0440, &exp_file_ops);
+	proc = proc_net_fops_create(net, "nf_conntrack_expect", 0440, &exp_file_ops);
 	if (!proc)
 		return -ENOMEM;
 #endif /* CONFIG_PROC_FS */
 	return 0;
 }
 
-static void exp_proc_remove(void)
+static void exp_proc_remove(struct net *net)
 {
 #ifdef CONFIG_PROC_FS
-	proc_net_remove(&init_net, "nf_conntrack_expect");
+	proc_net_remove(net, "nf_conntrack_expect");
 #endif /* CONFIG_PROC_FS */
 }
 
 module_param_named(expect_hashsize, nf_ct_expect_hsize, uint, 0600);
 
-int __init nf_conntrack_expect_init(void)
+int nf_conntrack_expect_init(struct net *net)
 {
 	int err = -ENOMEM;
 
-	if (!nf_ct_expect_hsize) {
-		nf_ct_expect_hsize = nf_conntrack_htable_size / 256;
-		if (!nf_ct_expect_hsize)
-			nf_ct_expect_hsize = 1;
+	if (net_eq(net, &init_net)) {
+		if (!nf_ct_expect_hsize) {
+			nf_ct_expect_hsize = nf_conntrack_htable_size / 256;
+			if (!nf_ct_expect_hsize)
+				nf_ct_expect_hsize = 1;
+		}
+		nf_ct_expect_max = nf_ct_expect_hsize * 4;
 	}
-	nf_ct_expect_max = nf_ct_expect_hsize * 4;
 
-	nf_ct_expect_hash = nf_ct_alloc_hashtable(&nf_ct_expect_hsize,
-						  &nf_ct_expect_vmalloc);
-	if (nf_ct_expect_hash == NULL)
+	net->ct.expect_count = 0;
+	net->ct.expect_hash = nf_ct_alloc_hashtable(&nf_ct_expect_hsize,
+						  &net->ct.expect_vmalloc);
+	if (net->ct.expect_hash == NULL)
 		goto err1;
 
-	nf_ct_expect_cachep = kmem_cache_create("nf_conntrack_expect",
+	if (net_eq(net, &init_net)) {
+		nf_ct_expect_cachep = kmem_cache_create("nf_conntrack_expect",
 					sizeof(struct nf_conntrack_expect),
 					0, 0, NULL);
-	if (!nf_ct_expect_cachep)
-		goto err2;
+		if (!nf_ct_expect_cachep)
+			goto err2;
+	}
 
-	err = exp_proc_init();
+	err = exp_proc_init(net);
 	if (err < 0)
 		goto err3;
 
 	return 0;
 
 err3:
-	kmem_cache_destroy(nf_ct_expect_cachep);
+	if (net_eq(net, &init_net))
+		kmem_cache_destroy(nf_ct_expect_cachep);
 err2:
-	nf_ct_free_hashtable(nf_ct_expect_hash, nf_ct_expect_vmalloc,
+	nf_ct_free_hashtable(net->ct.expect_hash, net->ct.expect_vmalloc,
 			     nf_ct_expect_hsize);
 err1:
 	return err;
 }
 
-void nf_conntrack_expect_fini(void)
+void nf_conntrack_expect_fini(struct net *net)
 {
-	exp_proc_remove();
-	kmem_cache_destroy(nf_ct_expect_cachep);
-	nf_ct_free_hashtable(nf_ct_expect_hash, nf_ct_expect_vmalloc,
+	exp_proc_remove(net);
+	if (net_eq(net, &init_net))
+		kmem_cache_destroy(nf_ct_expect_cachep);
+	nf_ct_free_hashtable(net->ct.expect_hash, net->ct.expect_vmalloc,
 			     nf_ct_expect_hsize);
 }
diff --git a/net/netfilter/nf_conntrack_ftp.c b/net/netfilter/nf_conntrack_ftp.c
index bb20672..4f71071 100644
--- a/net/netfilter/nf_conntrack_ftp.c
+++ b/net/netfilter/nf_conntrack_ftp.c
@@ -318,7 +318,8 @@
 }
 
 /* We don't update if it's older than what we have. */
-static void update_nl_seq(u32 nl_seq, struct nf_ct_ftp_master *info, int dir,
+static void update_nl_seq(struct nf_conn *ct, u32 nl_seq,
+			  struct nf_ct_ftp_master *info, int dir,
 			  struct sk_buff *skb)
 {
 	unsigned int i, oldest = NUM_SEQ_TO_REMEMBER;
@@ -336,11 +337,11 @@
 
 	if (info->seq_aft_nl_num[dir] < NUM_SEQ_TO_REMEMBER) {
 		info->seq_aft_nl[dir][info->seq_aft_nl_num[dir]++] = nl_seq;
-		nf_conntrack_event_cache(IPCT_HELPINFO_VOLATILE, skb);
+		nf_conntrack_event_cache(IPCT_HELPINFO_VOLATILE, ct);
 	} else if (oldest != NUM_SEQ_TO_REMEMBER &&
 		   after(nl_seq, info->seq_aft_nl[dir][oldest])) {
 		info->seq_aft_nl[dir][oldest] = nl_seq;
-		nf_conntrack_event_cache(IPCT_HELPINFO_VOLATILE, skb);
+		nf_conntrack_event_cache(IPCT_HELPINFO_VOLATILE, ct);
 	}
 }
 
@@ -509,7 +510,7 @@
 	/* Now if this ends in \n, update ftp info.  Seq may have been
 	 * adjusted by NAT code. */
 	if (ends_in_nl)
-		update_nl_seq(seq, ct_ftp_info, dir, skb);
+		update_nl_seq(ct, seq, ct_ftp_info, dir, skb);
  out:
 	spin_unlock_bh(&nf_ftp_lock);
 	return ret;
diff --git a/net/netfilter/nf_conntrack_h323_main.c b/net/netfilter/nf_conntrack_h323_main.c
index 2f83c15..c1504f7 100644
--- a/net/netfilter/nf_conntrack_h323_main.c
+++ b/net/netfilter/nf_conntrack_h323_main.c
@@ -709,7 +709,8 @@
 /* If the calling party is on the same side of the forward-to party,
  * we don't need to track the second call */
 static int callforward_do_filter(const union nf_inet_addr *src,
-                                 const union nf_inet_addr *dst, int family)
+				 const union nf_inet_addr *dst,
+				 u_int8_t family)
 {
 	const struct nf_afinfo *afinfo;
 	struct flowi fl1, fl2;
@@ -1209,6 +1210,7 @@
 					       union nf_inet_addr *addr,
 					       __be16 port)
 {
+	struct net *net = nf_ct_net(ct);
 	struct nf_conntrack_expect *exp;
 	struct nf_conntrack_tuple tuple;
 
@@ -1218,7 +1220,7 @@
 	tuple.dst.u.tcp.port = port;
 	tuple.dst.protonum = IPPROTO_TCP;
 
-	exp = __nf_ct_expect_find(&tuple);
+	exp = __nf_ct_expect_find(net, &tuple);
 	if (exp && exp->master == ct)
 		return exp;
 	return NULL;
diff --git a/net/netfilter/nf_conntrack_helper.c b/net/netfilter/nf_conntrack_helper.c
index 8e0b4c8..9c06b9f 100644
--- a/net/netfilter/nf_conntrack_helper.c
+++ b/net/netfilter/nf_conntrack_helper.c
@@ -123,13 +123,40 @@
 }
 EXPORT_SYMBOL_GPL(nf_conntrack_helper_register);
 
-void nf_conntrack_helper_unregister(struct nf_conntrack_helper *me)
+static void __nf_conntrack_helper_unregister(struct nf_conntrack_helper *me,
+					     struct net *net)
 {
 	struct nf_conntrack_tuple_hash *h;
 	struct nf_conntrack_expect *exp;
 	const struct hlist_node *n, *next;
 	unsigned int i;
 
+	/* Get rid of expectations */
+	for (i = 0; i < nf_ct_expect_hsize; i++) {
+		hlist_for_each_entry_safe(exp, n, next,
+					  &net->ct.expect_hash[i], hnode) {
+			struct nf_conn_help *help = nfct_help(exp->master);
+			if ((help->helper == me || exp->helper == me) &&
+			    del_timer(&exp->timeout)) {
+				nf_ct_unlink_expect(exp);
+				nf_ct_expect_put(exp);
+			}
+		}
+	}
+
+	/* Get rid of expecteds, set helpers to NULL. */
+	hlist_for_each_entry(h, n, &net->ct.unconfirmed, hnode)
+		unhelp(h, me);
+	for (i = 0; i < nf_conntrack_htable_size; i++) {
+		hlist_for_each_entry(h, n, &net->ct.hash[i], hnode)
+			unhelp(h, me);
+	}
+}
+
+void nf_conntrack_helper_unregister(struct nf_conntrack_helper *me)
+{
+	struct net *net;
+
 	mutex_lock(&nf_ct_helper_mutex);
 	hlist_del_rcu(&me->hnode);
 	nf_ct_helper_count--;
@@ -141,27 +168,8 @@
 	synchronize_rcu();
 
 	spin_lock_bh(&nf_conntrack_lock);
-
-	/* Get rid of expectations */
-	for (i = 0; i < nf_ct_expect_hsize; i++) {
-		hlist_for_each_entry_safe(exp, n, next,
-					  &nf_ct_expect_hash[i], hnode) {
-			struct nf_conn_help *help = nfct_help(exp->master);
-			if ((help->helper == me || exp->helper == me) &&
-			    del_timer(&exp->timeout)) {
-				nf_ct_unlink_expect(exp);
-				nf_ct_expect_put(exp);
-			}
-		}
-	}
-
-	/* Get rid of expecteds, set helpers to NULL. */
-	hlist_for_each_entry(h, n, &unconfirmed, hnode)
-		unhelp(h, me);
-	for (i = 0; i < nf_conntrack_htable_size; i++) {
-		hlist_for_each_entry(h, n, &nf_conntrack_hash[i], hnode)
-			unhelp(h, me);
-	}
+	for_each_net(net)
+		__nf_conntrack_helper_unregister(me, net);
 	spin_unlock_bh(&nf_conntrack_lock);
 }
 EXPORT_SYMBOL_GPL(nf_conntrack_helper_unregister);
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
index a875203..cadfd15 100644
--- a/net/netfilter/nf_conntrack_netlink.c
+++ b/net/netfilter/nf_conntrack_netlink.c
@@ -549,7 +549,7 @@
 	last = (struct nf_conn *)cb->args[1];
 	for (; cb->args[0] < nf_conntrack_htable_size; cb->args[0]++) {
 restart:
-		hlist_for_each_entry_rcu(h, n, &nf_conntrack_hash[cb->args[0]],
+		hlist_for_each_entry_rcu(h, n, &init_net.ct.hash[cb->args[0]],
 					 hnode) {
 			if (NF_CT_DIRECTION(h) != IP_CT_DIR_ORIGINAL)
 				continue;
@@ -794,14 +794,14 @@
 		err = ctnetlink_parse_tuple(cda, &tuple, CTA_TUPLE_REPLY, u3);
 	else {
 		/* Flush the whole table */
-		nf_conntrack_flush();
+		nf_conntrack_flush(&init_net);
 		return 0;
 	}
 
 	if (err < 0)
 		return err;
 
-	h = nf_conntrack_find_get(&tuple);
+	h = nf_conntrack_find_get(&init_net, &tuple);
 	if (!h)
 		return -ENOENT;
 
@@ -847,7 +847,7 @@
 	if (err < 0)
 		return err;
 
-	h = nf_conntrack_find_get(&tuple);
+	h = nf_conntrack_find_get(&init_net, &tuple);
 	if (!h)
 		return -ENOENT;
 
@@ -1125,7 +1125,7 @@
 	struct nf_conn_help *help;
 	struct nf_conntrack_helper *helper;
 
-	ct = nf_conntrack_alloc(otuple, rtuple, GFP_KERNEL);
+	ct = nf_conntrack_alloc(&init_net, otuple, rtuple, GFP_KERNEL);
 	if (ct == NULL || IS_ERR(ct))
 		return -ENOMEM;
 
@@ -1213,9 +1213,9 @@
 
 	spin_lock_bh(&nf_conntrack_lock);
 	if (cda[CTA_TUPLE_ORIG])
-		h = __nf_conntrack_find(&otuple);
+		h = __nf_conntrack_find(&init_net, &otuple);
 	else if (cda[CTA_TUPLE_REPLY])
-		h = __nf_conntrack_find(&rtuple);
+		h = __nf_conntrack_find(&init_net, &rtuple);
 
 	if (h == NULL) {
 		struct nf_conntrack_tuple master;
@@ -1230,7 +1230,7 @@
 			if (err < 0)
 				goto out_unlock;
 
-			master_h = __nf_conntrack_find(&master);
+			master_h = __nf_conntrack_find(&init_net, &master);
 			if (master_h == NULL) {
 				err = -ENOENT;
 				goto out_unlock;
@@ -1458,6 +1458,7 @@
 static int
 ctnetlink_exp_dump_table(struct sk_buff *skb, struct netlink_callback *cb)
 {
+	struct net *net = &init_net;
 	struct nf_conntrack_expect *exp, *last;
 	struct nfgenmsg *nfmsg = NLMSG_DATA(cb->nlh);
 	struct hlist_node *n;
@@ -1467,7 +1468,7 @@
 	last = (struct nf_conntrack_expect *)cb->args[1];
 	for (; cb->args[0] < nf_ct_expect_hsize; cb->args[0]++) {
 restart:
-		hlist_for_each_entry(exp, n, &nf_ct_expect_hash[cb->args[0]],
+		hlist_for_each_entry(exp, n, &net->ct.expect_hash[cb->args[0]],
 				     hnode) {
 			if (l3proto && exp->tuple.src.l3num != l3proto)
 				continue;
@@ -1529,7 +1530,7 @@
 	if (err < 0)
 		return err;
 
-	exp = nf_ct_expect_find_get(&tuple);
+	exp = nf_ct_expect_find_get(&init_net, &tuple);
 	if (!exp)
 		return -ENOENT;
 
@@ -1583,7 +1584,7 @@
 			return err;
 
 		/* bump usage count to 2 */
-		exp = nf_ct_expect_find_get(&tuple);
+		exp = nf_ct_expect_find_get(&init_net, &tuple);
 		if (!exp)
 			return -ENOENT;
 
@@ -1613,7 +1614,7 @@
 		}
 		for (i = 0; i < nf_ct_expect_hsize; i++) {
 			hlist_for_each_entry_safe(exp, n, next,
-						  &nf_ct_expect_hash[i],
+						  &init_net.ct.expect_hash[i],
 						  hnode) {
 				m_help = nfct_help(exp->master);
 				if (m_help->helper == h
@@ -1629,7 +1630,7 @@
 		spin_lock_bh(&nf_conntrack_lock);
 		for (i = 0; i < nf_ct_expect_hsize; i++) {
 			hlist_for_each_entry_safe(exp, n, next,
-						  &nf_ct_expect_hash[i],
+						  &init_net.ct.expect_hash[i],
 						  hnode) {
 				if (del_timer(&exp->timeout)) {
 					nf_ct_unlink_expect(exp);
@@ -1670,7 +1671,7 @@
 		return err;
 
 	/* Look for master conntrack of this expectation */
-	h = nf_conntrack_find_get(&master_tuple);
+	h = nf_conntrack_find_get(&init_net, &master_tuple);
 	if (!h)
 		return -ENOENT;
 	ct = nf_ct_tuplehash_to_ctrack(h);
@@ -1724,7 +1725,7 @@
 		return err;
 
 	spin_lock_bh(&nf_conntrack_lock);
-	exp = __nf_ct_expect_find(&tuple);
+	exp = __nf_ct_expect_find(&init_net, &tuple);
 
 	if (!exp) {
 		spin_unlock_bh(&nf_conntrack_lock);
diff --git a/net/netfilter/nf_conntrack_pptp.c b/net/netfilter/nf_conntrack_pptp.c
index 97e54b0..373e51e 100644
--- a/net/netfilter/nf_conntrack_pptp.c
+++ b/net/netfilter/nf_conntrack_pptp.c
@@ -98,6 +98,7 @@
 static void pptp_expectfn(struct nf_conn *ct,
 			 struct nf_conntrack_expect *exp)
 {
+	struct net *net = nf_ct_net(ct);
 	typeof(nf_nat_pptp_hook_expectfn) nf_nat_pptp_expectfn;
 	pr_debug("increasing timeouts\n");
 
@@ -121,7 +122,7 @@
 		pr_debug("trying to unexpect other dir: ");
 		nf_ct_dump_tuple(&inv_t);
 
-		exp_other = nf_ct_expect_find_get(&inv_t);
+		exp_other = nf_ct_expect_find_get(net, &inv_t);
 		if (exp_other) {
 			/* delete other expectation.  */
 			pr_debug("found\n");
@@ -134,7 +135,8 @@
 	rcu_read_unlock();
 }
 
-static int destroy_sibling_or_exp(const struct nf_conntrack_tuple *t)
+static int destroy_sibling_or_exp(struct net *net,
+				  const struct nf_conntrack_tuple *t)
 {
 	const struct nf_conntrack_tuple_hash *h;
 	struct nf_conntrack_expect *exp;
@@ -143,7 +145,7 @@
 	pr_debug("trying to timeout ct or exp for tuple ");
 	nf_ct_dump_tuple(t);
 
-	h = nf_conntrack_find_get(t);
+	h = nf_conntrack_find_get(net, t);
 	if (h)  {
 		sibling = nf_ct_tuplehash_to_ctrack(h);
 		pr_debug("setting timeout of conntrack %p to 0\n", sibling);
@@ -154,7 +156,7 @@
 		nf_ct_put(sibling);
 		return 1;
 	} else {
-		exp = nf_ct_expect_find_get(t);
+		exp = nf_ct_expect_find_get(net, t);
 		if (exp) {
 			pr_debug("unexpect_related of expect %p\n", exp);
 			nf_ct_unexpect_related(exp);
@@ -168,6 +170,7 @@
 /* timeout GRE data connections */
 static void pptp_destroy_siblings(struct nf_conn *ct)
 {
+	struct net *net = nf_ct_net(ct);
 	const struct nf_conn_help *help = nfct_help(ct);
 	struct nf_conntrack_tuple t;
 
@@ -178,7 +181,7 @@
 	t.dst.protonum = IPPROTO_GRE;
 	t.src.u.gre.key = help->help.ct_pptp_info.pns_call_id;
 	t.dst.u.gre.key = help->help.ct_pptp_info.pac_call_id;
-	if (!destroy_sibling_or_exp(&t))
+	if (!destroy_sibling_or_exp(net, &t))
 		pr_debug("failed to timeout original pns->pac ct/exp\n");
 
 	/* try reply (pac->pns) tuple */
@@ -186,7 +189,7 @@
 	t.dst.protonum = IPPROTO_GRE;
 	t.src.u.gre.key = help->help.ct_pptp_info.pac_call_id;
 	t.dst.u.gre.key = help->help.ct_pptp_info.pns_call_id;
-	if (!destroy_sibling_or_exp(&t))
+	if (!destroy_sibling_or_exp(net, &t))
 		pr_debug("failed to timeout reply pac->pns ct/exp\n");
 }
 
@@ -594,15 +597,32 @@
 	.expect_policy		= &pptp_exp_policy,
 };
 
+static void nf_conntrack_pptp_net_exit(struct net *net)
+{
+	nf_ct_gre_keymap_flush(net);
+}
+
+static struct pernet_operations nf_conntrack_pptp_net_ops = {
+	.exit = nf_conntrack_pptp_net_exit,
+};
+
 static int __init nf_conntrack_pptp_init(void)
 {
-	return nf_conntrack_helper_register(&pptp);
+	int rv;
+
+	rv = nf_conntrack_helper_register(&pptp);
+	if (rv < 0)
+		return rv;
+	rv = register_pernet_subsys(&nf_conntrack_pptp_net_ops);
+	if (rv < 0)
+		nf_conntrack_helper_unregister(&pptp);
+	return rv;
 }
 
 static void __exit nf_conntrack_pptp_fini(void)
 {
 	nf_conntrack_helper_unregister(&pptp);
-	nf_ct_gre_keymap_flush();
+	unregister_pernet_subsys(&nf_conntrack_pptp_net_ops);
 }
 
 module_init(nf_conntrack_pptp_init);
diff --git a/net/netfilter/nf_conntrack_proto.c b/net/netfilter/nf_conntrack_proto.c
index a49fc93..a59a307 100644
--- a/net/netfilter/nf_conntrack_proto.c
+++ b/net/netfilter/nf_conntrack_proto.c
@@ -207,6 +207,8 @@
 
 void nf_conntrack_l3proto_unregister(struct nf_conntrack_l3proto *proto)
 {
+	struct net *net;
+
 	BUG_ON(proto->l3proto >= AF_MAX);
 
 	mutex_lock(&nf_ct_proto_mutex);
@@ -219,7 +221,8 @@
 	synchronize_rcu();
 
 	/* Remove all contrack entries for this protocol */
-	nf_ct_iterate_cleanup(kill_l3proto, proto);
+	for_each_net(net)
+		nf_ct_iterate_cleanup(net, kill_l3proto, proto);
 }
 EXPORT_SYMBOL_GPL(nf_conntrack_l3proto_unregister);
 
@@ -316,6 +319,8 @@
 
 void nf_conntrack_l4proto_unregister(struct nf_conntrack_l4proto *l4proto)
 {
+	struct net *net;
+
 	BUG_ON(l4proto->l3proto >= PF_MAX);
 
 	mutex_lock(&nf_ct_proto_mutex);
@@ -328,7 +333,8 @@
 	synchronize_rcu();
 
 	/* Remove all contrack entries for this protocol */
-	nf_ct_iterate_cleanup(kill_l4proto, l4proto);
+	for_each_net(net)
+		nf_ct_iterate_cleanup(net, kill_l4proto, l4proto);
 }
 EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_unregister);
 
diff --git a/net/netfilter/nf_conntrack_proto_dccp.c b/net/netfilter/nf_conntrack_proto_dccp.c
index e7866dd..8fcf176 100644
--- a/net/netfilter/nf_conntrack_proto_dccp.c
+++ b/net/netfilter/nf_conntrack_proto_dccp.c
@@ -418,6 +418,7 @@
 static bool dccp_new(struct nf_conn *ct, const struct sk_buff *skb,
 		     unsigned int dataoff)
 {
+	struct net *net = nf_ct_net(ct);
 	struct dccp_hdr _dh, *dh;
 	const char *msg;
 	u_int8_t state;
@@ -445,7 +446,7 @@
 	return true;
 
 out_invalid:
-	if (LOG_INVALID(IPPROTO_DCCP))
+	if (LOG_INVALID(net, IPPROTO_DCCP))
 		nf_log_packet(nf_ct_l3num(ct), 0, skb, NULL, NULL, NULL, msg);
 	return false;
 }
@@ -461,8 +462,9 @@
 
 static int dccp_packet(struct nf_conn *ct, const struct sk_buff *skb,
 		       unsigned int dataoff, enum ip_conntrack_info ctinfo,
-		       int pf, unsigned int hooknum)
+		       u_int8_t pf, unsigned int hooknum)
 {
+	struct net *net = nf_ct_net(ct);
 	enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
 	struct dccp_hdr _dh, *dh;
 	u_int8_t type, old_state, new_state;
@@ -524,13 +526,13 @@
 		ct->proto.dccp.last_pkt = type;
 
 		write_unlock_bh(&dccp_lock);
-		if (LOG_INVALID(IPPROTO_DCCP))
+		if (LOG_INVALID(net, IPPROTO_DCCP))
 			nf_log_packet(pf, 0, skb, NULL, NULL, NULL,
 				      "nf_ct_dccp: invalid packet ignored ");
 		return NF_ACCEPT;
 	case CT_DCCP_INVALID:
 		write_unlock_bh(&dccp_lock);
-		if (LOG_INVALID(IPPROTO_DCCP))
+		if (LOG_INVALID(net, IPPROTO_DCCP))
 			nf_log_packet(pf, 0, skb, NULL, NULL, NULL,
 				      "nf_ct_dccp: invalid state transition ");
 		return -NF_ACCEPT;
@@ -545,9 +547,9 @@
 	return NF_ACCEPT;
 }
 
-static int dccp_error(struct sk_buff *skb, unsigned int dataoff,
-		      enum ip_conntrack_info *ctinfo, int pf,
-		      unsigned int hooknum)
+static int dccp_error(struct net *net, struct sk_buff *skb,
+		      unsigned int dataoff, enum ip_conntrack_info *ctinfo,
+		      u_int8_t pf, unsigned int hooknum)
 {
 	struct dccp_hdr _dh, *dh;
 	unsigned int dccp_len = skb->len - dataoff;
@@ -575,7 +577,7 @@
 		}
 	}
 
-	if (nf_conntrack_checksum && hooknum == NF_INET_PRE_ROUTING &&
+	if (net->ct.sysctl_checksum && hooknum == NF_INET_PRE_ROUTING &&
 	    nf_checksum_partial(skb, hooknum, dataoff, cscov, IPPROTO_DCCP,
 				pf)) {
 		msg = "nf_ct_dccp: bad checksum ";
@@ -590,7 +592,7 @@
 	return NF_ACCEPT;
 
 out_invalid:
-	if (LOG_INVALID(IPPROTO_DCCP))
+	if (LOG_INVALID(net, IPPROTO_DCCP))
 		nf_log_packet(pf, 0, skb, NULL, NULL, NULL, msg);
 	return -NF_ACCEPT;
 }
diff --git a/net/netfilter/nf_conntrack_proto_generic.c b/net/netfilter/nf_conntrack_proto_generic.c
index e31b0e7..dbe680a 100644
--- a/net/netfilter/nf_conntrack_proto_generic.c
+++ b/net/netfilter/nf_conntrack_proto_generic.c
@@ -45,7 +45,7 @@
 		  const struct sk_buff *skb,
 		  unsigned int dataoff,
 		  enum ip_conntrack_info ctinfo,
-		  int pf,
+		  u_int8_t pf,
 		  unsigned int hooknum)
 {
 	nf_ct_refresh_acct(ct, ctinfo, skb, nf_ct_generic_timeout);
diff --git a/net/netfilter/nf_conntrack_proto_gre.c b/net/netfilter/nf_conntrack_proto_gre.c
index 9bd0396..a2cdbcb 100644
--- a/net/netfilter/nf_conntrack_proto_gre.c
+++ b/net/netfilter/nf_conntrack_proto_gre.c
@@ -29,8 +29,11 @@
 #include <linux/list.h>
 #include <linux/seq_file.h>
 #include <linux/in.h>
+#include <linux/netdevice.h>
 #include <linux/skbuff.h>
-
+#include <net/dst.h>
+#include <net/net_namespace.h>
+#include <net/netns/generic.h>
 #include <net/netfilter/nf_conntrack_l4proto.h>
 #include <net/netfilter/nf_conntrack_helper.h>
 #include <net/netfilter/nf_conntrack_core.h>
@@ -40,19 +43,23 @@
 #define GRE_TIMEOUT		(30 * HZ)
 #define GRE_STREAM_TIMEOUT	(180 * HZ)
 
-static DEFINE_RWLOCK(nf_ct_gre_lock);
-static LIST_HEAD(gre_keymap_list);
+static int proto_gre_net_id;
+struct netns_proto_gre {
+	rwlock_t		keymap_lock;
+	struct list_head	keymap_list;
+};
 
-void nf_ct_gre_keymap_flush(void)
+void nf_ct_gre_keymap_flush(struct net *net)
 {
+	struct netns_proto_gre *net_gre = net_generic(net, proto_gre_net_id);
 	struct nf_ct_gre_keymap *km, *tmp;
 
-	write_lock_bh(&nf_ct_gre_lock);
-	list_for_each_entry_safe(km, tmp, &gre_keymap_list, list) {
+	write_lock_bh(&net_gre->keymap_lock);
+	list_for_each_entry_safe(km, tmp, &net_gre->keymap_list, list) {
 		list_del(&km->list);
 		kfree(km);
 	}
-	write_unlock_bh(&nf_ct_gre_lock);
+	write_unlock_bh(&net_gre->keymap_lock);
 }
 EXPORT_SYMBOL(nf_ct_gre_keymap_flush);
 
@@ -67,19 +74,20 @@
 }
 
 /* look up the source key for a given tuple */
-static __be16 gre_keymap_lookup(struct nf_conntrack_tuple *t)
+static __be16 gre_keymap_lookup(struct net *net, struct nf_conntrack_tuple *t)
 {
+	struct netns_proto_gre *net_gre = net_generic(net, proto_gre_net_id);
 	struct nf_ct_gre_keymap *km;
 	__be16 key = 0;
 
-	read_lock_bh(&nf_ct_gre_lock);
-	list_for_each_entry(km, &gre_keymap_list, list) {
+	read_lock_bh(&net_gre->keymap_lock);
+	list_for_each_entry(km, &net_gre->keymap_list, list) {
 		if (gre_key_cmpfn(km, t)) {
 			key = km->tuple.src.u.gre.key;
 			break;
 		}
 	}
-	read_unlock_bh(&nf_ct_gre_lock);
+	read_unlock_bh(&net_gre->keymap_lock);
 
 	pr_debug("lookup src key 0x%x for ", key);
 	nf_ct_dump_tuple(t);
@@ -91,20 +99,22 @@
 int nf_ct_gre_keymap_add(struct nf_conn *ct, enum ip_conntrack_dir dir,
 			 struct nf_conntrack_tuple *t)
 {
+	struct net *net = nf_ct_net(ct);
+	struct netns_proto_gre *net_gre = net_generic(net, proto_gre_net_id);
 	struct nf_conn_help *help = nfct_help(ct);
 	struct nf_ct_gre_keymap **kmp, *km;
 
 	kmp = &help->help.ct_pptp_info.keymap[dir];
 	if (*kmp) {
 		/* check whether it's a retransmission */
-		read_lock_bh(&nf_ct_gre_lock);
-		list_for_each_entry(km, &gre_keymap_list, list) {
+		read_lock_bh(&net_gre->keymap_lock);
+		list_for_each_entry(km, &net_gre->keymap_list, list) {
 			if (gre_key_cmpfn(km, t) && km == *kmp) {
-				read_unlock_bh(&nf_ct_gre_lock);
+				read_unlock_bh(&net_gre->keymap_lock);
 				return 0;
 			}
 		}
-		read_unlock_bh(&nf_ct_gre_lock);
+		read_unlock_bh(&net_gre->keymap_lock);
 		pr_debug("trying to override keymap_%s for ct %p\n",
 			 dir == IP_CT_DIR_REPLY ? "reply" : "orig", ct);
 		return -EEXIST;
@@ -119,9 +129,9 @@
 	pr_debug("adding new entry %p: ", km);
 	nf_ct_dump_tuple(&km->tuple);
 
-	write_lock_bh(&nf_ct_gre_lock);
-	list_add_tail(&km->list, &gre_keymap_list);
-	write_unlock_bh(&nf_ct_gre_lock);
+	write_lock_bh(&net_gre->keymap_lock);
+	list_add_tail(&km->list, &net_gre->keymap_list);
+	write_unlock_bh(&net_gre->keymap_lock);
 
 	return 0;
 }
@@ -130,12 +140,14 @@
 /* destroy the keymap entries associated with specified master ct */
 void nf_ct_gre_keymap_destroy(struct nf_conn *ct)
 {
+	struct net *net = nf_ct_net(ct);
+	struct netns_proto_gre *net_gre = net_generic(net, proto_gre_net_id);
 	struct nf_conn_help *help = nfct_help(ct);
 	enum ip_conntrack_dir dir;
 
 	pr_debug("entering for ct %p\n", ct);
 
-	write_lock_bh(&nf_ct_gre_lock);
+	write_lock_bh(&net_gre->keymap_lock);
 	for (dir = IP_CT_DIR_ORIGINAL; dir < IP_CT_DIR_MAX; dir++) {
 		if (help->help.ct_pptp_info.keymap[dir]) {
 			pr_debug("removing %p from list\n",
@@ -145,7 +157,7 @@
 			help->help.ct_pptp_info.keymap[dir] = NULL;
 		}
 	}
-	write_unlock_bh(&nf_ct_gre_lock);
+	write_unlock_bh(&net_gre->keymap_lock);
 }
 EXPORT_SYMBOL_GPL(nf_ct_gre_keymap_destroy);
 
@@ -164,6 +176,7 @@
 static bool gre_pkt_to_tuple(const struct sk_buff *skb, unsigned int dataoff,
 			     struct nf_conntrack_tuple *tuple)
 {
+	struct net *net = dev_net(skb->dev ? skb->dev : skb->dst->dev);
 	const struct gre_hdr_pptp *pgrehdr;
 	struct gre_hdr_pptp _pgrehdr;
 	__be16 srckey;
@@ -190,7 +203,7 @@
 	}
 
 	tuple->dst.u.gre.key = pgrehdr->call_id;
-	srckey = gre_keymap_lookup(tuple);
+	srckey = gre_keymap_lookup(net, tuple);
 	tuple->src.u.gre.key = srckey;
 
 	return true;
@@ -219,7 +232,7 @@
 		      const struct sk_buff *skb,
 		      unsigned int dataoff,
 		      enum ip_conntrack_info ctinfo,
-		      int pf,
+		      u_int8_t pf,
 		      unsigned int hooknum)
 {
 	/* If we've seen traffic both ways, this is a GRE connection.
@@ -229,7 +242,7 @@
 				   ct->proto.gre.stream_timeout);
 		/* Also, more likely to be important, and not a probe. */
 		set_bit(IPS_ASSURED_BIT, &ct->status);
-		nf_conntrack_event_cache(IPCT_STATUS, skb);
+		nf_conntrack_event_cache(IPCT_STATUS, ct);
 	} else
 		nf_ct_refresh_acct(ct, ctinfo, skb,
 				   ct->proto.gre.timeout);
@@ -285,15 +298,53 @@
 #endif
 };
 
+static int proto_gre_net_init(struct net *net)
+{
+	struct netns_proto_gre *net_gre;
+	int rv;
+
+	net_gre = kmalloc(sizeof(struct netns_proto_gre), GFP_KERNEL);
+	if (!net_gre)
+		return -ENOMEM;
+	rwlock_init(&net_gre->keymap_lock);
+	INIT_LIST_HEAD(&net_gre->keymap_list);
+
+	rv = net_assign_generic(net, proto_gre_net_id, net_gre);
+	if (rv < 0)
+		kfree(net_gre);
+	return rv;
+}
+
+static void proto_gre_net_exit(struct net *net)
+{
+	struct netns_proto_gre *net_gre = net_generic(net, proto_gre_net_id);
+
+	nf_ct_gre_keymap_flush(net);
+	kfree(net_gre);
+}
+
+static struct pernet_operations proto_gre_net_ops = {
+	.init = proto_gre_net_init,
+	.exit = proto_gre_net_exit,
+};
+
 static int __init nf_ct_proto_gre_init(void)
 {
-	return nf_conntrack_l4proto_register(&nf_conntrack_l4proto_gre4);
+	int rv;
+
+	rv = nf_conntrack_l4proto_register(&nf_conntrack_l4proto_gre4);
+	if (rv < 0)
+		return rv;
+	rv = register_pernet_gen_device(&proto_gre_net_id, &proto_gre_net_ops);
+	if (rv < 0)
+		nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_gre4);
+	return rv;
 }
 
 static void nf_ct_proto_gre_fini(void)
 {
 	nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_gre4);
-	nf_ct_gre_keymap_flush();
+	unregister_pernet_gen_device(proto_gre_net_id, &proto_gre_net_ops);
 }
 
 module_init(nf_ct_proto_gre_init);
diff --git a/net/netfilter/nf_conntrack_proto_sctp.c b/net/netfilter/nf_conntrack_proto_sctp.c
index 30aa5b9..ae8c260 100644
--- a/net/netfilter/nf_conntrack_proto_sctp.c
+++ b/net/netfilter/nf_conntrack_proto_sctp.c
@@ -287,7 +287,7 @@
 		       const struct sk_buff *skb,
 		       unsigned int dataoff,
 		       enum ip_conntrack_info ctinfo,
-		       int pf,
+		       u_int8_t pf,
 		       unsigned int hooknum)
 {
 	enum sctp_conntrack new_state, old_state;
@@ -369,7 +369,7 @@
 
 		ct->proto.sctp.state = new_state;
 		if (old_state != new_state)
-			nf_conntrack_event_cache(IPCT_PROTOINFO, skb);
+			nf_conntrack_event_cache(IPCT_PROTOINFO, ct);
 	}
 	write_unlock_bh(&sctp_lock);
 
@@ -380,7 +380,7 @@
 	    new_state == SCTP_CONNTRACK_ESTABLISHED) {
 		pr_debug("Setting assured bit\n");
 		set_bit(IPS_ASSURED_BIT, &ct->status);
-		nf_conntrack_event_cache(IPCT_STATUS, skb);
+		nf_conntrack_event_cache(IPCT_STATUS, ct);
 	}
 
 	return NF_ACCEPT;
diff --git a/net/netfilter/nf_conntrack_proto_tcp.c b/net/netfilter/nf_conntrack_proto_tcp.c
index 6f61261..f947ec4 100644
--- a/net/netfilter/nf_conntrack_proto_tcp.c
+++ b/net/netfilter/nf_conntrack_proto_tcp.c
@@ -486,8 +486,9 @@
 			  const struct sk_buff *skb,
 			  unsigned int dataoff,
 			  const struct tcphdr *tcph,
-			  int pf)
+			  u_int8_t pf)
 {
+	struct net *net = nf_ct_net(ct);
 	struct ip_ct_tcp_state *sender = &state->seen[dir];
 	struct ip_ct_tcp_state *receiver = &state->seen[!dir];
 	const struct nf_conntrack_tuple *tuple = &ct->tuplehash[dir].tuple;
@@ -668,7 +669,7 @@
 		if (sender->flags & IP_CT_TCP_FLAG_BE_LIBERAL ||
 		    nf_ct_tcp_be_liberal)
 			res = true;
-		if (!res && LOG_INVALID(IPPROTO_TCP))
+		if (!res && LOG_INVALID(net, IPPROTO_TCP))
 			nf_log_packet(pf, 0, skb, NULL, NULL, NULL,
 			"nf_ct_tcp: %s ",
 			before(seq, sender->td_maxend + 1) ?
@@ -746,10 +747,11 @@
 };
 
 /* Protect conntrack agaist broken packets. Code taken from ipt_unclean.c.  */
-static int tcp_error(struct sk_buff *skb,
+static int tcp_error(struct net *net,
+		     struct sk_buff *skb,
 		     unsigned int dataoff,
 		     enum ip_conntrack_info *ctinfo,
-		     int pf,
+		     u_int8_t pf,
 		     unsigned int hooknum)
 {
 	const struct tcphdr *th;
@@ -760,7 +762,7 @@
 	/* Smaller that minimal TCP header? */
 	th = skb_header_pointer(skb, dataoff, sizeof(_tcph), &_tcph);
 	if (th == NULL) {
-		if (LOG_INVALID(IPPROTO_TCP))
+		if (LOG_INVALID(net, IPPROTO_TCP))
 			nf_log_packet(pf, 0, skb, NULL, NULL, NULL,
 				"nf_ct_tcp: short packet ");
 		return -NF_ACCEPT;
@@ -768,7 +770,7 @@
 
 	/* Not whole TCP header or malformed packet */
 	if (th->doff*4 < sizeof(struct tcphdr) || tcplen < th->doff*4) {
-		if (LOG_INVALID(IPPROTO_TCP))
+		if (LOG_INVALID(net, IPPROTO_TCP))
 			nf_log_packet(pf, 0, skb, NULL, NULL, NULL,
 				"nf_ct_tcp: truncated/malformed packet ");
 		return -NF_ACCEPT;
@@ -779,9 +781,9 @@
 	 * because the checksum is assumed to be correct.
 	 */
 	/* FIXME: Source route IP option packets --RR */
-	if (nf_conntrack_checksum && hooknum == NF_INET_PRE_ROUTING &&
+	if (net->ct.sysctl_checksum && hooknum == NF_INET_PRE_ROUTING &&
 	    nf_checksum(skb, hooknum, dataoff, IPPROTO_TCP, pf)) {
-		if (LOG_INVALID(IPPROTO_TCP))
+		if (LOG_INVALID(net, IPPROTO_TCP))
 			nf_log_packet(pf, 0, skb, NULL, NULL, NULL,
 				  "nf_ct_tcp: bad TCP checksum ");
 		return -NF_ACCEPT;
@@ -790,7 +792,7 @@
 	/* Check TCP flags. */
 	tcpflags = (((u_int8_t *)th)[13] & ~(TH_ECE|TH_CWR|TH_PUSH));
 	if (!tcp_valid_flags[tcpflags]) {
-		if (LOG_INVALID(IPPROTO_TCP))
+		if (LOG_INVALID(net, IPPROTO_TCP))
 			nf_log_packet(pf, 0, skb, NULL, NULL, NULL,
 				  "nf_ct_tcp: invalid TCP flag combination ");
 		return -NF_ACCEPT;
@@ -804,9 +806,10 @@
 		      const struct sk_buff *skb,
 		      unsigned int dataoff,
 		      enum ip_conntrack_info ctinfo,
-		      int pf,
+		      u_int8_t pf,
 		      unsigned int hooknum)
 {
+	struct net *net = nf_ct_net(ct);
 	struct nf_conntrack_tuple *tuple;
 	enum tcp_conntrack new_state, old_state;
 	enum ip_conntrack_dir dir;
@@ -885,7 +888,7 @@
 			 * thus initiate a clean new session.
 			 */
 			write_unlock_bh(&tcp_lock);
-			if (LOG_INVALID(IPPROTO_TCP))
+			if (LOG_INVALID(net, IPPROTO_TCP))
 				nf_log_packet(pf, 0, skb, NULL, NULL, NULL,
 					  "nf_ct_tcp: killing out of sync session ");
 			nf_ct_kill(ct);
@@ -898,7 +901,7 @@
 		    segment_seq_plus_len(ntohl(th->seq), skb->len, dataoff, th);
 
 		write_unlock_bh(&tcp_lock);
-		if (LOG_INVALID(IPPROTO_TCP))
+		if (LOG_INVALID(net, IPPROTO_TCP))
 			nf_log_packet(pf, 0, skb, NULL, NULL, NULL,
 				  "nf_ct_tcp: invalid packet ignored ");
 		return NF_ACCEPT;
@@ -907,7 +910,7 @@
 		pr_debug("nf_ct_tcp: Invalid dir=%i index=%u ostate=%u\n",
 			 dir, get_conntrack_index(th), old_state);
 		write_unlock_bh(&tcp_lock);
-		if (LOG_INVALID(IPPROTO_TCP))
+		if (LOG_INVALID(net, IPPROTO_TCP))
 			nf_log_packet(pf, 0, skb, NULL, NULL, NULL,
 				  "nf_ct_tcp: invalid state ");
 		return -NF_ACCEPT;
@@ -968,9 +971,9 @@
 		timeout = tcp_timeouts[new_state];
 	write_unlock_bh(&tcp_lock);
 
-	nf_conntrack_event_cache(IPCT_PROTOINFO_VOLATILE, skb);
+	nf_conntrack_event_cache(IPCT_PROTOINFO_VOLATILE, ct);
 	if (new_state != old_state)
-		nf_conntrack_event_cache(IPCT_PROTOINFO, skb);
+		nf_conntrack_event_cache(IPCT_PROTOINFO, ct);
 
 	if (!test_bit(IPS_SEEN_REPLY_BIT, &ct->status)) {
 		/* If only reply is a RST, we can consider ourselves not to
@@ -989,7 +992,7 @@
 		   after SYN_RECV or a valid answer for a picked up
 		   connection. */
 		set_bit(IPS_ASSURED_BIT, &ct->status);
-		nf_conntrack_event_cache(IPCT_STATUS, skb);
+		nf_conntrack_event_cache(IPCT_STATUS, ct);
 	}
 	nf_ct_refresh_acct(ct, ctinfo, skb, timeout);
 
diff --git a/net/netfilter/nf_conntrack_proto_udp.c b/net/netfilter/nf_conntrack_proto_udp.c
index 8b21762..7c2ca48 100644
--- a/net/netfilter/nf_conntrack_proto_udp.c
+++ b/net/netfilter/nf_conntrack_proto_udp.c
@@ -66,7 +66,7 @@
 		      const struct sk_buff *skb,
 		      unsigned int dataoff,
 		      enum ip_conntrack_info ctinfo,
-		      int pf,
+		      u_int8_t pf,
 		      unsigned int hooknum)
 {
 	/* If we've seen traffic both ways, this is some kind of UDP
@@ -75,7 +75,7 @@
 		nf_ct_refresh_acct(ct, ctinfo, skb, nf_ct_udp_timeout_stream);
 		/* Also, more likely to be important, and not a probe */
 		if (!test_and_set_bit(IPS_ASSURED_BIT, &ct->status))
-			nf_conntrack_event_cache(IPCT_STATUS, skb);
+			nf_conntrack_event_cache(IPCT_STATUS, ct);
 	} else
 		nf_ct_refresh_acct(ct, ctinfo, skb, nf_ct_udp_timeout);
 
@@ -89,9 +89,9 @@
 	return true;
 }
 
-static int udp_error(struct sk_buff *skb, unsigned int dataoff,
+static int udp_error(struct net *net, struct sk_buff *skb, unsigned int dataoff,
 		     enum ip_conntrack_info *ctinfo,
-		     int pf,
+		     u_int8_t pf,
 		     unsigned int hooknum)
 {
 	unsigned int udplen = skb->len - dataoff;
@@ -101,7 +101,7 @@
 	/* Header is too small? */
 	hdr = skb_header_pointer(skb, dataoff, sizeof(_hdr), &_hdr);
 	if (hdr == NULL) {
-		if (LOG_INVALID(IPPROTO_UDP))
+		if (LOG_INVALID(net, IPPROTO_UDP))
 			nf_log_packet(pf, 0, skb, NULL, NULL, NULL,
 				      "nf_ct_udp: short packet ");
 		return -NF_ACCEPT;
@@ -109,7 +109,7 @@
 
 	/* Truncated/malformed packets */
 	if (ntohs(hdr->len) > udplen || ntohs(hdr->len) < sizeof(*hdr)) {
-		if (LOG_INVALID(IPPROTO_UDP))
+		if (LOG_INVALID(net, IPPROTO_UDP))
 			nf_log_packet(pf, 0, skb, NULL, NULL, NULL,
 				"nf_ct_udp: truncated/malformed packet ");
 		return -NF_ACCEPT;
@@ -123,9 +123,9 @@
 	 * We skip checking packets on the outgoing path
 	 * because the checksum is assumed to be correct.
 	 * FIXME: Source route IP option packets --RR */
-	if (nf_conntrack_checksum && hooknum == NF_INET_PRE_ROUTING &&
+	if (net->ct.sysctl_checksum && hooknum == NF_INET_PRE_ROUTING &&
 	    nf_checksum(skb, hooknum, dataoff, IPPROTO_UDP, pf)) {
-		if (LOG_INVALID(IPPROTO_UDP))
+		if (LOG_INVALID(net, IPPROTO_UDP))
 			nf_log_packet(pf, 0, skb, NULL, NULL, NULL,
 				"nf_ct_udp: bad UDP checksum ");
 		return -NF_ACCEPT;
diff --git a/net/netfilter/nf_conntrack_proto_udplite.c b/net/netfilter/nf_conntrack_proto_udplite.c
index 1fa62f3..d22d839e 100644
--- a/net/netfilter/nf_conntrack_proto_udplite.c
+++ b/net/netfilter/nf_conntrack_proto_udplite.c
@@ -65,7 +65,7 @@
 			  const struct sk_buff *skb,
 			  unsigned int dataoff,
 			  enum ip_conntrack_info ctinfo,
-			  int pf,
+			  u_int8_t pf,
 			  unsigned int hooknum)
 {
 	/* If we've seen traffic both ways, this is some kind of UDP
@@ -75,7 +75,7 @@
 				   nf_ct_udplite_timeout_stream);
 		/* Also, more likely to be important, and not a probe */
 		if (!test_and_set_bit(IPS_ASSURED_BIT, &ct->status))
-			nf_conntrack_event_cache(IPCT_STATUS, skb);
+			nf_conntrack_event_cache(IPCT_STATUS, ct);
 	} else
 		nf_ct_refresh_acct(ct, ctinfo, skb, nf_ct_udplite_timeout);
 
@@ -89,9 +89,11 @@
 	return true;
 }
 
-static int udplite_error(struct sk_buff *skb, unsigned int dataoff,
+static int udplite_error(struct net *net,
+			 struct sk_buff *skb,
+			 unsigned int dataoff,
 			 enum ip_conntrack_info *ctinfo,
-			 int pf,
+			 u_int8_t pf,
 			 unsigned int hooknum)
 {
 	unsigned int udplen = skb->len - dataoff;
@@ -102,7 +104,7 @@
 	/* Header is too small? */
 	hdr = skb_header_pointer(skb, dataoff, sizeof(_hdr), &_hdr);
 	if (hdr == NULL) {
-		if (LOG_INVALID(IPPROTO_UDPLITE))
+		if (LOG_INVALID(net, IPPROTO_UDPLITE))
 			nf_log_packet(pf, 0, skb, NULL, NULL, NULL,
 				      "nf_ct_udplite: short packet ");
 		return -NF_ACCEPT;
@@ -112,7 +114,7 @@
 	if (cscov == 0)
 		cscov = udplen;
 	else if (cscov < sizeof(*hdr) || cscov > udplen) {
-		if (LOG_INVALID(IPPROTO_UDPLITE))
+		if (LOG_INVALID(net, IPPROTO_UDPLITE))
 			nf_log_packet(pf, 0, skb, NULL, NULL, NULL,
 				"nf_ct_udplite: invalid checksum coverage ");
 		return -NF_ACCEPT;
@@ -120,17 +122,17 @@
 
 	/* UDPLITE mandates checksums */
 	if (!hdr->check) {
-		if (LOG_INVALID(IPPROTO_UDPLITE))
+		if (LOG_INVALID(net, IPPROTO_UDPLITE))
 			nf_log_packet(pf, 0, skb, NULL, NULL, NULL,
 				      "nf_ct_udplite: checksum missing ");
 		return -NF_ACCEPT;
 	}
 
 	/* Checksum invalid? Ignore. */
-	if (nf_conntrack_checksum && hooknum == NF_INET_PRE_ROUTING &&
+	if (net->ct.sysctl_checksum && hooknum == NF_INET_PRE_ROUTING &&
 	    nf_checksum_partial(skb, hooknum, dataoff, cscov, IPPROTO_UDP,
 	    			pf)) {
-		if (LOG_INVALID(IPPROTO_UDPLITE))
+		if (LOG_INVALID(net, IPPROTO_UDPLITE))
 			nf_log_packet(pf, 0, skb, NULL, NULL, NULL,
 				      "nf_ct_udplite: bad UDPLite checksum ");
 		return -NF_ACCEPT;
diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c
index 1fa306b..6813f1c 100644
--- a/net/netfilter/nf_conntrack_sip.c
+++ b/net/netfilter/nf_conntrack_sip.c
@@ -736,6 +736,7 @@
 	struct nf_conntrack_expect *exp, *rtp_exp, *rtcp_exp;
 	enum ip_conntrack_info ctinfo;
 	struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
+	struct net *net = nf_ct_net(ct);
 	enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
 	union nf_inet_addr *saddr;
 	struct nf_conntrack_tuple tuple;
@@ -775,7 +776,7 @@
 
 	rcu_read_lock();
 	do {
-		exp = __nf_ct_expect_find(&tuple);
+		exp = __nf_ct_expect_find(net, &tuple);
 
 		if (!exp || exp->master == ct ||
 		    nfct_help(exp->master)->helper != nfct_help(ct)->helper ||
diff --git a/net/netfilter/nf_conntrack_standalone.c b/net/netfilter/nf_conntrack_standalone.c
index 8509db1..98106d4 100644
--- a/net/netfilter/nf_conntrack_standalone.c
+++ b/net/netfilter/nf_conntrack_standalone.c
@@ -40,18 +40,20 @@
 EXPORT_SYMBOL_GPL(print_tuple);
 
 struct ct_iter_state {
+	struct seq_net_private p;
 	unsigned int bucket;
 };
 
 static struct hlist_node *ct_get_first(struct seq_file *seq)
 {
+	struct net *net = seq_file_net(seq);
 	struct ct_iter_state *st = seq->private;
 	struct hlist_node *n;
 
 	for (st->bucket = 0;
 	     st->bucket < nf_conntrack_htable_size;
 	     st->bucket++) {
-		n = rcu_dereference(nf_conntrack_hash[st->bucket].first);
+		n = rcu_dereference(net->ct.hash[st->bucket].first);
 		if (n)
 			return n;
 	}
@@ -61,13 +63,14 @@
 static struct hlist_node *ct_get_next(struct seq_file *seq,
 				      struct hlist_node *head)
 {
+	struct net *net = seq_file_net(seq);
 	struct ct_iter_state *st = seq->private;
 
 	head = rcu_dereference(head->next);
 	while (head == NULL) {
 		if (++st->bucket >= nf_conntrack_htable_size)
 			return NULL;
-		head = rcu_dereference(nf_conntrack_hash[st->bucket].first);
+		head = rcu_dereference(net->ct.hash[st->bucket].first);
 	}
 	return head;
 }
@@ -177,7 +180,7 @@
 
 static int ct_open(struct inode *inode, struct file *file)
 {
-	return seq_open_private(file, &ct_seq_ops,
+	return seq_open_net(inode, file, &ct_seq_ops,
 			sizeof(struct ct_iter_state));
 }
 
@@ -186,11 +189,12 @@
 	.open    = ct_open,
 	.read    = seq_read,
 	.llseek  = seq_lseek,
-	.release = seq_release_private,
+	.release = seq_release_net,
 };
 
 static void *ct_cpu_seq_start(struct seq_file *seq, loff_t *pos)
 {
+	struct net *net = seq_file_net(seq);
 	int cpu;
 
 	if (*pos == 0)
@@ -200,7 +204,7 @@
 		if (!cpu_possible(cpu))
 			continue;
 		*pos = cpu + 1;
-		return &per_cpu(nf_conntrack_stat, cpu);
+		return per_cpu_ptr(net->ct.stat, cpu);
 	}
 
 	return NULL;
@@ -208,13 +212,14 @@
 
 static void *ct_cpu_seq_next(struct seq_file *seq, void *v, loff_t *pos)
 {
+	struct net *net = seq_file_net(seq);
 	int cpu;
 
 	for (cpu = *pos; cpu < NR_CPUS; ++cpu) {
 		if (!cpu_possible(cpu))
 			continue;
 		*pos = cpu + 1;
-		return &per_cpu(nf_conntrack_stat, cpu);
+		return per_cpu_ptr(net->ct.stat, cpu);
 	}
 
 	return NULL;
@@ -226,7 +231,8 @@
 
 static int ct_cpu_seq_show(struct seq_file *seq, void *v)
 {
-	unsigned int nr_conntracks = atomic_read(&nf_conntrack_count);
+	struct net *net = seq_file_net(seq);
+	unsigned int nr_conntracks = atomic_read(&net->ct.count);
 	const struct ip_conntrack_stat *st = v;
 
 	if (v == SEQ_START_TOKEN) {
@@ -266,7 +272,8 @@
 
 static int ct_cpu_seq_open(struct inode *inode, struct file *file)
 {
-	return seq_open(file, &ct_cpu_seq_ops);
+	return seq_open_net(inode, file, &ct_cpu_seq_ops,
+			    sizeof(struct seq_net_private));
 }
 
 static const struct file_operations ct_cpu_seq_fops = {
@@ -274,56 +281,52 @@
 	.open	 = ct_cpu_seq_open,
 	.read	 = seq_read,
 	.llseek	 = seq_lseek,
-	.release = seq_release,
+	.release = seq_release_net,
 };
 
-static int nf_conntrack_standalone_init_proc(void)
+static int nf_conntrack_standalone_init_proc(struct net *net)
 {
 	struct proc_dir_entry *pde;
 
-	pde = proc_net_fops_create(&init_net, "nf_conntrack", 0440, &ct_file_ops);
+	pde = proc_net_fops_create(net, "nf_conntrack", 0440, &ct_file_ops);
 	if (!pde)
 		goto out_nf_conntrack;
 
-	pde = proc_create("nf_conntrack", S_IRUGO, init_net.proc_net_stat,
+	pde = proc_create("nf_conntrack", S_IRUGO, net->proc_net_stat,
 			  &ct_cpu_seq_fops);
 	if (!pde)
 		goto out_stat_nf_conntrack;
 	return 0;
 
 out_stat_nf_conntrack:
-	proc_net_remove(&init_net, "nf_conntrack");
+	proc_net_remove(net, "nf_conntrack");
 out_nf_conntrack:
 	return -ENOMEM;
 }
 
-static void nf_conntrack_standalone_fini_proc(void)
+static void nf_conntrack_standalone_fini_proc(struct net *net)
 {
-	remove_proc_entry("nf_conntrack", init_net.proc_net_stat);
-	proc_net_remove(&init_net, "nf_conntrack");
+	remove_proc_entry("nf_conntrack", net->proc_net_stat);
+	proc_net_remove(net, "nf_conntrack");
 }
 #else
-static int nf_conntrack_standalone_init_proc(void)
+static int nf_conntrack_standalone_init_proc(struct net *net)
 {
 	return 0;
 }
 
-static void nf_conntrack_standalone_fini_proc(void)
+static void nf_conntrack_standalone_fini_proc(struct net *net)
 {
 }
 #endif /* CONFIG_PROC_FS */
 
 /* Sysctl support */
 
-int nf_conntrack_checksum __read_mostly = 1;
-EXPORT_SYMBOL_GPL(nf_conntrack_checksum);
-
 #ifdef CONFIG_SYSCTL
 /* Log invalid packets of a given protocol */
 static int log_invalid_proto_min = 0;
 static int log_invalid_proto_max = 255;
 
-static struct ctl_table_header *nf_ct_sysctl_header;
 static struct ctl_table_header *nf_ct_netfilter_header;
 
 static ctl_table nf_ct_sysctl_table[] = {
@@ -338,7 +341,7 @@
 	{
 		.ctl_name	= NET_NF_CONNTRACK_COUNT,
 		.procname	= "nf_conntrack_count",
-		.data		= &nf_conntrack_count,
+		.data		= &init_net.ct.count,
 		.maxlen		= sizeof(int),
 		.mode		= 0444,
 		.proc_handler	= &proc_dointvec,
@@ -354,7 +357,7 @@
 	{
 		.ctl_name	= NET_NF_CONNTRACK_CHECKSUM,
 		.procname	= "nf_conntrack_checksum",
-		.data		= &nf_conntrack_checksum,
+		.data		= &init_net.ct.sysctl_checksum,
 		.maxlen		= sizeof(unsigned int),
 		.mode		= 0644,
 		.proc_handler	= &proc_dointvec,
@@ -362,7 +365,7 @@
 	{
 		.ctl_name	= NET_NF_CONNTRACK_LOG_INVALID,
 		.procname	= "nf_conntrack_log_invalid",
-		.data		= &nf_ct_log_invalid,
+		.data		= &init_net.ct.sysctl_log_invalid,
 		.maxlen		= sizeof(unsigned int),
 		.mode		= 0644,
 		.proc_handler	= &proc_dointvec_minmax,
@@ -400,74 +403,109 @@
 	{ }
 };
 
-EXPORT_SYMBOL_GPL(nf_ct_log_invalid);
-
-static int nf_conntrack_standalone_init_sysctl(void)
+static int nf_conntrack_standalone_init_sysctl(struct net *net)
 {
-	nf_ct_netfilter_header =
-		register_sysctl_paths(nf_ct_path, nf_ct_netfilter_table);
-	if (!nf_ct_netfilter_header)
-		goto out;
+	struct ctl_table *table;
 
-	nf_ct_sysctl_header =
-		 register_sysctl_paths(nf_net_netfilter_sysctl_path,
-					nf_ct_sysctl_table);
-	if (!nf_ct_sysctl_header)
+	if (net_eq(net, &init_net)) {
+		nf_ct_netfilter_header =
+		       register_sysctl_paths(nf_ct_path, nf_ct_netfilter_table);
+		if (!nf_ct_netfilter_header)
+			goto out;
+	}
+
+	table = kmemdup(nf_ct_sysctl_table, sizeof(nf_ct_sysctl_table),
+			GFP_KERNEL);
+	if (!table)
+		goto out_kmemdup;
+
+	table[1].data = &net->ct.count;
+	table[3].data = &net->ct.sysctl_checksum;
+	table[4].data = &net->ct.sysctl_log_invalid;
+
+	net->ct.sysctl_header = register_net_sysctl_table(net,
+					nf_net_netfilter_sysctl_path, table);
+	if (!net->ct.sysctl_header)
 		goto out_unregister_netfilter;
 
 	return 0;
 
 out_unregister_netfilter:
-	unregister_sysctl_table(nf_ct_netfilter_header);
+	kfree(table);
+out_kmemdup:
+	if (net_eq(net, &init_net))
+		unregister_sysctl_table(nf_ct_netfilter_header);
 out:
 	printk("nf_conntrack: can't register to sysctl.\n");
 	return -ENOMEM;
 }
 
-static void nf_conntrack_standalone_fini_sysctl(void)
+static void nf_conntrack_standalone_fini_sysctl(struct net *net)
 {
-	unregister_sysctl_table(nf_ct_netfilter_header);
-	unregister_sysctl_table(nf_ct_sysctl_header);
+	struct ctl_table *table;
+
+	if (net_eq(net, &init_net))
+		unregister_sysctl_table(nf_ct_netfilter_header);
+	table = net->ct.sysctl_header->ctl_table_arg;
+	unregister_net_sysctl_table(net->ct.sysctl_header);
+	kfree(table);
 }
 #else
-static int nf_conntrack_standalone_init_sysctl(void)
+static int nf_conntrack_standalone_init_sysctl(struct net *net)
 {
 	return 0;
 }
 
-static void nf_conntrack_standalone_fini_sysctl(void)
+static void nf_conntrack_standalone_fini_sysctl(struct net *net)
 {
 }
 #endif /* CONFIG_SYSCTL */
 
-static int __init nf_conntrack_standalone_init(void)
+static int nf_conntrack_net_init(struct net *net)
 {
 	int ret;
 
-	ret = nf_conntrack_init();
+	ret = nf_conntrack_init(net);
 	if (ret < 0)
-		goto out;
-	ret = nf_conntrack_standalone_init_proc();
+		goto out_init;
+	ret = nf_conntrack_standalone_init_proc(net);
 	if (ret < 0)
 		goto out_proc;
-	ret = nf_conntrack_standalone_init_sysctl();
+	net->ct.sysctl_checksum = 1;
+	net->ct.sysctl_log_invalid = 0;
+	ret = nf_conntrack_standalone_init_sysctl(net);
 	if (ret < 0)
 		goto out_sysctl;
 	return 0;
 
 out_sysctl:
-	nf_conntrack_standalone_fini_proc();
+	nf_conntrack_standalone_fini_proc(net);
 out_proc:
-	nf_conntrack_cleanup();
-out:
+	nf_conntrack_cleanup(net);
+out_init:
 	return ret;
 }
 
+static void nf_conntrack_net_exit(struct net *net)
+{
+	nf_conntrack_standalone_fini_sysctl(net);
+	nf_conntrack_standalone_fini_proc(net);
+	nf_conntrack_cleanup(net);
+}
+
+static struct pernet_operations nf_conntrack_net_ops = {
+	.init = nf_conntrack_net_init,
+	.exit = nf_conntrack_net_exit,
+};
+
+static int __init nf_conntrack_standalone_init(void)
+{
+	return register_pernet_subsys(&nf_conntrack_net_ops);
+}
+
 static void __exit nf_conntrack_standalone_fini(void)
 {
-	nf_conntrack_standalone_fini_sysctl();
-	nf_conntrack_standalone_fini_proc();
-	nf_conntrack_cleanup();
+	unregister_pernet_subsys(&nf_conntrack_net_ops);
 }
 
 module_init(nf_conntrack_standalone_init);
diff --git a/net/netfilter/nf_internals.h b/net/netfilter/nf_internals.h
index 196269c..bf66099 100644
--- a/net/netfilter/nf_internals.h
+++ b/net/netfilter/nf_internals.h
@@ -15,7 +15,7 @@
 /* core.c */
 extern unsigned int nf_iterate(struct list_head *head,
 				struct sk_buff *skb,
-				int hook,
+				unsigned int hook,
 				const struct net_device *indev,
 				const struct net_device *outdev,
 				struct list_head **i,
@@ -25,7 +25,7 @@
 /* nf_queue.c */
 extern int nf_queue(struct sk_buff *skb,
 		    struct list_head *elem,
-		    int pf, unsigned int hook,
+		    u_int8_t pf, unsigned int hook,
 		    struct net_device *indev,
 		    struct net_device *outdev,
 		    int (*okfn)(struct sk_buff *),
diff --git a/net/netfilter/nf_log.c b/net/netfilter/nf_log.c
index 9fda6ee..fa8ae5d 100644
--- a/net/netfilter/nf_log.c
+++ b/net/netfilter/nf_log.c
@@ -15,16 +15,16 @@
 
 #define NF_LOG_PREFIXLEN		128
 
-static const struct nf_logger *nf_loggers[NPROTO] __read_mostly;
+static const struct nf_logger *nf_loggers[NFPROTO_NUMPROTO] __read_mostly;
 static DEFINE_MUTEX(nf_log_mutex);
 
 /* return EBUSY if somebody else is registered, EEXIST if the same logger
  * is registred, 0 on success. */
-int nf_log_register(int pf, const struct nf_logger *logger)
+int nf_log_register(u_int8_t pf, const struct nf_logger *logger)
 {
 	int ret;
 
-	if (pf >= NPROTO)
+	if (pf >= ARRAY_SIZE(nf_loggers))
 		return -EINVAL;
 
 	/* Any setup of logging members must be done before
@@ -45,9 +45,9 @@
 }
 EXPORT_SYMBOL(nf_log_register);
 
-void nf_log_unregister_pf(int pf)
+void nf_log_unregister_pf(u_int8_t pf)
 {
-	if (pf >= NPROTO)
+	if (pf >= ARRAY_SIZE(nf_loggers))
 		return;
 	mutex_lock(&nf_log_mutex);
 	rcu_assign_pointer(nf_loggers[pf], NULL);
@@ -63,7 +63,7 @@
 	int i;
 
 	mutex_lock(&nf_log_mutex);
-	for (i = 0; i < NPROTO; i++) {
+	for (i = 0; i < ARRAY_SIZE(nf_loggers); i++) {
 		if (nf_loggers[i] == logger)
 			rcu_assign_pointer(nf_loggers[i], NULL);
 	}
@@ -73,7 +73,7 @@
 }
 EXPORT_SYMBOL(nf_log_unregister);
 
-void nf_log_packet(int pf,
+void nf_log_packet(u_int8_t pf,
 		   unsigned int hooknum,
 		   const struct sk_buff *skb,
 		   const struct net_device *in,
@@ -103,7 +103,7 @@
 {
 	rcu_read_lock();
 
-	if (*pos >= NPROTO)
+	if (*pos >= ARRAY_SIZE(nf_loggers))
 		return NULL;
 
 	return pos;
@@ -113,7 +113,7 @@
 {
 	(*pos)++;
 
-	if (*pos >= NPROTO)
+	if (*pos >= ARRAY_SIZE(nf_loggers))
 		return NULL;
 
 	return pos;
diff --git a/net/netfilter/nf_queue.c b/net/netfilter/nf_queue.c
index 582ec3e..4f2310c 100644
--- a/net/netfilter/nf_queue.c
+++ b/net/netfilter/nf_queue.c
@@ -16,17 +16,17 @@
  * long term mutex.  The handler must provide an an outfn() to accept packets
  * for queueing and must reinject all packets it receives, no matter what.
  */
-static const struct nf_queue_handler *queue_handler[NPROTO];
+static const struct nf_queue_handler *queue_handler[NFPROTO_NUMPROTO] __read_mostly;
 
 static DEFINE_MUTEX(queue_handler_mutex);
 
 /* return EBUSY when somebody else is registered, return EEXIST if the
  * same handler is registered, return 0 in case of success. */
-int nf_register_queue_handler(int pf, const struct nf_queue_handler *qh)
+int nf_register_queue_handler(u_int8_t pf, const struct nf_queue_handler *qh)
 {
 	int ret;
 
-	if (pf >= NPROTO)
+	if (pf >= ARRAY_SIZE(queue_handler))
 		return -EINVAL;
 
 	mutex_lock(&queue_handler_mutex);
@@ -45,9 +45,9 @@
 EXPORT_SYMBOL(nf_register_queue_handler);
 
 /* The caller must flush their queue before this */
-int nf_unregister_queue_handler(int pf, const struct nf_queue_handler *qh)
+int nf_unregister_queue_handler(u_int8_t pf, const struct nf_queue_handler *qh)
 {
-	if (pf >= NPROTO)
+	if (pf >= ARRAY_SIZE(queue_handler))
 		return -EINVAL;
 
 	mutex_lock(&queue_handler_mutex);
@@ -67,10 +67,10 @@
 
 void nf_unregister_queue_handlers(const struct nf_queue_handler *qh)
 {
-	int pf;
+	u_int8_t pf;
 
 	mutex_lock(&queue_handler_mutex);
-	for (pf = 0; pf < NPROTO; pf++)  {
+	for (pf = 0; pf < ARRAY_SIZE(queue_handler); pf++)  {
 		if (queue_handler[pf] == qh)
 			rcu_assign_pointer(queue_handler[pf], NULL);
 	}
@@ -107,7 +107,7 @@
  */
 static int __nf_queue(struct sk_buff *skb,
 		      struct list_head *elem,
-		      int pf, unsigned int hook,
+		      u_int8_t pf, unsigned int hook,
 		      struct net_device *indev,
 		      struct net_device *outdev,
 		      int (*okfn)(struct sk_buff *),
@@ -191,7 +191,7 @@
 
 int nf_queue(struct sk_buff *skb,
 	     struct list_head *elem,
-	     int pf, unsigned int hook,
+	     u_int8_t pf, unsigned int hook,
 	     struct net_device *indev,
 	     struct net_device *outdev,
 	     int (*okfn)(struct sk_buff *),
@@ -285,7 +285,7 @@
 #ifdef CONFIG_PROC_FS
 static void *seq_start(struct seq_file *seq, loff_t *pos)
 {
-	if (*pos >= NPROTO)
+	if (*pos >= ARRAY_SIZE(queue_handler))
 		return NULL;
 
 	return pos;
@@ -295,7 +295,7 @@
 {
 	(*pos)++;
 
-	if (*pos >= NPROTO)
+	if (*pos >= ARRAY_SIZE(queue_handler))
 		return NULL;
 
 	return pos;
diff --git a/net/netfilter/nf_sockopt.c b/net/netfilter/nf_sockopt.c
index 0148968..8ab829f 100644
--- a/net/netfilter/nf_sockopt.c
+++ b/net/netfilter/nf_sockopt.c
@@ -60,14 +60,11 @@
 }
 EXPORT_SYMBOL(nf_unregister_sockopt);
 
-static struct nf_sockopt_ops *nf_sockopt_find(struct sock *sk, int pf,
+static struct nf_sockopt_ops *nf_sockopt_find(struct sock *sk, u_int8_t pf,
 		int val, int get)
 {
 	struct nf_sockopt_ops *ops;
 
-	if (!net_eq(sock_net(sk), &init_net))
-		return ERR_PTR(-ENOPROTOOPT);
-
 	if (mutex_lock_interruptible(&nf_sockopt_mutex) != 0)
 		return ERR_PTR(-EINTR);
 
@@ -96,7 +93,7 @@
 }
 
 /* Call get/setsockopt() */
-static int nf_sockopt(struct sock *sk, int pf, int val,
+static int nf_sockopt(struct sock *sk, u_int8_t pf, int val,
 		      char __user *opt, int *len, int get)
 {
 	struct nf_sockopt_ops *ops;
@@ -115,21 +112,22 @@
 	return ret;
 }
 
-int nf_setsockopt(struct sock *sk, int pf, int val, char __user *opt,
+int nf_setsockopt(struct sock *sk, u_int8_t pf, int val, char __user *opt,
 		  int len)
 {
 	return nf_sockopt(sk, pf, val, opt, &len, 0);
 }
 EXPORT_SYMBOL(nf_setsockopt);
 
-int nf_getsockopt(struct sock *sk, int pf, int val, char __user *opt, int *len)
+int nf_getsockopt(struct sock *sk, u_int8_t pf, int val, char __user *opt,
+		  int *len)
 {
 	return nf_sockopt(sk, pf, val, opt, len, 1);
 }
 EXPORT_SYMBOL(nf_getsockopt);
 
 #ifdef CONFIG_COMPAT
-static int compat_nf_sockopt(struct sock *sk, int pf, int val,
+static int compat_nf_sockopt(struct sock *sk, u_int8_t pf, int val,
 			     char __user *opt, int *len, int get)
 {
 	struct nf_sockopt_ops *ops;
@@ -155,14 +153,14 @@
 	return ret;
 }
 
-int compat_nf_setsockopt(struct sock *sk, int pf,
+int compat_nf_setsockopt(struct sock *sk, u_int8_t pf,
 		int val, char __user *opt, int len)
 {
 	return compat_nf_sockopt(sk, pf, val, opt, &len, 0);
 }
 EXPORT_SYMBOL(compat_nf_setsockopt);
 
-int compat_nf_getsockopt(struct sock *sk, int pf,
+int compat_nf_getsockopt(struct sock *sk, u_int8_t pf,
 		int val, char __user *opt, int *len)
 {
 	return compat_nf_sockopt(sk, pf, val, opt, len, 1);
diff --git a/net/netfilter/nf_tproxy_core.c b/net/netfilter/nf_tproxy_core.c
new file mode 100644
index 0000000..cdc97f3
--- /dev/null
+++ b/net/netfilter/nf_tproxy_core.c
@@ -0,0 +1,95 @@
+/*
+ * Transparent proxy support for Linux/iptables
+ *
+ * Copyright (c) 2006-2007 BalaBit IT Ltd.
+ * Author: Balazs Scheidler, Krisztian Kovacs
+ *
+ * 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/net.h>
+#include <linux/if.h>
+#include <linux/netdevice.h>
+#include <net/udp.h>
+#include <net/netfilter/nf_tproxy_core.h>
+
+struct sock *
+nf_tproxy_get_sock_v4(struct net *net, const u8 protocol,
+		      const __be32 saddr, const __be32 daddr,
+		      const __be16 sport, const __be16 dport,
+		      const struct net_device *in, bool listening_only)
+{
+	struct sock *sk;
+
+	/* look up socket */
+	switch (protocol) {
+	case IPPROTO_TCP:
+		if (listening_only)
+			sk = __inet_lookup_listener(net, &tcp_hashinfo,
+						    daddr, ntohs(dport),
+						    in->ifindex);
+		else
+			sk = __inet_lookup(net, &tcp_hashinfo,
+					   saddr, sport, daddr, dport,
+					   in->ifindex);
+		break;
+	case IPPROTO_UDP:
+		sk = udp4_lib_lookup(net, saddr, sport, daddr, dport,
+				     in->ifindex);
+		break;
+	default:
+		WARN_ON(1);
+		sk = NULL;
+	}
+
+	pr_debug("tproxy socket lookup: proto %u %08x:%u -> %08x:%u, listener only: %d, sock %p\n",
+		 protocol, ntohl(saddr), ntohs(sport), ntohl(daddr), ntohs(dport), listening_only, sk);
+
+	return sk;
+}
+EXPORT_SYMBOL_GPL(nf_tproxy_get_sock_v4);
+
+static void
+nf_tproxy_destructor(struct sk_buff *skb)
+{
+	struct sock *sk = skb->sk;
+
+	skb->sk = NULL;
+	skb->destructor = NULL;
+
+	if (sk)
+		nf_tproxy_put_sock(sk);
+}
+
+/* consumes sk */
+int
+nf_tproxy_assign_sock(struct sk_buff *skb, struct sock *sk)
+{
+	if (inet_sk(sk)->transparent) {
+		skb->sk = sk;
+		skb->destructor = nf_tproxy_destructor;
+		return 1;
+	} else
+		nf_tproxy_put_sock(sk);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(nf_tproxy_assign_sock);
+
+static int __init nf_tproxy_init(void)
+{
+	pr_info("NF_TPROXY: Transparent proxy support initialized, version 4.1.0\n");
+	pr_info("NF_TPROXY: Copyright (c) 2006-2007 BalaBit IT Ltd.\n");
+	return 0;
+}
+
+module_init(nf_tproxy_init);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Krisztian Kovacs");
+MODULE_DESCRIPTION("Transparent proxy support core routines");
diff --git a/net/netfilter/nfnetlink_log.c b/net/netfilter/nfnetlink_log.c
index 9a35b57..41e0105 100644
--- a/net/netfilter/nfnetlink_log.c
+++ b/net/netfilter/nfnetlink_log.c
@@ -359,7 +359,7 @@
 __build_packet_message(struct nfulnl_instance *inst,
 			const struct sk_buff *skb,
 			unsigned int data_len,
-			unsigned int pf,
+			u_int8_t pf,
 			unsigned int hooknum,
 			const struct net_device *indev,
 			const struct net_device *outdev,
@@ -534,7 +534,7 @@
 
 /* log handler for internal netfilter logging api */
 static void
-nfulnl_log_packet(unsigned int pf,
+nfulnl_log_packet(u_int8_t pf,
 		  unsigned int hooknum,
 		  const struct sk_buff *skb,
 		  const struct net_device *in,
diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c
index 5d75cd8..89837a4 100644
--- a/net/netfilter/x_tables.c
+++ b/net/netfilter/x_tables.c
@@ -30,7 +30,7 @@
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
-MODULE_DESCRIPTION("[ip,ip6,arp]_tables backend module");
+MODULE_DESCRIPTION("{ip,ip6,arp,eb}_tables backend module");
 
 #define SMP_ALIGN(x) (((x) + SMP_CACHE_BYTES-1) & ~(SMP_CACHE_BYTES-1))
 
@@ -58,17 +58,20 @@
 #define duprintf(format, args...)
 #endif
 
-static const char *const xt_prefix[NPROTO] = {
-	[AF_INET]	= "ip",
-	[AF_INET6]	= "ip6",
-	[NF_ARP]	= "arp",
+static const char *const xt_prefix[NFPROTO_NUMPROTO] = {
+	[NFPROTO_UNSPEC] = "x",
+	[NFPROTO_IPV4]   = "ip",
+	[NFPROTO_ARP]    = "arp",
+	[NFPROTO_BRIDGE] = "eb",
+	[NFPROTO_IPV6]   = "ip6",
 };
 
 /* Registration hooks for targets. */
 int
 xt_register_target(struct xt_target *target)
 {
-	int ret, af = target->family;
+	u_int8_t af = target->family;
+	int ret;
 
 	ret = mutex_lock_interruptible(&xt[af].mutex);
 	if (ret != 0)
@@ -82,7 +85,7 @@
 void
 xt_unregister_target(struct xt_target *target)
 {
-	int af = target->family;
+	u_int8_t af = target->family;
 
 	mutex_lock(&xt[af].mutex);
 	list_del(&target->list);
@@ -123,7 +126,8 @@
 int
 xt_register_match(struct xt_match *match)
 {
-	int ret, af = match->family;
+	u_int8_t af = match->family;
+	int ret;
 
 	ret = mutex_lock_interruptible(&xt[af].mutex);
 	if (ret != 0)
@@ -139,7 +143,7 @@
 void
 xt_unregister_match(struct xt_match *match)
 {
-	int af =  match->family;
+	u_int8_t af = match->family;
 
 	mutex_lock(&xt[af].mutex);
 	list_del(&match->list);
@@ -185,7 +189,7 @@
  */
 
 /* Find match, grabs ref.  Returns ERR_PTR() on error. */
-struct xt_match *xt_find_match(int af, const char *name, u8 revision)
+struct xt_match *xt_find_match(u8 af, const char *name, u8 revision)
 {
 	struct xt_match *m;
 	int err = 0;
@@ -205,12 +209,17 @@
 		}
 	}
 	mutex_unlock(&xt[af].mutex);
+
+	if (af != NFPROTO_UNSPEC)
+		/* Try searching again in the family-independent list */
+		return xt_find_match(NFPROTO_UNSPEC, name, revision);
+
 	return ERR_PTR(err);
 }
 EXPORT_SYMBOL(xt_find_match);
 
 /* Find target, grabs ref.  Returns ERR_PTR() on error. */
-struct xt_target *xt_find_target(int af, const char *name, u8 revision)
+struct xt_target *xt_find_target(u8 af, const char *name, u8 revision)
 {
 	struct xt_target *t;
 	int err = 0;
@@ -230,11 +239,16 @@
 		}
 	}
 	mutex_unlock(&xt[af].mutex);
+
+	if (af != NFPROTO_UNSPEC)
+		/* Try searching again in the family-independent list */
+		return xt_find_target(NFPROTO_UNSPEC, name, revision);
+
 	return ERR_PTR(err);
 }
 EXPORT_SYMBOL(xt_find_target);
 
-struct xt_target *xt_request_find_target(int af, const char *name, u8 revision)
+struct xt_target *xt_request_find_target(u8 af, const char *name, u8 revision)
 {
 	struct xt_target *target;
 
@@ -246,7 +260,7 @@
 }
 EXPORT_SYMBOL_GPL(xt_request_find_target);
 
-static int match_revfn(int af, const char *name, u8 revision, int *bestp)
+static int match_revfn(u8 af, const char *name, u8 revision, int *bestp)
 {
 	const struct xt_match *m;
 	int have_rev = 0;
@@ -262,7 +276,7 @@
 	return have_rev;
 }
 
-static int target_revfn(int af, const char *name, u8 revision, int *bestp)
+static int target_revfn(u8 af, const char *name, u8 revision, int *bestp)
 {
 	const struct xt_target *t;
 	int have_rev = 0;
@@ -279,7 +293,7 @@
 }
 
 /* Returns true or false (if no such extension at all) */
-int xt_find_revision(int af, const char *name, u8 revision, int target,
+int xt_find_revision(u8 af, const char *name, u8 revision, int target,
 		     int *err)
 {
 	int have_rev, best = -1;
@@ -307,37 +321,47 @@
 }
 EXPORT_SYMBOL_GPL(xt_find_revision);
 
-int xt_check_match(const struct xt_match *match, unsigned short family,
-		   unsigned int size, const char *table, unsigned int hook_mask,
-		   unsigned short proto, int inv_proto)
+int xt_check_match(struct xt_mtchk_param *par,
+		   unsigned int size, u_int8_t proto, bool inv_proto)
 {
-	if (XT_ALIGN(match->matchsize) != size) {
+	if (XT_ALIGN(par->match->matchsize) != size &&
+	    par->match->matchsize != -1) {
+		/*
+		 * ebt_among is exempt from centralized matchsize checking
+		 * because it uses a dynamic-size data set.
+		 */
 		printk("%s_tables: %s match: invalid size %Zu != %u\n",
-		       xt_prefix[family], match->name,
-		       XT_ALIGN(match->matchsize), size);
+		       xt_prefix[par->family], par->match->name,
+		       XT_ALIGN(par->match->matchsize), size);
 		return -EINVAL;
 	}
-	if (match->table && strcmp(match->table, table)) {
+	if (par->match->table != NULL &&
+	    strcmp(par->match->table, par->table) != 0) {
 		printk("%s_tables: %s match: only valid in %s table, not %s\n",
-		       xt_prefix[family], match->name, match->table, table);
+		       xt_prefix[par->family], par->match->name,
+		       par->match->table, par->table);
 		return -EINVAL;
 	}
-	if (match->hooks && (hook_mask & ~match->hooks) != 0) {
-		printk("%s_tables: %s match: bad hook_mask %u/%u\n",
-		       xt_prefix[family], match->name, hook_mask, match->hooks);
+	if (par->match->hooks && (par->hook_mask & ~par->match->hooks) != 0) {
+		printk("%s_tables: %s match: bad hook_mask %#x/%#x\n",
+		       xt_prefix[par->family], par->match->name,
+		       par->hook_mask, par->match->hooks);
 		return -EINVAL;
 	}
-	if (match->proto && (match->proto != proto || inv_proto)) {
+	if (par->match->proto && (par->match->proto != proto || inv_proto)) {
 		printk("%s_tables: %s match: only valid for protocol %u\n",
-		       xt_prefix[family], match->name, match->proto);
+		       xt_prefix[par->family], par->match->name,
+		       par->match->proto);
 		return -EINVAL;
 	}
+	if (par->match->checkentry != NULL && !par->match->checkentry(par))
+		return -EINVAL;
 	return 0;
 }
 EXPORT_SYMBOL_GPL(xt_check_match);
 
 #ifdef CONFIG_COMPAT
-int xt_compat_add_offset(int af, unsigned int offset, short delta)
+int xt_compat_add_offset(u_int8_t af, unsigned int offset, short delta)
 {
 	struct compat_delta *tmp;
 
@@ -359,7 +383,7 @@
 }
 EXPORT_SYMBOL_GPL(xt_compat_add_offset);
 
-void xt_compat_flush_offsets(int af)
+void xt_compat_flush_offsets(u_int8_t af)
 {
 	struct compat_delta *tmp, *next;
 
@@ -373,7 +397,7 @@
 }
 EXPORT_SYMBOL_GPL(xt_compat_flush_offsets);
 
-short xt_compat_calc_jump(int af, unsigned int offset)
+short xt_compat_calc_jump(u_int8_t af, unsigned int offset)
 {
 	struct compat_delta *tmp;
 	short delta;
@@ -448,32 +472,36 @@
 EXPORT_SYMBOL_GPL(xt_compat_match_to_user);
 #endif /* CONFIG_COMPAT */
 
-int xt_check_target(const struct xt_target *target, unsigned short family,
-		    unsigned int size, const char *table, unsigned int hook_mask,
-		    unsigned short proto, int inv_proto)
+int xt_check_target(struct xt_tgchk_param *par,
+		    unsigned int size, u_int8_t proto, bool inv_proto)
 {
-	if (XT_ALIGN(target->targetsize) != size) {
+	if (XT_ALIGN(par->target->targetsize) != size) {
 		printk("%s_tables: %s target: invalid size %Zu != %u\n",
-		       xt_prefix[family], target->name,
-		       XT_ALIGN(target->targetsize), size);
+		       xt_prefix[par->family], par->target->name,
+		       XT_ALIGN(par->target->targetsize), size);
 		return -EINVAL;
 	}
-	if (target->table && strcmp(target->table, table)) {
+	if (par->target->table != NULL &&
+	    strcmp(par->target->table, par->table) != 0) {
 		printk("%s_tables: %s target: only valid in %s table, not %s\n",
-		       xt_prefix[family], target->name, target->table, table);
+		       xt_prefix[par->family], par->target->name,
+		       par->target->table, par->table);
 		return -EINVAL;
 	}
-	if (target->hooks && (hook_mask & ~target->hooks) != 0) {
-		printk("%s_tables: %s target: bad hook_mask %u/%u\n",
-		       xt_prefix[family], target->name, hook_mask,
-		       target->hooks);
+	if (par->target->hooks && (par->hook_mask & ~par->target->hooks) != 0) {
+		printk("%s_tables: %s target: bad hook_mask %#x/%#x\n",
+		       xt_prefix[par->family], par->target->name,
+		       par->hook_mask, par->target->hooks);
 		return -EINVAL;
 	}
-	if (target->proto && (target->proto != proto || inv_proto)) {
+	if (par->target->proto && (par->target->proto != proto || inv_proto)) {
 		printk("%s_tables: %s target: only valid for protocol %u\n",
-		       xt_prefix[family], target->name, target->proto);
+		       xt_prefix[par->family], par->target->name,
+		       par->target->proto);
 		return -EINVAL;
 	}
+	if (par->target->checkentry != NULL && !par->target->checkentry(par))
+		return -EINVAL;
 	return 0;
 }
 EXPORT_SYMBOL_GPL(xt_check_target);
@@ -590,7 +618,8 @@
 EXPORT_SYMBOL(xt_free_table_info);
 
 /* Find table by name, grabs mutex & ref.  Returns ERR_PTR() on error. */
-struct xt_table *xt_find_table_lock(struct net *net, int af, const char *name)
+struct xt_table *xt_find_table_lock(struct net *net, u_int8_t af,
+				    const char *name)
 {
 	struct xt_table *t;
 
@@ -612,13 +641,13 @@
 EXPORT_SYMBOL_GPL(xt_table_unlock);
 
 #ifdef CONFIG_COMPAT
-void xt_compat_lock(int af)
+void xt_compat_lock(u_int8_t af)
 {
 	mutex_lock(&xt[af].compat_mutex);
 }
 EXPORT_SYMBOL_GPL(xt_compat_lock);
 
-void xt_compat_unlock(int af)
+void xt_compat_unlock(u_int8_t af)
 {
 	mutex_unlock(&xt[af].compat_mutex);
 }
@@ -722,13 +751,13 @@
 #ifdef CONFIG_PROC_FS
 struct xt_names_priv {
 	struct seq_net_private p;
-	int af;
+	u_int8_t af;
 };
 static void *xt_table_seq_start(struct seq_file *seq, loff_t *pos)
 {
 	struct xt_names_priv *priv = seq->private;
 	struct net *net = seq_file_net(seq);
-	int af = priv->af;
+	u_int8_t af = priv->af;
 
 	mutex_lock(&xt[af].mutex);
 	return seq_list_start(&net->xt.tables[af], *pos);
@@ -738,7 +767,7 @@
 {
 	struct xt_names_priv *priv = seq->private;
 	struct net *net = seq_file_net(seq);
-	int af = priv->af;
+	u_int8_t af = priv->af;
 
 	return seq_list_next(v, &net->xt.tables[af], pos);
 }
@@ -746,7 +775,7 @@
 static void xt_table_seq_stop(struct seq_file *seq, void *v)
 {
 	struct xt_names_priv *priv = seq->private;
-	int af = priv->af;
+	u_int8_t af = priv->af;
 
 	mutex_unlock(&xt[af].mutex);
 }
@@ -922,14 +951,14 @@
 
 #endif /* CONFIG_PROC_FS */
 
-int xt_proto_init(struct net *net, int af)
+int xt_proto_init(struct net *net, u_int8_t af)
 {
 #ifdef CONFIG_PROC_FS
 	char buf[XT_FUNCTION_MAXNAMELEN];
 	struct proc_dir_entry *proc;
 #endif
 
-	if (af >= NPROTO)
+	if (af >= ARRAY_SIZE(xt_prefix))
 		return -EINVAL;
 
 
@@ -974,7 +1003,7 @@
 }
 EXPORT_SYMBOL_GPL(xt_proto_init);
 
-void xt_proto_fini(struct net *net, int af)
+void xt_proto_fini(struct net *net, u_int8_t af)
 {
 #ifdef CONFIG_PROC_FS
 	char buf[XT_FUNCTION_MAXNAMELEN];
@@ -998,7 +1027,7 @@
 {
 	int i;
 
-	for (i = 0; i < NPROTO; i++)
+	for (i = 0; i < NFPROTO_NUMPROTO; i++)
 		INIT_LIST_HEAD(&net->xt.tables[i]);
 	return 0;
 }
@@ -1011,11 +1040,11 @@
 {
 	int i, rv;
 
-	xt = kmalloc(sizeof(struct xt_af) * NPROTO, GFP_KERNEL);
+	xt = kmalloc(sizeof(struct xt_af) * NFPROTO_NUMPROTO, GFP_KERNEL);
 	if (!xt)
 		return -ENOMEM;
 
-	for (i = 0; i < NPROTO; i++) {
+	for (i = 0; i < NFPROTO_NUMPROTO; i++) {
 		mutex_init(&xt[i].mutex);
 #ifdef CONFIG_COMPAT
 		mutex_init(&xt[i].compat_mutex);
diff --git a/net/netfilter/xt_CLASSIFY.c b/net/netfilter/xt_CLASSIFY.c
index 77a52bf..011bc80 100644
--- a/net/netfilter/xt_CLASSIFY.c
+++ b/net/netfilter/xt_CLASSIFY.c
@@ -27,50 +27,34 @@
 MODULE_ALIAS("ip6t_CLASSIFY");
 
 static unsigned int
-classify_tg(struct sk_buff *skb, const struct net_device *in,
-            const struct net_device *out, unsigned int hooknum,
-            const struct xt_target *target, const void *targinfo)
+classify_tg(struct sk_buff *skb, const struct xt_target_param *par)
 {
-	const struct xt_classify_target_info *clinfo = targinfo;
+	const struct xt_classify_target_info *clinfo = par->targinfo;
 
 	skb->priority = clinfo->priority;
 	return XT_CONTINUE;
 }
 
-static struct xt_target classify_tg_reg[] __read_mostly = {
-	{
-		.family		= AF_INET,
-		.name 		= "CLASSIFY",
-		.target 	= classify_tg,
-		.targetsize	= sizeof(struct xt_classify_target_info),
-		.table		= "mangle",
-		.hooks		= (1 << NF_INET_LOCAL_OUT) |
-				  (1 << NF_INET_FORWARD) |
-				  (1 << NF_INET_POST_ROUTING),
-		.me 		= THIS_MODULE,
-	},
-	{
-		.name 		= "CLASSIFY",
-		.family		= AF_INET6,
-		.target 	= classify_tg,
-		.targetsize	= sizeof(struct xt_classify_target_info),
-		.table		= "mangle",
-		.hooks		= (1 << NF_INET_LOCAL_OUT) |
-				  (1 << NF_INET_FORWARD) |
-				  (1 << NF_INET_POST_ROUTING),
-		.me 		= THIS_MODULE,
-	},
+static struct xt_target classify_tg_reg __read_mostly = {
+	.name       = "CLASSIFY",
+	.revision   = 0,
+	.family     = NFPROTO_UNSPEC,
+	.table      = "mangle",
+	.hooks      = (1 << NF_INET_LOCAL_OUT) | (1 << NF_INET_FORWARD) |
+		      (1 << NF_INET_POST_ROUTING),
+	.target     = classify_tg,
+	.targetsize = sizeof(struct xt_classify_target_info),
+	.me         = THIS_MODULE,
 };
 
 static int __init classify_tg_init(void)
 {
-	return xt_register_targets(classify_tg_reg,
-	       ARRAY_SIZE(classify_tg_reg));
+	return xt_register_target(&classify_tg_reg);
 }
 
 static void __exit classify_tg_exit(void)
 {
-	xt_unregister_targets(classify_tg_reg, ARRAY_SIZE(classify_tg_reg));
+	xt_unregister_target(&classify_tg_reg);
 }
 
 module_init(classify_tg_init);
diff --git a/net/netfilter/xt_CONNMARK.c b/net/netfilter/xt_CONNMARK.c
index 5fecfb4..d6e5ab4 100644
--- a/net/netfilter/xt_CONNMARK.c
+++ b/net/netfilter/xt_CONNMARK.c
@@ -36,11 +36,9 @@
 #include <net/netfilter/nf_conntrack_ecache.h>
 
 static unsigned int
-connmark_tg_v0(struct sk_buff *skb, const struct net_device *in,
-               const struct net_device *out, unsigned int hooknum,
-               const struct xt_target *target, const void *targinfo)
+connmark_tg_v0(struct sk_buff *skb, const struct xt_target_param *par)
 {
-	const struct xt_connmark_target_info *markinfo = targinfo;
+	const struct xt_connmark_target_info *markinfo = par->targinfo;
 	struct nf_conn *ct;
 	enum ip_conntrack_info ctinfo;
 	u_int32_t diff;
@@ -54,7 +52,7 @@
 			newmark = (ct->mark & ~markinfo->mask) | markinfo->mark;
 			if (newmark != ct->mark) {
 				ct->mark = newmark;
-				nf_conntrack_event_cache(IPCT_MARK, skb);
+				nf_conntrack_event_cache(IPCT_MARK, ct);
 			}
 			break;
 		case XT_CONNMARK_SAVE:
@@ -62,7 +60,7 @@
 				  (skb->mark & markinfo->mask);
 			if (ct->mark != newmark) {
 				ct->mark = newmark;
-				nf_conntrack_event_cache(IPCT_MARK, skb);
+				nf_conntrack_event_cache(IPCT_MARK, ct);
 			}
 			break;
 		case XT_CONNMARK_RESTORE:
@@ -77,11 +75,9 @@
 }
 
 static unsigned int
-connmark_tg(struct sk_buff *skb, const struct net_device *in,
-            const struct net_device *out, unsigned int hooknum,
-            const struct xt_target *target, const void *targinfo)
+connmark_tg(struct sk_buff *skb, const struct xt_target_param *par)
 {
-	const struct xt_connmark_tginfo1 *info = targinfo;
+	const struct xt_connmark_tginfo1 *info = par->targinfo;
 	enum ip_conntrack_info ctinfo;
 	struct nf_conn *ct;
 	u_int32_t newmark;
@@ -95,7 +91,7 @@
 		newmark = (ct->mark & ~info->ctmask) ^ info->ctmark;
 		if (ct->mark != newmark) {
 			ct->mark = newmark;
-			nf_conntrack_event_cache(IPCT_MARK, skb);
+			nf_conntrack_event_cache(IPCT_MARK, ct);
 		}
 		break;
 	case XT_CONNMARK_SAVE:
@@ -103,7 +99,7 @@
 		          (skb->mark & info->nfmask);
 		if (ct->mark != newmark) {
 			ct->mark = newmark;
-			nf_conntrack_event_cache(IPCT_MARK, skb);
+			nf_conntrack_event_cache(IPCT_MARK, ct);
 		}
 		break;
 	case XT_CONNMARK_RESTORE:
@@ -116,18 +112,15 @@
 	return XT_CONTINUE;
 }
 
-static bool
-connmark_tg_check_v0(const char *tablename, const void *entry,
-                     const struct xt_target *target, void *targinfo,
-                     unsigned int hook_mask)
+static bool connmark_tg_check_v0(const struct xt_tgchk_param *par)
 {
-	const struct xt_connmark_target_info *matchinfo = targinfo;
+	const struct xt_connmark_target_info *matchinfo = par->targinfo;
 
 	if (matchinfo->mode == XT_CONNMARK_RESTORE) {
-		if (strcmp(tablename, "mangle") != 0) {
+		if (strcmp(par->table, "mangle") != 0) {
 			printk(KERN_WARNING "CONNMARK: restore can only be "
 			       "called from \"mangle\" table, not \"%s\"\n",
-			       tablename);
+			       par->table);
 			return false;
 		}
 	}
@@ -135,31 +128,27 @@
 		printk(KERN_WARNING "CONNMARK: Only supports 32bit mark\n");
 		return false;
 	}
-	if (nf_ct_l3proto_try_module_get(target->family) < 0) {
+	if (nf_ct_l3proto_try_module_get(par->family) < 0) {
 		printk(KERN_WARNING "can't load conntrack support for "
-				    "proto=%u\n", target->family);
+				    "proto=%u\n", par->family);
 		return false;
 	}
 	return true;
 }
 
-static bool
-connmark_tg_check(const char *tablename, const void *entry,
-                  const struct xt_target *target, void *targinfo,
-                  unsigned int hook_mask)
+static bool connmark_tg_check(const struct xt_tgchk_param *par)
 {
-	if (nf_ct_l3proto_try_module_get(target->family) < 0) {
+	if (nf_ct_l3proto_try_module_get(par->family) < 0) {
 		printk(KERN_WARNING "cannot load conntrack support for "
-		       "proto=%u\n", target->family);
+		       "proto=%u\n", par->family);
 		return false;
 	}
 	return true;
 }
 
-static void
-connmark_tg_destroy(const struct xt_target *target, void *targinfo)
+static void connmark_tg_destroy(const struct xt_tgdtor_param *par)
 {
-	nf_ct_l3proto_module_put(target->family);
+	nf_ct_l3proto_module_put(par->family);
 }
 
 #ifdef CONFIG_COMPAT
@@ -197,22 +186,7 @@
 	{
 		.name		= "CONNMARK",
 		.revision	= 0,
-		.family		= AF_INET,
-		.checkentry	= connmark_tg_check_v0,
-		.destroy	= connmark_tg_destroy,
-		.target		= connmark_tg_v0,
-		.targetsize	= sizeof(struct xt_connmark_target_info),
-#ifdef CONFIG_COMPAT
-		.compatsize	= sizeof(struct compat_xt_connmark_target_info),
-		.compat_from_user = connmark_tg_compat_from_user_v0,
-		.compat_to_user	= connmark_tg_compat_to_user_v0,
-#endif
-		.me		= THIS_MODULE
-	},
-	{
-		.name		= "CONNMARK",
-		.revision	= 0,
-		.family		= AF_INET6,
+		.family		= NFPROTO_UNSPEC,
 		.checkentry	= connmark_tg_check_v0,
 		.destroy	= connmark_tg_destroy,
 		.target		= connmark_tg_v0,
@@ -227,17 +201,7 @@
 	{
 		.name           = "CONNMARK",
 		.revision       = 1,
-		.family         = AF_INET,
-		.checkentry     = connmark_tg_check,
-		.target         = connmark_tg,
-		.targetsize     = sizeof(struct xt_connmark_tginfo1),
-		.destroy        = connmark_tg_destroy,
-		.me             = THIS_MODULE,
-	},
-	{
-		.name           = "CONNMARK",
-		.revision       = 1,
-		.family         = AF_INET6,
+		.family         = NFPROTO_UNSPEC,
 		.checkentry     = connmark_tg_check,
 		.target         = connmark_tg,
 		.targetsize     = sizeof(struct xt_connmark_tginfo1),
diff --git a/net/netfilter/xt_CONNSECMARK.c b/net/netfilter/xt_CONNSECMARK.c
index 76ca1f2..b54c375 100644
--- a/net/netfilter/xt_CONNSECMARK.c
+++ b/net/netfilter/xt_CONNSECMARK.c
@@ -43,7 +43,7 @@
 		ct = nf_ct_get(skb, &ctinfo);
 		if (ct && !ct->secmark) {
 			ct->secmark = skb->secmark;
-			nf_conntrack_event_cache(IPCT_SECMARK, skb);
+			nf_conntrack_event_cache(IPCT_SECMARK, ct);
 		}
 	}
 }
@@ -65,11 +65,9 @@
 }
 
 static unsigned int
-connsecmark_tg(struct sk_buff *skb, const struct net_device *in,
-               const struct net_device *out, unsigned int hooknum,
-               const struct xt_target *target, const void *targinfo)
+connsecmark_tg(struct sk_buff *skb, const struct xt_target_param *par)
 {
-	const struct xt_connsecmark_target_info *info = targinfo;
+	const struct xt_connsecmark_target_info *info = par->targinfo;
 
 	switch (info->mode) {
 	case CONNSECMARK_SAVE:
@@ -87,16 +85,14 @@
 	return XT_CONTINUE;
 }
 
-static bool
-connsecmark_tg_check(const char *tablename, const void *entry,
-                     const struct xt_target *target, void *targinfo,
-                     unsigned int hook_mask)
+static bool connsecmark_tg_check(const struct xt_tgchk_param *par)
 {
-	const struct xt_connsecmark_target_info *info = targinfo;
+	const struct xt_connsecmark_target_info *info = par->targinfo;
 
-	if (strcmp(tablename, "mangle") && strcmp(tablename, "security")) {
+	if (strcmp(par->table, "mangle") != 0 &&
+	    strcmp(par->table, "security") != 0) {
 		printk(KERN_INFO PFX "target only valid in the \'mangle\' "
-		       "or \'security\' tables, not \'%s\'.\n", tablename);
+		       "or \'security\' tables, not \'%s\'.\n", par->table);
 		return false;
 	}
 
@@ -110,51 +106,38 @@
 		return false;
 	}
 
-	if (nf_ct_l3proto_try_module_get(target->family) < 0) {
+	if (nf_ct_l3proto_try_module_get(par->family) < 0) {
 		printk(KERN_WARNING "can't load conntrack support for "
-				    "proto=%u\n", target->family);
+				    "proto=%u\n", par->family);
 		return false;
 	}
 	return true;
 }
 
-static void
-connsecmark_tg_destroy(const struct xt_target *target, void *targinfo)
+static void connsecmark_tg_destroy(const struct xt_tgdtor_param *par)
 {
-	nf_ct_l3proto_module_put(target->family);
+	nf_ct_l3proto_module_put(par->family);
 }
 
-static struct xt_target connsecmark_tg_reg[] __read_mostly = {
-	{
-		.name		= "CONNSECMARK",
-		.family		= AF_INET,
-		.checkentry	= connsecmark_tg_check,
-		.destroy	= connsecmark_tg_destroy,
-		.target		= connsecmark_tg,
-		.targetsize	= sizeof(struct xt_connsecmark_target_info),
-		.me		= THIS_MODULE,
-	},
-	{
-		.name		= "CONNSECMARK",
-		.family		= AF_INET6,
-		.checkentry	= connsecmark_tg_check,
-		.destroy	= connsecmark_tg_destroy,
-		.target		= connsecmark_tg,
-		.targetsize	= sizeof(struct xt_connsecmark_target_info),
-		.me		= THIS_MODULE,
-	},
+static struct xt_target connsecmark_tg_reg __read_mostly = {
+	.name       = "CONNSECMARK",
+	.revision   = 0,
+	.family     = NFPROTO_UNSPEC,
+	.checkentry = connsecmark_tg_check,
+	.destroy    = connsecmark_tg_destroy,
+	.target     = connsecmark_tg,
+	.targetsize = sizeof(struct xt_connsecmark_target_info),
+	.me         = THIS_MODULE,
 };
 
 static int __init connsecmark_tg_init(void)
 {
-	return xt_register_targets(connsecmark_tg_reg,
-	       ARRAY_SIZE(connsecmark_tg_reg));
+	return xt_register_target(&connsecmark_tg_reg);
 }
 
 static void __exit connsecmark_tg_exit(void)
 {
-	xt_unregister_targets(connsecmark_tg_reg,
-	                      ARRAY_SIZE(connsecmark_tg_reg));
+	xt_unregister_target(&connsecmark_tg_reg);
 }
 
 module_init(connsecmark_tg_init);
diff --git a/net/netfilter/xt_DSCP.c b/net/netfilter/xt_DSCP.c
index 97efd74..6a347e7 100644
--- a/net/netfilter/xt_DSCP.c
+++ b/net/netfilter/xt_DSCP.c
@@ -29,11 +29,9 @@
 MODULE_ALIAS("ip6t_TOS");
 
 static unsigned int
-dscp_tg(struct sk_buff *skb, const struct net_device *in,
-        const struct net_device *out, unsigned int hooknum,
-        const struct xt_target *target, const void *targinfo)
+dscp_tg(struct sk_buff *skb, const struct xt_target_param *par)
 {
-	const struct xt_DSCP_info *dinfo = targinfo;
+	const struct xt_DSCP_info *dinfo = par->targinfo;
 	u_int8_t dscp = ipv4_get_dsfield(ip_hdr(skb)) >> XT_DSCP_SHIFT;
 
 	if (dscp != dinfo->dscp) {
@@ -48,11 +46,9 @@
 }
 
 static unsigned int
-dscp_tg6(struct sk_buff *skb, const struct net_device *in,
-         const struct net_device *out, unsigned int hooknum,
-         const struct xt_target *target, const void *targinfo)
+dscp_tg6(struct sk_buff *skb, const struct xt_target_param *par)
 {
-	const struct xt_DSCP_info *dinfo = targinfo;
+	const struct xt_DSCP_info *dinfo = par->targinfo;
 	u_int8_t dscp = ipv6_get_dsfield(ipv6_hdr(skb)) >> XT_DSCP_SHIFT;
 
 	if (dscp != dinfo->dscp) {
@@ -65,26 +61,21 @@
 	return XT_CONTINUE;
 }
 
-static bool
-dscp_tg_check(const char *tablename, const void *e_void,
-              const struct xt_target *target, void *targinfo,
-              unsigned int hook_mask)
+static bool dscp_tg_check(const struct xt_tgchk_param *par)
 {
-	const u_int8_t dscp = ((struct xt_DSCP_info *)targinfo)->dscp;
+	const struct xt_DSCP_info *info = par->targinfo;
 
-	if (dscp > XT_DSCP_MAX) {
-		printk(KERN_WARNING "DSCP: dscp %x out of range\n", dscp);
+	if (info->dscp > XT_DSCP_MAX) {
+		printk(KERN_WARNING "DSCP: dscp %x out of range\n", info->dscp);
 		return false;
 	}
 	return true;
 }
 
 static unsigned int
-tos_tg_v0(struct sk_buff *skb, const struct net_device *in,
-          const struct net_device *out, unsigned int hooknum,
-          const struct xt_target *target, const void *targinfo)
+tos_tg_v0(struct sk_buff *skb, const struct xt_target_param *par)
 {
-	const struct ipt_tos_target_info *info = targinfo;
+	const struct ipt_tos_target_info *info = par->targinfo;
 	struct iphdr *iph = ip_hdr(skb);
 	u_int8_t oldtos;
 
@@ -101,12 +92,10 @@
 	return XT_CONTINUE;
 }
 
-static bool
-tos_tg_check_v0(const char *tablename, const void *e_void,
-                const struct xt_target *target, void *targinfo,
-                unsigned int hook_mask)
+static bool tos_tg_check_v0(const struct xt_tgchk_param *par)
 {
-	const u_int8_t tos = ((struct ipt_tos_target_info *)targinfo)->tos;
+	const struct ipt_tos_target_info *info = par->targinfo;
+	const uint8_t tos = info->tos;
 
 	if (tos != IPTOS_LOWDELAY && tos != IPTOS_THROUGHPUT &&
 	    tos != IPTOS_RELIABILITY && tos != IPTOS_MINCOST &&
@@ -119,11 +108,9 @@
 }
 
 static unsigned int
-tos_tg(struct sk_buff *skb, const struct net_device *in,
-       const struct net_device *out, unsigned int hooknum,
-       const struct xt_target *target, const void *targinfo)
+tos_tg(struct sk_buff *skb, const struct xt_target_param *par)
 {
-	const struct xt_tos_target_info *info = targinfo;
+	const struct xt_tos_target_info *info = par->targinfo;
 	struct iphdr *iph = ip_hdr(skb);
 	u_int8_t orig, nv;
 
@@ -141,11 +128,9 @@
 }
 
 static unsigned int
-tos_tg6(struct sk_buff *skb, const struct net_device *in,
-        const struct net_device *out, unsigned int hooknum,
-        const struct xt_target *target, const void *targinfo)
+tos_tg6(struct sk_buff *skb, const struct xt_target_param *par)
 {
-	const struct xt_tos_target_info *info = targinfo;
+	const struct xt_tos_target_info *info = par->targinfo;
 	struct ipv6hdr *iph = ipv6_hdr(skb);
 	u_int8_t orig, nv;
 
@@ -165,7 +150,7 @@
 static struct xt_target dscp_tg_reg[] __read_mostly = {
 	{
 		.name		= "DSCP",
-		.family		= AF_INET,
+		.family		= NFPROTO_IPV4,
 		.checkentry	= dscp_tg_check,
 		.target		= dscp_tg,
 		.targetsize	= sizeof(struct xt_DSCP_info),
@@ -174,7 +159,7 @@
 	},
 	{
 		.name		= "DSCP",
-		.family		= AF_INET6,
+		.family		= NFPROTO_IPV6,
 		.checkentry	= dscp_tg_check,
 		.target		= dscp_tg6,
 		.targetsize	= sizeof(struct xt_DSCP_info),
@@ -184,7 +169,7 @@
 	{
 		.name		= "TOS",
 		.revision	= 0,
-		.family		= AF_INET,
+		.family		= NFPROTO_IPV4,
 		.table		= "mangle",
 		.target		= tos_tg_v0,
 		.targetsize	= sizeof(struct ipt_tos_target_info),
@@ -194,7 +179,7 @@
 	{
 		.name		= "TOS",
 		.revision	= 1,
-		.family		= AF_INET,
+		.family		= NFPROTO_IPV4,
 		.table		= "mangle",
 		.target		= tos_tg,
 		.targetsize	= sizeof(struct xt_tos_target_info),
@@ -203,7 +188,7 @@
 	{
 		.name		= "TOS",
 		.revision	= 1,
-		.family		= AF_INET6,
+		.family		= NFPROTO_IPV6,
 		.table		= "mangle",
 		.target		= tos_tg6,
 		.targetsize	= sizeof(struct xt_tos_target_info),
diff --git a/net/netfilter/xt_MARK.c b/net/netfilter/xt_MARK.c
index f9ce20b..67574bc 100644
--- a/net/netfilter/xt_MARK.c
+++ b/net/netfilter/xt_MARK.c
@@ -25,22 +25,18 @@
 MODULE_ALIAS("ip6t_MARK");
 
 static unsigned int
-mark_tg_v0(struct sk_buff *skb, const struct net_device *in,
-           const struct net_device *out, unsigned int hooknum,
-           const struct xt_target *target, const void *targinfo)
+mark_tg_v0(struct sk_buff *skb, const struct xt_target_param *par)
 {
-	const struct xt_mark_target_info *markinfo = targinfo;
+	const struct xt_mark_target_info *markinfo = par->targinfo;
 
 	skb->mark = markinfo->mark;
 	return XT_CONTINUE;
 }
 
 static unsigned int
-mark_tg_v1(struct sk_buff *skb, const struct net_device *in,
-           const struct net_device *out, unsigned int hooknum,
-           const struct xt_target *target, const void *targinfo)
+mark_tg_v1(struct sk_buff *skb, const struct xt_target_param *par)
 {
-	const struct xt_mark_target_info_v1 *markinfo = targinfo;
+	const struct xt_mark_target_info_v1 *markinfo = par->targinfo;
 	int mark = 0;
 
 	switch (markinfo->mode) {
@@ -62,22 +58,17 @@
 }
 
 static unsigned int
-mark_tg(struct sk_buff *skb, const struct net_device *in,
-        const struct net_device *out, unsigned int hooknum,
-        const struct xt_target *target, const void *targinfo)
+mark_tg(struct sk_buff *skb, const struct xt_target_param *par)
 {
-	const struct xt_mark_tginfo2 *info = targinfo;
+	const struct xt_mark_tginfo2 *info = par->targinfo;
 
 	skb->mark = (skb->mark & ~info->mask) ^ info->mark;
 	return XT_CONTINUE;
 }
 
-static bool
-mark_tg_check_v0(const char *tablename, const void *entry,
-                 const struct xt_target *target, void *targinfo,
-                 unsigned int hook_mask)
+static bool mark_tg_check_v0(const struct xt_tgchk_param *par)
 {
-	const struct xt_mark_target_info *markinfo = targinfo;
+	const struct xt_mark_target_info *markinfo = par->targinfo;
 
 	if (markinfo->mark > 0xffffffff) {
 		printk(KERN_WARNING "MARK: Only supports 32bit wide mark\n");
@@ -86,12 +77,9 @@
 	return true;
 }
 
-static bool
-mark_tg_check_v1(const char *tablename, const void *entry,
-                 const struct xt_target *target, void *targinfo,
-                 unsigned int hook_mask)
+static bool mark_tg_check_v1(const struct xt_tgchk_param *par)
 {
-	const struct xt_mark_target_info_v1 *markinfo = targinfo;
+	const struct xt_mark_target_info_v1 *markinfo = par->targinfo;
 
 	if (markinfo->mode != XT_MARK_SET
 	    && markinfo->mode != XT_MARK_AND
@@ -161,7 +149,7 @@
 static struct xt_target mark_tg_reg[] __read_mostly = {
 	{
 		.name		= "MARK",
-		.family		= AF_INET,
+		.family		= NFPROTO_UNSPEC,
 		.revision	= 0,
 		.checkentry	= mark_tg_check_v0,
 		.target		= mark_tg_v0,
@@ -176,37 +164,7 @@
 	},
 	{
 		.name		= "MARK",
-		.family		= AF_INET,
-		.revision	= 1,
-		.checkentry	= mark_tg_check_v1,
-		.target		= mark_tg_v1,
-		.targetsize	= sizeof(struct xt_mark_target_info_v1),
-#ifdef CONFIG_COMPAT
-		.compatsize	= sizeof(struct compat_xt_mark_target_info_v1),
-		.compat_from_user = mark_tg_compat_from_user_v1,
-		.compat_to_user	= mark_tg_compat_to_user_v1,
-#endif
-		.table		= "mangle",
-		.me		= THIS_MODULE,
-	},
-	{
-		.name		= "MARK",
-		.family		= AF_INET6,
-		.revision	= 0,
-		.checkentry	= mark_tg_check_v0,
-		.target		= mark_tg_v0,
-		.targetsize	= sizeof(struct xt_mark_target_info),
-#ifdef CONFIG_COMPAT
-		.compatsize	= sizeof(struct compat_xt_mark_target_info),
-		.compat_from_user = mark_tg_compat_from_user_v0,
-		.compat_to_user	= mark_tg_compat_to_user_v0,
-#endif
-		.table		= "mangle",
-		.me		= THIS_MODULE,
-	},
-	{
-		.name		= "MARK",
-		.family		= AF_INET6,
+		.family		= NFPROTO_UNSPEC,
 		.revision	= 1,
 		.checkentry	= mark_tg_check_v1,
 		.target		= mark_tg_v1,
@@ -222,15 +180,7 @@
 	{
 		.name           = "MARK",
 		.revision       = 2,
-		.family         = AF_INET,
-		.target         = mark_tg,
-		.targetsize     = sizeof(struct xt_mark_tginfo2),
-		.me             = THIS_MODULE,
-	},
-	{
-		.name           = "MARK",
-		.revision       = 2,
-		.family         = AF_INET6,
+		.family         = NFPROTO_UNSPEC,
 		.target         = mark_tg,
 		.targetsize     = sizeof(struct xt_mark_tginfo2),
 		.me             = THIS_MODULE,
diff --git a/net/netfilter/xt_NFLOG.c b/net/netfilter/xt_NFLOG.c
index 19ae8ef..50e3a52 100644
--- a/net/netfilter/xt_NFLOG.c
+++ b/net/netfilter/xt_NFLOG.c
@@ -21,11 +21,9 @@
 MODULE_ALIAS("ip6t_NFLOG");
 
 static unsigned int
-nflog_tg(struct sk_buff *skb, const struct net_device *in,
-         const struct net_device *out, unsigned int hooknum,
-         const struct xt_target *target, const void *targinfo)
+nflog_tg(struct sk_buff *skb, const struct xt_target_param *par)
 {
-	const struct xt_nflog_info *info = targinfo;
+	const struct xt_nflog_info *info = par->targinfo;
 	struct nf_loginfo li;
 
 	li.type		     = NF_LOG_TYPE_ULOG;
@@ -33,17 +31,14 @@
 	li.u.ulog.group	     = info->group;
 	li.u.ulog.qthreshold = info->threshold;
 
-	nf_log_packet(target->family, hooknum, skb, in, out, &li,
-		      "%s", info->prefix);
+	nf_log_packet(par->family, par->hooknum, skb, par->in,
+	              par->out, &li, "%s", info->prefix);
 	return XT_CONTINUE;
 }
 
-static bool
-nflog_tg_check(const char *tablename, const void *entry,
-               const struct xt_target *target, void *targetinfo,
-               unsigned int hookmask)
+static bool nflog_tg_check(const struct xt_tgchk_param *par)
 {
-	const struct xt_nflog_info *info = targetinfo;
+	const struct xt_nflog_info *info = par->targinfo;
 
 	if (info->flags & ~XT_NFLOG_MASK)
 		return false;
@@ -52,33 +47,24 @@
 	return true;
 }
 
-static struct xt_target nflog_tg_reg[] __read_mostly = {
-	{
-		.name		= "NFLOG",
-		.family		= AF_INET,
-		.checkentry	= nflog_tg_check,
-		.target		= nflog_tg,
-		.targetsize	= sizeof(struct xt_nflog_info),
-		.me		= THIS_MODULE,
-	},
-	{
-		.name		= "NFLOG",
-		.family		= AF_INET6,
-		.checkentry	= nflog_tg_check,
-		.target		= nflog_tg,
-		.targetsize	= sizeof(struct xt_nflog_info),
-		.me		= THIS_MODULE,
-	},
+static struct xt_target nflog_tg_reg __read_mostly = {
+	.name       = "NFLOG",
+	.revision   = 0,
+	.family     = NFPROTO_UNSPEC,
+	.checkentry = nflog_tg_check,
+	.target     = nflog_tg,
+	.targetsize = sizeof(struct xt_nflog_info),
+	.me         = THIS_MODULE,
 };
 
 static int __init nflog_tg_init(void)
 {
-	return xt_register_targets(nflog_tg_reg, ARRAY_SIZE(nflog_tg_reg));
+	return xt_register_target(&nflog_tg_reg);
 }
 
 static void __exit nflog_tg_exit(void)
 {
-	xt_unregister_targets(nflog_tg_reg, ARRAY_SIZE(nflog_tg_reg));
+	xt_unregister_target(&nflog_tg_reg);
 }
 
 module_init(nflog_tg_init);
diff --git a/net/netfilter/xt_NFQUEUE.c b/net/netfilter/xt_NFQUEUE.c
index beb24d1..2cc1fff 100644
--- a/net/netfilter/xt_NFQUEUE.c
+++ b/net/netfilter/xt_NFQUEUE.c
@@ -24,11 +24,9 @@
 MODULE_ALIAS("arpt_NFQUEUE");
 
 static unsigned int
-nfqueue_tg(struct sk_buff *skb, const struct net_device *in,
-           const struct net_device *out, unsigned int hooknum,
-           const struct xt_target *target, const void *targinfo)
+nfqueue_tg(struct sk_buff *skb, const struct xt_target_param *par)
 {
-	const struct xt_NFQ_info *tinfo = targinfo;
+	const struct xt_NFQ_info *tinfo = par->targinfo;
 
 	return NF_QUEUE_NR(tinfo->queuenum);
 }
@@ -36,14 +34,14 @@
 static struct xt_target nfqueue_tg_reg[] __read_mostly = {
 	{
 		.name		= "NFQUEUE",
-		.family		= AF_INET,
+		.family		= NFPROTO_IPV4,
 		.target		= nfqueue_tg,
 		.targetsize	= sizeof(struct xt_NFQ_info),
 		.me		= THIS_MODULE,
 	},
 	{
 		.name		= "NFQUEUE",
-		.family		= AF_INET6,
+		.family		= NFPROTO_IPV6,
 		.target		= nfqueue_tg,
 		.targetsize	= sizeof(struct xt_NFQ_info),
 		.me		= THIS_MODULE,
diff --git a/net/netfilter/xt_NOTRACK.c b/net/netfilter/xt_NOTRACK.c
index 6c9de61..e7a0a54 100644
--- a/net/netfilter/xt_NOTRACK.c
+++ b/net/netfilter/xt_NOTRACK.c
@@ -13,9 +13,7 @@
 MODULE_ALIAS("ip6t_NOTRACK");
 
 static unsigned int
-notrack_tg(struct sk_buff *skb, const struct net_device *in,
-           const struct net_device *out, unsigned int hooknum,
-           const struct xt_target *target, const void *targinfo)
+notrack_tg(struct sk_buff *skb, const struct xt_target_param *par)
 {
 	/* Previously seen (loopback)? Ignore. */
 	if (skb->nfct != NULL)
@@ -32,31 +30,23 @@
 	return XT_CONTINUE;
 }
 
-static struct xt_target notrack_tg_reg[] __read_mostly = {
-	{
-		.name		= "NOTRACK",
-		.family		= AF_INET,
-		.target		= notrack_tg,
-		.table		= "raw",
-		.me		= THIS_MODULE,
-	},
-	{
-		.name		= "NOTRACK",
-		.family		= AF_INET6,
-		.target		= notrack_tg,
-		.table		= "raw",
-		.me		= THIS_MODULE,
-	},
+static struct xt_target notrack_tg_reg __read_mostly = {
+	.name     = "NOTRACK",
+	.revision = 0,
+	.family   = NFPROTO_UNSPEC,
+	.target   = notrack_tg,
+	.table    = "raw",
+	.me       = THIS_MODULE,
 };
 
 static int __init notrack_tg_init(void)
 {
-	return xt_register_targets(notrack_tg_reg, ARRAY_SIZE(notrack_tg_reg));
+	return xt_register_target(&notrack_tg_reg);
 }
 
 static void __exit notrack_tg_exit(void)
 {
-	xt_unregister_targets(notrack_tg_reg, ARRAY_SIZE(notrack_tg_reg));
+	xt_unregister_target(&notrack_tg_reg);
 }
 
 module_init(notrack_tg_init);
diff --git a/net/netfilter/xt_RATEEST.c b/net/netfilter/xt_RATEEST.c
index 64d6ad3..43f5676 100644
--- a/net/netfilter/xt_RATEEST.c
+++ b/net/netfilter/xt_RATEEST.c
@@ -71,14 +71,9 @@
 EXPORT_SYMBOL_GPL(xt_rateest_put);
 
 static unsigned int
-xt_rateest_tg(struct sk_buff *skb,
-	      const struct net_device *in,
-	      const struct net_device *out,
-	      unsigned int hooknum,
-	      const struct xt_target *target,
-	      const void *targinfo)
+xt_rateest_tg(struct sk_buff *skb, const struct xt_target_param *par)
 {
-	const struct xt_rateest_target_info *info = targinfo;
+	const struct xt_rateest_target_info *info = par->targinfo;
 	struct gnet_stats_basic *stats = &info->est->bstats;
 
 	spin_lock_bh(&info->est->lock);
@@ -89,14 +84,9 @@
 	return XT_CONTINUE;
 }
 
-static bool
-xt_rateest_tg_checkentry(const char *tablename,
-			 const void *entry,
-			 const struct xt_target *target,
-			 void *targinfo,
-			 unsigned int hook_mask)
+static bool xt_rateest_tg_checkentry(const struct xt_tgchk_param *par)
 {
-	struct xt_rateest_target_info *info = targinfo;
+	struct xt_rateest_target_info *info = par->targinfo;
 	struct xt_rateest *est;
 	struct {
 		struct nlattr		opt;
@@ -149,33 +139,22 @@
 	return false;
 }
 
-static void xt_rateest_tg_destroy(const struct xt_target *target,
-				  void *targinfo)
+static void xt_rateest_tg_destroy(const struct xt_tgdtor_param *par)
 {
-	struct xt_rateest_target_info *info = targinfo;
+	struct xt_rateest_target_info *info = par->targinfo;
 
 	xt_rateest_put(info->est);
 }
 
-static struct xt_target xt_rateest_target[] __read_mostly = {
-	{
-		.family		= AF_INET,
-		.name		= "RATEEST",
-		.target		= xt_rateest_tg,
-		.checkentry	= xt_rateest_tg_checkentry,
-		.destroy	= xt_rateest_tg_destroy,
-		.targetsize	= sizeof(struct xt_rateest_target_info),
-		.me		= THIS_MODULE,
-	},
-	{
-		.family		= AF_INET6,
-		.name		= "RATEEST",
-		.target		= xt_rateest_tg,
-		.checkentry	= xt_rateest_tg_checkentry,
-		.destroy	= xt_rateest_tg_destroy,
-		.targetsize	= sizeof(struct xt_rateest_target_info),
-		.me		= THIS_MODULE,
-	},
+static struct xt_target xt_rateest_tg_reg __read_mostly = {
+	.name       = "RATEEST",
+	.revision   = 0,
+	.family     = NFPROTO_UNSPEC,
+	.target     = xt_rateest_tg,
+	.checkentry = xt_rateest_tg_checkentry,
+	.destroy    = xt_rateest_tg_destroy,
+	.targetsize = sizeof(struct xt_rateest_target_info),
+	.me         = THIS_MODULE,
 };
 
 static int __init xt_rateest_tg_init(void)
@@ -186,13 +165,12 @@
 		INIT_HLIST_HEAD(&rateest_hash[i]);
 
 	get_random_bytes(&jhash_rnd, sizeof(jhash_rnd));
-	return xt_register_targets(xt_rateest_target,
-				   ARRAY_SIZE(xt_rateest_target));
+	return xt_register_target(&xt_rateest_tg_reg);
 }
 
 static void __exit xt_rateest_tg_fini(void)
 {
-	xt_unregister_targets(xt_rateest_target, ARRAY_SIZE(xt_rateest_target));
+	xt_unregister_target(&xt_rateest_tg_reg);
 }
 
 
diff --git a/net/netfilter/xt_SECMARK.c b/net/netfilter/xt_SECMARK.c
index 94f87ee..7a6f9e6 100644
--- a/net/netfilter/xt_SECMARK.c
+++ b/net/netfilter/xt_SECMARK.c
@@ -29,12 +29,10 @@
 static u8 mode;
 
 static unsigned int
-secmark_tg(struct sk_buff *skb, const struct net_device *in,
-           const struct net_device *out, unsigned int hooknum,
-           const struct xt_target *target, const void *targinfo)
+secmark_tg(struct sk_buff *skb, const struct xt_target_param *par)
 {
 	u32 secmark = 0;
-	const struct xt_secmark_target_info *info = targinfo;
+	const struct xt_secmark_target_info *info = par->targinfo;
 
 	BUG_ON(info->mode != mode);
 
@@ -82,16 +80,14 @@
 	return true;
 }
 
-static bool
-secmark_tg_check(const char *tablename, const void *entry,
-                 const struct xt_target *target, void *targinfo,
-                 unsigned int hook_mask)
+static bool secmark_tg_check(const struct xt_tgchk_param *par)
 {
-	struct xt_secmark_target_info *info = targinfo;
+	struct xt_secmark_target_info *info = par->targinfo;
 
-	if (strcmp(tablename, "mangle") && strcmp(tablename, "security")) {
+	if (strcmp(par->table, "mangle") != 0 &&
+	    strcmp(par->table, "security") != 0) {
 		printk(KERN_INFO PFX "target only valid in the \'mangle\' "
-		       "or \'security\' tables, not \'%s\'.\n", tablename);
+		       "or \'security\' tables, not \'%s\'.\n", par->table);
 		return false;
 	}
 
@@ -117,7 +113,7 @@
 	return true;
 }
 
-static void secmark_tg_destroy(const struct xt_target *target, void *targinfo)
+static void secmark_tg_destroy(const struct xt_tgdtor_param *par)
 {
 	switch (mode) {
 	case SECMARK_MODE_SEL:
@@ -125,35 +121,25 @@
 	}
 }
 
-static struct xt_target secmark_tg_reg[] __read_mostly = {
-	{
-		.name		= "SECMARK",
-		.family		= AF_INET,
-		.checkentry	= secmark_tg_check,
-		.destroy	= secmark_tg_destroy,
-		.target		= secmark_tg,
-		.targetsize	= sizeof(struct xt_secmark_target_info),
-		.me		= THIS_MODULE,
-	},
-	{
-		.name		= "SECMARK",
-		.family		= AF_INET6,
-		.checkentry	= secmark_tg_check,
-		.destroy	= secmark_tg_destroy,
-		.target		= secmark_tg,
-		.targetsize	= sizeof(struct xt_secmark_target_info),
-		.me		= THIS_MODULE,
-	},
+static struct xt_target secmark_tg_reg __read_mostly = {
+	.name       = "SECMARK",
+	.revision   = 0,
+	.family     = NFPROTO_UNSPEC,
+	.checkentry = secmark_tg_check,
+	.destroy    = secmark_tg_destroy,
+	.target     = secmark_tg,
+	.targetsize = sizeof(struct xt_secmark_target_info),
+	.me         = THIS_MODULE,
 };
 
 static int __init secmark_tg_init(void)
 {
-	return xt_register_targets(secmark_tg_reg, ARRAY_SIZE(secmark_tg_reg));
+	return xt_register_target(&secmark_tg_reg);
 }
 
 static void __exit secmark_tg_exit(void)
 {
-	xt_unregister_targets(secmark_tg_reg, ARRAY_SIZE(secmark_tg_reg));
+	xt_unregister_target(&secmark_tg_reg);
 }
 
 module_init(secmark_tg_init);
diff --git a/net/netfilter/xt_TCPMSS.c b/net/netfilter/xt_TCPMSS.c
index beb5094..4f3b1f8 100644
--- a/net/netfilter/xt_TCPMSS.c
+++ b/net/netfilter/xt_TCPMSS.c
@@ -174,15 +174,13 @@
 }
 
 static unsigned int
-tcpmss_tg4(struct sk_buff *skb, const struct net_device *in,
-           const struct net_device *out, unsigned int hooknum,
-           const struct xt_target *target, const void *targinfo)
+tcpmss_tg4(struct sk_buff *skb, const struct xt_target_param *par)
 {
 	struct iphdr *iph = ip_hdr(skb);
 	__be16 newlen;
 	int ret;
 
-	ret = tcpmss_mangle_packet(skb, targinfo,
+	ret = tcpmss_mangle_packet(skb, par->targinfo,
 				   tcpmss_reverse_mtu(skb, PF_INET),
 				   iph->ihl * 4,
 				   sizeof(*iph) + sizeof(struct tcphdr));
@@ -199,9 +197,7 @@
 
 #if defined(CONFIG_IP6_NF_IPTABLES) || defined(CONFIG_IP6_NF_IPTABLES_MODULE)
 static unsigned int
-tcpmss_tg6(struct sk_buff *skb, const struct net_device *in,
-           const struct net_device *out, unsigned int hooknum,
-           const struct xt_target *target, const void *targinfo)
+tcpmss_tg6(struct sk_buff *skb, const struct xt_target_param *par)
 {
 	struct ipv6hdr *ipv6h = ipv6_hdr(skb);
 	u8 nexthdr;
@@ -212,7 +208,7 @@
 	tcphoff = ipv6_skip_exthdr(skb, sizeof(*ipv6h), &nexthdr);
 	if (tcphoff < 0)
 		return NF_DROP;
-	ret = tcpmss_mangle_packet(skb, targinfo,
+	ret = tcpmss_mangle_packet(skb, par->targinfo,
 				   tcpmss_reverse_mtu(skb, PF_INET6),
 				   tcphoff,
 				   sizeof(*ipv6h) + sizeof(struct tcphdr));
@@ -241,16 +237,13 @@
 	return false;
 }
 
-static bool
-tcpmss_tg4_check(const char *tablename, const void *entry,
-                 const struct xt_target *target, void *targinfo,
-                 unsigned int hook_mask)
+static bool tcpmss_tg4_check(const struct xt_tgchk_param *par)
 {
-	const struct xt_tcpmss_info *info = targinfo;
-	const struct ipt_entry *e = entry;
+	const struct xt_tcpmss_info *info = par->targinfo;
+	const struct ipt_entry *e = par->entryinfo;
 
 	if (info->mss == XT_TCPMSS_CLAMP_PMTU &&
-	    (hook_mask & ~((1 << NF_INET_FORWARD) |
+	    (par->hook_mask & ~((1 << NF_INET_FORWARD) |
 			   (1 << NF_INET_LOCAL_OUT) |
 			   (1 << NF_INET_POST_ROUTING))) != 0) {
 		printk("xt_TCPMSS: path-MTU clamping only supported in "
@@ -264,16 +257,13 @@
 }
 
 #if defined(CONFIG_IP6_NF_IPTABLES) || defined(CONFIG_IP6_NF_IPTABLES_MODULE)
-static bool
-tcpmss_tg6_check(const char *tablename, const void *entry,
-                 const struct xt_target *target, void *targinfo,
-                 unsigned int hook_mask)
+static bool tcpmss_tg6_check(const struct xt_tgchk_param *par)
 {
-	const struct xt_tcpmss_info *info = targinfo;
-	const struct ip6t_entry *e = entry;
+	const struct xt_tcpmss_info *info = par->targinfo;
+	const struct ip6t_entry *e = par->entryinfo;
 
 	if (info->mss == XT_TCPMSS_CLAMP_PMTU &&
-	    (hook_mask & ~((1 << NF_INET_FORWARD) |
+	    (par->hook_mask & ~((1 << NF_INET_FORWARD) |
 			   (1 << NF_INET_LOCAL_OUT) |
 			   (1 << NF_INET_POST_ROUTING))) != 0) {
 		printk("xt_TCPMSS: path-MTU clamping only supported in "
@@ -289,7 +279,7 @@
 
 static struct xt_target tcpmss_tg_reg[] __read_mostly = {
 	{
-		.family		= AF_INET,
+		.family		= NFPROTO_IPV4,
 		.name		= "TCPMSS",
 		.checkentry	= tcpmss_tg4_check,
 		.target		= tcpmss_tg4,
@@ -299,7 +289,7 @@
 	},
 #if defined(CONFIG_IP6_NF_IPTABLES) || defined(CONFIG_IP6_NF_IPTABLES_MODULE)
 	{
-		.family		= AF_INET6,
+		.family		= NFPROTO_IPV6,
 		.name		= "TCPMSS",
 		.checkentry	= tcpmss_tg6_check,
 		.target		= tcpmss_tg6,
diff --git a/net/netfilter/xt_TCPOPTSTRIP.c b/net/netfilter/xt_TCPOPTSTRIP.c
index 9685b6f..9dd8c8e 100644
--- a/net/netfilter/xt_TCPOPTSTRIP.c
+++ b/net/netfilter/xt_TCPOPTSTRIP.c
@@ -75,19 +75,15 @@
 }
 
 static unsigned int
-tcpoptstrip_tg4(struct sk_buff *skb, const struct net_device *in,
-		const struct net_device *out, unsigned int hooknum,
-		const struct xt_target *target, const void *targinfo)
+tcpoptstrip_tg4(struct sk_buff *skb, const struct xt_target_param *par)
 {
-	return tcpoptstrip_mangle_packet(skb, targinfo, ip_hdrlen(skb),
+	return tcpoptstrip_mangle_packet(skb, par->targinfo, ip_hdrlen(skb),
 	       sizeof(struct iphdr) + sizeof(struct tcphdr));
 }
 
 #if defined(CONFIG_IP6_NF_MANGLE) || defined(CONFIG_IP6_NF_MANGLE_MODULE)
 static unsigned int
-tcpoptstrip_tg6(struct sk_buff *skb, const struct net_device *in,
-		const struct net_device *out, unsigned int hooknum,
-		const struct xt_target *target, const void *targinfo)
+tcpoptstrip_tg6(struct sk_buff *skb, const struct xt_target_param *par)
 {
 	struct ipv6hdr *ipv6h = ipv6_hdr(skb);
 	int tcphoff;
@@ -98,7 +94,7 @@
 	if (tcphoff < 0)
 		return NF_DROP;
 
-	return tcpoptstrip_mangle_packet(skb, targinfo, tcphoff,
+	return tcpoptstrip_mangle_packet(skb, par->targinfo, tcphoff,
 	       sizeof(*ipv6h) + sizeof(struct tcphdr));
 }
 #endif
@@ -106,7 +102,7 @@
 static struct xt_target tcpoptstrip_tg_reg[] __read_mostly = {
 	{
 		.name       = "TCPOPTSTRIP",
-		.family     = AF_INET,
+		.family     = NFPROTO_IPV4,
 		.table      = "mangle",
 		.proto      = IPPROTO_TCP,
 		.target     = tcpoptstrip_tg4,
@@ -116,7 +112,7 @@
 #if defined(CONFIG_IP6_NF_MANGLE) || defined(CONFIG_IP6_NF_MANGLE_MODULE)
 	{
 		.name       = "TCPOPTSTRIP",
-		.family     = AF_INET6,
+		.family     = NFPROTO_IPV6,
 		.table      = "mangle",
 		.proto      = IPPROTO_TCP,
 		.target     = tcpoptstrip_tg6,
diff --git a/net/netfilter/xt_TPROXY.c b/net/netfilter/xt_TPROXY.c
new file mode 100644
index 0000000..1340c2f
--- /dev/null
+++ b/net/netfilter/xt_TPROXY.c
@@ -0,0 +1,102 @@
+/*
+ * Transparent proxy support for Linux/iptables
+ *
+ * Copyright (c) 2006-2007 BalaBit IT Ltd.
+ * Author: Balazs Scheidler, Krisztian Kovacs
+ *
+ * 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/skbuff.h>
+#include <linux/ip.h>
+#include <net/checksum.h>
+#include <net/udp.h>
+#include <net/inet_sock.h>
+
+#include <linux/netfilter/x_tables.h>
+#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter/xt_TPROXY.h>
+
+#include <net/netfilter/ipv4/nf_defrag_ipv4.h>
+#include <net/netfilter/nf_tproxy_core.h>
+
+static unsigned int
+tproxy_tg(struct sk_buff *skb, const struct xt_target_param *par)
+{
+	const struct iphdr *iph = ip_hdr(skb);
+	const struct xt_tproxy_target_info *tgi = par->targinfo;
+	struct udphdr _hdr, *hp;
+	struct sock *sk;
+
+	hp = skb_header_pointer(skb, ip_hdrlen(skb), sizeof(_hdr), &_hdr);
+	if (hp == NULL)
+		return NF_DROP;
+
+	sk = nf_tproxy_get_sock_v4(dev_net(skb->dev), iph->protocol,
+				   iph->saddr, tgi->laddr ? tgi->laddr : iph->daddr,
+				   hp->source, tgi->lport ? tgi->lport : hp->dest,
+				   par->in, true);
+
+	/* NOTE: assign_sock consumes our sk reference */
+	if (sk && nf_tproxy_assign_sock(skb, sk)) {
+		/* This should be in a separate target, but we don't do multiple
+		   targets on the same rule yet */
+		skb->mark = (skb->mark & ~tgi->mark_mask) ^ tgi->mark_value;
+
+		pr_debug("redirecting: proto %u %08x:%u -> %08x:%u, mark: %x\n",
+			 iph->protocol, ntohl(iph->daddr), ntohs(hp->dest),
+			 ntohl(tgi->laddr), ntohs(tgi->lport), skb->mark);
+		return NF_ACCEPT;
+	}
+
+	pr_debug("no socket, dropping: proto %u %08x:%u -> %08x:%u, mark: %x\n",
+		 iph->protocol, ntohl(iph->daddr), ntohs(hp->dest),
+		 ntohl(tgi->laddr), ntohs(tgi->lport), skb->mark);
+	return NF_DROP;
+}
+
+static bool tproxy_tg_check(const struct xt_tgchk_param *par)
+{
+	const struct ipt_ip *i = par->entryinfo;
+
+	if ((i->proto == IPPROTO_TCP || i->proto == IPPROTO_UDP)
+	    && !(i->invflags & IPT_INV_PROTO))
+		return true;
+
+	pr_info("xt_TPROXY: Can be used only in combination with "
+		"either -p tcp or -p udp\n");
+	return false;
+}
+
+static struct xt_target tproxy_tg_reg __read_mostly = {
+	.name		= "TPROXY",
+	.family		= AF_INET,
+	.table		= "mangle",
+	.target		= tproxy_tg,
+	.targetsize	= sizeof(struct xt_tproxy_target_info),
+	.checkentry	= tproxy_tg_check,
+	.hooks		= 1 << NF_INET_PRE_ROUTING,
+	.me		= THIS_MODULE,
+};
+
+static int __init tproxy_tg_init(void)
+{
+	nf_defrag_ipv4_enable();
+	return xt_register_target(&tproxy_tg_reg);
+}
+
+static void __exit tproxy_tg_exit(void)
+{
+	xt_unregister_target(&tproxy_tg_reg);
+}
+
+module_init(tproxy_tg_init);
+module_exit(tproxy_tg_exit);
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Krisztian Kovacs");
+MODULE_DESCRIPTION("Netfilter transparent proxy (TPROXY) target module.");
+MODULE_ALIAS("ipt_TPROXY");
diff --git a/net/netfilter/xt_TRACE.c b/net/netfilter/xt_TRACE.c
index 30dab79a..fbb04b8 100644
--- a/net/netfilter/xt_TRACE.c
+++ b/net/netfilter/xt_TRACE.c
@@ -11,39 +11,29 @@
 MODULE_ALIAS("ip6t_TRACE");
 
 static unsigned int
-trace_tg(struct sk_buff *skb, const struct net_device *in,
-         const struct net_device *out, unsigned int hooknum,
-         const struct xt_target *target, const void *targinfo)
+trace_tg(struct sk_buff *skb, const struct xt_target_param *par)
 {
 	skb->nf_trace = 1;
 	return XT_CONTINUE;
 }
 
-static struct xt_target trace_tg_reg[] __read_mostly = {
-	{
-		.name		= "TRACE",
-		.family		= AF_INET,
-		.target		= trace_tg,
-		.table		= "raw",
-		.me		= THIS_MODULE,
-	},
-	{
-		.name		= "TRACE",
-		.family		= AF_INET6,
-		.target		= trace_tg,
-		.table		= "raw",
-		.me		= THIS_MODULE,
-	},
+static struct xt_target trace_tg_reg __read_mostly = {
+	.name       = "TRACE",
+	.revision   = 0,
+	.family     = NFPROTO_UNSPEC,
+	.table      = "raw",
+	.target     = trace_tg,
+	.me         = THIS_MODULE,
 };
 
 static int __init trace_tg_init(void)
 {
-	return xt_register_targets(trace_tg_reg, ARRAY_SIZE(trace_tg_reg));
+	return xt_register_target(&trace_tg_reg);
 }
 
 static void __exit trace_tg_exit(void)
 {
-	xt_unregister_targets(trace_tg_reg, ARRAY_SIZE(trace_tg_reg));
+	xt_unregister_target(&trace_tg_reg);
 }
 
 module_init(trace_tg_init);
diff --git a/net/netfilter/xt_comment.c b/net/netfilter/xt_comment.c
index 89f4736..e821798 100644
--- a/net/netfilter/xt_comment.c
+++ b/net/netfilter/xt_comment.c
@@ -16,40 +16,29 @@
 MODULE_ALIAS("ip6t_comment");
 
 static bool
-comment_mt(const struct sk_buff *skb, const struct net_device *in,
-           const struct net_device *out, const struct xt_match *match,
-           const void *matchinfo, int offset, unsigned int protooff,
-           bool *hotdrop)
+comment_mt(const struct sk_buff *skb, const struct xt_match_param *par)
 {
 	/* We always match */
 	return true;
 }
 
-static struct xt_match comment_mt_reg[] __read_mostly = {
-	{
-		.name		= "comment",
-		.family		= AF_INET,
-		.match		= comment_mt,
-		.matchsize	= sizeof(struct xt_comment_info),
-		.me		= THIS_MODULE
-	},
-	{
-		.name		= "comment",
-		.family		= AF_INET6,
-		.match		= comment_mt,
-		.matchsize	= sizeof(struct xt_comment_info),
-		.me		= THIS_MODULE
-	},
+static struct xt_match comment_mt_reg __read_mostly = {
+	.name      = "comment",
+	.revision  = 0,
+	.family    = NFPROTO_UNSPEC,
+	.match     = comment_mt,
+	.matchsize = sizeof(struct xt_comment_info),
+	.me        = THIS_MODULE,
 };
 
 static int __init comment_mt_init(void)
 {
-	return xt_register_matches(comment_mt_reg, ARRAY_SIZE(comment_mt_reg));
+	return xt_register_match(&comment_mt_reg);
 }
 
 static void __exit comment_mt_exit(void)
 {
-	xt_unregister_matches(comment_mt_reg, ARRAY_SIZE(comment_mt_reg));
+	xt_unregister_match(&comment_mt_reg);
 }
 
 module_init(comment_mt_init);
diff --git a/net/netfilter/xt_connbytes.c b/net/netfilter/xt_connbytes.c
index 3e39c4f..955e659 100644
--- a/net/netfilter/xt_connbytes.c
+++ b/net/netfilter/xt_connbytes.c
@@ -17,12 +17,9 @@
 MODULE_ALIAS("ip6t_connbytes");
 
 static bool
-connbytes_mt(const struct sk_buff *skb, const struct net_device *in,
-             const struct net_device *out, const struct xt_match *match,
-             const void *matchinfo, int offset, unsigned int protoff,
-             bool *hotdrop)
+connbytes_mt(const struct sk_buff *skb, const struct xt_match_param *par)
 {
-	const struct xt_connbytes_info *sinfo = matchinfo;
+	const struct xt_connbytes_info *sinfo = par->matchinfo;
 	const struct nf_conn *ct;
 	enum ip_conntrack_info ctinfo;
 	u_int64_t what = 0;	/* initialize to make gcc happy */
@@ -95,12 +92,9 @@
 		return what >= sinfo->count.from;
 }
 
-static bool
-connbytes_mt_check(const char *tablename, const void *ip,
-                   const struct xt_match *match, void *matchinfo,
-                   unsigned int hook_mask)
+static bool connbytes_mt_check(const struct xt_mtchk_param *par)
 {
-	const struct xt_connbytes_info *sinfo = matchinfo;
+	const struct xt_connbytes_info *sinfo = par->matchinfo;
 
 	if (sinfo->what != XT_CONNBYTES_PKTS &&
 	    sinfo->what != XT_CONNBYTES_BYTES &&
@@ -112,51 +106,39 @@
 	    sinfo->direction != XT_CONNBYTES_DIR_BOTH)
 		return false;
 
-	if (nf_ct_l3proto_try_module_get(match->family) < 0) {
+	if (nf_ct_l3proto_try_module_get(par->family) < 0) {
 		printk(KERN_WARNING "can't load conntrack support for "
-				    "proto=%u\n", match->family);
+				    "proto=%u\n", par->family);
 		return false;
 	}
 
 	return true;
 }
 
-static void
-connbytes_mt_destroy(const struct xt_match *match, void *matchinfo)
+static void connbytes_mt_destroy(const struct xt_mtdtor_param *par)
 {
-	nf_ct_l3proto_module_put(match->family);
+	nf_ct_l3proto_module_put(par->family);
 }
 
-static struct xt_match connbytes_mt_reg[] __read_mostly = {
-	{
-		.name		= "connbytes",
-		.family		= AF_INET,
-		.checkentry	= connbytes_mt_check,
-		.match		= connbytes_mt,
-		.destroy	= connbytes_mt_destroy,
-		.matchsize	= sizeof(struct xt_connbytes_info),
-		.me		= THIS_MODULE
-	},
-	{
-		.name		= "connbytes",
-		.family		= AF_INET6,
-		.checkentry	= connbytes_mt_check,
-		.match		= connbytes_mt,
-		.destroy	= connbytes_mt_destroy,
-		.matchsize	= sizeof(struct xt_connbytes_info),
-		.me		= THIS_MODULE
-	},
+static struct xt_match connbytes_mt_reg __read_mostly = {
+	.name       = "connbytes",
+	.revision   = 0,
+	.family     = NFPROTO_UNSPEC,
+	.checkentry = connbytes_mt_check,
+	.match      = connbytes_mt,
+	.destroy    = connbytes_mt_destroy,
+	.matchsize  = sizeof(struct xt_connbytes_info),
+	.me         = THIS_MODULE,
 };
 
 static int __init connbytes_mt_init(void)
 {
-	return xt_register_matches(connbytes_mt_reg,
-	       ARRAY_SIZE(connbytes_mt_reg));
+	return xt_register_match(&connbytes_mt_reg);
 }
 
 static void __exit connbytes_mt_exit(void)
 {
-	xt_unregister_matches(connbytes_mt_reg, ARRAY_SIZE(connbytes_mt_reg));
+	xt_unregister_match(&connbytes_mt_reg);
 }
 
 module_init(connbytes_mt_init);
diff --git a/net/netfilter/xt_connlimit.c b/net/netfilter/xt_connlimit.c
index 70907f6b..7f404cc 100644
--- a/net/netfilter/xt_connlimit.c
+++ b/net/netfilter/xt_connlimit.c
@@ -82,9 +82,9 @@
 static inline unsigned int
 same_source_net(const union nf_inet_addr *addr,
 		const union nf_inet_addr *mask,
-		const union nf_inet_addr *u3, unsigned int family)
+		const union nf_inet_addr *u3, u_int8_t family)
 {
-	if (family == AF_INET) {
+	if (family == NFPROTO_IPV4) {
 		return (addr->ip & mask->ip) == (u3->ip & mask->ip);
 	} else {
 		union nf_inet_addr lh, rh;
@@ -114,7 +114,7 @@
 	int matches = 0;
 
 
-	if (match->family == AF_INET6)
+	if (match->family == NFPROTO_IPV6)
 		hash = &data->iphash[connlimit_iphash6(addr, mask)];
 	else
 		hash = &data->iphash[connlimit_iphash(addr->ip & mask->ip)];
@@ -123,7 +123,7 @@
 
 	/* check the saved connections */
 	list_for_each_entry_safe(conn, tmp, hash, list) {
-		found    = __nf_conntrack_find(&conn->tuple);
+		found    = __nf_conntrack_find(&init_net, &conn->tuple);
 		found_ct = NULL;
 
 		if (found != NULL)
@@ -178,12 +178,9 @@
 }
 
 static bool
-connlimit_mt(const struct sk_buff *skb, const struct net_device *in,
-             const struct net_device *out, const struct xt_match *match,
-             const void *matchinfo, int offset, unsigned int protoff,
-             bool *hotdrop)
+connlimit_mt(const struct sk_buff *skb, const struct xt_match_param *par)
 {
-	const struct xt_connlimit_info *info = matchinfo;
+	const struct xt_connlimit_info *info = par->matchinfo;
 	union nf_inet_addr addr;
 	struct nf_conntrack_tuple tuple;
 	const struct nf_conntrack_tuple *tuple_ptr = &tuple;
@@ -195,10 +192,10 @@
 	if (ct != NULL)
 		tuple_ptr = &ct->tuplehash[0].tuple;
 	else if (!nf_ct_get_tuplepr(skb, skb_network_offset(skb),
-				    match->family, &tuple))
+				    par->family, &tuple))
 		goto hotdrop;
 
-	if (match->family == AF_INET6) {
+	if (par->family == NFPROTO_IPV6) {
 		const struct ipv6hdr *iph = ipv6_hdr(skb);
 		memcpy(&addr.ip6, &iph->saddr, sizeof(iph->saddr));
 	} else {
@@ -208,40 +205,37 @@
 
 	spin_lock_bh(&info->data->lock);
 	connections = count_them(info->data, tuple_ptr, &addr,
-	                         &info->mask, match);
+	                         &info->mask, par->match);
 	spin_unlock_bh(&info->data->lock);
 
 	if (connections < 0) {
 		/* kmalloc failed, drop it entirely */
-		*hotdrop = true;
+		*par->hotdrop = true;
 		return false;
 	}
 
 	return (connections > info->limit) ^ info->inverse;
 
  hotdrop:
-	*hotdrop = true;
+	*par->hotdrop = true;
 	return false;
 }
 
-static bool
-connlimit_mt_check(const char *tablename, const void *ip,
-                   const struct xt_match *match, void *matchinfo,
-                   unsigned int hook_mask)
+static bool connlimit_mt_check(const struct xt_mtchk_param *par)
 {
-	struct xt_connlimit_info *info = matchinfo;
+	struct xt_connlimit_info *info = par->matchinfo;
 	unsigned int i;
 
-	if (nf_ct_l3proto_try_module_get(match->family) < 0) {
+	if (nf_ct_l3proto_try_module_get(par->family) < 0) {
 		printk(KERN_WARNING "cannot load conntrack support for "
-		       "address family %u\n", match->family);
+		       "address family %u\n", par->family);
 		return false;
 	}
 
 	/* init private data */
 	info->data = kmalloc(sizeof(struct xt_connlimit_data), GFP_KERNEL);
 	if (info->data == NULL) {
-		nf_ct_l3proto_module_put(match->family);
+		nf_ct_l3proto_module_put(par->family);
 		return false;
 	}
 
@@ -252,16 +246,15 @@
 	return true;
 }
 
-static void
-connlimit_mt_destroy(const struct xt_match *match, void *matchinfo)
+static void connlimit_mt_destroy(const struct xt_mtdtor_param *par)
 {
-	const struct xt_connlimit_info *info = matchinfo;
+	const struct xt_connlimit_info *info = par->matchinfo;
 	struct xt_connlimit_conn *conn;
 	struct xt_connlimit_conn *tmp;
 	struct list_head *hash = info->data->iphash;
 	unsigned int i;
 
-	nf_ct_l3proto_module_put(match->family);
+	nf_ct_l3proto_module_put(par->family);
 
 	for (i = 0; i < ARRAY_SIZE(info->data->iphash); ++i) {
 		list_for_each_entry_safe(conn, tmp, &hash[i], list) {
@@ -273,41 +266,30 @@
 	kfree(info->data);
 }
 
-static struct xt_match connlimit_mt_reg[] __read_mostly = {
-	{
-		.name       = "connlimit",
-		.family     = AF_INET,
-		.checkentry = connlimit_mt_check,
-		.match      = connlimit_mt,
-		.matchsize  = sizeof(struct xt_connlimit_info),
-		.destroy    = connlimit_mt_destroy,
-		.me         = THIS_MODULE,
-	},
-	{
-		.name       = "connlimit",
-		.family     = AF_INET6,
-		.checkentry = connlimit_mt_check,
-		.match      = connlimit_mt,
-		.matchsize  = sizeof(struct xt_connlimit_info),
-		.destroy    = connlimit_mt_destroy,
-		.me         = THIS_MODULE,
-	},
+static struct xt_match connlimit_mt_reg __read_mostly = {
+	.name       = "connlimit",
+	.revision   = 0,
+	.family     = NFPROTO_UNSPEC,
+	.checkentry = connlimit_mt_check,
+	.match      = connlimit_mt,
+	.matchsize  = sizeof(struct xt_connlimit_info),
+	.destroy    = connlimit_mt_destroy,
+	.me         = THIS_MODULE,
 };
 
 static int __init connlimit_mt_init(void)
 {
-	return xt_register_matches(connlimit_mt_reg,
-	       ARRAY_SIZE(connlimit_mt_reg));
+	return xt_register_match(&connlimit_mt_reg);
 }
 
 static void __exit connlimit_mt_exit(void)
 {
-	xt_unregister_matches(connlimit_mt_reg, ARRAY_SIZE(connlimit_mt_reg));
+	xt_unregister_match(&connlimit_mt_reg);
 }
 
 module_init(connlimit_mt_init);
 module_exit(connlimit_mt_exit);
-MODULE_AUTHOR("Jan Engelhardt <jengelh@computergmbh.de>");
+MODULE_AUTHOR("Jan Engelhardt <jengelh@medozas.de>");
 MODULE_DESCRIPTION("Xtables: Number of connections matching");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS("ipt_connlimit");
diff --git a/net/netfilter/xt_connmark.c b/net/netfilter/xt_connmark.c
index aaa1b96..86cacab 100644
--- a/net/netfilter/xt_connmark.c
+++ b/net/netfilter/xt_connmark.c
@@ -34,12 +34,9 @@
 MODULE_ALIAS("ip6t_connmark");
 
 static bool
-connmark_mt(const struct sk_buff *skb, const struct net_device *in,
-            const struct net_device *out, const struct xt_match *match,
-            const void *matchinfo, int offset, unsigned int protoff,
-            bool *hotdrop)
+connmark_mt(const struct sk_buff *skb, const struct xt_match_param *par)
 {
-	const struct xt_connmark_mtinfo1 *info = matchinfo;
+	const struct xt_connmark_mtinfo1 *info = par->matchinfo;
 	enum ip_conntrack_info ctinfo;
 	const struct nf_conn *ct;
 
@@ -51,12 +48,9 @@
 }
 
 static bool
-connmark_mt_v0(const struct sk_buff *skb, const struct net_device *in,
-               const struct net_device *out, const struct xt_match *match,
-               const void *matchinfo, int offset, unsigned int protoff,
-               bool *hotdrop)
+connmark_mt_v0(const struct sk_buff *skb, const struct xt_match_param *par)
 {
-	const struct xt_connmark_info *info = matchinfo;
+	const struct xt_connmark_info *info = par->matchinfo;
 	const struct nf_conn *ct;
 	enum ip_conntrack_info ctinfo;
 
@@ -67,42 +61,35 @@
 	return ((ct->mark & info->mask) == info->mark) ^ info->invert;
 }
 
-static bool
-connmark_mt_check_v0(const char *tablename, const void *ip,
-                     const struct xt_match *match, void *matchinfo,
-                     unsigned int hook_mask)
+static bool connmark_mt_check_v0(const struct xt_mtchk_param *par)
 {
-	const struct xt_connmark_info *cm = matchinfo;
+	const struct xt_connmark_info *cm = par->matchinfo;
 
 	if (cm->mark > 0xffffffff || cm->mask > 0xffffffff) {
 		printk(KERN_WARNING "connmark: only support 32bit mark\n");
 		return false;
 	}
-	if (nf_ct_l3proto_try_module_get(match->family) < 0) {
+	if (nf_ct_l3proto_try_module_get(par->family) < 0) {
 		printk(KERN_WARNING "can't load conntrack support for "
-				    "proto=%u\n", match->family);
+				    "proto=%u\n", par->family);
 		return false;
 	}
 	return true;
 }
 
-static bool
-connmark_mt_check(const char *tablename, const void *ip,
-                  const struct xt_match *match, void *matchinfo,
-                  unsigned int hook_mask)
+static bool connmark_mt_check(const struct xt_mtchk_param *par)
 {
-	if (nf_ct_l3proto_try_module_get(match->family) < 0) {
+	if (nf_ct_l3proto_try_module_get(par->family) < 0) {
 		printk(KERN_WARNING "cannot load conntrack support for "
-		       "proto=%u\n", match->family);
+		       "proto=%u\n", par->family);
 		return false;
 	}
 	return true;
 }
 
-static void
-connmark_mt_destroy(const struct xt_match *match, void *matchinfo)
+static void connmark_mt_destroy(const struct xt_mtdtor_param *par)
 {
-	nf_ct_l3proto_module_put(match->family);
+	nf_ct_l3proto_module_put(par->family);
 }
 
 #ifdef CONFIG_COMPAT
@@ -140,22 +127,7 @@
 	{
 		.name		= "connmark",
 		.revision	= 0,
-		.family		= AF_INET,
-		.checkentry	= connmark_mt_check_v0,
-		.match		= connmark_mt_v0,
-		.destroy	= connmark_mt_destroy,
-		.matchsize	= sizeof(struct xt_connmark_info),
-#ifdef CONFIG_COMPAT
-		.compatsize	= sizeof(struct compat_xt_connmark_info),
-		.compat_from_user = connmark_mt_compat_from_user_v0,
-		.compat_to_user	= connmark_mt_compat_to_user_v0,
-#endif
-		.me		= THIS_MODULE
-	},
-	{
-		.name		= "connmark",
-		.revision	= 0,
-		.family		= AF_INET6,
+		.family		= NFPROTO_UNSPEC,
 		.checkentry	= connmark_mt_check_v0,
 		.match		= connmark_mt_v0,
 		.destroy	= connmark_mt_destroy,
@@ -170,17 +142,7 @@
 	{
 		.name           = "connmark",
 		.revision       = 1,
-		.family         = AF_INET,
-		.checkentry     = connmark_mt_check,
-		.match          = connmark_mt,
-		.matchsize      = sizeof(struct xt_connmark_mtinfo1),
-		.destroy        = connmark_mt_destroy,
-		.me             = THIS_MODULE,
-	},
-	{
-		.name           = "connmark",
-		.revision       = 1,
-		.family         = AF_INET6,
+		.family         = NFPROTO_UNSPEC,
 		.checkentry     = connmark_mt_check,
 		.match          = connmark_mt,
 		.matchsize      = sizeof(struct xt_connmark_mtinfo1),
diff --git a/net/netfilter/xt_conntrack.c b/net/netfilter/xt_conntrack.c
index d61412f..0b7139f 100644
--- a/net/netfilter/xt_conntrack.c
+++ b/net/netfilter/xt_conntrack.c
@@ -25,12 +25,9 @@
 MODULE_ALIAS("ip6t_conntrack");
 
 static bool
-conntrack_mt_v0(const struct sk_buff *skb, const struct net_device *in,
-                const struct net_device *out, const struct xt_match *match,
-                const void *matchinfo, int offset, unsigned int protoff,
-                bool *hotdrop)
+conntrack_mt_v0(const struct sk_buff *skb, const struct xt_match_param *par)
 {
-	const struct xt_conntrack_info *sinfo = matchinfo;
+	const struct xt_conntrack_info *sinfo = par->matchinfo;
 	const struct nf_conn *ct;
 	enum ip_conntrack_info ctinfo;
 	unsigned int statebit;
@@ -121,9 +118,9 @@
                   const union nf_inet_addr *uaddr,
                   const union nf_inet_addr *umask, unsigned int l3proto)
 {
-	if (l3proto == AF_INET)
+	if (l3proto == NFPROTO_IPV4)
 		return ((kaddr->ip ^ uaddr->ip) & umask->ip) == 0;
-	else if (l3proto == AF_INET6)
+	else if (l3proto == NFPROTO_IPV6)
 		return ipv6_masked_addr_cmp(&kaddr->in6, &umask->in6,
 		       &uaddr->in6) == 0;
 	else
@@ -133,7 +130,7 @@
 static inline bool
 conntrack_mt_origsrc(const struct nf_conn *ct,
                      const struct xt_conntrack_mtinfo1 *info,
-                     unsigned int family)
+		     u_int8_t family)
 {
 	return conntrack_addrcmp(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3,
 	       &info->origsrc_addr, &info->origsrc_mask, family);
@@ -142,7 +139,7 @@
 static inline bool
 conntrack_mt_origdst(const struct nf_conn *ct,
                      const struct xt_conntrack_mtinfo1 *info,
-                     unsigned int family)
+		     u_int8_t family)
 {
 	return conntrack_addrcmp(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u3,
 	       &info->origdst_addr, &info->origdst_mask, family);
@@ -151,7 +148,7 @@
 static inline bool
 conntrack_mt_replsrc(const struct nf_conn *ct,
                      const struct xt_conntrack_mtinfo1 *info,
-                     unsigned int family)
+		     u_int8_t family)
 {
 	return conntrack_addrcmp(&ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u3,
 	       &info->replsrc_addr, &info->replsrc_mask, family);
@@ -160,7 +157,7 @@
 static inline bool
 conntrack_mt_repldst(const struct nf_conn *ct,
                      const struct xt_conntrack_mtinfo1 *info,
-                     unsigned int family)
+		     u_int8_t family)
 {
 	return conntrack_addrcmp(&ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3,
 	       &info->repldst_addr, &info->repldst_mask, family);
@@ -205,12 +202,9 @@
 }
 
 static bool
-conntrack_mt(const struct sk_buff *skb, const struct net_device *in,
-             const struct net_device *out, const struct xt_match *match,
-             const void *matchinfo, int offset, unsigned int protoff,
-             bool *hotdrop)
+conntrack_mt(const struct sk_buff *skb, const struct xt_match_param *par)
 {
-	const struct xt_conntrack_mtinfo1 *info = matchinfo;
+	const struct xt_conntrack_mtinfo1 *info = par->matchinfo;
 	enum ip_conntrack_info ctinfo;
 	const struct nf_conn *ct;
 	unsigned int statebit;
@@ -244,22 +238,22 @@
 		return false;
 
 	if (info->match_flags & XT_CONNTRACK_ORIGSRC)
-		if (conntrack_mt_origsrc(ct, info, match->family) ^
+		if (conntrack_mt_origsrc(ct, info, par->family) ^
 		    !(info->invert_flags & XT_CONNTRACK_ORIGSRC))
 			return false;
 
 	if (info->match_flags & XT_CONNTRACK_ORIGDST)
-		if (conntrack_mt_origdst(ct, info, match->family) ^
+		if (conntrack_mt_origdst(ct, info, par->family) ^
 		    !(info->invert_flags & XT_CONNTRACK_ORIGDST))
 			return false;
 
 	if (info->match_flags & XT_CONNTRACK_REPLSRC)
-		if (conntrack_mt_replsrc(ct, info, match->family) ^
+		if (conntrack_mt_replsrc(ct, info, par->family) ^
 		    !(info->invert_flags & XT_CONNTRACK_REPLSRC))
 			return false;
 
 	if (info->match_flags & XT_CONNTRACK_REPLDST)
-		if (conntrack_mt_repldst(ct, info, match->family) ^
+		if (conntrack_mt_repldst(ct, info, par->family) ^
 		    !(info->invert_flags & XT_CONNTRACK_REPLDST))
 			return false;
 
@@ -284,23 +278,19 @@
 	return true;
 }
 
-static bool
-conntrack_mt_check(const char *tablename, const void *ip,
-                   const struct xt_match *match, void *matchinfo,
-                   unsigned int hook_mask)
+static bool conntrack_mt_check(const struct xt_mtchk_param *par)
 {
-	if (nf_ct_l3proto_try_module_get(match->family) < 0) {
+	if (nf_ct_l3proto_try_module_get(par->family) < 0) {
 		printk(KERN_WARNING "can't load conntrack support for "
-				    "proto=%u\n", match->family);
+				    "proto=%u\n", par->family);
 		return false;
 	}
 	return true;
 }
 
-static void
-conntrack_mt_destroy(const struct xt_match *match, void *matchinfo)
+static void conntrack_mt_destroy(const struct xt_mtdtor_param *par)
 {
-	nf_ct_l3proto_module_put(match->family);
+	nf_ct_l3proto_module_put(par->family);
 }
 
 #ifdef CONFIG_COMPAT
@@ -356,7 +346,7 @@
 	{
 		.name       = "conntrack",
 		.revision   = 0,
-		.family     = AF_INET,
+		.family     = NFPROTO_IPV4,
 		.match      = conntrack_mt_v0,
 		.checkentry = conntrack_mt_check,
 		.destroy    = conntrack_mt_destroy,
@@ -371,17 +361,7 @@
 	{
 		.name       = "conntrack",
 		.revision   = 1,
-		.family     = AF_INET,
-		.matchsize  = sizeof(struct xt_conntrack_mtinfo1),
-		.match      = conntrack_mt,
-		.checkentry = conntrack_mt_check,
-		.destroy    = conntrack_mt_destroy,
-		.me         = THIS_MODULE,
-	},
-	{
-		.name       = "conntrack",
-		.revision   = 1,
-		.family     = AF_INET6,
+		.family     = NFPROTO_UNSPEC,
 		.matchsize  = sizeof(struct xt_conntrack_mtinfo1),
 		.match      = conntrack_mt,
 		.checkentry = conntrack_mt_check,
diff --git a/net/netfilter/xt_dccp.c b/net/netfilter/xt_dccp.c
index 8b65221..e5d3e86 100644
--- a/net/netfilter/xt_dccp.c
+++ b/net/netfilter/xt_dccp.c
@@ -93,20 +93,18 @@
 }
 
 static bool
-dccp_mt(const struct sk_buff *skb, const struct net_device *in,
-        const struct net_device *out, const struct xt_match *match,
-        const void *matchinfo, int offset, unsigned int protoff, bool *hotdrop)
+dccp_mt(const struct sk_buff *skb, const struct xt_match_param *par)
 {
-	const struct xt_dccp_info *info = matchinfo;
+	const struct xt_dccp_info *info = par->matchinfo;
 	const struct dccp_hdr *dh;
 	struct dccp_hdr _dh;
 
-	if (offset)
+	if (par->fragoff != 0)
 		return false;
 
-	dh = skb_header_pointer(skb, protoff, sizeof(_dh), &_dh);
+	dh = skb_header_pointer(skb, par->thoff, sizeof(_dh), &_dh);
 	if (dh == NULL) {
-		*hotdrop = true;
+		*par->hotdrop = true;
 		return false;
 	}
 
@@ -118,17 +116,14 @@
 			XT_DCCP_DEST_PORTS, info->flags, info->invflags)
 		&& DCCHECK(match_types(dh, info->typemask),
 			   XT_DCCP_TYPE, info->flags, info->invflags)
-		&& DCCHECK(match_option(info->option, skb, protoff, dh,
-					hotdrop),
+		&& DCCHECK(match_option(info->option, skb, par->thoff, dh,
+					par->hotdrop),
 			   XT_DCCP_OPTION, info->flags, info->invflags);
 }
 
-static bool
-dccp_mt_check(const char *tablename, const void *inf,
-              const struct xt_match *match, void *matchinfo,
-              unsigned int hook_mask)
+static bool dccp_mt_check(const struct xt_mtchk_param *par)
 {
-	const struct xt_dccp_info *info = matchinfo;
+	const struct xt_dccp_info *info = par->matchinfo;
 
 	return !(info->flags & ~XT_DCCP_VALID_FLAGS)
 		&& !(info->invflags & ~XT_DCCP_VALID_FLAGS)
@@ -138,7 +133,7 @@
 static struct xt_match dccp_mt_reg[] __read_mostly = {
 	{
 		.name 		= "dccp",
-		.family		= AF_INET,
+		.family		= NFPROTO_IPV4,
 		.checkentry	= dccp_mt_check,
 		.match		= dccp_mt,
 		.matchsize	= sizeof(struct xt_dccp_info),
@@ -147,7 +142,7 @@
 	},
 	{
 		.name 		= "dccp",
-		.family		= AF_INET6,
+		.family		= NFPROTO_IPV6,
 		.checkentry	= dccp_mt_check,
 		.match		= dccp_mt,
 		.matchsize	= sizeof(struct xt_dccp_info),
diff --git a/net/netfilter/xt_dscp.c b/net/netfilter/xt_dscp.c
index 26f4aab..c3f8085 100644
--- a/net/netfilter/xt_dscp.c
+++ b/net/netfilter/xt_dscp.c
@@ -26,61 +26,48 @@
 MODULE_ALIAS("ip6t_tos");
 
 static bool
-dscp_mt(const struct sk_buff *skb, const struct net_device *in,
-        const struct net_device *out, const struct xt_match *match,
-        const void *matchinfo, int offset, unsigned int protoff, bool *hotdrop)
+dscp_mt(const struct sk_buff *skb, const struct xt_match_param *par)
 {
-	const struct xt_dscp_info *info = matchinfo;
+	const struct xt_dscp_info *info = par->matchinfo;
 	u_int8_t dscp = ipv4_get_dsfield(ip_hdr(skb)) >> XT_DSCP_SHIFT;
 
 	return (dscp == info->dscp) ^ !!info->invert;
 }
 
 static bool
-dscp_mt6(const struct sk_buff *skb, const struct net_device *in,
-         const struct net_device *out, const struct xt_match *match,
-         const void *matchinfo, int offset, unsigned int protoff,
-         bool *hotdrop)
+dscp_mt6(const struct sk_buff *skb, const struct xt_match_param *par)
 {
-	const struct xt_dscp_info *info = matchinfo;
+	const struct xt_dscp_info *info = par->matchinfo;
 	u_int8_t dscp = ipv6_get_dsfield(ipv6_hdr(skb)) >> XT_DSCP_SHIFT;
 
 	return (dscp == info->dscp) ^ !!info->invert;
 }
 
-static bool
-dscp_mt_check(const char *tablename, const void *info,
-              const struct xt_match *match, void *matchinfo,
-              unsigned int hook_mask)
+static bool dscp_mt_check(const struct xt_mtchk_param *par)
 {
-	const u_int8_t dscp = ((struct xt_dscp_info *)matchinfo)->dscp;
+	const struct xt_dscp_info *info = par->matchinfo;
 
-	if (dscp > XT_DSCP_MAX) {
-		printk(KERN_ERR "xt_dscp: dscp %x out of range\n", dscp);
+	if (info->dscp > XT_DSCP_MAX) {
+		printk(KERN_ERR "xt_dscp: dscp %x out of range\n", info->dscp);
 		return false;
 	}
 
 	return true;
 }
 
-static bool tos_mt_v0(const struct sk_buff *skb, const struct net_device *in,
-                      const struct net_device *out,
-                      const struct xt_match *match, const void *matchinfo,
-                      int offset, unsigned int protoff, bool *hotdrop)
+static bool
+tos_mt_v0(const struct sk_buff *skb, const struct xt_match_param *par)
 {
-	const struct ipt_tos_info *info = matchinfo;
+	const struct ipt_tos_info *info = par->matchinfo;
 
 	return (ip_hdr(skb)->tos == info->tos) ^ info->invert;
 }
 
-static bool tos_mt(const struct sk_buff *skb, const struct net_device *in,
-                   const struct net_device *out, const struct xt_match *match,
-                   const void *matchinfo, int offset, unsigned int protoff,
-                   bool *hotdrop)
+static bool tos_mt(const struct sk_buff *skb, const struct xt_match_param *par)
 {
-	const struct xt_tos_match_info *info = matchinfo;
+	const struct xt_tos_match_info *info = par->matchinfo;
 
-	if (match->family == AF_INET)
+	if (par->match->family == NFPROTO_IPV4)
 		return ((ip_hdr(skb)->tos & info->tos_mask) ==
 		       info->tos_value) ^ !!info->invert;
 	else
@@ -91,7 +78,7 @@
 static struct xt_match dscp_mt_reg[] __read_mostly = {
 	{
 		.name		= "dscp",
-		.family		= AF_INET,
+		.family		= NFPROTO_IPV4,
 		.checkentry	= dscp_mt_check,
 		.match		= dscp_mt,
 		.matchsize	= sizeof(struct xt_dscp_info),
@@ -99,7 +86,7 @@
 	},
 	{
 		.name		= "dscp",
-		.family		= AF_INET6,
+		.family		= NFPROTO_IPV6,
 		.checkentry	= dscp_mt_check,
 		.match		= dscp_mt6,
 		.matchsize	= sizeof(struct xt_dscp_info),
@@ -108,7 +95,7 @@
 	{
 		.name		= "tos",
 		.revision	= 0,
-		.family		= AF_INET,
+		.family		= NFPROTO_IPV4,
 		.match		= tos_mt_v0,
 		.matchsize	= sizeof(struct ipt_tos_info),
 		.me		= THIS_MODULE,
@@ -116,7 +103,7 @@
 	{
 		.name		= "tos",
 		.revision	= 1,
-		.family		= AF_INET,
+		.family		= NFPROTO_IPV4,
 		.match		= tos_mt,
 		.matchsize	= sizeof(struct xt_tos_match_info),
 		.me		= THIS_MODULE,
@@ -124,7 +111,7 @@
 	{
 		.name		= "tos",
 		.revision	= 1,
-		.family		= AF_INET6,
+		.family		= NFPROTO_IPV6,
 		.match		= tos_mt,
 		.matchsize	= sizeof(struct xt_tos_match_info),
 		.me		= THIS_MODULE,
diff --git a/net/netfilter/xt_esp.c b/net/netfilter/xt_esp.c
index a133eb9..6094399 100644
--- a/net/netfilter/xt_esp.c
+++ b/net/netfilter/xt_esp.c
@@ -42,26 +42,23 @@
 	return r;
 }
 
-static bool
-esp_mt(const struct sk_buff *skb, const struct net_device *in,
-       const struct net_device *out, const struct xt_match *match,
-       const void *matchinfo, int offset, unsigned int protoff, bool *hotdrop)
+static bool esp_mt(const struct sk_buff *skb, const struct xt_match_param *par)
 {
 	const struct ip_esp_hdr *eh;
 	struct ip_esp_hdr _esp;
-	const struct xt_esp *espinfo = matchinfo;
+	const struct xt_esp *espinfo = par->matchinfo;
 
 	/* Must not be a fragment. */
-	if (offset)
+	if (par->fragoff != 0)
 		return false;
 
-	eh = skb_header_pointer(skb, protoff, sizeof(_esp), &_esp);
+	eh = skb_header_pointer(skb, par->thoff, sizeof(_esp), &_esp);
 	if (eh == NULL) {
 		/* We've been asked to examine this packet, and we
 		 * can't.  Hence, no choice but to drop.
 		 */
 		duprintf("Dropping evil ESP tinygram.\n");
-		*hotdrop = true;
+		*par->hotdrop = true;
 		return false;
 	}
 
@@ -69,13 +66,9 @@
 			 !!(espinfo->invflags & XT_ESP_INV_SPI));
 }
 
-/* Called when user tries to insert an entry of this type. */
-static bool
-esp_mt_check(const char *tablename, const void *ip_void,
-             const struct xt_match *match, void *matchinfo,
-             unsigned int hook_mask)
+static bool esp_mt_check(const struct xt_mtchk_param *par)
 {
-	const struct xt_esp *espinfo = matchinfo;
+	const struct xt_esp *espinfo = par->matchinfo;
 
 	if (espinfo->invflags & ~XT_ESP_INV_MASK) {
 		duprintf("xt_esp: unknown flags %X\n", espinfo->invflags);
@@ -88,7 +81,7 @@
 static struct xt_match esp_mt_reg[] __read_mostly = {
 	{
 		.name		= "esp",
-		.family		= AF_INET,
+		.family		= NFPROTO_IPV4,
 		.checkentry	= esp_mt_check,
 		.match		= esp_mt,
 		.matchsize	= sizeof(struct xt_esp),
@@ -97,7 +90,7 @@
 	},
 	{
 		.name		= "esp",
-		.family		= AF_INET6,
+		.family		= NFPROTO_IPV6,
 		.checkentry	= esp_mt_check,
 		.match		= esp_mt,
 		.matchsize	= sizeof(struct xt_esp),
diff --git a/net/netfilter/xt_hashlimit.c b/net/netfilter/xt_hashlimit.c
index d9418a2..6fc4292 100644
--- a/net/netfilter/xt_hashlimit.c
+++ b/net/netfilter/xt_hashlimit.c
@@ -80,7 +80,7 @@
 struct xt_hashlimit_htable {
 	struct hlist_node node;		/* global list of all htables */
 	atomic_t use;
-	int family;
+	u_int8_t family;
 
 	struct hashlimit_cfg1 cfg;	/* config */
 
@@ -185,7 +185,7 @@
 }
 static void htable_gc(unsigned long htlong);
 
-static int htable_create_v0(struct xt_hashlimit_info *minfo, int family)
+static int htable_create_v0(struct xt_hashlimit_info *minfo, u_int8_t family)
 {
 	struct xt_hashlimit_htable *hinfo;
 	unsigned int size;
@@ -218,7 +218,7 @@
 	hinfo->cfg.gc_interval = minfo->cfg.gc_interval;
 	hinfo->cfg.expire      = minfo->cfg.expire;
 
-	if (family == AF_INET)
+	if (family == NFPROTO_IPV4)
 		hinfo->cfg.srcmask = hinfo->cfg.dstmask = 32;
 	else
 		hinfo->cfg.srcmask = hinfo->cfg.dstmask = 128;
@@ -237,11 +237,10 @@
 	hinfo->family = family;
 	hinfo->rnd_initialized = 0;
 	spin_lock_init(&hinfo->lock);
-	hinfo->pde =
-		proc_create_data(minfo->name, 0,
-				 family == AF_INET ? hashlimit_procdir4 :
-						     hashlimit_procdir6,
-				 &dl_file_ops, hinfo);
+	hinfo->pde = proc_create_data(minfo->name, 0,
+		(family == NFPROTO_IPV4) ?
+		hashlimit_procdir4 : hashlimit_procdir6,
+		&dl_file_ops, hinfo);
 	if (!hinfo->pde) {
 		vfree(hinfo);
 		return -1;
@@ -258,8 +257,7 @@
 	return 0;
 }
 
-static int htable_create(struct xt_hashlimit_mtinfo1 *minfo,
-                         unsigned int family)
+static int htable_create(struct xt_hashlimit_mtinfo1 *minfo, u_int8_t family)
 {
 	struct xt_hashlimit_htable *hinfo;
 	unsigned int size;
@@ -301,11 +299,10 @@
 	hinfo->rnd_initialized = 0;
 	spin_lock_init(&hinfo->lock);
 
-	hinfo->pde =
-		proc_create_data(minfo->name, 0,
-				 family == AF_INET ? hashlimit_procdir4 :
-						     hashlimit_procdir6,
-				 &dl_file_ops, hinfo);
+	hinfo->pde = proc_create_data(minfo->name, 0,
+		(family == NFPROTO_IPV4) ?
+		hashlimit_procdir4 : hashlimit_procdir6,
+		&dl_file_ops, hinfo);
 	if (hinfo->pde == NULL) {
 		vfree(hinfo);
 		return -1;
@@ -371,14 +368,14 @@
 
 	/* remove proc entry */
 	remove_proc_entry(hinfo->pde->name,
-			  hinfo->family == AF_INET ? hashlimit_procdir4 :
+			  hinfo->family == NFPROTO_IPV4 ? hashlimit_procdir4 :
 						     hashlimit_procdir6);
 	htable_selective_cleanup(hinfo, select_all);
 	vfree(hinfo);
 }
 
 static struct xt_hashlimit_htable *htable_find_get(const char *name,
-						   int family)
+						   u_int8_t family)
 {
 	struct xt_hashlimit_htable *hinfo;
 	struct hlist_node *pos;
@@ -502,7 +499,7 @@
 	memset(dst, 0, sizeof(*dst));
 
 	switch (hinfo->family) {
-	case AF_INET:
+	case NFPROTO_IPV4:
 		if (hinfo->cfg.mode & XT_HASHLIMIT_HASH_DIP)
 			dst->ip.dst = maskl(ip_hdr(skb)->daddr,
 			              hinfo->cfg.dstmask);
@@ -516,7 +513,7 @@
 		nexthdr = ip_hdr(skb)->protocol;
 		break;
 #if defined(CONFIG_IP6_NF_IPTABLES) || defined(CONFIG_IP6_NF_IPTABLES_MODULE)
-	case AF_INET6:
+	case NFPROTO_IPV6:
 		if (hinfo->cfg.mode & XT_HASHLIMIT_HASH_DIP) {
 			memcpy(&dst->ip6.dst, &ipv6_hdr(skb)->daddr,
 			       sizeof(dst->ip6.dst));
@@ -566,19 +563,16 @@
 }
 
 static bool
-hashlimit_mt_v0(const struct sk_buff *skb, const struct net_device *in,
-                const struct net_device *out, const struct xt_match *match,
-                const void *matchinfo, int offset, unsigned int protoff,
-                bool *hotdrop)
+hashlimit_mt_v0(const struct sk_buff *skb, const struct xt_match_param *par)
 {
 	const struct xt_hashlimit_info *r =
-		((const struct xt_hashlimit_info *)matchinfo)->u.master;
+		((const struct xt_hashlimit_info *)par->matchinfo)->u.master;
 	struct xt_hashlimit_htable *hinfo = r->hinfo;
 	unsigned long now = jiffies;
 	struct dsthash_ent *dh;
 	struct dsthash_dst dst;
 
-	if (hashlimit_init_dst(hinfo, &dst, skb, protoff) < 0)
+	if (hashlimit_init_dst(hinfo, &dst, skb, par->thoff) < 0)
 		goto hotdrop;
 
 	spin_lock_bh(&hinfo->lock);
@@ -616,23 +610,20 @@
 	return false;
 
 hotdrop:
-	*hotdrop = true;
+	*par->hotdrop = true;
 	return false;
 }
 
 static bool
-hashlimit_mt(const struct sk_buff *skb, const struct net_device *in,
-             const struct net_device *out, const struct xt_match *match,
-             const void *matchinfo, int offset, unsigned int protoff,
-             bool *hotdrop)
+hashlimit_mt(const struct sk_buff *skb, const struct xt_match_param *par)
 {
-	const struct xt_hashlimit_mtinfo1 *info = matchinfo;
+	const struct xt_hashlimit_mtinfo1 *info = par->matchinfo;
 	struct xt_hashlimit_htable *hinfo = info->hinfo;
 	unsigned long now = jiffies;
 	struct dsthash_ent *dh;
 	struct dsthash_dst dst;
 
-	if (hashlimit_init_dst(hinfo, &dst, skb, protoff) < 0)
+	if (hashlimit_init_dst(hinfo, &dst, skb, par->thoff) < 0)
 		goto hotdrop;
 
 	spin_lock_bh(&hinfo->lock);
@@ -669,16 +660,13 @@
 	return info->cfg.mode & XT_HASHLIMIT_INVERT;
 
  hotdrop:
-	*hotdrop = true;
+	*par->hotdrop = true;
 	return false;
 }
 
-static bool
-hashlimit_mt_check_v0(const char *tablename, const void *inf,
-                      const struct xt_match *match, void *matchinfo,
-                      unsigned int hook_mask)
+static bool hashlimit_mt_check_v0(const struct xt_mtchk_param *par)
 {
-	struct xt_hashlimit_info *r = matchinfo;
+	struct xt_hashlimit_info *r = par->matchinfo;
 
 	/* Check for overflow. */
 	if (r->cfg.burst == 0 ||
@@ -707,8 +695,8 @@
 	 * the list of htable's in htable_create(), since then we would
 	 * create duplicate proc files. -HW */
 	mutex_lock(&hlimit_mutex);
-	r->hinfo = htable_find_get(r->name, match->family);
-	if (!r->hinfo && htable_create_v0(r, match->family) != 0) {
+	r->hinfo = htable_find_get(r->name, par->match->family);
+	if (!r->hinfo && htable_create_v0(r, par->match->family) != 0) {
 		mutex_unlock(&hlimit_mutex);
 		return false;
 	}
@@ -719,12 +707,9 @@
 	return true;
 }
 
-static bool
-hashlimit_mt_check(const char *tablename, const void *inf,
-                   const struct xt_match *match, void *matchinfo,
-                   unsigned int hook_mask)
+static bool hashlimit_mt_check(const struct xt_mtchk_param *par)
 {
-	struct xt_hashlimit_mtinfo1 *info = matchinfo;
+	struct xt_hashlimit_mtinfo1 *info = par->matchinfo;
 
 	/* Check for overflow. */
 	if (info->cfg.burst == 0 ||
@@ -738,7 +723,7 @@
 		return false;
 	if (info->name[sizeof(info->name)-1] != '\0')
 		return false;
-	if (match->family == AF_INET) {
+	if (par->match->family == NFPROTO_IPV4) {
 		if (info->cfg.srcmask > 32 || info->cfg.dstmask > 32)
 			return false;
 	} else {
@@ -753,8 +738,8 @@
 	 * the list of htable's in htable_create(), since then we would
 	 * create duplicate proc files. -HW */
 	mutex_lock(&hlimit_mutex);
-	info->hinfo = htable_find_get(info->name, match->family);
-	if (!info->hinfo && htable_create(info, match->family) != 0) {
+	info->hinfo = htable_find_get(info->name, par->match->family);
+	if (!info->hinfo && htable_create(info, par->match->family) != 0) {
 		mutex_unlock(&hlimit_mutex);
 		return false;
 	}
@@ -763,17 +748,16 @@
 }
 
 static void
-hashlimit_mt_destroy_v0(const struct xt_match *match, void *matchinfo)
+hashlimit_mt_destroy_v0(const struct xt_mtdtor_param *par)
 {
-	const struct xt_hashlimit_info *r = matchinfo;
+	const struct xt_hashlimit_info *r = par->matchinfo;
 
 	htable_put(r->hinfo);
 }
 
-static void
-hashlimit_mt_destroy(const struct xt_match *match, void *matchinfo)
+static void hashlimit_mt_destroy(const struct xt_mtdtor_param *par)
 {
-	const struct xt_hashlimit_mtinfo1 *info = matchinfo;
+	const struct xt_hashlimit_mtinfo1 *info = par->matchinfo;
 
 	htable_put(info->hinfo);
 }
@@ -806,7 +790,7 @@
 	{
 		.name		= "hashlimit",
 		.revision	= 0,
-		.family		= AF_INET,
+		.family		= NFPROTO_IPV4,
 		.match		= hashlimit_mt_v0,
 		.matchsize	= sizeof(struct xt_hashlimit_info),
 #ifdef CONFIG_COMPAT
@@ -821,7 +805,7 @@
 	{
 		.name           = "hashlimit",
 		.revision       = 1,
-		.family         = AF_INET,
+		.family         = NFPROTO_IPV4,
 		.match          = hashlimit_mt,
 		.matchsize      = sizeof(struct xt_hashlimit_mtinfo1),
 		.checkentry     = hashlimit_mt_check,
@@ -831,7 +815,7 @@
 #if defined(CONFIG_IP6_NF_IPTABLES) || defined(CONFIG_IP6_NF_IPTABLES_MODULE)
 	{
 		.name		= "hashlimit",
-		.family		= AF_INET6,
+		.family		= NFPROTO_IPV6,
 		.match		= hashlimit_mt_v0,
 		.matchsize	= sizeof(struct xt_hashlimit_info),
 #ifdef CONFIG_COMPAT
@@ -846,7 +830,7 @@
 	{
 		.name           = "hashlimit",
 		.revision       = 1,
-		.family         = AF_INET6,
+		.family         = NFPROTO_IPV6,
 		.match          = hashlimit_mt,
 		.matchsize      = sizeof(struct xt_hashlimit_mtinfo1),
 		.checkentry     = hashlimit_mt_check,
@@ -901,14 +885,14 @@
 	spin_unlock_bh(&htable->lock);
 }
 
-static int dl_seq_real_show(struct dsthash_ent *ent, int family,
+static int dl_seq_real_show(struct dsthash_ent *ent, u_int8_t family,
 				   struct seq_file *s)
 {
 	/* recalculate to show accurate numbers */
 	rateinfo_recalc(ent, jiffies);
 
 	switch (family) {
-	case AF_INET:
+	case NFPROTO_IPV4:
 		return seq_printf(s, "%ld %u.%u.%u.%u:%u->"
 				     "%u.%u.%u.%u:%u %u %u %u\n",
 				 (long)(ent->expires - jiffies)/HZ,
@@ -919,7 +903,7 @@
 				 ent->rateinfo.credit, ent->rateinfo.credit_cap,
 				 ent->rateinfo.cost);
 #if defined(CONFIG_IP6_NF_IPTABLES) || defined(CONFIG_IP6_NF_IPTABLES_MODULE)
-	case AF_INET6:
+	case NFPROTO_IPV6:
 		return seq_printf(s, "%ld " NIP6_FMT ":%u->"
 				     NIP6_FMT ":%u %u %u %u\n",
 				 (long)(ent->expires - jiffies)/HZ,
diff --git a/net/netfilter/xt_helper.c b/net/netfilter/xt_helper.c
index dada290..64fc7f2 100644
--- a/net/netfilter/xt_helper.c
+++ b/net/netfilter/xt_helper.c
@@ -24,12 +24,9 @@
 
 
 static bool
-helper_mt(const struct sk_buff *skb, const struct net_device *in,
-          const struct net_device *out, const struct xt_match *match,
-          const void *matchinfo, int offset, unsigned int protoff,
-          bool *hotdrop)
+helper_mt(const struct sk_buff *skb, const struct xt_match_param *par)
 {
-	const struct xt_helper_info *info = matchinfo;
+	const struct xt_helper_info *info = par->matchinfo;
 	const struct nf_conn *ct;
 	const struct nf_conn_help *master_help;
 	const struct nf_conntrack_helper *helper;
@@ -57,56 +54,43 @@
 	return ret;
 }
 
-static bool
-helper_mt_check(const char *tablename, const void *inf,
-                const struct xt_match *match, void *matchinfo,
-                unsigned int hook_mask)
+static bool helper_mt_check(const struct xt_mtchk_param *par)
 {
-	struct xt_helper_info *info = matchinfo;
+	struct xt_helper_info *info = par->matchinfo;
 
-	if (nf_ct_l3proto_try_module_get(match->family) < 0) {
+	if (nf_ct_l3proto_try_module_get(par->family) < 0) {
 		printk(KERN_WARNING "can't load conntrack support for "
-				    "proto=%u\n", match->family);
+				    "proto=%u\n", par->family);
 		return false;
 	}
 	info->name[29] = '\0';
 	return true;
 }
 
-static void helper_mt_destroy(const struct xt_match *match, void *matchinfo)
+static void helper_mt_destroy(const struct xt_mtdtor_param *par)
 {
-	nf_ct_l3proto_module_put(match->family);
+	nf_ct_l3proto_module_put(par->family);
 }
 
-static struct xt_match helper_mt_reg[] __read_mostly = {
-	{
-		.name		= "helper",
-		.family		= AF_INET,
-		.checkentry	= helper_mt_check,
-		.match		= helper_mt,
-		.destroy	= helper_mt_destroy,
-		.matchsize	= sizeof(struct xt_helper_info),
-		.me		= THIS_MODULE,
-	},
-	{
-		.name		= "helper",
-		.family		= AF_INET6,
-		.checkentry	= helper_mt_check,
-		.match		= helper_mt,
-		.destroy	= helper_mt_destroy,
-		.matchsize	= sizeof(struct xt_helper_info),
-		.me		= THIS_MODULE,
-	},
+static struct xt_match helper_mt_reg __read_mostly = {
+	.name       = "helper",
+	.revision   = 0,
+	.family     = NFPROTO_UNSPEC,
+	.checkentry = helper_mt_check,
+	.match      = helper_mt,
+	.destroy    = helper_mt_destroy,
+	.matchsize  = sizeof(struct xt_helper_info),
+	.me         = THIS_MODULE,
 };
 
 static int __init helper_mt_init(void)
 {
-	return xt_register_matches(helper_mt_reg, ARRAY_SIZE(helper_mt_reg));
+	return xt_register_match(&helper_mt_reg);
 }
 
 static void __exit helper_mt_exit(void)
 {
-	xt_unregister_matches(helper_mt_reg, ARRAY_SIZE(helper_mt_reg));
+	xt_unregister_match(&helper_mt_reg);
 }
 
 module_init(helper_mt_init);
diff --git a/net/netfilter/xt_iprange.c b/net/netfilter/xt_iprange.c
index c63e933..6f62c36 100644
--- a/net/netfilter/xt_iprange.c
+++ b/net/netfilter/xt_iprange.c
@@ -17,12 +17,9 @@
 #include <linux/netfilter_ipv4/ipt_iprange.h>
 
 static bool
-iprange_mt_v0(const struct sk_buff *skb, const struct net_device *in,
-              const struct net_device *out, const struct xt_match *match,
-              const void *matchinfo, int offset, unsigned int protoff,
-              bool *hotdrop)
+iprange_mt_v0(const struct sk_buff *skb, const struct xt_match_param *par)
 {
-	const struct ipt_iprange_info *info = matchinfo;
+	const struct ipt_iprange_info *info = par->matchinfo;
 	const struct iphdr *iph = ip_hdr(skb);
 
 	if (info->flags & IPRANGE_SRC) {
@@ -55,12 +52,9 @@
 }
 
 static bool
-iprange_mt4(const struct sk_buff *skb, const struct net_device *in,
-            const struct net_device *out, const struct xt_match *match,
-            const void *matchinfo, int offset, unsigned int protoff,
-            bool *hotdrop)
+iprange_mt4(const struct sk_buff *skb, const struct xt_match_param *par)
 {
-	const struct xt_iprange_mtinfo *info = matchinfo;
+	const struct xt_iprange_mtinfo *info = par->matchinfo;
 	const struct iphdr *iph = ip_hdr(skb);
 	bool m;
 
@@ -111,12 +105,9 @@
 }
 
 static bool
-iprange_mt6(const struct sk_buff *skb, const struct net_device *in,
-            const struct net_device *out, const struct xt_match *match,
-            const void *matchinfo, int offset, unsigned int protoff,
-            bool *hotdrop)
+iprange_mt6(const struct sk_buff *skb, const struct xt_match_param *par)
 {
-	const struct xt_iprange_mtinfo *info = matchinfo;
+	const struct xt_iprange_mtinfo *info = par->matchinfo;
 	const struct ipv6hdr *iph = ipv6_hdr(skb);
 	bool m;
 
@@ -141,7 +132,7 @@
 	{
 		.name      = "iprange",
 		.revision  = 0,
-		.family    = AF_INET,
+		.family    = NFPROTO_IPV4,
 		.match     = iprange_mt_v0,
 		.matchsize = sizeof(struct ipt_iprange_info),
 		.me        = THIS_MODULE,
@@ -149,7 +140,7 @@
 	{
 		.name      = "iprange",
 		.revision  = 1,
-		.family    = AF_INET,
+		.family    = NFPROTO_IPV4,
 		.match     = iprange_mt4,
 		.matchsize = sizeof(struct xt_iprange_mtinfo),
 		.me        = THIS_MODULE,
@@ -157,7 +148,7 @@
 	{
 		.name      = "iprange",
 		.revision  = 1,
-		.family    = AF_INET6,
+		.family    = NFPROTO_IPV6,
 		.match     = iprange_mt6,
 		.matchsize = sizeof(struct xt_iprange_mtinfo),
 		.me        = THIS_MODULE,
diff --git a/net/netfilter/xt_length.c b/net/netfilter/xt_length.c
index b8640f9..c4871ca 100644
--- a/net/netfilter/xt_length.c
+++ b/net/netfilter/xt_length.c
@@ -21,24 +21,18 @@
 MODULE_ALIAS("ip6t_length");
 
 static bool
-length_mt(const struct sk_buff *skb, const struct net_device *in,
-          const struct net_device *out, const struct xt_match *match,
-          const void *matchinfo, int offset, unsigned int protoff,
-          bool *hotdrop)
+length_mt(const struct sk_buff *skb, const struct xt_match_param *par)
 {
-	const struct xt_length_info *info = matchinfo;
+	const struct xt_length_info *info = par->matchinfo;
 	u_int16_t pktlen = ntohs(ip_hdr(skb)->tot_len);
 
 	return (pktlen >= info->min && pktlen <= info->max) ^ info->invert;
 }
 
 static bool
-length_mt6(const struct sk_buff *skb, const struct net_device *in,
-           const struct net_device *out, const struct xt_match *match,
-           const void *matchinfo, int offset, unsigned int protoff,
-           bool *hotdrop)
+length_mt6(const struct sk_buff *skb, const struct xt_match_param *par)
 {
-	const struct xt_length_info *info = matchinfo;
+	const struct xt_length_info *info = par->matchinfo;
 	const u_int16_t pktlen = ntohs(ipv6_hdr(skb)->payload_len) +
 				 sizeof(struct ipv6hdr);
 
@@ -48,14 +42,14 @@
 static struct xt_match length_mt_reg[] __read_mostly = {
 	{
 		.name		= "length",
-		.family		= AF_INET,
+		.family		= NFPROTO_IPV4,
 		.match		= length_mt,
 		.matchsize	= sizeof(struct xt_length_info),
 		.me		= THIS_MODULE,
 	},
 	{
 		.name		= "length",
-		.family		= AF_INET6,
+		.family		= NFPROTO_IPV6,
 		.match		= length_mt6,
 		.matchsize	= sizeof(struct xt_length_info),
 		.me		= THIS_MODULE,
diff --git a/net/netfilter/xt_limit.c b/net/netfilter/xt_limit.c
index aad9ab8..c908d69 100644
--- a/net/netfilter/xt_limit.c
+++ b/net/netfilter/xt_limit.c
@@ -58,13 +58,10 @@
 #define CREDITS_PER_JIFFY POW2_BELOW32(MAX_CPJ)
 
 static bool
-limit_mt(const struct sk_buff *skb, const struct net_device *in,
-         const struct net_device *out, const struct xt_match *match,
-         const void *matchinfo, int offset, unsigned int protoff,
-         bool *hotdrop)
+limit_mt(const struct sk_buff *skb, const struct xt_match_param *par)
 {
 	struct xt_rateinfo *r =
-		((const struct xt_rateinfo *)matchinfo)->master;
+		((const struct xt_rateinfo *)par->matchinfo)->master;
 	unsigned long now = jiffies;
 
 	spin_lock_bh(&limit_lock);
@@ -95,12 +92,9 @@
 	return (user * HZ * CREDITS_PER_JIFFY) / XT_LIMIT_SCALE;
 }
 
-static bool
-limit_mt_check(const char *tablename, const void *inf,
-               const struct xt_match *match, void *matchinfo,
-               unsigned int hook_mask)
+static bool limit_mt_check(const struct xt_mtchk_param *par)
 {
-	struct xt_rateinfo *r = matchinfo;
+	struct xt_rateinfo *r = par->matchinfo;
 
 	/* Check for overflow. */
 	if (r->burst == 0
@@ -167,43 +161,29 @@
 }
 #endif /* CONFIG_COMPAT */
 
-static struct xt_match limit_mt_reg[] __read_mostly = {
-	{
-		.name		= "limit",
-		.family		= AF_INET,
-		.checkentry	= limit_mt_check,
-		.match		= limit_mt,
-		.matchsize	= sizeof(struct xt_rateinfo),
+static struct xt_match limit_mt_reg __read_mostly = {
+	.name             = "limit",
+	.revision         = 0,
+	.family           = NFPROTO_UNSPEC,
+	.match            = limit_mt,
+	.checkentry       = limit_mt_check,
+	.matchsize        = sizeof(struct xt_rateinfo),
 #ifdef CONFIG_COMPAT
-		.compatsize	= sizeof(struct compat_xt_rateinfo),
-		.compat_from_user = limit_mt_compat_from_user,
-		.compat_to_user	= limit_mt_compat_to_user,
+	.compatsize       = sizeof(struct compat_xt_rateinfo),
+	.compat_from_user = limit_mt_compat_from_user,
+	.compat_to_user   = limit_mt_compat_to_user,
 #endif
-		.me		= THIS_MODULE,
-	},
-	{
-		.name		= "limit",
-		.family		= AF_INET6,
-		.checkentry	= limit_mt_check,
-		.match		= limit_mt,
-		.matchsize	= sizeof(struct xt_rateinfo),
-#ifdef CONFIG_COMPAT
-		.compatsize	= sizeof(struct compat_xt_rateinfo),
-		.compat_from_user = limit_mt_compat_from_user,
-		.compat_to_user	= limit_mt_compat_to_user,
-#endif
-		.me		= THIS_MODULE,
-	},
+	.me               = THIS_MODULE,
 };
 
 static int __init limit_mt_init(void)
 {
-	return xt_register_matches(limit_mt_reg, ARRAY_SIZE(limit_mt_reg));
+	return xt_register_match(&limit_mt_reg);
 }
 
 static void __exit limit_mt_exit(void)
 {
-	xt_unregister_matches(limit_mt_reg, ARRAY_SIZE(limit_mt_reg));
+	xt_unregister_match(&limit_mt_reg);
 }
 
 module_init(limit_mt_init);
diff --git a/net/netfilter/xt_mac.c b/net/netfilter/xt_mac.c
index b3e96a0..c200711 100644
--- a/net/netfilter/xt_mac.c
+++ b/net/netfilter/xt_mac.c
@@ -24,12 +24,9 @@
 MODULE_ALIAS("ipt_mac");
 MODULE_ALIAS("ip6t_mac");
 
-static bool
-mac_mt(const struct sk_buff *skb, const struct net_device *in,
-       const struct net_device *out, const struct xt_match *match,
-       const void *matchinfo, int offset, unsigned int protoff, bool *hotdrop)
+static bool mac_mt(const struct sk_buff *skb, const struct xt_match_param *par)
 {
-    const struct xt_mac_info *info = matchinfo;
+    const struct xt_mac_info *info = par->matchinfo;
 
     /* Is mac pointer valid? */
     return skb_mac_header(skb) >= skb->head &&
@@ -39,37 +36,25 @@
 		^ info->invert);
 }
 
-static struct xt_match mac_mt_reg[] __read_mostly = {
-	{
-		.name		= "mac",
-		.family		= AF_INET,
-		.match		= mac_mt,
-		.matchsize	= sizeof(struct xt_mac_info),
-		.hooks		= (1 << NF_INET_PRE_ROUTING) |
-				  (1 << NF_INET_LOCAL_IN) |
-				  (1 << NF_INET_FORWARD),
-		.me		= THIS_MODULE,
-	},
-	{
-		.name		= "mac",
-		.family		= AF_INET6,
-		.match		= mac_mt,
-		.matchsize	= sizeof(struct xt_mac_info),
-		.hooks		= (1 << NF_INET_PRE_ROUTING) |
-				  (1 << NF_INET_LOCAL_IN) |
-				  (1 << NF_INET_FORWARD),
-		.me		= THIS_MODULE,
-	},
+static struct xt_match mac_mt_reg __read_mostly = {
+	.name      = "mac",
+	.revision  = 0,
+	.family    = NFPROTO_UNSPEC,
+	.match     = mac_mt,
+	.matchsize = sizeof(struct xt_mac_info),
+	.hooks     = (1 << NF_INET_PRE_ROUTING) | (1 << NF_INET_LOCAL_IN) |
+	             (1 << NF_INET_FORWARD),
+	.me        = THIS_MODULE,
 };
 
 static int __init mac_mt_init(void)
 {
-	return xt_register_matches(mac_mt_reg, ARRAY_SIZE(mac_mt_reg));
+	return xt_register_match(&mac_mt_reg);
 }
 
 static void __exit mac_mt_exit(void)
 {
-	xt_unregister_matches(mac_mt_reg, ARRAY_SIZE(mac_mt_reg));
+	xt_unregister_match(&mac_mt_reg);
 }
 
 module_init(mac_mt_init);
diff --git a/net/netfilter/xt_mark.c b/net/netfilter/xt_mark.c
index 9f78f61..10b9e34 100644
--- a/net/netfilter/xt_mark.c
+++ b/net/netfilter/xt_mark.c
@@ -23,32 +23,24 @@
 MODULE_ALIAS("ip6t_mark");
 
 static bool
-mark_mt_v0(const struct sk_buff *skb, const struct net_device *in,
-           const struct net_device *out, const struct xt_match *match,
-           const void *matchinfo, int offset, unsigned int protoff,
-           bool *hotdrop)
+mark_mt_v0(const struct sk_buff *skb, const struct xt_match_param *par)
 {
-	const struct xt_mark_info *info = matchinfo;
+	const struct xt_mark_info *info = par->matchinfo;
 
 	return ((skb->mark & info->mask) == info->mark) ^ info->invert;
 }
 
 static bool
-mark_mt(const struct sk_buff *skb, const struct net_device *in,
-        const struct net_device *out, const struct xt_match *match,
-        const void *matchinfo, int offset, unsigned int protoff, bool *hotdrop)
+mark_mt(const struct sk_buff *skb, const struct xt_match_param *par)
 {
-	const struct xt_mark_mtinfo1 *info = matchinfo;
+	const struct xt_mark_mtinfo1 *info = par->matchinfo;
 
 	return ((skb->mark & info->mask) == info->mark) ^ info->invert;
 }
 
-static bool
-mark_mt_check_v0(const char *tablename, const void *entry,
-                 const struct xt_match *match, void *matchinfo,
-                 unsigned int hook_mask)
+static bool mark_mt_check_v0(const struct xt_mtchk_param *par)
 {
-	const struct xt_mark_info *minfo = matchinfo;
+	const struct xt_mark_info *minfo = par->matchinfo;
 
 	if (minfo->mark > 0xffffffff || minfo->mask > 0xffffffff) {
 		printk(KERN_WARNING "mark: only supports 32bit mark\n");
@@ -92,21 +84,7 @@
 	{
 		.name		= "mark",
 		.revision	= 0,
-		.family		= AF_INET,
-		.checkentry	= mark_mt_check_v0,
-		.match		= mark_mt_v0,
-		.matchsize	= sizeof(struct xt_mark_info),
-#ifdef CONFIG_COMPAT
-		.compatsize	= sizeof(struct compat_xt_mark_info),
-		.compat_from_user = mark_mt_compat_from_user_v0,
-		.compat_to_user	= mark_mt_compat_to_user_v0,
-#endif
-		.me		= THIS_MODULE,
-	},
-	{
-		.name		= "mark",
-		.revision	= 0,
-		.family		= AF_INET6,
+		.family		= NFPROTO_UNSPEC,
 		.checkentry	= mark_mt_check_v0,
 		.match		= mark_mt_v0,
 		.matchsize	= sizeof(struct xt_mark_info),
@@ -120,15 +98,7 @@
 	{
 		.name           = "mark",
 		.revision       = 1,
-		.family         = AF_INET,
-		.match          = mark_mt,
-		.matchsize      = sizeof(struct xt_mark_mtinfo1),
-		.me             = THIS_MODULE,
-	},
-	{
-		.name           = "mark",
-		.revision       = 1,
-		.family         = AF_INET6,
+		.family         = NFPROTO_UNSPEC,
 		.match          = mark_mt,
 		.matchsize      = sizeof(struct xt_mark_mtinfo1),
 		.me             = THIS_MODULE,
diff --git a/net/netfilter/xt_multiport.c b/net/netfilter/xt_multiport.c
index fd88c48..d06bb2d 100644
--- a/net/netfilter/xt_multiport.c
+++ b/net/netfilter/xt_multiport.c
@@ -95,25 +95,22 @@
 }
 
 static bool
-multiport_mt_v0(const struct sk_buff *skb, const struct net_device *in,
-                const struct net_device *out, const struct xt_match *match,
-                const void *matchinfo, int offset, unsigned int protoff,
-                bool *hotdrop)
+multiport_mt_v0(const struct sk_buff *skb, const struct xt_match_param *par)
 {
 	const __be16 *pptr;
 	__be16 _ports[2];
-	const struct xt_multiport *multiinfo = matchinfo;
+	const struct xt_multiport *multiinfo = par->matchinfo;
 
-	if (offset)
+	if (par->fragoff != 0)
 		return false;
 
-	pptr = skb_header_pointer(skb, protoff, sizeof(_ports), _ports);
+	pptr = skb_header_pointer(skb, par->thoff, sizeof(_ports), _ports);
 	if (pptr == NULL) {
 		/* We've been asked to examine this packet, and we
 		 * can't.  Hence, no choice but to drop.
 		 */
 		duprintf("xt_multiport: Dropping evil offset=0 tinygram.\n");
-		*hotdrop = true;
+		*par->hotdrop = true;
 		return false;
 	}
 
@@ -122,25 +119,22 @@
 }
 
 static bool
-multiport_mt(const struct sk_buff *skb, const struct net_device *in,
-             const struct net_device *out, const struct xt_match *match,
-             const void *matchinfo, int offset, unsigned int protoff,
-             bool *hotdrop)
+multiport_mt(const struct sk_buff *skb, const struct xt_match_param *par)
 {
 	const __be16 *pptr;
 	__be16 _ports[2];
-	const struct xt_multiport_v1 *multiinfo = matchinfo;
+	const struct xt_multiport_v1 *multiinfo = par->matchinfo;
 
-	if (offset)
+	if (par->fragoff != 0)
 		return false;
 
-	pptr = skb_header_pointer(skb, protoff, sizeof(_ports), _ports);
+	pptr = skb_header_pointer(skb, par->thoff, sizeof(_ports), _ports);
 	if (pptr == NULL) {
 		/* We've been asked to examine this packet, and we
 		 * can't.  Hence, no choice but to drop.
 		 */
 		duprintf("xt_multiport: Dropping evil offset=0 tinygram.\n");
-		*hotdrop = true;
+		*par->hotdrop = true;
 		return false;
 	}
 
@@ -164,50 +158,37 @@
 		&& count <= XT_MULTI_PORTS;
 }
 
-/* Called when user tries to insert an entry of this type. */
-static bool
-multiport_mt_check_v0(const char *tablename, const void *info,
-                      const struct xt_match *match, void *matchinfo,
-                      unsigned int hook_mask)
+static bool multiport_mt_check_v0(const struct xt_mtchk_param *par)
 {
-	const struct ipt_ip *ip = info;
-	const struct xt_multiport *multiinfo = matchinfo;
+	const struct ipt_ip *ip = par->entryinfo;
+	const struct xt_multiport *multiinfo = par->matchinfo;
 
 	return check(ip->proto, ip->invflags, multiinfo->flags,
 		     multiinfo->count);
 }
 
-static bool
-multiport_mt_check(const char *tablename, const void *info,
-                   const struct xt_match *match, void *matchinfo,
-                   unsigned int hook_mask)
+static bool multiport_mt_check(const struct xt_mtchk_param *par)
 {
-	const struct ipt_ip *ip = info;
-	const struct xt_multiport_v1 *multiinfo = matchinfo;
+	const struct ipt_ip *ip = par->entryinfo;
+	const struct xt_multiport_v1 *multiinfo = par->matchinfo;
 
 	return check(ip->proto, ip->invflags, multiinfo->flags,
 		     multiinfo->count);
 }
 
-static bool
-multiport_mt6_check_v0(const char *tablename, const void *info,
-                       const struct xt_match *match, void *matchinfo,
-                       unsigned int hook_mask)
+static bool multiport_mt6_check_v0(const struct xt_mtchk_param *par)
 {
-	const struct ip6t_ip6 *ip = info;
-	const struct xt_multiport *multiinfo = matchinfo;
+	const struct ip6t_ip6 *ip = par->entryinfo;
+	const struct xt_multiport *multiinfo = par->matchinfo;
 
 	return check(ip->proto, ip->invflags, multiinfo->flags,
 		     multiinfo->count);
 }
 
-static bool
-multiport_mt6_check(const char *tablename, const void *info,
-                    const struct xt_match *match, void *matchinfo,
-                    unsigned int hook_mask)
+static bool multiport_mt6_check(const struct xt_mtchk_param *par)
 {
-	const struct ip6t_ip6 *ip = info;
-	const struct xt_multiport_v1 *multiinfo = matchinfo;
+	const struct ip6t_ip6 *ip = par->entryinfo;
+	const struct xt_multiport_v1 *multiinfo = par->matchinfo;
 
 	return check(ip->proto, ip->invflags, multiinfo->flags,
 		     multiinfo->count);
@@ -216,7 +197,7 @@
 static struct xt_match multiport_mt_reg[] __read_mostly = {
 	{
 		.name		= "multiport",
-		.family		= AF_INET,
+		.family		= NFPROTO_IPV4,
 		.revision	= 0,
 		.checkentry	= multiport_mt_check_v0,
 		.match		= multiport_mt_v0,
@@ -225,7 +206,7 @@
 	},
 	{
 		.name		= "multiport",
-		.family		= AF_INET,
+		.family		= NFPROTO_IPV4,
 		.revision	= 1,
 		.checkentry	= multiport_mt_check,
 		.match		= multiport_mt,
@@ -234,7 +215,7 @@
 	},
 	{
 		.name		= "multiport",
-		.family		= AF_INET6,
+		.family		= NFPROTO_IPV6,
 		.revision	= 0,
 		.checkentry	= multiport_mt6_check_v0,
 		.match		= multiport_mt_v0,
@@ -243,7 +224,7 @@
 	},
 	{
 		.name		= "multiport",
-		.family		= AF_INET6,
+		.family		= NFPROTO_IPV6,
 		.revision	= 1,
 		.checkentry	= multiport_mt6_check,
 		.match		= multiport_mt,
diff --git a/net/netfilter/xt_owner.c b/net/netfilter/xt_owner.c
index 9059c16..f19ebd9 100644
--- a/net/netfilter/xt_owner.c
+++ b/net/netfilter/xt_owner.c
@@ -21,12 +21,9 @@
 #include <linux/netfilter_ipv6/ip6t_owner.h>
 
 static bool
-owner_mt_v0(const struct sk_buff *skb, const struct net_device *in,
-            const struct net_device *out, const struct xt_match *match,
-            const void *matchinfo, int offset, unsigned int protoff,
-            bool *hotdrop)
+owner_mt_v0(const struct sk_buff *skb, const struct xt_match_param *par)
 {
-	const struct ipt_owner_info *info = matchinfo;
+	const struct ipt_owner_info *info = par->matchinfo;
 	const struct file *filp;
 
 	if (skb->sk == NULL || skb->sk->sk_socket == NULL)
@@ -50,12 +47,9 @@
 }
 
 static bool
-owner_mt6_v0(const struct sk_buff *skb, const struct net_device *in,
-             const struct net_device *out, const struct xt_match *match,
-             const void *matchinfo, int offset, unsigned int protoff,
-             bool *hotdrop)
+owner_mt6_v0(const struct sk_buff *skb, const struct xt_match_param *par)
 {
-	const struct ip6t_owner_info *info = matchinfo;
+	const struct ip6t_owner_info *info = par->matchinfo;
 	const struct file *filp;
 
 	if (skb->sk == NULL || skb->sk->sk_socket == NULL)
@@ -79,12 +73,9 @@
 }
 
 static bool
-owner_mt(const struct sk_buff *skb, const struct net_device *in,
-         const struct net_device *out, const struct xt_match *match,
-         const void *matchinfo, int offset, unsigned int protoff,
-         bool *hotdrop)
+owner_mt(const struct sk_buff *skb, const struct xt_match_param *par)
 {
-	const struct xt_owner_match_info *info = matchinfo;
+	const struct xt_owner_match_info *info = par->matchinfo;
 	const struct file *filp;
 
 	if (skb->sk == NULL || skb->sk->sk_socket == NULL)
@@ -116,12 +107,9 @@
 	return true;
 }
 
-static bool
-owner_mt_check_v0(const char *tablename, const void *ip,
-                  const struct xt_match *match, void *matchinfo,
-                  unsigned int hook_mask)
+static bool owner_mt_check_v0(const struct xt_mtchk_param *par)
 {
-	const struct ipt_owner_info *info = matchinfo;
+	const struct ipt_owner_info *info = par->matchinfo;
 
 	if (info->match & (IPT_OWNER_PID | IPT_OWNER_SID | IPT_OWNER_COMM)) {
 		printk(KERN_WARNING KBUILD_MODNAME
@@ -133,12 +121,9 @@
 	return true;
 }
 
-static bool
-owner_mt6_check_v0(const char *tablename, const void *ip,
-                   const struct xt_match *match, void *matchinfo,
-                   unsigned int hook_mask)
+static bool owner_mt6_check_v0(const struct xt_mtchk_param *par)
 {
-	const struct ip6t_owner_info *info = matchinfo;
+	const struct ip6t_owner_info *info = par->matchinfo;
 
 	if (info->match & (IP6T_OWNER_PID | IP6T_OWNER_SID)) {
 		printk(KERN_WARNING KBUILD_MODNAME
@@ -153,7 +138,7 @@
 	{
 		.name       = "owner",
 		.revision   = 0,
-		.family     = AF_INET,
+		.family     = NFPROTO_IPV4,
 		.match      = owner_mt_v0,
 		.matchsize  = sizeof(struct ipt_owner_info),
 		.checkentry = owner_mt_check_v0,
@@ -164,7 +149,7 @@
 	{
 		.name       = "owner",
 		.revision   = 0,
-		.family     = AF_INET6,
+		.family     = NFPROTO_IPV6,
 		.match      = owner_mt6_v0,
 		.matchsize  = sizeof(struct ip6t_owner_info),
 		.checkentry = owner_mt6_check_v0,
@@ -175,17 +160,7 @@
 	{
 		.name       = "owner",
 		.revision   = 1,
-		.family     = AF_INET,
-		.match      = owner_mt,
-		.matchsize  = sizeof(struct xt_owner_match_info),
-		.hooks      = (1 << NF_INET_LOCAL_OUT) |
-		              (1 << NF_INET_POST_ROUTING),
-		.me         = THIS_MODULE,
-	},
-	{
-		.name       = "owner",
-		.revision   = 1,
-		.family     = AF_INET6,
+		.family     = NFPROTO_UNSPEC,
 		.match      = owner_mt,
 		.matchsize  = sizeof(struct xt_owner_match_info),
 		.hooks      = (1 << NF_INET_LOCAL_OUT) |
diff --git a/net/netfilter/xt_physdev.c b/net/netfilter/xt_physdev.c
index 4ec1094..1bcdfc1 100644
--- a/net/netfilter/xt_physdev.c
+++ b/net/netfilter/xt_physdev.c
@@ -21,14 +21,11 @@
 MODULE_ALIAS("ip6t_physdev");
 
 static bool
-physdev_mt(const struct sk_buff *skb, const struct net_device *in,
-           const struct net_device *out, const struct xt_match *match,
-           const void *matchinfo, int offset, unsigned int protoff,
-           bool *hotdrop)
+physdev_mt(const struct sk_buff *skb, const struct xt_match_param *par)
 {
 	int i;
 	static const char nulldevname[IFNAMSIZ];
-	const struct xt_physdev_info *info = matchinfo;
+	const struct xt_physdev_info *info = par->matchinfo;
 	bool ret;
 	const char *indev, *outdev;
 	const struct nf_bridge_info *nf_bridge;
@@ -94,12 +91,9 @@
 	return ret ^ !(info->invert & XT_PHYSDEV_OP_OUT);
 }
 
-static bool
-physdev_mt_check(const char *tablename, const void *ip,
-                 const struct xt_match *match, void *matchinfo,
-                 unsigned int hook_mask)
+static bool physdev_mt_check(const struct xt_mtchk_param *par)
 {
-	const struct xt_physdev_info *info = matchinfo;
+	const struct xt_physdev_info *info = par->matchinfo;
 
 	if (!(info->bitmask & XT_PHYSDEV_OP_MASK) ||
 	    info->bitmask & ~XT_PHYSDEV_OP_MASK)
@@ -107,44 +101,35 @@
 	if (info->bitmask & XT_PHYSDEV_OP_OUT &&
 	    (!(info->bitmask & XT_PHYSDEV_OP_BRIDGED) ||
 	     info->invert & XT_PHYSDEV_OP_BRIDGED) &&
-	    hook_mask & ((1 << NF_INET_LOCAL_OUT) | (1 << NF_INET_FORWARD) |
-			 (1 << NF_INET_POST_ROUTING))) {
+	    par->hook_mask & ((1 << NF_INET_LOCAL_OUT) |
+	    (1 << NF_INET_FORWARD) | (1 << NF_INET_POST_ROUTING))) {
 		printk(KERN_WARNING "physdev match: using --physdev-out in the "
 		       "OUTPUT, FORWARD and POSTROUTING chains for non-bridged "
 		       "traffic is not supported anymore.\n");
-		if (hook_mask & (1 << NF_INET_LOCAL_OUT))
+		if (par->hook_mask & (1 << NF_INET_LOCAL_OUT))
 			return false;
 	}
 	return true;
 }
 
-static struct xt_match physdev_mt_reg[] __read_mostly = {
-	{
-		.name		= "physdev",
-		.family		= AF_INET,
-		.checkentry	= physdev_mt_check,
-		.match		= physdev_mt,
-		.matchsize	= sizeof(struct xt_physdev_info),
-		.me		= THIS_MODULE,
-	},
-	{
-		.name		= "physdev",
-		.family		= AF_INET6,
-		.checkentry	= physdev_mt_check,
-		.match		= physdev_mt,
-		.matchsize	= sizeof(struct xt_physdev_info),
-		.me		= THIS_MODULE,
-	},
+static struct xt_match physdev_mt_reg __read_mostly = {
+	.name       = "physdev",
+	.revision   = 0,
+	.family     = NFPROTO_UNSPEC,
+	.checkentry = physdev_mt_check,
+	.match      = physdev_mt,
+	.matchsize  = sizeof(struct xt_physdev_info),
+	.me         = THIS_MODULE,
 };
 
 static int __init physdev_mt_init(void)
 {
-	return xt_register_matches(physdev_mt_reg, ARRAY_SIZE(physdev_mt_reg));
+	return xt_register_match(&physdev_mt_reg);
 }
 
 static void __exit physdev_mt_exit(void)
 {
-	xt_unregister_matches(physdev_mt_reg, ARRAY_SIZE(physdev_mt_reg));
+	xt_unregister_match(&physdev_mt_reg);
 }
 
 module_init(physdev_mt_init);
diff --git a/net/netfilter/xt_pkttype.c b/net/netfilter/xt_pkttype.c
index 7936f7e..69da1d3 100644
--- a/net/netfilter/xt_pkttype.c
+++ b/net/netfilter/xt_pkttype.c
@@ -23,20 +23,17 @@
 MODULE_ALIAS("ip6t_pkttype");
 
 static bool
-pkttype_mt(const struct sk_buff *skb, const struct net_device *in,
-           const struct net_device *out, const struct xt_match *match,
-           const void *matchinfo, int offset, unsigned int protoff,
-           bool *hotdrop)
+pkttype_mt(const struct sk_buff *skb, const struct xt_match_param *par)
 {
-	const struct xt_pkttype_info *info = matchinfo;
+	const struct xt_pkttype_info *info = par->matchinfo;
 	u_int8_t type;
 
 	if (skb->pkt_type != PACKET_LOOPBACK)
 		type = skb->pkt_type;
-	else if (match->family == AF_INET &&
+	else if (par->family == NFPROTO_IPV4 &&
 	    ipv4_is_multicast(ip_hdr(skb)->daddr))
 		type = PACKET_MULTICAST;
-	else if (match->family == AF_INET6 &&
+	else if (par->family == NFPROTO_IPV6 &&
 	    ipv6_hdr(skb)->daddr.s6_addr[0] == 0xFF)
 		type = PACKET_MULTICAST;
 	else
@@ -45,31 +42,23 @@
 	return (type == info->pkttype) ^ info->invert;
 }
 
-static struct xt_match pkttype_mt_reg[] __read_mostly = {
-	{
-		.name		= "pkttype",
-		.family		= AF_INET,
-		.match		= pkttype_mt,
-		.matchsize	= sizeof(struct xt_pkttype_info),
-		.me		= THIS_MODULE,
-	},
-	{
-		.name		= "pkttype",
-		.family		= AF_INET6,
-		.match		= pkttype_mt,
-		.matchsize	= sizeof(struct xt_pkttype_info),
-		.me		= THIS_MODULE,
-	},
+static struct xt_match pkttype_mt_reg __read_mostly = {
+	.name      = "pkttype",
+	.revision  = 0,
+	.family    = NFPROTO_UNSPEC,
+	.match     = pkttype_mt,
+	.matchsize = sizeof(struct xt_pkttype_info),
+	.me        = THIS_MODULE,
 };
 
 static int __init pkttype_mt_init(void)
 {
-	return xt_register_matches(pkttype_mt_reg, ARRAY_SIZE(pkttype_mt_reg));
+	return xt_register_match(&pkttype_mt_reg);
 }
 
 static void __exit pkttype_mt_exit(void)
 {
-	xt_unregister_matches(pkttype_mt_reg, ARRAY_SIZE(pkttype_mt_reg));
+	xt_unregister_match(&pkttype_mt_reg);
 }
 
 module_init(pkttype_mt_init);
diff --git a/net/netfilter/xt_policy.c b/net/netfilter/xt_policy.c
index d351582..328bd20 100644
--- a/net/netfilter/xt_policy.c
+++ b/net/netfilter/xt_policy.c
@@ -26,9 +26,9 @@
 	    const union nf_inet_addr *a2, unsigned short family)
 {
 	switch (family) {
-	case AF_INET:
+	case NFPROTO_IPV4:
 		return ((a1->ip ^ a2->ip) & m->ip) == 0;
-	case AF_INET6:
+	case NFPROTO_IPV6:
 		return ipv6_masked_addr_cmp(&a1->in6, &m->in6, &a2->in6) == 0;
 	}
 	return false;
@@ -110,18 +110,15 @@
 }
 
 static bool
-policy_mt(const struct sk_buff *skb, const struct net_device *in,
-          const struct net_device *out, const struct xt_match *match,
-          const void *matchinfo, int offset, unsigned int protoff,
-          bool *hotdrop)
+policy_mt(const struct sk_buff *skb, const struct xt_match_param *par)
 {
-	const struct xt_policy_info *info = matchinfo;
+	const struct xt_policy_info *info = par->matchinfo;
 	int ret;
 
 	if (info->flags & XT_POLICY_MATCH_IN)
-		ret = match_policy_in(skb, info, match->family);
+		ret = match_policy_in(skb, info, par->match->family);
 	else
-		ret = match_policy_out(skb, info, match->family);
+		ret = match_policy_out(skb, info, par->match->family);
 
 	if (ret < 0)
 		ret = info->flags & XT_POLICY_MATCH_NONE ? true : false;
@@ -131,26 +128,23 @@
 	return ret;
 }
 
-static bool
-policy_mt_check(const char *tablename, const void *ip_void,
-                const struct xt_match *match, void *matchinfo,
-                unsigned int hook_mask)
+static bool policy_mt_check(const struct xt_mtchk_param *par)
 {
-	const struct xt_policy_info *info = matchinfo;
+	const struct xt_policy_info *info = par->matchinfo;
 
 	if (!(info->flags & (XT_POLICY_MATCH_IN|XT_POLICY_MATCH_OUT))) {
 		printk(KERN_ERR "xt_policy: neither incoming nor "
 				"outgoing policy selected\n");
 		return false;
 	}
-	if (hook_mask & (1 << NF_INET_PRE_ROUTING | 1 << NF_INET_LOCAL_IN)
-	    && info->flags & XT_POLICY_MATCH_OUT) {
+	if (par->hook_mask & ((1 << NF_INET_PRE_ROUTING) |
+	    (1 << NF_INET_LOCAL_IN)) && info->flags & XT_POLICY_MATCH_OUT) {
 		printk(KERN_ERR "xt_policy: output policy not valid in "
 				"PRE_ROUTING and INPUT\n");
 		return false;
 	}
-	if (hook_mask & (1 << NF_INET_POST_ROUTING | 1 << NF_INET_LOCAL_OUT)
-	    && info->flags & XT_POLICY_MATCH_IN) {
+	if (par->hook_mask & ((1 << NF_INET_POST_ROUTING) |
+	    (1 << NF_INET_LOCAL_OUT)) && info->flags & XT_POLICY_MATCH_IN) {
 		printk(KERN_ERR "xt_policy: input policy not valid in "
 				"POST_ROUTING and OUTPUT\n");
 		return false;
@@ -165,7 +159,7 @@
 static struct xt_match policy_mt_reg[] __read_mostly = {
 	{
 		.name		= "policy",
-		.family		= AF_INET,
+		.family		= NFPROTO_IPV4,
 		.checkentry 	= policy_mt_check,
 		.match		= policy_mt,
 		.matchsize	= sizeof(struct xt_policy_info),
@@ -173,7 +167,7 @@
 	},
 	{
 		.name		= "policy",
-		.family		= AF_INET6,
+		.family		= NFPROTO_IPV6,
 		.checkentry	= policy_mt_check,
 		.match		= policy_mt,
 		.matchsize	= sizeof(struct xt_policy_info),
diff --git a/net/netfilter/xt_quota.c b/net/netfilter/xt_quota.c
index 3b021d0..c84fce5 100644
--- a/net/netfilter/xt_quota.c
+++ b/net/netfilter/xt_quota.c
@@ -18,13 +18,10 @@
 static DEFINE_SPINLOCK(quota_lock);
 
 static bool
-quota_mt(const struct sk_buff *skb, const struct net_device *in,
-         const struct net_device *out, const struct xt_match *match,
-         const void *matchinfo, int offset, unsigned int protoff,
-         bool *hotdrop)
+quota_mt(const struct sk_buff *skb, const struct xt_match_param *par)
 {
 	struct xt_quota_info *q =
-		((const struct xt_quota_info *)matchinfo)->master;
+		((const struct xt_quota_info *)par->matchinfo)->master;
 	bool ret = q->flags & XT_QUOTA_INVERT;
 
 	spin_lock_bh(&quota_lock);
@@ -40,12 +37,9 @@
 	return ret;
 }
 
-static bool
-quota_mt_check(const char *tablename, const void *entry,
-               const struct xt_match *match, void *matchinfo,
-               unsigned int hook_mask)
+static bool quota_mt_check(const struct xt_mtchk_param *par)
 {
-	struct xt_quota_info *q = matchinfo;
+	struct xt_quota_info *q = par->matchinfo;
 
 	if (q->flags & ~XT_QUOTA_MASK)
 		return false;
@@ -54,33 +48,24 @@
 	return true;
 }
 
-static struct xt_match quota_mt_reg[] __read_mostly = {
-	{
-		.name		= "quota",
-		.family		= AF_INET,
-		.checkentry	= quota_mt_check,
-		.match		= quota_mt,
-		.matchsize	= sizeof(struct xt_quota_info),
-		.me		= THIS_MODULE
-	},
-	{
-		.name		= "quota",
-		.family		= AF_INET6,
-		.checkentry	= quota_mt_check,
-		.match		= quota_mt,
-		.matchsize	= sizeof(struct xt_quota_info),
-		.me		= THIS_MODULE
-	},
+static struct xt_match quota_mt_reg __read_mostly = {
+	.name       = "quota",
+	.revision   = 0,
+	.family     = NFPROTO_UNSPEC,
+	.match      = quota_mt,
+	.checkentry = quota_mt_check,
+	.matchsize  = sizeof(struct xt_quota_info),
+	.me         = THIS_MODULE,
 };
 
 static int __init quota_mt_init(void)
 {
-	return xt_register_matches(quota_mt_reg, ARRAY_SIZE(quota_mt_reg));
+	return xt_register_match(&quota_mt_reg);
 }
 
 static void __exit quota_mt_exit(void)
 {
-	xt_unregister_matches(quota_mt_reg, ARRAY_SIZE(quota_mt_reg));
+	xt_unregister_match(&quota_mt_reg);
 }
 
 module_init(quota_mt_init);
diff --git a/net/netfilter/xt_rateest.c b/net/netfilter/xt_rateest.c
index ebd84f1..220a1d5 100644
--- a/net/netfilter/xt_rateest.c
+++ b/net/netfilter/xt_rateest.c
@@ -14,16 +14,10 @@
 #include <net/netfilter/xt_rateest.h>
 
 
-static bool xt_rateest_mt(const struct sk_buff *skb,
-			  const struct net_device *in,
-			  const struct net_device *out,
-			  const struct xt_match *match,
-			  const void *matchinfo,
-			  int offset,
-			  unsigned int protoff,
-			  bool *hotdrop)
+static bool
+xt_rateest_mt(const struct sk_buff *skb, const struct xt_match_param *par)
 {
-	const struct xt_rateest_match_info *info = matchinfo;
+	const struct xt_rateest_match_info *info = par->matchinfo;
 	struct gnet_stats_rate_est *r;
 	u_int32_t bps1, bps2, pps1, pps2;
 	bool ret = true;
@@ -80,13 +74,9 @@
 	return ret;
 }
 
-static bool xt_rateest_mt_checkentry(const char *tablename,
-				     const void *ip,
-				     const struct xt_match *match,
-				     void *matchinfo,
-				     unsigned int hook_mask)
+static bool xt_rateest_mt_checkentry(const struct xt_mtchk_param *par)
 {
-	struct xt_rateest_match_info *info = matchinfo;
+	struct xt_rateest_match_info *info = par->matchinfo;
 	struct xt_rateest *est1, *est2;
 
 	if (hweight32(info->flags & (XT_RATEEST_MATCH_ABS |
@@ -127,46 +117,34 @@
 	return false;
 }
 
-static void xt_rateest_mt_destroy(const struct xt_match *match,
-				  void *matchinfo)
+static void xt_rateest_mt_destroy(const struct xt_mtdtor_param *par)
 {
-	struct xt_rateest_match_info *info = matchinfo;
+	struct xt_rateest_match_info *info = par->matchinfo;
 
 	xt_rateest_put(info->est1);
 	if (info->est2)
 		xt_rateest_put(info->est2);
 }
 
-static struct xt_match xt_rateest_match[] __read_mostly = {
-	{
-		.family		= AF_INET,
-		.name		= "rateest",
-		.match		= xt_rateest_mt,
-		.checkentry	= xt_rateest_mt_checkentry,
-		.destroy	= xt_rateest_mt_destroy,
-		.matchsize	= sizeof(struct xt_rateest_match_info),
-		.me		= THIS_MODULE,
-	},
-	{
-		.family		= AF_INET6,
-		.name		= "rateest",
-		.match		= xt_rateest_mt,
-		.checkentry	= xt_rateest_mt_checkentry,
-		.destroy	= xt_rateest_mt_destroy,
-		.matchsize	= sizeof(struct xt_rateest_match_info),
-		.me		= THIS_MODULE,
-	},
+static struct xt_match xt_rateest_mt_reg __read_mostly = {
+	.name       = "rateest",
+	.revision   = 0,
+	.family     = NFPROTO_UNSPEC,
+	.match      = xt_rateest_mt,
+	.checkentry = xt_rateest_mt_checkentry,
+	.destroy    = xt_rateest_mt_destroy,
+	.matchsize  = sizeof(struct xt_rateest_match_info),
+	.me         = THIS_MODULE,
 };
 
 static int __init xt_rateest_mt_init(void)
 {
-	return xt_register_matches(xt_rateest_match,
-				   ARRAY_SIZE(xt_rateest_match));
+	return xt_register_match(&xt_rateest_mt_reg);
 }
 
 static void __exit xt_rateest_mt_fini(void)
 {
-	xt_unregister_matches(xt_rateest_match, ARRAY_SIZE(xt_rateest_match));
+	xt_unregister_match(&xt_rateest_mt_reg);
 }
 
 MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
diff --git a/net/netfilter/xt_realm.c b/net/netfilter/xt_realm.c
index 7df1627..6741928 100644
--- a/net/netfilter/xt_realm.c
+++ b/net/netfilter/xt_realm.c
@@ -22,12 +22,9 @@
 MODULE_ALIAS("ipt_realm");
 
 static bool
-realm_mt(const struct sk_buff *skb, const struct net_device *in,
-         const struct net_device *out, const struct xt_match *match,
-         const void *matchinfo, int offset, unsigned int protoff,
-         bool *hotdrop)
+realm_mt(const struct sk_buff *skb, const struct xt_match_param *par)
 {
-	const struct xt_realm_info *info = matchinfo;
+	const struct xt_realm_info *info = par->matchinfo;
 	const struct dst_entry *dst = skb->dst;
 
 	return (info->id == (dst->tclassid & info->mask)) ^ info->invert;
@@ -39,7 +36,7 @@
 	.matchsize	= sizeof(struct xt_realm_info),
 	.hooks		= (1 << NF_INET_POST_ROUTING) | (1 << NF_INET_FORWARD) |
 			  (1 << NF_INET_LOCAL_OUT) | (1 << NF_INET_LOCAL_IN),
-	.family		= AF_INET,
+	.family		= NFPROTO_UNSPEC,
 	.me		= THIS_MODULE
 };
 
diff --git a/net/netfilter/xt_recent.c b/net/netfilter/xt_recent.c
new file mode 100644
index 0000000..4ebd4ca
--- /dev/null
+++ b/net/netfilter/xt_recent.c
@@ -0,0 +1,689 @@
+/*
+ * Copyright (c) 2006 Patrick McHardy <kaber@trash.net>
+ * Copyright © CC Computer Consultants GmbH, 2007 - 2008
+ *
+ * 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 is a replacement of the old ipt_recent module, which carried the
+ * following copyright notice:
+ *
+ * Author: Stephen Frost <sfrost@snowman.net>
+ * Copyright 2002-2003, Stephen Frost, 2.5.x port by laforge@netfilter.org
+ */
+#include <linux/init.h>
+#include <linux/ip.h>
+#include <linux/ipv6.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+#include <linux/string.h>
+#include <linux/ctype.h>
+#include <linux/list.h>
+#include <linux/random.h>
+#include <linux/jhash.h>
+#include <linux/bitops.h>
+#include <linux/skbuff.h>
+#include <linux/inet.h>
+#include <net/net_namespace.h>
+
+#include <linux/netfilter/x_tables.h>
+#include <linux/netfilter/xt_recent.h>
+
+MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
+MODULE_AUTHOR("Jan Engelhardt <jengelh@computergmbh.de>");
+MODULE_DESCRIPTION("Xtables: \"recently-seen\" host matching for IPv4");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("ipt_recent");
+MODULE_ALIAS("ip6t_recent");
+
+static unsigned int ip_list_tot = 100;
+static unsigned int ip_pkt_list_tot = 20;
+static unsigned int ip_list_hash_size = 0;
+static unsigned int ip_list_perms = 0644;
+static unsigned int ip_list_uid = 0;
+static unsigned int ip_list_gid = 0;
+module_param(ip_list_tot, uint, 0400);
+module_param(ip_pkt_list_tot, uint, 0400);
+module_param(ip_list_hash_size, uint, 0400);
+module_param(ip_list_perms, uint, 0400);
+module_param(ip_list_uid, uint, 0400);
+module_param(ip_list_gid, uint, 0400);
+MODULE_PARM_DESC(ip_list_tot, "number of IPs to remember per list");
+MODULE_PARM_DESC(ip_pkt_list_tot, "number of packets per IP to remember (max. 255)");
+MODULE_PARM_DESC(ip_list_hash_size, "size of hash table used to look up IPs");
+MODULE_PARM_DESC(ip_list_perms, "permissions on /proc/net/xt_recent/* files");
+MODULE_PARM_DESC(ip_list_uid,"owner of /proc/net/xt_recent/* files");
+MODULE_PARM_DESC(ip_list_gid,"owning group of /proc/net/xt_recent/* files");
+
+struct recent_entry {
+	struct list_head	list;
+	struct list_head	lru_list;
+	union nf_inet_addr	addr;
+	u_int16_t		family;
+	u_int8_t		ttl;
+	u_int8_t		index;
+	u_int16_t		nstamps;
+	unsigned long		stamps[0];
+};
+
+struct recent_table {
+	struct list_head	list;
+	char			name[XT_RECENT_NAME_LEN];
+#ifdef CONFIG_PROC_FS
+	struct proc_dir_entry	*proc_old, *proc;
+#endif
+	unsigned int		refcnt;
+	unsigned int		entries;
+	struct list_head	lru_list;
+	struct list_head	iphash[0];
+};
+
+static LIST_HEAD(tables);
+static DEFINE_SPINLOCK(recent_lock);
+static DEFINE_MUTEX(recent_mutex);
+
+#ifdef CONFIG_PROC_FS
+#ifdef CONFIG_NETFILTER_XT_MATCH_RECENT_PROC_COMPAT
+static struct proc_dir_entry *proc_old_dir;
+#endif
+static struct proc_dir_entry *recent_proc_dir;
+static const struct file_operations recent_old_fops, recent_mt_fops;
+#endif
+
+static u_int32_t hash_rnd;
+static bool hash_rnd_initted;
+
+static unsigned int recent_entry_hash4(const union nf_inet_addr *addr)
+{
+	if (!hash_rnd_initted) {
+		get_random_bytes(&hash_rnd, sizeof(hash_rnd));
+		hash_rnd_initted = true;
+	}
+	return jhash_1word((__force u32)addr->ip, hash_rnd) &
+	       (ip_list_hash_size - 1);
+}
+
+static unsigned int recent_entry_hash6(const union nf_inet_addr *addr)
+{
+	if (!hash_rnd_initted) {
+		get_random_bytes(&hash_rnd, sizeof(hash_rnd));
+		hash_rnd_initted = true;
+	}
+	return jhash2((u32 *)addr->ip6, ARRAY_SIZE(addr->ip6), hash_rnd) &
+	       (ip_list_hash_size - 1);
+}
+
+static struct recent_entry *
+recent_entry_lookup(const struct recent_table *table,
+		    const union nf_inet_addr *addrp, u_int16_t family,
+		    u_int8_t ttl)
+{
+	struct recent_entry *e;
+	unsigned int h;
+
+	if (family == NFPROTO_IPV4)
+		h = recent_entry_hash4(addrp);
+	else
+		h = recent_entry_hash6(addrp);
+
+	list_for_each_entry(e, &table->iphash[h], list)
+		if (e->family == family &&
+		    memcmp(&e->addr, addrp, sizeof(e->addr)) == 0 &&
+		    (ttl == e->ttl || ttl == 0 || e->ttl == 0))
+			return e;
+	return NULL;
+}
+
+static void recent_entry_remove(struct recent_table *t, struct recent_entry *e)
+{
+	list_del(&e->list);
+	list_del(&e->lru_list);
+	kfree(e);
+	t->entries--;
+}
+
+static struct recent_entry *
+recent_entry_init(struct recent_table *t, const union nf_inet_addr *addr,
+		  u_int16_t family, u_int8_t ttl)
+{
+	struct recent_entry *e;
+
+	if (t->entries >= ip_list_tot) {
+		e = list_entry(t->lru_list.next, struct recent_entry, lru_list);
+		recent_entry_remove(t, e);
+	}
+	e = kmalloc(sizeof(*e) + sizeof(e->stamps[0]) * ip_pkt_list_tot,
+		    GFP_ATOMIC);
+	if (e == NULL)
+		return NULL;
+	memcpy(&e->addr, addr, sizeof(e->addr));
+	e->ttl       = ttl;
+	e->stamps[0] = jiffies;
+	e->nstamps   = 1;
+	e->index     = 1;
+	e->family    = family;
+	if (family == NFPROTO_IPV4)
+		list_add_tail(&e->list, &t->iphash[recent_entry_hash4(addr)]);
+	else
+		list_add_tail(&e->list, &t->iphash[recent_entry_hash6(addr)]);
+	list_add_tail(&e->lru_list, &t->lru_list);
+	t->entries++;
+	return e;
+}
+
+static void recent_entry_update(struct recent_table *t, struct recent_entry *e)
+{
+	e->stamps[e->index++] = jiffies;
+	if (e->index > e->nstamps)
+		e->nstamps = e->index;
+	e->index %= ip_pkt_list_tot;
+	list_move_tail(&e->lru_list, &t->lru_list);
+}
+
+static struct recent_table *recent_table_lookup(const char *name)
+{
+	struct recent_table *t;
+
+	list_for_each_entry(t, &tables, list)
+		if (!strcmp(t->name, name))
+			return t;
+	return NULL;
+}
+
+static void recent_table_flush(struct recent_table *t)
+{
+	struct recent_entry *e, *next;
+	unsigned int i;
+
+	for (i = 0; i < ip_list_hash_size; i++)
+		list_for_each_entry_safe(e, next, &t->iphash[i], list)
+			recent_entry_remove(t, e);
+}
+
+static bool
+recent_mt(const struct sk_buff *skb, const struct xt_match_param *par)
+{
+	const struct xt_recent_mtinfo *info = par->matchinfo;
+	struct recent_table *t;
+	struct recent_entry *e;
+	union nf_inet_addr addr = {};
+	u_int8_t ttl;
+	bool ret = info->invert;
+
+	if (par->match->family == NFPROTO_IPV4) {
+		const struct iphdr *iph = ip_hdr(skb);
+
+		if (info->side == XT_RECENT_DEST)
+			addr.ip = iph->daddr;
+		else
+			addr.ip = iph->saddr;
+
+		ttl = iph->ttl;
+	} else {
+		const struct ipv6hdr *iph = ipv6_hdr(skb);
+
+		if (info->side == XT_RECENT_DEST)
+			memcpy(&addr.in6, &iph->daddr, sizeof(addr.in6));
+		else
+			memcpy(&addr.in6, &iph->saddr, sizeof(addr.in6));
+
+		ttl = iph->hop_limit;
+	}
+
+	/* use TTL as seen before forwarding */
+	if (par->out != NULL && skb->sk == NULL)
+		ttl++;
+
+	spin_lock_bh(&recent_lock);
+	t = recent_table_lookup(info->name);
+	e = recent_entry_lookup(t, &addr, par->match->family,
+				(info->check_set & XT_RECENT_TTL) ? ttl : 0);
+	if (e == NULL) {
+		if (!(info->check_set & XT_RECENT_SET))
+			goto out;
+		e = recent_entry_init(t, &addr, par->match->family, ttl);
+		if (e == NULL)
+			*par->hotdrop = true;
+		ret = !ret;
+		goto out;
+	}
+
+	if (info->check_set & XT_RECENT_SET)
+		ret = !ret;
+	else if (info->check_set & XT_RECENT_REMOVE) {
+		recent_entry_remove(t, e);
+		ret = !ret;
+	} else if (info->check_set & (XT_RECENT_CHECK | XT_RECENT_UPDATE)) {
+		unsigned long time = jiffies - info->seconds * HZ;
+		unsigned int i, hits = 0;
+
+		for (i = 0; i < e->nstamps; i++) {
+			if (info->seconds && time_after(time, e->stamps[i]))
+				continue;
+			if (++hits >= info->hit_count) {
+				ret = !ret;
+				break;
+			}
+		}
+	}
+
+	if (info->check_set & XT_RECENT_SET ||
+	    (info->check_set & XT_RECENT_UPDATE && ret)) {
+		recent_entry_update(t, e);
+		e->ttl = ttl;
+	}
+out:
+	spin_unlock_bh(&recent_lock);
+	return ret;
+}
+
+static bool recent_mt_check(const struct xt_mtchk_param *par)
+{
+	const struct xt_recent_mtinfo *info = par->matchinfo;
+	struct recent_table *t;
+	unsigned i;
+	bool ret = false;
+
+	if (hweight8(info->check_set &
+		     (XT_RECENT_SET | XT_RECENT_REMOVE |
+		      XT_RECENT_CHECK | XT_RECENT_UPDATE)) != 1)
+		return false;
+	if ((info->check_set & (XT_RECENT_SET | XT_RECENT_REMOVE)) &&
+	    (info->seconds || info->hit_count))
+		return false;
+	if (info->hit_count > ip_pkt_list_tot)
+		return false;
+	if (info->name[0] == '\0' ||
+	    strnlen(info->name, XT_RECENT_NAME_LEN) == XT_RECENT_NAME_LEN)
+		return false;
+
+	mutex_lock(&recent_mutex);
+	t = recent_table_lookup(info->name);
+	if (t != NULL) {
+		t->refcnt++;
+		ret = true;
+		goto out;
+	}
+
+	t = kzalloc(sizeof(*t) + sizeof(t->iphash[0]) * ip_list_hash_size,
+		    GFP_KERNEL);
+	if (t == NULL)
+		goto out;
+	t->refcnt = 1;
+	strcpy(t->name, info->name);
+	INIT_LIST_HEAD(&t->lru_list);
+	for (i = 0; i < ip_list_hash_size; i++)
+		INIT_LIST_HEAD(&t->iphash[i]);
+#ifdef CONFIG_PROC_FS
+	t->proc = proc_create(t->name, ip_list_perms, recent_proc_dir,
+		  &recent_mt_fops);
+	if (t->proc == NULL) {
+		kfree(t);
+		goto out;
+	}
+#ifdef CONFIG_NETFILTER_XT_MATCH_RECENT_PROC_COMPAT
+	t->proc_old = proc_create(t->name, ip_list_perms, proc_old_dir,
+		      &recent_old_fops);
+	if (t->proc_old == NULL) {
+		remove_proc_entry(t->name, proc_old_dir);
+		kfree(t);
+		goto out;
+	}
+	t->proc_old->uid   = ip_list_uid;
+	t->proc_old->gid   = ip_list_gid;
+	t->proc_old->data  = t;
+#endif
+	t->proc->uid       = ip_list_uid;
+	t->proc->gid       = ip_list_gid;
+	t->proc->data      = t;
+#endif
+	spin_lock_bh(&recent_lock);
+	list_add_tail(&t->list, &tables);
+	spin_unlock_bh(&recent_lock);
+	ret = true;
+out:
+	mutex_unlock(&recent_mutex);
+	return ret;
+}
+
+static void recent_mt_destroy(const struct xt_mtdtor_param *par)
+{
+	const struct xt_recent_mtinfo *info = par->matchinfo;
+	struct recent_table *t;
+
+	mutex_lock(&recent_mutex);
+	t = recent_table_lookup(info->name);
+	if (--t->refcnt == 0) {
+		spin_lock_bh(&recent_lock);
+		list_del(&t->list);
+		spin_unlock_bh(&recent_lock);
+#ifdef CONFIG_PROC_FS
+#ifdef CONFIG_NETFILTER_XT_MATCH_RECENT_PROC_COMPAT
+		remove_proc_entry(t->name, proc_old_dir);
+#endif
+		remove_proc_entry(t->name, recent_proc_dir);
+#endif
+		recent_table_flush(t);
+		kfree(t);
+	}
+	mutex_unlock(&recent_mutex);
+}
+
+#ifdef CONFIG_PROC_FS
+struct recent_iter_state {
+	const struct recent_table *table;
+	unsigned int		bucket;
+};
+
+static void *recent_seq_start(struct seq_file *seq, loff_t *pos)
+	__acquires(recent_lock)
+{
+	struct recent_iter_state *st = seq->private;
+	const struct recent_table *t = st->table;
+	struct recent_entry *e;
+	loff_t p = *pos;
+
+	spin_lock_bh(&recent_lock);
+
+	for (st->bucket = 0; st->bucket < ip_list_hash_size; st->bucket++)
+		list_for_each_entry(e, &t->iphash[st->bucket], list)
+			if (p-- == 0)
+				return e;
+	return NULL;
+}
+
+static void *recent_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+{
+	struct recent_iter_state *st = seq->private;
+	const struct recent_table *t = st->table;
+	const struct recent_entry *e = v;
+	const struct list_head *head = e->list.next;
+
+	while (head == &t->iphash[st->bucket]) {
+		if (++st->bucket >= ip_list_hash_size)
+			return NULL;
+		head = t->iphash[st->bucket].next;
+	}
+	(*pos)++;
+	return list_entry(head, struct recent_entry, list);
+}
+
+static void recent_seq_stop(struct seq_file *s, void *v)
+	__releases(recent_lock)
+{
+	spin_unlock_bh(&recent_lock);
+}
+
+static int recent_seq_show(struct seq_file *seq, void *v)
+{
+	const struct recent_entry *e = v;
+	unsigned int i;
+
+	i = (e->index - 1) % ip_pkt_list_tot;
+	if (e->family == NFPROTO_IPV4)
+		seq_printf(seq, "src=" NIPQUAD_FMT " ttl: %u last_seen: %lu "
+			   "oldest_pkt: %u", NIPQUAD(e->addr.ip), e->ttl,
+			   e->stamps[i], e->index);
+	else
+		seq_printf(seq, "src=" NIP6_FMT " ttl: %u last_seen: %lu "
+			   "oldest_pkt: %u", NIP6(e->addr.in6), e->ttl,
+			   e->stamps[i], e->index);
+	for (i = 0; i < e->nstamps; i++)
+		seq_printf(seq, "%s %lu", i ? "," : "", e->stamps[i]);
+	seq_printf(seq, "\n");
+	return 0;
+}
+
+static const struct seq_operations recent_seq_ops = {
+	.start		= recent_seq_start,
+	.next		= recent_seq_next,
+	.stop		= recent_seq_stop,
+	.show		= recent_seq_show,
+};
+
+static int recent_seq_open(struct inode *inode, struct file *file)
+{
+	struct proc_dir_entry *pde = PDE(inode);
+	struct recent_iter_state *st;
+
+	st = __seq_open_private(file, &recent_seq_ops, sizeof(*st));
+	if (st == NULL)
+		return -ENOMEM;
+
+	st->table    = pde->data;
+	return 0;
+}
+
+#ifdef CONFIG_NETFILTER_XT_MATCH_RECENT_PROC_COMPAT
+static int recent_old_seq_open(struct inode *inode, struct file *filp)
+{
+	static bool warned_of_old;
+
+	if (unlikely(!warned_of_old)) {
+		printk(KERN_INFO KBUILD_MODNAME ": Use of /proc/net/ipt_recent"
+		       " is deprecated; use /proc/net/xt_recent.\n");
+		warned_of_old = true;
+	}
+	return recent_seq_open(inode, filp);
+}
+
+static ssize_t recent_old_proc_write(struct file *file,
+				     const char __user *input,
+				     size_t size, loff_t *loff)
+{
+	const struct proc_dir_entry *pde = PDE(file->f_path.dentry->d_inode);
+	struct recent_table *t = pde->data;
+	struct recent_entry *e;
+	char buf[sizeof("+255.255.255.255")], *c = buf;
+	__be32 addr;
+	int add;
+
+	if (size > sizeof(buf))
+		size = sizeof(buf);
+	if (copy_from_user(buf, input, size))
+		return -EFAULT;
+
+	while (isspace(*c))
+		c++;
+
+	if (size - (c - buf) < 5)
+		return c - buf;
+	if (!strncmp(c, "clear", 5)) {
+		c += 5;
+		spin_lock_bh(&recent_lock);
+		recent_table_flush(t);
+		spin_unlock_bh(&recent_lock);
+		return c - buf;
+	}
+
+	switch (*c) {
+	case '-':
+		add = 0;
+		c++;
+		break;
+	case '+':
+		c++;
+	default:
+		add = 1;
+		break;
+	}
+	addr = in_aton(c);
+
+	spin_lock_bh(&recent_lock);
+	e = recent_entry_lookup(t, (const void *)&addr, NFPROTO_IPV4, 0);
+	if (e == NULL) {
+		if (add)
+			recent_entry_init(t, (const void *)&addr,
+					  NFPROTO_IPV4, 0);
+	} else {
+		if (add)
+			recent_entry_update(t, e);
+		else
+			recent_entry_remove(t, e);
+	}
+	spin_unlock_bh(&recent_lock);
+	return size;
+}
+
+static const struct file_operations recent_old_fops = {
+	.open		= recent_old_seq_open,
+	.read		= seq_read,
+	.write		= recent_old_proc_write,
+	.release	= seq_release_private,
+	.owner		= THIS_MODULE,
+};
+#endif
+
+static ssize_t
+recent_mt_proc_write(struct file *file, const char __user *input,
+		     size_t size, loff_t *loff)
+{
+	const struct proc_dir_entry *pde = PDE(file->f_path.dentry->d_inode);
+	struct recent_table *t = pde->data;
+	struct recent_entry *e;
+	char buf[sizeof("+b335:1d35:1e55:dead:c0de:1715:5afe:c0de")];
+	const char *c = buf;
+	union nf_inet_addr addr;
+	u_int16_t family;
+	bool add, succ;
+
+	if (size == 0)
+		return 0;
+	if (size > sizeof(buf))
+		size = sizeof(buf);
+	if (copy_from_user(buf, input, size) != 0)
+		return -EFAULT;
+
+	/* Strict protocol! */
+	if (*loff != 0)
+		return -ESPIPE;
+	switch (*c) {
+	case '/': /* flush table */
+		spin_lock_bh(&recent_lock);
+		recent_table_flush(t);
+		spin_unlock_bh(&recent_lock);
+		return size;
+	case '-': /* remove address */
+		add = false;
+		break;
+	case '+': /* add address */
+		add = true;
+		break;
+	default:
+		printk(KERN_INFO KBUILD_MODNAME ": Need +ip, -ip or /\n");
+		return -EINVAL;
+	}
+
+	++c;
+	--size;
+	if (strnchr(c, size, ':') != NULL) {
+		family = NFPROTO_IPV6;
+		succ   = in6_pton(c, size, (void *)&addr, '\n', NULL);
+	} else {
+		family = NFPROTO_IPV4;
+		succ   = in4_pton(c, size, (void *)&addr, '\n', NULL);
+	}
+
+	if (!succ) {
+		printk(KERN_INFO KBUILD_MODNAME ": illegal address written "
+		       "to procfs\n");
+		return -EINVAL;
+	}
+
+	spin_lock_bh(&recent_lock);
+	e = recent_entry_lookup(t, &addr, family, 0);
+	if (e == NULL) {
+		if (add)
+			recent_entry_init(t, &addr, family, 0);
+	} else {
+		if (add)
+			recent_entry_update(t, e);
+		else
+			recent_entry_remove(t, e);
+	}
+	spin_unlock_bh(&recent_lock);
+	/* Note we removed one above */
+	*loff += size + 1;
+	return size + 1;
+}
+
+static const struct file_operations recent_mt_fops = {
+	.open    = recent_seq_open,
+	.read    = seq_read,
+	.write   = recent_mt_proc_write,
+	.release = seq_release_private,
+	.owner   = THIS_MODULE,
+};
+#endif /* CONFIG_PROC_FS */
+
+static struct xt_match recent_mt_reg[] __read_mostly = {
+	{
+		.name       = "recent",
+		.revision   = 0,
+		.family     = NFPROTO_IPV4,
+		.match      = recent_mt,
+		.matchsize  = sizeof(struct xt_recent_mtinfo),
+		.checkentry = recent_mt_check,
+		.destroy    = recent_mt_destroy,
+		.me         = THIS_MODULE,
+	},
+	{
+		.name       = "recent",
+		.revision   = 0,
+		.family     = NFPROTO_IPV6,
+		.match      = recent_mt,
+		.matchsize  = sizeof(struct xt_recent_mtinfo),
+		.checkentry = recent_mt_check,
+		.destroy    = recent_mt_destroy,
+		.me         = THIS_MODULE,
+	},
+};
+
+static int __init recent_mt_init(void)
+{
+	int err;
+
+	if (!ip_list_tot || !ip_pkt_list_tot || ip_pkt_list_tot > 255)
+		return -EINVAL;
+	ip_list_hash_size = 1 << fls(ip_list_tot);
+
+	err = xt_register_matches(recent_mt_reg, ARRAY_SIZE(recent_mt_reg));
+#ifdef CONFIG_PROC_FS
+	if (err)
+		return err;
+	recent_proc_dir = proc_mkdir("xt_recent", init_net.proc_net);
+	if (recent_proc_dir == NULL) {
+		xt_unregister_matches(recent_mt_reg, ARRAY_SIZE(recent_mt_reg));
+		err = -ENOMEM;
+	}
+#ifdef CONFIG_NETFILTER_XT_MATCH_RECENT_PROC_COMPAT
+	if (err < 0)
+		return err;
+	proc_old_dir = proc_mkdir("ipt_recent", init_net.proc_net);
+	if (proc_old_dir == NULL) {
+		remove_proc_entry("xt_recent", init_net.proc_net);
+		xt_unregister_matches(recent_mt_reg, ARRAY_SIZE(recent_mt_reg));
+		err = -ENOMEM;
+	}
+#endif
+#endif
+	return err;
+}
+
+static void __exit recent_mt_exit(void)
+{
+	BUG_ON(!list_empty(&tables));
+	xt_unregister_matches(recent_mt_reg, ARRAY_SIZE(recent_mt_reg));
+#ifdef CONFIG_PROC_FS
+#ifdef CONFIG_NETFILTER_XT_MATCH_RECENT_PROC_COMPAT
+	remove_proc_entry("ipt_recent", init_net.proc_net);
+#endif
+	remove_proc_entry("xt_recent", init_net.proc_net);
+#endif
+}
+
+module_init(recent_mt_init);
+module_exit(recent_mt_exit);
diff --git a/net/netfilter/xt_sctp.c b/net/netfilter/xt_sctp.c
index e6e4681..e223cb4 100644
--- a/net/netfilter/xt_sctp.c
+++ b/net/netfilter/xt_sctp.c
@@ -117,23 +117,21 @@
 }
 
 static bool
-sctp_mt(const struct sk_buff *skb, const struct net_device *in,
-        const struct net_device *out, const struct xt_match *match,
-        const void *matchinfo, int offset, unsigned int protoff, bool *hotdrop)
+sctp_mt(const struct sk_buff *skb, const struct xt_match_param *par)
 {
-	const struct xt_sctp_info *info = matchinfo;
+	const struct xt_sctp_info *info = par->matchinfo;
 	const sctp_sctphdr_t *sh;
 	sctp_sctphdr_t _sh;
 
-	if (offset) {
+	if (par->fragoff != 0) {
 		duprintf("Dropping non-first fragment.. FIXME\n");
 		return false;
 	}
 
-	sh = skb_header_pointer(skb, protoff, sizeof(_sh), &_sh);
+	sh = skb_header_pointer(skb, par->thoff, sizeof(_sh), &_sh);
 	if (sh == NULL) {
 		duprintf("Dropping evil TCP offset=0 tinygram.\n");
-		*hotdrop = true;
+		*par->hotdrop = true;
 		return false;
 	}
 	duprintf("spt: %d\tdpt: %d\n", ntohs(sh->source), ntohs(sh->dest));
@@ -144,17 +142,14 @@
 		&& SCCHECK(ntohs(sh->dest) >= info->dpts[0]
 			&& ntohs(sh->dest) <= info->dpts[1],
 			XT_SCTP_DEST_PORTS, info->flags, info->invflags)
-		&& SCCHECK(match_packet(skb, protoff + sizeof (sctp_sctphdr_t),
-					info, hotdrop),
+		&& SCCHECK(match_packet(skb, par->thoff + sizeof(sctp_sctphdr_t),
+					info, par->hotdrop),
 			   XT_SCTP_CHUNK_TYPES, info->flags, info->invflags);
 }
 
-static bool
-sctp_mt_check(const char *tablename, const void *inf,
-              const struct xt_match *match, void *matchinfo,
-              unsigned int hook_mask)
+static bool sctp_mt_check(const struct xt_mtchk_param *par)
 {
-	const struct xt_sctp_info *info = matchinfo;
+	const struct xt_sctp_info *info = par->matchinfo;
 
 	return !(info->flags & ~XT_SCTP_VALID_FLAGS)
 		&& !(info->invflags & ~XT_SCTP_VALID_FLAGS)
@@ -169,7 +164,7 @@
 static struct xt_match sctp_mt_reg[] __read_mostly = {
 	{
 		.name		= "sctp",
-		.family		= AF_INET,
+		.family		= NFPROTO_IPV4,
 		.checkentry	= sctp_mt_check,
 		.match		= sctp_mt,
 		.matchsize	= sizeof(struct xt_sctp_info),
@@ -178,7 +173,7 @@
 	},
 	{
 		.name		= "sctp",
-		.family		= AF_INET6,
+		.family		= NFPROTO_IPV6,
 		.checkentry	= sctp_mt_check,
 		.match		= sctp_mt,
 		.matchsize	= sizeof(struct xt_sctp_info),
diff --git a/net/netfilter/xt_socket.c b/net/netfilter/xt_socket.c
new file mode 100644
index 0000000..02a8fed
--- /dev/null
+++ b/net/netfilter/xt_socket.c
@@ -0,0 +1,185 @@
+/*
+ * Transparent proxy support for Linux/iptables
+ *
+ * Copyright (C) 2007-2008 BalaBit IT Ltd.
+ * Author: Krisztian Kovacs
+ *
+ * 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/skbuff.h>
+#include <linux/netfilter/x_tables.h>
+#include <linux/netfilter_ipv4/ip_tables.h>
+#include <net/tcp.h>
+#include <net/udp.h>
+#include <net/icmp.h>
+#include <net/sock.h>
+#include <net/inet_sock.h>
+#include <net/netfilter/nf_tproxy_core.h>
+#include <net/netfilter/ipv4/nf_defrag_ipv4.h>
+
+#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
+#define XT_SOCKET_HAVE_CONNTRACK 1
+#include <net/netfilter/nf_conntrack.h>
+#endif
+
+static int
+extract_icmp_fields(const struct sk_buff *skb,
+		    u8 *protocol,
+		    __be32 *raddr,
+		    __be32 *laddr,
+		    __be16 *rport,
+		    __be16 *lport)
+{
+	unsigned int outside_hdrlen = ip_hdrlen(skb);
+	struct iphdr *inside_iph, _inside_iph;
+	struct icmphdr *icmph, _icmph;
+	__be16 *ports, _ports[2];
+
+	icmph = skb_header_pointer(skb, outside_hdrlen,
+				   sizeof(_icmph), &_icmph);
+	if (icmph == NULL)
+		return 1;
+
+	switch (icmph->type) {
+	case ICMP_DEST_UNREACH:
+	case ICMP_SOURCE_QUENCH:
+	case ICMP_REDIRECT:
+	case ICMP_TIME_EXCEEDED:
+	case ICMP_PARAMETERPROB:
+		break;
+	default:
+		return 1;
+	}
+
+	inside_iph = skb_header_pointer(skb, outside_hdrlen +
+					sizeof(struct icmphdr),
+					sizeof(_inside_iph), &_inside_iph);
+	if (inside_iph == NULL)
+		return 1;
+
+	if (inside_iph->protocol != IPPROTO_TCP &&
+	    inside_iph->protocol != IPPROTO_UDP)
+		return 1;
+
+	ports = skb_header_pointer(skb, outside_hdrlen +
+				   sizeof(struct icmphdr) +
+				   (inside_iph->ihl << 2),
+				   sizeof(_ports), &_ports);
+	if (ports == NULL)
+		return 1;
+
+	/* the inside IP packet is the one quoted from our side, thus
+	 * its saddr is the local address */
+	*protocol = inside_iph->protocol;
+	*laddr = inside_iph->saddr;
+	*lport = ports[0];
+	*raddr = inside_iph->daddr;
+	*rport = ports[1];
+
+	return 0;
+}
+
+
+static bool
+socket_mt(const struct sk_buff *skb, const struct xt_match_param *par)
+{
+	const struct iphdr *iph = ip_hdr(skb);
+	struct udphdr _hdr, *hp = NULL;
+	struct sock *sk;
+	__be32 daddr, saddr;
+	__be16 dport, sport;
+	u8 protocol;
+#ifdef XT_SOCKET_HAVE_CONNTRACK
+	struct nf_conn const *ct;
+	enum ip_conntrack_info ctinfo;
+#endif
+
+	if (iph->protocol == IPPROTO_UDP || iph->protocol == IPPROTO_TCP) {
+		hp = skb_header_pointer(skb, ip_hdrlen(skb),
+					sizeof(_hdr), &_hdr);
+		if (hp == NULL)
+			return false;
+
+		protocol = iph->protocol;
+		saddr = iph->saddr;
+		sport = hp->source;
+		daddr = iph->daddr;
+		dport = hp->dest;
+
+	} else if (iph->protocol == IPPROTO_ICMP) {
+		if (extract_icmp_fields(skb, &protocol, &saddr, &daddr,
+					&sport, &dport))
+			return false;
+	} else {
+		return false;
+	}
+
+#ifdef XT_SOCKET_HAVE_CONNTRACK
+	/* Do the lookup with the original socket address in case this is a
+	 * reply packet of an established SNAT-ted connection. */
+
+	ct = nf_ct_get(skb, &ctinfo);
+	if (ct && (ct != &nf_conntrack_untracked) &&
+	    ((iph->protocol != IPPROTO_ICMP &&
+	      ctinfo == IP_CT_IS_REPLY + IP_CT_ESTABLISHED) ||
+	     (iph->protocol == IPPROTO_ICMP &&
+	      ctinfo == IP_CT_IS_REPLY + IP_CT_RELATED)) &&
+	    (ct->status & IPS_SRC_NAT_DONE)) {
+
+		daddr = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip;
+		dport = (iph->protocol == IPPROTO_TCP) ?
+			ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.tcp.port :
+			ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.udp.port;
+	}
+#endif
+
+	sk = nf_tproxy_get_sock_v4(dev_net(skb->dev), protocol,
+				   saddr, daddr, sport, dport, par->in, false);
+	if (sk != NULL) {
+		bool wildcard = (inet_sk(sk)->rcv_saddr == 0);
+
+		nf_tproxy_put_sock(sk);
+		if (wildcard)
+			sk = NULL;
+	}
+
+	pr_debug("socket match: proto %u %08x:%u -> %08x:%u "
+		 "(orig %08x:%u) sock %p\n",
+		 protocol, ntohl(saddr), ntohs(sport),
+		 ntohl(daddr), ntohs(dport),
+		 ntohl(iph->daddr), hp ? ntohs(hp->dest) : 0, sk);
+
+	return (sk != NULL);
+}
+
+static struct xt_match socket_mt_reg __read_mostly = {
+	.name		= "socket",
+	.family		= AF_INET,
+	.match		= socket_mt,
+	.hooks		= 1 << NF_INET_PRE_ROUTING,
+	.me		= THIS_MODULE,
+};
+
+static int __init socket_mt_init(void)
+{
+	nf_defrag_ipv4_enable();
+	return xt_register_match(&socket_mt_reg);
+}
+
+static void __exit socket_mt_exit(void)
+{
+	xt_unregister_match(&socket_mt_reg);
+}
+
+module_init(socket_mt_init);
+module_exit(socket_mt_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Krisztian Kovacs, Balazs Scheidler");
+MODULE_DESCRIPTION("x_tables socket match module");
+MODULE_ALIAS("ipt_socket");
diff --git a/net/netfilter/xt_state.c b/net/netfilter/xt_state.c
index a776dc3..4c946cb 100644
--- a/net/netfilter/xt_state.c
+++ b/net/netfilter/xt_state.c
@@ -21,12 +21,9 @@
 MODULE_ALIAS("ip6t_state");
 
 static bool
-state_mt(const struct sk_buff *skb, const struct net_device *in,
-         const struct net_device *out, const struct xt_match *match,
-         const void *matchinfo, int offset, unsigned int protoff,
-         bool *hotdrop)
+state_mt(const struct sk_buff *skb, const struct xt_match_param *par)
 {
-	const struct xt_state_info *sinfo = matchinfo;
+	const struct xt_state_info *sinfo = par->matchinfo;
 	enum ip_conntrack_info ctinfo;
 	unsigned int statebit;
 
@@ -40,28 +37,25 @@
 	return (sinfo->statemask & statebit);
 }
 
-static bool
-state_mt_check(const char *tablename, const void *inf,
-               const struct xt_match *match, void *matchinfo,
-               unsigned int hook_mask)
+static bool state_mt_check(const struct xt_mtchk_param *par)
 {
-	if (nf_ct_l3proto_try_module_get(match->family) < 0) {
+	if (nf_ct_l3proto_try_module_get(par->match->family) < 0) {
 		printk(KERN_WARNING "can't load conntrack support for "
-				    "proto=%u\n", match->family);
+				    "proto=%u\n", par->match->family);
 		return false;
 	}
 	return true;
 }
 
-static void state_mt_destroy(const struct xt_match *match, void *matchinfo)
+static void state_mt_destroy(const struct xt_mtdtor_param *par)
 {
-	nf_ct_l3proto_module_put(match->family);
+	nf_ct_l3proto_module_put(par->match->family);
 }
 
 static struct xt_match state_mt_reg[] __read_mostly = {
 	{
 		.name		= "state",
-		.family		= AF_INET,
+		.family		= NFPROTO_IPV4,
 		.checkentry	= state_mt_check,
 		.match		= state_mt,
 		.destroy	= state_mt_destroy,
@@ -70,7 +64,7 @@
 	},
 	{
 		.name		= "state",
-		.family		= AF_INET6,
+		.family		= NFPROTO_IPV6,
 		.checkentry	= state_mt_check,
 		.match		= state_mt,
 		.destroy	= state_mt_destroy,
diff --git a/net/netfilter/xt_statistic.c b/net/netfilter/xt_statistic.c
index 4313308..0d75141 100644
--- a/net/netfilter/xt_statistic.c
+++ b/net/netfilter/xt_statistic.c
@@ -25,12 +25,9 @@
 static DEFINE_SPINLOCK(nth_lock);
 
 static bool
-statistic_mt(const struct sk_buff *skb, const struct net_device *in,
-             const struct net_device *out, const struct xt_match *match,
-             const void *matchinfo, int offset, unsigned int protoff,
-             bool *hotdrop)
+statistic_mt(const struct sk_buff *skb, const struct xt_match_param *par)
 {
-	struct xt_statistic_info *info = (struct xt_statistic_info *)matchinfo;
+	struct xt_statistic_info *info = (void *)par->matchinfo;
 	bool ret = info->flags & XT_STATISTIC_INVERT;
 
 	switch (info->mode) {
@@ -52,12 +49,9 @@
 	return ret;
 }
 
-static bool
-statistic_mt_check(const char *tablename, const void *entry,
-                   const struct xt_match *match, void *matchinfo,
-                   unsigned int hook_mask)
+static bool statistic_mt_check(const struct xt_mtchk_param *par)
 {
-	struct xt_statistic_info *info = matchinfo;
+	struct xt_statistic_info *info = par->matchinfo;
 
 	if (info->mode > XT_STATISTIC_MODE_MAX ||
 	    info->flags & ~XT_STATISTIC_MASK)
@@ -66,35 +60,24 @@
 	return true;
 }
 
-static struct xt_match statistic_mt_reg[] __read_mostly = {
-	{
-		.name		= "statistic",
-		.family		= AF_INET,
-		.checkentry	= statistic_mt_check,
-		.match		= statistic_mt,
-		.matchsize	= sizeof(struct xt_statistic_info),
-		.me		= THIS_MODULE,
-	},
-	{
-		.name		= "statistic",
-		.family		= AF_INET6,
-		.checkentry	= statistic_mt_check,
-		.match		= statistic_mt,
-		.matchsize	= sizeof(struct xt_statistic_info),
-		.me		= THIS_MODULE,
-	},
+static struct xt_match xt_statistic_mt_reg __read_mostly = {
+	.name       = "statistic",
+	.revision   = 0,
+	.family     = NFPROTO_UNSPEC,
+	.match      = statistic_mt,
+	.checkentry = statistic_mt_check,
+	.matchsize  = sizeof(struct xt_statistic_info),
+	.me         = THIS_MODULE,
 };
 
 static int __init statistic_mt_init(void)
 {
-	return xt_register_matches(statistic_mt_reg,
-	       ARRAY_SIZE(statistic_mt_reg));
+	return xt_register_match(&xt_statistic_mt_reg);
 }
 
 static void __exit statistic_mt_exit(void)
 {
-	xt_unregister_matches(statistic_mt_reg,
-	                      ARRAY_SIZE(statistic_mt_reg));
+	xt_unregister_match(&xt_statistic_mt_reg);
 }
 
 module_init(statistic_mt_init);
diff --git a/net/netfilter/xt_string.c b/net/netfilter/xt_string.c
index 4903182..b4d7741 100644
--- a/net/netfilter/xt_string.c
+++ b/net/netfilter/xt_string.c
@@ -22,18 +22,15 @@
 MODULE_ALIAS("ip6t_string");
 
 static bool
-string_mt(const struct sk_buff *skb, const struct net_device *in,
-          const struct net_device *out, const struct xt_match *match,
-          const void *matchinfo, int offset, unsigned int protoff,
-          bool *hotdrop)
+string_mt(const struct sk_buff *skb, const struct xt_match_param *par)
 {
-	const struct xt_string_info *conf = matchinfo;
+	const struct xt_string_info *conf = par->matchinfo;
 	struct ts_state state;
 	int invert;
 
 	memset(&state, 0, sizeof(struct ts_state));
 
-	invert = (match->revision == 0 ? conf->u.v0.invert :
+	invert = (par->match->revision == 0 ? conf->u.v0.invert :
 				    conf->u.v1.flags & XT_STRING_FLAG_INVERT);
 
 	return (skb_find_text((struct sk_buff *)skb, conf->from_offset,
@@ -43,12 +40,9 @@
 
 #define STRING_TEXT_PRIV(m) ((struct xt_string_info *)(m))
 
-static bool
-string_mt_check(const char *tablename, const void *ip,
-                const struct xt_match *match, void *matchinfo,
-                unsigned int hook_mask)
+static bool string_mt_check(const struct xt_mtchk_param *par)
 {
-	struct xt_string_info *conf = matchinfo;
+	struct xt_string_info *conf = par->matchinfo;
 	struct ts_config *ts_conf;
 	int flags = TS_AUTOLOAD;
 
@@ -59,7 +53,7 @@
 		return false;
 	if (conf->patlen > XT_STRING_MAX_PATTERN_SIZE)
 		return false;
-	if (match->revision == 1) {
+	if (par->match->revision == 1) {
 		if (conf->u.v1.flags &
 		    ~(XT_STRING_FLAG_IGNORECASE | XT_STRING_FLAG_INVERT))
 			return false;
@@ -76,16 +70,16 @@
 	return true;
 }
 
-static void string_mt_destroy(const struct xt_match *match, void *matchinfo)
+static void string_mt_destroy(const struct xt_mtdtor_param *par)
 {
-	textsearch_destroy(STRING_TEXT_PRIV(matchinfo)->config);
+	textsearch_destroy(STRING_TEXT_PRIV(par->matchinfo)->config);
 }
 
-static struct xt_match string_mt_reg[] __read_mostly = {
+static struct xt_match xt_string_mt_reg[] __read_mostly = {
 	{
 		.name 		= "string",
 		.revision	= 0,
-		.family		= AF_INET,
+		.family		= NFPROTO_UNSPEC,
 		.checkentry	= string_mt_check,
 		.match 		= string_mt,
 		.destroy 	= string_mt_destroy,
@@ -95,27 +89,7 @@
 	{
 		.name 		= "string",
 		.revision	= 1,
-		.family		= AF_INET,
-		.checkentry	= string_mt_check,
-		.match 		= string_mt,
-		.destroy 	= string_mt_destroy,
-		.matchsize	= sizeof(struct xt_string_info),
-		.me 		= THIS_MODULE
-	},
-	{
-		.name 		= "string",
-		.revision	= 0,
-		.family		= AF_INET6,
-		.checkentry	= string_mt_check,
-		.match 		= string_mt,
-		.destroy 	= string_mt_destroy,
-		.matchsize	= sizeof(struct xt_string_info),
-		.me 		= THIS_MODULE
-	},
-	{
-		.name 		= "string",
-		.revision	= 1,
-		.family		= AF_INET6,
+		.family		= NFPROTO_UNSPEC,
 		.checkentry	= string_mt_check,
 		.match 		= string_mt,
 		.destroy 	= string_mt_destroy,
@@ -126,12 +100,13 @@
 
 static int __init string_mt_init(void)
 {
-	return xt_register_matches(string_mt_reg, ARRAY_SIZE(string_mt_reg));
+	return xt_register_matches(xt_string_mt_reg,
+				   ARRAY_SIZE(xt_string_mt_reg));
 }
 
 static void __exit string_mt_exit(void)
 {
-	xt_unregister_matches(string_mt_reg, ARRAY_SIZE(string_mt_reg));
+	xt_unregister_matches(xt_string_mt_reg, ARRAY_SIZE(xt_string_mt_reg));
 }
 
 module_init(string_mt_init);
diff --git a/net/netfilter/xt_tcpmss.c b/net/netfilter/xt_tcpmss.c
index 6771bf0..4809b34 100644
--- a/net/netfilter/xt_tcpmss.c
+++ b/net/netfilter/xt_tcpmss.c
@@ -25,12 +25,9 @@
 MODULE_ALIAS("ip6t_tcpmss");
 
 static bool
-tcpmss_mt(const struct sk_buff *skb, const struct net_device *in,
-          const struct net_device *out, const struct xt_match *match,
-          const void *matchinfo, int offset, unsigned int protoff,
-          bool *hotdrop)
+tcpmss_mt(const struct sk_buff *skb, const struct xt_match_param *par)
 {
-	const struct xt_tcpmss_match_info *info = matchinfo;
+	const struct xt_tcpmss_match_info *info = par->matchinfo;
 	const struct tcphdr *th;
 	struct tcphdr _tcph;
 	/* tcp.doff is only 4 bits, ie. max 15 * 4 bytes */
@@ -39,7 +36,7 @@
 	unsigned int i, optlen;
 
 	/* If we don't have the whole header, drop packet. */
-	th = skb_header_pointer(skb, protoff, sizeof(_tcph), &_tcph);
+	th = skb_header_pointer(skb, par->thoff, sizeof(_tcph), &_tcph);
 	if (th == NULL)
 		goto dropit;
 
@@ -52,7 +49,7 @@
 		goto out;
 
 	/* Truncated options. */
-	op = skb_header_pointer(skb, protoff + sizeof(*th), optlen, _opt);
+	op = skb_header_pointer(skb, par->thoff + sizeof(*th), optlen, _opt);
 	if (op == NULL)
 		goto dropit;
 
@@ -76,14 +73,14 @@
 	return info->invert;
 
 dropit:
-	*hotdrop = true;
+	*par->hotdrop = true;
 	return false;
 }
 
 static struct xt_match tcpmss_mt_reg[] __read_mostly = {
 	{
 		.name		= "tcpmss",
-		.family		= AF_INET,
+		.family		= NFPROTO_IPV4,
 		.match		= tcpmss_mt,
 		.matchsize	= sizeof(struct xt_tcpmss_match_info),
 		.proto		= IPPROTO_TCP,
@@ -91,7 +88,7 @@
 	},
 	{
 		.name		= "tcpmss",
-		.family		= AF_INET6,
+		.family		= NFPROTO_IPV6,
 		.match		= tcpmss_mt,
 		.matchsize	= sizeof(struct xt_tcpmss_match_info),
 		.proto		= IPPROTO_TCP,
diff --git a/net/netfilter/xt_tcpudp.c b/net/netfilter/xt_tcpudp.c
index 951b06b..1ebdc49 100644
--- a/net/netfilter/xt_tcpudp.c
+++ b/net/netfilter/xt_tcpudp.c
@@ -68,25 +68,22 @@
 	return invert;
 }
 
-static bool
-tcp_mt(const struct sk_buff *skb, const struct net_device *in,
-       const struct net_device *out, const struct xt_match *match,
-       const void *matchinfo, int offset, unsigned int protoff, bool *hotdrop)
+static bool tcp_mt(const struct sk_buff *skb, const struct xt_match_param *par)
 {
 	const struct tcphdr *th;
 	struct tcphdr _tcph;
-	const struct xt_tcp *tcpinfo = matchinfo;
+	const struct xt_tcp *tcpinfo = par->matchinfo;
 
-	if (offset) {
+	if (par->fragoff != 0) {
 		/* To quote Alan:
 
 		   Don't allow a fragment of TCP 8 bytes in. Nobody normal
 		   causes this. Its a cracker trying to break in by doing a
 		   flag overwrite to pass the direction checks.
 		*/
-		if (offset == 1) {
+		if (par->fragoff == 1) {
 			duprintf("Dropping evil TCP offset=1 frag.\n");
-			*hotdrop = true;
+			*par->hotdrop = true;
 		}
 		/* Must not be a fragment. */
 		return false;
@@ -94,12 +91,12 @@
 
 #define FWINVTCP(bool, invflg) ((bool) ^ !!(tcpinfo->invflags & (invflg)))
 
-	th = skb_header_pointer(skb, protoff, sizeof(_tcph), &_tcph);
+	th = skb_header_pointer(skb, par->thoff, sizeof(_tcph), &_tcph);
 	if (th == NULL) {
 		/* We've been asked to examine this packet, and we
 		   can't.  Hence, no choice but to drop. */
 		duprintf("Dropping evil TCP offset=0 tinygram.\n");
-		*hotdrop = true;
+		*par->hotdrop = true;
 		return false;
 	}
 
@@ -117,49 +114,42 @@
 		return false;
 	if (tcpinfo->option) {
 		if (th->doff * 4 < sizeof(_tcph)) {
-			*hotdrop = true;
+			*par->hotdrop = true;
 			return false;
 		}
-		if (!tcp_find_option(tcpinfo->option, skb, protoff,
+		if (!tcp_find_option(tcpinfo->option, skb, par->thoff,
 				     th->doff*4 - sizeof(_tcph),
 				     tcpinfo->invflags & XT_TCP_INV_OPTION,
-				     hotdrop))
+				     par->hotdrop))
 			return false;
 	}
 	return true;
 }
 
-/* Called when user tries to insert an entry of this type. */
-static bool
-tcp_mt_check(const char *tablename, const void *info,
-             const struct xt_match *match, void *matchinfo,
-             unsigned int hook_mask)
+static bool tcp_mt_check(const struct xt_mtchk_param *par)
 {
-	const struct xt_tcp *tcpinfo = matchinfo;
+	const struct xt_tcp *tcpinfo = par->matchinfo;
 
 	/* Must specify no unknown invflags */
 	return !(tcpinfo->invflags & ~XT_TCP_INV_MASK);
 }
 
-static bool
-udp_mt(const struct sk_buff *skb, const struct net_device *in,
-       const struct net_device *out, const struct xt_match *match,
-       const void *matchinfo, int offset, unsigned int protoff, bool *hotdrop)
+static bool udp_mt(const struct sk_buff *skb, const struct xt_match_param *par)
 {
 	const struct udphdr *uh;
 	struct udphdr _udph;
-	const struct xt_udp *udpinfo = matchinfo;
+	const struct xt_udp *udpinfo = par->matchinfo;
 
 	/* Must not be a fragment. */
-	if (offset)
+	if (par->fragoff != 0)
 		return false;
 
-	uh = skb_header_pointer(skb, protoff, sizeof(_udph), &_udph);
+	uh = skb_header_pointer(skb, par->thoff, sizeof(_udph), &_udph);
 	if (uh == NULL) {
 		/* We've been asked to examine this packet, and we
 		   can't.  Hence, no choice but to drop. */
 		duprintf("Dropping evil UDP tinygram.\n");
-		*hotdrop = true;
+		*par->hotdrop = true;
 		return false;
 	}
 
@@ -171,13 +161,9 @@
 			      !!(udpinfo->invflags & XT_UDP_INV_DSTPT));
 }
 
-/* Called when user tries to insert an entry of this type. */
-static bool
-udp_mt_check(const char *tablename, const void *info,
-             const struct xt_match *match, void *matchinfo,
-             unsigned int hook_mask)
+static bool udp_mt_check(const struct xt_mtchk_param *par)
 {
-	const struct xt_udp *udpinfo = matchinfo;
+	const struct xt_udp *udpinfo = par->matchinfo;
 
 	/* Must specify no unknown invflags */
 	return !(udpinfo->invflags & ~XT_UDP_INV_MASK);
@@ -186,7 +172,7 @@
 static struct xt_match tcpudp_mt_reg[] __read_mostly = {
 	{
 		.name		= "tcp",
-		.family		= AF_INET,
+		.family		= NFPROTO_IPV4,
 		.checkentry	= tcp_mt_check,
 		.match		= tcp_mt,
 		.matchsize	= sizeof(struct xt_tcp),
@@ -195,7 +181,7 @@
 	},
 	{
 		.name		= "tcp",
-		.family		= AF_INET6,
+		.family		= NFPROTO_IPV6,
 		.checkentry	= tcp_mt_check,
 		.match		= tcp_mt,
 		.matchsize	= sizeof(struct xt_tcp),
@@ -204,7 +190,7 @@
 	},
 	{
 		.name		= "udp",
-		.family		= AF_INET,
+		.family		= NFPROTO_IPV4,
 		.checkentry	= udp_mt_check,
 		.match		= udp_mt,
 		.matchsize	= sizeof(struct xt_udp),
@@ -213,7 +199,7 @@
 	},
 	{
 		.name		= "udp",
-		.family		= AF_INET6,
+		.family		= NFPROTO_IPV6,
 		.checkentry	= udp_mt_check,
 		.match		= udp_mt,
 		.matchsize	= sizeof(struct xt_udp),
@@ -222,7 +208,7 @@
 	},
 	{
 		.name		= "udplite",
-		.family		= AF_INET,
+		.family		= NFPROTO_IPV4,
 		.checkentry	= udp_mt_check,
 		.match		= udp_mt,
 		.matchsize	= sizeof(struct xt_udp),
@@ -231,7 +217,7 @@
 	},
 	{
 		.name		= "udplite",
-		.family		= AF_INET6,
+		.family		= NFPROTO_IPV6,
 		.checkentry	= udp_mt_check,
 		.match		= udp_mt,
 		.matchsize	= sizeof(struct xt_udp),
diff --git a/net/netfilter/xt_time.c b/net/netfilter/xt_time.c
index 9f32859..29375ba 100644
--- a/net/netfilter/xt_time.c
+++ b/net/netfilter/xt_time.c
@@ -136,26 +136,26 @@
 	 * from w repeatedly while counting.)
 	 */
 	if (is_leap(year)) {
+		/* use days_since_leapyear[] in a leap year */
 		for (i = ARRAY_SIZE(days_since_leapyear) - 1;
-		    i > 0 && days_since_year[i] > w; --i)
+		    i > 0 && days_since_leapyear[i] > w; --i)
 			/* just loop */;
+		r->monthday = w - days_since_leapyear[i] + 1;
 	} else {
 		for (i = ARRAY_SIZE(days_since_year) - 1;
 		    i > 0 && days_since_year[i] > w; --i)
 			/* just loop */;
+		r->monthday = w - days_since_year[i] + 1;
 	}
 
 	r->month    = i + 1;
-	r->monthday = w - days_since_year[i] + 1;
 	return;
 }
 
 static bool
-time_mt(const struct sk_buff *skb, const struct net_device *in,
-        const struct net_device *out, const struct xt_match *match,
-        const void *matchinfo, int offset, unsigned int protoff, bool *hotdrop)
+time_mt(const struct sk_buff *skb, const struct xt_match_param *par)
 {
-	const struct xt_time_info *info = matchinfo;
+	const struct xt_time_info *info = par->matchinfo;
 	unsigned int packet_time;
 	struct xtm current_time;
 	s64 stamp;
@@ -218,12 +218,9 @@
 	return true;
 }
 
-static bool
-time_mt_check(const char *tablename, const void *ip,
-              const struct xt_match *match, void *matchinfo,
-              unsigned int hook_mask)
+static bool time_mt_check(const struct xt_mtchk_param *par)
 {
-	const struct xt_time_info *info = matchinfo;
+	const struct xt_time_info *info = par->matchinfo;
 
 	if (info->daytime_start > XT_TIME_MAX_DAYTIME ||
 	    info->daytime_stop > XT_TIME_MAX_DAYTIME) {
@@ -235,33 +232,23 @@
 	return true;
 }
 
-static struct xt_match time_mt_reg[] __read_mostly = {
-	{
-		.name       = "time",
-		.family     = AF_INET,
-		.match      = time_mt,
-		.matchsize  = sizeof(struct xt_time_info),
-		.checkentry = time_mt_check,
-		.me         = THIS_MODULE,
-	},
-	{
-		.name       = "time",
-		.family     = AF_INET6,
-		.match      = time_mt,
-		.matchsize  = sizeof(struct xt_time_info),
-		.checkentry = time_mt_check,
-		.me         = THIS_MODULE,
-	},
+static struct xt_match xt_time_mt_reg __read_mostly = {
+	.name       = "time",
+	.family     = NFPROTO_UNSPEC,
+	.match      = time_mt,
+	.checkentry = time_mt_check,
+	.matchsize  = sizeof(struct xt_time_info),
+	.me         = THIS_MODULE,
 };
 
 static int __init time_mt_init(void)
 {
-	return xt_register_matches(time_mt_reg, ARRAY_SIZE(time_mt_reg));
+	return xt_register_match(&xt_time_mt_reg);
 }
 
 static void __exit time_mt_exit(void)
 {
-	xt_unregister_matches(time_mt_reg, ARRAY_SIZE(time_mt_reg));
+	xt_unregister_match(&xt_time_mt_reg);
 }
 
 module_init(time_mt_init);
diff --git a/net/netfilter/xt_u32.c b/net/netfilter/xt_u32.c
index 627e0f3..24a5276 100644
--- a/net/netfilter/xt_u32.c
+++ b/net/netfilter/xt_u32.c
@@ -87,43 +87,32 @@
 	return true;
 }
 
-static bool
-u32_mt(const struct sk_buff *skb, const struct net_device *in,
-       const struct net_device *out, const struct xt_match *match,
-       const void *matchinfo, int offset, unsigned int protoff, bool *hotdrop)
+static bool u32_mt(const struct sk_buff *skb, const struct xt_match_param *par)
 {
-	const struct xt_u32 *data = matchinfo;
+	const struct xt_u32 *data = par->matchinfo;
 	bool ret;
 
 	ret = u32_match_it(data, skb);
 	return ret ^ data->invert;
 }
 
-static struct xt_match u32_mt_reg[] __read_mostly = {
-	{
-		.name       = "u32",
-		.family     = AF_INET,
-		.match      = u32_mt,
-		.matchsize  = sizeof(struct xt_u32),
-		.me         = THIS_MODULE,
-	},
-	{
-		.name       = "u32",
-		.family     = AF_INET6,
-		.match      = u32_mt,
-		.matchsize  = sizeof(struct xt_u32),
-		.me         = THIS_MODULE,
-	},
+static struct xt_match xt_u32_mt_reg __read_mostly = {
+	.name       = "u32",
+	.revision   = 0,
+	.family     = NFPROTO_UNSPEC,
+	.match      = u32_mt,
+	.matchsize  = sizeof(struct xt_u32),
+	.me         = THIS_MODULE,
 };
 
 static int __init u32_mt_init(void)
 {
-	return xt_register_matches(u32_mt_reg, ARRAY_SIZE(u32_mt_reg));
+	return xt_register_match(&xt_u32_mt_reg);
 }
 
 static void __exit u32_mt_exit(void)
 {
-	xt_unregister_matches(u32_mt_reg, ARRAY_SIZE(u32_mt_reg));
+	xt_unregister_match(&xt_u32_mt_reg);
 }
 
 module_init(u32_mt_init);
diff --git a/net/netlabel/Makefile b/net/netlabel/Makefile
index 8af18c0..ea750e9 100644
--- a/net/netlabel/Makefile
+++ b/net/netlabel/Makefile
@@ -5,7 +5,8 @@
 #
 
 # base objects
-obj-y	:= netlabel_user.o netlabel_kapi.o netlabel_domainhash.o
+obj-y	:= netlabel_user.o netlabel_kapi.o
+obj-y	+= netlabel_domainhash.o netlabel_addrlist.o
 
 # management objects
 obj-y	+= netlabel_mgmt.o
diff --git a/net/netlabel/netlabel_addrlist.c b/net/netlabel/netlabel_addrlist.c
new file mode 100644
index 0000000..b0925a3
--- /dev/null
+++ b/net/netlabel/netlabel_addrlist.c
@@ -0,0 +1,388 @@
+/*
+ * NetLabel Network Address Lists
+ *
+ * This file contains network address list functions used to manage ordered
+ * lists of network addresses for use by the NetLabel subsystem.  The NetLabel
+ * system manages static and dynamic label mappings for network protocols such
+ * as CIPSO and RIPSO.
+ *
+ * Author: Paul Moore <paul.moore@hp.com>
+ *
+ */
+
+/*
+ * (c) Copyright Hewlett-Packard Development Company, L.P., 2008
+ *
+ * This program is free software;  you can redistribute it and/or 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/types.h>
+#include <linux/rcupdate.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/in.h>
+#include <linux/in6.h>
+#include <linux/ip.h>
+#include <linux/ipv6.h>
+#include <net/ip.h>
+#include <net/ipv6.h>
+#include <linux/audit.h>
+
+#include "netlabel_addrlist.h"
+
+/*
+ * Address List Functions
+ */
+
+/**
+ * netlbl_af4list_search - Search for a matching IPv4 address entry
+ * @addr: IPv4 address
+ * @head: the list head
+ *
+ * Description:
+ * Searches the IPv4 address list given by @head.  If a matching address entry
+ * is found it is returned, otherwise NULL is returned.  The caller is
+ * responsible for calling the rcu_read_[un]lock() functions.
+ *
+ */
+struct netlbl_af4list *netlbl_af4list_search(__be32 addr,
+					     struct list_head *head)
+{
+	struct netlbl_af4list *iter;
+
+	list_for_each_entry_rcu(iter, head, list)
+		if (iter->valid && (addr & iter->mask) == iter->addr)
+			return iter;
+
+	return NULL;
+}
+
+/**
+ * netlbl_af4list_search_exact - Search for an exact IPv4 address entry
+ * @addr: IPv4 address
+ * @mask: IPv4 address mask
+ * @head: the list head
+ *
+ * Description:
+ * Searches the IPv4 address list given by @head.  If an exact match if found
+ * it is returned, otherwise NULL is returned.  The caller is responsible for
+ * calling the rcu_read_[un]lock() functions.
+ *
+ */
+struct netlbl_af4list *netlbl_af4list_search_exact(__be32 addr,
+						   __be32 mask,
+						   struct list_head *head)
+{
+	struct netlbl_af4list *iter;
+
+	list_for_each_entry_rcu(iter, head, list)
+		if (iter->valid && iter->addr == addr && iter->mask == mask)
+			return iter;
+
+	return NULL;
+}
+
+
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+/**
+ * netlbl_af6list_search - Search for a matching IPv6 address entry
+ * @addr: IPv6 address
+ * @head: the list head
+ *
+ * Description:
+ * Searches the IPv6 address list given by @head.  If a matching address entry
+ * is found it is returned, otherwise NULL is returned.  The caller is
+ * responsible for calling the rcu_read_[un]lock() functions.
+ *
+ */
+struct netlbl_af6list *netlbl_af6list_search(const struct in6_addr *addr,
+					     struct list_head *head)
+{
+	struct netlbl_af6list *iter;
+
+	list_for_each_entry_rcu(iter, head, list)
+		if (iter->valid &&
+		    ipv6_masked_addr_cmp(&iter->addr, &iter->mask, addr) == 0)
+			return iter;
+
+	return NULL;
+}
+
+/**
+ * netlbl_af6list_search_exact - Search for an exact IPv6 address entry
+ * @addr: IPv6 address
+ * @mask: IPv6 address mask
+ * @head: the list head
+ *
+ * Description:
+ * Searches the IPv6 address list given by @head.  If an exact match if found
+ * it is returned, otherwise NULL is returned.  The caller is responsible for
+ * calling the rcu_read_[un]lock() functions.
+ *
+ */
+struct netlbl_af6list *netlbl_af6list_search_exact(const struct in6_addr *addr,
+						   const struct in6_addr *mask,
+						   struct list_head *head)
+{
+	struct netlbl_af6list *iter;
+
+	list_for_each_entry_rcu(iter, head, list)
+		if (iter->valid &&
+		    ipv6_addr_equal(&iter->addr, addr) &&
+		    ipv6_addr_equal(&iter->mask, mask))
+			return iter;
+
+	return NULL;
+}
+#endif /* IPv6 */
+
+/**
+ * netlbl_af4list_add - Add a new IPv4 address entry to a list
+ * @entry: address entry
+ * @head: the list head
+ *
+ * Description:
+ * Add a new address entry to the list pointed to by @head.  On success zero is
+ * returned, otherwise a negative value is returned.  The caller is responsible
+ * for calling the necessary locking functions.
+ *
+ */
+int netlbl_af4list_add(struct netlbl_af4list *entry, struct list_head *head)
+{
+	struct netlbl_af4list *iter;
+
+	iter = netlbl_af4list_search(entry->addr, head);
+	if (iter != NULL &&
+	    iter->addr == entry->addr && iter->mask == entry->mask)
+		return -EEXIST;
+
+	/* in order to speed up address searches through the list (the common
+	 * case) we need to keep the list in order based on the size of the
+	 * address mask such that the entry with the widest mask (smallest
+	 * numerical value) appears first in the list */
+	list_for_each_entry_rcu(iter, head, list)
+		if (iter->valid &&
+		    ntohl(entry->mask) > ntohl(iter->mask)) {
+			__list_add_rcu(&entry->list,
+				       iter->list.prev,
+				       &iter->list);
+			return 0;
+		}
+	list_add_tail_rcu(&entry->list, head);
+	return 0;
+}
+
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+/**
+ * netlbl_af6list_add - Add a new IPv6 address entry to a list
+ * @entry: address entry
+ * @head: the list head
+ *
+ * Description:
+ * Add a new address entry to the list pointed to by @head.  On success zero is
+ * returned, otherwise a negative value is returned.  The caller is responsible
+ * for calling the necessary locking functions.
+ *
+ */
+int netlbl_af6list_add(struct netlbl_af6list *entry, struct list_head *head)
+{
+	struct netlbl_af6list *iter;
+
+	iter = netlbl_af6list_search(&entry->addr, head);
+	if (iter != NULL &&
+	    ipv6_addr_equal(&iter->addr, &entry->addr) &&
+	    ipv6_addr_equal(&iter->mask, &entry->mask))
+		return -EEXIST;
+
+	/* in order to speed up address searches through the list (the common
+	 * case) we need to keep the list in order based on the size of the
+	 * address mask such that the entry with the widest mask (smallest
+	 * numerical value) appears first in the list */
+	list_for_each_entry_rcu(iter, head, list)
+		if (iter->valid &&
+		    ipv6_addr_cmp(&entry->mask, &iter->mask) > 0) {
+			__list_add_rcu(&entry->list,
+				       iter->list.prev,
+				       &iter->list);
+			return 0;
+		}
+	list_add_tail_rcu(&entry->list, head);
+	return 0;
+}
+#endif /* IPv6 */
+
+/**
+ * netlbl_af4list_remove_entry - Remove an IPv4 address entry
+ * @entry: address entry
+ *
+ * Description:
+ * Remove the specified IP address entry.  The caller is responsible for
+ * calling the necessary locking functions.
+ *
+ */
+void netlbl_af4list_remove_entry(struct netlbl_af4list *entry)
+{
+	entry->valid = 0;
+	list_del_rcu(&entry->list);
+}
+
+/**
+ * netlbl_af4list_remove - Remove an IPv4 address entry
+ * @addr: IP address
+ * @mask: IP address mask
+ * @head: the list head
+ *
+ * Description:
+ * Remove an IP address entry from the list pointed to by @head.  Returns the
+ * entry on success, NULL on failure.  The caller is responsible for calling
+ * the necessary locking functions.
+ *
+ */
+struct netlbl_af4list *netlbl_af4list_remove(__be32 addr, __be32 mask,
+					     struct list_head *head)
+{
+	struct netlbl_af4list *entry;
+
+	entry = netlbl_af4list_search(addr, head);
+	if (entry != NULL && entry->addr == addr && entry->mask == mask) {
+		netlbl_af4list_remove_entry(entry);
+		return entry;
+	}
+
+	return NULL;
+}
+
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+/**
+ * netlbl_af6list_remove_entry - Remove an IPv6 address entry
+ * @entry: address entry
+ *
+ * Description:
+ * Remove the specified IP address entry.  The caller is responsible for
+ * calling the necessary locking functions.
+ *
+ */
+void netlbl_af6list_remove_entry(struct netlbl_af6list *entry)
+{
+	entry->valid = 0;
+	list_del_rcu(&entry->list);
+}
+
+/**
+ * netlbl_af6list_remove - Remove an IPv6 address entry
+ * @addr: IP address
+ * @mask: IP address mask
+ * @head: the list head
+ *
+ * Description:
+ * Remove an IP address entry from the list pointed to by @head.  Returns the
+ * entry on success, NULL on failure.  The caller is responsible for calling
+ * the necessary locking functions.
+ *
+ */
+struct netlbl_af6list *netlbl_af6list_remove(const struct in6_addr *addr,
+					     const struct in6_addr *mask,
+					     struct list_head *head)
+{
+	struct netlbl_af6list *entry;
+
+	entry = netlbl_af6list_search(addr, head);
+	if (entry != NULL &&
+	    ipv6_addr_equal(&entry->addr, addr) &&
+	    ipv6_addr_equal(&entry->mask, mask)) {
+		netlbl_af6list_remove_entry(entry);
+		return entry;
+	}
+
+	return NULL;
+}
+#endif /* IPv6 */
+
+/*
+ * Audit Helper Functions
+ */
+
+/**
+ * netlbl_af4list_audit_addr - Audit an IPv4 address
+ * @audit_buf: audit buffer
+ * @src: true if source address, false if destination
+ * @dev: network interface
+ * @addr: IP address
+ * @mask: IP address mask
+ *
+ * Description:
+ * Write the IPv4 address and address mask, if necessary, to @audit_buf.
+ *
+ */
+void netlbl_af4list_audit_addr(struct audit_buffer *audit_buf,
+					int src, const char *dev,
+					__be32 addr, __be32 mask)
+{
+	u32 mask_val = ntohl(mask);
+	char *dir = (src ? "src" : "dst");
+
+	if (dev != NULL)
+		audit_log_format(audit_buf, " netif=%s", dev);
+	audit_log_format(audit_buf, " %s=" NIPQUAD_FMT, dir, NIPQUAD(addr));
+	if (mask_val != 0xffffffff) {
+		u32 mask_len = 0;
+		while (mask_val > 0) {
+			mask_val <<= 1;
+			mask_len++;
+		}
+		audit_log_format(audit_buf, " %s_prefixlen=%d", dir, mask_len);
+	}
+}
+
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+/**
+ * netlbl_af6list_audit_addr - Audit an IPv6 address
+ * @audit_buf: audit buffer
+ * @src: true if source address, false if destination
+ * @dev: network interface
+ * @addr: IP address
+ * @mask: IP address mask
+ *
+ * Description:
+ * Write the IPv6 address and address mask, if necessary, to @audit_buf.
+ *
+ */
+void netlbl_af6list_audit_addr(struct audit_buffer *audit_buf,
+				 int src,
+				 const char *dev,
+				 const struct in6_addr *addr,
+				 const struct in6_addr *mask)
+{
+	char *dir = (src ? "src" : "dst");
+
+	if (dev != NULL)
+		audit_log_format(audit_buf, " netif=%s", dev);
+	audit_log_format(audit_buf, " %s=" NIP6_FMT, dir, NIP6(*addr));
+	if (ntohl(mask->s6_addr32[3]) != 0xffffffff) {
+		u32 mask_len = 0;
+		u32 mask_val;
+		int iter = -1;
+		while (ntohl(mask->s6_addr32[++iter]) == 0xffffffff)
+			mask_len += 32;
+		mask_val = ntohl(mask->s6_addr32[iter]);
+		while (mask_val > 0) {
+			mask_val <<= 1;
+			mask_len++;
+		}
+		audit_log_format(audit_buf, " %s_prefixlen=%d", dir, mask_len);
+	}
+}
+#endif /* IPv6 */
diff --git a/net/netlabel/netlabel_addrlist.h b/net/netlabel/netlabel_addrlist.h
new file mode 100644
index 0000000..0242bea
--- /dev/null
+++ b/net/netlabel/netlabel_addrlist.h
@@ -0,0 +1,189 @@
+/*
+ * NetLabel Network Address Lists
+ *
+ * This file contains network address list functions used to manage ordered
+ * lists of network addresses for use by the NetLabel subsystem.  The NetLabel
+ * system manages static and dynamic label mappings for network protocols such
+ * as CIPSO and RIPSO.
+ *
+ * Author: Paul Moore <paul.moore@hp.com>
+ *
+ */
+
+/*
+ * (c) Copyright Hewlett-Packard Development Company, L.P., 2008
+ *
+ * This program is free software;  you can redistribute it and/or 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 _NETLABEL_ADDRLIST_H
+#define _NETLABEL_ADDRLIST_H
+
+#include <linux/types.h>
+#include <linux/rcupdate.h>
+#include <linux/list.h>
+#include <linux/in6.h>
+#include <linux/audit.h>
+
+/**
+ * struct netlbl_af4list - NetLabel IPv4 address list
+ * @addr: IPv4 address
+ * @mask: IPv4 address mask
+ * @valid: valid flag
+ * @list: list structure, used internally
+ */
+struct netlbl_af4list {
+	__be32 addr;
+	__be32 mask;
+
+	u32 valid;
+	struct list_head list;
+};
+
+/**
+ * struct netlbl_af6list - NetLabel IPv6 address list
+ * @addr: IPv6 address
+ * @mask: IPv6 address mask
+ * @valid: valid flag
+ * @list: list structure, used internally
+ */
+struct netlbl_af6list {
+	struct in6_addr addr;
+	struct in6_addr mask;
+
+	u32 valid;
+	struct list_head list;
+};
+
+#define __af4list_entry(ptr) container_of(ptr, struct netlbl_af4list, list)
+
+static inline struct netlbl_af4list *__af4list_valid(struct list_head *s,
+						     struct list_head *h)
+{
+	struct list_head *i = s;
+	struct netlbl_af4list *n = __af4list_entry(s);
+	while (i != h && !n->valid) {
+		i = i->next;
+		n = __af4list_entry(i);
+	}
+	return n;
+}
+
+static inline struct netlbl_af4list *__af4list_valid_rcu(struct list_head *s,
+							 struct list_head *h)
+{
+	struct list_head *i = s;
+	struct netlbl_af4list *n = __af4list_entry(s);
+	while (i != h && !n->valid) {
+		i = rcu_dereference(i->next);
+		n = __af4list_entry(i);
+	}
+	return n;
+}
+
+#define netlbl_af4list_foreach(iter, head)				\
+	for (iter = __af4list_valid((head)->next, head);		\
+	     prefetch(iter->list.next), &iter->list != (head);		\
+	     iter = __af4list_valid(iter->list.next, head))
+
+#define netlbl_af4list_foreach_rcu(iter, head)				\
+	for (iter = __af4list_valid_rcu((head)->next, head);		\
+	     prefetch(iter->list.next),	&iter->list != (head);		\
+	     iter = __af4list_valid_rcu(iter->list.next, head))
+
+#define netlbl_af4list_foreach_safe(iter, tmp, head)			\
+	for (iter = __af4list_valid((head)->next, head),		\
+		     tmp = __af4list_valid(iter->list.next, head);	\
+	     &iter->list != (head);					\
+	     iter = tmp, tmp = __af4list_valid(iter->list.next, head))
+
+int netlbl_af4list_add(struct netlbl_af4list *entry,
+		       struct list_head *head);
+struct netlbl_af4list *netlbl_af4list_remove(__be32 addr, __be32 mask,
+					     struct list_head *head);
+void netlbl_af4list_remove_entry(struct netlbl_af4list *entry);
+struct netlbl_af4list *netlbl_af4list_search(__be32 addr,
+					     struct list_head *head);
+struct netlbl_af4list *netlbl_af4list_search_exact(__be32 addr,
+						   __be32 mask,
+						   struct list_head *head);
+void netlbl_af4list_audit_addr(struct audit_buffer *audit_buf,
+			       int src, const char *dev,
+			       __be32 addr, __be32 mask);
+
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+
+#define __af6list_entry(ptr) container_of(ptr, struct netlbl_af6list, list)
+
+static inline struct netlbl_af6list *__af6list_valid(struct list_head *s,
+						     struct list_head *h)
+{
+	struct list_head *i = s;
+	struct netlbl_af6list *n = __af6list_entry(s);
+	while (i != h && !n->valid) {
+		i = i->next;
+		n = __af6list_entry(i);
+	}
+	return n;
+}
+
+static inline struct netlbl_af6list *__af6list_valid_rcu(struct list_head *s,
+							 struct list_head *h)
+{
+	struct list_head *i = s;
+	struct netlbl_af6list *n = __af6list_entry(s);
+	while (i != h && !n->valid) {
+		i = rcu_dereference(i->next);
+		n = __af6list_entry(i);
+	}
+	return n;
+}
+
+#define netlbl_af6list_foreach(iter, head)				\
+	for (iter = __af6list_valid((head)->next, head);		\
+	     prefetch(iter->list.next),	&iter->list != (head);		\
+	     iter = __af6list_valid(iter->list.next, head))
+
+#define netlbl_af6list_foreach_rcu(iter, head)				\
+	for (iter = __af6list_valid_rcu((head)->next, head);		\
+	     prefetch(iter->list.next),	&iter->list != (head);		\
+	     iter = __af6list_valid_rcu(iter->list.next, head))
+
+#define netlbl_af6list_foreach_safe(iter, tmp, head)			\
+	for (iter = __af6list_valid((head)->next, head),		\
+		     tmp = __af6list_valid(iter->list.next, head);	\
+	     &iter->list != (head);					\
+	     iter = tmp, tmp = __af6list_valid(iter->list.next, head))
+
+int netlbl_af6list_add(struct netlbl_af6list *entry,
+		       struct list_head *head);
+struct netlbl_af6list *netlbl_af6list_remove(const struct in6_addr *addr,
+					     const struct in6_addr *mask,
+					     struct list_head *head);
+void netlbl_af6list_remove_entry(struct netlbl_af6list *entry);
+struct netlbl_af6list *netlbl_af6list_search(const struct in6_addr *addr,
+					     struct list_head *head);
+struct netlbl_af6list *netlbl_af6list_search_exact(const struct in6_addr *addr,
+						   const struct in6_addr *mask,
+						   struct list_head *head);
+void netlbl_af6list_audit_addr(struct audit_buffer *audit_buf,
+			       int src,
+			       const char *dev,
+			       const struct in6_addr *addr,
+			       const struct in6_addr *mask);
+#endif /* IPV6 */
+
+#endif
diff --git a/net/netlabel/netlabel_cipso_v4.c b/net/netlabel/netlabel_cipso_v4.c
index 0aec318..fff32b7 100644
--- a/net/netlabel/netlabel_cipso_v4.c
+++ b/net/netlabel/netlabel_cipso_v4.c
@@ -43,6 +43,7 @@
 #include "netlabel_user.h"
 #include "netlabel_cipso_v4.h"
 #include "netlabel_mgmt.h"
+#include "netlabel_domainhash.h"
 
 /* Argument struct for cipso_v4_doi_walk() */
 struct netlbl_cipsov4_doiwalk_arg {
@@ -51,6 +52,12 @@
 	u32 seq;
 };
 
+/* Argument struct for netlbl_domhsh_walk() */
+struct netlbl_domhsh_walk_arg {
+	struct netlbl_audit *audit_info;
+	u32 doi;
+};
+
 /* NetLabel Generic NETLINK CIPSOv4 family */
 static struct genl_family netlbl_cipsov4_gnl_family = {
 	.id = GENL_ID_GENERATE,
@@ -81,32 +88,6 @@
  */
 
 /**
- * netlbl_cipsov4_doi_free - Frees a CIPSO V4 DOI definition
- * @entry: the entry's RCU field
- *
- * Description:
- * This function is designed to be used as a callback to the call_rcu()
- * function so that the memory allocated to the DOI definition can be released
- * safely.
- *
- */
-void netlbl_cipsov4_doi_free(struct rcu_head *entry)
-{
-	struct cipso_v4_doi *ptr;
-
-	ptr = container_of(entry, struct cipso_v4_doi, rcu);
-	switch (ptr->type) {
-	case CIPSO_V4_MAP_STD:
-		kfree(ptr->map.std->lvl.cipso);
-		kfree(ptr->map.std->lvl.local);
-		kfree(ptr->map.std->cat.cipso);
-		kfree(ptr->map.std->cat.local);
-		break;
-	}
-	kfree(ptr);
-}
-
-/**
  * netlbl_cipsov4_add_common - Parse the common sections of a ADD message
  * @info: the Generic NETLINK info block
  * @doi_def: the CIPSO V4 DOI definition
@@ -151,9 +132,9 @@
  * @info: the Generic NETLINK info block
  *
  * Description:
- * Create a new CIPSO_V4_MAP_STD DOI definition based on the given ADD message
- * and add it to the CIPSO V4 engine.  Return zero on success and non-zero on
- * error.
+ * Create a new CIPSO_V4_MAP_TRANS DOI definition based on the given ADD
+ * message and add it to the CIPSO V4 engine.  Return zero on success and
+ * non-zero on error.
  *
  */
 static int netlbl_cipsov4_add_std(struct genl_info *info)
@@ -183,7 +164,7 @@
 		ret_val = -ENOMEM;
 		goto add_std_failure;
 	}
-	doi_def->type = CIPSO_V4_MAP_STD;
+	doi_def->type = CIPSO_V4_MAP_TRANS;
 
 	ret_val = netlbl_cipsov4_add_common(info, doi_def);
 	if (ret_val != 0)
@@ -342,7 +323,7 @@
 
 add_std_failure:
 	if (doi_def)
-		netlbl_cipsov4_doi_free(&doi_def->rcu);
+		cipso_v4_doi_free(doi_def);
 	return ret_val;
 }
 
@@ -379,7 +360,44 @@
 	return 0;
 
 add_pass_failure:
-	netlbl_cipsov4_doi_free(&doi_def->rcu);
+	cipso_v4_doi_free(doi_def);
+	return ret_val;
+}
+
+/**
+ * netlbl_cipsov4_add_local - Adds a CIPSO V4 DOI definition
+ * @info: the Generic NETLINK info block
+ *
+ * Description:
+ * Create a new CIPSO_V4_MAP_LOCAL DOI definition based on the given ADD
+ * message and add it to the CIPSO V4 engine.  Return zero on success and
+ * non-zero on error.
+ *
+ */
+static int netlbl_cipsov4_add_local(struct genl_info *info)
+{
+	int ret_val;
+	struct cipso_v4_doi *doi_def = NULL;
+
+	if (!info->attrs[NLBL_CIPSOV4_A_TAGLST])
+		return -EINVAL;
+
+	doi_def = kmalloc(sizeof(*doi_def), GFP_KERNEL);
+	if (doi_def == NULL)
+		return -ENOMEM;
+	doi_def->type = CIPSO_V4_MAP_LOCAL;
+
+	ret_val = netlbl_cipsov4_add_common(info, doi_def);
+	if (ret_val != 0)
+		goto add_local_failure;
+
+	ret_val = cipso_v4_doi_add(doi_def);
+	if (ret_val != 0)
+		goto add_local_failure;
+	return 0;
+
+add_local_failure:
+	cipso_v4_doi_free(doi_def);
 	return ret_val;
 }
 
@@ -412,14 +430,18 @@
 
 	type = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_MTYPE]);
 	switch (type) {
-	case CIPSO_V4_MAP_STD:
-		type_str = "std";
+	case CIPSO_V4_MAP_TRANS:
+		type_str = "trans";
 		ret_val = netlbl_cipsov4_add_std(info);
 		break;
 	case CIPSO_V4_MAP_PASS:
 		type_str = "pass";
 		ret_val = netlbl_cipsov4_add_pass(info);
 		break;
+	case CIPSO_V4_MAP_LOCAL:
+		type_str = "local";
+		ret_val = netlbl_cipsov4_add_local(info);
+		break;
 	}
 	if (ret_val == 0)
 		atomic_inc(&netlabel_mgmt_protocount);
@@ -491,7 +513,7 @@
 	doi_def = cipso_v4_doi_getdef(doi);
 	if (doi_def == NULL) {
 		ret_val = -EINVAL;
-		goto list_failure;
+		goto list_failure_lock;
 	}
 
 	ret_val = nla_put_u32(ans_skb, NLBL_CIPSOV4_A_MTYPE, doi_def->type);
@@ -516,7 +538,7 @@
 	nla_nest_end(ans_skb, nla_a);
 
 	switch (doi_def->type) {
-	case CIPSO_V4_MAP_STD:
+	case CIPSO_V4_MAP_TRANS:
 		nla_a = nla_nest_start(ans_skb, NLBL_CIPSOV4_A_MLSLVLLST);
 		if (nla_a == NULL) {
 			ret_val = -ENOMEM;
@@ -655,7 +677,7 @@
 				  struct netlink_callback *cb)
 {
 	struct netlbl_cipsov4_doiwalk_arg cb_arg;
-	int doi_skip = cb->args[0];
+	u32 doi_skip = cb->args[0];
 
 	cb_arg.nl_cb = cb;
 	cb_arg.skb = skb;
@@ -668,6 +690,29 @@
 }
 
 /**
+ * netlbl_cipsov4_remove_cb - netlbl_cipsov4_remove() callback for REMOVE
+ * @entry: LSM domain mapping entry
+ * @arg: the netlbl_domhsh_walk_arg structure
+ *
+ * Description:
+ * This function is intended for use by netlbl_cipsov4_remove() as the callback
+ * for the netlbl_domhsh_walk() function; it removes LSM domain map entries
+ * which are associated with the CIPSO DOI specified in @arg.  Returns zero on
+ * success, negative values on failure.
+ *
+ */
+static int netlbl_cipsov4_remove_cb(struct netlbl_dom_map *entry, void *arg)
+{
+	struct netlbl_domhsh_walk_arg *cb_arg = arg;
+
+	if (entry->type == NETLBL_NLTYPE_CIPSOV4 &&
+	    entry->type_def.cipsov4->doi == cb_arg->doi)
+		return netlbl_domhsh_remove_entry(entry, cb_arg->audit_info);
+
+	return 0;
+}
+
+/**
  * netlbl_cipsov4_remove - Handle a REMOVE message
  * @skb: the NETLINK buffer
  * @info: the Generic NETLINK info block
@@ -681,8 +726,11 @@
 {
 	int ret_val = -EINVAL;
 	u32 doi = 0;
+	struct netlbl_domhsh_walk_arg cb_arg;
 	struct audit_buffer *audit_buf;
 	struct netlbl_audit audit_info;
+	u32 skip_bkt = 0;
+	u32 skip_chain = 0;
 
 	if (!info->attrs[NLBL_CIPSOV4_A_DOI])
 		return -EINVAL;
@@ -690,11 +738,15 @@
 	doi = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_DOI]);
 	netlbl_netlink_auditinfo(skb, &audit_info);
 
-	ret_val = cipso_v4_doi_remove(doi,
-				      &audit_info,
-				      netlbl_cipsov4_doi_free);
-	if (ret_val == 0)
-		atomic_dec(&netlabel_mgmt_protocount);
+	cb_arg.doi = doi;
+	cb_arg.audit_info = &audit_info;
+	ret_val = netlbl_domhsh_walk(&skip_bkt, &skip_chain,
+				     netlbl_cipsov4_remove_cb, &cb_arg);
+	if (ret_val == 0 || ret_val == -ENOENT) {
+		ret_val = cipso_v4_doi_remove(doi, &audit_info);
+		if (ret_val == 0)
+			atomic_dec(&netlabel_mgmt_protocount);
+	}
 
 	audit_buf = netlbl_audit_start_common(AUDIT_MAC_CIPSOV4_DEL,
 					      &audit_info);
diff --git a/net/netlabel/netlabel_cipso_v4.h b/net/netlabel/netlabel_cipso_v4.h
index 220cb9d..c8a4079 100644
--- a/net/netlabel/netlabel_cipso_v4.h
+++ b/net/netlabel/netlabel_cipso_v4.h
@@ -45,12 +45,13 @@
  *     NLBL_CIPSOV4_A_MTYPE
  *     NLBL_CIPSOV4_A_TAGLST
  *
- *   If using CIPSO_V4_MAP_STD the following attributes are required:
+ *   If using CIPSO_V4_MAP_TRANS the following attributes are required:
  *
  *     NLBL_CIPSOV4_A_MLSLVLLST
  *     NLBL_CIPSOV4_A_MLSCATLST
  *
- *   If using CIPSO_V4_MAP_PASS no additional attributes are required.
+ *   If using CIPSO_V4_MAP_PASS or CIPSO_V4_MAP_LOCAL no additional attributes
+ *   are required.
  *
  * o REMOVE:
  *   Sent by an application to remove a specific DOI mapping table from the
@@ -76,12 +77,13 @@
  *     NLBL_CIPSOV4_A_MTYPE
  *     NLBL_CIPSOV4_A_TAGLST
  *
- *   If using CIPSO_V4_MAP_STD the following attributes are required:
+ *   If using CIPSO_V4_MAP_TRANS the following attributes are required:
  *
  *     NLBL_CIPSOV4_A_MLSLVLLST
  *     NLBL_CIPSOV4_A_MLSCATLST
  *
- *   If using CIPSO_V4_MAP_PASS no additional attributes are required.
+ *   If using CIPSO_V4_MAP_PASS or CIPSO_V4_MAP_LOCAL no additional attributes
+ *   are required.
  *
  * o LISTALL:
  *   This message is sent by an application to list the valid DOIs on the
diff --git a/net/netlabel/netlabel_domainhash.c b/net/netlabel/netlabel_domainhash.c
index 643c032..5fadf10 100644
--- a/net/netlabel/netlabel_domainhash.c
+++ b/net/netlabel/netlabel_domainhash.c
@@ -11,7 +11,7 @@
  */
 
 /*
- * (c) Copyright Hewlett-Packard Development Company, L.P., 2006
+ * (c) Copyright Hewlett-Packard Development Company, L.P., 2006, 2008
  *
  * This program is free software;  you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -40,6 +40,7 @@
 #include <asm/bug.h>
 
 #include "netlabel_mgmt.h"
+#include "netlabel_addrlist.h"
 #include "netlabel_domainhash.h"
 #include "netlabel_user.h"
 
@@ -72,8 +73,28 @@
 static void netlbl_domhsh_free_entry(struct rcu_head *entry)
 {
 	struct netlbl_dom_map *ptr;
+	struct netlbl_af4list *iter4;
+	struct netlbl_af4list *tmp4;
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+	struct netlbl_af6list *iter6;
+	struct netlbl_af6list *tmp6;
+#endif /* IPv6 */
 
 	ptr = container_of(entry, struct netlbl_dom_map, rcu);
+	if (ptr->type == NETLBL_NLTYPE_ADDRSELECT) {
+		netlbl_af4list_foreach_safe(iter4, tmp4,
+					    &ptr->type_def.addrsel->list4) {
+			netlbl_af4list_remove_entry(iter4);
+			kfree(netlbl_domhsh_addr4_entry(iter4));
+		}
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+		netlbl_af6list_foreach_safe(iter6, tmp6,
+					    &ptr->type_def.addrsel->list6) {
+			netlbl_af6list_remove_entry(iter6);
+			kfree(netlbl_domhsh_addr6_entry(iter6));
+		}
+#endif /* IPv6 */
+	}
 	kfree(ptr->domain);
 	kfree(ptr);
 }
@@ -115,13 +136,13 @@
 static struct netlbl_dom_map *netlbl_domhsh_search(const char *domain)
 {
 	u32 bkt;
+	struct list_head *bkt_list;
 	struct netlbl_dom_map *iter;
 
 	if (domain != NULL) {
 		bkt = netlbl_domhsh_hash(domain);
-		list_for_each_entry_rcu(iter,
-				     &rcu_dereference(netlbl_domhsh)->tbl[bkt],
-				     list)
+		bkt_list = &rcu_dereference(netlbl_domhsh)->tbl[bkt];
+		list_for_each_entry_rcu(iter, bkt_list, list)
 			if (iter->valid && strcmp(iter->domain, domain) == 0)
 				return iter;
 	}
@@ -156,6 +177,69 @@
 	return entry;
 }
 
+/**
+ * netlbl_domhsh_audit_add - Generate an audit entry for an add event
+ * @entry: the entry being added
+ * @addr4: the IPv4 address information
+ * @addr6: the IPv6 address information
+ * @result: the result code
+ * @audit_info: NetLabel audit information
+ *
+ * Description:
+ * Generate an audit record for adding a new NetLabel/LSM mapping entry with
+ * the given information.  Caller is responsibile for holding the necessary
+ * locks.
+ *
+ */
+static void netlbl_domhsh_audit_add(struct netlbl_dom_map *entry,
+				    struct netlbl_af4list *addr4,
+				    struct netlbl_af6list *addr6,
+				    int result,
+				    struct netlbl_audit *audit_info)
+{
+	struct audit_buffer *audit_buf;
+	struct cipso_v4_doi *cipsov4 = NULL;
+	u32 type;
+
+	audit_buf = netlbl_audit_start_common(AUDIT_MAC_MAP_ADD, audit_info);
+	if (audit_buf != NULL) {
+		audit_log_format(audit_buf, " nlbl_domain=%s",
+				 entry->domain ? entry->domain : "(default)");
+		if (addr4 != NULL) {
+			struct netlbl_domaddr4_map *map4;
+			map4 = netlbl_domhsh_addr4_entry(addr4);
+			type = map4->type;
+			cipsov4 = map4->type_def.cipsov4;
+			netlbl_af4list_audit_addr(audit_buf, 0, NULL,
+						  addr4->addr, addr4->mask);
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+		} else if (addr6 != NULL) {
+			struct netlbl_domaddr6_map *map6;
+			map6 = netlbl_domhsh_addr6_entry(addr6);
+			type = map6->type;
+			netlbl_af6list_audit_addr(audit_buf, 0, NULL,
+						  &addr6->addr, &addr6->mask);
+#endif /* IPv6 */
+		} else {
+			type = entry->type;
+			cipsov4 = entry->type_def.cipsov4;
+		}
+		switch (type) {
+		case NETLBL_NLTYPE_UNLABELED:
+			audit_log_format(audit_buf, " nlbl_protocol=unlbl");
+			break;
+		case NETLBL_NLTYPE_CIPSOV4:
+			BUG_ON(cipsov4 == NULL);
+			audit_log_format(audit_buf,
+					 " nlbl_protocol=cipsov4 cipso_doi=%u",
+					 cipsov4->doi);
+			break;
+		}
+		audit_log_format(audit_buf, " res=%u", result == 0 ? 1 : 0);
+		audit_log_end(audit_buf);
+	}
+}
+
 /*
  * Domain Hash Table Functions
  */
@@ -213,74 +297,106 @@
 int netlbl_domhsh_add(struct netlbl_dom_map *entry,
 		      struct netlbl_audit *audit_info)
 {
-	int ret_val;
-	u32 bkt;
-	struct audit_buffer *audit_buf;
-
-	switch (entry->type) {
-	case NETLBL_NLTYPE_UNLABELED:
-		ret_val = 0;
-		break;
-	case NETLBL_NLTYPE_CIPSOV4:
-		ret_val = cipso_v4_doi_domhsh_add(entry->type_def.cipsov4,
-						  entry->domain);
-		break;
-	default:
-		return -EINVAL;
-	}
-	if (ret_val != 0)
-		return ret_val;
-
-	entry->valid = 1;
-	INIT_RCU_HEAD(&entry->rcu);
+	int ret_val = 0;
+	struct netlbl_dom_map *entry_old;
+	struct netlbl_af4list *iter4;
+	struct netlbl_af4list *tmp4;
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+	struct netlbl_af6list *iter6;
+	struct netlbl_af6list *tmp6;
+#endif /* IPv6 */
 
 	rcu_read_lock();
+
 	spin_lock(&netlbl_domhsh_lock);
-	if (entry->domain != NULL) {
-		bkt = netlbl_domhsh_hash(entry->domain);
-		if (netlbl_domhsh_search(entry->domain) == NULL)
+	if (entry->domain != NULL)
+		entry_old = netlbl_domhsh_search(entry->domain);
+	else
+		entry_old = netlbl_domhsh_search_def(entry->domain);
+	if (entry_old == NULL) {
+		entry->valid = 1;
+		INIT_RCU_HEAD(&entry->rcu);
+
+		if (entry->domain != NULL) {
+			u32 bkt = netlbl_domhsh_hash(entry->domain);
 			list_add_tail_rcu(&entry->list,
 				    &rcu_dereference(netlbl_domhsh)->tbl[bkt]);
-		else
-			ret_val = -EEXIST;
-	} else {
-		INIT_LIST_HEAD(&entry->list);
-		if (rcu_dereference(netlbl_domhsh_def) == NULL)
+		} else {
+			INIT_LIST_HEAD(&entry->list);
 			rcu_assign_pointer(netlbl_domhsh_def, entry);
-		else
-			ret_val = -EEXIST;
-	}
+		}
+
+		if (entry->type == NETLBL_NLTYPE_ADDRSELECT) {
+			netlbl_af4list_foreach_rcu(iter4,
+					       &entry->type_def.addrsel->list4)
+				netlbl_domhsh_audit_add(entry, iter4, NULL,
+							ret_val, audit_info);
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+			netlbl_af6list_foreach_rcu(iter6,
+					       &entry->type_def.addrsel->list6)
+				netlbl_domhsh_audit_add(entry, NULL, iter6,
+							ret_val, audit_info);
+#endif /* IPv6 */
+		} else
+			netlbl_domhsh_audit_add(entry, NULL, NULL,
+						ret_val, audit_info);
+	} else if (entry_old->type == NETLBL_NLTYPE_ADDRSELECT &&
+		   entry->type == NETLBL_NLTYPE_ADDRSELECT) {
+		struct list_head *old_list4;
+		struct list_head *old_list6;
+
+		old_list4 = &entry_old->type_def.addrsel->list4;
+		old_list6 = &entry_old->type_def.addrsel->list6;
+
+		/* we only allow the addition of address selectors if all of
+		 * the selectors do not exist in the existing domain map */
+		netlbl_af4list_foreach_rcu(iter4,
+					   &entry->type_def.addrsel->list4)
+			if (netlbl_af4list_search_exact(iter4->addr,
+							iter4->mask,
+							old_list4)) {
+				ret_val = -EEXIST;
+				goto add_return;
+			}
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+		netlbl_af6list_foreach_rcu(iter6,
+					   &entry->type_def.addrsel->list6)
+			if (netlbl_af6list_search_exact(&iter6->addr,
+							&iter6->mask,
+							old_list6)) {
+				ret_val = -EEXIST;
+				goto add_return;
+			}
+#endif /* IPv6 */
+
+		netlbl_af4list_foreach_safe(iter4, tmp4,
+					    &entry->type_def.addrsel->list4) {
+			netlbl_af4list_remove_entry(iter4);
+			iter4->valid = 1;
+			ret_val = netlbl_af4list_add(iter4, old_list4);
+			netlbl_domhsh_audit_add(entry_old, iter4, NULL,
+						ret_val, audit_info);
+			if (ret_val != 0)
+				goto add_return;
+		}
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+		netlbl_af6list_foreach_safe(iter6, tmp6,
+					    &entry->type_def.addrsel->list6) {
+			netlbl_af6list_remove_entry(iter6);
+			iter6->valid = 1;
+			ret_val = netlbl_af6list_add(iter6, old_list6);
+			netlbl_domhsh_audit_add(entry_old, NULL, iter6,
+						ret_val, audit_info);
+			if (ret_val != 0)
+				goto add_return;
+		}
+#endif /* IPv6 */
+	} else
+		ret_val = -EINVAL;
+
+add_return:
 	spin_unlock(&netlbl_domhsh_lock);
-	audit_buf = netlbl_audit_start_common(AUDIT_MAC_MAP_ADD, audit_info);
-	if (audit_buf != NULL) {
-		audit_log_format(audit_buf,
-				 " nlbl_domain=%s",
-				 entry->domain ? entry->domain : "(default)");
-		switch (entry->type) {
-		case NETLBL_NLTYPE_UNLABELED:
-			audit_log_format(audit_buf, " nlbl_protocol=unlbl");
-			break;
-		case NETLBL_NLTYPE_CIPSOV4:
-			audit_log_format(audit_buf,
-					 " nlbl_protocol=cipsov4 cipso_doi=%u",
-					 entry->type_def.cipsov4->doi);
-			break;
-		}
-		audit_log_format(audit_buf, " res=%u", ret_val == 0 ? 1 : 0);
-		audit_log_end(audit_buf);
-	}
 	rcu_read_unlock();
-
-	if (ret_val != 0) {
-		switch (entry->type) {
-		case NETLBL_NLTYPE_CIPSOV4:
-			if (cipso_v4_doi_domhsh_remove(entry->type_def.cipsov4,
-						       entry->domain) != 0)
-				BUG();
-			break;
-		}
-	}
-
 	return ret_val;
 }
 
@@ -302,6 +418,71 @@
 }
 
 /**
+ * netlbl_domhsh_remove_entry - Removes a given entry from the domain table
+ * @entry: the entry to remove
+ * @audit_info: NetLabel audit information
+ *
+ * Description:
+ * Removes an entry from the domain hash table and handles any updates to the
+ * lower level protocol handler (i.e. CIPSO).  Caller is responsible for
+ * ensuring that the RCU read lock is held.  Returns zero on success, negative
+ * on failure.
+ *
+ */
+int netlbl_domhsh_remove_entry(struct netlbl_dom_map *entry,
+			       struct netlbl_audit *audit_info)
+{
+	int ret_val = 0;
+	struct audit_buffer *audit_buf;
+
+	if (entry == NULL)
+		return -ENOENT;
+
+	spin_lock(&netlbl_domhsh_lock);
+	if (entry->valid) {
+		entry->valid = 0;
+		if (entry != rcu_dereference(netlbl_domhsh_def))
+			list_del_rcu(&entry->list);
+		else
+			rcu_assign_pointer(netlbl_domhsh_def, NULL);
+	} else
+		ret_val = -ENOENT;
+	spin_unlock(&netlbl_domhsh_lock);
+
+	audit_buf = netlbl_audit_start_common(AUDIT_MAC_MAP_DEL, audit_info);
+	if (audit_buf != NULL) {
+		audit_log_format(audit_buf,
+				 " nlbl_domain=%s res=%u",
+				 entry->domain ? entry->domain : "(default)",
+				 ret_val == 0 ? 1 : 0);
+		audit_log_end(audit_buf);
+	}
+
+	if (ret_val == 0) {
+		struct netlbl_af4list *iter4;
+		struct netlbl_domaddr4_map *map4;
+
+		switch (entry->type) {
+		case NETLBL_NLTYPE_ADDRSELECT:
+			netlbl_af4list_foreach_rcu(iter4,
+					     &entry->type_def.addrsel->list4) {
+				map4 = netlbl_domhsh_addr4_entry(iter4);
+				cipso_v4_doi_putdef(map4->type_def.cipsov4);
+			}
+			/* no need to check the IPv6 list since we currently
+			 * support only unlabeled protocols for IPv6 */
+			break;
+		case NETLBL_NLTYPE_CIPSOV4:
+			cipso_v4_doi_putdef(entry->type_def.cipsov4);
+			break;
+		}
+		call_rcu(&entry->rcu, netlbl_domhsh_free_entry);
+	}
+
+	return ret_val;
+}
+
+/**
  * netlbl_domhsh_remove - Removes an entry from the domain hash table
  * @domain: the domain to remove
  * @audit_info: NetLabel audit information
@@ -314,47 +495,17 @@
  */
 int netlbl_domhsh_remove(const char *domain, struct netlbl_audit *audit_info)
 {
-	int ret_val = -ENOENT;
+	int ret_val;
 	struct netlbl_dom_map *entry;
-	struct audit_buffer *audit_buf;
 
 	rcu_read_lock();
 	if (domain)
 		entry = netlbl_domhsh_search(domain);
 	else
 		entry = netlbl_domhsh_search_def(domain);
-	if (entry == NULL)
-		goto remove_return;
-	switch (entry->type) {
-	case NETLBL_NLTYPE_CIPSOV4:
-		cipso_v4_doi_domhsh_remove(entry->type_def.cipsov4,
-					   entry->domain);
-		break;
-	}
-	spin_lock(&netlbl_domhsh_lock);
-	if (entry->valid) {
-		entry->valid = 0;
-		if (entry != rcu_dereference(netlbl_domhsh_def))
-			list_del_rcu(&entry->list);
-		else
-			rcu_assign_pointer(netlbl_domhsh_def, NULL);
-		ret_val = 0;
-	}
-	spin_unlock(&netlbl_domhsh_lock);
-
-	audit_buf = netlbl_audit_start_common(AUDIT_MAC_MAP_DEL, audit_info);
-	if (audit_buf != NULL) {
-		audit_log_format(audit_buf,
-				 " nlbl_domain=%s res=%u",
-				 entry->domain ? entry->domain : "(default)",
-				 ret_val == 0 ? 1 : 0);
-		audit_log_end(audit_buf);
-	}
-
-remove_return:
+	ret_val = netlbl_domhsh_remove_entry(entry, audit_info);
 	rcu_read_unlock();
-	if (ret_val == 0)
-		call_rcu(&entry->rcu, netlbl_domhsh_free_entry);
+
 	return ret_val;
 }
 
@@ -389,6 +540,70 @@
 }
 
 /**
+ * netlbl_domhsh_getentry_af4 - Get an entry from the domain hash table
+ * @domain: the domain name to search for
+ * @addr: the IP address to search for
+ *
+ * Description:
+ * Look through the domain hash table searching for an entry to match @domain
+ * and @addr, return a pointer to a copy of the entry or NULL.  The caller is
+ * responsible for ensuring that rcu_read_[un]lock() is called.
+ *
+ */
+struct netlbl_domaddr4_map *netlbl_domhsh_getentry_af4(const char *domain,
+						       __be32 addr)
+{
+	struct netlbl_dom_map *dom_iter;
+	struct netlbl_af4list *addr_iter;
+
+	dom_iter = netlbl_domhsh_search_def(domain);
+	if (dom_iter == NULL)
+		return NULL;
+	if (dom_iter->type != NETLBL_NLTYPE_ADDRSELECT)
+		return NULL;
+
+	addr_iter = netlbl_af4list_search(addr,
+					  &dom_iter->type_def.addrsel->list4);
+	if (addr_iter == NULL)
+		return NULL;
+
+	return netlbl_domhsh_addr4_entry(addr_iter);
+}
+
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+/**
+ * netlbl_domhsh_getentry_af6 - Get an entry from the domain hash table
+ * @domain: the domain name to search for
+ * @addr: the IP address to search for
+ *
+ * Description:
+ * Look through the domain hash table searching for an entry to match @domain
+ * and @addr, return a pointer to a copy of the entry or NULL.  The caller is
+ * responsible for ensuring that rcu_read_[un]lock() is called.
+ *
+ */
+struct netlbl_domaddr6_map *netlbl_domhsh_getentry_af6(const char *domain,
+						   const struct in6_addr *addr)
+{
+	struct netlbl_dom_map *dom_iter;
+	struct netlbl_af6list *addr_iter;
+
+	dom_iter = netlbl_domhsh_search_def(domain);
+	if (dom_iter == NULL)
+		return NULL;
+	if (dom_iter->type != NETLBL_NLTYPE_ADDRSELECT)
+		return NULL;
+
+	addr_iter = netlbl_af6list_search(addr,
+					  &dom_iter->type_def.addrsel->list6);
+	if (addr_iter == NULL)
+		return NULL;
+
+	return netlbl_domhsh_addr6_entry(addr_iter);
+}
+#endif /* IPv6 */
+
+/**
  * netlbl_domhsh_walk - Iterate through the domain mapping hash table
  * @skip_bkt: the number of buckets to skip at the start
  * @skip_chain: the number of entries to skip in the first iterated bucket
@@ -410,6 +625,7 @@
 {
 	int ret_val = -ENOENT;
 	u32 iter_bkt;
+	struct list_head *iter_list;
 	struct netlbl_dom_map *iter_entry;
 	u32 chain_cnt = 0;
 
@@ -417,9 +633,8 @@
 	for (iter_bkt = *skip_bkt;
 	     iter_bkt < rcu_dereference(netlbl_domhsh)->size;
 	     iter_bkt++, chain_cnt = 0) {
-		list_for_each_entry_rcu(iter_entry,
-				&rcu_dereference(netlbl_domhsh)->tbl[iter_bkt],
-				list)
+		iter_list = &rcu_dereference(netlbl_domhsh)->tbl[iter_bkt];
+		list_for_each_entry_rcu(iter_entry, iter_list, list)
 			if (iter_entry->valid) {
 				if (chain_cnt++ < *skip_chain)
 					continue;
diff --git a/net/netlabel/netlabel_domainhash.h b/net/netlabel/netlabel_domainhash.h
index 8220990..bfcb676 100644
--- a/net/netlabel/netlabel_domainhash.h
+++ b/net/netlabel/netlabel_domainhash.h
@@ -11,7 +11,7 @@
  */
 
 /*
- * (c) Copyright Hewlett-Packard Development Company, L.P., 2006
+ * (c) Copyright Hewlett-Packard Development Company, L.P., 2006, 2008
  *
  * This program is free software;  you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -36,16 +36,43 @@
 #include <linux/rcupdate.h>
 #include <linux/list.h>
 
+#include "netlabel_addrlist.h"
+
 /* Domain hash table size */
 /* XXX - currently this number is an uneducated guess */
 #define NETLBL_DOMHSH_BITSIZE       7
 
-/* Domain mapping definition struct */
+/* Domain mapping definition structures */
+#define netlbl_domhsh_addr4_entry(iter) \
+	container_of(iter, struct netlbl_domaddr4_map, list)
+struct netlbl_domaddr4_map {
+	u32 type;
+	union {
+		struct cipso_v4_doi *cipsov4;
+	} type_def;
+
+	struct netlbl_af4list list;
+};
+#define netlbl_domhsh_addr6_entry(iter) \
+	container_of(iter, struct netlbl_domaddr6_map, list)
+struct netlbl_domaddr6_map {
+	u32 type;
+
+	/* NOTE: no 'type_def' union needed at present since we don't currently
+	 *       support any IPv6 labeling protocols */
+
+	struct netlbl_af6list list;
+};
+struct netlbl_domaddr_map {
+	struct list_head list4;
+	struct list_head list6;
+};
 struct netlbl_dom_map {
 	char *domain;
 	u32 type;
 	union {
 		struct cipso_v4_doi *cipsov4;
+		struct netlbl_domaddr_map *addrsel;
 	} type_def;
 
 	u32 valid;
@@ -61,12 +88,21 @@
 		      struct netlbl_audit *audit_info);
 int netlbl_domhsh_add_default(struct netlbl_dom_map *entry,
 			      struct netlbl_audit *audit_info);
+int netlbl_domhsh_remove_entry(struct netlbl_dom_map *entry,
+			       struct netlbl_audit *audit_info);
 int netlbl_domhsh_remove(const char *domain, struct netlbl_audit *audit_info);
 int netlbl_domhsh_remove_default(struct netlbl_audit *audit_info);
 struct netlbl_dom_map *netlbl_domhsh_getentry(const char *domain);
+struct netlbl_domaddr4_map *netlbl_domhsh_getentry_af4(const char *domain,
+						       __be32 addr);
 int netlbl_domhsh_walk(u32 *skip_bkt,
 		     u32 *skip_chain,
 		     int (*callback) (struct netlbl_dom_map *entry, void *arg),
 		     void *cb_arg);
 
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+struct netlbl_domaddr6_map *netlbl_domhsh_getentry_af6(const char *domain,
+						  const struct in6_addr *addr);
+#endif /* IPv6 */
+
 #endif
diff --git a/net/netlabel/netlabel_kapi.c b/net/netlabel/netlabel_kapi.c
index 39793a1..b32eceb 100644
--- a/net/netlabel/netlabel_kapi.c
+++ b/net/netlabel/netlabel_kapi.c
@@ -10,7 +10,7 @@
  */
 
 /*
- * (c) Copyright Hewlett-Packard Development Company, L.P., 2006
+ * (c) Copyright Hewlett-Packard Development Company, L.P., 2006, 2008
  *
  * This program is free software;  you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -82,7 +82,7 @@
 
 	entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
 	if (entry == NULL)
-		goto cfg_unlbl_add_map_failure;
+		return -ENOMEM;
 	if (domain != NULL) {
 		entry->domain = kstrdup(domain, GFP_ATOMIC);
 		if (entry->domain == NULL)
@@ -104,49 +104,6 @@
 }
 
 /**
- * netlbl_cfg_cipsov4_add - Add a new CIPSOv4 DOI definition
- * @doi_def: the DOI definition
- * @audit_info: NetLabel audit information
- *
- * Description:
- * Add a new CIPSOv4 DOI definition to the NetLabel subsystem.  Returns zero on
- * success, negative values on failure.
- *
- */
-int netlbl_cfg_cipsov4_add(struct cipso_v4_doi *doi_def,
-			   struct netlbl_audit *audit_info)
-{
-	int ret_val;
-	const char *type_str;
-	struct audit_buffer *audit_buf;
-
-	ret_val = cipso_v4_doi_add(doi_def);
-
-	audit_buf = netlbl_audit_start_common(AUDIT_MAC_CIPSOV4_ADD,
-					      audit_info);
-	if (audit_buf != NULL) {
-		switch (doi_def->type) {
-		case CIPSO_V4_MAP_STD:
-			type_str = "std";
-			break;
-		case CIPSO_V4_MAP_PASS:
-			type_str = "pass";
-			break;
-		default:
-			type_str = "(unknown)";
-		}
-		audit_log_format(audit_buf,
-				 " cipso_doi=%u cipso_type=%s res=%u",
-				 doi_def->doi,
-				 type_str,
-				 ret_val == 0 ? 1 : 0);
-		audit_log_end(audit_buf);
-	}
-
-	return ret_val;
-}
-
-/**
  * netlbl_cfg_cipsov4_add_map - Add a new CIPSOv4 DOI definition and mapping
  * @doi_def: the DOI definition
  * @domain: the domain mapping to add
@@ -164,58 +121,71 @@
 			       struct netlbl_audit *audit_info)
 {
 	int ret_val = -ENOMEM;
+	u32 doi;
+	u32 doi_type;
 	struct netlbl_dom_map *entry;
+	const char *type_str;
+	struct audit_buffer *audit_buf;
+
+	doi = doi_def->doi;
+	doi_type = doi_def->type;
 
 	entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
 	if (entry == NULL)
-		goto cfg_cipsov4_add_map_failure;
+		return -ENOMEM;
 	if (domain != NULL) {
 		entry->domain = kstrdup(domain, GFP_ATOMIC);
 		if (entry->domain == NULL)
 			goto cfg_cipsov4_add_map_failure;
 	}
-	entry->type = NETLBL_NLTYPE_CIPSOV4;
-	entry->type_def.cipsov4 = doi_def;
 
-	/* Grab a RCU read lock here so nothing happens to the doi_def variable
-	 * between adding it to the CIPSOv4 protocol engine and adding a
-	 * domain mapping for it. */
-
-	rcu_read_lock();
-	ret_val = netlbl_cfg_cipsov4_add(doi_def, audit_info);
-	if (ret_val != 0)
-		goto cfg_cipsov4_add_map_failure_unlock;
-	ret_val = netlbl_domhsh_add(entry, audit_info);
+	ret_val = cipso_v4_doi_add(doi_def);
 	if (ret_val != 0)
 		goto cfg_cipsov4_add_map_failure_remove_doi;
-	rcu_read_unlock();
+	entry->type = NETLBL_NLTYPE_CIPSOV4;
+	entry->type_def.cipsov4 = cipso_v4_doi_getdef(doi);
+	if (entry->type_def.cipsov4 == NULL) {
+		ret_val = -ENOENT;
+		goto cfg_cipsov4_add_map_failure_remove_doi;
+	}
+	ret_val = netlbl_domhsh_add(entry, audit_info);
+	if (ret_val != 0)
+		goto cfg_cipsov4_add_map_failure_release_doi;
 
-	return 0;
+cfg_cipsov4_add_map_return:
+	audit_buf = netlbl_audit_start_common(AUDIT_MAC_CIPSOV4_ADD,
+					      audit_info);
+	if (audit_buf != NULL) {
+		switch (doi_type) {
+		case CIPSO_V4_MAP_TRANS:
+			type_str = "trans";
+			break;
+		case CIPSO_V4_MAP_PASS:
+			type_str = "pass";
+			break;
+		case CIPSO_V4_MAP_LOCAL:
+			type_str = "local";
+			break;
+		default:
+			type_str = "(unknown)";
+		}
+		audit_log_format(audit_buf,
+				 " cipso_doi=%u cipso_type=%s res=%u",
+				 doi, type_str, ret_val == 0 ? 1 : 0);
+		audit_log_end(audit_buf);
+	}
 
+	return ret_val;
+
+cfg_cipsov4_add_map_failure_release_doi:
+	cipso_v4_doi_putdef(doi_def);
 cfg_cipsov4_add_map_failure_remove_doi:
-	cipso_v4_doi_remove(doi_def->doi, audit_info, netlbl_cipsov4_doi_free);
-cfg_cipsov4_add_map_failure_unlock:
-	rcu_read_unlock();
+	cipso_v4_doi_remove(doi, audit_info);
 cfg_cipsov4_add_map_failure:
 	if (entry != NULL)
 		kfree(entry->domain);
 	kfree(entry);
-	return ret_val;
-}
-
-/**
- * netlbl_cfg_cipsov4_del - Removean existing CIPSOv4 DOI definition
- * @doi: the CIPSO DOI value
- * @audit_info: NetLabel audit information
- *
- * Description:
- * Removes an existing CIPSOv4 DOI definition from the NetLabel subsystem.
- * Returns zero on success, negative values on failure.
- *
- */
-int netlbl_cfg_cipsov4_del(u32 doi, struct netlbl_audit *audit_info)
-{
-	return cipso_v4_doi_remove(doi, audit_info, netlbl_cipsov4_doi_free);
+	goto cfg_cipsov4_add_map_return;
 }
 
 /*
@@ -452,7 +422,9 @@
  * Attach the correct label to the given socket using the security attributes
  * specified in @secattr.  This function requires exclusive access to @sk,
  * which means it either needs to be in the process of being created or locked.
- * Returns zero on success, negative values on failure.
+ * Returns zero on success, -EDESTADDRREQ if the domain is configured to use
+ * network address selectors (can't blindly label the socket), and negative
+ * values on all other failures.
  *
  */
 int netlbl_sock_setattr(struct sock *sk,
@@ -466,6 +438,9 @@
 	if (dom_entry == NULL)
 		goto socket_setattr_return;
 	switch (dom_entry->type) {
+	case NETLBL_NLTYPE_ADDRSELECT:
+		ret_val = -EDESTADDRREQ;
+		break;
 	case NETLBL_NLTYPE_CIPSOV4:
 		ret_val = cipso_v4_sock_setattr(sk,
 						dom_entry->type_def.cipsov4,
@@ -484,6 +459,20 @@
 }
 
 /**
+ * netlbl_sock_delattr - Delete all the NetLabel labels on a socket
+ * @sk: the socket
+ *
+ * Description:
+ * Remove all the NetLabel labeling from @sk.  The caller is responsible for
+ * ensuring that @sk is locked.
+ *
+ */
+void netlbl_sock_delattr(struct sock *sk)
+{
+	cipso_v4_sock_delattr(sk);
+}
+
+/**
  * netlbl_sock_getattr - Determine the security attributes of a sock
  * @sk: the sock
  * @secattr: the security attributes
@@ -501,6 +490,128 @@
 }
 
 /**
+ * netlbl_conn_setattr - Label a connected socket using the correct protocol
+ * @sk: the socket to label
+ * @addr: the destination address
+ * @secattr: the security attributes
+ *
+ * Description:
+ * Attach the correct label to the given connected socket using the security
+ * attributes specified in @secattr.  The caller is responsible for ensuring
+ * that @sk is locked.  Returns zero on success, negative values on failure.
+ *
+ */
+int netlbl_conn_setattr(struct sock *sk,
+			struct sockaddr *addr,
+			const struct netlbl_lsm_secattr *secattr)
+{
+	int ret_val;
+	struct sockaddr_in *addr4;
+	struct netlbl_domaddr4_map *af4_entry;
+
+	rcu_read_lock();
+	switch (addr->sa_family) {
+	case AF_INET:
+		addr4 = (struct sockaddr_in *)addr;
+		af4_entry = netlbl_domhsh_getentry_af4(secattr->domain,
+						       addr4->sin_addr.s_addr);
+		if (af4_entry == NULL) {
+			ret_val = -ENOENT;
+			goto conn_setattr_return;
+		}
+		switch (af4_entry->type) {
+		case NETLBL_NLTYPE_CIPSOV4:
+			ret_val = cipso_v4_sock_setattr(sk,
+						   af4_entry->type_def.cipsov4,
+						   secattr);
+			break;
+		case NETLBL_NLTYPE_UNLABELED:
+			/* just delete the protocols we support for right now
+			 * but we could remove other protocols if needed */
+			cipso_v4_sock_delattr(sk);
+			ret_val = 0;
+			break;
+		default:
+			ret_val = -ENOENT;
+		}
+		break;
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+	case AF_INET6:
+		/* since we don't support any IPv6 labeling protocols right
+		 * now we can optimize everything away until we do */
+		ret_val = 0;
+		break;
+#endif /* IPv6 */
+	default:
+		ret_val = 0;
+	}
+
+conn_setattr_return:
+	rcu_read_unlock();
+	return ret_val;
+}
+
+/**
+ * netlbl_skbuff_setattr - Label a packet using the correct protocol
+ * @skb: the packet
+ * @family: protocol family
+ * @secattr: the security attributes
+ *
+ * Description:
+ * Attach the correct label to the given packet using the security attributes
+ * specified in @secattr.  Returns zero on success, negative values on failure.
+ *
+ */
+int netlbl_skbuff_setattr(struct sk_buff *skb,
+			  u16 family,
+			  const struct netlbl_lsm_secattr *secattr)
+{
+	int ret_val;
+	struct iphdr *hdr4;
+	struct netlbl_domaddr4_map *af4_entry;
+
+	rcu_read_lock();
+	switch (family) {
+	case AF_INET:
+		hdr4 = ip_hdr(skb);
+		af4_entry = netlbl_domhsh_getentry_af4(secattr->domain,
+						       hdr4->daddr);
+		if (af4_entry == NULL) {
+			ret_val = -ENOENT;
+			goto skbuff_setattr_return;
+		}
+		switch (af4_entry->type) {
+		case NETLBL_NLTYPE_CIPSOV4:
+			ret_val = cipso_v4_skbuff_setattr(skb,
+						   af4_entry->type_def.cipsov4,
+						   secattr);
+			break;
+		case NETLBL_NLTYPE_UNLABELED:
+			/* just delete the protocols we support for right now
+			 * but we could remove other protocols if needed */
+			ret_val = cipso_v4_skbuff_delattr(skb);
+			break;
+		default:
+			ret_val = -ENOENT;
+		}
+		break;
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+	case AF_INET6:
+		/* since we don't support any IPv6 labeling protocols right
+		 * now we can optimize everything away until we do */
+		ret_val = 0;
+		break;
+#endif /* IPv6 */
+	default:
+		ret_val = 0;
+	}
+
+skbuff_setattr_return:
+	rcu_read_unlock();
+	return ret_val;
+}
+
+/**
  * netlbl_skbuff_getattr - Determine the security attributes of a packet
  * @skb: the packet
  * @family: protocol family
@@ -528,6 +639,7 @@
  * netlbl_skbuff_err - Handle a LSM error on a sk_buff
  * @skb: the packet
  * @error: the error code
+ * @gateway: true if host is acting as a gateway, false otherwise
  *
  * Description:
  * Deal with a LSM problem when handling the packet in @skb, typically this is
@@ -535,10 +647,10 @@
  * according to the packet's labeling protocol.
  *
  */
-void netlbl_skbuff_err(struct sk_buff *skb, int error)
+void netlbl_skbuff_err(struct sk_buff *skb, int error, int gateway)
 {
 	if (CIPSO_V4_OPTEXIST(skb))
-		cipso_v4_error(skb, error, 0);
+		cipso_v4_error(skb, error, gateway);
 }
 
 /**
diff --git a/net/netlabel/netlabel_mgmt.c b/net/netlabel/netlabel_mgmt.c
index 44be5d5..ee769ec 100644
--- a/net/netlabel/netlabel_mgmt.c
+++ b/net/netlabel/netlabel_mgmt.c
@@ -10,7 +10,7 @@
  */
 
 /*
- * (c) Copyright Hewlett-Packard Development Company, L.P., 2006
+ * (c) Copyright Hewlett-Packard Development Company, L.P., 2006, 2008
  *
  * This program is free software;  you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -32,9 +32,13 @@
 #include <linux/socket.h>
 #include <linux/string.h>
 #include <linux/skbuff.h>
+#include <linux/in.h>
+#include <linux/in6.h>
 #include <net/sock.h>
 #include <net/netlink.h>
 #include <net/genetlink.h>
+#include <net/ip.h>
+#include <net/ipv6.h>
 #include <net/netlabel.h>
 #include <net/cipso_ipv4.h>
 #include <asm/atomic.h>
@@ -71,6 +75,301 @@
 };
 
 /*
+ * Helper Functions
+ */
+
+/**
+ * netlbl_mgmt_add - Handle an ADD message
+ * @info: the Generic NETLINK info block
+ * @audit_info: NetLabel audit information
+ *
+ * Description:
+ * Helper function for the ADD and ADDDEF messages to add the domain mappings
+ * from the message to the hash table.  See netlabel.h for a description of the
+ * message format.  Returns zero on success, negative values on failure.
+ *
+ */
+static int netlbl_mgmt_add_common(struct genl_info *info,
+				  struct netlbl_audit *audit_info)
+{
+	int ret_val = -EINVAL;
+	struct netlbl_dom_map *entry = NULL;
+	struct netlbl_domaddr_map *addrmap = NULL;
+	struct cipso_v4_doi *cipsov4 = NULL;
+	u32 tmp_val;
+
+	entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+	if (entry == NULL) {
+		ret_val = -ENOMEM;
+		goto add_failure;
+	}
+	entry->type = nla_get_u32(info->attrs[NLBL_MGMT_A_PROTOCOL]);
+	if (info->attrs[NLBL_MGMT_A_DOMAIN]) {
+		size_t tmp_size = nla_len(info->attrs[NLBL_MGMT_A_DOMAIN]);
+		entry->domain = kmalloc(tmp_size, GFP_KERNEL);
+		if (entry->domain == NULL) {
+			ret_val = -ENOMEM;
+			goto add_failure;
+		}
+		nla_strlcpy(entry->domain,
+			    info->attrs[NLBL_MGMT_A_DOMAIN], tmp_size);
+	}
+
+	/* NOTE: internally we allow/use a entry->type value of
+	 *       NETLBL_NLTYPE_ADDRSELECT but we don't currently allow users
+	 *       to pass that as a protocol value because we need to know the
+	 *       "real" protocol */
+
+	switch (entry->type) {
+	case NETLBL_NLTYPE_UNLABELED:
+		break;
+	case NETLBL_NLTYPE_CIPSOV4:
+		if (!info->attrs[NLBL_MGMT_A_CV4DOI])
+			goto add_failure;
+
+		tmp_val = nla_get_u32(info->attrs[NLBL_MGMT_A_CV4DOI]);
+		cipsov4 = cipso_v4_doi_getdef(tmp_val);
+		if (cipsov4 == NULL)
+			goto add_failure;
+		entry->type_def.cipsov4 = cipsov4;
+		break;
+	default:
+		goto add_failure;
+	}
+
+	if (info->attrs[NLBL_MGMT_A_IPV4ADDR]) {
+		struct in_addr *addr;
+		struct in_addr *mask;
+		struct netlbl_domaddr4_map *map;
+
+		addrmap = kzalloc(sizeof(*addrmap), GFP_KERNEL);
+		if (addrmap == NULL) {
+			ret_val = -ENOMEM;
+			goto add_failure;
+		}
+		INIT_LIST_HEAD(&addrmap->list4);
+		INIT_LIST_HEAD(&addrmap->list6);
+
+		if (nla_len(info->attrs[NLBL_MGMT_A_IPV4ADDR]) !=
+		    sizeof(struct in_addr)) {
+			ret_val = -EINVAL;
+			goto add_failure;
+		}
+		if (nla_len(info->attrs[NLBL_MGMT_A_IPV4MASK]) !=
+		    sizeof(struct in_addr)) {
+			ret_val = -EINVAL;
+			goto add_failure;
+		}
+		addr = nla_data(info->attrs[NLBL_MGMT_A_IPV4ADDR]);
+		mask = nla_data(info->attrs[NLBL_MGMT_A_IPV4MASK]);
+
+		map = kzalloc(sizeof(*map), GFP_KERNEL);
+		if (map == NULL) {
+			ret_val = -ENOMEM;
+			goto add_failure;
+		}
+		map->list.addr = addr->s_addr & mask->s_addr;
+		map->list.mask = mask->s_addr;
+		map->list.valid = 1;
+		map->type = entry->type;
+		if (cipsov4)
+			map->type_def.cipsov4 = cipsov4;
+
+		ret_val = netlbl_af4list_add(&map->list, &addrmap->list4);
+		if (ret_val != 0) {
+			kfree(map);
+			goto add_failure;
+		}
+
+		entry->type = NETLBL_NLTYPE_ADDRSELECT;
+		entry->type_def.addrsel = addrmap;
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+	} else if (info->attrs[NLBL_MGMT_A_IPV6ADDR]) {
+		struct in6_addr *addr;
+		struct in6_addr *mask;
+		struct netlbl_domaddr6_map *map;
+
+		addrmap = kzalloc(sizeof(*addrmap), GFP_KERNEL);
+		if (addrmap == NULL) {
+			ret_val = -ENOMEM;
+			goto add_failure;
+		}
+		INIT_LIST_HEAD(&addrmap->list4);
+		INIT_LIST_HEAD(&addrmap->list6);
+
+		if (nla_len(info->attrs[NLBL_MGMT_A_IPV6ADDR]) !=
+		    sizeof(struct in6_addr)) {
+			ret_val = -EINVAL;
+			goto add_failure;
+		}
+		if (nla_len(info->attrs[NLBL_MGMT_A_IPV6MASK]) !=
+		    sizeof(struct in6_addr)) {
+			ret_val = -EINVAL;
+			goto add_failure;
+		}
+		addr = nla_data(info->attrs[NLBL_MGMT_A_IPV6ADDR]);
+		mask = nla_data(info->attrs[NLBL_MGMT_A_IPV6MASK]);
+
+		map = kzalloc(sizeof(*map), GFP_KERNEL);
+		if (map == NULL) {
+			ret_val = -ENOMEM;
+			goto add_failure;
+		}
+		ipv6_addr_copy(&map->list.addr, addr);
+		map->list.addr.s6_addr32[0] &= mask->s6_addr32[0];
+		map->list.addr.s6_addr32[1] &= mask->s6_addr32[1];
+		map->list.addr.s6_addr32[2] &= mask->s6_addr32[2];
+		map->list.addr.s6_addr32[3] &= mask->s6_addr32[3];
+		ipv6_addr_copy(&map->list.mask, mask);
+		map->list.valid = 1;
+		map->type = entry->type;
+
+		ret_val = netlbl_af6list_add(&map->list, &addrmap->list6);
+		if (ret_val != 0) {
+			kfree(map);
+			goto add_failure;
+		}
+
+		entry->type = NETLBL_NLTYPE_ADDRSELECT;
+		entry->type_def.addrsel = addrmap;
+#endif /* IPv6 */
+	}
+
+	ret_val = netlbl_domhsh_add(entry, audit_info);
+	if (ret_val != 0)
+		goto add_failure;
+
+	return 0;
+
+add_failure:
+	if (cipsov4)
+		cipso_v4_doi_putdef(cipsov4);
+	if (entry)
+		kfree(entry->domain);
+	kfree(addrmap);
+	kfree(entry);
+	return ret_val;
+}
+
+/**
+ * netlbl_mgmt_listentry - List a NetLabel/LSM domain map entry
+ * @skb: the NETLINK buffer
+ * @entry: the map entry
+ *
+ * Description:
+ * This function is a helper function used by the LISTALL and LISTDEF command
+ * handlers.  The caller is responsibile for ensuring that the RCU read lock
+ * is held.  Returns zero on success, negative values on failure.
+ *
+ */
+static int netlbl_mgmt_listentry(struct sk_buff *skb,
+				 struct netlbl_dom_map *entry)
+{
+	int ret_val;
+	struct nlattr *nla_a;
+	struct nlattr *nla_b;
+	struct netlbl_af4list *iter4;
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+	struct netlbl_af6list *iter6;
+#endif
+
+	if (entry->domain != NULL) {
+		ret_val = nla_put_string(skb,
+					 NLBL_MGMT_A_DOMAIN, entry->domain);
+		if (ret_val != 0)
+			return ret_val;
+	}
+
+	switch (entry->type) {
+	case NETLBL_NLTYPE_ADDRSELECT:
+		nla_a = nla_nest_start(skb, NLBL_MGMT_A_SELECTORLIST);
+		if (nla_a == NULL)
+			return -ENOMEM;
+
+		netlbl_af4list_foreach_rcu(iter4,
+					   &entry->type_def.addrsel->list4) {
+			struct netlbl_domaddr4_map *map4;
+			struct in_addr addr_struct;
+
+			nla_b = nla_nest_start(skb, NLBL_MGMT_A_ADDRSELECTOR);
+			if (nla_b == NULL)
+				return -ENOMEM;
+
+			addr_struct.s_addr = iter4->addr;
+			ret_val = nla_put(skb, NLBL_MGMT_A_IPV4ADDR,
+					  sizeof(struct in_addr),
+					  &addr_struct);
+			if (ret_val != 0)
+				return ret_val;
+			addr_struct.s_addr = iter4->mask;
+			ret_val = nla_put(skb, NLBL_MGMT_A_IPV4MASK,
+					  sizeof(struct in_addr),
+					  &addr_struct);
+			if (ret_val != 0)
+				return ret_val;
+			map4 = netlbl_domhsh_addr4_entry(iter4);
+			ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL,
+					      map4->type);
+			if (ret_val != 0)
+				return ret_val;
+			switch (map4->type) {
+			case NETLBL_NLTYPE_CIPSOV4:
+				ret_val = nla_put_u32(skb, NLBL_MGMT_A_CV4DOI,
+						  map4->type_def.cipsov4->doi);
+				if (ret_val != 0)
+					return ret_val;
+				break;
+			}
+
+			nla_nest_end(skb, nla_b);
+		}
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+		netlbl_af6list_foreach_rcu(iter6,
+					   &entry->type_def.addrsel->list6) {
+			struct netlbl_domaddr6_map *map6;
+
+			nla_b = nla_nest_start(skb, NLBL_MGMT_A_ADDRSELECTOR);
+			if (nla_b == NULL)
+				return -ENOMEM;
+
+			ret_val = nla_put(skb, NLBL_MGMT_A_IPV6ADDR,
+					  sizeof(struct in6_addr),
+					  &iter6->addr);
+			if (ret_val != 0)
+				return ret_val;
+			ret_val = nla_put(skb, NLBL_MGMT_A_IPV6MASK,
+					  sizeof(struct in6_addr),
+					  &iter6->mask);
+			if (ret_val != 0)
+				return ret_val;
+			map6 = netlbl_domhsh_addr6_entry(iter6);
+			ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL,
+					      map6->type);
+			if (ret_val != 0)
+				return ret_val;
+
+			nla_nest_end(skb, nla_b);
+		}
+#endif /* IPv6 */
+
+		nla_nest_end(skb, nla_a);
+		break;
+	case NETLBL_NLTYPE_UNLABELED:
+		ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL, entry->type);
+		break;
+	case NETLBL_NLTYPE_CIPSOV4:
+		ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL, entry->type);
+		if (ret_val != 0)
+			return ret_val;
+		ret_val = nla_put_u32(skb, NLBL_MGMT_A_CV4DOI,
+				      entry->type_def.cipsov4->doi);
+		break;
+	}
+
+	return ret_val;
+}
+
+/*
  * NetLabel Command Handlers
  */
 
@@ -87,67 +386,23 @@
  */
 static int netlbl_mgmt_add(struct sk_buff *skb, struct genl_info *info)
 {
-	int ret_val = -EINVAL;
-	struct netlbl_dom_map *entry = NULL;
-	size_t tmp_size;
-	u32 tmp_val;
 	struct netlbl_audit audit_info;
 
-	if (!info->attrs[NLBL_MGMT_A_DOMAIN] ||
-	    !info->attrs[NLBL_MGMT_A_PROTOCOL])
-		goto add_failure;
+	if ((!info->attrs[NLBL_MGMT_A_DOMAIN]) ||
+	    (!info->attrs[NLBL_MGMT_A_PROTOCOL]) ||
+	    (info->attrs[NLBL_MGMT_A_IPV4ADDR] &&
+	     info->attrs[NLBL_MGMT_A_IPV6ADDR]) ||
+	    (info->attrs[NLBL_MGMT_A_IPV4MASK] &&
+	     info->attrs[NLBL_MGMT_A_IPV6MASK]) ||
+	    ((info->attrs[NLBL_MGMT_A_IPV4ADDR] != NULL) ^
+	     (info->attrs[NLBL_MGMT_A_IPV4MASK] != NULL)) ||
+	    ((info->attrs[NLBL_MGMT_A_IPV6ADDR] != NULL) ^
+	     (info->attrs[NLBL_MGMT_A_IPV6MASK] != NULL)))
+		return -EINVAL;
 
 	netlbl_netlink_auditinfo(skb, &audit_info);
 
-	entry = kzalloc(sizeof(*entry), GFP_KERNEL);
-	if (entry == NULL) {
-		ret_val = -ENOMEM;
-		goto add_failure;
-	}
-	tmp_size = nla_len(info->attrs[NLBL_MGMT_A_DOMAIN]);
-	entry->domain = kmalloc(tmp_size, GFP_KERNEL);
-	if (entry->domain == NULL) {
-		ret_val = -ENOMEM;
-		goto add_failure;
-	}
-	entry->type = nla_get_u32(info->attrs[NLBL_MGMT_A_PROTOCOL]);
-	nla_strlcpy(entry->domain, info->attrs[NLBL_MGMT_A_DOMAIN], tmp_size);
-
-	switch (entry->type) {
-	case NETLBL_NLTYPE_UNLABELED:
-		ret_val = netlbl_domhsh_add(entry, &audit_info);
-		break;
-	case NETLBL_NLTYPE_CIPSOV4:
-		if (!info->attrs[NLBL_MGMT_A_CV4DOI])
-			goto add_failure;
-
-		tmp_val = nla_get_u32(info->attrs[NLBL_MGMT_A_CV4DOI]);
-		/* We should be holding a rcu_read_lock() here while we hold
-		 * the result but since the entry will always be deleted when
-		 * the CIPSO DOI is deleted we aren't going to keep the
-		 * lock. */
-		rcu_read_lock();
-		entry->type_def.cipsov4 = cipso_v4_doi_getdef(tmp_val);
-		if (entry->type_def.cipsov4 == NULL) {
-			rcu_read_unlock();
-			goto add_failure;
-		}
-		ret_val = netlbl_domhsh_add(entry, &audit_info);
-		rcu_read_unlock();
-		break;
-	default:
-		goto add_failure;
-	}
-	if (ret_val != 0)
-		goto add_failure;
-
-	return 0;
-
-add_failure:
-	if (entry)
-		kfree(entry->domain);
-	kfree(entry);
-	return ret_val;
+	return netlbl_mgmt_add_common(info, &audit_info);
 }
 
 /**
@@ -198,23 +453,9 @@
 	if (data == NULL)
 		goto listall_cb_failure;
 
-	ret_val = nla_put_string(cb_arg->skb,
-				 NLBL_MGMT_A_DOMAIN,
-				 entry->domain);
+	ret_val = netlbl_mgmt_listentry(cb_arg->skb, entry);
 	if (ret_val != 0)
 		goto listall_cb_failure;
-	ret_val = nla_put_u32(cb_arg->skb, NLBL_MGMT_A_PROTOCOL, entry->type);
-	if (ret_val != 0)
-		goto listall_cb_failure;
-	switch (entry->type) {
-	case NETLBL_NLTYPE_CIPSOV4:
-		ret_val = nla_put_u32(cb_arg->skb,
-				      NLBL_MGMT_A_CV4DOI,
-				      entry->type_def.cipsov4->doi);
-		if (ret_val != 0)
-			goto listall_cb_failure;
-		break;
-	}
 
 	cb_arg->seq++;
 	return genlmsg_end(cb_arg->skb, data);
@@ -268,56 +509,22 @@
  */
 static int netlbl_mgmt_adddef(struct sk_buff *skb, struct genl_info *info)
 {
-	int ret_val = -EINVAL;
-	struct netlbl_dom_map *entry = NULL;
-	u32 tmp_val;
 	struct netlbl_audit audit_info;
 
-	if (!info->attrs[NLBL_MGMT_A_PROTOCOL])
-		goto adddef_failure;
+	if ((!info->attrs[NLBL_MGMT_A_PROTOCOL]) ||
+	    (info->attrs[NLBL_MGMT_A_IPV4ADDR] &&
+	     info->attrs[NLBL_MGMT_A_IPV6ADDR]) ||
+	    (info->attrs[NLBL_MGMT_A_IPV4MASK] &&
+	     info->attrs[NLBL_MGMT_A_IPV6MASK]) ||
+	    ((info->attrs[NLBL_MGMT_A_IPV4ADDR] != NULL) ^
+	     (info->attrs[NLBL_MGMT_A_IPV4MASK] != NULL)) ||
+	    ((info->attrs[NLBL_MGMT_A_IPV6ADDR] != NULL) ^
+	     (info->attrs[NLBL_MGMT_A_IPV6MASK] != NULL)))
+		return -EINVAL;
 
 	netlbl_netlink_auditinfo(skb, &audit_info);
 
-	entry = kzalloc(sizeof(*entry), GFP_KERNEL);
-	if (entry == NULL) {
-		ret_val = -ENOMEM;
-		goto adddef_failure;
-	}
-	entry->type = nla_get_u32(info->attrs[NLBL_MGMT_A_PROTOCOL]);
-
-	switch (entry->type) {
-	case NETLBL_NLTYPE_UNLABELED:
-		ret_val = netlbl_domhsh_add_default(entry, &audit_info);
-		break;
-	case NETLBL_NLTYPE_CIPSOV4:
-		if (!info->attrs[NLBL_MGMT_A_CV4DOI])
-			goto adddef_failure;
-
-		tmp_val = nla_get_u32(info->attrs[NLBL_MGMT_A_CV4DOI]);
-		/* We should be holding a rcu_read_lock() here while we hold
-		 * the result but since the entry will always be deleted when
-		 * the CIPSO DOI is deleted we aren't going to keep the
-		 * lock. */
-		rcu_read_lock();
-		entry->type_def.cipsov4 = cipso_v4_doi_getdef(tmp_val);
-		if (entry->type_def.cipsov4 == NULL) {
-			rcu_read_unlock();
-			goto adddef_failure;
-		}
-		ret_val = netlbl_domhsh_add_default(entry, &audit_info);
-		rcu_read_unlock();
-		break;
-	default:
-		goto adddef_failure;
-	}
-	if (ret_val != 0)
-		goto adddef_failure;
-
-	return 0;
-
-adddef_failure:
-	kfree(entry);
-	return ret_val;
+	return netlbl_mgmt_add_common(info, &audit_info);
 }
 
 /**
@@ -371,19 +578,10 @@
 		ret_val = -ENOENT;
 		goto listdef_failure_lock;
 	}
-	ret_val = nla_put_u32(ans_skb, NLBL_MGMT_A_PROTOCOL, entry->type);
-	if (ret_val != 0)
-		goto listdef_failure_lock;
-	switch (entry->type) {
-	case NETLBL_NLTYPE_CIPSOV4:
-		ret_val = nla_put_u32(ans_skb,
-				      NLBL_MGMT_A_CV4DOI,
-				      entry->type_def.cipsov4->doi);
-		if (ret_val != 0)
-			goto listdef_failure_lock;
-		break;
-	}
+	ret_val = netlbl_mgmt_listentry(ans_skb, entry);
 	rcu_read_unlock();
+	if (ret_val != 0)
+		goto listdef_failure;
 
 	genlmsg_end(ans_skb, data);
 	return genlmsg_reply(ans_skb, info);
diff --git a/net/netlabel/netlabel_mgmt.h b/net/netlabel/netlabel_mgmt.h
index a43bff1..05d9643 100644
--- a/net/netlabel/netlabel_mgmt.h
+++ b/net/netlabel/netlabel_mgmt.h
@@ -45,6 +45,16 @@
  *     NLBL_MGMT_A_DOMAIN
  *     NLBL_MGMT_A_PROTOCOL
  *
+ *   If IPv4 is specified the following attributes are required:
+ *
+ *     NLBL_MGMT_A_IPV4ADDR
+ *     NLBL_MGMT_A_IPV4MASK
+ *
+ *   If IPv6 is specified the following attributes are required:
+ *
+ *     NLBL_MGMT_A_IPV6ADDR
+ *     NLBL_MGMT_A_IPV6MASK
+ *
  *   If using NETLBL_NLTYPE_CIPSOV4 the following attributes are required:
  *
  *     NLBL_MGMT_A_CV4DOI
@@ -68,13 +78,24 @@
  *   Required attributes:
  *
  *     NLBL_MGMT_A_DOMAIN
+ *
+ *   If the IP address selectors are not used the following attribute is
+ *   required:
+ *
  *     NLBL_MGMT_A_PROTOCOL
  *
- *   If using NETLBL_NLTYPE_CIPSOV4 the following attributes are required:
+ *   If the IP address selectors are used then the following attritbute is
+ *   required:
+ *
+ *     NLBL_MGMT_A_SELECTORLIST
+ *
+ *   If the mapping is using the NETLBL_NLTYPE_CIPSOV4 type then the following
+ *   attributes are required:
  *
  *     NLBL_MGMT_A_CV4DOI
  *
- *   If using NETLBL_NLTYPE_UNLABELED no other attributes are required.
+ *   If the mapping is using the NETLBL_NLTYPE_UNLABELED type no other
+ *   attributes are required.
  *
  * o ADDDEF:
  *   Sent by an application to set the default domain mapping for the NetLabel
@@ -100,15 +121,23 @@
  *   application there is no payload.  On success the kernel should send a
  *   response using the following format.
  *
- *   Required attributes:
+ *   If the IP address selectors are not used the following attribute is
+ *   required:
  *
  *     NLBL_MGMT_A_PROTOCOL
  *
- *   If using NETLBL_NLTYPE_CIPSOV4 the following attributes are required:
+ *   If the IP address selectors are used then the following attritbute is
+ *   required:
+ *
+ *     NLBL_MGMT_A_SELECTORLIST
+ *
+ *   If the mapping is using the NETLBL_NLTYPE_CIPSOV4 type then the following
+ *   attributes are required:
  *
  *     NLBL_MGMT_A_CV4DOI
  *
- *   If using NETLBL_NLTYPE_UNLABELED no other attributes are required.
+ *   If the mapping is using the NETLBL_NLTYPE_UNLABELED type no other
+ *   attributes are required.
  *
  * o PROTOCOLS:
  *   Sent by an application to request a list of configured NetLabel protocols
@@ -162,6 +191,26 @@
 	NLBL_MGMT_A_CV4DOI,
 	/* (NLA_U32)
 	 * the CIPSOv4 DOI value */
+	NLBL_MGMT_A_IPV6ADDR,
+	/* (NLA_BINARY, struct in6_addr)
+	 * an IPv6 address */
+	NLBL_MGMT_A_IPV6MASK,
+	/* (NLA_BINARY, struct in6_addr)
+	 * an IPv6 address mask */
+	NLBL_MGMT_A_IPV4ADDR,
+	/* (NLA_BINARY, struct in_addr)
+	 * an IPv4 address */
+	NLBL_MGMT_A_IPV4MASK,
+	/* (NLA_BINARY, struct in_addr)
+	 * and IPv4 address mask */
+	NLBL_MGMT_A_ADDRSELECTOR,
+	/* (NLA_NESTED)
+	 * an IP address selector, must contain an address, mask, and protocol
+	 * attribute plus any protocol specific attributes */
+	NLBL_MGMT_A_SELECTORLIST,
+	/* (NLA_NESTED)
+	 * the selector list, there must be at least one
+	 * NLBL_MGMT_A_ADDRSELECTOR attribute */
 	__NLBL_MGMT_A_MAX,
 };
 #define NLBL_MGMT_A_MAX (__NLBL_MGMT_A_MAX - 1)
diff --git a/net/netlabel/netlabel_unlabeled.c b/net/netlabel/netlabel_unlabeled.c
index 921c118..e8a5c32 100644
--- a/net/netlabel/netlabel_unlabeled.c
+++ b/net/netlabel/netlabel_unlabeled.c
@@ -10,7 +10,7 @@
  */
 
 /*
- * (c) Copyright Hewlett-Packard Development Company, L.P., 2006 - 2007
+ * (c) Copyright Hewlett-Packard Development Company, L.P., 2006 - 2008
  *
  * This program is free software;  you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -54,6 +54,7 @@
 #include <asm/atomic.h>
 
 #include "netlabel_user.h"
+#include "netlabel_addrlist.h"
 #include "netlabel_domainhash.h"
 #include "netlabel_unlabeled.h"
 #include "netlabel_mgmt.h"
@@ -76,22 +77,20 @@
 	struct list_head *tbl;
 	u32 size;
 };
+#define netlbl_unlhsh_addr4_entry(iter) \
+	container_of(iter, struct netlbl_unlhsh_addr4, list)
 struct netlbl_unlhsh_addr4 {
-	__be32 addr;
-	__be32 mask;
 	u32 secid;
 
-	u32 valid;
-	struct list_head list;
+	struct netlbl_af4list list;
 	struct rcu_head rcu;
 };
+#define netlbl_unlhsh_addr6_entry(iter) \
+	container_of(iter, struct netlbl_unlhsh_addr6, list)
 struct netlbl_unlhsh_addr6 {
-	struct in6_addr addr;
-	struct in6_addr mask;
 	u32 secid;
 
-	u32 valid;
-	struct list_head list;
+	struct netlbl_af6list list;
 	struct rcu_head rcu;
 };
 struct netlbl_unlhsh_iface {
@@ -147,76 +146,6 @@
 };
 
 /*
- * Audit Helper Functions
- */
-
-/**
- * netlbl_unlabel_audit_addr4 - Audit an IPv4 address
- * @audit_buf: audit buffer
- * @dev: network interface
- * @addr: IP address
- * @mask: IP address mask
- *
- * Description:
- * Write the IPv4 address and address mask, if necessary, to @audit_buf.
- *
- */
-static void netlbl_unlabel_audit_addr4(struct audit_buffer *audit_buf,
-				     const char *dev,
-				     __be32 addr, __be32 mask)
-{
-	u32 mask_val = ntohl(mask);
-
-	if (dev != NULL)
-		audit_log_format(audit_buf, " netif=%s", dev);
-	audit_log_format(audit_buf, " src=" NIPQUAD_FMT, NIPQUAD(addr));
-	if (mask_val != 0xffffffff) {
-		u32 mask_len = 0;
-		while (mask_val > 0) {
-			mask_val <<= 1;
-			mask_len++;
-		}
-		audit_log_format(audit_buf, " src_prefixlen=%d", mask_len);
-	}
-}
-
-#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
-/**
- * netlbl_unlabel_audit_addr6 - Audit an IPv6 address
- * @audit_buf: audit buffer
- * @dev: network interface
- * @addr: IP address
- * @mask: IP address mask
- *
- * Description:
- * Write the IPv6 address and address mask, if necessary, to @audit_buf.
- *
- */
-static void netlbl_unlabel_audit_addr6(struct audit_buffer *audit_buf,
-				     const char *dev,
-				     const struct in6_addr *addr,
-				     const struct in6_addr *mask)
-{
-	if (dev != NULL)
-		audit_log_format(audit_buf, " netif=%s", dev);
-	audit_log_format(audit_buf, " src=" NIP6_FMT, NIP6(*addr));
-	if (ntohl(mask->s6_addr32[3]) != 0xffffffff) {
-		u32 mask_len = 0;
-		u32 mask_val;
-		int iter = -1;
-		while (ntohl(mask->s6_addr32[++iter]) == 0xffffffff)
-			mask_len += 32;
-		mask_val = ntohl(mask->s6_addr32[iter]);
-		while (mask_val > 0) {
-			mask_val <<= 1;
-			mask_len++;
-		}
-		audit_log_format(audit_buf, " src_prefixlen=%d", mask_len);
-	}
-}
-#endif /* IPv6 */
-
-/*
  * Unlabeled Connection Hash Table Functions
  */
 
@@ -274,26 +203,28 @@
 static void netlbl_unlhsh_free_iface(struct rcu_head *entry)
 {
 	struct netlbl_unlhsh_iface *iface;
-	struct netlbl_unlhsh_addr4 *iter4;
-	struct netlbl_unlhsh_addr4 *tmp4;
-	struct netlbl_unlhsh_addr6 *iter6;
-	struct netlbl_unlhsh_addr6 *tmp6;
+	struct netlbl_af4list *iter4;
+	struct netlbl_af4list *tmp4;
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+	struct netlbl_af6list *iter6;
+	struct netlbl_af6list *tmp6;
+#endif /* IPv6 */
 
 	iface = container_of(entry, struct netlbl_unlhsh_iface, rcu);
 
 	/* no need for locks here since we are the only one with access to this
 	 * structure */
 
-	list_for_each_entry_safe(iter4, tmp4, &iface->addr4_list, list)
-		if (iter4->valid) {
-			list_del_rcu(&iter4->list);
-			kfree(iter4);
-		}
-	list_for_each_entry_safe(iter6, tmp6, &iface->addr6_list, list)
-		if (iter6->valid) {
-			list_del_rcu(&iter6->list);
-			kfree(iter6);
-		}
+	netlbl_af4list_foreach_safe(iter4, tmp4, &iface->addr4_list) {
+		netlbl_af4list_remove_entry(iter4);
+		kfree(netlbl_unlhsh_addr4_entry(iter4));
+	}
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+	netlbl_af6list_foreach_safe(iter6, tmp6, &iface->addr6_list) {
+		netlbl_af6list_remove_entry(iter6);
+		kfree(netlbl_unlhsh_addr6_entry(iter6));
+	}
+#endif /* IPv6 */
 	kfree(iface);
 }
 
@@ -316,59 +247,6 @@
 }
 
 /**
- * netlbl_unlhsh_search_addr4 - Search for a matching IPv4 address entry
- * @addr: IPv4 address
- * @iface: the network interface entry
- *
- * Description:
- * Searches the IPv4 address list of the network interface specified by @iface.
- * If a matching address entry is found it is returned, otherwise NULL is
- * returned.  The caller is responsible for calling the rcu_read_[un]lock()
- * functions.
- *
- */
-static struct netlbl_unlhsh_addr4 *netlbl_unlhsh_search_addr4(
-	                               __be32 addr,
-	                               const struct netlbl_unlhsh_iface *iface)
-{
-	struct netlbl_unlhsh_addr4 *iter;
-
-	list_for_each_entry_rcu(iter, &iface->addr4_list, list)
-		if (iter->valid && (addr & iter->mask) == iter->addr)
-			return iter;
-
-	return NULL;
-}
-
-#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
-/**
- * netlbl_unlhsh_search_addr6 - Search for a matching IPv6 address entry
- * @addr: IPv6 address
- * @iface: the network interface entry
- *
- * Description:
- * Searches the IPv6 address list of the network interface specified by @iface.
- * If a matching address entry is found it is returned, otherwise NULL is
- * returned.  The caller is responsible for calling the rcu_read_[un]lock()
- * functions.
- *
- */
-static struct netlbl_unlhsh_addr6 *netlbl_unlhsh_search_addr6(
-	                               const struct in6_addr *addr,
-	                               const struct netlbl_unlhsh_iface *iface)
-{
-	struct netlbl_unlhsh_addr6 *iter;
-
-	list_for_each_entry_rcu(iter, &iface->addr6_list, list)
-		if (iter->valid &&
-		    ipv6_masked_addr_cmp(&iter->addr, &iter->mask, addr) == 0)
-		return iter;
-
-	return NULL;
-}
-#endif /* IPv6 */
-
-/**
  * netlbl_unlhsh_search_iface - Search for a matching interface entry
  * @ifindex: the network interface
  *
@@ -381,12 +259,12 @@
 static struct netlbl_unlhsh_iface *netlbl_unlhsh_search_iface(int ifindex)
 {
 	u32 bkt;
+	struct list_head *bkt_list;
 	struct netlbl_unlhsh_iface *iter;
 
 	bkt = netlbl_unlhsh_hash(ifindex);
-	list_for_each_entry_rcu(iter,
-				&rcu_dereference(netlbl_unlhsh)->tbl[bkt],
-				list)
+	bkt_list = &rcu_dereference(netlbl_unlhsh)->tbl[bkt];
+	list_for_each_entry_rcu(iter, bkt_list, list)
 		if (iter->valid && iter->ifindex == ifindex)
 			return iter;
 
@@ -439,43 +317,26 @@
 				   const struct in_addr *mask,
 				   u32 secid)
 {
+	int ret_val;
 	struct netlbl_unlhsh_addr4 *entry;
-	struct netlbl_unlhsh_addr4 *iter;
 
 	entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
 	if (entry == NULL)
 		return -ENOMEM;
 
-	entry->addr = addr->s_addr & mask->s_addr;
-	entry->mask = mask->s_addr;
-	entry->secid = secid;
-	entry->valid = 1;
+	entry->list.addr = addr->s_addr & mask->s_addr;
+	entry->list.mask = mask->s_addr;
+	entry->list.valid = 1;
 	INIT_RCU_HEAD(&entry->rcu);
+	entry->secid = secid;
 
 	spin_lock(&netlbl_unlhsh_lock);
-	iter = netlbl_unlhsh_search_addr4(entry->addr, iface);
-	if (iter != NULL &&
-	    iter->addr == addr->s_addr && iter->mask == mask->s_addr) {
-		spin_unlock(&netlbl_unlhsh_lock);
-		kfree(entry);
-		return -EEXIST;
-	}
-	/* in order to speed up address searches through the list (the common
-	 * case) we need to keep the list in order based on the size of the
-	 * address mask such that the entry with the widest mask (smallest
-	 * numerical value) appears first in the list */
-	list_for_each_entry_rcu(iter, &iface->addr4_list, list)
-		if (iter->valid &&
-		    ntohl(entry->mask) > ntohl(iter->mask)) {
-			__list_add_rcu(&entry->list,
-				       iter->list.prev,
-				       &iter->list);
-			spin_unlock(&netlbl_unlhsh_lock);
-			return 0;
-		}
-	list_add_tail_rcu(&entry->list, &iface->addr4_list);
+	ret_val = netlbl_af4list_add(&entry->list, &iface->addr4_list);
 	spin_unlock(&netlbl_unlhsh_lock);
-	return 0;
+
+	if (ret_val != 0)
+		kfree(entry);
+	return ret_val;
 }
 
 #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
@@ -498,47 +359,29 @@
 				   const struct in6_addr *mask,
 				   u32 secid)
 {
+	int ret_val;
 	struct netlbl_unlhsh_addr6 *entry;
-	struct netlbl_unlhsh_addr6 *iter;
 
 	entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
 	if (entry == NULL)
 		return -ENOMEM;
 
-	ipv6_addr_copy(&entry->addr, addr);
-	entry->addr.s6_addr32[0] &= mask->s6_addr32[0];
-	entry->addr.s6_addr32[1] &= mask->s6_addr32[1];
-	entry->addr.s6_addr32[2] &= mask->s6_addr32[2];
-	entry->addr.s6_addr32[3] &= mask->s6_addr32[3];
-	ipv6_addr_copy(&entry->mask, mask);
-	entry->secid = secid;
-	entry->valid = 1;
+	ipv6_addr_copy(&entry->list.addr, addr);
+	entry->list.addr.s6_addr32[0] &= mask->s6_addr32[0];
+	entry->list.addr.s6_addr32[1] &= mask->s6_addr32[1];
+	entry->list.addr.s6_addr32[2] &= mask->s6_addr32[2];
+	entry->list.addr.s6_addr32[3] &= mask->s6_addr32[3];
+	ipv6_addr_copy(&entry->list.mask, mask);
+	entry->list.valid = 1;
 	INIT_RCU_HEAD(&entry->rcu);
+	entry->secid = secid;
 
 	spin_lock(&netlbl_unlhsh_lock);
-	iter = netlbl_unlhsh_search_addr6(&entry->addr, iface);
-	if (iter != NULL &&
-	    (ipv6_addr_equal(&iter->addr, addr) &&
-	     ipv6_addr_equal(&iter->mask, mask))) {
-		spin_unlock(&netlbl_unlhsh_lock);
-		kfree(entry);
-		return -EEXIST;
-	}
-	/* in order to speed up address searches through the list (the common
-	 * case) we need to keep the list in order based on the size of the
-	 * address mask such that the entry with the widest mask (smallest
-	 * numerical value) appears first in the list */
-	list_for_each_entry_rcu(iter, &iface->addr6_list, list)
-		if (iter->valid &&
-		    ipv6_addr_cmp(&entry->mask, &iter->mask) > 0) {
-			__list_add_rcu(&entry->list,
-				       iter->list.prev,
-				       &iter->list);
-			spin_unlock(&netlbl_unlhsh_lock);
-			return 0;
-		}
-	list_add_tail_rcu(&entry->list, &iface->addr6_list);
+	ret_val = netlbl_af6list_add(&entry->list, &iface->addr6_list);
 	spin_unlock(&netlbl_unlhsh_lock);
+
+	if (ret_val != 0)
+		kfree(entry);
 	return 0;
 }
 #endif /* IPv6 */
@@ -658,10 +501,10 @@
 		mask4 = (struct in_addr *)mask;
 		ret_val = netlbl_unlhsh_add_addr4(iface, addr4, mask4, secid);
 		if (audit_buf != NULL)
-			netlbl_unlabel_audit_addr4(audit_buf,
-						   dev_name,
-						   addr4->s_addr,
-						   mask4->s_addr);
+			netlbl_af4list_audit_addr(audit_buf, 1,
+						  dev_name,
+						  addr4->s_addr,
+						  mask4->s_addr);
 		break;
 	}
 #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
@@ -672,9 +515,9 @@
 		mask6 = (struct in6_addr *)mask;
 		ret_val = netlbl_unlhsh_add_addr6(iface, addr6, mask6, secid);
 		if (audit_buf != NULL)
-			netlbl_unlabel_audit_addr6(audit_buf,
-						   dev_name,
-						   addr6, mask6);
+			netlbl_af6list_audit_addr(audit_buf, 1,
+						  dev_name,
+						  addr6, mask6);
 		break;
 	}
 #endif /* IPv6 */
@@ -719,35 +562,34 @@
 				      const struct in_addr *mask,
 				      struct netlbl_audit *audit_info)
 {
-	int ret_val = -ENOENT;
+	int ret_val = 0;
+	struct netlbl_af4list *list_entry;
 	struct netlbl_unlhsh_addr4 *entry;
-	struct audit_buffer *audit_buf = NULL;
+	struct audit_buffer *audit_buf;
 	struct net_device *dev;
-	char *secctx = NULL;
+	char *secctx;
 	u32 secctx_len;
 
 	spin_lock(&netlbl_unlhsh_lock);
-	entry = netlbl_unlhsh_search_addr4(addr->s_addr, iface);
-	if (entry != NULL &&
-	    entry->addr == addr->s_addr && entry->mask == mask->s_addr) {
-		entry->valid = 0;
-		list_del_rcu(&entry->list);
-		ret_val = 0;
-	}
+	list_entry = netlbl_af4list_remove(addr->s_addr, mask->s_addr,
+					   &iface->addr4_list);
 	spin_unlock(&netlbl_unlhsh_lock);
+	if (list_entry == NULL)
+		ret_val = -ENOENT;
+	entry = netlbl_unlhsh_addr4_entry(list_entry);
 
 	audit_buf = netlbl_audit_start_common(AUDIT_MAC_UNLBL_STCDEL,
 					      audit_info);
 	if (audit_buf != NULL) {
 		dev = dev_get_by_index(net, iface->ifindex);
-		netlbl_unlabel_audit_addr4(audit_buf,
-					   (dev != NULL ? dev->name : NULL),
-					   entry->addr, entry->mask);
+		netlbl_af4list_audit_addr(audit_buf, 1,
+					  (dev != NULL ? dev->name : NULL),
+					  addr->s_addr, mask->s_addr);
 		if (dev != NULL)
 			dev_put(dev);
-		if (security_secid_to_secctx(entry->secid,
-					     &secctx,
-					     &secctx_len) == 0) {
+		if (entry && security_secid_to_secctx(entry->secid,
+						      &secctx,
+						      &secctx_len) == 0) {
 			audit_log_format(audit_buf, " sec_obj=%s", secctx);
 			security_release_secctx(secctx, secctx_len);
 		}
@@ -781,36 +623,33 @@
 				      const struct in6_addr *mask,
 				      struct netlbl_audit *audit_info)
 {
-	int ret_val = -ENOENT;
+	int ret_val = 0;
+	struct netlbl_af6list *list_entry;
 	struct netlbl_unlhsh_addr6 *entry;
-	struct audit_buffer *audit_buf = NULL;
+	struct audit_buffer *audit_buf;
 	struct net_device *dev;
-	char *secctx = NULL;
+	char *secctx;
 	u32 secctx_len;
 
 	spin_lock(&netlbl_unlhsh_lock);
-	entry = netlbl_unlhsh_search_addr6(addr, iface);
-	if (entry != NULL &&
-	    (ipv6_addr_equal(&entry->addr, addr) &&
-	     ipv6_addr_equal(&entry->mask, mask))) {
-		entry->valid = 0;
-		list_del_rcu(&entry->list);
-		ret_val = 0;
-	}
+	list_entry = netlbl_af6list_remove(addr, mask, &iface->addr6_list);
 	spin_unlock(&netlbl_unlhsh_lock);
+	if (list_entry == NULL)
+		ret_val = -ENOENT;
+	entry = netlbl_unlhsh_addr6_entry(list_entry);
 
 	audit_buf = netlbl_audit_start_common(AUDIT_MAC_UNLBL_STCDEL,
 					      audit_info);
 	if (audit_buf != NULL) {
 		dev = dev_get_by_index(net, iface->ifindex);
-		netlbl_unlabel_audit_addr6(audit_buf,
-					   (dev != NULL ? dev->name : NULL),
-					   addr, mask);
+		netlbl_af6list_audit_addr(audit_buf, 1,
+					  (dev != NULL ? dev->name : NULL),
+					  addr, mask);
 		if (dev != NULL)
 			dev_put(dev);
-		if (security_secid_to_secctx(entry->secid,
-					     &secctx,
-					     &secctx_len) == 0) {
+		if (entry && security_secid_to_secctx(entry->secid,
+						      &secctx,
+						      &secctx_len) == 0) {
 			audit_log_format(audit_buf, " sec_obj=%s", secctx);
 			security_release_secctx(secctx, secctx_len);
 		}
@@ -836,16 +675,18 @@
  */
 static void netlbl_unlhsh_condremove_iface(struct netlbl_unlhsh_iface *iface)
 {
-	struct netlbl_unlhsh_addr4 *iter4;
-	struct netlbl_unlhsh_addr6 *iter6;
+	struct netlbl_af4list *iter4;
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+	struct netlbl_af6list *iter6;
+#endif /* IPv6 */
 
 	spin_lock(&netlbl_unlhsh_lock);
-	list_for_each_entry_rcu(iter4, &iface->addr4_list, list)
-		if (iter4->valid)
-			goto unlhsh_condremove_failure;
-	list_for_each_entry_rcu(iter6, &iface->addr6_list, list)
-		if (iter6->valid)
-			goto unlhsh_condremove_failure;
+	netlbl_af4list_foreach_rcu(iter4, &iface->addr4_list)
+		goto unlhsh_condremove_failure;
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+	netlbl_af6list_foreach_rcu(iter6, &iface->addr6_list)
+		goto unlhsh_condremove_failure;
+#endif /* IPv6 */
 	iface->valid = 0;
 	if (iface->ifindex > 0)
 		list_del_rcu(&iface->list);
@@ -1349,7 +1190,7 @@
 	if (addr4) {
 		struct in_addr addr_struct;
 
-		addr_struct.s_addr = addr4->addr;
+		addr_struct.s_addr = addr4->list.addr;
 		ret_val = nla_put(cb_arg->skb,
 				  NLBL_UNLABEL_A_IPV4ADDR,
 				  sizeof(struct in_addr),
@@ -1357,7 +1198,7 @@
 		if (ret_val != 0)
 			goto list_cb_failure;
 
-		addr_struct.s_addr = addr4->mask;
+		addr_struct.s_addr = addr4->list.mask;
 		ret_val = nla_put(cb_arg->skb,
 				  NLBL_UNLABEL_A_IPV4MASK,
 				  sizeof(struct in_addr),
@@ -1370,14 +1211,14 @@
 		ret_val = nla_put(cb_arg->skb,
 				  NLBL_UNLABEL_A_IPV6ADDR,
 				  sizeof(struct in6_addr),
-				  &addr6->addr);
+				  &addr6->list.addr);
 		if (ret_val != 0)
 			goto list_cb_failure;
 
 		ret_val = nla_put(cb_arg->skb,
 				  NLBL_UNLABEL_A_IPV6MASK,
 				  sizeof(struct in6_addr),
-				  &addr6->mask);
+				  &addr6->list.mask);
 		if (ret_val != 0)
 			goto list_cb_failure;
 
@@ -1425,8 +1266,11 @@
 	u32 iter_bkt;
 	u32 iter_chain = 0, iter_addr4 = 0, iter_addr6 = 0;
 	struct netlbl_unlhsh_iface *iface;
-	struct netlbl_unlhsh_addr4 *addr4;
-	struct netlbl_unlhsh_addr6 *addr6;
+	struct list_head *iter_list;
+	struct netlbl_af4list *addr4;
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+	struct netlbl_af6list *addr6;
+#endif
 
 	cb_arg.nl_cb = cb;
 	cb_arg.skb = skb;
@@ -1436,44 +1280,43 @@
 	for (iter_bkt = skip_bkt;
 	     iter_bkt < rcu_dereference(netlbl_unlhsh)->size;
 	     iter_bkt++, iter_chain = 0, iter_addr4 = 0, iter_addr6 = 0) {
-		list_for_each_entry_rcu(iface,
-			        &rcu_dereference(netlbl_unlhsh)->tbl[iter_bkt],
-				list) {
+		iter_list = &rcu_dereference(netlbl_unlhsh)->tbl[iter_bkt];
+		list_for_each_entry_rcu(iface, iter_list, list) {
 			if (!iface->valid ||
 			    iter_chain++ < skip_chain)
 				continue;
-			list_for_each_entry_rcu(addr4,
-						&iface->addr4_list,
-						list) {
-				if (!addr4->valid || iter_addr4++ < skip_addr4)
+			netlbl_af4list_foreach_rcu(addr4,
+						   &iface->addr4_list) {
+				if (iter_addr4++ < skip_addr4)
 					continue;
 				if (netlbl_unlabel_staticlist_gen(
-					             NLBL_UNLABEL_C_STATICLIST,
-						     iface,
-						     addr4,
-						     NULL,
-						     &cb_arg) < 0) {
+					      NLBL_UNLABEL_C_STATICLIST,
+					      iface,
+					      netlbl_unlhsh_addr4_entry(addr4),
+					      NULL,
+					      &cb_arg) < 0) {
 					iter_addr4--;
 					iter_chain--;
 					goto unlabel_staticlist_return;
 				}
 			}
-			list_for_each_entry_rcu(addr6,
-						&iface->addr6_list,
-						list) {
-				if (!addr6->valid || iter_addr6++ < skip_addr6)
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+			netlbl_af6list_foreach_rcu(addr6,
+						   &iface->addr6_list) {
+				if (iter_addr6++ < skip_addr6)
 					continue;
 				if (netlbl_unlabel_staticlist_gen(
-						     NLBL_UNLABEL_C_STATICLIST,
-						     iface,
-						     NULL,
-						     addr6,
-						     &cb_arg) < 0) {
+					      NLBL_UNLABEL_C_STATICLIST,
+					      iface,
+					      NULL,
+					      netlbl_unlhsh_addr6_entry(addr6),
+					      &cb_arg) < 0) {
 					iter_addr6--;
 					iter_chain--;
 					goto unlabel_staticlist_return;
 				}
 			}
+#endif /* IPv6 */
 		}
 	}
 
@@ -1504,9 +1347,12 @@
 	struct netlbl_unlhsh_iface *iface;
 	u32 skip_addr4 = cb->args[0];
 	u32 skip_addr6 = cb->args[1];
-	u32 iter_addr4 = 0, iter_addr6 = 0;
-	struct netlbl_unlhsh_addr4 *addr4;
-	struct netlbl_unlhsh_addr6 *addr6;
+	u32 iter_addr4 = 0;
+	struct netlbl_af4list *addr4;
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+	u32 iter_addr6 = 0;
+	struct netlbl_af6list *addr6;
+#endif
 
 	cb_arg.nl_cb = cb;
 	cb_arg.skb = skb;
@@ -1517,30 +1363,32 @@
 	if (iface == NULL || !iface->valid)
 		goto unlabel_staticlistdef_return;
 
-	list_for_each_entry_rcu(addr4, &iface->addr4_list, list) {
-		if (!addr4->valid || iter_addr4++ < skip_addr4)
+	netlbl_af4list_foreach_rcu(addr4, &iface->addr4_list) {
+		if (iter_addr4++ < skip_addr4)
 			continue;
 		if (netlbl_unlabel_staticlist_gen(NLBL_UNLABEL_C_STATICLISTDEF,
-					   iface,
-					   addr4,
-					   NULL,
-					   &cb_arg) < 0) {
+					      iface,
+					      netlbl_unlhsh_addr4_entry(addr4),
+					      NULL,
+					      &cb_arg) < 0) {
 			iter_addr4--;
 			goto unlabel_staticlistdef_return;
 		}
 	}
-	list_for_each_entry_rcu(addr6, &iface->addr6_list, list) {
-		if (!addr6->valid || iter_addr6++ < skip_addr6)
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+	netlbl_af6list_foreach_rcu(addr6, &iface->addr6_list) {
+		if (iter_addr6++ < skip_addr6)
 			continue;
 		if (netlbl_unlabel_staticlist_gen(NLBL_UNLABEL_C_STATICLISTDEF,
-					   iface,
-					   NULL,
-					   addr6,
-					   &cb_arg) < 0) {
+					      iface,
+					      NULL,
+					      netlbl_unlhsh_addr6_entry(addr6),
+					      &cb_arg) < 0) {
 			iter_addr6--;
 			goto unlabel_staticlistdef_return;
 		}
 	}
+#endif /* IPv6 */
 
 unlabel_staticlistdef_return:
 	rcu_read_unlock();
@@ -1718,25 +1566,27 @@
 	switch (family) {
 	case PF_INET: {
 		struct iphdr *hdr4;
-		struct netlbl_unlhsh_addr4 *addr4;
+		struct netlbl_af4list *addr4;
 
 		hdr4 = ip_hdr(skb);
-		addr4 = netlbl_unlhsh_search_addr4(hdr4->saddr, iface);
+		addr4 = netlbl_af4list_search(hdr4->saddr,
+					      &iface->addr4_list);
 		if (addr4 == NULL)
 			goto unlabel_getattr_nolabel;
-		secattr->attr.secid = addr4->secid;
+		secattr->attr.secid = netlbl_unlhsh_addr4_entry(addr4)->secid;
 		break;
 	}
 #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
 	case PF_INET6: {
 		struct ipv6hdr *hdr6;
-		struct netlbl_unlhsh_addr6 *addr6;
+		struct netlbl_af6list *addr6;
 
 		hdr6 = ipv6_hdr(skb);
-		addr6 = netlbl_unlhsh_search_addr6(&hdr6->saddr, iface);
+		addr6 = netlbl_af6list_search(&hdr6->saddr,
+					      &iface->addr6_list);
 		if (addr6 == NULL)
 			goto unlabel_getattr_nolabel;
-		secattr->attr.secid = addr6->secid;
+		secattr->attr.secid = netlbl_unlhsh_addr6_entry(addr6)->secid;
 		break;
 	}
 #endif /* IPv6 */
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
index b0eacc0..2fd8afa 100644
--- a/net/netlink/af_netlink.c
+++ b/net/netlink/af_netlink.c
@@ -1,7 +1,7 @@
 /*
  * NETLINK      Kernel-user communication protocol.
  *
- * 		Authors:	Alan Cox <alan@redhat.com>
+ * 		Authors:	Alan Cox <alan@lxorguk.ukuu.org.uk>
  * 				Alexey Kuznetsov <kuznet@ms2.inr.ac.ru>
  *
  *		This program is free software; you can redistribute it and/or
diff --git a/net/netrom/af_netrom.c b/net/netrom/af_netrom.c
index 532e4fa..9f1ea4a 100644
--- a/net/netrom/af_netrom.c
+++ b/net/netrom/af_netrom.c
@@ -525,6 +525,7 @@
 	if (sk == NULL) return 0;
 
 	sock_hold(sk);
+	sock_orphan(sk);
 	lock_sock(sk);
 	nr = nr_sk(sk);
 
@@ -548,7 +549,6 @@
 		sk->sk_state    = TCP_CLOSE;
 		sk->sk_shutdown |= SEND_SHUTDOWN;
 		sk->sk_state_change(sk);
-		sock_orphan(sk);
 		sock_set_flag(sk, SOCK_DESTROY);
 		break;
 
diff --git a/net/phonet/Kconfig b/net/phonet/Kconfig
new file mode 100644
index 0000000..51a5669
--- /dev/null
+++ b/net/phonet/Kconfig
@@ -0,0 +1,16 @@
+#
+# Phonet protocol
+#
+
+config PHONET
+	tristate "Phonet protocols family"
+	help
+	  The Phone Network protocol (PhoNet) is a packet-oriented
+	  communication protocol developped by Nokia for use with its modems.
+
+	  This is required for Maemo to use cellular data connectivity (if
+	  supported). It can also be used to control Nokia phones
+	  from a Linux computer, although AT commands may be easier to use.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called phonet. If unsure, say N.
diff --git a/net/phonet/Makefile b/net/phonet/Makefile
new file mode 100644
index 0000000..d62bbba
--- /dev/null
+++ b/net/phonet/Makefile
@@ -0,0 +1,11 @@
+obj-$(CONFIG_PHONET) += phonet.o pn_pep.o
+
+phonet-objs := \
+	pn_dev.o \
+	pn_netlink.o \
+	socket.o \
+	datagram.o \
+	sysctl.o \
+	af_phonet.o
+
+pn_pep-objs := pep.o pep-gprs.o
diff --git a/net/phonet/af_phonet.c b/net/phonet/af_phonet.c
new file mode 100644
index 0000000..9e9c6fc
--- /dev/null
+++ b/net/phonet/af_phonet.c
@@ -0,0 +1,477 @@
+/*
+ * File: af_phonet.c
+ *
+ * Phonet protocols family
+ *
+ * Copyright (C) 2008 Nokia Corporation.
+ *
+ * Contact: Remi Denis-Courmont <remi.denis-courmont@nokia.com>
+ * Original author: Sakari Ailus <sakari.ailus@nokia.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.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <asm/unaligned.h>
+#include <net/sock.h>
+
+#include <linux/if_phonet.h>
+#include <linux/phonet.h>
+#include <net/phonet/phonet.h>
+#include <net/phonet/pn_dev.h>
+
+static struct net_proto_family phonet_proto_family;
+static struct phonet_protocol *phonet_proto_get(int protocol);
+static inline void phonet_proto_put(struct phonet_protocol *pp);
+
+/* protocol family functions */
+
+static int pn_socket_create(struct net *net, struct socket *sock, int protocol)
+{
+	struct sock *sk;
+	struct pn_sock *pn;
+	struct phonet_protocol *pnp;
+	int err;
+
+	if (net != &init_net)
+		return -EAFNOSUPPORT;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+
+	if (protocol == 0) {
+		/* Default protocol selection */
+		switch (sock->type) {
+		case SOCK_DGRAM:
+			protocol = PN_PROTO_PHONET;
+			break;
+		case SOCK_SEQPACKET:
+			protocol = PN_PROTO_PIPE;
+			break;
+		default:
+			return -EPROTONOSUPPORT;
+		}
+	}
+
+	pnp = phonet_proto_get(protocol);
+#ifdef CONFIG_KMOD
+	if (pnp == NULL &&
+	    request_module("net-pf-%d-proto-%d", PF_PHONET, protocol) == 0)
+		pnp = phonet_proto_get(protocol);
+#endif
+	if (pnp == NULL)
+		return -EPROTONOSUPPORT;
+	if (sock->type != pnp->sock_type) {
+		err = -EPROTONOSUPPORT;
+		goto out;
+	}
+
+	sk = sk_alloc(net, PF_PHONET, GFP_KERNEL, pnp->prot);
+	if (sk == NULL) {
+		err = -ENOMEM;
+		goto out;
+	}
+
+	sock_init_data(sock, sk);
+	sock->state = SS_UNCONNECTED;
+	sock->ops = pnp->ops;
+	sk->sk_backlog_rcv = sk->sk_prot->backlog_rcv;
+	sk->sk_protocol = protocol;
+	pn = pn_sk(sk);
+	pn->sobject = 0;
+	pn->resource = 0;
+	sk->sk_prot->init(sk);
+	err = 0;
+
+out:
+	phonet_proto_put(pnp);
+	return err;
+}
+
+static struct net_proto_family phonet_proto_family = {
+	.family = PF_PHONET,
+	.create = pn_socket_create,
+	.owner = THIS_MODULE,
+};
+
+/* Phonet device header operations */
+static int pn_header_create(struct sk_buff *skb, struct net_device *dev,
+				unsigned short type, const void *daddr,
+				const void *saddr, unsigned len)
+{
+	u8 *media = skb_push(skb, 1);
+
+	if (type != ETH_P_PHONET)
+		return -1;
+
+	if (!saddr)
+		saddr = dev->dev_addr;
+	*media = *(const u8 *)saddr;
+	return 1;
+}
+
+static int pn_header_parse(const struct sk_buff *skb, unsigned char *haddr)
+{
+	const u8 *media = skb_mac_header(skb);
+	*haddr = *media;
+	return 1;
+}
+
+struct header_ops phonet_header_ops = {
+	.create = pn_header_create,
+	.parse = pn_header_parse,
+};
+EXPORT_SYMBOL(phonet_header_ops);
+
+/*
+ * Prepends an ISI header and sends a datagram.
+ */
+static int pn_send(struct sk_buff *skb, struct net_device *dev,
+			u16 dst, u16 src, u8 res, u8 irq)
+{
+	struct phonethdr *ph;
+	int err;
+
+	if (skb->len + 2 > 0xffff) {
+		/* Phonet length field would overflow */
+		err = -EMSGSIZE;
+		goto drop;
+	}
+
+	skb_reset_transport_header(skb);
+	WARN_ON(skb_headroom(skb) & 1); /* HW assumes word alignment */
+	skb_push(skb, sizeof(struct phonethdr));
+	skb_reset_network_header(skb);
+	ph = pn_hdr(skb);
+	ph->pn_rdev = pn_dev(dst);
+	ph->pn_sdev = pn_dev(src);
+	ph->pn_res = res;
+	ph->pn_length = __cpu_to_be16(skb->len + 2 - sizeof(*ph));
+	ph->pn_robj = pn_obj(dst);
+	ph->pn_sobj = pn_obj(src);
+
+	skb->protocol = htons(ETH_P_PHONET);
+	skb->priority = 0;
+	skb->dev = dev;
+
+	if (pn_addr(src) == pn_addr(dst)) {
+		skb_reset_mac_header(skb);
+		skb->pkt_type = PACKET_LOOPBACK;
+		skb_orphan(skb);
+		if (irq)
+			netif_rx(skb);
+		else
+			netif_rx_ni(skb);
+		err = 0;
+	} else {
+		err = dev_hard_header(skb, dev, ntohs(skb->protocol),
+					NULL, NULL, skb->len);
+		if (err < 0) {
+			err = -EHOSTUNREACH;
+			goto drop;
+		}
+		err = dev_queue_xmit(skb);
+	}
+
+	return err;
+drop:
+	kfree_skb(skb);
+	return err;
+}
+
+static int pn_raw_send(const void *data, int len, struct net_device *dev,
+			u16 dst, u16 src, u8 res)
+{
+	struct sk_buff *skb = alloc_skb(MAX_PHONET_HEADER + len, GFP_ATOMIC);
+	if (skb == NULL)
+		return -ENOMEM;
+
+	skb_reserve(skb, MAX_PHONET_HEADER);
+	__skb_put(skb, len);
+	skb_copy_to_linear_data(skb, data, len);
+	return pn_send(skb, dev, dst, src, res, 1);
+}
+
+/*
+ * Create a Phonet header for the skb and send it out. Returns
+ * non-zero error code if failed. The skb is freed then.
+ */
+int pn_skb_send(struct sock *sk, struct sk_buff *skb,
+		const struct sockaddr_pn *target)
+{
+	struct net_device *dev;
+	struct pn_sock *pn = pn_sk(sk);
+	int err;
+	u16 src;
+	u8 daddr = pn_sockaddr_get_addr(target), saddr = PN_NO_ADDR;
+
+	err = -EHOSTUNREACH;
+	if (sk->sk_bound_dev_if)
+		dev = dev_get_by_index(sock_net(sk), sk->sk_bound_dev_if);
+	else
+		dev = phonet_device_get(sock_net(sk));
+	if (!dev || !(dev->flags & IFF_UP))
+		goto drop;
+
+	saddr = phonet_address_get(dev, daddr);
+	if (saddr == PN_NO_ADDR)
+		goto drop;
+
+	src = pn->sobject;
+	if (!pn_addr(src))
+		src = pn_object(saddr, pn_obj(src));
+
+	err = pn_send(skb, dev, pn_sockaddr_get_object(target),
+			src, pn_sockaddr_get_resource(target), 0);
+	dev_put(dev);
+	return err;
+
+drop:
+	kfree_skb(skb);
+	if (dev)
+		dev_put(dev);
+	return err;
+}
+EXPORT_SYMBOL(pn_skb_send);
+
+/* Do not send an error message in response to an error message */
+static inline int can_respond(struct sk_buff *skb)
+{
+	const struct phonethdr *ph;
+	const struct phonetmsg *pm;
+	u8 submsg_id;
+
+	if (!pskb_may_pull(skb, 3))
+		return 0;
+
+	ph = pn_hdr(skb);
+	if (phonet_address_get(skb->dev, ph->pn_rdev) != ph->pn_rdev)
+		return 0; /* we are not the destination */
+	if (ph->pn_res == PN_PREFIX && !pskb_may_pull(skb, 5))
+		return 0;
+
+	ph = pn_hdr(skb); /* re-acquires the pointer */
+	pm = pn_msg(skb);
+	if (pm->pn_msg_id != PN_COMMON_MESSAGE)
+		return 1;
+	submsg_id = (ph->pn_res == PN_PREFIX)
+		? pm->pn_e_submsg_id : pm->pn_submsg_id;
+	if (submsg_id != PN_COMM_ISA_ENTITY_NOT_REACHABLE_RESP &&
+		pm->pn_e_submsg_id != PN_COMM_SERVICE_NOT_IDENTIFIED_RESP)
+		return 1;
+	return 0;
+}
+
+static int send_obj_unreachable(struct sk_buff *rskb)
+{
+	const struct phonethdr *oph = pn_hdr(rskb);
+	const struct phonetmsg *opm = pn_msg(rskb);
+	struct phonetmsg resp;
+
+	memset(&resp, 0, sizeof(resp));
+	resp.pn_trans_id = opm->pn_trans_id;
+	resp.pn_msg_id = PN_COMMON_MESSAGE;
+	if (oph->pn_res == PN_PREFIX) {
+		resp.pn_e_res_id = opm->pn_e_res_id;
+		resp.pn_e_submsg_id = PN_COMM_ISA_ENTITY_NOT_REACHABLE_RESP;
+		resp.pn_e_orig_msg_id = opm->pn_msg_id;
+		resp.pn_e_status = 0;
+	} else {
+		resp.pn_submsg_id = PN_COMM_ISA_ENTITY_NOT_REACHABLE_RESP;
+		resp.pn_orig_msg_id = opm->pn_msg_id;
+		resp.pn_status = 0;
+	}
+	return pn_raw_send(&resp, sizeof(resp), rskb->dev,
+				pn_object(oph->pn_sdev, oph->pn_sobj),
+				pn_object(oph->pn_rdev, oph->pn_robj),
+				oph->pn_res);
+}
+
+static int send_reset_indications(struct sk_buff *rskb)
+{
+	struct phonethdr *oph = pn_hdr(rskb);
+	static const u8 data[4] = {
+		0x00 /* trans ID */, 0x10 /* subscribe msg */,
+		0x00 /* subscription count */, 0x00 /* dummy */
+	};
+
+	return pn_raw_send(data, sizeof(data), rskb->dev,
+				pn_object(oph->pn_sdev, 0x00),
+				pn_object(oph->pn_rdev, oph->pn_robj), 0x10);
+}
+
+
+/* packet type functions */
+
+/*
+ * Stuff received packets to associated sockets.
+ * On error, returns non-zero and releases the skb.
+ */
+static int phonet_rcv(struct sk_buff *skb, struct net_device *dev,
+			struct packet_type *pkttype,
+			struct net_device *orig_dev)
+{
+	struct phonethdr *ph;
+	struct sock *sk;
+	struct sockaddr_pn sa;
+	u16 len;
+
+	if (dev_net(dev) != &init_net)
+		goto out;
+
+	/* check we have at least a full Phonet header */
+	if (!pskb_pull(skb, sizeof(struct phonethdr)))
+		goto out;
+
+	/* check that the advertised length is correct */
+	ph = pn_hdr(skb);
+	len = get_unaligned_be16(&ph->pn_length);
+	if (len < 2)
+		goto out;
+	len -= 2;
+	if ((len > skb->len) || pskb_trim(skb, len))
+		goto out;
+	skb_reset_transport_header(skb);
+
+	pn_skb_get_dst_sockaddr(skb, &sa);
+	if (pn_sockaddr_get_addr(&sa) == 0)
+		goto out; /* currently, we cannot be device 0 */
+
+	sk = pn_find_sock_by_sa(&sa);
+	if (sk == NULL) {
+		if (can_respond(skb)) {
+			send_obj_unreachable(skb);
+			send_reset_indications(skb);
+		}
+		goto out;
+	}
+
+	/* Push data to the socket (or other sockets connected to it). */
+	return sk_receive_skb(sk, skb, 0);
+
+out:
+	kfree_skb(skb);
+	return NET_RX_DROP;
+}
+
+static struct packet_type phonet_packet_type = {
+	.type = __constant_htons(ETH_P_PHONET),
+	.dev = NULL,
+	.func = phonet_rcv,
+};
+
+/* Transport protocol registration */
+static struct phonet_protocol *proto_tab[PHONET_NPROTO] __read_mostly;
+static DEFINE_SPINLOCK(proto_tab_lock);
+
+int __init_or_module phonet_proto_register(int protocol,
+						struct phonet_protocol *pp)
+{
+	int err = 0;
+
+	if (protocol >= PHONET_NPROTO)
+		return -EINVAL;
+
+	err = proto_register(pp->prot, 1);
+	if (err)
+		return err;
+
+	spin_lock(&proto_tab_lock);
+	if (proto_tab[protocol])
+		err = -EBUSY;
+	else
+		proto_tab[protocol] = pp;
+	spin_unlock(&proto_tab_lock);
+
+	return err;
+}
+EXPORT_SYMBOL(phonet_proto_register);
+
+void phonet_proto_unregister(int protocol, struct phonet_protocol *pp)
+{
+	spin_lock(&proto_tab_lock);
+	BUG_ON(proto_tab[protocol] != pp);
+	proto_tab[protocol] = NULL;
+	spin_unlock(&proto_tab_lock);
+	proto_unregister(pp->prot);
+}
+EXPORT_SYMBOL(phonet_proto_unregister);
+
+static struct phonet_protocol *phonet_proto_get(int protocol)
+{
+	struct phonet_protocol *pp;
+
+	if (protocol >= PHONET_NPROTO)
+		return NULL;
+
+	spin_lock(&proto_tab_lock);
+	pp = proto_tab[protocol];
+	if (pp && !try_module_get(pp->prot->owner))
+		pp = NULL;
+	spin_unlock(&proto_tab_lock);
+
+	return pp;
+}
+
+static inline void phonet_proto_put(struct phonet_protocol *pp)
+{
+	module_put(pp->prot->owner);
+}
+
+/* Module registration */
+static int __init phonet_init(void)
+{
+	int err;
+
+	err = sock_register(&phonet_proto_family);
+	if (err) {
+		printk(KERN_ALERT
+			"phonet protocol family initialization failed\n");
+		return err;
+	}
+
+	phonet_device_init();
+	dev_add_pack(&phonet_packet_type);
+	phonet_netlink_register();
+	phonet_sysctl_init();
+
+	err = isi_register();
+	if (err)
+		goto err;
+	return 0;
+
+err:
+	phonet_sysctl_exit();
+	sock_unregister(PF_PHONET);
+	dev_remove_pack(&phonet_packet_type);
+	phonet_device_exit();
+	return err;
+}
+
+static void __exit phonet_exit(void)
+{
+	isi_unregister();
+	phonet_sysctl_exit();
+	sock_unregister(PF_PHONET);
+	dev_remove_pack(&phonet_packet_type);
+	phonet_device_exit();
+}
+
+module_init(phonet_init);
+module_exit(phonet_exit);
+MODULE_DESCRIPTION("Phonet protocol stack for Linux");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_NETPROTO(PF_PHONET);
diff --git a/net/phonet/datagram.c b/net/phonet/datagram.c
new file mode 100644
index 0000000..e087862
--- /dev/null
+++ b/net/phonet/datagram.c
@@ -0,0 +1,197 @@
+/*
+ * File: datagram.c
+ *
+ * Datagram (ISI) Phonet sockets
+ *
+ * Copyright (C) 2008 Nokia Corporation.
+ *
+ * Contact: Remi Denis-Courmont <remi.denis-courmont@nokia.com>
+ * Original author: Sakari Ailus <sakari.ailus@nokia.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.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/socket.h>
+#include <asm/ioctls.h>
+#include <net/sock.h>
+
+#include <linux/phonet.h>
+#include <net/phonet/phonet.h>
+
+static int pn_backlog_rcv(struct sock *sk, struct sk_buff *skb);
+
+/* associated socket ceases to exist */
+static void pn_sock_close(struct sock *sk, long timeout)
+{
+	sk_common_release(sk);
+}
+
+static int pn_ioctl(struct sock *sk, int cmd, unsigned long arg)
+{
+	struct sk_buff *skb;
+	int answ;
+
+	switch (cmd) {
+	case SIOCINQ:
+		lock_sock(sk);
+		skb = skb_peek(&sk->sk_receive_queue);
+		answ = skb ? skb->len : 0;
+		release_sock(sk);
+		return put_user(answ, (int __user *)arg);
+	}
+
+	return -ENOIOCTLCMD;
+}
+
+/* Destroy socket. All references are gone. */
+static void pn_destruct(struct sock *sk)
+{
+	skb_queue_purge(&sk->sk_receive_queue);
+}
+
+static int pn_init(struct sock *sk)
+{
+	sk->sk_destruct = pn_destruct;
+	return 0;
+}
+
+static int pn_sendmsg(struct kiocb *iocb, struct sock *sk,
+			struct msghdr *msg, size_t len)
+{
+	struct sockaddr_pn *target;
+	struct sk_buff *skb;
+	int err;
+
+	if (msg->msg_flags & MSG_OOB)
+		return -EOPNOTSUPP;
+
+	if (msg->msg_name == NULL)
+		return -EDESTADDRREQ;
+
+	if (msg->msg_namelen < sizeof(struct sockaddr_pn))
+		return -EINVAL;
+
+	target = (struct sockaddr_pn *)msg->msg_name;
+	if (target->spn_family != AF_PHONET)
+		return -EAFNOSUPPORT;
+
+	skb = sock_alloc_send_skb(sk, MAX_PHONET_HEADER + len,
+					msg->msg_flags & MSG_DONTWAIT, &err);
+	if (skb == NULL)
+		return err;
+	skb_reserve(skb, MAX_PHONET_HEADER);
+
+	err = memcpy_fromiovec((void *)skb_put(skb, len), msg->msg_iov, len);
+	if (err < 0) {
+		kfree_skb(skb);
+		return err;
+	}
+
+	/*
+	 * Fill in the Phonet header and
+	 * finally pass the packet forwards.
+	 */
+	err = pn_skb_send(sk, skb, target);
+
+	/* If ok, return len. */
+	return (err >= 0) ? len : err;
+}
+
+static int pn_recvmsg(struct kiocb *iocb, struct sock *sk,
+			struct msghdr *msg, size_t len, int noblock,
+			int flags, int *addr_len)
+{
+	struct sk_buff *skb = NULL;
+	struct sockaddr_pn sa;
+	int rval = -EOPNOTSUPP;
+	int copylen;
+
+	if (flags & MSG_OOB)
+		goto out_nofree;
+
+	if (addr_len)
+		*addr_len = sizeof(sa);
+
+	skb = skb_recv_datagram(sk, flags, noblock, &rval);
+	if (skb == NULL)
+		goto out_nofree;
+
+	pn_skb_get_src_sockaddr(skb, &sa);
+
+	copylen = skb->len;
+	if (len < copylen) {
+		msg->msg_flags |= MSG_TRUNC;
+		copylen = len;
+	}
+
+	rval = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copylen);
+	if (rval) {
+		rval = -EFAULT;
+		goto out;
+	}
+
+	rval = (flags & MSG_TRUNC) ? skb->len : copylen;
+
+	if (msg->msg_name != NULL)
+		memcpy(msg->msg_name, &sa, sizeof(struct sockaddr_pn));
+
+out:
+	skb_free_datagram(sk, skb);
+
+out_nofree:
+	return rval;
+}
+
+/* Queue an skb for a sock. */
+static int pn_backlog_rcv(struct sock *sk, struct sk_buff *skb)
+{
+	int err = sock_queue_rcv_skb(sk, skb);
+	if (err < 0)
+		kfree_skb(skb);
+	return err ? NET_RX_DROP : NET_RX_SUCCESS;
+}
+
+/* Module registration */
+static struct proto pn_proto = {
+	.close		= pn_sock_close,
+	.ioctl		= pn_ioctl,
+	.init		= pn_init,
+	.sendmsg	= pn_sendmsg,
+	.recvmsg	= pn_recvmsg,
+	.backlog_rcv	= pn_backlog_rcv,
+	.hash		= pn_sock_hash,
+	.unhash		= pn_sock_unhash,
+	.get_port	= pn_sock_get_port,
+	.obj_size	= sizeof(struct pn_sock),
+	.owner		= THIS_MODULE,
+	.name		= "PHONET",
+};
+
+static struct phonet_protocol pn_dgram_proto = {
+	.ops		= &phonet_dgram_ops,
+	.prot		= &pn_proto,
+	.sock_type	= SOCK_DGRAM,
+};
+
+int __init isi_register(void)
+{
+	return phonet_proto_register(PN_PROTO_PHONET, &pn_dgram_proto);
+}
+
+void __exit isi_unregister(void)
+{
+	phonet_proto_unregister(PN_PROTO_PHONET, &pn_dgram_proto);
+}
diff --git a/net/phonet/pep-gprs.c b/net/phonet/pep-gprs.c
new file mode 100644
index 0000000..9978afb
--- /dev/null
+++ b/net/phonet/pep-gprs.c
@@ -0,0 +1,347 @@
+/*
+ * File: pep-gprs.c
+ *
+ * GPRS over Phonet pipe end point socket
+ *
+ * Copyright (C) 2008 Nokia Corporation.
+ *
+ * Author: Rémi Denis-Courmont <remi.denis-courmont@nokia.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.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/netdevice.h>
+#include <linux/if_ether.h>
+#include <linux/if_arp.h>
+#include <net/sock.h>
+
+#include <linux/if_phonet.h>
+#include <net/tcp_states.h>
+#include <net/phonet/gprs.h>
+
+#define GPRS_DEFAULT_MTU 1400
+
+struct gprs_dev {
+	struct sock		*sk;
+	void			(*old_state_change)(struct sock *);
+	void			(*old_data_ready)(struct sock *, int);
+	void			(*old_write_space)(struct sock *);
+
+	struct net_device	*net;
+	struct net_device_stats	stats;
+
+	struct sk_buff_head	tx_queue;
+	struct work_struct	tx_work;
+	spinlock_t		tx_lock;
+	unsigned		tx_max;
+};
+
+static int gprs_type_trans(struct sk_buff *skb)
+{
+	const u8 *pvfc;
+	u8 buf;
+
+	pvfc = skb_header_pointer(skb, 0, 1, &buf);
+	if (!pvfc)
+		return 0;
+	/* Look at IP version field */
+	switch (*pvfc >> 4) {
+	case 4:
+		return htons(ETH_P_IP);
+	case 6:
+		return htons(ETH_P_IPV6);
+	}
+	return 0;
+}
+
+/*
+ * Socket callbacks
+ */
+
+static void gprs_state_change(struct sock *sk)
+{
+	struct gprs_dev *dev = sk->sk_user_data;
+
+	if (sk->sk_state == TCP_CLOSE_WAIT) {
+		netif_stop_queue(dev->net);
+		netif_carrier_off(dev->net);
+	}
+}
+
+static int gprs_recv(struct gprs_dev *dev, struct sk_buff *skb)
+{
+	int err = 0;
+	u16 protocol = gprs_type_trans(skb);
+
+	if (!protocol) {
+		err = -EINVAL;
+		goto drop;
+	}
+
+	if (likely(skb_headroom(skb) & 3)) {
+		struct sk_buff *rskb, *fs;
+		int flen = 0;
+
+		/* Phonet Pipe data header is misaligned (3 bytes),
+		 * so wrap the IP packet as a single fragment of an head-less
+		 * socket buffer. The network stack will pull what it needs,
+		 * but at least, the whole IP payload is not memcpy'd. */
+		rskb = netdev_alloc_skb(dev->net, 0);
+		if (!rskb) {
+			err = -ENOBUFS;
+			goto drop;
+		}
+		skb_shinfo(rskb)->frag_list = skb;
+		rskb->len += skb->len;
+		rskb->data_len += rskb->len;
+		rskb->truesize += rskb->len;
+
+		/* Avoid nested fragments */
+		for (fs = skb_shinfo(skb)->frag_list; fs; fs = fs->next)
+			flen += fs->len;
+		skb->next = skb_shinfo(skb)->frag_list;
+		skb_shinfo(skb)->frag_list = NULL;
+		skb->len -= flen;
+		skb->data_len -= flen;
+		skb->truesize -= flen;
+
+		skb = rskb;
+	}
+
+	skb->protocol = protocol;
+	skb_reset_mac_header(skb);
+	skb->dev = dev->net;
+
+	if (likely(dev->net->flags & IFF_UP)) {
+		dev->stats.rx_packets++;
+		dev->stats.rx_bytes += skb->len;
+		netif_rx(skb);
+		skb = NULL;
+	} else
+		err = -ENODEV;
+
+drop:
+	if (skb) {
+		dev_kfree_skb(skb);
+		dev->stats.rx_dropped++;
+	}
+	return err;
+}
+
+static void gprs_data_ready(struct sock *sk, int len)
+{
+	struct gprs_dev *dev = sk->sk_user_data;
+	struct sk_buff *skb;
+
+	while ((skb = pep_read(sk)) != NULL) {
+		skb_orphan(skb);
+		gprs_recv(dev, skb);
+	}
+}
+
+static void gprs_write_space(struct sock *sk)
+{
+	struct gprs_dev *dev = sk->sk_user_data;
+	unsigned credits = pep_writeable(sk);
+
+	spin_lock_bh(&dev->tx_lock);
+	dev->tx_max = credits;
+	if (credits > skb_queue_len(&dev->tx_queue))
+		netif_wake_queue(dev->net);
+	spin_unlock_bh(&dev->tx_lock);
+}
+
+/*
+ * Network device callbacks
+ */
+
+static int gprs_xmit(struct sk_buff *skb, struct net_device *net)
+{
+	struct gprs_dev *dev = netdev_priv(net);
+
+	switch (skb->protocol) {
+	case  htons(ETH_P_IP):
+	case  htons(ETH_P_IPV6):
+		break;
+	default:
+		dev_kfree_skb(skb);
+		return 0;
+	}
+
+	spin_lock(&dev->tx_lock);
+	if (likely(skb_queue_len(&dev->tx_queue) < dev->tx_max)) {
+		skb_queue_tail(&dev->tx_queue, skb);
+		skb = NULL;
+	}
+	if (skb_queue_len(&dev->tx_queue) >= dev->tx_max)
+		netif_stop_queue(net);
+	spin_unlock(&dev->tx_lock);
+
+	schedule_work(&dev->tx_work);
+	if (unlikely(skb))
+		dev_kfree_skb(skb);
+	return 0;
+}
+
+static void gprs_tx(struct work_struct *work)
+{
+	struct gprs_dev *dev = container_of(work, struct gprs_dev, tx_work);
+	struct sock *sk = dev->sk;
+	struct sk_buff *skb;
+
+	while ((skb = skb_dequeue(&dev->tx_queue)) != NULL) {
+		int err;
+
+		dev->stats.tx_bytes += skb->len;
+		dev->stats.tx_packets++;
+
+		skb_orphan(skb);
+		skb_set_owner_w(skb, sk);
+
+		lock_sock(sk);
+		err = pep_write(sk, skb);
+		if (err) {
+			LIMIT_NETDEBUG(KERN_WARNING"%s: TX error (%d)\n",
+					dev->net->name, err);
+			dev->stats.tx_aborted_errors++;
+			dev->stats.tx_errors++;
+		}
+		release_sock(sk);
+	}
+
+	lock_sock(sk);
+	gprs_write_space(sk);
+	release_sock(sk);
+}
+
+static int gprs_set_mtu(struct net_device *net, int new_mtu)
+{
+	if ((new_mtu < 576) || (new_mtu > (PHONET_MAX_MTU - 11)))
+		return -EINVAL;
+
+	net->mtu = new_mtu;
+	return 0;
+}
+
+static struct net_device_stats *gprs_get_stats(struct net_device *net)
+{
+	struct gprs_dev *dev = netdev_priv(net);
+
+	return &dev->stats;
+}
+
+static void gprs_setup(struct net_device *net)
+{
+	net->features		= NETIF_F_FRAGLIST;
+	net->type		= ARPHRD_NONE;
+	net->flags		= IFF_POINTOPOINT | IFF_NOARP;
+	net->mtu		= GPRS_DEFAULT_MTU;
+	net->hard_header_len	= 0;
+	net->addr_len		= 0;
+	net->tx_queue_len	= 10;
+
+	net->destructor		= free_netdev;
+	net->hard_start_xmit	= gprs_xmit; /* mandatory */
+	net->change_mtu		= gprs_set_mtu;
+	net->get_stats		= gprs_get_stats;
+}
+
+/*
+ * External interface
+ */
+
+/*
+ * Attach a GPRS interface to a datagram socket.
+ * Returns the interface index on success, negative error code on error.
+ */
+int gprs_attach(struct sock *sk)
+{
+	static const char ifname[] = "gprs%d";
+	struct gprs_dev *dev;
+	struct net_device *net;
+	int err;
+
+	if (unlikely(sk->sk_type == SOCK_STREAM))
+		return -EINVAL; /* need packet boundaries */
+
+	/* Create net device */
+	net = alloc_netdev(sizeof(*dev), ifname, gprs_setup);
+	if (!net)
+		return -ENOMEM;
+	dev = netdev_priv(net);
+	dev->net = net;
+	dev->tx_max = 0;
+	spin_lock_init(&dev->tx_lock);
+	skb_queue_head_init(&dev->tx_queue);
+	INIT_WORK(&dev->tx_work, gprs_tx);
+
+	netif_stop_queue(net);
+	err = register_netdev(net);
+	if (err) {
+		free_netdev(net);
+		return err;
+	}
+
+	lock_sock(sk);
+	if (unlikely(sk->sk_user_data)) {
+		err = -EBUSY;
+		goto out_rel;
+	}
+	if (unlikely((1 << sk->sk_state & (TCPF_CLOSE|TCPF_LISTEN)) ||
+			sock_flag(sk, SOCK_DEAD))) {
+		err = -EINVAL;
+		goto out_rel;
+	}
+	sk->sk_user_data	= dev;
+	dev->old_state_change	= sk->sk_state_change;
+	dev->old_data_ready	= sk->sk_data_ready;
+	dev->old_write_space	= sk->sk_write_space;
+	sk->sk_state_change	= gprs_state_change;
+	sk->sk_data_ready	= gprs_data_ready;
+	sk->sk_write_space	= gprs_write_space;
+	release_sock(sk);
+
+	sock_hold(sk);
+	dev->sk = sk;
+
+	printk(KERN_DEBUG"%s: attached\n", net->name);
+	gprs_write_space(sk); /* kick off TX */
+	return net->ifindex;
+
+out_rel:
+	release_sock(sk);
+	unregister_netdev(net);
+	return err;
+}
+
+void gprs_detach(struct sock *sk)
+{
+	struct gprs_dev *dev = sk->sk_user_data;
+	struct net_device *net = dev->net;
+
+	lock_sock(sk);
+	sk->sk_user_data	= NULL;
+	sk->sk_state_change	= dev->old_state_change;
+	sk->sk_data_ready	= dev->old_data_ready;
+	sk->sk_write_space	= dev->old_write_space;
+	release_sock(sk);
+
+	printk(KERN_DEBUG"%s: detached\n", net->name);
+	unregister_netdev(net);
+	flush_scheduled_work();
+	sock_put(sk);
+	skb_queue_purge(&dev->tx_queue);
+}
diff --git a/net/phonet/pep.c b/net/phonet/pep.c
new file mode 100644
index 0000000..bc6d50f
--- /dev/null
+++ b/net/phonet/pep.c
@@ -0,0 +1,1076 @@
+/*
+ * File: pep.c
+ *
+ * Phonet pipe protocol end point socket
+ *
+ * Copyright (C) 2008 Nokia Corporation.
+ *
+ * Author: Rémi Denis-Courmont <remi.denis-courmont@nokia.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.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/socket.h>
+#include <net/sock.h>
+#include <net/tcp_states.h>
+#include <asm/ioctls.h>
+
+#include <linux/phonet.h>
+#include <net/phonet/phonet.h>
+#include <net/phonet/pep.h>
+#include <net/phonet/gprs.h>
+
+/* sk_state values:
+ * TCP_CLOSE		sock not in use yet
+ * TCP_CLOSE_WAIT	disconnected pipe
+ * TCP_LISTEN		listening pipe endpoint
+ * TCP_SYN_RECV		connected pipe in disabled state
+ * TCP_ESTABLISHED	connected pipe in enabled state
+ *
+ * pep_sock locking:
+ *  - sk_state, ackq, hlist: sock lock needed
+ *  - listener: read only
+ *  - pipe_handle: read only
+ */
+
+#define CREDITS_MAX	10
+#define CREDITS_THR	7
+
+static const struct sockaddr_pn pipe_srv = {
+	.spn_family = AF_PHONET,
+	.spn_resource = 0xD9, /* pipe service */
+};
+
+#define pep_sb_size(s) (((s) + 5) & ~3) /* 2-bytes head, 32-bits aligned */
+
+/* Get the next TLV sub-block. */
+static unsigned char *pep_get_sb(struct sk_buff *skb, u8 *ptype, u8 *plen,
+					void *buf)
+{
+	void *data = NULL;
+	struct {
+		u8 sb_type;
+		u8 sb_len;
+	} *ph, h;
+	int buflen = *plen;
+
+	ph = skb_header_pointer(skb, 0, 2, &h);
+	if (ph == NULL || ph->sb_len < 2 || !pskb_may_pull(skb, ph->sb_len))
+		return NULL;
+	ph->sb_len -= 2;
+	*ptype = ph->sb_type;
+	*plen = ph->sb_len;
+
+	if (buflen > ph->sb_len)
+		buflen = ph->sb_len;
+	data = skb_header_pointer(skb, 2, buflen, buf);
+	__skb_pull(skb, 2 + ph->sb_len);
+	return data;
+}
+
+static int pep_reply(struct sock *sk, struct sk_buff *oskb,
+			u8 code, const void *data, int len, gfp_t priority)
+{
+	const struct pnpipehdr *oph = pnp_hdr(oskb);
+	struct pnpipehdr *ph;
+	struct sk_buff *skb;
+
+	skb = alloc_skb(MAX_PNPIPE_HEADER + len, priority);
+	if (!skb)
+		return -ENOMEM;
+	skb_set_owner_w(skb, sk);
+
+	skb_reserve(skb, MAX_PNPIPE_HEADER);
+	__skb_put(skb, len);
+	skb_copy_to_linear_data(skb, data, len);
+	__skb_push(skb, sizeof(*ph));
+	skb_reset_transport_header(skb);
+	ph = pnp_hdr(skb);
+	ph->utid = oph->utid;
+	ph->message_id = oph->message_id + 1; /* REQ -> RESP */
+	ph->pipe_handle = oph->pipe_handle;
+	ph->error_code = code;
+
+	return pn_skb_send(sk, skb, &pipe_srv);
+}
+
+#define PAD 0x00
+static int pep_accept_conn(struct sock *sk, struct sk_buff *skb)
+{
+	static const u8 data[20] = {
+		PAD, PAD, PAD, 2 /* sub-blocks */,
+		PN_PIPE_SB_REQUIRED_FC_TX, pep_sb_size(5), 3, PAD,
+			PN_MULTI_CREDIT_FLOW_CONTROL,
+			PN_ONE_CREDIT_FLOW_CONTROL,
+			PN_LEGACY_FLOW_CONTROL,
+			PAD,
+		PN_PIPE_SB_PREFERRED_FC_RX, pep_sb_size(5), 3, PAD,
+			PN_MULTI_CREDIT_FLOW_CONTROL,
+			PN_ONE_CREDIT_FLOW_CONTROL,
+			PN_LEGACY_FLOW_CONTROL,
+			PAD,
+	};
+
+	might_sleep();
+	return pep_reply(sk, skb, PN_PIPE_NO_ERROR, data, sizeof(data),
+				GFP_KERNEL);
+}
+
+static int pep_reject_conn(struct sock *sk, struct sk_buff *skb, u8 code)
+{
+	static const u8 data[4] = { PAD, PAD, PAD, 0 /* sub-blocks */ };
+	WARN_ON(code == PN_PIPE_NO_ERROR);
+	return pep_reply(sk, skb, code, data, sizeof(data), GFP_ATOMIC);
+}
+
+/* Control requests are not sent by the pipe service and have a specific
+ * message format. */
+static int pep_ctrlreq_error(struct sock *sk, struct sk_buff *oskb, u8 code,
+				gfp_t priority)
+{
+	const struct pnpipehdr *oph = pnp_hdr(oskb);
+	struct sk_buff *skb;
+	struct pnpipehdr *ph;
+	struct sockaddr_pn dst;
+
+	skb = alloc_skb(MAX_PNPIPE_HEADER + 4, priority);
+	if (!skb)
+		return -ENOMEM;
+	skb_set_owner_w(skb, sk);
+
+	skb_reserve(skb, MAX_PHONET_HEADER);
+	ph = (struct pnpipehdr *)skb_put(skb, sizeof(*ph) + 4);
+
+	ph->utid = oph->utid;
+	ph->message_id = PNS_PEP_CTRL_RESP;
+	ph->pipe_handle = oph->pipe_handle;
+	ph->data[0] = oph->data[1]; /* CTRL id */
+	ph->data[1] = oph->data[0]; /* PEP type */
+	ph->data[2] = code; /* error code, at an usual offset */
+	ph->data[3] = PAD;
+	ph->data[4] = PAD;
+
+	pn_skb_get_src_sockaddr(oskb, &dst);
+	return pn_skb_send(sk, skb, &dst);
+}
+
+static int pipe_snd_status(struct sock *sk, u8 type, u8 status, gfp_t priority)
+{
+	struct pep_sock *pn = pep_sk(sk);
+	struct pnpipehdr *ph;
+	struct sk_buff *skb;
+
+	skb = alloc_skb(MAX_PNPIPE_HEADER + 4, priority);
+	if (!skb)
+		return -ENOMEM;
+	skb_set_owner_w(skb, sk);
+
+	skb_reserve(skb, MAX_PNPIPE_HEADER + 4);
+	__skb_push(skb, sizeof(*ph) + 4);
+	skb_reset_transport_header(skb);
+	ph = pnp_hdr(skb);
+	ph->utid = 0;
+	ph->message_id = PNS_PEP_STATUS_IND;
+	ph->pipe_handle = pn->pipe_handle;
+	ph->pep_type = PN_PEP_TYPE_COMMON;
+	ph->data[1] = type;
+	ph->data[2] = PAD;
+	ph->data[3] = PAD;
+	ph->data[4] = status;
+
+	return pn_skb_send(sk, skb, &pipe_srv);
+}
+
+/* Send our RX flow control information to the sender.
+ * Socket must be locked. */
+static void pipe_grant_credits(struct sock *sk)
+{
+	struct pep_sock *pn = pep_sk(sk);
+
+	BUG_ON(sk->sk_state != TCP_ESTABLISHED);
+
+	switch (pn->rx_fc) {
+	case PN_LEGACY_FLOW_CONTROL: /* TODO */
+		break;
+	case PN_ONE_CREDIT_FLOW_CONTROL:
+		pipe_snd_status(sk, PN_PEP_IND_FLOW_CONTROL,
+				PEP_IND_READY, GFP_ATOMIC);
+		pn->rx_credits = 1;
+		break;
+	case PN_MULTI_CREDIT_FLOW_CONTROL:
+		if ((pn->rx_credits + CREDITS_THR) > CREDITS_MAX)
+			break;
+		if (pipe_snd_status(sk, PN_PEP_IND_ID_MCFC_GRANT_CREDITS,
+					CREDITS_MAX - pn->rx_credits,
+					GFP_ATOMIC) == 0)
+			pn->rx_credits = CREDITS_MAX;
+		break;
+	}
+}
+
+static int pipe_rcv_status(struct sock *sk, struct sk_buff *skb)
+{
+	struct pep_sock *pn = pep_sk(sk);
+	struct pnpipehdr *hdr = pnp_hdr(skb);
+
+	if (!pskb_may_pull(skb, sizeof(*hdr) + 4))
+		return -EINVAL;
+
+	if (hdr->data[0] != PN_PEP_TYPE_COMMON) {
+		LIMIT_NETDEBUG(KERN_DEBUG"Phonet unknown PEP type: %u\n",
+				(unsigned)hdr->data[0]);
+		return -EOPNOTSUPP;
+	}
+
+	switch (hdr->data[1]) {
+	case PN_PEP_IND_FLOW_CONTROL:
+		switch (pn->tx_fc) {
+		case PN_LEGACY_FLOW_CONTROL:
+			switch (hdr->data[4]) {
+			case PEP_IND_BUSY:
+				pn->tx_credits = 0;
+				break;
+			case PEP_IND_READY:
+				pn->tx_credits = 1;
+				break;
+			}
+			break;
+		case PN_ONE_CREDIT_FLOW_CONTROL:
+			if (hdr->data[4] == PEP_IND_READY)
+				pn->tx_credits = 1;
+			break;
+		}
+		break;
+
+	case PN_PEP_IND_ID_MCFC_GRANT_CREDITS:
+		if (pn->tx_fc != PN_MULTI_CREDIT_FLOW_CONTROL)
+			break;
+		if (pn->tx_credits + hdr->data[4] > 0xff)
+			pn->tx_credits = 0xff;
+		else
+			pn->tx_credits += hdr->data[4];
+		break;
+
+	default:
+		LIMIT_NETDEBUG(KERN_DEBUG"Phonet unknown PEP indication: %u\n",
+				(unsigned)hdr->data[1]);
+		return -EOPNOTSUPP;
+	}
+	if (pn->tx_credits)
+		sk->sk_write_space(sk);
+	return 0;
+}
+
+static int pipe_rcv_created(struct sock *sk, struct sk_buff *skb)
+{
+	struct pep_sock *pn = pep_sk(sk);
+	struct pnpipehdr *hdr = pnp_hdr(skb);
+	u8 n_sb = hdr->data[0];
+
+	pn->rx_fc = pn->tx_fc = PN_LEGACY_FLOW_CONTROL;
+	__skb_pull(skb, sizeof(*hdr));
+	while (n_sb > 0) {
+		u8 type, buf[2], len = sizeof(buf);
+		u8 *data = pep_get_sb(skb, &type, &len, buf);
+
+		if (data == NULL)
+			return -EINVAL;
+		switch (type) {
+		case PN_PIPE_SB_NEGOTIATED_FC:
+			if (len < 2 || (data[0] | data[1]) > 3)
+				break;
+			pn->tx_fc = data[0] & 3;
+			pn->rx_fc = data[1] & 3;
+			break;
+		}
+		n_sb--;
+	}
+	return 0;
+}
+
+/* Queue an skb to a connected sock.
+ * Socket lock must be held. */
+static int pipe_do_rcv(struct sock *sk, struct sk_buff *skb)
+{
+	struct pep_sock *pn = pep_sk(sk);
+	struct pnpipehdr *hdr = pnp_hdr(skb);
+	struct sk_buff_head *queue;
+	int err = 0;
+
+	BUG_ON(sk->sk_state == TCP_CLOSE_WAIT);
+
+	switch (hdr->message_id) {
+	case PNS_PEP_CONNECT_REQ:
+		pep_reject_conn(sk, skb, PN_PIPE_ERR_PEP_IN_USE);
+		break;
+
+	case PNS_PEP_DISCONNECT_REQ:
+		pep_reply(sk, skb, PN_PIPE_NO_ERROR, NULL, 0, GFP_ATOMIC);
+		sk->sk_state = TCP_CLOSE_WAIT;
+		if (!sock_flag(sk, SOCK_DEAD))
+			sk->sk_state_change(sk);
+		break;
+
+	case PNS_PEP_ENABLE_REQ:
+		/* Wait for PNS_PIPE_(ENABLED|REDIRECTED)_IND */
+		pep_reply(sk, skb, PN_PIPE_NO_ERROR, NULL, 0, GFP_ATOMIC);
+		break;
+
+	case PNS_PEP_RESET_REQ:
+		switch (hdr->state_after_reset) {
+		case PN_PIPE_DISABLE:
+			pn->init_enable = 0;
+			break;
+		case PN_PIPE_ENABLE:
+			pn->init_enable = 1;
+			break;
+		default: /* not allowed to send an error here!? */
+			err = -EINVAL;
+			goto out;
+		}
+		/* fall through */
+	case PNS_PEP_DISABLE_REQ:
+		pn->tx_credits = 0;
+		pep_reply(sk, skb, PN_PIPE_NO_ERROR, NULL, 0, GFP_ATOMIC);
+		break;
+
+	case PNS_PEP_CTRL_REQ:
+		if (skb_queue_len(&pn->ctrlreq_queue) >= PNPIPE_CTRLREQ_MAX)
+			break;
+		__skb_pull(skb, 4);
+		queue = &pn->ctrlreq_queue;
+		goto queue;
+
+	case PNS_PIPE_DATA:
+		__skb_pull(skb, 3); /* Pipe data header */
+		if (!pn_flow_safe(pn->rx_fc)) {
+			err = sock_queue_rcv_skb(sk, skb);
+			if (!err)
+				return 0;
+			break;
+		}
+
+		if (pn->rx_credits == 0) {
+			err = -ENOBUFS;
+			break;
+		}
+		pn->rx_credits--;
+		queue = &sk->sk_receive_queue;
+		goto queue;
+
+	case PNS_PEP_STATUS_IND:
+		pipe_rcv_status(sk, skb);
+		break;
+
+	case PNS_PIPE_REDIRECTED_IND:
+		err = pipe_rcv_created(sk, skb);
+		break;
+
+	case PNS_PIPE_CREATED_IND:
+		err = pipe_rcv_created(sk, skb);
+		if (err)
+			break;
+		/* fall through */
+	case PNS_PIPE_RESET_IND:
+		if (!pn->init_enable)
+			break;
+		/* fall through */
+	case PNS_PIPE_ENABLED_IND:
+		if (!pn_flow_safe(pn->tx_fc)) {
+			pn->tx_credits = 1;
+			sk->sk_write_space(sk);
+		}
+		if (sk->sk_state == TCP_ESTABLISHED)
+			break; /* Nothing to do */
+		sk->sk_state = TCP_ESTABLISHED;
+		pipe_grant_credits(sk);
+		break;
+
+	case PNS_PIPE_DISABLED_IND:
+		sk->sk_state = TCP_SYN_RECV;
+		pn->rx_credits = 0;
+		break;
+
+	default:
+		LIMIT_NETDEBUG(KERN_DEBUG"Phonet unknown PEP message: %u\n",
+				hdr->message_id);
+		err = -EINVAL;
+	}
+out:
+	kfree_skb(skb);
+	return err;
+
+queue:
+	skb->dev = NULL;
+	skb_set_owner_r(skb, sk);
+	err = skb->len;
+	skb_queue_tail(queue, skb);
+	if (!sock_flag(sk, SOCK_DEAD))
+		sk->sk_data_ready(sk, err);
+	return 0;
+}
+
+/* Destroy connected sock. */
+static void pipe_destruct(struct sock *sk)
+{
+	struct pep_sock *pn = pep_sk(sk);
+
+	skb_queue_purge(&sk->sk_receive_queue);
+	skb_queue_purge(&pn->ctrlreq_queue);
+}
+
+static int pep_connreq_rcv(struct sock *sk, struct sk_buff *skb)
+{
+	struct sock *newsk;
+	struct pep_sock *newpn, *pn = pep_sk(sk);
+	struct pnpipehdr *hdr;
+	struct sockaddr_pn dst;
+	u16 peer_type;
+	u8 pipe_handle, enabled, n_sb;
+
+	if (!pskb_pull(skb, sizeof(*hdr) + 4))
+		return -EINVAL;
+
+	hdr = pnp_hdr(skb);
+	pipe_handle = hdr->pipe_handle;
+	switch (hdr->state_after_connect) {
+	case PN_PIPE_DISABLE:
+		enabled = 0;
+		break;
+	case PN_PIPE_ENABLE:
+		enabled = 1;
+		break;
+	default:
+		pep_reject_conn(sk, skb, PN_PIPE_ERR_INVALID_PARAM);
+		return -EINVAL;
+	}
+	peer_type = hdr->other_pep_type << 8;
+
+	if (unlikely(sk->sk_state != TCP_LISTEN) || sk_acceptq_is_full(sk)) {
+		pep_reject_conn(sk, skb, PN_PIPE_ERR_PEP_IN_USE);
+		return -ENOBUFS;
+	}
+
+	/* Parse sub-blocks (options) */
+	n_sb = hdr->data[4];
+	while (n_sb > 0) {
+		u8 type, buf[1], len = sizeof(buf);
+		const u8 *data = pep_get_sb(skb, &type, &len, buf);
+
+		if (data == NULL)
+			return -EINVAL;
+		switch (type) {
+		case PN_PIPE_SB_CONNECT_REQ_PEP_SUB_TYPE:
+			if (len < 1)
+				return -EINVAL;
+			peer_type = (peer_type & 0xff00) | data[0];
+			break;
+		}
+		n_sb--;
+	}
+
+	skb = skb_clone(skb, GFP_ATOMIC);
+	if (!skb)
+		return -ENOMEM;
+
+	/* Create a new to-be-accepted sock */
+	newsk = sk_alloc(sock_net(sk), PF_PHONET, GFP_ATOMIC, sk->sk_prot);
+	if (!newsk) {
+		kfree_skb(skb);
+		return -ENOMEM;
+	}
+	sock_init_data(NULL, newsk);
+	newsk->sk_state = TCP_SYN_RECV;
+	newsk->sk_backlog_rcv = pipe_do_rcv;
+	newsk->sk_protocol = sk->sk_protocol;
+	newsk->sk_destruct = pipe_destruct;
+
+	newpn = pep_sk(newsk);
+	pn_skb_get_dst_sockaddr(skb, &dst);
+	newpn->pn_sk.sobject = pn_sockaddr_get_object(&dst);
+	newpn->pn_sk.resource = pn->pn_sk.resource;
+	skb_queue_head_init(&newpn->ctrlreq_queue);
+	newpn->pipe_handle = pipe_handle;
+	newpn->peer_type = peer_type;
+	newpn->rx_credits = newpn->tx_credits = 0;
+	newpn->rx_fc = newpn->tx_fc = PN_LEGACY_FLOW_CONTROL;
+	newpn->init_enable = enabled;
+
+	BUG_ON(!skb_queue_empty(&newsk->sk_receive_queue));
+	skb_queue_head(&newsk->sk_receive_queue, skb);
+	if (!sock_flag(sk, SOCK_DEAD))
+		sk->sk_data_ready(sk, 0);
+
+	sk_acceptq_added(sk);
+	sk_add_node(newsk, &pn->ackq);
+	return 0;
+}
+
+/* Listening sock must be locked */
+static struct sock *pep_find_pipe(const struct hlist_head *hlist,
+					const struct sockaddr_pn *dst,
+					u8 pipe_handle)
+{
+	struct hlist_node *node;
+	struct sock *sknode;
+	u16 dobj = pn_sockaddr_get_object(dst);
+
+	sk_for_each(sknode, node, hlist) {
+		struct pep_sock *pnnode = pep_sk(sknode);
+
+		/* Ports match, but addresses might not: */
+		if (pnnode->pn_sk.sobject != dobj)
+			continue;
+		if (pnnode->pipe_handle != pipe_handle)
+			continue;
+		if (sknode->sk_state == TCP_CLOSE_WAIT)
+			continue;
+
+		sock_hold(sknode);
+		return sknode;
+	}
+	return NULL;
+}
+
+/*
+ * Deliver an skb to a listening sock.
+ * Socket lock must be held.
+ * We then queue the skb to the right connected sock (if any).
+ */
+static int pep_do_rcv(struct sock *sk, struct sk_buff *skb)
+{
+	struct pep_sock *pn = pep_sk(sk);
+	struct sock *sknode;
+	struct pnpipehdr *hdr = pnp_hdr(skb);
+	struct sockaddr_pn dst;
+	int err = NET_RX_SUCCESS;
+	u8 pipe_handle;
+
+	if (!pskb_may_pull(skb, sizeof(*hdr)))
+		goto drop;
+
+	hdr = pnp_hdr(skb);
+	pipe_handle = hdr->pipe_handle;
+	if (pipe_handle == PN_PIPE_INVALID_HANDLE)
+		goto drop;
+
+	pn_skb_get_dst_sockaddr(skb, &dst);
+
+	/* Look for an existing pipe handle */
+	sknode = pep_find_pipe(&pn->hlist, &dst, pipe_handle);
+	if (sknode)
+		return sk_receive_skb(sknode, skb, 1);
+
+	/* Look for a pipe handle pending accept */
+	sknode = pep_find_pipe(&pn->ackq, &dst, pipe_handle);
+	if (sknode) {
+		sock_put(sknode);
+		if (net_ratelimit())
+			printk(KERN_WARNING"Phonet unconnected PEP ignored");
+		err = NET_RX_DROP;
+		goto drop;
+	}
+
+	switch (hdr->message_id) {
+	case PNS_PEP_CONNECT_REQ:
+		err = pep_connreq_rcv(sk, skb);
+		break;
+
+	case PNS_PEP_DISCONNECT_REQ:
+		pep_reply(sk, skb, PN_PIPE_NO_ERROR, NULL, 0, GFP_ATOMIC);
+		break;
+
+	case PNS_PEP_CTRL_REQ:
+		pep_ctrlreq_error(sk, skb, PN_PIPE_INVALID_HANDLE, GFP_ATOMIC);
+		break;
+
+	case PNS_PEP_RESET_REQ:
+	case PNS_PEP_ENABLE_REQ:
+	case PNS_PEP_DISABLE_REQ:
+		/* invalid handle is not even allowed here! */
+	default:
+		err = NET_RX_DROP;
+	}
+drop:
+	kfree_skb(skb);
+	return err;
+}
+
+/* associated socket ceases to exist */
+static void pep_sock_close(struct sock *sk, long timeout)
+{
+	struct pep_sock *pn = pep_sk(sk);
+	int ifindex = 0;
+
+	sk_common_release(sk);
+
+	lock_sock(sk);
+	if (sk->sk_state == TCP_LISTEN) {
+		/* Destroy the listen queue */
+		struct sock *sknode;
+		struct hlist_node *p, *n;
+
+		sk_for_each_safe(sknode, p, n, &pn->ackq)
+			sk_del_node_init(sknode);
+		sk->sk_state = TCP_CLOSE;
+	}
+	ifindex = pn->ifindex;
+	pn->ifindex = 0;
+	release_sock(sk);
+
+	if (ifindex)
+		gprs_detach(sk);
+}
+
+static int pep_wait_connreq(struct sock *sk, int noblock)
+{
+	struct task_struct *tsk = current;
+	struct pep_sock *pn = pep_sk(sk);
+	long timeo = sock_rcvtimeo(sk, noblock);
+
+	for (;;) {
+		DEFINE_WAIT(wait);
+
+		if (sk->sk_state != TCP_LISTEN)
+			return -EINVAL;
+		if (!hlist_empty(&pn->ackq))
+			break;
+		if (!timeo)
+			return -EWOULDBLOCK;
+		if (signal_pending(tsk))
+			return sock_intr_errno(timeo);
+
+		prepare_to_wait_exclusive(&sk->sk_socket->wait, &wait,
+						TASK_INTERRUPTIBLE);
+		release_sock(sk);
+		timeo = schedule_timeout(timeo);
+		lock_sock(sk);
+		finish_wait(&sk->sk_socket->wait, &wait);
+	}
+
+	return 0;
+}
+
+static struct sock *pep_sock_accept(struct sock *sk, int flags, int *errp)
+{
+	struct pep_sock *pn = pep_sk(sk);
+	struct sock *newsk = NULL;
+	struct sk_buff *oskb;
+	int err;
+
+	lock_sock(sk);
+	err = pep_wait_connreq(sk, flags & O_NONBLOCK);
+	if (err)
+		goto out;
+
+	newsk = __sk_head(&pn->ackq);
+
+	oskb = skb_dequeue(&newsk->sk_receive_queue);
+	err = pep_accept_conn(newsk, oskb);
+	if (err) {
+		skb_queue_head(&newsk->sk_receive_queue, oskb);
+		newsk = NULL;
+		goto out;
+	}
+
+	sock_hold(sk);
+	pep_sk(newsk)->listener = sk;
+
+	sock_hold(newsk);
+	sk_del_node_init(newsk);
+	sk_acceptq_removed(sk);
+	sk_add_node(newsk, &pn->hlist);
+	__sock_put(newsk);
+
+out:
+	release_sock(sk);
+	*errp = err;
+	return newsk;
+}
+
+static int pep_ioctl(struct sock *sk, int cmd, unsigned long arg)
+{
+	struct pep_sock *pn = pep_sk(sk);
+	int answ;
+
+	switch (cmd) {
+	case SIOCINQ:
+		if (sk->sk_state == TCP_LISTEN)
+			return -EINVAL;
+
+		lock_sock(sk);
+		if (sock_flag(sk, SOCK_URGINLINE)
+		 && !skb_queue_empty(&pn->ctrlreq_queue))
+			answ = skb_peek(&pn->ctrlreq_queue)->len;
+		else if (!skb_queue_empty(&sk->sk_receive_queue))
+			answ = skb_peek(&sk->sk_receive_queue)->len;
+		else
+			answ = 0;
+		release_sock(sk);
+		return put_user(answ, (int __user *)arg);
+	}
+
+	return -ENOIOCTLCMD;
+}
+
+static int pep_init(struct sock *sk)
+{
+	struct pep_sock *pn = pep_sk(sk);
+
+	INIT_HLIST_HEAD(&pn->ackq);
+	INIT_HLIST_HEAD(&pn->hlist);
+	skb_queue_head_init(&pn->ctrlreq_queue);
+	pn->pipe_handle = PN_PIPE_INVALID_HANDLE;
+	return 0;
+}
+
+static int pep_setsockopt(struct sock *sk, int level, int optname,
+				char __user *optval, int optlen)
+{
+	struct pep_sock *pn = pep_sk(sk);
+	int val = 0, err = 0;
+
+	if (level != SOL_PNPIPE)
+		return -ENOPROTOOPT;
+	if (optlen >= sizeof(int)) {
+		if (get_user(val, (int __user *) optval))
+			return -EFAULT;
+	}
+
+	lock_sock(sk);
+	switch (optname) {
+	case PNPIPE_ENCAP:
+		if (val && val != PNPIPE_ENCAP_IP) {
+			err = -EINVAL;
+			break;
+		}
+		if (!pn->ifindex == !val)
+			break; /* Nothing to do! */
+		if (!capable(CAP_NET_ADMIN)) {
+			err = -EPERM;
+			break;
+		}
+		if (val) {
+			release_sock(sk);
+			err = gprs_attach(sk);
+			if (err > 0) {
+				pn->ifindex = err;
+				err = 0;
+			}
+		} else {
+			pn->ifindex = 0;
+			release_sock(sk);
+			gprs_detach(sk);
+			err = 0;
+		}
+		goto out_norel;
+	default:
+		err = -ENOPROTOOPT;
+	}
+	release_sock(sk);
+
+out_norel:
+	return err;
+}
+
+static int pep_getsockopt(struct sock *sk, int level, int optname,
+				char __user *optval, int __user *optlen)
+{
+	struct pep_sock *pn = pep_sk(sk);
+	int len, val;
+
+	if (level != SOL_PNPIPE)
+		return -ENOPROTOOPT;
+	if (get_user(len, optlen))
+		return -EFAULT;
+
+	switch (optname) {
+	case PNPIPE_ENCAP:
+		val = pn->ifindex ? PNPIPE_ENCAP_IP : PNPIPE_ENCAP_NONE;
+		break;
+	case PNPIPE_IFINDEX:
+		val = pn->ifindex;
+		break;
+	default:
+		return -ENOPROTOOPT;
+	}
+
+	len = min_t(unsigned int, sizeof(int), len);
+	if (put_user(len, optlen))
+		return -EFAULT;
+	if (put_user(val, (int __user *) optval))
+		return -EFAULT;
+	return 0;
+}
+
+static int pipe_skb_send(struct sock *sk, struct sk_buff *skb)
+{
+	struct pep_sock *pn = pep_sk(sk);
+	struct pnpipehdr *ph;
+
+	skb_push(skb, 3);
+	skb_reset_transport_header(skb);
+	ph = pnp_hdr(skb);
+	ph->utid = 0;
+	ph->message_id = PNS_PIPE_DATA;
+	ph->pipe_handle = pn->pipe_handle;
+	if (pn_flow_safe(pn->tx_fc) && pn->tx_credits)
+		pn->tx_credits--;
+
+	return pn_skb_send(sk, skb, &pipe_srv);
+}
+
+static int pep_sendmsg(struct kiocb *iocb, struct sock *sk,
+			struct msghdr *msg, size_t len)
+{
+	struct pep_sock *pn = pep_sk(sk);
+	struct sk_buff *skb = NULL;
+	long timeo;
+	int flags = msg->msg_flags;
+	int err, done;
+
+	if (msg->msg_flags & MSG_OOB || !(msg->msg_flags & MSG_EOR))
+		return -EOPNOTSUPP;
+
+	lock_sock(sk);
+	timeo = sock_sndtimeo(sk, flags & MSG_DONTWAIT);
+	if ((1 << sk->sk_state) & (TCPF_LISTEN|TCPF_CLOSE)) {
+		err = -ENOTCONN;
+		goto out;
+	}
+	if (sk->sk_state != TCP_ESTABLISHED) {
+		/* Wait until the pipe gets to enabled state */
+disabled:
+		err = sk_stream_wait_connect(sk, &timeo);
+		if (err)
+			goto out;
+
+		if (sk->sk_state == TCP_CLOSE_WAIT) {
+			err = -ECONNRESET;
+			goto out;
+		}
+	}
+	BUG_ON(sk->sk_state != TCP_ESTABLISHED);
+
+	/* Wait until flow control allows TX */
+	done = pn->tx_credits > 0;
+	while (!done) {
+		DEFINE_WAIT(wait);
+
+		if (!timeo) {
+			err = -EAGAIN;
+			goto out;
+		}
+		if (signal_pending(current)) {
+			err = sock_intr_errno(timeo);
+			goto out;
+		}
+
+		prepare_to_wait(&sk->sk_socket->wait, &wait,
+				TASK_INTERRUPTIBLE);
+		done = sk_wait_event(sk, &timeo, pn->tx_credits > 0);
+		finish_wait(&sk->sk_socket->wait, &wait);
+
+		if (sk->sk_state != TCP_ESTABLISHED)
+			goto disabled;
+	}
+
+	if (!skb) {
+		skb = sock_alloc_send_skb(sk, MAX_PNPIPE_HEADER + len,
+						flags & MSG_DONTWAIT, &err);
+		if (skb == NULL)
+			goto out;
+		skb_reserve(skb, MAX_PHONET_HEADER + 3);
+
+		if (sk->sk_state != TCP_ESTABLISHED || !pn->tx_credits)
+			goto disabled; /* sock_alloc_send_skb might sleep */
+	}
+
+	err = memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len);
+	if (err < 0)
+		goto out;
+
+	err = pipe_skb_send(sk, skb);
+	if (err >= 0)
+		err = len; /* success! */
+	skb = NULL;
+out:
+	release_sock(sk);
+	kfree_skb(skb);
+	return err;
+}
+
+int pep_writeable(struct sock *sk)
+{
+	struct pep_sock *pn = pep_sk(sk);
+
+	return (sk->sk_state == TCP_ESTABLISHED) ? pn->tx_credits : 0;
+}
+
+int pep_write(struct sock *sk, struct sk_buff *skb)
+{
+	struct sk_buff *rskb, *fs;
+	int flen = 0;
+
+	rskb = alloc_skb(MAX_PNPIPE_HEADER, GFP_ATOMIC);
+	if (!rskb) {
+		kfree_skb(skb);
+		return -ENOMEM;
+	}
+	skb_shinfo(rskb)->frag_list = skb;
+	rskb->len += skb->len;
+	rskb->data_len += rskb->len;
+	rskb->truesize += rskb->len;
+
+	/* Avoid nested fragments */
+	for (fs = skb_shinfo(skb)->frag_list; fs; fs = fs->next)
+		flen += fs->len;
+	skb->next = skb_shinfo(skb)->frag_list;
+	skb_shinfo(skb)->frag_list = NULL;
+	skb->len -= flen;
+	skb->data_len -= flen;
+	skb->truesize -= flen;
+
+	skb_reserve(rskb, MAX_PHONET_HEADER + 3);
+	return pipe_skb_send(sk, rskb);
+}
+
+struct sk_buff *pep_read(struct sock *sk)
+{
+	struct sk_buff *skb = skb_dequeue(&sk->sk_receive_queue);
+
+	if (sk->sk_state == TCP_ESTABLISHED)
+		pipe_grant_credits(sk);
+	return skb;
+}
+
+static int pep_recvmsg(struct kiocb *iocb, struct sock *sk,
+			struct msghdr *msg, size_t len, int noblock,
+			int flags, int *addr_len)
+{
+	struct sk_buff *skb;
+	int err;
+
+	if (unlikely(1 << sk->sk_state & (TCPF_LISTEN | TCPF_CLOSE)))
+		return -ENOTCONN;
+
+	if ((flags & MSG_OOB) || sock_flag(sk, SOCK_URGINLINE)) {
+		/* Dequeue and acknowledge control request */
+		struct pep_sock *pn = pep_sk(sk);
+
+		skb = skb_dequeue(&pn->ctrlreq_queue);
+		if (skb) {
+			pep_ctrlreq_error(sk, skb, PN_PIPE_NO_ERROR,
+						GFP_KERNEL);
+			msg->msg_flags |= MSG_OOB;
+			goto copy;
+		}
+		if (flags & MSG_OOB)
+			return -EINVAL;
+	}
+
+	skb = skb_recv_datagram(sk, flags, noblock, &err);
+	lock_sock(sk);
+	if (skb == NULL) {
+		if (err == -ENOTCONN && sk->sk_state == TCP_CLOSE_WAIT)
+			err = -ECONNRESET;
+		release_sock(sk);
+		return err;
+	}
+
+	if (sk->sk_state == TCP_ESTABLISHED)
+		pipe_grant_credits(sk);
+	release_sock(sk);
+copy:
+	msg->msg_flags |= MSG_EOR;
+	if (skb->len > len)
+		msg->msg_flags |= MSG_TRUNC;
+	else
+		len = skb->len;
+
+	err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, len);
+	if (!err)
+		err = (flags & MSG_TRUNC) ? skb->len : len;
+
+	skb_free_datagram(sk, skb);
+	return err;
+}
+
+static void pep_sock_unhash(struct sock *sk)
+{
+	struct pep_sock *pn = pep_sk(sk);
+	struct sock *skparent = NULL;
+
+	lock_sock(sk);
+	if ((1 << sk->sk_state) & ~(TCPF_CLOSE|TCPF_LISTEN)) {
+		skparent = pn->listener;
+		sk_del_node_init(sk);
+		release_sock(sk);
+
+		sk = skparent;
+		pn = pep_sk(skparent);
+		lock_sock(sk);
+	}
+	/* Unhash a listening sock only when it is closed
+	 * and all of its active connected pipes are closed. */
+	if (hlist_empty(&pn->hlist))
+		pn_sock_unhash(&pn->pn_sk.sk);
+	release_sock(sk);
+
+	if (skparent)
+		sock_put(skparent);
+}
+
+static struct proto pep_proto = {
+	.close		= pep_sock_close,
+	.accept		= pep_sock_accept,
+	.ioctl		= pep_ioctl,
+	.init		= pep_init,
+	.setsockopt	= pep_setsockopt,
+	.getsockopt	= pep_getsockopt,
+	.sendmsg	= pep_sendmsg,
+	.recvmsg	= pep_recvmsg,
+	.backlog_rcv	= pep_do_rcv,
+	.hash		= pn_sock_hash,
+	.unhash		= pep_sock_unhash,
+	.get_port	= pn_sock_get_port,
+	.obj_size	= sizeof(struct pep_sock),
+	.owner		= THIS_MODULE,
+	.name		= "PNPIPE",
+};
+
+static struct phonet_protocol pep_pn_proto = {
+	.ops		= &phonet_stream_ops,
+	.prot		= &pep_proto,
+	.sock_type	= SOCK_SEQPACKET,
+};
+
+static int __init pep_register(void)
+{
+	return phonet_proto_register(PN_PROTO_PIPE, &pep_pn_proto);
+}
+
+static void __exit pep_unregister(void)
+{
+	phonet_proto_unregister(PN_PROTO_PIPE, &pep_pn_proto);
+}
+
+module_init(pep_register);
+module_exit(pep_unregister);
+MODULE_AUTHOR("Remi Denis-Courmont, Nokia");
+MODULE_DESCRIPTION("Phonet pipe protocol");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_NET_PF_PROTO(PF_PHONET, PN_PROTO_PIPE);
diff --git a/net/phonet/pn_dev.c b/net/phonet/pn_dev.c
new file mode 100644
index 0000000..53be9fc
--- /dev/null
+++ b/net/phonet/pn_dev.c
@@ -0,0 +1,208 @@
+/*
+ * File: pn_dev.c
+ *
+ * Phonet network device
+ *
+ * Copyright (C) 2008 Nokia Corporation.
+ *
+ * Contact: Remi Denis-Courmont <remi.denis-courmont@nokia.com>
+ * Original author: Sakari Ailus <sakari.ailus@nokia.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.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/net.h>
+#include <linux/netdevice.h>
+#include <linux/phonet.h>
+#include <net/sock.h>
+#include <net/phonet/pn_dev.h>
+
+/* when accessing, remember to lock with spin_lock(&pndevs.lock); */
+struct phonet_device_list pndevs = {
+	.list = LIST_HEAD_INIT(pndevs.list),
+	.lock = __SPIN_LOCK_UNLOCKED(pndevs.lock),
+};
+
+/* Allocate new Phonet device. */
+static struct phonet_device *__phonet_device_alloc(struct net_device *dev)
+{
+	struct phonet_device *pnd = kmalloc(sizeof(*pnd), GFP_ATOMIC);
+	if (pnd == NULL)
+		return NULL;
+	pnd->netdev = dev;
+	bitmap_zero(pnd->addrs, 64);
+
+	list_add(&pnd->list, &pndevs.list);
+	return pnd;
+}
+
+static struct phonet_device *__phonet_get(struct net_device *dev)
+{
+	struct phonet_device *pnd;
+
+	list_for_each_entry(pnd, &pndevs.list, list) {
+		if (pnd->netdev == dev)
+			return pnd;
+	}
+	return NULL;
+}
+
+static void __phonet_device_free(struct phonet_device *pnd)
+{
+	list_del(&pnd->list);
+	kfree(pnd);
+}
+
+struct net_device *phonet_device_get(struct net *net)
+{
+	struct phonet_device *pnd;
+	struct net_device *dev;
+
+	spin_lock_bh(&pndevs.lock);
+	list_for_each_entry(pnd, &pndevs.list, list) {
+		dev = pnd->netdev;
+		BUG_ON(!dev);
+
+		if (dev_net(dev) == net &&
+			(dev->reg_state == NETREG_REGISTERED) &&
+			((pnd->netdev->flags & IFF_UP)) == IFF_UP)
+			break;
+		dev = NULL;
+	}
+	if (dev)
+		dev_hold(dev);
+	spin_unlock_bh(&pndevs.lock);
+	return dev;
+}
+
+int phonet_address_add(struct net_device *dev, u8 addr)
+{
+	struct phonet_device *pnd;
+	int err = 0;
+
+	spin_lock_bh(&pndevs.lock);
+	/* Find or create Phonet-specific device data */
+	pnd = __phonet_get(dev);
+	if (pnd == NULL)
+		pnd = __phonet_device_alloc(dev);
+	if (unlikely(pnd == NULL))
+		err = -ENOMEM;
+	else if (test_and_set_bit(addr >> 2, pnd->addrs))
+		err = -EEXIST;
+	spin_unlock_bh(&pndevs.lock);
+	return err;
+}
+
+int phonet_address_del(struct net_device *dev, u8 addr)
+{
+	struct phonet_device *pnd;
+	int err = 0;
+
+	spin_lock_bh(&pndevs.lock);
+	pnd = __phonet_get(dev);
+	if (!pnd || !test_and_clear_bit(addr >> 2, pnd->addrs))
+		err = -EADDRNOTAVAIL;
+	if (bitmap_empty(pnd->addrs, 64))
+		__phonet_device_free(pnd);
+	spin_unlock_bh(&pndevs.lock);
+	return err;
+}
+
+/* Gets a source address toward a destination, through a interface. */
+u8 phonet_address_get(struct net_device *dev, u8 addr)
+{
+	struct phonet_device *pnd;
+
+	spin_lock_bh(&pndevs.lock);
+	pnd = __phonet_get(dev);
+	if (pnd) {
+		BUG_ON(bitmap_empty(pnd->addrs, 64));
+
+		/* Use same source address as destination, if possible */
+		if (!test_bit(addr >> 2, pnd->addrs))
+			addr = find_first_bit(pnd->addrs, 64) << 2;
+	} else
+		addr = PN_NO_ADDR;
+	spin_unlock_bh(&pndevs.lock);
+	return addr;
+}
+
+int phonet_address_lookup(u8 addr)
+{
+	struct phonet_device *pnd;
+
+	spin_lock_bh(&pndevs.lock);
+	list_for_each_entry(pnd, &pndevs.list, list) {
+		/* Don't allow unregistering devices! */
+		if ((pnd->netdev->reg_state != NETREG_REGISTERED) ||
+				((pnd->netdev->flags & IFF_UP)) != IFF_UP)
+			continue;
+
+		if (test_bit(addr >> 2, pnd->addrs)) {
+			spin_unlock_bh(&pndevs.lock);
+			return 0;
+		}
+	}
+	spin_unlock_bh(&pndevs.lock);
+	return -EADDRNOTAVAIL;
+}
+
+/* notify Phonet of device events */
+static int phonet_device_notify(struct notifier_block *me, unsigned long what,
+				void *arg)
+{
+	struct net_device *dev = arg;
+
+	if (what == NETDEV_UNREGISTER) {
+		struct phonet_device *pnd;
+
+		/* Destroy phonet-specific device data */
+		spin_lock_bh(&pndevs.lock);
+		pnd = __phonet_get(dev);
+		if (pnd)
+			__phonet_device_free(pnd);
+		spin_unlock_bh(&pndevs.lock);
+	}
+	return 0;
+
+}
+
+static struct notifier_block phonet_device_notifier = {
+	.notifier_call = phonet_device_notify,
+	.priority = 0,
+};
+
+/* Initialize Phonet devices list */
+void phonet_device_init(void)
+{
+	register_netdevice_notifier(&phonet_device_notifier);
+}
+
+void phonet_device_exit(void)
+{
+	struct phonet_device *pnd, *n;
+
+	rtnl_unregister_all(PF_PHONET);
+	rtnl_lock();
+	spin_lock_bh(&pndevs.lock);
+
+	list_for_each_entry_safe(pnd, n, &pndevs.list, list)
+		__phonet_device_free(pnd);
+
+	spin_unlock_bh(&pndevs.lock);
+	rtnl_unlock();
+	unregister_netdevice_notifier(&phonet_device_notifier);
+}
diff --git a/net/phonet/pn_netlink.c b/net/phonet/pn_netlink.c
new file mode 100644
index 0000000..b1770d6
--- /dev/null
+++ b/net/phonet/pn_netlink.c
@@ -0,0 +1,165 @@
+/*
+ * File: pn_netlink.c
+ *
+ * Phonet netlink interface
+ *
+ * Copyright (C) 2008 Nokia Corporation.
+ *
+ * Contact: Remi Denis-Courmont <remi.denis-courmont@nokia.com>
+ * Original author: Sakari Ailus <sakari.ailus@nokia.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.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/netlink.h>
+#include <linux/phonet.h>
+#include <net/sock.h>
+#include <net/phonet/pn_dev.h>
+
+static int fill_addr(struct sk_buff *skb, struct net_device *dev, u8 addr,
+		     u32 pid, u32 seq, int event);
+
+static void rtmsg_notify(int event, struct net_device *dev, u8 addr)
+{
+	struct sk_buff *skb;
+	int err = -ENOBUFS;
+
+	skb = nlmsg_new(NLMSG_ALIGN(sizeof(struct ifaddrmsg)) +
+			nla_total_size(1), GFP_KERNEL);
+	if (skb == NULL)
+		goto errout;
+	err = fill_addr(skb, dev, addr, 0, 0, event);
+	if (err < 0) {
+		WARN_ON(err == -EMSGSIZE);
+		kfree_skb(skb);
+		goto errout;
+	}
+	err = rtnl_notify(skb, dev_net(dev), 0,
+			  RTNLGRP_PHONET_IFADDR, NULL, GFP_KERNEL);
+errout:
+	if (err < 0)
+		rtnl_set_sk_err(dev_net(dev), RTNLGRP_PHONET_IFADDR, err);
+}
+
+static const struct nla_policy ifa_phonet_policy[IFA_MAX+1] = {
+	[IFA_LOCAL] = { .type = NLA_U8 },
+};
+
+static int addr_doit(struct sk_buff *skb, struct nlmsghdr *nlh, void *attr)
+{
+	struct net *net = sock_net(skb->sk);
+	struct nlattr *tb[IFA_MAX+1];
+	struct net_device *dev;
+	struct ifaddrmsg *ifm;
+	int err;
+	u8 pnaddr;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+
+	ASSERT_RTNL();
+
+	err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_phonet_policy);
+	if (err < 0)
+		return err;
+
+	ifm = nlmsg_data(nlh);
+	if (tb[IFA_LOCAL] == NULL)
+		return -EINVAL;
+	pnaddr = nla_get_u8(tb[IFA_LOCAL]);
+	if (pnaddr & 3)
+		/* Phonet addresses only have 6 high-order bits */
+		return -EINVAL;
+
+	dev = __dev_get_by_index(net, ifm->ifa_index);
+	if (dev == NULL)
+		return -ENODEV;
+
+	if (nlh->nlmsg_type == RTM_NEWADDR)
+		err = phonet_address_add(dev, pnaddr);
+	else
+		err = phonet_address_del(dev, pnaddr);
+	if (!err)
+		rtmsg_notify(nlh->nlmsg_type, dev, pnaddr);
+	return err;
+}
+
+static int fill_addr(struct sk_buff *skb, struct net_device *dev, u8 addr,
+			u32 pid, u32 seq, int event)
+{
+	struct ifaddrmsg *ifm;
+	struct nlmsghdr *nlh;
+
+	nlh = nlmsg_put(skb, pid, seq, event, sizeof(*ifm), 0);
+	if (nlh == NULL)
+		return -EMSGSIZE;
+
+	ifm = nlmsg_data(nlh);
+	ifm->ifa_family = AF_PHONET;
+	ifm->ifa_prefixlen = 0;
+	ifm->ifa_flags = IFA_F_PERMANENT;
+	ifm->ifa_scope = RT_SCOPE_LINK;
+	ifm->ifa_index = dev->ifindex;
+	NLA_PUT_U8(skb, IFA_LOCAL, addr);
+	return nlmsg_end(skb, nlh);
+
+nla_put_failure:
+	nlmsg_cancel(skb, nlh);
+	return -EMSGSIZE;
+}
+
+static int getaddr_dumpit(struct sk_buff *skb, struct netlink_callback *cb)
+{
+	struct phonet_device *pnd;
+	int dev_idx = 0, dev_start_idx = cb->args[0];
+	int addr_idx = 0, addr_start_idx = cb->args[1];
+
+	spin_lock_bh(&pndevs.lock);
+	list_for_each_entry(pnd, &pndevs.list, list) {
+		u8 addr;
+
+		if (dev_idx > dev_start_idx)
+			addr_start_idx = 0;
+		if (dev_idx++ < dev_start_idx)
+			continue;
+
+		addr_idx = 0;
+		for (addr = find_first_bit(pnd->addrs, 64); addr < 64;
+			addr = find_next_bit(pnd->addrs, 64, 1+addr)) {
+			if (addr_idx++ < addr_start_idx)
+				continue;
+
+			if (fill_addr(skb, pnd->netdev, addr << 2,
+					 NETLINK_CB(cb->skb).pid,
+					cb->nlh->nlmsg_seq, RTM_NEWADDR))
+				goto out;
+		}
+	}
+
+out:
+	spin_unlock_bh(&pndevs.lock);
+	cb->args[0] = dev_idx;
+	cb->args[1] = addr_idx;
+
+	return skb->len;
+}
+
+void __init phonet_netlink_register(void)
+{
+	rtnl_register(PF_PHONET, RTM_NEWADDR, addr_doit, NULL);
+	rtnl_register(PF_PHONET, RTM_DELADDR, addr_doit, NULL);
+	rtnl_register(PF_PHONET, RTM_GETADDR, NULL, getaddr_dumpit);
+}
diff --git a/net/phonet/socket.c b/net/phonet/socket.c
new file mode 100644
index 0000000..d817401
--- /dev/null
+++ b/net/phonet/socket.c
@@ -0,0 +1,411 @@
+/*
+ * File: socket.c
+ *
+ * Phonet sockets
+ *
+ * Copyright (C) 2008 Nokia Corporation.
+ *
+ * Contact: Remi Denis-Courmont <remi.denis-courmont@nokia.com>
+ * Original author: Sakari Ailus <sakari.ailus@nokia.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.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/net.h>
+#include <linux/poll.h>
+#include <net/sock.h>
+#include <net/tcp_states.h>
+
+#include <linux/phonet.h>
+#include <net/phonet/phonet.h>
+#include <net/phonet/pep.h>
+#include <net/phonet/pn_dev.h>
+
+static int pn_socket_release(struct socket *sock)
+{
+	struct sock *sk = sock->sk;
+
+	if (sk) {
+		sock->sk = NULL;
+		sk->sk_prot->close(sk, 0);
+	}
+	return 0;
+}
+
+static struct  {
+	struct hlist_head hlist;
+	spinlock_t lock;
+} pnsocks = {
+	.hlist = HLIST_HEAD_INIT,
+	.lock = __SPIN_LOCK_UNLOCKED(pnsocks.lock),
+};
+
+/*
+ * Find address based on socket address, match only certain fields.
+ * Also grab sock if it was found. Remember to sock_put it later.
+ */
+struct sock *pn_find_sock_by_sa(const struct sockaddr_pn *spn)
+{
+	struct hlist_node *node;
+	struct sock *sknode;
+	struct sock *rval = NULL;
+	u16 obj = pn_sockaddr_get_object(spn);
+	u8 res = spn->spn_resource;
+
+	spin_lock_bh(&pnsocks.lock);
+
+	sk_for_each(sknode, node, &pnsocks.hlist) {
+		struct pn_sock *pn = pn_sk(sknode);
+		BUG_ON(!pn->sobject); /* unbound socket */
+
+		if (pn_port(obj)) {
+			/* Look up socket by port */
+			if (pn_port(pn->sobject) != pn_port(obj))
+				continue;
+		} else {
+			/* If port is zero, look up by resource */
+			if (pn->resource != res)
+				continue;
+		}
+		if (pn_addr(pn->sobject)
+		 && pn_addr(pn->sobject) != pn_addr(obj))
+			continue;
+
+		rval = sknode;
+		sock_hold(sknode);
+		break;
+	}
+
+	spin_unlock_bh(&pnsocks.lock);
+
+	return rval;
+
+}
+
+void pn_sock_hash(struct sock *sk)
+{
+	spin_lock_bh(&pnsocks.lock);
+	sk_add_node(sk, &pnsocks.hlist);
+	spin_unlock_bh(&pnsocks.lock);
+}
+EXPORT_SYMBOL(pn_sock_hash);
+
+void pn_sock_unhash(struct sock *sk)
+{
+	spin_lock_bh(&pnsocks.lock);
+	sk_del_node_init(sk);
+	spin_unlock_bh(&pnsocks.lock);
+}
+EXPORT_SYMBOL(pn_sock_unhash);
+
+static int pn_socket_bind(struct socket *sock, struct sockaddr *addr, int len)
+{
+	struct sock *sk = sock->sk;
+	struct pn_sock *pn = pn_sk(sk);
+	struct sockaddr_pn *spn = (struct sockaddr_pn *)addr;
+	int err;
+	u16 handle;
+	u8 saddr;
+
+	if (sk->sk_prot->bind)
+		return sk->sk_prot->bind(sk, addr, len);
+
+	if (len < sizeof(struct sockaddr_pn))
+		return -EINVAL;
+	if (spn->spn_family != AF_PHONET)
+		return -EAFNOSUPPORT;
+
+	handle = pn_sockaddr_get_object((struct sockaddr_pn *)addr);
+	saddr = pn_addr(handle);
+	if (saddr && phonet_address_lookup(saddr))
+		return -EADDRNOTAVAIL;
+
+	lock_sock(sk);
+	if (sk->sk_state != TCP_CLOSE || pn_port(pn->sobject)) {
+		err = -EINVAL; /* attempt to rebind */
+		goto out;
+	}
+	err = sk->sk_prot->get_port(sk, pn_port(handle));
+	if (err)
+		goto out;
+
+	/* get_port() sets the port, bind() sets the address if applicable */
+	pn->sobject = pn_object(saddr, pn_port(pn->sobject));
+	pn->resource = spn->spn_resource;
+
+	/* Enable RX on the socket */
+	sk->sk_prot->hash(sk);
+out:
+	release_sock(sk);
+	return err;
+}
+
+static int pn_socket_autobind(struct socket *sock)
+{
+	struct sockaddr_pn sa;
+	int err;
+
+	memset(&sa, 0, sizeof(sa));
+	sa.spn_family = AF_PHONET;
+	err = pn_socket_bind(sock, (struct sockaddr *)&sa,
+				sizeof(struct sockaddr_pn));
+	if (err != -EINVAL)
+		return err;
+	BUG_ON(!pn_port(pn_sk(sock->sk)->sobject));
+	return 0; /* socket was already bound */
+}
+
+static int pn_socket_accept(struct socket *sock, struct socket *newsock,
+				int flags)
+{
+	struct sock *sk = sock->sk;
+	struct sock *newsk;
+	int err;
+
+	newsk = sk->sk_prot->accept(sk, flags, &err);
+	if (!newsk)
+		return err;
+
+	lock_sock(newsk);
+	sock_graft(newsk, newsock);
+	newsock->state = SS_CONNECTED;
+	release_sock(newsk);
+	return 0;
+}
+
+static int pn_socket_getname(struct socket *sock, struct sockaddr *addr,
+				int *sockaddr_len, int peer)
+{
+	struct sock *sk = sock->sk;
+	struct pn_sock *pn = pn_sk(sk);
+
+	memset(addr, 0, sizeof(struct sockaddr_pn));
+	addr->sa_family = AF_PHONET;
+	if (!peer) /* Race with bind() here is userland's problem. */
+		pn_sockaddr_set_object((struct sockaddr_pn *)addr,
+					pn->sobject);
+
+	*sockaddr_len = sizeof(struct sockaddr_pn);
+	return 0;
+}
+
+static unsigned int pn_socket_poll(struct file *file, struct socket *sock,
+					poll_table *wait)
+{
+	struct sock *sk = sock->sk;
+	struct pep_sock *pn = pep_sk(sk);
+	unsigned int mask = 0;
+
+	poll_wait(file, &sock->wait, wait);
+
+	switch (sk->sk_state) {
+	case TCP_LISTEN:
+		return hlist_empty(&pn->ackq) ? 0 : POLLIN;
+	case TCP_CLOSE:
+		return POLLERR;
+	}
+
+	if (!skb_queue_empty(&sk->sk_receive_queue))
+		mask |= POLLIN | POLLRDNORM;
+	if (!skb_queue_empty(&pn->ctrlreq_queue))
+		mask |= POLLPRI;
+	if (!mask && sk->sk_state == TCP_CLOSE_WAIT)
+		return POLLHUP;
+
+	if (sk->sk_state == TCP_ESTABLISHED && pn->tx_credits)
+		mask |= POLLOUT | POLLWRNORM | POLLWRBAND;
+
+	return mask;
+}
+
+static int pn_socket_ioctl(struct socket *sock, unsigned int cmd,
+				unsigned long arg)
+{
+	struct sock *sk = sock->sk;
+	struct pn_sock *pn = pn_sk(sk);
+
+	if (cmd == SIOCPNGETOBJECT) {
+		struct net_device *dev;
+		u16 handle;
+		u8 saddr;
+
+		if (get_user(handle, (__u16 __user *)arg))
+			return -EFAULT;
+
+		lock_sock(sk);
+		if (sk->sk_bound_dev_if)
+			dev = dev_get_by_index(sock_net(sk),
+						sk->sk_bound_dev_if);
+		else
+			dev = phonet_device_get(sock_net(sk));
+		if (dev && (dev->flags & IFF_UP))
+			saddr = phonet_address_get(dev, pn_addr(handle));
+		else
+			saddr = PN_NO_ADDR;
+		release_sock(sk);
+
+		if (dev)
+			dev_put(dev);
+		if (saddr == PN_NO_ADDR)
+			return -EHOSTUNREACH;
+
+		handle = pn_object(saddr, pn_port(pn->sobject));
+		return put_user(handle, (__u16 __user *)arg);
+	}
+
+	return sk->sk_prot->ioctl(sk, cmd, arg);
+}
+
+static int pn_socket_listen(struct socket *sock, int backlog)
+{
+	struct sock *sk = sock->sk;
+	int err = 0;
+
+	if (sock->state != SS_UNCONNECTED)
+		return -EINVAL;
+	if (pn_socket_autobind(sock))
+		return -ENOBUFS;
+
+	lock_sock(sk);
+	if (sk->sk_state != TCP_CLOSE) {
+		err = -EINVAL;
+		goto out;
+	}
+
+	sk->sk_state = TCP_LISTEN;
+	sk->sk_ack_backlog = 0;
+	sk->sk_max_ack_backlog = backlog;
+out:
+	release_sock(sk);
+	return err;
+}
+
+static int pn_socket_sendmsg(struct kiocb *iocb, struct socket *sock,
+				struct msghdr *m, size_t total_len)
+{
+	struct sock *sk = sock->sk;
+
+	if (pn_socket_autobind(sock))
+		return -EAGAIN;
+
+	return sk->sk_prot->sendmsg(iocb, sk, m, total_len);
+}
+
+const struct proto_ops phonet_dgram_ops = {
+	.family		= AF_PHONET,
+	.owner		= THIS_MODULE,
+	.release	= pn_socket_release,
+	.bind		= pn_socket_bind,
+	.connect	= sock_no_connect,
+	.socketpair	= sock_no_socketpair,
+	.accept		= sock_no_accept,
+	.getname	= pn_socket_getname,
+	.poll		= datagram_poll,
+	.ioctl		= pn_socket_ioctl,
+	.listen		= sock_no_listen,
+	.shutdown	= sock_no_shutdown,
+	.setsockopt	= sock_no_setsockopt,
+	.getsockopt	= sock_no_getsockopt,
+#ifdef CONFIG_COMPAT
+	.compat_setsockopt = sock_no_setsockopt,
+	.compat_getsockopt = sock_no_getsockopt,
+#endif
+	.sendmsg	= pn_socket_sendmsg,
+	.recvmsg	= sock_common_recvmsg,
+	.mmap		= sock_no_mmap,
+	.sendpage	= sock_no_sendpage,
+};
+
+const struct proto_ops phonet_stream_ops = {
+	.family		= AF_PHONET,
+	.owner		= THIS_MODULE,
+	.release	= pn_socket_release,
+	.bind		= pn_socket_bind,
+	.connect	= sock_no_connect,
+	.socketpair	= sock_no_socketpair,
+	.accept		= pn_socket_accept,
+	.getname	= pn_socket_getname,
+	.poll		= pn_socket_poll,
+	.ioctl		= pn_socket_ioctl,
+	.listen		= pn_socket_listen,
+	.shutdown	= sock_no_shutdown,
+	.setsockopt	= sock_common_setsockopt,
+	.getsockopt	= sock_common_getsockopt,
+#ifdef CONFIG_COMPAT
+	.compat_setsockopt = compat_sock_common_setsockopt,
+	.compat_getsockopt = compat_sock_common_getsockopt,
+#endif
+	.sendmsg	= pn_socket_sendmsg,
+	.recvmsg	= sock_common_recvmsg,
+	.mmap		= sock_no_mmap,
+	.sendpage	= sock_no_sendpage,
+};
+EXPORT_SYMBOL(phonet_stream_ops);
+
+static DEFINE_MUTEX(port_mutex);
+
+/* allocate port for a socket */
+int pn_sock_get_port(struct sock *sk, unsigned short sport)
+{
+	static int port_cur;
+	struct pn_sock *pn = pn_sk(sk);
+	struct sockaddr_pn try_sa;
+	struct sock *tmpsk;
+
+	memset(&try_sa, 0, sizeof(struct sockaddr_pn));
+	try_sa.spn_family = AF_PHONET;
+
+	mutex_lock(&port_mutex);
+
+	if (!sport) {
+		/* search free port */
+		int port, pmin, pmax;
+
+		phonet_get_local_port_range(&pmin, &pmax);
+		for (port = pmin; port <= pmax; port++) {
+			port_cur++;
+			if (port_cur < pmin || port_cur > pmax)
+				port_cur = pmin;
+
+			pn_sockaddr_set_port(&try_sa, port_cur);
+			tmpsk = pn_find_sock_by_sa(&try_sa);
+			if (tmpsk == NULL) {
+				sport = port_cur;
+				goto found;
+			} else
+				sock_put(tmpsk);
+		}
+	} else {
+		/* try to find specific port */
+		pn_sockaddr_set_port(&try_sa, sport);
+		tmpsk = pn_find_sock_by_sa(&try_sa);
+		if (tmpsk == NULL)
+			/* No sock there! We can use that port... */
+			goto found;
+		else
+			sock_put(tmpsk);
+	}
+	mutex_unlock(&port_mutex);
+
+	/* the port must be in use already */
+	return -EADDRINUSE;
+
+found:
+	mutex_unlock(&port_mutex);
+	pn->sobject = pn_object(pn_addr(pn->sobject), sport);
+	return 0;
+}
+EXPORT_SYMBOL(pn_sock_get_port);
diff --git a/net/phonet/sysctl.c b/net/phonet/sysctl.c
new file mode 100644
index 0000000..600a430
--- /dev/null
+++ b/net/phonet/sysctl.c
@@ -0,0 +1,113 @@
+/*
+ * File: sysctl.c
+ *
+ * Phonet /proc/sys/net/phonet interface implementation
+ *
+ * Copyright (C) 2008 Nokia Corporation.
+ *
+ * Contact: Remi Denis-Courmont <remi.denis-courmont@nokia.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.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include <linux/seqlock.h>
+#include <linux/sysctl.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+
+#define DYNAMIC_PORT_MIN	0x40
+#define DYNAMIC_PORT_MAX	0x7f
+
+static DEFINE_SEQLOCK(local_port_range_lock);
+static int local_port_range_min[2] = {0, 0};
+static int local_port_range_max[2] = {1023, 1023};
+static int local_port_range[2] = {DYNAMIC_PORT_MIN, DYNAMIC_PORT_MAX};
+static struct ctl_table_header *phonet_table_hrd;
+
+static void set_local_port_range(int range[2])
+{
+	write_seqlock(&local_port_range_lock);
+	local_port_range[0] = range[0];
+	local_port_range[1] = range[1];
+	write_sequnlock(&local_port_range_lock);
+}
+
+void phonet_get_local_port_range(int *min, int *max)
+{
+	unsigned seq;
+	do {
+		seq = read_seqbegin(&local_port_range_lock);
+		if (min)
+			*min = local_port_range[0];
+		if (max)
+			*max = local_port_range[1];
+	} while (read_seqretry(&local_port_range_lock, seq));
+}
+
+static int proc_local_port_range(ctl_table *table, int write, struct file *filp,
+				void __user *buffer,
+				size_t *lenp, loff_t *ppos)
+{
+	int ret;
+	int range[2] = {local_port_range[0], local_port_range[1]};
+	ctl_table tmp = {
+		.data = &range,
+		.maxlen = sizeof(range),
+		.mode = table->mode,
+		.extra1 = &local_port_range_min,
+		.extra2 = &local_port_range_max,
+	};
+
+	ret = proc_dointvec_minmax(&tmp, write, filp, buffer, lenp, ppos);
+
+	if (write && ret == 0) {
+		if (range[1] < range[0])
+			ret = -EINVAL;
+		else
+			set_local_port_range(range);
+	}
+
+	return ret;
+}
+
+static struct ctl_table phonet_table[] = {
+	{
+		.ctl_name	= CTL_UNNUMBERED,
+		.procname	= "local_port_range",
+		.data		= &local_port_range,
+		.maxlen		= sizeof(local_port_range),
+		.mode		= 0644,
+		.proc_handler	= &proc_local_port_range,
+		.strategy	= NULL,
+	},
+	{ .ctl_name = 0 }
+};
+
+struct ctl_path phonet_ctl_path[] = {
+	{ .procname = "net", .ctl_name = CTL_NET, },
+	{ .procname = "phonet", .ctl_name = CTL_UNNUMBERED, },
+	{ },
+};
+
+int __init phonet_sysctl_init(void)
+{
+	phonet_table_hrd = register_sysctl_paths(phonet_ctl_path, phonet_table);
+	return phonet_table_hrd == NULL ? -ENOMEM : 0;
+}
+
+void phonet_sysctl_exit(void)
+{
+	unregister_sysctl_table(phonet_table_hrd);
+}
diff --git a/net/rfkill/rfkill-input.c b/net/rfkill/rfkill-input.c
index e5b6955..21124ec 100644
--- a/net/rfkill/rfkill-input.c
+++ b/net/rfkill/rfkill-input.c
@@ -16,6 +16,7 @@
 #include <linux/workqueue.h>
 #include <linux/init.h>
 #include <linux/rfkill.h>
+#include <linux/sched.h>
 
 #include "rfkill-input.h"
 
diff --git a/net/rfkill/rfkill-input.h b/net/rfkill/rfkill-input.h
index f63d050..bbfa646 100644
--- a/net/rfkill/rfkill-input.h
+++ b/net/rfkill/rfkill-input.h
@@ -13,5 +13,6 @@
 
 void rfkill_switch_all(enum rfkill_type type, enum rfkill_state state);
 void rfkill_epo(void);
+void rfkill_restore_states(void);
 
 #endif /* __RFKILL_INPUT_H */
diff --git a/net/rfkill/rfkill.c b/net/rfkill/rfkill.c
index 74aecc0..f949a48 100644
--- a/net/rfkill/rfkill.c
+++ b/net/rfkill/rfkill.c
@@ -37,14 +37,20 @@
 MODULE_LICENSE("GPL");
 
 static LIST_HEAD(rfkill_list);	/* list of registered rf switches */
-static DEFINE_MUTEX(rfkill_mutex);
+static DEFINE_MUTEX(rfkill_global_mutex);
 
 static unsigned int rfkill_default_state = RFKILL_STATE_UNBLOCKED;
 module_param_named(default_state, rfkill_default_state, uint, 0444);
 MODULE_PARM_DESC(default_state,
 		 "Default initial state for all radio types, 0 = radio off");
 
-static enum rfkill_state rfkill_states[RFKILL_TYPE_MAX];
+struct rfkill_gsw_state {
+	enum rfkill_state current_state;
+	enum rfkill_state default_state;
+};
+
+static struct rfkill_gsw_state rfkill_global_states[RFKILL_TYPE_MAX];
+static unsigned long rfkill_states_lockdflt[BITS_TO_LONGS(RFKILL_TYPE_MAX)];
 
 static BLOCKING_NOTIFIER_HEAD(rfkill_notifier_list);
 
@@ -70,6 +76,7 @@
  */
 int register_rfkill_notifier(struct notifier_block *nb)
 {
+	BUG_ON(!nb);
 	return blocking_notifier_chain_register(&rfkill_notifier_list, nb);
 }
 EXPORT_SYMBOL_GPL(register_rfkill_notifier);
@@ -85,6 +92,7 @@
  */
 int unregister_rfkill_notifier(struct notifier_block *nb)
 {
+	BUG_ON(!nb);
 	return blocking_notifier_chain_unregister(&rfkill_notifier_list, nb);
 }
 EXPORT_SYMBOL_GPL(unregister_rfkill_notifier);
@@ -117,6 +125,7 @@
 
 static void notify_rfkill_state_change(struct rfkill *rfkill)
 {
+	rfkill_led_trigger(rfkill, rfkill->state);
 	blocking_notifier_call_chain(&rfkill_notifier_list,
 			RFKILL_STATE_CHANGED,
 			rfkill);
@@ -195,6 +204,11 @@
 		 * BLOCK even a transmitter that is already in state
 		 * RFKILL_STATE_HARD_BLOCKED */
 		break;
+	default:
+		WARN(1, KERN_WARNING
+			"rfkill: illegal state %d passed as parameter "
+			"to rfkill_toggle_radio\n", state);
+		return -EINVAL;
 	}
 
 	if (force || state != rfkill->state) {
@@ -204,31 +218,36 @@
 			rfkill->state = state;
 	}
 
-	if (force || rfkill->state != oldstate) {
-		rfkill_led_trigger(rfkill, rfkill->state);
+	if (force || rfkill->state != oldstate)
 		notify_rfkill_state_change(rfkill);
-	}
 
 	return retval;
 }
 
 /**
- * rfkill_switch_all - Toggle state of all switches of given type
+ * __rfkill_switch_all - Toggle state of all switches of given type
  * @type: type of interfaces to be affected
  * @state: the new state
  *
  * This function toggles the state of all switches of given type,
  * unless a specific switch is claimed by userspace (in which case,
  * that switch is left alone) or suspended.
+ *
+ * Caller must have acquired rfkill_global_mutex.
  */
-void rfkill_switch_all(enum rfkill_type type, enum rfkill_state state)
+static void __rfkill_switch_all(const enum rfkill_type type,
+				const enum rfkill_state state)
 {
 	struct rfkill *rfkill;
 
-	mutex_lock(&rfkill_mutex);
+	if (WARN((state >= RFKILL_STATE_MAX || type >= RFKILL_TYPE_MAX),
+			KERN_WARNING
+			"rfkill: illegal state %d or type %d "
+			"passed as parameter to __rfkill_switch_all\n",
+			state, type))
+		return;
 
-	rfkill_states[type] = state;
-
+	rfkill_global_states[type].current_state = state;
 	list_for_each_entry(rfkill, &rfkill_list, node) {
 		if ((!rfkill->user_claim) && (rfkill->type == type)) {
 			mutex_lock(&rfkill->mutex);
@@ -236,8 +255,21 @@
 			mutex_unlock(&rfkill->mutex);
 		}
 	}
+}
 
-	mutex_unlock(&rfkill_mutex);
+/**
+ * rfkill_switch_all - Toggle state of all switches of given type
+ * @type: type of interfaces to be affected
+ * @state: the new state
+ *
+ * Acquires rfkill_global_mutex and calls __rfkill_switch_all(@type, @state).
+ * Please refer to __rfkill_switch_all() for details.
+ */
+void rfkill_switch_all(enum rfkill_type type, enum rfkill_state state)
+{
+	mutex_lock(&rfkill_global_mutex);
+	__rfkill_switch_all(type, state);
+	mutex_unlock(&rfkill_global_mutex);
 }
 EXPORT_SYMBOL(rfkill_switch_all);
 
@@ -245,23 +277,53 @@
  * rfkill_epo - emergency power off all transmitters
  *
  * This kicks all non-suspended rfkill devices to RFKILL_STATE_SOFT_BLOCKED,
- * ignoring everything in its path but rfkill_mutex and rfkill->mutex.
+ * ignoring everything in its path but rfkill_global_mutex and rfkill->mutex.
+ *
+ * The global state before the EPO is saved and can be restored later
+ * using rfkill_restore_states().
  */
 void rfkill_epo(void)
 {
 	struct rfkill *rfkill;
+	int i;
 
-	mutex_lock(&rfkill_mutex);
+	mutex_lock(&rfkill_global_mutex);
+
 	list_for_each_entry(rfkill, &rfkill_list, node) {
 		mutex_lock(&rfkill->mutex);
 		rfkill_toggle_radio(rfkill, RFKILL_STATE_SOFT_BLOCKED, 1);
 		mutex_unlock(&rfkill->mutex);
 	}
-	mutex_unlock(&rfkill_mutex);
+	for (i = 0; i < RFKILL_TYPE_MAX; i++) {
+		rfkill_global_states[i].default_state =
+				rfkill_global_states[i].current_state;
+		rfkill_global_states[i].current_state =
+				RFKILL_STATE_SOFT_BLOCKED;
+	}
+	mutex_unlock(&rfkill_global_mutex);
 }
 EXPORT_SYMBOL_GPL(rfkill_epo);
 
 /**
+ * rfkill_restore_states - restore global states
+ *
+ * Restore (and sync switches to) the global state from the
+ * states in rfkill_default_states.  This can undo the effects of
+ * a call to rfkill_epo().
+ */
+void rfkill_restore_states(void)
+{
+	int i;
+
+	mutex_lock(&rfkill_global_mutex);
+
+	for (i = 0; i < RFKILL_TYPE_MAX; i++)
+		__rfkill_switch_all(i, rfkill_global_states[i].default_state);
+	mutex_unlock(&rfkill_global_mutex);
+}
+EXPORT_SYMBOL_GPL(rfkill_restore_states);
+
+/**
  * rfkill_force_state - Force the internal rfkill radio state
  * @rfkill: pointer to the rfkill class to modify.
  * @state: the current radio state the class should be forced to.
@@ -282,9 +344,11 @@
 {
 	enum rfkill_state oldstate;
 
-	if (state != RFKILL_STATE_SOFT_BLOCKED &&
-	    state != RFKILL_STATE_UNBLOCKED &&
-	    state != RFKILL_STATE_HARD_BLOCKED)
+	BUG_ON(!rfkill);
+	if (WARN((state >= RFKILL_STATE_MAX),
+			KERN_WARNING
+			"rfkill: illegal state %d passed as parameter "
+			"to rfkill_force_state\n", state))
 		return -EINVAL;
 
 	mutex_lock(&rfkill->mutex);
@@ -352,12 +416,16 @@
 				  const char *buf, size_t count)
 {
 	struct rfkill *rfkill = to_rfkill(dev);
-	unsigned int state = simple_strtoul(buf, NULL, 0);
+	unsigned long state;
 	int error;
 
 	if (!capable(CAP_NET_ADMIN))
 		return -EPERM;
 
+	error = strict_strtoul(buf, 0, &state);
+	if (error)
+		return error;
+
 	/* RFKILL_STATE_HARD_BLOCKED is illegal here... */
 	if (state != RFKILL_STATE_UNBLOCKED &&
 	    state != RFKILL_STATE_SOFT_BLOCKED)
@@ -385,7 +453,8 @@
 				  const char *buf, size_t count)
 {
 	struct rfkill *rfkill = to_rfkill(dev);
-	bool claim = !!simple_strtoul(buf, NULL, 0);
+	unsigned long claim_tmp;
+	bool claim;
 	int error;
 
 	if (!capable(CAP_NET_ADMIN))
@@ -394,11 +463,16 @@
 	if (rfkill->user_claim_unsupported)
 		return -EOPNOTSUPP;
 
+	error = strict_strtoul(buf, 0, &claim_tmp);
+	if (error)
+		return error;
+	claim = !!claim_tmp;
+
 	/*
 	 * Take the global lock to make sure the kernel is not in
 	 * the middle of rfkill_switch_all
 	 */
-	error = mutex_lock_interruptible(&rfkill_mutex);
+	error = mutex_lock_interruptible(&rfkill_global_mutex);
 	if (error)
 		return error;
 
@@ -406,14 +480,14 @@
 		if (!claim) {
 			mutex_lock(&rfkill->mutex);
 			rfkill_toggle_radio(rfkill,
-					    rfkill_states[rfkill->type],
-					    0);
+					rfkill_global_states[rfkill->type].current_state,
+					0);
 			mutex_unlock(&rfkill->mutex);
 		}
 		rfkill->user_claim = claim;
 	}
 
-	mutex_unlock(&rfkill_mutex);
+	mutex_unlock(&rfkill_global_mutex);
 
 	return error ? error : count;
 }
@@ -437,21 +511,9 @@
 #ifdef CONFIG_PM
 static int rfkill_suspend(struct device *dev, pm_message_t state)
 {
-	struct rfkill *rfkill = to_rfkill(dev);
-
-	if (dev->power.power_state.event != state.event) {
-		if (state.event & PM_EVENT_SLEEP) {
-			/* Stop transmitter, keep state, no notifies */
-			update_rfkill_state(rfkill);
-
-			mutex_lock(&rfkill->mutex);
-			rfkill->toggle_radio(rfkill->data,
-						RFKILL_STATE_SOFT_BLOCKED);
-			mutex_unlock(&rfkill->mutex);
-		}
-
+	/* mark class device as suspended */
+	if (dev->power.power_state.event != state.event)
 		dev->power.power_state = state;
-	}
 
 	return 0;
 }
@@ -525,24 +587,60 @@
 	.dev_uevent	= rfkill_dev_uevent,
 };
 
+static int rfkill_check_duplicity(const struct rfkill *rfkill)
+{
+	struct rfkill *p;
+	unsigned long seen[BITS_TO_LONGS(RFKILL_TYPE_MAX)];
+
+	memset(seen, 0, sizeof(seen));
+
+	list_for_each_entry(p, &rfkill_list, node) {
+		if (WARN((p == rfkill), KERN_WARNING
+				"rfkill: illegal attempt to register "
+				"an already registered rfkill struct\n"))
+			return -EEXIST;
+		set_bit(p->type, seen);
+	}
+
+	/* 0: first switch of its kind */
+	return test_bit(rfkill->type, seen);
+}
+
 static int rfkill_add_switch(struct rfkill *rfkill)
 {
-	mutex_lock(&rfkill_mutex);
+	int error;
 
-	rfkill_toggle_radio(rfkill, rfkill_states[rfkill->type], 0);
+	mutex_lock(&rfkill_global_mutex);
+
+	error = rfkill_check_duplicity(rfkill);
+	if (error < 0)
+		goto unlock_out;
+
+	if (!error) {
+		/* lock default after first use */
+		set_bit(rfkill->type, rfkill_states_lockdflt);
+		rfkill_global_states[rfkill->type].current_state =
+			rfkill_global_states[rfkill->type].default_state;
+	}
+
+	rfkill_toggle_radio(rfkill,
+			    rfkill_global_states[rfkill->type].current_state,
+			    0);
 
 	list_add_tail(&rfkill->node, &rfkill_list);
 
-	mutex_unlock(&rfkill_mutex);
+	error = 0;
+unlock_out:
+	mutex_unlock(&rfkill_global_mutex);
 
-	return 0;
+	return error;
 }
 
 static void rfkill_remove_switch(struct rfkill *rfkill)
 {
-	mutex_lock(&rfkill_mutex);
+	mutex_lock(&rfkill_global_mutex);
 	list_del_init(&rfkill->node);
-	mutex_unlock(&rfkill_mutex);
+	mutex_unlock(&rfkill_global_mutex);
 
 	mutex_lock(&rfkill->mutex);
 	rfkill_toggle_radio(rfkill, RFKILL_STATE_SOFT_BLOCKED, 1);
@@ -562,11 +660,18 @@
  * NOTE: If registration fails the structure shoudl be freed by calling
  * rfkill_free() otherwise rfkill_unregister() should be used.
  */
-struct rfkill *rfkill_allocate(struct device *parent, enum rfkill_type type)
+struct rfkill * __must_check rfkill_allocate(struct device *parent,
+					     enum rfkill_type type)
 {
 	struct rfkill *rfkill;
 	struct device *dev;
 
+	if (WARN((type >= RFKILL_TYPE_MAX),
+			KERN_WARNING
+			"rfkill: illegal type %d passed as parameter "
+			"to rfkill_allocate\n", type))
+		return NULL;
+
 	rfkill = kzalloc(sizeof(struct rfkill), GFP_KERNEL);
 	if (!rfkill)
 		return NULL;
@@ -633,15 +738,18 @@
  * structure needs to be registered. Immediately from registration the
  * switch driver should be able to service calls to toggle_radio.
  */
-int rfkill_register(struct rfkill *rfkill)
+int __must_check rfkill_register(struct rfkill *rfkill)
 {
 	static atomic_t rfkill_no = ATOMIC_INIT(0);
 	struct device *dev = &rfkill->dev;
 	int error;
 
-	if (!rfkill->toggle_radio)
-		return -EINVAL;
-	if (rfkill->type >= RFKILL_TYPE_MAX)
+	if (WARN((!rfkill || !rfkill->toggle_radio ||
+			rfkill->type >= RFKILL_TYPE_MAX ||
+			rfkill->state >= RFKILL_STATE_MAX),
+			KERN_WARNING
+			"rfkill: attempt to register a "
+			"badly initialized rfkill struct\n"))
 		return -EINVAL;
 
 	snprintf(dev->bus_id, sizeof(dev->bus_id),
@@ -676,6 +784,7 @@
  */
 void rfkill_unregister(struct rfkill *rfkill)
 {
+	BUG_ON(!rfkill);
 	device_del(&rfkill->dev);
 	rfkill_remove_switch(rfkill);
 	rfkill_led_trigger_unregister(rfkill);
@@ -683,6 +792,56 @@
 }
 EXPORT_SYMBOL(rfkill_unregister);
 
+/**
+ * rfkill_set_default - set initial value for a switch type
+ * @type - the type of switch to set the default state of
+ * @state - the new default state for that group of switches
+ *
+ * Sets the initial state rfkill should use for a given type.
+ * The following initial states are allowed: RFKILL_STATE_SOFT_BLOCKED
+ * and RFKILL_STATE_UNBLOCKED.
+ *
+ * This function is meant to be used by platform drivers for platforms
+ * that can save switch state across power down/reboot.
+ *
+ * The default state for each switch type can be changed exactly once.
+ * After a switch of that type is registered, the default state cannot
+ * be changed anymore.  This guards against multiple drivers it the
+ * same platform trying to set the initial switch default state, which
+ * is not allowed.
+ *
+ * Returns -EPERM if the state has already been set once or is in use,
+ * so drivers likely want to either ignore or at most printk(KERN_NOTICE)
+ * if this function returns -EPERM.
+ *
+ * Returns 0 if the new default state was set, or an error if it
+ * could not be set.
+ */
+int rfkill_set_default(enum rfkill_type type, enum rfkill_state state)
+{
+	int error;
+
+	if (WARN((type >= RFKILL_TYPE_MAX ||
+			(state != RFKILL_STATE_SOFT_BLOCKED &&
+			 state != RFKILL_STATE_UNBLOCKED)),
+			KERN_WARNING
+			"rfkill: illegal state %d or type %d passed as "
+			"parameter to rfkill_set_default\n", state, type))
+		return -EINVAL;
+
+	mutex_lock(&rfkill_global_mutex);
+
+	if (!test_and_set_bit(type, rfkill_states_lockdflt)) {
+		rfkill_global_states[type].default_state = state;
+		error = 0;
+	} else
+		error = -EPERM;
+
+	mutex_unlock(&rfkill_global_mutex);
+	return error;
+}
+EXPORT_SYMBOL_GPL(rfkill_set_default);
+
 /*
  * Rfkill module initialization/deinitialization.
  */
@@ -696,8 +855,8 @@
 	    rfkill_default_state != RFKILL_STATE_UNBLOCKED)
 		return -EINVAL;
 
-	for (i = 0; i < ARRAY_SIZE(rfkill_states); i++)
-		rfkill_states[i] = rfkill_default_state;
+	for (i = 0; i < RFKILL_TYPE_MAX; i++)
+		rfkill_global_states[i].default_state = rfkill_default_state;
 
 	error = class_register(&rfkill_class);
 	if (error) {
diff --git a/net/sched/Kconfig b/net/sched/Kconfig
index 9437b27..6767e54 100644
--- a/net/sched/Kconfig
+++ b/net/sched/Kconfig
@@ -106,6 +106,15 @@
 	  To compile this code as a module, choose M here: the
 	  module will be called sch_prio.
 
+config NET_SCH_MULTIQ
+	tristate "Hardware Multiqueue-aware Multi Band Queuing (MULTIQ)"
+	---help---
+	  Say Y here if you want to use an n-band queue packet scheduler
+	  to support devices that have multiple hardware transmit queues.
+
+	  To compile this code as a module, choose M here: the
+	  module will be called sch_multiq.
+
 config NET_SCH_RED
 	tristate "Random Early Detection (RED)"
 	---help---
@@ -476,6 +485,17 @@
 	  To compile this code as a module, choose M here: the
 	  module will be called simple.
 
+config NET_ACT_SKBEDIT
+        tristate "SKB Editing"
+        depends on NET_CLS_ACT
+        ---help---
+	  Say Y here to change skb priority or queue_mapping settings.
+
+	  If unsure, say N.
+
+	  To compile this code as a module, choose M here: the
+	  module will be called skbedit.
+
 config NET_CLS_IND
 	bool "Incoming device classification"
 	depends on NET_CLS_U32 || NET_CLS_FW
diff --git a/net/sched/Makefile b/net/sched/Makefile
index 1d2b0f7..e60c992 100644
--- a/net/sched/Makefile
+++ b/net/sched/Makefile
@@ -14,6 +14,7 @@
 obj-$(CONFIG_NET_ACT_NAT)	+= act_nat.o
 obj-$(CONFIG_NET_ACT_PEDIT)	+= act_pedit.o
 obj-$(CONFIG_NET_ACT_SIMP)	+= act_simple.o
+obj-$(CONFIG_NET_ACT_SKBEDIT)	+= act_skbedit.o
 obj-$(CONFIG_NET_SCH_FIFO)	+= sch_fifo.o
 obj-$(CONFIG_NET_SCH_CBQ)	+= sch_cbq.o
 obj-$(CONFIG_NET_SCH_HTB)	+= sch_htb.o
@@ -26,6 +27,7 @@
 obj-$(CONFIG_NET_SCH_TBF)	+= sch_tbf.o
 obj-$(CONFIG_NET_SCH_TEQL)	+= sch_teql.o
 obj-$(CONFIG_NET_SCH_PRIO)	+= sch_prio.o
+obj-$(CONFIG_NET_SCH_MULTIQ)	+= sch_multiq.o
 obj-$(CONFIG_NET_SCH_ATM)	+= sch_atm.o
 obj-$(CONFIG_NET_SCH_NETEM)	+= sch_netem.o
 obj-$(CONFIG_NET_CLS_U32)	+= cls_u32.o
diff --git a/net/sched/act_ipt.c b/net/sched/act_ipt.c
index d1263b3..0453d79 100644
--- a/net/sched/act_ipt.c
+++ b/net/sched/act_ipt.c
@@ -40,6 +40,7 @@
 
 static int ipt_init_target(struct ipt_entry_target *t, char *table, unsigned int hook)
 {
+	struct xt_tgchk_param par;
 	struct xt_target *target;
 	int ret = 0;
 
@@ -49,29 +50,30 @@
 		return -ENOENT;
 
 	t->u.kernel.target = target;
+	par.table     = table;
+	par.entryinfo = NULL;
+	par.target    = target;
+	par.targinfo  = t->data;
+	par.hook_mask = hook;
+	par.family    = NFPROTO_IPV4;
 
-	ret = xt_check_target(target, AF_INET, t->u.target_size - sizeof(*t),
-			      table, hook, 0, 0);
-	if (ret) {
+	ret = xt_check_target(&par, t->u.target_size - sizeof(*t), 0, false);
+	if (ret < 0) {
 		module_put(t->u.kernel.target->me);
 		return ret;
 	}
-	if (t->u.kernel.target->checkentry
-	    && !t->u.kernel.target->checkentry(table, NULL,
-					       t->u.kernel.target, t->data,
-					       hook)) {
-		module_put(t->u.kernel.target->me);
-		ret = -EINVAL;
-	}
-
-	return ret;
+	return 0;
 }
 
 static void ipt_destroy_target(struct ipt_entry_target *t)
 {
-	if (t->u.kernel.target->destroy)
-		t->u.kernel.target->destroy(t->u.kernel.target, t->data);
-	module_put(t->u.kernel.target->me);
+	struct xt_tgdtor_param par = {
+		.target   = t->u.kernel.target,
+		.targinfo = t->data,
+	};
+	if (par.target->destroy != NULL)
+		par.target->destroy(&par);
+	module_put(par.target->me);
 }
 
 static int tcf_ipt_release(struct tcf_ipt *ipt, int bind)
@@ -196,6 +198,7 @@
 {
 	int ret = 0, result = 0;
 	struct tcf_ipt *ipt = a->priv;
+	struct xt_target_param par;
 
 	if (skb_cloned(skb)) {
 		if (pskb_expand_head(skb, 0, 0, GFP_ATOMIC))
@@ -211,10 +214,13 @@
 	/* yes, we have to worry about both in and out dev
 	 worry later - danger - this API seems to have changed
 	 from earlier kernels */
-	ret = ipt->tcfi_t->u.kernel.target->target(skb, skb->dev, NULL,
-						   ipt->tcfi_hook,
-						   ipt->tcfi_t->u.kernel.target,
-						   ipt->tcfi_t->data);
+	par.in       = skb->dev;
+	par.out      = NULL;
+	par.hooknum  = ipt->tcfi_hook;
+	par.target   = ipt->tcfi_t->u.kernel.target;
+	par.targinfo = ipt->tcfi_t->data;
+	ret = par.target->target(skb, &par);
+
 	switch (ret) {
 	case NF_ACCEPT:
 		result = TC_ACT_OK;
diff --git a/net/sched/act_skbedit.c b/net/sched/act_skbedit.c
new file mode 100644
index 0000000..fe9777e
--- /dev/null
+++ b/net/sched/act_skbedit.c
@@ -0,0 +1,203 @@
+/*
+ * Copyright (c) 2008, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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.
+ *
+ * Author: Alexander Duyck <alexander.h.duyck@intel.com>
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/skbuff.h>
+#include <linux/rtnetlink.h>
+#include <net/netlink.h>
+#include <net/pkt_sched.h>
+
+#include <linux/tc_act/tc_skbedit.h>
+#include <net/tc_act/tc_skbedit.h>
+
+#define SKBEDIT_TAB_MASK     15
+static struct tcf_common *tcf_skbedit_ht[SKBEDIT_TAB_MASK + 1];
+static u32 skbedit_idx_gen;
+static DEFINE_RWLOCK(skbedit_lock);
+
+static struct tcf_hashinfo skbedit_hash_info = {
+	.htab	=	tcf_skbedit_ht,
+	.hmask	=	SKBEDIT_TAB_MASK,
+	.lock	=	&skbedit_lock,
+};
+
+static int tcf_skbedit(struct sk_buff *skb, struct tc_action *a,
+		       struct tcf_result *res)
+{
+	struct tcf_skbedit *d = a->priv;
+
+	spin_lock(&d->tcf_lock);
+	d->tcf_tm.lastuse = jiffies;
+	d->tcf_bstats.bytes += qdisc_pkt_len(skb);
+	d->tcf_bstats.packets++;
+
+	if (d->flags & SKBEDIT_F_PRIORITY)
+		skb->priority = d->priority;
+	if (d->flags & SKBEDIT_F_QUEUE_MAPPING &&
+	    skb->dev->real_num_tx_queues > d->queue_mapping)
+		skb_set_queue_mapping(skb, d->queue_mapping);
+
+	spin_unlock(&d->tcf_lock);
+	return d->tcf_action;
+}
+
+static const struct nla_policy skbedit_policy[TCA_SKBEDIT_MAX + 1] = {
+	[TCA_SKBEDIT_PARMS]		= { .len = sizeof(struct tc_skbedit) },
+	[TCA_SKBEDIT_PRIORITY]		= { .len = sizeof(u32) },
+	[TCA_SKBEDIT_QUEUE_MAPPING]	= { .len = sizeof(u16) },
+};
+
+static int tcf_skbedit_init(struct nlattr *nla, struct nlattr *est,
+			 struct tc_action *a, int ovr, int bind)
+{
+	struct nlattr *tb[TCA_SKBEDIT_MAX + 1];
+	struct tc_skbedit *parm;
+	struct tcf_skbedit *d;
+	struct tcf_common *pc;
+	u32 flags = 0, *priority = NULL;
+	u16 *queue_mapping = NULL;
+	int ret = 0, err;
+
+	if (nla == NULL)
+		return -EINVAL;
+
+	err = nla_parse_nested(tb, TCA_SKBEDIT_MAX, nla, skbedit_policy);
+	if (err < 0)
+		return err;
+
+	if (tb[TCA_SKBEDIT_PARMS] == NULL)
+		return -EINVAL;
+
+	if (tb[TCA_SKBEDIT_PRIORITY] != NULL) {
+		flags |= SKBEDIT_F_PRIORITY;
+		priority = nla_data(tb[TCA_SKBEDIT_PRIORITY]);
+	}
+
+	if (tb[TCA_SKBEDIT_QUEUE_MAPPING] != NULL) {
+		flags |= SKBEDIT_F_QUEUE_MAPPING;
+		queue_mapping = nla_data(tb[TCA_SKBEDIT_QUEUE_MAPPING]);
+	}
+	if (!flags)
+		return -EINVAL;
+
+	parm = nla_data(tb[TCA_SKBEDIT_PARMS]);
+
+	pc = tcf_hash_check(parm->index, a, bind, &skbedit_hash_info);
+	if (!pc) {
+		pc = tcf_hash_create(parm->index, est, a, sizeof(*d), bind,
+				     &skbedit_idx_gen, &skbedit_hash_info);
+		if (unlikely(!pc))
+			return -ENOMEM;
+
+		d = to_skbedit(pc);
+		ret = ACT_P_CREATED;
+	} else {
+		d = to_skbedit(pc);
+		if (!ovr) {
+			tcf_hash_release(pc, bind, &skbedit_hash_info);
+			return -EEXIST;
+		}
+	}
+
+	spin_lock_bh(&d->tcf_lock);
+
+	d->flags = flags;
+	if (flags & SKBEDIT_F_PRIORITY)
+		d->priority = *priority;
+	if (flags & SKBEDIT_F_QUEUE_MAPPING)
+		d->queue_mapping = *queue_mapping;
+	d->tcf_action = parm->action;
+
+	spin_unlock_bh(&d->tcf_lock);
+
+	if (ret == ACT_P_CREATED)
+		tcf_hash_insert(pc, &skbedit_hash_info);
+	return ret;
+}
+
+static inline int tcf_skbedit_cleanup(struct tc_action *a, int bind)
+{
+	struct tcf_skbedit *d = a->priv;
+
+	if (d)
+		return tcf_hash_release(&d->common, bind, &skbedit_hash_info);
+	return 0;
+}
+
+static inline int tcf_skbedit_dump(struct sk_buff *skb, struct tc_action *a,
+				int bind, int ref)
+{
+	unsigned char *b = skb_tail_pointer(skb);
+	struct tcf_skbedit *d = a->priv;
+	struct tc_skbedit opt;
+	struct tcf_t t;
+
+	opt.index = d->tcf_index;
+	opt.refcnt = d->tcf_refcnt - ref;
+	opt.bindcnt = d->tcf_bindcnt - bind;
+	opt.action = d->tcf_action;
+	NLA_PUT(skb, TCA_SKBEDIT_PARMS, sizeof(opt), &opt);
+	if (d->flags & SKBEDIT_F_PRIORITY)
+		NLA_PUT(skb, TCA_SKBEDIT_PRIORITY, sizeof(d->priority),
+			&d->priority);
+	if (d->flags & SKBEDIT_F_QUEUE_MAPPING)
+		NLA_PUT(skb, TCA_SKBEDIT_QUEUE_MAPPING,
+			sizeof(d->queue_mapping), &d->queue_mapping);
+	t.install = jiffies_to_clock_t(jiffies - d->tcf_tm.install);
+	t.lastuse = jiffies_to_clock_t(jiffies - d->tcf_tm.lastuse);
+	t.expires = jiffies_to_clock_t(d->tcf_tm.expires);
+	NLA_PUT(skb, TCA_SKBEDIT_TM, sizeof(t), &t);
+	return skb->len;
+
+nla_put_failure:
+	nlmsg_trim(skb, b);
+	return -1;
+}
+
+static struct tc_action_ops act_skbedit_ops = {
+	.kind		=	"skbedit",
+	.hinfo		=	&skbedit_hash_info,
+	.type		=	TCA_ACT_SKBEDIT,
+	.capab		=	TCA_CAP_NONE,
+	.owner		=	THIS_MODULE,
+	.act		=	tcf_skbedit,
+	.dump		=	tcf_skbedit_dump,
+	.cleanup	=	tcf_skbedit_cleanup,
+	.init		=	tcf_skbedit_init,
+	.walk		=	tcf_generic_walker,
+};
+
+MODULE_AUTHOR("Alexander Duyck, <alexander.h.duyck@intel.com>");
+MODULE_DESCRIPTION("SKB Editing");
+MODULE_LICENSE("GPL");
+
+static int __init skbedit_init_module(void)
+{
+	return tcf_register_action(&act_skbedit_ops);
+}
+
+static void __exit skbedit_cleanup_module(void)
+{
+	tcf_unregister_action(&act_skbedit_ops);
+}
+
+module_init(skbedit_init_module);
+module_exit(skbedit_cleanup_module);
diff --git a/net/sched/cls_flow.c b/net/sched/cls_flow.c
index 8f63a1a..0ebaff6 100644
--- a/net/sched/cls_flow.c
+++ b/net/sched/cls_flow.c
@@ -67,9 +67,9 @@
 static u32 flow_get_src(const struct sk_buff *skb)
 {
 	switch (skb->protocol) {
-	case __constant_htons(ETH_P_IP):
+	case htons(ETH_P_IP):
 		return ntohl(ip_hdr(skb)->saddr);
-	case __constant_htons(ETH_P_IPV6):
+	case htons(ETH_P_IPV6):
 		return ntohl(ipv6_hdr(skb)->saddr.s6_addr32[3]);
 	default:
 		return addr_fold(skb->sk);
@@ -79,9 +79,9 @@
 static u32 flow_get_dst(const struct sk_buff *skb)
 {
 	switch (skb->protocol) {
-	case __constant_htons(ETH_P_IP):
+	case htons(ETH_P_IP):
 		return ntohl(ip_hdr(skb)->daddr);
-	case __constant_htons(ETH_P_IPV6):
+	case htons(ETH_P_IPV6):
 		return ntohl(ipv6_hdr(skb)->daddr.s6_addr32[3]);
 	default:
 		return addr_fold(skb->dst) ^ (__force u16)skb->protocol;
@@ -91,9 +91,9 @@
 static u32 flow_get_proto(const struct sk_buff *skb)
 {
 	switch (skb->protocol) {
-	case __constant_htons(ETH_P_IP):
+	case htons(ETH_P_IP):
 		return ip_hdr(skb)->protocol;
-	case __constant_htons(ETH_P_IPV6):
+	case htons(ETH_P_IPV6):
 		return ipv6_hdr(skb)->nexthdr;
 	default:
 		return 0;
@@ -120,7 +120,7 @@
 	u32 res = 0;
 
 	switch (skb->protocol) {
-	case __constant_htons(ETH_P_IP): {
+	case htons(ETH_P_IP): {
 		struct iphdr *iph = ip_hdr(skb);
 
 		if (!(iph->frag_off&htons(IP_MF|IP_OFFSET)) &&
@@ -128,7 +128,7 @@
 			res = ntohs(*(__be16 *)((void *)iph + iph->ihl * 4));
 		break;
 	}
-	case __constant_htons(ETH_P_IPV6): {
+	case htons(ETH_P_IPV6): {
 		struct ipv6hdr *iph = ipv6_hdr(skb);
 
 		if (has_ports(iph->nexthdr))
@@ -147,7 +147,7 @@
 	u32 res = 0;
 
 	switch (skb->protocol) {
-	case __constant_htons(ETH_P_IP): {
+	case htons(ETH_P_IP): {
 		struct iphdr *iph = ip_hdr(skb);
 
 		if (!(iph->frag_off&htons(IP_MF|IP_OFFSET)) &&
@@ -155,7 +155,7 @@
 			res = ntohs(*(__be16 *)((void *)iph + iph->ihl * 4 + 2));
 		break;
 	}
-	case __constant_htons(ETH_P_IPV6): {
+	case htons(ETH_P_IPV6): {
 		struct ipv6hdr *iph = ipv6_hdr(skb);
 
 		if (has_ports(iph->nexthdr))
@@ -213,9 +213,9 @@
 static u32 flow_get_nfct_src(const struct sk_buff *skb)
 {
 	switch (skb->protocol) {
-	case __constant_htons(ETH_P_IP):
+	case htons(ETH_P_IP):
 		return ntohl(CTTUPLE(skb, src.u3.ip));
-	case __constant_htons(ETH_P_IPV6):
+	case htons(ETH_P_IPV6):
 		return ntohl(CTTUPLE(skb, src.u3.ip6[3]));
 	}
 fallback:
@@ -225,9 +225,9 @@
 static u32 flow_get_nfct_dst(const struct sk_buff *skb)
 {
 	switch (skb->protocol) {
-	case __constant_htons(ETH_P_IP):
+	case htons(ETH_P_IP):
 		return ntohl(CTTUPLE(skb, dst.u3.ip));
-	case __constant_htons(ETH_P_IPV6):
+	case htons(ETH_P_IPV6):
 		return ntohl(CTTUPLE(skb, dst.u3.ip6[3]));
 	}
 fallback:
diff --git a/net/sched/em_cmp.c b/net/sched/em_cmp.c
index cc49c93..bc45039 100644
--- a/net/sched/em_cmp.c
+++ b/net/sched/em_cmp.c
@@ -14,6 +14,7 @@
 #include <linux/kernel.h>
 #include <linux/skbuff.h>
 #include <linux/tc_ematch/tc_em_cmp.h>
+#include <asm/unaligned.h>
 #include <net/pkt_cls.h>
 
 static inline int cmp_needs_transformation(struct tcf_em_cmp *cmp)
@@ -37,8 +38,7 @@
 			break;
 
 		case TCF_EM_ALIGN_U16:
-			val = *ptr << 8;
-			val |= *(ptr+1);
+			val = get_unaligned_be16(ptr);
 
 			if (cmp_needs_transformation(cmp))
 				val = be16_to_cpu(val);
@@ -47,10 +47,7 @@
 		case TCF_EM_ALIGN_U32:
 			/* Worth checking boundries? The branching seems
 			 * to get worse. Visit again. */
-			val = *ptr << 24;
-			val |= *(ptr+1) << 16;
-			val |= *(ptr+2) << 8;
-			val |= *(ptr+3);
+			val = get_unaligned_be32(ptr);
 
 			if (cmp_needs_transformation(cmp))
 				val = be32_to_cpu(val);
diff --git a/net/sched/sch_dsmark.c b/net/sched/sch_dsmark.c
index edd1298..ba43aab 100644
--- a/net/sched/sch_dsmark.c
+++ b/net/sched/sch_dsmark.c
@@ -202,7 +202,7 @@
 
 	if (p->set_tc_index) {
 		switch (skb->protocol) {
-		case __constant_htons(ETH_P_IP):
+		case htons(ETH_P_IP):
 			if (skb_cow_head(skb, sizeof(struct iphdr)))
 				goto drop;
 
@@ -210,7 +210,7 @@
 				& ~INET_ECN_MASK;
 			break;
 
-		case __constant_htons(ETH_P_IPV6):
+		case htons(ETH_P_IPV6):
 			if (skb_cow_head(skb, sizeof(struct ipv6hdr)))
 				goto drop;
 
@@ -289,11 +289,11 @@
 	pr_debug("index %d->%d\n", skb->tc_index, index);
 
 	switch (skb->protocol) {
-	case __constant_htons(ETH_P_IP):
+	case htons(ETH_P_IP):
 		ipv4_change_dsfield(ip_hdr(skb), p->mask[index],
 				    p->value[index]);
 			break;
-	case __constant_htons(ETH_P_IPV6):
+	case htons(ETH_P_IPV6):
 		ipv6_change_dsfield(ipv6_hdr(skb), p->mask[index],
 				    p->value[index]);
 			break;
diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c
index 9634091..7b5572d 100644
--- a/net/sched/sch_generic.c
+++ b/net/sched/sch_generic.c
@@ -44,23 +44,30 @@
 
 static inline int dev_requeue_skb(struct sk_buff *skb, struct Qdisc *q)
 {
-	if (unlikely(skb->next))
-		q->gso_skb = skb;
-	else
-		q->ops->requeue(skb, q);
-
+	q->gso_skb = skb;
+	q->qstats.requeues++;
 	__netif_schedule(q);
+
 	return 0;
 }
 
 static inline struct sk_buff *dequeue_skb(struct Qdisc *q)
 {
-	struct sk_buff *skb;
+	struct sk_buff *skb = q->gso_skb;
 
-	if ((skb = q->gso_skb))
-		q->gso_skb = NULL;
-	else
+	if (unlikely(skb)) {
+		struct net_device *dev = qdisc_dev(q);
+		struct netdev_queue *txq;
+
+		/* check the reason of requeuing without tx lock first */
+		txq = netdev_get_tx_queue(dev, skb_get_queue_mapping(skb));
+		if (!netif_tx_queue_stopped(txq) && !netif_tx_queue_frozen(txq))
+			q->gso_skb = NULL;
+		else
+			skb = NULL;
+	} else {
 		skb = q->dequeue(q);
+	}
 
 	return skb;
 }
@@ -215,10 +222,9 @@
 			    time_after(jiffies, (dev->trans_start +
 						 dev->watchdog_timeo))) {
 				char drivername[64];
-				printk(KERN_INFO "NETDEV WATCHDOG: %s (%s): transmit timed out\n",
+				WARN_ONCE(1, KERN_INFO "NETDEV WATCHDOG: %s (%s): transmit timed out\n",
 				       dev->name, netdev_drivername(dev, drivername, 64));
 				dev->tx_timeout(dev);
-				WARN_ON_ONCE(1);
 			}
 			if (!mod_timer(&dev->watchdog_timer,
 				       round_jiffies(jiffies +
@@ -328,6 +334,7 @@
 	.flags		=	TCQ_F_BUILTIN,
 	.ops		=	&noop_qdisc_ops,
 	.list		=	LIST_HEAD_INIT(noop_qdisc.list),
+	.requeue.lock	=	__SPIN_LOCK_UNLOCKED(noop_qdisc.q.lock),
 	.q.lock		=	__SPIN_LOCK_UNLOCKED(noop_qdisc.q.lock),
 	.dev_queue	=	&noop_netdev_queue,
 };
@@ -353,6 +360,7 @@
 	.flags		=	TCQ_F_BUILTIN,
 	.ops		=	&noqueue_qdisc_ops,
 	.list		=	LIST_HEAD_INIT(noqueue_qdisc.list),
+	.requeue.lock	=	__SPIN_LOCK_UNLOCKED(noqueue_qdisc.q.lock),
 	.q.lock		=	__SPIN_LOCK_UNLOCKED(noqueue_qdisc.q.lock),
 	.dev_queue	=	&noqueue_netdev_queue,
 };
@@ -473,6 +481,7 @@
 	sch->padded = (char *) sch - (char *) p;
 
 	INIT_LIST_HEAD(&sch->list);
+	skb_queue_head_init(&sch->requeue);
 	skb_queue_head_init(&sch->q);
 	sch->ops = ops;
 	sch->enqueue = ops->enqueue;
@@ -541,6 +550,7 @@
 	dev_put(qdisc_dev(qdisc));
 
 	kfree_skb(qdisc->gso_skb);
+	__skb_queue_purge(&qdisc->requeue);
 
 	kfree((char *) qdisc - qdisc->padded);
 }
diff --git a/net/sched/sch_multiq.c b/net/sched/sch_multiq.c
new file mode 100644
index 0000000..915f314
--- /dev/null
+++ b/net/sched/sch_multiq.c
@@ -0,0 +1,477 @@
+/*
+ * Copyright (c) 2008, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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.
+ *
+ * Author: Alexander Duyck <alexander.h.duyck@intel.com>
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/skbuff.h>
+#include <net/netlink.h>
+#include <net/pkt_sched.h>
+
+
+struct multiq_sched_data {
+	u16 bands;
+	u16 max_bands;
+	u16 curband;
+	struct tcf_proto *filter_list;
+	struct Qdisc **queues;
+};
+
+
+static struct Qdisc *
+multiq_classify(struct sk_buff *skb, struct Qdisc *sch, int *qerr)
+{
+	struct multiq_sched_data *q = qdisc_priv(sch);
+	u32 band;
+	struct tcf_result res;
+	int err;
+
+	*qerr = NET_XMIT_SUCCESS | __NET_XMIT_BYPASS;
+	err = tc_classify(skb, q->filter_list, &res);
+#ifdef CONFIG_NET_CLS_ACT
+	switch (err) {
+	case TC_ACT_STOLEN:
+	case TC_ACT_QUEUED:
+		*qerr = NET_XMIT_SUCCESS | __NET_XMIT_STOLEN;
+	case TC_ACT_SHOT:
+		return NULL;
+	}
+#endif
+	band = skb_get_queue_mapping(skb);
+
+	if (band >= q->bands)
+		return q->queues[0];
+
+	return q->queues[band];
+}
+
+static int
+multiq_enqueue(struct sk_buff *skb, struct Qdisc *sch)
+{
+	struct Qdisc *qdisc;
+	int ret;
+
+	qdisc = multiq_classify(skb, sch, &ret);
+#ifdef CONFIG_NET_CLS_ACT
+	if (qdisc == NULL) {
+
+		if (ret & __NET_XMIT_BYPASS)
+			sch->qstats.drops++;
+		kfree_skb(skb);
+		return ret;
+	}
+#endif
+
+	ret = qdisc_enqueue(skb, qdisc);
+	if (ret == NET_XMIT_SUCCESS) {
+		sch->bstats.bytes += qdisc_pkt_len(skb);
+		sch->bstats.packets++;
+		sch->q.qlen++;
+		return NET_XMIT_SUCCESS;
+	}
+	if (net_xmit_drop_count(ret))
+		sch->qstats.drops++;
+	return ret;
+}
+
+
+static int
+multiq_requeue(struct sk_buff *skb, struct Qdisc *sch)
+{
+	struct Qdisc *qdisc;
+	struct multiq_sched_data *q = qdisc_priv(sch);
+	int ret;
+
+	qdisc = multiq_classify(skb, sch, &ret);
+#ifdef CONFIG_NET_CLS_ACT
+	if (qdisc == NULL) {
+		if (ret & __NET_XMIT_BYPASS)
+			sch->qstats.drops++;
+		kfree_skb(skb);
+		return ret;
+	}
+#endif
+
+	ret = qdisc->ops->requeue(skb, qdisc);
+	if (ret == NET_XMIT_SUCCESS) {
+		sch->q.qlen++;
+		sch->qstats.requeues++;
+		if (q->curband)
+			q->curband--;
+		else
+			q->curband = q->bands - 1;
+		return NET_XMIT_SUCCESS;
+	}
+	if (net_xmit_drop_count(ret))
+		sch->qstats.drops++;
+	return ret;
+}
+
+
+static struct sk_buff *multiq_dequeue(struct Qdisc *sch)
+{
+	struct multiq_sched_data *q = qdisc_priv(sch);
+	struct Qdisc *qdisc;
+	struct sk_buff *skb;
+	int band;
+
+	for (band = 0; band < q->bands; band++) {
+		/* cycle through bands to ensure fairness */
+		q->curband++;
+		if (q->curband >= q->bands)
+			q->curband = 0;
+
+		/* Check that target subqueue is available before
+		 * pulling an skb to avoid excessive requeues
+		 */
+		if (!__netif_subqueue_stopped(qdisc_dev(sch), q->curband)) {
+			qdisc = q->queues[q->curband];
+			skb = qdisc->dequeue(qdisc);
+			if (skb) {
+				sch->q.qlen--;
+				return skb;
+			}
+		}
+	}
+	return NULL;
+
+}
+
+static unsigned int multiq_drop(struct Qdisc *sch)
+{
+	struct multiq_sched_data *q = qdisc_priv(sch);
+	int band;
+	unsigned int len;
+	struct Qdisc *qdisc;
+
+	for (band = q->bands-1; band >= 0; band--) {
+		qdisc = q->queues[band];
+		if (qdisc->ops->drop) {
+			len = qdisc->ops->drop(qdisc);
+			if (len != 0) {
+				sch->q.qlen--;
+				return len;
+			}
+		}
+	}
+	return 0;
+}
+
+
+static void
+multiq_reset(struct Qdisc *sch)
+{
+	u16 band;
+	struct multiq_sched_data *q = qdisc_priv(sch);
+
+	for (band = 0; band < q->bands; band++)
+		qdisc_reset(q->queues[band]);
+	sch->q.qlen = 0;
+	q->curband = 0;
+}
+
+static void
+multiq_destroy(struct Qdisc *sch)
+{
+	int band;
+	struct multiq_sched_data *q = qdisc_priv(sch);
+
+	tcf_destroy_chain(&q->filter_list);
+	for (band = 0; band < q->bands; band++)
+		qdisc_destroy(q->queues[band]);
+
+	kfree(q->queues);
+}
+
+static int multiq_tune(struct Qdisc *sch, struct nlattr *opt)
+{
+	struct multiq_sched_data *q = qdisc_priv(sch);
+	struct tc_multiq_qopt *qopt;
+	int i;
+
+	if (!netif_is_multiqueue(qdisc_dev(sch)))
+		return -EINVAL;
+	if (nla_len(opt) < sizeof(*qopt))
+		return -EINVAL;
+
+	qopt = nla_data(opt);
+
+	qopt->bands = qdisc_dev(sch)->real_num_tx_queues;
+
+	sch_tree_lock(sch);
+	q->bands = qopt->bands;
+	for (i = q->bands; i < q->max_bands; i++) {
+		if (q->queues[i] != &noop_qdisc) {
+			struct Qdisc *child = xchg(&q->queues[i], &noop_qdisc);
+			qdisc_tree_decrease_qlen(child, child->q.qlen);
+			qdisc_destroy(child);
+		}
+	}
+
+	sch_tree_unlock(sch);
+
+	for (i = 0; i < q->bands; i++) {
+		if (q->queues[i] == &noop_qdisc) {
+			struct Qdisc *child;
+			child = qdisc_create_dflt(qdisc_dev(sch),
+						  sch->dev_queue,
+						  &pfifo_qdisc_ops,
+						  TC_H_MAKE(sch->handle,
+							    i + 1));
+			if (child) {
+				sch_tree_lock(sch);
+				child = xchg(&q->queues[i], child);
+
+				if (child != &noop_qdisc) {
+					qdisc_tree_decrease_qlen(child,
+								 child->q.qlen);
+					qdisc_destroy(child);
+				}
+				sch_tree_unlock(sch);
+			}
+		}
+	}
+	return 0;
+}
+
+static int multiq_init(struct Qdisc *sch, struct nlattr *opt)
+{
+	struct multiq_sched_data *q = qdisc_priv(sch);
+	int i, err;
+
+	q->queues = NULL;
+
+	if (opt == NULL)
+		return -EINVAL;
+
+	q->max_bands = qdisc_dev(sch)->num_tx_queues;
+
+	q->queues = kcalloc(q->max_bands, sizeof(struct Qdisc *), GFP_KERNEL);
+	if (!q->queues)
+		return -ENOBUFS;
+	for (i = 0; i < q->max_bands; i++)
+		q->queues[i] = &noop_qdisc;
+
+	err = multiq_tune(sch,opt);
+
+	if (err)
+		kfree(q->queues);
+
+	return err;
+}
+
+static int multiq_dump(struct Qdisc *sch, struct sk_buff *skb)
+{
+	struct multiq_sched_data *q = qdisc_priv(sch);
+	unsigned char *b = skb_tail_pointer(skb);
+	struct tc_multiq_qopt opt;
+
+	opt.bands = q->bands;
+	opt.max_bands = q->max_bands;
+
+	NLA_PUT(skb, TCA_OPTIONS, sizeof(opt), &opt);
+
+	return skb->len;
+
+nla_put_failure:
+	nlmsg_trim(skb, b);
+	return -1;
+}
+
+static int multiq_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new,
+		      struct Qdisc **old)
+{
+	struct multiq_sched_data *q = qdisc_priv(sch);
+	unsigned long band = arg - 1;
+
+	if (band >= q->bands)
+		return -EINVAL;
+
+	if (new == NULL)
+		new = &noop_qdisc;
+
+	sch_tree_lock(sch);
+	*old = q->queues[band];
+	q->queues[band] = new;
+	qdisc_tree_decrease_qlen(*old, (*old)->q.qlen);
+	qdisc_reset(*old);
+	sch_tree_unlock(sch);
+
+	return 0;
+}
+
+static struct Qdisc *
+multiq_leaf(struct Qdisc *sch, unsigned long arg)
+{
+	struct multiq_sched_data *q = qdisc_priv(sch);
+	unsigned long band = arg - 1;
+
+	if (band >= q->bands)
+		return NULL;
+
+	return q->queues[band];
+}
+
+static unsigned long multiq_get(struct Qdisc *sch, u32 classid)
+{
+	struct multiq_sched_data *q = qdisc_priv(sch);
+	unsigned long band = TC_H_MIN(classid);
+
+	if (band - 1 >= q->bands)
+		return 0;
+	return band;
+}
+
+static unsigned long multiq_bind(struct Qdisc *sch, unsigned long parent,
+				 u32 classid)
+{
+	return multiq_get(sch, classid);
+}
+
+
+static void multiq_put(struct Qdisc *q, unsigned long cl)
+{
+	return;
+}
+
+static int multiq_change(struct Qdisc *sch, u32 handle, u32 parent,
+			 struct nlattr **tca, unsigned long *arg)
+{
+	unsigned long cl = *arg;
+	struct multiq_sched_data *q = qdisc_priv(sch);
+
+	if (cl - 1 > q->bands)
+		return -ENOENT;
+	return 0;
+}
+
+static int multiq_delete(struct Qdisc *sch, unsigned long cl)
+{
+	struct multiq_sched_data *q = qdisc_priv(sch);
+	if (cl - 1 > q->bands)
+		return -ENOENT;
+	return 0;
+}
+
+
+static int multiq_dump_class(struct Qdisc *sch, unsigned long cl,
+			     struct sk_buff *skb, struct tcmsg *tcm)
+{
+	struct multiq_sched_data *q = qdisc_priv(sch);
+
+	if (cl - 1 > q->bands)
+		return -ENOENT;
+	tcm->tcm_handle |= TC_H_MIN(cl);
+	if (q->queues[cl-1])
+		tcm->tcm_info = q->queues[cl-1]->handle;
+	return 0;
+}
+
+static int multiq_dump_class_stats(struct Qdisc *sch, unsigned long cl,
+				 struct gnet_dump *d)
+{
+	struct multiq_sched_data *q = qdisc_priv(sch);
+	struct Qdisc *cl_q;
+
+	cl_q = q->queues[cl - 1];
+	if (gnet_stats_copy_basic(d, &cl_q->bstats) < 0 ||
+	    gnet_stats_copy_queue(d, &cl_q->qstats) < 0)
+		return -1;
+
+	return 0;
+}
+
+static void multiq_walk(struct Qdisc *sch, struct qdisc_walker *arg)
+{
+	struct multiq_sched_data *q = qdisc_priv(sch);
+	int band;
+
+	if (arg->stop)
+		return;
+
+	for (band = 0; band < q->bands; band++) {
+		if (arg->count < arg->skip) {
+			arg->count++;
+			continue;
+		}
+		if (arg->fn(sch, band+1, arg) < 0) {
+			arg->stop = 1;
+			break;
+		}
+		arg->count++;
+	}
+}
+
+static struct tcf_proto **multiq_find_tcf(struct Qdisc *sch, unsigned long cl)
+{
+	struct multiq_sched_data *q = qdisc_priv(sch);
+
+	if (cl)
+		return NULL;
+	return &q->filter_list;
+}
+
+static const struct Qdisc_class_ops multiq_class_ops = {
+	.graft		=	multiq_graft,
+	.leaf		=	multiq_leaf,
+	.get		=	multiq_get,
+	.put		=	multiq_put,
+	.change		=	multiq_change,
+	.delete		=	multiq_delete,
+	.walk		=	multiq_walk,
+	.tcf_chain	=	multiq_find_tcf,
+	.bind_tcf	=	multiq_bind,
+	.unbind_tcf	=	multiq_put,
+	.dump		=	multiq_dump_class,
+	.dump_stats	=	multiq_dump_class_stats,
+};
+
+static struct Qdisc_ops multiq_qdisc_ops __read_mostly = {
+	.next		=	NULL,
+	.cl_ops		=	&multiq_class_ops,
+	.id		=	"multiq",
+	.priv_size	=	sizeof(struct multiq_sched_data),
+	.enqueue	=	multiq_enqueue,
+	.dequeue	=	multiq_dequeue,
+	.requeue	=	multiq_requeue,
+	.drop		=	multiq_drop,
+	.init		=	multiq_init,
+	.reset		=	multiq_reset,
+	.destroy	=	multiq_destroy,
+	.change		=	multiq_tune,
+	.dump		=	multiq_dump,
+	.owner		=	THIS_MODULE,
+};
+
+static int __init multiq_module_init(void)
+{
+	return register_qdisc(&multiq_qdisc_ops);
+}
+
+static void __exit multiq_module_exit(void)
+{
+	unregister_qdisc(&multiq_qdisc_ops);
+}
+
+module_init(multiq_module_init)
+module_exit(multiq_module_exit)
+
+MODULE_LICENSE("GPL");
diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c
index 3781e55..a119599 100644
--- a/net/sched/sch_netem.c
+++ b/net/sched/sch_netem.c
@@ -388,6 +388,20 @@
 	[TCA_NETEM_CORRUPT]	= { .len = sizeof(struct tc_netem_corrupt) },
 };
 
+static int parse_attr(struct nlattr *tb[], int maxtype, struct nlattr *nla,
+		      const struct nla_policy *policy, int len)
+{
+	int nested_len = nla_len(nla) - NLA_ALIGN(len);
+
+	if (nested_len < 0)
+		return -EINVAL;
+	if (nested_len >= nla_attr_size(0))
+		return nla_parse(tb, maxtype, nla_data(nla) + NLA_ALIGN(len),
+				 nested_len, policy);
+	memset(tb, 0, sizeof(struct nlattr *) * (maxtype + 1));
+	return 0;
+}
+
 /* Parse netlink message to set options */
 static int netem_change(struct Qdisc *sch, struct nlattr *opt)
 {
@@ -399,8 +413,8 @@
 	if (opt == NULL)
 		return -EINVAL;
 
-	ret = nla_parse_nested_compat(tb, TCA_NETEM_MAX, opt, netem_policy,
-				      qopt, sizeof(*qopt));
+	qopt = nla_data(opt);
+	ret = parse_attr(tb, TCA_NETEM_MAX, opt, netem_policy, sizeof(*qopt));
 	if (ret < 0)
 		return ret;
 
diff --git a/net/sched/sch_prio.c b/net/sched/sch_prio.c
index a6697c6..504a78c 100644
--- a/net/sched/sch_prio.c
+++ b/net/sched/sch_prio.c
@@ -254,16 +254,12 @@
 {
 	struct prio_sched_data *q = qdisc_priv(sch);
 	unsigned char *b = skb_tail_pointer(skb);
-	struct nlattr *nest;
 	struct tc_prio_qopt opt;
 
 	opt.bands = q->bands;
 	memcpy(&opt.priomap, q->prio2band, TC_PRIO_MAX+1);
 
-	nest = nla_nest_compat_start(skb, TCA_OPTIONS, sizeof(opt), &opt);
-	if (nest == NULL)
-		goto nla_put_failure;
-	nla_nest_compat_end(skb, nest);
+	NLA_PUT(skb, TCA_OPTIONS, sizeof(opt), &opt);
 
 	return skb->len;
 
diff --git a/net/sched/sch_sfq.c b/net/sched/sch_sfq.c
index 6e041d1..fe1508e 100644
--- a/net/sched/sch_sfq.c
+++ b/net/sched/sch_sfq.c
@@ -119,7 +119,7 @@
 	u32 h, h2;
 
 	switch (skb->protocol) {
-	case __constant_htons(ETH_P_IP):
+	case htons(ETH_P_IP):
 	{
 		const struct iphdr *iph = ip_hdr(skb);
 		h = iph->daddr;
@@ -134,7 +134,7 @@
 			h2 ^= *(((u32*)iph) + iph->ihl);
 		break;
 	}
-	case __constant_htons(ETH_P_IPV6):
+	case htons(ETH_P_IPV6):
 	{
 		struct ipv6hdr *iph = ipv6_hdr(skb);
 		h = iph->daddr.s6_addr32[3];
diff --git a/net/sctp/associola.c b/net/sctp/associola.c
index 8472b8b..f4b2304 100644
--- a/net/sctp/associola.c
+++ b/net/sctp/associola.c
@@ -283,8 +283,7 @@
 	if (!sctp_ulpq_init(&asoc->ulpq, asoc))
 		goto fail_init;
 
-	/* Set up the tsn tracking. */
-	sctp_tsnmap_init(&asoc->peer.tsn_map, SCTP_TSN_MAP_SIZE, 0);
+	memset(&asoc->peer.tsn_map, 0, sizeof(struct sctp_tsnmap));
 
 	asoc->need_ecne = 0;
 
@@ -402,6 +401,8 @@
 	/* Dispose of any pending chunks on the inqueue. */
 	sctp_inq_free(&asoc->base.inqueue);
 
+	sctp_tsnmap_free(&asoc->peer.tsn_map);
+
 	/* Free ssnmap storage. */
 	sctp_ssnmap_free(asoc->ssnmap);
 
@@ -599,11 +600,12 @@
 	/* Check to see if this is a duplicate. */
 	peer = sctp_assoc_lookup_paddr(asoc, addr);
 	if (peer) {
+		/* An UNKNOWN state is only set on transports added by
+		 * user in sctp_connectx() call.  Such transports should be
+		 * considered CONFIRMED per RFC 4960, Section 5.4.
+		 */
 		if (peer->state == SCTP_UNKNOWN) {
-			if (peer_state == SCTP_ACTIVE)
-				peer->state = SCTP_ACTIVE;
-			if (peer_state == SCTP_UNCONFIRMED)
-				peer->state = SCTP_UNCONFIRMED;
+			peer->state = SCTP_ACTIVE;
 		}
 		return peer;
 	}
@@ -1121,8 +1123,8 @@
 	asoc->peer.rwnd = new->peer.rwnd;
 	asoc->peer.sack_needed = new->peer.sack_needed;
 	asoc->peer.i = new->peer.i;
-	sctp_tsnmap_init(&asoc->peer.tsn_map, SCTP_TSN_MAP_SIZE,
-			 asoc->peer.i.initial_tsn);
+	sctp_tsnmap_init(&asoc->peer.tsn_map, SCTP_TSN_MAP_INITIAL,
+			 asoc->peer.i.initial_tsn, GFP_ATOMIC);
 
 	/* Remove any peer addresses not present in the new association. */
 	list_for_each_safe(pos, temp, &asoc->peer.transport_addr_list) {
diff --git a/net/sctp/bind_addr.c b/net/sctp/bind_addr.c
index f62bc24..6d5944a 100644
--- a/net/sctp/bind_addr.c
+++ b/net/sctp/bind_addr.c
@@ -457,7 +457,7 @@
 {
 	int error = 0;
 
-	if (sctp_is_any(addr)) {
+	if (sctp_is_any(NULL, addr)) {
 		error = sctp_copy_local_addr_list(dest, scope, gfp, flags);
 	} else if (sctp_in_scope(addr, scope)) {
 		/* Now that the address is in scope, check to see if
@@ -477,11 +477,21 @@
 }
 
 /* Is this a wildcard address?  */
-int sctp_is_any(const union sctp_addr *addr)
+int sctp_is_any(struct sock *sk, const union sctp_addr *addr)
 {
-	struct sctp_af *af = sctp_get_af_specific(addr->sa.sa_family);
+	unsigned short fam = 0;
+	struct sctp_af *af;
+
+	/* Try to get the right address family */
+	if (addr->sa.sa_family != AF_UNSPEC)
+		fam = addr->sa.sa_family;
+	else if (sk)
+		fam = sk->sk_family;
+
+	af = sctp_get_af_specific(fam);
 	if (!af)
 		return 0;
+
 	return af->is_any(addr);
 }
 
diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c
index 47f91af..4124bbb 100644
--- a/net/sctp/ipv6.c
+++ b/net/sctp/ipv6.c
@@ -156,7 +156,7 @@
 	skb->network_header   = saveip;
 	skb->transport_header = savesctp;
 	if (!sk) {
-		ICMP6_INC_STATS_BH(idev, ICMP6_MIB_INERRORS);
+		ICMP6_INC_STATS_BH(dev_net(skb->dev), idev, ICMP6_MIB_INERRORS);
 		goto out;
 	}
 
@@ -837,6 +837,7 @@
 			       struct sctp_sock *opt)
 {
 	struct sctp_af *af1, *af2;
+	struct sock *sk = sctp_opt2sk(opt);
 
 	af1 = sctp_get_af_specific(addr1->sa.sa_family);
 	af2 = sctp_get_af_specific(addr2->sa.sa_family);
@@ -845,11 +846,11 @@
 		return 0;
 
 	/* If the socket is IPv6 only, v4 addrs will not match */
-	if (__ipv6_only_sock(sctp_opt2sk(opt)) && af1 != af2)
+	if (__ipv6_only_sock(sk) && af1 != af2)
 		return 0;
 
 	/* Today, wildcard AF_INET/AF_INET6. */
-	if (sctp_is_any(addr1) || sctp_is_any(addr2))
+	if (sctp_is_any(sk, addr1) || sctp_is_any(sk, addr2))
 		return 1;
 
 	if (addr1->sa.sa_family != addr2->sa.sa_family)
diff --git a/net/sctp/output.c b/net/sctp/output.c
index 0dc4a7d..c3f417f 100644
--- a/net/sctp/output.c
+++ b/net/sctp/output.c
@@ -533,7 +533,8 @@
 	if (!(dst->dev->features & NETIF_F_NO_CSUM)) {
 		crc32 = sctp_start_cksum((__u8 *)sh, cksum_buf_len);
 		crc32 = sctp_end_cksum(crc32);
-	}
+	} else
+		nskb->ip_summed = CHECKSUM_UNNECESSARY;
 
 	/* 3) Put the resultant value into the checksum field in the
 	 *    common header, and leave the rest of the bits unchanged.
@@ -698,7 +699,7 @@
 	 *    When a Fast Retransmit is being performed the sender SHOULD
 	 *    ignore the value of cwnd and SHOULD NOT delay retransmission.
 	 */
-	if (chunk->fast_retransmit <= 0)
+	if (chunk->fast_retransmit != SCTP_NEED_FRTX)
 		if (transport->flight_size >= transport->cwnd) {
 			retval = SCTP_XMIT_RWND_FULL;
 			goto finish;
diff --git a/net/sctp/outqueue.c b/net/sctp/outqueue.c
index 4328ad5..247ebc9 100644
--- a/net/sctp/outqueue.c
+++ b/net/sctp/outqueue.c
@@ -420,7 +420,7 @@
 		 * be added to the retransmit queue.
 		 */
 		if ((reason == SCTP_RTXR_FAST_RTX  &&
-			    (chunk->fast_retransmit > 0)) ||
+			    (chunk->fast_retransmit == SCTP_NEED_FRTX)) ||
 		    (reason != SCTP_RTXR_FAST_RTX  && !chunk->tsn_gap_acked)) {
 			/* If this chunk was sent less then 1 rto ago, do not
 			 * retransmit this chunk, but give the peer time
@@ -650,8 +650,8 @@
 			/* Mark the chunk as ineligible for fast retransmit
 			 * after it is retransmitted.
 			 */
-			if (chunk->fast_retransmit > 0)
-				chunk->fast_retransmit = -1;
+			if (chunk->fast_retransmit == SCTP_NEED_FRTX)
+				chunk->fast_retransmit = SCTP_DONT_FRTX;
 
 			/* Force start T3-rtx timer when fast retransmitting
 			 * the earliest outstanding TSN
@@ -680,8 +680,8 @@
 	 */
 	if (rtx_timeout || fast_rtx) {
 		list_for_each_entry(chunk1, lqueue, transmitted_list) {
-			if (chunk1->fast_retransmit > 0)
-				chunk1->fast_retransmit = -1;
+			if (chunk1->fast_retransmit == SCTP_NEED_FRTX)
+				chunk1->fast_retransmit = SCTP_DONT_FRTX;
 		}
 	}
 
@@ -1129,12 +1129,13 @@
 	unsigned outstanding;
 	struct sctp_transport *primary = asoc->peer.primary_path;
 	int count_of_newacks = 0;
+	int gap_ack_blocks;
 
 	/* Grab the association's destination address list. */
 	transport_list = &asoc->peer.transport_addr_list;
 
 	sack_ctsn = ntohl(sack->cum_tsn_ack);
-
+	gap_ack_blocks = ntohs(sack->num_gap_ack_blocks);
 	/*
 	 * SFR-CACC algorithm:
 	 * On receipt of a SACK the sender SHOULD execute the
@@ -1144,35 +1145,38 @@
 	 * on the current primary, the CHANGEOVER_ACTIVE flag SHOULD be
 	 * cleared. The CYCLING_CHANGEOVER flag SHOULD also be cleared for
 	 * all destinations.
-	 */
-	if (TSN_lte(primary->cacc.next_tsn_at_change, sack_ctsn)) {
-		primary->cacc.changeover_active = 0;
-		list_for_each_entry(transport, transport_list,
-				transports) {
-			transport->cacc.cycling_changeover = 0;
-		}
-	}
-
-	/*
-	 * SFR-CACC algorithm:
 	 * 2) If the SACK contains gap acks and the flag CHANGEOVER_ACTIVE
 	 * is set the receiver of the SACK MUST take the following actions:
 	 *
 	 * A) Initialize the cacc_saw_newack to 0 for all destination
 	 * addresses.
+	 *
+	 * Only bother if changeover_active is set. Otherwise, this is
+	 * totally suboptimal to do on every SACK.
 	 */
-	if (sack->num_gap_ack_blocks &&
-	    primary->cacc.changeover_active) {
-		list_for_each_entry(transport, transport_list, transports) {
-			transport->cacc.cacc_saw_newack = 0;
+	if (primary->cacc.changeover_active) {
+		u8 clear_cycling = 0;
+
+		if (TSN_lte(primary->cacc.next_tsn_at_change, sack_ctsn)) {
+			primary->cacc.changeover_active = 0;
+			clear_cycling = 1;
+		}
+
+		if (clear_cycling || gap_ack_blocks) {
+			list_for_each_entry(transport, transport_list,
+					transports) {
+				if (clear_cycling)
+					transport->cacc.cycling_changeover = 0;
+				if (gap_ack_blocks)
+					transport->cacc.cacc_saw_newack = 0;
+			}
 		}
 	}
 
 	/* Get the highest TSN in the sack. */
 	highest_tsn = sack_ctsn;
-	if (sack->num_gap_ack_blocks)
-		highest_tsn +=
-		    ntohs(frags[ntohs(sack->num_gap_ack_blocks) - 1].gab.end);
+	if (gap_ack_blocks)
+		highest_tsn += ntohs(frags[gap_ack_blocks - 1].gab.end);
 
 	if (TSN_lt(asoc->highest_sacked, highest_tsn)) {
 		highest_new_tsn = highest_tsn;
@@ -1181,11 +1185,11 @@
 		highest_new_tsn = sctp_highest_new_tsn(sack, asoc);
 	}
 
+
 	/* Run through the retransmit queue.  Credit bytes received
 	 * and free those chunks that we can.
 	 */
 	sctp_check_transmitted(q, &q->retransmit, NULL, sack, highest_new_tsn);
-	sctp_mark_missing(q, &q->retransmit, NULL, highest_new_tsn, 0);
 
 	/* Run through the transmitted queue.
 	 * Credit bytes received and free those chunks which we can.
@@ -1204,9 +1208,10 @@
 			count_of_newacks ++;
 	}
 
-	list_for_each_entry(transport, transport_list, transports) {
-		sctp_mark_missing(q, &transport->transmitted, transport,
-				  highest_new_tsn, count_of_newacks);
+	if (gap_ack_blocks) {
+		list_for_each_entry(transport, transport_list, transports)
+			sctp_mark_missing(q, &transport->transmitted, transport,
+					  highest_new_tsn, count_of_newacks);
 	}
 
 	/* Move the Cumulative TSN Ack Point if appropriate.  */
@@ -1651,7 +1656,7 @@
 		 * chunk if it has NOT been fast retransmitted or marked for
 		 * fast retransmit already.
 		 */
-		if (!chunk->fast_retransmit &&
+		if (chunk->fast_retransmit == SCTP_CAN_FRTX &&
 		    !chunk->tsn_gap_acked &&
 		    TSN_lt(tsn, highest_new_tsn_in_sack)) {
 
@@ -1676,7 +1681,7 @@
 		 */
 
 		if (chunk->tsn_missing_report >= 3) {
-			chunk->fast_retransmit = 1;
+			chunk->fast_retransmit = SCTP_NEED_FRTX;
 			do_fast_retransmit = 1;
 		}
 	}
diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c
index e8ca4e5..fd8acb4 100644
--- a/net/sctp/sm_make_chunk.c
+++ b/net/sctp/sm_make_chunk.c
@@ -702,12 +702,14 @@
 	__u32 ctsn;
 	__u16 num_gabs, num_dup_tsns;
 	struct sctp_tsnmap *map = (struct sctp_tsnmap *)&asoc->peer.tsn_map;
+	struct sctp_gap_ack_block gabs[SCTP_MAX_GABS];
 
+	memset(gabs, 0, sizeof(gabs));
 	ctsn = sctp_tsnmap_get_ctsn(map);
 	SCTP_DEBUG_PRINTK("sackCTSNAck sent:  0x%x.\n", ctsn);
 
 	/* How much room is needed in the chunk? */
-	num_gabs = sctp_tsnmap_num_gabs(map);
+	num_gabs = sctp_tsnmap_num_gabs(map, gabs);
 	num_dup_tsns = sctp_tsnmap_num_dups(map);
 
 	/* Initialize the SACK header.  */
@@ -763,7 +765,7 @@
 	/* Add the gap ack block information.   */
 	if (num_gabs)
 		sctp_addto_chunk(retval, sizeof(__u32) * num_gabs,
-				 sctp_tsnmap_get_gabs(map));
+				 gabs);
 
 	/* Add the duplicate TSN information.  */
 	if (num_dup_tsns)
@@ -1012,6 +1014,29 @@
 	return retval;
 }
 
+struct sctp_chunk *sctp_make_violation_paramlen(
+	const struct sctp_association *asoc,
+	const struct sctp_chunk *chunk,
+	struct sctp_paramhdr *param)
+{
+	struct sctp_chunk *retval;
+	static const char error[] = "The following parameter had invalid length:";
+	size_t payload_len = sizeof(error) + sizeof(sctp_errhdr_t) +
+				sizeof(sctp_paramhdr_t);
+
+	retval = sctp_make_abort(asoc, chunk, payload_len);
+	if (!retval)
+		goto nodata;
+
+	sctp_init_cause(retval, SCTP_ERROR_PROTO_VIOLATION,
+			sizeof(error) + sizeof(sctp_paramhdr_t));
+	sctp_addto_chunk(retval, sizeof(error), error);
+	sctp_addto_param(retval, sizeof(sctp_paramhdr_t), param);
+
+nodata:
+	return retval;
+}
+
 /* Make a HEARTBEAT chunk.  */
 struct sctp_chunk *sctp_make_heartbeat(const struct sctp_association *asoc,
 				  const struct sctp_transport *transport,
@@ -1188,7 +1213,7 @@
 	 */
 	retval->tsn_missing_report = 0;
 	retval->tsn_gap_acked = 0;
-	retval->fast_retransmit = 0;
+	retval->fast_retransmit = SCTP_CAN_FRTX;
 
 	/* If this is a fragmented message, track all fragments
 	 * of the message (for SEND_FAILED).
@@ -1782,11 +1807,6 @@
 					const struct sctp_chunk *chunk,
 					struct sctp_chunk **errp)
 {
-	static const char error[] = "The following parameter had invalid length:";
-	size_t		payload_len = WORD_ROUND(sizeof(error)) +
-						sizeof(sctp_paramhdr_t);
-
-
 	/* This is a fatal error.  Any accumulated non-fatal errors are
 	 * not reported.
 	 */
@@ -1794,14 +1814,7 @@
 		sctp_chunk_free(*errp);
 
 	/* Create an error chunk and fill it in with our payload. */
-	*errp = sctp_make_op_error_space(asoc, chunk, payload_len);
-
-	if (*errp) {
-		sctp_init_cause(*errp, SCTP_ERROR_PROTO_VIOLATION,
-				sizeof(error) + sizeof(sctp_paramhdr_t));
-		sctp_addto_chunk(*errp, sizeof(error), error);
-		sctp_addto_param(*errp, sizeof(sctp_paramhdr_t), param);
-	}
+	*errp = sctp_make_violation_paramlen(asoc, chunk, param);
 
 	return 0;
 }
@@ -1886,11 +1899,13 @@
 			    /* if the peer reports AUTH, assume that he
 			     * supports AUTH.
 			     */
-			    asoc->peer.auth_capable = 1;
+			    if (sctp_auth_enable)
+				    asoc->peer.auth_capable = 1;
 			    break;
 		    case SCTP_CID_ASCONF:
 		    case SCTP_CID_ASCONF_ACK:
-			    asoc->peer.asconf_capable = 1;
+			    if (sctp_addip_enable)
+				    asoc->peer.asconf_capable = 1;
 			    break;
 		    default:
 			    break;
@@ -2275,8 +2290,9 @@
 	}
 
 	/* Set up the TSN tracking pieces.  */
-	sctp_tsnmap_init(&asoc->peer.tsn_map, SCTP_TSN_MAP_SIZE,
-			 asoc->peer.i.initial_tsn);
+	if (!sctp_tsnmap_init(&asoc->peer.tsn_map, SCTP_TSN_MAP_INITIAL,
+				asoc->peer.i.initial_tsn, gfp))
+		goto clean_up;
 
 	/* RFC 2960 6.5 Stream Identifier and Stream Sequence Number
 	 *
@@ -2319,12 +2335,10 @@
 	/* Release the transport structures. */
 	list_for_each_safe(pos, temp, &asoc->peer.transport_addr_list) {
 		transport = list_entry(pos, struct sctp_transport, transports);
-		list_del_init(pos);
-		sctp_transport_free(transport);
+		if (transport->state != SCTP_ACTIVE)
+			sctp_assoc_rm_peer(asoc, transport);
 	}
 
-	asoc->peer.transport_count = 0;
-
 nomem:
 	return 0;
 }
@@ -2456,10 +2470,13 @@
 		break;
 
 	case SCTP_PARAM_ADAPTATION_LAYER_IND:
-		asoc->peer.adaptation_ind = param.aind->adaptation_ind;
+		asoc->peer.adaptation_ind = ntohl(param.aind->adaptation_ind);
 		break;
 
 	case SCTP_PARAM_SET_PRIMARY:
+		if (!sctp_addip_enable)
+			goto fall_through;
+
 		addr_param = param.v + sizeof(sctp_addip_param_t);
 
 		af = sctp_get_af_specific(param_type2af(param.p->type));
diff --git a/net/sctp/sm_sideeffect.c b/net/sctp/sm_sideeffect.c
index 9732c79..e1d6076 100644
--- a/net/sctp/sm_sideeffect.c
+++ b/net/sctp/sm_sideeffect.c
@@ -889,6 +889,35 @@
 		sctp_ulpq_tail_event(&asoc->ulpq, ev);
 }
 
+
+static void sctp_cmd_t1_timer_update(struct sctp_association *asoc,
+				    sctp_event_timeout_t timer,
+				    char *name)
+{
+	struct sctp_transport *t;
+
+	t = asoc->init_last_sent_to;
+	asoc->init_err_counter++;
+
+	if (t->init_sent_count > (asoc->init_cycle + 1)) {
+		asoc->timeouts[timer] *= 2;
+		if (asoc->timeouts[timer] > asoc->max_init_timeo) {
+			asoc->timeouts[timer] = asoc->max_init_timeo;
+		}
+		asoc->init_cycle++;
+		SCTP_DEBUG_PRINTK(
+			"T1 %s Timeout adjustment"
+			" init_err_counter: %d"
+			" cycle: %d"
+			" timeout: %ld\n",
+			name,
+			asoc->init_err_counter,
+			asoc->init_cycle,
+			asoc->timeouts[timer]);
+	}
+
+}
+
 /* These three macros allow us to pull the debugging code out of the
  * main flow of sctp_do_sm() to keep attention focused on the real
  * functionality there.
@@ -1123,7 +1152,8 @@
 
 		case SCTP_CMD_REPORT_TSN:
 			/* Record the arrival of a TSN.  */
-			sctp_tsnmap_mark(&asoc->peer.tsn_map, cmd->obj.u32);
+			error = sctp_tsnmap_mark(&asoc->peer.tsn_map,
+						 cmd->obj.u32);
 			break;
 
 		case SCTP_CMD_REPORT_FWDTSN:
@@ -1196,6 +1226,11 @@
 				sctp_add_cmd_sf(commands, SCTP_CMD_REPLY,
 						SCTP_CHUNK(cmd->obj.ptr));
 
+			if (new_obj->transport) {
+				new_obj->transport->init_sent_count++;
+				asoc->init_last_sent_to = new_obj->transport;
+			}
+
 			/* FIXME - Eventually come up with a cleaner way to
 			 * enabling COOKIE-ECHO + DATA bundling during
 			 * multihoming stale cookie scenarios, the following
@@ -1345,26 +1380,9 @@
 			 * all transports have been tried at the current
 			 * timeout.
 			 */
-			t = asoc->init_last_sent_to;
-			asoc->init_err_counter++;
-
-			if (t->init_sent_count > (asoc->init_cycle + 1)) {
-				asoc->timeouts[SCTP_EVENT_TIMEOUT_T1_INIT] *= 2;
-				if (asoc->timeouts[SCTP_EVENT_TIMEOUT_T1_INIT] >
-				    asoc->max_init_timeo) {
-					asoc->timeouts[SCTP_EVENT_TIMEOUT_T1_INIT] =
-						asoc->max_init_timeo;
-				}
-				asoc->init_cycle++;
-				SCTP_DEBUG_PRINTK(
-					"T1 INIT Timeout adjustment"
-					" init_err_counter: %d"
-					" cycle: %d"
-					" timeout: %ld\n",
-					asoc->init_err_counter,
-					asoc->init_cycle,
-					asoc->timeouts[SCTP_EVENT_TIMEOUT_T1_INIT]);
-			}
+			sctp_cmd_t1_timer_update(asoc,
+						SCTP_EVENT_TIMEOUT_T1_INIT,
+						"INIT");
 
 			sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_RESTART,
 					SCTP_TO(SCTP_EVENT_TIMEOUT_T1_INIT));
@@ -1377,20 +1395,9 @@
 			 * all transports have been tried at the current
 			 * timeout.
 			 */
-			asoc->init_err_counter++;
-
-			asoc->timeouts[SCTP_EVENT_TIMEOUT_T1_COOKIE] *= 2;
-			if (asoc->timeouts[SCTP_EVENT_TIMEOUT_T1_COOKIE] >
-			    asoc->max_init_timeo) {
-				asoc->timeouts[SCTP_EVENT_TIMEOUT_T1_COOKIE] =
-					asoc->max_init_timeo;
-			}
-			SCTP_DEBUG_PRINTK(
-				"T1 COOKIE Timeout adjustment"
-				" init_err_counter: %d"
-				" timeout: %ld\n",
-				asoc->init_err_counter,
-				asoc->timeouts[SCTP_EVENT_TIMEOUT_T1_COOKIE]);
+			sctp_cmd_t1_timer_update(asoc,
+						SCTP_EVENT_TIMEOUT_T1_COOKIE,
+						"COOKIE");
 
 			/* If we've sent any data bundled with
 			 * COOKIE-ECHO we need to resend.
@@ -1422,6 +1429,10 @@
 		case SCTP_CMD_INIT_COUNTER_RESET:
 			asoc->init_err_counter = 0;
 			asoc->init_cycle = 0;
+			list_for_each_entry(t, &asoc->peer.transport_addr_list,
+					    transports) {
+				t->init_sent_count = 0;
+			}
 			break;
 
 		case SCTP_CMD_REPORT_DUP:
diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c
index 8848d32..d4c3fbc 100644
--- a/net/sctp/sm_statefuns.c
+++ b/net/sctp/sm_statefuns.c
@@ -119,7 +119,7 @@
 				     const struct sctp_endpoint *ep,
 				     const struct sctp_association *asoc,
 				     const sctp_subtype_t type,
-				     void *arg,
+				     void *arg, void *ext,
 				     sctp_cmd_seq_t *commands);
 
 static sctp_disposition_t sctp_sf_violation_ctsn(
@@ -315,8 +315,10 @@
 	/* If the packet is an OOTB packet which is temporarily on the
 	 * control endpoint, respond with an ABORT.
 	 */
-	if (ep == sctp_sk((sctp_get_ctl_sock()))->ep)
+	if (ep == sctp_sk((sctp_get_ctl_sock()))->ep) {
+		SCTP_INC_STATS(SCTP_MIB_OUTOFBLUES);
 		return sctp_sf_tabort_8_4_8(ep, asoc, type, arg, commands);
+	}
 
 	/* 3.1 A packet containing an INIT chunk MUST have a zero Verification
 	 * Tag.
@@ -635,8 +637,10 @@
 	/* If the packet is an OOTB packet which is temporarily on the
 	 * control endpoint, respond with an ABORT.
 	 */
-	if (ep == sctp_sk((sctp_get_ctl_sock()))->ep)
+	if (ep == sctp_sk((sctp_get_ctl_sock()))->ep) {
+		SCTP_INC_STATS(SCTP_MIB_OUTOFBLUES);
 		return sctp_sf_tabort_8_4_8(ep, asoc, type, arg, commands);
+	}
 
 	/* Make sure that the COOKIE_ECHO chunk has a valid length.
 	 * In this case, we check that we have enough for at least a
@@ -2076,10 +2080,6 @@
 		    sctp_bind_addr_state(&asoc->base.bind_addr, &chunk->dest))
 		return sctp_sf_discard_chunk(ep, asoc, type, arg, commands);
 
-	/* Stop the T5-shutdown guard timer.  */
-	sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP,
-			SCTP_TO(SCTP_EVENT_TIMEOUT_T5_SHUTDOWN_GUARD));
-
 	return __sctp_sf_do_9_1_abort(ep, asoc, type, arg, commands);
 }
 
@@ -3382,6 +3382,8 @@
 	 * packet and the state function that handles OOTB SHUTDOWN_ACK is
 	 * called with a NULL association.
 	 */
+	SCTP_INC_STATS(SCTP_MIB_OUTOFBLUES);
+
 	return sctp_sf_shut_8_4_5(ep, NULL, type, arg, commands);
 }
 
@@ -3425,7 +3427,7 @@
 	addr_param = (union sctp_addr_param *)hdr->params;
 	length = ntohs(addr_param->p.length);
 	if (length < sizeof(sctp_paramhdr_t))
-		return sctp_sf_violation_paramlen(ep, asoc, type,
+		return sctp_sf_violation_paramlen(ep, asoc, type, arg,
 			   (void *)addr_param, commands);
 
 	/* Verify the ASCONF chunk before processing it. */
@@ -3433,8 +3435,8 @@
 			    (sctp_paramhdr_t *)((void *)addr_param + length),
 			    (void *)chunk->chunk_end,
 			    &err_param))
-		return sctp_sf_violation_paramlen(ep, asoc, type,
-						  (void *)&err_param, commands);
+		return sctp_sf_violation_paramlen(ep, asoc, type, arg,
+						  (void *)err_param, commands);
 
 	/* ADDIP 5.2 E1) Compare the value of the serial number to the value
 	 * the endpoint stored in a new association variable
@@ -3542,8 +3544,8 @@
 	    (sctp_paramhdr_t *)addip_hdr->params,
 	    (void *)asconf_ack->chunk_end,
 	    &err_param))
-		return sctp_sf_violation_paramlen(ep, asoc, type,
-			   (void *)&err_param, commands);
+		return sctp_sf_violation_paramlen(ep, asoc, type, arg,
+			   (void *)err_param, commands);
 
 	if (last_asconf) {
 		addip_hdr = (sctp_addiphdr_t *)last_asconf->subh.addip_hdr;
@@ -4186,11 +4188,10 @@
 		SCTP_INC_STATS(SCTP_MIB_OUTCTRLCHUNKS);
 	}
 
-discard:
-	sctp_sf_pdiscard(ep, asoc, SCTP_ST_CHUNK(0), arg, commands);
-
 	SCTP_INC_STATS(SCTP_MIB_ABORTEDS);
 
+discard:
+	sctp_sf_pdiscard(ep, asoc, SCTP_ST_CHUNK(0), arg, commands);
 	return SCTP_DISPOSITION_ABORT;
 
 nomem_pkt:
@@ -4240,12 +4241,36 @@
 				     const struct sctp_endpoint *ep,
 				     const struct sctp_association *asoc,
 				     const sctp_subtype_t type,
-				     void *arg,
-				     sctp_cmd_seq_t *commands) {
-	static const char err_str[] = "The following parameter had invalid length:";
+				     void *arg, void *ext,
+				     sctp_cmd_seq_t *commands)
+{
+	struct sctp_chunk *chunk =  arg;
+	struct sctp_paramhdr *param = ext;
+	struct sctp_chunk *abort = NULL;
 
-	return sctp_sf_abort_violation(ep, asoc, arg, commands, err_str,
-					sizeof(err_str));
+	if (sctp_auth_recv_cid(SCTP_CID_ABORT, asoc))
+		goto discard;
+
+	/* Make the abort chunk. */
+	abort = sctp_make_violation_paramlen(asoc, chunk, param);
+	if (!abort)
+		goto nomem;
+
+	sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(abort));
+	SCTP_INC_STATS(SCTP_MIB_OUTCTRLCHUNKS);
+
+	sctp_add_cmd_sf(commands, SCTP_CMD_SET_SK_ERR,
+			SCTP_ERROR(ECONNABORTED));
+	sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED,
+			SCTP_PERR(SCTP_ERROR_PROTO_VIOLATION));
+	SCTP_DEC_STATS(SCTP_MIB_CURRESTAB);
+	SCTP_INC_STATS(SCTP_MIB_ABORTEDS);
+
+discard:
+	sctp_sf_pdiscard(ep, asoc, SCTP_ST_CHUNK(0), arg, commands);
+	return SCTP_DISPOSITION_ABORT;
+nomem:
+	return SCTP_DISPOSITION_NOMEM;
 }
 
 /* Handle a protocol violation when the peer trying to advance the
@@ -4517,13 +4542,6 @@
 	sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE,
 			SCTP_STATE(SCTP_STATE_SHUTDOWN_PENDING));
 
-	/* sctpimpguide-05 Section 2.12.2
-	 * The sender of the SHUTDOWN MAY also start an overall guard timer
-	 * 'T5-shutdown-guard' to bound the overall time for shutdown sequence.
-	 */
-	sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_START,
-			SCTP_TO(SCTP_EVENT_TIMEOUT_T5_SHUTDOWN_GUARD));
-
 	disposition = SCTP_DISPOSITION_CONSUME;
 	if (sctp_outq_is_empty(&asoc->outqueue)) {
 		disposition = sctp_sf_do_9_2_start_shutdown(ep, asoc, type,
@@ -4968,6 +4986,13 @@
 	sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_START,
 			SCTP_TO(SCTP_EVENT_TIMEOUT_T2_SHUTDOWN));
 
+	/* RFC 4960 Section 9.2
+	 * The sender of the SHUTDOWN MAY also start an overall guard timer
+	 * 'T5-shutdown-guard' to bound the overall time for shutdown sequence.
+	 */
+	sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_START,
+			SCTP_TO(SCTP_EVENT_TIMEOUT_T5_SHUTDOWN_GUARD));
+
 	if (asoc->autoclose)
 		sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP,
 				SCTP_TO(SCTP_EVENT_TIMEOUT_AUTOCLOSE));
@@ -5279,6 +5304,8 @@
 		if (!repl)
 			return SCTP_DISPOSITION_NOMEM;
 
+		sctp_add_cmd_sf(commands, SCTP_CMD_INIT_CHOOSE_TRANSPORT,
+				SCTP_CHUNK(repl));
 		/* Issue a sideeffect to do the needed accounting. */
 		sctp_add_cmd_sf(commands, SCTP_CMD_COOKIEECHO_RESTART,
 				SCTP_TO(SCTP_EVENT_TIMEOUT_T1_COOKIE));
@@ -5406,7 +5433,7 @@
 		sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED,
 				SCTP_PERR(SCTP_ERROR_NO_ERROR));
 		SCTP_INC_STATS(SCTP_MIB_ABORTEDS);
-		SCTP_INC_STATS(SCTP_MIB_CURRESTAB);
+		SCTP_DEC_STATS(SCTP_MIB_CURRESTAB);
 		return SCTP_DISPOSITION_ABORT;
 	}
 
@@ -5462,6 +5489,9 @@
 	sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED,
 			SCTP_PERR(SCTP_ERROR_NO_ERROR));
 
+	SCTP_INC_STATS(SCTP_MIB_ABORTEDS);
+	SCTP_DEC_STATS(SCTP_MIB_CURRESTAB);
+
 	return SCTP_DISPOSITION_DELETE_TCB;
 nomem:
 	return SCTP_DISPOSITION_NOMEM;
@@ -5494,12 +5524,6 @@
 	sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE,
 			SCTP_STATE(SCTP_STATE_SHUTDOWN_PENDING));
 
-	/* sctpimpguide-05 Section 2.12.2
-	 * The sender of the SHUTDOWN MAY also start an overall guard timer
-	 * 'T5-shutdown-guard' to bound the overall time for shutdown sequence.
-	 */
-	sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_START,
-			SCTP_TO(SCTP_EVENT_TIMEOUT_T5_SHUTDOWN_GUARD));
 	disposition = SCTP_DISPOSITION_CONSUME;
 	if (sctp_outq_is_empty(&asoc->outqueue)) {
 		disposition = sctp_sf_do_9_2_start_shutdown(ep, asoc, type,
diff --git a/net/sctp/sm_statetable.c b/net/sctp/sm_statetable.c
index d991237..dd4ddc4 100644
--- a/net/sctp/sm_statetable.c
+++ b/net/sctp/sm_statetable.c
@@ -897,7 +897,7 @@
 	/* SCTP_STATE_ESTABLISHED */ \
 	TYPE_SCTP_FUNC(sctp_sf_timer_ignore), \
 	/* SCTP_STATE_SHUTDOWN_PENDING */ \
-	TYPE_SCTP_FUNC(sctp_sf_t5_timer_expire), \
+	TYPE_SCTP_FUNC(sctp_sf_timer_ignore), \
 	/* SCTP_STATE_SHUTDOWN_SENT */ \
 	TYPE_SCTP_FUNC(sctp_sf_t5_timer_expire), \
 	/* SCTP_STATE_SHUTDOWN_RECEIVED */ \
diff --git a/net/sctp/socket.c b/net/sctp/socket.c
index 5ffb9de..a1b9045 100644
--- a/net/sctp/socket.c
+++ b/net/sctp/socket.c
@@ -2309,7 +2309,7 @@
 	/* If an address other than INADDR_ANY is specified, and
 	 * no transport is found, then the request is invalid.
 	 */
-	if (!sctp_is_any(( union sctp_addr *)&params.spp_address)) {
+	if (!sctp_is_any(sk, ( union sctp_addr *)&params.spp_address)) {
 		trans = sctp_addr_id2transport(sk, &params.spp_address,
 					       params.spp_assoc_id);
 		if (!trans)
@@ -4062,7 +4062,7 @@
 	/* If an address other than INADDR_ANY is specified, and
 	 * no transport is found, then the request is invalid.
 	 */
-	if (!sctp_is_any(( union sctp_addr *)&params.spp_address)) {
+	if (!sctp_is_any(sk, ( union sctp_addr *)&params.spp_address)) {
 		trans = sctp_addr_id2transport(sk, &params.spp_address,
 					       params.spp_assoc_id);
 		if (!trans) {
@@ -4414,7 +4414,7 @@
 	if (sctp_list_single_entry(&bp->address_list)) {
 		addr = list_entry(bp->address_list.next,
 				  struct sctp_sockaddr_entry, list);
-		if (sctp_is_any(&addr->a)) {
+		if (sctp_is_any(sk, &addr->a)) {
 			rcu_read_lock();
 			list_for_each_entry_rcu(addr,
 						&sctp_local_addr_list, list) {
@@ -4602,7 +4602,7 @@
 	if (sctp_list_single_entry(&bp->address_list)) {
 		addr = list_entry(bp->address_list.next,
 				  struct sctp_sockaddr_entry, list);
-		if (sctp_is_any(&addr->a)) {
+		if (sctp_is_any(sk, &addr->a)) {
 			cnt = sctp_copy_laddrs_old(sk, bp->port,
 						   getaddrs.addr_num,
 						   addrs, &bytes_copied);
@@ -4695,7 +4695,7 @@
 	if (sctp_list_single_entry(&bp->address_list)) {
 		addr = list_entry(bp->address_list.next,
 				  struct sctp_sockaddr_entry, list);
-		if (sctp_is_any(&addr->a)) {
+		if (sctp_is_any(sk, &addr->a)) {
 			cnt = sctp_copy_laddrs(sk, bp->port, addrs,
 						space_left, &bytes_copied);
 			if (cnt < 0) {
diff --git a/net/sctp/tsnmap.c b/net/sctp/tsnmap.c
index f3e58b2..35c73e8 100644
--- a/net/sctp/tsnmap.c
+++ b/net/sctp/tsnmap.c
@@ -43,37 +43,44 @@
  */
 
 #include <linux/types.h>
+#include <linux/bitmap.h>
 #include <net/sctp/sctp.h>
 #include <net/sctp/sm.h>
 
 static void sctp_tsnmap_update(struct sctp_tsnmap *map);
-static void sctp_tsnmap_find_gap_ack(__u8 *map, __u16 off,
-				     __u16 len, __u16 base,
-				     int *started, __u16 *start,
-				     int *ended, __u16 *end);
+static void sctp_tsnmap_find_gap_ack(unsigned long *map, __u16 off,
+				     __u16 len, __u16 *start, __u16 *end);
+static int sctp_tsnmap_grow(struct sctp_tsnmap *map, u16 gap);
 
 /* Initialize a block of memory as a tsnmap.  */
 struct sctp_tsnmap *sctp_tsnmap_init(struct sctp_tsnmap *map, __u16 len,
-				     __u32 initial_tsn)
+				     __u32 initial_tsn, gfp_t gfp)
 {
-	map->tsn_map = map->raw_map;
-	map->overflow_map = map->tsn_map + len;
-	map->len = len;
+	if (!map->tsn_map) {
+		map->tsn_map = kzalloc(len>>3, gfp);
+		if (map->tsn_map == NULL)
+			return NULL;
 
-	/* Clear out a TSN ack status.  */
-	memset(map->tsn_map, 0x00, map->len + map->len);
+		map->len = len;
+	} else {
+		bitmap_zero(map->tsn_map, map->len);
+	}
 
 	/* Keep track of TSNs represented by tsn_map.  */
 	map->base_tsn = initial_tsn;
-	map->overflow_tsn = initial_tsn + map->len;
 	map->cumulative_tsn_ack_point = initial_tsn - 1;
 	map->max_tsn_seen = map->cumulative_tsn_ack_point;
-	map->malloced = 0;
 	map->num_dup_tsns = 0;
 
 	return map;
 }
 
+void sctp_tsnmap_free(struct sctp_tsnmap *map)
+{
+	map->len = 0;
+	kfree(map->tsn_map);
+}
+
 /* Test the tracking state of this TSN.
  * Returns:
  *   0 if the TSN has not yet been seen
@@ -82,66 +89,69 @@
  */
 int sctp_tsnmap_check(const struct sctp_tsnmap *map, __u32 tsn)
 {
-	__s32 gap;
-	int dup;
+	u32 gap;
+
+	/* Check to see if this is an old TSN */
+	if (TSN_lte(tsn, map->cumulative_tsn_ack_point))
+		return 1;
+
+	/* Verify that we can hold this TSN and that it will not
+	 * overlfow our map
+	 */
+	if (!TSN_lt(tsn, map->base_tsn + SCTP_TSN_MAP_SIZE))
+		return -1;
 
 	/* Calculate the index into the mapping arrays.  */
 	gap = tsn - map->base_tsn;
 
-	/* Verify that we can hold this TSN.  */
-	if (gap >= (/* base */ map->len + /* overflow */ map->len)) {
-		dup = -1;
-		goto out;
-	}
-
-	/* Honk if we've already seen this TSN.
-	 * We have three cases:
-	 *	1. The TSN is ancient or belongs to a previous tsn_map.
-	 *	2. The TSN is already marked in the tsn_map.
-	 *	3. The TSN is already marked in the tsn_map_overflow.
-	 */
-	if (gap < 0 ||
-	    (gap < map->len && map->tsn_map[gap]) ||
-	    (gap >= map->len && map->overflow_map[gap - map->len]))
-		dup = 1;
+	/* Check to see if TSN has already been recorded.  */
+	if (gap < map->len && test_bit(gap, map->tsn_map))
+		return 1;
 	else
-		dup = 0;
-
-out:
-	return dup;
+		return 0;
 }
 
 
 /* Mark this TSN as seen.  */
-void sctp_tsnmap_mark(struct sctp_tsnmap *map, __u32 tsn)
+int sctp_tsnmap_mark(struct sctp_tsnmap *map, __u32 tsn)
 {
-	__s32 gap;
+	u16 gap;
 
-	/* Vacuously mark any TSN which precedes the map base or
-	 * exceeds the end of the map.
-	 */
 	if (TSN_lt(tsn, map->base_tsn))
-		return;
-	if (!TSN_lt(tsn, map->base_tsn + map->len + map->len))
-		return;
+		return 0;
 
-	/* Bump the max.  */
-	if (TSN_lt(map->max_tsn_seen, tsn))
-		map->max_tsn_seen = tsn;
-
-	/* Assert: TSN is in range.  */
 	gap = tsn - map->base_tsn;
 
-	/* Mark the TSN as received.  */
-	if (gap < map->len)
-		map->tsn_map[gap]++;
-	else
-		map->overflow_map[gap - map->len]++;
+	if (gap >= map->len && !sctp_tsnmap_grow(map, gap))
+		return -ENOMEM;
 
-	/* Go fixup any internal TSN mapping variables including
-	 * cumulative_tsn_ack_point.
-	 */
-	sctp_tsnmap_update(map);
+	if (!sctp_tsnmap_has_gap(map) && gap == 0) {
+		/* In this case the map has no gaps and the tsn we are
+		 * recording is the next expected tsn.  We don't touch
+		 * the map but simply bump the values.
+		 */
+		map->max_tsn_seen++;
+		map->cumulative_tsn_ack_point++;
+		map->base_tsn++;
+	} else {
+		/* Either we already have a gap, or about to record a gap, so
+		 * have work to do.
+		 *
+		 * Bump the max.
+		 */
+		if (TSN_lt(map->max_tsn_seen, tsn))
+			map->max_tsn_seen = tsn;
+
+		/* Mark the TSN as received.  */
+		set_bit(gap, map->tsn_map);
+
+		/* Go fixup any internal TSN mapping variables including
+		 * cumulative_tsn_ack_point.
+		 */
+		sctp_tsnmap_update(map);
+	}
+
+	return 0;
 }
 
 
@@ -160,66 +170,34 @@
 					 struct sctp_tsnmap_iter *iter,
 					 __u16 *start, __u16 *end)
 {
-	int started, ended;
-	__u16 start_, end_, offset;
-
-	/* We haven't found a gap yet.  */
-	started = ended = 0;
+	int ended = 0;
+	__u16 start_ = 0, end_ = 0, offset;
 
 	/* If there are no more gap acks possible, get out fast.  */
 	if (TSN_lte(map->max_tsn_seen, iter->start))
 		return 0;
 
-	/* Search the first mapping array.  */
-	if (iter->start - map->base_tsn < map->len) {
+	offset = iter->start - map->base_tsn;
+	sctp_tsnmap_find_gap_ack(map->tsn_map, offset, map->len,
+				 &start_, &end_);
 
-		offset = iter->start - map->base_tsn;
-		sctp_tsnmap_find_gap_ack(map->tsn_map, offset, map->len, 0,
-					 &started, &start_, &ended, &end_);
-	}
-
-	/* Do we need to check the overflow map? */
-	if (!ended) {
-		/* Fix up where we'd like to start searching in the
-		 * overflow map.
-		 */
-		if (iter->start - map->base_tsn < map->len)
-			offset = 0;
-		else
-			offset = iter->start - map->base_tsn - map->len;
-
-		/* Search the overflow map.  */
-		sctp_tsnmap_find_gap_ack(map->overflow_map,
-					 offset,
-					 map->len,
-					 map->len,
-					 &started, &start_,
-					 &ended, &end_);
-	}
-
-	/* The Gap Ack Block happens to end at the end of the
-	 * overflow map.
-	 */
-	if (started && !ended) {
-		ended++;
-		end_ = map->len + map->len - 1;
-	}
+	/* The Gap Ack Block happens to end at the end of the map. */
+	if (start_ && !end_)
+		end_ = map->len - 1;
 
 	/* If we found a Gap Ack Block, return the start and end and
 	 * bump the iterator forward.
 	 */
-	if (ended) {
+	if (end_) {
 		/* Fix up the start and end based on the
-		 * Cumulative TSN Ack offset into the map.
+		 * Cumulative TSN Ack which is always 1 behind base.
 		 */
-		int gap = map->cumulative_tsn_ack_point -
-			map->base_tsn;
-
-		*start = start_ - gap;
-		*end = end_ - gap;
+		*start = start_ + 1;
+		*end = end_ + 1;
 
 		/* Move the iterator forward.  */
 		iter->start = map->cumulative_tsn_ack_point + *end + 1;
+		ended = 1;
 	}
 
 	return ended;
@@ -228,35 +206,33 @@
 /* Mark this and any lower TSN as seen.  */
 void sctp_tsnmap_skip(struct sctp_tsnmap *map, __u32 tsn)
 {
-	__s32 gap;
+	u32 gap;
 
-	/* Vacuously mark any TSN which precedes the map base or
-	 * exceeds the end of the map.
-	 */
 	if (TSN_lt(tsn, map->base_tsn))
 		return;
-	if (!TSN_lt(tsn, map->base_tsn + map->len + map->len))
+	if (!TSN_lt(tsn, map->base_tsn + SCTP_TSN_MAP_SIZE))
 		return;
 
 	/* Bump the max.  */
 	if (TSN_lt(map->max_tsn_seen, tsn))
 		map->max_tsn_seen = tsn;
 
-	/* Assert: TSN is in range.  */
 	gap = tsn - map->base_tsn + 1;
 
-	/* Mark the TSNs as received.  */
-	if (gap <= map->len)
-		memset(map->tsn_map, 0x01, gap);
-	else {
-		memset(map->tsn_map, 0x01, map->len);
-		memset(map->overflow_map, 0x01, (gap - map->len));
+	map->base_tsn += gap;
+	map->cumulative_tsn_ack_point += gap;
+	if (gap >= map->len) {
+		/* If our gap is larger then the map size, just
+		 * zero out the map.
+		 */
+		bitmap_zero(map->tsn_map, map->len);
+	} else {
+		/* If the gap is smaller then the map size,
+		 * shift the map by 'gap' bits and update further.
+		 */
+		bitmap_shift_right(map->tsn_map, map->tsn_map, gap, map->len);
+		sctp_tsnmap_update(map);
 	}
-
-	/* Go fixup any internal TSN mapping variables including
-	 * cumulative_tsn_ack_point.
-	 */
-	sctp_tsnmap_update(map);
 }
 
 /********************************************************************
@@ -268,27 +244,19 @@
  */
 static void sctp_tsnmap_update(struct sctp_tsnmap *map)
 {
-	__u32 ctsn;
+	u16 len;
+	unsigned long zero_bit;
 
-	ctsn = map->cumulative_tsn_ack_point;
-	do {
-		ctsn++;
-		if (ctsn == map->overflow_tsn) {
-			/* Now tsn_map must have been all '1's,
-			 * so we swap the map and check the overflow table
-			 */
-			__u8 *tmp = map->tsn_map;
-			memset(tmp, 0, map->len);
-			map->tsn_map = map->overflow_map;
-			map->overflow_map = tmp;
 
-			/* Update the tsn_map boundaries.  */
-			map->base_tsn += map->len;
-			map->overflow_tsn += map->len;
-		}
-	} while (map->tsn_map[ctsn - map->base_tsn]);
+	len = map->max_tsn_seen - map->cumulative_tsn_ack_point;
+	zero_bit = find_first_zero_bit(map->tsn_map, len);
+	if (!zero_bit)
+		return;		/* The first 0-bit is bit 0.  nothing to do */
 
-	map->cumulative_tsn_ack_point = ctsn - 1; /* Back up one. */
+	map->base_tsn += zero_bit;
+	map->cumulative_tsn_ack_point += zero_bit;
+
+	bitmap_shift_right(map->tsn_map, map->tsn_map, zero_bit, map->len);
 }
 
 /* How many data chunks  are we missing from our peer?
@@ -299,31 +267,19 @@
 	__u32 max_tsn = map->max_tsn_seen;
 	__u32 base_tsn = map->base_tsn;
 	__u16 pending_data;
-	__s32 gap, start, end, i;
+	u32 gap, i;
 
 	pending_data = max_tsn - cum_tsn;
 	gap = max_tsn - base_tsn;
 
-	if (gap <= 0 || gap >= (map->len + map->len))
+	if (gap == 0 || gap >= map->len)
 		goto out;
 
-	start = ((cum_tsn >= base_tsn) ? (cum_tsn - base_tsn + 1) : 0);
-	end = ((gap > map->len ) ? map->len : gap + 1);
-
-	for (i = start; i < end; i++) {
-		if (map->tsn_map[i])
+	for (i = 0; i < gap+1; i++) {
+		if (test_bit(i, map->tsn_map))
 			pending_data--;
 	}
 
-	if (gap >= map->len) {
-		start = 0;
-		end = gap - map->len + 1;
-		for (i = start; i < end; i++) {
-			if (map->overflow_map[i])
-				pending_data--;
-		}
-	}
-
 out:
 	return pending_data;
 }
@@ -334,10 +290,8 @@
  * The flags "started" and "ended" tell is if we found the beginning
  * or (respectively) the end of a Gap Ack Block.
  */
-static void sctp_tsnmap_find_gap_ack(__u8 *map, __u16 off,
-				     __u16 len, __u16 base,
-				     int *started, __u16 *start,
-				     int *ended, __u16 *end)
+static void sctp_tsnmap_find_gap_ack(unsigned long *map, __u16 off,
+				     __u16 len, __u16 *start, __u16 *end)
 {
 	int i = off;
 
@@ -348,56 +302,44 @@
 	/* Also, stop looking past the maximum TSN seen. */
 
 	/* Look for the start. */
-	if (!(*started)) {
-		for (; i < len; i++) {
-			if (map[i]) {
-				(*started)++;
-				*start = base + i;
-				break;
-			}
-		}
-	}
+	i = find_next_bit(map, len, off);
+	if (i < len)
+		*start = i;
 
 	/* Look for the end.  */
-	if (*started) {
+	if (*start) {
 		/* We have found the start, let's find the
 		 * end.  If we find the end, break out.
 		 */
-		for (; i < len; i++) {
-			if (!map[i]) {
-				(*ended)++;
-				*end = base + i - 1;
-				break;
-			}
-		}
+		i = find_next_zero_bit(map, len, i);
+		if (i < len)
+			*end = i - 1;
 	}
 }
 
 /* Renege that we have seen a TSN.  */
 void sctp_tsnmap_renege(struct sctp_tsnmap *map, __u32 tsn)
 {
-	__s32 gap;
+	u32 gap;
 
 	if (TSN_lt(tsn, map->base_tsn))
 		return;
-	if (!TSN_lt(tsn, map->base_tsn + map->len + map->len))
+	/* Assert: TSN is in range.  */
+	if (!TSN_lt(tsn, map->base_tsn + map->len))
 		return;
 
-	/* Assert: TSN is in range.  */
 	gap = tsn - map->base_tsn;
 
 	/* Pretend we never saw the TSN.  */
-	if (gap < map->len)
-		map->tsn_map[gap] = 0;
-	else
-		map->overflow_map[gap - map->len] = 0;
+	clear_bit(gap, map->tsn_map);
 }
 
 /* How many gap ack blocks do we have recorded? */
-__u16 sctp_tsnmap_num_gabs(struct sctp_tsnmap *map)
+__u16 sctp_tsnmap_num_gabs(struct sctp_tsnmap *map,
+			   struct sctp_gap_ack_block *gabs)
 {
 	struct sctp_tsnmap_iter iter;
-	int gabs = 0;
+	int ngaps = 0;
 
 	/* Refresh the gap ack information. */
 	if (sctp_tsnmap_has_gap(map)) {
@@ -407,12 +349,36 @@
 						&start,
 						&end)) {
 
-			map->gabs[gabs].start = htons(start);
-			map->gabs[gabs].end = htons(end);
-			gabs++;
-			if (gabs >= SCTP_MAX_GABS)
+			gabs[ngaps].start = htons(start);
+			gabs[ngaps].end = htons(end);
+			ngaps++;
+			if (ngaps >= SCTP_MAX_GABS)
 				break;
 		}
 	}
-	return gabs;
+	return ngaps;
+}
+
+static int sctp_tsnmap_grow(struct sctp_tsnmap *map, u16 gap)
+{
+	unsigned long *new;
+	unsigned long inc;
+	u16  len;
+
+	if (gap >= SCTP_TSN_MAP_SIZE)
+		return 0;
+
+	inc = ALIGN((gap - map->len),BITS_PER_LONG) + SCTP_TSN_MAP_INCREMENT;
+	len = min_t(u16, map->len + inc, SCTP_TSN_MAP_SIZE);
+
+	new = kzalloc(len>>3, GFP_ATOMIC);
+	if (!new)
+		return 0;
+
+	bitmap_copy(new, map->tsn_map, map->max_tsn_seen - map->base_tsn);
+	kfree(map->tsn_map);
+	map->tsn_map = new;
+	map->len = len;
+
+	return 1;
 }
diff --git a/net/sctp/ulpevent.c b/net/sctp/ulpevent.c
index a1f654a..5f186ca 100644
--- a/net/sctp/ulpevent.c
+++ b/net/sctp/ulpevent.c
@@ -713,7 +713,9 @@
 	/* Now that all memory allocations for this chunk succeeded, we
 	 * can mark it as received so the tsn_map is updated correctly.
 	 */
-	sctp_tsnmap_mark(&asoc->peer.tsn_map, ntohl(chunk->subh.data_hdr->tsn));
+	if (sctp_tsnmap_mark(&asoc->peer.tsn_map,
+			     ntohl(chunk->subh.data_hdr->tsn)))
+		goto fail_mark;
 
 	/* First calculate the padding, so we don't inadvertently
 	 * pass up the wrong length to the user.
@@ -755,8 +757,12 @@
 	event->msg_flags |= chunk->chunk_hdr->flags;
 	event->iif = sctp_chunk_iif(chunk);
 
-fail:
 	return event;
+
+fail_mark:
+	kfree_skb(skb);
+fail:
+	return NULL;
 }
 
 /* Create a partial delivery related event.
diff --git a/net/sctp/ulpqueue.c b/net/sctp/ulpqueue.c
index 5061a26..7b23803 100644
--- a/net/sctp/ulpqueue.c
+++ b/net/sctp/ulpqueue.c
@@ -317,7 +317,7 @@
 	}
 
 	/* Insert before pos. */
-	__skb_insert(sctp_event2skb(event), pos->prev, pos, &ulpq->reasm);
+	__skb_queue_before(&ulpq->reasm, pos, sctp_event2skb(event));
 
 }
 
@@ -825,8 +825,7 @@
 
 
 	/* Insert before pos. */
-	__skb_insert(sctp_event2skb(event), pos->prev, pos, &ulpq->lobby);
-
+	__skb_queue_before(&ulpq->lobby, pos, sctp_event2skb(event));
 }
 
 static struct sctp_ulpevent *sctp_ulpq_order(struct sctp_ulpq *ulpq,
diff --git a/net/socket.c b/net/socket.c
index 8ef8ba8..3e8d4e3 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -1511,6 +1511,7 @@
 	goto out_put;
 }
 
+#if 0
 #ifdef HAVE_SET_RESTORE_SIGMASK
 asmlinkage long sys_paccept(int fd, struct sockaddr __user *upeer_sockaddr,
 			    int __user *upeer_addrlen,
@@ -1564,6 +1565,7 @@
 	return do_accept(fd, upeer_sockaddr, upeer_addrlen, flags);
 }
 #endif
+#endif
 
 asmlinkage long sys_accept(int fd, struct sockaddr __user *upeer_sockaddr,
 			   int __user *upeer_addrlen)
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c
index 76739e9..da0789f 100644
--- a/net/sunrpc/clnt.c
+++ b/net/sunrpc/clnt.c
@@ -174,7 +174,7 @@
 	clnt->cl_procinfo = version->procs;
 	clnt->cl_maxproc  = version->nrprocs;
 	clnt->cl_protname = program->name;
-	clnt->cl_prog     = program->number;
+	clnt->cl_prog     = args->prognumber ? : program->number;
 	clnt->cl_vers     = version->number;
 	clnt->cl_stats    = program->stats;
 	clnt->cl_metrics  = rpc_alloc_iostats(clnt);
diff --git a/net/sunrpc/rpcb_clnt.c b/net/sunrpc/rpcb_clnt.c
index 24db2b4..34abc91 100644
--- a/net/sunrpc/rpcb_clnt.c
+++ b/net/sunrpc/rpcb_clnt.c
@@ -20,6 +20,7 @@
 #include <linux/in6.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
+#include <net/ipv6.h>
 
 #include <linux/sunrpc/clnt.h>
 #include <linux/sunrpc/sched.h>
@@ -176,13 +177,12 @@
 }
 
 static int rpcb_register_call(struct sockaddr *addr, size_t addrlen,
-			      u32 version, struct rpc_message *msg,
-			      int *result)
+			      u32 version, struct rpc_message *msg)
 {
 	struct rpc_clnt *rpcb_clnt;
-	int error = 0;
+	int result, error = 0;
 
-	*result = 0;
+	msg->rpc_resp = &result;
 
 	rpcb_clnt = rpcb_create_local(addr, addrlen, version);
 	if (!IS_ERR(rpcb_clnt)) {
@@ -191,12 +191,15 @@
 	} else
 		error = PTR_ERR(rpcb_clnt);
 
-	if (error < 0)
+	if (error < 0) {
 		printk(KERN_WARNING "RPC: failed to contact local rpcbind "
 				"server (errno %d).\n", -error);
-	dprintk("RPC:       registration status %d/%d\n", error, *result);
+		return error;
+	}
 
-	return error;
+	if (!result)
+		return -EACCES;
+	return 0;
 }
 
 /**
@@ -205,7 +208,11 @@
  * @vers: RPC version number to bind
  * @prot: transport protocol to register
  * @port: port value to register
- * @okay: OUT: result code
+ *
+ * Returns zero if the registration request was dispatched successfully
+ * and the rpcbind daemon returned success.  Otherwise, returns an errno
+ * value that reflects the nature of the error (request could not be
+ * dispatched, timed out, or rpcbind returned an error).
  *
  * RPC services invoke this function to advertise their contact
  * information via the system's rpcbind daemon.  RPC services
@@ -217,15 +224,6 @@
  * all registered transports for [program, version] from the local
  * rpcbind database.
  *
- * Returns zero if the registration request was dispatched
- * successfully and a reply was received.  The rpcbind daemon's
- * boolean result code is stored in *okay.
- *
- * Returns an errno value and sets *result to zero if there was
- * some problem that prevented the rpcbind request from being
- * dispatched, or if the rpcbind daemon did not respond within
- * the timeout.
- *
  * This function uses rpcbind protocol version 2 to contact the
  * local rpcbind daemon.
  *
@@ -236,7 +234,7 @@
  * IN6ADDR_ANY (ie available for all AF_INET and AF_INET6
  * addresses).
  */
-int rpcb_register(u32 prog, u32 vers, int prot, unsigned short port, int *okay)
+int rpcb_register(u32 prog, u32 vers, int prot, unsigned short port)
 {
 	struct rpcbind_args map = {
 		.r_prog		= prog,
@@ -246,7 +244,6 @@
 	};
 	struct rpc_message msg = {
 		.rpc_argp	= &map,
-		.rpc_resp	= okay,
 	};
 
 	dprintk("RPC:       %sregistering (%u, %u, %d, %u) with local "
@@ -259,7 +256,7 @@
 
 	return rpcb_register_call((struct sockaddr *)&rpcb_inaddr_loopback,
 					sizeof(rpcb_inaddr_loopback),
-					RPCBVERS_2, &msg, okay);
+					RPCBVERS_2, &msg);
 }
 
 /*
@@ -290,7 +287,7 @@
 
 	return rpcb_register_call((struct sockaddr *)&rpcb_inaddr_loopback,
 					sizeof(rpcb_inaddr_loopback),
-					RPCBVERS_4, msg, msg->rpc_resp);
+					RPCBVERS_4, msg);
 }
 
 /*
@@ -304,10 +301,13 @@
 	char buf[64];
 
 	/* Construct AF_INET6 universal address */
-	snprintf(buf, sizeof(buf),
-			NIP6_FMT".%u.%u",
-			NIP6(address_to_register->sin6_addr),
-			port >> 8, port & 0xff);
+	if (ipv6_addr_any(&address_to_register->sin6_addr))
+		snprintf(buf, sizeof(buf), "::.%u.%u",
+				port >> 8, port & 0xff);
+	else
+		snprintf(buf, sizeof(buf), NIP6_FMT".%u.%u",
+				NIP6(address_to_register->sin6_addr),
+				port >> 8, port & 0xff);
 	map->r_addr = buf;
 
 	dprintk("RPC:       %sregistering [%u, %u, %s, '%s'] with "
@@ -321,7 +321,7 @@
 
 	return rpcb_register_call((struct sockaddr *)&rpcb_in6addr_loopback,
 					sizeof(rpcb_in6addr_loopback),
-					RPCBVERS_4, msg, msg->rpc_resp);
+					RPCBVERS_4, msg);
 }
 
 /**
@@ -330,7 +330,11 @@
  * @version: RPC version number of service to (un)register
  * @address: address family, IP address, and port to (un)register
  * @netid: netid of transport protocol to (un)register
- * @result: result code from rpcbind RPC call
+ *
+ * Returns zero if the registration request was dispatched successfully
+ * and the rpcbind daemon returned success.  Otherwise, returns an errno
+ * value that reflects the nature of the error (request could not be
+ * dispatched, timed out, or rpcbind returned an error).
  *
  * RPC services invoke this function to advertise their contact
  * information via the system's rpcbind daemon.  RPC services
@@ -342,15 +346,6 @@
  * to zero.  Callers pass a netid of "" to unregister all
  * transport netids associated with [program, version, address].
  *
- * Returns zero if the registration request was dispatched
- * successfully and a reply was received.  The rpcbind daemon's
- * result code is stored in *result.
- *
- * Returns an errno value and sets *result to zero if there was
- * some problem that prevented the rpcbind request from being
- * dispatched, or if the rpcbind daemon did not respond within
- * the timeout.
- *
  * This function uses rpcbind protocol version 4 to contact the
  * local rpcbind daemon.  The local rpcbind daemon must support
  * version 4 of the rpcbind protocol in order for these functions
@@ -372,8 +367,7 @@
  * advertises the service on all IPv4 and IPv6 addresses.
  */
 int rpcb_v4_register(const u32 program, const u32 version,
-		     const struct sockaddr *address, const char *netid,
-		     int *result)
+		     const struct sockaddr *address, const char *netid)
 {
 	struct rpcbind_args map = {
 		.r_prog		= program,
@@ -383,11 +377,8 @@
 	};
 	struct rpc_message msg = {
 		.rpc_argp	= &map,
-		.rpc_resp	= result,
 	};
 
-	*result = 0;
-
 	switch (address->sa_family) {
 	case AF_INET:
 		return rpcb_register_netid4((struct sockaddr_in *)address,
@@ -633,7 +624,7 @@
 static int rpcb_encode_mapping(struct rpc_rqst *req, __be32 *p,
 			       struct rpcbind_args *rpcb)
 {
-	dprintk("RPC:       rpcb_encode_mapping(%u, %u, %d, %u)\n",
+	dprintk("RPC:       encoding rpcb request (%u, %u, %d, %u)\n",
 			rpcb->r_prog, rpcb->r_vers, rpcb->r_prot, rpcb->r_port);
 	*p++ = htonl(rpcb->r_prog);
 	*p++ = htonl(rpcb->r_vers);
@@ -648,7 +639,7 @@
 			       unsigned short *portp)
 {
 	*portp = (unsigned short) ntohl(*p++);
-	dprintk("RPC:       rpcb_decode_getport result %u\n",
+	dprintk("RPC:       rpcb getport result: %u\n",
 			*portp);
 	return 0;
 }
@@ -657,7 +648,7 @@
 			   unsigned int *boolp)
 {
 	*boolp = (unsigned int) ntohl(*p++);
-	dprintk("RPC:       rpcb_decode_set: call %s\n",
+	dprintk("RPC:       rpcb set/unset call %s\n",
 			(*boolp ? "succeeded" : "failed"));
 	return 0;
 }
@@ -665,7 +656,7 @@
 static int rpcb_encode_getaddr(struct rpc_rqst *req, __be32 *p,
 			       struct rpcbind_args *rpcb)
 {
-	dprintk("RPC:       rpcb_encode_getaddr(%u, %u, %s)\n",
+	dprintk("RPC:       encoding rpcb request (%u, %u, %s)\n",
 			rpcb->r_prog, rpcb->r_vers, rpcb->r_addr);
 	*p++ = htonl(rpcb->r_prog);
 	*p++ = htonl(rpcb->r_vers);
diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c
index 5a32cb7..54c98d8 100644
--- a/net/sunrpc/svc.c
+++ b/net/sunrpc/svc.c
@@ -28,6 +28,8 @@
 
 #define RPCDBG_FACILITY	RPCDBG_SVCDSP
 
+static void svc_unregister(const struct svc_serv *serv);
+
 #define svc_serv_is_pooled(serv)    ((serv)->sv_function)
 
 /*
@@ -357,7 +359,7 @@
  */
 static struct svc_serv *
 __svc_create(struct svc_program *prog, unsigned int bufsize, int npools,
-	   void (*shutdown)(struct svc_serv *serv))
+	   sa_family_t family, void (*shutdown)(struct svc_serv *serv))
 {
 	struct svc_serv	*serv;
 	unsigned int vers;
@@ -366,6 +368,7 @@
 
 	if (!(serv = kzalloc(sizeof(*serv), GFP_KERNEL)))
 		return NULL;
+	serv->sv_family    = family;
 	serv->sv_name      = prog->pg_name;
 	serv->sv_program   = prog;
 	serv->sv_nrthreads = 1;
@@ -416,30 +419,29 @@
 		spin_lock_init(&pool->sp_lock);
 	}
 
-
 	/* Remove any stale portmap registrations */
-	svc_register(serv, 0, 0);
+	svc_unregister(serv);
 
 	return serv;
 }
 
 struct svc_serv *
 svc_create(struct svc_program *prog, unsigned int bufsize,
-		void (*shutdown)(struct svc_serv *serv))
+		sa_family_t family, void (*shutdown)(struct svc_serv *serv))
 {
-	return __svc_create(prog, bufsize, /*npools*/1, shutdown);
+	return __svc_create(prog, bufsize, /*npools*/1, family, shutdown);
 }
 EXPORT_SYMBOL(svc_create);
 
 struct svc_serv *
 svc_create_pooled(struct svc_program *prog, unsigned int bufsize,
-		void (*shutdown)(struct svc_serv *serv),
+		  sa_family_t family, void (*shutdown)(struct svc_serv *serv),
 		  svc_thread_fn func, struct module *mod)
 {
 	struct svc_serv *serv;
 	unsigned int npools = svc_pool_map_get();
 
-	serv = __svc_create(prog, bufsize, npools, shutdown);
+	serv = __svc_create(prog, bufsize, npools, family, shutdown);
 
 	if (serv != NULL) {
 		serv->sv_function = func;
@@ -486,8 +488,7 @@
 	if (svc_serv_is_pooled(serv))
 		svc_pool_map_put();
 
-	/* Unregister service with the portmapper */
-	svc_register(serv, 0, 0);
+	svc_unregister(serv);
 	kfree(serv->sv_pools);
 	kfree(serv);
 }
@@ -718,55 +719,245 @@
 }
 EXPORT_SYMBOL(svc_exit_thread);
 
+#ifdef CONFIG_SUNRPC_REGISTER_V4
+
 /*
- * Register an RPC service with the local portmapper.
- * To unregister a service, call this routine with
- * proto and port == 0.
+ * Register an "inet" protocol family netid with the local
+ * rpcbind daemon via an rpcbind v4 SET request.
+ *
+ * No netconfig infrastructure is available in the kernel, so
+ * we map IP_ protocol numbers to netids by hand.
+ *
+ * Returns zero on success; a negative errno value is returned
+ * if any error occurs.
  */
-int
-svc_register(struct svc_serv *serv, int proto, unsigned short port)
+static int __svc_rpcb_register4(const u32 program, const u32 version,
+				const unsigned short protocol,
+				const unsigned short port)
+{
+	struct sockaddr_in sin = {
+		.sin_family		= AF_INET,
+		.sin_addr.s_addr	= htonl(INADDR_ANY),
+		.sin_port		= htons(port),
+	};
+	char *netid;
+
+	switch (protocol) {
+	case IPPROTO_UDP:
+		netid = RPCBIND_NETID_UDP;
+		break;
+	case IPPROTO_TCP:
+		netid = RPCBIND_NETID_TCP;
+		break;
+	default:
+		return -EPROTONOSUPPORT;
+	}
+
+	return rpcb_v4_register(program, version,
+				(struct sockaddr *)&sin, netid);
+}
+
+/*
+ * Register an "inet6" protocol family netid with the local
+ * rpcbind daemon via an rpcbind v4 SET request.
+ *
+ * No netconfig infrastructure is available in the kernel, so
+ * we map IP_ protocol numbers to netids by hand.
+ *
+ * Returns zero on success; a negative errno value is returned
+ * if any error occurs.
+ */
+static int __svc_rpcb_register6(const u32 program, const u32 version,
+				const unsigned short protocol,
+				const unsigned short port)
+{
+	struct sockaddr_in6 sin6 = {
+		.sin6_family		= AF_INET6,
+		.sin6_addr		= IN6ADDR_ANY_INIT,
+		.sin6_port		= htons(port),
+	};
+	char *netid;
+
+	switch (protocol) {
+	case IPPROTO_UDP:
+		netid = RPCBIND_NETID_UDP6;
+		break;
+	case IPPROTO_TCP:
+		netid = RPCBIND_NETID_TCP6;
+		break;
+	default:
+		return -EPROTONOSUPPORT;
+	}
+
+	return rpcb_v4_register(program, version,
+				(struct sockaddr *)&sin6, netid);
+}
+
+/*
+ * Register a kernel RPC service via rpcbind version 4.
+ *
+ * Returns zero on success; a negative errno value is returned
+ * if any error occurs.
+ */
+static int __svc_register(const u32 program, const u32 version,
+			  const sa_family_t family,
+			  const unsigned short protocol,
+			  const unsigned short port)
+{
+	int error;
+
+	switch (family) {
+	case AF_INET:
+		return __svc_rpcb_register4(program, version,
+						protocol, port);
+	case AF_INET6:
+		error = __svc_rpcb_register6(program, version,
+						protocol, port);
+		if (error < 0)
+			return error;
+
+		/*
+		 * Work around bug in some versions of Linux rpcbind
+		 * which don't allow registration of both inet and
+		 * inet6 netids.
+		 *
+		 * Error return ignored for now.
+		 */
+		__svc_rpcb_register4(program, version,
+						protocol, port);
+		return 0;
+	}
+
+	return -EAFNOSUPPORT;
+}
+
+#else	/* CONFIG_SUNRPC_REGISTER_V4 */
+
+/*
+ * Register a kernel RPC service via rpcbind version 2.
+ *
+ * Returns zero on success; a negative errno value is returned
+ * if any error occurs.
+ */
+static int __svc_register(const u32 program, const u32 version,
+			  sa_family_t family,
+			  const unsigned short protocol,
+			  const unsigned short port)
+{
+	if (family != AF_INET)
+		return -EAFNOSUPPORT;
+
+	return rpcb_register(program, version, protocol, port);
+}
+
+#endif /* CONFIG_SUNRPC_REGISTER_V4 */
+
+/**
+ * svc_register - register an RPC service with the local portmapper
+ * @serv: svc_serv struct for the service to register
+ * @proto: transport protocol number to advertise
+ * @port: port to advertise
+ *
+ * Service is registered for any address in serv's address family
+ */
+int svc_register(const struct svc_serv *serv, const unsigned short proto,
+		 const unsigned short port)
 {
 	struct svc_program	*progp;
-	unsigned long		flags;
 	unsigned int		i;
-	int			error = 0, dummy;
+	int			error = 0;
 
-	if (!port)
-		clear_thread_flag(TIF_SIGPENDING);
+	BUG_ON(proto == 0 && port == 0);
 
 	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("svc: svc_register(%s, %s, %d, %d)%s\n",
+			dprintk("svc: svc_register(%sv%d, %s, %u, %u)%s\n",
 					progp->pg_name,
+					i,
 					proto == IPPROTO_UDP?  "udp" : "tcp",
 					port,
-					i,
+					serv->sv_family,
 					progp->pg_vers[i]->vs_hidden?
 						" (but not telling portmap)" : "");
 
 			if (progp->pg_vers[i]->vs_hidden)
 				continue;
 
-			error = rpcb_register(progp->pg_prog, i, proto, port, &dummy);
+			error = __svc_register(progp->pg_prog, i,
+						serv->sv_family, proto, port);
 			if (error < 0)
 				break;
-			if (port && !dummy) {
-				error = -EACCES;
-				break;
-			}
 		}
 	}
 
-	if (!port) {
-		spin_lock_irqsave(&current->sighand->siglock, flags);
-		recalc_sigpending();
-		spin_unlock_irqrestore(&current->sighand->siglock, flags);
+	return error;
+}
+
+#ifdef CONFIG_SUNRPC_REGISTER_V4
+
+static void __svc_unregister(const u32 program, const u32 version,
+			     const char *progname)
+{
+	struct sockaddr_in6 sin6 = {
+		.sin6_family		= AF_INET6,
+		.sin6_addr		= IN6ADDR_ANY_INIT,
+		.sin6_port		= 0,
+	};
+	int error;
+
+	error = rpcb_v4_register(program, version,
+				(struct sockaddr *)&sin6, "");
+	dprintk("svc: %s(%sv%u), error %d\n",
+			__func__, progname, version, error);
+}
+
+#else	/* CONFIG_SUNRPC_REGISTER_V4 */
+
+static void __svc_unregister(const u32 program, const u32 version,
+			     const char *progname)
+{
+	int error;
+
+	error = rpcb_register(program, version, 0, 0);
+	dprintk("svc: %s(%sv%u), error %d\n",
+			__func__, progname, version, error);
+}
+
+#endif	/* CONFIG_SUNRPC_REGISTER_V4 */
+
+/*
+ * All netids, bind addresses and ports registered for [program, version]
+ * are removed from the local rpcbind database (if the service is not
+ * hidden) to make way for a new instance of the service.
+ *
+ * The result of unregistration is reported via dprintk for those who want
+ * verification of the result, but is otherwise not important.
+ */
+static void svc_unregister(const struct svc_serv *serv)
+{
+	struct svc_program *progp;
+	unsigned long flags;
+	unsigned int i;
+
+	clear_thread_flag(TIF_SIGPENDING);
+
+	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;
+			if (progp->pg_vers[i]->vs_hidden)
+				continue;
+
+			__svc_unregister(progp->pg_prog, i, progp->pg_name);
+		}
 	}
 
-	return error;
+	spin_lock_irqsave(&current->sighand->siglock, flags);
+	recalc_sigpending();
+	spin_unlock_irqrestore(&current->sighand->siglock, flags);
 }
 
 /*
diff --git a/net/sunrpc/svc_xprt.c b/net/sunrpc/svc_xprt.c
index e46c825..bf5b5cd 100644
--- a/net/sunrpc/svc_xprt.c
+++ b/net/sunrpc/svc_xprt.c
@@ -159,15 +159,44 @@
 }
 EXPORT_SYMBOL_GPL(svc_xprt_init);
 
-int svc_create_xprt(struct svc_serv *serv, char *xprt_name, unsigned short port,
-		    int flags)
+static struct svc_xprt *__svc_xpo_create(struct svc_xprt_class *xcl,
+					 struct svc_serv *serv,
+					 unsigned short port, int flags)
 {
-	struct svc_xprt_class *xcl;
 	struct sockaddr_in sin = {
 		.sin_family		= AF_INET,
 		.sin_addr.s_addr	= htonl(INADDR_ANY),
 		.sin_port		= htons(port),
 	};
+	struct sockaddr_in6 sin6 = {
+		.sin6_family		= AF_INET6,
+		.sin6_addr		= IN6ADDR_ANY_INIT,
+		.sin6_port		= htons(port),
+	};
+	struct sockaddr *sap;
+	size_t len;
+
+	switch (serv->sv_family) {
+	case AF_INET:
+		sap = (struct sockaddr *)&sin;
+		len = sizeof(sin);
+		break;
+	case AF_INET6:
+		sap = (struct sockaddr *)&sin6;
+		len = sizeof(sin6);
+		break;
+	default:
+		return ERR_PTR(-EAFNOSUPPORT);
+	}
+
+	return xcl->xcl_ops->xpo_create(serv, sap, len, flags);
+}
+
+int svc_create_xprt(struct svc_serv *serv, char *xprt_name, unsigned short port,
+		    int flags)
+{
+	struct svc_xprt_class *xcl;
+
 	dprintk("svc: creating transport %s[%d]\n", xprt_name, port);
 	spin_lock(&svc_xprt_class_lock);
 	list_for_each_entry(xcl, &svc_xprt_class_list, xcl_list) {
@@ -180,9 +209,7 @@
 			goto err;
 
 		spin_unlock(&svc_xprt_class_lock);
-		newxprt = xcl->xcl_ops->
-			xpo_create(serv, (struct sockaddr *)&sin, sizeof(sin),
-				   flags);
+		newxprt = __svc_xpo_create(xcl, serv, port, flags);
 		if (IS_ERR(newxprt)) {
 			module_put(xcl->xcl_owner);
 			return PTR_ERR(newxprt);
diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c
index 3e65719..95293f5 100644
--- a/net/sunrpc/svcsock.c
+++ b/net/sunrpc/svcsock.c
@@ -1114,6 +1114,7 @@
 	struct svc_sock	*svsk;
 	struct sock	*inet;
 	int		pmap_register = !(flags & SVC_SOCK_ANONYMOUS);
+	int		val;
 
 	dprintk("svc: svc_setup_socket %p\n", sock);
 	if (!(svsk = kzalloc(sizeof(*svsk), GFP_KERNEL))) {
@@ -1146,6 +1147,18 @@
 	else
 		svc_tcp_init(svsk, serv);
 
+	/*
+	 * We start one listener per sv_serv.  We want AF_INET
+	 * requests to be automatically shunted to our AF_INET6
+	 * listener using a mapped IPv4 address.  Make sure
+	 * no-one starts an equivalent IPv4 listener, which
+	 * would steal our incoming connections.
+	 */
+	val = 0;
+	if (serv->sv_family == AF_INET6)
+		kernel_setsockopt(sock, SOL_IPV6, IPV6_V6ONLY,
+					(char *)&val, sizeof(val));
+
 	dprintk("svc: svc_setup_socket created %p (inet %p)\n",
 				svsk, svsk->sk_sk);
 
@@ -1154,8 +1167,7 @@
 
 int svc_addsock(struct svc_serv *serv,
 		int fd,
-		char *name_return,
-		int *proto)
+		char *name_return)
 {
 	int err = 0;
 	struct socket *so = sockfd_lookup(fd, &err);
@@ -1190,7 +1202,6 @@
 		sockfd_put(so);
 		return err;
 	}
-	if (proto) *proto = so->sk->sk_protocol;
 	return one_sock_name(name_return, svsk);
 }
 EXPORT_SYMBOL_GPL(svc_addsock);
diff --git a/net/sunrpc/xprtrdma/rpc_rdma.c b/net/sunrpc/xprtrdma/rpc_rdma.c
index e55427f..5c1954d28 100644
--- a/net/sunrpc/xprtrdma/rpc_rdma.c
+++ b/net/sunrpc/xprtrdma/rpc_rdma.c
@@ -769,7 +769,7 @@
 	/* check for expected message types */
 	/* The order of some of these tests is important. */
 	switch (headerp->rm_type) {
-	case __constant_htonl(RDMA_MSG):
+	case htonl(RDMA_MSG):
 		/* never expect read chunks */
 		/* never expect reply chunks (two ways to check) */
 		/* never expect write chunks without having offered RDMA */
@@ -802,7 +802,7 @@
 		rpcrdma_inline_fixup(rqst, (char *)iptr, rep->rr_len);
 		break;
 
-	case __constant_htonl(RDMA_NOMSG):
+	case htonl(RDMA_NOMSG):
 		/* never expect read or write chunks, always reply chunks */
 		if (headerp->rm_body.rm_chunks[0] != xdr_zero ||
 		    headerp->rm_body.rm_chunks[1] != xdr_zero ||
diff --git a/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c b/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c
index 74de31a..a475657 100644
--- a/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c
+++ b/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c
@@ -116,7 +116,7 @@
  *
  * Assumptions:
  * - chunk[0]->position points to pages[0] at an offset of 0
- * - pages[] is not physically or virtually contigous and consists of
+ * - pages[] is not physically or virtually contiguous and consists of
  *   PAGE_SIZE elements.
  *
  * Output:
@@ -125,7 +125,7 @@
  *   chunk in the read list
  *
  */
-static int rdma_rcl_to_sge(struct svcxprt_rdma *xprt,
+static int map_read_chunks(struct svcxprt_rdma *xprt,
 			   struct svc_rqst *rqstp,
 			   struct svc_rdma_op_ctxt *head,
 			   struct rpcrdma_msg *rmsgp,
@@ -211,26 +211,128 @@
 	return sge_no;
 }
 
-static void rdma_set_ctxt_sge(struct svcxprt_rdma *xprt,
-			      struct svc_rdma_op_ctxt *ctxt,
-			      struct kvec *vec,
-			      u64 *sgl_offset,
-			      int count)
+/* Map a read-chunk-list to an XDR and fast register the page-list.
+ *
+ * Assumptions:
+ * - chunk[0]	position points to pages[0] at an offset of 0
+ * - pages[]	will be made physically contiguous by creating a one-off memory
+ *		region using the fastreg verb.
+ * - byte_count is # of bytes in read-chunk-list
+ * - ch_count	is # of chunks in read-chunk-list
+ *
+ * Output:
+ * - sge array pointing into pages[] array.
+ * - chunk_sge array specifying sge index and count for each
+ *   chunk in the read list
+ */
+static int fast_reg_read_chunks(struct svcxprt_rdma *xprt,
+				struct svc_rqst *rqstp,
+				struct svc_rdma_op_ctxt *head,
+				struct rpcrdma_msg *rmsgp,
+				struct svc_rdma_req_map *rpl_map,
+				struct svc_rdma_req_map *chl_map,
+				int ch_count,
+				int byte_count)
+{
+	int page_no;
+	int ch_no;
+	u32 offset;
+	struct rpcrdma_read_chunk *ch;
+	struct svc_rdma_fastreg_mr *frmr;
+	int ret = 0;
+
+	frmr = svc_rdma_get_frmr(xprt);
+	if (IS_ERR(frmr))
+		return -ENOMEM;
+
+	head->frmr = frmr;
+	head->arg.head[0] = rqstp->rq_arg.head[0];
+	head->arg.tail[0] = rqstp->rq_arg.tail[0];
+	head->arg.pages = &head->pages[head->count];
+	head->hdr_count = head->count; /* save count of hdr pages */
+	head->arg.page_base = 0;
+	head->arg.page_len = byte_count;
+	head->arg.len = rqstp->rq_arg.len + byte_count;
+	head->arg.buflen = rqstp->rq_arg.buflen + byte_count;
+
+	/* Fast register the page list */
+	frmr->kva = page_address(rqstp->rq_arg.pages[0]);
+	frmr->direction = DMA_FROM_DEVICE;
+	frmr->access_flags = (IB_ACCESS_LOCAL_WRITE|IB_ACCESS_REMOTE_WRITE);
+	frmr->map_len = byte_count;
+	frmr->page_list_len = PAGE_ALIGN(byte_count) >> PAGE_SHIFT;
+	for (page_no = 0; page_no < frmr->page_list_len; page_no++) {
+		frmr->page_list->page_list[page_no] =
+			ib_dma_map_single(xprt->sc_cm_id->device,
+					  page_address(rqstp->rq_arg.pages[page_no]),
+					  PAGE_SIZE, DMA_TO_DEVICE);
+		if (ib_dma_mapping_error(xprt->sc_cm_id->device,
+					 frmr->page_list->page_list[page_no]))
+			goto fatal_err;
+		atomic_inc(&xprt->sc_dma_used);
+		head->arg.pages[page_no] = rqstp->rq_arg.pages[page_no];
+	}
+	head->count += page_no;
+
+	/* rq_respages points one past arg pages */
+	rqstp->rq_respages = &rqstp->rq_arg.pages[page_no];
+
+	/* Create the reply and chunk maps */
+	offset = 0;
+	ch = (struct rpcrdma_read_chunk *)&rmsgp->rm_body.rm_chunks[0];
+	for (ch_no = 0; ch_no < ch_count; ch_no++) {
+		rpl_map->sge[ch_no].iov_base = frmr->kva + offset;
+		rpl_map->sge[ch_no].iov_len = ch->rc_target.rs_length;
+		chl_map->ch[ch_no].count = 1;
+		chl_map->ch[ch_no].start = ch_no;
+		offset += ch->rc_target.rs_length;
+		ch++;
+	}
+
+	ret = svc_rdma_fastreg(xprt, frmr);
+	if (ret)
+		goto fatal_err;
+
+	return ch_no;
+
+ fatal_err:
+	printk("svcrdma: error fast registering xdr for xprt %p", xprt);
+	svc_rdma_put_frmr(xprt, frmr);
+	return -EIO;
+}
+
+static int rdma_set_ctxt_sge(struct svcxprt_rdma *xprt,
+			     struct svc_rdma_op_ctxt *ctxt,
+			     struct svc_rdma_fastreg_mr *frmr,
+			     struct kvec *vec,
+			     u64 *sgl_offset,
+			     int count)
 {
 	int i;
 
 	ctxt->count = count;
 	ctxt->direction = DMA_FROM_DEVICE;
 	for (i = 0; i < count; i++) {
-		atomic_inc(&xprt->sc_dma_used);
-		ctxt->sge[i].addr =
-			ib_dma_map_single(xprt->sc_cm_id->device,
-					  vec[i].iov_base, vec[i].iov_len,
-					  DMA_FROM_DEVICE);
+		ctxt->sge[i].length = 0; /* in case map fails */
+		if (!frmr) {
+			ctxt->sge[i].addr =
+				ib_dma_map_single(xprt->sc_cm_id->device,
+						  vec[i].iov_base,
+						  vec[i].iov_len,
+						  DMA_FROM_DEVICE);
+			if (ib_dma_mapping_error(xprt->sc_cm_id->device,
+						 ctxt->sge[i].addr))
+				return -EINVAL;
+			ctxt->sge[i].lkey = xprt->sc_dma_lkey;
+			atomic_inc(&xprt->sc_dma_used);
+		} else {
+			ctxt->sge[i].addr = (unsigned long)vec[i].iov_base;
+			ctxt->sge[i].lkey = frmr->mr->lkey;
+		}
 		ctxt->sge[i].length = vec[i].iov_len;
-		ctxt->sge[i].lkey = xprt->sc_phys_mr->lkey;
 		*sgl_offset = *sgl_offset + vec[i].iov_len;
 	}
+	return 0;
 }
 
 static int rdma_read_max_sge(struct svcxprt_rdma *xprt, int sge_count)
@@ -278,6 +380,7 @@
 			 struct svc_rdma_op_ctxt *hdr_ctxt)
 {
 	struct ib_send_wr read_wr;
+	struct ib_send_wr inv_wr;
 	int err = 0;
 	int ch_no;
 	int ch_count;
@@ -301,9 +404,20 @@
 	svc_rdma_rcl_chunk_counts(ch, &ch_count, &byte_count);
 	if (ch_count > RPCSVC_MAXPAGES)
 		return -EINVAL;
-	sge_count = rdma_rcl_to_sge(xprt, rqstp, hdr_ctxt, rmsgp,
-				    rpl_map, chl_map,
-				    ch_count, byte_count);
+
+	if (!xprt->sc_frmr_pg_list_len)
+		sge_count = map_read_chunks(xprt, rqstp, hdr_ctxt, rmsgp,
+					    rpl_map, chl_map, ch_count,
+					    byte_count);
+	else
+		sge_count = fast_reg_read_chunks(xprt, rqstp, hdr_ctxt, rmsgp,
+						 rpl_map, chl_map, ch_count,
+						 byte_count);
+	if (sge_count < 0) {
+		err = -EIO;
+		goto out;
+	}
+
 	sgl_offset = 0;
 	ch_no = 0;
 
@@ -312,13 +426,16 @@
 next_sge:
 		ctxt = svc_rdma_get_context(xprt);
 		ctxt->direction = DMA_FROM_DEVICE;
+		ctxt->frmr = hdr_ctxt->frmr;
+		ctxt->read_hdr = NULL;
 		clear_bit(RDMACTXT_F_LAST_CTXT, &ctxt->flags);
+		clear_bit(RDMACTXT_F_FAST_UNREG, &ctxt->flags);
 
 		/* Prepare READ WR */
 		memset(&read_wr, 0, sizeof read_wr);
-		ctxt->wr_op = IB_WR_RDMA_READ;
 		read_wr.wr_id = (unsigned long)ctxt;
 		read_wr.opcode = IB_WR_RDMA_READ;
+		ctxt->wr_op = read_wr.opcode;
 		read_wr.send_flags = IB_SEND_SIGNALED;
 		read_wr.wr.rdma.rkey = ch->rc_target.rs_handle;
 		read_wr.wr.rdma.remote_addr =
@@ -327,10 +444,15 @@
 		read_wr.sg_list = ctxt->sge;
 		read_wr.num_sge =
 			rdma_read_max_sge(xprt, chl_map->ch[ch_no].count);
-		rdma_set_ctxt_sge(xprt, ctxt,
-				  &rpl_map->sge[chl_map->ch[ch_no].start],
-				  &sgl_offset,
-				  read_wr.num_sge);
+		err = rdma_set_ctxt_sge(xprt, ctxt, hdr_ctxt->frmr,
+					&rpl_map->sge[chl_map->ch[ch_no].start],
+					&sgl_offset,
+					read_wr.num_sge);
+		if (err) {
+			svc_rdma_unmap_dma(ctxt);
+			svc_rdma_put_context(ctxt, 0);
+			goto out;
+		}
 		if (((ch+1)->rc_discrim == 0) &&
 		    (read_wr.num_sge == chl_map->ch[ch_no].count)) {
 			/*
@@ -339,6 +461,29 @@
 			 * the client and the RPC needs to be enqueued.
 			 */
 			set_bit(RDMACTXT_F_LAST_CTXT, &ctxt->flags);
+			if (hdr_ctxt->frmr) {
+				set_bit(RDMACTXT_F_FAST_UNREG, &ctxt->flags);
+				/*
+				 * Invalidate the local MR used to map the data
+				 * sink.
+				 */
+				if (xprt->sc_dev_caps &
+				    SVCRDMA_DEVCAP_READ_W_INV) {
+					read_wr.opcode =
+						IB_WR_RDMA_READ_WITH_INV;
+					ctxt->wr_op = read_wr.opcode;
+					read_wr.ex.invalidate_rkey =
+						ctxt->frmr->mr->lkey;
+				} else {
+					/* Prepare INVALIDATE WR */
+					memset(&inv_wr, 0, sizeof inv_wr);
+					inv_wr.opcode = IB_WR_LOCAL_INV;
+					inv_wr.send_flags = IB_SEND_SIGNALED;
+					inv_wr.ex.invalidate_rkey =
+						hdr_ctxt->frmr->mr->lkey;
+					read_wr.next = &inv_wr;
+				}
+			}
 			ctxt->read_hdr = hdr_ctxt;
 		}
 		/* Post the read */
diff --git a/net/sunrpc/xprtrdma/svc_rdma_sendto.c b/net/sunrpc/xprtrdma/svc_rdma_sendto.c
index 84d3283..9a7a8e7 100644
--- a/net/sunrpc/xprtrdma/svc_rdma_sendto.c
+++ b/net/sunrpc/xprtrdma/svc_rdma_sendto.c
@@ -69,9 +69,127 @@
  * array is only concerned with the reply we are assured that we have
  * on extra page for the RPCRMDA header.
  */
-static void xdr_to_sge(struct svcxprt_rdma *xprt,
-		       struct xdr_buf *xdr,
-		       struct svc_rdma_req_map *vec)
+int fast_reg_xdr(struct svcxprt_rdma *xprt,
+		 struct xdr_buf *xdr,
+		 struct svc_rdma_req_map *vec)
+{
+	int sge_no;
+	u32 sge_bytes;
+	u32 page_bytes;
+	u32 page_off;
+	int page_no = 0;
+	u8 *frva;
+	struct svc_rdma_fastreg_mr *frmr;
+
+	frmr = svc_rdma_get_frmr(xprt);
+	if (IS_ERR(frmr))
+		return -ENOMEM;
+	vec->frmr = frmr;
+
+	/* Skip the RPCRDMA header */
+	sge_no = 1;
+
+	/* Map the head. */
+	frva = (void *)((unsigned long)(xdr->head[0].iov_base) & PAGE_MASK);
+	vec->sge[sge_no].iov_base = xdr->head[0].iov_base;
+	vec->sge[sge_no].iov_len = xdr->head[0].iov_len;
+	vec->count = 2;
+	sge_no++;
+
+	/* Build the FRMR */
+	frmr->kva = frva;
+	frmr->direction = DMA_TO_DEVICE;
+	frmr->access_flags = 0;
+	frmr->map_len = PAGE_SIZE;
+	frmr->page_list_len = 1;
+	frmr->page_list->page_list[page_no] =
+		ib_dma_map_single(xprt->sc_cm_id->device,
+				  (void *)xdr->head[0].iov_base,
+				  PAGE_SIZE, DMA_TO_DEVICE);
+	if (ib_dma_mapping_error(xprt->sc_cm_id->device,
+				 frmr->page_list->page_list[page_no]))
+		goto fatal_err;
+	atomic_inc(&xprt->sc_dma_used);
+
+	page_off = xdr->page_base;
+	page_bytes = xdr->page_len + page_off;
+	if (!page_bytes)
+		goto encode_tail;
+
+	/* Map the pages */
+	vec->sge[sge_no].iov_base = frva + frmr->map_len + page_off;
+	vec->sge[sge_no].iov_len = page_bytes;
+	sge_no++;
+	while (page_bytes) {
+		struct page *page;
+
+		page = xdr->pages[page_no++];
+		sge_bytes = min_t(u32, page_bytes, (PAGE_SIZE - page_off));
+		page_bytes -= sge_bytes;
+
+		frmr->page_list->page_list[page_no] =
+			ib_dma_map_page(xprt->sc_cm_id->device, page, 0,
+					  PAGE_SIZE, DMA_TO_DEVICE);
+		if (ib_dma_mapping_error(xprt->sc_cm_id->device,
+					 frmr->page_list->page_list[page_no]))
+			goto fatal_err;
+
+		atomic_inc(&xprt->sc_dma_used);
+		page_off = 0; /* reset for next time through loop */
+		frmr->map_len += PAGE_SIZE;
+		frmr->page_list_len++;
+	}
+	vec->count++;
+
+ encode_tail:
+	/* Map tail */
+	if (0 == xdr->tail[0].iov_len)
+		goto done;
+
+	vec->count++;
+	vec->sge[sge_no].iov_len = xdr->tail[0].iov_len;
+
+	if (((unsigned long)xdr->tail[0].iov_base & PAGE_MASK) ==
+	    ((unsigned long)xdr->head[0].iov_base & PAGE_MASK)) {
+		/*
+		 * If head and tail use the same page, we don't need
+		 * to map it again.
+		 */
+		vec->sge[sge_no].iov_base = xdr->tail[0].iov_base;
+	} else {
+		void *va;
+
+		/* Map another page for the tail */
+		page_off = (unsigned long)xdr->tail[0].iov_base & ~PAGE_MASK;
+		va = (void *)((unsigned long)xdr->tail[0].iov_base & PAGE_MASK);
+		vec->sge[sge_no].iov_base = frva + frmr->map_len + page_off;
+
+		frmr->page_list->page_list[page_no] =
+			ib_dma_map_single(xprt->sc_cm_id->device, va, PAGE_SIZE,
+					  DMA_TO_DEVICE);
+		if (ib_dma_mapping_error(xprt->sc_cm_id->device,
+					 frmr->page_list->page_list[page_no]))
+			goto fatal_err;
+		atomic_inc(&xprt->sc_dma_used);
+		frmr->map_len += PAGE_SIZE;
+		frmr->page_list_len++;
+	}
+
+ done:
+	if (svc_rdma_fastreg(xprt, frmr))
+		goto fatal_err;
+
+	return 0;
+
+ fatal_err:
+	printk("svcrdma: Error fast registering memory for xprt %p\n", xprt);
+	svc_rdma_put_frmr(xprt, frmr);
+	return -EIO;
+}
+
+static int map_xdr(struct svcxprt_rdma *xprt,
+		   struct xdr_buf *xdr,
+		   struct svc_rdma_req_map *vec)
 {
 	int sge_max = (xdr->len+PAGE_SIZE-1) / PAGE_SIZE + 3;
 	int sge_no;
@@ -83,6 +201,9 @@
 	BUG_ON(xdr->len !=
 	       (xdr->head[0].iov_len + xdr->page_len + xdr->tail[0].iov_len));
 
+	if (xprt->sc_frmr_pg_list_len)
+		return fast_reg_xdr(xprt, xdr, vec);
+
 	/* Skip the first sge, this is for the RPCRDMA header */
 	sge_no = 1;
 
@@ -116,9 +237,12 @@
 
 	BUG_ON(sge_no > sge_max);
 	vec->count = sge_no;
+	return 0;
 }
 
 /* Assumptions:
+ * - We are using FRMR
+ *     - or -
  * - The specified write_len can be represented in sc_max_sge * PAGE_SIZE
  */
 static int send_write(struct svcxprt_rdma *xprt, struct svc_rqst *rqstp,
@@ -158,30 +282,35 @@
 	sge_no = 0;
 
 	/* Copy the remaining SGE */
-	while (bc != 0 && xdr_sge_no < vec->count) {
-		sge[sge_no].lkey = xprt->sc_phys_mr->lkey;
-		sge_bytes = min((size_t)bc,
-				(size_t)(vec->sge[xdr_sge_no].iov_len-sge_off));
+	while (bc != 0) {
+		sge_bytes = min_t(size_t,
+			  bc, vec->sge[xdr_sge_no].iov_len-sge_off);
 		sge[sge_no].length = sge_bytes;
-		atomic_inc(&xprt->sc_dma_used);
-		sge[sge_no].addr =
-			ib_dma_map_single(xprt->sc_cm_id->device,
-					  (void *)
-					  vec->sge[xdr_sge_no].iov_base + sge_off,
-					  sge_bytes, DMA_TO_DEVICE);
-		if (dma_mapping_error(xprt->sc_cm_id->device->dma_device,
-					sge[sge_no].addr))
-			goto err;
+		if (!vec->frmr) {
+			sge[sge_no].addr =
+				ib_dma_map_single(xprt->sc_cm_id->device,
+						  (void *)
+						  vec->sge[xdr_sge_no].iov_base + sge_off,
+						  sge_bytes, DMA_TO_DEVICE);
+			if (ib_dma_mapping_error(xprt->sc_cm_id->device,
+						 sge[sge_no].addr))
+				goto err;
+			atomic_inc(&xprt->sc_dma_used);
+			sge[sge_no].lkey = xprt->sc_dma_lkey;
+		} else {
+			sge[sge_no].addr = (unsigned long)
+				vec->sge[xdr_sge_no].iov_base + sge_off;
+			sge[sge_no].lkey = vec->frmr->mr->lkey;
+		}
+		ctxt->count++;
+		ctxt->frmr = vec->frmr;
 		sge_off = 0;
 		sge_no++;
-		ctxt->count++;
 		xdr_sge_no++;
+		BUG_ON(xdr_sge_no > vec->count);
 		bc -= sge_bytes;
 	}
 
-	BUG_ON(bc != 0);
-	BUG_ON(xdr_sge_no > vec->count);
-
 	/* Prepare WRITE WR */
 	memset(&write_wr, 0, sizeof write_wr);
 	ctxt->wr_op = IB_WR_RDMA_WRITE;
@@ -226,7 +355,10 @@
 	res_ary = (struct rpcrdma_write_array *)
 		&rdma_resp->rm_body.rm_chunks[1];
 
-	max_write = xprt->sc_max_sge * PAGE_SIZE;
+	if (vec->frmr)
+		max_write = vec->frmr->map_len;
+	else
+		max_write = xprt->sc_max_sge * PAGE_SIZE;
 
 	/* Write chunks start at the pagelist */
 	for (xdr_off = rqstp->rq_res.head[0].iov_len, chunk_no = 0;
@@ -297,7 +429,10 @@
 	res_ary = (struct rpcrdma_write_array *)
 		&rdma_resp->rm_body.rm_chunks[2];
 
-	max_write = xprt->sc_max_sge * PAGE_SIZE;
+	if (vec->frmr)
+		max_write = vec->frmr->map_len;
+	else
+		max_write = xprt->sc_max_sge * PAGE_SIZE;
 
 	/* xdr offset starts at RPC message */
 	for (xdr_off = 0, chunk_no = 0;
@@ -307,7 +442,6 @@
 		ch = &arg_ary->wc_array[chunk_no].wc_target;
 		write_len = min(xfer_len, ch->rs_length);
 
-
 		/* Prepare the reply chunk given the length actually
 		 * written */
 		rs_offset = get_unaligned(&(ch->rs_offset));
@@ -366,6 +500,7 @@
 		      int byte_count)
 {
 	struct ib_send_wr send_wr;
+	struct ib_send_wr inv_wr;
 	int sge_no;
 	int sge_bytes;
 	int page_no;
@@ -385,27 +520,45 @@
 	/* Prepare the context */
 	ctxt->pages[0] = page;
 	ctxt->count = 1;
+	ctxt->frmr = vec->frmr;
+	if (vec->frmr)
+		set_bit(RDMACTXT_F_FAST_UNREG, &ctxt->flags);
+	else
+		clear_bit(RDMACTXT_F_FAST_UNREG, &ctxt->flags);
 
 	/* Prepare the SGE for the RPCRDMA Header */
-	atomic_inc(&rdma->sc_dma_used);
 	ctxt->sge[0].addr =
 		ib_dma_map_page(rdma->sc_cm_id->device,
 				page, 0, PAGE_SIZE, DMA_TO_DEVICE);
+	if (ib_dma_mapping_error(rdma->sc_cm_id->device, ctxt->sge[0].addr))
+		goto err;
+	atomic_inc(&rdma->sc_dma_used);
+
 	ctxt->direction = DMA_TO_DEVICE;
+
 	ctxt->sge[0].length = svc_rdma_xdr_get_reply_hdr_len(rdma_resp);
-	ctxt->sge[0].lkey = rdma->sc_phys_mr->lkey;
+	ctxt->sge[0].lkey = rdma->sc_dma_lkey;
 
 	/* Determine how many of our SGE are to be transmitted */
 	for (sge_no = 1; byte_count && sge_no < vec->count; sge_no++) {
 		sge_bytes = min_t(size_t, vec->sge[sge_no].iov_len, byte_count);
 		byte_count -= sge_bytes;
-		atomic_inc(&rdma->sc_dma_used);
-		ctxt->sge[sge_no].addr =
-			ib_dma_map_single(rdma->sc_cm_id->device,
-					  vec->sge[sge_no].iov_base,
-					  sge_bytes, DMA_TO_DEVICE);
+		if (!vec->frmr) {
+			ctxt->sge[sge_no].addr =
+				ib_dma_map_single(rdma->sc_cm_id->device,
+						  vec->sge[sge_no].iov_base,
+						  sge_bytes, DMA_TO_DEVICE);
+			if (ib_dma_mapping_error(rdma->sc_cm_id->device,
+						 ctxt->sge[sge_no].addr))
+				goto err;
+			atomic_inc(&rdma->sc_dma_used);
+			ctxt->sge[sge_no].lkey = rdma->sc_dma_lkey;
+		} else {
+			ctxt->sge[sge_no].addr = (unsigned long)
+				vec->sge[sge_no].iov_base;
+			ctxt->sge[sge_no].lkey = vec->frmr->mr->lkey;
+		}
 		ctxt->sge[sge_no].length = sge_bytes;
-		ctxt->sge[sge_no].lkey = rdma->sc_phys_mr->lkey;
 	}
 	BUG_ON(byte_count != 0);
 
@@ -417,11 +570,16 @@
 		ctxt->pages[page_no+1] = rqstp->rq_respages[page_no];
 		ctxt->count++;
 		rqstp->rq_respages[page_no] = NULL;
-		/* If there are more pages than SGE, terminate SGE list */
+		/*
+		 * If there are more pages than SGE, terminate SGE
+		 * list so that svc_rdma_unmap_dma doesn't attempt to
+		 * unmap garbage.
+		 */
 		if (page_no+1 >= sge_no)
 			ctxt->sge[page_no+1].length = 0;
 	}
 	BUG_ON(sge_no > rdma->sc_max_sge);
+	BUG_ON(sge_no > ctxt->count);
 	memset(&send_wr, 0, sizeof send_wr);
 	ctxt->wr_op = IB_WR_SEND;
 	send_wr.wr_id = (unsigned long)ctxt;
@@ -429,12 +587,26 @@
 	send_wr.num_sge = sge_no;
 	send_wr.opcode = IB_WR_SEND;
 	send_wr.send_flags =  IB_SEND_SIGNALED;
+	if (vec->frmr) {
+		/* Prepare INVALIDATE WR */
+		memset(&inv_wr, 0, sizeof inv_wr);
+		inv_wr.opcode = IB_WR_LOCAL_INV;
+		inv_wr.send_flags = IB_SEND_SIGNALED;
+		inv_wr.ex.invalidate_rkey =
+			vec->frmr->mr->lkey;
+		send_wr.next = &inv_wr;
+	}
 
 	ret = svc_rdma_send(rdma, &send_wr);
 	if (ret)
-		svc_rdma_put_context(ctxt, 1);
+		goto err;
 
-	return ret;
+	return 0;
+
+ err:
+	svc_rdma_put_frmr(rdma, vec->frmr);
+	svc_rdma_put_context(ctxt, 1);
+	return -EIO;
 }
 
 void svc_rdma_prep_reply_hdr(struct svc_rqst *rqstp)
@@ -477,8 +649,9 @@
 	ctxt = svc_rdma_get_context(rdma);
 	ctxt->direction = DMA_TO_DEVICE;
 	vec = svc_rdma_get_req_map();
-	xdr_to_sge(rdma, &rqstp->rq_res, vec);
-
+	ret = map_xdr(rdma, &rqstp->rq_res, vec);
+	if (ret)
+		goto err0;
 	inline_bytes = rqstp->rq_res.len;
 
 	/* Create the RDMA response header */
@@ -498,7 +671,7 @@
 	if (ret < 0) {
 		printk(KERN_ERR "svcrdma: failed to send write chunks, rc=%d\n",
 		       ret);
-		goto error;
+		goto err1;
 	}
 	inline_bytes -= ret;
 
@@ -508,7 +681,7 @@
 	if (ret < 0) {
 		printk(KERN_ERR "svcrdma: failed to send reply chunks, rc=%d\n",
 		       ret);
-		goto error;
+		goto err1;
 	}
 	inline_bytes -= ret;
 
@@ -517,9 +690,11 @@
 	svc_rdma_put_req_map(vec);
 	dprintk("svcrdma: send_reply returns %d\n", ret);
 	return ret;
- error:
+
+ err1:
+	put_page(res_page);
+ err0:
 	svc_rdma_put_req_map(vec);
 	svc_rdma_put_context(ctxt, 0);
-	put_page(res_page);
 	return ret;
 }
diff --git a/net/sunrpc/xprtrdma/svc_rdma_transport.c b/net/sunrpc/xprtrdma/svc_rdma_transport.c
index 900cb69..6fb493c 100644
--- a/net/sunrpc/xprtrdma/svc_rdma_transport.c
+++ b/net/sunrpc/xprtrdma/svc_rdma_transport.c
@@ -100,20 +100,29 @@
 	ctxt->xprt = xprt;
 	INIT_LIST_HEAD(&ctxt->dto_q);
 	ctxt->count = 0;
+	ctxt->frmr = NULL;
 	atomic_inc(&xprt->sc_ctxt_used);
 	return ctxt;
 }
 
-static void svc_rdma_unmap_dma(struct svc_rdma_op_ctxt *ctxt)
+void svc_rdma_unmap_dma(struct svc_rdma_op_ctxt *ctxt)
 {
 	struct svcxprt_rdma *xprt = ctxt->xprt;
 	int i;
 	for (i = 0; i < ctxt->count && ctxt->sge[i].length; i++) {
-		atomic_dec(&xprt->sc_dma_used);
-		ib_dma_unmap_single(xprt->sc_cm_id->device,
-				    ctxt->sge[i].addr,
-				    ctxt->sge[i].length,
-				    ctxt->direction);
+		/*
+		 * Unmap the DMA addr in the SGE if the lkey matches
+		 * the sc_dma_lkey, otherwise, ignore it since it is
+		 * an FRMR lkey and will be unmapped later when the
+		 * last WR that uses it completes.
+		 */
+		if (ctxt->sge[i].lkey == xprt->sc_dma_lkey) {
+			atomic_dec(&xprt->sc_dma_used);
+			ib_dma_unmap_single(xprt->sc_cm_id->device,
+					    ctxt->sge[i].addr,
+					    ctxt->sge[i].length,
+					    ctxt->direction);
+		}
 	}
 }
 
@@ -150,6 +159,7 @@
 		schedule_timeout_uninterruptible(msecs_to_jiffies(500));
 	}
 	map->count = 0;
+	map->frmr = NULL;
 	return map;
 }
 
@@ -316,6 +326,50 @@
 }
 
 /*
+ * Processs a completion context
+ */
+static void process_context(struct svcxprt_rdma *xprt,
+			    struct svc_rdma_op_ctxt *ctxt)
+{
+	svc_rdma_unmap_dma(ctxt);
+
+	switch (ctxt->wr_op) {
+	case IB_WR_SEND:
+		if (test_bit(RDMACTXT_F_FAST_UNREG, &ctxt->flags))
+			svc_rdma_put_frmr(xprt, ctxt->frmr);
+		svc_rdma_put_context(ctxt, 1);
+		break;
+
+	case IB_WR_RDMA_WRITE:
+		svc_rdma_put_context(ctxt, 0);
+		break;
+
+	case IB_WR_RDMA_READ:
+	case IB_WR_RDMA_READ_WITH_INV:
+		if (test_bit(RDMACTXT_F_LAST_CTXT, &ctxt->flags)) {
+			struct svc_rdma_op_ctxt *read_hdr = ctxt->read_hdr;
+			BUG_ON(!read_hdr);
+			if (test_bit(RDMACTXT_F_FAST_UNREG, &ctxt->flags))
+				svc_rdma_put_frmr(xprt, ctxt->frmr);
+			spin_lock_bh(&xprt->sc_rq_dto_lock);
+			set_bit(XPT_DATA, &xprt->sc_xprt.xpt_flags);
+			list_add_tail(&read_hdr->dto_q,
+				      &xprt->sc_read_complete_q);
+			spin_unlock_bh(&xprt->sc_rq_dto_lock);
+			svc_xprt_enqueue(&xprt->sc_xprt);
+		}
+		svc_rdma_put_context(ctxt, 0);
+		break;
+
+	default:
+		printk(KERN_ERR "svcrdma: unexpected completion type, "
+		       "opcode=%d\n",
+		       ctxt->wr_op);
+		break;
+	}
+}
+
+/*
  * Send Queue Completion Handler - potentially called on interrupt context.
  *
  * Note that caller must hold a transport reference.
@@ -327,17 +381,12 @@
 	struct ib_cq *cq = xprt->sc_sq_cq;
 	int ret;
 
-
 	if (!test_and_clear_bit(RDMAXPRT_SQ_PENDING, &xprt->sc_flags))
 		return;
 
 	ib_req_notify_cq(xprt->sc_sq_cq, IB_CQ_NEXT_COMP);
 	atomic_inc(&rdma_stat_sq_poll);
 	while ((ret = ib_poll_cq(cq, 1, &wc)) > 0) {
-		ctxt = (struct svc_rdma_op_ctxt *)(unsigned long)wc.wr_id;
-		xprt = ctxt->xprt;
-
-		svc_rdma_unmap_dma(ctxt);
 		if (wc.status != IB_WC_SUCCESS)
 			/* Close the transport */
 			set_bit(XPT_CLOSE, &xprt->sc_xprt.xpt_flags);
@@ -346,35 +395,10 @@
 		atomic_dec(&xprt->sc_sq_count);
 		wake_up(&xprt->sc_send_wait);
 
-		switch (ctxt->wr_op) {
-		case IB_WR_SEND:
-			svc_rdma_put_context(ctxt, 1);
-			break;
+		ctxt = (struct svc_rdma_op_ctxt *)(unsigned long)wc.wr_id;
+		if (ctxt)
+			process_context(xprt, ctxt);
 
-		case IB_WR_RDMA_WRITE:
-			svc_rdma_put_context(ctxt, 0);
-			break;
-
-		case IB_WR_RDMA_READ:
-			if (test_bit(RDMACTXT_F_LAST_CTXT, &ctxt->flags)) {
-				struct svc_rdma_op_ctxt *read_hdr = ctxt->read_hdr;
-				BUG_ON(!read_hdr);
-				spin_lock_bh(&xprt->sc_rq_dto_lock);
-				set_bit(XPT_DATA, &xprt->sc_xprt.xpt_flags);
-				list_add_tail(&read_hdr->dto_q,
-					      &xprt->sc_read_complete_q);
-				spin_unlock_bh(&xprt->sc_rq_dto_lock);
-				svc_xprt_enqueue(&xprt->sc_xprt);
-			}
-			svc_rdma_put_context(ctxt, 0);
-			break;
-
-		default:
-			printk(KERN_ERR "svcrdma: unexpected completion type, "
-			       "opcode=%d, status=%d\n",
-			       wc.opcode, wc.status);
-			break;
-		}
 		svc_xprt_put(&xprt->sc_xprt);
 	}
 
@@ -425,10 +449,12 @@
 	INIT_LIST_HEAD(&cma_xprt->sc_dto_q);
 	INIT_LIST_HEAD(&cma_xprt->sc_rq_dto_q);
 	INIT_LIST_HEAD(&cma_xprt->sc_read_complete_q);
+	INIT_LIST_HEAD(&cma_xprt->sc_frmr_q);
 	init_waitqueue_head(&cma_xprt->sc_send_wait);
 
 	spin_lock_init(&cma_xprt->sc_lock);
 	spin_lock_init(&cma_xprt->sc_rq_dto_lock);
+	spin_lock_init(&cma_xprt->sc_frmr_q_lock);
 
 	cma_xprt->sc_ord = svcrdma_ord;
 
@@ -462,7 +488,7 @@
 	struct ib_recv_wr recv_wr, *bad_recv_wr;
 	struct svc_rdma_op_ctxt *ctxt;
 	struct page *page;
-	unsigned long pa;
+	dma_addr_t pa;
 	int sge_no;
 	int buflen;
 	int ret;
@@ -474,13 +500,15 @@
 		BUG_ON(sge_no >= xprt->sc_max_sge);
 		page = svc_rdma_get_page();
 		ctxt->pages[sge_no] = page;
-		atomic_inc(&xprt->sc_dma_used);
 		pa = ib_dma_map_page(xprt->sc_cm_id->device,
 				     page, 0, PAGE_SIZE,
 				     DMA_FROM_DEVICE);
+		if (ib_dma_mapping_error(xprt->sc_cm_id->device, pa))
+			goto err_put_ctxt;
+		atomic_inc(&xprt->sc_dma_used);
 		ctxt->sge[sge_no].addr = pa;
 		ctxt->sge[sge_no].length = PAGE_SIZE;
-		ctxt->sge[sge_no].lkey = xprt->sc_phys_mr->lkey;
+		ctxt->sge[sge_no].lkey = xprt->sc_dma_lkey;
 		buflen += PAGE_SIZE;
 	}
 	ctxt->count = sge_no;
@@ -496,6 +524,10 @@
 		svc_rdma_put_context(ctxt, 1);
 	}
 	return ret;
+
+ err_put_ctxt:
+	svc_rdma_put_context(ctxt, 1);
+	return -ENOMEM;
 }
 
 /*
@@ -566,7 +598,7 @@
 		dprintk("svcrdma: Connect request on cma_id=%p, xprt = %p, "
 			"event=%d\n", cma_id, cma_id->context, event->event);
 		handle_connect_req(cma_id,
-				   event->param.conn.responder_resources);
+				   event->param.conn.initiator_depth);
 		break;
 
 	case RDMA_CM_EVENT_ESTABLISHED:
@@ -686,6 +718,97 @@
 	return ERR_PTR(ret);
 }
 
+static struct svc_rdma_fastreg_mr *rdma_alloc_frmr(struct svcxprt_rdma *xprt)
+{
+	struct ib_mr *mr;
+	struct ib_fast_reg_page_list *pl;
+	struct svc_rdma_fastreg_mr *frmr;
+
+	frmr = kmalloc(sizeof(*frmr), GFP_KERNEL);
+	if (!frmr)
+		goto err;
+
+	mr = ib_alloc_fast_reg_mr(xprt->sc_pd, RPCSVC_MAXPAGES);
+	if (!mr)
+		goto err_free_frmr;
+
+	pl = ib_alloc_fast_reg_page_list(xprt->sc_cm_id->device,
+					 RPCSVC_MAXPAGES);
+	if (!pl)
+		goto err_free_mr;
+
+	frmr->mr = mr;
+	frmr->page_list = pl;
+	INIT_LIST_HEAD(&frmr->frmr_list);
+	return frmr;
+
+ err_free_mr:
+	ib_dereg_mr(mr);
+ err_free_frmr:
+	kfree(frmr);
+ err:
+	return ERR_PTR(-ENOMEM);
+}
+
+static void rdma_dealloc_frmr_q(struct svcxprt_rdma *xprt)
+{
+	struct svc_rdma_fastreg_mr *frmr;
+
+	while (!list_empty(&xprt->sc_frmr_q)) {
+		frmr = list_entry(xprt->sc_frmr_q.next,
+				  struct svc_rdma_fastreg_mr, frmr_list);
+		list_del_init(&frmr->frmr_list);
+		ib_dereg_mr(frmr->mr);
+		ib_free_fast_reg_page_list(frmr->page_list);
+		kfree(frmr);
+	}
+}
+
+struct svc_rdma_fastreg_mr *svc_rdma_get_frmr(struct svcxprt_rdma *rdma)
+{
+	struct svc_rdma_fastreg_mr *frmr = NULL;
+
+	spin_lock_bh(&rdma->sc_frmr_q_lock);
+	if (!list_empty(&rdma->sc_frmr_q)) {
+		frmr = list_entry(rdma->sc_frmr_q.next,
+				  struct svc_rdma_fastreg_mr, frmr_list);
+		list_del_init(&frmr->frmr_list);
+		frmr->map_len = 0;
+		frmr->page_list_len = 0;
+	}
+	spin_unlock_bh(&rdma->sc_frmr_q_lock);
+	if (frmr)
+		return frmr;
+
+	return rdma_alloc_frmr(rdma);
+}
+
+static void frmr_unmap_dma(struct svcxprt_rdma *xprt,
+			   struct svc_rdma_fastreg_mr *frmr)
+{
+	int page_no;
+	for (page_no = 0; page_no < frmr->page_list_len; page_no++) {
+		dma_addr_t addr = frmr->page_list->page_list[page_no];
+		if (ib_dma_mapping_error(frmr->mr->device, addr))
+			continue;
+		atomic_dec(&xprt->sc_dma_used);
+		ib_dma_unmap_single(frmr->mr->device, addr, PAGE_SIZE,
+				    frmr->direction);
+	}
+}
+
+void svc_rdma_put_frmr(struct svcxprt_rdma *rdma,
+		       struct svc_rdma_fastreg_mr *frmr)
+{
+	if (frmr) {
+		frmr_unmap_dma(rdma, frmr);
+		spin_lock_bh(&rdma->sc_frmr_q_lock);
+		BUG_ON(!list_empty(&frmr->frmr_list));
+		list_add(&frmr->frmr_list, &rdma->sc_frmr_q);
+		spin_unlock_bh(&rdma->sc_frmr_q_lock);
+	}
+}
+
 /*
  * This is the xpo_recvfrom function for listening endpoints. Its
  * purpose is to accept incoming connections. The CMA callback handler
@@ -704,6 +827,8 @@
 	struct rdma_conn_param conn_param;
 	struct ib_qp_init_attr qp_attr;
 	struct ib_device_attr devattr;
+	int dma_mr_acc;
+	int need_dma_mr;
 	int ret;
 	int i;
 
@@ -819,15 +944,77 @@
 	}
 	newxprt->sc_qp = newxprt->sc_cm_id->qp;
 
-	/* Register all of physical memory */
-	newxprt->sc_phys_mr = ib_get_dma_mr(newxprt->sc_pd,
-					    IB_ACCESS_LOCAL_WRITE |
-					    IB_ACCESS_REMOTE_WRITE);
-	if (IS_ERR(newxprt->sc_phys_mr)) {
-		dprintk("svcrdma: Failed to create DMA MR ret=%d\n", ret);
+	/*
+	 * Use the most secure set of MR resources based on the
+	 * transport type and available memory management features in
+	 * the device. Here's the table implemented below:
+	 *
+	 *		Fast	Global	DMA	Remote WR
+	 *		Reg	LKEY	MR	Access
+	 *		Sup'd	Sup'd	Needed	Needed
+	 *
+	 * IWARP	N	N	Y	Y
+	 *		N	Y	Y	Y
+	 *		Y	N	Y	N
+	 *		Y	Y	N	-
+	 *
+	 * IB		N	N	Y	N
+	 *		N	Y	N	-
+	 *		Y	N	Y	N
+	 *		Y	Y	N	-
+	 *
+	 * NB:	iWARP requires remote write access for the data sink
+	 *	of an RDMA_READ. IB does not.
+	 */
+	if (devattr.device_cap_flags & IB_DEVICE_MEM_MGT_EXTENSIONS) {
+		newxprt->sc_frmr_pg_list_len =
+			devattr.max_fast_reg_page_list_len;
+		newxprt->sc_dev_caps |= SVCRDMA_DEVCAP_FAST_REG;
+	}
+
+	/*
+	 * Determine if a DMA MR is required and if so, what privs are required
+	 */
+	switch (rdma_node_get_transport(newxprt->sc_cm_id->device->node_type)) {
+	case RDMA_TRANSPORT_IWARP:
+		newxprt->sc_dev_caps |= SVCRDMA_DEVCAP_READ_W_INV;
+		if (!(newxprt->sc_dev_caps & SVCRDMA_DEVCAP_FAST_REG)) {
+			need_dma_mr = 1;
+			dma_mr_acc =
+				(IB_ACCESS_LOCAL_WRITE |
+				 IB_ACCESS_REMOTE_WRITE);
+		} else if (!(devattr.device_cap_flags & IB_DEVICE_LOCAL_DMA_LKEY)) {
+			need_dma_mr = 1;
+			dma_mr_acc = IB_ACCESS_LOCAL_WRITE;
+		} else
+			need_dma_mr = 0;
+		break;
+	case RDMA_TRANSPORT_IB:
+		if (!(devattr.device_cap_flags & IB_DEVICE_LOCAL_DMA_LKEY)) {
+			need_dma_mr = 1;
+			dma_mr_acc = IB_ACCESS_LOCAL_WRITE;
+		} else
+			need_dma_mr = 0;
+		break;
+	default:
 		goto errout;
 	}
 
+	/* Create the DMA MR if needed, otherwise, use the DMA LKEY */
+	if (need_dma_mr) {
+		/* Register all of physical memory */
+		newxprt->sc_phys_mr =
+			ib_get_dma_mr(newxprt->sc_pd, dma_mr_acc);
+		if (IS_ERR(newxprt->sc_phys_mr)) {
+			dprintk("svcrdma: Failed to create DMA MR ret=%d\n",
+				ret);
+			goto errout;
+		}
+		newxprt->sc_dma_lkey = newxprt->sc_phys_mr->lkey;
+	} else
+		newxprt->sc_dma_lkey =
+			newxprt->sc_cm_id->device->local_dma_lkey;
+
 	/* Post receive buffers */
 	for (i = 0; i < newxprt->sc_max_requests; i++) {
 		ret = svc_rdma_post_recv(newxprt);
@@ -961,6 +1148,9 @@
 	WARN_ON(atomic_read(&rdma->sc_ctxt_used) != 0);
 	WARN_ON(atomic_read(&rdma->sc_dma_used) != 0);
 
+	/* De-allocate fastreg mr */
+	rdma_dealloc_frmr_q(rdma);
+
 	/* Destroy the QP if present (not a listener) */
 	if (rdma->sc_qp && !IS_ERR(rdma->sc_qp))
 		ib_destroy_qp(rdma->sc_qp);
@@ -1014,21 +1204,59 @@
 	return 1;
 }
 
+/*
+ * Attempt to register the kvec representing the RPC memory with the
+ * device.
+ *
+ * Returns:
+ *  NULL : The device does not support fastreg or there were no more
+ *         fastreg mr.
+ *  frmr : The kvec register request was successfully posted.
+ *    <0 : An error was encountered attempting to register the kvec.
+ */
+int svc_rdma_fastreg(struct svcxprt_rdma *xprt,
+		     struct svc_rdma_fastreg_mr *frmr)
+{
+	struct ib_send_wr fastreg_wr;
+	u8 key;
+
+	/* Bump the key */
+	key = (u8)(frmr->mr->lkey & 0x000000FF);
+	ib_update_fast_reg_key(frmr->mr, ++key);
+
+	/* Prepare FASTREG WR */
+	memset(&fastreg_wr, 0, sizeof fastreg_wr);
+	fastreg_wr.opcode = IB_WR_FAST_REG_MR;
+	fastreg_wr.send_flags = IB_SEND_SIGNALED;
+	fastreg_wr.wr.fast_reg.iova_start = (unsigned long)frmr->kva;
+	fastreg_wr.wr.fast_reg.page_list = frmr->page_list;
+	fastreg_wr.wr.fast_reg.page_list_len = frmr->page_list_len;
+	fastreg_wr.wr.fast_reg.page_shift = PAGE_SHIFT;
+	fastreg_wr.wr.fast_reg.length = frmr->map_len;
+	fastreg_wr.wr.fast_reg.access_flags = frmr->access_flags;
+	fastreg_wr.wr.fast_reg.rkey = frmr->mr->lkey;
+	return svc_rdma_send(xprt, &fastreg_wr);
+}
+
 int svc_rdma_send(struct svcxprt_rdma *xprt, struct ib_send_wr *wr)
 {
-	struct ib_send_wr *bad_wr;
+	struct ib_send_wr *bad_wr, *n_wr;
+	int wr_count;
+	int i;
 	int ret;
 
 	if (test_bit(XPT_CLOSE, &xprt->sc_xprt.xpt_flags))
 		return -ENOTCONN;
 
 	BUG_ON(wr->send_flags != IB_SEND_SIGNALED);
-	BUG_ON(((struct svc_rdma_op_ctxt *)(unsigned long)wr->wr_id)->wr_op !=
-		wr->opcode);
+	wr_count = 1;
+	for (n_wr = wr->next; n_wr; n_wr = n_wr->next)
+		wr_count++;
+
 	/* If the SQ is full, wait until an SQ entry is available */
 	while (1) {
 		spin_lock_bh(&xprt->sc_lock);
-		if (xprt->sc_sq_depth == atomic_read(&xprt->sc_sq_count)) {
+		if (xprt->sc_sq_depth < atomic_read(&xprt->sc_sq_count) + wr_count) {
 			spin_unlock_bh(&xprt->sc_lock);
 			atomic_inc(&rdma_stat_sq_starve);
 
@@ -1043,19 +1271,26 @@
 				return 0;
 			continue;
 		}
-		/* Bumped used SQ WR count and post */
-		svc_xprt_get(&xprt->sc_xprt);
+		/* Take a transport ref for each WR posted */
+		for (i = 0; i < wr_count; i++)
+			svc_xprt_get(&xprt->sc_xprt);
+
+		/* Bump used SQ WR count and post */
+		atomic_add(wr_count, &xprt->sc_sq_count);
 		ret = ib_post_send(xprt->sc_qp, wr, &bad_wr);
-		if (!ret)
-			atomic_inc(&xprt->sc_sq_count);
-		else {
-			svc_xprt_put(&xprt->sc_xprt);
+		if (ret) {
+			set_bit(XPT_CLOSE, &xprt->sc_xprt.xpt_flags);
+			atomic_sub(wr_count, &xprt->sc_sq_count);
+			for (i = 0; i < wr_count; i ++)
+				svc_xprt_put(&xprt->sc_xprt);
 			dprintk("svcrdma: failed to post SQ WR rc=%d, "
 			       "sc_sq_count=%d, sc_sq_depth=%d\n",
 			       ret, atomic_read(&xprt->sc_sq_count),
 			       xprt->sc_sq_depth);
 		}
 		spin_unlock_bh(&xprt->sc_lock);
+		if (ret)
+			wake_up(&xprt->sc_send_wait);
 		break;
 	}
 	return ret;
@@ -1079,10 +1314,14 @@
 	length = svc_rdma_xdr_encode_error(xprt, rmsgp, err, va);
 
 	/* Prepare SGE for local address */
-	atomic_inc(&xprt->sc_dma_used);
 	sge.addr = ib_dma_map_page(xprt->sc_cm_id->device,
 				   p, 0, PAGE_SIZE, DMA_FROM_DEVICE);
-	sge.lkey = xprt->sc_phys_mr->lkey;
+	if (ib_dma_mapping_error(xprt->sc_cm_id->device, sge.addr)) {
+		put_page(p);
+		return;
+	}
+	atomic_inc(&xprt->sc_dma_used);
+	sge.lkey = xprt->sc_dma_lkey;
 	sge.length = length;
 
 	ctxt = svc_rdma_get_context(xprt);
@@ -1103,6 +1342,9 @@
 	if (ret) {
 		dprintk("svcrdma: Error %d posting send for protocol error\n",
 			ret);
+		ib_dma_unmap_page(xprt->sc_cm_id->device,
+				  sge.addr, PAGE_SIZE,
+				  DMA_FROM_DEVICE);
 		svc_rdma_put_context(ctxt, 1);
 	}
 }
diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c
index 4486c59..9a288d5 100644
--- a/net/sunrpc/xprtsock.c
+++ b/net/sunrpc/xprtsock.c
@@ -3,8 +3,8 @@
  *
  * Client-side transport implementation for sockets.
  *
- * TCP callback races fixes (C) 1998 Red Hat Software <alan@redhat.com>
- * TCP send fixes (C) 1998 Red Hat Software <alan@redhat.com>
+ * TCP callback races fixes (C) 1998 Red Hat
+ * TCP send fixes (C) 1998 Red Hat
  * TCP NFS related read + write fixes
  *  (C) 1999 Dave Airlie, University of Limerick, Ireland <airlied@linux.ie>
  *
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index 015606b..c647aab 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -1,7 +1,7 @@
 /*
  * NET4:	Implementation of BSD Unix domain sockets.
  *
- * Authors:	Alan Cox, <alan.cox@linux.org>
+ * Authors:	Alan Cox, <alan@lxorguk.ukuu.org.uk>
  *
  *		This program is free software; you can redistribute it and/or
  *		modify it under the terms of the GNU General Public License
diff --git a/net/wireless/Kconfig b/net/wireless/Kconfig
index 833b024..7d82be0 100644
--- a/net/wireless/Kconfig
+++ b/net/wireless/Kconfig
@@ -14,6 +14,38 @@
 
 	  If unsure, say Y.
 
+config WIRELESS_OLD_REGULATORY
+	bool "Old wireless static regulatory definitions"
+	default n
+	---help---
+	  This option enables the old static regulatory information
+	  and uses it within the new framework. This is available
+	  temporarily as an option to help prevent immediate issues
+	  due to the switch to the new regulatory framework which
+	  does require a new userspace application which has the
+	  database of regulatory information (CRDA) and another for
+	  setting regulatory domains (iw).
+
+	  For more information see:
+
+	  http://wireless.kernel.org/en/developers/Regulatory/CRDA
+	  http://wireless.kernel.org/en/users/Documentation/iw
+
+	  It is important to note though that if you *do* have CRDA present
+	  and if this option is enabled CRDA *will* be called to update the
+	  regulatory domain (for US and JP only). Support for letting the user
+	  set the regulatory domain through iw is also supported. This option
+	  mainly exists to leave around for a kernel release some old static
+	  regulatory domains that were defined and to keep around the old
+	  ieee80211_regdom module parameter. This is being phased out and you
+	  should stop using them ASAP.
+
+	  Say N unless you cannot install a new userspace application
+	  or have one currently depending on the ieee80211_regdom module
+	  parameter and cannot port it to use the new userspace interfaces.
+
+	  This is scheduled for removal for 2.6.29.
+
 config WIRELESS_EXT
 	bool "Wireless extensions"
 	default n
diff --git a/net/wireless/core.c b/net/wireless/core.c
index f1da0b9..24fdd4c 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -1,7 +1,7 @@
 /*
  * This is the linux wireless configuration interface.
  *
- * Copyright 2006, 2007		Johannes Berg <johannes@sipsolutions.net>
+ * Copyright 2006-2008		Johannes Berg <johannes@sipsolutions.net>
  */
 
 #include <linux/if.h>
@@ -19,6 +19,7 @@
 #include "nl80211.h"
 #include "core.h"
 #include "sysfs.h"
+#include "reg.h"
 
 /* name for sysfs, %d is appended */
 #define PHY_NAME "phy"
@@ -32,7 +33,6 @@
  * often because we need to do it for each command */
 LIST_HEAD(cfg80211_drv_list);
 DEFINE_MUTEX(cfg80211_drv_mutex);
-static int wiphy_counter;
 
 /* for debugfs */
 static struct dentry *ieee80211_debugfs_dir;
@@ -204,6 +204,8 @@
 
 struct wiphy *wiphy_new(struct cfg80211_ops *ops, int sizeof_priv)
 {
+	static int wiphy_counter;
+
 	struct cfg80211_registered_device *drv;
 	int alloc_size;
 
@@ -220,21 +222,18 @@
 
 	mutex_lock(&cfg80211_drv_mutex);
 
-	drv->idx = wiphy_counter;
-
-	/* now increase counter for the next device unless
-	 * it has wrapped previously */
-	if (wiphy_counter >= 0)
-		wiphy_counter++;
-
-	mutex_unlock(&cfg80211_drv_mutex);
+	drv->idx = wiphy_counter++;
 
 	if (unlikely(drv->idx < 0)) {
+		wiphy_counter--;
+		mutex_unlock(&cfg80211_drv_mutex);
 		/* ugh, wrapped! */
 		kfree(drv);
 		return NULL;
 	}
 
+	mutex_unlock(&cfg80211_drv_mutex);
+
 	/* give it a proper name */
 	snprintf(drv->wiphy.dev.bus_id, BUS_ID_SIZE,
 		 PHY_NAME "%d", drv->idx);
@@ -259,6 +258,13 @@
 	struct ieee80211_supported_band *sband;
 	bool have_band = false;
 	int i;
+	u16 ifmodes = wiphy->interface_modes;
+
+	/* sanity check ifmodes */
+	WARN_ON(!ifmodes);
+	ifmodes &= ((1 << __NL80211_IFTYPE_AFTER_LAST) - 1) & ~1;
+	if (WARN_ON(ifmodes != wiphy->interface_modes))
+		wiphy->interface_modes = ifmodes;
 
 	/* sanity check supported bands/channels */
 	for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
@@ -295,7 +301,9 @@
 	ieee80211_set_bitrate_flags(wiphy);
 
 	/* set up regulatory info */
-	wiphy_update_regulatory(wiphy);
+	mutex_lock(&cfg80211_reg_mutex);
+	wiphy_update_regulatory(wiphy, REGDOM_SET_BY_CORE);
+	mutex_unlock(&cfg80211_reg_mutex);
 
 	mutex_lock(&cfg80211_drv_mutex);
 
@@ -373,6 +381,8 @@
 
 	rdev = wiphy_to_dev(dev->ieee80211_ptr->wiphy);
 
+	WARN_ON(dev->ieee80211_ptr->iftype == NL80211_IFTYPE_UNSPECIFIED);
+
 	switch (state) {
 	case NETDEV_REGISTER:
 		mutex_lock(&rdev->devlist_mtx);
@@ -404,7 +414,9 @@
 
 static int cfg80211_init(void)
 {
-	int err = wiphy_sysfs_init();
+	int err;
+
+	err = wiphy_sysfs_init();
 	if (err)
 		goto out_fail_sysfs;
 
@@ -418,8 +430,14 @@
 
 	ieee80211_debugfs_dir = debugfs_create_dir("ieee80211", NULL);
 
+	err = regulatory_init();
+	if (err)
+		goto out_fail_reg;
+
 	return 0;
 
+out_fail_reg:
+	debugfs_remove(ieee80211_debugfs_dir);
 out_fail_nl80211:
 	unregister_netdevice_notifier(&cfg80211_netdev_notifier);
 out_fail_notifier:
@@ -427,6 +445,7 @@
 out_fail_sysfs:
 	return err;
 }
+
 subsys_initcall(cfg80211_init);
 
 static void cfg80211_exit(void)
@@ -435,5 +454,6 @@
 	nl80211_exit();
 	unregister_netdevice_notifier(&cfg80211_netdev_notifier);
 	wiphy_sysfs_exit();
+	regulatory_exit();
 }
 module_exit(cfg80211_exit);
diff --git a/net/wireless/core.h b/net/wireless/core.h
index 7a02c35..771cc5c 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -79,6 +79,6 @@
 			       char *newname);
 
 void ieee80211_set_bitrate_flags(struct wiphy *wiphy);
-void wiphy_update_regulatory(struct wiphy *wiphy);
+void wiphy_update_regulatory(struct wiphy *wiphy, enum reg_set_by setby);
 
 #endif /* __NET_WIRELESS_CORE_H */
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 59eb2cf..572793c 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -18,6 +18,7 @@
 #include <net/cfg80211.h>
 #include "core.h"
 #include "nl80211.h"
+#include "reg.h"
 
 /* the netlink family */
 static struct genl_family nl80211_fam = {
@@ -87,6 +88,16 @@
 	[NL80211_ATTR_MESH_ID] = { .type = NLA_BINARY,
 				.len = IEEE80211_MAX_MESH_ID_LEN },
 	[NL80211_ATTR_MPATH_NEXT_HOP] = { .type = NLA_U32 },
+
+	[NL80211_ATTR_REG_ALPHA2] = { .type = NLA_STRING, .len = 2 },
+	[NL80211_ATTR_REG_RULES] = { .type = NLA_NESTED },
+
+	[NL80211_ATTR_BSS_CTS_PROT] = { .type = NLA_U8 },
+	[NL80211_ATTR_BSS_SHORT_PREAMBLE] = { .type = NLA_U8 },
+	[NL80211_ATTR_BSS_SHORT_SLOT_TIME] = { .type = NLA_U8 },
+
+	[NL80211_ATTR_HT_CAPABILITY] = { .type = NLA_BINARY,
+					 .len = NL80211_HT_CAPABILITY_LEN },
 };
 
 /* message building helper */
@@ -106,10 +117,12 @@
 	struct nlattr *nl_bands, *nl_band;
 	struct nlattr *nl_freqs, *nl_freq;
 	struct nlattr *nl_rates, *nl_rate;
+	struct nlattr *nl_modes;
 	enum ieee80211_band band;
 	struct ieee80211_channel *chan;
 	struct ieee80211_rate *rate;
 	int i;
+	u16 ifmodes = dev->wiphy.interface_modes;
 
 	hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_WIPHY);
 	if (!hdr)
@@ -118,6 +131,20 @@
 	NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, dev->idx);
 	NLA_PUT_STRING(msg, NL80211_ATTR_WIPHY_NAME, wiphy_name(&dev->wiphy));
 
+	nl_modes = nla_nest_start(msg, NL80211_ATTR_SUPPORTED_IFTYPES);
+	if (!nl_modes)
+		goto nla_put_failure;
+
+	i = 0;
+	while (ifmodes) {
+		if (ifmodes & 1)
+			NLA_PUT_FLAG(msg, i);
+		ifmodes >>= 1;
+		i++;
+	}
+
+	nla_nest_end(msg, nl_modes);
+
 	nl_bands = nla_nest_start(msg, NL80211_ATTR_WIPHY_BANDS);
 	if (!nl_bands)
 		goto nla_put_failure;
@@ -272,7 +299,7 @@
 
 	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex);
 	NLA_PUT_STRING(msg, NL80211_ATTR_IFNAME, dev->name);
-	/* TODO: interface type */
+	NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, dev->ieee80211_ptr->iftype);
 	return genlmsg_end(msg, hdr);
 
  nla_put_failure:
@@ -391,40 +418,56 @@
 	int err, ifindex;
 	enum nl80211_iftype type;
 	struct net_device *dev;
-	u32 flags;
+	u32 _flags, *flags = NULL;
 
 	memset(&params, 0, sizeof(params));
 
-	if (info->attrs[NL80211_ATTR_IFTYPE]) {
-		type = nla_get_u32(info->attrs[NL80211_ATTR_IFTYPE]);
-		if (type > NL80211_IFTYPE_MAX)
-			return -EINVAL;
-	} else
-		return -EINVAL;
-
 	err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
 	if (err)
 		return err;
 	ifindex = dev->ifindex;
+	type = dev->ieee80211_ptr->iftype;
 	dev_put(dev);
 
-	if (!drv->ops->change_virtual_intf) {
+	err = -EINVAL;
+	if (info->attrs[NL80211_ATTR_IFTYPE]) {
+		type = nla_get_u32(info->attrs[NL80211_ATTR_IFTYPE]);
+		if (type > NL80211_IFTYPE_MAX)
+			goto unlock;
+	}
+
+	if (!drv->ops->change_virtual_intf ||
+	    !(drv->wiphy.interface_modes & (1 << type))) {
 		err = -EOPNOTSUPP;
 		goto unlock;
 	}
 
-	if (type == NL80211_IFTYPE_MESH_POINT &&
-	    info->attrs[NL80211_ATTR_MESH_ID]) {
+	if (info->attrs[NL80211_ATTR_MESH_ID]) {
+		if (type != NL80211_IFTYPE_MESH_POINT) {
+			err = -EINVAL;
+			goto unlock;
+		}
 		params.mesh_id = nla_data(info->attrs[NL80211_ATTR_MESH_ID]);
 		params.mesh_id_len = nla_len(info->attrs[NL80211_ATTR_MESH_ID]);
 	}
 
+	if (info->attrs[NL80211_ATTR_MNTR_FLAGS]) {
+		if (type != NL80211_IFTYPE_MONITOR) {
+			err = -EINVAL;
+			goto unlock;
+		}
+		err = parse_monitor_flags(info->attrs[NL80211_ATTR_MNTR_FLAGS],
+					  &_flags);
+		if (!err)
+			flags = &_flags;
+	}
 	rtnl_lock();
-	err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ?
-				  info->attrs[NL80211_ATTR_MNTR_FLAGS] : NULL,
-				  &flags);
 	err = drv->ops->change_virtual_intf(&drv->wiphy, ifindex,
-					    type, err ? NULL : &flags, &params);
+					    type, flags, &params);
+
+	dev = __dev_get_by_index(&init_net, ifindex);
+	WARN_ON(!dev || (!err && dev->ieee80211_ptr->iftype != type));
+
 	rtnl_unlock();
 
  unlock:
@@ -455,7 +498,8 @@
 	if (IS_ERR(drv))
 		return PTR_ERR(drv);
 
-	if (!drv->ops->add_virtual_intf) {
+	if (!drv->ops->add_virtual_intf ||
+	    !(drv->wiphy.interface_modes & (1 << type))) {
 		err = -EOPNOTSUPP;
 		goto unlock;
 	}
@@ -1125,6 +1169,10 @@
 		params.listen_interval =
 		    nla_get_u16(info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]);
 
+	if (info->attrs[NL80211_ATTR_HT_CAPABILITY])
+		params.ht_capa =
+			nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]);
+
 	if (parse_station_flags(info->attrs[NL80211_ATTR_STA_FLAGS],
 				&params.station_flags))
 		return -EINVAL;
@@ -1188,6 +1236,9 @@
 	params.listen_interval =
 		nla_get_u16(info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]);
 	params.aid = nla_get_u16(info->attrs[NL80211_ATTR_STA_AID]);
+	if (info->attrs[NL80211_ATTR_HT_CAPABILITY])
+		params.ht_capa =
+			nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]);
 
 	if (parse_station_flags(info->attrs[NL80211_ATTR_STA_FLAGS],
 				&params.station_flags))
@@ -1525,6 +1576,183 @@
 	return err;
 }
 
+static int nl80211_set_bss(struct sk_buff *skb, struct genl_info *info)
+{
+	struct cfg80211_registered_device *drv;
+	int err;
+	struct net_device *dev;
+	struct bss_parameters params;
+
+	memset(&params, 0, sizeof(params));
+	/* default to not changing parameters */
+	params.use_cts_prot = -1;
+	params.use_short_preamble = -1;
+	params.use_short_slot_time = -1;
+
+	if (info->attrs[NL80211_ATTR_BSS_CTS_PROT])
+		params.use_cts_prot =
+		    nla_get_u8(info->attrs[NL80211_ATTR_BSS_CTS_PROT]);
+	if (info->attrs[NL80211_ATTR_BSS_SHORT_PREAMBLE])
+		params.use_short_preamble =
+		    nla_get_u8(info->attrs[NL80211_ATTR_BSS_SHORT_PREAMBLE]);
+	if (info->attrs[NL80211_ATTR_BSS_SHORT_SLOT_TIME])
+		params.use_short_slot_time =
+		    nla_get_u8(info->attrs[NL80211_ATTR_BSS_SHORT_SLOT_TIME]);
+
+	err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
+	if (err)
+		return err;
+
+	if (!drv->ops->change_bss) {
+		err = -EOPNOTSUPP;
+		goto out;
+	}
+
+	rtnl_lock();
+	err = drv->ops->change_bss(&drv->wiphy, dev, &params);
+	rtnl_unlock();
+
+ out:
+	cfg80211_put_dev(drv);
+	dev_put(dev);
+	return err;
+}
+
+static const struct nla_policy
+	reg_rule_policy[NL80211_REG_RULE_ATTR_MAX + 1] = {
+	[NL80211_ATTR_REG_RULE_FLAGS]		= { .type = NLA_U32 },
+	[NL80211_ATTR_FREQ_RANGE_START]		= { .type = NLA_U32 },
+	[NL80211_ATTR_FREQ_RANGE_END]		= { .type = NLA_U32 },
+	[NL80211_ATTR_FREQ_RANGE_MAX_BW]	= { .type = NLA_U32 },
+	[NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN]	= { .type = NLA_U32 },
+	[NL80211_ATTR_POWER_RULE_MAX_EIRP]	= { .type = NLA_U32 },
+};
+
+static int parse_reg_rule(struct nlattr *tb[],
+	struct ieee80211_reg_rule *reg_rule)
+{
+	struct ieee80211_freq_range *freq_range = &reg_rule->freq_range;
+	struct ieee80211_power_rule *power_rule = &reg_rule->power_rule;
+
+	if (!tb[NL80211_ATTR_REG_RULE_FLAGS])
+		return -EINVAL;
+	if (!tb[NL80211_ATTR_FREQ_RANGE_START])
+		return -EINVAL;
+	if (!tb[NL80211_ATTR_FREQ_RANGE_END])
+		return -EINVAL;
+	if (!tb[NL80211_ATTR_FREQ_RANGE_MAX_BW])
+		return -EINVAL;
+	if (!tb[NL80211_ATTR_POWER_RULE_MAX_EIRP])
+		return -EINVAL;
+
+	reg_rule->flags = nla_get_u32(tb[NL80211_ATTR_REG_RULE_FLAGS]);
+
+	freq_range->start_freq_khz =
+		nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_START]);
+	freq_range->end_freq_khz =
+		nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_END]);
+	freq_range->max_bandwidth_khz =
+		nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_MAX_BW]);
+
+	power_rule->max_eirp =
+		nla_get_u32(tb[NL80211_ATTR_POWER_RULE_MAX_EIRP]);
+
+	if (tb[NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN])
+		power_rule->max_antenna_gain =
+			nla_get_u32(tb[NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN]);
+
+	return 0;
+}
+
+static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info)
+{
+	int r;
+	char *data = NULL;
+
+	if (!info->attrs[NL80211_ATTR_REG_ALPHA2])
+		return -EINVAL;
+
+	data = nla_data(info->attrs[NL80211_ATTR_REG_ALPHA2]);
+
+#ifdef CONFIG_WIRELESS_OLD_REGULATORY
+	/* We ignore world regdom requests with the old regdom setup */
+	if (is_world_regdom(data))
+		return -EINVAL;
+#endif
+	mutex_lock(&cfg80211_drv_mutex);
+	r = __regulatory_hint(NULL, REGDOM_SET_BY_USER, data, NULL);
+	mutex_unlock(&cfg80211_drv_mutex);
+	return r;
+}
+
+static int nl80211_set_reg(struct sk_buff *skb, struct genl_info *info)
+{
+	struct nlattr *tb[NL80211_REG_RULE_ATTR_MAX + 1];
+	struct nlattr *nl_reg_rule;
+	char *alpha2 = NULL;
+	int rem_reg_rules = 0, r = 0;
+	u32 num_rules = 0, rule_idx = 0, size_of_regd;
+	struct ieee80211_regdomain *rd = NULL;
+
+	if (!info->attrs[NL80211_ATTR_REG_ALPHA2])
+		return -EINVAL;
+
+	if (!info->attrs[NL80211_ATTR_REG_RULES])
+		return -EINVAL;
+
+	alpha2 = nla_data(info->attrs[NL80211_ATTR_REG_ALPHA2]);
+
+	nla_for_each_nested(nl_reg_rule, info->attrs[NL80211_ATTR_REG_RULES],
+			rem_reg_rules) {
+		num_rules++;
+		if (num_rules > NL80211_MAX_SUPP_REG_RULES)
+			goto bad_reg;
+	}
+
+	if (!reg_is_valid_request(alpha2))
+		return -EINVAL;
+
+	size_of_regd = sizeof(struct ieee80211_regdomain) +
+		(num_rules * sizeof(struct ieee80211_reg_rule));
+
+	rd = kzalloc(size_of_regd, GFP_KERNEL);
+	if (!rd)
+		return -ENOMEM;
+
+	rd->n_reg_rules = num_rules;
+	rd->alpha2[0] = alpha2[0];
+	rd->alpha2[1] = alpha2[1];
+
+	nla_for_each_nested(nl_reg_rule, info->attrs[NL80211_ATTR_REG_RULES],
+			rem_reg_rules) {
+		nla_parse(tb, NL80211_REG_RULE_ATTR_MAX,
+			nla_data(nl_reg_rule), nla_len(nl_reg_rule),
+			reg_rule_policy);
+		r = parse_reg_rule(tb, &rd->reg_rules[rule_idx]);
+		if (r)
+			goto bad_reg;
+
+		rule_idx++;
+
+		if (rule_idx > NL80211_MAX_SUPP_REG_RULES)
+			goto bad_reg;
+	}
+
+	BUG_ON(rule_idx != num_rules);
+
+	mutex_lock(&cfg80211_drv_mutex);
+	r = set_regdom(rd);
+	mutex_unlock(&cfg80211_drv_mutex);
+	if (r)
+		goto bad_reg;
+
+	return r;
+
+bad_reg:
+	kfree(rd);
+	return -EINVAL;
+}
+
 static struct genl_ops nl80211_ops[] = {
 	{
 		.cmd = NL80211_CMD_GET_WIPHY,
@@ -1656,6 +1884,24 @@
 		.policy = nl80211_policy,
 		.flags = GENL_ADMIN_PERM,
 	},
+	{
+		.cmd = NL80211_CMD_SET_BSS,
+		.doit = nl80211_set_bss,
+		.policy = nl80211_policy,
+		.flags = GENL_ADMIN_PERM,
+	},
+	{
+		.cmd = NL80211_CMD_SET_REG,
+		.doit = nl80211_set_reg,
+		.policy = nl80211_policy,
+		.flags = GENL_ADMIN_PERM,
+	},
+	{
+		.cmd = NL80211_CMD_REQ_SET_REG,
+		.doit = nl80211_req_set_reg,
+		.policy = nl80211_policy,
+		.flags = GENL_ADMIN_PERM,
+	},
 };
 
 /* multicast groups */
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index 855bff4..626dbb68 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -2,179 +2,871 @@
  * Copyright 2002-2005, Instant802 Networks, Inc.
  * Copyright 2005-2006, Devicescape Software, Inc.
  * Copyright 2007	Johannes Berg <johannes@sipsolutions.net>
+ * Copyright 2008	Luis R. Rodriguez <lrodriguz@atheros.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.
  */
 
-/*
- * This regulatory domain control implementation is highly incomplete, it
- * only exists for the purpose of not regressing mac80211.
- *
- * For now, drivers can restrict the set of allowed channels by either
- * not registering those channels or setting the IEEE80211_CHAN_DISABLED
- * flag; that flag will only be *set* by this code, never *cleared.
+/**
+ * DOC: Wireless regulatory infrastructure
  *
  * The usual implementation is for a driver to read a device EEPROM to
  * determine which regulatory domain it should be operating under, then
  * looking up the allowable channels in a driver-local table and finally
  * registering those channels in the wiphy structure.
  *
- * Alternatively, drivers that trust the regulatory domain control here
- * will register a complete set of capabilities and the control code
- * will restrict the set by setting the IEEE80211_CHAN_* flags.
+ * Another set of compliance enforcement is for drivers to use their
+ * own compliance limits which can be stored on the EEPROM. The host
+ * driver or firmware may ensure these are used.
+ *
+ * In addition to all this we provide an extra layer of regulatory
+ * conformance. For drivers which do not have any regulatory
+ * information CRDA provides the complete regulatory solution.
+ * For others it provides a community effort on further restrictions
+ * to enhance compliance.
+ *
+ * Note: When number of rules --> infinity we will not be able to
+ * index on alpha2 any more, instead we'll probably have to
+ * rely on some SHA1 checksum of the regdomain for example.
+ *
  */
 #include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/random.h>
+#include <linux/nl80211.h>
+#include <linux/platform_device.h>
 #include <net/wireless.h>
+#include <net/cfg80211.h>
 #include "core.h"
+#include "reg.h"
 
+/* wiphy is set if this request's initiator is REGDOM_SET_BY_DRIVER */
+struct regulatory_request {
+	struct list_head list;
+	struct wiphy *wiphy;
+	int granted;
+	enum reg_set_by initiator;
+	char alpha2[2];
+};
+
+static LIST_HEAD(regulatory_requests);
+DEFINE_MUTEX(cfg80211_reg_mutex);
+
+/* To trigger userspace events */
+static struct platform_device *reg_pdev;
+
+/* Keep the ordering from large to small */
+static u32 supported_bandwidths[] = {
+	MHZ_TO_KHZ(40),
+	MHZ_TO_KHZ(20),
+};
+
+static struct list_head regulatory_requests;
+
+/* Central wireless core regulatory domains, we only need two,
+ * the current one and a world regulatory domain in case we have no
+ * information to give us an alpha2 */
+static const struct ieee80211_regdomain *cfg80211_regdomain;
+
+/* We keep a static world regulatory domain in case of the absence of CRDA */
+static const struct ieee80211_regdomain world_regdom = {
+	.n_reg_rules = 1,
+	.alpha2 =  "00",
+	.reg_rules = {
+		REG_RULE(2412-10, 2462+10, 40, 6, 20,
+			NL80211_RRF_PASSIVE_SCAN |
+			NL80211_RRF_NO_IBSS),
+	}
+};
+
+static const struct ieee80211_regdomain *cfg80211_world_regdom =
+	&world_regdom;
+
+#ifdef CONFIG_WIRELESS_OLD_REGULATORY
 static char *ieee80211_regdom = "US";
 module_param(ieee80211_regdom, charp, 0444);
 MODULE_PARM_DESC(ieee80211_regdom, "IEEE 802.11 regulatory domain code");
 
-struct ieee80211_channel_range {
-	short start_freq;
-	short end_freq;
-	int max_power;
-	int max_antenna_gain;
-	u32 flags;
-};
+/* We assume 40 MHz bandwidth for the old regulatory work.
+ * We make emphasis we are using the exact same frequencies
+ * as before */
 
-struct ieee80211_regdomain {
-	const char *code;
-	const struct ieee80211_channel_range *ranges;
-	int n_ranges;
-};
-
-#define RANGE_PWR(_start, _end, _pwr, _ag, _flags)	\
-	{ _start, _end, _pwr, _ag, _flags }
-
-
-/*
- * Ideally, in the future, these definitions will be loaded from a
- * userspace table via some daemon.
- */
-static const struct ieee80211_channel_range ieee80211_US_channels[] = {
-	/* IEEE 802.11b/g, channels 1..11 */
-	RANGE_PWR(2412, 2462, 27, 6, 0),
-	/* IEEE 802.11a, channel 36*/
-	RANGE_PWR(5180, 5180, 23, 6, 0),
-	/* IEEE 802.11a, channel 40*/
-	RANGE_PWR(5200, 5200, 23, 6, 0),
-	/* IEEE 802.11a, channel 44*/
-	RANGE_PWR(5220, 5220, 23, 6, 0),
-	/* IEEE 802.11a, channels 48..64 */
-	RANGE_PWR(5240, 5320, 23, 6, 0),
-	/* IEEE 802.11a, channels 149..165, outdoor */
-	RANGE_PWR(5745, 5825, 30, 6, 0),
-};
-
-static const struct ieee80211_channel_range ieee80211_JP_channels[] = {
-	/* IEEE 802.11b/g, channels 1..14 */
-	RANGE_PWR(2412, 2484, 20, 6, 0),
-	/* IEEE 802.11a, channels 34..48 */
-	RANGE_PWR(5170, 5240, 20, 6, IEEE80211_CHAN_PASSIVE_SCAN),
-	/* IEEE 802.11a, channels 52..64 */
-	RANGE_PWR(5260, 5320, 20, 6, IEEE80211_CHAN_NO_IBSS |
-				     IEEE80211_CHAN_RADAR),
-};
-
-static const struct ieee80211_channel_range ieee80211_EU_channels[] = {
-	/* IEEE 802.11b/g, channels 1..13 */
-	RANGE_PWR(2412, 2472, 20, 6, 0),
-	/* IEEE 802.11a, channel 36*/
-	RANGE_PWR(5180, 5180, 23, 6, IEEE80211_CHAN_PASSIVE_SCAN),
-	/* IEEE 802.11a, channel 40*/
-	RANGE_PWR(5200, 5200, 23, 6, IEEE80211_CHAN_PASSIVE_SCAN),
-	/* IEEE 802.11a, channel 44*/
-	RANGE_PWR(5220, 5220, 23, 6, IEEE80211_CHAN_PASSIVE_SCAN),
-	/* IEEE 802.11a, channels 48..64 */
-	RANGE_PWR(5240, 5320, 23, 6, IEEE80211_CHAN_NO_IBSS |
-				     IEEE80211_CHAN_RADAR),
-	/* IEEE 802.11a, channels 100..140 */
-	RANGE_PWR(5500, 5700, 30, 6, IEEE80211_CHAN_NO_IBSS |
-				     IEEE80211_CHAN_RADAR),
-};
-
-#define REGDOM(_code)							\
-	{								\
-		.code = __stringify(_code),				\
-		.ranges = ieee80211_ ##_code## _channels,		\
-		.n_ranges = ARRAY_SIZE(ieee80211_ ##_code## _channels),	\
-	}
-
-static const struct ieee80211_regdomain ieee80211_regdoms[] = {
-	REGDOM(US),
-	REGDOM(JP),
-	REGDOM(EU),
-};
-
-
-static const struct ieee80211_regdomain *get_regdom(void)
-{
-	static const struct ieee80211_channel_range
-	ieee80211_world_channels[] = {
+static const struct ieee80211_regdomain us_regdom = {
+	.n_reg_rules = 6,
+	.alpha2 =  "US",
+	.reg_rules = {
 		/* IEEE 802.11b/g, channels 1..11 */
-		RANGE_PWR(2412, 2462, 27, 6, 0),
-	};
-	static const struct ieee80211_regdomain regdom_world = REGDOM(world);
-	int i;
+		REG_RULE(2412-10, 2462+10, 40, 6, 27, 0),
+		/* IEEE 802.11a, channel 36 */
+		REG_RULE(5180-10, 5180+10, 40, 6, 23, 0),
+		/* IEEE 802.11a, channel 40 */
+		REG_RULE(5200-10, 5200+10, 40, 6, 23, 0),
+		/* IEEE 802.11a, channel 44 */
+		REG_RULE(5220-10, 5220+10, 40, 6, 23, 0),
+		/* IEEE 802.11a, channels 48..64 */
+		REG_RULE(5240-10, 5320+10, 40, 6, 23, 0),
+		/* IEEE 802.11a, channels 149..165, outdoor */
+		REG_RULE(5745-10, 5825+10, 40, 6, 30, 0),
+	}
+};
 
-	for (i = 0; i < ARRAY_SIZE(ieee80211_regdoms); i++)
-		if (strcmp(ieee80211_regdom, ieee80211_regdoms[i].code) == 0)
-			return &ieee80211_regdoms[i];
+static const struct ieee80211_regdomain jp_regdom = {
+	.n_reg_rules = 3,
+	.alpha2 =  "JP",
+	.reg_rules = {
+		/* IEEE 802.11b/g, channels 1..14 */
+		REG_RULE(2412-10, 2484+10, 40, 6, 20, 0),
+		/* IEEE 802.11a, channels 34..48 */
+		REG_RULE(5170-10, 5240+10, 40, 6, 20,
+			NL80211_RRF_PASSIVE_SCAN),
+		/* IEEE 802.11a, channels 52..64 */
+		REG_RULE(5260-10, 5320+10, 40, 6, 20,
+			NL80211_RRF_NO_IBSS |
+			NL80211_RRF_DFS),
+	}
+};
 
-	return &regdom_world;
+static const struct ieee80211_regdomain eu_regdom = {
+	.n_reg_rules = 6,
+	/* This alpha2 is bogus, we leave it here just for stupid
+	 * backward compatibility */
+	.alpha2 =  "EU",
+	.reg_rules = {
+		/* IEEE 802.11b/g, channels 1..13 */
+		REG_RULE(2412-10, 2472+10, 40, 6, 20, 0),
+		/* IEEE 802.11a, channel 36 */
+		REG_RULE(5180-10, 5180+10, 40, 6, 23,
+			NL80211_RRF_PASSIVE_SCAN),
+		/* IEEE 802.11a, channel 40 */
+		REG_RULE(5200-10, 5200+10, 40, 6, 23,
+			NL80211_RRF_PASSIVE_SCAN),
+		/* IEEE 802.11a, channel 44 */
+		REG_RULE(5220-10, 5220+10, 40, 6, 23,
+			NL80211_RRF_PASSIVE_SCAN),
+		/* IEEE 802.11a, channels 48..64 */
+		REG_RULE(5240-10, 5320+10, 40, 6, 20,
+			NL80211_RRF_NO_IBSS |
+			NL80211_RRF_DFS),
+		/* IEEE 802.11a, channels 100..140 */
+		REG_RULE(5500-10, 5700+10, 40, 6, 30,
+			NL80211_RRF_NO_IBSS |
+			NL80211_RRF_DFS),
+	}
+};
+
+static const struct ieee80211_regdomain *static_regdom(char *alpha2)
+{
+	if (alpha2[0] == 'U' && alpha2[1] == 'S')
+		return &us_regdom;
+	if (alpha2[0] == 'J' && alpha2[1] == 'P')
+		return &jp_regdom;
+	if (alpha2[0] == 'E' && alpha2[1] == 'U')
+		return &eu_regdom;
+	/* Default, as per the old rules */
+	return &us_regdom;
 }
 
+static bool is_old_static_regdom(const struct ieee80211_regdomain *rd)
+{
+	if (rd == &us_regdom || rd == &jp_regdom || rd == &eu_regdom)
+		return true;
+	return false;
+}
+#else
+static inline bool is_old_static_regdom(const struct ieee80211_regdomain *rd)
+{
+	return false;
+}
+#endif
 
-static void handle_channel(struct ieee80211_channel *chan,
-			   const struct ieee80211_regdomain *rd)
+static void reset_regdomains(void)
+{
+	/* avoid freeing static information or freeing something twice */
+	if (cfg80211_regdomain == cfg80211_world_regdom)
+		cfg80211_regdomain = NULL;
+	if (cfg80211_world_regdom == &world_regdom)
+		cfg80211_world_regdom = NULL;
+	if (cfg80211_regdomain == &world_regdom)
+		cfg80211_regdomain = NULL;
+	if (is_old_static_regdom(cfg80211_regdomain))
+		cfg80211_regdomain = NULL;
+
+	kfree(cfg80211_regdomain);
+	kfree(cfg80211_world_regdom);
+
+	cfg80211_world_regdom = &world_regdom;
+	cfg80211_regdomain = NULL;
+}
+
+/* Dynamic world regulatory domain requested by the wireless
+ * core upon initialization */
+static void update_world_regdomain(const struct ieee80211_regdomain *rd)
+{
+	BUG_ON(list_empty(&regulatory_requests));
+
+	reset_regdomains();
+
+	cfg80211_world_regdom = rd;
+	cfg80211_regdomain = rd;
+}
+
+bool is_world_regdom(const char *alpha2)
+{
+	if (!alpha2)
+		return false;
+	if (alpha2[0] == '0' && alpha2[1] == '0')
+		return true;
+	return false;
+}
+
+static bool is_alpha2_set(const char *alpha2)
+{
+	if (!alpha2)
+		return false;
+	if (alpha2[0] != 0 && alpha2[1] != 0)
+		return true;
+	return false;
+}
+
+static bool is_alpha_upper(char letter)
+{
+	/* ASCII A - Z */
+	if (letter >= 65 && letter <= 90)
+		return true;
+	return false;
+}
+
+static bool is_unknown_alpha2(const char *alpha2)
+{
+	if (!alpha2)
+		return false;
+	/* Special case where regulatory domain was built by driver
+	 * but a specific alpha2 cannot be determined */
+	if (alpha2[0] == '9' && alpha2[1] == '9')
+		return true;
+	return false;
+}
+
+static bool is_an_alpha2(const char *alpha2)
+{
+	if (!alpha2)
+		return false;
+	if (is_alpha_upper(alpha2[0]) && is_alpha_upper(alpha2[1]))
+		return true;
+	return false;
+}
+
+static bool alpha2_equal(const char *alpha2_x, const char *alpha2_y)
+{
+	if (!alpha2_x || !alpha2_y)
+		return false;
+	if (alpha2_x[0] == alpha2_y[0] &&
+		alpha2_x[1] == alpha2_y[1])
+		return true;
+	return false;
+}
+
+static bool regdom_changed(const char *alpha2)
+{
+	if (!cfg80211_regdomain)
+		return true;
+	if (alpha2_equal(cfg80211_regdomain->alpha2, alpha2))
+		return false;
+	return true;
+}
+
+/* This lets us keep regulatory code which is updated on a regulatory
+ * basis in userspace. */
+static int call_crda(const char *alpha2)
+{
+	char country_env[9 + 2] = "COUNTRY=";
+	char *envp[] = {
+		country_env,
+		NULL
+	};
+
+	if (!is_world_regdom((char *) alpha2))
+		printk(KERN_INFO "cfg80211: Calling CRDA for country: %c%c\n",
+			alpha2[0], alpha2[1]);
+	else
+		printk(KERN_INFO "cfg80211: Calling CRDA to update world "
+			"regulatory domain\n");
+
+	country_env[8] = alpha2[0];
+	country_env[9] = alpha2[1];
+
+	return kobject_uevent_env(&reg_pdev->dev.kobj, KOBJ_CHANGE, envp);
+}
+
+/* This has the logic which determines when a new request
+ * should be ignored. */
+static int ignore_request(struct wiphy *wiphy, enum reg_set_by set_by,
+	char *alpha2, struct ieee80211_regdomain *rd)
+{
+	struct regulatory_request *last_request = NULL;
+
+	/* All initial requests are respected */
+	if (list_empty(&regulatory_requests))
+		return 0;
+
+	last_request = list_first_entry(&regulatory_requests,
+		struct regulatory_request, list);
+
+	switch (set_by) {
+	case REGDOM_SET_BY_INIT:
+		return -EINVAL;
+	case REGDOM_SET_BY_CORE:
+		/* Always respect new wireless core hints, should only
+		 * come in for updating the world regulatory domain at init
+		 * anyway */
+		return 0;
+	case REGDOM_SET_BY_COUNTRY_IE:
+		if (last_request->initiator == set_by) {
+			if (last_request->wiphy != wiphy) {
+				/* Two cards with two APs claiming different
+				 * different Country IE alpha2s!
+				 * You're special!! */
+				if (!alpha2_equal(last_request->alpha2,
+						cfg80211_regdomain->alpha2)) {
+					/* XXX: Deal with conflict, consider
+					 * building a new one out of the
+					 * intersection */
+					WARN_ON(1);
+					return -EOPNOTSUPP;
+				}
+				return -EALREADY;
+			}
+			/* Two consecutive Country IE hints on the same wiphy */
+			if (!alpha2_equal(cfg80211_regdomain->alpha2, alpha2))
+				return 0;
+			return -EALREADY;
+		}
+		if (WARN_ON(!is_alpha2_set(alpha2) || !is_an_alpha2(alpha2)),
+				"Invalid Country IE regulatory hint passed "
+				"to the wireless core\n")
+			return -EINVAL;
+		/* We ignore Country IE hints for now, as we haven't yet
+		 * added the dot11MultiDomainCapabilityEnabled flag
+		 * for wiphys */
+		return 1;
+	case REGDOM_SET_BY_DRIVER:
+		BUG_ON(!wiphy);
+		if (last_request->initiator == set_by) {
+			/* Two separate drivers hinting different things,
+			 * this is possible if you have two devices present
+			 * on a system with different EEPROM regulatory
+			 * readings. XXX: Do intersection, we support only
+			 * the first regulatory hint for now */
+			if (last_request->wiphy != wiphy)
+				return -EALREADY;
+			if (rd)
+				return -EALREADY;
+			/* Driver should not be trying to hint different
+			 * regulatory domains! */
+			BUG_ON(!alpha2_equal(alpha2,
+					cfg80211_regdomain->alpha2));
+			return -EALREADY;
+		}
+		if (last_request->initiator == REGDOM_SET_BY_CORE)
+			return 0;
+		/* XXX: Handle intersection, and add the
+		 * dot11MultiDomainCapabilityEnabled flag to wiphy. For now
+		 * we assume the driver has this set to false, following the
+		 * 802.11d dot11MultiDomainCapabilityEnabled documentation */
+		if (last_request->initiator == REGDOM_SET_BY_COUNTRY_IE)
+			return 0;
+		return 0;
+	case REGDOM_SET_BY_USER:
+		if (last_request->initiator == set_by ||
+				last_request->initiator == REGDOM_SET_BY_CORE)
+			return 0;
+		/* Drivers can use their wiphy's reg_notifier()
+		 * to override any information */
+		if (last_request->initiator == REGDOM_SET_BY_DRIVER)
+			return 0;
+		/* XXX: Handle intersection */
+		if (last_request->initiator == REGDOM_SET_BY_COUNTRY_IE)
+			return -EOPNOTSUPP;
+		return 0;
+	default:
+		return -EINVAL;
+	}
+}
+
+static bool __reg_is_valid_request(const char *alpha2,
+	struct regulatory_request **request)
+{
+	struct regulatory_request *req;
+	if (list_empty(&regulatory_requests))
+		return false;
+	list_for_each_entry(req, &regulatory_requests, list) {
+		if (alpha2_equal(req->alpha2, alpha2)) {
+			*request = req;
+			return true;
+		}
+	}
+	return false;
+}
+
+/* Used by nl80211 before kmalloc'ing our regulatory domain */
+bool reg_is_valid_request(const char *alpha2)
+{
+	struct regulatory_request *request = NULL;
+	return  __reg_is_valid_request(alpha2, &request);
+}
+
+/* Sanity check on a regulatory rule */
+static bool is_valid_reg_rule(const struct ieee80211_reg_rule *rule)
+{
+	const struct ieee80211_freq_range *freq_range = &rule->freq_range;
+	u32 freq_diff;
+
+	if (freq_range->start_freq_khz == 0 || freq_range->end_freq_khz == 0)
+		return false;
+
+	if (freq_range->start_freq_khz > freq_range->end_freq_khz)
+		return false;
+
+	freq_diff = freq_range->end_freq_khz - freq_range->start_freq_khz;
+
+	if (freq_range->max_bandwidth_khz > freq_diff)
+		return false;
+
+	return true;
+}
+
+static bool is_valid_rd(const struct ieee80211_regdomain *rd)
+{
+	const struct ieee80211_reg_rule *reg_rule = NULL;
+	unsigned int i;
+
+	if (!rd->n_reg_rules)
+		return false;
+
+	for (i = 0; i < rd->n_reg_rules; i++) {
+		reg_rule = &rd->reg_rules[i];
+		if (!is_valid_reg_rule(reg_rule))
+			return false;
+	}
+
+	return true;
+}
+
+/* Returns value in KHz */
+static u32 freq_max_bandwidth(const struct ieee80211_freq_range *freq_range,
+	u32 freq)
+{
+	unsigned int i;
+	for (i = 0; i < ARRAY_SIZE(supported_bandwidths); i++) {
+		u32 start_freq_khz = freq - supported_bandwidths[i]/2;
+		u32 end_freq_khz = freq + supported_bandwidths[i]/2;
+		if (start_freq_khz >= freq_range->start_freq_khz &&
+			end_freq_khz <= freq_range->end_freq_khz)
+			return supported_bandwidths[i];
+	}
+	return 0;
+}
+
+/* XXX: add support for the rest of enum nl80211_reg_rule_flags, we may
+ * want to just have the channel structure use these */
+static u32 map_regdom_flags(u32 rd_flags)
+{
+	u32 channel_flags = 0;
+	if (rd_flags & NL80211_RRF_PASSIVE_SCAN)
+		channel_flags |= IEEE80211_CHAN_PASSIVE_SCAN;
+	if (rd_flags & NL80211_RRF_NO_IBSS)
+		channel_flags |= IEEE80211_CHAN_NO_IBSS;
+	if (rd_flags & NL80211_RRF_DFS)
+		channel_flags |= IEEE80211_CHAN_RADAR;
+	return channel_flags;
+}
+
+/**
+ * freq_reg_info - get regulatory information for the given frequency
+ * @center_freq: Frequency in KHz for which we want regulatory information for
+ * @bandwidth: the bandwidth requirement you have in KHz, if you do not have one
+ * 	you can set this to 0. If this frequency is allowed we then set
+ * 	this value to the maximum allowed bandwidth.
+ * @reg_rule: the regulatory rule which we have for this frequency
+ *
+ * Use this function to get the regulatory rule for a specific frequency.
+ */
+static int freq_reg_info(u32 center_freq, u32 *bandwidth,
+			 const struct ieee80211_reg_rule **reg_rule)
 {
 	int i;
-	u32 flags = chan->orig_flags;
-	const struct ieee80211_channel_range *rg = NULL;
+	u32 max_bandwidth = 0;
 
-	for (i = 0; i < rd->n_ranges; i++) {
-		if (rd->ranges[i].start_freq <= chan->center_freq &&
-		    chan->center_freq <= rd->ranges[i].end_freq) {
-			rg = &rd->ranges[i];
+	if (!cfg80211_regdomain)
+		return -EINVAL;
+
+	for (i = 0; i < cfg80211_regdomain->n_reg_rules; i++) {
+		const struct ieee80211_reg_rule *rr;
+		const struct ieee80211_freq_range *fr = NULL;
+		const struct ieee80211_power_rule *pr = NULL;
+
+		rr = &cfg80211_regdomain->reg_rules[i];
+		fr = &rr->freq_range;
+		pr = &rr->power_rule;
+		max_bandwidth = freq_max_bandwidth(fr, center_freq);
+		if (max_bandwidth && *bandwidth <= max_bandwidth) {
+			*reg_rule = rr;
+			*bandwidth = max_bandwidth;
 			break;
 		}
 	}
 
-	if (!rg) {
-		/* not found */
+	return !max_bandwidth;
+}
+
+static void handle_channel(struct ieee80211_channel *chan)
+{
+	int r;
+	u32 flags = chan->orig_flags;
+	u32 max_bandwidth = 0;
+	const struct ieee80211_reg_rule *reg_rule = NULL;
+	const struct ieee80211_power_rule *power_rule = NULL;
+
+	r = freq_reg_info(MHZ_TO_KHZ(chan->center_freq),
+		&max_bandwidth, &reg_rule);
+
+	if (r) {
 		flags |= IEEE80211_CHAN_DISABLED;
 		chan->flags = flags;
 		return;
 	}
 
-	chan->flags = flags;
+	power_rule = &reg_rule->power_rule;
+
+	chan->flags = flags | map_regdom_flags(reg_rule->flags);
 	chan->max_antenna_gain = min(chan->orig_mag,
-					 rg->max_antenna_gain);
+		(int) MBI_TO_DBI(power_rule->max_antenna_gain));
+	chan->max_bandwidth = KHZ_TO_MHZ(max_bandwidth);
 	if (chan->orig_mpwr)
-		chan->max_power = min(chan->orig_mpwr, rg->max_power);
+		chan->max_power = min(chan->orig_mpwr,
+			(int) MBM_TO_DBM(power_rule->max_eirp));
 	else
-		chan->max_power = rg->max_power;
+		chan->max_power = (int) MBM_TO_DBM(power_rule->max_eirp);
 }
 
-static void handle_band(struct ieee80211_supported_band *sband,
-			const struct ieee80211_regdomain *rd)
+static void handle_band(struct ieee80211_supported_band *sband)
 {
 	int i;
 
 	for (i = 0; i < sband->n_channels; i++)
-		handle_channel(&sband->channels[i], rd);
+		handle_channel(&sband->channels[i]);
 }
 
-void wiphy_update_regulatory(struct wiphy *wiphy)
+static void update_all_wiphy_regulatory(enum reg_set_by setby)
+{
+	struct cfg80211_registered_device *drv;
+
+	list_for_each_entry(drv, &cfg80211_drv_list, list)
+		wiphy_update_regulatory(&drv->wiphy, setby);
+}
+
+void wiphy_update_regulatory(struct wiphy *wiphy, enum reg_set_by setby)
 {
 	enum ieee80211_band band;
-	const struct ieee80211_regdomain *rd = get_regdom();
-
-	for (band = 0; band < IEEE80211_NUM_BANDS; band++)
+	for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
 		if (wiphy->bands[band])
-			handle_band(wiphy->bands[band], rd);
+			handle_band(wiphy->bands[band]);
+		if (wiphy->reg_notifier)
+			wiphy->reg_notifier(wiphy, setby);
+	}
+}
+
+/* Caller must hold &cfg80211_drv_mutex */
+int __regulatory_hint(struct wiphy *wiphy, enum reg_set_by set_by,
+		      const char *alpha2, struct ieee80211_regdomain *rd)
+{
+	struct regulatory_request *request;
+	char *rd_alpha2;
+	int r = 0;
+
+	r = ignore_request(wiphy, set_by, (char *) alpha2, rd);
+	if (r)
+		return r;
+
+	if (rd)
+		rd_alpha2 = rd->alpha2;
+	else
+		rd_alpha2 = (char *) alpha2;
+
+	switch (set_by) {
+	case REGDOM_SET_BY_CORE:
+	case REGDOM_SET_BY_COUNTRY_IE:
+	case REGDOM_SET_BY_DRIVER:
+	case REGDOM_SET_BY_USER:
+		request = kzalloc(sizeof(struct regulatory_request),
+			GFP_KERNEL);
+		if (!request)
+			return -ENOMEM;
+
+		request->alpha2[0] = rd_alpha2[0];
+		request->alpha2[1] = rd_alpha2[1];
+		request->initiator = set_by;
+		request->wiphy = wiphy;
+
+		list_add_tail(&request->list, &regulatory_requests);
+		if (rd)
+			break;
+		r = call_crda(alpha2);
+#ifndef CONFIG_WIRELESS_OLD_REGULATORY
+		if (r)
+			printk(KERN_ERR "cfg80211: Failed calling CRDA\n");
+#endif
+		break;
+	default:
+		r = -ENOTSUPP;
+		break;
+	}
+
+	return r;
+}
+
+/* If rd is not NULL and if this call fails the caller must free it */
+int regulatory_hint(struct wiphy *wiphy, const char *alpha2,
+	struct ieee80211_regdomain *rd)
+{
+	int r;
+	BUG_ON(!rd && !alpha2);
+
+	mutex_lock(&cfg80211_drv_mutex);
+
+	r = __regulatory_hint(wiphy, REGDOM_SET_BY_DRIVER, alpha2, rd);
+	if (r || !rd)
+		goto unlock_and_exit;
+
+	/* If the driver passed a regulatory domain we skipped asking
+	 * userspace for one so we can now go ahead and set it */
+	r = set_regdom(rd);
+
+unlock_and_exit:
+	mutex_unlock(&cfg80211_drv_mutex);
+	return r;
+}
+EXPORT_SYMBOL(regulatory_hint);
+
+
+static void print_rd_rules(const struct ieee80211_regdomain *rd)
+{
+	unsigned int i;
+	const struct ieee80211_reg_rule *reg_rule = NULL;
+	const struct ieee80211_freq_range *freq_range = NULL;
+	const struct ieee80211_power_rule *power_rule = NULL;
+
+	printk(KERN_INFO "\t(start_freq - end_freq @ bandwidth), "
+		"(max_antenna_gain, max_eirp)\n");
+
+	for (i = 0; i < rd->n_reg_rules; i++) {
+		reg_rule = &rd->reg_rules[i];
+		freq_range = &reg_rule->freq_range;
+		power_rule = &reg_rule->power_rule;
+
+		/* There may not be documentation for max antenna gain
+		 * in certain regions */
+		if (power_rule->max_antenna_gain)
+			printk(KERN_INFO "\t(%d KHz - %d KHz @ %d KHz), "
+				"(%d mBi, %d mBm)\n",
+				freq_range->start_freq_khz,
+				freq_range->end_freq_khz,
+				freq_range->max_bandwidth_khz,
+				power_rule->max_antenna_gain,
+				power_rule->max_eirp);
+		else
+			printk(KERN_INFO "\t(%d KHz - %d KHz @ %d KHz), "
+				"(N/A, %d mBm)\n",
+				freq_range->start_freq_khz,
+				freq_range->end_freq_khz,
+				freq_range->max_bandwidth_khz,
+				power_rule->max_eirp);
+	}
+}
+
+static void print_regdomain(const struct ieee80211_regdomain *rd)
+{
+
+	if (is_world_regdom(rd->alpha2))
+		printk(KERN_INFO "cfg80211: World regulatory "
+			"domain updated:\n");
+	else {
+		if (is_unknown_alpha2(rd->alpha2))
+			printk(KERN_INFO "cfg80211: Regulatory domain "
+				"changed to driver built-in settings "
+				"(unknown country)\n");
+		else
+			printk(KERN_INFO "cfg80211: Regulatory domain "
+				"changed to country: %c%c\n",
+				rd->alpha2[0], rd->alpha2[1]);
+	}
+	print_rd_rules(rd);
+}
+
+void print_regdomain_info(const struct ieee80211_regdomain *rd)
+{
+	printk(KERN_INFO "cfg80211: Regulatory domain: %c%c\n",
+		rd->alpha2[0], rd->alpha2[1]);
+	print_rd_rules(rd);
+}
+
+static int __set_regdom(const struct ieee80211_regdomain *rd)
+{
+	struct regulatory_request *request = NULL;
+
+	/* Some basic sanity checks first */
+
+	if (is_world_regdom(rd->alpha2)) {
+		if (WARN_ON(!__reg_is_valid_request(rd->alpha2, &request)))
+			return -EINVAL;
+		update_world_regdomain(rd);
+		return 0;
+	}
+
+	if (!is_alpha2_set(rd->alpha2) && !is_an_alpha2(rd->alpha2) &&
+			!is_unknown_alpha2(rd->alpha2))
+		return -EINVAL;
+
+	if (list_empty(&regulatory_requests))
+		return -EINVAL;
+
+	/* allow overriding the static definitions if CRDA is present */
+	if (!is_old_static_regdom(cfg80211_regdomain) &&
+	    !regdom_changed(rd->alpha2))
+		return -EINVAL;
+
+	/* Now lets set the regulatory domain, update all driver channels
+	 * and finally inform them of what we have done, in case they want
+	 * to review or adjust their own settings based on their own
+	 * internal EEPROM data */
+
+	if (WARN_ON(!__reg_is_valid_request(rd->alpha2, &request)))
+		return -EINVAL;
+
+	reset_regdomains();
+
+	/* Country IE parsing coming soon */
+	switch (request->initiator) {
+	case REGDOM_SET_BY_CORE:
+	case REGDOM_SET_BY_DRIVER:
+	case REGDOM_SET_BY_USER:
+		if (!is_valid_rd(rd)) {
+			printk(KERN_ERR "cfg80211: Invalid "
+				"regulatory domain detected:\n");
+			print_regdomain_info(rd);
+			return -EINVAL;
+		}
+		break;
+	case REGDOM_SET_BY_COUNTRY_IE: /* Not yet */
+		WARN_ON(1);
+	default:
+		return -EOPNOTSUPP;
+	}
+
+	/* Tada! */
+	cfg80211_regdomain = rd;
+	request->granted = 1;
+
+	return 0;
+}
+
+
+/* Use this call to set the current regulatory domain. Conflicts with
+ * multiple drivers can be ironed out later. Caller must've already
+ * kmalloc'd the rd structure. If this calls fails you should kfree()
+ * the passed rd. Caller must hold cfg80211_drv_mutex */
+int set_regdom(const struct ieee80211_regdomain *rd)
+{
+	struct regulatory_request *this_request = NULL, *prev_request = NULL;
+	int r;
+
+	if (!list_empty(&regulatory_requests))
+		prev_request = list_first_entry(&regulatory_requests,
+			struct regulatory_request, list);
+
+	/* Note that this doesn't update the wiphys, this is done below */
+	r = __set_regdom(rd);
+	if (r)
+		return r;
+
+	BUG_ON((!__reg_is_valid_request(rd->alpha2, &this_request)));
+
+	/* The initial standard core update of the world regulatory domain, no
+	 * need to keep that request info around if it didn't fail. */
+	if (is_world_regdom(rd->alpha2) &&
+			this_request->initiator == REGDOM_SET_BY_CORE &&
+			this_request->granted) {
+		list_del(&this_request->list);
+		kfree(this_request);
+		this_request = NULL;
+	}
+
+	/* Remove old requests, we only leave behind the last one */
+	if (prev_request) {
+		list_del(&prev_request->list);
+		kfree(prev_request);
+		prev_request = NULL;
+	}
+
+	/* This would make this whole thing pointless */
+	BUG_ON(rd != cfg80211_regdomain);
+
+	/* update all wiphys now with the new established regulatory domain */
+	update_all_wiphy_regulatory(this_request->initiator);
+
+	print_regdomain(rd);
+
+	return r;
+}
+
+int regulatory_init(void)
+{
+	int err;
+
+	reg_pdev = platform_device_register_simple("regulatory", 0, NULL, 0);
+	if (IS_ERR(reg_pdev))
+		return PTR_ERR(reg_pdev);
+
+#ifdef CONFIG_WIRELESS_OLD_REGULATORY
+	cfg80211_regdomain = static_regdom(ieee80211_regdom);
+
+	printk(KERN_INFO "cfg80211: Using static regulatory domain info\n");
+	print_regdomain_info(cfg80211_regdomain);
+	/* The old code still requests for a new regdomain and if
+	 * you have CRDA you get it updated, otherwise you get
+	 * stuck with the static values. We ignore "EU" code as
+	 * that is not a valid ISO / IEC 3166 alpha2 */
+	if (ieee80211_regdom[0] != 'E' && ieee80211_regdom[1] != 'U')
+		err = __regulatory_hint(NULL, REGDOM_SET_BY_CORE,
+					ieee80211_regdom, NULL);
+#else
+	cfg80211_regdomain = cfg80211_world_regdom;
+
+	err = __regulatory_hint(NULL, REGDOM_SET_BY_CORE, "00", NULL);
+	if (err)
+		printk(KERN_ERR "cfg80211: calling CRDA failed - "
+		       "unable to update world regulatory domain, "
+		       "using static definition\n");
+#endif
+
+	return 0;
+}
+
+void regulatory_exit(void)
+{
+	struct regulatory_request *req, *req_tmp;
+
+	mutex_lock(&cfg80211_drv_mutex);
+
+	reset_regdomains();
+
+	list_for_each_entry_safe(req, req_tmp, &regulatory_requests, list) {
+		list_del(&req->list);
+		kfree(req);
+	}
+	platform_device_unregister(reg_pdev);
+
+	mutex_unlock(&cfg80211_drv_mutex);
 }
diff --git a/net/wireless/reg.h b/net/wireless/reg.h
new file mode 100644
index 0000000..a333628
--- /dev/null
+++ b/net/wireless/reg.h
@@ -0,0 +1,13 @@
+#ifndef __NET_WIRELESS_REG_H
+#define __NET_WIRELESS_REG_H
+
+extern struct mutex cfg80211_reg_mutex;
+bool is_world_regdom(const char *alpha2);
+bool reg_is_valid_request(const char *alpha2);
+
+int regulatory_init(void);
+void regulatory_exit(void);
+
+int set_regdom(const struct ieee80211_regdomain *rd);
+
+#endif  /* __NET_WIRELESS_REG_H */
diff --git a/net/xfrm/xfrm_output.c b/net/xfrm/xfrm_output.c
index ac25b4c..dc50f1e 100644
--- a/net/xfrm/xfrm_output.c
+++ b/net/xfrm/xfrm_output.c
@@ -27,10 +27,14 @@
 		- skb_headroom(skb);
 	int ntail = dst->dev->needed_tailroom - skb_tailroom(skb);
 
-	if (nhead > 0 || ntail > 0)
-		return pskb_expand_head(skb, nhead, ntail, GFP_ATOMIC);
+	if (nhead <= 0) {
+		if (ntail <= 0)
+			return 0;
+		nhead = 0;
+	} else if (ntail < 0)
+		ntail = 0;
 
-	return 0;
+	return pskb_expand_head(skb, nhead, ntail, GFP_ATOMIC);
 }
 
 static int xfrm_output_one(struct sk_buff *skb, int err)
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
index b7754b1..832b47c 100644
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -34,7 +34,7 @@
 
 #include "xfrm_hash.h"
 
-int sysctl_xfrm_larval_drop __read_mostly;
+int sysctl_xfrm_larval_drop __read_mostly = 1;
 
 #ifdef CONFIG_XFRM_STATISTICS
 DEFINE_SNMP_STAT(struct linux_xfrm_mib, xfrm_statistics) __read_mostly;
@@ -46,7 +46,7 @@
 
 static DEFINE_RWLOCK(xfrm_policy_lock);
 
-static struct list_head xfrm_policy_bytype[XFRM_POLICY_TYPE_MAX];
+static struct list_head xfrm_policy_all;
 unsigned int xfrm_policy_count[XFRM_POLICY_MAX*2];
 EXPORT_SYMBOL(xfrm_policy_count);
 
@@ -164,7 +164,7 @@
 
 	read_lock(&xp->lock);
 
-	if (xp->dead)
+	if (xp->walk.dead)
 		goto out;
 
 	dir = xfrm_policy_id2dir(xp->index);
@@ -236,7 +236,7 @@
 	policy = kzalloc(sizeof(struct xfrm_policy), gfp);
 
 	if (policy) {
-		INIT_LIST_HEAD(&policy->bytype);
+		INIT_LIST_HEAD(&policy->walk.all);
 		INIT_HLIST_NODE(&policy->bydst);
 		INIT_HLIST_NODE(&policy->byidx);
 		rwlock_init(&policy->lock);
@@ -252,17 +252,13 @@
 
 void xfrm_policy_destroy(struct xfrm_policy *policy)
 {
-	BUG_ON(!policy->dead);
+	BUG_ON(!policy->walk.dead);
 
 	BUG_ON(policy->bundles);
 
 	if (del_timer(&policy->timer))
 		BUG();
 
-	write_lock_bh(&xfrm_policy_lock);
-	list_del(&policy->bytype);
-	write_unlock_bh(&xfrm_policy_lock);
-
 	security_xfrm_policy_free(policy->security);
 	kfree(policy);
 }
@@ -310,8 +306,8 @@
 	int dead;
 
 	write_lock_bh(&policy->lock);
-	dead = policy->dead;
-	policy->dead = 1;
+	dead = policy->walk.dead;
+	policy->walk.dead = 1;
 	write_unlock_bh(&policy->lock);
 
 	if (unlikely(dead)) {
@@ -609,6 +605,7 @@
 	if (delpol) {
 		hlist_del(&delpol->bydst);
 		hlist_del(&delpol->byidx);
+		list_del(&delpol->walk.all);
 		xfrm_policy_count[dir]--;
 	}
 	policy->index = delpol ? delpol->index : xfrm_gen_index(policy->type, dir);
@@ -617,7 +614,7 @@
 	policy->curlft.use_time = 0;
 	if (!mod_timer(&policy->timer, jiffies + HZ))
 		xfrm_pol_hold(policy);
-	list_add_tail(&policy->bytype, &xfrm_policy_bytype[policy->type]);
+	list_add(&policy->walk.all, &xfrm_policy_all);
 	write_unlock_bh(&xfrm_policy_lock);
 
 	if (delpol)
@@ -684,6 +681,7 @@
 				}
 				hlist_del(&pol->bydst);
 				hlist_del(&pol->byidx);
+				list_del(&pol->walk.all);
 				xfrm_policy_count[dir]--;
 			}
 			ret = pol;
@@ -727,6 +725,7 @@
 				}
 				hlist_del(&pol->bydst);
 				hlist_del(&pol->byidx);
+				list_del(&pol->walk.all);
 				xfrm_policy_count[dir]--;
 			}
 			ret = pol;
@@ -840,6 +839,7 @@
 					continue;
 				hlist_del(&pol->bydst);
 				hlist_del(&pol->byidx);
+				list_del(&pol->walk.all);
 				write_unlock_bh(&xfrm_policy_lock);
 
 				xfrm_audit_policy_delete(pol, 1,
@@ -867,60 +867,68 @@
 		     int (*func)(struct xfrm_policy *, int, int, void*),
 		     void *data)
 {
-	struct xfrm_policy *old, *pol, *last = NULL;
+	struct xfrm_policy *pol;
+	struct xfrm_policy_walk_entry *x;
 	int error = 0;
 
 	if (walk->type >= XFRM_POLICY_TYPE_MAX &&
 	    walk->type != XFRM_POLICY_TYPE_ANY)
 		return -EINVAL;
 
-	if (walk->policy == NULL && walk->count != 0)
+	if (list_empty(&walk->walk.all) && walk->seq != 0)
 		return 0;
 
-	old = pol = walk->policy;
-	walk->policy = NULL;
-	read_lock_bh(&xfrm_policy_lock);
-
-	for (; walk->cur_type < XFRM_POLICY_TYPE_MAX; walk->cur_type++) {
-		if (walk->type != walk->cur_type &&
-		    walk->type != XFRM_POLICY_TYPE_ANY)
+	write_lock_bh(&xfrm_policy_lock);
+	if (list_empty(&walk->walk.all))
+		x = list_first_entry(&xfrm_policy_all, struct xfrm_policy_walk_entry, all);
+	else
+		x = list_entry(&walk->walk.all, struct xfrm_policy_walk_entry, all);
+	list_for_each_entry_from(x, &xfrm_policy_all, all) {
+		if (x->dead)
 			continue;
-
-		if (pol == NULL) {
-			pol = list_first_entry(&xfrm_policy_bytype[walk->cur_type],
-					       struct xfrm_policy, bytype);
+		pol = container_of(x, struct xfrm_policy, walk);
+		if (walk->type != XFRM_POLICY_TYPE_ANY &&
+		    walk->type != pol->type)
+			continue;
+		error = func(pol, xfrm_policy_id2dir(pol->index),
+			     walk->seq, data);
+		if (error) {
+			list_move_tail(&walk->walk.all, &x->all);
+			goto out;
 		}
-		list_for_each_entry_from(pol, &xfrm_policy_bytype[walk->cur_type], bytype) {
-			if (pol->dead)
-				continue;
-			if (last) {
-				error = func(last, xfrm_policy_id2dir(last->index),
-					     walk->count, data);
-				if (error) {
-					xfrm_pol_hold(last);
-					walk->policy = last;
-					goto out;
-				}
-			}
-			last = pol;
-			walk->count++;
-		}
-		pol = NULL;
+		walk->seq++;
 	}
-	if (walk->count == 0) {
+	if (walk->seq == 0) {
 		error = -ENOENT;
 		goto out;
 	}
-	if (last)
-		error = func(last, xfrm_policy_id2dir(last->index), 0, data);
+	list_del_init(&walk->walk.all);
 out:
-	read_unlock_bh(&xfrm_policy_lock);
-	if (old != NULL)
-		xfrm_pol_put(old);
+	write_unlock_bh(&xfrm_policy_lock);
 	return error;
 }
 EXPORT_SYMBOL(xfrm_policy_walk);
 
+void xfrm_policy_walk_init(struct xfrm_policy_walk *walk, u8 type)
+{
+	INIT_LIST_HEAD(&walk->walk.all);
+	walk->walk.dead = 1;
+	walk->type = type;
+	walk->seq = 0;
+}
+EXPORT_SYMBOL(xfrm_policy_walk_init);
+
+void xfrm_policy_walk_done(struct xfrm_policy_walk *walk)
+{
+	if (list_empty(&walk->walk.all))
+		return;
+
+	write_lock_bh(&xfrm_policy_lock);
+	list_del(&walk->walk.all);
+	write_unlock_bh(&xfrm_policy_lock);
+}
+EXPORT_SYMBOL(xfrm_policy_walk_done);
+
 /*
  * Find policy to apply to this flow.
  *
@@ -1077,7 +1085,7 @@
 	struct hlist_head *chain = policy_hash_bysel(&pol->selector,
 						     pol->family, dir);
 
-	list_add_tail(&pol->bytype, &xfrm_policy_bytype[pol->type]);
+	list_add(&pol->walk.all, &xfrm_policy_all);
 	hlist_add_head(&pol->bydst, chain);
 	hlist_add_head(&pol->byidx, xfrm_policy_byidx+idx_hash(pol->index));
 	xfrm_policy_count[dir]++;
@@ -1095,6 +1103,7 @@
 
 	hlist_del(&pol->bydst);
 	hlist_del(&pol->byidx);
+	list_del(&pol->walk.all);
 	xfrm_policy_count[dir]--;
 
 	return pol;
@@ -1720,7 +1729,7 @@
 
 		for (pi = 0; pi < npols; pi++) {
 			read_lock_bh(&pols[pi]->lock);
-			pol_dead |= pols[pi]->dead;
+			pol_dead |= pols[pi]->walk.dead;
 			read_unlock_bh(&pols[pi]->lock);
 		}
 
@@ -2415,9 +2424,7 @@
 			panic("XFRM: failed to allocate bydst hash\n");
 	}
 
-	for (dir = 0; dir < XFRM_POLICY_TYPE_MAX; dir++)
-		INIT_LIST_HEAD(&xfrm_policy_bytype[dir]);
-
+	INIT_LIST_HEAD(&xfrm_policy_all);
 	INIT_WORK(&xfrm_policy_gc_work, xfrm_policy_gc_task);
 	register_netdevice_notifier(&xfrm_dev_notifier);
 }
@@ -2601,7 +2608,7 @@
 	int i, j, n = 0;
 
 	write_lock_bh(&pol->lock);
-	if (unlikely(pol->dead)) {
+	if (unlikely(pol->walk.dead)) {
 		/* target policy has been deleted */
 		write_unlock_bh(&pol->lock);
 		return -ENOENT;
@@ -2672,7 +2679,8 @@
 }
 
 int xfrm_migrate(struct xfrm_selector *sel, u8 dir, u8 type,
-		 struct xfrm_migrate *m, int num_migrate)
+		 struct xfrm_migrate *m, int num_migrate,
+		 struct xfrm_kmaddress *k)
 {
 	int i, err, nx_cur = 0, nx_new = 0;
 	struct xfrm_policy *pol = NULL;
@@ -2716,7 +2724,7 @@
 	}
 
 	/* Stage 5 - announce */
-	km_migrate(sel, dir, type, m, num_migrate);
+	km_migrate(sel, dir, type, m, num_migrate, k);
 
 	xfrm_pol_put(pol);
 
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c
index 0a8f09c..508337f 100644
--- a/net/xfrm/xfrm_state.c
+++ b/net/xfrm/xfrm_state.c
@@ -408,11 +408,10 @@
 	struct hlist_head gc_list;
 
 	spin_lock_bh(&xfrm_state_gc_lock);
-	gc_list.first = xfrm_state_gc_list.first;
-	INIT_HLIST_HEAD(&xfrm_state_gc_list);
+	hlist_move_list(&xfrm_state_gc_list, &gc_list);
 	spin_unlock_bh(&xfrm_state_gc_lock);
 
-	hlist_for_each_entry_safe(x, entry, tmp, &gc_list, bydst)
+	hlist_for_each_entry_safe(x, entry, tmp, &gc_list, gclist)
 		xfrm_state_gc_destroy(x);
 
 	wake_up(&km_waitq);
@@ -514,7 +513,7 @@
 	if (x) {
 		atomic_set(&x->refcnt, 1);
 		atomic_set(&x->tunnel_users, 0);
-		INIT_LIST_HEAD(&x->all);
+		INIT_LIST_HEAD(&x->km.all);
 		INIT_HLIST_NODE(&x->bydst);
 		INIT_HLIST_NODE(&x->bysrc);
 		INIT_HLIST_NODE(&x->byspi);
@@ -540,12 +539,8 @@
 {
 	WARN_ON(x->km.state != XFRM_STATE_DEAD);
 
-	spin_lock_bh(&xfrm_state_lock);
-	list_del(&x->all);
-	spin_unlock_bh(&xfrm_state_lock);
-
 	spin_lock_bh(&xfrm_state_gc_lock);
-	hlist_add_head(&x->bydst, &xfrm_state_gc_list);
+	hlist_add_head(&x->gclist, &xfrm_state_gc_list);
 	spin_unlock_bh(&xfrm_state_gc_lock);
 	schedule_work(&xfrm_state_gc_work);
 }
@@ -558,6 +553,7 @@
 	if (x->km.state != XFRM_STATE_DEAD) {
 		x->km.state = XFRM_STATE_DEAD;
 		spin_lock(&xfrm_state_lock);
+		list_del(&x->km.all);
 		hlist_del(&x->bydst);
 		hlist_del(&x->bysrc);
 		if (x->id.spi)
@@ -858,7 +854,7 @@
 
 		if (km_query(x, tmpl, pol) == 0) {
 			x->km.state = XFRM_STATE_ACQ;
-			list_add_tail(&x->all, &xfrm_state_all);
+			list_add(&x->km.all, &xfrm_state_all);
 			hlist_add_head(&x->bydst, xfrm_state_bydst+h);
 			h = xfrm_src_hash(daddr, saddr, family);
 			hlist_add_head(&x->bysrc, xfrm_state_bysrc+h);
@@ -927,7 +923,7 @@
 
 	x->genid = ++xfrm_state_genid;
 
-	list_add_tail(&x->all, &xfrm_state_all);
+	list_add(&x->km.all, &xfrm_state_all);
 
 	h = xfrm_dst_hash(&x->id.daddr, &x->props.saddr,
 			  x->props.reqid, x->props.family);
@@ -1056,7 +1052,7 @@
 		xfrm_state_hold(x);
 		x->timer.expires = jiffies + sysctl_xfrm_acq_expires*HZ;
 		add_timer(&x->timer);
-		list_add_tail(&x->all, &xfrm_state_all);
+		list_add(&x->km.all, &xfrm_state_all);
 		hlist_add_head(&x->bydst, xfrm_state_bydst+h);
 		h = xfrm_src_hash(daddr, saddr, family);
 		hlist_add_head(&x->bysrc, xfrm_state_bysrc+h);
@@ -1553,47 +1549,62 @@
 		    int (*func)(struct xfrm_state *, int, void*),
 		    void *data)
 {
-	struct xfrm_state *old, *x, *last = NULL;
+	struct xfrm_state *state;
+	struct xfrm_state_walk *x;
 	int err = 0;
 
-	if (walk->state == NULL && walk->count != 0)
+	if (walk->seq != 0 && list_empty(&walk->all))
 		return 0;
 
-	old = x = walk->state;
-	walk->state = NULL;
 	spin_lock_bh(&xfrm_state_lock);
-	if (x == NULL)
-		x = list_first_entry(&xfrm_state_all, struct xfrm_state, all);
+	if (list_empty(&walk->all))
+		x = list_first_entry(&xfrm_state_all, struct xfrm_state_walk, all);
+	else
+		x = list_entry(&walk->all, struct xfrm_state_walk, all);
 	list_for_each_entry_from(x, &xfrm_state_all, all) {
-		if (x->km.state == XFRM_STATE_DEAD)
+		if (x->state == XFRM_STATE_DEAD)
 			continue;
-		if (!xfrm_id_proto_match(x->id.proto, walk->proto))
+		state = container_of(x, struct xfrm_state, km);
+		if (!xfrm_id_proto_match(state->id.proto, walk->proto))
 			continue;
-		if (last) {
-			err = func(last, walk->count, data);
-			if (err) {
-				xfrm_state_hold(last);
-				walk->state = last;
-				goto out;
-			}
+		err = func(state, walk->seq, data);
+		if (err) {
+			list_move_tail(&walk->all, &x->all);
+			goto out;
 		}
-		last = x;
-		walk->count++;
+		walk->seq++;
 	}
-	if (walk->count == 0) {
+	if (walk->seq == 0) {
 		err = -ENOENT;
 		goto out;
 	}
-	if (last)
-		err = func(last, 0, data);
+	list_del_init(&walk->all);
 out:
 	spin_unlock_bh(&xfrm_state_lock);
-	if (old != NULL)
-		xfrm_state_put(old);
 	return err;
 }
 EXPORT_SYMBOL(xfrm_state_walk);
 
+void xfrm_state_walk_init(struct xfrm_state_walk *walk, u8 proto)
+{
+	INIT_LIST_HEAD(&walk->all);
+	walk->proto = proto;
+	walk->state = XFRM_STATE_DEAD;
+	walk->seq = 0;
+}
+EXPORT_SYMBOL(xfrm_state_walk_init);
+
+void xfrm_state_walk_done(struct xfrm_state_walk *walk)
+{
+	if (list_empty(&walk->all))
+		return;
+
+	spin_lock_bh(&xfrm_state_lock);
+	list_del(&walk->all);
+	spin_lock_bh(&xfrm_state_lock);
+}
+EXPORT_SYMBOL(xfrm_state_walk_done);
+
 
 void xfrm_replay_notify(struct xfrm_state *x, int event)
 {
@@ -1803,7 +1814,8 @@
 
 #ifdef CONFIG_XFRM_MIGRATE
 int km_migrate(struct xfrm_selector *sel, u8 dir, u8 type,
-	       struct xfrm_migrate *m, int num_migrate)
+	       struct xfrm_migrate *m, int num_migrate,
+	       struct xfrm_kmaddress *k)
 {
 	int err = -EINVAL;
 	int ret;
@@ -1812,7 +1824,7 @@
 	read_lock(&xfrm_km_lock);
 	list_for_each_entry(km, &xfrm_km_list, list) {
 		if (km->migrate) {
-			ret = km->migrate(sel, dir, type, m, num_migrate);
+			ret = km->migrate(sel, dir, type, m, num_migrate, k);
 			if (!ret)
 				err = ret;
 		}
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c
index 04c4150..4a8a1ab 100644
--- a/net/xfrm/xfrm_user.c
+++ b/net/xfrm/xfrm_user.c
@@ -1102,7 +1102,7 @@
 	return xp;
  error:
 	*errp = err;
-	xp->dead = 1;
+	xp->walk.dead = 1;
 	xfrm_policy_destroy(xp);
 	return NULL;
 }
@@ -1595,7 +1595,7 @@
 		return -ENOENT;
 
 	read_lock(&xp->lock);
-	if (xp->dead) {
+	if (xp->walk.dead) {
 		read_unlock(&xp->lock);
 		goto out;
 	}
@@ -1710,12 +1710,23 @@
 
 #ifdef CONFIG_XFRM_MIGRATE
 static int copy_from_user_migrate(struct xfrm_migrate *ma,
+				  struct xfrm_kmaddress *k,
 				  struct nlattr **attrs, int *num)
 {
 	struct nlattr *rt = attrs[XFRMA_MIGRATE];
 	struct xfrm_user_migrate *um;
 	int i, num_migrate;
 
+	if (k != NULL) {
+		struct xfrm_user_kmaddress *uk;
+
+		uk = nla_data(attrs[XFRMA_KMADDRESS]);
+		memcpy(&k->local, &uk->local, sizeof(k->local));
+		memcpy(&k->remote, &uk->remote, sizeof(k->remote));
+		k->family = uk->family;
+		k->reserved = uk->reserved;
+	}
+
 	um = nla_data(rt);
 	num_migrate = nla_len(rt) / sizeof(*um);
 
@@ -1745,6 +1756,7 @@
 {
 	struct xfrm_userpolicy_id *pi = nlmsg_data(nlh);
 	struct xfrm_migrate m[XFRM_MAX_DEPTH];
+	struct xfrm_kmaddress km, *kmp;
 	u8 type;
 	int err;
 	int n = 0;
@@ -1752,19 +1764,20 @@
 	if (attrs[XFRMA_MIGRATE] == NULL)
 		return -EINVAL;
 
+	kmp = attrs[XFRMA_KMADDRESS] ? &km : NULL;
+
 	err = copy_from_user_policy_type(&type, attrs);
 	if (err)
 		return err;
 
-	err = copy_from_user_migrate((struct xfrm_migrate *)m,
-				     attrs, &n);
+	err = copy_from_user_migrate((struct xfrm_migrate *)m, kmp, attrs, &n);
 	if (err)
 		return err;
 
 	if (!n)
 		return 0;
 
-	xfrm_migrate(&pi->sel, pi->dir, type, m, n);
+	xfrm_migrate(&pi->sel, pi->dir, type, m, n, kmp);
 
 	return 0;
 }
@@ -1795,16 +1808,30 @@
 	return nla_put(skb, XFRMA_MIGRATE, sizeof(um), &um);
 }
 
-static inline size_t xfrm_migrate_msgsize(int num_migrate)
+static int copy_to_user_kmaddress(struct xfrm_kmaddress *k, struct sk_buff *skb)
+{
+	struct xfrm_user_kmaddress uk;
+
+	memset(&uk, 0, sizeof(uk));
+	uk.family = k->family;
+	uk.reserved = k->reserved;
+	memcpy(&uk.local, &k->local, sizeof(uk.local));
+	memcpy(&uk.remote, &k->local, sizeof(uk.remote));
+
+	return nla_put(skb, XFRMA_KMADDRESS, sizeof(uk), &uk);
+}
+
+static inline size_t xfrm_migrate_msgsize(int num_migrate, int with_kma)
 {
 	return NLMSG_ALIGN(sizeof(struct xfrm_userpolicy_id))
-	       + nla_total_size(sizeof(struct xfrm_user_migrate) * num_migrate)
-	       + userpolicy_type_attrsize();
+	      + (with_kma ? nla_total_size(sizeof(struct xfrm_kmaddress)) : 0)
+	      + nla_total_size(sizeof(struct xfrm_user_migrate) * num_migrate)
+	      + userpolicy_type_attrsize();
 }
 
 static int build_migrate(struct sk_buff *skb, struct xfrm_migrate *m,
-			 int num_migrate, struct xfrm_selector *sel,
-			 u8 dir, u8 type)
+			 int num_migrate, struct xfrm_kmaddress *k,
+			 struct xfrm_selector *sel, u8 dir, u8 type)
 {
 	struct xfrm_migrate *mp;
 	struct xfrm_userpolicy_id *pol_id;
@@ -1821,6 +1848,9 @@
 	memcpy(&pol_id->sel, sel, sizeof(pol_id->sel));
 	pol_id->dir = dir;
 
+	if (k != NULL && (copy_to_user_kmaddress(k, skb) < 0))
+			goto nlmsg_failure;
+
 	if (copy_to_user_policy_type(type, skb) < 0)
 		goto nlmsg_failure;
 
@@ -1836,23 +1866,25 @@
 }
 
 static int xfrm_send_migrate(struct xfrm_selector *sel, u8 dir, u8 type,
-			     struct xfrm_migrate *m, int num_migrate)
+			     struct xfrm_migrate *m, int num_migrate,
+			     struct xfrm_kmaddress *k)
 {
 	struct sk_buff *skb;
 
-	skb = nlmsg_new(xfrm_migrate_msgsize(num_migrate), GFP_ATOMIC);
+	skb = nlmsg_new(xfrm_migrate_msgsize(num_migrate, !!k), GFP_ATOMIC);
 	if (skb == NULL)
 		return -ENOMEM;
 
 	/* build migrate */
-	if (build_migrate(skb, m, num_migrate, sel, dir, type) < 0)
+	if (build_migrate(skb, m, num_migrate, k, sel, dir, type) < 0)
 		BUG();
 
 	return nlmsg_multicast(xfrm_nl, skb, 0, XFRMNLGRP_MIGRATE, GFP_ATOMIC);
 }
 #else
 static int xfrm_send_migrate(struct xfrm_selector *sel, u8 dir, u8 type,
-			     struct xfrm_migrate *m, int num_migrate)
+			     struct xfrm_migrate *m, int num_migrate,
+			     struct xfrm_kmaddress *k)
 {
 	return -ENOPROTOOPT;
 }
@@ -1901,6 +1933,7 @@
 	[XFRMA_COADDR]		= { .len = sizeof(xfrm_address_t) },
 	[XFRMA_POLICY_TYPE]	= { .len = sizeof(struct xfrm_userpolicy_type)},
 	[XFRMA_MIGRATE]		= { .len = sizeof(struct xfrm_user_migrate) },
+	[XFRMA_KMADDRESS]	= { .len = sizeof(struct xfrm_user_kmaddress) },
 };
 
 static struct xfrm_link {
diff --git a/scripts/Kbuild.include b/scripts/Kbuild.include
index d64e6ba..982dcae 100644
--- a/scripts/Kbuild.include
+++ b/scripts/Kbuild.include
@@ -105,12 +105,12 @@
 # Usage: cflags-y += $(call cc-option,-march=winchip-c6,-march=i586)
 
 cc-option = $(call try-run,\
-	$(CC) $(KBUILD_CFLAGS) $(1) -S -xc /dev/null -o "$$TMP",$(1),$(2))
+	$(CC) $(KBUILD_CFLAGS) $(1) -c -xc /dev/null -o "$$TMP",$(1),$(2))
 
 # cc-option-yn
 # Usage: flag := $(call cc-option-yn,-march=winchip-c6)
 cc-option-yn = $(call try-run,\
-	$(CC) $(KBUILD_CFLAGS) $(1) -S -xc /dev/null -o "$$TMP",y,n)
+	$(CC) $(KBUILD_CFLAGS) $(1) -c -xc /dev/null -o "$$TMP",y,n)
 
 # cc-option-align
 # Prefix align with either -falign or -malign
diff --git a/scripts/Makefile b/scripts/Makefile
index 1c73c5a..aafdf06 100644
--- a/scripts/Makefile
+++ b/scripts/Makefile
@@ -20,6 +20,7 @@
 
 subdir-$(CONFIG_MODVERSIONS) += genksyms
 subdir-y                     += mod
+subdir-$(CONFIG_SECURITY_SELINUX) += selinux
 
 # Let clean descend into subdirs
-subdir-	+= basic kconfig package
+subdir-	+= basic kconfig package selinux
diff --git a/scripts/bootgraph.pl b/scripts/bootgraph.pl
new file mode 100644
index 0000000..2243353
--- /dev/null
+++ b/scripts/bootgraph.pl
@@ -0,0 +1,147 @@
+#!/usr/bin/perl
+
+# Copyright 2008, Intel Corporation
+#
+# This file is part of the Linux kernel
+#
+# This program file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program in a file named COPYING; if not, write to the
+# Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor,
+# Boston, MA 02110-1301 USA
+#
+# Authors:
+# 	Arjan van de Ven <arjan@linux.intel.com>
+
+
+#
+# This script turns a dmesg output into a SVG graphic that shows which
+# functions take how much time. You can view SVG graphics with various
+# programs, including Inkscape, The Gimp and Firefox.
+#
+#
+# For this script to work, the kernel needs to be compiled with the
+# CONFIG_PRINTK_TIME configuration option enabled, and with
+# "initcall_debug" passed on the kernel command line.
+#
+# usage:
+# 	dmesg | perl scripts/bootgraph.pl > output.svg
+#
+
+my @rows;
+my %start, %end, %row;
+my $done = 0;
+my $rowcount = 0;
+my $maxtime = 0;
+my $firsttime = 100;
+my $count = 0;
+while (<>) {
+	my $line = $_;
+	if ($line =~ /([0-9\.]+)\] calling  ([a-zA-Z0-9\_]+)\+/) {
+		my $func = $2;
+		if ($done == 0) {
+			$start{$func} = $1;
+			if ($1 < $firsttime) {
+				$firsttime = $1;
+			}
+		}
+		$row{$func} = 1;
+		if ($line =~ /\@ ([0-9]+)/) {
+			my $pid = $1;
+			if (!defined($rows[$pid])) {
+				$rowcount = $rowcount + 1;
+				$rows[$pid] = $rowcount;
+			}
+			$row{$func} = $rows[$pid];
+		}
+		$count = $count + 1;
+	}
+
+	if ($line =~ /([0-9\.]+)\] initcall ([a-zA-Z0-9\_]+)\+.*returned/) {
+		if ($done == 0) {
+			$end{$2} = $1;
+			$maxtime = $1;
+		}
+	}
+	if ($line =~ /Write protecting the/) {
+		$done = 1;
+	}
+	if ($line =~ /Freeing unused kernel memory/) {
+		$done = 1;
+	}
+}
+
+if ($count == 0) {
+	print "No data found in the dmesg. Make sure that 'printk.time=1' and\n";
+	print "'initcall_debug' are passed on the kernel command line.\n\n";
+	print "Usage: \n";
+	print "      dmesg | perl scripts/bootgraph.pl > output.svg\n\n";
+	exit;
+}
+
+print "<?xml version=\"1.0\" standalone=\"no\"?> \n";
+print "<svg width=\"1000\" height=\"100%\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\">\n";
+
+my @styles;
+
+$styles[0] = "fill:rgb(0,0,255);fill-opacity:0.5;stroke-width:1;stroke:rgb(0,0,0)";
+$styles[1] = "fill:rgb(0,255,0);fill-opacity:0.5;stroke-width:1;stroke:rgb(0,0,0)";
+$styles[2] = "fill:rgb(255,0,20);fill-opacity:0.5;stroke-width:1;stroke:rgb(0,0,0)";
+$styles[3] = "fill:rgb(255,255,20);fill-opacity:0.5;stroke-width:1;stroke:rgb(0,0,0)";
+$styles[4] = "fill:rgb(255,0,255);fill-opacity:0.5;stroke-width:1;stroke:rgb(0,0,0)";
+$styles[5] = "fill:rgb(0,255,255);fill-opacity:0.5;stroke-width:1;stroke:rgb(0,0,0)";
+$styles[6] = "fill:rgb(0,128,255);fill-opacity:0.5;stroke-width:1;stroke:rgb(0,0,0)";
+$styles[7] = "fill:rgb(0,255,128);fill-opacity:0.5;stroke-width:1;stroke:rgb(0,0,0)";
+$styles[8] = "fill:rgb(255,0,128);fill-opacity:0.5;stroke-width:1;stroke:rgb(0,0,0)";
+$styles[9] = "fill:rgb(255,255,128);fill-opacity:0.5;stroke-width:1;stroke:rgb(0,0,0)";
+$styles[10] = "fill:rgb(255,128,255);fill-opacity:0.5;stroke-width:1;stroke:rgb(0,0,0)";
+$styles[11] = "fill:rgb(128,255,255);fill-opacity:0.5;stroke-width:1;stroke:rgb(0,0,0)";
+
+my $mult = 950.0 / ($maxtime - $firsttime);
+my $threshold = ($maxtime - $firsttime) / 60.0;
+my $stylecounter = 0;
+while (($key,$value) = each %start) {
+	my $duration = $end{$key} - $start{$key};
+
+	if ($duration >= $threshold) {
+		my $s, $s2, $e, $y;
+		$s = ($value - $firsttime) * $mult;
+		$s2 = $s + 6;
+		$e = ($end{$key} - $firsttime) * $mult;
+		$w = $e - $s;
+
+		$y = $row{$key} * 150;
+		$y2 = $y + 4;
+
+		$style = $styles[$stylecounter];
+		$stylecounter = $stylecounter + 1;
+		if ($stylecounter > 11) {
+			$stylecounter = 0;
+		};
+
+		print "<rect x=\"$s\" width=\"$w\" y=\"$y\" height=\"145\" style=\"$style\"/>\n";
+		print "<text transform=\"translate($s2,$y2) rotate(90)\">$key</text>\n";
+	}
+}
+
+
+# print the time line on top
+my $time = $firsttime;
+my $step = ($maxtime - $firsttime) / 15;
+while ($time < $maxtime) {
+	my $s2 = ($time - $firsttime) * $mult;
+	my $tm = int($time * 100) / 100.0;
+	print "<text transform=\"translate($s2,89) rotate(90)\">$tm</text>\n";
+	$time = $time + $step;
+}
+
+print "</svg>\n";
diff --git a/scripts/checkstack.pl b/scripts/checkstack.pl
index 3eca625..f7e8e93 100755
--- a/scripts/checkstack.pl
+++ b/scripts/checkstack.pl
@@ -81,7 +81,10 @@
 		$re = qr/.*st[dw]u.*r1,-($x{1,8})\(r1\)/o;
 	} elsif ($arch =~ /^s390x?$/) {
 		#   11160:       a7 fb ff 60             aghi   %r15,-160
-		$re = qr/.*ag?hi.*\%r15,-(([0-9]{2}|[3-9])[0-9]{2})/o;
+		# or
+		#  100092:	 e3 f0 ff c8 ff 71	 lay	 %r15,-56(%r15)
+		$re = qr/.*(?:lay|ag?hi).*\%r15,-(([0-9]{2}|[3-9])[0-9]{2})
+		      (?:\(\%r15\))?$/ox;
 	} elsif ($arch =~ /^sh64$/) {
 		#XXX: we only check for the immediate case presently,
 		#     though we will want to check for the movi/sub
diff --git a/scripts/kconfig/conf.c b/scripts/kconfig/conf.c
index 36b5eed..3e1057f 100644
--- a/scripts/kconfig/conf.c
+++ b/scripts/kconfig/conf.c
@@ -32,6 +32,7 @@
 
 static int indent = 1;
 static int valid_stdin = 1;
+static int sync_kconfig;
 static int conf_cnt;
 static char line[128];
 static struct menu *rootEntry;
@@ -65,7 +66,7 @@
 
 static void check_stdin(void)
 {
-	if (!valid_stdin && input_mode == ask_silent) {
+	if (!valid_stdin) {
 		printf(_("aborted!\n\n"));
 		printf(_("Console input/output is redirected. "));
 		printf(_("Run 'make oldconfig' to update configuration.\n\n"));
@@ -427,43 +428,6 @@
 		check_conf(child);
 }
 
-static void conf_do_update(void)
-{
-	/* Update until a loop caused no more changes */
-	do {
-		conf_cnt = 0;
-		check_conf(&rootmenu);
-	} while (conf_cnt);
-}
-
-static int conf_silent_update(void)
-{
-	const char *name;
-
-	if (conf_get_changed()) {
-		name = getenv("KCONFIG_NOSILENTUPDATE");
-		if (name && *name) {
-			fprintf(stderr,
-			_("\n*** Kernel configuration requires explicit update.\n\n"));
-			return 1;
-		}
-		conf_do_update();
-	}
-	return 0;
-}
-
-static int conf_update(void)
-{
-	rootEntry = &rootmenu;
-	conf(&rootmenu);
-	if (input_mode == ask_all) {
-		input_mode = ask_silent;
-		valid_stdin = 1;
-	}
-	conf_do_update();
-	return 0;
-}
-
 int main(int ac, char **av)
 {
 	int opt;
@@ -477,11 +441,11 @@
 	while ((opt = getopt(ac, av, "osdD:nmyrh")) != -1) {
 		switch (opt) {
 		case 'o':
-			input_mode = ask_new;
+			input_mode = ask_silent;
 			break;
 		case 's':
 			input_mode = ask_silent;
-			valid_stdin = isatty(0) && isatty(1) && isatty(2);
+			sync_kconfig = 1;
 			break;
 		case 'd':
 			input_mode = set_default;
@@ -519,6 +483,19 @@
 	name = av[optind];
 	conf_parse(name);
 	//zconfdump(stdout);
+	if (sync_kconfig) {
+		if (stat(".config", &tmpstat)) {
+			fprintf(stderr, _("***\n"
+				"*** You have not yet configured your kernel!\n"
+				"*** (missing kernel .config file)\n"
+				"***\n"
+				"*** Please run some configurator (e.g. \"make oldconfig\" or\n"
+				"*** \"make menuconfig\" or \"make xconfig\").\n"
+				"***\n"));
+			exit(1);
+		}
+	}
+
 	switch (input_mode) {
 	case set_default:
 		if (!defconfig_file)
@@ -531,16 +508,6 @@
 		}
 		break;
 	case ask_silent:
-		if (stat(".config", &tmpstat)) {
-			printf(_("***\n"
-				"*** You have not yet configured your kernel!\n"
-				"*** (missing kernel .config file)\n"
-				"***\n"
-				"*** Please run some configurator (e.g. \"make oldconfig\" or\n"
-				"*** \"make menuconfig\" or \"make xconfig\").\n"
-				"***\n"));
-			exit(1);
-		}
 	case ask_all:
 	case ask_new:
 		conf_read(NULL);
@@ -569,6 +536,19 @@
 	default:
 		break;
 	}
+
+	if (sync_kconfig) {
+		if (conf_get_changed()) {
+			name = getenv("KCONFIG_NOSILENTUPDATE");
+			if (name && *name) {
+				fprintf(stderr,
+					_("\n*** Kernel configuration requires explicit update.\n\n"));
+				return 1;
+			}
+		}
+		valid_stdin = isatty(0) && isatty(1) && isatty(2);
+	}
+
 	switch (input_mode) {
 	case set_no:
 		conf_set_all_new_symbols(def_no);
@@ -585,27 +565,38 @@
 	case set_default:
 		conf_set_all_new_symbols(def_default);
 		break;
-	case ask_silent:
 	case ask_new:
-		if (conf_silent_update())
-			exit(1);
-		break;
 	case ask_all:
-		if (conf_update())
-			exit(1);
+		rootEntry = &rootmenu;
+		conf(&rootmenu);
+		input_mode = ask_silent;
+		/* fall through */
+	case ask_silent:
+		/* Update until a loop caused no more changes */
+		do {
+			conf_cnt = 0;
+			check_conf(&rootmenu);
+		} while (conf_cnt);
 		break;
 	}
 
-	if (conf_write(NULL)) {
-		fprintf(stderr, _("\n*** Error during writing of the kernel configuration.\n\n"));
-		exit(1);
-	}
-	/* ask_silent is used during the build so we shall update autoconf.
-	 * All other commands are only used to generate a config.
-	 */
-	if (input_mode == ask_silent && conf_write_autoconf()) {
-		fprintf(stderr, _("\n*** Error during writing of the kernel configuration.\n\n"));
-		return 1;
+	if (sync_kconfig) {
+		/* silentoldconfig is used during the build so we shall update autoconf.
+		 * All other commands are only used to generate a config.
+		 */
+		if (conf_get_changed() && conf_write(NULL)) {
+			fprintf(stderr, _("\n*** Error during writing of the kernel configuration.\n\n"));
+			exit(1);
+		}
+		if (conf_write_autoconf()) {
+			fprintf(stderr, _("\n*** Error during update of the kernel configuration.\n\n"));
+			return 1;
+		}
+	} else {
+		if (conf_write(NULL)) {
+			fprintf(stderr, _("\n*** Error during writing of the kernel configuration.\n\n"));
+			exit(1);
+		}
 	}
 	return 0;
 }
diff --git a/scripts/kconfig/confdata.c b/scripts/kconfig/confdata.c
index df6a188..b91cf24 100644
--- a/scripts/kconfig/confdata.c
+++ b/scripts/kconfig/confdata.c
@@ -222,8 +222,10 @@
 				continue;
 			if (def == S_DEF_USER) {
 				sym = sym_find(line + 9);
-				if (!sym)
+				if (!sym) {
+					sym_add_change_count(1);
 					break;
+				}
 			} else {
 				sym = sym_lookup(line + 9, 0);
 				if (sym->type == S_UNKNOWN)
@@ -259,8 +261,10 @@
 			}
 			if (def == S_DEF_USER) {
 				sym = sym_find(line + 7);
-				if (!sym)
+				if (!sym) {
+					sym_add_change_count(1);
 					break;
+				}
 			} else {
 				sym = sym_lookup(line + 7, 0);
 				if (sym->type == S_UNKNOWN)
diff --git a/scripts/kernel-doc b/scripts/kernel-doc
index ff787e6..44ee94d 100755
--- a/scripts/kernel-doc
+++ b/scripts/kernel-doc
@@ -781,6 +781,7 @@
     print " <refsect1>\n";
     print "  <title>Members</title>\n";
 
+    if ($#{$args{'parameterlist'}} >= 0) {
     print "  <variablelist>\n";
     foreach $parameter (@{$args{'parameterlist'}}) {
       ($parameter =~ /^#/) && next;
@@ -798,6 +799,9 @@
       print "    </varlistentry>\n";
     }
     print "  </variablelist>\n";
+    } else {
+	print " <para>\n  None\n </para>\n";
+    }
     print " </refsect1>\n";
 
     output_section_xml(@_);
diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c
index 4c9890e..d4dc222 100644
--- a/scripts/mod/file2alias.c
+++ b/scripts/mod/file2alias.c
@@ -206,6 +206,20 @@
 		do_usb_entry_multi(symval + i, mod);
 }
 
+/* Looks like: hid:bNvNpN */
+static int do_hid_entry(const char *filename,
+			     struct hid_device_id *id, char *alias)
+{
+	id->vendor = TO_NATIVE(id->vendor);
+	id->product = TO_NATIVE(id->product);
+
+	sprintf(alias, "hid:b%04X", id->bus);
+	ADD(alias, "v", id->vendor != HID_ANY_ID, id->vendor);
+	ADD(alias, "p", id->product != HID_ANY_ID, id->product);
+
+	return 1;
+}
+
 /* Looks like: ieee1394:venNmoNspNverN */
 static int do_ieee1394_entry(const char *filename,
 			     struct ieee1394_device_id *id, char *alias)
@@ -629,6 +643,59 @@
 	return 1;
 }
 
+static const struct dmifield {
+	const char *prefix;
+	int field;
+} dmi_fields[] = {
+	{ "bvn", DMI_BIOS_VENDOR },
+	{ "bvr", DMI_BIOS_VERSION },
+	{ "bd",  DMI_BIOS_DATE },
+	{ "svn", DMI_SYS_VENDOR },
+	{ "pn",  DMI_PRODUCT_NAME },
+	{ "pvr", DMI_PRODUCT_VERSION },
+	{ "rvn", DMI_BOARD_VENDOR },
+	{ "rn",  DMI_BOARD_NAME },
+	{ "rvr", DMI_BOARD_VERSION },
+	{ "cvn", DMI_CHASSIS_VENDOR },
+	{ "ct",  DMI_CHASSIS_TYPE },
+	{ "cvr", DMI_CHASSIS_VERSION },
+	{ NULL,  DMI_NONE }
+};
+
+static void dmi_ascii_filter(char *d, const char *s)
+{
+	/* Filter out characters we don't want to see in the modalias string */
+	for (; *s; s++)
+		if (*s > ' ' && *s < 127 && *s != ':')
+			*(d++) = *s;
+
+	*d = 0;
+}
+
+
+static int do_dmi_entry(const char *filename, struct dmi_system_id *id,
+			char *alias)
+{
+	int i, j;
+
+	sprintf(alias, "dmi*");
+
+	for (i = 0; i < ARRAY_SIZE(dmi_fields); i++) {
+		for (j = 0; j < 4; j++) {
+			if (id->matches[j].slot &&
+			    id->matches[j].slot == dmi_fields[i].field) {
+				sprintf(alias + strlen(alias), ":%s*",
+					dmi_fields[i].prefix);
+				dmi_ascii_filter(alias + strlen(alias),
+						 id->matches[j].substr);
+				strcat(alias, "*");
+			}
+		}
+	}
+
+	strcat(alias, ":");
+	return 1;
+}
 /* Ignore any prefix, eg. some architectures prepend _ */
 static inline int sym_is(const char *symbol, const char *name)
 {
@@ -692,6 +759,10 @@
 	else if (sym_is(symname, "__mod_usb_device_table"))
 		/* special case to handle bcdDevice ranges */
 		do_usb_table(symval, sym->st_size, mod);
+	else if (sym_is(symname, "__mod_hid_device_table"))
+		do_table(symval, sym->st_size,
+			 sizeof(struct hid_device_id), "hid",
+			 do_hid_entry, mod);
 	else if (sym_is(symname, "__mod_ieee1394_device_table"))
 		do_table(symval, sym->st_size,
 			 sizeof(struct ieee1394_device_id), "ieee1394",
@@ -760,6 +831,10 @@
 		do_table(symval, sym->st_size,
 			 sizeof(struct i2c_device_id), "i2c",
 			 do_i2c_entry, mod);
+	else if (sym_is(symname, "__mod_dmi_device_table"))
+		do_table(symval, sym->st_size,
+			 sizeof(struct dmi_system_id), "dmi",
+			 do_dmi_entry, mod);
 	free(zeros);
 }
 
diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c
index 418cd7d..8e0de6a 100644
--- a/scripts/mod/modpost.c
+++ b/scripts/mod/modpost.c
@@ -1986,11 +1986,13 @@
 
 		mod = find_module(modname);
 		if (!mod) {
-			if (is_vmlinux(modname))
-				have_vmlinux = 1;
 			mod = new_module(NOFAIL(strdup(modname)));
 			mod->skip = 1;
 		}
+		if (is_vmlinux(modname)) {
+			have_vmlinux = 1;
+			mod->skip = 0;
+		}
 
 		if (!mod->skip)
 			add_marker(mod, marker, fmt);
diff --git a/scripts/selinux/Makefile b/scripts/selinux/Makefile
new file mode 100644
index 0000000..ca4b1ec
--- /dev/null
+++ b/scripts/selinux/Makefile
@@ -0,0 +1,2 @@
+subdir-y := mdp
+subdir-	+= mdp
diff --git a/scripts/selinux/README b/scripts/selinux/README
new file mode 100644
index 0000000..a936315
--- /dev/null
+++ b/scripts/selinux/README
@@ -0,0 +1,2 @@
+Please see Documentation/SELinux.txt for information on
+installing a dummy SELinux policy.
diff --git a/scripts/selinux/install_policy.sh b/scripts/selinux/install_policy.sh
new file mode 100644
index 0000000..7b9ccf6
--- /dev/null
+++ b/scripts/selinux/install_policy.sh
@@ -0,0 +1,69 @@
+#!/bin/sh
+if [ `id -u` -ne 0 ]; then
+	echo "$0: must be root to install the selinux policy"
+	exit 1
+fi
+SF=`which setfiles`
+if [ $? -eq 1 ]; then
+	if [ -f /sbin/setfiles ]; then
+		SF="/usr/setfiles"
+	else
+		echo "no selinux tools installed: setfiles"
+		exit 1
+	fi
+fi
+
+cd mdp
+
+CP=`which checkpolicy`
+VERS=`$CP -V | awk '{print $1}'`
+
+./mdp policy.conf file_contexts
+$CP -o policy.$VERS policy.conf
+
+mkdir -p /etc/selinux/dummy/policy
+mkdir -p /etc/selinux/dummy/contexts/files
+
+cp file_contexts /etc/selinux/dummy/contexts/files
+cp dbus_contexts /etc/selinux/dummy/contexts
+cp policy.$VERS /etc/selinux/dummy/policy
+FC_FILE=/etc/selinux/dummy/contexts/files/file_contexts
+
+if [ ! -d /etc/selinux ]; then
+	mkdir -p /etc/selinux
+fi
+if [ ! -f /etc/selinux/config ]; then
+	cat > /etc/selinux/config << EOF
+SELINUX=enforcing
+SELINUXTYPE=dummy
+EOF
+else
+	TYPE=`cat /etc/selinux/config | grep "^SELINUXTYPE" | tail -1 | awk -F= '{ print $2 '}`
+	if [ "eq$TYPE" != "eqdummy" ]; then
+		selinuxenabled
+		if [ $? -eq 0 ]; then
+			echo "SELinux already enabled with a non-dummy policy."
+			echo "Exiting.  Please install policy by hand if that"
+			echo "is what you REALLY want."
+			exit 1
+		fi
+		mv /etc/selinux/config /etc/selinux/config.mdpbak
+		grep -v "^SELINUXTYPE" /etc/selinux/config.mdpbak >> /etc/selinux/config
+		echo "SELINUXTYPE=dummy" >> /etc/selinux/config
+	fi
+fi
+
+cd /etc/selinux/dummy/contexts/files
+$SF file_contexts /
+
+mounts=`cat /proc/$$/mounts | egrep "ext2|ext3|xfs|jfs|ext4|ext4dev|gfs2" | awk '{ print $2 '}`
+$SF file_contexts $mounts
+
+
+dodev=`cat /proc/$$/mounts | grep "/dev "`
+if [ "eq$dodev" != "eq" ]; then
+	mount --move /dev /mnt
+	$SF file_contexts /dev
+	mount --move /mnt /dev
+fi
+
diff --git a/scripts/selinux/mdp/.gitignore b/scripts/selinux/mdp/.gitignore
new file mode 100644
index 0000000..654546d
--- /dev/null
+++ b/scripts/selinux/mdp/.gitignore
@@ -0,0 +1,2 @@
+# Generated file
+mdp
diff --git a/scripts/selinux/mdp/Makefile b/scripts/selinux/mdp/Makefile
new file mode 100644
index 0000000..eb365b3
--- /dev/null
+++ b/scripts/selinux/mdp/Makefile
@@ -0,0 +1,5 @@
+hostprogs-y	:= mdp
+HOST_EXTRACFLAGS += -Isecurity/selinux/include
+
+always		:= $(hostprogs-y)
+clean-files	:= $(hostprogs-y) policy.* file_contexts
diff --git a/scripts/selinux/mdp/dbus_contexts b/scripts/selinux/mdp/dbus_contexts
new file mode 100644
index 0000000..116e684
--- /dev/null
+++ b/scripts/selinux/mdp/dbus_contexts
@@ -0,0 +1,6 @@
+<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
+ "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
+<busconfig>
+  <selinux>
+  </selinux>
+</busconfig>
diff --git a/scripts/selinux/mdp/mdp.c b/scripts/selinux/mdp/mdp.c
new file mode 100644
index 0000000..ca757d4
--- /dev/null
+++ b/scripts/selinux/mdp/mdp.c
@@ -0,0 +1,242 @@
+/*
+ *
+ * mdp - make dummy policy
+ *
+ * When pointed at a kernel tree, builds a dummy policy for that kernel
+ * with exactly one type with full rights to itself.
+ *
+ * This program is free software; you can redistribute it and/or 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
+ *
+ * Authors: Serge E. Hallyn <serue@us.ibm.com>
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+
+#include "flask.h"
+
+void usage(char *name)
+{
+	printf("usage: %s [-m] policy_file context_file\n", name);
+	exit(1);
+}
+
+void find_common_name(char *cname, char *dest, int len)
+{
+	char *start, *end;
+
+	start = strchr(cname, '_')+1;
+	end = strchr(start, '_');
+	if (!start || !end || start-cname > len || end-start > len) {
+		printf("Error with commons defines\n");
+		exit(1);
+	}
+	strncpy(dest, start, end-start);
+	dest[end-start] = '\0';
+}
+
+#define S_(x) x,
+static char *classlist[] = {
+#include "class_to_string.h"
+	NULL
+};
+#undef S_
+
+#include "initial_sid_to_string.h"
+
+#define TB_(x) char *x[] = {
+#define TE_(x) NULL };
+#define S_(x) x,
+#include "common_perm_to_string.h"
+#undef TB_
+#undef TE_
+#undef S_
+
+struct common {
+	char *cname;
+	char **perms;
+};
+struct common common[] = {
+#define TB_(x) { #x, x },
+#define S_(x)
+#define TE_(x)
+#include "common_perm_to_string.h"
+#undef TB_
+#undef TE_
+#undef S_
+};
+
+#define S_(x, y, z) {x, #y},
+struct av_inherit {
+	int class;
+	char *common;
+};
+struct av_inherit av_inherit[] = {
+#include "av_inherit.h"
+};
+#undef S_
+
+#include "av_permissions.h"
+#define S_(x, y, z) {x, y, z},
+struct av_perms {
+	int class;
+	int perm_i;
+	char *perm_s;
+};
+struct av_perms av_perms[] = {
+#include "av_perm_to_string.h"
+};
+#undef S_
+
+int main(int argc, char *argv[])
+{
+	int i, j, mls = 0;
+	char **arg, *polout, *ctxout;
+	int classlist_len, initial_sid_to_string_len;
+	FILE *fout;
+
+	if (argc < 3)
+		usage(argv[0]);
+	arg = argv+1;
+	if (argc==4 && strcmp(argv[1], "-m") == 0) {
+		mls = 1;
+		arg++;
+	}
+	polout = *arg++;
+	ctxout = *arg;
+
+	fout = fopen(polout, "w");
+	if (!fout) {
+		printf("Could not open %s for writing\n", polout);
+		usage(argv[0]);
+	}
+
+	classlist_len = sizeof(classlist) / sizeof(char *);
+	/* print out the classes */
+	for (i=1; i < classlist_len; i++) {
+		if(classlist[i])
+			fprintf(fout, "class %s\n", classlist[i]);
+		else
+			fprintf(fout, "class user%d\n", i);
+	}
+	fprintf(fout, "\n");
+
+	initial_sid_to_string_len = sizeof(initial_sid_to_string) / sizeof (char *);
+	/* print out the sids */
+	for (i=1; i < initial_sid_to_string_len; i++)
+		fprintf(fout, "sid %s\n", initial_sid_to_string[i]);
+	fprintf(fout, "\n");
+
+	/* print out the commons */
+	for (i=0; i< sizeof(common)/sizeof(struct common); i++) {
+		char cname[101];
+		find_common_name(common[i].cname, cname, 100);
+		cname[100] = '\0';
+		fprintf(fout, "common %s\n{\n", cname);
+		for (j=0; common[i].perms[j]; j++)
+			fprintf(fout, "\t%s\n", common[i].perms[j]);
+		fprintf(fout, "}\n\n");
+	}
+	fprintf(fout, "\n");
+
+	/* print out the class permissions */
+	for (i=1; i < classlist_len; i++) {
+		if (classlist[i]) {
+			int firstperm = -1, numperms = 0;
+
+			fprintf(fout, "class %s\n", classlist[i]);
+			/* does it inherit from a common? */
+			for (j=0; j < sizeof(av_inherit)/sizeof(struct av_inherit); j++)
+				if (av_inherit[j].class == i)
+					fprintf(fout, "inherits %s\n", av_inherit[j].common);
+
+			for (j=0; j < sizeof(av_perms)/sizeof(struct av_perms); j++) {
+				if (av_perms[j].class == i) {
+					if (firstperm == -1)
+						firstperm = j;
+					numperms++;
+				}
+			}
+			if (!numperms) {
+				fprintf(fout, "\n");
+				continue;
+			}
+
+			fprintf(fout, "{\n");
+			/* print out the av_perms */
+			for (j=0; j < numperms; j++) {
+				fprintf(fout, "\t%s\n", av_perms[firstperm+j].perm_s);
+			}
+			fprintf(fout, "}\n\n");
+		}
+	}
+	fprintf(fout, "\n");
+
+	/* NOW PRINT OUT MLS STUFF */
+	if (mls) {
+		printf("MLS not yet implemented\n");
+		exit(1);
+	}
+
+	/* types, roles, and allows */
+	fprintf(fout, "type base_t;\n");
+	fprintf(fout, "role base_r types { base_t };\n");
+	for (i=1; i < classlist_len; i++) {
+		if (classlist[i])
+			fprintf(fout, "allow base_t base_t:%s *;\n", classlist[i]);
+		else
+			fprintf(fout, "allow base_t base_t:user%d *;\n", i);
+	}
+	fprintf(fout, "user user_u roles { base_r };\n");
+	fprintf(fout, "\n");
+
+	/* default sids */
+	for (i=1; i < initial_sid_to_string_len; i++)
+		fprintf(fout, "sid %s user_u:base_r:base_t\n", initial_sid_to_string[i]);
+	fprintf(fout, "\n");
+
+
+	fprintf(fout, "fs_use_xattr ext2 user_u:base_r:base_t;\n");
+	fprintf(fout, "fs_use_xattr ext3 user_u:base_r:base_t;\n");
+	fprintf(fout, "fs_use_xattr jfs user_u:base_r:base_t;\n");
+	fprintf(fout, "fs_use_xattr xfs user_u:base_r:base_t;\n");
+	fprintf(fout, "fs_use_xattr reiserfs user_u:base_r:base_t;\n");
+
+	fprintf(fout, "fs_use_task pipefs user_u:base_r:base_t;\n");
+	fprintf(fout, "fs_use_task sockfs user_u:base_r:base_t;\n");
+
+	fprintf(fout, "fs_use_trans devpts user_u:base_r:base_t;\n");
+	fprintf(fout, "fs_use_trans tmpfs user_u:base_r:base_t;\n");
+	fprintf(fout, "fs_use_trans shm user_u:base_r:base_t;\n");
+
+	fprintf(fout, "genfscon proc / user_u:base_r:base_t\n");
+
+	fclose(fout);
+
+	fout = fopen(ctxout, "w");
+	if (!fout) {
+		printf("Wrote policy, but cannot open %s for writing\n", ctxout);
+		usage(argv[0]);
+	}
+	fprintf(fout, "/ user_u:base_r:base_t\n");
+	fprintf(fout, "/.* user_u:base_r:base_t\n");
+	fclose(fout);
+
+	return 0;
+}
diff --git a/security/Kconfig b/security/Kconfig
index 5592939..d9f47ce 100644
--- a/security/Kconfig
+++ b/security/Kconfig
@@ -51,6 +51,14 @@
 
 	  If you are unsure how to answer this question, answer N.
 
+config SECURITYFS
+	bool "Enable the securityfs filesystem"
+	help
+	  This will build the securityfs filesystem.  It is currently used by
+	  the TPM bios character driver.  It is not used by SELinux or SMACK.
+
+	  If you are unsure how to answer this question, answer N.
+
 config SECURITY_NETWORK
 	bool "Socket and Networking Security Hooks"
 	depends on SECURITY
diff --git a/security/Makefile b/security/Makefile
index f654260..c05c127 100644
--- a/security/Makefile
+++ b/security/Makefile
@@ -10,7 +10,8 @@
 obj-y		+= commoncap.o
 
 # Object file lists
-obj-$(CONFIG_SECURITY)			+= security.o capability.o inode.o
+obj-$(CONFIG_SECURITY)			+= security.o capability.o
+obj-$(CONFIG_SECURITYFS)		+= inode.o
 # Must precede capability.o in order to stack properly.
 obj-$(CONFIG_SECURITY_SELINUX)		+= selinux/built-in.o
 obj-$(CONFIG_SECURITY_SMACK)		+= smack/built-in.o
diff --git a/security/commoncap.c b/security/commoncap.c
index e4c4b3f..399bfdb 100644
--- a/security/commoncap.c
+++ b/security/commoncap.c
@@ -541,7 +541,7 @@
  * yet with increased caps.
  * So we check for increased caps on the target process.
  */
-static inline int cap_safe_nice(struct task_struct *p)
+static int cap_safe_nice(struct task_struct *p)
 {
 	if (!cap_issubset(p->cap_permitted, current->cap_permitted) &&
 	    !capable(CAP_SYS_NICE))
diff --git a/security/inode.c b/security/inode.c
index acc6cf0..efea5a6 100644
--- a/security/inode.c
+++ b/security/inode.c
@@ -20,8 +20,7 @@
 #include <linux/init.h>
 #include <linux/namei.h>
 #include <linux/security.h>
-
-#define SECURITYFS_MAGIC	0x73636673
+#include <linux/magic.h>
 
 static struct vfsmount *mount;
 static int mount_count;
@@ -190,7 +189,7 @@
  * @name: a pointer to a string containing the name of the file to create.
  * @mode: the permission that the file should have
  * @parent: a pointer to the parent dentry for this file.  This should be a
- *          directory dentry if set.  If this paramater is NULL, then the
+ *          directory dentry if set.  If this parameter is %NULL, then the
  *          file will be created in the root of the securityfs filesystem.
  * @data: a pointer to something that the caller will want to get to later
  *        on.  The inode.i_private pointer will point to this value on
@@ -199,18 +198,18 @@
  *        this file.
  *
  * This is the basic "create a file" function for securityfs.  It allows for a
- * wide range of flexibility in createing a file, or a directory (if you
+ * wide range of flexibility in creating a file, or a directory (if you
  * want to create a directory, the securityfs_create_dir() function is
- * recommended to be used instead.)
+ * recommended to be used instead).
  *
- * This function will return a pointer to a dentry if it succeeds.  This
+ * This function returns a pointer to a dentry if it succeeds.  This
  * pointer must be passed to the securityfs_remove() function when the file is
  * to be removed (no automatic cleanup happens if your module is unloaded,
- * you are responsible here.)  If an error occurs, NULL will be returned.
+ * you are responsible here).  If an error occurs, %NULL is returned.
  *
- * If securityfs is not enabled in the kernel, the value -ENODEV will be
+ * If securityfs is not enabled in the kernel, the value %-ENODEV is
  * returned.  It is not wise to check for this value, but rather, check for
- * NULL or !NULL instead as to eliminate the need for #ifdef in the calling
+ * %NULL or !%NULL instead as to eliminate the need for #ifdef in the calling
  * code.
  */
 struct dentry *securityfs_create_file(const char *name, mode_t mode,
@@ -252,19 +251,19 @@
  * @name: a pointer to a string containing the name of the directory to
  *        create.
  * @parent: a pointer to the parent dentry for this file.  This should be a
- *          directory dentry if set.  If this paramater is NULL, then the
+ *          directory dentry if set.  If this parameter is %NULL, then the
  *          directory will be created in the root of the securityfs filesystem.
  *
- * This function creates a directory in securityfs with the given name.
+ * This function creates a directory in securityfs with the given @name.
  *
- * This function will return a pointer to a dentry if it succeeds.  This
+ * This function returns a pointer to a dentry if it succeeds.  This
  * pointer must be passed to the securityfs_remove() function when the file is
  * to be removed (no automatic cleanup happens if your module is unloaded,
- * you are responsible here.)  If an error occurs, NULL will be returned.
+ * you are responsible here).  If an error occurs, %NULL will be returned.
  *
- * If securityfs is not enabled in the kernel, the value -ENODEV will be
+ * If securityfs is not enabled in the kernel, the value %-ENODEV is
  * returned.  It is not wise to check for this value, but rather, check for
- * NULL or !NULL instead as to eliminate the need for #ifdef in the calling
+ * %NULL or !%NULL instead as to eliminate the need for #ifdef in the calling
  * code.
  */
 struct dentry *securityfs_create_dir(const char *name, struct dentry *parent)
@@ -278,16 +277,15 @@
 /**
  * securityfs_remove - removes a file or directory from the securityfs filesystem
  *
- * @dentry: a pointer to a the dentry of the file or directory to be
- *          removed.
+ * @dentry: a pointer to a the dentry of the file or directory to be removed.
  *
  * This function removes a file or directory in securityfs that was previously
  * created with a call to another securityfs function (like
  * securityfs_create_file() or variants thereof.)
  *
  * This function is required to be called in order for the file to be
- * removed, no automatic cleanup of files will happen when a module is
- * removed, you are responsible here.
+ * removed. No automatic cleanup of files will happen when a module is
+ * removed; you are responsible here.
  */
 void securityfs_remove(struct dentry *dentry)
 {
diff --git a/security/security.c b/security/security.c
index 3a4b4f5..255b085 100644
--- a/security/security.c
+++ b/security/security.c
@@ -82,8 +82,8 @@
  *
  * Return true if:
  *	-The passed LSM is the one chosen by user at boot time,
- *	-or user didsn't specify a specific LSM and we're the first to ask
- *	 for registeration permissoin,
+ *	-or user didn't specify a specific LSM and we're the first to ask
+ *	 for registration permission,
  *	-or the passed LSM is currently loaded.
  * Otherwise, return false.
  */
@@ -101,13 +101,13 @@
  * register_security - registers a security framework with the kernel
  * @ops: a pointer to the struct security_options that is to be registered
  *
- * This function is to allow a security module to register itself with the
+ * This function allows a security module to register itself with the
  * kernel security subsystem.  Some rudimentary checking is done on the @ops
  * value passed to this function. You'll need to check first if your LSM
  * is allowed to register its @ops by calling security_module_enable(@ops).
  *
  * If there is already a security module registered with the kernel,
- * an error will be returned.  Otherwise 0 is returned on success.
+ * an error will be returned.  Otherwise %0 is returned on success.
  */
 int register_security(struct security_operations *ops)
 {
diff --git a/security/selinux/Kconfig b/security/selinux/Kconfig
index a436d1c..26301dd 100644
--- a/security/selinux/Kconfig
+++ b/security/selinux/Kconfig
@@ -6,9 +6,6 @@
 	help
 	  This selects NSA Security-Enhanced Linux (SELinux).
 	  You will also need a policy configuration and a labeled filesystem.
-	  You can obtain the policy compiler (checkpolicy), the utility for
-	  labeling filesystems (setfiles), and an example policy configuration
-	  from <http://www.nsa.gov/selinux/>.
 	  If you are unsure how to answer this question, answer N.
 
 config SECURITY_SELINUX_BOOTPARAM
diff --git a/security/selinux/avc.c b/security/selinux/avc.c
index 114b4b4..cb30c7e 100644
--- a/security/selinux/avc.c
+++ b/security/selinux/avc.c
@@ -136,7 +136,7 @@
  * @tclass: target security class
  * @av: access vector
  */
-static void avc_dump_av(struct audit_buffer *ab, u16 tclass, u32 av)
+void avc_dump_av(struct audit_buffer *ab, u16 tclass, u32 av)
 {
 	const char **common_pts = NULL;
 	u32 common_base = 0;
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 03fc6a8..576e511 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -291,6 +291,7 @@
 	struct sk_security_struct *ssec = sk->sk_security;
 
 	sk->sk_security = NULL;
+	selinux_netlbl_sk_security_free(ssec);
 	kfree(ssec);
 }
 
@@ -324,7 +325,7 @@
 	Opt_rootcontext = 4,
 };
 
-static match_table_t tokens = {
+static const match_table_t tokens = {
 	{Opt_context, CONTEXT_STR "%s"},
 	{Opt_fscontext, FSCONTEXT_STR "%s"},
 	{Opt_defcontext, DEFCONTEXT_STR "%s"},
@@ -957,7 +958,8 @@
 	return rc;
 }
 
-void selinux_write_opts(struct seq_file *m, struct security_mnt_opts *opts)
+static void selinux_write_opts(struct seq_file *m,
+			       struct security_mnt_opts *opts)
 {
 	int i;
 	char *prefix;
@@ -1290,7 +1292,7 @@
 		/* Default to the fs superblock SID. */
 		isec->sid = sbsec->sid;
 
-		if (sbsec->proc) {
+		if (sbsec->proc && !S_ISLNK(inode->i_mode)) {
 			struct proc_inode *proci = PROC_I(inode);
 			if (proci->pde) {
 				isec->sclass = inode_mode_to_security_class(inode->i_mode);
@@ -2120,7 +2122,6 @@
 	long j = -1;
 	int drop_tty = 0;
 
-	mutex_lock(&tty_mutex);
 	tty = get_current_tty();
 	if (tty) {
 		file_list_lock();
@@ -2138,8 +2139,8 @@
 			}
 		}
 		file_list_unlock();
+		tty_kref_put(tty);
 	}
-	mutex_unlock(&tty_mutex);
 	/* Reset controlling tty. */
 	if (drop_tty)
 		no_tty();
@@ -3548,38 +3549,44 @@
 #endif /* IPV6 */
 
 static int selinux_parse_skb(struct sk_buff *skb, struct avc_audit_data *ad,
-			     char **addrp, int src, u8 *proto)
+			     char **_addrp, int src, u8 *proto)
 {
-	int ret = 0;
+	char *addrp;
+	int ret;
 
 	switch (ad->u.net.family) {
 	case PF_INET:
 		ret = selinux_parse_skb_ipv4(skb, ad, proto);
-		if (ret || !addrp)
-			break;
-		*addrp = (char *)(src ? &ad->u.net.v4info.saddr :
-					&ad->u.net.v4info.daddr);
-		break;
+		if (ret)
+			goto parse_error;
+		addrp = (char *)(src ? &ad->u.net.v4info.saddr :
+				       &ad->u.net.v4info.daddr);
+		goto okay;
 
 #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
 	case PF_INET6:
 		ret = selinux_parse_skb_ipv6(skb, ad, proto);
-		if (ret || !addrp)
-			break;
-		*addrp = (char *)(src ? &ad->u.net.v6info.saddr :
-					&ad->u.net.v6info.daddr);
-		break;
+		if (ret)
+			goto parse_error;
+		addrp = (char *)(src ? &ad->u.net.v6info.saddr :
+				       &ad->u.net.v6info.daddr);
+		goto okay;
 #endif	/* IPV6 */
 	default:
-		break;
+		addrp = NULL;
+		goto okay;
 	}
 
-	if (unlikely(ret))
-		printk(KERN_WARNING
-		       "SELinux: failure in selinux_parse_skb(),"
-		       " unable to parse packet\n");
-
+parse_error:
+	printk(KERN_WARNING
+	       "SELinux: failure in selinux_parse_skb(),"
+	       " unable to parse packet\n");
 	return ret;
+
+okay:
+	if (_addrp)
+		*_addrp = addrp;
+	return 0;
 }
 
 /**
@@ -3794,6 +3801,7 @@
 
 static int selinux_socket_connect(struct socket *sock, struct sockaddr *address, int addrlen)
 {
+	struct sock *sk = sock->sk;
 	struct inode_security_struct *isec;
 	int err;
 
@@ -3807,7 +3815,6 @@
 	isec = SOCK_INODE(sock)->i_security;
 	if (isec->sclass == SECCLASS_TCP_SOCKET ||
 	    isec->sclass == SECCLASS_DCCP_SOCKET) {
-		struct sock *sk = sock->sk;
 		struct avc_audit_data ad;
 		struct sockaddr_in *addr4 = NULL;
 		struct sockaddr_in6 *addr6 = NULL;
@@ -3841,6 +3848,8 @@
 			goto out;
 	}
 
+	err = selinux_netlbl_socket_connect(sk, address);
+
 out:
 	return err;
 }
@@ -4070,20 +4079,28 @@
 }
 
 static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb,
-				       struct avc_audit_data *ad,
-				       u16 family, char *addrp)
+				       u16 family)
 {
 	int err;
 	struct sk_security_struct *sksec = sk->sk_security;
 	u32 peer_sid;
 	u32 sk_sid = sksec->sid;
+	struct avc_audit_data ad;
+	char *addrp;
+
+	AVC_AUDIT_DATA_INIT(&ad, NET);
+	ad.u.net.netif = skb->iif;
+	ad.u.net.family = family;
+	err = selinux_parse_skb(skb, &ad, &addrp, 1, NULL);
+	if (err)
+		return err;
 
 	if (selinux_compat_net)
-		err = selinux_sock_rcv_skb_iptables_compat(sk, skb, ad,
+		err = selinux_sock_rcv_skb_iptables_compat(sk, skb, &ad,
 							   family, addrp);
 	else
 		err = avc_has_perm(sk_sid, skb->secmark, SECCLASS_PACKET,
-				   PACKET__RECV, ad);
+				   PACKET__RECV, &ad);
 	if (err)
 		return err;
 
@@ -4092,12 +4109,14 @@
 		if (err)
 			return err;
 		err = avc_has_perm(sk_sid, peer_sid,
-				   SECCLASS_PEER, PEER__RECV, ad);
+				   SECCLASS_PEER, PEER__RECV, &ad);
+		if (err)
+			selinux_netlbl_err(skb, err, 0);
 	} else {
-		err = selinux_netlbl_sock_rcv_skb(sksec, skb, family, ad);
+		err = selinux_netlbl_sock_rcv_skb(sksec, skb, family, &ad);
 		if (err)
 			return err;
-		err = selinux_xfrm_sock_rcv_skb(sksec->sid, skb, ad);
+		err = selinux_xfrm_sock_rcv_skb(sksec->sid, skb, &ad);
 	}
 
 	return err;
@@ -4111,6 +4130,8 @@
 	u32 sk_sid = sksec->sid;
 	struct avc_audit_data ad;
 	char *addrp;
+	u8 secmark_active;
+	u8 peerlbl_active;
 
 	if (family != PF_INET && family != PF_INET6)
 		return 0;
@@ -4119,6 +4140,18 @@
 	if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP))
 		family = PF_INET;
 
+	/* If any sort of compatibility mode is enabled then handoff processing
+	 * to the selinux_sock_rcv_skb_compat() function to deal with the
+	 * special handling.  We do this in an attempt to keep this function
+	 * as fast and as clean as possible. */
+	if (selinux_compat_net || !selinux_policycap_netpeer)
+		return selinux_sock_rcv_skb_compat(sk, skb, family);
+
+	secmark_active = selinux_secmark_enabled();
+	peerlbl_active = netlbl_enabled() || selinux_xfrm_enabled();
+	if (!secmark_active && !peerlbl_active)
+		return 0;
+
 	AVC_AUDIT_DATA_INIT(&ad, NET);
 	ad.u.net.netif = skb->iif;
 	ad.u.net.family = family;
@@ -4126,15 +4159,7 @@
 	if (err)
 		return err;
 
-	/* If any sort of compatibility mode is enabled then handoff processing
-	 * to the selinux_sock_rcv_skb_compat() function to deal with the
-	 * special handling.  We do this in an attempt to keep this function
-	 * as fast and as clean as possible. */
-	if (selinux_compat_net || !selinux_policycap_netpeer)
-		return selinux_sock_rcv_skb_compat(sk, skb, &ad,
-						   family, addrp);
-
-	if (netlbl_enabled() || selinux_xfrm_enabled()) {
+	if (peerlbl_active) {
 		u32 peer_sid;
 
 		err = selinux_skb_peerlbl_sid(skb, family, &peer_sid);
@@ -4142,13 +4167,17 @@
 			return err;
 		err = selinux_inet_sys_rcv_skb(skb->iif, addrp, family,
 					       peer_sid, &ad);
-		if (err)
+		if (err) {
+			selinux_netlbl_err(skb, err, 0);
 			return err;
+		}
 		err = avc_has_perm(sk_sid, peer_sid, SECCLASS_PEER,
 				   PEER__RECV, &ad);
+		if (err)
+			selinux_netlbl_err(skb, err, 0);
 	}
 
-	if (selinux_secmark_enabled()) {
+	if (secmark_active) {
 		err = avc_has_perm(sk_sid, skb->secmark, SECCLASS_PACKET,
 				   PACKET__RECV, &ad);
 		if (err)
@@ -4207,10 +4236,12 @@
 	u32 peer_secid = SECSID_NULL;
 	u16 family;
 
-	if (sock)
+	if (skb && skb->protocol == htons(ETH_P_IP))
+		family = PF_INET;
+	else if (skb && skb->protocol == htons(ETH_P_IPV6))
+		family = PF_INET6;
+	else if (sock)
 		family = sock->sk->sk_family;
-	else if (skb && skb->sk)
-		family = skb->sk->sk_family;
 	else
 		goto out;
 
@@ -4268,8 +4299,6 @@
 	    sk->sk_family == PF_UNIX)
 		isec->sid = sksec->sid;
 	sksec->sclass = isec->sclass;
-
-	selinux_netlbl_sock_graft(sk, parent);
 }
 
 static int selinux_inet_conn_request(struct sock *sk, struct sk_buff *skb,
@@ -4277,10 +4306,15 @@
 {
 	struct sk_security_struct *sksec = sk->sk_security;
 	int err;
+	u16 family = sk->sk_family;
 	u32 newsid;
 	u32 peersid;
 
-	err = selinux_skb_peerlbl_sid(skb, sk->sk_family, &peersid);
+	/* handle mapped IPv4 packets arriving via IPv6 sockets */
+	if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP))
+		family = PF_INET;
+
+	err = selinux_skb_peerlbl_sid(skb, family, &peersid);
 	if (err)
 		return err;
 	if (peersid == SECSID_NULL) {
@@ -4315,12 +4349,18 @@
 	selinux_netlbl_sk_security_reset(newsksec, req->rsk_ops->family);
 }
 
-static void selinux_inet_conn_established(struct sock *sk,
-				struct sk_buff *skb)
+static void selinux_inet_conn_established(struct sock *sk, struct sk_buff *skb)
 {
+	u16 family = sk->sk_family;
 	struct sk_security_struct *sksec = sk->sk_security;
 
-	selinux_skb_peerlbl_sid(skb, sk->sk_family, &sksec->peer_sid);
+	/* handle mapped IPv4 packets arriving via IPv6 sockets */
+	if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP))
+		family = PF_INET;
+
+	selinux_skb_peerlbl_sid(skb, family, &sksec->peer_sid);
+
+	selinux_netlbl_inet_conn_established(sk, family);
 }
 
 static void selinux_req_classify_flow(const struct request_sock *req,
@@ -4370,39 +4410,54 @@
 static unsigned int selinux_ip_forward(struct sk_buff *skb, int ifindex,
 				       u16 family)
 {
+	int err;
 	char *addrp;
 	u32 peer_sid;
 	struct avc_audit_data ad;
 	u8 secmark_active;
+	u8 netlbl_active;
 	u8 peerlbl_active;
 
 	if (!selinux_policycap_netpeer)
 		return NF_ACCEPT;
 
 	secmark_active = selinux_secmark_enabled();
-	peerlbl_active = netlbl_enabled() || selinux_xfrm_enabled();
+	netlbl_active = netlbl_enabled();
+	peerlbl_active = netlbl_active || selinux_xfrm_enabled();
 	if (!secmark_active && !peerlbl_active)
 		return NF_ACCEPT;
 
+	if (selinux_skb_peerlbl_sid(skb, family, &peer_sid) != 0)
+		return NF_DROP;
+
 	AVC_AUDIT_DATA_INIT(&ad, NET);
 	ad.u.net.netif = ifindex;
 	ad.u.net.family = family;
 	if (selinux_parse_skb(skb, &ad, &addrp, 1, NULL) != 0)
 		return NF_DROP;
 
-	if (selinux_skb_peerlbl_sid(skb, family, &peer_sid) != 0)
-		return NF_DROP;
-
-	if (peerlbl_active)
-		if (selinux_inet_sys_rcv_skb(ifindex, addrp, family,
-					     peer_sid, &ad) != 0)
+	if (peerlbl_active) {
+		err = selinux_inet_sys_rcv_skb(ifindex, addrp, family,
+					       peer_sid, &ad);
+		if (err) {
+			selinux_netlbl_err(skb, err, 1);
 			return NF_DROP;
+		}
+	}
 
 	if (secmark_active)
 		if (avc_has_perm(peer_sid, skb->secmark,
 				 SECCLASS_PACKET, PACKET__FORWARD_IN, &ad))
 			return NF_DROP;
 
+	if (netlbl_active)
+		/* we do this in the FORWARD path and not the POST_ROUTING
+		 * path because we want to make sure we apply the necessary
+		 * labeling before IPsec is applied so we can leverage AH
+		 * protection */
+		if (selinux_netlbl_skbuff_setsid(skb, family, peer_sid) != 0)
+			return NF_DROP;
+
 	return NF_ACCEPT;
 }
 
@@ -4426,6 +4481,37 @@
 }
 #endif	/* IPV6 */
 
+static unsigned int selinux_ip_output(struct sk_buff *skb,
+				      u16 family)
+{
+	u32 sid;
+
+	if (!netlbl_enabled())
+		return NF_ACCEPT;
+
+	/* we do this in the LOCAL_OUT path and not the POST_ROUTING path
+	 * because we want to make sure we apply the necessary labeling
+	 * before IPsec is applied so we can leverage AH protection */
+	if (skb->sk) {
+		struct sk_security_struct *sksec = skb->sk->sk_security;
+		sid = sksec->sid;
+	} else
+		sid = SECINITSID_KERNEL;
+	if (selinux_netlbl_skbuff_setsid(skb, family, sid) != 0)
+		return NF_DROP;
+
+	return NF_ACCEPT;
+}
+
+static unsigned int selinux_ipv4_output(unsigned int hooknum,
+					struct sk_buff *skb,
+					const struct net_device *in,
+					const struct net_device *out,
+					int (*okfn)(struct sk_buff *))
+{
+	return selinux_ip_output(skb, PF_INET);
+}
+
 static int selinux_ip_postroute_iptables_compat(struct sock *sk,
 						int ifindex,
 						struct avc_audit_data *ad,
@@ -4493,30 +4579,36 @@
 
 static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb,
 						int ifindex,
-						struct avc_audit_data *ad,
-						u16 family,
-						char *addrp,
-						u8 proto)
+						u16 family)
 {
 	struct sock *sk = skb->sk;
 	struct sk_security_struct *sksec;
+	struct avc_audit_data ad;
+	char *addrp;
+	u8 proto;
 
 	if (sk == NULL)
 		return NF_ACCEPT;
 	sksec = sk->sk_security;
 
+	AVC_AUDIT_DATA_INIT(&ad, NET);
+	ad.u.net.netif = ifindex;
+	ad.u.net.family = family;
+	if (selinux_parse_skb(skb, &ad, &addrp, 0, &proto))
+		return NF_DROP;
+
 	if (selinux_compat_net) {
 		if (selinux_ip_postroute_iptables_compat(skb->sk, ifindex,
-							 ad, family, addrp))
+							 &ad, family, addrp))
 			return NF_DROP;
 	} else {
 		if (avc_has_perm(sksec->sid, skb->secmark,
-				 SECCLASS_PACKET, PACKET__SEND, ad))
+				 SECCLASS_PACKET, PACKET__SEND, &ad))
 			return NF_DROP;
 	}
 
 	if (selinux_policycap_netpeer)
-		if (selinux_xfrm_postroute_last(sksec->sid, skb, ad, proto))
+		if (selinux_xfrm_postroute_last(sksec->sid, skb, &ad, proto))
 			return NF_DROP;
 
 	return NF_ACCEPT;
@@ -4530,23 +4622,15 @@
 	struct sock *sk;
 	struct avc_audit_data ad;
 	char *addrp;
-	u8 proto;
 	u8 secmark_active;
 	u8 peerlbl_active;
 
-	AVC_AUDIT_DATA_INIT(&ad, NET);
-	ad.u.net.netif = ifindex;
-	ad.u.net.family = family;
-	if (selinux_parse_skb(skb, &ad, &addrp, 0, &proto))
-		return NF_DROP;
-
 	/* If any sort of compatibility mode is enabled then handoff processing
 	 * to the selinux_ip_postroute_compat() function to deal with the
 	 * special handling.  We do this in an attempt to keep this function
 	 * as fast and as clean as possible. */
 	if (selinux_compat_net || !selinux_policycap_netpeer)
-		return selinux_ip_postroute_compat(skb, ifindex, &ad,
-						   family, addrp, proto);
+		return selinux_ip_postroute_compat(skb, ifindex, family);
 
 	/* If skb->dst->xfrm is non-NULL then the packet is undergoing an IPsec
 	 * packet transformation so allow the packet to pass without any checks
@@ -4562,21 +4646,45 @@
 	if (!secmark_active && !peerlbl_active)
 		return NF_ACCEPT;
 
-	/* if the packet is locally generated (skb->sk != NULL) then use the
-	 * socket's label as the peer label, otherwise the packet is being
-	 * forwarded through this system and we need to fetch the peer label
-	 * directly from the packet */
+	/* if the packet is being forwarded then get the peer label from the
+	 * packet itself; otherwise check to see if it is from a local
+	 * application or the kernel, if from an application get the peer label
+	 * from the sending socket, otherwise use the kernel's sid */
 	sk = skb->sk;
-	if (sk) {
+	if (sk == NULL) {
+		switch (family) {
+		case PF_INET:
+			if (IPCB(skb)->flags & IPSKB_FORWARDED)
+				secmark_perm = PACKET__FORWARD_OUT;
+			else
+				secmark_perm = PACKET__SEND;
+			break;
+		case PF_INET6:
+			if (IP6CB(skb)->flags & IP6SKB_FORWARDED)
+				secmark_perm = PACKET__FORWARD_OUT;
+			else
+				secmark_perm = PACKET__SEND;
+			break;
+		default:
+			return NF_DROP;
+		}
+		if (secmark_perm == PACKET__FORWARD_OUT) {
+			if (selinux_skb_peerlbl_sid(skb, family, &peer_sid))
+				return NF_DROP;
+		} else
+			peer_sid = SECINITSID_KERNEL;
+	} else {
 		struct sk_security_struct *sksec = sk->sk_security;
 		peer_sid = sksec->sid;
 		secmark_perm = PACKET__SEND;
-	} else {
-		if (selinux_skb_peerlbl_sid(skb, family, &peer_sid))
-				return NF_DROP;
-		secmark_perm = PACKET__FORWARD_OUT;
 	}
 
+	AVC_AUDIT_DATA_INIT(&ad, NET);
+	ad.u.net.netif = ifindex;
+	ad.u.net.family = family;
+	if (selinux_parse_skb(skb, &ad, &addrp, 0, NULL))
+		return NF_DROP;
+
 	if (secmark_active)
 		if (avc_has_perm(peer_sid, skb->secmark,
 				 SECCLASS_PACKET, secmark_perm, &ad))
@@ -5219,8 +5327,12 @@
 
 		if (sid == 0)
 			return -EINVAL;
-
-		/* Only allow single threaded processes to change context */
+		/*
+		 * SELinux allows to change context in the following case only.
+		 *  - Single threaded processes.
+		 *  - Multi threaded processes intend to change its context into
+		 *    more restricted domain (defined by TYPEBOUNDS statement).
+		 */
 		if (atomic_read(&p->mm->mm_users) != 1) {
 			struct task_struct *g, *t;
 			struct mm_struct *mm = p->mm;
@@ -5228,11 +5340,16 @@
 			do_each_thread(g, t) {
 				if (t->mm == mm && t != p) {
 					read_unlock(&tasklist_lock);
-					return -EPERM;
+					error = security_bounded_transition(tsec->sid, sid);
+					if (!error)
+						goto boundary_ok;
+
+					return error;
 				}
 			} while_each_thread(g, t);
 			read_unlock(&tasklist_lock);
 		}
+boundary_ok:
 
 		/* Check permissions for the transition. */
 		error = avc_has_perm(tsec->sid, sid, SECCLASS_PROCESS,
@@ -5641,6 +5758,13 @@
 		.pf =		PF_INET,
 		.hooknum =	NF_INET_FORWARD,
 		.priority =	NF_IP_PRI_SELINUX_FIRST,
+	},
+	{
+		.hook =		selinux_ipv4_output,
+		.owner =	THIS_MODULE,
+		.pf =		PF_INET,
+		.hooknum =	NF_INET_LOCAL_OUT,
+		.priority =	NF_IP_PRI_SELINUX_FIRST,
 	}
 };
 
diff --git a/security/selinux/include/avc.h b/security/selinux/include/avc.h
index 7b9769f..d12ff1a 100644
--- a/security/selinux/include/avc.h
+++ b/security/selinux/include/avc.h
@@ -12,6 +12,7 @@
 #include <linux/kdev_t.h>
 #include <linux/spinlock.h>
 #include <linux/init.h>
+#include <linux/audit.h>
 #include <linux/in6.h>
 #include <linux/path.h>
 #include <asm/system.h>
@@ -126,6 +127,9 @@
 		     u32 events, u32 ssid, u32 tsid,
 		     u16 tclass, u32 perms);
 
+/* Shows permission in human readable form */
+void avc_dump_av(struct audit_buffer *ab, u16 tclass, u32 av);
+
 /* Exported to selinuxfs */
 int avc_get_hash_stats(char *page);
 extern unsigned int avc_cache_threshold;
diff --git a/security/selinux/include/netlabel.h b/security/selinux/include/netlabel.h
index 487a7d8..b913c8d 100644
--- a/security/selinux/include/netlabel.h
+++ b/security/selinux/include/netlabel.h
@@ -39,6 +39,9 @@
 #ifdef CONFIG_NETLABEL
 void selinux_netlbl_cache_invalidate(void);
 
+void selinux_netlbl_err(struct sk_buff *skb, int error, int gateway);
+
+void selinux_netlbl_sk_security_free(struct sk_security_struct *ssec);
 void selinux_netlbl_sk_security_reset(struct sk_security_struct *ssec,
 				      int family);
 
@@ -46,8 +49,11 @@
 				 u16 family,
 				 u32 *type,
 				 u32 *sid);
+int selinux_netlbl_skbuff_setsid(struct sk_buff *skb,
+				 u16 family,
+				 u32 sid);
 
-void selinux_netlbl_sock_graft(struct sock *sk, struct socket *sock);
+void selinux_netlbl_inet_conn_established(struct sock *sk, u16 family);
 int selinux_netlbl_socket_post_create(struct socket *sock);
 int selinux_netlbl_inode_permission(struct inode *inode, int mask);
 int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec,
@@ -57,12 +63,27 @@
 int selinux_netlbl_socket_setsockopt(struct socket *sock,
 				     int level,
 				     int optname);
+int selinux_netlbl_socket_connect(struct sock *sk, struct sockaddr *addr);
+
 #else
 static inline void selinux_netlbl_cache_invalidate(void)
 {
 	return;
 }
 
+static inline void selinux_netlbl_err(struct sk_buff *skb,
+				      int error,
+				      int gateway)
+{
+	return;
+}
+
+static inline void selinux_netlbl_sk_security_free(
+					       struct sk_security_struct *ssec)
+{
+	return;
+}
+
 static inline void selinux_netlbl_sk_security_reset(
 					       struct sk_security_struct *ssec,
 					       int family)
@@ -79,9 +100,21 @@
 	*sid = SECSID_NULL;
 	return 0;
 }
+static inline int selinux_netlbl_skbuff_setsid(struct sk_buff *skb,
+					       u16 family,
+					       u32 sid)
+{
+	return 0;
+}
 
-static inline void selinux_netlbl_sock_graft(struct sock *sk,
-					     struct socket *sock)
+static inline int selinux_netlbl_conn_setsid(struct sock *sk,
+					     struct sockaddr *addr)
+{
+	return 0;
+}
+
+static inline void selinux_netlbl_inet_conn_established(struct sock *sk,
+							u16 family)
 {
 	return;
 }
@@ -107,6 +140,11 @@
 {
 	return 0;
 }
+static inline int selinux_netlbl_socket_connect(struct sock *sk,
+						struct sockaddr *addr)
+{
+	return 0;
+}
 #endif /* CONFIG_NETLABEL */
 
 #endif
diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h
index 91070ab..f8be8d7 100644
--- a/security/selinux/include/objsec.h
+++ b/security/selinux/include/objsec.h
@@ -109,16 +109,19 @@
 };
 
 struct sk_security_struct {
-	u32 sid;			/* SID of this object */
-	u32 peer_sid;			/* SID of peer */
-	u16 sclass;			/* sock security class */
 #ifdef CONFIG_NETLABEL
 	enum {				/* NetLabel state */
 		NLBL_UNSET = 0,
 		NLBL_REQUIRE,
 		NLBL_LABELED,
+		NLBL_REQSKB,
+		NLBL_CONNLABELED,
 	} nlbl_state;
+	struct netlbl_lsm_secattr *nlbl_secattr; /* NetLabel sec attributes */
 #endif
+	u32 sid;			/* SID of this object */
+	u32 peer_sid;			/* SID of peer */
+	u16 sclass;			/* sock security class */
 };
 
 struct key_security_struct {
diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h
index 7c54300..7244737 100644
--- a/security/selinux/include/security.h
+++ b/security/selinux/include/security.h
@@ -27,13 +27,14 @@
 #define POLICYDB_VERSION_RANGETRANS	21
 #define POLICYDB_VERSION_POLCAP		22
 #define POLICYDB_VERSION_PERMISSIVE	23
+#define POLICYDB_VERSION_BOUNDARY	24
 
 /* Range of policy versions we understand*/
 #define POLICYDB_VERSION_MIN   POLICYDB_VERSION_BASE
 #ifdef CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX
 #define POLICYDB_VERSION_MAX	CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX_VALUE
 #else
-#define POLICYDB_VERSION_MAX	POLICYDB_VERSION_PERMISSIVE
+#define POLICYDB_VERSION_MAX	POLICYDB_VERSION_BOUNDARY
 #endif
 
 #define CONTEXT_MNT	0x01
@@ -62,6 +63,16 @@
 extern int selinux_policycap_netpeer;
 extern int selinux_policycap_openperm;
 
+/*
+ * type_datum properties
+ * available at the kernel policy version >= POLICYDB_VERSION_BOUNDARY
+ */
+#define TYPEDATUM_PROPERTY_PRIMARY	0x0001
+#define TYPEDATUM_PROPERTY_ATTRIBUTE	0x0002
+
+/* limitation of boundary depth  */
+#define POLICYDB_BOUNDS_MAXDEPTH	4
+
 int security_load_policy(void *data, size_t len);
 
 int security_policycap_supported(unsigned int req_cap);
@@ -117,6 +128,8 @@
 int security_validate_transition(u32 oldsid, u32 newsid, u32 tasksid,
 				 u16 tclass);
 
+int security_bounded_transition(u32 oldsid, u32 newsid);
+
 int security_sid_mls_copy(u32 sid, u32 mls_sid, u32 *new_sid);
 
 int security_net_peersid_resolve(u32 nlbl_sid, u32 nlbl_type,
diff --git a/security/selinux/netlabel.c b/security/selinux/netlabel.c
index 89b41839..f58701a 100644
--- a/security/selinux/netlabel.c
+++ b/security/selinux/netlabel.c
@@ -9,7 +9,7 @@
  */
 
 /*
- * (c) Copyright Hewlett-Packard Development Company, L.P., 2007
+ * (c) Copyright Hewlett-Packard Development Company, L.P., 2007, 2008
  *
  * This program is free software;  you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -29,8 +29,12 @@
 
 #include <linux/spinlock.h>
 #include <linux/rcupdate.h>
+#include <linux/ip.h>
+#include <linux/ipv6.h>
 #include <net/sock.h>
 #include <net/netlabel.h>
+#include <net/ip.h>
+#include <net/ipv6.h>
 
 #include "objsec.h"
 #include "security.h"
@@ -64,32 +68,69 @@
 }
 
 /**
- * selinux_netlbl_sock_setsid - Label a socket using the NetLabel mechanism
- * @sk: the socket to label
- * @sid: the SID to use
+ * selinux_netlbl_sock_genattr - Generate the NetLabel socket secattr
+ * @sk: the socket
  *
  * Description:
- * Attempt to label a socket using the NetLabel mechanism using the given
- * SID.  Returns zero values on success, negative values on failure.
+ * Generate the NetLabel security attributes for a socket, making full use of
+ * the socket's attribute cache.  Returns a pointer to the security attributes
+ * on success, NULL on failure.
  *
  */
-static int selinux_netlbl_sock_setsid(struct sock *sk, u32 sid)
+static struct netlbl_lsm_secattr *selinux_netlbl_sock_genattr(struct sock *sk)
 {
 	int rc;
 	struct sk_security_struct *sksec = sk->sk_security;
-	struct netlbl_lsm_secattr secattr;
+	struct netlbl_lsm_secattr *secattr;
 
-	netlbl_secattr_init(&secattr);
+	if (sksec->nlbl_secattr != NULL)
+		return sksec->nlbl_secattr;
 
-	rc = security_netlbl_sid_to_secattr(sid, &secattr);
-	if (rc != 0)
-		goto sock_setsid_return;
-	rc = netlbl_sock_setattr(sk, &secattr);
-	if (rc == 0)
+	secattr = netlbl_secattr_alloc(GFP_ATOMIC);
+	if (secattr == NULL)
+		return NULL;
+	rc = security_netlbl_sid_to_secattr(sksec->sid, secattr);
+	if (rc != 0) {
+		netlbl_secattr_free(secattr);
+		return NULL;
+	}
+	sksec->nlbl_secattr = secattr;
+
+	return secattr;
+}
+
+/**
+ * selinux_netlbl_sock_setsid - Label a socket using the NetLabel mechanism
+ * @sk: the socket to label
+ *
+ * Description:
+ * Attempt to label a socket using the NetLabel mechanism.  Returns zero values
+ * on success, negative values on failure.
+ *
+ */
+static int selinux_netlbl_sock_setsid(struct sock *sk)
+{
+	int rc;
+	struct sk_security_struct *sksec = sk->sk_security;
+	struct netlbl_lsm_secattr *secattr;
+
+	if (sksec->nlbl_state != NLBL_REQUIRE)
+		return 0;
+
+	secattr = selinux_netlbl_sock_genattr(sk);
+	if (secattr == NULL)
+		return -ENOMEM;
+	rc = netlbl_sock_setattr(sk, secattr);
+	switch (rc) {
+	case 0:
 		sksec->nlbl_state = NLBL_LABELED;
+		break;
+	case -EDESTADDRREQ:
+		sksec->nlbl_state = NLBL_REQSKB;
+		rc = 0;
+		break;
+	}
 
-sock_setsid_return:
-	netlbl_secattr_destroy(&secattr);
 	return rc;
 }
 
@@ -106,6 +147,38 @@
 }
 
 /**
+ * selinux_netlbl_err - Handle a NetLabel packet error
+ * @skb: the packet
+ * @error: the error code
+ * @gateway: true if host is acting as a gateway, false otherwise
+ *
+ * Description:
+ * When a packet is dropped due to a call to avc_has_perm() pass the error
+ * code to the NetLabel subsystem so any protocol specific processing can be
+ * done.  This is safe to call even if you are unsure if NetLabel labeling is
+ * present on the packet, NetLabel is smart enough to only act when it should.
+ *
+ */
+void selinux_netlbl_err(struct sk_buff *skb, int error, int gateway)
+{
+	netlbl_skbuff_err(skb, error, gateway);
+}
+
+/**
+ * selinux_netlbl_sk_security_free - Free the NetLabel fields
+ * @sssec: the sk_security_struct
+ *
+ * Description:
+ * Free all of the memory in the NetLabel fields of a sk_security_struct.
+ *
+ */
+void selinux_netlbl_sk_security_free(struct sk_security_struct *ssec)
+{
+	if (ssec->nlbl_secattr != NULL)
+		netlbl_secattr_free(ssec->nlbl_secattr);
+}
+
+/**
  * selinux_netlbl_sk_security_reset - Reset the NetLabel fields
  * @ssec: the sk_security_struct
  * @family: the socket family
@@ -163,35 +236,118 @@
 }
 
 /**
- * selinux_netlbl_sock_graft - Netlabel the new socket
- * @sk: the new connection
- * @sock: the new socket
+ * selinux_netlbl_skbuff_setsid - Set the NetLabel on a packet given a sid
+ * @skb: the packet
+ * @family: protocol family
+ * @sid: the SID
  *
- * Description:
- * The connection represented by @sk is being grafted onto @sock so set the
- * socket's NetLabel to match the SID of @sk.
+ * Description
+ * Call the NetLabel mechanism to set the label of a packet using @sid.
+ * Returns zero on auccess, negative values on failure.
  *
  */
-void selinux_netlbl_sock_graft(struct sock *sk, struct socket *sock)
+int selinux_netlbl_skbuff_setsid(struct sk_buff *skb,
+				 u16 family,
+				 u32 sid)
 {
+	int rc;
+	struct netlbl_lsm_secattr secattr_storage;
+	struct netlbl_lsm_secattr *secattr = NULL;
+	struct sock *sk;
+
+	/* if this is a locally generated packet check to see if it is already
+	 * being labeled by it's parent socket, if it is just exit */
+	sk = skb->sk;
+	if (sk != NULL) {
+		struct sk_security_struct *sksec = sk->sk_security;
+		if (sksec->nlbl_state != NLBL_REQSKB)
+			return 0;
+		secattr = sksec->nlbl_secattr;
+	}
+	if (secattr == NULL) {
+		secattr = &secattr_storage;
+		netlbl_secattr_init(secattr);
+		rc = security_netlbl_sid_to_secattr(sid, secattr);
+		if (rc != 0)
+			goto skbuff_setsid_return;
+	}
+
+	rc = netlbl_skbuff_setattr(skb, family, secattr);
+
+skbuff_setsid_return:
+	if (secattr == &secattr_storage)
+		netlbl_secattr_destroy(secattr);
+	return rc;
+}
+
+/**
+ * selinux_netlbl_inet_conn_established - Netlabel the newly accepted connection
+ * @sk: the new connection
+ *
+ * Description:
+ * A new connection has been established on @sk so make sure it is labeled
+ * correctly with the NetLabel susbsystem.
+ *
+ */
+void selinux_netlbl_inet_conn_established(struct sock *sk, u16 family)
+{
+	int rc;
 	struct sk_security_struct *sksec = sk->sk_security;
-	struct netlbl_lsm_secattr secattr;
-	u32 nlbl_peer_sid;
+	struct netlbl_lsm_secattr *secattr;
+	struct inet_sock *sk_inet = inet_sk(sk);
+	struct sockaddr_in addr;
 
 	if (sksec->nlbl_state != NLBL_REQUIRE)
 		return;
 
-	netlbl_secattr_init(&secattr);
-	if (netlbl_sock_getattr(sk, &secattr) == 0 &&
-	    secattr.flags != NETLBL_SECATTR_NONE &&
-	    security_netlbl_secattr_to_sid(&secattr, &nlbl_peer_sid) == 0)
-		sksec->peer_sid = nlbl_peer_sid;
-	netlbl_secattr_destroy(&secattr);
+	secattr = selinux_netlbl_sock_genattr(sk);
+	if (secattr == NULL)
+		return;
 
-	/* Try to set the NetLabel on the socket to save time later, if we fail
-	 * here we will pick up the pieces in later calls to
-	 * selinux_netlbl_inode_permission(). */
-	selinux_netlbl_sock_setsid(sk, sksec->sid);
+	rc = netlbl_sock_setattr(sk, secattr);
+	switch (rc) {
+	case 0:
+		sksec->nlbl_state = NLBL_LABELED;
+		break;
+	case -EDESTADDRREQ:
+		/* no PF_INET6 support yet because we don't support any IPv6
+		 * labeling protocols */
+		if (family != PF_INET) {
+			sksec->nlbl_state = NLBL_UNSET;
+			return;
+		}
+
+		addr.sin_family = family;
+		addr.sin_addr.s_addr = sk_inet->daddr;
+		if (netlbl_conn_setattr(sk, (struct sockaddr *)&addr,
+					secattr) != 0) {
+			/* we failed to label the connected socket (could be
+			 * for a variety of reasons, the actual "why" isn't
+			 * important here) so we have to go to our backup plan,
+			 * labeling the packets individually in the netfilter
+			 * local output hook.  this is okay but we need to
+			 * adjust the MSS of the connection to take into
+			 * account any labeling overhead, since we don't know
+			 * the exact overhead at this point we'll use the worst
+			 * case value which is 40 bytes for IPv4 */
+			struct inet_connection_sock *sk_conn = inet_csk(sk);
+			sk_conn->icsk_ext_hdr_len += 40 -
+				      (sk_inet->opt ? sk_inet->opt->optlen : 0);
+			sk_conn->icsk_sync_mss(sk, sk_conn->icsk_pmtu_cookie);
+
+			sksec->nlbl_state = NLBL_REQSKB;
+		} else
+			sksec->nlbl_state = NLBL_CONNLABELED;
+		break;
+	default:
+		/* note that we are failing to label the socket which could be
+		 * a bad thing since it means traffic could leave the system
+		 * without the desired labeling, however, all is not lost as
+		 * we have a check in selinux_netlbl_inode_permission() to
+		 * pick up the pieces that we might drop here because we can't
+		 * return an error code */
+		break;
+	}
 }
 
 /**
@@ -205,13 +361,7 @@
  */
 int selinux_netlbl_socket_post_create(struct socket *sock)
 {
-	struct sock *sk = sock->sk;
-	struct sk_security_struct *sksec = sk->sk_security;
-
-	if (sksec->nlbl_state != NLBL_REQUIRE)
-		return 0;
-
-	return selinux_netlbl_sock_setsid(sk, sksec->sid);
+	return selinux_netlbl_sock_setsid(sock->sk);
 }
 
 /**
@@ -246,7 +396,7 @@
 	local_bh_disable();
 	bh_lock_sock_nested(sk);
 	if (likely(sksec->nlbl_state == NLBL_REQUIRE))
-		rc = selinux_netlbl_sock_setsid(sk, sksec->sid);
+		rc = selinux_netlbl_sock_setsid(sk);
 	else
 		rc = 0;
 	bh_unlock_sock(sk);
@@ -307,7 +457,7 @@
 		return 0;
 
 	if (nlbl_sid != SECINITSID_UNLABELED)
-		netlbl_skbuff_err(skb, rc);
+		netlbl_skbuff_err(skb, rc, 0);
 	return rc;
 }
 
@@ -334,7 +484,8 @@
 	struct netlbl_lsm_secattr secattr;
 
 	if (level == IPPROTO_IP && optname == IP_OPTIONS &&
-	    sksec->nlbl_state == NLBL_LABELED) {
+	    (sksec->nlbl_state == NLBL_LABELED ||
+	     sksec->nlbl_state == NLBL_CONNLABELED)) {
 		netlbl_secattr_init(&secattr);
 		lock_sock(sk);
 		rc = netlbl_sock_getattr(sk, &secattr);
@@ -346,3 +497,50 @@
 
 	return rc;
 }
+
+/**
+ * selinux_netlbl_socket_connect - Label a client-side socket on connect
+ * @sk: the socket to label
+ * @addr: the destination address
+ *
+ * Description:
+ * Attempt to label a connected socket with NetLabel using the given address.
+ * Returns zero values on success, negative values on failure.
+ *
+ */
+int selinux_netlbl_socket_connect(struct sock *sk, struct sockaddr *addr)
+{
+	int rc;
+	struct sk_security_struct *sksec = sk->sk_security;
+	struct netlbl_lsm_secattr *secattr;
+
+	if (sksec->nlbl_state != NLBL_REQSKB &&
+	    sksec->nlbl_state != NLBL_CONNLABELED)
+		return 0;
+
+	local_bh_disable();
+	bh_lock_sock_nested(sk);
+
+	/* connected sockets are allowed to disconnect when the address family
+	 * is set to AF_UNSPEC, if that is what is happening we want to reset
+	 * the socket */
+	if (addr->sa_family == AF_UNSPEC) {
+		netlbl_sock_delattr(sk);
+		sksec->nlbl_state = NLBL_REQSKB;
+		rc = 0;
+		goto socket_connect_return;
+	}
+	secattr = selinux_netlbl_sock_genattr(sk);
+	if (secattr == NULL) {
+		rc = -ENOMEM;
+		goto socket_connect_return;
+	}
+	rc = netlbl_conn_setattr(sk, addr, secattr);
+	if (rc == 0)
+		sksec->nlbl_state = NLBL_CONNLABELED;
+
+socket_connect_return:
+	bh_unlock_sock(sk);
+	local_bh_enable();
+	return rc;
+}
diff --git a/security/selinux/ss/avtab.c b/security/selinux/ss/avtab.c
index a1be97f..1215b8e 100644
--- a/security/selinux/ss/avtab.c
+++ b/security/selinux/ss/avtab.c
@@ -98,7 +98,7 @@
 avtab_insert_nonunique(struct avtab *h, struct avtab_key *key, struct avtab_datum *datum)
 {
 	int hvalue;
-	struct avtab_node *prev, *cur, *newnode;
+	struct avtab_node *prev, *cur;
 	u16 specified = key->specified & ~(AVTAB_ENABLED|AVTAB_ENABLED_OLD);
 
 	if (!h || !h->htable)
@@ -122,9 +122,7 @@
 		    key->target_class < cur->key.target_class)
 			break;
 	}
-	newnode = avtab_insert_node(h, hvalue, prev, cur, key, datum);
-
-	return newnode;
+	return avtab_insert_node(h, hvalue, prev, cur, key, datum);
 }
 
 struct avtab_datum *avtab_search(struct avtab *h, struct avtab_key *key)
@@ -231,7 +229,7 @@
 
 	for (i = 0; i < h->nslot; i++) {
 		cur = h->htable[i];
-		while (cur != NULL) {
+		while (cur) {
 			temp = cur;
 			cur = cur->next;
 			kmem_cache_free(avtab_node_cachep, temp);
diff --git a/security/selinux/ss/conditional.c b/security/selinux/ss/conditional.c
index fb4efe4..4a4e35c 100644
--- a/security/selinux/ss/conditional.c
+++ b/security/selinux/ss/conditional.c
@@ -29,7 +29,7 @@
 	int s[COND_EXPR_MAXDEPTH];
 	int sp = -1;
 
-	for (cur = expr; cur != NULL; cur = cur->next) {
+	for (cur = expr; cur; cur = cur->next) {
 		switch (cur->expr_type) {
 		case COND_BOOL:
 			if (sp == (COND_EXPR_MAXDEPTH - 1))
@@ -97,14 +97,14 @@
 		if (new_state == -1)
 			printk(KERN_ERR "SELinux: expression result was undefined - disabling all rules.\n");
 		/* turn the rules on or off */
-		for (cur = node->true_list; cur != NULL; cur = cur->next) {
+		for (cur = node->true_list; cur; cur = cur->next) {
 			if (new_state <= 0)
 				cur->node->key.specified &= ~AVTAB_ENABLED;
 			else
 				cur->node->key.specified |= AVTAB_ENABLED;
 		}
 
-		for (cur = node->false_list; cur != NULL; cur = cur->next) {
+		for (cur = node->false_list; cur; cur = cur->next) {
 			/* -1 or 1 */
 			if (new_state)
 				cur->node->key.specified &= ~AVTAB_ENABLED;
@@ -128,7 +128,7 @@
 static void cond_av_list_destroy(struct cond_av_list *list)
 {
 	struct cond_av_list *cur, *next;
-	for (cur = list; cur != NULL; cur = next) {
+	for (cur = list; cur; cur = next) {
 		next = cur->next;
 		/* the avtab_ptr_t node is destroy by the avtab */
 		kfree(cur);
@@ -139,7 +139,7 @@
 {
 	struct cond_expr *cur_expr, *next_expr;
 
-	for (cur_expr = node->expr; cur_expr != NULL; cur_expr = next_expr) {
+	for (cur_expr = node->expr; cur_expr; cur_expr = next_expr) {
 		next_expr = cur_expr->next;
 		kfree(cur_expr);
 	}
@@ -155,7 +155,7 @@
 	if (list == NULL)
 		return;
 
-	for (cur = list; cur != NULL; cur = next) {
+	for (cur = list; cur; cur = next) {
 		next = cur->next;
 		cond_node_destroy(cur);
 	}
@@ -239,7 +239,7 @@
 	rc = next_entry(key, fp, len);
 	if (rc < 0)
 		goto err;
-	key[len] = 0;
+	key[len] = '\0';
 	if (hashtab_insert(h, key, booldatum))
 		goto err;
 
@@ -291,7 +291,7 @@
 					goto err;
 				}
 				found = 0;
-				for (cur = other; cur != NULL; cur = cur->next) {
+				for (cur = other; cur; cur = cur->next) {
 					if (cur->node == node_ptr) {
 						found = 1;
 						break;
@@ -485,7 +485,7 @@
 	if (!ctab || !key || !avd)
 		return;
 
-	for (node = avtab_search_node(ctab, key); node != NULL;
+	for (node = avtab_search_node(ctab, key); node;
 				node = avtab_search_node_next(node, key->specified)) {
 		if ((u16)(AVTAB_ALLOWED|AVTAB_ENABLED) ==
 		    (node->key.specified & (AVTAB_ALLOWED|AVTAB_ENABLED)))
diff --git a/security/selinux/ss/conditional.h b/security/selinux/ss/conditional.h
index 65b9f83..53ddb01 100644
--- a/security/selinux/ss/conditional.h
+++ b/security/selinux/ss/conditional.h
@@ -28,7 +28,7 @@
 #define COND_XOR	5 /* bool ^ bool */
 #define COND_EQ		6 /* bool == bool */
 #define COND_NEQ	7 /* bool != bool */
-#define COND_LAST	8
+#define COND_LAST	COND_NEQ
 	__u32 expr_type;
 	__u32 bool;
 	struct cond_expr *next;
diff --git a/security/selinux/ss/ebitmap.c b/security/selinux/ss/ebitmap.c
index ddc2754..68c7348 100644
--- a/security/selinux/ss/ebitmap.c
+++ b/security/selinux/ss/ebitmap.c
@@ -109,7 +109,7 @@
 	*catmap = c_iter;
 	c_iter->startbit = e_iter->startbit & ~(NETLBL_CATMAP_SIZE - 1);
 
-	while (e_iter != NULL) {
+	while (e_iter) {
 		for (i = 0; i < EBITMAP_UNIT_NUMS; i++) {
 			unsigned int delta, e_startbit, c_endbit;
 
@@ -197,7 +197,7 @@
 			}
 		}
 		c_iter = c_iter->next;
-	} while (c_iter != NULL);
+	} while (c_iter);
 	if (e_iter != NULL)
 		ebmap->highbit = e_iter->startbit + EBITMAP_SIZE;
 	else
diff --git a/security/selinux/ss/hashtab.c b/security/selinux/ss/hashtab.c
index 2e7788e..933e735 100644
--- a/security/selinux/ss/hashtab.c
+++ b/security/selinux/ss/hashtab.c
@@ -81,7 +81,7 @@
 
 	hvalue = h->hash_value(h, key);
 	cur = h->htable[hvalue];
-	while (cur != NULL && h->keycmp(h, key, cur->key) > 0)
+	while (cur && h->keycmp(h, key, cur->key) > 0)
 		cur = cur->next;
 
 	if (cur == NULL || (h->keycmp(h, key, cur->key) != 0))
@@ -100,7 +100,7 @@
 
 	for (i = 0; i < h->size; i++) {
 		cur = h->htable[i];
-		while (cur != NULL) {
+		while (cur) {
 			temp = cur;
 			cur = cur->next;
 			kfree(temp);
@@ -127,7 +127,7 @@
 
 	for (i = 0; i < h->size; i++) {
 		cur = h->htable[i];
-		while (cur != NULL) {
+		while (cur) {
 			ret = apply(cur->key, cur->datum, args);
 			if (ret)
 				return ret;
diff --git a/security/selinux/ss/mls.c b/security/selinux/ss/mls.c
index 77d745d..b5407f1 100644
--- a/security/selinux/ss/mls.c
+++ b/security/selinux/ss/mls.c
@@ -283,8 +283,8 @@
 		p++;
 
 	delim = *p;
-	if (delim != 0)
-		*p++ = 0;
+	if (delim != '\0')
+		*p++ = '\0';
 
 	for (l = 0; l < 2; l++) {
 		levdatum = hashtab_search(pol->p_levels.table, scontextp);
@@ -302,14 +302,14 @@
 				while (*p && *p != ',' && *p != '-')
 					p++;
 				delim = *p;
-				if (delim != 0)
-					*p++ = 0;
+				if (delim != '\0')
+					*p++ = '\0';
 
 				/* Separate into range if exists */
 				rngptr = strchr(scontextp, '.');
 				if (rngptr != NULL) {
 					/* Remove '.' */
-					*rngptr++ = 0;
+					*rngptr++ = '\0';
 				}
 
 				catdatum = hashtab_search(pol->p_cats.table,
@@ -357,8 +357,8 @@
 				p++;
 
 			delim = *p;
-			if (delim != 0)
-				*p++ = 0;
+			if (delim != '\0')
+				*p++ = '\0';
 		} else
 			break;
 	}
diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c
index 2391761..72e4a54 100644
--- a/security/selinux/ss/policydb.c
+++ b/security/selinux/ss/policydb.c
@@ -30,6 +30,7 @@
 #include <linux/slab.h>
 #include <linux/string.h>
 #include <linux/errno.h>
+#include <linux/audit.h>
 #include "security.h"
 
 #include "policydb.h"
@@ -116,7 +117,12 @@
 		.version	= POLICYDB_VERSION_PERMISSIVE,
 		.sym_num	= SYM_NUM,
 		.ocon_num	= OCON_NUM,
-	}
+	},
+	{
+		.version	= POLICYDB_VERSION_BOUNDARY,
+		.sym_num	= SYM_NUM,
+		.ocon_num	= OCON_NUM,
+	},
 };
 
 static struct policydb_compat_info *policydb_lookup_compat(int version)
@@ -254,7 +260,9 @@
 
 	role = datum;
 	p = datap;
-	if (!role->value || role->value > p->p_roles.nprim)
+	if (!role->value
+	    || role->value > p->p_roles.nprim
+	    || role->bounds > p->p_roles.nprim)
 		return -EINVAL;
 	p->p_role_val_to_name[role->value - 1] = key;
 	p->role_val_to_struct[role->value - 1] = role;
@@ -270,9 +278,12 @@
 	p = datap;
 
 	if (typdatum->primary) {
-		if (!typdatum->value || typdatum->value > p->p_types.nprim)
+		if (!typdatum->value
+		    || typdatum->value > p->p_types.nprim
+		    || typdatum->bounds > p->p_types.nprim)
 			return -EINVAL;
 		p->p_type_val_to_name[typdatum->value - 1] = key;
+		p->type_val_to_struct[typdatum->value - 1] = typdatum;
 	}
 
 	return 0;
@@ -285,7 +296,9 @@
 
 	usrdatum = datum;
 	p = datap;
-	if (!usrdatum->value || usrdatum->value > p->p_users.nprim)
+	if (!usrdatum->value
+	    || usrdatum->value > p->p_users.nprim
+	    || usrdatum->bounds > p->p_users.nprim)
 		return -EINVAL;
 	p->p_user_val_to_name[usrdatum->value - 1] = key;
 	p->user_val_to_struct[usrdatum->value - 1] = usrdatum;
@@ -438,6 +451,14 @@
 		goto out;
 	}
 
+	p->type_val_to_struct =
+		kmalloc(p->p_types.nprim * sizeof(*(p->type_val_to_struct)),
+			GFP_KERNEL);
+	if (!p->type_val_to_struct) {
+		rc = -ENOMEM;
+		goto out;
+	}
+
 	if (cond_init_bool_indexes(p)) {
 		rc = -ENOMEM;
 		goto out;
@@ -625,6 +646,7 @@
 	kfree(p->class_val_to_struct);
 	kfree(p->role_val_to_struct);
 	kfree(p->user_val_to_struct);
+	kfree(p->type_val_to_struct);
 
 	avtab_destroy(&p->te_avtab);
 
@@ -932,7 +954,7 @@
 	rc = next_entry(key, fp, len);
 	if (rc < 0)
 		goto bad;
-	key[len] = 0;
+	key[len] = '\0';
 
 	rc = hashtab_insert(h, key, perdatum);
 	if (rc)
@@ -979,7 +1001,7 @@
 	rc = next_entry(key, fp, len);
 	if (rc < 0)
 		goto bad;
-	key[len] = 0;
+	key[len] = '\0';
 
 	for (i = 0; i < nel; i++) {
 		rc = perm_read(p, comdatum->permissions.table, fp);
@@ -1117,7 +1139,7 @@
 	rc = next_entry(key, fp, len);
 	if (rc < 0)
 		goto bad;
-	key[len] = 0;
+	key[len] = '\0';
 
 	if (len2) {
 		cladatum->comkey = kmalloc(len2 + 1, GFP_KERNEL);
@@ -1128,7 +1150,7 @@
 		rc = next_entry(cladatum->comkey, fp, len2);
 		if (rc < 0)
 			goto bad;
-		cladatum->comkey[len2] = 0;
+		cladatum->comkey[len2] = '\0';
 
 		cladatum->comdatum = hashtab_search(p->p_commons.table,
 						    cladatum->comkey);
@@ -1176,8 +1198,8 @@
 {
 	char *key = NULL;
 	struct role_datum *role;
-	int rc;
-	__le32 buf[2];
+	int rc, to_read = 2;
+	__le32 buf[3];
 	u32 len;
 
 	role = kzalloc(sizeof(*role), GFP_KERNEL);
@@ -1186,12 +1208,17 @@
 		goto out;
 	}
 
-	rc = next_entry(buf, fp, sizeof buf);
+	if (p->policyvers >= POLICYDB_VERSION_BOUNDARY)
+		to_read = 3;
+
+	rc = next_entry(buf, fp, sizeof(buf[0]) * to_read);
 	if (rc < 0)
 		goto bad;
 
 	len = le32_to_cpu(buf[0]);
 	role->value = le32_to_cpu(buf[1]);
+	if (p->policyvers >= POLICYDB_VERSION_BOUNDARY)
+		role->bounds = le32_to_cpu(buf[2]);
 
 	key = kmalloc(len + 1, GFP_KERNEL);
 	if (!key) {
@@ -1201,7 +1228,7 @@
 	rc = next_entry(key, fp, len);
 	if (rc < 0)
 		goto bad;
-	key[len] = 0;
+	key[len] = '\0';
 
 	rc = ebitmap_read(&role->dominates, fp);
 	if (rc)
@@ -1236,8 +1263,8 @@
 {
 	char *key = NULL;
 	struct type_datum *typdatum;
-	int rc;
-	__le32 buf[3];
+	int rc, to_read = 3;
+	__le32 buf[4];
 	u32 len;
 
 	typdatum = kzalloc(sizeof(*typdatum), GFP_KERNEL);
@@ -1246,13 +1273,27 @@
 		return rc;
 	}
 
-	rc = next_entry(buf, fp, sizeof buf);
+	if (p->policyvers >= POLICYDB_VERSION_BOUNDARY)
+		to_read = 4;
+
+	rc = next_entry(buf, fp, sizeof(buf[0]) * to_read);
 	if (rc < 0)
 		goto bad;
 
 	len = le32_to_cpu(buf[0]);
 	typdatum->value = le32_to_cpu(buf[1]);
-	typdatum->primary = le32_to_cpu(buf[2]);
+	if (p->policyvers >= POLICYDB_VERSION_BOUNDARY) {
+		u32 prop = le32_to_cpu(buf[2]);
+
+		if (prop & TYPEDATUM_PROPERTY_PRIMARY)
+			typdatum->primary = 1;
+		if (prop & TYPEDATUM_PROPERTY_ATTRIBUTE)
+			typdatum->attribute = 1;
+
+		typdatum->bounds = le32_to_cpu(buf[3]);
+	} else {
+		typdatum->primary = le32_to_cpu(buf[2]);
+	}
 
 	key = kmalloc(len + 1, GFP_KERNEL);
 	if (!key) {
@@ -1262,7 +1303,7 @@
 	rc = next_entry(key, fp, len);
 	if (rc < 0)
 		goto bad;
-	key[len] = 0;
+	key[len] = '\0';
 
 	rc = hashtab_insert(h, key, typdatum);
 	if (rc)
@@ -1309,8 +1350,8 @@
 {
 	char *key = NULL;
 	struct user_datum *usrdatum;
-	int rc;
-	__le32 buf[2];
+	int rc, to_read = 2;
+	__le32 buf[3];
 	u32 len;
 
 	usrdatum = kzalloc(sizeof(*usrdatum), GFP_KERNEL);
@@ -1319,12 +1360,17 @@
 		goto out;
 	}
 
-	rc = next_entry(buf, fp, sizeof buf);
+	if (p->policyvers >= POLICYDB_VERSION_BOUNDARY)
+		to_read = 3;
+
+	rc = next_entry(buf, fp, sizeof(buf[0]) * to_read);
 	if (rc < 0)
 		goto bad;
 
 	len = le32_to_cpu(buf[0]);
 	usrdatum->value = le32_to_cpu(buf[1]);
+	if (p->policyvers >= POLICYDB_VERSION_BOUNDARY)
+		usrdatum->bounds = le32_to_cpu(buf[2]);
 
 	key = kmalloc(len + 1, GFP_KERNEL);
 	if (!key) {
@@ -1334,7 +1380,7 @@
 	rc = next_entry(key, fp, len);
 	if (rc < 0)
 		goto bad;
-	key[len] = 0;
+	key[len] = '\0';
 
 	rc = ebitmap_read(&usrdatum->roles, fp);
 	if (rc)
@@ -1388,7 +1434,7 @@
 	rc = next_entry(key, fp, len);
 	if (rc < 0)
 		goto bad;
-	key[len] = 0;
+	key[len] = '\0';
 
 	levdatum->level = kmalloc(sizeof(struct mls_level), GFP_ATOMIC);
 	if (!levdatum->level) {
@@ -1440,7 +1486,7 @@
 	rc = next_entry(key, fp, len);
 	if (rc < 0)
 		goto bad;
-	key[len] = 0;
+	key[len] = '\0';
 
 	rc = hashtab_insert(h, key, catdatum);
 	if (rc)
@@ -1465,6 +1511,133 @@
 	cat_read,
 };
 
+static int user_bounds_sanity_check(void *key, void *datum, void *datap)
+{
+	struct user_datum *upper, *user;
+	struct policydb *p = datap;
+	int depth = 0;
+
+	upper = user = datum;
+	while (upper->bounds) {
+		struct ebitmap_node *node;
+		unsigned long bit;
+
+		if (++depth == POLICYDB_BOUNDS_MAXDEPTH) {
+			printk(KERN_ERR "SELinux: user %s: "
+			       "too deep or looped boundary",
+			       (char *) key);
+			return -EINVAL;
+		}
+
+		upper = p->user_val_to_struct[upper->bounds - 1];
+		ebitmap_for_each_positive_bit(&user->roles, node, bit) {
+			if (ebitmap_get_bit(&upper->roles, bit))
+				continue;
+
+			printk(KERN_ERR
+			       "SELinux: boundary violated policy: "
+			       "user=%s role=%s bounds=%s\n",
+			       p->p_user_val_to_name[user->value - 1],
+			       p->p_role_val_to_name[bit],
+			       p->p_user_val_to_name[upper->value - 1]);
+
+			return -EINVAL;
+		}
+	}
+
+	return 0;
+}
+
+static int role_bounds_sanity_check(void *key, void *datum, void *datap)
+{
+	struct role_datum *upper, *role;
+	struct policydb *p = datap;
+	int depth = 0;
+
+	upper = role = datum;
+	while (upper->bounds) {
+		struct ebitmap_node *node;
+		unsigned long bit;
+
+		if (++depth == POLICYDB_BOUNDS_MAXDEPTH) {
+			printk(KERN_ERR "SELinux: role %s: "
+			       "too deep or looped bounds\n",
+			       (char *) key);
+			return -EINVAL;
+		}
+
+		upper = p->role_val_to_struct[upper->bounds - 1];
+		ebitmap_for_each_positive_bit(&role->types, node, bit) {
+			if (ebitmap_get_bit(&upper->types, bit))
+				continue;
+
+			printk(KERN_ERR
+			       "SELinux: boundary violated policy: "
+			       "role=%s type=%s bounds=%s\n",
+			       p->p_role_val_to_name[role->value - 1],
+			       p->p_type_val_to_name[bit],
+			       p->p_role_val_to_name[upper->value - 1]);
+
+			return -EINVAL;
+		}
+	}
+
+	return 0;
+}
+
+static int type_bounds_sanity_check(void *key, void *datum, void *datap)
+{
+	struct type_datum *upper, *type;
+	struct policydb *p = datap;
+	int depth = 0;
+
+	upper = type = datum;
+	while (upper->bounds) {
+		if (++depth == POLICYDB_BOUNDS_MAXDEPTH) {
+			printk(KERN_ERR "SELinux: type %s: "
+			       "too deep or looped boundary\n",
+			       (char *) key);
+			return -EINVAL;
+		}
+
+		upper = p->type_val_to_struct[upper->bounds - 1];
+		if (upper->attribute) {
+			printk(KERN_ERR "SELinux: type %s: "
+			       "bounded by attribute %s",
+			       (char *) key,
+			       p->p_type_val_to_name[upper->value - 1]);
+			return -EINVAL;
+		}
+	}
+
+	return 0;
+}
+
+static int policydb_bounds_sanity_check(struct policydb *p)
+{
+	int rc;
+
+	if (p->policyvers < POLICYDB_VERSION_BOUNDARY)
+		return 0;
+
+	rc = hashtab_map(p->p_users.table,
+			 user_bounds_sanity_check, p);
+	if (rc)
+		return rc;
+
+	rc = hashtab_map(p->p_roles.table,
+			 role_bounds_sanity_check, p);
+	if (rc)
+		return rc;
+
+	rc = hashtab_map(p->p_types.table,
+			 type_bounds_sanity_check, p);
+	if (rc)
+		return rc;
+
+	return 0;
+}
+
 extern int ss_initialized;
 
 /*
@@ -1523,7 +1696,7 @@
 		kfree(policydb_str);
 		goto bad;
 	}
-	policydb_str[len] = 0;
+	policydb_str[len] = '\0';
 	if (strcmp(policydb_str, POLICYDB_STRING)) {
 		printk(KERN_ERR "SELinux:  policydb string %s does not match "
 		       "my string %s\n", policydb_str, POLICYDB_STRING);
@@ -1961,6 +2134,10 @@
 				goto bad;
 	}
 
+	rc = policydb_bounds_sanity_check(p);
+	if (rc)
+		goto bad;
+
 	rc = 0;
 out:
 	return rc;
diff --git a/security/selinux/ss/policydb.h b/security/selinux/ss/policydb.h
index 4253370..55152d4 100644
--- a/security/selinux/ss/policydb.h
+++ b/security/selinux/ss/policydb.h
@@ -61,6 +61,7 @@
 /* Role attributes */
 struct role_datum {
 	u32 value;			/* internal role value */
+	u32 bounds;			/* boundary of role */
 	struct ebitmap dominates;	/* set of roles dominated by this role */
 	struct ebitmap types;		/* set of authorized types for role */
 };
@@ -81,12 +82,15 @@
 /* Type attributes */
 struct type_datum {
 	u32 value;		/* internal type value */
+	u32 bounds;		/* boundary of type */
 	unsigned char primary;	/* primary name? */
+	unsigned char attribute;/* attribute ?*/
 };
 
 /* User attributes */
 struct user_datum {
 	u32 value;			/* internal user value */
+	u32 bounds;			/* bounds of user */
 	struct ebitmap roles;		/* set of authorized roles for user */
 	struct mls_range range;		/* MLS range (min - max) for user */
 	struct mls_level dfltlevel;	/* default login MLS level for user */
@@ -209,6 +213,7 @@
 	struct class_datum **class_val_to_struct;
 	struct role_datum **role_val_to_struct;
 	struct user_datum **user_val_to_struct;
+	struct type_datum **type_val_to_struct;
 
 	/* type enforcement access vectors and transitions */
 	struct avtab te_avtab;
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
index d11a815..343c8ab 100644
--- a/security/selinux/ss/services.c
+++ b/security/selinux/ss/services.c
@@ -88,6 +88,11 @@
 static int context_struct_to_string(struct context *context, char **scontext,
 				    u32 *scontext_len);
 
+static int context_struct_compute_av(struct context *scontext,
+				     struct context *tcontext,
+				     u16 tclass,
+				     u32 requested,
+				     struct av_decision *avd);
 /*
  * Return the boolean value of a constraint expression
  * when it is applied to the specified source and target
@@ -274,6 +279,100 @@
 }
 
 /*
+ * security_boundary_permission - drops violated permissions
+ * on boundary constraint.
+ */
+static void type_attribute_bounds_av(struct context *scontext,
+				     struct context *tcontext,
+				     u16 tclass,
+				     u32 requested,
+				     struct av_decision *avd)
+{
+	struct context lo_scontext;
+	struct context lo_tcontext;
+	struct av_decision lo_avd;
+	struct type_datum *source
+		= policydb.type_val_to_struct[scontext->type - 1];
+	struct type_datum *target
+		= policydb.type_val_to_struct[tcontext->type - 1];
+	u32 masked = 0;
+
+	if (source->bounds) {
+		memset(&lo_avd, 0, sizeof(lo_avd));
+
+		memcpy(&lo_scontext, scontext, sizeof(lo_scontext));
+		lo_scontext.type = source->bounds;
+
+		context_struct_compute_av(&lo_scontext,
+					  tcontext,
+					  tclass,
+					  requested,
+					  &lo_avd);
+		if ((lo_avd.allowed & avd->allowed) == avd->allowed)
+			return;		/* no masked permission */
+		masked = ~lo_avd.allowed & avd->allowed;
+	}
+
+	if (target->bounds) {
+		memset(&lo_avd, 0, sizeof(lo_avd));
+
+		memcpy(&lo_tcontext, tcontext, sizeof(lo_tcontext));
+		lo_tcontext.type = target->bounds;
+
+		context_struct_compute_av(scontext,
+					  &lo_tcontext,
+					  tclass,
+					  requested,
+					  &lo_avd);
+		if ((lo_avd.allowed & avd->allowed) == avd->allowed)
+			return;		/* no masked permission */
+		masked = ~lo_avd.allowed & avd->allowed;
+	}
+
+	if (source->bounds && target->bounds) {
+		memset(&lo_avd, 0, sizeof(lo_avd));
+		/*
+		 * lo_scontext and lo_tcontext are already
+		 * set up.
+		 */
+
+		context_struct_compute_av(&lo_scontext,
+					  &lo_tcontext,
+					  tclass,
+					  requested,
+					  &lo_avd);
+		if ((lo_avd.allowed & avd->allowed) == avd->allowed)
+			return;		/* no masked permission */
+		masked = ~lo_avd.allowed & avd->allowed;
+	}
+
+	if (masked) {
+		struct audit_buffer *ab;
+		char *stype_name
+			= policydb.p_type_val_to_name[source->value - 1];
+		char *ttype_name
+			= policydb.p_type_val_to_name[target->value - 1];
+		char *tclass_name
+			= policydb.p_class_val_to_name[tclass - 1];
+
+		/* mask violated permissions */
+		avd->allowed &= ~masked;
+
+		/* notice to userspace via audit message */
+		ab = audit_log_start(current->audit_context,
+				     GFP_ATOMIC, AUDIT_SELINUX_ERR);
+		if (!ab)
+			return;
+
+		audit_log_format(ab, "av boundary violation: "
+				 "source=%s target=%s tclass=%s",
+				 stype_name, ttype_name, tclass_name);
+		avc_dump_av(ab, tclass, masked);
+		audit_log_end(ab);
+	}
+}
+
+/*
  * Compute access vectors based on a context structure pair for
  * the permissions in a particular class.
  */
@@ -356,7 +455,7 @@
 			avkey.source_type = i + 1;
 			avkey.target_type = j + 1;
 			for (node = avtab_search_node(&policydb.te_avtab, &avkey);
-			     node != NULL;
+			     node;
 			     node = avtab_search_node_next(node, avkey.specified)) {
 				if (node->key.specified == AVTAB_ALLOWED)
 					avd->allowed |= node->datum.data;
@@ -404,6 +503,14 @@
 							PROCESS__DYNTRANSITION);
 	}
 
+	/*
+	 * If the given source and target types have boundary
+	 * constraint, lazy checks have to mask any violated
+	 * permission and notice it to userspace via audit.
+	 */
+	type_attribute_bounds_av(scontext, tcontext,
+				 tclass, requested, avd);
+
 	return 0;
 
 inval_class:
@@ -549,6 +656,69 @@
 	return rc;
 }
 
+/*
+ * security_bounded_transition - check whether the given
+ * transition is directed to bounded, or not.
+ * It returns 0, if @newsid is bounded by @oldsid.
+ * Otherwise, it returns error code.
+ *
+ * @oldsid : current security identifier
+ * @newsid : destinated security identifier
+ */
+int security_bounded_transition(u32 old_sid, u32 new_sid)
+{
+	struct context *old_context, *new_context;
+	struct type_datum *type;
+	int index;
+	int rc = -EINVAL;
+
+	read_lock(&policy_rwlock);
+
+	old_context = sidtab_search(&sidtab, old_sid);
+	if (!old_context) {
+		printk(KERN_ERR "SELinux: %s: unrecognized SID %u\n",
+		       __func__, old_sid);
+		goto out;
+	}
+
+	new_context = sidtab_search(&sidtab, new_sid);
+	if (!new_context) {
+		printk(KERN_ERR "SELinux: %s: unrecognized SID %u\n",
+		       __func__, new_sid);
+		goto out;
+	}
+
+	/* type/domain unchaned */
+	if (old_context->type == new_context->type) {
+		rc = 0;
+		goto out;
+	}
+
+	index = new_context->type;
+	while (true) {
+		type = policydb.type_val_to_struct[index - 1];
+		BUG_ON(!type);
+
+		/* not bounded anymore */
+		if (!type->bounds) {
+			rc = -EPERM;
+			break;
+		}
+
+		/* @newsid is bounded by @oldsid */
+		if (type->bounds == old_context->type) {
+			rc = 0;
+			break;
+		}
+		index = type->bounds;
+	}
+out:
+	read_unlock(&policy_rwlock);
+
+	return rc;
+}
+
+
 /**
  * security_compute_av - Compute access vector decisions.
  * @ssid: source security identifier
@@ -794,7 +964,7 @@
 	*p++ = 0;
 
 	typdatum = hashtab_search(pol->p_types.table, scontextp);
-	if (!typdatum)
+	if (!typdatum || typdatum->attribute)
 		goto out;
 
 	ctx->type = typdatum->value;
@@ -1037,7 +1207,7 @@
 	/* If no permanent rule, also check for enabled conditional rules */
 	if (!avdatum) {
 		node = avtab_search_node(&policydb.te_cond_avtab, &avkey);
-		for (; node != NULL; node = avtab_search_node_next(node, specified)) {
+		for (; node; node = avtab_search_node_next(node, specified)) {
 			if (node->key.specified & AVTAB_ENABLED) {
 				avdatum = &node->datum;
 				break;
@@ -2050,7 +2220,7 @@
 			policydb.bool_val_to_struct[i]->state = 0;
 	}
 
-	for (cur = policydb.cond_list; cur != NULL; cur = cur->next) {
+	for (cur = policydb.cond_list; cur; cur = cur->next) {
 		rc = evaluate_cond_node(&policydb, cur);
 		if (rc)
 			goto out;
@@ -2102,7 +2272,7 @@
 		if (booldatum)
 			booldatum->state = bvalues[i];
 	}
-	for (cur = p->cond_list; cur != NULL; cur = cur->next) {
+	for (cur = p->cond_list; cur; cur = cur->next) {
 		rc = evaluate_cond_node(p, cur);
 		if (rc)
 			goto out;
@@ -2737,6 +2907,7 @@
 		if (ctx == NULL)
 			goto netlbl_secattr_to_sid_return;
 
+		context_init(&ctx_new);
 		ctx_new.user = ctx->user;
 		ctx_new.role = ctx->role;
 		ctx_new.type = ctx->type;
@@ -2745,13 +2916,9 @@
 			if (ebitmap_netlbl_import(&ctx_new.range.level[0].cat,
 						  secattr->attr.mls.cat) != 0)
 				goto netlbl_secattr_to_sid_return;
-			ctx_new.range.level[1].cat.highbit =
-				ctx_new.range.level[0].cat.highbit;
-			ctx_new.range.level[1].cat.node =
-				ctx_new.range.level[0].cat.node;
-		} else {
-			ebitmap_init(&ctx_new.range.level[0].cat);
-			ebitmap_init(&ctx_new.range.level[1].cat);
+			memcpy(&ctx_new.range.level[1].cat,
+			       &ctx_new.range.level[0].cat,
+			       sizeof(ctx_new.range.level[0].cat));
 		}
 		if (mls_context_isvalid(&policydb, &ctx_new) != 1)
 			goto netlbl_secattr_to_sid_return_cleanup;
@@ -2788,7 +2955,7 @@
  */
 int security_netlbl_sid_to_secattr(u32 sid, struct netlbl_lsm_secattr *secattr)
 {
-	int rc = -ENOENT;
+	int rc;
 	struct context *ctx;
 
 	if (!ss_initialized)
@@ -2796,11 +2963,18 @@
 
 	read_lock(&policy_rwlock);
 	ctx = sidtab_search(&sidtab, sid);
-	if (ctx == NULL)
+	if (ctx == NULL) {
+		rc = -ENOENT;
 		goto netlbl_sid_to_secattr_failure;
+	}
 	secattr->domain = kstrdup(policydb.p_type_val_to_name[ctx->type - 1],
 				  GFP_ATOMIC);
-	secattr->flags |= NETLBL_SECATTR_DOMAIN_CPY;
+	if (secattr->domain == NULL) {
+		rc = -ENOMEM;
+		goto netlbl_sid_to_secattr_failure;
+	}
+	secattr->attr.secid = sid;
+	secattr->flags |= NETLBL_SECATTR_DOMAIN_CPY | NETLBL_SECATTR_SECID;
 	mls_export_netlbl_lvl(ctx, secattr);
 	rc = mls_export_netlbl_cat(ctx, secattr);
 	if (rc != 0)
diff --git a/security/selinux/ss/sidtab.c b/security/selinux/ss/sidtab.c
index a81ded1..e817989 100644
--- a/security/selinux/ss/sidtab.c
+++ b/security/selinux/ss/sidtab.c
@@ -43,7 +43,7 @@
 	hvalue = SIDTAB_HASH(sid);
 	prev = NULL;
 	cur = s->htable[hvalue];
-	while (cur != NULL && sid > cur->sid) {
+	while (cur && sid > cur->sid) {
 		prev = cur;
 		cur = cur->next;
 	}
@@ -92,7 +92,7 @@
 
 	hvalue = SIDTAB_HASH(sid);
 	cur = s->htable[hvalue];
-	while (cur != NULL && sid > cur->sid)
+	while (cur && sid > cur->sid)
 		cur = cur->next;
 
 	if (force && cur && sid == cur->sid && cur->context.len)
@@ -103,7 +103,7 @@
 		sid = SECINITSID_UNLABELED;
 		hvalue = SIDTAB_HASH(sid);
 		cur = s->htable[hvalue];
-		while (cur != NULL && sid > cur->sid)
+		while (cur && sid > cur->sid)
 			cur = cur->next;
 		if (!cur || sid != cur->sid)
 			return NULL;
@@ -136,7 +136,7 @@
 
 	for (i = 0; i < SIDTAB_SIZE; i++) {
 		cur = s->htable[i];
-		while (cur != NULL) {
+		while (cur) {
 			rc = apply(cur->sid, &cur->context, args);
 			if (rc)
 				goto out;
@@ -155,7 +155,7 @@
 
 	for (i = 0; i < SIDTAB_SIZE; i++) {
 		cur = s->htable[i];
-		while (cur != NULL) {
+		while (cur) {
 			if (context_cmp(&cur->context, context))
 				return cur->sid;
 			cur = cur->next;
@@ -242,7 +242,7 @@
 
 	for (i = 0; i < SIDTAB_SIZE; i++) {
 		cur = s->htable[i];
-		while (cur != NULL) {
+		while (cur) {
 			temp = cur;
 			cur = cur->next;
 			context_destroy(&temp->context);
diff --git a/security/smack/smack.h b/security/smack/smack.h
index 4a4477f..31dce55 100644
--- a/security/smack/smack.h
+++ b/security/smack/smack.h
@@ -178,6 +178,7 @@
 extern int smack_cipso_direct;
 extern int smack_net_nltype;
 extern char *smack_net_ambient;
+extern char *smack_onlycap;
 
 extern struct smack_known *smack_known;
 extern struct smack_known smack_known_floor;
diff --git a/security/smack/smack_access.c b/security/smack/smack_access.c
index f6b5f6e..79ff21e 100644
--- a/security/smack/smack_access.c
+++ b/security/smack/smack_access.c
@@ -157,7 +157,7 @@
  *
  * This function checks the current subject label/object label pair
  * in the access rule list and returns 0 if the access is permitted,
- * non zero otherwise. It allows that current my have the capability
+ * non zero otherwise. It allows that current may have the capability
  * to override the rules.
  */
 int smk_curacc(char *obj_label, u32 mode)
@@ -168,6 +168,14 @@
 	if (rc == 0)
 		return 0;
 
+	/*
+	 * Return if a specific label has been designated as the
+	 * only one that gets privilege and current does not
+	 * have that label.
+	 */
+	if (smack_onlycap != NULL && smack_onlycap != current->security)
+		return rc;
+
 	if (capable(CAP_MAC_OVERRIDE))
 		return 0;
 
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index 87d7541..6e2dc0b 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -2179,7 +2179,10 @@
 	 * This is the simplist possible security model
 	 * for networking.
 	 */
-	return smk_access(smack, ssp->smk_in, MAY_WRITE);
+	rc = smk_access(smack, ssp->smk_in, MAY_WRITE);
+	if (rc != 0)
+		netlbl_skbuff_err(skb, rc, 0);
+	return rc;
 }
 
 /**
diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c
index 271a835..c21d8c8 100644
--- a/security/smack/smackfs.c
+++ b/security/smack/smackfs.c
@@ -39,6 +39,7 @@
 	SMK_DIRECT	= 6,	/* CIPSO level indicating direct label */
 	SMK_AMBIENT	= 7,	/* internet ambient label */
 	SMK_NLTYPE	= 8,	/* label scheme to use by default */
+	SMK_ONLYCAP	= 9,	/* the only "capable" label */
 };
 
 /*
@@ -68,6 +69,16 @@
  */
 int smack_cipso_direct = SMACK_CIPSO_DIRECT_DEFAULT;
 
+/*
+ * Unless a process is running with this label even
+ * having CAP_MAC_OVERRIDE isn't enough to grant
+ * privilege to violate MAC policy. If no label is
+ * designated (the NULL case) capabilities apply to
+ * everyone. It is expected that the hat (^) label
+ * will be used if any label is used.
+ */
+char *smack_onlycap;
+
 static int smk_cipso_doi_value = SMACK_CIPSO_DOI_DEFAULT;
 struct smk_list_entry *smack_list;
 
@@ -343,9 +354,11 @@
 		doip->tags[rc] = CIPSO_V4_TAG_INVALID;
 
 	rc = netlbl_cfg_cipsov4_add_map(doip, NULL, &audit_info);
-	if (rc != 0)
+	if (rc != 0) {
 		printk(KERN_WARNING "%s:%d add rc = %d\n",
 		       __func__, __LINE__, rc);
+		kfree(doip);
+	}
 }
 
 /**
@@ -787,6 +800,85 @@
 	.write		= smk_write_ambient,
 };
 
+/**
+ * smk_read_onlycap - read() for /smack/onlycap
+ * @filp: file pointer, not actually used
+ * @buf: where to put the result
+ * @cn: maximum to send along
+ * @ppos: where to start
+ *
+ * Returns number of bytes read or error code, as appropriate
+ */
+static ssize_t smk_read_onlycap(struct file *filp, char __user *buf,
+				size_t cn, loff_t *ppos)
+{
+	char *smack = "";
+	ssize_t rc = -EINVAL;
+	int asize;
+
+	if (*ppos != 0)
+		return 0;
+
+	if (smack_onlycap != NULL)
+		smack = smack_onlycap;
+
+	asize = strlen(smack) + 1;
+
+	if (cn >= asize)
+		rc = simple_read_from_buffer(buf, cn, ppos, smack, asize);
+
+	return rc;
+}
+
+/**
+ * smk_write_onlycap - write() for /smack/onlycap
+ * @filp: file pointer, not actually used
+ * @buf: where to get the data from
+ * @count: bytes sent
+ * @ppos: where to start
+ *
+ * Returns number of bytes written or error code, as appropriate
+ */
+static ssize_t smk_write_onlycap(struct file *file, const char __user *buf,
+				 size_t count, loff_t *ppos)
+{
+	char in[SMK_LABELLEN];
+	char *sp = current->security;
+
+	if (!capable(CAP_MAC_ADMIN))
+		return -EPERM;
+
+	/*
+	 * This can be done using smk_access() but is done
+	 * explicitly for clarity. The smk_access() implementation
+	 * would use smk_access(smack_onlycap, MAY_WRITE)
+	 */
+	if (smack_onlycap != NULL && smack_onlycap != sp)
+		return -EPERM;
+
+	if (count >= SMK_LABELLEN)
+		return -EINVAL;
+
+	if (copy_from_user(in, buf, count) != 0)
+		return -EFAULT;
+
+	/*
+	 * Should the null string be passed in unset the onlycap value.
+	 * This seems like something to be careful with as usually
+	 * smk_import only expects to return NULL for errors. It
+	 * is usually the case that a nullstring or "\n" would be
+	 * bad to pass to smk_import but in fact this is useful here.
+	 */
+	smack_onlycap = smk_import(in, count);
+
+	return count;
+}
+
+static const struct file_operations smk_onlycap_ops = {
+	.read		= smk_read_onlycap,
+	.write		= smk_write_onlycap,
+};
+
 struct option_names {
 	int	o_number;
 	char	*o_name;
@@ -919,6 +1011,8 @@
 			{"ambient", &smk_ambient_ops, S_IRUGO|S_IWUSR},
 		[SMK_NLTYPE]	=
 			{"nltype", &smk_nltype_ops, S_IRUGO|S_IWUSR},
+		[SMK_ONLYCAP]	=
+			{"onlycap", &smk_onlycap_ops, S_IRUGO|S_IWUSR},
 		/* last one */ {""}
 	};
 
diff --git a/sound/Kconfig b/sound/Kconfig
index 8ebf512..200aca1 100644
--- a/sound/Kconfig
+++ b/sound/Kconfig
@@ -28,6 +28,10 @@
 
 if SOUND
 
+config SOUND_OSS_CORE
+	bool
+	default n
+
 source "sound/oss/dmasound/Kconfig"
 
 if !M68K
@@ -80,6 +84,7 @@
 
 menuconfig SOUND_PRIME
 	tristate "Open Sound System (DEPRECATED)"
+	select SOUND_OSS_CORE
 	help
 	  Say 'Y' or 'M' to enable Open Sound System drivers.
 
diff --git a/sound/aoa/codecs/snd-aoa-codec-tas.c b/sound/aoa/codecs/snd-aoa-codec-tas.c
index 7a16a33..6c515b2 100644
--- a/sound/aoa/codecs/snd-aoa-codec-tas.c
+++ b/sound/aoa/codecs/snd-aoa-codec-tas.c
@@ -654,15 +654,13 @@
 static struct transfer_info tas_transfers[] = {
 	{
 		/* input */
-		.formats = SNDRV_PCM_FMTBIT_S16_BE | SNDRV_PCM_FMTBIT_S16_BE |
-			   SNDRV_PCM_FMTBIT_S24_BE | SNDRV_PCM_FMTBIT_S24_BE,
+		.formats = SNDRV_PCM_FMTBIT_S16_BE | SNDRV_PCM_FMTBIT_S24_BE,
 		.rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000,
 		.transfer_in = 1,
 	},
 	{
 		/* output */
-		.formats = SNDRV_PCM_FMTBIT_S16_BE | SNDRV_PCM_FMTBIT_S16_BE |
-			   SNDRV_PCM_FMTBIT_S24_BE | SNDRV_PCM_FMTBIT_S24_BE,
+		.formats = SNDRV_PCM_FMTBIT_S16_BE | SNDRV_PCM_FMTBIT_S24_BE,
 		.rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000,
 		.transfer_in = 0,
 	},
diff --git a/sound/arm/Kconfig b/sound/arm/Kconfig
index 351e19e..f8e6de4 100644
--- a/sound/arm/Kconfig
+++ b/sound/arm/Kconfig
@@ -32,11 +32,20 @@
 	tristate
 	select SND_PCM
 
+config SND_PXA2XX_LIB
+	tristate
+	select SND_AC97_CODEC if SND_PXA2XX_LIB_AC97
+
+config SND_PXA2XX_LIB_AC97
+	bool
+
 config SND_PXA2XX_AC97
 	tristate "AC97 driver for the Intel PXA2xx chip"
 	depends on ARCH_PXA
 	select SND_PXA2XX_PCM
 	select SND_AC97_CODEC
+	select SND_PXA2XX_LIB
+	select SND_PXA2XX_LIB_AC97
 	help
 	  Say Y or M if you want to support any AC97 codec attached to
 	  the PXA2xx AC97 interface.
diff --git a/sound/arm/Makefile b/sound/arm/Makefile
index 4ef6dd0..2054de1 100644
--- a/sound/arm/Makefile
+++ b/sound/arm/Makefile
@@ -11,5 +11,9 @@
 obj-$(CONFIG_SND_PXA2XX_PCM)	+= snd-pxa2xx-pcm.o
 snd-pxa2xx-pcm-objs		:= pxa2xx-pcm.o
 
+obj-$(CONFIG_SND_PXA2XX_LIB)	+= snd-pxa2xx-lib.o
+snd-pxa2xx-lib-y		:= pxa2xx-pcm-lib.o
+snd-pxa2xx-lib-$(CONFIG_SND_PXA2XX_LIB_AC97)	+= pxa2xx-ac97-lib.o
+
 obj-$(CONFIG_SND_PXA2XX_AC97)	+= snd-pxa2xx-ac97.o
 snd-pxa2xx-ac97-objs		:= pxa2xx-ac97.o
diff --git a/sound/arm/aaci.c b/sound/arm/aaci.c
index b0a4744..89096e8 100644
--- a/sound/arm/aaci.c
+++ b/sound/arm/aaci.c
@@ -999,7 +999,7 @@
 	card = snd_card_new(SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
 			    THIS_MODULE, sizeof(struct aaci));
 	if (card == NULL)
-		return ERR_PTR(-ENOMEM);
+		return NULL;
 
 	card->private_free = aaci_free_card;
 
@@ -1083,8 +1083,8 @@
 		return ret;
 
 	aaci = aaci_init_card(dev);
-	if (IS_ERR(aaci)) {
-		ret = PTR_ERR(aaci);
+	if (!aaci) {
+		ret = -ENOMEM;
 		goto out;
 	}
 
diff --git a/sound/arm/pxa2xx-ac97-lib.c b/sound/arm/pxa2xx-ac97-lib.c
new file mode 100644
index 0000000..99026df
--- /dev/null
+++ b/sound/arm/pxa2xx-ac97-lib.c
@@ -0,0 +1,384 @@
+/*
+ * Based on sound/arm/pxa2xx-ac97.c and sound/soc/pxa/pxa2xx-ac97.c
+ * which contain:
+ *
+ * Author:	Nicolas Pitre
+ * Created:	Dec 02, 2004
+ * Copyright:	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 version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+
+#include <sound/ac97_codec.h>
+#include <sound/pxa2xx-lib.h>
+
+#include <asm/irq.h>
+#include <mach/hardware.h>
+#include <mach/pxa-regs.h>
+#include <mach/pxa2xx-gpio.h>
+#include <mach/audio.h>
+
+static DEFINE_MUTEX(car_mutex);
+static DECLARE_WAIT_QUEUE_HEAD(gsr_wq);
+static volatile long gsr_bits;
+static struct clk *ac97_clk;
+static struct clk *ac97conf_clk;
+
+/*
+ * Beware PXA27x bugs:
+ *
+ *   o Slot 12 read from modem space will hang controller.
+ *   o CDONE, SDONE interrupt fails after any slot 12 IO.
+ *
+ * We therefore have an hybrid approach for waiting on SDONE (interrupt or
+ * 1 jiffy timeout if interrupt never comes).
+ */
+
+unsigned short pxa2xx_ac97_read(struct snd_ac97 *ac97, unsigned short reg)
+{
+	unsigned short val = -1;
+	volatile u32 *reg_addr;
+
+	mutex_lock(&car_mutex);
+
+	/* set up primary or secondary codec space */
+	if ((cpu_is_pxa21x() || cpu_is_pxa25x()) && reg == AC97_GPIO_STATUS)
+		reg_addr = ac97->num ? &SMC_REG_BASE : &PMC_REG_BASE;
+	else
+		reg_addr = ac97->num ? &SAC_REG_BASE : &PAC_REG_BASE;
+	reg_addr += (reg >> 1);
+
+	/* start read access across the ac97 link */
+	GSR = GSR_CDONE | GSR_SDONE;
+	gsr_bits = 0;
+	val = *reg_addr;
+	if (reg == AC97_GPIO_STATUS)
+		goto out;
+	if (wait_event_timeout(gsr_wq, (GSR | gsr_bits) & GSR_SDONE, 1) <= 0 &&
+	    !((GSR | gsr_bits) & GSR_SDONE)) {
+		printk(KERN_ERR "%s: read error (ac97_reg=%d GSR=%#lx)\n",
+				__func__, reg, GSR | gsr_bits);
+		val = -1;
+		goto out;
+	}
+
+	/* valid data now */
+	GSR = GSR_CDONE | GSR_SDONE;
+	gsr_bits = 0;
+	val = *reg_addr;
+	/* but we've just started another cycle... */
+	wait_event_timeout(gsr_wq, (GSR | gsr_bits) & GSR_SDONE, 1);
+
+out:	mutex_unlock(&car_mutex);
+	return val;
+}
+EXPORT_SYMBOL_GPL(pxa2xx_ac97_read);
+
+void pxa2xx_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
+			unsigned short val)
+{
+	volatile u32 *reg_addr;
+
+	mutex_lock(&car_mutex);
+
+	/* set up primary or secondary codec space */
+	if ((cpu_is_pxa21x() || cpu_is_pxa25x()) && reg == AC97_GPIO_STATUS)
+		reg_addr = ac97->num ? &SMC_REG_BASE : &PMC_REG_BASE;
+	else
+		reg_addr = ac97->num ? &SAC_REG_BASE : &PAC_REG_BASE;
+	reg_addr += (reg >> 1);
+
+	GSR = GSR_CDONE | GSR_SDONE;
+	gsr_bits = 0;
+	*reg_addr = val;
+	if (wait_event_timeout(gsr_wq, (GSR | gsr_bits) & GSR_CDONE, 1) <= 0 &&
+	    !((GSR | gsr_bits) & GSR_CDONE))
+		printk(KERN_ERR "%s: write error (ac97_reg=%d GSR=%#lx)\n",
+				__func__, reg, GSR | gsr_bits);
+
+	mutex_unlock(&car_mutex);
+}
+EXPORT_SYMBOL_GPL(pxa2xx_ac97_write);
+
+#ifdef CONFIG_PXA25x
+static inline void pxa_ac97_warm_pxa25x(void)
+{
+	gsr_bits = 0;
+
+	GCR |= GCR_WARM_RST | GCR_PRIRDY_IEN | GCR_SECRDY_IEN;
+	wait_event_timeout(gsr_wq, gsr_bits & (GSR_PCR | GSR_SCR), 1);
+}
+
+static inline void pxa_ac97_cold_pxa25x(void)
+{
+	GCR &=  GCR_COLD_RST;  /* clear everything but nCRST */
+	GCR &= ~GCR_COLD_RST;  /* then assert nCRST */
+
+	gsr_bits = 0;
+
+	GCR = GCR_COLD_RST;
+	GCR |= GCR_CDONE_IE|GCR_SDONE_IE;
+	wait_event_timeout(gsr_wq, gsr_bits & (GSR_PCR | GSR_SCR), 1);
+}
+#endif
+
+#ifdef CONFIG_PXA27x
+static inline void pxa_ac97_warm_pxa27x(void)
+{
+	gsr_bits = 0;
+
+	/* warm reset broken on Bulverde,
+	   so manually keep AC97 reset high */
+	pxa_gpio_mode(113 | GPIO_OUT | GPIO_DFLT_HIGH);
+	udelay(10);
+	GCR |= GCR_WARM_RST;
+	pxa_gpio_mode(113 | GPIO_ALT_FN_2_OUT);
+	udelay(500);
+}
+
+static inline void pxa_ac97_cold_pxa27x(void)
+{
+	GCR &=  GCR_COLD_RST;  /* clear everything but nCRST */
+	GCR &= ~GCR_COLD_RST;  /* then assert nCRST */
+
+	gsr_bits = 0;
+
+	/* PXA27x Developers Manual section 13.5.2.2.1 */
+	clk_enable(ac97conf_clk);
+	udelay(5);
+	clk_disable(ac97conf_clk);
+	GCR = GCR_COLD_RST;
+	udelay(50);
+}
+#endif
+
+#ifdef CONFIG_PXA3xx
+static inline void pxa_ac97_warm_pxa3xx(void)
+{
+	int timeout = 100;
+
+	gsr_bits = 0;
+
+	/* Can't use interrupts */
+	GCR |= GCR_WARM_RST;
+	while (!((GSR | gsr_bits) & (GSR_PCR | GSR_SCR)) && timeout--)
+		mdelay(1);
+}
+
+static inline void pxa_ac97_cold_pxa3xx(void)
+{
+	int timeout = 1000;
+
+	/* Hold CLKBPB for 100us */
+	GCR = 0;
+	GCR = GCR_CLKBPB;
+	udelay(100);
+	GCR = 0;
+
+	GCR &=  GCR_COLD_RST;  /* clear everything but nCRST */
+	GCR &= ~GCR_COLD_RST;  /* then assert nCRST */
+
+	gsr_bits = 0;
+
+	/* Can't use interrupts on PXA3xx */
+	GCR &= ~(GCR_PRIRDY_IEN|GCR_SECRDY_IEN);
+
+	GCR = GCR_WARM_RST | GCR_COLD_RST;
+	while (!(GSR & (GSR_PCR | GSR_SCR)) && timeout--)
+		mdelay(10);
+}
+#endif
+
+bool pxa2xx_ac97_try_warm_reset(struct snd_ac97 *ac97)
+{
+#ifdef CONFIG_PXA25x
+	if (cpu_is_pxa21x() || cpu_is_pxa25x())
+		pxa_ac97_warm_pxa25x();
+	else
+#endif
+#ifdef CONFIG_PXA27x
+	if (cpu_is_pxa27x())
+		pxa_ac97_warm_pxa27x();
+	else
+#endif
+#ifdef CONFIG_PXA3xx
+	if (cpu_is_pxa3xx())
+		pxa_ac97_warm_pxa3xx();
+	else
+#endif
+		BUG();
+
+	if (!((GSR | gsr_bits) & (GSR_PCR | GSR_SCR))) {
+		printk(KERN_INFO "%s: warm reset timeout (GSR=%#lx)\n",
+				 __func__, gsr_bits);
+
+		return false;
+	}
+
+	return true;
+}
+EXPORT_SYMBOL_GPL(pxa2xx_ac97_try_warm_reset);
+
+bool pxa2xx_ac97_try_cold_reset(struct snd_ac97 *ac97)
+{
+#ifdef CONFIG_PXA25x
+	if (cpu_is_pxa21x() || cpu_is_pxa25x())
+		pxa_ac97_cold_pxa25x();
+	else
+#endif
+#ifdef CONFIG_PXA27x
+	if (cpu_is_pxa27x())
+		pxa_ac97_cold_pxa27x();
+	else
+#endif
+#ifdef CONFIG_PXA3xx
+	if (cpu_is_pxa3xx())
+		pxa_ac97_cold_pxa3xx();
+	else
+#endif
+		BUG();
+
+	if (!((GSR | gsr_bits) & (GSR_PCR | GSR_SCR))) {
+		printk(KERN_INFO "%s: cold reset timeout (GSR=%#lx)\n",
+				 __func__, gsr_bits);
+
+		return false;
+	}
+
+	return true;
+}
+EXPORT_SYMBOL_GPL(pxa2xx_ac97_try_cold_reset);
+
+
+void pxa2xx_ac97_finish_reset(struct snd_ac97 *ac97)
+{
+	GCR &= ~(GCR_PRIRDY_IEN|GCR_SECRDY_IEN);
+	GCR |= GCR_SDONE_IE|GCR_CDONE_IE;
+}
+EXPORT_SYMBOL_GPL(pxa2xx_ac97_finish_reset);
+
+static irqreturn_t pxa2xx_ac97_irq(int irq, void *dev_id)
+{
+	long status;
+
+	status = GSR;
+	if (status) {
+		GSR = status;
+		gsr_bits |= status;
+		wake_up(&gsr_wq);
+
+		/* Although we don't use those we still need to clear them
+		   since they tend to spuriously trigger when MMC is used
+		   (hardware bug? go figure)... */
+		if (cpu_is_pxa27x()) {
+			MISR = MISR_EOC;
+			PISR = PISR_EOC;
+			MCSR = MCSR_EOC;
+		}
+
+		return IRQ_HANDLED;
+	}
+
+	return IRQ_NONE;
+}
+
+#ifdef CONFIG_PM
+int pxa2xx_ac97_hw_suspend(void)
+{
+	GCR |= GCR_ACLINK_OFF;
+	clk_disable(ac97_clk);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(pxa2xx_ac97_hw_suspend);
+
+int pxa2xx_ac97_hw_resume(void)
+{
+	if (cpu_is_pxa21x() || cpu_is_pxa25x() || cpu_is_pxa27x()) {
+		pxa_gpio_mode(GPIO31_SYNC_AC97_MD);
+		pxa_gpio_mode(GPIO30_SDATA_OUT_AC97_MD);
+		pxa_gpio_mode(GPIO28_BITCLK_AC97_MD);
+		pxa_gpio_mode(GPIO29_SDATA_IN_AC97_MD);
+	}
+	if (cpu_is_pxa27x()) {
+		/* Use GPIO 113 as AC97 Reset on Bulverde */
+		pxa_gpio_mode(113 | GPIO_ALT_FN_2_OUT);
+	}
+	clk_enable(ac97_clk);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(pxa2xx_ac97_hw_resume);
+#endif
+
+int __devinit pxa2xx_ac97_hw_probe(struct platform_device *dev)
+{
+	int ret;
+
+	ret = request_irq(IRQ_AC97, pxa2xx_ac97_irq, 0, "AC97", NULL);
+	if (ret < 0)
+		goto err;
+
+	if (cpu_is_pxa21x() || cpu_is_pxa25x() || cpu_is_pxa27x()) {
+		pxa_gpio_mode(GPIO31_SYNC_AC97_MD);
+		pxa_gpio_mode(GPIO30_SDATA_OUT_AC97_MD);
+		pxa_gpio_mode(GPIO28_BITCLK_AC97_MD);
+		pxa_gpio_mode(GPIO29_SDATA_IN_AC97_MD);
+	}
+
+	if (cpu_is_pxa27x()) {
+		/* Use GPIO 113 as AC97 Reset on Bulverde */
+		pxa_gpio_mode(113 | GPIO_ALT_FN_2_OUT);
+		ac97conf_clk = clk_get(&dev->dev, "AC97CONFCLK");
+		if (IS_ERR(ac97conf_clk)) {
+			ret = PTR_ERR(ac97conf_clk);
+			ac97conf_clk = NULL;
+			goto err_irq;
+		}
+	}
+
+	ac97_clk = clk_get(&dev->dev, "AC97CLK");
+	if (IS_ERR(ac97_clk)) {
+		ret = PTR_ERR(ac97_clk);
+		ac97_clk = NULL;
+		goto err_irq;
+	}
+
+	return clk_enable(ac97_clk);
+
+err_irq:
+	GCR |= GCR_ACLINK_OFF;
+	if (ac97conf_clk) {
+		clk_put(ac97conf_clk);
+		ac97conf_clk = NULL;
+	}
+	free_irq(IRQ_AC97, NULL);
+err:
+	return ret;
+}
+EXPORT_SYMBOL_GPL(pxa2xx_ac97_hw_probe);
+
+void pxa2xx_ac97_hw_remove(struct platform_device *dev)
+{
+	GCR |= GCR_ACLINK_OFF;
+	free_irq(IRQ_AC97, NULL);
+	if (ac97conf_clk) {
+		clk_put(ac97conf_clk);
+		ac97conf_clk = NULL;
+	}
+	clk_disable(ac97_clk);
+	clk_put(ac97_clk);
+	ac97_clk = NULL;
+}
+EXPORT_SYMBOL_GPL(pxa2xx_ac97_hw_remove);
+
+MODULE_AUTHOR("Nicolas Pitre");
+MODULE_DESCRIPTION("Intel/Marvell PXA sound library");
+MODULE_LICENSE("GPL");
+
diff --git a/sound/arm/pxa2xx-ac97.c b/sound/arm/pxa2xx-ac97.c
index 199cca3..c2635be 100644
--- a/sound/arm/pxa2xx-ac97.c
+++ b/sound/arm/pxa2xx-ac97.c
@@ -12,198 +12,27 @@
 
 #include <linux/init.h>
 #include <linux/module.h>
-#include <linux/kernel.h>
 #include <linux/platform_device.h>
-#include <linux/interrupt.h>
-#include <linux/wait.h>
-#include <linux/clk.h>
-#include <linux/delay.h>
 
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/ac97_codec.h>
 #include <sound/initval.h>
+#include <sound/pxa2xx-lib.h>
 
-#include <asm/irq.h>
-#include <linux/mutex.h>
 #include <mach/hardware.h>
 #include <mach/pxa-regs.h>
-#include <mach/pxa2xx-gpio.h>
 #include <mach/audio.h>
 
 #include "pxa2xx-pcm.h"
 
-
-static DEFINE_MUTEX(car_mutex);
-static DECLARE_WAIT_QUEUE_HEAD(gsr_wq);
-static volatile long gsr_bits;
-static struct clk *ac97_clk;
-#ifdef CONFIG_PXA27x
-static struct clk *ac97conf_clk;
-#endif
-
-/*
- * Beware PXA27x bugs:
- *
- *   o Slot 12 read from modem space will hang controller.
- *   o CDONE, SDONE interrupt fails after any slot 12 IO.
- *
- * We therefore have an hybrid approach for waiting on SDONE (interrupt or
- * 1 jiffy timeout if interrupt never comes).
- */ 
-
-static unsigned short pxa2xx_ac97_read(struct snd_ac97 *ac97, unsigned short reg)
-{
-	unsigned short val = -1;
-	volatile u32 *reg_addr;
-
-	mutex_lock(&car_mutex);
-
-	/* set up primary or secondary codec space */
-	reg_addr = (ac97->num & 1) ? &SAC_REG_BASE : &PAC_REG_BASE;
-	reg_addr += (reg >> 1);
-
-	/* start read access across the ac97 link */
-	GSR = GSR_CDONE | GSR_SDONE;
-	gsr_bits = 0;
-	val = *reg_addr;
-	if (reg == AC97_GPIO_STATUS)
-		goto out;
-	if (wait_event_timeout(gsr_wq, (GSR | gsr_bits) & GSR_SDONE, 1) <= 0 &&
-	    !((GSR | gsr_bits) & GSR_SDONE)) {
-		printk(KERN_ERR "%s: read error (ac97_reg=%d GSR=%#lx)\n",
-				__func__, reg, GSR | gsr_bits);
-		val = -1;
-		goto out;
-	}
-
-	/* valid data now */
-	GSR = GSR_CDONE | GSR_SDONE;
-	gsr_bits = 0;
-	val = *reg_addr;			
-	/* but we've just started another cycle... */
-	wait_event_timeout(gsr_wq, (GSR | gsr_bits) & GSR_SDONE, 1);
-
-out:	mutex_unlock(&car_mutex);
-	return val;
-}
-
-static void pxa2xx_ac97_write(struct snd_ac97 *ac97, unsigned short reg, unsigned short val)
-{
-	volatile u32 *reg_addr;
-
-	mutex_lock(&car_mutex);
-
-	/* set up primary or secondary codec space */
-	reg_addr = (ac97->num & 1) ? &SAC_REG_BASE : &PAC_REG_BASE;
-	reg_addr += (reg >> 1);
-
-	GSR = GSR_CDONE | GSR_SDONE;
-	gsr_bits = 0;
-	*reg_addr = val;
-	if (wait_event_timeout(gsr_wq, (GSR | gsr_bits) & GSR_CDONE, 1) <= 0 &&
-	    !((GSR | gsr_bits) & GSR_CDONE))
-		printk(KERN_ERR "%s: write error (ac97_reg=%d GSR=%#lx)\n",
-				__func__, reg, GSR | gsr_bits);
-
-	mutex_unlock(&car_mutex);
-}
-
 static void pxa2xx_ac97_reset(struct snd_ac97 *ac97)
 {
-	/* First, try cold reset */
-#ifdef CONFIG_PXA3xx
-	int timeout;
-
-	/* Hold CLKBPB for 100us */
-	GCR = 0;
-	GCR = GCR_CLKBPB;
-	udelay(100);
-	GCR = 0;
-#endif
-
-	GCR &=  GCR_COLD_RST;  /* clear everything but nCRST */
-	GCR &= ~GCR_COLD_RST;  /* then assert nCRST */
-
-	gsr_bits = 0;
-#ifdef CONFIG_PXA27x
-	/* PXA27x Developers Manual section 13.5.2.2.1 */
-	clk_enable(ac97conf_clk);
-	udelay(5);
-	clk_disable(ac97conf_clk);
-	GCR = GCR_COLD_RST;
-	udelay(50);
-#elif defined(CONFIG_PXA3xx)
-	timeout = 1000;
-	/* Can't use interrupts on PXA3xx */
-	GCR &= ~(GCR_PRIRDY_IEN|GCR_SECRDY_IEN);
-
-	GCR = GCR_WARM_RST | GCR_COLD_RST;
-	while (!(GSR & (GSR_PCR | GSR_SCR)) && timeout--)
-		mdelay(10);
-#else
-	GCR = GCR_COLD_RST;
-	GCR |= GCR_CDONE_IE|GCR_SDONE_IE;
-	wait_event_timeout(gsr_wq, gsr_bits & (GSR_PCR | GSR_SCR), 1);
-#endif
-
-	if (!((GSR | gsr_bits) & (GSR_PCR | GSR_SCR))) {
-		printk(KERN_INFO "%s: cold reset timeout (GSR=%#lx)\n",
-				 __func__, gsr_bits);
-
-		/* let's try warm reset */
-		gsr_bits = 0;
-#ifdef CONFIG_PXA27x
-		/* warm reset broken on Bulverde,
-		   so manually keep AC97 reset high */
-		pxa_gpio_mode(113 | GPIO_OUT | GPIO_DFLT_HIGH); 
-		udelay(10);
-		GCR |= GCR_WARM_RST;
-		pxa_gpio_mode(113 | GPIO_ALT_FN_2_OUT);
-		udelay(500);
-#elif defined(CONFIG_PXA3xx)
-		timeout = 100;
-		/* Can't use interrupts */
-		GCR |= GCR_WARM_RST;
-		while (!((GSR | gsr_bits) & (GSR_PCR | GSR_SCR)) && timeout--)
-			mdelay(1);
-#else
-		GCR |= GCR_WARM_RST|GCR_PRIRDY_IEN|GCR_SECRDY_IEN;
-		wait_event_timeout(gsr_wq, gsr_bits & (GSR_PCR | GSR_SCR), 1);
-#endif			
-
-		if (!((GSR | gsr_bits) & (GSR_PCR | GSR_SCR)))
-			printk(KERN_INFO "%s: warm reset timeout (GSR=%#lx)\n",
-					 __func__, gsr_bits);
+	if (!pxa2xx_ac97_try_cold_reset(ac97)) {
+		pxa2xx_ac97_try_warm_reset(ac97);
 	}
 
-	GCR &= ~(GCR_PRIRDY_IEN|GCR_SECRDY_IEN);
-	GCR |= GCR_SDONE_IE|GCR_CDONE_IE;
-}
-
-static irqreturn_t pxa2xx_ac97_irq(int irq, void *dev_id)
-{
-	long status;
-
-	status = GSR;
-	if (status) {
-		GSR = status;
-		gsr_bits |= status;
-		wake_up(&gsr_wq);
-
-#ifdef CONFIG_PXA27x
-		/* Although we don't use those we still need to clear them
-		   since they tend to spuriously trigger when MMC is used
-		   (hardware bug? go figure)... */
-		MISR = MISR_EOC;
-		PISR = PISR_EOC;
-		MCSR = MCSR_EOC;
-#endif
-
-		return IRQ_HANDLED;
-	}
-
-	return IRQ_NONE;
+	pxa2xx_ac97_finish_reset(ac97);
 }
 
 static struct snd_ac97_bus_ops pxa2xx_ac97_ops = {
@@ -215,7 +44,7 @@
 static struct pxa2xx_pcm_dma_params pxa2xx_ac97_pcm_out = {
 	.name			= "AC97 PCM out",
 	.dev_addr		= __PREG(PCDR),
-	.drcmr			= &DRCMRTXPCDR,
+	.drcmr			= &DRCMR(12),
 	.dcmd			= DCMD_INCSRCADDR | DCMD_FLOWTRG |
 				  DCMD_BURST32 | DCMD_WIDTH4,
 };
@@ -223,7 +52,7 @@
 static struct pxa2xx_pcm_dma_params pxa2xx_ac97_pcm_in = {
 	.name			= "AC97 PCM in",
 	.dev_addr		= __PREG(PCDR),
-	.drcmr			= &DRCMRRXPCDR,
+	.drcmr			= &DRCMR(11),
 	.dcmd			= DCMD_INCTRGADDR | DCMD_FLOWSRC |
 				  DCMD_BURST32 | DCMD_WIDTH4,
 };
@@ -288,17 +117,19 @@
 	snd_ac97_suspend(pxa2xx_ac97_ac97);
 	if (platform_ops && platform_ops->suspend)
 		platform_ops->suspend(platform_ops->priv);
-	GCR |= GCR_ACLINK_OFF;
-	clk_disable(ac97_clk);
 
-	return 0;
+	return pxa2xx_ac97_hw_suspend();
 }
 
 static int pxa2xx_ac97_do_resume(struct snd_card *card)
 {
 	pxa2xx_audio_ops_t *platform_ops = card->dev->platform_data;
+	int rc;
 
-	clk_enable(ac97_clk);
+	rc = pxa2xx_ac97_hw_resume();
+	if (rc)
+		return rc;
+
 	if (platform_ops && platform_ops->resume)
 		platform_ops->resume(platform_ops->priv);
 	snd_ac97_resume(pxa2xx_ac97_ac97);
@@ -354,40 +185,17 @@
 	if (ret)
 		goto err;
 
-	ret = request_irq(IRQ_AC97, pxa2xx_ac97_irq, 0, "AC97", NULL);
-	if (ret < 0)
+	ret = pxa2xx_ac97_hw_probe(dev);
+	if (ret)
 		goto err;
 
-	pxa_gpio_mode(GPIO31_SYNC_AC97_MD);
-	pxa_gpio_mode(GPIO30_SDATA_OUT_AC97_MD);
-	pxa_gpio_mode(GPIO28_BITCLK_AC97_MD);
-	pxa_gpio_mode(GPIO29_SDATA_IN_AC97_MD);
-#ifdef CONFIG_PXA27x
-	/* Use GPIO 113 as AC97 Reset on Bulverde */
-	pxa_gpio_mode(113 | GPIO_ALT_FN_2_OUT);
-	ac97conf_clk = clk_get(&dev->dev, "AC97CONFCLK");
-	if (IS_ERR(ac97conf_clk)) {
-		ret = PTR_ERR(ac97conf_clk);
-		ac97conf_clk = NULL;
-		goto err;
-	}
-#endif
-
-	ac97_clk = clk_get(&dev->dev, "AC97CLK");
-	if (IS_ERR(ac97_clk)) {
-		ret = PTR_ERR(ac97_clk);
-		ac97_clk = NULL;
-		goto err;
-	}
-	clk_enable(ac97_clk);
-
 	ret = snd_ac97_bus(card, 0, &pxa2xx_ac97_ops, NULL, &ac97_bus);
 	if (ret)
-		goto err;
+		goto err_remove;
 	memset(&ac97_template, 0, sizeof(ac97_template));
 	ret = snd_ac97_mixer(ac97_bus, &ac97_template, &pxa2xx_ac97_ac97);
 	if (ret)
-		goto err;
+		goto err_remove;
 
 	snprintf(card->shortname, sizeof(card->shortname),
 		 "%s", snd_ac97_get_short_name(pxa2xx_ac97_ac97));
@@ -401,22 +209,11 @@
 		return 0;
 	}
 
- err:
+err_remove:
+	pxa2xx_ac97_hw_remove(dev);
+err:
 	if (card)
 		snd_card_free(card);
-	if (ac97_clk) {
-		GCR |= GCR_ACLINK_OFF;
-		free_irq(IRQ_AC97, NULL);
-		clk_disable(ac97_clk);
-		clk_put(ac97_clk);
-		ac97_clk = NULL;
-	}
-#ifdef CONFIG_PXA27x
-	if (ac97conf_clk) {
-		clk_put(ac97conf_clk);
-		ac97conf_clk = NULL;
-	}
-#endif
 	return ret;
 }
 
@@ -427,15 +224,7 @@
 	if (card) {
 		snd_card_free(card);
 		platform_set_drvdata(dev, NULL);
-		GCR |= GCR_ACLINK_OFF;
-		free_irq(IRQ_AC97, NULL);
-		clk_disable(ac97_clk);
-		clk_put(ac97_clk);
-		ac97_clk = NULL;
-#ifdef CONFIG_PXA27x
-		clk_put(ac97conf_clk);
-		ac97conf_clk = NULL;
-#endif
+		pxa2xx_ac97_hw_remove(dev);
 	}
 
 	return 0;
diff --git a/sound/arm/pxa2xx-pcm-lib.c b/sound/arm/pxa2xx-pcm-lib.c
new file mode 100644
index 0000000..1c93eb7
--- /dev/null
+++ b/sound/arm/pxa2xx-pcm-lib.c
@@ -0,0 +1,278 @@
+/*
+ * 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/dma-mapping.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/pxa2xx-lib.h>
+
+#include <asm/dma.h>
+#include <mach/pxa-regs.h>
+
+#include "pxa2xx-pcm.h"
+
+static const struct snd_pcm_hardware pxa2xx_pcm_hardware = {
+	.info			= SNDRV_PCM_INFO_MMAP |
+				  SNDRV_PCM_INFO_MMAP_VALID |
+				  SNDRV_PCM_INFO_INTERLEAVED |
+				  SNDRV_PCM_INFO_PAUSE |
+				  SNDRV_PCM_INFO_RESUME,
+	.formats		= SNDRV_PCM_FMTBIT_S16_LE |
+					SNDRV_PCM_FMTBIT_S24_LE |
+					SNDRV_PCM_FMTBIT_S32_LE,
+	.period_bytes_min	= 32,
+	.period_bytes_max	= 8192 - 32,
+	.periods_min		= 1,
+	.periods_max		= PAGE_SIZE/sizeof(pxa_dma_desc),
+	.buffer_bytes_max	= 128 * 1024,
+	.fifo_size		= 32,
+};
+
+int __pxa2xx_pcm_hw_params(struct snd_pcm_substream *substream,
+				struct snd_pcm_hw_params *params)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct pxa2xx_runtime_data *rtd = runtime->private_data;
+	size_t totsize = params_buffer_bytes(params);
+	size_t period = params_period_bytes(params);
+	pxa_dma_desc *dma_desc;
+	dma_addr_t dma_buff_phys, next_desc_phys;
+
+	snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
+	runtime->dma_bytes = totsize;
+
+	dma_desc = rtd->dma_desc_array;
+	next_desc_phys = rtd->dma_desc_array_phys;
+	dma_buff_phys = runtime->dma_addr;
+	do {
+		next_desc_phys += sizeof(pxa_dma_desc);
+		dma_desc->ddadr = next_desc_phys;
+		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+			dma_desc->dsadr = dma_buff_phys;
+			dma_desc->dtadr = rtd->params->dev_addr;
+		} else {
+			dma_desc->dsadr = rtd->params->dev_addr;
+			dma_desc->dtadr = dma_buff_phys;
+		}
+		if (period > totsize)
+			period = totsize;
+		dma_desc->dcmd = rtd->params->dcmd | period | DCMD_ENDIRQEN;
+		dma_desc++;
+		dma_buff_phys += period;
+	} while (totsize -= period);
+	dma_desc[-1].ddadr = rtd->dma_desc_array_phys;
+
+	return 0;
+}
+EXPORT_SYMBOL(__pxa2xx_pcm_hw_params);
+
+int __pxa2xx_pcm_hw_free(struct snd_pcm_substream *substream)
+{
+	struct pxa2xx_runtime_data *rtd = substream->runtime->private_data;
+
+	if (rtd && rtd->params)
+		*rtd->params->drcmr = 0;
+
+	snd_pcm_set_runtime_buffer(substream, NULL);
+	return 0;
+}
+EXPORT_SYMBOL(__pxa2xx_pcm_hw_free);
+
+int pxa2xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+	struct pxa2xx_runtime_data *prtd = substream->runtime->private_data;
+	int ret = 0;
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+		DDADR(prtd->dma_ch) = prtd->dma_desc_array_phys;
+		DCSR(prtd->dma_ch) = DCSR_RUN;
+		break;
+
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		DCSR(prtd->dma_ch) &= ~DCSR_RUN;
+		break;
+
+	case SNDRV_PCM_TRIGGER_RESUME:
+		DCSR(prtd->dma_ch) |= DCSR_RUN;
+		break;
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		DDADR(prtd->dma_ch) = prtd->dma_desc_array_phys;
+		DCSR(prtd->dma_ch) |= DCSR_RUN;
+		break;
+
+	default:
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+EXPORT_SYMBOL(pxa2xx_pcm_trigger);
+
+snd_pcm_uframes_t
+pxa2xx_pcm_pointer(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct pxa2xx_runtime_data *prtd = runtime->private_data;
+
+	dma_addr_t ptr = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
+			 DSADR(prtd->dma_ch) : DTADR(prtd->dma_ch);
+	snd_pcm_uframes_t x = bytes_to_frames(runtime, ptr - runtime->dma_addr);
+
+	if (x == runtime->buffer_size)
+		x = 0;
+	return x;
+}
+EXPORT_SYMBOL(pxa2xx_pcm_pointer);
+
+int __pxa2xx_pcm_prepare(struct snd_pcm_substream *substream)
+{
+	struct pxa2xx_runtime_data *prtd = substream->runtime->private_data;
+
+	DCSR(prtd->dma_ch) &= ~DCSR_RUN;
+	DCSR(prtd->dma_ch) = 0;
+	DCMD(prtd->dma_ch) = 0;
+	*prtd->params->drcmr = prtd->dma_ch | DRCMR_MAPVLD;
+
+	return 0;
+}
+EXPORT_SYMBOL(__pxa2xx_pcm_prepare);
+
+void pxa2xx_pcm_dma_irq(int dma_ch, void *dev_id)
+{
+	struct snd_pcm_substream *substream = dev_id;
+	struct pxa2xx_runtime_data *rtd = substream->runtime->private_data;
+	int dcsr;
+
+	dcsr = DCSR(dma_ch);
+	DCSR(dma_ch) = dcsr & ~DCSR_STOPIRQEN;
+
+	if (dcsr & DCSR_ENDINTR) {
+		snd_pcm_period_elapsed(substream);
+	} else {
+		printk(KERN_ERR "%s: DMA error on channel %d (DCSR=%#x)\n",
+			rtd->params->name, dma_ch, dcsr);
+		snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
+	}
+}
+EXPORT_SYMBOL(pxa2xx_pcm_dma_irq);
+
+int __pxa2xx_pcm_open(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct pxa2xx_runtime_data *rtd;
+	int ret;
+
+	runtime->hw = pxa2xx_pcm_hardware;
+
+	/*
+	 * For mysterious reasons (and despite what the manual says)
+	 * playback samples are lost if the DMA count is not a multiple
+	 * of the DMA burst size.  Let's add a rule to enforce that.
+	 */
+	ret = snd_pcm_hw_constraint_step(runtime, 0,
+		SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 32);
+	if (ret)
+		goto out;
+
+	ret = snd_pcm_hw_constraint_step(runtime, 0,
+		SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 32);
+	if (ret)
+		goto out;
+
+	ret = snd_pcm_hw_constraint_integer(runtime,
+					    SNDRV_PCM_HW_PARAM_PERIODS);
+	if (ret < 0)
+		goto out;
+
+	ret = -ENOMEM;
+	rtd = kmalloc(sizeof(*rtd), GFP_KERNEL);
+	if (!rtd)
+		goto out;
+	rtd->dma_desc_array =
+		dma_alloc_writecombine(substream->pcm->card->dev, PAGE_SIZE,
+				       &rtd->dma_desc_array_phys, GFP_KERNEL);
+	if (!rtd->dma_desc_array)
+		goto err1;
+
+	runtime->private_data = rtd;
+	return 0;
+
+ err1:
+	kfree(rtd);
+ out:
+	return ret;
+}
+EXPORT_SYMBOL(__pxa2xx_pcm_open);
+
+int __pxa2xx_pcm_close(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct pxa2xx_runtime_data *rtd = runtime->private_data;
+
+	dma_free_writecombine(substream->pcm->card->dev, PAGE_SIZE,
+			      rtd->dma_desc_array, rtd->dma_desc_array_phys);
+	kfree(rtd);
+	return 0;
+}
+EXPORT_SYMBOL(__pxa2xx_pcm_close);
+
+int pxa2xx_pcm_mmap(struct snd_pcm_substream *substream,
+	struct vm_area_struct *vma)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	return dma_mmap_writecombine(substream->pcm->card->dev, vma,
+				     runtime->dma_area,
+				     runtime->dma_addr,
+				     runtime->dma_bytes);
+}
+EXPORT_SYMBOL(pxa2xx_pcm_mmap);
+
+int pxa2xx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
+{
+	struct snd_pcm_substream *substream = pcm->streams[stream].substream;
+	struct snd_dma_buffer *buf = &substream->dma_buffer;
+	size_t size = pxa2xx_pcm_hardware.buffer_bytes_max;
+	buf->dev.type = SNDRV_DMA_TYPE_DEV;
+	buf->dev.dev = pcm->card->dev;
+	buf->private_data = NULL;
+	buf->area = dma_alloc_writecombine(pcm->card->dev, size,
+					   &buf->addr, GFP_KERNEL);
+	if (!buf->area)
+		return -ENOMEM;
+	buf->bytes = size;
+	return 0;
+}
+EXPORT_SYMBOL(pxa2xx_pcm_preallocate_dma_buffer);
+
+void pxa2xx_pcm_free_dma_buffers(struct snd_pcm *pcm)
+{
+	struct snd_pcm_substream *substream;
+	struct snd_dma_buffer *buf;
+	int stream;
+
+	for (stream = 0; stream < 2; stream++) {
+		substream = pcm->streams[stream].substream;
+		if (!substream)
+			continue;
+		buf = &substream->dma_buffer;
+		if (!buf->area)
+			continue;
+		dma_free_writecombine(pcm->card->dev, buf->bytes,
+				      buf->area, buf->addr);
+		buf->area = NULL;
+	}
+}
+EXPORT_SYMBOL(pxa2xx_pcm_free_dma_buffers);
+
+MODULE_AUTHOR("Nicolas Pitre");
+MODULE_DESCRIPTION("Intel PXA2xx sound library");
+MODULE_LICENSE("GPL");
diff --git a/sound/arm/pxa2xx-pcm.c b/sound/arm/pxa2xx-pcm.c
index 381094a..535704f 100644
--- a/sound/arm/pxa2xx-pcm.c
+++ b/sound/arm/pxa2xx-pcm.c
@@ -10,183 +10,20 @@
  * published by the Free Software Foundation.
  */
 
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/device.h>
-#include <linux/slab.h>
-#include <linux/dma-mapping.h>
-
 #include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-
-#include <asm/dma.h>
-#include <mach/hardware.h>
-#include <mach/pxa-regs.h>
+#include <sound/pxa2xx-lib.h>
 
 #include "pxa2xx-pcm.h"
 
-
-static const struct snd_pcm_hardware pxa2xx_pcm_hardware = {
-	.info			= SNDRV_PCM_INFO_MMAP |
-				  SNDRV_PCM_INFO_MMAP_VALID |
-				  SNDRV_PCM_INFO_INTERLEAVED |
-				  SNDRV_PCM_INFO_PAUSE,
-	.formats		= SNDRV_PCM_FMTBIT_S16_LE,
-	.period_bytes_min	= 32,
-	.period_bytes_max	= 8192 - 32,
-	.periods_min		= 1,
-	.periods_max		= PAGE_SIZE/sizeof(pxa_dma_desc),
-	.buffer_bytes_max	= 128 * 1024,
-	.fifo_size		= 32,
-};
-
-struct pxa2xx_runtime_data {
-	int dma_ch;
-	struct pxa2xx_pcm_dma_params *params;
-	pxa_dma_desc *dma_desc_array;
-	dma_addr_t dma_desc_array_phys;
-};
-
-static int pxa2xx_pcm_hw_params(struct snd_pcm_substream *substream,
-				struct snd_pcm_hw_params *params)
-{
-	struct snd_pcm_runtime *runtime = substream->runtime;
-	struct pxa2xx_runtime_data *rtd = runtime->private_data;
-	size_t totsize = params_buffer_bytes(params);
-	size_t period = params_period_bytes(params);
-	pxa_dma_desc *dma_desc;
-	dma_addr_t dma_buff_phys, next_desc_phys;
-
-	snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
-	runtime->dma_bytes = totsize;
-
-	dma_desc = rtd->dma_desc_array;
-	next_desc_phys = rtd->dma_desc_array_phys;
-	dma_buff_phys = runtime->dma_addr;
-	do {
-		next_desc_phys += sizeof(pxa_dma_desc);
-		dma_desc->ddadr = next_desc_phys;
-		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-			dma_desc->dsadr = dma_buff_phys;
-			dma_desc->dtadr = rtd->params->dev_addr;
-		} else {
-			dma_desc->dsadr = rtd->params->dev_addr;
-			dma_desc->dtadr = dma_buff_phys;
-		}
-		if (period > totsize)
-			period = totsize;
-		dma_desc->dcmd = rtd->params->dcmd | period | DCMD_ENDIRQEN;
-		dma_desc++;
-		dma_buff_phys += period;
-	} while (totsize -= period);
-	dma_desc[-1].ddadr = rtd->dma_desc_array_phys;
-
-	return 0;
-}
-
-static int pxa2xx_pcm_hw_free(struct snd_pcm_substream *substream)
-{
-	struct pxa2xx_runtime_data *rtd = substream->runtime->private_data;
-
-	*rtd->params->drcmr = 0;
-	snd_pcm_set_runtime_buffer(substream, NULL);
-	return 0;
-}
-
 static int pxa2xx_pcm_prepare(struct snd_pcm_substream *substream)
 {
 	struct pxa2xx_pcm_client *client = substream->private_data;
-	struct snd_pcm_runtime *runtime = substream->runtime;
-	struct pxa2xx_runtime_data *rtd = runtime->private_data;
 
-	DCSR(rtd->dma_ch) &= ~DCSR_RUN;
-	DCSR(rtd->dma_ch) = 0;
-	DCMD(rtd->dma_ch) = 0;
-	*rtd->params->drcmr = rtd->dma_ch | DRCMR_MAPVLD;
+	__pxa2xx_pcm_prepare(substream);
 
 	return client->prepare(substream);
 }
 
-static int pxa2xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
-{
-	struct pxa2xx_runtime_data *rtd = substream->runtime->private_data;
-	int ret = 0;
-
-	switch (cmd) {
-	case SNDRV_PCM_TRIGGER_START:
-		DDADR(rtd->dma_ch) = rtd->dma_desc_array_phys;
-		DCSR(rtd->dma_ch) = DCSR_RUN;
-		break;
-
-	case SNDRV_PCM_TRIGGER_STOP:
-	case SNDRV_PCM_TRIGGER_SUSPEND:
-	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-		DCSR(rtd->dma_ch) &= ~DCSR_RUN;
-		break;
-
-	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-		DCSR(rtd->dma_ch) |= DCSR_RUN;
-		break;
-
-	default:
-		ret = -EINVAL;
-	}
-
-	return ret;
-}
-
-static void pxa2xx_pcm_dma_irq(int dma_ch, void *dev_id)
-{
-	struct snd_pcm_substream *substream = dev_id;
-	struct pxa2xx_runtime_data *rtd = substream->runtime->private_data;
-	int dcsr;
-
-	dcsr = DCSR(dma_ch);
-	DCSR(dma_ch) = dcsr & ~DCSR_STOPIRQEN;
-
-	if (dcsr & DCSR_ENDINTR) {
-		snd_pcm_period_elapsed(substream);
-	} else {
-		printk( KERN_ERR "%s: DMA error on channel %d (DCSR=%#x)\n",
-			rtd->params->name, dma_ch, dcsr );
-		snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
-	}
-}
-
-static snd_pcm_uframes_t pxa2xx_pcm_pointer(struct snd_pcm_substream *substream)
-{
-	struct snd_pcm_runtime *runtime = substream->runtime;
-	struct pxa2xx_runtime_data *rtd = runtime->private_data;
-	dma_addr_t ptr = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
-			 DSADR(rtd->dma_ch) : DTADR(rtd->dma_ch);
-	snd_pcm_uframes_t x = bytes_to_frames(runtime, ptr - runtime->dma_addr);
-	if (x == runtime->buffer_size)
-		x = 0;
-	return x;
-}
-
-static int
-pxa2xx_pcm_hw_rule_mult32(struct snd_pcm_hw_params *params, struct snd_pcm_hw_rule *rule)
-{
-	struct snd_interval *i = hw_param_interval(params, rule->var);
-	int changed = 0;
-
-	if (i->min & 31) {
-		i->min = (i->min & ~31) + 32;
-		i->openmin = 0;
-		changed = 1;
-	}
-
-	if (i->max & 31) {
-		i->max &= ~31;
-		i->openmax = 0;
-		changed = 1;
-	}
-
-	return changed;
-}
-
 static int pxa2xx_pcm_open(struct snd_pcm_substream *substream)
 {
 	struct pxa2xx_pcm_client *client = substream->private_data;
@@ -194,33 +31,11 @@
 	struct pxa2xx_runtime_data *rtd;
 	int ret;
 
-	runtime->hw = pxa2xx_pcm_hardware;
-
-	/*
-	 * For mysterious reasons (and despite what the manual says)
-	 * playback samples are lost if the DMA count is not a multiple
-	 * of the DMA burst size.  Let's add a rule to enforce that.
-	 */
-	ret = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
-				  pxa2xx_pcm_hw_rule_mult32, NULL,
-				  SNDRV_PCM_HW_PARAM_PERIOD_BYTES, -1);
-	if (ret)
-		goto out;
-	ret = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
-				  pxa2xx_pcm_hw_rule_mult32, NULL,
-				  SNDRV_PCM_HW_PARAM_BUFFER_BYTES, -1);
+	ret = __pxa2xx_pcm_open(substream);
 	if (ret)
 		goto out;
 
-	ret = -ENOMEM;
-	rtd = kmalloc(sizeof(*rtd), GFP_KERNEL);
-	if (!rtd)
-		goto out;
-	rtd->dma_desc_array =
-		dma_alloc_writecombine(substream->pcm->card->dev, PAGE_SIZE,
-				       &rtd->dma_desc_array_phys, GFP_KERNEL);
-	if (!rtd->dma_desc_array)
-		goto err1;
+	rtd = runtime->private_data;
 
 	rtd->params = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
 		      client->playback_params : client->capture_params;
@@ -230,17 +45,13 @@
 		goto err2;
 	rtd->dma_ch = ret;
 
-	runtime->private_data = rtd;
 	ret = client->startup(substream);
 	if (!ret)
 		goto out;
 
 	pxa_free_dma(rtd->dma_ch);
  err2:
-	dma_free_writecombine(substream->pcm->card->dev, PAGE_SIZE,
-			      rtd->dma_desc_array, rtd->dma_desc_array_phys);
- err1:
-	kfree(rtd);
+	__pxa2xx_pcm_close(substream);
  out:
 	return ret;
 }
@@ -252,69 +63,22 @@
 
 	pxa_free_dma(rtd->dma_ch);
 	client->shutdown(substream);
-	dma_free_writecombine(substream->pcm->card->dev, PAGE_SIZE,
-			      rtd->dma_desc_array, rtd->dma_desc_array_phys);
-	kfree(rtd);
-	return 0;
-}
 
-static int
-pxa2xx_pcm_mmap(struct snd_pcm_substream *substream, struct vm_area_struct *vma)
-{
-	struct snd_pcm_runtime *runtime = substream->runtime;
-	return dma_mmap_writecombine(substream->pcm->card->dev, vma,
-				     runtime->dma_area,
-				     runtime->dma_addr,
-				     runtime->dma_bytes);
+	return __pxa2xx_pcm_close(substream);
 }
 
 static struct snd_pcm_ops pxa2xx_pcm_ops = {
 	.open		= pxa2xx_pcm_open,
 	.close		= pxa2xx_pcm_close,
 	.ioctl		= snd_pcm_lib_ioctl,
-	.hw_params	= pxa2xx_pcm_hw_params,
-	.hw_free	= pxa2xx_pcm_hw_free,
+	.hw_params	= __pxa2xx_pcm_hw_params,
+	.hw_free	= __pxa2xx_pcm_hw_free,
 	.prepare	= pxa2xx_pcm_prepare,
 	.trigger	= pxa2xx_pcm_trigger,
 	.pointer	= pxa2xx_pcm_pointer,
 	.mmap		= pxa2xx_pcm_mmap,
 };
 
-static int pxa2xx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
-{
-	struct snd_pcm_substream *substream = pcm->streams[stream].substream;
-	struct snd_dma_buffer *buf = &substream->dma_buffer;
-	size_t size = pxa2xx_pcm_hardware.buffer_bytes_max;
-	buf->dev.type = SNDRV_DMA_TYPE_DEV;
-	buf->dev.dev = pcm->card->dev;
-	buf->private_data = NULL;
-	buf->area = dma_alloc_writecombine(pcm->card->dev, size,
-					   &buf->addr, GFP_KERNEL);
-	if (!buf->area)
-		return -ENOMEM;
-	buf->bytes = size;
-	return 0;
-}
-
-static void pxa2xx_pcm_free_dma_buffers(struct snd_pcm *pcm)
-{
-	struct snd_pcm_substream *substream;
-	struct snd_dma_buffer *buf;
-	int stream;
-
-	for (stream = 0; stream < 2; stream++) {
-		substream = pcm->streams[stream].substream;
-		if (!substream)
-			continue;
-		buf = &substream->dma_buffer;
-		if (!buf->area)
-			continue;
-		dma_free_writecombine(pcm->card->dev, buf->bytes,
-				      buf->area, buf->addr);
-		buf->area = NULL;
-	}
-}
-
 static u64 pxa2xx_pcm_dmamask = 0xffffffff;
 
 int pxa2xx_pcm_new(struct snd_card *card, struct pxa2xx_pcm_client *client,
diff --git a/sound/arm/pxa2xx-pcm.h b/sound/arm/pxa2xx-pcm.h
index b79f1e8..5c4a4d3 100644
--- a/sound/arm/pxa2xx-pcm.h
+++ b/sound/arm/pxa2xx-pcm.h
@@ -9,14 +9,15 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  */
+#include <asm/dma.h>
 
-struct pxa2xx_pcm_dma_params {
-	char *name;			/* stream identifier */
-	u32 dcmd;			/* DMA descriptor dcmd field */
-	volatile u32 *drcmr;		/* the DMA request channel to use */
-	u32 dev_addr;			/* device physical address for DMA */
+struct pxa2xx_runtime_data {
+	int dma_ch;
+	struct pxa2xx_pcm_dma_params *params;
+	pxa_dma_desc *dma_desc_array;
+	dma_addr_t dma_desc_array_phys;
 };
-	
+
 struct pxa2xx_pcm_client {
 	struct pxa2xx_pcm_dma_params *playback_params;
 	struct pxa2xx_pcm_dma_params *capture_params;
diff --git a/sound/arm/sa11xx-uda1341.c b/sound/arm/sa11xx-uda1341.c
index b9c51bf..1dcd51d 100644
--- a/sound/arm/sa11xx-uda1341.c
+++ b/sound/arm/sa11xx-uda1341.c
@@ -442,7 +442,8 @@
                 
 	/* we are requested to process synchronization DMA transfer */
 	if (s->tx_spin) {
-		snd_assert(s->stream_id == SNDRV_PCM_STREAM_PLAYBACK, return);
+		if (snd_BUG_ON(s->stream_id != SNDRV_PCM_STREAM_PLAYBACK))
+			return;
 		/* fill the xmit dma buffers and return */
 #ifdef HH_VERSION
 		sa1100_dma_set_spin(s->dmach, FORCE_CLOCK_ADDR, FORCE_CLOCK_SIZE);
@@ -472,7 +473,7 @@
 				continue;		/* special case */
 		} else {
 			offset = dma_size * s->period;
-			snd_assert(dma_size <= DMA_BUF_SIZE, );
+			snd_BUG_ON(dma_size > DMA_BUF_SIZE);
 		}
 #ifdef HH_VERSION
 		ret = sa1100_dma_queue_buffer(s->dmach, s, runtime->dma_addr + offset, dma_size);
@@ -879,7 +880,7 @@
 	audio_dma_free(&chip->s[SNDRV_PCM_STREAM_CAPTURE]);
 }
 
-static int __init sa11xx_uda1341_probe(struct platform_device *devptr)
+static int __devinit sa11xx_uda1341_probe(struct platform_device *devptr)
 {
 	int err;
 	struct snd_card *card;
diff --git a/sound/core/Kconfig b/sound/core/Kconfig
index 335d45e..66348c9 100644
--- a/sound/core/Kconfig
+++ b/sound/core/Kconfig
@@ -12,6 +12,12 @@
 config SND_RAWMIDI
 	tristate
 
+# To be effective this also requires INPUT - users should say:
+#    select SND_JACK if INPUT=y || INPUT=SND
+# to avoid having to force INPUT on.
+config SND_JACK
+	bool
+
 config SND_SEQUENCER
 	tristate "Sequencer support"
 	select SND_TIMER
@@ -38,6 +44,7 @@
 	  will be called snd-seq-dummy.
 
 config SND_OSSEMUL
+	select SOUND_OSS_CORE
 	bool
 
 config SND_MIXER_OSS
@@ -101,6 +108,9 @@
 	  To compile this driver as a module, choose M here: the module
 	  will be called snd-rtctimer.
 
+	  Note that this option is exclusive with the new RTC drivers
+	  (CONFIG_RTC_CLASS) since this requires the old API.
+
 config SND_SEQ_RTCTIMER_DEFAULT
 	bool "Use RTC as default sequencer timer"
 	depends on SND_RTCTIMER && SND_SEQUENCER
diff --git a/sound/core/Makefile b/sound/core/Makefile
index da8e685..d57125a 100644
--- a/sound/core/Makefile
+++ b/sound/core/Makefile
@@ -7,6 +7,7 @@
 snd-$(CONFIG_ISA_DMA_API) += isadma.o
 snd-$(CONFIG_SND_OSSEMUL) += sound_oss.o info_oss.o
 snd-$(CONFIG_SND_VMASTER) += vmaster.o
+snd-$(CONFIG_SND_JACK)	  += jack.o
 
 snd-pcm-objs := pcm.o pcm_native.o pcm_lib.o pcm_timer.o pcm_misc.o \
 		pcm_memory.o
diff --git a/sound/core/control.c b/sound/core/control.c
index 281b2e2..6d71f9a 100644
--- a/sound/core/control.c
+++ b/sound/core/control.c
@@ -139,7 +139,8 @@
 	struct snd_ctl_file *ctl;
 	struct snd_kctl_event *ev;
 	
-	snd_assert(card != NULL && id != NULL, return);
+	if (snd_BUG_ON(!card || !id))
+		return;
 	read_lock(&card->ctl_files_rwlock);
 #if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE)
 	card->mixer_oss_change_count++;
@@ -188,8 +189,8 @@
 	struct snd_kcontrol *kctl;
 	unsigned int idx;
 	
-	snd_assert(control != NULL, return NULL);
-	snd_assert(control->count > 0, return NULL);
+	if (snd_BUG_ON(!control || !control->count))
+		return NULL;
 	kctl = kzalloc(sizeof(*kctl) + sizeof(struct snd_kcontrol_volatile) * control->count, GFP_KERNEL);
 	if (kctl == NULL) {
 		snd_printk(KERN_ERR "Cannot allocate control instance\n");
@@ -218,8 +219,8 @@
 	struct snd_kcontrol kctl;
 	unsigned int access;
 	
-	snd_assert(ncontrol != NULL, return NULL);
-	snd_assert(ncontrol->info != NULL, return NULL);
+	if (snd_BUG_ON(!ncontrol || !ncontrol->info))
+		return NULL;
 	memset(&kctl, 0, sizeof(kctl));
 	kctl.id.iface = ncontrol->iface;
 	kctl.id.device = ncontrol->device;
@@ -315,8 +316,8 @@
 
 	if (! kcontrol)
 		return err;
-	snd_assert(card != NULL, goto error);
-	snd_assert(kcontrol->info != NULL, goto error);
+	if (snd_BUG_ON(!card || !kcontrol->info))
+		goto error;
 	id = kcontrol->id;
 	down_write(&card->controls_rwsem);
 	if (snd_ctl_find_id(card, &id)) {
@@ -367,7 +368,8 @@
 	struct snd_ctl_elem_id id;
 	unsigned int idx;
 
-	snd_assert(card != NULL && kcontrol != NULL, return -EINVAL);
+	if (snd_BUG_ON(!card || !kcontrol))
+		return -EINVAL;
 	list_del(&kcontrol->list);
 	card->controls_count -= kcontrol->count;
 	id = kcontrol->id;
@@ -487,7 +489,8 @@
 {
 	struct snd_kcontrol *kctl;
 
-	snd_assert(card != NULL && numid != 0, return NULL);
+	if (snd_BUG_ON(!card || !numid))
+		return NULL;
 	list_for_each_entry(kctl, &card->controls, list) {
 		if (kctl->id.numid <= numid && kctl->id.numid + kctl->count > numid)
 			return kctl;
@@ -514,7 +517,8 @@
 {
 	struct snd_kcontrol *kctl;
 
-	snd_assert(card != NULL && id != NULL, return NULL);
+	if (snd_BUG_ON(!card || !id))
+		return NULL;
 	if (id->numid != 0)
 		return snd_ctl_find_numid(card, id->numid);
 	list_for_each_entry(kctl, &card->controls, list) {
@@ -647,7 +651,7 @@
 #endif
 	result = kctl->info(kctl, info);
 	if (result >= 0) {
-		snd_assert(info->access == 0, );
+		snd_BUG_ON(info->access);
 		index_offset = snd_ctl_get_ioff(kctl, &info->id);
 		vd = &kctl->vd[index_offset];
 		snd_ctl_build_ioff(&info->id, kctl, index_offset);
@@ -1160,7 +1164,8 @@
 
 	ctl = file->private_data;
 	card = ctl->card;
-	snd_assert(card != NULL, return -ENXIO);
+	if (snd_BUG_ON(!card))
+		return -ENXIO;
 	switch (cmd) {
 	case SNDRV_CTL_IOCTL_PVERSION:
 		return put_user(SNDRV_CTL_VERSION, ip) ? -EFAULT : 0;
@@ -1222,7 +1227,8 @@
 	ssize_t result = 0;
 
 	ctl = file->private_data;
-	snd_assert(ctl != NULL && ctl->card != NULL, return -ENXIO);
+	if (snd_BUG_ON(!ctl || !ctl->card))
+		return -ENXIO;
 	if (!ctl->subscribed)
 		return -EBADFD;
 	if (count < sizeof(struct snd_ctl_event))
@@ -1328,7 +1334,8 @@
 {
 	struct snd_kctl_ioctl *p;
 
-	snd_assert(fcn != NULL, return -EINVAL);
+	if (snd_BUG_ON(!fcn))
+		return -EINVAL;
 	down_write(&snd_ioctl_rwsem);
 	list_for_each_entry(p, lists, list) {
 		if (p->fioctl == fcn) {
@@ -1404,9 +1411,11 @@
 	int err, cardnum;
 	char name[16];
 
-	snd_assert(card != NULL, return -ENXIO);
+	if (snd_BUG_ON(!card))
+		return -ENXIO;
 	cardnum = card->number;
-	snd_assert(cardnum >= 0 && cardnum < SNDRV_CARDS, return -ENXIO);
+	if (snd_BUG_ON(cardnum < 0 || cardnum >= SNDRV_CARDS))
+		return -ENXIO;
 	sprintf(name, "controlC%i", cardnum);
 	if ((err = snd_register_device(SNDRV_DEVICE_TYPE_CONTROL, card, -1,
 				       &snd_ctl_f_ops, card, name)) < 0)
@@ -1423,16 +1432,18 @@
 	struct snd_ctl_file *ctl;
 	int err, cardnum;
 
-	snd_assert(card != NULL, return -ENXIO);
+	if (snd_BUG_ON(!card))
+		return -ENXIO;
 	cardnum = card->number;
-	snd_assert(cardnum >= 0 && cardnum < SNDRV_CARDS, return -ENXIO);
+	if (snd_BUG_ON(cardnum < 0 || cardnum >= SNDRV_CARDS))
+		return -ENXIO;
 
-	down_read(&card->controls_rwsem);
+	read_lock(&card->ctl_files_rwlock);
 	list_for_each_entry(ctl, &card->ctl_files, list) {
 		wake_up(&ctl->change_sleep);
 		kill_fasync(&ctl->fasync, SIGIO, POLL_ERR);
 	}
-	up_read(&card->controls_rwsem);
+	read_unlock(&card->ctl_files_rwlock);
 
 	if ((err = snd_unregister_device(SNDRV_DEVICE_TYPE_CONTROL,
 					 card, -1)) < 0)
@@ -1469,7 +1480,8 @@
 		.dev_disconnect = snd_ctl_dev_disconnect,
 	};
 
-	snd_assert(card != NULL, return -ENXIO);
+	if (snd_BUG_ON(!card))
+		return -ENXIO;
 	return snd_device_new(card, SNDRV_DEV_CONTROL, card, &ops);
 }
 
diff --git a/sound/core/control_compat.c b/sound/core/control_compat.c
index 6101259..368dc9c 100644
--- a/sound/core/control_compat.c
+++ b/sound/core/control_compat.c
@@ -398,7 +398,8 @@
 	int err;
 
 	ctl = file->private_data;
-	snd_assert(ctl && ctl->card, return -ENXIO);
+	if (snd_BUG_ON(!ctl || !ctl->card))
+		return -ENXIO;
 
 	switch (cmd) {
 	case SNDRV_CTL_IOCTL_PVERSION:
diff --git a/sound/core/device.c b/sound/core/device.c
index 202dac0..c58d822 100644
--- a/sound/core/device.c
+++ b/sound/core/device.c
@@ -45,9 +45,8 @@
 {
 	struct snd_device *dev;
 
-	snd_assert(card != NULL, return -ENXIO);
-	snd_assert(device_data != NULL, return -ENXIO);
-	snd_assert(ops != NULL, return -ENXIO);
+	if (snd_BUG_ON(!card || !device_data || !ops))
+		return -ENXIO;
 	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
 	if (dev == NULL) {
 		snd_printk(KERN_ERR "Cannot allocate device\n");
@@ -80,8 +79,8 @@
 {
 	struct snd_device *dev;
 	
-	snd_assert(card != NULL, return -ENXIO);
-	snd_assert(device_data != NULL, return -ENXIO);
+	if (snd_BUG_ON(!card || !device_data))
+		return -ENXIO;
 	list_for_each_entry(dev, &card->devices, list) {
 		if (dev->device_data != device_data)
 			continue;
@@ -123,8 +122,8 @@
 {
 	struct snd_device *dev;
 
-	snd_assert(card != NULL, return -ENXIO);
-	snd_assert(device_data != NULL, return -ENXIO);
+	if (snd_BUG_ON(!card || !device_data))
+		return -ENXIO;
 	list_for_each_entry(dev, &card->devices, list) {
 		if (dev->device_data != device_data)
 			continue;
@@ -159,8 +158,8 @@
 	struct snd_device *dev;
 	int err;
 
-	snd_assert(card != NULL, return -ENXIO);
-	snd_assert(device_data != NULL, return -ENXIO);
+	if (snd_BUG_ON(!card || !device_data))
+		return -ENXIO;
 	list_for_each_entry(dev, &card->devices, list) {
 		if (dev->device_data != device_data)
 			continue;
@@ -188,7 +187,8 @@
 	struct snd_device *dev;
 	int err;
 	
-	snd_assert(card != NULL, return -ENXIO);
+	if (snd_BUG_ON(!card))
+		return -ENXIO;
 	list_for_each_entry(dev, &card->devices, list) {
 		if (dev->state == SNDRV_DEV_BUILD && dev->ops->dev_register) {
 			if ((err = dev->ops->dev_register(dev)) < 0)
@@ -208,7 +208,8 @@
 	struct snd_device *dev;
 	int err = 0;
 
-	snd_assert(card != NULL, return -ENXIO);
+	if (snd_BUG_ON(!card))
+		return -ENXIO;
 	list_for_each_entry(dev, &card->devices, list) {
 		if (snd_device_disconnect(card, dev->device_data) < 0)
 			err = -ENXIO;
@@ -226,7 +227,8 @@
 	int err;
 	unsigned int range_low, range_high;
 
-	snd_assert(card != NULL, return -ENXIO);
+	if (snd_BUG_ON(!card))
+		return -ENXIO;
 	range_low = cmd * SNDRV_DEV_TYPE_RANGE_SIZE;
 	range_high = range_low + SNDRV_DEV_TYPE_RANGE_SIZE - 1;
       __again:
diff --git a/sound/core/hwdep.c b/sound/core/hwdep.c
index 6d6589f..195cafc 100644
--- a/sound/core/hwdep.c
+++ b/sound/core/hwdep.c
@@ -353,9 +353,10 @@
 		.dev_disconnect = snd_hwdep_dev_disconnect,
 	};
 
-	snd_assert(rhwdep != NULL, return -EINVAL);
-	*rhwdep = NULL;
-	snd_assert(card != NULL, return -ENXIO);
+	if (snd_BUG_ON(!card))
+		return -ENXIO;
+	if (rhwdep)
+		*rhwdep = NULL;
 	hwdep = kzalloc(sizeof(*hwdep), GFP_KERNEL);
 	if (hwdep == NULL) {
 		snd_printk(KERN_ERR "hwdep: cannot allocate\n");
@@ -374,13 +375,15 @@
 	}
 	init_waitqueue_head(&hwdep->open_wait);
 	mutex_init(&hwdep->open_mutex);
-	*rhwdep = hwdep;
+	if (rhwdep)
+		*rhwdep = hwdep;
 	return 0;
 }
 
 static int snd_hwdep_free(struct snd_hwdep *hwdep)
 {
-	snd_assert(hwdep != NULL, return -ENXIO);
+	if (!hwdep)
+		return 0;
 	if (hwdep->private_free)
 		hwdep->private_free(hwdep);
 	kfree(hwdep);
@@ -440,7 +443,8 @@
 {
 	struct snd_hwdep *hwdep = device->device_data;
 
-	snd_assert(hwdep != NULL, return -ENXIO);
+	if (snd_BUG_ON(!hwdep))
+		return -ENXIO;
 	mutex_lock(&register_mutex);
 	if (snd_hwdep_search(hwdep->card, hwdep->device) != hwdep) {
 		mutex_unlock(&register_mutex);
diff --git a/sound/core/info.c b/sound/core/info.c
index c67773a..527b207 100644
--- a/sound/core/info.c
+++ b/sound/core/info.c
@@ -217,7 +217,8 @@
 	loff_t pos;
 
 	data = file->private_data;
-	snd_assert(data != NULL, return -ENXIO);
+	if (snd_BUG_ON(!data))
+		return -ENXIO;
 	pos = *offset;
 	if (pos < 0 || (long) pos != pos || (ssize_t) count < 0)
 		return -EIO;
@@ -258,7 +259,8 @@
 	loff_t pos;
 
 	data = file->private_data;
-	snd_assert(data != NULL, return -ENXIO);
+	if (snd_BUG_ON(!data))
+		return -ENXIO;
 	entry = data->entry;
 	pos = *offset;
 	if (pos < 0 || (long) pos != pos || (ssize_t) count < 0)
@@ -614,7 +616,8 @@
 	char str[8];
 	struct snd_info_entry *entry;
 
-	snd_assert(card != NULL, return -ENXIO);
+	if (snd_BUG_ON(!card))
+		return -ENXIO;
 
 	sprintf(str, "card%i", card->number);
 	if ((entry = snd_info_create_module_entry(card->module, str, NULL)) == NULL)
@@ -636,7 +639,8 @@
 {
 	struct proc_dir_entry *p;
 
-	snd_assert(card != NULL, return -ENXIO);
+	if (snd_BUG_ON(!card))
+		return -ENXIO;
 
 	if (!strcmp(card->id, card->proc_root->name))
 		return 0;
@@ -654,7 +658,8 @@
  */
 void snd_info_card_disconnect(struct snd_card *card)
 {
-	snd_assert(card != NULL, return);
+	if (!card)
+		return;
 	mutex_lock(&info_mutex);
 	if (card->proc_root_link) {
 		snd_remove_proc_entry(snd_proc_root, card->proc_root_link);
@@ -671,7 +676,8 @@
  */
 int snd_info_card_free(struct snd_card *card)
 {
-	snd_assert(card != NULL, return -ENXIO);
+	if (!card)
+		return 0;
 	snd_info_free_entry(card->proc_root);
 	card->proc_root = NULL;
 	return 0;
@@ -849,7 +855,7 @@
 		return;
 	list_del_init(&entry->list);
 	root = entry->parent == NULL ? snd_proc_root : entry->parent->p;
-	snd_assert(root, return);
+	snd_BUG_ON(!root);
 	snd_remove_proc_entry(root, entry->p);
 	entry->p = NULL;
 }
@@ -947,7 +953,8 @@
 {
 	struct proc_dir_entry *root, *p = NULL;
 
-	snd_assert(entry != NULL, return -ENXIO);
+	if (snd_BUG_ON(!entry))
+		return -ENXIO;
 	root = entry->parent == NULL ? snd_proc_root : entry->parent->p;
 	mutex_lock(&info_mutex);
 	p = snd_create_proc_entry(entry->name, entry->mode, root);
diff --git a/sound/core/info_oss.c b/sound/core/info_oss.c
index e35789a..e4af138 100644
--- a/sound/core/info_oss.c
+++ b/sound/core/info_oss.c
@@ -43,8 +43,10 @@
 {
 	char *x;
 
-	snd_assert(dev >= 0 && dev < SNDRV_OSS_INFO_DEV_COUNT, return -ENXIO);
-	snd_assert(num >= 0 && num < SNDRV_CARDS, return -ENXIO);
+	if (snd_BUG_ON(dev < 0 || dev >= SNDRV_OSS_INFO_DEV_COUNT))
+		return -ENXIO;
+	if (snd_BUG_ON(num < 0 || num >= SNDRV_CARDS))
+		return -ENXIO;
 	mutex_lock(&strings);
 	if (string == NULL) {
 		if ((x = snd_sndstat_strings[num][dev]) != NULL) {
diff --git a/sound/core/init.c b/sound/core/init.c
index df46bbc..8af467d 100644
--- a/sound/core/init.c
+++ b/sound/core/init.c
@@ -545,7 +545,8 @@
 {
 	int err;
 
-	snd_assert(card != NULL, return -EINVAL);
+	if (snd_BUG_ON(!card))
+		return -EINVAL;
 #ifndef CONFIG_SYSFS_DEPRECATED
 	if (!card->card_dev) {
 		card->card_dev = device_create_drvdata(sound_class, card->dev,
diff --git a/sound/core/jack.c b/sound/core/jack.c
new file mode 100644
index 0000000..8133a2b
--- /dev/null
+++ b/sound/core/jack.c
@@ -0,0 +1,163 @@
+/*
+ *  Jack abstraction layer
+ *
+ *  Copyright 2008 Wolfson Microelectronics
+ *
+ *   This program is free software; you can redistribute it and/or 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/input.h>
+#include <sound/jack.h>
+#include <sound/core.h>
+
+static int snd_jack_dev_free(struct snd_device *device)
+{
+	struct snd_jack *jack = device->device_data;
+
+	/* If the input device is registered with the input subsystem
+	 * then we need to use a different deallocator. */
+	if (jack->registered)
+		input_unregister_device(jack->input_dev);
+	else
+		input_free_device(jack->input_dev);
+
+	kfree(jack);
+
+	return 0;
+}
+
+static int snd_jack_dev_register(struct snd_device *device)
+{
+	struct snd_jack *jack = device->device_data;
+	struct snd_card *card = device->card;
+	int err;
+
+	snprintf(jack->name, sizeof(jack->name), "%s %s",
+		 card->longname, jack->id);
+	jack->input_dev->name = jack->name;
+
+	/* Default to the sound card device. */
+	if (!jack->input_dev->dev.parent)
+		jack->input_dev->dev.parent = card->dev;
+
+	err = input_register_device(jack->input_dev);
+	if (err == 0)
+		jack->registered = 1;
+
+	return err;
+}
+
+/**
+ * snd_jack_new - Create a new jack
+ * @card:  the card instance
+ * @id:    an identifying string for this jack
+ * @type:  a bitmask of enum snd_jack_type values that can be detected by
+ *         this jack
+ * @jjack: Used to provide the allocated jack object to the caller.
+ *
+ * Creates a new jack object.
+ *
+ * Returns zero if successful, or a negative error code on failure.
+ * On success jjack will be initialised.
+ */
+int snd_jack_new(struct snd_card *card, const char *id, int type,
+		 struct snd_jack **jjack)
+{
+	struct snd_jack *jack;
+	int err;
+	static struct snd_device_ops ops = {
+		.dev_free = snd_jack_dev_free,
+		.dev_register = snd_jack_dev_register,
+	};
+
+	jack = kzalloc(sizeof(struct snd_jack), GFP_KERNEL);
+	if (jack == NULL)
+		return -ENOMEM;
+
+	jack->id = id;
+
+	jack->input_dev = input_allocate_device();
+	if (jack->input_dev == NULL) {
+		err = -ENOMEM;
+		goto fail_input;
+	}
+
+	jack->input_dev->phys = "ALSA";
+
+	jack->type = type;
+
+	if (type & SND_JACK_HEADPHONE)
+		input_set_capability(jack->input_dev, EV_SW,
+				     SW_HEADPHONE_INSERT);
+	if (type & SND_JACK_MICROPHONE)
+		input_set_capability(jack->input_dev, EV_SW,
+				     SW_MICROPHONE_INSERT);
+
+	err = snd_device_new(card, SNDRV_DEV_JACK, jack, &ops);
+	if (err < 0)
+		goto fail_input;
+
+	*jjack = jack;
+
+	return 0;
+
+fail_input:
+	input_free_device(jack->input_dev);
+	kfree(jack);
+	return err;
+}
+EXPORT_SYMBOL(snd_jack_new);
+
+/**
+ * snd_jack_set_parent - Set the parent device for a jack
+ *
+ * @jack:   The jack to configure
+ * @parent: The device to set as parent for the jack.
+ *
+ * Set the parent for the jack input device in the device tree.  This
+ * function is only valid prior to registration of the jack.  If no
+ * parent is configured then the parent device will be the sound card.
+ */
+void snd_jack_set_parent(struct snd_jack *jack, struct device *parent)
+{
+	WARN_ON(jack->registered);
+
+	jack->input_dev->dev.parent = parent;
+}
+EXPORT_SYMBOL(snd_jack_set_parent);
+
+/**
+ * snd_jack_report - Report the current status of a jack
+ *
+ * @jack:   The jack to report status for
+ * @status: The current status of the jack
+ */
+void snd_jack_report(struct snd_jack *jack, int status)
+{
+	if (jack->type & SND_JACK_HEADPHONE)
+		input_report_switch(jack->input_dev, SW_HEADPHONE_INSERT,
+				    status & SND_JACK_HEADPHONE);
+	if (jack->type & SND_JACK_MICROPHONE)
+		input_report_switch(jack->input_dev, SW_MICROPHONE_INSERT,
+				    status & SND_JACK_MICROPHONE);
+
+	input_sync(jack->input_dev);
+}
+EXPORT_SYMBOL(snd_jack_report);
+
+MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
+MODULE_DESCRIPTION("Jack detection support for ALSA");
+MODULE_LICENSE("GPL");
diff --git a/sound/core/memalloc.c b/sound/core/memalloc.c
index f5d6d8d..1b3534d 100644
--- a/sound/core/memalloc.c
+++ b/sound/core/memalloc.c
@@ -33,9 +33,6 @@
 #include <linux/moduleparam.h>
 #include <linux/mutex.h>
 #include <sound/memalloc.h>
-#ifdef CONFIG_SBUS
-#include <asm/sbus.h>
-#endif
 
 
 MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>, Jaroslav Kysela <perex@perex.cz>");
@@ -46,14 +43,6 @@
 /*
  */
 
-void *snd_malloc_sgbuf_pages(struct device *device,
-                             size_t size, struct snd_dma_buffer *dmab,
-			     size_t *res_size);
-int snd_free_sgbuf_pages(struct snd_dma_buffer *dmab);
-
-/*
- */
-
 static DEFINE_MUTEX(list_mutex);
 static LIST_HEAD(mem_list_head);
 
@@ -67,18 +56,6 @@
 /* id for pre-allocated buffers */
 #define SNDRV_DMA_DEVICE_UNUSED (unsigned int)-1
 
-#ifdef CONFIG_SND_DEBUG
-#define __ASTRING__(x) #x
-#define snd_assert(expr, args...) do {\
-	if (!(expr)) {\
-		printk(KERN_ERR "snd-malloc: BUG? (%s) (called from %p)\n", __ASTRING__(expr), __builtin_return_address(0));\
-		args;\
-	}\
-} while (0)
-#else
-#define snd_assert(expr, args...) /**/
-#endif
-
 /*
  *
  *  Generic memory allocators
@@ -111,8 +88,10 @@
 	int pg;
 	void *res;
 
-	snd_assert(size > 0, return NULL);
-	snd_assert(gfp_flags != 0, return NULL);
+	if (WARN_ON(!size))
+		return NULL;
+	if (WARN_ON(!gfp_flags))
+		return NULL;
 	gfp_flags |= __GFP_COMP;	/* compound page lets parts be mapped */
 	pg = get_order(size);
 	if ((res = (void *) __get_free_pages(gfp_flags, pg)) != NULL)
@@ -152,8 +131,8 @@
 	void *res;
 	gfp_t gfp_flags;
 
-	snd_assert(size > 0, return NULL);
-	snd_assert(dma != NULL, return NULL);
+	if (WARN_ON(!dma))
+		return NULL;
 	pg = get_order(size);
 	gfp_flags = GFP_KERNEL
 		| __GFP_COMP	/* compound page lets parts be mapped */
@@ -180,39 +159,6 @@
 }
 #endif /* CONFIG_HAS_DMA */
 
-#ifdef CONFIG_SBUS
-
-static void *snd_malloc_sbus_pages(struct device *dev, size_t size,
-				   dma_addr_t *dma_addr)
-{
-	struct sbus_dev *sdev = (struct sbus_dev *)dev;
-	int pg;
-	void *res;
-
-	snd_assert(size > 0, return NULL);
-	snd_assert(dma_addr != NULL, return NULL);
-	pg = get_order(size);
-	res = sbus_alloc_consistent(sdev, PAGE_SIZE * (1 << pg), dma_addr);
-	if (res != NULL)
-		inc_snd_pages(pg);
-	return res;
-}
-
-static void snd_free_sbus_pages(struct device *dev, size_t size,
-				void *ptr, dma_addr_t dma_addr)
-{
-	struct sbus_dev *sdev = (struct sbus_dev *)dev;
-	int pg;
-
-	if (ptr == NULL)
-		return;
-	pg = get_order(size);
-	dec_snd_pages(pg);
-	sbus_free_consistent(sdev, PAGE_SIZE * (1 << pg), ptr, dma_addr);
-}
-
-#endif /* CONFIG_SBUS */
-
 /*
  *
  *  ALSA generic memory management
@@ -236,8 +182,10 @@
 int snd_dma_alloc_pages(int type, struct device *device, size_t size,
 			struct snd_dma_buffer *dmab)
 {
-	snd_assert(size > 0, return -ENXIO);
-	snd_assert(dmab != NULL, return -ENXIO);
+	if (WARN_ON(!size))
+		return -ENXIO;
+	if (WARN_ON(!dmab))
+		return -ENXIO;
 
 	dmab->dev.type = type;
 	dmab->dev.dev = device;
@@ -247,11 +195,6 @@
 		dmab->area = snd_malloc_pages(size, (unsigned long)device);
 		dmab->addr = 0;
 		break;
-#ifdef CONFIG_SBUS
-	case SNDRV_DMA_TYPE_SBUS:
-		dmab->area = snd_malloc_sbus_pages(device, size, &dmab->addr);
-		break;
-#endif
 #ifdef CONFIG_HAS_DMA
 	case SNDRV_DMA_TYPE_DEV:
 		dmab->area = snd_malloc_dev_pages(device, size, &dmab->addr);
@@ -292,15 +235,17 @@
 {
 	int err;
 
-	snd_assert(size > 0, return -ENXIO);
-	snd_assert(dmab != NULL, return -ENXIO);
-
 	while ((err = snd_dma_alloc_pages(type, device, size, dmab)) < 0) {
+		size_t aligned_size;
 		if (err != -ENOMEM)
 			return err;
-		size >>= 1;
 		if (size <= PAGE_SIZE)
 			return -ENOMEM;
+		aligned_size = PAGE_SIZE << get_order(size);
+		if (size != aligned_size)
+			size = aligned_size;
+		else
+			size >>= 1;
 	}
 	if (! dmab->area)
 		return -ENOMEM;
@@ -320,11 +265,6 @@
 	case SNDRV_DMA_TYPE_CONTINUOUS:
 		snd_free_pages(dmab->area, dmab->bytes);
 		break;
-#ifdef CONFIG_SBUS
-	case SNDRV_DMA_TYPE_SBUS:
-		snd_free_sbus_pages(dmab->dev.dev, dmab->bytes, dmab->area, dmab->addr);
-		break;
-#endif
 #ifdef CONFIG_HAS_DMA
 	case SNDRV_DMA_TYPE_DEV:
 		snd_free_dev_pages(dmab->dev.dev, dmab->bytes, dmab->area, dmab->addr);
@@ -353,7 +293,8 @@
 {
 	struct snd_mem_list *mem;
 
-	snd_assert(dmab, return 0);
+	if (WARN_ON(!dmab))
+		return 0;
 
 	mutex_lock(&list_mutex);
 	list_for_each_entry(mem, &mem_list_head, list) {
@@ -387,7 +328,8 @@
 {
 	struct snd_mem_list *mem;
 
-	snd_assert(dmab, return -EINVAL);
+	if (WARN_ON(!dmab))
+		return -EINVAL;
 	mem = kmalloc(sizeof(*mem), GFP_KERNEL);
 	if (! mem)
 		return -ENOMEM;
@@ -431,7 +373,7 @@
 	long pages = snd_allocated_pages >> (PAGE_SHIFT-12);
 	struct snd_mem_list *mem;
 	int devno;
-	static char *types[] = { "UNKNOWN", "CONT", "DEV", "DEV-SG", "SBUS" };
+	static char *types[] = { "UNKNOWN", "CONT", "DEV", "DEV-SG" };
 
 	mutex_lock(&list_mutex);
 	seq_printf(seq, "pages  : %li bytes (%li pages per %likB)\n",
diff --git a/sound/core/oss/copy.c b/sound/core/oss/copy.c
index 9ded30d..05b58d4 100644
--- a/sound/core/oss/copy.c
+++ b/sound/core/oss/copy.c
@@ -32,17 +32,18 @@
 	unsigned int channel;
 	unsigned int nchannels;
 
-	snd_assert(plugin != NULL && src_channels != NULL && dst_channels != NULL, return -ENXIO);
+	if (snd_BUG_ON(!plugin || !src_channels || !dst_channels))
+		return -ENXIO;
 	if (frames == 0)
 		return 0;
 	nchannels = plugin->src_format.channels;
 	for (channel = 0; channel < nchannels; channel++) {
-		snd_assert(src_channels->area.first % 8 == 0 &&
-			   src_channels->area.step % 8 == 0,
-			   return -ENXIO);
-		snd_assert(dst_channels->area.first % 8 == 0 &&
-			   dst_channels->area.step % 8 == 0,
-			   return -ENXIO);
+		if (snd_BUG_ON(src_channels->area.first % 8 ||
+			       src_channels->area.step % 8))
+			return -ENXIO;
+		if (snd_BUG_ON(dst_channels->area.first % 8 ||
+			       dst_channels->area.step % 8))
+			return -ENXIO;
 		if (!src_channels->enabled) {
 			if (dst_channels->wanted)
 				snd_pcm_area_silence(&dst_channels->area, 0, frames, plugin->dst_format.format);
@@ -66,15 +67,20 @@
 	struct snd_pcm_plugin *plugin;
 	int width;
 
-	snd_assert(r_plugin != NULL, return -ENXIO);
+	if (snd_BUG_ON(!r_plugin))
+		return -ENXIO;
 	*r_plugin = NULL;
 
-	snd_assert(src_format->format == dst_format->format, return -ENXIO);
-	snd_assert(src_format->rate == dst_format->rate, return -ENXIO);
-	snd_assert(src_format->channels == dst_format->channels, return -ENXIO);
+	if (snd_BUG_ON(src_format->format != dst_format->format))
+		return -ENXIO;
+	if (snd_BUG_ON(src_format->rate != dst_format->rate))
+		return -ENXIO;
+	if (snd_BUG_ON(src_format->channels != dst_format->channels))
+		return -ENXIO;
 
 	width = snd_pcm_format_physical_width(src_format->format);
-	snd_assert(width > 0, return -ENXIO);
+	if (snd_BUG_ON(width <= 0))
+		return -ENXIO;
 
 	err = snd_pcm_plugin_build(plug, "copy", src_format, dst_format,
 				   0, &plugin);
diff --git a/sound/core/oss/io.c b/sound/core/oss/io.c
index f874f6c..6faa1d71 100644
--- a/sound/core/oss/io.c
+++ b/sound/core/oss/io.c
@@ -39,14 +39,17 @@
 				    struct snd_pcm_plugin_channel *dst_channels,
 				    snd_pcm_uframes_t frames)
 {
-	snd_assert(plugin != NULL, return -ENXIO);
-	snd_assert(src_channels != NULL, return -ENXIO);
+	if (snd_BUG_ON(!plugin))
+		return -ENXIO;
+	if (snd_BUG_ON(!src_channels))
+		return -ENXIO;
 	if (plugin->access == SNDRV_PCM_ACCESS_RW_INTERLEAVED) {
 		return pcm_write(plugin->plug, src_channels->area.addr, frames);
 	} else {
 		int channel, channels = plugin->dst_format.channels;
 		void **bufs = (void**)plugin->extra_data;
-		snd_assert(bufs != NULL, return -ENXIO);
+		if (snd_BUG_ON(!bufs))
+			return -ENXIO;
 		for (channel = 0; channel < channels; channel++) {
 			if (src_channels[channel].enabled)
 				bufs[channel] = src_channels[channel].area.addr;
@@ -62,14 +65,17 @@
 				   struct snd_pcm_plugin_channel *dst_channels,
 				   snd_pcm_uframes_t frames)
 {
-	snd_assert(plugin != NULL, return -ENXIO);
-	snd_assert(dst_channels != NULL, return -ENXIO);
+	if (snd_BUG_ON(!plugin))
+		return -ENXIO;
+	if (snd_BUG_ON(!dst_channels))
+		return -ENXIO;
 	if (plugin->access == SNDRV_PCM_ACCESS_RW_INTERLEAVED) {
 		return pcm_read(plugin->plug, dst_channels->area.addr, frames);
 	} else {
 		int channel, channels = plugin->dst_format.channels;
 		void **bufs = (void**)plugin->extra_data;
-		snd_assert(bufs != NULL, return -ENXIO);
+		if (snd_BUG_ON(!bufs))
+			return -ENXIO;
 		for (channel = 0; channel < channels; channel++) {
 			if (dst_channels[channel].enabled)
 				bufs[channel] = dst_channels[channel].area.addr;
@@ -107,9 +113,11 @@
 	struct snd_pcm_plugin_format format;
 	struct snd_pcm_plugin *plugin;
 
-	snd_assert(r_plugin != NULL, return -ENXIO);
+	if (snd_BUG_ON(!r_plugin))
+		return -ENXIO;
 	*r_plugin = NULL;
-	snd_assert(plug != NULL && params != NULL, return -ENXIO);
+	if (snd_BUG_ON(!plug || !params))
+		return -ENXIO;
 	format.format = params_format(params);
 	format.rate = params_rate(params);
 	format.channels = params_channels(params);
diff --git a/sound/core/oss/linear.c b/sound/core/oss/linear.c
index da3dbd4..4c1d168 100644
--- a/sound/core/oss/linear.c
+++ b/sound/core/oss/linear.c
@@ -92,7 +92,8 @@
 {
 	struct linear_priv *data;
 
-	snd_assert(plugin != NULL && src_channels != NULL && dst_channels != NULL, return -ENXIO);
+	if (snd_BUG_ON(!plugin || !src_channels || !dst_channels))
+		return -ENXIO;
 	data = (struct linear_priv *)plugin->extra_data;
 	if (frames == 0)
 		return 0;
@@ -100,12 +101,12 @@
 	{
 		unsigned int channel;
 		for (channel = 0; channel < plugin->src_format.channels; channel++) {
-			snd_assert(src_channels[channel].area.first % 8 == 0 &&
-				   src_channels[channel].area.step % 8 == 0,
-				   return -ENXIO);
-			snd_assert(dst_channels[channel].area.first % 8 == 0 &&
-				   dst_channels[channel].area.step % 8 == 0,
-				   return -ENXIO);
+			if (snd_BUG_ON(src_channels[channel].area.first % 8 ||
+				       src_channels[channel].area.step % 8))
+				return -ENXIO;
+			if (snd_BUG_ON(dst_channels[channel].area.first % 8 ||
+				       dst_channels[channel].area.step % 8))
+				return -ENXIO;
 		}
 	}
 #endif
@@ -154,13 +155,17 @@
 	struct linear_priv *data;
 	struct snd_pcm_plugin *plugin;
 
-	snd_assert(r_plugin != NULL, return -ENXIO);
+	if (snd_BUG_ON(!r_plugin))
+		return -ENXIO;
 	*r_plugin = NULL;
 
-	snd_assert(src_format->rate == dst_format->rate, return -ENXIO);
-	snd_assert(src_format->channels == dst_format->channels, return -ENXIO);
-	snd_assert(snd_pcm_format_linear(src_format->format) &&
-		   snd_pcm_format_linear(dst_format->format), return -ENXIO);
+	if (snd_BUG_ON(src_format->rate != dst_format->rate))
+		return -ENXIO;
+	if (snd_BUG_ON(src_format->channels != dst_format->channels))
+		return -ENXIO;
+	if (snd_BUG_ON(!snd_pcm_format_linear(src_format->format) ||
+		       !snd_pcm_format_linear(dst_format->format)))
+		return -ENXIO;
 
 	err = snd_pcm_plugin_build(plug, "linear format conversion",
 				   src_format, dst_format,
diff --git a/sound/core/oss/mixer_oss.c b/sound/core/oss/mixer_oss.c
index 581aa2c..4690b8b 100644
--- a/sound/core/oss/mixer_oss.c
+++ b/sound/core/oss/mixer_oss.c
@@ -257,8 +257,10 @@
 		result = pslot->get_volume(fmixer, pslot, &left, &right);
 	if (!pslot->stereo)
 		right = left;
-	snd_assert(left >= 0 && left <= 100, return -EIO);
-	snd_assert(right >= 0 && right <= 100, return -EIO);
+	if (snd_BUG_ON(left < 0 || left > 100))
+		return -EIO;
+	if (snd_BUG_ON(right < 0 || right > 100))
+		return -EIO;
 	if (result >= 0) {
 		pslot->volume[0] = left;
 		pslot->volume[1] = right;
@@ -298,7 +300,8 @@
 	int __user *p = argp;
 	int tmp;
 
-	snd_assert(fmixer != NULL, return -ENXIO);
+	if (snd_BUG_ON(!fmixer))
+		return -ENXIO;
 	if (((cmd >> 8) & 0xff) == 'M') {
 		switch (cmd) {
 		case SOUND_MIXER_INFO:
@@ -368,7 +371,8 @@
 {
 	struct snd_mixer_oss_file fmixer;
 	
-	snd_assert(card != NULL, return -ENXIO);
+	if (snd_BUG_ON(!card))
+		return -ENXIO;
 	if (card->mixer_oss == NULL)
 		return -ENXIO;
 	memset(&fmixer, 0, sizeof(fmixer));
@@ -1284,9 +1288,11 @@
 	struct snd_card *card;
 	int idx;
  
-	snd_assert(mixer != NULL, return -ENXIO);
+	if (!mixer)
+		return 0;
 	card = mixer->card;
-	snd_assert(mixer == card->mixer_oss, return -ENXIO);
+	if (snd_BUG_ON(mixer != card->mixer_oss))
+		return -ENXIO;
 	card->mixer_oss = NULL;
 	for (idx = 0; idx < SNDRV_OSS_MAX_MIXERS; idx++) {
 		struct snd_mixer_oss_slot *chn = &mixer->slots[idx];
diff --git a/sound/core/oss/mulaw.c b/sound/core/oss/mulaw.c
index 77f9619..f7649d4 100644
--- a/sound/core/oss/mulaw.c
+++ b/sound/core/oss/mulaw.c
@@ -252,19 +252,20 @@
 {
 	struct mulaw_priv *data;
 
-	snd_assert(plugin != NULL && src_channels != NULL && dst_channels != NULL, return -ENXIO);
+	if (snd_BUG_ON(!plugin || !src_channels || !dst_channels))
+		return -ENXIO;
 	if (frames == 0)
 		return 0;
 #ifdef CONFIG_SND_DEBUG
 	{
 		unsigned int channel;
 		for (channel = 0; channel < plugin->src_format.channels; channel++) {
-			snd_assert(src_channels[channel].area.first % 8 == 0 &&
-				   src_channels[channel].area.step % 8 == 0,
-				   return -ENXIO);
-			snd_assert(dst_channels[channel].area.first % 8 == 0 &&
-				   dst_channels[channel].area.step % 8 == 0,
-				   return -ENXIO);
+			if (snd_BUG_ON(src_channels[channel].area.first % 8 ||
+				       src_channels[channel].area.step % 8))
+				return -ENXIO;
+			if (snd_BUG_ON(dst_channels[channel].area.first % 8 ||
+				       dst_channels[channel].area.step % 8))
+				return -ENXIO;
 		}
 	}
 #endif
@@ -305,11 +306,14 @@
 	struct snd_pcm_plugin_format *format;
 	mulaw_f func;
 
-	snd_assert(r_plugin != NULL, return -ENXIO);
+	if (snd_BUG_ON(!r_plugin))
+		return -ENXIO;
 	*r_plugin = NULL;
 
-	snd_assert(src_format->rate == dst_format->rate, return -ENXIO);
-	snd_assert(src_format->channels == dst_format->channels, return -ENXIO);
+	if (snd_BUG_ON(src_format->rate != dst_format->rate))
+		return -ENXIO;
+	if (snd_BUG_ON(src_format->channels != dst_format->channels))
+		return -ENXIO;
 
 	if (dst_format->format == SNDRV_PCM_FORMAT_MU_LAW) {
 		format = src_format;
@@ -323,7 +327,8 @@
 		snd_BUG();
 		return -EINVAL;
 	}
-	snd_assert(snd_pcm_format_linear(format->format) != 0, return -ENXIO);
+	if (snd_BUG_ON(!snd_pcm_format_linear(format->format)))
+		return -ENXIO;
 
 	err = snd_pcm_plugin_build(plug, "Mu-Law<->linear conversion",
 				   src_format, dst_format,
diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c
index 4c601b1..1af62b8 100644
--- a/sound/core/oss/pcm_oss.c
+++ b/sound/core/oss/pcm_oss.c
@@ -452,7 +452,8 @@
 	} else {
 		*params = *save;
 		max = snd_pcm_hw_param_max(pcm, params, var, max, &maxdir);
-		snd_assert(max >= 0, return -EINVAL);
+		if (max < 0)
+			return max;
 		last = 1;
 	}
  _end:
@@ -461,7 +462,7 @@
 		v = snd_pcm_hw_param_last(pcm, params, var, dir);
 	else
 		v = snd_pcm_hw_param_first(pcm, params, var, dir);
-	snd_assert(v >= 0, return -EINVAL);
+	snd_BUG_ON(v < 0);
 	return v;
 }
 
@@ -778,7 +779,8 @@
 	while (oss_period_size * oss_periods > oss_buffer_size)
 		oss_period_size /= 2;
 
-	snd_assert(oss_period_size >= 16, return -EINVAL);
+	if (oss_period_size < 16)
+		return -EINVAL;
 	runtime->oss.period_bytes = oss_period_size;
 	runtime->oss.period_frames = 1;
 	runtime->oss.periods = oss_periods;
@@ -895,7 +897,8 @@
 		}
 	}
 	err = _snd_pcm_hw_param_set(sparams, SNDRV_PCM_HW_PARAM_FORMAT, sformat, 0);
-	snd_assert(err >= 0, goto failure);
+	if (err < 0)
+		goto failure;
 
 	if (direct) {
 		memcpy(params, sparams, sizeof(*params));
@@ -958,11 +961,13 @@
 
 	n = snd_pcm_plug_slave_size(substream, runtime->oss.period_bytes / oss_frame_size);
 	err = snd_pcm_hw_param_near(substream, sparams, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, n, NULL);
-	snd_assert(err >= 0, goto failure);
+	if (err < 0)
+		goto failure;
 
 	err = snd_pcm_hw_param_near(substream, sparams, SNDRV_PCM_HW_PARAM_PERIODS,
 				     runtime->oss.periods, NULL);
-	snd_assert(err >= 0, goto failure);
+	if (err < 0)
+		goto failure;
 
 	snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DROP, NULL);
 
@@ -1006,7 +1011,10 @@
 
 	runtime->oss.periods = params_periods(sparams);
 	oss_period_size = snd_pcm_plug_client_size(substream, params_period_size(sparams));
-	snd_assert(oss_period_size >= 0, err = -EINVAL; goto failure);
+	if (oss_period_size < 0) {
+		err = -EINVAL;
+		goto failure;
+	}
 #ifdef CONFIG_SND_PCM_OSS_PLUGINS
 	if (runtime->oss.plugin_first) {
 		err = snd_pcm_plug_alloc(substream, oss_period_size);
@@ -1017,7 +1025,10 @@
 	oss_period_size *= oss_frame_size;
 
 	oss_buffer_size = oss_period_size * runtime->oss.periods;
-	snd_assert(oss_buffer_size >= 0, err = -EINVAL; goto failure);
+	if (oss_buffer_size < 0) {
+		err = -EINVAL;
+		goto failure;
+	}
 
 	runtime->oss.period_bytes = oss_period_size;
 	runtime->oss.buffer_bytes = oss_buffer_size;
@@ -1069,7 +1080,8 @@
 				return err;
 		}
 	}
-	snd_assert(asubstream != NULL, return -EIO);
+	if (!asubstream)
+		return -EIO;
 	if (r_substream)
 		*r_substream = asubstream;
 	return 0;
@@ -1764,7 +1776,8 @@
 	err = snd_pcm_hw_refine(substream, params);
 	format_mask = *hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); 
 	kfree(params);
-	snd_assert(err >= 0, return err);
+	if (err < 0)
+		return err;
 	for (fmt = 0; fmt < 32; ++fmt) {
 		if (snd_mask_test(&format_mask, fmt)) {
 			int f = snd_pcm_oss_format_to(fmt);
@@ -2250,7 +2263,8 @@
 static int snd_pcm_oss_release_file(struct snd_pcm_oss_file *pcm_oss_file)
 {
 	int cidx;
-	snd_assert(pcm_oss_file != NULL, return -ENXIO);
+	if (!pcm_oss_file)
+		return 0;
 	for (cidx = 0; cidx < 2; ++cidx) {
 		struct snd_pcm_substream *substream = pcm_oss_file->streams[cidx];
 		if (substream)
@@ -2271,8 +2285,8 @@
 	struct snd_pcm_substream *substream;
 	unsigned int f_mode = file->f_mode;
 
-	snd_assert(rpcm_oss_file != NULL, return -EINVAL);
-	*rpcm_oss_file = NULL;
+	if (rpcm_oss_file)
+		*rpcm_oss_file = NULL;
 
 	pcm_oss_file = kzalloc(sizeof(*pcm_oss_file), GFP_KERNEL);
 	if (pcm_oss_file == NULL)
@@ -2312,7 +2326,8 @@
 	}
 
 	file->private_data = pcm_oss_file;
-	*rpcm_oss_file = pcm_oss_file;
+	if (rpcm_oss_file)
+		*rpcm_oss_file = pcm_oss_file;
 	return 0;
 }
 
@@ -2321,7 +2336,8 @@
 {
 	unsigned int idx;
 
-	snd_assert(task != NULL && name != NULL && size >= 2, return -EINVAL);
+	if (snd_BUG_ON(!task || !name || size < 2))
+		return -EINVAL;
 	for (idx = 0; idx < sizeof(task->comm) && idx + 1 < size; idx++)
 		name[idx] = task->comm[idx];
 	name[idx] = '\0';
@@ -2415,7 +2431,8 @@
 	substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK];
 	if (substream == NULL)
 		substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_CAPTURE];
-	snd_assert(substream != NULL, return -ENXIO);
+	if (snd_BUG_ON(!substream))
+		return -ENXIO;
 	pcm = substream->pcm;
 	if (!pcm->card->shutdown)
 		snd_pcm_oss_sync(pcm_oss_file);
@@ -2448,7 +2465,8 @@
 			if (substream != NULL)
 				break;
 		}
-		snd_assert(substream != NULL, return -ENXIO);
+		if (snd_BUG_ON(idx >= 2))
+			return -ENXIO;
 		return snd_mixer_oss_ioctl_card(substream->pcm->card, cmd, arg);
 	}
 #endif
diff --git a/sound/core/oss/pcm_plugin.c b/sound/core/oss/pcm_plugin.c
index bec9413..6751daa 100644
--- a/sound/core/oss/pcm_plugin.c
+++ b/sound/core/oss/pcm_plugin.c
@@ -62,7 +62,8 @@
 	if ((width = snd_pcm_format_physical_width(format->format)) < 0)
 		return width;
 	size = frames * format->channels * width;
-	snd_assert((size % 8) == 0, return -ENXIO);
+	if (snd_BUG_ON(size % 8))
+		return -ENXIO;
 	size /= 8;
 	if (plugin->buf_frames < frames) {
 		vfree(plugin->buf);
@@ -84,7 +85,8 @@
 			c->area.step = format->channels * width;
 		}
 	} else if (plugin->access == SNDRV_PCM_ACCESS_RW_NONINTERLEAVED) {
-		snd_assert((size % format->channels) == 0,);
+		if (snd_BUG_ON(size % format->channels))
+			return -EINVAL;
 		size /= format->channels;
 		for (channel = 0; channel < format->channels; channel++, c++) {
 			c->frames = frames;
@@ -102,13 +104,15 @@
 int snd_pcm_plug_alloc(struct snd_pcm_substream *plug, snd_pcm_uframes_t frames)
 {
 	int err;
-	snd_assert(snd_pcm_plug_first(plug) != NULL, return -ENXIO);
+	if (snd_BUG_ON(!snd_pcm_plug_first(plug)))
+		return -ENXIO;
 	if (snd_pcm_plug_stream(plug) == SNDRV_PCM_STREAM_PLAYBACK) {
 		struct snd_pcm_plugin *plugin = snd_pcm_plug_first(plug);
 		while (plugin->next) {
 			if (plugin->dst_frames)
 				frames = plugin->dst_frames(plugin, frames);
-			snd_assert(frames > 0, return -ENXIO);
+			if (snd_BUG_ON(frames <= 0))
+				return -ENXIO;
 			plugin = plugin->next;
 			err = snd_pcm_plugin_alloc(plugin, frames);
 			if (err < 0)
@@ -119,7 +123,8 @@
 		while (plugin->prev) {
 			if (plugin->src_frames)
 				frames = plugin->src_frames(plugin, frames);
-			snd_assert(frames > 0, return -ENXIO);
+			if (snd_BUG_ON(frames <= 0))
+				return -ENXIO;
 			plugin = plugin->prev;
 			err = snd_pcm_plugin_alloc(plugin, frames);
 			if (err < 0)
@@ -148,8 +153,10 @@
 	struct snd_pcm_plugin *plugin;
 	unsigned int channels;
 	
-	snd_assert(plug != NULL, return -ENXIO);
-	snd_assert(src_format != NULL && dst_format != NULL, return -ENXIO);
+	if (snd_BUG_ON(!plug))
+		return -ENXIO;
+	if (snd_BUG_ON(!src_format || !dst_format))
+		return -ENXIO;
 	plugin = kzalloc(sizeof(*plugin) + extra, GFP_KERNEL);
 	if (plugin == NULL)
 		return -ENOMEM;
@@ -159,10 +166,10 @@
 	plugin->access = SNDRV_PCM_ACCESS_RW_INTERLEAVED;
 	plugin->src_format = *src_format;
 	plugin->src_width = snd_pcm_format_physical_width(src_format->format);
-	snd_assert(plugin->src_width > 0, );
+	snd_BUG_ON(plugin->src_width <= 0);
 	plugin->dst_format = *dst_format;
 	plugin->dst_width = snd_pcm_format_physical_width(dst_format->format);
-	snd_assert(plugin->dst_width > 0, );
+	snd_BUG_ON(plugin->dst_width <= 0);
 	if (plugin->stream == SNDRV_PCM_STREAM_PLAYBACK)
 		channels = src_format->channels;
 	else
@@ -194,7 +201,8 @@
 	struct snd_pcm_plugin *plugin, *plugin_prev, *plugin_next;
 	int stream = snd_pcm_plug_stream(plug);
 
-	snd_assert(plug != NULL, return -ENXIO);
+	if (snd_BUG_ON(!plug))
+		return -ENXIO;
 	if (drv_frames == 0)
 		return 0;
 	if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
@@ -224,7 +232,8 @@
 	snd_pcm_sframes_t frames;
 	int stream = snd_pcm_plug_stream(plug);
 	
-	snd_assert(plug != NULL, return -ENXIO);
+	if (snd_BUG_ON(!plug))
+		return -ENXIO;
 	if (clt_frames == 0)
 		return 0;
 	frames = clt_frames;
@@ -540,7 +549,8 @@
 	int width, nchannels, channel;
 	int stream = snd_pcm_plug_stream(plug);
 
-	snd_assert(buf != NULL, return -ENXIO);
+	if (snd_BUG_ON(!buf))
+		return -ENXIO;
 	if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
 		plugin = snd_pcm_plug_first(plug);
 		format = &plugin->src_format;
@@ -553,7 +563,9 @@
 	if ((width = snd_pcm_format_physical_width(format->format)) < 0)
 		return width;
 	nchannels = format->channels;
-	snd_assert(plugin->access == SNDRV_PCM_ACCESS_RW_INTERLEAVED || format->channels <= 1, return -ENXIO);
+	if (snd_BUG_ON(plugin->access != SNDRV_PCM_ACCESS_RW_INTERLEAVED &&
+		       format->channels > 1))
+		return -ENXIO;
 	for (channel = 0; channel < nchannels; channel++, v++) {
 		v->frames = count;
 		v->enabled = 1;
diff --git a/sound/core/oss/rate.c b/sound/core/oss/rate.c
index 14dfb31..a466443 100644
--- a/sound/core/oss/rate.c
+++ b/sound/core/oss/rate.c
@@ -185,7 +185,8 @@
 	struct rate_priv *data;
 	snd_pcm_sframes_t res;
 
-	snd_assert(plugin != NULL, return -ENXIO);
+	if (snd_BUG_ON(!plugin))
+		return -ENXIO;
 	if (frames == 0)
 		return 0;
 	data = (struct rate_priv *)plugin->extra_data;
@@ -217,7 +218,8 @@
 	struct rate_priv *data;
 	snd_pcm_sframes_t res;
 
-	snd_assert(plugin != NULL, return -ENXIO);
+	if (snd_BUG_ON(!plugin))
+		return -ENXIO;
 	if (frames == 0)
 		return 0;
 	data = (struct rate_priv *)plugin->extra_data;
@@ -252,19 +254,20 @@
 	snd_pcm_uframes_t dst_frames;
 	struct rate_priv *data;
 
-	snd_assert(plugin != NULL && src_channels != NULL && dst_channels != NULL, return -ENXIO);
+	if (snd_BUG_ON(!plugin || !src_channels || !dst_channels))
+		return -ENXIO;
 	if (frames == 0)
 		return 0;
 #ifdef CONFIG_SND_DEBUG
 	{
 		unsigned int channel;
 		for (channel = 0; channel < plugin->src_format.channels; channel++) {
-			snd_assert(src_channels[channel].area.first % 8 == 0 &&
-				   src_channels[channel].area.step % 8 == 0,
-				   return -ENXIO);
-			snd_assert(dst_channels[channel].area.first % 8 == 0 &&
-				   dst_channels[channel].area.step % 8 == 0,
-				   return -ENXIO);
+			if (snd_BUG_ON(src_channels[channel].area.first % 8 ||
+				       src_channels[channel].area.step % 8))
+				return -ENXIO;
+			if (snd_BUG_ON(dst_channels[channel].area.first % 8 ||
+				       dst_channels[channel].area.step % 8))
+				return -ENXIO;
 		}
 	}
 #endif
@@ -281,7 +284,8 @@
 		       enum snd_pcm_plugin_action action,
 		       unsigned long udata)
 {
-	snd_assert(plugin != NULL, return -ENXIO);
+	if (snd_BUG_ON(!plugin))
+		return -ENXIO;
 	switch (action) {
 	case INIT:
 	case PREPARE:
@@ -302,14 +306,20 @@
 	struct rate_priv *data;
 	struct snd_pcm_plugin *plugin;
 
-	snd_assert(r_plugin != NULL, return -ENXIO);
+	if (snd_BUG_ON(!r_plugin))
+		return -ENXIO;
 	*r_plugin = NULL;
 
-	snd_assert(src_format->channels == dst_format->channels, return -ENXIO);
-	snd_assert(src_format->channels > 0, return -ENXIO);
-	snd_assert(src_format->format == SNDRV_PCM_FORMAT_S16, return -ENXIO);
-	snd_assert(dst_format->format == SNDRV_PCM_FORMAT_S16, return -ENXIO);
-	snd_assert(src_format->rate != dst_format->rate, return -ENXIO);
+	if (snd_BUG_ON(src_format->channels != dst_format->channels))
+		return -ENXIO;
+	if (snd_BUG_ON(src_format->channels <= 0))
+		return -ENXIO;
+	if (snd_BUG_ON(src_format->format != SNDRV_PCM_FORMAT_S16))
+		return -ENXIO;
+	if (snd_BUG_ON(dst_format->format != SNDRV_PCM_FORMAT_S16))
+		return -ENXIO;
+	if (snd_BUG_ON(src_format->rate == dst_format->rate))
+		return -ENXIO;
 
 	err = snd_pcm_plugin_build(plug, "rate conversion",
 				   src_format, dst_format,
diff --git a/sound/core/oss/route.c b/sound/core/oss/route.c
index da7ab7a..0dcc287 100644
--- a/sound/core/oss/route.c
+++ b/sound/core/oss/route.c
@@ -54,7 +54,8 @@
 	struct snd_pcm_plugin_channel *dvp;
 	int format;
 
-	snd_assert(plugin != NULL && src_channels != NULL && dst_channels != NULL, return -ENXIO);
+	if (snd_BUG_ON(!plugin || !src_channels || !dst_channels))
+		return -ENXIO;
 	if (frames == 0)
 		return 0;
 
@@ -90,10 +91,13 @@
 	struct snd_pcm_plugin *plugin;
 	int err;
 
-	snd_assert(r_plugin != NULL, return -ENXIO);
+	if (snd_BUG_ON(!r_plugin))
+		return -ENXIO;
 	*r_plugin = NULL;
-	snd_assert(src_format->rate == dst_format->rate, return -ENXIO);
-	snd_assert(src_format->format == dst_format->format, return -ENXIO);
+	if (snd_BUG_ON(src_format->rate != dst_format->rate))
+		return -ENXIO;
+	if (snd_BUG_ON(src_format->format != dst_format->format))
+		return -ENXIO;
 
 	err = snd_pcm_plugin_build(plug, "route conversion",
 				   src_format, dst_format, 0, &plugin);
diff --git a/sound/core/pcm.c b/sound/core/pcm.c
index 9dd9bc7..192a433 100644
--- a/sound/core/pcm.c
+++ b/sound/core/pcm.c
@@ -42,7 +42,7 @@
 static int snd_pcm_dev_register(struct snd_device *device);
 static int snd_pcm_dev_disconnect(struct snd_device *device);
 
-static struct snd_pcm *snd_pcm_search(struct snd_card *card, int device)
+static struct snd_pcm *snd_pcm_get(struct snd_card *card, int device)
 {
 	struct snd_pcm *pcm;
 
@@ -53,6 +53,37 @@
 	return NULL;
 }
 
+static int snd_pcm_next(struct snd_card *card, int device)
+{
+	struct snd_pcm *pcm;
+
+	list_for_each_entry(pcm, &snd_pcm_devices, list) {
+		if (pcm->card == card && pcm->device > device)
+			return pcm->device;
+		else if (pcm->card->number > card->number)
+			return -1;
+	}
+	return -1;
+}
+
+static int snd_pcm_add(struct snd_pcm *newpcm)
+{
+	struct snd_pcm *pcm;
+
+	list_for_each_entry(pcm, &snd_pcm_devices, list) {
+		if (pcm->card == newpcm->card && pcm->device == newpcm->device)
+			return -EBUSY;
+		if (pcm->card->number > newpcm->card->number ||
+				(pcm->card == newpcm->card &&
+				pcm->device > newpcm->device)) {
+			list_add(&newpcm->list, pcm->list.prev);
+			return 0;
+		}
+	}
+	list_add_tail(&newpcm->list, &snd_pcm_devices);
+	return 0;
+}
+
 static int snd_pcm_control_ioctl(struct snd_card *card,
 				 struct snd_ctl_file *control,
 				 unsigned int cmd, unsigned long arg)
@@ -65,14 +96,7 @@
 			if (get_user(device, (int __user *)arg))
 				return -EFAULT;
 			mutex_lock(&register_mutex);
-			device = device < 0 ? 0 : device + 1;
-			while (device < SNDRV_PCM_DEVICES) {
-				if (snd_pcm_search(card, device))
-					break;
-				device++;
-			}
-			if (device == SNDRV_PCM_DEVICES)
-				device = -1;
+			device = snd_pcm_next(card, device);
 			mutex_unlock(&register_mutex);
 			if (put_user(device, (int __user *)arg))
 				return -EFAULT;
@@ -98,7 +122,7 @@
 			if (get_user(subdevice, &info->subdevice))
 				return -EFAULT;
 			mutex_lock(&register_mutex);
-			pcm = snd_pcm_search(card, device);
+			pcm = snd_pcm_get(card, device);
 			if (pcm == NULL) {
 				err = -ENXIO;
 				goto _error;
@@ -232,7 +256,6 @@
 
 static const char *snd_pcm_stream_name(int stream)
 {
-	snd_assert(stream <= SNDRV_PCM_STREAM_LAST, return NULL);
 	return snd_pcm_stream_names[stream];
 }
 
@@ -248,7 +271,6 @@
 
 static const char *snd_pcm_tstamp_mode_name(int mode)
 {
-	snd_assert(mode <= SNDRV_PCM_TSTAMP_LAST, return NULL);
 	return snd_pcm_tstamp_mode_names[mode];
 }
 
@@ -682,9 +704,10 @@
 		.dev_disconnect = snd_pcm_dev_disconnect,
 	};
 
-	snd_assert(rpcm != NULL, return -EINVAL);
-	*rpcm = NULL;
-	snd_assert(card != NULL, return -ENXIO);
+	if (snd_BUG_ON(!card))
+		return -ENXIO;
+	if (rpcm)
+		*rpcm = NULL;
 	pcm = kzalloc(sizeof(*pcm), GFP_KERNEL);
 	if (pcm == NULL) {
 		snd_printk(KERN_ERR "Cannot allocate PCM\n");
@@ -708,7 +731,8 @@
 		snd_pcm_free(pcm);
 		return err;
 	}
-	*rpcm = pcm;
+	if (rpcm)
+		*rpcm = pcm;
 	return 0;
 }
 
@@ -742,7 +766,8 @@
 {
 	struct snd_pcm_notify *notify;
 
-	snd_assert(pcm != NULL, return -ENXIO);
+	if (!pcm)
+		return 0;
 	list_for_each_entry(notify, &snd_pcm_notify_list, list) {
 		notify->n_unregister(pcm);
 	}
@@ -773,15 +798,15 @@
 	int prefer_subdevice = -1;
 	size_t size;
 
-	snd_assert(rsubstream != NULL, return -EINVAL);
+	if (snd_BUG_ON(!pcm || !rsubstream))
+		return -ENXIO;
 	*rsubstream = NULL;
-	snd_assert(pcm != NULL, return -ENXIO);
 	pstr = &pcm->streams[stream];
 	if (pstr->substream == NULL || pstr->substream_count == 0)
 		return -ENODEV;
 
 	card = pcm->card;
-	down_read(&card->controls_rwsem);
+	read_lock(&card->ctl_files_rwlock);
 	list_for_each_entry(kctl, &card->ctl_files, list) {
 		if (kctl->pid == current->pid) {
 			prefer_subdevice = kctl->prefer_pcm_subdevice;
@@ -789,7 +814,7 @@
 				break;
 		}
 	}
-	up_read(&card->controls_rwsem);
+	read_unlock(&card->ctl_files_rwlock);
 
 	switch (stream) {
 	case SNDRV_PCM_STREAM_PLAYBACK:
@@ -883,8 +908,9 @@
 {
 	struct snd_pcm_runtime *runtime;
 
+	if (PCM_RUNTIME_CHECK(substream))
+		return;
 	runtime = substream->runtime;
-	snd_assert(runtime != NULL, return);
 	if (runtime->private_free != NULL)
 		runtime->private_free(runtime);
 	snd_free_pages((void*)runtime->status,
@@ -929,13 +955,14 @@
 	struct snd_pcm *pcm = device->device_data;
 	struct device *dev;
 
-	snd_assert(pcm != NULL && device != NULL, return -ENXIO);
+	if (snd_BUG_ON(!pcm || !device))
+		return -ENXIO;
 	mutex_lock(&register_mutex);
-	if (snd_pcm_search(pcm->card, pcm->device)) {
+	err = snd_pcm_add(pcm);
+	if (err) {
 		mutex_unlock(&register_mutex);
-		return -EBUSY;
+		return err;
 	}
-	list_add_tail(&pcm->list, &snd_pcm_devices);
 	for (cidx = 0; cidx < 2; cidx++) {
 		int devtype = -1;
 		if (pcm->streams[cidx].substream == NULL)
@@ -1019,10 +1046,11 @@
 {
 	struct snd_pcm *pcm;
 
-	snd_assert(notify != NULL &&
-		   notify->n_register != NULL &&
-		   notify->n_unregister != NULL &&
-		   notify->n_disconnect, return -EINVAL);
+	if (snd_BUG_ON(!notify ||
+		       !notify->n_register ||
+		       !notify->n_unregister ||
+		       !notify->n_disconnect))
+		return -EINVAL;
 	mutex_lock(&register_mutex);
 	if (nfree) {
 		list_del(&notify->list);
diff --git a/sound/core/pcm_compat.c b/sound/core/pcm_compat.c
index 49aa693..36d7a59 100644
--- a/sound/core/pcm_compat.c
+++ b/sound/core/pcm_compat.c
@@ -397,7 +397,8 @@
 	snd_pcm_uframes_t boundary;
 	int err;
 
-	snd_assert(runtime, return -EINVAL);
+	if (snd_BUG_ON(!runtime))
+		return -EINVAL;
 
 	if (get_user(sflags, &src->flags) ||
 	    get_user(scontrol.appl_ptr, &src->c.control.appl_ptr) ||
diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c
index 1533f03..6ea5cfb 100644
--- a/sound/core/pcm_lib.c
+++ b/sound/core/pcm_lib.c
@@ -85,7 +85,8 @@
 		}
 		frames = runtime->buffer_size - runtime->silence_filled;
 	}
-	snd_assert(frames <= runtime->buffer_size, return);
+	if (snd_BUG_ON(frames > runtime->buffer_size))
+		return;
 	if (frames == 0)
 		return;
 	ofs = runtime->silence_start % runtime->buffer_size;
@@ -96,7 +97,7 @@
 			if (substream->ops->silence) {
 				int err;
 				err = substream->ops->silence(substream, -1, ofs, transfer);
-				snd_assert(err >= 0, );
+				snd_BUG_ON(err < 0);
 			} else {
 				char *hwbuf = runtime->dma_area + frames_to_bytes(runtime, ofs);
 				snd_pcm_format_set_silence(runtime->format, hwbuf, transfer * runtime->channels);
@@ -108,7 +109,7 @@
 				for (c = 0; c < channels; ++c) {
 					int err;
 					err = substream->ops->silence(substream, c, ofs, transfer);
-					snd_assert(err >= 0, );
+					snd_BUG_ON(err < 0);
 				}
 			} else {
 				size_t dma_csize = runtime->dma_bytes / channels;
@@ -354,7 +355,7 @@
 {
 	u_int64_t n = (u_int64_t) a * b;
 	if (c == 0) {
-		snd_assert(n > 0, );
+		snd_BUG_ON(!n);
 		*r = 0;
 		return UINT_MAX;
 	}
@@ -380,7 +381,8 @@
 int snd_interval_refine(struct snd_interval *i, const struct snd_interval *v)
 {
 	int changed = 0;
-	snd_assert(!snd_interval_empty(i), return -EINVAL);
+	if (snd_BUG_ON(snd_interval_empty(i)))
+		return -EINVAL;
 	if (i->min < v->min) {
 		i->min = v->min;
 		i->openmin = v->openmin;
@@ -423,7 +425,8 @@
 
 static int snd_interval_refine_first(struct snd_interval *i)
 {
-	snd_assert(!snd_interval_empty(i), return -EINVAL);
+	if (snd_BUG_ON(snd_interval_empty(i)))
+		return -EINVAL;
 	if (snd_interval_single(i))
 		return 0;
 	i->max = i->min;
@@ -435,7 +438,8 @@
 
 static int snd_interval_refine_last(struct snd_interval *i)
 {
-	snd_assert(!snd_interval_empty(i), return -EINVAL);
+	if (snd_BUG_ON(snd_interval_empty(i)))
+		return -EINVAL;
 	if (snd_interval_single(i))
 		return 0;
 	i->min = i->max;
@@ -889,7 +893,8 @@
 	c->private = private;
 	k = 0;
 	while (1) {
-		snd_assert(k < ARRAY_SIZE(c->deps), return -EINVAL);
+		if (snd_BUG_ON(k >= ARRAY_SIZE(c->deps)))
+			return -EINVAL;
 		c->deps[k++] = dep;
 		if (dep < 0)
 			break;
@@ -1285,7 +1290,8 @@
 		return changed;
 	if (params->rmask) {
 		int err = snd_pcm_hw_refine(pcm, params);
-		snd_assert(err >= 0, return err);
+		if (snd_BUG_ON(err < 0))
+			return err;
 	}
 	return snd_pcm_hw_param_value(params, var, dir);
 }
@@ -1330,7 +1336,8 @@
 		return changed;
 	if (params->rmask) {
 		int err = snd_pcm_hw_refine(pcm, params);
-		snd_assert(err >= 0, return err);
+		if (snd_BUG_ON(err < 0))
+			return err;
 	}
 	return snd_pcm_hw_param_value(params, var, dir);
 }
@@ -1368,7 +1375,8 @@
 			err = snd_pcm_hw_param_first(pcm, params, *v, NULL);
 		else
 			err = snd_pcm_hw_param_last(pcm, params, *v, NULL);
-		snd_assert(err >= 0, return err);
+		if (snd_BUG_ON(err < 0))
+			return err;
 	}
 	return 0;
 }
@@ -1466,9 +1474,9 @@
 	struct snd_pcm_runtime *runtime;
 	unsigned long flags;
 
-	snd_assert(substream != NULL, return);
+	if (PCM_RUNTIME_CHECK(substream))
+		return;
 	runtime = substream->runtime;
-	snd_assert(runtime != NULL, return);
 
 	if (runtime->transfer_ack_begin)
 		runtime->transfer_ack_begin(substream);
@@ -1567,7 +1575,6 @@
 			return err;
 	} else {
 		char *hwbuf = runtime->dma_area + frames_to_bytes(runtime, hwoff);
-		snd_assert(runtime->dma_area, return -EFAULT);
 		if (copy_from_user(hwbuf, buf, frames_to_bytes(runtime, frames)))
 			return -EFAULT;
 	}
@@ -1629,7 +1636,10 @@
 		cont = runtime->buffer_size - runtime->control->appl_ptr % runtime->buffer_size;
 		if (frames > cont)
 			frames = cont;
-		snd_assert(frames != 0, snd_pcm_stream_unlock_irq(substream); return -EINVAL);
+		if (snd_BUG_ON(!frames)) {
+			snd_pcm_stream_unlock_irq(substream);
+			return -EINVAL;
+		}
 		appl_ptr = runtime->control->appl_ptr;
 		appl_ofs = appl_ptr % runtime->buffer_size;
 		snd_pcm_stream_unlock_irq(substream);
@@ -1669,18 +1679,30 @@
 	return xfer > 0 ? (snd_pcm_sframes_t)xfer : err;
 }
 
+/* sanity-check for read/write methods */
+static int pcm_sanity_check(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime;
+	if (PCM_RUNTIME_CHECK(substream))
+		return -ENXIO;
+	runtime = substream->runtime;
+	if (snd_BUG_ON(!substream->ops->copy && !runtime->dma_area))
+		return -EINVAL;
+	if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
+		return -EBADFD;
+	return 0;
+}
+
 snd_pcm_sframes_t snd_pcm_lib_write(struct snd_pcm_substream *substream, const void __user *buf, snd_pcm_uframes_t size)
 {
 	struct snd_pcm_runtime *runtime;
 	int nonblock;
+	int err;
 
-	snd_assert(substream != NULL, return -ENXIO);
+	err = pcm_sanity_check(substream);
+	if (err < 0)
+		return err;
 	runtime = substream->runtime;
-	snd_assert(runtime != NULL, return -ENXIO);
-	snd_assert(substream->ops->copy != NULL || runtime->dma_area != NULL, return -EINVAL);
-	if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
-		return -EBADFD;
-
 	nonblock = !!(substream->f_flags & O_NONBLOCK);
 
 	if (runtime->access != SNDRV_PCM_ACCESS_RW_INTERLEAVED &&
@@ -1703,7 +1725,8 @@
 	int channels = runtime->channels;
 	int c;
 	if (substream->ops->copy) {
-		snd_assert(substream->ops->silence != NULL, return -EINVAL);
+		if (snd_BUG_ON(!substream->ops->silence))
+			return -EINVAL;
 		for (c = 0; c < channels; ++c, ++bufs) {
 			if (*bufs == NULL) {
 				if ((err = substream->ops->silence(substream, c, hwoff, frames)) < 0)
@@ -1717,7 +1740,6 @@
 	} else {
 		/* default transfer behaviour */
 		size_t dma_csize = runtime->dma_bytes / channels;
-		snd_assert(runtime->dma_area, return -EFAULT);
 		for (c = 0; c < channels; ++c, ++bufs) {
 			char *hwbuf = runtime->dma_area + (c * dma_csize) + samples_to_bytes(runtime, hwoff);
 			if (*bufs == NULL) {
@@ -1738,14 +1760,12 @@
 {
 	struct snd_pcm_runtime *runtime;
 	int nonblock;
+	int err;
 
-	snd_assert(substream != NULL, return -ENXIO);
+	err = pcm_sanity_check(substream);
+	if (err < 0)
+		return err;
 	runtime = substream->runtime;
-	snd_assert(runtime != NULL, return -ENXIO);
-	snd_assert(substream->ops->copy != NULL || runtime->dma_area != NULL, return -EINVAL);
-	if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
-		return -EBADFD;
-
 	nonblock = !!(substream->f_flags & O_NONBLOCK);
 
 	if (runtime->access != SNDRV_PCM_ACCESS_RW_NONINTERLEAVED)
@@ -1769,7 +1789,6 @@
 			return err;
 	} else {
 		char *hwbuf = runtime->dma_area + frames_to_bytes(runtime, hwoff);
-		snd_assert(runtime->dma_area, return -EFAULT);
 		if (copy_to_user(buf, hwbuf, frames_to_bytes(runtime, frames)))
 			return -EFAULT;
 	}
@@ -1841,7 +1860,10 @@
 		cont = runtime->buffer_size - runtime->control->appl_ptr % runtime->buffer_size;
 		if (frames > cont)
 			frames = cont;
-		snd_assert(frames != 0, snd_pcm_stream_unlock_irq(substream); return -EINVAL);
+		if (snd_BUG_ON(!frames)) {
+			snd_pcm_stream_unlock_irq(substream);
+			return -EINVAL;
+		}
 		appl_ptr = runtime->control->appl_ptr;
 		appl_ofs = appl_ptr % runtime->buffer_size;
 		snd_pcm_stream_unlock_irq(substream);
@@ -1879,14 +1901,12 @@
 {
 	struct snd_pcm_runtime *runtime;
 	int nonblock;
+	int err;
 	
-	snd_assert(substream != NULL, return -ENXIO);
+	err = pcm_sanity_check(substream);
+	if (err < 0)
+		return err;
 	runtime = substream->runtime;
-	snd_assert(runtime != NULL, return -ENXIO);
-	snd_assert(substream->ops->copy != NULL || runtime->dma_area != NULL, return -EINVAL);
-	if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
-		return -EBADFD;
-
 	nonblock = !!(substream->f_flags & O_NONBLOCK);
 	if (runtime->access != SNDRV_PCM_ACCESS_RW_INTERLEAVED)
 		return -EINVAL;
@@ -1916,7 +1936,6 @@
 		}
 	} else {
 		snd_pcm_uframes_t dma_csize = runtime->dma_bytes / channels;
-		snd_assert(runtime->dma_area, return -EFAULT);
 		for (c = 0; c < channels; ++c, ++bufs) {
 			char *hwbuf;
 			char __user *buf;
@@ -1938,11 +1957,12 @@
 {
 	struct snd_pcm_runtime *runtime;
 	int nonblock;
+	int err;
 
-	snd_assert(substream != NULL, return -ENXIO);
+	err = pcm_sanity_check(substream);
+	if (err < 0)
+		return err;
 	runtime = substream->runtime;
-	snd_assert(runtime != NULL, return -ENXIO);
-	snd_assert(substream->ops->copy != NULL || runtime->dma_area != NULL, return -EINVAL);
 	if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
 		return -EBADFD;
 
diff --git a/sound/core/pcm_memory.c b/sound/core/pcm_memory.c
index ff07b4a..a6d4280 100644
--- a/sound/core/pcm_memory.c
+++ b/sound/core/pcm_memory.c
@@ -50,8 +50,6 @@
 	struct snd_dma_buffer *dmab = &substream->dma_buffer;
 	int err;
 
-	snd_assert(size > 0, return -EINVAL);
-
 	/* already reserved? */
 	if (snd_dma_get_reserved_buf(dmab, substream->dma_buf_id) > 0) {
 		if (dmab->bytes >= size)
@@ -326,6 +324,32 @@
 
 EXPORT_SYMBOL(snd_pcm_sgbuf_ops_page);
 
+/*
+ * compute the max chunk size with continuous pages on sg-buffer
+ */
+unsigned int snd_pcm_sgbuf_get_chunk_size(struct snd_pcm_substream *substream,
+					  unsigned int ofs, unsigned int size)
+{
+	struct snd_sg_buf *sg = snd_pcm_substream_sgbuf(substream);
+	unsigned int start, end, pg;
+
+	start = ofs >> PAGE_SHIFT;
+	end = (ofs + size - 1) >> PAGE_SHIFT;
+	/* check page continuity */
+	pg = sg->table[start].addr >> PAGE_SHIFT;
+	for (;;) {
+		start++;
+		if (start > end)
+			break;
+		pg++;
+		if ((sg->table[start].addr >> PAGE_SHIFT) != pg)
+			return (start << PAGE_SHIFT) - ofs;
+	}
+	/* ok, all on continuous pages */
+	return size;
+}
+EXPORT_SYMBOL(snd_pcm_sgbuf_get_chunk_size);
+
 /**
  * snd_pcm_lib_malloc_pages - allocate the DMA buffer
  * @substream: the substream to allocate the DMA buffer to
@@ -342,10 +366,12 @@
 	struct snd_pcm_runtime *runtime;
 	struct snd_dma_buffer *dmab = NULL;
 
-	snd_assert(substream->dma_buffer.dev.type != SNDRV_DMA_TYPE_UNKNOWN, return -EINVAL);
-	snd_assert(substream != NULL, return -EINVAL);
+	if (PCM_RUNTIME_CHECK(substream))
+		return -EINVAL;
+	if (snd_BUG_ON(substream->dma_buffer.dev.type ==
+		       SNDRV_DMA_TYPE_UNKNOWN))
+		return -EINVAL;
 	runtime = substream->runtime;
-	snd_assert(runtime != NULL, return -EINVAL);
 
 	if (runtime->dma_buffer_p) {
 		/* perphaps, we might free the large DMA memory region
@@ -391,9 +417,9 @@
 {
 	struct snd_pcm_runtime *runtime;
 
-	snd_assert(substream != NULL, return -EINVAL);
+	if (PCM_RUNTIME_CHECK(substream))
+		return -EINVAL;
 	runtime = substream->runtime;
-	snd_assert(runtime != NULL, return -EINVAL);
 	if (runtime->dma_area == NULL)
 		return 0;
 	if (runtime->dma_buffer_p != &substream->dma_buffer) {
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index c49b9d9..e61e125 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -95,7 +95,6 @@
 	struct snd_pcm *pcm = substream->pcm;
 	struct snd_pcm_str *pstr = substream->pstr;
 
-	snd_assert(substream != NULL, return -ENXIO);
 	memset(info, 0, sizeof(*info));
 	info->card = pcm->card->number;
 	info->device = pcm->device;
@@ -370,9 +369,9 @@
 	unsigned int bits;
 	snd_pcm_uframes_t frames;
 
-	snd_assert(substream != NULL, return -ENXIO);
+	if (PCM_RUNTIME_CHECK(substream))
+		return -ENXIO;
 	runtime = substream->runtime;
-	snd_assert(runtime != NULL, return -ENXIO);
 	snd_pcm_stream_lock_irq(substream);
 	switch (runtime->status->state) {
 	case SNDRV_PCM_STATE_OPEN:
@@ -490,9 +489,9 @@
 	struct snd_pcm_runtime *runtime;
 	int result = 0;
 
-	snd_assert(substream != NULL, return -ENXIO);
+	if (PCM_RUNTIME_CHECK(substream))
+		return -ENXIO;
 	runtime = substream->runtime;
-	snd_assert(runtime != NULL, return -ENXIO);
 	snd_pcm_stream_lock_irq(substream);
 	switch (runtime->status->state) {
 	case SNDRV_PCM_STATE_SETUP:
@@ -518,9 +517,9 @@
 {
 	struct snd_pcm_runtime *runtime;
 
-	snd_assert(substream != NULL, return -ENXIO);
+	if (PCM_RUNTIME_CHECK(substream))
+		return -ENXIO;
 	runtime = substream->runtime;
-	snd_assert(runtime != NULL, return -ENXIO);
 	snd_pcm_stream_lock_irq(substream);
 	if (runtime->status->state == SNDRV_PCM_STATE_OPEN) {
 		snd_pcm_stream_unlock_irq(substream);
@@ -622,11 +621,8 @@
 			       struct snd_pcm_status __user * _status)
 {
 	struct snd_pcm_status status;
-	struct snd_pcm_runtime *runtime;
 	int res;
 	
-	snd_assert(substream != NULL, return -ENXIO);
-	runtime = substream->runtime;
 	memset(&status, 0, sizeof(status));
 	res = snd_pcm_status(substream, &status);
 	if (res < 0)
@@ -642,7 +638,6 @@
 	struct snd_pcm_runtime *runtime;
 	unsigned int channel;
 	
-	snd_assert(substream != NULL, return -ENXIO);
 	channel = info->channel;
 	runtime = substream->runtime;
 	snd_pcm_stream_lock_irq(substream);
@@ -1250,7 +1245,6 @@
 	int err = substream->ops->ioctl(substream, SNDRV_PCM_IOCTL1_RESET, NULL);
 	if (err < 0)
 		return err;
-	// snd_assert(runtime->status->hw_ptr < runtime->buffer_size, );
 	runtime->hw_ptr_base = 0;
 	runtime->hw_ptr_interrupt = runtime->status->hw_ptr -
 		runtime->status->hw_ptr % runtime->period_size;
@@ -1421,7 +1415,6 @@
 	int i, num_drecs;
 	struct drain_rec *drec, drec_tmp, *d;
 
-	snd_assert(substream != NULL, return -ENXIO);
 	card = substream->pcm->card;
 	runtime = substream->runtime;
 
@@ -1541,21 +1534,16 @@
 	struct snd_card *card;
 	int result = 0;
 	
-	snd_assert(substream != NULL, return -ENXIO);
+	if (PCM_RUNTIME_CHECK(substream))
+		return -ENXIO;
 	runtime = substream->runtime;
 	card = substream->pcm->card;
 
 	if (runtime->status->state == SNDRV_PCM_STATE_OPEN ||
-	    runtime->status->state == SNDRV_PCM_STATE_DISCONNECTED)
+	    runtime->status->state == SNDRV_PCM_STATE_DISCONNECTED ||
+	    runtime->status->state == SNDRV_PCM_STATE_SUSPENDED)
 		return -EBADFD;
 
-	snd_power_lock(card);
-	if (runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) {
-		result = snd_power_wait(card, SNDRV_CTL_POWER_D0);
-		if (result < 0)
-			goto _unlock;
-	}
-
 	snd_pcm_stream_lock_irq(substream);
 	/* resume pause */
 	if (runtime->status->state == SNDRV_PCM_STATE_PAUSED)
@@ -1564,8 +1552,7 @@
 	snd_pcm_stop(substream, SNDRV_PCM_STATE_SETUP);
 	/* runtime->control->appl_ptr = runtime->status->hw_ptr; */
 	snd_pcm_stream_unlock_irq(substream);
- _unlock:
-	snd_power_unlock(card);
+
 	return result;
 }
 
@@ -1941,33 +1928,41 @@
 			mask |= 1 << SNDRV_PCM_ACCESS_MMAP_COMPLEX;
 	}
 	err = snd_pcm_hw_constraint_mask(runtime, SNDRV_PCM_HW_PARAM_ACCESS, mask);
-	snd_assert(err >= 0, return -EINVAL);
+	if (err < 0)
+		return err;
 
 	err = snd_pcm_hw_constraint_mask64(runtime, SNDRV_PCM_HW_PARAM_FORMAT, hw->formats);
-	snd_assert(err >= 0, return -EINVAL);
+	if (err < 0)
+		return err;
 
 	err = snd_pcm_hw_constraint_mask(runtime, SNDRV_PCM_HW_PARAM_SUBFORMAT, 1 << SNDRV_PCM_SUBFORMAT_STD);
-	snd_assert(err >= 0, return -EINVAL);
+	if (err < 0)
+		return err;
 
 	err = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_CHANNELS,
 					   hw->channels_min, hw->channels_max);
-	snd_assert(err >= 0, return -EINVAL);
+	if (err < 0)
+		return err;
 
 	err = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_RATE,
 					   hw->rate_min, hw->rate_max);
-	snd_assert(err >= 0, return -EINVAL);
+	 if (err < 0)
+		 return err;
 
 	err = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
 					   hw->period_bytes_min, hw->period_bytes_max);
-	snd_assert(err >= 0, return -EINVAL);
+	 if (err < 0)
+		 return err;
 
 	err = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIODS,
 					   hw->periods_min, hw->periods_max);
-	snd_assert(err >= 0, return -EINVAL);
+	if (err < 0)
+		return err;
 
 	err = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
 					   hw->period_bytes_min, hw->buffer_bytes_max);
-	snd_assert(err >= 0, return -EINVAL);
+	if (err < 0)
+		return err;
 
 	err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 
 				  snd_pcm_hw_rule_buffer_bytes_max, substream,
@@ -1978,7 +1973,8 @@
 	/* FIXME: remove */
 	if (runtime->dma_bytes) {
 		err = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 0, runtime->dma_bytes);
-		snd_assert(err >= 0, return -EINVAL);
+		if (err < 0)
+			return -EINVAL;
 	}
 
 	if (!(hw->rates & (SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_CONTINUOUS))) {
@@ -2074,8 +2070,8 @@
 	struct snd_pcm_str *str;
 	int err;
 
-	snd_assert(rpcm_file != NULL, return -EINVAL);
-	*rpcm_file = NULL;
+	if (rpcm_file)
+		*rpcm_file = NULL;
 
 	err = snd_pcm_open_substream(pcm, stream, file, &substream);
 	if (err < 0)
@@ -2093,7 +2089,8 @@
 		substream->pcm_release = pcm_release_private;
 	}
 	file->private_data = pcm_file;
-	*rpcm_file = pcm_file;
+	if (rpcm_file)
+		*rpcm_file = pcm_file;
 	return 0;
 }
 
@@ -2177,7 +2174,8 @@
 
 	pcm_file = file->private_data;
 	substream = pcm_file->substream;
-	snd_assert(substream != NULL, return -ENXIO);
+	if (snd_BUG_ON(!substream))
+		return -ENXIO;
 	pcm = substream->pcm;
 	fasync_helper(-1, file, 0, &substream->runtime->fasync);
 	mutex_lock(&pcm->open_mutex);
@@ -2500,8 +2498,6 @@
 				 struct snd_pcm_substream *substream,
 				 unsigned int cmd, void __user *arg)
 {
-	snd_assert(substream != NULL, return -ENXIO);
-
 	switch (cmd) {
 	case SNDRV_PCM_IOCTL_PVERSION:
 		return put_user(SNDRV_PCM_VERSION, (int __user *)arg) ? -EFAULT : 0;
@@ -2570,8 +2566,10 @@
 				   struct snd_pcm_substream *substream,
 				   unsigned int cmd, void __user *arg)
 {
-	snd_assert(substream != NULL, return -ENXIO);
-	snd_assert(substream->stream == SNDRV_PCM_STREAM_PLAYBACK, return -EINVAL);
+	if (snd_BUG_ON(!substream))
+		return -ENXIO;
+	if (snd_BUG_ON(substream->stream != SNDRV_PCM_STREAM_PLAYBACK))
+		return -EINVAL;
 	switch (cmd) {
 	case SNDRV_PCM_IOCTL_WRITEI_FRAMES:
 	{
@@ -2650,8 +2648,10 @@
 				  struct snd_pcm_substream *substream,
 				  unsigned int cmd, void __user *arg)
 {
-	snd_assert(substream != NULL, return -ENXIO);
-	snd_assert(substream->stream == SNDRV_PCM_STREAM_CAPTURE, return -EINVAL);
+	if (snd_BUG_ON(!substream))
+		return -ENXIO;
+	if (snd_BUG_ON(substream->stream != SNDRV_PCM_STREAM_CAPTURE))
+		return -EINVAL;
 	switch (cmd) {
 	case SNDRV_PCM_IOCTL_READI_FRAMES:
 	{
@@ -2790,7 +2790,8 @@
 
 	pcm_file = file->private_data;
 	substream = pcm_file->substream;
-	snd_assert(substream != NULL, return -ENXIO);
+	if (PCM_RUNTIME_CHECK(substream))
+		return -ENXIO;
 	runtime = substream->runtime;
 	if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
 		return -EBADFD;
@@ -2813,21 +2814,17 @@
 
 	pcm_file = file->private_data;
 	substream = pcm_file->substream;
-	snd_assert(substream != NULL, result = -ENXIO; goto end);
+	if (PCM_RUNTIME_CHECK(substream))
+		return -ENXIO;
 	runtime = substream->runtime;
-	if (runtime->status->state == SNDRV_PCM_STATE_OPEN) {
-		result = -EBADFD;
-		goto end;
-	}
-	if (!frame_aligned(runtime, count)) {
-		result = -EINVAL;
-		goto end;
-	}
+	if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
+		return -EBADFD;
+	if (!frame_aligned(runtime, count))
+		return -EINVAL;
 	count = bytes_to_frames(runtime, count);
 	result = snd_pcm_lib_write(substream, buf, count);
 	if (result > 0)
 		result = frames_to_bytes(runtime, result);
- end:
 	return result;
 }
 
@@ -2845,7 +2842,8 @@
 
 	pcm_file = iocb->ki_filp->private_data;
 	substream = pcm_file->substream;
-	snd_assert(substream != NULL, return -ENXIO);
+	if (PCM_RUNTIME_CHECK(substream))
+		return -ENXIO;
 	runtime = substream->runtime;
 	if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
 		return -EBADFD;
@@ -2879,17 +2877,14 @@
 
 	pcm_file = iocb->ki_filp->private_data;
 	substream = pcm_file->substream;
-	snd_assert(substream != NULL, result = -ENXIO; goto end);
+	if (PCM_RUNTIME_CHECK(substream))
+		return -ENXIO;
 	runtime = substream->runtime;
-	if (runtime->status->state == SNDRV_PCM_STATE_OPEN) {
-		result = -EBADFD;
-		goto end;
-	}
+	if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
+		return -EBADFD;
 	if (nr_segs > 128 || nr_segs != runtime->channels ||
-	    !frame_aligned(runtime, iov->iov_len)) {
-		result = -EINVAL;
-		goto end;
-	}
+	    !frame_aligned(runtime, iov->iov_len))
+		return -EINVAL;
 	frames = bytes_to_samples(runtime, iov->iov_len);
 	bufs = kmalloc(sizeof(void *) * nr_segs, GFP_KERNEL);
 	if (bufs == NULL)
@@ -2900,7 +2895,6 @@
 	if (result > 0)
 		result = frames_to_bytes(runtime, result);
 	kfree(bufs);
- end:
 	return result;
 }
 
@@ -2915,7 +2909,8 @@
 	pcm_file = file->private_data;
 
 	substream = pcm_file->substream;
-	snd_assert(substream != NULL, return -ENXIO);
+	if (PCM_RUNTIME_CHECK(substream))
+		return -ENXIO;
 	runtime = substream->runtime;
 
 	poll_wait(file, &runtime->sleep, wait);
@@ -2953,7 +2948,8 @@
 	pcm_file = file->private_data;
 
 	substream = pcm_file->substream;
-	snd_assert(substream != NULL, return -ENXIO);
+	if (PCM_RUNTIME_CHECK(substream))
+		return -ENXIO;
 	runtime = substream->runtime;
 
 	poll_wait(file, &runtime->sleep, wait);
@@ -3023,7 +3019,6 @@
 	if (!(area->vm_flags & VM_READ))
 		return -EINVAL;
 	runtime = substream->runtime;
-	snd_assert(runtime != NULL, return -EAGAIN);
 	size = area->vm_end - area->vm_start;
 	if (size != PAGE_ALIGN(sizeof(struct snd_pcm_mmap_status)))
 		return -EINVAL;
@@ -3063,7 +3058,6 @@
 	if (!(area->vm_flags & VM_READ))
 		return -EINVAL;
 	runtime = substream->runtime;
-	snd_assert(runtime != NULL, return -EAGAIN);
 	size = area->vm_end - area->vm_start;
 	if (size != PAGE_ALIGN(sizeof(struct snd_pcm_mmap_control)))
 		return -EINVAL;
@@ -3195,7 +3189,6 @@
 			return -EINVAL;
 	}
 	runtime = substream->runtime;
-	snd_assert(runtime != NULL, return -EAGAIN);
 	if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
 		return -EBADFD;
 	if (!(runtime->info & SNDRV_PCM_INFO_MMAP))
@@ -3227,7 +3220,8 @@
 	
 	pcm_file = file->private_data;
 	substream = pcm_file->substream;
-	snd_assert(substream != NULL, return -ENXIO);
+	if (PCM_RUNTIME_CHECK(substream))
+		return -ENXIO;
 
 	offset = area->vm_pgoff << PAGE_SHIFT;
 	switch (offset) {
@@ -3255,9 +3249,9 @@
 	lock_kernel();
 	pcm_file = file->private_data;
 	substream = pcm_file->substream;
-	snd_assert(substream != NULL, goto out);
+	if (PCM_RUNTIME_CHECK(substream))
+		goto out;
 	runtime = substream->runtime;
-
 	err = fasync_helper(fd, file, on, &runtime->fasync);
 out:
 	unlock_kernel();
@@ -3391,6 +3385,17 @@
 }
 #endif /* CONFIG_SND_SUPPORT_OLD_API */
 
+#ifndef CONFIG_MMU
+unsigned long dummy_get_unmapped_area(struct file *file, unsigned long addr,
+				      unsigned long len, unsigned long pgoff,
+				      unsigned long flags)
+{
+	return 0;
+}
+#else
+# define dummy_get_unmapped_area NULL
+#endif
+
 /*
  *  Register section
  */
@@ -3407,6 +3412,7 @@
 		.compat_ioctl = 	snd_pcm_ioctl_compat,
 		.mmap =			snd_pcm_mmap,
 		.fasync =		snd_pcm_fasync,
+		.get_unmapped_area =	dummy_get_unmapped_area,
 	},
 	{
 		.owner =		THIS_MODULE,
@@ -3419,5 +3425,6 @@
 		.compat_ioctl = 	snd_pcm_ioctl_compat,
 		.mmap =			snd_pcm_mmap,
 		.fasync =		snd_pcm_fasync,
+		.get_unmapped_area =	dummy_get_unmapped_area,
 	}
 };
diff --git a/sound/core/pcm_timer.c b/sound/core/pcm_timer.c
index 033a024..2c89c04 100644
--- a/sound/core/pcm_timer.c
+++ b/sound/core/pcm_timer.c
@@ -51,12 +51,14 @@
 	
         mult = 1000000000;
 	rate = runtime->rate;
-	snd_assert(rate != 0, return);
+	if (snd_BUG_ON(!rate))
+		return;
 	l = gcd(mult, rate);
 	mult /= l;
 	rate /= l;
 	fsize = runtime->period_size;
-	snd_assert(fsize != 0, return);
+	if (snd_BUG_ON(!fsize))
+		return;
 	l = gcd(rate, fsize);
 	rate /= l;
 	fsize /= l;
diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c
index f7ea728..c4995c9 100644
--- a/sound/core/rawmidi.c
+++ b/sound/core/rawmidi.c
@@ -418,7 +418,7 @@
 	mutex_lock(&rmidi->open_mutex);
 	while (1) {
 		subdevice = -1;
-		down_read(&card->controls_rwsem);
+		read_lock(&card->ctl_files_rwlock);
 		list_for_each_entry(kctl, &card->ctl_files, list) {
 			if (kctl->pid == current->pid) {
 				subdevice = kctl->prefer_rawmidi_subdevice;
@@ -426,7 +426,7 @@
 					break;
 			}
 		}
-		up_read(&card->controls_rwsem);
+		read_unlock(&card->ctl_files_rwlock);
 		err = snd_rawmidi_kernel_open(rmidi->card, rmidi->device,
 					      subdevice, fflags, rawmidi_file);
 		if (err >= 0)
@@ -470,8 +470,8 @@
 	struct snd_rawmidi_substream *substream;
 	struct snd_rawmidi_runtime *runtime;
 
-	snd_assert(rfile != NULL, return -ENXIO);
-	snd_assert(rfile->input != NULL || rfile->output != NULL, return -ENXIO);
+	if (snd_BUG_ON(!rfile))
+		return -ENXIO;
 	rmidi = rfile->rmidi;
 	mutex_lock(&rmidi->open_mutex);
 	if (rfile->input != NULL) {
@@ -1100,7 +1100,7 @@
 		return -EINVAL;
 	}
 	spin_lock_irqsave(&runtime->lock, flags);
-	snd_assert(runtime->avail + count <= runtime->buffer_size, );
+	snd_BUG_ON(runtime->avail + count > runtime->buffer_size);
 	runtime->hw_ptr += count;
 	runtime->hw_ptr %= runtime->buffer_size;
 	runtime->avail += count;
@@ -1141,8 +1141,10 @@
 	long count1, result;
 	struct snd_rawmidi_runtime *runtime = substream->runtime;
 
-	snd_assert(kernelbuf != NULL || userbuf != NULL, return -EINVAL);
-	snd_assert(runtime->buffer != NULL, return -EINVAL);
+	if (snd_BUG_ON(!kernelbuf && !userbuf))
+		return -EINVAL;
+	if (snd_BUG_ON(!runtime->buffer))
+		return -EINVAL;
 
 	result = 0;
 	spin_lock_irqsave(&runtime->lock, flags);
@@ -1420,9 +1422,10 @@
 		.dev_disconnect = snd_rawmidi_dev_disconnect,
 	};
 
-	snd_assert(rrawmidi != NULL, return -EINVAL);
-	*rrawmidi = NULL;
-	snd_assert(card != NULL, return -ENXIO);
+	if (snd_BUG_ON(!card))
+		return -ENXIO;
+	if (rrawmidi)
+		*rrawmidi = NULL;
 	rmidi = kzalloc(sizeof(*rmidi), GFP_KERNEL);
 	if (rmidi == NULL) {
 		snd_printk(KERN_ERR "rawmidi: cannot allocate\n");
@@ -1455,7 +1458,8 @@
 		snd_rawmidi_free(rmidi);
 		return err;
 	}
-	*rrawmidi = rmidi;
+	if (rrawmidi)
+		*rrawmidi = rmidi;
 	return 0;
 }
 
@@ -1472,7 +1476,8 @@
 
 static int snd_rawmidi_free(struct snd_rawmidi *rmidi)
 {
-	snd_assert(rmidi != NULL, return -ENXIO);	
+	if (!rmidi)
+		return 0;
 
 	snd_info_free_entry(rmidi->proc_entry);
 	rmidi->proc_entry = NULL;
diff --git a/sound/core/rtctimer.c b/sound/core/rtctimer.c
index 97b30fb..51e64e3 100644
--- a/sound/core/rtctimer.c
+++ b/sound/core/rtctimer.c
@@ -91,7 +91,8 @@
 rtctimer_start(struct snd_timer *timer)
 {
 	rtc_task_t *rtc = timer->private_data;
-	snd_assert(rtc != NULL, return -EINVAL);
+	if (snd_BUG_ON(!rtc))
+		return -EINVAL;
 	rtc_control(rtc, RTC_IRQP_SET, rtctimer_freq);
 	rtc_control(rtc, RTC_PIE_ON, 0);
 	return 0;
@@ -101,7 +102,8 @@
 rtctimer_stop(struct snd_timer *timer)
 {
 	rtc_task_t *rtc = timer->private_data;
-	snd_assert(rtc != NULL, return -EINVAL);
+	if (snd_BUG_ON(!rtc))
+		return -EINVAL;
 	rtc_control(rtc, RTC_PIE_OFF, 0);
 	return 0;
 }
diff --git a/sound/core/seq/oss/seq_oss.c b/sound/core/seq/oss/seq_oss.c
index 777796e..f25e3cc 100644
--- a/sound/core/seq/oss/seq_oss.c
+++ b/sound/core/seq/oss/seq_oss.c
@@ -164,7 +164,8 @@
 {
 	struct seq_oss_devinfo *dp;
 	dp = file->private_data;
-	snd_assert(dp != NULL, return -EIO);
+	if (snd_BUG_ON(!dp))
+		return -ENXIO;
 	return snd_seq_oss_read(dp, buf, count);
 }
 
@@ -174,7 +175,8 @@
 {
 	struct seq_oss_devinfo *dp;
 	dp = file->private_data;
-	snd_assert(dp != NULL, return -EIO);
+	if (snd_BUG_ON(!dp))
+		return -ENXIO;
 	return snd_seq_oss_write(dp, buf, count, file);
 }
 
@@ -183,7 +185,8 @@
 {
 	struct seq_oss_devinfo *dp;
 	dp = file->private_data;
-	snd_assert(dp != NULL, return -EIO);
+	if (snd_BUG_ON(!dp))
+		return -ENXIO;
 	return snd_seq_oss_ioctl(dp, cmd, arg);
 }
 
@@ -198,7 +201,8 @@
 {
 	struct seq_oss_devinfo *dp;
 	dp = file->private_data;
-	snd_assert(dp != NULL, return 0);
+	if (snd_BUG_ON(!dp))
+		return -ENXIO;
 	return snd_seq_oss_poll(dp, file, wait);
 }
 
diff --git a/sound/core/seq/oss/seq_oss_synth.c b/sound/core/seq/oss/seq_oss_synth.c
index e024e45..945a27c 100644
--- a/sound/core/seq/oss/seq_oss_synth.c
+++ b/sound/core/seq/oss/seq_oss_synth.c
@@ -308,7 +308,8 @@
 	struct seq_oss_synth *rec;
 	struct seq_oss_synthinfo *info;
 
-	snd_assert(dp->max_synthdev <= SNDRV_SEQ_OSS_MAX_SYNTH_DEVS, return);
+	if (snd_BUG_ON(dp->max_synthdev >= SNDRV_SEQ_OSS_MAX_SYNTH_DEVS))
+		return;
 	for (i = 0; i < dp->max_synthdev; i++) {
 		info = &dp->synths[i];
 		if (! info->opened)
@@ -402,7 +403,8 @@
 	struct seq_oss_synth *rec;
 	struct seq_oss_synthinfo *info;
 
-	snd_assert(dev >= 0 && dev < dp->max_synthdev, return);
+	if (snd_BUG_ON(dev < 0 || dev >= dp->max_synthdev))
+		return;
 	info = &dp->synths[dev];
 	if (! info->opened)
 		return;
diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c
index 7a1545d..8ca2be3 100644
--- a/sound/core/seq/seq_clientmgr.c
+++ b/sound/core/seq/seq_clientmgr.c
@@ -266,7 +266,8 @@
 {
 	unsigned long flags;
 
-	snd_assert(client != NULL, return -EINVAL);
+	if (!client)
+		return 0;
 	snd_seq_delete_all_ports(client);
 	snd_seq_queue_client_leave(client->number);
 	spin_lock_irqsave(&clients_lock, flags);
@@ -403,7 +404,8 @@
 		return -EFAULT;
 
 	/* check client structures are in place */
-	snd_assert(client != NULL, return -ENXIO);
+	if (snd_BUG_ON(!client))
+		return -ENXIO;
 
 	if (!client->accept_input || (fifo = client->data.user.fifo) == NULL)
 		return -ENXIO;
@@ -825,7 +827,8 @@
 	struct snd_seq_client *client;
 	int result;
 
-	snd_assert(cell != NULL, return -EINVAL);
+	if (snd_BUG_ON(!cell))
+		return -EINVAL;
 
 	client = snd_seq_client_use_ptr(cell->event.source.client);
 	if (client == NULL) {
@@ -994,7 +997,8 @@
 		return -ENXIO;
 
 	/* check client structures are in place */
-	snd_assert(client != NULL, return -ENXIO);
+	if (snd_BUG_ON(!client))
+		return -ENXIO;
 		
 	if (!client->accept_output || client->pool == NULL)
 		return -ENXIO;
@@ -1076,7 +1080,8 @@
 	unsigned int mask = 0;
 
 	/* check client structures are in place */
-	snd_assert(client != NULL, return -ENXIO);
+	if (snd_BUG_ON(!client))
+		return -ENXIO;
 
 	if ((snd_seq_file_flags(file) & SNDRV_SEQ_LFLG_INPUT) &&
 	    client->data.user.fifo) {
@@ -2195,7 +2200,8 @@
 {
 	struct snd_seq_client *client = file->private_data;
 
-	snd_assert(client != NULL, return -ENXIO);
+	if (snd_BUG_ON(!client))
+		return -ENXIO;
 		
 	return snd_seq_do_ioctl(client, cmd, (void __user *) arg);
 }
@@ -2216,7 +2222,8 @@
 	struct snd_seq_client *client;
 	va_list args;
 
-	snd_assert(! in_interrupt(), return -EBUSY);
+	if (snd_BUG_ON(in_interrupt()))
+		return -EBUSY;
 
 	if (card && client_index >= SNDRV_SEQ_CLIENTS_PER_CARD)
 		return -EINVAL;
@@ -2265,7 +2272,8 @@
 {
 	struct snd_seq_client *ptr;
 
-	snd_assert(! in_interrupt(), return -EBUSY);
+	if (snd_BUG_ON(in_interrupt()))
+		return -EBUSY;
 
 	ptr = clientptr(client);
 	if (ptr == NULL)
@@ -2288,7 +2296,8 @@
 	struct snd_seq_client *cptr;
 	int result;
 
-	snd_assert(ev != NULL, return -EINVAL);
+	if (snd_BUG_ON(!ev))
+		return -EINVAL;
 
 	if (ev->type == SNDRV_SEQ_EVENT_NONE)
 		return 0; /* ignore this */
@@ -2354,7 +2363,8 @@
 	struct snd_seq_client *cptr;
 	int result;
 
-	snd_assert(ev != NULL, return -EINVAL);
+	if (snd_BUG_ON(!ev))
+		return -EINVAL;
 
 	/* fill in client number */
 	ev->queue = SNDRV_SEQ_QUEUE_DIRECT;
diff --git a/sound/core/seq/seq_compat.c b/sound/core/seq/seq_compat.c
index 9628c06..38693f4 100644
--- a/sound/core/seq/seq_compat.c
+++ b/sound/core/seq/seq_compat.c
@@ -92,7 +92,8 @@
 	struct snd_seq_client *client = file->private_data;
 	void __user *argp = compat_ptr(arg);
 
-	snd_assert(client != NULL, return -ENXIO);
+	if (snd_BUG_ON(!client))
+		return -ENXIO;
 
 	switch (cmd) {
 	case SNDRV_SEQ_IOCTL_PVERSION:
diff --git a/sound/core/seq/seq_device.c b/sound/core/seq/seq_device.c
index 05410e5..1f99767 100644
--- a/sound/core/seq/seq_device.c
+++ b/sound/core/seq/seq_device.c
@@ -187,7 +187,8 @@
 	if (result)
 		*result = NULL;
 
-	snd_assert(id != NULL, return -EINVAL);
+	if (snd_BUG_ON(!id))
+		return -EINVAL;
 
 	ops = find_driver(id, 1);
 	if (ops == NULL)
@@ -232,7 +233,8 @@
 {
 	struct ops_list *ops;
 
-	snd_assert(dev != NULL, return -EINVAL);
+	if (snd_BUG_ON(!dev))
+		return -EINVAL;
 
 	ops = find_driver(dev->id, 0);
 	if (ops == NULL)
diff --git a/sound/core/seq/seq_fifo.c b/sound/core/seq/seq_fifo.c
index 3a94ed0..0d75afa 100644
--- a/sound/core/seq/seq_fifo.c
+++ b/sound/core/seq/seq_fifo.c
@@ -65,9 +65,11 @@
 {
 	struct snd_seq_fifo *f;
 
-	snd_assert(fifo != NULL, return);
+	if (snd_BUG_ON(!fifo))
+		return;
 	f = *fifo;
-	snd_assert(f != NULL, return);
+	if (snd_BUG_ON(!f))
+		return;
 	*fifo = NULL;
 
 	snd_seq_fifo_clear(f);
@@ -116,7 +118,8 @@
 	unsigned long flags;
 	int err;
 
-	snd_assert(f != NULL, return -EINVAL);
+	if (snd_BUG_ON(!f))
+		return -EINVAL;
 
 	snd_use_lock_use(&f->use_lock);
 	err = snd_seq_event_dup(f->pool, event, &cell, 1, NULL); /* always non-blocking */
@@ -174,7 +177,8 @@
 	unsigned long flags;
 	wait_queue_t wait;
 
-	snd_assert(f != NULL, return -EINVAL);
+	if (snd_BUG_ON(!f))
+		return -EINVAL;
 
 	*cellp = NULL;
 	init_waitqueue_entry(&wait, current);
@@ -233,7 +237,8 @@
 	struct snd_seq_pool *newpool, *oldpool;
 	struct snd_seq_event_cell *cell, *next, *oldhead;
 
-	snd_assert(f != NULL && f->pool != NULL, return -EINVAL);
+	if (snd_BUG_ON(!f || !f->pool))
+		return -EINVAL;
 
 	/* allocate new pool */
 	newpool = snd_seq_pool_new(poolsize);
diff --git a/sound/core/seq/seq_memory.c b/sound/core/seq/seq_memory.c
index 0cf6ac4..7fb5543 100644
--- a/sound/core/seq/seq_memory.c
+++ b/sound/core/seq/seq_memory.c
@@ -187,9 +187,11 @@
 	unsigned long flags;
 	struct snd_seq_pool *pool;
 
-	snd_assert(cell != NULL, return);
+	if (snd_BUG_ON(!cell))
+		return;
 	pool = cell->pool;
-	snd_assert(pool != NULL, return);
+	if (snd_BUG_ON(!pool))
+		return;
 
 	spin_lock_irqsave(&pool->lock, flags);
 	free_cell(pool, cell);
@@ -378,7 +380,8 @@
 	struct snd_seq_event_cell *cellptr;
 	unsigned long flags;
 
-	snd_assert(pool != NULL, return -EINVAL);
+	if (snd_BUG_ON(!pool))
+		return -EINVAL;
 	if (pool->ptr)			/* should be atomic? */
 		return 0;
 
@@ -414,7 +417,8 @@
 	struct snd_seq_event_cell *ptr;
 	int max_count = 5 * HZ;
 
-	snd_assert(pool != NULL, return -EINVAL);
+	if (snd_BUG_ON(!pool))
+		return -EINVAL;
 
 	/* wait for closing all threads */
 	spin_lock_irqsave(&pool->lock, flags);
diff --git a/sound/core/seq/seq_midi.c b/sound/core/seq/seq_midi.c
index 99b3536..4d26146 100644
--- a/sound/core/seq/seq_midi.c
+++ b/sound/core/seq/seq_midi.c
@@ -116,7 +116,8 @@
 	struct snd_rawmidi_runtime *runtime;
 	int tmp;
 
-	snd_assert(substream != NULL || buf != NULL, return -EINVAL);
+	if (snd_BUG_ON(!substream || !buf))
+		return -EINVAL;
 	runtime = substream->runtime;
 	if ((tmp = runtime->avail) < count) {
 		snd_printd("warning, output event was lost (count = %i, available = %i)\n", count, tmp);
@@ -135,7 +136,8 @@
 	struct snd_rawmidi_substream *substream;
 	int len;
 
-	snd_assert(msynth != NULL, return -EINVAL);
+	if (snd_BUG_ON(!msynth))
+		return -EINVAL;
 	substream = msynth->output_rfile.output;
 	if (substream == NULL)
 		return -ENODEV;
@@ -210,7 +212,8 @@
 	int err;
 	struct seq_midisynth *msynth = private_data;
 
-	snd_assert(msynth->input_rfile.input != NULL, return -EINVAL);
+	if (snd_BUG_ON(!msynth->input_rfile.input))
+		return -EINVAL;
 	err = snd_rawmidi_kernel_release(&msynth->input_rfile);
 	return err;
 }
@@ -247,7 +250,8 @@
 	struct seq_midisynth *msynth = private_data;
 	unsigned char buf = 0xff; /* MIDI reset */
 
-	snd_assert(msynth->output_rfile.output != NULL, return -EINVAL);
+	if (snd_BUG_ON(!msynth->output_rfile.output))
+		return -EINVAL;
 	/* sending single MIDI reset message to shut the device up */
 	snd_rawmidi_kernel_write(msynth->output_rfile.output, &buf, 1);
 	snd_rawmidi_drain_output(msynth->output_rfile.output);
@@ -285,7 +289,8 @@
 	int device = dev->device;
 	unsigned int input_count = 0, output_count = 0;
 
-	snd_assert(card != NULL && device >= 0 && device < SNDRV_RAWMIDI_DEVICES, return -EINVAL);
+	if (snd_BUG_ON(!card || device < 0 || device >= SNDRV_RAWMIDI_DEVICES))
+		return -EINVAL;
 	info = kmalloc(sizeof(*info), GFP_KERNEL);
 	if (! info)
 		return -ENOMEM;
diff --git a/sound/core/seq/seq_ports.c b/sound/core/seq/seq_ports.c
index 1c32a53..3bf7d73 100644
--- a/sound/core/seq/seq_ports.c
+++ b/sound/core/seq/seq_ports.c
@@ -130,7 +130,8 @@
 	int num = -1;
 	
 	/* sanity check */
-	snd_assert(client, return NULL);
+	if (snd_BUG_ON(!client))
+		return NULL;
 
 	if (client->num_ports >= SNDRV_SEQ_MAX_PORTS - 1) {
 		snd_printk(KERN_WARNING "too many ports for client %d\n", client->number);
@@ -268,8 +269,8 @@
 	if (port->private_free)
 		port->private_free(port->private_data);
 
-	snd_assert(port->c_src.count == 0,);
-	snd_assert(port->c_dest.count == 0,);
+	snd_BUG_ON(port->c_src.count != 0);
+	snd_BUG_ON(port->c_dest.count != 0);
 
 	kfree(port);
 	return 0;
@@ -336,7 +337,8 @@
 int snd_seq_set_port_info(struct snd_seq_client_port * port,
 			  struct snd_seq_port_info * info)
 {
-	snd_assert(port && info, return -EINVAL);
+	if (snd_BUG_ON(!port || !info))
+		return -EINVAL;
 
 	/* set port name */
 	if (info->name[0])
@@ -365,7 +367,8 @@
 int snd_seq_get_port_info(struct snd_seq_client_port * port,
 			  struct snd_seq_port_info * info)
 {
-	snd_assert(port && info, return -EINVAL);
+	if (snd_BUG_ON(!port || !info))
+		return -EINVAL;
 
 	/* get port name */
 	strlcpy(info->name, port->name, sizeof(info->name));
diff --git a/sound/core/seq/seq_prioq.c b/sound/core/seq/seq_prioq.c
index 85969db..0101a8b 100644
--- a/sound/core/seq/seq_prioq.c
+++ b/sound/core/seq/seq_prioq.c
@@ -153,8 +153,8 @@
 	int count;
 	int prior;
 
-	snd_assert(f, return -EINVAL);
-	snd_assert(cell, return -EINVAL);
+	if (snd_BUG_ON(!f || !cell))
+		return -EINVAL;
 	
 	/* check flags */
 	prior = (cell->event.flags & SNDRV_SEQ_PRIORITY_MASK);
diff --git a/sound/core/seq/seq_queue.c b/sound/core/seq/seq_queue.c
index 4a48c6e..e7a8e9e 100644
--- a/sound/core/seq/seq_queue.c
+++ b/sound/core/seq/seq_queue.c
@@ -315,7 +315,8 @@
 	int dest, err;
 	struct snd_seq_queue *q;
 
-	snd_assert(cell != NULL, return -EINVAL);
+	if (snd_BUG_ON(!cell))
+		return -EINVAL;
 	dest = cell->event.queue;	/* destination queue */
 	q = queueptr(dest);
 	if (q == NULL)
@@ -734,7 +735,8 @@
 {
 	struct snd_seq_queue *q;
 
-	snd_assert(ev != NULL, return -EINVAL);
+	if (snd_BUG_ON(!ev))
+		return -EINVAL;
 	q = queueptr(ev->data.queue.queue);
 
 	if (q == NULL)
diff --git a/sound/core/seq/seq_timer.c b/sound/core/seq/seq_timer.c
index d8fcd62..f745c31 100644
--- a/sound/core/seq/seq_timer.c
+++ b/sound/core/seq/seq_timer.c
@@ -173,7 +173,8 @@
 {
 	unsigned long flags;
 
-	snd_assert(tmr, return -EINVAL);
+	if (snd_BUG_ON(!tmr))
+		return -EINVAL;
 	if (tempo <= 0)
 		return -EINVAL;
 	spin_lock_irqsave(&tmr->lock, flags);
@@ -190,7 +191,8 @@
 {
 	unsigned long flags;
 
-	snd_assert(tmr, return -EINVAL);
+	if (snd_BUG_ON(!tmr))
+		return -EINVAL;
 	if (ppq <= 0)
 		return -EINVAL;
 	spin_lock_irqsave(&tmr->lock, flags);
@@ -214,7 +216,8 @@
 {
 	unsigned long flags;
 
-	snd_assert(tmr, return -EINVAL);
+	if (snd_BUG_ON(!tmr))
+		return -EINVAL;
 
 	spin_lock_irqsave(&tmr->lock, flags);
 	tmr->tick.cur_tick = position;
@@ -229,7 +232,8 @@
 {
 	unsigned long flags;
 
-	snd_assert(tmr, return -EINVAL);
+	if (snd_BUG_ON(!tmr))
+		return -EINVAL;
 
 	snd_seq_sanity_real_time(&position);
 	spin_lock_irqsave(&tmr->lock, flags);
@@ -244,7 +248,8 @@
 {
 	unsigned long flags;
 
-	snd_assert(tmr, return -EINVAL);
+	if (snd_BUG_ON(!tmr))
+		return -EINVAL;
 
 	/* FIXME */
 	if (base != SKEW_BASE) {
@@ -265,7 +270,8 @@
 	int err;
 
 	tmr = q->timer;
-	snd_assert(tmr != NULL, return -EINVAL);
+	if (snd_BUG_ON(!tmr))
+		return -EINVAL;
 	if (tmr->timeri)
 		return -EBUSY;
 	sprintf(str, "sequencer queue %i", q->queue);
@@ -302,7 +308,8 @@
 	struct snd_seq_timer *tmr;
 	
 	tmr = q->timer;
-	snd_assert(tmr != NULL, return -EINVAL);
+	if (snd_BUG_ON(!tmr))
+		return -EINVAL;
 	if (tmr->timeri) {
 		snd_timer_stop(tmr->timeri);
 		snd_timer_close(tmr->timeri);
@@ -328,7 +335,8 @@
 	unsigned long freq;
 
 	t = tmr->timeri->timer;
-	snd_assert(t, return -EINVAL);
+	if (snd_BUG_ON(!t))
+		return -EINVAL;
 
 	freq = tmr->preferred_resolution;
 	if (!freq)
diff --git a/sound/core/sgbuf.c b/sound/core/sgbuf.c
index cefd228..d4564ed 100644
--- a/sound/core/sgbuf.c
+++ b/sound/core/sgbuf.c
@@ -41,9 +41,11 @@
 	tmpb.dev.type = SNDRV_DMA_TYPE_DEV;
 	tmpb.dev.dev = sgbuf->dev;
 	for (i = 0; i < sgbuf->pages; i++) {
+		if (!(sgbuf->table[i].addr & ~PAGE_MASK))
+			continue; /* continuous pages */
 		tmpb.area = sgbuf->table[i].buf;
-		tmpb.addr = sgbuf->table[i].addr;
-		tmpb.bytes = PAGE_SIZE;
+		tmpb.addr = sgbuf->table[i].addr & PAGE_MASK;
+		tmpb.bytes = (sgbuf->table[i].addr & ~PAGE_MASK) << PAGE_SHIFT;
 		snd_dma_free_pages(&tmpb);
 	}
 	if (dmab->area)
@@ -58,13 +60,17 @@
 	return 0;
 }
 
+#define MAX_ALLOC_PAGES		32
+
 void *snd_malloc_sgbuf_pages(struct device *device,
 			     size_t size, struct snd_dma_buffer *dmab,
 			     size_t *res_size)
 {
 	struct snd_sg_buf *sgbuf;
-	unsigned int i, pages;
+	unsigned int i, pages, chunk, maxpages;
 	struct snd_dma_buffer tmpb;
+	struct snd_sg_page *table;
+	struct page **pgtable;
 
 	dmab->area = NULL;
 	dmab->addr = 0;
@@ -74,31 +80,55 @@
 	sgbuf->dev = device;
 	pages = snd_sgbuf_aligned_pages(size);
 	sgbuf->tblsize = sgbuf_align_table(pages);
-	sgbuf->table = kcalloc(sgbuf->tblsize, sizeof(*sgbuf->table), GFP_KERNEL);
-	if (! sgbuf->table)
+	table = kcalloc(sgbuf->tblsize, sizeof(*table), GFP_KERNEL);
+	if (!table)
 		goto _failed;
-	sgbuf->page_table = kcalloc(sgbuf->tblsize, sizeof(*sgbuf->page_table), GFP_KERNEL);
-	if (! sgbuf->page_table)
+	sgbuf->table = table;
+	pgtable = kcalloc(sgbuf->tblsize, sizeof(*pgtable), GFP_KERNEL);
+	if (!pgtable)
 		goto _failed;
+	sgbuf->page_table = pgtable;
 
-	/* allocate each page */
-	for (i = 0; i < pages; i++) {
-		if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, device, PAGE_SIZE, &tmpb) < 0) {
-			if (res_size == NULL)
+	/* allocate pages */
+	maxpages = MAX_ALLOC_PAGES;
+	while (pages > 0) {
+		chunk = pages;
+		/* don't be too eager to take a huge chunk */
+		if (chunk > maxpages)
+			chunk = maxpages;
+		chunk <<= PAGE_SHIFT;
+		if (snd_dma_alloc_pages_fallback(SNDRV_DMA_TYPE_DEV, device,
+						 chunk, &tmpb) < 0) {
+			if (!sgbuf->pages)
+				return NULL;
+			if (!res_size)
 				goto _failed;
-			*res_size = size = sgbuf->pages * PAGE_SIZE;
+			size = sgbuf->pages * PAGE_SIZE;
 			break;
 		}
-		sgbuf->table[i].buf = tmpb.area;
-		sgbuf->table[i].addr = tmpb.addr;
-		sgbuf->page_table[i] = virt_to_page(tmpb.area);
-		sgbuf->pages++;
+		chunk = tmpb.bytes >> PAGE_SHIFT;
+		for (i = 0; i < chunk; i++) {
+			table->buf = tmpb.area;
+			table->addr = tmpb.addr;
+			if (!i)
+				table->addr |= chunk; /* mark head */
+			table++;
+			*pgtable++ = virt_to_page(tmpb.area);
+			tmpb.area += PAGE_SIZE;
+			tmpb.addr += PAGE_SIZE;
+		}
+		sgbuf->pages += chunk;
+		pages -= chunk;
+		if (chunk < maxpages)
+			maxpages = chunk;
 	}
 
 	sgbuf->size = size;
 	dmab->area = vmap(sgbuf->page_table, sgbuf->pages, VM_MAP, PAGE_KERNEL);
 	if (! dmab->area)
 		goto _failed;
+	if (res_size)
+		*res_size = sgbuf->size;
 	return dmab->area;
 
  _failed:
diff --git a/sound/core/sound.c b/sound/core/sound.c
index 1003ae3..c0685e2 100644
--- a/sound/core/sound.c
+++ b/sound/core/sound.c
@@ -34,8 +34,6 @@
 #include <linux/kmod.h>
 #include <linux/mutex.h>
 
-#define SNDRV_OS_MINORS 256
-
 static int major = CONFIG_SND_MAJOR;
 int snd_major;
 EXPORT_SYMBOL(snd_major);
@@ -208,20 +206,23 @@
 		minor = type;
 		break;
 	case SNDRV_DEVICE_TYPE_CONTROL:
-		snd_assert(card != NULL, return -EINVAL);
+		if (snd_BUG_ON(!card))
+			return -EINVAL;
 		minor = SNDRV_MINOR(card->number, type);
 		break;
 	case SNDRV_DEVICE_TYPE_HWDEP:
 	case SNDRV_DEVICE_TYPE_RAWMIDI:
 	case SNDRV_DEVICE_TYPE_PCM_PLAYBACK:
 	case SNDRV_DEVICE_TYPE_PCM_CAPTURE:
-		snd_assert(card != NULL, return -EINVAL);
+		if (snd_BUG_ON(!card))
+			return -EINVAL;
 		minor = SNDRV_MINOR(card->number, type + dev);
 		break;
 	default:
 		return -EINVAL;
 	}
-	snd_assert(minor >= 0 && minor < SNDRV_OS_MINORS, return -EINVAL);
+	if (snd_BUG_ON(minor < 0 || minor >= SNDRV_OS_MINORS))
+		return -EINVAL;
 	return minor;
 }
 #endif
@@ -249,7 +250,8 @@
 	int minor;
 	struct snd_minor *preg;
 
-	snd_assert(name, return -EINVAL);
+	if (snd_BUG_ON(!name))
+		return -EINVAL;
 	preg = kmalloc(sizeof *preg, GFP_KERNEL);
 	if (preg == NULL)
 		return -ENOMEM;
diff --git a/sound/core/sound_oss.c b/sound/core/sound_oss.c
index 7be5154..7fe1226 100644
--- a/sound/core/sound_oss.c
+++ b/sound/core/sound_oss.c
@@ -64,7 +64,8 @@
 
 	switch (type) {
 	case SNDRV_OSS_DEVICE_TYPE_MIXER:
-		snd_assert(card != NULL && dev <= 1, return -EINVAL);
+		if (snd_BUG_ON(!card || dev < 0 || dev > 1))
+			return -EINVAL;
 		minor = SNDRV_MINOR_OSS(card->number, (dev ? SNDRV_MINOR_OSS_MIXER1 : SNDRV_MINOR_OSS_MIXER));
 		break;
 	case SNDRV_OSS_DEVICE_TYPE_SEQUENCER:
@@ -74,11 +75,13 @@
 		minor = SNDRV_MINOR_OSS_MUSIC;
 		break;
 	case SNDRV_OSS_DEVICE_TYPE_PCM:
-		snd_assert(card != NULL && dev <= 1, return -EINVAL);
+		if (snd_BUG_ON(!card || dev < 0 || dev > 1))
+			return -EINVAL;
 		minor = SNDRV_MINOR_OSS(card->number, (dev ? SNDRV_MINOR_OSS_PCM1 : SNDRV_MINOR_OSS_PCM));
 		break;
 	case SNDRV_OSS_DEVICE_TYPE_MIDI:
-		snd_assert(card != NULL && dev <= 1, return -EINVAL);
+		if (snd_BUG_ON(!card || dev < 0 || dev > 1))
+			return -EINVAL;
 		minor = SNDRV_MINOR_OSS(card->number, (dev ? SNDRV_MINOR_OSS_MIDI1 : SNDRV_MINOR_OSS_MIDI));
 		break;
 	case SNDRV_OSS_DEVICE_TYPE_DMFM:
@@ -90,7 +93,8 @@
 	default:
 		return -EINVAL;
 	}
-	snd_assert(minor >= 0 && minor < SNDRV_OSS_MINORS, return -EINVAL);
+	if (snd_BUG_ON(minor < 0 || minor >= SNDRV_OSS_MINORS))
+		return -EINVAL;
 	return minor;
 }
 
diff --git a/sound/core/timer.c b/sound/core/timer.c
index 0af337e..e582fac 100644
--- a/sound/core/timer.c
+++ b/sound/core/timer.c
@@ -306,7 +306,8 @@
 	struct snd_timer *timer = NULL;
 	struct snd_timer_instance *slave, *tmp;
 
-	snd_assert(timeri != NULL, return -ENXIO);
+	if (snd_BUG_ON(!timeri))
+		return -ENXIO;
 
 	/* force to stop the timer */
 	snd_timer_stop(timeri);
@@ -385,8 +386,9 @@
 		do_posix_clock_monotonic_gettime(&tstamp);
 	else
 		getnstimeofday(&tstamp);
-	snd_assert(event >= SNDRV_TIMER_EVENT_START &&
-		   event <= SNDRV_TIMER_EVENT_PAUSE, return);
+	if (snd_BUG_ON(event < SNDRV_TIMER_EVENT_START ||
+		       event > SNDRV_TIMER_EVENT_PAUSE))
+		return;
 	if (event == SNDRV_TIMER_EVENT_START ||
 	    event == SNDRV_TIMER_EVENT_CONTINUE)
 		resolution = snd_timer_resolution(ti);
@@ -474,7 +476,8 @@
 	struct snd_timer *timer;
 	unsigned long flags;
 
-	snd_assert(timeri != NULL, return -ENXIO);
+	if (snd_BUG_ON(!timeri))
+		return -ENXIO;
 
 	if (timeri->flags & SNDRV_TIMER_IFLG_SLAVE) {
 		if (!keep_flag) {
@@ -758,9 +761,10 @@
 		.dev_disconnect = snd_timer_dev_disconnect,
 	};
 
-	snd_assert(tid != NULL, return -EINVAL);
-	snd_assert(rtimer != NULL, return -EINVAL);
-	*rtimer = NULL;
+	if (snd_BUG_ON(!tid))
+		return -EINVAL;
+	if (rtimer)
+		*rtimer = NULL;
 	timer = kzalloc(sizeof(*timer), GFP_KERNEL);
 	if (timer == NULL) {
 		snd_printk(KERN_ERR "timer: cannot allocate\n");
@@ -788,13 +792,15 @@
 			return err;
 		}
 	}
-	*rtimer = timer;
+	if (rtimer)
+		*rtimer = timer;
 	return 0;
 }
 
 static int snd_timer_free(struct snd_timer *timer)
 {
-	snd_assert(timer != NULL, return -ENXIO);
+	if (!timer)
+		return 0;
 
 	mutex_lock(&register_mutex);
 	if (! list_empty(&timer->open_list_head)) {
@@ -827,8 +833,8 @@
 	struct snd_timer *timer = dev->device_data;
 	struct snd_timer *timer1;
 
-	snd_assert(timer != NULL && timer->hw.start != NULL &&
-		   timer->hw.stop != NULL, return -ENXIO);
+	if (snd_BUG_ON(!timer || !timer->hw.start || !timer->hw.stop))
+		return -ENXIO;
 	if (!(timer->hw.flags & SNDRV_TIMER_HW_SLAVE) &&
 	    !timer->hw.resolution && timer->hw.c_resolution == NULL)
 	    	return -EINVAL;
@@ -879,8 +885,9 @@
 
 	if (! (timer->hw.flags & SNDRV_TIMER_HW_SLAVE))
 		return;
-	snd_assert(event >= SNDRV_TIMER_EVENT_MSTART &&
-		   event <= SNDRV_TIMER_EVENT_MRESUME, return);
+	if (snd_BUG_ON(event < SNDRV_TIMER_EVENT_MSTART ||
+		       event > SNDRV_TIMER_EVENT_MRESUME))
+		return;
 	spin_lock_irqsave(&timer->lock, flags);
 	if (event == SNDRV_TIMER_EVENT_MSTART ||
 	    event == SNDRV_TIMER_EVENT_MCONTINUE ||
diff --git a/sound/core/timer_compat.c b/sound/core/timer_compat.c
index 5512f53..e05802a 100644
--- a/sound/core/timer_compat.c
+++ b/sound/core/timer_compat.c
@@ -40,9 +40,11 @@
 	struct snd_timer *t;
 
 	tu = file->private_data;
-	snd_assert(tu->timeri != NULL, return -ENXIO);
+	if (snd_BUG_ON(!tu->timeri))
+		return -ENXIO;
 	t = tu->timeri->timer;
-	snd_assert(t != NULL, return -ENXIO);
+	if (snd_BUG_ON(!t))
+		return -ENXIO;
 	memset(&info, 0, sizeof(info));
 	info.card = t->card ? t->card->number : -1;
 	if (t->hw.flags & SNDRV_TIMER_HW_SLAVE)
@@ -71,7 +73,8 @@
 	struct snd_timer_status status;
 	
 	tu = file->private_data;
-	snd_assert(tu->timeri != NULL, return -ENXIO);
+	if (snd_BUG_ON(!tu->timeri))
+		return -ENXIO;
 	memset(&status, 0, sizeof(status));
 	status.tstamp = tu->tstamp;
 	status.resolution = snd_timer_resolution(tu->timeri);
diff --git a/sound/drivers/dummy.c b/sound/drivers/dummy.c
index 4e4c69e..e5e749f 100644
--- a/sound/drivers/dummy.c
+++ b/sound/drivers/dummy.c
@@ -47,9 +47,11 @@
 static int emu10k1_playback_constraints(struct snd_pcm_runtime *runtime)
 {
 	int err;
-	if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0)
+	err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
+	if (err < 0)
 		return err;
-	if ((err = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 256, UINT_MAX)) < 0)
+	err = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 256, UINT_MAX);
+	if (err) < 0)
 		return err;
 	return 0;
 }
@@ -354,6 +356,7 @@
 	if ((dpcm = new_pcm_stream(substream)) == NULL)
 		return -ENOMEM;
 	runtime->private_data = dpcm;
+	/* makes the infrastructure responsible for freeing dpcm */
 	runtime->private_free = snd_card_dummy_runtime_free;
 	runtime->hw = snd_card_dummy_playback;
 	if (substream->pcm->device & 1) {
@@ -362,10 +365,9 @@
 	}
 	if (substream->pcm->device & 2)
 		runtime->hw.info &= ~(SNDRV_PCM_INFO_MMAP|SNDRV_PCM_INFO_MMAP_VALID);
-	if ((err = add_playback_constraints(runtime)) < 0) {
-		kfree(dpcm);
+	err = add_playback_constraints(runtime);
+	if (err < 0)
 		return err;
-	}
 
 	return 0;
 }
@@ -379,6 +381,7 @@
 	if ((dpcm = new_pcm_stream(substream)) == NULL)
 		return -ENOMEM;
 	runtime->private_data = dpcm;
+	/* makes the infrastructure responsible for freeing dpcm */
 	runtime->private_free = snd_card_dummy_runtime_free;
 	runtime->hw = snd_card_dummy_capture;
 	if (substream->pcm->device == 1) {
@@ -387,10 +390,9 @@
 	}
 	if (substream->pcm->device & 2)
 		runtime->hw.info &= ~(SNDRV_PCM_INFO_MMAP|SNDRV_PCM_INFO_MMAP_VALID);
-	if ((err = add_capture_constraints(runtime)) < 0) {
-		kfree(dpcm);
+	err = add_capture_constraints(runtime);
+	if (err < 0)
 		return err;
-	}
 
 	return 0;
 }
@@ -433,8 +435,9 @@
 	struct snd_pcm *pcm;
 	int err;
 
-	if ((err = snd_pcm_new(dummy->card, "Dummy PCM", device,
-			       substreams, substreams, &pcm)) < 0)
+	err = snd_pcm_new(dummy->card, "Dummy PCM", device,
+			       substreams, substreams, &pcm);
+	if (err < 0)
 		return err;
 	dummy->pcm = pcm;
 	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_card_dummy_playback_ops);
@@ -565,12 +568,14 @@
 	unsigned int idx;
 	int err;
 
-	snd_assert(dummy != NULL, return -EINVAL);
+	if (snd_BUG_ON(!dummy))
+		return -EINVAL;
 	spin_lock_init(&dummy->mixer_lock);
 	strcpy(card->mixername, "Dummy Mixer");
 
 	for (idx = 0; idx < ARRAY_SIZE(snd_dummy_controls); idx++) {
-		if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_dummy_controls[idx], dummy))) < 0)
+		err = snd_ctl_add(card, snd_ctl_new1(&snd_dummy_controls[idx], dummy));
+		if (err < 0)
 			return err;
 	}
 	return 0;
@@ -594,10 +599,12 @@
 			pcm_substreams[dev] = 1;
 		if (pcm_substreams[dev] > MAX_PCM_SUBSTREAMS)
 			pcm_substreams[dev] = MAX_PCM_SUBSTREAMS;
-		if ((err = snd_card_dummy_pcm(dummy, idx, pcm_substreams[dev])) < 0)
+		err = snd_card_dummy_pcm(dummy, idx, pcm_substreams[dev]);
+		if (err < 0)
 			goto __nodev;
 	}
-	if ((err = snd_card_dummy_new_mixer(dummy)) < 0)
+	err = snd_card_dummy_new_mixer(dummy);
+	if (err < 0)
 		goto __nodev;
 	strcpy(card->driver, "Dummy");
 	strcpy(card->shortname, "Dummy");
@@ -605,7 +612,8 @@
 
 	snd_card_set_dev(card, &devptr->dev);
 
-	if ((err = snd_card_register(card)) == 0) {
+	err = snd_card_register(card);
+	if (err == 0) {
 		platform_set_drvdata(devptr, card);
 		return 0;
 	}
@@ -668,7 +676,8 @@
 {
 	int i, cards, err;
 
-	if ((err = platform_driver_register(&snd_dummy_driver)) < 0)
+	err = platform_driver_register(&snd_dummy_driver);
+	if (err < 0)
 		return err;
 
 	cards = 0;
diff --git a/sound/drivers/mtpav.c b/sound/drivers/mtpav.c
index b5e1a71..5b89c088 100644
--- a/sound/drivers/mtpav.c
+++ b/sound/drivers/mtpav.c
@@ -715,6 +715,10 @@
 
 	card->private_free = snd_mtpav_free;
 
+	err = snd_mtpav_get_RAWMIDI(mtp_card);
+	if (err < 0)
+		goto __error;
+
 	err = snd_mtpav_get_ISA(mtp_card);
 	if (err < 0)
 		goto __error;
@@ -724,10 +728,6 @@
 	snprintf(card->longname, sizeof(card->longname),
 		 "MTPAV on parallel port at 0x%lx", port);
 
-	err = snd_mtpav_get_RAWMIDI(mtp_card);
-	if (err < 0)
-		goto __error;
-
 	snd_mtpav_portscan(mtp_card);
 
 	snd_card_set_dev(card, &dev->dev);
diff --git a/sound/drivers/opl3/opl3_lib.c b/sound/drivers/opl3/opl3_lib.c
index ebe4359..7805823 100644
--- a/sound/drivers/opl3/opl3_lib.c
+++ b/sound/drivers/opl3/opl3_lib.c
@@ -139,7 +139,8 @@
 		 * If we had an OPL4 chip, opl3->hardware would have been set
 		 * by the OPL4 driver; so we can assume OPL3 here.
 		 */
-		snd_assert(opl3->r_port != 0, return -ENODEV);
+		if (snd_BUG_ON(!opl3->r_port))
+			return -ENODEV;
 		opl3->hardware = OPL3_HW_OPL3;
 	}
 	return 0;
@@ -324,7 +325,8 @@
 
 static int snd_opl3_free(struct snd_opl3 *opl3)
 {
-	snd_assert(opl3 != NULL, return -ENXIO);
+	if (snd_BUG_ON(!opl3))
+		return -ENXIO;
 	if (opl3->private_free)
 		opl3->private_free(opl3);
 	snd_opl3_clear_patches(opl3);
diff --git a/sound/drivers/opl3/opl3_midi.c b/sound/drivers/opl3/opl3_midi.c
index cebcb8b..16feafa 100644
--- a/sound/drivers/opl3/opl3_midi.c
+++ b/sound/drivers/opl3/opl3_midi.c
@@ -617,7 +617,8 @@
 
 	struct snd_opl3_voice *vp, *vp2;
 
-	snd_assert(voice < MAX_OPL3_VOICES, return);
+	if (snd_BUG_ON(voice >= MAX_OPL3_VOICES))
+		return;
 
 	vp = &opl3->voices[voice];
 	if (voice < MAX_OPL2_VOICES) {
@@ -737,7 +738,8 @@
 
 	struct snd_opl3_voice *vp;
 
-	snd_assert(voice < MAX_OPL3_VOICES, return);
+	if (snd_BUG_ON(voice >= MAX_OPL3_VOICES))
+		return;
 
 	vp = &opl3->voices[voice];
 	if (vp->chan == NULL)
diff --git a/sound/drivers/opl3/opl3_oss.c b/sound/drivers/opl3/opl3_oss.c
index 239347f..9a2271d 100644
--- a/sound/drivers/opl3/opl3_oss.c
+++ b/sound/drivers/opl3/opl3_oss.c
@@ -162,7 +162,8 @@
 	struct snd_opl3 *opl3 = closure;
 	int err;
 
-	snd_assert(arg != NULL, return -ENXIO);
+	if (snd_BUG_ON(!arg))
+		return -ENXIO;
 
 	if ((err = snd_opl3_synth_setup(opl3)) < 0)
 		return err;
@@ -184,7 +185,8 @@
 {
 	struct snd_opl3 *opl3;
 
-	snd_assert(arg != NULL, return -ENXIO);
+	if (snd_BUG_ON(!arg))
+		return -ENXIO;
 	opl3 = arg->private_data;
 
 	snd_opl3_synth_cleanup(opl3);
@@ -206,7 +208,8 @@
 	char name[32];
 	int err, type;
 
-	snd_assert(arg != NULL, return -ENXIO);
+	if (snd_BUG_ON(!arg))
+		return -ENXIO;
 	opl3 = arg->private_data;
 
 	if (format == FM_PATCH)
@@ -246,7 +249,8 @@
 {
 	struct snd_opl3 *opl3;
 
-	snd_assert(arg != NULL, return -ENXIO);
+	if (snd_BUG_ON(!arg))
+		return -ENXIO;
 	opl3 = arg->private_data;
 	switch (cmd) {
 		case SNDCTL_FM_LOAD_INSTR:
@@ -271,7 +275,8 @@
 {
 	struct snd_opl3 *opl3;
 
-	snd_assert(arg != NULL, return -ENXIO);
+	if (snd_BUG_ON(!arg))
+		return -ENXIO;
 	opl3 = arg->private_data;
 
 	return 0;
diff --git a/sound/drivers/opl3/opl3_synth.c b/sound/drivers/opl3/opl3_synth.c
index fb64c89..962bb9c 100644
--- a/sound/drivers/opl3/opl3_synth.c
+++ b/sound/drivers/opl3/opl3_synth.c
@@ -92,7 +92,8 @@
 	struct snd_opl3 *opl3 = hw->private_data;
 	void __user *argp = (void __user *)arg;
 
-	snd_assert(opl3 != NULL, return -EINVAL);
+	if (snd_BUG_ON(!opl3))
+		return -EINVAL;
 
 	switch (cmd) {
 		/* get information */
diff --git a/sound/drivers/opl4/opl4_synth.c b/sound/drivers/opl4/opl4_synth.c
index 74f6e53..49b9e24 100644
--- a/sound/drivers/opl4/opl4_synth.c
+++ b/sound/drivers/opl4/opl4_synth.c
@@ -467,7 +467,7 @@
 	if (!list_empty(&opl4->off_voices))
 		return list_entry(opl4->off_voices.next, struct opl4_voice, list);
 	/* then get the oldest key-on voice */
-	snd_assert(!list_empty(&opl4->on_voices), );
+	snd_BUG_ON(list_empty(&opl4->on_voices));
 	return list_entry(opl4->on_voices.next, struct opl4_voice, list);
 }
 
diff --git a/sound/drivers/vx/vx_cmd.c b/sound/drivers/vx/vx_cmd.c
index 9529e3b..23f4857 100644
--- a/sound/drivers/vx/vx_cmd.c
+++ b/sound/drivers/vx/vx_cmd.c
@@ -99,7 +99,8 @@
  */
 void vx_init_rmh(struct vx_rmh *rmh, unsigned int cmd)
 {
-	snd_assert(cmd < CMD_LAST_INDEX, return);
+	if (snd_BUG_ON(cmd >= CMD_LAST_INDEX))
+		return;
 	rmh->LgCmd = vx_dsp_cmds[cmd].length;
 	rmh->LgStat = vx_dsp_cmds[cmd].st_length;
 	rmh->DspStat = vx_dsp_cmds[cmd].st_type;
diff --git a/sound/drivers/vx/vx_core.c b/sound/drivers/vx/vx_core.c
index 585af2e..473b07f 100644
--- a/sound/drivers/vx/vx_core.c
+++ b/sound/drivers/vx/vx_core.c
@@ -205,7 +205,8 @@
 
 	if (size < 1)
 		return 0;
-	snd_assert(size <= SIZE_MAX_STATUS, return -EINVAL);
+	if (snd_BUG_ON(size > SIZE_MAX_STATUS))
+		return -EINVAL;
 
 	for (i = 1; i <= size; i++) {
 		/* trigger an irq MESS_WRITE_NEXT */
@@ -425,13 +426,16 @@
 	int no_fillup = vx_has_new_dsp(chip);
 
 	/* check the length of boot image */
-	snd_assert(boot->size > 0, return -EINVAL);
-	snd_assert(boot->size % 3 == 0, return -EINVAL);
+	if (boot->size <= 0)
+		return -EINVAL;
+	if (boot->size % 3)
+		return -EINVAL;
 #if 0
 	{
 		/* more strict check */
 		unsigned int c = ((u32)boot->data[0] << 16) | ((u32)boot->data[1] << 8) | boot->data[2];
-		snd_assert(boot->size == (c + 2) * 3, return -EINVAL);
+		if (boot->size != (c + 2) * 3)
+			return -EINVAL;
 	}
 #endif
 
@@ -554,7 +558,8 @@
  */
 static void vx_reset_board(struct vx_core *chip, int cold_reset)
 {
-	snd_assert(chip->ops->reset_board, return);
+	if (snd_BUG_ON(!chip->ops->reset_board))
+		return;
 
 	/* current source, later sync'ed with target */
 	chip->audio_source = VX_AUDIO_SRC_LINE;
@@ -673,7 +678,8 @@
 	unsigned int csum = 0;
 	const unsigned char *image, *cptr;
 
-	snd_assert(dsp->size % 3 == 0, return -EINVAL);
+	if (dsp->size % 3)
+		return -EINVAL;
 
 	vx_toggle_dac_mute(chip, 1);
 
@@ -775,7 +781,8 @@
 {
 	struct vx_core *chip;
 
-	snd_assert(card && hw && ops, return NULL);
+	if (snd_BUG_ON(!card || !hw || !ops))
+		return NULL;
 
 	chip = kzalloc(sizeof(*chip) + extra_size, GFP_KERNEL);
 	if (! chip) {
diff --git a/sound/drivers/vx/vx_hwdep.c b/sound/drivers/vx/vx_hwdep.c
index efd22e9..8d6362e 100644
--- a/sound/drivers/vx/vx_hwdep.c
+++ b/sound/drivers/vx/vx_hwdep.c
@@ -141,7 +141,8 @@
 	};
 	struct vx_core *vx = hw->private_data;
 
-	snd_assert(type_ids[vx->type], return -EINVAL);
+	if (snd_BUG_ON(!type_ids[vx->type]))
+		return -EINVAL;
 	strcpy(info->id, type_ids[vx->type]);
 	if (vx_is_pcmcia(vx))
 		info->num_dsps = 4;
@@ -168,7 +169,8 @@
 	int index, err;
 	struct firmware *fw;
 
-	snd_assert(vx->ops->load_dsp, return -ENXIO);
+	if (snd_BUG_ON(!vx->ops->load_dsp))
+		return -ENXIO;
 
 	fw = kmalloc(sizeof(*fw), GFP_KERNEL);
 	if (! fw) {
diff --git a/sound/drivers/vx/vx_mixer.c b/sound/drivers/vx/vx_mixer.c
index 5a34732..c71b8d1 100644
--- a/sound/drivers/vx/vx_mixer.c
+++ b/sound/drivers/vx/vx_mixer.c
@@ -34,7 +34,8 @@
 {
 	unsigned long flags;
 
-	snd_assert(chip->ops->write_codec, return);
+	if (snd_BUG_ON(!chip->ops->write_codec))
+		return;
 
 	if (chip->chip_status & VX_STAT_IS_STALE)
 		return;
diff --git a/sound/drivers/vx/vx_pcm.c b/sound/drivers/vx/vx_pcm.c
index fdbf865..27de574 100644
--- a/sound/drivers/vx/vx_pcm.c
+++ b/sound/drivers/vx/vx_pcm.c
@@ -587,7 +587,8 @@
 		return -EBUSY;
 
 	audio = subs->pcm->device * 2;
-	snd_assert(audio < chip->audio_outs, return -EINVAL);
+	if (snd_BUG_ON(audio >= chip->audio_outs))
+		return -EINVAL;
 	
 	/* playback pipe may have been already allocated for monitoring */
 	pipe = chip->playback_pipes[audio];
@@ -996,7 +997,8 @@
 		return -EBUSY;
 
 	audio = subs->pcm->device * 2;
-	snd_assert(audio < chip->audio_ins, return -EINVAL);
+	if (snd_BUG_ON(audio >= chip->audio_ins))
+		return -EINVAL;
 	err = vx_alloc_pipe(chip, 1, audio, 2, &pipe);
 	if (err < 0)
 		return err;
@@ -1214,7 +1216,8 @@
 			}
 			if (capture)
 				continue;
-			snd_assert(p >= 0 && (unsigned int)p < chip->audio_outs,);
+			if (snd_BUG_ON(p < 0 || p >= chip->audio_outs))
+				continue;
 			pipe = chip->playback_pipes[p];
 			if (pipe && pipe->substream) {
 				vx_pcm_playback_update(chip, pipe->substream, pipe);
diff --git a/sound/drivers/vx/vx_uer.c b/sound/drivers/vx/vx_uer.c
index fb8932a..0e1ba9b 100644
--- a/sound/drivers/vx/vx_uer.c
+++ b/sound/drivers/vx/vx_uer.c
@@ -163,13 +163,15 @@
 {
 	int hexfreq;
 
-	snd_assert(freq > 0, return 0);
+	if (snd_BUG_ON(freq <= 0))
+		return 0;
 
 	hexfreq = (28224000 * 10) / freq;
 	hexfreq = (hexfreq + 5) / 10;
 
 	/* max freq = 55125 Hz */
-	snd_assert(hexfreq > 0x00000200, return 0);
+	if (snd_BUG_ON(hexfreq <= 0x00000200))
+		return 0;
 
 	if (hexfreq <= 0x03ff)
 		return hexfreq - 0x00000201;
diff --git a/sound/i2c/cs8427.c b/sound/i2c/cs8427.c
index 9c3d361..020a5d5 100644
--- a/sound/i2c/cs8427.c
+++ b/sound/i2c/cs8427.c
@@ -314,7 +314,8 @@
 	unsigned long end_time;
 	int data, aes3input = 0;
 
-	snd_assert(cs8427, return);
+	if (snd_BUG_ON(!cs8427))
+		return;
 	chip = cs8427->private_data;
 	snd_i2c_lock(cs8427->bus);
 	if ((chip->regmap[CS8427_REG_CLOCKSOURCE] & CS8427_RXDAES3INPUT) ==
@@ -526,7 +527,8 @@
 	unsigned int idx;
 	int err;
 
-	snd_assert(play_substream && cap_substream, return -EINVAL);
+	if (snd_BUG_ON(!play_substream || !cap_substream))
+		return -EINVAL;
 	for (idx = 0; idx < ARRAY_SIZE(snd_cs8427_iec958_controls); idx++) {
 		kctl = snd_ctl_new1(&snd_cs8427_iec958_controls[idx], cs8427);
 		if (kctl == NULL)
@@ -543,7 +545,8 @@
 
 	chip->playback.substream = play_substream;
 	chip->capture.substream = cap_substream;
-	snd_assert(chip->playback.pcm_ctl, return -EIO);
+	if (snd_BUG_ON(!chip->playback.pcm_ctl))
+		return -EIO;
 	return 0;
 }
 
@@ -553,7 +556,8 @@
 {
 	struct cs8427 *chip;
 
-	snd_assert(cs8427, return -ENXIO);
+	if (snd_BUG_ON(!cs8427))
+		return -ENXIO;
 	chip = cs8427->private_data;
 	if (active)
 		memcpy(chip->playback.pcm_status,
@@ -573,7 +577,8 @@
 	char *status;
 	int err, reset;
 
-	snd_assert(cs8427, return -ENXIO);
+	if (snd_BUG_ON(!cs8427))
+		return -ENXIO;
 	chip = cs8427->private_data;
 	status = chip->playback.pcm_status;
 	snd_i2c_lock(cs8427->bus);
diff --git a/sound/i2c/i2c.c b/sound/i2c/i2c.c
index b1e74e4..5c0c77d 100644
--- a/sound/i2c/i2c.c
+++ b/sound/i2c/i2c.c
@@ -49,7 +49,8 @@
 	struct snd_i2c_bus *slave;
 	struct snd_i2c_device *device;
 
-	snd_assert(bus != NULL, return -EINVAL);
+	if (snd_BUG_ON(!bus))
+		return -EINVAL;
 	while (!list_empty(&bus->devices)) {
 		device = snd_i2c_device(bus->devices.next);
 		snd_i2c_device_free(device);
@@ -113,7 +114,8 @@
 	struct snd_i2c_device *device;
 
 	*rdevice = NULL;
-	snd_assert(bus != NULL, return -EINVAL);
+	if (snd_BUG_ON(!bus))
+		return -EINVAL;
 	device = kzalloc(sizeof(*device), GFP_KERNEL);
 	if (device == NULL)
 		return -ENOMEM;
diff --git a/sound/i2c/l3/uda1341.c b/sound/i2c/l3/uda1341.c
index 1f4942e..9840eb4 100644
--- a/sound/i2c/l3/uda1341.c
+++ b/sound/i2c/l3/uda1341.c
@@ -771,7 +771,8 @@
 	struct l3_client *clnt;
 	int idx, err;
 
-	snd_assert(card != NULL, return -EINVAL);
+	if (snd_BUG_ON(!card))
+		return -EINVAL;
 
 	clnt = kzalloc(sizeof(*clnt), GFP_KERNEL);
 	if (clnt == NULL)
diff --git a/sound/i2c/other/ak4114.c b/sound/i2c/other/ak4114.c
index d20d893b..0341451 100644
--- a/sound/i2c/other/ak4114.c
+++ b/sound/i2c/other/ak4114.c
@@ -475,7 +475,8 @@
 	unsigned int idx;
 	int err;
 
-	snd_assert(cap_substream, return -EINVAL);
+	if (snd_BUG_ON(!cap_substream))
+		return -EINVAL;
 	ak4114->playback_substream = ply_substream;
 	ak4114->capture_substream = cap_substream;
 	for (idx = 0; idx < AK4114_CONTROLS; idx++) {
diff --git a/sound/i2c/other/ak4117.c b/sound/i2c/other/ak4117.c
index f350835..2cad2d6 100644
--- a/sound/i2c/other/ak4117.c
+++ b/sound/i2c/other/ak4117.c
@@ -431,7 +431,8 @@
 	unsigned int idx;
 	int err;
 
-	snd_assert(cap_substream, return -EINVAL);
+	if (snd_BUG_ON(!cap_substream))
+		return -EINVAL;
 	ak4117->substream = cap_substream;
 	for (idx = 0; idx < AK4117_CONTROLS; idx++) {
 		kctl = snd_ctl_new1(&snd_ak4117_iec958_controls[idx], ak4117);
diff --git a/sound/i2c/other/ak4xxx-adda.c b/sound/i2c/other/ak4xxx-adda.c
index 288926d..ee47aba 100644
--- a/sound/i2c/other/ak4xxx-adda.c
+++ b/sound/i2c/other/ak4xxx-adda.c
@@ -233,8 +233,8 @@
 		0x01, 0x02, /* 1: reset and soft-mute */
 		0x00, 0x06, /* 0: mode3(i2s), disable auto-clock detect,
 			     * disable DZF, sharp roll-off, RSTN#=0 */
-		0x02, 0x0e, /* 2: DA's power up, normal speed, RSTN#=0 */
-		// 0x02, 0x2e, /* quad speed */
+		0x02, 0x4e, /* 2: DA's power up, normal speed, RSTN#=0 */
+		/* 0x02, 0x6e,*/ /* quad speed */
 		0x03, 0x01, /* 3: de-emphasis off */
 		0x04, 0x00, /* 4: LOUT1 volume muted */
 		0x05, 0x00, /* 5: ROUT1 volume muted */
diff --git a/sound/i2c/other/tea575x-tuner.c b/sound/i2c/other/tea575x-tuner.c
index 83e9005..c13a178 100644
--- a/sound/i2c/other/tea575x-tuner.c
+++ b/sound/i2c/other/tea575x-tuner.c
@@ -87,8 +87,7 @@
 static int snd_tea575x_ioctl(struct inode *inode, struct file *file,
 			     unsigned int cmd, unsigned long data)
 {
-	struct video_device *dev = video_devdata(file);
-	struct snd_tea575x *tea = video_get_drvdata(dev);
+	struct snd_tea575x *tea = video_drvdata(file);
 	void __user *arg = (void __user *)data;
 	
 	switch(cmd) {
@@ -175,6 +174,21 @@
 {
 }
 
+static int snd_tea575x_exclusive_open(struct inode *inode, struct file *file)
+{
+	struct snd_tea575x *tea = video_drvdata(file);
+
+	return test_and_set_bit(0, &tea->in_use) ? -EBUSY : 0;
+}
+
+static int snd_tea575x_exclusive_release(struct inode *inode, struct file *file)
+{
+	struct snd_tea575x *tea = video_drvdata(file);
+
+	clear_bit(0, &tea->in_use);
+	return 0;
+}
+
 /*
  * initialize all the tea575x chips
  */
@@ -193,9 +207,10 @@
 	tea->vd.release = snd_tea575x_release;
 	video_set_drvdata(&tea->vd, tea);
 	tea->vd.fops = &tea->fops;
+	tea->in_use = 0;
 	tea->fops.owner = tea->card->module;
-	tea->fops.open = video_exclusive_open;
-	tea->fops.release = video_exclusive_release;
+	tea->fops.open = snd_tea575x_exclusive_open;
+	tea->fops.release = snd_tea575x_exclusive_release;
 	tea->fops.ioctl = snd_tea575x_ioctl;
 	if (video_register_device(&tea->vd, VFL_TYPE_RADIO, tea->dev_nr - 1) < 0) {
 		snd_printk(KERN_ERR "unable to register tea575x tuner\n");
diff --git a/sound/isa/Kconfig b/sound/isa/Kconfig
index 5769a13..660beb4 100644
--- a/sound/isa/Kconfig
+++ b/sound/isa/Kconfig
@@ -1,10 +1,6 @@
 # ALSA ISA drivers
 
-config SND_AD1848_LIB
-        tristate
-        select SND_PCM
-
-config SND_CS4231_LIB
+config SND_WSS_LIB
         tristate
         select SND_PCM
 
@@ -55,7 +51,7 @@
 
 config SND_AD1848
 	tristate "Generic AD1848/CS4248 driver"
-	select SND_AD1848_LIB
+	select SND_WSS_LIB
 	help
 	  Say Y here to include support for AD1848 (Analog Devices) or
 	  CS4248 (Cirrus Logic - Crystal Semiconductors) chips.
@@ -86,7 +82,7 @@
 	select ISAPNP
 	select SND_OPL3_LIB
 	select SND_MPU401_UART
-	select SND_CS4231_LIB
+	select SND_WSS_LIB
 	help
 	  Say Y here to include support for soundcards based on the
 	  Aztech Systems AZT2320 chip.
@@ -96,7 +92,7 @@
 
 config SND_CMI8330
 	tristate "C-Media CMI8330"
-	select SND_AD1848_LIB
+	select SND_WSS_LIB
 	select SND_SB16_DSP
 	help
 	  Say Y here to include support for soundcards based on the
@@ -108,7 +104,7 @@
 config SND_CS4231
 	tristate "Generic Cirrus Logic CS4231 driver"
 	select SND_MPU401_UART
-	select SND_CS4231_LIB
+	select SND_WSS_LIB
 	help
 	  Say Y here to include support for CS4231 chips from Cirrus
 	  Logic - Crystal Semiconductors.
@@ -120,7 +116,7 @@
 	tristate "Generic Cirrus Logic CS4232 driver"
 	select SND_OPL3_LIB
 	select SND_MPU401_UART
-	select SND_CS4231_LIB
+	select SND_WSS_LIB
 	help
 	  Say Y here to include support for CS4232 chips from Cirrus
 	  Logic - Crystal Semiconductors.
@@ -132,7 +128,7 @@
 	tristate "Generic Cirrus Logic CS4236+ driver"
 	select SND_OPL3_LIB
 	select SND_MPU401_UART
-	select SND_CS4231_LIB
+	select SND_WSS_LIB
 	help
 	  Say Y to include support for CS4235,CS4236,CS4237B,CS4238B,
 	  CS4239 chips from Cirrus Logic - Crystal Semiconductors.
@@ -192,7 +188,7 @@
 config SND_SC6000
 	tristate "Gallant SC-6000, Audio Excel DSP 16"
 	depends on HAS_IOPORT
-	select SND_AD1848_LIB
+	select SND_WSS_LIB
 	select SND_OPL3_LIB
 	select SND_MPU401_UART
 	help
@@ -228,7 +224,7 @@
 config SND_GUSMAX
 	tristate "Gravis UltraSound MAX"
 	select SND_RAWMIDI
-	select SND_CS4231_LIB
+	select SND_WSS_LIB
 	help
 	  Say Y here to include support for Gravis UltraSound MAX
 	  soundcards.
@@ -240,7 +236,7 @@
 	tristate "AMD InterWave, Gravis UltraSound PnP"
 	depends on PNP
 	select SND_RAWMIDI
-	select SND_CS4231_LIB
+	select SND_WSS_LIB
 	help
 	  Say Y here to include support for AMD InterWave based
 	  soundcards (Gravis UltraSound Plug & Play, STB SoundRage32,
@@ -253,7 +249,7 @@
 	tristate "AMD InterWave + TEA6330T (UltraSound 32-Pro)"
 	depends on PNP
 	select SND_RAWMIDI
-	select SND_CS4231_LIB
+	select SND_WSS_LIB
 	help
 	  Say Y here to include support for AMD InterWave based
 	  soundcards with a TEA6330T bass and treble regulator
@@ -266,7 +262,7 @@
 	tristate "Yamaha OPL3-SA2/SA3"
 	select SND_OPL3_LIB
 	select SND_MPU401_UART
-	select SND_CS4231_LIB
+	select SND_WSS_LIB
 	help
 	  Say Y here to include support for Yamaha OPL3-SA2 and OPL3-SA3
 	  chips.
@@ -279,7 +275,7 @@
 	select SND_OPL3_LIB
 	select SND_OPL4_LIB
 	select SND_MPU401_UART
-	select SND_AD1848_LIB
+	select SND_WSS_LIB
 	help
 	  Say Y here to include support for soundcards based on Opti
 	  82C92x or OTI-601 chips and using an AD1848 codec.
@@ -292,7 +288,7 @@
 	select SND_OPL3_LIB
 	select SND_OPL4_LIB
 	select SND_MPU401_UART
-	select SND_CS4231_LIB
+	select SND_WSS_LIB
 	help
 	  Say Y here to include support for soundcards based on Opti
 	  82C92x chips and using a CS4231 codec.
@@ -304,7 +300,7 @@
 	tristate "OPTi 82C93x"
 	select SND_OPL3_LIB
 	select SND_MPU401_UART
-	select SND_CS4231_LIB
+	select SND_WSS_LIB
 	help
 	  Say Y here to include support for soundcards based on Opti
 	  82C93x chips.
@@ -315,7 +311,7 @@
 config SND_MIRO
 	tristate "Miro miroSOUND PCM1pro/PCM12/PCM20radio driver"
 	select SND_OPL4_LIB
-	select SND_CS4231_LIB
+	select SND_WSS_LIB
 	select SND_MPU401_UART
 	select SND_PCM
 	help
@@ -364,7 +360,7 @@
 config SND_SB16_CSP
 	bool "Sound Blaster 16/AWE CSP support"
 	depends on (SND_SB16 || SND_SBAWE) && (BROKEN || !PPC)
-	select FW_LOADER if !SND_SB16_CSP_FIRMWARE_IN_KERNEL
+	select FW_LOADER
 	help
 	  Say Y here to include support for the CSP core.  This special
 	  coprocessor can do variable tasks like various compression and
@@ -372,7 +368,7 @@
 
 config SND_SGALAXY
 	tristate "Aztech Sound Galaxy"
-	select SND_AD1848_LIB
+	select SND_WSS_LIB
 	help
 	  Say Y here to include support for Aztech Sound Galaxy
 	  soundcards.
@@ -384,7 +380,7 @@
 	tristate "Ensoniq SoundScape PnP driver"
 	select SND_HWDEP
 	select SND_MPU401_UART
-	select SND_CS4231_LIB
+	select SND_WSS_LIB
 	help
 	  Say Y here to include support for Ensoniq SoundScape PnP
 	  soundcards.
@@ -397,7 +393,7 @@
 	select FW_LOADER
 	select SND_OPL3_LIB
 	select SND_MPU401_UART
-	select SND_CS4231_LIB
+	select SND_WSS_LIB
 	help
 	  Say Y here to include support for Turtle Beach Maui, Tropez
 	  and Tropez+ soundcards based on the Wavefront chip.
diff --git a/sound/isa/Makefile b/sound/isa/Makefile
index c0ce7db..63af13d 100644
--- a/sound/isa/Makefile
+++ b/sound/isa/Makefile
@@ -27,4 +27,4 @@
 obj-$(CONFIG_SND_SSCAPE) += snd-sscape.o
 
 obj-$(CONFIG_SND) += ad1816a/ ad1848/ cs423x/ es1688/ gus/ opti9xx/ \
-		     sb/ wavefront/
+		     sb/ wavefront/ wss/
diff --git a/sound/isa/ad1816a/ad1816a.c b/sound/isa/ad1816a/ad1816a.c
index 68f1260..7752424 100644
--- a/sound/isa/ad1816a/ad1816a.c
+++ b/sound/isa/ad1816a/ad1816a.c
@@ -83,8 +83,10 @@
 	{ .id = "MDK1605", .devs = { { .id = "ADS7180" }, { .id = "ADS7181" } } },
 	/* Shark Predator ISA - added by Ken Arromdee */
 	{ .id = "SMM7180", .devs = { { .id = "ADS7180" }, { .id = "ADS7181" } } },
-	/* Analog Devices AD1816A - Terratec AudioSystem EWS64S */
+	/* Analog Devices AD1816A - Terratec AudioSystem EWS64 S */
 	{ .id = "TER1112", .devs = { { .id = "ADS7180" }, { .id = "ADS7181" } } },
+	/* Analog Devices AD1816A - Terratec AudioSystem EWS64 S */
+	{ .id = "TER1112", .devs = { { .id = "TER1100" }, { .id = "TER1101" } } },
 	/* Analog Devices AD1816A - Terratec Base 64 */
 	{ .id = "TER1411", .devs = { { .id = "ADS7180" }, { .id = "ADS7181" } } },
 	/* end */
diff --git a/sound/isa/ad1816a/ad1816a_lib.c b/sound/isa/ad1816a/ad1816a_lib.c
index 4b8dfe2..3bfca7c 100644
--- a/sound/isa/ad1816a/ad1816a_lib.c
+++ b/sound/isa/ad1816a/ad1816a_lib.c
@@ -394,7 +394,8 @@
 
 static unsigned long snd_ad1816a_timer_resolution(struct snd_timer *timer)
 {
-	snd_assert(timer != NULL, return 0);
+	if (snd_BUG_ON(!timer))
+		return 0;
 
 	return 10000;
 }
@@ -961,7 +962,8 @@
 	unsigned int idx;
 	int err;
 
-	snd_assert(chip != NULL && chip->card != NULL, return -EINVAL);
+	if (snd_BUG_ON(!chip || !chip->card))
+		return -EINVAL;
 
 	card = chip->card;
 
diff --git a/sound/isa/ad1848/Makefile b/sound/isa/ad1848/Makefile
index ae23331..3d6dea3 100644
--- a/sound/isa/ad1848/Makefile
+++ b/sound/isa/ad1848/Makefile
@@ -3,10 +3,8 @@
 # Copyright (c) 2001 by Jaroslav Kysela <perex@perex.cz>
 #
 
-snd-ad1848-lib-objs := ad1848_lib.o
 snd-ad1848-objs := ad1848.o
 
 # Toplevel Module Dependency
 obj-$(CONFIG_SND_AD1848) += snd-ad1848.o
-obj-$(CONFIG_SND_AD1848_LIB) += snd-ad1848-lib.o
 
diff --git a/sound/isa/ad1848/ad1848.c b/sound/isa/ad1848/ad1848.c
index 5f5271e..b68d20e 100644
--- a/sound/isa/ad1848/ad1848.c
+++ b/sound/isa/ad1848/ad1848.c
@@ -28,7 +28,7 @@
 #include <linux/wait.h>
 #include <linux/moduleparam.h>
 #include <sound/core.h>
-#include <sound/ad1848.h>
+#include <sound/wss.h>
 #include <sound/initval.h>
 
 #define CRD_NAME "Generic AD1848/AD1847/CS4248"
@@ -87,7 +87,7 @@
 static int __devinit snd_ad1848_probe(struct device *dev, unsigned int n)
 {
 	struct snd_card *card;
-	struct snd_ad1848 *chip;
+	struct snd_wss *chip;
 	struct snd_pcm *pcm;
 	int error;
 
@@ -95,18 +95,19 @@
 	if (!card)
 		return -EINVAL;
 
-	error = snd_ad1848_create(card, port[n], irq[n], dma1[n],
-			thinkpad[n] ? AD1848_HW_THINKPAD : AD1848_HW_DETECT, &chip);
+	error = snd_wss_create(card, port[n], -1, irq[n], dma1[n], -1,
+			thinkpad[n] ? WSS_HW_THINKPAD : WSS_HW_DETECT,
+			0, &chip);
 	if (error < 0)
 		goto out;
 
 	card->private_data = chip;
 
-	error = snd_ad1848_pcm(chip, 0, &pcm);
+	error = snd_wss_pcm(chip, 0, &pcm);
 	if (error < 0)
 		goto out;
 
-	error = snd_ad1848_mixer(chip);
+	error = snd_wss_mixer(chip);
 	if (error < 0)
 		goto out;
 
@@ -142,7 +143,7 @@
 static int snd_ad1848_suspend(struct device *dev, unsigned int n, pm_message_t state)
 {
 	struct snd_card *card = dev_get_drvdata(dev);
-	struct snd_ad1848 *chip = card->private_data;
+	struct snd_wss *chip = card->private_data;
 
 	snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
 	chip->suspend(chip);
@@ -152,7 +153,7 @@
 static int snd_ad1848_resume(struct device *dev, unsigned int n)
 {
 	struct snd_card *card = dev_get_drvdata(dev);
-	struct snd_ad1848 *chip = card->private_data;
+	struct snd_wss *chip = card->private_data;
 
 	chip->resume(chip);
 	snd_power_change_state(card, SNDRV_CTL_POWER_D0);
diff --git a/sound/isa/ad1848/ad1848_lib.c b/sound/isa/ad1848/ad1848_lib.c
deleted file mode 100644
index 630c90f..0000000
--- a/sound/isa/ad1848/ad1848_lib.c
+++ /dev/null
@@ -1,1267 +0,0 @@
-/*
- *  Copyright (c) by Jaroslav Kysela <perex@perex.cz>
- *  Routines for control of AD1848/AD1847/CS4248
- *
- *
- *   This program is free software; you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License as published by
- *   the Free Software Foundation; either version 2 of the License, or
- *   (at your option) any later version.
- *
- *   This program is distributed in the hope that it will be useful,
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *   GNU General Public License for more details.
- *
- *   You should have received a copy of the GNU General Public License
- *   along with this program; if not, write to the Free Software
- *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
- *
- */
-
-#define SNDRV_MAIN_OBJECT_FILE
-#include <linux/delay.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/slab.h>
-#include <linux/ioport.h>
-#include <sound/core.h>
-#include <sound/ad1848.h>
-#include <sound/control.h>
-#include <sound/tlv.h>
-#include <sound/pcm_params.h>
-
-#include <asm/io.h>
-#include <asm/dma.h>
-
-MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
-MODULE_DESCRIPTION("Routines for control of AD1848/AD1847/CS4248");
-MODULE_LICENSE("GPL");
-
-#if 0
-#define SNDRV_DEBUG_MCE
-#endif
-
-/*
- *  Some variables
- */
-
-static unsigned char freq_bits[14] = {
-	/* 5510 */	0x00 | AD1848_XTAL2,
-	/* 6620 */	0x0E | AD1848_XTAL2,
-	/* 8000 */	0x00 | AD1848_XTAL1,
-	/* 9600 */	0x0E | AD1848_XTAL1,
-	/* 11025 */	0x02 | AD1848_XTAL2,
-	/* 16000 */	0x02 | AD1848_XTAL1,
-	/* 18900 */	0x04 | AD1848_XTAL2,
-	/* 22050 */	0x06 | AD1848_XTAL2,
-	/* 27042 */	0x04 | AD1848_XTAL1,
-	/* 32000 */	0x06 | AD1848_XTAL1,
-	/* 33075 */	0x0C | AD1848_XTAL2,
-	/* 37800 */	0x08 | AD1848_XTAL2,
-	/* 44100 */	0x0A | AD1848_XTAL2,
-	/* 48000 */	0x0C | AD1848_XTAL1
-};
-
-static unsigned int rates[14] = {
-	5510, 6620, 8000, 9600, 11025, 16000, 18900, 22050,
-	27042, 32000, 33075, 37800, 44100, 48000
-};
-
-static struct snd_pcm_hw_constraint_list hw_constraints_rates = {
-	.count = ARRAY_SIZE(rates),
-	.list = rates,
-	.mask = 0,
-};
-
-static unsigned char snd_ad1848_original_image[16] =
-{
-	0x00,			/* 00 - lic */
-	0x00,			/* 01 - ric */
-	0x9f,			/* 02 - la1ic */
-	0x9f,			/* 03 - ra1ic */
-	0x9f,			/* 04 - la2ic */
-	0x9f,			/* 05 - ra2ic */
-	0xbf,			/* 06 - loc */
-	0xbf,			/* 07 - roc */
-	0x20,			/* 08 - dfr */
-	AD1848_AUTOCALIB,	/* 09 - ic */
-	0x00,			/* 0a - pc */
-	0x00,			/* 0b - ti */
-	0x00,			/* 0c - mi */
-	0x00,			/* 0d - lbc */
-	0x00,			/* 0e - dru */
-	0x00,			/* 0f - drl */
-};
-
-/*
- *  Basic I/O functions
- */
-
-static void snd_ad1848_wait(struct snd_ad1848 *chip)
-{
-	int timeout;
-
-	for (timeout = 250; timeout > 0; timeout--) {
-		if ((inb(AD1848P(chip, REGSEL)) & AD1848_INIT) == 0)
-			break;
-		udelay(100);
-	}
-}
-
-void snd_ad1848_out(struct snd_ad1848 *chip,
-			   unsigned char reg,
-			   unsigned char value)
-{
-	snd_ad1848_wait(chip);
-#ifdef CONFIG_SND_DEBUG
-	if (inb(AD1848P(chip, REGSEL)) & AD1848_INIT)
-		snd_printk(KERN_WARNING "auto calibration time out - "
-			   "reg = 0x%x, value = 0x%x\n", reg, value);
-#endif
-	outb(chip->mce_bit | reg, AD1848P(chip, REGSEL));
-	outb(chip->image[reg] = value, AD1848P(chip, REG));
-	mb();
-	snd_printdd("codec out - reg 0x%x = 0x%x\n",
-			chip->mce_bit | reg, value);
-}
-
-EXPORT_SYMBOL(snd_ad1848_out);
-
-static void snd_ad1848_dout(struct snd_ad1848 *chip,
-			    unsigned char reg, unsigned char value)
-{
-	snd_ad1848_wait(chip);
-	outb(chip->mce_bit | reg, AD1848P(chip, REGSEL));
-	outb(value, AD1848P(chip, REG));
-	mb();
-}
-
-static unsigned char snd_ad1848_in(struct snd_ad1848 *chip, unsigned char reg)
-{
-	snd_ad1848_wait(chip);
-#ifdef CONFIG_SND_DEBUG
-	if (inb(AD1848P(chip, REGSEL)) & AD1848_INIT)
-		snd_printk(KERN_WARNING "auto calibration time out - "
-			   "reg = 0x%x\n", reg);
-#endif
-	outb(chip->mce_bit | reg, AD1848P(chip, REGSEL));
-	mb();
-	return inb(AD1848P(chip, REG));
-}
-
-#if 0
-
-static void snd_ad1848_debug(struct snd_ad1848 *chip)
-{
-	printk("AD1848 REGS:      INDEX = 0x%02x  ", inb(AD1848P(chip, REGSEL)));
-	printk("                 STATUS = 0x%02x\n", inb(AD1848P(chip, STATUS)));
-	printk("  0x00: left input      = 0x%02x  ", snd_ad1848_in(chip, 0x00));
-	printk("  0x08: playback format = 0x%02x\n", snd_ad1848_in(chip, 0x08));
-	printk("  0x01: right input     = 0x%02x  ", snd_ad1848_in(chip, 0x01));
-	printk("  0x09: iface (CFIG 1)  = 0x%02x\n", snd_ad1848_in(chip, 0x09));
-	printk("  0x02: AUXA left       = 0x%02x  ", snd_ad1848_in(chip, 0x02));
-	printk("  0x0a: pin control     = 0x%02x\n", snd_ad1848_in(chip, 0x0a));
-	printk("  0x03: AUXA right      = 0x%02x  ", snd_ad1848_in(chip, 0x03));
-	printk("  0x0b: init & status   = 0x%02x\n", snd_ad1848_in(chip, 0x0b));
-	printk("  0x04: AUXB left       = 0x%02x  ", snd_ad1848_in(chip, 0x04));
-	printk("  0x0c: revision & mode = 0x%02x\n", snd_ad1848_in(chip, 0x0c));
-	printk("  0x05: AUXB right      = 0x%02x  ", snd_ad1848_in(chip, 0x05));
-	printk("  0x0d: loopback        = 0x%02x\n", snd_ad1848_in(chip, 0x0d));
-	printk("  0x06: left output     = 0x%02x  ", snd_ad1848_in(chip, 0x06));
-	printk("  0x0e: data upr count  = 0x%02x\n", snd_ad1848_in(chip, 0x0e));
-	printk("  0x07: right output    = 0x%02x  ", snd_ad1848_in(chip, 0x07));
-	printk("  0x0f: data lwr count  = 0x%02x\n", snd_ad1848_in(chip, 0x0f));
-}
-
-#endif
-
-/*
- *  AD1848 detection / MCE routines
- */
-
-static void snd_ad1848_mce_up(struct snd_ad1848 *chip)
-{
-	unsigned long flags;
-	int timeout;
-
-	snd_ad1848_wait(chip);
-#ifdef CONFIG_SND_DEBUG
-	if (inb(AD1848P(chip, REGSEL)) & AD1848_INIT)
-		snd_printk(KERN_WARNING "mce_up - auto calibration time out (0)\n");
-#endif
-	spin_lock_irqsave(&chip->reg_lock, flags);
-	chip->mce_bit |= AD1848_MCE;
-	timeout = inb(AD1848P(chip, REGSEL));
-	if (timeout == 0x80)
-		snd_printk(KERN_WARNING "mce_up [0x%lx]: serious init problem - codec still busy\n", chip->port);
-	if (!(timeout & AD1848_MCE))
-		outb(chip->mce_bit | (timeout & 0x1f), AD1848P(chip, REGSEL));
-	spin_unlock_irqrestore(&chip->reg_lock, flags);
-}
-
-static void snd_ad1848_mce_down(struct snd_ad1848 *chip)
-{
-	unsigned long flags, timeout;
-	int reg;
-
-	spin_lock_irqsave(&chip->reg_lock, flags);
-	for (timeout = 5; timeout > 0; timeout--)
-		inb(AD1848P(chip, REGSEL));
-	/* end of cleanup sequence */
-	for (timeout = 12000; timeout > 0 && (inb(AD1848P(chip, REGSEL)) & AD1848_INIT); timeout--)
-		udelay(100);
-
-	snd_printdd("(1) timeout = %ld\n", timeout);
-
-#ifdef CONFIG_SND_DEBUG
-	if (inb(AD1848P(chip, REGSEL)) & AD1848_INIT)
-		snd_printk(KERN_WARNING "mce_down [0x%lx] - auto calibration time out (0)\n", AD1848P(chip, REGSEL));
-#endif
-
-	chip->mce_bit &= ~AD1848_MCE;
-	reg = inb(AD1848P(chip, REGSEL));
-	outb(chip->mce_bit | (reg & 0x1f), AD1848P(chip, REGSEL));
-	if (reg == 0x80)
-		snd_printk(KERN_WARNING "mce_down [0x%lx]: serious init problem - codec still busy\n", chip->port);
-	if ((reg & AD1848_MCE) == 0) {
-		spin_unlock_irqrestore(&chip->reg_lock, flags);
-		return;
-	}
-
-	/*
-	 * Wait for auto-calibration (AC) process to finish, i.e. ACI to go low.
-	 * It may take up to 5 sample periods (at most 907 us @ 5.5125 kHz) for
-	 * the process to _start_, so it is important to wait at least that long
-	 * before checking.  Otherwise we might think AC has finished when it
-	 * has in fact not begun.  It could take 128 (no AC) or 384 (AC) cycles
-	 * for ACI to drop.  This gives a wait of at most 70 ms with a more
-	 * typical value of 3-9 ms.
-	 */
-	timeout = jiffies + msecs_to_jiffies(250);
-	do {
-		spin_unlock_irqrestore(&chip->reg_lock, flags);
-		msleep(1);
-		spin_lock_irqsave(&chip->reg_lock, flags);
-		reg = snd_ad1848_in(chip, AD1848_TEST_INIT) &
-		      AD1848_CALIB_IN_PROGRESS;
-	} while (reg && time_before(jiffies, timeout));
-	spin_unlock_irqrestore(&chip->reg_lock, flags);
-	if (reg)
-		snd_printk(KERN_ERR
-			   "mce_down - auto calibration time out (2)\n");
-
-	snd_printdd("(4) jiffies = %lu\n", jiffies);
-	snd_printd("mce_down - exit = 0x%x\n", inb(AD1848P(chip, REGSEL)));
-}
-
-static unsigned int snd_ad1848_get_count(unsigned char format,
-				         unsigned int size)
-{
-	switch (format & 0xe0) {
-	case AD1848_LINEAR_16:
-		size >>= 1;
-		break;
-	}
-	if (format & AD1848_STEREO)
-		size >>= 1;
-	return size;
-}
-
-static int snd_ad1848_trigger(struct snd_ad1848 *chip, unsigned char what,
-			      int channel, int cmd)
-{
-	int result = 0;
-
-#if 0
-	printk("codec trigger!!! - what = %i, enable = %i, status = 0x%x\n", what, enable, inb(AD1848P(card, STATUS)));
-#endif
-	spin_lock(&chip->reg_lock);
-	if (cmd == SNDRV_PCM_TRIGGER_START) {
-		if (chip->image[AD1848_IFACE_CTRL] & what) {
-			spin_unlock(&chip->reg_lock);
-			return 0;
-		}
-		snd_ad1848_out(chip, AD1848_IFACE_CTRL, chip->image[AD1848_IFACE_CTRL] |= what);
-		chip->mode |= AD1848_MODE_RUNNING;
-	} else if (cmd == SNDRV_PCM_TRIGGER_STOP) {
-		if (!(chip->image[AD1848_IFACE_CTRL] & what)) {
-			spin_unlock(&chip->reg_lock);
-			return 0;
-		}
-		snd_ad1848_out(chip, AD1848_IFACE_CTRL, chip->image[AD1848_IFACE_CTRL] &= ~what);
-		chip->mode &= ~AD1848_MODE_RUNNING;
-	} else {
-		result = -EINVAL;
-	}
-	spin_unlock(&chip->reg_lock);
-	return result;
-}
-
-/*
- *  CODEC I/O
- */
-
-static unsigned char snd_ad1848_get_rate(unsigned int rate)
-{
-	int i;
-
-	for (i = 0; i < ARRAY_SIZE(rates); i++)
-		if (rate == rates[i])
-			return freq_bits[i];
-	snd_BUG();
-	return freq_bits[ARRAY_SIZE(rates) - 1];
-}
-
-static int snd_ad1848_ioctl(struct snd_pcm_substream *substream,
-			    unsigned int cmd, void *arg)
-{
-	return snd_pcm_lib_ioctl(substream, cmd, arg);
-}
-
-static unsigned char snd_ad1848_get_format(int format, int channels)
-{
-	unsigned char rformat;
-
-	rformat = AD1848_LINEAR_8;
-	switch (format) {
-	case SNDRV_PCM_FORMAT_A_LAW:	rformat = AD1848_ALAW_8; break;
-	case SNDRV_PCM_FORMAT_MU_LAW:	rformat = AD1848_ULAW_8; break;
-	case SNDRV_PCM_FORMAT_S16_LE:	rformat = AD1848_LINEAR_16; break;
-	}
-	if (channels > 1)
-		rformat |= AD1848_STEREO;
-#if 0
-	snd_printk("get_format: 0x%x (mode=0x%x)\n", format, mode);
-#endif
-	return rformat;
-}
-
-static void snd_ad1848_calibrate_mute(struct snd_ad1848 *chip, int mute)
-{
-	unsigned long flags;
-	
-	mute = mute ? 1 : 0;
-	spin_lock_irqsave(&chip->reg_lock, flags);
-	if (chip->calibrate_mute == mute) {
-		spin_unlock_irqrestore(&chip->reg_lock, flags);
-		return;
-	}
-	if (!mute) {
-		snd_ad1848_dout(chip, AD1848_LEFT_INPUT, chip->image[AD1848_LEFT_INPUT]);
-		snd_ad1848_dout(chip, AD1848_RIGHT_INPUT, chip->image[AD1848_RIGHT_INPUT]);
-	}
-	snd_ad1848_dout(chip, AD1848_AUX1_LEFT_INPUT, mute ? 0x80 : chip->image[AD1848_AUX1_LEFT_INPUT]);
-	snd_ad1848_dout(chip, AD1848_AUX1_RIGHT_INPUT, mute ? 0x80 : chip->image[AD1848_AUX1_RIGHT_INPUT]);
-	snd_ad1848_dout(chip, AD1848_AUX2_LEFT_INPUT, mute ? 0x80 : chip->image[AD1848_AUX2_LEFT_INPUT]);
-	snd_ad1848_dout(chip, AD1848_AUX2_RIGHT_INPUT, mute ? 0x80 : chip->image[AD1848_AUX2_RIGHT_INPUT]);
-	snd_ad1848_dout(chip, AD1848_LEFT_OUTPUT, mute ? 0x80 : chip->image[AD1848_LEFT_OUTPUT]);
-	snd_ad1848_dout(chip, AD1848_RIGHT_OUTPUT, mute ? 0x80 : chip->image[AD1848_RIGHT_OUTPUT]);
-	chip->calibrate_mute = mute;
-	spin_unlock_irqrestore(&chip->reg_lock, flags);
-}
-
-static void snd_ad1848_set_data_format(struct snd_ad1848 *chip, struct snd_pcm_hw_params *hw_params)
-{
-	if (hw_params == NULL) {
-		chip->image[AD1848_DATA_FORMAT] = 0x20;
-	} else {
-		chip->image[AD1848_DATA_FORMAT] =
-		    snd_ad1848_get_format(params_format(hw_params), params_channels(hw_params)) |
-		    snd_ad1848_get_rate(params_rate(hw_params));
-	}
-	// snd_printk(">>> pmode = 0x%x, dfr = 0x%x\n", pstr->mode, chip->image[AD1848_DATA_FORMAT]);
-}
-
-static int snd_ad1848_open(struct snd_ad1848 *chip, unsigned int mode)
-{
-	unsigned long flags;
-
-	if (chip->mode & AD1848_MODE_OPEN)
-		return -EAGAIN;
-
-	snd_ad1848_mce_down(chip);
-
-#ifdef SNDRV_DEBUG_MCE
-	snd_printk("open: (1)\n");
-#endif
-	snd_ad1848_mce_up(chip);
-	spin_lock_irqsave(&chip->reg_lock, flags);
-	chip->image[AD1848_IFACE_CTRL] &= ~(AD1848_PLAYBACK_ENABLE | AD1848_PLAYBACK_PIO |
-			     AD1848_CAPTURE_ENABLE | AD1848_CAPTURE_PIO |
-			     AD1848_CALIB_MODE);
-	chip->image[AD1848_IFACE_CTRL] |= AD1848_AUTOCALIB;
-	snd_ad1848_out(chip, AD1848_IFACE_CTRL, chip->image[AD1848_IFACE_CTRL]);
-	spin_unlock_irqrestore(&chip->reg_lock, flags);
-	snd_ad1848_mce_down(chip);
-
-#ifdef SNDRV_DEBUG_MCE
-	snd_printk("open: (2)\n");
-#endif
-
-	snd_ad1848_set_data_format(chip, NULL);
-
-	snd_ad1848_mce_up(chip);
-	spin_lock_irqsave(&chip->reg_lock, flags);
-	snd_ad1848_out(chip, AD1848_DATA_FORMAT, chip->image[AD1848_DATA_FORMAT]);
-	spin_unlock_irqrestore(&chip->reg_lock, flags);
-	snd_ad1848_mce_down(chip);
-
-#ifdef SNDRV_DEBUG_MCE
-	snd_printk("open: (3)\n");
-#endif
-
-	/* ok. now enable and ack CODEC IRQ */
-	spin_lock_irqsave(&chip->reg_lock, flags);
-	outb(0, AD1848P(chip, STATUS));	/* clear IRQ */
-	outb(0, AD1848P(chip, STATUS));	/* clear IRQ */
-	chip->image[AD1848_PIN_CTRL] |= AD1848_IRQ_ENABLE;
-	snd_ad1848_out(chip, AD1848_PIN_CTRL, chip->image[AD1848_PIN_CTRL]);
-	spin_unlock_irqrestore(&chip->reg_lock, flags);
-
-	chip->mode = mode;
-
-	return 0;
-}
-
-static void snd_ad1848_close(struct snd_ad1848 *chip)
-{
-	unsigned long flags;
-
-	if (!chip->mode)
-		return;
-	/* disable IRQ */
-	spin_lock_irqsave(&chip->reg_lock, flags);
-	outb(0, AD1848P(chip, STATUS));	/* clear IRQ */
-	outb(0, AD1848P(chip, STATUS));	/* clear IRQ */
-	chip->image[AD1848_PIN_CTRL] &= ~AD1848_IRQ_ENABLE;
-	snd_ad1848_out(chip, AD1848_PIN_CTRL, chip->image[AD1848_PIN_CTRL]);
-	spin_unlock_irqrestore(&chip->reg_lock, flags);
-
-	/* now disable capture & playback */
-
-	snd_ad1848_mce_up(chip);
-	spin_lock_irqsave(&chip->reg_lock, flags);
-	chip->image[AD1848_IFACE_CTRL] &= ~(AD1848_PLAYBACK_ENABLE | AD1848_PLAYBACK_PIO |
-			     AD1848_CAPTURE_ENABLE | AD1848_CAPTURE_PIO);
-	snd_ad1848_out(chip, AD1848_IFACE_CTRL, chip->image[AD1848_IFACE_CTRL]);
-	spin_unlock_irqrestore(&chip->reg_lock, flags);
-	snd_ad1848_mce_down(chip);
-
-	/* clear IRQ again */
-	spin_lock_irqsave(&chip->reg_lock, flags);
-	outb(0, AD1848P(chip, STATUS));	/* clear IRQ */
-	outb(0, AD1848P(chip, STATUS));	/* clear IRQ */
-	spin_unlock_irqrestore(&chip->reg_lock, flags);
-
-	chip->mode = 0;
-}
-
-/*
- *  ok.. exported functions..
- */
-
-static int snd_ad1848_playback_trigger(struct snd_pcm_substream *substream,
-				       int cmd)
-{
-	struct snd_ad1848 *chip = snd_pcm_substream_chip(substream);
-	return snd_ad1848_trigger(chip, AD1848_PLAYBACK_ENABLE, SNDRV_PCM_STREAM_PLAYBACK, cmd);
-}
-
-static int snd_ad1848_capture_trigger(struct snd_pcm_substream *substream,
-				      int cmd)
-{
-	struct snd_ad1848 *chip = snd_pcm_substream_chip(substream);
-	return snd_ad1848_trigger(chip, AD1848_CAPTURE_ENABLE, SNDRV_PCM_STREAM_CAPTURE, cmd);
-}
-
-static int snd_ad1848_playback_hw_params(struct snd_pcm_substream *substream,
-					 struct snd_pcm_hw_params *hw_params)
-{
-	struct snd_ad1848 *chip = snd_pcm_substream_chip(substream);
-	unsigned long flags;
-	int err;
-
-	if ((err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params))) < 0)
-		return err;
-	snd_ad1848_calibrate_mute(chip, 1);
-	snd_ad1848_set_data_format(chip, hw_params);
-	snd_ad1848_mce_up(chip);
-	spin_lock_irqsave(&chip->reg_lock, flags);
-	snd_ad1848_out(chip, AD1848_DATA_FORMAT, chip->image[AD1848_DATA_FORMAT]);
-	spin_unlock_irqrestore(&chip->reg_lock, flags);
-	snd_ad1848_mce_down(chip);
-	snd_ad1848_calibrate_mute(chip, 0);
-	return 0;
-}
-
-static int snd_ad1848_playback_hw_free(struct snd_pcm_substream *substream)
-{
-	return snd_pcm_lib_free_pages(substream);
-}
-
-static int snd_ad1848_playback_prepare(struct snd_pcm_substream *substream)
-{
-	struct snd_ad1848 *chip = snd_pcm_substream_chip(substream);
-	struct snd_pcm_runtime *runtime = substream->runtime;
-	unsigned long flags;
-	unsigned int size = snd_pcm_lib_buffer_bytes(substream);
-	unsigned int count = snd_pcm_lib_period_bytes(substream);
-
-	chip->dma_size = size;
-	chip->image[AD1848_IFACE_CTRL] &= ~(AD1848_PLAYBACK_ENABLE | AD1848_PLAYBACK_PIO);
-	snd_dma_program(chip->dma, runtime->dma_addr, size, DMA_MODE_WRITE | DMA_AUTOINIT);
-	count = snd_ad1848_get_count(chip->image[AD1848_DATA_FORMAT], count) - 1;
-	spin_lock_irqsave(&chip->reg_lock, flags);
-	snd_ad1848_out(chip, AD1848_DATA_LWR_CNT, (unsigned char) count);
-	snd_ad1848_out(chip, AD1848_DATA_UPR_CNT, (unsigned char) (count >> 8));
-	spin_unlock_irqrestore(&chip->reg_lock, flags);
-	return 0;
-}
-
-static int snd_ad1848_capture_hw_params(struct snd_pcm_substream *substream,
-					struct snd_pcm_hw_params *hw_params)
-{
-	struct snd_ad1848 *chip = snd_pcm_substream_chip(substream);
-	unsigned long flags;
-	int err;
-
-	if ((err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params))) < 0)
-		return err;
-	snd_ad1848_calibrate_mute(chip, 1);
-	snd_ad1848_set_data_format(chip, hw_params);
-	snd_ad1848_mce_up(chip);
-	spin_lock_irqsave(&chip->reg_lock, flags);
-	snd_ad1848_out(chip, AD1848_DATA_FORMAT, chip->image[AD1848_DATA_FORMAT]);
-	spin_unlock_irqrestore(&chip->reg_lock, flags);
-	snd_ad1848_mce_down(chip);
-	snd_ad1848_calibrate_mute(chip, 0);
-	return 0;
-}
-
-static int snd_ad1848_capture_hw_free(struct snd_pcm_substream *substream)
-{
-	return snd_pcm_lib_free_pages(substream);
-}
-
-static int snd_ad1848_capture_prepare(struct snd_pcm_substream *substream)
-{
-	struct snd_ad1848 *chip = snd_pcm_substream_chip(substream);
-	struct snd_pcm_runtime *runtime = substream->runtime;
-	unsigned long flags;
-	unsigned int size = snd_pcm_lib_buffer_bytes(substream);
-	unsigned int count = snd_pcm_lib_period_bytes(substream);
-
-	chip->dma_size = size;
-	chip->image[AD1848_IFACE_CTRL] &= ~(AD1848_CAPTURE_ENABLE | AD1848_CAPTURE_PIO);
-	snd_dma_program(chip->dma, runtime->dma_addr, size, DMA_MODE_READ | DMA_AUTOINIT);
-	count = snd_ad1848_get_count(chip->image[AD1848_DATA_FORMAT], count) - 1;
-	spin_lock_irqsave(&chip->reg_lock, flags);
-	snd_ad1848_out(chip, AD1848_DATA_LWR_CNT, (unsigned char) count);
-	snd_ad1848_out(chip, AD1848_DATA_UPR_CNT, (unsigned char) (count >> 8));
-	spin_unlock_irqrestore(&chip->reg_lock, flags);
-	return 0;
-}
-
-static irqreturn_t snd_ad1848_interrupt(int irq, void *dev_id)
-{
-	struct snd_ad1848 *chip = dev_id;
-
-	if ((chip->mode & AD1848_MODE_PLAY) && chip->playback_substream &&
-	    (chip->mode & AD1848_MODE_RUNNING))
-		snd_pcm_period_elapsed(chip->playback_substream);
-	if ((chip->mode & AD1848_MODE_CAPTURE) && chip->capture_substream &&
-	    (chip->mode & AD1848_MODE_RUNNING))
-		snd_pcm_period_elapsed(chip->capture_substream);
-	outb(0, AD1848P(chip, STATUS));	/* clear global interrupt bit */
-	return IRQ_HANDLED;
-}
-
-static snd_pcm_uframes_t snd_ad1848_playback_pointer(struct snd_pcm_substream *substream)
-{
-	struct snd_ad1848 *chip = snd_pcm_substream_chip(substream);
-	size_t ptr;
-	
-	if (!(chip->image[AD1848_IFACE_CTRL] & AD1848_PLAYBACK_ENABLE))
-		return 0;
-	ptr = snd_dma_pointer(chip->dma, chip->dma_size);
-	return bytes_to_frames(substream->runtime, ptr);
-}
-
-static snd_pcm_uframes_t snd_ad1848_capture_pointer(struct snd_pcm_substream *substream)
-{
-	struct snd_ad1848 *chip = snd_pcm_substream_chip(substream);
-	size_t ptr;
-
-	if (!(chip->image[AD1848_IFACE_CTRL] & AD1848_CAPTURE_ENABLE))
-		return 0;
-	ptr = snd_dma_pointer(chip->dma, chip->dma_size);
-	return bytes_to_frames(substream->runtime, ptr);
-}
-
-/*
-
- */
-
-static void snd_ad1848_thinkpad_twiddle(struct snd_ad1848 *chip, int on) {
-
-	int tmp;
-
-	if (!chip->thinkpad_flag) return;
-
-	outb(0x1c, AD1848_THINKPAD_CTL_PORT1);
-	tmp = inb(AD1848_THINKPAD_CTL_PORT2);
-
-	if (on)
-		/* turn it on */
-		tmp |= AD1848_THINKPAD_CS4248_ENABLE_BIT;
-	else
-		/* turn it off */
-		tmp &= ~AD1848_THINKPAD_CS4248_ENABLE_BIT;
-	
-	outb(tmp, AD1848_THINKPAD_CTL_PORT2);
-
-}
-
-#ifdef CONFIG_PM
-static void snd_ad1848_suspend(struct snd_ad1848 *chip)
-{
-	snd_pcm_suspend_all(chip->pcm);
-	if (chip->thinkpad_flag)
-		snd_ad1848_thinkpad_twiddle(chip, 0);
-}
-
-static void snd_ad1848_resume(struct snd_ad1848 *chip)
-{
-	int i;
-
-	if (chip->thinkpad_flag)
-		snd_ad1848_thinkpad_twiddle(chip, 1);
-
-	/* clear any pendings IRQ */
-	inb(AD1848P(chip, STATUS));
-	outb(0, AD1848P(chip, STATUS));
-	mb();
-
-	snd_ad1848_mce_down(chip);
-	for (i = 0; i < 16; i++)
-		snd_ad1848_out(chip, i, chip->image[i]);
-	snd_ad1848_mce_up(chip);
-	snd_ad1848_mce_down(chip);
-}
-#endif /* CONFIG_PM */
-
-static int snd_ad1848_probe(struct snd_ad1848 * chip)
-{
-	unsigned long flags;
-	int i, id, rev, ad1847;
-	unsigned char *ptr;
-
-#if 0
-	snd_ad1848_debug(chip);
-#endif
-	id = ad1847 = 0;
-	for (i = 0; i < 1000; i++) {
-		mb();
-		if (inb(AD1848P(chip, REGSEL)) & AD1848_INIT)
-			udelay(500);
-		else {
-			spin_lock_irqsave(&chip->reg_lock, flags);
-			snd_ad1848_out(chip, AD1848_MISC_INFO, 0x00);
-			snd_ad1848_out(chip, AD1848_LEFT_INPUT, 0xaa);
-			snd_ad1848_out(chip, AD1848_RIGHT_INPUT, 0x45);
-			rev = snd_ad1848_in(chip, AD1848_RIGHT_INPUT);
-			if (rev == 0x65) {
-				spin_unlock_irqrestore(&chip->reg_lock, flags);
-				id = 1;
-				ad1847 = 1;
-				break;
-			}
-			if (snd_ad1848_in(chip, AD1848_LEFT_INPUT) == 0xaa && rev == 0x45) {
-				spin_unlock_irqrestore(&chip->reg_lock, flags);
-				id = 1;
-				break;
-			}
-			spin_unlock_irqrestore(&chip->reg_lock, flags);
-		}
-	}
-	if (id != 1)
-		return -ENODEV;	/* no valid device found */
-	if (chip->hardware == AD1848_HW_DETECT) {
-		if (ad1847) {
-			chip->hardware = AD1848_HW_AD1847;
-		} else {
-			chip->hardware = AD1848_HW_AD1848;
-			rev = snd_ad1848_in(chip, AD1848_MISC_INFO);
-			if (rev & 0x80) {
-				chip->hardware = AD1848_HW_CS4248;
-			} else if ((rev & 0x0f) == 0x0a) {
-				snd_ad1848_out(chip, AD1848_MISC_INFO, 0x40);
-				for (i = 0; i < 16; ++i) {
-					if (snd_ad1848_in(chip, i) != snd_ad1848_in(chip, i + 16)) {
-						chip->hardware = AD1848_HW_CMI8330;
-						break;
-					}
-				}
-				snd_ad1848_out(chip, AD1848_MISC_INFO, 0x00);
-			}
-		}
-	}
-	spin_lock_irqsave(&chip->reg_lock, flags);
-	inb(AD1848P(chip, STATUS));	/* clear any pendings IRQ */
-	outb(0, AD1848P(chip, STATUS));
-	mb();
-	spin_unlock_irqrestore(&chip->reg_lock, flags);
-
-	chip->image[AD1848_MISC_INFO] = 0x00;
-	chip->image[AD1848_IFACE_CTRL] =
-	    (chip->image[AD1848_IFACE_CTRL] & ~AD1848_SINGLE_DMA) | AD1848_SINGLE_DMA;
-	ptr = (unsigned char *) &chip->image;
-	snd_ad1848_mce_down(chip);
-	spin_lock_irqsave(&chip->reg_lock, flags);
-	for (i = 0; i < 16; i++)	/* ok.. fill all AD1848 registers */
-		snd_ad1848_out(chip, i, *ptr++);
-	spin_unlock_irqrestore(&chip->reg_lock, flags);
-	snd_ad1848_mce_up(chip);
-	snd_ad1848_mce_down(chip);
-	return 0;		/* all things are ok.. */
-}
-
-/*
-
- */
-
-static struct snd_pcm_hardware snd_ad1848_playback =
-{
-	.info =			(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
-				 SNDRV_PCM_INFO_MMAP_VALID),
-	.formats =		(SNDRV_PCM_FMTBIT_MU_LAW | SNDRV_PCM_FMTBIT_A_LAW |
-				 SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE),
-	.rates =		SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_8000_48000,
-	.rate_min =		5510,
-	.rate_max =		48000,
-	.channels_min =		1,
-	.channels_max =		2,
-	.buffer_bytes_max =	(128*1024),
-	.period_bytes_min =	64,
-	.period_bytes_max =	(128*1024),
-	.periods_min =		1,
-	.periods_max =		1024,
-	.fifo_size =		0,
-};
-
-static struct snd_pcm_hardware snd_ad1848_capture =
-{
-	.info =			(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
-				 SNDRV_PCM_INFO_MMAP_VALID),
-	.formats =		(SNDRV_PCM_FMTBIT_MU_LAW | SNDRV_PCM_FMTBIT_A_LAW |
-				 SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE),
-	.rates =		SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_8000_48000,
-	.rate_min =		5510,
-	.rate_max =		48000,
-	.channels_min =		1,
-	.channels_max =		2,
-	.buffer_bytes_max =	(128*1024),
-	.period_bytes_min =	64,
-	.period_bytes_max =	(128*1024),
-	.periods_min =		1,
-	.periods_max =		1024,
-	.fifo_size =		0,
-};
-
-/*
-
- */
-
-static int snd_ad1848_playback_open(struct snd_pcm_substream *substream)
-{
-	struct snd_ad1848 *chip = snd_pcm_substream_chip(substream);
-	struct snd_pcm_runtime *runtime = substream->runtime;
-	int err;
-
-	if ((err = snd_ad1848_open(chip, AD1848_MODE_PLAY)) < 0)
-		return err;
-	chip->playback_substream = substream;
-	runtime->hw = snd_ad1848_playback;
-	snd_pcm_limit_isa_dma_size(chip->dma, &runtime->hw.buffer_bytes_max);
-	snd_pcm_limit_isa_dma_size(chip->dma, &runtime->hw.period_bytes_max);
-	snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates);
-	return 0;
-}
-
-static int snd_ad1848_capture_open(struct snd_pcm_substream *substream)
-{
-	struct snd_ad1848 *chip = snd_pcm_substream_chip(substream);
-	struct snd_pcm_runtime *runtime = substream->runtime;
-	int err;
-
-	if ((err = snd_ad1848_open(chip, AD1848_MODE_CAPTURE)) < 0)
-		return err;
-	chip->capture_substream = substream;
-	runtime->hw = snd_ad1848_capture;
-	snd_pcm_limit_isa_dma_size(chip->dma, &runtime->hw.buffer_bytes_max);
-	snd_pcm_limit_isa_dma_size(chip->dma, &runtime->hw.period_bytes_max);
-	snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates);
-	return 0;
-}
-
-static int snd_ad1848_playback_close(struct snd_pcm_substream *substream)
-{
-	struct snd_ad1848 *chip = snd_pcm_substream_chip(substream);
-
-	chip->mode &= ~AD1848_MODE_PLAY;
-	chip->playback_substream = NULL;
-	snd_ad1848_close(chip);
-	return 0;
-}
-
-static int snd_ad1848_capture_close(struct snd_pcm_substream *substream)
-{
-	struct snd_ad1848 *chip = snd_pcm_substream_chip(substream);
-
-	chip->mode &= ~AD1848_MODE_CAPTURE;
-	chip->capture_substream = NULL;
-	snd_ad1848_close(chip);
-	return 0;
-}
-
-static int snd_ad1848_free(struct snd_ad1848 *chip)
-{
-	release_and_free_resource(chip->res_port);
-	if (chip->irq >= 0)
-		free_irq(chip->irq, (void *) chip);
-	if (chip->dma >= 0) {
-		snd_dma_disable(chip->dma);
-		free_dma(chip->dma);
-	}
-	kfree(chip);
-	return 0;
-}
-
-static int snd_ad1848_dev_free(struct snd_device *device)
-{
-	struct snd_ad1848 *chip = device->device_data;
-	return snd_ad1848_free(chip);
-}
-
-static const char *snd_ad1848_chip_id(struct snd_ad1848 *chip)
-{
-	switch (chip->hardware) {
-	case AD1848_HW_AD1847:	return "AD1847";
-	case AD1848_HW_AD1848:	return "AD1848";
-	case AD1848_HW_CS4248:	return "CS4248";
-	case AD1848_HW_CMI8330: return "CMI8330/C3D";
-	default:		return "???";
-	}
-}
-
-int snd_ad1848_create(struct snd_card *card,
-		      unsigned long port,
-		      int irq, int dma,
-		      unsigned short hardware,
-		      struct snd_ad1848 ** rchip)
-{
-	static struct snd_device_ops ops = {
-		.dev_free =	snd_ad1848_dev_free,
-	};
-	struct snd_ad1848 *chip;
-	int err;
-
-	*rchip = NULL;
-	chip = kzalloc(sizeof(*chip), GFP_KERNEL);
-	if (chip == NULL)
-		return -ENOMEM;
-	spin_lock_init(&chip->reg_lock);
-	chip->card = card;
-	chip->port = port;
-	chip->irq = -1;
-	chip->dma = -1;
-	chip->hardware = hardware;
-	memcpy(&chip->image, &snd_ad1848_original_image, sizeof(snd_ad1848_original_image));
-	
-	if ((chip->res_port = request_region(port, 4, "AD1848")) == NULL) {
-		snd_printk(KERN_ERR "ad1848: can't grab port 0x%lx\n", port);
-		snd_ad1848_free(chip);
-		return -EBUSY;
-	}
-	if (request_irq(irq, snd_ad1848_interrupt, IRQF_DISABLED, "AD1848", (void *) chip)) {
-		snd_printk(KERN_ERR "ad1848: can't grab IRQ %d\n", irq);
-		snd_ad1848_free(chip);
-		return -EBUSY;
-	}
-	chip->irq = irq;
-	if (request_dma(dma, "AD1848")) {
-		snd_printk(KERN_ERR "ad1848: can't grab DMA %d\n", dma);
-		snd_ad1848_free(chip);
-		return -EBUSY;
-	}
-	chip->dma = dma;
-
-	if (hardware == AD1848_HW_THINKPAD) {
-		chip->thinkpad_flag = 1;
-		chip->hardware = AD1848_HW_DETECT; /* reset */
-		snd_ad1848_thinkpad_twiddle(chip, 1);
-	}
-
-	if (snd_ad1848_probe(chip) < 0) {
-		snd_ad1848_free(chip);
-		return -ENODEV;
-	}
-
-	/* Register device */
-	if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) {
-		snd_ad1848_free(chip);
-		return err;
-	}
-
-#ifdef CONFIG_PM
-	chip->suspend = snd_ad1848_suspend;
-	chip->resume = snd_ad1848_resume;
-#endif
-
-	*rchip = chip;
-	return 0;
-}
-
-EXPORT_SYMBOL(snd_ad1848_create);
-
-static struct snd_pcm_ops snd_ad1848_playback_ops = {
-	.open =		snd_ad1848_playback_open,
-	.close =	snd_ad1848_playback_close,
-	.ioctl =	snd_ad1848_ioctl,
-	.hw_params =	snd_ad1848_playback_hw_params,
-	.hw_free =	snd_ad1848_playback_hw_free,
-	.prepare =	snd_ad1848_playback_prepare,
-	.trigger =	snd_ad1848_playback_trigger,
-	.pointer =	snd_ad1848_playback_pointer,
-};
-
-static struct snd_pcm_ops snd_ad1848_capture_ops = {
-	.open =		snd_ad1848_capture_open,
-	.close =	snd_ad1848_capture_close,
-	.ioctl =	snd_ad1848_ioctl,
-	.hw_params =	snd_ad1848_capture_hw_params,
-	.hw_free =	snd_ad1848_capture_hw_free,
-	.prepare =	snd_ad1848_capture_prepare,
-	.trigger =	snd_ad1848_capture_trigger,
-	.pointer =	snd_ad1848_capture_pointer,
-};
-
-int snd_ad1848_pcm(struct snd_ad1848 *chip, int device, struct snd_pcm **rpcm)
-{
-	struct snd_pcm *pcm;
-	int err;
-
-	if ((err = snd_pcm_new(chip->card, "AD1848", device, 1, 1, &pcm)) < 0)
-		return err;
-
-	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_ad1848_playback_ops);
-	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_ad1848_capture_ops);
-
-	pcm->private_data = chip;
-	pcm->info_flags = SNDRV_PCM_INFO_HALF_DUPLEX;
-	strcpy(pcm->name, snd_ad1848_chip_id(chip));
-
-	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
-					      snd_dma_isa_data(),
-					      64*1024, chip->dma > 3 ? 128*1024 : 64*1024);
-
-	chip->pcm = pcm;
-	if (rpcm)
-		*rpcm = pcm;
-	return 0;
-}
-
-EXPORT_SYMBOL(snd_ad1848_pcm);
-
-const struct snd_pcm_ops *snd_ad1848_get_pcm_ops(int direction)
-{
-	return direction == SNDRV_PCM_STREAM_PLAYBACK ?
-		&snd_ad1848_playback_ops : &snd_ad1848_capture_ops;
-}
-
-EXPORT_SYMBOL(snd_ad1848_get_pcm_ops);
-
-/*
- *  MIXER part
- */
-
-static int snd_ad1848_info_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
-{
-	static char *texts[4] = {
-		"Line", "Aux", "Mic", "Mix"
-	};
-
-	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
-	uinfo->count = 2;
-	uinfo->value.enumerated.items = 4;
-	if (uinfo->value.enumerated.item > 3)
-		uinfo->value.enumerated.item = 3;
-	strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
-	return 0;
-}
-
-static int snd_ad1848_get_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
-{
-	struct snd_ad1848 *chip = snd_kcontrol_chip(kcontrol);
-	unsigned long flags;
-	
-	spin_lock_irqsave(&chip->reg_lock, flags);
-	ucontrol->value.enumerated.item[0] = (chip->image[AD1848_LEFT_INPUT] & AD1848_MIXS_ALL) >> 6;
-	ucontrol->value.enumerated.item[1] = (chip->image[AD1848_RIGHT_INPUT] & AD1848_MIXS_ALL) >> 6;
-	spin_unlock_irqrestore(&chip->reg_lock, flags);
-	return 0;
-}
-
-static int snd_ad1848_put_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
-{
-	struct snd_ad1848 *chip = snd_kcontrol_chip(kcontrol);
-	unsigned long flags;
-	unsigned short left, right;
-	int change;
-	
-	if (ucontrol->value.enumerated.item[0] > 3 ||
-	    ucontrol->value.enumerated.item[1] > 3)
-		return -EINVAL;
-	left = ucontrol->value.enumerated.item[0] << 6;
-	right = ucontrol->value.enumerated.item[1] << 6;
-	spin_lock_irqsave(&chip->reg_lock, flags);
-	left = (chip->image[AD1848_LEFT_INPUT] & ~AD1848_MIXS_ALL) | left;
-	right = (chip->image[AD1848_RIGHT_INPUT] & ~AD1848_MIXS_ALL) | right;
-	change = left != chip->image[AD1848_LEFT_INPUT] ||
-	         right != chip->image[AD1848_RIGHT_INPUT];
-	snd_ad1848_out(chip, AD1848_LEFT_INPUT, left);
-	snd_ad1848_out(chip, AD1848_RIGHT_INPUT, right);
-	spin_unlock_irqrestore(&chip->reg_lock, flags);
-	return change;
-}
-
-static int snd_ad1848_info_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
-{
-	int mask = (kcontrol->private_value >> 16) & 0xff;
-
-	uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER;
-	uinfo->count = 1;
-	uinfo->value.integer.min = 0;
-	uinfo->value.integer.max = mask;
-	return 0;
-}
-
-static int snd_ad1848_get_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
-{
-	struct snd_ad1848 *chip = snd_kcontrol_chip(kcontrol);
-	unsigned long flags;
-	int reg = kcontrol->private_value & 0xff;
-	int shift = (kcontrol->private_value >> 8) & 0xff;
-	int mask = (kcontrol->private_value >> 16) & 0xff;
-	int invert = (kcontrol->private_value >> 24) & 0xff;
-	
-	spin_lock_irqsave(&chip->reg_lock, flags);
-	ucontrol->value.integer.value[0] = (chip->image[reg] >> shift) & mask;
-	spin_unlock_irqrestore(&chip->reg_lock, flags);
-	if (invert)
-		ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0];
-	return 0;
-}
-
-static int snd_ad1848_put_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
-{
-	struct snd_ad1848 *chip = snd_kcontrol_chip(kcontrol);
-	unsigned long flags;
-	int reg = kcontrol->private_value & 0xff;
-	int shift = (kcontrol->private_value >> 8) & 0xff;
-	int mask = (kcontrol->private_value >> 16) & 0xff;
-	int invert = (kcontrol->private_value >> 24) & 0xff;
-	int change;
-	unsigned short val;
-	
-	val = (ucontrol->value.integer.value[0] & mask);
-	if (invert)
-		val = mask - val;
-	val <<= shift;
-	spin_lock_irqsave(&chip->reg_lock, flags);
-	val = (chip->image[reg] & ~(mask << shift)) | val;
-	change = val != chip->image[reg];
-	snd_ad1848_out(chip, reg, val);
-	spin_unlock_irqrestore(&chip->reg_lock, flags);
-	return change;
-}
-
-static int snd_ad1848_info_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
-{
-	int mask = (kcontrol->private_value >> 24) & 0xff;
-
-	uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER;
-	uinfo->count = 2;
-	uinfo->value.integer.min = 0;
-	uinfo->value.integer.max = mask;
-	return 0;
-}
-
-static int snd_ad1848_get_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
-{
-	struct snd_ad1848 *chip = snd_kcontrol_chip(kcontrol);
-	unsigned long flags;
-	int left_reg = kcontrol->private_value & 0xff;
-	int right_reg = (kcontrol->private_value >> 8) & 0xff;
-	int shift_left = (kcontrol->private_value >> 16) & 0x07;
-	int shift_right = (kcontrol->private_value >> 19) & 0x07;
-	int mask = (kcontrol->private_value >> 24) & 0xff;
-	int invert = (kcontrol->private_value >> 22) & 1;
-	
-	spin_lock_irqsave(&chip->reg_lock, flags);
-	ucontrol->value.integer.value[0] = (chip->image[left_reg] >> shift_left) & mask;
-	ucontrol->value.integer.value[1] = (chip->image[right_reg] >> shift_right) & mask;
-	spin_unlock_irqrestore(&chip->reg_lock, flags);
-	if (invert) {
-		ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0];
-		ucontrol->value.integer.value[1] = mask - ucontrol->value.integer.value[1];
-	}
-	return 0;
-}
-
-static int snd_ad1848_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
-{
-	struct snd_ad1848 *chip = snd_kcontrol_chip(kcontrol);
-	unsigned long flags;
-	int left_reg = kcontrol->private_value & 0xff;
-	int right_reg = (kcontrol->private_value >> 8) & 0xff;
-	int shift_left = (kcontrol->private_value >> 16) & 0x07;
-	int shift_right = (kcontrol->private_value >> 19) & 0x07;
-	int mask = (kcontrol->private_value >> 24) & 0xff;
-	int invert = (kcontrol->private_value >> 22) & 1;
-	int change;
-	unsigned short val1, val2;
-	
-	val1 = ucontrol->value.integer.value[0] & mask;
-	val2 = ucontrol->value.integer.value[1] & mask;
-	if (invert) {
-		val1 = mask - val1;
-		val2 = mask - val2;
-	}
-	val1 <<= shift_left;
-	val2 <<= shift_right;
-	spin_lock_irqsave(&chip->reg_lock, flags);
-	if (left_reg != right_reg) {
-		val1 = (chip->image[left_reg] & ~(mask << shift_left)) | val1;
-		val2 = (chip->image[right_reg] & ~(mask << shift_right)) | val2;
-		change = val1 != chip->image[left_reg] || val2 != chip->image[right_reg];
-		snd_ad1848_out(chip, left_reg, val1);
-		snd_ad1848_out(chip, right_reg, val2);
-	} else {
-		val1 = (chip->image[left_reg] & ~((mask << shift_left) | (mask << shift_right))) | val1 | val2;
-		change = val1 != chip->image[left_reg];
-		snd_ad1848_out(chip, left_reg, val1);		
-	}
-	spin_unlock_irqrestore(&chip->reg_lock, flags);
-	return change;
-}
-
-/*
- */
-int snd_ad1848_add_ctl_elem(struct snd_ad1848 *chip,
-			    const struct ad1848_mix_elem *c)
-{
-	static struct snd_kcontrol_new newctls[] = {
-		[AD1848_MIX_SINGLE] = {
-			.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-			.info = snd_ad1848_info_single,
-			.get = snd_ad1848_get_single,
-			.put = snd_ad1848_put_single,
-		},
-		[AD1848_MIX_DOUBLE] = {
-			.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-			.info = snd_ad1848_info_double,
-			.get = snd_ad1848_get_double,
-			.put = snd_ad1848_put_double,
-		},
-		[AD1848_MIX_CAPTURE] = {
-			.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-			.info = snd_ad1848_info_mux,
-			.get = snd_ad1848_get_mux,
-			.put = snd_ad1848_put_mux,
-		},
-	};
-	struct snd_kcontrol *ctl;
-	int err;
-
-	ctl = snd_ctl_new1(&newctls[c->type], chip);
-	if (! ctl)
-		return -ENOMEM;
-	strlcpy(ctl->id.name, c->name, sizeof(ctl->id.name));
-	ctl->id.index = c->index;
-	ctl->private_value = c->private_value;
-	if (c->tlv) {
-		ctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_TLV_READ;
-		ctl->tlv.p = c->tlv;
-	}
-	if ((err = snd_ctl_add(chip->card, ctl)) < 0)
-		return err;
-	return 0;
-}
-
-EXPORT_SYMBOL(snd_ad1848_add_ctl_elem);
-
-static const DECLARE_TLV_DB_SCALE(db_scale_6bit, -9450, 150, 0);
-static const DECLARE_TLV_DB_SCALE(db_scale_5bit_12db_max, -3450, 150, 0);
-static const DECLARE_TLV_DB_SCALE(db_scale_rec_gain, 0, 150, 0);
-
-static struct ad1848_mix_elem snd_ad1848_controls[] = {
-AD1848_DOUBLE("PCM Playback Switch", 0, AD1848_LEFT_OUTPUT, AD1848_RIGHT_OUTPUT, 7, 7, 1, 1),
-AD1848_DOUBLE_TLV("PCM Playback Volume", 0, AD1848_LEFT_OUTPUT, AD1848_RIGHT_OUTPUT, 0, 0, 63, 1,
-		  db_scale_6bit),
-AD1848_DOUBLE("Aux Playback Switch", 0, AD1848_AUX1_LEFT_INPUT, AD1848_AUX1_RIGHT_INPUT, 7, 7, 1, 1),
-AD1848_DOUBLE_TLV("Aux Playback Volume", 0, AD1848_AUX1_LEFT_INPUT, AD1848_AUX1_RIGHT_INPUT, 0, 0, 31, 1,
-		  db_scale_5bit_12db_max),
-AD1848_DOUBLE("Aux Playback Switch", 1, AD1848_AUX2_LEFT_INPUT, AD1848_AUX2_RIGHT_INPUT, 7, 7, 1, 1),
-AD1848_DOUBLE_TLV("Aux Playback Volume", 1, AD1848_AUX2_LEFT_INPUT, AD1848_AUX2_RIGHT_INPUT, 0, 0, 31, 1,
-		  db_scale_5bit_12db_max),
-AD1848_DOUBLE_TLV("Capture Volume", 0, AD1848_LEFT_INPUT, AD1848_RIGHT_INPUT, 0, 0, 15, 0,
-		  db_scale_rec_gain),
-{
-	.name = "Capture Source",
-	.type = AD1848_MIX_CAPTURE,
-},
-AD1848_SINGLE("Loopback Capture Switch", 0, AD1848_LOOPBACK, 0, 1, 0),
-AD1848_SINGLE_TLV("Loopback Capture Volume", 0, AD1848_LOOPBACK, 1, 63, 0,
-		  db_scale_6bit),
-};
-                                        
-int snd_ad1848_mixer(struct snd_ad1848 *chip)
-{
-	struct snd_card *card;
-	struct snd_pcm *pcm;
-	unsigned int idx;
-	int err;
-
-	snd_assert(chip != NULL && chip->pcm != NULL, return -EINVAL);
-
-	pcm = chip->pcm;
-	card = chip->card;
-
-	strcpy(card->mixername, pcm->name);
-
-	for (idx = 0; idx < ARRAY_SIZE(snd_ad1848_controls); idx++)
-		if ((err = snd_ad1848_add_ctl_elem(chip, &snd_ad1848_controls[idx])) < 0)
-			return err;
-
-	return 0;
-}
-
-EXPORT_SYMBOL(snd_ad1848_mixer);
-
-/*
- *  INIT part
- */
-
-static int __init alsa_ad1848_init(void)
-{
-	return 0;
-}
-
-static void __exit alsa_ad1848_exit(void)
-{
-}
-
-module_init(alsa_ad1848_init)
-module_exit(alsa_ad1848_exit)
diff --git a/sound/isa/azt2320.c b/sound/isa/azt2320.c
index 154e728..3e74d1a 100644
--- a/sound/isa/azt2320.c
+++ b/sound/isa/azt2320.c
@@ -38,7 +38,7 @@
 #include <linux/moduleparam.h>
 #include <sound/core.h>
 #include <sound/initval.h>
-#include <sound/cs4231.h>
+#include <sound/wss.h>
 #include <sound/mpu401.h>
 #include <sound/opl3.h>
 
@@ -76,7 +76,7 @@
 	int dev_no;
 	struct pnp_dev *dev;
 	struct pnp_dev *devmpu;
-	struct snd_cs4231 *chip;
+	struct snd_wss *chip;
 };
 
 static struct pnp_card_device_id snd_azt2320_pnpids[] = {
@@ -181,7 +181,7 @@
 	int error;
 	struct snd_card *card;
 	struct snd_card_azt2320 *acard;
-	struct snd_cs4231 *chip;
+	struct snd_wss *chip;
 	struct snd_opl3 *opl3;
 
 	if ((card = snd_card_new(index[dev], id[dev], THIS_MODULE,
@@ -200,11 +200,11 @@
 		return error;
 	}
 
-	if ((error = snd_cs4231_create(card, wss_port[dev], -1,
-				       irq[dev],
-				       dma1[dev],
-				       dma2[dev],
-				       CS4231_HW_DETECT, 0, &chip)) < 0) {
+	error = snd_wss_create(card, wss_port[dev], -1,
+			       irq[dev],
+			       dma1[dev], dma2[dev],
+			       WSS_HW_DETECT, 0, &chip);
+	if (error < 0) {
 		snd_card_free(card);
 		return error;
 	}
@@ -214,15 +214,18 @@
 	sprintf(card->longname, "%s, WSS at 0x%lx, irq %i, dma %i&%i",
 		card->shortname, chip->port, irq[dev], dma1[dev], dma2[dev]);
 
-	if ((error = snd_cs4231_pcm(chip, 0, NULL)) < 0) {
+	error = snd_wss_pcm(chip, 0, NULL);
+	if (error < 0) {
 		snd_card_free(card);
 		return error;
 	}
-	if ((error = snd_cs4231_mixer(chip)) < 0) {
+	error = snd_wss_mixer(chip);
+	if (error < 0) {
 		snd_card_free(card);
 		return error;
 	}
-	if ((error = snd_cs4231_timer(chip, 0, NULL)) < 0) {
+	error = snd_wss_timer(chip, 0, NULL);
+	if (error < 0) {
 		snd_card_free(card);
 		return error;
 	}
@@ -293,7 +296,7 @@
 {
 	struct snd_card *card = pnp_get_card_drvdata(pcard);
 	struct snd_card_azt2320 *acard = card->private_data;
-	struct snd_cs4231 *chip = acard->chip;
+	struct snd_wss *chip = acard->chip;
 
 	snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
 	chip->suspend(chip);
@@ -304,7 +307,7 @@
 {
 	struct snd_card *card = pnp_get_card_drvdata(pcard);
 	struct snd_card_azt2320 *acard = card->private_data;
-	struct snd_cs4231 *chip = acard->chip;
+	struct snd_wss *chip = acard->chip;
 
 	chip->resume(chip);
 	snd_power_change_state(card, SNDRV_CTL_POWER_D0);
diff --git a/sound/isa/cmi8330.c b/sound/isa/cmi8330.c
index 4d198ec..e49aec7 100644
--- a/sound/isa/cmi8330.c
+++ b/sound/isa/cmi8330.c
@@ -50,7 +50,7 @@
 #include <linux/pnp.h>
 #include <linux/moduleparam.h>
 #include <sound/core.h>
-#include <sound/ad1848.h>
+#include <sound/wss.h>
 #include <sound/sb.h>
 #include <sound/initval.h>
 
@@ -151,7 +151,7 @@
 	struct pnp_dev *play;
 #endif
 	struct snd_card *card;
-	struct snd_ad1848 *wss;
+	struct snd_wss *wss;
 	struct snd_sb *sb;
 
 	struct snd_pcm *pcm;
@@ -174,32 +174,57 @@
 #endif
 
 
-static struct ad1848_mix_elem snd_cmi8330_controls[] __devinitdata = {
-AD1848_DOUBLE("Master Playback Volume", 0, CMI8330_MASTVOL, CMI8330_MASTVOL, 4, 0, 15, 0),
-AD1848_SINGLE("Loud Playback Switch", 0, CMI8330_MUTEMUX, 6, 1, 1),
-AD1848_DOUBLE("PCM Playback Switch", 0, AD1848_LEFT_OUTPUT, AD1848_RIGHT_OUTPUT, 7, 7, 1, 1),
-AD1848_DOUBLE("PCM Playback Volume", 0, AD1848_LEFT_OUTPUT, AD1848_RIGHT_OUTPUT, 0, 0, 63, 1),
-AD1848_DOUBLE("Line Playback Switch", 0, CMI8330_MUTEMUX, CMI8330_MUTEMUX, 4, 3, 1, 0),
-AD1848_DOUBLE("Line Playback Volume", 0, CMI8330_LINVOL, CMI8330_LINVOL, 4, 0, 15, 0),
-AD1848_DOUBLE("Line Capture Switch", 0, CMI8330_RMUX3D, CMI8330_RMUX3D, 2, 1, 1, 0),
-AD1848_DOUBLE("Line Capture Volume", 0, CMI8330_LINGAIN, CMI8330_LINGAIN, 4, 0, 15, 0),
-AD1848_DOUBLE("CD Playback Switch", 0, CMI8330_MUTEMUX, CMI8330_MUTEMUX, 2, 1, 1, 0),
-AD1848_DOUBLE("CD Capture Switch", 0, CMI8330_RMUX3D, CMI8330_RMUX3D, 4, 3, 1, 0),
-AD1848_DOUBLE("CD Playback Volume", 0, CMI8330_CDINVOL, CMI8330_CDINVOL, 4, 0, 15, 0),
-AD1848_DOUBLE("CD Capture Volume", 0, CMI8330_CDINGAIN, CMI8330_CDINGAIN, 4, 0, 15, 0),
-AD1848_SINGLE("Mic Playback Switch", 0, CMI8330_MUTEMUX, 0, 1, 0),
-AD1848_SINGLE("Mic Playback Volume", 0, CMI8330_OUTPUTVOL, 0, 7, 0),
-AD1848_SINGLE("Mic Capture Switch", 0, CMI8330_RMUX3D, 0, 1, 0),
-AD1848_SINGLE("Mic Capture Volume", 0, CMI8330_OUTPUTVOL, 5, 7, 0),
-AD1848_DOUBLE("Wavetable Playback Switch", 0, CMI8330_RECMUX, CMI8330_RECMUX, 1, 0, 1, 0),
-AD1848_DOUBLE("Wavetable Playback Volume", 0, CMI8330_WAVVOL, CMI8330_WAVVOL, 4, 0, 15, 0),
-AD1848_DOUBLE("Wavetable Capture Switch", 0, CMI8330_RECMUX, CMI8330_RECMUX, 5, 4, 1, 0),
-AD1848_DOUBLE("Wavetable Capture Volume", 0, CMI8330_WAVGAIN, CMI8330_WAVGAIN, 4, 0, 15, 0),
-AD1848_SINGLE("3D Control - Switch", 0, CMI8330_RMUX3D, 5, 1, 1),
-AD1848_SINGLE("PC Speaker Playback Volume", 0, CMI8330_OUTPUTVOL, 3, 3, 0),
-AD1848_SINGLE("FM Playback Switch", 0, CMI8330_RECMUX, 3, 1, 1),
-AD1848_SINGLE(SNDRV_CTL_NAME_IEC958("Input ",CAPTURE,SWITCH), 0, CMI8330_RMUX3D, 7, 1, 1),
-AD1848_SINGLE(SNDRV_CTL_NAME_IEC958("Input ",PLAYBACK,SWITCH), 0, CMI8330_MUTEMUX, 7, 1, 1),
+static struct snd_kcontrol_new snd_cmi8330_controls[] __devinitdata = {
+WSS_DOUBLE("Master Playback Volume", 0,
+		CMI8330_MASTVOL, CMI8330_MASTVOL, 4, 0, 15, 0),
+WSS_SINGLE("Loud Playback Switch", 0,
+		CMI8330_MUTEMUX, 6, 1, 1),
+WSS_DOUBLE("PCM Playback Switch", 0,
+		CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 7, 7, 1, 1),
+WSS_DOUBLE("PCM Playback Volume", 0,
+		CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 0, 0, 63, 1),
+WSS_DOUBLE("Line Playback Switch", 0,
+		CMI8330_MUTEMUX, CMI8330_MUTEMUX, 4, 3, 1, 0),
+WSS_DOUBLE("Line Playback Volume", 0,
+		CMI8330_LINVOL, CMI8330_LINVOL, 4, 0, 15, 0),
+WSS_DOUBLE("Line Capture Switch", 0,
+		CMI8330_RMUX3D, CMI8330_RMUX3D, 2, 1, 1, 0),
+WSS_DOUBLE("Line Capture Volume", 0,
+		CMI8330_LINGAIN, CMI8330_LINGAIN, 4, 0, 15, 0),
+WSS_DOUBLE("CD Playback Switch", 0,
+		CMI8330_MUTEMUX, CMI8330_MUTEMUX, 2, 1, 1, 0),
+WSS_DOUBLE("CD Capture Switch", 0,
+		CMI8330_RMUX3D, CMI8330_RMUX3D, 4, 3, 1, 0),
+WSS_DOUBLE("CD Playback Volume", 0,
+		CMI8330_CDINVOL, CMI8330_CDINVOL, 4, 0, 15, 0),
+WSS_DOUBLE("CD Capture Volume", 0,
+		CMI8330_CDINGAIN, CMI8330_CDINGAIN, 4, 0, 15, 0),
+WSS_SINGLE("Mic Playback Switch", 0,
+		CMI8330_MUTEMUX, 0, 1, 0),
+WSS_SINGLE("Mic Playback Volume", 0,
+		CMI8330_OUTPUTVOL, 0, 7, 0),
+WSS_SINGLE("Mic Capture Switch", 0,
+		CMI8330_RMUX3D, 0, 1, 0),
+WSS_SINGLE("Mic Capture Volume", 0,
+		CMI8330_OUTPUTVOL, 5, 7, 0),
+WSS_DOUBLE("Wavetable Playback Switch", 0,
+		CMI8330_RECMUX, CMI8330_RECMUX, 1, 0, 1, 0),
+WSS_DOUBLE("Wavetable Playback Volume", 0,
+		CMI8330_WAVVOL, CMI8330_WAVVOL, 4, 0, 15, 0),
+WSS_DOUBLE("Wavetable Capture Switch", 0,
+		CMI8330_RECMUX, CMI8330_RECMUX, 5, 4, 1, 0),
+WSS_DOUBLE("Wavetable Capture Volume", 0,
+		CMI8330_WAVGAIN, CMI8330_WAVGAIN, 4, 0, 15, 0),
+WSS_SINGLE("3D Control - Switch", 0,
+		CMI8330_RMUX3D, 5, 1, 1),
+WSS_SINGLE("PC Speaker Playback Volume", 0,
+		CMI8330_OUTPUTVOL, 3, 3, 0),
+WSS_SINGLE("FM Playback Switch", 0,
+		CMI8330_RECMUX, 3, 1, 1),
+WSS_SINGLE(SNDRV_CTL_NAME_IEC958("Input ", CAPTURE, SWITCH), 0,
+		CMI8330_RMUX3D, 7, 1, 1),
+WSS_SINGLE(SNDRV_CTL_NAME_IEC958("Input ", PLAYBACK, SWITCH), 0,
+		CMI8330_MUTEMUX, 7, 1, 1),
 };
 
 #ifdef ENABLE_SB_MIXER
@@ -268,7 +293,10 @@
 	strcpy(card->mixername, "CMI8330/C3D");
 
 	for (idx = 0; idx < ARRAY_SIZE(snd_cmi8330_controls); idx++) {
-		if ((err = snd_ad1848_add_ctl_elem(acard->wss, &snd_cmi8330_controls[idx])) < 0)
+		err = snd_ctl_add(card,
+				snd_ctl_new1(&snd_cmi8330_controls[idx],
+					     acard->wss));
+		if (err < 0)
 			return err;
 	}
 
@@ -385,7 +413,7 @@
 	chip->streams[CMI_SB_STREAM].private_data = chip->sb;
 
 	/* AD1848 */
-	ops = snd_ad1848_get_pcm_ops(CMI_AD_STREAM);
+	ops = snd_wss_get_pcm_ops(CMI_AD_STREAM);
 	chip->streams[CMI_AD_STREAM].ops = *ops;
 	chip->streams[CMI_AD_STREAM].open = ops->open;
 	chip->streams[CMI_AD_STREAM].ops.open = cmi_open_callbacks[CMI_AD_STREAM];
@@ -461,16 +489,15 @@
 	int i, err;
 
 	acard = card->private_data;
-	if ((err = snd_ad1848_create(card,
-				     wssport[dev] + 4,
-				     wssirq[dev],
-				     wssdma[dev],
-				     AD1848_HW_DETECT,
-				     &acard->wss)) < 0) {
+	err = snd_wss_create(card, wssport[dev] + 4, -1,
+			     wssirq[dev],
+			     wssdma[dev], -1,
+			     WSS_HW_DETECT, 0, &acard->wss);
+	if (err < 0) {
 		snd_printk(KERN_ERR PFX "(AD1848) device busy??\n");
 		return err;
 	}
-	if (acard->wss->hardware != AD1848_HW_CMI8330) {
+	if (acard->wss->hardware != WSS_HW_CMI8330) {
 		snd_printk(KERN_ERR PFX "(AD1848) not found during probe\n");
 		return -ENODEV;
 	}
@@ -489,9 +516,10 @@
 		return err;
 	}
 
-	snd_ad1848_out(acard->wss, AD1848_MISC_INFO, 0x40); /* switch on MODE2 */
+	snd_wss_out(acard->wss, CS4231_MISC_INFO, 0x40); /* switch on MODE2 */
 	for (i = CMI8330_RMUX3D; i <= CMI8330_CDINGAIN; i++)
-		snd_ad1848_out(acard->wss, i, snd_cmi8330_image[i - CMI8330_RMUX3D]);
+		snd_wss_out(acard->wss, i,
+			    snd_cmi8330_image[i - CMI8330_RMUX3D]);
 
 	if ((err = snd_cmi8330_mixer(card, acard)) < 0) {
 		snd_printk(KERN_ERR PFX "failed to create mixers\n");
diff --git a/sound/isa/cs423x/Makefile b/sound/isa/cs423x/Makefile
index 5067ee0..5870ca2 100644
--- a/sound/isa/cs423x/Makefile
+++ b/sound/isa/cs423x/Makefile
@@ -3,14 +3,12 @@
 # Copyright (c) 2001 by Jaroslav Kysela <perex@perex.cz>
 #
 
-snd-cs4231-lib-objs := cs4231_lib.o
 snd-cs4236-lib-objs := cs4236_lib.o
 snd-cs4231-objs := cs4231.o
 snd-cs4232-objs := cs4232.o
 snd-cs4236-objs := cs4236.o
 
 # Toplevel Module Dependency
-obj-$(CONFIG_SND_CS4231_LIB) += snd-cs4231-lib.o
 obj-$(CONFIG_SND_CS4231) += snd-cs4231.o
 obj-$(CONFIG_SND_CS4232) += snd-cs4232.o
 obj-$(CONFIG_SND_CS4236) += snd-cs4236.o snd-cs4236-lib.o
diff --git a/sound/isa/cs423x/cs4231.c b/sound/isa/cs423x/cs4231.c
index e9462b9..ddd2891 100644
--- a/sound/isa/cs423x/cs4231.c
+++ b/sound/isa/cs423x/cs4231.c
@@ -27,7 +27,7 @@
 #include <linux/wait.h>
 #include <linux/moduleparam.h>
 #include <sound/core.h>
-#include <sound/cs4231.h>
+#include <sound/wss.h>
 #include <sound/mpu401.h>
 #include <sound/initval.h>
 
@@ -91,7 +91,7 @@
 static int __devinit snd_cs4231_probe(struct device *dev, unsigned int n)
 {
 	struct snd_card *card;
-	struct snd_cs4231 *chip;
+	struct snd_wss *chip;
 	struct snd_pcm *pcm;
 	int error;
 
@@ -99,14 +99,14 @@
 	if (!card)
 		return -EINVAL;
 
-	error = snd_cs4231_create(card, port[n], -1, irq[n], dma1[n], dma2[n],
-			CS4231_HW_DETECT, 0, &chip);
+	error = snd_wss_create(card, port[n], -1, irq[n], dma1[n], dma2[n],
+			WSS_HW_DETECT, 0, &chip);
 	if (error < 0)
 		goto out;
 
 	card->private_data = chip;
 
-	error = snd_cs4231_pcm(chip, 0, &pcm);
+	error = snd_wss_pcm(chip, 0, &pcm);
 	if (error < 0)
 		goto out;
 
@@ -118,11 +118,11 @@
 	if (dma2[n] >= 0)
 		sprintf(card->longname + strlen(card->longname), "&%d", dma2[n]);
 
-	error = snd_cs4231_mixer(chip);
+	error = snd_wss_mixer(chip);
 	if (error < 0)
 		goto out;
 
-	error = snd_cs4231_timer(chip, 0, NULL);
+	error = snd_wss_timer(chip, 0, NULL);
 	if (error < 0)
 		goto out;
 
@@ -160,7 +160,7 @@
 static int snd_cs4231_suspend(struct device *dev, unsigned int n, pm_message_t state)
 {
 	struct snd_card *card = dev_get_drvdata(dev);
-	struct snd_cs4231 *chip = card->private_data;
+	struct snd_wss *chip = card->private_data;
 
 	snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
 	chip->suspend(chip);
@@ -170,7 +170,7 @@
 static int snd_cs4231_resume(struct device *dev, unsigned int n)
 {
 	struct snd_card *card = dev_get_drvdata(dev);
-	struct snd_cs4231 *chip = card->private_data;
+	struct snd_wss *chip = card->private_data;
 
 	chip->resume(chip);
 	snd_power_change_state(card, SNDRV_CTL_POWER_D0);
diff --git a/sound/isa/cs423x/cs4231_lib.c b/sound/isa/cs423x/cs4231_lib.c
deleted file mode 100644
index 521db70..0000000
--- a/sound/isa/cs423x/cs4231_lib.c
+++ /dev/null
@@ -1,1945 +0,0 @@
-/*
- *  Copyright (c) by Jaroslav Kysela <perex@perex.cz>
- *  Routines for control of CS4231(A)/CS4232/InterWave & compatible chips
- *
- *  Bugs:
- *     - sometimes record brokes playback with WSS portion of 
- *       Yamaha OPL3-SA3 chip
- *     - CS4231 (GUS MAX) - still trouble with occasional noises
- *                        - broken initialization?
- *
- *   This program is free software; you can redistribute it and/or 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/delay.h>
-#include <linux/pm.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/slab.h>
-#include <linux/ioport.h>
-#include <sound/core.h>
-#include <sound/cs4231.h>
-#include <sound/pcm_params.h>
-
-#include <asm/io.h>
-#include <asm/dma.h>
-#include <asm/irq.h>
-
-MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
-MODULE_DESCRIPTION("Routines for control of CS4231(A)/CS4232/InterWave & compatible chips");
-MODULE_LICENSE("GPL");
-
-#if 0
-#define SNDRV_DEBUG_MCE
-#endif
-
-/*
- *  Some variables
- */
-
-static unsigned char freq_bits[14] = {
-	/* 5510 */	0x00 | CS4231_XTAL2,
-	/* 6620 */	0x0E | CS4231_XTAL2,
-	/* 8000 */	0x00 | CS4231_XTAL1,
-	/* 9600 */	0x0E | CS4231_XTAL1,
-	/* 11025 */	0x02 | CS4231_XTAL2,
-	/* 16000 */	0x02 | CS4231_XTAL1,
-	/* 18900 */	0x04 | CS4231_XTAL2,
-	/* 22050 */	0x06 | CS4231_XTAL2,
-	/* 27042 */	0x04 | CS4231_XTAL1,
-	/* 32000 */	0x06 | CS4231_XTAL1,
-	/* 33075 */	0x0C | CS4231_XTAL2,
-	/* 37800 */	0x08 | CS4231_XTAL2,
-	/* 44100 */	0x0A | CS4231_XTAL2,
-	/* 48000 */	0x0C | CS4231_XTAL1
-};
-
-static unsigned int rates[14] = {
-	5510, 6620, 8000, 9600, 11025, 16000, 18900, 22050,
-	27042, 32000, 33075, 37800, 44100, 48000
-};
-
-static struct snd_pcm_hw_constraint_list hw_constraints_rates = {
-	.count = ARRAY_SIZE(rates),
-	.list = rates,
-	.mask = 0,
-};
-
-static int snd_cs4231_xrate(struct snd_pcm_runtime *runtime)
-{
-	return snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates);
-}
-
-static unsigned char snd_cs4231_original_image[32] =
-{
-	0x00,			/* 00/00 - lic */
-	0x00,			/* 01/01 - ric */
-	0x9f,			/* 02/02 - la1ic */
-	0x9f,			/* 03/03 - ra1ic */
-	0x9f,			/* 04/04 - la2ic */
-	0x9f,			/* 05/05 - ra2ic */
-	0xbf,			/* 06/06 - loc */
-	0xbf,			/* 07/07 - roc */
-	0x20,			/* 08/08 - pdfr */
-	CS4231_AUTOCALIB,	/* 09/09 - ic */
-	0x00,			/* 0a/10 - pc */
-	0x00,			/* 0b/11 - ti */
-	CS4231_MODE2,		/* 0c/12 - mi */
-	0xfc,			/* 0d/13 - lbc */
-	0x00,			/* 0e/14 - pbru */
-	0x00,			/* 0f/15 - pbrl */
-	0x80,			/* 10/16 - afei */
-	0x01,			/* 11/17 - afeii */
-	0x9f,			/* 12/18 - llic */
-	0x9f,			/* 13/19 - rlic */
-	0x00,			/* 14/20 - tlb */
-	0x00,			/* 15/21 - thb */
-	0x00,			/* 16/22 - la3mic/reserved */
-	0x00,			/* 17/23 - ra3mic/reserved */
-	0x00,			/* 18/24 - afs */
-	0x00,			/* 19/25 - lamoc/version */
-	0xcf,			/* 1a/26 - mioc */
-	0x00,			/* 1b/27 - ramoc/reserved */
-	0x20,			/* 1c/28 - cdfr */
-	0x00,			/* 1d/29 - res4 */
-	0x00,			/* 1e/30 - cbru */
-	0x00,			/* 1f/31 - cbrl */
-};
-
-static unsigned char snd_opti93x_original_image[32] =
-{
-	0x00,		/* 00/00 - l_mixout_outctrl */
-	0x00,		/* 01/01 - r_mixout_outctrl */
-	0x88,		/* 02/02 - l_cd_inctrl */
-	0x88,		/* 03/03 - r_cd_inctrl */
-	0x88,		/* 04/04 - l_a1/fm_inctrl */
-	0x88,		/* 05/05 - r_a1/fm_inctrl */
-	0x80,		/* 06/06 - l_dac_inctrl */
-	0x80,		/* 07/07 - r_dac_inctrl */
-	0x00,		/* 08/08 - ply_dataform_reg */
-	0x00,		/* 09/09 - if_conf */
-	0x00,		/* 0a/10 - pin_ctrl */
-	0x00,		/* 0b/11 - err_init_reg */
-	0x0a,		/* 0c/12 - id_reg */
-	0x00,		/* 0d/13 - reserved */
-	0x00,		/* 0e/14 - ply_upcount_reg */
-	0x00,		/* 0f/15 - ply_lowcount_reg */
-	0x88,		/* 10/16 - reserved/l_a1_inctrl */
-	0x88,		/* 11/17 - reserved/r_a1_inctrl */
-	0x88,		/* 12/18 - l_line_inctrl */
-	0x88,		/* 13/19 - r_line_inctrl */
-	0x88,		/* 14/20 - l_mic_inctrl */
-	0x88,		/* 15/21 - r_mic_inctrl */
-	0x80,		/* 16/22 - l_out_outctrl */
-	0x80,		/* 17/23 - r_out_outctrl */
-	0x00,		/* 18/24 - reserved */
-	0x00,		/* 19/25 - reserved */
-	0x00,		/* 1a/26 - reserved */
-	0x00,		/* 1b/27 - reserved */
-	0x00,		/* 1c/28 - cap_dataform_reg */
-	0x00,		/* 1d/29 - reserved */
-	0x00,		/* 1e/30 - cap_upcount_reg */
-	0x00		/* 1f/31 - cap_lowcount_reg */
-};
-
-/*
- *  Basic I/O functions
- */
-
-static inline void cs4231_outb(struct snd_cs4231 *chip, u8 offset, u8 val)
-{
-	outb(val, chip->port + offset);
-}
-
-static inline u8 cs4231_inb(struct snd_cs4231 *chip, u8 offset)
-{
-	return inb(chip->port + offset);
-}
-
-static void snd_cs4231_wait(struct snd_cs4231 *chip)
-{
-	int timeout;
-
-	for (timeout = 250;
-	     timeout > 0 && (cs4231_inb(chip, CS4231P(REGSEL)) & CS4231_INIT);
-	     timeout--)
-	     	udelay(100);
-}
-
-static void snd_cs4231_outm(struct snd_cs4231 *chip, unsigned char reg,
-			    unsigned char mask, unsigned char value)
-{
-	unsigned char tmp = (chip->image[reg] & mask) | value;
-
-	snd_cs4231_wait(chip);
-#ifdef CONFIG_SND_DEBUG
-	if (cs4231_inb(chip, CS4231P(REGSEL)) & CS4231_INIT)
-		snd_printk("outm: auto calibration time out - reg = 0x%x, value = 0x%x\n", reg, value);
-#endif
-	chip->image[reg] = tmp;
-	if (!chip->calibrate_mute) {
-		cs4231_outb(chip, CS4231P(REGSEL), chip->mce_bit | reg);
-		wmb();
-		cs4231_outb(chip, CS4231P(REG), tmp);
-		mb();
-	}
-}
-
-static void snd_cs4231_dout(struct snd_cs4231 *chip, unsigned char reg, unsigned char value)
-{
-	int timeout;
-
-	for (timeout = 250;
-	     timeout > 0 && (cs4231_inb(chip, CS4231P(REGSEL)) & CS4231_INIT);
-	     timeout--)
-	     	udelay(10);
-	cs4231_outb(chip, CS4231P(REGSEL), chip->mce_bit | reg);
-	cs4231_outb(chip, CS4231P(REG), value);
-	mb();
-}
-
-void snd_cs4231_out(struct snd_cs4231 *chip, unsigned char reg, unsigned char value)
-{
-	snd_cs4231_wait(chip);
-#ifdef CONFIG_SND_DEBUG
-	if (cs4231_inb(chip, CS4231P(REGSEL)) & CS4231_INIT)
-		snd_printk("out: auto calibration time out - reg = 0x%x, value = 0x%x\n", reg, value);
-#endif
-	cs4231_outb(chip, CS4231P(REGSEL), chip->mce_bit | reg);
-	cs4231_outb(chip, CS4231P(REG), value);
-	chip->image[reg] = value;
-	mb();
-	snd_printdd("codec out - reg 0x%x = 0x%x\n",
-			chip->mce_bit | reg, value);
-}
-
-unsigned char snd_cs4231_in(struct snd_cs4231 *chip, unsigned char reg)
-{
-	snd_cs4231_wait(chip);
-#ifdef CONFIG_SND_DEBUG
-	if (cs4231_inb(chip, CS4231P(REGSEL)) & CS4231_INIT)
-		snd_printk("in: auto calibration time out - reg = 0x%x\n", reg);
-#endif
-	cs4231_outb(chip, CS4231P(REGSEL), chip->mce_bit | reg);
-	mb();
-	return cs4231_inb(chip, CS4231P(REG));
-}
-
-void snd_cs4236_ext_out(struct snd_cs4231 *chip, unsigned char reg, unsigned char val)
-{
-	cs4231_outb(chip, CS4231P(REGSEL), chip->mce_bit | 0x17);
-	cs4231_outb(chip, CS4231P(REG), reg | (chip->image[CS4236_EXT_REG] & 0x01));
-	cs4231_outb(chip, CS4231P(REG), val);
-	chip->eimage[CS4236_REG(reg)] = val;
-#if 0
-	printk("ext out : reg = 0x%x, val = 0x%x\n", reg, val);
-#endif
-}
-
-unsigned char snd_cs4236_ext_in(struct snd_cs4231 *chip, unsigned char reg)
-{
-	cs4231_outb(chip, CS4231P(REGSEL), chip->mce_bit | 0x17);
-	cs4231_outb(chip, CS4231P(REG), reg | (chip->image[CS4236_EXT_REG] & 0x01));
-#if 1
-	return cs4231_inb(chip, CS4231P(REG));
-#else
-	{
-		unsigned char res;
-		res = cs4231_inb(chip, CS4231P(REG));
-		printk("ext in : reg = 0x%x, val = 0x%x\n", reg, res);
-		return res;
-	}
-#endif
-}
-
-#if 0
-
-static void snd_cs4231_debug(struct snd_cs4231 *chip)
-{
-	printk("CS4231 REGS:      INDEX = 0x%02x  ", cs4231_inb(chip, CS4231P(REGSEL)));
-	printk("                 STATUS = 0x%02x\n", cs4231_inb(chip, CS4231P(STATUS)));
-	printk("  0x00: left input      = 0x%02x  ", snd_cs4231_in(chip, 0x00));
-	printk("  0x10: alt 1 (CFIG 2)  = 0x%02x\n", snd_cs4231_in(chip, 0x10));
-	printk("  0x01: right input     = 0x%02x  ", snd_cs4231_in(chip, 0x01));
-	printk("  0x11: alt 2 (CFIG 3)  = 0x%02x\n", snd_cs4231_in(chip, 0x11));
-	printk("  0x02: GF1 left input  = 0x%02x  ", snd_cs4231_in(chip, 0x02));
-	printk("  0x12: left line in    = 0x%02x\n", snd_cs4231_in(chip, 0x12));
-	printk("  0x03: GF1 right input = 0x%02x  ", snd_cs4231_in(chip, 0x03));
-	printk("  0x13: right line in   = 0x%02x\n", snd_cs4231_in(chip, 0x13));
-	printk("  0x04: CD left input   = 0x%02x  ", snd_cs4231_in(chip, 0x04));
-	printk("  0x14: timer low       = 0x%02x\n", snd_cs4231_in(chip, 0x14));
-	printk("  0x05: CD right input  = 0x%02x  ", snd_cs4231_in(chip, 0x05));
-	printk("  0x15: timer high      = 0x%02x\n", snd_cs4231_in(chip, 0x15));
-	printk("  0x06: left output     = 0x%02x  ", snd_cs4231_in(chip, 0x06));
-	printk("  0x16: left MIC (PnP)  = 0x%02x\n", snd_cs4231_in(chip, 0x16));
-	printk("  0x07: right output    = 0x%02x  ", snd_cs4231_in(chip, 0x07));
-	printk("  0x17: right MIC (PnP) = 0x%02x\n", snd_cs4231_in(chip, 0x17));
-	printk("  0x08: playback format = 0x%02x  ", snd_cs4231_in(chip, 0x08));
-	printk("  0x18: IRQ status      = 0x%02x\n", snd_cs4231_in(chip, 0x18));
-	printk("  0x09: iface (CFIG 1)  = 0x%02x  ", snd_cs4231_in(chip, 0x09));
-	printk("  0x19: left line out   = 0x%02x\n", snd_cs4231_in(chip, 0x19));
-	printk("  0x0a: pin control     = 0x%02x  ", snd_cs4231_in(chip, 0x0a));
-	printk("  0x1a: mono control    = 0x%02x\n", snd_cs4231_in(chip, 0x1a));
-	printk("  0x0b: init & status   = 0x%02x  ", snd_cs4231_in(chip, 0x0b));
-	printk("  0x1b: right line out  = 0x%02x\n", snd_cs4231_in(chip, 0x1b));
-	printk("  0x0c: revision & mode = 0x%02x  ", snd_cs4231_in(chip, 0x0c));
-	printk("  0x1c: record format   = 0x%02x\n", snd_cs4231_in(chip, 0x1c));
-	printk("  0x0d: loopback        = 0x%02x  ", snd_cs4231_in(chip, 0x0d));
-	printk("  0x1d: var freq (PnP)  = 0x%02x\n", snd_cs4231_in(chip, 0x1d));
-	printk("  0x0e: ply upr count   = 0x%02x  ", snd_cs4231_in(chip, 0x0e));
-	printk("  0x1e: ply lwr count   = 0x%02x\n", snd_cs4231_in(chip, 0x1e));
-	printk("  0x0f: rec upr count   = 0x%02x  ", snd_cs4231_in(chip, 0x0f));
-	printk("  0x1f: rec lwr count   = 0x%02x\n", snd_cs4231_in(chip, 0x1f));
-}
-
-#endif
-
-/*
- *  CS4231 detection / MCE routines
- */
-
-static void snd_cs4231_busy_wait(struct snd_cs4231 *chip)
-{
-	int timeout;
-
-	/* huh.. looks like this sequence is proper for CS4231A chip (GUS MAX) */
-	for (timeout = 5; timeout > 0; timeout--)
-		cs4231_inb(chip, CS4231P(REGSEL));
-	/* end of cleanup sequence */
-	for (timeout = 250;
-	     timeout > 0 && (cs4231_inb(chip, CS4231P(REGSEL)) & CS4231_INIT);
-	     timeout--)
-	     	udelay(10);
-}
-
-void snd_cs4231_mce_up(struct snd_cs4231 *chip)
-{
-	unsigned long flags;
-	int timeout;
-
-	snd_cs4231_wait(chip);
-#ifdef CONFIG_SND_DEBUG
-	if (cs4231_inb(chip, CS4231P(REGSEL)) & CS4231_INIT)
-		snd_printk("mce_up - auto calibration time out (0)\n");
-#endif
-	spin_lock_irqsave(&chip->reg_lock, flags);
-	chip->mce_bit |= CS4231_MCE;
-	timeout = cs4231_inb(chip, CS4231P(REGSEL));
-	if (timeout == 0x80)
-		snd_printk("mce_up [0x%lx]: serious init problem - codec still busy\n", chip->port);
-	if (!(timeout & CS4231_MCE))
-		cs4231_outb(chip, CS4231P(REGSEL), chip->mce_bit | (timeout & 0x1f));
-	spin_unlock_irqrestore(&chip->reg_lock, flags);
-}
-
-void snd_cs4231_mce_down(struct snd_cs4231 *chip)
-{
-	unsigned long flags;
-	unsigned long end_time;
-	int timeout;
-
-	snd_cs4231_busy_wait(chip);
-
-#ifdef CONFIG_SND_DEBUG
-	if (cs4231_inb(chip, CS4231P(REGSEL)) & CS4231_INIT)
-		snd_printk("mce_down [0x%lx] - auto calibration time out (0)\n", (long)CS4231P(REGSEL));
-#endif
-	spin_lock_irqsave(&chip->reg_lock, flags);
-	chip->mce_bit &= ~CS4231_MCE;
-	timeout = cs4231_inb(chip, CS4231P(REGSEL));
-	cs4231_outb(chip, CS4231P(REGSEL), chip->mce_bit | (timeout & 0x1f));
-	spin_unlock_irqrestore(&chip->reg_lock, flags);
-	if (timeout == 0x80)
-		snd_printk("mce_down [0x%lx]: serious init problem - codec still busy\n", chip->port);
-	if ((timeout & CS4231_MCE) == 0 ||
-	    !(chip->hardware & (CS4231_HW_CS4231_MASK | CS4231_HW_CS4232_MASK))) {
-		return;
-	}
-
-	/*
-	 * Wait for (possible -- during init auto-calibration may not be set)
-	 * calibration process to start. Needs upto 5 sample periods on AD1848
-	 * which at the slowest possible rate of 5.5125 kHz means 907 us.
-	 */
-	msleep(1);
-
-	snd_printdd("(1) jiffies = %lu\n", jiffies);
-
-	/* check condition up to 250 ms */
-	end_time = jiffies + msecs_to_jiffies(250);
-	while (snd_cs4231_in(chip, CS4231_TEST_INIT) &
-		CS4231_CALIB_IN_PROGRESS) {
-
-		if (time_after(jiffies, end_time)) {
-			snd_printk(KERN_ERR "mce_down - "
-					"auto calibration time out (2)\n");
-			return;
-		}
-		msleep(1);
-	}
-
-	snd_printdd("(2) jiffies = %lu\n", jiffies);
-
-	/* check condition up to 100 ms */
-	end_time = jiffies + msecs_to_jiffies(100);
-	while (cs4231_inb(chip, CS4231P(REGSEL)) & CS4231_INIT) {
-		if (time_after(jiffies, end_time)) {
-			snd_printk(KERN_ERR "mce_down - auto calibration time out (3)\n");
-			return;
-		}
-		msleep(1);
-	}
-
-	snd_printdd("(3) jiffies = %lu\n", jiffies);
-	snd_printd("mce_down - exit = 0x%x\n", cs4231_inb(chip, CS4231P(REGSEL)));
-}
-
-static unsigned int snd_cs4231_get_count(unsigned char format, unsigned int size)
-{
-	switch (format & 0xe0) {
-	case CS4231_LINEAR_16:
-	case CS4231_LINEAR_16_BIG:
-		size >>= 1;
-		break;
-	case CS4231_ADPCM_16:
-		return size >> 2;
-	}
-	if (format & CS4231_STEREO)
-		size >>= 1;
-	return size;
-}
-
-static int snd_cs4231_trigger(struct snd_pcm_substream *substream,
-			      int cmd)
-{
-	struct snd_cs4231 *chip = snd_pcm_substream_chip(substream);
-	int result = 0;
-	unsigned int what;
-	struct snd_pcm_substream *s;
-	int do_start;
-
-#if 0
-	printk("codec trigger!!! - what = %i, enable = %i, status = 0x%x\n", what, enable, cs4231_inb(chip, CS4231P(STATUS)));
-#endif
-
-	switch (cmd) {
-	case SNDRV_PCM_TRIGGER_START:
-	case SNDRV_PCM_TRIGGER_RESUME:
-		do_start = 1; break;
-	case SNDRV_PCM_TRIGGER_STOP:
-	case SNDRV_PCM_TRIGGER_SUSPEND:
-		do_start = 0; break;
-	default:
-		return -EINVAL;
-	}
-
-	what = 0;
-	snd_pcm_group_for_each_entry(s, substream) {
-		if (s == chip->playback_substream) {
-			what |= CS4231_PLAYBACK_ENABLE;
-			snd_pcm_trigger_done(s, substream);
-		} else if (s == chip->capture_substream) {
-			what |= CS4231_RECORD_ENABLE;
-			snd_pcm_trigger_done(s, substream);
-		}
-	}
-	spin_lock(&chip->reg_lock);
-	if (do_start) {
-		chip->image[CS4231_IFACE_CTRL] |= what;
-		if (chip->trigger)
-			chip->trigger(chip, what, 1);
-	} else {
-		chip->image[CS4231_IFACE_CTRL] &= ~what;
-		if (chip->trigger)
-			chip->trigger(chip, what, 0);
-	}
-	snd_cs4231_out(chip, CS4231_IFACE_CTRL, chip->image[CS4231_IFACE_CTRL]);
-	spin_unlock(&chip->reg_lock);
-#if 0
-	snd_cs4231_debug(chip);
-#endif
-	return result;
-}
-
-/*
- *  CODEC I/O
- */
-
-static unsigned char snd_cs4231_get_rate(unsigned int rate)
-{
-	int i;
-
-	for (i = 0; i < ARRAY_SIZE(rates); i++)
-		if (rate == rates[i])
-			return freq_bits[i];
-	// snd_BUG();
-	return freq_bits[ARRAY_SIZE(rates) - 1];
-}
-
-static unsigned char snd_cs4231_get_format(struct snd_cs4231 *chip,
-				           int format,
-                                           int channels)
-{
-	unsigned char rformat;
-
-	rformat = CS4231_LINEAR_8;
-	switch (format) {
-	case SNDRV_PCM_FORMAT_MU_LAW:	rformat = CS4231_ULAW_8; break;
-	case SNDRV_PCM_FORMAT_A_LAW:	rformat = CS4231_ALAW_8; break;
-	case SNDRV_PCM_FORMAT_S16_LE:	rformat = CS4231_LINEAR_16; break;
-	case SNDRV_PCM_FORMAT_S16_BE:	rformat = CS4231_LINEAR_16_BIG; break;
-	case SNDRV_PCM_FORMAT_IMA_ADPCM:	rformat = CS4231_ADPCM_16; break;
-	}
-	if (channels > 1)
-		rformat |= CS4231_STEREO;
-#if 0
-	snd_printk("get_format: 0x%x (mode=0x%x)\n", format, mode);
-#endif
-	return rformat;
-}
-
-static void snd_cs4231_calibrate_mute(struct snd_cs4231 *chip, int mute)
-{
-	unsigned long flags;
-
-	mute = mute ? 1 : 0;
-	spin_lock_irqsave(&chip->reg_lock, flags);
-	if (chip->calibrate_mute == mute) {
-		spin_unlock_irqrestore(&chip->reg_lock, flags);
-		return;
-	}
-	if (!mute) {
-		snd_cs4231_dout(chip, CS4231_LEFT_INPUT, chip->image[CS4231_LEFT_INPUT]);
-		snd_cs4231_dout(chip, CS4231_RIGHT_INPUT, chip->image[CS4231_RIGHT_INPUT]);
-		snd_cs4231_dout(chip, CS4231_LOOPBACK, chip->image[CS4231_LOOPBACK]);
-	}
-	snd_cs4231_dout(chip, CS4231_AUX1_LEFT_INPUT, mute ? 0x80 : chip->image[CS4231_AUX1_LEFT_INPUT]);
-	snd_cs4231_dout(chip, CS4231_AUX1_RIGHT_INPUT, mute ? 0x80 : chip->image[CS4231_AUX1_RIGHT_INPUT]);
-	snd_cs4231_dout(chip, CS4231_AUX2_LEFT_INPUT, mute ? 0x80 : chip->image[CS4231_AUX2_LEFT_INPUT]);
-	snd_cs4231_dout(chip, CS4231_AUX2_RIGHT_INPUT, mute ? 0x80 : chip->image[CS4231_AUX2_RIGHT_INPUT]);
-	snd_cs4231_dout(chip, CS4231_LEFT_OUTPUT, mute ? 0x80 : chip->image[CS4231_LEFT_OUTPUT]);
-	snd_cs4231_dout(chip, CS4231_RIGHT_OUTPUT, mute ? 0x80 : chip->image[CS4231_RIGHT_OUTPUT]);
-	snd_cs4231_dout(chip, CS4231_LEFT_LINE_IN, mute ? 0x80 : chip->image[CS4231_LEFT_LINE_IN]);
-	snd_cs4231_dout(chip, CS4231_RIGHT_LINE_IN, mute ? 0x80 : chip->image[CS4231_RIGHT_LINE_IN]);
-	snd_cs4231_dout(chip, CS4231_MONO_CTRL, mute ? 0xc0 : chip->image[CS4231_MONO_CTRL]);
-	if (chip->hardware == CS4231_HW_INTERWAVE) {
-		snd_cs4231_dout(chip, CS4231_LEFT_MIC_INPUT, mute ? 0x80 : chip->image[CS4231_LEFT_MIC_INPUT]);
-		snd_cs4231_dout(chip, CS4231_RIGHT_MIC_INPUT, mute ? 0x80 : chip->image[CS4231_RIGHT_MIC_INPUT]);		
-		snd_cs4231_dout(chip, CS4231_LINE_LEFT_OUTPUT, mute ? 0x80 : chip->image[CS4231_LINE_LEFT_OUTPUT]);
-		snd_cs4231_dout(chip, CS4231_LINE_RIGHT_OUTPUT, mute ? 0x80 : chip->image[CS4231_LINE_RIGHT_OUTPUT]);
-	}
-	chip->calibrate_mute = mute;
-	spin_unlock_irqrestore(&chip->reg_lock, flags);
-}
-
-static void snd_cs4231_playback_format(struct snd_cs4231 *chip,
-				       struct snd_pcm_hw_params *params,
-				       unsigned char pdfr)
-{
-	unsigned long flags;
-	int full_calib = 1;
-
-	mutex_lock(&chip->mce_mutex);
-	snd_cs4231_calibrate_mute(chip, 1);
-	if (chip->hardware == CS4231_HW_CS4231A ||
-	    (chip->hardware & CS4231_HW_CS4232_MASK)) {
-		spin_lock_irqsave(&chip->reg_lock, flags);
-		if ((chip->image[CS4231_PLAYBK_FORMAT] & 0x0f) == (pdfr & 0x0f)) {	/* rate is same? */
-			snd_cs4231_out(chip, CS4231_ALT_FEATURE_1, chip->image[CS4231_ALT_FEATURE_1] | 0x10);
-			snd_cs4231_out(chip, CS4231_PLAYBK_FORMAT, chip->image[CS4231_PLAYBK_FORMAT] = pdfr);
-			snd_cs4231_out(chip, CS4231_ALT_FEATURE_1, chip->image[CS4231_ALT_FEATURE_1] &= ~0x10);
-			udelay(100); /* Fixes audible clicks at least on GUS MAX */
-			full_calib = 0;
-		}
-		spin_unlock_irqrestore(&chip->reg_lock, flags);
-	}
-	if (full_calib) {
-		snd_cs4231_mce_up(chip);
-		spin_lock_irqsave(&chip->reg_lock, flags);
-		if (chip->hardware != CS4231_HW_INTERWAVE && !chip->single_dma) {
-			snd_cs4231_out(chip, CS4231_PLAYBK_FORMAT,
-					(chip->image[CS4231_IFACE_CTRL] & CS4231_RECORD_ENABLE) ?
-					(pdfr & 0xf0) | (chip->image[CS4231_REC_FORMAT] & 0x0f) :
-				        pdfr);
-		} else {
-			snd_cs4231_out(chip, CS4231_PLAYBK_FORMAT, chip->image[CS4231_PLAYBK_FORMAT] = pdfr);
-		}
-		spin_unlock_irqrestore(&chip->reg_lock, flags);
-		if (chip->hardware == CS4231_HW_OPL3SA2)
-			udelay(100);	/* this seems to help */
-		snd_cs4231_mce_down(chip);
-	}
-	snd_cs4231_calibrate_mute(chip, 0);
-	mutex_unlock(&chip->mce_mutex);
-}
-
-static void snd_cs4231_capture_format(struct snd_cs4231 *chip,
-				      struct snd_pcm_hw_params *params,
-                                      unsigned char cdfr)
-{
-	unsigned long flags;
-	int full_calib = 1;
-
-	mutex_lock(&chip->mce_mutex);
-	snd_cs4231_calibrate_mute(chip, 1);
-	if (chip->hardware == CS4231_HW_CS4231A ||
-	    (chip->hardware & CS4231_HW_CS4232_MASK)) {
-		spin_lock_irqsave(&chip->reg_lock, flags);
-		if ((chip->image[CS4231_PLAYBK_FORMAT] & 0x0f) == (cdfr & 0x0f) ||	/* rate is same? */
-		    (chip->image[CS4231_IFACE_CTRL] & CS4231_PLAYBACK_ENABLE)) {
-			snd_cs4231_out(chip, CS4231_ALT_FEATURE_1, chip->image[CS4231_ALT_FEATURE_1] | 0x20);
-			snd_cs4231_out(chip, CS4231_REC_FORMAT, chip->image[CS4231_REC_FORMAT] = cdfr);
-			snd_cs4231_out(chip, CS4231_ALT_FEATURE_1, chip->image[CS4231_ALT_FEATURE_1] &= ~0x20);
-			full_calib = 0;
-		}
-		spin_unlock_irqrestore(&chip->reg_lock, flags);
-	}
-	if (full_calib) {
-		snd_cs4231_mce_up(chip);
-		spin_lock_irqsave(&chip->reg_lock, flags);
-		if (chip->hardware != CS4231_HW_INTERWAVE) {
-			if (!(chip->image[CS4231_IFACE_CTRL] & CS4231_PLAYBACK_ENABLE)) {
-				snd_cs4231_out(chip, CS4231_PLAYBK_FORMAT,
-					       ((chip->single_dma ? cdfr : chip->image[CS4231_PLAYBK_FORMAT]) & 0xf0) |
-					       (cdfr & 0x0f));
-				spin_unlock_irqrestore(&chip->reg_lock, flags);
-				snd_cs4231_mce_down(chip);
-				snd_cs4231_mce_up(chip);
-				spin_lock_irqsave(&chip->reg_lock, flags);
-			}
-		}
-		snd_cs4231_out(chip, CS4231_REC_FORMAT, cdfr);
-		spin_unlock_irqrestore(&chip->reg_lock, flags);
-		snd_cs4231_mce_down(chip);
-	}
-	snd_cs4231_calibrate_mute(chip, 0);
-	mutex_unlock(&chip->mce_mutex);
-}
-
-/*
- *  Timer interface
- */
-
-static unsigned long snd_cs4231_timer_resolution(struct snd_timer * timer)
-{
-	struct snd_cs4231 *chip = snd_timer_chip(timer);
-	if (chip->hardware & CS4231_HW_CS4236B_MASK)
-		return 14467;
-	else
-		return chip->image[CS4231_PLAYBK_FORMAT] & 1 ? 9969 : 9920;
-}
-
-static int snd_cs4231_timer_start(struct snd_timer * timer)
-{
-	unsigned long flags;
-	unsigned int ticks;
-	struct snd_cs4231 *chip = snd_timer_chip(timer);
-	spin_lock_irqsave(&chip->reg_lock, flags);
-	ticks = timer->sticks;
-	if ((chip->image[CS4231_ALT_FEATURE_1] & CS4231_TIMER_ENABLE) == 0 ||
-	    (unsigned char)(ticks >> 8) != chip->image[CS4231_TIMER_HIGH] ||
-	    (unsigned char)ticks != chip->image[CS4231_TIMER_LOW]) {
-		snd_cs4231_out(chip, CS4231_TIMER_HIGH, chip->image[CS4231_TIMER_HIGH] = (unsigned char) (ticks >> 8));
-		snd_cs4231_out(chip, CS4231_TIMER_LOW, chip->image[CS4231_TIMER_LOW] = (unsigned char) ticks);
-		snd_cs4231_out(chip, CS4231_ALT_FEATURE_1, chip->image[CS4231_ALT_FEATURE_1] | CS4231_TIMER_ENABLE);
-	}
-	spin_unlock_irqrestore(&chip->reg_lock, flags);
-	return 0;
-}
-
-static int snd_cs4231_timer_stop(struct snd_timer * timer)
-{
-	unsigned long flags;
-	struct snd_cs4231 *chip = snd_timer_chip(timer);
-	spin_lock_irqsave(&chip->reg_lock, flags);
-	snd_cs4231_out(chip, CS4231_ALT_FEATURE_1, chip->image[CS4231_ALT_FEATURE_1] &= ~CS4231_TIMER_ENABLE);
-	spin_unlock_irqrestore(&chip->reg_lock, flags);
-	return 0;
-}
-
-static void snd_cs4231_init(struct snd_cs4231 *chip)
-{
-	unsigned long flags;
-
-	snd_cs4231_mce_down(chip);
-
-#ifdef SNDRV_DEBUG_MCE
-	snd_printk("init: (1)\n");
-#endif
-	snd_cs4231_mce_up(chip);
-	spin_lock_irqsave(&chip->reg_lock, flags);
-	chip->image[CS4231_IFACE_CTRL] &= ~(CS4231_PLAYBACK_ENABLE | CS4231_PLAYBACK_PIO |
-			     CS4231_RECORD_ENABLE | CS4231_RECORD_PIO |
-			     CS4231_CALIB_MODE);
-	chip->image[CS4231_IFACE_CTRL] |= CS4231_AUTOCALIB;
-	snd_cs4231_out(chip, CS4231_IFACE_CTRL, chip->image[CS4231_IFACE_CTRL]);
-	spin_unlock_irqrestore(&chip->reg_lock, flags);
-	snd_cs4231_mce_down(chip);
-
-#ifdef SNDRV_DEBUG_MCE
-	snd_printk("init: (2)\n");
-#endif
-
-	snd_cs4231_mce_up(chip);
-	spin_lock_irqsave(&chip->reg_lock, flags);
-	snd_cs4231_out(chip, CS4231_ALT_FEATURE_1, chip->image[CS4231_ALT_FEATURE_1]);
-	spin_unlock_irqrestore(&chip->reg_lock, flags);
-	snd_cs4231_mce_down(chip);
-
-#ifdef SNDRV_DEBUG_MCE
-	snd_printk("init: (3) - afei = 0x%x\n", chip->image[CS4231_ALT_FEATURE_1]);
-#endif
-
-	spin_lock_irqsave(&chip->reg_lock, flags);
-	snd_cs4231_out(chip, CS4231_ALT_FEATURE_2, chip->image[CS4231_ALT_FEATURE_2]);
-	spin_unlock_irqrestore(&chip->reg_lock, flags);
-
-	snd_cs4231_mce_up(chip);
-	spin_lock_irqsave(&chip->reg_lock, flags);
-	snd_cs4231_out(chip, CS4231_PLAYBK_FORMAT, chip->image[CS4231_PLAYBK_FORMAT]);
-	spin_unlock_irqrestore(&chip->reg_lock, flags);
-	snd_cs4231_mce_down(chip);
-
-#ifdef SNDRV_DEBUG_MCE
-	snd_printk("init: (4)\n");
-#endif
-
-	snd_cs4231_mce_up(chip);
-	spin_lock_irqsave(&chip->reg_lock, flags);
-	snd_cs4231_out(chip, CS4231_REC_FORMAT, chip->image[CS4231_REC_FORMAT]);
-	spin_unlock_irqrestore(&chip->reg_lock, flags);
-	snd_cs4231_mce_down(chip);
-
-#ifdef SNDRV_DEBUG_MCE
-	snd_printk("init: (5)\n");
-#endif
-}
-
-static int snd_cs4231_open(struct snd_cs4231 *chip, unsigned int mode)
-{
-	unsigned long flags;
-
-	mutex_lock(&chip->open_mutex);
-	if ((chip->mode & mode) ||
-	    ((chip->mode & CS4231_MODE_OPEN) && chip->single_dma)) {
-		mutex_unlock(&chip->open_mutex);
-		return -EAGAIN;
-	}
-	if (chip->mode & CS4231_MODE_OPEN) {
-		chip->mode |= mode;
-		mutex_unlock(&chip->open_mutex);
-		return 0;
-	}
-	/* ok. now enable and ack CODEC IRQ */
-	spin_lock_irqsave(&chip->reg_lock, flags);
-	snd_cs4231_out(chip, CS4231_IRQ_STATUS, CS4231_PLAYBACK_IRQ |
-		       CS4231_RECORD_IRQ |
-		       CS4231_TIMER_IRQ);
-	snd_cs4231_out(chip, CS4231_IRQ_STATUS, 0);
-	cs4231_outb(chip, CS4231P(STATUS), 0);	/* clear IRQ */
-	cs4231_outb(chip, CS4231P(STATUS), 0);	/* clear IRQ */
-	chip->image[CS4231_PIN_CTRL] |= CS4231_IRQ_ENABLE;
-	snd_cs4231_out(chip, CS4231_PIN_CTRL, chip->image[CS4231_PIN_CTRL]);
-	snd_cs4231_out(chip, CS4231_IRQ_STATUS, CS4231_PLAYBACK_IRQ |
-		       CS4231_RECORD_IRQ |
-		       CS4231_TIMER_IRQ);
-	snd_cs4231_out(chip, CS4231_IRQ_STATUS, 0);
-	spin_unlock_irqrestore(&chip->reg_lock, flags);
-
-	chip->mode = mode;
-	mutex_unlock(&chip->open_mutex);
-	return 0;
-}
-
-static void snd_cs4231_close(struct snd_cs4231 *chip, unsigned int mode)
-{
-	unsigned long flags;
-
-	mutex_lock(&chip->open_mutex);
-	chip->mode &= ~mode;
-	if (chip->mode & CS4231_MODE_OPEN) {
-		mutex_unlock(&chip->open_mutex);
-		return;
-	}
-	snd_cs4231_calibrate_mute(chip, 1);
-
-	/* disable IRQ */
-	spin_lock_irqsave(&chip->reg_lock, flags);
-	snd_cs4231_out(chip, CS4231_IRQ_STATUS, 0);
-	cs4231_outb(chip, CS4231P(STATUS), 0);	/* clear IRQ */
-	cs4231_outb(chip, CS4231P(STATUS), 0);	/* clear IRQ */
-	chip->image[CS4231_PIN_CTRL] &= ~CS4231_IRQ_ENABLE;
-	snd_cs4231_out(chip, CS4231_PIN_CTRL, chip->image[CS4231_PIN_CTRL]);
-
-	/* now disable record & playback */
-
-	if (chip->image[CS4231_IFACE_CTRL] & (CS4231_PLAYBACK_ENABLE | CS4231_PLAYBACK_PIO |
-					       CS4231_RECORD_ENABLE | CS4231_RECORD_PIO)) {
-		spin_unlock_irqrestore(&chip->reg_lock, flags);
-		snd_cs4231_mce_up(chip);
-		spin_lock_irqsave(&chip->reg_lock, flags);
-		chip->image[CS4231_IFACE_CTRL] &= ~(CS4231_PLAYBACK_ENABLE | CS4231_PLAYBACK_PIO |
-						     CS4231_RECORD_ENABLE | CS4231_RECORD_PIO);
-		snd_cs4231_out(chip, CS4231_IFACE_CTRL, chip->image[CS4231_IFACE_CTRL]);
-		spin_unlock_irqrestore(&chip->reg_lock, flags);
-		snd_cs4231_mce_down(chip);
-		spin_lock_irqsave(&chip->reg_lock, flags);
-	}
-
-	/* clear IRQ again */
-	snd_cs4231_out(chip, CS4231_IRQ_STATUS, 0);
-	cs4231_outb(chip, CS4231P(STATUS), 0);	/* clear IRQ */
-	cs4231_outb(chip, CS4231P(STATUS), 0);	/* clear IRQ */
-	spin_unlock_irqrestore(&chip->reg_lock, flags);
-
-	snd_cs4231_calibrate_mute(chip, 0);
-
-	chip->mode = 0;
-	mutex_unlock(&chip->open_mutex);
-}
-
-/*
- *  timer open/close
- */
-
-static int snd_cs4231_timer_open(struct snd_timer * timer)
-{
-	struct snd_cs4231 *chip = snd_timer_chip(timer);
-	snd_cs4231_open(chip, CS4231_MODE_TIMER);
-	return 0;
-}
-
-static int snd_cs4231_timer_close(struct snd_timer * timer)
-{
-	struct snd_cs4231 *chip = snd_timer_chip(timer);
-	snd_cs4231_close(chip, CS4231_MODE_TIMER);
-	return 0;
-}
-
-static struct snd_timer_hardware snd_cs4231_timer_table =
-{
-	.flags =	SNDRV_TIMER_HW_AUTO,
-	.resolution =	9945,
-	.ticks =	65535,
-	.open =		snd_cs4231_timer_open,
-	.close =	snd_cs4231_timer_close,
-	.c_resolution = snd_cs4231_timer_resolution,
-	.start =	snd_cs4231_timer_start,
-	.stop =		snd_cs4231_timer_stop,
-};
-
-/*
- *  ok.. exported functions..
- */
-
-static int snd_cs4231_playback_hw_params(struct snd_pcm_substream *substream,
-					 struct snd_pcm_hw_params *hw_params)
-{
-	struct snd_cs4231 *chip = snd_pcm_substream_chip(substream);
-	unsigned char new_pdfr;
-	int err;
-
-	if ((err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params))) < 0)
-		return err;
-	new_pdfr = snd_cs4231_get_format(chip, params_format(hw_params), params_channels(hw_params)) |
-		   snd_cs4231_get_rate(params_rate(hw_params));
-	chip->set_playback_format(chip, hw_params, new_pdfr);
-	return 0;
-}
-
-static int snd_cs4231_playback_hw_free(struct snd_pcm_substream *substream)
-{
-	return snd_pcm_lib_free_pages(substream);
-}
-
-static int snd_cs4231_playback_prepare(struct snd_pcm_substream *substream)
-{
-	struct snd_cs4231 *chip = snd_pcm_substream_chip(substream);
-	struct snd_pcm_runtime *runtime = substream->runtime;
-	unsigned long flags;
-	unsigned int size = snd_pcm_lib_buffer_bytes(substream);
-	unsigned int count = snd_pcm_lib_period_bytes(substream);
-
-	spin_lock_irqsave(&chip->reg_lock, flags);
-	chip->p_dma_size = size;
-	chip->image[CS4231_IFACE_CTRL] &= ~(CS4231_PLAYBACK_ENABLE | CS4231_PLAYBACK_PIO);
-	snd_dma_program(chip->dma1, runtime->dma_addr, size, DMA_MODE_WRITE | DMA_AUTOINIT);
-	count = snd_cs4231_get_count(chip->image[CS4231_PLAYBK_FORMAT], count) - 1;
-	snd_cs4231_out(chip, CS4231_PLY_LWR_CNT, (unsigned char) count);
-	snd_cs4231_out(chip, CS4231_PLY_UPR_CNT, (unsigned char) (count >> 8));
-	spin_unlock_irqrestore(&chip->reg_lock, flags);
-#if 0
-	snd_cs4231_debug(chip);
-#endif
-	return 0;
-}
-
-static int snd_cs4231_capture_hw_params(struct snd_pcm_substream *substream,
-					struct snd_pcm_hw_params *hw_params)
-{
-	struct snd_cs4231 *chip = snd_pcm_substream_chip(substream);
-	unsigned char new_cdfr;
-	int err;
-
-	if ((err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params))) < 0)
-		return err;
-	new_cdfr = snd_cs4231_get_format(chip, params_format(hw_params), params_channels(hw_params)) |
-		   snd_cs4231_get_rate(params_rate(hw_params));
-	chip->set_capture_format(chip, hw_params, new_cdfr);
-	return 0;
-}
-
-static int snd_cs4231_capture_hw_free(struct snd_pcm_substream *substream)
-{
-	return snd_pcm_lib_free_pages(substream);
-}
-
-static int snd_cs4231_capture_prepare(struct snd_pcm_substream *substream)
-{
-	struct snd_cs4231 *chip = snd_pcm_substream_chip(substream);
-	struct snd_pcm_runtime *runtime = substream->runtime;
-	unsigned long flags;
-	unsigned int size = snd_pcm_lib_buffer_bytes(substream);
-	unsigned int count = snd_pcm_lib_period_bytes(substream);
-
-	spin_lock_irqsave(&chip->reg_lock, flags);
-	chip->c_dma_size = size;
-	chip->image[CS4231_IFACE_CTRL] &= ~(CS4231_RECORD_ENABLE | CS4231_RECORD_PIO);
-	snd_dma_program(chip->dma2, runtime->dma_addr, size, DMA_MODE_READ | DMA_AUTOINIT);
-	count = snd_cs4231_get_count(chip->image[CS4231_REC_FORMAT], count) - 1;
-	if (chip->single_dma && chip->hardware != CS4231_HW_INTERWAVE) {
-		snd_cs4231_out(chip, CS4231_PLY_LWR_CNT, (unsigned char) count);
-		snd_cs4231_out(chip, CS4231_PLY_UPR_CNT, (unsigned char) (count >> 8));
-	} else {
-		snd_cs4231_out(chip, CS4231_REC_LWR_CNT, (unsigned char) count);
-		snd_cs4231_out(chip, CS4231_REC_UPR_CNT, (unsigned char) (count >> 8));
-	}
-	spin_unlock_irqrestore(&chip->reg_lock, flags);
-	return 0;
-}
-
-void snd_cs4231_overrange(struct snd_cs4231 *chip)
-{
-	unsigned long flags;
-	unsigned char res;
-
-	spin_lock_irqsave(&chip->reg_lock, flags);
-	res = snd_cs4231_in(chip, CS4231_TEST_INIT);
-	spin_unlock_irqrestore(&chip->reg_lock, flags);
-	if (res & (0x08 | 0x02))	/* detect overrange only above 0dB; may be user selectable? */
-		chip->capture_substream->runtime->overrange++;
-}
-
-irqreturn_t snd_cs4231_interrupt(int irq, void *dev_id)
-{
-	struct snd_cs4231 *chip = dev_id;
-	unsigned char status;
-
-	status = snd_cs4231_in(chip, CS4231_IRQ_STATUS);
-	if (status & CS4231_TIMER_IRQ) {
-		if (chip->timer)
-			snd_timer_interrupt(chip->timer, chip->timer->sticks);
-	}		
-	if (chip->single_dma && chip->hardware != CS4231_HW_INTERWAVE) {
-		if (status & CS4231_PLAYBACK_IRQ) {
-			if (chip->mode & CS4231_MODE_PLAY) {
-				if (chip->playback_substream)
-					snd_pcm_period_elapsed(chip->playback_substream);
-			}
-			if (chip->mode & CS4231_MODE_RECORD) {
-				if (chip->capture_substream) {
-					snd_cs4231_overrange(chip);
-					snd_pcm_period_elapsed(chip->capture_substream);
-				}
-			}
-		}
-	} else {
-		if (status & CS4231_PLAYBACK_IRQ) {
-			if (chip->playback_substream)
-				snd_pcm_period_elapsed(chip->playback_substream);
-		}
-		if (status & CS4231_RECORD_IRQ) {
-			if (chip->capture_substream) {
-				snd_cs4231_overrange(chip);
-				snd_pcm_period_elapsed(chip->capture_substream);
-			}
-		}
-	}
-
-	spin_lock(&chip->reg_lock);
-	snd_cs4231_outm(chip, CS4231_IRQ_STATUS, ~CS4231_ALL_IRQS | ~status, 0);
-	spin_unlock(&chip->reg_lock);
-	return IRQ_HANDLED;
-}
-
-static snd_pcm_uframes_t snd_cs4231_playback_pointer(struct snd_pcm_substream *substream)
-{
-	struct snd_cs4231 *chip = snd_pcm_substream_chip(substream);
-	size_t ptr;
-
-	if (!(chip->image[CS4231_IFACE_CTRL] & CS4231_PLAYBACK_ENABLE))
-		return 0;
-	ptr = snd_dma_pointer(chip->dma1, chip->p_dma_size);
-	return bytes_to_frames(substream->runtime, ptr);
-}
-
-static snd_pcm_uframes_t snd_cs4231_capture_pointer(struct snd_pcm_substream *substream)
-{
-	struct snd_cs4231 *chip = snd_pcm_substream_chip(substream);
-	size_t ptr;
-	
-	if (!(chip->image[CS4231_IFACE_CTRL] & CS4231_RECORD_ENABLE))
-		return 0;
-	ptr = snd_dma_pointer(chip->dma2, chip->c_dma_size);
-	return bytes_to_frames(substream->runtime, ptr);
-}
-
-/*
-
- */
-
-static int snd_cs4231_probe(struct snd_cs4231 *chip)
-{
-	unsigned long flags;
-	int i, id, rev;
-	unsigned char *ptr;
-	unsigned int hw;
-
-#if 0
-	snd_cs4231_debug(chip);
-#endif
-	id = 0;
-	for (i = 0; i < 50; i++) {
-		mb();
-		if (cs4231_inb(chip, CS4231P(REGSEL)) & CS4231_INIT)
-			udelay(2000);
-		else {
-			spin_lock_irqsave(&chip->reg_lock, flags);
-			snd_cs4231_out(chip, CS4231_MISC_INFO, CS4231_MODE2);
-			id = snd_cs4231_in(chip, CS4231_MISC_INFO) & 0x0f;
-			spin_unlock_irqrestore(&chip->reg_lock, flags);
-			if (id == 0x0a)
-				break;	/* this is valid value */
-		}
-	}
-	snd_printdd("cs4231: port = 0x%lx, id = 0x%x\n", chip->port, id);
-	if (id != 0x0a)
-		return -ENODEV;	/* no valid device found */
-
-	if (((hw = chip->hardware) & CS4231_HW_TYPE_MASK) == CS4231_HW_DETECT) {
-		rev = snd_cs4231_in(chip, CS4231_VERSION) & 0xe7;
-		snd_printdd("CS4231: VERSION (I25) = 0x%x\n", rev);
-		if (rev == 0x80) {
-			unsigned char tmp = snd_cs4231_in(chip, 23);
-			snd_cs4231_out(chip, 23, ~tmp);
-			if (snd_cs4231_in(chip, 23) != tmp)
-				chip->hardware = CS4231_HW_AD1845;
-			else
-				chip->hardware = CS4231_HW_CS4231;
-		} else if (rev == 0xa0) {
-			chip->hardware = CS4231_HW_CS4231A;
-		} else if (rev == 0xa2) {
-			chip->hardware = CS4231_HW_CS4232;
-		} else if (rev == 0xb2) {
-			chip->hardware = CS4231_HW_CS4232A;
-		} else if (rev == 0x83) {
-			chip->hardware = CS4231_HW_CS4236;
-		} else if (rev == 0x03) {
-			chip->hardware = CS4231_HW_CS4236B;
-		} else {
-			snd_printk("unknown CS chip with version 0x%x\n", rev);
-			return -ENODEV;		/* unknown CS4231 chip? */
-		}
-	}
-	spin_lock_irqsave(&chip->reg_lock, flags);
-	cs4231_inb(chip, CS4231P(STATUS));	/* clear any pendings IRQ */
-	cs4231_outb(chip, CS4231P(STATUS), 0);
-	mb();
-	spin_unlock_irqrestore(&chip->reg_lock, flags);
-
-	chip->image[CS4231_MISC_INFO] = CS4231_MODE2;
-	switch (chip->hardware) {
-	case CS4231_HW_INTERWAVE:
-		chip->image[CS4231_MISC_INFO] = CS4231_IW_MODE3;
-		break;
-	case CS4231_HW_CS4235:
-	case CS4231_HW_CS4236B:
-	case CS4231_HW_CS4237B:
-	case CS4231_HW_CS4238B:
-	case CS4231_HW_CS4239:
-		if (hw == CS4231_HW_DETECT3)
-			chip->image[CS4231_MISC_INFO] = CS4231_4236_MODE3;
-		else
-			chip->hardware = CS4231_HW_CS4236;
-		break;
-	}
-
-	chip->image[CS4231_IFACE_CTRL] =
-	    (chip->image[CS4231_IFACE_CTRL] & ~CS4231_SINGLE_DMA) |
-	    (chip->single_dma ? CS4231_SINGLE_DMA : 0);
-	if (chip->hardware != CS4231_HW_OPTI93X) {
-		chip->image[CS4231_ALT_FEATURE_1] = 0x80;
-		chip->image[CS4231_ALT_FEATURE_2] =
-			chip->hardware == CS4231_HW_INTERWAVE ? 0xc2 : 0x01;
-	}
-	ptr = (unsigned char *) &chip->image;
-	snd_cs4231_mce_down(chip);
-	spin_lock_irqsave(&chip->reg_lock, flags);
-	for (i = 0; i < 32; i++)	/* ok.. fill all CS4231 registers */
-		snd_cs4231_out(chip, i, *ptr++);
-	spin_unlock_irqrestore(&chip->reg_lock, flags);
-	snd_cs4231_mce_up(chip);
-	snd_cs4231_mce_down(chip);
-
-	mdelay(2);
-
-	/* ok.. try check hardware version for CS4236+ chips */
-	if ((hw & CS4231_HW_TYPE_MASK) == CS4231_HW_DETECT) {
-		if (chip->hardware == CS4231_HW_CS4236B) {
-			rev = snd_cs4236_ext_in(chip, CS4236_VERSION);
-			snd_cs4236_ext_out(chip, CS4236_VERSION, 0xff);
-			id = snd_cs4236_ext_in(chip, CS4236_VERSION);
-			snd_cs4236_ext_out(chip, CS4236_VERSION, rev);
-			snd_printdd("CS4231: ext version; rev = 0x%x, id = 0x%x\n", rev, id);
-			if ((id & 0x1f) == 0x1d) {	/* CS4235 */
-				chip->hardware = CS4231_HW_CS4235;
-				switch (id >> 5) {
-				case 4:
-				case 5:
-				case 6:
-					break;
-				default:
-					snd_printk("unknown CS4235 chip (enhanced version = 0x%x)\n", id);
-				}
-			} else if ((id & 0x1f) == 0x0b) {	/* CS4236/B */
-				switch (id >> 5) {
-				case 4:
-				case 5:
-				case 6:
-				case 7:
-					chip->hardware = CS4231_HW_CS4236B;
-					break;
-				default:
-					snd_printk("unknown CS4236 chip (enhanced version = 0x%x)\n", id);
-				}
-			} else if ((id & 0x1f) == 0x08) {	/* CS4237B */
-				chip->hardware = CS4231_HW_CS4237B;
-				switch (id >> 5) {
-				case 4:
-				case 5:
-				case 6:
-				case 7:
-					break;
-				default:
-					snd_printk("unknown CS4237B chip (enhanced version = 0x%x)\n", id);
-				}
-			} else if ((id & 0x1f) == 0x09) {	/* CS4238B */
-				chip->hardware = CS4231_HW_CS4238B;
-				switch (id >> 5) {
-				case 5:
-				case 6:
-				case 7:
-					break;
-				default:
-					snd_printk("unknown CS4238B chip (enhanced version = 0x%x)\n", id);
-				}
-			} else if ((id & 0x1f) == 0x1e) {	/* CS4239 */
-				chip->hardware = CS4231_HW_CS4239;
-				switch (id >> 5) {
-				case 4:
-				case 5:
-				case 6:
-					break;
-				default:
-					snd_printk("unknown CS4239 chip (enhanced version = 0x%x)\n", id);
-				}
-			} else {
-				snd_printk("unknown CS4236/CS423xB chip (enhanced version = 0x%x)\n", id);
-			}
-		}
-	}
-	return 0;		/* all things are ok.. */
-}
-
-/*
-
- */
-
-static struct snd_pcm_hardware snd_cs4231_playback =
-{
-	.info =			(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
-				 SNDRV_PCM_INFO_MMAP_VALID |
-				 SNDRV_PCM_INFO_RESUME |
-				 SNDRV_PCM_INFO_SYNC_START),
-	.formats =		(SNDRV_PCM_FMTBIT_MU_LAW | SNDRV_PCM_FMTBIT_A_LAW | SNDRV_PCM_FMTBIT_IMA_ADPCM |
-				 SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE),
-	.rates =		SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_8000_48000,
-	.rate_min =		5510,
-	.rate_max =		48000,
-	.channels_min =		1,
-	.channels_max =		2,
-	.buffer_bytes_max =	(128*1024),
-	.period_bytes_min =	64,
-	.period_bytes_max =	(128*1024),
-	.periods_min =		1,
-	.periods_max =		1024,
-	.fifo_size =		0,
-};
-
-static struct snd_pcm_hardware snd_cs4231_capture =
-{
-	.info =			(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
-				 SNDRV_PCM_INFO_MMAP_VALID |
-				 SNDRV_PCM_INFO_RESUME |
-				 SNDRV_PCM_INFO_SYNC_START),
-	.formats =		(SNDRV_PCM_FMTBIT_MU_LAW | SNDRV_PCM_FMTBIT_A_LAW | SNDRV_PCM_FMTBIT_IMA_ADPCM |
-				 SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE),
-	.rates =		SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_8000_48000,
-	.rate_min =		5510,
-	.rate_max =		48000,
-	.channels_min =		1,
-	.channels_max =		2,
-	.buffer_bytes_max =	(128*1024),
-	.period_bytes_min =	64,
-	.period_bytes_max =	(128*1024),
-	.periods_min =		1,
-	.periods_max =		1024,
-	.fifo_size =		0,
-};
-
-/*
-
- */
-
-static int snd_cs4231_playback_open(struct snd_pcm_substream *substream)
-{
-	struct snd_cs4231 *chip = snd_pcm_substream_chip(substream);
-	struct snd_pcm_runtime *runtime = substream->runtime;
-	int err;
-
-	runtime->hw = snd_cs4231_playback;
-
-	/* hardware bug in InterWave chipset */
-	if (chip->hardware == CS4231_HW_INTERWAVE && chip->dma1 > 3)
-	    	runtime->hw.formats &= ~SNDRV_PCM_FMTBIT_MU_LAW;
-	
-	/* hardware limitation of cheap chips */
-	if (chip->hardware == CS4231_HW_CS4235 ||
-	    chip->hardware == CS4231_HW_CS4239)
-		runtime->hw.formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE;
-
-	snd_pcm_limit_isa_dma_size(chip->dma1, &runtime->hw.buffer_bytes_max);
-	snd_pcm_limit_isa_dma_size(chip->dma1, &runtime->hw.period_bytes_max);
-
-	if (chip->claim_dma) {
-		if ((err = chip->claim_dma(chip, chip->dma_private_data, chip->dma1)) < 0)
-			return err;
-	}
-
-	if ((err = snd_cs4231_open(chip, CS4231_MODE_PLAY)) < 0) {
-		if (chip->release_dma)
-			chip->release_dma(chip, chip->dma_private_data, chip->dma1);
-		snd_free_pages(runtime->dma_area, runtime->dma_bytes);
-		return err;
-	}
-	chip->playback_substream = substream;
-	snd_pcm_set_sync(substream);
-	chip->rate_constraint(runtime);
-	return 0;
-}
-
-static int snd_cs4231_capture_open(struct snd_pcm_substream *substream)
-{
-	struct snd_cs4231 *chip = snd_pcm_substream_chip(substream);
-	struct snd_pcm_runtime *runtime = substream->runtime;
-	int err;
-
-	runtime->hw = snd_cs4231_capture;
-
-	/* hardware limitation of cheap chips */
-	if (chip->hardware == CS4231_HW_CS4235 ||
-	    chip->hardware == CS4231_HW_CS4239)
-		runtime->hw.formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE;
-
-	snd_pcm_limit_isa_dma_size(chip->dma2, &runtime->hw.buffer_bytes_max);
-	snd_pcm_limit_isa_dma_size(chip->dma2, &runtime->hw.period_bytes_max);
-
-	if (chip->claim_dma) {
-		if ((err = chip->claim_dma(chip, chip->dma_private_data, chip->dma2)) < 0)
-			return err;
-	}
-
-	if ((err = snd_cs4231_open(chip, CS4231_MODE_RECORD)) < 0) {
-		if (chip->release_dma)
-			chip->release_dma(chip, chip->dma_private_data, chip->dma2);
-		snd_free_pages(runtime->dma_area, runtime->dma_bytes);
-		return err;
-	}
-	chip->capture_substream = substream;
-	snd_pcm_set_sync(substream);
-	chip->rate_constraint(runtime);
-	return 0;
-}
-
-static int snd_cs4231_playback_close(struct snd_pcm_substream *substream)
-{
-	struct snd_cs4231 *chip = snd_pcm_substream_chip(substream);
-
-	chip->playback_substream = NULL;
-	snd_cs4231_close(chip, CS4231_MODE_PLAY);
-	return 0;
-}
-
-static int snd_cs4231_capture_close(struct snd_pcm_substream *substream)
-{
-	struct snd_cs4231 *chip = snd_pcm_substream_chip(substream);
-
-	chip->capture_substream = NULL;
-	snd_cs4231_close(chip, CS4231_MODE_RECORD);
-	return 0;
-}
-
-#ifdef CONFIG_PM
-
-/* lowlevel suspend callback for CS4231 */
-static void snd_cs4231_suspend(struct snd_cs4231 *chip)
-{
-	int reg;
-	unsigned long flags;
-	
-	snd_pcm_suspend_all(chip->pcm);
-	spin_lock_irqsave(&chip->reg_lock, flags);
-	for (reg = 0; reg < 32; reg++)
-		chip->image[reg] = snd_cs4231_in(chip, reg);
-	spin_unlock_irqrestore(&chip->reg_lock, flags);
-}
-
-/* lowlevel resume callback for CS4231 */
-static void snd_cs4231_resume(struct snd_cs4231 *chip)
-{
-	int reg;
-	unsigned long flags;
-	/* int timeout; */
-	
-	snd_cs4231_mce_up(chip);
-	spin_lock_irqsave(&chip->reg_lock, flags);
-	for (reg = 0; reg < 32; reg++) {
-		switch (reg) {
-		case CS4231_VERSION:
-			break;
-		default:
-			snd_cs4231_out(chip, reg, chip->image[reg]);
-			break;
-		}
-	}
-	spin_unlock_irqrestore(&chip->reg_lock, flags);
-#if 1
-	snd_cs4231_mce_down(chip);
-#else
-	/* The following is a workaround to avoid freeze after resume on TP600E.
-	   This is the first half of copy of snd_cs4231_mce_down(), but doesn't
-	   include rescheduling.  -- iwai
-	   */
-	snd_cs4231_busy_wait(chip);
-	spin_lock_irqsave(&chip->reg_lock, flags);
-	chip->mce_bit &= ~CS4231_MCE;
-	timeout = cs4231_inb(chip, CS4231P(REGSEL));
-	cs4231_outb(chip, CS4231P(REGSEL), chip->mce_bit | (timeout & 0x1f));
-	spin_unlock_irqrestore(&chip->reg_lock, flags);
-	if (timeout == 0x80)
-		snd_printk("down [0x%lx]: serious init problem - codec still busy\n", chip->port);
-	if ((timeout & CS4231_MCE) == 0 ||
-	    !(chip->hardware & (CS4231_HW_CS4231_MASK | CS4231_HW_CS4232_MASK))) {
-		return;
-	}
-	snd_cs4231_busy_wait(chip);
-#endif
-}
-#endif /* CONFIG_PM */
-
-static int snd_cs4231_free(struct snd_cs4231 *chip)
-{
-	release_and_free_resource(chip->res_port);
-	release_and_free_resource(chip->res_cport);
-	if (chip->irq >= 0) {
-		disable_irq(chip->irq);
-		if (!(chip->hwshare & CS4231_HWSHARE_IRQ))
-			free_irq(chip->irq, (void *) chip);
-	}
-	if (!(chip->hwshare & CS4231_HWSHARE_DMA1) && chip->dma1 >= 0) {
-		snd_dma_disable(chip->dma1);
-		free_dma(chip->dma1);
-	}
-	if (!(chip->hwshare & CS4231_HWSHARE_DMA2) && chip->dma2 >= 0 && chip->dma2 != chip->dma1) {
-		snd_dma_disable(chip->dma2);
-		free_dma(chip->dma2);
-	}
-	if (chip->timer)
-		snd_device_free(chip->card, chip->timer);
-	kfree(chip);
-	return 0;
-}
-
-static int snd_cs4231_dev_free(struct snd_device *device)
-{
-	struct snd_cs4231 *chip = device->device_data;
-	return snd_cs4231_free(chip);	
-}
-
-const char *snd_cs4231_chip_id(struct snd_cs4231 *chip)
-{
-	switch (chip->hardware) {
-	case CS4231_HW_CS4231:	return "CS4231";
-	case CS4231_HW_CS4231A: return "CS4231A";
-	case CS4231_HW_CS4232:	return "CS4232";
-	case CS4231_HW_CS4232A:	return "CS4232A";
-	case CS4231_HW_CS4235:	return "CS4235";
-	case CS4231_HW_CS4236:  return "CS4236";
-	case CS4231_HW_CS4236B: return "CS4236B";
-	case CS4231_HW_CS4237B: return "CS4237B";
-	case CS4231_HW_CS4238B: return "CS4238B";
-	case CS4231_HW_CS4239:	return "CS4239";
-	case CS4231_HW_INTERWAVE: return "AMD InterWave";
-	case CS4231_HW_OPL3SA2: return chip->card->shortname;
-	case CS4231_HW_AD1845: return "AD1845";
-	case CS4231_HW_OPTI93X: return "OPTi 93x";
-	default: return "???";
-	}
-}
-
-static int snd_cs4231_new(struct snd_card *card,
-			  unsigned short hardware,
-			  unsigned short hwshare,
-			  struct snd_cs4231 ** rchip)
-{
-	struct snd_cs4231 *chip;
-
-	*rchip = NULL;
-	chip = kzalloc(sizeof(*chip), GFP_KERNEL);
-	if (chip == NULL)
-		return -ENOMEM;
-	chip->hardware = hardware;
-	chip->hwshare = hwshare;
-
-	spin_lock_init(&chip->reg_lock);
-	mutex_init(&chip->mce_mutex);
-	mutex_init(&chip->open_mutex);
-	chip->card = card;
-	chip->rate_constraint = snd_cs4231_xrate;
-	chip->set_playback_format = snd_cs4231_playback_format;
-	chip->set_capture_format = snd_cs4231_capture_format;
-	if (chip->hardware == CS4231_HW_OPTI93X)
-		memcpy(&chip->image, &snd_opti93x_original_image,
-		       sizeof(snd_opti93x_original_image));
-	else
-		memcpy(&chip->image, &snd_cs4231_original_image,
-		       sizeof(snd_cs4231_original_image));
-
-        *rchip = chip;
-        return 0;
-}
-
-int snd_cs4231_create(struct snd_card *card,
-	              unsigned long port,
-	              unsigned long cport,
-		      int irq, int dma1, int dma2,
-		      unsigned short hardware,
-		      unsigned short hwshare,
-		      struct snd_cs4231 ** rchip)
-{
-	static struct snd_device_ops ops = {
-		.dev_free =	snd_cs4231_dev_free,
-	};
-	struct snd_cs4231 *chip;
-	int err;
-
-	err = snd_cs4231_new(card, hardware, hwshare, &chip);
-	if (err < 0)
-		return err;
-	
-	chip->irq = -1;
-	chip->dma1 = -1;
-	chip->dma2 = -1;
-
-	if ((chip->res_port = request_region(port, 4, "CS4231")) == NULL) {
-		snd_printk(KERN_ERR "cs4231: can't grab port 0x%lx\n", port);
-		snd_cs4231_free(chip);
-		return -EBUSY;
-	}
-	chip->port = port;
-	if ((long)cport >= 0 && (chip->res_cport = request_region(cport, 8, "CS4232 Control")) == NULL) {
-		snd_printk(KERN_ERR "cs4231: can't grab control port 0x%lx\n", cport);
-		snd_cs4231_free(chip);
-		return -ENODEV;
-	}
-	chip->cport = cport;
-	if (!(hwshare & CS4231_HWSHARE_IRQ) && request_irq(irq, snd_cs4231_interrupt, IRQF_DISABLED, "CS4231", (void *) chip)) {
-		snd_printk(KERN_ERR "cs4231: can't grab IRQ %d\n", irq);
-		snd_cs4231_free(chip);
-		return -EBUSY;
-	}
-	chip->irq = irq;
-	if (!(hwshare & CS4231_HWSHARE_DMA1) && request_dma(dma1, "CS4231 - 1")) {
-		snd_printk(KERN_ERR "cs4231: can't grab DMA1 %d\n", dma1);
-		snd_cs4231_free(chip);
-		return -EBUSY;
-	}
-	chip->dma1 = dma1;
-	if (!(hwshare & CS4231_HWSHARE_DMA2) && dma1 != dma2 && dma2 >= 0 && request_dma(dma2, "CS4231 - 2")) {
-		snd_printk(KERN_ERR "cs4231: can't grab DMA2 %d\n", dma2);
-		snd_cs4231_free(chip);
-		return -EBUSY;
-	}
-	if (dma1 == dma2 || dma2 < 0) {
-		chip->single_dma = 1;
-		chip->dma2 = chip->dma1;
-	} else
-		chip->dma2 = dma2;
-
-	/* global setup */
-	if (snd_cs4231_probe(chip) < 0) {
-		snd_cs4231_free(chip);
-		return -ENODEV;
-	}
-	snd_cs4231_init(chip);
-
-#if 0
-	if (chip->hardware & CS4231_HW_CS4232_MASK) {
-		if (chip->res_cport == NULL)
-			snd_printk("CS4232 control port features are not accessible\n");
-	}
-#endif
-
-	/* Register device */
-	if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) {
-		snd_cs4231_free(chip);
-		return err;
-	}
-
-#ifdef CONFIG_PM
-	/* Power Management */
-	chip->suspend = snd_cs4231_suspend;
-	chip->resume = snd_cs4231_resume;
-#endif
-
-	*rchip = chip;
-	return 0;
-}
-
-static struct snd_pcm_ops snd_cs4231_playback_ops = {
-	.open =		snd_cs4231_playback_open,
-	.close =	snd_cs4231_playback_close,
-	.ioctl =	snd_pcm_lib_ioctl,
-	.hw_params =	snd_cs4231_playback_hw_params,
-	.hw_free =	snd_cs4231_playback_hw_free,
-	.prepare =	snd_cs4231_playback_prepare,
-	.trigger =	snd_cs4231_trigger,
-	.pointer =	snd_cs4231_playback_pointer,
-};
-
-static struct snd_pcm_ops snd_cs4231_capture_ops = {
-	.open =		snd_cs4231_capture_open,
-	.close =	snd_cs4231_capture_close,
-	.ioctl =	snd_pcm_lib_ioctl,
-	.hw_params =	snd_cs4231_capture_hw_params,
-	.hw_free =	snd_cs4231_capture_hw_free,
-	.prepare =	snd_cs4231_capture_prepare,
-	.trigger =	snd_cs4231_trigger,
-	.pointer =	snd_cs4231_capture_pointer,
-};
-
-int snd_cs4231_pcm(struct snd_cs4231 *chip, int device, struct snd_pcm **rpcm)
-{
-	struct snd_pcm *pcm;
-	int err;
-
-	if ((err = snd_pcm_new(chip->card, "CS4231", device, 1, 1, &pcm)) < 0)
-		return err;
-
-	spin_lock_init(&chip->reg_lock);
-	mutex_init(&chip->mce_mutex);
-	mutex_init(&chip->open_mutex);
-
-	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_cs4231_playback_ops);
-	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_cs4231_capture_ops);
-	
-	/* global setup */
-	pcm->private_data = chip;
-	pcm->info_flags = 0;
-	if (chip->single_dma)
-		pcm->info_flags |= SNDRV_PCM_INFO_HALF_DUPLEX;
-	if (chip->hardware != CS4231_HW_INTERWAVE)
-		pcm->info_flags |= SNDRV_PCM_INFO_JOINT_DUPLEX;
-	strcpy(pcm->name, snd_cs4231_chip_id(chip));
-
-	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
-					      snd_dma_isa_data(),
-					      64*1024, chip->dma1 > 3 || chip->dma2 > 3 ? 128*1024 : 64*1024);
-
-	chip->pcm = pcm;
-	if (rpcm)
-		*rpcm = pcm;
-	return 0;
-}
-
-static void snd_cs4231_timer_free(struct snd_timer *timer)
-{
-	struct snd_cs4231 *chip = timer->private_data;
-	chip->timer = NULL;
-}
-
-int snd_cs4231_timer(struct snd_cs4231 *chip, int device, struct snd_timer **rtimer)
-{
-	struct snd_timer *timer;
-	struct snd_timer_id tid;
-	int err;
-
-	/* Timer initialization */
-	tid.dev_class = SNDRV_TIMER_CLASS_CARD;
-	tid.dev_sclass = SNDRV_TIMER_SCLASS_NONE;
-	tid.card = chip->card->number;
-	tid.device = device;
-	tid.subdevice = 0;
-	if ((err = snd_timer_new(chip->card, "CS4231", &tid, &timer)) < 0)
-		return err;
-	strcpy(timer->name, snd_cs4231_chip_id(chip));
-	timer->private_data = chip;
-	timer->private_free = snd_cs4231_timer_free;
-	timer->hw = snd_cs4231_timer_table;
-	chip->timer = timer;
-	if (rtimer)
-		*rtimer = timer;
-	return 0;
-}
-	
-/*
- *  MIXER part
- */
-
-static int snd_cs4231_info_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
-{
-	static char *texts[4] = {
-		"Line", "Aux", "Mic", "Mix"
-	};
-	static char *opl3sa_texts[4] = {
-		"Line", "CD", "Mic", "Mix"
-	};
-	static char *gusmax_texts[4] = {
-		"Line", "Synth", "Mic", "Mix"
-	};
-	char **ptexts = texts;
-	struct snd_cs4231 *chip = snd_kcontrol_chip(kcontrol);
-
-	snd_assert(chip->card != NULL, return -EINVAL);
-	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
-	uinfo->count = 2;
-	uinfo->value.enumerated.items = 4;
-	if (uinfo->value.enumerated.item > 3)
-		uinfo->value.enumerated.item = 3;
-	if (!strcmp(chip->card->driver, "GUS MAX"))
-		ptexts = gusmax_texts;
-	switch (chip->hardware) {
-	case CS4231_HW_INTERWAVE: ptexts = gusmax_texts; break;
-	case CS4231_HW_OPL3SA2: ptexts = opl3sa_texts; break;
-	}
-	strcpy(uinfo->value.enumerated.name, ptexts[uinfo->value.enumerated.item]);
-	return 0;
-}
-
-static int snd_cs4231_get_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
-{
-	struct snd_cs4231 *chip = snd_kcontrol_chip(kcontrol);
-	unsigned long flags;
-	
-	spin_lock_irqsave(&chip->reg_lock, flags);
-	ucontrol->value.enumerated.item[0] = (chip->image[CS4231_LEFT_INPUT] & CS4231_MIXS_ALL) >> 6;
-	ucontrol->value.enumerated.item[1] = (chip->image[CS4231_RIGHT_INPUT] & CS4231_MIXS_ALL) >> 6;
-	spin_unlock_irqrestore(&chip->reg_lock, flags);
-	return 0;
-}
-
-static int snd_cs4231_put_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
-{
-	struct snd_cs4231 *chip = snd_kcontrol_chip(kcontrol);
-	unsigned long flags;
-	unsigned short left, right;
-	int change;
-	
-	if (ucontrol->value.enumerated.item[0] > 3 ||
-	    ucontrol->value.enumerated.item[1] > 3)
-		return -EINVAL;
-	left = ucontrol->value.enumerated.item[0] << 6;
-	right = ucontrol->value.enumerated.item[1] << 6;
-	spin_lock_irqsave(&chip->reg_lock, flags);
-	left = (chip->image[CS4231_LEFT_INPUT] & ~CS4231_MIXS_ALL) | left;
-	right = (chip->image[CS4231_RIGHT_INPUT] & ~CS4231_MIXS_ALL) | right;
-	change = left != chip->image[CS4231_LEFT_INPUT] ||
-	         right != chip->image[CS4231_RIGHT_INPUT];
-	snd_cs4231_out(chip, CS4231_LEFT_INPUT, left);
-	snd_cs4231_out(chip, CS4231_RIGHT_INPUT, right);
-	spin_unlock_irqrestore(&chip->reg_lock, flags);
-	return change;
-}
-
-int snd_cs4231_info_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
-{
-	int mask = (kcontrol->private_value >> 16) & 0xff;
-
-	uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER;
-	uinfo->count = 1;
-	uinfo->value.integer.min = 0;
-	uinfo->value.integer.max = mask;
-	return 0;
-}
-
-int snd_cs4231_get_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
-{
-	struct snd_cs4231 *chip = snd_kcontrol_chip(kcontrol);
-	unsigned long flags;
-	int reg = kcontrol->private_value & 0xff;
-	int shift = (kcontrol->private_value >> 8) & 0xff;
-	int mask = (kcontrol->private_value >> 16) & 0xff;
-	int invert = (kcontrol->private_value >> 24) & 0xff;
-	
-	spin_lock_irqsave(&chip->reg_lock, flags);
-	ucontrol->value.integer.value[0] = (chip->image[reg] >> shift) & mask;
-	spin_unlock_irqrestore(&chip->reg_lock, flags);
-	if (invert)
-		ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0];
-	return 0;
-}
-
-int snd_cs4231_put_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
-{
-	struct snd_cs4231 *chip = snd_kcontrol_chip(kcontrol);
-	unsigned long flags;
-	int reg = kcontrol->private_value & 0xff;
-	int shift = (kcontrol->private_value >> 8) & 0xff;
-	int mask = (kcontrol->private_value >> 16) & 0xff;
-	int invert = (kcontrol->private_value >> 24) & 0xff;
-	int change;
-	unsigned short val;
-	
-	val = (ucontrol->value.integer.value[0] & mask);
-	if (invert)
-		val = mask - val;
-	val <<= shift;
-	spin_lock_irqsave(&chip->reg_lock, flags);
-	val = (chip->image[reg] & ~(mask << shift)) | val;
-	change = val != chip->image[reg];
-	snd_cs4231_out(chip, reg, val);
-	spin_unlock_irqrestore(&chip->reg_lock, flags);
-	return change;
-}
-
-int snd_cs4231_info_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
-{
-	int mask = (kcontrol->private_value >> 24) & 0xff;
-
-	uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER;
-	uinfo->count = 2;
-	uinfo->value.integer.min = 0;
-	uinfo->value.integer.max = mask;
-	return 0;
-}
-
-int snd_cs4231_get_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
-{
-	struct snd_cs4231 *chip = snd_kcontrol_chip(kcontrol);
-	unsigned long flags;
-	int left_reg = kcontrol->private_value & 0xff;
-	int right_reg = (kcontrol->private_value >> 8) & 0xff;
-	int shift_left = (kcontrol->private_value >> 16) & 0x07;
-	int shift_right = (kcontrol->private_value >> 19) & 0x07;
-	int mask = (kcontrol->private_value >> 24) & 0xff;
-	int invert = (kcontrol->private_value >> 22) & 1;
-	
-	spin_lock_irqsave(&chip->reg_lock, flags);
-	ucontrol->value.integer.value[0] = (chip->image[left_reg] >> shift_left) & mask;
-	ucontrol->value.integer.value[1] = (chip->image[right_reg] >> shift_right) & mask;
-	spin_unlock_irqrestore(&chip->reg_lock, flags);
-	if (invert) {
-		ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0];
-		ucontrol->value.integer.value[1] = mask - ucontrol->value.integer.value[1];
-	}
-	return 0;
-}
-
-int snd_cs4231_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
-{
-	struct snd_cs4231 *chip = snd_kcontrol_chip(kcontrol);
-	unsigned long flags;
-	int left_reg = kcontrol->private_value & 0xff;
-	int right_reg = (kcontrol->private_value >> 8) & 0xff;
-	int shift_left = (kcontrol->private_value >> 16) & 0x07;
-	int shift_right = (kcontrol->private_value >> 19) & 0x07;
-	int mask = (kcontrol->private_value >> 24) & 0xff;
-	int invert = (kcontrol->private_value >> 22) & 1;
-	int change;
-	unsigned short val1, val2;
-	
-	val1 = ucontrol->value.integer.value[0] & mask;
-	val2 = ucontrol->value.integer.value[1] & mask;
-	if (invert) {
-		val1 = mask - val1;
-		val2 = mask - val2;
-	}
-	val1 <<= shift_left;
-	val2 <<= shift_right;
-	spin_lock_irqsave(&chip->reg_lock, flags);
-	val1 = (chip->image[left_reg] & ~(mask << shift_left)) | val1;
-	val2 = (chip->image[right_reg] & ~(mask << shift_right)) | val2;
-	change = val1 != chip->image[left_reg] || val2 != chip->image[right_reg];
-	snd_cs4231_out(chip, left_reg, val1);
-	snd_cs4231_out(chip, right_reg, val2);
-	spin_unlock_irqrestore(&chip->reg_lock, flags);
-	return change;
-}
-
-static struct snd_kcontrol_new snd_cs4231_controls[] = {
-CS4231_DOUBLE("PCM Playback Switch", 0, CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 7, 7, 1, 1),
-CS4231_DOUBLE("PCM Playback Volume", 0, CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 0, 0, 63, 1),
-CS4231_DOUBLE("Line Playback Switch", 0, CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 7, 7, 1, 1),
-CS4231_DOUBLE("Line Playback Volume", 0, CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 0, 0, 31, 1),
-CS4231_DOUBLE("Aux Playback Switch", 0, CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 7, 7, 1, 1),
-CS4231_DOUBLE("Aux Playback Volume", 0, CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 0, 0, 31, 1),
-CS4231_DOUBLE("Aux Playback Switch", 1, CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 7, 7, 1, 1),
-CS4231_DOUBLE("Aux Playback Volume", 1, CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 0, 0, 31, 1),
-CS4231_SINGLE("Mono Playback Switch", 0, CS4231_MONO_CTRL, 7, 1, 1),
-CS4231_SINGLE("Mono Playback Volume", 0, CS4231_MONO_CTRL, 0, 15, 1),
-CS4231_SINGLE("Mono Output Playback Switch", 0, CS4231_MONO_CTRL, 6, 1, 1),
-CS4231_SINGLE("Mono Output Playback Bypass", 0, CS4231_MONO_CTRL, 5, 1, 0),
-CS4231_DOUBLE("Capture Volume", 0, CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 0, 0, 15, 0),
-{
-	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-	.name = "Capture Source",
-	.info = snd_cs4231_info_mux,
-	.get = snd_cs4231_get_mux,
-	.put = snd_cs4231_put_mux,
-},
-CS4231_DOUBLE("Mic Boost", 0, CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 5, 5, 1, 0),
-CS4231_SINGLE("Loopback Capture Switch", 0, CS4231_LOOPBACK, 0, 1, 0),
-CS4231_SINGLE("Loopback Capture Volume", 0, CS4231_LOOPBACK, 2, 63, 1)
-};
-                                        
-static struct snd_kcontrol_new snd_opti93x_controls[] = {
-CS4231_DOUBLE("Master Playback Switch", 0,
-	      OPTi93X_OUT_LEFT, OPTi93X_OUT_RIGHT, 7, 7, 1, 1),
-CS4231_DOUBLE("Master Playback Volume", 0,
-	      OPTi93X_OUT_LEFT, OPTi93X_OUT_RIGHT, 1, 1, 31, 1),
-CS4231_DOUBLE("PCM Playback Switch", 0,
-	      CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 7, 7, 1, 1),
-CS4231_DOUBLE("PCM Playback Volume", 0,
-	      CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 0, 0, 31, 1),
-CS4231_DOUBLE("FM Playback Switch", 0,
-	      CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 7, 7, 1, 1),
-CS4231_DOUBLE("FM Playback Volume", 0,
-	      CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 1, 1, 15, 1),
-CS4231_DOUBLE("Line Playback Switch", 0,
-	      CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 7, 7, 1, 1),
-CS4231_DOUBLE("Line Playback Volume", 0,
-	      CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 0, 0, 15, 1),
-CS4231_DOUBLE("Mic Playback Switch", 0,
-	      OPTi93X_MIC_LEFT_INPUT, OPTi93X_MIC_RIGHT_INPUT, 7, 7, 1, 1),
-CS4231_DOUBLE("Mic Playback Volume", 0,
-	      OPTi93X_MIC_LEFT_INPUT, OPTi93X_MIC_RIGHT_INPUT, 1, 1, 15, 1),
-CS4231_DOUBLE("Mic Boost", 0,
-	      CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 5, 5, 1, 0),
-CS4231_DOUBLE("CD Playback Switch", 0,
-	      CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 7, 7, 1, 1),
-CS4231_DOUBLE("CD Playback Volume", 0,
-	      CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 1, 1, 15, 1),
-CS4231_DOUBLE("Aux Playback Switch", 0,
-	      OPTi931_AUX_LEFT_INPUT, OPTi931_AUX_RIGHT_INPUT, 7, 7, 1, 1),
-CS4231_DOUBLE("Aux Playback Volume", 0,
-	      OPTi931_AUX_LEFT_INPUT, OPTi931_AUX_RIGHT_INPUT, 1, 1, 15, 1),
-CS4231_DOUBLE("Capture Volume", 0,
-	      CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 0, 0, 15, 0),
-{
-	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-	.name = "Capture Source",
-	.info = snd_cs4231_info_mux,
-	.get = snd_cs4231_get_mux,
-	.put = snd_cs4231_put_mux,
-}
-};
-
-int snd_cs4231_mixer(struct snd_cs4231 *chip)
-{
-	struct snd_card *card;
-	unsigned int idx;
-	int err;
-
-	snd_assert(chip != NULL && chip->pcm != NULL, return -EINVAL);
-
-	card = chip->card;
-
-	strcpy(card->mixername, chip->pcm->name);
-
-	if (chip->hardware == CS4231_HW_OPTI93X)
-		for (idx = 0; idx < ARRAY_SIZE(snd_opti93x_controls); idx++) {
-			err = snd_ctl_add(card,
-					snd_ctl_new1(&snd_opti93x_controls[idx],
-						     chip));
-			if (err < 0)
-				return err;
-		}
-	else
-		for (idx = 0; idx < ARRAY_SIZE(snd_cs4231_controls); idx++) {
-			err = snd_ctl_add(card,
-					snd_ctl_new1(&snd_cs4231_controls[idx],
-						     chip));
-			if (err < 0)
-				return err;
-		}
-	return 0;
-}
-
-EXPORT_SYMBOL(snd_cs4231_out);
-EXPORT_SYMBOL(snd_cs4231_in);
-EXPORT_SYMBOL(snd_cs4236_ext_out);
-EXPORT_SYMBOL(snd_cs4236_ext_in);
-EXPORT_SYMBOL(snd_cs4231_mce_up);
-EXPORT_SYMBOL(snd_cs4231_mce_down);
-EXPORT_SYMBOL(snd_cs4231_overrange);
-EXPORT_SYMBOL(snd_cs4231_interrupt);
-EXPORT_SYMBOL(snd_cs4231_chip_id);
-EXPORT_SYMBOL(snd_cs4231_create);
-EXPORT_SYMBOL(snd_cs4231_pcm);
-EXPORT_SYMBOL(snd_cs4231_mixer);
-EXPORT_SYMBOL(snd_cs4231_timer);
-EXPORT_SYMBOL(snd_cs4231_info_single);
-EXPORT_SYMBOL(snd_cs4231_get_single);
-EXPORT_SYMBOL(snd_cs4231_put_single);
-EXPORT_SYMBOL(snd_cs4231_info_double);
-EXPORT_SYMBOL(snd_cs4231_get_double);
-EXPORT_SYMBOL(snd_cs4231_put_double);
-
-/*
- *  INIT part
- */
-
-static int __init alsa_cs4231_init(void)
-{
-	return 0;
-}
-
-static void __exit alsa_cs4231_exit(void)
-{
-}
-
-module_init(alsa_cs4231_init)
-module_exit(alsa_cs4231_exit)
diff --git a/sound/isa/cs423x/cs4236.c b/sound/isa/cs423x/cs4236.c
index 4d4b8dd..91f9c15 100644
--- a/sound/isa/cs423x/cs4236.c
+++ b/sound/isa/cs423x/cs4236.c
@@ -26,7 +26,7 @@
 #include <linux/pnp.h>
 #include <linux/moduleparam.h>
 #include <sound/core.h>
-#include <sound/cs4231.h>
+#include <sound/wss.h>
 #include <sound/mpu401.h>
 #include <sound/opl3.h>
 #include <sound/initval.h>
@@ -134,7 +134,7 @@
 #endif /* CONFIG_PNP */
 
 struct snd_card_cs4236 {
-	struct snd_cs4231 *chip;
+	struct snd_wss *chip;
 	struct resource *res_sb_port;
 #ifdef CONFIG_PNP
 	struct pnp_dev *wss;
@@ -239,6 +239,8 @@
 	{ .id = "CSC9836", .devs = { { "CSC0000" }, { "CSC0010" }, { "CSC0003" } } },
 	/* Gallant SC-70P */
 	{ .id = "CSC9837", .devs = { { "CSC0000" }, { "CSC0010" }, { "CSC0003" } } },
+	/* Techmakers MF-4236PW */
+	{ .id = "CSCa736", .devs = { { "CSC0000" }, { "CSC0010" }, { "CSC0003" } } },
 	/* TerraTec AudioSystem EWS64XL - CS4236B */
 	{ .id = "CSCa836", .devs = { { "CSCa800" }, { "CSCa810" }, { "CSCa803" } } },
 	/* TerraTec AudioSystem EWS64XL - CS4236B */
@@ -396,7 +398,7 @@
 {
 	struct snd_card_cs4236 *acard;
 	struct snd_pcm *pcm;
-	struct snd_cs4231 *chip;
+	struct snd_wss *chip;
 	struct snd_opl3 *opl3;
 	int err;
 
@@ -408,41 +410,37 @@
 		}
 
 #ifdef CS4232
-	if ((err = snd_cs4231_create(card,
-				     port[dev],
-				     cport[dev],
-				     irq[dev],
-				     dma1[dev],
-				     dma2[dev],
-				     CS4231_HW_DETECT,
-				     0,
-				     &chip)) < 0)
+	err = snd_wss_create(card, port[dev], cport[dev],
+			     irq[dev],
+			     dma1[dev], dma2[dev],
+			     WSS_HW_DETECT, 0, &chip);
+	if (err < 0)
 		return err;
 	acard->chip = chip;
 
-	if ((err = snd_cs4231_pcm(chip, 0, &pcm)) < 0)
+	err = snd_wss_pcm(chip, 0, &pcm);
+	if (err < 0)
 		return err;
 
-	if ((err = snd_cs4231_mixer(chip)) < 0)
+	err = snd_wss_mixer(chip);
+	if (err < 0)
 		return err;
 
 #else /* CS4236 */
-	if ((err = snd_cs4236_create(card,
-				     port[dev],
-				     cport[dev],
-				     irq[dev],
-				     dma1[dev],
-				     dma2[dev],
-				     CS4231_HW_DETECT,
-				     0,
-				     &chip)) < 0)
+	err = snd_cs4236_create(card,
+				port[dev], cport[dev],
+				irq[dev], dma1[dev], dma2[dev],
+				WSS_HW_DETECT, 0, &chip);
+	if (err < 0)
 		return err;
 	acard->chip = chip;
 
-	if ((err = snd_cs4236_pcm(chip, 0, &pcm)) < 0)
+	err = snd_cs4236_pcm(chip, 0, &pcm);
+	if (err < 0)
 		return err;
 
-	if ((err = snd_cs4236_mixer(chip)) < 0)
+	err = snd_cs4236_mixer(chip);
+	if (err < 0)
 		return err;
 #endif
 	strcpy(card->driver, pcm->name);
@@ -455,7 +453,8 @@
 	if (dma2[dev] >= 0)
 		sprintf(card->longname + strlen(card->longname), "&%d", dma2[dev]);
 
-	if ((err = snd_cs4231_timer(chip, 0, NULL)) < 0)
+	err = snd_wss_timer(chip, 0, NULL);
+	if (err < 0)
 		return err;
 
 	if (fm_port[dev] > 0 && fm_port[dev] != SNDRV_AUTO_PORT) {
diff --git a/sound/isa/cs423x/cs4236_lib.c b/sound/isa/cs423x/cs4236_lib.c
index de71910..6a85fdc 100644
--- a/sound/isa/cs423x/cs4236_lib.c
+++ b/sound/isa/cs423x/cs4236_lib.c
@@ -85,7 +85,7 @@
 #include <linux/time.h>
 #include <linux/wait.h>
 #include <sound/core.h>
-#include <sound/cs4231.h>
+#include <sound/wss.h>
 #include <sound/asoundef.h>
 
 MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
@@ -121,13 +121,14 @@
  *
  */
 
-static void snd_cs4236_ctrl_out(struct snd_cs4231 *chip, unsigned char reg, unsigned char val)
+static void snd_cs4236_ctrl_out(struct snd_wss *chip,
+				unsigned char reg, unsigned char val)
 {
 	outb(reg, chip->cport + 3);
 	outb(chip->cimage[reg] = val, chip->cport + 4);
 }
 
-static unsigned char snd_cs4236_ctrl_in(struct snd_cs4231 *chip, unsigned char reg)
+static unsigned char snd_cs4236_ctrl_in(struct snd_wss *chip, unsigned char reg)
 {
 	outb(reg, chip->cport + 3);
 	return inb(chip->cport + 4);
@@ -180,44 +181,52 @@
 	}
 }
 
-static void snd_cs4236_playback_format(struct snd_cs4231 *chip, struct snd_pcm_hw_params *params, unsigned char pdfr)
+static void snd_cs4236_playback_format(struct snd_wss *chip,
+				       struct snd_pcm_hw_params *params,
+				       unsigned char pdfr)
 {
 	unsigned long flags;
 	unsigned char rate = divisor_to_rate_register(params->rate_den);
 	
 	spin_lock_irqsave(&chip->reg_lock, flags);
 	/* set fast playback format change and clean playback FIFO */
-	snd_cs4231_out(chip, CS4231_ALT_FEATURE_1, chip->image[CS4231_ALT_FEATURE_1] | 0x10);
-	snd_cs4231_out(chip, CS4231_PLAYBK_FORMAT, pdfr & 0xf0);
-	snd_cs4231_out(chip, CS4231_ALT_FEATURE_1, chip->image[CS4231_ALT_FEATURE_1] & ~0x10);
+	snd_wss_out(chip, CS4231_ALT_FEATURE_1,
+		    chip->image[CS4231_ALT_FEATURE_1] | 0x10);
+	snd_wss_out(chip, CS4231_PLAYBK_FORMAT, pdfr & 0xf0);
+	snd_wss_out(chip, CS4231_ALT_FEATURE_1,
+		    chip->image[CS4231_ALT_FEATURE_1] & ~0x10);
 	snd_cs4236_ext_out(chip, CS4236_DAC_RATE, rate);
 	spin_unlock_irqrestore(&chip->reg_lock, flags);
 }
 
-static void snd_cs4236_capture_format(struct snd_cs4231 *chip, struct snd_pcm_hw_params *params, unsigned char cdfr)
+static void snd_cs4236_capture_format(struct snd_wss *chip,
+				      struct snd_pcm_hw_params *params,
+				      unsigned char cdfr)
 {
 	unsigned long flags;
 	unsigned char rate = divisor_to_rate_register(params->rate_den);
 	
 	spin_lock_irqsave(&chip->reg_lock, flags);
 	/* set fast capture format change and clean capture FIFO */
-	snd_cs4231_out(chip, CS4231_ALT_FEATURE_1, chip->image[CS4231_ALT_FEATURE_1] | 0x20);
-	snd_cs4231_out(chip, CS4231_REC_FORMAT, cdfr & 0xf0);
-	snd_cs4231_out(chip, CS4231_ALT_FEATURE_1, chip->image[CS4231_ALT_FEATURE_1] & ~0x20);
+	snd_wss_out(chip, CS4231_ALT_FEATURE_1,
+		    chip->image[CS4231_ALT_FEATURE_1] | 0x20);
+	snd_wss_out(chip, CS4231_REC_FORMAT, cdfr & 0xf0);
+	snd_wss_out(chip, CS4231_ALT_FEATURE_1,
+		    chip->image[CS4231_ALT_FEATURE_1] & ~0x20);
 	snd_cs4236_ext_out(chip, CS4236_ADC_RATE, rate);
 	spin_unlock_irqrestore(&chip->reg_lock, flags);
 }
 
 #ifdef CONFIG_PM
 
-static void snd_cs4236_suspend(struct snd_cs4231 *chip)
+static void snd_cs4236_suspend(struct snd_wss *chip)
 {
 	int reg;
 	unsigned long flags;
 	
 	spin_lock_irqsave(&chip->reg_lock, flags);
 	for (reg = 0; reg < 32; reg++)
-		chip->image[reg] = snd_cs4231_in(chip, reg);
+		chip->image[reg] = snd_wss_in(chip, reg);
 	for (reg = 0; reg < 18; reg++)
 		chip->eimage[reg] = snd_cs4236_ext_in(chip, CS4236_I23VAL(reg));
 	for (reg = 2; reg < 9; reg++)
@@ -225,12 +234,12 @@
 	spin_unlock_irqrestore(&chip->reg_lock, flags);
 }
 
-static void snd_cs4236_resume(struct snd_cs4231 *chip)
+static void snd_cs4236_resume(struct snd_wss *chip)
 {
 	int reg;
 	unsigned long flags;
 	
-	snd_cs4231_mce_up(chip);
+	snd_wss_mce_up(chip);
 	spin_lock_irqsave(&chip->reg_lock, flags);
 	for (reg = 0; reg < 32; reg++) {
 		switch (reg) {
@@ -240,7 +249,7 @@
 		case 29:	/* why? CS4235 - master right */
 			break;
 		default:
-			snd_cs4231_out(chip, reg, chip->image[reg]);
+			snd_wss_out(chip, reg, chip->image[reg]);
 			break;
 		}
 	}
@@ -255,7 +264,7 @@
 		}
 	}
 	spin_unlock_irqrestore(&chip->reg_lock, flags);
-	snd_cs4231_mce_down(chip);
+	snd_wss_mce_down(chip);
 }
 
 #endif /* CONFIG_PM */
@@ -266,24 +275,26 @@
 		      int irq, int dma1, int dma2,
 		      unsigned short hardware,
 		      unsigned short hwshare,
-		      struct snd_cs4231 ** rchip)
+		      struct snd_wss **rchip)
 {
-	struct snd_cs4231 *chip;
+	struct snd_wss *chip;
 	unsigned char ver1, ver2;
 	unsigned int reg;
 	int err;
 
 	*rchip = NULL;
-	if (hardware == CS4231_HW_DETECT)
-		hardware = CS4231_HW_DETECT3;
+	if (hardware == WSS_HW_DETECT)
+		hardware = WSS_HW_DETECT3;
 	if (cport < 0x100) {
 		snd_printk("please, specify control port for CS4236+ chips\n");
 		return -ENODEV;
 	}
-	if ((err = snd_cs4231_create(card, port, cport, irq, dma1, dma2, hardware, hwshare, &chip)) < 0)
+	err = snd_wss_create(card, port, cport,
+			     irq, dma1, dma2, hardware, hwshare, &chip);
+	if (err < 0)
 		return err;
 
-	if (!(chip->hardware & CS4231_HW_CS4236B_MASK)) {
+	if (!(chip->hardware & WSS_HW_CS4236B_MASK)) {
 	        snd_printk("CS4236+: MODE3 and extended registers not available, hardware=0x%x\n",chip->hardware);
 		snd_device_free(card, chip);
 		return -ENODEV;
@@ -330,20 +341,20 @@
 		snd_cs4236_ext_out(chip, CS4236_I23VAL(reg), snd_cs4236_ext_map[reg]);
 
         /* initialize compatible but more featured registers */
-	snd_cs4231_out(chip, CS4231_LEFT_INPUT, 0x40);
-	snd_cs4231_out(chip, CS4231_RIGHT_INPUT, 0x40);
-	snd_cs4231_out(chip, CS4231_AUX1_LEFT_INPUT, 0xff);
-	snd_cs4231_out(chip, CS4231_AUX1_RIGHT_INPUT, 0xff);
-	snd_cs4231_out(chip, CS4231_AUX2_LEFT_INPUT, 0xdf);
-	snd_cs4231_out(chip, CS4231_AUX2_RIGHT_INPUT, 0xdf);
-	snd_cs4231_out(chip, CS4231_RIGHT_LINE_IN, 0xff);
-	snd_cs4231_out(chip, CS4231_LEFT_LINE_IN, 0xff);
-	snd_cs4231_out(chip, CS4231_RIGHT_LINE_IN, 0xff);
+	snd_wss_out(chip, CS4231_LEFT_INPUT, 0x40);
+	snd_wss_out(chip, CS4231_RIGHT_INPUT, 0x40);
+	snd_wss_out(chip, CS4231_AUX1_LEFT_INPUT, 0xff);
+	snd_wss_out(chip, CS4231_AUX1_RIGHT_INPUT, 0xff);
+	snd_wss_out(chip, CS4231_AUX2_LEFT_INPUT, 0xdf);
+	snd_wss_out(chip, CS4231_AUX2_RIGHT_INPUT, 0xdf);
+	snd_wss_out(chip, CS4231_RIGHT_LINE_IN, 0xff);
+	snd_wss_out(chip, CS4231_LEFT_LINE_IN, 0xff);
+	snd_wss_out(chip, CS4231_RIGHT_LINE_IN, 0xff);
 	switch (chip->hardware) {
-	case CS4231_HW_CS4235:
-	case CS4231_HW_CS4239:
-		snd_cs4231_out(chip, CS4235_LEFT_MASTER, 0xff);
-		snd_cs4231_out(chip, CS4235_RIGHT_MASTER, 0xff);
+	case WSS_HW_CS4235:
+	case WSS_HW_CS4239:
+		snd_wss_out(chip, CS4235_LEFT_MASTER, 0xff);
+		snd_wss_out(chip, CS4235_RIGHT_MASTER, 0xff);
 		break;
 	}
 
@@ -351,12 +362,13 @@
 	return 0;
 }
 
-int snd_cs4236_pcm(struct snd_cs4231 *chip, int device, struct snd_pcm **rpcm)
+int snd_cs4236_pcm(struct snd_wss *chip, int device, struct snd_pcm **rpcm)
 {
 	struct snd_pcm *pcm;
 	int err;
 	
-	if ((err = snd_cs4231_pcm(chip, device, &pcm)) < 0)
+	err = snd_wss_pcm(chip, device, &pcm);
+	if (err < 0)
 		return err;
 	pcm->info_flags &= ~SNDRV_PCM_INFO_JOINT_DUPLEX;
 	if (rpcm)
@@ -387,7 +399,7 @@
 
 static int snd_cs4236_get_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_cs4231 *chip = snd_kcontrol_chip(kcontrol);
+	struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
 	unsigned long flags;
 	int reg = kcontrol->private_value & 0xff;
 	int shift = (kcontrol->private_value >> 8) & 0xff;
@@ -404,7 +416,7 @@
 
 static int snd_cs4236_put_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_cs4231 *chip = snd_kcontrol_chip(kcontrol);
+	struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
 	unsigned long flags;
 	int reg = kcontrol->private_value & 0xff;
 	int shift = (kcontrol->private_value >> 8) & 0xff;
@@ -433,7 +445,7 @@
 
 static int snd_cs4236_get_singlec(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_cs4231 *chip = snd_kcontrol_chip(kcontrol);
+	struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
 	unsigned long flags;
 	int reg = kcontrol->private_value & 0xff;
 	int shift = (kcontrol->private_value >> 8) & 0xff;
@@ -450,7 +462,7 @@
 
 static int snd_cs4236_put_singlec(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_cs4231 *chip = snd_kcontrol_chip(kcontrol);
+	struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
 	unsigned long flags;
 	int reg = kcontrol->private_value & 0xff;
 	int shift = (kcontrol->private_value >> 8) & 0xff;
@@ -490,7 +502,7 @@
 
 static int snd_cs4236_get_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_cs4231 *chip = snd_kcontrol_chip(kcontrol);
+	struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
 	unsigned long flags;
 	int left_reg = kcontrol->private_value & 0xff;
 	int right_reg = (kcontrol->private_value >> 8) & 0xff;
@@ -512,7 +524,7 @@
 
 static int snd_cs4236_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_cs4231 *chip = snd_kcontrol_chip(kcontrol);
+	struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
 	unsigned long flags;
 	int left_reg = kcontrol->private_value & 0xff;
 	int right_reg = (kcontrol->private_value >> 8) & 0xff;
@@ -555,7 +567,7 @@
 
 static int snd_cs4236_get_double1(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_cs4231 *chip = snd_kcontrol_chip(kcontrol);
+	struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
 	unsigned long flags;
 	int left_reg = kcontrol->private_value & 0xff;
 	int right_reg = (kcontrol->private_value >> 8) & 0xff;
@@ -577,7 +589,7 @@
 
 static int snd_cs4236_put_double1(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_cs4231 *chip = snd_kcontrol_chip(kcontrol);
+	struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
 	unsigned long flags;
 	int left_reg = kcontrol->private_value & 0xff;
 	int right_reg = (kcontrol->private_value >> 8) & 0xff;
@@ -600,7 +612,7 @@
 	val1 = (chip->image[left_reg] & ~(mask << shift_left)) | val1;
 	val2 = (chip->eimage[CS4236_REG(right_reg)] & ~(mask << shift_right)) | val2;
 	change = val1 != chip->image[left_reg] || val2 != chip->eimage[CS4236_REG(right_reg)];
-	snd_cs4231_out(chip, left_reg, val1);
+	snd_wss_out(chip, left_reg, val1);
 	snd_cs4236_ext_out(chip, right_reg, val2);
 	spin_unlock_irqrestore(&chip->reg_lock, flags);
 	return change;
@@ -619,7 +631,7 @@
 
 static int snd_cs4236_get_master_digital(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_cs4231 *chip = snd_kcontrol_chip(kcontrol);
+	struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
 	unsigned long flags;
 	
 	spin_lock_irqsave(&chip->reg_lock, flags);
@@ -631,7 +643,7 @@
 
 static int snd_cs4236_put_master_digital(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_cs4231 *chip = snd_kcontrol_chip(kcontrol);
+	struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
 	unsigned long flags;
 	int change;
 	unsigned short val1, val2;
@@ -678,7 +690,7 @@
 
 static int snd_cs4235_get_output_accu(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_cs4231 *chip = snd_kcontrol_chip(kcontrol);
+	struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
 	unsigned long flags;
 	
 	spin_lock_irqsave(&chip->reg_lock, flags);
@@ -690,7 +702,7 @@
 
 static int snd_cs4235_put_output_accu(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_cs4231 *chip = snd_kcontrol_chip(kcontrol);
+	struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
 	unsigned long flags;
 	int change;
 	unsigned short val1, val2;
@@ -701,108 +713,160 @@
 	val1 = (chip->image[CS4235_LEFT_MASTER] & ~(3 << 5)) | val1;
 	val2 = (chip->image[CS4235_RIGHT_MASTER] & ~(3 << 5)) | val2;
 	change = val1 != chip->image[CS4235_LEFT_MASTER] || val2 != chip->image[CS4235_RIGHT_MASTER];
-	snd_cs4231_out(chip, CS4235_LEFT_MASTER, val1);
-	snd_cs4231_out(chip, CS4235_RIGHT_MASTER, val2);
+	snd_wss_out(chip, CS4235_LEFT_MASTER, val1);
+	snd_wss_out(chip, CS4235_RIGHT_MASTER, val2);
 	spin_unlock_irqrestore(&chip->reg_lock, flags);
 	return change;
 }
 
 static struct snd_kcontrol_new snd_cs4236_controls[] = {
 
-CS4236_DOUBLE("Master Digital Playback Switch", 0, CS4236_LEFT_MASTER, CS4236_RIGHT_MASTER, 7, 7, 1, 1),
-CS4236_DOUBLE("Master Digital Capture Switch", 0, CS4236_DAC_MUTE, CS4236_DAC_MUTE, 7, 6, 1, 1),
+CS4236_DOUBLE("Master Digital Playback Switch", 0,
+		CS4236_LEFT_MASTER, CS4236_RIGHT_MASTER, 7, 7, 1, 1),
+CS4236_DOUBLE("Master Digital Capture Switch", 0,
+		CS4236_DAC_MUTE, CS4236_DAC_MUTE, 7, 6, 1, 1),
 CS4236_MASTER_DIGITAL("Master Digital Volume", 0),
 
-CS4236_DOUBLE("Capture Boost Volume", 0, CS4236_LEFT_MIX_CTRL, CS4236_RIGHT_MIX_CTRL, 5, 5, 3, 1),
+CS4236_DOUBLE("Capture Boost Volume", 0,
+		CS4236_LEFT_MIX_CTRL, CS4236_RIGHT_MIX_CTRL, 5, 5, 3, 1),
 
-CS4231_DOUBLE("PCM Playback Switch", 0, CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 7, 7, 1, 1),
-CS4231_DOUBLE("PCM Playback Volume", 0, CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 0, 0, 63, 1),
+WSS_DOUBLE("PCM Playback Switch", 0,
+		CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 7, 7, 1, 1),
+WSS_DOUBLE("PCM Playback Volume", 0,
+		CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 0, 0, 63, 1),
 
-CS4236_DOUBLE("DSP Playback Switch", 0, CS4236_LEFT_DSP, CS4236_RIGHT_DSP, 7, 7, 1, 1),
-CS4236_DOUBLE("DSP Playback Volume", 0, CS4236_LEFT_DSP, CS4236_RIGHT_DSP, 0, 0, 63, 1),
+CS4236_DOUBLE("DSP Playback Switch", 0,
+		CS4236_LEFT_DSP, CS4236_RIGHT_DSP, 7, 7, 1, 1),
+CS4236_DOUBLE("DSP Playback Volume", 0,
+		CS4236_LEFT_DSP, CS4236_RIGHT_DSP, 0, 0, 63, 1),
 
-CS4236_DOUBLE("FM Playback Switch", 0, CS4236_LEFT_FM, CS4236_RIGHT_FM, 7, 7, 1, 1),
-CS4236_DOUBLE("FM Playback Volume", 0, CS4236_LEFT_FM, CS4236_RIGHT_FM, 0, 0, 63, 1),
+CS4236_DOUBLE("FM Playback Switch", 0,
+		CS4236_LEFT_FM, CS4236_RIGHT_FM, 7, 7, 1, 1),
+CS4236_DOUBLE("FM Playback Volume", 0,
+		CS4236_LEFT_FM, CS4236_RIGHT_FM, 0, 0, 63, 1),
 
-CS4236_DOUBLE("Wavetable Playback Switch", 0, CS4236_LEFT_WAVE, CS4236_RIGHT_WAVE, 7, 7, 1, 1),
-CS4236_DOUBLE("Wavetable Playback Volume", 0, CS4236_LEFT_WAVE, CS4236_RIGHT_WAVE, 0, 0, 63, 1),
+CS4236_DOUBLE("Wavetable Playback Switch", 0,
+		CS4236_LEFT_WAVE, CS4236_RIGHT_WAVE, 7, 7, 1, 1),
+CS4236_DOUBLE("Wavetable Playback Volume", 0,
+		CS4236_LEFT_WAVE, CS4236_RIGHT_WAVE, 0, 0, 63, 1),
 
-CS4231_DOUBLE("Synth Playback Switch", 0, CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 7, 7, 1, 1),
-CS4231_DOUBLE("Synth Volume", 0, CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 0, 0, 31, 1),
-CS4231_DOUBLE("Synth Capture Switch", 0, CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 6, 6, 1, 1),
-CS4231_DOUBLE("Synth Capture Bypass", 0, CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 5, 5, 1, 1),
+WSS_DOUBLE("Synth Playback Switch", 0,
+		CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 7, 7, 1, 1),
+WSS_DOUBLE("Synth Volume", 0,
+		CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 0, 0, 31, 1),
+WSS_DOUBLE("Synth Capture Switch", 0,
+		CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 6, 6, 1, 1),
+WSS_DOUBLE("Synth Capture Bypass", 0,
+		CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 5, 5, 1, 1),
 
-CS4236_DOUBLE("Mic Playback Switch", 0, CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 6, 6, 1, 1),
-CS4236_DOUBLE("Mic Capture Switch", 0, CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 7, 7, 1, 1),
+CS4236_DOUBLE("Mic Playback Switch", 0,
+		CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 6, 6, 1, 1),
+CS4236_DOUBLE("Mic Capture Switch", 0,
+		CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 7, 7, 1, 1),
 CS4236_DOUBLE("Mic Volume", 0, CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 0, 0, 31, 1),
-CS4236_DOUBLE("Mic Playback Boost", 0, CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 5, 5, 1, 0),
+CS4236_DOUBLE("Mic Playback Boost", 0,
+		CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 5, 5, 1, 0),
 
-CS4231_DOUBLE("Line Playback Switch", 0, CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 7, 7, 1, 1),
-CS4231_DOUBLE("Line Volume", 0, CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 0, 0, 31, 1),
-CS4231_DOUBLE("Line Capture Switch", 0, CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 6, 6, 1, 1),
-CS4231_DOUBLE("Line Capture Bypass", 0, CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 5, 5, 1, 1),
+WSS_DOUBLE("Line Playback Switch", 0,
+		CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 7, 7, 1, 1),
+WSS_DOUBLE("Line Volume", 0,
+		CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 0, 0, 31, 1),
+WSS_DOUBLE("Line Capture Switch", 0,
+		CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 6, 6, 1, 1),
+WSS_DOUBLE("Line Capture Bypass", 0,
+		CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 5, 5, 1, 1),
 
-CS4231_DOUBLE("CD Playback Switch", 0, CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 7, 7, 1, 1),
-CS4231_DOUBLE("CD Volume", 0, CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 0, 0, 31, 1),
-CS4231_DOUBLE("CD Capture Switch", 0, CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 6, 6, 1, 1),
+WSS_DOUBLE("CD Playback Switch", 0,
+		CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 7, 7, 1, 1),
+WSS_DOUBLE("CD Volume", 0,
+		CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 0, 0, 31, 1),
+WSS_DOUBLE("CD Capture Switch", 0,
+		CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 6, 6, 1, 1),
 
-CS4236_DOUBLE1("Mono Output Playback Switch", 0, CS4231_MONO_CTRL, CS4236_RIGHT_MIX_CTRL, 6, 7, 1, 1),
-CS4236_DOUBLE1("Mono Playback Switch", 0, CS4231_MONO_CTRL, CS4236_LEFT_MIX_CTRL, 7, 7, 1, 1),
-CS4231_SINGLE("Mono Playback Volume", 0, CS4231_MONO_CTRL, 0, 15, 1),
-CS4231_SINGLE("Mono Playback Bypass", 0, CS4231_MONO_CTRL, 5, 1, 0),
+CS4236_DOUBLE1("Mono Output Playback Switch", 0,
+		CS4231_MONO_CTRL, CS4236_RIGHT_MIX_CTRL, 6, 7, 1, 1),
+CS4236_DOUBLE1("Mono Playback Switch", 0,
+		CS4231_MONO_CTRL, CS4236_LEFT_MIX_CTRL, 7, 7, 1, 1),
+WSS_SINGLE("Mono Playback Volume", 0, CS4231_MONO_CTRL, 0, 15, 1),
+WSS_SINGLE("Mono Playback Bypass", 0, CS4231_MONO_CTRL, 5, 1, 0),
 
-CS4231_DOUBLE("Capture Volume", 0, CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 0, 0, 15, 0),
-CS4231_DOUBLE("Analog Loopback Capture Switch", 0, CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 7, 7, 1, 0),
+WSS_DOUBLE("Capture Volume", 0,
+		CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 0, 0, 15, 0),
+WSS_DOUBLE("Analog Loopback Capture Switch", 0,
+		CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 7, 7, 1, 0),
 
-CS4231_SINGLE("Digital Loopback Playback Switch", 0, CS4231_LOOPBACK, 0, 1, 0),
-CS4236_DOUBLE1("Digital Loopback Playback Volume", 0, CS4231_LOOPBACK, CS4236_RIGHT_LOOPBACK, 2, 0, 63, 1)
+WSS_SINGLE("Digital Loopback Playback Switch", 0, CS4231_LOOPBACK, 0, 1, 0),
+CS4236_DOUBLE1("Digital Loopback Playback Volume", 0,
+		CS4231_LOOPBACK, CS4236_RIGHT_LOOPBACK, 2, 0, 63, 1)
 };
 
 static struct snd_kcontrol_new snd_cs4235_controls[] = {
 
-CS4231_DOUBLE("Master Switch", 0, CS4235_LEFT_MASTER, CS4235_RIGHT_MASTER, 7, 7, 1, 1),
-CS4231_DOUBLE("Master Volume", 0, CS4235_LEFT_MASTER, CS4235_RIGHT_MASTER, 0, 0, 31, 1),
+WSS_DOUBLE("Master Switch", 0,
+		CS4235_LEFT_MASTER, CS4235_RIGHT_MASTER, 7, 7, 1, 1),
+WSS_DOUBLE("Master Volume", 0,
+		CS4235_LEFT_MASTER, CS4235_RIGHT_MASTER, 0, 0, 31, 1),
 
 CS4235_OUTPUT_ACCU("Playback Volume", 0),
 
-CS4236_DOUBLE("Master Digital Playback Switch", 0, CS4236_LEFT_MASTER, CS4236_RIGHT_MASTER, 7, 7, 1, 1),
-CS4236_DOUBLE("Master Digital Capture Switch", 0, CS4236_DAC_MUTE, CS4236_DAC_MUTE, 7, 6, 1, 1),
+CS4236_DOUBLE("Master Digital Playback Switch", 0,
+		CS4236_LEFT_MASTER, CS4236_RIGHT_MASTER, 7, 7, 1, 1),
+CS4236_DOUBLE("Master Digital Capture Switch", 0,
+		CS4236_DAC_MUTE, CS4236_DAC_MUTE, 7, 6, 1, 1),
 CS4236_MASTER_DIGITAL("Master Digital Volume", 0),
 
-CS4231_DOUBLE("Master Digital Playback Switch", 1, CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 7, 7, 1, 1),
-CS4231_DOUBLE("Master Digital Capture Switch", 1, CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 6, 6, 1, 1),
-CS4231_DOUBLE("Master Digital Volume", 1, CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 0, 0, 31, 1),
+WSS_DOUBLE("Master Digital Playback Switch", 1,
+		CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 7, 7, 1, 1),
+WSS_DOUBLE("Master Digital Capture Switch", 1,
+		CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 6, 6, 1, 1),
+WSS_DOUBLE("Master Digital Volume", 1,
+		CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 0, 0, 31, 1),
 
-CS4236_DOUBLE("Capture Volume", 0, CS4236_LEFT_MIX_CTRL, CS4236_RIGHT_MIX_CTRL, 5, 5, 3, 1),
+CS4236_DOUBLE("Capture Volume", 0,
+		CS4236_LEFT_MIX_CTRL, CS4236_RIGHT_MIX_CTRL, 5, 5, 3, 1),
 
-CS4231_DOUBLE("PCM Switch", 0, CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 7, 7, 1, 1),
-CS4231_DOUBLE("PCM Volume", 0, CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 0, 0, 63, 1),
+WSS_DOUBLE("PCM Switch", 0,
+		CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 7, 7, 1, 1),
+WSS_DOUBLE("PCM Volume", 0,
+		CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 0, 0, 63, 1),
 
 CS4236_DOUBLE("DSP Switch", 0, CS4236_LEFT_DSP, CS4236_RIGHT_DSP, 7, 7, 1, 1),
 
 CS4236_DOUBLE("FM Switch", 0, CS4236_LEFT_FM, CS4236_RIGHT_FM, 7, 7, 1, 1),
 
-CS4236_DOUBLE("Wavetable Switch", 0, CS4236_LEFT_WAVE, CS4236_RIGHT_WAVE, 7, 7, 1, 1),
+CS4236_DOUBLE("Wavetable Switch", 0,
+		CS4236_LEFT_WAVE, CS4236_RIGHT_WAVE, 7, 7, 1, 1),
 
-CS4236_DOUBLE("Mic Capture Switch", 0, CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 7, 7, 1, 1),
-CS4236_DOUBLE("Mic Playback Switch", 0, CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 6, 6, 1, 1),
+CS4236_DOUBLE("Mic Capture Switch", 0,
+		CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 7, 7, 1, 1),
+CS4236_DOUBLE("Mic Playback Switch", 0,
+		CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 6, 6, 1, 1),
 CS4236_SINGLE("Mic Volume", 0, CS4236_LEFT_MIC, 0, 31, 1),
 CS4236_SINGLE("Mic Playback Boost", 0, CS4236_LEFT_MIC, 5, 1, 0),
 
-CS4231_DOUBLE("Aux Playback Switch", 0, CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 7, 7, 1, 1),
-CS4231_DOUBLE("Aux Capture Switch", 0, CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 6, 6, 1, 1),
-CS4231_DOUBLE("Aux Volume", 0, CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 0, 0, 31, 1),
+WSS_DOUBLE("Aux Playback Switch", 0,
+		CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 7, 7, 1, 1),
+WSS_DOUBLE("Aux Capture Switch", 0,
+		CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 6, 6, 1, 1),
+WSS_DOUBLE("Aux Volume", 0,
+		CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 0, 0, 31, 1),
 
-CS4231_DOUBLE("Aux Playback Switch", 1, CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 7, 7, 1, 1),
-CS4231_DOUBLE("Aux Capture Switch", 1, CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 6, 6, 1, 1),
-CS4231_DOUBLE("Aux Volume", 1, CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 0, 0, 31, 1),
+WSS_DOUBLE("Aux Playback Switch", 1,
+		CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 7, 7, 1, 1),
+WSS_DOUBLE("Aux Capture Switch", 1,
+		CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 6, 6, 1, 1),
+WSS_DOUBLE("Aux Volume", 1,
+		CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 0, 0, 31, 1),
 
-CS4236_DOUBLE1("Master Mono Switch", 0, CS4231_MONO_CTRL, CS4236_RIGHT_MIX_CTRL, 6, 7, 1, 1),
+CS4236_DOUBLE1("Master Mono Switch", 0,
+		CS4231_MONO_CTRL, CS4236_RIGHT_MIX_CTRL, 6, 7, 1, 1),
 
-CS4236_DOUBLE1("Mono Switch", 0, CS4231_MONO_CTRL, CS4236_LEFT_MIX_CTRL, 7, 7, 1, 1),
-CS4231_SINGLE("Mono Volume", 0, CS4231_MONO_CTRL, 0, 15, 1),
+CS4236_DOUBLE1("Mono Switch", 0,
+		CS4231_MONO_CTRL, CS4236_LEFT_MIX_CTRL, 7, 7, 1, 1),
+WSS_SINGLE("Mono Volume", 0, CS4231_MONO_CTRL, 0, 15, 1),
 
-CS4231_DOUBLE("Analog Loopback Switch", 0, CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 7, 7, 1, 0),
+WSS_DOUBLE("Analog Loopback Switch", 0,
+		CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 7, 7, 1, 0),
 };
 
 #define CS4236_IEC958_ENABLE(xname, xindex) \
@@ -813,14 +877,14 @@
 
 static int snd_cs4236_get_iec958_switch(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_cs4231 *chip = snd_kcontrol_chip(kcontrol);
+	struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
 	unsigned long flags;
 	
 	spin_lock_irqsave(&chip->reg_lock, flags);
 	ucontrol->value.integer.value[0] = chip->image[CS4231_ALT_FEATURE_1] & 0x02 ? 1 : 0;
 #if 0
 	printk("get valid: ALT = 0x%x, C3 = 0x%x, C4 = 0x%x, C5 = 0x%x, C6 = 0x%x, C8 = 0x%x\n",
-			snd_cs4231_in(chip, CS4231_ALT_FEATURE_1),
+			snd_wss_in(chip, CS4231_ALT_FEATURE_1),
 			snd_cs4236_ctrl_in(chip, 3),
 			snd_cs4236_ctrl_in(chip, 4),
 			snd_cs4236_ctrl_in(chip, 5),
@@ -833,7 +897,7 @@
 
 static int snd_cs4236_put_iec958_switch(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_cs4231 *chip = snd_kcontrol_chip(kcontrol);
+	struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
 	unsigned long flags;
 	int change;
 	unsigned short enable, val;
@@ -841,23 +905,23 @@
 	enable = ucontrol->value.integer.value[0] & 1;
 
 	mutex_lock(&chip->mce_mutex);
-	snd_cs4231_mce_up(chip);
+	snd_wss_mce_up(chip);
 	spin_lock_irqsave(&chip->reg_lock, flags);
 	val = (chip->image[CS4231_ALT_FEATURE_1] & ~0x0e) | (0<<2) | (enable << 1);
 	change = val != chip->image[CS4231_ALT_FEATURE_1];
-	snd_cs4231_out(chip, CS4231_ALT_FEATURE_1, val);
+	snd_wss_out(chip, CS4231_ALT_FEATURE_1, val);
 	val = snd_cs4236_ctrl_in(chip, 4) | 0xc0;
 	snd_cs4236_ctrl_out(chip, 4, val);
 	udelay(100);
 	val &= ~0x40;
 	snd_cs4236_ctrl_out(chip, 4, val);
 	spin_unlock_irqrestore(&chip->reg_lock, flags);
-	snd_cs4231_mce_down(chip);
+	snd_wss_mce_down(chip);
 	mutex_unlock(&chip->mce_mutex);
 
 #if 0
 	printk("set valid: ALT = 0x%x, C3 = 0x%x, C4 = 0x%x, C5 = 0x%x, C6 = 0x%x, C8 = 0x%x\n",
-			snd_cs4231_in(chip, CS4231_ALT_FEATURE_1),
+			snd_wss_in(chip, CS4231_ALT_FEATURE_1),
 			snd_cs4236_ctrl_in(chip, 3),
 			snd_cs4236_ctrl_in(chip, 4),
 			snd_cs4236_ctrl_in(chip, 5),
@@ -896,19 +960,20 @@
 CS4236_SINGLEC("3D Control - IEC958", 0, 3, 5, 1, 0)
 };
 
-int snd_cs4236_mixer(struct snd_cs4231 *chip)
+int snd_cs4236_mixer(struct snd_wss *chip)
 {
 	struct snd_card *card;
 	unsigned int idx, count;
 	int err;
 	struct snd_kcontrol_new *kcontrol;
 
-	snd_assert(chip != NULL && chip->card != NULL, return -EINVAL);
+	if (snd_BUG_ON(!chip || !chip->card))
+		return -EINVAL;
 	card = chip->card;
-	strcpy(card->mixername, snd_cs4231_chip_id(chip));
+	strcpy(card->mixername, snd_wss_chip_id(chip));
 
-	if (chip->hardware == CS4231_HW_CS4235 ||
-	    chip->hardware == CS4231_HW_CS4239) {
+	if (chip->hardware == WSS_HW_CS4235 ||
+	    chip->hardware == WSS_HW_CS4239) {
 		for (idx = 0; idx < ARRAY_SIZE(snd_cs4235_controls); idx++) {
 			if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_cs4235_controls[idx], chip))) < 0)
 				return err;
@@ -920,16 +985,16 @@
 		}
 	}
 	switch (chip->hardware) {
-	case CS4231_HW_CS4235:
-	case CS4231_HW_CS4239:
+	case WSS_HW_CS4235:
+	case WSS_HW_CS4239:
 		count = ARRAY_SIZE(snd_cs4236_3d_controls_cs4235);
 		kcontrol = snd_cs4236_3d_controls_cs4235;
 		break;
-	case CS4231_HW_CS4237B:
+	case WSS_HW_CS4237B:
 		count = ARRAY_SIZE(snd_cs4236_3d_controls_cs4237);
 		kcontrol = snd_cs4236_3d_controls_cs4237;
 		break;
-	case CS4231_HW_CS4238B:
+	case WSS_HW_CS4238B:
 		count = ARRAY_SIZE(snd_cs4236_3d_controls_cs4238);
 		kcontrol = snd_cs4236_3d_controls_cs4238;
 		break;
@@ -941,8 +1006,8 @@
 		if ((err = snd_ctl_add(card, snd_ctl_new1(kcontrol, chip))) < 0)
 			return err;
 	}
-	if (chip->hardware == CS4231_HW_CS4237B ||
-	    chip->hardware == CS4231_HW_CS4238B) {
+	if (chip->hardware == WSS_HW_CS4237B ||
+	    chip->hardware == WSS_HW_CS4238B) {
 		for (idx = 0; idx < ARRAY_SIZE(snd_cs4236_iec958_controls); idx++) {
 			if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_cs4236_iec958_controls[idx], chip))) < 0)
 				return err;
diff --git a/sound/isa/es1688/es1688_lib.c b/sound/isa/es1688/es1688_lib.c
index 1e1e575..4fbb508 100644
--- a/sound/isa/es1688/es1688_lib.c
+++ b/sound/isa/es1688/es1688_lib.c
@@ -1009,7 +1009,8 @@
 	int err;
 	unsigned char reg, val;
 
-	snd_assert(chip != NULL && chip->card != NULL, return -EINVAL);
+	if (snd_BUG_ON(!chip || !chip->card))
+		return -EINVAL;
 
 	card = chip->card;
 
diff --git a/sound/isa/gus/gus_main.c b/sound/isa/gus/gus_main.c
index cccc16c..12eb98f 100644
--- a/sound/isa/gus/gus_main.c
+++ b/sound/isa/gus/gus_main.c
@@ -276,9 +276,11 @@
 	static unsigned char dmas[8] =
 		{6, 1, 0, 2, 0, 3, 4, 5};
 
-	snd_assert(gus != NULL, return -EINVAL);
+	if (snd_BUG_ON(!gus))
+		return -EINVAL;
 	card = gus->card;
-	snd_assert(card != NULL, return -EINVAL);
+	if (snd_BUG_ON(!card))
+		return -EINVAL;
 
 	gus->mix_cntrl_reg &= 0xf8;
 	gus->mix_cntrl_reg |= 0x01;	/* disable MIC, LINE IN, enable LINE OUT */
diff --git a/sound/isa/gus/gus_mixer.c b/sound/isa/gus/gus_mixer.c
index ebdb334..0dd4341 100644
--- a/sound/isa/gus/gus_mixer.c
+++ b/sound/isa/gus/gus_mixer.c
@@ -161,9 +161,11 @@
 	unsigned int idx, max;
 	int err;
 
-	snd_assert(gus != NULL, return -EINVAL);
+	if (snd_BUG_ON(!gus))
+		return -EINVAL;
 	card = gus->card;
-	snd_assert(card != NULL, return -EINVAL);
+	if (snd_BUG_ON(!card))
+		return -EINVAL;
 
 	if (gus->ics_flag)
 		snd_component_add(card, "ICS2101");
diff --git a/sound/isa/gus/gus_pcm.c b/sound/isa/gus/gus_pcm.c
index 99731dc..38510ae 100644
--- a/sound/isa/gus/gus_pcm.c
+++ b/sound/isa/gus/gus_pcm.c
@@ -352,8 +352,10 @@
 	
 	bpos = samples_to_bytes(runtime, pos) + (voice * (pcmp->dma_size / 2));
 	len = samples_to_bytes(runtime, count);
-	snd_assert(bpos <= pcmp->dma_size, return -EIO);
-	snd_assert(bpos + len <= pcmp->dma_size, return -EIO);
+	if (snd_BUG_ON(bpos > pcmp->dma_size))
+		return -EIO;
+	if (snd_BUG_ON(bpos + len > pcmp->dma_size))
+		return -EIO;
 	if (copy_from_user(runtime->dma_area + bpos, src, len))
 		return -EFAULT;
 	if (snd_gf1_pcm_use_dma && len > 32) {
@@ -381,8 +383,10 @@
 	
 	bpos = samples_to_bytes(runtime, pos) + (voice * (pcmp->dma_size / 2));
 	len = samples_to_bytes(runtime, count);
-	snd_assert(bpos <= pcmp->dma_size, return -EIO);
-	snd_assert(bpos + len <= pcmp->dma_size, return -EIO);
+	if (snd_BUG_ON(bpos > pcmp->dma_size))
+		return -EIO;
+	if (snd_BUG_ON(bpos + len > pcmp->dma_size))
+		return -EIO;
 	snd_pcm_format_set_silence(runtime->format, runtime->dma_area + bpos, count);
 	if (snd_gf1_pcm_use_dma && len > 32) {
 		return snd_gf1_pcm_block_change(substream, bpos, pcmp->memory + bpos, len);
diff --git a/sound/isa/gus/gusmax.c b/sound/isa/gus/gusmax.c
index f87c623..f94c197 100644
--- a/sound/isa/gus/gusmax.c
+++ b/sound/isa/gus/gusmax.c
@@ -28,7 +28,7 @@
 #include <asm/dma.h>
 #include <sound/core.h>
 #include <sound/gus.h>
-#include <sound/cs4231.h>
+#include <sound/wss.h>
 #define SNDRV_LEGACY_FIND_FREE_IRQ
 #define SNDRV_LEGACY_FIND_FREE_DMA
 #include <sound/initval.h>
@@ -75,7 +75,7 @@
 	int irq;
 	struct snd_card *card;
 	struct snd_gus_card *gus;
-	struct snd_cs4231 *cs4231;
+	struct snd_wss *wss;
 	unsigned short gus_status_reg;
 	unsigned short pcm_status_reg;
 };
@@ -117,7 +117,7 @@
 		}
 		if (inb(maxcard->pcm_status_reg) & 0x01) { /* IRQ bit is set? */
 			handled = 1;
-			snd_cs4231_interrupt(irq, maxcard->cs4231);
+			snd_wss_interrupt(irq, maxcard->wss);
 			loop++;
 		}
 	} while (loop && --max > 0);
@@ -140,10 +140,7 @@
 	outb(gus->max_cntrl_val, GUSP(gus, MAXCNTRLPORT));
 }
 
-#define CS4231_PRIVATE( left, right, shift, mute ) \
-			((left << 24)|(right << 16)|(shift<<8)|mute)
-
-static int __devinit snd_gusmax_mixer(struct snd_cs4231 *chip)
+static int __devinit snd_gusmax_mixer(struct snd_wss *chip)
 {
 	struct snd_card *card = chip->card;
 	struct snd_ctl_elem_id id1, id2;
@@ -214,7 +211,7 @@
 	int xirq, xdma1, xdma2, err;
 	struct snd_card *card;
 	struct snd_gus_card *gus = NULL;
-	struct snd_cs4231 *cs4231;
+	struct snd_wss *wss;
 	struct snd_gusmax *maxcard;
 
 	card = snd_card_new(index[dev], id[dev], THIS_MODULE,
@@ -301,33 +298,39 @@
 	}
 	maxcard->irq = xirq;
 	
-	if ((err = snd_cs4231_create(card,
-				     gus->gf1.port + 0x10c, -1, xirq,
-				     xdma2 < 0 ? xdma1 : xdma2, xdma1,
-				     CS4231_HW_DETECT,
-				     CS4231_HWSHARE_IRQ |
-				     CS4231_HWSHARE_DMA1 |
-				     CS4231_HWSHARE_DMA2,
-				     &cs4231)) < 0)
+	err = snd_wss_create(card,
+			     gus->gf1.port + 0x10c, -1, xirq,
+			     xdma2 < 0 ? xdma1 : xdma2, xdma1,
+			     WSS_HW_DETECT,
+			     WSS_HWSHARE_IRQ |
+			     WSS_HWSHARE_DMA1 |
+			     WSS_HWSHARE_DMA2,
+			     &wss);
+	if (err < 0)
 		goto _err;
 
-	if ((err = snd_cs4231_pcm(cs4231, 0, NULL)) < 0)
+	err = snd_wss_pcm(wss, 0, NULL);
+	if (err < 0)
 		goto _err;
 
-	if ((err = snd_cs4231_mixer(cs4231)) < 0)
+	err = snd_wss_mixer(wss);
+	if (err < 0)
 		goto _err;
 
-	if ((err = snd_cs4231_timer(cs4231, 2, NULL)) < 0)
+	err = snd_wss_timer(wss, 2, NULL);
+	if (err < 0)
 		goto _err;
 
 	if (pcm_channels[dev] > 0) {
 		if ((err = snd_gf1_pcm_new(gus, 1, 1, NULL)) < 0)
 			goto _err;
 	}
-	if ((err = snd_gusmax_mixer(cs4231)) < 0)
+	err = snd_gusmax_mixer(wss);
+	if (err < 0)
 		goto _err;
 
-	if ((err = snd_gf1_rawmidi_new(gus, 0, NULL)) < 0)
+	err = snd_gf1_rawmidi_new(gus, 0, NULL);
+	if (err < 0)
 		goto _err;
 
 	sprintf(card->longname + strlen(card->longname), " at 0x%lx, irq %i, dma %i", gus->gf1.port, xirq, xdma1);
@@ -336,11 +339,12 @@
 
 	snd_card_set_dev(card, pdev);
 
-	if ((err = snd_card_register(card)) < 0)
+	err = snd_card_register(card);
+	if (err < 0)
 		goto _err;
 		
 	maxcard->gus = gus;
-	maxcard->cs4231 = cs4231;
+	maxcard->wss = wss;
 
 	dev_set_drvdata(pdev, card);
 	return 0;
diff --git a/sound/isa/gus/interwave.c b/sound/isa/gus/interwave.c
index ca0d7ac..5faecfb 100644
--- a/sound/isa/gus/interwave.c
+++ b/sound/isa/gus/interwave.c
@@ -32,7 +32,7 @@
 #include <asm/dma.h>
 #include <sound/core.h>
 #include <sound/gus.h>
-#include <sound/cs4231.h>
+#include <sound/wss.h>
 #ifdef SNDRV_STB
 #include <sound/tea6330t.h>
 #endif
@@ -118,7 +118,7 @@
 	int irq;
 	struct snd_card *card;
 	struct snd_gus_card *gus;
-	struct snd_cs4231 *cs4231;
+	struct snd_wss *wss;
 #ifdef SNDRV_STB
 	struct resource *i2c_res;
 #endif
@@ -312,7 +312,7 @@
 		}
 		if (inb(iwcard->pcm_status_reg) & 0x01) {	/* IRQ bit is set? */
 			handled = 1;
-			snd_cs4231_interrupt(irq, iwcard->cs4231);
+			snd_wss_interrupt(irq, iwcard->wss);
 			loop++;
 		}
 	} while (loop && --max > 0);
@@ -498,13 +498,17 @@
 }
 
 static struct snd_kcontrol_new snd_interwave_controls[] = {
-CS4231_DOUBLE("Master Playback Switch", 0, CS4231_LINE_LEFT_OUTPUT, CS4231_LINE_RIGHT_OUTPUT, 7, 7, 1, 1),
-CS4231_DOUBLE("Master Playback Volume", 0, CS4231_LINE_LEFT_OUTPUT, CS4231_LINE_RIGHT_OUTPUT, 0, 0, 31, 1),
-CS4231_DOUBLE("Mic Playback Switch", 0, CS4231_LEFT_MIC_INPUT, CS4231_RIGHT_MIC_INPUT, 7, 7, 1, 1),
-CS4231_DOUBLE("Mic Playback Volume", 0, CS4231_LEFT_MIC_INPUT, CS4231_RIGHT_MIC_INPUT, 0, 0, 31, 1)
+WSS_DOUBLE("Master Playback Switch", 0,
+		CS4231_LINE_LEFT_OUTPUT, CS4231_LINE_RIGHT_OUTPUT, 7, 7, 1, 1),
+WSS_DOUBLE("Master Playback Volume", 0,
+		CS4231_LINE_LEFT_OUTPUT, CS4231_LINE_RIGHT_OUTPUT, 0, 0, 31, 1),
+WSS_DOUBLE("Mic Playback Switch", 0,
+		CS4231_LEFT_MIC_INPUT, CS4231_RIGHT_MIC_INPUT, 7, 7, 1, 1),
+WSS_DOUBLE("Mic Playback Volume", 0,
+		CS4231_LEFT_MIC_INPUT, CS4231_RIGHT_MIC_INPUT, 0, 0, 31, 1)
 };
 
-static int __devinit snd_interwave_mixer(struct snd_cs4231 *chip)
+static int __devinit snd_interwave_mixer(struct snd_wss *chip)
 {
 	struct snd_card *card = chip->card;
 	struct snd_ctl_elem_id id1, id2;
@@ -527,10 +531,10 @@
 	for (idx = 0; idx < ARRAY_SIZE(snd_interwave_controls); idx++)
 		if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_interwave_controls[idx], chip))) < 0)
 			return err;
-	snd_cs4231_out(chip, CS4231_LINE_LEFT_OUTPUT, 0x9f);
-	snd_cs4231_out(chip, CS4231_LINE_RIGHT_OUTPUT, 0x9f);
-	snd_cs4231_out(chip, CS4231_LEFT_MIC_INPUT, 0x9f);
-	snd_cs4231_out(chip, CS4231_RIGHT_MIC_INPUT, 0x9f);
+	snd_wss_out(chip, CS4231_LINE_LEFT_OUTPUT, 0x9f);
+	snd_wss_out(chip, CS4231_LINE_RIGHT_OUTPUT, 0x9f);
+	snd_wss_out(chip, CS4231_LEFT_MIC_INPUT, 0x9f);
+	snd_wss_out(chip, CS4231_RIGHT_MIC_INPUT, 0x9f);
 	/* reassign AUXA to SYNTHESIZER */
 	strcpy(id1.name, "Aux Playback Switch");
 	strcpy(id2.name, "Synth Playback Switch");
@@ -642,7 +646,7 @@
 {
 	int xirq, xdma1, xdma2;
 	struct snd_interwave *iwcard = card->private_data;
-	struct snd_cs4231 *cs4231;
+	struct snd_wss *wss;
 	struct snd_gus_card *gus;
 #ifdef SNDRV_STB
 	struct snd_i2c_bus *i2c_bus;
@@ -684,33 +688,39 @@
 	}
 	iwcard->irq = xirq;
 
-	if ((err = snd_cs4231_create(card,
-				     gus->gf1.port + 0x10c, -1, xirq,
-				     xdma2 < 0 ? xdma1 : xdma2, xdma1,
-				     CS4231_HW_INTERWAVE,
-				     CS4231_HWSHARE_IRQ |
-				     CS4231_HWSHARE_DMA1 |
-				     CS4231_HWSHARE_DMA2,
-				     &cs4231)) < 0)
+	err = snd_wss_create(card,
+			     gus->gf1.port + 0x10c, -1, xirq,
+			     xdma2 < 0 ? xdma1 : xdma2, xdma1,
+			     WSS_HW_INTERWAVE,
+			     WSS_HWSHARE_IRQ |
+			     WSS_HWSHARE_DMA1 |
+			     WSS_HWSHARE_DMA2,
+			     &wss);
+	if (err < 0)
 		return err;
 
-	if ((err = snd_cs4231_pcm(cs4231, 0, &pcm)) < 0)
+	err = snd_wss_pcm(wss, 0, &pcm);
+	if (err < 0)
 		return err;
 
 	sprintf(pcm->name + strlen(pcm->name), " rev %c", gus->revision + 'A');
 	strcat(pcm->name, " (codec)");
 
-	if ((err = snd_cs4231_timer(cs4231, 2, NULL)) < 0)
+	err = snd_wss_timer(wss, 2, NULL);
+	if (err < 0)
 		return err;
 
-	if ((err = snd_cs4231_mixer(cs4231)) < 0)
+	err = snd_wss_mixer(wss);
+	if (err < 0)
 		return err;
 
 	if (pcm_channels[dev] > 0) {
-		if ((err = snd_gf1_pcm_new(gus, 1, 1, NULL)) < 0)
+		err = snd_gf1_pcm_new(gus, 1, 1, NULL);
+		if (err < 0)
 			return err;
 	}
-	if ((err = snd_interwave_mixer(cs4231)) < 0)
+	err = snd_interwave_mixer(wss);
+	if (err < 0)
 		return err;
 
 #ifdef SNDRV_STB
@@ -754,10 +764,11 @@
 	if (xdma2 >= 0)
 		sprintf(card->longname + strlen(card->longname), "&%d", xdma2);
 
-	if ((err = snd_card_register(card)) < 0)
+	err = snd_card_register(card);
+	if (err < 0)
 		return err;
 	
-	iwcard->cs4231 = cs4231;
+	iwcard->wss = wss;
 	iwcard->gus = gus;
 	return 0;
 }
diff --git a/sound/isa/opl3sa2.c b/sound/isa/opl3sa2.c
index 854a9f7..58c972b 100644
--- a/sound/isa/opl3sa2.c
+++ b/sound/isa/opl3sa2.c
@@ -28,7 +28,7 @@
 #include <linux/pnp.h>
 #include <linux/moduleparam.h>
 #include <sound/core.h>
-#include <sound/cs4231.h>
+#include <sound/wss.h>
 #include <sound/mpu401.h>
 #include <sound/opl3.h>
 #include <sound/initval.h>
@@ -124,7 +124,6 @@
 #define OPL3SA2_PM_D3	(OPL3SA2_PM_ADOWN|OPL3SA2_PM_PSV|OPL3SA2_PM_PDN|OPL3SA2_PM_PDX)
 
 struct snd_opl3sa2 {
-	struct snd_card *card;
 	int version;		/* 2 or 3 */
 	unsigned long port;	/* control port */
 	struct resource *res_port; /* control port resource */
@@ -133,7 +132,7 @@
 	spinlock_t reg_lock;
 	struct snd_hwdep *synth;
 	struct snd_rawmidi *rmidi;
-	struct snd_cs4231 *cs4231;
+	struct snd_wss *wss;
 	unsigned char ctlregs[0x20];
 	int ymode;		/* SL added */
 	struct snd_kcontrol *master_switch;
@@ -222,14 +221,13 @@
 	spin_unlock_irqrestore(&chip->reg_lock, flags);
 }
 
-static int __devinit snd_opl3sa2_detect(struct snd_opl3sa2 *chip)
+static int __devinit snd_opl3sa2_detect(struct snd_card *card)
 {
-	struct snd_card *card;
+	struct snd_opl3sa2 *chip = card->private_data;
 	unsigned long port;
 	unsigned char tmp, tmp1;
 	char str[2];
 
-	card = chip->card;
 	port = chip->port;
 	if ((chip->res_port = request_region(port, 2, "OPL3-SA control")) == NULL) {
 		snd_printk(KERN_ERR PFX "can't grab port 0x%lx\n", port);
@@ -298,12 +296,14 @@
 static irqreturn_t snd_opl3sa2_interrupt(int irq, void *dev_id)
 {
 	unsigned short status;
-	struct snd_opl3sa2 *chip = dev_id;
+	struct snd_card *card = dev_id;
+	struct snd_opl3sa2 *chip;
 	int handled = 0;
 
-	if (chip == NULL || chip->card == NULL)
+	if (card == NULL)
 		return IRQ_NONE;
 
+	chip = card->private_data;
 	status = snd_opl3sa2_read(chip, OPL3SA2_IRQ_STATUS);
 
 	if (status & 0x20) {
@@ -318,7 +318,7 @@
 
 	if (status & 0x07) {	/* TI,CI,PI */
 		handled = 1;
-		snd_cs4231_interrupt(irq, chip->cs4231);
+		snd_wss_interrupt(irq, chip->wss);
 	}
 
 	if (status & 0x40) { /* hardware volume change */
@@ -327,8 +327,10 @@
 		snd_opl3sa2_read(chip, OPL3SA2_MASTER_RIGHT);
 		snd_opl3sa2_read(chip, OPL3SA2_MASTER_LEFT);
 		if (chip->master_switch && chip->master_volume) {
-			snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, &chip->master_switch->id);
-			snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, &chip->master_volume->id);
+			snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE,
+					&chip->master_switch->id);
+			snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE,
+					&chip->master_volume->id);
 		}
 	}
 	return IRQ_RETVAL(handled);
@@ -336,29 +338,18 @@
 
 #define OPL3SA2_SINGLE(xname, xindex, reg, shift, mask, invert) \
 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
-  .info = snd_opl3sa2_info_single, \
+  .info = snd_wss_info_single, \
   .get = snd_opl3sa2_get_single, .put = snd_opl3sa2_put_single, \
   .private_value = reg | (shift << 8) | (mask << 16) | (invert << 24) }
 #define OPL3SA2_SINGLE_TLV(xname, xindex, reg, shift, mask, invert, xtlv) \
 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
   .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \
   .name = xname, .index = xindex, \
-  .info = snd_opl3sa2_info_single, \
+  .info = snd_wss_info_single, \
   .get = snd_opl3sa2_get_single, .put = snd_opl3sa2_put_single, \
   .private_value = reg | (shift << 8) | (mask << 16) | (invert << 24), \
   .tlv = { .p = (xtlv) } }
 
-static int snd_opl3sa2_info_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
-{
-	int mask = (kcontrol->private_value >> 16) & 0xff;
-
-	uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER;
-	uinfo->count = 1;
-	uinfo->value.integer.min = 0;
-	uinfo->value.integer.max = mask;
-	return 0;
-}
-
 static int snd_opl3sa2_get_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 {
 	struct snd_opl3sa2 *chip = snd_kcontrol_chip(kcontrol);
@@ -402,29 +393,18 @@
 
 #define OPL3SA2_DOUBLE(xname, xindex, left_reg, right_reg, shift_left, shift_right, mask, invert) \
 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
-  .info = snd_opl3sa2_info_double, \
+  .info = snd_wss_info_double, \
   .get = snd_opl3sa2_get_double, .put = snd_opl3sa2_put_double, \
   .private_value = left_reg | (right_reg << 8) | (shift_left << 16) | (shift_right << 19) | (mask << 24) | (invert << 22) }
 #define OPL3SA2_DOUBLE_TLV(xname, xindex, left_reg, right_reg, shift_left, shift_right, mask, invert, xtlv) \
 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
   .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \
   .name = xname, .index = xindex, \
-  .info = snd_opl3sa2_info_double, \
+  .info = snd_wss_info_double, \
   .get = snd_opl3sa2_get_double, .put = snd_opl3sa2_put_double, \
   .private_value = left_reg | (right_reg << 8) | (shift_left << 16) | (shift_right << 19) | (mask << 24) | (invert << 22), \
   .tlv = { .p = (xtlv) } }
 
-static int snd_opl3sa2_info_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
-{
-	int mask = (kcontrol->private_value >> 24) & 0xff;
-
-	uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER;
-	uinfo->count = 2;
-	uinfo->value.integer.min = 0;
-	uinfo->value.integer.max = mask;
-	return 0;
-}
-
 static int snd_opl3sa2_get_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 {
 	struct snd_opl3sa2 *chip = snd_kcontrol_chip(kcontrol);
@@ -512,9 +492,9 @@
 	chip->master_volume = NULL;
 }
 
-static int __devinit snd_opl3sa2_mixer(struct snd_opl3sa2 *chip)
+static int __devinit snd_opl3sa2_mixer(struct snd_card *card)
 {
-	struct snd_card *card = chip->card;
+	struct snd_opl3sa2 *chip = card->private_data;
 	struct snd_ctl_elem_id id1, id2;
 	struct snd_kcontrol *kctl;
 	unsigned int idx;
@@ -573,7 +553,7 @@
 	struct snd_opl3sa2 *chip = card->private_data;
 
 	snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
-	chip->cs4231->suspend(chip->cs4231);
+	chip->wss->suspend(chip->wss);
 	/* power down */
 	snd_opl3sa2_write(chip, OPL3SA2_PM_CTRL, OPL3SA2_PM_D3);
 
@@ -597,8 +577,8 @@
 		for (i = 0x12; i <= 0x16; i++)
 			snd_opl3sa2_write(chip, i, chip->ctlregs[i]);
 	}
-	/* restore cs4231 */
-	chip->cs4231->resume(chip->cs4231);
+	/* restore wss */
+	chip->wss->resume(chip->wss);
 
 	snd_power_change_state(card, SNDRV_CTL_POWER_D0);
 	return 0;
@@ -650,7 +630,6 @@
 	chip = card->private_data;
 	spin_lock_init(&chip->reg_lock);
 	chip->irq = -1;
-	chip->card = card;
 	card->private_free = snd_opl3sa2_free;
 	return card;
 }
@@ -659,7 +638,7 @@
 {
 	int xirq, xdma1, xdma2;
 	struct snd_opl3sa2 *chip;
-	struct snd_cs4231 *cs4231;
+	struct snd_wss *wss;
 	struct snd_opl3 *opl3;
 	int err;
 
@@ -672,30 +651,36 @@
 	xdma2 = dma2[dev];
 	if (xdma2 < 0)
 		chip->single_dma = 1;
-	if ((err = snd_opl3sa2_detect(chip)) < 0)
+	err = snd_opl3sa2_detect(card);
+	if (err < 0)
 		return err;
-	if (request_irq(xirq, snd_opl3sa2_interrupt, IRQF_DISABLED, "OPL3-SA2", chip)) {
+	err = request_irq(xirq, snd_opl3sa2_interrupt, IRQF_DISABLED,
+			  "OPL3-SA2", card);
+	if (err) {
 		snd_printk(KERN_ERR PFX "can't grab IRQ %d\n", xirq);
 		return -ENODEV;
 	}
 	chip->irq = xirq;
-	if ((err = snd_cs4231_create(card,
-				     wss_port[dev] + 4, -1,
-				     xirq, xdma1, xdma2,
-				     CS4231_HW_OPL3SA2,
-				     CS4231_HWSHARE_IRQ,
-				     &cs4231)) < 0) {
+	err = snd_wss_create(card,
+			     wss_port[dev] + 4, -1,
+			     xirq, xdma1, xdma2,
+			     WSS_HW_OPL3SA2, WSS_HWSHARE_IRQ, &wss);
+	if (err < 0) {
 		snd_printd("Oops, WSS not detected at 0x%lx\n", wss_port[dev] + 4);
 		return err;
 	}
-	chip->cs4231 = cs4231;
-	if ((err = snd_cs4231_pcm(cs4231, 0, NULL)) < 0)
+	chip->wss = wss;
+	err = snd_wss_pcm(wss, 0, NULL);
+	if (err < 0)
 		return err;
-	if ((err = snd_cs4231_mixer(cs4231)) < 0)
+	err = snd_wss_mixer(wss);
+	if (err < 0)
 		return err;
-	if ((err = snd_opl3sa2_mixer(chip)) < 0)
+	err = snd_opl3sa2_mixer(card);
+	if (err < 0)
 		return err;
-	if ((err = snd_cs4231_timer(cs4231, 0, NULL)) < 0)
+	err = snd_wss_timer(wss, 0, NULL);
+	if (err < 0)
 		return err;
 	if (fm_port[dev] >= 0x340 && fm_port[dev] < 0x400) {
 		if ((err = snd_opl3_create(card, fm_port[dev],
diff --git a/sound/isa/opti9xx/miro.c b/sound/isa/opti9xx/miro.c
index 2a1e2f5..440755c 100644
--- a/sound/isa/opti9xx/miro.c
+++ b/sound/isa/opti9xx/miro.c
@@ -32,7 +32,7 @@
 #include <asm/io.h>
 #include <asm/dma.h>
 #include <sound/core.h>
-#include <sound/cs4231.h>
+#include <sound/wss.h>
 #include <sound/mpu401.h>
 #include <sound/opl4.h>
 #include <sound/control.h>
@@ -675,7 +675,8 @@
 	unsigned int idx;
 	int err;
 
-	snd_assert(miro != NULL && miro->card != NULL, return -EINVAL);
+	if (snd_BUG_ON(!miro || !miro->card))
+		return -EINVAL;
 
 	card = miro->card;
 
@@ -1221,7 +1222,7 @@
 
 	int error;
 	struct snd_miro *miro;
-	struct snd_cs4231 *codec;
+	struct snd_wss *codec;
 	struct snd_timer *timer;
 	struct snd_card *card;
 	struct snd_pcm *pcm;
@@ -1310,29 +1311,32 @@
 		}
 	}
 
-	if ((error = snd_miro_configure(miro))) {
+	error = snd_miro_configure(miro);
+	if (error) {
 		snd_card_free(card);
 		return error;
 	}
 
-	if ((error = snd_cs4231_create(card, miro->wss_base + 4, -1,
-				       miro->irq, miro->dma1, miro->dma2,
-				       CS4231_HW_AD1845,
-				       0,
-				       &codec)) < 0) {
+	error = snd_wss_create(card, miro->wss_base + 4, -1,
+				miro->irq, miro->dma1, miro->dma2,
+				WSS_HW_AD1845, 0, &codec);
+	if (error < 0) {
 		snd_card_free(card);
 		return error;
 	}
 
-	if ((error = snd_cs4231_pcm(codec, 0, &pcm)) < 0) {
+	error = snd_wss_pcm(codec, 0, &pcm);
+	if (error < 0)  {
 		snd_card_free(card);
 		return error;
 	}
-	if ((error = snd_cs4231_mixer(codec)) < 0) {
+	error = snd_wss_mixer(codec);
+	if (error < 0) {
 		snd_card_free(card);
 		return error;
 	}
-	if ((error = snd_cs4231_timer(codec, 0, &timer)) < 0) {
+	error = snd_wss_timer(codec, 0, &timer);
+	if (error < 0) {
 		snd_card_free(card);
 		return error;
 	}
diff --git a/sound/isa/opti9xx/opti92x-ad1848.c b/sound/isa/opti9xx/opti92x-ad1848.c
index 0797ca4..19706b0 100644
--- a/sound/isa/opti9xx/opti92x-ad1848.c
+++ b/sound/isa/opti9xx/opti92x-ad1848.c
@@ -33,11 +33,7 @@
 #include <asm/io.h>
 #include <asm/dma.h>
 #include <sound/core.h>
-#if defined(CS4231) || defined(OPTi93X)
-#include <sound/cs4231.h>
-#else
-#include <sound/ad1848.h>
-#endif	/* CS4231 */
+#include <sound/wss.h>
 #include <sound/mpu401.h>
 #include <sound/opl3.h>
 #ifndef OPTi93X
@@ -139,7 +135,7 @@
 	unsigned long mc_base_size;
 #ifdef OPTi93X
 	unsigned long mc_indir_index;
-	struct snd_cs4231 *codec;
+	struct snd_wss *codec;
 #endif	/* OPTi93X */
 	unsigned long pwd_reg;
 
@@ -148,9 +144,7 @@
 	long wss_base;
 	int irq;
 	int dma1;
-#if defined(CS4231) || defined(OPTi93X)
 	int dma2;
-#endif	/* CS4231 || OPTi93X */
 
 	long fm_port;
 
@@ -225,9 +219,7 @@
 	chip->wss_base = -1;
 	chip->irq = -1;
 	chip->dma1 = -1;
-#if defined(CS4231) || defined (OPTi93X)
 	chip->dma2 = -1;
-#endif 	/* CS4231 || OPTi93X */
 	chip->fm_port = -1;
 	chip->mpu_port = -1;
 	chip->mpu_irq = -1;
@@ -562,7 +554,7 @@
 
 static irqreturn_t snd_opti93x_interrupt(int irq, void *dev_id)
 {
-	struct snd_cs4231 *codec = dev_id;
+	struct snd_wss *codec = dev_id;
 	struct snd_opti9xx *chip = codec->card->private_data;
 	unsigned char status;
 
@@ -570,7 +562,7 @@
 	if ((status & OPTi93X_IRQ_PLAYBACK) && codec->playback_substream)
 		snd_pcm_period_elapsed(codec->playback_substream);
 	if ((status & OPTi93X_IRQ_CAPTURE) && codec->capture_substream) {
-		snd_cs4231_overrange(codec);
+		snd_wss_overrange(codec);
 		snd_pcm_period_elapsed(codec->capture_substream);
 	}
 	outb(0x00, OPTi93X_PORT(codec, STATUS));
@@ -691,7 +683,7 @@
         
 	if (chip) {
 #ifdef OPTi93X
-		struct snd_cs4231 *codec = chip->codec;
+		struct snd_wss *codec = chip->codec;
 		if (codec && codec->irq > 0) {
 			disable_irq(codec->irq);
 			free_irq(codec->irq, codec);
@@ -706,14 +698,10 @@
 	static long possible_ports[] = {0x530, 0xe80, 0xf40, 0x604, -1};
 	int error;
 	struct snd_opti9xx *chip = card->private_data;
-#if defined(CS4231) || defined(OPTi93X)
-	struct snd_cs4231 *codec;
+	struct snd_wss *codec;
 #ifdef CS4231
 	struct snd_timer *timer;
 #endif
-#else
-	struct snd_ad1848 *codec;
-#endif
 	struct snd_pcm *pcm;
 	struct snd_rawmidi *rmidi;
 	struct snd_hwdep *synth;
@@ -731,38 +719,46 @@
 	chip->dma1 = dma1;
 #if defined(CS4231) || defined(OPTi93X)
 	chip->dma2 = dma2;
+#else
+	chip->dma2 = -1;
 #endif
 
 	if (chip->wss_base == SNDRV_AUTO_PORT) {
-		if ((chip->wss_base = snd_legacy_find_free_ioport(possible_ports, 4)) < 0) {
+		chip->wss_base = snd_legacy_find_free_ioport(possible_ports, 4);
+		if (chip->wss_base < 0) {
 			snd_printk("unable to find a free WSS port\n");
 			return -EBUSY;
 		}
 	}
-	if ((error = snd_opti9xx_configure(chip)))
+	error = snd_opti9xx_configure(chip);
+	if (error)
 		return error;
 
-#if defined(CS4231) || defined(OPTi93X)
-	if ((error = snd_cs4231_create(card, chip->wss_base + 4, -1,
-				       chip->irq, chip->dma1, chip->dma2,
-#ifdef CS4231
-				       CS4231_HW_DETECT, 0,
-#else /* OPTi93x */
-				       CS4231_HW_OPTI93X, CS4231_HWSHARE_IRQ,
+	error = snd_wss_create(card, chip->wss_base + 4, -1,
+			       chip->irq, chip->dma1, chip->dma2,
+#ifdef OPTi93X
+			       WSS_HW_OPTI93X, WSS_HWSHARE_IRQ,
+#else
+			       WSS_HW_DETECT, 0,
 #endif
-				       &codec)) < 0)
+			       &codec);
+	if (error < 0)
 		return error;
 #ifdef OPTi93X
 	chip->codec = codec;
 #endif
-	if ((error = snd_cs4231_pcm(codec, 0, &pcm)) < 0)
+	error = snd_wss_pcm(codec, 0, &pcm);
+	if (error < 0)
 		return error;
-	if ((error = snd_cs4231_mixer(codec)) < 0)
+	error = snd_wss_mixer(codec);
+	if (error < 0)
 		return error;
 #ifdef CS4231
-	if ((error = snd_cs4231_timer(codec, 0, &timer)) < 0)
+	error = snd_wss_timer(codec, 0, &timer);
+	if (error < 0)
 		return error;
-#else /* OPTI93X */
+#endif
+#ifdef OPTi93X
 	error = request_irq(chip->irq, snd_opti93x_interrupt,
 			    IRQF_DISABLED, DEV_NAME" - WSS", codec);
 	if (error < 0) {
@@ -770,16 +766,6 @@
 		return error;
 	}
 #endif
-#else
-	if ((error = snd_ad1848_create(card, chip->wss_base + 4,
-				       chip->irq, chip->dma1,
-				       AD1848_HW_DETECT, &codec)) < 0)
-		return error;
-	if ((error = snd_ad1848_pcm(codec, 0, &pcm)) < 0)
-		return error;
-	if ((error = snd_ad1848_mixer(codec)) < 0)
-		return error;
-#endif
 	strcpy(card->driver, chip->name);
 	sprintf(card->shortname, "OPTi %s", card->driver);
 #if defined(CS4231) || defined(OPTi93X)
diff --git a/sound/isa/sb/emu8000.c b/sound/isa/sb/emu8000.c
index b35be7d..96678d5 100644
--- a/sound/isa/sb/emu8000.c
+++ b/sound/isa/sb/emu8000.c
@@ -1023,7 +1023,8 @@
 {
 	int i, err = 0;
 
-	snd_assert(emu != NULL && card != NULL, return -EINVAL);
+	if (snd_BUG_ON(!emu || !card))
+		return -EINVAL;
 
 	spin_lock_init(&emu->control_lock);
 
diff --git a/sound/isa/sb/emu8000_patch.c b/sound/isa/sb/emu8000_patch.c
index 1be16c9..c99c607 100644
--- a/sound/isa/sb/emu8000_patch.c
+++ b/sound/isa/sb/emu8000_patch.c
@@ -156,7 +156,8 @@
 	struct snd_emu8000 *emu;
 
 	emu = rec->hw;
-	snd_assert(sp != NULL, return -EINVAL);
+	if (snd_BUG_ON(!sp))
+		return -EINVAL;
 
 	if (sp->v.size == 0)
 		return 0;
diff --git a/sound/isa/sb/sb16_csp.c b/sound/isa/sb/sb16_csp.c
index 35f3d7b..49037d0 100644
--- a/sound/isa/sb/sb16_csp.c
+++ b/sound/isa/sb/sb16_csp.c
@@ -198,7 +198,8 @@
 	struct snd_sb_csp_start start_info;
 	int err;
 
-	snd_assert(p != NULL, return -EINVAL);
+	if (snd_BUG_ON(!p))
+		return -EINVAL;
 
 	if (snd_sb_csp_check_version(p))
 		return -ENODEV;
@@ -1046,7 +1047,8 @@
 	struct snd_card *card;
 	int err;
 
-	snd_assert(p != NULL, return -EINVAL);
+	if (snd_BUG_ON(!p))
+		return -EINVAL;
 
 	card = p->chip->card;
 	p->qpos_left = p->qpos_right = SNDRV_SB_CSP_QSOUND_MAX_RIGHT / 2;
@@ -1071,7 +1073,8 @@
 	struct snd_card *card;
 	unsigned long flags;
 
-	snd_assert(p != NULL, return);
+	if (snd_BUG_ON(!p))
+		return;
 
 	card = p->chip->card;	
 	
diff --git a/sound/isa/sb/sb16_main.c b/sound/isa/sb/sb16_main.c
index f7e8192..2a6cc1c 100644
--- a/sound/isa/sb/sb16_main.c
+++ b/sound/isa/sb/sb16_main.c
@@ -669,7 +669,8 @@
 static int snd_sb16_set_dma_mode(struct snd_sb *chip, int what)
 {
 	if (chip->dma8 < 0 || chip->dma16 < 0) {
-		snd_assert(what == 0, return -EINVAL);
+		if (snd_BUG_ON(what))
+			return -EINVAL;
 		return 0;
 	}
 	if (what == 0) {
diff --git a/sound/isa/sb/sb8_main.c b/sound/isa/sb/sb8_main.c
index fe03bb8..658d557 100644
--- a/sound/isa/sb/sb8_main.c
+++ b/sound/isa/sb/sb8_main.c
@@ -111,7 +111,9 @@
 	switch (chip->hardware) {
 	case SB_HW_PRO:
 		if (runtime->channels > 1) {
-			snd_assert(rate == SB8_RATE(11025) || rate == SB8_RATE(22050), return -EINVAL);
+			if (snd_BUG_ON(rate != SB8_RATE(11025) &&
+				       rate != SB8_RATE(22050)))
+				return -EINVAL;
 			chip->playback_format = SB_DSP_HI_OUTPUT_AUTO;
 			break;
 		}
@@ -237,7 +239,9 @@
 	switch (chip->hardware) {
 	case SB_HW_PRO:
 		if (runtime->channels > 1) {
-			snd_assert(rate == SB8_RATE(11025) || rate == SB8_RATE(22050), return -EINVAL);
+			if (snd_BUG_ON(rate != SB8_RATE(11025) &&
+				       rate != SB8_RATE(22050)))
+				return -EINVAL;
 			chip->capture_format = SB_DSP_HI_INPUT_AUTO;
 			break;
 		}
diff --git a/sound/isa/sb/sb_common.c b/sound/isa/sb/sb_common.c
index b432d9a..27a6515 100644
--- a/sound/isa/sb/sb_common.c
+++ b/sound/isa/sb/sb_common.c
@@ -219,7 +219,8 @@
 		.dev_free =	snd_sbdsp_dev_free,
 	};
 
-	snd_assert(r_chip != NULL, return -EINVAL);
+	if (snd_BUG_ON(!r_chip))
+		return -EINVAL;
 	*r_chip = NULL;
 	chip = kzalloc(sizeof(*chip), GFP_KERNEL);
 	if (chip == NULL)
diff --git a/sound/isa/sb/sb_mixer.c b/sound/isa/sb/sb_mixer.c
index 73d4572..406a431 100644
--- a/sound/isa/sb/sb_mixer.c
+++ b/sound/isa/sb/sb_mixer.c
@@ -792,7 +792,8 @@
 	struct snd_card *card;
 	int err;
 
-	snd_assert(chip != NULL && chip->card != NULL, return -EINVAL);
+	if (snd_BUG_ON(!chip || !chip->card))
+		return -EINVAL;
 
 	card = chip->card;
 
@@ -925,7 +926,8 @@
 static void save_mixer(struct snd_sb *chip, unsigned char *regs, int num_regs)
 {
 	unsigned char *val = chip->saved_regs;
-	snd_assert(num_regs <= ARRAY_SIZE(chip->saved_regs), return);
+	if (snd_BUG_ON(num_regs > ARRAY_SIZE(chip->saved_regs)))
+		return;
 	for (; num_regs; num_regs--)
 		*val++ = snd_sbmixer_read(chip, *regs++);
 }
@@ -933,7 +935,8 @@
 static void restore_mixer(struct snd_sb *chip, unsigned char *regs, int num_regs)
 {
 	unsigned char *val = chip->saved_regs;
-	snd_assert(num_regs <= ARRAY_SIZE(chip->saved_regs), return);
+	if (snd_BUG_ON(num_regs > ARRAY_SIZE(chip->saved_regs)))
+		return;
 	for (; num_regs; num_regs--)
 		snd_sbmixer_write(chip, *regs++, *val++);
 }
diff --git a/sound/isa/sc6000.c b/sound/isa/sc6000.c
index da3d152..ca35924 100644
--- a/sound/isa/sc6000.c
+++ b/sound/isa/sc6000.c
@@ -29,7 +29,7 @@
 #include <linux/io.h>
 #include <asm/dma.h>
 #include <sound/core.h>
-#include <sound/ad1848.h>
+#include <sound/wss.h>
 #include <sound/opl3.h>
 #include <sound/mpu401.h>
 #include <sound/control.h>
@@ -397,7 +397,7 @@
 	return 0;
 }
 
-static int __devinit snd_sc6000_mixer(struct snd_ad1848 *chip)
+static int __devinit snd_sc6000_mixer(struct snd_wss *chip)
 {
 	struct snd_card *card = chip->card;
 	struct snd_ctl_elem_id id1, id2;
@@ -483,7 +483,7 @@
 	int xirq = irq[dev];
 	int xdma = dma[dev];
 	struct snd_card *card;
-	struct snd_ad1848 *chip;
+	struct snd_wss *chip;
 	struct snd_opl3 *opl3;
 	char __iomem *vport;
 	char __iomem *vmss_port;
@@ -548,21 +548,21 @@
 	if (err < 0)
 		goto err_unmap2;
 
-	err = snd_ad1848_create(card, mss_port[dev] + 4, xirq, xdma,
-				AD1848_HW_DETECT, &chip);
+	err = snd_wss_create(card, mss_port[dev] + 4,  -1, xirq, xdma, -1,
+			     WSS_HW_DETECT, 0, &chip);
 	if (err < 0)
 		goto err_unmap2;
 	card->private_data = chip;
 
-	err = snd_ad1848_pcm(chip, 0, NULL);
+	err = snd_wss_pcm(chip, 0, NULL);
 	if (err < 0) {
 		snd_printk(KERN_ERR PFX
-			   "error creating new ad1848 PCM device\n");
+			   "error creating new WSS PCM device\n");
 		goto err_unmap2;
 	}
-	err = snd_ad1848_mixer(chip);
+	err = snd_wss_mixer(chip);
 	if (err < 0) {
-		snd_printk(KERN_ERR PFX "error creating new ad1848 mixer\n");
+		snd_printk(KERN_ERR PFX "error creating new WSS mixer\n");
 		goto err_unmap2;
 	}
 	err = snd_sc6000_mixer(chip);
diff --git a/sound/isa/sgalaxy.c b/sound/isa/sgalaxy.c
index a07274e..2c7503b 100644
--- a/sound/isa/sgalaxy.c
+++ b/sound/isa/sgalaxy.c
@@ -31,7 +31,7 @@
 #include <asm/dma.h>
 #include <sound/core.h>
 #include <sound/sb.h>
-#include <sound/ad1848.h>
+#include <sound/wss.h>
 #include <sound/control.h>
 #define SNDRV_LEGACY_FIND_FREE_IRQ
 #define SNDRV_LEGACY_FIND_FREE_DMA
@@ -175,12 +175,14 @@
 	return snd_sgalaxy_setup_wss(wssport[dev], irq, dma);
 }
 
-static struct ad1848_mix_elem snd_sgalaxy_controls[] = {
-AD1848_DOUBLE("Aux Playback Switch", 0, SGALAXY_AUXC_LEFT, SGALAXY_AUXC_RIGHT, 7, 7, 1, 1),
-AD1848_DOUBLE("Aux Playback Volume", 0, SGALAXY_AUXC_LEFT, SGALAXY_AUXC_RIGHT, 0, 0, 31, 0)
+static struct snd_kcontrol_new snd_sgalaxy_controls[] = {
+WSS_DOUBLE("Aux Playback Switch", 0,
+		SGALAXY_AUXC_LEFT, SGALAXY_AUXC_RIGHT, 7, 7, 1, 1),
+WSS_DOUBLE("Aux Playback Volume", 0,
+		SGALAXY_AUXC_LEFT, SGALAXY_AUXC_RIGHT, 0, 0, 31, 0)
 };
 
-static int __devinit snd_sgalaxy_mixer(struct snd_ad1848 *chip)
+static int __devinit snd_sgalaxy_mixer(struct snd_wss *chip)
 {
 	struct snd_card *card = chip->card;
 	struct snd_ctl_elem_id id1, id2;
@@ -210,7 +212,9 @@
 		return err;
 	/* build AUX2 input */
 	for (idx = 0; idx < ARRAY_SIZE(snd_sgalaxy_controls); idx++) {
-		if ((err = snd_ad1848_add_ctl_elem(chip, &snd_sgalaxy_controls[idx])) < 0)
+		err = snd_ctl_add(card,
+				snd_ctl_new1(&snd_sgalaxy_controls[idx], chip));
+		if (err < 0)
 			return err;
 	}
 	return 0;
@@ -237,7 +241,7 @@
 	static int possible_dmas[] = {1, 3, 0, -1};
 	int err, xirq, xdma1;
 	struct snd_card *card;
-	struct snd_ad1848 *chip;
+	struct snd_wss *chip;
 
 	card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
 	if (card == NULL)
@@ -263,18 +267,21 @@
 	if ((err = snd_sgalaxy_detect(dev, xirq, xdma1)) < 0)
 		goto _err;
 
-	if ((err = snd_ad1848_create(card, wssport[dev] + 4,
-				     xirq, xdma1,
-				     AD1848_HW_DETECT, &chip)) < 0)
+	err = snd_wss_create(card, wssport[dev] + 4, -1,
+			     xirq, xdma1, -1,
+			     WSS_HW_DETECT, 0, &chip);
+	if (err < 0)
 		goto _err;
 	card->private_data = chip;
 
-	if ((err = snd_ad1848_pcm(chip, 0, NULL)) < 0) {
-		snd_printdd(PFX "error creating new ad1848 PCM device\n");
+	err = snd_wss_pcm(chip, 0, NULL);
+	if (err < 0) {
+		snd_printdd(PFX "error creating new WSS PCM device\n");
 		goto _err;
 	}
-	if ((err = snd_ad1848_mixer(chip)) < 0) {
-		snd_printdd(PFX "error creating new ad1848 mixer\n");
+	err = snd_wss_mixer(chip);
+	if (err < 0) {
+		snd_printdd(PFX "error creating new WSS mixer\n");
 		goto _err;
 	}
 	if ((err = snd_sgalaxy_mixer(chip)) < 0) {
@@ -312,7 +319,7 @@
 			       pm_message_t state)
 {
 	struct snd_card *card = dev_get_drvdata(pdev);
-	struct snd_ad1848 *chip = card->private_data;
+	struct snd_wss *chip = card->private_data;
 
 	snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
 	chip->suspend(chip);
@@ -322,11 +329,11 @@
 static int snd_sgalaxy_resume(struct device *pdev, unsigned int n)
 {
 	struct snd_card *card = dev_get_drvdata(pdev);
-	struct snd_ad1848 *chip = card->private_data;
+	struct snd_wss *chip = card->private_data;
 
 	chip->resume(chip);
-	snd_ad1848_out(chip, SGALAXY_AUXC_LEFT, chip->image[SGALAXY_AUXC_LEFT]);
-	snd_ad1848_out(chip, SGALAXY_AUXC_RIGHT, chip->image[SGALAXY_AUXC_RIGHT]);
+	snd_wss_out(chip, SGALAXY_AUXC_LEFT, chip->image[SGALAXY_AUXC_LEFT]);
+	snd_wss_out(chip, SGALAXY_AUXC_RIGHT, chip->image[SGALAXY_AUXC_RIGHT]);
 
 	snd_power_change_state(card, SNDRV_CTL_POWER_D0);
 	return 0;
diff --git a/sound/isa/sscape.c b/sound/isa/sscape.c
index 06ad786..48a16d8 100644
--- a/sound/isa/sscape.c
+++ b/sound/isa/sscape.c
@@ -31,7 +31,7 @@
 #include <asm/dma.h>
 #include <sound/core.h>
 #include <sound/hwdep.h>
-#include <sound/cs4231.h>
+#include <sound/wss.h>
 #include <sound/mpu401.h>
 #include <sound/initval.h>
 
@@ -147,7 +147,7 @@
 	enum card_type type;
 	struct resource *io_res;
 	struct resource *wss_res;
-	struct snd_cs4231 *chip;
+	struct snd_wss *chip;
 	struct snd_mpu401 *mpu;
 	struct snd_hwdep *hw;
 
@@ -726,7 +726,7 @@
 static int sscape_midi_get(struct snd_kcontrol *kctl,
                            struct snd_ctl_elem_value *uctl)
 {
-	struct snd_cs4231 *chip = snd_kcontrol_chip(kctl);
+	struct snd_wss *chip = snd_kcontrol_chip(kctl);
 	struct snd_card *card = chip->card;
 	register struct soundscape *s = get_card_soundscape(card);
 	unsigned long flags;
@@ -746,7 +746,7 @@
 static int sscape_midi_put(struct snd_kcontrol *kctl,
                            struct snd_ctl_elem_value *uctl)
 {
-	struct snd_cs4231 *chip = snd_kcontrol_chip(kctl);
+	struct snd_wss *chip = snd_kcontrol_chip(kctl);
 	struct snd_card *card = chip->card;
 	register struct soundscape *s = get_card_soundscape(card);
 	unsigned long flags;
@@ -958,7 +958,9 @@
  * Override for the CS4231 playback format function.
  * The AD1845 has much simpler format and rate selection.
  */
-static void ad1845_playback_format(struct snd_cs4231 * chip, struct snd_pcm_hw_params *params, unsigned char format)
+static void ad1845_playback_format(struct snd_wss *chip,
+				   struct snd_pcm_hw_params *params,
+				   unsigned char format)
 {
 	unsigned long flags;
 	unsigned rate = params_rate(params);
@@ -983,9 +985,9 @@
 	 * NOTE: We seem to need to write to the MSB before the LSB
 	 *       to get the correct sample frequency.
 	 */
-	snd_cs4231_out(chip, CS4231_PLAYBK_FORMAT, (format & 0xf0));
-	snd_cs4231_out(chip, AD1845_FREQ_SEL_MSB, (unsigned char) (rate >> 8));
-	snd_cs4231_out(chip, AD1845_FREQ_SEL_LSB, (unsigned char) rate);
+	snd_wss_out(chip, CS4231_PLAYBK_FORMAT, (format & 0xf0));
+	snd_wss_out(chip, AD1845_FREQ_SEL_MSB, (unsigned char) (rate >> 8));
+	snd_wss_out(chip, AD1845_FREQ_SEL_LSB, (unsigned char) rate);
 
 	spin_unlock_irqrestore(&chip->reg_lock, flags);
 }
@@ -994,7 +996,9 @@
  * Override for the CS4231 capture format function. 
  * The AD1845 has much simpler format and rate selection.
  */
-static void ad1845_capture_format(struct snd_cs4231 * chip, struct snd_pcm_hw_params *params, unsigned char format)
+static void ad1845_capture_format(struct snd_wss *chip,
+				  struct snd_pcm_hw_params *params,
+				  unsigned char format)
 {
 	unsigned long flags;
 	unsigned rate = params_rate(params);
@@ -1019,9 +1023,9 @@
 	 * NOTE: We seem to need to write to the MSB before the LSB
 	 *       to get the correct sample frequency.
 	 */
-	snd_cs4231_out(chip, CS4231_REC_FORMAT, (format & 0xf0));
-	snd_cs4231_out(chip, AD1845_FREQ_SEL_MSB, (unsigned char) (rate >> 8));
-	snd_cs4231_out(chip, AD1845_FREQ_SEL_LSB, (unsigned char) rate);
+	snd_wss_out(chip, CS4231_REC_FORMAT, (format & 0xf0));
+	snd_wss_out(chip, AD1845_FREQ_SEL_MSB, (unsigned char) (rate >> 8));
+	snd_wss_out(chip, AD1845_FREQ_SEL_LSB, (unsigned char) rate);
 
 	spin_unlock_irqrestore(&chip->reg_lock, flags);
 }
@@ -1036,7 +1040,7 @@
 				   int irq, int dma1, int dma2)
 {
 	register struct soundscape *sscape = get_card_soundscape(card);
-	struct snd_cs4231 *chip;
+	struct snd_wss *chip;
 	int err;
 
 	if (sscape->type == SSCAPE_VIVO)
@@ -1045,9 +1049,8 @@
 	if (dma1 == dma2)
 		dma2 = -1;
 
-	err = snd_cs4231_create(card,
-				port, -1, irq, dma1, dma2,
-				CS4231_HW_DETECT, CS4231_HWSHARE_DMA1, &chip);
+	err = snd_wss_create(card, port, -1, irq, dma1, dma2,
+			     WSS_HW_DETECT, WSS_HWSHARE_DMA1, &chip);
 	if (!err) {
 		unsigned long flags;
 		struct snd_pcm *pcm;
@@ -1063,11 +1066,11 @@
  *
 #define AD1845_IFACE_CONFIG  \
            (CS4231_AUTOCALIB | CS4231_RECORD_ENABLE | CS4231_PLAYBACK_ENABLE)
-    snd_cs4231_mce_up(chip);
+    snd_wss_mce_up(chip);
     spin_lock_irqsave(&chip->reg_lock, flags);
-    snd_cs4231_out(chip, CS4231_IFACE_CTRL, AD1845_IFACE_CONFIG);
+    snd_wss_out(chip, CS4231_IFACE_CTRL, AD1845_IFACE_CONFIG);
     spin_unlock_irqrestore(&chip->reg_lock, flags);
-    snd_cs4231_mce_down(chip);
+    snd_wss_mce_down(chip);
  */
 
 		if (sscape->type != SSCAPE_VIVO) {
@@ -1077,11 +1080,11 @@
 			 * be 14.31818 MHz, because we must set this register
 			 * to get the playback to sound correct ...
 			 */
-			snd_cs4231_mce_up(chip);
+			snd_wss_mce_up(chip);
 			spin_lock_irqsave(&chip->reg_lock, flags);
-			snd_cs4231_out(chip, AD1845_CRYS_CLOCK_SEL, 0x20);
+			snd_wss_out(chip, AD1845_CRYS_CLOCK_SEL, 0x20);
 			spin_unlock_irqrestore(&chip->reg_lock, flags);
-			snd_cs4231_mce_down(chip);
+			snd_wss_mce_down(chip);
 
 			/*
 			 * More custom configuration:
@@ -1089,28 +1092,28 @@
 			 * b) enable frequency selection (for capture/playback)
 			 */
 			spin_lock_irqsave(&chip->reg_lock, flags);
-			snd_cs4231_out(chip, CS4231_MISC_INFO,
-					CS4231_MODE2 | 0x10);
-			val = snd_cs4231_in(chip, AD1845_PWR_DOWN_CTRL);
-			snd_cs4231_out(chip, AD1845_PWR_DOWN_CTRL,
-					val | AD1845_FREQ_SEL_ENABLE);
+			snd_wss_out(chip, CS4231_MISC_INFO,
+				    CS4231_MODE2 | 0x10);
+			val = snd_wss_in(chip, AD1845_PWR_DOWN_CTRL);
+			snd_wss_out(chip, AD1845_PWR_DOWN_CTRL,
+				    val | AD1845_FREQ_SEL_ENABLE);
 			spin_unlock_irqrestore(&chip->reg_lock, flags);
 		}
 
-		err = snd_cs4231_pcm(chip, 0, &pcm);
+		err = snd_wss_pcm(chip, 0, &pcm);
 		if (err < 0) {
 			snd_printk(KERN_ERR "sscape: No PCM device "
 					    "for AD1845 chip\n");
 			goto _error;
 		}
 
-		err = snd_cs4231_mixer(chip);
+		err = snd_wss_mixer(chip);
 		if (err < 0) {
 			snd_printk(KERN_ERR "sscape: No mixer device "
 					    "for AD1845 chip\n");
 			goto _error;
 		}
-		err = snd_cs4231_timer(chip, 0, NULL);
+		err = snd_wss_timer(chip, 0, NULL);
 		if (err < 0) {
 			snd_printk(KERN_ERR "sscape: No timer device "
 					    "for AD1845 chip\n");
diff --git a/sound/isa/wavefront/wavefront.c b/sound/isa/wavefront/wavefront.c
index 3a6c6fe..4c095bc 100644
--- a/sound/isa/wavefront/wavefront.c
+++ b/sound/isa/wavefront/wavefront.c
@@ -1,6 +1,6 @@
 /*
  *  ALSA card-level driver for Turtle Beach Wavefront cards 
- *                                              (Maui,Tropez,Tropez+)
+ *						(Maui,Tropez,Tropez+)
  *
  *  Copyright (c) 1997-1999 by Paul Barton-Davis <pbd@op.net>
  *
@@ -29,6 +29,7 @@
 #include <sound/core.h>
 #include <sound/initval.h>
 #include <sound/opl3.h>
+#include <sound/wss.h>
 #include <sound/snd_wavefront.h>
 
 MODULE_AUTHOR("Paul Barton-Davis <pbd@op.net>");
@@ -319,8 +320,8 @@
 	snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, &snd_wavefront_midi_input);
 
 	rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT |
-	                     SNDRV_RAWMIDI_INFO_INPUT |
-	                     SNDRV_RAWMIDI_INFO_DUPLEX;
+			     SNDRV_RAWMIDI_INFO_INPUT |
+			     SNDRV_RAWMIDI_INFO_DUPLEX;
 
 	return rmidi;
 }
@@ -363,7 +364,7 @@
 snd_wavefront_probe (struct snd_card *card, int dev)
 {
 	snd_wavefront_card_t *acard = card->private_data;
-	struct snd_cs4231 *chip;
+	struct snd_wss *chip;
 	struct snd_hwdep *wavefront_synth;
 	struct snd_rawmidi *ics2115_internal_rmidi = NULL;
 	struct snd_rawmidi *ics2115_external_rmidi = NULL;
@@ -372,21 +373,20 @@
 
 	/* --------- PCM --------------- */
 
-	if ((err = snd_cs4231_create (card,
-				      cs4232_pcm_port[dev],
-				      -1,
-				      cs4232_pcm_irq[dev],
-				      dma1[dev],
-				      dma2[dev],
-				      CS4231_HW_DETECT, 0, &chip)) < 0) {
-		snd_printk (KERN_ERR "can't allocate CS4231 device\n");
+	err = snd_wss_create(card, cs4232_pcm_port[dev], -1,
+			     cs4232_pcm_irq[dev], dma1[dev], dma2[dev],
+			     WSS_HW_DETECT, 0, &chip);
+	if (err < 0) {
+		snd_printk(KERN_ERR "can't allocate WSS device\n");
 		return err;
 	}
 
-	if ((err = snd_cs4231_pcm (chip, 0, NULL)) < 0)
+	err = snd_wss_pcm(chip, 0, NULL);
+	if (err < 0)
 		return err;
 
-	if ((err = snd_cs4231_timer (chip, 0, NULL)) < 0)
+	err = snd_wss_timer(chip, 0, NULL);
+	if (err < 0)
 		return err;
 
 	/* ---------- OPL3 synth --------- */
@@ -394,24 +394,24 @@
 	if (fm_port[dev] > 0 && fm_port[dev] != SNDRV_AUTO_PORT) {
 		struct snd_opl3 *opl3;
 
-	        if ((err = snd_opl3_create(card,
-					   fm_port[dev],
-					   fm_port[dev] + 2,
-					   OPL3_HW_OPL3_CS,
-					   0, &opl3)) < 0) {
+		err = snd_opl3_create(card, fm_port[dev], fm_port[dev] + 2,
+				      OPL3_HW_OPL3_CS, 0, &opl3);
+		if (err < 0) {
 			snd_printk (KERN_ERR "can't allocate or detect OPL3 synth\n");
 			return err;
 		}
 
-		if ((err = snd_opl3_hwdep_new(opl3, hw_dev, 1, NULL)) < 0)
+		err = snd_opl3_hwdep_new(opl3, hw_dev, 1, NULL);
+		if (err < 0)
 			return err;
 		hw_dev++;
 	}
 
 	/* ------- ICS2115 Wavetable synth ------- */
 
-	if ((acard->wavefront.res_base = request_region(ics2115_port[dev], 16,
-							"ICS2115")) == NULL) {
+	acard->wavefront.res_base = request_region(ics2115_port[dev], 16,
+						   "ICS2115");
+	if (acard->wavefront.res_base == NULL) {
 		snd_printk(KERN_ERR "unable to grab ICS2115 i/o region 0x%lx-0x%lx\n",
 			   ics2115_port[dev], ics2115_port[dev] + 16 - 1);
 		return -EBUSY;
@@ -425,7 +425,8 @@
 	acard->wavefront.irq = ics2115_irq[dev];
 	acard->wavefront.base = ics2115_port[dev];
 
-	if ((wavefront_synth = snd_wavefront_new_synth (card, hw_dev, acard)) == NULL) {
+	wavefront_synth = snd_wavefront_new_synth(card, hw_dev, acard);
+	if (wavefront_synth == NULL) {
 		snd_printk (KERN_ERR "can't create WaveFront synth device\n");
 		return -ENOMEM;
 	}
@@ -436,7 +437,8 @@
 
 	/* --------- Mixer ------------ */
 
-	if ((err = snd_cs4231_mixer(chip)) < 0) {
+	err = snd_wss_mixer(chip);
+	if (err < 0) {
 		snd_printk (KERN_ERR "can't allocate mixer device\n");
 		return err;
 	}
@@ -444,11 +446,11 @@
 	/* -------- CS4232 MPU-401 interface -------- */
 
 	if (cs4232_mpu_port[dev] > 0 && cs4232_mpu_port[dev] != SNDRV_AUTO_PORT) {
-		if ((err = snd_mpu401_uart_new(card, midi_dev, MPU401_HW_CS4232,
-					       cs4232_mpu_port[dev], 0,
-					       cs4232_mpu_irq[dev],
-					       IRQF_DISABLED,
-					       NULL)) < 0) {
+		err = snd_mpu401_uart_new(card, midi_dev, MPU401_HW_CS4232,
+					  cs4232_mpu_port[dev], 0,
+					  cs4232_mpu_irq[dev], IRQF_DISABLED,
+					  NULL);
+		if (err < 0) {
 			snd_printk (KERN_ERR "can't allocate CS4232 MPU-401 device\n");
 			return err;
 		}
@@ -601,7 +603,7 @@
 
 #ifdef CONFIG_PNP
 static int __devinit snd_wavefront_pnp_detect(struct pnp_card_link *pcard,
-                                              const struct pnp_card_device_id *pid)
+					const struct pnp_card_device_id *pid)
 {
 	static int dev;
 	struct snd_card *card;
diff --git a/sound/isa/wavefront/wavefront_fx.c b/sound/isa/wavefront/wavefront_fx.c
index 2efaa7f..dfc449a 100644
--- a/sound/isa/wavefront/wavefront_fx.c
+++ b/sound/isa/wavefront/wavefront_fx.c
@@ -180,11 +180,11 @@
 	unsigned short *pd;
 	int err = 0;
 
-	snd_assert(sdev->card != NULL, return -ENODEV);
-	
 	card = sdev->card;
-
-	snd_assert(card->private_data != NULL, return -ENODEV);
+	if (snd_BUG_ON(!card))
+		return -ENODEV;
+	if (snd_BUG_ON(!card->private_data))
+		return -ENODEV;
 
 	acard = card->private_data;
 	dev = &acard->wavefront;
diff --git a/sound/isa/wavefront/wavefront_midi.c b/sound/isa/wavefront/wavefront_midi.c
index a33384a..f14a7c0 100644
--- a/sound/isa/wavefront/wavefront_midi.c
+++ b/sound/isa/wavefront/wavefront_midi.c
@@ -235,8 +235,10 @@
 	snd_wavefront_midi_t *midi;
 	snd_wavefront_mpu_id mpu;
 
-	snd_assert(substream != NULL && substream->rmidi != NULL, return -EIO);
-	snd_assert(substream->rmidi->private_data != NULL, return -EIO);
+	if (snd_BUG_ON(!substream || !substream->rmidi))
+		return -ENXIO;
+	if (snd_BUG_ON(!substream->rmidi->private_data))
+		return -ENXIO;
 
 	mpu = *((snd_wavefront_mpu_id *) substream->rmidi->private_data);
 
@@ -257,8 +259,10 @@
 	snd_wavefront_midi_t *midi;
 	snd_wavefront_mpu_id mpu;
 
-	snd_assert(substream != NULL && substream->rmidi != NULL, return -EIO);
-	snd_assert(substream->rmidi->private_data != NULL, return -EIO);
+	if (snd_BUG_ON(!substream || !substream->rmidi))
+		return -ENXIO;
+	if (snd_BUG_ON(!substream->rmidi->private_data))
+		return -ENXIO;
 
 	mpu = *((snd_wavefront_mpu_id *) substream->rmidi->private_data);
 
@@ -279,8 +283,10 @@
 	snd_wavefront_midi_t *midi;
 	snd_wavefront_mpu_id mpu;
 
-	snd_assert(substream != NULL && substream->rmidi != NULL, return -EIO);
-	snd_assert(substream->rmidi->private_data != NULL, return -EIO);
+	if (snd_BUG_ON(!substream || !substream->rmidi))
+		return -ENXIO;
+	if (snd_BUG_ON(!substream->rmidi->private_data))
+		return -ENXIO;
 
 	mpu = *((snd_wavefront_mpu_id *) substream->rmidi->private_data);
 
@@ -300,8 +306,10 @@
 	snd_wavefront_midi_t *midi;
 	snd_wavefront_mpu_id mpu;
 
-	snd_assert(substream != NULL && substream->rmidi != NULL, return -EIO);
-	snd_assert(substream->rmidi->private_data != NULL, return -EIO);
+	if (snd_BUG_ON(!substream || !substream->rmidi))
+		return -ENXIO;
+	if (snd_BUG_ON(!substream->rmidi->private_data))
+		return -ENXIO;
 
 	mpu = *((snd_wavefront_mpu_id *) substream->rmidi->private_data);
 
diff --git a/sound/isa/wavefront/wavefront_synth.c b/sound/isa/wavefront/wavefront_synth.c
index 0bb9b92..4c41082 100644
--- a/sound/isa/wavefront/wavefront_synth.c
+++ b/sound/isa/wavefront/wavefront_synth.c
@@ -1648,9 +1648,10 @@
 
 	card = (struct snd_card *) hw->card;
 
-	snd_assert(card != NULL, return -ENODEV);
-
-	snd_assert(card->private_data != NULL, return -ENODEV);
+	if (snd_BUG_ON(!card))
+		return -ENODEV;
+	if (snd_BUG_ON(!card->private_data))
+		return -ENODEV;
 
 	acard = card->private_data;
 	dev = &acard->wavefront;
diff --git a/sound/isa/wss/Makefile b/sound/isa/wss/Makefile
new file mode 100644
index 0000000..454fee7
--- /dev/null
+++ b/sound/isa/wss/Makefile
@@ -0,0 +1,10 @@
+#
+# Makefile for ALSA
+# Copyright (c) 2008 by Jaroslav Kysela <perex@perex.cz>
+#
+
+snd-wss-lib-objs := wss_lib.o
+
+# Toplevel Module Dependency
+obj-$(CONFIG_SND_WSS_LIB) += snd-wss-lib.o
+
diff --git a/sound/isa/wss/wss_lib.c b/sound/isa/wss/wss_lib.c
new file mode 100644
index 0000000..3d6c5f2
--- /dev/null
+++ b/sound/isa/wss/wss_lib.c
@@ -0,0 +1,2322 @@
+/*
+ *  Copyright (c) by Jaroslav Kysela <perex@perex.cz>
+ *  Routines for control of CS4231(A)/CS4232/InterWave & compatible chips
+ *
+ *  Bugs:
+ *     - sometimes record brokes playback with WSS portion of
+ *       Yamaha OPL3-SA3 chip
+ *     - CS4231 (GUS MAX) - still trouble with occasional noises
+ *			  - broken initialization?
+ *
+ *   This program is free software; you can redistribute it and/or 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/delay.h>
+#include <linux/pm.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/ioport.h>
+#include <sound/core.h>
+#include <sound/wss.h>
+#include <sound/pcm_params.h>
+#include <sound/tlv.h>
+
+#include <asm/io.h>
+#include <asm/dma.h>
+#include <asm/irq.h>
+
+MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
+MODULE_DESCRIPTION("Routines for control of CS4231(A)/CS4232/InterWave & compatible chips");
+MODULE_LICENSE("GPL");
+
+#if 0
+#define SNDRV_DEBUG_MCE
+#endif
+
+/*
+ *  Some variables
+ */
+
+static unsigned char freq_bits[14] = {
+	/* 5510 */	0x00 | CS4231_XTAL2,
+	/* 6620 */	0x0E | CS4231_XTAL2,
+	/* 8000 */	0x00 | CS4231_XTAL1,
+	/* 9600 */	0x0E | CS4231_XTAL1,
+	/* 11025 */	0x02 | CS4231_XTAL2,
+	/* 16000 */	0x02 | CS4231_XTAL1,
+	/* 18900 */	0x04 | CS4231_XTAL2,
+	/* 22050 */	0x06 | CS4231_XTAL2,
+	/* 27042 */	0x04 | CS4231_XTAL1,
+	/* 32000 */	0x06 | CS4231_XTAL1,
+	/* 33075 */	0x0C | CS4231_XTAL2,
+	/* 37800 */	0x08 | CS4231_XTAL2,
+	/* 44100 */	0x0A | CS4231_XTAL2,
+	/* 48000 */	0x0C | CS4231_XTAL1
+};
+
+static unsigned int rates[14] = {
+	5510, 6620, 8000, 9600, 11025, 16000, 18900, 22050,
+	27042, 32000, 33075, 37800, 44100, 48000
+};
+
+static struct snd_pcm_hw_constraint_list hw_constraints_rates = {
+	.count = ARRAY_SIZE(rates),
+	.list = rates,
+	.mask = 0,
+};
+
+static int snd_wss_xrate(struct snd_pcm_runtime *runtime)
+{
+	return snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
+					  &hw_constraints_rates);
+}
+
+static unsigned char snd_wss_original_image[32] =
+{
+	0x00,			/* 00/00 - lic */
+	0x00,			/* 01/01 - ric */
+	0x9f,			/* 02/02 - la1ic */
+	0x9f,			/* 03/03 - ra1ic */
+	0x9f,			/* 04/04 - la2ic */
+	0x9f,			/* 05/05 - ra2ic */
+	0xbf,			/* 06/06 - loc */
+	0xbf,			/* 07/07 - roc */
+	0x20,			/* 08/08 - pdfr */
+	CS4231_AUTOCALIB,	/* 09/09 - ic */
+	0x00,			/* 0a/10 - pc */
+	0x00,			/* 0b/11 - ti */
+	CS4231_MODE2,		/* 0c/12 - mi */
+	0xfc,			/* 0d/13 - lbc */
+	0x00,			/* 0e/14 - pbru */
+	0x00,			/* 0f/15 - pbrl */
+	0x80,			/* 10/16 - afei */
+	0x01,			/* 11/17 - afeii */
+	0x9f,			/* 12/18 - llic */
+	0x9f,			/* 13/19 - rlic */
+	0x00,			/* 14/20 - tlb */
+	0x00,			/* 15/21 - thb */
+	0x00,			/* 16/22 - la3mic/reserved */
+	0x00,			/* 17/23 - ra3mic/reserved */
+	0x00,			/* 18/24 - afs */
+	0x00,			/* 19/25 - lamoc/version */
+	0xcf,			/* 1a/26 - mioc */
+	0x00,			/* 1b/27 - ramoc/reserved */
+	0x20,			/* 1c/28 - cdfr */
+	0x00,			/* 1d/29 - res4 */
+	0x00,			/* 1e/30 - cbru */
+	0x00,			/* 1f/31 - cbrl */
+};
+
+static unsigned char snd_opti93x_original_image[32] =
+{
+	0x00,		/* 00/00 - l_mixout_outctrl */
+	0x00,		/* 01/01 - r_mixout_outctrl */
+	0x88,		/* 02/02 - l_cd_inctrl */
+	0x88,		/* 03/03 - r_cd_inctrl */
+	0x88,		/* 04/04 - l_a1/fm_inctrl */
+	0x88,		/* 05/05 - r_a1/fm_inctrl */
+	0x80,		/* 06/06 - l_dac_inctrl */
+	0x80,		/* 07/07 - r_dac_inctrl */
+	0x00,		/* 08/08 - ply_dataform_reg */
+	0x00,		/* 09/09 - if_conf */
+	0x00,		/* 0a/10 - pin_ctrl */
+	0x00,		/* 0b/11 - err_init_reg */
+	0x0a,		/* 0c/12 - id_reg */
+	0x00,		/* 0d/13 - reserved */
+	0x00,		/* 0e/14 - ply_upcount_reg */
+	0x00,		/* 0f/15 - ply_lowcount_reg */
+	0x88,		/* 10/16 - reserved/l_a1_inctrl */
+	0x88,		/* 11/17 - reserved/r_a1_inctrl */
+	0x88,		/* 12/18 - l_line_inctrl */
+	0x88,		/* 13/19 - r_line_inctrl */
+	0x88,		/* 14/20 - l_mic_inctrl */
+	0x88,		/* 15/21 - r_mic_inctrl */
+	0x80,		/* 16/22 - l_out_outctrl */
+	0x80,		/* 17/23 - r_out_outctrl */
+	0x00,		/* 18/24 - reserved */
+	0x00,		/* 19/25 - reserved */
+	0x00,		/* 1a/26 - reserved */
+	0x00,		/* 1b/27 - reserved */
+	0x00,		/* 1c/28 - cap_dataform_reg */
+	0x00,		/* 1d/29 - reserved */
+	0x00,		/* 1e/30 - cap_upcount_reg */
+	0x00		/* 1f/31 - cap_lowcount_reg */
+};
+
+/*
+ *  Basic I/O functions
+ */
+
+static inline void wss_outb(struct snd_wss *chip, u8 offset, u8 val)
+{
+	outb(val, chip->port + offset);
+}
+
+static inline u8 wss_inb(struct snd_wss *chip, u8 offset)
+{
+	return inb(chip->port + offset);
+}
+
+static void snd_wss_wait(struct snd_wss *chip)
+{
+	int timeout;
+
+	for (timeout = 250;
+	     timeout > 0 && (wss_inb(chip, CS4231P(REGSEL)) & CS4231_INIT);
+	     timeout--)
+		udelay(100);
+}
+
+static void snd_wss_outm(struct snd_wss *chip, unsigned char reg,
+			    unsigned char mask, unsigned char value)
+{
+	unsigned char tmp = (chip->image[reg] & mask) | value;
+
+	snd_wss_wait(chip);
+#ifdef CONFIG_SND_DEBUG
+	if (wss_inb(chip, CS4231P(REGSEL)) & CS4231_INIT)
+		snd_printk("outm: auto calibration time out - reg = 0x%x, value = 0x%x\n", reg, value);
+#endif
+	chip->image[reg] = tmp;
+	if (!chip->calibrate_mute) {
+		wss_outb(chip, CS4231P(REGSEL), chip->mce_bit | reg);
+		wmb();
+		wss_outb(chip, CS4231P(REG), tmp);
+		mb();
+	}
+}
+
+static void snd_wss_dout(struct snd_wss *chip, unsigned char reg,
+			 unsigned char value)
+{
+	int timeout;
+
+	for (timeout = 250;
+	     timeout > 0 && (wss_inb(chip, CS4231P(REGSEL)) & CS4231_INIT);
+	     timeout--)
+		udelay(10);
+	wss_outb(chip, CS4231P(REGSEL), chip->mce_bit | reg);
+	wss_outb(chip, CS4231P(REG), value);
+	mb();
+}
+
+void snd_wss_out(struct snd_wss *chip, unsigned char reg, unsigned char value)
+{
+	snd_wss_wait(chip);
+#ifdef CONFIG_SND_DEBUG
+	if (wss_inb(chip, CS4231P(REGSEL)) & CS4231_INIT)
+		snd_printk("out: auto calibration time out - reg = 0x%x, value = 0x%x\n", reg, value);
+#endif
+	wss_outb(chip, CS4231P(REGSEL), chip->mce_bit | reg);
+	wss_outb(chip, CS4231P(REG), value);
+	chip->image[reg] = value;
+	mb();
+	snd_printdd("codec out - reg 0x%x = 0x%x\n",
+			chip->mce_bit | reg, value);
+}
+EXPORT_SYMBOL(snd_wss_out);
+
+unsigned char snd_wss_in(struct snd_wss *chip, unsigned char reg)
+{
+	snd_wss_wait(chip);
+#ifdef CONFIG_SND_DEBUG
+	if (wss_inb(chip, CS4231P(REGSEL)) & CS4231_INIT)
+		snd_printk("in: auto calibration time out - reg = 0x%x\n", reg);
+#endif
+	wss_outb(chip, CS4231P(REGSEL), chip->mce_bit | reg);
+	mb();
+	return wss_inb(chip, CS4231P(REG));
+}
+EXPORT_SYMBOL(snd_wss_in);
+
+void snd_cs4236_ext_out(struct snd_wss *chip, unsigned char reg,
+			unsigned char val)
+{
+	wss_outb(chip, CS4231P(REGSEL), chip->mce_bit | 0x17);
+	wss_outb(chip, CS4231P(REG),
+		 reg | (chip->image[CS4236_EXT_REG] & 0x01));
+	wss_outb(chip, CS4231P(REG), val);
+	chip->eimage[CS4236_REG(reg)] = val;
+#if 0
+	printk("ext out : reg = 0x%x, val = 0x%x\n", reg, val);
+#endif
+}
+EXPORT_SYMBOL(snd_cs4236_ext_out);
+
+unsigned char snd_cs4236_ext_in(struct snd_wss *chip, unsigned char reg)
+{
+	wss_outb(chip, CS4231P(REGSEL), chip->mce_bit | 0x17);
+	wss_outb(chip, CS4231P(REG),
+		 reg | (chip->image[CS4236_EXT_REG] & 0x01));
+#if 1
+	return wss_inb(chip, CS4231P(REG));
+#else
+	{
+		unsigned char res;
+		res = wss_inb(chip, CS4231P(REG));
+		printk("ext in : reg = 0x%x, val = 0x%x\n", reg, res);
+		return res;
+	}
+#endif
+}
+EXPORT_SYMBOL(snd_cs4236_ext_in);
+
+#if 0
+
+static void snd_wss_debug(struct snd_wss *chip)
+{
+	printk(KERN_DEBUG
+		"CS4231 REGS:      INDEX = 0x%02x  "
+		"                 STATUS = 0x%02x\n",
+					wss_inb(chip, CS4231P(REGSEL)),
+					wss_inb(chip, CS4231P(STATUS)));
+	printk(KERN_DEBUG
+		"  0x00: left input      = 0x%02x  "
+		"  0x10: alt 1 (CFIG 2)  = 0x%02x\n",
+					snd_wss_in(chip, 0x00),
+					snd_wss_in(chip, 0x10));
+	printk(KERN_DEBUG
+		"  0x01: right input     = 0x%02x  "
+		"  0x11: alt 2 (CFIG 3)  = 0x%02x\n",
+					snd_wss_in(chip, 0x01),
+					snd_wss_in(chip, 0x11));
+	printk(KERN_DEBUG
+		"  0x02: GF1 left input  = 0x%02x  "
+		"  0x12: left line in    = 0x%02x\n",
+					snd_wss_in(chip, 0x02),
+					snd_wss_in(chip, 0x12));
+	printk(KERN_DEBUG
+		"  0x03: GF1 right input = 0x%02x  "
+		"  0x13: right line in   = 0x%02x\n",
+					snd_wss_in(chip, 0x03),
+					snd_wss_in(chip, 0x13));
+	printk(KERN_DEBUG
+		"  0x04: CD left input   = 0x%02x  "
+		"  0x14: timer low       = 0x%02x\n",
+					snd_wss_in(chip, 0x04),
+					snd_wss_in(chip, 0x14));
+	printk(KERN_DEBUG
+		"  0x05: CD right input  = 0x%02x  "
+		"  0x15: timer high      = 0x%02x\n",
+					snd_wss_in(chip, 0x05),
+					snd_wss_in(chip, 0x15));
+	printk(KERN_DEBUG
+		"  0x06: left output     = 0x%02x  "
+		"  0x16: left MIC (PnP)  = 0x%02x\n",
+					snd_wss_in(chip, 0x06),
+					snd_wss_in(chip, 0x16));
+	printk(KERN_DEBUG
+		"  0x07: right output    = 0x%02x  "
+		"  0x17: right MIC (PnP) = 0x%02x\n",
+					snd_wss_in(chip, 0x07),
+					snd_wss_in(chip, 0x17));
+	printk(KERN_DEBUG
+		"  0x08: playback format = 0x%02x  "
+		"  0x18: IRQ status      = 0x%02x\n",
+					snd_wss_in(chip, 0x08),
+					snd_wss_in(chip, 0x18));
+	printk(KERN_DEBUG
+		"  0x09: iface (CFIG 1)  = 0x%02x  "
+		"  0x19: left line out   = 0x%02x\n",
+					snd_wss_in(chip, 0x09),
+					snd_wss_in(chip, 0x19));
+	printk(KERN_DEBUG
+		"  0x0a: pin control     = 0x%02x  "
+		"  0x1a: mono control    = 0x%02x\n",
+					snd_wss_in(chip, 0x0a),
+					snd_wss_in(chip, 0x1a));
+	printk(KERN_DEBUG
+		"  0x0b: init & status   = 0x%02x  "
+		"  0x1b: right line out  = 0x%02x\n",
+					snd_wss_in(chip, 0x0b),
+					snd_wss_in(chip, 0x1b));
+	printk(KERN_DEBUG
+		"  0x0c: revision & mode = 0x%02x  "
+		"  0x1c: record format   = 0x%02x\n",
+					snd_wss_in(chip, 0x0c),
+					snd_wss_in(chip, 0x1c));
+	printk(KERN_DEBUG
+		"  0x0d: loopback        = 0x%02x  "
+		"  0x1d: var freq (PnP)  = 0x%02x\n",
+					snd_wss_in(chip, 0x0d),
+					snd_wss_in(chip, 0x1d));
+	printk(KERN_DEBUG
+		"  0x0e: ply upr count   = 0x%02x  "
+		"  0x1e: ply lwr count   = 0x%02x\n",
+					snd_wss_in(chip, 0x0e),
+					snd_wss_in(chip, 0x1e));
+	printk(KERN_DEBUG
+		"  0x0f: rec upr count   = 0x%02x  "
+		"  0x1f: rec lwr count   = 0x%02x\n",
+					snd_wss_in(chip, 0x0f),
+					snd_wss_in(chip, 0x1f));
+}
+
+#endif
+
+/*
+ *  CS4231 detection / MCE routines
+ */
+
+static void snd_wss_busy_wait(struct snd_wss *chip)
+{
+	int timeout;
+
+	/* huh.. looks like this sequence is proper for CS4231A chip (GUS MAX) */
+	for (timeout = 5; timeout > 0; timeout--)
+		wss_inb(chip, CS4231P(REGSEL));
+	/* end of cleanup sequence */
+	for (timeout = 25000;
+	     timeout > 0 && (wss_inb(chip, CS4231P(REGSEL)) & CS4231_INIT);
+	     timeout--)
+		udelay(10);
+}
+
+void snd_wss_mce_up(struct snd_wss *chip)
+{
+	unsigned long flags;
+	int timeout;
+
+	snd_wss_wait(chip);
+#ifdef CONFIG_SND_DEBUG
+	if (wss_inb(chip, CS4231P(REGSEL)) & CS4231_INIT)
+		snd_printk("mce_up - auto calibration time out (0)\n");
+#endif
+	spin_lock_irqsave(&chip->reg_lock, flags);
+	chip->mce_bit |= CS4231_MCE;
+	timeout = wss_inb(chip, CS4231P(REGSEL));
+	if (timeout == 0x80)
+		snd_printk("mce_up [0x%lx]: serious init problem - codec still busy\n", chip->port);
+	if (!(timeout & CS4231_MCE))
+		wss_outb(chip, CS4231P(REGSEL),
+			 chip->mce_bit | (timeout & 0x1f));
+	spin_unlock_irqrestore(&chip->reg_lock, flags);
+}
+EXPORT_SYMBOL(snd_wss_mce_up);
+
+void snd_wss_mce_down(struct snd_wss *chip)
+{
+	unsigned long flags;
+	unsigned long end_time;
+	int timeout;
+	int hw_mask = WSS_HW_CS4231_MASK | WSS_HW_CS4232_MASK | WSS_HW_AD1848;
+
+	snd_wss_busy_wait(chip);
+
+#ifdef CONFIG_SND_DEBUG
+	if (wss_inb(chip, CS4231P(REGSEL)) & CS4231_INIT)
+		snd_printk("mce_down [0x%lx] - auto calibration time out (0)\n", (long)CS4231P(REGSEL));
+#endif
+	spin_lock_irqsave(&chip->reg_lock, flags);
+	chip->mce_bit &= ~CS4231_MCE;
+	timeout = wss_inb(chip, CS4231P(REGSEL));
+	wss_outb(chip, CS4231P(REGSEL), chip->mce_bit | (timeout & 0x1f));
+	spin_unlock_irqrestore(&chip->reg_lock, flags);
+	if (timeout == 0x80)
+		snd_printk("mce_down [0x%lx]: serious init problem - codec still busy\n", chip->port);
+	if ((timeout & CS4231_MCE) == 0 || !(chip->hardware & hw_mask))
+		return;
+
+	/*
+	 * Wait for (possible -- during init auto-calibration may not be set)
+	 * calibration process to start. Needs upto 5 sample periods on AD1848
+	 * which at the slowest possible rate of 5.5125 kHz means 907 us.
+	 */
+	msleep(1);
+
+	snd_printdd("(1) jiffies = %lu\n", jiffies);
+
+	/* check condition up to 250 ms */
+	end_time = jiffies + msecs_to_jiffies(250);
+	while (snd_wss_in(chip, CS4231_TEST_INIT) &
+		CS4231_CALIB_IN_PROGRESS) {
+
+		if (time_after(jiffies, end_time)) {
+			snd_printk(KERN_ERR "mce_down - "
+					"auto calibration time out (2)\n");
+			return;
+		}
+		msleep(1);
+	}
+
+	snd_printdd("(2) jiffies = %lu\n", jiffies);
+
+	/* check condition up to 100 ms */
+	end_time = jiffies + msecs_to_jiffies(100);
+	while (wss_inb(chip, CS4231P(REGSEL)) & CS4231_INIT) {
+		if (time_after(jiffies, end_time)) {
+			snd_printk(KERN_ERR "mce_down - auto calibration time out (3)\n");
+			return;
+		}
+		msleep(1);
+	}
+
+	snd_printdd("(3) jiffies = %lu\n", jiffies);
+	snd_printd("mce_down - exit = 0x%x\n", wss_inb(chip, CS4231P(REGSEL)));
+}
+EXPORT_SYMBOL(snd_wss_mce_down);
+
+static unsigned int snd_wss_get_count(unsigned char format, unsigned int size)
+{
+	switch (format & 0xe0) {
+	case CS4231_LINEAR_16:
+	case CS4231_LINEAR_16_BIG:
+		size >>= 1;
+		break;
+	case CS4231_ADPCM_16:
+		return size >> 2;
+	}
+	if (format & CS4231_STEREO)
+		size >>= 1;
+	return size;
+}
+
+static int snd_wss_trigger(struct snd_pcm_substream *substream,
+			   int cmd)
+{
+	struct snd_wss *chip = snd_pcm_substream_chip(substream);
+	int result = 0;
+	unsigned int what;
+	struct snd_pcm_substream *s;
+	int do_start;
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_RESUME:
+		do_start = 1; break;
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+		do_start = 0; break;
+	default:
+		return -EINVAL;
+	}
+
+	what = 0;
+	snd_pcm_group_for_each_entry(s, substream) {
+		if (s == chip->playback_substream) {
+			what |= CS4231_PLAYBACK_ENABLE;
+			snd_pcm_trigger_done(s, substream);
+		} else if (s == chip->capture_substream) {
+			what |= CS4231_RECORD_ENABLE;
+			snd_pcm_trigger_done(s, substream);
+		}
+	}
+	spin_lock(&chip->reg_lock);
+	if (do_start) {
+		chip->image[CS4231_IFACE_CTRL] |= what;
+		if (chip->trigger)
+			chip->trigger(chip, what, 1);
+	} else {
+		chip->image[CS4231_IFACE_CTRL] &= ~what;
+		if (chip->trigger)
+			chip->trigger(chip, what, 0);
+	}
+	snd_wss_out(chip, CS4231_IFACE_CTRL, chip->image[CS4231_IFACE_CTRL]);
+	spin_unlock(&chip->reg_lock);
+#if 0
+	snd_wss_debug(chip);
+#endif
+	return result;
+}
+
+/*
+ *  CODEC I/O
+ */
+
+static unsigned char snd_wss_get_rate(unsigned int rate)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(rates); i++)
+		if (rate == rates[i])
+			return freq_bits[i];
+	// snd_BUG();
+	return freq_bits[ARRAY_SIZE(rates) - 1];
+}
+
+static unsigned char snd_wss_get_format(struct snd_wss *chip,
+					int format,
+					int channels)
+{
+	unsigned char rformat;
+
+	rformat = CS4231_LINEAR_8;
+	switch (format) {
+	case SNDRV_PCM_FORMAT_MU_LAW:	rformat = CS4231_ULAW_8; break;
+	case SNDRV_PCM_FORMAT_A_LAW:	rformat = CS4231_ALAW_8; break;
+	case SNDRV_PCM_FORMAT_S16_LE:	rformat = CS4231_LINEAR_16; break;
+	case SNDRV_PCM_FORMAT_S16_BE:	rformat = CS4231_LINEAR_16_BIG; break;
+	case SNDRV_PCM_FORMAT_IMA_ADPCM:	rformat = CS4231_ADPCM_16; break;
+	}
+	if (channels > 1)
+		rformat |= CS4231_STEREO;
+#if 0
+	snd_printk("get_format: 0x%x (mode=0x%x)\n", format, mode);
+#endif
+	return rformat;
+}
+
+static void snd_wss_calibrate_mute(struct snd_wss *chip, int mute)
+{
+	unsigned long flags;
+
+	mute = mute ? 0x80 : 0;
+	spin_lock_irqsave(&chip->reg_lock, flags);
+	if (chip->calibrate_mute == mute) {
+		spin_unlock_irqrestore(&chip->reg_lock, flags);
+		return;
+	}
+	if (!mute) {
+		snd_wss_dout(chip, CS4231_LEFT_INPUT,
+			     chip->image[CS4231_LEFT_INPUT]);
+		snd_wss_dout(chip, CS4231_RIGHT_INPUT,
+			     chip->image[CS4231_RIGHT_INPUT]);
+		snd_wss_dout(chip, CS4231_LOOPBACK,
+			     chip->image[CS4231_LOOPBACK]);
+	}
+	snd_wss_dout(chip, CS4231_AUX1_LEFT_INPUT,
+		     mute | chip->image[CS4231_AUX1_LEFT_INPUT]);
+	snd_wss_dout(chip, CS4231_AUX1_RIGHT_INPUT,
+		     mute | chip->image[CS4231_AUX1_RIGHT_INPUT]);
+	snd_wss_dout(chip, CS4231_AUX2_LEFT_INPUT,
+		     mute | chip->image[CS4231_AUX2_LEFT_INPUT]);
+	snd_wss_dout(chip, CS4231_AUX2_RIGHT_INPUT,
+		     mute | chip->image[CS4231_AUX2_RIGHT_INPUT]);
+	snd_wss_dout(chip, CS4231_LEFT_OUTPUT,
+		     mute | chip->image[CS4231_LEFT_OUTPUT]);
+	snd_wss_dout(chip, CS4231_RIGHT_OUTPUT,
+		     mute | chip->image[CS4231_RIGHT_OUTPUT]);
+	if (!(chip->hardware & WSS_HW_AD1848_MASK)) {
+		snd_wss_dout(chip, CS4231_LEFT_LINE_IN,
+			     mute | chip->image[CS4231_LEFT_LINE_IN]);
+		snd_wss_dout(chip, CS4231_RIGHT_LINE_IN,
+			     mute | chip->image[CS4231_RIGHT_LINE_IN]);
+		snd_wss_dout(chip, CS4231_MONO_CTRL,
+			     mute ? 0xc0 : chip->image[CS4231_MONO_CTRL]);
+	}
+	if (chip->hardware == WSS_HW_INTERWAVE) {
+		snd_wss_dout(chip, CS4231_LEFT_MIC_INPUT,
+			     mute | chip->image[CS4231_LEFT_MIC_INPUT]);
+		snd_wss_dout(chip, CS4231_RIGHT_MIC_INPUT,
+			     mute | chip->image[CS4231_RIGHT_MIC_INPUT]);
+		snd_wss_dout(chip, CS4231_LINE_LEFT_OUTPUT,
+			     mute | chip->image[CS4231_LINE_LEFT_OUTPUT]);
+		snd_wss_dout(chip, CS4231_LINE_RIGHT_OUTPUT,
+			     mute | chip->image[CS4231_LINE_RIGHT_OUTPUT]);
+	}
+	chip->calibrate_mute = mute;
+	spin_unlock_irqrestore(&chip->reg_lock, flags);
+}
+
+static void snd_wss_playback_format(struct snd_wss *chip,
+				       struct snd_pcm_hw_params *params,
+				       unsigned char pdfr)
+{
+	unsigned long flags;
+	int full_calib = 1;
+
+	mutex_lock(&chip->mce_mutex);
+	snd_wss_calibrate_mute(chip, 1);
+	if (chip->hardware == WSS_HW_CS4231A ||
+	    (chip->hardware & WSS_HW_CS4232_MASK)) {
+		spin_lock_irqsave(&chip->reg_lock, flags);
+		if ((chip->image[CS4231_PLAYBK_FORMAT] & 0x0f) == (pdfr & 0x0f)) {	/* rate is same? */
+			snd_wss_out(chip, CS4231_ALT_FEATURE_1,
+				    chip->image[CS4231_ALT_FEATURE_1] | 0x10);
+			chip->image[CS4231_PLAYBK_FORMAT] = pdfr;
+			snd_wss_out(chip, CS4231_PLAYBK_FORMAT,
+				    chip->image[CS4231_PLAYBK_FORMAT]);
+			snd_wss_out(chip, CS4231_ALT_FEATURE_1,
+				    chip->image[CS4231_ALT_FEATURE_1] &= ~0x10);
+			udelay(100); /* Fixes audible clicks at least on GUS MAX */
+			full_calib = 0;
+		}
+		spin_unlock_irqrestore(&chip->reg_lock, flags);
+	}
+	if (full_calib) {
+		snd_wss_mce_up(chip);
+		spin_lock_irqsave(&chip->reg_lock, flags);
+		if (chip->hardware != WSS_HW_INTERWAVE && !chip->single_dma) {
+			if (chip->image[CS4231_IFACE_CTRL] & CS4231_RECORD_ENABLE)
+				pdfr = (pdfr & 0xf0) |
+				       (chip->image[CS4231_REC_FORMAT] & 0x0f);
+		} else {
+			chip->image[CS4231_PLAYBK_FORMAT] = pdfr;
+		}
+		snd_wss_out(chip, CS4231_PLAYBK_FORMAT, pdfr);
+		spin_unlock_irqrestore(&chip->reg_lock, flags);
+		if (chip->hardware == WSS_HW_OPL3SA2)
+			udelay(100);	/* this seems to help */
+		snd_wss_mce_down(chip);
+	}
+	snd_wss_calibrate_mute(chip, 0);
+	mutex_unlock(&chip->mce_mutex);
+}
+
+static void snd_wss_capture_format(struct snd_wss *chip,
+				   struct snd_pcm_hw_params *params,
+				   unsigned char cdfr)
+{
+	unsigned long flags;
+	int full_calib = 1;
+
+	mutex_lock(&chip->mce_mutex);
+	snd_wss_calibrate_mute(chip, 1);
+	if (chip->hardware == WSS_HW_CS4231A ||
+	    (chip->hardware & WSS_HW_CS4232_MASK)) {
+		spin_lock_irqsave(&chip->reg_lock, flags);
+		if ((chip->image[CS4231_PLAYBK_FORMAT] & 0x0f) == (cdfr & 0x0f) ||	/* rate is same? */
+		    (chip->image[CS4231_IFACE_CTRL] & CS4231_PLAYBACK_ENABLE)) {
+			snd_wss_out(chip, CS4231_ALT_FEATURE_1,
+				chip->image[CS4231_ALT_FEATURE_1] | 0x20);
+			snd_wss_out(chip, CS4231_REC_FORMAT,
+				chip->image[CS4231_REC_FORMAT] = cdfr);
+			snd_wss_out(chip, CS4231_ALT_FEATURE_1,
+				chip->image[CS4231_ALT_FEATURE_1] &= ~0x20);
+			full_calib = 0;
+		}
+		spin_unlock_irqrestore(&chip->reg_lock, flags);
+	}
+	if (full_calib) {
+		snd_wss_mce_up(chip);
+		spin_lock_irqsave(&chip->reg_lock, flags);
+		if (chip->hardware != WSS_HW_INTERWAVE &&
+		    !(chip->image[CS4231_IFACE_CTRL] & CS4231_PLAYBACK_ENABLE)) {
+			if (chip->single_dma)
+				snd_wss_out(chip, CS4231_PLAYBK_FORMAT, cdfr);
+			else
+				snd_wss_out(chip, CS4231_PLAYBK_FORMAT,
+				   (chip->image[CS4231_PLAYBK_FORMAT] & 0xf0) |
+				   (cdfr & 0x0f));
+			spin_unlock_irqrestore(&chip->reg_lock, flags);
+			snd_wss_mce_down(chip);
+			snd_wss_mce_up(chip);
+			spin_lock_irqsave(&chip->reg_lock, flags);
+		}
+		if (chip->hardware & WSS_HW_AD1848_MASK)
+			snd_wss_out(chip, CS4231_PLAYBK_FORMAT, cdfr);
+		else
+			snd_wss_out(chip, CS4231_REC_FORMAT, cdfr);
+		spin_unlock_irqrestore(&chip->reg_lock, flags);
+		snd_wss_mce_down(chip);
+	}
+	snd_wss_calibrate_mute(chip, 0);
+	mutex_unlock(&chip->mce_mutex);
+}
+
+/*
+ *  Timer interface
+ */
+
+static unsigned long snd_wss_timer_resolution(struct snd_timer *timer)
+{
+	struct snd_wss *chip = snd_timer_chip(timer);
+	if (chip->hardware & WSS_HW_CS4236B_MASK)
+		return 14467;
+	else
+		return chip->image[CS4231_PLAYBK_FORMAT] & 1 ? 9969 : 9920;
+}
+
+static int snd_wss_timer_start(struct snd_timer *timer)
+{
+	unsigned long flags;
+	unsigned int ticks;
+	struct snd_wss *chip = snd_timer_chip(timer);
+	spin_lock_irqsave(&chip->reg_lock, flags);
+	ticks = timer->sticks;
+	if ((chip->image[CS4231_ALT_FEATURE_1] & CS4231_TIMER_ENABLE) == 0 ||
+	    (unsigned char)(ticks >> 8) != chip->image[CS4231_TIMER_HIGH] ||
+	    (unsigned char)ticks != chip->image[CS4231_TIMER_LOW]) {
+		chip->image[CS4231_TIMER_HIGH] = (unsigned char) (ticks >> 8);
+		snd_wss_out(chip, CS4231_TIMER_HIGH,
+			    chip->image[CS4231_TIMER_HIGH]);
+		chip->image[CS4231_TIMER_LOW] = (unsigned char) ticks;
+		snd_wss_out(chip, CS4231_TIMER_LOW,
+			    chip->image[CS4231_TIMER_LOW]);
+		snd_wss_out(chip, CS4231_ALT_FEATURE_1,
+			    chip->image[CS4231_ALT_FEATURE_1] |
+			    CS4231_TIMER_ENABLE);
+	}
+	spin_unlock_irqrestore(&chip->reg_lock, flags);
+	return 0;
+}
+
+static int snd_wss_timer_stop(struct snd_timer *timer)
+{
+	unsigned long flags;
+	struct snd_wss *chip = snd_timer_chip(timer);
+	spin_lock_irqsave(&chip->reg_lock, flags);
+	chip->image[CS4231_ALT_FEATURE_1] &= ~CS4231_TIMER_ENABLE;
+	snd_wss_out(chip, CS4231_ALT_FEATURE_1,
+		    chip->image[CS4231_ALT_FEATURE_1]);
+	spin_unlock_irqrestore(&chip->reg_lock, flags);
+	return 0;
+}
+
+static void snd_wss_init(struct snd_wss *chip)
+{
+	unsigned long flags;
+
+	snd_wss_mce_down(chip);
+
+#ifdef SNDRV_DEBUG_MCE
+	snd_printk("init: (1)\n");
+#endif
+	snd_wss_mce_up(chip);
+	spin_lock_irqsave(&chip->reg_lock, flags);
+	chip->image[CS4231_IFACE_CTRL] &= ~(CS4231_PLAYBACK_ENABLE |
+					    CS4231_PLAYBACK_PIO |
+					    CS4231_RECORD_ENABLE |
+					    CS4231_RECORD_PIO |
+					    CS4231_CALIB_MODE);
+	chip->image[CS4231_IFACE_CTRL] |= CS4231_AUTOCALIB;
+	snd_wss_out(chip, CS4231_IFACE_CTRL, chip->image[CS4231_IFACE_CTRL]);
+	spin_unlock_irqrestore(&chip->reg_lock, flags);
+	snd_wss_mce_down(chip);
+
+#ifdef SNDRV_DEBUG_MCE
+	snd_printk("init: (2)\n");
+#endif
+
+	snd_wss_mce_up(chip);
+	spin_lock_irqsave(&chip->reg_lock, flags);
+	snd_wss_out(chip,
+		    CS4231_ALT_FEATURE_1, chip->image[CS4231_ALT_FEATURE_1]);
+	spin_unlock_irqrestore(&chip->reg_lock, flags);
+	snd_wss_mce_down(chip);
+
+#ifdef SNDRV_DEBUG_MCE
+	snd_printk("init: (3) - afei = 0x%x\n",
+		   chip->image[CS4231_ALT_FEATURE_1]);
+#endif
+
+	spin_lock_irqsave(&chip->reg_lock, flags);
+	snd_wss_out(chip, CS4231_ALT_FEATURE_2,
+		    chip->image[CS4231_ALT_FEATURE_2]);
+	spin_unlock_irqrestore(&chip->reg_lock, flags);
+
+	snd_wss_mce_up(chip);
+	spin_lock_irqsave(&chip->reg_lock, flags);
+	snd_wss_out(chip, CS4231_PLAYBK_FORMAT,
+		    chip->image[CS4231_PLAYBK_FORMAT]);
+	spin_unlock_irqrestore(&chip->reg_lock, flags);
+	snd_wss_mce_down(chip);
+
+#ifdef SNDRV_DEBUG_MCE
+	snd_printk("init: (4)\n");
+#endif
+
+	snd_wss_mce_up(chip);
+	spin_lock_irqsave(&chip->reg_lock, flags);
+	if (!(chip->hardware & WSS_HW_AD1848_MASK))
+		snd_wss_out(chip, CS4231_REC_FORMAT,
+			    chip->image[CS4231_REC_FORMAT]);
+	spin_unlock_irqrestore(&chip->reg_lock, flags);
+	snd_wss_mce_down(chip);
+
+#ifdef SNDRV_DEBUG_MCE
+	snd_printk("init: (5)\n");
+#endif
+}
+
+static int snd_wss_open(struct snd_wss *chip, unsigned int mode)
+{
+	unsigned long flags;
+
+	mutex_lock(&chip->open_mutex);
+	if ((chip->mode & mode) ||
+	    ((chip->mode & WSS_MODE_OPEN) && chip->single_dma)) {
+		mutex_unlock(&chip->open_mutex);
+		return -EAGAIN;
+	}
+	if (chip->mode & WSS_MODE_OPEN) {
+		chip->mode |= mode;
+		mutex_unlock(&chip->open_mutex);
+		return 0;
+	}
+	/* ok. now enable and ack CODEC IRQ */
+	spin_lock_irqsave(&chip->reg_lock, flags);
+	if (!(chip->hardware & WSS_HW_AD1848_MASK)) {
+		snd_wss_out(chip, CS4231_IRQ_STATUS,
+			    CS4231_PLAYBACK_IRQ |
+			    CS4231_RECORD_IRQ |
+			    CS4231_TIMER_IRQ);
+		snd_wss_out(chip, CS4231_IRQ_STATUS, 0);
+	}
+	wss_outb(chip, CS4231P(STATUS), 0);	/* clear IRQ */
+	wss_outb(chip, CS4231P(STATUS), 0);	/* clear IRQ */
+	chip->image[CS4231_PIN_CTRL] |= CS4231_IRQ_ENABLE;
+	snd_wss_out(chip, CS4231_PIN_CTRL, chip->image[CS4231_PIN_CTRL]);
+	if (!(chip->hardware & WSS_HW_AD1848_MASK)) {
+		snd_wss_out(chip, CS4231_IRQ_STATUS,
+			    CS4231_PLAYBACK_IRQ |
+			    CS4231_RECORD_IRQ |
+			    CS4231_TIMER_IRQ);
+		snd_wss_out(chip, CS4231_IRQ_STATUS, 0);
+	}
+	spin_unlock_irqrestore(&chip->reg_lock, flags);
+
+	chip->mode = mode;
+	mutex_unlock(&chip->open_mutex);
+	return 0;
+}
+
+static void snd_wss_close(struct snd_wss *chip, unsigned int mode)
+{
+	unsigned long flags;
+
+	mutex_lock(&chip->open_mutex);
+	chip->mode &= ~mode;
+	if (chip->mode & WSS_MODE_OPEN) {
+		mutex_unlock(&chip->open_mutex);
+		return;
+	}
+	snd_wss_calibrate_mute(chip, 1);
+
+	/* disable IRQ */
+	spin_lock_irqsave(&chip->reg_lock, flags);
+	if (!(chip->hardware & WSS_HW_AD1848_MASK))
+		snd_wss_out(chip, CS4231_IRQ_STATUS, 0);
+	wss_outb(chip, CS4231P(STATUS), 0);	/* clear IRQ */
+	wss_outb(chip, CS4231P(STATUS), 0);	/* clear IRQ */
+	chip->image[CS4231_PIN_CTRL] &= ~CS4231_IRQ_ENABLE;
+	snd_wss_out(chip, CS4231_PIN_CTRL, chip->image[CS4231_PIN_CTRL]);
+
+	/* now disable record & playback */
+
+	if (chip->image[CS4231_IFACE_CTRL] & (CS4231_PLAYBACK_ENABLE | CS4231_PLAYBACK_PIO |
+					       CS4231_RECORD_ENABLE | CS4231_RECORD_PIO)) {
+		spin_unlock_irqrestore(&chip->reg_lock, flags);
+		snd_wss_mce_up(chip);
+		spin_lock_irqsave(&chip->reg_lock, flags);
+		chip->image[CS4231_IFACE_CTRL] &= ~(CS4231_PLAYBACK_ENABLE | CS4231_PLAYBACK_PIO |
+						     CS4231_RECORD_ENABLE | CS4231_RECORD_PIO);
+		snd_wss_out(chip, CS4231_IFACE_CTRL,
+			    chip->image[CS4231_IFACE_CTRL]);
+		spin_unlock_irqrestore(&chip->reg_lock, flags);
+		snd_wss_mce_down(chip);
+		spin_lock_irqsave(&chip->reg_lock, flags);
+	}
+
+	/* clear IRQ again */
+	if (!(chip->hardware & WSS_HW_AD1848_MASK))
+		snd_wss_out(chip, CS4231_IRQ_STATUS, 0);
+	wss_outb(chip, CS4231P(STATUS), 0);	/* clear IRQ */
+	wss_outb(chip, CS4231P(STATUS), 0);	/* clear IRQ */
+	spin_unlock_irqrestore(&chip->reg_lock, flags);
+
+	snd_wss_calibrate_mute(chip, 0);
+
+	chip->mode = 0;
+	mutex_unlock(&chip->open_mutex);
+}
+
+/*
+ *  timer open/close
+ */
+
+static int snd_wss_timer_open(struct snd_timer *timer)
+{
+	struct snd_wss *chip = snd_timer_chip(timer);
+	snd_wss_open(chip, WSS_MODE_TIMER);
+	return 0;
+}
+
+static int snd_wss_timer_close(struct snd_timer *timer)
+{
+	struct snd_wss *chip = snd_timer_chip(timer);
+	snd_wss_close(chip, WSS_MODE_TIMER);
+	return 0;
+}
+
+static struct snd_timer_hardware snd_wss_timer_table =
+{
+	.flags =	SNDRV_TIMER_HW_AUTO,
+	.resolution =	9945,
+	.ticks =	65535,
+	.open =		snd_wss_timer_open,
+	.close =	snd_wss_timer_close,
+	.c_resolution = snd_wss_timer_resolution,
+	.start =	snd_wss_timer_start,
+	.stop =		snd_wss_timer_stop,
+};
+
+/*
+ *  ok.. exported functions..
+ */
+
+static int snd_wss_playback_hw_params(struct snd_pcm_substream *substream,
+					 struct snd_pcm_hw_params *hw_params)
+{
+	struct snd_wss *chip = snd_pcm_substream_chip(substream);
+	unsigned char new_pdfr;
+	int err;
+
+	if ((err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params))) < 0)
+		return err;
+	new_pdfr = snd_wss_get_format(chip, params_format(hw_params),
+				params_channels(hw_params)) |
+				snd_wss_get_rate(params_rate(hw_params));
+	chip->set_playback_format(chip, hw_params, new_pdfr);
+	return 0;
+}
+
+static int snd_wss_playback_hw_free(struct snd_pcm_substream *substream)
+{
+	return snd_pcm_lib_free_pages(substream);
+}
+
+static int snd_wss_playback_prepare(struct snd_pcm_substream *substream)
+{
+	struct snd_wss *chip = snd_pcm_substream_chip(substream);
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	unsigned long flags;
+	unsigned int size = snd_pcm_lib_buffer_bytes(substream);
+	unsigned int count = snd_pcm_lib_period_bytes(substream);
+
+	spin_lock_irqsave(&chip->reg_lock, flags);
+	chip->p_dma_size = size;
+	chip->image[CS4231_IFACE_CTRL] &= ~(CS4231_PLAYBACK_ENABLE | CS4231_PLAYBACK_PIO);
+	snd_dma_program(chip->dma1, runtime->dma_addr, size, DMA_MODE_WRITE | DMA_AUTOINIT);
+	count = snd_wss_get_count(chip->image[CS4231_PLAYBK_FORMAT], count) - 1;
+	snd_wss_out(chip, CS4231_PLY_LWR_CNT, (unsigned char) count);
+	snd_wss_out(chip, CS4231_PLY_UPR_CNT, (unsigned char) (count >> 8));
+	spin_unlock_irqrestore(&chip->reg_lock, flags);
+#if 0
+	snd_wss_debug(chip);
+#endif
+	return 0;
+}
+
+static int snd_wss_capture_hw_params(struct snd_pcm_substream *substream,
+					struct snd_pcm_hw_params *hw_params)
+{
+	struct snd_wss *chip = snd_pcm_substream_chip(substream);
+	unsigned char new_cdfr;
+	int err;
+
+	if ((err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params))) < 0)
+		return err;
+	new_cdfr = snd_wss_get_format(chip, params_format(hw_params),
+			   params_channels(hw_params)) |
+			   snd_wss_get_rate(params_rate(hw_params));
+	chip->set_capture_format(chip, hw_params, new_cdfr);
+	return 0;
+}
+
+static int snd_wss_capture_hw_free(struct snd_pcm_substream *substream)
+{
+	return snd_pcm_lib_free_pages(substream);
+}
+
+static int snd_wss_capture_prepare(struct snd_pcm_substream *substream)
+{
+	struct snd_wss *chip = snd_pcm_substream_chip(substream);
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	unsigned long flags;
+	unsigned int size = snd_pcm_lib_buffer_bytes(substream);
+	unsigned int count = snd_pcm_lib_period_bytes(substream);
+
+	spin_lock_irqsave(&chip->reg_lock, flags);
+	chip->c_dma_size = size;
+	chip->image[CS4231_IFACE_CTRL] &= ~(CS4231_RECORD_ENABLE | CS4231_RECORD_PIO);
+	snd_dma_program(chip->dma2, runtime->dma_addr, size, DMA_MODE_READ | DMA_AUTOINIT);
+	if (chip->hardware & WSS_HW_AD1848_MASK)
+		count = snd_wss_get_count(chip->image[CS4231_PLAYBK_FORMAT],
+					  count);
+	else
+		count = snd_wss_get_count(chip->image[CS4231_REC_FORMAT],
+					  count);
+	count--;
+	if (chip->single_dma && chip->hardware != WSS_HW_INTERWAVE) {
+		snd_wss_out(chip, CS4231_PLY_LWR_CNT, (unsigned char) count);
+		snd_wss_out(chip, CS4231_PLY_UPR_CNT,
+			    (unsigned char) (count >> 8));
+	} else {
+		snd_wss_out(chip, CS4231_REC_LWR_CNT, (unsigned char) count);
+		snd_wss_out(chip, CS4231_REC_UPR_CNT,
+			    (unsigned char) (count >> 8));
+	}
+	spin_unlock_irqrestore(&chip->reg_lock, flags);
+	return 0;
+}
+
+void snd_wss_overrange(struct snd_wss *chip)
+{
+	unsigned long flags;
+	unsigned char res;
+
+	spin_lock_irqsave(&chip->reg_lock, flags);
+	res = snd_wss_in(chip, CS4231_TEST_INIT);
+	spin_unlock_irqrestore(&chip->reg_lock, flags);
+	if (res & (0x08 | 0x02))	/* detect overrange only above 0dB; may be user selectable? */
+		chip->capture_substream->runtime->overrange++;
+}
+EXPORT_SYMBOL(snd_wss_overrange);
+
+irqreturn_t snd_wss_interrupt(int irq, void *dev_id)
+{
+	struct snd_wss *chip = dev_id;
+	unsigned char status;
+
+	if (chip->hardware & WSS_HW_AD1848_MASK)
+		/* pretend it was the only possible irq for AD1848 */
+		status = CS4231_PLAYBACK_IRQ;
+	else
+		status = snd_wss_in(chip, CS4231_IRQ_STATUS);
+	if (status & CS4231_TIMER_IRQ) {
+		if (chip->timer)
+			snd_timer_interrupt(chip->timer, chip->timer->sticks);
+	}
+	if (chip->single_dma && chip->hardware != WSS_HW_INTERWAVE) {
+		if (status & CS4231_PLAYBACK_IRQ) {
+			if (chip->mode & WSS_MODE_PLAY) {
+				if (chip->playback_substream)
+					snd_pcm_period_elapsed(chip->playback_substream);
+			}
+			if (chip->mode & WSS_MODE_RECORD) {
+				if (chip->capture_substream) {
+					snd_wss_overrange(chip);
+					snd_pcm_period_elapsed(chip->capture_substream);
+				}
+			}
+		}
+	} else {
+		if (status & CS4231_PLAYBACK_IRQ) {
+			if (chip->playback_substream)
+				snd_pcm_period_elapsed(chip->playback_substream);
+		}
+		if (status & CS4231_RECORD_IRQ) {
+			if (chip->capture_substream) {
+				snd_wss_overrange(chip);
+				snd_pcm_period_elapsed(chip->capture_substream);
+			}
+		}
+	}
+
+	spin_lock(&chip->reg_lock);
+	status = ~CS4231_ALL_IRQS | ~status;
+	if (chip->hardware & WSS_HW_AD1848_MASK)
+		wss_outb(chip, CS4231P(STATUS), 0);
+	else
+		snd_wss_outm(chip, CS4231_IRQ_STATUS, status, 0);
+	spin_unlock(&chip->reg_lock);
+	return IRQ_HANDLED;
+}
+EXPORT_SYMBOL(snd_wss_interrupt);
+
+static snd_pcm_uframes_t snd_wss_playback_pointer(struct snd_pcm_substream *substream)
+{
+	struct snd_wss *chip = snd_pcm_substream_chip(substream);
+	size_t ptr;
+
+	if (!(chip->image[CS4231_IFACE_CTRL] & CS4231_PLAYBACK_ENABLE))
+		return 0;
+	ptr = snd_dma_pointer(chip->dma1, chip->p_dma_size);
+	return bytes_to_frames(substream->runtime, ptr);
+}
+
+static snd_pcm_uframes_t snd_wss_capture_pointer(struct snd_pcm_substream *substream)
+{
+	struct snd_wss *chip = snd_pcm_substream_chip(substream);
+	size_t ptr;
+
+	if (!(chip->image[CS4231_IFACE_CTRL] & CS4231_RECORD_ENABLE))
+		return 0;
+	ptr = snd_dma_pointer(chip->dma2, chip->c_dma_size);
+	return bytes_to_frames(substream->runtime, ptr);
+}
+
+/*
+
+ */
+
+static int snd_ad1848_probe(struct snd_wss *chip)
+{
+	unsigned long timeout = jiffies + msecs_to_jiffies(1000);
+	unsigned long flags;
+	unsigned char r;
+	unsigned short hardware = 0;
+	int err = 0;
+	int i;
+
+	while (wss_inb(chip, CS4231P(REGSEL)) & CS4231_INIT) {
+		if (time_after(jiffies, timeout))
+			return -ENODEV;
+		cond_resched();
+	}
+	spin_lock_irqsave(&chip->reg_lock, flags);
+
+	/* set CS423x MODE 1 */
+	snd_wss_dout(chip, CS4231_MISC_INFO, 0);
+
+	snd_wss_dout(chip, CS4231_RIGHT_INPUT, 0x45); /* 0x55 & ~0x10 */
+	r = snd_wss_in(chip, CS4231_RIGHT_INPUT);
+	if (r != 0x45) {
+		/* RMGE always high on AD1847 */
+		if ((r & ~CS4231_ENABLE_MIC_GAIN) != 0x45) {
+			err = -ENODEV;
+			goto out;
+		}
+		hardware = WSS_HW_AD1847;
+	} else {
+		snd_wss_dout(chip, CS4231_LEFT_INPUT,  0xaa);
+		r = snd_wss_in(chip, CS4231_LEFT_INPUT);
+		/* L/RMGE always low on AT2320 */
+		if ((r | CS4231_ENABLE_MIC_GAIN) != 0xaa) {
+			err = -ENODEV;
+			goto out;
+		}
+	}
+
+	/* clear pending IRQ */
+	wss_inb(chip, CS4231P(STATUS));
+	wss_outb(chip, CS4231P(STATUS), 0);
+	mb();
+
+	if ((chip->hardware & WSS_HW_TYPE_MASK) != WSS_HW_DETECT)
+		goto out;
+
+	if (hardware) {
+		chip->hardware = hardware;
+		goto out;
+	}
+
+	r = snd_wss_in(chip, CS4231_MISC_INFO);
+
+	/* set CS423x MODE 2 */
+	snd_wss_dout(chip, CS4231_MISC_INFO, CS4231_MODE2);
+	for (i = 0; i < 16; i++) {
+		if (snd_wss_in(chip, i) != snd_wss_in(chip, 16 + i)) {
+			/* we have more than 16 registers: check ID */
+			if ((r & 0xf) != 0xa)
+				goto out_mode;
+			/*
+			 * on CMI8330, CS4231_VERSION is volume control and
+			 * can be set to 0
+			 */
+			snd_wss_dout(chip, CS4231_VERSION, 0);
+			r = snd_wss_in(chip, CS4231_VERSION) & 0xe7;
+			if (!r)
+				chip->hardware = WSS_HW_CMI8330;
+			goto out_mode;
+		}
+	}
+	if (r & 0x80)
+		chip->hardware = WSS_HW_CS4248;
+	else
+		chip->hardware = WSS_HW_AD1848;
+out_mode:
+	snd_wss_dout(chip, CS4231_MISC_INFO, 0);
+out:
+	spin_unlock_irqrestore(&chip->reg_lock, flags);
+	return err;
+}
+
+static int snd_wss_probe(struct snd_wss *chip)
+{
+	unsigned long flags;
+	int i, id, rev, regnum;
+	unsigned char *ptr;
+	unsigned int hw;
+
+	id = snd_ad1848_probe(chip);
+	if (id < 0)
+		return id;
+
+	hw = chip->hardware;
+	if ((hw & WSS_HW_TYPE_MASK) == WSS_HW_DETECT) {
+		for (i = 0; i < 50; i++) {
+			mb();
+			if (wss_inb(chip, CS4231P(REGSEL)) & CS4231_INIT)
+				msleep(2);
+			else {
+				spin_lock_irqsave(&chip->reg_lock, flags);
+				snd_wss_out(chip, CS4231_MISC_INFO,
+					    CS4231_MODE2);
+				id = snd_wss_in(chip, CS4231_MISC_INFO) & 0x0f;
+				spin_unlock_irqrestore(&chip->reg_lock, flags);
+				if (id == 0x0a)
+					break;	/* this is valid value */
+			}
+		}
+		snd_printdd("wss: port = 0x%lx, id = 0x%x\n", chip->port, id);
+		if (id != 0x0a)
+			return -ENODEV;	/* no valid device found */
+
+		rev = snd_wss_in(chip, CS4231_VERSION) & 0xe7;
+		snd_printdd("CS4231: VERSION (I25) = 0x%x\n", rev);
+		if (rev == 0x80) {
+			unsigned char tmp = snd_wss_in(chip, 23);
+			snd_wss_out(chip, 23, ~tmp);
+			if (snd_wss_in(chip, 23) != tmp)
+				chip->hardware = WSS_HW_AD1845;
+			else
+				chip->hardware = WSS_HW_CS4231;
+		} else if (rev == 0xa0) {
+			chip->hardware = WSS_HW_CS4231A;
+		} else if (rev == 0xa2) {
+			chip->hardware = WSS_HW_CS4232;
+		} else if (rev == 0xb2) {
+			chip->hardware = WSS_HW_CS4232A;
+		} else if (rev == 0x83) {
+			chip->hardware = WSS_HW_CS4236;
+		} else if (rev == 0x03) {
+			chip->hardware = WSS_HW_CS4236B;
+		} else {
+			snd_printk("unknown CS chip with version 0x%x\n", rev);
+			return -ENODEV;		/* unknown CS4231 chip? */
+		}
+	}
+	spin_lock_irqsave(&chip->reg_lock, flags);
+	wss_inb(chip, CS4231P(STATUS));	/* clear any pendings IRQ */
+	wss_outb(chip, CS4231P(STATUS), 0);
+	mb();
+	spin_unlock_irqrestore(&chip->reg_lock, flags);
+
+	if (!(chip->hardware & WSS_HW_AD1848_MASK))
+		chip->image[CS4231_MISC_INFO] = CS4231_MODE2;
+	switch (chip->hardware) {
+	case WSS_HW_INTERWAVE:
+		chip->image[CS4231_MISC_INFO] = CS4231_IW_MODE3;
+		break;
+	case WSS_HW_CS4235:
+	case WSS_HW_CS4236B:
+	case WSS_HW_CS4237B:
+	case WSS_HW_CS4238B:
+	case WSS_HW_CS4239:
+		if (hw == WSS_HW_DETECT3)
+			chip->image[CS4231_MISC_INFO] = CS4231_4236_MODE3;
+		else
+			chip->hardware = WSS_HW_CS4236;
+		break;
+	}
+
+	chip->image[CS4231_IFACE_CTRL] =
+	    (chip->image[CS4231_IFACE_CTRL] & ~CS4231_SINGLE_DMA) |
+	    (chip->single_dma ? CS4231_SINGLE_DMA : 0);
+	if (chip->hardware != WSS_HW_OPTI93X) {
+		chip->image[CS4231_ALT_FEATURE_1] = 0x80;
+		chip->image[CS4231_ALT_FEATURE_2] =
+			chip->hardware == WSS_HW_INTERWAVE ? 0xc2 : 0x01;
+	}
+	ptr = (unsigned char *) &chip->image;
+	regnum = (chip->hardware & WSS_HW_AD1848_MASK) ? 16 : 32;
+	snd_wss_mce_down(chip);
+	spin_lock_irqsave(&chip->reg_lock, flags);
+	for (i = 0; i < regnum; i++)	/* ok.. fill all registers */
+		snd_wss_out(chip, i, *ptr++);
+	spin_unlock_irqrestore(&chip->reg_lock, flags);
+	snd_wss_mce_up(chip);
+	snd_wss_mce_down(chip);
+
+	mdelay(2);
+
+	/* ok.. try check hardware version for CS4236+ chips */
+	if ((hw & WSS_HW_TYPE_MASK) == WSS_HW_DETECT) {
+		if (chip->hardware == WSS_HW_CS4236B) {
+			rev = snd_cs4236_ext_in(chip, CS4236_VERSION);
+			snd_cs4236_ext_out(chip, CS4236_VERSION, 0xff);
+			id = snd_cs4236_ext_in(chip, CS4236_VERSION);
+			snd_cs4236_ext_out(chip, CS4236_VERSION, rev);
+			snd_printdd("CS4231: ext version; rev = 0x%x, id = 0x%x\n", rev, id);
+			if ((id & 0x1f) == 0x1d) {	/* CS4235 */
+				chip->hardware = WSS_HW_CS4235;
+				switch (id >> 5) {
+				case 4:
+				case 5:
+				case 6:
+					break;
+				default:
+					snd_printk("unknown CS4235 chip (enhanced version = 0x%x)\n", id);
+				}
+			} else if ((id & 0x1f) == 0x0b) {	/* CS4236/B */
+				switch (id >> 5) {
+				case 4:
+				case 5:
+				case 6:
+				case 7:
+					chip->hardware = WSS_HW_CS4236B;
+					break;
+				default:
+					snd_printk("unknown CS4236 chip (enhanced version = 0x%x)\n", id);
+				}
+			} else if ((id & 0x1f) == 0x08) {	/* CS4237B */
+				chip->hardware = WSS_HW_CS4237B;
+				switch (id >> 5) {
+				case 4:
+				case 5:
+				case 6:
+				case 7:
+					break;
+				default:
+					snd_printk("unknown CS4237B chip (enhanced version = 0x%x)\n", id);
+				}
+			} else if ((id & 0x1f) == 0x09) {	/* CS4238B */
+				chip->hardware = WSS_HW_CS4238B;
+				switch (id >> 5) {
+				case 5:
+				case 6:
+				case 7:
+					break;
+				default:
+					snd_printk("unknown CS4238B chip (enhanced version = 0x%x)\n", id);
+				}
+			} else if ((id & 0x1f) == 0x1e) {	/* CS4239 */
+				chip->hardware = WSS_HW_CS4239;
+				switch (id >> 5) {
+				case 4:
+				case 5:
+				case 6:
+					break;
+				default:
+					snd_printk("unknown CS4239 chip (enhanced version = 0x%x)\n", id);
+				}
+			} else {
+				snd_printk("unknown CS4236/CS423xB chip (enhanced version = 0x%x)\n", id);
+			}
+		}
+	}
+	return 0;		/* all things are ok.. */
+}
+
+/*
+
+ */
+
+static struct snd_pcm_hardware snd_wss_playback =
+{
+	.info =			(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
+				 SNDRV_PCM_INFO_MMAP_VALID |
+				 SNDRV_PCM_INFO_RESUME |
+				 SNDRV_PCM_INFO_SYNC_START),
+	.formats =		(SNDRV_PCM_FMTBIT_MU_LAW | SNDRV_PCM_FMTBIT_A_LAW | SNDRV_PCM_FMTBIT_IMA_ADPCM |
+				 SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE),
+	.rates =		SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_8000_48000,
+	.rate_min =		5510,
+	.rate_max =		48000,
+	.channels_min =		1,
+	.channels_max =		2,
+	.buffer_bytes_max =	(128*1024),
+	.period_bytes_min =	64,
+	.period_bytes_max =	(128*1024),
+	.periods_min =		1,
+	.periods_max =		1024,
+	.fifo_size =		0,
+};
+
+static struct snd_pcm_hardware snd_wss_capture =
+{
+	.info =			(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
+				 SNDRV_PCM_INFO_MMAP_VALID |
+				 SNDRV_PCM_INFO_RESUME |
+				 SNDRV_PCM_INFO_SYNC_START),
+	.formats =		(SNDRV_PCM_FMTBIT_MU_LAW | SNDRV_PCM_FMTBIT_A_LAW | SNDRV_PCM_FMTBIT_IMA_ADPCM |
+				 SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE),
+	.rates =		SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_8000_48000,
+	.rate_min =		5510,
+	.rate_max =		48000,
+	.channels_min =		1,
+	.channels_max =		2,
+	.buffer_bytes_max =	(128*1024),
+	.period_bytes_min =	64,
+	.period_bytes_max =	(128*1024),
+	.periods_min =		1,
+	.periods_max =		1024,
+	.fifo_size =		0,
+};
+
+/*
+
+ */
+
+static int snd_wss_playback_open(struct snd_pcm_substream *substream)
+{
+	struct snd_wss *chip = snd_pcm_substream_chip(substream);
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	int err;
+
+	runtime->hw = snd_wss_playback;
+
+	/* hardware limitation of older chipsets */
+	if (chip->hardware & WSS_HW_AD1848_MASK)
+		runtime->hw.formats &= ~(SNDRV_PCM_FMTBIT_IMA_ADPCM |
+					 SNDRV_PCM_FMTBIT_S16_BE);
+
+	/* hardware bug in InterWave chipset */
+	if (chip->hardware == WSS_HW_INTERWAVE && chip->dma1 > 3)
+		runtime->hw.formats &= ~SNDRV_PCM_FMTBIT_MU_LAW;
+
+	/* hardware limitation of cheap chips */
+	if (chip->hardware == WSS_HW_CS4235 ||
+	    chip->hardware == WSS_HW_CS4239)
+		runtime->hw.formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE;
+
+	snd_pcm_limit_isa_dma_size(chip->dma1, &runtime->hw.buffer_bytes_max);
+	snd_pcm_limit_isa_dma_size(chip->dma1, &runtime->hw.period_bytes_max);
+
+	if (chip->claim_dma) {
+		if ((err = chip->claim_dma(chip, chip->dma_private_data, chip->dma1)) < 0)
+			return err;
+	}
+
+	err = snd_wss_open(chip, WSS_MODE_PLAY);
+	if (err < 0) {
+		if (chip->release_dma)
+			chip->release_dma(chip, chip->dma_private_data, chip->dma1);
+		snd_free_pages(runtime->dma_area, runtime->dma_bytes);
+		return err;
+	}
+	chip->playback_substream = substream;
+	snd_pcm_set_sync(substream);
+	chip->rate_constraint(runtime);
+	return 0;
+}
+
+static int snd_wss_capture_open(struct snd_pcm_substream *substream)
+{
+	struct snd_wss *chip = snd_pcm_substream_chip(substream);
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	int err;
+
+	runtime->hw = snd_wss_capture;
+
+	/* hardware limitation of older chipsets */
+	if (chip->hardware & WSS_HW_AD1848_MASK)
+		runtime->hw.formats &= ~(SNDRV_PCM_FMTBIT_IMA_ADPCM |
+					 SNDRV_PCM_FMTBIT_S16_BE);
+
+	/* hardware limitation of cheap chips */
+	if (chip->hardware == WSS_HW_CS4235 ||
+	    chip->hardware == WSS_HW_CS4239 ||
+	    chip->hardware == WSS_HW_OPTI93X)
+		runtime->hw.formats = SNDRV_PCM_FMTBIT_U8 |
+				      SNDRV_PCM_FMTBIT_S16_LE;
+
+	snd_pcm_limit_isa_dma_size(chip->dma2, &runtime->hw.buffer_bytes_max);
+	snd_pcm_limit_isa_dma_size(chip->dma2, &runtime->hw.period_bytes_max);
+
+	if (chip->claim_dma) {
+		if ((err = chip->claim_dma(chip, chip->dma_private_data, chip->dma2)) < 0)
+			return err;
+	}
+
+	err = snd_wss_open(chip, WSS_MODE_RECORD);
+	if (err < 0) {
+		if (chip->release_dma)
+			chip->release_dma(chip, chip->dma_private_data, chip->dma2);
+		snd_free_pages(runtime->dma_area, runtime->dma_bytes);
+		return err;
+	}
+	chip->capture_substream = substream;
+	snd_pcm_set_sync(substream);
+	chip->rate_constraint(runtime);
+	return 0;
+}
+
+static int snd_wss_playback_close(struct snd_pcm_substream *substream)
+{
+	struct snd_wss *chip = snd_pcm_substream_chip(substream);
+
+	chip->playback_substream = NULL;
+	snd_wss_close(chip, WSS_MODE_PLAY);
+	return 0;
+}
+
+static int snd_wss_capture_close(struct snd_pcm_substream *substream)
+{
+	struct snd_wss *chip = snd_pcm_substream_chip(substream);
+
+	chip->capture_substream = NULL;
+	snd_wss_close(chip, WSS_MODE_RECORD);
+	return 0;
+}
+
+static void snd_wss_thinkpad_twiddle(struct snd_wss *chip, int on)
+{
+	int tmp;
+
+	if (!chip->thinkpad_flag)
+		return;
+
+	outb(0x1c, AD1848_THINKPAD_CTL_PORT1);
+	tmp = inb(AD1848_THINKPAD_CTL_PORT2);
+
+	if (on)
+		/* turn it on */
+		tmp |= AD1848_THINKPAD_CS4248_ENABLE_BIT;
+	else
+		/* turn it off */
+		tmp &= ~AD1848_THINKPAD_CS4248_ENABLE_BIT;
+
+	outb(tmp, AD1848_THINKPAD_CTL_PORT2);
+}
+
+#ifdef CONFIG_PM
+
+/* lowlevel suspend callback for CS4231 */
+static void snd_wss_suspend(struct snd_wss *chip)
+{
+	int reg;
+	unsigned long flags;
+
+	snd_pcm_suspend_all(chip->pcm);
+	spin_lock_irqsave(&chip->reg_lock, flags);
+	for (reg = 0; reg < 32; reg++)
+		chip->image[reg] = snd_wss_in(chip, reg);
+	spin_unlock_irqrestore(&chip->reg_lock, flags);
+	if (chip->thinkpad_flag)
+		snd_wss_thinkpad_twiddle(chip, 0);
+}
+
+/* lowlevel resume callback for CS4231 */
+static void snd_wss_resume(struct snd_wss *chip)
+{
+	int reg;
+	unsigned long flags;
+	/* int timeout; */
+
+	if (chip->thinkpad_flag)
+		snd_wss_thinkpad_twiddle(chip, 1);
+	snd_wss_mce_up(chip);
+	spin_lock_irqsave(&chip->reg_lock, flags);
+	for (reg = 0; reg < 32; reg++) {
+		switch (reg) {
+		case CS4231_VERSION:
+			break;
+		default:
+			snd_wss_out(chip, reg, chip->image[reg]);
+			break;
+		}
+	}
+	spin_unlock_irqrestore(&chip->reg_lock, flags);
+#if 1
+	snd_wss_mce_down(chip);
+#else
+	/* The following is a workaround to avoid freeze after resume on TP600E.
+	   This is the first half of copy of snd_wss_mce_down(), but doesn't
+	   include rescheduling.  -- iwai
+	   */
+	snd_wss_busy_wait(chip);
+	spin_lock_irqsave(&chip->reg_lock, flags);
+	chip->mce_bit &= ~CS4231_MCE;
+	timeout = wss_inb(chip, CS4231P(REGSEL));
+	wss_outb(chip, CS4231P(REGSEL), chip->mce_bit | (timeout & 0x1f));
+	spin_unlock_irqrestore(&chip->reg_lock, flags);
+	if (timeout == 0x80)
+		snd_printk("down [0x%lx]: serious init problem - codec still busy\n", chip->port);
+	if ((timeout & CS4231_MCE) == 0 ||
+	    !(chip->hardware & (WSS_HW_CS4231_MASK | WSS_HW_CS4232_MASK))) {
+		return;
+	}
+	snd_wss_busy_wait(chip);
+#endif
+}
+#endif /* CONFIG_PM */
+
+static int snd_wss_free(struct snd_wss *chip)
+{
+	release_and_free_resource(chip->res_port);
+	release_and_free_resource(chip->res_cport);
+	if (chip->irq >= 0) {
+		disable_irq(chip->irq);
+		if (!(chip->hwshare & WSS_HWSHARE_IRQ))
+			free_irq(chip->irq, (void *) chip);
+	}
+	if (!(chip->hwshare & WSS_HWSHARE_DMA1) && chip->dma1 >= 0) {
+		snd_dma_disable(chip->dma1);
+		free_dma(chip->dma1);
+	}
+	if (!(chip->hwshare & WSS_HWSHARE_DMA2) &&
+	    chip->dma2 >= 0 && chip->dma2 != chip->dma1) {
+		snd_dma_disable(chip->dma2);
+		free_dma(chip->dma2);
+	}
+	if (chip->timer)
+		snd_device_free(chip->card, chip->timer);
+	kfree(chip);
+	return 0;
+}
+
+static int snd_wss_dev_free(struct snd_device *device)
+{
+	struct snd_wss *chip = device->device_data;
+	return snd_wss_free(chip);
+}
+
+const char *snd_wss_chip_id(struct snd_wss *chip)
+{
+	switch (chip->hardware) {
+	case WSS_HW_CS4231:
+		return "CS4231";
+	case WSS_HW_CS4231A:
+		return "CS4231A";
+	case WSS_HW_CS4232:
+		return "CS4232";
+	case WSS_HW_CS4232A:
+		return "CS4232A";
+	case WSS_HW_CS4235:
+		return "CS4235";
+	case WSS_HW_CS4236:
+		return "CS4236";
+	case WSS_HW_CS4236B:
+		return "CS4236B";
+	case WSS_HW_CS4237B:
+		return "CS4237B";
+	case WSS_HW_CS4238B:
+		return "CS4238B";
+	case WSS_HW_CS4239:
+		return "CS4239";
+	case WSS_HW_INTERWAVE:
+		return "AMD InterWave";
+	case WSS_HW_OPL3SA2:
+		return chip->card->shortname;
+	case WSS_HW_AD1845:
+		return "AD1845";
+	case WSS_HW_OPTI93X:
+		return "OPTi 93x";
+	case WSS_HW_AD1847:
+		return "AD1847";
+	case WSS_HW_AD1848:
+		return "AD1848";
+	case WSS_HW_CS4248:
+		return "CS4248";
+	case WSS_HW_CMI8330:
+		return "CMI8330/C3D";
+	default:
+		return "???";
+	}
+}
+EXPORT_SYMBOL(snd_wss_chip_id);
+
+static int snd_wss_new(struct snd_card *card,
+			  unsigned short hardware,
+			  unsigned short hwshare,
+			  struct snd_wss **rchip)
+{
+	struct snd_wss *chip;
+
+	*rchip = NULL;
+	chip = kzalloc(sizeof(*chip), GFP_KERNEL);
+	if (chip == NULL)
+		return -ENOMEM;
+	chip->hardware = hardware;
+	chip->hwshare = hwshare;
+
+	spin_lock_init(&chip->reg_lock);
+	mutex_init(&chip->mce_mutex);
+	mutex_init(&chip->open_mutex);
+	chip->card = card;
+	chip->rate_constraint = snd_wss_xrate;
+	chip->set_playback_format = snd_wss_playback_format;
+	chip->set_capture_format = snd_wss_capture_format;
+	if (chip->hardware == WSS_HW_OPTI93X)
+		memcpy(&chip->image, &snd_opti93x_original_image,
+		       sizeof(snd_opti93x_original_image));
+	else
+		memcpy(&chip->image, &snd_wss_original_image,
+		       sizeof(snd_wss_original_image));
+	if (chip->hardware & WSS_HW_AD1848_MASK) {
+		chip->image[CS4231_PIN_CTRL] = 0;
+		chip->image[CS4231_TEST_INIT] = 0;
+	}
+
+	*rchip = chip;
+	return 0;
+}
+
+int snd_wss_create(struct snd_card *card,
+		      unsigned long port,
+		      unsigned long cport,
+		      int irq, int dma1, int dma2,
+		      unsigned short hardware,
+		      unsigned short hwshare,
+		      struct snd_wss **rchip)
+{
+	static struct snd_device_ops ops = {
+		.dev_free =	snd_wss_dev_free,
+	};
+	struct snd_wss *chip;
+	int err;
+
+	err = snd_wss_new(card, hardware, hwshare, &chip);
+	if (err < 0)
+		return err;
+
+	chip->irq = -1;
+	chip->dma1 = -1;
+	chip->dma2 = -1;
+
+	chip->res_port = request_region(port, 4, "WSS");
+	if (!chip->res_port) {
+		snd_printk(KERN_ERR "wss: can't grab port 0x%lx\n", port);
+		snd_wss_free(chip);
+		return -EBUSY;
+	}
+	chip->port = port;
+	if ((long)cport >= 0) {
+		chip->res_cport = request_region(cport, 8, "CS4232 Control");
+		if (!chip->res_cport) {
+			snd_printk(KERN_ERR
+				"wss: can't grab control port 0x%lx\n", cport);
+			snd_wss_free(chip);
+			return -ENODEV;
+		}
+	}
+	chip->cport = cport;
+	if (!(hwshare & WSS_HWSHARE_IRQ))
+		if (request_irq(irq, snd_wss_interrupt, IRQF_DISABLED,
+				"WSS", (void *) chip)) {
+			snd_printk(KERN_ERR "wss: can't grab IRQ %d\n", irq);
+			snd_wss_free(chip);
+			return -EBUSY;
+		}
+	chip->irq = irq;
+	if (!(hwshare & WSS_HWSHARE_DMA1) && request_dma(dma1, "WSS - 1")) {
+		snd_printk(KERN_ERR "wss: can't grab DMA1 %d\n", dma1);
+		snd_wss_free(chip);
+		return -EBUSY;
+	}
+	chip->dma1 = dma1;
+	if (!(hwshare & WSS_HWSHARE_DMA2) && dma1 != dma2 &&
+	      dma2 >= 0 && request_dma(dma2, "WSS - 2")) {
+		snd_printk(KERN_ERR "wss: can't grab DMA2 %d\n", dma2);
+		snd_wss_free(chip);
+		return -EBUSY;
+	}
+	if (dma1 == dma2 || dma2 < 0) {
+		chip->single_dma = 1;
+		chip->dma2 = chip->dma1;
+	} else
+		chip->dma2 = dma2;
+
+	if (hardware == WSS_HW_THINKPAD) {
+		chip->thinkpad_flag = 1;
+		chip->hardware = WSS_HW_DETECT; /* reset */
+		snd_wss_thinkpad_twiddle(chip, 1);
+	}
+
+	/* global setup */
+	if (snd_wss_probe(chip) < 0) {
+		snd_wss_free(chip);
+		return -ENODEV;
+	}
+	snd_wss_init(chip);
+
+#if 0
+	if (chip->hardware & WSS_HW_CS4232_MASK) {
+		if (chip->res_cport == NULL)
+			snd_printk("CS4232 control port features are not accessible\n");
+	}
+#endif
+
+	/* Register device */
+	err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops);
+	if (err < 0) {
+		snd_wss_free(chip);
+		return err;
+	}
+
+#ifdef CONFIG_PM
+	/* Power Management */
+	chip->suspend = snd_wss_suspend;
+	chip->resume = snd_wss_resume;
+#endif
+
+	*rchip = chip;
+	return 0;
+}
+EXPORT_SYMBOL(snd_wss_create);
+
+static struct snd_pcm_ops snd_wss_playback_ops = {
+	.open =		snd_wss_playback_open,
+	.close =	snd_wss_playback_close,
+	.ioctl =	snd_pcm_lib_ioctl,
+	.hw_params =	snd_wss_playback_hw_params,
+	.hw_free =	snd_wss_playback_hw_free,
+	.prepare =	snd_wss_playback_prepare,
+	.trigger =	snd_wss_trigger,
+	.pointer =	snd_wss_playback_pointer,
+};
+
+static struct snd_pcm_ops snd_wss_capture_ops = {
+	.open =		snd_wss_capture_open,
+	.close =	snd_wss_capture_close,
+	.ioctl =	snd_pcm_lib_ioctl,
+	.hw_params =	snd_wss_capture_hw_params,
+	.hw_free =	snd_wss_capture_hw_free,
+	.prepare =	snd_wss_capture_prepare,
+	.trigger =	snd_wss_trigger,
+	.pointer =	snd_wss_capture_pointer,
+};
+
+int snd_wss_pcm(struct snd_wss *chip, int device, struct snd_pcm **rpcm)
+{
+	struct snd_pcm *pcm;
+	int err;
+
+	err = snd_pcm_new(chip->card, "WSS", device, 1, 1, &pcm);
+	if (err < 0)
+		return err;
+
+	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_wss_playback_ops);
+	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_wss_capture_ops);
+
+	/* global setup */
+	pcm->private_data = chip;
+	pcm->info_flags = 0;
+	if (chip->single_dma)
+		pcm->info_flags |= SNDRV_PCM_INFO_HALF_DUPLEX;
+	if (chip->hardware != WSS_HW_INTERWAVE)
+		pcm->info_flags |= SNDRV_PCM_INFO_JOINT_DUPLEX;
+	strcpy(pcm->name, snd_wss_chip_id(chip));
+
+	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
+					      snd_dma_isa_data(),
+					      64*1024, chip->dma1 > 3 || chip->dma2 > 3 ? 128*1024 : 64*1024);
+
+	chip->pcm = pcm;
+	if (rpcm)
+		*rpcm = pcm;
+	return 0;
+}
+EXPORT_SYMBOL(snd_wss_pcm);
+
+static void snd_wss_timer_free(struct snd_timer *timer)
+{
+	struct snd_wss *chip = timer->private_data;
+	chip->timer = NULL;
+}
+
+int snd_wss_timer(struct snd_wss *chip, int device, struct snd_timer **rtimer)
+{
+	struct snd_timer *timer;
+	struct snd_timer_id tid;
+	int err;
+
+	/* Timer initialization */
+	tid.dev_class = SNDRV_TIMER_CLASS_CARD;
+	tid.dev_sclass = SNDRV_TIMER_SCLASS_NONE;
+	tid.card = chip->card->number;
+	tid.device = device;
+	tid.subdevice = 0;
+	if ((err = snd_timer_new(chip->card, "CS4231", &tid, &timer)) < 0)
+		return err;
+	strcpy(timer->name, snd_wss_chip_id(chip));
+	timer->private_data = chip;
+	timer->private_free = snd_wss_timer_free;
+	timer->hw = snd_wss_timer_table;
+	chip->timer = timer;
+	if (rtimer)
+		*rtimer = timer;
+	return 0;
+}
+EXPORT_SYMBOL(snd_wss_timer);
+
+/*
+ *  MIXER part
+ */
+
+static int snd_wss_info_mux(struct snd_kcontrol *kcontrol,
+			    struct snd_ctl_elem_info *uinfo)
+{
+	static char *texts[4] = {
+		"Line", "Aux", "Mic", "Mix"
+	};
+	static char *opl3sa_texts[4] = {
+		"Line", "CD", "Mic", "Mix"
+	};
+	static char *gusmax_texts[4] = {
+		"Line", "Synth", "Mic", "Mix"
+	};
+	char **ptexts = texts;
+	struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
+
+	if (snd_BUG_ON(!chip->card))
+		return -EINVAL;
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+	uinfo->count = 2;
+	uinfo->value.enumerated.items = 4;
+	if (uinfo->value.enumerated.item > 3)
+		uinfo->value.enumerated.item = 3;
+	if (!strcmp(chip->card->driver, "GUS MAX"))
+		ptexts = gusmax_texts;
+	switch (chip->hardware) {
+	case WSS_HW_INTERWAVE:
+		ptexts = gusmax_texts;
+		break;
+	case WSS_HW_OPL3SA2:
+		ptexts = opl3sa_texts;
+		break;
+	}
+	strcpy(uinfo->value.enumerated.name, ptexts[uinfo->value.enumerated.item]);
+	return 0;
+}
+
+static int snd_wss_get_mux(struct snd_kcontrol *kcontrol,
+			   struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
+	unsigned long flags;
+
+	spin_lock_irqsave(&chip->reg_lock, flags);
+	ucontrol->value.enumerated.item[0] = (chip->image[CS4231_LEFT_INPUT] & CS4231_MIXS_ALL) >> 6;
+	ucontrol->value.enumerated.item[1] = (chip->image[CS4231_RIGHT_INPUT] & CS4231_MIXS_ALL) >> 6;
+	spin_unlock_irqrestore(&chip->reg_lock, flags);
+	return 0;
+}
+
+static int snd_wss_put_mux(struct snd_kcontrol *kcontrol,
+			   struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
+	unsigned long flags;
+	unsigned short left, right;
+	int change;
+
+	if (ucontrol->value.enumerated.item[0] > 3 ||
+	    ucontrol->value.enumerated.item[1] > 3)
+		return -EINVAL;
+	left = ucontrol->value.enumerated.item[0] << 6;
+	right = ucontrol->value.enumerated.item[1] << 6;
+	spin_lock_irqsave(&chip->reg_lock, flags);
+	left = (chip->image[CS4231_LEFT_INPUT] & ~CS4231_MIXS_ALL) | left;
+	right = (chip->image[CS4231_RIGHT_INPUT] & ~CS4231_MIXS_ALL) | right;
+	change = left != chip->image[CS4231_LEFT_INPUT] ||
+		 right != chip->image[CS4231_RIGHT_INPUT];
+	snd_wss_out(chip, CS4231_LEFT_INPUT, left);
+	snd_wss_out(chip, CS4231_RIGHT_INPUT, right);
+	spin_unlock_irqrestore(&chip->reg_lock, flags);
+	return change;
+}
+
+int snd_wss_info_single(struct snd_kcontrol *kcontrol,
+			struct snd_ctl_elem_info *uinfo)
+{
+	int mask = (kcontrol->private_value >> 16) & 0xff;
+
+	uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 1;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = mask;
+	return 0;
+}
+EXPORT_SYMBOL(snd_wss_info_single);
+
+int snd_wss_get_single(struct snd_kcontrol *kcontrol,
+		       struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
+	unsigned long flags;
+	int reg = kcontrol->private_value & 0xff;
+	int shift = (kcontrol->private_value >> 8) & 0xff;
+	int mask = (kcontrol->private_value >> 16) & 0xff;
+	int invert = (kcontrol->private_value >> 24) & 0xff;
+
+	spin_lock_irqsave(&chip->reg_lock, flags);
+	ucontrol->value.integer.value[0] = (chip->image[reg] >> shift) & mask;
+	spin_unlock_irqrestore(&chip->reg_lock, flags);
+	if (invert)
+		ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0];
+	return 0;
+}
+EXPORT_SYMBOL(snd_wss_get_single);
+
+int snd_wss_put_single(struct snd_kcontrol *kcontrol,
+		       struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
+	unsigned long flags;
+	int reg = kcontrol->private_value & 0xff;
+	int shift = (kcontrol->private_value >> 8) & 0xff;
+	int mask = (kcontrol->private_value >> 16) & 0xff;
+	int invert = (kcontrol->private_value >> 24) & 0xff;
+	int change;
+	unsigned short val;
+
+	val = (ucontrol->value.integer.value[0] & mask);
+	if (invert)
+		val = mask - val;
+	val <<= shift;
+	spin_lock_irqsave(&chip->reg_lock, flags);
+	val = (chip->image[reg] & ~(mask << shift)) | val;
+	change = val != chip->image[reg];
+	snd_wss_out(chip, reg, val);
+	spin_unlock_irqrestore(&chip->reg_lock, flags);
+	return change;
+}
+EXPORT_SYMBOL(snd_wss_put_single);
+
+int snd_wss_info_double(struct snd_kcontrol *kcontrol,
+			struct snd_ctl_elem_info *uinfo)
+{
+	int mask = (kcontrol->private_value >> 24) & 0xff;
+
+	uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 2;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = mask;
+	return 0;
+}
+EXPORT_SYMBOL(snd_wss_info_double);
+
+int snd_wss_get_double(struct snd_kcontrol *kcontrol,
+		       struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
+	unsigned long flags;
+	int left_reg = kcontrol->private_value & 0xff;
+	int right_reg = (kcontrol->private_value >> 8) & 0xff;
+	int shift_left = (kcontrol->private_value >> 16) & 0x07;
+	int shift_right = (kcontrol->private_value >> 19) & 0x07;
+	int mask = (kcontrol->private_value >> 24) & 0xff;
+	int invert = (kcontrol->private_value >> 22) & 1;
+
+	spin_lock_irqsave(&chip->reg_lock, flags);
+	ucontrol->value.integer.value[0] = (chip->image[left_reg] >> shift_left) & mask;
+	ucontrol->value.integer.value[1] = (chip->image[right_reg] >> shift_right) & mask;
+	spin_unlock_irqrestore(&chip->reg_lock, flags);
+	if (invert) {
+		ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0];
+		ucontrol->value.integer.value[1] = mask - ucontrol->value.integer.value[1];
+	}
+	return 0;
+}
+EXPORT_SYMBOL(snd_wss_get_double);
+
+int snd_wss_put_double(struct snd_kcontrol *kcontrol,
+		       struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
+	unsigned long flags;
+	int left_reg = kcontrol->private_value & 0xff;
+	int right_reg = (kcontrol->private_value >> 8) & 0xff;
+	int shift_left = (kcontrol->private_value >> 16) & 0x07;
+	int shift_right = (kcontrol->private_value >> 19) & 0x07;
+	int mask = (kcontrol->private_value >> 24) & 0xff;
+	int invert = (kcontrol->private_value >> 22) & 1;
+	int change;
+	unsigned short val1, val2;
+
+	val1 = ucontrol->value.integer.value[0] & mask;
+	val2 = ucontrol->value.integer.value[1] & mask;
+	if (invert) {
+		val1 = mask - val1;
+		val2 = mask - val2;
+	}
+	val1 <<= shift_left;
+	val2 <<= shift_right;
+	spin_lock_irqsave(&chip->reg_lock, flags);
+	if (left_reg != right_reg) {
+		val1 = (chip->image[left_reg] & ~(mask << shift_left)) | val1;
+		val2 = (chip->image[right_reg] & ~(mask << shift_right)) | val2;
+		change = val1 != chip->image[left_reg] ||
+			 val2 != chip->image[right_reg];
+		snd_wss_out(chip, left_reg, val1);
+		snd_wss_out(chip, right_reg, val2);
+	} else {
+		mask = (mask << shift_left) | (mask << shift_right);
+		val1 = (chip->image[left_reg] & ~mask) | val1 | val2;
+		change = val1 != chip->image[left_reg];
+		snd_wss_out(chip, left_reg, val1);
+	}
+	spin_unlock_irqrestore(&chip->reg_lock, flags);
+	return change;
+}
+EXPORT_SYMBOL(snd_wss_put_double);
+
+static const DECLARE_TLV_DB_SCALE(db_scale_6bit, -9450, 150, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_5bit_12db_max, -3450, 150, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_rec_gain, 0, 150, 0);
+
+static struct snd_kcontrol_new snd_ad1848_controls[] = {
+WSS_DOUBLE("PCM Playback Switch", 0, CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT,
+	   7, 7, 1, 1),
+WSS_DOUBLE_TLV("PCM Playback Volume", 0,
+	       CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 0, 0, 63, 1,
+	       db_scale_6bit),
+WSS_DOUBLE("Aux Playback Switch", 0,
+	   CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 7, 7, 1, 1),
+WSS_DOUBLE_TLV("Aux Playback Volume", 0,
+	       CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 0, 0, 31, 1,
+	       db_scale_5bit_12db_max),
+WSS_DOUBLE("Aux Playback Switch", 1,
+	   CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 7, 7, 1, 1),
+WSS_DOUBLE_TLV("Aux Playback Volume", 1,
+	       CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 0, 0, 31, 1,
+	       db_scale_5bit_12db_max),
+WSS_DOUBLE_TLV("Capture Volume", 0, CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT,
+		0, 0, 15, 0, db_scale_rec_gain),
+{
+	.name = "Capture Source",
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.info = snd_wss_info_mux,
+	.get = snd_wss_get_mux,
+	.put = snd_wss_put_mux,
+},
+WSS_SINGLE("Loopback Capture Switch", 0, CS4231_LOOPBACK, 0, 1, 0),
+WSS_SINGLE_TLV("Loopback Capture Volume", 0, CS4231_LOOPBACK, 1, 63, 0,
+	       db_scale_6bit),
+};
+
+static struct snd_kcontrol_new snd_wss_controls[] = {
+WSS_DOUBLE("PCM Playback Switch", 0,
+		CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 7, 7, 1, 1),
+WSS_DOUBLE("PCM Playback Volume", 0,
+		CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 0, 0, 63, 1),
+WSS_DOUBLE("Line Playback Switch", 0,
+		CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 7, 7, 1, 1),
+WSS_DOUBLE("Line Playback Volume", 0,
+		CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 0, 0, 31, 1),
+WSS_DOUBLE("Aux Playback Switch", 0,
+		CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 7, 7, 1, 1),
+WSS_DOUBLE("Aux Playback Volume", 0,
+		CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 0, 0, 31, 1),
+WSS_DOUBLE("Aux Playback Switch", 1,
+		CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 7, 7, 1, 1),
+WSS_DOUBLE("Aux Playback Volume", 1,
+		CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 0, 0, 31, 1),
+WSS_SINGLE("Mono Playback Switch", 0,
+		CS4231_MONO_CTRL, 7, 1, 1),
+WSS_SINGLE("Mono Playback Volume", 0,
+		CS4231_MONO_CTRL, 0, 15, 1),
+WSS_SINGLE("Mono Output Playback Switch", 0,
+		CS4231_MONO_CTRL, 6, 1, 1),
+WSS_SINGLE("Mono Output Playback Bypass", 0,
+		CS4231_MONO_CTRL, 5, 1, 0),
+WSS_DOUBLE("Capture Volume", 0,
+		CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 0, 0, 15, 0),
+{
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.name = "Capture Source",
+	.info = snd_wss_info_mux,
+	.get = snd_wss_get_mux,
+	.put = snd_wss_put_mux,
+},
+WSS_DOUBLE("Mic Boost", 0,
+		CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 5, 5, 1, 0),
+WSS_SINGLE("Loopback Capture Switch", 0,
+		CS4231_LOOPBACK, 0, 1, 0),
+WSS_SINGLE("Loopback Capture Volume", 0,
+		CS4231_LOOPBACK, 2, 63, 1)
+};
+
+static struct snd_kcontrol_new snd_opti93x_controls[] = {
+WSS_DOUBLE("Master Playback Switch", 0,
+		OPTi93X_OUT_LEFT, OPTi93X_OUT_RIGHT, 7, 7, 1, 1),
+WSS_DOUBLE("Master Playback Volume", 0,
+		OPTi93X_OUT_LEFT, OPTi93X_OUT_RIGHT, 1, 1, 31, 1),
+WSS_DOUBLE("PCM Playback Switch", 0,
+		CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 7, 7, 1, 1),
+WSS_DOUBLE("PCM Playback Volume", 0,
+		CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 0, 0, 31, 1),
+WSS_DOUBLE("FM Playback Switch", 0,
+		CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 7, 7, 1, 1),
+WSS_DOUBLE("FM Playback Volume", 0,
+		CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 1, 1, 15, 1),
+WSS_DOUBLE("Line Playback Switch", 0,
+		CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 7, 7, 1, 1),
+WSS_DOUBLE("Line Playback Volume", 0,
+		CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 0, 0, 15, 1),
+WSS_DOUBLE("Mic Playback Switch", 0,
+		OPTi93X_MIC_LEFT_INPUT, OPTi93X_MIC_RIGHT_INPUT, 7, 7, 1, 1),
+WSS_DOUBLE("Mic Playback Volume", 0,
+		OPTi93X_MIC_LEFT_INPUT, OPTi93X_MIC_RIGHT_INPUT, 1, 1, 15, 1),
+WSS_DOUBLE("Mic Boost", 0,
+		CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 5, 5, 1, 0),
+WSS_DOUBLE("CD Playback Switch", 0,
+		CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 7, 7, 1, 1),
+WSS_DOUBLE("CD Playback Volume", 0,
+		CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 1, 1, 15, 1),
+WSS_DOUBLE("Aux Playback Switch", 0,
+		OPTi931_AUX_LEFT_INPUT, OPTi931_AUX_RIGHT_INPUT, 7, 7, 1, 1),
+WSS_DOUBLE("Aux Playback Volume", 0,
+		OPTi931_AUX_LEFT_INPUT, OPTi931_AUX_RIGHT_INPUT, 1, 1, 15, 1),
+WSS_DOUBLE("Capture Volume", 0,
+		CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 0, 0, 15, 0),
+{
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.name = "Capture Source",
+	.info = snd_wss_info_mux,
+	.get = snd_wss_get_mux,
+	.put = snd_wss_put_mux,
+}
+};
+
+int snd_wss_mixer(struct snd_wss *chip)
+{
+	struct snd_card *card;
+	unsigned int idx;
+	int err;
+
+	if (snd_BUG_ON(!chip || !chip->pcm))
+		return -EINVAL;
+
+	card = chip->card;
+
+	strcpy(card->mixername, chip->pcm->name);
+
+	if (chip->hardware == WSS_HW_OPTI93X)
+		for (idx = 0; idx < ARRAY_SIZE(snd_opti93x_controls); idx++) {
+			err = snd_ctl_add(card,
+					snd_ctl_new1(&snd_opti93x_controls[idx],
+						     chip));
+			if (err < 0)
+				return err;
+		}
+	else if (chip->hardware & WSS_HW_AD1848_MASK)
+		for (idx = 0; idx < ARRAY_SIZE(snd_ad1848_controls); idx++) {
+			err = snd_ctl_add(card,
+					snd_ctl_new1(&snd_ad1848_controls[idx],
+						     chip));
+			if (err < 0)
+				return err;
+		}
+	else
+		for (idx = 0; idx < ARRAY_SIZE(snd_wss_controls); idx++) {
+			err = snd_ctl_add(card,
+					snd_ctl_new1(&snd_wss_controls[idx],
+						     chip));
+			if (err < 0)
+				return err;
+		}
+	return 0;
+}
+EXPORT_SYMBOL(snd_wss_mixer);
+
+const struct snd_pcm_ops *snd_wss_get_pcm_ops(int direction)
+{
+	return direction == SNDRV_PCM_STREAM_PLAYBACK ?
+		&snd_wss_playback_ops : &snd_wss_capture_ops;
+}
+EXPORT_SYMBOL(snd_wss_get_pcm_ops);
+
+/*
+ *  INIT part
+ */
+
+static int __init alsa_wss_init(void)
+{
+	return 0;
+}
+
+static void __exit alsa_wss_exit(void)
+{
+}
+
+module_init(alsa_wss_init);
+module_exit(alsa_wss_exit);
diff --git a/sound/mips/au1x00.c b/sound/mips/au1x00.c
index fbef38a..1881cec 100644
--- a/sound/mips/au1x00.c
+++ b/sound/mips/au1x00.c
@@ -190,14 +190,16 @@
 static void
 au1000_dma_stop(struct audio_stream *stream)
 {
-	snd_assert(stream->buffer, return);
+	if (snd_BUG_ON(!stream->buffer))
+		return;
 	disable_dma(stream->dma);
 }
 
 static void
 au1000_dma_start(struct audio_stream *stream)
 {
-	snd_assert(stream->buffer, return);
+	if (snd_BUG_ON(!stream->buffer))
+		return;
 
 	init_dma(stream->dma);
 	if (get_dma_active_buffer(stream->dma) == 0) {
diff --git a/sound/oss/Kconfig b/sound/oss/Kconfig
index d4fafb6..1ca7427 100644
--- a/sound/oss/Kconfig
+++ b/sound/oss/Kconfig
@@ -24,13 +24,6 @@
 	  <file:Documentation/sound/oss/vwsnd> for more info on this driver's
 	  capabilities.
 
-config SOUND_HAL2
-	tristate "SGI HAL2 sound (EXPERIMENTAL)"
-	depends on SGI_IP22 && EXPERIMENTAL
-	help
-	  Say Y or M if you have an SGI Indy or Indigo2 system and want to be able to
-	  use its on-board A2 audio system.
-
 config SOUND_AU1550_AC97
 	tristate "Au1550/Au1200 AC97 Sound"
 	depends on SOC_AU1550 || SOC_AU1200
@@ -546,34 +539,6 @@
 	  Base I/O port address for the CD-ROM interface of the Audio Excel
 	  DSP 16 card.
 
-choice
-	prompt "Audio Excel DSP 16"
-	optional
-	depends on SOUND_AEDSP16
-
-config AEDSP16_MSS
-	bool "MSS emulation"
-	depends on SOUND_MSS
-	help
-	  Answer Y if you want your audio card to emulate Microsoft Sound
-	  System. You should then say Y to "Microsoft Sound System support"
-	  and say N to "Audio Excel DSP 16 (SBPro emulation)".
-
-config AEDSP16_SBPRO
-	bool "SBPro emulation"
-	depends on SOUND_SB
-	help
-	  Answer Y if you want your audio card to emulate Sound Blaster Pro.
-	  You should then say Y to "100% Sound Blaster compatibles
-	  (SB16/32/64, ESS, Jazz16) support" and N to "Audio Excel DSP 16 (MSS
-	  emulation)".
-
-	  If you compile the driver into the kernel, you have to add
-	  "aedsp16=<io>,<irq>,<dma>,<mssio>,<mpuio>,<mouirq>" to the kernel
-	  command line.
-
-endchoice
-
 config SOUND_VIDC
 	tristate "VIDC 16-bit sound"
 	depends on ARM && (ARCH_ACORN || ARCH_CLPS7500)
diff --git a/sound/oss/Makefile b/sound/oss/Makefile
index c611514..e0ae4d4 100644
--- a/sound/oss/Makefile
+++ b/sound/oss/Makefile
@@ -10,7 +10,6 @@
 # Please leave it as is, cause the link order is significant !
 
 obj-$(CONFIG_SOUND_SH_DAC_AUDIO)	+= sh_dac_audio.o
-obj-$(CONFIG_SOUND_HAL2)	+= hal2.o
 obj-$(CONFIG_SOUND_AEDSP16)	+= aedsp16.o
 obj-$(CONFIG_SOUND_PSS)		+= pss.o ad1848.o mpu401.o
 obj-$(CONFIG_SOUND_TRIX)	+= trix.o ad1848.o sb_lib.o uart401.o
diff --git a/sound/oss/ac97_codec.c b/sound/oss/ac97_codec.c
index b63839e..456a1b4 100644
--- a/sound/oss/ac97_codec.c
+++ b/sound/oss/ac97_codec.c
@@ -30,7 +30,7 @@
  **************************************************************************
  *
  * History
- * May 02, 2003 Liam Girdwood <liam.girdwood@wolfsonmicro.com>
+ * May 02, 2003 Liam Girdwood <lrg@slimlogic.co.uk>
  *	Removed non existant WM9700
  *	Added support for WM9705, WM9708, WM9709, WM9710, WM9711
  *	WM9712 and WM9717
diff --git a/sound/oss/aedsp16.c b/sound/oss/aedsp16.c
index 51e1fde..a0274f3 100644
--- a/sound/oss/aedsp16.c
+++ b/sound/oss/aedsp16.c
@@ -29,14 +29,6 @@
 #include "sound_config.h"
 
 /*
- * Sanity checks
- */
-
-#if defined(CONFIG_SOUND_AEDSP16_SBPRO) && defined(CONFIG_SOUND_AEDSP16_MSS)
-#error You have to enable only one of the MSS and SBPRO emulations.
-#endif
-
-/*
 
    READ THIS
 
diff --git a/sound/oss/dmasound/Kconfig b/sound/oss/dmasound/Kconfig
index 3eb7827..f456574 100644
--- a/sound/oss/dmasound/Kconfig
+++ b/sound/oss/dmasound/Kconfig
@@ -42,3 +42,4 @@
 
 config DMASOUND
 	tristate
+	select SOUND_OSS_CORE
diff --git a/sound/oss/hal2.c b/sound/oss/hal2.c
deleted file mode 100644
index a94b9df..0000000
--- a/sound/oss/hal2.c
+++ /dev/null
@@ -1,1558 +0,0 @@
-/*
- *  Driver for A2 audio system used in SGI machines
- *  Copyright (c) 2001, 2002, 2003 Ladislav Michl <ladis@linux-mips.org>
- *  
- *  Based on Ulf Carlsson's code.
- *
- *  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., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- *  Supported devices:
- *  /dev/dsp    standard dsp device, (mostly) OSS compatible
- *  /dev/mixer	standard mixer device, (mostly) OSS compatible
- *
- */
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/sched.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/poll.h>
-#include <linux/interrupt.h>
-#include <linux/dma-mapping.h>
-#include <linux/sound.h>
-#include <linux/soundcard.h>
-#include <linux/mutex.h>
-
-
-#include <asm/io.h>
-#include <asm/sgi/hpc3.h>
-#include <asm/sgi/ip22.h>
-
-#include "hal2.h"
-
-#if 0
-#define DEBUG(args...)		printk(args)
-#else
-#define DEBUG(args...)
-#endif
-
-#if 0 
-#define DEBUG_MIX(args...)	printk(args)
-#else
-#define DEBUG_MIX(args...)
-#endif
-
-/*
- * Before touching these look how it works. It is a bit unusual I know,
- * but it helps to keep things simple. This driver is considered complete
- * and I won't add any new features although hardware has many cool
- * capabilities.
- * (Historical note: HAL2 driver was first written by Ulf Carlsson - ALSA
- * 0.3 running with 2.2.x kernel. Then ALSA changed completely and it
- * seemed easier to me to write OSS driver from scratch - this one. Now
- * when ALSA is official part of 2.6 kernel it's time to write ALSA driver
- * using (hopefully) final version of ALSA interface)
- */
-#define H2_BLOCK_SIZE	1024
-#define H2_ADC_BUFSIZE	8192
-#define H2_DAC_BUFSIZE	16834
-
-struct hal2_pbus {
-	struct hpc3_pbus_dmacregs *pbus;
-	int pbusnr;
-	unsigned int ctrl;		/* Current state of pbus->pbdma_ctrl */
-};
-
-struct hal2_desc {
-	struct hpc_dma_desc desc;
-	u32 cnt;			/* don't touch, it is also padding */
-};
-
-struct hal2_codec {
-	unsigned char *buffer;
-	struct hal2_desc *desc;
-	int desc_count;
-	int tail, head;			/* tail index, head index */
-	struct hal2_pbus pbus;
-	unsigned int format;		/* Audio data format */
-	int voices;			/* mono/stereo */
-	unsigned int sample_rate;
-	unsigned int master;		/* Master frequency */
-	unsigned short mod;		/* MOD value */
-	unsigned short inc;		/* INC value */
-
-	wait_queue_head_t dma_wait;
-	spinlock_t lock;
-	struct mutex sem;
-
-	int usecount;			/* recording and playback are
-					 * independent */
-};
-
-#define H2_MIX_OUTPUT_ATT	0
-#define H2_MIX_INPUT_GAIN	1
-#define H2_MIXERS		2
-struct hal2_mixer {
-	int modcnt;
-	unsigned int master;
-	unsigned int volume[H2_MIXERS];
-};
-
-struct hal2_card {
-	int dev_dsp;			/* audio device */
-	int dev_mixer;			/* mixer device */
-	int dev_midi;			/* midi device */
-
-	struct hal2_ctl_regs *ctl_regs;	/* HAL2 ctl registers */
-	struct hal2_aes_regs *aes_regs;	/* HAL2 aes registers */
-	struct hal2_vol_regs *vol_regs;	/* HAL2 vol registers */
-	struct hal2_syn_regs *syn_regs;	/* HAL2 syn registers */
-
-	struct hal2_codec dac;
-	struct hal2_codec adc;
-	struct hal2_mixer mixer;
-};
-
-#define H2_INDIRECT_WAIT(regs)	while (regs->isr & H2_ISR_TSTATUS);
-
-#define H2_READ_ADDR(addr)	(addr | (1<<7))
-#define H2_WRITE_ADDR(addr)	(addr)
-
-static char *hal2str = "HAL2";
-
-/*
- * I doubt anyone has a machine with two HAL2 cards. It's possible to
- * have two HPC's, so it is probably possible to have two HAL2 cards.
- * Try to deal with it, but note that it is not tested.
- */
-#define MAXCARDS	2
-static struct hal2_card* hal2_card[MAXCARDS];
-
-static const struct {
-	unsigned char idx:4, avail:1;
-} mixtable[SOUND_MIXER_NRDEVICES] = {
-	[SOUND_MIXER_PCM]	= { H2_MIX_OUTPUT_ATT, 1 },	/* voice */
-	[SOUND_MIXER_MIC]	= { H2_MIX_INPUT_GAIN, 1 },	/* mic */
-};
-
-#define H2_SUPPORTED_FORMATS	(AFMT_S16_LE | AFMT_S16_BE)
-
-static inline void hal2_isr_write(struct hal2_card *hal2, u16 val)
-{
-	hal2->ctl_regs->isr = val;
-}
-
-static inline u16 hal2_isr_look(struct hal2_card *hal2)
-{
-	return hal2->ctl_regs->isr;
-}
-
-static inline u16 hal2_rev_look(struct hal2_card *hal2)
-{
-	return hal2->ctl_regs->rev;
-}
-
-#ifdef HAL2_DUMP_REGS
-static u16 hal2_i_look16(struct hal2_card *hal2, u16 addr)
-{
-	struct hal2_ctl_regs *regs = hal2->ctl_regs;
-
-	regs->iar = H2_READ_ADDR(addr);
-	H2_INDIRECT_WAIT(regs);
-	return regs->idr0;
-}
-#endif
-
-static u32 hal2_i_look32(struct hal2_card *hal2, u16 addr)
-{
-	u32 ret;
-	struct hal2_ctl_regs *regs = hal2->ctl_regs;
-
-	regs->iar = H2_READ_ADDR(addr);
-	H2_INDIRECT_WAIT(regs);
-	ret = regs->idr0 & 0xffff;
-	regs->iar = H2_READ_ADDR(addr | 0x1);
-	H2_INDIRECT_WAIT(regs);
-	ret |= (regs->idr0 & 0xffff) << 16;
-	return ret;
-}
-
-static void hal2_i_write16(struct hal2_card *hal2, u16 addr, u16 val)
-{
-	struct hal2_ctl_regs *regs = hal2->ctl_regs;
-
-	regs->idr0 = val;
-	regs->idr1 = 0;
-	regs->idr2 = 0;
-	regs->idr3 = 0;
-	regs->iar = H2_WRITE_ADDR(addr);
-	H2_INDIRECT_WAIT(regs);
-}
-
-static void hal2_i_write32(struct hal2_card *hal2, u16 addr, u32 val)
-{
-	struct hal2_ctl_regs *regs = hal2->ctl_regs;
-
-	regs->idr0 = val & 0xffff;
-	regs->idr1 = val >> 16;
-	regs->idr2 = 0;
-	regs->idr3 = 0;
-	regs->iar = H2_WRITE_ADDR(addr);
-	H2_INDIRECT_WAIT(regs);
-}
-
-static void hal2_i_setbit16(struct hal2_card *hal2, u16 addr, u16 bit)
-{
-	struct hal2_ctl_regs *regs = hal2->ctl_regs;
-
-	regs->iar = H2_READ_ADDR(addr);
-	H2_INDIRECT_WAIT(regs);
-	regs->idr0 = (regs->idr0 & 0xffff) | bit;
-	regs->idr1 = 0;
-	regs->idr2 = 0;
-	regs->idr3 = 0;
-	regs->iar = H2_WRITE_ADDR(addr);
-	H2_INDIRECT_WAIT(regs);
-}
-
-static void hal2_i_setbit32(struct hal2_card *hal2, u16 addr, u32 bit)
-{
-	u32 tmp;
-	struct hal2_ctl_regs *regs = hal2->ctl_regs;
-
-	regs->iar = H2_READ_ADDR(addr);
-	H2_INDIRECT_WAIT(regs);
-	tmp = (regs->idr0 & 0xffff) | (regs->idr1 << 16) | bit;
-	regs->idr0 = tmp & 0xffff;
-	regs->idr1 = tmp >> 16;
-	regs->idr2 = 0;
-	regs->idr3 = 0;
-	regs->iar = H2_WRITE_ADDR(addr);
-	H2_INDIRECT_WAIT(regs);
-}
-
-static void hal2_i_clearbit16(struct hal2_card *hal2, u16 addr, u16 bit)
-{
-	struct hal2_ctl_regs *regs = hal2->ctl_regs;
-
-	regs->iar = H2_READ_ADDR(addr);
-	H2_INDIRECT_WAIT(regs);
-	regs->idr0 = (regs->idr0 & 0xffff) & ~bit;
-	regs->idr1 = 0;
-	regs->idr2 = 0;
-	regs->idr3 = 0;
-	regs->iar = H2_WRITE_ADDR(addr);
-	H2_INDIRECT_WAIT(regs);
-}
-
-#if 0
-static void hal2_i_clearbit32(struct hal2_card *hal2, u16 addr, u32 bit)
-{
-	u32 tmp;
-	hal2_ctl_regs_t *regs = hal2->ctl_regs;
-
-	regs->iar = H2_READ_ADDR(addr);
-	H2_INDIRECT_WAIT(regs);
-	tmp = ((regs->idr0 & 0xffff) | (regs->idr1 << 16)) & ~bit;
-	regs->idr0 = tmp & 0xffff;
-	regs->idr1 = tmp >> 16;
-	regs->idr2 = 0;
-	regs->idr3 = 0;
-	regs->iar = H2_WRITE_ADDR(addr);
-	H2_INDIRECT_WAIT(regs);
-}
-#endif
-
-#ifdef HAL2_DUMP_REGS
-static void hal2_dump_regs(struct hal2_card *hal2)
-{
-	DEBUG("isr: %08hx ", hal2_isr_look(hal2));
-	DEBUG("rev: %08hx\n", hal2_rev_look(hal2));
-	DEBUG("relay: %04hx\n", hal2_i_look16(hal2, H2I_RELAY_C));
-	DEBUG("port en: %04hx ", hal2_i_look16(hal2, H2I_DMA_PORT_EN));
-	DEBUG("dma end: %04hx ", hal2_i_look16(hal2, H2I_DMA_END));
-	DEBUG("dma drv: %04hx\n", hal2_i_look16(hal2, H2I_DMA_DRV));
-	DEBUG("syn ctl: %04hx ", hal2_i_look16(hal2, H2I_SYNTH_C));
-	DEBUG("aesrx ctl: %04hx ", hal2_i_look16(hal2, H2I_AESRX_C));
-	DEBUG("aestx ctl: %04hx ", hal2_i_look16(hal2, H2I_AESTX_C));
-	DEBUG("dac ctl1: %04hx ", hal2_i_look16(hal2, H2I_ADC_C1));
-	DEBUG("dac ctl2: %08x ", hal2_i_look32(hal2, H2I_ADC_C2));
-	DEBUG("adc ctl1: %04hx ", hal2_i_look16(hal2, H2I_DAC_C1));
-	DEBUG("adc ctl2: %08x ", hal2_i_look32(hal2, H2I_DAC_C2));
-	DEBUG("syn map: %04hx\n", hal2_i_look16(hal2, H2I_SYNTH_MAP_C));
-	DEBUG("bres1 ctl1: %04hx ", hal2_i_look16(hal2, H2I_BRES1_C1));
-	DEBUG("bres1 ctl2: %04x ", hal2_i_look32(hal2, H2I_BRES1_C2));
-	DEBUG("bres2 ctl1: %04hx ", hal2_i_look16(hal2, H2I_BRES2_C1));
-	DEBUG("bres2 ctl2: %04x ", hal2_i_look32(hal2, H2I_BRES2_C2));
-	DEBUG("bres3 ctl1: %04hx ", hal2_i_look16(hal2, H2I_BRES3_C1));
-	DEBUG("bres3 ctl2: %04x\n", hal2_i_look32(hal2, H2I_BRES3_C2));
-}
-#endif
-
-static struct hal2_card* hal2_dsp_find_card(int minor)
-{
-	int i;
-
-	for (i = 0; i < MAXCARDS; i++)
-		if (hal2_card[i] != NULL && hal2_card[i]->dev_dsp == minor)
-			return hal2_card[i];
-	return NULL;
-}
-
-static struct hal2_card* hal2_mixer_find_card(int minor)
-{
-	int i;
-
-	for (i = 0; i < MAXCARDS; i++)
-		if (hal2_card[i] != NULL && hal2_card[i]->dev_mixer == minor)
-			return hal2_card[i];
-	return NULL;
-}
-
-static void hal2_inc_head(struct hal2_codec *codec)
-{
-	codec->head++;
-	if (codec->head == codec->desc_count)
-		codec->head = 0;
-}
-
-static void hal2_inc_tail(struct hal2_codec *codec)
-{
-	codec->tail++;
-	if (codec->tail == codec->desc_count)
-		codec->tail = 0;
-}
-
-static void hal2_dac_interrupt(struct hal2_codec *dac)
-{
-	int running;
-
-	spin_lock(&dac->lock);
-	/* if tail buffer contains zero samples DMA stream was already
-	 * stopped */
-	running = dac->desc[dac->tail].cnt;
-	dac->desc[dac->tail].cnt = 0;
-	dac->desc[dac->tail].desc.cntinfo = HPCDMA_XIE | HPCDMA_EOX;
-	/* we just proccessed empty buffer, don't update tail pointer */
-	if (running)
-		hal2_inc_tail(dac);
-	spin_unlock(&dac->lock);
-
-	wake_up(&dac->dma_wait);
-}
-
-static void hal2_adc_interrupt(struct hal2_codec *adc)
-{
-	int running;
-
-	spin_lock(&adc->lock);
-	/* if head buffer contains nonzero samples DMA stream was already
-	 * stopped */
-	running = !adc->desc[adc->head].cnt;
-	adc->desc[adc->head].cnt = H2_BLOCK_SIZE;
-	adc->desc[adc->head].desc.cntinfo = HPCDMA_XIE | HPCDMA_EOR;
-	/* we just proccessed empty buffer, don't update head pointer */
-	if (running)
-		hal2_inc_head(adc);
-	spin_unlock(&adc->lock);
-
-	wake_up(&adc->dma_wait);
-}
-
-static irqreturn_t hal2_interrupt(int irq, void *dev_id)
-{
-	struct hal2_card *hal2 = dev_id;
-	irqreturn_t ret = IRQ_NONE;
-
-	/* decide what caused this interrupt */
-	if (hal2->dac.pbus.pbus->pbdma_ctrl & HPC3_PDMACTRL_INT) {
-		hal2_dac_interrupt(&hal2->dac);
-		ret = IRQ_HANDLED;
-	}
-	if (hal2->adc.pbus.pbus->pbdma_ctrl & HPC3_PDMACTRL_INT) {
-		hal2_adc_interrupt(&hal2->adc);
-		ret = IRQ_HANDLED;
-	}
-	return ret;
-}
-
-static int hal2_compute_rate(struct hal2_codec *codec, unsigned int rate)
-{
-	unsigned short mod;
-	
-	DEBUG("rate: %d\n", rate);
-	
-	if (rate < 4000) rate = 4000;
-	else if (rate > 48000) rate = 48000;
-
-	if (44100 % rate < 48000 % rate) {
-		mod = 4 * 44100 / rate;
-		codec->master = 44100;
-	} else {
-		mod = 4 * 48000 / rate;
-		codec->master = 48000;
-	}
-
-	codec->inc = 4;
-	codec->mod = mod;
-	rate = 4 * codec->master / mod;
-
-	DEBUG("real_rate: %d\n", rate);
-
-	return rate;
-}
-
-static void hal2_set_dac_rate(struct hal2_card *hal2)
-{
-	unsigned int master = hal2->dac.master;
-	int inc = hal2->dac.inc;
-	int mod = hal2->dac.mod;
-
-	DEBUG("master: %d inc: %d mod: %d\n", master, inc, mod);
-	
-	hal2_i_write16(hal2, H2I_BRES1_C1, (master == 44100) ? 1 : 0);
-	hal2_i_write32(hal2, H2I_BRES1_C2, ((0xffff & (inc - mod - 1)) << 16) | inc);
-}
-
-static void hal2_set_adc_rate(struct hal2_card *hal2)
-{
-	unsigned int master = hal2->adc.master;
-	int inc = hal2->adc.inc;
-	int mod = hal2->adc.mod;
-
-	DEBUG("master: %d inc: %d mod: %d\n", master, inc, mod);
-	
-	hal2_i_write16(hal2, H2I_BRES2_C1, (master == 44100) ? 1 : 0);
-	hal2_i_write32(hal2, H2I_BRES2_C2, ((0xffff & (inc - mod - 1)) << 16) | inc);
-}
-
-static void hal2_setup_dac(struct hal2_card *hal2)
-{
-	unsigned int fifobeg, fifoend, highwater, sample_size;
-	struct hal2_pbus *pbus = &hal2->dac.pbus;
-
-	DEBUG("hal2_setup_dac\n");
-	
-	/* Now we set up some PBUS information. The PBUS needs information about
-	 * what portion of the fifo it will use. If it's receiving or
-	 * transmitting, and finally whether the stream is little endian or big
-	 * endian. The information is written later, on the start call.
-	 */
-	sample_size = 2 * hal2->dac.voices;
-	/* Fifo should be set to hold exactly four samples. Highwater mark
-	 * should be set to two samples. */
-	highwater = (sample_size * 2) >> 1;	/* halfwords */
-	fifobeg = 0;				/* playback is first */
-	fifoend = (sample_size * 4) >> 3;	/* doublewords */
-	pbus->ctrl = HPC3_PDMACTRL_RT | HPC3_PDMACTRL_LD |
-		     (highwater << 8) | (fifobeg << 16) | (fifoend << 24) |
-		     (hal2->dac.format & AFMT_S16_LE ? HPC3_PDMACTRL_SEL : 0);
-	/* We disable everything before we do anything at all */
-	pbus->pbus->pbdma_ctrl = HPC3_PDMACTRL_LD;
-	hal2_i_clearbit16(hal2, H2I_DMA_PORT_EN, H2I_DMA_PORT_EN_CODECTX);
-	/* Setup the HAL2 for playback */
-	hal2_set_dac_rate(hal2);
-	/* Set endianess */
-	if (hal2->dac.format & AFMT_S16_LE)
-		hal2_i_setbit16(hal2, H2I_DMA_END, H2I_DMA_END_CODECTX);
-	else
-		hal2_i_clearbit16(hal2, H2I_DMA_END, H2I_DMA_END_CODECTX);
-	/* Set DMA bus */
-	hal2_i_setbit16(hal2, H2I_DMA_DRV, (1 << pbus->pbusnr));
-	/* We are using 1st Bresenham clock generator for playback */
-	hal2_i_write16(hal2, H2I_DAC_C1, (pbus->pbusnr << H2I_C1_DMA_SHIFT)
-			| (1 << H2I_C1_CLKID_SHIFT)
-			| (hal2->dac.voices << H2I_C1_DATAT_SHIFT));
-}
-
-static void hal2_setup_adc(struct hal2_card *hal2)
-{
-	unsigned int fifobeg, fifoend, highwater, sample_size;
-	struct hal2_pbus *pbus = &hal2->adc.pbus;
-
-	DEBUG("hal2_setup_adc\n");
-
-	sample_size = 2 * hal2->adc.voices;
-	highwater = (sample_size * 2) >> 1;		/* halfwords */
-	fifobeg = (4 * 4) >> 3;				/* record is second */
-	fifoend = (4 * 4 + sample_size * 4) >> 3;	/* doublewords */
-	pbus->ctrl = HPC3_PDMACTRL_RT | HPC3_PDMACTRL_RCV | HPC3_PDMACTRL_LD | 
-		     (highwater << 8) | (fifobeg << 16) | (fifoend << 24) |
-		     (hal2->adc.format & AFMT_S16_LE ? HPC3_PDMACTRL_SEL : 0);
-	pbus->pbus->pbdma_ctrl = HPC3_PDMACTRL_LD;
-	hal2_i_clearbit16(hal2, H2I_DMA_PORT_EN, H2I_DMA_PORT_EN_CODECR);
-	/* Setup the HAL2 for record */
-	hal2_set_adc_rate(hal2);
-	/* Set endianess */
-	if (hal2->adc.format & AFMT_S16_LE)
-		hal2_i_setbit16(hal2, H2I_DMA_END, H2I_DMA_END_CODECR);
-	else
-		hal2_i_clearbit16(hal2, H2I_DMA_END, H2I_DMA_END_CODECR);
-	/* Set DMA bus */
-	hal2_i_setbit16(hal2, H2I_DMA_DRV, (1 << pbus->pbusnr));
-	/* We are using 2nd Bresenham clock generator for record */
-	hal2_i_write16(hal2, H2I_ADC_C1, (pbus->pbusnr << H2I_C1_DMA_SHIFT)
-			| (2 << H2I_C1_CLKID_SHIFT)
-			| (hal2->adc.voices << H2I_C1_DATAT_SHIFT));
-}
-
-static dma_addr_t hal2_desc_addr(struct hal2_codec *codec, int i)
-{
-	if (--i < 0)
-		i = codec->desc_count - 1;
-	return codec->desc[i].desc.pnext;
-}
-
-static void hal2_start_dac(struct hal2_card *hal2)
-{
-	struct hal2_codec *dac = &hal2->dac;
-	struct hal2_pbus *pbus = &dac->pbus;
-
-	pbus->pbus->pbdma_dptr = hal2_desc_addr(dac, dac->tail);
-	pbus->pbus->pbdma_ctrl = pbus->ctrl | HPC3_PDMACTRL_ACT;
-	/* enable DAC */
-	hal2_i_setbit16(hal2, H2I_DMA_PORT_EN, H2I_DMA_PORT_EN_CODECTX);
-}
-
-static void hal2_start_adc(struct hal2_card *hal2)
-{
-	struct hal2_codec *adc = &hal2->adc;
-	struct hal2_pbus *pbus = &adc->pbus;
-
-	pbus->pbus->pbdma_dptr = hal2_desc_addr(adc, adc->head);
-	pbus->pbus->pbdma_ctrl = pbus->ctrl | HPC3_PDMACTRL_ACT;
-	/* enable ADC */
-	hal2_i_setbit16(hal2, H2I_DMA_PORT_EN, H2I_DMA_PORT_EN_CODECR);
-}
-
-static inline void hal2_stop_dac(struct hal2_card *hal2)
-{
-	hal2->dac.pbus.pbus->pbdma_ctrl = HPC3_PDMACTRL_LD;
-	/* The HAL2 itself may remain enabled safely */
-}
-
-static inline void hal2_stop_adc(struct hal2_card *hal2)
-{
-	hal2->adc.pbus.pbus->pbdma_ctrl = HPC3_PDMACTRL_LD;
-}
-
-static int hal2_alloc_dmabuf(struct hal2_codec *codec, int size,
-			     int count, int cntinfo, int dir)
-{
-	struct hal2_desc *desc, *dma_addr;
-	int i;
-
-	DEBUG("allocating %dk DMA buffer.\n", size / 1024);
-
-	codec->buffer = (unsigned char *)__get_free_pages(GFP_KERNEL | GFP_DMA,
-							  get_order(size));
-	if (!codec->buffer)
-		return -ENOMEM;
-	desc = dma_alloc_coherent(NULL, count * sizeof(struct hal2_desc),
-				  (dma_addr_t *)&dma_addr, GFP_KERNEL);
-	if (!desc) {
-		free_pages((unsigned long)codec->buffer, get_order(size));
-		return -ENOMEM;
-	}
-	codec->desc = desc;
-	for (i = 0; i < count; i++) {
-		desc->desc.pbuf = dma_map_single(NULL,
-			(void *)(codec->buffer + i * H2_BLOCK_SIZE),
-			H2_BLOCK_SIZE, dir);
-		desc->desc.cntinfo = cntinfo;
-		desc->desc.pnext = (i == count - 1) ?
-				   (u32)dma_addr : (u32)(dma_addr + i + 1);
-		desc->cnt = 0;
-		desc++;
-	}
-	codec->desc_count = count;
-	codec->head = codec->tail = 0;
-	return 0;
-}
-
-static int hal2_alloc_dac_dmabuf(struct hal2_codec *codec)
-{
-	return hal2_alloc_dmabuf(codec, H2_DAC_BUFSIZE,
-				 H2_DAC_BUFSIZE / H2_BLOCK_SIZE,
-				 HPCDMA_XIE | HPCDMA_EOX,
-				 DMA_TO_DEVICE);
-}
-
-static int hal2_alloc_adc_dmabuf(struct hal2_codec *codec)
-{
-	return hal2_alloc_dmabuf(codec, H2_ADC_BUFSIZE,
-				 H2_ADC_BUFSIZE / H2_BLOCK_SIZE,
-				 HPCDMA_XIE | H2_BLOCK_SIZE,
-				 DMA_TO_DEVICE);
-}
-
-static void hal2_free_dmabuf(struct hal2_codec *codec, int size, int dir)
-{
-	dma_addr_t dma_addr;
-	int i;
-
-	dma_addr = codec->desc[codec->desc_count - 1].desc.pnext;
-	for (i = 0; i < codec->desc_count; i++)
-		dma_unmap_single(NULL, codec->desc[i].desc.pbuf,
-				 H2_BLOCK_SIZE, dir);
-	dma_free_coherent(NULL, codec->desc_count * sizeof(struct hal2_desc),
-			  (void *)codec->desc, dma_addr);
-	free_pages((unsigned long)codec->buffer, get_order(size));
-}
-
-static void hal2_free_dac_dmabuf(struct hal2_codec *codec)
-{
-	return hal2_free_dmabuf(codec, H2_DAC_BUFSIZE, DMA_TO_DEVICE);
-}
-
-static void hal2_free_adc_dmabuf(struct hal2_codec *codec)
-{
-	return hal2_free_dmabuf(codec, H2_ADC_BUFSIZE, DMA_FROM_DEVICE);
-}
-
-/* 
- * Add 'count' bytes to 'buffer' from DMA ring buffers. Return number of
- * bytes added or -EFAULT if copy_from_user failed.
- */
-static int hal2_get_buffer(struct hal2_card *hal2, char *buffer, int count)
-{
-	unsigned long flags;
-	int size, ret = 0;
-	unsigned char *buf;
-	struct hal2_desc *tail;
-	struct hal2_codec *adc = &hal2->adc;
-
-	DEBUG("getting %d bytes ", count);
-
-	spin_lock_irqsave(&adc->lock, flags);
-	tail = &adc->desc[adc->tail];
-	/* enable DMA stream if there are no data */
-	if (!tail->cnt && !(adc->pbus.pbus->pbdma_ctrl & HPC3_PDMACTRL_ISACT))
-		hal2_start_adc(hal2);
-	while (tail->cnt > 0 && count > 0) {
-		size = min((int)tail->cnt, count);
-		buf = &adc->buffer[(adc->tail + 1) * H2_BLOCK_SIZE - tail->cnt];
-		spin_unlock_irqrestore(&adc->lock, flags);
-		dma_sync_single(NULL, tail->desc.pbuf, size, DMA_FROM_DEVICE);
-		if (copy_to_user(buffer, buf, size)) {
-			ret = -EFAULT;
-			goto out;
-		}
-		spin_lock_irqsave(&adc->lock, flags);
-		tail->cnt -= size;
-		/* buffer is empty, update tail pointer */
-		if (tail->cnt == 0) {
-			tail->desc.cntinfo = HPCDMA_XIE | H2_BLOCK_SIZE;
-			hal2_inc_tail(adc);
-			tail = &adc->desc[adc->tail];
-			/* enable DMA stream again if needed */
-			if (!(adc->pbus.pbus->pbdma_ctrl & HPC3_PDMACTRL_ISACT))
-				hal2_start_adc(hal2);
-		}
-		buffer += size;
-		ret += size;
-		count -= size;
-
-		DEBUG("(%d) ", size);
-	}
-	spin_unlock_irqrestore(&adc->lock, flags);
-out:
-	DEBUG("\n");
-
-	return ret;
-} 
-
-/* 
- * Add 'count' bytes from 'buffer' to DMA ring buffers. Return number of
- * bytes added or -EFAULT if copy_from_user failed.
- */
-static int hal2_add_buffer(struct hal2_card *hal2, char *buffer, int count)
-{
-	unsigned long flags;
-	unsigned char *buf;
-	int size, ret = 0;
-	struct hal2_desc *head;
-	struct hal2_codec *dac = &hal2->dac;
-
-	DEBUG("adding %d bytes ", count);
-
-	spin_lock_irqsave(&dac->lock, flags);
-	head = &dac->desc[dac->head];
-	while (head->cnt == 0 && count > 0) {
-		size = min((int)H2_BLOCK_SIZE, count);
-		buf = &dac->buffer[dac->head * H2_BLOCK_SIZE];
-		spin_unlock_irqrestore(&dac->lock, flags);
-		if (copy_from_user(buf, buffer, size)) {
-			ret = -EFAULT;
-			goto out;
-		}
-		dma_sync_single(NULL, head->desc.pbuf, size, DMA_TO_DEVICE);
-		spin_lock_irqsave(&dac->lock, flags);
-		head->desc.cntinfo = size | HPCDMA_XIE;
-		head->cnt = size;
-		buffer += size;
-		ret += size;
-		count -= size;
-		hal2_inc_head(dac);
-		head = &dac->desc[dac->head];
-
-		DEBUG("(%d) ", size);
-	}
-	if (!(dac->pbus.pbus->pbdma_ctrl & HPC3_PDMACTRL_ISACT) && ret > 0)
-		hal2_start_dac(hal2);
-	spin_unlock_irqrestore(&dac->lock, flags);
-out:
-	DEBUG("\n");
-
-	return ret;
-}
-
-#define hal2_reset_dac_pointer(hal2)	hal2_reset_pointer(hal2, 1)
-#define hal2_reset_adc_pointer(hal2)	hal2_reset_pointer(hal2, 0)
-static void hal2_reset_pointer(struct hal2_card *hal2, int is_dac)
-{
-	int i;
-	struct hal2_codec *codec = (is_dac) ? &hal2->dac : &hal2->adc;
-
-	DEBUG("hal2_reset_pointer\n");
-
-	for (i = 0; i < codec->desc_count; i++) {
-		codec->desc[i].cnt = 0;
-		codec->desc[i].desc.cntinfo = HPCDMA_XIE | (is_dac) ?
-					      HPCDMA_EOX : H2_BLOCK_SIZE;
-	}
-	codec->head = codec->tail = 0;
-}
-
-static int hal2_sync_dac(struct hal2_card *hal2)
-{
-	DECLARE_WAITQUEUE(wait, current);
-	struct hal2_codec *dac = &hal2->dac;
-	int ret = 0;
-	unsigned long flags;
-	signed long timeout = 1000 * H2_BLOCK_SIZE * 2 * dac->voices *
-			      HZ / dac->sample_rate / 900;
-
-	while (dac->pbus.pbus->pbdma_ctrl & HPC3_PDMACTRL_ISACT) {
-		add_wait_queue(&dac->dma_wait, &wait);
-		set_current_state(TASK_INTERRUPTIBLE);
-		schedule_timeout(timeout);
-		spin_lock_irqsave(&dac->lock, flags);
-		if (dac->desc[dac->tail].cnt)
-			ret = -ETIME;
-		spin_unlock_irqrestore(&dac->lock, flags);
-		if (signal_pending(current))
-			ret = -ERESTARTSYS;
-		if (ret) {
-			hal2_stop_dac(hal2);
-			hal2_reset_dac_pointer(hal2);
-		}
-		remove_wait_queue(&dac->dma_wait, &wait);
-	}
-
-	return ret;
-}
-
-static int hal2_write_mixer(struct hal2_card *hal2, int index, int vol)
-{
-	unsigned int l, r, tmp;
-
-	DEBUG_MIX("mixer %d write\n", index);
-
-	if (index >= SOUND_MIXER_NRDEVICES || !mixtable[index].avail)
-		return -EINVAL;
-
-	r = (vol >> 8) & 0xff;
-	if (r > 100)
-		r = 100;
-	l = vol & 0xff;
-	if (l > 100)
-		l = 100;
-
-	hal2->mixer.volume[mixtable[index].idx] = l | (r << 8);
-
-	switch (mixtable[index].idx) {
-	case H2_MIX_OUTPUT_ATT:
-
-		DEBUG_MIX("output attenuator %d,%d\n", l, r);
-
-		if (r | l) {
-			tmp = hal2_i_look32(hal2, H2I_DAC_C2);
-			tmp &= ~(H2I_C2_L_ATT_M | H2I_C2_R_ATT_M | H2I_C2_MUTE);
-
-			/* Attenuator has five bits */
-			l = 31 * (100 - l) / 99;
-			r = 31 * (100 - r) / 99;
-
-			DEBUG_MIX("left: %d, right %d\n", l, r);
-
-			tmp |= (l << H2I_C2_L_ATT_SHIFT) & H2I_C2_L_ATT_M;
-			tmp |= (r << H2I_C2_R_ATT_SHIFT) & H2I_C2_R_ATT_M;
-			hal2_i_write32(hal2, H2I_DAC_C2, tmp);
-		} else 
-			hal2_i_setbit32(hal2, H2I_DAC_C2, H2I_C2_MUTE);
-		break;
-	case H2_MIX_INPUT_GAIN:
-
-		DEBUG_MIX("input gain %d,%d\n", l, r);
-
-		tmp = hal2_i_look32(hal2, H2I_ADC_C2);
-		tmp &= ~(H2I_C2_L_GAIN_M | H2I_C2_R_GAIN_M);
-
-		/* Gain control has four bits */
-		l = 16 * l / 100;
-		r = 16 * r / 100;
-
-		DEBUG_MIX("left: %d, right %d\n", l, r);
-
-		tmp |= (l << H2I_C2_L_GAIN_SHIFT) & H2I_C2_L_GAIN_M;
-		tmp |= (r << H2I_C2_R_GAIN_SHIFT) & H2I_C2_R_GAIN_M;
-		hal2_i_write32(hal2, H2I_ADC_C2, tmp);
-
-		break;
-	}
-
-	return 0;
-}
-
-static void hal2_init_mixer(struct hal2_card *hal2)
-{
-	int i;
-
-	for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
-		if (mixtable[i].avail)
-			hal2->mixer.volume[mixtable[i].idx] = 100 | (100 << 8);
-
-	/* disable attenuator */
-	hal2_i_write32(hal2, H2I_DAC_C2, 0);
-	/* set max input gain */
-	hal2_i_write32(hal2, H2I_ADC_C2, H2I_C2_MUTE |
-			(H2I_C2_L_GAIN_M << H2I_C2_L_GAIN_SHIFT) |
-			(H2I_C2_R_GAIN_M << H2I_C2_R_GAIN_SHIFT));
-	/* set max volume */
-	hal2->mixer.master = 0xff;
-	hal2->vol_regs->left = 0xff;
-	hal2->vol_regs->right = 0xff;
-}
-
-/*
- * XXX: later i'll implement mixer for main volume which will be disabled
- * by default. enabling it users will be allowed to have master volume level
- * control on panel in their favourite X desktop
- */
-static void hal2_volume_control(int direction)
-{
-	unsigned int master = hal2_card[0]->mixer.master;
-	struct hal2_vol_regs *vol = hal2_card[0]->vol_regs;
-
-	/* volume up */
-	if (direction > 0 && master < 0xff)
-		master++;
-	/* volume down */
-	else if (direction < 0 && master > 0)
-		master--;
-	/* TODO: mute/unmute */
-	vol->left = master;
-	vol->right = master;
-	hal2_card[0]->mixer.master = master;
-}
-
-static int hal2_mixer_ioctl(struct hal2_card *hal2, unsigned int cmd,
-			    unsigned long arg)
-{
-	int val;
-
-        if (cmd == SOUND_MIXER_INFO) {
-		mixer_info info;
-
-		memset(&info, 0, sizeof(info));
-		strlcpy(info.id, hal2str, sizeof(info.id));
-		strlcpy(info.name, hal2str, sizeof(info.name));
-		info.modify_counter = hal2->mixer.modcnt;
-		if (copy_to_user((void *)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, hal2str, sizeof(info.id));
-		strlcpy(info.name, hal2str, sizeof(info.name));
-		if (copy_to_user((void *)arg, &info, sizeof(info)))
-			return -EFAULT;
-		return 0;
-	}
-	if (cmd == OSS_GETVERSION)
-		return put_user(SOUND_VERSION, (int *)arg);
-
-	if (_IOC_TYPE(cmd) != 'M' || _IOC_SIZE(cmd) != sizeof(int))
-                return -EINVAL;
-
-        if (_IOC_DIR(cmd) == _IOC_READ) {
-                switch (_IOC_NR(cmd)) {
-		/* Give the current record source */
-		case SOUND_MIXER_RECSRC:
-			val = 0;	/* FIXME */
-			break;
-		/* Give the supported mixers, all of them support stereo */
-                case SOUND_MIXER_DEVMASK:
-                case SOUND_MIXER_STEREODEVS: {
-			int i;
-
-			for (val = i = 0; i < SOUND_MIXER_NRDEVICES; i++)
-				if (mixtable[i].avail)
-					val |= 1 << i;
-			break;
-			}
-		/* Arg contains a bit for each supported recording source */
-                case SOUND_MIXER_RECMASK:
-			val = 0;
-			break;
-                case SOUND_MIXER_CAPS:
-			val = 0;
-			break;
-		/* Read a specific mixer */
-		default: {
-			int i = _IOC_NR(cmd);
-
-			if (i >= SOUND_MIXER_NRDEVICES || !mixtable[i].avail)
-				return -EINVAL;
-			val = hal2->mixer.volume[mixtable[i].idx];
-			break;
-			}
-		}
-		return put_user(val, (int *)arg);
-	}
-
-        if (_IOC_DIR(cmd) != (_IOC_WRITE|_IOC_READ))
-		return -EINVAL;
-
-	hal2->mixer.modcnt++;
-
-	if (get_user(val, (int *)arg))
-		return -EFAULT;
-
-	switch (_IOC_NR(cmd)) {
-	/* Arg contains a bit for each recording source */
-	case SOUND_MIXER_RECSRC:
-		return 0;	/* FIXME */
-	default:
-		return hal2_write_mixer(hal2, _IOC_NR(cmd), val);
-	}
-
-	return 0;
-}
-
-static int hal2_open_mixdev(struct inode *inode, struct file *file)
-{
-	struct hal2_card *hal2 = hal2_mixer_find_card(iminor(inode));
-
-	if (hal2) {
-		file->private_data = hal2;
-		return nonseekable_open(inode, file);
-	}
-	return -ENODEV;
-}
-
-static int hal2_release_mixdev(struct inode *inode, struct file *file)
-{
-	return 0;
-}
-
-static int hal2_ioctl_mixdev(struct inode *inode, struct file *file,
-			     unsigned int cmd, unsigned long arg)
-{
-	return hal2_mixer_ioctl((struct hal2_card *)file->private_data, cmd, arg);
-}
-
-static int hal2_ioctl(struct inode *inode, struct file *file, 
-		      unsigned int cmd, unsigned long arg)
-{
-	int val;
-	struct hal2_card *hal2 = (struct hal2_card *) file->private_data;
-
-	switch (cmd) {
-	case OSS_GETVERSION:
-		return put_user(SOUND_VERSION, (int *)arg);
-
-	case SNDCTL_DSP_SYNC:
-		if (file->f_mode & FMODE_WRITE)
-			return hal2_sync_dac(hal2);
-		return 0;
-
-	case SNDCTL_DSP_SETDUPLEX:
-		return 0;
-
-	case SNDCTL_DSP_GETCAPS:
-		return put_user(DSP_CAP_DUPLEX | DSP_CAP_MULTI, (int *)arg);
-
-	case SNDCTL_DSP_RESET:
-		if (file->f_mode & FMODE_READ) {
-			hal2_stop_adc(hal2);
-			hal2_reset_adc_pointer(hal2);
-		}
-		if (file->f_mode & FMODE_WRITE) {
-			hal2_stop_dac(hal2);
-			hal2_reset_dac_pointer(hal2);
-		}
-		return 0;
-
- 	case SNDCTL_DSP_SPEED:
-		if (get_user(val, (int *)arg))
-			return -EFAULT;
-		if (file->f_mode & FMODE_READ) {
-			hal2_stop_adc(hal2);
-			val = hal2_compute_rate(&hal2->adc, val);
-			hal2->adc.sample_rate = val;
-			hal2_set_adc_rate(hal2);
-		}
-		if (file->f_mode & FMODE_WRITE) {
-			hal2_stop_dac(hal2);
-			val = hal2_compute_rate(&hal2->dac, val);
-			hal2->dac.sample_rate = val;
-			hal2_set_dac_rate(hal2);
-		}
-		return put_user(val, (int *)arg);
-
-	case SNDCTL_DSP_STEREO:
-		if (get_user(val, (int *)arg))
-			return -EFAULT;
-		if (file->f_mode & FMODE_READ) {
-			hal2_stop_adc(hal2);
-			hal2->adc.voices = (val) ? 2 : 1;
-			hal2_setup_adc(hal2);
-		}
-		if (file->f_mode & FMODE_WRITE) {
-			hal2_stop_dac(hal2);
-			hal2->dac.voices = (val) ? 2 : 1;
-			hal2_setup_dac(hal2);
-                }
-		return 0;
-
-	case SNDCTL_DSP_CHANNELS:
-		if (get_user(val, (int *)arg))
-			return -EFAULT;
-		if (val != 0) {
-			if (file->f_mode & FMODE_READ) {
-				hal2_stop_adc(hal2);
-				hal2->adc.voices = (val == 1) ? 1 : 2;
-				hal2_setup_adc(hal2);
-			}
-			if (file->f_mode & FMODE_WRITE) {
-				hal2_stop_dac(hal2);
-				hal2->dac.voices = (val == 1) ? 1 : 2;
-				hal2_setup_dac(hal2);
-			}
-		}
-		val = -EINVAL;
-		if (file->f_mode & FMODE_READ)
-			val = hal2->adc.voices;
-		if (file->f_mode & FMODE_WRITE)
-			val = hal2->dac.voices;
-		return put_user(val, (int *)arg);
-
-	case SNDCTL_DSP_GETFMTS: /* Returns a mask */
-                return put_user(H2_SUPPORTED_FORMATS, (int *)arg);
-
-	case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/
-		if (get_user(val, (int *)arg))
-			return -EFAULT;
-		if (val != AFMT_QUERY) {
-			if (!(val & H2_SUPPORTED_FORMATS))
-				return -EINVAL;
-			if (file->f_mode & FMODE_READ) {
-				hal2_stop_adc(hal2);
-				hal2->adc.format = val;
-				hal2_setup_adc(hal2);
-			}
-			if (file->f_mode & FMODE_WRITE) {
-				hal2_stop_dac(hal2);
-				hal2->dac.format = val;
-				hal2_setup_dac(hal2);
-			}
-		} else {
-			val = -EINVAL;
-			if (file->f_mode & FMODE_READ)
-				val = hal2->adc.format;
-			if (file->f_mode & FMODE_WRITE)
-				val = hal2->dac.format;
-		}
-		return put_user(val, (int *)arg);
-
-	case SNDCTL_DSP_POST:
-		return 0;
-
-	case SNDCTL_DSP_GETOSPACE: {
-		audio_buf_info info;
-		int i;
-		unsigned long flags;
-		struct hal2_codec *dac = &hal2->dac;
-
-		if (!(file->f_mode & FMODE_WRITE))
-			return -EINVAL;
-		info.fragments = 0;
-		spin_lock_irqsave(&dac->lock, flags);
-		for (i = 0; i < dac->desc_count; i++)
-			if (dac->desc[i].cnt == 0)
-				info.fragments++;
-		spin_unlock_irqrestore(&dac->lock, flags);
-		info.fragstotal = dac->desc_count;
-		info.fragsize = H2_BLOCK_SIZE;
-                info.bytes = info.fragsize * info.fragments;
-
-		return copy_to_user((void *)arg, &info, sizeof(info)) ? -EFAULT : 0;
-	}
-
-	case SNDCTL_DSP_GETISPACE: {
-		audio_buf_info info;
-		int i;
-		unsigned long flags;
-		struct hal2_codec *adc = &hal2->adc;
-
-		if (!(file->f_mode & FMODE_READ))
-			return -EINVAL;
-		info.fragments = 0;
-		info.bytes = 0;
-		spin_lock_irqsave(&adc->lock, flags);
-		for (i = 0; i < adc->desc_count; i++)
-			if (adc->desc[i].cnt > 0) {
-				info.fragments++;
-				info.bytes += adc->desc[i].cnt;
-			}
-		spin_unlock_irqrestore(&adc->lock, flags);
-		info.fragstotal = adc->desc_count;
-		info.fragsize = H2_BLOCK_SIZE;
-
-		return copy_to_user((void *)arg, &info, sizeof(info)) ? -EFAULT : 0;
-	}
-
-	case SNDCTL_DSP_NONBLOCK:
-		file->f_flags |= O_NONBLOCK;
-		return 0;
-
-	case SNDCTL_DSP_GETBLKSIZE:
-		return put_user(H2_BLOCK_SIZE, (int *)arg);
-
-	case SNDCTL_DSP_SETFRAGMENT:
-		return 0;
-
-	case SOUND_PCM_READ_RATE:
-		val = -EINVAL;
-		if (file->f_mode & FMODE_READ)
-			val = hal2->adc.sample_rate;
-		if (file->f_mode & FMODE_WRITE)
-			val = hal2->dac.sample_rate;
-		return put_user(val, (int *)arg);
-
-	case SOUND_PCM_READ_CHANNELS:
-		val = -EINVAL;
-		if (file->f_mode & FMODE_READ)
-			val = hal2->adc.voices;
-		if (file->f_mode & FMODE_WRITE)
-			val = hal2->dac.voices;
-		return put_user(val, (int *)arg);
-
-	case SOUND_PCM_READ_BITS:
-		return put_user(16, (int *)arg);
-	}
-
-	return hal2_mixer_ioctl(hal2, cmd, arg);
-}
-
-static ssize_t hal2_read(struct file *file, char *buffer,
-			 size_t count, loff_t *ppos)
-{
-	ssize_t err;
-	struct hal2_card *hal2 = (struct hal2_card *) file->private_data;
-	struct hal2_codec *adc = &hal2->adc;
-
-	if (!count)
-		return 0;
-	if (mutex_lock_interruptible(&adc->sem))
-		return -EINTR;
-	if (file->f_flags & O_NONBLOCK) {
-		err = hal2_get_buffer(hal2, buffer, count);
-		err = err == 0 ? -EAGAIN : err;
-	} else {
-		do {
-			/* ~10% longer */
-			signed long timeout = 1000 * H2_BLOCK_SIZE *
-				2 * adc->voices * HZ / adc->sample_rate / 900;
-			unsigned long flags;
-			DECLARE_WAITQUEUE(wait, current);
-			ssize_t cnt = 0;
-
-			err = hal2_get_buffer(hal2, buffer, count);
-			if (err > 0) {
-				count -= err;
-				cnt += err;
-				buffer += err;
-				err = cnt;
-			}
-			if (count > 0 && err >= 0) {
-				add_wait_queue(&adc->dma_wait, &wait);
-				set_current_state(TASK_INTERRUPTIBLE);
-				schedule_timeout(timeout);
-				spin_lock_irqsave(&adc->lock, flags);
-				if (!adc->desc[adc->tail].cnt)
-					err = -EAGAIN;
-				spin_unlock_irqrestore(&adc->lock, flags);
-				if (signal_pending(current))
-					err = -ERESTARTSYS;
-				remove_wait_queue(&adc->dma_wait, &wait);
-				if (err < 0) {
-					hal2_stop_adc(hal2);
-					hal2_reset_adc_pointer(hal2);
-				}
-			}
-		} while (count > 0 && err >= 0);
-	}
-	mutex_unlock(&adc->sem);
-
-	return err;
-}
-
-static ssize_t hal2_write(struct file *file, const char *buffer,
-			  size_t count, loff_t *ppos)
-{
-	ssize_t err;
-	char *buf = (char*) buffer;
-	struct hal2_card *hal2 = (struct hal2_card *) file->private_data;
-	struct hal2_codec *dac = &hal2->dac;
-
-	if (!count)
-		return 0;
-	if (mutex_lock_interruptible(&dac->sem))
-		return -EINTR;
-	if (file->f_flags & O_NONBLOCK) {
-		err = hal2_add_buffer(hal2, buf, count);
-		err = err == 0 ? -EAGAIN : err;
-	} else {
-		do {
-			/* ~10% longer */
-			signed long timeout = 1000 * H2_BLOCK_SIZE *
-				2 * dac->voices * HZ / dac->sample_rate / 900;
-			unsigned long flags;
-			DECLARE_WAITQUEUE(wait, current);
-			ssize_t cnt = 0;
-
-			err = hal2_add_buffer(hal2, buf, count);
-			if (err > 0) {
-				count -= err;
-				cnt += err;
-				buf += err;
-				err = cnt;
-			}
-			if (count > 0 && err >= 0) {
-				add_wait_queue(&dac->dma_wait, &wait);
-				set_current_state(TASK_INTERRUPTIBLE);
-				schedule_timeout(timeout);
-				spin_lock_irqsave(&dac->lock, flags);
-				if (dac->desc[dac->head].cnt)
-					err = -EAGAIN;
-				spin_unlock_irqrestore(&dac->lock, flags);
-				if (signal_pending(current))
-					err = -ERESTARTSYS;
-				remove_wait_queue(&dac->dma_wait, &wait);
-				if (err < 0) {
-					hal2_stop_dac(hal2);
-					hal2_reset_dac_pointer(hal2);
-				}
-			}
-		} while (count > 0 && err >= 0);
-	}
-	mutex_unlock(&dac->sem);
-
-	return err;
-}
-
-static unsigned int hal2_poll(struct file *file, struct poll_table_struct *wait)
-{
-	unsigned long flags;
-	unsigned int mask = 0;
-	struct hal2_card *hal2 = (struct hal2_card *) file->private_data;
-
-	if (file->f_mode & FMODE_READ) {
-		struct hal2_codec *adc = &hal2->adc;
-
-		poll_wait(file, &adc->dma_wait, wait);
-		spin_lock_irqsave(&adc->lock, flags);
-		if (adc->desc[adc->tail].cnt > 0)
-			mask |= POLLIN;
-		spin_unlock_irqrestore(&adc->lock, flags);
-	}
-
-	if (file->f_mode & FMODE_WRITE) {
-		struct hal2_codec *dac = &hal2->dac;
-
-		poll_wait(file, &dac->dma_wait, wait);
-		spin_lock_irqsave(&dac->lock, flags);
-		if (dac->desc[dac->head].cnt == 0)
-			mask |= POLLOUT;
-		spin_unlock_irqrestore(&dac->lock, flags);
-	}
-
-	return mask;
-}
-
-static int hal2_open(struct inode *inode, struct file *file)
-{
-	int err;
-	struct hal2_card *hal2 = hal2_dsp_find_card(iminor(inode));
-
-	if (!hal2)
-		return -ENODEV;
-	file->private_data = hal2;
-	if (file->f_mode & FMODE_READ) {
-		struct hal2_codec *adc = &hal2->adc;
-
-		if (adc->usecount)
-			return -EBUSY;
-		/* OSS spec wanted us to use 8 bit, 8 kHz mono by default,
-		 * but HAL2 can't do 8bit audio */
-		adc->format = AFMT_S16_BE;
-		adc->voices = 1;
-		adc->sample_rate = hal2_compute_rate(adc, 8000);
-		hal2_set_adc_rate(hal2);
-		err = hal2_alloc_adc_dmabuf(adc);
-		if (err)
-			return err;
-		hal2_setup_adc(hal2);
-		adc->usecount++;
-	}
-	if (file->f_mode & FMODE_WRITE) {
-		struct hal2_codec *dac = &hal2->dac;
-
-		if (dac->usecount)
-			return -EBUSY;
-		dac->format = AFMT_S16_BE;
-		dac->voices = 1;
-		dac->sample_rate = hal2_compute_rate(dac, 8000);
-		hal2_set_dac_rate(hal2);
-		err = hal2_alloc_dac_dmabuf(dac);
-		if (err)
-			return err;
-		hal2_setup_dac(hal2);
-		dac->usecount++;
-	}
-
-	return nonseekable_open(inode, file);
-}
-
-static int hal2_release(struct inode *inode, struct file *file)
-{
-	struct hal2_card *hal2 = (struct hal2_card *) file->private_data;
-
-	if (file->f_mode & FMODE_READ) {
-		struct hal2_codec *adc = &hal2->adc;
-
-		mutex_lock(&adc->sem);
-		hal2_stop_adc(hal2);
-		hal2_free_adc_dmabuf(adc);
-		adc->usecount--;
-		mutex_unlock(&adc->sem);
-	}
-	if (file->f_mode & FMODE_WRITE) {
-		struct hal2_codec *dac = &hal2->dac;
-
-		mutex_lock(&dac->sem);
-		hal2_sync_dac(hal2);
-		hal2_free_dac_dmabuf(dac);
-		dac->usecount--;
-		mutex_unlock(&dac->sem);
-	}
-
-	return 0;
-}
-
-static const struct file_operations hal2_audio_fops = {
-	.owner		= THIS_MODULE,
-	.llseek		= no_llseek,
-	.read		= hal2_read,
-	.write		= hal2_write,
-	.poll		= hal2_poll,
-	.ioctl		= hal2_ioctl,
-	.open		= hal2_open,
-	.release	= hal2_release,
-};
-
-static const struct file_operations hal2_mixer_fops = {
-	.owner		= THIS_MODULE,
-	.llseek		= no_llseek,
-	.ioctl		= hal2_ioctl_mixdev,
-	.open		= hal2_open_mixdev,
-	.release	= hal2_release_mixdev,
-};
-
-static void hal2_init_codec(struct hal2_codec *codec, struct hpc3_regs *hpc3,
-			    int index)
-{
-	codec->pbus.pbusnr = index;
-	codec->pbus.pbus = &hpc3->pbdma[index];
-	init_waitqueue_head(&codec->dma_wait);
-	mutex_init(&codec->sem);
-	spin_lock_init(&codec->lock);
-}
-
-static int hal2_detect(struct hal2_card *hal2)
-{
-	unsigned short board, major, minor;
-	unsigned short rev;
-
-	/* reset HAL2 */
-	hal2_isr_write(hal2, 0);
-	/* release reset */
-	hal2_isr_write(hal2, H2_ISR_GLOBAL_RESET_N | H2_ISR_CODEC_RESET_N);
-
-	hal2_i_write16(hal2, H2I_RELAY_C, H2I_RELAY_C_STATE); 
-	if ((rev = hal2_rev_look(hal2)) & H2_REV_AUDIO_PRESENT)
-		return -ENODEV;
-
-	board = (rev & H2_REV_BOARD_M) >> 12;
-	major = (rev & H2_REV_MAJOR_CHIP_M) >> 4;
-	minor = (rev & H2_REV_MINOR_CHIP_M);
-
-	printk(KERN_INFO "SGI HAL2 revision %i.%i.%i\n",
-	       board, major, minor);
-
-	return 0;
-}
-
-static int hal2_init_card(struct hal2_card **phal2, struct hpc3_regs *hpc3)
-{
-	int ret = 0;
-	struct hal2_card *hal2;
-
-	hal2 = kzalloc(sizeof(struct hal2_card), GFP_KERNEL);
-	if (!hal2)
-		return -ENOMEM;
-
-	hal2->ctl_regs = (struct hal2_ctl_regs *)hpc3->pbus_extregs[0];
-	hal2->aes_regs = (struct hal2_aes_regs *)hpc3->pbus_extregs[1];
-	hal2->vol_regs = (struct hal2_vol_regs *)hpc3->pbus_extregs[2];
-	hal2->syn_regs = (struct hal2_syn_regs *)hpc3->pbus_extregs[3];
-
-	if (hal2_detect(hal2) < 0) {
-		ret = -ENODEV;
-		goto free_card;
-	}
-
-	hal2_init_codec(&hal2->dac, hpc3, 0);
-	hal2_init_codec(&hal2->adc, hpc3, 1);
-
-	/*
-	 * All DMA channel interfaces in HAL2 are designed to operate with
-	 * PBUS programmed for 2 cycles in D3, 2 cycles in D4 and 2 cycles
-	 * in D5. HAL2 is a 16-bit device which can accept both big and little
-	 * endian format. It assumes that even address bytes are on high
-	 * portion of PBUS (15:8) and assumes that HPC3 is programmed to
-	 * accept a live (unsynchronized) version of P_DREQ_N from HAL2.
-	 */
-#define HAL2_PBUS_DMACFG ((0 << HPC3_DMACFG_D3R_SHIFT) | \
-			  (2 << HPC3_DMACFG_D4R_SHIFT) | \
-			  (2 << HPC3_DMACFG_D5R_SHIFT) | \
-			  (0 << HPC3_DMACFG_D3W_SHIFT) | \
-			  (2 << HPC3_DMACFG_D4W_SHIFT) | \
-			  (2 << HPC3_DMACFG_D5W_SHIFT) | \
-				HPC3_DMACFG_DS16 | \
-				HPC3_DMACFG_EVENHI | \
-				HPC3_DMACFG_RTIME | \
-			  (8 << HPC3_DMACFG_BURST_SHIFT) | \
-				HPC3_DMACFG_DRQLIVE)
-	/*
-	 * Ignore what's mentioned in the specification and write value which
-	 * works in The Real World (TM)
-	 */
-	hpc3->pbus_dmacfg[hal2->dac.pbus.pbusnr][0] = 0x8208844;
-	hpc3->pbus_dmacfg[hal2->adc.pbus.pbusnr][0] = 0x8208844;
-
-	if (request_irq(SGI_HPCDMA_IRQ, hal2_interrupt, IRQF_SHARED,
-			hal2str, hal2)) {
-		printk(KERN_ERR "HAL2: Can't get irq %d\n", SGI_HPCDMA_IRQ);
-		ret = -EAGAIN;
-		goto free_card;
-	}
-
-	hal2->dev_dsp = register_sound_dsp(&hal2_audio_fops, -1);
-	if (hal2->dev_dsp < 0) {
-		ret = hal2->dev_dsp;
-		goto free_irq;
-	}
-
-	hal2->dev_mixer = register_sound_mixer(&hal2_mixer_fops, -1);
-	if (hal2->dev_mixer < 0) {
-		ret = hal2->dev_mixer;
-		goto unregister_dsp;
-	}
-
-	hal2_init_mixer(hal2);
-
-	*phal2 = hal2;
-	return 0;
-unregister_dsp:
-	unregister_sound_dsp(hal2->dev_dsp);
-free_irq:
-	free_irq(SGI_HPCDMA_IRQ, hal2);
-free_card:
-	kfree(hal2);
-
-	return ret;
-}
-
-extern void (*indy_volume_button)(int);
-
-/* 
- * Assuming only one HAL2 card. Mail me if you ever meet machine with
- * more than one.
- */
-static int __init init_hal2(void)
-{
-	int i, error;
-
-	for (i = 0; i < MAXCARDS; i++)
-		hal2_card[i] = NULL;
-
-	error = hal2_init_card(&hal2_card[0], hpc3c0);
-
-	/* let Indy's volume buttons work */
-	if (!error && !ip22_is_fullhouse())
-		indy_volume_button = hal2_volume_control;
-
-	return error;
-
-}
-
-static void __exit exit_hal2(void)
-{
-	int i;
-
-	/* unregister volume butons callback function */
-	indy_volume_button = NULL;
-	
-	for (i = 0; i < MAXCARDS; i++)
-		if (hal2_card[i]) {
-			free_irq(SGI_HPCDMA_IRQ, hal2_card[i]);
-			unregister_sound_dsp(hal2_card[i]->dev_dsp);
-			unregister_sound_mixer(hal2_card[i]->dev_mixer);
-			kfree(hal2_card[i]);
-	}
-}
-
-module_init(init_hal2);
-module_exit(exit_hal2);
-
-MODULE_DESCRIPTION("OSS compatible driver for SGI HAL2 audio");
-MODULE_AUTHOR("Ladislav Michl");
-MODULE_LICENSE("GPL");
diff --git a/sound/oss/hal2.h b/sound/oss/hal2.h
deleted file mode 100644
index 2bd3b52..0000000
--- a/sound/oss/hal2.h
+++ /dev/null
@@ -1,248 +0,0 @@
-#ifndef __HAL2_H
-#define __HAL2_H
-
-/*
- *  Driver for HAL2 sound processors
- *  Copyright (c) 1999 Ulf Carlsson <ulfc@bun.falkenberg.se>
- *  Copyright (c) 2001, 2002, 2003 Ladislav Michl <ladis@linux-mips.org>
- *
- *  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., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-#include <asm/addrspace.h>
-#include <asm/sgi/hpc3.h>
-#include <linux/spinlock.h>
-#include <linux/types.h>
-
-/* Indirect status register */
-
-#define H2_ISR_TSTATUS		0x01	/* RO: transaction status 1=busy */
-#define H2_ISR_USTATUS		0x02	/* RO: utime status bit 1=armed */
-#define H2_ISR_QUAD_MODE	0x04	/* codec mode 0=indigo 1=quad */
-#define H2_ISR_GLOBAL_RESET_N	0x08	/* chip global reset 0=reset */
-#define H2_ISR_CODEC_RESET_N	0x10	/* codec/synth reset 0=reset  */
-
-/* Revision register */
-
-#define H2_REV_AUDIO_PRESENT	0x8000	/* RO: audio present 0=present */
-#define H2_REV_BOARD_M		0x7000	/* RO: bits 14:12, board revision */
-#define H2_REV_MAJOR_CHIP_M	0x00F0	/* RO: bits 7:4, major chip revision */
-#define H2_REV_MINOR_CHIP_M	0x000F	/* RO: bits 3:0, minor chip revision */
-
-/* Indirect address register */
-
-/*
- * Address of indirect internal register to be accessed. A write to this
- * register initiates read or write access to the indirect registers in the
- * HAL2. Note that there af four indirect data registers for write access to
- * registers larger than 16 byte.
- */
-
-#define H2_IAR_TYPE_M		0xF000	/* bits 15:12, type of functional */
-					/* block the register resides in */
-					/* 1=DMA Port */
-					/* 9=Global DMA Control */
-					/* 2=Bresenham */
-					/* 3=Unix Timer */
-#define H2_IAR_NUM_M		0x0F00	/* bits 11:8 instance of the */
-					/* blockin which the indirect */
-					/* register resides */
-					/* If IAR_TYPE_M=DMA Port: */
-					/* 1=Synth In */
-					/* 2=AES In */
-					/* 3=AES Out */
-					/* 4=DAC Out */
-					/* 5=ADC Out */
-					/* 6=Synth Control */
-					/* If IAR_TYPE_M=Global DMA Control: */
-					/* 1=Control */
-					/* If IAR_TYPE_M=Bresenham: */
-					/* 1=Bresenham Clock Gen 1 */
-					/* 2=Bresenham Clock Gen 2 */
-					/* 3=Bresenham Clock Gen 3 */
-					/* If IAR_TYPE_M=Unix Timer: */
-					/* 1=Unix Timer */
-#define H2_IAR_ACCESS_SELECT	0x0080	/* 1=read 0=write */
-#define H2_IAR_PARAM		0x000C	/* Parameter Select */
-#define H2_IAR_RB_INDEX_M	0x0003	/* Read Back Index */
-					/* 00:word0 */
-					/* 01:word1 */
-					/* 10:word2 */
-					/* 11:word3 */
-/*
- * HAL2 internal addressing
- *
- * The HAL2 has "indirect registers" (idr) which are accessed by writing to the
- * Indirect Data registers. Write the address to the Indirect Address register
- * to transfer the data.
- *
- * We define the H2IR_* to the read address and H2IW_* to the write address and
- * H2I_* to be fields in whatever register is referred to.
- *
- * When we write to indirect registers which are larger than one word (16 bit)
- * we have to fill more than one indirect register before writing. When we read
- * back however we have to read several times, each time with different Read
- * Back Indexes (there are defs for doing this easily).
- */
-
-/*
- * Relay Control
- */
-#define H2I_RELAY_C		0x9100
-#define H2I_RELAY_C_STATE	0x01		/* state of RELAY pin signal */
-
-/* DMA port enable */
-
-#define H2I_DMA_PORT_EN		0x9104
-#define H2I_DMA_PORT_EN_SY_IN	0x01		/* Synth_in DMA port */
-#define H2I_DMA_PORT_EN_AESRX	0x02		/* AES receiver DMA port */
-#define H2I_DMA_PORT_EN_AESTX	0x04		/* AES transmitter DMA port */
-#define H2I_DMA_PORT_EN_CODECTX	0x08		/* CODEC transmit DMA port */
-#define H2I_DMA_PORT_EN_CODECR	0x10		/* CODEC receive DMA port */
-
-#define H2I_DMA_END		0x9108 		/* global dma endian select */
-#define H2I_DMA_END_SY_IN	0x01		/* Synth_in DMA port */
-#define H2I_DMA_END_AESRX	0x02		/* AES receiver DMA port */
-#define H2I_DMA_END_AESTX	0x04		/* AES transmitter DMA port */
-#define H2I_DMA_END_CODECTX	0x08		/* CODEC transmit DMA port */
-#define H2I_DMA_END_CODECR	0x10		/* CODEC receive DMA port */
-						/* 0=b_end 1=l_end */
-
-#define H2I_DMA_DRV		0x910C  	/* global PBUS DMA enable */
-
-#define H2I_SYNTH_C		0x1104		/* Synth DMA control */
-
-#define H2I_AESRX_C		0x1204	 	/* AES RX dma control */
-
-#define H2I_C_TS_EN		0x20		/* Timestamp enable */
-#define H2I_C_TS_FRMT		0x40		/* Timestamp format */
-#define H2I_C_NAUDIO		0x80		/* Sign extend */
-
-/* AESRX CTL, 16 bit */
-
-#define H2I_AESTX_C		0x1304		/* AES TX DMA control */
-#define H2I_AESTX_C_CLKID_SHIFT	3		/* Bresenham Clock Gen 1-3 */
-#define H2I_AESTX_C_CLKID_M	0x18
-#define H2I_AESTX_C_DATAT_SHIFT	8		/* 1=mono 2=stereo (3=quad) */
-#define H2I_AESTX_C_DATAT_M	0x300
-
-/* CODEC registers */
-
-#define H2I_DAC_C1		0x1404 		/* DAC DMA control, 16 bit */
-#define H2I_DAC_C2		0x1408		/* DAC DMA control, 32 bit */
-#define H2I_ADC_C1		0x1504 		/* ADC DMA control, 16 bit */
-#define H2I_ADC_C2		0x1508		/* ADC DMA control, 32 bit */
-
-/* Bits in CTL1 register */
-
-#define H2I_C1_DMA_SHIFT	0		/* DMA channel */
-#define H2I_C1_DMA_M		0x7
-#define H2I_C1_CLKID_SHIFT	3		/* Bresenham Clock Gen 1-3 */
-#define H2I_C1_CLKID_M		0x18
-#define H2I_C1_DATAT_SHIFT	8		/* 1=mono 2=stereo (3=quad) */
-#define H2I_C1_DATAT_M		0x300
-
-/* Bits in CTL2 register */
-
-#define H2I_C2_R_GAIN_SHIFT	0		/* right a/d input gain */	
-#define H2I_C2_R_GAIN_M		0xf	
-#define H2I_C2_L_GAIN_SHIFT	4		/* left a/d input gain */
-#define H2I_C2_L_GAIN_M		0xf0
-#define H2I_C2_R_SEL		0x100		/* right input select */
-#define H2I_C2_L_SEL		0x200		/* left input select */
-#define H2I_C2_MUTE		0x400		/* mute */
-#define H2I_C2_DO1		0x00010000	/* digital output port bit 0 */
-#define H2I_C2_DO2		0x00020000	/* digital output port bit 1 */
-#define H2I_C2_R_ATT_SHIFT	18		/* right d/a output - */
-#define H2I_C2_R_ATT_M		0x007c0000	/* attenuation */
-#define H2I_C2_L_ATT_SHIFT	23		/* left d/a output - */
-#define H2I_C2_L_ATT_M		0x0f800000	/* attenuation */
-
-#define H2I_SYNTH_MAP_C		0x1104		/* synth dma handshake ctrl */
-
-/* Clock generator CTL 1, 16 bit */
-
-#define H2I_BRES1_C1		0x2104
-#define H2I_BRES2_C1		0x2204
-#define H2I_BRES3_C1		0x2304
-
-#define H2I_BRES_C1_SHIFT	0		/* 0=48.0 1=44.1 2=aes_rx */
-#define H2I_BRES_C1_M		0x03
-				
-/* Clock generator CTL 2, 32 bit */
-
-#define H2I_BRES1_C2		0x2108
-#define H2I_BRES2_C2		0x2208
-#define H2I_BRES3_C2		0x2308
-
-#define H2I_BRES_C2_INC_SHIFT	0		/* increment value */
-#define H2I_BRES_C2_INC_M	0xffff
-#define H2I_BRES_C2_MOD_SHIFT	16		/* modcontrol value */
-#define H2I_BRES_C2_MOD_M	0xffff0000	/* modctrl=0xffff&(modinc-1) */
-
-/* Unix timer, 64 bit */
-
-#define H2I_UTIME		0x3104
-#define H2I_UTIME_0_LD		0xffff		/* microseconds, LSB's */
-#define H2I_UTIME_1_LD0		0x0f		/* microseconds, MSB's */
-#define H2I_UTIME_1_LD1		0xf0		/* tenths of microseconds */
-#define H2I_UTIME_2_LD		0xffff		/* seconds, LSB's */
-#define H2I_UTIME_3_LD		0xffff		/* seconds, MSB's */
-
-struct hal2_ctl_regs {
-	u32 _unused0[4];
-	volatile u32 isr;		/* 0x10 Status Register */
-	u32 _unused1[3];
-	volatile u32 rev;		/* 0x20 Revision Register */
-	u32 _unused2[3];
-	volatile u32 iar;		/* 0x30 Indirect Address Register */
-	u32 _unused3[3];
-	volatile u32 idr0;		/* 0x40 Indirect Data Register 0 */
-	u32 _unused4[3];
-	volatile u32 idr1;		/* 0x50 Indirect Data Register 1 */
-	u32 _unused5[3];
-	volatile u32 idr2;		/* 0x60 Indirect Data Register 2 */
-	u32 _unused6[3];
-	volatile u32 idr3;		/* 0x70 Indirect Data Register 3 */
-};
-
-struct hal2_aes_regs {
-	volatile u32 rx_stat[2];	/* Status registers */
-	volatile u32 rx_cr[2];		/* Control registers */
-	volatile u32 rx_ud[4];		/* User data window */
-	volatile u32 rx_st[24];		/* Channel status data */
-	
-	volatile u32 tx_stat[1];	/* Status register */
-	volatile u32 tx_cr[3];		/* Control registers */
-	volatile u32 tx_ud[4];		/* User data window */
-	volatile u32 tx_st[24];		/* Channel status data */
-};
-
-struct hal2_vol_regs {
-	volatile u32 right;		/* Right volume */
-	volatile u32 left;		/* Left volume */
-};
-
-struct hal2_syn_regs {
-	u32 _unused0[2];
-	volatile u32 page;		/* DOC Page register */
-	volatile u32 regsel;		/* DOC Register selection */
-	volatile u32 dlow;		/* DOC Data low */
-	volatile u32 dhigh;		/* DOC Data high */
-	volatile u32 irq;		/* IRQ Status */
-	volatile u32 dram;		/* DRAM Access */
-};
-
-#endif	/* __HAL2_H */
diff --git a/sound/oss/mpu401.c b/sound/oss/mpu401.c
index a690ca5..6c0a770 100644
--- a/sound/oss/mpu401.c
+++ b/sound/oss/mpu401.c
@@ -1015,7 +1015,7 @@
 		mpu401_chk_version(m, devc);
 		if (devc->version == 0)
 			mpu401_chk_version(m, devc);
-			spin_unlock_irqrestore(&devc->lock,flags);
+		spin_unlock_irqrestore(&devc->lock, flags);
 	}
 
 	if (devc->version != 0)
diff --git a/sound/parisc/harmony.c b/sound/parisc/harmony.c
index 99f5483..41f870f 100644
--- a/sound/parisc/harmony.c
+++ b/sound/parisc/harmony.c
@@ -868,7 +868,8 @@
 	struct snd_card *card = h->card;
 	int idx, err;
 
-	snd_assert(h != NULL, return -EINVAL);
+	if (snd_BUG_ON(!h))
+		return -EINVAL;
 	strcpy(card->mixername, "Harmony Gain control interface");
 
 	for (idx = 0; idx < HARMONY_CONTROLS; idx++) {
diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig
index 31f52d3..7003711 100644
--- a/sound/pci/Kconfig
+++ b/sound/pci/Kconfig
@@ -517,6 +517,14 @@
 	  This interface can be used for out-of-band communication
 	  with codecs for debugging purposes.
 
+config SND_HDA_INPUT_BEEP
+	bool "Support digital beep via input layer"
+	depends on SND_HDA_INTEL
+	depends on INPUT=y || INPUT=SND_HDA_INTEL
+	help
+	  Say Y here to build a digital beep interface for HD-audio
+	  driver. This interface is used to generate digital beeps.
+
 config SND_HDA_CODEC_REALTEK
 	bool "Build Realtek HD-audio codec support"
 	depends on SND_HDA_INTEL
@@ -557,6 +565,14 @@
 	  Say Y here to include ATI HDMI HD-audio codec support in
 	  snd-hda-intel driver, such as ATI RS600 HDMI.
 
+config SND_HDA_CODEC_NVHDMI
+	bool "Build NVIDIA HDMI HD-audio codec support"
+	depends on SND_HDA_INTEL
+	default y
+	help
+	  Say Y here to include NVIDIA HDMI HD-audio codec support in
+	  snd-hda-intel driver, such as NVIDIA MCP78 HDMI.
+
 config SND_HDA_CODEC_CONEXANT
 	bool "Build Conexant HD-audio codec support"
 	depends on SND_HDA_INTEL
@@ -649,8 +665,9 @@
 
 	  Currently supported hardware is: M-Audio Delta 1010(LT),
 	  DiO 2496, 66, 44, 410, Audiophile 24/96; Digigram VX442;
-	  TerraTec EWX 24/96, EWS 88MT, 88D, DMX 6Fire, Phase 88;
-	  Hoontech SoundTrack DSP 24/Value/Media7.1; Event EZ8.
+	  TerraTec EWX 24/96, EWS 88MT/D, DMX 6Fire, Phase 88;
+	  Hoontech SoundTrack DSP 24/Value/Media7.1; Event EZ8;
+	  Lionstracs Mediastation, Terrasoniq TS 88.
 
 	  To compile this driver as a module, choose M here: the module
 	  will be called snd-ice1712.
@@ -665,9 +682,12 @@
 	  ICE/VT1724/1720 (Envy24HT/PT) chips.
 
 	  Currently supported hardware is: AMP AUDIO2000; M-Audio
-	  Revolution 7.1; TerraTec Aureon 5.1 Sky, 7.1 Space/Universe;
-	  AudioTrak Prodigy 7.1; Pontis MS300; Albatron K8X800 Pro II;
-	  Chaintech ZNF3-150/250.
+	  Revolution 5.1, 7.1, Audiophile 192; TerraTec Aureon 5.1 Sky,
+	  7.1 Space/Universe, Phase 22/28; Onkyo SE-90PCI, SE-200PCI;
+	  AudioTrak Prodigy 192, 7.1 (HIFI/LT/XT), HD2; Hercules
+	  Fortissimo IV; ESI Juli@; Pontis MS300; EGO-SYS WaveTerminal
+	  192M; Albatron K8X800 Pro II; Chaintech ZNF3-150/250, 9CJS,
+	  AV-710; Shuttle SN25P.
 
 	  To compile this driver as a module, choose M here: the module
 	  will be called snd-ice1724.
@@ -845,7 +865,8 @@
 	select SND_OXYGEN_LIB
 	help
 	  Say Y here to include support for sound cards based on the
-	  Asus AV100/AV200 chips, i.e., Xonar D1, DX, D2 and D2X.
+	  Asus AV100/AV200 chips, i.e., Xonar D1, DX, D2, D2X and
+	  HDAV1.3 (Deluxe).
 
 	  To compile this driver as a module, choose M here: the module
 	  will be called snd-virtuoso.
diff --git a/sound/pci/ac97/ac97_codec.c b/sound/pci/ac97/ac97_codec.c
index 8c49a00..6704acb 100644
--- a/sound/pci/ac97/ac97_codec.c
+++ b/sound/pci/ac97/ac97_codec.c
@@ -67,8 +67,8 @@
 };
 
 static const struct ac97_codec_id snd_ac97_codec_id_vendors[] = {
-{ 0x414b4d00, 0xffffff00, "Asahi Kasei",	NULL,	NULL },
 { 0x41445300, 0xffffff00, "Analog Devices",	NULL,	NULL },
+{ 0x414b4d00, 0xffffff00, "Asahi Kasei",	NULL,	NULL },
 { 0x414c4300, 0xffffff00, "Realtek",		NULL,	NULL },
 { 0x414c4700, 0xffffff00, "Realtek",		NULL,	NULL },
 { 0x434d4900, 0xffffff00, "C-Media Electronics", NULL,	NULL },
@@ -94,11 +94,6 @@
 };
 
 static const struct ac97_codec_id snd_ac97_codec_ids[] = {
-{ 0x414b4d00, 0xffffffff, "AK4540",		NULL,		NULL },
-{ 0x414b4d01, 0xffffffff, "AK4542",		NULL,		NULL },
-{ 0x414b4d02, 0xffffffff, "AK4543",		NULL,		NULL },
-{ 0x414b4d06, 0xffffffff, "AK4544A",		NULL,		NULL },
-{ 0x414b4d07, 0xffffffff, "AK4545",		NULL,		NULL },
 { 0x41445303, 0xffffffff, "AD1819",		patch_ad1819,	NULL },
 { 0x41445340, 0xffffffff, "AD1881",		patch_ad1881,	NULL },
 { 0x41445348, 0xffffffff, "AD1881A",		patch_ad1881,	NULL },
@@ -112,20 +107,25 @@
 { 0x41445374, 0xffffffff, "AD1981B",		patch_ad1981b,	NULL },
 { 0x41445375, 0xffffffff, "AD1985",		patch_ad1985,	NULL },
 { 0x41445378, 0xffffffff, "AD1986",		patch_ad1986,	NULL },
+{ 0x414b4d00, 0xffffffff, "AK4540",		NULL,		NULL },
+{ 0x414b4d01, 0xffffffff, "AK4542",		NULL,		NULL },
+{ 0x414b4d02, 0xffffffff, "AK4543",		NULL,		NULL },
+{ 0x414b4d06, 0xffffffff, "AK4544A",		NULL,		NULL },
+{ 0x414b4d07, 0xffffffff, "AK4545",		NULL,		NULL },
 { 0x414c4300, 0xffffff00, "ALC100,100P", 	NULL,		NULL },
 { 0x414c4710, 0xfffffff0, "ALC200,200P",	NULL,		NULL },
 { 0x414c4721, 0xffffffff, "ALC650D",		NULL,	NULL }, /* already patched */
 { 0x414c4722, 0xffffffff, "ALC650E",		NULL,	NULL }, /* already patched */
 { 0x414c4723, 0xffffffff, "ALC650F",		NULL,	NULL }, /* already patched */
 { 0x414c4720, 0xfffffff0, "ALC650",		patch_alc650,	NULL },
-{ 0x414c4760, 0xfffffff0, "ALC655",		patch_alc655,	NULL },
-{ 0x414c4781, 0xffffffff, "ALC658D",		NULL,	NULL }, /* already patched */
-{ 0x414c4780, 0xfffffff0, "ALC658",		patch_alc655,	NULL },
-{ 0x414c4790, 0xfffffff0, "ALC850",		patch_alc850,	NULL },
 { 0x414c4730, 0xffffffff, "ALC101",		NULL,		NULL },
 { 0x414c4740, 0xfffffff0, "ALC202",		NULL,		NULL },
 { 0x414c4750, 0xfffffff0, "ALC250",		NULL,		NULL },
-{ 0x414c4770, 0xfffffff0, "ALC203",		NULL,		NULL },
+{ 0x414c4760, 0xfffffff0, "ALC655",		patch_alc655,	NULL },
+{ 0x414c4770, 0xfffffff0, "ALC203",		patch_alc203,	NULL },
+{ 0x414c4781, 0xffffffff, "ALC658D",		NULL,	NULL }, /* already patched */
+{ 0x414c4780, 0xfffffff0, "ALC658",		patch_alc655,	NULL },
+{ 0x414c4790, 0xfffffff0, "ALC850",		patch_alc850,	NULL },
 { 0x434d4941, 0xffffffff, "CMI9738",		patch_cm9738,	NULL },
 { 0x434d4961, 0xffffffff, "CMI9739",		patch_cm9739,	NULL },
 { 0x434d4969, 0xffffffff, "CMI9780",		patch_cm9780,	NULL },
@@ -168,7 +168,7 @@
 { 0x54584e20, 0xffffffff, "TLC320AD9xC",	NULL,		NULL },
 { 0x56494161, 0xffffffff, "VIA1612A",		NULL,		NULL }, // modified ICE1232 with S/PDIF
 { 0x56494170, 0xffffffff, "VIA1617A",		patch_vt1617a,	NULL }, // modified VT1616 with S/PDIF
-{ 0x56494182, 0xffffffff, "VIA1618",		NULL,		NULL },
+{ 0x56494182, 0xffffffff, "VIA1618",		patch_vt1618,   NULL },
 { 0x57454301, 0xffffffff, "W83971D",		NULL,		NULL },
 { 0x574d4c00, 0xffffffff, "WM9701,WM9701A",	NULL,		NULL },
 { 0x574d4C03, 0xffffffff, "WM9703,WM9707,WM9708,WM9717", patch_wolfson03, NULL},
@@ -1890,8 +1890,8 @@
 		.dev_free =	snd_ac97_bus_dev_free,
 	};
 
-	snd_assert(card != NULL, return -EINVAL);
-	snd_assert(rbus != NULL, return -EINVAL);
+	if (snd_BUG_ON(!card))
+		return -EINVAL;
 	bus = kzalloc(sizeof(*bus), GFP_KERNEL);
 	if (bus == NULL)
 		return -ENOMEM;
@@ -1906,7 +1906,8 @@
 		snd_ac97_bus_free(bus);
 		return err;
 	}
-	*rbus = bus;
+	if (rbus)
+		*rbus = bus;
 	return 0;
 }
 
@@ -1991,10 +1992,14 @@
 		.dev_disconnect =	snd_ac97_dev_disconnect,
 	};
 
-	snd_assert(rac97 != NULL, return -EINVAL);
-	*rac97 = NULL;
-	snd_assert(bus != NULL && template != NULL, return -EINVAL);
-	snd_assert(template->num < 4 && bus->codec[template->num] == NULL, return -EINVAL);
+	if (rac97)
+		*rac97 = NULL;
+	if (snd_BUG_ON(!bus || !template))
+		return -EINVAL;
+	if (snd_BUG_ON(template->num >= 4))
+		return -EINVAL;
+	if (bus->codec[template->num])
+		return -EBUSY;
 
 	card = bus->card;
 	ac97 = kzalloc(sizeof(*ac97), GFP_KERNEL);
diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c
index f4fbc79..6e831af 100644
--- a/sound/pci/ac97/ac97_patch.c
+++ b/sound/pci/ac97/ac97_patch.c
@@ -476,7 +476,7 @@
 }
 
 /*
- * May 2, 2003 Liam Girdwood <liam.girdwood@wolfsonmicro.com>
+ * May 2, 2003 Liam Girdwood <lrg@slimlogic.co.uk>
  *  removed broken wolfson00 patch.
  *  added support for WM9705,WM9708,WM9709,WM9710,WM9711,WM9712 and WM9717.
  */
@@ -2560,6 +2560,14 @@
 	return 0;
 }
 
+/*
+ * realtek ALC203: use mono-out for pin 37
+ */
+static int patch_alc203(struct snd_ac97 *ac97)
+{
+	snd_ac97_update_bits(ac97, 0x7a, 0x400, 0x400);
+	return 0;
+}
 
 /*
  * realtek ALC65x/850 codecs
@@ -3457,7 +3465,7 @@
 
 /*
  * unfortunately, the vt1617a stashes the twiddlers required for
- * nooding the i/o jacks on 2 different regs. * thameans that we cant
+ * noodling the i/o jacks on 2 different regs. that means that we can't
  * use the easy way provided by AC97_ENUM_DOUBLE() we have to write
  * are own funcs.
  *
@@ -3490,7 +3498,7 @@
 	
 	pac97 = snd_kcontrol_chip(kcontrol); /* grab codec handle */
 
-	/* grab our desirec bits, then mash them together in a manner
+	/* grab our desired bits, then mash them together in a manner
 	 * consistent with Table 6 on page 17 in the 1617a docs */
  
 	usSM51 = snd_ac97_read(pac97, 0x7a) >> 14;
@@ -3540,7 +3548,7 @@
 	},
 };
 
-int patch_vt1617a(struct snd_ac97 * ac97)
+static int patch_vt1617a(struct snd_ac97 * ac97)
 {
 	int err = 0;
 	int val;
@@ -3568,6 +3576,200 @@
 	return err;
 }
 
+/* VIA VT1618 8 CHANNEL AC97 CODEC
+ *
+ * VIA implements 'Smart 5.1' completely differently on the 1618 than
+ * it does on the 1617a. awesome! They seem to have sourced this
+ * particular revision of the technology from somebody else, it's
+ * called Universal Audio Jack and it shows up on some other folk's chips
+ * as well.
+ *
+ * ordering in this list reflects vt1618 docs for Reg 60h and
+ * the block diagram, DACs are as follows:
+ *
+ *        OUT_O -> Front,
+ *	  OUT_1 -> Surround,
+ *	  OUT_2 -> C/LFE
+ *
+ * Unlike the 1617a, each OUT has a consistent set of mappings
+ * for all bitpatterns other than 00:
+ *
+ *        01       Unmixed Output
+ *        10       Line In
+ *        11       Mic  In
+ *
+ * Special Case of 00:
+ *
+ *        OUT_0    Mixed Output
+ *        OUT_1    Reserved
+ *        OUT_2    Reserved
+ *
+ * I have no idea what the hell Reserved does, but on an MSI
+ * CN700T, i have to set it to get 5.1 output - YMMV, bad
+ * shit may happen.
+ *
+ * If other chips use Universal Audio Jack, then this code might be applicable
+ * to them.
+ */
+
+struct vt1618_uaj_item {
+	unsigned short mask;
+	unsigned short shift;
+	const char *items[4];
+};
+
+/* This list reflects the vt1618 docs for Vendor Defined Register 0x60. */
+
+static struct vt1618_uaj_item vt1618_uaj[3] = {
+	{
+		/* speaker jack */
+		.mask  = 0x03,
+		.shift = 0,
+		.items = {
+			"Speaker Out", "DAC Unmixed Out", "Line In", "Mic In"
+		}
+	},
+	{
+		/* line jack */
+		.mask  = 0x0c,
+		.shift = 2,
+		.items = {
+			"Surround Out", "DAC Unmixed Out", "Line In", "Mic In"
+		}
+	},
+	{
+		/* mic jack */
+		.mask  = 0x30,
+		.shift = 4,
+		.items = {
+			"Center LFE Out", "DAC Unmixed Out", "Line In", "Mic In"
+		},
+	},
+};
+
+static int snd_ac97_vt1618_UAJ_info(struct snd_kcontrol *kcontrol,
+				    struct snd_ctl_elem_info *uinfo)
+{
+	return ac97_enum_text_info(kcontrol, uinfo,
+				   vt1618_uaj[kcontrol->private_value].items,
+				   4);
+}
+
+/* All of the vt1618 Universal Audio Jack twiddlers are on
+ * Vendor Defined Register 0x60, page 0. The bits, and thus
+ * the mask, are the only thing that changes
+ */
+static int snd_ac97_vt1618_UAJ_get(struct snd_kcontrol *kcontrol,
+				   struct snd_ctl_elem_value *ucontrol)
+{
+	unsigned short datpag, uaj;
+	struct snd_ac97 *pac97 = snd_kcontrol_chip(kcontrol);
+
+	mutex_lock(&pac97->page_mutex);
+
+	datpag = snd_ac97_read(pac97, AC97_INT_PAGING) & AC97_PAGE_MASK;
+	snd_ac97_update_bits(pac97, AC97_INT_PAGING, AC97_PAGE_MASK, 0);
+
+	uaj = snd_ac97_read(pac97, 0x60) &
+		vt1618_uaj[kcontrol->private_value].mask;
+
+	snd_ac97_update_bits(pac97, AC97_INT_PAGING, AC97_PAGE_MASK, datpag);
+	mutex_unlock(&pac97->page_mutex);
+
+	ucontrol->value.enumerated.item[0] = uaj >>
+		vt1618_uaj[kcontrol->private_value].shift;
+
+	return 0;
+}
+
+static int snd_ac97_vt1618_UAJ_put(struct snd_kcontrol *kcontrol,
+				   struct snd_ctl_elem_value *ucontrol)
+{
+	return ac97_update_bits_page(snd_kcontrol_chip(kcontrol), 0x60,
+				     vt1618_uaj[kcontrol->private_value].mask,
+				     ucontrol->value.enumerated.item[0]<<
+				     vt1618_uaj[kcontrol->private_value].shift,
+				     0);
+}
+
+/* config aux in jack - not found on 3 jack motherboards or soundcards */
+
+static int snd_ac97_vt1618_aux_info(struct snd_kcontrol *kcontrol,
+				     struct snd_ctl_elem_info *uinfo)
+{
+	static const char *txt_aux[] = {"Aux In", "Back Surr Out"};
+
+	return ac97_enum_text_info(kcontrol, uinfo, txt_aux, 2);
+}
+
+static int snd_ac97_vt1618_aux_get(struct snd_kcontrol *kcontrol,
+				   struct snd_ctl_elem_value *ucontrol)
+{
+	ucontrol->value.enumerated.item[0] =
+		(snd_ac97_read(snd_kcontrol_chip(kcontrol), 0x5c) & 0x0008)>>3;
+	return 0;
+}
+
+static int snd_ac97_vt1618_aux_put(struct snd_kcontrol *kcontrol,
+				   struct snd_ctl_elem_value *ucontrol)
+{
+	/* toggle surround rear dac power */
+
+	snd_ac97_update_bits(snd_kcontrol_chip(kcontrol), 0x5c, 0x0008,
+			     ucontrol->value.enumerated.item[0] << 3);
+
+	/* toggle aux in surround rear out jack */
+
+	return snd_ac97_update_bits(snd_kcontrol_chip(kcontrol), 0x76, 0x0008,
+				    ucontrol->value.enumerated.item[0] << 3);
+}
+
+static const struct snd_kcontrol_new snd_ac97_controls_vt1618[] = {
+	AC97_SINGLE("Exchange Center/LFE", 0x5a,  8, 1,     0),
+	AC97_SINGLE("DC Offset",           0x5a, 10, 1,     0),
+	AC97_SINGLE("Soft Mute",           0x5c,  0, 1,     1),
+	AC97_SINGLE("Headphone Amp",       0x5c,  5, 1,     1),
+	AC97_DOUBLE("Back Surr Volume",    0x5e,  8, 0, 31, 1),
+	AC97_SINGLE("Back Surr Switch",    0x5e, 15, 1,     1),
+	{
+		.iface         = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name          = "Speaker Jack Mode",
+		.info          = snd_ac97_vt1618_UAJ_info,
+		.get           = snd_ac97_vt1618_UAJ_get,
+		.put           = snd_ac97_vt1618_UAJ_put,
+		.private_value = 0
+	},
+	{
+		.iface         = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name          = "Line Jack Mode",
+		.info          = snd_ac97_vt1618_UAJ_info,
+		.get           = snd_ac97_vt1618_UAJ_get,
+		.put           = snd_ac97_vt1618_UAJ_put,
+		.private_value = 1
+	},
+	{
+		.iface         = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name          = "Mic Jack Mode",
+		.info          = snd_ac97_vt1618_UAJ_info,
+		.get           = snd_ac97_vt1618_UAJ_get,
+		.put           = snd_ac97_vt1618_UAJ_put,
+		.private_value = 2
+	},
+	{
+		.iface         = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name          = "Aux Jack Mode",
+		.info          = snd_ac97_vt1618_aux_info,
+		.get           = snd_ac97_vt1618_aux_get,
+		.put           = snd_ac97_vt1618_aux_put,
+	}
+};
+
+static int patch_vt1618(struct snd_ac97 *ac97)
+{
+	return patch_build_controls(ac97, snd_ac97_controls_vt1618,
+				    ARRAY_SIZE(snd_ac97_controls_vt1618));
+}
+
 /*
  */
 static void it2646_update_jacks(struct snd_ac97 *ac97)
diff --git a/sound/pci/ad1889.c b/sound/pci/ad1889.c
index 39ec55b..92f3a97 100644
--- a/sound/pci/ad1889.c
+++ b/sound/pci/ad1889.c
@@ -549,7 +549,8 @@
 	ptr = ad1889_readl(chip, AD_DMA_WAVCA);
 	ptr -= chip->wave.addr;
 	
-	snd_assert((ptr >= 0) && (ptr < chip->wave.size), return 0);
+	if (snd_BUG_ON(ptr >= chip->wave.size))
+		return 0;
 	
 	return bytes_to_frames(ss->runtime, ptr);
 }
@@ -567,7 +568,8 @@
 	ptr = ad1889_readl(chip, AD_DMA_ADCCA);
 	ptr -= chip->ramc.addr;
 
-	snd_assert((ptr >= 0) && (ptr < chip->ramc.size), return 0);
+	if (snd_BUG_ON(ptr >= chip->ramc.size))
+		return 0;
 	
 	return bytes_to_frames(ss->runtime, ptr);
 }
diff --git a/sound/pci/ak4531_codec.c b/sound/pci/ak4531_codec.c
index 33d37b1..0f819dd 100644
--- a/sound/pci/ak4531_codec.c
+++ b/sound/pci/ak4531_codec.c
@@ -392,9 +392,10 @@
 		.dev_free =	snd_ak4531_dev_free,
 	};
 
-	snd_assert(rak4531 != NULL, return -EINVAL);
-	*rak4531 = NULL;
-	snd_assert(card != NULL && _ak4531 != NULL, return -EINVAL);
+	if (snd_BUG_ON(!card || !_ak4531))
+		return -EINVAL;
+	if (rak4531)
+		*rak4531 = NULL;
 	ak4531 = kzalloc(sizeof(*ak4531), GFP_KERNEL);
 	if (ak4531 == NULL)
 		return -ENOMEM;
@@ -428,7 +429,8 @@
 #if 0
 	snd_ak4531_dump(ak4531);
 #endif
-	*rak4531 = ak4531;
+	if (rak4531)
+		*rak4531 = ak4531;
 	return 0;
 }
 
diff --git a/sound/pci/als4000.c b/sound/pci/als4000.c
index 27ce613..ba57005 100644
--- a/sound/pci/als4000.c
+++ b/sound/pci/als4000.c
@@ -2,7 +2,7 @@
  *  card-als4000.c - driver for Avance Logic ALS4000 based soundcards.
  *  Copyright (C) 2000 by Bart Hartgers <bart@etpmod.phys.tue.nl>,
  *			  Jaroslav Kysela <perex@perex.cz>
- *  Copyright (C) 2002 by Andreas Mohr <hw7oshyuv3001@sneakemail.com>
+ *  Copyright (C) 2002, 2008 by Andreas Mohr <hw7oshyuv3001@sneakemail.com>
  *
  *  Framework borrowed from Massimo Piccioni's card-als100.c.
  *
@@ -27,8 +27,10 @@
  *  bought an ALS4000 based soundcard, I was forced to base this driver
  *  on reverse engineering.
  *
- *  Note: this is no longer true. Pretty verbose chip docu (ALS4000a.PDF)
- *  can be found on the ALSA web site.
+ *  Note: this is no longer true (thank you!):
+ *  pretty verbose chip docu (ALS4000a.PDF) can be found on the ALSA web site.
+ *  Page numbers stated anywhere below with the "SPECS_PAGE:" tag
+ *  refer to: ALS4000a.PDF specs Ver 1.0, May 28th, 1998.
  *
  *  The ALS4000 seems to be the PCI-cousin of the ALS100. It contains an
  *  ALS100-like SB DSP/mixer, an OPL3 synth, a MPU401 and a gameport 
@@ -59,7 +61,7 @@
  * - value -> some port 0x0c0d
  *
  * ToDo:
- * - Proper shared IRQ handling?
+ * - by default, don't enable legacy game and use PCI game I/O
  * - power management? (card can do voice wakeup according to datasheet!!)
  */
 
@@ -78,7 +80,7 @@
 #include <sound/sb.h>
 #include <sound/initval.h>
 
-MODULE_AUTHOR("Bart Hartgers <bart@etpmod.phys.tue.nl>");
+MODULE_AUTHOR("Bart Hartgers <bart@etpmod.phys.tue.nl>, Andreas Mohr");
 MODULE_DESCRIPTION("Avance Logic ALS4000");
 MODULE_LICENSE("GPL");
 MODULE_SUPPORTED_DEVICE("{{Avance Logic,ALS4000}}");
@@ -107,7 +109,7 @@
 
 struct snd_card_als4000 {
 	/* most frequent access first */
-	unsigned long gcr;
+	unsigned long iobase;
 	struct pci_dev *pci;
 	struct snd_sb *chip;
 #ifdef SUPPORT_JOYSTICK
@@ -122,28 +124,168 @@
 
 MODULE_DEVICE_TABLE(pci, snd_als4000_ids);
 
-static inline void snd_als4000_gcr_write_addr(unsigned long port, u32 reg, u32 val)
+enum als4k_iobase_t {
+	/* IOx: B == Byte, W = Word, D = DWord; SPECS_PAGE: 37 */
+	ALS4K_IOD_00_AC97_ACCESS = 0x00,
+	ALS4K_IOW_04_AC97_READ = 0x04,
+	ALS4K_IOB_06_AC97_STATUS = 0x06,
+	ALS4K_IOB_07_IRQSTATUS = 0x07,
+	ALS4K_IOD_08_GCR_DATA = 0x08,
+	ALS4K_IOB_0C_GCR_INDEX = 0x0c,
+	ALS4K_IOB_0E_IRQTYPE_SB_CR1E_MPU = 0x0e,
+	ALS4K_IOB_10_ADLIB_ADDR0 = 0x10,
+	ALS4K_IOB_11_ADLIB_ADDR1 = 0x11,
+	ALS4K_IOB_12_ADLIB_ADDR2 = 0x12,
+	ALS4K_IOB_13_ADLIB_ADDR3 = 0x13,
+	ALS4K_IOB_14_MIXER_INDEX = 0x14,
+	ALS4K_IOB_15_MIXER_DATA = 0x15,
+	ALS4K_IOB_16_ESP_RESET = 0x16,
+	ALS4K_IOB_16_ACK_FOR_CR1E = 0x16, /* 2nd function */
+	ALS4K_IOB_18_OPL_ADDR0 = 0x18,
+	ALS4K_IOB_19_OPL_ADDR1 = 0x19,
+	ALS4K_IOB_1A_ESP_RD_DATA = 0x1a,
+	ALS4K_IOB_1C_ESP_CMD_DATA = 0x1c,
+	ALS4K_IOB_1C_ESP_WR_STATUS = 0x1c, /* 2nd function */
+	ALS4K_IOB_1E_ESP_RD_STATUS8 = 0x1e,
+	ALS4K_IOB_1F_ESP_RD_STATUS16 = 0x1f,
+	ALS4K_IOB_20_ESP_GAMEPORT_200 = 0x20,
+	ALS4K_IOB_21_ESP_GAMEPORT_201 = 0x21,
+	ALS4K_IOB_30_MIDI_DATA = 0x30,
+	ALS4K_IOB_31_MIDI_STATUS = 0x31,
+	ALS4K_IOB_31_MIDI_COMMAND = 0x31, /* 2nd function */
+};
+
+enum als4k_iobase_0e_t {
+	ALS4K_IOB_0E_MPU_IRQ = 0x10,
+	ALS4K_IOB_0E_CR1E_IRQ = 0x40,
+	ALS4K_IOB_0E_SB_DMA_IRQ = 0x80,
+};
+
+enum als4k_gcr_t { /* all registers 32bit wide; SPECS_PAGE: 38 to 42 */
+	ALS4K_GCR8C_MISC_CTRL = 0x8c,
+	ALS4K_GCR90_TEST_MODE_REG = 0x90,
+	ALS4K_GCR91_DMA0_ADDR = 0x91,
+	ALS4K_GCR92_DMA0_MODE_COUNT = 0x92,
+	ALS4K_GCR93_DMA1_ADDR = 0x93,
+	ALS4K_GCR94_DMA1_MODE_COUNT = 0x94,
+	ALS4K_GCR95_DMA3_ADDR = 0x95,
+	ALS4K_GCR96_DMA3_MODE_COUNT = 0x96,
+	ALS4K_GCR99_DMA_EMULATION_CTRL = 0x99,
+	ALS4K_GCRA0_FIFO1_CURRENT_ADDR = 0xa0,
+	ALS4K_GCRA1_FIFO1_STATUS_BYTECOUNT = 0xa1,
+	ALS4K_GCRA2_FIFO2_PCIADDR = 0xa2,
+	ALS4K_GCRA3_FIFO2_COUNT = 0xa3,
+	ALS4K_GCRA4_FIFO2_CURRENT_ADDR = 0xa4,
+	ALS4K_GCRA5_FIFO1_STATUS_BYTECOUNT = 0xa5,
+	ALS4K_GCRA6_PM_CTRL = 0xa6,
+	ALS4K_GCRA7_PCI_ACCESS_STORAGE = 0xa7,
+	ALS4K_GCRA8_LEGACY_CFG1 = 0xa8,
+	ALS4K_GCRA9_LEGACY_CFG2 = 0xa9,
+	ALS4K_GCRFF_DUMMY_SCRATCH = 0xff,
+};
+
+enum als4k_gcr8c_t {
+	ALS4K_GCR8C_IRQ_MASK_CTRL_ENABLE = 0x8000,
+	ALS4K_GCR8C_CHIP_REV_MASK = 0xf0000
+};
+
+static inline void snd_als4k_iobase_writeb(unsigned long iobase,
+						enum als4k_iobase_t reg,
+						u8 val)
 {
-	outb(reg, port+0x0c);
-	outl(val, port+0x08);
+	outb(val, iobase + reg);
 }
 
-static inline void snd_als4000_gcr_write(struct snd_sb *sb, u32 reg, u32 val)
+static inline void snd_als4k_iobase_writel(unsigned long iobase,
+						enum als4k_iobase_t reg,
+						u32 val)
 {
-	snd_als4000_gcr_write_addr(sb->alt_port, reg, val);
+	outl(val, iobase + reg);
+}
+
+static inline u8 snd_als4k_iobase_readb(unsigned long iobase,
+						enum als4k_iobase_t reg)
+{
+	return inb(iobase + reg);
+}
+
+static inline u32 snd_als4k_iobase_readl(unsigned long iobase,
+						enum als4k_iobase_t reg)
+{
+	return inl(iobase + reg);
+}
+
+static inline void snd_als4k_gcr_write_addr(unsigned long iobase,
+						 enum als4k_gcr_t reg,
+						 u32 val)
+{
+	snd_als4k_iobase_writeb(iobase, ALS4K_IOB_0C_GCR_INDEX, reg);
+	snd_als4k_iobase_writel(iobase, ALS4K_IOD_08_GCR_DATA, val);
+}
+
+static inline void snd_als4k_gcr_write(struct snd_sb *sb,
+					 enum als4k_gcr_t reg,
+					 u32 val)
+{
+	snd_als4k_gcr_write_addr(sb->alt_port, reg, val);
 }	
 
-static inline u32 snd_als4000_gcr_read_addr(unsigned long port, u32 reg)
+static inline u32 snd_als4k_gcr_read_addr(unsigned long iobase,
+						 enum als4k_gcr_t reg)
 {
-	outb(reg, port+0x0c);
-	return inl(port+0x08);
+	/* SPECS_PAGE: 37/38 */
+	snd_als4k_iobase_writeb(iobase, ALS4K_IOB_0C_GCR_INDEX, reg);
+	return snd_als4k_iobase_readl(iobase, ALS4K_IOD_08_GCR_DATA);
 }
 
-static inline u32 snd_als4000_gcr_read(struct snd_sb *sb, u32 reg)
+static inline u32 snd_als4k_gcr_read(struct snd_sb *sb, enum als4k_gcr_t reg)
 {
-	return snd_als4000_gcr_read_addr(sb->alt_port, reg);
+	return snd_als4k_gcr_read_addr(sb->alt_port, reg);
 }
 
+enum als4k_cr_t { /* all registers 8bit wide; SPECS_PAGE: 20 to 23 */
+	ALS4K_CR0_SB_CONFIG = 0x00,
+	ALS4K_CR2_MISC_CONTROL = 0x02,
+	ALS4K_CR3_CONFIGURATION = 0x03,
+	ALS4K_CR17_FIFO_STATUS = 0x17,
+	ALS4K_CR18_ESP_MAJOR_VERSION = 0x18,
+	ALS4K_CR19_ESP_MINOR_VERSION = 0x19,
+	ALS4K_CR1A_MPU401_UART_MODE_CONTROL = 0x1a,
+	ALS4K_CR1C_FIFO2_BLOCK_LENGTH_LO = 0x1c,
+	ALS4K_CR1D_FIFO2_BLOCK_LENGTH_HI = 0x1d,
+	ALS4K_CR1E_FIFO2_CONTROL = 0x1e, /* secondary PCM FIFO (recording) */
+	ALS4K_CR3A_MISC_CONTROL = 0x3a,
+	ALS4K_CR3B_CRC32_BYTE0 = 0x3b, /* for testing, activate via CR3A */
+	ALS4K_CR3C_CRC32_BYTE1 = 0x3c,
+	ALS4K_CR3D_CRC32_BYTE2 = 0x3d,
+	ALS4K_CR3E_CRC32_BYTE3 = 0x3e,
+};
+
+enum als4k_cr0_t {
+	ALS4K_CR0_DMA_CONTIN_MODE_CTRL = 0x02, /* IRQ/FIFO controlled for 0/1 */
+	ALS4K_CR0_DMA_90H_MODE_CTRL = 0x04, /* IRQ/FIFO controlled for 0/1 */
+	ALS4K_CR0_MX80_81_REG_WRITE_ENABLE = 0x80,
+};
+
+static inline void snd_als4_cr_write(struct snd_sb *chip,
+					enum als4k_cr_t reg,
+					u8 data)
+{
+	/* Control Register is reg | 0xc0 (bit 7, 6 set) on sbmixer_index
+	 * NOTE: assumes chip->mixer_lock to be locked externally already!
+	 * SPECS_PAGE: 6 */
+	snd_sbmixer_write(chip, reg | 0xc0, data);
+}
+
+static inline u8 snd_als4_cr_read(struct snd_sb *chip,
+					enum als4k_cr_t reg)
+{
+	/* NOTE: assumes chip->mixer_lock to be locked externally already! */
+	return snd_sbmixer_read(chip, reg | 0xc0);
+}
+
+
+
 static void snd_als4000_set_rate(struct snd_sb *chip, unsigned int rate)
 {
 	if (!(chip->mode & SB_RATE_LOCK)) {
@@ -156,15 +298,19 @@
 static inline void snd_als4000_set_capture_dma(struct snd_sb *chip,
 					       dma_addr_t addr, unsigned size)
 {
-	snd_als4000_gcr_write(chip, 0xa2, addr);
-	snd_als4000_gcr_write(chip, 0xa3, (size-1));
+	/* SPECS_PAGE: 40 */
+	snd_als4k_gcr_write(chip, ALS4K_GCRA2_FIFO2_PCIADDR, addr);
+	snd_als4k_gcr_write(chip, ALS4K_GCRA3_FIFO2_COUNT, (size-1));
 }
 
 static inline void snd_als4000_set_playback_dma(struct snd_sb *chip,
-						dma_addr_t addr, unsigned size)
+						dma_addr_t addr,
+						unsigned size)
 {
-	snd_als4000_gcr_write(chip, 0x91, addr);
-	snd_als4000_gcr_write(chip, 0x92, (size-1)|0x180000);
+	/* SPECS_PAGE: 38 */
+	snd_als4k_gcr_write(chip, ALS4K_GCR91_DMA0_ADDR, addr);
+	snd_als4k_gcr_write(chip, ALS4K_GCR92_DMA0_MODE_COUNT,
+							(size-1)|0x180000);
 }
 
 #define ALS4000_FORMAT_SIGNED	(1<<0)
@@ -248,7 +394,7 @@
 	count = snd_pcm_lib_period_bytes(substream);
 	
 	if (chip->capture_format & ALS4000_FORMAT_16BIT)
-		count >>=1;
+		count >>= 1;
 	count--;
 
 	spin_lock_irq(&chip->reg_lock);
@@ -256,8 +402,8 @@
 	snd_als4000_set_capture_dma(chip, runtime->dma_addr, size);
 	spin_unlock_irq(&chip->reg_lock);
 	spin_lock_irq(&chip->mixer_lock);
-	snd_sbmixer_write(chip, 0xdc, count);
-	snd_sbmixer_write(chip, 0xdd, count>>8);
+	snd_als4_cr_write(chip, ALS4K_CR1C_FIFO2_BLOCK_LENGTH_LO, count & 0xff);
+	snd_als4_cr_write(chip, ALS4K_CR1D_FIFO2_BLOCK_LENGTH_HI, count >> 8);
 	spin_unlock_irq(&chip->mixer_lock);
 	return 0;
 }
@@ -275,7 +421,7 @@
 	count = snd_pcm_lib_period_bytes(substream);
 	
 	if (chip->playback_format & ALS4000_FORMAT_16BIT)
-		count >>=1;
+		count >>= 1;
 	count--;
 	
 	/* FIXME: from second playback on, there's a lot more clicks and pops
@@ -292,8 +438,8 @@
 	/* snd_sbdsp_command(chip, SB_DSP_SPEAKER_ON); */
 	snd_sbdsp_command(chip, playback_cmd(chip).dsp_cmd);
 	snd_sbdsp_command(chip, playback_cmd(chip).format);
-	snd_sbdsp_command(chip, count);
-	snd_sbdsp_command(chip, count>>8);
+	snd_sbdsp_command(chip, count & 0xff);
+	snd_sbdsp_command(chip, count >> 8);
 	snd_sbdsp_command(chip, playback_cmd(chip).dma_off);	
 	spin_unlock_irq(&chip->reg_lock);
 	
@@ -305,17 +451,25 @@
 	struct snd_sb *chip = snd_pcm_substream_chip(substream);
 	int result = 0;
 	
+	/* FIXME race condition in here!!!
+	   chip->mode non-atomic update gets consistently protected
+	   by reg_lock always, _except_ for this place!!
+	   Probably need to take reg_lock as outer (or inner??) lock, too.
+	   (or serialize both lock operations? probably not, though... - racy?)
+	*/
 	spin_lock(&chip->mixer_lock);
 	switch (cmd) {
 	case SNDRV_PCM_TRIGGER_START:
 	case SNDRV_PCM_TRIGGER_RESUME:
 		chip->mode |= SB_RATE_LOCK_CAPTURE;
-		snd_sbmixer_write(chip, 0xde, capture_cmd(chip));
+		snd_als4_cr_write(chip, ALS4K_CR1E_FIFO2_CONTROL,
+							 capture_cmd(chip));
 		break;
 	case SNDRV_PCM_TRIGGER_STOP:
 	case SNDRV_PCM_TRIGGER_SUSPEND:
 		chip->mode &= ~SB_RATE_LOCK_CAPTURE;
-		snd_sbmixer_write(chip, 0xde, 0);
+		snd_als4_cr_write(chip, ALS4K_CR1E_FIFO2_CONTROL,
+							 capture_cmd(chip));
 		break;
 	default:
 		result = -EINVAL;
@@ -356,8 +510,9 @@
 	unsigned int result;
 
 	spin_lock(&chip->reg_lock);	
-	result = snd_als4000_gcr_read(chip, 0xa4) & 0xffff;
+	result = snd_als4k_gcr_read(chip, ALS4K_GCRA4_FIFO2_CURRENT_ADDR);
 	spin_unlock(&chip->reg_lock);
+	result &= 0xffff;
 	return bytes_to_frames( substream->runtime, result );
 }
 
@@ -367,8 +522,9 @@
 	unsigned result;
 
 	spin_lock(&chip->reg_lock);	
-	result = snd_als4000_gcr_read(chip, 0xa0) & 0xffff;
+	result = snd_als4k_gcr_read(chip, ALS4K_GCRA0_FIFO1_CURRENT_ADDR);
 	spin_unlock(&chip->reg_lock);
+	result &= 0xffff;
 	return bytes_to_frames( substream->runtime, result );
 }
 
@@ -376,45 +532,63 @@
  * return IRQ_HANDLED no matter whether we actually had an IRQ flag or not).
  * ALS4000a.PDF writes that while ACKing IRQ in PCI block will *not* ACK
  * the IRQ in the SB core, ACKing IRQ in SB block *will* ACK the PCI IRQ
- * register (alt_port + 0x0e). Probably something could be optimized here to
- * query/write one register only...
+ * register (alt_port + ALS4K_IOB_0E_IRQTYPE_SB_CR1E_MPU). Probably something
+ * could be optimized here to query/write one register only...
  * And even if both registers need to be queried, then there's still the
  * question of whether it's actually correct to ACK PCI IRQ before reading
  * SB IRQ like we do now, since ALS4000a.PDF mentions that PCI IRQ will *clear*
  * SB IRQ status.
+ * (hmm, SPECS_PAGE: 38 mentions it the other way around!)
  * And do we *really* need the lock here for *reading* SB_DSP4_IRQSTATUS??
  * */
 static irqreturn_t snd_als4000_interrupt(int irq, void *dev_id)
 {
 	struct snd_sb *chip = dev_id;
-	unsigned gcr_status;
-	unsigned sb_status;
+	unsigned pci_irqstatus;
+	unsigned sb_irqstatus;
 
-	/* find out which bit of the ALS4000 produced the interrupt */
-	gcr_status = inb(chip->alt_port + 0xe);
-
-	if ((gcr_status & 0x80) && (chip->playback_substream)) /* playback */
+	/* find out which bit of the ALS4000 PCI block produced the interrupt,
+	   SPECS_PAGE: 38, 5 */
+	pci_irqstatus = snd_als4k_iobase_readb(chip->alt_port,
+				 ALS4K_IOB_0E_IRQTYPE_SB_CR1E_MPU);
+	if ((pci_irqstatus & ALS4K_IOB_0E_SB_DMA_IRQ)
+	 && (chip->playback_substream)) /* playback */
 		snd_pcm_period_elapsed(chip->playback_substream);
-	if ((gcr_status & 0x40) && (chip->capture_substream)) /* capturing */
+	if ((pci_irqstatus & ALS4K_IOB_0E_CR1E_IRQ)
+	 && (chip->capture_substream)) /* capturing */
 		snd_pcm_period_elapsed(chip->capture_substream);
-	if ((gcr_status & 0x10) && (chip->rmidi)) /* MPU401 interrupt */
+	if ((pci_irqstatus & ALS4K_IOB_0E_MPU_IRQ)
+	 && (chip->rmidi)) /* MPU401 interrupt */
 		snd_mpu401_uart_interrupt(irq, chip->rmidi->private_data);
-	/* release the gcr */
-	outb(gcr_status, chip->alt_port + 0xe);
+	/* ACK the PCI block IRQ */
+	snd_als4k_iobase_writeb(chip->alt_port,
+			 ALS4K_IOB_0E_IRQTYPE_SB_CR1E_MPU, pci_irqstatus);
 	
 	spin_lock(&chip->mixer_lock);
-	sb_status = snd_sbmixer_read(chip, SB_DSP4_IRQSTATUS);
+	/* SPECS_PAGE: 20 */
+	sb_irqstatus = snd_sbmixer_read(chip, SB_DSP4_IRQSTATUS);
 	spin_unlock(&chip->mixer_lock);
 	
-	if (sb_status & SB_IRQTYPE_8BIT) 
+	if (sb_irqstatus & SB_IRQTYPE_8BIT)
 		snd_sb_ack_8bit(chip);
-	if (sb_status & SB_IRQTYPE_16BIT) 
+	if (sb_irqstatus & SB_IRQTYPE_16BIT)
 		snd_sb_ack_16bit(chip);
-	if (sb_status & SB_IRQTYPE_MPUIN)
+	if (sb_irqstatus & SB_IRQTYPE_MPUIN)
 		inb(chip->mpu_port);
-	if (sb_status & 0x20)
-		inb(SBP(chip, RESET));
-	return IRQ_HANDLED;
+	if (sb_irqstatus & ALS4K_IRQTYPE_CR1E_DMA)
+		snd_als4k_iobase_readb(chip->alt_port,
+					ALS4K_IOB_16_ACK_FOR_CR1E);
+
+	/* printk(KERN_INFO "als4000: irq 0x%04x 0x%04x\n",
+					 pci_irqstatus, sb_irqstatus); */
+
+	/* only ack the things we actually handled above */
+	return IRQ_RETVAL(
+	     (pci_irqstatus & (ALS4K_IOB_0E_SB_DMA_IRQ|ALS4K_IOB_0E_CR1E_IRQ|
+				ALS4K_IOB_0E_MPU_IRQ))
+	  || (sb_irqstatus & (SB_IRQTYPE_8BIT|SB_IRQTYPE_16BIT|
+				SB_IRQTYPE_MPUIN|ALS4K_IRQTYPE_CR1E_DMA))
+	);
 }
 
 /*****************************************************************/
@@ -526,7 +700,8 @@
 	struct snd_pcm *pcm;
 	int err;
 
-	if ((err = snd_pcm_new(chip->card, "ALS4000 DSP", device, 1, 1, &pcm)) < 0)
+	err = snd_pcm_new(chip->card, "ALS4000 DSP", device, 1, 1, &pcm);
+	if (err < 0)
 		return err;
 	pcm->private_data = chip;
 	pcm->info_flags = SNDRV_PCM_INFO_JOINT_DUPLEX;
@@ -543,48 +718,55 @@
 
 /******************************************************************/
 
-static void snd_als4000_set_addr(unsigned long gcr,
-					unsigned int sb,
-					unsigned int mpu,
-					unsigned int opl,
-					unsigned int game)
+static void snd_als4000_set_addr(unsigned long iobase,
+					unsigned int sb_io,
+					unsigned int mpu_io,
+					unsigned int opl_io,
+					unsigned int game_io)
 {
-	u32 confA = 0;
-	u32 confB = 0;
+	u32 cfg1 = 0;
+	u32 cfg2 = 0;
 
-	if (mpu > 0)
-		confB |= (mpu | 1) << 16;
-	if (sb > 0)
-		confB |= (sb | 1);
-	if (game > 0)
-		confA |= (game | 1) << 16;
-	if (opl > 0)	
-		confA |= (opl | 1);
-	snd_als4000_gcr_write_addr(gcr, 0xa8, confA);
-	snd_als4000_gcr_write_addr(gcr, 0xa9, confB);
+	if (mpu_io > 0)
+		cfg2 |= (mpu_io | 1) << 16;
+	if (sb_io > 0)
+		cfg2 |= (sb_io | 1);
+	if (game_io > 0)
+		cfg1 |= (game_io | 1) << 16;
+	if (opl_io > 0)
+		cfg1 |= (opl_io | 1);
+	snd_als4k_gcr_write_addr(iobase, ALS4K_GCRA8_LEGACY_CFG1, cfg1);
+	snd_als4k_gcr_write_addr(iobase, ALS4K_GCRA9_LEGACY_CFG2, cfg2);
 }
 
 static void snd_als4000_configure(struct snd_sb *chip)
 {
-	unsigned tmp;
+	u8 tmp;
 	int i;
 
 	/* do some more configuration */
 	spin_lock_irq(&chip->mixer_lock);
-	tmp = snd_sbmixer_read(chip, 0xc0);
-	snd_sbmixer_write(chip, 0xc0, tmp|0x80);
-	/* always select DMA channel 0, since we do not actually use DMA */
+	tmp = snd_als4_cr_read(chip, ALS4K_CR0_SB_CONFIG);
+	snd_als4_cr_write(chip, ALS4K_CR0_SB_CONFIG,
+				tmp|ALS4K_CR0_MX80_81_REG_WRITE_ENABLE);
+	/* always select DMA channel 0, since we do not actually use DMA
+	 * SPECS_PAGE: 19/20 */
 	snd_sbmixer_write(chip, SB_DSP4_DMASETUP, SB_DMASETUP_DMA0);
-	snd_sbmixer_write(chip, 0xc0, tmp&0x7f);
+	snd_als4_cr_write(chip, ALS4K_CR0_SB_CONFIG,
+				 tmp & ~ALS4K_CR0_MX80_81_REG_WRITE_ENABLE);
 	spin_unlock_irq(&chip->mixer_lock);
 	
 	spin_lock_irq(&chip->reg_lock);
-	/* magic number. Enables interrupts(?) */
-	snd_als4000_gcr_write(chip, 0x8c, 0x28000);
-	for(i = 0x91; i <= 0x96; ++i)
-		snd_als4000_gcr_write(chip, i, 0);
+	/* enable interrupts */
+	snd_als4k_gcr_write(chip, ALS4K_GCR8C_MISC_CTRL,
+					ALS4K_GCR8C_IRQ_MASK_CTRL_ENABLE);
+
+	/* SPECS_PAGE: 39 */
+	for (i = ALS4K_GCR91_DMA0_ADDR; i <= ALS4K_GCR96_DMA3_MODE_COUNT; ++i)
+		snd_als4k_gcr_write(chip, i, 0);
 	
-	snd_als4000_gcr_write(chip, 0x99, snd_als4000_gcr_read(chip, 0x99));
+	snd_als4k_gcr_write(chip, ALS4K_GCR99_DMA_EMULATION_CTRL,
+		snd_als4k_gcr_read(chip, ALS4K_GCR99_DMA_EMULATION_CTRL));
 	spin_unlock_irq(&chip->reg_lock);
 }
 
@@ -628,7 +810,7 @@
 	gameport_set_port_data(gp, r);
 
 	/* Enable legacy joystick port */
-	snd_als4000_set_addr(acard->gcr, 0, 0, 0, 1);
+	snd_als4000_set_addr(acard->iobase, 0, 0, 0, 1);
 
 	gameport_register_port(acard->gameport);
 
@@ -643,7 +825,9 @@
 		gameport_unregister_port(acard->gameport);
 		acard->gameport = NULL;
 
-		snd_als4000_set_addr(acard->gcr, 0, 0, 0, 0); /* disable joystick */
+		/* disable joystick */
+		snd_als4000_set_addr(acard->iobase, 0, 0, 0, 0);
+
 		release_and_free_resource(r);
 	}
 }
@@ -654,10 +838,10 @@
 
 static void snd_card_als4000_free( struct snd_card *card )
 {
-	struct snd_card_als4000 * acard = (struct snd_card_als4000 *)card->private_data;
+	struct snd_card_als4000 *acard = card->private_data;
 
 	/* make sure that interrupts are disabled */
-	snd_als4000_gcr_write_addr( acard->gcr, 0x8c, 0);
+	snd_als4k_gcr_write_addr(acard->iobase, ALS4K_GCR8C_MISC_CTRL, 0);
 	/* free resources */
 	snd_als4000_free_gameport(acard);
 	pci_release_regions(acard->pci);
@@ -670,7 +854,7 @@
 	static int dev;
 	struct snd_card *card;
 	struct snd_card_als4000 *acard;
-	unsigned long gcr;
+	unsigned long iobase;
 	struct snd_sb *chip;
 	struct snd_opl3 *opl3;
 	unsigned short word;
@@ -699,31 +883,32 @@
 		pci_disable_device(pci);
 		return err;
 	}
-	gcr = pci_resource_start(pci, 0);
+	iobase = pci_resource_start(pci, 0);
 
 	pci_read_config_word(pci, PCI_COMMAND, &word);
 	pci_write_config_word(pci, PCI_COMMAND, word | PCI_COMMAND_IO);
 	pci_set_master(pci);
 	
 	card = snd_card_new(index[dev], id[dev], THIS_MODULE, 
-			    sizeof( struct snd_card_als4000 ) );
+			    sizeof(*acard) /* private_data: acard */);
 	if (card == NULL) {
 		pci_release_regions(pci);
 		pci_disable_device(pci);
 		return -ENOMEM;
 	}
 
-	acard = (struct snd_card_als4000 *)card->private_data;
+	acard = card->private_data;
 	acard->pci = pci;
-	acard->gcr = gcr;
+	acard->iobase = iobase;
 	card->private_free = snd_card_als4000_free;
 
 	/* disable all legacy ISA stuff */
-	snd_als4000_set_addr(acard->gcr, 0, 0, 0, 0);
+	snd_als4000_set_addr(acard->iobase, 0, 0, 0, 0);
 
 	if ((err = snd_sbdsp_create(card,
-				    gcr + 0x10,
+				    iobase + ALS4K_IOB_10_ADLIB_ADDR0,
 				    pci->irq,
+		/* internally registered as IRQF_SHARED in case of ALS4000 SB */
 				    snd_als4000_interrupt,
 				    -1,
 				    -1,
@@ -734,7 +919,7 @@
 	acard->chip = chip;
 
 	chip->pci = pci;
-	chip->alt_port = gcr;
+	chip->alt_port = iobase;
 	snd_card_set_dev(card, &pci->dev);
 
 	snd_als4000_configure(chip);
@@ -745,11 +930,18 @@
 		card->shortname, chip->alt_port, chip->irq);
 
 	if ((err = snd_mpu401_uart_new( card, 0, MPU401_HW_ALS4000,
-				        gcr+0x30, MPU401_INFO_INTEGRATED,
+					iobase + ALS4K_IOB_30_MIDI_DATA,
+					MPU401_INFO_INTEGRATED,
 					pci->irq, 0, &chip->rmidi)) < 0) {
-		printk(KERN_ERR "als4000: no MPU-401 device at 0x%lx?\n", gcr+0x30);
+		printk(KERN_ERR "als4000: no MPU-401 device at 0x%lx?\n",
+				iobase + ALS4K_IOB_30_MIDI_DATA);
 		goto out_err;
 	}
+	/* FIXME: ALS4000 has interesting MPU401 configuration features
+	 * at ALS4K_CR1A_MPU401_UART_MODE_CONTROL
+	 * (pass-thru / UART switching, fast MIDI clock, etc.),
+	 * however there doesn't seem to be an ALSA API for this...
+	 * SPECS_PAGE: 21 */
 
 	if ((err = snd_als4000_pcm(chip, 0)) < 0) {
 		goto out_err;
@@ -758,10 +950,13 @@
 		goto out_err;
 	}	    
 
-	if (snd_opl3_create(card, gcr+0x10, gcr+0x12,
+	if (snd_opl3_create(card,
+				iobase + ALS4K_IOB_10_ADLIB_ADDR0,
+				iobase + ALS4K_IOB_12_ADLIB_ADDR2,
 			    OPL3_HW_AUTO, 1, &opl3) < 0) {
 		printk(KERN_ERR "als4000: no OPL device at 0x%lx-0x%lx?\n",
-			   gcr+0x10, gcr+0x12 );
+			   iobase + ALS4K_IOB_10_ADLIB_ADDR0,
+			   iobase + ALS4K_IOB_12_ADLIB_ADDR2);
 	} else {
 		if ((err = snd_opl3_hwdep_new(opl3, 0, 1, NULL)) < 0) {
 			goto out_err;
@@ -831,13 +1026,13 @@
 
 #ifdef SUPPORT_JOYSTICK
 	if (acard->gameport)
-		snd_als4000_set_addr(acard->gcr, 0, 0, 0, 1);
+		snd_als4000_set_addr(acard->iobase, 0, 0, 0, 1);
 #endif
 
 	snd_power_change_state(card, SNDRV_CTL_POWER_D0);
 	return 0;
 }
-#endif
+#endif /* CONFIG_PM */
 
 
 static struct pci_driver driver = {
diff --git a/sound/pci/atiixp.c b/sound/pci/atiixp.c
index 457228f..085a52b 100644
--- a/sound/pci/atiixp.c
+++ b/sound/pci/atiixp.c
@@ -37,7 +37,7 @@
 MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>");
 MODULE_DESCRIPTION("ATI IXP AC97 controller");
 MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE("{{ATI,IXP150/200/250/300/400}}");
+MODULE_SUPPORTED_DEVICE("{{ATI,IXP150/200/250/300/400/600}}");
 
 static int index = SNDRV_DEFAULT_IDX1;	/* Index 0-MAX */
 static char *id = SNDRV_DEFAULT_STR1;	/* ID for this card */
@@ -290,6 +290,7 @@
 	{ 0x1002, 0x4341, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* SB200 */
 	{ 0x1002, 0x4361, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* SB300 */
 	{ 0x1002, 0x4370, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* SB400 */
+	{ 0x1002, 0x4382, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* SB600 */
 	{ 0, }
 };
 
@@ -722,7 +723,9 @@
 	struct atiixp_dma *dma = substream->runtime->private_data;
 	int err = 0;
 
-	snd_assert(dma->ops->enable_transfer && dma->ops->flush_dma, return -EINVAL);
+	if (snd_BUG_ON(!dma->ops->enable_transfer ||
+		       !dma->ops->flush_dma))
+		return -EINVAL;
 
 	spin_lock(&chip->reg_lock);
 	switch (cmd) {
@@ -1032,7 +1035,8 @@
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	int err;
 
-	snd_assert(dma->ops && dma->ops->enable_dma, return -EINVAL);
+	if (snd_BUG_ON(!dma->ops || !dma->ops->enable_dma))
+		return -EINVAL;
 
 	if (dma->opened)
 		return -EBUSY;
@@ -1064,7 +1068,8 @@
 {
 	struct atiixp *chip = snd_pcm_substream_chip(substream);
 	/* disable DMA bits */
-	snd_assert(dma->ops && dma->ops->enable_dma, return -EINVAL);
+	if (snd_BUG_ON(!dma->ops || !dma->ops->enable_dma))
+		return -EINVAL;
 	spin_lock_irq(&chip->reg_lock);
 	dma->ops->enable_dma(chip, 0);
 	spin_unlock_irq(&chip->reg_lock);
diff --git a/sound/pci/atiixp_modem.c b/sound/pci/atiixp_modem.c
index d457a32..2f10630 100644
--- a/sound/pci/atiixp_modem.c
+++ b/sound/pci/atiixp_modem.c
@@ -674,7 +674,9 @@
 	struct atiixp_dma *dma = substream->runtime->private_data;
 	int err = 0;
 
-	snd_assert(dma->ops->enable_transfer && dma->ops->flush_dma, return -EINVAL);
+	if (snd_BUG_ON(!dma->ops->enable_transfer ||
+		       !dma->ops->flush_dma))
+		return -EINVAL;
 
 	spin_lock(&chip->reg_lock);
 	switch(cmd) {
@@ -865,7 +867,8 @@
 		.mask = 0,
 	};
 
-	snd_assert(dma->ops && dma->ops->enable_dma, return -EINVAL);
+	if (snd_BUG_ON(!dma->ops || !dma->ops->enable_dma))
+		return -EINVAL;
 
 	if (dma->opened)
 		return -EBUSY;
@@ -895,7 +898,8 @@
 {
 	struct atiixp_modem *chip = snd_pcm_substream_chip(substream);
 	/* disable DMA bits */
-	snd_assert(dma->ops && dma->ops->enable_dma, return -EINVAL);
+	if (snd_BUG_ON(!dma->ops || !dma->ops->enable_dma))
+		return -EINVAL;
 	spin_lock_irq(&chip->reg_lock);
 	dma->ops->enable_dma(chip, 0);
 	spin_unlock_irq(&chip->reg_lock);
diff --git a/sound/pci/au88x0/au88x0.h b/sound/pci/au88x0/au88x0.h
index 4aad35b..cf46bba 100644
--- a/sound/pci/au88x0/au88x0.h
+++ b/sound/pci/au88x0/au88x0.h
@@ -125,7 +125,6 @@
 	/* Virtual page extender stuff */
 	int nr_periods;
 	int period_bytes;
-	struct snd_sg_buf *sgbuf;	/* DMA Scatter Gather struct */
 	int period_real;
 	int period_virt;
 
@@ -195,16 +194,14 @@
 
 /* DMA Engines. */
 static void vortex_adbdma_setbuffers(vortex_t * vortex, int adbdma,
-				     struct snd_sg_buf * sgbuf, int size,
-				     int count);
+				     int size, int count);
 static void vortex_adbdma_setmode(vortex_t * vortex, int adbdma, int ie,
 				  int dir, int fmt, int d,
 				  u32 offset);
 static void vortex_adbdma_setstartbuffer(vortex_t * vortex, int adbdma, int sb);
 #ifndef CHIP_AU8810
 static void vortex_wtdma_setbuffers(vortex_t * vortex, int wtdma,
-				    struct snd_sg_buf * sgbuf, int size,
-				    int count);
+				    int size, int count);
 static void vortex_wtdma_setmode(vortex_t * vortex, int wtdma, int ie, int fmt, int d,	/*int e, */
 				 u32 offset);
 static void vortex_wtdma_setstartbuffer(vortex_t * vortex, int wtdma, int sb);
diff --git a/sound/pci/au88x0/au88x0_core.c b/sound/pci/au88x0/au88x0_core.c
index 333c62d..b070e57 100644
--- a/sound/pci/au88x0/au88x0_core.c
+++ b/sound/pci/au88x0/au88x0_core.c
@@ -427,7 +427,7 @@
 
 	/* Set clipping ceiling (this may be all wrong). */
 	/*
-	for (x = 0; x > 0x80; x++) {
+	for (x = 0; x < 0x80; x++) {
 		hwwrite(vortex->mmio, VORTEX_MIXER_CLIP + (x << 2), 0x3ffff);
 	}
 	*/
@@ -1097,19 +1097,12 @@
 
 static void
 vortex_adbdma_setbuffers(vortex_t * vortex, int adbdma,
-			 struct snd_sg_buf * sgbuf, int psize, int count)
+			 int psize, int count)
 {
 	stream_t *dma = &vortex->dma_adb[adbdma];
 
-	if (sgbuf == NULL) {
-		printk(KERN_INFO "vortex: FATAL: sgbuf is NULL!\n");
-		return;
-	}
-	//printk(KERN_INFO "vortex: page count = %d, tblcount = %d\n", count, sgbuf->tblsize);
-
 	dma->period_bytes = psize;
 	dma->nr_periods = count;
-	dma->sgbuf = sgbuf;
 
 	dma->cfg0 = 0;
 	dma->cfg1 = 0;
@@ -1120,26 +1113,26 @@
 		dma->cfg1 |= 0x88000000 | 0x44000000 | 0x30000000 | (psize - 1);
 		hwwrite(vortex->mmio,
 			VORTEX_ADBDMA_BUFBASE + (adbdma << 4) + 0xc,
-			snd_sgbuf_get_addr(sgbuf, psize * 3));
+			snd_pcm_sgbuf_get_addr(dma->substream, psize * 3));
 		/* 3 pages */
 	case 3:
 		dma->cfg0 |= 0x12000000;
 		dma->cfg1 |= 0x80000000 | 0x40000000 | ((psize - 1) << 0xc);
 		hwwrite(vortex->mmio,
 			VORTEX_ADBDMA_BUFBASE + (adbdma << 4) + 0x8,
-			snd_sgbuf_get_addr(sgbuf, psize * 2));
+			snd_pcm_sgbuf_get_addr(dma->substream, psize * 2));
 		/* 2 pages */
 	case 2:
 		dma->cfg0 |= 0x88000000 | 0x44000000 | 0x10000000 | (psize - 1);
 		hwwrite(vortex->mmio,
 			VORTEX_ADBDMA_BUFBASE + (adbdma << 4) + 0x4,
-			snd_sgbuf_get_addr(sgbuf, psize));
+			snd_pcm_sgbuf_get_addr(dma->substream, psize));
 		/* 1 page */
 	case 1:
 		dma->cfg0 |= 0x80000000 | 0x40000000 | ((psize - 1) << 0xc);
 		hwwrite(vortex->mmio,
 			VORTEX_ADBDMA_BUFBASE + (adbdma << 4),
-			snd_sgbuf_get_addr(sgbuf, 0));
+			snd_pcm_sgbuf_get_addr(dma->substream, 0));
 		break;
 	}
 	//printk("vortex: cfg0 = 0x%x\nvortex: cfg1=0x%x\n", dma->cfg0, dma->cfg1);
@@ -1205,7 +1198,7 @@
 			//hwwrite(vortex->mmio, VORTEX_ADBDMA_BUFBASE+(((adbdma << 2)+pp) << 2), dma->table[p].addr);
 			hwwrite(vortex->mmio,
 				VORTEX_ADBDMA_BUFBASE + (((adbdma << 2) + pp) << 2),
-				snd_sgbuf_get_addr(dma->sgbuf,
+				snd_pcm_sgbuf_get_addr(dma->substream,
 				dma->period_bytes * p));
 			/* Force write thru cache. */
 			hwread(vortex->mmio, VORTEX_ADBDMA_BUFBASE +
@@ -1244,7 +1237,10 @@
 			if (pp >= 4)
 				pp -= 4;
 		}
-		hwwrite(vortex->mmio, VORTEX_ADBDMA_BUFBASE+(((adbdma << 2)+pp) << 2), snd_sgbuf_get_addr(dma->sgbuf, dma->period_bytes * p));
+		hwwrite(vortex->mmio,
+			VORTEX_ADBDMA_BUFBASE + (((adbdma << 2) + pp) << 2),
+			snd_pcm_sgbuf_get_addr(dma->substream,
+					       dma->period_bytes * p));
 		/* Force write thru cache. */
 		hwread(vortex->mmio, VORTEX_ADBDMA_BUFBASE + (((adbdma << 2)+pp) << 2));
 	}
@@ -1367,13 +1363,12 @@
 
 static void
 vortex_wtdma_setbuffers(vortex_t * vortex, int wtdma,
-			struct snd_sg_buf * sgbuf, int psize, int count)
+			int psize, int count)
 {
 	stream_t *dma = &vortex->dma_wt[wtdma];
 
 	dma->period_bytes = psize;
 	dma->nr_periods = count;
-	dma->sgbuf = sgbuf;
 
 	dma->cfg0 = 0;
 	dma->cfg1 = 0;
@@ -1383,23 +1378,23 @@
 	case 4:
 		dma->cfg1 |= 0x88000000 | 0x44000000 | 0x30000000 | (psize-1);
 		hwwrite(vortex->mmio, VORTEX_WTDMA_BUFBASE + (wtdma << 4) + 0xc,
-			snd_sgbuf_get_addr(sgbuf, psize * 3));
+			snd_pcm_sgbuf_get_addr(dma->substream, psize * 3));
 		/* 3 pages */
 	case 3:
 		dma->cfg0 |= 0x12000000;
 		dma->cfg1 |= 0x80000000 | 0x40000000 | ((psize-1) << 0xc);
 		hwwrite(vortex->mmio, VORTEX_WTDMA_BUFBASE + (wtdma << 4)  + 0x8,
-			snd_sgbuf_get_addr(sgbuf, psize * 2));
+			snd_pcm_sgbuf_get_addr(dma->substream, psize * 2));
 		/* 2 pages */
 	case 2:
 		dma->cfg0 |= 0x88000000 | 0x44000000 | 0x10000000 | (psize-1);
 		hwwrite(vortex->mmio, VORTEX_WTDMA_BUFBASE + (wtdma << 4) + 0x4,
-			snd_sgbuf_get_addr(sgbuf, psize));
+			snd_pcm_sgbuf_get_addr(dma->substream, psize));
 		/* 1 page */
 	case 1:
 		dma->cfg0 |= 0x80000000 | 0x40000000 | ((psize-1) << 0xc);
 		hwwrite(vortex->mmio, VORTEX_WTDMA_BUFBASE + (wtdma << 4),
-			snd_sgbuf_get_addr(sgbuf, 0));
+			snd_pcm_sgbuf_get_addr(dma->substream, 0));
 		break;
 	}
 	hwwrite(vortex->mmio, VORTEX_WTDMA_BUFCFG0 + (wtdma << 3), dma->cfg0);
@@ -1465,7 +1460,8 @@
 			hwwrite(vortex->mmio,
 				VORTEX_WTDMA_BUFBASE +
 				(((wtdma << 2) + pp) << 2),
-				snd_sgbuf_get_addr(dma->sgbuf, dma->period_bytes * p));
+				snd_pcm_sgbuf_get_addr(dma->substream,
+						       dma->period_bytes * p));
 			/* Force write thru cache. */
 			hwread(vortex->mmio, VORTEX_WTDMA_BUFBASE +
 			       (((wtdma << 2) + pp) << 2));
diff --git a/sound/pci/au88x0/au88x0_pcm.c b/sound/pci/au88x0/au88x0_pcm.c
index f9a58b4..b9d2f20 100644
--- a/sound/pci/au88x0/au88x0_pcm.c
+++ b/sound/pci/au88x0/au88x0_pcm.c
@@ -189,7 +189,6 @@
 {
 	vortex_t *chip = snd_pcm_substream_chip(substream);
 	stream_t *stream = (stream_t *) (substream->runtime->private_data);
-	struct snd_sg_buf *sgbuf;
 	int err;
 
 	// Alloc buffer memory.
@@ -199,8 +198,6 @@
 		printk(KERN_ERR "Vortex: pcm page alloc failed!\n");
 		return err;
 	}
-	//sgbuf = (struct snd_sg_buf *) substream->runtime->dma_private;
-	sgbuf = snd_pcm_substream_sgbuf(substream);
 	/*
 	   printk(KERN_INFO "Vortex: periods %d, period_bytes %d, channels = %d\n", params_periods(hw_params),
 	   params_period_bytes(hw_params), params_channels(hw_params));
@@ -226,7 +223,7 @@
 		stream = substream->runtime->private_data = &chip->dma_adb[dma];
 		stream->substream = substream;
 		/* Setup Buffers. */
-		vortex_adbdma_setbuffers(chip, dma, sgbuf,
+		vortex_adbdma_setbuffers(chip, dma,
 					 params_period_bytes(hw_params),
 					 params_periods(hw_params));
 	}
@@ -240,7 +237,7 @@
 		    &chip->dma_wt[substream->number];
 		stream->dma = substream->number;
 		stream->substream = substream;
-		vortex_wtdma_setbuffers(chip, substream->number, sgbuf,
+		vortex_wtdma_setbuffers(chip, substream->number,
 					params_period_bytes(hw_params),
 					params_periods(hw_params));
 	}
@@ -392,13 +389,6 @@
 	return (bytes_to_frames(substream->runtime, current_ptr));
 }
 
-/* Page callback. */
-/*
-static struct page *snd_pcm_sgbuf_ops_page(struct snd_pcm_substream *substream, unsigned long offset) {
-	
-	
-}
-*/
 /* operators */
 static struct snd_pcm_ops snd_vortex_playback_ops = {
 	.open = snd_vortex_pcm_open,
diff --git a/sound/pci/azt3328.c b/sound/pci/azt3328.c
index 22f18f3..333007c 100644
--- a/sound/pci/azt3328.c
+++ b/sound/pci/azt3328.c
@@ -816,7 +816,8 @@
 	int err;
 
 	snd_azf3328_dbgcallenter();
-	snd_assert(chip != NULL && chip->card != NULL, return -EINVAL);
+	if (snd_BUG_ON(!chip || !chip->card))
+		return -EINVAL;
 
 	card = chip->card;
 
@@ -1471,7 +1472,8 @@
 	u8 val;
 	unsigned long flags;
 
-	snd_assert(chip, return 0);
+	if (snd_BUG_ON(!chip))
+		return 0;
 
 	spin_lock_irqsave(&chip->reg_lock, flags);
 	val = snd_azf3328_game_inb(chip, IDX_GAME_LEGACY_COMPATIBLE);
diff --git a/sound/pci/bt87x.c b/sound/pci/bt87x.c
index 4ecdd63..3aa8d97 100644
--- a/sound/pci/bt87x.c
+++ b/sound/pci/bt87x.c
@@ -227,7 +227,6 @@
 static int snd_bt87x_create_risc(struct snd_bt87x *chip, struct snd_pcm_substream *substream,
 			       	 unsigned int periods, unsigned int period_bytes)
 {
-	struct snd_sg_buf *sgbuf = snd_pcm_substream_sgbuf(substream);
 	unsigned int i, offset;
 	u32 *risc;
 
@@ -246,6 +245,7 @@
 		rest = period_bytes;
 		do {
 			u32 cmd, len;
+			unsigned int addr;
 
 			len = PAGE_SIZE - (offset % PAGE_SIZE);
 			if (len > rest)
@@ -260,7 +260,8 @@
 			if (len == rest)
 				cmd |= RISC_EOL | RISC_IRQ;
 			*risc++ = cpu_to_le32(cmd);
-			*risc++ = cpu_to_le32((u32)snd_pcm_sgbuf_get_addr(sgbuf, offset));
+			addr = snd_pcm_sgbuf_get_addr(substream, offset);
+			*risc++ = cpu_to_le32(addr);
 			offset += len;
 			rest -= len;
 		} while (rest > 0);
diff --git a/sound/pci/ca0106/ca0106_main.c b/sound/pci/ca0106/ca0106_main.c
index 6abe8a3..a7d8966 100644
--- a/sound/pci/ca0106/ca0106_main.c
+++ b/sound/pci/ca0106/ca0106_main.c
@@ -254,7 +254,7 @@
 	   .name   = "MSI K8N Diamond MB",
 	   .gpio_type = 2,
 	   .i2c_adc = 1,
-	   .spi_dac = 2 },
+	   .spi_dac = 2 } ,
 	 /* Shuttle XPC SD31P which has an onboard Creative Labs
 	  * Sound Blaster Live! 24-bit EAX
 	  * high-definition 7.1 audio processor".
diff --git a/sound/pci/ca0106/ca_midi.c b/sound/pci/ca0106/ca_midi.c
index 893ee4f..c788511 100644
--- a/sound/pci/ca0106/ca_midi.c
+++ b/sound/pci/ca0106/ca_midi.c
@@ -125,7 +125,8 @@
 	struct snd_ca_midi *midi = substream->rmidi->private_data;
 	unsigned long flags;
 	
-	snd_assert(midi->dev_id, return -ENXIO);
+	if (snd_BUG_ON(!midi->dev_id))
+		return -ENXIO;
 	spin_lock_irqsave(&midi->open_lock, flags);
 	midi->midi_mode |= CA_MIDI_MODE_INPUT;
 	midi->substream_input = substream;
@@ -144,7 +145,8 @@
 	struct snd_ca_midi *midi = substream->rmidi->private_data;
 	unsigned long flags;
 
-	snd_assert(midi->dev_id, return -ENXIO);
+	if (snd_BUG_ON(!midi->dev_id))
+		return -ENXIO;
 	spin_lock_irqsave(&midi->open_lock, flags);
 	midi->midi_mode |= CA_MIDI_MODE_OUTPUT;
 	midi->substream_output = substream;
@@ -163,7 +165,8 @@
 	struct snd_ca_midi *midi = substream->rmidi->private_data;
 	unsigned long flags;
 
-	snd_assert(midi->dev_id, return -ENXIO);
+	if (snd_BUG_ON(!midi->dev_id))
+		return -ENXIO;
 	spin_lock_irqsave(&midi->open_lock, flags);
 	midi->interrupt_disable(midi,midi->rx_enable);
 	midi->midi_mode &= ~CA_MIDI_MODE_INPUT;
@@ -181,7 +184,9 @@
 {
 	struct snd_ca_midi *midi = substream->rmidi->private_data;
 	unsigned long flags;
-	snd_assert(midi->dev_id, return -ENXIO);
+
+	if (snd_BUG_ON(!midi->dev_id))
+		return -ENXIO;
 	
 	spin_lock_irqsave(&midi->open_lock, flags);
 
@@ -201,7 +206,9 @@
 static void ca_midi_input_trigger(struct snd_rawmidi_substream *substream, int up)
 {
 	struct snd_ca_midi *midi = substream->rmidi->private_data;
-	snd_assert(midi->dev_id, return);
+
+	if (snd_BUG_ON(!midi->dev_id))
+		return;
 
 	if (up) {
 		midi->interrupt_enable(midi,midi->rx_enable);
@@ -215,7 +222,8 @@
 	struct snd_ca_midi *midi = substream->rmidi->private_data;
 	unsigned long flags;
 
-	snd_assert(midi->dev_id, return);
+	if (snd_BUG_ON(!midi->dev_id))
+		return;
 
 	if (up) {
 		int max = 4;
diff --git a/sound/pci/cmipci.c b/sound/pci/cmipci.c
index 9971b5b..1a74ca6 100644
--- a/sound/pci/cmipci.c
+++ b/sound/pci/cmipci.c
@@ -2357,7 +2357,8 @@
 {
 	struct cmipci_switch_args *args;
 	args = (struct cmipci_switch_args *)kcontrol->private_value;
-	snd_assert(args != NULL, return -EINVAL);
+	if (snd_BUG_ON(!args))
+		return -EINVAL;
 	return _snd_cmipci_uswitch_get(kcontrol, ucontrol, args);
 }
 
@@ -2401,7 +2402,8 @@
 {
 	struct cmipci_switch_args *args;
 	args = (struct cmipci_switch_args *)kcontrol->private_value;
-	snd_assert(args != NULL, return -EINVAL);
+	if (snd_BUG_ON(!args))
+		return -EINVAL;
 	return _snd_cmipci_uswitch_put(kcontrol, ucontrol, args);
 }
 
@@ -2662,7 +2664,8 @@
 	unsigned int idx;
 	int err;
 
-	snd_assert(cm != NULL && cm->card != NULL, return -EINVAL);
+	if (snd_BUG_ON(!cm || !cm->card))
+		return -EINVAL;
 
 	card = cm->card;
 
diff --git a/sound/pci/cs4281.c b/sound/pci/cs4281.c
index 7556fd9..ef9308f 100644
--- a/sound/pci/cs4281.c
+++ b/sound/pci/cs4281.c
@@ -766,13 +766,13 @@
 	if (!capture) {
 		if (dma->left_slot == chip->src_left_play_slot) {
 			unsigned int val = snd_cs4281_rate(runtime->rate, NULL);
-			snd_assert(dma->right_slot == chip->src_right_play_slot, );
+			snd_BUG_ON(dma->right_slot != chip->src_right_play_slot);
 			snd_cs4281_pokeBA0(chip, BA0_DACSR, val);
 		}
 	} else {
 		if (dma->left_slot == chip->src_left_rec_slot) {
 			unsigned int val = snd_cs4281_rate(runtime->rate, NULL);
-			snd_assert(dma->right_slot == chip->src_right_rec_slot, );
+			snd_BUG_ON(dma->right_slot != chip->src_right_rec_slot);
 			snd_cs4281_pokeBA0(chip, BA0_ADCSR, val);
 		}
 	}
@@ -1209,7 +1209,8 @@
 {
 	struct cs4281 *chip = gameport_get_port_data(gameport);
 
-	snd_assert(chip, return);
+	if (snd_BUG_ON(!chip))
+		return;
 	snd_cs4281_pokeBA0(chip, BA0_JSPT, 0xff);
 }
 
@@ -1217,7 +1218,8 @@
 {
 	struct cs4281 *chip = gameport_get_port_data(gameport);
 
-	snd_assert(chip, return 0);
+	if (snd_BUG_ON(!chip))
+		return 0;
 	return snd_cs4281_peekBA0(chip, BA0_JSPT);
 }
 
@@ -1228,7 +1230,8 @@
 	struct cs4281 *chip = gameport_get_port_data(gameport);
 	unsigned js1, js2, jst;
 	
-	snd_assert(chip, return 0);
+	if (snd_BUG_ON(!chip))
+		return 0;
 
 	js1 = snd_cs4281_peekBA0(chip, BA0_JSC1);
 	js2 = snd_cs4281_peekBA0(chip, BA0_JSC2);
diff --git a/sound/pci/cs46xx/cs46xx_lib.c b/sound/pci/cs46xx/cs46xx_lib.c
index e214e56..fb6dc39 100644
--- a/sound/pci/cs46xx/cs46xx_lib.c
+++ b/sound/pci/cs46xx/cs46xx_lib.c
@@ -90,9 +90,10 @@
 	int count;
 	unsigned short result,tmp;
 	u32 offset = 0;
-	snd_assert ( (codec_index == CS46XX_PRIMARY_CODEC_INDEX) ||
-		     (codec_index == CS46XX_SECONDARY_CODEC_INDEX),
-		     return -EINVAL);
+
+	if (snd_BUG_ON(codec_index != CS46XX_PRIMARY_CODEC_INDEX &&
+		       codec_index != CS46XX_SECONDARY_CODEC_INDEX))
+		return -EINVAL;
 
 	chip->active_ctrl(chip, 1);
 
@@ -212,9 +213,9 @@
 	unsigned short val;
 	int codec_index = ac97->num;
 
-	snd_assert(codec_index == CS46XX_PRIMARY_CODEC_INDEX ||
-		   codec_index == CS46XX_SECONDARY_CODEC_INDEX,
-		   return 0xffff);
+	if (snd_BUG_ON(codec_index != CS46XX_PRIMARY_CODEC_INDEX &&
+		       codec_index != CS46XX_SECONDARY_CODEC_INDEX))
+		return 0xffff;
 
 	val = snd_cs46xx_codec_read(chip, reg, codec_index);
 
@@ -229,9 +230,9 @@
 {
 	int count;
 
-	snd_assert ((codec_index == CS46XX_PRIMARY_CODEC_INDEX) ||
-		    (codec_index == CS46XX_SECONDARY_CODEC_INDEX),
-		    return);
+	if (snd_BUG_ON(codec_index != CS46XX_PRIMARY_CODEC_INDEX &&
+		       codec_index != CS46XX_SECONDARY_CODEC_INDEX))
+		return;
 
 	chip->active_ctrl(chip, 1);
 
@@ -294,9 +295,9 @@
 	struct snd_cs46xx *chip = ac97->private_data;
 	int codec_index = ac97->num;
 
-	snd_assert(codec_index == CS46XX_PRIMARY_CODEC_INDEX ||
-		   codec_index == CS46XX_SECONDARY_CODEC_INDEX,
-		   return);
+	if (snd_BUG_ON(codec_index != CS46XX_PRIMARY_CODEC_INDEX &&
+		       codec_index != CS46XX_SECONDARY_CODEC_INDEX))
+		return;
 
 	snd_cs46xx_codec_write(chip, reg, val, codec_index);
 }
@@ -315,7 +316,8 @@
 	unsigned int bank = offset >> 16;
 	offset = offset & 0xffff;
 
-	snd_assert(!(offset & 3) && !(len & 3), return -EINVAL);
+	if (snd_BUG_ON((offset & 3) || (len & 3)))
+		return -EINVAL;
 	dst = chip->region.idx[bank+1].remap_addr + offset;
 	len /= sizeof(u32);
 
@@ -343,7 +345,8 @@
 	unsigned int bank = offset >> 16;
 	offset = offset & 0xffff;
 
-	snd_assert(!(offset & 3) && !(len & 3), return -EINVAL);
+	if (snd_BUG_ON((offset & 3) || (len & 3)))
+		return -EINVAL;
 	dst = chip->region.idx[bank+1].remap_addr + offset;
 	len /= sizeof(u32);
 
@@ -722,7 +725,9 @@
 	struct snd_cs46xx *chip = snd_pcm_substream_chip(substream);
 	size_t ptr;
 	struct snd_cs46xx_pcm *cpcm = substream->runtime->private_data;
-	snd_assert (cpcm->pcm_channel,return -ENXIO);
+
+	if (snd_BUG_ON(!cpcm->pcm_channel))
+		return -ENXIO;
 
 #ifdef CONFIG_SND_CS46XX_NEW_DSP
 	ptr = snd_cs46xx_peek(chip, (cpcm->pcm_channel->pcm_reader_scb->address + 2) << 2);
@@ -740,7 +745,8 @@
 	struct snd_cs46xx_pcm *cpcm = substream->runtime->private_data;
 
 #ifdef CONFIG_SND_CS46XX_NEW_DSP
-	snd_assert (cpcm->pcm_channel,return -ENXIO);
+	if (snd_BUG_ON(!cpcm->pcm_channel))
+		return -ENXIO;
 	ptr = snd_cs46xx_peek(chip, (cpcm->pcm_channel->pcm_reader_scb->address + 2) << 2);
 #else
 	ptr = snd_cs46xx_peek(chip, BA1_PBA);
@@ -908,7 +914,8 @@
 	cpcm = runtime->private_data;
 
 #ifdef CONFIG_SND_CS46XX_NEW_DSP
-	snd_assert (sample_rate != 0, return -ENXIO);
+	if (snd_BUG_ON(!sample_rate))
+		return -ENXIO;
 
 	mutex_lock(&chip->spos_mutex);
 
@@ -917,7 +924,7 @@
 		return -ENXIO;
 	}
 
-	snd_assert (cpcm->pcm_channel != NULL);
+	snd_BUG_ON(!cpcm->pcm_channel);
 	if (!cpcm->pcm_channel) {
 		mutex_unlock(&chip->spos_mutex);
 		return -ENXIO;
@@ -952,7 +959,7 @@
 		} else if (cpcm->pcm_channel_id == DSP_IEC958_CHANNEL) {
 			substream->ops = &snd_cs46xx_playback_iec958_ops;
 		} else {
-			snd_assert(0);
+			snd_BUG();
 		}
 #else
 		substream->ops = &snd_cs46xx_playback_ops;
@@ -981,7 +988,7 @@
 		} else if (cpcm->pcm_channel_id == DSP_IEC958_CHANNEL) {
 			substream->ops = &snd_cs46xx_playback_indirect_iec958_ops;
 		} else {
-			snd_assert(0);
+			snd_BUG();
 		}
 #else
 		substream->ops = &snd_cs46xx_playback_indirect_ops;
@@ -1029,7 +1036,8 @@
 	cpcm = runtime->private_data;
 
 #ifdef CONFIG_SND_CS46XX_NEW_DSP
-    snd_assert (cpcm->pcm_channel != NULL, return -ENXIO);
+	if (snd_BUG_ON(!cpcm->pcm_channel))
+		return -ENXIO;
 
 	pfie = snd_cs46xx_peek(chip, (cpcm->pcm_channel->pcm_reader_scb->address + 1) << 2 );
 	pfie &= ~0x0000f03f;
@@ -1714,9 +1722,9 @@
 {
 	struct snd_cs46xx *chip = ac97->private_data;
 
-	snd_assert ((ac97 == chip->ac97[CS46XX_PRIMARY_CODEC_INDEX]) ||
-		    (ac97 == chip->ac97[CS46XX_SECONDARY_CODEC_INDEX]),
-		    return);
+	if (snd_BUG_ON(ac97 != chip->ac97[CS46XX_PRIMARY_CODEC_INDEX] &&
+		       ac97 != chip->ac97[CS46XX_SECONDARY_CODEC_INDEX]))
+		return;
 
 	if (ac97 == chip->ac97[CS46XX_PRIMARY_CODEC_INDEX]) {
 		chip->ac97[CS46XX_PRIMARY_CODEC_INDEX] = NULL;
@@ -1864,7 +1872,7 @@
 		break;
 	default:
 		res = -EINVAL;
-		snd_assert(0, (void)0);
+		snd_BUG(); /* should never happen ... */
 	}
 
 	return res;
@@ -2236,7 +2244,7 @@
 		snd_printdd("cs46xx: CODOEC2 mode %04x\n",0x3);
 		snd_cs46xx_ac97_write(ac97,AC97_CSR_ACMODE,0x3);
 	} else {
-		snd_assert(0); /* should never happen ... */
+		snd_BUG(); /* should never happen ... */
 	}
 
 	udelay(50);
@@ -2553,7 +2561,8 @@
 {
 	struct snd_cs46xx *chip = gameport_get_port_data(gameport);
 
-	snd_assert(chip, return);
+	if (snd_BUG_ON(!chip))
+		return;
 	snd_cs46xx_pokeBA0(chip, BA0_JSPT, 0xFF);  //outb(gameport->io, 0xFF);
 }
 
@@ -2561,7 +2570,8 @@
 {
 	struct snd_cs46xx *chip = gameport_get_port_data(gameport);
 
-	snd_assert(chip, return 0);
+	if (snd_BUG_ON(!chip))
+		return 0;
 	return snd_cs46xx_peekBA0(chip, BA0_JSPT); //inb(gameport->io);
 }
 
@@ -2570,7 +2580,8 @@
 	struct snd_cs46xx *chip = gameport_get_port_data(gameport);
 	unsigned js1, js2, jst;
 
-	snd_assert(chip, return 0);
+	if (snd_BUG_ON(!chip))
+		return 0;
 
 	js1 = snd_cs46xx_peekBA0(chip, BA0_JSC1);
 	js2 = snd_cs46xx_peekBA0(chip, BA0_JSC2);
@@ -2754,7 +2765,8 @@
 {
 	int idx;
 
-	snd_assert(chip != NULL, return -EINVAL);
+	if (snd_BUG_ON(!chip))
+		return -EINVAL;
 
 	if (chip->active_ctrl)
 		chip->active_ctrl(chip, 1);
@@ -3489,8 +3501,9 @@
 		.name = "Mitac MI6020/21",
 		.amp = amp_voyetra,
 	},
+	/* Hercules Game Theatre XP */
 	{
-		.vendor = 0x14AF,
+		.vendor = 0x14af, /* Guillemot Corporation */
 		.id = 0x0050,
 		.name = "Hercules Game Theatre XP",
 		.amp = amp_hercules,
@@ -3532,9 +3545,25 @@
 		.amp = amp_hercules,
 		.mixer_init = hercules_mixer_init,
 	},
+	/* Herculess Fortissimo */
+	{
+		.vendor = 0x1681,
+		.id = 0xa010,
+		.name = "Hercules Gamesurround Fortissimo II",
+	},
+	{
+		.vendor = 0x1681,
+		.id = 0xa011,
+		.name = "Hercules Gamesurround Fortissimo III 7.1",
+	},
 	/* Teratec */
 	{
 		.vendor = 0x153b,
+		.id = 0x112e,
+		.name = "Terratec DMX XFire 1024",
+	},
+	{
+		.vendor = 0x153b,
 		.id = 0x1136,
 		.name = "Terratec SiXPack 5.1",
 	},
diff --git a/sound/pci/cs46xx/dsp_spos.c b/sound/pci/cs46xx/dsp_spos.c
index ccc8bed..f4f0c8f 100644
--- a/sound/pci/cs46xx/dsp_spos.c
+++ b/sound/pci/cs46xx/dsp_spos.c
@@ -63,7 +63,8 @@
 	u32 mop_operands,mop_type,wide_op;
 	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
 
-	snd_assert( ((size % 2) == 0), return -EINVAL);
+	if (snd_BUG_ON(size %2))
+		return -EINVAL;
   
 	while (i < size) {
 		loval = data[i++];
@@ -289,7 +290,8 @@
 	int i;
 	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
 
-	snd_assert(ins != NULL, return);
+	if (snd_BUG_ON(!ins))
+		return;
 
 	mutex_lock(&chip->spos_mutex);
 	for (i = 0; i < ins->nscb; ++i) {
@@ -404,7 +406,8 @@
 
 		/* if module has a code segment it must have
 		   symbol table */
-		snd_assert(module->symbol_table.symbols != NULL ,return -ENOMEM);
+		if (snd_BUG_ON(!module->symbol_table.symbols))
+			return -ENOMEM;
 		if (add_symbols(chip,module)) {
 			snd_printk(KERN_ERR "dsp_spos: failed to load symbol table\n");
 			return -ENOMEM;
@@ -1369,7 +1372,8 @@
 
 	valid_slots = snd_cs46xx_peekBA0(chip, BA0_ACOSV);
 
-	snd_assert (chip->nr_ac97_codecs == 1 || chip->nr_ac97_codecs == 2);
+	if (snd_BUG_ON(chip->nr_ac97_codecs != 1 && chip->nr_ac97_codecs != 2))
+		goto _fail_end;
 
 	if (chip->nr_ac97_codecs == 1) {
 		/* output on slot 5 and 11 
@@ -1609,11 +1613,14 @@
 
 		spdifo_scb_desc = cs46xx_dsp_create_scb(chip,"SPDIFOSCB",(u32 *)&spdifo_scb,SPDIFO_SCB_INST);
 
-		snd_assert(spdifo_scb_desc, return -EIO);
+		if (snd_BUG_ON(!spdifo_scb_desc))
+			return -EIO;
 		spdifi_scb_desc = cs46xx_dsp_create_scb(chip,"SPDIFISCB",(u32 *)&spdifi_scb,SPDIFI_SCB_INST);
-		snd_assert(spdifi_scb_desc, return -EIO);
+		if (snd_BUG_ON(!spdifi_scb_desc))
+			return -EIO;
 		async_codec_scb_desc = cs46xx_dsp_create_scb(chip,"AsynCodecInputSCB",(u32 *)&async_codec_input_scb, HFG_TREE_SCB);
-		snd_assert(async_codec_scb_desc, return -EIO);
+		if (snd_BUG_ON(!async_codec_scb_desc))
+			return -EIO;
 
 		async_codec_scb_desc->parent_scb_ptr = NULL;
 		async_codec_scb_desc->next_scb_ptr = spdifi_scb_desc;
@@ -1698,8 +1705,10 @@
 	chip->active_ctrl(chip, 1);
 	chip->amplifier_ctrl(chip, 1);
 
-	snd_assert (ins->asynch_rx_scb == NULL,return -EINVAL);
-	snd_assert (ins->spdif_in_src != NULL,return -EINVAL);
+	if (snd_BUG_ON(ins->asynch_rx_scb))
+		return -EINVAL;
+	if (snd_BUG_ON(!ins->spdif_in_src))
+		return -EINVAL;
 
 	mutex_lock(&chip->spos_mutex);
 
@@ -1754,8 +1763,10 @@
 {
 	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
 
-	snd_assert (ins->asynch_rx_scb != NULL, return -EINVAL);
-	snd_assert (ins->spdif_in_src != NULL,return -EINVAL);	
+	if (snd_BUG_ON(!ins->asynch_rx_scb))
+		return -EINVAL;
+	if (snd_BUG_ON(!ins->spdif_in_src))
+		return -EINVAL;
 
 	mutex_lock(&chip->spos_mutex);
 
@@ -1780,8 +1791,10 @@
 {
 	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
 
-	snd_assert (ins->pcm_input == NULL,return -EINVAL);
-	snd_assert (ins->ref_snoop_scb != NULL,return -EINVAL);
+	if (snd_BUG_ON(ins->pcm_input))
+		return -EINVAL;
+	if (snd_BUG_ON(!ins->ref_snoop_scb))
+		return -EINVAL;
 
 	mutex_lock(&chip->spos_mutex);
 	ins->pcm_input = cs46xx_add_record_source(chip,ins->ref_snoop_scb,PCMSERIALIN_PCM_SCB_ADDR,
@@ -1795,7 +1808,8 @@
 {
 	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
 
-	snd_assert (ins->pcm_input != NULL,return -EINVAL);
+	if (snd_BUG_ON(!ins->pcm_input))
+		return -EINVAL;
 
 	mutex_lock(&chip->spos_mutex);
 	cs46xx_dsp_remove_scb (chip,ins->pcm_input);
@@ -1809,8 +1823,10 @@
 {
 	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
 
-	snd_assert (ins->adc_input == NULL,return -EINVAL);
-	snd_assert (ins->codec_in_scb != NULL,return -EINVAL);
+	if (snd_BUG_ON(ins->adc_input))
+		return -EINVAL;
+	if (snd_BUG_ON(!ins->codec_in_scb))
+		return -EINVAL;
 
 	mutex_lock(&chip->spos_mutex);
 	ins->adc_input = cs46xx_add_record_source(chip,ins->codec_in_scb,PCMSERIALIN_SCB_ADDR,
@@ -1824,7 +1840,8 @@
 {
 	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
 
-	snd_assert (ins->adc_input != NULL,return -EINVAL);
+	if (snd_BUG_ON(!ins->adc_input))
+		return -EINVAL;
 
 	mutex_lock(&chip->spos_mutex);
 	cs46xx_dsp_remove_scb (chip,ins->adc_input);
diff --git a/sound/pci/cs46xx/dsp_spos_scb_lib.c b/sound/pci/cs46xx/dsp_spos_scb_lib.c
index 2873cfe..dd7c41b 100644
--- a/sound/pci/cs46xx/dsp_spos_scb_lib.c
+++ b/sound/pci/cs46xx/dsp_spos_scb_lib.c
@@ -46,8 +46,11 @@
 	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
 	int symbol_index = (int)(symbol - ins->symbol_table.symbols);
 
-	snd_assert(ins->symbol_table.nsymbols > 0,return);
-	snd_assert(symbol_index >= 0 && symbol_index < ins->symbol_table.nsymbols, return);
+	if (snd_BUG_ON(ins->symbol_table.nsymbols <= 0))
+		return;
+	if (snd_BUG_ON(symbol_index < 0 ||
+		       symbol_index >= ins->symbol_table.nsymbols))
+		return;
 
 	ins->symbol_table.symbols[symbol_index].deleted = 1;
 
@@ -116,8 +119,9 @@
 
 	if ( scb->parent_scb_ptr ) {
 		/* unlink parent SCB */
-		snd_assert ((scb->parent_scb_ptr->sub_list_ptr == scb ||
-			     scb->parent_scb_ptr->next_scb_ptr == scb),return);
+		if (snd_BUG_ON(scb->parent_scb_ptr->sub_list_ptr != scb &&
+			       scb->parent_scb_ptr->next_scb_ptr != scb))
+			return;
   
 		if (scb->parent_scb_ptr->sub_list_ptr == scb) {
 
@@ -140,7 +144,6 @@
 				scb->next_scb_ptr = ins->the_null_scb;
 			}
 		} else {
-			/* snd_assert ( (scb->sub_list_ptr == ins->the_null_scb), return); */
 			scb->parent_scb_ptr->next_scb_ptr = scb->next_scb_ptr;
 
 			if (scb->next_scb_ptr != ins->the_null_scb) {
@@ -181,16 +184,17 @@
 	unsigned long flags;
 
 	/* check integrety */
-	snd_assert ( (scb->index >= 0 && 
-		      scb->index < ins->nscb && 
-		      (ins->scbs + scb->index) == scb), return );
+	if (snd_BUG_ON(scb->index < 0 ||
+		       scb->index >= ins->nscb ||
+		       (ins->scbs + scb->index) != scb))
+		return;
 
 #if 0
 	/* can't remove a SCB with childs before 
 	   removing childs first  */
-	snd_assert ( (scb->sub_list_ptr == ins->the_null_scb &&
-		      scb->next_scb_ptr == ins->the_null_scb),
-		     goto _end);
+	if (snd_BUG_ON(scb->sub_list_ptr != ins->the_null_scb ||
+		       scb->next_scb_ptr != ins->the_null_scb))
+		goto _end;
 #endif
 
 	spin_lock_irqsave(&scb->lock, flags);
@@ -198,7 +202,8 @@
 	spin_unlock_irqrestore(&scb->lock, flags);
 
 	cs46xx_dsp_proc_free_scb_desc(scb);
-	snd_assert (scb->scb_symbol != NULL, return );
+	if (snd_BUG_ON(!scb->scb_symbol))
+		return;
 	remove_symbol (chip,scb->scb_symbol);
 
 	ins->scbs[scb->index].deleted = 1;
@@ -234,7 +239,6 @@
 		snd_info_free_entry(scb->proc_info);
 		scb->proc_info = NULL;
 
-		snd_assert (scb_info != NULL, return);
 		kfree (scb_info);
 	}
 }
@@ -291,7 +295,8 @@
   
 	unsigned long flags;
 
-	snd_assert (ins->the_null_scb != NULL,return NULL);
+	if (snd_BUG_ON(!ins->the_null_scb))
+		return NULL;
 
 	/* fill the data that will be wroten to DSP */
 	scb_data[SCBsubListPtr] = 
@@ -321,18 +326,20 @@
 #endif
 		/* link to  parent SCB */
 		if (scb_child_type == SCB_ON_PARENT_NEXT_SCB) {
-			snd_assert ( (scb->parent_scb_ptr->next_scb_ptr == ins->the_null_scb),
-				     return NULL);
+			if (snd_BUG_ON(scb->parent_scb_ptr->next_scb_ptr !=
+				       ins->the_null_scb))
+				return NULL;
 
 			scb->parent_scb_ptr->next_scb_ptr = scb;
 
 		} else if (scb_child_type == SCB_ON_PARENT_SUBLIST_SCB) {
-			snd_assert ( (scb->parent_scb_ptr->sub_list_ptr == ins->the_null_scb),
-				     return NULL);
+			if (snd_BUG_ON(scb->parent_scb_ptr->sub_list_ptr !=
+				       ins->the_null_scb))
+				return NULL;
 
 			scb->parent_scb_ptr->sub_list_ptr = scb;
 		} else {
-			snd_assert (0,return NULL);
+			snd_BUG();
 		}
 
 		spin_lock_irqsave(&chip->reg_lock, flags);
@@ -675,7 +682,7 @@
 		if (pass_through) {
 			/* wont work with any other rate than
 			   the native DSP rate */
-			snd_assert (rate == 48000);
+			snd_BUG_ON(rate != 48000);
 
 			scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&src_task_scb,
 							    dest,"DMAREADER",parent_scb,
@@ -1142,7 +1149,8 @@
 	struct dsp_scb_descriptor * scb = from;
 
 	while (scb->next_scb_ptr != ins->the_null_scb) {
-		snd_assert (scb->next_scb_ptr != NULL, return NULL);
+		if (snd_BUG_ON(!scb->next_scb_ptr))
+			return NULL;
 
 		scb = scb->next_scb_ptr;
 	}
@@ -1246,10 +1254,11 @@
 		break;
 	case DSP_PCM_S71_CHANNEL:
 		/* TODO */
-		snd_assert(0);
+		snd_BUG();
 		break;
 	case DSP_IEC958_CHANNEL:
-		snd_assert (ins->asynch_tx_scb != NULL, return NULL);
+		if (snd_BUG_ON(!ins->asynch_tx_scb))
+			return NULL;
 		mixer_scb = ins->asynch_tx_scb;
 
 		/* if sample rate is set to 48khz we pass
@@ -1262,7 +1271,7 @@
 		}
 		break;
 	default:
-		snd_assert (0);
+		snd_BUG();
 		return NULL;
 	}
 	/* default sample rate is 44100 */
@@ -1308,7 +1317,8 @@
 				break;
 			}
 		}
-		snd_assert (src_index != -1,return NULL);
+		if (snd_BUG_ON(src_index == -1))
+			return NULL;
 
 		/* we need to create a new SRC SCB */
 		if (mixer_scb->sub_list_ptr == ins->the_null_scb) {
@@ -1462,9 +1472,10 @@
 	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
 	unsigned long flags;
 
-	snd_assert(pcm_channel->active, return );
-	snd_assert(ins->npcm_channels > 0, return );
-	snd_assert(pcm_channel->src_scb->ref_count > 0, return );
+	if (snd_BUG_ON(!pcm_channel->active ||
+		       ins->npcm_channels <= 0 ||
+		       pcm_channel->src_scb->ref_count <= 0))
+		return;
 
 	spin_lock_irqsave(&chip->reg_lock, flags);
 	pcm_channel->unlinked = 1;
@@ -1479,8 +1490,9 @@
 	if (!pcm_channel->src_scb->ref_count) {
 		cs46xx_dsp_remove_scb(chip,pcm_channel->src_scb);
 
-		snd_assert (pcm_channel->src_slot >= 0 && pcm_channel->src_slot < DSP_MAX_SRC_NR,
-			    return );
+		if (snd_BUG_ON(pcm_channel->src_slot < 0 ||
+			       pcm_channel->src_slot >= DSP_MAX_SRC_NR))
+			return;
 
 		ins->src_scb_slots[pcm_channel->src_slot] = 0;
 		ins->nsrc_scb --;
@@ -1490,11 +1502,11 @@
 int cs46xx_dsp_pcm_unlink (struct snd_cs46xx * chip,
 			   struct dsp_pcm_channel_descriptor * pcm_channel)
 {
-	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
 	unsigned long flags;
 
-	snd_assert(pcm_channel->active,return -EIO);
-	snd_assert(ins->npcm_channels > 0,return -EIO);
+	if (snd_BUG_ON(!pcm_channel->active ||
+		       chip->dsp_spos_instance->npcm_channels <= 0))
+		return -EIO;
 
 	spin_lock(&pcm_channel->src_scb->lock);
 
@@ -1537,7 +1549,7 @@
 
 	src_scb->sub_list_ptr = pcm_channel->pcm_reader_scb;
 
-	snd_assert (pcm_channel->pcm_reader_scb->parent_scb_ptr == NULL, ; );
+	snd_BUG_ON(pcm_channel->pcm_reader_scb->parent_scb_ptr);
 	pcm_channel->pcm_reader_scb->parent_scb_ptr = parent_scb;
 
 	spin_lock_irqsave(&chip->reg_lock, flags);
@@ -1564,7 +1576,8 @@
 	struct dsp_scb_descriptor * pcm_input;
 	int insert_point;
 
-	snd_assert (ins->record_mixer_scb != NULL,return NULL);
+	if (snd_BUG_ON(!ins->record_mixer_scb))
+		return NULL;
 
 	if (ins->record_mixer_scb->sub_list_ptr != ins->the_null_scb) {
 		parent = find_next_free_scb (chip,ins->record_mixer_scb->sub_list_ptr);
@@ -1583,7 +1596,8 @@
 
 int cs46xx_src_unlink(struct snd_cs46xx *chip, struct dsp_scb_descriptor * src)
 {
-	snd_assert (src->parent_scb_ptr != NULL,  return -EINVAL );
+	if (snd_BUG_ON(!src->parent_scb_ptr))
+		return -EINVAL;
 
 	/* mute SCB */
 	cs46xx_dsp_scb_set_volume (chip,src,0,0);
@@ -1598,8 +1612,10 @@
 	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
 	struct dsp_scb_descriptor * parent_scb;
 
-	snd_assert (src->parent_scb_ptr == NULL,   return -EINVAL );
-	snd_assert(ins->master_mix_scb !=NULL,   return -EINVAL );
+	if (snd_BUG_ON(src->parent_scb_ptr))
+		return -EINVAL;
+	if (snd_BUG_ON(!ins->master_mix_scb))
+		return -EINVAL;
 
 	if (ins->master_mix_scb->sub_list_ptr != ins->the_null_scb) {
 		parent_scb = find_next_free_scb (chip,ins->master_mix_scb->sub_list_ptr);
@@ -1635,8 +1651,11 @@
 		return -EBUSY;
 	}
 
-	snd_assert (ins->asynch_tx_scb == NULL, return -EINVAL);
-	snd_assert (ins->master_mix_scb->next_scb_ptr == ins->the_null_scb, return -EINVAL);
+	if (snd_BUG_ON(ins->asynch_tx_scb))
+		return -EINVAL;
+	if (snd_BUG_ON(ins->master_mix_scb->next_scb_ptr !=
+		       ins->the_null_scb))
+		return -EINVAL;
 
 	/* reset output snooper sample buffer pointer */
 	snd_cs46xx_poke (chip, (ins->ref_snoop_scb->address + 2) << 2,
@@ -1676,10 +1695,15 @@
 	}
 
 	/* check integrety */
-	snd_assert (ins->asynch_tx_scb != NULL, return -EINVAL);
-	snd_assert (ins->spdif_pcm_input_scb != NULL,return -EINVAL);
-	snd_assert (ins->master_mix_scb->next_scb_ptr == ins->asynch_tx_scb, return -EINVAL);
-	snd_assert (ins->asynch_tx_scb->parent_scb_ptr == ins->master_mix_scb, return -EINVAL);
+	if (snd_BUG_ON(!ins->asynch_tx_scb))
+		return -EINVAL;
+	if (snd_BUG_ON(!ins->spdif_pcm_input_scb))
+		return -EINVAL;
+	if (snd_BUG_ON(ins->master_mix_scb->next_scb_ptr != ins->asynch_tx_scb))
+		return -EINVAL;
+	if (snd_BUG_ON(ins->asynch_tx_scb->parent_scb_ptr !=
+		       ins->master_mix_scb))
+		return -EINVAL;
 
 	cs46xx_dsp_remove_scb (chip,ins->spdif_pcm_input_scb);
 	cs46xx_dsp_remove_scb (chip,ins->asynch_tx_scb);
@@ -1734,7 +1758,8 @@
 {
 	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
 
-	snd_assert (ins->asynch_tx_scb != NULL, return -EINVAL);
+	if (snd_BUG_ON(!ins->asynch_tx_scb))
+		return -EINVAL;
 
 	ins->spdif_status_out  &= ~DSP_SPDIF_STATUS_PLAYBACK_OPEN;
 
diff --git a/sound/pci/echoaudio/darla20_dsp.c b/sound/pci/echoaudio/darla20_dsp.c
index 4159e3b..2904330 100644
--- a/sound/pci/echoaudio/darla20_dsp.c
+++ b/sound/pci/echoaudio/darla20_dsp.c
@@ -34,7 +34,8 @@
 	int err;
 
 	DE_INIT(("init_hw() - Darla20\n"));
-	snd_assert((subdevice_id & 0xfff0) == DARLA20, return -ENODEV);
+	if (snd_BUG_ON((subdevice_id & 0xfff0) != DARLA20))
+		return -ENODEV;
 
 	if ((err = init_dsp_comm_page(chip))) {
 		DE_INIT(("init_hw - could not initialize DSP comm page\n"));
diff --git a/sound/pci/echoaudio/darla24_dsp.c b/sound/pci/echoaudio/darla24_dsp.c
index 79938ee..6022873 100644
--- a/sound/pci/echoaudio/darla24_dsp.c
+++ b/sound/pci/echoaudio/darla24_dsp.c
@@ -34,7 +34,8 @@
 	int err;
 
 	DE_INIT(("init_hw() - Darla24\n"));
-	snd_assert((subdevice_id & 0xfff0) == DARLA24, return -ENODEV);
+	if (snd_BUG_ON((subdevice_id & 0xfff0) != DARLA24))
+		return -ENODEV;
 
 	if ((err = init_dsp_comm_page(chip))) {
 		DE_INIT(("init_hw - could not initialize DSP comm page\n"));
@@ -148,8 +149,9 @@
 
 static int set_input_clock(struct echoaudio *chip, u16 clock)
 {
-	snd_assert(clock == ECHO_CLOCK_INTERNAL ||
-		   clock == ECHO_CLOCK_ESYNC, return -EINVAL);
+	if (snd_BUG_ON(clock != ECHO_CLOCK_INTERNAL &&
+		       clock != ECHO_CLOCK_ESYNC))
+		return -EINVAL;
 	chip->input_clock = clock;
 	return set_sample_rate(chip, chip->sample_rate);
 }
diff --git a/sound/pci/echoaudio/echo3g_dsp.c b/sound/pci/echoaudio/echo3g_dsp.c
index 48eb7c5..417e25a 100644
--- a/sound/pci/echoaudio/echo3g_dsp.c
+++ b/sound/pci/echoaudio/echo3g_dsp.c
@@ -47,7 +47,8 @@
 
 	local_irq_enable();
 	DE_INIT(("init_hw() - Echo3G\n"));
-	snd_assert((subdevice_id & 0xfff0) == ECHO3G, return -ENODEV);
+	if (snd_BUG_ON((subdevice_id & 0xfff0) != ECHO3G))
+		return -ENODEV;
 
 	if ((err = init_dsp_comm_page(chip))) {
 		DE_INIT(("init_hw - could not initialize DSP comm page\n"));
@@ -104,9 +105,11 @@
 	if ((err = init_line_levels(chip)) < 0)
 		return err;
 	err = set_digital_mode(chip, DIGITAL_MODE_SPDIF_RCA);
-	snd_assert(err >= 0, return err);
+	if (err < 0)
+		return err;
 	err = set_phantom_power(chip, 0);
-	snd_assert(err >= 0, return err);
+	if (err < 0)
+		return err;
 	err = set_professional_spdif(chip, TRUE);
 
 	DE_INIT(("init_hw done\n"));
diff --git a/sound/pci/echoaudio/echoaudio.c b/sound/pci/echoaudio/echoaudio.c
index e16dc92..8dbc5c4 100644
--- a/sound/pci/echoaudio/echoaudio.c
+++ b/sound/pci/echoaudio/echoaudio.c
@@ -490,7 +490,6 @@
 {
 	struct echoaudio *chip;
 	int err, per, rest, page, edge, offs;
-	struct snd_sg_buf *sgbuf;
 	struct audiopipe *pipe;
 
 	chip = snd_pcm_substream_chip(substream);
@@ -503,7 +502,7 @@
 	if (pipe->index >= 0) {
 		DE_HWP(("hwp_ie free(%d)\n", pipe->index));
 		err = free_pipes(chip, pipe);
-		snd_assert(!err);
+		snd_BUG_ON(err);
 		chip->substream[pipe->index] = NULL;
 	}
 
@@ -531,10 +530,6 @@
 		return err;
 	}
 
-	sgbuf = snd_pcm_substream_sgbuf(substream);
-
-	DE_HWP(("pcm_hw_params table size=%d pages=%d\n",
-		sgbuf->size, sgbuf->pages));
 	sglist_init(chip, pipe);
 	edge = PAGE_SIZE;
 	for (offs = page = per = 0; offs < params_buffer_bytes(hw_params);
@@ -543,16 +538,15 @@
 		if (offs + rest > params_buffer_bytes(hw_params))
 			rest = params_buffer_bytes(hw_params) - offs;
 		while (rest) {
+			dma_addr_t addr;
+			addr = snd_pcm_sgbuf_get_addr(substream, offs);
 			if (rest <= edge - offs) {
-				sglist_add_mapping(chip, pipe,
-						   snd_sgbuf_get_addr(sgbuf, offs),
-						   rest);
+				sglist_add_mapping(chip, pipe, addr, rest);
 				sglist_add_irq(chip, pipe);
 				offs += rest;
 				rest = 0;
 			} else {
-				sglist_add_mapping(chip, pipe,
-						   snd_sgbuf_get_addr(sgbuf, offs),
+				sglist_add_mapping(chip, pipe, addr,
 						   edge - offs);
 				rest -= edge - offs;
 				offs = edge;
@@ -690,8 +684,10 @@
 		return -EINVAL;
 	}
 
-	snd_assert(pipe_index < px_num(chip), return -EINVAL);
-	snd_assert(is_pipe_allocated(chip, pipe_index), return -EINVAL);
+	if (snd_BUG_ON(pipe_index >= px_num(chip)))
+		return -EINVAL;
+	if (snd_BUG_ON(!is_pipe_allocated(chip, pipe_index)))
+		return -EINVAL;
 	set_audio_format(chip, pipe_index, &format);
 	return 0;
 }
diff --git a/sound/pci/echoaudio/echoaudio_3g.c b/sound/pci/echoaudio/echoaudio_3g.c
index 52a9331..c3736bb 100644
--- a/sound/pci/echoaudio/echoaudio_3g.c
+++ b/sound/pci/echoaudio/echoaudio_3g.c
@@ -103,9 +103,11 @@
 	int err, i, o;
 
 	/* All audio channels must be closed before changing the digital mode */
-	snd_assert(!chip->pipe_alloc_mask, return -EAGAIN);
+	if (snd_BUG_ON(chip->pipe_alloc_mask))
+		return -EAGAIN;
 
-	snd_assert(chip->digital_modes & (1 << mode), return -EINVAL);
+	if (snd_BUG_ON(!(chip->digital_modes & (1 << mode))))
+		return -EINVAL;
 
 	previous_mode = chip->digital_mode;
 	err = dsp_set_digital_mode(chip, mode);
@@ -267,8 +269,9 @@
 		return 0;
 	}
 
-	snd_assert(rate < 50000 || chip->digital_mode != DIGITAL_MODE_ADAT,
-		   return -EINVAL);
+	if (snd_BUG_ON(rate >= 50000 &&
+		       chip->digital_mode == DIGITAL_MODE_ADAT))
+		return -EINVAL;
 
 	clock = 0;
 	control_reg = le32_to_cpu(chip->comm_page->control_register);
diff --git a/sound/pci/echoaudio/echoaudio_dsp.c b/sound/pci/echoaudio/echoaudio_dsp.c
index e6c1007..be0e181 100644
--- a/sound/pci/echoaudio/echoaudio_dsp.c
+++ b/sound/pci/echoaudio/echoaudio_dsp.c
@@ -474,7 +474,8 @@
 	const struct firmware *fw;
 	int box_type, err;
 
-	snd_assert(chip->dsp_code_to_load && chip->comm_page, return -EPERM);
+	if (snd_BUG_ON(!chip->dsp_code_to_load || !chip->comm_page))
+		return -EPERM;
 
 	/* See if the ASIC is present and working - only if the DSP is already loaded */
 	if (chip->dsp_code) {
@@ -512,8 +513,8 @@
 /* Set the nominal level for an input or output bus (true = -10dBV, false = +4dBu) */
 static int set_nominal_level(struct echoaudio *chip, u16 index, char consumer)
 {
-	snd_assert(index < num_busses_out(chip) + num_busses_in(chip),
-		   return -EINVAL);
+	if (snd_BUG_ON(index >= num_busses_out(chip) + num_busses_in(chip)))
+		return -EINVAL;
 
 	/* Wait for the handshake (OK even if ASIC is not loaded) */
 	if (wait_handshake(chip))
@@ -536,7 +537,8 @@
 /* Set the gain for a single physical output channel (dB). */
 static int set_output_gain(struct echoaudio *chip, u16 channel, s8 gain)
 {
-	snd_assert(channel < num_busses_out(chip), return -EINVAL);
+	if (snd_BUG_ON(channel >= num_busses_out(chip)))
+		return -EINVAL;
 
 	if (wait_handshake(chip))
 		return -EIO;
@@ -554,8 +556,9 @@
 static int set_monitor_gain(struct echoaudio *chip, u16 output, u16 input,
 			    s8 gain)
 {
-	snd_assert(output < num_busses_out(chip) &&
-		   input < num_busses_in(chip), return -EINVAL);
+	if (snd_BUG_ON(output >= num_busses_out(chip) ||
+		    input >= num_busses_in(chip)))
+		return -EINVAL;
 
 	if (wait_handshake(chip))
 		return -EIO;
@@ -1065,8 +1068,10 @@
 	int i;
 
 	DE_ACT(("free_pipes: Pipe %d\n", pipe->index));
-	snd_assert(is_pipe_allocated(chip, pipe->index), return -EINVAL);
-	snd_assert(pipe->state == PIPE_STATE_STOPPED, return -EINVAL);
+	if (snd_BUG_ON(!is_pipe_allocated(chip, pipe->index)))
+		return -EINVAL;
+	if (snd_BUG_ON(pipe->state != PIPE_STATE_STOPPED))
+		return -EINVAL;
 
 	for (channel_mask = i = 0; i < pipe->interleave; i++)
 		channel_mask |= 1 << (pipe->index + i);
diff --git a/sound/pci/echoaudio/echoaudio_gml.c b/sound/pci/echoaudio/echoaudio_gml.c
index 3aa37e7..afa2733 100644
--- a/sound/pci/echoaudio/echoaudio_gml.c
+++ b/sound/pci/echoaudio/echoaudio_gml.c
@@ -112,9 +112,11 @@
 		return -EIO;
 
 	/* All audio channels must be closed before changing the digital mode */
-	snd_assert(!chip->pipe_alloc_mask, return -EAGAIN);
+	if (snd_BUG_ON(chip->pipe_alloc_mask))
+		return -EAGAIN;
 
-	snd_assert(chip->digital_modes & (1 << mode), return -EINVAL);
+	if (snd_BUG_ON(!(chip->digital_modes & (1 << mode))))
+		return -EINVAL;
 
 	previous_mode = chip->digital_mode;
 	err = dsp_set_digital_mode(chip, mode);
diff --git a/sound/pci/echoaudio/gina20_dsp.c b/sound/pci/echoaudio/gina20_dsp.c
index 2757c89..db6c952 100644
--- a/sound/pci/echoaudio/gina20_dsp.c
+++ b/sound/pci/echoaudio/gina20_dsp.c
@@ -38,7 +38,8 @@
 	int err;
 
 	DE_INIT(("init_hw() - Gina20\n"));
-	snd_assert((subdevice_id & 0xfff0) == GINA20, return -ENODEV);
+	if (snd_BUG_ON((subdevice_id & 0xfff0) != GINA20))
+		return -ENODEV;
 
 	if ((err = init_dsp_comm_page(chip))) {
 		DE_INIT(("init_hw - could not initialize DSP comm page\n"));
@@ -177,7 +178,8 @@
 /* Set input bus gain (one unit is 0.5dB !) */
 static int set_input_gain(struct echoaudio *chip, u16 input, int gain)
 {
-	snd_assert(input < num_busses_in(chip), return -EINVAL);
+	if (snd_BUG_ON(input >= num_busses_in(chip)))
+		return -EINVAL;
 
 	if (wait_handshake(chip))
 		return -EIO;
diff --git a/sound/pci/echoaudio/gina24_dsp.c b/sound/pci/echoaudio/gina24_dsp.c
index 144fc56..2fef37a 100644
--- a/sound/pci/echoaudio/gina24_dsp.c
+++ b/sound/pci/echoaudio/gina24_dsp.c
@@ -43,7 +43,8 @@
 	int err;
 
 	DE_INIT(("init_hw() - Gina24\n"));
-	snd_assert((subdevice_id & 0xfff0) == GINA24, return -ENODEV);
+	if (snd_BUG_ON((subdevice_id & 0xfff0) != GINA24))
+		return -ENODEV;
 
 	if ((err = init_dsp_comm_page(chip))) {
 		DE_INIT(("init_hw - could not initialize DSP comm page\n"));
@@ -84,7 +85,8 @@
 	if ((err = init_line_levels(chip)) < 0)
 		return err;
 	err = set_digital_mode(chip, DIGITAL_MODE_SPDIF_RCA);
-	snd_assert(err >= 0, return err);
+	if (err < 0)
+		return err;
 	err = set_professional_spdif(chip, TRUE);
 
 	DE_INIT(("init_hw done\n"));
@@ -163,8 +165,9 @@
 {
 	u32 control_reg, clock;
 
-	snd_assert(rate < 50000 || chip->digital_mode != DIGITAL_MODE_ADAT,
-		   return -EINVAL);
+	if (snd_BUG_ON(rate >= 50000 &&
+		       chip->digital_mode == DIGITAL_MODE_ADAT))
+		return -EINVAL;
 
 	/* Only set the clock for internal mode. */
 	if (chip->input_clock != ECHO_CLOCK_INTERNAL) {
diff --git a/sound/pci/echoaudio/indigo_dsp.c b/sound/pci/echoaudio/indigo_dsp.c
index d6ac773..f05e39f 100644
--- a/sound/pci/echoaudio/indigo_dsp.c
+++ b/sound/pci/echoaudio/indigo_dsp.c
@@ -39,7 +39,8 @@
 	int err;
 
 	DE_INIT(("init_hw() - Indigo\n"));
-	snd_assert((subdevice_id & 0xfff0) == INDIGO, return -ENODEV);
+	if (snd_BUG_ON((subdevice_id & 0xfff0) != INDIGO))
+		return -ENODEV;
 
 	if ((err = init_dsp_comm_page(chip))) {
 		DE_INIT(("init_hw - could not initialize DSP comm page\n"));
@@ -143,8 +144,9 @@
 {
 	int index;
 
-	snd_assert(pipe < num_pipes_out(chip) &&
-		   output < num_busses_out(chip), return -EINVAL);
+	if (snd_BUG_ON(pipe >= num_pipes_out(chip) ||
+		       output >= num_busses_out(chip)))
+		return -EINVAL;
 
 	if (wait_handshake(chip))
 		return -EIO;
diff --git a/sound/pci/echoaudio/indigodj_dsp.c b/sound/pci/echoaudio/indigodj_dsp.c
index 500e150..90730a5 100644
--- a/sound/pci/echoaudio/indigodj_dsp.c
+++ b/sound/pci/echoaudio/indigodj_dsp.c
@@ -39,7 +39,8 @@
 	int err;
 
 	DE_INIT(("init_hw() - Indigo DJ\n"));
-	snd_assert((subdevice_id & 0xfff0) == INDIGO_DJ, return -ENODEV);
+	if (snd_BUG_ON((subdevice_id & 0xfff0) != INDIGO_DJ))
+		return -ENODEV;
 
 	if ((err = init_dsp_comm_page(chip))) {
 		DE_INIT(("init_hw - could not initialize DSP comm page\n"));
@@ -143,8 +144,9 @@
 {
 	int index;
 
-	snd_assert(pipe < num_pipes_out(chip) &&
-		   output < num_busses_out(chip), return -EINVAL);
+	if (snd_BUG_ON(pipe >= num_pipes_out(chip) ||
+		       output >= num_busses_out(chip)))
+		return -EINVAL;
 
 	if (wait_handshake(chip))
 		return -EIO;
diff --git a/sound/pci/echoaudio/indigoio_dsp.c b/sound/pci/echoaudio/indigoio_dsp.c
index f3ad13d..a7e09ec 100644
--- a/sound/pci/echoaudio/indigoio_dsp.c
+++ b/sound/pci/echoaudio/indigoio_dsp.c
@@ -39,7 +39,8 @@
 	int err;
 
 	DE_INIT(("init_hw() - Indigo IO\n"));
-	snd_assert((subdevice_id & 0xfff0) == INDIGO_IO, return -ENODEV);
+	if (snd_BUG_ON((subdevice_id & 0xfff0) != INDIGO_IO))
+		return -ENODEV;
 
 	if ((err = init_dsp_comm_page(chip))) {
 		DE_INIT(("init_hw - could not initialize DSP comm page\n"));
@@ -114,8 +115,9 @@
 {
 	int index;
 
-	snd_assert(pipe < num_pipes_out(chip) &&
-		   output < num_busses_out(chip), return -EINVAL);
+	if (snd_BUG_ON(pipe >= num_pipes_out(chip) ||
+		       output >= num_busses_out(chip)))
+		return -EINVAL;
 
 	if (wait_handshake(chip))
 		return -EIO;
diff --git a/sound/pci/echoaudio/layla20_dsp.c b/sound/pci/echoaudio/layla20_dsp.c
index 990c9a6..ede75c6 100644
--- a/sound/pci/echoaudio/layla20_dsp.c
+++ b/sound/pci/echoaudio/layla20_dsp.c
@@ -42,7 +42,8 @@
 	int err;
 
 	DE_INIT(("init_hw() - Layla20\n"));
-	snd_assert((subdevice_id & 0xfff0) == LAYLA20, return -ENODEV);
+	if (snd_BUG_ON((subdevice_id & 0xfff0) != LAYLA20))
+		return -ENODEV;
 
 	if ((err = init_dsp_comm_page(chip))) {
 		DE_INIT(("init_hw - could not initialize DSP comm page\n"));
@@ -155,7 +156,8 @@
 
 static int set_sample_rate(struct echoaudio *chip, u32 rate)
 {
-	snd_assert(rate >= 8000 && rate <= 50000, return -EINVAL);
+	if (snd_BUG_ON(rate < 8000 || rate > 50000))
+		return -EINVAL;
 
 	/* Only set the clock for internal mode. Do not return failure,
 	   simply treat it as a non-event. */
@@ -252,7 +254,8 @@
 /* Set input bus gain (one unit is 0.5dB !) */
 static int set_input_gain(struct echoaudio *chip, u16 input, int gain)
 {
-	snd_assert(input < num_busses_in(chip), return -EINVAL);
+	if (snd_BUG_ON(input >= num_busses_in(chip)))
+		return -EINVAL;
 
 	if (wait_handshake(chip))
 		return -EIO;
diff --git a/sound/pci/echoaudio/layla24_dsp.c b/sound/pci/echoaudio/layla24_dsp.c
index 97e42e1..d61b5cb 100644
--- a/sound/pci/echoaudio/layla24_dsp.c
+++ b/sound/pci/echoaudio/layla24_dsp.c
@@ -42,7 +42,8 @@
 	int err;
 
 	DE_INIT(("init_hw() - Layla24\n"));
-	snd_assert((subdevice_id & 0xfff0) == LAYLA24, return -ENODEV);
+	if (snd_BUG_ON((subdevice_id & 0xfff0) != LAYLA24))
+		return -ENODEV;
 
 	if ((err = init_dsp_comm_page(chip))) {
 		DE_INIT(("init_hw - could not initialize DSP comm page\n"));
@@ -73,7 +74,8 @@
 		return err;
 
 	err = set_digital_mode(chip, DIGITAL_MODE_SPDIF_RCA);
-	snd_assert(err >= 0, return err);
+	if (err < 0)
+		return err;
 	err = set_professional_spdif(chip, TRUE);
 
 	DE_INIT(("init_hw done\n"));
@@ -158,8 +160,9 @@
 {
 	u32 control_reg, clock, base_rate;
 
-	snd_assert(rate < 50000 || chip->digital_mode != DIGITAL_MODE_ADAT,
-		   return -EINVAL);
+	if (snd_BUG_ON(rate >= 50000 &&
+		       chip->digital_mode == DIGITAL_MODE_ADAT))
+		return -EINVAL;
 
 	/* Only set the clock for internal mode. */
 	if (chip->input_clock != ECHO_CLOCK_INTERNAL) {
diff --git a/sound/pci/echoaudio/mia_dsp.c b/sound/pci/echoaudio/mia_dsp.c
index 891c705..2273866 100644
--- a/sound/pci/echoaudio/mia_dsp.c
+++ b/sound/pci/echoaudio/mia_dsp.c
@@ -42,7 +42,8 @@
 	int err;
 
 	DE_INIT(("init_hw() - Mia\n"));
-	snd_assert((subdevice_id & 0xfff0) == MIA, return -ENODEV);
+	if (snd_BUG_ON((subdevice_id & 0xfff0) != MIA))
+		return -ENODEV;
 
 	if ((err = init_dsp_comm_page(chip))) {
 		DE_INIT(("init_hw - could not initialize DSP comm page\n"));
@@ -161,8 +162,9 @@
 static int set_input_clock(struct echoaudio *chip, u16 clock)
 {
 	DE_ACT(("set_input_clock(%d)\n", clock));
-	snd_assert(clock == ECHO_CLOCK_INTERNAL || clock == ECHO_CLOCK_SPDIF,
-		   return -EINVAL);
+	if (snd_BUG_ON(clock != ECHO_CLOCK_INTERNAL &&
+		       clock != ECHO_CLOCK_SPDIF))
+		return -EINVAL;
 
 	chip->input_clock = clock;
 	return set_sample_rate(chip, chip->sample_rate);
@@ -176,8 +178,9 @@
 {
 	int index;
 
-	snd_assert(pipe < num_pipes_out(chip) &&
-		   output < num_busses_out(chip), return -EINVAL);
+	if (snd_BUG_ON(pipe >= num_pipes_out(chip) ||
+		       output >= num_busses_out(chip)))
+		return -EINVAL;
 
 	if (wait_handshake(chip))
 		return -EIO;
diff --git a/sound/pci/echoaudio/midi.c b/sound/pci/echoaudio/midi.c
index 91f5bff..77bf2a8 100644
--- a/sound/pci/echoaudio/midi.c
+++ b/sound/pci/echoaudio/midi.c
@@ -59,7 +59,8 @@
 Returns how many actually written or < 0 on error */
 static int write_midi(struct echoaudio *chip, u8 *data, int bytes)
 {
-	snd_assert(bytes > 0 && bytes < MIDI_OUT_BUFFER_SIZE, return -EINVAL);
+	if (snd_BUG_ON(bytes <= 0 || bytes >= MIDI_OUT_BUFFER_SIZE))
+		return -EINVAL;
 
 	if (wait_handshake(chip))
 		return -EIO;
@@ -119,7 +120,8 @@
 	/* The count is at index 0, followed by actual data */
 	count = le16_to_cpu(chip->comm_page->midi_input[0]);
 
-	snd_assert(count < MIDI_IN_BUFFER_SIZE, return 0);
+	if (snd_BUG_ON(count >= MIDI_IN_BUFFER_SIZE))
+		return 0;
 
 	/* Get the MIDI data from the comm page */
 	i = 1;
diff --git a/sound/pci/echoaudio/mona_dsp.c b/sound/pci/echoaudio/mona_dsp.c
index c0b4bf0..eaa619b 100644
--- a/sound/pci/echoaudio/mona_dsp.c
+++ b/sound/pci/echoaudio/mona_dsp.c
@@ -43,7 +43,8 @@
 	int err;
 
 	DE_INIT(("init_hw() - Mona\n"));
-	snd_assert((subdevice_id & 0xfff0) == MONA, return -ENODEV);
+	if (snd_BUG_ON((subdevice_id & 0xfff0) != MONA))
+		return -ENODEV;
 
 	if ((err = init_dsp_comm_page(chip))) {
 		DE_INIT(("init_hw - could not initialize DSP comm page\n"));
@@ -79,7 +80,8 @@
 		return err;
 
 	err = set_digital_mode(chip, DIGITAL_MODE_SPDIF_RCA);
-	snd_assert(err >= 0, return err);
+	if (err < 0)
+		return err;
 	err = set_professional_spdif(chip, TRUE);
 
 	DE_INIT(("init_hw done\n"));
diff --git a/sound/pci/emu10k1/emu10k1_callback.c b/sound/pci/emu10k1/emu10k1_callback.c
index 45088eb..0e649dc 100644
--- a/sound/pci/emu10k1/emu10k1_callback.c
+++ b/sound/pci/emu10k1/emu10k1_callback.c
@@ -145,7 +145,8 @@
 {
 	struct snd_emu10k1 *hw;
 	
-	snd_assert(vp, return);
+	if (snd_BUG_ON(!vp))
+		return;
 	hw = vp->hw;
 	snd_emu10k1_ptr_write(hw, DCYSUSV, vp->ch, 0x807f | DCYSUSV_CHANNELENABLE_MASK);
 	if (vp->block) {
@@ -325,7 +326,8 @@
 	
 	hw = vp->hw;
 	ch = vp->ch;
-	snd_assert(ch >= 0, return -EINVAL);
+	if (snd_BUG_ON(ch < 0))
+		return -EINVAL;
 	chan = vp->chan;
 
 	emem = (struct snd_emu10k1_memblk *)vp->block;
diff --git a/sound/pci/emu10k1/emu10k1_patch.c b/sound/pci/emu10k1/emu10k1_patch.c
index 42bae6f..e10f027 100644
--- a/sound/pci/emu10k1/emu10k1_patch.c
+++ b/sound/pci/emu10k1/emu10k1_patch.c
@@ -46,8 +46,8 @@
 	struct snd_emu10k1 *emu;
 
 	emu = rec->hw;
-	snd_assert(sp != NULL, return -EINVAL);
-	snd_assert(hdr != NULL, return -EINVAL);
+	if (snd_BUG_ON(!sp || !hdr))
+		return -EINVAL;
 
 	if (sp->v.size == 0) {
 		snd_printd("emu: rom font for sample %d\n", sp->v.sample);
@@ -104,7 +104,8 @@
 	size = BLANK_HEAD_SIZE;
 	if (! (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_8BITS))
 		size *= 2;
-	snd_assert(offset + size <= blocksize, return -EINVAL);
+	if (offset + size > blocksize)
+		return -EINVAL;
 	snd_emu10k1_synth_bzero(emu, sp->block, offset, size);
 	offset += size;
 
@@ -112,7 +113,8 @@
 	size = loopend;
 	if (! (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_8BITS))
 		size *= 2;
-	snd_assert(offset + size <= blocksize, return -EINVAL);
+	if (offset + size > blocksize)
+		return -EINVAL;
 	if (snd_emu10k1_synth_copy_from_user(emu, sp->block, offset, data, size)) {
 		snd_emu10k1_synth_free(emu, sp->block);
 		sp->block = NULL;
@@ -129,12 +131,14 @@
 			int woffset;
 			unsigned short *wblock = (unsigned short*)block;
 			woffset = offset / 2;
-			snd_assert(offset + loopsize*2 <= blocksize, return -EINVAL);
+			if (offset + loopsize * 2 > blocksize)
+				return -EINVAL;
 			for (i = 0; i < loopsize; i++)
 				wblock[woffset + i] = wblock[woffset - i -1];
 			offset += loopsize * 2;
 		} else {
-			snd_assert(offset + loopsize <= blocksize, return -EINVAL);
+			if (offset + loopsize > blocksize)
+				return -EINVAL;
 			for (i = 0; i < loopsize; i++)
 				block[offset + i] = block[offset - i -1];
 			offset += loopsize;
@@ -154,7 +158,8 @@
 
 	/* loopend -> sample end */
 	size = sp->v.size - loopend;
-	snd_assert(size >= 0, return -EINVAL);
+	if (size < 0)
+		return -EINVAL;
 	if (! (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_8BITS))
 		size *= 2;
 	if (snd_emu10k1_synth_copy_from_user(emu, sp->block, offset, data, size)) {
@@ -212,8 +217,8 @@
 	struct snd_emu10k1 *emu;
 
 	emu = rec->hw;
-	snd_assert(sp != NULL, return -EINVAL);
-	snd_assert(hdr != NULL, return -EINVAL);
+	if (snd_BUG_ON(!sp || !hdr))
+		return -EINVAL;
 
 	if (sp->block) {
 		snd_emu10k1_synth_free(emu, sp->block);
diff --git a/sound/pci/emu10k1/emu10k1x.c b/sound/pci/emu10k1/emu10k1x.c
index 491a4a5..5ff4dbb 100644
--- a/sound/pci/emu10k1/emu10k1x.c
+++ b/sound/pci/emu10k1/emu10k1x.c
@@ -1319,7 +1319,8 @@
 	unsigned long flags;
 	
 	emu = midi->emu;
-	snd_assert(emu, return -ENXIO);
+	if (snd_BUG_ON(!emu))
+		return -ENXIO;
 	spin_lock_irqsave(&midi->open_lock, flags);
 	midi->midi_mode |= EMU10K1X_MIDI_MODE_INPUT;
 	midi->substream_input = substream;
@@ -1345,7 +1346,8 @@
 	unsigned long flags;
 
 	emu = midi->emu;
-	snd_assert(emu, return -ENXIO);
+	if (snd_BUG_ON(!emu))
+		return -ENXIO;
 	spin_lock_irqsave(&midi->open_lock, flags);
 	midi->midi_mode |= EMU10K1X_MIDI_MODE_OUTPUT;
 	midi->substream_output = substream;
@@ -1372,7 +1374,8 @@
 	int err = 0;
 
 	emu = midi->emu;
-	snd_assert(emu, return -ENXIO);
+	if (snd_BUG_ON(!emu))
+		return -ENXIO;
 	spin_lock_irqsave(&midi->open_lock, flags);
 	snd_emu10k1x_intr_disable(emu, midi->rx_enable);
 	midi->midi_mode &= ~EMU10K1X_MIDI_MODE_INPUT;
@@ -1394,7 +1397,8 @@
 	int err = 0;
 
 	emu = midi->emu;
-	snd_assert(emu, return -ENXIO);
+	if (snd_BUG_ON(!emu))
+		return -ENXIO;
 	spin_lock_irqsave(&midi->open_lock, flags);
 	snd_emu10k1x_intr_disable(emu, midi->tx_enable);
 	midi->midi_mode &= ~EMU10K1X_MIDI_MODE_OUTPUT;
@@ -1413,7 +1417,8 @@
 	struct emu10k1x *emu;
 	struct emu10k1x_midi *midi = substream->rmidi->private_data;
 	emu = midi->emu;
-	snd_assert(emu, return);
+	if (snd_BUG_ON(!emu))
+		return;
 
 	if (up)
 		snd_emu10k1x_intr_enable(emu, midi->rx_enable);
@@ -1428,7 +1433,8 @@
 	unsigned long flags;
 
 	emu = midi->emu;
-	snd_assert(emu, return);
+	if (snd_BUG_ON(!emu))
+		return;
 
 	if (up) {
 		int max = 4;
diff --git a/sound/pci/emu10k1/emufx.c b/sound/pci/emu10k1/emufx.c
index 71dc4c8..7dba08f 100644
--- a/sound/pci/emu10k1/emufx.c
+++ b/sound/pci/emu10k1/emufx.c
@@ -487,7 +487,8 @@
 				 u32 op, u32 r, u32 a, u32 x, u32 y)
 {
 	u_int32_t *code;
-	snd_assert(*ptr < 512, return);
+	if (snd_BUG_ON(*ptr >= 512))
+		return;
 	code = (u_int32_t __force *)icode->code + (*ptr) * 2;
 	set_bit(*ptr, icode->code_valid);
 	code[0] = ((x & 0x3ff) << 10) | (y & 0x3ff);
@@ -503,7 +504,8 @@
 					u32 op, u32 r, u32 a, u32 x, u32 y)
 {
 	u_int32_t *code;
-	snd_assert(*ptr < 1024, return);
+	if (snd_BUG_ON(*ptr >= 1024))
+		return;
 	code = (u_int32_t __force *)icode->code + (*ptr) * 2;
 	set_bit(*ptr, icode->code_valid);
 	code[0] = ((x & 0x7ff) << 12) | (y & 0x7ff);
diff --git a/sound/pci/emu10k1/emumpu401.c b/sound/pci/emu10k1/emumpu401.c
index c4d76d1..8578c70 100644
--- a/sound/pci/emu10k1/emumpu401.c
+++ b/sound/pci/emu10k1/emumpu401.c
@@ -157,7 +157,8 @@
 	unsigned long flags;
 
 	emu = midi->emu;
-	snd_assert(emu, return -ENXIO);
+	if (snd_BUG_ON(!emu))
+		return -ENXIO;
 	spin_lock_irqsave(&midi->open_lock, flags);
 	midi->midi_mode |= EMU10K1_MIDI_MODE_INPUT;
 	midi->substream_input = substream;
@@ -183,7 +184,8 @@
 	unsigned long flags;
 
 	emu = midi->emu;
-	snd_assert(emu, return -ENXIO);
+	if (snd_BUG_ON(!emu))
+		return -ENXIO;
 	spin_lock_irqsave(&midi->open_lock, flags);
 	midi->midi_mode |= EMU10K1_MIDI_MODE_OUTPUT;
 	midi->substream_output = substream;
@@ -210,7 +212,8 @@
 	int err = 0;
 
 	emu = midi->emu;
-	snd_assert(emu, return -ENXIO);
+	if (snd_BUG_ON(!emu))
+		return -ENXIO;
 	spin_lock_irqsave(&midi->open_lock, flags);
 	snd_emu10k1_intr_disable(emu, midi->rx_enable);
 	midi->midi_mode &= ~EMU10K1_MIDI_MODE_INPUT;
@@ -232,7 +235,8 @@
 	int err = 0;
 
 	emu = midi->emu;
-	snd_assert(emu, return -ENXIO);
+	if (snd_BUG_ON(!emu))
+		return -ENXIO;
 	spin_lock_irqsave(&midi->open_lock, flags);
 	snd_emu10k1_intr_disable(emu, midi->tx_enable);
 	midi->midi_mode &= ~EMU10K1_MIDI_MODE_OUTPUT;
@@ -251,7 +255,8 @@
 	struct snd_emu10k1 *emu;
 	struct snd_emu10k1_midi *midi = (struct snd_emu10k1_midi *)substream->rmidi->private_data;
 	emu = midi->emu;
-	snd_assert(emu, return);
+	if (snd_BUG_ON(!emu))
+		return;
 
 	if (up)
 		snd_emu10k1_intr_enable(emu, midi->rx_enable);
@@ -266,7 +271,8 @@
 	unsigned long flags;
 
 	emu = midi->emu;
-	snd_assert(emu, return);
+	if (snd_BUG_ON(!emu))
+		return;
 
 	if (up) {
 		int max = 4;
diff --git a/sound/pci/emu10k1/memory.c b/sound/pci/emu10k1/memory.c
index 7d379f5..6a47672 100644
--- a/sound/pci/emu10k1/memory.c
+++ b/sound/pci/emu10k1/memory.c
@@ -107,7 +107,8 @@
 
 	list_for_each (pos, &emu->mapped_link_head) {
 		struct snd_emu10k1_memblk *blk = get_emu10k1_memblk(pos, mapped_link);
-		snd_assert(blk->mapped_page >= 0, continue);
+		if (blk->mapped_page < 0)
+			continue;
 		size = blk->mapped_page - page;
 		if (size == npages) {
 			*nextp = pos;
@@ -295,15 +296,18 @@
 snd_emu10k1_alloc_pages(struct snd_emu10k1 *emu, struct snd_pcm_substream *substream)
 {
 	struct snd_pcm_runtime *runtime = substream->runtime;
-	struct snd_sg_buf *sgbuf = snd_pcm_substream_sgbuf(substream);
 	struct snd_util_memhdr *hdr;
 	struct snd_emu10k1_memblk *blk;
 	int page, err, idx;
 
-	snd_assert(emu, return NULL);
-	snd_assert(runtime->dma_bytes > 0 && runtime->dma_bytes < MAXPAGES * EMUPAGESIZE, return NULL);
+	if (snd_BUG_ON(!emu))
+		return NULL;
+	if (snd_BUG_ON(runtime->dma_bytes <= 0 ||
+		       runtime->dma_bytes >= MAXPAGES * EMUPAGESIZE))
+		return NULL;
 	hdr = emu->memhdr;
-	snd_assert(hdr, return NULL);
+	if (snd_BUG_ON(!hdr))
+		return NULL;
 
 	mutex_lock(&hdr->block_mutex);
 	blk = search_empty(emu, runtime->dma_bytes);
@@ -316,16 +320,9 @@
 	 */
 	idx = 0;
 	for (page = blk->first_page; page <= blk->last_page; page++, idx++) {
+		unsigned long ofs = idx << PAGE_SHIFT;
 		dma_addr_t addr;
-#ifdef CONFIG_SND_DEBUG
-		if (idx >= sgbuf->pages) {
-			printk(KERN_ERR "emu: pages overflow! (%d-%d) for %d\n",
-			       blk->first_page, blk->last_page, sgbuf->pages);
-			mutex_unlock(&hdr->block_mutex);
-			return NULL;
-		}
-#endif
-		addr = sgbuf->table[idx].addr;
+		addr = snd_pcm_sgbuf_get_addr(substream, ofs);
 		if (! is_valid_page(emu, addr)) {
 			printk(KERN_ERR "emu: failure page = %d\n", idx);
 			mutex_unlock(&hdr->block_mutex);
@@ -353,7 +350,8 @@
  */
 int snd_emu10k1_free_pages(struct snd_emu10k1 *emu, struct snd_util_memblk *blk)
 {
-	snd_assert(emu && blk, return -EINVAL);
+	if (snd_BUG_ON(!emu || !blk))
+		return -EINVAL;
 	return snd_emu10k1_synth_free(emu, blk);
 }
 
@@ -498,7 +496,8 @@
 static inline void *offset_ptr(struct snd_emu10k1 *emu, int page, int offset)
 {
 	char *ptr;
-	snd_assert(page >= 0 && page < emu->max_cache_pages, return NULL);
+	if (snd_BUG_ON(page < 0 || page >= emu->max_cache_pages))
+		return NULL;
 	ptr = emu->page_ptr_table[page];
 	if (! ptr) {
 		printk(KERN_ERR "emu10k1: access to NULL ptr: page = %d\n", page);
diff --git a/sound/pci/emu10k1/voice.c b/sound/pci/emu10k1/voice.c
index 958cb2a..d7300a1 100644
--- a/sound/pci/emu10k1/voice.c
+++ b/sound/pci/emu10k1/voice.c
@@ -111,8 +111,10 @@
 	unsigned long flags;
 	int result;
 
-	snd_assert(rvoice != NULL, return -EINVAL);
-	snd_assert(number, return -EINVAL);
+	if (snd_BUG_ON(!rvoice))
+		return -EINVAL;
+	if (snd_BUG_ON(!number))
+		return -EINVAL;
 
 	spin_lock_irqsave(&emu->voice_lock, flags);
 	for (;;) {
@@ -145,7 +147,8 @@
 {
 	unsigned long flags;
 
-	snd_assert(pvoice != NULL, return -EINVAL);
+	if (snd_BUG_ON(!pvoice))
+		return -EINVAL;
 	spin_lock_irqsave(&emu->voice_lock, flags);
 	pvoice->interrupt = NULL;
 	pvoice->use = pvoice->pcm = pvoice->synth = pvoice->midi = pvoice->efx = 0;
diff --git a/sound/pci/es1938.c b/sound/pci/es1938.c
index 84fac1f..4cd9a1fa 100644
--- a/sound/pci/es1938.c
+++ b/sound/pci/es1938.c
@@ -860,7 +860,8 @@
 	struct es1938 *chip = snd_pcm_substream_chip(substream);
 	pos <<= chip->dma1_shift;
 	count <<= chip->dma1_shift;
-	snd_assert(pos + count <= chip->dma1_size, return -EINVAL);
+	if (snd_BUG_ON(pos + count > chip->dma1_size))
+		return -EINVAL;
 	if (pos + count < chip->dma1_size) {
 		if (copy_to_user(dst, runtime->dma_area + pos + 1, count))
 			return -EFAULT;
diff --git a/sound/pci/es1968.c b/sound/pci/es1968.c
index 1bf298d..20ee759 100644
--- a/sound/pci/es1968.c
+++ b/sound/pci/es1968.c
@@ -692,7 +692,8 @@
 /* no spinlock */
 static void __apu_set_register(struct es1968 *chip, u16 channel, u8 reg, u16 data)
 {
-	snd_assert(channel < NR_APUS, return);
+	if (snd_BUG_ON(channel >= NR_APUS))
+		return;
 #ifdef CONFIG_PM
 	chip->apu_map[channel][reg] = data;
 #endif
@@ -711,7 +712,8 @@
 
 static u16 __apu_get_register(struct es1968 *chip, u16 channel, u8 reg)
 {
-	snd_assert(channel < NR_APUS, return 0);
+	if (snd_BUG_ON(channel >= NR_APUS))
+		return 0;
 	reg |= (channel << 4);
 	apu_index_set(chip, reg);
 	return __maestro_read(chip, IDR0_DATA_PORT);
diff --git a/sound/pci/hda/Makefile b/sound/pci/hda/Makefile
index ab0c726..1980c6d 100644
--- a/sound/pci/hda/Makefile
+++ b/sound/pci/hda/Makefile
@@ -5,6 +5,7 @@
 snd-hda-intel-y += hda_codec.o
 snd-hda-intel-$(CONFIG_PROC_FS) += hda_proc.o
 snd-hda-intel-$(CONFIG_SND_HDA_HWDEP) += hda_hwdep.o
+snd-hda-intel-$(CONFIG_SND_HDA_INPUT_BEEP) += hda_beep.o
 snd-hda-intel-$(CONFIG_SND_HDA_GENERIC) += hda_generic.o
 snd-hda-intel-$(CONFIG_SND_HDA_CODEC_REALTEK) += patch_realtek.o
 snd-hda-intel-$(CONFIG_SND_HDA_CODEC_CMEDIA) += patch_cmedia.o
@@ -14,5 +15,6 @@
 snd-hda-intel-$(CONFIG_SND_HDA_CODEC_ATIHDMI) += patch_atihdmi.o
 snd-hda-intel-$(CONFIG_SND_HDA_CODEC_CONEXANT) += patch_conexant.o
 snd-hda-intel-$(CONFIG_SND_HDA_CODEC_VIA) += patch_via.o
+snd-hda-intel-$(CONFIG_SND_HDA_CODEC_NVHDMI) += patch_nvhdmi.o
 
 obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-intel.o
diff --git a/sound/pci/hda/hda_beep.c b/sound/pci/hda/hda_beep.c
new file mode 100644
index 0000000..9b77b3e
--- /dev/null
+++ b/sound/pci/hda/hda_beep.c
@@ -0,0 +1,134 @@
+/*
+ * Digital Beep Input Interface for HD-audio codec
+ *
+ * Author: Matthew Ranostay <mranostay@embeddedalley.com>
+ * Copyright (c) 2008 Embedded Alley Solutions Inc
+ *
+ *  This driver is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This driver is 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/input.h>
+#include <linux/pci.h>
+#include <linux/workqueue.h>
+#include <sound/core.h>
+#include "hda_beep.h"
+
+enum {
+	DIGBEEP_HZ_STEP = 46875,	/* 46.875 Hz */
+	DIGBEEP_HZ_MIN = 93750,		/* 93.750 Hz */
+	DIGBEEP_HZ_MAX = 12000000,	/* 12 KHz */
+};
+
+static void snd_hda_generate_beep(struct work_struct *work)
+{
+	struct hda_beep *beep =
+		container_of(work, struct hda_beep, beep_work);
+	struct hda_codec *codec = beep->codec;
+
+	/* generate tone */
+	snd_hda_codec_write_cache(codec, beep->nid, 0,
+			AC_VERB_SET_BEEP_CONTROL, beep->tone);
+}
+
+static int snd_hda_beep_event(struct input_dev *dev, unsigned int type,
+				unsigned int code, int hz)
+{
+	struct hda_beep *beep = input_get_drvdata(dev);
+
+	switch (code) {
+	case SND_BELL:
+		if (hz)
+			hz = 1000;
+	case SND_TONE:
+		hz *= 1000; /* fixed point */
+		hz = hz - DIGBEEP_HZ_MIN;
+		if (hz < 0)
+			hz = 0; /* turn off PC beep*/
+		else if (hz >= (DIGBEEP_HZ_MAX - DIGBEEP_HZ_MIN))
+			hz = 0xff;
+		else {
+			hz /= DIGBEEP_HZ_STEP;
+			hz++;
+		}
+		break;
+	default:
+		return -1;
+	}
+	beep->tone = hz;
+
+	/* schedule beep event */
+	schedule_work(&beep->beep_work);
+	return 0;
+}
+
+int snd_hda_attach_beep_device(struct hda_codec *codec, int nid)
+{
+	struct input_dev *input_dev;
+	struct hda_beep *beep;
+	int err;
+
+	beep = kzalloc(sizeof(*beep), GFP_KERNEL);
+	if (beep == NULL)
+		return -ENOMEM;
+	snprintf(beep->phys, sizeof(beep->phys),
+		"card%d/codec#%d/beep0", codec->bus->card->number, codec->addr);
+	input_dev = input_allocate_device();
+
+	/* setup digital beep device */
+	input_dev->name = "HDA Digital PCBeep";
+	input_dev->phys = beep->phys;
+	input_dev->id.bustype = BUS_PCI;
+
+	input_dev->id.vendor = codec->vendor_id >> 16;
+	input_dev->id.product = codec->vendor_id & 0xffff;
+	input_dev->id.version = 0x01;
+
+	input_dev->evbit[0] = BIT_MASK(EV_SND);
+	input_dev->sndbit[0] = BIT_MASK(SND_BELL) | BIT_MASK(SND_TONE);
+	input_dev->event = snd_hda_beep_event;
+	input_dev->dev.parent = &codec->bus->pci->dev;
+	input_set_drvdata(input_dev, beep);
+
+	err = input_register_device(input_dev);
+	if (err < 0) {
+		input_free_device(input_dev);
+		kfree(beep);
+		return err;
+	}
+
+	/* enable linear scale */
+	snd_hda_codec_write(codec, nid, 0,
+		AC_VERB_SET_DIGI_CONVERT_2, 0x01);
+
+	beep->nid = nid;
+	beep->dev = input_dev;
+	beep->codec = codec;
+	codec->beep = beep;
+
+	INIT_WORK(&beep->beep_work, &snd_hda_generate_beep);
+	return 0;
+}
+
+void snd_hda_detach_beep_device(struct hda_codec *codec)
+{
+	struct hda_beep *beep = codec->beep;
+	if (beep) {
+		cancel_work_sync(&beep->beep_work);
+		flush_scheduled_work();
+
+		input_unregister_device(beep->dev);
+		kfree(beep);
+	}
+}
diff --git a/sound/pci/hda/hda_beep.h b/sound/pci/hda/hda_beep.h
new file mode 100644
index 0000000..de4036e
--- /dev/null
+++ b/sound/pci/hda/hda_beep.h
@@ -0,0 +1,44 @@
+/*
+ * Digital Beep Input Interface for HD-audio codec
+ *
+ * Author: Matthew Ranostay <mranostay@embeddedalley.com>
+ * Copyright (c) 2008 Embedded Alley Solutions Inc
+ *
+ *  This driver is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This driver is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+#ifndef __SOUND_HDA_BEEP_H
+#define __SOUND_HDA_BEEP_H
+
+#include "hda_codec.h"
+
+/* beep information */
+struct hda_beep {
+	struct input_dev *dev;
+	struct hda_codec *codec;
+	char phys[32];
+	int tone;
+	int nid;
+	struct work_struct beep_work; /* scheduled task for beep event */
+};
+
+#ifdef CONFIG_SND_HDA_INPUT_BEEP
+int snd_hda_attach_beep_device(struct hda_codec *codec, int nid);
+void snd_hda_detach_beep_device(struct hda_codec *codec);
+#else
+#define snd_hda_attach_beep_device(...)
+#define snd_hda_detach_beep_device(...)
+#endif
+#endif
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index d2e1093..6447754 100644
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/pci/hda/hda_codec.c
@@ -94,6 +94,9 @@
 #ifdef CONFIG_SND_HDA_CODEC_VIA
 	snd_hda_preset_via,
 #endif
+#ifdef CONFIG_SND_HDA_CODEC_NVHDMI
+	snd_hda_preset_nvhdmi,
+#endif
 	NULL
 };
 
@@ -211,7 +214,8 @@
 	unsigned int shift, num_elems, mask;
 	hda_nid_t prev_nid;
 
-	snd_assert(conn_list && max_conns > 0, return -EINVAL);
+	if (snd_BUG_ON(!conn_list || max_conns <= 0))
+		return -EINVAL;
 
 	parm = snd_hda_param_read(codec, nid, AC_PAR_CONNLIST_LEN);
 	if (parm & AC_CLIST_LONG) {
@@ -313,7 +317,7 @@
 }
 
 /*
- * process queueud unsolicited events
+ * process queued unsolicited events
  */
 static void process_unsol_events(struct work_struct *work)
 {
@@ -407,8 +411,10 @@
 		.dev_free = snd_hda_bus_dev_free,
 	};
 
-	snd_assert(temp, return -EINVAL);
-	snd_assert(temp->ops.command && temp->ops.get_response, return -EINVAL);
+	if (snd_BUG_ON(!temp))
+		return -EINVAL;
+	if (snd_BUG_ON(!temp->ops.command || !temp->ops.get_response))
+		return -EINVAL;
 
 	if (busp)
 		*busp = NULL;
@@ -585,11 +591,13 @@
 				struct hda_codec **codecp)
 {
 	struct hda_codec *codec;
-	char component[13];
+	char component[31];
 	int err;
 
-	snd_assert(bus, return -EINVAL);
-	snd_assert(codec_addr <= HDA_MAX_CODEC_ADDRESS, return -EINVAL);
+	if (snd_BUG_ON(!bus))
+		return -EINVAL;
+	if (snd_BUG_ON(codec_addr > HDA_MAX_CODEC_ADDRESS))
+		return -EINVAL;
 
 	if (bus->caddr_tbl[codec_addr]) {
 		snd_printk(KERN_ERR "hda_codec: "
@@ -688,7 +696,7 @@
 	snd_hda_create_hwdep(codec);
 #endif
 
-	sprintf(component, "HDA:%08x", codec->vendor_id);
+	sprintf(component, "HDA:%08x,%08x,%08x", codec->vendor_id, codec->subsystem_id, codec->revision_id);
 	snd_component_add(codec->bus->card, component);
 
 	if (codecp)
@@ -956,15 +964,6 @@
 }
 #endif /* SND_HDA_NEEDS_RESUME */
 
-/*
- * AMP control callbacks
- */
-/* retrieve parameters from private_value */
-#define get_amp_nid(kc)		((kc)->private_value & 0xffff)
-#define get_amp_channels(kc)	(((kc)->private_value >> 16) & 0x3)
-#define get_amp_direction(kc)	(((kc)->private_value >> 18) & 0x1)
-#define get_amp_index(kc)	(((kc)->private_value >> 19) & 0xf)
-
 /* volume */
 int snd_hda_mixer_amp_volume_info(struct snd_kcontrol *kcontrol,
 				  struct snd_ctl_elem_info *uinfo)
@@ -1430,6 +1429,29 @@
 	return sbits;
 }
 
+/* set digital convert verbs both for the given NID and its slaves */
+static void set_dig_out(struct hda_codec *codec, hda_nid_t nid,
+			int verb, int val)
+{
+	hda_nid_t *d;
+
+	snd_hda_codec_write(codec, nid, 0, verb, val);
+	d = codec->slave_dig_outs;
+	if (!d)
+		return;
+	for (; *d; d++)
+		snd_hda_codec_write(codec, *d, 0, verb, val);
+}
+
+static inline void set_dig_out_convert(struct hda_codec *codec, hda_nid_t nid,
+				       int dig1, int dig2)
+{
+	if (dig1 != -1)
+		set_dig_out(codec, nid, AC_VERB_SET_DIGI_CONVERT_1, dig1);
+	if (dig2 != -1)
+		set_dig_out(codec, nid, AC_VERB_SET_DIGI_CONVERT_2, dig2);
+}
+
 static int snd_hda_spdif_default_put(struct snd_kcontrol *kcontrol,
 				     struct snd_ctl_elem_value *ucontrol)
 {
@@ -1448,14 +1470,8 @@
 	change = codec->spdif_ctls != val;
 	codec->spdif_ctls = val;
 
-	if (change) {
-		snd_hda_codec_write_cache(codec, nid, 0,
-					  AC_VERB_SET_DIGI_CONVERT_1,
-					  val & 0xff);
-		snd_hda_codec_write_cache(codec, nid, 0,
-					  AC_VERB_SET_DIGI_CONVERT_2,
-					  val >> 8);
-	}
+	if (change)
+		set_dig_out_convert(codec, nid, val & 0xff, (val >> 8) & 0xff);
 
 	mutex_unlock(&codec->spdif_mutex);
 	return change;
@@ -1487,9 +1503,7 @@
 	change = codec->spdif_ctls != val;
 	if (change) {
 		codec->spdif_ctls = val;
-		snd_hda_codec_write_cache(codec, nid, 0,
-					  AC_VERB_SET_DIGI_CONVERT_1,
-					  val & 0xff);
+		set_dig_out_convert(codec, nid, val & 0xff, -1);
 		/* unmute amp switch (if any) */
 		if ((get_wcaps(codec, nid) & AC_WCAP_OUT_AMP) &&
 		    (val & AC_DIG1_ENABLE))
@@ -2236,11 +2250,13 @@
 	if (info->ops.close == NULL)
 		info->ops.close = hda_pcm_default_open_close;
 	if (info->ops.prepare == NULL) {
-		snd_assert(info->nid, return -EINVAL);
+		if (snd_BUG_ON(!info->nid))
+			return -EINVAL;
 		info->ops.prepare = hda_pcm_default_prepare;
 	}
 	if (info->ops.cleanup == NULL) {
-		snd_assert(info->nid, return -EINVAL);
+		if (snd_BUG_ON(!info->nid))
+			return -EINVAL;
 		info->ops.cleanup = hda_pcm_default_cleanup;
 	}
 	return 0;
@@ -2583,14 +2599,31 @@
 				 unsigned int stream_tag, unsigned int format)
 {
 	/* turn off SPDIF once; otherwise the IEC958 bits won't be updated */
-	if (codec->spdif_ctls & AC_DIG1_ENABLE)
-		snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1,
-				    codec->spdif_ctls & ~AC_DIG1_ENABLE & 0xff);
+	if (codec->spdif_status_reset && (codec->spdif_ctls & AC_DIG1_ENABLE))
+		set_dig_out_convert(codec, nid, 
+				    codec->spdif_ctls & ~AC_DIG1_ENABLE & 0xff,
+				    -1);
 	snd_hda_codec_setup_stream(codec, nid, stream_tag, 0, format);
+	if (codec->slave_dig_outs) {
+		hda_nid_t *d;
+		for (d = codec->slave_dig_outs; *d; d++)
+			snd_hda_codec_setup_stream(codec, *d, stream_tag, 0,
+						   format);
+	}
 	/* turn on again (if needed) */
-	if (codec->spdif_ctls & AC_DIG1_ENABLE)
-		snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1,
-				    codec->spdif_ctls & 0xff);
+	if (codec->spdif_status_reset && (codec->spdif_ctls & AC_DIG1_ENABLE))
+		set_dig_out_convert(codec, nid,
+				    codec->spdif_ctls & 0xff, -1);
+}
+
+static void cleanup_dig_out_stream(struct hda_codec *codec, hda_nid_t nid)
+{
+	snd_hda_codec_cleanup_stream(codec, nid);
+	if (codec->slave_dig_outs) {
+		hda_nid_t *d;
+		for (d = codec->slave_dig_outs; *d; d++)
+			snd_hda_codec_cleanup_stream(codec, *d);
+	}
 }
 
 /*
@@ -2602,7 +2635,7 @@
 	mutex_lock(&codec->spdif_mutex);
 	if (mout->dig_out_used == HDA_DIG_ANALOG_DUP)
 		/* already opened as analog dup; reset it once */
-		snd_hda_codec_cleanup_stream(codec, mout->dig_out_nid);
+		cleanup_dig_out_stream(codec, mout->dig_out_nid);
 	mout->dig_out_used = HDA_DIG_EXCLUSIVE;
 	mutex_unlock(&codec->spdif_mutex);
 	return 0;
@@ -2697,7 +2730,7 @@
 					     stream_tag, format);
 		} else {
 			mout->dig_out_used = 0;
-			snd_hda_codec_cleanup_stream(codec, mout->dig_out_nid);
+			cleanup_dig_out_stream(codec, mout->dig_out_nid);
 		}
 	}
 	mutex_unlock(&codec->spdif_mutex);
@@ -2748,7 +2781,7 @@
 						     mout->extra_out_nid[i]);
 	mutex_lock(&codec->spdif_mutex);
 	if (mout->dig_out_nid && mout->dig_out_used == HDA_DIG_ANALOG_DUP) {
-		snd_hda_codec_cleanup_stream(codec, mout->dig_out_nid);
+		cleanup_dig_out_stream(codec, mout->dig_out_nid);
 		mout->dig_out_used = 0;
 	}
 	mutex_unlock(&codec->spdif_mutex);
@@ -2756,7 +2789,7 @@
 }
 
 /*
- * Helper for automatic ping configuration
+ * Helper for automatic pin configuration
  */
 
 static int is_in_nid_list(hda_nid_t nid, hda_nid_t *list)
diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h
index efc6828..60468f5 100644
--- a/sound/pci/hda/hda_codec.h
+++ b/sound/pci/hda/hda_codec.h
@@ -90,6 +90,14 @@
 #define AC_VERB_GET_CONFIG_DEFAULT		0x0f1c
 /* f20: AFG/MFG */
 #define AC_VERB_GET_SUBSYSTEM_ID		0x0f20
+#define AC_VERB_GET_CVT_CHAN_COUNT		0x0f2d
+#define AC_VERB_GET_HDMI_DIP_SIZE		0x0f2e
+#define AC_VERB_GET_HDMI_ELDD			0x0f2f
+#define AC_VERB_GET_HDMI_DIP_INDEX		0x0f30
+#define AC_VERB_GET_HDMI_DIP_DATA		0x0f31
+#define AC_VERB_GET_HDMI_DIP_XMIT		0x0f32
+#define AC_VERB_GET_HDMI_CP_CTRL		0x0f33
+#define AC_VERB_GET_HDMI_CHAN_SLOT		0x0f34
 
 /*
  * SET verbs
@@ -121,7 +129,14 @@
 #define AC_VERB_SET_CONFIG_DEFAULT_BYTES_1	0x71d
 #define AC_VERB_SET_CONFIG_DEFAULT_BYTES_2	0x71e
 #define AC_VERB_SET_CONFIG_DEFAULT_BYTES_3	0x71f
+#define AC_VERB_SET_EAPD				0x788
 #define AC_VERB_SET_CODEC_RESET			0x7ff
+#define AC_VERB_SET_CVT_CHAN_COUNT		0x72d
+#define AC_VERB_SET_HDMI_DIP_INDEX		0x730
+#define AC_VERB_SET_HDMI_DIP_DATA		0x731
+#define AC_VERB_SET_HDMI_DIP_XMIT		0x732
+#define AC_VERB_SET_HDMI_CP_CTRL		0x733
+#define AC_VERB_SET_HDMI_CHAN_SLOT		0x734
 
 /*
  * Parameter IDs
@@ -143,6 +158,7 @@
 #define AC_PAR_GPIO_CAP			0x11
 #define AC_PAR_AMP_OUT_CAP		0x12
 #define AC_PAR_VOL_KNB_CAP		0x13
+#define AC_PAR_HDMI_LPCM_CAP		0x20
 
 /*
  * AC_VERB_PARAMETERS results (32bit)
@@ -171,6 +187,8 @@
 #define AC_WCAP_DIGITAL			(1<<9)	/* digital I/O */
 #define AC_WCAP_POWER			(1<<10)	/* power control */
 #define AC_WCAP_LR_SWAP			(1<<11)	/* L/R swap */
+#define AC_WCAP_CP_CAPS			(1<<12) /* content protection */
+#define AC_WCAP_CHAN_CNT_EXT		(7<<13)	/* channel count ext */
 #define AC_WCAP_DELAY			(0xf<<16)
 #define AC_WCAP_DELAY_SHIFT		16
 #define AC_WCAP_TYPE			(0xf<<20)
@@ -206,9 +224,20 @@
 /* Input converter SDI select */
 #define AC_SDI_SELECT			(0xf<<0)
 
-/* Unsolicited response */
+/* Unsolicited response control */
 #define AC_UNSOL_TAG			(0x3f<<0)
 #define AC_UNSOL_ENABLED		(1<<7)
+#define AC_USRSP_EN			AC_UNSOL_ENABLED
+
+/* Unsolicited responses */
+#define AC_UNSOL_RES_TAG		(0x3f<<26)
+#define AC_UNSOL_RES_TAG_SHIFT		26
+#define AC_UNSOL_RES_SUBTAG		(0x1f<<21)
+#define AC_UNSOL_RES_SUBTAG_SHIFT	21
+#define AC_UNSOL_RES_ELDV		(1<<1)	/* ELD Data valid (for HDMI) */
+#define AC_UNSOL_RES_PD			(1<<0)	/* pinsense detect */
+#define AC_UNSOL_RES_CP_STATE		(1<<1)	/* content protection */
+#define AC_UNSOL_RES_CP_READY		(1<<0)	/* content protection */
 
 /* Pin widget capabilies */
 #define AC_PINCAP_IMP_SENSE		(1<<0)	/* impedance sense capable */
@@ -222,6 +251,10 @@
  *       but is marked reserved in the Intel HDA specification.
  */
 #define AC_PINCAP_LR_SWAP		(1<<7)	/* L/R swap */
+/* Note: The same bit as LR_SWAP is newly defined as HDMI capability
+ *       in HD-audio specification
+ */
+#define AC_PINCAP_HDMI			(1<<7)	/* HDMI pin */
 #define AC_PINCAP_VREF			(0x37<<8)
 #define AC_PINCAP_VREF_SHIFT		8
 #define AC_PINCAP_EAPD			(1<<16)	/* EAPD capable */
@@ -272,6 +305,22 @@
 #define AC_KNBCAP_NUM_STEPS		(0x7f<<0)
 #define AC_KNBCAP_DELTA			(1<<7)
 
+/* HDMI LPCM capabilities */
+#define AC_LPCMCAP_48K_CP_CHNS		(0x0f<<0) /* max channels w/ CP-on */	
+#define AC_LPCMCAP_48K_NO_CHNS		(0x0f<<4) /* max channels w/o CP-on */
+#define AC_LPCMCAP_48K_20BIT		(1<<8)	/* 20b bitrate supported */
+#define AC_LPCMCAP_48K_24BIT		(1<<9)	/* 24b bitrate supported */
+#define AC_LPCMCAP_96K_CP_CHNS		(0x0f<<10) /* max channels w/ CP-on */	
+#define AC_LPCMCAP_96K_NO_CHNS		(0x0f<<14) /* max channels w/o CP-on */
+#define AC_LPCMCAP_96K_20BIT		(1<<18)	/* 20b bitrate supported */
+#define AC_LPCMCAP_96K_24BIT		(1<<19)	/* 24b bitrate supported */
+#define AC_LPCMCAP_192K_CP_CHNS		(0x0f<<20) /* max channels w/ CP-on */	
+#define AC_LPCMCAP_192K_NO_CHNS		(0x0f<<24) /* max channels w/o CP-on */
+#define AC_LPCMCAP_192K_20BIT		(1<<28)	/* 20b bitrate supported */
+#define AC_LPCMCAP_192K_24BIT		(1<<29)	/* 24b bitrate supported */
+#define AC_LPCMCAP_44K			(1<<30)	/* 44.1kHz support */
+#define AC_LPCMCAP_44K_MS		(1<<31)	/* 44.1kHz-multiplies support */
+
 /*
  * Control Parameters
  */
@@ -317,18 +366,44 @@
 #define AC_PINCTL_OUT_EN		(1<<6)
 #define AC_PINCTL_HP_EN			(1<<7)
 
-/* Unsolicited response - 8bit */
-#define AC_USRSP_EN			(1<<7)
-
 /* Pin sense - 32bit */
 #define AC_PINSENSE_IMPEDANCE_MASK	(0x7fffffff)
 #define AC_PINSENSE_PRESENCE		(1<<31)
+#define AC_PINSENSE_ELDV		(1<<30)	/* ELD valid (HDMI) */
 
 /* EAPD/BTL enable - 32bit */
 #define AC_EAPDBTL_BALANCED		(1<<0)
 #define AC_EAPDBTL_EAPD			(1<<1)
 #define AC_EAPDBTL_LR_SWAP		(1<<2)
 
+/* HDMI ELD data */
+#define AC_ELDD_ELD_VALID		(1<<31)
+#define AC_ELDD_ELD_DATA		0xff
+
+/* HDMI DIP size */
+#define AC_DIPSIZE_ELD_BUF		(1<<3) /* ELD buf size of packet size */
+#define AC_DIPSIZE_PACK_IDX		(0x07<<0) /* packet index */
+
+/* HDMI DIP index */
+#define AC_DIPIDX_PACK_IDX		(0x07<<5) /* packet idnex */
+#define AC_DIPIDX_BYTE_IDX		(0x1f<<0) /* byte index */
+
+/* HDMI DIP xmit (transmit) control */
+#define AC_DIPXMIT_MASK			(0x3<<6)
+#define AC_DIPXMIT_DISABLE		(0x0<<6) /* disable xmit */
+#define AC_DIPXMIT_ONCE			(0x2<<6) /* xmit once then disable */
+#define AC_DIPXMIT_BEST			(0x3<<6) /* best effort */
+
+/* HDMI content protection (CP) control */
+#define AC_CPCTRL_CES			(1<<9) /* current encryption state */
+#define AC_CPCTRL_READY			(1<<8) /* ready bit */
+#define AC_CPCTRL_SUBTAG		(0x1f<<3) /* subtag for unsol-resp */
+#define AC_CPCTRL_STATE			(3<<0) /* current CP request state */
+
+/* Converter channel <-> HDMI slot mapping */
+#define AC_CVTMAP_HDMI_SLOT		(0xf<<0) /* HDMI slot number */
+#define AC_CVTMAP_CHAN			(0xf<<4) /* converter channel number */
+
 /* configuration default - 32bit */
 #define AC_DEFCFG_SEQUENCE		(0xf<<0)
 #define AC_DEFCFG_DEF_ASSOC		(0xf<<4)
@@ -449,6 +524,7 @@
  */
 
 struct hda_bus;
+struct hda_beep;
 struct hda_codec;
 struct hda_pcm;
 struct hda_pcm_stream;
@@ -634,6 +710,9 @@
 	/* codec specific info */
 	void *spec;
 
+	/* beep device */
+	struct hda_beep *beep;
+
 	/* widget capabilities cache */
 	unsigned int num_nodes;
 	hda_nid_t start_nid;
@@ -646,9 +725,15 @@
 	unsigned int spdif_status;	/* IEC958 status bits */
 	unsigned short spdif_ctls;	/* SPDIF control bits */
 	unsigned int spdif_in_enable;	/* SPDIF input enable? */
+	hda_nid_t *slave_dig_outs; /* optional digital out slave widgets */
 
 	struct snd_hwdep *hwdep;	/* assigned hwdep device */
 
+	/* misc flags */
+	unsigned int spdif_status_reset :1; /* needs to toggle SPDIF for each
+					     * status change
+					     * (e.g. Realtek codecs)
+					     */
 #ifdef CONFIG_SND_HDA_POWER_SAVE
 	unsigned int power_on :1;	/* current (global) power-state */
 	unsigned int power_transition :1; /* power-state in transition */
diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c
index 59e4389..0ca3089 100644
--- a/sound/pci/hda/hda_generic.c
+++ b/sound/pci/hda/hda_generic.c
@@ -174,7 +174,8 @@
 	int i, nodes, err;
 	hda_nid_t nid;
 
-	snd_assert(spec, return -EINVAL);
+	if (snd_BUG_ON(!spec))
+		return -EINVAL;
 
 	spec->def_amp_out_caps = snd_hda_param_read(codec, codec->afg, AC_PAR_AMP_OUT_CAP);
 	spec->def_amp_in_caps = snd_hda_param_read(codec, codec->afg, AC_PAR_AMP_IN_CAP);
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
index 1c53e33..9f316c1 100644
--- a/sound/pci/hda/hda_intel.c
+++ b/sound/pci/hda/hda_intel.c
@@ -222,9 +222,9 @@
 #define RIRB_INT_OVERRUN	0x04
 #define RIRB_INT_MASK		0x05
 
-/* STATESTS int mask: SD2,SD1,SD0 */
-#define AZX_MAX_CODECS		3
-#define STATESTS_INT_MASK	0x07
+/* STATESTS int mask: S3,SD2,SD1,SD0 */
+#define AZX_MAX_CODECS		4
+#define STATESTS_INT_MASK	0x0f
 
 /* SD_CTL bits */
 #define SD_CTL_STREAM_RESET	0x01	/* stream reset bit */
@@ -286,6 +286,11 @@
 #define INTEL_SCH_HDA_DEVC      0x78
 #define INTEL_SCH_HDA_DEVC_NOSNOOP       (0x1<<11)
 
+/* Define IN stream 0 FIFO size offset in VIA controller */
+#define VIA_IN_STREAM0_FIFO_SIZE_OFFSET	0x90
+/* Define VIA HD Audio Device ID*/
+#define VIA_HDAC_DEVICE_ID		0x3288
+
 
 /*
  */
@@ -317,6 +322,12 @@
 	unsigned int running :1;
 	unsigned int irq_pending :1;
 	unsigned int irq_ignore :1;
+	/*
+	 * For VIA:
+	 *  A flag to ensure DMA position is 0
+	 *  when link position is not greater than FIFO size
+	 */
+	unsigned int insufficient :1;
 };
 
 /* CORB/RIRB */
@@ -379,6 +390,7 @@
 	unsigned int polling_mode :1;
 	unsigned int msi :1;
 	unsigned int irq_pending_warned :1;
+	unsigned int via_dmapos_patch :1; /* enable DMA-position fix for VIA */
 
 	/* for debugging */
 	unsigned int last_cmd;	/* last issued command (to sync) */
@@ -398,6 +410,7 @@
 	AZX_DRIVER_ULI,
 	AZX_DRIVER_NVIDIA,
 	AZX_DRIVER_TERA,
+	AZX_NUM_DRIVERS, /* keep this as last entry */
 };
 
 static char *driver_short_names[] __devinitdata = {
@@ -818,6 +831,11 @@
 /* start a stream */
 static void azx_stream_start(struct azx *chip, struct azx_dev *azx_dev)
 {
+	/*
+	 * Before stream start, initialize parameter
+	 */
+	azx_dev->insufficient = 1;
+
 	/* enable SIE */
 	azx_writeb(chip, INTCTL,
 		   azx_readb(chip, INTCTL) | (1 << azx_dev->index));
@@ -998,7 +1016,6 @@
 		      struct azx_dev *azx_dev, u32 **bdlp,
 		      int ofs, int size, int with_ioc)
 {
-	struct snd_sg_buf *sgbuf = snd_pcm_substream_sgbuf(substream);
 	u32 *bdl = *bdlp;
 
 	while (size > 0) {
@@ -1008,14 +1025,12 @@
 		if (azx_dev->frags >= AZX_MAX_BDL_ENTRIES)
 			return -EINVAL;
 
-		addr = snd_pcm_sgbuf_get_addr(sgbuf, ofs);
+		addr = snd_pcm_sgbuf_get_addr(substream, ofs);
 		/* program the address field of the BDL entry */
 		bdl[0] = cpu_to_le32((u32)addr);
 		bdl[1] = cpu_to_le32(upper_32_bits(addr));
 		/* program the size field of the BDL entry */
-		chunk = PAGE_SIZE - (ofs % PAGE_SIZE);
-		if (size < chunk)
-			chunk = size;
+		chunk = snd_pcm_sgbuf_get_chunk_size(substream, ofs, size);
 		bdl[2] = cpu_to_le32(chunk);
 		/* program the IOC to enable interrupt
 		 * only when the whole fragment is processed
@@ -1151,7 +1166,8 @@
 
 	/* enable the position buffer */
 	if (chip->position_fix == POS_FIX_POSBUF ||
-	    chip->position_fix == POS_FIX_AUTO) {
+	    chip->position_fix == POS_FIX_AUTO ||
+	    chip->via_dmapos_patch) {
 		if (!(azx_readl(chip, DPLBASE) & ICH6_DPLBASE_ENABLE))
 			azx_writel(chip, DPLBASE,
 				(u32)chip->posbuf.addr | ICH6_DPLBASE_ENABLE);
@@ -1169,23 +1185,26 @@
  * Codec initialization
  */
 
-static unsigned int azx_max_codecs[] __devinitdata = {
-	[AZX_DRIVER_ICH] = 4,		/* Some ICH9 boards use SD3 */
-	[AZX_DRIVER_SCH] = 3,
-	[AZX_DRIVER_ATI] = 4,
-	[AZX_DRIVER_ATIHDMI] = 4,
-	[AZX_DRIVER_VIA] = 3,		/* FIXME: correct? */
-	[AZX_DRIVER_SIS] = 3,		/* FIXME: correct? */
-	[AZX_DRIVER_ULI] = 3,		/* FIXME: correct? */
-	[AZX_DRIVER_NVIDIA] = 3,	/* FIXME: correct? */
+/* number of codec slots for each chipset: 0 = default slots (i.e. 4) */
+static unsigned int azx_max_codecs[AZX_NUM_DRIVERS] __devinitdata = {
 	[AZX_DRIVER_TERA] = 1,
 };
 
+/* number of slots to probe as default
+ * this can be different from azx_max_codecs[] -- e.g. some boards
+ * report wrongly the non-existing 4th slot availability
+ */
+static unsigned int azx_default_codecs[AZX_NUM_DRIVERS] __devinitdata = {
+	[AZX_DRIVER_ICH] = 3,
+	[AZX_DRIVER_ATI] = 3,
+};
+
 static int __devinit azx_codec_create(struct azx *chip, const char *model,
 				      unsigned int codec_probe_mask)
 {
 	struct hda_bus_template bus_temp;
 	int c, codecs, audio_codecs, err;
+	int def_slots, max_slots;
 
 	memset(&bus_temp, 0, sizeof(bus_temp));
 	bus_temp.private_data = chip;
@@ -1201,8 +1220,17 @@
 	if (err < 0)
 		return err;
 
+	if (chip->driver_type == AZX_DRIVER_NVIDIA)
+		chip->bus->needs_damn_long_delay = 1;
+
 	codecs = audio_codecs = 0;
-	for (c = 0; c < AZX_MAX_CODECS; c++) {
+	max_slots = azx_max_codecs[chip->driver_type];
+	if (!max_slots)
+		max_slots = AZX_MAX_CODECS;
+	def_slots = azx_default_codecs[chip->driver_type];
+	if (!def_slots)
+		def_slots = max_slots;
+	for (c = 0; c < def_slots; c++) {
 		if ((chip->codec_mask & (1 << c)) & codec_probe_mask) {
 			struct hda_codec *codec;
 			err = snd_hda_codec_new(chip->bus, c, &codec);
@@ -1215,7 +1243,7 @@
 	}
 	if (!audio_codecs) {
 		/* probe additional slots if no codec is found */
-		for (; c < azx_max_codecs[chip->driver_type]; c++) {
+		for (; c < max_slots; c++) {
 			if ((chip->codec_mask & (1 << c)) & codec_probe_mask) {
 				err = snd_hda_codec_new(chip->bus, c, NULL);
 				if (err < 0)
@@ -1507,13 +1535,71 @@
 	return 0;
 }
 
+/* get the current DMA position with correction on VIA chips */
+static unsigned int azx_via_get_position(struct azx *chip,
+					 struct azx_dev *azx_dev)
+{
+	unsigned int link_pos, mini_pos, bound_pos;
+	unsigned int mod_link_pos, mod_dma_pos, mod_mini_pos;
+	unsigned int fifo_size;
+
+	link_pos = azx_sd_readl(azx_dev, SD_LPIB);
+	if (azx_dev->index >= 4) {
+		/* Playback, no problem using link position */
+		return link_pos;
+	}
+
+	/* Capture */
+	/* For new chipset,
+	 * use mod to get the DMA position just like old chipset
+	 */
+	mod_dma_pos = le32_to_cpu(*azx_dev->posbuf);
+	mod_dma_pos %= azx_dev->period_bytes;
+
+	/* azx_dev->fifo_size can't get FIFO size of in stream.
+	 * Get from base address + offset.
+	 */
+	fifo_size = readw(chip->remap_addr + VIA_IN_STREAM0_FIFO_SIZE_OFFSET);
+
+	if (azx_dev->insufficient) {
+		/* Link position never gather than FIFO size */
+		if (link_pos <= fifo_size)
+			return 0;
+
+		azx_dev->insufficient = 0;
+	}
+
+	if (link_pos <= fifo_size)
+		mini_pos = azx_dev->bufsize + link_pos - fifo_size;
+	else
+		mini_pos = link_pos - fifo_size;
+
+	/* Find nearest previous boudary */
+	mod_mini_pos = mini_pos % azx_dev->period_bytes;
+	mod_link_pos = link_pos % azx_dev->period_bytes;
+	if (mod_link_pos >= fifo_size)
+		bound_pos = link_pos - mod_link_pos;
+	else if (mod_dma_pos >= mod_mini_pos)
+		bound_pos = mini_pos - mod_mini_pos;
+	else {
+		bound_pos = mini_pos - mod_mini_pos + azx_dev->period_bytes;
+		if (bound_pos >= azx_dev->bufsize)
+			bound_pos = 0;
+	}
+
+	/* Calculate real DMA position we want */
+	return bound_pos + mod_dma_pos;
+}
+
 static unsigned int azx_get_position(struct azx *chip,
 				     struct azx_dev *azx_dev)
 {
 	unsigned int pos;
 
-	if (chip->position_fix == POS_FIX_POSBUF ||
-	    chip->position_fix == POS_FIX_AUTO) {
+	if (chip->via_dmapos_patch)
+		pos = azx_via_get_position(chip, azx_dev);
+	else if (chip->position_fix == POS_FIX_POSBUF ||
+		 chip->position_fix == POS_FIX_AUTO) {
 		/* use the position buffer */
 		pos = le32_to_cpu(*azx_dev->posbuf);
 	} else {
@@ -1559,6 +1645,8 @@
 			chip->position_fix = POS_FIX_POSBUF;
 	}
 
+	if (!bdl_pos_adj[chip->dev_index])
+		return 1; /* no delayed ack */
 	if (pos % azx_dev->period_bytes > azx_dev->period_bytes / 2)
 		return 0; /* NG - it's below the period boundary */
 	return 1; /* OK, it's fine */
@@ -1646,7 +1734,8 @@
 	if (!cpcm->stream[0].substreams && !cpcm->stream[1].substreams)
 		return 0;
 
-	snd_assert(cpcm->name, return -EINVAL);
+	if (snd_BUG_ON(!cpcm->name))
+		return -EINVAL;
 
 	err = snd_pcm_new(chip->card, cpcm->name, cpcm->device,
 			  cpcm->stream[0].substreams,
@@ -1670,7 +1759,7 @@
 		snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &azx_pcm_ops);
 	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG,
 					      snd_dma_pci_data(chip->pci),
-					      1024 * 64, 1024 * 1024);
+					      1024 * 64, 32 * 1024 * 1024);
 	chip->pcm[cpcm->device] = pcm;
 	return 0;
 }
@@ -1946,6 +2035,15 @@
 {
 	const struct snd_pci_quirk *q;
 
+	/* Check VIA HD Audio Controller exist */
+	if (chip->pci->vendor == PCI_VENDOR_ID_VIA &&
+	    chip->pci->device == VIA_HDAC_DEVICE_ID) {
+		chip->via_dmapos_patch = 1;
+		/* Use link position directly, avoid any transfer problem. */
+		return POS_FIX_LPIB;
+	}
+	chip->via_dmapos_patch = 0;
+
 	if (fix == POS_FIX_AUTO) {
 		q = snd_pci_quirk_lookup(chip->pci, position_fix_list);
 		if (q) {
diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h
index 5c9e578..7957fef 100644
--- a/sound/pci/hda/hda_local.h
+++ b/sound/pci/hda/hda_local.h
@@ -368,12 +368,15 @@
 #define AMP_OUT_UNMUTE	0xb000
 #define AMP_OUT_ZERO	0xb000
 /* pinctl values */
-#define PIN_IN		0x20
-#define PIN_VREF80	0x24
-#define PIN_VREF50	0x21
-#define PIN_OUT		0x40
-#define PIN_HP		0xc0
-#define PIN_HP_AMP	0x80
+#define PIN_IN			(AC_PINCTL_IN_EN)
+#define PIN_VREFHIZ	(AC_PINCTL_IN_EN | AC_PINCTL_VREF_HIZ)
+#define PIN_VREF50		(AC_PINCTL_IN_EN | AC_PINCTL_VREF_50)
+#define PIN_VREFGRD	(AC_PINCTL_IN_EN | AC_PINCTL_VREF_GRD)
+#define PIN_VREF80		(AC_PINCTL_IN_EN | AC_PINCTL_VREF_80)
+#define PIN_VREF100	(AC_PINCTL_IN_EN | AC_PINCTL_VREF_100)
+#define PIN_OUT		(AC_PINCTL_OUT_EN)
+#define PIN_HP			(AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN)
+#define PIN_HP_AMP		(AC_PINCTL_HP_EN)
 
 /*
  * get widget capabilities
@@ -418,4 +421,13 @@
 				 hda_nid_t nid);
 #endif /* CONFIG_SND_HDA_POWER_SAVE */
 
+/*
+ * AMP control callbacks
+ */
+/* retrieve parameters from private_value */
+#define get_amp_nid(kc)		((kc)->private_value & 0xffff)
+#define get_amp_channels(kc)	(((kc)->private_value >> 16) & 0x3)
+#define get_amp_direction(kc)	(((kc)->private_value >> 18) & 0x1)
+#define get_amp_index(kc)	(((kc)->private_value >> 19) & 0xf)
+
 #endif /* __SOUND_HDA_LOCAL_H */
diff --git a/sound/pci/hda/hda_patch.h b/sound/pci/hda/hda_patch.h
index 2fdf235..dfbcfa8 100644
--- a/sound/pci/hda/hda_patch.h
+++ b/sound/pci/hda/hda_patch.h
@@ -18,3 +18,5 @@
 extern struct hda_codec_preset snd_hda_preset_conexant[];
 /* VIA codecs */
 extern struct hda_codec_preset snd_hda_preset_via[];
+/* NVIDIA HDMI codecs */
+extern struct hda_codec_preset snd_hda_preset_nvhdmi[];
diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c
index 1e5aff5..743d779 100644
--- a/sound/pci/hda/hda_proc.c
+++ b/sound/pci/hda/hda_proc.c
@@ -216,7 +216,7 @@
 	unsigned int caps, val;
 
 	caps = snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP);
-	snd_iprintf(buffer, "  Pincap 0x08%x:", caps);
+	snd_iprintf(buffer, "  Pincap 0x%08x:", caps);
 	if (caps & AC_PINCAP_IN)
 		snd_iprintf(buffer, " IN");
 	if (caps & AC_PINCAP_OUT)
@@ -229,8 +229,13 @@
 		snd_iprintf(buffer, " Detect");
 	if (caps & AC_PINCAP_BALANCE)
 		snd_iprintf(buffer, " Balanced");
-	if (caps & AC_PINCAP_LR_SWAP)
-		snd_iprintf(buffer, " R/L");
+	if (caps & AC_PINCAP_HDMI) {
+		/* Realtek uses this bit as a different meaning */
+		if ((codec->vendor_id >> 16) == 0x10ec)
+			snd_iprintf(buffer, " R/L");
+		else
+			snd_iprintf(buffer, " HDMI");
+	}
 	if (caps & AC_PINCAP_TRIG_REQ)
 		snd_iprintf(buffer, " Trigger");
 	if (caps & AC_PINCAP_IMP_SENSE)
@@ -552,9 +557,15 @@
 
 		snd_iprintf(buffer, "Node 0x%02x [%s] wcaps 0x%x:", nid,
 			    get_wid_type_name(wid_type), wid_caps);
-		if (wid_caps & AC_WCAP_STEREO)
-			snd_iprintf(buffer, " Stereo");
-		else
+		if (wid_caps & AC_WCAP_STEREO) {
+			unsigned int chans;
+			chans = (wid_caps & AC_WCAP_CHAN_CNT_EXT) >> 13;
+			chans = ((chans << 1) | 1) + 1;
+			if (chans == 2)
+				snd_iprintf(buffer, " Stereo");
+			else
+				snd_iprintf(buffer, " %d-Channels", chans);
+		} else
 			snd_iprintf(buffer, " Mono");
 		if (wid_caps & AC_WCAP_DIGITAL)
 			snd_iprintf(buffer, " Digital");
@@ -566,6 +577,8 @@
 			snd_iprintf(buffer, " Stripe");
 		if (wid_caps & AC_WCAP_LR_SWAP)
 			snd_iprintf(buffer, " R/L");
+		if (wid_caps & AC_WCAP_CP_CAPS)
+			snd_iprintf(buffer, " CP");
 		snd_iprintf(buffer, "\n");
 
 		/* volume knob is a special widget that always have connection
diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c
index e8003d9..2b00c4a 100644
--- a/sound/pci/hda/patch_analog.c
+++ b/sound/pci/hda/patch_analog.c
@@ -1826,9 +1826,14 @@
 	0x0c, 0x0d, 0x0e
 };
 
-#define AD1988_SPDIF_OUT	0x02
+#define AD1988_SPDIF_OUT		0x02
+#define AD1988_SPDIF_OUT_HDMI	0x0b
 #define AD1988_SPDIF_IN		0x07
 
+static hda_nid_t ad1989b_slave_dig_outs[2] = {
+	AD1988_SPDIF_OUT, AD1988_SPDIF_OUT_HDMI
+};
+
 static struct hda_input_mux ad1988_6stack_capture_source = {
 	.num_items = 5,
 	.items = {
@@ -2143,6 +2148,7 @@
 
 static struct snd_kcontrol_new ad1989_spdif_out_mixers[] = {
 	HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME("HDMI Playback Volume", 0x1d, 0x0, HDA_OUTPUT),
 	{ } /* end */
 };
 
@@ -2207,6 +2213,8 @@
 	{0x34, AC_VERB_SET_CONNECT_SEL, 0x0},
 	/* Analog CD Input */
 	{0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+	/* Analog Mix output amp */
+	{0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x1f}, /* 0dB */
 
 	{ }
 };
@@ -2247,8 +2255,12 @@
 
 /* AD1989 has no ADC -> SPDIF route */
 static struct hda_verb ad1989_spdif_init_verbs[] = {
-	/* SPDIF out pin */
+	/* SPDIF-1 out pin */
+	{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
 	{0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */
+	/* SPDIF-2/HDMI out pin */
+	{0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+	{0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */
 	{ }
 };
 
@@ -2336,6 +2348,8 @@
 	{0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
 	{0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
 	{0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+	/* Analog Mix output amp */
+	{0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x1f}, /* 0dB */
 	{ }
 };
 
@@ -2409,6 +2423,8 @@
 	{0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
 	{0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
 	{0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+	/* Analog Mix output amp */
+	{0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x1f}, /* 0dB */
 	{ }
 };
 
@@ -2868,6 +2884,7 @@
 	SND_PCI_QUIRK(0x1043, 0x81ec, "Asus P5B-DLX", AD1988_6STACK_DIG),
 	SND_PCI_QUIRK(0x1043, 0x81f6, "Asus M2N-SLI", AD1988_6STACK_DIG),
 	SND_PCI_QUIRK(0x1043, 0x8277, "Asus P5K-E/WIFI-AP", AD1988_6STACK_DIG),
+	SND_PCI_QUIRK(0x1043, 0x8311, "Asus P5Q-Premium/Pro", AD1988_6STACK_DIG),
 	{}
 };
 
@@ -2975,6 +2992,7 @@
 				ad1989_spdif_out_mixers;
 			spec->init_verbs[spec->num_init_verbs++] =
 				ad1989_spdif_init_verbs;
+			codec->slave_dig_outs = ad1989b_slave_dig_outs;
 		} else {
 			spec->mixers[spec->num_mixers++] =
 				ad1988_spdif_out_mixers;
@@ -3911,7 +3929,7 @@
 
 
 /*
- * AD1882
+ * AD1882 / AD1882A
  *
  * port-A - front hp-out
  * port-B - front mic-in
@@ -3948,6 +3966,18 @@
 	},
 };
 
+/* list: 0x11, 0x39, 0x3a, 0x3c, 0x18, 0x1f, 0x12, 0x20 */
+static struct hda_input_mux ad1882a_capture_source = {
+	.num_items = 5,
+	.items = {
+		{ "Front Mic", 0x1 },
+		{ "Mic", 0x4},
+		{ "Line", 0x2 },
+		{ "Digital Mic", 0x06 },
+		{ "Mix", 0x7 },
+	},
+};
+
 static struct snd_kcontrol_new ad1882_base_mixers[] = {
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
@@ -3957,16 +3987,7 @@
 	HDA_CODEC_MUTE("Front Playback Switch", 0x12, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x13, 1, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x13, 1, 0x0, HDA_OUTPUT),
-	HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
-	HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
-	HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x01, HDA_INPUT),
-	HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x01, HDA_INPUT),
-	HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x04, HDA_INPUT),
-	HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x04, HDA_INPUT),
-	HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x06, HDA_INPUT),
-	HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x06, HDA_INPUT),
-	HDA_CODEC_VOLUME("Beep Playback Volume", 0x20, 0x07, HDA_INPUT),
-	HDA_CODEC_MUTE("Beep Playback Switch", 0x20, 0x07, HDA_INPUT),
+
 	HDA_CODEC_VOLUME("Mic Boost", 0x3c, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Front Mic Boost", 0x39, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Line-In Boost", 0x3a, 0x0, HDA_OUTPUT),
@@ -3999,6 +4020,35 @@
 	{ } /* end */
 };
 
+static struct snd_kcontrol_new ad1882_loopback_mixers[] = {
+	HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
+	HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
+	HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x01, HDA_INPUT),
+	HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x01, HDA_INPUT),
+	HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x04, HDA_INPUT),
+	HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x04, HDA_INPUT),
+	HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x06, HDA_INPUT),
+	HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x06, HDA_INPUT),
+	HDA_CODEC_VOLUME("Beep Playback Volume", 0x20, 0x07, HDA_INPUT),
+	HDA_CODEC_MUTE("Beep Playback Switch", 0x20, 0x07, HDA_INPUT),
+	{ } /* end */
+};
+
+static struct snd_kcontrol_new ad1882a_loopback_mixers[] = {
+	HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
+	HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
+	HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x04, HDA_INPUT),
+	HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x04, HDA_INPUT),
+	HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x01, HDA_INPUT),
+	HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x01, HDA_INPUT),
+	HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x06, HDA_INPUT),
+	HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x06, HDA_INPUT),
+	HDA_CODEC_VOLUME("Beep Playback Volume", 0x20, 0x07, HDA_INPUT),
+	HDA_CODEC_MUTE("Beep Playback Switch", 0x20, 0x07, HDA_INPUT),
+	HDA_CODEC_VOLUME("Digital Mic Boost", 0x1f, 0x0, HDA_INPUT),
+	{ } /* end */
+};
+
 static struct snd_kcontrol_new ad1882_3stack_mixers[] = {
 	HDA_CODEC_MUTE("Surround Playback Switch", 0x15, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x17, 1, 0x0, HDA_OUTPUT),
@@ -4168,9 +4218,16 @@
 	spec->num_adc_nids = ARRAY_SIZE(ad1882_adc_nids);
 	spec->adc_nids = ad1882_adc_nids;
 	spec->capsrc_nids = ad1882_capsrc_nids;
-	spec->input_mux = &ad1882_capture_source;
-	spec->num_mixers = 1;
+	if (codec->vendor_id == 0x11d1882)
+		spec->input_mux = &ad1882_capture_source;
+	else
+		spec->input_mux = &ad1882a_capture_source;
+	spec->num_mixers = 2;
 	spec->mixers[0] = ad1882_base_mixers;
+	if (codec->vendor_id == 0x11d1882)
+		spec->mixers[1] = ad1882_loopback_mixers;
+	else
+		spec->mixers[1] = ad1882a_loopback_mixers;
 	spec->num_init_verbs = 1;
 	spec->init_verbs[0] = ad1882_init_verbs;
 	spec->spdif_route = 0;
@@ -4187,8 +4244,8 @@
 	switch (board_config) {
 	default:
 	case AD1882_3STACK:
-		spec->num_mixers = 2;
-		spec->mixers[1] = ad1882_3stack_mixers;
+		spec->num_mixers = 3;
+		spec->mixers[2] = ad1882_3stack_mixers;
 		spec->channel_mode = ad1882_modes;
 		spec->num_channel_mode = ARRAY_SIZE(ad1882_modes);
 		spec->need_dac_fix = 1;
@@ -4196,8 +4253,8 @@
 		spec->multiout.num_dacs = 1;
 		break;
 	case AD1882_6STACK:
-		spec->num_mixers = 2;
-		spec->mixers[1] = ad1882_6stack_mixers;
+		spec->num_mixers = 3;
+		spec->mixers[2] = ad1882_6stack_mixers;
 		break;
 	}
 	return 0;
@@ -4220,6 +4277,7 @@
 	{ .id = 0x11d41986, .name = "AD1986A", .patch = patch_ad1986a },
 	{ .id = 0x11d41988, .name = "AD1988", .patch = patch_ad1988 },
 	{ .id = 0x11d4198b, .name = "AD1988B", .patch = patch_ad1988 },
+	{ .id = 0x11d4882a, .name = "AD1882A", .patch = patch_ad1882 },
 	{ .id = 0x11d4989a, .name = "AD1989A", .patch = patch_ad1988 },
 	{ .id = 0x11d4989b, .name = "AD1989B", .patch = patch_ad1988 },
 	{} /* terminator */
diff --git a/sound/pci/hda/patch_atihdmi.c b/sound/pci/hda/patch_atihdmi.c
index 1227250..ba61575 100644
--- a/sound/pci/hda/patch_atihdmi.c
+++ b/sound/pci/hda/patch_atihdmi.c
@@ -35,6 +35,9 @@
 	struct hda_pcm pcm_rec;
 };
 
+#define CVT_NID		0x02	/* audio converter */
+#define PIN_NID		0x03	/* HDMI output pin */
+
 static struct hda_verb atihdmi_basic_init[] = {
 	/* enable digital output on pin widget */
 	{ 0x03, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
@@ -60,8 +63,9 @@
 {
 	snd_hda_sequence_write(codec, atihdmi_basic_init);
 	/* SI codec requires to unmute the pin */
-	if (get_wcaps(codec, 0x03) & AC_WCAP_OUT_AMP)
-		snd_hda_codec_write(codec, 0x03, 0, AC_VERB_SET_AMP_GAIN_MUTE,
+	if (get_wcaps(codec, PIN_NID) & AC_WCAP_OUT_AMP)
+		snd_hda_codec_write(codec, PIN_NID, 0,
+				    AC_VERB_SET_AMP_GAIN_MUTE,
 				    AMP_OUT_UNMUTE);
 	return 0;
 }
@@ -92,15 +96,29 @@
 					    struct snd_pcm_substream *substream)
 {
 	struct atihdmi_spec *spec = codec->spec;
-	return snd_hda_multi_out_dig_prepare(codec, &spec->multiout, stream_tag,
-					     format, substream);
+	int chans = substream->runtime->channels;
+	int i, err;
+
+	err = snd_hda_multi_out_dig_prepare(codec, &spec->multiout, stream_tag,
+					    format, substream);
+	if (err < 0)
+		return err;
+	snd_hda_codec_write(codec, CVT_NID, 0, AC_VERB_SET_CVT_CHAN_COUNT,
+			    chans - 1);
+	/* FIXME: XXX */
+	for (i = 0; i < chans; i++) {
+		snd_hda_codec_write(codec, CVT_NID, 0,
+				    AC_VERB_SET_HDMI_CHAN_SLOT,
+				    (i << 4) | i);
+	}
+	return 0;
 }
 
 static struct hda_pcm_stream atihdmi_pcm_digital_playback = {
 	.substreams = 1,
 	.channels_min = 2,
 	.channels_max = 2,
-	.nid = 0x2, /* NID to query formats and rates and setup streams */
+	.nid = CVT_NID, /* NID to query formats and rates and setup streams */
 	.ops = {
 		.open = atihdmi_dig_playback_pcm_open,
 		.close = atihdmi_dig_playback_pcm_close,
@@ -112,6 +130,7 @@
 {
 	struct atihdmi_spec *spec = codec->spec;
 	struct hda_pcm *info = &spec->pcm_rec;
+	unsigned int chans;
 
 	codec->num_pcms = 1;
 	codec->pcm_info = info;
@@ -120,6 +139,13 @@
 	info->pcm_type = HDA_PCM_TYPE_HDMI;
 	info->stream[SNDRV_PCM_STREAM_PLAYBACK] = atihdmi_pcm_digital_playback;
 
+	/* FIXME: we must check ELD and change the PCM parameters dynamically
+	 */
+	chans = get_wcaps(codec, CVT_NID);
+	chans = (chans & AC_WCAP_CHAN_CNT_EXT) >> 13;
+	chans = ((chans << 1) | 1) + 1;
+	info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = chans;
+
 	return 0;
 }
 
@@ -147,9 +173,11 @@
 
 	spec->multiout.num_dacs = 0;	  /* no analog */
 	spec->multiout.max_channels = 2;
-	spec->multiout.dig_out_nid = 0x2; /* NID for copying analog to digital,
-					   * seems to be unused in pure-digital
-					   * case. */
+	/* NID for copying analog to digital,
+	 * seems to be unused in pure-digital
+	 * case.
+	 */
+	spec->multiout.dig_out_nid = CVT_NID;
 
 	codec->patch_ops = atihdmi_patch_ops;
 
@@ -164,6 +192,7 @@
 	{ .id = 0x10027919, .name = "ATI RS600 HDMI", .patch = patch_atihdmi },
 	{ .id = 0x1002791a, .name = "ATI RS690/780 HDMI", .patch = patch_atihdmi },
 	{ .id = 0x1002aa01, .name = "ATI R6xx HDMI", .patch = patch_atihdmi },
+	{ .id = 0x10951390, .name = "SiI1390 HDMI", .patch = patch_atihdmi },
 	{ .id = 0x10951392, .name = "SiI1392 HDMI", .patch = patch_atihdmi },
 	{ .id = 0x17e80047, .name = "Chrontel HDMI",  .patch = patch_atihdmi },
 	{} /* terminator */
diff --git a/sound/pci/hda/patch_nvhdmi.c b/sound/pci/hda/patch_nvhdmi.c
new file mode 100644
index 0000000..1a65775
--- /dev/null
+++ b/sound/pci/hda/patch_nvhdmi.c
@@ -0,0 +1,164 @@
+/*
+ * Universal Interface for Intel High Definition Audio Codec
+ *
+ * HD audio interface patch for NVIDIA HDMI codecs
+ *
+ * Copyright (c) 2008 NVIDIA Corp.  All rights reserved.
+ * Copyright (c) 2008 Wei Ni <wni@nvidia.com>
+ *
+ *
+ *  This driver is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This driver is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include "hda_codec.h"
+#include "hda_local.h"
+
+struct nvhdmi_spec {
+	struct hda_multi_out multiout;
+
+	struct hda_pcm pcm_rec;
+};
+
+static struct hda_verb nvhdmi_basic_init[] = {
+	/* enable digital output on pin widget */
+	{ 0x05, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+	{} /* terminator */
+};
+
+/*
+ * Controls
+ */
+static int nvhdmi_build_controls(struct hda_codec *codec)
+{
+	struct nvhdmi_spec *spec = codec->spec;
+	int err;
+
+	err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid);
+	if (err < 0)
+		return err;
+
+	return 0;
+}
+
+static int nvhdmi_init(struct hda_codec *codec)
+{
+	snd_hda_sequence_write(codec, nvhdmi_basic_init);
+	return 0;
+}
+
+/*
+ * Digital out
+ */
+static int nvhdmi_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
+				     struct hda_codec *codec,
+				     struct snd_pcm_substream *substream)
+{
+	struct nvhdmi_spec *spec = codec->spec;
+	return snd_hda_multi_out_dig_open(codec, &spec->multiout);
+}
+
+static int nvhdmi_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
+				      struct hda_codec *codec,
+				      struct snd_pcm_substream *substream)
+{
+	struct nvhdmi_spec *spec = codec->spec;
+	return snd_hda_multi_out_dig_close(codec, &spec->multiout);
+}
+
+static int nvhdmi_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
+					    struct hda_codec *codec,
+					    unsigned int stream_tag,
+					    unsigned int format,
+					    struct snd_pcm_substream *substream)
+{
+	struct nvhdmi_spec *spec = codec->spec;
+	return snd_hda_multi_out_dig_prepare(codec, &spec->multiout, stream_tag,
+					     format, substream);
+}
+
+static struct hda_pcm_stream nvhdmi_pcm_digital_playback = {
+	.substreams = 1,
+	.channels_min = 2,
+	.channels_max = 2,
+	.nid = 0x4, /* NID to query formats and rates and setup streams */
+	.rates = SNDRV_PCM_RATE_48000,
+	.maxbps = 16,
+	.formats = SNDRV_PCM_FMTBIT_S16_LE,
+	.ops = {
+		.open = nvhdmi_dig_playback_pcm_open,
+		.close = nvhdmi_dig_playback_pcm_close,
+		.prepare = nvhdmi_dig_playback_pcm_prepare
+	},
+};
+
+static int nvhdmi_build_pcms(struct hda_codec *codec)
+{
+	struct nvhdmi_spec *spec = codec->spec;
+	struct hda_pcm *info = &spec->pcm_rec;
+
+	codec->num_pcms = 1;
+	codec->pcm_info = info;
+
+	info->name = "NVIDIA HDMI";
+	info->stream[SNDRV_PCM_STREAM_PLAYBACK] = nvhdmi_pcm_digital_playback;
+
+	return 0;
+}
+
+static void nvhdmi_free(struct hda_codec *codec)
+{
+	kfree(codec->spec);
+}
+
+static struct hda_codec_ops nvhdmi_patch_ops = {
+	.build_controls = nvhdmi_build_controls,
+	.build_pcms = nvhdmi_build_pcms,
+	.init = nvhdmi_init,
+	.free = nvhdmi_free,
+};
+
+static int patch_nvhdmi(struct hda_codec *codec)
+{
+	struct nvhdmi_spec *spec;
+
+	spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+	if (spec == NULL)
+		return -ENOMEM;
+
+	codec->spec = spec;
+
+	spec->multiout.num_dacs = 0;	  /* no analog */
+	spec->multiout.max_channels = 2;
+	spec->multiout.dig_out_nid = 0x4; /* NID for copying analog to digital,
+					   * seems to be unused in pure-digital
+					   * case. */
+
+	codec->patch_ops = nvhdmi_patch_ops;
+
+	return 0;
+}
+
+/*
+ * patch entries
+ */
+struct hda_codec_preset snd_hda_preset_nvhdmi[] = {
+	{ .id = 0x10de0002, .name = "NVIDIA MCP78 HDMI", .patch = patch_nvhdmi },
+	{ .id = 0x10de0007, .name = "NVIDIA MCP7A HDMI", .patch = patch_nvhdmi },
+	{} /* terminator */
+};
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index 6602516..0b6e682 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -72,6 +72,7 @@
 enum {
 	ALC260_BASIC,
 	ALC260_HP,
+	ALC260_HP_DC7600,
 	ALC260_HP_3013,
 	ALC260_FUJITSU_S702X,
 	ALC260_ACER,
@@ -100,6 +101,9 @@
 	ALC262_BENQ_T31,
 	ALC262_ULTRA,
 	ALC262_LENOVO_3000,
+	ALC262_NEC,
+	ALC262_TOSHIBA_S06,
+	ALC262_TOSHIBA_RX1,
 	ALC262_AUTO,
 	ALC262_MODEL_LAST /* last tag */
 };
@@ -110,6 +114,7 @@
 	ALC268_3ST,
 	ALC268_TOSHIBA,
 	ALC268_ACER,
+	ALC268_ACER_ASPIRE_ONE,
 	ALC268_DELL,
 	ALC268_ZEPTO,
 #ifdef CONFIG_SND_DEBUG
@@ -122,6 +127,7 @@
 /* ALC269 models */
 enum {
 	ALC269_BASIC,
+	ALC269_QUANTA_FL1,
 	ALC269_ASUS_EEEPC_P703,
 	ALC269_ASUS_EEEPC_P901,
 	ALC269_AUTO,
@@ -169,6 +175,13 @@
 	ALC663_ASUS_G71V,
 	ALC663_ASUS_H13,
 	ALC663_ASUS_G50V,
+	ALC662_ECS,
+	ALC663_ASUS_MODE1,
+	ALC662_ASUS_MODE2,
+	ALC663_ASUS_MODE3,
+	ALC663_ASUS_MODE4,
+	ALC663_ASUS_MODE5,
+	ALC663_ASUS_MODE6,
 	ALC662_AUTO,
 	ALC662_MODEL_LAST,
 };
@@ -200,18 +213,21 @@
 	ALC883_ACER,
 	ALC883_ACER_ASPIRE,
 	ALC883_MEDION,
-	ALC883_MEDION_MD2,	
+	ALC883_MEDION_MD2,
 	ALC883_LAPTOP_EAPD,
 	ALC883_LENOVO_101E_2ch,
 	ALC883_LENOVO_NB0763,
 	ALC888_LENOVO_MS7195_DIG,
-	ALC883_HAIER_W66,		
+	ALC888_LENOVO_SKY,
+	ALC883_HAIER_W66,
 	ALC888_3ST_HP,
 	ALC888_6ST_DELL,
 	ALC883_MITAC,
 	ALC883_CLEVO_M720,
 	ALC883_FUJITSU_PI2515,
 	ALC883_3ST_6ch_INTEL,
+	ALC888_ASUS_M90V,
+	ALC888_ASUS_EEE1601,
 	ALC883_AUTO,
 	ALC883_MODEL_LAST,
 };
@@ -398,7 +414,7 @@
 
 /*
  * Control the mode of pin widget settings via the mixer.  "pc" is used
- * instead of "%" to avoid consequences of accidently treating the % as 
+ * instead of "%" to avoid consequences of accidently treating the % as
  * being part of a format specifier.  Maximum allowed length of a value is
  * 63 characters plus NULL terminator.
  *
@@ -429,7 +445,7 @@
 #define ALC_PIN_DIR_IN_NOMICBIAS    0x03
 #define ALC_PIN_DIR_INOUT_NOMICBIAS 0x04
 
-/* Info about the pin modes supported by the different pin direction modes. 
+/* Info about the pin modes supported by the different pin direction modes.
  * For each direction the minimum and maximum values are given.
  */
 static signed char alc_pin_mode_dir_info[5][2] = {
@@ -502,7 +518,7 @@
 					  AC_VERB_SET_PIN_WIDGET_CONTROL,
 					  alc_pin_mode_values[val]);
 
-		/* Also enable the retasking pin's input/output as required 
+		/* Also enable the retasking pin's input/output as required
 		 * for the requested pin mode.  Enum values of 2 or less are
 		 * input modes.
 		 *
@@ -707,7 +723,7 @@
 	     i++)
 		spec->init_verbs[spec->num_init_verbs++] =
 			preset->init_verbs[i];
-	
+
 	spec->channel_mode = preset->channel_mode;
 	spec->num_channel_mode = preset->num_channel_mode;
 	spec->need_dac_fix = preset->need_dac_fix;
@@ -718,7 +734,7 @@
 	spec->multiout.dac_nids = preset->dac_nids;
 	spec->multiout.dig_out_nid = preset->dig_out_nid;
 	spec->multiout.hp_nid = preset->hp_nid;
-	
+
 	spec->num_mux_defs = preset->num_mux_defs;
 	if (!spec->num_mux_defs)
 		spec->num_mux_defs = 1;
@@ -855,7 +871,7 @@
 	if ((ass != codec->bus->pci->subsystem_device) && (ass & 1))
 		goto do_sku;
 
-	/*	
+	/*
 	 * 31~30	: port conetcivity
 	 * 29~21	: reserve
 	 * 20		: PCBEEP input
@@ -946,7 +962,7 @@
 			tmp = snd_hda_codec_read(codec, 0x20, 0,
 						 AC_VERB_GET_PROC_COEF, 0);
 			snd_hda_codec_write(codec, 0x20, 0,
-					    AC_VERB_SET_COEF_INDEX, 7);	
+					    AC_VERB_SET_COEF_INDEX, 7);
 			snd_hda_codec_write(codec, 0x20, 0,
 					    AC_VERB_SET_PROC_COEF,
 					    tmp | 0x2010);
@@ -961,7 +977,7 @@
 			tmp = snd_hda_codec_read(codec, 0x20, 0,
 						 AC_VERB_GET_PROC_COEF, 0);
 			snd_hda_codec_write(codec, 0x20, 0,
-					    AC_VERB_SET_COEF_INDEX, 7);	
+					    AC_VERB_SET_COEF_INDEX, 7);
 			snd_hda_codec_write(codec, 0x20, 0,
 					    AC_VERB_SET_PROC_COEF,
 					    tmp | 0x3000);
@@ -970,7 +986,7 @@
 	default:
 		break;
 	}
-	
+
 	/* is laptop or Desktop and enable the function "Mute internal speaker
 	 * when the external headphone out jack is plugged"
 	 */
@@ -1006,6 +1022,7 @@
 	snd_hda_codec_write(codec, spec->autocfg.hp_pins[0], 0,
 			    AC_VERB_SET_UNSOLICITED_ENABLE,
 			    AC_USRSP_EN | ALC880_HP_EVENT);
+
 	spec->unsol_event = alc_sku_unsol_event;
 }
 
@@ -1296,7 +1313,7 @@
  *
  * The system also has a pair of internal speakers, and a headphone jack.
  * These are both connected to Line2 on the codec, hence to DAC 02.
- * 
+ *
  * There is a variable resistor to control the speaker or headphone
  * volume. This is a hardware-only device without a software API.
  *
@@ -1824,7 +1841,7 @@
 	{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
 	{0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
 	{0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-	
+
 	{ }
 };
 
@@ -1869,7 +1886,7 @@
 
 /*
 * Uniwill P53
-* HP = 0x14, InternalSpeaker = 0x15, mic = 0x19, 
+* HP = 0x14, InternalSpeaker = 0x15, mic = 0x19,
  */
 static struct hda_verb alc880_uniwill_p53_init_verbs[] = {
 	{0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
@@ -1968,7 +1985,7 @@
 static void alc880_uniwill_p53_dcvol_automute(struct hda_codec *codec)
 {
 	unsigned int present;
-	
+
 	present = snd_hda_codec_read(codec, 0x21, 0,
 				     AC_VERB_GET_VOLUME_KNOB_CONTROL, 0);
 	present &= HDA_AMP_VOLMASK;
@@ -2050,7 +2067,7 @@
 	{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
 	{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
 	{0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-	
+
 	{ }
 };
 
@@ -2632,12 +2649,14 @@
 
 	info->name = spec->stream_name_analog;
 	if (spec->stream_analog_playback) {
-		snd_assert(spec->multiout.dac_nids, return -EINVAL);
+		if (snd_BUG_ON(!spec->multiout.dac_nids))
+			return -EINVAL;
 		info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *(spec->stream_analog_playback);
 		info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0];
 	}
 	if (spec->stream_analog_capture) {
-		snd_assert(spec->adc_nids, return -EINVAL);
+		if (snd_BUG_ON(!spec->adc_nids))
+			return -EINVAL;
 		info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_analog_capture);
 		info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
 	}
@@ -2667,6 +2686,8 @@
 			info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_digital_capture);
 			info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid;
 		}
+		/* FIXME: do we need this for all Realtek codec models? */
+		codec->spdif_status_reset = 1;
 	}
 
 	/* If the use of more than one ADC is requested for the current
@@ -3683,7 +3704,7 @@
 {
 	struct alc_spec *spec = codec->spec;
 	int i;
-	
+
 	alc_subsystem_id(codec, 0x15, 0x1b, 0x14);
 	for (i = 0; i < spec->autocfg.line_outs; i++) {
 		hda_nid_t nid = spec->autocfg.line_out_pins[i];
@@ -4124,6 +4145,33 @@
 	{ } /* end */
 };
 
+static struct hda_bind_ctls alc260_dc7600_bind_master_vol = {
+	.ops = &snd_hda_bind_vol,
+	.values = {
+		HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_OUTPUT),
+		HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_OUTPUT),
+		HDA_COMPOSE_AMP_VAL(0x0a, 3, 0, HDA_OUTPUT),
+		0
+	},
+};
+
+static struct hda_bind_ctls alc260_dc7600_bind_switch = {
+	.ops = &snd_hda_bind_sw,
+	.values = {
+		HDA_COMPOSE_AMP_VAL(0x11, 3, 0, HDA_OUTPUT),
+		HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
+		0
+	},
+};
+
+static struct snd_kcontrol_new alc260_hp_dc7600_mixer[] = {
+	HDA_BIND_VOL("Master Playback Volume", &alc260_dc7600_bind_master_vol),
+	HDA_BIND_SW("LineOut Playback Switch", &alc260_dc7600_bind_switch),
+	HDA_CODEC_MUTE("Speaker Playback Switch", 0x0f, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Headphone Playback Switch", 0x10, 0x0, HDA_OUTPUT),
+	{ } /* end */
+};
+
 static struct hda_verb alc260_hp_3013_unsol_verbs[] = {
 	{0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
 	{},
@@ -4147,7 +4195,30 @@
 		alc260_hp_3013_automute(codec);
 }
 
-/* Fujitsu S702x series laptops.  ALC260 pin usage: Mic/Line jack = 0x12, 
+static void alc260_hp_3012_automute(struct hda_codec *codec)
+{
+	unsigned int present, bits;
+
+	present = snd_hda_codec_read(codec, 0x10, 0,
+			AC_VERB_GET_PIN_SENSE, 0) & AC_PINSENSE_PRESENCE;
+
+	bits = present ? 0 : PIN_OUT;
+	snd_hda_codec_write(codec, 0x0f, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
+			    bits);
+	snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
+			    bits);
+	snd_hda_codec_write(codec, 0x15, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
+			    bits);
+}
+
+static void alc260_hp_3012_unsol_event(struct hda_codec *codec,
+				       unsigned int res)
+{
+	if ((res >> 26) == ALC880_HP_EVENT)
+		alc260_hp_3012_automute(codec);
+}
+
+/* Fujitsu S702x series laptops.  ALC260 pin usage: Mic/Line jack = 0x12,
  * HP jack = 0x14, CD audio =  0x16, internal speaker = 0x10.
  */
 static struct snd_kcontrol_new alc260_fujitsu_mixer[] = {
@@ -4478,7 +4549,7 @@
 	{0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
 	{0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
 
-	/* Ensure Line1 pin widget takes its input from the OUT1 sum bus 
+	/* Ensure Line1 pin widget takes its input from the OUT1 sum bus
 	 * when acting as an output.
 	 */
 	{0x0d, AC_VERB_SET_CONNECT_SEL, 0},
@@ -4503,14 +4574,14 @@
 	 * stage.
 	 */
 	{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-	/* Unmute input buffer of pin widget used for Line-in (no equiv 
+	/* Unmute input buffer of pin widget used for Line-in (no equiv
 	 * mixer ctrl)
 	 */
 	{0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 
 	/* Mute capture amp left and right */
 	{0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-	/* Set ADC connection select to match default mixer setting - line 
+	/* Set ADC connection select to match default mixer setting - line
 	 * in (on mic1 pin)
 	 */
 	{0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
@@ -4564,7 +4635,7 @@
 	{0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
 	{0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
 
-	/* Ensure Mic1 and Line1 pin widgets take input from the OUT1 sum 
+	/* Ensure Mic1 and Line1 pin widgets take input from the OUT1 sum
 	 * bus when acting as outputs.
 	 */
 	{0x0b, AC_VERB_SET_CONNECT_SEL, 0},
@@ -4675,6 +4746,20 @@
                 alc260_replacer_672v_automute(codec);
 }
 
+static struct hda_verb alc260_hp_dc7600_verbs[] = {
+	{0x05, AC_VERB_SET_CONNECT_SEL, 0x01},
+	{0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
+	{0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+	{0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+	{0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+	{0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+	{0x10, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
+	{0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
+	{0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
+	{}
+};
+
 /* Test configuration for debugging, modelled after the ALC880 test
  * configuration.
  */
@@ -4686,7 +4771,7 @@
 	0x04, 0x05,
 };
 /* For testing the ALC260, each input MUX needs its own definition since
- * the signal assignments are different.  This assumes that the first ADC 
+ * the signal assignments are different.  This assumes that the first ADC
  * is NID 0x04.
  */
 static struct hda_input_mux alc260_test_capture_sources[2] = {
@@ -4769,7 +4854,7 @@
 
 	/* Switches to allow the digital IO pins to be enabled.  The datasheet
 	 * is ambigious as to which NID is which; testing on laptops which
-	 * make this output available should provide clarification. 
+	 * make this output available should provide clarification.
 	 */
 	ALC_SPDIF_CTRL_SWITCH("SPDIF Playback Switch", 0x03, 0x01),
 	ALC_SPDIF_CTRL_SWITCH("SPDIF Capture Switch", 0x06, 0x01),
@@ -4805,7 +4890,7 @@
 	{0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
 	{0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
 
-	/* Ensure mic1, mic2, line1 and line2 pin widgets take input from the 
+	/* Ensure mic1, mic2, line1 and line2 pin widgets take input from the
 	 * OUT1 sum bus when acting as an output.
 	 */
 	{0x0b, AC_VERB_SET_CONNECT_SEL, 0},
@@ -4897,7 +4982,7 @@
 		sw_val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
 	} else
 		return 0; /* N/A */
-	
+
 	snprintf(name, sizeof(name), "%s Playback Volume", pfx);
 	err = add_control(spec, ALC_CTL_WIDGET_VOL, name, vol_val);
 	if (err < 0)
@@ -5003,7 +5088,7 @@
 		int pin_type = get_pin_type(spec->autocfg.line_out_type);
 		alc260_auto_set_output_and_unmute(codec, nid, pin_type, 0);
 	}
-	
+
 	nid = spec->autocfg.speaker_pins[0];
 	if (nid)
 		alc260_auto_set_output_and_unmute(codec, nid, PIN_OUT, 0);
@@ -5045,7 +5130,7 @@
 	{0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 	{0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
 	{0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-	
+
 	/* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
 	 * mixer widget
 	 * Note: PASD motherboards uses the Line In 2 as the input for
@@ -5074,7 +5159,7 @@
 	{0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
 	{0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 	{0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-	
+
 	{ }
 };
 
@@ -5155,6 +5240,7 @@
 	[ALC260_BASIC]		= "basic",
 	[ALC260_HP]		= "hp",
 	[ALC260_HP_3013]	= "hp-3013",
+	[ALC260_HP_DC7600]	= "hp-dc7600",
 	[ALC260_FUJITSU_S702X]	= "fujitsu",
 	[ALC260_ACER]		= "acer",
 	[ALC260_WILL]		= "will",
@@ -5172,7 +5258,7 @@
 	SND_PCI_QUIRK(0x103c, 0x280a, "HP d5750", ALC260_HP_3013),
 	SND_PCI_QUIRK(0x103c, 0x3010, "HP", ALC260_HP_3013),
 	SND_PCI_QUIRK(0x103c, 0x3011, "HP", ALC260_HP_3013),
-	SND_PCI_QUIRK(0x103c, 0x3012, "HP", ALC260_HP_3013),
+	SND_PCI_QUIRK(0x103c, 0x3012, "HP", ALC260_HP_DC7600),
 	SND_PCI_QUIRK(0x103c, 0x3013, "HP", ALC260_HP_3013),
 	SND_PCI_QUIRK(0x103c, 0x3014, "HP", ALC260_HP),
 	SND_PCI_QUIRK(0x103c, 0x3015, "HP", ALC260_HP),
@@ -5218,6 +5304,22 @@
 		.unsol_event = alc260_hp_unsol_event,
 		.init_hook = alc260_hp_automute,
 	},
+	[ALC260_HP_DC7600] = {
+		.mixers = { alc260_hp_dc7600_mixer,
+			    alc260_input_mixer,
+			    alc260_capture_alt_mixer },
+		.init_verbs = { alc260_init_verbs,
+				alc260_hp_dc7600_verbs },
+		.num_dacs = ARRAY_SIZE(alc260_dac_nids),
+		.dac_nids = alc260_dac_nids,
+		.num_adc_nids = ARRAY_SIZE(alc260_hp_adc_nids),
+		.adc_nids = alc260_hp_adc_nids,
+		.num_channel_mode = ARRAY_SIZE(alc260_modes),
+		.channel_mode = alc260_modes,
+		.input_mux = &alc260_capture_source,
+		.unsol_event = alc260_hp_3012_unsol_event,
+		.init_hook = alc260_hp_3012_automute,
+	},
 	[ALC260_HP_3013] = {
 		.mixers = { alc260_hp_3013_mixer,
 			    alc260_input_mixer,
@@ -5933,7 +6035,7 @@
 
 	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
 	{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-	
+
 	{0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
 	{0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
 	{0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
@@ -5949,7 +6051,7 @@
 static void alc882_targa_automute(struct hda_codec *codec)
 {
  	unsigned int present;
- 
+
  	present = snd_hda_codec_read(codec, 0x14, 0,
 				     AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
 	snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
@@ -5975,7 +6077,7 @@
 	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
 	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
 	{0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-	
+
 	{0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
 	{0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
 	{0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
@@ -5993,7 +6095,7 @@
 	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
 	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
 	{0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-        
+
 	{0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
 	{0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
 	{0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
@@ -6319,7 +6421,7 @@
 		.channel_mode = alc882_3ST_6ch_modes,
 		.need_dac_fix = 1,
 		.input_mux = &alc882_capture_source,
-	},	
+	},
 	[ALC882_ASUS_A7M] = {
 		.mixers = { alc882_asus_a7m_mixer, alc882_chmode_mixer },
 		.init_verbs = { alc882_init_verbs, alc882_eapd_verbs,
@@ -6332,14 +6434,14 @@
 		.channel_mode = alc880_threestack_modes,
 		.need_dac_fix = 1,
 		.input_mux = &alc882_capture_source,
-	},	
+	},
 };
 
 
 /*
  * Pin config fixes
  */
-enum { 
+enum {
 	PINFIX_ABIT_AW9D_MAX
 };
 
@@ -6554,16 +6656,19 @@
 			board_config = ALC885_MACPRO;
 			break;
 		case 0x106b1000: /* iMac 24 */
+		case 0x106b2800: /* AppleTV */
 			board_config = ALC885_IMAC24;
 			break;
 		case 0x106b00a1: /* Macbook (might be wrong - PCI SSID?) */
+		case 0x106b00a4: /* MacbookPro4,1 */
 		case 0x106b2c00: /* Macbook Pro rev3 */
 		case 0x106b3600: /* Macbook 3.1 */
 			board_config = ALC885_MBP3;
 			break;
 		default:
 			/* ALC889A is handled better as ALC888-compatible */
-			if (codec->revision_id == 0x100103) {
+			if (codec->revision_id == 0x100101 ||
+			    codec->revision_id == 0x100103) {
 				alc_free(codec);
 				return patch_alc883(codec);
 			}
@@ -6718,6 +6823,23 @@
 	},
 };
 
+static struct hda_input_mux alc883_lenovo_sky_capture_source = {
+	.num_items = 3,
+	.items = {
+		{ "Mic", 0x0 },
+		{ "Front Mic", 0x1 },
+		{ "Line", 0x4 },
+	},
+};
+
+static struct hda_input_mux alc883_asus_eee1601_capture_source = {
+	.num_items = 2,
+	.items = {
+		{ "Mic", 0x0 },
+		{ "Line", 0x2 },
+	},
+};
+
 #define alc883_mux_enum_info alc_mux_enum_info
 #define alc883_mux_enum_get alc_mux_enum_get
 /* ALC883 has the ALC882-type input selection */
@@ -7032,13 +7154,11 @@
 	HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
 	HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
 	HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
-	HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
-	HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		/* .name = "Capture Source", */
 		.name = "Input Source",
-		.count = 2,
+		.count = 1,
 		.info = alc883_mux_enum_info,
 		.get = alc883_mux_enum_get,
 		.put = alc883_mux_enum_put,
@@ -7256,7 +7376,7 @@
 		.put = alc883_mux_enum_put,
 	},
 	{ } /* end */
-};	
+};
 
 static struct snd_kcontrol_new alc883_acer_aspire_mixer[] = {
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
@@ -7283,6 +7403,87 @@
 	{ } /* end */
 };
 
+static struct snd_kcontrol_new alc888_lenovo_sky_mixer[] = {
+	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+	HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
+	HDA_CODEC_VOLUME("Surround Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
+	HDA_BIND_MUTE("Surround Playback Switch", 0x0e, 2, HDA_INPUT),
+	HDA_CODEC_VOLUME_MONO("Center Playback Volume",
+						0x0d, 1, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0d, 2, 0x0, HDA_OUTPUT),
+	HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0d, 1, 2, HDA_INPUT),
+	HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0d, 2, 2, HDA_INPUT),
+	HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
+	HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
+	HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("iSpeaker Playback Switch", 0x1a, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
+	HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
+	HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
+	HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
+	HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+	HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+	HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+	HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+	HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
+	HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
+	HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
+	HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
+	HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
+	HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		/* .name = "Capture Source", */
+		.name = "Input Source",
+		.count = 2,
+		.info = alc883_mux_enum_info,
+		.get = alc883_mux_enum_get,
+		.put = alc883_mux_enum_put,
+	},
+	{ } /* end */
+};
+
+static struct hda_bind_ctls alc883_bind_cap_vol = {
+	.ops = &snd_hda_bind_vol,
+	.values = {
+		HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT),
+		HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT),
+		0
+	},
+};
+
+static struct hda_bind_ctls alc883_bind_cap_switch = {
+	.ops = &snd_hda_bind_sw,
+	.values = {
+		HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT),
+		HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT),
+		0
+	},
+};
+
+static struct snd_kcontrol_new alc883_asus_eee1601_mixer[] = {
+	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+	HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
+	HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
+	HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
+	HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+	HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+	HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+	HDA_BIND_VOL("Capture Volume", &alc883_bind_cap_vol),
+	HDA_BIND_SW("Capture Switch", &alc883_bind_cap_switch),
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		/* .name = "Capture Source", */
+		.name = "Input Source",
+		.count = 1,
+		.info = alc883_mux_enum_info,
+		.get = alc883_mux_enum_get,
+		.put = alc883_mux_enum_put,
+	},
+	{ } /* end */
+};
+
 static struct snd_kcontrol_new alc883_chmode_mixer[] = {
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
@@ -7296,7 +7497,7 @@
 
 static struct hda_verb alc883_init_verbs[] = {
 	/* ADC1: mute amp left and right */
-	{0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+	{0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 	{0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
 	/* ADC2: mute amp left and right */
 	{0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
@@ -7361,14 +7562,14 @@
 	/* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
 	/* Input mixer2 */
 	{0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-	{0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-	{0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
-	{0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
+	{0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+	{0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
+	{0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
 	/* Input mixer3 */
 	{0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-	{0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-	{0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
-	{0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
+	{0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+	{0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
+	{0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
 	{ }
 };
 
@@ -7468,7 +7669,7 @@
 
 	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
 	{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-	
+
 	{0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
 	{0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
 	{0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
@@ -7518,6 +7719,18 @@
 	{ } /* end */
 };
 
+static struct hda_verb alc888_lenovo_sky_verbs[] = {
+	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+	{0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+	{0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+	{0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+	{0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+	{0x1a, AC_VERB_SET_CONNECT_SEL, 0x00},
+	{0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
+	{ } /* end */
+};
+
 static struct hda_verb alc888_3st_hp_verbs[] = {
 	{0x14, AC_VERB_SET_CONNECT_SEL, 0x00},	/* Front: output 0 (0x0c) */
 	{0x16, AC_VERB_SET_CONNECT_SEL, 0x01},	/* Rear : output 1 (0x0d) */
@@ -7555,7 +7768,7 @@
 static void alc888_lenovo_ms7195_front_automute(struct hda_codec *codec)
 {
  	unsigned int present;
- 
+
  	present = snd_hda_codec_read(codec, 0x1b, 0,
 				     AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
 	snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
@@ -7568,7 +7781,7 @@
 static void alc888_lenovo_ms7195_rca_automute(struct hda_codec *codec)
 {
  	unsigned int present;
- 
+
  	present = snd_hda_codec_read(codec, 0x14, 0,
 				     AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
 	snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
@@ -7598,7 +7811,7 @@
 static void alc883_medion_md2_automute(struct hda_codec *codec)
 {
  	unsigned int present;
- 
+
  	present = snd_hda_codec_read(codec, 0x14, 0,
 				     AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
 	snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
@@ -7753,7 +7966,7 @@
 static void alc883_acer_aspire_automute(struct hda_codec *codec)
 {
  	unsigned int present;
- 
+
  	present = snd_hda_codec_read(codec, 0x14, 0,
 				     AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
 	snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
@@ -7790,7 +8003,7 @@
 static void alc888_6st_dell_front_automute(struct hda_codec *codec)
 {
  	unsigned int present;
- 
+
  	present = snd_hda_codec_read(codec, 0x1b, 0,
 				AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
 	snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
@@ -7814,6 +8027,50 @@
 	}
 }
 
+static void alc888_lenovo_sky_front_automute(struct hda_codec *codec)
+{
+	unsigned int mute;
+	unsigned int present;
+
+	snd_hda_codec_read(codec, 0x1b, 0, AC_VERB_SET_PIN_SENSE, 0);
+	present = snd_hda_codec_read(codec, 0x1b, 0,
+				     AC_VERB_GET_PIN_SENSE, 0);
+	present = (present & 0x80000000) != 0;
+	if (present) {
+		/* mute internal speaker */
+		snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
+					 HDA_AMP_MUTE, HDA_AMP_MUTE);
+		snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
+					 HDA_AMP_MUTE, HDA_AMP_MUTE);
+		snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
+					 HDA_AMP_MUTE, HDA_AMP_MUTE);
+		snd_hda_codec_amp_stereo(codec, 0x17, HDA_OUTPUT, 0,
+					 HDA_AMP_MUTE, HDA_AMP_MUTE);
+		snd_hda_codec_amp_stereo(codec, 0x1a, HDA_OUTPUT, 0,
+					 HDA_AMP_MUTE, HDA_AMP_MUTE);
+	} else {
+		/* unmute internal speaker if necessary */
+		mute = snd_hda_codec_amp_read(codec, 0x1b, 0, HDA_OUTPUT, 0);
+		snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
+					 HDA_AMP_MUTE, mute);
+		snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
+					 HDA_AMP_MUTE, mute);
+		snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
+					 HDA_AMP_MUTE, mute);
+		snd_hda_codec_amp_stereo(codec, 0x17, HDA_OUTPUT, 0,
+					 HDA_AMP_MUTE, mute);
+		snd_hda_codec_amp_stereo(codec, 0x1a, HDA_OUTPUT, 0,
+					 HDA_AMP_MUTE, mute);
+	}
+}
+
+static void alc883_lenovo_sky_unsol_event(struct hda_codec *codec,
+					     unsigned int res)
+{
+	if ((res >> 26) == ALC880_HP_EVENT)
+		alc888_lenovo_sky_front_automute(codec);
+}
+
 /*
  * generic initialization of ADC, input mixers and output mixers
  */
@@ -7898,6 +8155,105 @@
 	{ } /* end */
 };
 
+static struct hda_verb alc888_asus_m90v_verbs[] = {
+	{0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+	{0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+	{0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+	/* enable unsolicited event */
+	{0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
+	{0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
+	{ } /* end */
+};
+
+static void alc883_nb_mic_automute(struct hda_codec *codec)
+{
+	unsigned int present;
+
+	present = snd_hda_codec_read(codec, 0x18, 0,
+				     AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
+	snd_hda_codec_write(codec, 0x23, 0, AC_VERB_SET_AMP_GAIN_MUTE,
+			    0x7000 | (0x00 << 8) | (present ? 0 : 0x80));
+	snd_hda_codec_write(codec, 0x23, 0, AC_VERB_SET_AMP_GAIN_MUTE,
+			    0x7000 | (0x01 << 8) | (present ? 0x80 : 0));
+}
+
+static void alc883_M90V_speaker_automute(struct hda_codec *codec)
+{
+	unsigned int present;
+	unsigned char bits;
+
+	present = snd_hda_codec_read(codec, 0x1b, 0,
+				     AC_VERB_GET_PIN_SENSE, 0)
+		& AC_PINSENSE_PRESENCE;
+	bits = present ? 0 : PIN_OUT;
+	snd_hda_codec_write(codec, 0x14, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
+			    bits);
+	snd_hda_codec_write(codec, 0x15, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
+			    bits);
+	snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
+			    bits);
+}
+
+static void alc883_mode2_unsol_event(struct hda_codec *codec,
+					   unsigned int res)
+{
+	switch (res >> 26) {
+	case ALC880_HP_EVENT:
+		alc883_M90V_speaker_automute(codec);
+		break;
+	case ALC880_MIC_EVENT:
+		alc883_nb_mic_automute(codec);
+		break;
+	}
+}
+
+static void alc883_mode2_inithook(struct hda_codec *codec)
+{
+	alc883_M90V_speaker_automute(codec);
+	alc883_nb_mic_automute(codec);
+}
+
+static struct hda_verb alc888_asus_eee1601_verbs[] = {
+	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+	{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+	{0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+	{0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+	{0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+	{0x20, AC_VERB_SET_COEF_INDEX, 0x0b},
+	{0x20, AC_VERB_SET_PROC_COEF,  0x0838},
+	/* enable unsolicited event */
+	{0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
+	{ } /* end */
+};
+
+static void alc883_eee1601_speaker_automute(struct hda_codec *codec)
+{
+	unsigned int present;
+	unsigned char bits;
+
+	present = snd_hda_codec_read(codec, 0x14, 0,
+				     AC_VERB_GET_PIN_SENSE, 0)
+		& AC_PINSENSE_PRESENCE;
+	bits = present ? 0 : PIN_OUT;
+	snd_hda_codec_write(codec, 0x1b, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
+			    bits);
+}
+
+static void alc883_eee1601_unsol_event(struct hda_codec *codec,
+					   unsigned int res)
+{
+	switch (res >> 26) {
+	case ALC880_HP_EVENT:
+		alc883_eee1601_speaker_automute(codec);
+		break;
+	}
+}
+
+static void alc883_eee1601_inithook(struct hda_codec *codec)
+{
+	alc883_eee1601_speaker_automute(codec);
+}
+
 #ifdef CONFIG_SND_HDA_POWER_SAVE
 #define alc883_loopbacks	alc880_loopbacks
 #endif
@@ -7927,6 +8283,7 @@
 	[ALC883_LENOVO_101E_2ch] = "lenovo-101e",
 	[ALC883_LENOVO_NB0763]	= "lenovo-nb0763",
 	[ALC888_LENOVO_MS7195_DIG] = "lenovo-ms7195-dig",
+	[ALC888_LENOVO_SKY] = "lenovo-sky",
 	[ALC883_HAIER_W66] 	= "haier-w66",
 	[ALC888_3ST_HP]		= "3stack-hp",
 	[ALC888_6ST_DELL]	= "6stack-dell",
@@ -7942,7 +8299,7 @@
 	SND_PCI_QUIRK(0x1025, 0x006c, "Acer Aspire 9810", ALC883_ACER_ASPIRE),
 	SND_PCI_QUIRK(0x1025, 0x0110, "Acer Aspire", ALC883_ACER_ASPIRE),
 	SND_PCI_QUIRK(0x1025, 0x0112, "Acer Aspire 9303", ALC883_ACER_ASPIRE),
-	SND_PCI_QUIRK(0x1025, 0x0121, "Acer Aspire 5920G", ALC883_ACER_ASPIRE), 
+	SND_PCI_QUIRK(0x1025, 0x0121, "Acer Aspire 5920G", ALC883_ACER_ASPIRE),
 	SND_PCI_QUIRK(0x1025, 0, "Acer laptop", ALC883_ACER), /* default Acer */
 	SND_PCI_QUIRK(0x1028, 0x020d, "Dell Inspiron 530", ALC888_6ST_DELL),
 	SND_PCI_QUIRK(0x103c, 0x2a3d, "HP Pavillion", ALC883_6ST_DIG),
@@ -7950,10 +8307,13 @@
 	SND_PCI_QUIRK(0x103c, 0x2a60, "HP Lucknow", ALC888_3ST_HP),
 	SND_PCI_QUIRK(0x103c, 0x2a61, "HP Nettle", ALC883_6ST_DIG),
 	SND_PCI_QUIRK(0x1043, 0x8249, "Asus M2A-VM HDMI", ALC883_3ST_6ch_DIG),
+	SND_PCI_QUIRK(0x1043, 0x8317, "Asus M90V", ALC888_ASUS_M90V),
+	SND_PCI_QUIRK(0x1043, 0x835f, "Asus Eee 1601", ALC888_ASUS_EEE1601),
 	SND_PCI_QUIRK(0x105b, 0x0ce8, "Foxconn P35AX-S", ALC883_6ST_DIG),
 	SND_PCI_QUIRK(0x105b, 0x6668, "Foxconn", ALC883_6ST_DIG),
 	SND_PCI_QUIRK(0x1071, 0x8253, "Mitac 8252d", ALC883_MITAC),
 	SND_PCI_QUIRK(0x1071, 0x8258, "Evesham Voyaeger", ALC883_LAPTOP_EAPD),
+	SND_PCI_QUIRK(0x10f1, 0x2350, "TYAN-S2350", ALC888_6ST_DELL),
 	SND_PCI_QUIRK(0x108e, 0x534d, NULL, ALC883_3ST_6ch),
 	SND_PCI_QUIRK(0x1458, 0xa002, "MSI", ALC883_6ST_DIG),
 	SND_PCI_QUIRK(0x1462, 0x0349, "MSI", ALC883_TARGA_2ch_DIG),
@@ -7989,6 +8349,7 @@
 	SND_PCI_QUIRK(0x17aa, 0x2085, "Lenovo NB0763", ALC883_LENOVO_NB0763),
 	SND_PCI_QUIRK(0x17aa, 0x3bfc, "Lenovo NB0763", ALC883_LENOVO_NB0763),
 	SND_PCI_QUIRK(0x17aa, 0x3bfd, "Lenovo NB0763", ALC883_LENOVO_NB0763),
+	SND_PCI_QUIRK(0x17aa, 0x101d, "Lenovo Sky", ALC888_LENOVO_SKY),
 	SND_PCI_QUIRK(0x17c0, 0x4071, "MEDION MD2", ALC883_MEDION_MD2),
 	SND_PCI_QUIRK(0x17f2, 0x5000, "Albatron KI690-AM2", ALC883_6ST_DIG),
 	SND_PCI_QUIRK(0x1991, 0x5625, "Haier W66", ALC883_HAIER_W66),
@@ -8128,7 +8489,7 @@
 		.input_mux = &alc883_capture_source,
 		.unsol_event = alc883_medion_md2_unsol_event,
 		.init_hook = alc883_medion_md2_automute,
-	},	
+	},
 	[ALC883_LAPTOP_EAPD] = {
 		.mixers = { alc883_base_mixer },
 		.init_verbs = { alc883_init_verbs, alc882_eapd_verbs },
@@ -8245,6 +8606,49 @@
 		.unsol_event = alc883_2ch_fujitsu_pi2515_unsol_event,
 		.init_hook = alc883_2ch_fujitsu_pi2515_automute,
 	},
+	[ALC888_LENOVO_SKY] = {
+		.mixers = { alc888_lenovo_sky_mixer, alc883_chmode_mixer },
+		.init_verbs = { alc883_init_verbs, alc888_lenovo_sky_verbs},
+		.num_dacs = ARRAY_SIZE(alc883_dac_nids),
+		.dac_nids = alc883_dac_nids,
+		.dig_out_nid = ALC883_DIGOUT_NID,
+		.num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
+		.adc_nids = alc883_adc_nids,
+		.num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
+		.channel_mode = alc883_sixstack_modes,
+		.need_dac_fix = 1,
+		.input_mux = &alc883_lenovo_sky_capture_source,
+		.unsol_event = alc883_lenovo_sky_unsol_event,
+		.init_hook = alc888_lenovo_sky_front_automute,
+	},
+	[ALC888_ASUS_M90V] = {
+		.mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
+		.init_verbs = { alc883_init_verbs, alc888_asus_m90v_verbs },
+		.num_dacs = ARRAY_SIZE(alc883_dac_nids),
+		.dac_nids = alc883_dac_nids,
+		.dig_out_nid = ALC883_DIGOUT_NID,
+		.dig_in_nid = ALC883_DIGIN_NID,
+		.num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
+		.channel_mode = alc883_3ST_6ch_modes,
+		.need_dac_fix = 1,
+		.input_mux = &alc883_fujitsu_pi2515_capture_source,
+		.unsol_event = alc883_mode2_unsol_event,
+		.init_hook = alc883_mode2_inithook,
+	},
+	[ALC888_ASUS_EEE1601] = {
+		.mixers = { alc883_asus_eee1601_mixer },
+		.init_verbs = { alc883_init_verbs, alc888_asus_eee1601_verbs },
+		.num_dacs = ARRAY_SIZE(alc883_dac_nids),
+		.dac_nids = alc883_dac_nids,
+		.dig_out_nid = ALC883_DIGOUT_NID,
+		.dig_in_nid = ALC883_DIGIN_NID,
+		.num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
+		.channel_mode = alc883_3ST_2ch_modes,
+		.need_dac_fix = 1,
+		.input_mux = &alc883_asus_eee1601_capture_source,
+		.unsol_event = alc883_eee1601_unsol_event,
+		.init_hook = alc883_eee1601_inithook,
+	},
 };
 
 
@@ -8452,6 +8856,13 @@
 #define alc262_modes		alc260_modes
 #define alc262_capture_source	alc882_capture_source
 
+static hda_nid_t alc262_dmic_adc_nids[1] = {
+	/* ADC0 */
+	0x09
+};
+
+static hda_nid_t alc262_dmic_capsrc_nids[1] = { 0x22 };
+
 static struct snd_kcontrol_new alc262_base_mixer[] = {
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
@@ -8833,10 +9244,10 @@
 	{0x16, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
 	{0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
 	{0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
-	
+
 	{0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
 	{0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
-	
+
 	/* FIXME: use matrix-type input source selection */
 	/* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
 	/* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
@@ -8858,6 +9269,12 @@
 	{ }
 };
 
+static struct hda_verb alc262_eapd_verbs[] = {
+	{0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
+	{0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
+	{ }
+};
+
 static struct hda_verb alc262_hippo_unsol_verbs[] = {
 	{0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
 	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
@@ -8884,6 +9301,91 @@
 	{}
 };
 
+static struct hda_input_mux alc262_dmic_capture_source = {
+	.num_items = 2,
+	.items = {
+		{ "Int DMic", 0x9 },
+		{ "Mic", 0x0 },
+	},
+};
+
+static struct snd_kcontrol_new alc262_toshiba_s06_mixer[] = {
+	HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+	HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+	HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
+	HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		/* The multiple "Capture Source" controls confuse alsamixer
+		 * So call somewhat different..
+		 */
+		/* .name = "Capture Source", */
+		.name = "Input Source",
+		.count = 1,
+		.info = alc_mux_enum_info,
+		.get = alc_mux_enum_get,
+		.put = alc_mux_enum_put,
+	},
+	{ } /* end */
+};
+
+static struct hda_verb alc262_toshiba_s06_verbs[] = {
+	{0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+	{0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
+	{0x22, AC_VERB_SET_CONNECT_SEL, 0x09},
+	{0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
+	{0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
+	{0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
+	{}
+};
+
+static void alc262_dmic_automute(struct hda_codec *codec)
+{
+	unsigned int present;
+
+	present = snd_hda_codec_read(codec, 0x18, 0,
+					AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
+	snd_hda_codec_write(codec, 0x22, 0,
+				AC_VERB_SET_CONNECT_SEL, present ? 0x0 : 0x09);
+}
+
+/* toggle speaker-output according to the hp-jack state */
+static void alc262_toshiba_s06_speaker_automute(struct hda_codec *codec)
+{
+	unsigned int present;
+	unsigned char bits;
+
+	present = snd_hda_codec_read(codec, 0x15, 0,
+					AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
+	bits = present ? 0 : PIN_OUT;
+	snd_hda_codec_write(codec, 0x14, 0,
+					AC_VERB_SET_PIN_WIDGET_CONTROL, bits);
+}
+
+
+
+/* unsolicited event for HP jack sensing */
+static void alc262_toshiba_s06_unsol_event(struct hda_codec *codec,
+				       unsigned int res)
+{
+	if ((res >> 26) == ALC880_HP_EVENT)
+		alc262_toshiba_s06_speaker_automute(codec);
+	if ((res >> 26) == ALC880_MIC_EVENT)
+		alc262_dmic_automute(codec);
+
+}
+
+static void alc262_toshiba_s06_init_hook(struct hda_codec *codec)
+{
+	alc262_toshiba_s06_speaker_automute(codec);
+	alc262_dmic_automute(codec);
+}
+
 /* mute/unmute internal speaker according to the hp jack and mute state */
 static void alc262_hippo_automute(struct hda_codec *codec)
 {
@@ -8948,6 +9450,41 @@
 }
 
 /*
+ * nec model
+ *  0x15 = headphone
+ *  0x16 = internal speaker
+ *  0x18 = external mic
+ */
+
+static struct snd_kcontrol_new alc262_nec_mixer[] = {
+	HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 0, 0x0, HDA_OUTPUT),
+
+	HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+	HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+	HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+
+	HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
+	{ } /* end */
+};
+
+static struct hda_verb alc262_nec_verbs[] = {
+	/* Unmute Speaker */
+	{0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+
+	/* Headphone */
+	{0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
+	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+
+	/* External mic to headphone */
+	{0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+	/* External mic to speaker */
+	{0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+	{}
+};
+
+/*
  * fujitsu model
  *  0x14 = headphone/spdif-out, 0x15 = internal speaker,
  *  0x1b = port replicator headphone out
@@ -9179,6 +9716,25 @@
 	{ } /* end */
 };
 
+static struct snd_kcontrol_new alc262_toshiba_rx1_mixer[] = {
+	HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol),
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Master Playback Switch",
+		.info = snd_hda_mixer_amp_switch_info,
+		.get = snd_hda_mixer_amp_switch_get,
+		.put = alc262_sony_master_sw_put,
+		.private_value = HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
+	},
+	HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+	HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+	HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+	HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
+	HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
+	HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
+	{ } /* end */
+};
+
 /* additional init verbs for Benq laptops */
 static struct hda_verb alc262_EAPD_verbs[] = {
 	{0x20, AC_VERB_SET_COEF_INDEX, 0x07},
@@ -9427,7 +9983,7 @@
 	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
 	{0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
 	{0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-	
+
 	/* set up input amps for analog loopback */
 	/* Amp Indices: DAC = 0, mixer = 1 */
 	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
@@ -9482,7 +10038,7 @@
 	{0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
 	{0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
         {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
-	
+
 	/*
 	 * Set up output mixers (0x0c - 0x0e)
 	 */
@@ -9643,6 +10199,24 @@
 	{ }
 };
 
+static struct hda_verb alc262_toshiba_rx1_unsol_verbs[] = {
+
+	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },	/* Front Speaker */
+	{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+	{0x14, AC_VERB_SET_CONNECT_SEL, 0x01},
+
+	{0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },	/* MIC jack */
+	{0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },	/* Front MIC */
+	{0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) },
+	{0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) },
+
+	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },	/* HP  jack */
+	{0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
+	{0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
+	{}
+};
+
+
 #ifdef CONFIG_SND_HDA_POWER_SAVE
 #define alc262_loopbacks	alc880_loopbacks
 #endif
@@ -9729,13 +10303,17 @@
 	[ALC262_BENQ_ED8]	= "benq",
 	[ALC262_BENQ_T31]	= "benq-t31",
 	[ALC262_SONY_ASSAMD]	= "sony-assamd",
+	[ALC262_TOSHIBA_S06]	= "toshiba-s06",
+	[ALC262_TOSHIBA_RX1]	= "toshiba-rx1",
 	[ALC262_ULTRA]		= "ultra",
 	[ALC262_LENOVO_3000]	= "lenovo-3000",
+	[ALC262_NEC]		= "nec",
 	[ALC262_AUTO]		= "auto",
 };
 
 static struct snd_pci_quirk alc262_cfg_tbl[] = {
 	SND_PCI_QUIRK(0x1002, 0x437b, "Hippo", ALC262_HIPPO),
+	SND_PCI_QUIRK(0x1033, 0x8895, "NEC Versa S9100", ALC262_NEC),
 	SND_PCI_QUIRK(0x103c, 0x12fe, "HP xw9400", ALC262_HP_BPC),
 	SND_PCI_QUIRK(0x103c, 0x12ff, "HP xw4550", ALC262_HP_BPC),
 	SND_PCI_QUIRK(0x103c, 0x1306, "HP xw8600", ALC262_HP_BPC),
@@ -9764,7 +10342,8 @@
 	SND_PCI_QUIRK(0x104d, 0x900e, "Sony ASSAMD", ALC262_SONY_ASSAMD),
 	SND_PCI_QUIRK(0x104d, 0x9015, "Sony 0x9015", ALC262_SONY_ASSAMD),
 	SND_PCI_QUIRK(0x1179, 0x0001, "Toshiba dynabook SS RX1",
-		      ALC262_SONY_ASSAMD),
+		      ALC262_TOSHIBA_RX1),
+	SND_PCI_QUIRK(0x1179, 0x0268, "Toshiba S06", ALC262_TOSHIBA_S06),
 	SND_PCI_QUIRK(0x10cf, 0x1397, "Fujitsu", ALC262_FUJITSU),
 	SND_PCI_QUIRK(0x10cf, 0x142d, "Fujitsu Lifebook E8410", ALC262_FUJITSU),
 	SND_PCI_QUIRK(0x144d, 0xc032, "Samsung Q1 Ultra", ALC262_ULTRA),
@@ -9918,7 +10497,7 @@
 		.input_mux = &alc262_capture_source,
 		.unsol_event = alc262_hippo_unsol_event,
 		.init_hook = alc262_hippo_automute,
-	},	
+	},
 	[ALC262_ULTRA] = {
 		.mixers = { alc262_ultra_mixer, alc262_ultra_capture_mixer },
 		.init_verbs = { alc262_ultra_verbs },
@@ -9946,6 +10525,43 @@
 		.input_mux = &alc262_fujitsu_capture_source,
 		.unsol_event = alc262_lenovo_3000_unsol_event,
 	},
+	[ALC262_NEC] = {
+		.mixers = { alc262_nec_mixer },
+		.init_verbs = { alc262_nec_verbs },
+		.num_dacs = ARRAY_SIZE(alc262_dac_nids),
+		.dac_nids = alc262_dac_nids,
+		.hp_nid = 0x03,
+		.num_channel_mode = ARRAY_SIZE(alc262_modes),
+		.channel_mode = alc262_modes,
+		.input_mux = &alc262_capture_source,
+	},
+	[ALC262_TOSHIBA_S06] = {
+		.mixers = { alc262_toshiba_s06_mixer },
+		.init_verbs = { alc262_init_verbs, alc262_toshiba_s06_verbs,
+							alc262_eapd_verbs },
+		.num_dacs = ARRAY_SIZE(alc262_dac_nids),
+		.capsrc_nids = alc262_dmic_capsrc_nids,
+		.dac_nids = alc262_dac_nids,
+		.adc_nids = alc262_dmic_adc_nids, /* ADC0 */
+		.dig_out_nid = ALC262_DIGOUT_NID,
+		.num_channel_mode = ARRAY_SIZE(alc262_modes),
+		.channel_mode = alc262_modes,
+		.input_mux = &alc262_dmic_capture_source,
+		.unsol_event = alc262_toshiba_s06_unsol_event,
+		.init_hook = alc262_toshiba_s06_init_hook,
+	},
+	[ALC262_TOSHIBA_RX1] = {
+		.mixers = { alc262_toshiba_rx1_mixer },
+		.init_verbs = { alc262_init_verbs, alc262_toshiba_rx1_unsol_verbs },
+		.num_dacs = ARRAY_SIZE(alc262_dac_nids),
+		.dac_nids = alc262_dac_nids,
+		.hp_nid = 0x03,
+		.num_channel_mode = ARRAY_SIZE(alc262_modes),
+		.channel_mode = alc262_modes,
+		.input_mux = &alc262_capture_source,
+		.unsol_event = alc262_hippo_unsol_event,
+		.init_hook = alc262_hippo_automute,
+	},
 };
 
 static int patch_alc262(struct hda_codec *codec)
@@ -10004,7 +10620,7 @@
 	spec->stream_name_analog = "ALC262 Analog";
 	spec->stream_analog_playback = &alc262_pcm_analog_playback;
 	spec->stream_analog_capture = &alc262_pcm_analog_capture;
-		
+
 	spec->stream_name_digital = "ALC262 Digital";
 	spec->stream_digital_playback = &alc262_pcm_digital_playback;
 	spec->stream_digital_capture = &alc262_pcm_digital_capture;
@@ -10040,7 +10656,7 @@
 	if (!spec->loopback.amplist)
 		spec->loopback.amplist = alc262_loopbacks;
 #endif
-		
+
 	return 0;
 }
 
@@ -10049,7 +10665,7 @@
  */
 #define ALC268_DIGOUT_NID	ALC880_DIGOUT_NID
 #define alc268_modes		alc260_modes
-	
+
 static hda_nid_t alc268_dac_nids[2] = {
 	/* front, hp */
 	0x02, 0x03
@@ -10109,6 +10725,14 @@
 	{ } /* end */
 };
 
+static struct hda_input_mux alc268_acer_lc_capture_source = {
+	.num_items = 2,
+	.items = {
+		{ "i-Mic", 0x6 },
+		{ "E-Mic", 0x0 },
+	},
+};
+
 /* Acer specific */
 /* bind volumes of both NID 0x02 and 0x03 */
 static struct hda_bind_ctls alc268_acer_bind_master_vol = {
@@ -10161,6 +10785,21 @@
 	return change;
 }
 
+static struct snd_kcontrol_new alc268_acer_aspire_one_mixer[] = {
+	/* output mixer control */
+	HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Master Playback Switch",
+		.info = snd_hda_mixer_amp_switch_info,
+		.get = snd_hda_mixer_amp_switch_get,
+		.put = alc268_acer_master_sw_put,
+		.private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
+	},
+	HDA_CODEC_VOLUME("Mic Boost Capture Volume", 0x18, 0, HDA_INPUT),
+	{ }
+};
+
 static struct snd_kcontrol_new alc268_acer_mixer[] = {
 	/* output mixer control */
 	HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
@@ -10178,6 +10817,16 @@
 	{ }
 };
 
+static struct hda_verb alc268_acer_aspire_one_verbs[] = {
+	{0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+	{0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
+	{0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
+	{0x23, AC_VERB_SET_CONNECT_SEL, 0x06},
+	{0x23, AC_VERB_SET_AMP_GAIN_MUTE, 0xa017},
+	{ }
+};
+
 static struct hda_verb alc268_acer_verbs[] = {
 	{0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* internal dmic? */
 	{0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
@@ -10185,7 +10834,6 @@
 	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
 	{0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
 	{0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-
 	{0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
 	{ }
 };
@@ -10212,6 +10860,47 @@
 	alc268_acer_automute(codec, 1);
 }
 
+/* toggle speaker-output according to the hp-jack state */
+static void alc268_aspire_one_speaker_automute(struct hda_codec *codec)
+{
+	unsigned int present;
+	unsigned char bits;
+
+	present = snd_hda_codec_read(codec, 0x15, 0,
+				AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
+	bits = present ? AMP_IN_MUTE(0) : 0;
+	snd_hda_codec_amp_stereo(codec, 0x0f, HDA_INPUT, 0,
+				AMP_IN_MUTE(0), bits);
+	snd_hda_codec_amp_stereo(codec, 0x0f, HDA_INPUT, 1,
+				AMP_IN_MUTE(0), bits);
+}
+
+
+static void alc268_acer_mic_automute(struct hda_codec *codec)
+{
+	unsigned int present;
+
+	present = snd_hda_codec_read(codec, 0x18, 0,
+				AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
+	snd_hda_codec_write(codec, 0x23, 0, AC_VERB_SET_CONNECT_SEL,
+			    present ? 0x0 : 0x6);
+}
+
+static void alc268_acer_lc_unsol_event(struct hda_codec *codec,
+				    unsigned int res)
+{
+	if ((res >> 26) == ALC880_HP_EVENT)
+		alc268_aspire_one_speaker_automute(codec);
+	if ((res >> 26) == ALC880_MIC_EVENT)
+		alc268_acer_mic_automute(codec);
+}
+
+static void alc268_acer_lc_init_hook(struct hda_codec *codec)
+{
+	alc268_aspire_one_speaker_automute(codec);
+	alc268_acer_mic_automute(codec);
+}
+
 static struct snd_kcontrol_new alc268_dell_mixer[] = {
 	/* output mixer control */
 	HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
@@ -10360,7 +11049,7 @@
 	{0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
 
 	/* Unmute Selector 23h,24h and set the default input to mic-in */
-	
+
 	{0x23, AC_VERB_SET_CONNECT_SEL, 0x00},
 	{0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
 	{0x24, AC_VERB_SET_CONNECT_SEL, 0x00},
@@ -10559,7 +11248,7 @@
 
 	nid = cfg->line_out_pins[0];
 	if (nid)
-		alc268_new_analog_output(spec, nid, "Front", 0);	
+		alc268_new_analog_output(spec, nid, "Front", 0);
 
 	nid = cfg->speaker_pins[0];
 	if (nid == 0x1d) {
@@ -10581,7 +11270,7 @@
 		if (err < 0)
 			return err;
 	}
-	return 0;	
+	return 0;
 }
 
 /* create playback/capture controls for input pins */
@@ -10602,7 +11291,7 @@
 		case 0x1a:
 			idx1 = 2;	/* Line In */
 			break;
-		case 0x1c:	
+		case 0x1c:
 			idx1 = 3;	/* CD */
 			break;
 		case 0x12:
@@ -10614,7 +11303,7 @@
 		}
 		imux->items[imux->num_items].label = auto_pin_cfg_labels[i];
 		imux->items[imux->num_items].index = idx1;
-		imux->num_items++;	
+		imux->num_items++;
 	}
 	return 0;
 }
@@ -10644,11 +11333,11 @@
 	}
 
 	dac_vol1 = dac_vol2 = 0xb000 | 0x40;	/* set max volume  */
-	if (line_nid == 0x14)	
+	if (line_nid == 0x14)
 		dac_vol2 = AMP_OUT_ZERO;
 	else if (line_nid == 0x15)
 		dac_vol1 = AMP_OUT_ZERO;
-	if (hp_nid == 0x14)	
+	if (hp_nid == 0x14)
 		dac_vol2 = AMP_OUT_ZERO;
 	else if (hp_nid == 0x15)
 		dac_vol1 = AMP_OUT_ZERO;
@@ -10739,6 +11428,7 @@
 	[ALC268_3ST]		= "3stack",
 	[ALC268_TOSHIBA]	= "toshiba",
 	[ALC268_ACER]		= "acer",
+	[ALC268_ACER_ASPIRE_ONE]	= "acer-aspire",
 	[ALC268_DELL]		= "dell",
 	[ALC268_ZEPTO]		= "zepto",
 #ifdef CONFIG_SND_DEBUG
@@ -10753,11 +11443,14 @@
 	SND_PCI_QUIRK(0x1025, 0x012e, "Acer Aspire 5310", ALC268_ACER),
 	SND_PCI_QUIRK(0x1025, 0x0130, "Acer Extensa 5210", ALC268_ACER),
 	SND_PCI_QUIRK(0x1025, 0x0136, "Acer Aspire 5315", ALC268_ACER),
+	SND_PCI_QUIRK(0x1025, 0x015b, "Acer Aspire One",
+						ALC268_ACER_ASPIRE_ONE),
 	SND_PCI_QUIRK(0x1028, 0x0253, "Dell OEM", ALC268_DELL),
 	SND_PCI_QUIRK(0x103c, 0x30cc, "TOSHIBA", ALC268_TOSHIBA),
 	SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC268_3ST),
 	SND_PCI_QUIRK(0x1179, 0xff10, "TOSHIBA A205", ALC268_TOSHIBA),
 	SND_PCI_QUIRK(0x1179, 0xff50, "TOSHIBA A305", ALC268_TOSHIBA),
+	SND_PCI_QUIRK(0x1179, 0xff64, "TOSHIBA L305", ALC268_TOSHIBA),
 	SND_PCI_QUIRK(0x14c0, 0x0025, "COMPAL IFL90/JFL-92", ALC268_TOSHIBA),
 	SND_PCI_QUIRK(0x152d, 0x0763, "Diverse (CPR2000)", ALC268_ACER),
 	SND_PCI_QUIRK(0x152d, 0x0771, "Quanta IL1", ALC267_QUANTA_IL1),
@@ -10830,6 +11523,23 @@
 		.unsol_event = alc268_acer_unsol_event,
 		.init_hook = alc268_acer_init_hook,
 	},
+	[ALC268_ACER_ASPIRE_ONE] = {
+		.mixers = { alc268_acer_aspire_one_mixer,
+				alc268_capture_alt_mixer },
+		.init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
+				alc268_acer_aspire_one_verbs },
+		.num_dacs = ARRAY_SIZE(alc268_dac_nids),
+		.dac_nids = alc268_dac_nids,
+		.num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
+		.adc_nids = alc268_adc_nids_alt,
+		.capsrc_nids = alc268_capsrc_nids,
+		.hp_nid = 0x03,
+		.num_channel_mode = ARRAY_SIZE(alc268_modes),
+		.channel_mode = alc268_modes,
+		.input_mux = &alc268_acer_lc_capture_source,
+		.unsol_event = alc268_acer_lc_unsol_event,
+		.init_hook = alc268_acer_lc_init_hook,
+	},
 	[ALC268_DELL] = {
 		.mixers = { alc268_dell_mixer, alc268_beep_mixer },
 		.init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
@@ -10974,7 +11684,7 @@
 	codec->patch_ops = alc_patch_ops;
 	if (board_config == ALC268_AUTO)
 		spec->init_hook = alc268_auto_init;
-		
+
 	return 0;
 }
 
@@ -10990,6 +11700,14 @@
 	0x08,
 };
 
+static hda_nid_t alc269_capsrc_nids[1] = {
+	0x23,
+};
+
+/* NOTE: ADC2 (0x07) is connected from a recording *MIXER* (0x24),
+ *       not a mux!
+ */
+
 static struct hda_input_mux alc269_eeepc_dmic_capture_source = {
 	.num_items = 2,
 	.items = {
@@ -11016,6 +11734,8 @@
 	HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
 	HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
 	HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+	HDA_CODEC_VOLUME("Beep Playback Volume", 0x0b, 0x4, HDA_INPUT),
+	HDA_CODEC_MUTE("Beep Playback Switch", 0x0b, 0x4, HDA_INPUT),
 	HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
 	HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
 	HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
@@ -11025,6 +11745,28 @@
 	{ } /* end */
 };
 
+static struct snd_kcontrol_new alc269_quanta_fl1_mixer[] = {
+	/* output mixer control */
+	HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Master Playback Switch",
+		.info = snd_hda_mixer_amp_switch_info,
+		.get = snd_hda_mixer_amp_switch_get,
+		.put = alc268_acer_master_sw_put,
+		.private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
+	},
+	HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+	HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+	HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+	HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
+	HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
+	HDA_CODEC_VOLUME("Internal Mic Boost", 0x19, 0, HDA_INPUT),
+	HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x04, HDA_INPUT),
+	HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x04, HDA_INPUT),
+	{ }
+};
+
 /* bind volumes of both NID 0x0c and 0x0d */
 static struct hda_bind_ctls alc269_epc_bind_vol = {
 	.ops = &snd_hda_bind_vol,
@@ -11068,6 +11810,165 @@
 	{ } /* end */
 };
 
+/* beep control */
+static struct snd_kcontrol_new alc269_beep_mixer[] = {
+	HDA_CODEC_VOLUME("Beep Playback Volume", 0x0b, 0x4, HDA_INPUT),
+	HDA_CODEC_MUTE("Beep Playback Switch", 0x0b, 0x4, HDA_INPUT),
+	{ } /* end */
+};
+
+static struct hda_verb alc269_quanta_fl1_verbs[] = {
+	{0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
+	{0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+	{0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
+	{0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
+	{0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+	{ }
+};
+
+/* toggle speaker-output according to the hp-jack state */
+static void alc269_quanta_fl1_speaker_automute(struct hda_codec *codec)
+{
+	unsigned int present;
+	unsigned char bits;
+
+	present = snd_hda_codec_read(codec, 0x15, 0,
+			AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
+	bits = present ? AMP_IN_MUTE(0) : 0;
+	snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
+			AMP_IN_MUTE(0), bits);
+	snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
+			AMP_IN_MUTE(0), bits);
+
+	snd_hda_codec_write(codec, 0x20, 0,
+			AC_VERB_SET_COEF_INDEX, 0x0c);
+	snd_hda_codec_write(codec, 0x20, 0,
+			AC_VERB_SET_PROC_COEF, 0x680);
+
+	snd_hda_codec_write(codec, 0x20, 0,
+			AC_VERB_SET_COEF_INDEX, 0x0c);
+	snd_hda_codec_write(codec, 0x20, 0,
+			AC_VERB_SET_PROC_COEF, 0x480);
+}
+
+static void alc269_quanta_fl1_mic_automute(struct hda_codec *codec)
+{
+	unsigned int present;
+
+	present = snd_hda_codec_read(codec, 0x18, 0,
+				AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
+	snd_hda_codec_write(codec, 0x23, 0,
+			    AC_VERB_SET_CONNECT_SEL, present ? 0x0 : 0x1);
+}
+
+static void alc269_quanta_fl1_unsol_event(struct hda_codec *codec,
+				    unsigned int res)
+{
+	if ((res >> 26) == ALC880_HP_EVENT)
+		alc269_quanta_fl1_speaker_automute(codec);
+	if ((res >> 26) == ALC880_MIC_EVENT)
+		alc269_quanta_fl1_mic_automute(codec);
+}
+
+static void alc269_quanta_fl1_init_hook(struct hda_codec *codec)
+{
+	alc269_quanta_fl1_speaker_automute(codec);
+	alc269_quanta_fl1_mic_automute(codec);
+}
+
+static struct hda_verb alc269_eeepc_dmic_init_verbs[] = {
+	{0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
+	{0x23, AC_VERB_SET_CONNECT_SEL, 0x05},
+	{0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 },
+	{0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7019 | (0x00 << 8))},
+	{0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+	{0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
+	{0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
+	{}
+};
+
+static struct hda_verb alc269_eeepc_amic_init_verbs[] = {
+	{0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
+	{0x23, AC_VERB_SET_CONNECT_SEL, 0x01},
+	{0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 },
+	{0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x701b | (0x00 << 8))},
+	{0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
+	{0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
+	{}
+};
+
+/* toggle speaker-output according to the hp-jack state */
+static void alc269_speaker_automute(struct hda_codec *codec)
+{
+	unsigned int present;
+	unsigned char bits;
+
+	present = snd_hda_codec_read(codec, 0x15, 0,
+				AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
+	bits = present ? AMP_IN_MUTE(0) : 0;
+	snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
+				AMP_IN_MUTE(0), bits);
+	snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
+				AMP_IN_MUTE(0), bits);
+}
+
+static void alc269_eeepc_dmic_automute(struct hda_codec *codec)
+{
+	unsigned int present;
+
+	present = snd_hda_codec_read(codec, 0x18, 0,
+				AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
+	snd_hda_codec_write(codec, 0x23, 0,
+				AC_VERB_SET_CONNECT_SEL,  (present ? 0 : 5));
+}
+
+static void alc269_eeepc_amic_automute(struct hda_codec *codec)
+{
+	unsigned int present;
+
+	present = snd_hda_codec_read(codec, 0x18, 0,
+				AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
+	snd_hda_codec_write(codec, 0x24, 0, AC_VERB_SET_AMP_GAIN_MUTE,
+				0x7000 | (0x00 << 8) | (present ? 0 : 0x80));
+	snd_hda_codec_write(codec, 0x24, 0, AC_VERB_SET_AMP_GAIN_MUTE,
+				0x7000 | (0x01 << 8) | (present ? 0x80 : 0));
+}
+
+/* unsolicited event for HP jack sensing */
+static void alc269_eeepc_dmic_unsol_event(struct hda_codec *codec,
+				     unsigned int res)
+{
+	if ((res >> 26) == ALC880_HP_EVENT)
+		alc269_speaker_automute(codec);
+
+	if ((res >> 26) == ALC880_MIC_EVENT)
+		alc269_eeepc_dmic_automute(codec);
+}
+
+static void alc269_eeepc_dmic_inithook(struct hda_codec *codec)
+{
+	alc269_speaker_automute(codec);
+	alc269_eeepc_dmic_automute(codec);
+}
+
+/* unsolicited event for HP jack sensing */
+static void alc269_eeepc_amic_unsol_event(struct hda_codec *codec,
+				     unsigned int res)
+{
+	if ((res >> 26) == ALC880_HP_EVENT)
+		alc269_speaker_automute(codec);
+
+	if ((res >> 26) == ALC880_MIC_EVENT)
+		alc269_eeepc_amic_automute(codec);
+}
+
+static void alc269_eeepc_amic_inithook(struct hda_codec *codec)
+{
+	alc269_speaker_automute(codec);
+	alc269_eeepc_amic_automute(codec);
+}
+
 /*
  * generic initialization of ADC, input mixers and output mixers
  */
@@ -11075,7 +11976,7 @@
 	/*
 	 * Unmute ADC0 and set the default input to mic-in
 	 */
-	{0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+	{0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 
 	/* Mute input amps (PCBeep, Line In, Mic 1 & Mic 2) of the
 	 * analog-loopback mixer widget
@@ -11127,8 +12028,8 @@
 	/* FIXME: use matrix-type input source selection */
 	/* Mixer elements: 0x18, 19, 1a, 1b, 1d, 0b */
 	/* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
-	{0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-	{0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+	{0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+	{0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
 	{0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
 	{0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
 
@@ -11138,98 +12039,6 @@
 	{ }
 };
 
-static struct hda_verb alc269_eeepc_dmic_init_verbs[] = {
-	{0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
-	{0x23, AC_VERB_SET_CONNECT_SEL, 0x05},
-	{0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 },
-	{0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7019 | (0x00 << 8))},
-	{0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-	{0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
-	{0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
-	{}
-};
-
-static struct hda_verb alc269_eeepc_amic_init_verbs[] = {
-	{0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
-	{0x23, AC_VERB_SET_CONNECT_SEL, 0x01},
-	{0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 },
-	{0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x701b | (0x00 << 8))},
-	{0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
-	{0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
-	{}
-};
-
-/* toggle speaker-output according to the hp-jack state */
-static void alc269_speaker_automute(struct hda_codec *codec)
-{
-	unsigned int present;
-	unsigned int bits;
-
-	present = snd_hda_codec_read(codec, 0x15, 0,
-				     AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
-	bits = present ? AMP_IN_MUTE(0) : 0;
-	snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
-				 AMP_IN_MUTE(0), bits);
-	snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
-				 AMP_IN_MUTE(0), bits);
-}
-
-static void alc269_eeepc_dmic_automute(struct hda_codec *codec)
-{
-	unsigned int present;
-
-	present = snd_hda_codec_read(codec, 0x18, 0, AC_VERB_GET_PIN_SENSE, 0)
-		& AC_PINSENSE_PRESENCE;
-	snd_hda_codec_write(codec, 0x23, 0, AC_VERB_SET_CONNECT_SEL,
-			    present ? 0 : 5);
-}
-
-static void alc269_eeepc_amic_automute(struct hda_codec *codec)
-{
-	unsigned int present;
-
-	present = snd_hda_codec_read(codec, 0x18, 0, AC_VERB_GET_PIN_SENSE, 0)
-		& AC_PINSENSE_PRESENCE;
-	snd_hda_codec_write(codec, 0x24, 0, AC_VERB_SET_AMP_GAIN_MUTE,
-			    present ? AMP_IN_UNMUTE(0) : AMP_IN_MUTE(0));
-	snd_hda_codec_write(codec, 0x24, 0, AC_VERB_SET_AMP_GAIN_MUTE,
-			    present ? AMP_IN_MUTE(1) : AMP_IN_UNMUTE(1));
-}
-
-/* unsolicited event for HP jack sensing */
-static void alc269_eeepc_dmic_unsol_event(struct hda_codec *codec,
-					  unsigned int res)
-{
-	if ((res >> 26) == ALC880_HP_EVENT)
-		alc269_speaker_automute(codec);
-
-	if ((res >> 26) == ALC880_MIC_EVENT)
-		alc269_eeepc_dmic_automute(codec);
-}
-
-static void alc269_eeepc_dmic_inithook(struct hda_codec *codec)
-{
-	alc269_speaker_automute(codec);
-	alc269_eeepc_dmic_automute(codec);
-}
-
-/* unsolicited event for HP jack sensing */
-static void alc269_eeepc_amic_unsol_event(struct hda_codec *codec,
-					  unsigned int res)
-{
-	if ((res >> 26) == ALC880_HP_EVENT)
-		alc269_speaker_automute(codec);
-
-	if ((res >> 26) == ALC880_MIC_EVENT)
-		alc269_eeepc_amic_automute(codec);
-}
-
-static void alc269_eeepc_amic_inithook(struct hda_codec *codec)
-{
-	alc269_speaker_automute(codec);
-	alc269_eeepc_amic_automute(codec);
-}
-
 /* add playback controls from the parsed DAC table */
 static int alc269_auto_create_multi_out_ctls(struct alc_spec *spec,
 					     const struct auto_pin_cfg *cfg)
@@ -11330,7 +12139,7 @@
 static int alc269_parse_auto_config(struct hda_codec *codec)
 {
 	struct alc_spec *spec = codec->spec;
-	int err;
+	int i, err;
 	static hda_nid_t alc269_ignore[] = { 0x1d, 0 };
 
 	err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
@@ -11353,9 +12162,20 @@
 	if (spec->kctl_alloc)
 		spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
 
+	/* create a beep mixer control if the pin 0x1d isn't assigned */
+	for (i = 0; i < ARRAY_SIZE(spec->autocfg.input_pins); i++)
+		if (spec->autocfg.input_pins[i] == 0x1d)
+			break;
+	if (i >= ARRAY_SIZE(spec->autocfg.input_pins))
+		spec->mixers[spec->num_mixers++] = alc269_beep_mixer;
+
 	spec->init_verbs[spec->num_init_verbs++] = alc269_init_verbs;
 	spec->num_mux_defs = 1;
 	spec->input_mux = &spec->private_imux;
+	/* set default input source */
+	snd_hda_codec_write_cache(codec, alc269_capsrc_nids[0],
+				  0, AC_VERB_SET_CONNECT_SEL,
+				  spec->input_mux->items[0].index);
 
 	err = alc_auto_add_mic_boost(codec);
 	if (err < 0)
@@ -11387,14 +12207,20 @@
  * configuration and preset
  */
 static const char *alc269_models[ALC269_MODEL_LAST] = {
-	[ALC269_BASIC]		= "basic",
+	[ALC269_BASIC]			= "basic",
+	[ALC269_QUANTA_FL1]		= "quanta",
+	[ALC269_ASUS_EEEPC_P703]	= "eeepc-p703",
+	[ALC269_ASUS_EEEPC_P901]	= "eeepc-p901"
 };
 
 static struct snd_pci_quirk alc269_cfg_tbl[] = {
+	SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_QUANTA_FL1),
 	SND_PCI_QUIRK(0x1043, 0x8330, "ASUS Eeepc P703 P900A",
 		      ALC269_ASUS_EEEPC_P703),
 	SND_PCI_QUIRK(0x1043, 0x831a, "ASUS Eeepc P901",
 		      ALC269_ASUS_EEEPC_P901),
+	SND_PCI_QUIRK(0x1043, 0x834a, "ASUS Eeepc S101",
+		      ALC269_ASUS_EEEPC_P901),
 	{}
 };
 
@@ -11409,6 +12235,18 @@
 		.channel_mode = alc269_modes,
 		.input_mux = &alc269_capture_source,
 	},
+	[ALC269_QUANTA_FL1] = {
+		.mixers = { alc269_quanta_fl1_mixer },
+		.init_verbs = { alc269_init_verbs, alc269_quanta_fl1_verbs },
+		.num_dacs = ARRAY_SIZE(alc269_dac_nids),
+		.dac_nids = alc269_dac_nids,
+		.hp_nid = 0x03,
+		.num_channel_mode = ARRAY_SIZE(alc269_modes),
+		.channel_mode = alc269_modes,
+		.input_mux = &alc269_capture_source,
+		.unsol_event = alc269_quanta_fl1_unsol_event,
+		.init_hook = alc269_quanta_fl1_init_hook,
+	},
 	[ALC269_ASUS_EEEPC_P703] = {
 		.mixers = { alc269_eeepc_mixer, alc269_epc_capture_mixer },
 		.init_verbs = { alc269_init_verbs,
@@ -11488,6 +12326,7 @@
 
 	spec->adc_nids = alc269_adc_nids;
 	spec->num_adc_nids = ARRAY_SIZE(alc269_adc_nids);
+	spec->capsrc_nids = alc269_capsrc_nids;
 
 	codec->patch_ops = alc_patch_ops;
 	if (board_config == ALC269_AUTO)
@@ -11689,7 +12528,7 @@
 	HDA_CODEC_MUTE("Master Playback Switch", 0x03, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
 	HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
-	
+
         /*Capture mixer control */
 	HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
 	HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
@@ -11832,20 +12671,20 @@
 	/* route front mic to ADC1*/
 	{0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
 	{0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-	
+
 	/* Unmute DAC0~3 & spdif out*/
 	{0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
 	{0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
 	{0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
 	{0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
 	{0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-	
+
 	/* Unmute Mixer 14 (mic) 1c (Line in)*/
 	{0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
         {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
 	{0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
         {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-	
+
 	/* Unmute Stereo Mixer 15 */
 	{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 	{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
@@ -11901,13 +12740,13 @@
 	{0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
 	{0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
 	{0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-	
+
 	/* Unmute Mixer 14 (mic) 1c (Line in)*/
 	{0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
         {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
 	{0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
         {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-	
+
 	/* Unmute Stereo Mixer 15 */
 	{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 	{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
@@ -11963,13 +12802,13 @@
 	{0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
 	{0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
 	{0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-	
+
 	/* Unmute Mixer 14 (mic) 1c (Line in)*/
 	{0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
         {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
 	{0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
         {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-	
+
 	/* Unmute Stereo Mixer 15 */
 	{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 	{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
@@ -12034,7 +12873,7 @@
         {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
 	{0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
         {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-	
+
 	/* Unmute Stereo Mixer 15 */
 	{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 	{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
@@ -12071,20 +12910,20 @@
 	 */
 	/* {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, */
 	{0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-	
+
 	/* Unmute DAC0~3 & spdif out*/
 	{0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
 	{0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
 	{0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
 	{0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
 	{0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-	
+
 	/* Unmute Mixer 14 (mic) 1c (Line in)*/
 	{0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 	{0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
 	{0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 	{0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-	
+
 	/* Unmute Stereo Mixer 15 */
 	{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 	{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
@@ -12659,7 +13498,7 @@
 	if (!spec->loopback.amplist)
 		spec->loopback.amplist = alc861_loopbacks;
 #endif
-		
+
 	return 0;
 }
 
@@ -12913,7 +13752,7 @@
 	HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
 	HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
 	HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
-	
+
 	{ } /* end */
 };
 
@@ -13058,7 +13897,7 @@
 	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
 	{0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
 	{0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
-	{0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},	
+	{0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
 	{}
 };
 
@@ -13120,7 +13959,7 @@
 	{0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
 	{0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
 	{0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-	
+
 	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
 	{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
 	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
@@ -13145,7 +13984,7 @@
 	{0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
 
 	{0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-	{0x09, AC_VERB_SET_CONNECT_SEL, 0x00},	
+	{0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
 	{0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
 
 	{ } /* end */
@@ -13304,7 +14143,7 @@
 		.input_mux = &alc861vd_hp_capture_source,
 		.unsol_event = alc861vd_dallas_unsol_event,
 		.init_hook = alc861vd_dallas_automute,
-	},		
+	},
 };
 
 /*
@@ -13883,13 +14722,120 @@
 	{ } /* end */
 };
 
+static struct hda_bind_ctls alc663_asus_bind_master_vol = {
+	.ops = &snd_hda_bind_vol,
+	.values = {
+		HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
+		HDA_COMPOSE_AMP_VAL(0x03, 3, 0, HDA_OUTPUT),
+		0
+	},
+};
+
+static struct hda_bind_ctls alc663_asus_one_bind_switch = {
+	.ops = &snd_hda_bind_sw,
+	.values = {
+		HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
+		HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
+		0
+	},
+};
+
 static struct snd_kcontrol_new alc663_m51va_mixer[] = {
+	HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
+	HDA_BIND_SW("Master Playback Switch", &alc663_asus_one_bind_switch),
+	HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+	HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+	{ } /* end */
+};
+
+static struct hda_bind_ctls alc663_asus_tree_bind_switch = {
+	.ops = &snd_hda_bind_sw,
+	.values = {
+		HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
+		HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
+		HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
+		0
+	},
+};
+
+static struct snd_kcontrol_new alc663_two_hp_m1_mixer[] = {
+	HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
+	HDA_BIND_SW("Master Playback Switch", &alc663_asus_tree_bind_switch),
+	HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+	HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+	HDA_CODEC_VOLUME("F-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+	HDA_CODEC_MUTE("F-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
+
+	{ } /* end */
+};
+
+static struct hda_bind_ctls alc663_asus_four_bind_switch = {
+	.ops = &snd_hda_bind_sw,
+	.values = {
+		HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
+		HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
+		HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT),
+		0
+	},
+};
+
+static struct snd_kcontrol_new alc663_two_hp_m2_mixer[] = {
+	HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
+	HDA_BIND_SW("Master Playback Switch", &alc663_asus_four_bind_switch),
+	HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+	HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+	HDA_CODEC_VOLUME("F-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+	HDA_CODEC_MUTE("F-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
+	{ } /* end */
+};
+
+static struct snd_kcontrol_new alc662_1bjd_mixer[] = {
 	HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+	HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+	HDA_CODEC_VOLUME("F-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+	HDA_CODEC_MUTE("F-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
+	{ } /* end */
+};
+
+static struct hda_bind_ctls alc663_asus_two_bind_master_vol = {
+	.ops = &snd_hda_bind_vol,
+	.values = {
+		HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
+		HDA_COMPOSE_AMP_VAL(0x04, 3, 0, HDA_OUTPUT),
+		0
+	},
+};
+
+static struct hda_bind_ctls alc663_asus_two_bind_switch = {
+	.ops = &snd_hda_bind_sw,
+	.values = {
+		HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
+		HDA_COMPOSE_AMP_VAL(0x16, 3, 0, HDA_OUTPUT),
+		0
+	},
+};
+
+static struct snd_kcontrol_new alc663_asus_21jd_clfe_mixer[] = {
+	HDA_BIND_VOL("Master Playback Volume",
+				&alc663_asus_two_bind_master_vol),
+	HDA_BIND_SW("Master Playback Switch", &alc663_asus_two_bind_switch),
+	HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
 	HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-	HDA_CODEC_MUTE("DMic Playback Switch", 0x23, 0x9, HDA_INPUT),
+	{ } /* end */
+};
+
+static struct snd_kcontrol_new alc663_asus_15jd_clfe_mixer[] = {
+	HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
+	HDA_BIND_SW("Master Playback Switch", &alc663_asus_two_bind_switch),
+	HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+	HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
 	{ } /* end */
 };
 
@@ -14074,17 +15020,84 @@
 };
 
 static struct hda_verb alc663_m51va_init_verbs[] = {
+	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+	{0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
 	{0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
 	{0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-	{0x21, AC_VERB_SET_CONNECT_SEL, 0x00},	/* Headphone */
-
-	{0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)},
-
+	{0x21, AC_VERB_SET_CONNECT_SEL, 0x01},	/* Headphone */
+	{0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+	{0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)},
 	{0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
 	{0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
 	{}
 };
 
+static struct hda_verb alc663_21jd_amic_init_verbs[] = {
+	{0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+	{0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+	{0x21, AC_VERB_SET_CONNECT_SEL, 0x01},	/* Headphone */
+	{0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+	{0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+	{0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
+	{0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
+	{}
+};
+
+static struct hda_verb alc662_1bjd_amic_init_verbs[] = {
+	{0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+	{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+	{0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+	{0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},	/* Headphone */
+	{0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+	{0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+	{0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
+	{0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
+	{}
+};
+
+static struct hda_verb alc663_15jd_amic_init_verbs[] = {
+	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+	{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+	{0x15, AC_VERB_SET_CONNECT_SEL, 0x01},	/* Headphone */
+	{0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+	{0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+	{0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
+	{0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
+	{}
+};
+
+static struct hda_verb alc663_two_hp_amic_m1_init_verbs[] = {
+	{0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+	{0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+	{0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+	{0x21, AC_VERB_SET_CONNECT_SEL, 0x0},	/* Headphone */
+	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+	{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+	{0x15, AC_VERB_SET_CONNECT_SEL, 0x0},	/* Headphone */
+	{0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+	{0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+	{0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
+	{0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
+	{0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
+	{}
+};
+
+static struct hda_verb alc663_two_hp_amic_m2_init_verbs[] = {
+	{0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+	{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+	{0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+	{0x1b, AC_VERB_SET_CONNECT_SEL, 0x01},	/* Headphone */
+	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+	{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+	{0x15, AC_VERB_SET_CONNECT_SEL, 0x01},	/* Headphone */
+	{0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+	{0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+	{0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
+	{0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
+	{0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
+	{}
+};
+
 static struct hda_verb alc663_g71v_init_verbs[] = {
 	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
 	/* {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, */
@@ -14110,6 +15123,14 @@
 	{}
 };
 
+static struct hda_verb alc662_ecs_init_verbs[] = {
+	{0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0x701f},
+	{0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+	{0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
+	{0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
+	{}
+};
+
 /* capture mixer elements */
 static struct snd_kcontrol_new alc662_capture_mixer[] = {
 	HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
@@ -14129,6 +15150,12 @@
 	{ } /* end */
 };
 
+static struct snd_kcontrol_new alc662_auto_capture_mixer[] = {
+	HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
+	HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
+	{ } /* end */
+};
+
 static void alc662_lenovo_101e_ispeaker_automute(struct hda_codec *codec)
 {
 	unsigned int present;
@@ -14209,12 +15236,12 @@
 	if (present) {
 		/* mute internal speaker */
 		snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
-					 HDA_AMP_MUTE, HDA_AMP_MUTE);
+					HDA_AMP_MUTE, HDA_AMP_MUTE);
 	} else {
 		/* unmute internal speaker if necessary */
 		mute = snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0);
 		snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
-					 HDA_AMP_MUTE, mute);
+					HDA_AMP_MUTE, mute);
 	}
 }
 
@@ -14237,11 +15264,108 @@
 	unsigned char bits;
 
 	present = snd_hda_codec_read(codec, 0x21, 0,
-				     AC_VERB_GET_PIN_SENSE, 0)
-		& AC_PINSENSE_PRESENCE;
+			AC_VERB_GET_PIN_SENSE, 0)
+			& AC_PINSENSE_PRESENCE;
 	bits = present ? HDA_AMP_MUTE : 0;
-	snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
-				 HDA_AMP_MUTE, bits);
+	snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
+				AMP_IN_MUTE(0), bits);
+	snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
+				AMP_IN_MUTE(0), bits);
+}
+
+static void alc663_21jd_two_speaker_automute(struct hda_codec *codec)
+{
+	unsigned int present;
+	unsigned char bits;
+
+	present = snd_hda_codec_read(codec, 0x21, 0,
+			AC_VERB_GET_PIN_SENSE, 0)
+			& AC_PINSENSE_PRESENCE;
+	bits = present ? HDA_AMP_MUTE : 0;
+	snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
+				AMP_IN_MUTE(0), bits);
+	snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
+				AMP_IN_MUTE(0), bits);
+	snd_hda_codec_amp_stereo(codec, 0x0e, HDA_INPUT, 0,
+				AMP_IN_MUTE(0), bits);
+	snd_hda_codec_amp_stereo(codec, 0x0e, HDA_INPUT, 1,
+				AMP_IN_MUTE(0), bits);
+}
+
+static void alc663_15jd_two_speaker_automute(struct hda_codec *codec)
+{
+	unsigned int present;
+	unsigned char bits;
+
+	present = snd_hda_codec_read(codec, 0x15, 0,
+			AC_VERB_GET_PIN_SENSE, 0)
+			& AC_PINSENSE_PRESENCE;
+	bits = present ? HDA_AMP_MUTE : 0;
+	snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
+				AMP_IN_MUTE(0), bits);
+	snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
+				AMP_IN_MUTE(0), bits);
+	snd_hda_codec_amp_stereo(codec, 0x0e, HDA_INPUT, 0,
+				AMP_IN_MUTE(0), bits);
+	snd_hda_codec_amp_stereo(codec, 0x0e, HDA_INPUT, 1,
+				AMP_IN_MUTE(0), bits);
+}
+
+static void alc662_f5z_speaker_automute(struct hda_codec *codec)
+{
+	unsigned int present;
+	unsigned char bits;
+
+	present = snd_hda_codec_read(codec, 0x1b, 0,
+			AC_VERB_GET_PIN_SENSE, 0)
+			& AC_PINSENSE_PRESENCE;
+	bits = present ? 0 : PIN_OUT;
+	snd_hda_codec_write(codec, 0x14, 0,
+			 AC_VERB_SET_PIN_WIDGET_CONTROL, bits);
+}
+
+static void alc663_two_hp_m1_speaker_automute(struct hda_codec *codec)
+{
+	unsigned int present1, present2;
+
+	present1 = snd_hda_codec_read(codec, 0x21, 0,
+			AC_VERB_GET_PIN_SENSE, 0)
+			& AC_PINSENSE_PRESENCE;
+	present2 = snd_hda_codec_read(codec, 0x15, 0,
+			AC_VERB_GET_PIN_SENSE, 0)
+			& AC_PINSENSE_PRESENCE;
+
+	if (present1 || present2) {
+		snd_hda_codec_write_cache(codec, 0x14, 0,
+			AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
+	} else {
+		snd_hda_codec_write_cache(codec, 0x14, 0,
+			AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
+	}
+}
+
+static void alc663_two_hp_m2_speaker_automute(struct hda_codec *codec)
+{
+	unsigned int present1, present2;
+
+	present1 = snd_hda_codec_read(codec, 0x1b, 0,
+				AC_VERB_GET_PIN_SENSE, 0)
+				& AC_PINSENSE_PRESENCE;
+	present2 = snd_hda_codec_read(codec, 0x15, 0,
+				AC_VERB_GET_PIN_SENSE, 0)
+				& AC_PINSENSE_PRESENCE;
+
+	if (present1 || present2) {
+		snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
+				AMP_IN_MUTE(0), AMP_IN_MUTE(0));
+		snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
+				AMP_IN_MUTE(0), AMP_IN_MUTE(0));
+	} else {
+		snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
+				AMP_IN_MUTE(0), 0);
+		snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
+				AMP_IN_MUTE(0), 0);
+	}
 }
 
 static void alc663_m51va_mic_automute(struct hda_codec *codec)
@@ -14249,16 +15373,16 @@
 	unsigned int present;
 
 	present = snd_hda_codec_read(codec, 0x18, 0,
-				     AC_VERB_GET_PIN_SENSE, 0)
-		& AC_PINSENSE_PRESENCE;
+			AC_VERB_GET_PIN_SENSE, 0)
+			& AC_PINSENSE_PRESENCE;
 	snd_hda_codec_write_cache(codec, 0x22, 0, AC_VERB_SET_AMP_GAIN_MUTE,
-			    0x7000 | (0x00 << 8) | (present ? 0 : 0x80));
+			0x7000 | (0x00 << 8) | (present ? 0 : 0x80));
 	snd_hda_codec_write_cache(codec, 0x23, 0, AC_VERB_SET_AMP_GAIN_MUTE,
-			    0x7000 | (0x00 << 8) | (present ? 0 : 0x80));
+			0x7000 | (0x00 << 8) | (present ? 0 : 0x80));
 	snd_hda_codec_write_cache(codec, 0x22, 0, AC_VERB_SET_AMP_GAIN_MUTE,
-			    0x7000 | (0x09 << 8) | (present ? 0x80 : 0));
+			0x7000 | (0x09 << 8) | (present ? 0x80 : 0));
 	snd_hda_codec_write_cache(codec, 0x23, 0, AC_VERB_SET_AMP_GAIN_MUTE,
-			    0x7000 | (0x09 << 8) | (present ? 0x80 : 0));
+			0x7000 | (0x09 << 8) | (present ? 0x80 : 0));
 }
 
 static void alc663_m51va_unsol_event(struct hda_codec *codec,
@@ -14280,6 +15404,121 @@
 	alc663_m51va_mic_automute(codec);
 }
 
+/* ***************** Mode1 ******************************/
+static void alc663_mode1_unsol_event(struct hda_codec *codec,
+					   unsigned int res)
+{
+	switch (res >> 26) {
+	case ALC880_HP_EVENT:
+		alc663_m51va_speaker_automute(codec);
+		break;
+	case ALC880_MIC_EVENT:
+		alc662_eeepc_mic_automute(codec);
+		break;
+	}
+}
+
+static void alc663_mode1_inithook(struct hda_codec *codec)
+{
+	alc663_m51va_speaker_automute(codec);
+	alc662_eeepc_mic_automute(codec);
+}
+/* ***************** Mode2 ******************************/
+static void alc662_mode2_unsol_event(struct hda_codec *codec,
+					   unsigned int res)
+{
+	switch (res >> 26) {
+	case ALC880_HP_EVENT:
+		alc662_f5z_speaker_automute(codec);
+		break;
+	case ALC880_MIC_EVENT:
+		alc662_eeepc_mic_automute(codec);
+		break;
+	}
+}
+
+static void alc662_mode2_inithook(struct hda_codec *codec)
+{
+	alc662_f5z_speaker_automute(codec);
+	alc662_eeepc_mic_automute(codec);
+}
+/* ***************** Mode3 ******************************/
+static void alc663_mode3_unsol_event(struct hda_codec *codec,
+					   unsigned int res)
+{
+	switch (res >> 26) {
+	case ALC880_HP_EVENT:
+		alc663_two_hp_m1_speaker_automute(codec);
+		break;
+	case ALC880_MIC_EVENT:
+		alc662_eeepc_mic_automute(codec);
+		break;
+	}
+}
+
+static void alc663_mode3_inithook(struct hda_codec *codec)
+{
+	alc663_two_hp_m1_speaker_automute(codec);
+	alc662_eeepc_mic_automute(codec);
+}
+/* ***************** Mode4 ******************************/
+static void alc663_mode4_unsol_event(struct hda_codec *codec,
+					   unsigned int res)
+{
+	switch (res >> 26) {
+	case ALC880_HP_EVENT:
+		alc663_21jd_two_speaker_automute(codec);
+		break;
+	case ALC880_MIC_EVENT:
+		alc662_eeepc_mic_automute(codec);
+		break;
+	}
+}
+
+static void alc663_mode4_inithook(struct hda_codec *codec)
+{
+	alc663_21jd_two_speaker_automute(codec);
+	alc662_eeepc_mic_automute(codec);
+}
+/* ***************** Mode5 ******************************/
+static void alc663_mode5_unsol_event(struct hda_codec *codec,
+					   unsigned int res)
+{
+	switch (res >> 26) {
+	case ALC880_HP_EVENT:
+		alc663_15jd_two_speaker_automute(codec);
+		break;
+	case ALC880_MIC_EVENT:
+		alc662_eeepc_mic_automute(codec);
+		break;
+	}
+}
+
+static void alc663_mode5_inithook(struct hda_codec *codec)
+{
+	alc663_15jd_two_speaker_automute(codec);
+	alc662_eeepc_mic_automute(codec);
+}
+/* ***************** Mode6 ******************************/
+static void alc663_mode6_unsol_event(struct hda_codec *codec,
+					   unsigned int res)
+{
+	switch (res >> 26) {
+	case ALC880_HP_EVENT:
+		alc663_two_hp_m2_speaker_automute(codec);
+		break;
+	case ALC880_MIC_EVENT:
+		alc662_eeepc_mic_automute(codec);
+		break;
+	}
+}
+
+static void alc663_mode6_inithook(struct hda_codec *codec)
+{
+	alc663_two_hp_m2_speaker_automute(codec);
+	alc662_eeepc_mic_automute(codec);
+}
+
 static void alc663_g71v_hp_automute(struct hda_codec *codec)
 {
 	unsigned int present;
@@ -14350,6 +15589,46 @@
 	alc662_eeepc_mic_automute(codec);
 }
 
+/* bind hp and internal speaker mute (with plug check) */
+static int alc662_ecs_master_sw_put(struct snd_kcontrol *kcontrol,
+				     struct snd_ctl_elem_value *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	long *valp = ucontrol->value.integer.value;
+	int change;
+
+	change = snd_hda_codec_amp_update(codec, 0x1b, 0, HDA_OUTPUT, 0,
+					  HDA_AMP_MUTE,
+					  valp[0] ? 0 : HDA_AMP_MUTE);
+	change |= snd_hda_codec_amp_update(codec, 0x1b, 1, HDA_OUTPUT, 0,
+					   HDA_AMP_MUTE,
+					   valp[1] ? 0 : HDA_AMP_MUTE);
+	if (change)
+		alc262_hippo1_automute(codec);
+	return change;
+}
+
+static struct snd_kcontrol_new alc662_ecs_mixer[] = {
+	HDA_CODEC_VOLUME("Master Playback Volume", 0x02, 0x0, HDA_OUTPUT),
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Master Playback Switch",
+		.info = snd_hda_mixer_amp_switch_info,
+		.get = snd_hda_mixer_amp_switch_get,
+		.put = alc662_ecs_master_sw_put,
+		.private_value = HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT),
+	},
+
+	HDA_CODEC_VOLUME("e-Mic/LineIn Boost", 0x18, 0, HDA_INPUT),
+	HDA_CODEC_VOLUME("e-Mic/LineIn Playback Volume", 0x0b, 0x0, HDA_INPUT),
+	HDA_CODEC_MUTE("e-Mic/LineIn Playback Switch", 0x0b, 0x0, HDA_INPUT),
+
+	HDA_CODEC_VOLUME("i-Mic Boost", 0x19, 0, HDA_INPUT),
+	HDA_CODEC_VOLUME("i-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+	HDA_CODEC_MUTE("i-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
+	{ } /* end */
+};
+
 #ifdef CONFIG_SND_HDA_POWER_SAVE
 #define alc662_loopbacks	alc880_loopbacks
 #endif
@@ -14372,21 +15651,67 @@
 	[ALC662_LENOVO_101E]	= "lenovo-101e",
 	[ALC662_ASUS_EEEPC_P701] = "eeepc-p701",
 	[ALC662_ASUS_EEEPC_EP20] = "eeepc-ep20",
+	[ALC662_ECS] = "ecs",
 	[ALC663_ASUS_M51VA] = "m51va",
 	[ALC663_ASUS_G71V] = "g71v",
 	[ALC663_ASUS_H13] = "h13",
 	[ALC663_ASUS_G50V] = "g50v",
+	[ALC663_ASUS_MODE1] = "asus-mode1",
+	[ALC662_ASUS_MODE2] = "asus-mode2",
+	[ALC663_ASUS_MODE3] = "asus-mode3",
+	[ALC663_ASUS_MODE4] = "asus-mode4",
+	[ALC663_ASUS_MODE5] = "asus-mode5",
+	[ALC663_ASUS_MODE6] = "asus-mode6",
 	[ALC662_AUTO]		= "auto",
 };
 
 static struct snd_pci_quirk alc662_cfg_tbl[] = {
-	SND_PCI_QUIRK(0x1043, 0x11c3, "ASUS G71V", ALC663_ASUS_G71V),
 	SND_PCI_QUIRK(0x1043, 0x1878, "ASUS M51VA", ALC663_ASUS_M51VA),
 	SND_PCI_QUIRK(0x1043, 0x19a3, "ASUS M51VA", ALC663_ASUS_G50V),
 	SND_PCI_QUIRK(0x1043, 0x8290, "ASUS P5GC-MX", ALC662_3ST_6ch_DIG),
 	SND_PCI_QUIRK(0x1043, 0x82a1, "ASUS Eeepc", ALC662_ASUS_EEEPC_P701),
 	SND_PCI_QUIRK(0x1043, 0x82d1, "ASUS Eeepc EP20", ALC662_ASUS_EEEPC_EP20),
+	SND_PCI_QUIRK(0x1043, 0x1903, "ASUS F5GL", ALC663_ASUS_MODE1),
+	SND_PCI_QUIRK(0x1043, 0x1878, "ASUS M50Vr", ALC663_ASUS_MODE1),
+	SND_PCI_QUIRK(0x1043, 0x1000, "ASUS N50Vm", ALC663_ASUS_MODE1),
+	SND_PCI_QUIRK(0x1043, 0x19b3, "ASUS F7Z", ALC663_ASUS_MODE1),
+	SND_PCI_QUIRK(0x1043, 0x1953, "ASUS NB", ALC663_ASUS_MODE1),
+	SND_PCI_QUIRK(0x1043, 0x19a3, "ASUS NB", ALC663_ASUS_MODE1),
+	SND_PCI_QUIRK(0x1043, 0x11d3, "ASUS NB", ALC663_ASUS_MODE1),
+	SND_PCI_QUIRK(0x1043, 0x1203, "ASUS NB", ALC663_ASUS_MODE1),
+	SND_PCI_QUIRK(0x1043, 0x19e3, "ASUS NB", ALC663_ASUS_MODE1),
+	SND_PCI_QUIRK(0x1043, 0x19c3, "ASUS F5Z/F6x", ALC662_ASUS_MODE2),
+	SND_PCI_QUIRK(0x1043, 0x1339, "ASUS NB", ALC662_ASUS_MODE2),
+	SND_PCI_QUIRK(0x1043, 0x1913, "ASUS NB", ALC662_ASUS_MODE2),
+	SND_PCI_QUIRK(0x1043, 0x1843, "ASUS NB", ALC662_ASUS_MODE2),
+	SND_PCI_QUIRK(0x1043, 0x1813, "ASUS NB", ALC662_ASUS_MODE2),
+	SND_PCI_QUIRK(0x1043, 0x11f3, "ASUS NB", ALC662_ASUS_MODE2),
+	SND_PCI_QUIRK(0x1043, 0x1876, "ASUS NB", ALC662_ASUS_MODE2),
+	SND_PCI_QUIRK(0x1043, 0x1864, "ASUS NB", ALC662_ASUS_MODE2),
+	SND_PCI_QUIRK(0x1043, 0x1783, "ASUS NB", ALC662_ASUS_MODE2),
+	SND_PCI_QUIRK(0x1043, 0x1753, "ASUS NB", ALC662_ASUS_MODE2),
+	SND_PCI_QUIRK(0x1043, 0x16c3, "ASUS NB", ALC662_ASUS_MODE2),
+	SND_PCI_QUIRK(0x1043, 0x1933, "ASUS F80Q", ALC662_ASUS_MODE2),
+	SND_PCI_QUIRK(0x1043, 0x1893, "ASUS M50Vm", ALC663_ASUS_MODE3),
+	SND_PCI_QUIRK(0x1043, 0x11c3, "ASUS M70V", ALC663_ASUS_MODE3),
+	SND_PCI_QUIRK(0x1043, 0x1963, "ASUS X71C", ALC663_ASUS_MODE3),
+	SND_PCI_QUIRK(0x1043, 0x1894, "ASUS X55", ALC663_ASUS_MODE3),
+	SND_PCI_QUIRK(0x1043, 0x1092, "ASUS NB", ALC663_ASUS_MODE3),
+	SND_PCI_QUIRK(0x1043, 0x19f3, "ASUS NB", ALC663_ASUS_MODE4),
+	SND_PCI_QUIRK(0x1043, 0x1823, "ASUS NB", ALC663_ASUS_MODE5),
+	SND_PCI_QUIRK(0x1043, 0x1833, "ASUS NB", ALC663_ASUS_MODE6),
+	SND_PCI_QUIRK(0x1043, 0x1763, "ASUS NB", ALC663_ASUS_MODE6),
+	SND_PCI_QUIRK(0x1043, 0x1765, "ASUS NB", ALC663_ASUS_MODE6),
+	SND_PCI_QUIRK(0x105b, 0x0d47, "Foxconn 45CMX/45GMX/45CMX-K",
+		      ALC662_3ST_6ch_DIG),
 	SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo", ALC662_LENOVO_101E),
+	SND_PCI_QUIRK(0x1019, 0x9087, "ECS", ALC662_ECS),
+	SND_PCI_QUIRK(0x105b, 0x0cd6, "Foxconn", ALC662_ECS),
+	SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte 945GCM-S2L",
+		      ALC662_3ST_6ch_DIG),
+	SND_PCI_QUIRK(0x1565, 0x820f, "Biostar TA780G M2+", ALC662_3ST_6ch_DIG),
+	SND_PCI_QUIRK(0x1849, 0x3662, "ASROCK K10N78FullHD-hSLI R3.0",
+					ALC662_3ST_6ch_DIG),
 	SND_PCI_QUIRK(0x1854, 0x2000, "ASUS H13-2000", ALC663_ASUS_H13),
 	SND_PCI_QUIRK(0x1854, 0x2001, "ASUS H13-2001", ALC663_ASUS_H13),
 	SND_PCI_QUIRK(0x1854, 0x2002, "ASUS H13-2002", ALC663_ASUS_H13),
@@ -14477,6 +15802,18 @@
 		.unsol_event = alc662_eeepc_ep20_unsol_event,
 		.init_hook = alc662_eeepc_ep20_inithook,
 	},
+	[ALC662_ECS] = {
+		.mixers = { alc662_ecs_mixer, alc662_capture_mixer },
+		.init_verbs = { alc662_init_verbs,
+				alc662_ecs_init_verbs },
+		.num_dacs = ARRAY_SIZE(alc662_dac_nids),
+		.dac_nids = alc662_dac_nids,
+		.num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
+		.channel_mode = alc662_3ST_2ch_modes,
+		.input_mux = &alc662_eeepc_capture_source,
+		.unsol_event = alc662_eeepc_unsol_event,
+		.init_hook = alc662_eeepc_inithook,
+	},
 	[ALC663_ASUS_M51VA] = {
 		.mixers = { alc663_m51va_mixer, alc662_capture_mixer},
 		.init_verbs = { alc662_init_verbs, alc663_m51va_init_verbs },
@@ -14524,6 +15861,91 @@
 		.unsol_event = alc663_g50v_unsol_event,
 		.init_hook = alc663_g50v_inithook,
 	},
+	[ALC663_ASUS_MODE1] = {
+		.mixers = { alc663_m51va_mixer, alc662_auto_capture_mixer },
+		.init_verbs = { alc662_init_verbs,
+				alc663_21jd_amic_init_verbs },
+		.num_dacs = ARRAY_SIZE(alc662_dac_nids),
+		.hp_nid = 0x03,
+		.dac_nids = alc662_dac_nids,
+		.dig_out_nid = ALC662_DIGOUT_NID,
+		.num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
+		.channel_mode = alc662_3ST_2ch_modes,
+		.input_mux = &alc662_eeepc_capture_source,
+		.unsol_event = alc663_mode1_unsol_event,
+		.init_hook = alc663_mode1_inithook,
+	},
+	[ALC662_ASUS_MODE2] = {
+		.mixers = { alc662_1bjd_mixer, alc662_auto_capture_mixer },
+		.init_verbs = { alc662_init_verbs,
+				alc662_1bjd_amic_init_verbs },
+		.num_dacs = ARRAY_SIZE(alc662_dac_nids),
+		.dac_nids = alc662_dac_nids,
+		.dig_out_nid = ALC662_DIGOUT_NID,
+		.num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
+		.channel_mode = alc662_3ST_2ch_modes,
+		.input_mux = &alc662_eeepc_capture_source,
+		.unsol_event = alc662_mode2_unsol_event,
+		.init_hook = alc662_mode2_inithook,
+	},
+	[ALC663_ASUS_MODE3] = {
+		.mixers = { alc663_two_hp_m1_mixer, alc662_auto_capture_mixer },
+		.init_verbs = { alc662_init_verbs,
+				alc663_two_hp_amic_m1_init_verbs },
+		.num_dacs = ARRAY_SIZE(alc662_dac_nids),
+		.hp_nid = 0x03,
+		.dac_nids = alc662_dac_nids,
+		.dig_out_nid = ALC662_DIGOUT_NID,
+		.num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
+		.channel_mode = alc662_3ST_2ch_modes,
+		.input_mux = &alc662_eeepc_capture_source,
+		.unsol_event = alc663_mode3_unsol_event,
+		.init_hook = alc663_mode3_inithook,
+	},
+	[ALC663_ASUS_MODE4] = {
+		.mixers = { alc663_asus_21jd_clfe_mixer,
+				alc662_auto_capture_mixer},
+		.init_verbs = { alc662_init_verbs,
+				alc663_21jd_amic_init_verbs},
+		.num_dacs = ARRAY_SIZE(alc662_dac_nids),
+		.hp_nid = 0x03,
+		.dac_nids = alc662_dac_nids,
+		.dig_out_nid = ALC662_DIGOUT_NID,
+		.num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
+		.channel_mode = alc662_3ST_2ch_modes,
+		.input_mux = &alc662_eeepc_capture_source,
+		.unsol_event = alc663_mode4_unsol_event,
+		.init_hook = alc663_mode4_inithook,
+	},
+	[ALC663_ASUS_MODE5] = {
+		.mixers = { alc663_asus_15jd_clfe_mixer,
+				alc662_auto_capture_mixer },
+		.init_verbs = { alc662_init_verbs,
+				alc663_15jd_amic_init_verbs },
+		.num_dacs = ARRAY_SIZE(alc662_dac_nids),
+		.hp_nid = 0x03,
+		.dac_nids = alc662_dac_nids,
+		.dig_out_nid = ALC662_DIGOUT_NID,
+		.num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
+		.channel_mode = alc662_3ST_2ch_modes,
+		.input_mux = &alc662_eeepc_capture_source,
+		.unsol_event = alc663_mode5_unsol_event,
+		.init_hook = alc663_mode5_inithook,
+	},
+	[ALC663_ASUS_MODE6] = {
+		.mixers = { alc663_two_hp_m2_mixer, alc662_auto_capture_mixer },
+		.init_verbs = { alc662_init_verbs,
+				alc663_two_hp_amic_m2_init_verbs },
+		.num_dacs = ARRAY_SIZE(alc662_dac_nids),
+		.hp_nid = 0x03,
+		.dac_nids = alc662_dac_nids,
+		.dig_out_nid = ALC662_DIGOUT_NID,
+		.num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
+		.channel_mode = alc662_3ST_2ch_modes,
+		.input_mux = &alc662_eeepc_capture_source,
+		.unsol_event = alc663_mode6_unsol_event,
+		.init_hook = alc663_mode6_inithook,
+	},
 };
 
 
@@ -14560,15 +15982,15 @@
 							      HDA_OUTPUT));
 			if (err < 0)
 				return err;
-			err = add_control(spec, ALC_CTL_BIND_MUTE,
+			err = add_control(spec, ALC_CTL_WIDGET_MUTE,
 					  "Center Playback Switch",
-					  HDA_COMPOSE_AMP_VAL(nid, 1, 2,
+					  HDA_COMPOSE_AMP_VAL(0x0e, 1, 0,
 							      HDA_INPUT));
 			if (err < 0)
 				return err;
-			err = add_control(spec, ALC_CTL_BIND_MUTE,
+			err = add_control(spec, ALC_CTL_WIDGET_MUTE,
 					  "LFE Playback Switch",
-					  HDA_COMPOSE_AMP_VAL(nid, 2, 2,
+					  HDA_COMPOSE_AMP_VAL(0x0e, 2, 0,
 							      HDA_INPUT));
 			if (err < 0)
 				return err;
@@ -14580,9 +16002,9 @@
 			if (err < 0)
 				return err;
 			sprintf(name, "%s Playback Switch", chname[i]);
-			err = add_control(spec, ALC_CTL_BIND_MUTE, name,
-					  HDA_COMPOSE_AMP_VAL(nid, 3, 2,
-							      HDA_INPUT));
+			err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
+				HDA_COMPOSE_AMP_VAL(alc880_idx_to_mixer(i),
+						    3, 0, HDA_INPUT));
 			if (err < 0)
 				return err;
 		}
@@ -14777,7 +16199,7 @@
 
 	spec->num_mux_defs = 1;
 	spec->input_mux = &spec->private_imux;
-	
+
 	spec->init_verbs[spec->num_init_verbs++] = alc662_auto_init_verbs;
 	if (codec->vendor_id == 0x10ec0663)
 		spec->init_verbs[spec->num_init_verbs++] =
@@ -14896,6 +16318,8 @@
 	{ .id = 0x10ec0880, .name = "ALC880", .patch = patch_alc880 },
 	{ .id = 0x10ec0882, .name = "ALC882", .patch = patch_alc882 },
 	{ .id = 0x10ec0883, .name = "ALC883", .patch = patch_alc883 },
+	{ .id = 0x10ec0885, .rev = 0x100101, .name = "ALC889A",
+	  .patch = patch_alc882 }, /* should be patch_alc883() in future */
 	{ .id = 0x10ec0885, .rev = 0x100103, .name = "ALC889A",
 	  .patch = patch_alc882 }, /* should be patch_alc883() in future */
 	{ .id = 0x10ec0885, .name = "ALC885", .patch = patch_alc882 },
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c
index ad994fc..c590655 100644
--- a/sound/pci/hda/patch_sigmatel.c
+++ b/sound/pci/hda/patch_sigmatel.c
@@ -33,10 +33,12 @@
 #include "hda_codec.h"
 #include "hda_local.h"
 #include "hda_patch.h"
+#include "hda_beep.h"
 
 #define NUM_CONTROL_ALLOC	32
 #define STAC_PWR_EVENT		0x20
 #define STAC_HP_EVENT		0x30
+#define STAC_VREF_EVENT		0x40
 
 enum {
 	STAC_REF,
@@ -71,9 +73,15 @@
 };
 
 enum {
+	STAC_92HD83XXX_REF,
+	STAC_92HD83XXX_MODELS
+};
+
+enum {
 	STAC_92HD71BXX_REF,
 	STAC_DELL_M4_1,
 	STAC_DELL_M4_2,
+	STAC_HP_M4,
 	STAC_92HD71BXX_MODELS
 };
 
@@ -104,6 +112,7 @@
 	STAC_MACBOOK_PRO_V2,
 	STAC_IMAC_INTEL,
 	STAC_IMAC_INTEL_20,
+	STAC_ECS_202,
 	STAC_922X_DELL_D81,
 	STAC_922X_DELL_D82,
 	STAC_922X_DELL_M81,
@@ -130,6 +139,7 @@
 	unsigned int mic_switch: 1;
 	unsigned int alt_switch: 1;
 	unsigned int hp_detect: 1;
+	unsigned int spdif_mute: 1;
 
 	/* gpio lines */
 	unsigned int eapd_mask;
@@ -138,17 +148,22 @@
 	unsigned int gpio_data;
 	unsigned int gpio_mute;
 
+	/* stream */
+	unsigned int stream_delay;
+
 	/* analog loopback */
 	unsigned char aloopback_mask;
 	unsigned char aloopback_shift;
 
 	/* power management */
 	unsigned int num_pwrs;
+	unsigned int *pwr_mapping;
 	hda_nid_t *pwr_nids;
 	hda_nid_t *dac_list;
 
 	/* playback */
 	struct hda_input_mux *mono_mux;
+	struct hda_input_mux *amp_mux;
 	unsigned int cur_mmux;
 	struct hda_multi_out multiout;
 	hda_nid_t dac_nids[5];
@@ -162,8 +177,14 @@
 	unsigned int num_dmics;
 	hda_nid_t *dmux_nids;
 	unsigned int num_dmuxes;
+	hda_nid_t *smux_nids;
+	unsigned int num_smuxes;
+	const char **spdif_labels;
+
 	hda_nid_t dig_in_nid;
 	hda_nid_t mono_nid;
+	hda_nid_t anabeep_nid;
+	hda_nid_t digbeep_nid;
 
 	/* pin widgets */
 	hda_nid_t *pin_nids;
@@ -180,6 +201,12 @@
 	unsigned int cur_dmux[2];
 	struct hda_input_mux *input_mux;
 	unsigned int cur_mux[3];
+	struct hda_input_mux *sinput_mux;
+	unsigned int cur_smux[2];
+	unsigned int cur_amux;
+	hda_nid_t *amp_nids;
+	unsigned int num_amps;
+	unsigned int powerdown_adcs;
 
 	/* i/o switches */
 	unsigned int io_switch[2];
@@ -195,6 +222,8 @@
 	struct snd_kcontrol_new *kctl_alloc;
 	struct hda_input_mux private_dimux;
 	struct hda_input_mux private_imux;
+	struct hda_input_mux private_smux;
+	struct hda_input_mux private_amp_mux;
 	struct hda_input_mux private_mono_mux;
 };
 
@@ -215,10 +244,19 @@
 	0x0f, 0x10, 0x11
 };
 
+static hda_nid_t stac92hd73xx_slave_dig_outs[2] = {
+	0x26, 0,
+};
+
 static hda_nid_t stac92hd73xx_adc_nids[2] = {
 	0x1a, 0x1b
 };
 
+#define DELL_M6_AMP 2
+static hda_nid_t stac92hd73xx_amp_nids[3] = {
+	0x0b, 0x0c, 0x0e
+};
+
 #define STAC92HD73XX_NUM_DMICS	2
 static hda_nid_t stac92hd73xx_dmic_nids[STAC92HD73XX_NUM_DMICS + 1] = {
 	0x13, 0x14, 0
@@ -237,6 +275,41 @@
 	0x20, 0x21,
 };
 
+static hda_nid_t stac92hd73xx_smux_nids[2] = {
+	0x22, 0x23,
+};
+
+#define STAC92HD83XXX_NUM_DMICS	2
+static hda_nid_t stac92hd83xxx_dmic_nids[STAC92HD83XXX_NUM_DMICS + 1] = {
+	0x11, 0x12, 0
+};
+
+#define STAC92HD81_DAC_COUNT 2
+#define STAC92HD83_DAC_COUNT 3
+static hda_nid_t stac92hd83xxx_dac_nids[STAC92HD73_DAC_COUNT] = {
+	0x13, 0x14, 0x22,
+};
+
+static hda_nid_t stac92hd83xxx_dmux_nids[2] = {
+	0x17, 0x18,
+};
+
+static hda_nid_t stac92hd83xxx_adc_nids[2] = {
+	0x15, 0x16,
+};
+
+static hda_nid_t stac92hd83xxx_pwr_nids[4] = {
+	0xa, 0xb, 0xd, 0xe,
+};
+
+static hda_nid_t stac92hd83xxx_slave_dig_outs[2] = {
+	0x1e, 0,
+};
+
+static unsigned int stac92hd83xxx_pwr_mapping[4] = {
+	0x03, 0x0c, 0x10, 0x40,
+};
+
 static hda_nid_t stac92hd71bxx_pwr_nids[3] = {
 	0x0a, 0x0d, 0x0f
 };
@@ -249,8 +322,12 @@
 	0x1a, 0x1b
 };
 
-static hda_nid_t stac92hd71bxx_dmux_nids[1] = {
-	0x1c,
+static hda_nid_t stac92hd71bxx_dmux_nids[2] = {
+	0x1c, 0x1d,
+};
+
+static hda_nid_t stac92hd71bxx_smux_nids[2] = {
+	0x24, 0x25,
 };
 
 static hda_nid_t stac92hd71bxx_dac_nids[1] = {
@@ -262,6 +339,10 @@
 	0x18, 0x19, 0
 };
 
+static hda_nid_t stac92hd71bxx_slave_dig_outs[2] = {
+	0x22, 0
+};
+
 static hda_nid_t stac925x_adc_nids[1] = {
         0x03,
 };
@@ -299,6 +380,10 @@
         0x15, 0x16, 0x17
 };
 
+static hda_nid_t stac927x_smux_nids[1] = {
+	0x21,
+};
+
 static hda_nid_t stac927x_dac_nids[6] = {
 	0x02, 0x03, 0x04, 0x05, 0x06, 0
 };
@@ -312,6 +397,11 @@
 	0x13, 0x14, 0
 };
 
+static const char *stac927x_spdif_labels[5] = {
+	"Digital Playback", "ADAT", "Analog Mux 1",
+	"Analog Mux 2", "Analog Mux 3"
+};
+
 static hda_nid_t stac9205_adc_nids[2] = {
         0x12, 0x13
 };
@@ -324,6 +414,10 @@
 	0x1d,
 };
 
+static hda_nid_t stac9205_smux_nids[1] = {
+	0x21,
+};
+
 #define STAC9205_NUM_DMICS	2
 static hda_nid_t stac9205_dmic_nids[STAC9205_NUM_DMICS + 1] = {
         0x17, 0x18, 0
@@ -347,12 +441,18 @@
 static hda_nid_t stac92hd73xx_pin_nids[13] = {
 	0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
 	0x0f, 0x10, 0x11, 0x12, 0x13,
-	0x14, 0x1e, 0x22
+	0x14, 0x22, 0x23
 };
 
-static hda_nid_t stac92hd71bxx_pin_nids[10] = {
+static hda_nid_t stac92hd83xxx_pin_nids[14] = {
+	0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
+	0x0f, 0x10, 0x11, 0x12, 0x13,
+	0x1d, 0x1e, 0x1f, 0x20
+};
+static hda_nid_t stac92hd71bxx_pin_nids[11] = {
 	0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
 	0x0f, 0x14, 0x18, 0x19, 0x1e,
+	0x1f,
 };
 
 static hda_nid_t stac927x_pin_nids[14] = {
@@ -367,6 +467,34 @@
 	0x21, 0x22,
 };
 
+#define stac92xx_amp_volume_info snd_hda_mixer_amp_volume_info
+
+static int stac92xx_amp_volume_get(struct snd_kcontrol *kcontrol,
+				 struct snd_ctl_elem_value *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct sigmatel_spec *spec = codec->spec;
+	hda_nid_t nid = spec->amp_nids[spec->cur_amux];
+
+	kcontrol->private_value ^= get_amp_nid(kcontrol);
+	kcontrol->private_value |= nid;
+
+	return snd_hda_mixer_amp_volume_get(kcontrol, ucontrol);
+}
+
+static int stac92xx_amp_volume_put(struct snd_kcontrol *kcontrol,
+				 struct snd_ctl_elem_value *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct sigmatel_spec *spec = codec->spec;
+	hda_nid_t nid = spec->amp_nids[spec->cur_amux];
+
+	kcontrol->private_value ^= get_amp_nid(kcontrol);
+	kcontrol->private_value |= nid;
+
+	return snd_hda_mixer_amp_volume_put(kcontrol, ucontrol);
+}
+
 static int stac92xx_dmux_enum_info(struct snd_kcontrol *kcontrol,
 				   struct snd_ctl_elem_info *uinfo)
 {
@@ -397,6 +525,58 @@
 			spec->dmux_nids[dmux_idx], &spec->cur_dmux[dmux_idx]);
 }
 
+static int stac92xx_smux_enum_info(struct snd_kcontrol *kcontrol,
+				   struct snd_ctl_elem_info *uinfo)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct sigmatel_spec *spec = codec->spec;
+	return snd_hda_input_mux_info(spec->sinput_mux, uinfo);
+}
+
+static int stac92xx_smux_enum_get(struct snd_kcontrol *kcontrol,
+				  struct snd_ctl_elem_value *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct sigmatel_spec *spec = codec->spec;
+	unsigned int smux_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
+
+	ucontrol->value.enumerated.item[0] = spec->cur_smux[smux_idx];
+	return 0;
+}
+
+static int stac92xx_smux_enum_put(struct snd_kcontrol *kcontrol,
+				  struct snd_ctl_elem_value *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct sigmatel_spec *spec = codec->spec;
+	struct hda_input_mux *smux = &spec->private_smux;
+	unsigned int smux_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
+	int err, val;
+	hda_nid_t nid;
+
+	err = snd_hda_input_mux_put(codec, spec->sinput_mux, ucontrol,
+			spec->smux_nids[smux_idx], &spec->cur_smux[smux_idx]);
+	if (err < 0)
+		return err;
+
+	if (spec->spdif_mute) {
+		if (smux_idx == 0)
+			nid = spec->multiout.dig_out_nid;
+		else
+			nid = codec->slave_dig_outs[smux_idx - 1];
+		if (spec->cur_smux[smux_idx] == smux->num_items - 1)
+			val = AMP_OUT_MUTE;
+		if (smux_idx == 0)
+			nid = spec->multiout.dig_out_nid;
+		else
+			nid = codec->slave_dig_outs[smux_idx - 1];
+		/* un/mute SPDIF out */
+		snd_hda_codec_write_cache(codec, nid, 0,
+			AC_VERB_SET_AMP_GAIN_MUTE, val);
+	}
+	return 0;
+}
+
 static int stac92xx_mux_enum_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
 {
 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
@@ -452,6 +632,41 @@
 				     spec->mono_nid, &spec->cur_mmux);
 }
 
+static int stac92xx_amp_mux_enum_info(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_info *uinfo)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct sigmatel_spec *spec = codec->spec;
+	return snd_hda_input_mux_info(spec->amp_mux, uinfo);
+}
+
+static int stac92xx_amp_mux_enum_get(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct sigmatel_spec *spec = codec->spec;
+
+	ucontrol->value.enumerated.item[0] = spec->cur_amux;
+	return 0;
+}
+
+static int stac92xx_amp_mux_enum_put(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct sigmatel_spec *spec = codec->spec;
+	struct snd_kcontrol *ctl =
+		snd_hda_find_mixer_ctl(codec, "Amp Capture Volume");
+	if (!ctl)
+		return -EINVAL;
+
+	snd_ctl_notify(codec->bus->card, SNDRV_CTL_EVENT_MASK_VALUE |
+		SNDRV_CTL_EVENT_MASK_INFO, &ctl->id);
+
+	return snd_hda_input_mux_put(codec, spec->amp_mux, ucontrol,
+				     0, &spec->cur_amux);
+}
+
 #define stac92xx_aloopback_info snd_ctl_boolean_mono_info
 
 static int stac92xx_aloopback_get(struct snd_kcontrol *kcontrol,
@@ -546,8 +761,8 @@
 	{ 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xec},
 	/* setup audio connections */
 	{ 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00},
-	{ 0x0a, AC_VERB_SET_CONNECT_SEL, 0x01},
-	{ 0x0f, AC_VERB_SET_CONNECT_SEL, 0x02},
+	{ 0x0a, AC_VERB_SET_CONNECT_SEL, 0x02},
+	{ 0x0f, AC_VERB_SET_CONNECT_SEL, 0x01},
 	/* setup adcs to point to mixer */
 	{ 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b},
 	{ 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b},
@@ -628,25 +843,36 @@
 	{}
 };
 
+static struct hda_verb stac92hd83xxx_core_init[] = {
+	/* start of config #1 */
+	{ 0xe, AC_VERB_SET_CONNECT_SEL, 0x3},
+
+	/* start of config #2 */
+	{ 0xa, AC_VERB_SET_CONNECT_SEL, 0x0},
+	{ 0xb, AC_VERB_SET_CONNECT_SEL, 0x0},
+	{ 0xd, AC_VERB_SET_CONNECT_SEL, 0x1},
+
+	/* power state controls amps */
+	{ 0x01, AC_VERB_SET_EAPD, 1 << 2},
+};
+
 static struct hda_verb stac92hd71bxx_core_init[] = {
 	/* set master volume and direct control */
 	{ 0x28, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
 	/* connect headphone jack to dac1 */
 	{ 0x0a, AC_VERB_SET_CONNECT_SEL, 0x01},
-	{ 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Speaker */
 	/* unmute right and left channels for nodes 0x0a, 0xd, 0x0f */
 	{ 0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 	{ 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 	{ 0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 };
 
-#define HD_DISABLE_PORTF 3
+#define HD_DISABLE_PORTF 2
 static struct hda_verb stac92hd71bxx_analog_core_init[] = {
 	/* start of config #1 */
 
 	/* connect port 0f to audio mixer */
 	{ 0x0f, AC_VERB_SET_CONNECT_SEL, 0x2},
-	{ 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Speaker */
 	/* unmute right and left channels for node 0x0f */
 	{ 0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 	/* start of config #2 */
@@ -655,10 +881,6 @@
 	{ 0x28, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
 	/* connect headphone jack to dac1 */
 	{ 0x0a, AC_VERB_SET_CONNECT_SEL, 0x01},
-	/* connect port 0d to audio mixer */
-	{ 0x0d, AC_VERB_SET_CONNECT_SEL, 0x2},
-	/* unmute dac0 input in audio mixer */
-	{ 0x17, AC_VERB_SET_AMP_GAIN_MUTE, 0x701f},
 	/* unmute right and left channels for nodes 0x0a, 0xd */
 	{ 0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 	{ 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
@@ -690,12 +912,16 @@
 static struct hda_verb stac927x_core_init[] = {
 	/* set master volume and direct control */	
 	{ 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
+	/* enable analog pc beep path */
+	{ 0x01, AC_VERB_SET_DIGI_CONVERT_2, 1 << 5},
 	{}
 };
 
 static struct hda_verb stac9205_core_init[] = {
 	/* set master volume and direct control */	
 	{ 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
+	/* enable analog pc beep path */
+	{ 0x01, AC_VERB_SET_DIGI_CONVERT_2, 1 << 5},
 	{}
 };
 
@@ -709,6 +935,31 @@
 		.put = stac92xx_mono_mux_enum_put, \
 	}
 
+#define STAC_AMP_MUX \
+	{ \
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+		.name = "Amp Selector Capture Switch", \
+		.count = 1, \
+		.info = stac92xx_amp_mux_enum_info, \
+		.get = stac92xx_amp_mux_enum_get, \
+		.put = stac92xx_amp_mux_enum_put, \
+	}
+
+#define STAC_AMP_VOL(xname, nid, chs, idx, dir) \
+	{ \
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+		.name = xname, \
+		.index = 0, \
+		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \
+			SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
+			SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK, \
+		.info = stac92xx_amp_volume_info, \
+		.get = stac92xx_amp_volume_get, \
+		.put = stac92xx_amp_volume_put, \
+		.tlv = { .c = snd_hda_mixer_amp_tlv }, \
+		.private_value = HDA_COMPOSE_AMP_VAL(nid, chs, idx, dir) \
+	}
+
 #define STAC_INPUT_SOURCE(cnt) \
 	{ \
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
@@ -736,11 +987,28 @@
 	STAC_INPUT_SOURCE(1),
 	HDA_CODEC_VOLUME("Capture Volume", 0x0a, 0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Capture Switch", 0x0a, 0, HDA_OUTPUT),
-	HDA_CODEC_VOLUME("Capture Mux Volume", 0x0c, 0, HDA_OUTPUT),
 	{ } /* end */
 };
 
+#define DELL_M6_MIXER 6
 static struct snd_kcontrol_new stac92hd73xx_6ch_mixer[] = {
+	/* start of config #1 */
+	HDA_CODEC_VOLUME("Front Mic Mixer Capture Volume", 0x1d, 0, HDA_INPUT),
+	HDA_CODEC_MUTE("Front Mic Mixer Capture Switch", 0x1d, 0, HDA_INPUT),
+
+	HDA_CODEC_VOLUME("Line In Mixer Capture Volume", 0x1d, 0x2, HDA_INPUT),
+	HDA_CODEC_MUTE("Line In Mixer Capture Switch", 0x1d, 0x2, HDA_INPUT),
+
+	HDA_CODEC_VOLUME("CD Mixer Capture Volume", 0x1d, 0x4, HDA_INPUT),
+	HDA_CODEC_MUTE("CD Mixer Capture Switch", 0x1d, 0x4, HDA_INPUT),
+
+	/* start of config #2 */
+	HDA_CODEC_VOLUME("Mic Mixer Capture Volume", 0x1d, 0x1, HDA_INPUT),
+	HDA_CODEC_MUTE("Mic Mixer Capture Switch", 0x1d, 0x1, HDA_INPUT),
+
+	HDA_CODEC_VOLUME("DAC Mixer Capture Volume", 0x1d, 0x3, HDA_INPUT),
+	HDA_CODEC_MUTE("DAC Mixer Capture Switch", 0x1d, 0x3, HDA_INPUT),
+
 	STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 3),
 
 	HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x20, 0x0, HDA_OUTPUT),
@@ -749,20 +1017,6 @@
 	HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x21, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x21, 0x0, HDA_OUTPUT),
 
-	HDA_CODEC_VOLUME("Front Mic Mixer Capture Volume", 0x1d, 0, HDA_INPUT),
-	HDA_CODEC_MUTE("Front Mic Mixer Capture Switch", 0x1d, 0, HDA_INPUT),
-
-	HDA_CODEC_VOLUME("Mic Mixer Capture Volume", 0x1d, 0x1, HDA_INPUT),
-	HDA_CODEC_MUTE("Mic Mixer Capture Switch", 0x1d, 0x1, HDA_INPUT),
-
-	HDA_CODEC_VOLUME("Line In Mixer Capture Volume", 0x1d, 0x2, HDA_INPUT),
-	HDA_CODEC_MUTE("Line In Mixer Capture Switch", 0x1d, 0x2, HDA_INPUT),
-
-	HDA_CODEC_VOLUME("DAC Mixer Capture Volume", 0x1d, 0x3, HDA_INPUT),
-	HDA_CODEC_MUTE("DAC Mixer Capture Switch", 0x1d, 0x3, HDA_INPUT),
-
-	HDA_CODEC_VOLUME("CD Mixer Capture Volume", 0x1d, 0x4, HDA_INPUT),
-	HDA_CODEC_MUTE("CD Mixer Capture Switch", 0x1d, 0x4, HDA_INPUT),
 	{ } /* end */
 };
 
@@ -818,22 +1072,59 @@
 	{ } /* end */
 };
 
+
+static struct snd_kcontrol_new stac92hd83xxx_mixer[] = {
+	HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x17, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x17, 0x0, HDA_OUTPUT),
+
+	HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x18, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x18, 0x0, HDA_OUTPUT),
+
+	HDA_CODEC_VOLUME("DAC0 Capture Volume", 0x1b, 0, HDA_INPUT),
+	HDA_CODEC_MUTE("DAC0 Capture Switch", 0x1b, 0, HDA_INPUT),
+
+	HDA_CODEC_VOLUME("DAC1 Capture Volume", 0x1b, 0x1, HDA_INPUT),
+	HDA_CODEC_MUTE("DAC1 Capture Switch", 0x1b, 0x1, HDA_INPUT),
+
+	HDA_CODEC_VOLUME("Front Mic Capture Volume", 0x1b, 0x2, HDA_INPUT),
+	HDA_CODEC_MUTE("Front Mic Capture Switch", 0x1b, 0x2, HDA_INPUT),
+
+	HDA_CODEC_VOLUME("Line In Capture Volume", 0x1b, 0x3, HDA_INPUT),
+	HDA_CODEC_MUTE("Line In Capture Switch", 0x1b, 0x3, HDA_INPUT),
+
+	/*
+	HDA_CODEC_VOLUME("Mic Capture Volume", 0x1b, 0x4, HDA_INPUT),
+	HDA_CODEC_MUTE("Mic Capture Switch", 0x1b 0x4, HDA_INPUT),
+	*/
+	{ } /* end */
+};
+
 static struct snd_kcontrol_new stac92hd71bxx_analog_mixer[] = {
 	STAC_INPUT_SOURCE(2),
+	STAC_ANALOG_LOOPBACK(0xFA0, 0x7A0, 2),
 
 	HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1c, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1c, 0x0, HDA_OUTPUT),
-	HDA_CODEC_VOLUME_IDX("Capture Mux Volume", 0x0, 0x1a, 0x0, HDA_OUTPUT),
 
 	HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x1d, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1d, 0x0, HDA_OUTPUT),
-	HDA_CODEC_VOLUME_IDX("Capture Mux Volume", 0x1, 0x1b, 0x0, HDA_OUTPUT),
-
+	/* analog pc-beep replaced with digital beep support */
+	/*
 	HDA_CODEC_VOLUME("PC Beep Volume", 0x17, 0x2, HDA_INPUT),
 	HDA_CODEC_MUTE("PC Beep Switch", 0x17, 0x2, HDA_INPUT),
+	*/
 
-	HDA_CODEC_MUTE("Analog Loopback 1", 0x17, 0x3, HDA_INPUT),
-	HDA_CODEC_MUTE("Analog Loopback 2", 0x17, 0x4, HDA_INPUT),
+	HDA_CODEC_MUTE("Import0 Mux Capture Switch", 0x17, 0x0, HDA_INPUT),
+	HDA_CODEC_VOLUME("Import0 Mux Capture Volume", 0x17, 0x0, HDA_INPUT),
+
+	HDA_CODEC_MUTE("Import1 Mux Capture Switch", 0x17, 0x1, HDA_INPUT),
+	HDA_CODEC_VOLUME("Import1 Mux Capture Volume", 0x17, 0x1, HDA_INPUT),
+
+	HDA_CODEC_MUTE("DAC0 Capture Switch", 0x17, 0x3, HDA_INPUT),
+	HDA_CODEC_VOLUME("DAC0 Capture Volume", 0x17, 0x3, HDA_INPUT),
+
+	HDA_CODEC_MUTE("DAC1 Capture Switch", 0x17, 0x4, HDA_INPUT),
+	HDA_CODEC_VOLUME("DAC1 Capture Volume", 0x17, 0x4, HDA_INPUT),
 	{ } /* end */
 };
 
@@ -843,11 +1134,9 @@
 
 	HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1c, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1c, 0x0, HDA_OUTPUT),
-	HDA_CODEC_VOLUME_IDX("Capture Mux Volume", 0x0, 0x1a, 0x0, HDA_OUTPUT),
 
 	HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x1d, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1d, 0x0, HDA_OUTPUT),
-	HDA_CODEC_VOLUME_IDX("Capture Mux Volume", 0x1, 0x1b, 0x0, HDA_OUTPUT),
 	{ } /* end */
 };
 
@@ -855,7 +1144,6 @@
 	STAC_INPUT_SOURCE(1),
 	HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Capture Switch", 0x14, 0, HDA_OUTPUT),
-	HDA_CODEC_VOLUME("Capture Mux Volume", 0x0f, 0, HDA_OUTPUT),
 	{ } /* end */
 };
 
@@ -865,12 +1153,9 @@
 
 	HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1b, 0x0, HDA_INPUT),
 	HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1d, 0x0, HDA_OUTPUT),
-	HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x0, 0x19, 0x0, HDA_OUTPUT),
 
 	HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x1c, 0x0, HDA_INPUT),
 	HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1e, 0x0, HDA_OUTPUT),
-	HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x1, 0x1A, 0x0, HDA_OUTPUT),
-
 	{ } /* end */
 };
 
@@ -879,11 +1164,9 @@
 	STAC_INPUT_SOURCE(2),
 	HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x17, 0x0, HDA_INPUT),
 	HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x17, 0x0, HDA_INPUT),
-	HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x0, 0x12, 0x0, HDA_OUTPUT),
 
 	HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x18, 0x0, HDA_INPUT),
 	HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x18, 0x0, HDA_INPUT),
-	HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x1, 0x13, 0x0, HDA_OUTPUT),
 	{ } /* end */
 };
 
@@ -894,15 +1177,12 @@
 
 	HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x18, 0x0, HDA_INPUT),
 	HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1b, 0x0, HDA_OUTPUT),
-	HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x0, 0x15, 0x0, HDA_OUTPUT),
 
 	HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x19, 0x0, HDA_INPUT),
 	HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1c, 0x0, HDA_OUTPUT),
-	HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x1, 0x16, 0x0, HDA_OUTPUT),
 
 	HDA_CODEC_VOLUME_IDX("Capture Volume", 0x2, 0x1A, 0x0, HDA_INPUT),
 	HDA_CODEC_MUTE_IDX("Capture Switch", 0x2, 0x1d, 0x0, HDA_OUTPUT),
-	HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x2, 0x17, 0x0, HDA_OUTPUT),
 	{ } /* end */
 };
 
@@ -915,6 +1195,15 @@
 	.put = stac92xx_dmux_enum_put,
 };
 
+static struct snd_kcontrol_new stac_smux_mixer = {
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.name = "IEC958 Playback Source",
+	/* count set later */
+	.info = stac92xx_smux_enum_info,
+	.get = stac92xx_smux_enum_get,
+	.put = stac92xx_smux_enum_put,
+};
+
 static const char *slave_vols[] = {
 	"Front Playback Volume",
 	"Surround Playback Volume",
@@ -966,6 +1255,22 @@
 		if (err < 0)
 			return err;
 	}
+	if (spec->num_smuxes > 0) {
+		int wcaps = get_wcaps(codec, spec->multiout.dig_out_nid);
+		struct hda_input_mux *smux = &spec->private_smux;
+		/* check for mute support on SPDIF out */
+		if (wcaps & AC_WCAP_OUT_AMP) {
+			smux->items[smux->num_items].label = "Off";
+			smux->items[smux->num_items].index = 0;
+			smux->num_items++;
+			spec->spdif_mute = 1;
+		}
+		stac_smux_mixer.count = spec->num_smuxes;
+		err = snd_ctl_add(codec->bus->card,
+				  snd_ctl_new1(&stac_smux_mixer, codec));
+		if (err < 0)
+			return err;
+	}
 
 	if (spec->multiout.dig_out_nid) {
 		err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid);
@@ -977,7 +1282,7 @@
 			return err;
 		spec->multiout.share_spdif = 1;
 	}
-	if (spec->dig_in_nid) {
+	if (spec->dig_in_nid && (!spec->gpio_dir & 0x01)) {
 		err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
 		if (err < 0)
 			return err;
@@ -1325,40 +1630,65 @@
 	{} /* terminator */
 };
 
-static unsigned int ref92hd71bxx_pin_configs[10] = {
-	0x02214030, 0x02a19040, 0x01a19020, 0x01014010,
-	0x0181302e, 0x01114010, 0x01019020, 0x90a000f0,
-	0x90a000f0, 0x01452050,
+static unsigned int ref92hd83xxx_pin_configs[14] = {
+	0x02214030, 0x02211010, 0x02a19020, 0x02170130,
+	0x01014050, 0x01819040, 0x01014020, 0x90a3014e,
+	0x40f000f0, 0x40f000f0, 0x40f000f0, 0x40f000f0,
+	0x01451160, 0x98560170,
 };
 
-static unsigned int dell_m4_1_pin_configs[10] = {
+static unsigned int *stac92hd83xxx_brd_tbl[STAC_92HD83XXX_MODELS] = {
+	[STAC_92HD83XXX_REF] = ref92hd83xxx_pin_configs,
+};
+
+static const char *stac92hd83xxx_models[STAC_92HD83XXX_MODELS] = {
+	[STAC_92HD83XXX_REF] = "ref",
+};
+
+static struct snd_pci_quirk stac92hd83xxx_cfg_tbl[] = {
+	/* SigmaTel reference board */
+	SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
+		      "DFI LanParty", STAC_92HD71BXX_REF),
+};
+
+static unsigned int ref92hd71bxx_pin_configs[11] = {
+	0x02214030, 0x02a19040, 0x01a19020, 0x01014010,
+	0x0181302e, 0x01014010, 0x01019020, 0x90a000f0,
+	0x90a000f0, 0x01452050, 0x01452050,
+};
+
+static unsigned int dell_m4_1_pin_configs[11] = {
 	0x0421101f, 0x04a11221, 0x40f000f0, 0x90170110,
 	0x23a1902e, 0x23014250, 0x40f000f0, 0x90a000f0,
-	0x40f000f0, 0x4f0000f0,
+	0x40f000f0, 0x4f0000f0, 0x4f0000f0,
 };
 
-static unsigned int dell_m4_2_pin_configs[10] = {
+static unsigned int dell_m4_2_pin_configs[11] = {
 	0x0421101f, 0x04a11221, 0x90a70330, 0x90170110,
 	0x23a1902e, 0x23014250, 0x40f000f0, 0x40f000f0,
-	0x40f000f0, 0x044413b0,
+	0x40f000f0, 0x044413b0, 0x044413b0,
 };
 
 static unsigned int *stac92hd71bxx_brd_tbl[STAC_92HD71BXX_MODELS] = {
 	[STAC_92HD71BXX_REF] = ref92hd71bxx_pin_configs,
 	[STAC_DELL_M4_1]	= dell_m4_1_pin_configs,
 	[STAC_DELL_M4_2]	= dell_m4_2_pin_configs,
+	[STAC_HP_M4]		= NULL,
 };
 
 static const char *stac92hd71bxx_models[STAC_92HD71BXX_MODELS] = {
 	[STAC_92HD71BXX_REF] = "ref",
 	[STAC_DELL_M4_1] = "dell-m4-1",
 	[STAC_DELL_M4_2] = "dell-m4-2",
+	[STAC_HP_M4] = "hp-m4",
 };
 
 static struct snd_pci_quirk stac92hd71bxx_cfg_tbl[] = {
 	/* SigmaTel reference board */
 	SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
 		      "DFI LanParty", STAC_92HD71BXX_REF),
+	SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x361a,
+				"unknown HP", STAC_HP_M4),
 	SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0233,
 				"unknown Dell", STAC_DELL_M4_1),
 	SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0234,
@@ -1477,6 +1807,11 @@
 	0x400000fc, 0x400000fb,
 };
 
+static unsigned int ecs202_pin_configs[10] = {
+	0x0221401f, 0x02a19020, 0x01a19020, 0x01114010,
+	0x408000f0, 0x01813022, 0x074510a0, 0x40c400f1,
+	0x9037012e, 0x40e000f2,
+};
 
 static unsigned int *stac922x_brd_tbl[STAC_922X_MODELS] = {
 	[STAC_D945_REF] = ref922x_pin_configs,
@@ -1495,6 +1830,7 @@
 	[STAC_MACBOOK_PRO_V2] = intel_mac_v3_pin_configs,
 	[STAC_IMAC_INTEL] = intel_mac_v2_pin_configs,
 	[STAC_IMAC_INTEL_20] = intel_mac_v3_pin_configs,
+	[STAC_ECS_202] = ecs202_pin_configs,
 	[STAC_922X_DELL_D81] = dell_922x_d81_pin_configs,
 	[STAC_922X_DELL_D82] = dell_922x_d82_pin_configs,	
 	[STAC_922X_DELL_M81] = dell_922x_m81_pin_configs,
@@ -1518,6 +1854,7 @@
 	[STAC_MACBOOK_PRO_V2]	= "macbook-pro",
 	[STAC_IMAC_INTEL] = "imac-intel",
 	[STAC_IMAC_INTEL_20] = "imac-intel-20",
+	[STAC_ECS_202] = "ecs202",
 	[STAC_922X_DELL_D81] = "dell-d81",
 	[STAC_922X_DELL_D82] = "dell-d82",
 	[STAC_922X_DELL_M81] = "dell-m81",
@@ -1604,6 +1941,33 @@
 		      "unknown Dell", STAC_922X_DELL_D81),
 	SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d7,
 		      "Dell XPS M1210", STAC_922X_DELL_M82),
+	/* ECS/PC Chips boards */
+	SND_PCI_QUIRK(0x1019, 0x2144,
+		      "ECS/PC chips", STAC_ECS_202),
+	SND_PCI_QUIRK(0x1019, 0x2608,
+		      "ECS/PC chips", STAC_ECS_202),
+	SND_PCI_QUIRK(0x1019, 0x2633,
+		      "ECS/PC chips P17G/1333", STAC_ECS_202),
+	SND_PCI_QUIRK(0x1019, 0x2811,
+		      "ECS/PC chips", STAC_ECS_202),
+	SND_PCI_QUIRK(0x1019, 0x2812,
+		      "ECS/PC chips", STAC_ECS_202),
+	SND_PCI_QUIRK(0x1019, 0x2813,
+		      "ECS/PC chips", STAC_ECS_202),
+	SND_PCI_QUIRK(0x1019, 0x2814,
+		      "ECS/PC chips", STAC_ECS_202),
+	SND_PCI_QUIRK(0x1019, 0x2815,
+		      "ECS/PC chips", STAC_ECS_202),
+	SND_PCI_QUIRK(0x1019, 0x2816,
+		      "ECS/PC chips", STAC_ECS_202),
+	SND_PCI_QUIRK(0x1019, 0x2817,
+		      "ECS/PC chips", STAC_ECS_202),
+	SND_PCI_QUIRK(0x1019, 0x2818,
+		      "ECS/PC chips", STAC_ECS_202),
+	SND_PCI_QUIRK(0x1019, 0x2819,
+		      "ECS/PC chips", STAC_ECS_202),
+	SND_PCI_QUIRK(0x1019, 0x2820,
+		      "ECS/PC chips", STAC_ECS_202),
 	{} /* terminator */
 };
 
@@ -1683,8 +2047,8 @@
 	/* Dell 3 stack systems with verb table in BIOS */
 	SND_PCI_QUIRK(PCI_VENDOR_ID_DELL,  0x01f3, "Dell Inspiron 1420", STAC_DELL_BIOS),
 	SND_PCI_QUIRK(PCI_VENDOR_ID_DELL,  0x0227, "Dell Vostro 1400  ", STAC_DELL_BIOS),
-	SND_PCI_QUIRK(PCI_VENDOR_ID_DELL,  0x022f, "Dell     ", STAC_DELL_BIOS),
 	SND_PCI_QUIRK(PCI_VENDOR_ID_DELL,  0x022e, "Dell     ", STAC_DELL_BIOS),
+	SND_PCI_QUIRK(PCI_VENDOR_ID_DELL,  0x022f, "Dell Inspiron 1525", STAC_DELL_3ST),
 	SND_PCI_QUIRK(PCI_VENDOR_ID_DELL,  0x0242, "Dell     ", STAC_DELL_BIOS),
 	SND_PCI_QUIRK(PCI_VENDOR_ID_DELL,  0x0243, "Dell     ", STAC_DELL_BIOS),
 	SND_PCI_QUIRK(PCI_VENDOR_ID_DELL,  0x02ff, "Dell     ", STAC_DELL_BIOS),
@@ -1867,6 +2231,8 @@
 				      struct snd_pcm_substream *substream)
 {
 	struct sigmatel_spec *spec = codec->spec;
+	if (spec->stream_delay)
+		msleep(spec->stream_delay);
 	return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream,
 					     hinfo);
 }
@@ -1930,9 +2296,14 @@
 					struct snd_pcm_substream *substream)
 {
 	struct sigmatel_spec *spec = codec->spec;
+	hda_nid_t nid = spec->adc_nids[substream->number];
 
-	snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number],
-                                   stream_tag, 0, format);
+	if (spec->powerdown_adcs) {
+		msleep(40);
+		snd_hda_codec_write_cache(codec, nid, 0,
+			AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
+	}
+	snd_hda_codec_setup_stream(codec, nid, stream_tag, 0, format);
 	return 0;
 }
 
@@ -1941,8 +2312,12 @@
 					struct snd_pcm_substream *substream)
 {
 	struct sigmatel_spec *spec = codec->spec;
+	hda_nid_t nid = spec->adc_nids[substream->number];
 
-	snd_hda_codec_cleanup_stream(codec, spec->adc_nids[substream->number]);
+	snd_hda_codec_cleanup_stream(codec, nid);
+	if (spec->powerdown_adcs)
+		snd_hda_codec_write_cache(codec, nid, 0,
+			AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
 	return 0;
 }
 
@@ -2193,6 +2568,8 @@
 	STAC_CTL_WIDGET_VOL,
 	STAC_CTL_WIDGET_MUTE,
 	STAC_CTL_WIDGET_MONO_MUX,
+	STAC_CTL_WIDGET_AMP_MUX,
+	STAC_CTL_WIDGET_AMP_VOL,
 	STAC_CTL_WIDGET_HP_SWITCH,
 	STAC_CTL_WIDGET_IO_SWITCH,
 	STAC_CTL_WIDGET_CLFE_SWITCH
@@ -2202,13 +2579,16 @@
 	HDA_CODEC_VOLUME(NULL, 0, 0, 0),
 	HDA_CODEC_MUTE(NULL, 0, 0, 0),
 	STAC_MONO_MUX,
+	STAC_AMP_MUX,
+	STAC_AMP_VOL(NULL, 0, 0, 0, 0),
 	STAC_CODEC_HP_SWITCH(NULL),
 	STAC_CODEC_IO_SWITCH(NULL, 0),
 	STAC_CODEC_CLFE_SWITCH(NULL, 0),
 };
 
 /* add dynamic controls */
-static int stac92xx_add_control(struct sigmatel_spec *spec, int type, const char *name, unsigned long val)
+static int stac92xx_add_control_idx(struct sigmatel_spec *spec, int type,
+		int idx, const char *name, unsigned long val)
 {
 	struct snd_kcontrol_new *knew;
 
@@ -2228,6 +2608,7 @@
 
 	knew = &spec->kctl_alloc[spec->num_kctl_used];
 	*knew = stac92xx_control_templates[type];
+	knew->index = idx;
 	knew->name = kstrdup(name, GFP_KERNEL);
 	if (! knew->name)
 		return -ENOMEM;
@@ -2236,6 +2617,14 @@
 	return 0;
 }
 
+
+/* add dynamic controls */
+static int stac92xx_add_control(struct sigmatel_spec *spec, int type,
+		const char *name, unsigned long val)
+{
+	return stac92xx_add_control_idx(spec, type, 0, name, val);
+}
+
 /* flag inputs as additional dynamic lineouts */
 static int stac92xx_add_dyn_out_pins(struct hda_codec *codec, struct auto_pin_cfg *cfg)
 {
@@ -2467,6 +2856,10 @@
 		}
 	}
 
+	if ((spec->multiout.num_dacs - cfg->line_outs) > 0 &&
+			cfg->hp_outs && !spec->multiout.hp_nid)
+		spec->multiout.hp_nid = nid;
+
 	if (cfg->hp_outs > 1) {
 		err = stac92xx_add_control(spec,
 			STAC_CTL_WIDGET_HP_SWITCH,
@@ -2579,8 +2972,8 @@
 }
 
 /* labels for mono mux outputs */
-static const char *stac92xx_mono_labels[3] = {
-	"DAC0", "DAC1", "Mixer"
+static const char *stac92xx_mono_labels[4] = {
+	"DAC0", "DAC1", "Mixer", "DAC2"
 };
 
 /* create mono mux for mono out on capable codecs */
@@ -2609,6 +3002,116 @@
 				"Mono Mux", spec->mono_nid);
 }
 
+/* labels for amp mux outputs */
+static const char *stac92xx_amp_labels[3] = {
+	"Front Microphone", "Microphone", "Line In",
+};
+
+/* create amp out controls mux on capable codecs */
+static int stac92xx_auto_create_amp_output_ctls(struct hda_codec *codec)
+{
+	struct sigmatel_spec *spec = codec->spec;
+	struct hda_input_mux *amp_mux = &spec->private_amp_mux;
+	int i, err;
+
+	for (i = 0; i < spec->num_amps; i++) {
+		amp_mux->items[amp_mux->num_items].label =
+					stac92xx_amp_labels[i];
+		amp_mux->items[amp_mux->num_items].index = i;
+		amp_mux->num_items++;
+	}
+
+	if (spec->num_amps > 1) {
+		err = stac92xx_add_control(spec, STAC_CTL_WIDGET_AMP_MUX,
+			"Amp Selector Capture Switch", 0);
+		if (err < 0)
+			return err;
+	}
+	return stac92xx_add_control(spec, STAC_CTL_WIDGET_AMP_VOL,
+		"Amp Capture Volume",
+		HDA_COMPOSE_AMP_VAL(spec->amp_nids[0], 3, 0, HDA_INPUT));
+}
+
+
+/* create PC beep volume controls */
+static int stac92xx_auto_create_beep_ctls(struct hda_codec *codec,
+						hda_nid_t nid)
+{
+	struct sigmatel_spec *spec = codec->spec;
+	u32 caps = query_amp_caps(codec, nid, HDA_OUTPUT);
+	int err;
+
+	/* check for mute support for the the amp */
+	if ((caps & AC_AMPCAP_MUTE) >> AC_AMPCAP_MUTE_SHIFT) {
+		err = stac92xx_add_control(spec, STAC_CTL_WIDGET_MUTE,
+			"PC Beep Playback Switch",
+			HDA_COMPOSE_AMP_VAL(nid, 1, 0, HDA_OUTPUT));
+			if (err < 0)
+				return err;
+	}
+
+	/* check to see if there is volume support for the amp */
+	if ((caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT) {
+		err = stac92xx_add_control(spec, STAC_CTL_WIDGET_VOL,
+			"PC Beep Playback Volume",
+			HDA_COMPOSE_AMP_VAL(nid, 1, 0, HDA_OUTPUT));
+			if (err < 0)
+				return err;
+	}
+	return 0;
+}
+
+static int stac92xx_auto_create_mux_input_ctls(struct hda_codec *codec)
+{
+	struct sigmatel_spec *spec = codec->spec;
+	int wcaps, nid, i, err = 0;
+
+	for (i = 0; i < spec->num_muxes; i++) {
+		nid = spec->mux_nids[i];
+		wcaps = get_wcaps(codec, nid);
+
+		if (wcaps & AC_WCAP_OUT_AMP) {
+			err = stac92xx_add_control_idx(spec,
+				STAC_CTL_WIDGET_VOL, i, "Mux Capture Volume",
+				HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
+			if (err < 0)
+				return err;
+		}
+	}
+	return 0;
+};
+
+static const char *stac92xx_spdif_labels[3] = {
+	"Digital Playback", "Analog Mux 1", "Analog Mux 2",
+};
+
+static int stac92xx_auto_create_spdif_mux_ctls(struct hda_codec *codec)
+{
+	struct sigmatel_spec *spec = codec->spec;
+	struct hda_input_mux *spdif_mux = &spec->private_smux;
+	const char **labels = spec->spdif_labels;
+	int i, num_cons;
+	hda_nid_t con_lst[HDA_MAX_NUM_INPUTS];
+
+	num_cons = snd_hda_get_connections(codec,
+				spec->smux_nids[0],
+				con_lst,
+				HDA_MAX_NUM_INPUTS);
+	if (!num_cons)
+		return -EINVAL;
+
+	if (!labels)
+		labels = stac92xx_spdif_labels;
+
+	for (i = 0; i < num_cons; i++) {
+		spdif_mux->items[spdif_mux->num_items].label = labels[i];
+		spdif_mux->items[spdif_mux->num_items].index = i;
+		spdif_mux->num_items++;
+	}
+
+	return 0;
+}
+
 /* labels for dmic mux inputs */
 static const char *stac92xx_dmic_labels[5] = {
 	"Analog Inputs", "Digital Mic 1", "Digital Mic 2",
@@ -2656,16 +3159,19 @@
 			}
 		continue;
 found:
-		wcaps = get_wcaps(codec, nid);
+		wcaps = get_wcaps(codec, nid) &
+			(AC_WCAP_OUT_AMP | AC_WCAP_IN_AMP);
 
-		if (wcaps & AC_WCAP_OUT_AMP) {
+		if (wcaps) {
 			sprintf(name, "%s Capture Volume",
 				stac92xx_dmic_labels[dimux->num_items]);
 
 			err = stac92xx_add_control(spec,
 				STAC_CTL_WIDGET_VOL,
 				name,
-				HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
+				HDA_COMPOSE_AMP_VAL(nid, 3, 0,
+				(wcaps & AC_WCAP_OUT_AMP) ?
+				HDA_OUTPUT : HDA_INPUT));
 			if (err < 0)
 				return err;
 		}
@@ -2789,8 +3295,8 @@
 		hp_speaker_swap = 1;
 	}
 	if (spec->autocfg.mono_out_pin) {
-		int dir = (get_wcaps(codec, spec->autocfg.mono_out_pin)
-				& AC_WCAP_OUT_AMP) ? HDA_OUTPUT : HDA_INPUT;
+		int dir = get_wcaps(codec, spec->autocfg.mono_out_pin) &
+			(AC_WCAP_OUT_AMP | AC_WCAP_IN_AMP);
 		u32 caps = query_amp_caps(codec,
 				spec->autocfg.mono_out_pin, dir);
 		hda_nid_t conn_list[1];
@@ -2812,21 +3318,26 @@
 						!(wcaps & AC_WCAP_LR_SWAP))
 					spec->mono_nid = conn_list[0];
 		}
-		/* all mono outs have a least a mute/unmute switch */
-		err = stac92xx_add_control(spec, STAC_CTL_WIDGET_MUTE,
-			"Mono Playback Switch",
-			HDA_COMPOSE_AMP_VAL(spec->autocfg.mono_out_pin,
-					1, 0, dir));
-		if (err < 0)
-			return err;
-		/* check to see if there is volume support for the amp */
-		if ((caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT) {
-			err = stac92xx_add_control(spec, STAC_CTL_WIDGET_VOL,
-				"Mono Playback Volume",
-				HDA_COMPOSE_AMP_VAL(spec->autocfg.mono_out_pin,
-					1, 0, dir));
+		if (dir) {
+			hda_nid_t nid = spec->autocfg.mono_out_pin;
+
+			/* most mono outs have a least a mute/unmute switch */
+			dir = (dir & AC_WCAP_OUT_AMP) ? HDA_OUTPUT : HDA_INPUT;
+			err = stac92xx_add_control(spec, STAC_CTL_WIDGET_MUTE,
+				"Mono Playback Switch",
+				HDA_COMPOSE_AMP_VAL(nid, 1, 0, dir));
 			if (err < 0)
 				return err;
+			/* check for volume support for the amp */
+			if ((caps & AC_AMPCAP_NUM_STEPS)
+					>> AC_AMPCAP_NUM_STEPS_SHIFT) {
+				err = stac92xx_add_control(spec,
+					STAC_CTL_WIDGET_VOL,
+					"Mono Playback Volume",
+				HDA_COMPOSE_AMP_VAL(nid, 1, 0, dir));
+				if (err < 0)
+					return err;
+			}
 		}
 
 		stac92xx_auto_set_pinctl(codec, spec->autocfg.mono_out_pin,
@@ -2844,6 +3355,28 @@
 	if (err < 0)
 		return err;
 
+	/* setup analog beep controls */
+	if (spec->anabeep_nid > 0) {
+		err = stac92xx_auto_create_beep_ctls(codec,
+			spec->anabeep_nid);
+		if (err < 0)
+			return err;
+	}
+
+	/* setup digital beep controls and input device */
+#ifdef CONFIG_SND_HDA_INPUT_BEEP
+	if (spec->digbeep_nid > 0) {
+		hda_nid_t nid = spec->digbeep_nid;
+
+		err = stac92xx_auto_create_beep_ctls(codec, nid);
+		if (err < 0)
+			return err;
+		err = snd_hda_attach_beep_device(codec, nid);
+		if (err < 0)
+			return err;
+	}
+#endif
+
 	if (hp_speaker_swap == 1) {
 		/* Restore the hp_outs and line_outs */
 		memcpy(spec->autocfg.hp_pins, spec->autocfg.line_out_pins,
@@ -2872,11 +3405,25 @@
 		if (err < 0)
 			return err;
 	}
-
-	if (spec->num_dmics > 0)
+	if (spec->num_amps > 0) {
+		err = stac92xx_auto_create_amp_output_ctls(codec);
+		if (err < 0)
+			return err;
+	}
+	if (spec->num_dmics > 0 && !spec->dinput_mux)
 		if ((err = stac92xx_auto_create_dmic_input_ctls(codec,
 						&spec->autocfg)) < 0)
 			return err;
+	if (spec->num_muxes > 0) {
+		err = stac92xx_auto_create_mux_input_ctls(codec);
+		if (err < 0)
+			return err;
+	}
+	if (spec->num_smuxes > 0) {
+		err = stac92xx_auto_create_spdif_mux_ctls(codec);
+		if (err < 0)
+			return err;
+	}
 
 	spec->multiout.max_channels = spec->multiout.num_dacs * 2;
 	if (spec->multiout.max_channels > 2)
@@ -2884,17 +3431,17 @@
 
 	if (spec->autocfg.dig_out_pin)
 		spec->multiout.dig_out_nid = dig_out;
-	if (spec->autocfg.dig_in_pin)
+	if (dig_in && spec->autocfg.dig_in_pin)
 		spec->dig_in_nid = dig_in;
 
 	if (spec->kctl_alloc)
 		spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
 
 	spec->input_mux = &spec->private_imux;
-	if (!spec->dinput_mux)
-		spec->dinput_mux = &spec->private_dimux;
+	spec->dinput_mux = &spec->private_dimux;
+	spec->sinput_mux = &spec->private_smux;
 	spec->mono_mux = &spec->private_mono_mux;
-
+	spec->amp_mux = &spec->private_amp_mux;
 	return 1;
 }
 
@@ -3074,6 +3621,12 @@
 
 	snd_hda_sequence_write(codec, spec->init);
 
+	/* power down adcs initially */
+	if (spec->powerdown_adcs)
+		for (i = 0; i < spec->num_adcs; i++)
+			snd_hda_codec_write_cache(codec,
+				spec->adc_nids[i], 0,
+				AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
 	/* set up pins */
 	if (spec->hp_detect) {
 		/* Enable unsolicited responses on the HP widget */
@@ -3095,7 +3648,12 @@
 	for (i = 0; i < AUTO_PIN_LAST; i++) {
 		hda_nid_t nid = cfg->input_pins[i];
 		if (nid) {
-			unsigned int pinctl = AC_PINCTL_IN_EN;
+			unsigned int pinctl = snd_hda_codec_read(codec, nid,
+				0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
+			/* if PINCTL already set then skip */
+			if (pinctl & AC_PINCAP_IN)
+				continue;
+			pinctl = AC_PINCTL_IN_EN;
 			if (i == AUTO_PIN_MIC || i == AUTO_PIN_FRONT_MIC)
 				pinctl |= stac92xx_get_vref(codec, nid);
 			stac92xx_auto_set_pinctl(codec, nid, pinctl);
@@ -3158,6 +3716,7 @@
 		kfree(spec->bios_pin_configs);
 
 	kfree(spec);
+	snd_hda_detach_beep_device(codec);
 }
 
 static void stac92xx_set_pinctl(struct hda_codec *codec, hda_nid_t nid,
@@ -3279,7 +3838,12 @@
 	val = snd_hda_codec_read(codec, codec->afg, 0, 0x0fec, 0x0)
 							& 0x000000ff;
 	presence = get_hp_pin_presence(codec, nid);
-	idx = 1 << idx;
+
+	/* several codecs have two power down bits */
+	if (spec->pwr_mapping)
+		idx = spec->pwr_mapping[idx];
+	else
+		idx = 1 << idx;
 
 	if (presence)
 		val &= ~idx;
@@ -3295,13 +3859,22 @@
 	struct sigmatel_spec *spec = codec->spec;
 	int idx = res >> 26 & 0x0f;
 
-	switch ((res >> 26) & 0x30) {
+	switch ((res >> 26) & 0x70) {
 	case STAC_HP_EVENT:
 		stac92xx_hp_detect(codec, res);
 		/* fallthru */
 	case STAC_PWR_EVENT:
 		if (spec->num_pwrs > 0)
 			stac92xx_pin_sense(codec, idx);
+		break;
+	case STAC_VREF_EVENT: {
+		int data = snd_hda_codec_read(codec, codec->afg, 0,
+			AC_VERB_GET_GPIO_DATA, 0);
+		/* toggle VREF state based on GPIOx status */
+		snd_hda_codec_write(codec, codec->afg, 0, 0x7e0,
+			!!(data & (1 << idx)));
+		break;
+		}
 	}
 }
 
@@ -3478,9 +4051,9 @@
 	.num_items = 4,
 	.items = {
 		{ "Analog Inputs", 0x0b },
-		{ "CD", 0x08 },
 		{ "Digital Mic 1", 0x09 },
 		{ "Digital Mic 2", 0x0a },
+		{ "CD", 0x08 },
 	}
 };
 
@@ -3495,6 +4068,7 @@
 		return -ENOMEM;
 
 	codec->spec = spec;
+	codec->slave_dig_outs = stac92hd73xx_slave_dig_outs;
 	spec->num_pins = ARRAY_SIZE(stac92hd73xx_pin_nids);
 	spec->pin_nids = stac92hd73xx_pin_nids;
 	spec->board_config = snd_hda_check_board_config(codec,
@@ -3527,17 +4101,14 @@
 
 	switch (spec->multiout.num_dacs) {
 	case 0x3: /* 6 Channel */
-		spec->multiout.hp_nid = 0x17;
 		spec->mixer = stac92hd73xx_6ch_mixer;
 		spec->init = stac92hd73xx_6ch_core_init;
 		break;
 	case 0x4: /* 8 Channel */
-		spec->multiout.hp_nid = 0x18;
 		spec->mixer = stac92hd73xx_8ch_mixer;
 		spec->init = stac92hd73xx_8ch_core_init;
 		break;
 	case 0x5: /* 10 Channel */
-		spec->multiout.hp_nid = 0x19;
 		spec->mixer = stac92hd73xx_10ch_mixer;
 		spec->init = stac92hd73xx_10ch_core_init;
 	};
@@ -3546,27 +4117,34 @@
 	spec->aloopback_mask = 0x01;
 	spec->aloopback_shift = 8;
 
+	spec->digbeep_nid = 0x1c;
 	spec->mux_nids = stac92hd73xx_mux_nids;
 	spec->adc_nids = stac92hd73xx_adc_nids;
 	spec->dmic_nids = stac92hd73xx_dmic_nids;
 	spec->dmux_nids = stac92hd73xx_dmux_nids;
+	spec->smux_nids = stac92hd73xx_smux_nids;
+	spec->amp_nids = stac92hd73xx_amp_nids;
+	spec->num_amps = ARRAY_SIZE(stac92hd73xx_amp_nids);
 
 	spec->num_muxes = ARRAY_SIZE(stac92hd73xx_mux_nids);
 	spec->num_adcs = ARRAY_SIZE(stac92hd73xx_adc_nids);
 	spec->num_dmuxes = ARRAY_SIZE(stac92hd73xx_dmux_nids);
-	spec->dinput_mux = &stac92hd73xx_dmux;
-	/* GPIO0 High = Enable EAPD */
-	spec->eapd_mask = spec->gpio_mask = spec->gpio_dir = 0x1;
-	spec->gpio_data = 0x01;
+	memcpy(&spec->private_dimux, &stac92hd73xx_dmux,
+			sizeof(stac92hd73xx_dmux));
 
 	switch (spec->board_config) {
 	case STAC_DELL_M6:
 		spec->init = dell_eq_core_init;
+		spec->num_smuxes = 0;
+		spec->mixer = &stac92hd73xx_6ch_mixer[DELL_M6_MIXER];
+		spec->amp_nids = &stac92hd73xx_amp_nids[DELL_M6_AMP];
+		spec->num_amps = 1;
 		switch (codec->subsystem_id) {
 		case 0x1028025e: /* Analog Mics */
 		case 0x1028025f:
 			stac92xx_set_config_reg(codec, 0x0b, 0x90A70170);
 			spec->num_dmics = 0;
+			spec->private_dimux.num_items = 1;
 			break;
 		case 0x10280271: /* Digital Mics */
 		case 0x10280272:
@@ -3576,23 +4154,32 @@
 		case 0x10280255:
 			stac92xx_set_config_reg(codec, 0x13, 0x90A60160);
 			spec->num_dmics = 1;
+			spec->private_dimux.num_items = 2;
 			break;
 		case 0x10280256: /* Both */
 		case 0x10280057:
 			stac92xx_set_config_reg(codec, 0x0b, 0x90A70170);
 			stac92xx_set_config_reg(codec, 0x13, 0x90A60160);
 			spec->num_dmics = 1;
+			spec->private_dimux.num_items = 2;
 			break;
 		}
 		break;
 	default:
 		spec->num_dmics = STAC92HD73XX_NUM_DMICS;
+		spec->num_smuxes = ARRAY_SIZE(stac92hd73xx_smux_nids);
 	}
+	if (spec->board_config > STAC_92HD73XX_REF) {
+		/* GPIO0 High = Enable EAPD */
+		spec->eapd_mask = spec->gpio_mask = spec->gpio_dir = 0x1;
+		spec->gpio_data = 0x01;
+	}
+	spec->dinput_mux = &spec->private_dimux;
 
 	spec->num_pwrs = ARRAY_SIZE(stac92hd73xx_pwr_nids);
 	spec->pwr_nids = stac92hd73xx_pwr_nids;
 
-	err = stac92xx_parse_auto_config(codec, 0x22, 0x24);
+	err = stac92xx_parse_auto_config(codec, 0x25, 0x27);
 
 	if (!err) {
 		if (spec->board_config < 0) {
@@ -3614,6 +4201,146 @@
 	return 0;
 }
 
+static struct hda_input_mux stac92hd83xxx_dmux = {
+	.num_items = 3,
+	.items = {
+		{ "Analog Inputs", 0x03 },
+		{ "Digital Mic 1", 0x04 },
+		{ "Digital Mic 2", 0x05 },
+	}
+};
+
+static int patch_stac92hd83xxx(struct hda_codec *codec)
+{
+	struct sigmatel_spec *spec;
+	int err;
+
+	spec  = kzalloc(sizeof(*spec), GFP_KERNEL);
+	if (spec == NULL)
+		return -ENOMEM;
+
+	codec->spec = spec;
+	codec->slave_dig_outs = stac92hd83xxx_slave_dig_outs;
+	spec->mono_nid = 0x19;
+	spec->digbeep_nid = 0x21;
+	spec->dmic_nids = stac92hd83xxx_dmic_nids;
+	spec->dmux_nids = stac92hd83xxx_dmux_nids;
+	spec->adc_nids = stac92hd83xxx_adc_nids;
+	spec->pwr_nids = stac92hd83xxx_pwr_nids;
+	spec->pwr_mapping = stac92hd83xxx_pwr_mapping;
+	spec->num_pwrs = ARRAY_SIZE(stac92hd83xxx_pwr_nids);
+	spec->multiout.dac_nids = stac92hd83xxx_dac_nids;
+
+	spec->init = stac92hd83xxx_core_init;
+	switch (codec->vendor_id) {
+	case 0x111d7605:
+		spec->multiout.num_dacs = STAC92HD81_DAC_COUNT;
+		break;
+	default:
+		spec->num_pwrs--;
+		spec->init++; /* switch to config #2 */
+		spec->multiout.num_dacs = STAC92HD83_DAC_COUNT;
+	}
+
+	spec->mixer = stac92hd83xxx_mixer;
+	spec->num_pins = ARRAY_SIZE(stac92hd83xxx_pin_nids);
+	spec->num_dmuxes = ARRAY_SIZE(stac92hd83xxx_dmux_nids);
+	spec->num_adcs = ARRAY_SIZE(stac92hd83xxx_adc_nids);
+	spec->num_dmics = STAC92HD83XXX_NUM_DMICS;
+	spec->dinput_mux = &stac92hd83xxx_dmux;
+	spec->pin_nids = stac92hd83xxx_pin_nids;
+	spec->board_config = snd_hda_check_board_config(codec,
+							STAC_92HD83XXX_MODELS,
+							stac92hd83xxx_models,
+							stac92hd83xxx_cfg_tbl);
+again:
+	if (spec->board_config < 0) {
+		snd_printdd(KERN_INFO "hda_codec: Unknown model for"
+			" STAC92HD83XXX, using BIOS defaults\n");
+		err = stac92xx_save_bios_config_regs(codec);
+		if (err < 0) {
+			stac92xx_free(codec);
+			return err;
+		}
+		spec->pin_configs = spec->bios_pin_configs;
+	} else {
+		spec->pin_configs = stac92hd83xxx_brd_tbl[spec->board_config];
+		stac92xx_set_config_regs(codec);
+	}
+
+	err = stac92xx_parse_auto_config(codec, 0x1d, 0);
+	if (!err) {
+		if (spec->board_config < 0) {
+			printk(KERN_WARNING "hda_codec: No auto-config is "
+			       "available, default to model=ref\n");
+			spec->board_config = STAC_92HD83XXX_REF;
+			goto again;
+		}
+		err = -EINVAL;
+	}
+
+	if (err < 0) {
+		stac92xx_free(codec);
+		return err;
+	}
+
+	codec->patch_ops = stac92xx_patch_ops;
+
+	return 0;
+}
+
+#ifdef SND_HDA_NEEDS_RESUME
+static void stac92hd71xx_set_power_state(struct hda_codec *codec, int pwr)
+{
+	struct sigmatel_spec *spec = codec->spec;
+	int i;
+	snd_hda_codec_write_cache(codec, codec->afg, 0,
+		AC_VERB_SET_POWER_STATE, pwr);
+
+	msleep(1);
+	for (i = 0; i < spec->num_adcs; i++) {
+		snd_hda_codec_write_cache(codec,
+			spec->adc_nids[i], 0,
+			AC_VERB_SET_POWER_STATE, pwr);
+	}
+};
+
+static int stac92hd71xx_resume(struct hda_codec *codec)
+{
+	stac92hd71xx_set_power_state(codec, AC_PWRST_D0);
+	return stac92xx_resume(codec);
+}
+
+static int stac92hd71xx_suspend(struct hda_codec *codec, pm_message_t state)
+{
+	stac92hd71xx_set_power_state(codec, AC_PWRST_D3);
+	return 0;
+};
+
+#endif
+
+static struct hda_codec_ops stac92hd71bxx_patch_ops = {
+	.build_controls = stac92xx_build_controls,
+	.build_pcms = stac92xx_build_pcms,
+	.init = stac92xx_init,
+	.free = stac92xx_free,
+	.unsol_event = stac92xx_unsol_event,
+#ifdef SND_HDA_NEEDS_RESUME
+	.resume = stac92hd71xx_resume,
+	.suspend = stac92hd71xx_suspend,
+#endif
+};
+
+static struct hda_input_mux stac92hd71bxx_dmux = {
+	.num_items = 4,
+	.items = {
+		{ "Analog Inputs", 0x00 },
+		{ "Mixer", 0x01 },
+		{ "Digital Mic 1", 0x02 },
+		{ "Digital Mic 2", 0x03 },
+	}
+};
+
 static int patch_stac92hd71bxx(struct hda_codec *codec)
 {
 	struct sigmatel_spec *spec;
@@ -3624,9 +4351,12 @@
 		return -ENOMEM;
 
 	codec->spec = spec;
+	codec->patch_ops = stac92xx_patch_ops;
 	spec->num_pins = ARRAY_SIZE(stac92hd71bxx_pin_nids);
 	spec->num_pwrs = ARRAY_SIZE(stac92hd71bxx_pwr_nids);
 	spec->pin_nids = stac92hd71bxx_pin_nids;
+	memcpy(&spec->private_dimux, &stac92hd71bxx_dmux,
+			sizeof(stac92hd71bxx_dmux));
 	spec->board_config = snd_hda_check_board_config(codec,
 							STAC_92HD71BXX_MODELS,
 							stac92hd71bxx_models,
@@ -3653,47 +4383,101 @@
 	case 0x111d76b5:
 		spec->mixer = stac92hd71bxx_mixer;
 		spec->init = stac92hd71bxx_core_init;
+		codec->slave_dig_outs = stac92hd71bxx_slave_dig_outs;
 		break;
 	case 0x111d7608: /* 5 Port with Analog Mixer */
+		switch (codec->subsystem_id) {
+		case 0x103c361a:
+			/* Enable VREF power saving on GPIO1 detect */
+			snd_hda_codec_write(codec, codec->afg, 0,
+				AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK, 0x02);
+			snd_hda_codec_write_cache(codec, codec->afg, 0,
+					AC_VERB_SET_UNSOLICITED_ENABLE,
+					(AC_USRSP_EN | STAC_VREF_EVENT | 0x01));
+			spec->gpio_mask |= 0x02;
+			break;
+		}
+		if ((codec->revision_id & 0xf) == 0 ||
+				(codec->revision_id & 0xf) == 1) {
+#ifdef SND_HDA_NEEDS_RESUME
+			codec->patch_ops = stac92hd71bxx_patch_ops;
+#endif
+			spec->stream_delay = 40; /* 40 milliseconds */
+		}
+
 		/* no output amps */
 		spec->num_pwrs = 0;
 		spec->mixer = stac92hd71bxx_analog_mixer;
+		spec->dinput_mux = &spec->private_dimux;
 
 		/* disable VSW */
 		spec->init = &stac92hd71bxx_analog_core_init[HD_DISABLE_PORTF];
 		stac92xx_set_config_reg(codec, 0xf, 0x40f000f0);
 		break;
 	case 0x111d7603: /* 6 Port with Analog Mixer */
+		if ((codec->revision_id & 0xf) == 1) {
+#ifdef SND_HDA_NEEDS_RESUME
+			codec->patch_ops = stac92hd71bxx_patch_ops;
+#endif
+			spec->stream_delay = 40; /* 40 milliseconds */
+		}
+
 		/* no output amps */
 		spec->num_pwrs = 0;
 		/* fallthru */
 	default:
+		spec->dinput_mux = &spec->private_dimux;
 		spec->mixer = stac92hd71bxx_analog_mixer;
 		spec->init = stac92hd71bxx_analog_core_init;
+		codec->slave_dig_outs = stac92hd71bxx_slave_dig_outs;
 	}
 
-	spec->aloopback_mask = 0x20;
+	spec->aloopback_mask = 0x50;
 	spec->aloopback_shift = 0;
 
-	/* GPIO0 High = EAPD */
-	spec->gpio_mask = 0x01;
-	spec->gpio_dir = 0x01;
-	spec->gpio_data = 0x01;
+	if (spec->board_config > STAC_92HD71BXX_REF) {
+		/* GPIO0 = EAPD */
+		spec->gpio_mask = 0x01;
+		spec->gpio_dir = 0x01;
+		spec->gpio_data = 0x01;
+	}
 
+	spec->powerdown_adcs = 1;
+	spec->digbeep_nid = 0x26;
 	spec->mux_nids = stac92hd71bxx_mux_nids;
 	spec->adc_nids = stac92hd71bxx_adc_nids;
 	spec->dmic_nids = stac92hd71bxx_dmic_nids;
 	spec->dmux_nids = stac92hd71bxx_dmux_nids;
+	spec->smux_nids = stac92hd71bxx_smux_nids;
 	spec->pwr_nids = stac92hd71bxx_pwr_nids;
 
 	spec->num_muxes = ARRAY_SIZE(stac92hd71bxx_mux_nids);
 	spec->num_adcs = ARRAY_SIZE(stac92hd71bxx_adc_nids);
-	spec->num_dmics = STAC92HD71BXX_NUM_DMICS;
-	spec->num_dmuxes = ARRAY_SIZE(stac92hd71bxx_dmux_nids);
+
+	switch (spec->board_config) {
+	case STAC_HP_M4:
+		spec->num_dmics = 0;
+		spec->num_smuxes = 0;
+		spec->num_dmuxes = 0;
+
+		/* enable internal microphone */
+		stac92xx_set_config_reg(codec, 0x0e, 0x01813040);
+		stac92xx_auto_set_pinctl(codec, 0x0e,
+			AC_PINCTL_IN_EN | AC_PINCTL_VREF_80);
+		break;
+	default:
+		spec->num_dmics = STAC92HD71BXX_NUM_DMICS;
+		spec->num_smuxes = ARRAY_SIZE(stac92hd71bxx_smux_nids);
+		spec->num_dmuxes = ARRAY_SIZE(stac92hd71bxx_dmux_nids);
+	};
 
 	spec->multiout.num_dacs = 1;
 	spec->multiout.hp_nid = 0x11;
 	spec->multiout.dac_nids = stac92hd71bxx_dac_nids;
+	if (spec->dinput_mux)
+		spec->private_dimux.num_items +=
+			spec->num_dmics -
+				(ARRAY_SIZE(stac92hd71bxx_dmic_nids) - 1);
 
 	err = stac92xx_parse_auto_config(codec, 0x21, 0x23);
 	if (!err) {
@@ -3711,8 +4495,6 @@
 		return err;
 	}
 
-	codec->patch_ops = stac92xx_patch_ops;
-
 	return 0;
 };
 
@@ -3854,10 +4636,14 @@
 		stac92xx_set_config_regs(codec);
 	}
 
+	spec->digbeep_nid = 0x23;
 	spec->adc_nids = stac927x_adc_nids;
 	spec->num_adcs = ARRAY_SIZE(stac927x_adc_nids);
 	spec->mux_nids = stac927x_mux_nids;
 	spec->num_muxes = ARRAY_SIZE(stac927x_mux_nids);
+	spec->smux_nids = stac927x_smux_nids;
+	spec->num_smuxes = ARRAY_SIZE(stac927x_smux_nids);
+	spec->spdif_labels = stac927x_spdif_labels;
 	spec->dac_list = stac927x_dac_nids;
 	spec->multiout.dac_nids = spec->dac_nids;
 
@@ -3900,9 +4686,11 @@
 		spec->num_dmuxes = ARRAY_SIZE(stac927x_dmux_nids);
 		break;
 	default:
-		/* GPIO0 High = Enable EAPD */
-		spec->eapd_mask = spec->gpio_mask = spec->gpio_dir = 0x1;
-		spec->gpio_data = 0x01;
+		if (spec->board_config > STAC_D965_REF) {
+			/* GPIO0 High = Enable EAPD */
+			spec->eapd_mask = spec->gpio_mask = 0x01;
+			spec->gpio_dir = spec->gpio_data = 0x01;
+		}
 		spec->num_dmics = 0;
 
 		spec->init = stac927x_core_init;
@@ -3974,10 +4762,13 @@
 		stac92xx_set_config_regs(codec);
 	}
 
+	spec->digbeep_nid = 0x23;
 	spec->adc_nids = stac9205_adc_nids;
 	spec->num_adcs = ARRAY_SIZE(stac9205_adc_nids);
 	spec->mux_nids = stac9205_mux_nids;
 	spec->num_muxes = ARRAY_SIZE(stac9205_mux_nids);
+	spec->smux_nids = stac9205_smux_nids;
+	spec->num_smuxes = ARRAY_SIZE(stac9205_smux_nids);
 	spec->dmic_nids = stac9205_dmic_nids;
 	spec->num_dmics = STAC9205_NUM_DMICS;
 	spec->dmux_nids = stac9205_dmux_nids;
@@ -4013,6 +4804,9 @@
 		 */
 		spec->gpio_data = 0x01;
 		break;
+	case STAC_9205_REF:
+		/* SPDIF-In enabled */
+		break;
 	default:
 		/* GPIO0 High = EAPD */
 		spec->eapd_mask = spec->gpio_mask = spec->gpio_dir = 0x1;
@@ -4332,6 +5126,8 @@
  	{ .id = 0x838476a6, .name = "STAC9254", .patch = patch_stac9205 },
  	{ .id = 0x838476a7, .name = "STAC9254D", .patch = patch_stac9205 },
 	{ .id = 0x111d7603, .name = "92HD75B3X5", .patch = patch_stac92hd71bxx},
+	{ .id = 0x111d7604, .name = "92HD83C1X5", .patch = patch_stac92hd83xxx},
+	{ .id = 0x111d7605, .name = "92HD81B1X5", .patch = patch_stac92hd83xxx},
 	{ .id = 0x111d7608, .name = "92HD75B2X5", .patch = patch_stac92hd71bxx},
 	{ .id = 0x111d7674, .name = "92HD73D1X5", .patch = patch_stac92hd73xx },
 	{ .id = 0x111d7675, .name = "92HD73C1X5", .patch = patch_stac92hd73xx },
diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c
index e7e4352..63e4871 100644
--- a/sound/pci/hda/patch_via.c
+++ b/sound/pci/hda/patch_via.c
@@ -1,10 +1,10 @@
 /*
  * Universal Interface for Intel High Definition Audio Codec
  *
- * HD audio interface patch for VIA VT1708 codec
+ * HD audio interface patch for VIA VT1702/VT1708/VT1709 codec
  *
- * Copyright (c) 2006 Lydia Wang <lydiawang@viatech.com>
- *                    Takashi Iwai <tiwai@suse.de>
+ * Copyright (c) 2006-2008 Lydia Wang <lydiawang@viatech.com>
+ *			   Takashi Iwai <tiwai@suse.de>
  *
  *  This driver is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -29,6 +29,13 @@
 /* 2006-09-08  Lydia Wang  Fix internal loopback recording source select bug */
 /* 2007-09-12  Lydia Wang  Add EAPD enable during driver initialization      */
 /* 2007-09-17  Lydia Wang  Add VT1708B codec support                        */
+/* 2007-11-14  Lydia Wang  Add VT1708A codec HP and CD pin connect config    */
+/* 2008-02-03  Lydia Wang  Fix Rear channels and Back channels inverse issue */
+/* 2008-03-06  Lydia Wang  Add VT1702 codec and VT1708S codec support        */
+/* 2008-04-09  Lydia Wang  Add mute front speaker when HP plugin             */
+/* 2008-04-09  Lydia Wang  Add Independent HP feature                        */
+/* 2008-05-28  Lydia Wang  Add second S/PDIF Out support for VT1702	     */
+/* 2008-09-15  Logan Li    Add VT1708S Mic Boost workaround/backdoor	     */
 /*                                                                           */
 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
 
@@ -37,6 +44,7 @@
 #include <linux/delay.h>
 #include <linux/slab.h>
 #include <sound/core.h>
+#include <sound/asoundef.h>
 #include "hda_codec.h"
 #include "hda_local.h"
 #include "hda_patch.h"
@@ -53,6 +61,8 @@
 #define VT1708_DIGOUT_NID	0x14
 #define VT1708_DIGIN_NID	0x16
 #define VT1708_DIGIN_PIN	0x26
+#define VT1708_HP_PIN_NID	0x20
+#define VT1708_CD_PIN_NID	0x24
 
 #define VT1709_HP_DAC_NID	0x28
 #define VT1709_DIGOUT_NID	0x13
@@ -64,12 +74,64 @@
 #define VT1708B_DIGIN_NID	0x15
 #define VT1708B_DIGIN_PIN	0x21
 
+#define VT1708S_HP_NID		0x25
+#define VT1708S_DIGOUT_NID	0x12
+
+#define VT1702_HP_NID		0x17
+#define VT1702_DIGOUT_NID	0x11
+
 #define IS_VT1708_VENDORID(x)		((x) >= 0x11061708 && (x) <= 0x1106170b)
 #define IS_VT1709_10CH_VENDORID(x)	((x) >= 0x1106e710 && (x) <= 0x1106e713)
 #define IS_VT1709_6CH_VENDORID(x)	((x) >= 0x1106e714 && (x) <= 0x1106e717)
 #define IS_VT1708B_8CH_VENDORID(x)	((x) >= 0x1106e720 && (x) <= 0x1106e723)
 #define IS_VT1708B_4CH_VENDORID(x)	((x) >= 0x1106e724 && (x) <= 0x1106e727)
+#define IS_VT1708S_VENDORID(x)		((x) >= 0x11060397 && (x) <= 0x11067397)
+#define IS_VT1702_VENDORID(x)		((x) >= 0x11060398 && (x) <= 0x11067398)
 
+enum VIA_HDA_CODEC {
+	UNKNOWN = -1,
+	VT1708,
+	VT1709_10CH,
+	VT1709_6CH,
+	VT1708B_8CH,
+	VT1708B_4CH,
+	VT1708S,
+	VT1702,
+	CODEC_TYPES,
+};
+
+static enum VIA_HDA_CODEC get_codec_type(u32 vendor_id)
+{
+	u16 ven_id = vendor_id >> 16;
+	u16 dev_id = vendor_id & 0xffff;
+	enum VIA_HDA_CODEC codec_type;
+
+	/* get codec type */
+	if (ven_id != 0x1106)
+		codec_type = UNKNOWN;
+	else if (dev_id >= 0x1708 && dev_id <= 0x170b)
+		codec_type = VT1708;
+	else if (dev_id >= 0xe710 && dev_id <= 0xe713)
+		codec_type = VT1709_10CH;
+	else if (dev_id >= 0xe714 && dev_id <= 0xe717)
+		codec_type = VT1709_6CH;
+	else if (dev_id >= 0xe720 && dev_id <= 0xe723)
+		codec_type = VT1708B_8CH;
+	else if (dev_id >= 0xe724 && dev_id <= 0xe727)
+		codec_type = VT1708B_4CH;
+	else if ((dev_id & 0xfff) == 0x397
+		 && (dev_id >> 12) < 8)
+		codec_type = VT1708S;
+	else if ((dev_id & 0xfff) == 0x398
+		 && (dev_id >> 12) < 8)
+		codec_type = VT1702;
+	else
+		codec_type = UNKNOWN;
+	return codec_type;
+};
+
+#define VIA_HP_EVENT		0x01
+#define VIA_GPIO_EVENT		0x02
 
 enum {
 	VIA_CTL_WIDGET_VOL,
@@ -77,12 +139,54 @@
 };
 
 enum {
-	AUTO_SEQ_FRONT,
+	AUTO_SEQ_FRONT = 0,
 	AUTO_SEQ_SURROUND,
 	AUTO_SEQ_CENLFE,
 	AUTO_SEQ_SIDE
 };
 
+#define get_amp_nid(kc)	((kc)->private_value & 0xffff)
+
+/* Some VT1708S based boards gets the micboost setting wrong, so we have
+ * to apply some brute-force and re-write the TLV's by software. */
+static int mic_boost_tlv(struct snd_kcontrol *kcontrol, int op_flag,
+			 unsigned int size, unsigned int __user *_tlv)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	hda_nid_t nid = get_amp_nid(kcontrol);
+
+	if (get_codec_type(codec->vendor_id) == VT1708S
+	    && (nid == 0x1a || nid == 0x1e)) {
+		if (size < 4 * sizeof(unsigned int))
+			return -ENOMEM;
+		if (put_user(1, _tlv))	/* SNDRV_CTL_TLVT_DB_SCALE */
+			return -EFAULT;
+		if (put_user(2 * sizeof(unsigned int), _tlv + 1))
+			return -EFAULT;
+		if (put_user(0, _tlv + 2)) /* offset = 0 */
+			return -EFAULT;
+		if (put_user(1000, _tlv + 3)) /* step size = 10 dB */
+			return -EFAULT;
+	}
+	return 0;
+}
+
+static int mic_boost_volume_info(struct snd_kcontrol *kcontrol,
+				 struct snd_ctl_elem_info *uinfo)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	hda_nid_t nid = get_amp_nid(kcontrol);
+
+	if (get_codec_type(codec->vendor_id) == VT1708S
+	    && (nid == 0x1a || nid == 0x1e)) {
+		uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+		uinfo->count = 2;
+		uinfo->value.integer.min = 0;
+		uinfo->value.integer.max = 3;
+	}
+	return 0;
+}
+
 static struct snd_kcontrol_new vt1708_control_templates[] = {
 	HDA_CODEC_VOLUME(NULL, 0, 0, 0),
 	HDA_CODEC_MUTE(NULL, 0, 0, 0),
@@ -94,7 +198,8 @@
 	struct snd_kcontrol_new *mixers[3];
 	unsigned int num_mixers;
 
-	struct hda_verb *init_verbs;
+	struct hda_verb *init_verbs[5];
+	unsigned int num_iverbs;
 
 	char *stream_name_analog;
 	struct hda_pcm_stream *stream_analog_playback;
@@ -106,6 +211,7 @@
 
 	/* playback */
 	struct hda_multi_out multiout;
+	hda_nid_t extra_dig_out_nid;
 
 	/* capture */
 	unsigned int num_adc_nids;
@@ -117,15 +223,19 @@
 	unsigned int cur_mux[3];
 
 	/* PCM information */
-	struct hda_pcm pcm_rec[2];
+	struct hda_pcm pcm_rec[3];
 
 	/* dynamic controls, init_verbs and input_mux */
 	struct auto_pin_cfg autocfg;
 	unsigned int num_kctl_alloc, num_kctl_used;
 	struct snd_kcontrol_new *kctl_alloc;
-	struct hda_input_mux private_imux;
+	struct hda_input_mux private_imux[2];
 	hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS];
 
+	/* HP mode source */
+	const struct hda_input_mux *hp_mux;
+	unsigned int hp_independent_mode;
+
 #ifdef CONFIG_SND_HDA_POWER_SAVE
 	struct hda_loopback_check loopback;
 #endif
@@ -146,6 +256,16 @@
 	0x13, 0x14
 };
 
+static hda_nid_t vt1708S_adc_nids[2] = {
+	/* ADC1-2 */
+	0x13, 0x14
+};
+
+static hda_nid_t vt1702_adc_nids[3] = {
+	/* ADC1-2 */
+	0x12, 0x20, 0x1F
+};
+
 /* add dynamic controls */
 static int via_add_control(struct via_spec *spec, int type, const char *name,
 			   unsigned long val)
@@ -283,19 +403,108 @@
 		return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
 					     0x18, &spec->cur_mux[adc_idx]);
 	else if ((IS_VT1709_10CH_VENDORID(vendor_id) ||
-		  IS_VT1709_6CH_VENDORID(vendor_id)) && adc_idx == 0)
+		  IS_VT1709_6CH_VENDORID(vendor_id)) && (adc_idx == 0))
 		return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
 					     0x19, &spec->cur_mux[adc_idx]);
 	else if ((IS_VT1708B_8CH_VENDORID(vendor_id) ||
-		  IS_VT1708B_4CH_VENDORID(vendor_id)) && adc_idx == 0)
+		  IS_VT1708B_4CH_VENDORID(vendor_id)) && (adc_idx == 0))
 		return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
 					     0x17, &spec->cur_mux[adc_idx]);
+	else if (IS_VT1702_VENDORID(vendor_id) && (adc_idx == 0))
+		return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
+					     0x13, &spec->cur_mux[adc_idx]);
 	else
 		return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
 					     spec->adc_nids[adc_idx],
 					     &spec->cur_mux[adc_idx]);
 }
 
+static int via_independent_hp_info(struct snd_kcontrol *kcontrol,
+				   struct snd_ctl_elem_info *uinfo)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct via_spec *spec = codec->spec;
+	return snd_hda_input_mux_info(spec->hp_mux, uinfo);
+}
+
+static int via_independent_hp_get(struct snd_kcontrol *kcontrol,
+				  struct snd_ctl_elem_value *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct via_spec *spec = codec->spec;
+	hda_nid_t nid = spec->autocfg.hp_pins[0];
+	unsigned int pinsel = snd_hda_codec_read(codec, nid, 0,
+						 AC_VERB_GET_CONNECT_SEL,
+						 0x00);
+
+	ucontrol->value.enumerated.item[0] = pinsel;
+
+	return 0;
+}
+
+static int via_independent_hp_put(struct snd_kcontrol *kcontrol,
+				  struct snd_ctl_elem_value *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct via_spec *spec = codec->spec;
+	hda_nid_t nid = spec->autocfg.hp_pins[0];
+	unsigned int pinsel = ucontrol->value.enumerated.item[0];
+	unsigned int con_nid = snd_hda_codec_read(codec, nid, 0,
+					 AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
+
+	if (con_nid == spec->multiout.hp_nid) {
+		if (pinsel == 0) {
+			if (!spec->hp_independent_mode) {
+				if (spec->multiout.num_dacs > 1)
+					spec->multiout.num_dacs -= 1;
+				spec->hp_independent_mode = 1;
+			}
+		} else if (pinsel == 1) {
+		       if (spec->hp_independent_mode) {
+				if (spec->multiout.num_dacs > 1)
+					spec->multiout.num_dacs += 1;
+				spec->hp_independent_mode = 0;
+		       }
+		}
+	} else {
+		if (pinsel == 0) {
+			if (spec->hp_independent_mode) {
+				if (spec->multiout.num_dacs > 1)
+					spec->multiout.num_dacs += 1;
+				spec->hp_independent_mode = 0;
+			}
+		} else if (pinsel == 1) {
+		       if (!spec->hp_independent_mode) {
+				if (spec->multiout.num_dacs > 1)
+					spec->multiout.num_dacs -= 1;
+				spec->hp_independent_mode = 1;
+		       }
+		}
+	}
+	snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL,
+			    pinsel);
+
+	if (spec->multiout.hp_nid &&
+	    spec->multiout.hp_nid != spec->multiout.dac_nids[HDA_FRONT])
+			snd_hda_codec_setup_stream(codec,
+						   spec->multiout.hp_nid,
+						   0, 0, 0);
+
+	return 0;
+}
+
+static struct snd_kcontrol_new via_hp_mixer[] = {
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Independent HP",
+		.count = 1,
+		.info = via_independent_hp_info,
+		.get = via_independent_hp_get,
+		.put = via_independent_hp_put,
+	},
+	{ } /* end */
+};
+
 /* capture mixer elements */
 static struct snd_kcontrol_new vt1708_capture_mixer[] = {
 	HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_INPUT),
@@ -380,6 +589,138 @@
 	return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
 }
 
+
+static void playback_multi_pcm_prep_0(struct hda_codec *codec,
+				      unsigned int stream_tag,
+				      unsigned int format,
+				      struct snd_pcm_substream *substream)
+{
+	struct via_spec *spec = codec->spec;
+	struct hda_multi_out *mout = &spec->multiout;
+	hda_nid_t *nids = mout->dac_nids;
+	int chs = substream->runtime->channels;
+	int i;
+
+	mutex_lock(&codec->spdif_mutex);
+	if (mout->dig_out_nid && mout->dig_out_used != HDA_DIG_EXCLUSIVE) {
+		if (chs == 2 &&
+		    snd_hda_is_supported_format(codec, mout->dig_out_nid,
+						format) &&
+		    !(codec->spdif_status & IEC958_AES0_NONAUDIO)) {
+			mout->dig_out_used = HDA_DIG_ANALOG_DUP;
+			/* turn off SPDIF once; otherwise the IEC958 bits won't
+			 * be updated */
+			if (codec->spdif_ctls & AC_DIG1_ENABLE)
+				snd_hda_codec_write(codec, mout->dig_out_nid, 0,
+						    AC_VERB_SET_DIGI_CONVERT_1,
+						    codec->spdif_ctls &
+							~AC_DIG1_ENABLE & 0xff);
+			snd_hda_codec_setup_stream(codec, mout->dig_out_nid,
+						   stream_tag, 0, format);
+			/* turn on again (if needed) */
+			if (codec->spdif_ctls & AC_DIG1_ENABLE)
+				snd_hda_codec_write(codec, mout->dig_out_nid, 0,
+						    AC_VERB_SET_DIGI_CONVERT_1,
+						    codec->spdif_ctls & 0xff);
+		} else {
+			mout->dig_out_used = 0;
+			snd_hda_codec_setup_stream(codec, mout->dig_out_nid,
+						   0, 0, 0);
+		}
+	}
+	mutex_unlock(&codec->spdif_mutex);
+
+	/* front */
+	snd_hda_codec_setup_stream(codec, nids[HDA_FRONT], stream_tag,
+				   0, format);
+
+	if (mout->hp_nid && mout->hp_nid != nids[HDA_FRONT] &&
+	    !spec->hp_independent_mode)
+		/* headphone out will just decode front left/right (stereo) */
+		snd_hda_codec_setup_stream(codec, mout->hp_nid, stream_tag,
+					   0, format);
+
+	/* extra outputs copied from front */
+	for (i = 0; i < ARRAY_SIZE(mout->extra_out_nid); i++)
+		if (mout->extra_out_nid[i])
+			snd_hda_codec_setup_stream(codec,
+						   mout->extra_out_nid[i],
+						   stream_tag, 0, format);
+
+	/* surrounds */
+	for (i = 1; i < mout->num_dacs; i++) {
+		if (chs >= (i + 1) * 2) /* independent out */
+			snd_hda_codec_setup_stream(codec, nids[i], stream_tag,
+						   i * 2, format);
+		else /* copy front */
+			snd_hda_codec_setup_stream(codec, nids[i], stream_tag,
+						   0, format);
+	}
+}
+
+static int via_playback_multi_pcm_prepare(struct hda_pcm_stream *hinfo,
+					  struct hda_codec *codec,
+					  unsigned int stream_tag,
+					  unsigned int format,
+					  struct snd_pcm_substream *substream)
+{
+	struct via_spec *spec = codec->spec;
+	struct hda_multi_out *mout = &spec->multiout;
+	hda_nid_t *nids = mout->dac_nids;
+
+	if (substream->number == 0)
+		playback_multi_pcm_prep_0(codec, stream_tag, format,
+					  substream);
+	else {
+		if (mout->hp_nid && mout->hp_nid != nids[HDA_FRONT] &&
+		    spec->hp_independent_mode)
+			snd_hda_codec_setup_stream(codec, mout->hp_nid,
+						   stream_tag, 0, format);
+	}
+
+	return 0;
+}
+
+static int via_playback_multi_pcm_cleanup(struct hda_pcm_stream *hinfo,
+				    struct hda_codec *codec,
+				    struct snd_pcm_substream *substream)
+{
+	struct via_spec *spec = codec->spec;
+	struct hda_multi_out *mout = &spec->multiout;
+	hda_nid_t *nids = mout->dac_nids;
+	int i;
+
+	if (substream->number == 0) {
+		for (i = 0; i < mout->num_dacs; i++)
+			snd_hda_codec_setup_stream(codec, nids[i], 0, 0, 0);
+
+		if (mout->hp_nid && !spec->hp_independent_mode)
+			snd_hda_codec_setup_stream(codec, mout->hp_nid,
+						   0, 0, 0);
+
+		for (i = 0; i < ARRAY_SIZE(mout->extra_out_nid); i++)
+			if (mout->extra_out_nid[i])
+				snd_hda_codec_setup_stream(codec,
+							mout->extra_out_nid[i],
+							0, 0, 0);
+		mutex_lock(&codec->spdif_mutex);
+		if (mout->dig_out_nid &&
+		    mout->dig_out_used == HDA_DIG_ANALOG_DUP) {
+			snd_hda_codec_setup_stream(codec, mout->dig_out_nid,
+						   0, 0, 0);
+			mout->dig_out_used = 0;
+		}
+		mutex_unlock(&codec->spdif_mutex);
+	} else {
+		if (mout->hp_nid && mout->hp_nid != nids[HDA_FRONT] &&
+		    spec->hp_independent_mode)
+			snd_hda_codec_setup_stream(codec, mout->hp_nid,
+						   0, 0, 0);
+	}
+
+	return 0;
+}
+
 /*
  * Digital out
  */
@@ -399,6 +740,21 @@
 	return snd_hda_multi_out_dig_close(codec, &spec->multiout);
 }
 
+/* setup SPDIF output stream */
+static void setup_dig_playback_stream(struct hda_codec *codec, hda_nid_t nid,
+				 unsigned int stream_tag, unsigned int format)
+{
+	/* turn off SPDIF once; otherwise the IEC958 bits won't be updated */
+	if (codec->spdif_ctls & AC_DIG1_ENABLE)
+		snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1,
+				    codec->spdif_ctls & ~AC_DIG1_ENABLE & 0xff);
+	snd_hda_codec_setup_stream(codec, nid, stream_tag, 0, format);
+	/* turn on again (if needed) */
+	if (codec->spdif_ctls & AC_DIG1_ENABLE)
+		snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1,
+				    codec->spdif_ctls & 0xff);
+}
+
 static int via_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
 					struct hda_codec *codec,
 					unsigned int stream_tag,
@@ -406,8 +762,20 @@
 					struct snd_pcm_substream *substream)
 {
 	struct via_spec *spec = codec->spec;
-	return snd_hda_multi_out_dig_prepare(codec, &spec->multiout,
-					     stream_tag, format, substream);
+	hda_nid_t nid;
+
+	/* 1st or 2nd S/PDIF */
+	if (substream->number == 0)
+		nid = spec->multiout.dig_out_nid;
+	else if (substream->number == 1)
+		nid = spec->extra_dig_out_nid;
+	else
+		return -1;
+
+	mutex_lock(&codec->spdif_mutex);
+	setup_dig_playback_stream(codec, nid, stream_tag, format);
+	mutex_unlock(&codec->spdif_mutex);
+	return 0;
 }
 
 /*
@@ -436,14 +804,14 @@
 }
 
 static struct hda_pcm_stream vt1708_pcm_analog_playback = {
-	.substreams = 1,
+	.substreams = 2,
 	.channels_min = 2,
 	.channels_max = 8,
 	.nid = 0x10, /* NID to query formats and rates */
 	.ops = {
 		.open = via_playback_pcm_open,
-		.prepare = via_playback_pcm_prepare,
-		.cleanup = via_playback_pcm_cleanup
+		.prepare = via_playback_multi_pcm_prepare,
+		.cleanup = via_playback_multi_pcm_cleanup
 	},
 };
 
@@ -515,6 +883,13 @@
 		if (err < 0)
 			return err;
 		spec->multiout.share_spdif = 1;
+
+		if (spec->extra_dig_out_nid) {
+			err = snd_hda_create_spdif_out_ctls(codec,
+						    spec->extra_dig_out_nid);
+			if (err < 0)
+				return err;
+		}
 	}
 	if (spec->dig_in_nid) {
 		err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
@@ -580,10 +955,89 @@
 	kfree(codec->spec);
 }
 
+/* mute internal speaker if HP is plugged */
+static void via_hp_automute(struct hda_codec *codec)
+{
+	unsigned int present;
+	struct via_spec *spec = codec->spec;
+
+	present = snd_hda_codec_read(codec, spec->autocfg.hp_pins[0], 0,
+				     AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
+	snd_hda_codec_amp_stereo(codec, spec->autocfg.line_out_pins[0],
+				 HDA_OUTPUT, 0, HDA_AMP_MUTE,
+				 present ? HDA_AMP_MUTE : 0);
+}
+
+static void via_gpio_control(struct hda_codec *codec)
+{
+	unsigned int gpio_data;
+	unsigned int vol_counter;
+	unsigned int vol;
+	unsigned int master_vol;
+
+	struct via_spec *spec = codec->spec;
+
+	gpio_data = snd_hda_codec_read(codec, codec->afg, 0,
+				       AC_VERB_GET_GPIO_DATA, 0) & 0x03;
+
+	vol_counter = (snd_hda_codec_read(codec, codec->afg, 0,
+					  0xF84, 0) & 0x3F0000) >> 16;
+
+	vol = vol_counter & 0x1F;
+	master_vol = snd_hda_codec_read(codec, 0x1A, 0,
+					AC_VERB_GET_AMP_GAIN_MUTE,
+					AC_AMP_GET_INPUT);
+
+	if (gpio_data == 0x02) {
+		/* unmute line out */
+		snd_hda_codec_amp_stereo(codec, spec->autocfg.line_out_pins[0],
+					 HDA_OUTPUT, 0, HDA_AMP_MUTE, 0);
+
+		if (vol_counter & 0x20) {
+			/* decrease volume */
+			if (vol > master_vol)
+				vol = master_vol;
+			snd_hda_codec_amp_stereo(codec, 0x1A, HDA_INPUT,
+						 0, HDA_AMP_VOLMASK,
+						 master_vol-vol);
+		} else {
+			/* increase volume */
+			snd_hda_codec_amp_stereo(codec, 0x1A, HDA_INPUT, 0,
+					 HDA_AMP_VOLMASK,
+					 ((master_vol+vol) > 0x2A) ? 0x2A :
+					  (master_vol+vol));
+		}
+	} else if (!(gpio_data & 0x02)) {
+		/* mute line out */
+		snd_hda_codec_amp_stereo(codec,
+					 spec->autocfg.line_out_pins[0],
+					 HDA_OUTPUT, 0, HDA_AMP_MUTE,
+					 HDA_AMP_MUTE);
+	}
+}
+
+/* unsolicited event for jack sensing */
+static void via_unsol_event(struct hda_codec *codec,
+				  unsigned int res)
+{
+	res >>= 26;
+	if (res == VIA_HP_EVENT)
+		via_hp_automute(codec);
+	else if (res == VIA_GPIO_EVENT)
+		via_gpio_control(codec);
+}
+
+static hda_nid_t slave_dig_outs[] = {
+	0,
+};
+
 static int via_init(struct hda_codec *codec)
 {
 	struct via_spec *spec = codec->spec;
-	snd_hda_sequence_write(codec, spec->init_verbs);
+	int i;
+	for (i = 0; i < spec->num_iverbs; i++)
+		snd_hda_sequence_write(codec, spec->init_verbs[i]);
+
 	/* Lydia Add for EAPD enable */
 	if (!spec->dig_in_nid) { /* No Digital In connection */
 		if (IS_VT1708_VENDORID(codec->vendor_id)) {
@@ -611,6 +1065,9 @@
 		snd_hda_codec_write(codec, spec->autocfg.dig_in_pin, 0,
 				    AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN);
 
+	/* no slave outs */
+	codec->slave_dig_outs = slave_dig_outs;
+
  	return 0;
 }
 
@@ -657,10 +1114,10 @@
 				spec->multiout.dac_nids[i] = 0x12;
 				break;
 			case AUTO_SEQ_SURROUND:
-				spec->multiout.dac_nids[i] = 0x13;
+				spec->multiout.dac_nids[i] = 0x11;
 				break;
 			case AUTO_SEQ_SIDE:
-				spec->multiout.dac_nids[i] = 0x11;
+				spec->multiout.dac_nids[i] = 0x13;
 				break;
 			}
 		}
@@ -685,7 +1142,7 @@
 			continue;
 		
 		if (i != AUTO_SEQ_FRONT)
-			nid_vol = 0x1b - i + 1;
+			nid_vol = 0x18 + i;
 
 		if (i == AUTO_SEQ_CENLFE) {
 			/* Center/LFE */
@@ -760,6 +1217,24 @@
 	return 0;
 }
 
+static void create_hp_imux(struct via_spec *spec)
+{
+	int i;
+	struct hda_input_mux *imux = &spec->private_imux[1];
+	static const char *texts[] = { "OFF", "ON", NULL};
+
+	/* for hp mode select */
+	i = 0;
+	while (texts[i] != NULL) {
+		imux->items[imux->num_items].label =  texts[i];
+		imux->items[imux->num_items].index = i;
+		imux->num_items++;
+		i++;
+	}
+
+	spec->hp_mux = &spec->private_imux[1];
+}
+
 static int vt1708_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
 {
 	int err;
@@ -780,6 +1255,8 @@
 	if (err < 0)
 		return err;
 
+	create_hp_imux(spec);
+
 	return 0;
 }
 
@@ -790,7 +1267,7 @@
 	static char *labels[] = {
 		"Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
 	};
-	struct hda_input_mux *imux = &spec->private_imux;
+	struct hda_input_mux *imux = &spec->private_imux[0];
 	int i, err, idx = 0;
 
 	/* for internal loopback recording select */
@@ -840,11 +1317,36 @@
 };
 #endif
 
+static void vt1708_set_pinconfig_connect(struct hda_codec *codec, hda_nid_t nid)
+{
+	unsigned int def_conf;
+	unsigned char seqassoc;
+
+	def_conf = snd_hda_codec_read(codec, nid, 0,
+				      AC_VERB_GET_CONFIG_DEFAULT, 0);
+	seqassoc = (unsigned char) get_defcfg_association(def_conf);
+	seqassoc = (seqassoc << 4) | get_defcfg_sequence(def_conf);
+	if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE) {
+		if (seqassoc == 0xff) {
+			def_conf = def_conf & (~(AC_JACK_PORT_BOTH << 30));
+			snd_hda_codec_write(codec, nid, 0,
+					    AC_VERB_SET_CONFIG_DEFAULT_BYTES_3,
+					    def_conf >> 24);
+		}
+	}
+
+	return;
+}
+
 static int vt1708_parse_auto_config(struct hda_codec *codec)
 {
 	struct via_spec *spec = codec->spec;
 	int err;
 
+	/* Add HP and CD pin config connect bit re-config action */
+	vt1708_set_pinconfig_connect(codec, VT1708_HP_PIN_NID);
+	vt1708_set_pinconfig_connect(codec, VT1708_CD_PIN_NID);
+
 	err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
 	if (err < 0)
 		return err;
@@ -874,9 +1376,12 @@
 	if (spec->kctl_alloc)
 		spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
 
-	spec->init_verbs = vt1708_volume_init_verbs;	
+	spec->init_verbs[spec->num_iverbs++] = vt1708_volume_init_verbs;
 
-	spec->input_mux = &spec->private_imux;
+	spec->input_mux = &spec->private_imux[0];
+
+	if (spec->hp_mux)
+		spec->mixers[spec->num_mixers++] = via_hp_mixer;
 
 	return 1;
 }
@@ -897,7 +1402,7 @@
 	int err;
 
 	/* create a codec specific record */
-	spec = kcalloc(1, sizeof(*spec), GFP_KERNEL);
+	spec = kzalloc(sizeof(*spec), GFP_KERNEL);
 	if (spec == NULL)
 		return -ENOMEM;
 
@@ -966,6 +1471,11 @@
 	{ } /* end */
 };
 
+static struct hda_verb vt1709_uniwill_init_verbs[] = {
+	{0x20, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_HP_EVENT},
+	{ }
+};
+
 /*
  * generic initialization of ADC, input mixers and output mixers
  */
@@ -1090,11 +1600,11 @@
 					break;
 				case AUTO_SEQ_SURROUND:
 					/* AOW3 */
-					spec->multiout.dac_nids[i] = 0x27;
+					spec->multiout.dac_nids[i] = 0x11;
 					break;
 				case AUTO_SEQ_SIDE:
 					/* AOW1 */
-					spec->multiout.dac_nids[i] = 0x11;
+					spec->multiout.dac_nids[i] = 0x27;
 					break;
 				default:
 					break;
@@ -1203,26 +1713,26 @@
 		} else if (i == AUTO_SEQ_SURROUND) {
 			sprintf(name, "%s Playback Volume", chname[i]);
 			err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
-					      HDA_COMPOSE_AMP_VAL(0x29, 3, 0,
+					      HDA_COMPOSE_AMP_VAL(0x1a, 3, 0,
 								  HDA_OUTPUT));
 			if (err < 0)
 				return err;
 			sprintf(name, "%s Playback Switch", chname[i]);
 			err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
-					      HDA_COMPOSE_AMP_VAL(0x29, 3, 0,
+					      HDA_COMPOSE_AMP_VAL(0x1a, 3, 0,
 								  HDA_OUTPUT));
 			if (err < 0)
 				return err;
 		} else if (i == AUTO_SEQ_SIDE) {
 			sprintf(name, "%s Playback Volume", chname[i]);
 			err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
-					      HDA_COMPOSE_AMP_VAL(0x1a, 3, 0,
+					      HDA_COMPOSE_AMP_VAL(0x29, 3, 0,
 								  HDA_OUTPUT));
 			if (err < 0)
 				return err;
 			sprintf(name, "%s Playback Switch", chname[i]);
 			err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
-					      HDA_COMPOSE_AMP_VAL(0x1a, 3, 0,
+					      HDA_COMPOSE_AMP_VAL(0x29, 3, 0,
 								  HDA_OUTPUT));
 			if (err < 0)
 				return err;
@@ -1265,7 +1775,7 @@
 	static char *labels[] = {
 		"Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
 	};
-	struct hda_input_mux *imux = &spec->private_imux;
+	struct hda_input_mux *imux = &spec->private_imux[0];
 	int i, err, idx = 0;
 
 	/* for internal loopback recording select */
@@ -1339,7 +1849,10 @@
 	if (spec->kctl_alloc)
 		spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
 
-	spec->input_mux = &spec->private_imux;
+	spec->input_mux = &spec->private_imux[0];
+
+	if (spec->hp_mux)
+		spec->mixers[spec->num_mixers++] = via_hp_mixer;
 
 	return 1;
 }
@@ -1360,7 +1873,7 @@
 	int err;
 
 	/* create a codec specific record */
-	spec = kcalloc(1, sizeof(*spec), GFP_KERNEL);
+	spec = kzalloc(sizeof(*spec), GFP_KERNEL);
 	if (spec == NULL)
 		return -ENOMEM;
 
@@ -1375,7 +1888,8 @@
 		       "Using genenic mode...\n");
 	}
 
-	spec->init_verbs = vt1709_10ch_volume_init_verbs;	
+	spec->init_verbs[spec->num_iverbs++] = vt1709_10ch_volume_init_verbs;
+	spec->init_verbs[spec->num_iverbs++] = vt1709_uniwill_init_verbs;
 
 	spec->stream_name_analog = "VT1709 Analog";
 	spec->stream_analog_playback = &vt1709_10ch_pcm_analog_playback;
@@ -1396,6 +1910,7 @@
 	codec->patch_ops = via_patch_ops;
 
 	codec->patch_ops.init = via_auto_init;
+	codec->patch_ops.unsol_event = via_unsol_event;
 #ifdef CONFIG_SND_HDA_POWER_SAVE
 	spec->loopback.amplist = vt1709_loopbacks;
 #endif
@@ -1451,7 +1966,7 @@
 	int err;
 
 	/* create a codec specific record */
-	spec = kcalloc(1, sizeof(*spec), GFP_KERNEL);
+	spec = kzalloc(sizeof(*spec), GFP_KERNEL);
 	if (spec == NULL)
 		return -ENOMEM;
 
@@ -1466,7 +1981,8 @@
 		       "Using genenic mode...\n");
 	}
 
-	spec->init_verbs = vt1709_6ch_volume_init_verbs;	
+	spec->init_verbs[spec->num_iverbs++] = vt1709_6ch_volume_init_verbs;
+	spec->init_verbs[spec->num_iverbs++] = vt1709_uniwill_init_verbs;
 
 	spec->stream_name_analog = "VT1709 Analog";
 	spec->stream_analog_playback = &vt1709_6ch_pcm_analog_playback;
@@ -1487,6 +2003,7 @@
 	codec->patch_ops = via_patch_ops;
 
 	codec->patch_ops.init = via_auto_init;
+	codec->patch_ops.unsol_event = via_unsol_event;
 #ifdef CONFIG_SND_HDA_POWER_SAVE
 	spec->loopback.amplist = vt1709_loopbacks;
 #endif
@@ -1586,27 +2103,32 @@
 	{ }
 };
 
+static struct hda_verb vt1708B_uniwill_init_verbs[] = {
+	{0x1D, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_HP_EVENT},
+	{ }
+};
+
 static struct hda_pcm_stream vt1708B_8ch_pcm_analog_playback = {
-	.substreams = 1,
+	.substreams = 2,
 	.channels_min = 2,
 	.channels_max = 8,
 	.nid = 0x10, /* NID to query formats and rates */
 	.ops = {
 		.open = via_playback_pcm_open,
-		.prepare = via_playback_pcm_prepare,
-		.cleanup = via_playback_pcm_cleanup
+		.prepare = via_playback_multi_pcm_prepare,
+		.cleanup = via_playback_multi_pcm_cleanup
 	},
 };
 
 static struct hda_pcm_stream vt1708B_4ch_pcm_analog_playback = {
-	.substreams = 1,
+	.substreams = 2,
 	.channels_min = 2,
 	.channels_max = 4,
 	.nid = 0x10, /* NID to query formats and rates */
 	.ops = {
 		.open = via_playback_pcm_open,
-		.prepare = via_playback_pcm_prepare,
-		.cleanup = via_playback_pcm_cleanup
+		.prepare = via_playback_multi_pcm_prepare,
+		.cleanup = via_playback_multi_pcm_cleanup
 	},
 };
 
@@ -1662,10 +2184,10 @@
 				spec->multiout.dac_nids[i] = 0x24;
 				break;
 			case AUTO_SEQ_SURROUND:
-				spec->multiout.dac_nids[i] = 0x25;
+				spec->multiout.dac_nids[i] = 0x11;
 				break;
 			case AUTO_SEQ_SIDE:
-				spec->multiout.dac_nids[i] = 0x11;
+				spec->multiout.dac_nids[i] = 0x25;
 				break;
 			}
 		}
@@ -1680,7 +2202,7 @@
 {
 	char name[32];
 	static const char *chname[4] = { "Front", "Surround", "C/LFE", "Side" };
-	hda_nid_t nid_vols[] = {0x16, 0x27, 0x26, 0x18};
+	hda_nid_t nid_vols[] = {0x16, 0x18, 0x26, 0x27};
 	hda_nid_t nid, nid_vol = 0;
 	int i, err;
 
@@ -1785,6 +2307,8 @@
 	if (err < 0)
 		return err;
 
+	create_hp_imux(spec);
+
 	return 0;
 }
 
@@ -1795,7 +2319,7 @@
 	static char *labels[] = {
 		"Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
 	};
-	struct hda_input_mux *imux = &spec->private_imux;
+	struct hda_input_mux *imux = &spec->private_imux[0];
 	int i, err, idx = 0;
 
 	/* for internal loopback recording select */
@@ -1869,7 +2393,10 @@
 	if (spec->kctl_alloc)
 		spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
 
-	spec->input_mux = &spec->private_imux;
+	spec->input_mux = &spec->private_imux[0];
+
+	if (spec->hp_mux)
+		spec->mixers[spec->num_mixers++] = via_hp_mixer;
 
 	return 1;
 }
@@ -1890,7 +2417,7 @@
 	int err;
 
 	/* create a codec specific record */
-	spec = kcalloc(1, sizeof(*spec), GFP_KERNEL);
+	spec = kzalloc(sizeof(*spec), GFP_KERNEL);
 	if (spec == NULL)
 		return -ENOMEM;
 
@@ -1906,7 +2433,8 @@
 		       "from BIOS.  Using genenic mode...\n");
 	}
 
-	spec->init_verbs = vt1708B_8ch_volume_init_verbs;
+	spec->init_verbs[spec->num_iverbs++] = vt1708B_8ch_volume_init_verbs;
+	spec->init_verbs[spec->num_iverbs++] = vt1708B_uniwill_init_verbs;
 
 	spec->stream_name_analog = "VT1708B Analog";
 	spec->stream_analog_playback = &vt1708B_8ch_pcm_analog_playback;
@@ -1926,6 +2454,7 @@
 	codec->patch_ops = via_patch_ops;
 
 	codec->patch_ops.init = via_auto_init;
+	codec->patch_ops.unsol_event = via_unsol_event;
 #ifdef CONFIG_SND_HDA_POWER_SAVE
 	spec->loopback.amplist = vt1708B_loopbacks;
 #endif
@@ -1939,7 +2468,7 @@
 	int err;
 
 	/* create a codec specific record */
-	spec = kcalloc(1, sizeof(*spec), GFP_KERNEL);
+	spec = kzalloc(sizeof(*spec), GFP_KERNEL);
 	if (spec == NULL)
 		return -ENOMEM;
 
@@ -1955,7 +2484,8 @@
 		       "from BIOS.  Using genenic mode...\n");
 	}
 
-	spec->init_verbs = vt1708B_4ch_volume_init_verbs;
+	spec->init_verbs[spec->num_iverbs++] = vt1708B_4ch_volume_init_verbs;
+	spec->init_verbs[spec->num_iverbs++] = vt1708B_uniwill_init_verbs;
 
 	spec->stream_name_analog = "VT1708B Analog";
 	spec->stream_analog_playback = &vt1708B_4ch_pcm_analog_playback;
@@ -1975,6 +2505,7 @@
 	codec->patch_ops = via_patch_ops;
 
 	codec->patch_ops.init = via_auto_init;
+	codec->patch_ops.unsol_event = via_unsol_event;
 #ifdef CONFIG_SND_HDA_POWER_SAVE
 	spec->loopback.amplist = vt1708B_loopbacks;
 #endif
@@ -1982,6 +2513,752 @@
 	return 0;
 }
 
+/* Patch for VT1708S */
+
+/* VT1708S software backdoor based override for buggy hardware micboost
+ * setting */
+#define MIC_BOOST_VOLUME(xname, nid) {				\
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,		\
+	.name = xname,					\
+	.index = 0,					\
+	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |	\
+	SNDRV_CTL_ELEM_ACCESS_TLV_READ |		\
+	SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK,		\
+	.info = mic_boost_volume_info,			\
+	.get = snd_hda_mixer_amp_volume_get,		\
+	.put = snd_hda_mixer_amp_volume_put,		\
+	.tlv = { .c = mic_boost_tlv },			\
+	.private_value = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT) }
+
+/* capture mixer elements */
+static struct snd_kcontrol_new vt1708S_capture_mixer[] = {
+	HDA_CODEC_VOLUME("Capture Volume", 0x13, 0x0, HDA_INPUT),
+	HDA_CODEC_MUTE("Capture Switch", 0x13, 0x0, HDA_INPUT),
+	HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x14, 0x0, HDA_INPUT),
+	HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x14, 0x0, HDA_INPUT),
+	MIC_BOOST_VOLUME("Mic Boost Capture Volume", 0x1A),
+	MIC_BOOST_VOLUME("Front Mic Boost Capture Volume", 0x1E),
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		/* The multiple "Capture Source" controls confuse alsamixer
+		 * So call somewhat different..
+		 */
+		/* .name = "Capture Source", */
+		.name = "Input Source",
+		.count = 1,
+		.info = via_mux_enum_info,
+		.get = via_mux_enum_get,
+		.put = via_mux_enum_put,
+	},
+	{ } /* end */
+};
+
+static struct hda_verb vt1708S_volume_init_verbs[] = {
+	/* Unmute ADC0-1 and set the default input to mic-in */
+	{0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+	{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+
+	/* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the
+	 * analog-loopback mixer widget */
+	/* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
+	{0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+	{0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+	{0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
+	{0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
+	{0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
+
+	/* Setup default input of PW4 to MW0 */
+	{0x1d, AC_VERB_SET_CONNECT_SEL, 0x0},
+	/* PW9, PW10  Output enable */
+	{0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
+	{0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
+	/* Enable Mic Boost Volume backdoor */
+	{0x1, 0xf98, 0x1},
+	{ }
+};
+
+static struct hda_verb vt1708S_uniwill_init_verbs[] = {
+	{0x1D, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_HP_EVENT},
+	{ }
+};
+
+static struct hda_pcm_stream vt1708S_pcm_analog_playback = {
+	.substreams = 2,
+	.channels_min = 2,
+	.channels_max = 8,
+	.nid = 0x10, /* NID to query formats and rates */
+	.ops = {
+		.open = via_playback_pcm_open,
+		.prepare = via_playback_pcm_prepare,
+		.cleanup = via_playback_pcm_cleanup
+	},
+};
+
+static struct hda_pcm_stream vt1708S_pcm_analog_capture = {
+	.substreams = 2,
+	.channels_min = 2,
+	.channels_max = 2,
+	.nid = 0x13, /* NID to query formats and rates */
+	.ops = {
+		.prepare = via_capture_pcm_prepare,
+		.cleanup = via_capture_pcm_cleanup
+	},
+};
+
+static struct hda_pcm_stream vt1708S_pcm_digital_playback = {
+	.substreams = 2,
+	.channels_min = 2,
+	.channels_max = 2,
+	/* NID is set in via_build_pcms */
+	.ops = {
+		.open = via_dig_playback_pcm_open,
+		.close = via_dig_playback_pcm_close,
+		.prepare = via_dig_playback_pcm_prepare
+	},
+};
+
+/* fill in the dac_nids table from the parsed pin configuration */
+static int vt1708S_auto_fill_dac_nids(struct via_spec *spec,
+				     const struct auto_pin_cfg *cfg)
+{
+	int i;
+	hda_nid_t nid;
+
+	spec->multiout.num_dacs = cfg->line_outs;
+
+	spec->multiout.dac_nids = spec->private_dac_nids;
+
+	for (i = 0; i < 4; i++) {
+		nid = cfg->line_out_pins[i];
+		if (nid) {
+			/* config dac list */
+			switch (i) {
+			case AUTO_SEQ_FRONT:
+				spec->multiout.dac_nids[i] = 0x10;
+				break;
+			case AUTO_SEQ_CENLFE:
+				spec->multiout.dac_nids[i] = 0x24;
+				break;
+			case AUTO_SEQ_SURROUND:
+				spec->multiout.dac_nids[i] = 0x11;
+				break;
+			case AUTO_SEQ_SIDE:
+				spec->multiout.dac_nids[i] = 0x25;
+				break;
+			}
+		}
+	}
+
+	return 0;
+}
+
+/* add playback controls from the parsed DAC table */
+static int vt1708S_auto_create_multi_out_ctls(struct via_spec *spec,
+					     const struct auto_pin_cfg *cfg)
+{
+	char name[32];
+	static const char *chname[4] = { "Front", "Surround", "C/LFE", "Side" };
+	hda_nid_t nid_vols[] = {0x10, 0x11, 0x24, 0x25};
+	hda_nid_t nid_mutes[] = {0x1C, 0x18, 0x26, 0x27};
+	hda_nid_t nid, nid_vol, nid_mute;
+	int i, err;
+
+	for (i = 0; i <= AUTO_SEQ_SIDE; i++) {
+		nid = cfg->line_out_pins[i];
+
+		if (!nid)
+			continue;
+
+		nid_vol = nid_vols[i];
+		nid_mute = nid_mutes[i];
+
+		if (i == AUTO_SEQ_CENLFE) {
+			/* Center/LFE */
+			err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
+					      "Center Playback Volume",
+					      HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0,
+								  HDA_OUTPUT));
+			if (err < 0)
+				return err;
+			err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
+					      "LFE Playback Volume",
+					      HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0,
+								  HDA_OUTPUT));
+			if (err < 0)
+				return err;
+			err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
+					      "Center Playback Switch",
+					      HDA_COMPOSE_AMP_VAL(nid_mute,
+								  1, 0,
+								  HDA_OUTPUT));
+			if (err < 0)
+				return err;
+			err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
+					      "LFE Playback Switch",
+					      HDA_COMPOSE_AMP_VAL(nid_mute,
+								  2, 0,
+								  HDA_OUTPUT));
+			if (err < 0)
+				return err;
+		} else if (i == AUTO_SEQ_FRONT) {
+			/* add control to mixer index 0 */
+			err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
+					      "Master Front Playback Volume",
+					      HDA_COMPOSE_AMP_VAL(0x16, 3, 0,
+								  HDA_INPUT));
+			if (err < 0)
+				return err;
+			err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
+					      "Master Front Playback Switch",
+					      HDA_COMPOSE_AMP_VAL(0x16, 3, 0,
+								  HDA_INPUT));
+			if (err < 0)
+				return err;
+
+			/* Front */
+			sprintf(name, "%s Playback Volume", chname[i]);
+			err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
+					      HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
+								  HDA_OUTPUT));
+			if (err < 0)
+				return err;
+			sprintf(name, "%s Playback Switch", chname[i]);
+			err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
+					      HDA_COMPOSE_AMP_VAL(nid_mute,
+								  3, 0,
+								  HDA_OUTPUT));
+			if (err < 0)
+				return err;
+		} else {
+			sprintf(name, "%s Playback Volume", chname[i]);
+			err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
+					      HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
+								  HDA_OUTPUT));
+			if (err < 0)
+				return err;
+			sprintf(name, "%s Playback Switch", chname[i]);
+			err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
+					      HDA_COMPOSE_AMP_VAL(nid_mute,
+								  3, 0,
+								  HDA_OUTPUT));
+			if (err < 0)
+				return err;
+		}
+	}
+
+	return 0;
+}
+
+static int vt1708S_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
+{
+	int err;
+
+	if (!pin)
+		return 0;
+
+	spec->multiout.hp_nid = VT1708S_HP_NID; /* AOW3 */
+
+	err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
+			      "Headphone Playback Volume",
+			      HDA_COMPOSE_AMP_VAL(0x25, 3, 0, HDA_OUTPUT));
+	if (err < 0)
+		return err;
+
+	err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
+			      "Headphone Playback Switch",
+			      HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
+	if (err < 0)
+		return err;
+
+	create_hp_imux(spec);
+
+	return 0;
+}
+
+/* create playback/capture controls for input pins */
+static int vt1708S_auto_create_analog_input_ctls(struct via_spec *spec,
+						const struct auto_pin_cfg *cfg)
+{
+	static char *labels[] = {
+		"Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
+	};
+	struct hda_input_mux *imux = &spec->private_imux[0];
+	int i, err, idx = 0;
+
+	/* for internal loopback recording select */
+	imux->items[imux->num_items].label = "Stereo Mixer";
+	imux->items[imux->num_items].index = 5;
+	imux->num_items++;
+
+	for (i = 0; i < AUTO_PIN_LAST; i++) {
+		if (!cfg->input_pins[i])
+			continue;
+
+		switch (cfg->input_pins[i]) {
+		case 0x1a: /* Mic */
+			idx = 2;
+			break;
+
+		case 0x1b: /* Line In */
+			idx = 3;
+			break;
+
+		case 0x1e: /* Front Mic */
+			idx = 4;
+			break;
+
+		case 0x1f: /* CD */
+			idx = 1;
+			break;
+		}
+		err = via_new_analog_input(spec, cfg->input_pins[i], labels[i],
+					   idx, 0x16);
+		if (err < 0)
+			return err;
+		imux->items[imux->num_items].label = labels[i];
+		imux->items[imux->num_items].index = idx-1;
+		imux->num_items++;
+	}
+	return 0;
+}
+
+static int vt1708S_parse_auto_config(struct hda_codec *codec)
+{
+	struct via_spec *spec = codec->spec;
+	int err;
+	static hda_nid_t vt1708s_ignore[] = {0x21, 0};
+
+	err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
+					   vt1708s_ignore);
+	if (err < 0)
+		return err;
+	err = vt1708S_auto_fill_dac_nids(spec, &spec->autocfg);
+	if (err < 0)
+		return err;
+	if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0])
+		return 0; /* can't find valid BIOS pin config */
+
+	err = vt1708S_auto_create_multi_out_ctls(spec, &spec->autocfg);
+	if (err < 0)
+		return err;
+	err = vt1708S_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
+	if (err < 0)
+		return err;
+	err = vt1708S_auto_create_analog_input_ctls(spec, &spec->autocfg);
+	if (err < 0)
+		return err;
+
+	spec->multiout.max_channels = spec->multiout.num_dacs * 2;
+
+	if (spec->autocfg.dig_out_pin)
+		spec->multiout.dig_out_nid = VT1708S_DIGOUT_NID;
+
+	spec->extra_dig_out_nid = 0x15;
+
+	if (spec->kctl_alloc)
+		spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
+
+	spec->input_mux = &spec->private_imux[0];
+
+	if (spec->hp_mux)
+		spec->mixers[spec->num_mixers++] = via_hp_mixer;
+
+	return 1;
+}
+
+#ifdef CONFIG_SND_HDA_POWER_SAVE
+static struct hda_amp_list vt1708S_loopbacks[] = {
+	{ 0x16, HDA_INPUT, 1 },
+	{ 0x16, HDA_INPUT, 2 },
+	{ 0x16, HDA_INPUT, 3 },
+	{ 0x16, HDA_INPUT, 4 },
+	{ } /* end */
+};
+#endif
+
+static int patch_vt1708S(struct hda_codec *codec)
+{
+	struct via_spec *spec;
+	int err;
+
+	/* create a codec specific record */
+	spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+	if (spec == NULL)
+		return -ENOMEM;
+
+	codec->spec = spec;
+
+	/* automatic parse from the BIOS config */
+	err = vt1708S_parse_auto_config(codec);
+	if (err < 0) {
+		via_free(codec);
+		return err;
+	} else if (!err) {
+		printk(KERN_INFO "hda_codec: Cannot set up configuration "
+		       "from BIOS.  Using genenic mode...\n");
+	}
+
+	spec->init_verbs[spec->num_iverbs++] = vt1708S_volume_init_verbs;
+	spec->init_verbs[spec->num_iverbs++] = vt1708S_uniwill_init_verbs;
+
+	spec->stream_name_analog = "VT1708S Analog";
+	spec->stream_analog_playback = &vt1708S_pcm_analog_playback;
+	spec->stream_analog_capture = &vt1708S_pcm_analog_capture;
+
+	spec->stream_name_digital = "VT1708S Digital";
+	spec->stream_digital_playback = &vt1708S_pcm_digital_playback;
+
+	if (!spec->adc_nids && spec->input_mux) {
+		spec->adc_nids = vt1708S_adc_nids;
+		spec->num_adc_nids = ARRAY_SIZE(vt1708S_adc_nids);
+		spec->mixers[spec->num_mixers] = vt1708S_capture_mixer;
+		spec->num_mixers++;
+	}
+
+	codec->patch_ops = via_patch_ops;
+
+	codec->patch_ops.init = via_auto_init;
+	codec->patch_ops.unsol_event = via_unsol_event;
+#ifdef CONFIG_SND_HDA_POWER_SAVE
+	spec->loopback.amplist = vt1708S_loopbacks;
+#endif
+
+	return 0;
+}
+
+/* Patch for VT1702 */
+
+/* capture mixer elements */
+static struct snd_kcontrol_new vt1702_capture_mixer[] = {
+	HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_INPUT),
+	HDA_CODEC_MUTE("Capture Switch", 0x12, 0x0, HDA_INPUT),
+	HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x20, 0x0, HDA_INPUT),
+	HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x20, 0x0, HDA_INPUT),
+	HDA_CODEC_VOLUME("Digital Mic Capture Volume", 0x1F, 0x0, HDA_INPUT),
+	HDA_CODEC_MUTE("Digital Mic Capture Switch", 0x1F, 0x0, HDA_INPUT),
+	HDA_CODEC_VOLUME("Digital Mic Boost Capture Volume", 0x1E, 0x0,
+			 HDA_INPUT),
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		/* The multiple "Capture Source" controls confuse alsamixer
+		 * So call somewhat different..
+		 */
+		/* .name = "Capture Source", */
+		.name = "Input Source",
+		.count = 1,
+		.info = via_mux_enum_info,
+		.get = via_mux_enum_get,
+		.put = via_mux_enum_put,
+	},
+	{ } /* end */
+};
+
+static struct hda_verb vt1702_volume_init_verbs[] = {
+	/*
+	 * Unmute ADC0-1 and set the default input to mic-in
+	 */
+	{0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+	{0x1F, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+	{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+
+
+	/* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
+	 * mixer widget
+	 */
+	/* Amp Indices: Mic1 = 1, Line = 1, Mic2 = 3 */
+	{0x1A, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+	{0x1A, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+	{0x1A, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
+	{0x1A, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
+	{0x1A, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
+
+	/* Setup default input of PW4 to MW0 */
+	{0x17, AC_VERB_SET_CONNECT_SEL, 0x1},
+	/* PW6 PW7 Output enable */
+	{0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
+	{0x1C, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
+	{ }
+};
+
+static struct hda_verb vt1702_uniwill_init_verbs[] = {
+	{0x01, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_GPIO_EVENT},
+	{0x17, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_HP_EVENT},
+	{ }
+};
+
+static struct hda_pcm_stream vt1702_pcm_analog_playback = {
+	.substreams = 2,
+	.channels_min = 2,
+	.channels_max = 2,
+	.nid = 0x10, /* NID to query formats and rates */
+	.ops = {
+		.open = via_playback_pcm_open,
+		.prepare = via_playback_multi_pcm_prepare,
+		.cleanup = via_playback_multi_pcm_cleanup
+	},
+};
+
+static struct hda_pcm_stream vt1702_pcm_analog_capture = {
+	.substreams = 3,
+	.channels_min = 2,
+	.channels_max = 2,
+	.nid = 0x12, /* NID to query formats and rates */
+	.ops = {
+		.prepare = via_capture_pcm_prepare,
+		.cleanup = via_capture_pcm_cleanup
+	},
+};
+
+static struct hda_pcm_stream vt1702_pcm_digital_playback = {
+	.substreams = 2,
+	.channels_min = 2,
+	.channels_max = 2,
+	/* NID is set in via_build_pcms */
+	.ops = {
+		.open = via_dig_playback_pcm_open,
+		.close = via_dig_playback_pcm_close,
+		.prepare = via_dig_playback_pcm_prepare
+	},
+};
+
+/* fill in the dac_nids table from the parsed pin configuration */
+static int vt1702_auto_fill_dac_nids(struct via_spec *spec,
+				     const struct auto_pin_cfg *cfg)
+{
+	spec->multiout.num_dacs = 1;
+	spec->multiout.dac_nids = spec->private_dac_nids;
+
+	if (cfg->line_out_pins[0]) {
+		/* config dac list */
+		spec->multiout.dac_nids[0] = 0x10;
+	}
+
+	return 0;
+}
+
+/* add playback controls from the parsed DAC table */
+static int vt1702_auto_create_line_out_ctls(struct via_spec *spec,
+					     const struct auto_pin_cfg *cfg)
+{
+	int err;
+
+	if (!cfg->line_out_pins[0])
+		return -1;
+
+	/* add control to mixer index 0 */
+	err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
+			      "Master Front Playback Volume",
+			      HDA_COMPOSE_AMP_VAL(0x1A, 3, 0, HDA_INPUT));
+	if (err < 0)
+		return err;
+	err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
+			      "Master Front Playback Switch",
+			      HDA_COMPOSE_AMP_VAL(0x1A, 3, 0, HDA_INPUT));
+	if (err < 0)
+		return err;
+
+	/* Front */
+	err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
+			      "Front Playback Volume",
+			      HDA_COMPOSE_AMP_VAL(0x10, 3, 0, HDA_OUTPUT));
+	if (err < 0)
+		return err;
+	err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
+			      "Front Playback Switch",
+			      HDA_COMPOSE_AMP_VAL(0x16, 3, 0, HDA_OUTPUT));
+	if (err < 0)
+		return err;
+
+	return 0;
+}
+
+static int vt1702_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
+{
+	int err;
+
+	if (!pin)
+		return 0;
+
+	spec->multiout.hp_nid = 0x1D;
+
+	err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
+			      "Headphone Playback Volume",
+			      HDA_COMPOSE_AMP_VAL(0x1D, 3, 0, HDA_OUTPUT));
+	if (err < 0)
+		return err;
+
+	err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
+			      "Headphone Playback Switch",
+			      HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
+	if (err < 0)
+		return err;
+
+	create_hp_imux(spec);
+
+	return 0;
+}
+
+/* create playback/capture controls for input pins */
+static int vt1702_auto_create_analog_input_ctls(struct via_spec *spec,
+						const struct auto_pin_cfg *cfg)
+{
+	static char *labels[] = {
+		"Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
+	};
+	struct hda_input_mux *imux = &spec->private_imux[0];
+	int i, err, idx = 0;
+
+	/* for internal loopback recording select */
+	imux->items[imux->num_items].label = "Stereo Mixer";
+	imux->items[imux->num_items].index = 3;
+	imux->num_items++;
+
+	for (i = 0; i < AUTO_PIN_LAST; i++) {
+		if (!cfg->input_pins[i])
+			continue;
+
+		switch (cfg->input_pins[i]) {
+		case 0x14: /* Mic */
+			idx = 1;
+			break;
+
+		case 0x15: /* Line In */
+			idx = 2;
+			break;
+
+		case 0x18: /* Front Mic */
+			idx = 3;
+			break;
+		}
+		err = via_new_analog_input(spec, cfg->input_pins[i],
+					   labels[i], idx, 0x1A);
+		if (err < 0)
+			return err;
+		imux->items[imux->num_items].label = labels[i];
+		imux->items[imux->num_items].index = idx-1;
+		imux->num_items++;
+	}
+	return 0;
+}
+
+static int vt1702_parse_auto_config(struct hda_codec *codec)
+{
+	struct via_spec *spec = codec->spec;
+	int err;
+	static hda_nid_t vt1702_ignore[] = {0x1C, 0};
+
+	err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
+					   vt1702_ignore);
+	if (err < 0)
+		return err;
+	err = vt1702_auto_fill_dac_nids(spec, &spec->autocfg);
+	if (err < 0)
+		return err;
+	if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0])
+		return 0; /* can't find valid BIOS pin config */
+
+	err = vt1702_auto_create_line_out_ctls(spec, &spec->autocfg);
+	if (err < 0)
+		return err;
+	err = vt1702_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
+	if (err < 0)
+		return err;
+	err = vt1702_auto_create_analog_input_ctls(spec, &spec->autocfg);
+	if (err < 0)
+		return err;
+
+	spec->multiout.max_channels = spec->multiout.num_dacs * 2;
+
+	if (spec->autocfg.dig_out_pin)
+		spec->multiout.dig_out_nid = VT1702_DIGOUT_NID;
+
+	spec->extra_dig_out_nid = 0x1B;
+
+	if (spec->kctl_alloc)
+		spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
+
+	spec->input_mux = &spec->private_imux[0];
+
+	if (spec->hp_mux)
+		spec->mixers[spec->num_mixers++] = via_hp_mixer;
+
+	return 1;
+}
+
+#ifdef CONFIG_SND_HDA_POWER_SAVE
+static struct hda_amp_list vt1702_loopbacks[] = {
+	{ 0x1A, HDA_INPUT, 1 },
+	{ 0x1A, HDA_INPUT, 2 },
+	{ 0x1A, HDA_INPUT, 3 },
+	{ 0x1A, HDA_INPUT, 4 },
+	{ } /* end */
+};
+#endif
+
+static int patch_vt1702(struct hda_codec *codec)
+{
+	struct via_spec *spec;
+	int err;
+	unsigned int response;
+	unsigned char control;
+
+	/* create a codec specific record */
+	spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+	if (spec == NULL)
+		return -ENOMEM;
+
+	codec->spec = spec;
+
+	/* automatic parse from the BIOS config */
+	err = vt1702_parse_auto_config(codec);
+	if (err < 0) {
+		via_free(codec);
+		return err;
+	} else if (!err) {
+		printk(KERN_INFO "hda_codec: Cannot set up configuration "
+		       "from BIOS.  Using genenic mode...\n");
+	}
+
+	spec->init_verbs[spec->num_iverbs++] = vt1702_volume_init_verbs;
+	spec->init_verbs[spec->num_iverbs++] = vt1702_uniwill_init_verbs;
+
+	spec->stream_name_analog = "VT1702 Analog";
+	spec->stream_analog_playback = &vt1702_pcm_analog_playback;
+	spec->stream_analog_capture = &vt1702_pcm_analog_capture;
+
+	spec->stream_name_digital = "VT1702 Digital";
+	spec->stream_digital_playback = &vt1702_pcm_digital_playback;
+
+	if (!spec->adc_nids && spec->input_mux) {
+		spec->adc_nids = vt1702_adc_nids;
+		spec->num_adc_nids = ARRAY_SIZE(vt1702_adc_nids);
+		spec->mixers[spec->num_mixers] = vt1702_capture_mixer;
+		spec->num_mixers++;
+	}
+
+	codec->patch_ops = via_patch_ops;
+
+	codec->patch_ops.init = via_auto_init;
+	codec->patch_ops.unsol_event = via_unsol_event;
+#ifdef CONFIG_SND_HDA_POWER_SAVE
+	spec->loopback.amplist = vt1702_loopbacks;
+#endif
+
+	/* Open backdoor */
+	response = snd_hda_codec_read(codec, codec->afg, 0, 0xF8C, 0);
+	control = (unsigned char)(response & 0xff);
+	control |= 0x3;
+	snd_hda_codec_write(codec,  codec->afg, 0, 0xF88, control);
+
+	/* Enable GPIO 0&1 for volume&mute control */
+	/* Enable GPIO 2 for DMIC-DATA */
+	response = snd_hda_codec_read(codec, codec->afg, 0, 0xF84, 0);
+	control = (unsigned char)((response >> 16) & 0x3f);
+	snd_hda_codec_write(codec,  codec->afg, 0, 0xF82, control);
+
+	return 0;
+}
+
 /*
  * patch entries
  */
@@ -2022,5 +3299,37 @@
 	  .patch = patch_vt1708B_4ch},
 	{ .id = 0x1106E727, .name = "VIA VT1708B 4-Ch",
 	  .patch = patch_vt1708B_4ch},
+	{ .id = 0x11060397, .name = "VIA VT1708S",
+	  .patch = patch_vt1708S},
+	{ .id = 0x11061397, .name = "VIA VT1708S",
+	  .patch = patch_vt1708S},
+	{ .id = 0x11062397, .name = "VIA VT1708S",
+	  .patch = patch_vt1708S},
+	{ .id = 0x11063397, .name = "VIA VT1708S",
+	  .patch = patch_vt1708S},
+	{ .id = 0x11064397, .name = "VIA VT1708S",
+	  .patch = patch_vt1708S},
+	{ .id = 0x11065397, .name = "VIA VT1708S",
+	  .patch = patch_vt1708S},
+	{ .id = 0x11066397, .name = "VIA VT1708S",
+	  .patch = patch_vt1708S},
+	{ .id = 0x11067397, .name = "VIA VT1708S",
+	  .patch = patch_vt1708S},
+	{ .id = 0x11060398, .name = "VIA VT1702",
+	  .patch = patch_vt1702},
+	{ .id = 0x11061398, .name = "VIA VT1702",
+	  .patch = patch_vt1702},
+	{ .id = 0x11062398, .name = "VIA VT1702",
+	  .patch = patch_vt1702},
+	{ .id = 0x11063398, .name = "VIA VT1702",
+	  .patch = patch_vt1702},
+	{ .id = 0x11064398, .name = "VIA VT1702",
+	  .patch = patch_vt1702},
+	{ .id = 0x11065398, .name = "VIA VT1702",
+	  .patch = patch_vt1702},
+	{ .id = 0x11066398, .name = "VIA VT1702",
+	  .patch = patch_vt1702},
+	{ .id = 0x11067398, .name = "VIA VT1702",
+	  .patch = patch_vt1702},
 	{} /* terminator */
 };
diff --git a/sound/pci/ice1712/ak4xxx.c b/sound/pci/ice1712/ak4xxx.c
index dab31b2..03391da 100644
--- a/sound/pci/ice1712/ak4xxx.c
+++ b/sound/pci/ice1712/ak4xxx.c
@@ -59,7 +59,8 @@
 	struct snd_ak4xxx_private *priv = (void *)ak->private_value[0];
 	struct snd_ice1712 *ice = ak->private_data[0];
 
-	snd_assert(chip >= 0 && chip < 4, return);
+	if (snd_BUG_ON(chip < 0 || chip >= 4))
+		return;
 
 	tmp = snd_ice1712_gpio_read(ice);
 	tmp |= priv->add_flags;
diff --git a/sound/pci/ice1712/aureon.c b/sound/pci/ice1712/aureon.c
index 868ae29..110d16e 100644
--- a/sound/pci/ice1712/aureon.c
+++ b/sound/pci/ice1712/aureon.c
@@ -44,10 +44,9 @@
  *       not working: prety much everything else, at least i could verify that
  *                    we have no digital output, no capture, pretty bad clicks and poops
  *                    on mixer switch and other coll stuff.
- *
- */      
+ */
 
-#include <asm/io.h>
+#include <linux/io.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
 #include <linux/init.h>
@@ -131,7 +130,7 @@
 	snd_ice1712_gpio_write(ice, tmp);
 	udelay(50);
 
-	/* 
+	/*
 	 * send i2c stop condition and start condition
 	 * to obtain sane state
 	 */
@@ -152,10 +151,16 @@
 	 * skipping ack cycles inbetween
 	 */
 	for (j = 0; j < 3; j++) {
-		switch(j) {
-		case 0: val = dev; break;
-		case 1: val = reg; break;
-		case 2: val = data; break;
+		switch (j) {
+		case 0:
+			val = dev;
+			break;
+		case 1:
+			val = reg;
+			break;
+		case 2:
+			val = data;
+			break;
 		}
 		for (i = 7; i >= 0; i--) {
 			tmp &= ~AUREON_SPI_CLK;
@@ -171,7 +176,7 @@
 			snd_ice1712_gpio_write(ice, tmp);
 			udelay(40);
 		}
-                tmp &= ~AUREON_SPI_CLK;
+		tmp &= ~AUREON_SPI_CLK;
 		snd_ice1712_gpio_write(ice, tmp);
 		udelay(40);
 		tmp |= AUREON_SPI_CLK;
@@ -203,7 +208,7 @@
 	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
 	uinfo->count = 1;
 	uinfo->value.enumerated.items = 3;
-	if(uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
+	if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
 		uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
 	strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
 	return 0;
@@ -231,12 +236,12 @@
 		return -EINVAL;
 	snd_ice1712_save_gpio_status(ice);
 	oval = spec->pca9554_out;
-	if ((change = (oval != nval))) {
+	change = (oval != nval);
+	if (change) {
 		aureon_pca9554_write(ice, PCA9554_OUT, nval);
 		spec->pca9554_out = nval;
 	}
 	snd_ice1712_restore_gpio_status(ice);
-	
 	return change;
 }
 
@@ -256,7 +261,7 @@
 	udelay(10);
 	tmp &= ~AUREON_AC97_ADDR;
 	snd_ice1712_gpio_write(ice, tmp);
-	udelay(10);	
+	udelay(10);
 
 	/* Send low-order byte to XILINX chip */
 	tmp &= ~AUREON_AC97_DATA_MASK;
@@ -269,7 +274,7 @@
 	tmp &= ~AUREON_AC97_DATA_LOW;
 	snd_ice1712_gpio_write(ice, tmp);
 	udelay(10);
-	
+
 	/* Send high-order byte to XILINX chip */
 	tmp &= ~AUREON_AC97_DATA_MASK;
 	tmp |= (val >> 8) & AUREON_AC97_DATA_MASK;
@@ -282,7 +287,7 @@
 	tmp &= ~AUREON_AC97_DATA_HIGH;
 	snd_ice1712_gpio_write(ice, tmp);
 	udelay(10);
-	
+
 	/* Instruct XILINX chip to parse the data to the STAC9744 chip */
 	tmp |= AUREON_AC97_COMMIT;
 	snd_ice1712_gpio_write(ice, tmp);
@@ -290,7 +295,7 @@
 	tmp &= ~AUREON_AC97_COMMIT;
 	snd_ice1712_gpio_write(ice, tmp);
 	udelay(10);
-	
+
 	/* Store the data in out private buffer */
 	spec->stac9744[(reg & 0x7F) >> 1] = val;
 }
@@ -304,7 +309,7 @@
 /*
  * Initialize STAC9744 chip
  */
-static int aureon_ac97_init (struct snd_ice1712 *ice)
+static int aureon_ac97_init(struct snd_ice1712 *ice)
 {
 	struct aureon_spec *spec = ice->spec;
 	int i;
@@ -335,20 +340,21 @@
 	tmp = (snd_ice1712_gpio_read(ice) | AUREON_AC97_RESET) & ~AUREON_AC97_DATA_MASK;
 	snd_ice1712_gpio_write(ice, tmp);
 	udelay(3);
-	
+
 	tmp &= ~AUREON_AC97_RESET;
 	snd_ice1712_gpio_write(ice, tmp);
 	udelay(3);
-	
+
 	tmp |= AUREON_AC97_RESET;
 	snd_ice1712_gpio_write(ice, tmp);
 	udelay(3);
-	
+
 	memset(&spec->stac9744, 0, sizeof(spec->stac9744));
-	for (i=0; ac97_defaults[i] != (unsigned short)-1; i+=2)
+	for (i = 0; ac97_defaults[i] != (unsigned short)-1; i += 2)
 		spec->stac9744[(ac97_defaults[i]) >> 1] = ac97_defaults[i+1];
-		
-	aureon_ac97_write(ice, AC97_MASTER, 0x0000); // Unmute AC'97 master volume permanently - muting is done by WM8770
+
+	/* Unmute AC'97 master volume permanently - muting is done by WM8770 */
+	aureon_ac97_write(ice, AC97_MASTER, 0x0000);
 
 	return 0;
 }
@@ -388,7 +394,7 @@
 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
 	unsigned short ovol, nvol;
 	int change;
-	
+
 	snd_ice1712_save_gpio_status(ice);
 
 	ovol = aureon_ac97_read(ice, kcontrol->private_value & 0x7F);
@@ -396,13 +402,14 @@
 	if (kcontrol->private_value & AUREON_AC97_STEREO)
 		nvol |= ((0x1F - ucontrol->value.integer.value[1]) << 8) & 0x1F00;
 	nvol |= ovol & ~0x1F1F;
-	
-	if ((change = (ovol != nvol)))
+
+	change = (ovol != nvol);
+	if (change)
 		aureon_ac97_write(ice, kcontrol->private_value & 0x7F, nvol);
 
 	snd_ice1712_restore_gpio_status(ice);
 
-	return change;		
+	return change;
 }
 
 /*
@@ -416,7 +423,8 @@
 
 	mutex_lock(&ice->gpio_mutex);
 
-	ucontrol->value.integer.value[0] = aureon_ac97_read(ice, kcontrol->private_value & 0x7F) & 0x8000 ? 0 : 1;
+	ucontrol->value.integer.value[0] = aureon_ac97_read(ice,
+			kcontrol->private_value & 0x7F) & 0x8000 ? 0 : 1;
 
 	mutex_unlock(&ice->gpio_mutex);
 	return 0;
@@ -429,13 +437,14 @@
 	int change;
 
 	snd_ice1712_save_gpio_status(ice);
-	
+
 	ovol = aureon_ac97_read(ice, kcontrol->private_value & 0x7F);
-	nvol = (ucontrol->value.integer.value[0] ? 0x0000 : 0x8000) | (ovol & ~	0x8000);
-	
-	if ((change = (ovol != nvol)))
+	nvol = (ucontrol->value.integer.value[0] ? 0x0000 : 0x8000) | (ovol & ~0x8000);
+
+	change = (ovol != nvol);
+	if (change)
 		aureon_ac97_write(ice, kcontrol->private_value & 0x7F, nvol);
-		
+
 	snd_ice1712_restore_gpio_status(ice);
 
 	return change;
@@ -465,13 +474,14 @@
 	int change;
 
 	snd_ice1712_save_gpio_status(ice);
-	
+
 	ovol = aureon_ac97_read(ice, AC97_MIC);
 	nvol = (ucontrol->value.integer.value[0] ? 0x0000 : 0x0020) | (ovol & ~0x0020);
-	
-	if ((change = (ovol != nvol)))
+
+	change = (ovol != nvol);
+	if (change)
 		aureon_ac97_write(ice, AC97_MIC, nvol);
-		
+
 	snd_ice1712_restore_gpio_status(ice);
 
 	return change;
@@ -493,16 +503,15 @@
 		snd_ice1712_gpio_set_mask(ice, ~(PRODIGY_SPI_MOSI|PRODIGY_SPI_CLK|PRODIGY_WM_CS));
 		mosi = PRODIGY_SPI_MOSI;
 		clk = PRODIGY_SPI_CLK;
-	}
-	else {
+	} else {
 		snd_ice1712_gpio_set_mask(ice, ~(AUREON_WM_RW|AUREON_SPI_MOSI|AUREON_SPI_CLK|
 						 AUREON_WM_CS|AUREON_CS8415_CS));
 		mosi = AUREON_SPI_MOSI;
 		clk = AUREON_SPI_CLK;
-		
+
 		tmp |= AUREON_WM_RW;
 	}
-	
+
 	tmp &= ~cs;
 	snd_ice1712_gpio_write(ice, tmp);
 	udelay(1);
@@ -534,7 +543,9 @@
 /*
  * Read data in SPI mode
  */
-static void aureon_spi_read(struct snd_ice1712 *ice, unsigned int cs, unsigned int data, int bits, unsigned char *buffer, int size) {
+static void aureon_spi_read(struct snd_ice1712 *ice, unsigned int cs,
+		unsigned int data, int bits, unsigned char *buffer, int size)
+{
 	int i, j;
 	unsigned int tmp;
 
@@ -544,7 +555,7 @@
 	snd_ice1712_gpio_write(ice, tmp);
 	udelay(1);
 
-	for (i=bits-1; i>=0; i--) {
+	for (i = bits-1; i >= 0; i--) {
 		if (data & (1 << i))
 			tmp |= AUREON_SPI_MOSI;
 		else
@@ -561,9 +572,9 @@
 		udelay(1);
 	}
 
-	for (j=0; j<size; j++) {
+	for (j = 0; j < size; j++) {
 		unsigned char outdata = 0;
-		for (i=7; i>=0; i--) {
+		for (i = 7; i >= 0; i--) {
 			tmp = snd_ice1712_gpio_read(ice);
 			outdata <<= 1;
 			outdata |= (tmp & AUREON_SPI_MISO) ? 1 : 0;
@@ -584,19 +595,24 @@
 	snd_ice1712_gpio_write(ice, tmp);
 }
 
-static unsigned char aureon_cs8415_get(struct snd_ice1712 *ice, int reg) {
+static unsigned char aureon_cs8415_get(struct snd_ice1712 *ice, int reg)
+{
 	unsigned char val;
 	aureon_spi_write(ice, AUREON_CS8415_CS, 0x2000 | reg, 16);
 	aureon_spi_read(ice, AUREON_CS8415_CS, 0x21, 8, &val, 1);
 	return val;
 }
 
-static void aureon_cs8415_read(struct snd_ice1712 *ice, int reg, unsigned char *buffer, int size) {
+static void aureon_cs8415_read(struct snd_ice1712 *ice, int reg,
+				unsigned char *buffer, int size)
+{
 	aureon_spi_write(ice, AUREON_CS8415_CS, 0x2000 | reg, 16);
 	aureon_spi_read(ice, AUREON_CS8415_CS, 0x21, 8, buffer, size);
 }
 
-static void aureon_cs8415_put(struct snd_ice1712 *ice, int reg, unsigned char val) {
+static void aureon_cs8415_put(struct snd_ice1712 *ice, int reg,
+						unsigned char val)
+{
 	aureon_spi_write(ice, AUREON_CS8415_CS, 0x200000 | (reg << 8) | val, 24);
 }
 
@@ -654,18 +670,20 @@
 	return 0;
 }
 
-static int aureon_ac97_mmute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) {
+static int aureon_ac97_mmute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+{
 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
 	unsigned short ovol, nvol;
 	int change;
-	
+
 	snd_ice1712_save_gpio_status(ice);
-	
+
 	ovol = wm_get(ice, WM_OUT_MUX1);
 	nvol = (ovol & ~0x02) | (ucontrol->value.integer.value[0] ? 0x02 : 0x00);
-	if ((change = (ovol != nvol)))
+	change = (ovol != nvol);
+	if (change)
 		wm_put(ice, WM_OUT_MUX1, nvol);
-		
+
 	snd_ice1712_restore_gpio_status(ice);
 
 	return change;
@@ -702,12 +720,12 @@
 static void wm_set_vol(struct snd_ice1712 *ice, unsigned int index, unsigned short vol, unsigned short master)
 {
 	unsigned char nvol;
-	
+
 	if ((master & WM_VOL_MUTE) || (vol & WM_VOL_MUTE))
 		nvol = 0;
 	else
 		nvol = 127 - wm_vol[(((vol & ~WM_VOL_MUTE) * (master & ~WM_VOL_MUTE)) / 127) & WM_VOL_MAX];
-	
+
 	wm_put(ice, index, nvol);
 	wm_put_nocache(ice, index, 0x180 | nvol);
 }
@@ -736,7 +754,8 @@
 	snd_ice1712_save_gpio_status(ice);
 	oval = wm_get(ice, WM_MUTE);
 	nval = (oval & ~0x10) | (ucontrol->value.integer.value[0] ? 0 : 0x10);
-	if ((change = (nval != oval)))
+	change = (oval != nval);
+	if (change)
 		wm_put(ice, WM_MUTE, nval);
 	snd_ice1712_restore_gpio_status(ice);
 
@@ -760,7 +779,7 @@
 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
 	struct aureon_spec *spec = ice->spec;
 	int i;
-	for (i=0; i<2; i++)
+	for (i = 0; i < 2; i++)
 		ucontrol->value.integer.value[i] =
 			spec->master[i] & ~WM_VOL_MUTE;
 	return 0;
@@ -849,7 +868,8 @@
 /*
  * WM8770 mute control
  */
-static int wm_mute_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) {
+static int wm_mute_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
+{
 	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
 	uinfo->count = kcontrol->private_value >> 8;
 	uinfo->value.integer.min = 0;
@@ -862,7 +882,7 @@
 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
 	struct aureon_spec *spec = ice->spec;
 	int voices, ofs, i;
-	
+
 	voices = kcontrol->private_value >> 8;
 	ofs = kcontrol->private_value & 0xFF;
 
@@ -907,7 +927,7 @@
 {
 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
 	struct aureon_spec *spec = ice->spec;
-	
+
 	ucontrol->value.integer.value[0] =
 		(spec->master[0] & WM_VOL_MUTE) ? 0 : 1;
 	ucontrol->value.integer.value[1] =
@@ -1083,21 +1103,21 @@
 static int wm_adc_mux_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
 {
 	static const char * const texts[] = {
-		"CD",		//AIN1
-		"Aux",		//AIN2
-		"Line",		//AIN3
-		"Mic",		//AIN4
-		"AC97"		//AIN5
+		"CD",		/* AIN1 */
+		"Aux",		/* AIN2 */
+		"Line",		/* AIN3 */
+		"Mic",		/* AIN4 */
+		"AC97"		/* AIN5 */
 	};
 	static const char * const universe_texts[] = {
-		"Aux1",		//AIN1
-		"CD",		//AIN2
-		"Phono",	//AIN3
-		"Line",		//AIN4
-		"Aux2",		//AIN5
-		"Mic",		//AIN6
-		"Aux3",		//AIN7
-		"AC97"		//AIN8
+		"Aux1",		/* AIN1 */
+		"CD",		/* AIN2 */
+		"Phono",	/* AIN3 */
+		"Line",		/* AIN4 */
+		"Aux2",		/* AIN5 */
+		"Mic",		/* AIN6 */
+		"Aux3",		/* AIN7 */
+		"AC97"		/* AIN8 */
 	};
 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
 
@@ -1108,8 +1128,7 @@
 		if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
 			uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
 		strcpy(uinfo->value.enumerated.name, universe_texts[uinfo->value.enumerated.item]);
-	}
-	else {
+	} else {
 		uinfo->value.enumerated.items = 5;
 		if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
 			uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
@@ -1156,8 +1175,8 @@
 {
 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
 	static const char * const aureon_texts[] = {
-		"CD",		//RXP0
-		"Optical"	//RXP1
+		"CD",		/* RXP0 */
+		"Optical"	/* RXP1 */
 	};
 	static const char * const prodigy_texts[] = {
 		"CD",
@@ -1180,10 +1199,10 @@
 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
 	struct aureon_spec *spec = ice->spec;
 
-	//snd_ice1712_save_gpio_status(ice);
-	//val = aureon_cs8415_get(ice, CS8415_CTRL2);
+	/* snd_ice1712_save_gpio_status(ice); */
+	/* val = aureon_cs8415_get(ice, CS8415_CTRL2); */
 	ucontrol->value.enumerated.item[0] = spec->cs8415_mux;
-	//snd_ice1712_restore_gpio_status(ice);
+	/* snd_ice1712_restore_gpio_status(ice); */
 	return 0;
 }
 
@@ -1206,7 +1225,7 @@
 	return change;
 }
 
-static int aureon_cs8415_rate_info (struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
+static int aureon_cs8415_rate_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
 {
 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
 	uinfo->count = 1;
@@ -1215,7 +1234,7 @@
 	return 0;
 }
 
-static int aureon_cs8415_rate_get (struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+static int aureon_cs8415_rate_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 {
 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
 	unsigned char ratio;
@@ -1229,7 +1248,7 @@
  */
 #define aureon_cs8415_mute_info		snd_ctl_boolean_mono_info
 
-static int aureon_cs8415_mute_get (struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+static int aureon_cs8415_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 {
 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
 	snd_ice1712_save_gpio_status(ice);
@@ -1238,7 +1257,7 @@
 	return 0;
 }
 
-static int aureon_cs8415_mute_put (struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+static int aureon_cs8415_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 {
 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
 	unsigned char oval, nval;
@@ -1249,7 +1268,8 @@
 		nval = oval & ~0x20;
 	else
 		nval = oval | 0x20;
-	if ((change = (oval != nval)))
+	change = (oval != nval);
+	if (change)
 		aureon_cs8415_put(ice, CS8415_CTRL1, nval);
 	snd_ice1712_restore_gpio_status(ice);
 	return change;
@@ -1258,15 +1278,17 @@
 /*
  * CS8415A Q-Sub info
  */
-static int aureon_cs8415_qsub_info (struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) {
+static int aureon_cs8415_qsub_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
+{
 	uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
 	uinfo->count = 10;
 	return 0;
 }
 
-static int aureon_cs8415_qsub_get (struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) {
+static int aureon_cs8415_qsub_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+{
 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
-	
+
 	snd_ice1712_save_gpio_status(ice);
 	aureon_cs8415_read(ice, CS8415_QSUB, ucontrol->value.bytes.data, 10);
 	snd_ice1712_restore_gpio_status(ice);
@@ -1274,18 +1296,21 @@
 	return 0;
 }
 
-static int aureon_cs8415_spdif_info (struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) {
+static int aureon_cs8415_spdif_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
+{
 	uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
 	uinfo->count = 1;
 	return 0;
 }
 
-static int aureon_cs8415_mask_get (struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) {
+static int aureon_cs8415_mask_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+{
 	memset(ucontrol->value.iec958.status, 0xFF, 24);
 	return 0;
 }
 
-static int aureon_cs8415_spdif_get (struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) {
+static int aureon_cs8415_spdif_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+{
 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
 
 	snd_ice1712_save_gpio_status(ice);
@@ -1311,9 +1336,9 @@
 	else
 		if (ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71LT &&
 		    ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71XT)
-			tmp &= ~ AUREON_HP_SEL;
+			tmp &= ~AUREON_HP_SEL;
 		else
-			tmp &= ~ PRODIGY_HP_SEL;
+			tmp &= ~PRODIGY_HP_SEL;
 	if (tmp != tmp2) {
 		snd_ice1712_gpio_write(ice, tmp);
 		return 1;
@@ -1325,7 +1350,7 @@
 {
 	unsigned int tmp = snd_ice1712_gpio_read(ice);
 
-	return ( tmp & AUREON_HP_SEL )!= 0;
+	return (tmp & AUREON_HP_SEL) != 0;
 }
 
 #define aureon_hpamp_info	snd_ctl_boolean_mono_info
@@ -1343,7 +1368,7 @@
 {
 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
 
-	return aureon_set_headphone_amp(ice,ucontrol->value.integer.value[0]);
+	return aureon_set_headphone_amp(ice, ucontrol->value.integer.value[0]);
 }
 
 /*
@@ -1390,7 +1415,7 @@
 		uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
 	strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
 
-        return 0;
+	return 0;
 }
 
 static int aureon_oversampling_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
@@ -1434,7 +1459,7 @@
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
-			   SNDRV_CTL_ELEM_ACCESS_TLV_READ),
+				SNDRV_CTL_ELEM_ACCESS_TLV_READ),
 		.name = "Master Playback Volume",
 		.info = wm_master_vol_info,
 		.get = wm_master_vol_get,
@@ -1452,7 +1477,7 @@
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
-			   SNDRV_CTL_ELEM_ACCESS_TLV_READ),
+				SNDRV_CTL_ELEM_ACCESS_TLV_READ),
 		.name = "Front Playback Volume",
 		.info = wm_vol_info,
 		.get = wm_vol_get,
@@ -1471,7 +1496,7 @@
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
-			   SNDRV_CTL_ELEM_ACCESS_TLV_READ),
+				SNDRV_CTL_ELEM_ACCESS_TLV_READ),
 		.name = "Rear Playback Volume",
 		.info = wm_vol_info,
 		.get = wm_vol_get,
@@ -1490,7 +1515,7 @@
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
-			   SNDRV_CTL_ELEM_ACCESS_TLV_READ),
+				SNDRV_CTL_ELEM_ACCESS_TLV_READ),
 		.name = "Center Playback Volume",
 		.info = wm_vol_info,
 		.get = wm_vol_get,
@@ -1509,7 +1534,7 @@
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
-			   SNDRV_CTL_ELEM_ACCESS_TLV_READ),
+				SNDRV_CTL_ELEM_ACCESS_TLV_READ),
 		.name = "LFE Playback Volume",
 		.info = wm_vol_info,
 		.get = wm_vol_get,
@@ -1528,7 +1553,7 @@
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
-			   SNDRV_CTL_ELEM_ACCESS_TLV_READ),
+				SNDRV_CTL_ELEM_ACCESS_TLV_READ),
 		.name = "Side Playback Volume",
 		.info = wm_vol_info,
 		.get = wm_vol_get,
@@ -1539,23 +1564,23 @@
 };
 
 static struct snd_kcontrol_new wm_controls[] __devinitdata = {
- 	{
- 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.name = "PCM Playback Switch",
 		.info = wm_pcm_mute_info,
 		.get = wm_pcm_mute_get,
 		.put = wm_pcm_mute_put
- 	},
- 	{
- 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	},
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
-			   SNDRV_CTL_ELEM_ACCESS_TLV_READ),
+				SNDRV_CTL_ELEM_ACCESS_TLV_READ),
 		.name = "PCM Playback Volume",
 		.info = wm_pcm_vol_info,
 		.get = wm_pcm_vol_get,
 		.put = wm_pcm_vol_put,
 		.tlv = { .p = db_scale_wm_pcm }
- 	},
+	},
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.name = "Capture Switch",
@@ -1566,7 +1591,7 @@
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
-			   SNDRV_CTL_ELEM_ACCESS_TLV_READ),
+				SNDRV_CTL_ELEM_ACCESS_TLV_READ),
 		.name = "Capture Volume",
 		.info = wm_adc_vol_info,
 		.get = wm_adc_vol_get,
@@ -1605,232 +1630,232 @@
 };
 
 static struct snd_kcontrol_new ac97_controls[] __devinitdata = {
- 	{
- 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.name = "AC97 Playback Switch",
 		.info = aureon_ac97_mmute_info,
 		.get = aureon_ac97_mmute_get,
 		.put = aureon_ac97_mmute_put,
 		.private_value = AC97_MASTER
- 	},
- 	{
- 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	},
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
-			   SNDRV_CTL_ELEM_ACCESS_TLV_READ),
- 		.name = "AC97 Playback Volume",
- 		.info = aureon_ac97_vol_info,
- 		.get = aureon_ac97_vol_get,
- 		.put = aureon_ac97_vol_put,
- 		.private_value = AC97_MASTER|AUREON_AC97_STEREO,
+				SNDRV_CTL_ELEM_ACCESS_TLV_READ),
+		.name = "AC97 Playback Volume",
+		.info = aureon_ac97_vol_info,
+		.get = aureon_ac97_vol_get,
+		.put = aureon_ac97_vol_put,
+		.private_value = AC97_MASTER|AUREON_AC97_STEREO,
 		.tlv = { .p = db_scale_ac97_master }
- 	},
- 	{
- 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- 		.name = "CD Playback Switch",
- 		.info = aureon_ac97_mute_info,
- 		.get = aureon_ac97_mute_get,
- 		.put = aureon_ac97_mute_put,
- 		.private_value = AC97_CD
- 	},
- 	{
- 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	},
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "CD Playback Switch",
+		.info = aureon_ac97_mute_info,
+		.get = aureon_ac97_mute_get,
+		.put = aureon_ac97_mute_put,
+		.private_value = AC97_CD
+	},
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
-			   SNDRV_CTL_ELEM_ACCESS_TLV_READ),
- 		.name = "CD Playback Volume",
- 		.info = aureon_ac97_vol_info,
- 		.get = aureon_ac97_vol_get,
- 		.put = aureon_ac97_vol_put,
- 		.private_value = AC97_CD|AUREON_AC97_STEREO,
+				SNDRV_CTL_ELEM_ACCESS_TLV_READ),
+		.name = "CD Playback Volume",
+		.info = aureon_ac97_vol_info,
+		.get = aureon_ac97_vol_get,
+		.put = aureon_ac97_vol_put,
+		.private_value = AC97_CD|AUREON_AC97_STEREO,
 		.tlv = { .p = db_scale_ac97_gain }
- 	},
- 	{
- 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- 		.name = "Aux Playback Switch",
- 		.info = aureon_ac97_mute_info,
- 		.get = aureon_ac97_mute_get,
- 		.put = aureon_ac97_mute_put,
- 		.private_value = AC97_AUX,
- 	},
- 	{
- 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	},
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Aux Playback Switch",
+		.info = aureon_ac97_mute_info,
+		.get = aureon_ac97_mute_get,
+		.put = aureon_ac97_mute_put,
+		.private_value = AC97_AUX,
+	},
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
-			   SNDRV_CTL_ELEM_ACCESS_TLV_READ),
- 		.name = "Aux Playback Volume",
- 		.info = aureon_ac97_vol_info,
- 		.get = aureon_ac97_vol_get,
- 		.put = aureon_ac97_vol_put,
- 		.private_value = AC97_AUX|AUREON_AC97_STEREO,
+				SNDRV_CTL_ELEM_ACCESS_TLV_READ),
+		.name = "Aux Playback Volume",
+		.info = aureon_ac97_vol_info,
+		.get = aureon_ac97_vol_get,
+		.put = aureon_ac97_vol_put,
+		.private_value = AC97_AUX|AUREON_AC97_STEREO,
 		.tlv = { .p = db_scale_ac97_gain }
- 	},
- 	{
- 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- 		.name = "Line Playback Switch",
- 		.info = aureon_ac97_mute_info,
- 		.get = aureon_ac97_mute_get,
- 		.put = aureon_ac97_mute_put,
- 		.private_value = AC97_LINE
- 	},
- 	{
- 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	},
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Line Playback Switch",
+		.info = aureon_ac97_mute_info,
+		.get = aureon_ac97_mute_get,
+		.put = aureon_ac97_mute_put,
+		.private_value = AC97_LINE
+	},
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
-			   SNDRV_CTL_ELEM_ACCESS_TLV_READ),
- 		.name = "Line Playback Volume",
- 		.info = aureon_ac97_vol_info,
- 		.get = aureon_ac97_vol_get,
- 		.put = aureon_ac97_vol_put,
- 		.private_value = AC97_LINE|AUREON_AC97_STEREO,
+				SNDRV_CTL_ELEM_ACCESS_TLV_READ),
+		.name = "Line Playback Volume",
+		.info = aureon_ac97_vol_info,
+		.get = aureon_ac97_vol_get,
+		.put = aureon_ac97_vol_put,
+		.private_value = AC97_LINE|AUREON_AC97_STEREO,
 		.tlv = { .p = db_scale_ac97_gain }
- 	},
- 	{
- 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- 		.name = "Mic Playback Switch",
- 		.info = aureon_ac97_mute_info,
- 		.get = aureon_ac97_mute_get,
- 		.put = aureon_ac97_mute_put,
- 		.private_value = AC97_MIC
- 	},
- 	{
- 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	},
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Mic Playback Switch",
+		.info = aureon_ac97_mute_info,
+		.get = aureon_ac97_mute_get,
+		.put = aureon_ac97_mute_put,
+		.private_value = AC97_MIC
+	},
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
-			   SNDRV_CTL_ELEM_ACCESS_TLV_READ),
- 		.name = "Mic Playback Volume",
- 		.info = aureon_ac97_vol_info,
- 		.get = aureon_ac97_vol_get,
- 		.put = aureon_ac97_vol_put,
- 		.private_value = AC97_MIC,
+				SNDRV_CTL_ELEM_ACCESS_TLV_READ),
+		.name = "Mic Playback Volume",
+		.info = aureon_ac97_vol_info,
+		.get = aureon_ac97_vol_get,
+		.put = aureon_ac97_vol_put,
+		.private_value = AC97_MIC,
 		.tlv = { .p = db_scale_ac97_gain }
- 	},
- 	{
- 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- 		.name = "Mic Boost (+20dB)",
- 		.info = aureon_ac97_micboost_info,
- 		.get = aureon_ac97_micboost_get,
- 		.put = aureon_ac97_micboost_put
- 	}
+	},
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Mic Boost (+20dB)",
+		.info = aureon_ac97_micboost_info,
+		.get = aureon_ac97_micboost_get,
+		.put = aureon_ac97_micboost_put
+	}
 };
 
 static struct snd_kcontrol_new universe_ac97_controls[] __devinitdata = {
- 	{
- 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.name = "AC97 Playback Switch",
 		.info = aureon_ac97_mmute_info,
 		.get = aureon_ac97_mmute_get,
 		.put = aureon_ac97_mmute_put,
 		.private_value = AC97_MASTER
- 	},
- 	{
- 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	},
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
-			   SNDRV_CTL_ELEM_ACCESS_TLV_READ),
- 		.name = "AC97 Playback Volume",
- 		.info = aureon_ac97_vol_info,
- 		.get = aureon_ac97_vol_get,
- 		.put = aureon_ac97_vol_put,
- 		.private_value = AC97_MASTER|AUREON_AC97_STEREO,
+				SNDRV_CTL_ELEM_ACCESS_TLV_READ),
+		.name = "AC97 Playback Volume",
+		.info = aureon_ac97_vol_info,
+		.get = aureon_ac97_vol_get,
+		.put = aureon_ac97_vol_put,
+		.private_value = AC97_MASTER|AUREON_AC97_STEREO,
 		.tlv = { .p = db_scale_ac97_master }
- 	},
- 	{
- 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- 		.name = "CD Playback Switch",
- 		.info = aureon_ac97_mute_info,
- 		.get = aureon_ac97_mute_get,
- 		.put = aureon_ac97_mute_put,
- 		.private_value = AC97_AUX
- 	},
- 	{
- 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	},
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "CD Playback Switch",
+		.info = aureon_ac97_mute_info,
+		.get = aureon_ac97_mute_get,
+		.put = aureon_ac97_mute_put,
+		.private_value = AC97_AUX
+	},
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
-			   SNDRV_CTL_ELEM_ACCESS_TLV_READ),
- 		.name = "CD Playback Volume",
- 		.info = aureon_ac97_vol_info,
- 		.get = aureon_ac97_vol_get,
- 		.put = aureon_ac97_vol_put,
- 		.private_value = AC97_AUX|AUREON_AC97_STEREO,
+				SNDRV_CTL_ELEM_ACCESS_TLV_READ),
+		.name = "CD Playback Volume",
+		.info = aureon_ac97_vol_info,
+		.get = aureon_ac97_vol_get,
+		.put = aureon_ac97_vol_put,
+		.private_value = AC97_AUX|AUREON_AC97_STEREO,
 		.tlv = { .p = db_scale_ac97_gain }
- 	},
- 	{
- 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- 		.name = "Phono Playback Switch",
- 		.info = aureon_ac97_mute_info,
- 		.get = aureon_ac97_mute_get,
- 		.put = aureon_ac97_mute_put,
- 		.private_value = AC97_CD
- 	},
- 	{
- 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	},
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Phono Playback Switch",
+		.info = aureon_ac97_mute_info,
+		.get = aureon_ac97_mute_get,
+		.put = aureon_ac97_mute_put,
+		.private_value = AC97_CD
+	},
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
-			   SNDRV_CTL_ELEM_ACCESS_TLV_READ),
- 		.name = "Phono Playback Volume",
- 		.info = aureon_ac97_vol_info,
- 		.get = aureon_ac97_vol_get,
- 		.put = aureon_ac97_vol_put,
- 		.private_value = AC97_CD|AUREON_AC97_STEREO,
+				SNDRV_CTL_ELEM_ACCESS_TLV_READ),
+		.name = "Phono Playback Volume",
+		.info = aureon_ac97_vol_info,
+		.get = aureon_ac97_vol_get,
+		.put = aureon_ac97_vol_put,
+		.private_value = AC97_CD|AUREON_AC97_STEREO,
 		.tlv = { .p = db_scale_ac97_gain }
- 	},
- 	{
- 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- 		.name = "Line Playback Switch",
- 		.info = aureon_ac97_mute_info,
- 		.get = aureon_ac97_mute_get,
- 		.put = aureon_ac97_mute_put,
- 		.private_value = AC97_LINE
- 	},
- 	{
- 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	},
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Line Playback Switch",
+		.info = aureon_ac97_mute_info,
+		.get = aureon_ac97_mute_get,
+		.put = aureon_ac97_mute_put,
+		.private_value = AC97_LINE
+	},
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
-			   SNDRV_CTL_ELEM_ACCESS_TLV_READ),
- 		.name = "Line Playback Volume",
- 		.info = aureon_ac97_vol_info,
- 		.get = aureon_ac97_vol_get,
- 		.put = aureon_ac97_vol_put,
- 		.private_value = AC97_LINE|AUREON_AC97_STEREO,
+				SNDRV_CTL_ELEM_ACCESS_TLV_READ),
+		.name = "Line Playback Volume",
+		.info = aureon_ac97_vol_info,
+		.get = aureon_ac97_vol_get,
+		.put = aureon_ac97_vol_put,
+		.private_value = AC97_LINE|AUREON_AC97_STEREO,
 		.tlv = { .p = db_scale_ac97_gain }
- 	},
- 	{
- 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- 		.name = "Mic Playback Switch",
- 		.info = aureon_ac97_mute_info,
- 		.get = aureon_ac97_mute_get,
- 		.put = aureon_ac97_mute_put,
- 		.private_value = AC97_MIC
- 	},
- 	{
- 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	},
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Mic Playback Switch",
+		.info = aureon_ac97_mute_info,
+		.get = aureon_ac97_mute_get,
+		.put = aureon_ac97_mute_put,
+		.private_value = AC97_MIC
+	},
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
-			   SNDRV_CTL_ELEM_ACCESS_TLV_READ),
- 		.name = "Mic Playback Volume",
- 		.info = aureon_ac97_vol_info,
- 		.get = aureon_ac97_vol_get,
- 		.put = aureon_ac97_vol_put,
- 		.private_value = AC97_MIC,
+				SNDRV_CTL_ELEM_ACCESS_TLV_READ),
+		.name = "Mic Playback Volume",
+		.info = aureon_ac97_vol_info,
+		.get = aureon_ac97_vol_get,
+		.put = aureon_ac97_vol_put,
+		.private_value = AC97_MIC,
 		.tlv = { .p = db_scale_ac97_gain }
- 	},
- 	{
- 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- 		.name = "Mic Boost (+20dB)",
- 		.info = aureon_ac97_micboost_info,
- 		.get = aureon_ac97_micboost_get,
- 		.put = aureon_ac97_micboost_put
- 	},
- 	{
- 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- 		.name = "Aux Playback Switch",
- 		.info = aureon_ac97_mute_info,
- 		.get = aureon_ac97_mute_get,
- 		.put = aureon_ac97_mute_put,
- 		.private_value = AC97_VIDEO,
- 	},
- 	{
- 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	},
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Mic Boost (+20dB)",
+		.info = aureon_ac97_micboost_info,
+		.get = aureon_ac97_micboost_get,
+		.put = aureon_ac97_micboost_put
+	},
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Aux Playback Switch",
+		.info = aureon_ac97_mute_info,
+		.get = aureon_ac97_mute_get,
+		.put = aureon_ac97_mute_put,
+		.private_value = AC97_VIDEO,
+	},
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
-			   SNDRV_CTL_ELEM_ACCESS_TLV_READ),
- 		.name = "Aux Playback Volume",
- 		.info = aureon_ac97_vol_info,
- 		.get = aureon_ac97_vol_get,
- 		.put = aureon_ac97_vol_put,
- 		.private_value = AC97_VIDEO|AUREON_AC97_STEREO,
+				SNDRV_CTL_ELEM_ACCESS_TLV_READ),
+		.name = "Aux Playback Volume",
+		.info = aureon_ac97_vol_info,
+		.get = aureon_ac97_vol_get,
+		.put = aureon_ac97_vol_put,
+		.private_value = AC97_VIDEO|AUREON_AC97_STEREO,
 		.tlv = { .p = db_scale_ac97_gain }
- 	},
+	},
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.name = "Aux Source",
@@ -1844,43 +1869,43 @@
 static struct snd_kcontrol_new cs8415_controls[] __devinitdata = {
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-		.name = SNDRV_CTL_NAME_IEC958("",CAPTURE,SWITCH),
+		.name = SNDRV_CTL_NAME_IEC958("", CAPTURE, SWITCH),
 		.info = aureon_cs8415_mute_info,
 		.get = aureon_cs8415_mute_get,
 		.put = aureon_cs8415_mute_put
 	},
- 	{
- 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-		.name = SNDRV_CTL_NAME_IEC958("",CAPTURE,NONE) "Source",
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = SNDRV_CTL_NAME_IEC958("", CAPTURE, NONE) "Source",
 		.info = aureon_cs8415_mux_info,
 		.get = aureon_cs8415_mux_get,
 		.put = aureon_cs8415_mux_put,
 	},
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_PCM,
-		.name = SNDRV_CTL_NAME_IEC958("Q-subcode ",CAPTURE,DEFAULT),
+		.name = SNDRV_CTL_NAME_IEC958("Q-subcode ", CAPTURE, DEFAULT),
 		.access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
 		.info = aureon_cs8415_qsub_info,
 		.get = aureon_cs8415_qsub_get,
 	},
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_PCM,
-		.name = SNDRV_CTL_NAME_IEC958("",CAPTURE,MASK),
+		.name = SNDRV_CTL_NAME_IEC958("", CAPTURE, MASK),
 		.access = SNDRV_CTL_ELEM_ACCESS_READ,
 		.info = aureon_cs8415_spdif_info,
 		.get = aureon_cs8415_mask_get
 	},
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_PCM,
-		.name = SNDRV_CTL_NAME_IEC958("",CAPTURE,DEFAULT),
+		.name = SNDRV_CTL_NAME_IEC958("", CAPTURE, DEFAULT),
 		.access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
 		.info = aureon_cs8415_spdif_info,
 		.get = aureon_cs8415_spdif_get
 	},
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_PCM,
-		.name = SNDRV_CTL_NAME_IEC958("",CAPTURE,NONE) "Rate",
-		.access =SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
+		.name = SNDRV_CTL_NAME_IEC958("", CAPTURE, NONE) "Rate",
+		.access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
 		.info = aureon_cs8415_rate_info,
 		.get = aureon_cs8415_rate_get
 	}
@@ -1905,15 +1930,14 @@
 		if (err < 0)
 			return err;
 	}
-	
+
 	if (ice->eeprom.subvendor == VT1724_SUBDEVICE_AUREON71_UNIVERSE) {
 		for (i = 0; i < ARRAY_SIZE(universe_ac97_controls); i++) {
 			err = snd_ctl_add(ice->card, snd_ctl_new1(&universe_ac97_controls[i], ice));
 			if (err < 0)
 				return err;
 		}
-	}
-	else if (ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71LT &&
+	} else if (ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71LT &&
 		 ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71XT) {
 		for (i = 0; i < ARRAY_SIZE(ac97_controls); i++) {
 			err = snd_ctl_add(ice->card, snd_ctl_new1(&ac97_controls[i], ice));
@@ -1932,7 +1956,7 @@
 		else if ((id & 0x0F) != 0x01)
 			snd_printk(KERN_INFO "Detected unsupported CS8415 rev. (%c)\n", (char)((id & 0x0F) + 'A' - 1));
 		else {
-			for (i = 0; i< ARRAY_SIZE(cs8415_controls); i++) {
+			for (i = 0; i < ARRAY_SIZE(cs8415_controls); i++) {
 				struct snd_kcontrol *kctl;
 				err = snd_ctl_add(ice->card, (kctl = snd_ctl_new1(&cs8415_controls[i], ice)));
 				if (err < 0)
@@ -1943,7 +1967,7 @@
 		}
 		snd_ice1712_restore_gpio_status(ice);
 	}
-	
+
 	return 0;
 }
 
@@ -2059,11 +2083,12 @@
 
 	/* to remeber the register values of CS8415 */
 	ice->akm = kzalloc(sizeof(struct snd_akm4xxx), GFP_KERNEL);
-	if (! ice->akm)
+	if (!ice->akm)
 		return -ENOMEM;
 	ice->akm_codecs = 1;
-	
-	if ((err = aureon_ac97_init(ice)) != 0)
+
+	err = aureon_ac97_init(ice);
+	if (err != 0)
 		return err;
 
 	snd_ice1712_gpio_set_dir(ice, 0x5fffff); /* fix this for the time being */
@@ -2086,7 +2111,7 @@
 	/* initialize WM8770 codec */
 	if (ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71 ||
 		ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71LT ||
-	        ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71XT)
+		ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71XT)
 		p = wm_inits_prodigy;
 	else
 		p = wm_inits_aureon;
@@ -2105,10 +2130,10 @@
 
 	snd_ice1712_restore_gpio_status(ice);
 
-        /* initialize PCA9554 pin directions & set default input*/
+	/* initialize PCA9554 pin directions & set default input */
 	aureon_pca9554_write(ice, PCA9554_DIR, 0x00);
 	aureon_pca9554_write(ice, PCA9554_OUT, 0x00);   /* internal AUX */
-	
+
 	spec->master[0] = WM_VOL_MUTE;
 	spec->master[1] = WM_VOL_MUTE;
 	for (i = 0; i < ice->num_total_dacs; i++) {
@@ -2158,6 +2183,24 @@
 };
 #define prodigy71_eeprom aureon71_eeprom
 
+static unsigned char aureon71_universe_eeprom[] __devinitdata = {
+	[ICE_EEP2_SYSCONF]     = 0x2b,	/* clock 512, mpu401, spdif-in/ADC,
+					 * 4DACs
+					 */
+	[ICE_EEP2_ACLINK]      = 0x80,	/* I2S */
+	[ICE_EEP2_I2S]         = 0xfc,	/* vol, 96k, 24bit, 192k */
+	[ICE_EEP2_SPDIF]       = 0xc3,	/* out-en, out-int, spdif-in */
+	[ICE_EEP2_GPIO_DIR]    = 0xff,
+	[ICE_EEP2_GPIO_DIR1]   = 0xff,
+	[ICE_EEP2_GPIO_DIR2]   = 0x5f,
+	[ICE_EEP2_GPIO_MASK]   = 0x00,
+	[ICE_EEP2_GPIO_MASK1]  = 0x00,
+	[ICE_EEP2_GPIO_MASK2]  = 0x00,
+	[ICE_EEP2_GPIO_STATE]  = 0x00,
+	[ICE_EEP2_GPIO_STATE1] = 0x00,
+	[ICE_EEP2_GPIO_STATE2] = 0x00,
+};
+
 static unsigned char prodigy71lt_eeprom[] __devinitdata = {
 	[ICE_EEP2_SYSCONF]     = 0x4b,	/* clock 384, spdif-in/ADC, 4DACs */
 	[ICE_EEP2_ACLINK]      = 0x80,	/* I2S */
@@ -2197,14 +2240,14 @@
 		.eeprom_data = aureon71_eeprom,
 		.driver = "Aureon71",
 	},
- 	{
- 		.subvendor = VT1724_SUBDEVICE_AUREON71_UNIVERSE,
- 		.name = "Terratec Aureon 7.1-Universe",
+	{
+		.subvendor = VT1724_SUBDEVICE_AUREON71_UNIVERSE,
+		.name = "Terratec Aureon 7.1-Universe",
 		.model = "universe",
- 		.chip_init = aureon_init,
- 		.build_controls = aureon_add_controls,
- 		.eeprom_size = sizeof(aureon71_eeprom),
- 		.eeprom_data = aureon71_eeprom,
+		.chip_init = aureon_init,
+		.build_controls = aureon_add_controls,
+		.eeprom_size = sizeof(aureon71_universe_eeprom),
+		.eeprom_data = aureon71_universe_eeprom,
 		.driver = "Aureon71Univ", /* keep in 15 letters */
 	},
 	{
diff --git a/sound/pci/ice1712/delta.c b/sound/pci/ice1712/delta.c
index 0ed96c1..d216362 100644
--- a/sound/pci/ice1712/delta.c
+++ b/sound/pci/ice1712/delta.c
@@ -400,7 +400,7 @@
 static int snd_ice1712_delta1010lt_wordclock_status_get(struct snd_kcontrol *kcontrol,
 			 struct snd_ctl_elem_value *ucontrol)
 {
-	char reg = 0x10; // cs8427 receiver error register
+	char reg = 0x10; /* CS8427 receiver error register */
 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
 
 	if (snd_i2c_sendbytes(ice->cs8427, &reg, 1) != 1)
diff --git a/sound/pci/ice1712/delta.h b/sound/pci/ice1712/delta.h
index ea7116c..f7f14df 100644
--- a/sound/pci/ice1712/delta.h
+++ b/sound/pci/ice1712/delta.h
@@ -31,6 +31,7 @@
 		"{MidiMan M Audio,Delta DiO 2496},"\
 		"{MidiMan M Audio,Delta 66},"\
 		"{MidiMan M Audio,Delta 44},"\
+		"{MidiMan M Audio,Delta 410},"\
 		"{MidiMan M Audio,Audiophile 24/96},"\
 		"{Digigram,VX442},"\
 		"{Lionstracs,Mediastation},"
diff --git a/sound/pci/ice1712/ews.c b/sound/pci/ice1712/ews.c
index 013fc4f..6fe35b8 100644
--- a/sound/pci/ice1712/ews.c
+++ b/sound/pci/ice1712/ews.c
@@ -149,7 +149,8 @@
 	struct ews_spec *spec = ice->spec;
 	unsigned char data, ndata;
 
-	snd_assert(chip_mask >= 0 && chip_mask <= 0x0f, return -EINVAL);
+	if (snd_BUG_ON(chip_mask < 0 || chip_mask > 0x0f))
+		return -EINVAL;
 	snd_i2c_lock(ice->i2c);
 	if (snd_i2c_readbytes(spec->i2cdevs[EWS_I2C_PCF2], &data, 1) != 1)
 		goto __error;
@@ -685,7 +686,8 @@
 	int channel = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
 	unsigned char data;
 
-	snd_assert(channel >= 0 && channel <= 7, return 0);
+	if (snd_BUG_ON(channel < 0 || channel > 7))
+		return 0;
 	snd_i2c_lock(ice->i2c);
 	if (snd_i2c_readbytes(spec->i2cdevs[EWS_I2C_PCF1], &data, 1) != 1) {
 		snd_i2c_unlock(ice->i2c);
@@ -705,7 +707,8 @@
 	int channel = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
 	unsigned char data, ndata;
 
-	snd_assert(channel >= 0 && channel <= 7, return 0);
+	if (snd_BUG_ON(channel < 0 || channel > 7))
+		return 0;
 	snd_i2c_lock(ice->i2c);
 	if (snd_i2c_readbytes(spec->i2cdevs[EWS_I2C_PCF1], &data, 1) != 1) {
 		snd_i2c_unlock(ice->i2c);
diff --git a/sound/pci/ice1712/ice1712.c b/sound/pci/ice1712/ice1712.c
index 29d449d..5b44238 100644
--- a/sound/pci/ice1712/ice1712.c
+++ b/sound/pci/ice1712/ice1712.c
@@ -17,7 +17,7 @@
  *   along with this program; if not, write to the Free Software
  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  *
- */      
+ */
 
 /*
   NOTES:
@@ -35,7 +35,7 @@
  *
  *  2002.11.26	James Stafford <jstafford@ampltd.com>
  *	Added support for VT1724 (Envy24HT)
- *	I have left out support for 176.4 and 192 KHz for the moment. 
+ *	I have left out support for 176.4 and 192 KHz for the moment.
  *  I also haven't done anything with the internal S/PDIF transmitter or the MPU-401
  *
  *  2003.02.20  Taksahi Iwai <tiwai@suse.de>
@@ -47,7 +47,7 @@
  */
 
 
-#include <asm/io.h>
+#include <linux/io.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
 #include <linux/init.h>
@@ -123,7 +123,7 @@
 /*
  *  Basic I/O
  */
- 
+
 /* check whether the clock mode is spdif-in */
 static inline int is_spdif_master(struct snd_ice1712 *ice)
 {
@@ -135,13 +135,13 @@
 	return is_spdif_master(ice) || PRO_RATE_LOCKED;
 }
 
-static inline void snd_ice1712_ds_write(struct snd_ice1712 * ice, u8 channel, u8 addr, u32 data)
+static inline void snd_ice1712_ds_write(struct snd_ice1712 *ice, u8 channel, u8 addr, u32 data)
 {
 	outb((channel << 4) | addr, ICEDS(ice, INDEX));
 	outl(data, ICEDS(ice, DATA));
 }
 
-static inline u32 snd_ice1712_ds_read(struct snd_ice1712 * ice, u8 channel, u8 addr)
+static inline u32 snd_ice1712_ds_read(struct snd_ice1712 *ice, u8 channel, u8 addr)
 {
 	outb((channel << 4) | addr, ICEDS(ice, INDEX));
 	return inl(ICEDS(ice, DATA));
@@ -260,7 +260,7 @@
 static int snd_ice1712_digmix_route_ac97_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 {
 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
-	
+
 	ucontrol->value.integer.value[0] = inb(ICEMT(ice, MONITOR_ROUTECTRL)) & ICE1712_ROUTE_AC97 ? 1 : 0;
 	return 0;
 }
@@ -269,11 +269,12 @@
 {
 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
 	unsigned char val, nval;
-	
+
 	spin_lock_irq(&ice->reg_lock);
 	val = inb(ICEMT(ice, MONITOR_ROUTECTRL));
 	nval = val & ~ICE1712_ROUTE_AC97;
-	if (ucontrol->value.integer.value[0]) nval |= ICE1712_ROUTE_AC97;
+	if (ucontrol->value.integer.value[0])
+		nval |= ICE1712_ROUTE_AC97;
 	outb(nval, ICEMT(ice, MONITOR_ROUTECTRL));
 	spin_unlock_irq(&ice->reg_lock);
 	return val != nval;
@@ -329,7 +330,7 @@
 	unsigned char reg[2] = { 0x80 | 4, 0 };   /* CS8427 auto increment | register number 4 + data */
 	unsigned char val, nval;
 	int res = 0;
-	
+
 	snd_i2c_lock(ice->i2c);
 	if (snd_i2c_sendbytes(ice->cs8427, reg, 1) != 1) {
 		snd_i2c_unlock(ice->i2c);
@@ -381,9 +382,9 @@
 {
 	int err;
 
-	if ((err = snd_cs8427_create(ice->i2c, addr,
-				     (ice->cs8427_timeout * HZ) / 1000,
-				     &ice->cs8427)) < 0) {
+	err = snd_cs8427_create(ice->i2c, addr,
+		(ice->cs8427_timeout * HZ) / 1000, &ice->cs8427);
+	if (err < 0) {
 		snd_printk(KERN_ERR "CS8427 initialization failed\n");
 		return err;
 	}
@@ -395,9 +396,9 @@
 
 static void snd_ice1712_set_input_clock_source(struct snd_ice1712 *ice, int spdif_is_master)
 {
-        /* change CS8427 clock source too */
-        if (ice->cs8427)
-                snd_ice1712_cs8427_set_input_clock(ice, spdif_is_master);
+	/* change CS8427 clock source too */
+	if (ice->cs8427)
+		snd_ice1712_cs8427_set_input_clock(ice, spdif_is_master);
 	/* notify ak4524 chip as well */
 	if (spdif_is_master) {
 		unsigned int i;
@@ -457,11 +458,12 @@
 			u16 pbkstatus;
 			struct snd_pcm_substream *substream;
 			pbkstatus = inw(ICEDS(ice, INTSTAT));
-			//printk("pbkstatus = 0x%x\n", pbkstatus);
+			/* printk("pbkstatus = 0x%x\n", pbkstatus); */
 			for (idx = 0; idx < 6; idx++) {
 				if ((pbkstatus & (3 << (idx * 2))) == 0)
 					continue;
-				if ((substream = ice->playback_con_substream_ds[idx]) != NULL)
+				substream = ice->playback_con_substream_ds[idx];
+				if (substream != NULL)
 					snd_pcm_period_elapsed(substream);
 				outw(3 << (idx * 2), ICEDS(ice, INTSTAT));
 			}
@@ -507,7 +509,7 @@
 	struct snd_ice1712 *ice = snd_pcm_substream_chip(substream);
 	int result = 0;
 	u32 tmp;
-	
+
 	spin_lock(&ice->reg_lock);
 	tmp = snd_ice1712_read(ice, ICE1712_IREG_PBK_CTRL);
 	if (cmd == SNDRV_PCM_TRIGGER_START) {
@@ -532,7 +534,7 @@
 	struct snd_ice1712 *ice = snd_pcm_substream_chip(substream);
 	int result = 0;
 	u32 tmp;
-	
+
 	spin_lock(&ice->reg_lock);
 	tmp = snd_ice1712_ds_read(ice, substream->number * 2, ICE1712_DSC_CONTROL);
 	if (cmd == SNDRV_PCM_TRIGGER_START) {
@@ -557,7 +559,7 @@
 	struct snd_ice1712 *ice = snd_pcm_substream_chip(substream);
 	int result = 0;
 	u8 tmp;
-	
+
 	spin_lock(&ice->reg_lock);
 	tmp = snd_ice1712_read(ice, ICE1712_IREG_CAP_CTRL);
 	if (cmd == SNDRV_PCM_TRIGGER_START) {
@@ -711,8 +713,7 @@
 	return bytes_to_frames(substream->runtime, ptr);
 }
 
-static const struct snd_pcm_hardware snd_ice1712_playback =
-{
+static const struct snd_pcm_hardware snd_ice1712_playback = {
 	.info =			(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
 				 SNDRV_PCM_INFO_BLOCK_TRANSFER |
 				 SNDRV_PCM_INFO_MMAP_VALID |
@@ -731,8 +732,7 @@
 	.fifo_size =		0,
 };
 
-static const struct snd_pcm_hardware snd_ice1712_playback_ds =
-{
+static const struct snd_pcm_hardware snd_ice1712_playback_ds = {
 	.info =			(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
 				 SNDRV_PCM_INFO_BLOCK_TRANSFER |
 				 SNDRV_PCM_INFO_MMAP_VALID |
@@ -751,8 +751,7 @@
 	.fifo_size =		0,
 };
 
-static const struct snd_pcm_hardware snd_ice1712_capture =
-{
+static const struct snd_pcm_hardware snd_ice1712_capture = {
 	.info =			(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
 				 SNDRV_PCM_INFO_BLOCK_TRANSFER |
 				 SNDRV_PCM_INFO_MMAP_VALID),
@@ -788,7 +787,7 @@
 
 	ice->playback_con_substream_ds[substream->number] = substream;
 	runtime->hw = snd_ice1712_playback_ds;
-	spin_lock_irq(&ice->reg_lock); 
+	spin_lock_irq(&ice->reg_lock);
 	tmp = inw(ICEDS(ice, INTMASK)) & ~(1 << (substream->number * 2));
 	outw(tmp, ICEDS(ice, INTMASK));
 	spin_unlock_irq(&ice->reg_lock);
@@ -821,7 +820,7 @@
 	struct snd_ice1712 *ice = snd_pcm_substream_chip(substream);
 	u32 tmp;
 
-	spin_lock_irq(&ice->reg_lock); 
+	spin_lock_irq(&ice->reg_lock);
 	tmp = inw(ICEDS(ice, INTMASK)) | (3 << (substream->number * 2));
 	outw(tmp, ICEDS(ice, INTMASK));
 	spin_unlock_irq(&ice->reg_lock);
@@ -870,7 +869,7 @@
 	.pointer =	snd_ice1712_capture_pointer,
 };
 
-static int __devinit snd_ice1712_pcm(struct snd_ice1712 * ice, int device, struct snd_pcm ** rpcm)
+static int __devinit snd_ice1712_pcm(struct snd_ice1712 *ice, int device, struct snd_pcm **rpcm)
 {
 	struct snd_pcm *pcm;
 	int err;
@@ -900,7 +899,7 @@
 	return 0;
 }
 
-static int __devinit snd_ice1712_pcm_ds(struct snd_ice1712 * ice, int device, struct snd_pcm ** rpcm)
+static int __devinit snd_ice1712_pcm_ds(struct snd_ice1712 *ice, int device, struct snd_pcm **rpcm)
 {
 	struct snd_pcm *pcm;
 	int err;
@@ -1029,14 +1028,14 @@
 	if (inb(ICEMT(ice, PLAYBACK_CONTROL)) & (ICE1712_CAPTURE_START_SHADOW|
 						 ICE1712_PLAYBACK_PAUSE|
 						 ICE1712_PLAYBACK_START)) {
-	      __out:
+__out:
 		spin_unlock_irqrestore(&ice->reg_lock, flags);
 		return;
 	}
 	if (!force && is_pro_rate_locked(ice))
 		goto __out;
 
-        old = inb(ICEMT(ice, RATE));
+	old = inb(ICEMT(ice, RATE));
 	if (!force && old == val)
 		goto __out;
 	outb(val, ICEMT(ice, RATE));
@@ -1123,8 +1122,7 @@
 	return bytes_to_frames(substream->runtime, ptr);
 }
 
-static const struct snd_pcm_hardware snd_ice1712_playback_pro =
-{
+static const struct snd_pcm_hardware snd_ice1712_playback_pro = {
 	.info =			(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
 				 SNDRV_PCM_INFO_BLOCK_TRANSFER |
 				 SNDRV_PCM_INFO_MMAP_VALID |
@@ -1143,8 +1141,7 @@
 	.fifo_size =		0,
 };
 
-static const struct snd_pcm_hardware snd_ice1712_capture_pro =
-{
+static const struct snd_pcm_hardware snd_ice1712_capture_pro = {
 	.info =			(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
 				 SNDRV_PCM_INFO_BLOCK_TRANSFER |
 				 SNDRV_PCM_INFO_MMAP_VALID |
@@ -1238,7 +1235,7 @@
 	.pointer =	snd_ice1712_capture_pro_pointer,
 };
 
-static int __devinit snd_ice1712_pcm_profi(struct snd_ice1712 * ice, int device, struct snd_pcm ** rpcm)
+static int __devinit snd_ice1712_pcm_profi(struct snd_ice1712 *ice, int device, struct snd_pcm **rpcm)
 {
 	struct snd_pcm *pcm;
 	int err;
@@ -1262,7 +1259,7 @@
 	ice->pcm_pro = pcm;
 	if (rpcm)
 		*rpcm = pcm;
-	
+
 	if (ice->cs8427) {
 		/* assign channels to iec958 */
 		err = snd_cs8427_iec958_build(ice->cs8427,
@@ -1272,7 +1269,8 @@
 			return err;
 	}
 
-	if ((err = snd_ice1712_build_pro_mixer(ice)) < 0)
+	err = snd_ice1712_build_pro_mixer(ice);
+	if (err < 0)
 		return err;
 	return 0;
 }
@@ -1299,7 +1297,7 @@
 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
 	int priv_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id) +
 		kcontrol->private_value;
-	
+
 	spin_lock_irq(&ice->reg_lock);
 	ucontrol->value.integer.value[0] =
 		!((ice->pro_volumes[priv_idx] >> 15) & 1);
@@ -1341,7 +1339,7 @@
 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
 	int priv_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id) +
 		kcontrol->private_value;
-	
+
 	spin_lock_irq(&ice->reg_lock);
 	ucontrol->value.integer.value[0] =
 		(ice->pro_volumes[priv_idx] >> 0) & 127;
@@ -1406,7 +1404,7 @@
 
 static struct snd_kcontrol_new snd_ice1712_multi_capture_spdif_switch __devinitdata = {
 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-	.name = SNDRV_CTL_NAME_IEC958("Multi ",CAPTURE,SWITCH),
+	.name = SNDRV_CTL_NAME_IEC958("Multi ", CAPTURE, SWITCH),
 	.info = snd_ice1712_pro_mixer_switch_info,
 	.get = snd_ice1712_pro_mixer_switch_get,
 	.put = snd_ice1712_pro_mixer_switch_put,
@@ -1428,7 +1426,7 @@
 
 static struct snd_kcontrol_new snd_ice1712_multi_capture_spdif_volume __devinitdata = {
 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-	.name = SNDRV_CTL_NAME_IEC958("Multi ",CAPTURE,VOLUME),
+	.name = SNDRV_CTL_NAME_IEC958("Multi ", CAPTURE, VOLUME),
 	.info = snd_ice1712_pro_mixer_volume_info,
 	.get = snd_ice1712_pro_mixer_volume_get,
 	.put = snd_ice1712_pro_mixer_volume_put,
@@ -1448,7 +1446,7 @@
 		if (err < 0)
 			return err;
 	}
-	
+
 	if (ice->num_total_adcs > 0) {
 		struct snd_kcontrol_new tmp = snd_ice1712_multi_capture_analog_switch;
 		tmp.count = ice->num_total_adcs;
@@ -1495,7 +1493,7 @@
 	ice->ac97 = NULL;
 }
 
-static int __devinit snd_ice1712_ac97_mixer(struct snd_ice1712 * ice)
+static int __devinit snd_ice1712_ac97_mixer(struct snd_ice1712 *ice)
 {
 	int err, bus_num = 0;
 	struct snd_ac97_template ac97;
@@ -1510,27 +1508,32 @@
 	};
 
 	if (ice_has_con_ac97(ice)) {
-		if ((err = snd_ac97_bus(ice->card, bus_num++, &con_ops, NULL, &pbus)) < 0)
+		err = snd_ac97_bus(ice->card, bus_num++, &con_ops, NULL, &pbus);
+		if (err < 0)
 			return err;
 		memset(&ac97, 0, sizeof(ac97));
 		ac97.private_data = ice;
 		ac97.private_free = snd_ice1712_mixer_free_ac97;
-		if ((err = snd_ac97_mixer(pbus, &ac97, &ice->ac97)) < 0)
+		err = snd_ac97_mixer(pbus, &ac97, &ice->ac97);
+		if (err < 0)
 			printk(KERN_WARNING "ice1712: cannot initialize ac97 for consumer, skipped\n");
 		else {
-			if ((err = snd_ctl_add(ice->card, snd_ctl_new1(&snd_ice1712_mixer_digmix_route_ac97, ice))) < 0)
+			err = snd_ctl_add(ice->card, snd_ctl_new1(&snd_ice1712_mixer_digmix_route_ac97, ice));
+			if (err < 0)
 				return err;
 			return 0;
 		}
 	}
 
-	if (! (ice->eeprom.data[ICE_EEP1_ACLINK] & ICE1712_CFG_PRO_I2S)) {
-		if ((err = snd_ac97_bus(ice->card, bus_num, &pro_ops, NULL, &pbus)) < 0)
+	if (!(ice->eeprom.data[ICE_EEP1_ACLINK] & ICE1712_CFG_PRO_I2S)) {
+		err = snd_ac97_bus(ice->card, bus_num, &pro_ops, NULL, &pbus);
+		if (err < 0)
 			return err;
 		memset(&ac97, 0, sizeof(ac97));
 		ac97.private_data = ice;
 		ac97.private_free = snd_ice1712_mixer_free_ac97;
-		if ((err = snd_ac97_mixer(pbus, &ac97, &ice->ac97)) < 0)
+		err = snd_ac97_mixer(pbus, &ac97, &ice->ac97);
+		if (err < 0)
 			printk(KERN_WARNING "ice1712: cannot initialize pro ac97, skipped\n");
 		else
 			return 0;
@@ -1549,7 +1552,7 @@
 	return (unsigned int)ice->eeprom.data[idx] | ((unsigned int)ice->eeprom.data[idx + 1] << 8);
 }
 
-static void snd_ice1712_proc_read(struct snd_info_entry *entry, 
+static void snd_ice1712_proc_read(struct snd_info_entry *entry,
 				  struct snd_info_buffer *buffer)
 {
 	struct snd_ice1712 *ice = entry->private_data;
@@ -1585,15 +1588,15 @@
 	snd_iprintf(buffer, "  SPDOUT           : 0x%04x\n", (unsigned)inw(ICEMT(ice, ROUTE_SPDOUT)));
 	snd_iprintf(buffer, "  RATE             : 0x%02x\n", (unsigned)inb(ICEMT(ice, RATE)));
 	snd_iprintf(buffer, "  GPIO_DATA        : 0x%02x\n", (unsigned)snd_ice1712_get_gpio_data(ice));
-        snd_iprintf(buffer, "  GPIO_WRITE_MASK  : 0x%02x\n", (unsigned)snd_ice1712_read(ice, ICE1712_IREG_GPIO_WRITE_MASK));
+	snd_iprintf(buffer, "  GPIO_WRITE_MASK  : 0x%02x\n", (unsigned)snd_ice1712_read(ice, ICE1712_IREG_GPIO_WRITE_MASK));
 	snd_iprintf(buffer, "  GPIO_DIRECTION   : 0x%02x\n", (unsigned)snd_ice1712_read(ice, ICE1712_IREG_GPIO_DIRECTION));
 }
 
-static void __devinit snd_ice1712_proc_init(struct snd_ice1712 * ice)
+static void __devinit snd_ice1712_proc_init(struct snd_ice1712 *ice)
 {
 	struct snd_info_entry *entry;
 
-	if (! snd_card_proc_new(ice->card, "ice1712", &entry))
+	if (!snd_card_proc_new(ice->card, "ice1712", &entry))
 		snd_info_set_text_ops(entry, ice, snd_ice1712_proc_read);
 }
 
@@ -1613,7 +1616,7 @@
 				  struct snd_ctl_elem_value *ucontrol)
 {
 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
-	
+
 	memcpy(ucontrol->value.bytes.data, &ice->eeprom, sizeof(ice->eeprom));
 	return 0;
 }
@@ -1641,7 +1644,7 @@
 {
 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
 	if (ice->spdif.ops.default_get)
-		ice->spdif.ops.default_get(ice, ucontrol); 
+		ice->spdif.ops.default_get(ice, ucontrol);
 	return 0;
 }
 
@@ -1657,7 +1660,7 @@
 static struct snd_kcontrol_new snd_ice1712_spdif_default __devinitdata =
 {
 	.iface =	SNDRV_CTL_ELEM_IFACE_PCM,
-	.name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT),
+	.name =         SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT),
 	.info =		snd_ice1712_spdif_info,
 	.get =		snd_ice1712_spdif_default_get,
 	.put =		snd_ice1712_spdif_default_put
@@ -1709,7 +1712,7 @@
 {
 	.access =	SNDRV_CTL_ELEM_ACCESS_READ,
 	.iface =	SNDRV_CTL_ELEM_IFACE_PCM,
-	.name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,CON_MASK),
+	.name =         SNDRV_CTL_NAME_IEC958("", PLAYBACK, CON_MASK),
 	.info =		snd_ice1712_spdif_info,
 	.get =		snd_ice1712_spdif_maskc_get,
 };
@@ -1718,7 +1721,7 @@
 {
 	.access =	SNDRV_CTL_ELEM_ACCESS_READ,
 	.iface =	SNDRV_CTL_ELEM_IFACE_PCM,
-	.name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,PRO_MASK),
+	.name =         SNDRV_CTL_NAME_IEC958("", PLAYBACK, PRO_MASK),
 	.info =		snd_ice1712_spdif_info,
 	.get =		snd_ice1712_spdif_maskp_get,
 };
@@ -1746,7 +1749,7 @@
 	.access =	(SNDRV_CTL_ELEM_ACCESS_READWRITE |
 			 SNDRV_CTL_ELEM_ACCESS_INACTIVE),
 	.iface =	SNDRV_CTL_ELEM_IFACE_PCM,
-	.name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,PCM_STREAM),
+	.name =         SNDRV_CTL_NAME_IEC958("", PLAYBACK, PCM_STREAM),
 	.info =		snd_ice1712_spdif_info,
 	.get =		snd_ice1712_spdif_stream_get,
 	.put =		snd_ice1712_spdif_stream_put
@@ -1758,7 +1761,7 @@
 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
 	unsigned char mask = kcontrol->private_value & 0xff;
 	int invert = (kcontrol->private_value & (1<<24)) ? 1 : 0;
-	
+
 	snd_ice1712_save_gpio_status(ice);
 	ucontrol->value.integer.value[0] =
 		(snd_ice1712_gpio_read(ice) & mask ? 1 : 0) ^ invert;
@@ -1825,7 +1828,7 @@
 		9, 6, 3, 1, 7, 4, 0, 12, 8, 5, 2, 11, 255, 255, 255, 10
 	};
 	unsigned char val;
-	
+
 	spin_lock_irq(&ice->reg_lock);
 	if (is_spdif_master(ice)) {
 		ucontrol->value.enumerated.item[0] = 13;
@@ -1867,7 +1870,7 @@
 
 	if ((oval & ICE1712_SPDIF_MASTER) !=
 	    (inb(ICEMT(ice, RATE)) & ICE1712_SPDIF_MASTER))
-	        snd_ice1712_set_input_clock_source(ice, is_spdif_master(ice));
+		snd_ice1712_set_input_clock_source(ice, is_spdif_master(ice));
 
 	return change;
 }
@@ -1897,7 +1900,7 @@
 		"64000",	/* 10: 15 */
 		"88200",	/* 11: 11 */
 		"96000",	/* 12: 7 */
-		// "IEC958 Input",	/* 13: -- */
+		/* "IEC958 Input",	13: -- */
 	};
 	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
 	uinfo->count = 1;
@@ -2026,7 +2029,7 @@
 		"IEC958 In L", "IEC958 In R", /* 9-10 */
 		"Digital Mixer", /* 11 - optional */
 	};
-	
+
 	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
 	uinfo->count = 1;
 	uinfo->value.enumerated.items =
@@ -2070,7 +2073,7 @@
 	int change, shift;
 	int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
 	unsigned int val, old_val, nval;
-	
+
 	/* update PSDOUT */
 	if (ucontrol->value.enumerated.item[0] >= 11)
 		nval = idx < 2 ? 1 : 0; /* dig mixer (or pcm) */
@@ -2140,7 +2143,7 @@
 	int change, shift;
 	int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
 	unsigned int val, old_val, nval;
-	
+
 	/* update SPDOUT */
 	spin_lock_irq(&ice->reg_lock);
 	val = old_val = inw(ICEMT(ice, ROUTE_SPDOUT));
@@ -2182,7 +2185,7 @@
 
 static struct snd_kcontrol_new snd_ice1712_mixer_pro_spdif_route __devinitdata = {
 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-	.name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Route",
+	.name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, NONE) "Route",
 	.info = snd_ice1712_pro_route_info,
 	.get = snd_ice1712_pro_route_spdif_get,
 	.put = snd_ice1712_pro_route_spdif_put,
@@ -2204,7 +2207,7 @@
 					   struct snd_ctl_elem_value *ucontrol)
 {
 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
-	
+
 	ucontrol->value.integer.value[0] = inb(ICEMT(ice, MONITOR_RATE));
 	return 0;
 }
@@ -2245,7 +2248,7 @@
 {
 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
 	int idx;
-	
+
 	spin_lock_irq(&ice->reg_lock);
 	for (idx = 0; idx < 22; idx++) {
 		outb(idx, ICEMT(ice, MONITOR_PEAKINDEX));
@@ -2296,12 +2299,12 @@
 	unsigned int i, size;
 	struct snd_ice1712_card_info * const *tbl, *c;
 
-	if (! modelname || ! *modelname) {
+	if (!modelname || !*modelname) {
 		ice->eeprom.subvendor = 0;
 		if ((inb(ICEREG(ice, I2C_CTRL)) & ICE1712_I2C_EEPROM) != 0)
 			ice->eeprom.subvendor = (snd_ice1712_read_i2c(ice, dev, 0x00) << 0) |
-				(snd_ice1712_read_i2c(ice, dev, 0x01) << 8) | 
-				(snd_ice1712_read_i2c(ice, dev, 0x02) << 16) | 
+				(snd_ice1712_read_i2c(ice, dev, 0x01) << 8) |
+				(snd_ice1712_read_i2c(ice, dev, 0x02) << 16) |
 				(snd_ice1712_read_i2c(ice, dev, 0x03) << 24);
 		if (ice->eeprom.subvendor == 0 ||
 		    ice->eeprom.subvendor == (unsigned int)-1) {
@@ -2318,12 +2321,12 @@
 	}
 	for (tbl = card_tables; *tbl; tbl++) {
 		for (c = *tbl; c->subvendor; c++) {
-			if (modelname && c->model && ! strcmp(modelname, c->model)) {
+			if (modelname && c->model && !strcmp(modelname, c->model)) {
 				printk(KERN_INFO "ice1712: Using board model %s\n", c->name);
 				ice->eeprom.subvendor = c->subvendor;
 			} else if (c->subvendor != ice->eeprom.subvendor)
 				continue;
-			if (! c->eeprom_size || ! c->eeprom_data)
+			if (!c->eeprom_size || !c->eeprom_data)
 				goto found;
 			/* if the EEPROM is given by the driver, use it */
 			snd_printdd("using the defined eeprom..\n");
@@ -2416,7 +2419,8 @@
 	int err;
 	struct snd_kcontrol *kctl;
 
-	snd_assert(ice->pcm_pro != NULL, return -EIO);
+	if (snd_BUG_ON(!ice->pcm_pro))
+		return -EIO;
 	err = snd_ctl_add(ice->card, kctl = snd_ctl_new1(&snd_ice1712_spdif_default, ice));
 	if (err < 0)
 		return err;
@@ -2483,13 +2487,13 @@
 
 static int snd_ice1712_free(struct snd_ice1712 *ice)
 {
-	if (! ice->port)
+	if (!ice->port)
 		goto __hw_end;
 	/* mask all interrupts */
 	outb(0xc0, ICEMT(ice, IRQ));
 	outb(0xff, ICEREG(ice, IRQMASK));
 	/* --- */
-      __hw_end:
+__hw_end:
 	if (ice->irq >= 0)
 		free_irq(ice->irq, ice);
 
@@ -2514,7 +2518,7 @@
 					int omni,
 					int cs8427_timeout,
 					int dxr_enable,
-					struct snd_ice1712 ** r_ice1712)
+					struct snd_ice1712 **r_ice1712)
 {
 	struct snd_ice1712 *ice;
 	int err;
@@ -2524,8 +2528,9 @@
 
 	*r_ice1712 = NULL;
 
-        /* enable PCI device */
-	if ((err = pci_enable_device(pci)) < 0)
+	/* enable PCI device */
+	err = pci_enable_device(pci);
+	if (err < 0)
 		return err;
 	/* check, if we can restrict PCI DMA transfers to 28 bits */
 	if (pci_set_dma_mask(pci, DMA_28BIT_MASK) < 0 ||
@@ -2569,7 +2574,8 @@
 	snd_ice1712_proc_init(ice);
 	synchronize_irq(pci->irq);
 
-	if ((err = pci_request_regions(pci, "ICE1712")) < 0) {
+	err = pci_request_regions(pci, "ICE1712");
+	if (err < 0) {
 		kfree(ice);
 		pci_disable_device(pci);
 		return err;
@@ -2585,7 +2591,7 @@
 		snd_ice1712_free(ice);
 		return -EIO;
 	}
-	
+
 	ice->irq = pci->irq;
 
 	if (snd_ice1712_read_eeprom(ice, modelname) < 0) {
@@ -2605,9 +2611,10 @@
 	     ICEREG(ice, IRQMASK));
 	outb(0x00, ICEMT(ice, IRQ));
 
-	if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, ice, &ops)) < 0) {
+	err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, ice, &ops);
+	if (err < 0) {
 		snd_ice1712_free(ice);
- 		return err;
+		return err;
 	}
 
 	snd_card_set_dev(card, &pci->dev);
@@ -2647,10 +2654,10 @@
 
 	strcpy(card->driver, "ICE1712");
 	strcpy(card->shortname, "ICEnsemble ICE1712");
-	
-	if ((err = snd_ice1712_create(card, pci, model[dev], omni[dev],
-				      cs8427_timeout[dev], dxr_enable[dev],
-				      &ice)) < 0) {
+
+	err = snd_ice1712_create(card, pci, model[dev], omni[dev],
+		cs8427_timeout[dev], dxr_enable[dev], &ice);
+	if (err < 0) {
 		snd_card_free(card);
 		return err;
 	}
@@ -2662,7 +2669,8 @@
 				if (c->driver) /* specific driver? */
 					strcpy(card->driver, c->driver);
 				if (c->chip_init) {
-					if ((err = c->chip_init(ice)) < 0) {
+					err = c->chip_init(ice);
+					if (err < 0) {
 						snd_card_free(card);
 						return err;
 					}
@@ -2674,47 +2682,52 @@
 	c = &no_matched;
  __found:
 
-	if ((err = snd_ice1712_pcm_profi(ice, pcm_dev++, NULL)) < 0) {
+	err = snd_ice1712_pcm_profi(ice, pcm_dev++, NULL);
+	if (err < 0) {
 		snd_card_free(card);
 		return err;
 	}
-	
+
 	if (ice_has_con_ac97(ice))
-		if ((err = snd_ice1712_pcm(ice, pcm_dev++, NULL)) < 0) {
+		err = snd_ice1712_pcm(ice, pcm_dev++, NULL);
+		if (err < 0) {
 			snd_card_free(card);
 			return err;
 		}
 
-	if ((err = snd_ice1712_ac97_mixer(ice)) < 0) {
+	err = snd_ice1712_ac97_mixer(ice);
+	if (err < 0) {
 		snd_card_free(card);
 		return err;
 	}
 
-	if ((err = snd_ice1712_build_controls(ice)) < 0) {
+	err = snd_ice1712_build_controls(ice);
+	if (err < 0) {
 		snd_card_free(card);
 		return err;
 	}
 
 	if (c->build_controls) {
-		if ((err = c->build_controls(ice)) < 0) {
+		err = c->build_controls(ice);
+		if (err < 0) {
 			snd_card_free(card);
 			return err;
 		}
 	}
 
 	if (ice_has_con_ac97(ice))
-		if ((err = snd_ice1712_pcm_ds(ice, pcm_dev++, NULL)) < 0) {
+		err = snd_ice1712_pcm_ds(ice, pcm_dev++, NULL);
+		if (err < 0) {
 			snd_card_free(card);
 			return err;
 		}
 
-	if (! c->no_mpu401) {
-		if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_ICE1712,
-					       ICEREG(ice, MPU1_CTRL),
-					       (c->mpu401_1_info_flags |
-						MPU401_INFO_INTEGRATED),
-					       ice->irq, 0,
-					       &ice->rmidi[0])) < 0) {
+	if (!c->no_mpu401) {
+		err = snd_mpu401_uart_new(card, 0, MPU401_HW_ICE1712,
+			ICEREG(ice, MPU1_CTRL),
+			(c->mpu401_1_info_flags | MPU401_INFO_INTEGRATED),
+			ice->irq, 0, &ice->rmidi[0]);
+		if (err < 0) {
 			snd_card_free(card);
 			return err;
 		}
@@ -2726,12 +2739,12 @@
 
 		if (ice->eeprom.data[ICE_EEP1_CODEC] & ICE1712_CFG_2xMPU401) {
 			/*  2nd port used  */
-			if ((err = snd_mpu401_uart_new(card, 1, MPU401_HW_ICE1712,
-						       ICEREG(ice, MPU2_CTRL),
-						       (c->mpu401_2_info_flags |
-							MPU401_INFO_INTEGRATED),
-						       ice->irq, 0,
-						       &ice->rmidi[1])) < 0) {
+			err = snd_mpu401_uart_new(card, 1, MPU401_HW_ICE1712,
+				ICEREG(ice, MPU2_CTRL),
+				(c->mpu401_2_info_flags | MPU401_INFO_INTEGRATED),
+				ice->irq, 0, &ice->rmidi[1]);
+
+			if (err < 0) {
 				snd_card_free(card);
 				return err;
 			}
@@ -2749,7 +2762,8 @@
 	sprintf(card->longname, "%s at 0x%lx, irq %i",
 		card->shortname, ice->port, ice->irq);
 
-	if ((err = snd_card_register(card)) < 0) {
+	err = snd_card_register(card);
+	if (err < 0) {
 		snd_card_free(card);
 		return err;
 	}
diff --git a/sound/pci/ice1712/ice1712.h b/sound/pci/ice1712/ice1712.h
index 762fbd7..fdae6de 100644
--- a/sound/pci/ice1712/ice1712.h
+++ b/sound/pci/ice1712/ice1712.h
@@ -20,7 +20,7 @@
  *   along with this program; if not, write to the Free Software
  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  *
- */      
+ */
 
 #include <sound/control.h>
 #include <sound/ac97_codec.h>
@@ -112,7 +112,7 @@
  */
 
 #define ICEDS(ice, x) ((ice)->dmapath_port + ICE1712_DS_##x)
- 
+
 #define ICE1712_DS_INTMASK		0x00	/* word - interrupt mask */
 #define ICE1712_DS_INTSTAT		0x02	/* word - interrupt status */
 #define ICE1712_DS_DATA			0x04	/* dword - channel data */
@@ -121,7 +121,7 @@
 /*
  *  Consumer section channel registers
  */
- 
+
 #define ICE1712_DSC_ADDR0		0x00	/* dword - base address 0 */
 #define ICE1712_DSC_COUNT0		0x01	/* word - count 0 */
 #define ICE1712_DSC_ADDR1		0x02	/* dword - base address 1 */
@@ -138,7 +138,7 @@
 #define ICE1712_DSC_RATE		0x05	/* dword - rate */
 #define ICE1712_DSC_VOLUME		0x06	/* word - volume control */
 
-/* 
+/*
  *  Professional multi-track direct control registers
  */
 
@@ -214,7 +214,7 @@
 
 
 /*
- *  
+ *
  */
 
 struct snd_ice1712;
@@ -253,12 +253,12 @@
 	ICE_EEP1_ADC_ID2,
 	ICE_EEP1_ADC_ID3
 };
-	
+
 #define ice_has_con_ac97(ice)	(!((ice)->eeprom.data[ICE_EEP1_CODEC] & ICE1712_CFG_NO_CON_AC97))
 
 
 struct snd_ak4xxx_private {
-	unsigned int cif: 1;		/* CIF mode */
+	unsigned int cif:1;		/* CIF mode */
 	unsigned char caddr;		/* C0 and C1 bits */
 	unsigned int data_mask;		/* DATA gpio bit */
 	unsigned int clk_mask;		/* CLK gpio bit */
@@ -306,11 +306,11 @@
 	struct snd_pcm *pcm;
 	struct snd_pcm *pcm_ds;
 	struct snd_pcm *pcm_pro;
-        struct snd_pcm_substream *playback_con_substream;
-        struct snd_pcm_substream *playback_con_substream_ds[6];
-        struct snd_pcm_substream *capture_con_substream;
-        struct snd_pcm_substream *playback_pro_substream;
-        struct snd_pcm_substream *capture_pro_substream;
+	struct snd_pcm_substream *playback_con_substream;
+	struct snd_pcm_substream *playback_con_substream_ds[6];
+	struct snd_pcm_substream *capture_con_substream;
+	struct snd_pcm_substream *playback_pro_substream;
+	struct snd_pcm_substream *capture_pro_substream;
 	unsigned int playback_pro_size;
 	unsigned int capture_pro_size;
 	unsigned int playback_con_virt_addr[6];
@@ -326,15 +326,15 @@
 	struct snd_ice1712_eeprom eeprom;
 
 	unsigned int pro_volumes[20];
-	unsigned int omni: 1;		/* Delta Omni I/O */
-	unsigned int dxr_enable: 1;	/* Terratec DXR enable for DMX6FIRE */
-	unsigned int vt1724: 1;
-	unsigned int vt1720: 1;
-	unsigned int has_spdif: 1;	/* VT1720/4 - has SPDIF I/O */
-	unsigned int force_pdma4: 1;	/* VT1720/4 - PDMA4 as non-spdif */
-	unsigned int force_rdma1: 1;	/* VT1720/4 - RDMA1 as non-spdif */
-	unsigned int midi_output: 1;	/* VT1720/4: MIDI output triggered */
-	unsigned int midi_input: 1;	/* VT1720/4: MIDI input triggered */
+	unsigned int omni:1;		/* Delta Omni I/O */
+	unsigned int dxr_enable:1;	/* Terratec DXR enable for DMX6FIRE */
+	unsigned int vt1724:1;
+	unsigned int vt1720:1;
+	unsigned int has_spdif:1;	/* VT1720/4 - has SPDIF I/O */
+	unsigned int force_pdma4:1;	/* VT1720/4 - PDMA4 as non-spdif */
+	unsigned int force_rdma1:1;	/* VT1720/4 - RDMA1 as non-spdif */
+	unsigned int midi_output:1;	/* VT1720/4: MIDI output triggered */
+	unsigned int midi_input:1;	/* VT1720/4: MIDI input triggered */
 	unsigned int num_total_dacs;	/* total DACs */
 	unsigned int num_total_adcs;	/* total ADCs */
 	unsigned int cur_rate;		/* current rate */
@@ -351,7 +351,7 @@
 	struct snd_i2c_bus *i2c;		/* I2C bus */
 	struct snd_i2c_device *cs8427;	/* CS8427 I2C device */
 	unsigned int cs8427_timeout;	/* CS8427 reset timeout in HZ/100 */
-	
+
 	struct ice1712_gpio {
 		unsigned int direction;		/* current direction bits */
 		unsigned int write_mask;	/* current mask bits */
@@ -455,7 +455,7 @@
 {
 	ice->gpio.direction &= ~mask;
 	snd_ice1712_gpio_set_dir(ice, ice->gpio.direction);
-	return  (snd_ice1712_gpio_read(ice) & mask);
+	return  snd_ice1712_gpio_read(ice) & mask;
 }
 
 int snd_ice1712_spdif_build_controls(struct snd_ice1712 *ice);
@@ -467,13 +467,13 @@
 
 int snd_ice1712_init_cs8427(struct snd_ice1712 *ice, int addr);
 
-static inline void snd_ice1712_write(struct snd_ice1712 * ice, u8 addr, u8 data)
+static inline void snd_ice1712_write(struct snd_ice1712 *ice, u8 addr, u8 data)
 {
 	outb(addr, ICEREG(ice, INDEX));
 	outb(data, ICEREG(ice, DATA));
 }
 
-static inline u8 snd_ice1712_read(struct snd_ice1712 * ice, u8 addr)
+static inline u8 snd_ice1712_read(struct snd_ice1712 *ice, u8 addr)
 {
 	outb(addr, ICEREG(ice, INDEX));
 	return inb(ICEREG(ice, DATA));
@@ -491,7 +491,7 @@
 	char *driver;
 	int (*chip_init)(struct snd_ice1712 *);
 	int (*build_controls)(struct snd_ice1712 *);
-	unsigned int no_mpu401: 1;
+	unsigned int no_mpu401:1;
 	unsigned int mpu401_1_info_flags;
 	unsigned int mpu401_2_info_flags;
 	const char *mpu401_1_name;
diff --git a/sound/pci/ice1712/ice1724.c b/sound/pci/ice1712/ice1724.c
index e596d77..1b3f117 100644
--- a/sound/pci/ice1712/ice1724.c
+++ b/sound/pci/ice1712/ice1724.c
@@ -20,9 +20,9 @@
  *   along with this program; if not, write to the Free Software
  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  *
- */      
+ */
 
-#include <asm/io.h>
+#include <linux/io.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
 #include <linux/init.h>
@@ -105,7 +105,7 @@
 /*
  *  Basic I/O
  */
- 
+
 /*
  *  default rates, default clock routines
  */
@@ -198,7 +198,7 @@
 static void snd_vt1724_set_gpio_mask(struct snd_ice1712 *ice, unsigned int data)
 {
 	outw(data, ICEREG1724(ice, GPIO_WRITE_MASK));
-	if (! ice->vt1720) /* VT1720 supports only 16 GPIO bits */
+	if (!ice->vt1720) /* VT1720 supports only 16 GPIO bits */
 		outb((data >> 16) & 0xff, ICEREG1724(ice, GPIO_WRITE_MASK_22));
 	inw(ICEREG1724(ice, GPIO_WRITE_MASK)); /* dummy read for pci-posting */
 }
@@ -206,7 +206,7 @@
 static void snd_vt1724_set_gpio_data(struct snd_ice1712 *ice, unsigned int data)
 {
 	outw(data, ICEREG1724(ice, GPIO_DATA));
-	if (! ice->vt1720)
+	if (!ice->vt1720)
 		outb(data >> 16, ICEREG1724(ice, GPIO_DATA_22));
 	inw(ICEREG1724(ice, GPIO_DATA)); /* dummy read for pci-posting */
 }
@@ -214,7 +214,7 @@
 static unsigned int snd_vt1724_get_gpio_data(struct snd_ice1712 *ice)
 {
 	unsigned int data;
-	if (! ice->vt1720)
+	if (!ice->vt1720)
 		data = (unsigned int)inb(ICEREG1724(ice, GPIO_DATA_22));
 	else
 		data = 0;
@@ -399,7 +399,7 @@
 			break;
 		}
 #endif
-		handled = 1;		
+		handled = 1;
 		if (status & VT1724_IRQ_MPU_TX) {
 			spin_lock(&ice->reg_lock);
 			if (ice->midi_output)
@@ -468,8 +468,8 @@
 			/* ought to really handle this properly */
 			if (mtstat & VT1724_MULTI_FIFO_ERR) {
 				unsigned char fstat = inb(ICEMT1724(ice, DMA_FIFO_ERR));
-				outb(fstat, ICEMT1724(ice, DMA_FIFO_ERR));	
-				outb(VT1724_MULTI_FIFO_ERR | inb(ICEMT1724(ice, DMA_INT_MASK)), ICEMT1724(ice, DMA_INT_MASK));	
+				outb(fstat, ICEMT1724(ice, DMA_FIFO_ERR));
+				outb(VT1724_MULTI_FIFO_ERR | inb(ICEMT1724(ice, DMA_INT_MASK)), ICEMT1724(ice, DMA_INT_MASK));
 				/* If I don't do this, I get machine lockup due to continual interrupts */
 			}
 
@@ -733,17 +733,17 @@
 	outl(substream->runtime->dma_addr, ICEMT1724(ice, PLAYBACK_ADDR));
 
 	size = (snd_pcm_lib_buffer_bytes(substream) >> 2) - 1;
-	// outl(size, ICEMT1724(ice, PLAYBACK_SIZE));
+	/* outl(size, ICEMT1724(ice, PLAYBACK_SIZE)); */
 	outw(size, ICEMT1724(ice, PLAYBACK_SIZE));
 	outb(size >> 16, ICEMT1724(ice, PLAYBACK_SIZE) + 2);
 	size = (snd_pcm_lib_period_bytes(substream) >> 2) - 1;
-	// outl(size, ICEMT1724(ice, PLAYBACK_COUNT));
+	/* outl(size, ICEMT1724(ice, PLAYBACK_COUNT)); */
 	outw(size, ICEMT1724(ice, PLAYBACK_COUNT));
 	outb(size >> 16, ICEMT1724(ice, PLAYBACK_COUNT) + 2);
 
 	spin_unlock_irq(&ice->reg_lock);
 
-	// printk("pro prepare: ch = %d, addr = 0x%x, buffer = 0x%x, period = 0x%x\n", substream->runtime->channels, (unsigned int)substream->runtime->dma_addr, snd_pcm_lib_buffer_bytes(substream), snd_pcm_lib_period_bytes(substream));
+	/* printk("pro prepare: ch = %d, addr = 0x%x, buffer = 0x%x, period = 0x%x\n", substream->runtime->channels, (unsigned int)substream->runtime->dma_addr, snd_pcm_lib_buffer_bytes(substream), snd_pcm_lib_period_bytes(substream)); */
 	return 0;
 }
 
@@ -771,7 +771,7 @@
 	ptr = inl(ICEMT1724(ice, PLAYBACK_SIZE)) & 0xffffff;
 	ptr = (ptr + 1) << 2;
 	ptr = bytes_to_frames(substream->runtime, ptr);
-	if (! ptr)
+	if (!ptr)
 		;
 	else if (ptr <= substream->runtime->buffer_size)
 		ptr = substream->runtime->buffer_size - ptr;
@@ -815,7 +815,7 @@
 	ptr = inw(ice->profi_port + reg->size);
 	ptr = (ptr + 1) << 2;
 	ptr = bytes_to_frames(substream->runtime, ptr);
-	if (! ptr)
+	if (!ptr)
 		;
 	else if (ptr <= substream->runtime->buffer_size)
 		ptr = substream->runtime->buffer_size - ptr;
@@ -842,8 +842,7 @@
 	.start = VT1724_RDMA0_START,
 };
 
-static const struct snd_pcm_hardware snd_vt1724_playback_pro =
-{
+static const struct snd_pcm_hardware snd_vt1724_playback_pro = {
 	.info =			(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
 				 SNDRV_PCM_INFO_BLOCK_TRANSFER |
 				 SNDRV_PCM_INFO_MMAP_VALID |
@@ -861,8 +860,7 @@
 	.periods_max =		1024,
 };
 
-static const struct snd_pcm_hardware snd_vt1724_spdif =
-{
+static const struct snd_pcm_hardware snd_vt1724_spdif = {
 	.info =			(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
 				 SNDRV_PCM_INFO_BLOCK_TRANSFER |
 				 SNDRV_PCM_INFO_MMAP_VALID |
@@ -883,8 +881,7 @@
 	.periods_max =		1024,
 };
 
-static const struct snd_pcm_hardware snd_vt1724_2ch_stereo =
-{
+static const struct snd_pcm_hardware snd_vt1724_2ch_stereo = {
 	.info =			(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
 				 SNDRV_PCM_INFO_BLOCK_TRANSFER |
 				 SNDRV_PCM_INFO_MMAP_VALID |
@@ -942,7 +939,7 @@
 {
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct snd_ice1712 *ice = snd_pcm_substream_chip(substream);
-	int chs;
+	int chs, num_indeps;
 
 	runtime->private_data = (void *)&vt1724_playback_pro_reg;
 	ice->playback_pro_substream = substream;
@@ -952,7 +949,8 @@
 	set_rate_constraints(ice, substream);
 	mutex_lock(&ice->open_mutex);
 	/* calculate the currently available channels */
-	for (chs = 0; chs < 3; chs++) {
+	num_indeps = ice->num_total_dacs / 2 - 1;
+	for (chs = 0; chs < num_indeps; chs++) {
 		if (ice->pcm_reserved[chs])
 			break;
 	}
@@ -1029,7 +1027,7 @@
 	.pointer =	snd_vt1724_pcm_pointer,
 };
 
-static int __devinit snd_vt1724_pcm_profi(struct snd_ice1712 * ice, int device)
+static int __devinit snd_vt1724_pcm_profi(struct snd_ice1712 *ice, int device)
 {
 	struct snd_pcm *pcm;
 	int err;
@@ -1114,7 +1112,7 @@
 static int snd_vt1724_playback_spdif_prepare(struct snd_pcm_substream *substream)
 {
 	struct snd_ice1712 *ice = snd_pcm_substream_chip(substream);
-	if (! ice->force_pdma4)
+	if (!ice->force_pdma4)
 		update_spdif_rate(ice, substream->runtime->rate);
 	return snd_vt1724_pcm_prepare(substream);
 }
@@ -1214,7 +1212,7 @@
 };
 
 
-static int __devinit snd_vt1724_pcm_spdif(struct snd_ice1712 * ice, int device)
+static int __devinit snd_vt1724_pcm_spdif(struct snd_ice1712 *ice, int device)
 {
 	char *name;
 	struct snd_pcm *pcm;
@@ -1233,7 +1231,7 @@
 		ice->has_spdif = 1;
 	} else
 		capt = 0;
-	if (! play && ! capt)
+	if (!play && !capt)
 		return 0; /* no spdif device */
 
 	if (ice->force_pdma4 || ice->force_rdma1)
@@ -1348,7 +1346,7 @@
 };
 
 
-static int __devinit snd_vt1724_pcm_indep(struct snd_ice1712 * ice, int device)
+static int __devinit snd_vt1724_pcm_indep(struct snd_ice1712 *ice, int device)
 {
 	struct snd_pcm *pcm;
 	int play;
@@ -1383,11 +1381,11 @@
  *  Mixer section
  */
 
-static int __devinit snd_vt1724_ac97_mixer(struct snd_ice1712 * ice)
+static int __devinit snd_vt1724_ac97_mixer(struct snd_ice1712 *ice)
 {
 	int err;
 
-	if (! (ice->eeprom.data[ICE_EEP2_ACLINK] & VT1724_CFG_PRO_I2S)) {
+	if (!(ice->eeprom.data[ICE_EEP2_ACLINK] & VT1724_CFG_PRO_I2S)) {
 		struct snd_ac97_bus *pbus;
 		struct snd_ac97_template ac97;
 		static struct snd_ac97_bus_ops ops = {
@@ -1400,11 +1398,13 @@
 		mdelay(5); /* FIXME */
 		outb(inb(ICEMT1724(ice, AC97_CMD)) & ~0x80, ICEMT1724(ice, AC97_CMD));
 
-		if ((err = snd_ac97_bus(ice->card, 0, &ops, NULL, &pbus)) < 0)
+		err = snd_ac97_bus(ice->card, 0, &ops, NULL, &pbus);
+		if (err < 0)
 			return err;
 		memset(&ac97, 0, sizeof(ac97));
 		ac97.private_data = ice;
-		if ((err = snd_ac97_mixer(pbus, &ac97, &ice->ac97)) < 0)
+		err = snd_ac97_mixer(pbus, &ac97, &ice->ac97);
+		if (err < 0)
 			printk(KERN_WARNING "ice1712: cannot initialize pro ac97, skipped\n");
 		else
 			return 0;
@@ -1425,7 +1425,7 @@
 		((unsigned int)ice->eeprom.data[idx + 2] << 16);
 }
 
-static void snd_vt1724_proc_read(struct snd_info_entry *entry, 
+static void snd_vt1724_proc_read(struct snd_info_entry *entry,
 				 struct snd_info_buffer *buffer)
 {
 	struct snd_ice1712 *ice = entry->private_data;
@@ -1467,11 +1467,11 @@
 			    idx, inb(ice->profi_port+idx));
 }
 
-static void __devinit snd_vt1724_proc_init(struct snd_ice1712 * ice)
+static void __devinit snd_vt1724_proc_init(struct snd_ice1712 *ice)
 {
 	struct snd_info_entry *entry;
 
-	if (! snd_card_proc_new(ice->card, "ice1724", &entry))
+	if (!snd_card_proc_new(ice->card, "ice1724", &entry))
 		snd_info_set_text_ops(entry, ice, snd_vt1724_proc_read);
 }
 
@@ -1491,7 +1491,7 @@
 				 struct snd_ctl_elem_value *ucontrol)
 {
 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
-	
+
 	memcpy(ucontrol->value.bytes.data, &ice->eeprom, sizeof(ice->eeprom));
 	return 0;
 }
@@ -1606,13 +1606,13 @@
 	if (val != old)
 		update_spdif_bits(ice, val);
 	spin_unlock_irq(&ice->reg_lock);
-	return (val != old);
+	return val != old;
 }
 
 static struct snd_kcontrol_new snd_vt1724_spdif_default __devinitdata =
 {
 	.iface =	SNDRV_CTL_ELEM_IFACE_PCM,
-	.name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT),
+	.name =         SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT),
 	.info =		snd_vt1724_spdif_info,
 	.get =		snd_vt1724_spdif_default_get,
 	.put =		snd_vt1724_spdif_default_put
@@ -1645,7 +1645,7 @@
 {
 	.access =	SNDRV_CTL_ELEM_ACCESS_READ,
 	.iface =	SNDRV_CTL_ELEM_IFACE_PCM,
-	.name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,CON_MASK),
+	.name =         SNDRV_CTL_NAME_IEC958("", PLAYBACK, CON_MASK),
 	.info =		snd_vt1724_spdif_info,
 	.get =		snd_vt1724_spdif_maskc_get,
 };
@@ -1654,7 +1654,7 @@
 {
 	.access =	SNDRV_CTL_ELEM_ACCESS_READ,
 	.iface =	SNDRV_CTL_ELEM_IFACE_PCM,
-	.name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,PRO_MASK),
+	.name =         SNDRV_CTL_NAME_IEC958("", PLAYBACK, PRO_MASK),
 	.info =		snd_vt1724_spdif_info,
 	.get =		snd_vt1724_spdif_maskp_get,
 };
@@ -1691,8 +1691,8 @@
 {
 	.iface =	SNDRV_CTL_ELEM_IFACE_MIXER,
 	/* FIXME: the following conflict with IEC958 Playback Route */
-	// .name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,SWITCH),
-	.name =         SNDRV_CTL_NAME_IEC958("Output ",NONE,SWITCH),
+	/* .name =         SNDRV_CTL_NAME_IEC958("", PLAYBACK, SWITCH), */
+	.name =         SNDRV_CTL_NAME_IEC958("Output ", NONE, SWITCH),
 	.info =		snd_vt1724_spdif_sw_info,
 	.get =		snd_vt1724_spdif_sw_get,
 	.put =		snd_vt1724_spdif_sw_put
@@ -1712,7 +1712,7 @@
 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
 	int shift = kcontrol->private_value & 0xff;
 	int invert = (kcontrol->private_value & (1<<24)) ? 1 : 0;
-	
+
 	snd_ice1712_save_gpio_status(ice);
 	ucontrol->value.integer.value[0] =
 		(snd_ice1712_gpio_read(ice) & (1 << shift) ? 1 : 0) ^ invert;
@@ -1767,7 +1767,7 @@
 {
 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
 	unsigned int i, rate;
-	
+
 	spin_lock_irq(&ice->reg_lock);
 	if (ice->is_spdif_master(ice)) {
 		ucontrol->value.enumerated.item[0] = ice->hw_rates->count;
@@ -1923,7 +1923,7 @@
 		"H/W In 0", "H/W In 1", /* 1-2 */
 		"IEC958 In L", "IEC958 In R", /* 3-4 */
 	};
-	
+
 	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
 	uinfo->count = 1;
 	uinfo->value.enumerated.items = 5;
@@ -1953,7 +1953,7 @@
 
 	val = inl(ICEMT1724(ice, ROUTE_PLAYBACK));
 	val >>= shift;
-	val &= 7;	//we now have 3 bits per output
+	val &= 7; /* we now have 3 bits per output */
 	eitem = xlate[val];
 	if (eitem == 255) {
 		snd_BUG();
@@ -2032,7 +2032,7 @@
 
 static struct snd_kcontrol_new snd_vt1724_mixer_pro_spdif_route __devinitdata = {
 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-	.name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Route",
+	.name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, NONE) "Route",
 	.info = snd_vt1724_pro_route_info,
 	.get = snd_vt1724_pro_route_spdif_get,
 	.put = snd_vt1724_pro_route_spdif_put,
@@ -2055,7 +2055,7 @@
 {
 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
 	int idx;
-	
+
 	spin_lock_irq(&ice->reg_lock);
 	for (idx = 0; idx < 22; idx++) {
 		outb(idx, ICEMT1724(ice, MONITOR_PEAKINDEX));
@@ -2082,7 +2082,7 @@
 
 static struct snd_ice1712_card_info *card_tables[] __devinitdata = {
 	snd_vt1724_revo_cards,
-	snd_vt1724_amp_cards, 
+	snd_vt1724_amp_cards,
 	snd_vt1724_aureon_cards,
 	snd_vt1720_mobo_cards,
 	snd_vt1720_pontis_cards,
@@ -2120,7 +2120,7 @@
 	wait_i2c_busy(ice);
 	val = inb(ICEREG1724(ice, I2C_DATA));
 	mutex_unlock(&ice->i2c_mutex);
-	//printk("i2c_read: [0x%x,0x%x] = 0x%x\n", dev, addr, val);
+	/* printk("i2c_read: [0x%x,0x%x] = 0x%x\n", dev, addr, val); */
 	return val;
 }
 
@@ -2129,7 +2129,7 @@
 {
 	mutex_lock(&ice->i2c_mutex);
 	wait_i2c_busy(ice);
-	//printk("i2c_write: [0x%x,0x%x] = 0x%x\n", dev, addr, data);
+	/* printk("i2c_write: [0x%x,0x%x] = 0x%x\n", dev, addr, data); */
 	outb(addr, ICEREG1724(ice, I2C_BYTE_ADDR));
 	outb(data, ICEREG1724(ice, I2C_DATA));
 	outb(dev | VT1724_I2C_WRITE, ICEREG1724(ice, I2C_DEV_ADDR));
@@ -2144,13 +2144,13 @@
 	unsigned int i, size;
 	struct snd_ice1712_card_info * const *tbl, *c;
 
-	if (! modelname || ! *modelname) {
+	if (!modelname || !*modelname) {
 		ice->eeprom.subvendor = 0;
 		if ((inb(ICEREG1724(ice, I2C_CTRL)) & VT1724_I2C_EEPROM) != 0)
 			ice->eeprom.subvendor =
 				(snd_vt1724_read_i2c(ice, dev, 0x00) << 0) |
-				(snd_vt1724_read_i2c(ice, dev, 0x01) << 8) | 
-				(snd_vt1724_read_i2c(ice, dev, 0x02) << 16) | 
+				(snd_vt1724_read_i2c(ice, dev, 0x01) << 8) |
+				(snd_vt1724_read_i2c(ice, dev, 0x02) << 16) |
 				(snd_vt1724_read_i2c(ice, dev, 0x03) << 24);
 		if (ice->eeprom.subvendor == 0 ||
 		    ice->eeprom.subvendor == (unsigned int)-1) {
@@ -2173,13 +2173,13 @@
 	for (tbl = card_tables; *tbl; tbl++) {
 		for (c = *tbl; c->subvendor; c++) {
 			if (modelname && c->model &&
-			    ! strcmp(modelname, c->model)) {
+			    !strcmp(modelname, c->model)) {
 				printk(KERN_INFO "ice1724: Using board model %s\n",
 				       c->name);
 				ice->eeprom.subvendor = c->subvendor;
 			} else if (c->subvendor != ice->eeprom.subvendor)
 				continue;
-			if (! c->eeprom_size || ! c->eeprom_data)
+			if (!c->eeprom_size || !c->eeprom_data)
 				goto found;
 			/* if the EEPROM is given by the driver, use it */
 			snd_printdd("using the defined eeprom..\n");
@@ -2250,7 +2250,8 @@
 	int err;
 	struct snd_kcontrol *kctl;
 
-	snd_assert(ice->pcm != NULL, return -EIO);
+	if (snd_BUG_ON(!ice->pcm))
+		return -EIO;
 
 	err = snd_ctl_add(ice->card, snd_ctl_new1(&snd_vt1724_mixer_pro_spdif_route, ice));
 	if (err < 0)
@@ -2320,13 +2321,13 @@
 
 static int snd_vt1724_free(struct snd_ice1712 *ice)
 {
-	if (! ice->port)
+	if (!ice->port)
 		goto __hw_end;
 	/* mask all interrupts */
 	outb(0xff, ICEMT1724(ice, DMA_INT_MASK));
 	outb(0xff, ICEREG1724(ice, IRQMASK));
 	/* --- */
-      __hw_end:
+__hw_end:
 	if (ice->irq >= 0)
 		free_irq(ice->irq, ice);
 	pci_release_regions(ice->pci);
@@ -2346,7 +2347,7 @@
 static int __devinit snd_vt1724_create(struct snd_card *card,
 				       struct pci_dev *pci,
 				       const char *modelname,
-				       struct snd_ice1712 ** r_ice1712)
+				       struct snd_ice1712 **r_ice1712)
 {
 	struct snd_ice1712 *ice;
 	int err;
@@ -2357,8 +2358,9 @@
 
 	*r_ice1712 = NULL;
 
-        /* enable PCI device */
-	if ((err = pci_enable_device(pci)) < 0)
+	/* enable PCI device */
+	err = pci_enable_device(pci);
+	if (err < 0)
 		return err;
 
 	ice = kzalloc(sizeof(*ice), GFP_KERNEL);
@@ -2382,7 +2384,8 @@
 	snd_vt1724_proc_init(ice);
 	synchronize_irq(pci->irq);
 
-	if ((err = pci_request_regions(pci, "ICE1724")) < 0) {
+	err = pci_request_regions(pci, "ICE1724");
+	if (err < 0) {
 		kfree(ice);
 		pci_disable_device(pci);
 		return err;
@@ -2417,9 +2420,10 @@
 	 */
 	outb(VT1724_MULTI_FIFO_ERR, ICEMT1724(ice, DMA_INT_MASK));
 
-	if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, ice, &ops)) < 0) {
+	err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, ice, &ops);
+	if (err < 0) {
 		snd_vt1724_free(ice);
- 		return err;
+		return err;
 	}
 
 	snd_card_set_dev(card, &pci->dev);
@@ -2457,8 +2461,9 @@
 
 	strcpy(card->driver, "ICE1724");
 	strcpy(card->shortname, "ICEnsemble ICE1724");
-	
-	if ((err = snd_vt1724_create(card, pci, model[dev], &ice)) < 0) {
+
+	err = snd_vt1724_create(card, pci, model[dev], &ice);
+	if (err < 0) {
 		snd_card_free(card);
 		return err;
 	}
@@ -2470,7 +2475,8 @@
 				if (c->driver) /* specific driver? */
 					strcpy(card->driver, c->driver);
 				if (c->chip_init) {
-					if ((err = c->chip_init(ice)) < 0) {
+					err = c->chip_init(ice);
+					if (err < 0) {
 						snd_card_free(card);
 						return err;
 					}
@@ -2480,15 +2486,15 @@
 		}
 	}
 	c = &no_matched;
- __found:
-       /*
-        * VT1724 has separate DMAs for the analog and the SPDIF streams while
-        * ICE1712 has only one for both (mixed up).
-        *
-        * Confusingly the analog PCM is named "professional" here because it
-        * was called so in ice1712 driver, and vt1724 driver is derived from
-        * ice1712 driver.
-        */
+__found:
+	/*
+	* VT1724 has separate DMAs for the analog and the SPDIF streams while
+	* ICE1712 has only one for both (mixed up).
+	*
+	* Confusingly the analog PCM is named "professional" here because it
+	* was called so in ice1712 driver, and vt1724 driver is derived from
+	* ice1712 driver.
+	*/
 	ice->pro_rate_default = PRO_RATE_DEFAULT;
 	if (!ice->is_spdif_master)
 		ice->is_spdif_master = stdclock_is_spdif_master;
@@ -2503,46 +2509,53 @@
 	if (!ice->hw_rates)
 		set_std_hw_rates(ice);
 
-	if ((err = snd_vt1724_pcm_profi(ice, pcm_dev++)) < 0) {
-		snd_card_free(card);
-		return err;
-	}
-	
-	if ((err = snd_vt1724_pcm_spdif(ice, pcm_dev++)) < 0) {
-		snd_card_free(card);
-		return err;
-	}
-	
-	if ((err = snd_vt1724_pcm_indep(ice, pcm_dev++)) < 0) {
+	err = snd_vt1724_pcm_profi(ice, pcm_dev++);
+	if (err < 0) {
 		snd_card_free(card);
 		return err;
 	}
 
-	if ((err = snd_vt1724_ac97_mixer(ice)) < 0) {
+	err = snd_vt1724_pcm_spdif(ice, pcm_dev++);
+	if (err < 0) {
 		snd_card_free(card);
 		return err;
 	}
 
-	if ((err = snd_vt1724_build_controls(ice)) < 0) {
+	err = snd_vt1724_pcm_indep(ice, pcm_dev++);
+	if (err < 0) {
+		snd_card_free(card);
+		return err;
+	}
+
+	err = snd_vt1724_ac97_mixer(ice);
+	if (err < 0) {
+		snd_card_free(card);
+		return err;
+	}
+
+	err = snd_vt1724_build_controls(ice);
+	if (err < 0) {
 		snd_card_free(card);
 		return err;
 	}
 
 	if (ice->pcm && ice->has_spdif) { /* has SPDIF I/O */
-		if ((err = snd_vt1724_spdif_build_controls(ice)) < 0) {
+		err = snd_vt1724_spdif_build_controls(ice);
+		if (err < 0) {
 			snd_card_free(card);
 			return err;
 		}
 	}
 
 	if (c->build_controls) {
-		if ((err = c->build_controls(ice)) < 0) {
+		err = c->build_controls(ice);
+		if (err < 0) {
 			snd_card_free(card);
 			return err;
 		}
 	}
 
-	if (! c->no_mpu401) {
+	if (!c->no_mpu401) {
 		if (ice->eeprom.data[ICE_EEP2_SYSCONF] & VT1724_CFG_MPU401) {
 			struct snd_rawmidi *rmidi;
 
@@ -2574,7 +2587,8 @@
 	sprintf(card->longname, "%s at 0x%lx, irq %i",
 		card->shortname, ice->port, ice->irq);
 
-	if ((err = snd_card_register(card)) < 0) {
+	err = snd_card_register(card);
+	if (err < 0) {
 		snd_card_free(card);
 		return err;
 	}
diff --git a/sound/pci/ice1712/juli.c b/sound/pci/ice1712/juli.c
index b4e0c16..c51659b 100644
--- a/sound/pci/ice1712/juli.c
+++ b/sound/pci/ice1712/juli.c
@@ -21,7 +21,7 @@
  *   along with this program; if not, write to the Free Software
  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  *
- */      
+ */
 
 #include <asm/io.h>
 #include <linux/delay.h>
@@ -34,9 +34,10 @@
 #include "ice1712.h"
 #include "envy24ht.h"
 #include "juli.h"
+
 struct juli_spec {
 	struct ak4114 *ak4114;
-	unsigned int analog: 1;
+	unsigned int analog:1;
 };
 
 /*
@@ -160,14 +161,17 @@
 	return 0;
 }
 
-static void juli_ak4114_write(void *private_data, unsigned char reg, unsigned char val)
+static void juli_ak4114_write(void *private_data, unsigned char reg,
+				unsigned char val)
 {
-	snd_vt1724_write_i2c((struct snd_ice1712 *)private_data, AK4114_ADDR, reg, val);
+	snd_vt1724_write_i2c((struct snd_ice1712 *)private_data, AK4114_ADDR,
+				reg, val);
 }
-        
+
 static unsigned char juli_ak4114_read(void *private_data, unsigned char reg)
 {
-	return snd_vt1724_read_i2c((struct snd_ice1712 *)private_data, AK4114_ADDR, reg);
+	return snd_vt1724_read_i2c((struct snd_ice1712 *)private_data,
+					AK4114_ADDR, reg);
 }
 
 /*
@@ -175,7 +179,7 @@
  * to the external rate
  */
 static void juli_spdif_in_open(struct snd_ice1712 *ice,
-			       struct snd_pcm_substream *substream)
+				struct snd_pcm_substream *substream)
 {
 	struct juli_spec *spec = ice->spec;
 	struct snd_pcm_runtime *runtime = substream->runtime;
@@ -208,7 +212,8 @@
 {
 	struct snd_ice1712 *ice = ak->private_data[0];
 	 
-	snd_assert(chip == 0, return);
+	if (snd_BUG_ON(chip))
+		return;
 	snd_vt1724_write_i2c(ice, AK4358_ADDR, addr, data);
 }
 
@@ -571,10 +576,12 @@
 static int __devinit juli_init(struct snd_ice1712 *ice)
 {
 	static const unsigned char ak4114_init_vals[] = {
-		/* AK4117_REG_PWRDN */	AK4114_RST | AK4114_PWN | AK4114_OCKS0 | AK4114_OCKS1,
+		/* AK4117_REG_PWRDN */	AK4114_RST | AK4114_PWN |
+					AK4114_OCKS0 | AK4114_OCKS1,
 		/* AK4114_REQ_FORMAT */	AK4114_DIF_I24I2S,
 		/* AK4114_REG_IO0 */	AK4114_TX1E,
-		/* AK4114_REG_IO1 */	AK4114_EFH_1024 | AK4114_DIT | AK4114_IPS(1),
+		/* AK4114_REG_IO1 */	AK4114_EFH_1024 | AK4114_DIT |
+					AK4114_IPS(1),
 		/* AK4114_REG_INT0_MASK */ 0,
 		/* AK4114_REG_INT1_MASK */ 0
 	};
@@ -604,12 +611,14 @@
 	spec->ak4114->check_flags = 0;
 
 #if 0
-        /* it seems that the analog doughter board detection does not work
-           reliably, so force the analog flag; it should be very rare
-           to use Juli@ without the analog doughter board */
+/*
+ * it seems that the analog doughter board detection does not work reliably, so
+ * force the analog flag; it should be very rare (if ever) to come at Juli@
+ * used without the analog daughter board
+ */
 	spec->analog = (ice->gpio.get_data(ice) & GPIO_ANALOG_PRESENT) ? 0 : 1;
 #else
-        spec->analog = 1;
+	spec->analog = 1;
 #endif
 
 	if (spec->analog) {
@@ -617,14 +626,16 @@
 		ice->num_total_dacs = 2;
 		ice->num_total_adcs = 2;
 
-		ak = ice->akm = kzalloc(sizeof(struct snd_akm4xxx), GFP_KERNEL);
-		if (! ak)
+		ice->akm = kzalloc(sizeof(struct snd_akm4xxx), GFP_KERNEL);
+		ak = ice->akm;
+		if (!ak)
 			return -ENOMEM;
 		ice->akm_codecs = 1;
-		if ((err = snd_ice1712_akm4xxx_init(ak, &akm_juli_dac, NULL, ice)) < 0)
+		err = snd_ice1712_akm4xxx_init(ak, &akm_juli_dac, NULL, ice);
+		if (err < 0)
 			return err;
 	}
-	
+
 	/* juli is clocked by Xilinx array */
 	ice->hw_rates = &juli_rates_info;
 	ice->is_spdif_master = juli_is_spdif_master;
diff --git a/sound/pci/ice1712/phase.c b/sound/pci/ice1712/phase.c
index 5a158b7..de29be8 100644
--- a/sound/pci/ice1712/phase.c
+++ b/sound/pci/ice1712/phase.c
@@ -22,15 +22,24 @@
  */
 
 /* PHASE 22 overview:
- *   Audio controller: VIA Envy24HT-S (slightly trimmed down version of Envy24HT)
+ *   Audio controller: VIA Envy24HT-S (slightly trimmed down Envy24HT, 4in/4out)
  *   Analog chip: AK4524 (partially via Philip's 74HCT125)
- *   Digital receiver: CS8414-CS (not supported in this release)
+ *   Digital receiver: CS8414-CS (supported in this release)
+ *		PHASE 22 revision 2.0 and Terrasoniq/Musonik TS22PCI have CS8416
+ *		(support status unknown, please test and report)
  *
  *   Envy connects to AK4524
  *	- CS directly from GPIO 10
  *	- CCLK via 74HCT125's gate #4 from GPIO 4
  *	- CDTI via 74HCT125's gate #2 from GPIO 5
- *		CDTI may be completely blocked by 74HCT125's gate #1 controlled by GPIO 3
+ *		CDTI may be completely blocked by 74HCT125's gate #1
+ *		controlled by GPIO 3
+ */
+
+/* PHASE 28 overview:
+ *   Audio controller: VIA Envy24HT (full untrimmed version, 4in/8out)
+ *   Analog chip: WM8770 (8 channel 192k DAC, 2 channel 96k ADC)
+ *   Digital receiver: CS8414-CS (supported in this release)
  */
 
 #include <asm/io.h>
@@ -77,18 +86,18 @@
  * Computed as 20 * Log10(255 / x)
  */
 static const unsigned char wm_vol[256] = {
-	127, 48, 42, 39, 36, 34, 33, 31, 30, 29, 28, 27, 27, 26, 25, 25, 24, 24, 23,
-	23, 22, 22, 21, 21, 21, 20, 20, 20, 19, 19, 19, 18, 18, 18, 18, 17, 17, 17,
-	17, 16, 16, 16, 16, 15, 15, 15, 15, 15, 15, 14, 14, 14, 14, 14, 13, 13, 13,
-	13, 13, 13, 13, 12, 12, 12, 12, 12, 12, 12, 11, 11, 11, 11, 11, 11, 11, 11,
-	11, 10, 10, 10, 10, 10, 10, 10, 10, 10, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 8, 8,
-	8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6,
-	6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
-	5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3,
-	3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-	2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-	0, 0
+	127, 48, 42, 39, 36, 34, 33, 31, 30, 29, 28, 27, 27, 26, 25, 25, 24,
+	24, 23, 23, 22, 22, 21, 21, 21, 20, 20, 20, 19, 19, 19, 18, 18, 18, 18,
+	17, 17, 17, 17, 16, 16, 16, 16, 15, 15, 15, 15, 15, 15, 14, 14, 14, 14,
+	14, 13, 13, 13, 13, 13, 13, 13, 12, 12, 12, 12, 12, 12, 12, 11, 11, 11,
+	11, 11, 11, 11, 11, 11, 10, 10, 10, 10, 10, 10, 10, 10, 10, 9, 9, 9, 9,
+	9, 9, 9, 9, 9, 9, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7,
+	7, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5,
+	5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+	4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+	3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+	2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+	1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
 };
 
 #define WM_VOL_MAX	(sizeof(wm_vol) - 1)
@@ -117,26 +126,31 @@
 	struct snd_akm4xxx *ak;
 	int err;
 
-	// Configure DAC/ADC description for generic part of ice1724
+	/* Configure DAC/ADC description for generic part of ice1724 */
 	switch (ice->eeprom.subvendor) {
 	case VT1724_SUBDEVICE_PHASE22:
+	case VT1724_SUBDEVICE_TS22:
 		ice->num_total_dacs = 2;
 		ice->num_total_adcs = 2;
-		ice->vt1720 = 1; // Envy24HT-S have 16 bit wide GPIO
+		ice->vt1720 = 1; /* Envy24HT-S have 16 bit wide GPIO */
 		break;
 	default:
 		snd_BUG();
 		return -EINVAL;
 	}
 
-	// Initialize analog chips
-	ak = ice->akm = kzalloc(sizeof(struct snd_akm4xxx), GFP_KERNEL);
-	if (! ak)
+	/* Initialize analog chips */
+	ice->akm = kzalloc(sizeof(struct snd_akm4xxx), GFP_KERNEL);
+	ak = ice->akm;
+	if (!ak)
 		return -ENOMEM;
 	ice->akm_codecs = 1;
 	switch (ice->eeprom.subvendor) {
 	case VT1724_SUBDEVICE_PHASE22:
-		if ((err = snd_ice1712_akm4xxx_init(ak, &akm_phase22, &akm_phase22_priv, ice)) < 0)
+	case VT1724_SUBDEVICE_TS22:
+		err = snd_ice1712_akm4xxx_init(ak, &akm_phase22,
+						&akm_phase22_priv, ice);
+		if (err < 0)
 			return err;
 		break;
 	}
@@ -150,6 +164,7 @@
 
 	switch (ice->eeprom.subvendor) {
 	case VT1724_SUBDEVICE_PHASE22:
+	case VT1724_SUBDEVICE_TS22:
 		err = snd_ice1712_akm4xxx_build_controls(ice);
 		if (err < 0)
 			return err;
@@ -158,9 +173,10 @@
 }
 
 static unsigned char phase22_eeprom[] __devinitdata = {
-	[ICE_EEP2_SYSCONF]     = 0x00,	/* 1xADC, 1xDACs */
+	[ICE_EEP2_SYSCONF]     = 0x28,  /* clock 512, mpu 401,
+					spdif-in/1xADC, 1xDACs */
 	[ICE_EEP2_ACLINK]      = 0x80,	/* I2S */
-	[ICE_EEP2_I2S]         = 0xf8,	/* vol, 96k, 24bit */
+	[ICE_EEP2_I2S]         = 0xf0,	/* vol, 96k, 24bit */
 	[ICE_EEP2_SPDIF]       = 0xc3,	/* out-en, out-int, spdif-in */
 	[ICE_EEP2_GPIO_DIR]    = 0xff,
 	[ICE_EEP2_GPIO_DIR1]   = 0xff,
@@ -174,7 +190,8 @@
 };
 
 static unsigned char phase28_eeprom[] __devinitdata = {
-	[ICE_EEP2_SYSCONF]     = 0x0b,	/* clock 512, spdif-in/ADC, 4DACs */
+	[ICE_EEP2_SYSCONF]     = 0x2b,  /* clock 512, mpu401,
+					spdif-in/1xADC, 4xDACs */
 	[ICE_EEP2_ACLINK]      = 0x80,	/* I2S */
 	[ICE_EEP2_I2S]         = 0xfc,	/* vol, 96k, 24bit, 192k */
 	[ICE_EEP2_SPDIF]       = 0xc3,	/* out-en, out-int, spdif-in */
@@ -192,15 +209,16 @@
 /*
  * write data in the SPI mode
  */
-static void phase28_spi_write(struct snd_ice1712 *ice, unsigned int cs, unsigned int data, int bits)
+static void phase28_spi_write(struct snd_ice1712 *ice, unsigned int cs,
+				unsigned int data, int bits)
 {
 	unsigned int tmp;
 	int i;
 
 	tmp = snd_ice1712_gpio_read(ice);
 
-	snd_ice1712_gpio_set_mask(ice, ~(PHASE28_WM_RW|PHASE28_SPI_MOSI|PHASE28_SPI_CLK|
-					 PHASE28_WM_CS));
+	snd_ice1712_gpio_set_mask(ice, ~(PHASE28_WM_RW|PHASE28_SPI_MOSI|
+					PHASE28_SPI_CLK|PHASE28_WM_CS));
 	tmp |= PHASE28_WM_RW;
 	tmp &= ~cs;
 	snd_ice1712_gpio_write(ice, tmp);
@@ -259,14 +277,16 @@
 	ice->akm[0].images[reg + 1] = val;
 }
 
-static void wm_set_vol(struct snd_ice1712 *ice, unsigned int index, unsigned short vol, unsigned short master)
+static void wm_set_vol(struct snd_ice1712 *ice, unsigned int index,
+			unsigned short vol, unsigned short master)
 {
 	unsigned char nvol;
 
 	if ((master & WM_VOL_MUTE) || (vol & WM_VOL_MUTE))
 		nvol = 0;
 	else
-		nvol = 127 - wm_vol[(((vol & ~WM_VOL_MUTE) * (master & ~WM_VOL_MUTE)) / 127) & WM_VOL_MAX];
+		nvol = 127 - wm_vol[(((vol & ~WM_VOL_MUTE) *
+			(master & ~WM_VOL_MUTE)) / 127) & WM_VOL_MAX];
 
 	wm_put(ice, index, nvol);
 	wm_put_nocache(ice, index, 0x180 | nvol);
@@ -277,17 +297,20 @@
  */
 #define wm_pcm_mute_info	snd_ctl_boolean_mono_info
 
-static int wm_pcm_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+static int wm_pcm_mute_get(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
 {
 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
 
 	mutex_lock(&ice->gpio_mutex);
-	ucontrol->value.integer.value[0] = (wm_get(ice, WM_MUTE) & 0x10) ? 0 : 1;
+	ucontrol->value.integer.value[0] = (wm_get(ice, WM_MUTE) & 0x10) ?
+						0 : 1;
 	mutex_unlock(&ice->gpio_mutex);
 	return 0;
 }
 
-static int wm_pcm_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+static int wm_pcm_mute_put(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
 {
 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
 	unsigned short nval, oval;
@@ -296,7 +319,8 @@
 	snd_ice1712_save_gpio_status(ice);
 	oval = wm_get(ice, WM_MUTE);
 	nval = (oval & ~0x10) | (ucontrol->value.integer.value[0] ? 0 : 0x10);
-	if ((change = (nval != oval)))
+	change = (nval != oval);
+	if (change)
 		wm_put(ice, WM_MUTE, nval);
 	snd_ice1712_restore_gpio_status(ice);
 
@@ -306,7 +330,8 @@
 /*
  * Master volume attenuation mixer control
  */
-static int wm_master_vol_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
+static int wm_master_vol_info(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_info *uinfo)
 {
 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
 	uinfo->count = 2;
@@ -315,17 +340,20 @@
 	return 0;
 }
 
-static int wm_master_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+static int wm_master_vol_get(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
 {
 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
 	struct phase28_spec *spec = ice->spec;
 	int i;
-	for (i=0; i<2; i++)
-		ucontrol->value.integer.value[i] = spec->master[i] & ~WM_VOL_MUTE;
+	for (i = 0; i < 2; i++)
+		ucontrol->value.integer.value[i] = spec->master[i] &
+							~WM_VOL_MUTE;
 	return 0;
 }
 
-static int wm_master_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+static int wm_master_vol_put(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
 {
 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
 	struct phase28_spec *spec = ice->spec;
@@ -355,38 +383,38 @@
 {
 	static const unsigned short wm_inits_phase28[] = {
 		/* These come first to reduce init pop noise */
-		0x1b, 0x044,		/* ADC Mux (AC'97 source) */
-		0x1c, 0x00B,		/* Out Mux1 (VOUT1 = DAC+AUX, VOUT2 = DAC) */
-		0x1d, 0x009,		/* Out Mux2 (VOUT2 = DAC, VOUT3 = DAC) */
+		0x1b, 0x044,	/* ADC Mux (AC'97 source) */
+		0x1c, 0x00B,	/* Out Mux1 (VOUT1 = DAC+AUX, VOUT2 = DAC) */
+		0x1d, 0x009,	/* Out Mux2 (VOUT2 = DAC, VOUT3 = DAC) */
 
-		0x18, 0x000,		/* All power-up */
+		0x18, 0x000,	/* All power-up */
 
-		0x16, 0x122,		/* I2S, normal polarity, 24bit */
-		0x17, 0x022,		/* 256fs, slave mode */
-		0x00, 0,		/* DAC1 analog mute */
-		0x01, 0,		/* DAC2 analog mute */
-		0x02, 0,		/* DAC3 analog mute */
-		0x03, 0,		/* DAC4 analog mute */
-		0x04, 0,		/* DAC5 analog mute */
-		0x05, 0,		/* DAC6 analog mute */
-		0x06, 0,		/* DAC7 analog mute */
-		0x07, 0,		/* DAC8 analog mute */
-		0x08, 0x100,		/* master analog mute */
-		0x09, 0xff,		/* DAC1 digital full */
-		0x0a, 0xff,		/* DAC2 digital full */
-		0x0b, 0xff,		/* DAC3 digital full */
-		0x0c, 0xff,		/* DAC4 digital full */
-		0x0d, 0xff,		/* DAC5 digital full */
-		0x0e, 0xff,		/* DAC6 digital full */
-		0x0f, 0xff,		/* DAC7 digital full */
-		0x10, 0xff,		/* DAC8 digital full */
-		0x11, 0x1ff,		/* master digital full */
-		0x12, 0x000,		/* phase normal */
-		0x13, 0x090,		/* unmute DAC L/R */
-		0x14, 0x000,		/* all unmute */
-		0x15, 0x000,		/* no deemphasis, no ZFLG */
-		0x19, 0x000,		/* -12dB ADC/L */
-		0x1a, 0x000,		/* -12dB ADC/R */
+		0x16, 0x122,	/* I2S, normal polarity, 24bit */
+		0x17, 0x022,	/* 256fs, slave mode */
+		0x00, 0,	/* DAC1 analog mute */
+		0x01, 0,	/* DAC2 analog mute */
+		0x02, 0,	/* DAC3 analog mute */
+		0x03, 0,	/* DAC4 analog mute */
+		0x04, 0,	/* DAC5 analog mute */
+		0x05, 0,	/* DAC6 analog mute */
+		0x06, 0,	/* DAC7 analog mute */
+		0x07, 0,	/* DAC8 analog mute */
+		0x08, 0x100,	/* master analog mute */
+		0x09, 0xff,	/* DAC1 digital full */
+		0x0a, 0xff,	/* DAC2 digital full */
+		0x0b, 0xff,	/* DAC3 digital full */
+		0x0c, 0xff,	/* DAC4 digital full */
+		0x0d, 0xff,	/* DAC5 digital full */
+		0x0e, 0xff,	/* DAC6 digital full */
+		0x0f, 0xff,	/* DAC7 digital full */
+		0x10, 0xff,	/* DAC8 digital full */
+		0x11, 0x1ff,	/* master digital full */
+		0x12, 0x000,	/* phase normal */
+		0x13, 0x090,	/* unmute DAC L/R */
+		0x14, 0x000,	/* all unmute */
+		0x15, 0x000,	/* no deemphasis, no ZFLG */
+		0x19, 0x000,	/* -12dB ADC/L */
+		0x1a, 0x000,	/* -12dB ADC/R */
 		(unsigned short)-1
 	};
 
@@ -404,17 +432,19 @@
 		return -ENOMEM;
 	ice->spec = spec;
 
-	// Initialize analog chips
-	ak = ice->akm = kzalloc(sizeof(struct snd_akm4xxx), GFP_KERNEL);
+	/* Initialize analog chips */
+	ice->akm = kzalloc(sizeof(struct snd_akm4xxx), GFP_KERNEL);
+	ak = ice->akm;
 	if (!ak)
 		return -ENOMEM;
 	ice->akm_codecs = 1;
 
-	snd_ice1712_gpio_set_dir(ice, 0x5fffff); /* fix this for the time being */
+	snd_ice1712_gpio_set_dir(ice, 0x5fffff); /* fix this for time being */
 
 	/* reset the wm codec as the SPI mode */
 	snd_ice1712_save_gpio_status(ice);
-	snd_ice1712_gpio_set_mask(ice, ~(PHASE28_WM_RESET|PHASE28_WM_CS|PHASE28_HP_SEL));
+	snd_ice1712_gpio_set_mask(ice, ~(PHASE28_WM_RESET|PHASE28_WM_CS|
+					PHASE28_HP_SEL));
 
 	tmp = snd_ice1712_gpio_read(ice);
 	tmp &= ~PHASE28_WM_RESET;
@@ -446,7 +476,8 @@
 /*
  * DAC volume attenuation mixer control
  */
-static int wm_vol_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
+static int wm_vol_info(struct snd_kcontrol *kcontrol,
+			struct snd_ctl_elem_info *uinfo)
 {
 	int voices = kcontrol->private_value >> 8;
 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
@@ -456,7 +487,8 @@
 	return 0;
 }
 
-static int wm_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+static int wm_vol_get(struct snd_kcontrol *kcontrol,
+			struct snd_ctl_elem_value *ucontrol)
 {
 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
 	struct phase28_spec *spec = ice->spec;
@@ -470,7 +502,8 @@
 	return 0;
 }
 
-static int wm_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+static int wm_vol_put(struct snd_kcontrol *kcontrol,
+			struct snd_ctl_elem_value *ucontrol)
 {
 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
 	struct phase28_spec *spec = ice->spec;
@@ -501,7 +534,8 @@
 /*
  * WM8770 mute control
  */
-static int wm_mute_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) {
+static int wm_mute_info(struct snd_kcontrol *kcontrol,
+			struct snd_ctl_elem_info *uinfo) {
 	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
 	uinfo->count = kcontrol->private_value >> 8;
 	uinfo->value.integer.min = 0;
@@ -509,7 +543,8 @@
 	return 0;
 }
 
-static int wm_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+static int wm_mute_get(struct snd_kcontrol *kcontrol,
+			struct snd_ctl_elem_value *ucontrol)
 {
 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
 	struct phase28_spec *spec = ice->spec;
@@ -524,7 +559,8 @@
 	return 0;
 }
 
-static int wm_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+static int wm_mute_put(struct snd_kcontrol *kcontrol,
+			struct snd_ctl_elem_value *ucontrol)
 {
 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
 	struct phase28_spec *spec = ice->spec;
@@ -539,9 +575,10 @@
 		if (ucontrol->value.integer.value[i] != val) {
 			spec->vol[ofs + i] &= ~WM_VOL_MUTE;
 			spec->vol[ofs + i] |=
-				ucontrol->value.integer.value[i] ? 0 : WM_VOL_MUTE;
+				ucontrol->value.integer.value[i] ? 0 :
+				WM_VOL_MUTE;
 			wm_set_vol(ice, ofs + i, spec->vol[ofs + i],
-				   spec->master[i]);
+					spec->master[i]);
 			change = 1;
 		}
 	}
@@ -555,7 +592,8 @@
  */
 #define wm_master_mute_info		snd_ctl_boolean_stereo_info
 
-static int wm_master_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+static int wm_master_mute_get(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
 {
 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
 	struct phase28_spec *spec = ice->spec;
@@ -567,7 +605,8 @@
 	return 0;
 }
 
-static int wm_master_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+static int wm_master_mute_put(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
 {
 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
 	struct phase28_spec *spec = ice->spec;
@@ -580,11 +619,12 @@
 			int dac;
 			spec->master[i] &= ~WM_VOL_MUTE;
 			spec->master[i] |=
-				ucontrol->value.integer.value[i] ? 0 : WM_VOL_MUTE;
+				ucontrol->value.integer.value[i] ? 0 :
+				WM_VOL_MUTE;
 			for (dac = 0; dac < ice->num_total_dacs; dac += 2)
 				wm_set_vol(ice, WM_DAC_ATTEN + dac + i,
-					   spec->vol[dac + i],
-					   spec->master[i]);
+						spec->vol[dac + i],
+						spec->master[i]);
 			change = 1;
 		}
 	}
@@ -597,7 +637,8 @@
 #define PCM_0dB 0xff
 #define PCM_RES 128	/* -64dB */
 #define PCM_MIN (PCM_0dB - PCM_RES)
-static int wm_pcm_vol_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
+static int wm_pcm_vol_info(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_info *uinfo)
 {
 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
 	uinfo->count = 1;
@@ -606,7 +647,8 @@
 	return 0;
 }
 
-static int wm_pcm_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+static int wm_pcm_vol_get(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
 {
 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
 	unsigned short val;
@@ -619,7 +661,8 @@
 	return 0;
 }
 
-static int wm_pcm_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+static int wm_pcm_vol_put(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
 {
 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
 	unsigned short ovol, nvol;
@@ -633,7 +676,8 @@
 	ovol = wm_get(ice, WM_DAC_DIG_MASTER_ATTEN) & 0xff;
 	if (ovol != nvol) {
 		wm_put(ice, WM_DAC_DIG_MASTER_ATTEN, nvol); /* prelatch */
-		wm_put_nocache(ice, WM_DAC_DIG_MASTER_ATTEN, nvol | 0x100); /* update */
+		/* update */
+		wm_put_nocache(ice, WM_DAC_DIG_MASTER_ATTEN, nvol | 0x100);
 		change = 1;
 	}
 	snd_ice1712_restore_gpio_status(ice);
@@ -645,18 +689,22 @@
  */
 #define phase28_deemp_info	snd_ctl_boolean_mono_info
 
-static int phase28_deemp_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+static int phase28_deemp_get(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
 {
 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
-	ucontrol->value.integer.value[0] = (wm_get(ice, WM_DAC_CTRL2) & 0xf) == 0xf;
+	ucontrol->value.integer.value[0] = (wm_get(ice, WM_DAC_CTRL2) & 0xf) ==
+						0xf;
 	return 0;
 }
 
-static int phase28_deemp_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+static int phase28_deemp_put(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
 {
 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
 	int temp, temp2;
-	temp2 = temp = wm_get(ice, WM_DAC_CTRL2);
+	temp = wm_get(ice, WM_DAC_CTRL2);
+	temp2 = temp;
 	if (ucontrol->value.integer.value[0])
 		temp |= 0xf;
 	else
@@ -671,7 +719,8 @@
 /*
  * ADC Oversampling
  */
-static int phase28_oversampling_info(struct snd_kcontrol *k, struct snd_ctl_elem_info *uinfo)
+static int phase28_oversampling_info(struct snd_kcontrol *k,
+					struct snd_ctl_elem_info *uinfo)
 {
 	static char *texts[2] = { "128x", "64x"	};
 
@@ -680,25 +729,31 @@
 	uinfo->value.enumerated.items = 2;
 
 	if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
-		uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
-	strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
+		uinfo->value.enumerated.item = uinfo->value.enumerated.items -
+						1;
+	strcpy(uinfo->value.enumerated.name,
+		texts[uinfo->value.enumerated.item]);
 
-        return 0;
-}
-
-static int phase28_oversampling_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
-{
-	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
-	ucontrol->value.enumerated.item[0] = (wm_get(ice, WM_MASTER) & 0x8) == 0x8;
 	return 0;
 }
 
-static int phase28_oversampling_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+static int phase28_oversampling_get(struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
+	ucontrol->value.enumerated.item[0] = (wm_get(ice, WM_MASTER) & 0x8) ==
+						0x8;
+	return 0;
+}
+
+static int phase28_oversampling_put(struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_value *ucontrol)
 {
 	int temp, temp2;
 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
 
-	temp2 = temp = wm_get(ice, WM_MASTER);
+	temp = wm_get(ice, WM_MASTER);
+	temp2 = temp;
 
 	if (ucontrol->value.enumerated.item[0])
 		temp |= 0x8;
@@ -871,13 +926,16 @@
 
 	counts = ARRAY_SIZE(phase28_dac_controls);
 	for (i = 0; i < counts; i++) {
-		err = snd_ctl_add(ice->card, snd_ctl_new1(&phase28_dac_controls[i], ice));
+		err = snd_ctl_add(ice->card,
+					snd_ctl_new1(&phase28_dac_controls[i],
+							ice));
 		if (err < 0)
 			return err;
 	}
 
 	for (i = 0; i < ARRAY_SIZE(wm_controls); i++) {
-		err = snd_ctl_add(ice->card, snd_ctl_new1(&wm_controls[i], ice));
+		err = snd_ctl_add(ice->card,
+					snd_ctl_new1(&wm_controls[i], ice));
 		if (err < 0)
 			return err;
 	}
@@ -904,5 +962,14 @@
 		.eeprom_size = sizeof(phase28_eeprom),
 		.eeprom_data = phase28_eeprom,
 	},
+	{
+		.subvendor = VT1724_SUBDEVICE_TS22,
+		.name = "Terrasoniq TS22 PCI",
+		.model = "TS22",
+		.chip_init = phase22_init,
+		.build_controls = phase22_add_controls,
+		.eeprom_size = sizeof(phase22_eeprom),
+		.eeprom_data = phase22_eeprom,
+	},
 	{ } /* terminator */
 };
diff --git a/sound/pci/ice1712/phase.h b/sound/pci/ice1712/phase.h
index 13e841b..7fc22d9 100644
--- a/sound/pci/ice1712/phase.h
+++ b/sound/pci/ice1712/phase.h
@@ -22,13 +22,15 @@
  *   along with this program; if not, write to the Free Software
  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  *
- */      
+ */
 
-#define PHASE_DEVICE_DESC "{Terratec,Phase 22},"\
-                          "{Terratec,Phase 28},"
+#define PHASE_DEVICE_DESC	"{Terratec,Phase 22},"\
+				"{Terratec,Phase 28},"\
+				"{Terrasoniq,TS22},"
 
 #define VT1724_SUBDEVICE_PHASE22	0x3b155011
 #define VT1724_SUBDEVICE_PHASE28	0x3b154911
+#define VT1724_SUBDEVICE_TS22		0x3b157b11
 
 /* entry point */
 extern struct snd_ice1712_card_info snd_vt1724_phase_cards[];
diff --git a/sound/pci/ice1712/pontis.c b/sound/pci/ice1712/pontis.c
index 203cdc1bf..6bc3f91 100644
--- a/sound/pci/ice1712/pontis.c
+++ b/sound/pci/ice1712/pontis.c
@@ -43,7 +43,8 @@
 /* WM8776 registers */
 #define WM_HP_ATTEN_L		0x00	/* headphone left attenuation */
 #define WM_HP_ATTEN_R		0x01	/* headphone left attenuation */
-#define WM_HP_MASTER		0x02	/* headphone master (both channels), override LLR */
+#define WM_HP_MASTER		0x02	/* headphone master (both channels) */
+					/* override LLR */
 #define WM_DAC_ATTEN_L		0x03	/* digital left attenuation */
 #define WM_DAC_ATTEN_R		0x04
 #define WM_DAC_MASTER		0x05
@@ -740,7 +741,7 @@
 		WM_DAC_ATTEN_L,	0x0100,	/* DAC 0dB */
 		WM_DAC_ATTEN_R,	0x0000,	/* DAC 0dB */
 		WM_DAC_ATTEN_R,	0x0100,	/* DAC 0dB */
-		// WM_DAC_MASTER,	0x0100,	/* DAC master muted */
+		/* WM_DAC_MASTER,	0x0100, */	/* DAC master muted */
 		WM_PHASE_SWAP,	0x0000,	/* phase normal */
 		WM_DAC_CTRL2,	0x0000,	/* no deemphasis, no ZFLG */
 		WM_ADC_ATTEN_L,	0x0000,	/* ADC muted */
diff --git a/sound/pci/ice1712/revo.c b/sound/pci/ice1712/revo.c
index 4d26314..b508bb3 100644
--- a/sound/pci/ice1712/revo.c
+++ b/sound/pci/ice1712/revo.c
@@ -1,7 +1,7 @@
 /*
  *   ALSA driver for ICEnsemble ICE1712 (Envy24)
  *
- *   Lowlevel functions for M-Audio Revolution 7.1
+ *   Lowlevel functions for M-Audio Audiophile 192, Revolution 7.1 and 5.1
  *
  *	Copyright (c) 2003 Takashi Iwai <tiwai@suse.de>
  *
@@ -48,7 +48,7 @@
 }
 
 /*
- * change the rate of envy24HT, AK4355 and AK4381
+ * change the rate of Envy24HT, AK4355 and AK4381
  */
 static void revo_set_rate_val(struct snd_akm4xxx *ak, unsigned int rate)
 {
@@ -83,8 +83,8 @@
 	tmp = snd_akm4xxx_get(ak, 0, reg);
 	tmp &= ~(0x03 << shift);
 	tmp |= dfs << shift;
-	// snd_akm4xxx_write(ak, 0, reg, tmp);
-	snd_akm4xxx_set(ak, 0, reg, tmp); /* the value is written in reset(0) */
+	/* snd_akm4xxx_write(ak, 0, reg, tmp); */
+	snd_akm4xxx_set(ak, 0, reg, tmp); /* value is written in reset(0) */
 	snd_akm4xxx_reset(ak, 0);
 }
 
@@ -216,6 +216,7 @@
 	AK_DAC("PCM Center Playback Volume", 1),
 	AK_DAC("PCM LFE Playback Volume", 1),
 	AK_DAC("PCM Rear Playback Volume", 2),
+	AK_DAC("PCM Headphone Volume", 2),
 };
 
 static const char *revo51_adc_input_names[] = {
@@ -279,7 +280,7 @@
 
 static struct snd_akm4xxx akm_revo51 __devinitdata = {
 	.type = SND_AK4358,
-	.num_dacs = 6,
+	.num_dacs = 8,
 	.ops = {
 		.set_rate_val = revo_set_rate_val
 	},
@@ -508,7 +509,7 @@
 		ice->gpio.i2s_mclk_changed = revo_i2s_mclk_changed;
 		break;
 	case VT1724_SUBDEVICE_REVOLUTION51:
-		ice->num_total_dacs = 6;
+		ice->num_total_dacs = 8;
 		ice->num_total_adcs = 2;
 		break;
 	case VT1724_SUBDEVICE_AUDIOPHILE192:
@@ -524,16 +525,20 @@
 	ak = ice->akm = kcalloc(2, sizeof(struct snd_akm4xxx), GFP_KERNEL);
 	if (! ak)
 		return -ENOMEM;
-	ice->akm_codecs = 2;
 	switch (ice->eeprom.subvendor) {
 	case VT1724_SUBDEVICE_REVOLUTION71:
 		ice->akm_codecs = 2;
-		if ((err = snd_ice1712_akm4xxx_init(ak, &akm_revo_front, &akm_revo_front_priv, ice)) < 0)
+		err = snd_ice1712_akm4xxx_init(ak, &akm_revo_front,
+						&akm_revo_front_priv, ice);
+		if (err < 0)
 			return err;
-		if ((err = snd_ice1712_akm4xxx_init(ak + 1, &akm_revo_surround, &akm_revo_surround_priv, ice)) < 0)
+		err = snd_ice1712_akm4xxx_init(ak+1, &akm_revo_surround,
+						&akm_revo_surround_priv, ice);
+		if (err < 0)
 			return err;
 		/* unmute all codecs */
-		snd_ice1712_gpio_write_bits(ice, VT1724_REVO_MUTE, VT1724_REVO_MUTE);
+		snd_ice1712_gpio_write_bits(ice, VT1724_REVO_MUTE,
+						VT1724_REVO_MUTE);
 		break;
 	case VT1724_SUBDEVICE_REVOLUTION51:
 		ice->akm_codecs = 2;
diff --git a/sound/pci/ice1712/wtm.c b/sound/pci/ice1712/wtm.c
index a08d17c..5af9e84 100644
--- a/sound/pci/ice1712/wtm.c
+++ b/sound/pci/ice1712/wtm.c
@@ -1,12 +1,12 @@
 /*
  *	ALSA driver for ICEnsemble VT1724 (Envy24HT)
- *	
+ *
  *	Lowlevel functions for Ego Sys Waveterminal 192M
  *
  *		Copyright (c) 2006 Guedez Clement <klem.dev@gmail.com>
  *		Some functions are taken from the Prodigy192 driver
  *		source
- *		
+ *
  *	This program is free software; you can redistribute it and/or 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
@@ -20,12 +20,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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *	
- */	
+ *
+ */
 
 
 
-#include <asm/io.h>
+#include <linux/io.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
 #include <linux/init.h>
@@ -39,9 +39,9 @@
 
 
 /*
- *	2*ADC 6*DAC no1 ringbuffer r/w on i2c bus 
+ *	2*ADC 6*DAC no1 ringbuffer r/w on i2c bus
  */
-static inline void stac9460_put(struct snd_ice1712 *ice, int reg, 
+static inline void stac9460_put(struct snd_ice1712 *ice, int reg,
 						unsigned char val)
 {
 	snd_vt1724_write_i2c(ice, STAC9460_I2C_ADDR, reg, val);
@@ -73,7 +73,7 @@
 #define stac9460_dac_mute_info		snd_ctl_boolean_mono_info
 
 static int stac9460_dac_mute_get(struct snd_kcontrol *kcontrol,
-	       			struct snd_ctl_elem_value *ucontrol)
+				struct snd_ctl_elem_value *ucontrol)
 {
 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
 	unsigned char val;
@@ -88,14 +88,14 @@
 	}
 	if (id < 6)
 		val = stac9460_get(ice, idx);
-	else 
-		val = stac9460_2_get(ice,idx - 6);
+	else
+		val = stac9460_2_get(ice, idx - 6);
 	ucontrol->value.integer.value[0] = (~val >> 7) & 0x1;
 	return 0;
 }
 
 static int stac9460_dac_mute_put(struct snd_kcontrol *kcontrol,
-	       			struct snd_ctl_elem_value *ucontrol)
+				struct snd_ctl_elem_value *ucontrol)
 {
 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
 	unsigned char new, old;
@@ -105,8 +105,8 @@
 	if (kcontrol->private_value) {
 		idx = STAC946X_MASTER_VOLUME;
 		old = stac9460_get(ice, idx);
-		new = (~ucontrol->value.integer.value[0]<< 7 & 0x80) |
-		       					(old & ~0x80);
+		new = (~ucontrol->value.integer.value[0] << 7 & 0x80) |
+							(old & ~0x80);
 		change = (new != old);
 		if (change) {
 			stac9460_put(ice, idx, new);
@@ -117,16 +117,16 @@
 		idx = id + STAC946X_LF_VOLUME;
 		if (id < 6)
 			old = stac9460_get(ice, idx);
-		else 
+		else
 			old = stac9460_2_get(ice, idx - 6);
-		new = (~ucontrol->value.integer.value[0]<< 7 & 0x80) |
+		new = (~ucontrol->value.integer.value[0] << 7 & 0x80) |
 							(old & ~0x80);
 		change = (new != old);
 		if (change) {
 			if (id < 6)
-			       	stac9460_put(ice, idx, new);
+				stac9460_put(ice, idx, new);
 			else
-			       	stac9460_2_put(ice, idx - 6, new);
+				stac9460_2_put(ice, idx - 6, new);
 		}
 	}
 	return change;
@@ -136,7 +136,7 @@
  * 	DAC volume attenuation mixer control
  */
 static int stac9460_dac_vol_info(struct snd_kcontrol *kcontrol,
-	       			struct snd_ctl_elem_info *uinfo)
+				struct snd_ctl_elem_info *uinfo)
 {
 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
 	uinfo->count = 1;
@@ -146,7 +146,7 @@
 }
 
 static int stac9460_dac_vol_get(struct snd_kcontrol *kcontrol,
-	       			struct snd_ctl_elem_value *ucontrol)
+				struct snd_ctl_elem_value *ucontrol)
 {
 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
 	int idx, id;
@@ -161,14 +161,14 @@
 	}
 	if (id < 6)
 		vol = stac9460_get(ice, idx) & 0x7f;
-	else 
+	else
 		vol = stac9460_2_get(ice, idx - 6) & 0x7f;
 	ucontrol->value.integer.value[0] = 0x7f - vol;
 	return 0;
 }
 
 static int stac9460_dac_vol_put(struct snd_kcontrol *kcontrol,
-	       			struct snd_ctl_elem_value *ucontrol)
+				struct snd_ctl_elem_value *ucontrol)
 {
 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
 	int idx, id;
@@ -182,8 +182,8 @@
 		ovol = 0x7f - (tmp & 0x7f);
 		change = (ovol != nvol);
 		if (change) {
-			 stac9460_put(ice, idx, (0x7f - nvol) | (tmp & 0x80));
-			 stac9460_2_put(ice, idx, (0x7f - nvol) | (tmp & 0x80));
+			stac9460_put(ice, idx, (0x7f - nvol) | (tmp & 0x80));
+			stac9460_2_put(ice, idx, (0x7f - nvol) | (tmp & 0x80));
 		}
 	} else {
 		id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
@@ -191,17 +191,17 @@
 		nvol = ucontrol->value.integer.value[0] & 0x7f;
 		if (id < 6)
 			tmp = stac9460_get(ice, idx);
-		else 
+		else
 			tmp = stac9460_2_get(ice, idx - 6);
 		ovol = 0x7f - (tmp & 0x7f);
 		change = (ovol != nvol);
 		if (change) {
 			if (id < 6)
 				stac9460_put(ice, idx, (0x7f - nvol) |
-					       		(tmp & 0x80));
-			else 
+							(tmp & 0x80));
+			else
 				stac9460_2_put(ice, idx-6, (0x7f - nvol) |
-					       			(tmp & 0x80));
+							(tmp & 0x80));
 		}
 	}
 	return change;
@@ -213,12 +213,12 @@
 #define stac9460_adc_mute_info		snd_ctl_boolean_stereo_info
 
 static int stac9460_adc_mute_get(struct snd_kcontrol *kcontrol,
-	       			struct snd_ctl_elem_value *ucontrol)
+				struct snd_ctl_elem_value *ucontrol)
 {
 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
 	unsigned char val;
 	int i, id;
-	
+
 	id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
 	if (id == 0) {
 		for (i = 0; i < 2; ++i) {
@@ -235,20 +235,20 @@
 }
 
 static int stac9460_adc_mute_put(struct snd_kcontrol *kcontrol,
-	       			struct snd_ctl_elem_value *ucontrol)
+				struct snd_ctl_elem_value *ucontrol)
 {
 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
 	unsigned char new, old;
 	int i, reg, id;
 	int change;
-	
+
 	id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
 	if (id == 0) {
 		for (i = 0; i < 2; ++i) {
 			reg = STAC946X_MIC_L_VOLUME + i;
 			old = stac9460_get(ice, reg);
 			new = (~ucontrol->value.integer.value[i]<<7&0x80) |
-			       					(old&~0x80);
+								(old&~0x80);
 			change = (new != old);
 			if (change)
 				stac9460_put(ice, reg, new);
@@ -258,7 +258,7 @@
 			reg = STAC946X_MIC_L_VOLUME + i;
 			old = stac9460_2_get(ice, reg);
 			new = (~ucontrol->value.integer.value[i]<<7&0x80) |
-			       					(old&~0x80);
+								(old&~0x80);
 			change = (new != old);
 			if (change)
 				stac9460_2_put(ice, reg, new);
@@ -271,7 +271,7 @@
  *ADC gain mixer control
  */
 static int stac9460_adc_vol_info(struct snd_kcontrol *kcontrol,
-	       			struct snd_ctl_elem_info *uinfo)
+				struct snd_ctl_elem_info *uinfo)
 {
 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
 	uinfo->count = 2;
@@ -281,12 +281,12 @@
 }
 
 static int stac9460_adc_vol_get(struct snd_kcontrol *kcontrol,
-	       			struct snd_ctl_elem_value *ucontrol)
+				struct snd_ctl_elem_value *ucontrol)
 {
 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
 	int i, reg, id;
 	unsigned char vol;
-	
+
 	id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
 	if (id == 0) {
 		for (i = 0; i < 2; ++i) {
@@ -305,13 +305,13 @@
 }
 
 static int stac9460_adc_vol_put(struct snd_kcontrol *kcontrol,
-	       		struct snd_ctl_elem_value *ucontrol)
+				struct snd_ctl_elem_value *ucontrol)
 {
 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
 	int i, reg, id;
 	unsigned char ovol, nvol;
 	int change;
-	
+
 	id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
 	if (id == 0) {
 		for (i = 0; i < 2; ++i) {
@@ -321,7 +321,7 @@
 			change = ((ovol & 0x0f) != nvol);
 			if (change)
 				stac9460_put(ice, reg, (0x0f - nvol) |
-					       		(ovol & ~0x0f));
+							(ovol & ~0x0f));
 		}
 	} else {
 		for (i = 0; i < 2; ++i) {
@@ -331,7 +331,7 @@
 			change = ((ovol & 0x0f) != nvol);
 			if (change)
 				stac9460_2_put(ice, reg, (0x0f - nvol) |
-					       		(ovol & ~0x0f));
+							(ovol & ~0x0f));
 		}
 	}
 	return change;
@@ -344,23 +344,23 @@
 #define stac9460_mic_sw_info		snd_ctl_boolean_mono_info
 
 static int stac9460_mic_sw_get(struct snd_kcontrol *kcontrol,
-	       		struct snd_ctl_elem_value *ucontrol)
+				struct snd_ctl_elem_value *ucontrol)
 {
 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
 	unsigned char val;
 	int id;
-		
+
 	id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
 	if (id == 0)
-	       	val = stac9460_get(ice, STAC946X_GENERAL_PURPOSE);
+		val = stac9460_get(ice, STAC946X_GENERAL_PURPOSE);
 	else
-	       	val = stac9460_2_get(ice, STAC946X_GENERAL_PURPOSE);
+		val = stac9460_2_get(ice, STAC946X_GENERAL_PURPOSE);
 	ucontrol->value.integer.value[0] = ~val>>7 & 0x1;
 	return 0;
 }
 
 static int stac9460_mic_sw_put(struct snd_kcontrol *kcontrol,
-	       		struct snd_ctl_elem_value *ucontrol)
+				struct snd_ctl_elem_value *ucontrol)
 {
 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
 	unsigned char new, old;
@@ -368,16 +368,16 @@
 
 	id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
 	if (id == 0)
-	       	old = stac9460_get(ice, STAC946X_GENERAL_PURPOSE);
+		old = stac9460_get(ice, STAC946X_GENERAL_PURPOSE);
 	else
-	       	old = stac9460_2_get(ice, STAC946X_GENERAL_PURPOSE);
-	new = (~ucontrol->value.integer.value[0]<< 7 & 0x80) | (old & ~0x80);
+		old = stac9460_2_get(ice, STAC946X_GENERAL_PURPOSE);
+	new = (~ucontrol->value.integer.value[0] << 7 & 0x80) | (old & ~0x80);
 	change = (new != old);
 	if (change) {
 		if (id == 0)
-		       	stac9460_put(ice, STAC946X_GENERAL_PURPOSE, new);
+			stac9460_put(ice, STAC946X_GENERAL_PURPOSE, new);
 		else
-		       	stac9460_2_put(ice, STAC946X_GENERAL_PURPOSE, new);
+			stac9460_2_put(ice, STAC946X_GENERAL_PURPOSE, new);
 	}
 	return change;
 }
@@ -443,7 +443,7 @@
 		.get = stac9460_adc_vol_get,
 		.put = stac9460_adc_vol_put,
 
-	}	
+	}
 };
 
 
@@ -470,7 +470,7 @@
 		(unsigned short)-1
 	};
 	unsigned short *p;
-		
+
 	/*WTM 192M*/
 	ice->num_total_dacs = 8;
 	ice->num_total_adcs = 4;
diff --git a/sound/pci/ice1712/wtm.h b/sound/pci/ice1712/wtm.h
index 03a394e..423c1a2 100644
--- a/sound/pci/ice1712/wtm.h
+++ b/sound/pci/ice1712/wtm.h
@@ -10,8 +10,8 @@
  */
 
 #define	AK4114_ADDR		0x20	/*S/PDIF receiver*/
-#define STAC9460_I2C_ADDR	0x54	/* ADC*2 | DAC*6 */	
-#define STAC9460_2_I2C_ADDR	0x56	/* ADC|DAC *2 */	
+#define STAC9460_I2C_ADDR	0x54	/* ADC*2 | DAC*6 */
+#define STAC9460_2_I2C_ADDR	0x56	/* ADC|DAC *2 */
 
 
 extern struct snd_ice1712_card_info snd_vt1724_wtm_cards[];
diff --git a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c
index 048d99e..c88d1ea 100644
--- a/sound/pci/intel8x0.c
+++ b/sound/pci/intel8x0.c
@@ -59,6 +59,12 @@
 		"{SiS,SI7012},"
 		"{NVidia,nForce Audio},"
 		"{NVidia,nForce2 Audio},"
+		"{NVidia,nForce3 Audio},"
+		"{NVidia,MCP04},"
+		"{NVidia,MCP501},"
+		"{NVidia,CK804},"
+		"{NVidia,CK8},"
+		"{NVidia,CK8S},"
 		"{AMD,AMD768},"
 		"{AMD,AMD8111},"
 	        "{ALI,M5455}}");
@@ -77,7 +83,7 @@
 module_param(id, charp, 0444);
 MODULE_PARM_DESC(id, "ID string for Intel i8x0 soundcard.");
 module_param(ac97_clock, int, 0444);
-MODULE_PARM_DESC(ac97_clock, "AC'97 codec clock (0 = auto-detect).");
+MODULE_PARM_DESC(ac97_clock, "AC'97 codec clock (0 = whitelist + auto-detect, 1 = force autodetect).");
 module_param(ac97_quirk, charp, 0444);
 MODULE_PARM_DESC(ac97_quirk, "AC'97 workaround for strange hardware.");
 module_param(buggy_semaphore, bool, 0444);
@@ -1957,6 +1963,12 @@
 	},
 	{
 		.subvendor = 0x10cf,
+		.subdevice = 0x127d,
+		.name = "Fujitsu Lifebook P7010",
+		.type = AC97_TUNE_HP_ONLY
+	},
+	{
+		.subvendor = 0x10cf,
 		.subdevice = 0x127e,
 		.name = "Fujitsu Lifebook C1211D",
 		.type = AC97_TUNE_HP_ONLY
@@ -2132,8 +2144,8 @@
 				snd_intel8x0_codec_read_test(chip, codecs);
 				chip->ac97_sdin[codecs] =
 					igetbyte(chip, ICHREG(SDM)) & ICH_LDI_MASK;
-				snd_assert(chip->ac97_sdin[codecs] < 3,
-					   chip->ac97_sdin[codecs] = 0);
+				if (snd_BUG_ON(chip->ac97_sdin[codecs] >= 3))
+					chip->ac97_sdin[codecs] = 0;
 			} else
 				chip->ac97_sdin[codecs] = i;
 			codecs++;
@@ -2686,6 +2698,28 @@
 	snd_ac97_update_power(chip->ac97[0], AC97_PCM_FRONT_DAC_RATE, 0);
 }
 
+static struct snd_pci_quirk intel8x0_clock_list[] __devinitdata = {
+	SND_PCI_QUIRK(0x0e11, 0x008a, "AD1885", 41000),
+	SND_PCI_QUIRK(0x1028, 0x00be, "AD1885", 44100),
+	SND_PCI_QUIRK(0x1028, 0x0177, "AD1980", 48000),
+	SND_PCI_QUIRK(0x1043, 0x80f3, "AD1985", 48000),
+	{ }	/* terminator */
+};
+
+static int __devinit intel8x0_in_clock_list(struct intel8x0 *chip)
+{
+	struct pci_dev *pci = chip->pci;
+	const struct snd_pci_quirk *wl;
+
+	wl = snd_pci_quirk_lookup(pci, intel8x0_clock_list);
+	if (!wl)
+		return 0;
+	printk(KERN_INFO "intel8x0: white list rate for %04x:%04x is %i\n",
+	       pci->subsystem_vendor, pci->subsystem_device, wl->value);
+	chip->ac97_bus->clock = wl->value;
+	return 1;
+}
+
 #ifdef CONFIG_PROC_FS
 static void snd_intel8x0_proc_read(struct snd_info_entry * entry,
 				   struct snd_info_buffer *buffer)
@@ -3081,8 +3115,14 @@
 		 "%s with %s at irq %i", card->shortname,
 		 snd_ac97_get_short_name(chip->ac97[0]), chip->irq);
 
-	if (! ac97_clock)
-		intel8x0_measure_ac97_clock(chip);
+	if (ac97_clock == 0 || ac97_clock == 1) {
+		if (ac97_clock == 0) {
+			if (intel8x0_in_clock_list(chip) == 0)
+				intel8x0_measure_ac97_clock(chip);
+		} else {
+			intel8x0_measure_ac97_clock(chip);
+		}
+	}
 
 	if ((err = snd_card_register(card)) < 0) {
 		snd_card_free(card);
diff --git a/sound/pci/intel8x0m.c b/sound/pci/intel8x0m.c
index faf674e..93449e4 100644
--- a/sound/pci/intel8x0m.c
+++ b/sound/pci/intel8x0m.c
@@ -306,7 +306,8 @@
 	static unsigned int codec_bit[3] = {
 		ICH_PCR, ICH_SCR, ICH_TCR
 	};
-	snd_assert(codec < 3, return ICH_PCR);
+	if (snd_BUG_ON(codec >= 3))
+		return ICH_PCR;
 	return codec_bit[codec];
 }
 
diff --git a/sound/pci/korg1212/korg1212.c b/sound/pci/korg1212/korg1212.c
index 4a44c0f..5f8006b 100644
--- a/sound/pci/korg1212/korg1212.c
+++ b/sound/pci/korg1212/korg1212.c
@@ -1281,7 +1281,8 @@
 
 	K1212_DEBUG_PRINTK_VERBOSE("K1212_DEBUG: snd_korg1212_silence pos=%d offset=%d size=%d count=%d\n",
 				   pos, offset, size, count);
-	snd_assert(pos + count <= K1212_MAX_SAMPLES, return -EINVAL);
+	if (snd_BUG_ON(pos + count > K1212_MAX_SAMPLES))
+		return -EINVAL;
 
 	for (i=0; i < count; i++) {
 #if K1212_DEBUG_LEVEL > 0
@@ -1306,7 +1307,8 @@
 
 	K1212_DEBUG_PRINTK_VERBOSE("K1212_DEBUG: snd_korg1212_copy_to pos=%d offset=%d size=%d\n",
 				   pos, offset, size);
-	snd_assert(pos + count <= K1212_MAX_SAMPLES, return -EINVAL);
+	if (snd_BUG_ON(pos + count > K1212_MAX_SAMPLES))
+		return -EINVAL;
 
 	for (i=0; i < count; i++) {
 #if K1212_DEBUG_LEVEL > 0
@@ -1336,7 +1338,8 @@
 	K1212_DEBUG_PRINTK_VERBOSE("K1212_DEBUG: snd_korg1212_copy_from pos=%d offset=%d size=%d count=%d\n",
 				   pos, offset, size, count);
 
-	snd_assert(pos + count <= K1212_MAX_SAMPLES, return -EINVAL);
+	if (snd_BUG_ON(pos + count > K1212_MAX_SAMPLES))
+		return -EINVAL;
 
 	for (i=0; i < count; i++) {
 #if K1212_DEBUG_LEVEL > 0
diff --git a/sound/pci/maestro3.c b/sound/pci/maestro3.c
index 0037be7..9ff3f9e 100644
--- a/sound/pci/maestro3.c
+++ b/sound/pci/maestro3.c
@@ -1175,7 +1175,8 @@
 	struct m3_dma *s = subs->runtime->private_data;
 	int err = -EINVAL;
 
-	snd_assert(s != NULL, return -ENXIO);
+	if (snd_BUG_ON(!s))
+		return -ENXIO;
 
 	spin_lock(&chip->reg_lock);
 	switch (cmd) {
@@ -1487,7 +1488,8 @@
 	struct snd_pcm_runtime *runtime = subs->runtime;
 	struct m3_dma *s = runtime->private_data;
 
-	snd_assert(s != NULL, return -ENXIO);
+	if (snd_BUG_ON(!s))
+		return -ENXIO;
 
 	if (runtime->format != SNDRV_PCM_FORMAT_U8 &&
 	    runtime->format != SNDRV_PCM_FORMAT_S16_LE)
@@ -1546,7 +1548,9 @@
 	struct snd_m3 *chip = snd_pcm_substream_chip(subs);
 	unsigned int ptr;
 	struct m3_dma *s = subs->runtime->private_data;
-	snd_assert(s != NULL, return 0);
+
+	if (snd_BUG_ON(!s))
+		return 0;
 
 	spin_lock(&chip->reg_lock);
 	ptr = snd_m3_get_pointer(chip, s, subs);
diff --git a/sound/pci/mixart/mixart.c b/sound/pci/mixart/mixart.c
index 3dd0c79..2d0dce6 100644
--- a/sound/pci/mixart/mixart.c
+++ b/sound/pci/mixart/mixart.c
@@ -708,7 +708,7 @@
 		pcm_number = MIXART_PCM_ANALOG;
 		runtime->hw = snd_mixart_analog_caps;
 	} else {
-		snd_assert ( pcm == chip->pcm_dig ); 
+		snd_BUG_ON(pcm != chip->pcm_dig);
 		pcm_number = MIXART_PCM_DIGITAL;
 		runtime->hw = snd_mixart_digital_caps;
 	}
@@ -783,7 +783,7 @@
 		pcm_number = MIXART_PCM_ANALOG;
 		runtime->hw = snd_mixart_analog_caps;
 	} else {
-		snd_assert ( pcm == chip->pcm_dig ); 
+		snd_BUG_ON(pcm != chip->pcm_dig);
 		pcm_number = MIXART_PCM_DIGITAL;
 		runtime->hw = snd_mixart_digital_caps;
 	}
diff --git a/sound/pci/mixart/mixart_core.c b/sound/pci/mixart/mixart_core.c
index 785085e..b9a06c2 100644
--- a/sound/pci/mixart/mixart_core.c
+++ b/sound/pci/mixart/mixart_core.c
@@ -56,8 +56,10 @@
 	if (tailptr == headptr)
 		return 0; /* no message posted */
 
-	snd_assert( tailptr >= MSG_OUTBOUND_POST_STACK, return 0); /* error */
-	snd_assert( tailptr < (MSG_OUTBOUND_POST_STACK+MSG_BOUND_STACK_SIZE), return 0); /* error */
+	if (tailptr < MSG_OUTBOUND_POST_STACK)
+		return 0; /* error */
+	if (tailptr >= MSG_OUTBOUND_POST_STACK + MSG_BOUND_STACK_SIZE)
+		return 0; /* error */
 
 	*msg_frame = readl_be(MIXART_MEM(mgr, tailptr));
 
@@ -149,7 +151,8 @@
 	u32 msg_frame_address;
 	int err, i;
 
-	snd_assert(msg->size % 4 == 0, return -EINVAL);
+	if (snd_BUG_ON(msg->size % 4))
+		return -EINVAL;
 
 	err = 0;
 
@@ -289,9 +292,12 @@
 	wait_queue_t wait;
 	long timeout;
 
-	snd_assert(notif_event != 0, return -EINVAL);
-	snd_assert((notif_event & MSG_TYPE_MASK) == MSG_TYPE_NOTIFY, return -EINVAL);
-	snd_assert((notif_event & MSG_CANCEL_NOTIFY_MASK) == 0, return -EINVAL);
+	if (snd_BUG_ON(!notif_event))
+		return -EINVAL;
+	if (snd_BUG_ON((notif_event & MSG_TYPE_MASK) != MSG_TYPE_NOTIFY))
+		return -EINVAL;
+	if (snd_BUG_ON(notif_event & MSG_CANCEL_NOTIFY_MASK))
+		return -EINVAL;
 
 	mutex_lock(&mgr->msg_mutex);
 
diff --git a/sound/pci/mixart/mixart_hwdep.c b/sound/pci/mixart/mixart_hwdep.c
index f986031..3782b52 100644
--- a/sound/pci/mixart/mixart_hwdep.c
+++ b/sound/pci/mixart/mixart_hwdep.c
@@ -288,7 +288,9 @@
 		return -EINVAL;
 	}
 
-	snd_assert(phys_io.nb_uid >= (MIXART_MAX_CARDS * 2),  return -EINVAL); /* min 2 phys io per card (analog in + analog out) */
+	/* min 2 phys io per card (analog in + analog out) */
+	if (phys_io.nb_uid < MIXART_MAX_CARDS * 2)
+		return -EINVAL;
 
 	for(k=0; k<mgr->num_cards; k++) {
 		mgr->chip[k]->uid_in_analog_physio = phys_io.uid[k];
@@ -363,8 +365,10 @@
 		}
 
 		/* check xilinx validity */
-		snd_assert(((u32*)(dsp->data))[0]==0xFFFFFFFF, return -EINVAL);
-		snd_assert(dsp->size % 4 == 0, return -EINVAL);
+		if (((u32*)(dsp->data))[0] == 0xffffffff)
+			return -EINVAL;
+		if (dsp->size % 4)
+			return -EINVAL;
 
 		/* set xilinx status to copying */
 		writel_be( 1, MIXART_MEM( mgr, MIXART_PSEUDOREG_MXLX_STATUS_OFFSET ));
@@ -462,8 +466,10 @@
 		}
  
 		/* check daughterboard xilinx validity */
-		snd_assert(((u32*)(dsp->data))[0]==0xFFFFFFFF, return -EINVAL);
-		snd_assert(dsp->size % 4 == 0, return -EINVAL);
+		if (((u32*)(dsp->data))[0] == 0xffffffff)
+			return -EINVAL;
+		if (dsp->size % 4)
+			return -EINVAL;
 
 		/* inform mixart about the size of the file */
 		writel_be( dsp->size, MIXART_MEM( mgr, MIXART_PSEUDOREG_DXLX_SIZE_OFFSET ));
@@ -480,7 +486,8 @@
 
 		/* get the address where to write the file */
 		val = readl_be( MIXART_MEM( mgr, MIXART_PSEUDOREG_DXLX_BASE_ADDR_OFFSET ));
-		snd_assert(val != 0, return -EINVAL);
+		if (!val)
+			return -EINVAL;
 
 		/* copy daughterboard xilinx code */
 		memcpy_toio(  MIXART_MEM( mgr, val),  dsp->data,  dsp->size);
diff --git a/sound/pci/mixart/mixart_mixer.c b/sound/pci/mixart/mixart_mixer.c
index 6fdda1f..3ba6174 100644
--- a/sound/pci/mixart/mixart_mixer.c
+++ b/sound/pci/mixart/mixart_mixer.c
@@ -837,7 +837,7 @@
 		if(is_aes)	stored_volume = chip->digital_capture_volume[1];	/* AES capture */
 		else		stored_volume = chip->digital_capture_volume[0];	/* analog capture */
 	} else {
-		snd_assert ( idx < MIXART_PLAYBACK_STREAMS ); 
+		snd_BUG_ON(idx >= MIXART_PLAYBACK_STREAMS);
 		if(is_aes)	stored_volume = chip->digital_playback_volume[MIXART_PLAYBACK_STREAMS + idx]; /* AES playback */
 		else		stored_volume = chip->digital_playback_volume[idx];	/* analog playback */
 	}
@@ -863,7 +863,7 @@
 		else		/* analog capture */
 			stored_volume = chip->digital_capture_volume[0];
 	} else {
-		snd_assert ( idx < MIXART_PLAYBACK_STREAMS ); 
+		snd_BUG_ON(idx >= MIXART_PLAYBACK_STREAMS);
 		if (is_aes)	/* AES playback */
 			stored_volume = chip->digital_playback_volume[MIXART_PLAYBACK_STREAMS + idx];
 		else		/* analog playback */
@@ -909,7 +909,7 @@
 {
 	struct snd_mixart *chip = snd_kcontrol_chip(kcontrol);
 	int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); /* index */
-	snd_assert ( idx < MIXART_PLAYBACK_STREAMS ); 
+	snd_BUG_ON(idx >= MIXART_PLAYBACK_STREAMS);
 	mutex_lock(&chip->mgr->mixer_mutex);
 	if(kcontrol->private_value & MIXART_VOL_AES_MASK)	/* AES playback */
 		idx += MIXART_PLAYBACK_STREAMS;
@@ -926,7 +926,7 @@
 	int is_aes = kcontrol->private_value & MIXART_VOL_AES_MASK;
 	int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); /* index */
 	int i, j;
-	snd_assert ( idx < MIXART_PLAYBACK_STREAMS ); 
+	snd_BUG_ON(idx >= MIXART_PLAYBACK_STREAMS);
 	mutex_lock(&chip->mgr->mixer_mutex);
 	j = idx;
 	if (is_aes)
diff --git a/sound/pci/nm256/nm256.c b/sound/pci/nm256/nm256.c
index 06d13e7..50c9f8a 100644
--- a/sound/pci/nm256/nm256.c
+++ b/sound/pci/nm256/nm256.c
@@ -562,7 +562,8 @@
 	struct nm256_stream *s = substream->runtime->private_data;
 	int err = 0;
 
-	snd_assert(s != NULL, return -ENXIO);
+	if (snd_BUG_ON(!s))
+		return -ENXIO;
 
 	spin_lock(&chip->reg_lock);
 	switch (cmd) {
@@ -599,7 +600,8 @@
 	struct nm256_stream *s = substream->runtime->private_data;
 	int err = 0;
 
-	snd_assert(s != NULL, return -ENXIO);
+	if (snd_BUG_ON(!s))
+		return -ENXIO;
 
 	spin_lock(&chip->reg_lock);
 	switch (cmd) {
@@ -635,7 +637,8 @@
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct nm256_stream *s = runtime->private_data;
 
-	snd_assert(s, return -ENXIO);
+	if (snd_BUG_ON(!s))
+		return -ENXIO;
 	s->dma_size = frames_to_bytes(runtime, substream->runtime->buffer_size);
 	s->period_size = frames_to_bytes(runtime, substream->runtime->period_size);
 	s->periods = substream->runtime->periods;
@@ -660,7 +663,8 @@
 	struct nm256_stream *s = substream->runtime->private_data;
 	unsigned long curp;
 
-	snd_assert(s, return 0);
+	if (snd_BUG_ON(!s))
+		return 0;
 	curp = snd_nm256_readl(chip, NM_PBUFFER_CURRP) - (unsigned long)s->buf;
 	curp %= s->dma_size;
 	return bytes_to_frames(substream->runtime, curp);
@@ -673,7 +677,8 @@
 	struct nm256_stream *s = substream->runtime->private_data;
 	unsigned long curp;
 
-	snd_assert(s != NULL, return 0);
+	if (snd_BUG_ON(!s))
+		return 0;
 	curp = snd_nm256_readl(chip, NM_RBUFFER_CURRP) - (unsigned long)s->buf;
 	curp %= s->dma_size;	
 	return bytes_to_frames(substream->runtime, curp);
diff --git a/sound/pci/oxygen/hifier.c b/sound/pci/oxygen/hifier.c
index dad393a..1ab833f 100644
--- a/sound/pci/oxygen/hifier.c
+++ b/sound/pci/oxygen/hifier.c
@@ -94,6 +94,11 @@
 {
 }
 
+static void hifier_resume(struct oxygen *chip)
+{
+	hifier_registers_init(chip);
+}
+
 static void set_ak4396_params(struct oxygen *chip,
 			       struct snd_pcm_hw_params *params)
 {
@@ -150,16 +155,16 @@
 	.init = hifier_init,
 	.control_filter = hifier_control_filter,
 	.cleanup = hifier_cleanup,
-	.resume = hifier_registers_init,
+	.resume = hifier_resume,
 	.set_dac_params = set_ak4396_params,
 	.set_adc_params = set_cs5340_params,
 	.update_dac_volume = update_ak4396_volume,
 	.update_dac_mute = update_ak4396_mute,
 	.dac_tlv = ak4396_db_scale,
 	.model_data_size = sizeof(struct hifier_data),
-	.pcm_dev_cfg = PLAYBACK_0_TO_I2S |
-		       PLAYBACK_1_TO_SPDIF |
-		       CAPTURE_0_FROM_I2S_1,
+	.device_config = PLAYBACK_0_TO_I2S |
+			 PLAYBACK_1_TO_SPDIF |
+			 CAPTURE_0_FROM_I2S_1,
 	.dac_channels = 2,
 	.dac_volume_min = 0,
 	.dac_volume_max = 255,
@@ -180,7 +185,7 @@
 		++dev;
 		return -ENOENT;
 	}
-	err = oxygen_pci_probe(pci, index[dev], id[dev], &model_hifier);
+	err = oxygen_pci_probe(pci, index[dev], id[dev], &model_hifier, 0);
 	if (err >= 0)
 		++dev;
 	return err;
diff --git a/sound/pci/oxygen/oxygen.c b/sound/pci/oxygen/oxygen.c
index c5829d3..b60f621 100644
--- a/sound/pci/oxygen/oxygen.c
+++ b/sound/pci/oxygen/oxygen.c
@@ -58,17 +58,22 @@
 module_param_array(enable, bool, NULL, 0444);
 MODULE_PARM_DESC(enable, "enable card");
 
+enum {
+	MODEL_CMEDIA_REF,	/* C-Media's reference design */
+	MODEL_MERIDIAN,		/* AuzenTech X-Meridian */
+};
+
 static struct pci_device_id oxygen_ids[] __devinitdata = {
-	{ OXYGEN_PCI_SUBID(0x10b0, 0x0216) },
-	{ OXYGEN_PCI_SUBID(0x10b0, 0x0218) },
-	{ OXYGEN_PCI_SUBID(0x10b0, 0x0219) },
-	{ OXYGEN_PCI_SUBID(0x13f6, 0x0001) },
-	{ OXYGEN_PCI_SUBID(0x13f6, 0x0010) },
-	{ OXYGEN_PCI_SUBID(0x13f6, 0x8788) },
-	{ OXYGEN_PCI_SUBID(0x147a, 0xa017) },
-	{ OXYGEN_PCI_SUBID(0x1a58, 0x0910) },
-	{ OXYGEN_PCI_SUBID(0x415a, 0x5431), .driver_data = 1 },
-	{ OXYGEN_PCI_SUBID(0x7284, 0x9761) },
+	{ OXYGEN_PCI_SUBID(0x10b0, 0x0216), .driver_data = MODEL_CMEDIA_REF },
+	{ OXYGEN_PCI_SUBID(0x10b0, 0x0218), .driver_data = MODEL_CMEDIA_REF },
+	{ OXYGEN_PCI_SUBID(0x10b0, 0x0219), .driver_data = MODEL_CMEDIA_REF },
+	{ OXYGEN_PCI_SUBID(0x13f6, 0x0001), .driver_data = MODEL_CMEDIA_REF },
+	{ OXYGEN_PCI_SUBID(0x13f6, 0x0010), .driver_data = MODEL_CMEDIA_REF },
+	{ OXYGEN_PCI_SUBID(0x13f6, 0x8788), .driver_data = MODEL_CMEDIA_REF },
+	{ OXYGEN_PCI_SUBID(0x147a, 0xa017), .driver_data = MODEL_CMEDIA_REF },
+	{ OXYGEN_PCI_SUBID(0x1a58, 0x0910), .driver_data = MODEL_CMEDIA_REF },
+	{ OXYGEN_PCI_SUBID(0x415a, 0x5431), .driver_data = MODEL_MERIDIAN },
+	{ OXYGEN_PCI_SUBID(0x7284, 0x9761), .driver_data = MODEL_CMEDIA_REF },
 	{ }
 };
 MODULE_DEVICE_TABLE(pci, oxygen_ids);
@@ -199,6 +204,11 @@
 	wm8785_registers_init(chip);
 }
 
+static void meridian_resume(struct oxygen *chip)
+{
+	ak4396_registers_init(chip);
+}
+
 static void set_ak4396_params(struct oxygen *chip,
 			      struct snd_pcm_hw_params *params)
 {
@@ -281,11 +291,28 @@
 
 static const DECLARE_TLV_DB_LINEAR(ak4396_db_scale, TLV_DB_GAIN_MUTE, 0);
 
+static int generic_probe(struct oxygen *chip, unsigned long driver_data)
+{
+	if (driver_data == MODEL_MERIDIAN) {
+		chip->model.init = meridian_init;
+		chip->model.resume = meridian_resume;
+		chip->model.set_adc_params = set_ak5385_params;
+		chip->model.device_config = PLAYBACK_0_TO_I2S |
+					    PLAYBACK_1_TO_SPDIF |
+					    CAPTURE_0_FROM_I2S_2 |
+					    CAPTURE_1_FROM_SPDIF;
+		chip->model.misc_flags = OXYGEN_MISC_MIDI;
+		chip->model.device_config |= MIDI_OUTPUT | MIDI_INPUT;
+	}
+	return 0;
+}
+
 static const struct oxygen_model model_generic = {
 	.shortname = "C-Media CMI8788",
 	.longname = "C-Media Oxygen HD Audio",
 	.chip = "CMI8788",
 	.owner = THIS_MODULE,
+	.probe = generic_probe,
 	.init = generic_init,
 	.cleanup = generic_cleanup,
 	.resume = generic_resume,
@@ -295,12 +322,12 @@
 	.update_dac_mute = update_ak4396_mute,
 	.dac_tlv = ak4396_db_scale,
 	.model_data_size = sizeof(struct generic_data),
-	.pcm_dev_cfg = PLAYBACK_0_TO_I2S |
-		       PLAYBACK_1_TO_SPDIF |
-		       PLAYBACK_2_TO_AC97_1 |
-		       CAPTURE_0_FROM_I2S_1 |
-		       CAPTURE_1_FROM_SPDIF |
-		       CAPTURE_2_FROM_AC97_1,
+	.device_config = PLAYBACK_0_TO_I2S |
+			 PLAYBACK_1_TO_SPDIF |
+			 PLAYBACK_2_TO_AC97_1 |
+			 CAPTURE_0_FROM_I2S_1 |
+			 CAPTURE_1_FROM_SPDIF |
+			 CAPTURE_2_FROM_AC97_1,
 	.dac_channels = 8,
 	.dac_volume_min = 0,
 	.dac_volume_max = 255,
@@ -309,41 +336,11 @@
 	.dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
 	.adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
 };
-static const struct oxygen_model model_meridian = {
-	.shortname = "C-Media CMI8788",
-	.longname = "C-Media Oxygen HD Audio",
-	.chip = "CMI8788",
-	.owner = THIS_MODULE,
-	.init = meridian_init,
-	.cleanup = generic_cleanup,
-	.resume = ak4396_registers_init,
-	.set_dac_params = set_ak4396_params,
-	.set_adc_params = set_ak5385_params,
-	.update_dac_volume = update_ak4396_volume,
-	.update_dac_mute = update_ak4396_mute,
-	.dac_tlv = ak4396_db_scale,
-	.model_data_size = sizeof(struct generic_data),
-	.pcm_dev_cfg = PLAYBACK_0_TO_I2S |
-		       PLAYBACK_1_TO_SPDIF |
-		       PLAYBACK_2_TO_AC97_1 |
-		       CAPTURE_0_FROM_I2S_2 |
-		       CAPTURE_1_FROM_SPDIF |
-		       CAPTURE_2_FROM_AC97_1,
-	.dac_channels = 8,
-	.dac_volume_min = 0,
-	.dac_volume_max = 255,
-	.misc_flags = OXYGEN_MISC_MIDI,
-	.function_flags = OXYGEN_FUNCTION_SPI |
-			  OXYGEN_FUNCTION_ENABLE_SPI_4_5,
-	.dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
-	.adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
-};
 
 static int __devinit generic_oxygen_probe(struct pci_dev *pci,
 					  const struct pci_device_id *pci_id)
 {
 	static int dev;
-	int is_meridian;
 	int err;
 
 	if (dev >= SNDRV_CARDS)
@@ -352,9 +349,8 @@
 		++dev;
 		return -ENOENT;
 	}
-	is_meridian = pci_id->driver_data;
 	err = oxygen_pci_probe(pci, index[dev], id[dev],
-			       is_meridian ? &model_meridian : &model_generic);
+			       &model_generic, pci_id->driver_data);
 	if (err >= 0)
 		++dev;
 	return err;
diff --git a/sound/pci/oxygen/oxygen.h b/sound/pci/oxygen/oxygen.h
index 74a6448..19107c6 100644
--- a/sound/pci/oxygen/oxygen.h
+++ b/sound/pci/oxygen/oxygen.h
@@ -19,14 +19,19 @@
 #define OXYGEN_IO_SIZE	0x100
 
 /* model-specific configuration of outputs/inputs */
-#define PLAYBACK_0_TO_I2S	0x001
-#define PLAYBACK_1_TO_SPDIF	0x004
-#define PLAYBACK_2_TO_AC97_1	0x008
-#define CAPTURE_0_FROM_I2S_1	0x010
-#define CAPTURE_0_FROM_I2S_2	0x020
-#define CAPTURE_1_FROM_SPDIF	0x080
-#define CAPTURE_2_FROM_I2S_2	0x100
-#define CAPTURE_2_FROM_AC97_1	0x200
+#define PLAYBACK_0_TO_I2S	0x0001
+     /* PLAYBACK_0_TO_AC97_0		not implemented */
+#define PLAYBACK_1_TO_SPDIF	0x0004
+#define PLAYBACK_2_TO_AC97_1	0x0008
+#define CAPTURE_0_FROM_I2S_1	0x0010
+#define CAPTURE_0_FROM_I2S_2	0x0020
+     /* CAPTURE_0_FROM_AC97_0		not implemented */
+#define CAPTURE_1_FROM_SPDIF	0x0080
+#define CAPTURE_2_FROM_I2S_2	0x0100
+#define CAPTURE_2_FROM_AC97_1	0x0200
+     /* CAPTURE_3_FROM_I2S_3		not implemented */
+#define MIDI_OUTPUT		0x0800
+#define MIDI_INPUT		0x1000
 
 enum {
 	CONTROL_SPDIF_PCM,
@@ -51,7 +56,43 @@
 struct snd_pcm_hw_params;
 struct snd_kcontrol_new;
 struct snd_rawmidi;
-struct oxygen_model;
+struct oxygen;
+
+struct oxygen_model {
+	const char *shortname;
+	const char *longname;
+	const char *chip;
+	struct module *owner;
+	int (*probe)(struct oxygen *chip, unsigned long driver_data);
+	void (*init)(struct oxygen *chip);
+	int (*control_filter)(struct snd_kcontrol_new *template);
+	int (*mixer_init)(struct oxygen *chip);
+	void (*cleanup)(struct oxygen *chip);
+	void (*suspend)(struct oxygen *chip);
+	void (*resume)(struct oxygen *chip);
+	void (*pcm_hardware_filter)(unsigned int channel,
+				    struct snd_pcm_hardware *hardware);
+	void (*set_dac_params)(struct oxygen *chip,
+			       struct snd_pcm_hw_params *params);
+	void (*set_adc_params)(struct oxygen *chip,
+			       struct snd_pcm_hw_params *params);
+	void (*update_dac_volume)(struct oxygen *chip);
+	void (*update_dac_mute)(struct oxygen *chip);
+	void (*gpio_changed)(struct oxygen *chip);
+	void (*uart_input)(struct oxygen *chip);
+	void (*ac97_switch)(struct oxygen *chip,
+			    unsigned int reg, unsigned int mute);
+	const unsigned int *dac_tlv;
+	size_t model_data_size;
+	unsigned int device_config;
+	u8 dac_channels;
+	u8 dac_volume_min;
+	u8 dac_volume_max;
+	u8 misc_flags;
+	u8 function_flags;
+	u16 dac_i2s_format;
+	u16 adc_i2s_format;
+};
 
 struct oxygen {
 	unsigned long addr;
@@ -61,7 +102,6 @@
 	struct pci_dev *pci;
 	struct snd_rawmidi *midi;
 	int irq;
-	const struct oxygen_model *model;
 	void *model_data;
 	unsigned int interrupt_mask;
 	u8 dac_volume[8];
@@ -86,46 +126,16 @@
 		__le32 _32[OXYGEN_IO_SIZE / 4];
 	} saved_registers;
 	u16 saved_ac97_registers[2][0x40];
-};
-
-struct oxygen_model {
-	const char *shortname;
-	const char *longname;
-	const char *chip;
-	struct module *owner;
-	void (*init)(struct oxygen *chip);
-	int (*control_filter)(struct snd_kcontrol_new *template);
-	int (*mixer_init)(struct oxygen *chip);
-	void (*cleanup)(struct oxygen *chip);
-	void (*suspend)(struct oxygen *chip);
-	void (*resume)(struct oxygen *chip);
-	void (*pcm_hardware_filter)(unsigned int channel,
-				    struct snd_pcm_hardware *hardware);
-	void (*set_dac_params)(struct oxygen *chip,
-			       struct snd_pcm_hw_params *params);
-	void (*set_adc_params)(struct oxygen *chip,
-			       struct snd_pcm_hw_params *params);
-	void (*update_dac_volume)(struct oxygen *chip);
-	void (*update_dac_mute)(struct oxygen *chip);
-	void (*gpio_changed)(struct oxygen *chip);
-	void (*ac97_switch)(struct oxygen *chip,
-			    unsigned int reg, unsigned int mute);
-	const unsigned int *dac_tlv;
-	size_t model_data_size;
-	unsigned int pcm_dev_cfg;
-	u8 dac_channels;
-	u8 dac_volume_min;
-	u8 dac_volume_max;
-	u8 misc_flags;
-	u8 function_flags;
-	u16 dac_i2s_format;
-	u16 adc_i2s_format;
+	unsigned int uart_input_count;
+	u8 uart_input[32];
+	struct oxygen_model model;
 };
 
 /* oxygen_lib.c */
 
 int oxygen_pci_probe(struct pci_dev *pci, int index, char *id,
-		     const struct oxygen_model *model);
+		     const struct oxygen_model *model,
+		     unsigned long driver_data);
 void oxygen_pci_remove(struct pci_dev *pci);
 #ifdef CONFIG_PM
 int oxygen_pci_suspend(struct pci_dev *pci, pm_message_t state);
@@ -167,6 +177,9 @@
 void oxygen_write_spi(struct oxygen *chip, u8 control, unsigned int data);
 void oxygen_write_i2c(struct oxygen *chip, u8 device, u8 map, u8 data);
 
+void oxygen_reset_uart(struct oxygen *chip);
+void oxygen_write_uart(struct oxygen *chip, u8 data);
+
 static inline void oxygen_set_bits8(struct oxygen *chip,
 				    unsigned int reg, u8 value)
 {
diff --git a/sound/pci/oxygen/oxygen_io.c b/sound/pci/oxygen/oxygen_io.c
index 83f135f..3126c4b 100644
--- a/sound/pci/oxygen/oxygen_io.c
+++ b/sound/pci/oxygen/oxygen_io.c
@@ -20,6 +20,7 @@
 #include <linux/delay.h>
 #include <linux/sched.h>
 #include <sound/core.h>
+#include <sound/mpu401.h>
 #include <asm/io.h>
 #include "oxygen.h"
 
@@ -232,3 +233,24 @@
 		      device | OXYGEN_2WIRE_DIR_WRITE);
 }
 EXPORT_SYMBOL(oxygen_write_i2c);
+
+static void _write_uart(struct oxygen *chip, unsigned int port, u8 data)
+{
+	if (oxygen_read8(chip, OXYGEN_MPU401 + 1) & MPU401_TX_FULL)
+		msleep(1);
+	oxygen_write8(chip, OXYGEN_MPU401 + port, data);
+}
+
+void oxygen_reset_uart(struct oxygen *chip)
+{
+	_write_uart(chip, 1, MPU401_RESET);
+	msleep(1); /* wait for ACK */
+	_write_uart(chip, 1, MPU401_ENTER_UART);
+}
+EXPORT_SYMBOL(oxygen_reset_uart);
+
+void oxygen_write_uart(struct oxygen *chip, u8 data)
+{
+	_write_uart(chip, 0, data);
+}
+EXPORT_SYMBOL(oxygen_write_uart);
diff --git a/sound/pci/oxygen/oxygen_lib.c b/sound/pci/oxygen/oxygen_lib.c
index 22f3785..84f481d 100644
--- a/sound/pci/oxygen/oxygen_lib.c
+++ b/sound/pci/oxygen/oxygen_lib.c
@@ -35,6 +35,30 @@
 MODULE_LICENSE("GPL v2");
 
 
+static inline int oxygen_uart_input_ready(struct oxygen *chip)
+{
+	return !(oxygen_read8(chip, OXYGEN_MPU401 + 1) & MPU401_RX_EMPTY);
+}
+
+static void oxygen_read_uart(struct oxygen *chip)
+{
+	if (unlikely(!oxygen_uart_input_ready(chip))) {
+		/* no data, but read it anyway to clear the interrupt */
+		oxygen_read8(chip, OXYGEN_MPU401);
+		return;
+	}
+	do {
+		u8 data = oxygen_read8(chip, OXYGEN_MPU401);
+		if (data == MPU401_ACK)
+			continue;
+		if (chip->uart_input_count >= ARRAY_SIZE(chip->uart_input))
+			chip->uart_input_count = 0;
+		chip->uart_input[chip->uart_input_count++] = data;
+	} while (oxygen_uart_input_ready(chip));
+	if (chip->model.uart_input)
+		chip->model.uart_input(chip);
+}
+
 static irqreturn_t oxygen_interrupt(int dummy, void *dev_id)
 {
 	struct oxygen *chip = dev_id;
@@ -87,8 +111,12 @@
 	if (status & OXYGEN_INT_GPIO)
 		schedule_work(&chip->gpio_work);
 
-	if ((status & OXYGEN_INT_MIDI) && chip->midi)
-		snd_mpu401_uart_interrupt(0, chip->midi->private_data);
+	if (status & OXYGEN_INT_MIDI) {
+		if (chip->midi)
+			snd_mpu401_uart_interrupt(0, chip->midi->private_data);
+		else
+			oxygen_read_uart(chip);
+	}
 
 	if (status & OXYGEN_INT_AC97)
 		wake_up(&chip->ac97_waitqueue);
@@ -161,8 +189,8 @@
 {
 	struct oxygen *chip = container_of(work, struct oxygen, gpio_work);
 
-	if (chip->model->gpio_changed)
-		chip->model->gpio_changed(chip);
+	if (chip->model.gpio_changed)
+		chip->model.gpio_changed(chip);
 }
 
 #ifdef CONFIG_PROC_FS
@@ -221,7 +249,7 @@
 
 	chip->dac_routing = 1;
 	for (i = 0; i < 8; ++i)
-		chip->dac_volume[i] = chip->model->dac_volume_min;
+		chip->dac_volume[i] = chip->model.dac_volume_min;
 	chip->dac_mute = 1;
 	chip->spdif_playback_enable = 1;
 	chip->spdif_bits = OXYGEN_SPDIF_C | OXYGEN_SPDIF_ORIGINAL |
@@ -243,7 +271,7 @@
 
 	oxygen_write8_masked(chip, OXYGEN_FUNCTION,
 			     OXYGEN_FUNCTION_RESET_CODEC |
-			     chip->model->function_flags,
+			     chip->model.function_flags,
 			     OXYGEN_FUNCTION_RESET_CODEC |
 			     OXYGEN_FUNCTION_2WIRE_SPI_MASK |
 			     OXYGEN_FUNCTION_ENABLE_SPI_4_5);
@@ -255,7 +283,7 @@
 		      OXYGEN_DMA_MULTICH_BURST_8);
 	oxygen_write16(chip, OXYGEN_INTERRUPT_MASK, 0);
 	oxygen_write8_masked(chip, OXYGEN_MISC,
-			     chip->model->misc_flags,
+			     chip->model.misc_flags,
 			     OXYGEN_MISC_WRITE_PCI_SUBID |
 			     OXYGEN_MISC_REC_C_FROM_SPDIF |
 			     OXYGEN_MISC_REC_B_FROM_AC97 |
@@ -270,21 +298,21 @@
 		      (OXYGEN_FORMAT_16 << OXYGEN_MULTICH_FORMAT_SHIFT));
 	oxygen_write8(chip, OXYGEN_REC_CHANNELS, OXYGEN_REC_CHANNELS_2_2_2);
 	oxygen_write16(chip, OXYGEN_I2S_MULTICH_FORMAT,
-		       OXYGEN_RATE_48000 | chip->model->dac_i2s_format |
+		       OXYGEN_RATE_48000 | chip->model.dac_i2s_format |
 		       OXYGEN_I2S_MCLK_256 | OXYGEN_I2S_BITS_16 |
 		       OXYGEN_I2S_MASTER | OXYGEN_I2S_BCLK_64);
-	if (chip->model->pcm_dev_cfg & CAPTURE_0_FROM_I2S_1)
+	if (chip->model.device_config & CAPTURE_0_FROM_I2S_1)
 		oxygen_write16(chip, OXYGEN_I2S_A_FORMAT,
-			       OXYGEN_RATE_48000 | chip->model->adc_i2s_format |
+			       OXYGEN_RATE_48000 | chip->model.adc_i2s_format |
 			       OXYGEN_I2S_MCLK_256 | OXYGEN_I2S_BITS_16 |
 			       OXYGEN_I2S_MASTER | OXYGEN_I2S_BCLK_64);
 	else
 		oxygen_write16(chip, OXYGEN_I2S_A_FORMAT,
 			       OXYGEN_I2S_MASTER | OXYGEN_I2S_MUTE_MCLK);
-	if (chip->model->pcm_dev_cfg & (CAPTURE_0_FROM_I2S_2 |
-					CAPTURE_2_FROM_I2S_2))
+	if (chip->model.device_config & (CAPTURE_0_FROM_I2S_2 |
+					 CAPTURE_2_FROM_I2S_2))
 		oxygen_write16(chip, OXYGEN_I2S_B_FORMAT,
-			       OXYGEN_RATE_48000 | chip->model->adc_i2s_format |
+			       OXYGEN_RATE_48000 | chip->model.adc_i2s_format |
 			       OXYGEN_I2S_MCLK_256 | OXYGEN_I2S_BITS_16 |
 			       OXYGEN_I2S_MASTER | OXYGEN_I2S_BCLK_64);
 	else
@@ -295,7 +323,7 @@
 	oxygen_clear_bits32(chip, OXYGEN_SPDIF_CONTROL,
 			    OXYGEN_SPDIF_OUT_ENABLE |
 			    OXYGEN_SPDIF_LOOPBACK);
-	if (chip->model->pcm_dev_cfg & CAPTURE_1_FROM_SPDIF)
+	if (chip->model.device_config & CAPTURE_1_FROM_SPDIF)
 		oxygen_write32_masked(chip, OXYGEN_SPDIF_CONTROL,
 				      OXYGEN_SPDIF_SENSE_MASK |
 				      OXYGEN_SPDIF_LOCK_MASK |
@@ -417,14 +445,15 @@
 	if (chip->irq >= 0)
 		free_irq(chip->irq, chip);
 	flush_scheduled_work();
-	chip->model->cleanup(chip);
+	chip->model.cleanup(chip);
 	mutex_destroy(&chip->mutex);
 	pci_release_regions(chip->pci);
 	pci_disable_device(chip->pci);
 }
 
 int oxygen_pci_probe(struct pci_dev *pci, int index, char *id,
-		     const struct oxygen_model *model)
+		     const struct oxygen_model *model,
+		     unsigned long driver_data)
 {
 	struct snd_card *card;
 	struct oxygen *chip;
@@ -439,7 +468,7 @@
 	chip->card = card;
 	chip->pci = pci;
 	chip->irq = -1;
-	chip->model = model;
+	chip->model = *model;
 	chip->model_data = chip + 1;
 	spin_lock_init(&chip->reg_lock);
 	mutex_init(&chip->mutex);
@@ -470,23 +499,28 @@
 	snd_card_set_dev(card, &pci->dev);
 	card->private_free = oxygen_card_free;
 
+	if (chip->model.probe) {
+		err = chip->model.probe(chip, driver_data);
+		if (err < 0)
+			goto err_card;
+	}
 	oxygen_init(chip);
-	model->init(chip);
+	chip->model.init(chip);
 
 	err = request_irq(pci->irq, oxygen_interrupt, IRQF_SHARED,
-			  model->chip, chip);
+			  chip->model.chip, chip);
 	if (err < 0) {
 		snd_printk(KERN_ERR "cannot grab interrupt %d\n", pci->irq);
 		goto err_card;
 	}
 	chip->irq = pci->irq;
 
-	strcpy(card->driver, model->chip);
-	strcpy(card->shortname, model->shortname);
+	strcpy(card->driver, chip->model.chip);
+	strcpy(card->shortname, chip->model.shortname);
 	sprintf(card->longname, "%s (rev %u) at %#lx, irq %i",
-		model->longname, chip->revision, chip->addr, chip->irq);
-	strcpy(card->mixername, model->chip);
-	snd_component_add(card, model->chip);
+		chip->model.longname, chip->revision, chip->addr, chip->irq);
+	strcpy(card->mixername, chip->model.chip);
+	snd_component_add(card, chip->model.chip);
 
 	err = oxygen_pcm_init(chip);
 	if (err < 0)
@@ -496,10 +530,15 @@
 	if (err < 0)
 		goto err_card;
 
-	if (model->misc_flags & OXYGEN_MISC_MIDI) {
+	if (chip->model.device_config & (MIDI_OUTPUT | MIDI_INPUT)) {
+		unsigned int info_flags = MPU401_INFO_INTEGRATED;
+		if (chip->model.device_config & MIDI_OUTPUT)
+			info_flags |= MPU401_INFO_OUTPUT;
+		if (chip->model.device_config & MIDI_INPUT)
+			info_flags |= MPU401_INFO_INPUT;
 		err = snd_mpu401_uart_new(card, 0, MPU401_HW_CMIPCI,
 					  chip->addr + OXYGEN_MPU401,
-					  MPU401_INFO_INTEGRATED, 0, 0,
+					  info_flags, 0, 0,
 					  &chip->midi);
 		if (err < 0)
 			goto err_card;
@@ -508,7 +547,7 @@
 	oxygen_proc_init(chip);
 
 	spin_lock_irq(&chip->reg_lock);
-	if (chip->model->pcm_dev_cfg & CAPTURE_1_FROM_SPDIF)
+	if (chip->model.device_config & CAPTURE_1_FROM_SPDIF)
 		chip->interrupt_mask |= OXYGEN_INT_SPDIF_IN_DETECT;
 	if (chip->has_ac97_0 | chip->has_ac97_1)
 		chip->interrupt_mask |= OXYGEN_INT_AC97;
@@ -552,8 +591,8 @@
 		if (chip->streams[i])
 			snd_pcm_suspend(chip->streams[i]);
 
-	if (chip->model->suspend)
-		chip->model->suspend(chip);
+	if (chip->model.suspend)
+		chip->model.suspend(chip);
 
 	spin_lock_irq(&chip->reg_lock);
 	saved_interrupt_mask = chip->interrupt_mask;
@@ -624,8 +663,8 @@
 	if (chip->has_ac97_1)
 		oxygen_restore_ac97(chip, 1);
 
-	if (chip->model->resume)
-		chip->model->resume(chip);
+	if (chip->model.resume)
+		chip->model.resume(chip);
 
 	oxygen_write16(chip, OXYGEN_INTERRUPT_MASK, chip->interrupt_mask);
 
diff --git a/sound/pci/oxygen/oxygen_mixer.c b/sound/pci/oxygen/oxygen_mixer.c
index 05eb899..304da16 100644
--- a/sound/pci/oxygen/oxygen_mixer.c
+++ b/sound/pci/oxygen/oxygen_mixer.c
@@ -31,9 +31,9 @@
 	struct oxygen *chip = ctl->private_data;
 
 	info->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
-	info->count = chip->model->dac_channels;
-	info->value.integer.min = chip->model->dac_volume_min;
-	info->value.integer.max = chip->model->dac_volume_max;
+	info->count = chip->model.dac_channels;
+	info->value.integer.min = chip->model.dac_volume_min;
+	info->value.integer.max = chip->model.dac_volume_max;
 	return 0;
 }
 
@@ -44,7 +44,7 @@
 	unsigned int i;
 
 	mutex_lock(&chip->mutex);
-	for (i = 0; i < chip->model->dac_channels; ++i)
+	for (i = 0; i < chip->model.dac_channels; ++i)
 		value->value.integer.value[i] = chip->dac_volume[i];
 	mutex_unlock(&chip->mutex);
 	return 0;
@@ -59,13 +59,13 @@
 
 	changed = 0;
 	mutex_lock(&chip->mutex);
-	for (i = 0; i < chip->model->dac_channels; ++i)
+	for (i = 0; i < chip->model.dac_channels; ++i)
 		if (value->value.integer.value[i] != chip->dac_volume[i]) {
 			chip->dac_volume[i] = value->value.integer.value[i];
 			changed = 1;
 		}
 	if (changed)
-		chip->model->update_dac_volume(chip);
+		chip->model.update_dac_volume(chip);
 	mutex_unlock(&chip->mutex);
 	return changed;
 }
@@ -91,7 +91,7 @@
 	changed = !value->value.integer.value[0] != chip->dac_mute;
 	if (changed) {
 		chip->dac_mute = !value->value.integer.value[0];
-		chip->model->update_dac_mute(chip);
+		chip->model.update_dac_mute(chip);
 	}
 	mutex_unlock(&chip->mutex);
 	return changed;
@@ -103,7 +103,7 @@
 		"Front", "Front+Surround", "Front+Surround+Back"
 	};
 	struct oxygen *chip = ctl->private_data;
-	unsigned int count = 2 + (chip->model->dac_channels == 8);
+	unsigned int count = 2 + (chip->model.dac_channels == 8);
 
 	info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
 	info->count = 1;
@@ -172,7 +172,7 @@
 static int upmix_put(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value)
 {
 	struct oxygen *chip = ctl->private_data;
-	unsigned int count = 2 + (chip->model->dac_channels == 8);
+	unsigned int count = 2 + (chip->model.dac_channels == 8);
 	int changed;
 
 	mutex_lock(&chip->mutex);
@@ -211,13 +211,13 @@
 	case OXYGEN_RATE_64000:
 		return 0xb << OXYGEN_SPDIF_CS_RATE_SHIFT;
 	case OXYGEN_RATE_88200:
-		return 0x8 << OXYGEN_SPDIF_CS_RATE_SHIFT;
+		return IEC958_AES3_CON_FS_88200 << OXYGEN_SPDIF_CS_RATE_SHIFT;
 	case OXYGEN_RATE_96000:
-		return 0xa << OXYGEN_SPDIF_CS_RATE_SHIFT;
+		return IEC958_AES3_CON_FS_96000 << OXYGEN_SPDIF_CS_RATE_SHIFT;
 	case OXYGEN_RATE_176400:
-		return 0xc << OXYGEN_SPDIF_CS_RATE_SHIFT;
+		return IEC958_AES3_CON_FS_176400 << OXYGEN_SPDIF_CS_RATE_SHIFT;
 	case OXYGEN_RATE_192000:
-		return 0xe << OXYGEN_SPDIF_CS_RATE_SHIFT;
+		return IEC958_AES3_CON_FS_192000 << OXYGEN_SPDIF_CS_RATE_SHIFT;
 	}
 }
 
@@ -521,8 +521,8 @@
 	value = oxygen_read_ac97(chip, 0, priv_idx);
 	if (!(value & 0x8000)) {
 		oxygen_write_ac97(chip, 0, priv_idx, value | 0x8000);
-		if (chip->model->ac97_switch)
-			chip->model->ac97_switch(chip, priv_idx, 0x8000);
+		if (chip->model.ac97_switch)
+			chip->model.ac97_switch(chip, priv_idx, 0x8000);
 		snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE,
 			       &chip->controls[control]->id);
 	}
@@ -549,8 +549,8 @@
 	change = newreg != oldreg;
 	if (change) {
 		oxygen_write_ac97(chip, codec, index, newreg);
-		if (codec == 0 && chip->model->ac97_switch)
-			chip->model->ac97_switch(chip, index, newreg & 0x8000);
+		if (codec == 0 && chip->model.ac97_switch)
+			chip->model.ac97_switch(chip, index, newreg & 0x8000);
 		if (index == AC97_LINE) {
 			oxygen_write_ac97_masked(chip, 0, CM9780_GPIO_STATUS,
 						 newreg & 0x8000 ?
@@ -939,16 +939,16 @@
 
 	for (i = 0; i < count; ++i) {
 		template = controls[i];
-		if (chip->model->control_filter) {
-			err = chip->model->control_filter(&template);
+		if (chip->model.control_filter) {
+			err = chip->model.control_filter(&template);
 			if (err < 0)
 				return err;
 			if (err == 1)
 				continue;
 		}
 		if (!strcmp(template.name, "Master Playback Volume") &&
-		    chip->model->dac_tlv) {
-			template.tlv.p = chip->model->dac_tlv;
+		    chip->model.dac_tlv) {
+			template.tlv.p = chip->model.dac_tlv;
 			template.access |= SNDRV_CTL_ELEM_ACCESS_TLV_READ;
 		}
 		ctl = snd_ctl_new1(&template, chip);
@@ -974,14 +974,14 @@
 	err = add_controls(chip, controls, ARRAY_SIZE(controls));
 	if (err < 0)
 		return err;
-	if (chip->model->pcm_dev_cfg & CAPTURE_1_FROM_SPDIF) {
+	if (chip->model.device_config & CAPTURE_1_FROM_SPDIF) {
 		err = add_controls(chip, spdif_input_controls,
 				   ARRAY_SIZE(spdif_input_controls));
 		if (err < 0)
 			return err;
 	}
 	for (i = 0; i < ARRAY_SIZE(monitor_controls); ++i) {
-		if (!(chip->model->pcm_dev_cfg & monitor_controls[i].pcm_dev))
+		if (!(chip->model.device_config & monitor_controls[i].pcm_dev))
 			continue;
 		err = add_controls(chip, monitor_controls[i].controls,
 				   ARRAY_SIZE(monitor_controls[i].controls));
@@ -1000,5 +1000,5 @@
 		if (err < 0)
 			return err;
 	}
-	return chip->model->mixer_init ? chip->model->mixer_init(chip) : 0;
+	return chip->model.mixer_init ? chip->model.mixer_init(chip) : 0;
 }
diff --git a/sound/pci/oxygen/oxygen_pcm.c b/sound/pci/oxygen/oxygen_pcm.c
index c4ad65a..c262049 100644
--- a/sound/pci/oxygen/oxygen_pcm.c
+++ b/sound/pci/oxygen/oxygen_pcm.c
@@ -129,7 +129,7 @@
 
 	runtime->private_data = (void *)(uintptr_t)channel;
 	if (channel == PCM_B && chip->has_ac97_1 &&
-	    (chip->model->pcm_dev_cfg & CAPTURE_2_FROM_AC97_1))
+	    (chip->model.device_config & CAPTURE_2_FROM_AC97_1))
 		runtime->hw = oxygen_ac97_hardware;
 	else
 		runtime->hw = *oxygen_hardware[channel];
@@ -140,11 +140,11 @@
 		runtime->hw.rate_min = 44100;
 		break;
 	case PCM_MULTICH:
-		runtime->hw.channels_max = chip->model->dac_channels;
+		runtime->hw.channels_max = chip->model.dac_channels;
 		break;
 	}
-	if (chip->model->pcm_hardware_filter)
-		chip->model->pcm_hardware_filter(channel, &runtime->hw);
+	if (chip->model.pcm_hardware_filter)
+		chip->model.pcm_hardware_filter(channel, &runtime->hw);
 	err = snd_pcm_hw_constraint_step(runtime, 0,
 					 SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 32);
 	if (err < 0)
@@ -355,7 +355,7 @@
 	oxygen_write16_masked(chip, OXYGEN_I2S_A_FORMAT,
 			      oxygen_rate(hw_params) |
 			      oxygen_i2s_mclk(hw_params) |
-			      chip->model->adc_i2s_format |
+			      chip->model.adc_i2s_format |
 			      oxygen_i2s_bits(hw_params),
 			      OXYGEN_I2S_RATE_MASK |
 			      OXYGEN_I2S_FORMAT_MASK |
@@ -364,7 +364,7 @@
 	spin_unlock_irq(&chip->reg_lock);
 
 	mutex_lock(&chip->mutex);
-	chip->model->set_adc_params(chip, hw_params);
+	chip->model.set_adc_params(chip, hw_params);
 	mutex_unlock(&chip->mutex);
 	return 0;
 }
@@ -381,7 +381,7 @@
 		return err;
 
 	is_ac97 = chip->has_ac97_1 &&
-		(chip->model->pcm_dev_cfg & CAPTURE_2_FROM_AC97_1);
+		(chip->model.device_config & CAPTURE_2_FROM_AC97_1);
 
 	spin_lock_irq(&chip->reg_lock);
 	oxygen_write8_masked(chip, OXYGEN_REC_FORMAT,
@@ -391,7 +391,7 @@
 		oxygen_write16_masked(chip, OXYGEN_I2S_B_FORMAT,
 				      oxygen_rate(hw_params) |
 				      oxygen_i2s_mclk(hw_params) |
-				      chip->model->adc_i2s_format |
+				      chip->model.adc_i2s_format |
 				      oxygen_i2s_bits(hw_params),
 				      OXYGEN_I2S_RATE_MASK |
 				      OXYGEN_I2S_FORMAT_MASK |
@@ -401,7 +401,7 @@
 
 	if (!is_ac97) {
 		mutex_lock(&chip->mutex);
-		chip->model->set_adc_params(chip, hw_params);
+		chip->model.set_adc_params(chip, hw_params);
 		mutex_unlock(&chip->mutex);
 	}
 	return 0;
@@ -468,7 +468,7 @@
 			     OXYGEN_MULTICH_FORMAT_MASK);
 	oxygen_write16_masked(chip, OXYGEN_I2S_MULTICH_FORMAT,
 			      oxygen_rate(hw_params) |
-			      chip->model->dac_i2s_format |
+			      chip->model.dac_i2s_format |
 			      oxygen_i2s_bits(hw_params),
 			      OXYGEN_I2S_RATE_MASK |
 			      OXYGEN_I2S_FORMAT_MASK |
@@ -478,7 +478,7 @@
 	spin_unlock_irq(&chip->reg_lock);
 
 	mutex_lock(&chip->mutex);
-	chip->model->set_dac_params(chip, hw_params);
+	chip->model.set_dac_params(chip, hw_params);
 	mutex_unlock(&chip->mutex);
 	return 0;
 }
@@ -657,25 +657,26 @@
 	int outs, ins;
 	int err;
 
-	outs = !!(chip->model->pcm_dev_cfg & PLAYBACK_0_TO_I2S);
-	ins = !!(chip->model->pcm_dev_cfg & (CAPTURE_0_FROM_I2S_1 |
-					     CAPTURE_0_FROM_I2S_2));
+	outs = !!(chip->model.device_config & PLAYBACK_0_TO_I2S);
+	ins = !!(chip->model.device_config & (CAPTURE_0_FROM_I2S_1 |
+					      CAPTURE_0_FROM_I2S_2));
 	if (outs | ins) {
-		err = snd_pcm_new(chip->card, "Analog", 0, outs, ins, &pcm);
+		err = snd_pcm_new(chip->card, "Multichannel",
+				  0, outs, ins, &pcm);
 		if (err < 0)
 			return err;
 		if (outs)
 			snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
 					&oxygen_multich_ops);
-		if (chip->model->pcm_dev_cfg & CAPTURE_0_FROM_I2S_1)
+		if (chip->model.device_config & CAPTURE_0_FROM_I2S_1)
 			snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
 					&oxygen_rec_a_ops);
-		else if (chip->model->pcm_dev_cfg & CAPTURE_0_FROM_I2S_2)
+		else if (chip->model.device_config & CAPTURE_0_FROM_I2S_2)
 			snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
 					&oxygen_rec_b_ops);
 		pcm->private_data = chip;
 		pcm->private_free = oxygen_pcm_free;
-		strcpy(pcm->name, "Analog");
+		strcpy(pcm->name, "Multichannel");
 		if (outs)
 			snd_pcm_lib_preallocate_pages(pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream,
 						      SNDRV_DMA_TYPE_DEV,
@@ -690,8 +691,8 @@
 						      BUFFER_BYTES_MAX);
 	}
 
-	outs = !!(chip->model->pcm_dev_cfg & PLAYBACK_1_TO_SPDIF);
-	ins = !!(chip->model->pcm_dev_cfg & CAPTURE_1_FROM_SPDIF);
+	outs = !!(chip->model.device_config & PLAYBACK_1_TO_SPDIF);
+	ins = !!(chip->model.device_config & CAPTURE_1_FROM_SPDIF);
 	if (outs | ins) {
 		err = snd_pcm_new(chip->card, "Digital", 1, outs, ins, &pcm);
 		if (err < 0)
@@ -712,11 +713,11 @@
 	}
 
 	if (chip->has_ac97_1) {
-		outs = !!(chip->model->pcm_dev_cfg & PLAYBACK_2_TO_AC97_1);
-		ins = !!(chip->model->pcm_dev_cfg & CAPTURE_2_FROM_AC97_1);
+		outs = !!(chip->model.device_config & PLAYBACK_2_TO_AC97_1);
+		ins = !!(chip->model.device_config & CAPTURE_2_FROM_AC97_1);
 	} else {
 		outs = 0;
-		ins = !!(chip->model->pcm_dev_cfg & CAPTURE_2_FROM_I2S_2);
+		ins = !!(chip->model.device_config & CAPTURE_2_FROM_I2S_2);
 	}
 	if (outs | ins) {
 		err = snd_pcm_new(chip->card, outs ? "AC97" : "Analog2",
diff --git a/sound/pci/oxygen/virtuoso.c b/sound/pci/oxygen/virtuoso.c
index 01d7b75..98c6a8c 100644
--- a/sound/pci/oxygen/virtuoso.c
+++ b/sound/pci/oxygen/virtuoso.c
@@ -62,14 +62,66 @@
  * AD0 <- 0
  */
 
+/*
+ * Xonar HDAV1.3 (Deluxe)
+ * ----------------------
+ *
+ * CMI8788:
+ *
+ * I²C <-> PCM1796 (front)
+ *
+ * GPI 0 <- external power present
+ *
+ * GPIO 0 -> enable output to speakers
+ * GPIO 2 -> M0 of CS5381
+ * GPIO 3 -> M1 of CS5381
+ * GPIO 8 -> route input jack to line-in (0) or mic-in (1)
+ *
+ * TXD -> HDMI controller
+ * RXD <- HDMI controller
+ *
+ * PCM1796 front: AD1,0 <- 0,0
+ *
+ * no daughterboard
+ * ----------------
+ *
+ * GPIO 4 <- 1
+ *
+ * H6 daughterboard
+ * ----------------
+ *
+ * GPIO 4 <- 0
+ * GPIO 5 <- 0
+ *
+ * I²C <-> PCM1796 (surround)
+ *     <-> PCM1796 (center/LFE)
+ *     <-> PCM1796 (back)
+ *
+ * PCM1796 surround:   AD1,0 <- 0,1
+ * PCM1796 center/LFE: AD1,0 <- 1,0
+ * PCM1796 back:       AD1,0 <- 1,1
+ *
+ * unknown daughterboard
+ * ---------------------
+ *
+ * GPIO 4 <- 0
+ * GPIO 5 <- 1
+ *
+ * I²C <-> CS4362A (surround, center/LFE, back)
+ *
+ * CS4362A: AD0 <- 0
+ */
+
 #include <linux/pci.h>
 #include <linux/delay.h>
 #include <linux/mutex.h>
 #include <sound/ac97_codec.h>
+#include <sound/asoundef.h>
 #include <sound/control.h>
 #include <sound/core.h>
 #include <sound/initval.h>
 #include <sound/pcm.h>
+#include <sound/pcm_params.h>
 #include <sound/tlv.h>
 #include "oxygen.h"
 #include "cm9780.h"
@@ -98,12 +150,15 @@
 	MODEL_D2X,
 	MODEL_D1,
 	MODEL_DX,
+	MODEL_HDAV,	/* without daughterboard */
+	MODEL_HDAV_H6,	/* with H6 daughterboard */
 };
 
 static struct pci_device_id xonar_ids[] __devinitdata = {
 	{ OXYGEN_PCI_SUBID(0x1043, 0x8269), .driver_data = MODEL_D2 },
 	{ OXYGEN_PCI_SUBID(0x1043, 0x8275), .driver_data = MODEL_DX },
 	{ OXYGEN_PCI_SUBID(0x1043, 0x82b7), .driver_data = MODEL_D2X },
+	{ OXYGEN_PCI_SUBID(0x1043, 0x8314), .driver_data = MODEL_HDAV },
 	{ OXYGEN_PCI_SUBID(0x1043, 0x834f), .driver_data = MODEL_D1 },
 	{ }
 };
@@ -124,11 +179,18 @@
 #define GPIO_DX_FRONT_PANEL	0x0002
 #define GPIO_DX_INPUT_ROUTE	0x0100
 
+#define GPIO_HDAV_DB_MASK	0x0030
+#define GPIO_HDAV_DB_H6		0x0000
+#define GPIO_HDAV_DB_XX		0x0020
+
+#define I2C_DEVICE_PCM1796(i)	(0x98 + ((i) << 1))	/* 10011, ADx=i, /W=0 */
 #define I2C_DEVICE_CS4398	0x9e	/* 10011, AD1=1, AD0=1, /W=0 */
 #define I2C_DEVICE_CS4362A	0x30	/* 001100, AD0=0, /W=0 */
 
 struct xonar_data {
+	unsigned int model;
 	unsigned int anti_pop_delay;
+	unsigned int dacs;
 	u16 output_enable_bit;
 	u8 ext_power_reg;
 	u8 ext_power_int_reg;
@@ -137,10 +199,13 @@
 	u8 pcm1796_oversampling;
 	u8 cs4398_fm;
 	u8 cs4362a_fm;
+	u8 hdmi_params[5];
 };
 
-static void pcm1796_write(struct oxygen *chip, unsigned int codec,
-			  u8 reg, u8 value)
+static void xonar_gpio_changed(struct oxygen *chip);
+
+static inline void pcm1796_write_spi(struct oxygen *chip, unsigned int codec,
+				     u8 reg, u8 value)
 {
 	/* maps ALSA channel pair number to SPI output */
 	static const u8 codec_map[4] = {
@@ -154,6 +219,22 @@
 			 (reg << 8) | value);
 }
 
+static inline void pcm1796_write_i2c(struct oxygen *chip, unsigned int codec,
+				     u8 reg, u8 value)
+{
+	oxygen_write_i2c(chip, I2C_DEVICE_PCM1796(codec), reg, value);
+}
+
+static void pcm1796_write(struct oxygen *chip, unsigned int codec,
+			  u8 reg, u8 value)
+{
+	if ((chip->model.function_flags & OXYGEN_FUNCTION_2WIRE_SPI_MASK) ==
+	    OXYGEN_FUNCTION_SPI)
+		pcm1796_write_spi(chip, codec, reg, value);
+	else
+		pcm1796_write_i2c(chip, codec, reg, value);
+}
+
 static void cs4398_write(struct oxygen *chip, u8 reg, u8 value)
 {
 	oxygen_write_i2c(chip, I2C_DEVICE_CS4398, reg, value);
@@ -164,6 +245,24 @@
 	oxygen_write_i2c(chip, I2C_DEVICE_CS4362A, reg, value);
 }
 
+static void hdmi_write_command(struct oxygen *chip, u8 command,
+			       unsigned int count, const u8 *params)
+{
+	unsigned int i;
+	u8 checksum;
+
+	oxygen_write_uart(chip, 0xfb);
+	oxygen_write_uart(chip, 0xef);
+	oxygen_write_uart(chip, command);
+	oxygen_write_uart(chip, count);
+	for (i = 0; i < count; ++i)
+		oxygen_write_uart(chip, params[i]);
+	checksum = 0xfb + 0xef + command + count;
+	for (i = 0; i < count; ++i)
+		checksum += params[i];
+	oxygen_write_uart(chip, checksum);
+}
+
 static void xonar_enable_output(struct oxygen *chip)
 {
 	struct xonar_data *data = chip->model_data;
@@ -180,6 +279,7 @@
 		oxygen_set_bits8(chip, data->ext_power_int_reg,
 				 data->ext_power_bit);
 		chip->interrupt_mask |= OXYGEN_INT_GPIO;
+		chip->model.gpio_changed = xonar_gpio_changed;
 		data->has_power = !!(oxygen_read8(chip, data->ext_power_reg)
 				     & data->ext_power_bit);
 	}
@@ -193,9 +293,10 @@
 
 static void update_pcm1796_volume(struct oxygen *chip)
 {
+	struct xonar_data *data = chip->model_data;
 	unsigned int i;
 
-	for (i = 0; i < 4; ++i) {
+	for (i = 0; i < data->dacs; ++i) {
 		pcm1796_write(chip, i, 16, chip->dac_volume[i * 2]);
 		pcm1796_write(chip, i, 17, chip->dac_volume[i * 2 + 1]);
 	}
@@ -203,13 +304,14 @@
 
 static void update_pcm1796_mute(struct oxygen *chip)
 {
+	struct xonar_data *data = chip->model_data;
 	unsigned int i;
 	u8 value;
 
 	value = PCM1796_DMF_DISABLED | PCM1796_FMT_24_LJUST | PCM1796_ATLD;
 	if (chip->dac_mute)
 		value |= PCM1796_MUTE;
-	for (i = 0; i < 4; ++i)
+	for (i = 0; i < data->dacs; ++i)
 		pcm1796_write(chip, i, 18, value);
 }
 
@@ -218,7 +320,7 @@
 	struct xonar_data *data = chip->model_data;
 	unsigned int i;
 
-	for (i = 0; i < 4; ++i) {
+	for (i = 0; i < data->dacs; ++i) {
 		pcm1796_write(chip, i, 19, PCM1796_FLT_SHARP | PCM1796_ATS_1);
 		pcm1796_write(chip, i, 20, data->pcm1796_oversampling);
 		pcm1796_write(chip, i, 21, 0);
@@ -234,6 +336,13 @@
 	data->anti_pop_delay = 300;
 	data->output_enable_bit = GPIO_D2_OUTPUT_ENABLE;
 	data->pcm1796_oversampling = PCM1796_OS_64;
+	if (data->model == MODEL_D2X) {
+		data->ext_power_reg = OXYGEN_GPIO_DATA;
+		data->ext_power_int_reg = OXYGEN_GPIO_INTERRUPT_MASK;
+		data->ext_power_bit = GPIO_D2X_EXT_POWER;
+		oxygen_clear_bits16(chip, OXYGEN_GPIO_CONTROL,
+				    GPIO_D2X_EXT_POWER);
+	}
 
 	pcm1796_init(chip);
 
@@ -246,17 +355,6 @@
 	snd_component_add(chip->card, "CS5381");
 }
 
-static void xonar_d2x_init(struct oxygen *chip)
-{
-	struct xonar_data *data = chip->model_data;
-
-	data->ext_power_reg = OXYGEN_GPIO_DATA;
-	data->ext_power_int_reg = OXYGEN_GPIO_INTERRUPT_MASK;
-	data->ext_power_bit = GPIO_D2X_EXT_POWER;
-	oxygen_clear_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_D2X_EXT_POWER);
-	xonar_d2_init(chip);
-}
-
 static void update_cs4362a_volumes(struct oxygen *chip)
 {
 	u8 mute;
@@ -324,6 +422,11 @@
 	data->cs4398_fm = CS4398_FM_SINGLE | CS4398_DEM_NONE | CS4398_DIF_LJUST;
 	data->cs4362a_fm = CS4362A_FM_SINGLE |
 		CS4362A_ATAPI_B_R | CS4362A_ATAPI_A_L;
+	if (data->model == MODEL_DX) {
+		data->ext_power_reg = OXYGEN_GPI_DATA;
+		data->ext_power_int_reg = OXYGEN_GPI_INTERRUPT_MASK;
+		data->ext_power_bit = GPI_DX_EXT_POWER;
+	}
 
 	oxygen_write16(chip, OXYGEN_2WIRE_BUS_STATUS,
 		       OXYGEN_2WIRE_LENGTH_8 |
@@ -344,30 +447,86 @@
 	snd_component_add(chip->card, "CS5361");
 }
 
-static void xonar_dx_init(struct oxygen *chip)
+static void xonar_hdav_init(struct oxygen *chip)
 {
 	struct xonar_data *data = chip->model_data;
+	u8 param;
 
+	oxygen_write16(chip, OXYGEN_2WIRE_BUS_STATUS,
+		       OXYGEN_2WIRE_LENGTH_8 |
+		       OXYGEN_2WIRE_INTERRUPT_MASK |
+		       OXYGEN_2WIRE_SPEED_FAST);
+
+	data->anti_pop_delay = 100;
+	data->output_enable_bit = GPIO_DX_OUTPUT_ENABLE;
 	data->ext_power_reg = OXYGEN_GPI_DATA;
 	data->ext_power_int_reg = OXYGEN_GPI_INTERRUPT_MASK;
 	data->ext_power_bit = GPI_DX_EXT_POWER;
-	xonar_d1_init(chip);
+	data->pcm1796_oversampling = PCM1796_OS_64;
+
+	pcm1796_init(chip);
+
+	oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_DX_INPUT_ROUTE);
+	oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, GPIO_DX_INPUT_ROUTE);
+
+	oxygen_reset_uart(chip);
+	param = 0;
+	hdmi_write_command(chip, 0x61, 1, &param);
+	param = 1;
+	hdmi_write_command(chip, 0x74, 1, &param);
+	data->hdmi_params[1] = IEC958_AES3_CON_FS_48000;
+	data->hdmi_params[4] = 1;
+	hdmi_write_command(chip, 0x54, 5, data->hdmi_params);
+
+	xonar_common_init(chip);
+
+	snd_component_add(chip->card, "PCM1796");
+	snd_component_add(chip->card, "CS5381");
 }
 
-static void xonar_cleanup(struct oxygen *chip)
+static void xonar_disable_output(struct oxygen *chip)
 {
 	struct xonar_data *data = chip->model_data;
 
 	oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, data->output_enable_bit);
 }
 
+static void xonar_d2_cleanup(struct oxygen *chip)
+{
+	xonar_disable_output(chip);
+}
+
 static void xonar_d1_cleanup(struct oxygen *chip)
 {
-	xonar_cleanup(chip);
+	xonar_disable_output(chip);
 	cs4362a_write(chip, 0x01, CS4362A_PDN | CS4362A_CPEN);
 	oxygen_clear_bits8(chip, OXYGEN_FUNCTION, OXYGEN_FUNCTION_RESET_CODEC);
 }
 
+static void xonar_hdav_cleanup(struct oxygen *chip)
+{
+	u8 param = 0;
+
+	hdmi_write_command(chip, 0x74, 1, &param);
+	xonar_disable_output(chip);
+}
+
+static void xonar_d2_suspend(struct oxygen *chip)
+{
+	xonar_d2_cleanup(chip);
+}
+
+static void xonar_d1_suspend(struct oxygen *chip)
+{
+	xonar_d1_cleanup(chip);
+}
+
+static void xonar_hdav_suspend(struct oxygen *chip)
+{
+	xonar_hdav_cleanup(chip);
+	msleep(2);
+}
+
 static void xonar_d2_resume(struct oxygen *chip)
 {
 	pcm1796_init(chip);
@@ -380,6 +539,33 @@
 	xonar_enable_output(chip);
 }
 
+static void xonar_hdav_resume(struct oxygen *chip)
+{
+	struct xonar_data *data = chip->model_data;
+	u8 param;
+
+	oxygen_reset_uart(chip);
+	param = 0;
+	hdmi_write_command(chip, 0x61, 1, &param);
+	param = 1;
+	hdmi_write_command(chip, 0x74, 1, &param);
+	hdmi_write_command(chip, 0x54, 5, data->hdmi_params);
+	pcm1796_init(chip);
+	xonar_enable_output(chip);
+}
+
+static void xonar_hdav_pcm_hardware_filter(unsigned int channel,
+					   struct snd_pcm_hardware *hardware)
+{
+	if (channel == PCM_MULTICH) {
+		hardware->rates = SNDRV_PCM_RATE_44100 |
+				  SNDRV_PCM_RATE_48000 |
+				  SNDRV_PCM_RATE_96000 |
+				  SNDRV_PCM_RATE_192000;
+		hardware->rate_min = 44100;
+	}
+}
+
 static void set_pcm1796_params(struct oxygen *chip,
 			       struct snd_pcm_hw_params *params)
 {
@@ -388,7 +574,7 @@
 
 	data->pcm1796_oversampling =
 		params_rate(params) >= 96000 ? PCM1796_OS_32 : PCM1796_OS_64;
-	for (i = 0; i < 4; ++i)
+	for (i = 0; i < data->dacs; ++i)
 		pcm1796_write(chip, i, 20, data->pcm1796_oversampling);
 }
 
@@ -430,6 +616,42 @@
 	cs4362a_write(chip, 0x0c, data->cs4362a_fm);
 }
 
+static void set_hdmi_params(struct oxygen *chip,
+			    struct snd_pcm_hw_params *params)
+{
+	struct xonar_data *data = chip->model_data;
+
+	data->hdmi_params[0] = 0; /* 1 = non-audio */
+	switch (params_rate(params)) {
+	case 44100:
+		data->hdmi_params[1] = IEC958_AES3_CON_FS_44100;
+		break;
+	case 48000:
+		data->hdmi_params[1] = IEC958_AES3_CON_FS_48000;
+		break;
+	default: /* 96000 */
+		data->hdmi_params[1] = IEC958_AES3_CON_FS_96000;
+		break;
+	case 192000:
+		data->hdmi_params[1] = IEC958_AES3_CON_FS_192000;
+		break;
+	}
+	data->hdmi_params[2] = params_channels(params) / 2 - 1;
+	if (params_format(params) == SNDRV_PCM_FORMAT_S16_LE)
+		data->hdmi_params[3] = 0;
+	else
+		data->hdmi_params[3] = 0xc0;
+	data->hdmi_params[4] = 1; /* ? */
+	hdmi_write_command(chip, 0x54, 5, data->hdmi_params);
+}
+
+static void set_hdav_params(struct oxygen *chip,
+			    struct snd_pcm_hw_params *params)
+{
+	set_pcm1796_params(chip, params);
+	set_hdmi_params(chip, params);
+}
+
 static void xonar_gpio_changed(struct oxygen *chip)
 {
 	struct xonar_data *data = chip->model_data;
@@ -449,29 +671,43 @@
 	}
 }
 
-static int alt_switch_get(struct snd_kcontrol *ctl,
-			  struct snd_ctl_elem_value *value)
+static void xonar_hdav_uart_input(struct oxygen *chip)
+{
+	if (chip->uart_input_count >= 2 &&
+	    chip->uart_input[chip->uart_input_count - 2] == 'O' &&
+	    chip->uart_input[chip->uart_input_count - 1] == 'K') {
+		printk(KERN_DEBUG "message from Xonar HDAV HDMI chip received:");
+		print_hex_dump_bytes("", DUMP_PREFIX_OFFSET,
+				     chip->uart_input, chip->uart_input_count);
+		chip->uart_input_count = 0;
+	}
+}
+
+static int gpio_bit_switch_get(struct snd_kcontrol *ctl,
+			       struct snd_ctl_elem_value *value)
 {
 	struct oxygen *chip = ctl->private_data;
+	u16 bit = ctl->private_value;
 
 	value->value.integer.value[0] =
-		!!(oxygen_read16(chip, OXYGEN_GPIO_DATA) & GPIO_D2_ALT);
+		!!(oxygen_read16(chip, OXYGEN_GPIO_DATA) & bit);
 	return 0;
 }
 
-static int alt_switch_put(struct snd_kcontrol *ctl,
-			  struct snd_ctl_elem_value *value)
+static int gpio_bit_switch_put(struct snd_kcontrol *ctl,
+			       struct snd_ctl_elem_value *value)
 {
 	struct oxygen *chip = ctl->private_data;
+	u16 bit = ctl->private_value;
 	u16 old_bits, new_bits;
 	int changed;
 
 	spin_lock_irq(&chip->reg_lock);
 	old_bits = oxygen_read16(chip, OXYGEN_GPIO_DATA);
 	if (value->value.integer.value[0])
-		new_bits = old_bits | GPIO_D2_ALT;
+		new_bits = old_bits | bit;
 	else
-		new_bits = old_bits & ~GPIO_D2_ALT;
+		new_bits = old_bits & ~bit;
 	changed = new_bits != old_bits;
 	if (changed)
 		oxygen_write16(chip, OXYGEN_GPIO_DATA, new_bits);
@@ -483,47 +719,22 @@
 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 	.name = "Analog Loopback Switch",
 	.info = snd_ctl_boolean_mono_info,
-	.get = alt_switch_get,
-	.put = alt_switch_put,
+	.get = gpio_bit_switch_get,
+	.put = gpio_bit_switch_put,
+	.private_value = GPIO_D2_ALT,
 };
 
-static int front_panel_get(struct snd_kcontrol *ctl,
-			   struct snd_ctl_elem_value *value)
-{
-	struct oxygen *chip = ctl->private_data;
-
-	value->value.integer.value[0] =
-		!!(oxygen_read16(chip, OXYGEN_GPIO_DATA) & GPIO_DX_FRONT_PANEL);
-	return 0;
-}
-
-static int front_panel_put(struct snd_kcontrol *ctl,
-			   struct snd_ctl_elem_value *value)
-{
-	struct oxygen *chip = ctl->private_data;
-	u16 old_reg, new_reg;
-
-	spin_lock_irq(&chip->reg_lock);
-	old_reg = oxygen_read16(chip, OXYGEN_GPIO_DATA);
-	if (value->value.integer.value[0])
-		new_reg = old_reg | GPIO_DX_FRONT_PANEL;
-	else
-		new_reg = old_reg & ~GPIO_DX_FRONT_PANEL;
-	oxygen_write16(chip, OXYGEN_GPIO_DATA, new_reg);
-	spin_unlock_irq(&chip->reg_lock);
-	return old_reg != new_reg;
-}
-
 static const struct snd_kcontrol_new front_panel_switch = {
 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 	.name = "Front Panel Switch",
 	.info = snd_ctl_boolean_mono_info,
-	.get = front_panel_get,
-	.put = front_panel_put,
+	.get = gpio_bit_switch_get,
+	.put = gpio_bit_switch_put,
+	.private_value = GPIO_DX_FRONT_PANEL,
 };
 
-static void xonar_d1_ac97_switch(struct oxygen *chip,
-				 unsigned int reg, unsigned int mute)
+static void xonar_line_mic_ac97_switch(struct oxygen *chip,
+				       unsigned int reg, unsigned int mute)
 {
 	if (reg == AC97_LINE) {
 		spin_lock_irq(&chip->reg_lock);
@@ -552,7 +763,7 @@
 	return 0;
 }
 
-static int xonar_mixer_init(struct oxygen *chip)
+static int xonar_d2_mixer_init(struct oxygen *chip)
 {
 	return snd_ctl_add(chip->card, snd_ctl_new1(&alt_switch, chip));
 }
@@ -562,130 +773,147 @@
 	return snd_ctl_add(chip->card, snd_ctl_new1(&front_panel_switch, chip));
 }
 
-static const struct oxygen_model xonar_models[] = {
-	[MODEL_D2] = {
-		.shortname = "Xonar D2",
-		.longname = "Asus Virtuoso 200",
-		.chip = "AV200",
-		.owner = THIS_MODULE,
-		.init = xonar_d2_init,
-		.control_filter = xonar_d2_control_filter,
-		.mixer_init = xonar_mixer_init,
-		.cleanup = xonar_cleanup,
-		.suspend = xonar_cleanup,
-		.resume = xonar_d2_resume,
-		.set_dac_params = set_pcm1796_params,
-		.set_adc_params = set_cs53x1_params,
-		.update_dac_volume = update_pcm1796_volume,
-		.update_dac_mute = update_pcm1796_mute,
-		.dac_tlv = pcm1796_db_scale,
-		.model_data_size = sizeof(struct xonar_data),
-		.pcm_dev_cfg = PLAYBACK_0_TO_I2S |
-			       PLAYBACK_1_TO_SPDIF |
-			       CAPTURE_0_FROM_I2S_2 |
-			       CAPTURE_1_FROM_SPDIF,
-		.dac_channels = 8,
-		.dac_volume_min = 0x0f,
-		.dac_volume_max = 0xff,
-		.misc_flags = OXYGEN_MISC_MIDI,
-		.function_flags = OXYGEN_FUNCTION_SPI |
-				  OXYGEN_FUNCTION_ENABLE_SPI_4_5,
-		.dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
-		.adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
-	},
-	[MODEL_D2X] = {
-		.shortname = "Xonar D2X",
-		.longname = "Asus Virtuoso 200",
-		.chip = "AV200",
-		.owner = THIS_MODULE,
-		.init = xonar_d2x_init,
-		.control_filter = xonar_d2_control_filter,
-		.mixer_init = xonar_mixer_init,
-		.cleanup = xonar_cleanup,
-		.suspend = xonar_cleanup,
-		.resume = xonar_d2_resume,
-		.set_dac_params = set_pcm1796_params,
-		.set_adc_params = set_cs53x1_params,
-		.update_dac_volume = update_pcm1796_volume,
-		.update_dac_mute = update_pcm1796_mute,
-		.gpio_changed = xonar_gpio_changed,
-		.dac_tlv = pcm1796_db_scale,
-		.model_data_size = sizeof(struct xonar_data),
-		.pcm_dev_cfg = PLAYBACK_0_TO_I2S |
-			       PLAYBACK_1_TO_SPDIF |
-			       CAPTURE_0_FROM_I2S_2 |
-			       CAPTURE_1_FROM_SPDIF,
-		.dac_channels = 8,
-		.dac_volume_min = 0x0f,
-		.dac_volume_max = 0xff,
-		.misc_flags = OXYGEN_MISC_MIDI,
-		.function_flags = OXYGEN_FUNCTION_SPI |
-				  OXYGEN_FUNCTION_ENABLE_SPI_4_5,
-		.dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
-		.adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
-	},
-	[MODEL_D1] = {
-		.shortname = "Xonar D1",
-		.longname = "Asus Virtuoso 100",
-		.chip = "AV200",
-		.owner = THIS_MODULE,
-		.init = xonar_d1_init,
-		.control_filter = xonar_d1_control_filter,
-		.mixer_init = xonar_d1_mixer_init,
-		.cleanup = xonar_d1_cleanup,
-		.suspend = xonar_d1_cleanup,
-		.resume = xonar_d1_resume,
-		.set_dac_params = set_cs43xx_params,
-		.set_adc_params = set_cs53x1_params,
-		.update_dac_volume = update_cs43xx_volume,
-		.update_dac_mute = update_cs43xx_mute,
-		.ac97_switch = xonar_d1_ac97_switch,
-		.dac_tlv = cs4362a_db_scale,
-		.model_data_size = sizeof(struct xonar_data),
-		.pcm_dev_cfg = PLAYBACK_0_TO_I2S |
-			       PLAYBACK_1_TO_SPDIF |
-			       CAPTURE_0_FROM_I2S_2,
-		.dac_channels = 8,
-		.dac_volume_min = 0,
-		.dac_volume_max = 127,
-		.function_flags = OXYGEN_FUNCTION_2WIRE,
-		.dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
-		.adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
-	},
-	[MODEL_DX] = {
-		.shortname = "Xonar DX",
-		.longname = "Asus Virtuoso 100",
-		.chip = "AV200",
-		.owner = THIS_MODULE,
-		.init = xonar_dx_init,
-		.control_filter = xonar_d1_control_filter,
-		.mixer_init = xonar_d1_mixer_init,
-		.cleanup = xonar_d1_cleanup,
-		.suspend = xonar_d1_cleanup,
-		.resume = xonar_d1_resume,
-		.set_dac_params = set_cs43xx_params,
-		.set_adc_params = set_cs53x1_params,
-		.update_dac_volume = update_cs43xx_volume,
-		.update_dac_mute = update_cs43xx_mute,
-		.gpio_changed = xonar_gpio_changed,
-		.ac97_switch = xonar_d1_ac97_switch,
-		.dac_tlv = cs4362a_db_scale,
-		.model_data_size = sizeof(struct xonar_data),
-		.pcm_dev_cfg = PLAYBACK_0_TO_I2S |
-			       PLAYBACK_1_TO_SPDIF |
-			       CAPTURE_0_FROM_I2S_2,
-		.dac_channels = 8,
-		.dac_volume_min = 0,
-		.dac_volume_max = 127,
-		.function_flags = OXYGEN_FUNCTION_2WIRE,
-		.dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
-		.adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
-	},
+static int xonar_model_probe(struct oxygen *chip, unsigned long driver_data)
+{
+	static const char *const names[] = {
+		[MODEL_D1]	= "Xonar D1",
+		[MODEL_DX]	= "Xonar DX",
+		[MODEL_D2]	= "Xonar D2",
+		[MODEL_D2X]	= "Xonar D2X",
+		[MODEL_HDAV]	= "Xonar HDAV1.3",
+		[MODEL_HDAV_H6]	= "Xonar HDAV1.3+H6",
+	};
+	static const u8 dacs[] = {
+		[MODEL_D1]	= 2,
+		[MODEL_DX]	= 2,
+		[MODEL_D2]	= 4,
+		[MODEL_D2X]	= 4,
+		[MODEL_HDAV]	= 1,
+		[MODEL_HDAV_H6]	= 4,
+	};
+	struct xonar_data *data = chip->model_data;
+
+	data->model = driver_data;
+	if (data->model == MODEL_HDAV) {
+		oxygen_clear_bits16(chip, OXYGEN_GPIO_CONTROL,
+				    GPIO_HDAV_DB_MASK);
+		switch (oxygen_read16(chip, OXYGEN_GPIO_DATA) &
+			GPIO_HDAV_DB_MASK) {
+		case GPIO_HDAV_DB_H6:
+			data->model = MODEL_HDAV_H6;
+			break;
+		case GPIO_HDAV_DB_XX:
+			snd_printk(KERN_ERR "unknown daughterboard\n");
+			return -ENODEV;
+		}
+	}
+
+	data->dacs = dacs[data->model];
+	chip->model.shortname = names[data->model];
+	return 0;
+}
+
+static const struct oxygen_model model_xonar_d2 = {
+	.longname = "Asus Virtuoso 200",
+	.chip = "AV200",
+	.owner = THIS_MODULE,
+	.probe = xonar_model_probe,
+	.init = xonar_d2_init,
+	.control_filter = xonar_d2_control_filter,
+	.mixer_init = xonar_d2_mixer_init,
+	.cleanup = xonar_d2_cleanup,
+	.suspend = xonar_d2_suspend,
+	.resume = xonar_d2_resume,
+	.set_dac_params = set_pcm1796_params,
+	.set_adc_params = set_cs53x1_params,
+	.update_dac_volume = update_pcm1796_volume,
+	.update_dac_mute = update_pcm1796_mute,
+	.dac_tlv = pcm1796_db_scale,
+	.model_data_size = sizeof(struct xonar_data),
+	.device_config = PLAYBACK_0_TO_I2S |
+			 PLAYBACK_1_TO_SPDIF |
+			 CAPTURE_0_FROM_I2S_2 |
+			 CAPTURE_1_FROM_SPDIF |
+			 MIDI_OUTPUT |
+			 MIDI_INPUT,
+	.dac_channels = 8,
+	.dac_volume_min = 0x0f,
+	.dac_volume_max = 0xff,
+	.misc_flags = OXYGEN_MISC_MIDI,
+	.function_flags = OXYGEN_FUNCTION_SPI |
+			  OXYGEN_FUNCTION_ENABLE_SPI_4_5,
+	.dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
+	.adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
+};
+
+static const struct oxygen_model model_xonar_d1 = {
+	.longname = "Asus Virtuoso 100",
+	.chip = "AV200",
+	.owner = THIS_MODULE,
+	.probe = xonar_model_probe,
+	.init = xonar_d1_init,
+	.control_filter = xonar_d1_control_filter,
+	.mixer_init = xonar_d1_mixer_init,
+	.cleanup = xonar_d1_cleanup,
+	.suspend = xonar_d1_suspend,
+	.resume = xonar_d1_resume,
+	.set_dac_params = set_cs43xx_params,
+	.set_adc_params = set_cs53x1_params,
+	.update_dac_volume = update_cs43xx_volume,
+	.update_dac_mute = update_cs43xx_mute,
+	.ac97_switch = xonar_line_mic_ac97_switch,
+	.dac_tlv = cs4362a_db_scale,
+	.model_data_size = sizeof(struct xonar_data),
+	.device_config = PLAYBACK_0_TO_I2S |
+			 PLAYBACK_1_TO_SPDIF |
+			 CAPTURE_0_FROM_I2S_2,
+	.dac_channels = 8,
+	.dac_volume_min = 0,
+	.dac_volume_max = 127,
+	.function_flags = OXYGEN_FUNCTION_2WIRE,
+	.dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
+	.adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
+};
+
+static const struct oxygen_model model_xonar_hdav = {
+	.longname = "Asus Virtuoso 200",
+	.chip = "AV200",
+	.owner = THIS_MODULE,
+	.probe = xonar_model_probe,
+	.init = xonar_hdav_init,
+	.cleanup = xonar_hdav_cleanup,
+	.suspend = xonar_hdav_suspend,
+	.resume = xonar_hdav_resume,
+	.pcm_hardware_filter = xonar_hdav_pcm_hardware_filter,
+	.set_dac_params = set_hdav_params,
+	.set_adc_params = set_cs53x1_params,
+	.update_dac_volume = update_pcm1796_volume,
+	.update_dac_mute = update_pcm1796_mute,
+	.uart_input = xonar_hdav_uart_input,
+	.ac97_switch = xonar_line_mic_ac97_switch,
+	.dac_tlv = pcm1796_db_scale,
+	.model_data_size = sizeof(struct xonar_data),
+	.device_config = PLAYBACK_0_TO_I2S |
+			 PLAYBACK_1_TO_SPDIF |
+			 CAPTURE_0_FROM_I2S_2,
+	.dac_channels = 8,
+	.dac_volume_min = 0x0f,
+	.dac_volume_max = 0xff,
+	.function_flags = OXYGEN_FUNCTION_2WIRE,
+	.dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
+	.adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
 };
 
 static int __devinit xonar_probe(struct pci_dev *pci,
 				 const struct pci_device_id *pci_id)
 {
+	static const struct oxygen_model *const models[] = {
+		[MODEL_D1]	= &model_xonar_d1,
+		[MODEL_DX]	= &model_xonar_d1,
+		[MODEL_D2]	= &model_xonar_d2,
+		[MODEL_D2X]	= &model_xonar_d2,
+		[MODEL_HDAV]	= &model_xonar_hdav,
+	};
 	static int dev;
 	int err;
 
@@ -695,8 +923,10 @@
 		++dev;
 		return -ENOENT;
 	}
+	BUG_ON(pci_id->driver_data >= ARRAY_SIZE(models));
 	err = oxygen_pci_probe(pci, index[dev], id[dev],
-			       &xonar_models[pci_id->driver_data]);
+			       models[pci_id->driver_data],
+			       pci_id->driver_data);
 	if (err >= 0)
 		++dev;
 	return err;
diff --git a/sound/pci/pcxhr/pcxhr.c b/sound/pci/pcxhr/pcxhr.c
index 2c7e253..0e06c6c 100644
--- a/sound/pci/pcxhr/pcxhr.c
+++ b/sound/pci/pcxhr/pcxhr.c
@@ -464,7 +464,8 @@
 	pcxhr_init_rmh(&rmh, CMD_UPDATE_R_BUFFERS);
 	pcxhr_set_pipe_cmd_params(&rmh, is_capture, stream->pipe->first_audio, stream_num, 0);
 
-	snd_assert(subs->runtime->dma_bytes < 0x200000);	/* max buffer size is 2 MByte */
+	/* max buffer size is 2 MByte */
+	snd_BUG_ON(subs->runtime->dma_bytes >= 0x200000);
 	rmh.cmd[1] = subs->runtime->dma_bytes * 8;		/* size in bits */
 	rmh.cmd[2] = subs->runtime->dma_addr >> 24;		/* most significant byte */
 	rmh.cmd[2] |= 1<<19;					/* this is a circular buffer */
@@ -1228,7 +1229,8 @@
 		return -ENOMEM;
 	}
 
-	snd_assert(pci_id->driver_data < PCI_ID_LAST, return -ENODEV);
+	if (snd_BUG_ON(pci_id->driver_data >= PCI_ID_LAST))
+		return -ENODEV;
 	card_name = pcxhr_board_params[pci_id->driver_data].board_name;
 	mgr->playback_chips = pcxhr_board_params[pci_id->driver_data].playback_chips;
 	mgr->capture_chips  = pcxhr_board_params[pci_id->driver_data].capture_chips;
diff --git a/sound/pci/pcxhr/pcxhr_core.c b/sound/pci/pcxhr/pcxhr_core.c
index 000e6fe..7143259 100644
--- a/sound/pci/pcxhr/pcxhr_core.c
+++ b/sound/pci/pcxhr/pcxhr_core.c
@@ -319,16 +319,20 @@
 	const unsigned char *data;
 	unsigned char dummy;
 	/* check the length of boot image */
-	snd_assert(dsp->size > 0, return -EINVAL);
-	snd_assert(dsp->size % 3 == 0, return -EINVAL);
-	snd_assert(dsp->data, return -EINVAL);
+	if (dsp->size <= 0)
+		return -EINVAL;
+	if (dsp->size % 3)
+		return -EINVAL;
+	if (snd_BUG_ON(!dsp->data))
+		return -EINVAL;
 	/* transfert data buffer from PC to DSP */
 	for (i = 0; i < dsp->size; i += 3) {
 		data = dsp->data + i;
 		if (i == 0) {
 			/* test data header consistency */
 			len = (unsigned int)((data[0]<<16) + (data[1]<<8) + data[2]);
-			snd_assert((len==0) || (dsp->size == (len+2)*3), return -EINVAL);
+			if (len && dsp->size != (len + 2) * 3)
+				return -EINVAL;
 		}
 		/* wait DSP ready for new transfer */
 		err = pcxhr_check_reg_bit(mgr, PCXHR_DSP_ISR, PCXHR_ISR_HI08_TRDY,
@@ -389,7 +393,8 @@
 	unsigned char dummy;
 
 	/* send the hostport address to the DSP (only the upper 24 bit !) */
-	snd_assert((physaddr & 0xff) == 0, return -EINVAL);
+	if (snd_BUG_ON(physaddr & 0xff))
+		return -EINVAL;
 	PCXHR_OUTPL(mgr, PCXHR_PLX_MBOX1, (physaddr >> 8));
 
 	err = pcxhr_send_it_dsp(mgr, PCXHR_IT_DOWNLOAD_BOOT, 0);
@@ -570,7 +575,8 @@
 	u32 data;
 	unsigned char reg;
 
-	snd_assert(rmh->cmd_len<PCXHR_SIZE_MAX_CMD, return -EINVAL);
+	if (snd_BUG_ON(rmh->cmd_len >= PCXHR_SIZE_MAX_CMD))
+		return -EINVAL;
 	err = pcxhr_send_it_dsp(mgr, PCXHR_IT_MESSAGE, 1);
 	if (err) {
 		snd_printk(KERN_ERR "pcxhr_send_message : ED_DSP_CRASHED\n");
@@ -677,7 +683,8 @@
  */
 void pcxhr_init_rmh(struct pcxhr_rmh *rmh, int cmd)
 {
-	snd_assert(cmd < CMD_LAST_INDEX, return);
+	if (snd_BUG_ON(cmd >= CMD_LAST_INDEX))
+		return;
 	rmh->cmd[0] = pcxhr_dsp_cmds[cmd].opcode;
 	rmh->cmd_len = 1;
 	rmh->stat_len = pcxhr_dsp_cmds[cmd].st_length;
@@ -690,17 +697,17 @@
 			       unsigned int param1, unsigned int param2,
 			       unsigned int param3)
 {
-	snd_assert(param1 <= MASK_FIRST_FIELD);
+	snd_BUG_ON(param1 > MASK_FIRST_FIELD);
 	if (capture)
 		rmh->cmd[0] |= 0x800;		/* COMMAND_RECORD_MASK */
 	if (param1)
 		rmh->cmd[0] |= (param1 << FIELD_SIZE);
 	if (param2) {
-		snd_assert(param2 <= MASK_FIRST_FIELD);
+		snd_BUG_ON(param2 > MASK_FIRST_FIELD);
 		rmh->cmd[0] |= param2;
 	}
 	if(param3) {
-		snd_assert(param3 <= MASK_DSP_WORD);
+		snd_BUG_ON(param3 > MASK_DSP_WORD);
 		rmh->cmd[1] = param3;
 		rmh->cmd_len = 2;
 	}
diff --git a/sound/pci/pcxhr/pcxhr_hwdep.c b/sound/pci/pcxhr/pcxhr_hwdep.c
index d2f0432..96640d9 100644
--- a/sound/pci/pcxhr/pcxhr_hwdep.c
+++ b/sound/pci/pcxhr/pcxhr_hwdep.c
@@ -65,15 +65,18 @@
 	if (err)
 		return err;
 	/* test 8 or 12 phys out */
-	snd_assert((rmh.stat[0] & MASK_FIRST_FIELD) == mgr->playback_chips*2,
-		   return -EINVAL);
+	if ((rmh.stat[0] & MASK_FIRST_FIELD) != mgr->playback_chips * 2)
+		return -EINVAL;
 	/* test 8 or 2 phys in */
-	snd_assert(((rmh.stat[0] >> (2*FIELD_SIZE)) & MASK_FIRST_FIELD) ==
-		   mgr->capture_chips * 2, return -EINVAL);
+	if (((rmh.stat[0] >> (2 * FIELD_SIZE)) & MASK_FIRST_FIELD) !=
+	    mgr->capture_chips * 2)
+		return -EINVAL;
 	/* test max nb substream per board */
-	snd_assert((rmh.stat[1] & 0x5F) >= card_streams, return -EINVAL);
+	if ((rmh.stat[1] & 0x5F) < card_streams)
+		return -EINVAL;
 	/* test max nb substream per pipe */
-	snd_assert(((rmh.stat[1]>>7)&0x5F) >= PCXHR_PLAYBACK_STREAMS, return -EINVAL);
+	if (((rmh.stat[1] >> 7) & 0x5F) < PCXHR_PLAYBACK_STREAMS)
+		return -EINVAL;
 
 	pcxhr_init_rmh(&rmh, CMD_VERSION);
 	/* firmware num for DSP */
diff --git a/sound/pci/riptide/riptide.c b/sound/pci/riptide/riptide.c
index 6a35962..e9f0706 100644
--- a/sound/pci/riptide/riptide.c
+++ b/sound/pci/riptide/riptide.c
@@ -865,7 +865,8 @@
 	struct riptideport *hwport;
 	struct cmdport *cmdport = NULL;
 
-	snd_assert(cif, return -EINVAL);
+	if (snd_BUG_ON(!cif))
+		return -EINVAL;
 
 	hwport = cif->hwport;
 	if (cif->errcnt > MAX_ERROR_COUNT) {
@@ -1482,7 +1483,6 @@
 {
 	struct snd_riptide *chip = snd_pcm_substream_chip(substream);
 	struct snd_pcm_runtime *runtime = substream->runtime;
-	struct snd_sg_buf *sgbuf = snd_pcm_substream_sgbuf(substream);
 	struct pcmhw *data = get_pcmhwdev(substream);
 	struct cmdif *cif = chip->cif;
 	unsigned char *lbuspath = NULL;
@@ -1490,7 +1490,8 @@
 	int err = 0;
 	snd_pcm_format_t format;
 
-	snd_assert(cif && data, return -EINVAL);
+	if (snd_BUG_ON(!cif || !data))
+		return -EINVAL;
 
 	snd_printdd("prepare id %d ch: %d f:0x%x r:%d\n", data->id,
 		    runtime->channels, runtime->format, runtime->rate);
@@ -1513,9 +1514,9 @@
 			lbuspath = data->paths.stereo;
 		break;
 	}
-	snd_printdd("use sgdlist at 0x%p and buffer at 0x%p\n",
-		    data->sgdlist.area, sgbuf);
-	if (data->sgdlist.area && sgbuf) {
+	snd_printdd("use sgdlist at 0x%p\n",
+		    data->sgdlist.area);
+	if (data->sgdlist.area) {
 		unsigned int i, j, size, pages, f, pt, period;
 		struct sgd *c, *p = NULL;
 
@@ -1533,6 +1534,7 @@
 		pt = 0;
 		j = 0;
 		for (i = 0; i < pages; i++) {
+			unsigned int ofs, addr;
 			c = &data->sgdbuf[i];
 			if (p)
 				p->dwNextLink = cpu_to_le32(data->sgdlist.addr +
@@ -1540,8 +1542,9 @@
 							     sizeof(struct
 								    sgd)));
 			c->dwNextLink = cpu_to_le32(data->sgdlist.addr);
-			c->dwSegPtrPhys =
-			    cpu_to_le32(sgbuf->table[j].addr + pt);
+			ofs = j << PAGE_SHIFT;
+			addr = snd_pcm_sgbuf_get_addr(substream, ofs) + pt;
+			c->dwSegPtrPhys = cpu_to_le32(addr);
 			pt = (pt + f) % PAGE_SIZE;
 			if (pt == 0)
 				j++;
@@ -1772,7 +1775,8 @@
 	union cmdret rptr = CMDRET_ZERO;
 	int i = 0;
 
-	snd_assert(cif, return);
+	if (snd_BUG_ON(!cif))
+		return;
 
 	snd_printdd("Write AC97 reg 0x%x 0x%x\n", reg, val);
 	do {
@@ -1790,7 +1794,8 @@
 	struct cmdif *cif = chip->cif;
 	union cmdret rptr = CMDRET_ZERO;
 
-	snd_assert(cif, return 0);
+	if (snd_BUG_ON(!cif))
+		return 0;
 
 	if (SEND_RACR(cif, reg, &rptr) != 0)
 		SEND_RACR(cif, reg, &rptr);
@@ -1804,7 +1809,8 @@
 	unsigned int device_id;
 	int err;
 
-	snd_assert(chip, return -EINVAL);
+	if (snd_BUG_ON(!chip))
+		return -EINVAL;
 
 	cif = chip->cif;
 	if (!cif) {
@@ -1836,7 +1842,8 @@
 {
 	struct cmdif *cif;
 
-	snd_assert(chip, return 0);
+	if (!chip)
+		return 0;
 
 	if ((cif = chip->cif)) {
 		SET_GRESET(cif->hwport);
diff --git a/sound/pci/rme9652/hdsp.c b/sound/pci/rme9652/hdsp.c
index 4d6fbb3..d723543 100644
--- a/sound/pci/rme9652/hdsp.c
+++ b/sound/pci/rme9652/hdsp.c
@@ -1036,7 +1036,7 @@
 	n = DDS_NUMERATOR;
 	div64_32(&n, rate, &r);
 	/* n should be less than 2^32 for being written to FREQ register */
-	snd_assert((n >> 32) == 0);
+	snd_BUG_ON(n >> 32);
 	/* HDSP_freqReg and HDSP_resetPointer are the same, so keep the DDS
 	   value to write it after a reset */
 	hdsp->dds_value = n;
@@ -3043,7 +3043,7 @@
 	struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
 
 	offset = ucontrol->id.index - 1;
-	snd_assert(offset >= 0);
+	snd_BUG_ON(offset < 0);
 
 	switch (hdsp->io_type) {
 	case Digiface:
@@ -3767,7 +3767,8 @@
 {
 	int mapped_channel;
 
-        snd_assert(channel >= 0 && channel < hdsp->max_channels, return NULL);
+        if (snd_BUG_ON(channel < 0 || channel >= hdsp->max_channels))
+		return NULL;
         
 	if ((mapped_channel = hdsp->channel_map[channel]) < 0)
 		return NULL;
@@ -3784,10 +3785,12 @@
 	struct hdsp *hdsp = snd_pcm_substream_chip(substream);
 	char *channel_buf;
 
-	snd_assert(pos + count <= HDSP_CHANNEL_BUFFER_BYTES / 4, return -EINVAL);
+	if (snd_BUG_ON(pos + count > HDSP_CHANNEL_BUFFER_BYTES / 4))
+		return -EINVAL;
 
 	channel_buf = hdsp_channel_buffer_location (hdsp, substream->pstr->stream, channel);
-	snd_assert(channel_buf != NULL, return -EIO);
+	if (snd_BUG_ON(!channel_buf))
+		return -EIO;
 	if (copy_from_user(channel_buf + pos * 4, src, count * 4))
 		return -EFAULT;
 	return count;
@@ -3799,10 +3802,12 @@
 	struct hdsp *hdsp = snd_pcm_substream_chip(substream);
 	char *channel_buf;
 
-	snd_assert(pos + count <= HDSP_CHANNEL_BUFFER_BYTES / 4, return -EINVAL);
+	if (snd_BUG_ON(pos + count > HDSP_CHANNEL_BUFFER_BYTES / 4))
+		return -EINVAL;
 
 	channel_buf = hdsp_channel_buffer_location (hdsp, substream->pstr->stream, channel);
-	snd_assert(channel_buf != NULL, return -EIO);
+	if (snd_BUG_ON(!channel_buf))
+		return -EIO;
 	if (copy_to_user(dst, channel_buf + pos * 4, count * 4))
 		return -EFAULT;
 	return count;
@@ -3815,7 +3820,8 @@
 	char *channel_buf;
 
 	channel_buf = hdsp_channel_buffer_location (hdsp, substream->pstr->stream, channel);
-	snd_assert(channel_buf != NULL, return -EIO);
+	if (snd_BUG_ON(!channel_buf))
+		return -EIO;
 	memset(channel_buf + pos * 4, 0, count * 4);
 	return count;
 }
@@ -3927,7 +3933,8 @@
 	struct hdsp *hdsp = snd_pcm_substream_chip(substream);
 	int mapped_channel;
 
-	snd_assert(info->channel < hdsp->max_channels, return -EINVAL);
+	if (snd_BUG_ON(info->channel >= hdsp->max_channels))
+		return -EINVAL;
 
 	if ((mapped_channel = hdsp->channel_map[info->channel]) < 0)
 		return -EINVAL;
diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c
index ab423bc..98762f9 100644
--- a/sound/pci/rme9652/hdspm.c
+++ b/sound/pci/rme9652/hdspm.c
@@ -535,7 +535,8 @@
 static int hdspm_update_simple_mixer_controls(struct hdspm * hdspm);
 static int hdspm_autosync_ref(struct hdspm * hdspm);
 static int snd_hdspm_set_defaults(struct hdspm * hdspm);
-static void hdspm_set_sgbuf(struct hdspm * hdspm, struct snd_sg_buf *sgbuf,
+static void hdspm_set_sgbuf(struct hdspm * hdspm,
+			    struct snd_pcm_substream *substream,
 			     unsigned int reg, int channels);
 
 static inline int HDSPM_bit2freq(int n)
@@ -845,7 +846,7 @@
 	n = 110100480000000ULL;    /* Value checked for AES32 and MADI */
 	div64_32(&n, rate, &r);
 	/* n should be less than 2^32 for being written to FREQ register */
-	snd_assert((n >> 32) == 0);
+	snd_BUG_ON(n >> 32);
 	hdspm_write(hdspm, HDSPM_freqReg, (u32)n);
 }
 
@@ -2617,8 +2618,8 @@
 
 	channel = ucontrol->id.index - 1;
 
-	snd_assert(channel >= 0
-		   || channel < HDSPM_MAX_CHANNELS, return -EINVAL);
+	if (snd_BUG_ON(channel < 0 || channel >= HDSPM_MAX_CHANNELS))
+		return -EINVAL;
 
 	mapped_channel = hdspm->channel_map[channel];
 	if (mapped_channel < 0)
@@ -2652,8 +2653,8 @@
 
 	channel = ucontrol->id.index - 1;
 
-	snd_assert(channel >= 0
-		   || channel < HDSPM_MAX_CHANNELS, return -EINVAL);
+	if (snd_BUG_ON(channel < 0 || channel >= HDSPM_MAX_CHANNELS))
+		return -EINVAL;
 
 	mapped_channel = hdspm->channel_map[channel];
 	if (mapped_channel < 0)
@@ -3496,8 +3497,8 @@
 {
 	int mapped_channel;
 
-	snd_assert(channel >= 0
-		   || channel < HDSPM_MAX_CHANNELS, return NULL);
+	if (snd_BUG_ON(channel < 0 || channel >= HDSPM_MAX_CHANNELS))
+		return NULL;
 
 	mapped_channel = hdspm->channel_map[channel];
 	if (mapped_channel < 0)
@@ -3520,14 +3521,15 @@
 	struct hdspm *hdspm = snd_pcm_substream_chip(substream);
 	char *channel_buf;
 
-	snd_assert(pos + count <= HDSPM_CHANNEL_BUFFER_BYTES / 4,
-		   return -EINVAL);
+	if (snd_BUG_ON(pos + count > HDSPM_CHANNEL_BUFFER_BYTES / 4))
+		return -EINVAL;
 
 	channel_buf =
 		hdspm_channel_buffer_location(hdspm, substream->pstr->stream,
 					      channel);
 
-	snd_assert(channel_buf != NULL, return -EIO);
+	if (snd_BUG_ON(!channel_buf))
+		return -EIO;
 
 	return copy_from_user(channel_buf + pos * 4, src, count * 4);
 }
@@ -3539,13 +3541,14 @@
 	struct hdspm *hdspm = snd_pcm_substream_chip(substream);
 	char *channel_buf;
 
-	snd_assert(pos + count <= HDSPM_CHANNEL_BUFFER_BYTES / 4,
-		   return -EINVAL);
+	if (snd_BUG_ON(pos + count > HDSPM_CHANNEL_BUFFER_BYTES / 4))
+		return -EINVAL;
 
 	channel_buf =
 		hdspm_channel_buffer_location(hdspm, substream->pstr->stream,
 					      channel);
-	snd_assert(channel_buf != NULL, return -EIO);
+	if (snd_BUG_ON(!channel_buf))
+		return -EIO;
 	return copy_to_user(dst, channel_buf + pos * 4, count * 4);
 }
 
@@ -3559,7 +3562,8 @@
 	channel_buf =
 		hdspm_channel_buffer_location(hdspm, substream->pstr->stream,
 					      channel);
-	snd_assert(channel_buf != NULL, return -EIO);
+	if (snd_BUG_ON(!channel_buf))
+		return -EIO;
 	memset(channel_buf + pos * 4, 0, count * 4);
 	return 0;
 }
@@ -3601,8 +3605,6 @@
 	int i;
 	pid_t this_pid;
 	pid_t other_pid;
-	struct snd_sg_buf *sgbuf;
-
 
 	spin_lock_irq(&hdspm->lock);
 
@@ -3670,11 +3672,9 @@
 	if (err < 0)
 		return err;
 
-	sgbuf = snd_pcm_substream_sgbuf(substream);
-
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
 
-		hdspm_set_sgbuf(hdspm, sgbuf, HDSPM_pageAddressBufferOut,
+		hdspm_set_sgbuf(hdspm, substream, HDSPM_pageAddressBufferOut,
 				params_channels(params));
 
 		for (i = 0; i < params_channels(params); ++i)
@@ -3685,7 +3685,7 @@
 		snd_printdd("Allocated sample buffer for playback at %p\n",
 				hdspm->playback_buffer);
 	} else {
-		hdspm_set_sgbuf(hdspm, sgbuf, HDSPM_pageAddressBufferIn,
+		hdspm_set_sgbuf(hdspm, substream, HDSPM_pageAddressBufferIn,
 				params_channels(params));
 
 		for (i = 0; i < params_channels(params); ++i)
@@ -3700,7 +3700,7 @@
 	   snd_printdd("Allocated sample buffer for %s at 0x%08X\n",
 	   substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
 	   "playback" : "capture",
-	   snd_pcm_sgbuf_get_addr(sgbuf, 0));
+	   snd_pcm_sgbuf_get_addr(substream, 0));
 	 */
 	/*
 	snd_printdd("set_hwparams: %s %d Hz, %d channels, bs = %d\n",
@@ -3744,7 +3744,8 @@
 	struct hdspm *hdspm = snd_pcm_substream_chip(substream);
 	int mapped_channel;
 
-	snd_assert(info->channel < HDSPM_MAX_CHANNELS, return -EINVAL);
+	if (snd_BUG_ON(info->channel >= HDSPM_MAX_CHANNELS))
+		return -EINVAL;
 
 	mapped_channel = hdspm->channel_map[info->channel];
 	if (mapped_channel < 0)
@@ -4249,13 +4250,14 @@
 	return 0;
 }
 
-static void hdspm_set_sgbuf(struct hdspm * hdspm, struct snd_sg_buf *sgbuf,
+static void hdspm_set_sgbuf(struct hdspm * hdspm,
+			    struct snd_pcm_substream *substream,
 			     unsigned int reg, int channels)
 {
 	int i;
 	for (i = 0; i < (channels * 16); i++)
 		hdspm_write(hdspm, reg + 4 * i,
-			    snd_pcm_sgbuf_get_addr(sgbuf, (size_t) 4096 * i));
+			    snd_pcm_sgbuf_get_addr(substream, 4096 * i));
 }
 
 /* ------------- ALSA Devices ---------------------------- */
diff --git a/sound/pci/rme9652/rme9652.c b/sound/pci/rme9652/rme9652.c
index a123f0e..2570907 100644
--- a/sound/pci/rme9652/rme9652.c
+++ b/sound/pci/rme9652/rme9652.c
@@ -595,8 +595,6 @@
 	} else {
 		int mapped_channel;
 
-		snd_assert(channel == RME9652_NCHANNELS, return);
-
 		mapped_channel = rme9652->channel_map[channel];
 
 		if (enable) {
@@ -1893,7 +1891,8 @@
 {
 	int mapped_channel;
 
-        snd_assert(channel >= 0 || channel < RME9652_NCHANNELS, return NULL);
+	if (snd_BUG_ON(channel < 0 || channel >= RME9652_NCHANNELS))
+		return NULL;
         
 	if ((mapped_channel = rme9652->channel_map[channel]) < 0) {
 		return NULL;
@@ -1914,12 +1913,14 @@
 	struct snd_rme9652 *rme9652 = snd_pcm_substream_chip(substream);
 	char *channel_buf;
 
-	snd_assert(pos + count <= RME9652_CHANNEL_BUFFER_BYTES / 4, return -EINVAL);
+	if (snd_BUG_ON(pos + count > RME9652_CHANNEL_BUFFER_BYTES / 4))
+		return -EINVAL;
 
 	channel_buf = rme9652_channel_buffer_location (rme9652,
 						       substream->pstr->stream,
 						       channel);
-	snd_assert(channel_buf != NULL, return -EIO);
+	if (snd_BUG_ON(!channel_buf))
+		return -EIO;
 	if (copy_from_user(channel_buf + pos * 4, src, count * 4))
 		return -EFAULT;
 	return count;
@@ -1931,12 +1932,14 @@
 	struct snd_rme9652 *rme9652 = snd_pcm_substream_chip(substream);
 	char *channel_buf;
 
-	snd_assert(pos + count <= RME9652_CHANNEL_BUFFER_BYTES / 4, return -EINVAL);
+	if (snd_BUG_ON(pos + count > RME9652_CHANNEL_BUFFER_BYTES / 4))
+		return -EINVAL;
 
 	channel_buf = rme9652_channel_buffer_location (rme9652,
 						       substream->pstr->stream,
 						       channel);
-	snd_assert(channel_buf != NULL, return -EIO);
+	if (snd_BUG_ON(!channel_buf))
+		return -EIO;
 	if (copy_to_user(dst, channel_buf + pos * 4, count * 4))
 		return -EFAULT;
 	return count;
@@ -1951,7 +1954,8 @@
 	channel_buf = rme9652_channel_buffer_location (rme9652,
 						       substream->pstr->stream,
 						       channel);
-	snd_assert(channel_buf != NULL, return -EIO);
+	if (snd_BUG_ON(!channel_buf))
+		return -EIO;
 	memset(channel_buf + pos * 4, 0, count * 4);
 	return count;
 }
@@ -2053,7 +2057,8 @@
 	struct snd_rme9652 *rme9652 = snd_pcm_substream_chip(substream);
 	int chn;
 
-	snd_assert(info->channel < RME9652_NCHANNELS, return -EINVAL);
+	if (snd_BUG_ON(info->channel >= RME9652_NCHANNELS))
+		return -EINVAL;
 
 	if ((chn = rme9652->channel_map[info->channel]) < 0) {
 		return -EINVAL;
diff --git a/sound/pci/sonicvibes.c b/sound/pci/sonicvibes.c
index 0d3d305..cd408b8 100644
--- a/sound/pci/sonicvibes.c
+++ b/sound/pci/sonicvibes.c
@@ -534,8 +534,8 @@
 			params->rate_den = 1;
 		} else {
 			snd_sonicvibes_pll(rate, &r, &m, &n);
-			snd_assert((SV_REFFREQUENCY % 16) == 0, return -EINVAL);
-			snd_assert((SV_ADCMULT % 512) == 0, return -EINVAL);
+			snd_BUG_ON(SV_REFFREQUENCY % 16);
+			snd_BUG_ON(SV_ADCMULT % 512);
 			params->rate_num = (SV_REFFREQUENCY/16) * (n+2) * r;
 			params->rate_den = (SV_ADCMULT/512) * (m+2);
 		}
@@ -849,7 +849,8 @@
 
 	if ((err = snd_pcm_new(sonic->card, "s3_86c617", device, 1, 1, &pcm)) < 0)
 		return err;
-	snd_assert(pcm != NULL, return -EINVAL);
+	if (snd_BUG_ON(!pcm))
+		return -EINVAL;
 
 	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_sonicvibes_playback_ops);
 	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_sonicvibes_capture_ops);
@@ -1089,7 +1090,8 @@
 	unsigned int idx;
 	int err;
 
-	snd_assert(sonic != NULL && sonic->card != NULL, return -EINVAL);
+	if (snd_BUG_ON(!sonic || !sonic->card))
+		return -EINVAL;
 	card = sonic->card;
 	strcpy(card->mixername, "S3 SonicVibes");
 
diff --git a/sound/pci/trident/trident_main.c b/sound/pci/trident/trident_main.c
index a69b420..c612b43 100644
--- a/sound/pci/trident/trident_main.c
+++ b/sound/pci/trident/trident_main.c
@@ -2931,7 +2931,8 @@
 {
 	struct snd_trident_pcm_mixer *tmix;
 
-	snd_assert(trident != NULL && voice != NULL && substream != NULL, return -EINVAL);
+	if (snd_BUG_ON(!trident || !voice || !substream))
+		return -EINVAL;
 	tmix = &trident->pcm_mixer[substream->number];
 	tmix->voice = voice;
 	tmix->vol = T4D_DEFAULT_PCM_VOL;
@@ -2946,7 +2947,8 @@
 {
 	struct snd_trident_pcm_mixer *tmix;
 
-	snd_assert(trident != NULL && substream != NULL, return -EINVAL);
+	if (snd_BUG_ON(!trident || !substream))
+		return -EINVAL;
 	tmix = &trident->pcm_mixer[substream->number];
 	tmix->voice = NULL;
 	snd_trident_notify_pcm_change(trident, tmix, substream->number, 0);
@@ -3131,7 +3133,8 @@
 {
 	struct snd_trident *chip = gameport_get_port_data(gameport);
 
-	snd_assert(chip, return 0);
+	if (snd_BUG_ON(!chip))
+		return 0;
 	return inb(TRID_REG(chip, GAMEPORT_LEGACY));
 }
 
@@ -3139,7 +3142,8 @@
 {
 	struct snd_trident *chip = gameport_get_port_data(gameport);
 
-	snd_assert(chip, return);
+	if (snd_BUG_ON(!chip))
+		return;
 	outb(0xff, TRID_REG(chip, GAMEPORT_LEGACY));
 }
 
@@ -3148,7 +3152,8 @@
 	struct snd_trident *chip = gameport_get_port_data(gameport);
 	int i;
 
-	snd_assert(chip, return 0);
+	if (snd_BUG_ON(!chip))
+		return 0;
 
 	*buttons = (~inb(TRID_REG(chip, GAMEPORT_LEGACY)) >> 4) & 0xf;
 
@@ -3164,7 +3169,8 @@
 {
 	struct snd_trident *chip = gameport_get_port_data(gameport);
 
-	snd_assert(chip, return 0);
+	if (snd_BUG_ON(!chip))
+		return 0;
 
 	switch (mode) {
 		case GAMEPORT_MODE_COOKED:
@@ -3891,8 +3897,8 @@
 {
 	unsigned int i, val, mask[2] = { 0, 0 };
 
-	snd_assert(v_min <= 63, return);
-	snd_assert(v_max <= 63, return);
+	if (snd_BUG_ON(v_min > 63 || v_max > 63))
+		return;
 	for (i = v_min; i <= v_max; i++)
 		mask[i >> 5] |= 1 << (i & 0x1f);
 	if (mask[0]) {
diff --git a/sound/pci/trident/trident_memory.c b/sound/pci/trident/trident_memory.c
index 3fd7f1b..f9779e2 100644
--- a/sound/pci/trident/trident_memory.c
+++ b/sound/pci/trident/trident_memory.c
@@ -194,11 +194,14 @@
 	struct snd_util_memblk *blk;
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	int idx, page;
-	struct snd_sg_buf *sgbuf = snd_pcm_substream_sgbuf(substream);
 
-	snd_assert(runtime->dma_bytes > 0 && runtime->dma_bytes <= SNDRV_TRIDENT_MAX_PAGES * SNDRV_TRIDENT_PAGE_SIZE, return NULL);
+	if (snd_BUG_ON(runtime->dma_bytes <= 0 ||
+		       runtime->dma_bytes > SNDRV_TRIDENT_MAX_PAGES *
+					SNDRV_TRIDENT_PAGE_SIZE))
+		return NULL;
 	hdr = trident->tlb.memhdr;
-	snd_assert(hdr != NULL, return NULL);
+	if (snd_BUG_ON(!hdr))
+		return NULL;
 
 	
 
@@ -208,18 +211,14 @@
 		mutex_unlock(&hdr->block_mutex);
 		return NULL;
 	}
-	if (lastpg(blk) - firstpg(blk) >= sgbuf->pages) {
-		snd_printk(KERN_ERR "page calculation doesn't match: allocated pages = %d, trident = %d/%d\n", sgbuf->pages, firstpg(blk), lastpg(blk));
-		__snd_util_mem_free(hdr, blk);
-		mutex_unlock(&hdr->block_mutex);
-		return NULL;
-	}
 			   
 	/* set TLB entries */
 	idx = 0;
 	for (page = firstpg(blk); page <= lastpg(blk); page++, idx++) {
-		dma_addr_t addr = sgbuf->table[idx].addr;
-		unsigned long ptr = (unsigned long)sgbuf->table[idx].buf;
+		unsigned long ofs = idx << PAGE_SHIFT;
+		dma_addr_t addr = snd_pcm_sgbuf_get_addr(substream, ofs);
+		unsigned long ptr = (unsigned long)
+			snd_pcm_sgbuf_get_ptr(substream, ofs);
 		if (! is_valid_page(addr)) {
 			__snd_util_mem_free(hdr, blk);
 			mutex_unlock(&hdr->block_mutex);
@@ -245,9 +244,13 @@
 	dma_addr_t addr;
 	unsigned long ptr;
 
-	snd_assert(runtime->dma_bytes> 0 && runtime->dma_bytes <= SNDRV_TRIDENT_MAX_PAGES * SNDRV_TRIDENT_PAGE_SIZE, return NULL);
+	if (snd_BUG_ON(runtime->dma_bytes <= 0 ||
+		       runtime->dma_bytes > SNDRV_TRIDENT_MAX_PAGES *
+					SNDRV_TRIDENT_PAGE_SIZE))
+		return NULL;
 	hdr = trident->tlb.memhdr;
-	snd_assert(hdr != NULL, return NULL);
+	if (snd_BUG_ON(!hdr))
+		return NULL;
 
 	mutex_lock(&hdr->block_mutex);
 	blk = search_empty(hdr, runtime->dma_bytes);
@@ -279,8 +282,8 @@
 snd_trident_alloc_pages(struct snd_trident *trident,
 			struct snd_pcm_substream *substream)
 {
-	snd_assert(trident != NULL, return NULL);
-	snd_assert(substream != NULL, return NULL);
+	if (snd_BUG_ON(!trident || !substream))
+		return NULL;
 	if (substream->dma_buffer.dev.type == SNDRV_DMA_TYPE_DEV_SG)
 		return snd_trident_alloc_sg_pages(trident, substream);
 	else
@@ -297,8 +300,8 @@
 	struct snd_util_memhdr *hdr;
 	int page;
 
-	snd_assert(trident != NULL, return -EINVAL);
-	snd_assert(blk != NULL, return -EINVAL);
+	if (snd_BUG_ON(!trident || !blk))
+		return -EINVAL;
 
 	hdr = trident->tlb.memhdr;
 	mutex_lock(&hdr->block_mutex);
diff --git a/sound/pci/via82xx.c b/sound/pci/via82xx.c
index 6781be9..1aafe95 100644
--- a/sound/pci/via82xx.c
+++ b/sound/pci/via82xx.c
@@ -313,6 +313,7 @@
 } ;
 
 #define VIA_TABLE_SIZE	255
+#define VIA_MAX_BUFSIZE	(1<<24)
 
 struct viadev {
 	unsigned int reg_offset;
@@ -420,7 +421,6 @@
 {
 	unsigned int i, idx, ofs, rest;
 	struct via82xx *chip = snd_pcm_substream_chip(substream);
-	struct snd_sg_buf *sgbuf = snd_pcm_substream_sgbuf(substream);
 
 	if (dev->table.area == NULL) {
 		/* the start of each lists must be aligned to 8 bytes,
@@ -449,15 +449,15 @@
 		do {
 			unsigned int r;
 			unsigned int flag;
+			unsigned int addr;
 
 			if (idx >= VIA_TABLE_SIZE) {
 				snd_printk(KERN_ERR "via82xx: too much table size!\n");
 				return -EINVAL;
 			}
-			((u32 *)dev->table.area)[idx << 1] = cpu_to_le32((u32)snd_pcm_sgbuf_get_addr(sgbuf, ofs));
-			r = PAGE_SIZE - (ofs % PAGE_SIZE);
-			if (rest < r)
-				r = rest;
+			addr = snd_pcm_sgbuf_get_addr(substream, ofs);
+			((u32 *)dev->table.area)[idx << 1] = cpu_to_le32(addr);
+			r = snd_pcm_sgbuf_get_chunk_size(substream, ofs, rest);
 			rest -= r;
 			if (! rest) {
 				if (i == periods - 1)
@@ -824,7 +824,8 @@
 	struct viadev *viadev = substream->runtime->private_data;
 	unsigned int idx, ptr, count, res;
 
-	snd_assert(viadev->tbl_entries, return 0);
+	if (snd_BUG_ON(!viadev->tbl_entries))
+		return 0;
 	if (!(inb(VIADEV_REG(viadev, OFFSET_STATUS)) & VIA_REG_STAT_ACTIVE))
 		return 0;
 
@@ -855,7 +856,8 @@
 	unsigned int idx, count, res;
 	int status;
 	
-	snd_assert(viadev->tbl_entries, return 0);
+	if (snd_BUG_ON(!viadev->tbl_entries))
+		return 0;
 
 	spin_lock(&chip->reg_lock);
 	count = inl(VIADEV_REG(viadev, OFFSET_CURR_COUNT));
@@ -1037,7 +1039,7 @@
 	else
 		rbits = (0x100000 / 48000) * runtime->rate +
 			((0x100000 % 48000) * runtime->rate) / 48000;
-	snd_assert((rbits & ~0xfffff) == 0, return -EINVAL);
+	snd_BUG_ON(rbits & ~0xfffff);
 	snd_via82xx_channel_reset(chip, viadev);
 	snd_via82xx_set_table_ptr(chip, viadev);
 	outb(chip->playback_volume[viadev->reg_offset / 0x10][0],
@@ -1144,9 +1146,9 @@
 	.rate_max =		48000,
 	.channels_min =		1,
 	.channels_max =		2,
-	.buffer_bytes_max =	128 * 1024,
+	.buffer_bytes_max =	VIA_MAX_BUFSIZE,
 	.period_bytes_min =	32,
-	.period_bytes_max =	128 * 1024,
+	.period_bytes_max =	VIA_MAX_BUFSIZE / 2,
 	.periods_min =		2,
 	.periods_max =		VIA_TABLE_SIZE / 2,
 	.fifo_size =		0,
@@ -1398,10 +1400,9 @@
 	/* capture */
 	init_viadev(chip, chip->capture_devno, VIA_REG_CAPTURE_8233_STATUS, 6, 1);
 
-	if ((err = snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG,
-							 snd_dma_pci_data(chip->pci),
-							 64*1024, 128*1024)) < 0)
-		return err;
+	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG,
+					      snd_dma_pci_data(chip->pci),
+					      64*1024, VIA_MAX_BUFSIZE);
 
 	/* PCM #1:  multi-channel playback and 2nd capture */
 	err = snd_pcm_new(chip->card, chip->card->shortname, 1, 1, 1, &pcm);
@@ -1417,11 +1418,9 @@
 	/* set up capture */
 	init_viadev(chip, chip->capture_devno + 1, VIA_REG_CAPTURE_8233_STATUS + 0x10, 7, 1);
 
-	if ((err = snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG,
-						         snd_dma_pci_data(chip->pci),
-							 64*1024, 128*1024)) < 0)
-		return err;
-
+	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG,
+					      snd_dma_pci_data(chip->pci),
+					      64*1024, VIA_MAX_BUFSIZE);
 	return 0;
 }
 
@@ -1453,10 +1452,9 @@
 	/* capture */
 	init_viadev(chip, chip->capture_devno, VIA_REG_CAPTURE_8233_STATUS, 6, 1);
 
-	if ((err = snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG,
-							 snd_dma_pci_data(chip->pci),
-							 64*1024, 128*1024)) < 0)
-		return err;
+	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG,
+					      snd_dma_pci_data(chip->pci),
+					      64*1024, VIA_MAX_BUFSIZE);
 
 	/* SPDIF supported? */
 	if (! ac97_can_spdif(chip->ac97))
@@ -1473,11 +1471,9 @@
 	/* set up playback */
 	init_viadev(chip, chip->playback_devno, 0x30, 3, 0);
 
-	if ((err = snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG,
-							 snd_dma_pci_data(chip->pci),
-							 64*1024, 128*1024)) < 0)
-		return err;
-
+	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG,
+					      snd_dma_pci_data(chip->pci),
+					      64*1024, VIA_MAX_BUFSIZE);
 	return 0;
 }
 
@@ -1505,11 +1501,9 @@
 	init_viadev(chip, 0, VIA_REG_PLAYBACK_STATUS, 0, 0);
 	init_viadev(chip, 1, VIA_REG_CAPTURE_STATUS, 0, 1);
 
-	if ((err = snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG,
-							 snd_dma_pci_data(chip->pci),
-							 64*1024, 128*1024)) < 0)
-		return err;
-
+	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG,
+					      snd_dma_pci_data(chip->pci),
+					      64*1024, VIA_MAX_BUFSIZE);
 	return 0;
 }
 
diff --git a/sound/pci/via82xx_modem.c b/sound/pci/via82xx_modem.c
index 31f64ee..5bd79d2 100644
--- a/sound/pci/via82xx_modem.c
+++ b/sound/pci/via82xx_modem.c
@@ -281,7 +281,6 @@
 {
 	unsigned int i, idx, ofs, rest;
 	struct via82xx_modem *chip = snd_pcm_substream_chip(substream);
-	struct snd_sg_buf *sgbuf = snd_pcm_substream_sgbuf(substream);
 
 	if (dev->table.area == NULL) {
 		/* the start of each lists must be aligned to 8 bytes,
@@ -310,12 +309,14 @@
 		do {
 			unsigned int r;
 			unsigned int flag;
+			unsigned int addr;
 
 			if (idx >= VIA_TABLE_SIZE) {
 				snd_printk(KERN_ERR "via82xx: too much table size!\n");
 				return -EINVAL;
 			}
-			((u32 *)dev->table.area)[idx << 1] = cpu_to_le32((u32)snd_pcm_sgbuf_get_addr(sgbuf, ofs));
+			addr = snd_pcm_sgbuf_get_addr(substream, ofs);
+			((u32 *)dev->table.area)[idx << 1] = cpu_to_le32(addr);
 			r = PAGE_SIZE - (ofs % PAGE_SIZE);
 			if (rest < r)
 				r = rest;
@@ -612,7 +613,8 @@
 	struct viadev *viadev = substream->runtime->private_data;
 	unsigned int idx, ptr, count, res;
 
-	snd_assert(viadev->tbl_entries, return 0);
+	if (snd_BUG_ON(!viadev->tbl_entries))
+		return 0;
 	if (!(inb(VIADEV_REG(viadev, OFFSET_STATUS)) & VIA_REG_STAT_ACTIVE))
 		return 0;
 
diff --git a/sound/pci/vx222/vx222_ops.c b/sound/pci/vx222/vx222_ops.c
index 631f3a6..7e87f39 100644
--- a/sound/pci/vx222/vx222_ops.c
+++ b/sound/pci/vx222/vx222_ops.c
@@ -253,7 +253,8 @@
 	int offset = pipe->hw_ptr;
 	u32 *addr = (u32 *)(runtime->dma_area + offset);
 
-	snd_assert(count % 4 == 0, return);
+	if (snd_BUG_ON(count % 4))
+		return;
 
 	vx2_setup_pseudo_dma(chip, 1);
 
@@ -291,7 +292,8 @@
 	u32 *addr = (u32 *)(runtime->dma_area + offset);
 	unsigned long port = vx2_reg_addr(chip, VX_DMA);
 
-	snd_assert(count % 4 == 0, return);
+	if (snd_BUG_ON(count % 4))
+		return;
 
 	vx2_setup_pseudo_dma(chip, 0);
 	/* Transfer using pseudo-dma.
@@ -675,7 +677,8 @@
 	   a look up table, as there is no linear matching between the driver codec values
 	   and the real dBu value
 	*/
-	snd_assert(data < sizeof(vx2_akm_gains_lut), return);
+	if (snd_BUG_ON(data >= sizeof(vx2_akm_gains_lut)))
+		return;
 
 	switch (reg) {
 	case XX_CODEC_LEVEL_LEFT_REGISTER:
@@ -823,7 +826,8 @@
 		preamp++;	/* raise pre ampli + 18dB */
 		miclevel -= (18 * 2);   /* lower level 18 dB (*2 because of 0.5 dB steps !) */
         }
-	snd_assert(preamp < 4, return);
+	if (snd_BUG_ON(preamp >= 4))
+		return;
 
 	/* set pre-amp level */
 	chip->regSELMIC &= ~MICRO_SELECT_PREAMPLI_MASK;
diff --git a/sound/pci/ymfpci/ymfpci_main.c b/sound/pci/ymfpci/ymfpci_main.c
index 92d49aa..90d0d62 100644
--- a/sound/pci/ymfpci/ymfpci_main.c
+++ b/sound/pci/ymfpci/ymfpci_main.c
@@ -259,8 +259,10 @@
 	unsigned long flags;
 	int result;
 	
-	snd_assert(rvoice != NULL, return -EINVAL);
-	snd_assert(!pair || type == YMFPCI_PCM, return -EINVAL);
+	if (snd_BUG_ON(!rvoice))
+		return -EINVAL;
+	if (snd_BUG_ON(pair && type != YMFPCI_PCM))
+		return -EINVAL;
 	
 	spin_lock_irqsave(&chip->voice_lock, flags);
 	for (;;) {
@@ -278,7 +280,8 @@
 {
 	unsigned long flags;
 	
-	snd_assert(pvoice != NULL, return -EINVAL);
+	if (snd_BUG_ON(!pvoice))
+		return -EINVAL;
 	snd_ymfpci_hw_stop(chip);
 	spin_lock_irqsave(&chip->voice_lock, flags);
 	if (pvoice->number == chip->src441_used) {
@@ -494,7 +497,8 @@
 	u8 use_left, use_right;
 	unsigned long flags;
 
-	snd_assert(voice != NULL, return);
+	if (snd_BUG_ON(!voice))
+		return;
 	if (runtime->channels == 1) {
 		use_left = 1;
 		use_right = 1;
@@ -1813,7 +1817,8 @@
 	}
 
 	/* add S/PDIF control */
-	snd_assert(chip->pcm_spdif != NULL, return -EIO);
+	if (snd_BUG_ON(!chip->pcm_spdif))
+		return -ENXIO;
 	if ((err = snd_ctl_add(chip->card, kctl = snd_ctl_new1(&snd_ymfpci_spdif_default, chip))) < 0)
 		return err;
 	kctl->id.device = chip->pcm_spdif->device;
@@ -2133,7 +2138,8 @@
 	chip->work_base = ptr;
 	chip->work_base_addr = ptr_addr;
 	
-	snd_assert(ptr + chip->work_size == chip->work_ptr.area + chip->work_ptr.bytes, );
+	snd_BUG_ON(ptr + chip->work_size !=
+		   chip->work_ptr.area + chip->work_ptr.bytes);
 
 	snd_ymfpci_writel(chip, YDSXGR_PLAYCTRLBASE, chip->bank_base_playback_addr);
 	snd_ymfpci_writel(chip, YDSXGR_RECCTRLBASE, chip->bank_base_capture_addr);
@@ -2168,7 +2174,8 @@
 {
 	u16 ctrl;
 
-	snd_assert(chip != NULL, return -EINVAL);
+	if (snd_BUG_ON(!chip))
+		return -EINVAL;
 
 	if (chip->res_reg_area) {	/* don't touch busy hardware */
 		snd_ymfpci_writel(chip, YDSXGR_NATIVEDACOUTVOL, 0);
diff --git a/sound/pcmcia/vx/vxp_ops.c b/sound/pcmcia/vx/vxp_ops.c
index 99bf2a6..989e04a 100644
--- a/sound/pcmcia/vx/vxp_ops.c
+++ b/sound/pcmcia/vx/vxp_ops.c
@@ -408,7 +408,8 @@
 	int offset = pipe->hw_ptr;
 	unsigned short *addr = (unsigned short *)(runtime->dma_area + offset);
 
-	snd_assert(count % 2 == 0, return);
+	if (snd_BUG_ON(count % 2))
+		return;
 	vx_setup_pseudo_dma(chip, 0);
 	if (offset + count > pipe->buffer_bytes) {
 		int length = pipe->buffer_bytes - offset;
diff --git a/sound/ppc/awacs.c b/sound/ppc/awacs.c
index 566a6d0..7bd33e6 100644
--- a/sound/ppc/awacs.c
+++ b/sound/ppc/awacs.c
@@ -319,7 +319,8 @@
 static void awacs_amp_free(struct snd_pmac *chip)
 {
 	struct awacs_amp *amp = chip->mixer_data;
-	snd_assert(amp, return);
+	if (!amp)
+		return;
 	kfree(amp);
 	chip->mixer_data = NULL;
 	chip->mixer_free = NULL;
@@ -345,8 +346,7 @@
 	struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
 	int index = kcontrol->private_value;
 	struct awacs_amp *amp = chip->mixer_data;
-	snd_assert(amp, return -EINVAL);
-	snd_assert(index >= 0 && index <= 1, return -EINVAL);
+
 	ucontrol->value.integer.value[0] = 31 - (amp->amp_vol[index][0] & 31);
 	ucontrol->value.integer.value[1] = 31 - (amp->amp_vol[index][1] & 31);
 	return 0;
@@ -359,8 +359,6 @@
 	int index = kcontrol->private_value;
 	int vol[2];
 	struct awacs_amp *amp = chip->mixer_data;
-	snd_assert(amp, return -EINVAL);
-	snd_assert(index >= 0 && index <= 1, return -EINVAL);
 
 	vol[0] = (31 - (ucontrol->value.integer.value[0] & 31))
 		| (amp->amp_vol[index][0] & 32);
@@ -375,8 +373,7 @@
 	struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
 	int index = kcontrol->private_value;
 	struct awacs_amp *amp = chip->mixer_data;
-	snd_assert(amp, return -EINVAL);
-	snd_assert(index >= 0 && index <= 1, return -EINVAL);
+
 	ucontrol->value.integer.value[0] = (amp->amp_vol[index][0] & 32)
 					? 0 : 1;
 	ucontrol->value.integer.value[1] = (amp->amp_vol[index][1] & 32)
@@ -391,8 +388,6 @@
 	int index = kcontrol->private_value;
 	int vol[2];
 	struct awacs_amp *amp = chip->mixer_data;
-	snd_assert(amp, return -EINVAL);
-	snd_assert(index >= 0 && index <= 1, return -EINVAL);
 
 	vol[0] = (ucontrol->value.integer.value[0] ? 0 : 32)
 		| (amp->amp_vol[index][0] & 31);
@@ -417,8 +412,7 @@
 	struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
 	int index = kcontrol->private_value;
 	struct awacs_amp *amp = chip->mixer_data;
-	snd_assert(amp, return -EINVAL);
-	snd_assert(index >= 0 && index <= 1, return -EINVAL);
+
 	ucontrol->value.integer.value[0] = amp->amp_tone[index];
 	return 0;
 }
@@ -430,8 +424,7 @@
 	int index = kcontrol->private_value;
 	struct awacs_amp *amp = chip->mixer_data;
 	unsigned int val;
-	snd_assert(amp, return -EINVAL);
-	snd_assert(index >= 0 && index <= 1, return -EINVAL);
+
 	val = ucontrol->value.integer.value[0];
 	if (val > 14)
 		return -EINVAL;
@@ -458,7 +451,7 @@
 {
 	struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
 	struct awacs_amp *amp = chip->mixer_data;
-	snd_assert(amp, return -EINVAL);
+
 	ucontrol->value.integer.value[0] = amp->amp_master;
 	return 0;
 }
@@ -469,7 +462,7 @@
 	struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
 	struct awacs_amp *amp = chip->mixer_data;
 	unsigned int val;
-	snd_assert(amp, return -EINVAL);
+
 	val = ucontrol->value.integer.value[0];
 	if (val > 99)
 		return -EINVAL;
@@ -621,6 +614,13 @@
 	AWACS_SWITCH("CD Capture Switch", 0, SHIFT_MUX_CD, 0),
 };
 
+static struct snd_kcontrol_new snd_pmac_screamer_mixers_g4agp[] __initdata = {
+	AWACS_VOLUME("Line out Playback Volume", 2, 6, 1),
+	AWACS_VOLUME("Master Playback Volume", 5, 6, 1),
+	AWACS_SWITCH("CD Capture Switch", 0, SHIFT_MUX_CD, 0),
+	AWACS_SWITCH("Line Capture Switch", 0, SHIFT_MUX_MIC, 0),
+};
+
 static struct snd_kcontrol_new snd_pmac_awacs_mixers_pmac7500[] __initdata = {
 	AWACS_VOLUME("Line out Playback Volume", 2, 6, 1),
 	AWACS_SWITCH("CD Capture Switch", 0, SHIFT_MUX_CD, 0),
@@ -688,7 +688,10 @@
 static struct snd_kcontrol_new snd_pmac_awacs_speaker_sw __initdata =
 AWACS_SWITCH("PC Speaker Playback Switch", 1, SHIFT_SPKMUTE, 1);
 
-static struct snd_kcontrol_new snd_pmac_awacs_speaker_sw_imac __initdata =
+static struct snd_kcontrol_new snd_pmac_awacs_speaker_sw_imac1 __initdata =
+AWACS_SWITCH("PC Speaker Playback Switch", 1, SHIFT_PAROUT1, 1);
+
+static struct snd_kcontrol_new snd_pmac_awacs_speaker_sw_imac2 __initdata =
 AWACS_SWITCH("PC Speaker Playback Switch", 1, SHIFT_PAROUT1, 0);
 
 
@@ -765,11 +768,12 @@
 
 #define IS_PM7500 (machine_is_compatible("AAPL,7500"))
 #define IS_BEIGE (machine_is_compatible("AAPL,Gossamer"))
-#define IS_IMAC (machine_is_compatible("PowerMac2,1") \
-		|| machine_is_compatible("PowerMac2,2") \
+#define IS_IMAC1 (machine_is_compatible("PowerMac2,1"))
+#define IS_IMAC2 (machine_is_compatible("PowerMac2,2") \
 		|| machine_is_compatible("PowerMac4,1"))
+#define IS_G4AGP (machine_is_compatible("PowerMac3,1"))
 
-static int imac;
+static int imac1, imac2;
 
 #ifdef PMAC_SUPPORT_AUTOMUTE
 /*
@@ -815,13 +819,18 @@
 		{
 			int reg = chip->awacs_reg[1]
 				| (MASK_HDMUTE | MASK_SPKMUTE);
-			if (imac) {
+			if (imac1) {
+				reg &= ~MASK_SPKMUTE;
+				reg |= MASK_PAROUT1;
+			} else if (imac2) {
 				reg &= ~MASK_SPKMUTE;
 				reg &= ~MASK_PAROUT1;
 			}
 			if (snd_pmac_awacs_detect_headphone(chip))
 				reg &= ~MASK_HDMUTE;
-			else if (imac)
+			else if (imac1)
+				reg &= ~MASK_PAROUT1;
+			else if (imac2)
 				reg |= MASK_PAROUT1;
 			else
 				reg &= ~MASK_SPKMUTE;
@@ -850,9 +859,13 @@
 {
 	int pm7500 = IS_PM7500;
 	int beige = IS_BEIGE;
+	int g4agp = IS_G4AGP;
+	int imac;
 	int err, vol;
 
-	imac = IS_IMAC;
+	imac1 = IS_IMAC1;
+	imac2 = IS_IMAC2;
+	imac = imac1 || imac2;
 	/* looks like MASK_GAINLINE triggers something, so we set here
 	 * as start-up
 	 */
@@ -939,7 +952,7 @@
 				snd_pmac_awacs_mixers);
 	if (err < 0)
 		return err;
-	if (beige)
+	if (beige || g4agp)
 		;
 	else if (chip->model == PMAC_SCREAMER)
 		err = build_mixers(chip, ARRAY_SIZE(snd_pmac_screamer_mixers2),
@@ -961,13 +974,17 @@
 		err = build_mixers(chip,
 				   ARRAY_SIZE(snd_pmac_screamer_mixers_imac),
 				   snd_pmac_screamer_mixers_imac);
+	else if (g4agp)
+		err = build_mixers(chip,
+				   ARRAY_SIZE(snd_pmac_screamer_mixers_g4agp),
+				   snd_pmac_screamer_mixers_g4agp);
 	else
 		err = build_mixers(chip,
 				   ARRAY_SIZE(snd_pmac_awacs_mixers_pmac),
 				   snd_pmac_awacs_mixers_pmac);
 	if (err < 0)
 		return err;
-	chip->master_sw_ctl = snd_ctl_new1((pm7500 || imac)
+	chip->master_sw_ctl = snd_ctl_new1((pm7500 || imac || g4agp)
 			? &snd_pmac_awacs_master_sw_imac
 			: &snd_pmac_awacs_master_sw, chip);
 	err = snd_ctl_add(chip->card, chip->master_sw_ctl);
@@ -1004,15 +1021,17 @@
 					snd_pmac_awacs_speaker_vol);
 		if (err < 0)
 			return err;
-		chip->speaker_sw_ctl = snd_ctl_new1(imac
-				? &snd_pmac_awacs_speaker_sw_imac
+		chip->speaker_sw_ctl = snd_ctl_new1(imac1
+				? &snd_pmac_awacs_speaker_sw_imac1
+				: imac2
+				? &snd_pmac_awacs_speaker_sw_imac2
 				: &snd_pmac_awacs_speaker_sw, chip);
 		err = snd_ctl_add(chip->card, chip->speaker_sw_ctl);
 		if (err < 0)
 			return err;
 	}
 
-	if (beige)
+	if (beige || g4agp)
 		err = build_mixers(chip,
 				ARRAY_SIZE(snd_pmac_screamer_mic_boost_beige),
 				snd_pmac_screamer_mic_boost_beige);
diff --git a/sound/ppc/beep.c b/sound/ppc/beep.c
index baa2a72..89f5c32 100644
--- a/sound/ppc/beep.c
+++ b/sound/ppc/beep.c
@@ -185,7 +185,8 @@
 			     struct snd_ctl_elem_value *ucontrol)
 {
 	struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
-	snd_assert(chip->beep, return -ENXIO);
+	if (snd_BUG_ON(!chip->beep))
+		return -ENXIO;
 	ucontrol->value.integer.value[0] = chip->beep->volume;
 	return 0;
 }
@@ -195,7 +196,8 @@
 {
 	struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
 	unsigned int oval, nval;
-	snd_assert(chip->beep, return -ENXIO);
+	if (snd_BUG_ON(!chip->beep))
+		return -ENXIO;
 	oval = chip->beep->volume;
 	nval = ucontrol->value.integer.value[0];
 	if (nval > 100)
diff --git a/sound/ppc/tumbler.c b/sound/ppc/tumbler.c
index 009df8d..f746e15 100644
--- a/sound/ppc/tumbler.c
+++ b/sound/ppc/tumbler.c
@@ -263,7 +263,7 @@
 {
 	struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
 	struct pmac_tumbler *mix = chip->mixer_data;
-	snd_assert(mix, return -ENODEV);
+
 	ucontrol->value.integer.value[0] = mix->master_vol[0];
 	ucontrol->value.integer.value[1] = mix->master_vol[1];
 	return 0;
@@ -277,7 +277,6 @@
 	unsigned int vol[2];
 	int change;
 
-	snd_assert(mix, return -ENODEV);
 	vol[0] = ucontrol->value.integer.value[0];
 	vol[1] = ucontrol->value.integer.value[1];
 	if (vol[0] >= ARRAY_SIZE(master_volume_table) ||
@@ -299,7 +298,7 @@
 {
 	struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
 	struct pmac_tumbler *mix = chip->mixer_data;
-	snd_assert(mix, return -ENODEV);
+
 	ucontrol->value.integer.value[0] = mix->master_switch[0];
 	ucontrol->value.integer.value[1] = mix->master_switch[1];
 	return 0;
@@ -312,7 +311,6 @@
 	struct pmac_tumbler *mix = chip->mixer_data;
 	int change;
 
-	snd_assert(mix, return -ENODEV);
 	change = mix->master_switch[0] != ucontrol->value.integer.value[0] ||
 		mix->master_switch[1] != ucontrol->value.integer.value[1];
 	if (change) {
@@ -807,7 +805,6 @@
 	struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
 	struct pmac_tumbler *mix = chip->mixer_data;
 
-	snd_assert(mix, return -ENODEV);
 	ucontrol->value.enumerated.item[0] = mix->capture_source;
 	return 0;
 }
@@ -819,7 +816,6 @@
 	struct pmac_tumbler *mix = chip->mixer_data;
 	int change;
 
-	snd_assert(mix, return -ENODEV);
 	change = ucontrol->value.enumerated.item[0] != mix->capture_source;
 	if (change) {
 		mix->capture_source = !!ucontrol->value.enumerated.item[0];
@@ -978,7 +974,8 @@
 		return;
 
 	mix = chip->mixer_data;
-	snd_assert(mix, return);
+	if (snd_BUG_ON(!mix))
+		return;
 
 	headphone = tumbler_detect_headphone(chip);
 	lineout = tumbler_detect_lineout(chip);
@@ -1033,7 +1030,8 @@
 	if (chip->auto_mute) {
 		struct pmac_tumbler *mix;
 		mix = chip->mixer_data;
-		snd_assert(mix, return);
+		if (snd_BUG_ON(!mix))
+			return;
 		mix->auto_mute_notify = do_notify;
 		schedule_work(&device_change);
 	}
@@ -1227,8 +1225,6 @@
 {
 	struct pmac_tumbler *mix = chip->mixer_data;
 
-	snd_assert(mix, return);
-
 	mix->acs &= ~1;
 	mix->master_switch[0] = mix->save_master_switch[0];
 	mix->master_switch[1] = mix->save_master_switch[1];
@@ -1275,7 +1271,6 @@
 {
 	int irq;
 	struct pmac_tumbler *mix = chip->mixer_data;
-	snd_assert(mix, return -EINVAL);
 
 	if (tumbler_find_device("audio-hw-reset",
 				"platform-do-hw-reset",
diff --git a/sound/sh/aica.c b/sound/sh/aica.c
index 54df8ba..7c920f3 100644
--- a/sound/sh/aica.c
+++ b/sound/sh/aica.c
@@ -106,7 +106,8 @@
 {
 	int i;
 	unsigned long flags;
-	snd_assert(length % 4 == 0, return);
+	if (snd_BUG_ON(length % 4))
+		return;
 	for (i = 0; i < length; i++) {
 		if (!(i % 8))
 			spu_write_wait();
@@ -589,7 +590,7 @@
 	return 0;
 }
 
-static int snd_aica_remove(struct platform_device *devptr)
+static int __devexit snd_aica_remove(struct platform_device *devptr)
 {
 	struct snd_card_aica *dreamcastcard;
 	dreamcastcard = platform_get_drvdata(devptr);
@@ -601,7 +602,7 @@
 	return 0;
 }
 
-static int __init snd_aica_probe(struct platform_device *devptr)
+static int __devinit snd_aica_probe(struct platform_device *devptr)
 {
 	int err;
 	struct snd_card_aica *dreamcastcard;
@@ -650,7 +651,7 @@
 
 static struct platform_driver snd_aica_driver = {
 	.probe = snd_aica_probe,
-	.remove = snd_aica_remove,
+	.remove = __devexit_p(snd_aica_remove),
 	.driver = {
 		   .name = SND_AICA_DRIVER},
 };
diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig
index f743530..4dfda66 100644
--- a/sound/soc/Kconfig
+++ b/sound/soc/Kconfig
@@ -5,6 +5,7 @@
 menuconfig SND_SOC
 	tristate "ALSA for SoC audio support"
 	select SND_PCM
+	select AC97_BUS if SND_SOC_AC97_BUS
 	---help---
 
 	  If you want ASoC support, you should say Y here and also to the
@@ -31,6 +32,7 @@
 source "sound/soc/fsl/Kconfig"
 source "sound/soc/davinci/Kconfig"
 source "sound/soc/omap/Kconfig"
+source "sound/soc/blackfin/Kconfig"
 
 # Supported codecs
 source "sound/soc/codecs/Kconfig"
diff --git a/sound/soc/Makefile b/sound/soc/Makefile
index 933a66d..d849349 100644
--- a/sound/soc/Makefile
+++ b/sound/soc/Makefile
@@ -2,4 +2,4 @@
 
 obj-$(CONFIG_SND_SOC)	+= snd-soc-core.o
 obj-$(CONFIG_SND_SOC)	+= codecs/ at32/ at91/ pxa/ s3c24xx/ sh/ fsl/ davinci/
-obj-$(CONFIG_SND_SOC)	+= omap/ au1x/
+obj-$(CONFIG_SND_SOC)	+= omap/ au1x/ blackfin/
diff --git a/sound/soc/at32/at32-pcm.c b/sound/soc/at32/at32-pcm.c
index 435f1da..c83584f 100644
--- a/sound/soc/at32/at32-pcm.c
+++ b/sound/soc/at32/at32-pcm.c
@@ -434,7 +434,8 @@
 	params = prtd->params;
 
 	/* Disable the PDC and save the PDC registers */
-	ssc_writex(params->ssc->regs, PDC_PTCR, params->mask->pdc_disable);
+	ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR,
+		   params->mask->pdc_disable);
 
 	prtd->pdc_xpr_save = ssc_readx(params->ssc->regs, params->pdc->xpr);
 	prtd->pdc_xcr_save = ssc_readx(params->ssc->regs, params->pdc->xcr);
@@ -464,7 +465,7 @@
 	ssc_writex(params->ssc->regs, params->pdc->xnpr, prtd->pdc_xnpr_save);
 	ssc_writex(params->ssc->regs, params->pdc->xncr, prtd->pdc_xncr_save);
 
-	ssc_writex(params->ssc->regs, PDC_PTCR, params->mask->pdc_enable);
+	ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR, params->mask->pdc_enable);
 	return 0;
 }
 #else /* CONFIG_PM */
diff --git a/sound/soc/at32/playpaq_wm8510.c b/sound/soc/at32/playpaq_wm8510.c
index 3f32621..98a2d58 100644
--- a/sound/soc/at32/playpaq_wm8510.c
+++ b/sound/soc/at32/playpaq_wm8510.c
@@ -377,6 +377,7 @@
 
 
 static struct wm8510_setup_data playpaq_wm8510_setup = {
+	.i2c_bus = 0,
 	.i2c_address = 0x1a,
 };
 
@@ -405,7 +406,6 @@
 	ssc = ssc_request(0);
 	if (IS_ERR(ssc)) {
 		ret = PTR_ERR(ssc);
-		ssc = NULL;
 		goto err_ssc;
 	}
 	ssc_p->ssc = ssc;
@@ -476,10 +476,7 @@
 		_gclk0 = NULL;
 	}
 err_gclk0:
-	if (ssc != NULL) {
-		ssc_free(ssc);
-		ssc = NULL;
-	}
+	ssc_free(ssc);
 err_ssc:
 	return ret;
 }
diff --git a/sound/soc/at91/Kconfig b/sound/soc/at91/Kconfig
index 9051865..85a8832 100644
--- a/sound/soc/at91/Kconfig
+++ b/sound/soc/at91/Kconfig
@@ -8,20 +8,3 @@
 
 config SND_AT91_SOC_SSC
 	tristate
-
-config SND_AT91_SOC_ETI_B1_WM8731
-	tristate "SoC Audio support for WM8731-based Endrelia ETI-B1 boards"
-	depends on SND_AT91_SOC && (MACH_ETI_B1 || MACH_ETI_C1)
-	select SND_AT91_SOC_SSC
-	select SND_SOC_WM8731
-	help
-	  Say Y if you want to add support for SoC audio on WM8731-based
-	  Endrelia Technologies Inc ETI-B1 or ETI-C1 boards.
-
-config SND_AT91_SOC_ETI_SLAVE
-	bool "Run codec in slave Mode on Endrelia boards"
-	depends on SND_AT91_SOC_ETI_B1_WM8731
-	default n
-	help
-	  Say Y if you want to run with the AT91 SSC generating the BCLK
-	  and LRC signals on Endrelia boards.
diff --git a/sound/soc/at91/Makefile b/sound/soc/at91/Makefile
index f23da17..b817f11 100644
--- a/sound/soc/at91/Makefile
+++ b/sound/soc/at91/Makefile
@@ -4,8 +4,3 @@
 
 obj-$(CONFIG_SND_AT91_SOC) += snd-soc-at91.o
 obj-$(CONFIG_SND_AT91_SOC_SSC) += snd-soc-at91-ssc.o
-
-# AT91 Machine Support
-snd-soc-eti-b1-wm8731-objs := eti_b1_wm8731.o
-
-obj-$(CONFIG_SND_AT91_SOC_ETI_B1_WM8731) += snd-soc-eti-b1-wm8731.o
diff --git a/sound/soc/at91/at91-ssc.c b/sound/soc/at91/at91-ssc.c
index 5d44515..1b61cc4 100644
--- a/sound/soc/at91/at91-ssc.c
+++ b/sound/soc/at91/at91-ssc.c
@@ -5,7 +5,7 @@
  *         Endrelia Technologies Inc.
  *
  * Based on pxa2xx Platform drivers by
- * Liam Girdwood <liam.girdwood@wolfsonmicro.com>
+ * Liam Girdwood <lrg@slimlogic.co.uk>
  *
  *  This program is free software; you can redistribute  it and/or modify it
  *  under  the terms of  the GNU General  Public License as published by the
@@ -408,7 +408,7 @@
 		dma_params->pdc_xfer_size = 4;
 		break;
 	default:
-		printk(KERN_WARNING "at91-ssc: unsupported PCM format");
+		printk(KERN_WARNING "at91-ssc: unsupported PCM format\n");
 		return -EINVAL;
 	}
 
diff --git a/sound/soc/at91/eti_b1_wm8731.c b/sound/soc/at91/eti_b1_wm8731.c
deleted file mode 100644
index b81d6b2..0000000
--- a/sound/soc/at91/eti_b1_wm8731.c
+++ /dev/null
@@ -1,348 +0,0 @@
-/*
- * eti_b1_wm8731  --  SoC audio for AT91RM9200-based Endrelia ETI_B1 board.
- *
- * Author:	Frank Mandarino <fmandarino@endrelia.com>
- *		Endrelia Technologies Inc.
- * Created:	Mar 29, 2006
- *
- * Based on corgi.c by:
- *
- * Copyright 2005 Wolfson Microelectronics PLC.
- * Copyright 2005 Openedhand Ltd.
- *
- * Authors: Liam Girdwood <liam.girdwood@wolfsonmicro.com>
- *          Richard Purdie <richard@openedhand.com>
- *
- *  This program is free software; you can redistribute  it and/or modify it
- *  under  the terms of  the GNU General  Public License as published by the
- *  Free Software Foundation;  either version 2 of the  License, or (at your
- *  option) any later version.
- *
- */
-
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/kernel.h>
-#include <linux/clk.h>
-#include <linux/timer.h>
-#include <linux/interrupt.h>
-#include <linux/platform_device.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/soc.h>
-#include <sound/soc-dapm.h>
-
-#include <mach/hardware.h>
-#include <mach/gpio.h>
-
-#include "../codecs/wm8731.h"
-#include "at91-pcm.h"
-#include "at91-ssc.h"
-
-#if 0
-#define	DBG(x...)	printk(KERN_INFO "eti_b1_wm8731: " x)
-#else
-#define	DBG(x...)
-#endif
-
-static struct clk *pck1_clk;
-static struct clk *pllb_clk;
-
-
-static int eti_b1_startup(struct snd_pcm_substream *substream)
-{
-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
-	struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
-	int ret;
-
-	/* cpu clock is the AT91 master clock sent to the SSC */
-	ret = snd_soc_dai_set_sysclk(cpu_dai, AT91_SYSCLK_MCK,
-		60000000, SND_SOC_CLOCK_IN);
-	if (ret < 0)
-		return ret;
-
-	/* codec system clock is supplied by PCK1, set to 12MHz */
-	ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK,
-		12000000, SND_SOC_CLOCK_IN);
-	if (ret < 0)
-		return ret;
-
-	/* Start PCK1 clock. */
-	clk_enable(pck1_clk);
-	DBG("pck1 started\n");
-
-	return 0;
-}
-
-static void eti_b1_shutdown(struct snd_pcm_substream *substream)
-{
-	/* Stop PCK1 clock. */
-	clk_disable(pck1_clk);
-	DBG("pck1 stopped\n");
-}
-
-static int eti_b1_hw_params(struct snd_pcm_substream *substream,
-	struct snd_pcm_hw_params *params)
-{
-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
-	struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
-	int ret;
-
-#ifdef CONFIG_SND_AT91_SOC_ETI_SLAVE
-	unsigned int rate;
-	int cmr_div, period;
-
-	/* set codec DAI configuration */
-	ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
-		SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
-	if (ret < 0)
-		return ret;
-
-	/* set cpu DAI configuration */
-	ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
-		SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
-	if (ret < 0)
-		return ret;
-
-	/*
-	 * The SSC clock dividers depend on the sample rate.  The CMR.DIV
-	 * field divides the system master clock MCK to drive the SSC TK
-	 * signal which provides the codec BCLK.  The TCMR.PERIOD and
-	 * RCMR.PERIOD fields further divide the BCLK signal to drive
-	 * the SSC TF and RF signals which provide the codec DACLRC and
-	 * ADCLRC clocks.
-	 *
-	 * The dividers were determined through trial and error, where a
-	 * CMR.DIV value is chosen such that the resulting BCLK value is
-	 * divisible, or almost divisible, by (2 * sample rate), and then
-	 * the TCMR.PERIOD or RCMR.PERIOD is BCLK / (2 * sample rate) - 1.
-	 */
-	rate = params_rate(params);
-
-	switch (rate) {
-	case 8000:
-		cmr_div = 25;	/* BCLK = 60MHz/(2*25) = 1.2MHz */
-		period = 74;	/* LRC = BCLK/(2*(74+1)) = 8000Hz */
-		break;
-	case 32000:
-		cmr_div = 7;	/* BCLK = 60MHz/(2*7) ~= 4.28571428MHz */
-		period = 66;	/* LRC = BCLK/(2*(66+1)) = 31982.942Hz */
-		break;
-	case 48000:
-		cmr_div = 13;	/* BCLK = 60MHz/(2*13) ~= 2.3076923MHz */
-		period = 23;	/* LRC = BCLK/(2*(23+1)) = 48076.923Hz */
-		break;
-	default:
-		printk(KERN_WARNING "unsupported rate %d on ETI-B1 board\n", rate);
-		return -EINVAL;
-	}
-
-	/* set the MCK divider for BCLK */
-	ret = snd_soc_dai_set_clkdiv(cpu_dai, AT91SSC_CMR_DIV, cmr_div);
-	if (ret < 0)
-		return ret;
-
-	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-		/* set the BCLK divider for DACLRC */
-		ret = snd_soc_dai_set_clkdiv(cpu_dai,
-						AT91SSC_TCMR_PERIOD, period);
-	} else {
-		/* set the BCLK divider for ADCLRC */
-		ret = snd_soc_dai_set_clkdiv(cpu_dai,
-						AT91SSC_RCMR_PERIOD, period);
-	}
-	if (ret < 0)
-		return ret;
-
-#else /* CONFIG_SND_AT91_SOC_ETI_SLAVE */
-	/*
-	 * Codec in Master Mode.
-	 */
-
-	/* set codec DAI configuration */
-	ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
-		SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
-	if (ret < 0)
-		return ret;
-
-	/* set cpu DAI configuration */
-	ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
-		SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
-	if (ret < 0)
-		return ret;
-
-#endif /* CONFIG_SND_AT91_SOC_ETI_SLAVE */
-
-	return 0;
-}
-
-static struct snd_soc_ops eti_b1_ops = {
-	.startup = eti_b1_startup,
-	.hw_params = eti_b1_hw_params,
-	.shutdown = eti_b1_shutdown,
-};
-
-
-static const struct snd_soc_dapm_widget eti_b1_dapm_widgets[] = {
-	SND_SOC_DAPM_MIC("Int Mic", NULL),
-	SND_SOC_DAPM_SPK("Ext Spk", NULL),
-};
-
-static const struct snd_soc_dapm_route intercon[] = {
-
-	/* speaker connected to LHPOUT */
-	{"Ext Spk", NULL, "LHPOUT"},
-
-	/* mic is connected to Mic Jack, with WM8731 Mic Bias */
-	{"MICIN", NULL, "Mic Bias"},
-	{"Mic Bias", NULL, "Int Mic"},
-};
-
-/*
- * Logic for a wm8731 as connected on a Endrelia ETI-B1 board.
- */
-static int eti_b1_wm8731_init(struct snd_soc_codec *codec)
-{
-	DBG("eti_b1_wm8731_init() called\n");
-
-	/* Add specific widgets */
-	snd_soc_dapm_new_controls(codec, eti_b1_dapm_widgets,
-				  ARRAY_SIZE(eti_b1_dapm_widgets));
-
-	/* Set up specific audio path interconnects */
-	snd_soc_dapm_add_route(codec, intercon, ARRAY_SIZE(intercon));
-
-	/* not connected */
-	snd_soc_dapm_disable_pin(codec, "RLINEIN");
-	snd_soc_dapm_disable_pin(codec, "LLINEIN");
-
-	/* always connected */
-	snd_soc_dapm_enable_pin(codec, "Int Mic");
-	snd_soc_dapm_enable_pin(codec, "Ext Spk");
-
-	snd_soc_dapm_sync(codec);
-
-	return 0;
-}
-
-static struct snd_soc_dai_link eti_b1_dai = {
-	.name = "WM8731",
-	.stream_name = "WM8731 PCM",
-	.cpu_dai = &at91_ssc_dai[1],
-	.codec_dai = &wm8731_dai,
-	.init = eti_b1_wm8731_init,
-	.ops = &eti_b1_ops,
-};
-
-static struct snd_soc_machine snd_soc_machine_eti_b1 = {
-	.name = "ETI_B1_WM8731",
-	.dai_link = &eti_b1_dai,
-	.num_links = 1,
-};
-
-static struct wm8731_setup_data eti_b1_wm8731_setup = {
-	.i2c_address = 0x1a,
-};
-
-static struct snd_soc_device eti_b1_snd_devdata = {
-	.machine = &snd_soc_machine_eti_b1,
-	.platform = &at91_soc_platform,
-	.codec_dev = &soc_codec_dev_wm8731,
-	.codec_data = &eti_b1_wm8731_setup,
-};
-
-static struct platform_device *eti_b1_snd_device;
-
-static int __init eti_b1_init(void)
-{
-	int ret;
-	struct at91_ssc_periph *ssc = eti_b1_dai.cpu_dai->private_data;
-
-	if (!request_mem_region(AT91RM9200_BASE_SSC1, SZ_16K, "soc-audio")) {
-		DBG("SSC1 memory region is busy\n");
-		return -EBUSY;
-	}
-
-	ssc->base = ioremap(AT91RM9200_BASE_SSC1, SZ_16K);
-	if (!ssc->base) {
-		DBG("SSC1 memory ioremap failed\n");
-		ret = -ENOMEM;
-		goto fail_release_mem;
-	}
-
-	ssc->pid = AT91RM9200_ID_SSC1;
-
-	eti_b1_snd_device = platform_device_alloc("soc-audio", -1);
-	if (!eti_b1_snd_device) {
-		DBG("platform device allocation failed\n");
-		ret = -ENOMEM;
-		goto fail_io_unmap;
-	}
-
-	platform_set_drvdata(eti_b1_snd_device, &eti_b1_snd_devdata);
-	eti_b1_snd_devdata.dev = &eti_b1_snd_device->dev;
-
-	ret = platform_device_add(eti_b1_snd_device);
-	if (ret) {
-		DBG("platform device add failed\n");
-		platform_device_put(eti_b1_snd_device);
-		goto fail_io_unmap;
-	}
-
-	at91_set_A_periph(AT91_PIN_PB6, 0);	/* TF1 */
-	at91_set_A_periph(AT91_PIN_PB7, 0);	/* TK1 */
-	at91_set_A_periph(AT91_PIN_PB8, 0);	/* TD1 */
-	at91_set_A_periph(AT91_PIN_PB9, 0);	/* RD1 */
-/*	at91_set_A_periph(AT91_PIN_PB10, 0);*/	/* RK1 */
-	at91_set_A_periph(AT91_PIN_PB11, 0);	/* RF1 */
-
-	/*
-	 * Set PCK1 parent to PLLB and its rate to 12 Mhz.
-	 */
-	pllb_clk = clk_get(NULL, "pllb");
-	pck1_clk = clk_get(NULL, "pck1");
-
-	clk_set_parent(pck1_clk, pllb_clk);
-	clk_set_rate(pck1_clk, 12000000);
-
-	DBG("MCLK rate %luHz\n", clk_get_rate(pck1_clk));
-
-	/* assign the GPIO pin to PCK1 */
-	at91_set_B_periph(AT91_PIN_PA24, 0);
-
-#ifdef CONFIG_SND_AT91_SOC_ETI_SLAVE
-	printk(KERN_INFO "eti_b1_wm8731: Codec in Slave Mode\n");
-#else
-	printk(KERN_INFO "eti_b1_wm8731: Codec in Master Mode\n");
-#endif
-	return ret;
-
-fail_io_unmap:
-	iounmap(ssc->base);
-fail_release_mem:
-	release_mem_region(AT91RM9200_BASE_SSC1, SZ_16K);
-	return ret;
-}
-
-static void __exit eti_b1_exit(void)
-{
-	struct at91_ssc_periph *ssc = eti_b1_dai.cpu_dai->private_data;
-
-	clk_put(pck1_clk);
-	clk_put(pllb_clk);
-
-	platform_device_unregister(eti_b1_snd_device);
-
-	iounmap(ssc->base);
-	release_mem_region(AT91RM9200_BASE_SSC1, SZ_16K);
-}
-
-module_init(eti_b1_init);
-module_exit(eti_b1_exit);
-
-/* Module information */
-MODULE_AUTHOR("Frank Mandarino <fmandarino@endrelia.com>");
-MODULE_DESCRIPTION("ALSA SoC ETI-B1-WM8731");
-MODULE_LICENSE("GPL");
diff --git a/sound/soc/blackfin/Kconfig b/sound/soc/blackfin/Kconfig
new file mode 100644
index 0000000..dc00620
--- /dev/null
+++ b/sound/soc/blackfin/Kconfig
@@ -0,0 +1,101 @@
+config SND_BF5XX_I2S
+	tristate "SoC I2S Audio for the ADI BF5xx chip"
+	depends on BLACKFIN && SND_SOC
+	help
+	  Say Y or M if you want to add support for codecs attached to
+	  the Blackfin SPORT (synchronous serial ports) interface in I2S
+	  mode (supports single stereo In/Out).
+	  You will also need to select the audio interfaces to support below.
+
+config SND_BF5XX_SOC_SSM2602
+	tristate "SoC SSM2602 Audio support for BF52x ezkit"
+	depends on SND_BF5XX_I2S
+	select SND_BF5XX_SOC_I2S
+	select SND_SOC_SSM2602
+	select I2C
+	select I2C_BLACKFIN_TWI
+	help
+	  Say Y if you want to add support for SoC audio on BF527-EZKIT.
+
+config SND_BF5XX_SOC_AD73311
+	tristate "SoC AD73311 Audio support for Blackfin"
+	depends on SND_BF5XX_I2S
+	select SND_BF5XX_SOC_I2S
+	select SND_SOC_AD73311
+	help
+	  Say Y if you want to add support for AD73311 codec on Blackfin.
+
+config SND_BFIN_AD73311_SE
+	int "PF pin for AD73311L Chip Select"
+	depends on SND_BF5XX_SOC_AD73311
+	default 4
+	help
+	  Enter the GPIO used to control AD73311's SE pin. Acceptable
+	  values are 0 to 7
+
+config SND_BF5XX_AC97
+	tristate "SoC AC97 Audio for the ADI BF5xx chip"
+	depends on BLACKFIN && SND_SOC
+	help
+	  Say Y or M if you want to add support for codecs attached to
+	  the Blackfin SPORT (synchronous serial ports) interface in slot 16
+	  mode (pseudo AC97 interface).
+	  You will also need to select the audio interfaces to support below.
+
+	  Note:
+	  AC97 codecs which do not implment the slot-16 mode will not function
+	  properly with this driver. This driver is known to work with the
+	  Analog Devices line of AC97 codecs.
+
+config SND_MMAP_SUPPORT
+	bool "Enable MMAP Support"
+	depends on SND_BF5XX_AC97
+	default y
+	help
+	  Say y if you want AC97 driver to support mmap mode.
+	  We introduce an intermediate buffer to simulate mmap.
+
+config SND_BF5XX_SOC_SPORT
+	tristate
+	
+config SND_BF5XX_SOC_I2S
+	tristate
+	select SND_BF5XX_SOC_SPORT
+
+config SND_BF5XX_SOC_AC97
+	tristate
+	select AC97_BUS
+	select SND_SOC_AC97_BUS
+	select SND_BF5XX_SOC_SPORT
+
+config SND_BF5XX_SOC_AD1980
+	tristate "SoC AD1980/1 Audio support for BF5xx"
+	depends on SND_BF5XX_AC97
+	select SND_BF5XX_SOC_AC97
+	select SND_SOC_AD1980
+	help
+	  Say Y if you want to add support for SoC audio on BF5xx STAMP/EZKIT.
+
+config SND_BF5XX_SPORT_NUM
+	int "Set a SPORT for Sound chip"
+	depends on (SND_BF5XX_I2S || SND_BF5XX_AC97)
+	range 0 3 if BF54x
+	range 0 1 if (BF53x || BF561)
+	default 0
+	help
+	  Set the correct SPORT for sound chip.
+
+config SND_BF5XX_HAVE_COLD_RESET
+	bool "BOARD has COLD Reset GPIO"
+	depends on SND_BF5XX_AC97
+	default y if BFIN548_EZKIT
+	default n if !BFIN548_EZKIT
+	
+config SND_BF5XX_RESET_GPIO_NUM
+	int "Set a GPIO for cold reset"
+	depends on SND_BF5XX_HAVE_COLD_RESET
+	range 0 159
+	default 19 if BFIN548_EZKIT
+	default 5 if BFIN537_STAMP
+	help
+	  Set the correct GPIO for RESET the sound chip.
diff --git a/sound/soc/blackfin/Makefile b/sound/soc/blackfin/Makefile
new file mode 100644
index 0000000..97bb37a
--- /dev/null
+++ b/sound/soc/blackfin/Makefile
@@ -0,0 +1,21 @@
+# Blackfin Platform Support
+snd-bf5xx-ac97-objs := bf5xx-ac97-pcm.o
+snd-bf5xx-i2s-objs := bf5xx-i2s-pcm.o
+snd-soc-bf5xx-sport-objs := bf5xx-sport.o
+snd-soc-bf5xx-ac97-objs := bf5xx-ac97.o
+snd-soc-bf5xx-i2s-objs := bf5xx-i2s.o
+
+obj-$(CONFIG_SND_BF5XX_AC97) += snd-bf5xx-ac97.o
+obj-$(CONFIG_SND_BF5XX_I2S) += snd-bf5xx-i2s.o
+obj-$(CONFIG_SND_BF5XX_SOC_SPORT) += snd-soc-bf5xx-sport.o
+obj-$(CONFIG_SND_BF5XX_SOC_AC97) += snd-soc-bf5xx-ac97.o
+obj-$(CONFIG_SND_BF5XX_SOC_I2S) += snd-soc-bf5xx-i2s.o
+
+# Blackfin Machine Support
+snd-ad1980-objs := bf5xx-ad1980.o
+snd-ssm2602-objs := bf5xx-ssm2602.o
+snd-ad73311-objs := bf5xx-ad73311.o
+
+obj-$(CONFIG_SND_BF5XX_SOC_AD1980) += snd-ad1980.o
+obj-$(CONFIG_SND_BF5XX_SOC_SSM2602) += snd-ssm2602.o
+obj-$(CONFIG_SND_BF5XX_SOC_AD73311) += snd-ad73311.o
diff --git a/sound/soc/blackfin/bf5xx-ac97-pcm.c b/sound/soc/blackfin/bf5xx-ac97-pcm.c
new file mode 100644
index 0000000..25e50d2
--- /dev/null
+++ b/sound/soc/blackfin/bf5xx-ac97-pcm.c
@@ -0,0 +1,457 @@
+/*
+ * File:         sound/soc/blackfin/bf5xx-ac97-pcm.c
+ * Author:       Cliff Cai <Cliff.Cai@analog.com>
+ *
+ * Created:      Tue June 06 2008
+ * Description:  DMA Driver for AC97 sound chip
+ *
+ * Modified:
+ *               Copyright 2008 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.org/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/dma-mapping.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include <asm/dma.h>
+
+#include "bf5xx-ac97-pcm.h"
+#include "bf5xx-ac97.h"
+#include "bf5xx-sport.h"
+
+#if defined(CONFIG_SND_MMAP_SUPPORT)
+static void bf5xx_mmap_copy(struct snd_pcm_substream *substream,
+	 snd_pcm_uframes_t count)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct sport_device *sport = runtime->private_data;
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		bf5xx_pcm_to_ac97(
+			(struct ac97_frame *)sport->tx_dma_buf + sport->tx_pos,
+			(__u32 *)runtime->dma_area + sport->tx_pos, count);
+		sport->tx_pos += runtime->period_size;
+		if (sport->tx_pos >= runtime->buffer_size)
+			sport->tx_pos %= runtime->buffer_size;
+		sport->tx_delay_pos = sport->tx_pos;
+	} else {
+		bf5xx_ac97_to_pcm(
+			(struct ac97_frame *)sport->rx_dma_buf + sport->rx_pos,
+			(__u32 *)runtime->dma_area + sport->rx_pos, count);
+		sport->rx_pos += runtime->period_size;
+		if (sport->rx_pos >= runtime->buffer_size)
+			sport->rx_pos %= runtime->buffer_size;
+	}
+}
+#endif
+
+static void bf5xx_dma_irq(void *data)
+{
+	struct snd_pcm_substream *pcm = data;
+#if defined(CONFIG_SND_MMAP_SUPPORT)
+	struct snd_pcm_runtime *runtime = pcm->runtime;
+	struct sport_device *sport = runtime->private_data;
+	bf5xx_mmap_copy(pcm, runtime->period_size);
+	if (pcm->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		if (sport->once == 0) {
+			snd_pcm_period_elapsed(pcm);
+			bf5xx_mmap_copy(pcm, runtime->period_size);
+			sport->once = 1;
+		}
+	}
+#endif
+	snd_pcm_period_elapsed(pcm);
+}
+
+/* The memory size for pure pcm data is 128*1024 = 0x20000 bytes.
+ * The total rx/tx buffer is for ac97 frame to hold all pcm data
+ * is  0x20000 * sizeof(struct ac97_frame) / 4.
+ */
+#ifdef CONFIG_SND_MMAP_SUPPORT
+static const struct snd_pcm_hardware bf5xx_pcm_hardware = {
+	.info			= SNDRV_PCM_INFO_INTERLEAVED |
+				   SNDRV_PCM_INFO_MMAP |
+				   SNDRV_PCM_INFO_MMAP_VALID |
+				   SNDRV_PCM_INFO_BLOCK_TRANSFER,
+#else
+static const struct snd_pcm_hardware bf5xx_pcm_hardware = {
+	.info			= SNDRV_PCM_INFO_INTERLEAVED |
+				  SNDRV_PCM_INFO_BLOCK_TRANSFER,
+#endif
+	.formats		= SNDRV_PCM_FMTBIT_S16_LE,
+	.period_bytes_min	= 32,
+	.period_bytes_max	= 0x10000,
+	.periods_min		= 1,
+	.periods_max		= PAGE_SIZE/32,
+	.buffer_bytes_max	= 0x20000, /* 128 kbytes */
+	.fifo_size		= 16,
+};
+
+static int bf5xx_pcm_hw_params(struct snd_pcm_substream *substream,
+	struct snd_pcm_hw_params *params)
+{
+	size_t size = bf5xx_pcm_hardware.buffer_bytes_max
+			* sizeof(struct ac97_frame) / 4;
+
+	snd_pcm_lib_malloc_pages(substream, size);
+
+	return 0;
+}
+
+static int bf5xx_pcm_hw_free(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+	memset(runtime->dma_area, 0, runtime->buffer_size);
+	snd_pcm_lib_free_pages(substream);
+	return 0;
+}
+
+static int bf5xx_pcm_prepare(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct sport_device *sport = runtime->private_data;
+
+	/* An intermediate buffer is introduced for implementing mmap for
+	 * SPORT working in TMD mode(include AC97).
+	 */
+#if defined(CONFIG_SND_MMAP_SUPPORT)
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		sport_set_tx_callback(sport, bf5xx_dma_irq, substream);
+		sport_config_tx_dma(sport, sport->tx_dma_buf, runtime->periods,
+			runtime->period_size * sizeof(struct ac97_frame));
+	} else {
+		sport_set_rx_callback(sport, bf5xx_dma_irq, substream);
+		sport_config_rx_dma(sport, sport->rx_dma_buf, runtime->periods,
+			runtime->period_size * sizeof(struct ac97_frame));
+	}
+#else
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		sport_set_tx_callback(sport, bf5xx_dma_irq, substream);
+		sport_config_tx_dma(sport, runtime->dma_area, runtime->periods,
+			runtime->period_size * sizeof(struct ac97_frame));
+	} else {
+		sport_set_rx_callback(sport, bf5xx_dma_irq, substream);
+		sport_config_rx_dma(sport, runtime->dma_area, runtime->periods,
+			runtime->period_size * sizeof(struct ac97_frame));
+	}
+#endif
+	return 0;
+}
+
+static int bf5xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct sport_device *sport = runtime->private_data;
+	int ret = 0;
+
+	pr_debug("%s enter\n", __func__);
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+			bf5xx_mmap_copy(substream, runtime->period_size);
+			snd_pcm_period_elapsed(substream);
+			sport->tx_delay_pos = 0;
+			sport_tx_start(sport);
+		}
+		else
+			sport_rx_start(sport);
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+#if defined(CONFIG_SND_MMAP_SUPPORT)
+			sport->tx_pos = 0;
+#endif
+			sport_tx_stop(sport);
+		} else {
+#if defined(CONFIG_SND_MMAP_SUPPORT)
+			sport->rx_pos = 0;
+#endif
+			sport_rx_stop(sport);
+		}
+		break;
+	default:
+		ret = -EINVAL;
+	}
+	return ret;
+}
+
+static snd_pcm_uframes_t bf5xx_pcm_pointer(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct sport_device *sport = runtime->private_data;
+	unsigned int curr;
+
+#if defined(CONFIG_SND_MMAP_SUPPORT)
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		curr = sport->tx_delay_pos;
+	else
+		curr = sport->rx_pos;
+#else
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		curr = sport_curr_offset_tx(sport) / sizeof(struct ac97_frame);
+	else
+		curr = sport_curr_offset_rx(sport) / sizeof(struct ac97_frame);
+
+#endif
+	return curr;
+}
+
+static int bf5xx_pcm_open(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	int ret;
+
+	pr_debug("%s enter\n", __func__);
+	snd_soc_set_runtime_hwparams(substream, &bf5xx_pcm_hardware);
+
+	ret = snd_pcm_hw_constraint_integer(runtime,
+					    SNDRV_PCM_HW_PARAM_PERIODS);
+	if (ret < 0)
+		goto out;
+
+	if (sport_handle != NULL)
+		runtime->private_data = sport_handle;
+	else {
+		pr_err("sport_handle is NULL\n");
+		return -1;
+	}
+	return 0;
+
+ out:
+	return ret;
+}
+
+static int bf5xx_pcm_close(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct sport_device *sport = runtime->private_data;
+
+	pr_debug("%s enter\n", __func__);
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		sport->once = 0;
+		memset(sport->tx_dma_buf, 0, runtime->buffer_size * sizeof(struct ac97_frame));
+	} else
+		memset(sport->rx_dma_buf, 0, runtime->buffer_size * sizeof(struct ac97_frame));
+
+	return 0;
+}
+
+#ifdef CONFIG_SND_MMAP_SUPPORT
+static int bf5xx_pcm_mmap(struct snd_pcm_substream *substream,
+	struct vm_area_struct *vma)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	size_t size = vma->vm_end - vma->vm_start;
+	vma->vm_start = (unsigned long)runtime->dma_area;
+	vma->vm_end = vma->vm_start + size;
+	vma->vm_flags |=  VM_SHARED;
+	return 0 ;
+}
+#else
+static	int bf5xx_pcm_copy(struct snd_pcm_substream *substream, int channel,
+		    snd_pcm_uframes_t pos,
+		    void __user *buf, snd_pcm_uframes_t count)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+
+	pr_debug("%s copy pos:0x%lx count:0x%lx\n",
+			substream->stream ? "Capture" : "Playback", pos, count);
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		bf5xx_pcm_to_ac97(
+				(struct ac97_frame *)runtime->dma_area + pos,
+				buf, count);
+	else
+		bf5xx_ac97_to_pcm(
+				(struct ac97_frame *)runtime->dma_area + pos,
+				buf, count);
+	return 0;
+}
+#endif
+
+struct snd_pcm_ops bf5xx_pcm_ac97_ops = {
+	.open		= bf5xx_pcm_open,
+	.close		= bf5xx_pcm_close,
+	.ioctl		= snd_pcm_lib_ioctl,
+	.hw_params	= bf5xx_pcm_hw_params,
+	.hw_free	= bf5xx_pcm_hw_free,
+	.prepare	= bf5xx_pcm_prepare,
+	.trigger	= bf5xx_pcm_trigger,
+	.pointer	= bf5xx_pcm_pointer,
+#ifdef CONFIG_SND_MMAP_SUPPORT
+	.mmap		= bf5xx_pcm_mmap,
+#else
+	.copy		= bf5xx_pcm_copy,
+#endif
+};
+
+static int bf5xx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
+{
+	struct snd_pcm_substream *substream = pcm->streams[stream].substream;
+	struct snd_dma_buffer *buf = &substream->dma_buffer;
+	size_t size = bf5xx_pcm_hardware.buffer_bytes_max
+			* sizeof(struct ac97_frame) / 4;
+
+	buf->dev.type = SNDRV_DMA_TYPE_DEV;
+	buf->dev.dev = pcm->card->dev;
+	buf->private_data = NULL;
+	buf->area = dma_alloc_coherent(pcm->card->dev, size,
+			&buf->addr, GFP_KERNEL);
+	if (!buf->area) {
+		pr_err("Failed to allocate dma memory\n");
+		pr_err("Please increase uncached DMA memory region\n");
+		return -ENOMEM;
+	}
+	buf->bytes = size;
+
+	pr_debug("%s, area:%p, size:0x%08lx\n", __func__,
+			buf->area, buf->bytes);
+
+	if (stream == SNDRV_PCM_STREAM_PLAYBACK)
+		sport_handle->tx_buf = buf->area;
+	else
+		sport_handle->rx_buf = buf->area;
+
+/*
+ * Need to allocate local buffer when enable
+ * MMAP for SPORT working in TMD mode (include AC97).
+ */
+#if defined(CONFIG_SND_MMAP_SUPPORT)
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		if (!sport_handle->tx_dma_buf) {
+			sport_handle->tx_dma_buf = dma_alloc_coherent(NULL, \
+				size, &sport_handle->tx_dma_phy, GFP_KERNEL);
+			if (!sport_handle->tx_dma_buf) {
+				pr_err("Failed to allocate memory for tx dma \
+					buf - Please increase uncached DMA \
+					memory region\n");
+				return -ENOMEM;
+			} else
+				memset(sport_handle->tx_dma_buf, 0, size);
+		} else
+			memset(sport_handle->tx_dma_buf, 0, size);
+	} else {
+		if (!sport_handle->rx_dma_buf) {
+			sport_handle->rx_dma_buf = dma_alloc_coherent(NULL, \
+				size, &sport_handle->rx_dma_phy, GFP_KERNEL);
+			if (!sport_handle->rx_dma_buf) {
+				pr_err("Failed to allocate memory for rx dma \
+					buf - Please increase uncached DMA \
+					memory region\n");
+				return -ENOMEM;
+			} else
+				memset(sport_handle->rx_dma_buf, 0, size);
+		} else
+			memset(sport_handle->rx_dma_buf, 0, size);
+	}
+#endif
+	return 0;
+}
+
+static void bf5xx_pcm_free_dma_buffers(struct snd_pcm *pcm)
+{
+	struct snd_pcm_substream *substream;
+	struct snd_dma_buffer *buf;
+	int stream;
+#if defined(CONFIG_SND_MMAP_SUPPORT)
+	size_t size = bf5xx_pcm_hardware.buffer_bytes_max *
+		sizeof(struct ac97_frame) / 4;
+#endif
+	for (stream = 0; stream < 2; stream++) {
+		substream = pcm->streams[stream].substream;
+		if (!substream)
+			continue;
+
+		buf = &substream->dma_buffer;
+		if (!buf->area)
+			continue;
+		dma_free_coherent(NULL, buf->bytes, buf->area, 0);
+		buf->area = NULL;
+#if defined(CONFIG_SND_MMAP_SUPPORT)
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		if (sport_handle->tx_dma_buf)
+			dma_free_coherent(NULL, size, \
+				sport_handle->tx_dma_buf, 0);
+		sport_handle->tx_dma_buf = NULL;
+	} else {
+
+		if (sport_handle->rx_dma_buf)
+			dma_free_coherent(NULL, size, \
+				sport_handle->rx_dma_buf, 0);
+		sport_handle->rx_dma_buf = NULL;
+	}
+#endif
+	}
+	if (sport_handle)
+		sport_done(sport_handle);
+}
+
+static u64 bf5xx_pcm_dmamask = DMA_32BIT_MASK;
+
+int bf5xx_pcm_ac97_new(struct snd_card *card, struct snd_soc_dai *dai,
+	struct snd_pcm *pcm)
+{
+	int ret = 0;
+
+	pr_debug("%s enter\n", __func__);
+	if (!card->dev->dma_mask)
+		card->dev->dma_mask = &bf5xx_pcm_dmamask;
+	if (!card->dev->coherent_dma_mask)
+		card->dev->coherent_dma_mask = DMA_32BIT_MASK;
+
+	if (dai->playback.channels_min) {
+		ret = bf5xx_pcm_preallocate_dma_buffer(pcm,
+			SNDRV_PCM_STREAM_PLAYBACK);
+		if (ret)
+			goto out;
+	}
+
+	if (dai->capture.channels_min) {
+		ret = bf5xx_pcm_preallocate_dma_buffer(pcm,
+			SNDRV_PCM_STREAM_CAPTURE);
+		if (ret)
+			goto out;
+	}
+ out:
+	return ret;
+}
+
+struct snd_soc_platform bf5xx_ac97_soc_platform = {
+	.name		= "bf5xx-audio",
+	.pcm_ops 	= &bf5xx_pcm_ac97_ops,
+	.pcm_new	= bf5xx_pcm_ac97_new,
+	.pcm_free	= bf5xx_pcm_free_dma_buffers,
+};
+EXPORT_SYMBOL_GPL(bf5xx_ac97_soc_platform);
+
+MODULE_AUTHOR("Cliff Cai");
+MODULE_DESCRIPTION("ADI Blackfin AC97 PCM DMA module");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/blackfin/bf5xx-ac97-pcm.h b/sound/soc/blackfin/bf5xx-ac97-pcm.h
new file mode 100644
index 0000000..350125a
--- /dev/null
+++ b/sound/soc/blackfin/bf5xx-ac97-pcm.h
@@ -0,0 +1,29 @@
+/*
+ * linux/sound/arm/bf5xx-ac97-pcm.h -- ALSA PCM interface for the Blackfin
+ *
+ * Copyright 2007 Analog Device Inc.
+ *
+ * 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 _BF5XX_AC97_PCM_H
+#define _BF5XX_AC97_PCM_H
+
+struct bf5xx_pcm_dma_params {
+	char *name;			/* stream identifier */
+};
+
+struct bf5xx_gpio {
+	u32 sys;
+	u32 rx;
+	u32 tx;
+	u32 clk;
+	u32 frm;
+};
+
+/* platform data */
+extern struct snd_soc_platform bf5xx_ac97_soc_platform;
+
+#endif
diff --git a/sound/soc/blackfin/bf5xx-ac97.c b/sound/soc/blackfin/bf5xx-ac97.c
new file mode 100644
index 0000000..5e5aafb
--- /dev/null
+++ b/sound/soc/blackfin/bf5xx-ac97.c
@@ -0,0 +1,406 @@
+/*
+ * bf5xx-ac97.c -- AC97 support for the ADI blackfin chip.
+ *
+ * Author:	Roy Huang
+ * Created:	11th. June 2007
+ * Copyright:	Analog Device Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/wait.h>
+#include <linux/delay.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/ac97_codec.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+
+#include <asm/irq.h>
+#include <asm/portmux.h>
+#include <linux/mutex.h>
+#include <linux/gpio.h>
+
+#include "bf5xx-sport.h"
+#include "bf5xx-ac97.h"
+
+#if defined(CONFIG_BF54x)
+#define PIN_REQ_SPORT_0 {P_SPORT0_TFS, P_SPORT0_DTPRI, P_SPORT0_TSCLK, \
+		P_SPORT0_RFS, P_SPORT0_DRPRI, P_SPORT0_RSCLK, 0}
+
+#define PIN_REQ_SPORT_1 {P_SPORT1_TFS, P_SPORT1_DTPRI, P_SPORT1_TSCLK, \
+		P_SPORT1_RFS, P_SPORT1_DRPRI, P_SPORT1_RSCLK, 0}
+
+#define PIN_REQ_SPORT_2 {P_SPORT2_TFS, P_SPORT2_DTPRI, P_SPORT2_TSCLK, \
+		P_SPORT2_RFS, P_SPORT2_DRPRI, P_SPORT2_RSCLK, 0}
+
+#define PIN_REQ_SPORT_3 {P_SPORT3_TFS, P_SPORT3_DTPRI, P_SPORT3_TSCLK, \
+		P_SPORT3_RFS, P_SPORT3_DRPRI, P_SPORT3_RSCLK, 0}
+#else
+#define PIN_REQ_SPORT_0 {P_SPORT0_DTPRI, P_SPORT0_TSCLK, P_SPORT0_RFS, \
+		 P_SPORT0_DRPRI, P_SPORT0_RSCLK, 0}
+
+#define PIN_REQ_SPORT_1 {P_SPORT1_DTPRI, P_SPORT1_TSCLK, P_SPORT1_RFS, \
+		 P_SPORT1_DRPRI, P_SPORT1_RSCLK, 0}
+#endif
+
+static int *cmd_count;
+static int sport_num = CONFIG_SND_BF5XX_SPORT_NUM;
+
+#if defined(CONFIG_BF54x)
+static struct sport_param sport_params[4] = {
+	{
+		.dma_rx_chan	= CH_SPORT0_RX,
+		.dma_tx_chan	= CH_SPORT0_TX,
+		.err_irq	= IRQ_SPORT0_ERR,
+		.regs		= (struct sport_register *)SPORT0_TCR1,
+	},
+	{
+		.dma_rx_chan	= CH_SPORT1_RX,
+		.dma_tx_chan	= CH_SPORT1_TX,
+		.err_irq	= IRQ_SPORT1_ERR,
+		.regs		= (struct sport_register *)SPORT1_TCR1,
+	},
+	{
+		.dma_rx_chan	= CH_SPORT2_RX,
+		.dma_tx_chan	= CH_SPORT2_TX,
+		.err_irq	= IRQ_SPORT2_ERR,
+		.regs		= (struct sport_register *)SPORT2_TCR1,
+	},
+	{
+		.dma_rx_chan	= CH_SPORT3_RX,
+		.dma_tx_chan	= CH_SPORT3_TX,
+		.err_irq	= IRQ_SPORT3_ERR,
+		.regs		= (struct sport_register *)SPORT3_TCR1,
+	}
+};
+#else
+static struct sport_param sport_params[2] = {
+	{
+		.dma_rx_chan	= CH_SPORT0_RX,
+		.dma_tx_chan	= CH_SPORT0_TX,
+		.err_irq	= IRQ_SPORT0_ERROR,
+		.regs		= (struct sport_register *)SPORT0_TCR1,
+	},
+	{
+		.dma_rx_chan	= CH_SPORT1_RX,
+		.dma_tx_chan	= CH_SPORT1_TX,
+		.err_irq	= IRQ_SPORT1_ERROR,
+		.regs		= (struct sport_register *)SPORT1_TCR1,
+	}
+};
+#endif
+
+void bf5xx_pcm_to_ac97(struct ac97_frame *dst, const __u32 *src, \
+		size_t count)
+{
+	while (count--) {
+		dst->ac97_tag = TAG_VALID | TAG_PCM;
+		(dst++)->ac97_pcm = *src++;
+	}
+}
+EXPORT_SYMBOL(bf5xx_pcm_to_ac97);
+
+void bf5xx_ac97_to_pcm(const struct ac97_frame *src, __u32 *dst, \
+		size_t count)
+{
+	while (count--)
+		*(dst++) = (src++)->ac97_pcm;
+}
+EXPORT_SYMBOL(bf5xx_ac97_to_pcm);
+
+static unsigned int sport_tx_curr_frag(struct sport_device *sport)
+{
+	return sport->tx_curr_frag = sport_curr_offset_tx(sport) / \
+			sport->tx_fragsize;
+}
+
+static void enqueue_cmd(struct snd_ac97 *ac97, __u16 addr, __u16 data)
+{
+	struct sport_device *sport = sport_handle;
+	int nextfrag = sport_tx_curr_frag(sport);
+	struct ac97_frame *nextwrite;
+
+	sport_incfrag(sport, &nextfrag, 1);
+
+	nextwrite = (struct ac97_frame *)(sport->tx_buf + \
+			nextfrag * sport->tx_fragsize);
+	pr_debug("sport->tx_buf:%p, nextfrag:0x%x nextwrite:%p, cmd_count:%d\n",
+		sport->tx_buf, nextfrag, nextwrite, cmd_count[nextfrag]);
+	nextwrite[cmd_count[nextfrag]].ac97_tag |= TAG_CMD;
+	nextwrite[cmd_count[nextfrag]].ac97_addr = addr;
+	nextwrite[cmd_count[nextfrag]].ac97_data = data;
+	++cmd_count[nextfrag];
+	pr_debug("ac97_sport: Inserting %02x/%04x into fragment %d\n",
+			addr >> 8, data, nextfrag);
+}
+
+static unsigned short bf5xx_ac97_read(struct snd_ac97 *ac97,
+	unsigned short reg)
+{
+	struct ac97_frame out_frame[2], in_frame[2];
+
+	pr_debug("%s enter 0x%x\n", __func__, reg);
+
+	/* When dma descriptor is enabled, the register should not be read */
+	if (sport_handle->tx_run || sport_handle->rx_run) {
+		pr_err("Could you send a mail to cliff.cai@analog.com "
+				"to report this?\n");
+		return -EFAULT;
+	}
+
+	memset(&out_frame, 0, 2 * sizeof(struct ac97_frame));
+	memset(&in_frame, 0, 2 * sizeof(struct ac97_frame));
+	out_frame[0].ac97_tag = TAG_VALID | TAG_CMD;
+	out_frame[0].ac97_addr = ((reg << 8) | 0x8000);
+	sport_send_and_recv(sport_handle, (unsigned char *)&out_frame,
+			(unsigned char *)&in_frame,
+			2 * sizeof(struct ac97_frame));
+	return in_frame[1].ac97_data;
+}
+
+void bf5xx_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
+	unsigned short val)
+{
+	pr_debug("%s enter 0x%x:0x%04x\n", __func__, reg, val);
+
+	if (sport_handle->tx_run) {
+		enqueue_cmd(ac97, (reg << 8), val); /* write */
+		enqueue_cmd(ac97, (reg << 8) | 0x8000, 0); /* read back */
+	} else {
+		struct ac97_frame frame;
+		memset(&frame, 0, sizeof(struct ac97_frame));
+		frame.ac97_tag = TAG_VALID | TAG_CMD;
+		frame.ac97_addr = (reg << 8);
+		frame.ac97_data = val;
+		sport_send_and_recv(sport_handle, (unsigned char *)&frame, \
+				NULL, sizeof(struct ac97_frame));
+	}
+}
+
+static void bf5xx_ac97_warm_reset(struct snd_ac97 *ac97)
+{
+#if defined(CONFIG_BF54x) || defined(CONFIG_BF561) || \
+ (defined(BF537_FAMILY) && (CONFIG_SND_BF5XX_SPORT_NUM == 1))
+
+#define CONCAT(a, b, c) a ## b ## c
+#define BFIN_SPORT_RFS(x) CONCAT(P_SPORT, x, _RFS)
+
+	u16 per = BFIN_SPORT_RFS(CONFIG_SND_BF5XX_SPORT_NUM);
+	u16 gpio = P_IDENT(BFIN_SPORT_RFS(CONFIG_SND_BF5XX_SPORT_NUM));
+
+	pr_debug("%s enter\n", __func__);
+
+	peripheral_free(per);
+	gpio_request(gpio, "bf5xx-ac97");
+	gpio_direction_output(gpio, 1);
+	udelay(2);
+	gpio_set_value(gpio, 0);
+	udelay(1);
+	gpio_free(gpio);
+	peripheral_request(per, "soc-audio");
+#else
+	pr_info("%s: Not implemented\n", __func__);
+#endif
+}
+
+static void bf5xx_ac97_cold_reset(struct snd_ac97 *ac97)
+{
+#ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET
+	pr_debug("%s enter\n", __func__);
+
+	/* It is specified for bf548-ezkit */
+	gpio_set_value(CONFIG_SND_BF5XX_RESET_GPIO_NUM, 0);
+	/* Keep reset pin low for 1 ms */
+	mdelay(1);
+	gpio_set_value(CONFIG_SND_BF5XX_RESET_GPIO_NUM, 1);
+	/* Wait for bit clock recover */
+	mdelay(1);
+#else
+	pr_info("%s: Not implemented\n", __func__);
+#endif
+}
+
+struct snd_ac97_bus_ops soc_ac97_ops = {
+	.read	= bf5xx_ac97_read,
+	.write	= bf5xx_ac97_write,
+	.warm_reset	= bf5xx_ac97_warm_reset,
+	.reset	= bf5xx_ac97_cold_reset,
+};
+EXPORT_SYMBOL_GPL(soc_ac97_ops);
+
+#ifdef CONFIG_PM
+static int bf5xx_ac97_suspend(struct platform_device *pdev,
+	struct snd_soc_dai *dai)
+{
+	struct sport_device *sport =
+		(struct sport_device *)dai->private_data;
+
+	pr_debug("%s : sport %d\n", __func__, dai->id);
+	if (!dai->active)
+		return 0;
+	if (dai->capture.active)
+		sport_rx_stop(sport);
+	if (dai->playback.active)
+		sport_tx_stop(sport);
+	return 0;
+}
+
+static int bf5xx_ac97_resume(struct platform_device *pdev,
+	struct snd_soc_dai *dai)
+{
+	int ret;
+	struct sport_device *sport =
+		(struct sport_device *)dai->private_data;
+
+	pr_debug("%s : sport %d\n", __func__, dai->id);
+	if (!dai->active)
+		return 0;
+
+	ret = sport_set_multichannel(sport_handle, 16, 0x1F, 1);
+	if (ret) {
+		pr_err("SPORT is busy!\n");
+		return -EBUSY;
+	}
+
+	ret = sport_config_rx(sport_handle, IRFS, 0xF, 0, (16*16-1));
+	if (ret) {
+		pr_err("SPORT is busy!\n");
+		return -EBUSY;
+	}
+
+	ret = sport_config_tx(sport_handle, ITFS, 0xF, 0, (16*16-1));
+	if (ret) {
+		pr_err("SPORT is busy!\n");
+		return -EBUSY;
+	}
+
+	if (dai->capture.active)
+		sport_rx_start(sport);
+	if (dai->playback.active)
+		sport_tx_start(sport);
+	return 0;
+}
+
+#else
+#define bf5xx_ac97_suspend	NULL
+#define bf5xx_ac97_resume	NULL
+#endif
+
+static int bf5xx_ac97_probe(struct platform_device *pdev,
+			    struct snd_soc_dai *dai)
+{
+	int ret;
+#if defined(CONFIG_BF54x)
+	u16 sport_req[][7] = {PIN_REQ_SPORT_0, PIN_REQ_SPORT_1,
+				 PIN_REQ_SPORT_2, PIN_REQ_SPORT_3};
+#else
+	u16 sport_req[][7] = {PIN_REQ_SPORT_0, PIN_REQ_SPORT_1};
+#endif
+	cmd_count = (int *)get_zeroed_page(GFP_KERNEL);
+	if (cmd_count == NULL)
+		return -ENOMEM;
+
+	if (peripheral_request_list(&sport_req[sport_num][0], "soc-audio")) {
+		pr_err("Requesting Peripherals failed\n");
+		return -EFAULT;
+		}
+
+#ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET
+	/* Request PB3 as reset pin */
+	if (gpio_request(CONFIG_SND_BF5XX_RESET_GPIO_NUM, "SND_AD198x RESET")) {
+		pr_err("Failed to request GPIO_%d for reset\n",
+				CONFIG_SND_BF5XX_RESET_GPIO_NUM);
+		peripheral_free_list(&sport_req[sport_num][0]);
+		return -1;
+	}
+	gpio_direction_output(CONFIG_SND_BF5XX_RESET_GPIO_NUM, 1);
+#endif
+	sport_handle = sport_init(&sport_params[sport_num], 2, \
+			sizeof(struct ac97_frame), NULL);
+	if (!sport_handle) {
+		peripheral_free_list(&sport_req[sport_num][0]);
+#ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET
+		gpio_free(CONFIG_SND_BF5XX_RESET_GPIO_NUM);
+#endif
+		return -ENODEV;
+	}
+	/*SPORT works in TDM mode to simulate AC97 transfers*/
+	ret = sport_set_multichannel(sport_handle, 16, 0x1F, 1);
+	if (ret) {
+		pr_err("SPORT is busy!\n");
+		kfree(sport_handle);
+		peripheral_free_list(&sport_req[sport_num][0]);
+#ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET
+		gpio_free(CONFIG_SND_BF5XX_RESET_GPIO_NUM);
+#endif
+		return -EBUSY;
+	}
+
+	ret = sport_config_rx(sport_handle, IRFS, 0xF, 0, (16*16-1));
+	if (ret) {
+		pr_err("SPORT is busy!\n");
+		kfree(sport_handle);
+		peripheral_free_list(&sport_req[sport_num][0]);
+#ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET
+		gpio_free(CONFIG_SND_BF5XX_RESET_GPIO_NUM);
+#endif
+		return -EBUSY;
+	}
+
+	ret = sport_config_tx(sport_handle, ITFS, 0xF, 0, (16*16-1));
+	if (ret) {
+		pr_err("SPORT is busy!\n");
+		kfree(sport_handle);
+		peripheral_free_list(&sport_req[sport_num][0]);
+#ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET
+		gpio_free(CONFIG_SND_BF5XX_RESET_GPIO_NUM);
+#endif
+		return -EBUSY;
+	}
+	return 0;
+}
+
+static void bf5xx_ac97_remove(struct platform_device *pdev,
+			      struct snd_soc_dai *dai)
+{
+	free_page((unsigned long)cmd_count);
+	cmd_count = NULL;
+#ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET
+	gpio_free(CONFIG_SND_BF5XX_RESET_GPIO_NUM);
+#endif
+}
+
+struct snd_soc_dai bfin_ac97_dai = {
+	.name = "bf5xx-ac97",
+	.id = 0,
+	.type = SND_SOC_DAI_AC97,
+	.probe = bf5xx_ac97_probe,
+	.remove = bf5xx_ac97_remove,
+	.suspend = bf5xx_ac97_suspend,
+	.resume = bf5xx_ac97_resume,
+	.playback = {
+		.stream_name = "AC97 Playback",
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = SNDRV_PCM_RATE_48000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE, },
+	.capture = {
+		.stream_name = "AC97 Capture",
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = SNDRV_PCM_RATE_48000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE, },
+};
+EXPORT_SYMBOL_GPL(bfin_ac97_dai);
+
+MODULE_AUTHOR("Roy Huang");
+MODULE_DESCRIPTION("AC97 driver for ADI Blackfin");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/blackfin/bf5xx-ac97.h b/sound/soc/blackfin/bf5xx-ac97.h
new file mode 100644
index 0000000..3f77cc5
--- /dev/null
+++ b/sound/soc/blackfin/bf5xx-ac97.h
@@ -0,0 +1,36 @@
+/*
+ * linux/sound/arm/bf5xx-ac97.h
+ *
+ * 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 _BF5XX_AC97_H
+#define _BF5XX_AC97_H
+
+extern struct snd_ac97_bus_ops bf5xx_ac97_ops;
+extern struct snd_ac97 *ac97;
+/* Frame format in memory, only support stereo currently */
+struct ac97_frame {
+	u16 ac97_tag;		/* slot 0 */
+	u16 ac97_addr;		/* slot 1 */
+	u16 ac97_data;		/* slot 2 */
+	u32 ac97_pcm;		/* slot 3 and 4: left and right pcm data */
+} __attribute__ ((packed));
+
+#define TAG_VALID		0x8000
+#define TAG_CMD			0x6000
+#define TAG_PCM_LEFT		0x1000
+#define TAG_PCM_RIGHT		0x0800
+#define TAG_PCM			(TAG_PCM_LEFT | TAG_PCM_RIGHT)
+
+extern struct snd_soc_dai bfin_ac97_dai;
+
+void bf5xx_pcm_to_ac97(struct ac97_frame *dst, const __u32 *src, \
+		size_t count);
+
+void bf5xx_ac97_to_pcm(const struct ac97_frame *src, __u32 *dst, \
+		size_t count);
+
+#endif
diff --git a/sound/soc/blackfin/bf5xx-ad1980.c b/sound/soc/blackfin/bf5xx-ad1980.c
new file mode 100644
index 0000000..124425d
--- /dev/null
+++ b/sound/soc/blackfin/bf5xx-ad1980.c
@@ -0,0 +1,113 @@
+/*
+ * File:         sound/soc/blackfin/bf5xx-ad1980.c
+ * Author:       Cliff Cai <Cliff.Cai@analog.com>
+ *
+ * Created:      Tue June 06 2008
+ * Description:  Board driver for AD1980/1 audio codec
+ *
+ * Modified:
+ *               Copyright 2008 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.org/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/device.h>
+#include <asm/dma.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+
+#include <linux/gpio.h>
+#include <asm/portmux.h>
+
+#include "../codecs/ad1980.h"
+#include "bf5xx-sport.h"
+#include "bf5xx-ac97-pcm.h"
+#include "bf5xx-ac97.h"
+
+static struct snd_soc_machine bf5xx_board;
+
+static int bf5xx_board_startup(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+
+	pr_debug("%s enter\n", __func__);
+	cpu_dai->private_data = sport_handle;
+	return 0;
+}
+
+static struct snd_soc_ops bf5xx_board_ops = {
+	.startup = bf5xx_board_startup,
+};
+
+static struct snd_soc_dai_link bf5xx_board_dai = {
+	.name = "AC97",
+	.stream_name = "AC97 HiFi",
+	.cpu_dai = &bfin_ac97_dai,
+	.codec_dai = &ad1980_dai,
+	.ops = &bf5xx_board_ops,
+};
+
+static struct snd_soc_machine bf5xx_board = {
+	.name = "bf5xx-board",
+	.dai_link = &bf5xx_board_dai,
+	.num_links = 1,
+};
+
+static struct snd_soc_device bf5xx_board_snd_devdata = {
+	.machine = &bf5xx_board,
+	.platform = &bf5xx_ac97_soc_platform,
+	.codec_dev = &soc_codec_dev_ad1980,
+};
+
+static struct platform_device *bf5xx_board_snd_device;
+
+static int __init bf5xx_board_init(void)
+{
+	int ret;
+
+	bf5xx_board_snd_device = platform_device_alloc("soc-audio", -1);
+	if (!bf5xx_board_snd_device)
+		return -ENOMEM;
+
+	platform_set_drvdata(bf5xx_board_snd_device, &bf5xx_board_snd_devdata);
+	bf5xx_board_snd_devdata.dev = &bf5xx_board_snd_device->dev;
+	ret = platform_device_add(bf5xx_board_snd_device);
+
+	if (ret)
+		platform_device_put(bf5xx_board_snd_device);
+
+	return ret;
+}
+
+static void __exit bf5xx_board_exit(void)
+{
+	platform_device_unregister(bf5xx_board_snd_device);
+}
+
+module_init(bf5xx_board_init);
+module_exit(bf5xx_board_exit);
+
+/* Module information */
+MODULE_AUTHOR("Cliff Cai");
+MODULE_DESCRIPTION("ALSA SoC AD1980/1 BF5xx board");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/blackfin/bf5xx-ad73311.c b/sound/soc/blackfin/bf5xx-ad73311.c
new file mode 100644
index 0000000..622c9b9
--- /dev/null
+++ b/sound/soc/blackfin/bf5xx-ad73311.c
@@ -0,0 +1,240 @@
+/*
+ * File:         sound/soc/blackfin/bf5xx-ad73311.c
+ * Author:       Cliff Cai <Cliff.Cai@analog.com>
+ *
+ * Created:      Thur Sep 25 2008
+ * Description:  Board driver for ad73311 sound chip
+ *
+ * Modified:
+ *               Copyright 2008 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.org/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/pcm_params.h>
+
+#include <asm/blackfin.h>
+#include <asm/cacheflush.h>
+#include <asm/irq.h>
+#include <asm/dma.h>
+#include <asm/portmux.h>
+
+#include "../codecs/ad73311.h"
+#include "bf5xx-sport.h"
+#include "bf5xx-i2s-pcm.h"
+#include "bf5xx-i2s.h"
+
+#if CONFIG_SND_BF5XX_SPORT_NUM == 0
+#define bfin_write_SPORT_TCR1	bfin_write_SPORT0_TCR1
+#define bfin_read_SPORT_TCR1	bfin_read_SPORT0_TCR1
+#define bfin_write_SPORT_TCR2	bfin_write_SPORT0_TCR2
+#define bfin_write_SPORT_TX16	bfin_write_SPORT0_TX16
+#define bfin_read_SPORT_STAT	bfin_read_SPORT0_STAT
+#else
+#define bfin_write_SPORT_TCR1	bfin_write_SPORT1_TCR1
+#define bfin_read_SPORT_TCR1	bfin_read_SPORT1_TCR1
+#define bfin_write_SPORT_TCR2	bfin_write_SPORT1_TCR2
+#define bfin_write_SPORT_TX16	bfin_write_SPORT1_TX16
+#define bfin_read_SPORT_STAT	bfin_read_SPORT1_STAT
+#endif
+
+#define GPIO_SE CONFIG_SND_BFIN_AD73311_SE
+
+static struct snd_soc_machine bf5xx_ad73311;
+
+static int snd_ad73311_startup(void)
+{
+	pr_debug("%s enter\n", __func__);
+
+	/* Pull up SE pin on AD73311L */
+	gpio_set_value(GPIO_SE, 1);
+	return 0;
+}
+
+static int snd_ad73311_configure(void)
+{
+	unsigned short ctrl_regs[6];
+	unsigned short status = 0;
+	int count = 0;
+
+	/* DMCLK = MCLK = 16.384 MHz
+	 * SCLK = DMCLK/8 = 2.048 MHz
+	 * Sample Rate = DMCLK/2048  = 8 KHz
+	 */
+	ctrl_regs[0] = AD_CONTROL | AD_WRITE | CTRL_REG_B | REGB_MCDIV(0) | \
+			REGB_SCDIV(0) | REGB_DIRATE(0);
+	ctrl_regs[1] = AD_CONTROL | AD_WRITE | CTRL_REG_C | REGC_PUDEV | \
+			REGC_PUADC | REGC_PUDAC | REGC_PUREF | REGC_REFUSE ;
+	ctrl_regs[2] = AD_CONTROL | AD_WRITE | CTRL_REG_D | REGD_OGS(2) | \
+			REGD_IGS(2);
+	ctrl_regs[3] = AD_CONTROL | AD_WRITE | CTRL_REG_E | REGE_DA(0x1f);
+	ctrl_regs[4] = AD_CONTROL | AD_WRITE | CTRL_REG_F | REGF_SEEN ;
+	ctrl_regs[5] = AD_CONTROL | AD_WRITE | CTRL_REG_A | REGA_MODE_DATA;
+
+	local_irq_disable();
+	snd_ad73311_startup();
+	udelay(1);
+
+	bfin_write_SPORT_TCR1(TFSR);
+	bfin_write_SPORT_TCR2(0xF);
+	SSYNC();
+
+	/* SPORT Tx Register is a 8 x 16 FIFO, all the data can be put to
+	 * FIFO before enable SPORT to transfer the data
+	 */
+	for (count = 0; count < 6; count++)
+		bfin_write_SPORT_TX16(ctrl_regs[count]);
+	SSYNC();
+	bfin_write_SPORT_TCR1(bfin_read_SPORT_TCR1() | TSPEN);
+	SSYNC();
+
+	/* When TUVF is set, the data is already send out */
+	while (!(status & TUVF) && count++ < 10000) {
+		udelay(1);
+		status = bfin_read_SPORT_STAT();
+		SSYNC();
+	}
+	bfin_write_SPORT_TCR1(bfin_read_SPORT_TCR1() & ~TSPEN);
+	SSYNC();
+	local_irq_enable();
+
+	if (count == 10000) {
+		printk(KERN_ERR "ad73311: failed to configure codec\n");
+		return -1;
+	}
+	return 0;
+}
+
+static int bf5xx_probe(struct platform_device *pdev)
+{
+	int err;
+	if (gpio_request(GPIO_SE, "AD73311_SE")) {
+		printk(KERN_ERR "%s: Failed ro request GPIO_%d\n", __func__, GPIO_SE);
+		return -EBUSY;
+	}
+
+	gpio_direction_output(GPIO_SE, 0);
+
+	err = snd_ad73311_configure();
+	if (err < 0)
+		return -EFAULT;
+
+	return 0;
+}
+
+static int bf5xx_ad73311_startup(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+
+	pr_debug("%s enter\n", __func__);
+	cpu_dai->private_data = sport_handle;
+	return 0;
+}
+
+static int bf5xx_ad73311_hw_params(struct snd_pcm_substream *substream,
+	struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+	int ret = 0;
+
+	pr_debug("%s rate %d format %x\n", __func__, params_rate(params),
+		params_format(params));
+
+	/* set cpu DAI configuration */
+	ret = cpu_dai->dai_ops.set_fmt(cpu_dai, SND_SOC_DAIFMT_DSP_A |
+		SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+
+static struct snd_soc_ops bf5xx_ad73311_ops = {
+	.startup = bf5xx_ad73311_startup,
+	.hw_params = bf5xx_ad73311_hw_params,
+};
+
+static struct snd_soc_dai_link bf5xx_ad73311_dai = {
+	.name = "ad73311",
+	.stream_name = "AD73311",
+	.cpu_dai = &bf5xx_i2s_dai,
+	.codec_dai = &ad73311_dai,
+	.ops = &bf5xx_ad73311_ops,
+};
+
+static struct snd_soc_machine bf5xx_ad73311 = {
+	.name = "bf5xx_ad73311",
+	.probe = bf5xx_probe,
+	.dai_link = &bf5xx_ad73311_dai,
+	.num_links = 1,
+};
+
+static struct snd_soc_device bf5xx_ad73311_snd_devdata = {
+	.machine = &bf5xx_ad73311,
+	.platform = &bf5xx_i2s_soc_platform,
+	.codec_dev = &soc_codec_dev_ad73311,
+};
+
+static struct platform_device *bf52x_ad73311_snd_device;
+
+static int __init bf5xx_ad73311_init(void)
+{
+	int ret;
+
+	pr_debug("%s enter\n", __func__);
+	bf52x_ad73311_snd_device = platform_device_alloc("soc-audio", -1);
+	if (!bf52x_ad73311_snd_device)
+		return -ENOMEM;
+
+	platform_set_drvdata(bf52x_ad73311_snd_device, &bf5xx_ad73311_snd_devdata);
+	bf5xx_ad73311_snd_devdata.dev = &bf52x_ad73311_snd_device->dev;
+	ret = platform_device_add(bf52x_ad73311_snd_device);
+
+	if (ret)
+		platform_device_put(bf52x_ad73311_snd_device);
+
+	return ret;
+}
+
+static void __exit bf5xx_ad73311_exit(void)
+{
+	pr_debug("%s enter\n", __func__);
+	platform_device_unregister(bf52x_ad73311_snd_device);
+}
+
+module_init(bf5xx_ad73311_init);
+module_exit(bf5xx_ad73311_exit);
+
+/* Module information */
+MODULE_AUTHOR("Cliff Cai");
+MODULE_DESCRIPTION("ALSA SoC AD73311 Blackfin");
+MODULE_LICENSE("GPL");
+
diff --git a/sound/soc/blackfin/bf5xx-i2s-pcm.c b/sound/soc/blackfin/bf5xx-i2s-pcm.c
new file mode 100644
index 0000000..61fccf9
--- /dev/null
+++ b/sound/soc/blackfin/bf5xx-i2s-pcm.c
@@ -0,0 +1,288 @@
+/*
+ * File:         sound/soc/blackfin/bf5xx-i2s-pcm.c
+ * Author:       Cliff Cai <Cliff.Cai@analog.com>
+ *
+ * Created:      Tue June 06 2008
+ * Description:  DMA driver for i2s codec
+ *
+ * Modified:
+ *               Copyright 2008 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.org/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/dma-mapping.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include <asm/dma.h>
+
+#include "bf5xx-i2s-pcm.h"
+#include "bf5xx-i2s.h"
+#include "bf5xx-sport.h"
+
+static void bf5xx_dma_irq(void *data)
+{
+	struct snd_pcm_substream *pcm = data;
+	snd_pcm_period_elapsed(pcm);
+}
+
+static const struct snd_pcm_hardware bf5xx_pcm_hardware = {
+	.info			= SNDRV_PCM_INFO_INTERLEAVED |
+				   SNDRV_PCM_INFO_MMAP |
+				   SNDRV_PCM_INFO_MMAP_VALID |
+				   SNDRV_PCM_INFO_BLOCK_TRANSFER,
+	.formats		= SNDRV_PCM_FMTBIT_S16_LE |
+				   SNDRV_PCM_FMTBIT_S24_LE |
+				   SNDRV_PCM_FMTBIT_S32_LE,
+	.period_bytes_min	= 32,
+	.period_bytes_max	= 0x10000,
+	.periods_min		= 1,
+	.periods_max		= PAGE_SIZE/32,
+	.buffer_bytes_max	= 0x20000, /* 128 kbytes */
+	.fifo_size		= 16,
+};
+
+static int bf5xx_pcm_hw_params(struct snd_pcm_substream *substream,
+	struct snd_pcm_hw_params *params)
+{
+	size_t size = bf5xx_pcm_hardware.buffer_bytes_max;
+	snd_pcm_lib_malloc_pages(substream, size);
+
+	return 0;
+}
+
+static int bf5xx_pcm_hw_free(struct snd_pcm_substream *substream)
+{
+	snd_pcm_lib_free_pages(substream);
+
+	return 0;
+}
+
+static int bf5xx_pcm_prepare(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct sport_device *sport = runtime->private_data;
+	int period_bytes = frames_to_bytes(runtime, runtime->period_size);
+
+	pr_debug("%s enter\n", __func__);
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		sport_set_tx_callback(sport, bf5xx_dma_irq, substream);
+		sport_config_tx_dma(sport, runtime->dma_area,
+			runtime->periods, period_bytes);
+	} else {
+		sport_set_rx_callback(sport, bf5xx_dma_irq, substream);
+		sport_config_rx_dma(sport, runtime->dma_area,
+			runtime->periods, period_bytes);
+	}
+
+	return 0;
+}
+
+static int bf5xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct sport_device *sport = runtime->private_data;
+	int ret = 0;
+
+	pr_debug("%s enter\n", __func__);
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+			sport_tx_start(sport);
+		else
+			sport_rx_start(sport);
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+			sport_tx_stop(sport);
+		else
+			sport_rx_stop(sport);
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+static snd_pcm_uframes_t bf5xx_pcm_pointer(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct sport_device *sport = runtime->private_data;
+	unsigned int diff;
+	snd_pcm_uframes_t frames;
+	pr_debug("%s enter\n", __func__);
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		diff = sport_curr_offset_tx(sport);
+		frames = bytes_to_frames(substream->runtime, diff);
+	} else {
+		diff = sport_curr_offset_rx(sport);
+		frames = bytes_to_frames(substream->runtime, diff);
+	}
+	return frames;
+}
+
+static int bf5xx_pcm_open(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	int ret;
+
+	pr_debug("%s enter\n", __func__);
+	snd_soc_set_runtime_hwparams(substream, &bf5xx_pcm_hardware);
+
+	ret = snd_pcm_hw_constraint_integer(runtime, \
+			SNDRV_PCM_HW_PARAM_PERIODS);
+	if (ret < 0)
+		goto out;
+
+	if (sport_handle != NULL)
+		runtime->private_data = sport_handle;
+	else {
+		pr_err("sport_handle is NULL\n");
+		return -1;
+	}
+	return 0;
+
+ out:
+	return ret;
+}
+
+static int bf5xx_pcm_mmap(struct snd_pcm_substream *substream,
+	struct vm_area_struct *vma)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	size_t size = vma->vm_end - vma->vm_start;
+	vma->vm_start = (unsigned long)runtime->dma_area;
+	vma->vm_end = vma->vm_start + size;
+	vma->vm_flags |=  VM_SHARED;
+
+	return 0 ;
+}
+
+struct snd_pcm_ops bf5xx_pcm_i2s_ops = {
+	.open		= bf5xx_pcm_open,
+	.ioctl		= snd_pcm_lib_ioctl,
+	.hw_params	= bf5xx_pcm_hw_params,
+	.hw_free	= bf5xx_pcm_hw_free,
+	.prepare	= bf5xx_pcm_prepare,
+	.trigger	= bf5xx_pcm_trigger,
+	.pointer	= bf5xx_pcm_pointer,
+	.mmap		= bf5xx_pcm_mmap,
+};
+
+static int bf5xx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
+{
+	struct snd_pcm_substream *substream = pcm->streams[stream].substream;
+	struct snd_dma_buffer *buf = &substream->dma_buffer;
+	size_t size = bf5xx_pcm_hardware.buffer_bytes_max;
+
+	buf->dev.type = SNDRV_DMA_TYPE_DEV;
+	buf->dev.dev = pcm->card->dev;
+	buf->private_data = NULL;
+	buf->area = dma_alloc_coherent(pcm->card->dev, size,
+			&buf->addr, GFP_KERNEL);
+	if (!buf->area) {
+		pr_err("Failed to allocate dma memory \
+			Please increase uncached DMA memory region\n");
+		return -ENOMEM;
+	}
+	buf->bytes = size;
+
+	pr_debug("%s, area:%p, size:0x%08lx\n", __func__,
+		buf->area, buf->bytes);
+
+	if (stream == SNDRV_PCM_STREAM_PLAYBACK)
+		sport_handle->tx_buf = buf->area;
+	else
+		sport_handle->rx_buf = buf->area;
+
+	return 0;
+}
+
+static void bf5xx_pcm_free_dma_buffers(struct snd_pcm *pcm)
+{
+	struct snd_pcm_substream *substream;
+	struct snd_dma_buffer *buf;
+	int stream;
+
+	for (stream = 0; stream < 2; stream++) {
+		substream = pcm->streams[stream].substream;
+		if (!substream)
+			continue;
+
+		buf = &substream->dma_buffer;
+		if (!buf->area)
+			continue;
+		dma_free_coherent(NULL, buf->bytes, buf->area, 0);
+		buf->area = NULL;
+	}
+	if (sport_handle)
+		sport_done(sport_handle);
+}
+
+static u64 bf5xx_pcm_dmamask = DMA_32BIT_MASK;
+
+int bf5xx_pcm_i2s_new(struct snd_card *card, struct snd_soc_dai *dai,
+	struct snd_pcm *pcm)
+{
+	int ret = 0;
+
+	pr_debug("%s enter\n", __func__);
+	if (!card->dev->dma_mask)
+		card->dev->dma_mask = &bf5xx_pcm_dmamask;
+	if (!card->dev->coherent_dma_mask)
+		card->dev->coherent_dma_mask = DMA_32BIT_MASK;
+
+	if (dai->playback.channels_min) {
+		ret = bf5xx_pcm_preallocate_dma_buffer(pcm,
+			SNDRV_PCM_STREAM_PLAYBACK);
+		if (ret)
+			goto out;
+	}
+
+	if (dai->capture.channels_min) {
+		ret = bf5xx_pcm_preallocate_dma_buffer(pcm,
+			SNDRV_PCM_STREAM_CAPTURE);
+		if (ret)
+			goto out;
+	}
+ out:
+	return ret;
+}
+
+struct snd_soc_platform bf5xx_i2s_soc_platform = {
+	.name		= "bf5xx-audio",
+	.pcm_ops 	= &bf5xx_pcm_i2s_ops,
+	.pcm_new	= bf5xx_pcm_i2s_new,
+	.pcm_free	= bf5xx_pcm_free_dma_buffers,
+};
+EXPORT_SYMBOL_GPL(bf5xx_i2s_soc_platform);
+
+MODULE_AUTHOR("Cliff Cai");
+MODULE_DESCRIPTION("ADI Blackfin I2S PCM DMA module");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/blackfin/bf5xx-i2s-pcm.h b/sound/soc/blackfin/bf5xx-i2s-pcm.h
new file mode 100644
index 0000000..4d4609a
--- /dev/null
+++ b/sound/soc/blackfin/bf5xx-i2s-pcm.h
@@ -0,0 +1,29 @@
+/*
+ * linux/sound/arm/bf5xx-i2s-pcm.h -- ALSA PCM interface for the Blackfin
+ *
+ * Copyright 2007 Analog Device Inc.
+ *
+ * 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 _BF5XX_I2S_PCM_H
+#define _BF5XX_I2S_PCM_H
+
+struct bf5xx_pcm_dma_params {
+	char *name;			/* stream identifier */
+};
+
+struct bf5xx_gpio {
+	u32 sys;
+	u32 rx;
+	u32 tx;
+	u32 clk;
+	u32 frm;
+};
+
+/* platform data */
+extern struct snd_soc_platform bf5xx_i2s_soc_platform;
+
+#endif
diff --git a/sound/soc/blackfin/bf5xx-i2s.c b/sound/soc/blackfin/bf5xx-i2s.c
new file mode 100644
index 0000000..827587f
--- /dev/null
+++ b/sound/soc/blackfin/bf5xx-i2s.c
@@ -0,0 +1,311 @@
+/*
+ * File:         sound/soc/blackfin/bf5xx-i2s.c
+ * Author:       Cliff Cai <Cliff.Cai@analog.com>
+ *
+ * Created:      Tue June 06 2008
+ * Description:  Blackfin I2S CPU DAI driver
+ *
+ * Modified:
+ *               Copyright 2008 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.org/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+
+#include <asm/irq.h>
+#include <asm/portmux.h>
+#include <linux/mutex.h>
+#include <linux/gpio.h>
+
+#include "bf5xx-sport.h"
+#include "bf5xx-i2s.h"
+
+struct bf5xx_i2s_port {
+	u16 tcr1;
+	u16 rcr1;
+	u16 tcr2;
+	u16 rcr2;
+	int counter;
+};
+
+static struct bf5xx_i2s_port bf5xx_i2s;
+static int sport_num = CONFIG_SND_BF5XX_SPORT_NUM;
+
+static struct sport_param sport_params[2] = {
+	{
+		.dma_rx_chan	= CH_SPORT0_RX,
+		.dma_tx_chan	= CH_SPORT0_TX,
+		.err_irq	= IRQ_SPORT0_ERROR,
+		.regs		= (struct sport_register *)SPORT0_TCR1,
+	},
+	{
+		.dma_rx_chan	= CH_SPORT1_RX,
+		.dma_tx_chan	= CH_SPORT1_TX,
+		.err_irq	= IRQ_SPORT1_ERROR,
+		.regs		= (struct sport_register *)SPORT1_TCR1,
+	}
+};
+
+static u16 sport_req[][7] = {
+		{ P_SPORT0_DTPRI, P_SPORT0_TSCLK, P_SPORT0_RFS,
+		  P_SPORT0_DRPRI, P_SPORT0_RSCLK, 0},
+		{ P_SPORT1_DTPRI, P_SPORT1_TSCLK, P_SPORT1_RFS,
+		  P_SPORT1_DRPRI, P_SPORT1_RSCLK, 0},
+};
+
+static int bf5xx_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai,
+		unsigned int fmt)
+{
+	int ret = 0;
+
+	/* interface format:support I2S,slave mode */
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		bf5xx_i2s.tcr1 |= TFSR | TCKFE;
+		bf5xx_i2s.rcr1 |= RFSR | RCKFE;
+		bf5xx_i2s.tcr2 |= TSFSE;
+		bf5xx_i2s.rcr2 |= RSFSE;
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		bf5xx_i2s.tcr1 |= TFSR;
+		bf5xx_i2s.rcr1 |= RFSR;
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		ret = -EINVAL;
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBS_CFS:
+		ret = -EINVAL;
+		break;
+	case SND_SOC_DAIFMT_CBM_CFS:
+		ret = -EINVAL;
+		break;
+	case SND_SOC_DAIFMT_CBM_CFM:
+		break;
+	case SND_SOC_DAIFMT_CBS_CFM:
+		ret = -EINVAL;
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
+static int bf5xx_i2s_startup(struct snd_pcm_substream *substream)
+{
+	pr_debug("%s enter\n", __func__);
+
+	/*this counter is used for counting how many pcm streams are opened*/
+	bf5xx_i2s.counter++;
+	return 0;
+}
+
+static int bf5xx_i2s_hw_params(struct snd_pcm_substream *substream,
+				struct snd_pcm_hw_params *params)
+{
+	int ret = 0;
+
+	bf5xx_i2s.tcr2 &= ~0x1f;
+	bf5xx_i2s.rcr2 &= ~0x1f;
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S16_LE:
+		bf5xx_i2s.tcr2 |= 15;
+		bf5xx_i2s.rcr2 |= 15;
+		sport_handle->wdsize = 2;
+		break;
+	case SNDRV_PCM_FORMAT_S24_LE:
+		bf5xx_i2s.tcr2 |= 23;
+		bf5xx_i2s.rcr2 |= 23;
+		sport_handle->wdsize = 3;
+		break;
+	case SNDRV_PCM_FORMAT_S32_LE:
+		bf5xx_i2s.tcr2 |= 31;
+		bf5xx_i2s.rcr2 |= 31;
+		sport_handle->wdsize = 4;
+		break;
+	}
+
+	if (bf5xx_i2s.counter == 1) {
+		/*
+		 * TX and RX are not independent,they are enabled at the
+		 * same time, even if only one side is running. So, we
+		 * need to configure both of them at the time when the first
+		 * stream is opened.
+		 *
+		 * CPU DAI:slave mode.
+		 */
+		ret = sport_config_rx(sport_handle, bf5xx_i2s.rcr1,
+				      bf5xx_i2s.rcr2, 0, 0);
+		if (ret) {
+			pr_err("SPORT is busy!\n");
+			return -EBUSY;
+		}
+
+		ret = sport_config_tx(sport_handle, bf5xx_i2s.tcr1,
+				      bf5xx_i2s.tcr2, 0, 0);
+		if (ret) {
+			pr_err("SPORT is busy!\n");
+			return -EBUSY;
+		}
+	}
+
+	return 0;
+}
+
+static void bf5xx_i2s_shutdown(struct snd_pcm_substream *substream)
+{
+	pr_debug("%s enter\n", __func__);
+	bf5xx_i2s.counter--;
+}
+
+static int bf5xx_i2s_probe(struct platform_device *pdev,
+			   struct snd_soc_dai *dai)
+{
+	pr_debug("%s enter\n", __func__);
+	if (peripheral_request_list(&sport_req[sport_num][0], "soc-audio")) {
+		pr_err("Requesting Peripherals failed\n");
+		return -EFAULT;
+	}
+
+	/* request DMA for SPORT */
+	sport_handle = sport_init(&sport_params[sport_num], 4, \
+			2 * sizeof(u32), NULL);
+	if (!sport_handle) {
+		peripheral_free_list(&sport_req[sport_num][0]);
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+static void bf5xx_i2s_remove(struct platform_device *pdev,
+			   struct snd_soc_dai *dai)
+{
+	pr_debug("%s enter\n", __func__);
+	peripheral_free_list(&sport_req[sport_num][0]);
+}
+
+#ifdef CONFIG_PM
+static int bf5xx_i2s_suspend(struct platform_device *dev,
+			     struct snd_soc_dai *dai)
+{
+	struct sport_device *sport =
+		(struct sport_device *)dai->private_data;
+
+	pr_debug("%s : sport %d\n", __func__, dai->id);
+	if (!dai->active)
+		return 0;
+	if (dai->capture.active)
+		sport_rx_stop(sport);
+	if (dai->playback.active)
+		sport_tx_stop(sport);
+	return 0;
+}
+
+static int bf5xx_i2s_resume(struct platform_device *pdev,
+			    struct snd_soc_dai *dai)
+{
+	int ret;
+	struct sport_device *sport =
+		(struct sport_device *)dai->private_data;
+
+	pr_debug("%s : sport %d\n", __func__, dai->id);
+	if (!dai->active)
+		return 0;
+
+	ret = sport_config_rx(sport_handle, RFSR | RCKFE, RSFSE|0x1f, 0, 0);
+	if (ret) {
+		pr_err("SPORT is busy!\n");
+		return -EBUSY;
+	}
+
+	ret = sport_config_tx(sport_handle, TFSR | TCKFE, TSFSE|0x1f, 0, 0);
+	if (ret) {
+		pr_err("SPORT is busy!\n");
+		return -EBUSY;
+	}
+
+	if (dai->capture.active)
+		sport_rx_start(sport);
+	if (dai->playback.active)
+		sport_tx_start(sport);
+	return 0;
+}
+
+#else
+#define bf5xx_i2s_suspend	NULL
+#define bf5xx_i2s_resume	NULL
+#endif
+
+#define BF5XX_I2S_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
+		SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | \
+		SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | \
+		SNDRV_PCM_RATE_96000)
+
+#define BF5XX_I2S_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE |\
+	SNDRV_PCM_FMTBIT_S32_LE)
+
+struct snd_soc_dai bf5xx_i2s_dai = {
+	.name = "bf5xx-i2s",
+	.id = 0,
+	.type = SND_SOC_DAI_I2S,
+	.probe = bf5xx_i2s_probe,
+	.remove = bf5xx_i2s_remove,
+	.suspend = bf5xx_i2s_suspend,
+	.resume = bf5xx_i2s_resume,
+	.playback = {
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = BF5XX_I2S_RATES,
+		.formats = BF5XX_I2S_FORMATS,},
+	.capture = {
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = BF5XX_I2S_RATES,
+		.formats = BF5XX_I2S_FORMATS,},
+	.ops = {
+		.startup   = bf5xx_i2s_startup,
+		.shutdown  = bf5xx_i2s_shutdown,
+		.hw_params = bf5xx_i2s_hw_params,},
+	.dai_ops = {
+		.set_fmt = bf5xx_i2s_set_dai_fmt,
+	},
+};
+EXPORT_SYMBOL_GPL(bf5xx_i2s_dai);
+
+/* Module information */
+MODULE_AUTHOR("Cliff Cai");
+MODULE_DESCRIPTION("I2S driver for ADI Blackfin");
+MODULE_LICENSE("GPL");
+
diff --git a/sound/soc/blackfin/bf5xx-i2s.h b/sound/soc/blackfin/bf5xx-i2s.h
new file mode 100644
index 0000000..7107d1a
--- /dev/null
+++ b/sound/soc/blackfin/bf5xx-i2s.h
@@ -0,0 +1,14 @@
+/*
+ * linux/sound/arm/bf5xx-i2s.h
+ *
+ * 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 _BF5XX_I2S_H
+#define _BF5XX_I2S_H
+
+extern struct snd_soc_dai bf5xx_i2s_dai;
+
+#endif
diff --git a/sound/soc/blackfin/bf5xx-sport.c b/sound/soc/blackfin/bf5xx-sport.c
new file mode 100644
index 0000000..3b99e48
--- /dev/null
+++ b/sound/soc/blackfin/bf5xx-sport.c
@@ -0,0 +1,1032 @@
+/*
+ * File:         bf5xx_sport.c
+ * Based on:
+ * Author:       Roy Huang <roy.huang@analog.com>
+ *
+ * Created:      Tue Sep 21 10:52:42 CEST 2004
+ * Description:
+ *               Blackfin SPORT Driver
+ *
+ *               Copyright 2004-2007 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.org/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/gpio.h>
+#include <linux/bug.h>
+#include <asm/portmux.h>
+#include <asm/dma.h>
+#include <asm/blackfin.h>
+#include <asm/cacheflush.h>
+
+#include "bf5xx-sport.h"
+/* delay between frame sync pulse and first data bit in multichannel mode */
+#define FRAME_DELAY (1<<12)
+
+struct sport_device *sport_handle;
+EXPORT_SYMBOL(sport_handle);
+/* note: multichannel is in units of 8 channels,
+ * tdm_count is # channels NOT / 8 ! */
+int sport_set_multichannel(struct sport_device *sport,
+		int tdm_count, u32 mask, int packed)
+{
+	pr_debug("%s tdm_count=%d mask:0x%08x packed=%d\n", __func__,
+			tdm_count, mask, packed);
+
+	if ((sport->regs->tcr1 & TSPEN) || (sport->regs->rcr1 & RSPEN))
+		return -EBUSY;
+
+	if (tdm_count & 0x7)
+		return -EINVAL;
+
+	if (tdm_count > 32)
+		return -EINVAL; /* Only support less than 32 channels now */
+
+	if (tdm_count) {
+		sport->regs->mcmc1 = ((tdm_count>>3)-1) << 12;
+		sport->regs->mcmc2 = FRAME_DELAY | MCMEN | \
+				(packed ? (MCDTXPE|MCDRXPE) : 0);
+
+		sport->regs->mtcs0 = mask;
+		sport->regs->mrcs0 = mask;
+		sport->regs->mtcs1 = 0;
+		sport->regs->mrcs1 = 0;
+		sport->regs->mtcs2 = 0;
+		sport->regs->mrcs2 = 0;
+		sport->regs->mtcs3 = 0;
+		sport->regs->mrcs3 = 0;
+	} else {
+		sport->regs->mcmc1 = 0;
+		sport->regs->mcmc2 = 0;
+
+		sport->regs->mtcs0 = 0;
+		sport->regs->mrcs0 = 0;
+	}
+
+	sport->regs->mtcs1 = 0; sport->regs->mtcs2 = 0; sport->regs->mtcs3 = 0;
+	sport->regs->mrcs1 = 0; sport->regs->mrcs2 = 0; sport->regs->mrcs3 = 0;
+
+	SSYNC();
+
+	return 0;
+}
+EXPORT_SYMBOL(sport_set_multichannel);
+
+int sport_config_rx(struct sport_device *sport, unsigned int rcr1,
+		unsigned int rcr2, unsigned int clkdiv, unsigned int fsdiv)
+{
+	if ((sport->regs->tcr1 & TSPEN) || (sport->regs->rcr1 & RSPEN))
+		return -EBUSY;
+
+	sport->regs->rcr1 = rcr1;
+	sport->regs->rcr2 = rcr2;
+	sport->regs->rclkdiv = clkdiv;
+	sport->regs->rfsdiv = fsdiv;
+
+	SSYNC();
+
+	return 0;
+}
+EXPORT_SYMBOL(sport_config_rx);
+
+int sport_config_tx(struct sport_device *sport, unsigned int tcr1,
+		unsigned int tcr2, unsigned int clkdiv, unsigned int fsdiv)
+{
+	if ((sport->regs->tcr1 & TSPEN) || (sport->regs->rcr1 & RSPEN))
+		return -EBUSY;
+
+	sport->regs->tcr1 = tcr1;
+	sport->regs->tcr2 = tcr2;
+	sport->regs->tclkdiv = clkdiv;
+	sport->regs->tfsdiv = fsdiv;
+
+	SSYNC();
+
+	return 0;
+}
+EXPORT_SYMBOL(sport_config_tx);
+
+static void setup_desc(struct dmasg *desc, void *buf, int fragcount,
+		size_t fragsize, unsigned int cfg,
+		unsigned int x_count, unsigned int ycount, size_t wdsize)
+{
+
+	int i;
+
+	for (i = 0; i < fragcount; ++i) {
+		desc[i].next_desc_addr  = (unsigned long)&(desc[i + 1]);
+		desc[i].start_addr = (unsigned long)buf + i*fragsize;
+		desc[i].cfg = cfg;
+		desc[i].x_count = x_count;
+		desc[i].x_modify = wdsize;
+		desc[i].y_count = ycount;
+		desc[i].y_modify = wdsize;
+	}
+
+	/* make circular */
+	desc[fragcount-1].next_desc_addr = (unsigned long)desc;
+
+	pr_debug("setup desc: desc0=%p, next0=%lx, desc1=%p,"
+		"next1=%lx\nx_count=%x,y_count=%x,addr=0x%lx,cfs=0x%x\n",
+		&(desc[0]), desc[0].next_desc_addr,
+		&(desc[1]), desc[1].next_desc_addr,
+		desc[0].x_count, desc[0].y_count,
+		desc[0].start_addr, desc[0].cfg);
+}
+
+static int sport_start(struct sport_device *sport)
+{
+	enable_dma(sport->dma_rx_chan);
+	enable_dma(sport->dma_tx_chan);
+	sport->regs->rcr1 |= RSPEN;
+	sport->regs->tcr1 |= TSPEN;
+	SSYNC();
+
+	return 0;
+}
+
+static int sport_stop(struct sport_device *sport)
+{
+	sport->regs->tcr1 &= ~TSPEN;
+	sport->regs->rcr1 &= ~RSPEN;
+	SSYNC();
+
+	disable_dma(sport->dma_rx_chan);
+	disable_dma(sport->dma_tx_chan);
+	return 0;
+}
+
+static inline int sport_hook_rx_dummy(struct sport_device *sport)
+{
+	struct dmasg *desc, temp_desc;
+	unsigned long flags;
+
+	BUG_ON(sport->dummy_rx_desc == NULL);
+	BUG_ON(sport->curr_rx_desc == sport->dummy_rx_desc);
+
+	/* Maybe the dummy buffer descriptor ring is damaged */
+	sport->dummy_rx_desc->next_desc_addr = \
+			(unsigned long)(sport->dummy_rx_desc+1);
+
+	local_irq_save(flags);
+	desc = (struct dmasg *)get_dma_next_desc_ptr(sport->dma_rx_chan);
+	/* Copy the descriptor which will be damaged to backup */
+	temp_desc = *desc;
+	desc->x_count = 0xa;
+	desc->y_count = 0;
+	desc->next_desc_addr = (unsigned long)(sport->dummy_rx_desc);
+	local_irq_restore(flags);
+	/* Waiting for dummy buffer descriptor is already hooked*/
+	while ((get_dma_curr_desc_ptr(sport->dma_rx_chan) -
+			sizeof(struct dmasg)) !=
+			(unsigned long)sport->dummy_rx_desc)
+		;
+	sport->curr_rx_desc = sport->dummy_rx_desc;
+	/* Restore the damaged descriptor */
+	*desc = temp_desc;
+
+	return 0;
+}
+
+static inline int sport_rx_dma_start(struct sport_device *sport, int dummy)
+{
+	if (dummy) {
+		sport->dummy_rx_desc->next_desc_addr = \
+				(unsigned long) sport->dummy_rx_desc;
+		sport->curr_rx_desc = sport->dummy_rx_desc;
+	} else
+		sport->curr_rx_desc = sport->dma_rx_desc;
+
+	set_dma_next_desc_addr(sport->dma_rx_chan, \
+			(unsigned long)(sport->curr_rx_desc));
+	set_dma_x_count(sport->dma_rx_chan, 0);
+	set_dma_x_modify(sport->dma_rx_chan, 0);
+	set_dma_config(sport->dma_rx_chan, (DMAFLOW_LARGE | NDSIZE_9 | \
+				WDSIZE_32 | WNR));
+	set_dma_curr_addr(sport->dma_rx_chan, sport->curr_rx_desc->start_addr);
+	SSYNC();
+
+	return 0;
+}
+
+static inline int sport_tx_dma_start(struct sport_device *sport, int dummy)
+{
+	if (dummy) {
+		sport->dummy_tx_desc->next_desc_addr = \
+				(unsigned long) sport->dummy_tx_desc;
+		sport->curr_tx_desc = sport->dummy_tx_desc;
+	} else
+		sport->curr_tx_desc = sport->dma_tx_desc;
+
+	set_dma_next_desc_addr(sport->dma_tx_chan, \
+			(unsigned long)(sport->curr_tx_desc));
+	set_dma_x_count(sport->dma_tx_chan, 0);
+	set_dma_x_modify(sport->dma_tx_chan, 0);
+	set_dma_config(sport->dma_tx_chan,
+			(DMAFLOW_LARGE | NDSIZE_9 | WDSIZE_32));
+	set_dma_curr_addr(sport->dma_tx_chan, sport->curr_tx_desc->start_addr);
+	SSYNC();
+
+	return 0;
+}
+
+int sport_rx_start(struct sport_device *sport)
+{
+	unsigned long flags;
+	pr_debug("%s enter\n", __func__);
+	if (sport->rx_run)
+		return -EBUSY;
+	if (sport->tx_run) {
+		/* tx is running, rx is not running */
+		BUG_ON(sport->dma_rx_desc == NULL);
+		BUG_ON(sport->curr_rx_desc != sport->dummy_rx_desc);
+		local_irq_save(flags);
+		while ((get_dma_curr_desc_ptr(sport->dma_rx_chan) -
+			sizeof(struct dmasg)) !=
+			(unsigned long)sport->dummy_rx_desc)
+			;
+		sport->dummy_rx_desc->next_desc_addr =
+				(unsigned long)(sport->dma_rx_desc);
+		local_irq_restore(flags);
+		sport->curr_rx_desc = sport->dma_rx_desc;
+	} else {
+		sport_tx_dma_start(sport, 1);
+		sport_rx_dma_start(sport, 0);
+		sport_start(sport);
+	}
+
+	sport->rx_run = 1;
+
+	return 0;
+}
+EXPORT_SYMBOL(sport_rx_start);
+
+int sport_rx_stop(struct sport_device *sport)
+{
+	pr_debug("%s enter\n", __func__);
+
+	if (!sport->rx_run)
+		return 0;
+	if (sport->tx_run) {
+		/* TX dma is still running, hook the dummy buffer */
+		sport_hook_rx_dummy(sport);
+	} else {
+		/* Both rx and tx dma will be stopped */
+		sport_stop(sport);
+		sport->curr_rx_desc = NULL;
+		sport->curr_tx_desc = NULL;
+	}
+
+	sport->rx_run = 0;
+
+	return 0;
+}
+EXPORT_SYMBOL(sport_rx_stop);
+
+static inline int sport_hook_tx_dummy(struct sport_device *sport)
+{
+	struct dmasg *desc, temp_desc;
+	unsigned long flags;
+
+	BUG_ON(sport->dummy_tx_desc == NULL);
+	BUG_ON(sport->curr_tx_desc == sport->dummy_tx_desc);
+
+	sport->dummy_tx_desc->next_desc_addr = \
+			(unsigned long)(sport->dummy_tx_desc+1);
+
+	/* Shorten the time on last normal descriptor */
+	local_irq_save(flags);
+	desc = (struct dmasg *)get_dma_next_desc_ptr(sport->dma_tx_chan);
+	/* Store the descriptor which will be damaged */
+	temp_desc = *desc;
+	desc->x_count = 0xa;
+	desc->y_count = 0;
+	desc->next_desc_addr = (unsigned long)(sport->dummy_tx_desc);
+	local_irq_restore(flags);
+	/* Waiting for dummy buffer descriptor is already hooked*/
+	while ((get_dma_curr_desc_ptr(sport->dma_tx_chan) - \
+			sizeof(struct dmasg)) != \
+			(unsigned long)sport->dummy_tx_desc)
+		;
+	sport->curr_tx_desc = sport->dummy_tx_desc;
+	/* Restore the damaged descriptor */
+	*desc = temp_desc;
+
+	return 0;
+}
+
+int sport_tx_start(struct sport_device *sport)
+{
+	unsigned flags;
+	pr_debug("%s: tx_run:%d, rx_run:%d\n", __func__,
+			sport->tx_run, sport->rx_run);
+	if (sport->tx_run)
+		return -EBUSY;
+	if (sport->rx_run) {
+		BUG_ON(sport->dma_tx_desc == NULL);
+		BUG_ON(sport->curr_tx_desc != sport->dummy_tx_desc);
+		/* Hook the normal buffer descriptor */
+		local_irq_save(flags);
+		while ((get_dma_curr_desc_ptr(sport->dma_tx_chan) -
+			sizeof(struct dmasg)) !=
+			(unsigned long)sport->dummy_tx_desc)
+			;
+		sport->dummy_tx_desc->next_desc_addr =
+				(unsigned long)(sport->dma_tx_desc);
+		local_irq_restore(flags);
+		sport->curr_tx_desc = sport->dma_tx_desc;
+	} else {
+
+		sport_tx_dma_start(sport, 0);
+		/* Let rx dma run the dummy buffer */
+		sport_rx_dma_start(sport, 1);
+		sport_start(sport);
+	}
+	sport->tx_run = 1;
+	return 0;
+}
+EXPORT_SYMBOL(sport_tx_start);
+
+int sport_tx_stop(struct sport_device *sport)
+{
+	if (!sport->tx_run)
+		return 0;
+	if (sport->rx_run) {
+		/* RX is still running, hook the dummy buffer */
+		sport_hook_tx_dummy(sport);
+	} else {
+		/* Both rx and tx dma stopped */
+		sport_stop(sport);
+		sport->curr_rx_desc = NULL;
+		sport->curr_tx_desc = NULL;
+	}
+
+	sport->tx_run = 0;
+
+	return 0;
+}
+EXPORT_SYMBOL(sport_tx_stop);
+
+static inline int compute_wdsize(size_t wdsize)
+{
+	switch (wdsize) {
+	case 1:
+		return WDSIZE_8;
+	case 2:
+		return WDSIZE_16;
+	case 4:
+	default:
+		return WDSIZE_32;
+	}
+}
+
+int sport_config_rx_dma(struct sport_device *sport, void *buf,
+		int fragcount, size_t fragsize)
+{
+	unsigned int x_count;
+	unsigned int y_count;
+	unsigned int cfg;
+	dma_addr_t addr;
+
+	pr_debug("%s buf:%p, frag:%d, fragsize:0x%lx\n", __func__, \
+			buf, fragcount, fragsize);
+
+	x_count = fragsize / sport->wdsize;
+	y_count = 0;
+
+	/* for fragments larger than 64k words we use 2d dma,
+	 * denote fragecount as two numbers' mutliply and both of them
+	 * are less than 64k.*/
+	if (x_count >= 0x10000) {
+		int i, count = x_count;
+
+		for (i = 16; i > 0; i--) {
+			x_count = 1 << i;
+			if ((count & (x_count - 1)) == 0) {
+				y_count = count >> i;
+				if (y_count < 0x10000)
+					break;
+			}
+		}
+		if (i == 0)
+			return -EINVAL;
+	}
+	pr_debug("%s(x_count:0x%x, y_count:0x%x)\n", __func__,
+			x_count, y_count);
+
+	if (sport->dma_rx_desc)
+		dma_free_coherent(NULL, sport->rx_desc_bytes,
+					sport->dma_rx_desc, 0);
+
+	/* Allocate a new descritor ring as current one. */
+	sport->dma_rx_desc = dma_alloc_coherent(NULL, \
+			fragcount * sizeof(struct dmasg), &addr, 0);
+	sport->rx_desc_bytes = fragcount * sizeof(struct dmasg);
+
+	if (!sport->dma_rx_desc) {
+		pr_err("Failed to allocate memory for rx desc\n");
+		return -ENOMEM;
+	}
+
+	sport->rx_buf = buf;
+	sport->rx_fragsize = fragsize;
+	sport->rx_frags = fragcount;
+
+	cfg     = 0x7000 | DI_EN | compute_wdsize(sport->wdsize) | WNR | \
+		  (DESC_ELEMENT_COUNT << 8); /* large descriptor mode */
+
+	if (y_count != 0)
+		cfg |= DMA2D;
+
+	setup_desc(sport->dma_rx_desc, buf, fragcount, fragsize,
+			cfg|DMAEN, x_count, y_count, sport->wdsize);
+
+	return 0;
+}
+EXPORT_SYMBOL(sport_config_rx_dma);
+
+int sport_config_tx_dma(struct sport_device *sport, void *buf, \
+		int fragcount, size_t fragsize)
+{
+	unsigned int x_count;
+	unsigned int y_count;
+	unsigned int cfg;
+	dma_addr_t addr;
+
+	pr_debug("%s buf:%p, fragcount:%d, fragsize:0x%lx\n",
+			__func__, buf, fragcount, fragsize);
+
+	x_count = fragsize/sport->wdsize;
+	y_count = 0;
+
+	/* for fragments larger than 64k words we use 2d dma,
+	 * denote fragecount as two numbers' mutliply and both of them
+	 * are less than 64k.*/
+	if (x_count >= 0x10000) {
+		int i, count = x_count;
+
+		for (i = 16; i > 0; i--) {
+			x_count = 1 << i;
+			if ((count & (x_count - 1)) == 0) {
+				y_count = count >> i;
+				if (y_count < 0x10000)
+					break;
+			}
+		}
+		if (i == 0)
+			return -EINVAL;
+	}
+	pr_debug("%s x_count:0x%x, y_count:0x%x\n", __func__,
+			x_count, y_count);
+
+
+	if (sport->dma_tx_desc) {
+		dma_free_coherent(NULL, sport->tx_desc_bytes, \
+				sport->dma_tx_desc, 0);
+	}
+
+	sport->dma_tx_desc = dma_alloc_coherent(NULL, \
+			fragcount * sizeof(struct dmasg), &addr, 0);
+	sport->tx_desc_bytes = fragcount * sizeof(struct dmasg);
+	if (!sport->dma_tx_desc) {
+		pr_err("Failed to allocate memory for tx desc\n");
+		return -ENOMEM;
+	}
+
+	sport->tx_buf = buf;
+	sport->tx_fragsize = fragsize;
+	sport->tx_frags = fragcount;
+	cfg     = 0x7000 | DI_EN | compute_wdsize(sport->wdsize) | \
+		  (DESC_ELEMENT_COUNT << 8); /* large descriptor mode */
+
+	if (y_count != 0)
+		cfg |= DMA2D;
+
+	setup_desc(sport->dma_tx_desc, buf, fragcount, fragsize,
+			cfg|DMAEN, x_count, y_count, sport->wdsize);
+
+	return 0;
+}
+EXPORT_SYMBOL(sport_config_tx_dma);
+
+/* setup dummy dma descriptor ring, which don't generate interrupts,
+ * the x_modify is set to 0 */
+static int sport_config_rx_dummy(struct sport_device *sport)
+{
+	struct dmasg *desc;
+	unsigned config;
+
+	pr_debug("%s entered\n", __func__);
+#if L1_DATA_A_LENGTH != 0
+	desc = (struct dmasg *) l1_data_sram_alloc(2 * sizeof(*desc));
+#else
+	{
+		dma_addr_t addr;
+		desc = dma_alloc_coherent(NULL, 2 * sizeof(*desc), &addr, 0);
+	}
+#endif
+	if (desc == NULL) {
+		pr_err("Failed to allocate memory for dummy rx desc\n");
+		return -ENOMEM;
+	}
+	memset(desc, 0, 2 * sizeof(*desc));
+	sport->dummy_rx_desc = desc;
+	desc->start_addr = (unsigned long)sport->dummy_buf;
+	config = DMAFLOW_LARGE | NDSIZE_9 | compute_wdsize(sport->wdsize)
+		 | WNR | DMAEN;
+	desc->cfg = config;
+	desc->x_count = sport->dummy_count/sport->wdsize;
+	desc->x_modify = sport->wdsize;
+	desc->y_count = 0;
+	desc->y_modify = 0;
+	memcpy(desc+1, desc, sizeof(*desc));
+	desc->next_desc_addr = (unsigned long)(desc+1);
+	desc[1].next_desc_addr = (unsigned long)desc;
+	return 0;
+}
+
+static int sport_config_tx_dummy(struct sport_device *sport)
+{
+	struct dmasg *desc;
+	unsigned int config;
+
+	pr_debug("%s entered\n", __func__);
+
+#if L1_DATA_A_LENGTH != 0
+	desc = (struct dmasg *) l1_data_sram_alloc(2 * sizeof(*desc));
+#else
+	{
+		dma_addr_t addr;
+		desc = dma_alloc_coherent(NULL, 2 * sizeof(*desc), &addr, 0);
+	}
+#endif
+	if (!desc) {
+		pr_err("Failed to allocate memory for dummy tx desc\n");
+		return -ENOMEM;
+	}
+	memset(desc, 0, 2 * sizeof(*desc));
+	sport->dummy_tx_desc = desc;
+	desc->start_addr = (unsigned long)sport->dummy_buf + \
+		sport->dummy_count;
+	config = DMAFLOW_LARGE | NDSIZE_9 |
+		 compute_wdsize(sport->wdsize) | DMAEN;
+	desc->cfg = config;
+	desc->x_count = sport->dummy_count/sport->wdsize;
+	desc->x_modify = sport->wdsize;
+	desc->y_count = 0;
+	desc->y_modify = 0;
+	memcpy(desc+1, desc, sizeof(*desc));
+	desc->next_desc_addr = (unsigned long)(desc+1);
+	desc[1].next_desc_addr = (unsigned long)desc;
+	return 0;
+}
+
+unsigned long sport_curr_offset_rx(struct sport_device *sport)
+{
+	unsigned long curr = get_dma_curr_addr(sport->dma_rx_chan);
+
+	return (unsigned char *)curr - sport->rx_buf;
+}
+EXPORT_SYMBOL(sport_curr_offset_rx);
+
+unsigned long sport_curr_offset_tx(struct sport_device *sport)
+{
+	unsigned long curr = get_dma_curr_addr(sport->dma_tx_chan);
+
+	return (unsigned char *)curr - sport->tx_buf;
+}
+EXPORT_SYMBOL(sport_curr_offset_tx);
+
+void sport_incfrag(struct sport_device *sport, int *frag, int tx)
+{
+	++(*frag);
+	if (tx == 1 && *frag == sport->tx_frags)
+		*frag = 0;
+
+	if (tx == 0 && *frag == sport->rx_frags)
+		*frag = 0;
+}
+EXPORT_SYMBOL(sport_incfrag);
+
+void sport_decfrag(struct sport_device *sport, int *frag, int tx)
+{
+	--(*frag);
+	if (tx == 1 && *frag == 0)
+		*frag = sport->tx_frags;
+
+	if (tx == 0 && *frag == 0)
+		*frag = sport->rx_frags;
+}
+EXPORT_SYMBOL(sport_decfrag);
+
+static int sport_check_status(struct sport_device *sport,
+		unsigned int *sport_stat,
+		unsigned int *rx_stat,
+		unsigned int *tx_stat)
+{
+	int status = 0;
+
+	if (sport_stat) {
+		SSYNC();
+		status = sport->regs->stat;
+		if (status & (TOVF|TUVF|ROVF|RUVF))
+			sport->regs->stat = (status & (TOVF|TUVF|ROVF|RUVF));
+		SSYNC();
+		*sport_stat = status;
+	}
+
+	if (rx_stat) {
+		SSYNC();
+		status = get_dma_curr_irqstat(sport->dma_rx_chan);
+		if (status & (DMA_DONE|DMA_ERR))
+			clear_dma_irqstat(sport->dma_rx_chan);
+		SSYNC();
+		*rx_stat = status;
+	}
+
+	if (tx_stat) {
+		SSYNC();
+		status = get_dma_curr_irqstat(sport->dma_tx_chan);
+		if (status & (DMA_DONE|DMA_ERR))
+			clear_dma_irqstat(sport->dma_tx_chan);
+		SSYNC();
+		*tx_stat = status;
+	}
+
+	return 0;
+}
+
+int  sport_dump_stat(struct sport_device *sport, char *buf, size_t len)
+{
+	int ret;
+
+	ret = snprintf(buf, len,
+			"sts: 0x%04x\n"
+			"rx dma %d sts: 0x%04x tx dma %d sts: 0x%04x\n",
+			sport->regs->stat,
+			sport->dma_rx_chan,
+			get_dma_curr_irqstat(sport->dma_rx_chan),
+			sport->dma_tx_chan,
+			get_dma_curr_irqstat(sport->dma_tx_chan));
+	buf += ret;
+	len -= ret;
+
+	ret += snprintf(buf, len,
+			"curr_rx_desc:0x%p, curr_tx_desc:0x%p\n"
+			"dma_rx_desc:0x%p, dma_tx_desc:0x%p\n"
+			"dummy_rx_desc:0x%p, dummy_tx_desc:0x%p\n",
+			sport->curr_rx_desc, sport->curr_tx_desc,
+			sport->dma_rx_desc, sport->dma_tx_desc,
+			sport->dummy_rx_desc, sport->dummy_tx_desc);
+
+	return ret;
+}
+
+static irqreturn_t rx_handler(int irq, void *dev_id)
+{
+	unsigned int rx_stat;
+	struct sport_device *sport = dev_id;
+
+	pr_debug("%s enter\n", __func__);
+	sport_check_status(sport, NULL, &rx_stat, NULL);
+	if (!(rx_stat & DMA_DONE))
+		pr_err("rx dma is already stopped\n");
+
+	if (sport->rx_callback) {
+		sport->rx_callback(sport->rx_data);
+		return IRQ_HANDLED;
+	}
+
+	return IRQ_NONE;
+}
+
+static irqreturn_t tx_handler(int irq, void *dev_id)
+{
+	unsigned int tx_stat;
+	struct sport_device *sport = dev_id;
+	pr_debug("%s enter\n", __func__);
+	sport_check_status(sport, NULL, NULL, &tx_stat);
+	if (!(tx_stat & DMA_DONE)) {
+		pr_err("tx dma is already stopped\n");
+		return IRQ_HANDLED;
+	}
+	if (sport->tx_callback) {
+		sport->tx_callback(sport->tx_data);
+		return IRQ_HANDLED;
+	}
+
+	return IRQ_NONE;
+}
+
+static irqreturn_t err_handler(int irq, void *dev_id)
+{
+	unsigned int status = 0;
+	struct sport_device *sport = dev_id;
+
+	pr_debug("%s\n", __func__);
+	if (sport_check_status(sport, &status, NULL, NULL)) {
+		pr_err("error checking status ??");
+		return IRQ_NONE;
+	}
+
+	if (status & (TOVF|TUVF|ROVF|RUVF)) {
+		pr_info("sport status error:%s%s%s%s\n",
+				status & TOVF ? " TOVF" : "",
+				status & TUVF ? " TUVF" : "",
+				status & ROVF ? " ROVF" : "",
+				status & RUVF ? " RUVF" : "");
+		if (status & TOVF || status & TUVF) {
+			disable_dma(sport->dma_tx_chan);
+			if (sport->tx_run)
+				sport_tx_dma_start(sport, 0);
+			else
+				sport_tx_dma_start(sport, 1);
+			enable_dma(sport->dma_tx_chan);
+		} else {
+			disable_dma(sport->dma_rx_chan);
+			if (sport->rx_run)
+				sport_rx_dma_start(sport, 0);
+			else
+				sport_rx_dma_start(sport, 1);
+			enable_dma(sport->dma_rx_chan);
+		}
+	}
+	status = sport->regs->stat;
+	if (status & (TOVF|TUVF|ROVF|RUVF))
+		sport->regs->stat = (status & (TOVF|TUVF|ROVF|RUVF));
+	SSYNC();
+
+	if (sport->err_callback)
+		sport->err_callback(sport->err_data);
+
+	return IRQ_HANDLED;
+}
+
+int sport_set_rx_callback(struct sport_device *sport,
+		       void (*rx_callback)(void *), void *rx_data)
+{
+	BUG_ON(rx_callback == NULL);
+	sport->rx_callback = rx_callback;
+	sport->rx_data = rx_data;
+
+	return 0;
+}
+EXPORT_SYMBOL(sport_set_rx_callback);
+
+int sport_set_tx_callback(struct sport_device *sport,
+		void (*tx_callback)(void *), void *tx_data)
+{
+	BUG_ON(tx_callback == NULL);
+	sport->tx_callback = tx_callback;
+	sport->tx_data = tx_data;
+
+	return 0;
+}
+EXPORT_SYMBOL(sport_set_tx_callback);
+
+int sport_set_err_callback(struct sport_device *sport,
+		void (*err_callback)(void *), void *err_data)
+{
+	BUG_ON(err_callback == NULL);
+	sport->err_callback = err_callback;
+	sport->err_data = err_data;
+
+	return 0;
+}
+EXPORT_SYMBOL(sport_set_err_callback);
+
+struct sport_device *sport_init(struct sport_param *param, unsigned wdsize,
+		unsigned dummy_count, void *private_data)
+{
+	int ret;
+	struct sport_device *sport;
+	pr_debug("%s enter\n", __func__);
+	BUG_ON(param == NULL);
+	BUG_ON(wdsize == 0 || dummy_count == 0);
+	sport = kmalloc(sizeof(struct sport_device), GFP_KERNEL);
+	if (!sport) {
+		pr_err("Failed to allocate for sport device\n");
+		return NULL;
+	}
+
+	memset(sport, 0, sizeof(struct sport_device));
+	sport->dma_rx_chan = param->dma_rx_chan;
+	sport->dma_tx_chan = param->dma_tx_chan;
+	sport->err_irq = param->err_irq;
+	sport->regs = param->regs;
+	sport->private_data = private_data;
+
+	if (request_dma(sport->dma_rx_chan, "SPORT RX Data") == -EBUSY) {
+		pr_err("Failed to request RX dma %d\n", \
+				sport->dma_rx_chan);
+		goto __init_err1;
+	}
+	if (set_dma_callback(sport->dma_rx_chan, rx_handler, sport) != 0) {
+		pr_err("Failed to request RX irq %d\n", \
+				sport->dma_rx_chan);
+		goto __init_err2;
+	}
+
+	if (request_dma(sport->dma_tx_chan, "SPORT TX Data") == -EBUSY) {
+		pr_err("Failed to request TX dma %d\n", \
+				sport->dma_tx_chan);
+		goto __init_err2;
+	}
+
+	if (set_dma_callback(sport->dma_tx_chan, tx_handler, sport) != 0) {
+		pr_err("Failed to request TX irq %d\n", \
+				sport->dma_tx_chan);
+		goto __init_err3;
+	}
+
+	if (request_irq(sport->err_irq, err_handler, IRQF_SHARED, "SPORT err",
+			sport) < 0) {
+		pr_err("Failed to request err irq:%d\n", \
+				sport->err_irq);
+		goto __init_err3;
+	}
+
+	pr_err("dma rx:%d tx:%d, err irq:%d, regs:%p\n",
+			sport->dma_rx_chan, sport->dma_tx_chan,
+			sport->err_irq, sport->regs);
+
+	sport->wdsize = wdsize;
+	sport->dummy_count = dummy_count;
+
+#if L1_DATA_A_LENGTH != 0
+	sport->dummy_buf = l1_data_sram_alloc(dummy_count * 2);
+#else
+	sport->dummy_buf = kmalloc(dummy_count * 2, GFP_KERNEL);
+#endif
+	if (sport->dummy_buf == NULL) {
+		pr_err("Failed to allocate dummy buffer\n");
+		goto __error;
+	}
+
+	memset(sport->dummy_buf, 0, dummy_count * 2);
+	ret = sport_config_rx_dummy(sport);
+	if (ret) {
+		pr_err("Failed to config rx dummy ring\n");
+		goto __error;
+	}
+	ret = sport_config_tx_dummy(sport);
+	if (ret) {
+		pr_err("Failed to config tx dummy ring\n");
+		goto __error;
+	}
+
+	return sport;
+__error:
+	free_irq(sport->err_irq, sport);
+__init_err3:
+	free_dma(sport->dma_tx_chan);
+__init_err2:
+	free_dma(sport->dma_rx_chan);
+__init_err1:
+	kfree(sport);
+	return NULL;
+}
+EXPORT_SYMBOL(sport_init);
+
+void sport_done(struct sport_device *sport)
+{
+	if (sport == NULL)
+		return;
+
+	sport_stop(sport);
+	if (sport->dma_rx_desc)
+		dma_free_coherent(NULL, sport->rx_desc_bytes,
+			sport->dma_rx_desc, 0);
+	if (sport->dma_tx_desc)
+		dma_free_coherent(NULL, sport->tx_desc_bytes,
+			sport->dma_tx_desc, 0);
+
+#if L1_DATA_A_LENGTH != 0
+	l1_data_sram_free(sport->dummy_rx_desc);
+	l1_data_sram_free(sport->dummy_tx_desc);
+	l1_data_sram_free(sport->dummy_buf);
+#else
+	dma_free_coherent(NULL, 2*sizeof(struct dmasg),
+		sport->dummy_rx_desc, 0);
+	dma_free_coherent(NULL, 2*sizeof(struct dmasg),
+		sport->dummy_tx_desc, 0);
+	kfree(sport->dummy_buf);
+#endif
+	free_dma(sport->dma_rx_chan);
+	free_dma(sport->dma_tx_chan);
+	free_irq(sport->err_irq, sport);
+
+	kfree(sport);
+		sport = NULL;
+}
+EXPORT_SYMBOL(sport_done);
+/*
+* It is only used to send several bytes when dma is not enabled
+ * sport controller is configured but not enabled.
+ * Multichannel cannot works with pio mode */
+/* Used by ac97 to write and read codec register */
+int sport_send_and_recv(struct sport_device *sport, u8 *out_data, \
+		u8 *in_data, int len)
+{
+	unsigned short dma_config;
+	unsigned short status;
+	unsigned long flags;
+	unsigned long wait = 0;
+
+	pr_debug("%s enter, out_data:%p, in_data:%p len:%d\n", \
+			__func__, out_data, in_data, len);
+	pr_debug("tcr1:0x%04x, tcr2:0x%04x, tclkdiv:0x%04x, tfsdiv:0x%04x\n"
+			"mcmc1:0x%04x, mcmc2:0x%04x\n",
+			sport->regs->tcr1, sport->regs->tcr2,
+			sport->regs->tclkdiv, sport->regs->tfsdiv,
+			sport->regs->mcmc1, sport->regs->mcmc2);
+	flush_dcache_range((unsigned)out_data, (unsigned)(out_data + len));
+
+	/* Enable tx dma */
+	dma_config = (RESTART | WDSIZE_16 | DI_EN);
+	set_dma_start_addr(sport->dma_tx_chan, (unsigned long)out_data);
+	set_dma_x_count(sport->dma_tx_chan, len/2);
+	set_dma_x_modify(sport->dma_tx_chan, 2);
+	set_dma_config(sport->dma_tx_chan, dma_config);
+	enable_dma(sport->dma_tx_chan);
+
+	if (in_data != NULL) {
+		invalidate_dcache_range((unsigned)in_data, \
+				(unsigned)(in_data + len));
+		/* Enable rx dma */
+		dma_config = (RESTART | WDSIZE_16 | WNR | DI_EN);
+		set_dma_start_addr(sport->dma_rx_chan, (unsigned long)in_data);
+		set_dma_x_count(sport->dma_rx_chan, len/2);
+		set_dma_x_modify(sport->dma_rx_chan, 2);
+		set_dma_config(sport->dma_rx_chan, dma_config);
+		enable_dma(sport->dma_rx_chan);
+	}
+
+	local_irq_save(flags);
+	sport->regs->tcr1 |= TSPEN;
+	sport->regs->rcr1 |= RSPEN;
+	SSYNC();
+
+	status = get_dma_curr_irqstat(sport->dma_tx_chan);
+	while (status & DMA_RUN) {
+		udelay(1);
+		status = get_dma_curr_irqstat(sport->dma_tx_chan);
+		pr_debug("DMA status:0x%04x\n", status);
+		if (wait++ > 100)
+			goto __over;
+	}
+	status = sport->regs->stat;
+	wait = 0;
+
+	while (!(status & TXHRE)) {
+		pr_debug("sport status:0x%04x\n", status);
+		udelay(1);
+		status = *(unsigned short *)&sport->regs->stat;
+		if (wait++ > 1000)
+			goto __over;
+	}
+	/* Wait for the last byte sent out */
+	udelay(20);
+	pr_debug("sport status:0x%04x\n", status);
+
+__over:
+	sport->regs->tcr1 &= ~TSPEN;
+	sport->regs->rcr1 &= ~RSPEN;
+	SSYNC();
+	disable_dma(sport->dma_tx_chan);
+	/* Clear the status */
+	clear_dma_irqstat(sport->dma_tx_chan);
+	if (in_data != NULL) {
+		disable_dma(sport->dma_rx_chan);
+		clear_dma_irqstat(sport->dma_rx_chan);
+	}
+	SSYNC();
+	local_irq_restore(flags);
+
+	return 0;
+}
+EXPORT_SYMBOL(sport_send_and_recv);
+
+MODULE_AUTHOR("Roy Huang");
+MODULE_DESCRIPTION("SPORT driver for ADI Blackfin");
+MODULE_LICENSE("GPL");
+
diff --git a/sound/soc/blackfin/bf5xx-sport.h b/sound/soc/blackfin/bf5xx-sport.h
new file mode 100644
index 0000000..fcadcc0
--- /dev/null
+++ b/sound/soc/blackfin/bf5xx-sport.h
@@ -0,0 +1,194 @@
+/*
+ * File:         bf5xx_ac97_sport.h
+ * Based on:
+ * Author:       Roy Huang <roy.huang@analog.com>
+ *
+ * Created:
+ * Description:
+ *
+ *               Copyright 2004-2007 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.org/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+
+#ifndef __BF5XX_SPORT_H__
+#define __BF5XX_SPORT_H__
+
+#include <linux/types.h>
+#include <linux/wait.h>
+#include <linux/workqueue.h>
+#include <asm/dma.h>
+
+struct sport_register {
+	u16 tcr1;	u16 reserved0;
+	u16 tcr2;	u16 reserved1;
+	u16 tclkdiv;	u16 reserved2;
+	u16 tfsdiv;	u16 reserved3;
+	u32 tx;
+	u32 reserved_l0;
+	u32 rx;
+	u32 reserved_l1;
+	u16 rcr1;	u16 reserved4;
+	u16 rcr2;	u16 reserved5;
+	u16 rclkdiv;	u16 reserved6;
+	u16 rfsdiv;	u16 reserved7;
+	u16 stat;	u16 reserved8;
+	u16 chnl;	u16 reserved9;
+	u16 mcmc1;	u16 reserved10;
+	u16 mcmc2;	u16 reserved11;
+	u32 mtcs0;
+	u32 mtcs1;
+	u32 mtcs2;
+	u32 mtcs3;
+	u32 mrcs0;
+	u32 mrcs1;
+	u32 mrcs2;
+	u32 mrcs3;
+};
+
+#define DESC_ELEMENT_COUNT 9
+
+struct sport_device {
+	int dma_rx_chan;
+	int dma_tx_chan;
+	int err_irq;
+	struct sport_register *regs;
+
+	unsigned char *rx_buf;
+	unsigned char *tx_buf;
+	unsigned int rx_fragsize;
+	unsigned int tx_fragsize;
+	unsigned int rx_frags;
+	unsigned int tx_frags;
+	unsigned int wdsize;
+
+	/* for dummy dma transfer */
+	void *dummy_buf;
+	unsigned int dummy_count;
+
+	/* DMA descriptor ring head of current audio stream*/
+	struct dmasg *dma_rx_desc;
+	struct dmasg *dma_tx_desc;
+	unsigned int rx_desc_bytes;
+	unsigned int tx_desc_bytes;
+
+	unsigned int rx_run:1; /* rx is running */
+	unsigned int tx_run:1; /* tx is running */
+
+	struct dmasg *dummy_rx_desc;
+	struct dmasg *dummy_tx_desc;
+
+	struct dmasg *curr_rx_desc;
+	struct dmasg *curr_tx_desc;
+
+	int rx_curr_frag;
+	int tx_curr_frag;
+
+	unsigned int rcr1;
+	unsigned int rcr2;
+	int rx_tdm_count;
+
+	unsigned int tcr1;
+	unsigned int tcr2;
+	int tx_tdm_count;
+
+	void (*rx_callback)(void *data);
+	void *rx_data;
+	void (*tx_callback)(void *data);
+	void *tx_data;
+	void (*err_callback)(void *data);
+	void *err_data;
+	unsigned char *tx_dma_buf;
+	unsigned char *rx_dma_buf;
+#ifdef CONFIG_SND_MMAP_SUPPORT
+	dma_addr_t tx_dma_phy;
+	dma_addr_t rx_dma_phy;
+	int tx_pos;/*pcm sample count*/
+	int rx_pos;
+	unsigned int tx_buffer_size;
+	unsigned int rx_buffer_size;
+	int tx_delay_pos;
+	int once;
+#endif
+	void *private_data;
+};
+
+extern struct sport_device *sport_handle;
+
+struct sport_param {
+	int dma_rx_chan;
+	int dma_tx_chan;
+	int err_irq;
+	struct sport_register *regs;
+};
+
+struct sport_device *sport_init(struct sport_param *param, unsigned wdsize,
+		unsigned dummy_count, void *private_data);
+
+void sport_done(struct sport_device *sport);
+
+/* first use these ...*/
+
+/* note: multichannel is in units of 8 channels, tdm_count is number of channels
+ *  NOT / 8 ! all channels are enabled by default */
+int sport_set_multichannel(struct sport_device *sport, int tdm_count,
+		u32 mask, int packed);
+
+int sport_config_rx(struct sport_device *sport,
+		unsigned int rcr1, unsigned int rcr2,
+		unsigned int clkdiv, unsigned int fsdiv);
+
+int sport_config_tx(struct sport_device *sport,
+		unsigned int tcr1, unsigned int tcr2,
+		unsigned int clkdiv, unsigned int fsdiv);
+
+/* ... then these: */
+
+/* buffer size (in bytes) == fragcount * fragsize_bytes */
+
+/* this is not a very general api, it sets the dma to 2d autobuffer mode */
+
+int sport_config_rx_dma(struct sport_device *sport, void *buf,
+		int fragcount, size_t fragsize_bytes);
+
+int sport_config_tx_dma(struct sport_device *sport, void *buf,
+		int fragcount, size_t fragsize_bytes);
+
+int sport_tx_start(struct sport_device *sport);
+int sport_tx_stop(struct sport_device *sport);
+int sport_rx_start(struct sport_device *sport);
+int sport_rx_stop(struct sport_device *sport);
+
+/* for use in interrupt handler */
+unsigned long sport_curr_offset_rx(struct sport_device *sport);
+unsigned long sport_curr_offset_tx(struct sport_device *sport);
+
+void sport_incfrag(struct sport_device *sport, int *frag, int tx);
+void sport_decfrag(struct sport_device *sport, int *frag, int tx);
+
+int sport_set_rx_callback(struct sport_device *sport,
+		       void (*rx_callback)(void *), void *rx_data);
+int sport_set_tx_callback(struct sport_device *sport,
+		       void (*tx_callback)(void *), void *tx_data);
+int sport_set_err_callback(struct sport_device *sport,
+		       void (*err_callback)(void *), void *err_data);
+
+int sport_send_and_recv(struct sport_device *sport, u8 *out_data, \
+		u8 *in_data, int len);
+#endif /* BF53X_SPORT_H */
diff --git a/sound/soc/blackfin/bf5xx-ssm2602.c b/sound/soc/blackfin/bf5xx-ssm2602.c
new file mode 100644
index 0000000..e15f67f
--- /dev/null
+++ b/sound/soc/blackfin/bf5xx-ssm2602.c
@@ -0,0 +1,186 @@
+/*
+ * File:         sound/soc/blackfin/bf5xx-ssm2602.c
+ * Author:       Cliff Cai <Cliff.Cai@analog.com>
+ *
+ * Created:      Tue June 06 2008
+ * Description:  board driver for SSM2602 sound chip
+ *
+ * Modified:
+ *               Copyright 2008 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.org/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/device.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/pcm_params.h>
+
+#include <asm/dma.h>
+#include <asm/portmux.h>
+#include <linux/gpio.h>
+#include "../codecs/ssm2602.h"
+#include "bf5xx-sport.h"
+#include "bf5xx-i2s-pcm.h"
+#include "bf5xx-i2s.h"
+
+static struct snd_soc_machine bf5xx_ssm2602;
+
+static int bf5xx_ssm2602_startup(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+
+	pr_debug("%s enter\n", __func__);
+	cpu_dai->private_data = sport_handle;
+	return 0;
+}
+
+static int bf5xx_ssm2602_hw_params(struct snd_pcm_substream *substream,
+	struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
+	struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+	unsigned int clk = 0;
+	int ret = 0;
+
+	pr_debug("%s rate %d format %x\n", __func__, params_rate(params),
+		params_format(params));
+	/*
+	 * If you are using a crystal source which frequency is not 12MHz
+	 * then modify the below case statement with frequency of the crystal.
+	 *
+	 * If you are using the SPORT to generate clocking then this is
+	 * where to do it.
+	 */
+
+	switch (params_rate(params)) {
+	case 8000:
+	case 16000:
+	case 48000:
+	case 96000:
+	case 11025:
+	case 22050:
+	case 44100:
+		clk = 12000000;
+		break;
+	}
+
+	/*
+	 * CODEC is master for BCLK and LRC in this configuration.
+	 */
+
+	/* set codec DAI configuration */
+	ret = codec_dai->dai_ops.set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
+		SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
+	if (ret < 0)
+		return ret;
+	/* set cpu DAI configuration */
+	ret = cpu_dai->dai_ops.set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
+		SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
+	if (ret < 0)
+		return ret;
+
+	ret = codec_dai->dai_ops.set_sysclk(codec_dai, SSM2602_SYSCLK, clk,
+		SND_SOC_CLOCK_IN);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static struct snd_soc_ops bf5xx_ssm2602_ops = {
+	.startup = bf5xx_ssm2602_startup,
+	.hw_params = bf5xx_ssm2602_hw_params,
+};
+
+static struct snd_soc_dai_link bf5xx_ssm2602_dai = {
+	.name = "ssm2602",
+	.stream_name = "SSM2602",
+	.cpu_dai = &bf5xx_i2s_dai,
+	.codec_dai = &ssm2602_dai,
+	.ops = &bf5xx_ssm2602_ops,
+};
+
+/*
+ * SSM2602 2 wire address is determined by CSB
+ * state during powerup.
+ *    low  = 0x1a
+ *    high = 0x1b
+ */
+
+static struct ssm2602_setup_data bf5xx_ssm2602_setup = {
+	.i2c_bus = 0,
+	.i2c_address = 0x1b,
+};
+
+static struct snd_soc_machine bf5xx_ssm2602 = {
+	.name = "bf5xx_ssm2602",
+	.dai_link = &bf5xx_ssm2602_dai,
+	.num_links = 1,
+};
+
+static struct snd_soc_device bf5xx_ssm2602_snd_devdata = {
+	.machine = &bf5xx_ssm2602,
+	.platform = &bf5xx_i2s_soc_platform,
+	.codec_dev = &soc_codec_dev_ssm2602,
+	.codec_data = &bf5xx_ssm2602_setup,
+};
+
+static struct platform_device *bf52x_ssm2602_snd_device;
+
+static int __init bf5xx_ssm2602_init(void)
+{
+	int ret;
+
+	pr_debug("%s enter\n", __func__);
+	bf52x_ssm2602_snd_device = platform_device_alloc("soc-audio", -1);
+	if (!bf52x_ssm2602_snd_device)
+		return -ENOMEM;
+
+	platform_set_drvdata(bf52x_ssm2602_snd_device,
+				&bf5xx_ssm2602_snd_devdata);
+	bf5xx_ssm2602_snd_devdata.dev = &bf52x_ssm2602_snd_device->dev;
+	ret = platform_device_add(bf52x_ssm2602_snd_device);
+
+	if (ret)
+		platform_device_put(bf52x_ssm2602_snd_device);
+
+	return ret;
+}
+
+static void __exit bf5xx_ssm2602_exit(void)
+{
+	pr_debug("%s enter\n", __func__);
+	platform_device_unregister(bf52x_ssm2602_snd_device);
+}
+
+module_init(bf5xx_ssm2602_init);
+module_exit(bf5xx_ssm2602_exit);
+
+/* Module information */
+MODULE_AUTHOR("Cliff Cai");
+MODULE_DESCRIPTION("ALSA SoC SSM2602 BF527-EZKIT");
+MODULE_LICENSE("GPL");
+
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 1db04a2..4975d85 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -1,34 +1,47 @@
+config SND_SOC_ALL_CODECS
+	tristate "Build all ASoC CODEC drivers"
+	depends on I2C
+	select SPI
+	select SPI_MASTER
+	select SND_SOC_AD73311
+	select SND_SOC_AK4535
+	select SND_SOC_CS4270
+	select SND_SOC_SSM2602
+	select SND_SOC_TLV320AIC23
+	select SND_SOC_TLV320AIC26
+	select SND_SOC_TLV320AIC3X
+	select SND_SOC_UDA1380
+	select SND_SOC_WM8510
+	select SND_SOC_WM8580
+	select SND_SOC_WM8731
+	select SND_SOC_WM8750
+	select SND_SOC_WM8753
+	select SND_SOC_WM8900
+	select SND_SOC_WM8903
+	select SND_SOC_WM8971
+	select SND_SOC_WM8990
+        help
+          Normally ASoC codec drivers are only built if a machine driver which
+          uses them is also built since they are only usable with a machine
+          driver.  Selecting this option will allow these drivers to be built
+          without an explicit machine driver for test and development purposes.
+
+          If unsure select "N".
+
+
 config SND_SOC_AC97_CODEC
 	tristate
 	select SND_AC97_CODEC
 
+config SND_SOC_AD1980
+	tristate
+
+config SND_SOC_AD73311
+	tristate
+
 config SND_SOC_AK4535
 	tristate
 
-config SND_SOC_UDA1380
-        tristate
-
-config SND_SOC_WM8510
-	tristate
-
-config SND_SOC_WM8731
-	tristate
-
-config SND_SOC_WM8750
-	tristate
-
-config SND_SOC_WM8753
-	tristate
-
-config SND_SOC_WM8990
-	tristate
-
-config SND_SOC_WM9712
-	tristate
-
-config SND_SOC_WM9713
-	tristate
-
 # Cirrus Logic CS4270 Codec
 config SND_SOC_CS4270
 	tristate
@@ -47,6 +60,53 @@
 	bool
 	depends on SND_SOC_CS4270
 
+config SND_SOC_SSM2602
+	tristate
+
+config SND_SOC_TLV320AIC23
+	tristate
+	depends on I2C
+
+config SND_SOC_TLV320AIC26
+	tristate "TI TLV320AIC26 Codec support"
+	depends on SPI
+
 config SND_SOC_TLV320AIC3X
 	tristate
 	depends on I2C
+
+config SND_SOC_UDA1380
+        tristate
+
+config SND_SOC_WM8510
+	tristate
+
+config SND_SOC_WM8580
+	tristate
+
+config SND_SOC_WM8731
+	tristate
+
+config SND_SOC_WM8750
+	tristate
+
+config SND_SOC_WM8753
+	tristate
+
+config SND_SOC_WM8900
+	tristate
+
+config SND_SOC_WM8903
+	tristate
+
+config SND_SOC_WM8971
+	tristate
+
+config SND_SOC_WM8990
+	tristate
+
+config SND_SOC_WM9712
+	tristate
+
+config SND_SOC_WM9713
+	tristate
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index d7b97ab..90f0a58 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -1,25 +1,43 @@
 snd-soc-ac97-objs := ac97.o
+snd-soc-ad1980-objs := ad1980.o
+snd-soc-ad73311-objs := ad73311.o
 snd-soc-ak4535-objs := ak4535.o
+snd-soc-cs4270-objs := cs4270.o
+snd-soc-ssm2602-objs := ssm2602.o
+snd-soc-tlv320aic23-objs := tlv320aic23.o
+snd-soc-tlv320aic26-objs := tlv320aic26.o
+snd-soc-tlv320aic3x-objs := tlv320aic3x.o
 snd-soc-uda1380-objs := uda1380.o
 snd-soc-wm8510-objs := wm8510.o
+snd-soc-wm8580-objs := wm8580.o
 snd-soc-wm8731-objs := wm8731.o
 snd-soc-wm8750-objs := wm8750.o
 snd-soc-wm8753-objs := wm8753.o
+snd-soc-wm8900-objs := wm8900.o
+snd-soc-wm8903-objs := wm8903.o
+snd-soc-wm8971-objs := wm8971.o
 snd-soc-wm8990-objs := wm8990.o
 snd-soc-wm9712-objs := wm9712.o
 snd-soc-wm9713-objs := wm9713.o
-snd-soc-cs4270-objs := cs4270.o
-snd-soc-tlv320aic3x-objs := tlv320aic3x.o
 
 obj-$(CONFIG_SND_SOC_AC97_CODEC)	+= snd-soc-ac97.o
+obj-$(CONFIG_SND_SOC_AD1980)	+= snd-soc-ad1980.o
+obj-$(CONFIG_SND_SOC_AD73311) += snd-soc-ad73311.o
 obj-$(CONFIG_SND_SOC_AK4535)	+= snd-soc-ak4535.o
+obj-$(CONFIG_SND_SOC_CS4270)	+= snd-soc-cs4270.o
+obj-$(CONFIG_SND_SOC_SSM2602)	+= snd-soc-ssm2602.o
+obj-$(CONFIG_SND_SOC_TLV320AIC23)	+= snd-soc-tlv320aic23.o
+obj-$(CONFIG_SND_SOC_TLV320AIC26)	+= snd-soc-tlv320aic26.o
+obj-$(CONFIG_SND_SOC_TLV320AIC3X)	+= snd-soc-tlv320aic3x.o
 obj-$(CONFIG_SND_SOC_UDA1380)	+= snd-soc-uda1380.o
 obj-$(CONFIG_SND_SOC_WM8510)	+= snd-soc-wm8510.o
+obj-$(CONFIG_SND_SOC_WM8580)	+= snd-soc-wm8580.o
 obj-$(CONFIG_SND_SOC_WM8731)	+= snd-soc-wm8731.o
 obj-$(CONFIG_SND_SOC_WM8750)	+= snd-soc-wm8750.o
 obj-$(CONFIG_SND_SOC_WM8753)	+= snd-soc-wm8753.o
+obj-$(CONFIG_SND_SOC_WM8900)	+= snd-soc-wm8900.o
+obj-$(CONFIG_SND_SOC_WM8903)	+= snd-soc-wm8903.o
+obj-$(CONFIG_SND_SOC_WM8971)	+= snd-soc-wm8971.o
 obj-$(CONFIG_SND_SOC_WM8990)	+= snd-soc-wm8990.o
 obj-$(CONFIG_SND_SOC_WM9712)	+= snd-soc-wm9712.o
 obj-$(CONFIG_SND_SOC_WM9713)	+= snd-soc-wm9713.o
-obj-$(CONFIG_SND_SOC_CS4270)	+= snd-soc-cs4270.o
-obj-$(CONFIG_SND_SOC_TLV320AIC3X)	+= snd-soc-tlv320aic3x.o
diff --git a/sound/soc/codecs/ac97.c b/sound/soc/codecs/ac97.c
index 61fd96c..bd1ebdc 100644
--- a/sound/soc/codecs/ac97.c
+++ b/sound/soc/codecs/ac97.c
@@ -2,8 +2,7 @@
  * ac97.c  --  ALSA Soc AC97 codec support
  *
  * Copyright 2005 Wolfson Microelectronics PLC.
- * Author: Liam Girdwood
- *         liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com
+ * Author: Liam Girdwood <lrg@slimlogic.co.uk>
  *
  *  This program is free software; you can redistribute  it and/or modify it
  *  under  the terms of  the GNU General  Public License as published by the
diff --git a/sound/soc/codecs/ad1980.c b/sound/soc/codecs/ad1980.c
new file mode 100644
index 0000000..1397b8e
--- /dev/null
+++ b/sound/soc/codecs/ad1980.c
@@ -0,0 +1,308 @@
+/*
+ * ad1980.c  --  ALSA Soc AD1980 codec support
+ *
+ * Copyright:	Analog Device Inc.
+ * Author:	Roy Huang <roy.huang@analog.com>
+ * 		Cliff Cai <cliff.cai@analog.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/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/ac97_codec.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+
+#include "ad1980.h"
+
+static unsigned int ac97_read(struct snd_soc_codec *codec,
+	unsigned int reg);
+static int ac97_write(struct snd_soc_codec *codec,
+	unsigned int reg, unsigned int val);
+
+/*
+ * AD1980 register cache
+ */
+static const u16 ad1980_reg[] = {
+	0x0090, 0x8000, 0x8000, 0x8000, /* 0 - 6  */
+	0x0000, 0x0000, 0x8008, 0x8008, /* 8 - e  */
+	0x8808, 0x8808, 0x0000, 0x8808, /* 10 - 16 */
+	0x8808, 0x0000, 0x8000, 0x0000, /* 18 - 1e */
+	0x0000, 0x0000, 0x0000, 0x0000, /* 20 - 26 */
+	0x03c7, 0x0000, 0xbb80, 0xbb80, /* 28 - 2e */
+	0xbb80, 0xbb80, 0x0000, 0x8080, /* 30 - 36 */
+	0x8080, 0x2000, 0x0000, 0x0000, /* 38 - 3e */
+	0x0000, 0x0000, 0x0000, 0x0000, /* reserved */
+	0x0000, 0x0000, 0x0000, 0x0000, /* reserved */
+	0x0000, 0x0000, 0x0000, 0x0000, /* reserved */
+	0x0000, 0x0000, 0x0000, 0x0000, /* reserved */
+	0x8080, 0x0000, 0x0000, 0x0000, /* 60 - 66 */
+	0x0000, 0x0000, 0x0000, 0x0000, /* reserved */
+	0x0000, 0x0000, 0x1001, 0x0000, /* 70 - 76 */
+	0x0000, 0x0000, 0x4144, 0x5370  /* 78 - 7e */
+};
+
+static const char *ad1980_rec_sel[] = {"Mic", "CD", "NC", "AUX", "Line",
+		"Stereo Mix", "Mono Mix", "Phone"};
+
+static const struct soc_enum ad1980_cap_src =
+	SOC_ENUM_DOUBLE(AC97_REC_SEL, 8, 0, 7, ad1980_rec_sel);
+
+static const struct snd_kcontrol_new ad1980_snd_ac97_controls[] = {
+SOC_DOUBLE("Master Playback Volume", AC97_MASTER, 8, 0, 31, 1),
+SOC_SINGLE("Master Playback Switch", AC97_MASTER, 15, 1, 1),
+
+SOC_DOUBLE("Headphone Playback Volume", AC97_HEADPHONE, 8, 0, 31, 1),
+SOC_SINGLE("Headphone Playback Switch", AC97_HEADPHONE, 15, 1, 1),
+
+SOC_DOUBLE("PCM Playback Volume", AC97_PCM, 8, 0, 31, 1),
+SOC_SINGLE("PCM Playback Switch", AC97_PCM, 15, 1, 1),
+
+SOC_DOUBLE("PCM Capture Volume", AC97_REC_GAIN, 8, 0, 31, 0),
+SOC_SINGLE("PCM Capture Switch", AC97_REC_GAIN, 15, 1, 1),
+
+SOC_SINGLE("Mono Playback Volume", AC97_MASTER_MONO, 0, 31, 1),
+SOC_SINGLE("Mono Playback Switch", AC97_MASTER_MONO, 15, 1, 1),
+
+SOC_SINGLE("Phone Capture Volume", AC97_PHONE, 0, 31, 1),
+SOC_SINGLE("Phone Capture Switch", AC97_PHONE, 15, 1, 1),
+
+SOC_SINGLE("Mic Volume", AC97_MIC, 0, 31, 1),
+SOC_SINGLE("Mic Switch", AC97_MIC, 15, 1, 1),
+
+SOC_SINGLE("Stereo Mic Switch", AC97_AD_MISC, 6, 1, 0),
+SOC_DOUBLE("Line HP Swap Switch", AC97_AD_MISC, 10, 5, 1, 0),
+
+SOC_DOUBLE("Surround Playback Volume", AC97_SURROUND_MASTER, 8, 0, 31, 1),
+SOC_DOUBLE("Surround Playback Switch", AC97_SURROUND_MASTER, 15, 7, 1, 1),
+
+SOC_ENUM("Capture Source", ad1980_cap_src),
+
+SOC_SINGLE("Mic Boost Switch", AC97_MIC, 6, 1, 0),
+};
+
+/* add non dapm controls */
+static int ad1980_add_controls(struct snd_soc_codec *codec)
+{
+	int err, i;
+
+	for (i = 0; i < ARRAY_SIZE(ad1980_snd_ac97_controls); i++) {
+		err = snd_ctl_add(codec->card, snd_soc_cnew(
+				&ad1980_snd_ac97_controls[i], codec, NULL));
+		if (err < 0)
+			return err;
+	}
+	return 0;
+}
+
+static unsigned int ac97_read(struct snd_soc_codec *codec,
+	unsigned int reg)
+{
+	u16 *cache = codec->reg_cache;
+
+	switch (reg) {
+	case AC97_RESET:
+	case AC97_INT_PAGING:
+	case AC97_POWERDOWN:
+	case AC97_EXTENDED_STATUS:
+	case AC97_VENDOR_ID1:
+	case AC97_VENDOR_ID2:
+		return soc_ac97_ops.read(codec->ac97, reg);
+	default:
+		reg = reg >> 1;
+
+		if (reg >= (ARRAY_SIZE(ad1980_reg)))
+			return -EINVAL;
+
+		return cache[reg];
+	}
+}
+
+static int ac97_write(struct snd_soc_codec *codec, unsigned int reg,
+	unsigned int val)
+{
+	u16 *cache = codec->reg_cache;
+
+	soc_ac97_ops.write(codec->ac97, reg, val);
+	reg = reg >> 1;
+	if (reg < (ARRAY_SIZE(ad1980_reg)))
+		cache[reg] = val;
+
+	return 0;
+}
+
+struct snd_soc_dai ad1980_dai = {
+	.name = "AC97",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = SNDRV_PCM_RATE_48000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE, },
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = SNDRV_PCM_RATE_48000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE, },
+};
+EXPORT_SYMBOL_GPL(ad1980_dai);
+
+static int ad1980_reset(struct snd_soc_codec *codec, int try_warm)
+{
+	u16 retry_cnt = 0;
+
+retry:
+	if (try_warm && soc_ac97_ops.warm_reset) {
+		soc_ac97_ops.warm_reset(codec->ac97);
+		if (ac97_read(codec, AC97_RESET) == 0x0090)
+			return 1;
+	}
+
+	soc_ac97_ops.reset(codec->ac97);
+	/* Set bit 16slot in register 74h, then every slot will has only 16
+	 * bits. This command is sent out in 20bit mode, in which case the
+	 * first nibble of data is eaten by the addr. (Tag is always 16 bit)*/
+	ac97_write(codec, AC97_AD_SERIAL_CFG, 0x9900);
+
+	if (ac97_read(codec, AC97_RESET)  != 0x0090)
+		goto err;
+	return 0;
+
+err:
+	while (retry_cnt++ < 10)
+		goto retry;
+
+	printk(KERN_ERR "AD1980 AC97 reset failed\n");
+	return -EIO;
+}
+
+static int ad1980_soc_probe(struct platform_device *pdev)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	struct snd_soc_codec *codec;
+	int ret = 0;
+	u16 vendor_id2;
+
+	printk(KERN_INFO "AD1980 SoC Audio Codec\n");
+
+	socdev->codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
+	if (socdev->codec == NULL)
+		return -ENOMEM;
+	codec = socdev->codec;
+	mutex_init(&codec->mutex);
+
+	codec->reg_cache =
+		kzalloc(sizeof(u16) * ARRAY_SIZE(ad1980_reg), GFP_KERNEL);
+	if (codec->reg_cache == NULL) {
+		ret = -ENOMEM;
+		goto cache_err;
+	}
+	memcpy(codec->reg_cache, ad1980_reg, sizeof(u16) * \
+			ARRAY_SIZE(ad1980_reg));
+	codec->reg_cache_size = sizeof(u16) * ARRAY_SIZE(ad1980_reg);
+	codec->reg_cache_step = 2;
+	codec->name = "AD1980";
+	codec->owner = THIS_MODULE;
+	codec->dai = &ad1980_dai;
+	codec->num_dai = 1;
+	codec->write = ac97_write;
+	codec->read = ac97_read;
+	INIT_LIST_HEAD(&codec->dapm_widgets);
+	INIT_LIST_HEAD(&codec->dapm_paths);
+
+	ret = snd_soc_new_ac97_codec(codec, &soc_ac97_ops, 0);
+	if (ret < 0) {
+		printk(KERN_ERR "ad1980: failed to register AC97 codec\n");
+		goto codec_err;
+	}
+
+	/* register pcms */
+	ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
+	if (ret < 0)
+		goto pcm_err;
+
+
+	ret = ad1980_reset(codec, 0);
+	if (ret < 0) {
+		printk(KERN_ERR "AC97 link error\n");
+		goto reset_err;
+	}
+
+	/* Read out vendor ID to make sure it is ad1980 */
+	if (ac97_read(codec, AC97_VENDOR_ID1) != 0x4144)
+		goto reset_err;
+
+	vendor_id2 = ac97_read(codec, AC97_VENDOR_ID2);
+
+	if (vendor_id2 != 0x5370) {
+		if (vendor_id2 != 0x5374)
+			goto reset_err;
+		else
+			printk(KERN_WARNING "ad1980: "
+				"Found AD1981 - only 2/2 IN/OUT Channels "
+				"supported\n");
+	}
+
+	ac97_write(codec, AC97_MASTER, 0x0000); /* unmute line out volume */
+	ac97_write(codec, AC97_PCM, 0x0000);	/* unmute PCM out volume */
+	ac97_write(codec, AC97_REC_GAIN, 0x0000);/* unmute record volume */
+
+	ad1980_add_controls(codec);
+	ret = snd_soc_register_card(socdev);
+	if (ret < 0) {
+		printk(KERN_ERR "ad1980: failed to register card\n");
+		goto reset_err;
+	}
+
+	return 0;
+
+reset_err:
+	snd_soc_free_pcms(socdev);
+
+pcm_err:
+	snd_soc_free_ac97_codec(codec);
+
+codec_err:
+	kfree(codec->reg_cache);
+
+cache_err:
+	kfree(socdev->codec);
+	socdev->codec = NULL;
+	return ret;
+}
+
+static int ad1980_soc_remove(struct platform_device *pdev)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	struct snd_soc_codec *codec = socdev->codec;
+
+	if (codec == NULL)
+		return 0;
+
+	snd_soc_dapm_free(socdev);
+	snd_soc_free_pcms(socdev);
+	snd_soc_free_ac97_codec(codec);
+	kfree(codec->reg_cache);
+	kfree(codec);
+	return 0;
+}
+
+struct snd_soc_codec_device soc_codec_dev_ad1980 = {
+	.probe = 	ad1980_soc_probe,
+	.remove = 	ad1980_soc_remove,
+};
+EXPORT_SYMBOL_GPL(soc_codec_dev_ad1980);
+
+MODULE_DESCRIPTION("ASoC ad1980 driver");
+MODULE_AUTHOR("Roy Huang, Cliff Cai");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/ad1980.h b/sound/soc/codecs/ad1980.h
new file mode 100644
index 0000000..db6c850
--- /dev/null
+++ b/sound/soc/codecs/ad1980.h
@@ -0,0 +1,23 @@
+/*
+ * ad1980.h  --  ad1980 Soc Audio driver
+ */
+
+#ifndef _AD1980_H
+#define _AD1980_H
+/* Bit definition of Power-Down Control/Status Register */
+#define ADC		0x0001
+#define DAC		0x0002
+#define ANL		0x0004
+#define REF		0x0008
+#define PR0		0x0100
+#define PR1		0x0200
+#define PR2		0x0400
+#define PR3		0x0800
+#define PR4		0x1000
+#define PR5		0x2000
+#define PR6		0x4000
+
+extern struct snd_soc_dai ad1980_dai;
+extern struct snd_soc_codec_device soc_codec_dev_ad1980;
+
+#endif
diff --git a/sound/soc/codecs/ad73311.c b/sound/soc/codecs/ad73311.c
new file mode 100644
index 0000000..37af860
--- /dev/null
+++ b/sound/soc/codecs/ad73311.c
@@ -0,0 +1,107 @@
+/*
+ * ad73311.c  --  ALSA Soc AD73311 codec support
+ *
+ * Copyright:	Analog Device Inc.
+ * Author:	Cliff Cai <cliff.cai@analog.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.
+ *
+ *  Revision history
+ *    25th Sep 2008   Initial version.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/ac97_codec.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+
+#include "ad73311.h"
+
+struct snd_soc_dai ad73311_dai = {
+	.name = "AD73311",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 1,
+		.channels_max = 1,
+		.rates = SNDRV_PCM_RATE_8000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE, },
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 1,
+		.channels_max = 1,
+		.rates = SNDRV_PCM_RATE_8000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE, },
+};
+EXPORT_SYMBOL_GPL(ad73311_dai);
+
+static int ad73311_soc_probe(struct platform_device *pdev)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	struct snd_soc_codec *codec;
+	int ret = 0;
+
+	codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
+	if (codec == NULL)
+		return -ENOMEM;
+	mutex_init(&codec->mutex);
+	codec->name = "AD73311";
+	codec->owner = THIS_MODULE;
+	codec->dai = &ad73311_dai;
+	codec->num_dai = 1;
+	socdev->codec = codec;
+	INIT_LIST_HEAD(&codec->dapm_widgets);
+	INIT_LIST_HEAD(&codec->dapm_paths);
+
+	/* register pcms */
+	ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
+	if (ret < 0) {
+		printk(KERN_ERR "ad73311: failed to create pcms\n");
+		goto pcm_err;
+	}
+
+	ret = snd_soc_register_card(socdev);
+	if (ret < 0) {
+		printk(KERN_ERR "ad73311: failed to register card\n");
+		goto register_err;
+	}
+
+	return ret;
+
+register_err:
+	snd_soc_free_pcms(socdev);
+pcm_err:
+	kfree(socdev->codec);
+	socdev->codec = NULL;
+	return ret;
+}
+
+static int ad73311_soc_remove(struct platform_device *pdev)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	struct snd_soc_codec *codec = socdev->codec;
+
+	if (codec == NULL)
+		return 0;
+	snd_soc_free_pcms(socdev);
+	kfree(codec);
+	return 0;
+}
+
+struct snd_soc_codec_device soc_codec_dev_ad73311 = {
+	.probe = 	ad73311_soc_probe,
+	.remove = 	ad73311_soc_remove,
+};
+EXPORT_SYMBOL_GPL(soc_codec_dev_ad73311);
+
+MODULE_DESCRIPTION("ASoC ad73311 driver");
+MODULE_AUTHOR("Cliff Cai ");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/ad73311.h b/sound/soc/codecs/ad73311.h
new file mode 100644
index 0000000..507ce0c
--- /dev/null
+++ b/sound/soc/codecs/ad73311.h
@@ -0,0 +1,90 @@
+/*
+ * File:         sound/soc/codec/ad73311.h
+ * Based on:
+ * Author:       Cliff Cai <cliff.cai@analog.com>
+ *
+ * Created:      Thur Sep 25, 2008
+ * Description:  definitions for AD73311 registers
+ *
+ *
+ * Modified:
+ *               Copyright 2006 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.org/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifndef __AD73311_H__
+#define __AD73311_H__
+
+#define AD_CONTROL	0x8000
+#define AD_DATA		0x0000
+#define AD_READ		0x4000
+#define AD_WRITE	0x0000
+
+/* Control register A */
+#define CTRL_REG_A	(0 << 8)
+
+#define REGA_MODE_PRO	0x00
+#define REGA_MODE_DATA	0x01
+#define REGA_MODE_MIXED	0x03
+#define REGA_DLB		0x04
+#define REGA_SLB		0x08
+#define REGA_DEVC(x)		((x & 0x7) << 4)
+#define REGA_RESET		0x80
+
+/* Control register B */
+#define CTRL_REG_B	(1 << 8)
+
+#define REGB_DIRATE(x)	(x & 0x3)
+#define REGB_SCDIV(x)	((x & 0x3) << 2)
+#define REGB_MCDIV(x)	((x & 0x7) << 4)
+#define REGB_CEE		(1 << 7)
+
+/* Control register C */
+#define CTRL_REG_C	(2 << 8)
+
+#define REGC_PUDEV		(1 << 0)
+#define REGC_PUADC		(1 << 3)
+#define REGC_PUDAC		(1 << 4)
+#define REGC_PUREF		(1 << 5)
+#define REGC_REFUSE		(1 << 6)
+
+/* Control register D */
+#define CTRL_REG_D	(3 << 8)
+
+#define REGD_IGS(x)		(x & 0x7)
+#define REGD_RMOD		(1 << 3)
+#define REGD_OGS(x)		((x & 0x7) << 4)
+#define REGD_MUTE		(x << 7)
+
+/* Control register E */
+#define CTRL_REG_E	(4 << 8)
+
+#define REGE_DA(x)		(x & 0x1f)
+#define REGE_IBYP		(1 << 5)
+
+/* Control register F */
+#define CTRL_REG_F	(5 << 8)
+
+#define REGF_SEEN		(1 << 5)
+#define REGF_INV		(1 << 6)
+#define REGF_ALB		(1 << 7)
+
+extern struct snd_soc_dai ad73311_dai;
+extern struct snd_soc_codec_device soc_codec_dev_ad73311;
+#endif
diff --git a/sound/soc/codecs/ak4535.c b/sound/soc/codecs/ak4535.c
index 7da9f467..2a89b58 100644
--- a/sound/soc/codecs/ak4535.c
+++ b/sound/soc/codecs/ak4535.c
@@ -28,7 +28,6 @@
 
 #include "ak4535.h"
 
-#define AUDIO_NAME "ak4535"
 #define AK4535_VERSION "0.3"
 
 struct snd_soc_codec_device soc_codec_dev_ak4535;
@@ -535,87 +534,85 @@
 
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
 
-#define I2C_DRIVERID_AK4535 0xfefe /* liam -  need a proper id */
-
-static unsigned short normal_i2c[] = { 0, I2C_CLIENT_END };
-
-/* Magic definition of all other variables and things */
-I2C_CLIENT_INSMOD;
-
-static struct i2c_driver ak4535_i2c_driver;
-static struct i2c_client client_template;
-
-/* If the i2c layer weren't so broken, we could pass this kind of data
-   around */
-static int ak4535_codec_probe(struct i2c_adapter *adap, int addr, int kind)
+static int ak4535_i2c_probe(struct i2c_client *i2c,
+			    const struct i2c_device_id *id)
 {
 	struct snd_soc_device *socdev = ak4535_socdev;
-	struct ak4535_setup_data *setup = socdev->codec_data;
 	struct snd_soc_codec *codec = socdev->codec;
-	struct i2c_client *i2c;
 	int ret;
 
-	if (addr != setup->i2c_address)
-		return -ENODEV;
-
-	client_template.adapter = adap;
-	client_template.addr = addr;
-
-	i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL);
-	if (i2c == NULL)
-		return -ENOMEM;
-
 	i2c_set_clientdata(i2c, codec);
 	codec->control_data = i2c;
 
-	ret = i2c_attach_client(i2c);
-	if (ret < 0) {
-		printk(KERN_ERR "failed to attach codec at addr %x\n", addr);
-		goto err;
-	}
-
 	ret = ak4535_init(socdev);
-	if (ret < 0) {
+	if (ret < 0)
 		printk(KERN_ERR "failed to initialise AK4535\n");
-		goto err;
-	}
-	return ret;
 
-err:
-	kfree(i2c);
 	return ret;
 }
 
-static int ak4535_i2c_detach(struct i2c_client *client)
+static int ak4535_i2c_remove(struct i2c_client *client)
 {
 	struct snd_soc_codec *codec = i2c_get_clientdata(client);
-	i2c_detach_client(client);
 	kfree(codec->reg_cache);
-	kfree(client);
 	return 0;
 }
 
-static int ak4535_i2c_attach(struct i2c_adapter *adap)
-{
-	return i2c_probe(adap, &addr_data, ak4535_codec_probe);
-}
+static const struct i2c_device_id ak4535_i2c_id[] = {
+	{ "ak4535", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, ak4535_i2c_id);
 
-/* corgi i2c codec control layer */
 static struct i2c_driver ak4535_i2c_driver = {
 	.driver = {
 		.name = "AK4535 I2C Codec",
 		.owner = THIS_MODULE,
 	},
-	.id =             I2C_DRIVERID_AK4535,
-	.attach_adapter = ak4535_i2c_attach,
-	.detach_client =  ak4535_i2c_detach,
-	.command =        NULL,
+	.probe =    ak4535_i2c_probe,
+	.remove =   ak4535_i2c_remove,
+	.id_table = ak4535_i2c_id,
 };
 
-static struct i2c_client client_template = {
-	.name =   "AK4535",
-	.driver = &ak4535_i2c_driver,
-};
+static int ak4535_add_i2c_device(struct platform_device *pdev,
+				 const struct ak4535_setup_data *setup)
+{
+	struct i2c_board_info info;
+	struct i2c_adapter *adapter;
+	struct i2c_client *client;
+	int ret;
+
+	ret = i2c_add_driver(&ak4535_i2c_driver);
+	if (ret != 0) {
+		dev_err(&pdev->dev, "can't add i2c driver\n");
+		return ret;
+	}
+
+	memset(&info, 0, sizeof(struct i2c_board_info));
+	info.addr = setup->i2c_address;
+	strlcpy(info.type, "ak4535", I2C_NAME_SIZE);
+
+	adapter = i2c_get_adapter(setup->i2c_bus);
+	if (!adapter) {
+		dev_err(&pdev->dev, "can't get i2c adapter %d\n",
+			setup->i2c_bus);
+		goto err_driver;
+	}
+
+	client = i2c_new_device(adapter, &info);
+	i2c_put_adapter(adapter);
+	if (!client) {
+		dev_err(&pdev->dev, "can't add i2c device at 0x%x\n",
+			(unsigned int)info.addr);
+		goto err_driver;
+	}
+
+	return 0;
+
+err_driver:
+	i2c_del_driver(&ak4535_i2c_driver);
+	return -ENODEV;
+}
 #endif
 
 static int ak4535_probe(struct platform_device *pdev)
@@ -624,7 +621,7 @@
 	struct ak4535_setup_data *setup;
 	struct snd_soc_codec *codec;
 	struct ak4535_priv *ak4535;
-	int ret = 0;
+	int ret;
 
 	printk(KERN_INFO "AK4535 Audio Codec %s", AK4535_VERSION);
 
@@ -646,17 +643,14 @@
 	INIT_LIST_HEAD(&codec->dapm_paths);
 
 	ak4535_socdev = socdev;
+	ret = -ENODEV;
+
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
 	if (setup->i2c_address) {
-		normal_i2c[0] = setup->i2c_address;
 		codec->hw_write = (hw_write_t)i2c_master_send;
 		codec->hw_read = (hw_read_t)i2c_master_recv;
-		ret = i2c_add_driver(&ak4535_i2c_driver);
-		if (ret != 0)
-			printk(KERN_ERR "can't add i2c driver");
+		ret = ak4535_add_i2c_device(pdev, setup);
 	}
-#else
-	/* Add other interfaces here */
 #endif
 
 	if (ret != 0) {
@@ -678,6 +672,7 @@
 	snd_soc_free_pcms(socdev);
 	snd_soc_dapm_free(socdev);
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+	i2c_unregister_device(codec->control_data);
 	i2c_del_driver(&ak4535_i2c_driver);
 #endif
 	kfree(codec->private_data);
diff --git a/sound/soc/codecs/ak4535.h b/sound/soc/codecs/ak4535.h
index e9fe30e..c7a5870 100644
--- a/sound/soc/codecs/ak4535.h
+++ b/sound/soc/codecs/ak4535.h
@@ -37,6 +37,7 @@
 #define AK4535_CACHEREGNUM 	0x10
 
 struct ak4535_setup_data {
+	int            i2c_bus;
 	unsigned short i2c_address;
 };
 
diff --git a/sound/soc/codecs/cs4270.c b/sound/soc/codecs/cs4270.c
index 9deb8c7..0bbd945 100644
--- a/sound/soc/codecs/cs4270.c
+++ b/sound/soc/codecs/cs4270.c
@@ -490,34 +490,7 @@
 
 #endif
 
-static int cs4270_i2c_probe(struct i2c_adapter *adap, int addr, int kind);
-
-/*
- * Notify the driver that a new I2C bus has been found.
- *
- * This function is called for each I2C bus in the system.  The function
- * then asks the I2C subsystem to probe that bus at the addresses on which
- * our device (the CS4270) could exist.  If a device is found at one of
- * those addresses, then our probe function (cs4270_i2c_probe) is called.
- */
-static int cs4270_i2c_attach(struct i2c_adapter *adapter)
-{
-	return i2c_probe(adapter, &addr_data, cs4270_i2c_probe);
-}
-
-static int cs4270_i2c_detach(struct i2c_client *client)
-{
-	struct snd_soc_codec *codec = i2c_get_clientdata(client);
-
-	i2c_detach_client(client);
-	codec->control_data = NULL;
-
-	kfree(codec->reg_cache);
-	codec->reg_cache = NULL;
-
-	kfree(client);
-	return 0;
-}
+static int cs4270_i2c_probe(struct i2c_client *, const struct i2c_device_id *);
 
 /* A list of non-DAPM controls that the CS4270 supports */
 static const struct snd_kcontrol_new cs4270_snd_controls[] = {
@@ -525,14 +498,19 @@
 		CS4270_VOLA, CS4270_VOLB, 0, 0xFF, 1)
 };
 
+static const struct i2c_device_id cs4270_id[] = {
+	{"cs4270", 0},
+	{}
+};
+MODULE_DEVICE_TABLE(i2c, cs4270_id);
+
 static struct i2c_driver cs4270_i2c_driver = {
 	.driver = {
 		.name = "CS4270 I2C",
 		.owner = THIS_MODULE,
 	},
-	.id =             I2C_DRIVERID_CS4270,
-	.attach_adapter = cs4270_i2c_attach,
-	.detach_client =  cs4270_i2c_detach,
+	.id_table = cs4270_id,
+	.probe = cs4270_i2c_probe,
 };
 
 /*
@@ -561,11 +539,11 @@
  * Note: snd_soc_new_pcms() must be called before this function can be called,
  * because of snd_ctl_add().
  */
-static int cs4270_i2c_probe(struct i2c_adapter *adapter, int addr, int kind)
+static int cs4270_i2c_probe(struct i2c_client *i2c_client,
+	const struct i2c_device_id *id)
 {
 	struct snd_soc_device *socdev = cs4270_socdev;
 	struct snd_soc_codec *codec = socdev->codec;
-	struct i2c_client *i2c_client = NULL;
 	int i;
 	int ret = 0;
 
@@ -578,12 +556,6 @@
 
 	/* Note: codec_dai->codec is NULL here */
 
-	i2c_client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
-	if (!i2c_client) {
-		printk(KERN_ERR "cs4270: could not allocate I2C client\n");
-		return -ENOMEM;
-	}
-
 	codec->reg_cache = kzalloc(CS4270_NUMREGS, GFP_KERNEL);
 	if (!codec->reg_cache) {
 		printk(KERN_ERR "cs4270: could not allocate register cache\n");
@@ -591,13 +563,6 @@
 		goto error;
 	}
 
-	i2c_set_clientdata(i2c_client, codec);
-	strcpy(i2c_client->name, "CS4270");
-
-	i2c_client->driver = &cs4270_i2c_driver;
-	i2c_client->adapter = adapter;
-	i2c_client->addr = addr;
-
 	/* Verify that we have a CS4270 */
 
 	ret = i2c_smbus_read_byte_data(i2c_client, CS4270_CHIPID);
@@ -612,18 +577,10 @@
 		goto error;
 	}
 
-	printk(KERN_INFO "cs4270: found device at I2C address %X\n", addr);
+	printk(KERN_INFO "cs4270: found device at I2C address %X\n",
+		i2c_client->addr);
 	printk(KERN_INFO "cs4270: hardware revision %X\n", ret & 0xF);
 
-	/* Tell the I2C layer a new client has arrived */
-
-	ret = i2c_attach_client(i2c_client);
-	if (ret) {
-		printk(KERN_ERR "cs4270: could not attach codec, "
-			"I2C address %x, error code %i\n", addr, ret);
-		goto error;
-	}
-
 	codec->control_data = i2c_client;
 	codec->read = cs4270_read_reg_cache;
 	codec->write = cs4270_i2c_write;
@@ -648,20 +605,17 @@
 			goto error;
 	}
 
+	i2c_set_clientdata(i2c_client, codec);
+
 	return 0;
 
 error:
-	if (codec->control_data) {
-		i2c_detach_client(i2c_client);
-		codec->control_data = NULL;
-	}
+	codec->control_data = NULL;
 
 	kfree(codec->reg_cache);
 	codec->reg_cache = NULL;
 	codec->reg_cache_size = 0;
 
-	kfree(i2c_client);
-
 	return ret;
 }
 
@@ -727,7 +681,7 @@
 	ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
 	if (ret < 0) {
 		printk(KERN_ERR "cs4270: failed to create PCMs\n");
-		return ret;
+		goto error_free_codec;
 	}
 
 #ifdef USE_I2C
@@ -736,8 +690,7 @@
 	ret = i2c_add_driver(&cs4270_i2c_driver);
 	if (ret) {
 		printk(KERN_ERR "cs4270: failed to attach driver");
-		snd_soc_free_pcms(socdev);
-		return ret;
+		goto error_free_pcms;
 	}
 
 	/* Did we find a CS4270 on the I2C bus? */
@@ -759,10 +712,23 @@
 	ret = snd_soc_register_card(socdev);
 	if (ret < 0) {
 		printk(KERN_ERR "cs4270: failed to register card\n");
-		snd_soc_free_pcms(socdev);
-		return ret;
+		goto error_del_driver;
 	}
 
+	return 0;
+
+error_del_driver:
+#ifdef USE_I2C
+	i2c_del_driver(&cs4270_i2c_driver);
+
+error_free_pcms:
+#endif
+	snd_soc_free_pcms(socdev);
+
+error_free_codec:
+	kfree(socdev->codec);
+	socdev->codec = NULL;
+
 	return ret;
 }
 
@@ -773,8 +739,7 @@
 	snd_soc_free_pcms(socdev);
 
 #ifdef USE_I2C
-	if (socdev->codec->control_data)
-		i2c_del_driver(&cs4270_i2c_driver);
+	i2c_del_driver(&cs4270_i2c_driver);
 #endif
 
 	kfree(socdev->codec);
diff --git a/sound/soc/codecs/ssm2602.c b/sound/soc/codecs/ssm2602.c
new file mode 100644
index 0000000..44ef0da
--- /dev/null
+++ b/sound/soc/codecs/ssm2602.c
@@ -0,0 +1,775 @@
+/*
+ * File:         sound/soc/codecs/ssm2602.c
+ * Author:       Cliff Cai <Cliff.Cai@analog.com>
+ *
+ * Created:      Tue June 06 2008
+ * Description:  Driver for ssm2602 sound chip
+ *
+ * Modified:
+ *               Copyright 2008 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.org/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+
+#include "ssm2602.h"
+
+#define SSM2602_VERSION "0.1"
+
+struct snd_soc_codec_device soc_codec_dev_ssm2602;
+
+/* codec private data */
+struct ssm2602_priv {
+	unsigned int sysclk;
+	struct snd_pcm_substream *master_substream;
+	struct snd_pcm_substream *slave_substream;
+};
+
+/*
+ * ssm2602 register cache
+ * We can't read the ssm2602 register space when we are
+ * using 2 wire for device control, so we cache them instead.
+ * There is no point in caching the reset register
+ */
+static const u16 ssm2602_reg[SSM2602_CACHEREGNUM] = {
+	0x0017, 0x0017, 0x0079, 0x0079,
+	0x0000, 0x0000, 0x0000, 0x000a,
+	0x0000, 0x0000
+};
+
+/*
+ * read ssm2602 register cache
+ */
+static inline unsigned int ssm2602_read_reg_cache(struct snd_soc_codec *codec,
+	unsigned int reg)
+{
+	u16 *cache = codec->reg_cache;
+	if (reg == SSM2602_RESET)
+		return 0;
+	if (reg >= SSM2602_CACHEREGNUM)
+		return -1;
+	return cache[reg];
+}
+
+/*
+ * write ssm2602 register cache
+ */
+static inline void ssm2602_write_reg_cache(struct snd_soc_codec *codec,
+	u16 reg, unsigned int value)
+{
+	u16 *cache = codec->reg_cache;
+	if (reg >= SSM2602_CACHEREGNUM)
+		return;
+	cache[reg] = value;
+}
+
+/*
+ * write to the ssm2602 register space
+ */
+static int ssm2602_write(struct snd_soc_codec *codec, unsigned int reg,
+	unsigned int value)
+{
+	u8 data[2];
+
+	/* data is
+	 *   D15..D9 ssm2602 register offset
+	 *   D8...D0 register data
+	 */
+	data[0] = (reg << 1) | ((value >> 8) & 0x0001);
+	data[1] = value & 0x00ff;
+
+	ssm2602_write_reg_cache(codec, reg, value);
+	if (codec->hw_write(codec->control_data, data, 2) == 2)
+		return 0;
+	else
+		return -EIO;
+}
+
+#define ssm2602_reset(c)	ssm2602_write(c, SSM2602_RESET, 0)
+
+/*Appending several "None"s just for OSS mixer use*/
+static const char *ssm2602_input_select[] = {
+	"Line", "Mic", "None", "None", "None",
+	"None", "None", "None",
+};
+
+static const char *ssm2602_deemph[] = {"None", "32Khz", "44.1Khz", "48Khz"};
+
+static const struct soc_enum ssm2602_enum[] = {
+	SOC_ENUM_SINGLE(SSM2602_APANA, 2, 2, ssm2602_input_select),
+	SOC_ENUM_SINGLE(SSM2602_APDIGI, 1, 4, ssm2602_deemph),
+};
+
+static const struct snd_kcontrol_new ssm2602_snd_controls[] = {
+
+SOC_DOUBLE_R("Master Playback Volume", SSM2602_LOUT1V, SSM2602_ROUT1V,
+	0, 127, 0),
+SOC_DOUBLE_R("Master Playback ZC Switch", SSM2602_LOUT1V, SSM2602_ROUT1V,
+	7, 1, 0),
+
+SOC_DOUBLE_R("Capture Volume", SSM2602_LINVOL, SSM2602_RINVOL, 0, 31, 0),
+SOC_DOUBLE_R("Capture Switch", SSM2602_LINVOL, SSM2602_RINVOL, 7, 1, 1),
+
+SOC_SINGLE("Mic Boost (+20dB)", SSM2602_APANA, 0, 1, 0),
+SOC_SINGLE("Mic Switch", SSM2602_APANA, 1, 1, 1),
+
+SOC_SINGLE("Sidetone Playback Volume", SSM2602_APANA, 6, 3, 1),
+
+SOC_SINGLE("ADC High Pass Filter Switch", SSM2602_APDIGI, 0, 1, 1),
+SOC_SINGLE("Store DC Offset Switch", SSM2602_APDIGI, 4, 1, 0),
+
+SOC_ENUM("Capture Source", ssm2602_enum[0]),
+
+SOC_ENUM("Playback De-emphasis", ssm2602_enum[1]),
+};
+
+/* add non dapm controls */
+static int ssm2602_add_controls(struct snd_soc_codec *codec)
+{
+	int err, i;
+
+	for (i = 0; i < ARRAY_SIZE(ssm2602_snd_controls); i++) {
+		err = snd_ctl_add(codec->card,
+			snd_soc_cnew(&ssm2602_snd_controls[i], codec, NULL));
+		if (err < 0)
+			return err;
+	}
+
+	return 0;
+}
+
+/* Output Mixer */
+static const struct snd_kcontrol_new ssm2602_output_mixer_controls[] = {
+SOC_DAPM_SINGLE("Line Bypass Switch", SSM2602_APANA, 3, 1, 0),
+SOC_DAPM_SINGLE("Mic Sidetone Switch", SSM2602_APANA, 5, 1, 0),
+SOC_DAPM_SINGLE("HiFi Playback Switch", SSM2602_APANA, 4, 1, 0),
+};
+
+/* Input mux */
+static const struct snd_kcontrol_new ssm2602_input_mux_controls =
+SOC_DAPM_ENUM("Input Select", ssm2602_enum[0]);
+
+static const struct snd_soc_dapm_widget ssm2602_dapm_widgets[] = {
+SND_SOC_DAPM_MIXER("Output Mixer", SSM2602_PWR, 4, 1,
+	&ssm2602_output_mixer_controls[0],
+	ARRAY_SIZE(ssm2602_output_mixer_controls)),
+SND_SOC_DAPM_DAC("DAC", "HiFi Playback", SSM2602_PWR, 3, 1),
+SND_SOC_DAPM_OUTPUT("LOUT"),
+SND_SOC_DAPM_OUTPUT("LHPOUT"),
+SND_SOC_DAPM_OUTPUT("ROUT"),
+SND_SOC_DAPM_OUTPUT("RHPOUT"),
+SND_SOC_DAPM_ADC("ADC", "HiFi Capture", SSM2602_PWR, 2, 1),
+SND_SOC_DAPM_MUX("Input Mux", SND_SOC_NOPM, 0, 0, &ssm2602_input_mux_controls),
+SND_SOC_DAPM_PGA("Line Input", SSM2602_PWR, 0, 1, NULL, 0),
+SND_SOC_DAPM_MICBIAS("Mic Bias", SSM2602_PWR, 1, 1),
+SND_SOC_DAPM_INPUT("MICIN"),
+SND_SOC_DAPM_INPUT("RLINEIN"),
+SND_SOC_DAPM_INPUT("LLINEIN"),
+};
+
+static const struct snd_soc_dapm_route audio_conn[] = {
+	/* output mixer */
+	{"Output Mixer", "Line Bypass Switch", "Line Input"},
+	{"Output Mixer", "HiFi Playback Switch", "DAC"},
+	{"Output Mixer", "Mic Sidetone Switch", "Mic Bias"},
+
+	/* outputs */
+	{"RHPOUT", NULL, "Output Mixer"},
+	{"ROUT", NULL, "Output Mixer"},
+	{"LHPOUT", NULL, "Output Mixer"},
+	{"LOUT", NULL, "Output Mixer"},
+
+	/* input mux */
+	{"Input Mux", "Line", "Line Input"},
+	{"Input Mux", "Mic", "Mic Bias"},
+	{"ADC", NULL, "Input Mux"},
+
+	/* inputs */
+	{"Line Input", NULL, "LLINEIN"},
+	{"Line Input", NULL, "RLINEIN"},
+	{"Mic Bias", NULL, "MICIN"},
+};
+
+static int ssm2602_add_widgets(struct snd_soc_codec *codec)
+{
+	snd_soc_dapm_new_controls(codec, ssm2602_dapm_widgets,
+				  ARRAY_SIZE(ssm2602_dapm_widgets));
+
+	snd_soc_dapm_add_routes(codec, audio_conn, ARRAY_SIZE(audio_conn));
+
+	snd_soc_dapm_new_widgets(codec);
+	return 0;
+}
+
+struct _coeff_div {
+	u32 mclk;
+	u32 rate;
+	u16 fs;
+	u8 sr:4;
+	u8 bosr:1;
+	u8 usb:1;
+};
+
+/* codec mclk clock divider coefficients */
+static const struct _coeff_div coeff_div[] = {
+	/* 48k */
+	{12288000, 48000, 256, 0x0, 0x0, 0x0},
+	{18432000, 48000, 384, 0x0, 0x1, 0x0},
+	{12000000, 48000, 250, 0x0, 0x0, 0x1},
+
+	/* 32k */
+	{12288000, 32000, 384, 0x6, 0x0, 0x0},
+	{18432000, 32000, 576, 0x6, 0x1, 0x0},
+	{12000000, 32000, 375, 0x6, 0x0, 0x1},
+
+	/* 8k */
+	{12288000, 8000, 1536, 0x3, 0x0, 0x0},
+	{18432000, 8000, 2304, 0x3, 0x1, 0x0},
+	{11289600, 8000, 1408, 0xb, 0x0, 0x0},
+	{16934400, 8000, 2112, 0xb, 0x1, 0x0},
+	{12000000, 8000, 1500, 0x3, 0x0, 0x1},
+
+	/* 96k */
+	{12288000, 96000, 128, 0x7, 0x0, 0x0},
+	{18432000, 96000, 192, 0x7, 0x1, 0x0},
+	{12000000, 96000, 125, 0x7, 0x0, 0x1},
+
+	/* 44.1k */
+	{11289600, 44100, 256, 0x8, 0x0, 0x0},
+	{16934400, 44100, 384, 0x8, 0x1, 0x0},
+	{12000000, 44100, 272, 0x8, 0x1, 0x1},
+
+	/* 88.2k */
+	{11289600, 88200, 128, 0xf, 0x0, 0x0},
+	{16934400, 88200, 192, 0xf, 0x1, 0x0},
+	{12000000, 88200, 136, 0xf, 0x1, 0x1},
+};
+
+static inline int get_coeff(int mclk, int rate)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(coeff_div); i++) {
+		if (coeff_div[i].rate == rate && coeff_div[i].mclk == mclk)
+			return i;
+	}
+	return i;
+}
+
+static int ssm2602_hw_params(struct snd_pcm_substream *substream,
+	struct snd_pcm_hw_params *params)
+{
+	u16 srate;
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_device *socdev = rtd->socdev;
+	struct snd_soc_codec *codec = socdev->codec;
+	struct ssm2602_priv *ssm2602 = codec->private_data;
+	u16 iface = ssm2602_read_reg_cache(codec, SSM2602_IFACE) & 0xfff3;
+	int i = get_coeff(ssm2602->sysclk, params_rate(params));
+
+	/*no match is found*/
+	if (i == ARRAY_SIZE(coeff_div))
+		return -EINVAL;
+
+	srate = (coeff_div[i].sr << 2) |
+		(coeff_div[i].bosr << 1) | coeff_div[i].usb;
+
+	ssm2602_write(codec, SSM2602_ACTIVE, 0);
+	ssm2602_write(codec, SSM2602_SRATE, srate);
+
+	/* bit size */
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S16_LE:
+		break;
+	case SNDRV_PCM_FORMAT_S20_3LE:
+		iface |= 0x0004;
+		break;
+	case SNDRV_PCM_FORMAT_S24_LE:
+		iface |= 0x0008;
+		break;
+	case SNDRV_PCM_FORMAT_S32_LE:
+		iface |= 0x000c;
+		break;
+	}
+	ssm2602_write(codec, SSM2602_IFACE, iface);
+	ssm2602_write(codec, SSM2602_ACTIVE, ACTIVE_ACTIVATE_CODEC);
+	return 0;
+}
+
+static int ssm2602_startup(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_device *socdev = rtd->socdev;
+	struct snd_soc_codec *codec = socdev->codec;
+	struct ssm2602_priv *ssm2602 = codec->private_data;
+	struct snd_pcm_runtime *master_runtime;
+
+	/* The DAI has shared clocks so if we already have a playback or
+	 * capture going then constrain this substream to match it.
+	 */
+	if (ssm2602->master_substream) {
+		master_runtime = ssm2602->master_substream->runtime;
+		snd_pcm_hw_constraint_minmax(substream->runtime,
+					     SNDRV_PCM_HW_PARAM_RATE,
+					     master_runtime->rate,
+					     master_runtime->rate);
+
+		snd_pcm_hw_constraint_minmax(substream->runtime,
+					     SNDRV_PCM_HW_PARAM_SAMPLE_BITS,
+					     master_runtime->sample_bits,
+					     master_runtime->sample_bits);
+
+		ssm2602->slave_substream = substream;
+	} else
+		ssm2602->master_substream = substream;
+
+	return 0;
+}
+
+static int ssm2602_pcm_prepare(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_device *socdev = rtd->socdev;
+	struct snd_soc_codec *codec = socdev->codec;
+	/* set active */
+	ssm2602_write(codec, SSM2602_ACTIVE, ACTIVE_ACTIVATE_CODEC);
+
+	return 0;
+}
+
+static void ssm2602_shutdown(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_device *socdev = rtd->socdev;
+	struct snd_soc_codec *codec = socdev->codec;
+	/* deactivate */
+	if (!codec->active)
+		ssm2602_write(codec, SSM2602_ACTIVE, 0);
+}
+
+static int ssm2602_mute(struct snd_soc_dai *dai, int mute)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	u16 mute_reg = ssm2602_read_reg_cache(codec, SSM2602_APDIGI) & ~APDIGI_ENABLE_DAC_MUTE;
+	if (mute)
+		ssm2602_write(codec, SSM2602_APDIGI,
+				mute_reg | APDIGI_ENABLE_DAC_MUTE);
+	else
+		ssm2602_write(codec, SSM2602_APDIGI, mute_reg);
+	return 0;
+}
+
+static int ssm2602_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+		int clk_id, unsigned int freq, int dir)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+	struct ssm2602_priv *ssm2602 = codec->private_data;
+	switch (freq) {
+	case 11289600:
+	case 12000000:
+	case 12288000:
+	case 16934400:
+	case 18432000:
+		ssm2602->sysclk = freq;
+		return 0;
+	}
+	return -EINVAL;
+}
+
+static int ssm2602_set_dai_fmt(struct snd_soc_dai *codec_dai,
+		unsigned int fmt)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+	u16 iface = 0;
+
+	/* set master/slave audio interface */
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		iface |= 0x0040;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* interface format */
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		iface |= 0x0002;
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		iface |= 0x0001;
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		iface |= 0x0003;
+		break;
+	case SND_SOC_DAIFMT_DSP_B:
+		iface |= 0x0013;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* clock inversion */
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		break;
+	case SND_SOC_DAIFMT_IB_IF:
+		iface |= 0x0090;
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		iface |= 0x0080;
+		break;
+	case SND_SOC_DAIFMT_NB_IF:
+		iface |= 0x0010;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* set iface */
+	ssm2602_write(codec, SSM2602_IFACE, iface);
+	return 0;
+}
+
+static int ssm2602_set_bias_level(struct snd_soc_codec *codec,
+				 enum snd_soc_bias_level level)
+{
+	u16 reg = ssm2602_read_reg_cache(codec, SSM2602_PWR) & 0xff7f;
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		/* vref/mid, osc on, dac unmute */
+		ssm2602_write(codec, SSM2602_PWR, reg);
+		break;
+	case SND_SOC_BIAS_PREPARE:
+		break;
+	case SND_SOC_BIAS_STANDBY:
+		/* everything off except vref/vmid, */
+		ssm2602_write(codec, SSM2602_PWR, reg | PWR_CLK_OUT_PDN);
+		break;
+	case SND_SOC_BIAS_OFF:
+		/* everything off, dac mute, inactive */
+		ssm2602_write(codec, SSM2602_ACTIVE, 0);
+		ssm2602_write(codec, SSM2602_PWR, 0xffff);
+		break;
+
+	}
+	codec->bias_level = level;
+	return 0;
+}
+
+#define SSM2602_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
+		SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |\
+		SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |\
+		SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |\
+		SNDRV_PCM_RATE_96000)
+
+struct snd_soc_dai ssm2602_dai = {
+	.name = "SSM2602",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = SSM2602_RATES,
+		.formats = SNDRV_PCM_FMTBIT_S32_LE,},
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = SSM2602_RATES,
+		.formats = SNDRV_PCM_FMTBIT_S32_LE,},
+	.ops = {
+		.startup = ssm2602_startup,
+		.prepare = ssm2602_pcm_prepare,
+		.hw_params = ssm2602_hw_params,
+		.shutdown = ssm2602_shutdown,
+	},
+	.dai_ops = {
+		.digital_mute = ssm2602_mute,
+		.set_sysclk = ssm2602_set_dai_sysclk,
+		.set_fmt = ssm2602_set_dai_fmt,
+	}
+};
+EXPORT_SYMBOL_GPL(ssm2602_dai);
+
+static int ssm2602_suspend(struct platform_device *pdev, pm_message_t state)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	struct snd_soc_codec *codec = socdev->codec;
+
+	ssm2602_set_bias_level(codec, SND_SOC_BIAS_OFF);
+	return 0;
+}
+
+static int ssm2602_resume(struct platform_device *pdev)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	struct snd_soc_codec *codec = socdev->codec;
+	int i;
+	u8 data[2];
+	u16 *cache = codec->reg_cache;
+
+	/* Sync reg_cache with the hardware */
+	for (i = 0; i < ARRAY_SIZE(ssm2602_reg); i++) {
+		data[0] = (i << 1) | ((cache[i] >> 8) & 0x0001);
+		data[1] = cache[i] & 0x00ff;
+		codec->hw_write(codec->control_data, data, 2);
+	}
+	ssm2602_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+	ssm2602_set_bias_level(codec, codec->suspend_bias_level);
+	return 0;
+}
+
+/*
+ * initialise the ssm2602 driver
+ * register the mixer and dsp interfaces with the kernel
+ */
+static int ssm2602_init(struct snd_soc_device *socdev)
+{
+	struct snd_soc_codec *codec = socdev->codec;
+	int reg, ret = 0;
+
+	codec->name = "SSM2602";
+	codec->owner = THIS_MODULE;
+	codec->read = ssm2602_read_reg_cache;
+	codec->write = ssm2602_write;
+	codec->set_bias_level = ssm2602_set_bias_level;
+	codec->dai = &ssm2602_dai;
+	codec->num_dai = 1;
+	codec->reg_cache_size = sizeof(ssm2602_reg);
+	codec->reg_cache = kmemdup(ssm2602_reg, sizeof(ssm2602_reg),
+					GFP_KERNEL);
+	if (codec->reg_cache == NULL)
+		return -ENOMEM;
+
+	ssm2602_reset(codec);
+
+	/* register pcms */
+	ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
+	if (ret < 0) {
+		pr_err("ssm2602: failed to create pcms\n");
+		goto pcm_err;
+	}
+	/*power on device*/
+	ssm2602_write(codec, SSM2602_ACTIVE, 0);
+	/* set the update bits */
+	reg = ssm2602_read_reg_cache(codec, SSM2602_LINVOL);
+	ssm2602_write(codec, SSM2602_LINVOL, reg | LINVOL_LRIN_BOTH);
+	reg = ssm2602_read_reg_cache(codec, SSM2602_RINVOL);
+	ssm2602_write(codec, SSM2602_RINVOL, reg | RINVOL_RLIN_BOTH);
+	reg = ssm2602_read_reg_cache(codec, SSM2602_LOUT1V);
+	ssm2602_write(codec, SSM2602_LOUT1V, reg | LOUT1V_LRHP_BOTH);
+	reg = ssm2602_read_reg_cache(codec, SSM2602_ROUT1V);
+	ssm2602_write(codec, SSM2602_ROUT1V, reg | ROUT1V_RLHP_BOTH);
+	/*select Line in as default input*/
+	ssm2602_write(codec, SSM2602_APANA,
+			APANA_ENABLE_MIC_BOOST2 | APANA_SELECT_DAC |
+			APANA_ENABLE_MIC_BOOST);
+	ssm2602_write(codec, SSM2602_PWR, 0);
+
+	ssm2602_add_controls(codec);
+	ssm2602_add_widgets(codec);
+	ret = snd_soc_register_card(socdev);
+	if (ret < 0) {
+		pr_err("ssm2602: failed to register card\n");
+		goto card_err;
+	}
+
+	return ret;
+
+card_err:
+	snd_soc_free_pcms(socdev);
+	snd_soc_dapm_free(socdev);
+pcm_err:
+	kfree(codec->reg_cache);
+	return ret;
+}
+
+static struct snd_soc_device *ssm2602_socdev;
+
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+/*
+ * ssm2602 2 wire address is determined by GPIO5
+ * state during powerup.
+ *    low  = 0x1a
+ *    high = 0x1b
+ */
+static int ssm2602_i2c_probe(struct i2c_client *i2c,
+			     const struct i2c_device_id *id)
+{
+	struct snd_soc_device *socdev = ssm2602_socdev;
+	struct snd_soc_codec *codec = socdev->codec;
+	int ret;
+
+	i2c_set_clientdata(i2c, codec);
+	codec->control_data = i2c;
+
+	ret = ssm2602_init(socdev);
+	if (ret < 0)
+		pr_err("failed to initialise SSM2602\n");
+
+	return ret;
+}
+
+static int ssm2602_i2c_remove(struct i2c_client *client)
+{
+	struct snd_soc_codec *codec = i2c_get_clientdata(client);
+	kfree(codec->reg_cache);
+	return 0;
+}
+
+static const struct i2c_device_id ssm2602_i2c_id[] = {
+	{ "ssm2602", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, ssm2602_i2c_id);
+/* corgi i2c codec control layer */
+static struct i2c_driver ssm2602_i2c_driver = {
+	.driver = {
+		.name = "SSM2602 I2C Codec",
+		.owner = THIS_MODULE,
+	},
+	.probe = ssm2602_i2c_probe,
+	.remove = ssm2602_i2c_remove,
+	.id_table = ssm2602_i2c_id,
+};
+
+static int ssm2602_add_i2c_device(struct platform_device *pdev,
+				  const struct ssm2602_setup_data *setup)
+{
+	struct i2c_board_info info;
+	struct i2c_adapter *adapter;
+	struct i2c_client *client;
+	int ret;
+
+	ret = i2c_add_driver(&ssm2602_i2c_driver);
+	if (ret != 0) {
+		dev_err(&pdev->dev, "can't add i2c driver\n");
+		return ret;
+	}
+	memset(&info, 0, sizeof(struct i2c_board_info));
+	info.addr = setup->i2c_address;
+	strlcpy(info.type, "ssm2602", I2C_NAME_SIZE);
+	adapter = i2c_get_adapter(setup->i2c_bus);
+	if (!adapter) {
+		dev_err(&pdev->dev, "can't get i2c adapter %d\n",
+		setup->i2c_bus);
+		goto err_driver;
+	}
+	client = i2c_new_device(adapter, &info);
+	i2c_put_adapter(adapter);
+	if (!client) {
+		dev_err(&pdev->dev, "can't add i2c device at 0x%x\n",
+		(unsigned int)info.addr);
+		goto err_driver;
+	}
+	return 0;
+err_driver:
+	i2c_del_driver(&ssm2602_i2c_driver);
+	return -ENODEV;
+}
+#endif
+
+static int ssm2602_probe(struct platform_device *pdev)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	struct ssm2602_setup_data *setup;
+	struct snd_soc_codec *codec;
+	struct ssm2602_priv *ssm2602;
+	int ret = 0;
+
+	pr_info("ssm2602 Audio Codec %s", SSM2602_VERSION);
+
+	setup = socdev->codec_data;
+	codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
+	if (codec == NULL)
+		return -ENOMEM;
+
+	ssm2602 = kzalloc(sizeof(struct ssm2602_priv), GFP_KERNEL);
+	if (ssm2602 == NULL) {
+		kfree(codec);
+		return -ENOMEM;
+	}
+
+	codec->private_data = ssm2602;
+	socdev->codec = codec;
+	mutex_init(&codec->mutex);
+	INIT_LIST_HEAD(&codec->dapm_widgets);
+	INIT_LIST_HEAD(&codec->dapm_paths);
+
+	ssm2602_socdev = socdev;
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+	if (setup->i2c_address) {
+		codec->hw_write = (hw_write_t)i2c_master_send;
+		ret = ssm2602_add_i2c_device(pdev, setup);
+	}
+#else
+	/* other interfaces */
+#endif
+	return ret;
+}
+
+/* remove everything here */
+static int ssm2602_remove(struct platform_device *pdev)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	struct snd_soc_codec *codec = socdev->codec;
+
+	if (codec->control_data)
+		ssm2602_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
+	snd_soc_free_pcms(socdev);
+	snd_soc_dapm_free(socdev);
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+	i2c_unregister_device(codec->control_data);
+	i2c_del_driver(&ssm2602_i2c_driver);
+#endif
+	kfree(codec->private_data);
+	kfree(codec);
+
+	return 0;
+}
+
+struct snd_soc_codec_device soc_codec_dev_ssm2602 = {
+	.probe = 	ssm2602_probe,
+	.remove = 	ssm2602_remove,
+	.suspend = 	ssm2602_suspend,
+	.resume =	ssm2602_resume,
+};
+EXPORT_SYMBOL_GPL(soc_codec_dev_ssm2602);
+
+MODULE_DESCRIPTION("ASoC ssm2602 driver");
+MODULE_AUTHOR("Cliff Cai");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/ssm2602.h b/sound/soc/codecs/ssm2602.h
new file mode 100644
index 0000000..f344e6d
--- /dev/null
+++ b/sound/soc/codecs/ssm2602.h
@@ -0,0 +1,130 @@
+/*
+ * File:         sound/soc/codecs/ssm2602.h
+ * Author:       Cliff Cai <Cliff.Cai@analog.com>
+ *
+ * Created:      Tue June 06 2008
+ *
+ * Modified:
+ *               Copyright 2008 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.org/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifndef _SSM2602_H
+#define _SSM2602_H
+
+/* SSM2602 Codec Register definitions */
+
+#define SSM2602_LINVOL   0x00
+#define SSM2602_RINVOL   0x01
+#define SSM2602_LOUT1V   0x02
+#define SSM2602_ROUT1V   0x03
+#define SSM2602_APANA    0x04
+#define SSM2602_APDIGI   0x05
+#define SSM2602_PWR      0x06
+#define SSM2602_IFACE    0x07
+#define SSM2602_SRATE    0x08
+#define SSM2602_ACTIVE   0x09
+#define SSM2602_RESET	 0x0f
+
+/*SSM2602 Codec Register Field definitions
+ *(Mask value to extract the corresponding Register field)
+ */
+
+/*Left ADC Volume Control (SSM2602_REG_LEFT_ADC_VOL)*/
+#define     LINVOL_LIN_VOL                0x01F   /* Left Channel PGA Volume control                      */
+#define     LINVOL_LIN_ENABLE_MUTE        0x080   /* Left Channel Input Mute                              */
+#define     LINVOL_LRIN_BOTH              0x100   /* Left Channel Line Input Volume update                */
+
+/*Right ADC Volume Control (SSM2602_REG_RIGHT_ADC_VOL)*/
+#define     RINVOL_RIN_VOL                0x01F   /* Right Channel PGA Volume control                     */
+#define     RINVOL_RIN_ENABLE_MUTE        0x080   /* Right Channel Input Mute                             */
+#define     RINVOL_RLIN_BOTH              0x100   /* Right Channel Line Input Volume update               */
+
+/*Left DAC Volume Control (SSM2602_REG_LEFT_DAC_VOL)*/
+#define     LOUT1V_LHP_VOL                0x07F   /* Left Channel Headphone volume control                */
+#define     LOUT1V_ENABLE_LZC             0x080   /* Left Channel Zero cross detect enable                */
+#define     LOUT1V_LRHP_BOTH              0x100   /* Left Channel Headphone volume update                 */
+
+/*Right DAC Volume Control (SSM2602_REG_RIGHT_DAC_VOL)*/
+#define     ROUT1V_RHP_VOL                0x07F   /* Right Channel Headphone volume control               */
+#define     ROUT1V_ENABLE_RZC             0x080   /* Right Channel Zero cross detect enable               */
+#define     ROUT1V_RLHP_BOTH              0x100   /* Right Channel Headphone volume update                */
+
+/*Analogue Audio Path Control (SSM2602_REG_ANALOGUE_PATH)*/
+#define     APANA_ENABLE_MIC_BOOST       0x001   /* Primary Microphone Amplifier gain booster control    */
+#define     APANA_ENABLE_MIC_MUTE        0x002   /* Microphone Mute Control                              */
+#define     APANA_ADC_IN_SELECT          0x004   /* Microphone/Line IN select to ADC (1=MIC, 0=Line In)  */
+#define     APANA_ENABLE_BYPASS          0x008   /* Line input bypass to line output                     */
+#define     APANA_SELECT_DAC             0x010   /* Select DAC (1=Select DAC, 0=Don't Select DAC)        */
+#define     APANA_ENABLE_SIDETONE        0x020   /* Enable/Disable Side Tone                             */
+#define     APANA_SIDETONE_ATTN          0x0C0   /* Side Tone Attenuation                                */
+#define     APANA_ENABLE_MIC_BOOST2      0x100   /* Secondary Microphone Amplifier gain booster control  */
+
+/*Digital Audio Path Control (SSM2602_REG_DIGITAL_PATH)*/
+#define     APDIGI_ENABLE_ADC_HPF         0x001   /* Enable/Disable ADC Highpass Filter                   */
+#define     APDIGI_DE_EMPHASIS            0x006   /* De-Emphasis Control                                  */
+#define     APDIGI_ENABLE_DAC_MUTE        0x008   /* DAC Mute Control                                     */
+#define     APDIGI_STORE_OFFSET           0x010   /* Store/Clear DC offset when HPF is disabled           */
+
+/*Power Down Control (SSM2602_REG_POWER)
+ *(1=Enable PowerDown, 0=Disable PowerDown)
+ */
+#define     PWR_LINE_IN_PDN            0x001   /* Line Input Power Down                                */
+#define     PWR_MIC_PDN                0x002   /* Microphone Input & Bias Power Down                   */
+#define     PWR_ADC_PDN                0x004   /* ADC Power Down                                       */
+#define     PWR_DAC_PDN                0x008   /* DAC Power Down                                       */
+#define     PWR_OUT_PDN                0x010   /* Outputs Power Down                                   */
+#define     PWR_OSC_PDN                0x020   /* Oscillator Power Down                                */
+#define     PWR_CLK_OUT_PDN            0x040   /* CLKOUT Power Down                                    */
+#define     PWR_POWER_OFF              0x080   /* POWEROFF Mode                                        */
+
+/*Digital Audio Interface Format (SSM2602_REG_DIGITAL_IFACE)*/
+#define     IFACE_IFACE_FORMAT           0x003   /* Digital Audio input format control                   */
+#define     IFACE_AUDIO_DATA_LEN         0x00C   /* Audio Data word length control                       */
+#define     IFACE_DAC_LR_POLARITY        0x010   /* Polarity Control for clocks in RJ,LJ and I2S modes   */
+#define     IFACE_DAC_LR_SWAP            0x020   /* Swap DAC data control                                */
+#define     IFACE_ENABLE_MASTER          0x040   /* Enable/Disable Master Mode                           */
+#define     IFACE_BCLK_INVERT            0x080   /* Bit Clock Inversion control                          */
+
+/*Sampling Control (SSM2602_REG_SAMPLING_CTRL)*/
+#define     SRATE_ENABLE_USB_MODE        0x001   /* Enable/Disable USB Mode                              */
+#define     SRATE_BOS_RATE               0x002   /* Base Over-Sampling rate                              */
+#define     SRATE_SAMPLE_RATE            0x03C   /* Clock setting condition (Sampling rate control)      */
+#define     SRATE_CORECLK_DIV2           0x040   /* Core Clock divider select                            */
+#define     SRATE_CLKOUT_DIV2            0x080   /* Clock Out divider select                             */
+
+/*Active Control (SSM2602_REG_ACTIVE_CTRL)*/
+#define     ACTIVE_ACTIVATE_CODEC         0x001   /* Activate Codec Digital Audio Interface               */
+
+/*********************************************************************/
+
+#define SSM2602_CACHEREGNUM 	10
+
+#define SSM2602_SYSCLK	0
+#define SSM2602_DAI		0
+
+struct ssm2602_setup_data {
+	int i2c_bus;
+	unsigned short i2c_address;
+};
+
+extern struct snd_soc_dai ssm2602_dai;
+extern struct snd_soc_codec_device soc_codec_dev_ssm2602;
+
+#endif
diff --git a/sound/soc/codecs/tlv320aic23.c b/sound/soc/codecs/tlv320aic23.c
new file mode 100644
index 0000000..bac7815
--- /dev/null
+++ b/sound/soc/codecs/tlv320aic23.c
@@ -0,0 +1,714 @@
+/*
+ * ALSA SoC TLV320AIC23 codec driver
+ *
+ * Author:      Arun KS, <arunks@mistralsolutions.com>
+ * Copyright:   (C) 2008 Mistral Solutions Pvt Ltd.,
+ *
+ * Based on sound/soc/codecs/wm8731.c by Richard Purdie
+ *
+ * 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.
+ *
+ * Notes:
+ *  The AIC23 is a driver for a low power stereo audio
+ *  codec tlv320aic23
+ *
+ *  The machine layer should disable unsupported inputs/outputs by
+ *  snd_soc_dapm_disable_pin(codec, "LHPOUT"), etc.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/tlv.h>
+#include <sound/initval.h>
+
+#include "tlv320aic23.h"
+
+#define AIC23_VERSION "0.1"
+
+struct tlv320aic23_srate_reg_info {
+	u32 sample_rate;
+	u8 control;		/* SR3, SR2, SR1, SR0 and BOSR */
+	u8 divider;		/* if 0 CLKIN = MCLK, if 1 CLKIN = MCLK/2 */
+};
+
+/*
+ * AIC23 register cache
+ */
+static const u16 tlv320aic23_reg[] = {
+	0x0097, 0x0097, 0x00F9, 0x00F9,	/* 0 */
+	0x001A, 0x0004, 0x0007, 0x0001,	/* 4 */
+	0x0020, 0x0000, 0x0000, 0x0000,	/* 8 */
+	0x0000, 0x0000, 0x0000, 0x0000,	/* 12 */
+};
+
+/*
+ * read tlv320aic23 register cache
+ */
+static inline unsigned int tlv320aic23_read_reg_cache(struct snd_soc_codec
+						      *codec, unsigned int reg)
+{
+	u16 *cache = codec->reg_cache;
+	if (reg >= ARRAY_SIZE(tlv320aic23_reg))
+		return -1;
+	return cache[reg];
+}
+
+/*
+ * write tlv320aic23 register cache
+ */
+static inline void tlv320aic23_write_reg_cache(struct snd_soc_codec *codec,
+					       u8 reg, u16 value)
+{
+	u16 *cache = codec->reg_cache;
+	if (reg >= ARRAY_SIZE(tlv320aic23_reg))
+		return;
+	cache[reg] = value;
+}
+
+/*
+ * write to the tlv320aic23 register space
+ */
+static int tlv320aic23_write(struct snd_soc_codec *codec, unsigned int reg,
+			     unsigned int value)
+{
+
+	u8 data;
+
+	/* TLV320AIC23 has 7 bit address and 9 bits of data
+	 * so we need to switch one data bit into reg and rest
+	 * of data into val
+	 */
+
+	if ((reg < 0 || reg > 9) && (reg != 15)) {
+		printk(KERN_WARNING "%s Invalid register R%d\n", __func__, reg);
+		return -1;
+	}
+
+	data = (reg << 1) | (value >> 8 & 0x01);
+
+	tlv320aic23_write_reg_cache(codec, reg, value);
+
+	if (codec->hw_write(codec->control_data, data,
+			    (value & 0xff)) == 0)
+		return 0;
+
+	printk(KERN_ERR "%s cannot write %03x to register R%d\n", __func__,
+	       value, reg);
+
+	return -EIO;
+}
+
+static const char *rec_src_text[] = { "Line", "Mic" };
+static const char *deemph_text[] = {"None", "32Khz", "44.1Khz", "48Khz"};
+
+static const struct soc_enum rec_src_enum =
+	SOC_ENUM_SINGLE(TLV320AIC23_ANLG, 2, 2, rec_src_text);
+
+static const struct snd_kcontrol_new tlv320aic23_rec_src_mux_controls =
+SOC_DAPM_ENUM("Input Select", rec_src_enum);
+
+static const struct soc_enum tlv320aic23_rec_src =
+	SOC_ENUM_SINGLE(TLV320AIC23_ANLG, 2, 2, rec_src_text);
+static const struct soc_enum tlv320aic23_deemph =
+	SOC_ENUM_SINGLE(TLV320AIC23_DIGT, 1, 4, deemph_text);
+
+static const DECLARE_TLV_DB_SCALE(out_gain_tlv, -12100, 100, 0);
+static const DECLARE_TLV_DB_SCALE(input_gain_tlv, -1725, 75, 0);
+static const DECLARE_TLV_DB_SCALE(sidetone_vol_tlv, -1800, 300, 0);
+
+static int snd_soc_tlv320aic23_put_volsw(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	u16 val, reg;
+
+	val = (ucontrol->value.integer.value[0] & 0x07);
+
+	/* linear conversion to userspace
+	* 000	=	-6db
+	* 001	=	-9db
+	* 010	=	-12db
+	* 011	=	-18db (Min)
+	* 100	=	0db (Max)
+	*/
+	val = (val >= 4) ? 4  : (3 - val);
+
+	reg = tlv320aic23_read_reg_cache(codec, TLV320AIC23_ANLG) & (~0x1C0);
+	tlv320aic23_write(codec, TLV320AIC23_ANLG, reg | (val << 6));
+
+	return 0;
+}
+
+static int snd_soc_tlv320aic23_get_volsw(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	u16 val;
+
+	val = tlv320aic23_read_reg_cache(codec, TLV320AIC23_ANLG) & (0x1C0);
+	val = val >> 6;
+	val = (val >= 4) ? 4  : (3 -  val);
+	ucontrol->value.integer.value[0] = val;
+	return 0;
+
+}
+
+#define SOC_TLV320AIC23_SINGLE_TLV(xname, reg, shift, max, invert, tlv_array) \
+{	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+	.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\
+		 SNDRV_CTL_ELEM_ACCESS_READWRITE,\
+	.tlv.p = (tlv_array), \
+	.info = snd_soc_info_volsw, .get = snd_soc_tlv320aic23_get_volsw,\
+	.put = snd_soc_tlv320aic23_put_volsw, \
+	.private_value =  SOC_SINGLE_VALUE(reg, shift, max, invert) }
+
+static const struct snd_kcontrol_new tlv320aic23_snd_controls[] = {
+	SOC_DOUBLE_R_TLV("Digital Playback Volume", TLV320AIC23_LCHNVOL,
+			 TLV320AIC23_RCHNVOL, 0, 127, 0, out_gain_tlv),
+	SOC_SINGLE("Digital Playback Switch", TLV320AIC23_DIGT, 3, 1, 1),
+	SOC_DOUBLE_R("Line Input Switch", TLV320AIC23_LINVOL,
+		     TLV320AIC23_RINVOL, 7, 1, 0),
+	SOC_DOUBLE_R_TLV("Line Input Volume", TLV320AIC23_LINVOL,
+			 TLV320AIC23_RINVOL, 0, 31, 0, input_gain_tlv),
+	SOC_SINGLE("Mic Input Switch", TLV320AIC23_ANLG, 1, 1, 1),
+	SOC_SINGLE("Mic Booster Switch", TLV320AIC23_ANLG, 0, 1, 0),
+	SOC_TLV320AIC23_SINGLE_TLV("Sidetone Volume", TLV320AIC23_ANLG,
+				  6, 4, 0, sidetone_vol_tlv),
+	SOC_ENUM("Playback De-emphasis", tlv320aic23_deemph),
+};
+
+/* add non dapm controls */
+static int tlv320aic23_add_controls(struct snd_soc_codec *codec)
+{
+
+	int err, i;
+
+	for (i = 0; i < ARRAY_SIZE(tlv320aic23_snd_controls); i++) {
+		err = snd_ctl_add(codec->card,
+				  snd_soc_cnew(&tlv320aic23_snd_controls[i],
+					       codec, NULL));
+		if (err < 0)
+			return err;
+	}
+
+	return 0;
+
+}
+
+/* PGA Mixer controls for Line and Mic switch */
+static const struct snd_kcontrol_new tlv320aic23_output_mixer_controls[] = {
+	SOC_DAPM_SINGLE("Line Bypass Switch", TLV320AIC23_ANLG, 3, 1, 0),
+	SOC_DAPM_SINGLE("Mic Sidetone Switch", TLV320AIC23_ANLG, 5, 1, 0),
+	SOC_DAPM_SINGLE("Playback Switch", TLV320AIC23_ANLG, 4, 1, 0),
+};
+
+static const struct snd_soc_dapm_widget tlv320aic23_dapm_widgets[] = {
+	SND_SOC_DAPM_DAC("DAC", "Playback", TLV320AIC23_PWR, 3, 1),
+	SND_SOC_DAPM_ADC("ADC", "Capture", TLV320AIC23_PWR, 2, 1),
+	SND_SOC_DAPM_MUX("Capture Source", SND_SOC_NOPM, 0, 0,
+			 &tlv320aic23_rec_src_mux_controls),
+	SND_SOC_DAPM_MIXER("Output Mixer", TLV320AIC23_PWR, 4, 1,
+			   &tlv320aic23_output_mixer_controls[0],
+			   ARRAY_SIZE(tlv320aic23_output_mixer_controls)),
+	SND_SOC_DAPM_PGA("Line Input", TLV320AIC23_PWR, 0, 1, NULL, 0),
+	SND_SOC_DAPM_PGA("Mic Input", TLV320AIC23_PWR, 1, 1, NULL, 0),
+
+	SND_SOC_DAPM_OUTPUT("LHPOUT"),
+	SND_SOC_DAPM_OUTPUT("RHPOUT"),
+	SND_SOC_DAPM_OUTPUT("LOUT"),
+	SND_SOC_DAPM_OUTPUT("ROUT"),
+
+	SND_SOC_DAPM_INPUT("LLINEIN"),
+	SND_SOC_DAPM_INPUT("RLINEIN"),
+
+	SND_SOC_DAPM_INPUT("MICIN"),
+};
+
+static const struct snd_soc_dapm_route intercon[] = {
+	/* Output Mixer */
+	{"Output Mixer", "Line Bypass Switch", "Line Input"},
+	{"Output Mixer", "Playback Switch", "DAC"},
+	{"Output Mixer", "Mic Sidetone Switch", "Mic Input"},
+
+	/* Outputs */
+	{"RHPOUT", NULL, "Output Mixer"},
+	{"LHPOUT", NULL, "Output Mixer"},
+	{"LOUT", NULL, "Output Mixer"},
+	{"ROUT", NULL, "Output Mixer"},
+
+	/* Inputs */
+	{"Line Input", "NULL", "LLINEIN"},
+	{"Line Input", "NULL", "RLINEIN"},
+
+	{"Mic Input", "NULL", "MICIN"},
+
+	/* input mux */
+	{"Capture Source", "Line", "Line Input"},
+	{"Capture Source", "Mic", "Mic Input"},
+	{"ADC", NULL, "Capture Source"},
+
+};
+
+/* tlv320aic23 related */
+static const struct tlv320aic23_srate_reg_info srate_reg_info[] = {
+	{4000, 0x06, 1},	/*  4000 */
+	{8000, 0x06, 0},	/*  8000 */
+	{16000, 0x0C, 1},	/* 16000 */
+	{22050, 0x11, 1},	/* 22050 */
+	{24000, 0x00, 1},	/* 24000 */
+	{32000, 0x0C, 0},	/* 32000 */
+	{44100, 0x11, 0},	/* 44100 */
+	{48000, 0x00, 0},	/* 48000 */
+	{88200, 0x1F, 0},	/* 88200 */
+	{96000, 0x0E, 0},	/* 96000 */
+};
+
+static int tlv320aic23_add_widgets(struct snd_soc_codec *codec)
+{
+	snd_soc_dapm_new_controls(codec, tlv320aic23_dapm_widgets,
+				  ARRAY_SIZE(tlv320aic23_dapm_widgets));
+
+	/* set up audio path interconnects */
+	snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon));
+
+	snd_soc_dapm_new_widgets(codec);
+	return 0;
+}
+
+static int tlv320aic23_hw_params(struct snd_pcm_substream *substream,
+				 struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_device *socdev = rtd->socdev;
+	struct snd_soc_codec *codec = socdev->codec;
+	u16 iface_reg, data;
+	u8 count = 0;
+
+	iface_reg =
+	    tlv320aic23_read_reg_cache(codec,
+				       TLV320AIC23_DIGT_FMT) & ~(0x03 << 2);
+
+	/* Search for the right sample rate */
+	/* Verify what happens if the rate is not supported
+	 * now it goes to 96Khz */
+	while ((srate_reg_info[count].sample_rate != params_rate(params)) &&
+	       (count < ARRAY_SIZE(srate_reg_info))) {
+		count++;
+	}
+
+	data =  (srate_reg_info[count].divider << TLV320AIC23_CLKIN_SHIFT) |
+		(srate_reg_info[count]. control << TLV320AIC23_BOSR_SHIFT) |
+		TLV320AIC23_USB_CLK_ON;
+
+	tlv320aic23_write(codec, TLV320AIC23_SRATE, data);
+
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S16_LE:
+		break;
+	case SNDRV_PCM_FORMAT_S20_3LE:
+		iface_reg |= (0x01 << 2);
+		break;
+	case SNDRV_PCM_FORMAT_S24_LE:
+		iface_reg |= (0x02 << 2);
+		break;
+	case SNDRV_PCM_FORMAT_S32_LE:
+		iface_reg |= (0x03 << 2);
+		break;
+	}
+	tlv320aic23_write(codec, TLV320AIC23_DIGT_FMT, iface_reg);
+
+	return 0;
+}
+
+static int tlv320aic23_pcm_prepare(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_device *socdev = rtd->socdev;
+	struct snd_soc_codec *codec = socdev->codec;
+
+	/* set active */
+	tlv320aic23_write(codec, TLV320AIC23_ACTIVE, 0x0001);
+
+	return 0;
+}
+
+static void tlv320aic23_shutdown(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_device *socdev = rtd->socdev;
+	struct snd_soc_codec *codec = socdev->codec;
+
+	/* deactivate */
+	if (!codec->active) {
+		udelay(50);
+		tlv320aic23_write(codec, TLV320AIC23_ACTIVE, 0x0);
+	}
+}
+
+static int tlv320aic23_mute(struct snd_soc_dai *dai, int mute)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	u16 reg;
+
+	reg = tlv320aic23_read_reg_cache(codec, TLV320AIC23_DIGT);
+	if (mute)
+		reg |= TLV320AIC23_DACM_MUTE;
+
+	else
+		reg &= ~TLV320AIC23_DACM_MUTE;
+
+	tlv320aic23_write(codec, TLV320AIC23_DIGT, reg);
+
+	return 0;
+}
+
+static int tlv320aic23_set_dai_fmt(struct snd_soc_dai *codec_dai,
+				   unsigned int fmt)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+	u16 iface_reg;
+
+	iface_reg =
+	    tlv320aic23_read_reg_cache(codec, TLV320AIC23_DIGT_FMT) & (~0x03);
+
+	/* set master/slave audio interface */
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		iface_reg |= TLV320AIC23_MS_MASTER;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		break;
+	default:
+		return -EINVAL;
+
+	}
+
+	/* interface format */
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		iface_reg |= TLV320AIC23_FOR_I2S;
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		iface_reg |= TLV320AIC23_FOR_DSP;
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		iface_reg |= TLV320AIC23_FOR_LJUST;
+		break;
+	default:
+		return -EINVAL;
+
+	}
+
+	tlv320aic23_write(codec, TLV320AIC23_DIGT_FMT, iface_reg);
+
+	return 0;
+}
+
+static int tlv320aic23_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+				      int clk_id, unsigned int freq, int dir)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+
+	switch (freq) {
+	case 12000000:
+		return 0;
+	}
+	return -EINVAL;
+}
+
+static int tlv320aic23_set_bias_level(struct snd_soc_codec *codec,
+				      enum snd_soc_bias_level level)
+{
+	u16 reg = tlv320aic23_read_reg_cache(codec, TLV320AIC23_PWR) & 0xff7f;
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		/* vref/mid, osc on, dac unmute */
+		tlv320aic23_write(codec, TLV320AIC23_PWR, reg);
+		break;
+	case SND_SOC_BIAS_PREPARE:
+		break;
+	case SND_SOC_BIAS_STANDBY:
+		/* everything off except vref/vmid, */
+		tlv320aic23_write(codec, TLV320AIC23_PWR, reg | 0x0040);
+		break;
+	case SND_SOC_BIAS_OFF:
+		/* everything off, dac mute, inactive */
+		tlv320aic23_write(codec, TLV320AIC23_ACTIVE, 0x0);
+		tlv320aic23_write(codec, TLV320AIC23_PWR, 0xffff);
+		break;
+	}
+	codec->bias_level = level;
+	return 0;
+}
+
+#define AIC23_RATES	SNDRV_PCM_RATE_8000_96000
+#define AIC23_FORMATS	(SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
+			 SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+struct snd_soc_dai tlv320aic23_dai = {
+	.name = "tlv320aic23",
+	.playback = {
+		     .stream_name = "Playback",
+		     .channels_min = 2,
+		     .channels_max = 2,
+		     .rates = AIC23_RATES,
+		     .formats = AIC23_FORMATS,},
+	.capture = {
+		    .stream_name = "Capture",
+		    .channels_min = 2,
+		    .channels_max = 2,
+		    .rates = AIC23_RATES,
+		    .formats = AIC23_FORMATS,},
+	.ops = {
+		.prepare = tlv320aic23_pcm_prepare,
+		.hw_params = tlv320aic23_hw_params,
+		.shutdown = tlv320aic23_shutdown,
+		},
+	.dai_ops = {
+		    .digital_mute = tlv320aic23_mute,
+		    .set_fmt = tlv320aic23_set_dai_fmt,
+		    .set_sysclk = tlv320aic23_set_dai_sysclk,
+		    }
+};
+EXPORT_SYMBOL_GPL(tlv320aic23_dai);
+
+static int tlv320aic23_suspend(struct platform_device *pdev,
+			       pm_message_t state)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	struct snd_soc_codec *codec = socdev->codec;
+
+	tlv320aic23_write(codec, TLV320AIC23_ACTIVE, 0x0);
+	tlv320aic23_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
+	return 0;
+}
+
+static int tlv320aic23_resume(struct platform_device *pdev)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	struct snd_soc_codec *codec = socdev->codec;
+	int i;
+	u16 reg;
+
+	/* Sync reg_cache with the hardware */
+	for (reg = 0; reg < ARRAY_SIZE(tlv320aic23_reg); i++) {
+		u16 val = tlv320aic23_read_reg_cache(codec, reg);
+		tlv320aic23_write(codec, reg, val);
+	}
+
+	tlv320aic23_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+	tlv320aic23_set_bias_level(codec, codec->suspend_bias_level);
+
+	return 0;
+}
+
+/*
+ * initialise the AIC23 driver
+ * register the mixer and dsp interfaces with the kernel
+ */
+static int tlv320aic23_init(struct snd_soc_device *socdev)
+{
+	struct snd_soc_codec *codec = socdev->codec;
+	int ret = 0;
+	u16 reg;
+
+	codec->name = "tlv320aic23";
+	codec->owner = THIS_MODULE;
+	codec->read = tlv320aic23_read_reg_cache;
+	codec->write = tlv320aic23_write;
+	codec->set_bias_level = tlv320aic23_set_bias_level;
+	codec->dai = &tlv320aic23_dai;
+	codec->num_dai = 1;
+	codec->reg_cache_size = ARRAY_SIZE(tlv320aic23_reg);
+	codec->reg_cache =
+	    kmemdup(tlv320aic23_reg, sizeof(tlv320aic23_reg), GFP_KERNEL);
+	if (codec->reg_cache == NULL)
+		return -ENOMEM;
+
+	/* Reset codec */
+	tlv320aic23_write(codec, TLV320AIC23_RESET, 0);
+
+	/* register pcms */
+	ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
+	if (ret < 0) {
+		printk(KERN_ERR "tlv320aic23: failed to create pcms\n");
+		goto pcm_err;
+	}
+
+	/* power on device */
+	tlv320aic23_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+	tlv320aic23_write(codec, TLV320AIC23_DIGT, TLV320AIC23_DEEMP_44K);
+
+	/* Unmute input */
+	reg = tlv320aic23_read_reg_cache(codec, TLV320AIC23_LINVOL);
+	tlv320aic23_write(codec, TLV320AIC23_LINVOL,
+			  (reg & (~TLV320AIC23_LIM_MUTED)) |
+			  (TLV320AIC23_LRS_ENABLED));
+
+	reg = tlv320aic23_read_reg_cache(codec, TLV320AIC23_RINVOL);
+	tlv320aic23_write(codec, TLV320AIC23_RINVOL,
+			  (reg & (~TLV320AIC23_LIM_MUTED)) |
+			  TLV320AIC23_LRS_ENABLED);
+
+	reg = tlv320aic23_read_reg_cache(codec, TLV320AIC23_ANLG);
+	tlv320aic23_write(codec, TLV320AIC23_ANLG,
+			 (reg) & (~TLV320AIC23_BYPASS_ON) &
+			 (~TLV320AIC23_MICM_MUTED));
+
+	/* Default output volume */
+	tlv320aic23_write(codec, TLV320AIC23_LCHNVOL,
+			  TLV320AIC23_DEFAULT_OUT_VOL &
+			  TLV320AIC23_OUT_VOL_MASK);
+	tlv320aic23_write(codec, TLV320AIC23_RCHNVOL,
+			  TLV320AIC23_DEFAULT_OUT_VOL &
+			  TLV320AIC23_OUT_VOL_MASK);
+
+	tlv320aic23_write(codec, TLV320AIC23_ACTIVE, 0x1);
+
+	tlv320aic23_add_controls(codec);
+	tlv320aic23_add_widgets(codec);
+	ret = snd_soc_register_card(socdev);
+	if (ret < 0) {
+		printk(KERN_ERR "tlv320aic23: failed to register card\n");
+		goto card_err;
+	}
+
+	return ret;
+
+card_err:
+	snd_soc_free_pcms(socdev);
+	snd_soc_dapm_free(socdev);
+pcm_err:
+	kfree(codec->reg_cache);
+	return ret;
+}
+static struct snd_soc_device *tlv320aic23_socdev;
+
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+/*
+ * If the i2c layer weren't so broken, we could pass this kind of data
+ * around
+ */
+static int tlv320aic23_codec_probe(struct i2c_client *i2c,
+				   const struct i2c_device_id *i2c_id)
+{
+	struct snd_soc_device *socdev = tlv320aic23_socdev;
+	struct snd_soc_codec *codec = socdev->codec;
+	int ret;
+
+	if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+		return -EINVAL;
+
+	i2c_set_clientdata(i2c, codec);
+	codec->control_data = i2c;
+
+	ret = tlv320aic23_init(socdev);
+	if (ret < 0) {
+		printk(KERN_ERR "tlv320aic23: failed to initialise AIC23\n");
+		goto err;
+	}
+	return ret;
+
+err:
+	kfree(codec);
+	kfree(i2c);
+	return ret;
+}
+static int __exit tlv320aic23_i2c_remove(struct i2c_client *i2c)
+{
+	put_device(&i2c->dev);
+	return 0;
+}
+
+static const struct i2c_device_id tlv320aic23_id[] = {
+	{"tlv320aic23", 0},
+	{}
+};
+
+MODULE_DEVICE_TABLE(i2c, tlv320aic23_id);
+
+static struct i2c_driver tlv320aic23_i2c_driver = {
+	.driver = {
+		   .name = "tlv320aic23",
+		   },
+	.probe = tlv320aic23_codec_probe,
+	.remove = __exit_p(tlv320aic23_i2c_remove),
+	.id_table = tlv320aic23_id,
+};
+
+#endif
+
+static int tlv320aic23_probe(struct platform_device *pdev)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	struct snd_soc_codec *codec;
+	int ret = 0;
+
+	printk(KERN_INFO "AIC23 Audio Codec %s\n", AIC23_VERSION);
+
+	codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
+	if (codec == NULL)
+		return -ENOMEM;
+
+	socdev->codec = codec;
+	mutex_init(&codec->mutex);
+	INIT_LIST_HEAD(&codec->dapm_widgets);
+	INIT_LIST_HEAD(&codec->dapm_paths);
+
+	tlv320aic23_socdev = socdev;
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+	codec->hw_write = (hw_write_t) i2c_smbus_write_byte_data;
+	codec->hw_read = NULL;
+	ret = i2c_add_driver(&tlv320aic23_i2c_driver);
+	if (ret != 0)
+		printk(KERN_ERR "can't add i2c driver");
+#endif
+	return ret;
+}
+
+static int tlv320aic23_remove(struct platform_device *pdev)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	struct snd_soc_codec *codec = socdev->codec;
+
+	if (codec->control_data)
+		tlv320aic23_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
+	snd_soc_free_pcms(socdev);
+	snd_soc_dapm_free(socdev);
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+	i2c_del_driver(&tlv320aic23_i2c_driver);
+#endif
+	kfree(codec->reg_cache);
+	kfree(codec);
+
+	return 0;
+}
+struct snd_soc_codec_device soc_codec_dev_tlv320aic23 = {
+	.probe = tlv320aic23_probe,
+	.remove = tlv320aic23_remove,
+	.suspend = tlv320aic23_suspend,
+	.resume = tlv320aic23_resume,
+};
+EXPORT_SYMBOL_GPL(soc_codec_dev_tlv320aic23);
+
+MODULE_DESCRIPTION("ASoC TLV320AIC23 codec driver");
+MODULE_AUTHOR("Arun KS <arunks@mistralsolutions.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/tlv320aic23.h b/sound/soc/codecs/tlv320aic23.h
new file mode 100644
index 0000000..79d1faf
--- /dev/null
+++ b/sound/soc/codecs/tlv320aic23.h
@@ -0,0 +1,122 @@
+/*
+ * ALSA SoC TLV320AIC23 codec driver
+ *
+ * Author:      Arun KS, <arunks@mistralsolutions.com>
+ * Copyright:   (C) 2008 Mistral Solutions Pvt Ltd
+ *
+ * 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 _TLV320AIC23_H
+#define _TLV320AIC23_H
+
+/* Codec TLV320AIC23 */
+#define TLV320AIC23_LINVOL		0x00
+#define TLV320AIC23_RINVOL		0x01
+#define TLV320AIC23_LCHNVOL		0x02
+#define TLV320AIC23_RCHNVOL		0x03
+#define TLV320AIC23_ANLG		0x04
+#define TLV320AIC23_DIGT		0x05
+#define TLV320AIC23_PWR			0x06
+#define TLV320AIC23_DIGT_FMT		0x07
+#define TLV320AIC23_SRATE		0x08
+#define TLV320AIC23_ACTIVE		0x09
+#define TLV320AIC23_RESET		0x0F
+
+/* Left (right) line input volume control register */
+#define TLV320AIC23_LRS_ENABLED		0x0100
+#define TLV320AIC23_LIM_MUTED		0x0080
+#define TLV320AIC23_LIV_DEFAULT		0x0017
+#define TLV320AIC23_LIV_MAX		0x001f
+#define TLV320AIC23_LIV_MIN		0x0000
+
+/* Left (right) channel headphone volume control register */
+#define TLV320AIC23_LZC_ON		0x0080
+#define TLV320AIC23_LHV_DEFAULT		0x0079
+#define TLV320AIC23_LHV_MAX		0x007f
+#define TLV320AIC23_LHV_MIN		0x0000
+
+/* Analog audio path control register */
+#define TLV320AIC23_STA_REG(x)		((x)<<6)
+#define TLV320AIC23_STE_ENABLED		0x0020
+#define TLV320AIC23_DAC_SELECTED	0x0010
+#define TLV320AIC23_BYPASS_ON		0x0008
+#define TLV320AIC23_INSEL_MIC		0x0004
+#define TLV320AIC23_MICM_MUTED		0x0002
+#define TLV320AIC23_MICB_20DB		0x0001
+
+/* Digital audio path control register */
+#define TLV320AIC23_DACM_MUTE		0x0008
+#define TLV320AIC23_DEEMP_32K		0x0002
+#define TLV320AIC23_DEEMP_44K		0x0004
+#define TLV320AIC23_DEEMP_48K		0x0006
+#define TLV320AIC23_ADCHP_ON		0x0001
+
+/* Power control down register */
+#define TLV320AIC23_DEVICE_PWR_OFF  	0x0080
+#define TLV320AIC23_CLK_OFF		0x0040
+#define TLV320AIC23_OSC_OFF		0x0020
+#define TLV320AIC23_OUT_OFF		0x0010
+#define TLV320AIC23_DAC_OFF		0x0008
+#define TLV320AIC23_ADC_OFF		0x0004
+#define TLV320AIC23_MIC_OFF		0x0002
+#define TLV320AIC23_LINE_OFF		0x0001
+
+/* Digital audio interface register */
+#define TLV320AIC23_MS_MASTER		0x0040
+#define TLV320AIC23_LRSWAP_ON		0x0020
+#define TLV320AIC23_LRP_ON		0x0010
+#define TLV320AIC23_IWL_16		0x0000
+#define TLV320AIC23_IWL_20		0x0004
+#define TLV320AIC23_IWL_24		0x0008
+#define TLV320AIC23_IWL_32		0x000C
+#define TLV320AIC23_FOR_I2S		0x0002
+#define TLV320AIC23_FOR_DSP		0x0003
+#define TLV320AIC23_FOR_LJUST		0x0001
+
+/* Sample rate control register */
+#define TLV320AIC23_CLKOUT_HALF		0x0080
+#define TLV320AIC23_CLKIN_HALF		0x0040
+#define TLV320AIC23_BOSR_384fs		0x0002	/* BOSR_272fs in USB mode */
+#define TLV320AIC23_USB_CLK_ON		0x0001
+#define TLV320AIC23_SR_MASK             0xf
+#define TLV320AIC23_CLKOUT_SHIFT        7
+#define TLV320AIC23_CLKIN_SHIFT         6
+#define TLV320AIC23_SR_SHIFT            2
+#define TLV320AIC23_BOSR_SHIFT          1
+
+/* Digital interface register */
+#define TLV320AIC23_ACT_ON		0x0001
+
+/*
+ * AUDIO related MACROS
+ */
+
+#define TLV320AIC23_DEFAULT_OUT_VOL	0x70
+#define TLV320AIC23_DEFAULT_IN_VOLUME	0x10
+
+#define TLV320AIC23_OUT_VOL_MIN		TLV320AIC23_LHV_MIN
+#define TLV320AIC23_OUT_VOL_MAX		TLV320AIC23_LHV_MAX
+#define TLV320AIC23_OUT_VO_RANGE	(TLV320AIC23_OUT_VOL_MAX - \
+					TLV320AIC23_OUT_VOL_MIN)
+#define TLV320AIC23_OUT_VOL_MASK	TLV320AIC23_OUT_VOL_MAX
+
+#define TLV320AIC23_IN_VOL_MIN		TLV320AIC23_LIV_MIN
+#define TLV320AIC23_IN_VOL_MAX		TLV320AIC23_LIV_MAX
+#define TLV320AIC23_IN_VOL_RANGE	(TLV320AIC23_IN_VOL_MAX - \
+					TLV320AIC23_IN_VOL_MIN)
+#define TLV320AIC23_IN_VOL_MASK		TLV320AIC23_IN_VOL_MAX
+
+#define TLV320AIC23_SIDETONE_MASK	0x1c0
+#define TLV320AIC23_SIDETONE_0		0x100
+#define TLV320AIC23_SIDETONE_6		0x000
+#define TLV320AIC23_SIDETONE_9		0x040
+#define TLV320AIC23_SIDETONE_12		0x080
+#define TLV320AIC23_SIDETONE_18		0x0c0
+
+extern struct snd_soc_dai tlv320aic23_dai;
+extern struct snd_soc_codec_device soc_codec_dev_tlv320aic23;
+
+#endif /* _TLV320AIC23_H */
diff --git a/sound/soc/codecs/tlv320aic26.c b/sound/soc/codecs/tlv320aic26.c
new file mode 100644
index 0000000..bed8a9e
--- /dev/null
+++ b/sound/soc/codecs/tlv320aic26.c
@@ -0,0 +1,520 @@
+/*
+ * Texas Instruments TLV320AIC26 low power audio CODEC
+ * ALSA SoC CODEC driver
+ *
+ * Copyright (C) 2008 Secret Lab Technologies Ltd.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/device.h>
+#include <linux/sysfs.h>
+#include <linux/spi/spi.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/soc-of-simple.h>
+#include <sound/initval.h>
+
+#include "tlv320aic26.h"
+
+MODULE_DESCRIPTION("ASoC TLV320AIC26 codec driver");
+MODULE_AUTHOR("Grant Likely <grant.likely@secretlab.ca>");
+MODULE_LICENSE("GPL");
+
+/* AIC26 driver private data */
+struct aic26 {
+	struct spi_device *spi;
+	struct snd_soc_codec codec;
+	u16 reg_cache[AIC26_NUM_REGS];	/* shadow registers */
+	int master;
+	int datfm;
+	int mclk;
+
+	/* Keyclick parameters */
+	int keyclick_amplitude;
+	int keyclick_freq;
+	int keyclick_len;
+};
+
+/* ---------------------------------------------------------------------
+ * Register access routines
+ */
+static unsigned int aic26_reg_read(struct snd_soc_codec *codec,
+				   unsigned int reg)
+{
+	struct aic26 *aic26 = codec->private_data;
+	u16 *cache = codec->reg_cache;
+	u16 cmd, value;
+	u8 buffer[2];
+	int rc;
+
+	if (reg >= AIC26_NUM_REGS) {
+		WARN_ON_ONCE(1);
+		return 0;
+	}
+
+	/* Do SPI transfer; first 16bits are command; remaining is
+	 * register contents */
+	cmd = AIC26_READ_COMMAND_WORD(reg);
+	buffer[0] = (cmd >> 8) & 0xff;
+	buffer[1] = cmd & 0xff;
+	rc = spi_write_then_read(aic26->spi, buffer, 2, buffer, 2);
+	if (rc) {
+		dev_err(&aic26->spi->dev, "AIC26 reg read error\n");
+		return -EIO;
+	}
+	value = (buffer[0] << 8) | buffer[1];
+
+	/* Update the cache before returning with the value */
+	cache[reg] = value;
+	return value;
+}
+
+static unsigned int aic26_reg_read_cache(struct snd_soc_codec *codec,
+					 unsigned int reg)
+{
+	u16 *cache = codec->reg_cache;
+
+	if (reg >= AIC26_NUM_REGS) {
+		WARN_ON_ONCE(1);
+		return 0;
+	}
+
+	return cache[reg];
+}
+
+static int aic26_reg_write(struct snd_soc_codec *codec, unsigned int reg,
+			   unsigned int value)
+{
+	struct aic26 *aic26 = codec->private_data;
+	u16 *cache = codec->reg_cache;
+	u16 cmd;
+	u8 buffer[4];
+	int rc;
+
+	if (reg >= AIC26_NUM_REGS) {
+		WARN_ON_ONCE(1);
+		return -EINVAL;
+	}
+
+	/* Do SPI transfer; first 16bits are command; remaining is data
+	 * to write into register */
+	cmd = AIC26_WRITE_COMMAND_WORD(reg);
+	buffer[0] = (cmd >> 8) & 0xff;
+	buffer[1] = cmd & 0xff;
+	buffer[2] = value >> 8;
+	buffer[3] = value;
+	rc = spi_write(aic26->spi, buffer, 4);
+	if (rc) {
+		dev_err(&aic26->spi->dev, "AIC26 reg read error\n");
+		return -EIO;
+	}
+
+	/* update cache before returning */
+	cache[reg] = value;
+	return 0;
+}
+
+/* ---------------------------------------------------------------------
+ * Digital Audio Interface Operations
+ */
+static int aic26_hw_params(struct snd_pcm_substream *substream,
+			   struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_device *socdev = rtd->socdev;
+	struct snd_soc_codec *codec = socdev->codec;
+	struct aic26 *aic26 = codec->private_data;
+	int fsref, divisor, wlen, pval, jval, dval, qval;
+	u16 reg;
+
+	dev_dbg(&aic26->spi->dev, "aic26_hw_params(substream=%p, params=%p)\n",
+		substream, params);
+	dev_dbg(&aic26->spi->dev, "rate=%i format=%i\n", params_rate(params),
+		params_format(params));
+
+	switch (params_rate(params)) {
+	case 8000:  fsref = 48000; divisor = AIC26_DIV_6; break;
+	case 11025: fsref = 44100; divisor = AIC26_DIV_4; break;
+	case 12000: fsref = 48000; divisor = AIC26_DIV_4; break;
+	case 16000: fsref = 48000; divisor = AIC26_DIV_3; break;
+	case 22050: fsref = 44100; divisor = AIC26_DIV_2; break;
+	case 24000: fsref = 48000; divisor = AIC26_DIV_2; break;
+	case 32000: fsref = 48000; divisor = AIC26_DIV_1_5; break;
+	case 44100: fsref = 44100; divisor = AIC26_DIV_1; break;
+	case 48000: fsref = 48000; divisor = AIC26_DIV_1; break;
+	default:
+		dev_dbg(&aic26->spi->dev, "bad rate\n"); return -EINVAL;
+	}
+
+	/* select data word length */
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S8:     wlen = AIC26_WLEN_16; break;
+	case SNDRV_PCM_FORMAT_S16_BE: wlen = AIC26_WLEN_16; break;
+	case SNDRV_PCM_FORMAT_S24_BE: wlen = AIC26_WLEN_24; break;
+	case SNDRV_PCM_FORMAT_S32_BE: wlen = AIC26_WLEN_32; break;
+	default:
+		dev_dbg(&aic26->spi->dev, "bad format\n"); return -EINVAL;
+	}
+
+	/* Configure PLL */
+	pval = 1;
+	jval = (fsref == 44100) ? 7 : 8;
+	dval = (fsref == 44100) ? 5264 : 1920;
+	qval = 0;
+	reg = 0x8000 | qval << 11 | pval << 8 | jval << 2;
+	aic26_reg_write(codec, AIC26_REG_PLL_PROG1, reg);
+	reg = dval << 2;
+	aic26_reg_write(codec, AIC26_REG_PLL_PROG2, reg);
+
+	/* Audio Control 3 (master mode, fsref rate) */
+	reg = aic26_reg_read_cache(codec, AIC26_REG_AUDIO_CTRL3);
+	reg &= ~0xf800;
+	if (aic26->master)
+		reg |= 0x0800;
+	if (fsref == 48000)
+		reg |= 0x2000;
+	aic26_reg_write(codec, AIC26_REG_AUDIO_CTRL3, reg);
+
+	/* Audio Control 1 (FSref divisor) */
+	reg = aic26_reg_read_cache(codec, AIC26_REG_AUDIO_CTRL1);
+	reg &= ~0x0fff;
+	reg |= wlen | aic26->datfm | (divisor << 3) | divisor;
+	aic26_reg_write(codec, AIC26_REG_AUDIO_CTRL1, reg);
+
+	return 0;
+}
+
+/**
+ * aic26_mute - Mute control to reduce noise when changing audio format
+ */
+static int aic26_mute(struct snd_soc_dai *dai, int mute)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	struct aic26 *aic26 = codec->private_data;
+	u16 reg = aic26_reg_read_cache(codec, AIC26_REG_DAC_GAIN);
+
+	dev_dbg(&aic26->spi->dev, "aic26_mute(dai=%p, mute=%i)\n",
+		dai, mute);
+
+	if (mute)
+		reg |= 0x8080;
+	else
+		reg &= ~0x8080;
+	aic26_reg_write(codec, AIC26_REG_DAC_GAIN, reg);
+
+	return 0;
+}
+
+static int aic26_set_sysclk(struct snd_soc_dai *codec_dai,
+			    int clk_id, unsigned int freq, int dir)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+	struct aic26 *aic26 = codec->private_data;
+
+	dev_dbg(&aic26->spi->dev, "aic26_set_sysclk(dai=%p, clk_id==%i,"
+		" freq=%i, dir=%i)\n",
+		codec_dai, clk_id, freq, dir);
+
+	/* MCLK needs to fall between 2MHz and 50 MHz */
+	if ((freq < 2000000) || (freq > 50000000))
+		return -EINVAL;
+
+	aic26->mclk = freq;
+	return 0;
+}
+
+static int aic26_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+	struct aic26 *aic26 = codec->private_data;
+
+	dev_dbg(&aic26->spi->dev, "aic26_set_fmt(dai=%p, fmt==%i)\n",
+		codec_dai, fmt);
+
+	/* set master/slave audio interface */
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM: aic26->master = 1; break;
+	case SND_SOC_DAIFMT_CBS_CFS: aic26->master = 0; break;
+	default:
+		dev_dbg(&aic26->spi->dev, "bad master\n"); return -EINVAL;
+	}
+
+	/* interface format */
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:     aic26->datfm = AIC26_DATFM_I2S; break;
+	case SND_SOC_DAIFMT_DSP_A:   aic26->datfm = AIC26_DATFM_DSP; break;
+	case SND_SOC_DAIFMT_RIGHT_J: aic26->datfm = AIC26_DATFM_RIGHTJ; break;
+	case SND_SOC_DAIFMT_LEFT_J:  aic26->datfm = AIC26_DATFM_LEFTJ; break;
+	default:
+		dev_dbg(&aic26->spi->dev, "bad format\n"); return -EINVAL;
+	}
+
+	return 0;
+}
+
+/* ---------------------------------------------------------------------
+ * Digital Audio Interface Definition
+ */
+#define AIC26_RATES	(SNDRV_PCM_RATE_8000  | SNDRV_PCM_RATE_11025 |\
+			 SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |\
+			 SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |\
+			 SNDRV_PCM_RATE_48000)
+#define AIC26_FORMATS	(SNDRV_PCM_FMTBIT_S8     | SNDRV_PCM_FMTBIT_S16_BE |\
+			 SNDRV_PCM_FMTBIT_S24_BE | SNDRV_PCM_FMTBIT_S32_BE)
+
+struct snd_soc_dai aic26_dai = {
+	.name = "tlv320aic26",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = AIC26_RATES,
+		.formats = AIC26_FORMATS,
+	},
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = AIC26_RATES,
+		.formats = AIC26_FORMATS,
+	},
+	.ops = {
+		.hw_params = aic26_hw_params,
+	},
+	.dai_ops = {
+		.digital_mute = aic26_mute,
+		.set_sysclk = aic26_set_sysclk,
+		.set_fmt = aic26_set_fmt,
+	},
+};
+EXPORT_SYMBOL_GPL(aic26_dai);
+
+/* ---------------------------------------------------------------------
+ * ALSA controls
+ */
+static const char *aic26_capture_src_text[] = {"Mic", "Aux"};
+static const struct soc_enum aic26_capture_src_enum =
+	SOC_ENUM_SINGLE(AIC26_REG_AUDIO_CTRL1, 12, 2, aic26_capture_src_text);
+
+static const struct snd_kcontrol_new aic26_snd_controls[] = {
+	/* Output */
+	SOC_DOUBLE("PCM Playback Volume", AIC26_REG_DAC_GAIN, 8, 0, 0x7f, 1),
+	SOC_DOUBLE("PCM Playback Switch", AIC26_REG_DAC_GAIN, 15, 7, 1, 1),
+	SOC_SINGLE("PCM Capture Volume", AIC26_REG_ADC_GAIN, 8, 0x7f, 0),
+	SOC_SINGLE("PCM Capture Mute", AIC26_REG_ADC_GAIN, 15, 1, 1),
+	SOC_SINGLE("Keyclick activate", AIC26_REG_AUDIO_CTRL2, 15, 0x1, 0),
+	SOC_SINGLE("Keyclick amplitude", AIC26_REG_AUDIO_CTRL2, 12, 0x7, 0),
+	SOC_SINGLE("Keyclick frequency", AIC26_REG_AUDIO_CTRL2, 8, 0x7, 0),
+	SOC_SINGLE("Keyclick period", AIC26_REG_AUDIO_CTRL2, 4, 0xf, 0),
+	SOC_ENUM("Capture Source", aic26_capture_src_enum),
+};
+
+/* ---------------------------------------------------------------------
+ * SoC CODEC portion of driver: probe and release routines
+ */
+static int aic26_probe(struct platform_device *pdev)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	struct snd_soc_codec *codec;
+	struct snd_kcontrol *kcontrol;
+	struct aic26 *aic26;
+	int i, ret, err;
+
+	dev_info(&pdev->dev, "Probing AIC26 SoC CODEC driver\n");
+	dev_dbg(&pdev->dev, "socdev=%p\n", socdev);
+	dev_dbg(&pdev->dev, "codec_data=%p\n", socdev->codec_data);
+
+	/* Fetch the relevant aic26 private data here (it's already been
+	 * stored in the .codec pointer) */
+	aic26 = socdev->codec_data;
+	if (aic26 == NULL) {
+		dev_err(&pdev->dev, "aic26: missing codec pointer\n");
+		return -ENODEV;
+	}
+	codec = &aic26->codec;
+	socdev->codec = codec;
+
+	dev_dbg(&pdev->dev, "Registering PCMs, dev=%p, socdev->dev=%p\n",
+		&pdev->dev, socdev->dev);
+	/* register pcms */
+	ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "aic26: failed to create pcms\n");
+		return -ENODEV;
+	}
+
+	/* register controls */
+	dev_dbg(&pdev->dev, "Registering controls\n");
+	for (i = 0; i < ARRAY_SIZE(aic26_snd_controls); i++) {
+		kcontrol = snd_soc_cnew(&aic26_snd_controls[i], codec, NULL);
+		err = snd_ctl_add(codec->card, kcontrol);
+		WARN_ON(err < 0);
+	}
+
+	/* CODEC is setup, we can register the card now */
+	dev_dbg(&pdev->dev, "Registering card\n");
+	ret = snd_soc_register_card(socdev);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "aic26: failed to register card\n");
+		goto card_err;
+	}
+	return 0;
+
+ card_err:
+	snd_soc_free_pcms(socdev);
+	return ret;
+}
+
+static int aic26_remove(struct platform_device *pdev)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	snd_soc_free_pcms(socdev);
+	return 0;
+}
+
+struct snd_soc_codec_device aic26_soc_codec_dev = {
+	.probe = aic26_probe,
+	.remove = aic26_remove,
+};
+EXPORT_SYMBOL_GPL(aic26_soc_codec_dev);
+
+/* ---------------------------------------------------------------------
+ * SPI device portion of driver: sysfs files for debugging
+ */
+
+static ssize_t aic26_keyclick_show(struct device *dev,
+				   struct device_attribute *attr, char *buf)
+{
+	struct aic26 *aic26 = dev_get_drvdata(dev);
+	int val, amp, freq, len;
+
+	val = aic26_reg_read_cache(&aic26->codec, AIC26_REG_AUDIO_CTRL2);
+	amp = (val >> 12) & 0x7;
+	freq = (125 << ((val >> 8) & 0x7)) >> 1;
+	len = 2 * (1 + ((val >> 4) & 0xf));
+
+	return sprintf(buf, "amp=%x freq=%iHz len=%iclks\n", amp, freq, len);
+}
+
+/* Any write to the keyclick attribute will trigger the keyclick event */
+static ssize_t aic26_keyclick_set(struct device *dev,
+				  struct device_attribute *attr,
+				  const char *buf, size_t count)
+{
+	struct aic26 *aic26 = dev_get_drvdata(dev);
+	int val;
+
+	val = aic26_reg_read_cache(&aic26->codec, AIC26_REG_AUDIO_CTRL2);
+	val |= 0x8000;
+	aic26_reg_write(&aic26->codec, AIC26_REG_AUDIO_CTRL2, val);
+
+	return count;
+}
+
+static DEVICE_ATTR(keyclick, 0644, aic26_keyclick_show, aic26_keyclick_set);
+
+/* ---------------------------------------------------------------------
+ * SPI device portion of driver: probe and release routines and SPI
+ * 				 driver registration.
+ */
+static int aic26_spi_probe(struct spi_device *spi)
+{
+	struct aic26 *aic26;
+	int rc, i, reg;
+
+	dev_dbg(&spi->dev, "probing tlv320aic26 spi device\n");
+
+	/* Allocate driver data */
+	aic26 = kzalloc(sizeof *aic26, GFP_KERNEL);
+	if (!aic26)
+		return -ENOMEM;
+
+	/* Initialize the driver data */
+	aic26->spi = spi;
+	dev_set_drvdata(&spi->dev, aic26);
+
+	/* Setup what we can in the codec structure so that the register
+	 * access functions will work as expected.  More will be filled
+	 * out when it is probed by the SoC CODEC part of this driver */
+	aic26->codec.private_data = aic26;
+	aic26->codec.name = "aic26";
+	aic26->codec.owner = THIS_MODULE;
+	aic26->codec.dai = &aic26_dai;
+	aic26->codec.num_dai = 1;
+	aic26->codec.read = aic26_reg_read;
+	aic26->codec.write = aic26_reg_write;
+	aic26->master = 1;
+	mutex_init(&aic26->codec.mutex);
+	INIT_LIST_HEAD(&aic26->codec.dapm_widgets);
+	INIT_LIST_HEAD(&aic26->codec.dapm_paths);
+	aic26->codec.reg_cache_size = AIC26_NUM_REGS;
+	aic26->codec.reg_cache = aic26->reg_cache;
+
+	/* Reset the codec to power on defaults */
+	aic26_reg_write(&aic26->codec, AIC26_REG_RESET, 0xBB00);
+
+	/* Power up CODEC */
+	aic26_reg_write(&aic26->codec, AIC26_REG_POWER_CTRL, 0);
+
+	/* Audio Control 3 (master mode, fsref rate) */
+	reg = aic26_reg_read(&aic26->codec, AIC26_REG_AUDIO_CTRL3);
+	reg &= ~0xf800;
+	reg |= 0x0800; /* set master mode */
+	aic26_reg_write(&aic26->codec, AIC26_REG_AUDIO_CTRL3, reg);
+
+	/* Fill register cache */
+	for (i = 0; i < ARRAY_SIZE(aic26->reg_cache); i++)
+		aic26_reg_read(&aic26->codec, i);
+
+	/* Register the sysfs files for debugging */
+	/* Create SysFS files */
+	rc = device_create_file(&spi->dev, &dev_attr_keyclick);
+	if (rc)
+		dev_info(&spi->dev, "error creating sysfs files\n");
+
+#if defined(CONFIG_SND_SOC_OF_SIMPLE)
+	/* Tell the of_soc helper about this codec */
+	of_snd_soc_register_codec(&aic26_soc_codec_dev, aic26, &aic26_dai,
+				  spi->dev.archdata.of_node);
+#endif
+
+	dev_dbg(&spi->dev, "SPI device initialized\n");
+	return 0;
+}
+
+static int aic26_spi_remove(struct spi_device *spi)
+{
+	struct aic26 *aic26 = dev_get_drvdata(&spi->dev);
+
+	kfree(aic26);
+
+	return 0;
+}
+
+static struct spi_driver aic26_spi = {
+	.driver = {
+		.name = "tlv320aic26",
+		.owner = THIS_MODULE,
+	},
+	.probe = aic26_spi_probe,
+	.remove = aic26_spi_remove,
+};
+
+static int __init aic26_init(void)
+{
+	return spi_register_driver(&aic26_spi);
+}
+module_init(aic26_init);
+
+static void __exit aic26_exit(void)
+{
+	spi_unregister_driver(&aic26_spi);
+}
+module_exit(aic26_exit);
diff --git a/sound/soc/codecs/tlv320aic26.h b/sound/soc/codecs/tlv320aic26.h
new file mode 100644
index 0000000..786ba16
--- /dev/null
+++ b/sound/soc/codecs/tlv320aic26.h
@@ -0,0 +1,96 @@
+/*
+ * Texas Instruments TLV320AIC26 low power audio CODEC
+ * register definitions
+ *
+ * Copyright (C) 2008 Secret Lab Technologies Ltd.
+ */
+
+#ifndef _TLV320AIC16_H_
+#define _TLV320AIC16_H_
+
+/* AIC26 Registers */
+#define AIC26_READ_COMMAND_WORD(addr)	((1 << 15) | (addr << 5))
+#define AIC26_WRITE_COMMAND_WORD(addr)	((0 << 15) | (addr << 5))
+#define AIC26_PAGE_ADDR(page, offset)	((page << 6) | offset)
+#define AIC26_NUM_REGS			AIC26_PAGE_ADDR(3, 0)
+
+/* Page 0: Auxillary data registers */
+#define AIC26_REG_BAT1			AIC26_PAGE_ADDR(0, 0x05)
+#define AIC26_REG_BAT2			AIC26_PAGE_ADDR(0, 0x06)
+#define AIC26_REG_AUX			AIC26_PAGE_ADDR(0, 0x07)
+#define AIC26_REG_TEMP1			AIC26_PAGE_ADDR(0, 0x09)
+#define AIC26_REG_TEMP2			AIC26_PAGE_ADDR(0, 0x0A)
+
+/* Page 1: Auxillary control registers */
+#define AIC26_REG_AUX_ADC		AIC26_PAGE_ADDR(1, 0x00)
+#define AIC26_REG_STATUS		AIC26_PAGE_ADDR(1, 0x01)
+#define AIC26_REG_REFERENCE		AIC26_PAGE_ADDR(1, 0x03)
+#define AIC26_REG_RESET			AIC26_PAGE_ADDR(1, 0x04)
+
+/* Page 2: Audio control registers */
+#define AIC26_REG_AUDIO_CTRL1		AIC26_PAGE_ADDR(2, 0x00)
+#define AIC26_REG_ADC_GAIN		AIC26_PAGE_ADDR(2, 0x01)
+#define AIC26_REG_DAC_GAIN		AIC26_PAGE_ADDR(2, 0x02)
+#define AIC26_REG_SIDETONE		AIC26_PAGE_ADDR(2, 0x03)
+#define AIC26_REG_AUDIO_CTRL2		AIC26_PAGE_ADDR(2, 0x04)
+#define AIC26_REG_POWER_CTRL		AIC26_PAGE_ADDR(2, 0x05)
+#define AIC26_REG_AUDIO_CTRL3		AIC26_PAGE_ADDR(2, 0x06)
+
+#define AIC26_REG_FILTER_COEFF_L_N0	AIC26_PAGE_ADDR(2, 0x07)
+#define AIC26_REG_FILTER_COEFF_L_N1	AIC26_PAGE_ADDR(2, 0x08)
+#define AIC26_REG_FILTER_COEFF_L_N2	AIC26_PAGE_ADDR(2, 0x09)
+#define AIC26_REG_FILTER_COEFF_L_N3	AIC26_PAGE_ADDR(2, 0x0A)
+#define AIC26_REG_FILTER_COEFF_L_N4	AIC26_PAGE_ADDR(2, 0x0B)
+#define AIC26_REG_FILTER_COEFF_L_N5	AIC26_PAGE_ADDR(2, 0x0C)
+#define AIC26_REG_FILTER_COEFF_L_D1	AIC26_PAGE_ADDR(2, 0x0D)
+#define AIC26_REG_FILTER_COEFF_L_D2	AIC26_PAGE_ADDR(2, 0x0E)
+#define AIC26_REG_FILTER_COEFF_L_D4	AIC26_PAGE_ADDR(2, 0x0F)
+#define AIC26_REG_FILTER_COEFF_L_D5	AIC26_PAGE_ADDR(2, 0x10)
+#define AIC26_REG_FILTER_COEFF_R_N0	AIC26_PAGE_ADDR(2, 0x11)
+#define AIC26_REG_FILTER_COEFF_R_N1	AIC26_PAGE_ADDR(2, 0x12)
+#define AIC26_REG_FILTER_COEFF_R_N2	AIC26_PAGE_ADDR(2, 0x13)
+#define AIC26_REG_FILTER_COEFF_R_N3	AIC26_PAGE_ADDR(2, 0x14)
+#define AIC26_REG_FILTER_COEFF_R_N4	AIC26_PAGE_ADDR(2, 0x15)
+#define AIC26_REG_FILTER_COEFF_R_N5	AIC26_PAGE_ADDR(2, 0x16)
+#define AIC26_REG_FILTER_COEFF_R_D1	AIC26_PAGE_ADDR(2, 0x17)
+#define AIC26_REG_FILTER_COEFF_R_D2	AIC26_PAGE_ADDR(2, 0x18)
+#define AIC26_REG_FILTER_COEFF_R_D4	AIC26_PAGE_ADDR(2, 0x19)
+#define AIC26_REG_FILTER_COEFF_R_D5	AIC26_PAGE_ADDR(2, 0x1A)
+
+#define AIC26_REG_PLL_PROG1		AIC26_PAGE_ADDR(2, 0x1B)
+#define AIC26_REG_PLL_PROG2		AIC26_PAGE_ADDR(2, 0x1C)
+#define AIC26_REG_AUDIO_CTRL4		AIC26_PAGE_ADDR(2, 0x1D)
+#define AIC26_REG_AUDIO_CTRL5		AIC26_PAGE_ADDR(2, 0x1E)
+
+/* fsref dividers; used in register 'Audio Control 1' */
+enum aic26_divisors {
+	AIC26_DIV_1	= 0,
+	AIC26_DIV_1_5	= 1,
+	AIC26_DIV_2	= 2,
+	AIC26_DIV_3	= 3,
+	AIC26_DIV_4	= 4,
+	AIC26_DIV_5	= 5,
+	AIC26_DIV_5_5	= 6,
+	AIC26_DIV_6	= 7,
+};
+
+/* Digital data format */
+enum aic26_datfm {
+	AIC26_DATFM_I2S		= 0 << 8,
+	AIC26_DATFM_DSP		= 1 << 8,
+	AIC26_DATFM_RIGHTJ	= 2 << 8, /* right justified */
+	AIC26_DATFM_LEFTJ	= 3 << 8, /* left justified */
+};
+
+/* Sample word length in bits; used in register 'Audio Control 1' */
+enum aic26_wlen {
+	AIC26_WLEN_16	= 0 << 10,
+	AIC26_WLEN_20	= 1 << 10,
+	AIC26_WLEN_24	= 2 << 10,
+	AIC26_WLEN_32	= 3 << 10,
+};
+
+extern struct snd_soc_dai aic26_dai;
+extern struct snd_soc_codec_device aic26_soc_codec_dev;
+
+#endif /* _TLV320AIC16_H_ */
diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c
index 5f9abb1..05336ed 100644
--- a/sound/soc/codecs/tlv320aic3x.c
+++ b/sound/soc/codecs/tlv320aic3x.c
@@ -1,7 +1,7 @@
 /*
  * ALSA SoC TLV320AIC3X codec driver
  *
- * Author:      Vladimir Barinov, <vbarinov@ru.mvista.com>
+ * Author:      Vladimir Barinov, <vbarinov@embeddedalley.com>
  * Copyright:   (C) 2007 MontaVista Software, Inc., <source@mvista.com>
  *
  * Based on sound/soc/codecs/wm8753.c by Liam Girdwood
@@ -48,7 +48,6 @@
 
 #include "tlv320aic3x.h"
 
-#define AUDIO_NAME "aic3x"
 #define AIC3X_VERSION "0.2"
 
 /* codec private data */
@@ -991,7 +990,7 @@
 			 SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE)
 
 struct snd_soc_dai aic3x_dai = {
-	.name = "aic3x",
+	.name = "tlv320aic3x",
 	.playback = {
 		.stream_name = "Playback",
 		.channels_min = 1,
@@ -1055,7 +1054,7 @@
 	struct aic3x_setup_data *setup = socdev->codec_data;
 	int reg, ret = 0;
 
-	codec->name = "aic3x";
+	codec->name = "tlv320aic3x";
 	codec->owner = THIS_MODULE;
 	codec->read = aic3x_read_reg_cache;
 	codec->write = aic3x_write;
@@ -1172,71 +1171,39 @@
  * AIC3X 2 wire address can be up to 4 devices with device addresses
  * 0x18, 0x19, 0x1A, 0x1B
  */
-static unsigned short normal_i2c[] = { 0, I2C_CLIENT_END };
-
-/* Magic definition of all other variables and things */
-I2C_CLIENT_INSMOD;
-
-static struct i2c_driver aic3x_i2c_driver;
-static struct i2c_client client_template;
 
 /*
  * If the i2c layer weren't so broken, we could pass this kind of data
  * around
  */
-static int aic3x_codec_probe(struct i2c_adapter *adap, int addr, int kind)
+static int aic3x_i2c_probe(struct i2c_client *i2c,
+			   const struct i2c_device_id *id)
 {
 	struct snd_soc_device *socdev = aic3x_socdev;
-	struct aic3x_setup_data *setup = socdev->codec_data;
 	struct snd_soc_codec *codec = socdev->codec;
-	struct i2c_client *i2c;
 	int ret;
 
-	if (addr != setup->i2c_address)
-		return -ENODEV;
-
-	client_template.adapter = adap;
-	client_template.addr = addr;
-
-	i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL);
-	if (i2c == NULL)
-		return -ENOMEM;
-
 	i2c_set_clientdata(i2c, codec);
 	codec->control_data = i2c;
 
-	ret = i2c_attach_client(i2c);
-	if (ret < 0) {
-		printk(KERN_ERR "aic3x: failed to attach codec at addr %x\n",
-		       addr);
-		goto err;
-	}
-
 	ret = aic3x_init(socdev);
-	if (ret < 0) {
+	if (ret < 0)
 		printk(KERN_ERR "aic3x: failed to initialise AIC3X\n");
-		goto err;
-	}
-	return ret;
-
-err:
-	kfree(i2c);
 	return ret;
 }
 
-static int aic3x_i2c_detach(struct i2c_client *client)
+static int aic3x_i2c_remove(struct i2c_client *client)
 {
 	struct snd_soc_codec *codec = i2c_get_clientdata(client);
-	i2c_detach_client(client);
 	kfree(codec->reg_cache);
-	kfree(client);
 	return 0;
 }
 
-static int aic3x_i2c_attach(struct i2c_adapter *adap)
-{
-	return i2c_probe(adap, &addr_data, aic3x_codec_probe);
-}
+static const struct i2c_device_id aic3x_i2c_id[] = {
+	{ "tlv320aic3x", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, aic3x_i2c_id);
 
 /* machine i2c codec control layer */
 static struct i2c_driver aic3x_i2c_driver = {
@@ -1244,13 +1211,9 @@
 		.name = "aic3x I2C Codec",
 		.owner = THIS_MODULE,
 	},
-	.attach_adapter = aic3x_i2c_attach,
-	.detach_client = aic3x_i2c_detach,
-};
-
-static struct i2c_client client_template = {
-	.name = "AIC3X",
-	.driver = &aic3x_i2c_driver,
+	.probe = aic3x_i2c_probe,
+	.remove = aic3x_i2c_remove,
+	.id_table = aic3x_i2c_id,
 };
 
 static int aic3x_i2c_read(struct i2c_client *client, u8 *value, int len)
@@ -1258,6 +1221,46 @@
 	value[0] = i2c_smbus_read_byte_data(client, value[0]);
 	return (len == 1);
 }
+
+static int aic3x_add_i2c_device(struct platform_device *pdev,
+				 const struct aic3x_setup_data *setup)
+{
+	struct i2c_board_info info;
+	struct i2c_adapter *adapter;
+	struct i2c_client *client;
+	int ret;
+
+	ret = i2c_add_driver(&aic3x_i2c_driver);
+	if (ret != 0) {
+		dev_err(&pdev->dev, "can't add i2c driver\n");
+		return ret;
+	}
+
+	memset(&info, 0, sizeof(struct i2c_board_info));
+	info.addr = setup->i2c_address;
+	strlcpy(info.type, "tlv320aic3x", I2C_NAME_SIZE);
+
+	adapter = i2c_get_adapter(setup->i2c_bus);
+	if (!adapter) {
+		dev_err(&pdev->dev, "can't get i2c adapter %d\n",
+			setup->i2c_bus);
+		goto err_driver;
+	}
+
+	client = i2c_new_device(adapter, &info);
+	i2c_put_adapter(adapter);
+	if (!client) {
+		dev_err(&pdev->dev, "can't add i2c device at 0x%x\n",
+			(unsigned int)info.addr);
+		goto err_driver;
+	}
+
+	return 0;
+
+err_driver:
+	i2c_del_driver(&aic3x_i2c_driver);
+	return -ENODEV;
+}
 #endif
 
 static int aic3x_probe(struct platform_device *pdev)
@@ -1290,12 +1293,9 @@
 	aic3x_socdev = socdev;
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
 	if (setup->i2c_address) {
-		normal_i2c[0] = setup->i2c_address;
 		codec->hw_write = (hw_write_t) i2c_master_send;
 		codec->hw_read = (hw_read_t) aic3x_i2c_read;
-		ret = i2c_add_driver(&aic3x_i2c_driver);
-		if (ret != 0)
-			printk(KERN_ERR "can't add i2c driver");
+		ret = aic3x_add_i2c_device(pdev, setup);
 	}
 #else
 	/* Add other interfaces here */
@@ -1320,6 +1320,7 @@
 	snd_soc_free_pcms(socdev);
 	snd_soc_dapm_free(socdev);
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+	i2c_unregister_device(codec->control_data);
 	i2c_del_driver(&aic3x_i2c_driver);
 #endif
 	kfree(codec->private_data);
diff --git a/sound/soc/codecs/tlv320aic3x.h b/sound/soc/codecs/tlv320aic3x.h
index d76c079..00a195a 100644
--- a/sound/soc/codecs/tlv320aic3x.h
+++ b/sound/soc/codecs/tlv320aic3x.h
@@ -1,7 +1,7 @@
 /*
  * ALSA SoC TLV320AIC3X codec driver
  *
- * Author:      Vladimir Barinov, <vbarinov@ru.mvista.com>
+ * Author:      Vladimir Barinov, <vbarinov@embeddedalley.com>
  * Copyright:   (C) 2007 MontaVista Software, Inc., <source@mvista.com>
  *
  * This program is free software; you can redistribute it and/or modify
@@ -224,6 +224,7 @@
 int aic3x_headset_detected(struct snd_soc_codec *codec);
 
 struct aic3x_setup_data {
+	int i2c_bus;
 	unsigned short i2c_address;
 	unsigned int gpio_func[2];
 };
diff --git a/sound/soc/codecs/uda1380.c b/sound/soc/codecs/uda1380.c
index 807318f..a69ee72 100644
--- a/sound/soc/codecs/uda1380.c
+++ b/sound/soc/codecs/uda1380.c
@@ -36,7 +36,6 @@
 #include "uda1380.h"
 
 #define UDA1380_VERSION "0.6"
-#define AUDIO_NAME "uda1380"
 
 /*
  * uda1380 register cache
@@ -701,87 +700,86 @@
 
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
 
-#define I2C_DRIVERID_UDA1380 0xfefe /* liam -  need a proper id */
-
-static unsigned short normal_i2c[] = { 0, I2C_CLIENT_END };
-
-/* Magic definition of all other variables and things */
-I2C_CLIENT_INSMOD;
-
-static struct i2c_driver uda1380_i2c_driver;
-static struct i2c_client client_template;
-
-/* If the i2c layer weren't so broken, we could pass this kind of data
-   around */
-
-static int uda1380_codec_probe(struct i2c_adapter *adap, int addr, int kind)
+static int uda1380_i2c_probe(struct i2c_client *i2c,
+			     const struct i2c_device_id *id)
 {
 	struct snd_soc_device *socdev = uda1380_socdev;
 	struct uda1380_setup_data *setup = socdev->codec_data;
 	struct snd_soc_codec *codec = socdev->codec;
-	struct i2c_client *i2c;
 	int ret;
 
-	if (addr != setup->i2c_address)
-		return -ENODEV;
-
-	client_template.adapter = adap;
-	client_template.addr = addr;
-
-	i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL);
-	if (i2c == NULL)
-		return -ENOMEM;
-
 	i2c_set_clientdata(i2c, codec);
 	codec->control_data = i2c;
 
-	ret = i2c_attach_client(i2c);
-	if (ret < 0) {
-		pr_err("uda1380: failed to attach codec at addr %x\n", addr);
-		goto err;
-	}
-
 	ret = uda1380_init(socdev, setup->dac_clk);
-	if (ret < 0) {
+	if (ret < 0)
 		pr_err("uda1380: failed to initialise UDA1380\n");
-		goto err;
-	}
-	return ret;
 
-err:
-	kfree(i2c);
 	return ret;
 }
 
-static int uda1380_i2c_detach(struct i2c_client *client)
+static int uda1380_i2c_remove(struct i2c_client *client)
 {
 	struct snd_soc_codec *codec = i2c_get_clientdata(client);
-	i2c_detach_client(client);
 	kfree(codec->reg_cache);
-	kfree(client);
 	return 0;
 }
 
-static int uda1380_i2c_attach(struct i2c_adapter *adap)
-{
-	return i2c_probe(adap, &addr_data, uda1380_codec_probe);
-}
+static const struct i2c_device_id uda1380_i2c_id[] = {
+	{ "uda1380", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, uda1380_i2c_id);
 
 static struct i2c_driver uda1380_i2c_driver = {
 	.driver = {
 		.name =  "UDA1380 I2C Codec",
 		.owner = THIS_MODULE,
 	},
-	.id =             I2C_DRIVERID_UDA1380,
-	.attach_adapter = uda1380_i2c_attach,
-	.detach_client =  uda1380_i2c_detach,
-	.command =        NULL,
+	.probe =    uda1380_i2c_probe,
+	.remove =   uda1380_i2c_remove,
+	.id_table = uda1380_i2c_id,
 };
 
-static struct i2c_client client_template = {
-	.name =   "UDA1380",
-	.driver = &uda1380_i2c_driver,
-};
+static int uda1380_add_i2c_device(struct platform_device *pdev,
+				  const struct uda1380_setup_data *setup)
+{
+	struct i2c_board_info info;
+	struct i2c_adapter *adapter;
+	struct i2c_client *client;
+	int ret;
+
+	ret = i2c_add_driver(&uda1380_i2c_driver);
+	if (ret != 0) {
+		dev_err(&pdev->dev, "can't add i2c driver\n");
+		return ret;
+	}
+
+	memset(&info, 0, sizeof(struct i2c_board_info));
+	info.addr = setup->i2c_address;
+	strlcpy(info.type, "uda1380", I2C_NAME_SIZE);
+
+	adapter = i2c_get_adapter(setup->i2c_bus);
+	if (!adapter) {
+		dev_err(&pdev->dev, "can't get i2c adapter %d\n",
+			setup->i2c_bus);
+		goto err_driver;
+	}
+
+	client = i2c_new_device(adapter, &info);
+	i2c_put_adapter(adapter);
+	if (!client) {
+		dev_err(&pdev->dev, "can't add i2c device at 0x%x\n",
+			(unsigned int)info.addr);
+		goto err_driver;
+	}
+
+	return 0;
+
+err_driver:
+	i2c_del_driver(&uda1380_i2c_driver);
+	return -ENODEV;
+}
 #endif
 
 static int uda1380_probe(struct platform_device *pdev)
@@ -789,7 +787,7 @@
 	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
 	struct uda1380_setup_data *setup;
 	struct snd_soc_codec *codec;
-	int ret = 0;
+	int ret;
 
 	pr_info("UDA1380 Audio Codec %s", UDA1380_VERSION);
 
@@ -804,16 +802,13 @@
 	INIT_LIST_HEAD(&codec->dapm_paths);
 
 	uda1380_socdev = socdev;
+	ret = -ENODEV;
+
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
 	if (setup->i2c_address) {
-		normal_i2c[0] = setup->i2c_address;
 		codec->hw_write = (hw_write_t)i2c_master_send;
-		ret = i2c_add_driver(&uda1380_i2c_driver);
-		if (ret != 0)
-			printk(KERN_ERR "can't add i2c driver");
+		ret = uda1380_add_i2c_device(pdev, setup);
 	}
-#else
-	/* Add other interfaces here */
 #endif
 
 	if (ret != 0)
@@ -833,6 +828,7 @@
 	snd_soc_free_pcms(socdev);
 	snd_soc_dapm_free(socdev);
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+	i2c_unregister_device(codec->control_data);
 	i2c_del_driver(&uda1380_i2c_driver);
 #endif
 	kfree(codec);
diff --git a/sound/soc/codecs/uda1380.h b/sound/soc/codecs/uda1380.h
index 50c603e..c55c17a 100644
--- a/sound/soc/codecs/uda1380.h
+++ b/sound/soc/codecs/uda1380.h
@@ -73,6 +73,7 @@
 #define R23_AGC_EN	0x0001
 
 struct uda1380_setup_data {
+	int            i2c_bus;
 	unsigned short i2c_address;
 	int            dac_clk;
 #define UDA1380_DAC_CLK_SYSCLK 0
diff --git a/sound/soc/codecs/wm8510.c b/sound/soc/codecs/wm8510.c
index 3d998e6..d8ca2da 100644
--- a/sound/soc/codecs/wm8510.c
+++ b/sound/soc/codecs/wm8510.c
@@ -3,7 +3,7 @@
  *
  * Copyright 2006 Wolfson Microelectronics PLC.
  *
- * Author: Liam Girdwood <liam.girdwood@wolfsonmicro.com>
+ * Author: Liam Girdwood <lrg@slimlogic.co.uk>
  *
  * 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
@@ -18,6 +18,7 @@
 #include <linux/pm.h>
 #include <linux/i2c.h>
 #include <linux/platform_device.h>
+#include <linux/spi/spi.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
@@ -27,7 +28,6 @@
 
 #include "wm8510.h"
 
-#define AUDIO_NAME "wm8510"
 #define WM8510_VERSION "0.6"
 
 struct snd_soc_codec_device soc_codec_dev_wm8510;
@@ -55,6 +55,9 @@
 	0x0001,
 };
 
+#define WM8510_POWER1_BIASEN  0x08
+#define WM8510_POWER1_BUFIOEN 0x10
+
 /*
  * read wm8510 register cache
  */
@@ -199,7 +202,7 @@
 };
 
 static const struct snd_kcontrol_new wm8510_boost_controls[] = {
-SOC_DAPM_SINGLE("Mic PGA Switch", WM8510_INPPGA,  6, 1, 0),
+SOC_DAPM_SINGLE("Mic PGA Switch", WM8510_INPPGA,  6, 1, 1),
 SOC_DAPM_SINGLE("Aux Volume", WM8510_ADCBOOST, 0, 7, 0),
 SOC_DAPM_SINGLE("Mic Volume", WM8510_ADCBOOST, 4, 7, 0),
 };
@@ -224,9 +227,9 @@
 SND_SOC_DAPM_PGA("SpkP Out", WM8510_POWER3, 6, 0, NULL, 0),
 SND_SOC_DAPM_PGA("Mono Out", WM8510_POWER3, 7, 0, NULL, 0),
 
-SND_SOC_DAPM_PGA("Mic PGA", WM8510_POWER2, 2, 0,
-		 &wm8510_micpga_controls[0],
-		 ARRAY_SIZE(wm8510_micpga_controls)),
+SND_SOC_DAPM_MIXER("Mic PGA", WM8510_POWER2, 2, 0,
+		   &wm8510_micpga_controls[0],
+		   ARRAY_SIZE(wm8510_micpga_controls)),
 SND_SOC_DAPM_MIXER("Boost Mixer", WM8510_POWER2, 4, 0,
 	&wm8510_boost_controls[0],
 	ARRAY_SIZE(wm8510_boost_controls)),
@@ -526,23 +529,35 @@
 static int wm8510_set_bias_level(struct snd_soc_codec *codec,
 	enum snd_soc_bias_level level)
 {
+	u16 power1 = wm8510_read_reg_cache(codec, WM8510_POWER1) & ~0x3;
 
 	switch (level) {
 	case SND_SOC_BIAS_ON:
-		wm8510_write(codec, WM8510_POWER1, 0x1ff);
-		wm8510_write(codec, WM8510_POWER2, 0x1ff);
-		wm8510_write(codec, WM8510_POWER3, 0x1ff);
-		break;
 	case SND_SOC_BIAS_PREPARE:
-	case SND_SOC_BIAS_STANDBY:
+		power1 |= 0x1;  /* VMID 50k */
+		wm8510_write(codec, WM8510_POWER1, power1);
 		break;
+
+	case SND_SOC_BIAS_STANDBY:
+		power1 |= WM8510_POWER1_BIASEN | WM8510_POWER1_BUFIOEN;
+
+		if (codec->bias_level == SND_SOC_BIAS_OFF) {
+			/* Initial cap charge at VMID 5k */
+			wm8510_write(codec, WM8510_POWER1, power1 | 0x3);
+			mdelay(100);
+		}
+
+		power1 |= 0x2;  /* VMID 500k */
+		wm8510_write(codec, WM8510_POWER1, power1);
+		break;
+
 	case SND_SOC_BIAS_OFF:
-		/* everything off, dac mute, inactive */
-		wm8510_write(codec, WM8510_POWER1, 0x0);
-		wm8510_write(codec, WM8510_POWER2, 0x0);
-		wm8510_write(codec, WM8510_POWER3, 0x0);
+		wm8510_write(codec, WM8510_POWER1, 0);
+		wm8510_write(codec, WM8510_POWER2, 0);
+		wm8510_write(codec, WM8510_POWER3, 0);
 		break;
 	}
+
 	codec->bias_level = level;
 	return 0;
 }
@@ -640,6 +655,7 @@
 	}
 
 	/* power on device */
+	codec->bias_level = SND_SOC_BIAS_OFF;
 	wm8510_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 	wm8510_add_controls(codec);
 	wm8510_add_widgets(codec);
@@ -665,90 +681,144 @@
 /*
  * WM8510 2 wire address is 0x1a
  */
-#define I2C_DRIVERID_WM8510 0xfefe /* liam -  need a proper id */
 
-static unsigned short normal_i2c[] = { 0, I2C_CLIENT_END };
-
-/* Magic definition of all other variables and things */
-I2C_CLIENT_INSMOD;
-
-static struct i2c_driver wm8510_i2c_driver;
-static struct i2c_client client_template;
-
-/* If the i2c layer weren't so broken, we could pass this kind of data
-   around */
-
-static int wm8510_codec_probe(struct i2c_adapter *adap, int addr, int kind)
+static int wm8510_i2c_probe(struct i2c_client *i2c,
+			    const struct i2c_device_id *id)
 {
 	struct snd_soc_device *socdev = wm8510_socdev;
-	struct wm8510_setup_data *setup = socdev->codec_data;
 	struct snd_soc_codec *codec = socdev->codec;
-	struct i2c_client *i2c;
 	int ret;
 
-	if (addr != setup->i2c_address)
-		return -ENODEV;
-
-	client_template.adapter = adap;
-	client_template.addr = addr;
-
-	i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL);
-	if (i2c == NULL)
-		return -ENOMEM;
-
 	i2c_set_clientdata(i2c, codec);
 	codec->control_data = i2c;
 
-	ret = i2c_attach_client(i2c);
-	if (ret < 0) {
-		pr_err("failed to attach codec at addr %x\n", addr);
-		goto err;
-	}
-
 	ret = wm8510_init(socdev);
-	if (ret < 0) {
+	if (ret < 0)
 		pr_err("failed to initialise WM8510\n");
-		goto err;
-	}
-	return ret;
 
-err:
-	kfree(i2c);
 	return ret;
 }
 
-static int wm8510_i2c_detach(struct i2c_client *client)
+static int wm8510_i2c_remove(struct i2c_client *client)
 {
 	struct snd_soc_codec *codec = i2c_get_clientdata(client);
-	i2c_detach_client(client);
 	kfree(codec->reg_cache);
-	kfree(client);
 	return 0;
 }
 
-static int wm8510_i2c_attach(struct i2c_adapter *adap)
-{
-	return i2c_probe(adap, &addr_data, wm8510_codec_probe);
-}
+static const struct i2c_device_id wm8510_i2c_id[] = {
+	{ "wm8510", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, wm8510_i2c_id);
 
-/* corgi i2c codec control layer */
 static struct i2c_driver wm8510_i2c_driver = {
 	.driver = {
 		.name = "WM8510 I2C Codec",
 		.owner = THIS_MODULE,
 	},
-	.id =             I2C_DRIVERID_WM8510,
-	.attach_adapter = wm8510_i2c_attach,
-	.detach_client =  wm8510_i2c_detach,
-	.command =        NULL,
+	.probe =    wm8510_i2c_probe,
+	.remove =   wm8510_i2c_remove,
+	.id_table = wm8510_i2c_id,
 };
 
-static struct i2c_client client_template = {
-	.name =   "WM8510",
-	.driver = &wm8510_i2c_driver,
-};
+static int wm8510_add_i2c_device(struct platform_device *pdev,
+				 const struct wm8510_setup_data *setup)
+{
+	struct i2c_board_info info;
+	struct i2c_adapter *adapter;
+	struct i2c_client *client;
+	int ret;
+
+	ret = i2c_add_driver(&wm8510_i2c_driver);
+	if (ret != 0) {
+		dev_err(&pdev->dev, "can't add i2c driver\n");
+		return ret;
+	}
+
+	memset(&info, 0, sizeof(struct i2c_board_info));
+	info.addr = setup->i2c_address;
+	strlcpy(info.type, "wm8510", I2C_NAME_SIZE);
+
+	adapter = i2c_get_adapter(setup->i2c_bus);
+	if (!adapter) {
+		dev_err(&pdev->dev, "can't get i2c adapter %d\n",
+			setup->i2c_bus);
+		goto err_driver;
+	}
+
+	client = i2c_new_device(adapter, &info);
+	i2c_put_adapter(adapter);
+	if (!client) {
+		dev_err(&pdev->dev, "can't add i2c device at 0x%x\n",
+			(unsigned int)info.addr);
+		goto err_driver;
+	}
+
+	return 0;
+
+err_driver:
+	i2c_del_driver(&wm8510_i2c_driver);
+	return -ENODEV;
+}
 #endif
 
+#if defined(CONFIG_SPI_MASTER)
+static int __devinit wm8510_spi_probe(struct spi_device *spi)
+{
+	struct snd_soc_device *socdev = wm8510_socdev;
+	struct snd_soc_codec *codec = socdev->codec;
+	int ret;
+
+	codec->control_data = spi;
+
+	ret = wm8510_init(socdev);
+	if (ret < 0)
+		dev_err(&spi->dev, "failed to initialise WM8510\n");
+
+	return ret;
+}
+
+static int __devexit wm8510_spi_remove(struct spi_device *spi)
+{
+	return 0;
+}
+
+static struct spi_driver wm8510_spi_driver = {
+	.driver = {
+		.name	= "wm8510",
+		.bus	= &spi_bus_type,
+		.owner	= THIS_MODULE,
+	},
+	.probe		= wm8510_spi_probe,
+	.remove		= __devexit_p(wm8510_spi_remove),
+};
+
+static int wm8510_spi_write(struct spi_device *spi, const char *data, int len)
+{
+	struct spi_transfer t;
+	struct spi_message m;
+	u8 msg[2];
+
+	if (len <= 0)
+		return 0;
+
+	msg[0] = data[0];
+	msg[1] = data[1];
+
+	spi_message_init(&m);
+	memset(&t, 0, (sizeof t));
+
+	t.tx_buf = &msg[0];
+	t.len = len;
+
+	spi_message_add_tail(&t, &m);
+	spi_sync(spi, &m);
+
+	return len;
+}
+#endif /* CONFIG_SPI_MASTER */
+
 static int wm8510_probe(struct platform_device *pdev)
 {
 	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
@@ -771,14 +841,17 @@
 	wm8510_socdev = socdev;
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
 	if (setup->i2c_address) {
-		normal_i2c[0] = setup->i2c_address;
 		codec->hw_write = (hw_write_t)i2c_master_send;
-		ret = i2c_add_driver(&wm8510_i2c_driver);
-		if (ret != 0)
-			printk(KERN_ERR "can't add i2c driver");
+		ret = wm8510_add_i2c_device(pdev, setup);
 	}
-#else
-	/* Add other interfaces here */
+#endif
+#if defined(CONFIG_SPI_MASTER)
+	if (setup->spi) {
+		codec->hw_write = (hw_write_t)wm8510_spi_write;
+		ret = spi_register_driver(&wm8510_spi_driver);
+		if (ret != 0)
+			printk(KERN_ERR "can't add spi driver");
+	}
 #endif
 
 	if (ret != 0)
@@ -798,8 +871,12 @@
 	snd_soc_free_pcms(socdev);
 	snd_soc_dapm_free(socdev);
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+	i2c_unregister_device(codec->control_data);
 	i2c_del_driver(&wm8510_i2c_driver);
 #endif
+#if defined(CONFIG_SPI_MASTER)
+	spi_unregister_driver(&wm8510_spi_driver);
+#endif
 	kfree(codec);
 
 	return 0;
diff --git a/sound/soc/codecs/wm8510.h b/sound/soc/codecs/wm8510.h
index f5d2e42..bdefcf5 100644
--- a/sound/soc/codecs/wm8510.h
+++ b/sound/soc/codecs/wm8510.h
@@ -94,6 +94,8 @@
 #define WM8510_MCLKDIV_12	(7 << 5)
 
 struct wm8510_setup_data {
+	int spi;
+	int i2c_bus;
 	unsigned short i2c_address;
 };
 
diff --git a/sound/soc/codecs/wm8580.c b/sound/soc/codecs/wm8580.c
new file mode 100644
index 0000000..627ebfb
--- /dev/null
+++ b/sound/soc/codecs/wm8580.c
@@ -0,0 +1,1053 @@
+/*
+ * wm8580.c  --  WM8580 ALSA Soc Audio driver
+ *
+ * Copyright 2008 Wolfson Microelectronics PLC.
+ *
+ *  This program is free software; you can redistribute  it and/or 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.
+ *
+ * Notes:
+ *  The WM8580 is a multichannel codec with S/PDIF support, featuring six
+ *  DAC channels and two ADC channels.
+ *
+ *  Currently only the primary audio interface is supported - S/PDIF and
+ *  the secondary audio interfaces are not.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/tlv.h>
+#include <sound/initval.h>
+#include <asm/div64.h>
+
+#include "wm8580.h"
+
+#define WM8580_VERSION "0.1"
+
+struct pll_state {
+	unsigned int in;
+	unsigned int out;
+};
+
+/* codec private data */
+struct wm8580_priv {
+	struct pll_state a;
+	struct pll_state b;
+};
+
+/* WM8580 register space */
+#define WM8580_PLLA1                         0x00
+#define WM8580_PLLA2                         0x01
+#define WM8580_PLLA3                         0x02
+#define WM8580_PLLA4                         0x03
+#define WM8580_PLLB1                         0x04
+#define WM8580_PLLB2                         0x05
+#define WM8580_PLLB3                         0x06
+#define WM8580_PLLB4                         0x07
+#define WM8580_CLKSEL                        0x08
+#define WM8580_PAIF1                         0x09
+#define WM8580_PAIF2                         0x0A
+#define WM8580_SAIF1                         0x0B
+#define WM8580_PAIF3                         0x0C
+#define WM8580_PAIF4                         0x0D
+#define WM8580_SAIF2                         0x0E
+#define WM8580_DAC_CONTROL1                  0x0F
+#define WM8580_DAC_CONTROL2                  0x10
+#define WM8580_DAC_CONTROL3                  0x11
+#define WM8580_DAC_CONTROL4                  0x12
+#define WM8580_DAC_CONTROL5                  0x13
+#define WM8580_DIGITAL_ATTENUATION_DACL1     0x14
+#define WM8580_DIGITAL_ATTENUATION_DACR1     0x15
+#define WM8580_DIGITAL_ATTENUATION_DACL2     0x16
+#define WM8580_DIGITAL_ATTENUATION_DACR2     0x17
+#define WM8580_DIGITAL_ATTENUATION_DACL3     0x18
+#define WM8580_DIGITAL_ATTENUATION_DACR3     0x19
+#define WM8580_MASTER_DIGITAL_ATTENUATION    0x1C
+#define WM8580_ADC_CONTROL1                  0x1D
+#define WM8580_SPDTXCHAN0                    0x1E
+#define WM8580_SPDTXCHAN1                    0x1F
+#define WM8580_SPDTXCHAN2                    0x20
+#define WM8580_SPDTXCHAN3                    0x21
+#define WM8580_SPDTXCHAN4                    0x22
+#define WM8580_SPDTXCHAN5                    0x23
+#define WM8580_SPDMODE                       0x24
+#define WM8580_INTMASK                       0x25
+#define WM8580_GPO1                          0x26
+#define WM8580_GPO2                          0x27
+#define WM8580_GPO3                          0x28
+#define WM8580_GPO4                          0x29
+#define WM8580_GPO5                          0x2A
+#define WM8580_INTSTAT                       0x2B
+#define WM8580_SPDRXCHAN1                    0x2C
+#define WM8580_SPDRXCHAN2                    0x2D
+#define WM8580_SPDRXCHAN3                    0x2E
+#define WM8580_SPDRXCHAN4                    0x2F
+#define WM8580_SPDRXCHAN5                    0x30
+#define WM8580_SPDSTAT                       0x31
+#define WM8580_PWRDN1                        0x32
+#define WM8580_PWRDN2                        0x33
+#define WM8580_READBACK                      0x34
+#define WM8580_RESET                         0x35
+
+/* PLLB4 (register 7h) */
+#define WM8580_PLLB4_MCLKOUTSRC_MASK   0x60
+#define WM8580_PLLB4_MCLKOUTSRC_PLLA   0x20
+#define WM8580_PLLB4_MCLKOUTSRC_PLLB   0x40
+#define WM8580_PLLB4_MCLKOUTSRC_OSC    0x60
+
+#define WM8580_PLLB4_CLKOUTSRC_MASK    0x180
+#define WM8580_PLLB4_CLKOUTSRC_PLLACLK 0x080
+#define WM8580_PLLB4_CLKOUTSRC_PLLBCLK 0x100
+#define WM8580_PLLB4_CLKOUTSRC_OSCCLK  0x180
+
+/* CLKSEL (register 8h) */
+#define WM8580_CLKSEL_DAC_CLKSEL_MASK 0x03
+#define WM8580_CLKSEL_DAC_CLKSEL_PLLA 0x01
+#define WM8580_CLKSEL_DAC_CLKSEL_PLLB 0x02
+
+/* AIF control 1 (registers 9h-bh) */
+#define WM8580_AIF_RATE_MASK       0x7
+#define WM8580_AIF_RATE_128        0x0
+#define WM8580_AIF_RATE_192        0x1
+#define WM8580_AIF_RATE_256        0x2
+#define WM8580_AIF_RATE_384        0x3
+#define WM8580_AIF_RATE_512        0x4
+#define WM8580_AIF_RATE_768        0x5
+#define WM8580_AIF_RATE_1152       0x6
+
+#define WM8580_AIF_BCLKSEL_MASK   0x18
+#define WM8580_AIF_BCLKSEL_64     0x00
+#define WM8580_AIF_BCLKSEL_128    0x08
+#define WM8580_AIF_BCLKSEL_256    0x10
+#define WM8580_AIF_BCLKSEL_SYSCLK 0x18
+
+#define WM8580_AIF_MS             0x20
+
+#define WM8580_AIF_CLKSRC_MASK    0xc0
+#define WM8580_AIF_CLKSRC_PLLA    0x40
+#define WM8580_AIF_CLKSRC_PLLB    0x40
+#define WM8580_AIF_CLKSRC_MCLK    0xc0
+
+/* AIF control 2 (registers ch-eh) */
+#define WM8580_AIF_FMT_MASK    0x03
+#define WM8580_AIF_FMT_RIGHTJ  0x00
+#define WM8580_AIF_FMT_LEFTJ   0x01
+#define WM8580_AIF_FMT_I2S     0x02
+#define WM8580_AIF_FMT_DSP     0x03
+
+#define WM8580_AIF_LENGTH_MASK   0x0c
+#define WM8580_AIF_LENGTH_16     0x00
+#define WM8580_AIF_LENGTH_20     0x04
+#define WM8580_AIF_LENGTH_24     0x08
+#define WM8580_AIF_LENGTH_32     0x0c
+
+#define WM8580_AIF_LRP         0x10
+#define WM8580_AIF_BCP         0x20
+
+/* Powerdown Register 1 (register 32h) */
+#define WM8580_PWRDN1_PWDN     0x001
+#define WM8580_PWRDN1_ALLDACPD 0x040
+
+/* Powerdown Register 2 (register 33h) */
+#define WM8580_PWRDN2_OSSCPD   0x001
+#define WM8580_PWRDN2_PLLAPD   0x002
+#define WM8580_PWRDN2_PLLBPD   0x004
+#define WM8580_PWRDN2_SPDIFPD  0x008
+#define WM8580_PWRDN2_SPDIFTXD 0x010
+#define WM8580_PWRDN2_SPDIFRXD 0x020
+
+#define WM8580_DAC_CONTROL5_MUTEALL 0x10
+
+/*
+ * wm8580 register cache
+ * We can't read the WM8580 register space when we
+ * are using 2 wire for device control, so we cache them instead.
+ */
+static const u16 wm8580_reg[] = {
+	0x0121, 0x017e, 0x007d, 0x0014, /*R3*/
+	0x0121, 0x017e, 0x007d, 0x0194, /*R7*/
+	0x001c, 0x0002, 0x0002, 0x00c2, /*R11*/
+	0x0182, 0x0082, 0x000a, 0x0024, /*R15*/
+	0x0009, 0x0000, 0x00ff, 0x0000, /*R19*/
+	0x00ff, 0x00ff, 0x00ff, 0x00ff, /*R23*/
+	0x00ff, 0x00ff, 0x00ff, 0x00ff, /*R27*/
+	0x01f0, 0x0040, 0x0000, 0x0000, /*R31(0x1F)*/
+	0x0000, 0x0000, 0x0031, 0x000b, /*R35*/
+	0x0039, 0x0000, 0x0010, 0x0032, /*R39*/
+	0x0054, 0x0076, 0x0098, 0x0000, /*R43(0x2B)*/
+	0x0000, 0x0000, 0x0000, 0x0000, /*R47*/
+	0x0000, 0x0000, 0x005e, 0x003e, /*R51(0x33)*/
+	0x0000, 0x0000 /*R53*/
+};
+
+/*
+ * read wm8580 register cache
+ */
+static inline unsigned int wm8580_read_reg_cache(struct snd_soc_codec *codec,
+	unsigned int reg)
+{
+	u16 *cache = codec->reg_cache;
+	BUG_ON(reg > ARRAY_SIZE(wm8580_reg));
+	return cache[reg];
+}
+
+/*
+ * write wm8580 register cache
+ */
+static inline void wm8580_write_reg_cache(struct snd_soc_codec *codec,
+	unsigned int reg, unsigned int value)
+{
+	u16 *cache = codec->reg_cache;
+
+	cache[reg] = value;
+}
+
+/*
+ * write to the WM8580 register space
+ */
+static int wm8580_write(struct snd_soc_codec *codec, unsigned int reg,
+	unsigned int value)
+{
+	u8 data[2];
+
+	BUG_ON(reg > ARRAY_SIZE(wm8580_reg));
+
+	/* Registers are 9 bits wide */
+	value &= 0x1ff;
+
+	switch (reg) {
+	case WM8580_RESET:
+		/* Uncached */
+		break;
+	default:
+		if (value == wm8580_read_reg_cache(codec, reg))
+			return 0;
+	}
+
+	/* data is
+	 *   D15..D9 WM8580 register offset
+	 *   D8...D0 register data
+	 */
+	data[0] = (reg << 1) | ((value >> 8) & 0x0001);
+	data[1] = value & 0x00ff;
+
+	wm8580_write_reg_cache(codec, reg, value);
+	if (codec->hw_write(codec->control_data, data, 2) == 2)
+		return 0;
+	else
+		return -EIO;
+}
+
+static inline unsigned int wm8580_read(struct snd_soc_codec *codec,
+				       unsigned int reg)
+{
+	switch (reg) {
+	default:
+		return wm8580_read_reg_cache(codec, reg);
+	}
+}
+
+static const DECLARE_TLV_DB_SCALE(dac_tlv, -12750, 50, 1);
+
+static int wm8580_out_vu(struct snd_kcontrol *kcontrol,
+			 struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	int reg = kcontrol->private_value & 0xff;
+	int reg2 = (kcontrol->private_value >> 24) & 0xff;
+	int ret;
+	u16 val;
+
+	/* Clear the register cache so we write without VU set */
+	wm8580_write_reg_cache(codec, reg, 0);
+	wm8580_write_reg_cache(codec, reg2, 0);
+
+	ret = snd_soc_put_volsw_2r(kcontrol, ucontrol);
+	if (ret < 0)
+		return ret;
+
+	/* Now write again with the volume update bit set */
+	val = wm8580_read_reg_cache(codec, reg);
+	wm8580_write(codec, reg, val | 0x0100);
+
+	val = wm8580_read_reg_cache(codec, reg2);
+	wm8580_write(codec, reg2, val | 0x0100);
+
+	return 0;
+}
+
+#define SOC_WM8580_OUT_DOUBLE_R_TLV(xname, reg_left, reg_right, shift, max, invert, tlv_array) \
+{	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
+	.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\
+		SNDRV_CTL_ELEM_ACCESS_READWRITE,  \
+	.tlv.p = (tlv_array), \
+	.info = snd_soc_info_volsw_2r, \
+	.get = snd_soc_get_volsw_2r, .put = wm8580_out_vu, \
+	.private_value = (reg_left) | ((shift) << 8)  |		\
+		((max) << 12) | ((invert) << 20) | ((reg_right) << 24) }
+
+static const struct snd_kcontrol_new wm8580_snd_controls[] = {
+SOC_WM8580_OUT_DOUBLE_R_TLV("DAC1 Playback Volume",
+			    WM8580_DIGITAL_ATTENUATION_DACL1,
+			    WM8580_DIGITAL_ATTENUATION_DACR1,
+			    0, 0xff, 0, dac_tlv),
+SOC_WM8580_OUT_DOUBLE_R_TLV("DAC2 Playback Volume",
+			    WM8580_DIGITAL_ATTENUATION_DACL2,
+			    WM8580_DIGITAL_ATTENUATION_DACR2,
+			    0, 0xff, 0, dac_tlv),
+SOC_WM8580_OUT_DOUBLE_R_TLV("DAC3 Playback Volume",
+			    WM8580_DIGITAL_ATTENUATION_DACL3,
+			    WM8580_DIGITAL_ATTENUATION_DACR3,
+			    0, 0xff, 0, dac_tlv),
+
+SOC_SINGLE("DAC1 Deemphasis Switch", WM8580_DAC_CONTROL3, 0, 1, 0),
+SOC_SINGLE("DAC2 Deemphasis Switch", WM8580_DAC_CONTROL3, 1, 1, 0),
+SOC_SINGLE("DAC3 Deemphasis Switch", WM8580_DAC_CONTROL3, 2, 1, 0),
+
+SOC_DOUBLE("DAC1 Invert Switch", WM8580_DAC_CONTROL4,  0, 1, 1, 0),
+SOC_DOUBLE("DAC2 Invert Switch", WM8580_DAC_CONTROL4,  2, 3, 1, 0),
+SOC_DOUBLE("DAC3 Invert Switch", WM8580_DAC_CONTROL4,  4, 5, 1, 0),
+
+SOC_SINGLE("DAC ZC Switch", WM8580_DAC_CONTROL5, 5, 1, 0),
+SOC_SINGLE("DAC1 Switch", WM8580_DAC_CONTROL5, 0, 1, 0),
+SOC_SINGLE("DAC2 Switch", WM8580_DAC_CONTROL5, 1, 1, 0),
+SOC_SINGLE("DAC3 Switch", WM8580_DAC_CONTROL5, 2, 1, 0),
+
+SOC_DOUBLE("ADC Mute Switch", WM8580_ADC_CONTROL1, 0, 1, 1, 0),
+SOC_SINGLE("ADC High-Pass Filter Switch", WM8580_ADC_CONTROL1, 4, 1, 0),
+};
+
+/* Add non-DAPM controls */
+static int wm8580_add_controls(struct snd_soc_codec *codec)
+{
+	int err, i;
+
+	for (i = 0; i < ARRAY_SIZE(wm8580_snd_controls); i++) {
+		err = snd_ctl_add(codec->card,
+				  snd_soc_cnew(&wm8580_snd_controls[i],
+					       codec, NULL));
+		if (err < 0)
+			return err;
+	}
+	return 0;
+}
+static const struct snd_soc_dapm_widget wm8580_dapm_widgets[] = {
+SND_SOC_DAPM_DAC("DAC1", "Playback", WM8580_PWRDN1, 2, 1),
+SND_SOC_DAPM_DAC("DAC2", "Playback", WM8580_PWRDN1, 3, 1),
+SND_SOC_DAPM_DAC("DAC3", "Playback", WM8580_PWRDN1, 4, 1),
+
+SND_SOC_DAPM_OUTPUT("VOUT1L"),
+SND_SOC_DAPM_OUTPUT("VOUT1R"),
+SND_SOC_DAPM_OUTPUT("VOUT2L"),
+SND_SOC_DAPM_OUTPUT("VOUT2R"),
+SND_SOC_DAPM_OUTPUT("VOUT3L"),
+SND_SOC_DAPM_OUTPUT("VOUT3R"),
+
+SND_SOC_DAPM_ADC("ADC", "Capture", WM8580_PWRDN1, 1, 1),
+
+SND_SOC_DAPM_INPUT("AINL"),
+SND_SOC_DAPM_INPUT("AINR"),
+};
+
+static const struct snd_soc_dapm_route audio_map[] = {
+	{ "VOUT1L", NULL, "DAC1" },
+	{ "VOUT1R", NULL, "DAC1" },
+
+	{ "VOUT2L", NULL, "DAC2" },
+	{ "VOUT2R", NULL, "DAC2" },
+
+	{ "VOUT3L", NULL, "DAC3" },
+	{ "VOUT3R", NULL, "DAC3" },
+
+	{ "ADC", NULL, "AINL" },
+	{ "ADC", NULL, "AINR" },
+};
+
+static int wm8580_add_widgets(struct snd_soc_codec *codec)
+{
+	snd_soc_dapm_new_controls(codec, wm8580_dapm_widgets,
+				  ARRAY_SIZE(wm8580_dapm_widgets));
+
+	snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+
+	snd_soc_dapm_new_widgets(codec);
+	return 0;
+}
+
+/* PLL divisors */
+struct _pll_div {
+	u32 prescale:1;
+	u32 postscale:1;
+	u32 freqmode:2;
+	u32 n:4;
+	u32 k:24;
+};
+
+/* The size in bits of the pll divide */
+#define FIXED_PLL_SIZE (1 << 22)
+
+/* PLL rate to output rate divisions */
+static struct {
+	unsigned int div;
+	unsigned int freqmode;
+	unsigned int postscale;
+} post_table[] = {
+	{  2,  0, 0 },
+	{  4,  0, 1 },
+	{  4,  1, 0 },
+	{  8,  1, 1 },
+	{  8,  2, 0 },
+	{ 16,  2, 1 },
+	{ 12,  3, 0 },
+	{ 24,  3, 1 }
+};
+
+static int pll_factors(struct _pll_div *pll_div, unsigned int target,
+		       unsigned int source)
+{
+	u64 Kpart;
+	unsigned int K, Ndiv, Nmod;
+	int i;
+
+	pr_debug("wm8580: PLL %dHz->%dHz\n", source, target);
+
+	/* Scale the output frequency up; the PLL should run in the
+	 * region of 90-100MHz.
+	 */
+	for (i = 0; i < ARRAY_SIZE(post_table); i++) {
+		if (target * post_table[i].div >=  90000000 &&
+		    target * post_table[i].div <= 100000000) {
+			pll_div->freqmode = post_table[i].freqmode;
+			pll_div->postscale = post_table[i].postscale;
+			target *= post_table[i].div;
+			break;
+		}
+	}
+
+	if (i == ARRAY_SIZE(post_table)) {
+		printk(KERN_ERR "wm8580: Unable to scale output frequency "
+		       "%u\n", target);
+		return -EINVAL;
+	}
+
+	Ndiv = target / source;
+
+	if (Ndiv < 5) {
+		source /= 2;
+		pll_div->prescale = 1;
+		Ndiv = target / source;
+	} else
+		pll_div->prescale = 0;
+
+	if ((Ndiv < 5) || (Ndiv > 13)) {
+		printk(KERN_ERR
+			"WM8580 N=%d outside supported range\n", Ndiv);
+		return -EINVAL;
+	}
+
+	pll_div->n = Ndiv;
+	Nmod = target % source;
+	Kpart = FIXED_PLL_SIZE * (long long)Nmod;
+
+	do_div(Kpart, source);
+
+	K = Kpart & 0xFFFFFFFF;
+
+	pll_div->k = K;
+
+	pr_debug("PLL %x.%x prescale %d freqmode %d postscale %d\n",
+		 pll_div->n, pll_div->k, pll_div->prescale, pll_div->freqmode,
+		 pll_div->postscale);
+
+	return 0;
+}
+
+static int wm8580_set_dai_pll(struct snd_soc_dai *codec_dai,
+		int pll_id, unsigned int freq_in, unsigned int freq_out)
+{
+	int offset;
+	struct snd_soc_codec *codec = codec_dai->codec;
+	struct wm8580_priv *wm8580 = codec->private_data;
+	struct pll_state *state;
+	struct _pll_div pll_div;
+	unsigned int reg;
+	unsigned int pwr_mask;
+	int ret;
+
+	/* GCC isn't able to work out the ifs below for initialising/using
+	 * pll_div so suppress warnings.
+	 */
+	memset(&pll_div, 0, sizeof(pll_div));
+
+	switch (pll_id) {
+	case WM8580_PLLA:
+		state = &wm8580->a;
+		offset = 0;
+		pwr_mask = WM8580_PWRDN2_PLLAPD;
+		break;
+	case WM8580_PLLB:
+		state = &wm8580->b;
+		offset = 4;
+		pwr_mask = WM8580_PWRDN2_PLLBPD;
+		break;
+	default:
+		return -ENODEV;
+	}
+
+	if (freq_in && freq_out) {
+		ret = pll_factors(&pll_div, freq_out, freq_in);
+		if (ret != 0)
+			return ret;
+	}
+
+	state->in = freq_in;
+	state->out = freq_out;
+
+	/* Always disable the PLL - it is not safe to leave it running
+	 * while reprogramming it.
+	 */
+	reg = wm8580_read(codec, WM8580_PWRDN2);
+	wm8580_write(codec, WM8580_PWRDN2, reg | pwr_mask);
+
+	if (!freq_in || !freq_out)
+		return 0;
+
+	wm8580_write(codec, WM8580_PLLA1 + offset, pll_div.k & 0x1ff);
+	wm8580_write(codec, WM8580_PLLA2 + offset, (pll_div.k >> 9) & 0xff);
+	wm8580_write(codec, WM8580_PLLA3 + offset,
+		     (pll_div.k >> 18 & 0xf) | (pll_div.n << 4));
+
+	reg = wm8580_read(codec, WM8580_PLLA4 + offset);
+	reg &= ~0x3f;
+	reg |= pll_div.prescale | pll_div.postscale << 1 |
+		pll_div.freqmode << 4;
+
+	wm8580_write(codec, WM8580_PLLA4 + offset, reg);
+
+	/* All done, turn it on */
+	reg = wm8580_read(codec, WM8580_PWRDN2);
+	wm8580_write(codec, WM8580_PWRDN2, reg & ~pwr_mask);
+
+	return 0;
+}
+
+/*
+ * Set PCM DAI bit size and sample rate.
+ */
+static int wm8580_paif_hw_params(struct snd_pcm_substream *substream,
+	struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai_link *dai = rtd->dai;
+	struct snd_soc_device *socdev = rtd->socdev;
+	struct snd_soc_codec *codec = socdev->codec;
+	u16 paifb = wm8580_read(codec, WM8580_PAIF3 + dai->codec_dai->id);
+
+	paifb &= ~WM8580_AIF_LENGTH_MASK;
+	/* bit size */
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S16_LE:
+		break;
+	case SNDRV_PCM_FORMAT_S20_3LE:
+		paifb |= WM8580_AIF_LENGTH_20;
+		break;
+	case SNDRV_PCM_FORMAT_S24_LE:
+		paifb |= WM8580_AIF_LENGTH_24;
+		break;
+	case SNDRV_PCM_FORMAT_S32_LE:
+		paifb |= WM8580_AIF_LENGTH_24;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	wm8580_write(codec, WM8580_PAIF3 + dai->codec_dai->id, paifb);
+	return 0;
+}
+
+static int wm8580_set_paif_dai_fmt(struct snd_soc_dai *codec_dai,
+				      unsigned int fmt)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+	unsigned int aifa;
+	unsigned int aifb;
+	int can_invert_lrclk;
+
+	aifa = wm8580_read(codec, WM8580_PAIF1 + codec_dai->id);
+	aifb = wm8580_read(codec, WM8580_PAIF3 + codec_dai->id);
+
+	aifb &= ~(WM8580_AIF_FMT_MASK | WM8580_AIF_LRP | WM8580_AIF_BCP);
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBS_CFS:
+		aifa &= ~WM8580_AIF_MS;
+		break;
+	case SND_SOC_DAIFMT_CBM_CFM:
+		aifa |= WM8580_AIF_MS;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		can_invert_lrclk = 1;
+		aifb |= WM8580_AIF_FMT_I2S;
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		can_invert_lrclk = 1;
+		aifb |= WM8580_AIF_FMT_RIGHTJ;
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		can_invert_lrclk = 1;
+		aifb |= WM8580_AIF_FMT_LEFTJ;
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		can_invert_lrclk = 0;
+		aifb |= WM8580_AIF_FMT_DSP;
+		break;
+	case SND_SOC_DAIFMT_DSP_B:
+		can_invert_lrclk = 0;
+		aifb |= WM8580_AIF_FMT_DSP;
+		aifb |= WM8580_AIF_LRP;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		break;
+
+	case SND_SOC_DAIFMT_IB_IF:
+		if (!can_invert_lrclk)
+			return -EINVAL;
+		aifb |= WM8580_AIF_BCP;
+		aifb |= WM8580_AIF_LRP;
+		break;
+
+	case SND_SOC_DAIFMT_IB_NF:
+		aifb |= WM8580_AIF_BCP;
+		break;
+
+	case SND_SOC_DAIFMT_NB_IF:
+		if (!can_invert_lrclk)
+			return -EINVAL;
+		aifb |= WM8580_AIF_LRP;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	wm8580_write(codec, WM8580_PAIF1 + codec_dai->id, aifa);
+	wm8580_write(codec, WM8580_PAIF3 + codec_dai->id, aifb);
+
+	return 0;
+}
+
+static int wm8580_set_dai_clkdiv(struct snd_soc_dai *codec_dai,
+				 int div_id, int div)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+	unsigned int reg;
+
+	switch (div_id) {
+	case WM8580_MCLK:
+		reg = wm8580_read(codec, WM8580_PLLB4);
+		reg &= ~WM8580_PLLB4_MCLKOUTSRC_MASK;
+
+		switch (div) {
+		case WM8580_CLKSRC_MCLK:
+			/* Input */
+			break;
+
+		case WM8580_CLKSRC_PLLA:
+			reg |= WM8580_PLLB4_MCLKOUTSRC_PLLA;
+			break;
+		case WM8580_CLKSRC_PLLB:
+			reg |= WM8580_PLLB4_MCLKOUTSRC_PLLB;
+			break;
+
+		case WM8580_CLKSRC_OSC:
+			reg |= WM8580_PLLB4_MCLKOUTSRC_OSC;
+			break;
+
+		default:
+			return -EINVAL;
+		}
+		wm8580_write(codec, WM8580_PLLB4, reg);
+		break;
+
+	case WM8580_DAC_CLKSEL:
+		reg = wm8580_read(codec, WM8580_CLKSEL);
+		reg &= ~WM8580_CLKSEL_DAC_CLKSEL_MASK;
+
+		switch (div) {
+		case WM8580_CLKSRC_MCLK:
+			break;
+
+		case WM8580_CLKSRC_PLLA:
+			reg |= WM8580_CLKSEL_DAC_CLKSEL_PLLA;
+			break;
+
+		case WM8580_CLKSRC_PLLB:
+			reg |= WM8580_CLKSEL_DAC_CLKSEL_PLLB;
+			break;
+
+		default:
+			return -EINVAL;
+		}
+		wm8580_write(codec, WM8580_CLKSEL, reg);
+		break;
+
+	case WM8580_CLKOUTSRC:
+		reg = wm8580_read(codec, WM8580_PLLB4);
+		reg &= ~WM8580_PLLB4_CLKOUTSRC_MASK;
+
+		switch (div) {
+		case WM8580_CLKSRC_NONE:
+			break;
+
+		case WM8580_CLKSRC_PLLA:
+			reg |= WM8580_PLLB4_CLKOUTSRC_PLLACLK;
+			break;
+
+		case WM8580_CLKSRC_PLLB:
+			reg |= WM8580_PLLB4_CLKOUTSRC_PLLBCLK;
+			break;
+
+		case WM8580_CLKSRC_OSC:
+			reg |= WM8580_PLLB4_CLKOUTSRC_OSCCLK;
+			break;
+
+		default:
+			return -EINVAL;
+		}
+		wm8580_write(codec, WM8580_PLLB4, reg);
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int wm8580_digital_mute(struct snd_soc_dai *codec_dai, int mute)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+	unsigned int reg;
+
+	reg = wm8580_read(codec, WM8580_DAC_CONTROL5);
+
+	if (mute)
+		reg |= WM8580_DAC_CONTROL5_MUTEALL;
+	else
+		reg &= ~WM8580_DAC_CONTROL5_MUTEALL;
+
+	wm8580_write(codec, WM8580_DAC_CONTROL5, reg);
+
+	return 0;
+}
+
+static int wm8580_set_bias_level(struct snd_soc_codec *codec,
+	enum snd_soc_bias_level level)
+{
+	u16 reg;
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+	case SND_SOC_BIAS_PREPARE:
+	case SND_SOC_BIAS_STANDBY:
+		break;
+	case SND_SOC_BIAS_OFF:
+		reg = wm8580_read(codec, WM8580_PWRDN1);
+		wm8580_write(codec, WM8580_PWRDN1, reg | WM8580_PWRDN1_PWDN);
+		break;
+	}
+	codec->bias_level = level;
+	return 0;
+}
+
+#define WM8580_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
+			SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+struct snd_soc_dai wm8580_dai[] = {
+	{
+		.name = "WM8580 PAIFRX",
+		.id = 0,
+		.playback = {
+			.stream_name = "Playback",
+			.channels_min = 1,
+			.channels_max = 6,
+			.rates = SNDRV_PCM_RATE_8000_192000,
+			.formats = WM8580_FORMATS,
+		},
+		.ops = {
+			 .hw_params = wm8580_paif_hw_params,
+		 },
+		.dai_ops = {
+			 .set_fmt = wm8580_set_paif_dai_fmt,
+			 .set_clkdiv = wm8580_set_dai_clkdiv,
+			 .set_pll = wm8580_set_dai_pll,
+			 .digital_mute = wm8580_digital_mute,
+		 },
+	},
+	{
+		.name = "WM8580 PAIFTX",
+		.id = 1,
+		.capture = {
+			.stream_name = "Capture",
+			.channels_min = 2,
+			.channels_max = 2,
+			.rates = SNDRV_PCM_RATE_8000_192000,
+			.formats = WM8580_FORMATS,
+		},
+		.ops = {
+			 .hw_params = wm8580_paif_hw_params,
+		 },
+		.dai_ops = {
+			 .set_fmt = wm8580_set_paif_dai_fmt,
+			 .set_clkdiv = wm8580_set_dai_clkdiv,
+			 .set_pll = wm8580_set_dai_pll,
+		 },
+	},
+};
+EXPORT_SYMBOL_GPL(wm8580_dai);
+
+/*
+ * initialise the WM8580 driver
+ * register the mixer and dsp interfaces with the kernel
+ */
+static int wm8580_init(struct snd_soc_device *socdev)
+{
+	struct snd_soc_codec *codec = socdev->codec;
+	int ret = 0;
+
+	codec->name = "WM8580";
+	codec->owner = THIS_MODULE;
+	codec->read = wm8580_read_reg_cache;
+	codec->write = wm8580_write;
+	codec->set_bias_level = wm8580_set_bias_level;
+	codec->dai = wm8580_dai;
+	codec->num_dai = ARRAY_SIZE(wm8580_dai);
+	codec->reg_cache_size = ARRAY_SIZE(wm8580_reg);
+	codec->reg_cache = kmemdup(wm8580_reg, sizeof(wm8580_reg),
+				   GFP_KERNEL);
+
+	if (codec->reg_cache == NULL)
+		return -ENOMEM;
+
+	/* Get the codec into a known state */
+	wm8580_write(codec, WM8580_RESET, 0);
+
+	/* Power up and get individual control of the DACs */
+	wm8580_write(codec, WM8580_PWRDN1, wm8580_read(codec, WM8580_PWRDN1) &
+		     ~(WM8580_PWRDN1_PWDN | WM8580_PWRDN1_ALLDACPD));
+
+	/* Make VMID high impedence */
+	wm8580_write(codec, WM8580_ADC_CONTROL1,
+		     wm8580_read(codec,  WM8580_ADC_CONTROL1) & ~0x100);
+
+	/* register pcms */
+	ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1,
+			       SNDRV_DEFAULT_STR1);
+	if (ret < 0) {
+		printk(KERN_ERR "wm8580: failed to create pcms\n");
+		goto pcm_err;
+	}
+
+	wm8580_add_controls(codec);
+	wm8580_add_widgets(codec);
+
+	ret = snd_soc_register_card(socdev);
+	if (ret < 0) {
+		printk(KERN_ERR "wm8580: failed to register card\n");
+		goto card_err;
+	}
+	return ret;
+
+card_err:
+	snd_soc_free_pcms(socdev);
+	snd_soc_dapm_free(socdev);
+pcm_err:
+	kfree(codec->reg_cache);
+	return ret;
+}
+
+/* If the i2c layer weren't so broken, we could pass this kind of data
+   around */
+static struct snd_soc_device *wm8580_socdev;
+
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+
+/*
+ * WM8580 2 wire address is determined by GPIO5
+ * state during powerup.
+ *    low  = 0x1a
+ *    high = 0x1b
+ */
+static unsigned short normal_i2c[] = { 0, I2C_CLIENT_END };
+
+/* Magic definition of all other variables and things */
+I2C_CLIENT_INSMOD;
+
+static struct i2c_driver wm8580_i2c_driver;
+static struct i2c_client client_template;
+
+static int wm8580_codec_probe(struct i2c_adapter *adap, int addr, int kind)
+{
+	struct snd_soc_device *socdev = wm8580_socdev;
+	struct wm8580_setup_data *setup = socdev->codec_data;
+	struct snd_soc_codec *codec = socdev->codec;
+	struct i2c_client *i2c;
+	int ret;
+
+	if (addr != setup->i2c_address)
+		return -ENODEV;
+
+	client_template.adapter = adap;
+	client_template.addr = addr;
+
+	i2c =  kmemdup(&client_template, sizeof(client_template), GFP_KERNEL);
+	if (i2c == NULL) {
+		kfree(codec);
+		return -ENOMEM;
+	}
+	i2c_set_clientdata(i2c, codec);
+	codec->control_data = i2c;
+
+	ret = i2c_attach_client(i2c);
+	if (ret < 0) {
+		dev_err(&i2c->dev, "failed to attach codec at addr %x\n", addr);
+		goto err;
+	}
+
+	ret = wm8580_init(socdev);
+	if (ret < 0) {
+		dev_err(&i2c->dev, "failed to initialise WM8580\n");
+		goto err;
+	}
+
+	return ret;
+
+err:
+	kfree(codec);
+	kfree(i2c);
+	return ret;
+}
+
+static int wm8580_i2c_detach(struct i2c_client *client)
+{
+	struct snd_soc_codec *codec = i2c_get_clientdata(client);
+	i2c_detach_client(client);
+	kfree(codec->reg_cache);
+	kfree(client);
+	return 0;
+}
+
+static int wm8580_i2c_attach(struct i2c_adapter *adap)
+{
+	return i2c_probe(adap, &addr_data, wm8580_codec_probe);
+}
+
+/* corgi i2c codec control layer */
+static struct i2c_driver wm8580_i2c_driver = {
+	.driver = {
+		.name = "WM8580 I2C Codec",
+		.owner = THIS_MODULE,
+	},
+	.attach_adapter = wm8580_i2c_attach,
+	.detach_client =  wm8580_i2c_detach,
+	.command =        NULL,
+};
+
+static struct i2c_client client_template = {
+	.name =   "WM8580",
+	.driver = &wm8580_i2c_driver,
+};
+#endif
+
+static int wm8580_probe(struct platform_device *pdev)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	struct wm8580_setup_data *setup;
+	struct snd_soc_codec *codec;
+	struct wm8580_priv *wm8580;
+	int ret = 0;
+
+	pr_info("WM8580 Audio Codec %s\n", WM8580_VERSION);
+
+	setup = socdev->codec_data;
+	codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
+	if (codec == NULL)
+		return -ENOMEM;
+
+	wm8580 = kzalloc(sizeof(struct wm8580_priv), GFP_KERNEL);
+	if (wm8580 == NULL) {
+		kfree(codec);
+		return -ENOMEM;
+	}
+
+	codec->private_data = wm8580;
+	socdev->codec = codec;
+	mutex_init(&codec->mutex);
+	INIT_LIST_HEAD(&codec->dapm_widgets);
+	INIT_LIST_HEAD(&codec->dapm_paths);
+	wm8580_socdev = socdev;
+
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+	if (setup->i2c_address) {
+		normal_i2c[0] = setup->i2c_address;
+		codec->hw_write = (hw_write_t)i2c_master_send;
+		ret = i2c_add_driver(&wm8580_i2c_driver);
+		if (ret != 0)
+			printk(KERN_ERR "can't add i2c driver");
+	}
+#else
+		/* Add other interfaces here */
+#endif
+	return ret;
+}
+
+/* power down chip */
+static int wm8580_remove(struct platform_device *pdev)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	struct snd_soc_codec *codec = socdev->codec;
+
+	if (codec->control_data)
+		wm8580_set_bias_level(codec, SND_SOC_BIAS_OFF);
+	snd_soc_free_pcms(socdev);
+	snd_soc_dapm_free(socdev);
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+	i2c_del_driver(&wm8580_i2c_driver);
+#endif
+	kfree(codec->private_data);
+	kfree(codec);
+
+	return 0;
+}
+
+struct snd_soc_codec_device soc_codec_dev_wm8580 = {
+	.probe = 	wm8580_probe,
+	.remove = 	wm8580_remove,
+};
+EXPORT_SYMBOL_GPL(soc_codec_dev_wm8580);
+
+MODULE_DESCRIPTION("ASoC WM8580 driver");
+MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm8580.h b/sound/soc/codecs/wm8580.h
new file mode 100644
index 0000000..589ddab
--- /dev/null
+++ b/sound/soc/codecs/wm8580.h
@@ -0,0 +1,42 @@
+/*
+ * wm8580.h  --  audio driver for WM8580
+ *
+ * Copyright 2008 Samsung Electronics.
+ * Author: Ryu Euiyoul
+ *         ryu.real@gmail.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 _WM8580_H
+#define _WM8580_H
+
+#define WM8580_PLLA  1
+#define WM8580_PLLB  2
+
+#define WM8580_MCLK       1
+#define WM8580_DAC_CLKSEL 2
+#define WM8580_CLKOUTSRC  3
+
+#define WM8580_CLKSRC_MCLK 1
+#define WM8580_CLKSRC_PLLA 2
+#define WM8580_CLKSRC_PLLB 3
+#define WM8580_CLKSRC_OSC  4
+#define WM8580_CLKSRC_NONE 5
+
+struct wm8580_setup_data {
+	unsigned short i2c_address;
+};
+
+#define WM8580_DAI_PAIFRX 0
+#define WM8580_DAI_PAIFTX 1
+
+extern struct snd_soc_dai wm8580_dai[];
+extern struct snd_soc_codec_device soc_codec_dev_wm8580;
+
+#endif
+
diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c
index 9402fca..7f8a7e3 100644
--- a/sound/soc/codecs/wm8731.c
+++ b/sound/soc/codecs/wm8731.c
@@ -19,6 +19,7 @@
 #include <linux/pm.h>
 #include <linux/i2c.h>
 #include <linux/platform_device.h>
+#include <linux/spi/spi.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
@@ -28,7 +29,6 @@
 
 #include "wm8731.h"
 
-#define AUDIO_NAME "wm8731"
 #define WM8731_VERSION "0.13"
 
 struct snd_soc_codec_device soc_codec_dev_wm8731;
@@ -570,88 +570,144 @@
  *    low  = 0x1a
  *    high = 0x1b
  */
-static unsigned short normal_i2c[] = { 0, I2C_CLIENT_END };
 
-/* Magic definition of all other variables and things */
-I2C_CLIENT_INSMOD;
-
-static struct i2c_driver wm8731_i2c_driver;
-static struct i2c_client client_template;
-
-/* If the i2c layer weren't so broken, we could pass this kind of data
-   around */
-
-static int wm8731_codec_probe(struct i2c_adapter *adap, int addr, int kind)
+static int wm8731_i2c_probe(struct i2c_client *i2c,
+			    const struct i2c_device_id *id)
 {
 	struct snd_soc_device *socdev = wm8731_socdev;
-	struct wm8731_setup_data *setup = socdev->codec_data;
 	struct snd_soc_codec *codec = socdev->codec;
-	struct i2c_client *i2c;
 	int ret;
 
-	if (addr != setup->i2c_address)
-		return -ENODEV;
-
-	client_template.adapter = adap;
-	client_template.addr = addr;
-
-	i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL);
-	if (i2c == NULL)
-		return -ENOMEM;
-
 	i2c_set_clientdata(i2c, codec);
 	codec->control_data = i2c;
 
-	ret = i2c_attach_client(i2c);
-	if (ret < 0) {
-		pr_err("failed to attach codec at addr %x\n", addr);
-		goto err;
-	}
-
 	ret = wm8731_init(socdev);
-	if (ret < 0) {
+	if (ret < 0)
 		pr_err("failed to initialise WM8731\n");
-		goto err;
-	}
-	return ret;
 
-err:
-	kfree(i2c);
 	return ret;
 }
 
-static int wm8731_i2c_detach(struct i2c_client *client)
+static int wm8731_i2c_remove(struct i2c_client *client)
 {
 	struct snd_soc_codec *codec = i2c_get_clientdata(client);
-	i2c_detach_client(client);
 	kfree(codec->reg_cache);
-	kfree(client);
 	return 0;
 }
 
-static int wm8731_i2c_attach(struct i2c_adapter *adap)
-{
-	return i2c_probe(adap, &addr_data, wm8731_codec_probe);
-}
+static const struct i2c_device_id wm8731_i2c_id[] = {
+	{ "wm8731", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, wm8731_i2c_id);
 
-/* corgi i2c codec control layer */
 static struct i2c_driver wm8731_i2c_driver = {
 	.driver = {
 		.name = "WM8731 I2C Codec",
 		.owner = THIS_MODULE,
 	},
-	.id =             I2C_DRIVERID_WM8731,
-	.attach_adapter = wm8731_i2c_attach,
-	.detach_client =  wm8731_i2c_detach,
-	.command =        NULL,
+	.probe =    wm8731_i2c_probe,
+	.remove =   wm8731_i2c_remove,
+	.id_table = wm8731_i2c_id,
 };
 
-static struct i2c_client client_template = {
-	.name =   "WM8731",
-	.driver = &wm8731_i2c_driver,
-};
+static int wm8731_add_i2c_device(struct platform_device *pdev,
+				 const struct wm8731_setup_data *setup)
+{
+	struct i2c_board_info info;
+	struct i2c_adapter *adapter;
+	struct i2c_client *client;
+	int ret;
+
+	ret = i2c_add_driver(&wm8731_i2c_driver);
+	if (ret != 0) {
+		dev_err(&pdev->dev, "can't add i2c driver\n");
+		return ret;
+	}
+
+	memset(&info, 0, sizeof(struct i2c_board_info));
+	info.addr = setup->i2c_address;
+	strlcpy(info.type, "wm8731", I2C_NAME_SIZE);
+
+	adapter = i2c_get_adapter(setup->i2c_bus);
+	if (!adapter) {
+		dev_err(&pdev->dev, "can't get i2c adapter %d\n",
+			setup->i2c_bus);
+		goto err_driver;
+	}
+
+	client = i2c_new_device(adapter, &info);
+	i2c_put_adapter(adapter);
+	if (!client) {
+		dev_err(&pdev->dev, "can't add i2c device at 0x%x\n",
+			(unsigned int)info.addr);
+		goto err_driver;
+	}
+
+	return 0;
+
+err_driver:
+	i2c_del_driver(&wm8731_i2c_driver);
+	return -ENODEV;
+}
 #endif
 
+#if defined(CONFIG_SPI_MASTER)
+static int __devinit wm8731_spi_probe(struct spi_device *spi)
+{
+	struct snd_soc_device *socdev = wm8731_socdev;
+	struct snd_soc_codec *codec = socdev->codec;
+	int ret;
+
+	codec->control_data = spi;
+
+	ret = wm8731_init(socdev);
+	if (ret < 0)
+		dev_err(&spi->dev, "failed to initialise WM8731\n");
+
+	return ret;
+}
+
+static int __devexit wm8731_spi_remove(struct spi_device *spi)
+{
+	return 0;
+}
+
+static struct spi_driver wm8731_spi_driver = {
+	.driver = {
+		.name	= "wm8731",
+		.bus	= &spi_bus_type,
+		.owner	= THIS_MODULE,
+	},
+	.probe		= wm8731_spi_probe,
+	.remove		= __devexit_p(wm8731_spi_remove),
+};
+
+static int wm8731_spi_write(struct spi_device *spi, const char *data, int len)
+{
+	struct spi_transfer t;
+	struct spi_message m;
+	u8 msg[2];
+
+	if (len <= 0)
+		return 0;
+
+	msg[0] = data[0];
+	msg[1] = data[1];
+
+	spi_message_init(&m);
+	memset(&t, 0, (sizeof t));
+
+	t.tx_buf = &msg[0];
+	t.len = len;
+
+	spi_message_add_tail(&t, &m);
+	spi_sync(spi, &m);
+
+	return len;
+}
+#endif /* CONFIG_SPI_MASTER */
+
 static int wm8731_probe(struct platform_device *pdev)
 {
 	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
@@ -680,16 +736,21 @@
 	INIT_LIST_HEAD(&codec->dapm_paths);
 
 	wm8731_socdev = socdev;
+	ret = -ENODEV;
+
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
 	if (setup->i2c_address) {
-		normal_i2c[0] = setup->i2c_address;
 		codec->hw_write = (hw_write_t)i2c_master_send;
-		ret = i2c_add_driver(&wm8731_i2c_driver);
-		if (ret != 0)
-			printk(KERN_ERR "can't add i2c driver");
+		ret = wm8731_add_i2c_device(pdev, setup);
 	}
-#else
-	/* Add other interfaces here */
+#endif
+#if defined(CONFIG_SPI_MASTER)
+	if (setup->spi) {
+		codec->hw_write = (hw_write_t)wm8731_spi_write;
+		ret = spi_register_driver(&wm8731_spi_driver);
+		if (ret != 0)
+			printk(KERN_ERR "can't add spi driver");
+	}
 #endif
 
 	if (ret != 0) {
@@ -711,8 +772,12 @@
 	snd_soc_free_pcms(socdev);
 	snd_soc_dapm_free(socdev);
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+	i2c_unregister_device(codec->control_data);
 	i2c_del_driver(&wm8731_i2c_driver);
 #endif
+#if defined(CONFIG_SPI_MASTER)
+	spi_unregister_driver(&wm8731_spi_driver);
+#endif
 	kfree(codec->private_data);
 	kfree(codec);
 
diff --git a/sound/soc/codecs/wm8731.h b/sound/soc/codecs/wm8731.h
index 99f2e3c..95190e9 100644
--- a/sound/soc/codecs/wm8731.h
+++ b/sound/soc/codecs/wm8731.h
@@ -35,6 +35,8 @@
 #define WM8731_DAI		0
 
 struct wm8731_setup_data {
+	int            spi;
+	int            i2c_bus;
 	unsigned short i2c_address;
 };
 
diff --git a/sound/soc/codecs/wm8750.c b/sound/soc/codecs/wm8750.c
index dd1f554..9b7296e 100644
--- a/sound/soc/codecs/wm8750.c
+++ b/sound/soc/codecs/wm8750.c
@@ -19,6 +19,7 @@
 #include <linux/pm.h>
 #include <linux/i2c.h>
 #include <linux/platform_device.h>
+#include <linux/spi/spi.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
@@ -28,7 +29,6 @@
 
 #include "wm8750.h"
 
-#define AUDIO_NAME "WM8750"
 #define WM8750_VERSION "0.12"
 
 /* codec private data */
@@ -841,88 +841,147 @@
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
 
 /*
- * WM8731 2 wire address is determined by GPIO5
+ * WM8750 2 wire address is determined by GPIO5
  * state during powerup.
  *    low  = 0x1a
  *    high = 0x1b
  */
-static unsigned short normal_i2c[] = { 0, I2C_CLIENT_END };
 
-/* Magic definition of all other variables and things */
-I2C_CLIENT_INSMOD;
-
-static struct i2c_driver wm8750_i2c_driver;
-static struct i2c_client client_template;
-
-static int wm8750_codec_probe(struct i2c_adapter *adap, int addr, int kind)
+static int wm8750_i2c_probe(struct i2c_client *i2c,
+			    const struct i2c_device_id *id)
 {
 	struct snd_soc_device *socdev = wm8750_socdev;
-	struct wm8750_setup_data *setup = socdev->codec_data;
 	struct snd_soc_codec *codec = socdev->codec;
-	struct i2c_client *i2c;
 	int ret;
 
-	if (addr != setup->i2c_address)
-		return -ENODEV;
-
-	client_template.adapter = adap;
-	client_template.addr = addr;
-
-	i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL);
-	if (i2c == NULL)
-		return -ENOMEM;
-
 	i2c_set_clientdata(i2c, codec);
 	codec->control_data = i2c;
 
-	ret = i2c_attach_client(i2c);
-	if (ret < 0) {
-		pr_err("failed to attach codec at addr %x\n", addr);
-		goto err;
-	}
-
 	ret = wm8750_init(socdev);
-	if (ret < 0) {
+	if (ret < 0)
 		pr_err("failed to initialise WM8750\n");
-		goto err;
-	}
-	return ret;
 
-err:
-	kfree(i2c);
 	return ret;
 }
 
-static int wm8750_i2c_detach(struct i2c_client *client)
+static int wm8750_i2c_remove(struct i2c_client *client)
 {
 	struct snd_soc_codec *codec = i2c_get_clientdata(client);
-	i2c_detach_client(client);
 	kfree(codec->reg_cache);
-	kfree(client);
 	return 0;
 }
 
-static int wm8750_i2c_attach(struct i2c_adapter *adap)
-{
-	return i2c_probe(adap, &addr_data, wm8750_codec_probe);
-}
+static const struct i2c_device_id wm8750_i2c_id[] = {
+	{ "wm8750", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, wm8750_i2c_id);
 
-/* corgi i2c codec control layer */
 static struct i2c_driver wm8750_i2c_driver = {
 	.driver = {
 		.name = "WM8750 I2C Codec",
 		.owner = THIS_MODULE,
 	},
-	.id =             I2C_DRIVERID_WM8750,
-	.attach_adapter = wm8750_i2c_attach,
-	.detach_client =  wm8750_i2c_detach,
-	.command =        NULL,
+	.probe =    wm8750_i2c_probe,
+	.remove =   wm8750_i2c_remove,
+	.id_table = wm8750_i2c_id,
 };
 
-static struct i2c_client client_template = {
-	.name =   "WM8750",
-	.driver = &wm8750_i2c_driver,
+static int wm8750_add_i2c_device(struct platform_device *pdev,
+				 const struct wm8750_setup_data *setup)
+{
+	struct i2c_board_info info;
+	struct i2c_adapter *adapter;
+	struct i2c_client *client;
+	int ret;
+
+	ret = i2c_add_driver(&wm8750_i2c_driver);
+	if (ret != 0) {
+		dev_err(&pdev->dev, "can't add i2c driver\n");
+		return ret;
+	}
+
+	memset(&info, 0, sizeof(struct i2c_board_info));
+	info.addr = setup->i2c_address;
+	strlcpy(info.type, "wm8750", I2C_NAME_SIZE);
+
+	adapter = i2c_get_adapter(setup->i2c_bus);
+	if (!adapter) {
+		dev_err(&pdev->dev, "can't get i2c adapter %d\n",
+			setup->i2c_bus);
+		goto err_driver;
+	}
+
+	client = i2c_new_device(adapter, &info);
+	i2c_put_adapter(adapter);
+	if (!client) {
+		dev_err(&pdev->dev, "can't add i2c device at 0x%x\n",
+			(unsigned int)info.addr);
+		goto err_driver;
+	}
+
+	return 0;
+
+err_driver:
+	i2c_del_driver(&wm8750_i2c_driver);
+	return -ENODEV;
+}
+#endif
+
+#if defined(CONFIG_SPI_MASTER)
+static int __devinit wm8750_spi_probe(struct spi_device *spi)
+{
+	struct snd_soc_device *socdev = wm8750_socdev;
+	struct snd_soc_codec *codec = socdev->codec;
+	int ret;
+
+	codec->control_data = spi;
+
+	ret = wm8750_init(socdev);
+	if (ret < 0)
+		dev_err(&spi->dev, "failed to initialise WM8750\n");
+
+	return ret;
+}
+
+static int __devexit wm8750_spi_remove(struct spi_device *spi)
+{
+	return 0;
+}
+
+static struct spi_driver wm8750_spi_driver = {
+	.driver = {
+		.name	= "wm8750",
+		.bus	= &spi_bus_type,
+		.owner	= THIS_MODULE,
+	},
+	.probe		= wm8750_spi_probe,
+	.remove		= __devexit_p(wm8750_spi_remove),
 };
+
+static int wm8750_spi_write(struct spi_device *spi, const char *data, int len)
+{
+	struct spi_transfer t;
+	struct spi_message m;
+	u8 msg[2];
+
+	if (len <= 0)
+		return 0;
+
+	msg[0] = data[0];
+	msg[1] = data[1];
+
+	spi_message_init(&m);
+	memset(&t, 0, (sizeof t));
+
+	t.tx_buf = &msg[0];
+	t.len = len;
+
+	spi_message_add_tail(&t, &m);
+	spi_sync(spi, &m);
+
+	return len;
+}
 #endif
 
 static int wm8750_probe(struct platform_device *pdev)
@@ -931,7 +990,7 @@
 	struct wm8750_setup_data *setup = socdev->codec_data;
 	struct snd_soc_codec *codec;
 	struct wm8750_priv *wm8750;
-	int ret = 0;
+	int ret;
 
 	pr_info("WM8750 Audio Codec %s", WM8750_VERSION);
 	codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
@@ -952,16 +1011,21 @@
 	wm8750_socdev = socdev;
 	INIT_DELAYED_WORK(&codec->delayed_work, wm8750_work);
 
+	ret = -ENODEV;
+
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
 	if (setup->i2c_address) {
-		normal_i2c[0] = setup->i2c_address;
 		codec->hw_write = (hw_write_t)i2c_master_send;
-		ret = i2c_add_driver(&wm8750_i2c_driver);
-		if (ret != 0)
-			printk(KERN_ERR "can't add i2c driver");
+		ret = wm8750_add_i2c_device(pdev, setup);
 	}
-#else
-		/* Add other interfaces here */
+#endif
+#if defined(CONFIG_SPI_MASTER)
+	if (setup->spi) {
+		codec->hw_write = (hw_write_t)wm8750_spi_write;
+		ret = spi_register_driver(&wm8750_spi_driver);
+		if (ret != 0)
+			printk(KERN_ERR "can't add spi driver");
+	}
 #endif
 
 	if (ret != 0) {
@@ -1002,8 +1066,12 @@
 	snd_soc_free_pcms(socdev);
 	snd_soc_dapm_free(socdev);
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+	i2c_unregister_device(codec->control_data);
 	i2c_del_driver(&wm8750_i2c_driver);
 #endif
+#if defined(CONFIG_SPI_MASTER)
+	spi_unregister_driver(&wm8750_spi_driver);
+#endif
 	kfree(codec->private_data);
 	kfree(codec);
 
diff --git a/sound/soc/codecs/wm8750.h b/sound/soc/codecs/wm8750.h
index 8ef30e6..1dc100e 100644
--- a/sound/soc/codecs/wm8750.h
+++ b/sound/soc/codecs/wm8750.h
@@ -58,6 +58,8 @@
 #define WM8750_SYSCLK	0
 
 struct wm8750_setup_data {
+	int spi;
+	int i2c_bus;
 	unsigned short i2c_address;
 };
 
diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c
index 5761164..d426eaa 100644
--- a/sound/soc/codecs/wm8753.c
+++ b/sound/soc/codecs/wm8753.c
@@ -2,8 +2,7 @@
  * wm8753.c  --  WM8753 ALSA Soc Audio driver
  *
  * Copyright 2003 Wolfson Microelectronics PLC.
- * Author: Liam Girdwood
- *         liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com
+ * Author: Liam Girdwood <lrg@slimlogic.co.uk>
  *
  *  This program is free software; you can redistribute  it and/or modify it
  *  under  the terms of  the GNU General  Public License as published by the
@@ -40,6 +39,7 @@
 #include <linux/pm.h>
 #include <linux/i2c.h>
 #include <linux/platform_device.h>
+#include <linux/spi/spi.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
@@ -51,7 +51,6 @@
 
 #include "wm8753.h"
 
-#define AUDIO_NAME "wm8753"
 #define WM8753_VERSION "0.16"
 
 static int caps_charge = 2000;
@@ -583,7 +582,7 @@
 
 	/* out 4 */
 	{"Out4 Mux", "VREF", "VREF"},
-	{"Out4 Mux", "Capture ST", "Capture ST Mixer"},
+	{"Out4 Mux", "Capture ST", "Playback Mixer"},
 	{"Out4 Mux", "LOUT2", "LOUT2"},
 	{"Out 4", NULL, "Out4 Mux"},
 	{"OUT4", NULL, "Out 4"},
@@ -607,7 +606,7 @@
 	/* Capture Right Mux */
 	{"Capture Right Mux", "PGA", "Right Capture Volume"},
 	{"Capture Right Mux", "Line or RXP-RXN", "Line Right Mux"},
-	{"Capture Right Mux", "Sidetone", "Capture ST Mixer"},
+	{"Capture Right Mux", "Sidetone", "Playback Mixer"},
 
 	/* Mono Capture mixer-mux */
 	{"Capture Right Mixer", "Stereo", "Capture Right Mux"},
@@ -1637,86 +1636,145 @@
  *    low  = 0x1a
  *    high = 0x1b
  */
-static unsigned short normal_i2c[] = { 0, I2C_CLIENT_END };
 
-/* Magic definition of all other variables and things */
-I2C_CLIENT_INSMOD;
-
-static struct i2c_driver wm8753_i2c_driver;
-static struct i2c_client client_template;
-
-static int wm8753_codec_probe(struct i2c_adapter *adap, int addr, int kind)
+static int wm8753_i2c_probe(struct i2c_client *i2c,
+			    const struct i2c_device_id *id)
 {
 	struct snd_soc_device *socdev = wm8753_socdev;
-	struct wm8753_setup_data *setup = socdev->codec_data;
 	struct snd_soc_codec *codec = socdev->codec;
-	struct i2c_client *i2c;
 	int ret;
 
-	if (addr != setup->i2c_address)
-		return -ENODEV;
-
-	client_template.adapter = adap;
-	client_template.addr = addr;
-
-	i2c =  kmemdup(&client_template, sizeof(client_template), GFP_KERNEL);
-	if (!i2c)
-		return -ENOMEM;
-
 	i2c_set_clientdata(i2c, codec);
 	codec->control_data = i2c;
 
-	ret = i2c_attach_client(i2c);
-	if (ret < 0) {
-		pr_err("failed to attach codec at addr %x\n", addr);
-		goto err;
-	}
-
 	ret = wm8753_init(socdev);
-	if (ret < 0) {
+	if (ret < 0)
 		pr_err("failed to initialise WM8753\n");
-		goto err;
-	}
 
 	return ret;
-
-err:
-	kfree(i2c);
-	return ret;
 }
 
-static int wm8753_i2c_detach(struct i2c_client *client)
+static int wm8753_i2c_remove(struct i2c_client *client)
 {
 	struct snd_soc_codec *codec = i2c_get_clientdata(client);
-	i2c_detach_client(client);
 	kfree(codec->reg_cache);
-	kfree(client);
 	return 0;
 }
 
-static int wm8753_i2c_attach(struct i2c_adapter *adap)
-{
-	return i2c_probe(adap, &addr_data, wm8753_codec_probe);
-}
+static const struct i2c_device_id wm8753_i2c_id[] = {
+	{ "wm8753", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, wm8753_i2c_id);
 
-/* corgi i2c codec control layer */
 static struct i2c_driver wm8753_i2c_driver = {
 	.driver = {
 		.name = "WM8753 I2C Codec",
 		.owner = THIS_MODULE,
 	},
-	.id =             I2C_DRIVERID_WM8753,
-	.attach_adapter = wm8753_i2c_attach,
-	.detach_client =  wm8753_i2c_detach,
-	.command =        NULL,
+	.probe =    wm8753_i2c_probe,
+	.remove =   wm8753_i2c_remove,
+	.id_table = wm8753_i2c_id,
 };
 
-static struct i2c_client client_template = {
-	.name =   "WM8753",
-	.driver = &wm8753_i2c_driver,
-};
+static int wm8753_add_i2c_device(struct platform_device *pdev,
+				 const struct wm8753_setup_data *setup)
+{
+	struct i2c_board_info info;
+	struct i2c_adapter *adapter;
+	struct i2c_client *client;
+	int ret;
+
+	ret = i2c_add_driver(&wm8753_i2c_driver);
+	if (ret != 0) {
+		dev_err(&pdev->dev, "can't add i2c driver\n");
+		return ret;
+	}
+
+	memset(&info, 0, sizeof(struct i2c_board_info));
+	info.addr = setup->i2c_address;
+	strlcpy(info.type, "wm8753", I2C_NAME_SIZE);
+
+	adapter = i2c_get_adapter(setup->i2c_bus);
+	if (!adapter) {
+		dev_err(&pdev->dev, "can't get i2c adapter %d\n",
+			setup->i2c_bus);
+		goto err_driver;
+	}
+
+	client = i2c_new_device(adapter, &info);
+	i2c_put_adapter(adapter);
+	if (!client) {
+		dev_err(&pdev->dev, "can't add i2c device at 0x%x\n",
+			(unsigned int)info.addr);
+		goto err_driver;
+	}
+
+	return 0;
+
+err_driver:
+	i2c_del_driver(&wm8753_i2c_driver);
+	return -ENODEV;
+}
 #endif
 
+#if defined(CONFIG_SPI_MASTER)
+static int __devinit wm8753_spi_probe(struct spi_device *spi)
+{
+	struct snd_soc_device *socdev = wm8753_socdev;
+	struct snd_soc_codec *codec = socdev->codec;
+	int ret;
+
+	codec->control_data = spi;
+
+	ret = wm8753_init(socdev);
+	if (ret < 0)
+		dev_err(&spi->dev, "failed to initialise WM8753\n");
+
+	return ret;
+}
+
+static int __devexit wm8753_spi_remove(struct spi_device *spi)
+{
+	return 0;
+}
+
+static struct spi_driver wm8753_spi_driver = {
+	.driver = {
+		.name	= "wm8753",
+		.bus	= &spi_bus_type,
+		.owner	= THIS_MODULE,
+	},
+	.probe		= wm8753_spi_probe,
+	.remove		= __devexit_p(wm8753_spi_remove),
+};
+
+static int wm8753_spi_write(struct spi_device *spi, const char *data, int len)
+{
+	struct spi_transfer t;
+	struct spi_message m;
+	u8 msg[2];
+
+	if (len <= 0)
+		return 0;
+
+	msg[0] = data[0];
+	msg[1] = data[1];
+
+	spi_message_init(&m);
+	memset(&t, 0, (sizeof t));
+
+	t.tx_buf = &msg[0];
+	t.len = len;
+
+	spi_message_add_tail(&t, &m);
+	spi_sync(spi, &m);
+
+	return len;
+}
+#endif
+
+
 static int wm8753_probe(struct platform_device *pdev)
 {
 	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
@@ -1748,14 +1806,17 @@
 
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
 	if (setup->i2c_address) {
-		normal_i2c[0] = setup->i2c_address;
 		codec->hw_write = (hw_write_t)i2c_master_send;
-		ret = i2c_add_driver(&wm8753_i2c_driver);
-		if (ret != 0)
-			printk(KERN_ERR "can't add i2c driver");
+		ret = wm8753_add_i2c_device(pdev, setup);
 	}
-#else
-		/* Add other interfaces here */
+#endif
+#if defined(CONFIG_SPI_MASTER)
+	if (setup->spi) {
+		codec->hw_write = (hw_write_t)wm8753_spi_write;
+		ret = spi_register_driver(&wm8753_spi_driver);
+		if (ret != 0)
+			printk(KERN_ERR "can't add spi driver");
+	}
 #endif
 
 	if (ret != 0) {
@@ -1796,8 +1857,12 @@
 	snd_soc_free_pcms(socdev);
 	snd_soc_dapm_free(socdev);
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+	i2c_unregister_device(codec->control_data);
 	i2c_del_driver(&wm8753_i2c_driver);
 #endif
+#if defined(CONFIG_SPI_MASTER)
+	spi_unregister_driver(&wm8753_spi_driver);
+#endif
 	kfree(codec->private_data);
 	kfree(codec);
 
diff --git a/sound/soc/codecs/wm8753.h b/sound/soc/codecs/wm8753.h
index 44f5f1f..f55704c 100644
--- a/sound/soc/codecs/wm8753.h
+++ b/sound/soc/codecs/wm8753.h
@@ -2,8 +2,7 @@
  * wm8753.h  --  audio driver for WM8753
  *
  * Copyright 2003 Wolfson Microelectronics PLC.
- * Author: Liam Girdwood
- *         liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com
+ * Author: Liam Girdwood <lrg@slimlogic.co.uk>
  *
  *  This program is free software; you can redistribute  it and/or modify it
  *  under  the terms of  the GNU General  Public License as published by the
@@ -79,6 +78,8 @@
 #define WM8753_ADCTL2		0x3f
 
 struct wm8753_setup_data {
+	int spi;
+	int i2c_bus;
 	unsigned short i2c_address;
 };
 
diff --git a/sound/soc/codecs/wm8900.c b/sound/soc/codecs/wm8900.c
new file mode 100644
index 0000000..3b326c9
--- /dev/null
+++ b/sound/soc/codecs/wm8900.c
@@ -0,0 +1,1541 @@
+/*
+ * wm8900.c  --  WM8900 ALSA Soc Audio driver
+ *
+ * Copyright 2007, 2008 Wolfson Microelectronics PLC.
+ *
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.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.
+ *
+ * TODO:
+ *  - Tristating.
+ *  - TDM.
+ *  - Jack detect.
+ *  - FLL source configuration, currently only MCLK is supported.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+
+#include "wm8900.h"
+
+/* WM8900 register space */
+#define WM8900_REG_RESET	0x0
+#define WM8900_REG_ID		0x0
+#define WM8900_REG_POWER1	0x1
+#define WM8900_REG_POWER2	0x2
+#define WM8900_REG_POWER3	0x3
+#define WM8900_REG_AUDIO1	0x4
+#define WM8900_REG_AUDIO2	0x5
+#define WM8900_REG_CLOCKING1    0x6
+#define WM8900_REG_CLOCKING2    0x7
+#define WM8900_REG_AUDIO3       0x8
+#define WM8900_REG_AUDIO4       0x9
+#define WM8900_REG_DACCTRL      0xa
+#define WM8900_REG_LDAC_DV      0xb
+#define WM8900_REG_RDAC_DV      0xc
+#define WM8900_REG_SIDETONE     0xd
+#define WM8900_REG_ADCCTRL      0xe
+#define WM8900_REG_LADC_DV	0xf
+#define WM8900_REG_RADC_DV      0x10
+#define WM8900_REG_GPIO         0x12
+#define WM8900_REG_INCTL	0x15
+#define WM8900_REG_LINVOL	0x16
+#define WM8900_REG_RINVOL	0x17
+#define WM8900_REG_INBOOSTMIX1  0x18
+#define WM8900_REG_INBOOSTMIX2  0x19
+#define WM8900_REG_ADCPATH	0x1a
+#define WM8900_REG_AUXBOOST	0x1b
+#define WM8900_REG_ADDCTL       0x1e
+#define WM8900_REG_FLLCTL1      0x24
+#define WM8900_REG_FLLCTL2      0x25
+#define WM8900_REG_FLLCTL3      0x26
+#define WM8900_REG_FLLCTL4      0x27
+#define WM8900_REG_FLLCTL5      0x28
+#define WM8900_REG_FLLCTL6      0x29
+#define WM8900_REG_LOUTMIXCTL1  0x2c
+#define WM8900_REG_ROUTMIXCTL1  0x2d
+#define WM8900_REG_BYPASS1	0x2e
+#define WM8900_REG_BYPASS2	0x2f
+#define WM8900_REG_AUXOUT_CTL   0x30
+#define WM8900_REG_LOUT1CTL     0x33
+#define WM8900_REG_ROUT1CTL     0x34
+#define WM8900_REG_LOUT2CTL	0x35
+#define WM8900_REG_ROUT2CTL	0x36
+#define WM8900_REG_HPCTL1	0x3a
+#define WM8900_REG_OUTBIASCTL   0x73
+
+#define WM8900_MAXREG		0x80
+
+#define WM8900_REG_ADDCTL_OUT1_DIS    0x80
+#define WM8900_REG_ADDCTL_OUT2_DIS    0x40
+#define WM8900_REG_ADDCTL_VMID_DIS    0x20
+#define WM8900_REG_ADDCTL_BIAS_SRC    0x10
+#define WM8900_REG_ADDCTL_VMID_SOFTST 0x04
+#define WM8900_REG_ADDCTL_TEMP_SD     0x02
+
+#define WM8900_REG_GPIO_TEMP_ENA   0x2
+
+#define WM8900_REG_POWER1_STARTUP_BIAS_ENA 0x0100
+#define WM8900_REG_POWER1_BIAS_ENA         0x0008
+#define WM8900_REG_POWER1_VMID_BUF_ENA     0x0004
+#define WM8900_REG_POWER1_FLL_ENA          0x0040
+
+#define WM8900_REG_POWER2_SYSCLK_ENA  0x8000
+#define WM8900_REG_POWER2_ADCL_ENA    0x0002
+#define WM8900_REG_POWER2_ADCR_ENA    0x0001
+
+#define WM8900_REG_POWER3_DACL_ENA    0x0002
+#define WM8900_REG_POWER3_DACR_ENA    0x0001
+
+#define WM8900_REG_AUDIO1_AIF_FMT_MASK 0x0018
+#define WM8900_REG_AUDIO1_LRCLK_INV    0x0080
+#define WM8900_REG_AUDIO1_BCLK_INV     0x0100
+
+#define WM8900_REG_CLOCKING1_BCLK_DIR   0x1
+#define WM8900_REG_CLOCKING1_MCLK_SRC   0x100
+#define WM8900_REG_CLOCKING1_BCLK_MASK  (~0x01e)
+#define WM8900_REG_CLOCKING1_OPCLK_MASK (~0x7000)
+
+#define WM8900_REG_CLOCKING2_ADC_CLKDIV 0xe0
+#define WM8900_REG_CLOCKING2_DAC_CLKDIV 0x1c
+
+#define WM8900_REG_DACCTRL_MUTE          0x004
+#define WM8900_REG_DACCTRL_AIF_LRCLKRATE 0x400
+
+#define WM8900_REG_AUDIO3_ADCLRC_DIR    0x0800
+
+#define WM8900_REG_AUDIO4_DACLRC_DIR    0x0800
+
+#define WM8900_REG_FLLCTL1_OSC_ENA    0x100
+
+#define WM8900_REG_FLLCTL6_FLL_SLOW_LOCK_REF 0x100
+
+#define WM8900_REG_HPCTL1_HP_IPSTAGE_ENA 0x80
+#define WM8900_REG_HPCTL1_HP_OPSTAGE_ENA 0x40
+#define WM8900_REG_HPCTL1_HP_CLAMP_IP    0x20
+#define WM8900_REG_HPCTL1_HP_CLAMP_OP    0x10
+#define WM8900_REG_HPCTL1_HP_SHORT       0x08
+#define WM8900_REG_HPCTL1_HP_SHORT2      0x04
+
+#define WM8900_LRC_MASK 0xfc00
+
+struct snd_soc_codec_device soc_codec_dev_wm8900;
+
+struct wm8900_priv {
+	u32 fll_in; /* FLL input frequency */
+	u32 fll_out; /* FLL output frequency */
+};
+
+/*
+ * wm8900 register cache.  We can't read the entire register space and we
+ * have slow control buses so we cache the registers.
+ */
+static const u16 wm8900_reg_defaults[WM8900_MAXREG] = {
+	0x8900, 0x0000,
+	0xc000, 0x0000,
+	0x4050, 0x4000,
+	0x0008, 0x0000,
+	0x0040, 0x0040,
+	0x1004, 0x00c0,
+	0x00c0, 0x0000,
+	0x0100, 0x00c0,
+	0x00c0, 0x0000,
+	0xb001, 0x0000,
+	0x0000, 0x0044,
+	0x004c, 0x004c,
+	0x0044, 0x0044,
+	0x0000, 0x0044,
+	0x0000, 0x0000,
+	0x0002, 0x0000,
+	0x0000, 0x0000,
+	0x0000, 0x0000,
+	0x0008, 0x0000,
+	0x0000, 0x0008,
+	0x0097, 0x0100,
+	0x0000, 0x0000,
+	0x0050, 0x0050,
+	0x0055, 0x0055,
+	0x0055, 0x0000,
+	0x0000, 0x0079,
+	0x0079, 0x0079,
+	0x0079, 0x0000,
+	/* Remaining registers all zero */
+};
+
+/*
+ * read wm8900 register cache
+ */
+static inline unsigned int wm8900_read_reg_cache(struct snd_soc_codec *codec,
+	unsigned int reg)
+{
+	u16 *cache = codec->reg_cache;
+
+	BUG_ON(reg >= WM8900_MAXREG);
+
+	if (reg == WM8900_REG_ID)
+		return 0;
+
+	return cache[reg];
+}
+
+/*
+ * write wm8900 register cache
+ */
+static inline void wm8900_write_reg_cache(struct snd_soc_codec *codec,
+	u16 reg, unsigned int value)
+{
+	u16 *cache = codec->reg_cache;
+
+	BUG_ON(reg >= WM8900_MAXREG);
+
+	cache[reg] = value;
+}
+
+/*
+ * write to the WM8900 register space
+ */
+static int wm8900_write(struct snd_soc_codec *codec, unsigned int reg,
+			unsigned int value)
+{
+	u8 data[3];
+
+	if (value == wm8900_read_reg_cache(codec, reg))
+		return 0;
+
+	/* data is
+	 *   D15..D9 WM8900 register offset
+	 *   D8...D0 register data
+	 */
+	data[0] = reg;
+	data[1] = value >> 8;
+	data[2] = value & 0x00ff;
+
+	wm8900_write_reg_cache(codec, reg, value);
+	if (codec->hw_write(codec->control_data, data, 3) == 3)
+		return 0;
+	else
+		return -EIO;
+}
+
+/*
+ * Read from the wm8900.
+ */
+static unsigned int wm8900_chip_read(struct snd_soc_codec *codec, u8 reg)
+{
+	struct i2c_msg xfer[2];
+	u16 data;
+	int ret;
+	struct i2c_client *client = codec->control_data;
+
+	BUG_ON(reg != WM8900_REG_ID && reg != WM8900_REG_POWER1);
+
+	/* Write register */
+	xfer[0].addr = client->addr;
+	xfer[0].flags = 0;
+	xfer[0].len = 1;
+	xfer[0].buf = &reg;
+
+	/* Read data */
+	xfer[1].addr = client->addr;
+	xfer[1].flags = I2C_M_RD;
+	xfer[1].len = 2;
+	xfer[1].buf = (u8 *)&data;
+
+	ret = i2c_transfer(client->adapter, xfer, 2);
+	if (ret != 2) {
+		printk(KERN_CRIT "i2c_transfer returned %d\n", ret);
+		return 0;
+	}
+
+	return (data >> 8) | ((data & 0xff) << 8);
+}
+
+/*
+ * Read from the WM8900 register space.  Most registers can't be read
+ * and are therefore supplied from cache.
+ */
+static unsigned int wm8900_read(struct snd_soc_codec *codec, unsigned int reg)
+{
+	switch (reg) {
+	case WM8900_REG_ID:
+		return wm8900_chip_read(codec, reg);
+	default:
+		return wm8900_read_reg_cache(codec, reg);
+	}
+}
+
+static void wm8900_reset(struct snd_soc_codec *codec)
+{
+	wm8900_write(codec, WM8900_REG_RESET, 0);
+
+	memcpy(codec->reg_cache, wm8900_reg_defaults,
+	       sizeof(codec->reg_cache));
+}
+
+static int wm8900_hp_event(struct snd_soc_dapm_widget *w,
+			   struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = w->codec;
+	u16 hpctl1 = wm8900_read(codec, WM8900_REG_HPCTL1);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		/* Clamp headphone outputs */
+		hpctl1 = WM8900_REG_HPCTL1_HP_CLAMP_IP |
+			WM8900_REG_HPCTL1_HP_CLAMP_OP;
+		wm8900_write(codec, WM8900_REG_HPCTL1, hpctl1);
+		break;
+
+	case SND_SOC_DAPM_POST_PMU:
+		/* Enable the input stage */
+		hpctl1 &= ~WM8900_REG_HPCTL1_HP_CLAMP_IP;
+		hpctl1 |= WM8900_REG_HPCTL1_HP_SHORT |
+			WM8900_REG_HPCTL1_HP_SHORT2 |
+			WM8900_REG_HPCTL1_HP_IPSTAGE_ENA;
+		wm8900_write(codec, WM8900_REG_HPCTL1, hpctl1);
+
+		msleep(400);
+
+		/* Enable the output stage */
+		hpctl1 &= ~WM8900_REG_HPCTL1_HP_CLAMP_OP;
+		hpctl1 |= WM8900_REG_HPCTL1_HP_OPSTAGE_ENA;
+		wm8900_write(codec, WM8900_REG_HPCTL1, hpctl1);
+
+		/* Remove the shorts */
+		hpctl1 &= ~WM8900_REG_HPCTL1_HP_SHORT2;
+		wm8900_write(codec, WM8900_REG_HPCTL1, hpctl1);
+		hpctl1 &= ~WM8900_REG_HPCTL1_HP_SHORT;
+		wm8900_write(codec, WM8900_REG_HPCTL1, hpctl1);
+		break;
+
+	case SND_SOC_DAPM_PRE_PMD:
+		/* Short the output */
+		hpctl1 |= WM8900_REG_HPCTL1_HP_SHORT;
+		wm8900_write(codec, WM8900_REG_HPCTL1, hpctl1);
+
+		/* Disable the output stage */
+		hpctl1 &= ~WM8900_REG_HPCTL1_HP_OPSTAGE_ENA;
+		wm8900_write(codec, WM8900_REG_HPCTL1, hpctl1);
+
+		/* Clamp the outputs and power down input */
+		hpctl1 |= WM8900_REG_HPCTL1_HP_CLAMP_IP |
+			WM8900_REG_HPCTL1_HP_CLAMP_OP;
+		hpctl1 &= ~WM8900_REG_HPCTL1_HP_IPSTAGE_ENA;
+		wm8900_write(codec, WM8900_REG_HPCTL1, hpctl1);
+		break;
+
+	case SND_SOC_DAPM_POST_PMD:
+		/* Disable everything */
+		wm8900_write(codec, WM8900_REG_HPCTL1, 0);
+		break;
+
+	default:
+		BUG();
+	}
+
+	return 0;
+}
+
+static const DECLARE_TLV_DB_SCALE(out_pga_tlv, -5700, 100, 0);
+
+static const DECLARE_TLV_DB_SCALE(out_mix_tlv, -1500, 300, 0);
+
+static const DECLARE_TLV_DB_SCALE(in_boost_tlv, -1200, 600, 0);
+
+static const DECLARE_TLV_DB_SCALE(in_pga_tlv, -1200, 100, 0);
+
+static const DECLARE_TLV_DB_SCALE(dac_boost_tlv, 0, 600, 0);
+
+static const DECLARE_TLV_DB_SCALE(dac_tlv, -7200, 75, 1);
+
+static const DECLARE_TLV_DB_SCALE(adc_svol_tlv, -3600, 300, 0);
+
+static const DECLARE_TLV_DB_SCALE(adc_tlv, -7200, 75, 1);
+
+static const char *mic_bias_level_txt[] = { "0.9*AVDD", "0.65*AVDD" };
+
+static const struct soc_enum mic_bias_level =
+SOC_ENUM_SINGLE(WM8900_REG_INCTL, 8, 2, mic_bias_level_txt);
+
+static const char *dac_mute_rate_txt[] = { "Fast", "Slow" };
+
+static const struct soc_enum dac_mute_rate =
+SOC_ENUM_SINGLE(WM8900_REG_DACCTRL, 7, 2, dac_mute_rate_txt);
+
+static const char *dac_deemphasis_txt[] = {
+	"Disabled", "32kHz", "44.1kHz", "48kHz"
+};
+
+static const struct soc_enum dac_deemphasis =
+SOC_ENUM_SINGLE(WM8900_REG_DACCTRL, 4, 4, dac_deemphasis_txt);
+
+static const char *adc_hpf_cut_txt[] = {
+	"Hi-fi mode", "Voice mode 1", "Voice mode 2", "Voice mode 3"
+};
+
+static const struct soc_enum adc_hpf_cut =
+SOC_ENUM_SINGLE(WM8900_REG_ADCCTRL, 5, 4, adc_hpf_cut_txt);
+
+static const char *lr_txt[] = {
+	"Left", "Right"
+};
+
+static const struct soc_enum aifl_src =
+SOC_ENUM_SINGLE(WM8900_REG_AUDIO1, 15, 2, lr_txt);
+
+static const struct soc_enum aifr_src =
+SOC_ENUM_SINGLE(WM8900_REG_AUDIO1, 14, 2, lr_txt);
+
+static const struct soc_enum dacl_src =
+SOC_ENUM_SINGLE(WM8900_REG_AUDIO2, 15, 2, lr_txt);
+
+static const struct soc_enum dacr_src =
+SOC_ENUM_SINGLE(WM8900_REG_AUDIO2, 14, 2, lr_txt);
+
+static const char *sidetone_txt[] = {
+	"Disabled", "Left ADC", "Right ADC"
+};
+
+static const struct soc_enum dacl_sidetone =
+SOC_ENUM_SINGLE(WM8900_REG_SIDETONE, 2, 3, sidetone_txt);
+
+static const struct soc_enum dacr_sidetone =
+SOC_ENUM_SINGLE(WM8900_REG_SIDETONE, 0, 3, sidetone_txt);
+
+static const struct snd_kcontrol_new wm8900_snd_controls[] = {
+SOC_ENUM("Mic Bias Level", mic_bias_level),
+
+SOC_SINGLE_TLV("Left Input PGA Volume", WM8900_REG_LINVOL, 0, 31, 0,
+	       in_pga_tlv),
+SOC_SINGLE("Left Input PGA Switch", WM8900_REG_LINVOL, 6, 1, 1),
+SOC_SINGLE("Left Input PGA ZC Switch", WM8900_REG_LINVOL, 7, 1, 0),
+
+SOC_SINGLE_TLV("Right Input PGA Volume", WM8900_REG_RINVOL, 0, 31, 0,
+	       in_pga_tlv),
+SOC_SINGLE("Right Input PGA Switch", WM8900_REG_RINVOL, 6, 1, 1),
+SOC_SINGLE("Right Input PGA ZC Switch", WM8900_REG_RINVOL, 7, 1, 0),
+
+SOC_SINGLE("DAC Soft Mute Switch", WM8900_REG_DACCTRL, 6, 1, 1),
+SOC_ENUM("DAC Mute Rate", dac_mute_rate),
+SOC_SINGLE("DAC Mono Switch", WM8900_REG_DACCTRL, 9, 1, 0),
+SOC_ENUM("DAC Deemphasis", dac_deemphasis),
+SOC_SINGLE("DAC Sloping Stopband Filter Switch", WM8900_REG_DACCTRL, 8, 1, 0),
+SOC_SINGLE("DAC Sigma-Delta Modulator Clock Switch", WM8900_REG_DACCTRL,
+	   12, 1, 0),
+
+SOC_SINGLE("ADC HPF Switch", WM8900_REG_ADCCTRL, 8, 1, 0),
+SOC_ENUM("ADC HPF Cut-Off", adc_hpf_cut),
+SOC_DOUBLE("ADC Invert Switch", WM8900_REG_ADCCTRL, 1, 0, 1, 0),
+SOC_SINGLE_TLV("Left ADC Sidetone Volume", WM8900_REG_SIDETONE, 9, 12, 0,
+	       adc_svol_tlv),
+SOC_SINGLE_TLV("Right ADC Sidetone Volume", WM8900_REG_SIDETONE, 5, 12, 0,
+	       adc_svol_tlv),
+SOC_ENUM("Left Digital Audio Source", aifl_src),
+SOC_ENUM("Right Digital Audio Source", aifr_src),
+
+SOC_SINGLE_TLV("DAC Input Boost Volume", WM8900_REG_AUDIO2, 10, 4, 0,
+	       dac_boost_tlv),
+SOC_ENUM("Left DAC Source", dacl_src),
+SOC_ENUM("Right DAC Source", dacr_src),
+SOC_ENUM("Left DAC Sidetone", dacl_sidetone),
+SOC_ENUM("Right DAC Sidetone", dacr_sidetone),
+SOC_DOUBLE("DAC Invert Switch", WM8900_REG_DACCTRL, 1, 0, 1, 0),
+
+SOC_DOUBLE_R_TLV("Digital Playback Volume",
+		 WM8900_REG_LDAC_DV, WM8900_REG_RDAC_DV,
+		 1, 96, 0, dac_tlv),
+SOC_DOUBLE_R_TLV("Digital Capture Volume",
+		 WM8900_REG_LADC_DV, WM8900_REG_RADC_DV, 1, 119, 0, adc_tlv),
+
+SOC_SINGLE_TLV("LINPUT3 Bypass Volume", WM8900_REG_LOUTMIXCTL1, 4, 7, 0,
+	       out_mix_tlv),
+SOC_SINGLE_TLV("RINPUT3 Bypass Volume", WM8900_REG_ROUTMIXCTL1, 4, 7, 0,
+	       out_mix_tlv),
+SOC_SINGLE_TLV("Left AUX Bypass Volume", WM8900_REG_AUXOUT_CTL, 4, 7, 0,
+	       out_mix_tlv),
+SOC_SINGLE_TLV("Right AUX Bypass Volume", WM8900_REG_AUXOUT_CTL, 0, 7, 0,
+	       out_mix_tlv),
+
+SOC_SINGLE_TLV("LeftIn to RightOut Mixer Volume", WM8900_REG_BYPASS1, 0, 7, 0,
+	       out_mix_tlv),
+SOC_SINGLE_TLV("LeftIn to LeftOut Mixer Volume", WM8900_REG_BYPASS1, 4, 7, 0,
+	       out_mix_tlv),
+SOC_SINGLE_TLV("RightIn to LeftOut Mixer Volume", WM8900_REG_BYPASS2, 0, 7, 0,
+	       out_mix_tlv),
+SOC_SINGLE_TLV("RightIn to RightOut Mixer Volume", WM8900_REG_BYPASS2, 4, 7, 0,
+	       out_mix_tlv),
+
+SOC_SINGLE_TLV("IN2L Boost Volume", WM8900_REG_INBOOSTMIX1, 0, 3, 0,
+	       in_boost_tlv),
+SOC_SINGLE_TLV("IN3L Boost Volume", WM8900_REG_INBOOSTMIX1, 4, 3, 0,
+	       in_boost_tlv),
+SOC_SINGLE_TLV("IN2R Boost Volume", WM8900_REG_INBOOSTMIX2, 0, 3, 0,
+	       in_boost_tlv),
+SOC_SINGLE_TLV("IN3R Boost Volume", WM8900_REG_INBOOSTMIX2, 4, 3, 0,
+	       in_boost_tlv),
+SOC_SINGLE_TLV("Left AUX Boost Volume", WM8900_REG_AUXBOOST, 4, 3, 0,
+	       in_boost_tlv),
+SOC_SINGLE_TLV("Right AUX Boost Volume", WM8900_REG_AUXBOOST, 0, 3, 0,
+	       in_boost_tlv),
+
+SOC_DOUBLE_R_TLV("LINEOUT1 Volume", WM8900_REG_LOUT1CTL, WM8900_REG_ROUT1CTL,
+	       0, 63, 0, out_pga_tlv),
+SOC_DOUBLE_R("LINEOUT1 Switch", WM8900_REG_LOUT1CTL, WM8900_REG_ROUT1CTL,
+	     6, 1, 1),
+SOC_DOUBLE_R("LINEOUT1 ZC Switch", WM8900_REG_LOUT1CTL, WM8900_REG_ROUT1CTL,
+	     7, 1, 0),
+
+SOC_DOUBLE_R_TLV("LINEOUT2 Volume",
+		 WM8900_REG_LOUT2CTL, WM8900_REG_ROUT2CTL,
+		 0, 63, 0, out_pga_tlv),
+SOC_DOUBLE_R("LINEOUT2 Switch",
+	     WM8900_REG_LOUT2CTL, WM8900_REG_ROUT2CTL, 6, 1, 1),
+SOC_DOUBLE_R("LINEOUT2 ZC Switch",
+	     WM8900_REG_LOUT2CTL, WM8900_REG_ROUT2CTL, 7, 1, 0),
+SOC_SINGLE("LINEOUT2 LP -12dB", WM8900_REG_LOUTMIXCTL1,
+	   0, 1, 1),
+
+};
+
+/* add non dapm controls */
+static int wm8900_add_controls(struct snd_soc_codec *codec)
+{
+	int err, i;
+
+	for (i = 0; i < ARRAY_SIZE(wm8900_snd_controls); i++) {
+		err = snd_ctl_add(codec->card,
+				  snd_soc_cnew(&wm8900_snd_controls[i],
+					       codec, NULL));
+		if (err < 0)
+			return err;
+	}
+
+	return 0;
+}
+
+static const struct snd_kcontrol_new wm8900_dapm_loutput2_control =
+SOC_DAPM_SINGLE("LINEOUT2L Switch", WM8900_REG_POWER3, 6, 1, 0);
+
+static const struct snd_kcontrol_new wm8900_dapm_routput2_control =
+SOC_DAPM_SINGLE("LINEOUT2R Switch", WM8900_REG_POWER3, 5, 1, 0);
+
+static const struct snd_kcontrol_new wm8900_loutmix_controls[] = {
+SOC_DAPM_SINGLE("LINPUT3 Bypass Switch", WM8900_REG_LOUTMIXCTL1, 7, 1, 0),
+SOC_DAPM_SINGLE("AUX Bypass Switch", WM8900_REG_AUXOUT_CTL, 7, 1, 0),
+SOC_DAPM_SINGLE("Left Input Mixer Switch", WM8900_REG_BYPASS1, 7, 1, 0),
+SOC_DAPM_SINGLE("Right Input Mixer Switch", WM8900_REG_BYPASS2, 3, 1, 0),
+SOC_DAPM_SINGLE("DACL Switch", WM8900_REG_LOUTMIXCTL1, 8, 1, 0),
+};
+
+static const struct snd_kcontrol_new wm8900_routmix_controls[] = {
+SOC_DAPM_SINGLE("RINPUT3 Bypass Switch", WM8900_REG_ROUTMIXCTL1, 7, 1, 0),
+SOC_DAPM_SINGLE("AUX Bypass Switch", WM8900_REG_AUXOUT_CTL, 3, 1, 0),
+SOC_DAPM_SINGLE("Left Input Mixer Switch", WM8900_REG_BYPASS1, 3, 1, 0),
+SOC_DAPM_SINGLE("Right Input Mixer Switch", WM8900_REG_BYPASS2, 7, 1, 0),
+SOC_DAPM_SINGLE("DACR Switch", WM8900_REG_ROUTMIXCTL1, 8, 1, 0),
+};
+
+static const struct snd_kcontrol_new wm8900_linmix_controls[] = {
+SOC_DAPM_SINGLE("LINPUT2 Switch", WM8900_REG_INBOOSTMIX1, 2, 1, 1),
+SOC_DAPM_SINGLE("LINPUT3 Switch", WM8900_REG_INBOOSTMIX1, 6, 1, 1),
+SOC_DAPM_SINGLE("AUX Switch", WM8900_REG_AUXBOOST, 6, 1, 1),
+SOC_DAPM_SINGLE("Input PGA Switch", WM8900_REG_ADCPATH, 6, 1, 0),
+};
+
+static const struct snd_kcontrol_new wm8900_rinmix_controls[] = {
+SOC_DAPM_SINGLE("RINPUT2 Switch", WM8900_REG_INBOOSTMIX2, 2, 1, 1),
+SOC_DAPM_SINGLE("RINPUT3 Switch", WM8900_REG_INBOOSTMIX2, 6, 1, 1),
+SOC_DAPM_SINGLE("AUX Switch", WM8900_REG_AUXBOOST, 2, 1, 1),
+SOC_DAPM_SINGLE("Input PGA Switch", WM8900_REG_ADCPATH, 2, 1, 0),
+};
+
+static const struct snd_kcontrol_new wm8900_linpga_controls[] = {
+SOC_DAPM_SINGLE("LINPUT1 Switch", WM8900_REG_INCTL, 6, 1, 0),
+SOC_DAPM_SINGLE("LINPUT2 Switch", WM8900_REG_INCTL, 5, 1, 0),
+SOC_DAPM_SINGLE("LINPUT3 Switch", WM8900_REG_INCTL, 4, 1, 0),
+};
+
+static const struct snd_kcontrol_new wm8900_rinpga_controls[] = {
+SOC_DAPM_SINGLE("RINPUT1 Switch", WM8900_REG_INCTL, 2, 1, 0),
+SOC_DAPM_SINGLE("RINPUT2 Switch", WM8900_REG_INCTL, 1, 1, 0),
+SOC_DAPM_SINGLE("RINPUT3 Switch", WM8900_REG_INCTL, 0, 1, 0),
+};
+
+static const char *wm9700_lp_mux[] = { "Disabled", "Enabled" };
+
+static const struct soc_enum wm8900_lineout2_lp_mux =
+SOC_ENUM_SINGLE(WM8900_REG_LOUTMIXCTL1, 1, 2, wm9700_lp_mux);
+
+static const struct snd_kcontrol_new wm8900_lineout2_lp =
+SOC_DAPM_ENUM("Route", wm8900_lineout2_lp_mux);
+
+static const struct snd_soc_dapm_widget wm8900_dapm_widgets[] = {
+
+/* Externally visible pins */
+SND_SOC_DAPM_OUTPUT("LINEOUT1L"),
+SND_SOC_DAPM_OUTPUT("LINEOUT1R"),
+SND_SOC_DAPM_OUTPUT("LINEOUT2L"),
+SND_SOC_DAPM_OUTPUT("LINEOUT2R"),
+SND_SOC_DAPM_OUTPUT("HP_L"),
+SND_SOC_DAPM_OUTPUT("HP_R"),
+
+SND_SOC_DAPM_INPUT("RINPUT1"),
+SND_SOC_DAPM_INPUT("LINPUT1"),
+SND_SOC_DAPM_INPUT("RINPUT2"),
+SND_SOC_DAPM_INPUT("LINPUT2"),
+SND_SOC_DAPM_INPUT("RINPUT3"),
+SND_SOC_DAPM_INPUT("LINPUT3"),
+SND_SOC_DAPM_INPUT("AUX"),
+
+SND_SOC_DAPM_VMID("VMID"),
+
+/* Input */
+SND_SOC_DAPM_MIXER("Left Input PGA", WM8900_REG_POWER2, 3, 0,
+		   wm8900_linpga_controls,
+		   ARRAY_SIZE(wm8900_linpga_controls)),
+SND_SOC_DAPM_MIXER("Right Input PGA", WM8900_REG_POWER2, 2, 0,
+		   wm8900_rinpga_controls,
+		   ARRAY_SIZE(wm8900_rinpga_controls)),
+
+SND_SOC_DAPM_MIXER("Left Input Mixer", WM8900_REG_POWER2, 5, 0,
+		   wm8900_linmix_controls,
+		   ARRAY_SIZE(wm8900_linmix_controls)),
+SND_SOC_DAPM_MIXER("Right Input Mixer", WM8900_REG_POWER2, 4, 0,
+		   wm8900_rinmix_controls,
+		   ARRAY_SIZE(wm8900_rinmix_controls)),
+
+SND_SOC_DAPM_MICBIAS("Mic Bias", WM8900_REG_POWER1, 4, 0),
+
+SND_SOC_DAPM_ADC("ADCL", "Left HiFi Capture", WM8900_REG_POWER2, 1, 0),
+SND_SOC_DAPM_ADC("ADCR", "Right HiFi Capture", WM8900_REG_POWER2, 0, 0),
+
+/* Output */
+SND_SOC_DAPM_DAC("DACL", "Left HiFi Playback", WM8900_REG_POWER3, 1, 0),
+SND_SOC_DAPM_DAC("DACR", "Right HiFi Playback", WM8900_REG_POWER3, 0, 0),
+
+SND_SOC_DAPM_PGA_E("Headphone Amplifier", WM8900_REG_POWER3, 7, 0, NULL, 0,
+		   wm8900_hp_event,
+		   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+
+SND_SOC_DAPM_PGA("LINEOUT1L PGA", WM8900_REG_POWER2, 8, 0, NULL, 0),
+SND_SOC_DAPM_PGA("LINEOUT1R PGA", WM8900_REG_POWER2, 7, 0, NULL, 0),
+
+SND_SOC_DAPM_MUX("LINEOUT2 LP", SND_SOC_NOPM, 0, 0, &wm8900_lineout2_lp),
+SND_SOC_DAPM_PGA("LINEOUT2L PGA", WM8900_REG_POWER3, 6, 0, NULL, 0),
+SND_SOC_DAPM_PGA("LINEOUT2R PGA", WM8900_REG_POWER3, 5, 0, NULL, 0),
+
+SND_SOC_DAPM_MIXER("Left Output Mixer", WM8900_REG_POWER3, 3, 0,
+		   wm8900_loutmix_controls,
+		   ARRAY_SIZE(wm8900_loutmix_controls)),
+SND_SOC_DAPM_MIXER("Right Output Mixer", WM8900_REG_POWER3, 2, 0,
+		   wm8900_routmix_controls,
+		   ARRAY_SIZE(wm8900_routmix_controls)),
+};
+
+/* Target, Path, Source */
+static const struct snd_soc_dapm_route audio_map[] = {
+/* Inputs */
+{"Left Input PGA", "LINPUT1 Switch", "LINPUT1"},
+{"Left Input PGA", "LINPUT2 Switch", "LINPUT2"},
+{"Left Input PGA", "LINPUT3 Switch", "LINPUT3"},
+
+{"Right Input PGA", "RINPUT1 Switch", "RINPUT1"},
+{"Right Input PGA", "RINPUT2 Switch", "RINPUT2"},
+{"Right Input PGA", "RINPUT3 Switch", "RINPUT3"},
+
+{"Left Input Mixer", "LINPUT2 Switch", "LINPUT2"},
+{"Left Input Mixer", "LINPUT3 Switch", "LINPUT3"},
+{"Left Input Mixer", "AUX Switch", "AUX"},
+{"Left Input Mixer", "Input PGA Switch", "Left Input PGA"},
+
+{"Right Input Mixer", "RINPUT2 Switch", "RINPUT2"},
+{"Right Input Mixer", "RINPUT3 Switch", "RINPUT3"},
+{"Right Input Mixer", "AUX Switch", "AUX"},
+{"Right Input Mixer", "Input PGA Switch", "Right Input PGA"},
+
+{"ADCL", NULL, "Left Input Mixer"},
+{"ADCR", NULL, "Right Input Mixer"},
+
+/* Outputs */
+{"LINEOUT1L", NULL, "LINEOUT1L PGA"},
+{"LINEOUT1L PGA", NULL, "Left Output Mixer"},
+{"LINEOUT1R", NULL, "LINEOUT1R PGA"},
+{"LINEOUT1R PGA", NULL, "Right Output Mixer"},
+
+{"LINEOUT2L PGA", NULL, "Left Output Mixer"},
+{"LINEOUT2 LP", "Disabled", "LINEOUT2L PGA"},
+{"LINEOUT2 LP", "Enabled", "Left Output Mixer"},
+{"LINEOUT2L", NULL, "LINEOUT2 LP"},
+
+{"LINEOUT2R PGA", NULL, "Right Output Mixer"},
+{"LINEOUT2 LP", "Disabled", "LINEOUT2R PGA"},
+{"LINEOUT2 LP", "Enabled", "Right Output Mixer"},
+{"LINEOUT2R", NULL, "LINEOUT2 LP"},
+
+{"Left Output Mixer", "LINPUT3 Bypass Switch", "LINPUT3"},
+{"Left Output Mixer", "AUX Bypass Switch", "AUX"},
+{"Left Output Mixer", "Left Input Mixer Switch", "Left Input Mixer"},
+{"Left Output Mixer", "Right Input Mixer Switch", "Right Input Mixer"},
+{"Left Output Mixer", "DACL Switch", "DACL"},
+
+{"Right Output Mixer", "RINPUT3 Bypass Switch", "RINPUT3"},
+{"Right Output Mixer", "AUX Bypass Switch", "AUX"},
+{"Right Output Mixer", "Left Input Mixer Switch", "Left Input Mixer"},
+{"Right Output Mixer", "Right Input Mixer Switch", "Right Input Mixer"},
+{"Right Output Mixer", "DACR Switch", "DACR"},
+
+/* Note that the headphone output stage needs to be connected
+ * externally to LINEOUT2 via DC blocking capacitors.  Other
+ * configurations are not supported.
+ *
+ * Note also that left and right headphone paths are treated as a
+ * mono path.
+ */
+{"Headphone Amplifier", NULL, "LINEOUT2 LP"},
+{"Headphone Amplifier", NULL, "LINEOUT2 LP"},
+{"HP_L", NULL, "Headphone Amplifier"},
+{"HP_R", NULL, "Headphone Amplifier"},
+};
+
+static int wm8900_add_widgets(struct snd_soc_codec *codec)
+{
+	snd_soc_dapm_new_controls(codec, wm8900_dapm_widgets,
+				  ARRAY_SIZE(wm8900_dapm_widgets));
+
+	snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+
+	snd_soc_dapm_new_widgets(codec);
+
+	return 0;
+}
+
+static int wm8900_hw_params(struct snd_pcm_substream *substream,
+	struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_device *socdev = rtd->socdev;
+	struct snd_soc_codec *codec = socdev->codec;
+	u16 reg;
+
+	reg = wm8900_read(codec, WM8900_REG_AUDIO1) & ~0x60;
+
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S16_LE:
+		break;
+	case SNDRV_PCM_FORMAT_S20_3LE:
+		reg |= 0x20;
+		break;
+	case SNDRV_PCM_FORMAT_S24_LE:
+		reg |= 0x40;
+		break;
+	case SNDRV_PCM_FORMAT_S32_LE:
+		reg |= 0x60;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	wm8900_write(codec, WM8900_REG_AUDIO1, reg);
+
+	return 0;
+}
+
+/* FLL divisors */
+struct _fll_div {
+	u16 fll_ratio;
+	u16 fllclk_div;
+	u16 fll_slow_lock_ref;
+	u16 n;
+	u16 k;
+};
+
+/* The size in bits of the FLL divide multiplied by 10
+ * to allow rounding later */
+#define FIXED_FLL_SIZE ((1 << 16) * 10)
+
+static int fll_factors(struct _fll_div *fll_div, unsigned int Fref,
+		       unsigned int Fout)
+{
+	u64 Kpart;
+	unsigned int K, Ndiv, Nmod, target;
+	unsigned int div;
+
+	BUG_ON(!Fout);
+
+	/* The FLL must run at 90-100MHz which is then scaled down to
+	 * the output value by FLLCLK_DIV. */
+	target = Fout;
+	div = 1;
+	while (target < 90000000) {
+		div *= 2;
+		target *= 2;
+	}
+
+	if (target > 100000000)
+		printk(KERN_WARNING "wm8900: FLL rate %d out of range, Fref=%d"
+		       " Fout=%d\n", target, Fref, Fout);
+	if (div > 32) {
+		printk(KERN_ERR "wm8900: Invalid FLL division rate %u, "
+		       "Fref=%d, Fout=%d, target=%d\n",
+		       div, Fref, Fout, target);
+		return -EINVAL;
+	}
+
+	fll_div->fllclk_div = div >> 2;
+
+	if (Fref < 48000)
+		fll_div->fll_slow_lock_ref = 1;
+	else
+		fll_div->fll_slow_lock_ref = 0;
+
+	Ndiv = target / Fref;
+
+	if (Fref < 1000000)
+		fll_div->fll_ratio = 8;
+	else
+		fll_div->fll_ratio = 1;
+
+	fll_div->n = Ndiv / fll_div->fll_ratio;
+	Nmod = (target / fll_div->fll_ratio) % Fref;
+
+	/* Calculate fractional part - scale up so we can round. */
+	Kpart = FIXED_FLL_SIZE * (long long)Nmod;
+
+	do_div(Kpart, Fref);
+
+	K = Kpart & 0xFFFFFFFF;
+
+	if ((K % 10) >= 5)
+		K += 5;
+
+	/* Move down to proper range now rounding is done */
+	fll_div->k = K / 10;
+
+	BUG_ON(target != Fout * (fll_div->fllclk_div << 2));
+	BUG_ON(!K && target != Fref * fll_div->fll_ratio * fll_div->n);
+
+	return 0;
+}
+
+static int wm8900_set_fll(struct snd_soc_codec *codec,
+	int fll_id, unsigned int freq_in, unsigned int freq_out)
+{
+	struct wm8900_priv *wm8900 = codec->private_data;
+	struct _fll_div fll_div;
+	unsigned int reg;
+
+	if (wm8900->fll_in == freq_in && wm8900->fll_out == freq_out)
+		return 0;
+
+	/* The digital side should be disabled during any change. */
+	reg = wm8900_read(codec, WM8900_REG_POWER1);
+	wm8900_write(codec, WM8900_REG_POWER1,
+		     reg & (~WM8900_REG_POWER1_FLL_ENA));
+
+	/* Disable the FLL? */
+	if (!freq_in || !freq_out) {
+		reg = wm8900_read(codec, WM8900_REG_CLOCKING1);
+		wm8900_write(codec, WM8900_REG_CLOCKING1,
+			     reg & (~WM8900_REG_CLOCKING1_MCLK_SRC));
+
+		reg = wm8900_read(codec, WM8900_REG_FLLCTL1);
+		wm8900_write(codec, WM8900_REG_FLLCTL1,
+			     reg & (~WM8900_REG_FLLCTL1_OSC_ENA));
+
+		wm8900->fll_in = freq_in;
+		wm8900->fll_out = freq_out;
+
+		return 0;
+	}
+
+	if (fll_factors(&fll_div, freq_in, freq_out) != 0)
+		goto reenable;
+
+	wm8900->fll_in = freq_in;
+	wm8900->fll_out = freq_out;
+
+	/* The osclilator *MUST* be enabled before we enable the
+	 * digital circuit. */
+	wm8900_write(codec, WM8900_REG_FLLCTL1,
+		     fll_div.fll_ratio | WM8900_REG_FLLCTL1_OSC_ENA);
+
+	wm8900_write(codec, WM8900_REG_FLLCTL4, fll_div.n >> 5);
+	wm8900_write(codec, WM8900_REG_FLLCTL5,
+		     (fll_div.fllclk_div << 6) | (fll_div.n & 0x1f));
+
+	if (fll_div.k) {
+		wm8900_write(codec, WM8900_REG_FLLCTL2,
+			     (fll_div.k >> 8) | 0x100);
+		wm8900_write(codec, WM8900_REG_FLLCTL3, fll_div.k & 0xff);
+	} else
+		wm8900_write(codec, WM8900_REG_FLLCTL2, 0);
+
+	if (fll_div.fll_slow_lock_ref)
+		wm8900_write(codec, WM8900_REG_FLLCTL6,
+			     WM8900_REG_FLLCTL6_FLL_SLOW_LOCK_REF);
+	else
+		wm8900_write(codec, WM8900_REG_FLLCTL6, 0);
+
+	reg = wm8900_read(codec, WM8900_REG_POWER1);
+	wm8900_write(codec, WM8900_REG_POWER1,
+		     reg | WM8900_REG_POWER1_FLL_ENA);
+
+reenable:
+	reg = wm8900_read(codec, WM8900_REG_CLOCKING1);
+	wm8900_write(codec, WM8900_REG_CLOCKING1,
+		     reg | WM8900_REG_CLOCKING1_MCLK_SRC);
+
+	return 0;
+}
+
+static int wm8900_set_dai_pll(struct snd_soc_dai *codec_dai,
+		int pll_id, unsigned int freq_in, unsigned int freq_out)
+{
+	return wm8900_set_fll(codec_dai->codec, pll_id, freq_in, freq_out);
+}
+
+static int wm8900_set_dai_clkdiv(struct snd_soc_dai *codec_dai,
+				 int div_id, int div)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+	unsigned int reg;
+
+	switch (div_id) {
+	case WM8900_BCLK_DIV:
+		reg = wm8900_read(codec, WM8900_REG_CLOCKING1);
+		wm8900_write(codec, WM8900_REG_CLOCKING1,
+			     div | (reg & WM8900_REG_CLOCKING1_BCLK_MASK));
+		break;
+	case WM8900_OPCLK_DIV:
+		reg = wm8900_read(codec, WM8900_REG_CLOCKING1);
+		wm8900_write(codec, WM8900_REG_CLOCKING1,
+			     div | (reg & WM8900_REG_CLOCKING1_OPCLK_MASK));
+		break;
+	case WM8900_DAC_LRCLK:
+		reg = wm8900_read(codec, WM8900_REG_AUDIO4);
+		wm8900_write(codec, WM8900_REG_AUDIO4,
+			     div | (reg & WM8900_LRC_MASK));
+		break;
+	case WM8900_ADC_LRCLK:
+		reg = wm8900_read(codec, WM8900_REG_AUDIO3);
+		wm8900_write(codec, WM8900_REG_AUDIO3,
+			     div | (reg & WM8900_LRC_MASK));
+		break;
+	case WM8900_DAC_CLKDIV:
+		reg = wm8900_read(codec, WM8900_REG_CLOCKING2);
+		wm8900_write(codec, WM8900_REG_CLOCKING2,
+			     div | (reg & WM8900_REG_CLOCKING2_DAC_CLKDIV));
+		break;
+	case WM8900_ADC_CLKDIV:
+		reg = wm8900_read(codec, WM8900_REG_CLOCKING2);
+		wm8900_write(codec, WM8900_REG_CLOCKING2,
+			     div | (reg & WM8900_REG_CLOCKING2_ADC_CLKDIV));
+		break;
+	case WM8900_LRCLK_MODE:
+		reg = wm8900_read(codec, WM8900_REG_DACCTRL);
+		wm8900_write(codec, WM8900_REG_DACCTRL,
+			     div | (reg & WM8900_REG_DACCTRL_AIF_LRCLKRATE));
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+
+static int wm8900_set_dai_fmt(struct snd_soc_dai *codec_dai,
+			      unsigned int fmt)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+	unsigned int clocking1, aif1, aif3, aif4;
+
+	clocking1 = wm8900_read(codec, WM8900_REG_CLOCKING1);
+	aif1 = wm8900_read(codec, WM8900_REG_AUDIO1);
+	aif3 = wm8900_read(codec, WM8900_REG_AUDIO3);
+	aif4 = wm8900_read(codec, WM8900_REG_AUDIO4);
+
+	/* set master/slave audio interface */
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBS_CFS:
+		clocking1 &= ~WM8900_REG_CLOCKING1_BCLK_DIR;
+		aif3 &= ~WM8900_REG_AUDIO3_ADCLRC_DIR;
+		aif4 &= ~WM8900_REG_AUDIO4_DACLRC_DIR;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFM:
+		clocking1 &= ~WM8900_REG_CLOCKING1_BCLK_DIR;
+		aif3 |= WM8900_REG_AUDIO3_ADCLRC_DIR;
+		aif4 |= WM8900_REG_AUDIO4_DACLRC_DIR;
+		break;
+	case SND_SOC_DAIFMT_CBM_CFM:
+		clocking1 |= WM8900_REG_CLOCKING1_BCLK_DIR;
+		aif3 |= WM8900_REG_AUDIO3_ADCLRC_DIR;
+		aif4 |= WM8900_REG_AUDIO4_DACLRC_DIR;
+		break;
+	case SND_SOC_DAIFMT_CBM_CFS:
+		clocking1 |= WM8900_REG_CLOCKING1_BCLK_DIR;
+		aif3 &= ~WM8900_REG_AUDIO3_ADCLRC_DIR;
+		aif4 &= ~WM8900_REG_AUDIO4_DACLRC_DIR;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_DSP_A:
+		aif1 |= WM8900_REG_AUDIO1_AIF_FMT_MASK;
+		aif1 &= ~WM8900_REG_AUDIO1_LRCLK_INV;
+		break;
+	case SND_SOC_DAIFMT_DSP_B:
+		aif1 |= WM8900_REG_AUDIO1_AIF_FMT_MASK;
+		aif1 |= WM8900_REG_AUDIO1_LRCLK_INV;
+		break;
+	case SND_SOC_DAIFMT_I2S:
+		aif1 &= ~WM8900_REG_AUDIO1_AIF_FMT_MASK;
+		aif1 |= 0x10;
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		aif1 &= ~WM8900_REG_AUDIO1_AIF_FMT_MASK;
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		aif1 &= ~WM8900_REG_AUDIO1_AIF_FMT_MASK;
+		aif1 |= 0x8;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* Clock inversion */
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_DSP_A:
+	case SND_SOC_DAIFMT_DSP_B:
+		/* frame inversion not valid for DSP modes */
+		switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+		case SND_SOC_DAIFMT_NB_NF:
+			aif1 &= ~WM8900_REG_AUDIO1_BCLK_INV;
+			break;
+		case SND_SOC_DAIFMT_IB_NF:
+			aif1 |= WM8900_REG_AUDIO1_BCLK_INV;
+			break;
+		default:
+			return -EINVAL;
+		}
+		break;
+	case SND_SOC_DAIFMT_I2S:
+	case SND_SOC_DAIFMT_RIGHT_J:
+	case SND_SOC_DAIFMT_LEFT_J:
+		switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+		case SND_SOC_DAIFMT_NB_NF:
+			aif1 &= ~WM8900_REG_AUDIO1_BCLK_INV;
+			aif1 &= ~WM8900_REG_AUDIO1_LRCLK_INV;
+			break;
+		case SND_SOC_DAIFMT_IB_IF:
+			aif1 |= WM8900_REG_AUDIO1_BCLK_INV;
+			aif1 |= WM8900_REG_AUDIO1_LRCLK_INV;
+			break;
+		case SND_SOC_DAIFMT_IB_NF:
+			aif1 |= WM8900_REG_AUDIO1_BCLK_INV;
+			aif1 &= ~WM8900_REG_AUDIO1_LRCLK_INV;
+			break;
+		case SND_SOC_DAIFMT_NB_IF:
+			aif1 &= ~WM8900_REG_AUDIO1_BCLK_INV;
+			aif1 |= WM8900_REG_AUDIO1_LRCLK_INV;
+			break;
+		default:
+			return -EINVAL;
+		}
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	wm8900_write(codec, WM8900_REG_CLOCKING1, clocking1);
+	wm8900_write(codec, WM8900_REG_AUDIO1, aif1);
+	wm8900_write(codec, WM8900_REG_AUDIO3, aif3);
+	wm8900_write(codec, WM8900_REG_AUDIO4, aif4);
+
+	return 0;
+}
+
+static int wm8900_digital_mute(struct snd_soc_dai *codec_dai, int mute)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+	u16 reg;
+
+	reg = wm8900_read(codec, WM8900_REG_DACCTRL);
+
+	if (mute)
+		reg |= WM8900_REG_DACCTRL_MUTE;
+	else
+		reg &= ~WM8900_REG_DACCTRL_MUTE;
+
+	wm8900_write(codec, WM8900_REG_DACCTRL, reg);
+
+	return 0;
+}
+
+#define WM8900_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
+		      SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |\
+		      SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000)
+
+#define WM8900_PCM_FORMATS \
+	(SNDRV_PCM_FORMAT_S16_LE | SNDRV_PCM_FORMAT_S20_3LE | \
+	 SNDRV_PCM_FORMAT_S24_LE)
+
+struct snd_soc_dai wm8900_dai = {
+	.name = "WM8900 HiFi",
+	.playback = {
+		.stream_name = "HiFi Playback",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = WM8900_RATES,
+		.formats = WM8900_PCM_FORMATS,
+	},
+	.capture = {
+		.stream_name = "HiFi Capture",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = WM8900_RATES,
+		.formats = WM8900_PCM_FORMATS,
+	 },
+	.ops = {
+		.hw_params = wm8900_hw_params,
+	 },
+	.dai_ops = {
+		 .set_clkdiv = wm8900_set_dai_clkdiv,
+		 .set_pll = wm8900_set_dai_pll,
+		 .set_fmt = wm8900_set_dai_fmt,
+		 .digital_mute = wm8900_digital_mute,
+	 },
+};
+EXPORT_SYMBOL_GPL(wm8900_dai);
+
+static int wm8900_set_bias_level(struct snd_soc_codec *codec,
+				 enum snd_soc_bias_level level)
+{
+	u16 reg;
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		/* Enable thermal shutdown */
+		reg = wm8900_read(codec, WM8900_REG_GPIO);
+		wm8900_write(codec, WM8900_REG_GPIO,
+			     reg | WM8900_REG_GPIO_TEMP_ENA);
+		reg = wm8900_read(codec, WM8900_REG_ADDCTL);
+		wm8900_write(codec, WM8900_REG_ADDCTL,
+			     reg | WM8900_REG_ADDCTL_TEMP_SD);
+		break;
+
+	case SND_SOC_BIAS_PREPARE:
+		break;
+
+	case SND_SOC_BIAS_STANDBY:
+		/* Charge capacitors if initial power up */
+		if (codec->bias_level == SND_SOC_BIAS_OFF) {
+			/* STARTUP_BIAS_ENA on */
+			wm8900_write(codec, WM8900_REG_POWER1,
+				     WM8900_REG_POWER1_STARTUP_BIAS_ENA);
+
+			/* Startup bias mode */
+			wm8900_write(codec, WM8900_REG_ADDCTL,
+				     WM8900_REG_ADDCTL_BIAS_SRC |
+				     WM8900_REG_ADDCTL_VMID_SOFTST);
+
+			/* VMID 2x50k */
+			wm8900_write(codec, WM8900_REG_POWER1,
+				     WM8900_REG_POWER1_STARTUP_BIAS_ENA | 0x1);
+
+			/* Allow capacitors to charge */
+			schedule_timeout_interruptible(msecs_to_jiffies(400));
+
+			/* Enable bias */
+			wm8900_write(codec, WM8900_REG_POWER1,
+				     WM8900_REG_POWER1_STARTUP_BIAS_ENA |
+				     WM8900_REG_POWER1_BIAS_ENA | 0x1);
+
+			wm8900_write(codec, WM8900_REG_ADDCTL, 0);
+
+			wm8900_write(codec, WM8900_REG_POWER1,
+				     WM8900_REG_POWER1_BIAS_ENA | 0x1);
+		}
+
+		reg = wm8900_read(codec, WM8900_REG_POWER1);
+		wm8900_write(codec, WM8900_REG_POWER1,
+			     (reg & WM8900_REG_POWER1_FLL_ENA) |
+			     WM8900_REG_POWER1_BIAS_ENA | 0x1);
+		wm8900_write(codec, WM8900_REG_POWER2,
+			     WM8900_REG_POWER2_SYSCLK_ENA);
+		wm8900_write(codec, WM8900_REG_POWER3, 0);
+		break;
+
+	case SND_SOC_BIAS_OFF:
+		/* Startup bias enable */
+		reg = wm8900_read(codec, WM8900_REG_POWER1);
+		wm8900_write(codec, WM8900_REG_POWER1,
+			     reg & WM8900_REG_POWER1_STARTUP_BIAS_ENA);
+		wm8900_write(codec, WM8900_REG_ADDCTL,
+			     WM8900_REG_ADDCTL_BIAS_SRC |
+			     WM8900_REG_ADDCTL_VMID_SOFTST);
+
+		/* Discharge caps */
+		wm8900_write(codec, WM8900_REG_POWER1,
+			     WM8900_REG_POWER1_STARTUP_BIAS_ENA);
+		schedule_timeout_interruptible(msecs_to_jiffies(500));
+
+		/* Remove clamp */
+		wm8900_write(codec, WM8900_REG_HPCTL1, 0);
+
+		/* Power down */
+		wm8900_write(codec, WM8900_REG_ADDCTL, 0);
+		wm8900_write(codec, WM8900_REG_POWER1, 0);
+		wm8900_write(codec, WM8900_REG_POWER2, 0);
+		wm8900_write(codec, WM8900_REG_POWER3, 0);
+
+		/* Need to let things settle before stopping the clock
+		 * to ensure that restart works, see "Stopping the
+		 * master clock" in the datasheet. */
+		schedule_timeout_interruptible(msecs_to_jiffies(1));
+		wm8900_write(codec, WM8900_REG_POWER2,
+			     WM8900_REG_POWER2_SYSCLK_ENA);
+		break;
+	}
+	codec->bias_level = level;
+	return 0;
+}
+
+static int wm8900_suspend(struct platform_device *pdev, pm_message_t state)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	struct snd_soc_codec *codec = socdev->codec;
+	struct wm8900_priv *wm8900 = codec->private_data;
+	int fll_out = wm8900->fll_out;
+	int fll_in  = wm8900->fll_in;
+	int ret;
+
+	/* Stop the FLL in an orderly fashion */
+	ret = wm8900_set_fll(codec, 0, 0, 0);
+	if (ret != 0) {
+		dev_err(&pdev->dev, "Failed to stop FLL\n");
+		return ret;
+	}
+
+	wm8900->fll_out = fll_out;
+	wm8900->fll_in = fll_in;
+
+	wm8900_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
+	return 0;
+}
+
+static int wm8900_resume(struct platform_device *pdev)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	struct snd_soc_codec *codec = socdev->codec;
+	struct wm8900_priv *wm8900 = codec->private_data;
+	u16 *cache;
+	int i, ret;
+
+	cache = kmemdup(codec->reg_cache, sizeof(wm8900_reg_defaults),
+			GFP_KERNEL);
+
+	wm8900_reset(codec);
+	wm8900_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+	/* Restart the FLL? */
+	if (wm8900->fll_out) {
+		int fll_out = wm8900->fll_out;
+		int fll_in  = wm8900->fll_in;
+
+		wm8900->fll_in = 0;
+		wm8900->fll_out = 0;
+
+		ret = wm8900_set_fll(codec, 0, fll_in, fll_out);
+		if (ret != 0) {
+			dev_err(&pdev->dev, "Failed to restart FLL\n");
+			return ret;
+		}
+	}
+
+	if (cache) {
+		for (i = 0; i < WM8900_MAXREG; i++)
+			wm8900_write(codec, i, cache[i]);
+		kfree(cache);
+	} else
+		dev_err(&pdev->dev, "Unable to allocate register cache\n");
+
+	return 0;
+}
+
+/*
+ * initialise the WM8900 driver
+ * register the mixer and dsp interfaces with the kernel
+ */
+static int wm8900_init(struct snd_soc_device *socdev)
+{
+	struct snd_soc_codec *codec = socdev->codec;
+	int ret = 0;
+	unsigned int reg;
+	struct i2c_client *i2c_client = socdev->codec->control_data;
+
+	codec->name = "WM8900";
+	codec->owner = THIS_MODULE;
+	codec->read = wm8900_read;
+	codec->write = wm8900_write;
+	codec->dai = &wm8900_dai;
+	codec->num_dai = 1;
+	codec->reg_cache_size = WM8900_MAXREG;
+	codec->reg_cache = kmemdup(wm8900_reg_defaults,
+				   sizeof(wm8900_reg_defaults), GFP_KERNEL);
+
+	if (codec->reg_cache == NULL)
+		return -ENOMEM;
+
+	reg = wm8900_read(codec, WM8900_REG_ID);
+	if (reg != 0x8900) {
+		dev_err(&i2c_client->dev, "Device is not a WM8900 - ID %x\n",
+			reg);
+		return -ENODEV;
+	}
+
+	codec->private_data = kzalloc(sizeof(struct wm8900_priv), GFP_KERNEL);
+	if (codec->private_data == NULL) {
+		ret = -ENOMEM;
+		goto priv_err;
+	}
+
+	/* Read back from the chip */
+	reg = wm8900_chip_read(codec, WM8900_REG_POWER1);
+	reg = (reg >> 12) & 0xf;
+	dev_info(&i2c_client->dev, "WM8900 revision %d\n", reg);
+
+	wm8900_reset(codec);
+
+	/* Latch the volume update bits */
+	wm8900_write(codec, WM8900_REG_LINVOL,
+		     wm8900_read(codec, WM8900_REG_LINVOL) | 0x100);
+	wm8900_write(codec, WM8900_REG_RINVOL,
+		     wm8900_read(codec, WM8900_REG_RINVOL) | 0x100);
+	wm8900_write(codec, WM8900_REG_LOUT1CTL,
+		     wm8900_read(codec, WM8900_REG_LOUT1CTL) | 0x100);
+	wm8900_write(codec, WM8900_REG_ROUT1CTL,
+		     wm8900_read(codec, WM8900_REG_ROUT1CTL) | 0x100);
+	wm8900_write(codec, WM8900_REG_LOUT2CTL,
+		     wm8900_read(codec, WM8900_REG_LOUT2CTL) | 0x100);
+	wm8900_write(codec, WM8900_REG_ROUT2CTL,
+		     wm8900_read(codec, WM8900_REG_ROUT2CTL) | 0x100);
+	wm8900_write(codec, WM8900_REG_LDAC_DV,
+		     wm8900_read(codec, WM8900_REG_LDAC_DV) | 0x100);
+	wm8900_write(codec, WM8900_REG_RDAC_DV,
+		     wm8900_read(codec, WM8900_REG_RDAC_DV) | 0x100);
+	wm8900_write(codec, WM8900_REG_LADC_DV,
+		     wm8900_read(codec, WM8900_REG_LADC_DV) | 0x100);
+	wm8900_write(codec, WM8900_REG_RADC_DV,
+		     wm8900_read(codec, WM8900_REG_RADC_DV) | 0x100);
+
+	/* Set the DAC and mixer output bias */
+	wm8900_write(codec, WM8900_REG_OUTBIASCTL, 0x81);
+
+	/* Register pcms */
+	ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
+	if (ret < 0) {
+		dev_err(&i2c_client->dev, "Failed to register new PCMs\n");
+		goto pcm_err;
+	}
+
+	/* Turn the chip on */
+	codec->bias_level = SND_SOC_BIAS_OFF;
+	wm8900_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+	wm8900_add_controls(codec);
+	wm8900_add_widgets(codec);
+
+	ret = snd_soc_register_card(socdev);
+	if (ret < 0) {
+		dev_err(&i2c_client->dev, "Failed to register card\n");
+		goto card_err;
+	}
+	return ret;
+
+card_err:
+	snd_soc_free_pcms(socdev);
+	snd_soc_dapm_free(socdev);
+pcm_err:
+	kfree(codec->reg_cache);
+priv_err:
+	kfree(codec->private_data);
+	return ret;
+}
+
+static struct snd_soc_device *wm8900_socdev;
+
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+
+static unsigned short normal_i2c[] = { 0, I2C_CLIENT_END };
+
+/* Magic definition of all other variables and things */
+I2C_CLIENT_INSMOD;
+
+static struct i2c_driver wm8900_i2c_driver;
+static struct i2c_client client_template;
+
+/* If the i2c layer weren't so broken, we could pass this kind of data
+   around */
+static int wm8900_codec_probe(struct i2c_adapter *adap, int addr, int kind)
+{
+	struct snd_soc_device *socdev = wm8900_socdev;
+	struct wm8900_setup_data *setup = socdev->codec_data;
+	struct snd_soc_codec *codec = socdev->codec;
+	struct i2c_client *i2c;
+	int ret;
+
+	if (addr != setup->i2c_address)
+		return -ENODEV;
+
+	dev_err(&adap->dev, "Probe on %x\n", addr);
+
+	client_template.adapter = adap;
+	client_template.addr = addr;
+
+	i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL);
+	if (i2c == NULL) {
+		kfree(codec);
+		return -ENOMEM;
+	}
+	i2c_set_clientdata(i2c, codec);
+	codec->control_data = i2c;
+
+	ret = i2c_attach_client(i2c);
+	if (ret < 0) {
+		dev_err(&adap->dev,
+			"failed to attach codec at addr %x\n", addr);
+		goto err;
+	}
+
+	ret = wm8900_init(socdev);
+	if (ret < 0) {
+		dev_err(&adap->dev, "failed to initialise WM8900\n");
+		goto err;
+	}
+	return ret;
+
+err:
+	kfree(codec);
+	kfree(i2c);
+	return ret;
+}
+
+static int wm8900_i2c_detach(struct i2c_client *client)
+{
+	struct snd_soc_codec *codec = i2c_get_clientdata(client);
+	i2c_detach_client(client);
+	kfree(codec->reg_cache);
+	kfree(client);
+	return 0;
+}
+
+static int wm8900_i2c_attach(struct i2c_adapter *adap)
+{
+	return i2c_probe(adap, &addr_data, wm8900_codec_probe);
+}
+
+/* corgi i2c codec control layer */
+static struct i2c_driver wm8900_i2c_driver = {
+	.driver = {
+		.name = "WM8900 I2C codec",
+		.owner = THIS_MODULE,
+	},
+	.attach_adapter = wm8900_i2c_attach,
+	.detach_client =  wm8900_i2c_detach,
+	.command =        NULL,
+};
+
+static struct i2c_client client_template = {
+	.name =   "WM8900",
+	.driver = &wm8900_i2c_driver,
+};
+#endif
+
+static int wm8900_probe(struct platform_device *pdev)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	struct wm8900_setup_data *setup;
+	struct snd_soc_codec *codec;
+	int ret = 0;
+
+	dev_info(&pdev->dev, "WM8900 Audio Codec\n");
+
+	setup = socdev->codec_data;
+	codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
+	if (codec == NULL)
+		return -ENOMEM;
+
+	mutex_init(&codec->mutex);
+	INIT_LIST_HEAD(&codec->dapm_widgets);
+	INIT_LIST_HEAD(&codec->dapm_paths);
+
+	socdev->codec = codec;
+
+	codec->set_bias_level = wm8900_set_bias_level;
+
+	wm8900_socdev = socdev;
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+	if (setup->i2c_address) {
+		normal_i2c[0] = setup->i2c_address;
+		codec->hw_write = (hw_write_t)i2c_master_send;
+		ret = i2c_add_driver(&wm8900_i2c_driver);
+		if (ret != 0)
+			printk(KERN_ERR "can't add i2c driver");
+	}
+#else
+#error Non-I2C interfaces not yet supported
+#endif
+	return ret;
+}
+
+/* power down chip */
+static int wm8900_remove(struct platform_device *pdev)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	struct snd_soc_codec *codec = socdev->codec;
+
+	if (codec->control_data)
+		wm8900_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
+	snd_soc_free_pcms(socdev);
+	snd_soc_dapm_free(socdev);
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+	i2c_del_driver(&wm8900_i2c_driver);
+#endif
+	kfree(codec);
+
+	return 0;
+}
+
+struct snd_soc_codec_device soc_codec_dev_wm8900 = {
+	.probe = 	wm8900_probe,
+	.remove = 	wm8900_remove,
+	.suspend = 	wm8900_suspend,
+	.resume =	wm8900_resume,
+};
+EXPORT_SYMBOL_GPL(soc_codec_dev_wm8900);
+
+MODULE_DESCRIPTION("ASoC WM8900 driver");
+MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfonmicro.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm8900.h b/sound/soc/codecs/wm8900.h
new file mode 100644
index 0000000..ba450d9
--- /dev/null
+++ b/sound/soc/codecs/wm8900.h
@@ -0,0 +1,64 @@
+/*
+ * wm8900.h  --  WM890 Soc Audio driver
+ *
+ * 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 _WM8900_H
+#define _WM8900_H
+
+#define WM8900_FLL 1
+
+#define WM8900_BCLK_DIV   1
+#define WM8900_ADC_CLKDIV 2
+#define WM8900_DAC_CLKDIV 3
+#define WM8900_ADC_LRCLK  4
+#define WM8900_DAC_LRCLK  5
+#define WM8900_OPCLK_DIV  6
+#define WM8900_LRCLK_MODE 7
+
+#define WM8900_BCLK_DIV_1   0x00
+#define WM8900_BCLK_DIV_1_5 0x02
+#define WM8900_BCLK_DIV_2   0x04
+#define WM8900_BCLK_DIV_3   0x06
+#define WM8900_BCLK_DIV_4   0x08
+#define WM8900_BCLK_DIV_5_5 0x0a
+#define WM8900_BCLK_DIV_6   0x0c
+#define WM8900_BCLK_DIV_8   0x0e
+#define WM8900_BCLK_DIV_11  0x10
+#define WM8900_BCLK_DIV_12  0x12
+#define WM8900_BCLK_DIV_16  0x14
+#define WM8900_BCLK_DIV_22  0x16
+#define WM8900_BCLK_DIV_24  0x18
+#define WM8900_BCLK_DIV_32  0x1a
+#define WM8900_BCLK_DIV_44  0x1c
+#define WM8900_BCLK_DIV_48  0x1e
+
+#define WM8900_ADC_CLKDIV_1   0x00
+#define WM8900_ADC_CLKDIV_1_5 0x20
+#define WM8900_ADC_CLKDIV_2   0x40
+#define WM8900_ADC_CLKDIV_3   0x60
+#define WM8900_ADC_CLKDIV_4   0x80
+#define WM8900_ADC_CLKDIV_5_5 0xa0
+#define WM8900_ADC_CLKDIV_6   0xc0
+
+#define WM8900_DAC_CLKDIV_1   0x00
+#define WM8900_DAC_CLKDIV_1_5 0x04
+#define WM8900_DAC_CLKDIV_2   0x08
+#define WM8900_DAC_CLKDIV_3   0x0c
+#define WM8900_DAC_CLKDIV_4   0x10
+#define WM8900_DAC_CLKDIV_5_5 0x14
+#define WM8900_DAC_CLKDIV_6   0x18
+
+#define WM8900_
+
+struct wm8900_setup_data {
+	unsigned short i2c_address;
+};
+
+extern struct snd_soc_dai wm8900_dai;
+extern struct snd_soc_codec_device soc_codec_dev_wm8900;
+
+#endif
diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c
new file mode 100644
index 0000000..ce40d78
--- /dev/null
+++ b/sound/soc/codecs/wm8903.c
@@ -0,0 +1,1813 @@
+/*
+ * wm8903.c  --  WM8903 ALSA SoC Audio driver
+ *
+ * Copyright 2008 Wolfson Microelectronics
+ *
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.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.
+ *
+ * TODO:
+ *  - TDM mode configuration.
+ *  - Mic detect.
+ *  - Digital microphone support.
+ *  - Interrupt support (mic detect and sequencer).
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/tlv.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+
+#include "wm8903.h"
+
+struct wm8903_priv {
+	int sysclk;
+
+	/* Reference counts */
+	int charge_pump_users;
+	int class_w_users;
+	int playback_active;
+	int capture_active;
+
+	struct snd_pcm_substream *master_substream;
+	struct snd_pcm_substream *slave_substream;
+};
+
+/* Register defaults at reset */
+static u16 wm8903_reg_defaults[] = {
+	0x8903,     /* R0   - SW Reset and ID */
+	0x0000,     /* R1   - Revision Number */
+	0x0000,     /* R2 */
+	0x0000,     /* R3 */
+	0x0018,     /* R4   - Bias Control 0 */
+	0x0000,     /* R5   - VMID Control 0 */
+	0x0000,     /* R6   - Mic Bias Control 0 */
+	0x0000,     /* R7 */
+	0x0001,     /* R8   - Analogue DAC 0 */
+	0x0000,     /* R9 */
+	0x0001,     /* R10  - Analogue ADC 0 */
+	0x0000,     /* R11 */
+	0x0000,     /* R12  - Power Management 0 */
+	0x0000,     /* R13  - Power Management 1 */
+	0x0000,     /* R14  - Power Management 2 */
+	0x0000,     /* R15  - Power Management 3 */
+	0x0000,     /* R16  - Power Management 4 */
+	0x0000,     /* R17  - Power Management 5 */
+	0x0000,     /* R18  - Power Management 6 */
+	0x0000,     /* R19 */
+	0x0400,     /* R20  - Clock Rates 0 */
+	0x0D07,     /* R21  - Clock Rates 1 */
+	0x0000,     /* R22  - Clock Rates 2 */
+	0x0000,     /* R23 */
+	0x0050,     /* R24  - Audio Interface 0 */
+	0x0242,     /* R25  - Audio Interface 1 */
+	0x0008,     /* R26  - Audio Interface 2 */
+	0x0022,     /* R27  - Audio Interface 3 */
+	0x0000,     /* R28 */
+	0x0000,     /* R29 */
+	0x00C0,     /* R30  - DAC Digital Volume Left */
+	0x00C0,     /* R31  - DAC Digital Volume Right */
+	0x0000,     /* R32  - DAC Digital 0 */
+	0x0000,     /* R33  - DAC Digital 1 */
+	0x0000,     /* R34 */
+	0x0000,     /* R35 */
+	0x00C0,     /* R36  - ADC Digital Volume Left */
+	0x00C0,     /* R37  - ADC Digital Volume Right */
+	0x0000,     /* R38  - ADC Digital 0 */
+	0x0073,     /* R39  - Digital Microphone 0 */
+	0x09BF,     /* R40  - DRC 0 */
+	0x3241,     /* R41  - DRC 1 */
+	0x0020,     /* R42  - DRC 2 */
+	0x0000,     /* R43  - DRC 3 */
+	0x0085,     /* R44  - Analogue Left Input 0 */
+	0x0085,     /* R45  - Analogue Right Input 0 */
+	0x0044,     /* R46  - Analogue Left Input 1 */
+	0x0044,     /* R47  - Analogue Right Input 1 */
+	0x0000,     /* R48 */
+	0x0000,     /* R49 */
+	0x0008,     /* R50  - Analogue Left Mix 0 */
+	0x0004,     /* R51  - Analogue Right Mix 0 */
+	0x0000,     /* R52  - Analogue Spk Mix Left 0 */
+	0x0000,     /* R53  - Analogue Spk Mix Left 1 */
+	0x0000,     /* R54  - Analogue Spk Mix Right 0 */
+	0x0000,     /* R55  - Analogue Spk Mix Right 1 */
+	0x0000,     /* R56 */
+	0x002D,     /* R57  - Analogue OUT1 Left */
+	0x002D,     /* R58  - Analogue OUT1 Right */
+	0x0039,     /* R59  - Analogue OUT2 Left */
+	0x0039,     /* R60  - Analogue OUT2 Right */
+	0x0100,     /* R61 */
+	0x0139,     /* R62  - Analogue OUT3 Left */
+	0x0139,     /* R63  - Analogue OUT3 Right */
+	0x0000,     /* R64 */
+	0x0000,     /* R65  - Analogue SPK Output Control 0 */
+	0x0000,     /* R66 */
+	0x0010,     /* R67  - DC Servo 0 */
+	0x0100,     /* R68 */
+	0x00A4,     /* R69  - DC Servo 2 */
+	0x0807,     /* R70 */
+	0x0000,     /* R71 */
+	0x0000,     /* R72 */
+	0x0000,     /* R73 */
+	0x0000,     /* R74 */
+	0x0000,     /* R75 */
+	0x0000,     /* R76 */
+	0x0000,     /* R77 */
+	0x0000,     /* R78 */
+	0x000E,     /* R79 */
+	0x0000,     /* R80 */
+	0x0000,     /* R81 */
+	0x0000,     /* R82 */
+	0x0000,     /* R83 */
+	0x0000,     /* R84 */
+	0x0000,     /* R85 */
+	0x0000,     /* R86 */
+	0x0006,     /* R87 */
+	0x0000,     /* R88 */
+	0x0000,     /* R89 */
+	0x0000,     /* R90  - Analogue HP 0 */
+	0x0060,     /* R91 */
+	0x0000,     /* R92 */
+	0x0000,     /* R93 */
+	0x0000,     /* R94  - Analogue Lineout 0 */
+	0x0060,     /* R95 */
+	0x0000,     /* R96 */
+	0x0000,     /* R97 */
+	0x0000,     /* R98  - Charge Pump 0 */
+	0x1F25,     /* R99 */
+	0x2B19,     /* R100 */
+	0x01C0,     /* R101 */
+	0x01EF,     /* R102 */
+	0x2B00,     /* R103 */
+	0x0000,     /* R104 - Class W 0 */
+	0x01C0,     /* R105 */
+	0x1C10,     /* R106 */
+	0x0000,     /* R107 */
+	0x0000,     /* R108 - Write Sequencer 0 */
+	0x0000,     /* R109 - Write Sequencer 1 */
+	0x0000,     /* R110 - Write Sequencer 2 */
+	0x0000,     /* R111 - Write Sequencer 3 */
+	0x0000,     /* R112 - Write Sequencer 4 */
+	0x0000,     /* R113 */
+	0x0000,     /* R114 - Control Interface */
+	0x0000,     /* R115 */
+	0x00A8,     /* R116 - GPIO Control 1 */
+	0x00A8,     /* R117 - GPIO Control 2 */
+	0x00A8,     /* R118 - GPIO Control 3 */
+	0x0220,     /* R119 - GPIO Control 4 */
+	0x01A0,     /* R120 - GPIO Control 5 */
+	0x0000,     /* R121 - Interrupt Status 1 */
+	0xFFFF,     /* R122 - Interrupt Status 1 Mask */
+	0x0000,     /* R123 - Interrupt Polarity 1 */
+	0x0000,     /* R124 */
+	0x0003,     /* R125 */
+	0x0000,     /* R126 - Interrupt Control */
+	0x0000,     /* R127 */
+	0x0005,     /* R128 */
+	0x0000,     /* R129 - Control Interface Test 1 */
+	0x0000,     /* R130 */
+	0x0000,     /* R131 */
+	0x0000,     /* R132 */
+	0x0000,     /* R133 */
+	0x0000,     /* R134 */
+	0x03FF,     /* R135 */
+	0x0007,     /* R136 */
+	0x0040,     /* R137 */
+	0x0000,     /* R138 */
+	0x0000,     /* R139 */
+	0x0000,     /* R140 */
+	0x0000,     /* R141 */
+	0x0000,     /* R142 */
+	0x0000,     /* R143 */
+	0x0000,     /* R144 */
+	0x0000,     /* R145 */
+	0x0000,     /* R146 */
+	0x0000,     /* R147 */
+	0x4000,     /* R148 */
+	0x6810,     /* R149 - Charge Pump Test 1 */
+	0x0004,     /* R150 */
+	0x0000,     /* R151 */
+	0x0000,     /* R152 */
+	0x0000,     /* R153 */
+	0x0000,     /* R154 */
+	0x0000,     /* R155 */
+	0x0000,     /* R156 */
+	0x0000,     /* R157 */
+	0x0000,     /* R158 */
+	0x0000,     /* R159 */
+	0x0000,     /* R160 */
+	0x0000,     /* R161 */
+	0x0000,     /* R162 */
+	0x0000,     /* R163 */
+	0x0028,     /* R164 - Clock Rate Test 4 */
+	0x0004,     /* R165 */
+	0x0000,     /* R166 */
+	0x0060,     /* R167 */
+	0x0000,     /* R168 */
+	0x0000,     /* R169 */
+	0x0000,     /* R170 */
+	0x0000,     /* R171 */
+	0x0000,     /* R172 - Analogue Output Bias 0 */
+};
+
+static unsigned int wm8903_read_reg_cache(struct snd_soc_codec *codec,
+						 unsigned int reg)
+{
+	u16 *cache = codec->reg_cache;
+
+	BUG_ON(reg >= ARRAY_SIZE(wm8903_reg_defaults));
+
+	return cache[reg];
+}
+
+static unsigned int wm8903_hw_read(struct snd_soc_codec *codec, u8 reg)
+{
+	struct i2c_msg xfer[2];
+	u16 data;
+	int ret;
+	struct i2c_client *client = codec->control_data;
+
+	/* Write register */
+	xfer[0].addr = client->addr;
+	xfer[0].flags = 0;
+	xfer[0].len = 1;
+	xfer[0].buf = &reg;
+
+	/* Read data */
+	xfer[1].addr = client->addr;
+	xfer[1].flags = I2C_M_RD;
+	xfer[1].len = 2;
+	xfer[1].buf = (u8 *)&data;
+
+	ret = i2c_transfer(client->adapter, xfer, 2);
+	if (ret != 2) {
+		pr_err("i2c_transfer returned %d\n", ret);
+		return 0;
+	}
+
+	return (data >> 8) | ((data & 0xff) << 8);
+}
+
+static unsigned int wm8903_read(struct snd_soc_codec *codec,
+				unsigned int reg)
+{
+	switch (reg) {
+	case WM8903_SW_RESET_AND_ID:
+	case WM8903_REVISION_NUMBER:
+	case WM8903_INTERRUPT_STATUS_1:
+	case WM8903_WRITE_SEQUENCER_4:
+		return wm8903_hw_read(codec, reg);
+
+	default:
+		return wm8903_read_reg_cache(codec, reg);
+	}
+}
+
+static void wm8903_write_reg_cache(struct snd_soc_codec *codec,
+				   u16 reg, unsigned int value)
+{
+	u16 *cache = codec->reg_cache;
+
+	BUG_ON(reg >= ARRAY_SIZE(wm8903_reg_defaults));
+
+	switch (reg) {
+	case WM8903_SW_RESET_AND_ID:
+	case WM8903_REVISION_NUMBER:
+		break;
+
+	default:
+		cache[reg] = value;
+		break;
+	}
+}
+
+static int wm8903_write(struct snd_soc_codec *codec, unsigned int reg,
+			unsigned int value)
+{
+	u8 data[3];
+
+	wm8903_write_reg_cache(codec, reg, value);
+
+	/* Data format is 1 byte of address followed by 2 bytes of data */
+	data[0] = reg;
+	data[1] = (value >> 8) & 0xff;
+	data[2] = value & 0xff;
+
+	if (codec->hw_write(codec->control_data, data, 3) == 2)
+		return 0;
+	else
+		return -EIO;
+}
+
+static int wm8903_run_sequence(struct snd_soc_codec *codec, unsigned int start)
+{
+	u16 reg[5];
+	struct i2c_client *i2c = codec->control_data;
+
+	BUG_ON(start > 48);
+
+	/* Enable the sequencer */
+	reg[0] = wm8903_read(codec, WM8903_WRITE_SEQUENCER_0);
+	reg[0] |= WM8903_WSEQ_ENA;
+	wm8903_write(codec, WM8903_WRITE_SEQUENCER_0, reg[0]);
+
+	dev_dbg(&i2c->dev, "Starting sequence at %d\n", start);
+
+	wm8903_write(codec, WM8903_WRITE_SEQUENCER_3,
+		     start | WM8903_WSEQ_START);
+
+	/* Wait for it to complete.  If we have the interrupt wired up then
+	 * we could block waiting for an interrupt, though polling may still
+	 * be desirable for diagnostic purposes.
+	 */
+	do {
+		msleep(10);
+
+		reg[4] = wm8903_read(codec, WM8903_WRITE_SEQUENCER_4);
+	} while (reg[4] & WM8903_WSEQ_BUSY);
+
+	dev_dbg(&i2c->dev, "Sequence complete\n");
+
+	/* Disable the sequencer again */
+	wm8903_write(codec, WM8903_WRITE_SEQUENCER_0,
+		     reg[0] & ~WM8903_WSEQ_ENA);
+
+	return 0;
+}
+
+static void wm8903_sync_reg_cache(struct snd_soc_codec *codec, u16 *cache)
+{
+	int i;
+
+	/* There really ought to be something better we can do here :/ */
+	for (i = 0; i < ARRAY_SIZE(wm8903_reg_defaults); i++)
+		cache[i] = wm8903_hw_read(codec, i);
+}
+
+static void wm8903_reset(struct snd_soc_codec *codec)
+{
+	wm8903_write(codec, WM8903_SW_RESET_AND_ID, 0);
+}
+
+#define WM8903_OUTPUT_SHORT 0x8
+#define WM8903_OUTPUT_OUT   0x4
+#define WM8903_OUTPUT_INT   0x2
+#define WM8903_OUTPUT_IN    0x1
+
+/*
+ * Event for headphone and line out amplifier power changes.  Special
+ * power up/down sequences are required in order to maximise pop/click
+ * performance.
+ */
+static int wm8903_output_event(struct snd_soc_dapm_widget *w,
+			       struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = w->codec;
+	struct wm8903_priv *wm8903 = codec->private_data;
+	struct i2c_client *i2c = codec->control_data;
+	u16 val;
+	u16 reg;
+	int shift;
+	u16 cp_reg = wm8903_read(codec, WM8903_CHARGE_PUMP_0);
+
+	switch (w->reg) {
+	case WM8903_POWER_MANAGEMENT_2:
+		reg = WM8903_ANALOGUE_HP_0;
+		break;
+	case WM8903_POWER_MANAGEMENT_3:
+		reg = WM8903_ANALOGUE_LINEOUT_0;
+		break;
+	default:
+		BUG();
+	}
+
+	switch (w->shift) {
+	case 0:
+		shift = 0;
+		break;
+	case 1:
+		shift = 4;
+		break;
+	default:
+		BUG();
+	}
+
+	if (event & SND_SOC_DAPM_PRE_PMU) {
+		val = wm8903_read(codec, reg);
+
+		/* Short the output */
+		val &= ~(WM8903_OUTPUT_SHORT << shift);
+		wm8903_write(codec, reg, val);
+
+		wm8903->charge_pump_users++;
+
+		dev_dbg(&i2c->dev, "Charge pump use count now %d\n",
+			wm8903->charge_pump_users);
+
+		if (wm8903->charge_pump_users == 1) {
+			dev_dbg(&i2c->dev, "Enabling charge pump\n");
+			wm8903_write(codec, WM8903_CHARGE_PUMP_0,
+				     cp_reg | WM8903_CP_ENA);
+			mdelay(4);
+		}
+	}
+
+	if (event & SND_SOC_DAPM_POST_PMU) {
+		val = wm8903_read(codec, reg);
+
+		val |= (WM8903_OUTPUT_IN << shift);
+		wm8903_write(codec, reg, val);
+
+		val |= (WM8903_OUTPUT_INT << shift);
+		wm8903_write(codec, reg, val);
+
+		/* Turn on the output ENA_OUTP */
+		val |= (WM8903_OUTPUT_OUT << shift);
+		wm8903_write(codec, reg, val);
+
+		/* Remove the short */
+		val |= (WM8903_OUTPUT_SHORT << shift);
+		wm8903_write(codec, reg, val);
+	}
+
+	if (event & SND_SOC_DAPM_PRE_PMD) {
+		val = wm8903_read(codec, reg);
+
+		/* Short the output */
+		val &= ~(WM8903_OUTPUT_SHORT << shift);
+		wm8903_write(codec, reg, val);
+
+		/* Then disable the intermediate and output stages */
+		val &= ~((WM8903_OUTPUT_OUT | WM8903_OUTPUT_INT |
+			  WM8903_OUTPUT_IN) << shift);
+		wm8903_write(codec, reg, val);
+	}
+
+	if (event & SND_SOC_DAPM_POST_PMD) {
+		wm8903->charge_pump_users--;
+
+		dev_dbg(&i2c->dev, "Charge pump use count now %d\n",
+			wm8903->charge_pump_users);
+
+		if (wm8903->charge_pump_users == 0) {
+			dev_dbg(&i2c->dev, "Disabling charge pump\n");
+			wm8903_write(codec, WM8903_CHARGE_PUMP_0,
+				     cp_reg & ~WM8903_CP_ENA);
+		}
+	}
+
+	return 0;
+}
+
+/*
+ * When used with DAC outputs only the WM8903 charge pump supports
+ * operation in class W mode, providing very low power consumption
+ * when used with digital sources.  Enable and disable this mode
+ * automatically depending on the mixer configuration.
+ *
+ * All the relevant controls are simple switches.
+ */
+static int wm8903_class_w_put(struct snd_kcontrol *kcontrol,
+			      struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol);
+	struct snd_soc_codec *codec = widget->codec;
+	struct wm8903_priv *wm8903 = codec->private_data;
+	struct i2c_client *i2c = codec->control_data;
+	u16 reg;
+	int ret;
+
+	reg = wm8903_read(codec, WM8903_CLASS_W_0);
+
+	/* Turn it off if we're about to enable bypass */
+	if (ucontrol->value.integer.value[0]) {
+		if (wm8903->class_w_users == 0) {
+			dev_dbg(&i2c->dev, "Disabling Class W\n");
+			wm8903_write(codec, WM8903_CLASS_W_0, reg &
+				     ~(WM8903_CP_DYN_FREQ | WM8903_CP_DYN_V));
+		}
+		wm8903->class_w_users++;
+	}
+
+	/* Implement the change */
+	ret = snd_soc_dapm_put_volsw(kcontrol, ucontrol);
+
+	/* If we've just disabled the last bypass path turn Class W on */
+	if (!ucontrol->value.integer.value[0]) {
+		if (wm8903->class_w_users == 1) {
+			dev_dbg(&i2c->dev, "Enabling Class W\n");
+			wm8903_write(codec, WM8903_CLASS_W_0, reg |
+				     WM8903_CP_DYN_FREQ | WM8903_CP_DYN_V);
+		}
+		wm8903->class_w_users--;
+	}
+
+	dev_dbg(&i2c->dev, "Bypass use count now %d\n",
+		wm8903->class_w_users);
+
+	return ret;
+}
+
+#define SOC_DAPM_SINGLE_W(xname, reg, shift, max, invert) \
+{	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+	.info = snd_soc_info_volsw, \
+	.get = snd_soc_dapm_get_volsw, .put = wm8903_class_w_put, \
+	.private_value =  SOC_SINGLE_VALUE(reg, shift, max, invert) }
+
+
+/* ALSA can only do steps of .01dB */
+static const DECLARE_TLV_DB_SCALE(digital_tlv, -7200, 75, 1);
+
+static const DECLARE_TLV_DB_SCALE(out_tlv, -5700, 100, 0);
+
+static const DECLARE_TLV_DB_SCALE(drc_tlv_thresh, 0, 75, 0);
+static const DECLARE_TLV_DB_SCALE(drc_tlv_amp, -2250, 75, 0);
+static const DECLARE_TLV_DB_SCALE(drc_tlv_min, 0, 600, 0);
+static const DECLARE_TLV_DB_SCALE(drc_tlv_max, 1200, 600, 0);
+static const DECLARE_TLV_DB_SCALE(drc_tlv_startup, -300, 50, 0);
+
+static const char *drc_slope_text[] = {
+	"1", "1/2", "1/4", "1/8", "1/16", "0"
+};
+
+static const struct soc_enum drc_slope_r0 =
+	SOC_ENUM_SINGLE(WM8903_DRC_2, 3, 6, drc_slope_text);
+
+static const struct soc_enum drc_slope_r1 =
+	SOC_ENUM_SINGLE(WM8903_DRC_2, 0, 6, drc_slope_text);
+
+static const char *drc_attack_text[] = {
+	"instantaneous",
+	"363us", "762us", "1.45ms", "2.9ms", "5.8ms", "11.6ms", "23.2ms",
+	"46.4ms", "92.8ms", "185.6ms"
+};
+
+static const struct soc_enum drc_attack =
+	SOC_ENUM_SINGLE(WM8903_DRC_1, 12, 11, drc_attack_text);
+
+static const char *drc_decay_text[] = {
+	"186ms", "372ms", "743ms", "1.49s", "2.97s", "5.94s", "11.89s",
+	"23.87s", "47.56s"
+};
+
+static const struct soc_enum drc_decay =
+	SOC_ENUM_SINGLE(WM8903_DRC_1, 8, 9, drc_decay_text);
+
+static const char *drc_ff_delay_text[] = {
+	"5 samples", "9 samples"
+};
+
+static const struct soc_enum drc_ff_delay =
+	SOC_ENUM_SINGLE(WM8903_DRC_0, 5, 2, drc_ff_delay_text);
+
+static const char *drc_qr_decay_text[] = {
+	"0.725ms", "1.45ms", "5.8ms"
+};
+
+static const struct soc_enum drc_qr_decay =
+	SOC_ENUM_SINGLE(WM8903_DRC_1, 4, 3, drc_qr_decay_text);
+
+static const char *drc_smoothing_text[] = {
+	"Low", "Medium", "High"
+};
+
+static const struct soc_enum drc_smoothing =
+	SOC_ENUM_SINGLE(WM8903_DRC_0, 11, 3, drc_smoothing_text);
+
+static const char *soft_mute_text[] = {
+	"Fast (fs/2)", "Slow (fs/32)"
+};
+
+static const struct soc_enum soft_mute =
+	SOC_ENUM_SINGLE(WM8903_DAC_DIGITAL_1, 10, 2, soft_mute_text);
+
+static const char *mute_mode_text[] = {
+	"Hard", "Soft"
+};
+
+static const struct soc_enum mute_mode =
+	SOC_ENUM_SINGLE(WM8903_DAC_DIGITAL_1, 9, 2, mute_mode_text);
+
+static const char *dac_deemphasis_text[] = {
+	"Disabled", "32kHz", "44.1kHz", "48kHz"
+};
+
+static const struct soc_enum dac_deemphasis =
+	SOC_ENUM_SINGLE(WM8903_DAC_DIGITAL_1, 1, 4, dac_deemphasis_text);
+
+static const char *companding_text[] = {
+	"ulaw", "alaw"
+};
+
+static const struct soc_enum dac_companding =
+	SOC_ENUM_SINGLE(WM8903_AUDIO_INTERFACE_0, 0, 2, companding_text);
+
+static const struct soc_enum adc_companding =
+	SOC_ENUM_SINGLE(WM8903_AUDIO_INTERFACE_0, 2, 2, companding_text);
+
+static const char *input_mode_text[] = {
+	"Single-Ended", "Differential Line", "Differential Mic"
+};
+
+static const struct soc_enum linput_mode_enum =
+	SOC_ENUM_SINGLE(WM8903_ANALOGUE_LEFT_INPUT_1, 0, 3, input_mode_text);
+
+static const struct soc_enum rinput_mode_enum =
+	SOC_ENUM_SINGLE(WM8903_ANALOGUE_RIGHT_INPUT_1, 0, 3, input_mode_text);
+
+static const char *linput_mux_text[] = {
+	"IN1L", "IN2L", "IN3L"
+};
+
+static const struct soc_enum linput_enum =
+	SOC_ENUM_SINGLE(WM8903_ANALOGUE_LEFT_INPUT_1, 2, 3, linput_mux_text);
+
+static const struct soc_enum linput_inv_enum =
+	SOC_ENUM_SINGLE(WM8903_ANALOGUE_LEFT_INPUT_1, 4, 3, linput_mux_text);
+
+static const char *rinput_mux_text[] = {
+	"IN1R", "IN2R", "IN3R"
+};
+
+static const struct soc_enum rinput_enum =
+	SOC_ENUM_SINGLE(WM8903_ANALOGUE_RIGHT_INPUT_1, 2, 3, rinput_mux_text);
+
+static const struct soc_enum rinput_inv_enum =
+	SOC_ENUM_SINGLE(WM8903_ANALOGUE_RIGHT_INPUT_1, 4, 3, rinput_mux_text);
+
+
+static const struct snd_kcontrol_new wm8903_snd_controls[] = {
+
+/* Input PGAs - No TLV since the scale depends on PGA mode */
+SOC_SINGLE("Left Input PGA Switch", WM8903_ANALOGUE_LEFT_INPUT_0,
+	   7, 1, 1),
+SOC_SINGLE("Left Input PGA Volume", WM8903_ANALOGUE_LEFT_INPUT_0,
+	   0, 31, 0),
+SOC_SINGLE("Left Input PGA Common Mode Switch", WM8903_ANALOGUE_LEFT_INPUT_1,
+	   6, 1, 0),
+
+SOC_SINGLE("Right Input PGA Switch", WM8903_ANALOGUE_RIGHT_INPUT_0,
+	   7, 1, 1),
+SOC_SINGLE("Right Input PGA Volume", WM8903_ANALOGUE_RIGHT_INPUT_0,
+	   0, 31, 0),
+SOC_SINGLE("Right Input PGA Common Mode Switch", WM8903_ANALOGUE_RIGHT_INPUT_1,
+	   6, 1, 0),
+
+/* ADCs */
+SOC_SINGLE("DRC Switch", WM8903_DRC_0, 15, 1, 0),
+SOC_ENUM("DRC Compressor Slope R0", drc_slope_r0),
+SOC_ENUM("DRC Compressor Slope R1", drc_slope_r1),
+SOC_SINGLE_TLV("DRC Compressor Threashold Volume", WM8903_DRC_3, 5, 124, 1,
+	       drc_tlv_thresh),
+SOC_SINGLE_TLV("DRC Volume", WM8903_DRC_3, 0, 30, 1, drc_tlv_amp),
+SOC_SINGLE_TLV("DRC Minimum Gain Volume", WM8903_DRC_1, 2, 3, 1, drc_tlv_min),
+SOC_SINGLE_TLV("DRC Maximum Gain Volume", WM8903_DRC_1, 0, 3, 0, drc_tlv_max),
+SOC_ENUM("DRC Attack Rate", drc_attack),
+SOC_ENUM("DRC Decay Rate", drc_decay),
+SOC_ENUM("DRC FF Delay", drc_ff_delay),
+SOC_SINGLE("DRC Anticlip Switch", WM8903_DRC_0, 1, 1, 0),
+SOC_SINGLE("DRC QR Switch", WM8903_DRC_0, 2, 1, 0),
+SOC_SINGLE_TLV("DRC QR Threashold Volume", WM8903_DRC_0, 6, 3, 0, drc_tlv_max),
+SOC_ENUM("DRC QR Decay Rate", drc_qr_decay),
+SOC_SINGLE("DRC Smoothing Switch", WM8903_DRC_0, 3, 1, 0),
+SOC_SINGLE("DRC Smoothing Hysteresis Switch", WM8903_DRC_0, 0, 1, 0),
+SOC_ENUM("DRC Smoothing Threashold", drc_smoothing),
+SOC_SINGLE_TLV("DRC Startup Volume", WM8903_DRC_0, 6, 18, 0, drc_tlv_startup),
+
+SOC_DOUBLE_R_TLV("Digital Capture Volume", WM8903_ADC_DIGITAL_VOLUME_LEFT,
+		 WM8903_ADC_DIGITAL_VOLUME_RIGHT, 1, 96, 0, digital_tlv),
+SOC_ENUM("ADC Companding Mode", adc_companding),
+SOC_SINGLE("ADC Companding Switch", WM8903_AUDIO_INTERFACE_0, 3, 1, 0),
+
+/* DAC */
+SOC_DOUBLE_R_TLV("Digital Playback Volume", WM8903_DAC_DIGITAL_VOLUME_LEFT,
+		 WM8903_DAC_DIGITAL_VOLUME_RIGHT, 1, 120, 0, digital_tlv),
+SOC_ENUM("DAC Soft Mute Rate", soft_mute),
+SOC_ENUM("DAC Mute Mode", mute_mode),
+SOC_SINGLE("DAC Mono Switch", WM8903_DAC_DIGITAL_1, 12, 1, 0),
+SOC_ENUM("DAC De-emphasis", dac_deemphasis),
+SOC_SINGLE("DAC Sloping Stopband Filter Switch",
+	   WM8903_DAC_DIGITAL_1, 11, 1, 0),
+SOC_ENUM("DAC Companding Mode", dac_companding),
+SOC_SINGLE("DAC Companding Switch", WM8903_AUDIO_INTERFACE_0, 1, 1, 0),
+
+/* Headphones */
+SOC_DOUBLE_R("Headphone Switch",
+	     WM8903_ANALOGUE_OUT1_LEFT, WM8903_ANALOGUE_OUT1_RIGHT,
+	     8, 1, 1),
+SOC_DOUBLE_R("Headphone ZC Switch",
+	     WM8903_ANALOGUE_OUT1_LEFT, WM8903_ANALOGUE_OUT1_RIGHT,
+	     6, 1, 0),
+SOC_DOUBLE_R_TLV("Headphone Volume",
+		 WM8903_ANALOGUE_OUT1_LEFT, WM8903_ANALOGUE_OUT1_RIGHT,
+		 0, 63, 0, out_tlv),
+
+/* Line out */
+SOC_DOUBLE_R("Line Out Switch",
+	     WM8903_ANALOGUE_OUT2_LEFT, WM8903_ANALOGUE_OUT2_RIGHT,
+	     8, 1, 1),
+SOC_DOUBLE_R("Line Out ZC Switch",
+	     WM8903_ANALOGUE_OUT2_LEFT, WM8903_ANALOGUE_OUT2_RIGHT,
+	     6, 1, 0),
+SOC_DOUBLE_R_TLV("Line Out Volume",
+		 WM8903_ANALOGUE_OUT2_LEFT, WM8903_ANALOGUE_OUT2_RIGHT,
+		 0, 63, 0, out_tlv),
+
+/* Speaker */
+SOC_DOUBLE_R("Speaker Switch",
+	     WM8903_ANALOGUE_OUT3_LEFT, WM8903_ANALOGUE_OUT3_RIGHT, 8, 1, 1),
+SOC_DOUBLE_R("Speaker ZC Switch",
+	     WM8903_ANALOGUE_OUT3_LEFT, WM8903_ANALOGUE_OUT3_RIGHT, 6, 1, 0),
+SOC_DOUBLE_R_TLV("Speaker Volume",
+		 WM8903_ANALOGUE_OUT3_LEFT, WM8903_ANALOGUE_OUT3_RIGHT,
+		 0, 63, 0, out_tlv),
+};
+
+static int wm8903_add_controls(struct snd_soc_codec *codec)
+{
+	int err, i;
+
+	for (i = 0; i < ARRAY_SIZE(wm8903_snd_controls); i++) {
+		err = snd_ctl_add(codec->card,
+				  snd_soc_cnew(&wm8903_snd_controls[i],
+					       codec, NULL));
+		if (err < 0)
+			return err;
+	}
+
+	return 0;
+}
+
+static const struct snd_kcontrol_new linput_mode_mux =
+	SOC_DAPM_ENUM("Left Input Mode Mux", linput_mode_enum);
+
+static const struct snd_kcontrol_new rinput_mode_mux =
+	SOC_DAPM_ENUM("Right Input Mode Mux", rinput_mode_enum);
+
+static const struct snd_kcontrol_new linput_mux =
+	SOC_DAPM_ENUM("Left Input Mux", linput_enum);
+
+static const struct snd_kcontrol_new linput_inv_mux =
+	SOC_DAPM_ENUM("Left Inverting Input Mux", linput_inv_enum);
+
+static const struct snd_kcontrol_new rinput_mux =
+	SOC_DAPM_ENUM("Right Input Mux", rinput_enum);
+
+static const struct snd_kcontrol_new rinput_inv_mux =
+	SOC_DAPM_ENUM("Right Inverting Input Mux", rinput_inv_enum);
+
+static const struct snd_kcontrol_new left_output_mixer[] = {
+SOC_DAPM_SINGLE("DACL Switch", WM8903_ANALOGUE_LEFT_MIX_0, 3, 1, 0),
+SOC_DAPM_SINGLE("DACR Switch", WM8903_ANALOGUE_LEFT_MIX_0, 2, 1, 0),
+SOC_DAPM_SINGLE_W("Left Bypass Switch", WM8903_ANALOGUE_LEFT_MIX_0, 1, 1, 0),
+SOC_DAPM_SINGLE_W("Right Bypass Switch", WM8903_ANALOGUE_LEFT_MIX_0, 1, 1, 0),
+};
+
+static const struct snd_kcontrol_new right_output_mixer[] = {
+SOC_DAPM_SINGLE("DACL Switch", WM8903_ANALOGUE_RIGHT_MIX_0, 3, 1, 0),
+SOC_DAPM_SINGLE("DACR Switch", WM8903_ANALOGUE_RIGHT_MIX_0, 2, 1, 0),
+SOC_DAPM_SINGLE_W("Left Bypass Switch", WM8903_ANALOGUE_RIGHT_MIX_0, 1, 1, 0),
+SOC_DAPM_SINGLE_W("Right Bypass Switch", WM8903_ANALOGUE_RIGHT_MIX_0, 1, 1, 0),
+};
+
+static const struct snd_kcontrol_new left_speaker_mixer[] = {
+SOC_DAPM_SINGLE("DACL Switch", WM8903_ANALOGUE_SPK_MIX_LEFT_0, 3, 1, 0),
+SOC_DAPM_SINGLE("DACR Switch", WM8903_ANALOGUE_SPK_MIX_LEFT_0, 2, 1, 0),
+SOC_DAPM_SINGLE("Left Bypass Switch", WM8903_ANALOGUE_SPK_MIX_LEFT_0, 1, 1, 0),
+SOC_DAPM_SINGLE("Right Bypass Switch", WM8903_ANALOGUE_SPK_MIX_LEFT_0,
+		1, 1, 0),
+};
+
+static const struct snd_kcontrol_new right_speaker_mixer[] = {
+SOC_DAPM_SINGLE("DACL Switch", WM8903_ANALOGUE_SPK_MIX_RIGHT_0, 3, 1, 0),
+SOC_DAPM_SINGLE("DACR Switch", WM8903_ANALOGUE_SPK_MIX_RIGHT_0, 2, 1, 0),
+SOC_DAPM_SINGLE("Left Bypass Switch", WM8903_ANALOGUE_SPK_MIX_RIGHT_0,
+		1, 1, 0),
+SOC_DAPM_SINGLE("Right Bypass Switch", WM8903_ANALOGUE_SPK_MIX_RIGHT_0,
+		1, 1, 0),
+};
+
+static const struct snd_soc_dapm_widget wm8903_dapm_widgets[] = {
+SND_SOC_DAPM_INPUT("IN1L"),
+SND_SOC_DAPM_INPUT("IN1R"),
+SND_SOC_DAPM_INPUT("IN2L"),
+SND_SOC_DAPM_INPUT("IN2R"),
+SND_SOC_DAPM_INPUT("IN3L"),
+SND_SOC_DAPM_INPUT("IN3R"),
+
+SND_SOC_DAPM_OUTPUT("HPOUTL"),
+SND_SOC_DAPM_OUTPUT("HPOUTR"),
+SND_SOC_DAPM_OUTPUT("LINEOUTL"),
+SND_SOC_DAPM_OUTPUT("LINEOUTR"),
+SND_SOC_DAPM_OUTPUT("LOP"),
+SND_SOC_DAPM_OUTPUT("LON"),
+SND_SOC_DAPM_OUTPUT("ROP"),
+SND_SOC_DAPM_OUTPUT("RON"),
+
+SND_SOC_DAPM_MICBIAS("Mic Bias", WM8903_MIC_BIAS_CONTROL_0, 0, 0),
+
+SND_SOC_DAPM_MUX("Left Input Mux", SND_SOC_NOPM, 0, 0, &linput_mux),
+SND_SOC_DAPM_MUX("Left Input Inverting Mux", SND_SOC_NOPM, 0, 0,
+		 &linput_inv_mux),
+SND_SOC_DAPM_MUX("Left Input Mode Mux", SND_SOC_NOPM, 0, 0, &linput_mode_mux),
+
+SND_SOC_DAPM_MUX("Right Input Mux", SND_SOC_NOPM, 0, 0, &rinput_mux),
+SND_SOC_DAPM_MUX("Right Input Inverting Mux", SND_SOC_NOPM, 0, 0,
+		 &rinput_inv_mux),
+SND_SOC_DAPM_MUX("Right Input Mode Mux", SND_SOC_NOPM, 0, 0, &rinput_mode_mux),
+
+SND_SOC_DAPM_PGA("Left Input PGA", WM8903_POWER_MANAGEMENT_0, 1, 0, NULL, 0),
+SND_SOC_DAPM_PGA("Right Input PGA", WM8903_POWER_MANAGEMENT_0, 0, 0, NULL, 0),
+
+SND_SOC_DAPM_ADC("ADCL", "Left HiFi Capture", WM8903_POWER_MANAGEMENT_6, 1, 0),
+SND_SOC_DAPM_ADC("ADCR", "Right HiFi Capture", WM8903_POWER_MANAGEMENT_6, 0, 0),
+
+SND_SOC_DAPM_DAC("DACL", "Left Playback", WM8903_POWER_MANAGEMENT_6, 3, 0),
+SND_SOC_DAPM_DAC("DACR", "Right Playback", WM8903_POWER_MANAGEMENT_6, 2, 0),
+
+SND_SOC_DAPM_MIXER("Left Output Mixer", WM8903_POWER_MANAGEMENT_1, 1, 0,
+		   left_output_mixer, ARRAY_SIZE(left_output_mixer)),
+SND_SOC_DAPM_MIXER("Right Output Mixer", WM8903_POWER_MANAGEMENT_1, 0, 0,
+		   right_output_mixer, ARRAY_SIZE(right_output_mixer)),
+
+SND_SOC_DAPM_MIXER("Left Speaker Mixer", WM8903_POWER_MANAGEMENT_4, 1, 0,
+		   left_speaker_mixer, ARRAY_SIZE(left_speaker_mixer)),
+SND_SOC_DAPM_MIXER("Right Speaker Mixer", WM8903_POWER_MANAGEMENT_4, 0, 0,
+		   right_speaker_mixer, ARRAY_SIZE(right_speaker_mixer)),
+
+SND_SOC_DAPM_PGA_E("Left Headphone Output PGA", WM8903_POWER_MANAGEMENT_2,
+		   1, 0, NULL, 0, wm8903_output_event,
+		   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+SND_SOC_DAPM_PGA_E("Right Headphone Output PGA", WM8903_POWER_MANAGEMENT_2,
+		   0, 0, NULL, 0, wm8903_output_event,
+		   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+
+SND_SOC_DAPM_PGA_E("Left Line Output PGA", WM8903_POWER_MANAGEMENT_3, 1, 0,
+		   NULL, 0, wm8903_output_event,
+		   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+SND_SOC_DAPM_PGA_E("Right Line Output PGA", WM8903_POWER_MANAGEMENT_3, 0, 0,
+		   NULL, 0, wm8903_output_event,
+		   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+
+SND_SOC_DAPM_PGA("Left Speaker PGA", WM8903_POWER_MANAGEMENT_5, 1, 0,
+		 NULL, 0),
+SND_SOC_DAPM_PGA("Right Speaker PGA", WM8903_POWER_MANAGEMENT_5, 0, 0,
+		 NULL, 0),
+
+};
+
+static const struct snd_soc_dapm_route intercon[] = {
+
+	{ "Left Input Mux", "IN1L", "IN1L" },
+	{ "Left Input Mux", "IN2L", "IN2L" },
+	{ "Left Input Mux", "IN3L", "IN3L" },
+
+	{ "Left Input Inverting Mux", "IN1L", "IN1L" },
+	{ "Left Input Inverting Mux", "IN2L", "IN2L" },
+	{ "Left Input Inverting Mux", "IN3L", "IN3L" },
+
+	{ "Right Input Mux", "IN1R", "IN1R" },
+	{ "Right Input Mux", "IN2R", "IN2R" },
+	{ "Right Input Mux", "IN3R", "IN3R" },
+
+	{ "Right Input Inverting Mux", "IN1R", "IN1R" },
+	{ "Right Input Inverting Mux", "IN2R", "IN2R" },
+	{ "Right Input Inverting Mux", "IN3R", "IN3R" },
+
+	{ "Left Input Mode Mux", "Single-Ended", "Left Input Inverting Mux" },
+	{ "Left Input Mode Mux", "Differential Line",
+	  "Left Input Mux" },
+	{ "Left Input Mode Mux", "Differential Line",
+	  "Left Input Inverting Mux" },
+	{ "Left Input Mode Mux", "Differential Mic",
+	  "Left Input Mux" },
+	{ "Left Input Mode Mux", "Differential Mic",
+	  "Left Input Inverting Mux" },
+
+	{ "Right Input Mode Mux", "Single-Ended",
+	  "Right Input Inverting Mux" },
+	{ "Right Input Mode Mux", "Differential Line",
+	  "Right Input Mux" },
+	{ "Right Input Mode Mux", "Differential Line",
+	  "Right Input Inverting Mux" },
+	{ "Right Input Mode Mux", "Differential Mic",
+	  "Right Input Mux" },
+	{ "Right Input Mode Mux", "Differential Mic",
+	  "Right Input Inverting Mux" },
+
+	{ "Left Input PGA", NULL, "Left Input Mode Mux" },
+	{ "Right Input PGA", NULL, "Right Input Mode Mux" },
+
+	{ "ADCL", NULL, "Left Input PGA" },
+	{ "ADCR", NULL, "Right Input PGA" },
+
+	{ "Left Output Mixer", "Left Bypass Switch", "Left Input PGA" },
+	{ "Left Output Mixer", "Right Bypass Switch", "Right Input PGA" },
+	{ "Left Output Mixer", "DACL Switch", "DACL" },
+	{ "Left Output Mixer", "DACR Switch", "DACR" },
+
+	{ "Right Output Mixer", "Left Bypass Switch", "Left Input PGA" },
+	{ "Right Output Mixer", "Right Bypass Switch", "Right Input PGA" },
+	{ "Right Output Mixer", "DACL Switch", "DACL" },
+	{ "Right Output Mixer", "DACR Switch", "DACR" },
+
+	{ "Left Speaker Mixer", "Left Bypass Switch", "Left Input PGA" },
+	{ "Left Speaker Mixer", "Right Bypass Switch", "Right Input PGA" },
+	{ "Left Speaker Mixer", "DACL Switch", "DACL" },
+	{ "Left Speaker Mixer", "DACR Switch", "DACR" },
+
+	{ "Right Speaker Mixer", "Left Bypass Switch", "Left Input PGA" },
+	{ "Right Speaker Mixer", "Right Bypass Switch", "Right Input PGA" },
+	{ "Right Speaker Mixer", "DACL Switch", "DACL" },
+	{ "Right Speaker Mixer", "DACR Switch", "DACR" },
+
+	{ "Left Line Output PGA", NULL, "Left Output Mixer" },
+	{ "Right Line Output PGA", NULL, "Right Output Mixer" },
+
+	{ "Left Headphone Output PGA", NULL, "Left Output Mixer" },
+	{ "Right Headphone Output PGA", NULL, "Right Output Mixer" },
+
+	{ "Left Speaker PGA", NULL, "Left Speaker Mixer" },
+	{ "Right Speaker PGA", NULL, "Right Speaker Mixer" },
+
+	{ "HPOUTL", NULL, "Left Headphone Output PGA" },
+	{ "HPOUTR", NULL, "Right Headphone Output PGA" },
+
+	{ "LINEOUTL", NULL, "Left Line Output PGA" },
+	{ "LINEOUTR", NULL, "Right Line Output PGA" },
+
+	{ "LOP", NULL, "Left Speaker PGA" },
+	{ "LON", NULL, "Left Speaker PGA" },
+
+	{ "ROP", NULL, "Right Speaker PGA" },
+	{ "RON", NULL, "Right Speaker PGA" },
+};
+
+static int wm8903_add_widgets(struct snd_soc_codec *codec)
+{
+	snd_soc_dapm_new_controls(codec, wm8903_dapm_widgets,
+				  ARRAY_SIZE(wm8903_dapm_widgets));
+
+	snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon));
+
+	snd_soc_dapm_new_widgets(codec);
+
+	return 0;
+}
+
+static int wm8903_set_bias_level(struct snd_soc_codec *codec,
+				 enum snd_soc_bias_level level)
+{
+	struct i2c_client *i2c = codec->control_data;
+	u16 reg, reg2;
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+	case SND_SOC_BIAS_PREPARE:
+		reg = wm8903_read(codec, WM8903_VMID_CONTROL_0);
+		reg &= ~(WM8903_VMID_RES_MASK);
+		reg |= WM8903_VMID_RES_50K;
+		wm8903_write(codec, WM8903_VMID_CONTROL_0, reg);
+		break;
+
+	case SND_SOC_BIAS_STANDBY:
+		if (codec->bias_level == SND_SOC_BIAS_OFF) {
+			wm8903_run_sequence(codec, 0);
+			wm8903_sync_reg_cache(codec, codec->reg_cache);
+
+			/* Enable low impedence charge pump output */
+			reg = wm8903_read(codec,
+					  WM8903_CONTROL_INTERFACE_TEST_1);
+			wm8903_write(codec, WM8903_CONTROL_INTERFACE_TEST_1,
+				     reg | WM8903_TEST_KEY);
+			reg2 = wm8903_read(codec, WM8903_CHARGE_PUMP_TEST_1);
+			wm8903_write(codec, WM8903_CHARGE_PUMP_TEST_1,
+				     reg2 | WM8903_CP_SW_KELVIN_MODE_MASK);
+			wm8903_write(codec, WM8903_CONTROL_INTERFACE_TEST_1,
+				     reg);
+
+			/* By default no bypass paths are enabled so
+			 * enable Class W support.
+			 */
+			dev_dbg(&i2c->dev, "Enabling Class W\n");
+			wm8903_write(codec, WM8903_CLASS_W_0, reg |
+				     WM8903_CP_DYN_FREQ | WM8903_CP_DYN_V);
+		}
+
+		reg = wm8903_read(codec, WM8903_VMID_CONTROL_0);
+		reg &= ~(WM8903_VMID_RES_MASK);
+		reg |= WM8903_VMID_RES_250K;
+		wm8903_write(codec, WM8903_VMID_CONTROL_0, reg);
+		break;
+
+	case SND_SOC_BIAS_OFF:
+		wm8903_run_sequence(codec, 32);
+		break;
+	}
+
+	codec->bias_level = level;
+
+	return 0;
+}
+
+static int wm8903_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+				 int clk_id, unsigned int freq, int dir)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+	struct wm8903_priv *wm8903 = codec->private_data;
+
+	wm8903->sysclk = freq;
+
+	return 0;
+}
+
+static int wm8903_set_dai_fmt(struct snd_soc_dai *codec_dai,
+			      unsigned int fmt)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+	u16 aif1 = wm8903_read(codec, WM8903_AUDIO_INTERFACE_1);
+
+	aif1 &= ~(WM8903_LRCLK_DIR | WM8903_BCLK_DIR | WM8903_AIF_FMT_MASK |
+		  WM8903_AIF_LRCLK_INV | WM8903_AIF_BCLK_INV);
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBS_CFS:
+		break;
+	case SND_SOC_DAIFMT_CBS_CFM:
+		aif1 |= WM8903_LRCLK_DIR;
+		break;
+	case SND_SOC_DAIFMT_CBM_CFM:
+		aif1 |= WM8903_LRCLK_DIR | WM8903_BCLK_DIR;
+		break;
+	case SND_SOC_DAIFMT_CBM_CFS:
+		aif1 |= WM8903_BCLK_DIR;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_DSP_A:
+		aif1 |= 0x3;
+		break;
+	case SND_SOC_DAIFMT_DSP_B:
+		aif1 |= 0x3 | WM8903_AIF_LRCLK_INV;
+		break;
+	case SND_SOC_DAIFMT_I2S:
+		aif1 |= 0x2;
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		aif1 |= 0x1;
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* Clock inversion */
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_DSP_A:
+	case SND_SOC_DAIFMT_DSP_B:
+		/* frame inversion not valid for DSP modes */
+		switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+		case SND_SOC_DAIFMT_NB_NF:
+			break;
+		case SND_SOC_DAIFMT_IB_NF:
+			aif1 |= WM8903_AIF_BCLK_INV;
+			break;
+		default:
+			return -EINVAL;
+		}
+		break;
+	case SND_SOC_DAIFMT_I2S:
+	case SND_SOC_DAIFMT_RIGHT_J:
+	case SND_SOC_DAIFMT_LEFT_J:
+		switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+		case SND_SOC_DAIFMT_NB_NF:
+			break;
+		case SND_SOC_DAIFMT_IB_IF:
+			aif1 |= WM8903_AIF_BCLK_INV | WM8903_AIF_LRCLK_INV;
+			break;
+		case SND_SOC_DAIFMT_IB_NF:
+			aif1 |= WM8903_AIF_BCLK_INV;
+			break;
+		case SND_SOC_DAIFMT_NB_IF:
+			aif1 |= WM8903_AIF_LRCLK_INV;
+			break;
+		default:
+			return -EINVAL;
+		}
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	wm8903_write(codec, WM8903_AUDIO_INTERFACE_1, aif1);
+
+	return 0;
+}
+
+static int wm8903_digital_mute(struct snd_soc_dai *codec_dai, int mute)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+	u16 reg;
+
+	reg = wm8903_read(codec, WM8903_DAC_DIGITAL_1);
+
+	if (mute)
+		reg |= WM8903_DAC_MUTE;
+	else
+		reg &= ~WM8903_DAC_MUTE;
+
+	wm8903_write(codec, WM8903_DAC_DIGITAL_1, reg);
+
+	return 0;
+}
+
+/* Lookup table for CLK_SYS/fs ratio.  256fs or more is recommended
+ * for optimal performance so we list the lower rates first and match
+ * on the last match we find. */
+static struct {
+	int div;
+	int rate;
+	int mode;
+	int mclk_div;
+} clk_sys_ratios[] = {
+	{   64, 0x0, 0x0, 1 },
+	{   68, 0x0, 0x1, 1 },
+	{  125, 0x0, 0x2, 1 },
+	{  128, 0x1, 0x0, 1 },
+	{  136, 0x1, 0x1, 1 },
+	{  192, 0x2, 0x0, 1 },
+	{  204, 0x2, 0x1, 1 },
+
+	{   64, 0x0, 0x0, 2 },
+	{   68, 0x0, 0x1, 2 },
+	{  125, 0x0, 0x2, 2 },
+	{  128, 0x1, 0x0, 2 },
+	{  136, 0x1, 0x1, 2 },
+	{  192, 0x2, 0x0, 2 },
+	{  204, 0x2, 0x1, 2 },
+
+	{  250, 0x2, 0x2, 1 },
+	{  256, 0x3, 0x0, 1 },
+	{  272, 0x3, 0x1, 1 },
+	{  384, 0x4, 0x0, 1 },
+	{  408, 0x4, 0x1, 1 },
+	{  375, 0x4, 0x2, 1 },
+	{  512, 0x5, 0x0, 1 },
+	{  544, 0x5, 0x1, 1 },
+	{  500, 0x5, 0x2, 1 },
+	{  768, 0x6, 0x0, 1 },
+	{  816, 0x6, 0x1, 1 },
+	{  750, 0x6, 0x2, 1 },
+	{ 1024, 0x7, 0x0, 1 },
+	{ 1088, 0x7, 0x1, 1 },
+	{ 1000, 0x7, 0x2, 1 },
+	{ 1408, 0x8, 0x0, 1 },
+	{ 1496, 0x8, 0x1, 1 },
+	{ 1536, 0x9, 0x0, 1 },
+	{ 1632, 0x9, 0x1, 1 },
+	{ 1500, 0x9, 0x2, 1 },
+
+	{  250, 0x2, 0x2, 2 },
+	{  256, 0x3, 0x0, 2 },
+	{  272, 0x3, 0x1, 2 },
+	{  384, 0x4, 0x0, 2 },
+	{  408, 0x4, 0x1, 2 },
+	{  375, 0x4, 0x2, 2 },
+	{  512, 0x5, 0x0, 2 },
+	{  544, 0x5, 0x1, 2 },
+	{  500, 0x5, 0x2, 2 },
+	{  768, 0x6, 0x0, 2 },
+	{  816, 0x6, 0x1, 2 },
+	{  750, 0x6, 0x2, 2 },
+	{ 1024, 0x7, 0x0, 2 },
+	{ 1088, 0x7, 0x1, 2 },
+	{ 1000, 0x7, 0x2, 2 },
+	{ 1408, 0x8, 0x0, 2 },
+	{ 1496, 0x8, 0x1, 2 },
+	{ 1536, 0x9, 0x0, 2 },
+	{ 1632, 0x9, 0x1, 2 },
+	{ 1500, 0x9, 0x2, 2 },
+};
+
+/* CLK_SYS/BCLK ratios - multiplied by 10 due to .5s */
+static struct {
+	int ratio;
+	int div;
+} bclk_divs[] = {
+	{  10,  0 },
+	{  15,  1 },
+	{  20,  2 },
+	{  30,  3 },
+	{  40,  4 },
+	{  50,  5 },
+	{  55,  6 },
+	{  60,  7 },
+	{  80,  8 },
+	{ 100,  9 },
+	{ 110, 10 },
+	{ 120, 11 },
+	{ 160, 12 },
+	{ 200, 13 },
+	{ 220, 14 },
+	{ 240, 15 },
+	{ 250, 16 },
+	{ 300, 17 },
+	{ 320, 18 },
+	{ 440, 19 },
+	{ 480, 20 },
+};
+
+/* Sample rates for DSP */
+static struct {
+	int rate;
+	int value;
+} sample_rates[] = {
+	{  8000,  0 },
+	{ 11025,  1 },
+	{ 12000,  2 },
+	{ 16000,  3 },
+	{ 22050,  4 },
+	{ 24000,  5 },
+	{ 32000,  6 },
+	{ 44100,  7 },
+	{ 48000,  8 },
+	{ 88200,  9 },
+	{ 96000, 10 },
+	{ 0,      0 },
+};
+
+static int wm8903_startup(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_device *socdev = rtd->socdev;
+	struct snd_soc_codec *codec = socdev->codec;
+	struct wm8903_priv *wm8903 = codec->private_data;
+	struct i2c_client *i2c = codec->control_data;
+	struct snd_pcm_runtime *master_runtime;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		wm8903->playback_active++;
+	else
+		wm8903->capture_active++;
+
+	/* The DAI has shared clocks so if we already have a playback or
+	 * capture going then constrain this substream to match it.
+	 */
+	if (wm8903->master_substream) {
+		master_runtime = wm8903->master_substream->runtime;
+
+		dev_dbg(&i2c->dev, "Constraining to %d bits at %dHz\n",
+			master_runtime->sample_bits,
+			master_runtime->rate);
+
+		snd_pcm_hw_constraint_minmax(substream->runtime,
+					     SNDRV_PCM_HW_PARAM_RATE,
+					     master_runtime->rate,
+					     master_runtime->rate);
+
+		snd_pcm_hw_constraint_minmax(substream->runtime,
+					     SNDRV_PCM_HW_PARAM_SAMPLE_BITS,
+					     master_runtime->sample_bits,
+					     master_runtime->sample_bits);
+
+		wm8903->slave_substream = substream;
+	} else
+		wm8903->master_substream = substream;
+
+	return 0;
+}
+
+static void wm8903_shutdown(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_device *socdev = rtd->socdev;
+	struct snd_soc_codec *codec = socdev->codec;
+	struct wm8903_priv *wm8903 = codec->private_data;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		wm8903->playback_active--;
+	else
+		wm8903->capture_active--;
+
+	if (wm8903->master_substream == substream)
+		wm8903->master_substream = wm8903->slave_substream;
+
+	wm8903->slave_substream = NULL;
+}
+
+static int wm8903_hw_params(struct snd_pcm_substream *substream,
+			    struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_device *socdev = rtd->socdev;
+	struct snd_soc_codec *codec = socdev->codec;
+	struct wm8903_priv *wm8903 = codec->private_data;
+	struct i2c_client *i2c = codec->control_data;
+	int fs = params_rate(params);
+	int bclk;
+	int bclk_div;
+	int i;
+	int dsp_config;
+	int clk_config;
+	int best_val;
+	int cur_val;
+	int clk_sys;
+
+	u16 aif1 = wm8903_read(codec, WM8903_AUDIO_INTERFACE_1);
+	u16 aif2 = wm8903_read(codec, WM8903_AUDIO_INTERFACE_2);
+	u16 aif3 = wm8903_read(codec, WM8903_AUDIO_INTERFACE_3);
+	u16 clock0 = wm8903_read(codec, WM8903_CLOCK_RATES_0);
+	u16 clock1 = wm8903_read(codec, WM8903_CLOCK_RATES_1);
+
+	if (substream == wm8903->slave_substream) {
+		dev_dbg(&i2c->dev, "Ignoring hw_params for slave substream\n");
+		return 0;
+	}
+
+	/* Configure sample rate logic for DSP - choose nearest rate */
+	dsp_config = 0;
+	best_val = abs(sample_rates[dsp_config].rate - fs);
+	for (i = 1; i < ARRAY_SIZE(sample_rates); i++) {
+		cur_val = abs(sample_rates[i].rate - fs);
+		if (cur_val <= best_val) {
+			dsp_config = i;
+			best_val = cur_val;
+		}
+	}
+
+	/* Constraints should stop us hitting this but let's make sure */
+	if (wm8903->capture_active)
+		switch (sample_rates[dsp_config].rate) {
+		case 88200:
+		case 96000:
+			dev_err(&i2c->dev, "%dHz unsupported by ADC\n",
+				fs);
+			return -EINVAL;
+
+		default:
+			break;
+		}
+
+	dev_dbg(&i2c->dev, "DSP fs = %dHz\n", sample_rates[dsp_config].rate);
+	clock1 &= ~WM8903_SAMPLE_RATE_MASK;
+	clock1 |= sample_rates[dsp_config].value;
+
+	aif1 &= ~WM8903_AIF_WL_MASK;
+	bclk = 2 * fs;
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S16_LE:
+		bclk *= 16;
+		break;
+	case SNDRV_PCM_FORMAT_S20_3LE:
+		bclk *= 20;
+		aif1 |= 0x4;
+		break;
+	case SNDRV_PCM_FORMAT_S24_LE:
+		bclk *= 24;
+		aif1 |= 0x8;
+		break;
+	case SNDRV_PCM_FORMAT_S32_LE:
+		bclk *= 32;
+		aif1 |= 0xc;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	dev_dbg(&i2c->dev, "MCLK = %dHz, target sample rate = %dHz\n",
+		wm8903->sysclk, fs);
+
+	/* We may not have an MCLK which allows us to generate exactly
+	 * the clock we want, particularly with USB derived inputs, so
+	 * approximate.
+	 */
+	clk_config = 0;
+	best_val = abs((wm8903->sysclk /
+			(clk_sys_ratios[0].mclk_div *
+			 clk_sys_ratios[0].div)) - fs);
+	for (i = 1; i < ARRAY_SIZE(clk_sys_ratios); i++) {
+		cur_val = abs((wm8903->sysclk /
+			       (clk_sys_ratios[i].mclk_div *
+				clk_sys_ratios[i].div)) - fs);
+
+		if (cur_val <= best_val) {
+			clk_config = i;
+			best_val = cur_val;
+		}
+	}
+
+	if (clk_sys_ratios[clk_config].mclk_div == 2) {
+		clock0 |= WM8903_MCLKDIV2;
+		clk_sys = wm8903->sysclk / 2;
+	} else {
+		clock0 &= ~WM8903_MCLKDIV2;
+		clk_sys = wm8903->sysclk;
+	}
+
+	clock1 &= ~(WM8903_CLK_SYS_RATE_MASK |
+		    WM8903_CLK_SYS_MODE_MASK);
+	clock1 |= clk_sys_ratios[clk_config].rate << WM8903_CLK_SYS_RATE_SHIFT;
+	clock1 |= clk_sys_ratios[clk_config].mode << WM8903_CLK_SYS_MODE_SHIFT;
+
+	dev_dbg(&i2c->dev, "CLK_SYS_RATE=%x, CLK_SYS_MODE=%x div=%d\n",
+		clk_sys_ratios[clk_config].rate,
+		clk_sys_ratios[clk_config].mode,
+		clk_sys_ratios[clk_config].div);
+
+	dev_dbg(&i2c->dev, "Actual CLK_SYS = %dHz\n", clk_sys);
+
+	/* We may not get quite the right frequency if using
+	 * approximate clocks so look for the closest match that is
+	 * higher than the target (we need to ensure that there enough
+	 * BCLKs to clock out the samples).
+	 */
+	bclk_div = 0;
+	best_val = ((clk_sys * 10) / bclk_divs[0].ratio) - bclk;
+	i = 1;
+	while (i < ARRAY_SIZE(bclk_divs)) {
+		cur_val = ((clk_sys * 10) / bclk_divs[i].ratio) - bclk;
+		if (cur_val < 0) /* BCLK table is sorted */
+			break;
+		bclk_div = i;
+		best_val = cur_val;
+		i++;
+	}
+
+	aif2 &= ~WM8903_BCLK_DIV_MASK;
+	aif3 &= ~WM8903_LRCLK_RATE_MASK;
+
+	dev_dbg(&i2c->dev, "BCLK ratio %d for %dHz - actual BCLK = %dHz\n",
+		bclk_divs[bclk_div].ratio / 10, bclk,
+		(clk_sys * 10) / bclk_divs[bclk_div].ratio);
+
+	aif2 |= bclk_divs[bclk_div].div;
+	aif3 |= bclk / fs;
+
+	wm8903_write(codec, WM8903_CLOCK_RATES_0, clock0);
+	wm8903_write(codec, WM8903_CLOCK_RATES_1, clock1);
+	wm8903_write(codec, WM8903_AUDIO_INTERFACE_1, aif1);
+	wm8903_write(codec, WM8903_AUDIO_INTERFACE_2, aif2);
+	wm8903_write(codec, WM8903_AUDIO_INTERFACE_3, aif3);
+
+	return 0;
+}
+
+#define WM8903_PLAYBACK_RATES (SNDRV_PCM_RATE_8000 |\
+			       SNDRV_PCM_RATE_11025 |	\
+			       SNDRV_PCM_RATE_16000 |	\
+			       SNDRV_PCM_RATE_22050 |	\
+			       SNDRV_PCM_RATE_32000 |	\
+			       SNDRV_PCM_RATE_44100 |	\
+			       SNDRV_PCM_RATE_48000 |	\
+			       SNDRV_PCM_RATE_88200 |	\
+			       SNDRV_PCM_RATE_96000)
+
+#define WM8903_CAPTURE_RATES (SNDRV_PCM_RATE_8000 |\
+			      SNDRV_PCM_RATE_11025 |	\
+			      SNDRV_PCM_RATE_16000 |	\
+			      SNDRV_PCM_RATE_22050 |	\
+			      SNDRV_PCM_RATE_32000 |	\
+			      SNDRV_PCM_RATE_44100 |	\
+			      SNDRV_PCM_RATE_48000)
+
+#define WM8903_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
+			SNDRV_PCM_FMTBIT_S20_3LE |\
+			SNDRV_PCM_FMTBIT_S24_LE)
+
+struct snd_soc_dai wm8903_dai = {
+	.name = "WM8903",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = WM8903_PLAYBACK_RATES,
+		.formats = WM8903_FORMATS,
+	},
+	.capture = {
+		 .stream_name = "Capture",
+		 .channels_min = 2,
+		 .channels_max = 2,
+		 .rates = WM8903_CAPTURE_RATES,
+		 .formats = WM8903_FORMATS,
+	 },
+	.ops = {
+		 .startup = wm8903_startup,
+		 .shutdown = wm8903_shutdown,
+		 .hw_params = wm8903_hw_params,
+	},
+	.dai_ops = {
+		 .digital_mute = wm8903_digital_mute,
+		 .set_fmt = wm8903_set_dai_fmt,
+		 .set_sysclk = wm8903_set_dai_sysclk
+	}
+};
+EXPORT_SYMBOL_GPL(wm8903_dai);
+
+static int wm8903_suspend(struct platform_device *pdev, pm_message_t state)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	struct snd_soc_codec *codec = socdev->codec;
+
+	wm8903_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
+	return 0;
+}
+
+static int wm8903_resume(struct platform_device *pdev)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	struct snd_soc_codec *codec = socdev->codec;
+	struct i2c_client *i2c = codec->control_data;
+	int i;
+	u16 *reg_cache = codec->reg_cache;
+	u16 *tmp_cache = kmemdup(codec->reg_cache, sizeof(wm8903_reg_defaults),
+				 GFP_KERNEL);
+
+	/* Bring the codec back up to standby first to minimise pop/clicks */
+	wm8903_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+	wm8903_set_bias_level(codec, codec->suspend_bias_level);
+
+	/* Sync back everything else */
+	if (tmp_cache) {
+		for (i = 2; i < ARRAY_SIZE(wm8903_reg_defaults); i++)
+			if (tmp_cache[i] != reg_cache[i])
+				wm8903_write(codec, i, tmp_cache[i]);
+	} else {
+		dev_err(&i2c->dev, "Failed to allocate temporary cache\n");
+	}
+
+	return 0;
+}
+
+/*
+ * initialise the WM8903 driver
+ * register the mixer and dsp interfaces with the kernel
+ */
+static int wm8903_init(struct snd_soc_device *socdev)
+{
+	struct snd_soc_codec *codec = socdev->codec;
+	struct i2c_client *i2c = codec->control_data;
+	int ret = 0;
+	u16 val;
+
+	val = wm8903_hw_read(codec, WM8903_SW_RESET_AND_ID);
+	if (val != wm8903_reg_defaults[WM8903_SW_RESET_AND_ID]) {
+		dev_err(&i2c->dev,
+			"Device with ID register %x is not a WM8903\n", val);
+		return -ENODEV;
+	}
+
+	codec->name = "WM8903";
+	codec->owner = THIS_MODULE;
+	codec->read = wm8903_read;
+	codec->write = wm8903_write;
+	codec->bias_level = SND_SOC_BIAS_OFF;
+	codec->set_bias_level = wm8903_set_bias_level;
+	codec->dai = &wm8903_dai;
+	codec->num_dai = 1;
+	codec->reg_cache_size = ARRAY_SIZE(wm8903_reg_defaults);
+	codec->reg_cache = kmemdup(wm8903_reg_defaults,
+				   sizeof(wm8903_reg_defaults),
+				   GFP_KERNEL);
+	if (codec->reg_cache == NULL) {
+		dev_err(&i2c->dev, "Failed to allocate register cache\n");
+		return -ENOMEM;
+	}
+
+	val = wm8903_read(codec, WM8903_REVISION_NUMBER);
+	dev_info(&i2c->dev, "WM8903 revision %d\n",
+		 val & WM8903_CHIP_REV_MASK);
+
+	wm8903_reset(codec);
+
+	/* register pcms */
+	ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
+	if (ret < 0) {
+		dev_err(&i2c->dev, "failed to create pcms\n");
+		goto pcm_err;
+	}
+
+	/* SYSCLK is required for pretty much anything */
+	wm8903_write(codec, WM8903_CLOCK_RATES_2, WM8903_CLK_SYS_ENA);
+
+	/* power on device */
+	wm8903_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+	/* Latch volume update bits */
+	val = wm8903_read(codec, WM8903_ADC_DIGITAL_VOLUME_LEFT);
+	val |= WM8903_ADCVU;
+	wm8903_write(codec, WM8903_ADC_DIGITAL_VOLUME_LEFT, val);
+	wm8903_write(codec, WM8903_ADC_DIGITAL_VOLUME_RIGHT, val);
+
+	val = wm8903_read(codec, WM8903_DAC_DIGITAL_VOLUME_LEFT);
+	val |= WM8903_DACVU;
+	wm8903_write(codec, WM8903_DAC_DIGITAL_VOLUME_LEFT, val);
+	wm8903_write(codec, WM8903_DAC_DIGITAL_VOLUME_RIGHT, val);
+
+	val = wm8903_read(codec, WM8903_ANALOGUE_OUT1_LEFT);
+	val |= WM8903_HPOUTVU;
+	wm8903_write(codec, WM8903_ANALOGUE_OUT1_LEFT, val);
+	wm8903_write(codec, WM8903_ANALOGUE_OUT1_RIGHT, val);
+
+	val = wm8903_read(codec, WM8903_ANALOGUE_OUT2_LEFT);
+	val |= WM8903_LINEOUTVU;
+	wm8903_write(codec, WM8903_ANALOGUE_OUT2_LEFT, val);
+	wm8903_write(codec, WM8903_ANALOGUE_OUT2_RIGHT, val);
+
+	val = wm8903_read(codec, WM8903_ANALOGUE_OUT3_LEFT);
+	val |= WM8903_SPKVU;
+	wm8903_write(codec, WM8903_ANALOGUE_OUT3_LEFT, val);
+	wm8903_write(codec, WM8903_ANALOGUE_OUT3_RIGHT, val);
+
+	/* Enable DAC soft mute by default */
+	val = wm8903_read(codec, WM8903_DAC_DIGITAL_1);
+	val |= WM8903_DAC_MUTEMODE;
+	wm8903_write(codec, WM8903_DAC_DIGITAL_1, val);
+
+	wm8903_add_controls(codec);
+	wm8903_add_widgets(codec);
+	ret = snd_soc_register_card(socdev);
+	if (ret < 0) {
+		dev_err(&i2c->dev, "wm8903: failed to register card\n");
+		goto card_err;
+	}
+
+	return ret;
+
+card_err:
+	snd_soc_free_pcms(socdev);
+	snd_soc_dapm_free(socdev);
+pcm_err:
+	kfree(codec->reg_cache);
+	return ret;
+}
+
+static struct snd_soc_device *wm8903_socdev;
+
+static int wm8903_i2c_probe(struct i2c_client *i2c,
+			    const struct i2c_device_id *id)
+{
+	struct snd_soc_device *socdev = wm8903_socdev;
+	struct snd_soc_codec *codec = socdev->codec;
+	int ret;
+
+	i2c_set_clientdata(i2c, codec);
+	codec->control_data = i2c;
+
+	ret = wm8903_init(socdev);
+	if (ret < 0)
+		dev_err(&i2c->dev, "Device initialisation failed\n");
+
+	return ret;
+}
+
+static int wm8903_i2c_remove(struct i2c_client *client)
+{
+	struct snd_soc_codec *codec = i2c_get_clientdata(client);
+	kfree(codec->reg_cache);
+	return 0;
+}
+
+/* i2c codec control layer */
+static const struct i2c_device_id wm8903_i2c_id[] = {
+       { "wm8903", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, wm8903_i2c_id);
+
+static struct i2c_driver wm8903_i2c_driver = {
+	.driver = {
+		.name = "WM8903",
+		.owner = THIS_MODULE,
+	},
+	.probe    = wm8903_i2c_probe,
+	.remove   = wm8903_i2c_remove,
+	.id_table = wm8903_i2c_id,
+};
+
+static int wm8903_probe(struct platform_device *pdev)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	struct wm8903_setup_data *setup;
+	struct snd_soc_codec *codec;
+	struct wm8903_priv *wm8903;
+	struct i2c_board_info board_info;
+	struct i2c_adapter *adapter;
+	struct i2c_client *i2c_client;
+	int ret = 0;
+
+	setup = socdev->codec_data;
+
+	if (!setup->i2c_address) {
+		dev_err(&pdev->dev, "No codec address provided\n");
+		return -ENODEV;
+	}
+
+	codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
+	if (codec == NULL)
+		return -ENOMEM;
+
+	wm8903 = kzalloc(sizeof(struct wm8903_priv), GFP_KERNEL);
+	if (wm8903 == NULL) {
+		ret = -ENOMEM;
+		goto err_codec;
+	}
+
+	codec->private_data = wm8903;
+	socdev->codec = codec;
+	mutex_init(&codec->mutex);
+	INIT_LIST_HEAD(&codec->dapm_widgets);
+	INIT_LIST_HEAD(&codec->dapm_paths);
+
+	wm8903_socdev = socdev;
+
+	codec->hw_write = (hw_write_t)i2c_master_send;
+	ret = i2c_add_driver(&wm8903_i2c_driver);
+	if (ret != 0) {
+		dev_err(&pdev->dev, "can't add i2c driver\n");
+		goto err_priv;
+	} else {
+		memset(&board_info, 0, sizeof(board_info));
+		strlcpy(board_info.type, "wm8903", I2C_NAME_SIZE);
+		board_info.addr = setup->i2c_address;
+
+		adapter = i2c_get_adapter(setup->i2c_bus);
+		if (!adapter) {
+			dev_err(&pdev->dev, "Can't get I2C bus %d\n",
+				setup->i2c_bus);
+			ret = -ENODEV;
+			goto err_adapter;
+		}
+
+		i2c_client = i2c_new_device(adapter, &board_info);
+		i2c_put_adapter(adapter);
+		if (i2c_client == NULL) {
+			dev_err(&pdev->dev,
+				"I2C driver registration failed\n");
+			ret = -ENODEV;
+			goto err_adapter;
+		}
+	}
+
+	return ret;
+
+err_adapter:
+	i2c_del_driver(&wm8903_i2c_driver);
+err_priv:
+	kfree(codec->private_data);
+err_codec:
+	kfree(codec);
+	return ret;
+}
+
+/* power down chip */
+static int wm8903_remove(struct platform_device *pdev)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	struct snd_soc_codec *codec = socdev->codec;
+
+	if (codec->control_data)
+		wm8903_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
+	snd_soc_free_pcms(socdev);
+	snd_soc_dapm_free(socdev);
+	i2c_unregister_device(socdev->codec->control_data);
+	i2c_del_driver(&wm8903_i2c_driver);
+	kfree(codec->private_data);
+	kfree(codec);
+
+	return 0;
+}
+
+struct snd_soc_codec_device soc_codec_dev_wm8903 = {
+	.probe = 	wm8903_probe,
+	.remove = 	wm8903_remove,
+	.suspend = 	wm8903_suspend,
+	.resume =	wm8903_resume,
+};
+EXPORT_SYMBOL_GPL(soc_codec_dev_wm8903);
+
+MODULE_DESCRIPTION("ASoC WM8903 driver");
+MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.cm>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm8903.h b/sound/soc/codecs/wm8903.h
new file mode 100644
index 0000000..cec622f
--- /dev/null
+++ b/sound/soc/codecs/wm8903.h
@@ -0,0 +1,1463 @@
+/*
+ * wm8903.h - WM8903 audio codec interface
+ *
+ * Copyright 2008 Wolfson Microelectronics PLC.
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.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 _WM8903_H
+#define _WM8903_H
+
+#include <linux/i2c.h>
+
+extern struct snd_soc_dai wm8903_dai;
+extern struct snd_soc_codec_device soc_codec_dev_wm8903;
+
+struct wm8903_setup_data {
+	int i2c_bus;
+	int i2c_address;
+};
+
+#define WM8903_MCLK_DIV_2 1
+#define WM8903_CLK_SYS    2
+#define WM8903_BCLK       3
+#define WM8903_LRCLK      4
+
+/*
+ * Register values.
+ */
+#define WM8903_SW_RESET_AND_ID                  0x00
+#define WM8903_REVISION_NUMBER                  0x01
+#define WM8903_BIAS_CONTROL_0                   0x04
+#define WM8903_VMID_CONTROL_0                   0x05
+#define WM8903_MIC_BIAS_CONTROL_0               0x06
+#define WM8903_ANALOGUE_DAC_0                   0x08
+#define WM8903_ANALOGUE_ADC_0                   0x0A
+#define WM8903_POWER_MANAGEMENT_0               0x0C
+#define WM8903_POWER_MANAGEMENT_1               0x0D
+#define WM8903_POWER_MANAGEMENT_2               0x0E
+#define WM8903_POWER_MANAGEMENT_3               0x0F
+#define WM8903_POWER_MANAGEMENT_4               0x10
+#define WM8903_POWER_MANAGEMENT_5               0x11
+#define WM8903_POWER_MANAGEMENT_6               0x12
+#define WM8903_CLOCK_RATES_0                    0x14
+#define WM8903_CLOCK_RATES_1                    0x15
+#define WM8903_CLOCK_RATES_2                    0x16
+#define WM8903_AUDIO_INTERFACE_0                0x18
+#define WM8903_AUDIO_INTERFACE_1                0x19
+#define WM8903_AUDIO_INTERFACE_2                0x1A
+#define WM8903_AUDIO_INTERFACE_3                0x1B
+#define WM8903_DAC_DIGITAL_VOLUME_LEFT          0x1E
+#define WM8903_DAC_DIGITAL_VOLUME_RIGHT         0x1F
+#define WM8903_DAC_DIGITAL_0                    0x20
+#define WM8903_DAC_DIGITAL_1                    0x21
+#define WM8903_ADC_DIGITAL_VOLUME_LEFT          0x24
+#define WM8903_ADC_DIGITAL_VOLUME_RIGHT         0x25
+#define WM8903_ADC_DIGITAL_0                    0x26
+#define WM8903_DIGITAL_MICROPHONE_0             0x27
+#define WM8903_DRC_0                            0x28
+#define WM8903_DRC_1                            0x29
+#define WM8903_DRC_2                            0x2A
+#define WM8903_DRC_3                            0x2B
+#define WM8903_ANALOGUE_LEFT_INPUT_0            0x2C
+#define WM8903_ANALOGUE_RIGHT_INPUT_0           0x2D
+#define WM8903_ANALOGUE_LEFT_INPUT_1            0x2E
+#define WM8903_ANALOGUE_RIGHT_INPUT_1           0x2F
+#define WM8903_ANALOGUE_LEFT_MIX_0              0x32
+#define WM8903_ANALOGUE_RIGHT_MIX_0             0x33
+#define WM8903_ANALOGUE_SPK_MIX_LEFT_0          0x34
+#define WM8903_ANALOGUE_SPK_MIX_LEFT_1          0x35
+#define WM8903_ANALOGUE_SPK_MIX_RIGHT_0         0x36
+#define WM8903_ANALOGUE_SPK_MIX_RIGHT_1         0x37
+#define WM8903_ANALOGUE_OUT1_LEFT               0x39
+#define WM8903_ANALOGUE_OUT1_RIGHT              0x3A
+#define WM8903_ANALOGUE_OUT2_LEFT               0x3B
+#define WM8903_ANALOGUE_OUT2_RIGHT              0x3C
+#define WM8903_ANALOGUE_OUT3_LEFT               0x3E
+#define WM8903_ANALOGUE_OUT3_RIGHT              0x3F
+#define WM8903_ANALOGUE_SPK_OUTPUT_CONTROL_0    0x41
+#define WM8903_DC_SERVO_0                       0x43
+#define WM8903_DC_SERVO_2                       0x45
+#define WM8903_ANALOGUE_HP_0                    0x5A
+#define WM8903_ANALOGUE_LINEOUT_0               0x5E
+#define WM8903_CHARGE_PUMP_0                    0x62
+#define WM8903_CLASS_W_0                        0x68
+#define WM8903_WRITE_SEQUENCER_0                0x6C
+#define WM8903_WRITE_SEQUENCER_1                0x6D
+#define WM8903_WRITE_SEQUENCER_2                0x6E
+#define WM8903_WRITE_SEQUENCER_3                0x6F
+#define WM8903_WRITE_SEQUENCER_4                0x70
+#define WM8903_CONTROL_INTERFACE                0x72
+#define WM8903_GPIO_CONTROL_1                   0x74
+#define WM8903_GPIO_CONTROL_2                   0x75
+#define WM8903_GPIO_CONTROL_3                   0x76
+#define WM8903_GPIO_CONTROL_4                   0x77
+#define WM8903_GPIO_CONTROL_5                   0x78
+#define WM8903_INTERRUPT_STATUS_1               0x79
+#define WM8903_INTERRUPT_STATUS_1_MASK          0x7A
+#define WM8903_INTERRUPT_POLARITY_1             0x7B
+#define WM8903_INTERRUPT_CONTROL                0x7E
+#define WM8903_CONTROL_INTERFACE_TEST_1         0x81
+#define WM8903_CHARGE_PUMP_TEST_1               0x95
+#define WM8903_CLOCK_RATE_TEST_4                0xA4
+#define WM8903_ANALOGUE_OUTPUT_BIAS_0           0xAC
+
+#define WM8903_REGISTER_COUNT                   75
+#define WM8903_MAX_REGISTER                     0xAC
+
+/*
+ * Field Definitions.
+ */
+
+/*
+ * R0 (0x00) - SW Reset and ID
+ */
+#define WM8903_SW_RESET_DEV_ID1_MASK            0xFFFF  /* SW_RESET_DEV_ID1 - [15:0] */
+#define WM8903_SW_RESET_DEV_ID1_SHIFT                0  /* SW_RESET_DEV_ID1 - [15:0] */
+#define WM8903_SW_RESET_DEV_ID1_WIDTH               16  /* SW_RESET_DEV_ID1 - [15:0] */
+
+/*
+ * R1 (0x01) - Revision Number
+ */
+#define WM8903_CHIP_REV_MASK                    0x000F  /* CHIP_REV - [3:0] */
+#define WM8903_CHIP_REV_SHIFT                        0  /* CHIP_REV - [3:0] */
+#define WM8903_CHIP_REV_WIDTH                        4  /* CHIP_REV - [3:0] */
+
+/*
+ * R4 (0x04) - Bias Control 0
+ */
+#define WM8903_POBCTRL                          0x0010  /* POBCTRL */
+#define WM8903_POBCTRL_MASK                     0x0010  /* POBCTRL */
+#define WM8903_POBCTRL_SHIFT                         4  /* POBCTRL */
+#define WM8903_POBCTRL_WIDTH                         1  /* POBCTRL */
+#define WM8903_ISEL_MASK                        0x000C  /* ISEL - [3:2] */
+#define WM8903_ISEL_SHIFT                            2  /* ISEL - [3:2] */
+#define WM8903_ISEL_WIDTH                            2  /* ISEL - [3:2] */
+#define WM8903_STARTUP_BIAS_ENA                 0x0002  /* STARTUP_BIAS_ENA */
+#define WM8903_STARTUP_BIAS_ENA_MASK            0x0002  /* STARTUP_BIAS_ENA */
+#define WM8903_STARTUP_BIAS_ENA_SHIFT                1  /* STARTUP_BIAS_ENA */
+#define WM8903_STARTUP_BIAS_ENA_WIDTH                1  /* STARTUP_BIAS_ENA */
+#define WM8903_BIAS_ENA                         0x0001  /* BIAS_ENA */
+#define WM8903_BIAS_ENA_MASK                    0x0001  /* BIAS_ENA */
+#define WM8903_BIAS_ENA_SHIFT                        0  /* BIAS_ENA */
+#define WM8903_BIAS_ENA_WIDTH                        1  /* BIAS_ENA */
+
+/*
+ * R5 (0x05) - VMID Control 0
+ */
+#define WM8903_VMID_TIE_ENA                     0x0080  /* VMID_TIE_ENA */
+#define WM8903_VMID_TIE_ENA_MASK                0x0080  /* VMID_TIE_ENA */
+#define WM8903_VMID_TIE_ENA_SHIFT                    7  /* VMID_TIE_ENA */
+#define WM8903_VMID_TIE_ENA_WIDTH                    1  /* VMID_TIE_ENA */
+#define WM8903_BUFIO_ENA                        0x0040  /* BUFIO_ENA */
+#define WM8903_BUFIO_ENA_MASK                   0x0040  /* BUFIO_ENA */
+#define WM8903_BUFIO_ENA_SHIFT                       6  /* BUFIO_ENA */
+#define WM8903_BUFIO_ENA_WIDTH                       1  /* BUFIO_ENA */
+#define WM8903_VMID_IO_ENA                      0x0020  /* VMID_IO_ENA */
+#define WM8903_VMID_IO_ENA_MASK                 0x0020  /* VMID_IO_ENA */
+#define WM8903_VMID_IO_ENA_SHIFT                     5  /* VMID_IO_ENA */
+#define WM8903_VMID_IO_ENA_WIDTH                     1  /* VMID_IO_ENA */
+#define WM8903_VMID_SOFT_MASK                   0x0018  /* VMID_SOFT - [4:3] */
+#define WM8903_VMID_SOFT_SHIFT                       3  /* VMID_SOFT - [4:3] */
+#define WM8903_VMID_SOFT_WIDTH                       2  /* VMID_SOFT - [4:3] */
+#define WM8903_VMID_RES_MASK                    0x0006  /* VMID_RES - [2:1] */
+#define WM8903_VMID_RES_SHIFT                        1  /* VMID_RES - [2:1] */
+#define WM8903_VMID_RES_WIDTH                        2  /* VMID_RES - [2:1] */
+#define WM8903_VMID_BUF_ENA                     0x0001  /* VMID_BUF_ENA */
+#define WM8903_VMID_BUF_ENA_MASK                0x0001  /* VMID_BUF_ENA */
+#define WM8903_VMID_BUF_ENA_SHIFT                    0  /* VMID_BUF_ENA */
+#define WM8903_VMID_BUF_ENA_WIDTH                    1  /* VMID_BUF_ENA */
+
+#define WM8903_VMID_RES_50K                          2
+#define WM8903_VMID_RES_250K                         3
+#define WM8903_VMID_RES_5K                           4
+
+/*
+ * R6 (0x06) - Mic Bias Control 0
+ */
+#define WM8903_MICDET_HYST_ENA                  0x0080  /* MICDET_HYST_ENA */
+#define WM8903_MICDET_HYST_ENA_MASK             0x0080  /* MICDET_HYST_ENA */
+#define WM8903_MICDET_HYST_ENA_SHIFT                 7  /* MICDET_HYST_ENA */
+#define WM8903_MICDET_HYST_ENA_WIDTH                 1  /* MICDET_HYST_ENA */
+#define WM8903_MICDET_THR_MASK                  0x0070  /* MICDET_THR - [6:4] */
+#define WM8903_MICDET_THR_SHIFT                      4  /* MICDET_THR - [6:4] */
+#define WM8903_MICDET_THR_WIDTH                      3  /* MICDET_THR - [6:4] */
+#define WM8903_MICSHORT_THR_MASK                0x000C  /* MICSHORT_THR - [3:2] */
+#define WM8903_MICSHORT_THR_SHIFT                    2  /* MICSHORT_THR - [3:2] */
+#define WM8903_MICSHORT_THR_WIDTH                    2  /* MICSHORT_THR - [3:2] */
+#define WM8903_MICDET_ENA                       0x0002  /* MICDET_ENA */
+#define WM8903_MICDET_ENA_MASK                  0x0002  /* MICDET_ENA */
+#define WM8903_MICDET_ENA_SHIFT                      1  /* MICDET_ENA */
+#define WM8903_MICDET_ENA_WIDTH                      1  /* MICDET_ENA */
+#define WM8903_MICBIAS_ENA                      0x0001  /* MICBIAS_ENA */
+#define WM8903_MICBIAS_ENA_MASK                 0x0001  /* MICBIAS_ENA */
+#define WM8903_MICBIAS_ENA_SHIFT                     0  /* MICBIAS_ENA */
+#define WM8903_MICBIAS_ENA_WIDTH                     1  /* MICBIAS_ENA */
+
+/*
+ * R8 (0x08) - Analogue DAC 0
+ */
+#define WM8903_DACBIAS_SEL_MASK                 0x0018  /* DACBIAS_SEL - [4:3] */
+#define WM8903_DACBIAS_SEL_SHIFT                     3  /* DACBIAS_SEL - [4:3] */
+#define WM8903_DACBIAS_SEL_WIDTH                     2  /* DACBIAS_SEL - [4:3] */
+#define WM8903_DACVMID_BIAS_SEL_MASK            0x0006  /* DACVMID_BIAS_SEL - [2:1] */
+#define WM8903_DACVMID_BIAS_SEL_SHIFT                1  /* DACVMID_BIAS_SEL - [2:1] */
+#define WM8903_DACVMID_BIAS_SEL_WIDTH                2  /* DACVMID_BIAS_SEL - [2:1] */
+
+/*
+ * R10 (0x0A) - Analogue ADC 0
+ */
+#define WM8903_ADC_OSR128                       0x0001  /* ADC_OSR128 */
+#define WM8903_ADC_OSR128_MASK                  0x0001  /* ADC_OSR128 */
+#define WM8903_ADC_OSR128_SHIFT                      0  /* ADC_OSR128 */
+#define WM8903_ADC_OSR128_WIDTH                      1  /* ADC_OSR128 */
+
+/*
+ * R12 (0x0C) - Power Management 0
+ */
+#define WM8903_INL_ENA                          0x0002  /* INL_ENA */
+#define WM8903_INL_ENA_MASK                     0x0002  /* INL_ENA */
+#define WM8903_INL_ENA_SHIFT                         1  /* INL_ENA */
+#define WM8903_INL_ENA_WIDTH                         1  /* INL_ENA */
+#define WM8903_INR_ENA                          0x0001  /* INR_ENA */
+#define WM8903_INR_ENA_MASK                     0x0001  /* INR_ENA */
+#define WM8903_INR_ENA_SHIFT                         0  /* INR_ENA */
+#define WM8903_INR_ENA_WIDTH                         1  /* INR_ENA */
+
+/*
+ * R13 (0x0D) - Power Management 1
+ */
+#define WM8903_MIXOUTL_ENA                      0x0002  /* MIXOUTL_ENA */
+#define WM8903_MIXOUTL_ENA_MASK                 0x0002  /* MIXOUTL_ENA */
+#define WM8903_MIXOUTL_ENA_SHIFT                     1  /* MIXOUTL_ENA */
+#define WM8903_MIXOUTL_ENA_WIDTH                     1  /* MIXOUTL_ENA */
+#define WM8903_MIXOUTR_ENA                      0x0001  /* MIXOUTR_ENA */
+#define WM8903_MIXOUTR_ENA_MASK                 0x0001  /* MIXOUTR_ENA */
+#define WM8903_MIXOUTR_ENA_SHIFT                     0  /* MIXOUTR_ENA */
+#define WM8903_MIXOUTR_ENA_WIDTH                     1  /* MIXOUTR_ENA */
+
+/*
+ * R14 (0x0E) - Power Management 2
+ */
+#define WM8903_HPL_PGA_ENA                      0x0002  /* HPL_PGA_ENA */
+#define WM8903_HPL_PGA_ENA_MASK                 0x0002  /* HPL_PGA_ENA */
+#define WM8903_HPL_PGA_ENA_SHIFT                     1  /* HPL_PGA_ENA */
+#define WM8903_HPL_PGA_ENA_WIDTH                     1  /* HPL_PGA_ENA */
+#define WM8903_HPR_PGA_ENA                      0x0001  /* HPR_PGA_ENA */
+#define WM8903_HPR_PGA_ENA_MASK                 0x0001  /* HPR_PGA_ENA */
+#define WM8903_HPR_PGA_ENA_SHIFT                     0  /* HPR_PGA_ENA */
+#define WM8903_HPR_PGA_ENA_WIDTH                     1  /* HPR_PGA_ENA */
+
+/*
+ * R15 (0x0F) - Power Management 3
+ */
+#define WM8903_LINEOUTL_PGA_ENA                 0x0002  /* LINEOUTL_PGA_ENA */
+#define WM8903_LINEOUTL_PGA_ENA_MASK            0x0002  /* LINEOUTL_PGA_ENA */
+#define WM8903_LINEOUTL_PGA_ENA_SHIFT                1  /* LINEOUTL_PGA_ENA */
+#define WM8903_LINEOUTL_PGA_ENA_WIDTH                1  /* LINEOUTL_PGA_ENA */
+#define WM8903_LINEOUTR_PGA_ENA                 0x0001  /* LINEOUTR_PGA_ENA */
+#define WM8903_LINEOUTR_PGA_ENA_MASK            0x0001  /* LINEOUTR_PGA_ENA */
+#define WM8903_LINEOUTR_PGA_ENA_SHIFT                0  /* LINEOUTR_PGA_ENA */
+#define WM8903_LINEOUTR_PGA_ENA_WIDTH                1  /* LINEOUTR_PGA_ENA */
+
+/*
+ * R16 (0x10) - Power Management 4
+ */
+#define WM8903_MIXSPKL_ENA                      0x0002  /* MIXSPKL_ENA */
+#define WM8903_MIXSPKL_ENA_MASK                 0x0002  /* MIXSPKL_ENA */
+#define WM8903_MIXSPKL_ENA_SHIFT                     1  /* MIXSPKL_ENA */
+#define WM8903_MIXSPKL_ENA_WIDTH                     1  /* MIXSPKL_ENA */
+#define WM8903_MIXSPKR_ENA                      0x0001  /* MIXSPKR_ENA */
+#define WM8903_MIXSPKR_ENA_MASK                 0x0001  /* MIXSPKR_ENA */
+#define WM8903_MIXSPKR_ENA_SHIFT                     0  /* MIXSPKR_ENA */
+#define WM8903_MIXSPKR_ENA_WIDTH                     1  /* MIXSPKR_ENA */
+
+/*
+ * R17 (0x11) - Power Management 5
+ */
+#define WM8903_SPKL_ENA                         0x0002  /* SPKL_ENA */
+#define WM8903_SPKL_ENA_MASK                    0x0002  /* SPKL_ENA */
+#define WM8903_SPKL_ENA_SHIFT                        1  /* SPKL_ENA */
+#define WM8903_SPKL_ENA_WIDTH                        1  /* SPKL_ENA */
+#define WM8903_SPKR_ENA                         0x0001  /* SPKR_ENA */
+#define WM8903_SPKR_ENA_MASK                    0x0001  /* SPKR_ENA */
+#define WM8903_SPKR_ENA_SHIFT                        0  /* SPKR_ENA */
+#define WM8903_SPKR_ENA_WIDTH                        1  /* SPKR_ENA */
+
+/*
+ * R18 (0x12) - Power Management 6
+ */
+#define WM8903_DACL_ENA                         0x0008  /* DACL_ENA */
+#define WM8903_DACL_ENA_MASK                    0x0008  /* DACL_ENA */
+#define WM8903_DACL_ENA_SHIFT                        3  /* DACL_ENA */
+#define WM8903_DACL_ENA_WIDTH                        1  /* DACL_ENA */
+#define WM8903_DACR_ENA                         0x0004  /* DACR_ENA */
+#define WM8903_DACR_ENA_MASK                    0x0004  /* DACR_ENA */
+#define WM8903_DACR_ENA_SHIFT                        2  /* DACR_ENA */
+#define WM8903_DACR_ENA_WIDTH                        1  /* DACR_ENA */
+#define WM8903_ADCL_ENA                         0x0002  /* ADCL_ENA */
+#define WM8903_ADCL_ENA_MASK                    0x0002  /* ADCL_ENA */
+#define WM8903_ADCL_ENA_SHIFT                        1  /* ADCL_ENA */
+#define WM8903_ADCL_ENA_WIDTH                        1  /* ADCL_ENA */
+#define WM8903_ADCR_ENA                         0x0001  /* ADCR_ENA */
+#define WM8903_ADCR_ENA_MASK                    0x0001  /* ADCR_ENA */
+#define WM8903_ADCR_ENA_SHIFT                        0  /* ADCR_ENA */
+#define WM8903_ADCR_ENA_WIDTH                        1  /* ADCR_ENA */
+
+/*
+ * R20 (0x14) - Clock Rates 0
+ */
+#define WM8903_MCLKDIV2                         0x0001  /* MCLKDIV2 */
+#define WM8903_MCLKDIV2_MASK                    0x0001  /* MCLKDIV2 */
+#define WM8903_MCLKDIV2_SHIFT                        0  /* MCLKDIV2 */
+#define WM8903_MCLKDIV2_WIDTH                        1  /* MCLKDIV2 */
+
+/*
+ * R21 (0x15) - Clock Rates 1
+ */
+#define WM8903_CLK_SYS_RATE_MASK                0x3C00  /* CLK_SYS_RATE - [13:10] */
+#define WM8903_CLK_SYS_RATE_SHIFT                   10  /* CLK_SYS_RATE - [13:10] */
+#define WM8903_CLK_SYS_RATE_WIDTH                    4  /* CLK_SYS_RATE - [13:10] */
+#define WM8903_CLK_SYS_MODE_MASK                0x0300  /* CLK_SYS_MODE - [9:8] */
+#define WM8903_CLK_SYS_MODE_SHIFT                    8  /* CLK_SYS_MODE - [9:8] */
+#define WM8903_CLK_SYS_MODE_WIDTH                    2  /* CLK_SYS_MODE - [9:8] */
+#define WM8903_SAMPLE_RATE_MASK                 0x000F  /* SAMPLE_RATE - [3:0] */
+#define WM8903_SAMPLE_RATE_SHIFT                     0  /* SAMPLE_RATE - [3:0] */
+#define WM8903_SAMPLE_RATE_WIDTH                     4  /* SAMPLE_RATE - [3:0] */
+
+/*
+ * R22 (0x16) - Clock Rates 2
+ */
+#define WM8903_CLK_SYS_ENA                      0x0004  /* CLK_SYS_ENA */
+#define WM8903_CLK_SYS_ENA_MASK                 0x0004  /* CLK_SYS_ENA */
+#define WM8903_CLK_SYS_ENA_SHIFT                     2  /* CLK_SYS_ENA */
+#define WM8903_CLK_SYS_ENA_WIDTH                     1  /* CLK_SYS_ENA */
+#define WM8903_CLK_DSP_ENA                      0x0002  /* CLK_DSP_ENA */
+#define WM8903_CLK_DSP_ENA_MASK                 0x0002  /* CLK_DSP_ENA */
+#define WM8903_CLK_DSP_ENA_SHIFT                     1  /* CLK_DSP_ENA */
+#define WM8903_CLK_DSP_ENA_WIDTH                     1  /* CLK_DSP_ENA */
+#define WM8903_TO_ENA                           0x0001  /* TO_ENA */
+#define WM8903_TO_ENA_MASK                      0x0001  /* TO_ENA */
+#define WM8903_TO_ENA_SHIFT                          0  /* TO_ENA */
+#define WM8903_TO_ENA_WIDTH                          1  /* TO_ENA */
+
+/*
+ * R24 (0x18) - Audio Interface 0
+ */
+#define WM8903_DACL_DATINV                      0x1000  /* DACL_DATINV */
+#define WM8903_DACL_DATINV_MASK                 0x1000  /* DACL_DATINV */
+#define WM8903_DACL_DATINV_SHIFT                    12  /* DACL_DATINV */
+#define WM8903_DACL_DATINV_WIDTH                     1  /* DACL_DATINV */
+#define WM8903_DACR_DATINV                      0x0800  /* DACR_DATINV */
+#define WM8903_DACR_DATINV_MASK                 0x0800  /* DACR_DATINV */
+#define WM8903_DACR_DATINV_SHIFT                    11  /* DACR_DATINV */
+#define WM8903_DACR_DATINV_WIDTH                     1  /* DACR_DATINV */
+#define WM8903_DAC_BOOST_MASK                   0x0600  /* DAC_BOOST - [10:9] */
+#define WM8903_DAC_BOOST_SHIFT                       9  /* DAC_BOOST - [10:9] */
+#define WM8903_DAC_BOOST_WIDTH                       2  /* DAC_BOOST - [10:9] */
+#define WM8903_LOOPBACK                         0x0100  /* LOOPBACK */
+#define WM8903_LOOPBACK_MASK                    0x0100  /* LOOPBACK */
+#define WM8903_LOOPBACK_SHIFT                        8  /* LOOPBACK */
+#define WM8903_LOOPBACK_WIDTH                        1  /* LOOPBACK */
+#define WM8903_AIFADCL_SRC                      0x0080  /* AIFADCL_SRC */
+#define WM8903_AIFADCL_SRC_MASK                 0x0080  /* AIFADCL_SRC */
+#define WM8903_AIFADCL_SRC_SHIFT                     7  /* AIFADCL_SRC */
+#define WM8903_AIFADCL_SRC_WIDTH                     1  /* AIFADCL_SRC */
+#define WM8903_AIFADCR_SRC                      0x0040  /* AIFADCR_SRC */
+#define WM8903_AIFADCR_SRC_MASK                 0x0040  /* AIFADCR_SRC */
+#define WM8903_AIFADCR_SRC_SHIFT                     6  /* AIFADCR_SRC */
+#define WM8903_AIFADCR_SRC_WIDTH                     1  /* AIFADCR_SRC */
+#define WM8903_AIFDACL_SRC                      0x0020  /* AIFDACL_SRC */
+#define WM8903_AIFDACL_SRC_MASK                 0x0020  /* AIFDACL_SRC */
+#define WM8903_AIFDACL_SRC_SHIFT                     5  /* AIFDACL_SRC */
+#define WM8903_AIFDACL_SRC_WIDTH                     1  /* AIFDACL_SRC */
+#define WM8903_AIFDACR_SRC                      0x0010  /* AIFDACR_SRC */
+#define WM8903_AIFDACR_SRC_MASK                 0x0010  /* AIFDACR_SRC */
+#define WM8903_AIFDACR_SRC_SHIFT                     4  /* AIFDACR_SRC */
+#define WM8903_AIFDACR_SRC_WIDTH                     1  /* AIFDACR_SRC */
+#define WM8903_ADC_COMP                         0x0008  /* ADC_COMP */
+#define WM8903_ADC_COMP_MASK                    0x0008  /* ADC_COMP */
+#define WM8903_ADC_COMP_SHIFT                        3  /* ADC_COMP */
+#define WM8903_ADC_COMP_WIDTH                        1  /* ADC_COMP */
+#define WM8903_ADC_COMPMODE                     0x0004  /* ADC_COMPMODE */
+#define WM8903_ADC_COMPMODE_MASK                0x0004  /* ADC_COMPMODE */
+#define WM8903_ADC_COMPMODE_SHIFT                    2  /* ADC_COMPMODE */
+#define WM8903_ADC_COMPMODE_WIDTH                    1  /* ADC_COMPMODE */
+#define WM8903_DAC_COMP                         0x0002  /* DAC_COMP */
+#define WM8903_DAC_COMP_MASK                    0x0002  /* DAC_COMP */
+#define WM8903_DAC_COMP_SHIFT                        1  /* DAC_COMP */
+#define WM8903_DAC_COMP_WIDTH                        1  /* DAC_COMP */
+#define WM8903_DAC_COMPMODE                     0x0001  /* DAC_COMPMODE */
+#define WM8903_DAC_COMPMODE_MASK                0x0001  /* DAC_COMPMODE */
+#define WM8903_DAC_COMPMODE_SHIFT                    0  /* DAC_COMPMODE */
+#define WM8903_DAC_COMPMODE_WIDTH                    1  /* DAC_COMPMODE */
+
+/*
+ * R25 (0x19) - Audio Interface 1
+ */
+#define WM8903_AIFDAC_TDM                       0x2000  /* AIFDAC_TDM */
+#define WM8903_AIFDAC_TDM_MASK                  0x2000  /* AIFDAC_TDM */
+#define WM8903_AIFDAC_TDM_SHIFT                     13  /* AIFDAC_TDM */
+#define WM8903_AIFDAC_TDM_WIDTH                      1  /* AIFDAC_TDM */
+#define WM8903_AIFDAC_TDM_CHAN                  0x1000  /* AIFDAC_TDM_CHAN */
+#define WM8903_AIFDAC_TDM_CHAN_MASK             0x1000  /* AIFDAC_TDM_CHAN */
+#define WM8903_AIFDAC_TDM_CHAN_SHIFT                12  /* AIFDAC_TDM_CHAN */
+#define WM8903_AIFDAC_TDM_CHAN_WIDTH                 1  /* AIFDAC_TDM_CHAN */
+#define WM8903_AIFADC_TDM                       0x0800  /* AIFADC_TDM */
+#define WM8903_AIFADC_TDM_MASK                  0x0800  /* AIFADC_TDM */
+#define WM8903_AIFADC_TDM_SHIFT                     11  /* AIFADC_TDM */
+#define WM8903_AIFADC_TDM_WIDTH                      1  /* AIFADC_TDM */
+#define WM8903_AIFADC_TDM_CHAN                  0x0400  /* AIFADC_TDM_CHAN */
+#define WM8903_AIFADC_TDM_CHAN_MASK             0x0400  /* AIFADC_TDM_CHAN */
+#define WM8903_AIFADC_TDM_CHAN_SHIFT                10  /* AIFADC_TDM_CHAN */
+#define WM8903_AIFADC_TDM_CHAN_WIDTH                 1  /* AIFADC_TDM_CHAN */
+#define WM8903_LRCLK_DIR                        0x0200  /* LRCLK_DIR */
+#define WM8903_LRCLK_DIR_MASK                   0x0200  /* LRCLK_DIR */
+#define WM8903_LRCLK_DIR_SHIFT                       9  /* LRCLK_DIR */
+#define WM8903_LRCLK_DIR_WIDTH                       1  /* LRCLK_DIR */
+#define WM8903_AIF_BCLK_INV                     0x0080  /* AIF_BCLK_INV */
+#define WM8903_AIF_BCLK_INV_MASK                0x0080  /* AIF_BCLK_INV */
+#define WM8903_AIF_BCLK_INV_SHIFT                    7  /* AIF_BCLK_INV */
+#define WM8903_AIF_BCLK_INV_WIDTH                    1  /* AIF_BCLK_INV */
+#define WM8903_BCLK_DIR                         0x0040  /* BCLK_DIR */
+#define WM8903_BCLK_DIR_MASK                    0x0040  /* BCLK_DIR */
+#define WM8903_BCLK_DIR_SHIFT                        6  /* BCLK_DIR */
+#define WM8903_BCLK_DIR_WIDTH                        1  /* BCLK_DIR */
+#define WM8903_AIF_LRCLK_INV                    0x0010  /* AIF_LRCLK_INV */
+#define WM8903_AIF_LRCLK_INV_MASK               0x0010  /* AIF_LRCLK_INV */
+#define WM8903_AIF_LRCLK_INV_SHIFT                   4  /* AIF_LRCLK_INV */
+#define WM8903_AIF_LRCLK_INV_WIDTH                   1  /* AIF_LRCLK_INV */
+#define WM8903_AIF_WL_MASK                      0x000C  /* AIF_WL - [3:2] */
+#define WM8903_AIF_WL_SHIFT                          2  /* AIF_WL - [3:2] */
+#define WM8903_AIF_WL_WIDTH                          2  /* AIF_WL - [3:2] */
+#define WM8903_AIF_FMT_MASK                     0x0003  /* AIF_FMT - [1:0] */
+#define WM8903_AIF_FMT_SHIFT                         0  /* AIF_FMT - [1:0] */
+#define WM8903_AIF_FMT_WIDTH                         2  /* AIF_FMT - [1:0] */
+
+/*
+ * R26 (0x1A) - Audio Interface 2
+ */
+#define WM8903_BCLK_DIV_MASK                    0x001F  /* BCLK_DIV - [4:0] */
+#define WM8903_BCLK_DIV_SHIFT                        0  /* BCLK_DIV - [4:0] */
+#define WM8903_BCLK_DIV_WIDTH                        5  /* BCLK_DIV - [4:0] */
+
+/*
+ * R27 (0x1B) - Audio Interface 3
+ */
+#define WM8903_LRCLK_RATE_MASK                  0x07FF  /* LRCLK_RATE - [10:0] */
+#define WM8903_LRCLK_RATE_SHIFT                      0  /* LRCLK_RATE - [10:0] */
+#define WM8903_LRCLK_RATE_WIDTH                     11  /* LRCLK_RATE - [10:0] */
+
+/*
+ * R30 (0x1E) - DAC Digital Volume Left
+ */
+#define WM8903_DACVU                            0x0100  /* DACVU */
+#define WM8903_DACVU_MASK                       0x0100  /* DACVU */
+#define WM8903_DACVU_SHIFT                           8  /* DACVU */
+#define WM8903_DACVU_WIDTH                           1  /* DACVU */
+#define WM8903_DACL_VOL_MASK                    0x00FF  /* DACL_VOL - [7:0] */
+#define WM8903_DACL_VOL_SHIFT                        0  /* DACL_VOL - [7:0] */
+#define WM8903_DACL_VOL_WIDTH                        8  /* DACL_VOL - [7:0] */
+
+/*
+ * R31 (0x1F) - DAC Digital Volume Right
+ */
+#define WM8903_DACVU                            0x0100  /* DACVU */
+#define WM8903_DACVU_MASK                       0x0100  /* DACVU */
+#define WM8903_DACVU_SHIFT                           8  /* DACVU */
+#define WM8903_DACVU_WIDTH                           1  /* DACVU */
+#define WM8903_DACR_VOL_MASK                    0x00FF  /* DACR_VOL - [7:0] */
+#define WM8903_DACR_VOL_SHIFT                        0  /* DACR_VOL - [7:0] */
+#define WM8903_DACR_VOL_WIDTH                        8  /* DACR_VOL - [7:0] */
+
+/*
+ * R32 (0x20) - DAC Digital 0
+ */
+#define WM8903_ADCL_DAC_SVOL_MASK               0x0F00  /* ADCL_DAC_SVOL - [11:8] */
+#define WM8903_ADCL_DAC_SVOL_SHIFT                   8  /* ADCL_DAC_SVOL - [11:8] */
+#define WM8903_ADCL_DAC_SVOL_WIDTH                   4  /* ADCL_DAC_SVOL - [11:8] */
+#define WM8903_ADCR_DAC_SVOL_MASK               0x00F0  /* ADCR_DAC_SVOL - [7:4] */
+#define WM8903_ADCR_DAC_SVOL_SHIFT                   4  /* ADCR_DAC_SVOL - [7:4] */
+#define WM8903_ADCR_DAC_SVOL_WIDTH                   4  /* ADCR_DAC_SVOL - [7:4] */
+#define WM8903_ADC_TO_DACL_MASK                 0x000C  /* ADC_TO_DACL - [3:2] */
+#define WM8903_ADC_TO_DACL_SHIFT                     2  /* ADC_TO_DACL - [3:2] */
+#define WM8903_ADC_TO_DACL_WIDTH                     2  /* ADC_TO_DACL - [3:2] */
+#define WM8903_ADC_TO_DACR_MASK                 0x0003  /* ADC_TO_DACR - [1:0] */
+#define WM8903_ADC_TO_DACR_SHIFT                     0  /* ADC_TO_DACR - [1:0] */
+#define WM8903_ADC_TO_DACR_WIDTH                     2  /* ADC_TO_DACR - [1:0] */
+
+/*
+ * R33 (0x21) - DAC Digital 1
+ */
+#define WM8903_DAC_MONO                         0x1000  /* DAC_MONO */
+#define WM8903_DAC_MONO_MASK                    0x1000  /* DAC_MONO */
+#define WM8903_DAC_MONO_SHIFT                       12  /* DAC_MONO */
+#define WM8903_DAC_MONO_WIDTH                        1  /* DAC_MONO */
+#define WM8903_DAC_SB_FILT                      0x0800  /* DAC_SB_FILT */
+#define WM8903_DAC_SB_FILT_MASK                 0x0800  /* DAC_SB_FILT */
+#define WM8903_DAC_SB_FILT_SHIFT                    11  /* DAC_SB_FILT */
+#define WM8903_DAC_SB_FILT_WIDTH                     1  /* DAC_SB_FILT */
+#define WM8903_DAC_MUTERATE                     0x0400  /* DAC_MUTERATE */
+#define WM8903_DAC_MUTERATE_MASK                0x0400  /* DAC_MUTERATE */
+#define WM8903_DAC_MUTERATE_SHIFT                   10  /* DAC_MUTERATE */
+#define WM8903_DAC_MUTERATE_WIDTH                    1  /* DAC_MUTERATE */
+#define WM8903_DAC_MUTEMODE                     0x0200  /* DAC_MUTEMODE */
+#define WM8903_DAC_MUTEMODE_MASK                0x0200  /* DAC_MUTEMODE */
+#define WM8903_DAC_MUTEMODE_SHIFT                    9  /* DAC_MUTEMODE */
+#define WM8903_DAC_MUTEMODE_WIDTH                    1  /* DAC_MUTEMODE */
+#define WM8903_DAC_MUTE                         0x0008  /* DAC_MUTE */
+#define WM8903_DAC_MUTE_MASK                    0x0008  /* DAC_MUTE */
+#define WM8903_DAC_MUTE_SHIFT                        3  /* DAC_MUTE */
+#define WM8903_DAC_MUTE_WIDTH                        1  /* DAC_MUTE */
+#define WM8903_DEEMPH_MASK                      0x0006  /* DEEMPH - [2:1] */
+#define WM8903_DEEMPH_SHIFT                          1  /* DEEMPH - [2:1] */
+#define WM8903_DEEMPH_WIDTH                          2  /* DEEMPH - [2:1] */
+
+/*
+ * R36 (0x24) - ADC Digital Volume Left
+ */
+#define WM8903_ADCVU                            0x0100  /* ADCVU */
+#define WM8903_ADCVU_MASK                       0x0100  /* ADCVU */
+#define WM8903_ADCVU_SHIFT                           8  /* ADCVU */
+#define WM8903_ADCVU_WIDTH                           1  /* ADCVU */
+#define WM8903_ADCL_VOL_MASK                    0x00FF  /* ADCL_VOL - [7:0] */
+#define WM8903_ADCL_VOL_SHIFT                        0  /* ADCL_VOL - [7:0] */
+#define WM8903_ADCL_VOL_WIDTH                        8  /* ADCL_VOL - [7:0] */
+
+/*
+ * R37 (0x25) - ADC Digital Volume Right
+ */
+#define WM8903_ADCVU                            0x0100  /* ADCVU */
+#define WM8903_ADCVU_MASK                       0x0100  /* ADCVU */
+#define WM8903_ADCVU_SHIFT                           8  /* ADCVU */
+#define WM8903_ADCVU_WIDTH                           1  /* ADCVU */
+#define WM8903_ADCR_VOL_MASK                    0x00FF  /* ADCR_VOL - [7:0] */
+#define WM8903_ADCR_VOL_SHIFT                        0  /* ADCR_VOL - [7:0] */
+#define WM8903_ADCR_VOL_WIDTH                        8  /* ADCR_VOL - [7:0] */
+
+/*
+ * R38 (0x26) - ADC Digital 0
+ */
+#define WM8903_ADC_HPF_CUT_MASK                 0x0060  /* ADC_HPF_CUT - [6:5] */
+#define WM8903_ADC_HPF_CUT_SHIFT                     5  /* ADC_HPF_CUT - [6:5] */
+#define WM8903_ADC_HPF_CUT_WIDTH                     2  /* ADC_HPF_CUT - [6:5] */
+#define WM8903_ADC_HPF_ENA                      0x0010  /* ADC_HPF_ENA */
+#define WM8903_ADC_HPF_ENA_MASK                 0x0010  /* ADC_HPF_ENA */
+#define WM8903_ADC_HPF_ENA_SHIFT                     4  /* ADC_HPF_ENA */
+#define WM8903_ADC_HPF_ENA_WIDTH                     1  /* ADC_HPF_ENA */
+#define WM8903_ADCL_DATINV                      0x0002  /* ADCL_DATINV */
+#define WM8903_ADCL_DATINV_MASK                 0x0002  /* ADCL_DATINV */
+#define WM8903_ADCL_DATINV_SHIFT                     1  /* ADCL_DATINV */
+#define WM8903_ADCL_DATINV_WIDTH                     1  /* ADCL_DATINV */
+#define WM8903_ADCR_DATINV                      0x0001  /* ADCR_DATINV */
+#define WM8903_ADCR_DATINV_MASK                 0x0001  /* ADCR_DATINV */
+#define WM8903_ADCR_DATINV_SHIFT                     0  /* ADCR_DATINV */
+#define WM8903_ADCR_DATINV_WIDTH                     1  /* ADCR_DATINV */
+
+/*
+ * R39 (0x27) - Digital Microphone 0
+ */
+#define WM8903_DIGMIC_MODE_SEL                  0x0100  /* DIGMIC_MODE_SEL */
+#define WM8903_DIGMIC_MODE_SEL_MASK             0x0100  /* DIGMIC_MODE_SEL */
+#define WM8903_DIGMIC_MODE_SEL_SHIFT                 8  /* DIGMIC_MODE_SEL */
+#define WM8903_DIGMIC_MODE_SEL_WIDTH                 1  /* DIGMIC_MODE_SEL */
+#define WM8903_DIGMIC_CLK_SEL_L_MASK            0x00C0  /* DIGMIC_CLK_SEL_L - [7:6] */
+#define WM8903_DIGMIC_CLK_SEL_L_SHIFT                6  /* DIGMIC_CLK_SEL_L - [7:6] */
+#define WM8903_DIGMIC_CLK_SEL_L_WIDTH                2  /* DIGMIC_CLK_SEL_L - [7:6] */
+#define WM8903_DIGMIC_CLK_SEL_R_MASK            0x0030  /* DIGMIC_CLK_SEL_R - [5:4] */
+#define WM8903_DIGMIC_CLK_SEL_R_SHIFT                4  /* DIGMIC_CLK_SEL_R - [5:4] */
+#define WM8903_DIGMIC_CLK_SEL_R_WIDTH                2  /* DIGMIC_CLK_SEL_R - [5:4] */
+#define WM8903_DIGMIC_CLK_SEL_RT_MASK           0x000C  /* DIGMIC_CLK_SEL_RT - [3:2] */
+#define WM8903_DIGMIC_CLK_SEL_RT_SHIFT               2  /* DIGMIC_CLK_SEL_RT - [3:2] */
+#define WM8903_DIGMIC_CLK_SEL_RT_WIDTH               2  /* DIGMIC_CLK_SEL_RT - [3:2] */
+#define WM8903_DIGMIC_CLK_SEL_MASK              0x0003  /* DIGMIC_CLK_SEL - [1:0] */
+#define WM8903_DIGMIC_CLK_SEL_SHIFT                  0  /* DIGMIC_CLK_SEL - [1:0] */
+#define WM8903_DIGMIC_CLK_SEL_WIDTH                  2  /* DIGMIC_CLK_SEL - [1:0] */
+
+/*
+ * R40 (0x28) - DRC 0
+ */
+#define WM8903_DRC_ENA                          0x8000  /* DRC_ENA */
+#define WM8903_DRC_ENA_MASK                     0x8000  /* DRC_ENA */
+#define WM8903_DRC_ENA_SHIFT                        15  /* DRC_ENA */
+#define WM8903_DRC_ENA_WIDTH                         1  /* DRC_ENA */
+#define WM8903_DRC_THRESH_HYST_MASK             0x1800  /* DRC_THRESH_HYST - [12:11] */
+#define WM8903_DRC_THRESH_HYST_SHIFT                11  /* DRC_THRESH_HYST - [12:11] */
+#define WM8903_DRC_THRESH_HYST_WIDTH                 2  /* DRC_THRESH_HYST - [12:11] */
+#define WM8903_DRC_STARTUP_GAIN_MASK            0x07C0  /* DRC_STARTUP_GAIN - [10:6] */
+#define WM8903_DRC_STARTUP_GAIN_SHIFT                6  /* DRC_STARTUP_GAIN - [10:6] */
+#define WM8903_DRC_STARTUP_GAIN_WIDTH                5  /* DRC_STARTUP_GAIN - [10:6] */
+#define WM8903_DRC_FF_DELAY                     0x0020  /* DRC_FF_DELAY */
+#define WM8903_DRC_FF_DELAY_MASK                0x0020  /* DRC_FF_DELAY */
+#define WM8903_DRC_FF_DELAY_SHIFT                    5  /* DRC_FF_DELAY */
+#define WM8903_DRC_FF_DELAY_WIDTH                    1  /* DRC_FF_DELAY */
+#define WM8903_DRC_SMOOTH_ENA                   0x0008  /* DRC_SMOOTH_ENA */
+#define WM8903_DRC_SMOOTH_ENA_MASK              0x0008  /* DRC_SMOOTH_ENA */
+#define WM8903_DRC_SMOOTH_ENA_SHIFT                  3  /* DRC_SMOOTH_ENA */
+#define WM8903_DRC_SMOOTH_ENA_WIDTH                  1  /* DRC_SMOOTH_ENA */
+#define WM8903_DRC_QR_ENA                       0x0004  /* DRC_QR_ENA */
+#define WM8903_DRC_QR_ENA_MASK                  0x0004  /* DRC_QR_ENA */
+#define WM8903_DRC_QR_ENA_SHIFT                      2  /* DRC_QR_ENA */
+#define WM8903_DRC_QR_ENA_WIDTH                      1  /* DRC_QR_ENA */
+#define WM8903_DRC_ANTICLIP_ENA                 0x0002  /* DRC_ANTICLIP_ENA */
+#define WM8903_DRC_ANTICLIP_ENA_MASK            0x0002  /* DRC_ANTICLIP_ENA */
+#define WM8903_DRC_ANTICLIP_ENA_SHIFT                1  /* DRC_ANTICLIP_ENA */
+#define WM8903_DRC_ANTICLIP_ENA_WIDTH                1  /* DRC_ANTICLIP_ENA */
+#define WM8903_DRC_HYST_ENA                     0x0001  /* DRC_HYST_ENA */
+#define WM8903_DRC_HYST_ENA_MASK                0x0001  /* DRC_HYST_ENA */
+#define WM8903_DRC_HYST_ENA_SHIFT                    0  /* DRC_HYST_ENA */
+#define WM8903_DRC_HYST_ENA_WIDTH                    1  /* DRC_HYST_ENA */
+
+/*
+ * R41 (0x29) - DRC 1
+ */
+#define WM8903_DRC_ATTACK_RATE_MASK             0xF000  /* DRC_ATTACK_RATE - [15:12] */
+#define WM8903_DRC_ATTACK_RATE_SHIFT                12  /* DRC_ATTACK_RATE - [15:12] */
+#define WM8903_DRC_ATTACK_RATE_WIDTH                 4  /* DRC_ATTACK_RATE - [15:12] */
+#define WM8903_DRC_DECAY_RATE_MASK              0x0F00  /* DRC_DECAY_RATE - [11:8] */
+#define WM8903_DRC_DECAY_RATE_SHIFT                  8  /* DRC_DECAY_RATE - [11:8] */
+#define WM8903_DRC_DECAY_RATE_WIDTH                  4  /* DRC_DECAY_RATE - [11:8] */
+#define WM8903_DRC_THRESH_QR_MASK               0x00C0  /* DRC_THRESH_QR - [7:6] */
+#define WM8903_DRC_THRESH_QR_SHIFT                   6  /* DRC_THRESH_QR - [7:6] */
+#define WM8903_DRC_THRESH_QR_WIDTH                   2  /* DRC_THRESH_QR - [7:6] */
+#define WM8903_DRC_RATE_QR_MASK                 0x0030  /* DRC_RATE_QR - [5:4] */
+#define WM8903_DRC_RATE_QR_SHIFT                     4  /* DRC_RATE_QR - [5:4] */
+#define WM8903_DRC_RATE_QR_WIDTH                     2  /* DRC_RATE_QR - [5:4] */
+#define WM8903_DRC_MINGAIN_MASK                 0x000C  /* DRC_MINGAIN - [3:2] */
+#define WM8903_DRC_MINGAIN_SHIFT                     2  /* DRC_MINGAIN - [3:2] */
+#define WM8903_DRC_MINGAIN_WIDTH                     2  /* DRC_MINGAIN - [3:2] */
+#define WM8903_DRC_MAXGAIN_MASK                 0x0003  /* DRC_MAXGAIN - [1:0] */
+#define WM8903_DRC_MAXGAIN_SHIFT                     0  /* DRC_MAXGAIN - [1:0] */
+#define WM8903_DRC_MAXGAIN_WIDTH                     2  /* DRC_MAXGAIN - [1:0] */
+
+/*
+ * R42 (0x2A) - DRC 2
+ */
+#define WM8903_DRC_R0_SLOPE_COMP_MASK           0x0038  /* DRC_R0_SLOPE_COMP - [5:3] */
+#define WM8903_DRC_R0_SLOPE_COMP_SHIFT               3  /* DRC_R0_SLOPE_COMP - [5:3] */
+#define WM8903_DRC_R0_SLOPE_COMP_WIDTH               3  /* DRC_R0_SLOPE_COMP - [5:3] */
+#define WM8903_DRC_R1_SLOPE_COMP_MASK           0x0007  /* DRC_R1_SLOPE_COMP - [2:0] */
+#define WM8903_DRC_R1_SLOPE_COMP_SHIFT               0  /* DRC_R1_SLOPE_COMP - [2:0] */
+#define WM8903_DRC_R1_SLOPE_COMP_WIDTH               3  /* DRC_R1_SLOPE_COMP - [2:0] */
+
+/*
+ * R43 (0x2B) - DRC 3
+ */
+#define WM8903_DRC_THRESH_COMP_MASK             0x07E0  /* DRC_THRESH_COMP - [10:5] */
+#define WM8903_DRC_THRESH_COMP_SHIFT                 5  /* DRC_THRESH_COMP - [10:5] */
+#define WM8903_DRC_THRESH_COMP_WIDTH                 6  /* DRC_THRESH_COMP - [10:5] */
+#define WM8903_DRC_AMP_COMP_MASK                0x001F  /* DRC_AMP_COMP - [4:0] */
+#define WM8903_DRC_AMP_COMP_SHIFT                    0  /* DRC_AMP_COMP - [4:0] */
+#define WM8903_DRC_AMP_COMP_WIDTH                    5  /* DRC_AMP_COMP - [4:0] */
+
+/*
+ * R44 (0x2C) - Analogue Left Input 0
+ */
+#define WM8903_LINMUTE                          0x0080  /* LINMUTE */
+#define WM8903_LINMUTE_MASK                     0x0080  /* LINMUTE */
+#define WM8903_LINMUTE_SHIFT                         7  /* LINMUTE */
+#define WM8903_LINMUTE_WIDTH                         1  /* LINMUTE */
+#define WM8903_LIN_VOL_MASK                     0x001F  /* LIN_VOL - [4:0] */
+#define WM8903_LIN_VOL_SHIFT                         0  /* LIN_VOL - [4:0] */
+#define WM8903_LIN_VOL_WIDTH                         5  /* LIN_VOL - [4:0] */
+
+/*
+ * R45 (0x2D) - Analogue Right Input 0
+ */
+#define WM8903_RINMUTE                          0x0080  /* RINMUTE */
+#define WM8903_RINMUTE_MASK                     0x0080  /* RINMUTE */
+#define WM8903_RINMUTE_SHIFT                         7  /* RINMUTE */
+#define WM8903_RINMUTE_WIDTH                         1  /* RINMUTE */
+#define WM8903_RIN_VOL_MASK                     0x001F  /* RIN_VOL - [4:0] */
+#define WM8903_RIN_VOL_SHIFT                         0  /* RIN_VOL - [4:0] */
+#define WM8903_RIN_VOL_WIDTH                         5  /* RIN_VOL - [4:0] */
+
+/*
+ * R46 (0x2E) - Analogue Left Input 1
+ */
+#define WM8903_INL_CM_ENA                       0x0040  /* INL_CM_ENA */
+#define WM8903_INL_CM_ENA_MASK                  0x0040  /* INL_CM_ENA */
+#define WM8903_INL_CM_ENA_SHIFT                      6  /* INL_CM_ENA */
+#define WM8903_INL_CM_ENA_WIDTH                      1  /* INL_CM_ENA */
+#define WM8903_L_IP_SEL_N_MASK                  0x0030  /* L_IP_SEL_N - [5:4] */
+#define WM8903_L_IP_SEL_N_SHIFT                      4  /* L_IP_SEL_N - [5:4] */
+#define WM8903_L_IP_SEL_N_WIDTH                      2  /* L_IP_SEL_N - [5:4] */
+#define WM8903_L_IP_SEL_P_MASK                  0x000C  /* L_IP_SEL_P - [3:2] */
+#define WM8903_L_IP_SEL_P_SHIFT                      2  /* L_IP_SEL_P - [3:2] */
+#define WM8903_L_IP_SEL_P_WIDTH                      2  /* L_IP_SEL_P - [3:2] */
+#define WM8903_L_MODE_MASK                      0x0003  /* L_MODE - [1:0] */
+#define WM8903_L_MODE_SHIFT                          0  /* L_MODE - [1:0] */
+#define WM8903_L_MODE_WIDTH                          2  /* L_MODE - [1:0] */
+
+/*
+ * R47 (0x2F) - Analogue Right Input 1
+ */
+#define WM8903_INR_CM_ENA                       0x0040  /* INR_CM_ENA */
+#define WM8903_INR_CM_ENA_MASK                  0x0040  /* INR_CM_ENA */
+#define WM8903_INR_CM_ENA_SHIFT                      6  /* INR_CM_ENA */
+#define WM8903_INR_CM_ENA_WIDTH                      1  /* INR_CM_ENA */
+#define WM8903_R_IP_SEL_N_MASK                  0x0030  /* R_IP_SEL_N - [5:4] */
+#define WM8903_R_IP_SEL_N_SHIFT                      4  /* R_IP_SEL_N - [5:4] */
+#define WM8903_R_IP_SEL_N_WIDTH                      2  /* R_IP_SEL_N - [5:4] */
+#define WM8903_R_IP_SEL_P_MASK                  0x000C  /* R_IP_SEL_P - [3:2] */
+#define WM8903_R_IP_SEL_P_SHIFT                      2  /* R_IP_SEL_P - [3:2] */
+#define WM8903_R_IP_SEL_P_WIDTH                      2  /* R_IP_SEL_P - [3:2] */
+#define WM8903_R_MODE_MASK                      0x0003  /* R_MODE - [1:0] */
+#define WM8903_R_MODE_SHIFT                          0  /* R_MODE - [1:0] */
+#define WM8903_R_MODE_WIDTH                          2  /* R_MODE - [1:0] */
+
+/*
+ * R50 (0x32) - Analogue Left Mix 0
+ */
+#define WM8903_DACL_TO_MIXOUTL                  0x0008  /* DACL_TO_MIXOUTL */
+#define WM8903_DACL_TO_MIXOUTL_MASK             0x0008  /* DACL_TO_MIXOUTL */
+#define WM8903_DACL_TO_MIXOUTL_SHIFT                 3  /* DACL_TO_MIXOUTL */
+#define WM8903_DACL_TO_MIXOUTL_WIDTH                 1  /* DACL_TO_MIXOUTL */
+#define WM8903_DACR_TO_MIXOUTL                  0x0004  /* DACR_TO_MIXOUTL */
+#define WM8903_DACR_TO_MIXOUTL_MASK             0x0004  /* DACR_TO_MIXOUTL */
+#define WM8903_DACR_TO_MIXOUTL_SHIFT                 2  /* DACR_TO_MIXOUTL */
+#define WM8903_DACR_TO_MIXOUTL_WIDTH                 1  /* DACR_TO_MIXOUTL */
+#define WM8903_BYPASSL_TO_MIXOUTL               0x0002  /* BYPASSL_TO_MIXOUTL */
+#define WM8903_BYPASSL_TO_MIXOUTL_MASK          0x0002  /* BYPASSL_TO_MIXOUTL */
+#define WM8903_BYPASSL_TO_MIXOUTL_SHIFT              1  /* BYPASSL_TO_MIXOUTL */
+#define WM8903_BYPASSL_TO_MIXOUTL_WIDTH              1  /* BYPASSL_TO_MIXOUTL */
+#define WM8903_BYPASSR_TO_MIXOUTL               0x0001  /* BYPASSR_TO_MIXOUTL */
+#define WM8903_BYPASSR_TO_MIXOUTL_MASK          0x0001  /* BYPASSR_TO_MIXOUTL */
+#define WM8903_BYPASSR_TO_MIXOUTL_SHIFT              0  /* BYPASSR_TO_MIXOUTL */
+#define WM8903_BYPASSR_TO_MIXOUTL_WIDTH              1  /* BYPASSR_TO_MIXOUTL */
+
+/*
+ * R51 (0x33) - Analogue Right Mix 0
+ */
+#define WM8903_DACL_TO_MIXOUTR                  0x0008  /* DACL_TO_MIXOUTR */
+#define WM8903_DACL_TO_MIXOUTR_MASK             0x0008  /* DACL_TO_MIXOUTR */
+#define WM8903_DACL_TO_MIXOUTR_SHIFT                 3  /* DACL_TO_MIXOUTR */
+#define WM8903_DACL_TO_MIXOUTR_WIDTH                 1  /* DACL_TO_MIXOUTR */
+#define WM8903_DACR_TO_MIXOUTR                  0x0004  /* DACR_TO_MIXOUTR */
+#define WM8903_DACR_TO_MIXOUTR_MASK             0x0004  /* DACR_TO_MIXOUTR */
+#define WM8903_DACR_TO_MIXOUTR_SHIFT                 2  /* DACR_TO_MIXOUTR */
+#define WM8903_DACR_TO_MIXOUTR_WIDTH                 1  /* DACR_TO_MIXOUTR */
+#define WM8903_BYPASSL_TO_MIXOUTR               0x0002  /* BYPASSL_TO_MIXOUTR */
+#define WM8903_BYPASSL_TO_MIXOUTR_MASK          0x0002  /* BYPASSL_TO_MIXOUTR */
+#define WM8903_BYPASSL_TO_MIXOUTR_SHIFT              1  /* BYPASSL_TO_MIXOUTR */
+#define WM8903_BYPASSL_TO_MIXOUTR_WIDTH              1  /* BYPASSL_TO_MIXOUTR */
+#define WM8903_BYPASSR_TO_MIXOUTR               0x0001  /* BYPASSR_TO_MIXOUTR */
+#define WM8903_BYPASSR_TO_MIXOUTR_MASK          0x0001  /* BYPASSR_TO_MIXOUTR */
+#define WM8903_BYPASSR_TO_MIXOUTR_SHIFT              0  /* BYPASSR_TO_MIXOUTR */
+#define WM8903_BYPASSR_TO_MIXOUTR_WIDTH              1  /* BYPASSR_TO_MIXOUTR */
+
+/*
+ * R52 (0x34) - Analogue Spk Mix Left 0
+ */
+#define WM8903_DACL_TO_MIXSPKL                  0x0008  /* DACL_TO_MIXSPKL */
+#define WM8903_DACL_TO_MIXSPKL_MASK             0x0008  /* DACL_TO_MIXSPKL */
+#define WM8903_DACL_TO_MIXSPKL_SHIFT                 3  /* DACL_TO_MIXSPKL */
+#define WM8903_DACL_TO_MIXSPKL_WIDTH                 1  /* DACL_TO_MIXSPKL */
+#define WM8903_DACR_TO_MIXSPKL                  0x0004  /* DACR_TO_MIXSPKL */
+#define WM8903_DACR_TO_MIXSPKL_MASK             0x0004  /* DACR_TO_MIXSPKL */
+#define WM8903_DACR_TO_MIXSPKL_SHIFT                 2  /* DACR_TO_MIXSPKL */
+#define WM8903_DACR_TO_MIXSPKL_WIDTH                 1  /* DACR_TO_MIXSPKL */
+#define WM8903_BYPASSL_TO_MIXSPKL               0x0002  /* BYPASSL_TO_MIXSPKL */
+#define WM8903_BYPASSL_TO_MIXSPKL_MASK          0x0002  /* BYPASSL_TO_MIXSPKL */
+#define WM8903_BYPASSL_TO_MIXSPKL_SHIFT              1  /* BYPASSL_TO_MIXSPKL */
+#define WM8903_BYPASSL_TO_MIXSPKL_WIDTH              1  /* BYPASSL_TO_MIXSPKL */
+#define WM8903_BYPASSR_TO_MIXSPKL               0x0001  /* BYPASSR_TO_MIXSPKL */
+#define WM8903_BYPASSR_TO_MIXSPKL_MASK          0x0001  /* BYPASSR_TO_MIXSPKL */
+#define WM8903_BYPASSR_TO_MIXSPKL_SHIFT              0  /* BYPASSR_TO_MIXSPKL */
+#define WM8903_BYPASSR_TO_MIXSPKL_WIDTH              1  /* BYPASSR_TO_MIXSPKL */
+
+/*
+ * R53 (0x35) - Analogue Spk Mix Left 1
+ */
+#define WM8903_DACL_MIXSPKL_VOL                 0x0008  /* DACL_MIXSPKL_VOL */
+#define WM8903_DACL_MIXSPKL_VOL_MASK            0x0008  /* DACL_MIXSPKL_VOL */
+#define WM8903_DACL_MIXSPKL_VOL_SHIFT                3  /* DACL_MIXSPKL_VOL */
+#define WM8903_DACL_MIXSPKL_VOL_WIDTH                1  /* DACL_MIXSPKL_VOL */
+#define WM8903_DACR_MIXSPKL_VOL                 0x0004  /* DACR_MIXSPKL_VOL */
+#define WM8903_DACR_MIXSPKL_VOL_MASK            0x0004  /* DACR_MIXSPKL_VOL */
+#define WM8903_DACR_MIXSPKL_VOL_SHIFT                2  /* DACR_MIXSPKL_VOL */
+#define WM8903_DACR_MIXSPKL_VOL_WIDTH                1  /* DACR_MIXSPKL_VOL */
+#define WM8903_BYPASSL_MIXSPKL_VOL              0x0002  /* BYPASSL_MIXSPKL_VOL */
+#define WM8903_BYPASSL_MIXSPKL_VOL_MASK         0x0002  /* BYPASSL_MIXSPKL_VOL */
+#define WM8903_BYPASSL_MIXSPKL_VOL_SHIFT             1  /* BYPASSL_MIXSPKL_VOL */
+#define WM8903_BYPASSL_MIXSPKL_VOL_WIDTH             1  /* BYPASSL_MIXSPKL_VOL */
+#define WM8903_BYPASSR_MIXSPKL_VOL              0x0001  /* BYPASSR_MIXSPKL_VOL */
+#define WM8903_BYPASSR_MIXSPKL_VOL_MASK         0x0001  /* BYPASSR_MIXSPKL_VOL */
+#define WM8903_BYPASSR_MIXSPKL_VOL_SHIFT             0  /* BYPASSR_MIXSPKL_VOL */
+#define WM8903_BYPASSR_MIXSPKL_VOL_WIDTH             1  /* BYPASSR_MIXSPKL_VOL */
+
+/*
+ * R54 (0x36) - Analogue Spk Mix Right 0
+ */
+#define WM8903_DACL_TO_MIXSPKR                  0x0008  /* DACL_TO_MIXSPKR */
+#define WM8903_DACL_TO_MIXSPKR_MASK             0x0008  /* DACL_TO_MIXSPKR */
+#define WM8903_DACL_TO_MIXSPKR_SHIFT                 3  /* DACL_TO_MIXSPKR */
+#define WM8903_DACL_TO_MIXSPKR_WIDTH                 1  /* DACL_TO_MIXSPKR */
+#define WM8903_DACR_TO_MIXSPKR                  0x0004  /* DACR_TO_MIXSPKR */
+#define WM8903_DACR_TO_MIXSPKR_MASK             0x0004  /* DACR_TO_MIXSPKR */
+#define WM8903_DACR_TO_MIXSPKR_SHIFT                 2  /* DACR_TO_MIXSPKR */
+#define WM8903_DACR_TO_MIXSPKR_WIDTH                 1  /* DACR_TO_MIXSPKR */
+#define WM8903_BYPASSL_TO_MIXSPKR               0x0002  /* BYPASSL_TO_MIXSPKR */
+#define WM8903_BYPASSL_TO_MIXSPKR_MASK          0x0002  /* BYPASSL_TO_MIXSPKR */
+#define WM8903_BYPASSL_TO_MIXSPKR_SHIFT              1  /* BYPASSL_TO_MIXSPKR */
+#define WM8903_BYPASSL_TO_MIXSPKR_WIDTH              1  /* BYPASSL_TO_MIXSPKR */
+#define WM8903_BYPASSR_TO_MIXSPKR               0x0001  /* BYPASSR_TO_MIXSPKR */
+#define WM8903_BYPASSR_TO_MIXSPKR_MASK          0x0001  /* BYPASSR_TO_MIXSPKR */
+#define WM8903_BYPASSR_TO_MIXSPKR_SHIFT              0  /* BYPASSR_TO_MIXSPKR */
+#define WM8903_BYPASSR_TO_MIXSPKR_WIDTH              1  /* BYPASSR_TO_MIXSPKR */
+
+/*
+ * R55 (0x37) - Analogue Spk Mix Right 1
+ */
+#define WM8903_DACL_MIXSPKR_VOL                 0x0008  /* DACL_MIXSPKR_VOL */
+#define WM8903_DACL_MIXSPKR_VOL_MASK            0x0008  /* DACL_MIXSPKR_VOL */
+#define WM8903_DACL_MIXSPKR_VOL_SHIFT                3  /* DACL_MIXSPKR_VOL */
+#define WM8903_DACL_MIXSPKR_VOL_WIDTH                1  /* DACL_MIXSPKR_VOL */
+#define WM8903_DACR_MIXSPKR_VOL                 0x0004  /* DACR_MIXSPKR_VOL */
+#define WM8903_DACR_MIXSPKR_VOL_MASK            0x0004  /* DACR_MIXSPKR_VOL */
+#define WM8903_DACR_MIXSPKR_VOL_SHIFT                2  /* DACR_MIXSPKR_VOL */
+#define WM8903_DACR_MIXSPKR_VOL_WIDTH                1  /* DACR_MIXSPKR_VOL */
+#define WM8903_BYPASSL_MIXSPKR_VOL              0x0002  /* BYPASSL_MIXSPKR_VOL */
+#define WM8903_BYPASSL_MIXSPKR_VOL_MASK         0x0002  /* BYPASSL_MIXSPKR_VOL */
+#define WM8903_BYPASSL_MIXSPKR_VOL_SHIFT             1  /* BYPASSL_MIXSPKR_VOL */
+#define WM8903_BYPASSL_MIXSPKR_VOL_WIDTH             1  /* BYPASSL_MIXSPKR_VOL */
+#define WM8903_BYPASSR_MIXSPKR_VOL              0x0001  /* BYPASSR_MIXSPKR_VOL */
+#define WM8903_BYPASSR_MIXSPKR_VOL_MASK         0x0001  /* BYPASSR_MIXSPKR_VOL */
+#define WM8903_BYPASSR_MIXSPKR_VOL_SHIFT             0  /* BYPASSR_MIXSPKR_VOL */
+#define WM8903_BYPASSR_MIXSPKR_VOL_WIDTH             1  /* BYPASSR_MIXSPKR_VOL */
+
+/*
+ * R57 (0x39) - Analogue OUT1 Left
+ */
+#define WM8903_HPL_MUTE                         0x0100  /* HPL_MUTE */
+#define WM8903_HPL_MUTE_MASK                    0x0100  /* HPL_MUTE */
+#define WM8903_HPL_MUTE_SHIFT                        8  /* HPL_MUTE */
+#define WM8903_HPL_MUTE_WIDTH                        1  /* HPL_MUTE */
+#define WM8903_HPOUTVU                          0x0080  /* HPOUTVU */
+#define WM8903_HPOUTVU_MASK                     0x0080  /* HPOUTVU */
+#define WM8903_HPOUTVU_SHIFT                         7  /* HPOUTVU */
+#define WM8903_HPOUTVU_WIDTH                         1  /* HPOUTVU */
+#define WM8903_HPOUTLZC                         0x0040  /* HPOUTLZC */
+#define WM8903_HPOUTLZC_MASK                    0x0040  /* HPOUTLZC */
+#define WM8903_HPOUTLZC_SHIFT                        6  /* HPOUTLZC */
+#define WM8903_HPOUTLZC_WIDTH                        1  /* HPOUTLZC */
+#define WM8903_HPOUTL_VOL_MASK                  0x003F  /* HPOUTL_VOL - [5:0] */
+#define WM8903_HPOUTL_VOL_SHIFT                      0  /* HPOUTL_VOL - [5:0] */
+#define WM8903_HPOUTL_VOL_WIDTH                      6  /* HPOUTL_VOL - [5:0] */
+
+/*
+ * R58 (0x3A) - Analogue OUT1 Right
+ */
+#define WM8903_HPR_MUTE                         0x0100  /* HPR_MUTE */
+#define WM8903_HPR_MUTE_MASK                    0x0100  /* HPR_MUTE */
+#define WM8903_HPR_MUTE_SHIFT                        8  /* HPR_MUTE */
+#define WM8903_HPR_MUTE_WIDTH                        1  /* HPR_MUTE */
+#define WM8903_HPOUTVU                          0x0080  /* HPOUTVU */
+#define WM8903_HPOUTVU_MASK                     0x0080  /* HPOUTVU */
+#define WM8903_HPOUTVU_SHIFT                         7  /* HPOUTVU */
+#define WM8903_HPOUTVU_WIDTH                         1  /* HPOUTVU */
+#define WM8903_HPOUTRZC                         0x0040  /* HPOUTRZC */
+#define WM8903_HPOUTRZC_MASK                    0x0040  /* HPOUTRZC */
+#define WM8903_HPOUTRZC_SHIFT                        6  /* HPOUTRZC */
+#define WM8903_HPOUTRZC_WIDTH                        1  /* HPOUTRZC */
+#define WM8903_HPOUTR_VOL_MASK                  0x003F  /* HPOUTR_VOL - [5:0] */
+#define WM8903_HPOUTR_VOL_SHIFT                      0  /* HPOUTR_VOL - [5:0] */
+#define WM8903_HPOUTR_VOL_WIDTH                      6  /* HPOUTR_VOL - [5:0] */
+
+/*
+ * R59 (0x3B) - Analogue OUT2 Left
+ */
+#define WM8903_LINEOUTL_MUTE                    0x0100  /* LINEOUTL_MUTE */
+#define WM8903_LINEOUTL_MUTE_MASK               0x0100  /* LINEOUTL_MUTE */
+#define WM8903_LINEOUTL_MUTE_SHIFT                   8  /* LINEOUTL_MUTE */
+#define WM8903_LINEOUTL_MUTE_WIDTH                   1  /* LINEOUTL_MUTE */
+#define WM8903_LINEOUTVU                        0x0080  /* LINEOUTVU */
+#define WM8903_LINEOUTVU_MASK                   0x0080  /* LINEOUTVU */
+#define WM8903_LINEOUTVU_SHIFT                       7  /* LINEOUTVU */
+#define WM8903_LINEOUTVU_WIDTH                       1  /* LINEOUTVU */
+#define WM8903_LINEOUTLZC                       0x0040  /* LINEOUTLZC */
+#define WM8903_LINEOUTLZC_MASK                  0x0040  /* LINEOUTLZC */
+#define WM8903_LINEOUTLZC_SHIFT                      6  /* LINEOUTLZC */
+#define WM8903_LINEOUTLZC_WIDTH                      1  /* LINEOUTLZC */
+#define WM8903_LINEOUTL_VOL_MASK                0x003F  /* LINEOUTL_VOL - [5:0] */
+#define WM8903_LINEOUTL_VOL_SHIFT                    0  /* LINEOUTL_VOL - [5:0] */
+#define WM8903_LINEOUTL_VOL_WIDTH                    6  /* LINEOUTL_VOL - [5:0] */
+
+/*
+ * R60 (0x3C) - Analogue OUT2 Right
+ */
+#define WM8903_LINEOUTR_MUTE                    0x0100  /* LINEOUTR_MUTE */
+#define WM8903_LINEOUTR_MUTE_MASK               0x0100  /* LINEOUTR_MUTE */
+#define WM8903_LINEOUTR_MUTE_SHIFT                   8  /* LINEOUTR_MUTE */
+#define WM8903_LINEOUTR_MUTE_WIDTH                   1  /* LINEOUTR_MUTE */
+#define WM8903_LINEOUTVU                        0x0080  /* LINEOUTVU */
+#define WM8903_LINEOUTVU_MASK                   0x0080  /* LINEOUTVU */
+#define WM8903_LINEOUTVU_SHIFT                       7  /* LINEOUTVU */
+#define WM8903_LINEOUTVU_WIDTH                       1  /* LINEOUTVU */
+#define WM8903_LINEOUTRZC                       0x0040  /* LINEOUTRZC */
+#define WM8903_LINEOUTRZC_MASK                  0x0040  /* LINEOUTRZC */
+#define WM8903_LINEOUTRZC_SHIFT                      6  /* LINEOUTRZC */
+#define WM8903_LINEOUTRZC_WIDTH                      1  /* LINEOUTRZC */
+#define WM8903_LINEOUTR_VOL_MASK                0x003F  /* LINEOUTR_VOL - [5:0] */
+#define WM8903_LINEOUTR_VOL_SHIFT                    0  /* LINEOUTR_VOL - [5:0] */
+#define WM8903_LINEOUTR_VOL_WIDTH                    6  /* LINEOUTR_VOL - [5:0] */
+
+/*
+ * R62 (0x3E) - Analogue OUT3 Left
+ */
+#define WM8903_SPKL_MUTE                        0x0100  /* SPKL_MUTE */
+#define WM8903_SPKL_MUTE_MASK                   0x0100  /* SPKL_MUTE */
+#define WM8903_SPKL_MUTE_SHIFT                       8  /* SPKL_MUTE */
+#define WM8903_SPKL_MUTE_WIDTH                       1  /* SPKL_MUTE */
+#define WM8903_SPKVU                            0x0080  /* SPKVU */
+#define WM8903_SPKVU_MASK                       0x0080  /* SPKVU */
+#define WM8903_SPKVU_SHIFT                           7  /* SPKVU */
+#define WM8903_SPKVU_WIDTH                           1  /* SPKVU */
+#define WM8903_SPKLZC                           0x0040  /* SPKLZC */
+#define WM8903_SPKLZC_MASK                      0x0040  /* SPKLZC */
+#define WM8903_SPKLZC_SHIFT                          6  /* SPKLZC */
+#define WM8903_SPKLZC_WIDTH                          1  /* SPKLZC */
+#define WM8903_SPKL_VOL_MASK                    0x003F  /* SPKL_VOL - [5:0] */
+#define WM8903_SPKL_VOL_SHIFT                        0  /* SPKL_VOL - [5:0] */
+#define WM8903_SPKL_VOL_WIDTH                        6  /* SPKL_VOL - [5:0] */
+
+/*
+ * R63 (0x3F) - Analogue OUT3 Right
+ */
+#define WM8903_SPKR_MUTE                        0x0100  /* SPKR_MUTE */
+#define WM8903_SPKR_MUTE_MASK                   0x0100  /* SPKR_MUTE */
+#define WM8903_SPKR_MUTE_SHIFT                       8  /* SPKR_MUTE */
+#define WM8903_SPKR_MUTE_WIDTH                       1  /* SPKR_MUTE */
+#define WM8903_SPKVU                            0x0080  /* SPKVU */
+#define WM8903_SPKVU_MASK                       0x0080  /* SPKVU */
+#define WM8903_SPKVU_SHIFT                           7  /* SPKVU */
+#define WM8903_SPKVU_WIDTH                           1  /* SPKVU */
+#define WM8903_SPKRZC                           0x0040  /* SPKRZC */
+#define WM8903_SPKRZC_MASK                      0x0040  /* SPKRZC */
+#define WM8903_SPKRZC_SHIFT                          6  /* SPKRZC */
+#define WM8903_SPKRZC_WIDTH                          1  /* SPKRZC */
+#define WM8903_SPKR_VOL_MASK                    0x003F  /* SPKR_VOL - [5:0] */
+#define WM8903_SPKR_VOL_SHIFT                        0  /* SPKR_VOL - [5:0] */
+#define WM8903_SPKR_VOL_WIDTH                        6  /* SPKR_VOL - [5:0] */
+
+/*
+ * R65 (0x41) - Analogue SPK Output Control 0
+ */
+#define WM8903_SPK_DISCHARGE                    0x0002  /* SPK_DISCHARGE */
+#define WM8903_SPK_DISCHARGE_MASK               0x0002  /* SPK_DISCHARGE */
+#define WM8903_SPK_DISCHARGE_SHIFT                   1  /* SPK_DISCHARGE */
+#define WM8903_SPK_DISCHARGE_WIDTH                   1  /* SPK_DISCHARGE */
+#define WM8903_VROI                             0x0001  /* VROI */
+#define WM8903_VROI_MASK                        0x0001  /* VROI */
+#define WM8903_VROI_SHIFT                            0  /* VROI */
+#define WM8903_VROI_WIDTH                            1  /* VROI */
+
+/*
+ * R67 (0x43) - DC Servo 0
+ */
+#define WM8903_DCS_MASTER_ENA                   0x0010  /* DCS_MASTER_ENA */
+#define WM8903_DCS_MASTER_ENA_MASK              0x0010  /* DCS_MASTER_ENA */
+#define WM8903_DCS_MASTER_ENA_SHIFT                  4  /* DCS_MASTER_ENA */
+#define WM8903_DCS_MASTER_ENA_WIDTH                  1  /* DCS_MASTER_ENA */
+#define WM8903_DCS_ENA_MASK                     0x000F  /* DCS_ENA - [3:0] */
+#define WM8903_DCS_ENA_SHIFT                         0  /* DCS_ENA - [3:0] */
+#define WM8903_DCS_ENA_WIDTH                         4  /* DCS_ENA - [3:0] */
+
+/*
+ * R69 (0x45) - DC Servo 2
+ */
+#define WM8903_DCS_MODE_MASK                    0x0003  /* DCS_MODE - [1:0] */
+#define WM8903_DCS_MODE_SHIFT                        0  /* DCS_MODE - [1:0] */
+#define WM8903_DCS_MODE_WIDTH                        2  /* DCS_MODE - [1:0] */
+
+/*
+ * R90 (0x5A) - Analogue HP 0
+ */
+#define WM8903_HPL_RMV_SHORT                    0x0080  /* HPL_RMV_SHORT */
+#define WM8903_HPL_RMV_SHORT_MASK               0x0080  /* HPL_RMV_SHORT */
+#define WM8903_HPL_RMV_SHORT_SHIFT                   7  /* HPL_RMV_SHORT */
+#define WM8903_HPL_RMV_SHORT_WIDTH                   1  /* HPL_RMV_SHORT */
+#define WM8903_HPL_ENA_OUTP                     0x0040  /* HPL_ENA_OUTP */
+#define WM8903_HPL_ENA_OUTP_MASK                0x0040  /* HPL_ENA_OUTP */
+#define WM8903_HPL_ENA_OUTP_SHIFT                    6  /* HPL_ENA_OUTP */
+#define WM8903_HPL_ENA_OUTP_WIDTH                    1  /* HPL_ENA_OUTP */
+#define WM8903_HPL_ENA_DLY                      0x0020  /* HPL_ENA_DLY */
+#define WM8903_HPL_ENA_DLY_MASK                 0x0020  /* HPL_ENA_DLY */
+#define WM8903_HPL_ENA_DLY_SHIFT                     5  /* HPL_ENA_DLY */
+#define WM8903_HPL_ENA_DLY_WIDTH                     1  /* HPL_ENA_DLY */
+#define WM8903_HPL_ENA                          0x0010  /* HPL_ENA */
+#define WM8903_HPL_ENA_MASK                     0x0010  /* HPL_ENA */
+#define WM8903_HPL_ENA_SHIFT                         4  /* HPL_ENA */
+#define WM8903_HPL_ENA_WIDTH                         1  /* HPL_ENA */
+#define WM8903_HPR_RMV_SHORT                    0x0008  /* HPR_RMV_SHORT */
+#define WM8903_HPR_RMV_SHORT_MASK               0x0008  /* HPR_RMV_SHORT */
+#define WM8903_HPR_RMV_SHORT_SHIFT                   3  /* HPR_RMV_SHORT */
+#define WM8903_HPR_RMV_SHORT_WIDTH                   1  /* HPR_RMV_SHORT */
+#define WM8903_HPR_ENA_OUTP                     0x0004  /* HPR_ENA_OUTP */
+#define WM8903_HPR_ENA_OUTP_MASK                0x0004  /* HPR_ENA_OUTP */
+#define WM8903_HPR_ENA_OUTP_SHIFT                    2  /* HPR_ENA_OUTP */
+#define WM8903_HPR_ENA_OUTP_WIDTH                    1  /* HPR_ENA_OUTP */
+#define WM8903_HPR_ENA_DLY                      0x0002  /* HPR_ENA_DLY */
+#define WM8903_HPR_ENA_DLY_MASK                 0x0002  /* HPR_ENA_DLY */
+#define WM8903_HPR_ENA_DLY_SHIFT                     1  /* HPR_ENA_DLY */
+#define WM8903_HPR_ENA_DLY_WIDTH                     1  /* HPR_ENA_DLY */
+#define WM8903_HPR_ENA                          0x0001  /* HPR_ENA */
+#define WM8903_HPR_ENA_MASK                     0x0001  /* HPR_ENA */
+#define WM8903_HPR_ENA_SHIFT                         0  /* HPR_ENA */
+#define WM8903_HPR_ENA_WIDTH                         1  /* HPR_ENA */
+
+/*
+ * R94 (0x5E) - Analogue Lineout 0
+ */
+#define WM8903_LINEOUTL_RMV_SHORT               0x0080  /* LINEOUTL_RMV_SHORT */
+#define WM8903_LINEOUTL_RMV_SHORT_MASK          0x0080  /* LINEOUTL_RMV_SHORT */
+#define WM8903_LINEOUTL_RMV_SHORT_SHIFT              7  /* LINEOUTL_RMV_SHORT */
+#define WM8903_LINEOUTL_RMV_SHORT_WIDTH              1  /* LINEOUTL_RMV_SHORT */
+#define WM8903_LINEOUTL_ENA_OUTP                0x0040  /* LINEOUTL_ENA_OUTP */
+#define WM8903_LINEOUTL_ENA_OUTP_MASK           0x0040  /* LINEOUTL_ENA_OUTP */
+#define WM8903_LINEOUTL_ENA_OUTP_SHIFT               6  /* LINEOUTL_ENA_OUTP */
+#define WM8903_LINEOUTL_ENA_OUTP_WIDTH               1  /* LINEOUTL_ENA_OUTP */
+#define WM8903_LINEOUTL_ENA_DLY                 0x0020  /* LINEOUTL_ENA_DLY */
+#define WM8903_LINEOUTL_ENA_DLY_MASK            0x0020  /* LINEOUTL_ENA_DLY */
+#define WM8903_LINEOUTL_ENA_DLY_SHIFT                5  /* LINEOUTL_ENA_DLY */
+#define WM8903_LINEOUTL_ENA_DLY_WIDTH                1  /* LINEOUTL_ENA_DLY */
+#define WM8903_LINEOUTL_ENA                     0x0010  /* LINEOUTL_ENA */
+#define WM8903_LINEOUTL_ENA_MASK                0x0010  /* LINEOUTL_ENA */
+#define WM8903_LINEOUTL_ENA_SHIFT                    4  /* LINEOUTL_ENA */
+#define WM8903_LINEOUTL_ENA_WIDTH                    1  /* LINEOUTL_ENA */
+#define WM8903_LINEOUTR_RMV_SHORT               0x0008  /* LINEOUTR_RMV_SHORT */
+#define WM8903_LINEOUTR_RMV_SHORT_MASK          0x0008  /* LINEOUTR_RMV_SHORT */
+#define WM8903_LINEOUTR_RMV_SHORT_SHIFT              3  /* LINEOUTR_RMV_SHORT */
+#define WM8903_LINEOUTR_RMV_SHORT_WIDTH              1  /* LINEOUTR_RMV_SHORT */
+#define WM8903_LINEOUTR_ENA_OUTP                0x0004  /* LINEOUTR_ENA_OUTP */
+#define WM8903_LINEOUTR_ENA_OUTP_MASK           0x0004  /* LINEOUTR_ENA_OUTP */
+#define WM8903_LINEOUTR_ENA_OUTP_SHIFT               2  /* LINEOUTR_ENA_OUTP */
+#define WM8903_LINEOUTR_ENA_OUTP_WIDTH               1  /* LINEOUTR_ENA_OUTP */
+#define WM8903_LINEOUTR_ENA_DLY                 0x0002  /* LINEOUTR_ENA_DLY */
+#define WM8903_LINEOUTR_ENA_DLY_MASK            0x0002  /* LINEOUTR_ENA_DLY */
+#define WM8903_LINEOUTR_ENA_DLY_SHIFT                1  /* LINEOUTR_ENA_DLY */
+#define WM8903_LINEOUTR_ENA_DLY_WIDTH                1  /* LINEOUTR_ENA_DLY */
+#define WM8903_LINEOUTR_ENA                     0x0001  /* LINEOUTR_ENA */
+#define WM8903_LINEOUTR_ENA_MASK                0x0001  /* LINEOUTR_ENA */
+#define WM8903_LINEOUTR_ENA_SHIFT                    0  /* LINEOUTR_ENA */
+#define WM8903_LINEOUTR_ENA_WIDTH                    1  /* LINEOUTR_ENA */
+
+/*
+ * R98 (0x62) - Charge Pump 0
+ */
+#define WM8903_CP_ENA                           0x0001  /* CP_ENA */
+#define WM8903_CP_ENA_MASK                      0x0001  /* CP_ENA */
+#define WM8903_CP_ENA_SHIFT                          0  /* CP_ENA */
+#define WM8903_CP_ENA_WIDTH                          1  /* CP_ENA */
+
+/*
+ * R104 (0x68) - Class W 0
+ */
+#define WM8903_CP_DYN_FREQ                      0x0002  /* CP_DYN_FREQ */
+#define WM8903_CP_DYN_FREQ_MASK                 0x0002  /* CP_DYN_FREQ */
+#define WM8903_CP_DYN_FREQ_SHIFT                     1  /* CP_DYN_FREQ */
+#define WM8903_CP_DYN_FREQ_WIDTH                     1  /* CP_DYN_FREQ */
+#define WM8903_CP_DYN_V                         0x0001  /* CP_DYN_V */
+#define WM8903_CP_DYN_V_MASK                    0x0001  /* CP_DYN_V */
+#define WM8903_CP_DYN_V_SHIFT                        0  /* CP_DYN_V */
+#define WM8903_CP_DYN_V_WIDTH                        1  /* CP_DYN_V */
+
+/*
+ * R108 (0x6C) - Write Sequencer 0
+ */
+#define WM8903_WSEQ_ENA                         0x0100  /* WSEQ_ENA */
+#define WM8903_WSEQ_ENA_MASK                    0x0100  /* WSEQ_ENA */
+#define WM8903_WSEQ_ENA_SHIFT                        8  /* WSEQ_ENA */
+#define WM8903_WSEQ_ENA_WIDTH                        1  /* WSEQ_ENA */
+#define WM8903_WSEQ_WRITE_INDEX_MASK            0x001F  /* WSEQ_WRITE_INDEX - [4:0] */
+#define WM8903_WSEQ_WRITE_INDEX_SHIFT                0  /* WSEQ_WRITE_INDEX - [4:0] */
+#define WM8903_WSEQ_WRITE_INDEX_WIDTH                5  /* WSEQ_WRITE_INDEX - [4:0] */
+
+/*
+ * R109 (0x6D) - Write Sequencer 1
+ */
+#define WM8903_WSEQ_DATA_WIDTH_MASK             0x7000  /* WSEQ_DATA_WIDTH - [14:12] */
+#define WM8903_WSEQ_DATA_WIDTH_SHIFT                12  /* WSEQ_DATA_WIDTH - [14:12] */
+#define WM8903_WSEQ_DATA_WIDTH_WIDTH                 3  /* WSEQ_DATA_WIDTH - [14:12] */
+#define WM8903_WSEQ_DATA_START_MASK             0x0F00  /* WSEQ_DATA_START - [11:8] */
+#define WM8903_WSEQ_DATA_START_SHIFT                 8  /* WSEQ_DATA_START - [11:8] */
+#define WM8903_WSEQ_DATA_START_WIDTH                 4  /* WSEQ_DATA_START - [11:8] */
+#define WM8903_WSEQ_ADDR_MASK                   0x00FF  /* WSEQ_ADDR - [7:0] */
+#define WM8903_WSEQ_ADDR_SHIFT                       0  /* WSEQ_ADDR - [7:0] */
+#define WM8903_WSEQ_ADDR_WIDTH                       8  /* WSEQ_ADDR - [7:0] */
+
+/*
+ * R110 (0x6E) - Write Sequencer 2
+ */
+#define WM8903_WSEQ_EOS                         0x4000  /* WSEQ_EOS */
+#define WM8903_WSEQ_EOS_MASK                    0x4000  /* WSEQ_EOS */
+#define WM8903_WSEQ_EOS_SHIFT                       14  /* WSEQ_EOS */
+#define WM8903_WSEQ_EOS_WIDTH                        1  /* WSEQ_EOS */
+#define WM8903_WSEQ_DELAY_MASK                  0x0F00  /* WSEQ_DELAY - [11:8] */
+#define WM8903_WSEQ_DELAY_SHIFT                      8  /* WSEQ_DELAY - [11:8] */
+#define WM8903_WSEQ_DELAY_WIDTH                      4  /* WSEQ_DELAY - [11:8] */
+#define WM8903_WSEQ_DATA_MASK                   0x00FF  /* WSEQ_DATA - [7:0] */
+#define WM8903_WSEQ_DATA_SHIFT                       0  /* WSEQ_DATA - [7:0] */
+#define WM8903_WSEQ_DATA_WIDTH                       8  /* WSEQ_DATA - [7:0] */
+
+/*
+ * R111 (0x6F) - Write Sequencer 3
+ */
+#define WM8903_WSEQ_ABORT                       0x0200  /* WSEQ_ABORT */
+#define WM8903_WSEQ_ABORT_MASK                  0x0200  /* WSEQ_ABORT */
+#define WM8903_WSEQ_ABORT_SHIFT                      9  /* WSEQ_ABORT */
+#define WM8903_WSEQ_ABORT_WIDTH                      1  /* WSEQ_ABORT */
+#define WM8903_WSEQ_START                       0x0100  /* WSEQ_START */
+#define WM8903_WSEQ_START_MASK                  0x0100  /* WSEQ_START */
+#define WM8903_WSEQ_START_SHIFT                      8  /* WSEQ_START */
+#define WM8903_WSEQ_START_WIDTH                      1  /* WSEQ_START */
+#define WM8903_WSEQ_START_INDEX_MASK            0x003F  /* WSEQ_START_INDEX - [5:0] */
+#define WM8903_WSEQ_START_INDEX_SHIFT                0  /* WSEQ_START_INDEX - [5:0] */
+#define WM8903_WSEQ_START_INDEX_WIDTH                6  /* WSEQ_START_INDEX - [5:0] */
+
+/*
+ * R112 (0x70) - Write Sequencer 4
+ */
+#define WM8903_WSEQ_CURRENT_INDEX_MASK          0x03F0  /* WSEQ_CURRENT_INDEX - [9:4] */
+#define WM8903_WSEQ_CURRENT_INDEX_SHIFT              4  /* WSEQ_CURRENT_INDEX - [9:4] */
+#define WM8903_WSEQ_CURRENT_INDEX_WIDTH              6  /* WSEQ_CURRENT_INDEX - [9:4] */
+#define WM8903_WSEQ_BUSY                        0x0001  /* WSEQ_BUSY */
+#define WM8903_WSEQ_BUSY_MASK                   0x0001  /* WSEQ_BUSY */
+#define WM8903_WSEQ_BUSY_SHIFT                       0  /* WSEQ_BUSY */
+#define WM8903_WSEQ_BUSY_WIDTH                       1  /* WSEQ_BUSY */
+
+/*
+ * R114 (0x72) - Control Interface
+ */
+#define WM8903_MASK_WRITE_ENA                   0x0001  /* MASK_WRITE_ENA */
+#define WM8903_MASK_WRITE_ENA_MASK              0x0001  /* MASK_WRITE_ENA */
+#define WM8903_MASK_WRITE_ENA_SHIFT                  0  /* MASK_WRITE_ENA */
+#define WM8903_MASK_WRITE_ENA_WIDTH                  1  /* MASK_WRITE_ENA */
+
+/*
+ * R116 (0x74) - GPIO Control 1
+ */
+#define WM8903_GP1_FN_MASK                      0x1F00  /* GP1_FN - [12:8] */
+#define WM8903_GP1_FN_SHIFT                          8  /* GP1_FN - [12:8] */
+#define WM8903_GP1_FN_WIDTH                          5  /* GP1_FN - [12:8] */
+#define WM8903_GP1_DIR                          0x0080  /* GP1_DIR */
+#define WM8903_GP1_DIR_MASK                     0x0080  /* GP1_DIR */
+#define WM8903_GP1_DIR_SHIFT                         7  /* GP1_DIR */
+#define WM8903_GP1_DIR_WIDTH                         1  /* GP1_DIR */
+#define WM8903_GP1_OP_CFG                       0x0040  /* GP1_OP_CFG */
+#define WM8903_GP1_OP_CFG_MASK                  0x0040  /* GP1_OP_CFG */
+#define WM8903_GP1_OP_CFG_SHIFT                      6  /* GP1_OP_CFG */
+#define WM8903_GP1_OP_CFG_WIDTH                      1  /* GP1_OP_CFG */
+#define WM8903_GP1_IP_CFG                       0x0020  /* GP1_IP_CFG */
+#define WM8903_GP1_IP_CFG_MASK                  0x0020  /* GP1_IP_CFG */
+#define WM8903_GP1_IP_CFG_SHIFT                      5  /* GP1_IP_CFG */
+#define WM8903_GP1_IP_CFG_WIDTH                      1  /* GP1_IP_CFG */
+#define WM8903_GP1_LVL                          0x0010  /* GP1_LVL */
+#define WM8903_GP1_LVL_MASK                     0x0010  /* GP1_LVL */
+#define WM8903_GP1_LVL_SHIFT                         4  /* GP1_LVL */
+#define WM8903_GP1_LVL_WIDTH                         1  /* GP1_LVL */
+#define WM8903_GP1_PD                           0x0008  /* GP1_PD */
+#define WM8903_GP1_PD_MASK                      0x0008  /* GP1_PD */
+#define WM8903_GP1_PD_SHIFT                          3  /* GP1_PD */
+#define WM8903_GP1_PD_WIDTH                          1  /* GP1_PD */
+#define WM8903_GP1_PU                           0x0004  /* GP1_PU */
+#define WM8903_GP1_PU_MASK                      0x0004  /* GP1_PU */
+#define WM8903_GP1_PU_SHIFT                          2  /* GP1_PU */
+#define WM8903_GP1_PU_WIDTH                          1  /* GP1_PU */
+#define WM8903_GP1_INTMODE                      0x0002  /* GP1_INTMODE */
+#define WM8903_GP1_INTMODE_MASK                 0x0002  /* GP1_INTMODE */
+#define WM8903_GP1_INTMODE_SHIFT                     1  /* GP1_INTMODE */
+#define WM8903_GP1_INTMODE_WIDTH                     1  /* GP1_INTMODE */
+#define WM8903_GP1_DB                           0x0001  /* GP1_DB */
+#define WM8903_GP1_DB_MASK                      0x0001  /* GP1_DB */
+#define WM8903_GP1_DB_SHIFT                          0  /* GP1_DB */
+#define WM8903_GP1_DB_WIDTH                          1  /* GP1_DB */
+
+/*
+ * R117 (0x75) - GPIO Control 2
+ */
+#define WM8903_GP2_FN_MASK                      0x1F00  /* GP2_FN - [12:8] */
+#define WM8903_GP2_FN_SHIFT                          8  /* GP2_FN - [12:8] */
+#define WM8903_GP2_FN_WIDTH                          5  /* GP2_FN - [12:8] */
+#define WM8903_GP2_DIR                          0x0080  /* GP2_DIR */
+#define WM8903_GP2_DIR_MASK                     0x0080  /* GP2_DIR */
+#define WM8903_GP2_DIR_SHIFT                         7  /* GP2_DIR */
+#define WM8903_GP2_DIR_WIDTH                         1  /* GP2_DIR */
+#define WM8903_GP2_OP_CFG                       0x0040  /* GP2_OP_CFG */
+#define WM8903_GP2_OP_CFG_MASK                  0x0040  /* GP2_OP_CFG */
+#define WM8903_GP2_OP_CFG_SHIFT                      6  /* GP2_OP_CFG */
+#define WM8903_GP2_OP_CFG_WIDTH                      1  /* GP2_OP_CFG */
+#define WM8903_GP2_IP_CFG                       0x0020  /* GP2_IP_CFG */
+#define WM8903_GP2_IP_CFG_MASK                  0x0020  /* GP2_IP_CFG */
+#define WM8903_GP2_IP_CFG_SHIFT                      5  /* GP2_IP_CFG */
+#define WM8903_GP2_IP_CFG_WIDTH                      1  /* GP2_IP_CFG */
+#define WM8903_GP2_LVL                          0x0010  /* GP2_LVL */
+#define WM8903_GP2_LVL_MASK                     0x0010  /* GP2_LVL */
+#define WM8903_GP2_LVL_SHIFT                         4  /* GP2_LVL */
+#define WM8903_GP2_LVL_WIDTH                         1  /* GP2_LVL */
+#define WM8903_GP2_PD                           0x0008  /* GP2_PD */
+#define WM8903_GP2_PD_MASK                      0x0008  /* GP2_PD */
+#define WM8903_GP2_PD_SHIFT                          3  /* GP2_PD */
+#define WM8903_GP2_PD_WIDTH                          1  /* GP2_PD */
+#define WM8903_GP2_PU                           0x0004  /* GP2_PU */
+#define WM8903_GP2_PU_MASK                      0x0004  /* GP2_PU */
+#define WM8903_GP2_PU_SHIFT                          2  /* GP2_PU */
+#define WM8903_GP2_PU_WIDTH                          1  /* GP2_PU */
+#define WM8903_GP2_INTMODE                      0x0002  /* GP2_INTMODE */
+#define WM8903_GP2_INTMODE_MASK                 0x0002  /* GP2_INTMODE */
+#define WM8903_GP2_INTMODE_SHIFT                     1  /* GP2_INTMODE */
+#define WM8903_GP2_INTMODE_WIDTH                     1  /* GP2_INTMODE */
+#define WM8903_GP2_DB                           0x0001  /* GP2_DB */
+#define WM8903_GP2_DB_MASK                      0x0001  /* GP2_DB */
+#define WM8903_GP2_DB_SHIFT                          0  /* GP2_DB */
+#define WM8903_GP2_DB_WIDTH                          1  /* GP2_DB */
+
+/*
+ * R118 (0x76) - GPIO Control 3
+ */
+#define WM8903_GP3_FN_MASK                      0x1F00  /* GP3_FN - [12:8] */
+#define WM8903_GP3_FN_SHIFT                          8  /* GP3_FN - [12:8] */
+#define WM8903_GP3_FN_WIDTH                          5  /* GP3_FN - [12:8] */
+#define WM8903_GP3_DIR                          0x0080  /* GP3_DIR */
+#define WM8903_GP3_DIR_MASK                     0x0080  /* GP3_DIR */
+#define WM8903_GP3_DIR_SHIFT                         7  /* GP3_DIR */
+#define WM8903_GP3_DIR_WIDTH                         1  /* GP3_DIR */
+#define WM8903_GP3_OP_CFG                       0x0040  /* GP3_OP_CFG */
+#define WM8903_GP3_OP_CFG_MASK                  0x0040  /* GP3_OP_CFG */
+#define WM8903_GP3_OP_CFG_SHIFT                      6  /* GP3_OP_CFG */
+#define WM8903_GP3_OP_CFG_WIDTH                      1  /* GP3_OP_CFG */
+#define WM8903_GP3_IP_CFG                       0x0020  /* GP3_IP_CFG */
+#define WM8903_GP3_IP_CFG_MASK                  0x0020  /* GP3_IP_CFG */
+#define WM8903_GP3_IP_CFG_SHIFT                      5  /* GP3_IP_CFG */
+#define WM8903_GP3_IP_CFG_WIDTH                      1  /* GP3_IP_CFG */
+#define WM8903_GP3_LVL                          0x0010  /* GP3_LVL */
+#define WM8903_GP3_LVL_MASK                     0x0010  /* GP3_LVL */
+#define WM8903_GP3_LVL_SHIFT                         4  /* GP3_LVL */
+#define WM8903_GP3_LVL_WIDTH                         1  /* GP3_LVL */
+#define WM8903_GP3_PD                           0x0008  /* GP3_PD */
+#define WM8903_GP3_PD_MASK                      0x0008  /* GP3_PD */
+#define WM8903_GP3_PD_SHIFT                          3  /* GP3_PD */
+#define WM8903_GP3_PD_WIDTH                          1  /* GP3_PD */
+#define WM8903_GP3_PU                           0x0004  /* GP3_PU */
+#define WM8903_GP3_PU_MASK                      0x0004  /* GP3_PU */
+#define WM8903_GP3_PU_SHIFT                          2  /* GP3_PU */
+#define WM8903_GP3_PU_WIDTH                          1  /* GP3_PU */
+#define WM8903_GP3_INTMODE                      0x0002  /* GP3_INTMODE */
+#define WM8903_GP3_INTMODE_MASK                 0x0002  /* GP3_INTMODE */
+#define WM8903_GP3_INTMODE_SHIFT                     1  /* GP3_INTMODE */
+#define WM8903_GP3_INTMODE_WIDTH                     1  /* GP3_INTMODE */
+#define WM8903_GP3_DB                           0x0001  /* GP3_DB */
+#define WM8903_GP3_DB_MASK                      0x0001  /* GP3_DB */
+#define WM8903_GP3_DB_SHIFT                          0  /* GP3_DB */
+#define WM8903_GP3_DB_WIDTH                          1  /* GP3_DB */
+
+/*
+ * R119 (0x77) - GPIO Control 4
+ */
+#define WM8903_GP4_FN_MASK                      0x1F00  /* GP4_FN - [12:8] */
+#define WM8903_GP4_FN_SHIFT                          8  /* GP4_FN - [12:8] */
+#define WM8903_GP4_FN_WIDTH                          5  /* GP4_FN - [12:8] */
+#define WM8903_GP4_DIR                          0x0080  /* GP4_DIR */
+#define WM8903_GP4_DIR_MASK                     0x0080  /* GP4_DIR */
+#define WM8903_GP4_DIR_SHIFT                         7  /* GP4_DIR */
+#define WM8903_GP4_DIR_WIDTH                         1  /* GP4_DIR */
+#define WM8903_GP4_OP_CFG                       0x0040  /* GP4_OP_CFG */
+#define WM8903_GP4_OP_CFG_MASK                  0x0040  /* GP4_OP_CFG */
+#define WM8903_GP4_OP_CFG_SHIFT                      6  /* GP4_OP_CFG */
+#define WM8903_GP4_OP_CFG_WIDTH                      1  /* GP4_OP_CFG */
+#define WM8903_GP4_IP_CFG                       0x0020  /* GP4_IP_CFG */
+#define WM8903_GP4_IP_CFG_MASK                  0x0020  /* GP4_IP_CFG */
+#define WM8903_GP4_IP_CFG_SHIFT                      5  /* GP4_IP_CFG */
+#define WM8903_GP4_IP_CFG_WIDTH                      1  /* GP4_IP_CFG */
+#define WM8903_GP4_LVL                          0x0010  /* GP4_LVL */
+#define WM8903_GP4_LVL_MASK                     0x0010  /* GP4_LVL */
+#define WM8903_GP4_LVL_SHIFT                         4  /* GP4_LVL */
+#define WM8903_GP4_LVL_WIDTH                         1  /* GP4_LVL */
+#define WM8903_GP4_PD                           0x0008  /* GP4_PD */
+#define WM8903_GP4_PD_MASK                      0x0008  /* GP4_PD */
+#define WM8903_GP4_PD_SHIFT                          3  /* GP4_PD */
+#define WM8903_GP4_PD_WIDTH                          1  /* GP4_PD */
+#define WM8903_GP4_PU                           0x0004  /* GP4_PU */
+#define WM8903_GP4_PU_MASK                      0x0004  /* GP4_PU */
+#define WM8903_GP4_PU_SHIFT                          2  /* GP4_PU */
+#define WM8903_GP4_PU_WIDTH                          1  /* GP4_PU */
+#define WM8903_GP4_INTMODE                      0x0002  /* GP4_INTMODE */
+#define WM8903_GP4_INTMODE_MASK                 0x0002  /* GP4_INTMODE */
+#define WM8903_GP4_INTMODE_SHIFT                     1  /* GP4_INTMODE */
+#define WM8903_GP4_INTMODE_WIDTH                     1  /* GP4_INTMODE */
+#define WM8903_GP4_DB                           0x0001  /* GP4_DB */
+#define WM8903_GP4_DB_MASK                      0x0001  /* GP4_DB */
+#define WM8903_GP4_DB_SHIFT                          0  /* GP4_DB */
+#define WM8903_GP4_DB_WIDTH                          1  /* GP4_DB */
+
+/*
+ * R120 (0x78) - GPIO Control 5
+ */
+#define WM8903_GP5_FN_MASK                      0x1F00  /* GP5_FN - [12:8] */
+#define WM8903_GP5_FN_SHIFT                          8  /* GP5_FN - [12:8] */
+#define WM8903_GP5_FN_WIDTH                          5  /* GP5_FN - [12:8] */
+#define WM8903_GP5_DIR                          0x0080  /* GP5_DIR */
+#define WM8903_GP5_DIR_MASK                     0x0080  /* GP5_DIR */
+#define WM8903_GP5_DIR_SHIFT                         7  /* GP5_DIR */
+#define WM8903_GP5_DIR_WIDTH                         1  /* GP5_DIR */
+#define WM8903_GP5_OP_CFG                       0x0040  /* GP5_OP_CFG */
+#define WM8903_GP5_OP_CFG_MASK                  0x0040  /* GP5_OP_CFG */
+#define WM8903_GP5_OP_CFG_SHIFT                      6  /* GP5_OP_CFG */
+#define WM8903_GP5_OP_CFG_WIDTH                      1  /* GP5_OP_CFG */
+#define WM8903_GP5_IP_CFG                       0x0020  /* GP5_IP_CFG */
+#define WM8903_GP5_IP_CFG_MASK                  0x0020  /* GP5_IP_CFG */
+#define WM8903_GP5_IP_CFG_SHIFT                      5  /* GP5_IP_CFG */
+#define WM8903_GP5_IP_CFG_WIDTH                      1  /* GP5_IP_CFG */
+#define WM8903_GP5_LVL                          0x0010  /* GP5_LVL */
+#define WM8903_GP5_LVL_MASK                     0x0010  /* GP5_LVL */
+#define WM8903_GP5_LVL_SHIFT                         4  /* GP5_LVL */
+#define WM8903_GP5_LVL_WIDTH                         1  /* GP5_LVL */
+#define WM8903_GP5_PD                           0x0008  /* GP5_PD */
+#define WM8903_GP5_PD_MASK                      0x0008  /* GP5_PD */
+#define WM8903_GP5_PD_SHIFT                          3  /* GP5_PD */
+#define WM8903_GP5_PD_WIDTH                          1  /* GP5_PD */
+#define WM8903_GP5_PU                           0x0004  /* GP5_PU */
+#define WM8903_GP5_PU_MASK                      0x0004  /* GP5_PU */
+#define WM8903_GP5_PU_SHIFT                          2  /* GP5_PU */
+#define WM8903_GP5_PU_WIDTH                          1  /* GP5_PU */
+#define WM8903_GP5_INTMODE                      0x0002  /* GP5_INTMODE */
+#define WM8903_GP5_INTMODE_MASK                 0x0002  /* GP5_INTMODE */
+#define WM8903_GP5_INTMODE_SHIFT                     1  /* GP5_INTMODE */
+#define WM8903_GP5_INTMODE_WIDTH                     1  /* GP5_INTMODE */
+#define WM8903_GP5_DB                           0x0001  /* GP5_DB */
+#define WM8903_GP5_DB_MASK                      0x0001  /* GP5_DB */
+#define WM8903_GP5_DB_SHIFT                          0  /* GP5_DB */
+#define WM8903_GP5_DB_WIDTH                          1  /* GP5_DB */
+
+/*
+ * R121 (0x79) - Interrupt Status 1
+ */
+#define WM8903_MICSHRT_EINT                     0x8000  /* MICSHRT_EINT */
+#define WM8903_MICSHRT_EINT_MASK                0x8000  /* MICSHRT_EINT */
+#define WM8903_MICSHRT_EINT_SHIFT                   15  /* MICSHRT_EINT */
+#define WM8903_MICSHRT_EINT_WIDTH                    1  /* MICSHRT_EINT */
+#define WM8903_MICDET_EINT                      0x4000  /* MICDET_EINT */
+#define WM8903_MICDET_EINT_MASK                 0x4000  /* MICDET_EINT */
+#define WM8903_MICDET_EINT_SHIFT                    14  /* MICDET_EINT */
+#define WM8903_MICDET_EINT_WIDTH                     1  /* MICDET_EINT */
+#define WM8903_WSEQ_BUSY_EINT                   0x2000  /* WSEQ_BUSY_EINT */
+#define WM8903_WSEQ_BUSY_EINT_MASK              0x2000  /* WSEQ_BUSY_EINT */
+#define WM8903_WSEQ_BUSY_EINT_SHIFT                 13  /* WSEQ_BUSY_EINT */
+#define WM8903_WSEQ_BUSY_EINT_WIDTH                  1  /* WSEQ_BUSY_EINT */
+#define WM8903_GP5_EINT                         0x0010  /* GP5_EINT */
+#define WM8903_GP5_EINT_MASK                    0x0010  /* GP5_EINT */
+#define WM8903_GP5_EINT_SHIFT                        4  /* GP5_EINT */
+#define WM8903_GP5_EINT_WIDTH                        1  /* GP5_EINT */
+#define WM8903_GP4_EINT                         0x0008  /* GP4_EINT */
+#define WM8903_GP4_EINT_MASK                    0x0008  /* GP4_EINT */
+#define WM8903_GP4_EINT_SHIFT                        3  /* GP4_EINT */
+#define WM8903_GP4_EINT_WIDTH                        1  /* GP4_EINT */
+#define WM8903_GP3_EINT                         0x0004  /* GP3_EINT */
+#define WM8903_GP3_EINT_MASK                    0x0004  /* GP3_EINT */
+#define WM8903_GP3_EINT_SHIFT                        2  /* GP3_EINT */
+#define WM8903_GP3_EINT_WIDTH                        1  /* GP3_EINT */
+#define WM8903_GP2_EINT                         0x0002  /* GP2_EINT */
+#define WM8903_GP2_EINT_MASK                    0x0002  /* GP2_EINT */
+#define WM8903_GP2_EINT_SHIFT                        1  /* GP2_EINT */
+#define WM8903_GP2_EINT_WIDTH                        1  /* GP2_EINT */
+#define WM8903_GP1_EINT                         0x0001  /* GP1_EINT */
+#define WM8903_GP1_EINT_MASK                    0x0001  /* GP1_EINT */
+#define WM8903_GP1_EINT_SHIFT                        0  /* GP1_EINT */
+#define WM8903_GP1_EINT_WIDTH                        1  /* GP1_EINT */
+
+/*
+ * R122 (0x7A) - Interrupt Status 1 Mask
+ */
+#define WM8903_IM_MICSHRT_EINT                  0x8000  /* IM_MICSHRT_EINT */
+#define WM8903_IM_MICSHRT_EINT_MASK             0x8000  /* IM_MICSHRT_EINT */
+#define WM8903_IM_MICSHRT_EINT_SHIFT                15  /* IM_MICSHRT_EINT */
+#define WM8903_IM_MICSHRT_EINT_WIDTH                 1  /* IM_MICSHRT_EINT */
+#define WM8903_IM_MICDET_EINT                   0x4000  /* IM_MICDET_EINT */
+#define WM8903_IM_MICDET_EINT_MASK              0x4000  /* IM_MICDET_EINT */
+#define WM8903_IM_MICDET_EINT_SHIFT                 14  /* IM_MICDET_EINT */
+#define WM8903_IM_MICDET_EINT_WIDTH                  1  /* IM_MICDET_EINT */
+#define WM8903_IM_WSEQ_BUSY_EINT                0x2000  /* IM_WSEQ_BUSY_EINT */
+#define WM8903_IM_WSEQ_BUSY_EINT_MASK           0x2000  /* IM_WSEQ_BUSY_EINT */
+#define WM8903_IM_WSEQ_BUSY_EINT_SHIFT              13  /* IM_WSEQ_BUSY_EINT */
+#define WM8903_IM_WSEQ_BUSY_EINT_WIDTH               1  /* IM_WSEQ_BUSY_EINT */
+#define WM8903_IM_GP5_EINT                      0x0010  /* IM_GP5_EINT */
+#define WM8903_IM_GP5_EINT_MASK                 0x0010  /* IM_GP5_EINT */
+#define WM8903_IM_GP5_EINT_SHIFT                     4  /* IM_GP5_EINT */
+#define WM8903_IM_GP5_EINT_WIDTH                     1  /* IM_GP5_EINT */
+#define WM8903_IM_GP4_EINT                      0x0008  /* IM_GP4_EINT */
+#define WM8903_IM_GP4_EINT_MASK                 0x0008  /* IM_GP4_EINT */
+#define WM8903_IM_GP4_EINT_SHIFT                     3  /* IM_GP4_EINT */
+#define WM8903_IM_GP4_EINT_WIDTH                     1  /* IM_GP4_EINT */
+#define WM8903_IM_GP3_EINT                      0x0004  /* IM_GP3_EINT */
+#define WM8903_IM_GP3_EINT_MASK                 0x0004  /* IM_GP3_EINT */
+#define WM8903_IM_GP3_EINT_SHIFT                     2  /* IM_GP3_EINT */
+#define WM8903_IM_GP3_EINT_WIDTH                     1  /* IM_GP3_EINT */
+#define WM8903_IM_GP2_EINT                      0x0002  /* IM_GP2_EINT */
+#define WM8903_IM_GP2_EINT_MASK                 0x0002  /* IM_GP2_EINT */
+#define WM8903_IM_GP2_EINT_SHIFT                     1  /* IM_GP2_EINT */
+#define WM8903_IM_GP2_EINT_WIDTH                     1  /* IM_GP2_EINT */
+#define WM8903_IM_GP1_EINT                      0x0001  /* IM_GP1_EINT */
+#define WM8903_IM_GP1_EINT_MASK                 0x0001  /* IM_GP1_EINT */
+#define WM8903_IM_GP1_EINT_SHIFT                     0  /* IM_GP1_EINT */
+#define WM8903_IM_GP1_EINT_WIDTH                     1  /* IM_GP1_EINT */
+
+/*
+ * R123 (0x7B) - Interrupt Polarity 1
+ */
+#define WM8903_MICSHRT_INV                      0x8000  /* MICSHRT_INV */
+#define WM8903_MICSHRT_INV_MASK                 0x8000  /* MICSHRT_INV */
+#define WM8903_MICSHRT_INV_SHIFT                    15  /* MICSHRT_INV */
+#define WM8903_MICSHRT_INV_WIDTH                     1  /* MICSHRT_INV */
+#define WM8903_MICDET_INV                       0x4000  /* MICDET_INV */
+#define WM8903_MICDET_INV_MASK                  0x4000  /* MICDET_INV */
+#define WM8903_MICDET_INV_SHIFT                     14  /* MICDET_INV */
+#define WM8903_MICDET_INV_WIDTH                      1  /* MICDET_INV */
+
+/*
+ * R126 (0x7E) - Interrupt Control
+ */
+#define WM8903_IRQ_POL                          0x0001  /* IRQ_POL */
+#define WM8903_IRQ_POL_MASK                     0x0001  /* IRQ_POL */
+#define WM8903_IRQ_POL_SHIFT                         0  /* IRQ_POL */
+#define WM8903_IRQ_POL_WIDTH                         1  /* IRQ_POL */
+
+/*
+ * R129 (0x81) - Control Interface Test 1
+ */
+#define WM8903_USER_KEY                         0x0002  /* USER_KEY */
+#define WM8903_USER_KEY_MASK                    0x0002  /* USER_KEY */
+#define WM8903_USER_KEY_SHIFT                        1  /* USER_KEY */
+#define WM8903_USER_KEY_WIDTH                        1  /* USER_KEY */
+#define WM8903_TEST_KEY                         0x0001  /* TEST_KEY */
+#define WM8903_TEST_KEY_MASK                    0x0001  /* TEST_KEY */
+#define WM8903_TEST_KEY_SHIFT                        0  /* TEST_KEY */
+#define WM8903_TEST_KEY_WIDTH                        1  /* TEST_KEY */
+
+/*
+ * R149 (0x95) - Charge Pump Test 1
+ */
+#define WM8903_CP_SW_KELVIN_MODE_MASK           0x0006  /* CP_SW_KELVIN_MODE - [2:1] */
+#define WM8903_CP_SW_KELVIN_MODE_SHIFT               1  /* CP_SW_KELVIN_MODE - [2:1] */
+#define WM8903_CP_SW_KELVIN_MODE_WIDTH               2  /* CP_SW_KELVIN_MODE - [2:1] */
+
+/*
+ * R164 (0xA4) - Clock Rate Test 4
+ */
+#define WM8903_ADC_DIG_MIC                      0x0200  /* ADC_DIG_MIC */
+#define WM8903_ADC_DIG_MIC_MASK                 0x0200  /* ADC_DIG_MIC */
+#define WM8903_ADC_DIG_MIC_SHIFT                     9  /* ADC_DIG_MIC */
+#define WM8903_ADC_DIG_MIC_WIDTH                     1  /* ADC_DIG_MIC */
+
+/*
+ * R172 (0xAC) - Analogue Output Bias 0
+ */
+#define WM8903_PGA_BIAS_MASK                    0x0070  /* PGA_BIAS - [6:4] */
+#define WM8903_PGA_BIAS_SHIFT                        4  /* PGA_BIAS - [6:4] */
+#define WM8903_PGA_BIAS_WIDTH                        3  /* PGA_BIAS - [6:4] */
+
+#endif
diff --git a/sound/soc/codecs/wm8971.c b/sound/soc/codecs/wm8971.c
new file mode 100644
index 0000000..f41a578
--- /dev/null
+++ b/sound/soc/codecs/wm8971.c
@@ -0,0 +1,941 @@
+/*
+ * wm8971.c  --  WM8971 ALSA SoC Audio driver
+ *
+ * Copyright 2005 Lab126, Inc.
+ *
+ * Author: Kenneth Kiraly <kiraly@lab126.com>
+ *
+ * Based on wm8753.c by Liam Girdwood
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+
+#include "wm8971.h"
+
+#define WM8971_VERSION "0.9"
+
+#define	WM8971_REG_COUNT		43
+
+static struct workqueue_struct *wm8971_workq = NULL;
+
+/* codec private data */
+struct wm8971_priv {
+	unsigned int sysclk;
+};
+
+/*
+ * wm8971 register cache
+ * We can't read the WM8971 register space when we
+ * are using 2 wire for device control, so we cache them instead.
+ */
+static const u16 wm8971_reg[] = {
+	0x0097, 0x0097, 0x0079, 0x0079,  /*  0 */
+	0x0000, 0x0008, 0x0000, 0x000a,  /*  4 */
+	0x0000, 0x0000, 0x00ff, 0x00ff,  /*  8 */
+	0x000f, 0x000f, 0x0000, 0x0000,  /* 12 */
+	0x0000, 0x007b, 0x0000, 0x0032,  /* 16 */
+	0x0000, 0x00c3, 0x00c3, 0x00c0,  /* 20 */
+	0x0000, 0x0000, 0x0000, 0x0000,  /* 24 */
+	0x0000, 0x0000, 0x0000, 0x0000,  /* 28 */
+	0x0000, 0x0000, 0x0050, 0x0050,  /* 32 */
+	0x0050, 0x0050, 0x0050, 0x0050,  /* 36 */
+	0x0079, 0x0079, 0x0079,          /* 40 */
+};
+
+static inline unsigned int wm8971_read_reg_cache(struct snd_soc_codec *codec,
+	unsigned int reg)
+{
+	u16 *cache = codec->reg_cache;
+	if (reg < WM8971_REG_COUNT)
+		return cache[reg];
+
+	return -1;
+}
+
+static inline void wm8971_write_reg_cache(struct snd_soc_codec *codec,
+	unsigned int reg, unsigned int value)
+{
+	u16 *cache = codec->reg_cache;
+	if (reg < WM8971_REG_COUNT)
+		cache[reg] = value;
+}
+
+static int wm8971_write(struct snd_soc_codec *codec, unsigned int reg,
+	unsigned int value)
+{
+	u8 data[2];
+
+	/* data is
+	 *   D15..D9 WM8753 register offset
+	 *   D8...D0 register data
+	 */
+	data[0] = (reg << 1) | ((value >> 8) & 0x0001);
+	data[1] = value & 0x00ff;
+
+	wm8971_write_reg_cache (codec, reg, value);
+	if (codec->hw_write(codec->control_data, data, 2) == 2)
+		return 0;
+	else
+		return -EIO;
+}
+
+#define wm8971_reset(c)	wm8971_write(c, WM8971_RESET, 0)
+
+/* WM8971 Controls */
+static const char *wm8971_bass[] = { "Linear Control", "Adaptive Boost" };
+static const char *wm8971_bass_filter[] = { "130Hz @ 48kHz",
+	"200Hz @ 48kHz" };
+static const char *wm8971_treble[] = { "8kHz", "4kHz" };
+static const char *wm8971_alc_func[] = { "Off", "Right", "Left", "Stereo" };
+static const char *wm8971_ng_type[] = { "Constant PGA Gain",
+	"Mute ADC Output" };
+static const char *wm8971_deemp[] = { "None", "32kHz", "44.1kHz", "48kHz" };
+static const char *wm8971_mono_mux[] = {"Stereo", "Mono (Left)",
+	"Mono (Right)", "Digital Mono"};
+static const char *wm8971_dac_phase[] = { "Non Inverted", "Inverted" };
+static const char *wm8971_lline_mux[] = {"Line", "NC", "NC", "PGA",
+	"Differential"};
+static const char *wm8971_rline_mux[] = {"Line", "Mic", "NC", "PGA",
+	"Differential"};
+static const char *wm8971_lpga_sel[] = {"Line", "NC", "NC", "Differential"};
+static const char *wm8971_rpga_sel[] = {"Line", "Mic", "NC", "Differential"};
+static const char *wm8971_adcpol[] = {"Normal", "L Invert", "R Invert",
+	"L + R Invert"};
+
+static const struct soc_enum wm8971_enum[] = {
+	SOC_ENUM_SINGLE(WM8971_BASS, 7, 2, wm8971_bass),	/* 0 */
+	SOC_ENUM_SINGLE(WM8971_BASS, 6, 2, wm8971_bass_filter),
+	SOC_ENUM_SINGLE(WM8971_TREBLE, 6, 2, wm8971_treble),
+	SOC_ENUM_SINGLE(WM8971_ALC1, 7, 4, wm8971_alc_func),
+	SOC_ENUM_SINGLE(WM8971_NGATE, 1, 2, wm8971_ng_type),    /* 4 */
+	SOC_ENUM_SINGLE(WM8971_ADCDAC, 1, 4, wm8971_deemp),
+	SOC_ENUM_SINGLE(WM8971_ADCTL1, 4, 4, wm8971_mono_mux),
+	SOC_ENUM_SINGLE(WM8971_ADCTL1, 1, 2, wm8971_dac_phase),
+	SOC_ENUM_SINGLE(WM8971_LOUTM1, 0, 5, wm8971_lline_mux), /* 8 */
+	SOC_ENUM_SINGLE(WM8971_ROUTM1, 0, 5, wm8971_rline_mux),
+	SOC_ENUM_SINGLE(WM8971_LADCIN, 6, 4, wm8971_lpga_sel),
+	SOC_ENUM_SINGLE(WM8971_RADCIN, 6, 4, wm8971_rpga_sel),
+	SOC_ENUM_SINGLE(WM8971_ADCDAC, 5, 4, wm8971_adcpol),    /* 12 */
+	SOC_ENUM_SINGLE(WM8971_ADCIN, 6, 4, wm8971_mono_mux),
+};
+
+static const struct snd_kcontrol_new wm8971_snd_controls[] = {
+	SOC_DOUBLE_R("Capture Volume", WM8971_LINVOL, WM8971_RINVOL, 0, 63, 0),
+	SOC_DOUBLE_R("Capture ZC Switch", WM8971_LINVOL, WM8971_RINVOL,
+		     6, 1, 0),
+	SOC_DOUBLE_R("Capture Switch", WM8971_LINVOL, WM8971_RINVOL, 7, 1, 1),
+
+	SOC_DOUBLE_R("Headphone Playback ZC Switch", WM8971_LOUT1V,
+		WM8971_ROUT1V, 7, 1, 0),
+	SOC_DOUBLE_R("Speaker Playback ZC Switch", WM8971_LOUT2V,
+		WM8971_ROUT2V, 7, 1, 0),
+	SOC_SINGLE("Mono Playback ZC Switch", WM8971_MOUTV, 7, 1, 0),
+
+	SOC_DOUBLE_R("PCM Volume", WM8971_LDAC, WM8971_RDAC, 0, 255, 0),
+
+	SOC_DOUBLE_R("Bypass Left Playback Volume", WM8971_LOUTM1,
+		WM8971_LOUTM2, 4, 7, 1),
+	SOC_DOUBLE_R("Bypass Right Playback Volume", WM8971_ROUTM1,
+		WM8971_ROUTM2, 4, 7, 1),
+	SOC_DOUBLE_R("Bypass Mono Playback Volume", WM8971_MOUTM1,
+		WM8971_MOUTM2, 4, 7, 1),
+
+	SOC_DOUBLE_R("Headphone Playback Volume", WM8971_LOUT1V,
+		WM8971_ROUT1V, 0, 127, 0),
+	SOC_DOUBLE_R("Speaker Playback Volume", WM8971_LOUT2V,
+		WM8971_ROUT2V, 0, 127, 0),
+
+	SOC_ENUM("Bass Boost", wm8971_enum[0]),
+	SOC_ENUM("Bass Filter", wm8971_enum[1]),
+	SOC_SINGLE("Bass Volume", WM8971_BASS, 0, 7, 1),
+
+	SOC_SINGLE("Treble Volume", WM8971_TREBLE, 0, 7, 0),
+	SOC_ENUM("Treble Cut-off", wm8971_enum[2]),
+
+	SOC_SINGLE("Capture Filter Switch", WM8971_ADCDAC, 0, 1, 1),
+
+	SOC_SINGLE("ALC Target Volume", WM8971_ALC1, 0, 7, 0),
+	SOC_SINGLE("ALC Max Volume", WM8971_ALC1, 4, 7, 0),
+
+	SOC_SINGLE("ALC Capture Target Volume", WM8971_ALC1, 0, 7, 0),
+	SOC_SINGLE("ALC Capture Max Volume", WM8971_ALC1, 4, 7, 0),
+	SOC_ENUM("ALC Capture Function", wm8971_enum[3]),
+	SOC_SINGLE("ALC Capture ZC Switch", WM8971_ALC2, 7, 1, 0),
+	SOC_SINGLE("ALC Capture Hold Time", WM8971_ALC2, 0, 15, 0),
+	SOC_SINGLE("ALC Capture Decay Time", WM8971_ALC3, 4, 15, 0),
+	SOC_SINGLE("ALC Capture Attack Time", WM8971_ALC3, 0, 15, 0),
+	SOC_SINGLE("ALC Capture NG Threshold", WM8971_NGATE, 3, 31, 0),
+	SOC_ENUM("ALC Capture NG Type", wm8971_enum[4]),
+	SOC_SINGLE("ALC Capture NG Switch", WM8971_NGATE, 0, 1, 0),
+
+	SOC_SINGLE("Capture 6dB Attenuate", WM8971_ADCDAC, 8, 1, 0),
+	SOC_SINGLE("Playback 6dB Attenuate", WM8971_ADCDAC, 7, 1, 0),
+
+	SOC_ENUM("Playback De-emphasis", wm8971_enum[5]),
+	SOC_ENUM("Playback Function", wm8971_enum[6]),
+	SOC_ENUM("Playback Phase", wm8971_enum[7]),
+
+	SOC_DOUBLE_R("Mic Boost", WM8971_LADCIN, WM8971_RADCIN, 4, 3, 0),
+};
+
+/* add non-DAPM controls */
+static int wm8971_add_controls(struct snd_soc_codec *codec)
+{
+	int err, i;
+
+	for (i = 0; i < ARRAY_SIZE(wm8971_snd_controls); i++) {
+		err = snd_ctl_add(codec->card,
+				snd_soc_cnew(&wm8971_snd_controls[i],
+					     codec, NULL));
+		if (err < 0)
+			return err;
+	}
+	return 0;
+}
+
+/*
+ * DAPM Controls
+ */
+
+/* Left Mixer */
+static const struct snd_kcontrol_new wm8971_left_mixer_controls[] = {
+SOC_DAPM_SINGLE("Playback Switch", WM8971_LOUTM1, 8, 1, 0),
+SOC_DAPM_SINGLE("Left Bypass Switch", WM8971_LOUTM1, 7, 1, 0),
+SOC_DAPM_SINGLE("Right Playback Switch", WM8971_LOUTM2, 8, 1, 0),
+SOC_DAPM_SINGLE("Right Bypass Switch", WM8971_LOUTM2, 7, 1, 0),
+};
+
+/* Right Mixer */
+static const struct snd_kcontrol_new wm8971_right_mixer_controls[] = {
+SOC_DAPM_SINGLE("Left Playback Switch", WM8971_ROUTM1, 8, 1, 0),
+SOC_DAPM_SINGLE("Left Bypass Switch", WM8971_ROUTM1, 7, 1, 0),
+SOC_DAPM_SINGLE("Playback Switch", WM8971_ROUTM2, 8, 1, 0),
+SOC_DAPM_SINGLE("Right Bypass Switch", WM8971_ROUTM2, 7, 1, 0),
+};
+
+/* Mono Mixer */
+static const struct snd_kcontrol_new wm8971_mono_mixer_controls[] = {
+SOC_DAPM_SINGLE("Left Playback Switch", WM8971_MOUTM1, 8, 1, 0),
+SOC_DAPM_SINGLE("Left Bypass Switch", WM8971_MOUTM1, 7, 1, 0),
+SOC_DAPM_SINGLE("Right Playback Switch", WM8971_MOUTM2, 8, 1, 0),
+SOC_DAPM_SINGLE("Right Bypass Switch", WM8971_MOUTM2, 7, 1, 0),
+};
+
+/* Left Line Mux */
+static const struct snd_kcontrol_new wm8971_left_line_controls =
+SOC_DAPM_ENUM("Route", wm8971_enum[8]);
+
+/* Right Line Mux */
+static const struct snd_kcontrol_new wm8971_right_line_controls =
+SOC_DAPM_ENUM("Route", wm8971_enum[9]);
+
+/* Left PGA Mux */
+static const struct snd_kcontrol_new wm8971_left_pga_controls =
+SOC_DAPM_ENUM("Route", wm8971_enum[10]);
+
+/* Right PGA Mux */
+static const struct snd_kcontrol_new wm8971_right_pga_controls =
+SOC_DAPM_ENUM("Route", wm8971_enum[11]);
+
+/* Mono ADC Mux */
+static const struct snd_kcontrol_new wm8971_monomux_controls =
+SOC_DAPM_ENUM("Route", wm8971_enum[13]);
+
+static const struct snd_soc_dapm_widget wm8971_dapm_widgets[] = {
+	SND_SOC_DAPM_MIXER("Left Mixer", SND_SOC_NOPM, 0, 0,
+		&wm8971_left_mixer_controls[0],
+		ARRAY_SIZE(wm8971_left_mixer_controls)),
+	SND_SOC_DAPM_MIXER("Right Mixer", SND_SOC_NOPM, 0, 0,
+		&wm8971_right_mixer_controls[0],
+		ARRAY_SIZE(wm8971_right_mixer_controls)),
+	SND_SOC_DAPM_MIXER("Mono Mixer", WM8971_PWR2, 2, 0,
+		&wm8971_mono_mixer_controls[0],
+		ARRAY_SIZE(wm8971_mono_mixer_controls)),
+
+	SND_SOC_DAPM_PGA("Right Out 2", WM8971_PWR2, 3, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Left Out 2", WM8971_PWR2, 4, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Right Out 1", WM8971_PWR2, 5, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Left Out 1", WM8971_PWR2, 6, 0, NULL, 0),
+	SND_SOC_DAPM_DAC("Right DAC", "Right Playback", WM8971_PWR2, 7, 0),
+	SND_SOC_DAPM_DAC("Left DAC", "Left Playback", WM8971_PWR2, 8, 0),
+	SND_SOC_DAPM_PGA("Mono Out 1", WM8971_PWR2, 2, 0, NULL, 0),
+
+	SND_SOC_DAPM_MICBIAS("Mic Bias", WM8971_PWR1, 1, 0),
+	SND_SOC_DAPM_ADC("Right ADC", "Right Capture", WM8971_PWR1, 2, 0),
+	SND_SOC_DAPM_ADC("Left ADC", "Left Capture", WM8971_PWR1, 3, 0),
+
+	SND_SOC_DAPM_MUX("Left PGA Mux", WM8971_PWR1, 5, 0,
+		&wm8971_left_pga_controls),
+	SND_SOC_DAPM_MUX("Right PGA Mux", WM8971_PWR1, 4, 0,
+		&wm8971_right_pga_controls),
+	SND_SOC_DAPM_MUX("Left Line Mux", SND_SOC_NOPM, 0, 0,
+		&wm8971_left_line_controls),
+	SND_SOC_DAPM_MUX("Right Line Mux", SND_SOC_NOPM, 0, 0,
+		&wm8971_right_line_controls),
+
+	SND_SOC_DAPM_MUX("Left ADC Mux", SND_SOC_NOPM, 0, 0,
+		&wm8971_monomux_controls),
+	SND_SOC_DAPM_MUX("Right ADC Mux", SND_SOC_NOPM, 0, 0,
+		&wm8971_monomux_controls),
+
+	SND_SOC_DAPM_OUTPUT("LOUT1"),
+	SND_SOC_DAPM_OUTPUT("ROUT1"),
+	SND_SOC_DAPM_OUTPUT("LOUT2"),
+	SND_SOC_DAPM_OUTPUT("ROUT2"),
+	SND_SOC_DAPM_OUTPUT("MONO"),
+
+	SND_SOC_DAPM_INPUT("LINPUT1"),
+	SND_SOC_DAPM_INPUT("RINPUT1"),
+	SND_SOC_DAPM_INPUT("MIC"),
+};
+
+static const struct snd_soc_dapm_route audio_map[] = {
+	/* left mixer */
+	{"Left Mixer", "Playback Switch", "Left DAC"},
+	{"Left Mixer", "Left Bypass Switch", "Left Line Mux"},
+	{"Left Mixer", "Right Playback Switch", "Right DAC"},
+	{"Left Mixer", "Right Bypass Switch", "Right Line Mux"},
+
+	/* right mixer */
+	{"Right Mixer", "Left Playback Switch", "Left DAC"},
+	{"Right Mixer", "Left Bypass Switch", "Left Line Mux"},
+	{"Right Mixer", "Playback Switch", "Right DAC"},
+	{"Right Mixer", "Right Bypass Switch", "Right Line Mux"},
+
+	/* left out 1 */
+	{"Left Out 1", NULL, "Left Mixer"},
+	{"LOUT1", NULL, "Left Out 1"},
+
+	/* left out 2 */
+	{"Left Out 2", NULL, "Left Mixer"},
+	{"LOUT2", NULL, "Left Out 2"},
+
+	/* right out 1 */
+	{"Right Out 1", NULL, "Right Mixer"},
+	{"ROUT1", NULL, "Right Out 1"},
+
+	/* right out 2 */
+	{"Right Out 2", NULL, "Right Mixer"},
+	{"ROUT2", NULL, "Right Out 2"},
+
+	/* mono mixer */
+	{"Mono Mixer", "Left Playback Switch", "Left DAC"},
+	{"Mono Mixer", "Left Bypass Switch", "Left Line Mux"},
+	{"Mono Mixer", "Right Playback Switch", "Right DAC"},
+	{"Mono Mixer", "Right Bypass Switch", "Right Line Mux"},
+
+	/* mono out */
+	{"Mono Out", NULL, "Mono Mixer"},
+	{"MONO1", NULL, "Mono Out"},
+
+	/* Left Line Mux */
+	{"Left Line Mux", "Line", "LINPUT1"},
+	{"Left Line Mux", "PGA", "Left PGA Mux"},
+	{"Left Line Mux", "Differential", "Differential Mux"},
+
+	/* Right Line Mux */
+	{"Right Line Mux", "Line", "RINPUT1"},
+	{"Right Line Mux", "Mic", "MIC"},
+	{"Right Line Mux", "PGA", "Right PGA Mux"},
+	{"Right Line Mux", "Differential", "Differential Mux"},
+
+	/* Left PGA Mux */
+	{"Left PGA Mux", "Line", "LINPUT1"},
+	{"Left PGA Mux", "Differential", "Differential Mux"},
+
+	/* Right PGA Mux */
+	{"Right PGA Mux", "Line", "RINPUT1"},
+	{"Right PGA Mux", "Differential", "Differential Mux"},
+
+	/* Differential Mux */
+	{"Differential Mux", "Line", "LINPUT1"},
+	{"Differential Mux", "Line", "RINPUT1"},
+
+	/* Left ADC Mux */
+	{"Left ADC Mux", "Stereo", "Left PGA Mux"},
+	{"Left ADC Mux", "Mono (Left)", "Left PGA Mux"},
+	{"Left ADC Mux", "Digital Mono", "Left PGA Mux"},
+
+	/* Right ADC Mux */
+	{"Right ADC Mux", "Stereo", "Right PGA Mux"},
+	{"Right ADC Mux", "Mono (Right)", "Right PGA Mux"},
+	{"Right ADC Mux", "Digital Mono", "Right PGA Mux"},
+
+	/* ADC */
+	{"Left ADC", NULL, "Left ADC Mux"},
+	{"Right ADC", NULL, "Right ADC Mux"},
+};
+
+static int wm8971_add_widgets(struct snd_soc_codec *codec)
+{
+	snd_soc_dapm_new_controls(codec, wm8971_dapm_widgets,
+				  ARRAY_SIZE(wm8971_dapm_widgets));
+
+	snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+
+	snd_soc_dapm_new_widgets(codec);
+
+	return 0;
+}
+
+struct _coeff_div {
+	u32 mclk;
+	u32 rate;
+	u16 fs;
+	u8 sr:5;
+	u8 usb:1;
+};
+
+/* codec hifi mclk clock divider coefficients */
+static const struct _coeff_div coeff_div[] = {
+	/* 8k */
+	{12288000, 8000, 1536, 0x6, 0x0},
+	{11289600, 8000, 1408, 0x16, 0x0},
+	{18432000, 8000, 2304, 0x7, 0x0},
+	{16934400, 8000, 2112, 0x17, 0x0},
+	{12000000, 8000, 1500, 0x6, 0x1},
+
+	/* 11.025k */
+	{11289600, 11025, 1024, 0x18, 0x0},
+	{16934400, 11025, 1536, 0x19, 0x0},
+	{12000000, 11025, 1088, 0x19, 0x1},
+
+	/* 16k */
+	{12288000, 16000, 768, 0xa, 0x0},
+	{18432000, 16000, 1152, 0xb, 0x0},
+	{12000000, 16000, 750, 0xa, 0x1},
+
+	/* 22.05k */
+	{11289600, 22050, 512, 0x1a, 0x0},
+	{16934400, 22050, 768, 0x1b, 0x0},
+	{12000000, 22050, 544, 0x1b, 0x1},
+
+	/* 32k */
+	{12288000, 32000, 384, 0xc, 0x0},
+	{18432000, 32000, 576, 0xd, 0x0},
+	{12000000, 32000, 375, 0xa, 0x1},
+
+	/* 44.1k */
+	{11289600, 44100, 256, 0x10, 0x0},
+	{16934400, 44100, 384, 0x11, 0x0},
+	{12000000, 44100, 272, 0x11, 0x1},
+
+	/* 48k */
+	{12288000, 48000, 256, 0x0, 0x0},
+	{18432000, 48000, 384, 0x1, 0x0},
+	{12000000, 48000, 250, 0x0, 0x1},
+
+	/* 88.2k */
+	{11289600, 88200, 128, 0x1e, 0x0},
+	{16934400, 88200, 192, 0x1f, 0x0},
+	{12000000, 88200, 136, 0x1f, 0x1},
+
+	/* 96k */
+	{12288000, 96000, 128, 0xe, 0x0},
+	{18432000, 96000, 192, 0xf, 0x0},
+	{12000000, 96000, 125, 0xe, 0x1},
+};
+
+static int get_coeff(int mclk, int rate)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(coeff_div); i++) {
+		if (coeff_div[i].rate == rate && coeff_div[i].mclk == mclk)
+			return i;
+	}
+	return -EINVAL;
+}
+
+static int wm8971_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+		int clk_id, unsigned int freq, int dir)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+	struct wm8971_priv *wm8971 = codec->private_data;
+
+	switch (freq) {
+	case 11289600:
+	case 12000000:
+	case 12288000:
+	case 16934400:
+	case 18432000:
+		wm8971->sysclk = freq;
+		return 0;
+	}
+	return -EINVAL;
+}
+
+static int wm8971_set_dai_fmt(struct snd_soc_dai *codec_dai,
+		unsigned int fmt)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+	u16 iface = 0;
+
+	/* set master/slave audio interface */
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		iface = 0x0040;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* interface format */
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		iface |= 0x0002;
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		iface |= 0x0001;
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		iface |= 0x0003;
+		break;
+	case SND_SOC_DAIFMT_DSP_B:
+		iface |= 0x0013;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* clock inversion */
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		break;
+	case SND_SOC_DAIFMT_IB_IF:
+		iface |= 0x0090;
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		iface |= 0x0080;
+		break;
+	case SND_SOC_DAIFMT_NB_IF:
+		iface |= 0x0010;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	wm8971_write(codec, WM8971_IFACE, iface);
+	return 0;
+}
+
+static int wm8971_pcm_hw_params(struct snd_pcm_substream *substream,
+	struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_device *socdev = rtd->socdev;
+	struct snd_soc_codec *codec = socdev->codec;
+	struct wm8971_priv *wm8971 = codec->private_data;
+	u16 iface = wm8971_read_reg_cache(codec, WM8971_IFACE) & 0x1f3;
+	u16 srate = wm8971_read_reg_cache(codec, WM8971_SRATE) & 0x1c0;
+	int coeff = get_coeff(wm8971->sysclk, params_rate(params));
+
+	/* bit size */
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S16_LE:
+		break;
+	case SNDRV_PCM_FORMAT_S20_3LE:
+		iface |= 0x0004;
+		break;
+	case SNDRV_PCM_FORMAT_S24_LE:
+		iface |= 0x0008;
+		break;
+	case SNDRV_PCM_FORMAT_S32_LE:
+		iface |= 0x000c;
+		break;
+	}
+
+	/* set iface & srate */
+	wm8971_write(codec, WM8971_IFACE, iface);
+	if (coeff >= 0)
+		wm8971_write(codec, WM8971_SRATE, srate |
+			(coeff_div[coeff].sr << 1) | coeff_div[coeff].usb);
+
+	return 0;
+}
+
+static int wm8971_mute(struct snd_soc_dai *dai, int mute)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	u16 mute_reg = wm8971_read_reg_cache(codec, WM8971_ADCDAC) & 0xfff7;
+
+	if (mute)
+		wm8971_write(codec, WM8971_ADCDAC, mute_reg | 0x8);
+	else
+		wm8971_write(codec, WM8971_ADCDAC, mute_reg);
+	return 0;
+}
+
+static int wm8971_set_bias_level(struct snd_soc_codec *codec,
+	enum snd_soc_bias_level level)
+{
+	u16 pwr_reg = wm8971_read_reg_cache(codec, WM8971_PWR1) & 0xfe3e;
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		/* set vmid to 50k and unmute dac */
+		wm8971_write(codec, WM8971_PWR1, pwr_reg | 0x00c1);
+		break;
+	case SND_SOC_BIAS_PREPARE:
+		break;
+	case SND_SOC_BIAS_STANDBY:
+		/* mute dac and set vmid to 500k, enable VREF */
+		wm8971_write(codec, WM8971_PWR1, pwr_reg | 0x0140);
+		break;
+	case SND_SOC_BIAS_OFF:
+		wm8971_write(codec, WM8971_PWR1, 0x0001);
+		break;
+	}
+	codec->bias_level = level;
+	return 0;
+}
+
+#define WM8971_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
+		SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 | \
+		SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000)
+
+#define WM8971_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
+	SNDRV_PCM_FMTBIT_S24_LE)
+
+struct snd_soc_dai wm8971_dai = {
+	.name = "WM8971",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = WM8971_RATES,
+		.formats = WM8971_FORMATS,},
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = WM8971_RATES,
+		.formats = WM8971_FORMATS,},
+	.ops = {
+		.hw_params = wm8971_pcm_hw_params,
+	},
+	.dai_ops = {
+		.digital_mute = wm8971_mute,
+		.set_fmt = wm8971_set_dai_fmt,
+		.set_sysclk = wm8971_set_dai_sysclk,
+	},
+};
+EXPORT_SYMBOL_GPL(wm8971_dai);
+
+static void wm8971_work(struct work_struct *work)
+{
+	struct snd_soc_codec *codec =
+		container_of(work, struct snd_soc_codec, delayed_work.work);
+	wm8971_set_bias_level(codec, codec->bias_level);
+}
+
+static int wm8971_suspend(struct platform_device *pdev, pm_message_t state)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	struct snd_soc_codec *codec = socdev->codec;
+
+	wm8971_set_bias_level(codec, SND_SOC_BIAS_OFF);
+	return 0;
+}
+
+static int wm8971_resume(struct platform_device *pdev)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	struct snd_soc_codec *codec = socdev->codec;
+	int i;
+	u8 data[2];
+	u16 *cache = codec->reg_cache;
+	u16 reg;
+
+	/* Sync reg_cache with the hardware */
+	for (i = 0; i < ARRAY_SIZE(wm8971_reg); i++) {
+		if (i + 1 == WM8971_RESET)
+			continue;
+		data[0] = (i << 1) | ((cache[i] >> 8) & 0x0001);
+		data[1] = cache[i] & 0x00ff;
+		codec->hw_write(codec->control_data, data, 2);
+	}
+
+	wm8971_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+	/* charge wm8971 caps */
+	if (codec->suspend_bias_level == SND_SOC_BIAS_ON) {
+		reg = wm8971_read_reg_cache(codec, WM8971_PWR1) & 0xfe3e;
+		wm8971_write(codec, WM8971_PWR1, reg | 0x01c0);
+		codec->bias_level = SND_SOC_BIAS_ON;
+		queue_delayed_work(wm8971_workq, &codec->delayed_work,
+			msecs_to_jiffies(1000));
+	}
+
+	return 0;
+}
+
+static int wm8971_init(struct snd_soc_device *socdev)
+{
+	struct snd_soc_codec *codec = socdev->codec;
+	int reg, ret = 0;
+
+	codec->name = "WM8971";
+	codec->owner = THIS_MODULE;
+	codec->read = wm8971_read_reg_cache;
+	codec->write = wm8971_write;
+	codec->set_bias_level = wm8971_set_bias_level;
+	codec->dai = &wm8971_dai;
+	codec->reg_cache_size = ARRAY_SIZE(wm8971_reg);
+	codec->num_dai = 1;
+	codec->reg_cache = kmemdup(wm8971_reg, sizeof(wm8971_reg), GFP_KERNEL);
+
+	if (codec->reg_cache == NULL)
+		return -ENOMEM;
+
+	wm8971_reset(codec);
+
+	/* register pcms */
+	ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
+	if (ret < 0) {
+		printk(KERN_ERR "wm8971: failed to create pcms\n");
+		goto pcm_err;
+	}
+
+	/* charge output caps - set vmid to 5k for quick power up */
+	reg = wm8971_read_reg_cache(codec, WM8971_PWR1) & 0xfe3e;
+	wm8971_write(codec, WM8971_PWR1, reg | 0x01c0);
+	codec->bias_level = SND_SOC_BIAS_STANDBY;
+	queue_delayed_work(wm8971_workq, &codec->delayed_work,
+		msecs_to_jiffies(1000));
+
+	/* set the update bits */
+	reg = wm8971_read_reg_cache(codec, WM8971_LDAC);
+	wm8971_write(codec, WM8971_LDAC, reg | 0x0100);
+	reg = wm8971_read_reg_cache(codec, WM8971_RDAC);
+	wm8971_write(codec, WM8971_RDAC, reg | 0x0100);
+
+	reg = wm8971_read_reg_cache(codec, WM8971_LOUT1V);
+	wm8971_write(codec, WM8971_LOUT1V, reg | 0x0100);
+	reg = wm8971_read_reg_cache(codec, WM8971_ROUT1V);
+	wm8971_write(codec, WM8971_ROUT1V, reg | 0x0100);
+
+	reg = wm8971_read_reg_cache(codec, WM8971_LOUT2V);
+	wm8971_write(codec, WM8971_LOUT2V, reg | 0x0100);
+	reg = wm8971_read_reg_cache(codec, WM8971_ROUT2V);
+	wm8971_write(codec, WM8971_ROUT2V, reg | 0x0100);
+
+	reg = wm8971_read_reg_cache(codec, WM8971_LINVOL);
+	wm8971_write(codec, WM8971_LINVOL, reg | 0x0100);
+	reg = wm8971_read_reg_cache(codec, WM8971_RINVOL);
+	wm8971_write(codec, WM8971_RINVOL, reg | 0x0100);
+
+	wm8971_add_controls(codec);
+	wm8971_add_widgets(codec);
+	ret = snd_soc_register_card(socdev);
+	if (ret < 0) {
+		printk(KERN_ERR "wm8971: failed to register card\n");
+		goto card_err;
+	}
+	return ret;
+
+card_err:
+	snd_soc_free_pcms(socdev);
+	snd_soc_dapm_free(socdev);
+pcm_err:
+	kfree(codec->reg_cache);
+	return ret;
+}
+
+/* If the i2c layer weren't so broken, we could pass this kind of data
+   around */
+static struct snd_soc_device *wm8971_socdev;
+
+#if defined (CONFIG_I2C) || defined (CONFIG_I2C_MODULE)
+
+static int wm8971_i2c_probe(struct i2c_client *i2c,
+			    const struct i2c_device_id *id)
+{
+	struct snd_soc_device *socdev = wm8971_socdev;
+	struct snd_soc_codec *codec = socdev->codec;
+	int ret;
+
+	i2c_set_clientdata(i2c, codec);
+
+	codec->control_data = i2c;
+
+	ret = wm8971_init(socdev);
+	if (ret < 0)
+		pr_err("failed to initialise WM8971\n");
+
+	return ret;
+}
+
+static int wm8971_i2c_remove(struct i2c_client *client)
+{
+	struct snd_soc_codec *codec = i2c_get_clientdata(client);
+	kfree(codec->reg_cache);
+	return 0;
+}
+
+static const struct i2c_device_id wm8971_i2c_id[] = {
+	{ "wm8971", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, wm8971_i2c_id);
+
+static struct i2c_driver wm8971_i2c_driver = {
+	.driver = {
+		.name = "WM8971 I2C Codec",
+		.owner = THIS_MODULE,
+	},
+	.probe    = wm8971_i2c_probe,
+	.remove   = wm8971_i2c_remove,
+	.id_table = wm8971_i2c_id,
+};
+
+static int wm8971_add_i2c_device(struct platform_device *pdev,
+				 const struct wm8971_setup_data *setup)
+{
+	struct i2c_board_info info;
+	struct i2c_adapter *adapter;
+	struct i2c_client *client;
+	int ret;
+
+	ret = i2c_add_driver(&wm8971_i2c_driver);
+	if (ret != 0) {
+		dev_err(&pdev->dev, "can't add i2c driver\n");
+		return ret;
+	}
+
+	memset(&info, 0, sizeof(struct i2c_board_info));
+	info.addr = setup->i2c_address;
+	strlcpy(info.type, "wm8971", I2C_NAME_SIZE);
+
+	adapter = i2c_get_adapter(setup->i2c_bus);
+	if (!adapter) {
+		dev_err(&pdev->dev, "can't get i2c adapter %d\n",
+			setup->i2c_bus);
+		goto err_driver;
+	}
+
+	client = i2c_new_device(adapter, &info);
+	i2c_put_adapter(adapter);
+	if (!client) {
+		dev_err(&pdev->dev, "can't add i2c device at 0x%x\n",
+			(unsigned int)info.addr);
+		goto err_driver;
+	}
+
+	return 0;
+
+err_driver:
+	i2c_del_driver(&wm8971_i2c_driver);
+	return -ENODEV;
+}
+
+#endif
+
+static int wm8971_probe(struct platform_device *pdev)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	struct wm8971_setup_data *setup;
+	struct snd_soc_codec *codec;
+	struct wm8971_priv *wm8971;
+	int ret = 0;
+
+	pr_info("WM8971 Audio Codec %s", WM8971_VERSION);
+
+	setup = socdev->codec_data;
+	codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
+	if (codec == NULL)
+		return -ENOMEM;
+
+	wm8971 = kzalloc(sizeof(struct wm8971_priv), GFP_KERNEL);
+	if (wm8971 == NULL) {
+		kfree(codec);
+		return -ENOMEM;
+	}
+
+	codec->private_data = wm8971;
+	socdev->codec = codec;
+	mutex_init(&codec->mutex);
+	INIT_LIST_HEAD(&codec->dapm_widgets);
+	INIT_LIST_HEAD(&codec->dapm_paths);
+	wm8971_socdev = socdev;
+
+	INIT_DELAYED_WORK(&codec->delayed_work, wm8971_work);
+	wm8971_workq = create_workqueue("wm8971");
+	if (wm8971_workq == NULL) {
+		kfree(codec->private_data);
+		kfree(codec);
+		return -ENOMEM;
+	}
+
+#if defined (CONFIG_I2C) || defined (CONFIG_I2C_MODULE)
+	if (setup->i2c_address) {
+		codec->hw_write = (hw_write_t)i2c_master_send;
+		ret = wm8971_add_i2c_device(pdev, setup);
+	}
+#endif
+	/* Add other interfaces here */
+
+	if (ret != 0) {
+		destroy_workqueue(wm8971_workq);
+		kfree(codec->private_data);
+		kfree(codec);
+	}
+
+	return ret;
+}
+
+/* power down chip */
+static int wm8971_remove(struct platform_device *pdev)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	struct snd_soc_codec *codec = socdev->codec;
+
+	if (codec->control_data)
+		wm8971_set_bias_level(codec, SND_SOC_BIAS_OFF);
+	if (wm8971_workq)
+		destroy_workqueue(wm8971_workq);
+	snd_soc_free_pcms(socdev);
+	snd_soc_dapm_free(socdev);
+#if defined (CONFIG_I2C) || defined (CONFIG_I2C_MODULE)
+	i2c_unregister_device(codec->control_data);
+	i2c_del_driver(&wm8971_i2c_driver);
+#endif
+	kfree(codec->private_data);
+	kfree(codec);
+
+	return 0;
+}
+
+struct snd_soc_codec_device soc_codec_dev_wm8971 = {
+	.probe = 	wm8971_probe,
+	.remove = 	wm8971_remove,
+	.suspend = 	wm8971_suspend,
+	.resume =	wm8971_resume,
+};
+
+EXPORT_SYMBOL_GPL(soc_codec_dev_wm8971);
+
+MODULE_DESCRIPTION("ASoC WM8971 driver");
+MODULE_AUTHOR("Lab126");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm8971.h b/sound/soc/codecs/wm8971.h
new file mode 100644
index 0000000..ef4f08f
--- /dev/null
+++ b/sound/soc/codecs/wm8971.h
@@ -0,0 +1,64 @@
+/*
+ * wm8971.h  --  audio driver for WM8971
+ *
+ * Copyright 2005 Lab126, Inc.
+ *
+ * Author: Kenneth Kiraly <kiraly@lab126.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 _WM8971_H
+#define _WM8971_H
+
+#define WM8971_LINVOL	0x00
+#define WM8971_RINVOL	0x01
+#define WM8971_LOUT1V	0x02
+#define WM8971_ROUT1V	0x03
+#define WM8971_ADCDAC	0x05
+#define WM8971_IFACE	0x07
+#define WM8971_SRATE	0x08
+#define WM8971_LDAC		0x0a
+#define WM8971_RDAC		0x0b
+#define WM8971_BASS		0x0c
+#define WM8971_TREBLE	0x0d
+#define WM8971_RESET	0x0f
+#define WM8971_ALC1		0x11
+#define	WM8971_ALC2		0x12
+#define	WM8971_ALC3		0x13
+#define WM8971_NGATE	0x14
+#define WM8971_LADC		0x15
+#define WM8971_RADC		0x16
+#define	WM8971_ADCTL1	0x17
+#define	WM8971_ADCTL2	0x18
+#define WM8971_PWR1		0x19
+#define WM8971_PWR2		0x1a
+#define	WM8971_ADCTL3	0x1b
+#define WM8971_ADCIN	0x1f
+#define	WM8971_LADCIN	0x20
+#define	WM8971_RADCIN	0x21
+#define WM8971_LOUTM1	0x22
+#define WM8971_LOUTM2	0x23
+#define WM8971_ROUTM1	0x24
+#define WM8971_ROUTM2	0x25
+#define WM8971_MOUTM1	0x26
+#define WM8971_MOUTM2	0x27
+#define WM8971_LOUT2V	0x28
+#define WM8971_ROUT2V	0x29
+#define WM8971_MOUTV	0x2A
+
+#define WM8971_SYSCLK	0
+
+struct wm8971_setup_data {
+	int i2c_bus;
+	unsigned short i2c_address;
+};
+
+extern struct snd_soc_dai wm8971_dai;
+extern struct snd_soc_codec_device soc_codec_dev_wm8971;
+
+#endif
diff --git a/sound/soc/codecs/wm8990.c b/sound/soc/codecs/wm8990.c
index dd995ef..572d22b 100644
--- a/sound/soc/codecs/wm8990.c
+++ b/sound/soc/codecs/wm8990.c
@@ -30,7 +30,6 @@
 
 #include "wm8990.h"
 
-#define AUDIO_NAME "wm8990"
 #define WM8990_VERSION "0.2"
 
 /* codec private data */
@@ -1477,81 +1476,86 @@
  *    low  = 0x34
  *    high = 0x36
  */
-static unsigned short normal_i2c[] = { 0, I2C_CLIENT_END };
 
-/* Magic definition of all other variables and things */
-I2C_CLIENT_INSMOD;
-
-static struct i2c_driver wm8990_i2c_driver;
-static struct i2c_client client_template;
-
-static int wm8990_codec_probe(struct i2c_adapter *adap, int addr, int kind)
+static int wm8990_i2c_probe(struct i2c_client *i2c,
+			    const struct i2c_device_id *id)
 {
 	struct snd_soc_device *socdev = wm8990_socdev;
-	struct wm8990_setup_data *setup = socdev->codec_data;
 	struct snd_soc_codec *codec = socdev->codec;
-	struct i2c_client *i2c;
 	int ret;
 
-	if (addr != setup->i2c_address)
-		return -ENODEV;
-
-	client_template.adapter = adap;
-	client_template.addr = addr;
-
-	i2c =  kmemdup(&client_template, sizeof(client_template), GFP_KERNEL);
-	if (i2c == NULL)
-		return -ENOMEM;
-
 	i2c_set_clientdata(i2c, codec);
 	codec->control_data = i2c;
 
-	ret = i2c_attach_client(i2c);
-	if (ret < 0) {
-		pr_err("failed to attach codec at addr %x\n", addr);
-		goto err;
-	}
-
 	ret = wm8990_init(socdev);
-	if (ret < 0) {
+	if (ret < 0)
 		pr_err("failed to initialise WM8990\n");
-		goto err;
-	}
-	return ret;
 
-err:
-	kfree(i2c);
 	return ret;
 }
 
-static int wm8990_i2c_detach(struct i2c_client *client)
+static int wm8990_i2c_remove(struct i2c_client *client)
 {
 	struct snd_soc_codec *codec = i2c_get_clientdata(client);
-	i2c_detach_client(client);
 	kfree(codec->reg_cache);
-	kfree(client);
 	return 0;
 }
 
-static int wm8990_i2c_attach(struct i2c_adapter *adap)
-{
-	return i2c_probe(adap, &addr_data, wm8990_codec_probe);
-}
+static const struct i2c_device_id wm8990_i2c_id[] = {
+	{ "wm8990", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, wm8990_i2c_id);
 
 static struct i2c_driver wm8990_i2c_driver = {
 	.driver = {
 		.name = "WM8990 I2C Codec",
 		.owner = THIS_MODULE,
 	},
-	.attach_adapter = wm8990_i2c_attach,
-	.detach_client =  wm8990_i2c_detach,
-	.command =        NULL,
+	.probe =    wm8990_i2c_probe,
+	.remove =   wm8990_i2c_remove,
+	.id_table = wm8990_i2c_id,
 };
 
-static struct i2c_client client_template = {
-	.name =   "WM8990",
-	.driver = &wm8990_i2c_driver,
-};
+static int wm8990_add_i2c_device(struct platform_device *pdev,
+				 const struct wm8990_setup_data *setup)
+{
+	struct i2c_board_info info;
+	struct i2c_adapter *adapter;
+	struct i2c_client *client;
+	int ret;
+
+	ret = i2c_add_driver(&wm8990_i2c_driver);
+	if (ret != 0) {
+		dev_err(&pdev->dev, "can't add i2c driver\n");
+		return ret;
+	}
+
+	memset(&info, 0, sizeof(struct i2c_board_info));
+	info.addr = setup->i2c_address;
+	strlcpy(info.type, "wm8990", I2C_NAME_SIZE);
+
+	adapter = i2c_get_adapter(setup->i2c_bus);
+	if (!adapter) {
+		dev_err(&pdev->dev, "can't get i2c adapter %d\n",
+			setup->i2c_bus);
+		goto err_driver;
+	}
+
+	client = i2c_new_device(adapter, &info);
+	i2c_put_adapter(adapter);
+	if (!client) {
+		dev_err(&pdev->dev, "can't add i2c device at 0x%x\n",
+			(unsigned int)info.addr);
+		goto err_driver;
+	}
+
+	return 0;
+
+err_driver:
+	i2c_del_driver(&wm8990_i2c_driver);
+	return -ENODEV;
+}
 #endif
 
 static int wm8990_probe(struct platform_device *pdev)
@@ -1560,7 +1564,7 @@
 	struct wm8990_setup_data *setup;
 	struct snd_soc_codec *codec;
 	struct wm8990_priv *wm8990;
-	int ret = 0;
+	int ret;
 
 	pr_info("WM8990 Audio Codec %s\n", WM8990_VERSION);
 
@@ -1582,16 +1586,13 @@
 	INIT_LIST_HEAD(&codec->dapm_paths);
 	wm8990_socdev = socdev;
 
+	ret = -ENODEV;
+
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
 	if (setup->i2c_address) {
-		normal_i2c[0] = setup->i2c_address;
 		codec->hw_write = (hw_write_t)i2c_master_send;
-		ret = i2c_add_driver(&wm8990_i2c_driver);
-		if (ret != 0)
-			printk(KERN_ERR "can't add i2c driver");
+		ret = wm8990_add_i2c_device(pdev, setup);
 	}
-#else
-		/* Add other interfaces here */
 #endif
 
 	if (ret != 0) {
@@ -1612,6 +1613,7 @@
 	snd_soc_free_pcms(socdev);
 	snd_soc_dapm_free(socdev);
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+	i2c_unregister_device(codec->control_data);
 	i2c_del_driver(&wm8990_i2c_driver);
 #endif
 	kfree(codec->private_data);
diff --git a/sound/soc/codecs/wm8990.h b/sound/soc/codecs/wm8990.h
index 0a08325..0e192f3 100644
--- a/sound/soc/codecs/wm8990.h
+++ b/sound/soc/codecs/wm8990.h
@@ -827,6 +827,7 @@
 #define WM8990_AINRMUX_PWR_BIT			3
 
 struct wm8990_setup_data {
+	unsigned i2c_bus;
 	unsigned short i2c_address;
 };
 
diff --git a/sound/soc/codecs/wm9712.c b/sound/soc/codecs/wm9712.c
index 2f1c91b..ffb471e 100644
--- a/sound/soc/codecs/wm9712.c
+++ b/sound/soc/codecs/wm9712.c
@@ -2,8 +2,7 @@
  * wm9712.c  --  ALSA Soc WM9712 codec support
  *
  * Copyright 2006 Wolfson Microelectronics PLC.
- * Author: Liam Girdwood
- *         liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com
+ * Author: Liam Girdwood <lrg@slimlogic.co.uk>
  *
  *  This program is free software; you can redistribute  it and/or modify it
  *  under  the terms of  the GNU General  Public License as published by the
diff --git a/sound/soc/codecs/wm9713.c b/sound/soc/codecs/wm9713.c
index 38d1fe0..aba402b 100644
--- a/sound/soc/codecs/wm9713.c
+++ b/sound/soc/codecs/wm9713.c
@@ -2,8 +2,7 @@
  * wm9713.c  --  ALSA Soc WM9713 codec support
  *
  * Copyright 2006 Wolfson Microelectronics PLC.
- * Author: Liam Girdwood
- *         liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com
+ * Author: Liam Girdwood <lrg@slimlogic.co.uk>
  *
  *  This program is free software; you can redistribute  it and/or modify it
  *  under  the terms of  the GNU General  Public License as published by the
@@ -419,8 +418,12 @@
 SND_SOC_DAPM_MIXER("Capture Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
 SND_SOC_DAPM_DAC("Voice DAC", "Voice Playback", AC97_EXTENDED_MID, 12, 1),
 SND_SOC_DAPM_DAC("Aux DAC", "Aux Playback", AC97_EXTENDED_MID, 11, 1),
-SND_SOC_DAPM_ADC("Left ADC", "Left HiFi Capture", AC97_EXTENDED_MID, 5, 1),
-SND_SOC_DAPM_ADC("Right ADC", "Right HiFi Capture", AC97_EXTENDED_MID, 4, 1),
+SND_SOC_DAPM_PGA("Left ADC", AC97_EXTENDED_MID, 5, 1, NULL, 0),
+SND_SOC_DAPM_PGA("Right ADC", AC97_EXTENDED_MID, 4, 1, NULL, 0),
+SND_SOC_DAPM_ADC("Left HiFi ADC", "Left HiFi Capture", SND_SOC_NOPM, 0, 0),
+SND_SOC_DAPM_ADC("Right HiFi ADC", "Right HiFi Capture", SND_SOC_NOPM, 0, 0),
+SND_SOC_DAPM_ADC("Left Voice ADC", "Left Voice Capture", SND_SOC_NOPM, 0, 0),
+SND_SOC_DAPM_ADC("Right Voice ADC", "Right Voice Capture", SND_SOC_NOPM, 0, 0),
 SND_SOC_DAPM_PGA("Left Headphone", AC97_EXTENDED_MSTATUS, 10, 1, NULL, 0),
 SND_SOC_DAPM_PGA("Right Headphone", AC97_EXTENDED_MSTATUS, 9, 1, NULL, 0),
 SND_SOC_DAPM_PGA("Left Speaker", AC97_EXTENDED_MSTATUS, 8, 1, NULL, 0),
@@ -583,9 +586,13 @@
 
 	/* left ADC */
 	{"Left ADC", NULL, "Left Capture Source"},
+	{"Left Voice ADC", NULL, "Left ADC"},
+	{"Left HiFi ADC", NULL, "Left ADC"},
 
 	/* right ADC */
 	{"Right ADC", NULL, "Right Capture Source"},
+	{"Right Voice ADC", NULL, "Right ADC"},
+	{"Right HiFi ADC", NULL, "Right ADC"},
 
 	/* mic */
 	{"Mic A Pre Amp", NULL, "Mic A Source"},
@@ -949,17 +956,17 @@
 
 static void wm9713_voiceshutdown(struct snd_pcm_substream *substream)
 {
-    struct snd_soc_pcm_runtime *rtd = substream->private_data;
-    struct snd_soc_device *socdev = rtd->socdev;
-    struct snd_soc_codec *codec = socdev->codec;
-    u16 status;
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_device *socdev = rtd->socdev;
+	struct snd_soc_codec *codec = socdev->codec;
+	u16 status;
 
-    /* Gracefully shut down the voice interface. */
-    status = ac97_read(codec, AC97_EXTENDED_STATUS) | 0x1000;
-    ac97_write(codec, AC97_HANDSET_RATE, 0x0280);
-    schedule_timeout_interruptible(msecs_to_jiffies(1));
-    ac97_write(codec, AC97_HANDSET_RATE, 0x0F80);
-    ac97_write(codec, AC97_EXTENDED_MID, status);
+	/* Gracefully shut down the voice interface. */
+	status = ac97_read(codec, AC97_EXTENDED_STATUS) | 0x1000;
+	ac97_write(codec, AC97_HANDSET_RATE, 0x0280);
+	schedule_timeout_interruptible(msecs_to_jiffies(1));
+	ac97_write(codec, AC97_HANDSET_RATE, 0x0F80);
+	ac97_write(codec, AC97_EXTENDED_MID, status);
 }
 
 static int ac97_hifi_prepare(struct snd_pcm_substream *substream)
diff --git a/sound/soc/davinci/davinci-evm.c b/sound/soc/davinci/davinci-evm.c
index 65fdbd8..9e6062c 100644
--- a/sound/soc/davinci/davinci-evm.c
+++ b/sound/soc/davinci/davinci-evm.c
@@ -1,7 +1,7 @@
 /*
  * ASoC driver for TI DAVINCI EVM platform
  *
- * Author:      Vladimir Barinov, <vbarinov@ru.mvista.com>
+ * Author:      Vladimir Barinov, <vbarinov@embeddedalley.com>
  * Copyright:   (C) 2007 MontaVista Software, Inc., <source@mvista.com>
  *
  * This program is free software; you can redistribute it and/or modify
@@ -136,6 +136,7 @@
 
 /* evm audio private data */
 static struct aic3x_setup_data evm_aic3x_setup = {
+	.i2c_bus = 0,
 	.i2c_address = 0x1b,
 };
 
diff --git a/sound/soc/davinci/davinci-i2s.c b/sound/soc/davinci/davinci-i2s.c
index 5ebf1ff..abb5fed 100644
--- a/sound/soc/davinci/davinci-i2s.c
+++ b/sound/soc/davinci/davinci-i2s.c
@@ -1,7 +1,7 @@
 /*
  * ALSA SoC I2S (McBSP) Audio Layer for TI DAVINCI processor
  *
- * Author:      Vladimir Barinov, <vbarinov@ru.mvista.com>
+ * Author:      Vladimir Barinov, <vbarinov@embeddedalley.com>
  * Copyright:   (C) 2007 MontaVista Software, Inc., <source@mvista.com>
  *
  * This program is free software; you can redistribute it and/or modify
@@ -256,7 +256,7 @@
 		mcbsp_word_length = DAVINCI_MCBSP_WORD_32;
 		break;
 	default:
-		printk(KERN_WARNING "davinci-i2s: unsupported PCM format");
+		printk(KERN_WARNING "davinci-i2s: unsupported PCM format\n");
 		return -EINVAL;
 	}
 
diff --git a/sound/soc/davinci/davinci-i2s.h b/sound/soc/davinci/davinci-i2s.h
index c5b0918..241648c 100644
--- a/sound/soc/davinci/davinci-i2s.h
+++ b/sound/soc/davinci/davinci-i2s.h
@@ -1,7 +1,7 @@
 /*
  * ALSA SoC I2S (McBSP) Audio Layer for TI DAVINCI processor
  *
- * Author:      Vladimir Barinov, <vbarinov@ru.mvista.com>
+ * Author:      Vladimir Barinov, <vbarinov@embeddedalley.com>
  * Copyright:   (C) 2007 MontaVista Software, Inc., <source@mvista.com>
  *
  * This program is free software; you can redistribute it and/or modify
diff --git a/sound/soc/davinci/davinci-pcm.c b/sound/soc/davinci/davinci-pcm.c
index 6a5e56a..76feaa6 100644
--- a/sound/soc/davinci/davinci-pcm.c
+++ b/sound/soc/davinci/davinci-pcm.c
@@ -1,7 +1,7 @@
 /*
  * ALSA PCM interface for the TI DAVINCI processor
  *
- * Author:      Vladimir Barinov, <vbarinov@ru.mvista.com>
+ * Author:      Vladimir Barinov, <vbarinov@embeddedalley.com>
  * Copyright:   (C) 2007 MontaVista Software, Inc., <source@mvista.com>
  *
  * This program is free software; you can redistribute it and/or modify
diff --git a/sound/soc/davinci/davinci-pcm.h b/sound/soc/davinci/davinci-pcm.h
index 8d6a45e..62cb4eb 100644
--- a/sound/soc/davinci/davinci-pcm.h
+++ b/sound/soc/davinci/davinci-pcm.h
@@ -1,7 +1,7 @@
 /*
  * ALSA PCM interface for the TI DAVINCI processor
  *
- * Author:      Vladimir Barinov, <vbarinov@ru.mvista.com>
+ * Author:      Vladimir Barinov, <vbarinov@embeddedalley.com>
  * Copyright:   (C) 2007 MontaVista Software, Inc., <source@mvista.com>
  *
  * This program is free software; you can redistribute it and/or modify
diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig
index 3368ace..bba9546 100644
--- a/sound/soc/fsl/Kconfig
+++ b/sound/soc/fsl/Kconfig
@@ -1,3 +1,6 @@
+config SND_SOC_OF_SIMPLE
+	tristate
+
 config SND_SOC_MPC8610
 	bool "ALSA SoC support for the MPC8610 SOC"
 	depends on MPC8610_HPCD
@@ -14,3 +17,10 @@
 	default y if MPC8610_HPCD
 	help
 	  Say Y if you want to enable audio on the Freescale MPC8610 HPCD.
+
+config SND_SOC_MPC5200_I2S
+	tristate "Freescale MPC5200 PSC in I2S mode driver"
+	select SND_SOC_OF_SIMPLE
+	depends on SND_SOC && PPC_MPC52xx
+	help
+	  Say Y here to support the MPC5200 PSCs in I2S mode.
diff --git a/sound/soc/fsl/Makefile b/sound/soc/fsl/Makefile
index 62f680a..035da4a 100644
--- a/sound/soc/fsl/Makefile
+++ b/sound/soc/fsl/Makefile
@@ -1,6 +1,11 @@
+# Simple machine driver that extracts configuration from the OF device tree
+obj-$(CONFIG_SND_SOC_OF_SIMPLE) += soc-of-simple.o
+
 # MPC8610 HPCD Machine Support
 obj-$(CONFIG_SND_SOC_MPC8610_HPCD) += mpc8610_hpcd.o
 
 # MPC8610 Platform Support
 obj-$(CONFIG_SND_SOC_MPC8610) += fsl_ssi.o fsl_dma.o
 
+obj-$(CONFIG_SND_SOC_MPC5200_I2S) += mpc5200_psc_i2s.o
+
diff --git a/sound/soc/fsl/mpc5200_psc_i2s.c b/sound/soc/fsl/mpc5200_psc_i2s.c
new file mode 100644
index 0000000..8692329
--- /dev/null
+++ b/sound/soc/fsl/mpc5200_psc_i2s.c
@@ -0,0 +1,884 @@
+/*
+ * Freescale MPC5200 PSC in I2S mode
+ * ALSA SoC Digital Audio Interface (DAI) driver
+ *
+ * Copyright (C) 2008 Secret Lab Technologies Ltd.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/of_device.h>
+#include <linux/of_platform.h>
+#include <linux/dma-mapping.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+#include <sound/soc-of-simple.h>
+
+#include <sysdev/bestcomm/bestcomm.h>
+#include <sysdev/bestcomm/gen_bd.h>
+#include <asm/mpc52xx_psc.h>
+
+MODULE_AUTHOR("Grant Likely <grant.likely@secretlab.ca>");
+MODULE_DESCRIPTION("Freescale MPC5200 PSC in I2S mode ASoC Driver");
+MODULE_LICENSE("GPL");
+
+/**
+ * PSC_I2S_RATES: sample rates supported by the I2S
+ *
+ * This driver currently only supports the PSC running in I2S slave mode,
+ * which means the codec determines the sample rate.  Therefore, we tell
+ * ALSA that we support all rates and let the codec driver decide what rates
+ * are really supported.
+ */
+#define PSC_I2S_RATES (SNDRV_PCM_RATE_5512 | SNDRV_PCM_RATE_8000_192000 | \
+			SNDRV_PCM_RATE_CONTINUOUS)
+
+/**
+ * PSC_I2S_FORMATS: audio formats supported by the PSC I2S mode
+ */
+#define PSC_I2S_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_BE | \
+			 SNDRV_PCM_FMTBIT_S24_BE | SNDRV_PCM_FMTBIT_S24_BE | \
+			 SNDRV_PCM_FMTBIT_S32_BE)
+
+/**
+ * psc_i2s_stream - Data specific to a single stream (playback or capture)
+ * @active:		flag indicating if the stream is active
+ * @psc_i2s:		pointer back to parent psc_i2s data structure
+ * @bcom_task:		bestcomm task structure
+ * @irq:		irq number for bestcomm task
+ * @period_start:	physical address of start of DMA region
+ * @period_end:		physical address of end of DMA region
+ * @period_next_pt:	physical address of next DMA buffer to enqueue
+ * @period_bytes:	size of DMA period in bytes
+ */
+struct psc_i2s_stream {
+	int active;
+	struct psc_i2s *psc_i2s;
+	struct bcom_task *bcom_task;
+	int irq;
+	struct snd_pcm_substream *stream;
+	dma_addr_t period_start;
+	dma_addr_t period_end;
+	dma_addr_t period_next_pt;
+	dma_addr_t period_current_pt;
+	int period_bytes;
+};
+
+/**
+ * psc_i2s - Private driver data
+ * @name: short name for this device ("PSC0", "PSC1", etc)
+ * @psc_regs: pointer to the PSC's registers
+ * @fifo_regs: pointer to the PSC's FIFO registers
+ * @irq: IRQ of this PSC
+ * @dev: struct device pointer
+ * @dai: the CPU DAI for this device
+ * @sicr: Base value used in serial interface control register; mode is ORed
+ *        with this value.
+ * @playback: Playback stream context data
+ * @capture: Capture stream context data
+ */
+struct psc_i2s {
+	char name[32];
+	struct mpc52xx_psc __iomem *psc_regs;
+	struct mpc52xx_psc_fifo __iomem *fifo_regs;
+	unsigned int irq;
+	struct device *dev;
+	struct snd_soc_dai dai;
+	spinlock_t lock;
+	u32 sicr;
+
+	/* per-stream data */
+	struct psc_i2s_stream playback;
+	struct psc_i2s_stream capture;
+
+	/* Statistics */
+	struct {
+		int overrun_count;
+		int underrun_count;
+	} stats;
+};
+
+/*
+ * Interrupt handlers
+ */
+static irqreturn_t psc_i2s_status_irq(int irq, void *_psc_i2s)
+{
+	struct psc_i2s *psc_i2s = _psc_i2s;
+	struct mpc52xx_psc __iomem *regs = psc_i2s->psc_regs;
+	u16 isr;
+
+	isr = in_be16(&regs->mpc52xx_psc_isr);
+
+	/* Playback underrun error */
+	if (psc_i2s->playback.active && (isr & MPC52xx_PSC_IMR_TXEMP))
+		psc_i2s->stats.underrun_count++;
+
+	/* Capture overrun error */
+	if (psc_i2s->capture.active && (isr & MPC52xx_PSC_IMR_ORERR))
+		psc_i2s->stats.overrun_count++;
+
+	out_8(&regs->command, 4 << 4);	/* reset the error status */
+
+	return IRQ_HANDLED;
+}
+
+/**
+ * psc_i2s_bcom_enqueue_next_buffer - Enqueue another audio buffer
+ * @s: pointer to stream private data structure
+ *
+ * Enqueues another audio period buffer into the bestcomm queue.
+ *
+ * Note: The routine must only be called when there is space available in
+ * the queue.  Otherwise the enqueue will fail and the audio ring buffer
+ * will get out of sync
+ */
+static void psc_i2s_bcom_enqueue_next_buffer(struct psc_i2s_stream *s)
+{
+	struct bcom_bd *bd;
+
+	/* Prepare and enqueue the next buffer descriptor */
+	bd = bcom_prepare_next_buffer(s->bcom_task);
+	bd->status = s->period_bytes;
+	bd->data[0] = s->period_next_pt;
+	bcom_submit_next_buffer(s->bcom_task, NULL);
+
+	/* Update for next period */
+	s->period_next_pt += s->period_bytes;
+	if (s->period_next_pt >= s->period_end)
+		s->period_next_pt = s->period_start;
+}
+
+/* Bestcomm DMA irq handler */
+static irqreturn_t psc_i2s_bcom_irq(int irq, void *_psc_i2s_stream)
+{
+	struct psc_i2s_stream *s = _psc_i2s_stream;
+
+	/* For each finished period, dequeue the completed period buffer
+	 * and enqueue a new one in it's place. */
+	while (bcom_buffer_done(s->bcom_task)) {
+		bcom_retrieve_buffer(s->bcom_task, NULL, NULL);
+		s->period_current_pt += s->period_bytes;
+		if (s->period_current_pt >= s->period_end)
+			s->period_current_pt = s->period_start;
+		psc_i2s_bcom_enqueue_next_buffer(s);
+		bcom_enable(s->bcom_task);
+	}
+
+	/* If the stream is active, then also inform the PCM middle layer
+	 * of the period finished event. */
+	if (s->active)
+		snd_pcm_period_elapsed(s->stream);
+
+	return IRQ_HANDLED;
+}
+
+/**
+ * psc_i2s_startup: create a new substream
+ *
+ * This is the first function called when a stream is opened.
+ *
+ * If this is the first stream open, then grab the IRQ and program most of
+ * the PSC registers.
+ */
+static int psc_i2s_startup(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct psc_i2s *psc_i2s = rtd->dai->cpu_dai->private_data;
+	int rc;
+
+	dev_dbg(psc_i2s->dev, "psc_i2s_startup(substream=%p)\n", substream);
+
+	if (!psc_i2s->playback.active &&
+	    !psc_i2s->capture.active) {
+		/* Setup the IRQs */
+		rc = request_irq(psc_i2s->irq, &psc_i2s_status_irq, IRQF_SHARED,
+				 "psc-i2s-status", psc_i2s);
+		rc |= request_irq(psc_i2s->capture.irq,
+				  &psc_i2s_bcom_irq, IRQF_SHARED,
+				  "psc-i2s-capture", &psc_i2s->capture);
+		rc |= request_irq(psc_i2s->playback.irq,
+				  &psc_i2s_bcom_irq, IRQF_SHARED,
+				  "psc-i2s-playback", &psc_i2s->playback);
+		if (rc) {
+			free_irq(psc_i2s->irq, psc_i2s);
+			free_irq(psc_i2s->capture.irq,
+				 &psc_i2s->capture);
+			free_irq(psc_i2s->playback.irq,
+				 &psc_i2s->playback);
+			return -ENODEV;
+		}
+	}
+
+	return 0;
+}
+
+static int psc_i2s_hw_params(struct snd_pcm_substream *substream,
+				 struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct psc_i2s *psc_i2s = rtd->dai->cpu_dai->private_data;
+	u32 mode;
+
+	dev_dbg(psc_i2s->dev, "%s(substream=%p) p_size=%i p_bytes=%i"
+		" periods=%i buffer_size=%i  buffer_bytes=%i\n",
+		__func__, substream, params_period_size(params),
+		params_period_bytes(params), params_periods(params),
+		params_buffer_size(params), params_buffer_bytes(params));
+
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S8:
+		mode = MPC52xx_PSC_SICR_SIM_CODEC_8;
+		break;
+	case SNDRV_PCM_FORMAT_S16_BE:
+		mode = MPC52xx_PSC_SICR_SIM_CODEC_16;
+		break;
+	case SNDRV_PCM_FORMAT_S24_BE:
+		mode = MPC52xx_PSC_SICR_SIM_CODEC_24;
+		break;
+	case SNDRV_PCM_FORMAT_S32_BE:
+		mode = MPC52xx_PSC_SICR_SIM_CODEC_32;
+		break;
+	default:
+		dev_dbg(psc_i2s->dev, "invalid format\n");
+		return -EINVAL;
+	}
+	out_be32(&psc_i2s->psc_regs->sicr, psc_i2s->sicr | mode);
+
+	snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
+
+	return 0;
+}
+
+static int psc_i2s_hw_free(struct snd_pcm_substream *substream)
+{
+	snd_pcm_set_runtime_buffer(substream, NULL);
+	return 0;
+}
+
+/**
+ * psc_i2s_trigger: start and stop the DMA transfer.
+ *
+ * This function is called by ALSA to start, stop, pause, and resume the DMA
+ * transfer of data.
+ */
+static int psc_i2s_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct psc_i2s *psc_i2s = rtd->dai->cpu_dai->private_data;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct psc_i2s_stream *s;
+	struct mpc52xx_psc __iomem *regs = psc_i2s->psc_regs;
+	u16 imr;
+	u8 psc_cmd;
+	long flags;
+
+	if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE)
+		s = &psc_i2s->capture;
+	else
+		s = &psc_i2s->playback;
+
+	dev_dbg(psc_i2s->dev, "psc_i2s_trigger(substream=%p, cmd=%i)"
+		" stream_id=%i\n",
+		substream, cmd, substream->pstr->stream);
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+		s->period_bytes = frames_to_bytes(runtime,
+						  runtime->period_size);
+		s->period_start = virt_to_phys(runtime->dma_area);
+		s->period_end = s->period_start +
+				(s->period_bytes * runtime->periods);
+		s->period_next_pt = s->period_start;
+		s->period_current_pt = s->period_start;
+		s->active = 1;
+
+		/* First; reset everything */
+		if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE) {
+			out_8(&regs->command, MPC52xx_PSC_RST_RX);
+			out_8(&regs->command, MPC52xx_PSC_RST_ERR_STAT);
+		} else {
+			out_8(&regs->command, MPC52xx_PSC_RST_TX);
+			out_8(&regs->command, MPC52xx_PSC_RST_ERR_STAT);
+		}
+
+		/* Next, fill up the bestcomm bd queue and enable DMA.
+		 * This will begin filling the PSC's fifo. */
+		if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE)
+			bcom_gen_bd_rx_reset(s->bcom_task);
+		else
+			bcom_gen_bd_tx_reset(s->bcom_task);
+		while (!bcom_queue_full(s->bcom_task))
+			psc_i2s_bcom_enqueue_next_buffer(s);
+		bcom_enable(s->bcom_task);
+
+		/* Due to errata in the i2s mode; need to line up enabling
+		 * the transmitter with a transition on the frame sync
+		 * line */
+
+		spin_lock_irqsave(&psc_i2s->lock, flags);
+		/* first make sure it is low */
+		while ((in_8(&regs->ipcr_acr.ipcr) & 0x80) != 0)
+			;
+		/* then wait for the transition to high */
+		while ((in_8(&regs->ipcr_acr.ipcr) & 0x80) == 0)
+			;
+		/* Finally, enable the PSC.
+		 * Receiver must always be enabled; even when we only want
+		 * transmit.  (see 15.3.2.3 of MPC5200B User's Guide) */
+		psc_cmd = MPC52xx_PSC_RX_ENABLE;
+		if (substream->pstr->stream == SNDRV_PCM_STREAM_PLAYBACK)
+			psc_cmd |= MPC52xx_PSC_TX_ENABLE;
+		out_8(&regs->command, psc_cmd);
+		spin_unlock_irqrestore(&psc_i2s->lock, flags);
+
+		break;
+
+	case SNDRV_PCM_TRIGGER_STOP:
+		/* Turn off the PSC */
+		s->active = 0;
+		if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE) {
+			if (!psc_i2s->playback.active) {
+				out_8(&regs->command, 2 << 4);	/* reset rx */
+				out_8(&regs->command, 3 << 4);	/* reset tx */
+				out_8(&regs->command, 4 << 4);	/* reset err */
+			}
+		} else {
+			out_8(&regs->command, 3 << 4);	/* reset tx */
+			out_8(&regs->command, 4 << 4);	/* reset err */
+			if (!psc_i2s->capture.active)
+				out_8(&regs->command, 2 << 4);	/* reset rx */
+		}
+
+		bcom_disable(s->bcom_task);
+		while (!bcom_queue_empty(s->bcom_task))
+			bcom_retrieve_buffer(s->bcom_task, NULL, NULL);
+
+		break;
+
+	default:
+		dev_dbg(psc_i2s->dev, "invalid command\n");
+		return -EINVAL;
+	}
+
+	/* Update interrupt enable settings */
+	imr = 0;
+	if (psc_i2s->playback.active)
+		imr |= MPC52xx_PSC_IMR_TXEMP;
+	if (psc_i2s->capture.active)
+		imr |= MPC52xx_PSC_IMR_ORERR;
+	out_be16(&regs->isr_imr.imr, imr);
+
+	return 0;
+}
+
+/**
+ * psc_i2s_shutdown: shutdown the data transfer on a stream
+ *
+ * Shutdown the PSC if there are no other substreams open.
+ */
+static void psc_i2s_shutdown(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct psc_i2s *psc_i2s = rtd->dai->cpu_dai->private_data;
+
+	dev_dbg(psc_i2s->dev, "psc_i2s_shutdown(substream=%p)\n", substream);
+
+	/*
+	 * If this is the last active substream, disable the PSC and release
+	 * the IRQ.
+	 */
+	if (!psc_i2s->playback.active &&
+	    !psc_i2s->capture.active) {
+
+		/* Disable all interrupts and reset the PSC */
+		out_be16(&psc_i2s->psc_regs->isr_imr.imr, 0);
+		out_8(&psc_i2s->psc_regs->command, 3 << 4); /* reset tx */
+		out_8(&psc_i2s->psc_regs->command, 2 << 4); /* reset rx */
+		out_8(&psc_i2s->psc_regs->command, 1 << 4); /* reset mode */
+		out_8(&psc_i2s->psc_regs->command, 4 << 4); /* reset error */
+
+		/* Release irqs */
+		free_irq(psc_i2s->irq, psc_i2s);
+		free_irq(psc_i2s->capture.irq, &psc_i2s->capture);
+		free_irq(psc_i2s->playback.irq, &psc_i2s->playback);
+	}
+}
+
+/**
+ * psc_i2s_set_sysclk: set the clock frequency and direction
+ *
+ * This function is called by the machine driver to tell us what the clock
+ * frequency and direction are.
+ *
+ * Currently, we only support operating as a clock slave (SND_SOC_CLOCK_IN),
+ * and we don't care about the frequency.  Return an error if the direction
+ * is not SND_SOC_CLOCK_IN.
+ *
+ * @clk_id: reserved, should be zero
+ * @freq: the frequency of the given clock ID, currently ignored
+ * @dir: SND_SOC_CLOCK_IN (clock slave) or SND_SOC_CLOCK_OUT (clock master)
+ */
+static int psc_i2s_set_sysclk(struct snd_soc_dai *cpu_dai,
+			      int clk_id, unsigned int freq, int dir)
+{
+	struct psc_i2s *psc_i2s = cpu_dai->private_data;
+	dev_dbg(psc_i2s->dev, "psc_i2s_set_sysclk(cpu_dai=%p, dir=%i)\n",
+				cpu_dai, dir);
+	return (dir == SND_SOC_CLOCK_IN) ? 0 : -EINVAL;
+}
+
+/**
+ * psc_i2s_set_fmt: set the serial format.
+ *
+ * This function is called by the machine driver to tell us what serial
+ * format to use.
+ *
+ * This driver only supports I2S mode.  Return an error if the format is
+ * not SND_SOC_DAIFMT_I2S.
+ *
+ * @format: one of SND_SOC_DAIFMT_xxx
+ */
+static int psc_i2s_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int format)
+{
+	struct psc_i2s *psc_i2s = cpu_dai->private_data;
+	dev_dbg(psc_i2s->dev, "psc_i2s_set_fmt(cpu_dai=%p, format=%i)\n",
+				cpu_dai, format);
+	return (format == SND_SOC_DAIFMT_I2S) ? 0 : -EINVAL;
+}
+
+/* ---------------------------------------------------------------------
+ * ALSA SoC Bindings
+ *
+ * - Digital Audio Interface (DAI) template
+ * - create/destroy dai hooks
+ */
+
+/**
+ * psc_i2s_dai_template: template CPU Digital Audio Interface
+ */
+static struct snd_soc_dai psc_i2s_dai_template = {
+	.type = SND_SOC_DAI_I2S,
+	.playback = {
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = PSC_I2S_RATES,
+		.formats = PSC_I2S_FORMATS,
+	},
+	.capture = {
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = PSC_I2S_RATES,
+		.formats = PSC_I2S_FORMATS,
+	},
+	.ops = {
+		.startup = psc_i2s_startup,
+		.hw_params = psc_i2s_hw_params,
+		.hw_free = psc_i2s_hw_free,
+		.shutdown = psc_i2s_shutdown,
+		.trigger = psc_i2s_trigger,
+	},
+	.dai_ops = {
+		.set_sysclk = psc_i2s_set_sysclk,
+		.set_fmt = psc_i2s_set_fmt,
+	},
+};
+
+/* ---------------------------------------------------------------------
+ * The PSC I2S 'ASoC platform' driver
+ *
+ * Can be referenced by an 'ASoC machine' driver
+ * This driver only deals with the audio bus; it doesn't have any
+ * interaction with the attached codec
+ */
+
+static const struct snd_pcm_hardware psc_i2s_pcm_hardware = {
+	.info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
+		SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER,
+	.formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_BE |
+		   SNDRV_PCM_FMTBIT_S24_BE | SNDRV_PCM_FMTBIT_S32_BE,
+	.rate_min = 8000,
+	.rate_max = 48000,
+	.channels_min = 2,
+	.channels_max = 2,
+	.period_bytes_max	= 1024 * 1024,
+	.period_bytes_min	= 32,
+	.periods_min		= 2,
+	.periods_max		= 256,
+	.buffer_bytes_max	= 2 * 1024 * 1024,
+	.fifo_size		= 0,
+};
+
+static int psc_i2s_pcm_open(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct psc_i2s *psc_i2s = rtd->dai->cpu_dai->private_data;
+	struct psc_i2s_stream *s;
+
+	dev_dbg(psc_i2s->dev, "psc_i2s_pcm_open(substream=%p)\n", substream);
+
+	if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE)
+		s = &psc_i2s->capture;
+	else
+		s = &psc_i2s->playback;
+
+	snd_soc_set_runtime_hwparams(substream, &psc_i2s_pcm_hardware);
+
+	s->stream = substream;
+	return 0;
+}
+
+static int psc_i2s_pcm_close(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct psc_i2s *psc_i2s = rtd->dai->cpu_dai->private_data;
+	struct psc_i2s_stream *s;
+
+	dev_dbg(psc_i2s->dev, "psc_i2s_pcm_close(substream=%p)\n", substream);
+
+	if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE)
+		s = &psc_i2s->capture;
+	else
+		s = &psc_i2s->playback;
+
+	s->stream = NULL;
+	return 0;
+}
+
+static snd_pcm_uframes_t
+psc_i2s_pcm_pointer(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct psc_i2s *psc_i2s = rtd->dai->cpu_dai->private_data;
+	struct psc_i2s_stream *s;
+	dma_addr_t count;
+
+	if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE)
+		s = &psc_i2s->capture;
+	else
+		s = &psc_i2s->playback;
+
+	count = s->period_current_pt - s->period_start;
+
+	return bytes_to_frames(substream->runtime, count);
+}
+
+static struct snd_pcm_ops psc_i2s_pcm_ops = {
+	.open		= psc_i2s_pcm_open,
+	.close		= psc_i2s_pcm_close,
+	.ioctl		= snd_pcm_lib_ioctl,
+	.pointer	= psc_i2s_pcm_pointer,
+};
+
+static u64 psc_i2s_pcm_dmamask = 0xffffffff;
+static int psc_i2s_pcm_new(struct snd_card *card, struct snd_soc_dai *dai,
+			   struct snd_pcm *pcm)
+{
+	struct snd_soc_pcm_runtime *rtd = pcm->private_data;
+	size_t size = psc_i2s_pcm_hardware.buffer_bytes_max;
+	int rc = 0;
+
+	dev_dbg(rtd->socdev->dev, "psc_i2s_pcm_new(card=%p, dai=%p, pcm=%p)\n",
+		card, dai, pcm);
+
+	if (!card->dev->dma_mask)
+		card->dev->dma_mask = &psc_i2s_pcm_dmamask;
+	if (!card->dev->coherent_dma_mask)
+		card->dev->coherent_dma_mask = 0xffffffff;
+
+	if (pcm->streams[0].substream) {
+		rc = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, pcm->dev, size,
+					&pcm->streams[0].substream->dma_buffer);
+		if (rc)
+			goto playback_alloc_err;
+	}
+
+	if (pcm->streams[1].substream) {
+		rc = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, pcm->dev, size,
+					&pcm->streams[1].substream->dma_buffer);
+		if (rc)
+			goto capture_alloc_err;
+	}
+
+	return 0;
+
+ capture_alloc_err:
+	if (pcm->streams[0].substream)
+		snd_dma_free_pages(&pcm->streams[0].substream->dma_buffer);
+ playback_alloc_err:
+	dev_err(card->dev, "Cannot allocate buffer(s)\n");
+	return -ENOMEM;
+}
+
+static void psc_i2s_pcm_free(struct snd_pcm *pcm)
+{
+	struct snd_soc_pcm_runtime *rtd = pcm->private_data;
+	struct snd_pcm_substream *substream;
+	int stream;
+
+	dev_dbg(rtd->socdev->dev, "psc_i2s_pcm_free(pcm=%p)\n", pcm);
+
+	for (stream = 0; stream < 2; stream++) {
+		substream = pcm->streams[stream].substream;
+		if (substream) {
+			snd_dma_free_pages(&substream->dma_buffer);
+			substream->dma_buffer.area = NULL;
+			substream->dma_buffer.addr = 0;
+		}
+	}
+}
+
+struct snd_soc_platform psc_i2s_pcm_soc_platform = {
+	.name		= "mpc5200-psc-audio",
+	.pcm_ops	= &psc_i2s_pcm_ops,
+	.pcm_new	= &psc_i2s_pcm_new,
+	.pcm_free	= &psc_i2s_pcm_free,
+};
+
+/* ---------------------------------------------------------------------
+ * Sysfs attributes for debugging
+ */
+
+static ssize_t psc_i2s_status_show(struct device *dev,
+			   struct device_attribute *attr, char *buf)
+{
+	struct psc_i2s *psc_i2s = dev_get_drvdata(dev);
+
+	return sprintf(buf, "status=%.4x sicr=%.8x rfnum=%i rfstat=0x%.4x "
+			"tfnum=%i tfstat=0x%.4x\n",
+			in_be16(&psc_i2s->psc_regs->sr_csr.status),
+			in_be32(&psc_i2s->psc_regs->sicr),
+			in_be16(&psc_i2s->fifo_regs->rfnum) & 0x1ff,
+			in_be16(&psc_i2s->fifo_regs->rfstat),
+			in_be16(&psc_i2s->fifo_regs->tfnum) & 0x1ff,
+			in_be16(&psc_i2s->fifo_regs->tfstat));
+}
+
+static int *psc_i2s_get_stat_attr(struct psc_i2s *psc_i2s, const char *name)
+{
+	if (strcmp(name, "playback_underrun") == 0)
+		return &psc_i2s->stats.underrun_count;
+	if (strcmp(name, "capture_overrun") == 0)
+		return &psc_i2s->stats.overrun_count;
+
+	return NULL;
+}
+
+static ssize_t psc_i2s_stat_show(struct device *dev,
+				 struct device_attribute *attr, char *buf)
+{
+	struct psc_i2s *psc_i2s = dev_get_drvdata(dev);
+	int *attrib;
+
+	attrib = psc_i2s_get_stat_attr(psc_i2s, attr->attr.name);
+	if (!attrib)
+		return 0;
+
+	return sprintf(buf, "%i\n", *attrib);
+}
+
+static ssize_t psc_i2s_stat_store(struct device *dev,
+				  struct device_attribute *attr,
+				  const char *buf,
+				  size_t count)
+{
+	struct psc_i2s *psc_i2s = dev_get_drvdata(dev);
+	int *attrib;
+
+	attrib = psc_i2s_get_stat_attr(psc_i2s, attr->attr.name);
+	if (!attrib)
+		return 0;
+
+	*attrib = simple_strtoul(buf, NULL, 0);
+	return count;
+}
+
+DEVICE_ATTR(status, 0644, psc_i2s_status_show, NULL);
+DEVICE_ATTR(playback_underrun, 0644, psc_i2s_stat_show, psc_i2s_stat_store);
+DEVICE_ATTR(capture_overrun, 0644, psc_i2s_stat_show, psc_i2s_stat_store);
+
+/* ---------------------------------------------------------------------
+ * OF platform bus binding code:
+ * - Probe/remove operations
+ * - OF device match table
+ */
+static int __devinit psc_i2s_of_probe(struct of_device *op,
+				      const struct of_device_id *match)
+{
+	phys_addr_t fifo;
+	struct psc_i2s *psc_i2s;
+	struct resource res;
+	int size, psc_id, irq, rc;
+	const __be32 *prop;
+	void __iomem *regs;
+
+	dev_dbg(&op->dev, "probing psc i2s device\n");
+
+	/* Get the PSC ID */
+	prop = of_get_property(op->node, "cell-index", &size);
+	if (!prop || size < sizeof *prop)
+		return -ENODEV;
+	psc_id = be32_to_cpu(*prop);
+
+	/* Fetch the registers and IRQ of the PSC */
+	irq = irq_of_parse_and_map(op->node, 0);
+	if (of_address_to_resource(op->node, 0, &res)) {
+		dev_err(&op->dev, "Missing reg property\n");
+		return -ENODEV;
+	}
+	regs = ioremap(res.start, 1 + res.end - res.start);
+	if (!regs) {
+		dev_err(&op->dev, "Could not map registers\n");
+		return -ENODEV;
+	}
+
+	/* Allocate and initialize the driver private data */
+	psc_i2s = kzalloc(sizeof *psc_i2s, GFP_KERNEL);
+	if (!psc_i2s) {
+		iounmap(regs);
+		return -ENOMEM;
+	}
+	spin_lock_init(&psc_i2s->lock);
+	psc_i2s->irq = irq;
+	psc_i2s->psc_regs = regs;
+	psc_i2s->fifo_regs = regs + sizeof *psc_i2s->psc_regs;
+	psc_i2s->dev = &op->dev;
+	psc_i2s->playback.psc_i2s = psc_i2s;
+	psc_i2s->capture.psc_i2s = psc_i2s;
+	snprintf(psc_i2s->name, sizeof psc_i2s->name, "PSC%u", psc_id+1);
+
+	/* Fill out the CPU DAI structure */
+	memcpy(&psc_i2s->dai, &psc_i2s_dai_template, sizeof psc_i2s->dai);
+	psc_i2s->dai.private_data = psc_i2s;
+	psc_i2s->dai.name = psc_i2s->name;
+	psc_i2s->dai.id = psc_id;
+
+	/* Find the address of the fifo data registers and setup the
+	 * DMA tasks */
+	fifo = res.start + offsetof(struct mpc52xx_psc, buffer.buffer_32);
+	psc_i2s->capture.bcom_task =
+		bcom_psc_gen_bd_rx_init(psc_id, 10, fifo, 512);
+	psc_i2s->playback.bcom_task =
+		bcom_psc_gen_bd_tx_init(psc_id, 10, fifo);
+	if (!psc_i2s->capture.bcom_task ||
+	    !psc_i2s->playback.bcom_task) {
+		dev_err(&op->dev, "Could not allocate bestcomm tasks\n");
+		iounmap(regs);
+		kfree(psc_i2s);
+		return -ENODEV;
+	}
+
+	/* Disable all interrupts and reset the PSC */
+	out_be16(&psc_i2s->psc_regs->isr_imr.imr, 0);
+	out_8(&psc_i2s->psc_regs->command, 3 << 4); /* reset transmitter */
+	out_8(&psc_i2s->psc_regs->command, 2 << 4); /* reset receiver */
+	out_8(&psc_i2s->psc_regs->command, 1 << 4); /* reset mode */
+	out_8(&psc_i2s->psc_regs->command, 4 << 4); /* reset error */
+
+	/* Configure the serial interface mode; defaulting to CODEC8 mode */
+	psc_i2s->sicr = MPC52xx_PSC_SICR_DTS1 | MPC52xx_PSC_SICR_I2S |
+			MPC52xx_PSC_SICR_CLKPOL;
+	if (of_get_property(op->node, "fsl,cellslave", NULL))
+		psc_i2s->sicr |= MPC52xx_PSC_SICR_CELLSLAVE |
+				 MPC52xx_PSC_SICR_GENCLK;
+	out_be32(&psc_i2s->psc_regs->sicr,
+		 psc_i2s->sicr | MPC52xx_PSC_SICR_SIM_CODEC_8);
+
+	/* Check for the codec handle.  If it is not present then we
+	 * are done */
+	if (!of_get_property(op->node, "codec-handle", NULL))
+		return 0;
+
+	/* Set up mode register;
+	 * First write: RxRdy (FIFO Alarm) generates rx FIFO irq
+	 * Second write: register Normal mode for non loopback
+	 */
+	out_8(&psc_i2s->psc_regs->mode, 0);
+	out_8(&psc_i2s->psc_regs->mode, 0);
+
+	/* Set the TX and RX fifo alarm thresholds */
+	out_be16(&psc_i2s->fifo_regs->rfalarm, 0x100);
+	out_8(&psc_i2s->fifo_regs->rfcntl, 0x4);
+	out_be16(&psc_i2s->fifo_regs->tfalarm, 0x100);
+	out_8(&psc_i2s->fifo_regs->tfcntl, 0x7);
+
+	/* Lookup the IRQ numbers */
+	psc_i2s->playback.irq =
+		bcom_get_task_irq(psc_i2s->playback.bcom_task);
+	psc_i2s->capture.irq =
+		bcom_get_task_irq(psc_i2s->capture.bcom_task);
+
+	/* Save what we've done so it can be found again later */
+	dev_set_drvdata(&op->dev, psc_i2s);
+
+	/* Register the SYSFS files */
+	rc = device_create_file(psc_i2s->dev, &dev_attr_status);
+	rc = device_create_file(psc_i2s->dev, &dev_attr_capture_overrun);
+	rc = device_create_file(psc_i2s->dev, &dev_attr_playback_underrun);
+	if (rc)
+		dev_info(psc_i2s->dev, "error creating sysfs files\n");
+
+	/* Tell the ASoC OF helpers about it */
+	of_snd_soc_register_platform(&psc_i2s_pcm_soc_platform, op->node,
+				     &psc_i2s->dai);
+
+	return 0;
+}
+
+static int __devexit psc_i2s_of_remove(struct of_device *op)
+{
+	struct psc_i2s *psc_i2s = dev_get_drvdata(&op->dev);
+
+	dev_dbg(&op->dev, "psc_i2s_remove()\n");
+
+	bcom_gen_bd_rx_release(psc_i2s->capture.bcom_task);
+	bcom_gen_bd_tx_release(psc_i2s->playback.bcom_task);
+
+	iounmap(psc_i2s->psc_regs);
+	iounmap(psc_i2s->fifo_regs);
+	kfree(psc_i2s);
+	dev_set_drvdata(&op->dev, NULL);
+
+	return 0;
+}
+
+/* Match table for of_platform binding */
+static struct of_device_id psc_i2s_match[] __devinitdata = {
+	{ .compatible = "fsl,mpc5200-psc-i2s", },
+	{}
+};
+MODULE_DEVICE_TABLE(of, psc_i2s_match);
+
+static struct of_platform_driver psc_i2s_driver = {
+	.match_table = psc_i2s_match,
+	.probe = psc_i2s_of_probe,
+	.remove = __devexit_p(psc_i2s_of_remove),
+	.driver = {
+		.name = "mpc5200-psc-i2s",
+		.owner = THIS_MODULE,
+	},
+};
+
+/* ---------------------------------------------------------------------
+ * Module setup and teardown; simply register the of_platform driver
+ * for the PSC in I2S mode.
+ */
+static int __init psc_i2s_init(void)
+{
+	return of_register_platform_driver(&psc_i2s_driver);
+}
+module_init(psc_i2s_init);
+
+static void __exit psc_i2s_exit(void)
+{
+	of_unregister_platform_driver(&psc_i2s_driver);
+}
+module_exit(psc_i2s_exit);
+
+
diff --git a/sound/soc/fsl/mpc8610_hpcd.c b/sound/soc/fsl/mpc8610_hpcd.c
index 4bdc9d8..94f89de 100644
--- a/sound/soc/fsl/mpc8610_hpcd.c
+++ b/sound/soc/fsl/mpc8610_hpcd.c
@@ -68,10 +68,6 @@
 	guts_set_pmuxcr_dma(machine_data->guts, machine_data->dma_id,
 		machine_data->dma_channel_id[1], 0);
 
-	guts_set_pmuxcr_dma(machine_data->guts, 1, 0, 0);
-	guts_set_pmuxcr_dma(machine_data->guts, 1, 3, 0);
-	guts_set_pmuxcr_dma(machine_data->guts, 0, 3, 0);
-
 	switch (machine_data->ssi_id) {
 	case 0:
 		clrsetbits_be32(&machine_data->guts->pmuxcr,
@@ -230,6 +226,8 @@
 	struct fsl_ssi_info ssi_info;
 	struct fsl_dma_info dma_info;
 	int ret = -ENODEV;
+	unsigned int playback_dma_channel;
+	unsigned int capture_dma_channel;
 
 	machine_data = kzalloc(sizeof(struct mpc8610_hpcd_data), GFP_KERNEL);
 	if (!machine_data)
@@ -381,8 +379,9 @@
 		goto error;
 	}
 
-	/* Find the DMA channels to use.  For now, we always use the first DMA
-	   controller. */
+	/* Find the DMA channels to use.  Both SSIs need to use the same DMA
+	 * controller, so let's use DMA#1.
+	 */
 	for_each_compatible_node(dma_np, NULL, "fsl,mpc8610-dma") {
 		iprop = of_get_property(dma_np, "cell-index", NULL);
 		if (iprop && (*iprop == 0)) {
@@ -397,14 +396,19 @@
 	}
 	machine_data->dma_id = *iprop;
 
+	/* SSI1 needs to use DMA Channels 0 and 1, and SSI2 needs to use DMA
+	 * channels 2 and 3.  This is just how the MPC8610 is wired
+	 * internally.
+	 */
+	playback_dma_channel = (machine_data->ssi_id == 0) ? 0 : 2;
+	capture_dma_channel = (machine_data->ssi_id == 0) ? 1 : 3;
+
 	/*
-	 * Find the DMA channels to use.  For now, we always use DMA channel 0
-	 * for playback, and DMA channel 1 for capture.
+	 * Find the DMA channels to use.
 	 */
 	while ((dma_channel_np = of_get_next_child(dma_np, dma_channel_np))) {
 		iprop = of_get_property(dma_channel_np, "cell-index", NULL);
-		/* Is it DMA channel 0? */
-		if (iprop && (*iprop == 0)) {
+		if (iprop && (*iprop == playback_dma_channel)) {
 			/* dma_channel[0] and dma_irq[0] are for playback */
 			dma_info.dma_channel[0] = of_iomap(dma_channel_np, 0);
 			dma_info.dma_irq[0] =
@@ -412,7 +416,7 @@
 			machine_data->dma_channel_id[0] = *iprop;
 			continue;
 		}
-		if (iprop && (*iprop == 1)) {
+		if (iprop && (*iprop == capture_dma_channel)) {
 			/* dma_channel[1] and dma_irq[1] are for capture */
 			dma_info.dma_channel[1] = of_iomap(dma_channel_np, 0);
 			dma_info.dma_irq[1] =
diff --git a/sound/soc/fsl/soc-of-simple.c b/sound/soc/fsl/soc-of-simple.c
new file mode 100644
index 0000000..0382fda
--- /dev/null
+++ b/sound/soc/fsl/soc-of-simple.c
@@ -0,0 +1,171 @@
+/*
+ * OF helpers for ALSA SoC Layer
+ *
+ * Copyright (C) 2008, Secret Lab Technologies Ltd.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/bitops.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-of-simple.h>
+#include <sound/initval.h>
+
+MODULE_AUTHOR("Grant Likely <grant.likely@secretlab.ca>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("ALSA SoC OpenFirmware bindings");
+
+static DEFINE_MUTEX(of_snd_soc_mutex);
+static LIST_HEAD(of_snd_soc_device_list);
+static int of_snd_soc_next_index;
+
+struct of_snd_soc_device {
+	int id;
+	struct list_head list;
+	struct snd_soc_device device;
+	struct snd_soc_machine machine;
+	struct snd_soc_dai_link dai_link;
+	struct platform_device *pdev;
+	struct device_node *platform_node;
+	struct device_node *codec_node;
+};
+
+static struct snd_soc_ops of_snd_soc_ops = {
+};
+
+static struct of_snd_soc_device *
+of_snd_soc_get_device(struct device_node *codec_node)
+{
+	struct of_snd_soc_device *of_soc;
+
+	list_for_each_entry(of_soc, &of_snd_soc_device_list, list) {
+		if (of_soc->codec_node == codec_node)
+			return of_soc;
+	}
+
+	of_soc = kzalloc(sizeof(struct of_snd_soc_device), GFP_KERNEL);
+	if (!of_soc)
+		return NULL;
+
+	/* Initialize the structure and add it to the global list */
+	of_soc->codec_node = codec_node;
+	of_soc->id = of_snd_soc_next_index++;
+	of_soc->machine.dai_link = &of_soc->dai_link;
+	of_soc->machine.num_links = 1;
+	of_soc->device.machine = &of_soc->machine;
+	of_soc->dai_link.ops = &of_snd_soc_ops;
+	list_add(&of_soc->list, &of_snd_soc_device_list);
+
+	return of_soc;
+}
+
+static void of_snd_soc_register_device(struct of_snd_soc_device *of_soc)
+{
+	struct platform_device *pdev;
+	int rc;
+
+	/* Only register the device if both the codec and platform have
+	 * been registered */
+	if ((!of_soc->device.codec_data) || (!of_soc->platform_node))
+		return;
+
+	pr_info("platform<-->codec match achieved; registering machine\n");
+
+	pdev = platform_device_alloc("soc-audio", of_soc->id);
+	if (!pdev) {
+		pr_err("of_soc: platform_device_alloc() failed\n");
+		return;
+	}
+
+	pdev->dev.platform_data = of_soc;
+	platform_set_drvdata(pdev, &of_soc->device);
+	of_soc->device.dev = &pdev->dev;
+
+	/* The ASoC device is complete; register it */
+	rc = platform_device_add(pdev);
+	if (rc) {
+		pr_err("of_soc: platform_device_add() failed\n");
+		return;
+	}
+
+}
+
+int of_snd_soc_register_codec(struct snd_soc_codec_device *codec_dev,
+			      void *codec_data, struct snd_soc_dai *dai,
+			      struct device_node *node)
+{
+	struct of_snd_soc_device *of_soc;
+	int rc = 0;
+
+	pr_info("registering ASoC codec driver: %s\n", node->full_name);
+
+	mutex_lock(&of_snd_soc_mutex);
+	of_soc = of_snd_soc_get_device(node);
+	if (!of_soc) {
+		rc = -ENOMEM;
+		goto out;
+	}
+
+	/* Store the codec data */
+	of_soc->device.codec_data = codec_data;
+	of_soc->device.codec_dev = codec_dev;
+	of_soc->dai_link.name = (char *)node->name;
+	of_soc->dai_link.stream_name = (char *)node->name;
+	of_soc->dai_link.codec_dai = dai;
+
+	/* Now try to register the SoC device */
+	of_snd_soc_register_device(of_soc);
+
+ out:
+	mutex_unlock(&of_snd_soc_mutex);
+	return rc;
+}
+EXPORT_SYMBOL_GPL(of_snd_soc_register_codec);
+
+int of_snd_soc_register_platform(struct snd_soc_platform *platform,
+				 struct device_node *node,
+				 struct snd_soc_dai *cpu_dai)
+{
+	struct of_snd_soc_device *of_soc;
+	struct device_node *codec_node;
+	const phandle *handle;
+	int len, rc = 0;
+
+	pr_info("registering ASoC platform driver: %s\n", node->full_name);
+
+	handle = of_get_property(node, "codec-handle", &len);
+	if (!handle || len < sizeof(handle))
+		return -ENODEV;
+	codec_node = of_find_node_by_phandle(*handle);
+	if (!codec_node)
+		return -ENODEV;
+	pr_info("looking for codec: %s\n", codec_node->full_name);
+
+	mutex_lock(&of_snd_soc_mutex);
+	of_soc = of_snd_soc_get_device(codec_node);
+	if (!of_soc) {
+		rc = -ENOMEM;
+		goto out;
+	}
+
+	of_soc->platform_node = node;
+	of_soc->dai_link.cpu_dai = cpu_dai;
+	of_soc->device.platform = platform;
+	of_soc->machine.name = of_soc->dai_link.cpu_dai->name;
+
+	/* Now try to register the SoC device */
+	of_snd_soc_register_device(of_soc);
+
+ out:
+	mutex_unlock(&of_snd_soc_mutex);
+	return rc;
+}
+EXPORT_SYMBOL_GPL(of_snd_soc_register_platform);
diff --git a/sound/soc/omap/Kconfig b/sound/soc/omap/Kconfig
index aea27e7..8b7766b 100644
--- a/sound/soc/omap/Kconfig
+++ b/sound/soc/omap/Kconfig
@@ -13,3 +13,11 @@
 	select SND_SOC_TLV320AIC3X
 	help
 	  Say Y if you want to add support for SoC audio on Nokia N810.
+
+config SND_OMAP_SOC_OSK5912
+	tristate "SoC Audio support for omap osk5912"
+	depends on SND_OMAP_SOC && MACH_OMAP_OSK
+	select SND_OMAP_SOC_MCBSP
+	select SND_SOC_TLV320AIC23
+	help
+	  Say Y if you want to add support for SoC audio on osk5912.
diff --git a/sound/soc/omap/Makefile b/sound/soc/omap/Makefile
index d8d8d58..e09d1f2 100644
--- a/sound/soc/omap/Makefile
+++ b/sound/soc/omap/Makefile
@@ -7,5 +7,7 @@
 
 # OMAP Machine Support
 snd-soc-n810-objs := n810.o
+snd-soc-osk5912-objs := osk5912.o
 
 obj-$(CONFIG_SND_OMAP_SOC_N810) += snd-soc-n810.o
+obj-$(CONFIG_SND_OMAP_SOC_OSK5912) += snd-soc-osk5912.o
diff --git a/sound/soc/omap/n810.c b/sound/soc/omap/n810.c
index 87d0ed0..fae3ad3 100644
--- a/sound/soc/omap/n810.c
+++ b/sound/soc/omap/n810.c
@@ -247,9 +247,9 @@
 	int i, err;
 
 	/* Not connected */
-	snd_soc_dapm_disable_pin(codec, "MONO_LOUT");
-	snd_soc_dapm_disable_pin(codec, "HPLCOM");
-	snd_soc_dapm_disable_pin(codec, "HPRCOM");
+	snd_soc_dapm_nc_pin(codec, "MONO_LOUT");
+	snd_soc_dapm_nc_pin(codec, "HPLCOM");
+	snd_soc_dapm_nc_pin(codec, "HPRCOM");
 
 	/* Add N810 specific controls */
 	for (i = 0; i < ARRAY_SIZE(aic33_n810_controls); i++) {
@@ -290,6 +290,7 @@
 
 /* Audio private data */
 static struct aic3x_setup_data n810_aic33_setup = {
+	.i2c_bus = 2,
 	.i2c_address = 0x18,
 	.gpio_func[0] = AIC3X_GPIO1_FUNC_DISABLED,
 	.gpio_func[1] = AIC3X_GPIO2_FUNC_DIGITAL_MIC_INPUT,
diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/omap/omap-mcbsp.c
index 35310e1..0a063a9 100644
--- a/sound/soc/omap/omap-mcbsp.c
+++ b/sound/soc/omap/omap-mcbsp.c
@@ -59,12 +59,7 @@
  * Stream DMA parameters. DMA request line and port address are set runtime
  * since they are different between OMAP1 and later OMAPs
  */
-static struct omap_pcm_dma_data omap_mcbsp_dai_dma_params[NUM_LINKS][2] = {
-{
-	{ .name		= "I2S PCM Stereo out", },
-	{ .name		= "I2S PCM Stereo in", },
-},
-};
+static struct omap_pcm_dma_data omap_mcbsp_dai_dma_params[NUM_LINKS][2];
 
 #if defined(CONFIG_ARCH_OMAP15XX) || defined(CONFIG_ARCH_OMAP16XX)
 static const int omap1_dma_reqs[][2] = {
@@ -84,11 +79,22 @@
 static const int omap1_dma_reqs[][2] = {};
 static const unsigned long omap1_mcbsp_port[][2] = {};
 #endif
-#if defined(CONFIG_ARCH_OMAP2420)
-static const int omap2420_dma_reqs[][2] = {
+
+#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX)
+static const int omap24xx_dma_reqs[][2] = {
 	{ OMAP24XX_DMA_MCBSP1_TX, OMAP24XX_DMA_MCBSP1_RX },
 	{ OMAP24XX_DMA_MCBSP2_TX, OMAP24XX_DMA_MCBSP2_RX },
+#if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP34XX)
+	{ OMAP24XX_DMA_MCBSP3_TX, OMAP24XX_DMA_MCBSP3_RX },
+	{ OMAP24XX_DMA_MCBSP4_TX, OMAP24XX_DMA_MCBSP4_RX },
+	{ OMAP24XX_DMA_MCBSP5_TX, OMAP24XX_DMA_MCBSP5_RX },
+#endif
 };
+#else
+static const int omap24xx_dma_reqs[][2] = {};
+#endif
+
+#if defined(CONFIG_ARCH_OMAP2420)
 static const unsigned long omap2420_mcbsp_port[][2] = {
 	{ OMAP24XX_MCBSP1_BASE + OMAP_MCBSP_REG_DXR1,
 	  OMAP24XX_MCBSP1_BASE + OMAP_MCBSP_REG_DRR1 },
@@ -96,10 +102,43 @@
 	  OMAP24XX_MCBSP2_BASE + OMAP_MCBSP_REG_DRR1 },
 };
 #else
-static const int omap2420_dma_reqs[][2] = {};
 static const unsigned long omap2420_mcbsp_port[][2] = {};
 #endif
 
+#if defined(CONFIG_ARCH_OMAP2430)
+static const unsigned long omap2430_mcbsp_port[][2] = {
+	{ OMAP24XX_MCBSP1_BASE + OMAP_MCBSP_REG_DXR,
+	  OMAP24XX_MCBSP1_BASE + OMAP_MCBSP_REG_DRR },
+	{ OMAP24XX_MCBSP2_BASE + OMAP_MCBSP_REG_DXR,
+	  OMAP24XX_MCBSP2_BASE + OMAP_MCBSP_REG_DRR },
+	{ OMAP2430_MCBSP3_BASE + OMAP_MCBSP_REG_DXR,
+	  OMAP2430_MCBSP3_BASE + OMAP_MCBSP_REG_DRR },
+	{ OMAP2430_MCBSP4_BASE + OMAP_MCBSP_REG_DXR,
+	  OMAP2430_MCBSP4_BASE + OMAP_MCBSP_REG_DRR },
+	{ OMAP2430_MCBSP5_BASE + OMAP_MCBSP_REG_DXR,
+	  OMAP2430_MCBSP5_BASE + OMAP_MCBSP_REG_DRR },
+};
+#else
+static const unsigned long omap2430_mcbsp_port[][2] = {};
+#endif
+
+#if defined(CONFIG_ARCH_OMAP34XX)
+static const unsigned long omap34xx_mcbsp_port[][2] = {
+	{ OMAP34XX_MCBSP1_BASE + OMAP_MCBSP_REG_DXR,
+	  OMAP34XX_MCBSP1_BASE + OMAP_MCBSP_REG_DRR },
+	{ OMAP34XX_MCBSP2_BASE + OMAP_MCBSP_REG_DXR,
+	  OMAP34XX_MCBSP2_BASE + OMAP_MCBSP_REG_DRR },
+	{ OMAP34XX_MCBSP3_BASE + OMAP_MCBSP_REG_DXR,
+	  OMAP34XX_MCBSP3_BASE + OMAP_MCBSP_REG_DRR },
+	{ OMAP34XX_MCBSP4_BASE + OMAP_MCBSP_REG_DXR,
+	  OMAP34XX_MCBSP4_BASE + OMAP_MCBSP_REG_DRR },
+	{ OMAP34XX_MCBSP5_BASE + OMAP_MCBSP_REG_DXR,
+	  OMAP34XX_MCBSP5_BASE + OMAP_MCBSP_REG_DRR },
+};
+#else
+static const unsigned long omap34xx_mcbsp_port[][2] = {};
+#endif
+
 static int omap_mcbsp_dai_startup(struct snd_pcm_substream *substream)
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
@@ -167,14 +206,19 @@
 		dma = omap1_dma_reqs[bus_id][substream->stream];
 		port = omap1_mcbsp_port[bus_id][substream->stream];
 	} else if (cpu_is_omap2420()) {
-		dma = omap2420_dma_reqs[bus_id][substream->stream];
+		dma = omap24xx_dma_reqs[bus_id][substream->stream];
 		port = omap2420_mcbsp_port[bus_id][substream->stream];
+	} else if (cpu_is_omap2430()) {
+		dma = omap24xx_dma_reqs[bus_id][substream->stream];
+		port = omap2430_mcbsp_port[bus_id][substream->stream];
+	} else if (cpu_is_omap343x()) {
+		dma = omap24xx_dma_reqs[bus_id][substream->stream];
+		port = omap34xx_mcbsp_port[bus_id][substream->stream];
 	} else {
-		/*
-		 * TODO: Add support for 2430 and 3430
-		 */
 		return -ENODEV;
 	}
+	omap_mcbsp_dai_dma_params[id][substream->stream].name =
+		substream->stream ? "Audio Capture" : "Audio Playback";
 	omap_mcbsp_dai_dma_params[id][substream->stream].dma_req = dma;
 	omap_mcbsp_dai_dma_params[id][substream->stream].port_addr = port;
 	cpu_dai->dma_data = &omap_mcbsp_dai_dma_params[id][substream->stream];
@@ -245,6 +289,11 @@
 		regs->rcr2	|= RDATDLY(1);
 		regs->xcr2	|= XDATDLY(1);
 		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		/* 0-bit data delay */
+		regs->rcr2      |= RDATDLY(0);
+		regs->xcr2      |= XDATDLY(0);
+		break;
 	default:
 		/* Unsupported data format */
 		return -EINVAL;
@@ -310,7 +359,7 @@
 				       int clk_id)
 {
 	int sel_bit;
-	u16 reg;
+	u16 reg, reg_devconf1 = OMAP243X_CONTROL_DEVCONF1;
 
 	if (cpu_class_is_omap1()) {
 		/* OMAP1's can use only external source clock */
@@ -320,6 +369,12 @@
 			return 0;
 	}
 
+	if (cpu_is_omap2420() && mcbsp_data->bus_id > 1)
+		return -EINVAL;
+
+	if (cpu_is_omap343x())
+		reg_devconf1 = OMAP343X_CONTROL_DEVCONF1;
+
 	switch (mcbsp_data->bus_id) {
 	case 0:
 		reg = OMAP2_CONTROL_DEVCONF0;
@@ -329,20 +384,26 @@
 		reg = OMAP2_CONTROL_DEVCONF0;
 		sel_bit = 6;
 		break;
-	/* TODO: Support for ports 3 - 5 in OMAP2430 and OMAP34xx */
+	case 2:
+		reg = reg_devconf1;
+		sel_bit = 0;
+		break;
+	case 3:
+		reg = reg_devconf1;
+		sel_bit = 2;
+		break;
+	case 4:
+		reg = reg_devconf1;
+		sel_bit = 4;
+		break;
 	default:
 		return -EINVAL;
 	}
 
-	if (cpu_class_is_omap2()) {
-		if (clk_id == OMAP_MCBSP_SYSCLK_CLKS_FCLK) {
-			omap_ctrl_writel(omap_ctrl_readl(reg) &
-					 ~(1 << sel_bit), reg);
-		} else {
-			omap_ctrl_writel(omap_ctrl_readl(reg) |
-					 (1 << sel_bit), reg);
-		}
-	}
+	if (clk_id == OMAP_MCBSP_SYSCLK_CLKS_FCLK)
+		omap_ctrl_writel(omap_ctrl_readl(reg) & ~(1 << sel_bit), reg);
+	else
+		omap_ctrl_writel(omap_ctrl_readl(reg) | (1 << sel_bit), reg);
 
 	return 0;
 }
@@ -376,37 +437,49 @@
 	return err;
 }
 
-struct snd_soc_dai omap_mcbsp_dai[NUM_LINKS] = {
-{
-	.name = "omap-mcbsp-dai",
-	.id = 0,
-	.type = SND_SOC_DAI_I2S,
-	.playback = {
-		.channels_min = 2,
-		.channels_max = 2,
-		.rates = OMAP_MCBSP_RATES,
-		.formats = SNDRV_PCM_FMTBIT_S16_LE,
-	},
-	.capture = {
-		.channels_min = 2,
-		.channels_max = 2,
-		.rates = OMAP_MCBSP_RATES,
-		.formats = SNDRV_PCM_FMTBIT_S16_LE,
-	},
-	.ops = {
-		.startup = omap_mcbsp_dai_startup,
-		.shutdown = omap_mcbsp_dai_shutdown,
-		.trigger = omap_mcbsp_dai_trigger,
-		.hw_params = omap_mcbsp_dai_hw_params,
-	},
-	.dai_ops = {
-		.set_fmt = omap_mcbsp_dai_set_dai_fmt,
-		.set_clkdiv = omap_mcbsp_dai_set_clkdiv,
-		.set_sysclk = omap_mcbsp_dai_set_dai_sysclk,
-	},
-	.private_data = &mcbsp_data[0].bus_id,
-},
+#define OMAP_MCBSP_DAI_BUILDER(link_id)				\
+{								\
+	.name = "omap-mcbsp-dai-(link_id)",			\
+	.id = (link_id),					\
+	.type = SND_SOC_DAI_I2S,				\
+	.playback = {						\
+		.channels_min = 2,				\
+		.channels_max = 2,				\
+		.rates = OMAP_MCBSP_RATES,			\
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,		\
+	},							\
+	.capture = {						\
+		.channels_min = 2,				\
+		.channels_max = 2,				\
+		.rates = OMAP_MCBSP_RATES,			\
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,		\
+	},							\
+	.ops = {						\
+		.startup = omap_mcbsp_dai_startup,		\
+		.shutdown = omap_mcbsp_dai_shutdown,		\
+		.trigger = omap_mcbsp_dai_trigger,		\
+		.hw_params = omap_mcbsp_dai_hw_params,		\
+	},							\
+	.dai_ops = {						\
+		.set_fmt = omap_mcbsp_dai_set_dai_fmt,		\
+		.set_clkdiv = omap_mcbsp_dai_set_clkdiv,	\
+		.set_sysclk = omap_mcbsp_dai_set_dai_sysclk,	\
+	},							\
+	.private_data = &mcbsp_data[(link_id)].bus_id,		\
+}
+
+struct snd_soc_dai omap_mcbsp_dai[] = {
+	OMAP_MCBSP_DAI_BUILDER(0),
+	OMAP_MCBSP_DAI_BUILDER(1),
+#if NUM_LINKS >= 3
+	OMAP_MCBSP_DAI_BUILDER(2),
+#endif
+#if NUM_LINKS == 5
+	OMAP_MCBSP_DAI_BUILDER(3),
+	OMAP_MCBSP_DAI_BUILDER(4),
+#endif
 };
+
 EXPORT_SYMBOL_GPL(omap_mcbsp_dai);
 
 MODULE_AUTHOR("Jarkko Nikula <jarkko.nikula@nokia.com>");
diff --git a/sound/soc/omap/omap-mcbsp.h b/sound/soc/omap/omap-mcbsp.h
index ed8afb5..df7ad13 100644
--- a/sound/soc/omap/omap-mcbsp.h
+++ b/sound/soc/omap/omap-mcbsp.h
@@ -38,11 +38,17 @@
 	OMAP_MCBSP_CLKGDV,		/* Sample rate generator divider */
 };
 
-/*
- * REVISIT: Preparation for the ASoC v2. Let the number of available links to
- * be same than number of McBSP ports found in OMAP(s) we are compiling for.
- */
-#define NUM_LINKS	1
+#if defined(CONFIG_ARCH_OMAP2420)
+#define NUM_LINKS	2
+#endif
+#if defined(CONFIG_ARCH_OMAP15XX) || defined(CONFIG_ARCH_OMAP16XX)
+#undef  NUM_LINKS
+#define NUM_LINKS	3
+#endif
+#if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP34XX)
+#undef  NUM_LINKS
+#define NUM_LINKS	5
+#endif
 
 extern struct snd_soc_dai omap_mcbsp_dai[NUM_LINKS];
 
diff --git a/sound/soc/omap/omap-pcm.c b/sound/soc/omap/omap-pcm.c
index 690bfea..e9084fd 100644
--- a/sound/soc/omap/omap-pcm.c
+++ b/sound/soc/omap/omap-pcm.c
@@ -97,7 +97,7 @@
 	prtd->dma_data = dma_data;
 	err = omap_request_dma(dma_data->dma_req, dma_data->name,
 			       omap_pcm_dma_irq, substream, &prtd->dma_ch);
-	if (!cpu_is_omap1510()) {
+	if (!err & !cpu_is_omap1510()) {
 		/*
 		 * Link channel with itself so DMA doesn't need any
 		 * reprogramming while looping the buffer
@@ -147,12 +147,14 @@
 		dma_params.src_or_dst_synch	= OMAP_DMA_DST_SYNC;
 		dma_params.src_start		= runtime->dma_addr;
 		dma_params.dst_start		= dma_data->port_addr;
+		dma_params.dst_port		= OMAP_DMA_PORT_MPUI;
 	} else {
 		dma_params.src_amode		= OMAP_DMA_AMODE_CONSTANT;
 		dma_params.dst_amode		= OMAP_DMA_AMODE_POST_INC;
 		dma_params.src_or_dst_synch	= OMAP_DMA_SRC_SYNC;
 		dma_params.src_start		= dma_data->port_addr;
 		dma_params.dst_start		= runtime->dma_addr;
+		dma_params.src_port		= OMAP_DMA_PORT_MPUI;
 	}
 	/*
 	 * Set DMA transfer frame size equal to ALSA period size and frame
diff --git a/sound/soc/omap/osk5912.c b/sound/soc/omap/osk5912.c
new file mode 100644
index 0000000..0fe7337
--- /dev/null
+++ b/sound/soc/omap/osk5912.c
@@ -0,0 +1,232 @@
+/*
+ * osk5912.c  --  SoC audio for OSK 5912
+ *
+ * Copyright (C) 2008 Mistral Solutions
+ *
+ * Contact: Arun KS  <arunks@mistralsolutions.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.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+
+#include <asm/mach-types.h>
+#include <mach/hardware.h>
+#include <linux/gpio.h>
+#include <mach/mcbsp.h>
+
+#include "omap-mcbsp.h"
+#include "omap-pcm.h"
+#include "../codecs/tlv320aic23.h"
+
+#define CODEC_CLOCK 	12000000
+
+static struct clk *tlv320aic23_mclk;
+
+static int osk_startup(struct snd_pcm_substream *substream)
+{
+	return clk_enable(tlv320aic23_mclk);
+}
+
+static void osk_shutdown(struct snd_pcm_substream *substream)
+{
+	clk_disable(tlv320aic23_mclk);
+}
+
+static int osk_hw_params(struct snd_pcm_substream *substream,
+			 struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
+	struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+	int err;
+
+	/* Set codec DAI configuration */
+	err = snd_soc_dai_set_fmt(codec_dai,
+				  SND_SOC_DAIFMT_DSP_A |
+				  SND_SOC_DAIFMT_NB_IF |
+				  SND_SOC_DAIFMT_CBM_CFM);
+	if (err < 0) {
+		printk(KERN_ERR "can't set codec DAI configuration\n");
+		return err;
+	}
+
+	/* Set cpu DAI configuration */
+	err = snd_soc_dai_set_fmt(cpu_dai,
+				  SND_SOC_DAIFMT_DSP_A |
+				  SND_SOC_DAIFMT_NB_IF |
+				  SND_SOC_DAIFMT_CBM_CFM);
+	if (err < 0) {
+		printk(KERN_ERR "can't set cpu DAI configuration\n");
+		return err;
+	}
+
+	/* Set the codec system clock for DAC and ADC */
+	err =
+	    snd_soc_dai_set_sysclk(codec_dai, 0, CODEC_CLOCK, SND_SOC_CLOCK_IN);
+
+	if (err < 0) {
+		printk(KERN_ERR "can't set codec system clock\n");
+		return err;
+	}
+
+	return err;
+}
+
+static struct snd_soc_ops osk_ops = {
+	.startup = osk_startup,
+	.hw_params = osk_hw_params,
+	.shutdown = osk_shutdown,
+};
+
+static const struct snd_soc_dapm_widget tlv320aic23_dapm_widgets[] = {
+	SND_SOC_DAPM_HP("Headphone Jack", NULL),
+	SND_SOC_DAPM_LINE("Line In", NULL),
+	SND_SOC_DAPM_MIC("Mic Jack", NULL),
+};
+
+static const struct snd_soc_dapm_route audio_map[] = {
+	{"Headphone Jack", NULL, "LHPOUT"},
+	{"Headphone Jack", NULL, "RHPOUT"},
+
+	{"LLINEIN", NULL, "Line In"},
+	{"RLINEIN", NULL, "Line In"},
+
+	{"MICIN", NULL, "Mic Jack"},
+};
+
+static int osk_tlv320aic23_init(struct snd_soc_codec *codec)
+{
+
+	/* Add osk5912 specific widgets */
+	snd_soc_dapm_new_controls(codec, tlv320aic23_dapm_widgets,
+				  ARRAY_SIZE(tlv320aic23_dapm_widgets));
+
+	/* Set up osk5912 specific audio path audio_map */
+	snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+
+	snd_soc_dapm_enable_pin(codec, "Headphone Jack");
+	snd_soc_dapm_enable_pin(codec, "Line In");
+	snd_soc_dapm_enable_pin(codec, "Mic Jack");
+
+	snd_soc_dapm_sync(codec);
+
+	return 0;
+}
+
+/* Digital audio interface glue - connects codec <--> CPU */
+static struct snd_soc_dai_link osk_dai = {
+	.name = "TLV320AIC23",
+	.stream_name = "AIC23",
+	.cpu_dai = &omap_mcbsp_dai[0],
+	.codec_dai = &tlv320aic23_dai,
+	.init = osk_tlv320aic23_init,
+	.ops = &osk_ops,
+};
+
+/* Audio machine driver */
+static struct snd_soc_machine snd_soc_machine_osk = {
+	.name = "OSK5912",
+	.dai_link = &osk_dai,
+	.num_links = 1,
+};
+
+/* Audio subsystem */
+static struct snd_soc_device osk_snd_devdata = {
+	.machine = &snd_soc_machine_osk,
+	.platform = &omap_soc_platform,
+	.codec_dev = &soc_codec_dev_tlv320aic23,
+};
+
+static struct platform_device *osk_snd_device;
+
+static int __init osk_soc_init(void)
+{
+	int err;
+	u32 curRate;
+	struct device *dev;
+
+	if (!(machine_is_omap_osk()))
+		return -ENODEV;
+
+	osk_snd_device = platform_device_alloc("soc-audio", -1);
+	if (!osk_snd_device)
+		return -ENOMEM;
+
+	platform_set_drvdata(osk_snd_device, &osk_snd_devdata);
+	osk_snd_devdata.dev = &osk_snd_device->dev;
+	*(unsigned int *)osk_dai.cpu_dai->private_data = 0;	/* McBSP1 */
+	err = platform_device_add(osk_snd_device);
+	if (err)
+		goto err1;
+
+	dev = &osk_snd_device->dev;
+
+	tlv320aic23_mclk = clk_get(dev, "mclk");
+	if (IS_ERR(tlv320aic23_mclk)) {
+		printk(KERN_ERR "Could not get mclk clock\n");
+		return -ENODEV;
+	}
+
+	if (clk_get_usecount(tlv320aic23_mclk) > 0) {
+		/* MCLK is already in use */
+		printk(KERN_WARNING
+		       "MCLK in use at %d Hz. We change it to %d Hz\n",
+		       (uint) clk_get_rate(tlv320aic23_mclk), CODEC_CLOCK);
+	}
+
+	/*
+	 * Configure 12 MHz output on MCLK.
+	 */
+	curRate = (uint) clk_get_rate(tlv320aic23_mclk);
+	if (curRate != CODEC_CLOCK) {
+		if (clk_set_rate(tlv320aic23_mclk, CODEC_CLOCK)) {
+			printk(KERN_ERR "Cannot set MCLK for AIC23 CODEC\n");
+			err = -ECANCELED;
+			goto err1;
+		}
+	}
+
+	printk(KERN_INFO "MCLK = %d [%d], usecount = %d\n",
+	       (uint) clk_get_rate(tlv320aic23_mclk), CODEC_CLOCK,
+	       clk_get_usecount(tlv320aic23_mclk));
+
+	return 0;
+err1:
+	clk_put(tlv320aic23_mclk);
+	platform_device_del(osk_snd_device);
+	platform_device_put(osk_snd_device);
+
+	return err;
+
+}
+
+static void __exit osk_soc_exit(void)
+{
+	platform_device_unregister(osk_snd_device);
+}
+
+module_init(osk_soc_init);
+module_exit(osk_soc_exit);
+
+MODULE_AUTHOR("Arun KS <arunks@mistralsolutions.com>");
+MODULE_DESCRIPTION("ALSA SoC OSK 5912");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/pxa/Kconfig b/sound/soc/pxa/Kconfig
index 9212c37..f8c1cdd 100644
--- a/sound/soc/pxa/Kconfig
+++ b/sound/soc/pxa/Kconfig
@@ -1,6 +1,7 @@
 config SND_PXA2XX_SOC
 	tristate "SoC Audio for the Intel PXA2xx chip"
 	depends on ARCH_PXA
+	select SND_PXA2XX_LIB
 	help
 	  Say Y or M if you want to add support for codecs attached to
 	  the PXA2xx AC97, I2S or SSP interface. You will also need
@@ -13,6 +14,8 @@
 config SND_PXA2XX_SOC_AC97
 	tristate
 	select AC97_BUS
+	select SND_ARM
+	select SND_PXA2XX_LIB_AC97
 	select SND_SOC_AC97_BUS
 
 config SND_PXA2XX_SOC_I2S
diff --git a/sound/soc/pxa/corgi.c b/sound/soc/pxa/corgi.c
index 0a53f72..2718eaf 100644
--- a/sound/soc/pxa/corgi.c
+++ b/sound/soc/pxa/corgi.c
@@ -4,7 +4,7 @@
  * Copyright 2005 Wolfson Microelectronics PLC.
  * Copyright 2005 Openedhand Ltd.
  *
- * Authors: Liam Girdwood <liam.girdwood@wolfsonmicro.com>
+ * Authors: Liam Girdwood <lrg@slimlogic.co.uk>
  *          Richard Purdie <richard@openedhand.com>
  *
  *  This program is free software; you can redistribute  it and/or modify it
@@ -18,13 +18,13 @@
 #include <linux/timer.h>
 #include <linux/interrupt.h>
 #include <linux/platform_device.h>
+#include <linux/gpio.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/soc.h>
 #include <sound/soc-dapm.h>
 
 #include <asm/mach-types.h>
-#include <asm/hardware/scoop.h>
 #include <mach/pxa-regs.h>
 #include <mach/hardware.h>
 #include <mach/corgi.h>
@@ -54,8 +54,8 @@
 	switch (corgi_jack_func) {
 	case CORGI_HP:
 		/* set = unmute headphone */
-		set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_L);
-		set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_R);
+		gpio_set_value(CORGI_GPIO_MUTE_L, 1);
+		gpio_set_value(CORGI_GPIO_MUTE_R, 1);
 		snd_soc_dapm_disable_pin(codec, "Mic Jack");
 		snd_soc_dapm_disable_pin(codec, "Line Jack");
 		snd_soc_dapm_enable_pin(codec, "Headphone Jack");
@@ -63,24 +63,24 @@
 		break;
 	case CORGI_MIC:
 		/* reset = mute headphone */
-		reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_L);
-		reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_R);
+		gpio_set_value(CORGI_GPIO_MUTE_L, 0);
+		gpio_set_value(CORGI_GPIO_MUTE_R, 0);
 		snd_soc_dapm_enable_pin(codec, "Mic Jack");
 		snd_soc_dapm_disable_pin(codec, "Line Jack");
 		snd_soc_dapm_disable_pin(codec, "Headphone Jack");
 		snd_soc_dapm_disable_pin(codec, "Headset Jack");
 		break;
 	case CORGI_LINE:
-		reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_L);
-		reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_R);
+		gpio_set_value(CORGI_GPIO_MUTE_L, 0);
+		gpio_set_value(CORGI_GPIO_MUTE_R, 0);
 		snd_soc_dapm_disable_pin(codec, "Mic Jack");
 		snd_soc_dapm_enable_pin(codec, "Line Jack");
 		snd_soc_dapm_disable_pin(codec, "Headphone Jack");
 		snd_soc_dapm_disable_pin(codec, "Headset Jack");
 		break;
 	case CORGI_HEADSET:
-		reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_L);
-		set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_R);
+		gpio_set_value(CORGI_GPIO_MUTE_L, 0);
+		gpio_set_value(CORGI_GPIO_MUTE_R, 1);
 		snd_soc_dapm_enable_pin(codec, "Mic Jack");
 		snd_soc_dapm_disable_pin(codec, "Line Jack");
 		snd_soc_dapm_disable_pin(codec, "Headphone Jack");
@@ -114,8 +114,8 @@
 	struct snd_soc_codec *codec = rtd->socdev->codec;
 
 	/* set = unmute headphone */
-	set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_L);
-	set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_R);
+	gpio_set_value(CORGI_GPIO_MUTE_L, 1);
+	gpio_set_value(CORGI_GPIO_MUTE_R, 1);
 	return 0;
 }
 
@@ -218,22 +218,14 @@
 static int corgi_amp_event(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *k, int event)
 {
-	if (SND_SOC_DAPM_EVENT_ON(event))
-		set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_APM_ON);
-	else
-		reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_APM_ON);
-
+	gpio_set_value(CORGI_GPIO_APM_ON, SND_SOC_DAPM_EVENT_ON(event));
 	return 0;
 }
 
 static int corgi_mic_event(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *k, int event)
 {
-	if (SND_SOC_DAPM_EVENT_ON(event))
-		set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MIC_BIAS);
-	else
-		reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MIC_BIAS);
-
+	gpio_set_value(CORGI_GPIO_MIC_BIAS, SND_SOC_DAPM_EVENT_ON(event));
 	return 0;
 }
 
@@ -289,8 +281,8 @@
 {
 	int i, err;
 
-	snd_soc_dapm_disable_pin(codec, "LLINEIN");
-	snd_soc_dapm_disable_pin(codec, "RLINEIN");
+	snd_soc_dapm_nc_pin(codec, "LLINEIN");
+	snd_soc_dapm_nc_pin(codec, "RLINEIN");
 
 	/* Add corgi specific controls */
 	for (i = 0; i < ARRAY_SIZE(wm8731_corgi_controls); i++) {
@@ -330,6 +322,7 @@
 
 /* corgi audio private data */
 static struct wm8731_setup_data corgi_wm8731_setup = {
+	.i2c_bus = 0,
 	.i2c_address = 0x1b,
 };
 
diff --git a/sound/soc/pxa/em-x270.c b/sound/soc/pxa/em-x270.c
index d9c3f7b..e6ff692 100644
--- a/sound/soc/pxa/em-x270.c
+++ b/sound/soc/pxa/em-x270.c
@@ -9,7 +9,7 @@
  * Copyright 2005 Wolfson Microelectronics PLC.
  * Copyright 2005 Openedhand Ltd.
  *
- * Authors: Liam Girdwood <liam.girdwood@wolfsonmicro.com>
+ * Authors: Liam Girdwood <lrg@slimlogic.co.uk>
  *          Richard Purdie <richard@openedhand.com>
  *
  *  This program is free software; you can redistribute  it and/or modify it
diff --git a/sound/soc/pxa/poodle.c b/sound/soc/pxa/poodle.c
index a4697f7..4d9930c 100644
--- a/sound/soc/pxa/poodle.c
+++ b/sound/soc/pxa/poodle.c
@@ -4,7 +4,7 @@
  * Copyright 2005 Wolfson Microelectronics PLC.
  * Copyright 2005 Openedhand Ltd.
  *
- * Authors: Liam Girdwood <liam.girdwood@wolfsonmicro.com>
+ * Authors: Liam Girdwood <lrg@slimlogic.co.uk>
  *          Richard Purdie <richard@openedhand.com>
  *
  *  This program is free software; you can redistribute  it and/or modify it
@@ -242,8 +242,8 @@
 {
 	int i, err;
 
-	snd_soc_dapm_disable_pin(codec, "LLINEIN");
-	snd_soc_dapm_disable_pin(codec, "RLINEIN");
+	snd_soc_dapm_nc_pin(codec, "LLINEIN");
+	snd_soc_dapm_nc_pin(codec, "RLINEIN");
 	snd_soc_dapm_enable_pin(codec, "MICIN");
 
 	/* Add poodle specific controls */
@@ -284,6 +284,7 @@
 
 /* poodle audio private data */
 static struct wm8731_setup_data poodle_wm8731_setup = {
+	.i2c_bus = 0,
 	.i2c_address = 0x1b,
 };
 
diff --git a/sound/soc/pxa/pxa2xx-ac97.c b/sound/soc/pxa/pxa2xx-ac97.c
index d94a495..a7a3a9c 100644
--- a/sound/soc/pxa/pxa2xx-ac97.c
+++ b/sound/soc/pxa/pxa2xx-ac97.c
@@ -13,225 +13,30 @@
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
-#include <linux/interrupt.h>
-#include <linux/wait.h>
-#include <linux/clk.h>
-#include <linux/delay.h>
 
 #include <sound/core.h>
-#include <sound/pcm.h>
 #include <sound/ac97_codec.h>
-#include <sound/initval.h>
 #include <sound/soc.h>
+#include <sound/pxa2xx-lib.h>
 
-#include <asm/irq.h>
-#include <linux/mutex.h>
 #include <mach/hardware.h>
 #include <mach/pxa-regs.h>
-#include <mach/pxa2xx-gpio.h>
-#include <mach/audio.h>
 
 #include "pxa2xx-pcm.h"
 #include "pxa2xx-ac97.h"
 
-static DEFINE_MUTEX(car_mutex);
-static DECLARE_WAIT_QUEUE_HEAD(gsr_wq);
-static volatile long gsr_bits;
-static struct clk *ac97_clk;
-#ifdef CONFIG_PXA27x
-static struct clk *ac97conf_clk;
-#endif
-
-/*
- * Beware PXA27x bugs:
- *
- *   o Slot 12 read from modem space will hang controller.
- *   o CDONE, SDONE interrupt fails after any slot 12 IO.
- *
- * We therefore have an hybrid approach for waiting on SDONE (interrupt or
- * 1 jiffy timeout if interrupt never comes).
- */
-
-static unsigned short pxa2xx_ac97_read(struct snd_ac97 *ac97,
-	unsigned short reg)
-{
-	unsigned short val = -1;
-	volatile u32 *reg_addr;
-
-	mutex_lock(&car_mutex);
-
-	/* set up primary or secondary codec/modem space */
-#if defined(CONFIG_PXA27x) || defined(CONFIG_PXA3xx)
-	reg_addr = ac97->num ? &SAC_REG_BASE : &PAC_REG_BASE;
-#else
-	if (reg == AC97_GPIO_STATUS)
-		reg_addr = ac97->num ? &SMC_REG_BASE : &PMC_REG_BASE;
-	else
-		reg_addr = ac97->num ? &SAC_REG_BASE : &PAC_REG_BASE;
-#endif
-	reg_addr += (reg >> 1);
-
-#ifndef CONFIG_PXA27x
-	if (reg == AC97_GPIO_STATUS) {
-		/* read from controller cache */
-		val = *reg_addr;
-		goto out;
-	}
-#endif
-
-	/* start read access across the ac97 link */
-	GSR = GSR_CDONE | GSR_SDONE;
-	gsr_bits = 0;
-	val = *reg_addr;
-
-	wait_event_timeout(gsr_wq, (GSR | gsr_bits) & GSR_SDONE, 1);
-	if (!((GSR | gsr_bits) & GSR_SDONE)) {
-		printk(KERN_ERR "%s: read error (ac97_reg=%x GSR=%#lx)\n",
-				__func__, reg, GSR | gsr_bits);
-		val = -1;
-		goto out;
-	}
-
-	/* valid data now */
-	GSR = GSR_CDONE | GSR_SDONE;
-	gsr_bits = 0;
-	val = *reg_addr;
-	/* but we've just started another cycle... */
-	wait_event_timeout(gsr_wq, (GSR | gsr_bits) & GSR_SDONE, 1);
-
-out:	mutex_unlock(&car_mutex);
-	return val;
-}
-
-static void pxa2xx_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
-	unsigned short val)
-{
-	volatile u32 *reg_addr;
-
-	mutex_lock(&car_mutex);
-
-	/* set up primary or secondary codec/modem space */
-#if defined(CONFIG_PXA27x) || defined(CONFIG_PXA3xx)
-	reg_addr = ac97->num ? &SAC_REG_BASE : &PAC_REG_BASE;
-#else
-	if (reg == AC97_GPIO_STATUS)
-		reg_addr = ac97->num ? &SMC_REG_BASE : &PMC_REG_BASE;
-	else
-		reg_addr = ac97->num ? &SAC_REG_BASE : &PAC_REG_BASE;
-#endif
-	reg_addr += (reg >> 1);
-
-	GSR = GSR_CDONE | GSR_SDONE;
-	gsr_bits = 0;
-	*reg_addr = val;
-	wait_event_timeout(gsr_wq, (GSR | gsr_bits) & GSR_CDONE, 1);
-	if (!((GSR | gsr_bits) & GSR_CDONE))
-		printk(KERN_ERR "%s: write error (ac97_reg=%x GSR=%#lx)\n",
-				__func__, reg, GSR | gsr_bits);
-
-	mutex_unlock(&car_mutex);
-}
-
 static void pxa2xx_ac97_warm_reset(struct snd_ac97 *ac97)
 {
-#ifdef CONFIG_PXA3xx
-	int timeout = 100;
-#endif
-	gsr_bits = 0;
+	pxa2xx_ac97_try_warm_reset(ac97);
 
-#ifdef CONFIG_PXA27x
-	/* warm reset broken on Bulverde,
-	   so manually keep AC97 reset high */
-	pxa_gpio_mode(113 | GPIO_OUT | GPIO_DFLT_HIGH);
-	udelay(10);
-	GCR |= GCR_WARM_RST;
-	pxa_gpio_mode(113 | GPIO_ALT_FN_2_OUT);
-	udelay(500);
-#elif defined(CONFIG_PXA3xx)
-	/* Can't use interrupts */
-	GCR |= GCR_WARM_RST;
-	while (!((GSR | gsr_bits) & (GSR_PCR | GSR_SCR)) && timeout--)
-		mdelay(1);
-#else
-	GCR |= GCR_WARM_RST | GCR_PRIRDY_IEN | GCR_SECRDY_IEN;
-	wait_event_timeout(gsr_wq, gsr_bits & (GSR_PCR | GSR_SCR), 1);
-#endif
-
-	if (!((GSR | gsr_bits) & (GSR_PCR | GSR_SCR)))
-		printk(KERN_INFO "%s: warm reset timeout (GSR=%#lx)\n",
-				 __func__, gsr_bits);
-
-	GCR &= ~(GCR_PRIRDY_IEN|GCR_SECRDY_IEN);
-	GCR |= GCR_SDONE_IE|GCR_CDONE_IE;
+	pxa2xx_ac97_finish_reset(ac97);
 }
 
 static void pxa2xx_ac97_cold_reset(struct snd_ac97 *ac97)
 {
-#ifdef CONFIG_PXA3xx
-	int timeout = 1000;
+	pxa2xx_ac97_try_cold_reset(ac97);
 
-	/* Hold CLKBPB for 100us */
-	GCR = 0;
-	GCR = GCR_CLKBPB;
-	udelay(100);
-	GCR = 0;
-#endif
-
-	GCR &=  GCR_COLD_RST;  /* clear everything but nCRST */
-	GCR &= ~GCR_COLD_RST;  /* then assert nCRST */
-
-	gsr_bits = 0;
-#ifdef CONFIG_PXA27x
-	/* PXA27x Developers Manual section 13.5.2.2.1 */
-	clk_enable(ac97conf_clk);
-	udelay(5);
-	clk_disable(ac97conf_clk);
-	GCR = GCR_COLD_RST;
-	udelay(50);
-#elif defined(CONFIG_PXA3xx)
-	/* Can't use interrupts on PXA3xx */
-	GCR &= ~(GCR_PRIRDY_IEN|GCR_SECRDY_IEN);
-
-	GCR = GCR_WARM_RST | GCR_COLD_RST;
-	while (!(GSR & (GSR_PCR | GSR_SCR)) && timeout--)
-		mdelay(10);
-#else
-	GCR = GCR_COLD_RST;
-	GCR |= GCR_CDONE_IE|GCR_SDONE_IE;
-	wait_event_timeout(gsr_wq, gsr_bits & (GSR_PCR | GSR_SCR), 1);
-#endif
-
-	if (!((GSR | gsr_bits) & (GSR_PCR | GSR_SCR)))
-		printk(KERN_INFO "%s: cold reset timeout (GSR=%#lx)\n",
-				 __func__, gsr_bits);
-
-	GCR &= ~(GCR_PRIRDY_IEN|GCR_SECRDY_IEN);
-	GCR |= GCR_SDONE_IE|GCR_CDONE_IE;
-}
-
-static irqreturn_t pxa2xx_ac97_irq(int irq, void *dev_id)
-{
-	long status;
-
-	status = GSR;
-	if (status) {
-		GSR = status;
-		gsr_bits |= status;
-		wake_up(&gsr_wq);
-
-#ifdef CONFIG_PXA27x
-		/* Although we don't use those we still need to clear them
-		   since they tend to spuriously trigger when MMC is used
-		   (hardware bug? go figure)... */
-		MISR = MISR_EOC;
-		PISR = PISR_EOC;
-		MCSR = MCSR_EOC;
-#endif
-
-		return IRQ_HANDLED;
-	}
-
-	return IRQ_NONE;
+	pxa2xx_ac97_finish_reset(ac97);
 }
 
 struct snd_ac97_bus_ops soc_ac97_ops = {
@@ -244,7 +49,7 @@
 static struct pxa2xx_pcm_dma_params pxa2xx_ac97_pcm_stereo_out = {
 	.name			= "AC97 PCM Stereo out",
 	.dev_addr		= __PREG(PCDR),
-	.drcmr			= &DRCMRTXPCDR,
+	.drcmr			= &DRCMR(12),
 	.dcmd			= DCMD_INCSRCADDR | DCMD_FLOWTRG |
 				  DCMD_BURST32 | DCMD_WIDTH4,
 };
@@ -252,7 +57,7 @@
 static struct pxa2xx_pcm_dma_params pxa2xx_ac97_pcm_stereo_in = {
 	.name			= "AC97 PCM Stereo in",
 	.dev_addr		= __PREG(PCDR),
-	.drcmr			= &DRCMRRXPCDR,
+	.drcmr			= &DRCMR(11),
 	.dcmd			= DCMD_INCTRGADDR | DCMD_FLOWSRC |
 				  DCMD_BURST32 | DCMD_WIDTH4,
 };
@@ -260,7 +65,7 @@
 static struct pxa2xx_pcm_dma_params pxa2xx_ac97_pcm_aux_mono_out = {
 	.name			= "AC97 Aux PCM (Slot 5) Mono out",
 	.dev_addr		= __PREG(MODR),
-	.drcmr			= &DRCMRTXMODR,
+	.drcmr			= &DRCMR(10),
 	.dcmd			= DCMD_INCSRCADDR | DCMD_FLOWTRG |
 				  DCMD_BURST16 | DCMD_WIDTH2,
 };
@@ -268,7 +73,7 @@
 static struct pxa2xx_pcm_dma_params pxa2xx_ac97_pcm_aux_mono_in = {
 	.name			= "AC97 Aux PCM (Slot 5) Mono in",
 	.dev_addr		= __PREG(MODR),
-	.drcmr			= &DRCMRRXMODR,
+	.drcmr			= &DRCMR(9),
 	.dcmd			= DCMD_INCTRGADDR | DCMD_FLOWSRC |
 				  DCMD_BURST16 | DCMD_WIDTH2,
 };
@@ -276,7 +81,7 @@
 static struct pxa2xx_pcm_dma_params pxa2xx_ac97_pcm_mic_mono_in = {
 	.name			= "AC97 Mic PCM (Slot 6) Mono in",
 	.dev_addr		= __PREG(MCDR),
-	.drcmr			= &DRCMRRXMCDR,
+	.drcmr			= &DRCMR(8),
 	.dcmd			= DCMD_INCTRGADDR | DCMD_FLOWSRC |
 				  DCMD_BURST16 | DCMD_WIDTH2,
 };
@@ -285,24 +90,13 @@
 static int pxa2xx_ac97_suspend(struct platform_device *pdev,
 	struct snd_soc_dai *dai)
 {
-	GCR |= GCR_ACLINK_OFF;
-	clk_disable(ac97_clk);
-	return 0;
+	return pxa2xx_ac97_hw_suspend();
 }
 
 static int pxa2xx_ac97_resume(struct platform_device *pdev,
 	struct snd_soc_dai *dai)
 {
-	pxa_gpio_mode(GPIO31_SYNC_AC97_MD);
-	pxa_gpio_mode(GPIO30_SDATA_OUT_AC97_MD);
-	pxa_gpio_mode(GPIO28_BITCLK_AC97_MD);
-	pxa_gpio_mode(GPIO29_SDATA_IN_AC97_MD);
-#ifdef CONFIG_PXA27x
-	/* Use GPIO 113 as AC97 Reset on Bulverde */
-	pxa_gpio_mode(113 | GPIO_ALT_FN_2_OUT);
-#endif
-	clk_enable(ac97_clk);
-	return 0;
+	return pxa2xx_ac97_hw_resume();
 }
 
 #else
@@ -313,61 +107,13 @@
 static int pxa2xx_ac97_probe(struct platform_device *pdev,
 			     struct snd_soc_dai *dai)
 {
-	int ret;
-
-	ret = request_irq(IRQ_AC97, pxa2xx_ac97_irq, IRQF_DISABLED, "AC97", NULL);
-	if (ret < 0)
-		goto err;
-
-	pxa_gpio_mode(GPIO31_SYNC_AC97_MD);
-	pxa_gpio_mode(GPIO30_SDATA_OUT_AC97_MD);
-	pxa_gpio_mode(GPIO28_BITCLK_AC97_MD);
-	pxa_gpio_mode(GPIO29_SDATA_IN_AC97_MD);
-#ifdef CONFIG_PXA27x
-	/* Use GPIO 113 as AC97 Reset on Bulverde */
-	pxa_gpio_mode(113 | GPIO_ALT_FN_2_OUT);
-
-	ac97conf_clk = clk_get(&pdev->dev, "AC97CONFCLK");
-	if (IS_ERR(ac97conf_clk)) {
-		ret = PTR_ERR(ac97conf_clk);
-		ac97conf_clk = NULL;
-		goto err_irq;
-	}
-#endif
-	ac97_clk = clk_get(&pdev->dev, "AC97CLK");
-	if (IS_ERR(ac97_clk)) {
-		ret = PTR_ERR(ac97_clk);
-		ac97_clk = NULL;
-		goto err_irq;
-	}
-	clk_enable(ac97_clk);
-	return 0;
-
- err_irq:
-	GCR |= GCR_ACLINK_OFF;
-#ifdef CONFIG_PXA27x
-	if (ac97conf_clk) {
-		clk_put(ac97conf_clk);
-		ac97conf_clk = NULL;
-	}
-#endif
-	free_irq(IRQ_AC97, NULL);
- err:
-	return ret;
+	return pxa2xx_ac97_hw_probe(pdev);
 }
 
 static void pxa2xx_ac97_remove(struct platform_device *pdev,
 			       struct snd_soc_dai *dai)
 {
-	GCR |= GCR_ACLINK_OFF;
-	free_irq(IRQ_AC97, NULL);
-#ifdef CONFIG_PXA27x
-	clk_put(ac97conf_clk);
-	ac97conf_clk = NULL;
-#endif
-	clk_disable(ac97_clk);
-	clk_put(ac97_clk);
-	ac97_clk = NULL;
+	pxa2xx_ac97_hw_remove(pdev);
 }
 
 static int pxa2xx_ac97_hw_params(struct snd_pcm_substream *substream,
diff --git a/sound/soc/pxa/pxa2xx-i2s.c b/sound/soc/pxa/pxa2xx-i2s.c
index c796b18..e758034 100644
--- a/sound/soc/pxa/pxa2xx-i2s.c
+++ b/sound/soc/pxa/pxa2xx-i2s.c
@@ -3,7 +3,7 @@
  *
  * Copyright 2005 Wolfson Microelectronics PLC.
  * Author: Liam Girdwood
- *         liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com
+ *         lrg@slimlogic.co.uk
  *
  *  This program is free software; you can redistribute  it and/or modify it
  *  under  the terms of  the GNU General  Public License as published by the
@@ -21,6 +21,7 @@
 #include <sound/pcm.h>
 #include <sound/initval.h>
 #include <sound/soc.h>
+#include <sound/pxa2xx-lib.h>
 
 #include <mach/hardware.h>
 #include <mach/pxa-regs.h>
@@ -30,6 +31,54 @@
 #include "pxa2xx-pcm.h"
 #include "pxa2xx-i2s.h"
 
+struct pxa2xx_gpio {
+	u32 sys;
+	u32	rx;
+	u32 tx;
+	u32 clk;
+	u32 frm;
+};
+
+/*
+ * I2S Controller Register and Bit Definitions
+ */
+#define SACR0		__REG(0x40400000)  /* Global Control Register */
+#define SACR1		__REG(0x40400004)  /* Serial Audio I 2 S/MSB-Justified Control Register */
+#define SASR0		__REG(0x4040000C)  /* Serial Audio I 2 S/MSB-Justified Interface and FIFO Status Register */
+#define SAIMR		__REG(0x40400014)  /* Serial Audio Interrupt Mask Register */
+#define SAICR		__REG(0x40400018)  /* Serial Audio Interrupt Clear Register */
+#define SADIV		__REG(0x40400060)  /* Audio Clock Divider Register. */
+#define SADR		__REG(0x40400080)  /* Serial Audio Data Register (TX and RX FIFO access Register). */
+
+#define SACR0_RFTH(x)	((x) << 12)	/* Rx FIFO Interrupt or DMA Trigger Threshold */
+#define SACR0_TFTH(x)	((x) << 8)	/* Tx FIFO Interrupt or DMA Trigger Threshold */
+#define SACR0_STRF	(1 << 5)	/* FIFO Select for EFWR Special Function */
+#define SACR0_EFWR	(1 << 4)	/* Enable EFWR Function  */
+#define SACR0_RST	(1 << 3)	/* FIFO, i2s Register Reset */
+#define SACR0_BCKD	(1 << 2) 	/* Bit Clock Direction */
+#define SACR0_ENB	(1 << 0)	/* Enable I2S Link */
+#define SACR1_ENLBF	(1 << 5)	/* Enable Loopback */
+#define SACR1_DRPL	(1 << 4) 	/* Disable Replaying Function */
+#define SACR1_DREC	(1 << 3)	/* Disable Recording Function */
+#define SACR1_AMSL	(1 << 0)	/* Specify Alternate Mode */
+
+#define SASR0_I2SOFF	(1 << 7)	/* Controller Status */
+#define SASR0_ROR	(1 << 6)	/* Rx FIFO Overrun */
+#define SASR0_TUR	(1 << 5)	/* Tx FIFO Underrun */
+#define SASR0_RFS	(1 << 4)	/* Rx FIFO Service Request */
+#define SASR0_TFS	(1 << 3)	/* Tx FIFO Service Request */
+#define SASR0_BSY	(1 << 2)	/* I2S Busy */
+#define SASR0_RNE	(1 << 1)	/* Rx FIFO Not Empty */
+#define SASR0_TNF	(1 << 0) 	/* Tx FIFO Not Empty */
+
+#define SAICR_ROR	(1 << 6)	/* Clear Rx FIFO Overrun Interrupt */
+#define SAICR_TUR	(1 << 5)	/* Clear Tx FIFO Underrun Interrupt */
+
+#define SAIMR_ROR	(1 << 6)	/* Enable Rx FIFO Overrun Condition Interrupt */
+#define SAIMR_TUR	(1 << 5)	/* Enable Tx FIFO Underrun Condition Interrupt */
+#define SAIMR_RFS	(1 << 4)	/* Enable Rx FIFO Service Interrupt */
+#define SAIMR_TFS	(1 << 3)	/* Enable Tx FIFO Service Interrupt */
+
 struct pxa_i2s_port {
 	u32 sadiv;
 	u32 sacr0;
@@ -44,7 +93,7 @@
 static struct pxa2xx_pcm_dma_params pxa2xx_i2s_pcm_stereo_out = {
 	.name			= "I2S PCM Stereo out",
 	.dev_addr		= __PREG(SADR),
-	.drcmr			= &DRCMRTXSADR,
+	.drcmr			= &DRCMR(3),
 	.dcmd			= DCMD_INCSRCADDR | DCMD_FLOWTRG |
 				  DCMD_BURST32 | DCMD_WIDTH4,
 };
@@ -52,7 +101,7 @@
 static struct pxa2xx_pcm_dma_params pxa2xx_i2s_pcm_stereo_in = {
 	.name			= "I2S PCM Stereo in",
 	.dev_addr		= __PREG(SADR),
-	.drcmr			= &DRCMRRXSADR,
+	.drcmr			= &DRCMR(2),
 	.dcmd			= DCMD_INCTRGADDR | DCMD_FLOWSRC |
 				  DCMD_BURST32 | DCMD_WIDTH4,
 };
@@ -65,11 +114,6 @@
 		.frm = GPIO31_SYNC_I2S_MD,
 	},
 	{ /* I2S SoC Master */
-#ifdef CONFIG_PXA27x
-		.sys = GPIO113_I2S_SYSCLK_MD,
-#else
-		.sys = GPIO32_SYSCLK_I2S_MD,
-#endif
 		.rx = GPIO29_SDATA_IN_I2S_MD,
 		.tx = GPIO30_SDATA_OUT_I2S_MD,
 		.clk = GPIO28_BITCLK_OUT_I2S_MD,
@@ -343,6 +387,11 @@
 
 static int __init pxa2xx_i2s_init(void)
 {
+	if (cpu_is_pxa27x())
+		gpio_bus[1].sys = GPIO113_I2S_SYSCLK_MD;
+	else
+		gpio_bus[1].sys = GPIO32_SYSCLK_I2S_MD;
+
 	clk_i2s = ERR_PTR(-ENOENT);
 	return platform_driver_register(&pxa2xx_i2s_driver);
 }
@@ -356,6 +405,6 @@
 module_exit(pxa2xx_i2s_exit);
 
 /* Module information */
-MODULE_AUTHOR("Liam Girdwood, liam.girdwood@wolfsonmicro.com, www.wolfsonmicro.com");
+MODULE_AUTHOR("Liam Girdwood, lrg@slimlogic.co.uk");
 MODULE_DESCRIPTION("pxa2xx I2S SoC Interface");
 MODULE_LICENSE("GPL");
diff --git a/sound/soc/pxa/pxa2xx-pcm.c b/sound/soc/pxa/pxa2xx-pcm.c
index 4345f38..afcd892 100644
--- a/sound/soc/pxa/pxa2xx-pcm.c
+++ b/sound/soc/pxa/pxa2xx-pcm.c
@@ -10,64 +10,14 @@
  * published by the Free Software Foundation.
  */
 
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
 #include <linux/dma-mapping.h>
 
 #include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
 #include <sound/soc.h>
-
-#include <asm/dma.h>
-#include <mach/hardware.h>
-#include <mach/pxa-regs.h>
-#include <mach/audio.h>
+#include <sound/pxa2xx-lib.h>
 
 #include "pxa2xx-pcm.h"
-
-static const struct snd_pcm_hardware pxa2xx_pcm_hardware = {
-	.info			= SNDRV_PCM_INFO_MMAP |
-				  SNDRV_PCM_INFO_MMAP_VALID |
-				  SNDRV_PCM_INFO_INTERLEAVED |
-				  SNDRV_PCM_INFO_PAUSE |
-				  SNDRV_PCM_INFO_RESUME,
-	.formats		= SNDRV_PCM_FMTBIT_S16_LE |
-					SNDRV_PCM_FMTBIT_S24_LE |
-					SNDRV_PCM_FMTBIT_S32_LE,
-	.period_bytes_min	= 32,
-	.period_bytes_max	= 8192 - 32,
-	.periods_min		= 1,
-	.periods_max		= PAGE_SIZE/sizeof(pxa_dma_desc),
-	.buffer_bytes_max	= 128 * 1024,
-	.fifo_size		= 32,
-};
-
-struct pxa2xx_runtime_data {
-	int dma_ch;
-	struct pxa2xx_pcm_dma_params *params;
-	pxa_dma_desc *dma_desc_array;
-	dma_addr_t dma_desc_array_phys;
-};
-
-static void pxa2xx_pcm_dma_irq(int dma_ch, void *dev_id)
-{
-	struct snd_pcm_substream *substream = dev_id;
-	struct pxa2xx_runtime_data *prtd = substream->runtime->private_data;
-	int dcsr;
-
-	dcsr = DCSR(dma_ch);
-	DCSR(dma_ch) = dcsr & ~DCSR_STOPIRQEN;
-
-	if (dcsr & DCSR_ENDINTR) {
-		snd_pcm_period_elapsed(substream);
-	} else {
-		printk(KERN_ERR "%s: DMA error on channel %d (DCSR=%#x)\n",
-			prtd->params->name, dma_ch, dcsr);
-	}
-}
+#include "../../arm/pxa2xx-pcm.h"
 
 static int pxa2xx_pcm_hw_params(struct snd_pcm_substream *substream,
 	struct snd_pcm_hw_params *params)
@@ -76,10 +26,6 @@
 	struct pxa2xx_runtime_data *prtd = runtime->private_data;
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	struct pxa2xx_pcm_dma_params *dma = rtd->dai->cpu_dai->dma_data;
-	size_t totsize = params_buffer_bytes(params);
-	size_t period = params_period_bytes(params);
-	pxa_dma_desc *dma_desc;
-	dma_addr_t dma_buff_phys, next_desc_phys;
 	int ret;
 
 	/* return if this is a bufferless transfer e.g.
@@ -106,42 +52,16 @@
 		prtd->dma_ch = ret;
 	}
 
-	snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
-	runtime->dma_bytes = totsize;
-
-	dma_desc = prtd->dma_desc_array;
-	next_desc_phys = prtd->dma_desc_array_phys;
-	dma_buff_phys = runtime->dma_addr;
-	do {
-		next_desc_phys += sizeof(pxa_dma_desc);
-		dma_desc->ddadr = next_desc_phys;
-		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-			dma_desc->dsadr = dma_buff_phys;
-			dma_desc->dtadr = prtd->params->dev_addr;
-		} else {
-			dma_desc->dsadr = prtd->params->dev_addr;
-			dma_desc->dtadr = dma_buff_phys;
-		}
-		if (period > totsize)
-			period = totsize;
-		dma_desc->dcmd = prtd->params->dcmd | period | DCMD_ENDIRQEN;
-		dma_desc++;
-		dma_buff_phys += period;
-	} while (totsize -= period);
-	dma_desc[-1].ddadr = prtd->dma_desc_array_phys;
-
-	return 0;
+	return __pxa2xx_pcm_hw_params(substream, params);
 }
 
 static int pxa2xx_pcm_hw_free(struct snd_pcm_substream *substream)
 {
 	struct pxa2xx_runtime_data *prtd = substream->runtime->private_data;
 
-	if (prtd && prtd->params)
-		*prtd->params->drcmr = 0;
+	__pxa2xx_pcm_hw_free(substream);
 
 	if (prtd->dma_ch) {
-		snd_pcm_set_runtime_buffer(substream, NULL);
 		pxa_free_dma(prtd->dma_ch);
 		prtd->dma_ch = 0;
 	}
@@ -149,188 +69,21 @@
 	return 0;
 }
 
-static int pxa2xx_pcm_prepare(struct snd_pcm_substream *substream)
-{
-	struct pxa2xx_runtime_data *prtd = substream->runtime->private_data;
-
-	DCSR(prtd->dma_ch) &= ~DCSR_RUN;
-	DCSR(prtd->dma_ch) = 0;
-	DCMD(prtd->dma_ch) = 0;
-	*prtd->params->drcmr = prtd->dma_ch | DRCMR_MAPVLD;
-
-	return 0;
-}
-
-static int pxa2xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
-{
-	struct pxa2xx_runtime_data *prtd = substream->runtime->private_data;
-	int ret = 0;
-
-	switch (cmd) {
-	case SNDRV_PCM_TRIGGER_START:
-		DDADR(prtd->dma_ch) = prtd->dma_desc_array_phys;
-		DCSR(prtd->dma_ch) = DCSR_RUN;
-		break;
-
-	case SNDRV_PCM_TRIGGER_STOP:
-	case SNDRV_PCM_TRIGGER_SUSPEND:
-	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-		DCSR(prtd->dma_ch) &= ~DCSR_RUN;
-		break;
-
-	case SNDRV_PCM_TRIGGER_RESUME:
-		DCSR(prtd->dma_ch) |= DCSR_RUN;
-		break;
-	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-		DDADR(prtd->dma_ch) = prtd->dma_desc_array_phys;
-		DCSR(prtd->dma_ch) |= DCSR_RUN;
-		break;
-
-	default:
-		ret = -EINVAL;
-	}
-
-	return ret;
-}
-
-static snd_pcm_uframes_t
-pxa2xx_pcm_pointer(struct snd_pcm_substream *substream)
-{
-	struct snd_pcm_runtime *runtime = substream->runtime;
-	struct pxa2xx_runtime_data *prtd = runtime->private_data;
-
-	dma_addr_t ptr = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
-			 DSADR(prtd->dma_ch) : DTADR(prtd->dma_ch);
-	snd_pcm_uframes_t x = bytes_to_frames(runtime, ptr - runtime->dma_addr);
-
-	if (x == runtime->buffer_size)
-		x = 0;
-	return x;
-}
-
-static int pxa2xx_pcm_open(struct snd_pcm_substream *substream)
-{
-	struct snd_pcm_runtime *runtime = substream->runtime;
-	struct pxa2xx_runtime_data *prtd;
-	int ret;
-
-	snd_soc_set_runtime_hwparams(substream, &pxa2xx_pcm_hardware);
-
-	/*
-	 * For mysterious reasons (and despite what the manual says)
-	 * playback samples are lost if the DMA count is not a multiple
-	 * of the DMA burst size.  Let's add a rule to enforce that.
-	 */
-	ret = snd_pcm_hw_constraint_step(runtime, 0,
-		SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 32);
-	if (ret)
-		goto out;
-
-	ret = snd_pcm_hw_constraint_step(runtime, 0,
-		SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 32);
-	if (ret)
-		goto out;
-
-	ret = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
-	if (ret < 0)
-		goto out;
-
-	prtd = kzalloc(sizeof(struct pxa2xx_runtime_data), GFP_KERNEL);
-	if (prtd == NULL) {
-		ret = -ENOMEM;
-		goto out;
-	}
-
-	prtd->dma_desc_array =
-		dma_alloc_writecombine(substream->pcm->card->dev, PAGE_SIZE,
-				       &prtd->dma_desc_array_phys, GFP_KERNEL);
-	if (!prtd->dma_desc_array) {
-		ret = -ENOMEM;
-		goto err1;
-	}
-
-	runtime->private_data = prtd;
-	return 0;
-
- err1:
-	kfree(prtd);
- out:
-	return ret;
-}
-
-static int pxa2xx_pcm_close(struct snd_pcm_substream *substream)
-{
-	struct snd_pcm_runtime *runtime = substream->runtime;
-	struct pxa2xx_runtime_data *prtd = runtime->private_data;
-
-	dma_free_writecombine(substream->pcm->card->dev, PAGE_SIZE,
-			      prtd->dma_desc_array, prtd->dma_desc_array_phys);
-	kfree(prtd);
-	return 0;
-}
-
-static int pxa2xx_pcm_mmap(struct snd_pcm_substream *substream,
-	struct vm_area_struct *vma)
-{
-	struct snd_pcm_runtime *runtime = substream->runtime;
-	return dma_mmap_writecombine(substream->pcm->card->dev, vma,
-				     runtime->dma_area,
-				     runtime->dma_addr,
-				     runtime->dma_bytes);
-}
-
 struct snd_pcm_ops pxa2xx_pcm_ops = {
-	.open		= pxa2xx_pcm_open,
-	.close		= pxa2xx_pcm_close,
+	.open		= __pxa2xx_pcm_open,
+	.close		= __pxa2xx_pcm_close,
 	.ioctl		= snd_pcm_lib_ioctl,
 	.hw_params	= pxa2xx_pcm_hw_params,
 	.hw_free	= pxa2xx_pcm_hw_free,
-	.prepare	= pxa2xx_pcm_prepare,
+	.prepare	= __pxa2xx_pcm_prepare,
 	.trigger	= pxa2xx_pcm_trigger,
 	.pointer	= pxa2xx_pcm_pointer,
 	.mmap		= pxa2xx_pcm_mmap,
 };
 
-static int pxa2xx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
-{
-	struct snd_pcm_substream *substream = pcm->streams[stream].substream;
-	struct snd_dma_buffer *buf = &substream->dma_buffer;
-	size_t size = pxa2xx_pcm_hardware.buffer_bytes_max;
-	buf->dev.type = SNDRV_DMA_TYPE_DEV;
-	buf->dev.dev = pcm->card->dev;
-	buf->private_data = NULL;
-	buf->area = dma_alloc_writecombine(pcm->card->dev, size,
-					   &buf->addr, GFP_KERNEL);
-	if (!buf->area)
-		return -ENOMEM;
-	buf->bytes = size;
-	return 0;
-}
-
-static void pxa2xx_pcm_free_dma_buffers(struct snd_pcm *pcm)
-{
-	struct snd_pcm_substream *substream;
-	struct snd_dma_buffer *buf;
-	int stream;
-
-	for (stream = 0; stream < 2; stream++) {
-		substream = pcm->streams[stream].substream;
-		if (!substream)
-			continue;
-
-		buf = &substream->dma_buffer;
-		if (!buf->area)
-			continue;
-
-		dma_free_writecombine(pcm->card->dev, buf->bytes,
-				      buf->area, buf->addr);
-		buf->area = NULL;
-	}
-}
-
 static u64 pxa2xx_pcm_dmamask = DMA_32BIT_MASK;
 
-int pxa2xx_pcm_new(struct snd_card *card, struct snd_soc_dai *dai,
+static int pxa2xx_soc_pcm_new(struct snd_card *card, struct snd_soc_dai *dai,
 	struct snd_pcm *pcm)
 {
 	int ret = 0;
@@ -360,7 +113,7 @@
 struct snd_soc_platform pxa2xx_soc_platform = {
 	.name		= "pxa2xx-audio",
 	.pcm_ops 	= &pxa2xx_pcm_ops,
-	.pcm_new	= pxa2xx_pcm_new,
+	.pcm_new	= pxa2xx_soc_pcm_new,
 	.pcm_free	= pxa2xx_pcm_free_dma_buffers,
 };
 EXPORT_SYMBOL_GPL(pxa2xx_soc_platform);
diff --git a/sound/soc/pxa/pxa2xx-pcm.h b/sound/soc/pxa/pxa2xx-pcm.h
index 54c9c75..60c3b20 100644
--- a/sound/soc/pxa/pxa2xx-pcm.h
+++ b/sound/soc/pxa/pxa2xx-pcm.h
@@ -13,21 +13,6 @@
 #ifndef _PXA2XX_PCM_H
 #define _PXA2XX_PCM_H
 
-struct pxa2xx_pcm_dma_params {
-	char *name;			/* stream identifier */
-	u32 dcmd;			/* DMA descriptor dcmd field */
-	volatile u32 *drcmr;		/* the DMA request channel to use */
-	u32 dev_addr;			/* device physical address for DMA */
-};
-
-struct pxa2xx_gpio {
-	u32 sys;
-	u32	rx;
-	u32 tx;
-	u32 clk;
-	u32 frm;
-};
-
 /* platform data */
 extern struct snd_soc_platform pxa2xx_soc_platform;
 
diff --git a/sound/soc/pxa/spitz.c b/sound/soc/pxa/spitz.c
index 37cb768..d307b67 100644
--- a/sound/soc/pxa/spitz.c
+++ b/sound/soc/pxa/spitz.c
@@ -4,7 +4,7 @@
  * Copyright 2005 Wolfson Microelectronics PLC.
  * Copyright 2005 Openedhand Ltd.
  *
- * Authors: Liam Girdwood <liam.girdwood@wolfsonmicro.com>
+ * Authors: Liam Girdwood <lrg@slimlogic.co.uk>
  *          Richard Purdie <richard@openedhand.com>
  *
  *  This program is free software; you can redistribute  it and/or modify it
@@ -19,16 +19,15 @@
 #include <linux/timer.h>
 #include <linux/interrupt.h>
 #include <linux/platform_device.h>
+#include <linux/gpio.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/soc.h>
 #include <sound/soc-dapm.h>
 
 #include <asm/mach-types.h>
-#include <asm/hardware/scoop.h>
 #include <mach/pxa-regs.h>
 #include <mach/hardware.h>
-#include <mach/akita.h>
 #include <mach/spitz.h>
 #include "../codecs/wm8750.h"
 #include "pxa2xx-pcm.h"
@@ -63,8 +62,8 @@
 		snd_soc_dapm_disable_pin(codec, "Mic Jack");
 		snd_soc_dapm_disable_pin(codec, "Line Jack");
 		snd_soc_dapm_enable_pin(codec, "Headphone Jack");
-		set_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_L);
-		set_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_R);
+		gpio_set_value(SPITZ_GPIO_MUTE_L, 1);
+		gpio_set_value(SPITZ_GPIO_MUTE_R, 1);
 		break;
 	case SPITZ_MIC:
 		/* enable mic jack and bias, mute hp */
@@ -72,8 +71,8 @@
 		snd_soc_dapm_disable_pin(codec, "Headset Jack");
 		snd_soc_dapm_disable_pin(codec, "Line Jack");
 		snd_soc_dapm_enable_pin(codec, "Mic Jack");
-		reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_L);
-		reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_R);
+		gpio_set_value(SPITZ_GPIO_MUTE_L, 0);
+		gpio_set_value(SPITZ_GPIO_MUTE_R, 0);
 		break;
 	case SPITZ_LINE:
 		/* enable line jack, disable mic bias and mute hp */
@@ -81,8 +80,8 @@
 		snd_soc_dapm_disable_pin(codec, "Headset Jack");
 		snd_soc_dapm_disable_pin(codec, "Mic Jack");
 		snd_soc_dapm_enable_pin(codec, "Line Jack");
-		reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_L);
-		reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_R);
+		gpio_set_value(SPITZ_GPIO_MUTE_L, 0);
+		gpio_set_value(SPITZ_GPIO_MUTE_R, 0);
 		break;
 	case SPITZ_HEADSET:
 		/* enable and unmute headset jack enable mic bias, mute L hp */
@@ -90,8 +89,8 @@
 		snd_soc_dapm_enable_pin(codec, "Mic Jack");
 		snd_soc_dapm_disable_pin(codec, "Line Jack");
 		snd_soc_dapm_enable_pin(codec, "Headset Jack");
-		reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_L);
-		set_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_R);
+		gpio_set_value(SPITZ_GPIO_MUTE_L, 0);
+		gpio_set_value(SPITZ_GPIO_MUTE_R, 1);
 		break;
 	case SPITZ_HP_OFF:
 
@@ -100,8 +99,8 @@
 		snd_soc_dapm_disable_pin(codec, "Headset Jack");
 		snd_soc_dapm_disable_pin(codec, "Mic Jack");
 		snd_soc_dapm_disable_pin(codec, "Line Jack");
-		reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_L);
-		reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_R);
+		gpio_set_value(SPITZ_GPIO_MUTE_L, 0);
+		gpio_set_value(SPITZ_GPIO_MUTE_R, 0);
 		break;
 	}
 	snd_soc_dapm_sync(codec);
@@ -215,23 +214,14 @@
 static int spitz_mic_bias(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *k, int event)
 {
-	if (machine_is_borzoi() || machine_is_spitz()) {
-		if (SND_SOC_DAPM_EVENT_ON(event))
-			set_scoop_gpio(&spitzscoop2_device.dev,
-				SPITZ_SCP2_MIC_BIAS);
-		else
-			reset_scoop_gpio(&spitzscoop2_device.dev,
-				SPITZ_SCP2_MIC_BIAS);
-	}
+	if (machine_is_borzoi() || machine_is_spitz())
+		gpio_set_value(SPITZ_GPIO_MIC_BIAS,
+				SND_SOC_DAPM_EVENT_ON(event));
 
-	if (machine_is_akita()) {
-		if (SND_SOC_DAPM_EVENT_ON(event))
-			akita_set_ioexp(&akitaioexp_device.dev,
-				AKITA_IOEXP_MIC_BIAS);
-		else
-			akita_reset_ioexp(&akitaioexp_device.dev,
-				AKITA_IOEXP_MIC_BIAS);
-	}
+	if (machine_is_akita())
+		gpio_set_value(AKITA_GPIO_MIC_BIAS,
+				SND_SOC_DAPM_EVENT_ON(event));
+
 	return 0;
 }
 
@@ -291,13 +281,13 @@
 	int i, err;
 
 	/* NC codec pins */
-	snd_soc_dapm_disable_pin(codec, "RINPUT1");
-	snd_soc_dapm_disable_pin(codec, "LINPUT2");
-	snd_soc_dapm_disable_pin(codec, "RINPUT2");
-	snd_soc_dapm_disable_pin(codec, "LINPUT3");
-	snd_soc_dapm_disable_pin(codec, "RINPUT3");
-	snd_soc_dapm_disable_pin(codec, "OUT3");
-	snd_soc_dapm_disable_pin(codec, "MONO1");
+	snd_soc_dapm_nc_pin(codec, "RINPUT1");
+	snd_soc_dapm_nc_pin(codec, "LINPUT2");
+	snd_soc_dapm_nc_pin(codec, "RINPUT2");
+	snd_soc_dapm_nc_pin(codec, "LINPUT3");
+	snd_soc_dapm_nc_pin(codec, "RINPUT3");
+	snd_soc_dapm_nc_pin(codec, "OUT3");
+	snd_soc_dapm_nc_pin(codec, "MONO1");
 
 	/* Add spitz specific controls */
 	for (i = 0; i < ARRAY_SIZE(wm8750_spitz_controls); i++) {
@@ -337,6 +327,7 @@
 
 /* spitz audio private data */
 static struct wm8750_setup_data spitz_wm8750_setup = {
+	.i2c_bus = 0,
 	.i2c_address = 0x1b,
 };
 
diff --git a/sound/soc/pxa/tosa.c b/sound/soc/pxa/tosa.c
index 2baaa75..afefe41 100644
--- a/sound/soc/pxa/tosa.c
+++ b/sound/soc/pxa/tosa.c
@@ -4,7 +4,7 @@
  * Copyright 2005 Wolfson Microelectronics PLC.
  * Copyright 2005 Openedhand Ltd.
  *
- * Authors: Liam Girdwood <liam.girdwood@wolfsonmicro.com>
+ * Authors: Liam Girdwood <lrg@slimlogic.co.uk>
  *          Richard Purdie <richard@openedhand.com>
  *
  *  This program is free software; you can redistribute  it and/or modify it
@@ -190,8 +190,8 @@
 {
 	int i, err;
 
-	snd_soc_dapm_disable_pin(codec, "OUT3");
-	snd_soc_dapm_disable_pin(codec, "MONOOUT");
+	snd_soc_dapm_nc_pin(codec, "OUT3");
+	snd_soc_dapm_nc_pin(codec, "MONOOUT");
 
 	/* add tosa specific controls */
 	for (i = 0; i < ARRAY_SIZE(tosa_controls); i++) {
diff --git a/sound/soc/s3c24xx/neo1973_wm8753.c b/sound/soc/s3c24xx/neo1973_wm8753.c
index 8089f8e..87ddfef 100644
--- a/sound/soc/s3c24xx/neo1973_wm8753.c
+++ b/sound/soc/s3c24xx/neo1973_wm8753.c
@@ -24,6 +24,7 @@
 #include <sound/soc-dapm.h>
 #include <sound/tlv.h>
 
+#include <asm/mach-types.h>
 #include <asm/hardware/scoop.h>
 #include <mach/regs-clock.h>
 #include <mach/regs-gpio.h>
@@ -510,21 +511,20 @@
 	DBG("Entered %s\n", __func__);
 
 	/* set up NC codec pins */
-	snd_soc_dapm_disable_pin(codec, "LOUT2");
-	snd_soc_dapm_disable_pin(codec, "ROUT2");
-	snd_soc_dapm_disable_pin(codec, "OUT3");
-	snd_soc_dapm_disable_pin(codec, "OUT4");
-	snd_soc_dapm_disable_pin(codec, "LINE1");
-	snd_soc_dapm_disable_pin(codec, "LINE2");
-
-
-	/* set endpoints to default mode */
-	set_scenario_endpoints(codec, NEO_AUDIO_OFF);
+	snd_soc_dapm_nc_pin(codec, "LOUT2");
+	snd_soc_dapm_nc_pin(codec, "ROUT2");
+	snd_soc_dapm_nc_pin(codec, "OUT3");
+	snd_soc_dapm_nc_pin(codec, "OUT4");
+	snd_soc_dapm_nc_pin(codec, "LINE1");
+	snd_soc_dapm_nc_pin(codec, "LINE2");
 
 	/* Add neo1973 specific widgets */
 	snd_soc_dapm_new_controls(codec, wm8753_dapm_widgets,
 				  ARRAY_SIZE(wm8753_dapm_widgets));
 
+	/* set endpoints to default mode */
+	set_scenario_endpoints(codec, NEO_AUDIO_OFF);
+
 	/* add neo1973 specific controls */
 	for (i = 0; i < ARRAY_SIZE(wm8753_neo1973_controls); i++) {
 		err = snd_ctl_add(codec->card,
@@ -586,6 +586,7 @@
 };
 
 static struct wm8753_setup_data neo1973_wm8753_setup = {
+	.i2c_bus = 0,
 	.i2c_address = 0x1a,
 };
 
@@ -596,54 +597,24 @@
 	.codec_data = &neo1973_wm8753_setup,
 };
 
-static struct i2c_client client_template;
-
-static const unsigned short normal_i2c[] = { 0x7C, I2C_CLIENT_END };
-
-/* Magic definition of all other variables and things */
-I2C_CLIENT_INSMOD;
-
-static int lm4857_amp_probe(struct i2c_adapter *adap, int addr, int kind)
+static int lm4857_i2c_probe(struct i2c_client *client,
+			    const struct i2c_device_id *id)
 {
-	int ret;
-
 	DBG("Entered %s\n", __func__);
 
-	client_template.adapter = adap;
-	client_template.addr = addr;
-
-	i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL);
-	if (i2c == NULL)
-		return -ENOMEM;
-
-	ret = i2c_attach_client(i2c);
-	if (ret < 0) {
-		printk(KERN_ERR "LM4857 failed to attach at addr %x\n", addr);
-		goto exit_err;
-	}
+	i2c = client;
 
 	lm4857_write_regs();
-	return ret;
-
-exit_err:
-	kfree(i2c);
-	return ret;
-}
-
-static int lm4857_i2c_detach(struct i2c_client *client)
-{
-	DBG("Entered %s\n", __func__);
-
-	i2c_detach_client(client);
-	kfree(client);
 	return 0;
 }
 
-static int lm4857_i2c_attach(struct i2c_adapter *adap)
+static int lm4857_i2c_remove(struct i2c_client *client)
 {
 	DBG("Entered %s\n", __func__);
 
-	return i2c_probe(adap, &addr_data, lm4857_amp_probe);
+	i2c = NULL;
+
+	return 0;
 }
 
 static u8 lm4857_state;
@@ -681,24 +652,22 @@
 	lm4857_write_regs();
 }
 
-/* corgi i2c codec control layer */
+static const struct i2c_device_id lm4857_i2c_id[] = {
+	{ "neo1973_lm4857", 0 },
+	{ }
+};
+
 static struct i2c_driver lm4857_i2c_driver = {
 	.driver = {
 		.name = "LM4857 I2C Amp",
 		.owner = THIS_MODULE,
 	},
-	.id =             I2C_DRIVERID_LM4857,
 	.suspend =        lm4857_suspend,
 	.resume	=         lm4857_resume,
 	.shutdown =       lm4857_shutdown,
-	.attach_adapter = lm4857_i2c_attach,
-	.detach_client =  lm4857_i2c_detach,
-	.command =        NULL,
-};
-
-static struct i2c_client client_template = {
-	.name =   "LM4857",
-	.driver = &lm4857_i2c_driver,
+	.probe =          lm4857_i2c_probe,
+	.remove =         lm4857_i2c_remove,
+	.id_table =       lm4857_i2c_id,
 };
 
 static struct platform_device *neo1973_snd_device;
@@ -709,6 +678,12 @@
 
 	DBG("Entered %s\n", __func__);
 
+	if (!machine_is_neo1973_gta01()) {
+		printk(KERN_INFO
+			"Only GTA01 hardware supported by ASoC driver\n");
+		return -ENODEV;
+	}
+
 	neo1973_snd_device = platform_device_alloc("soc-audio", -1);
 	if (!neo1973_snd_device)
 		return -ENOMEM;
@@ -717,12 +692,15 @@
 	neo1973_snd_devdata.dev = &neo1973_snd_device->dev;
 	ret = platform_device_add(neo1973_snd_device);
 
-	if (ret)
+	if (ret) {
 		platform_device_put(neo1973_snd_device);
+		return ret;
+	}
 
 	ret = i2c_add_driver(&lm4857_i2c_driver);
+
 	if (ret != 0)
-		printk(KERN_ERR "can't add i2c driver");
+		platform_device_unregister(neo1973_snd_device);
 
 	return ret;
 }
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index 83f1190..462e635d 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -4,8 +4,7 @@
  * Copyright 2005 Wolfson Microelectronics PLC.
  * Copyright 2005 Openedhand Ltd.
  *
- * Author: Liam Girdwood
- *         liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com
+ * Author: Liam Girdwood <lrg@slimlogic.co.uk>
  *         with code, comments and ideas from :-
  *         Richard Purdie <richard@openedhand.com>
  *
@@ -340,6 +339,12 @@
 	}
 	codec->active--;
 
+	/* Muting the DAC suppresses artifacts caused during digital
+	 * shutdown, for example from stopping clocks.
+	 */
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		snd_soc_dai_digital_mute(codec_dai, 1);
+
 	if (cpu_dai->ops.shutdown)
 		cpu_dai->ops.shutdown(substream);
 
@@ -970,9 +975,29 @@
 		step = codec->reg_cache_step;
 
 	count += sprintf(buf, "%s registers\n", codec->name);
-	for (i = 0; i < codec->reg_cache_size; i += step)
-		count += sprintf(buf + count, "%2x: %4x\n", i,
-			codec->read(codec, i));
+	for (i = 0; i < codec->reg_cache_size; i += step) {
+		count += sprintf(buf + count, "%2x: ", i);
+		if (count >= PAGE_SIZE - 1)
+			break;
+
+		if (codec->display_register)
+			count += codec->display_register(codec, buf + count,
+							 PAGE_SIZE - count, i);
+		else
+			count += snprintf(buf + count, PAGE_SIZE - count,
+					  "%4x", codec->read(codec, i));
+
+		if (count >= PAGE_SIZE - 1)
+			break;
+
+		count += snprintf(buf + count, PAGE_SIZE - count, "\n");
+		if (count >= PAGE_SIZE - 1)
+			break;
+	}
+
+	/* Truncate count; min() would cause a warning */
+	if (count >= PAGE_SIZE)
+		count = PAGE_SIZE - 1;
 
 	return count;
 }
@@ -1296,10 +1321,10 @@
 
 	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
 	uinfo->count = e->shift_l == e->shift_r ? 1 : 2;
-	uinfo->value.enumerated.items = e->mask;
+	uinfo->value.enumerated.items = e->max;
 
-	if (uinfo->value.enumerated.item > e->mask - 1)
-		uinfo->value.enumerated.item = e->mask - 1;
+	if (uinfo->value.enumerated.item > e->max - 1)
+		uinfo->value.enumerated.item = e->max - 1;
 	strcpy(uinfo->value.enumerated.name,
 		e->texts[uinfo->value.enumerated.item]);
 	return 0;
@@ -1322,7 +1347,7 @@
 	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
 	unsigned short val, bitmask;
 
-	for (bitmask = 1; bitmask < e->mask; bitmask <<= 1)
+	for (bitmask = 1; bitmask < e->max; bitmask <<= 1)
 		;
 	val = snd_soc_read(codec, e->reg);
 	ucontrol->value.enumerated.item[0]
@@ -1352,14 +1377,14 @@
 	unsigned short val;
 	unsigned short mask, bitmask;
 
-	for (bitmask = 1; bitmask < e->mask; bitmask <<= 1)
+	for (bitmask = 1; bitmask < e->max; bitmask <<= 1)
 		;
-	if (ucontrol->value.enumerated.item[0] > e->mask - 1)
+	if (ucontrol->value.enumerated.item[0] > e->max - 1)
 		return -EINVAL;
 	val = ucontrol->value.enumerated.item[0] << e->shift_l;
 	mask = (bitmask - 1) << e->shift_l;
 	if (e->shift_l != e->shift_r) {
-		if (ucontrol->value.enumerated.item[1] > e->mask - 1)
+		if (ucontrol->value.enumerated.item[1] > e->max - 1)
 			return -EINVAL;
 		val |= ucontrol->value.enumerated.item[1] << e->shift_r;
 		mask |= (bitmask - 1) << e->shift_r;
@@ -1386,10 +1411,10 @@
 
 	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
 	uinfo->count = 1;
-	uinfo->value.enumerated.items = e->mask;
+	uinfo->value.enumerated.items = e->max;
 
-	if (uinfo->value.enumerated.item > e->mask - 1)
-		uinfo->value.enumerated.item = e->mask - 1;
+	if (uinfo->value.enumerated.item > e->max - 1)
+		uinfo->value.enumerated.item = e->max - 1;
 	strcpy(uinfo->value.enumerated.name,
 		e->texts[uinfo->value.enumerated.item]);
 	return 0;
@@ -1434,9 +1459,11 @@
 int snd_soc_info_volsw(struct snd_kcontrol *kcontrol,
 	struct snd_ctl_elem_info *uinfo)
 {
-	int max = (kcontrol->private_value >> 16) & 0xff;
-	int shift = (kcontrol->private_value >> 8) & 0x0f;
-	int rshift = (kcontrol->private_value >> 12) & 0x0f;
+	struct soc_mixer_control *mc =
+		(struct soc_mixer_control *)kcontrol->private_value;
+	int max = mc->max;
+	unsigned int shift = mc->min;
+	unsigned int rshift = mc->rshift;
 
 	if (max == 1)
 		uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
@@ -1462,13 +1489,15 @@
 int snd_soc_get_volsw(struct snd_kcontrol *kcontrol,
 	struct snd_ctl_elem_value *ucontrol)
 {
+	struct soc_mixer_control *mc =
+		(struct soc_mixer_control *)kcontrol->private_value;
 	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
-	int reg = kcontrol->private_value & 0xff;
-	int shift = (kcontrol->private_value >> 8) & 0x0f;
-	int rshift = (kcontrol->private_value >> 12) & 0x0f;
-	int max = (kcontrol->private_value >> 16) & 0xff;
-	int mask = (1 << fls(max)) - 1;
-	int invert = (kcontrol->private_value >> 24) & 0x01;
+	unsigned int reg = mc->reg;
+	unsigned int shift = mc->shift;
+	unsigned int rshift = mc->rshift;
+	int max = mc->max;
+	unsigned int mask = (1 << fls(max)) - 1;
+	unsigned int invert = mc->invert;
 
 	ucontrol->value.integer.value[0] =
 		(snd_soc_read(codec, reg) >> shift) & mask;
@@ -1499,13 +1528,15 @@
 int snd_soc_put_volsw(struct snd_kcontrol *kcontrol,
 	struct snd_ctl_elem_value *ucontrol)
 {
+	struct soc_mixer_control *mc =
+		(struct soc_mixer_control *)kcontrol->private_value;
 	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
-	int reg = kcontrol->private_value & 0xff;
-	int shift = (kcontrol->private_value >> 8) & 0x0f;
-	int rshift = (kcontrol->private_value >> 12) & 0x0f;
-	int max = (kcontrol->private_value >> 16) & 0xff;
-	int mask = (1 << fls(max)) - 1;
-	int invert = (kcontrol->private_value >> 24) & 0x01;
+	unsigned int reg = mc->reg;
+	unsigned int shift = mc->shift;
+	unsigned int rshift = mc->rshift;
+	int max = mc->max;
+	unsigned int mask = (1 << fls(max)) - 1;
+	unsigned int invert = mc->invert;
 	unsigned short val, val2, val_mask;
 
 	val = (ucontrol->value.integer.value[0] & mask);
@@ -1537,7 +1568,9 @@
 int snd_soc_info_volsw_2r(struct snd_kcontrol *kcontrol,
 	struct snd_ctl_elem_info *uinfo)
 {
-	int max = (kcontrol->private_value >> 12) & 0xff;
+	struct soc_mixer_control *mc =
+		(struct soc_mixer_control *)kcontrol->private_value;
+	int max = mc->max;
 
 	if (max == 1)
 		uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
@@ -1563,13 +1596,15 @@
 int snd_soc_get_volsw_2r(struct snd_kcontrol *kcontrol,
 	struct snd_ctl_elem_value *ucontrol)
 {
+	struct soc_mixer_control *mc =
+		(struct soc_mixer_control *)kcontrol->private_value;
 	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
-	int reg = kcontrol->private_value & 0xff;
-	int reg2 = (kcontrol->private_value >> 24) & 0xff;
-	int shift = (kcontrol->private_value >> 8) & 0x0f;
-	int max = (kcontrol->private_value >> 12) & 0xff;
-	int mask = (1<<fls(max))-1;
-	int invert = (kcontrol->private_value >> 20) & 0x01;
+	unsigned int reg = mc->reg;
+	unsigned int reg2 = mc->rreg;
+	unsigned int shift = mc->shift;
+	int max = mc->max;
+	unsigned int mask = (1<<fls(max))-1;
+	unsigned int invert = mc->invert;
 
 	ucontrol->value.integer.value[0] =
 		(snd_soc_read(codec, reg) >> shift) & mask;
@@ -1598,13 +1633,15 @@
 int snd_soc_put_volsw_2r(struct snd_kcontrol *kcontrol,
 	struct snd_ctl_elem_value *ucontrol)
 {
+	struct soc_mixer_control *mc =
+		(struct soc_mixer_control *)kcontrol->private_value;
 	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
-	int reg = kcontrol->private_value & 0xff;
-	int reg2 = (kcontrol->private_value >> 24) & 0xff;
-	int shift = (kcontrol->private_value >> 8) & 0x0f;
-	int max = (kcontrol->private_value >> 12) & 0xff;
-	int mask = (1 << fls(max)) - 1;
-	int invert = (kcontrol->private_value >> 20) & 0x01;
+	unsigned int reg = mc->reg;
+	unsigned int reg2 = mc->rreg;
+	unsigned int shift = mc->shift;
+	int max = mc->max;
+	unsigned int mask = (1 << fls(max)) - 1;
+	unsigned int invert = mc->invert;
 	int err;
 	unsigned short val, val2, val_mask;
 
@@ -1641,8 +1678,10 @@
 int snd_soc_info_volsw_s8(struct snd_kcontrol *kcontrol,
 	struct snd_ctl_elem_info *uinfo)
 {
-	int max = (signed char)((kcontrol->private_value >> 16) & 0xff);
-	int min = (signed char)((kcontrol->private_value >> 24) & 0xff);
+	struct soc_mixer_control *mc =
+		(struct soc_mixer_control *)kcontrol->private_value;
+	int max = mc->max;
+	int min = mc->min;
 
 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
 	uinfo->count = 2;
@@ -1664,9 +1703,11 @@
 int snd_soc_get_volsw_s8(struct snd_kcontrol *kcontrol,
 	struct snd_ctl_elem_value *ucontrol)
 {
+	struct soc_mixer_control *mc =
+		(struct soc_mixer_control *)kcontrol->private_value;
 	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
-	int reg = kcontrol->private_value & 0xff;
-	int min = (signed char)((kcontrol->private_value >> 24) & 0xff);
+	unsigned int reg = mc->reg;
+	int min = mc->min;
 	int val = snd_soc_read(codec, reg);
 
 	ucontrol->value.integer.value[0] =
@@ -1689,9 +1730,11 @@
 int snd_soc_put_volsw_s8(struct snd_kcontrol *kcontrol,
 	struct snd_ctl_elem_value *ucontrol)
 {
+	struct soc_mixer_control *mc =
+		(struct soc_mixer_control *)kcontrol->private_value;
 	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
-	int reg = kcontrol->private_value & 0xff;
-	int min = (signed char)((kcontrol->private_value >> 24) & 0xff);
+	unsigned int reg = mc->reg;
+	int min = mc->min;
 	unsigned short val;
 
 	val = (ucontrol->value.integer.value[0]+min) & 0xff;
@@ -1842,7 +1885,7 @@
 module_exit(snd_soc_exit);
 
 /* Module information */
-MODULE_AUTHOR("Liam Girdwood, liam.girdwood@wolfsonmicro.com, www.wolfsonmicro.com");
+MODULE_AUTHOR("Liam Girdwood, lrg@slimlogic.co.uk");
 MODULE_DESCRIPTION("ALSA SoC Core");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS("platform:soc-audio");
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index f9d100b..efbd0b3 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -2,8 +2,7 @@
  * soc-dapm.c  --  ALSA SoC Dynamic Audio Power Management
  *
  * Copyright 2005 Wolfson Microelectronics PLC.
- * Author: Liam Girdwood
- *         liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com
+ * Author: Liam Girdwood <lrg@slimlogic.co.uk>
  *
  *  This program is free software; you can redistribute  it and/or modify it
  *  under  the terms of  the GNU General  Public License as published by the
@@ -38,6 +37,7 @@
 #include <linux/bitops.h>
 #include <linux/platform_device.h>
 #include <linux/jiffies.h>
+#include <linux/debugfs.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
@@ -67,7 +67,9 @@
 module_param(dapm_status, int, 0);
 MODULE_PARM_DESC(dapm_status, "enable DPM sysfs entries");
 
-static unsigned int pop_time;
+static struct dentry *asoc_debugfs;
+
+static u32 pop_time;
 
 static void pop_wait(void)
 {
@@ -104,10 +106,13 @@
 	case snd_soc_dapm_switch:
 	case snd_soc_dapm_mixer: {
 		int val;
-		int reg = w->kcontrols[i].private_value & 0xff;
-		int shift = (w->kcontrols[i].private_value >> 8) & 0x0f;
-		int mask = (w->kcontrols[i].private_value >> 16) & 0xff;
-		int invert = (w->kcontrols[i].private_value >> 24) & 0x01;
+		struct soc_mixer_control *mc = (struct soc_mixer_control *)
+			w->kcontrols[i].private_value;
+		unsigned int reg = mc->reg;
+		unsigned int shift = mc->shift;
+		int max = mc->max;
+		unsigned int mask = (1 << fls(max)) - 1;
+		unsigned int invert = mc->invert;
 
 		val = snd_soc_read(w->codec, reg);
 		val = (val >> shift) & mask;
@@ -122,13 +127,13 @@
 		struct soc_enum *e = (struct soc_enum *)w->kcontrols[i].private_value;
 		int val, item, bitmask;
 
-		for (bitmask = 1; bitmask < e->mask; bitmask <<= 1)
+		for (bitmask = 1; bitmask < e->max; bitmask <<= 1)
 		;
 		val = snd_soc_read(w->codec, e->reg);
 		item = (val >> e->shift_l) & (bitmask - 1);
 
 		p->connect = 0;
-		for (i = 0; i < e->mask; i++) {
+		for (i = 0; i < e->max; i++) {
 			if (!(strcmp(p->name, e->texts[i])) && item == i)
 				p->connect = 1;
 		}
@@ -165,7 +170,7 @@
 	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
 	int i;
 
-	for (i = 0; i < e->mask; i++) {
+	for (i = 0; i < e->max; i++) {
 		if (!(strcmp(control_name, e->texts[i]))) {
 			list_add(&path->list, &codec->dapm_paths);
 			list_add(&path->list_sink, &dest->sources);
@@ -247,16 +252,19 @@
 		return 0;
 
 	if (widget->num_kcontrols && k) {
-		int reg = k->private_value & 0xff;
-		int shift = (k->private_value >> 8) & 0x0f;
-		int mask = (k->private_value >> 16) & 0xff;
-		int invert = (k->private_value >> 24) & 0x01;
+		struct soc_mixer_control *mc =
+			(struct soc_mixer_control *)k->private_value;
+		unsigned int reg = mc->reg;
+		unsigned int shift = mc->shift;
+		int max = mc->max;
+		unsigned int mask = (1 << fls(max)) - 1;
+		unsigned int invert = mc->invert;
 
 		if (power) {
 			int i;
 			/* power up has happended, increase volume to last level */
 			if (invert) {
-				for (i = mask; i > widget->saved_value; i--)
+				for (i = max; i > widget->saved_value; i--)
 					snd_soc_update_bits(widget->codec, reg, mask, i);
 			} else {
 				for (i = 0; i < widget->saved_value; i++)
@@ -684,7 +692,7 @@
 /* test and update the power status of a mux widget */
 static int dapm_mux_update_power(struct snd_soc_dapm_widget *widget,
 				 struct snd_kcontrol *kcontrol, int mask,
-				 int val, struct soc_enum* e)
+				 int mux, int val, struct soc_enum *e)
 {
 	struct snd_soc_dapm_path *path;
 	int found = 0;
@@ -700,12 +708,12 @@
 		if (path->kcontrol != kcontrol)
 			continue;
 
-		if (!path->name || ! e->texts[val])
+		if (!path->name || !e->texts[mux])
 			continue;
 
 		found = 1;
 		/* we now need to match the string in the enum to the path */
-		if (!(strcmp(path->name, e->texts[val])))
+		if (!(strcmp(path->name, e->texts[mux])))
 			path->connect = 1; /* new connection */
 		else
 			path->connect = 0; /* old connection must be powered down */
@@ -811,51 +819,35 @@
 
 static DEVICE_ATTR(dapm_widget, 0444, dapm_widget_show, NULL);
 
-/* pop/click delay times */
-static ssize_t dapm_pop_time_show(struct device *dev,
-	struct device_attribute *attr, char *buf)
-{
-	return sprintf(buf, "%d\n", pop_time);
-}
-
-static ssize_t dapm_pop_time_store(struct device *dev,
-				   struct device_attribute *attr,
-				   const char *buf, size_t count)
-
-{
-	unsigned long val;
-
-	if (strict_strtoul(buf, 10, &val) >= 0)
-		pop_time = val;
-	else
-		printk(KERN_ERR "Unable to parse pop_time setting\n");
-
-	return count;
-}
-
-static DEVICE_ATTR(dapm_pop_time, 0744, dapm_pop_time_show,
-		   dapm_pop_time_store);
-
 int snd_soc_dapm_sys_add(struct device *dev)
 {
 	int ret = 0;
 
-	if (dapm_status) {
-		ret = device_create_file(dev, &dev_attr_dapm_widget);
+	if (!dapm_status)
+		return 0;
 
-		if (ret == 0)
-			ret = device_create_file(dev, &dev_attr_dapm_pop_time);
-	}
+	ret = device_create_file(dev, &dev_attr_dapm_widget);
+	if (ret != 0)
+		return ret;
 
-	return ret;
+	asoc_debugfs = debugfs_create_dir("asoc", NULL);
+	if (!IS_ERR(asoc_debugfs))
+		debugfs_create_u32("dapm_pop_time", 0744, asoc_debugfs,
+				   &pop_time);
+	else
+		asoc_debugfs = NULL;
+
+	return 0;
 }
 
 static void snd_soc_dapm_sys_remove(struct device *dev)
 {
 	if (dapm_status) {
-		device_remove_file(dev, &dev_attr_dapm_pop_time);
 		device_remove_file(dev, &dev_attr_dapm_widget);
 	}
+
+	if (asoc_debugfs)
+		debugfs_remove_recursive(asoc_debugfs);
 }
 
 /* free all dapm widgets and resources */
@@ -1133,12 +1125,14 @@
 	struct snd_ctl_elem_value *ucontrol)
 {
 	struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol);
-	int reg = kcontrol->private_value & 0xff;
-	int shift = (kcontrol->private_value >> 8) & 0x0f;
-	int rshift = (kcontrol->private_value >> 12) & 0x0f;
-	int max = (kcontrol->private_value >> 16) & 0xff;
-	int invert = (kcontrol->private_value >> 24) & 0x01;
-	int mask = (1 << fls(max)) - 1;
+	struct soc_mixer_control *mc =
+		(struct soc_mixer_control *)kcontrol->private_value;
+	unsigned int reg = mc->reg;
+	unsigned int shift = mc->shift;
+	unsigned int rshift = mc->rshift;
+	int max = mc->max;
+	unsigned int invert = mc->invert;
+	unsigned int mask = (1 << fls(max)) - 1;
 
 	/* return the saved value if we are powered down */
 	if (widget->id == snd_soc_dapm_pga && !widget->power) {
@@ -1176,12 +1170,14 @@
 	struct snd_ctl_elem_value *ucontrol)
 {
 	struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol);
-	int reg = kcontrol->private_value & 0xff;
-	int shift = (kcontrol->private_value >> 8) & 0x0f;
-	int rshift = (kcontrol->private_value >> 12) & 0x0f;
-	int max = (kcontrol->private_value >> 16) & 0xff;
-	int mask = (1 << fls(max)) - 1;
-	int invert = (kcontrol->private_value >> 24) & 0x01;
+	struct soc_mixer_control *mc =
+		(struct soc_mixer_control *)kcontrol->private_value;
+	unsigned int reg = mc->reg;
+	unsigned int shift = mc->shift;
+	unsigned int rshift = mc->rshift;
+	int max = mc->max;
+	unsigned int mask = (1 << fls(max)) - 1;
+	unsigned int invert = mc->invert;
 	unsigned short val, val2, val_mask;
 	int ret;
 
@@ -1248,7 +1244,7 @@
 	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
 	unsigned short val, bitmask;
 
-	for (bitmask = 1; bitmask < e->mask; bitmask <<= 1)
+	for (bitmask = 1; bitmask < e->max; bitmask <<= 1)
 		;
 	val = snd_soc_read(widget->codec, e->reg);
 	ucontrol->value.enumerated.item[0] = (val >> e->shift_l) & (bitmask - 1);
@@ -1278,15 +1274,15 @@
 	unsigned short mask, bitmask;
 	int ret = 0;
 
-	for (bitmask = 1; bitmask < e->mask; bitmask <<= 1)
+	for (bitmask = 1; bitmask < e->max; bitmask <<= 1)
 		;
-	if (ucontrol->value.enumerated.item[0] > e->mask - 1)
+	if (ucontrol->value.enumerated.item[0] > e->max - 1)
 		return -EINVAL;
 	mux = ucontrol->value.enumerated.item[0];
 	val = mux << e->shift_l;
 	mask = (bitmask - 1) << e->shift_l;
 	if (e->shift_l != e->shift_r) {
-		if (ucontrol->value.enumerated.item[1] > e->mask - 1)
+		if (ucontrol->value.enumerated.item[1] > e->max - 1)
 			return -EINVAL;
 		val |= ucontrol->value.enumerated.item[1] << e->shift_r;
 		mask |= (bitmask - 1) << e->shift_r;
@@ -1294,7 +1290,7 @@
 
 	mutex_lock(&widget->codec->mutex);
 	widget->value = val;
-	dapm_mux_update_power(widget, kcontrol, mask, mux, e);
+	dapm_mux_update_power(widget, kcontrol, mask, mux, val, e);
 	if (widget->event) {
 		if (widget->event_flags & SND_SOC_DAPM_PRE_REG) {
 			ret = widget->event(widget,
@@ -1487,6 +1483,26 @@
 EXPORT_SYMBOL_GPL(snd_soc_dapm_disable_pin);
 
 /**
+ * snd_soc_dapm_nc_pin - permanently disable pin.
+ * @codec: SoC codec
+ * @pin: pin name
+ *
+ * Marks the specified pin as being not connected, disabling it along
+ * any parent or child widgets.  At present this is identical to
+ * snd_soc_dapm_disable_pin() but in future it will be extended to do
+ * additional things such as disabling controls which only affect
+ * paths through the pin.
+ *
+ * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
+ * do any widget power switching.
+ */
+int snd_soc_dapm_nc_pin(struct snd_soc_codec *codec, char *pin)
+{
+	return snd_soc_dapm_set_pin(codec, pin, 0);
+}
+EXPORT_SYMBOL_GPL(snd_soc_dapm_nc_pin);
+
+/**
  * snd_soc_dapm_get_pin_status - get audio pin status
  * @codec: audio codec
  * @pin: audio signal pin endpoint (or start point)
@@ -1524,6 +1540,6 @@
 EXPORT_SYMBOL_GPL(snd_soc_dapm_free);
 
 /* Module information */
-MODULE_AUTHOR("Liam Girdwood, liam.girdwood@wolfsonmicro.com, www.wolfsonmicro.com");
+MODULE_AUTHOR("Liam Girdwood, lrg@slimlogic.co.uk");
 MODULE_DESCRIPTION("Dynamic Audio Power Management core for ALSA SoC");
 MODULE_LICENSE("GPL");
diff --git a/sound/sound_core.c b/sound/sound_core.c
index 1b04259..4ae07e2 100644
--- a/sound/sound_core.c
+++ b/sound/sound_core.c
@@ -1,5 +1,61 @@
 /*
- *	Sound core handling. Breaks out sound functions to submodules
+ *	Sound core.  This file is composed of two parts.  sound_class
+ *	which is common to both OSS and ALSA and OSS sound core which
+ *	is used OSS or emulation of it.
+ */
+
+/*
+ * First, the common part.
+ */
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/err.h>
+
+#ifdef CONFIG_SOUND_OSS_CORE
+static int __init init_oss_soundcore(void);
+static void cleanup_oss_soundcore(void);
+#else
+static inline int init_oss_soundcore(void)	{ return 0; }
+static inline void cleanup_oss_soundcore(void)	{ }
+#endif
+
+struct class *sound_class;
+EXPORT_SYMBOL(sound_class);
+
+MODULE_DESCRIPTION("Core sound module");
+MODULE_AUTHOR("Alan Cox");
+MODULE_LICENSE("GPL");
+
+static int __init init_soundcore(void)
+{
+	int rc;
+
+	rc = init_oss_soundcore();
+	if (rc)
+		return rc;
+
+	sound_class = class_create(THIS_MODULE, "sound");
+	if (IS_ERR(sound_class)) {
+		cleanup_oss_soundcore();
+		return PTR_ERR(sound_class);
+	}
+
+	return 0;
+}
+
+static void __exit cleanup_soundcore(void)
+{
+	cleanup_oss_soundcore();
+	class_destroy(sound_class);
+}
+
+module_init(init_soundcore);
+module_exit(cleanup_soundcore);
+
+
+#ifdef CONFIG_SOUND_OSS_CORE
+/*
+ *	OSS sound core handling. Breaks out sound functions to submodules
  *	
  *	Author:		Alan Cox <alan.cox@linux.org>
  *
@@ -34,21 +90,17 @@
  *	locking at some point in 2.3.x.
  */
 
-#include <linux/module.h>
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/smp_lock.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
-#include <linux/fs.h>
 #include <linux/sound.h>
 #include <linux/major.h>
 #include <linux/kmod.h>
-#include <linux/device.h>
 
 #define SOUND_STEP 16
 
-
 struct sound_unit
 {
 	int unit_minor;
@@ -64,9 +116,6 @@
 extern int msnd_pinnacle_init(void);
 #endif
 
-struct class *sound_class;
-EXPORT_SYMBOL(sound_class);
-
 /*
  *	Low level list operator. Scan the ordered list, find a hole and
  *	join into it. Called with the lock asserted
@@ -523,31 +572,23 @@
 	return -ENODEV;
 }
 
-MODULE_DESCRIPTION("Core sound module");
-MODULE_AUTHOR("Alan Cox");
-MODULE_LICENSE("GPL");
 MODULE_ALIAS_CHARDEV_MAJOR(SOUND_MAJOR);
 
-static void __exit cleanup_soundcore(void)
+static void cleanup_oss_soundcore(void)
 {
 	/* We have nothing to really do here - we know the lists must be
 	   empty */
 	unregister_chrdev(SOUND_MAJOR, "sound");
-	class_destroy(sound_class);
 }
 
-static int __init init_soundcore(void)
+static int __init init_oss_soundcore(void)
 {
 	if (register_chrdev(SOUND_MAJOR, "sound", &soundcore_fops)==-1) {
 		printk(KERN_ERR "soundcore: sound device already in use.\n");
 		return -EBUSY;
 	}
-	sound_class = class_create(THIS_MODULE, "sound");
-	if (IS_ERR(sound_class))
-		return PTR_ERR(sound_class);
 
 	return 0;
 }
 
-module_init(init_soundcore);
-module_exit(cleanup_soundcore);
+#endif /* CONFIG_SOUND_OSS_CORE */
diff --git a/sound/sparc/amd7930.c b/sound/sparc/amd7930.c
index 0c63e05..f87933e 100644
--- a/sound/sparc/amd7930.c
+++ b/sound/sparc/amd7930.c
@@ -1,6 +1,6 @@
 /*
  * Driver for AMD7930 sound chips found on Sparcs.
- * Copyright (C) 2002 David S. Miller <davem@redhat.com>
+ * Copyright (C) 2002, 2008 David S. Miller <davem@davemloft.net>
  *
  * Based entirely upon drivers/sbus/audio/amd7930.c which is:
  * Copyright (C) 1996,1997 Thomas K. Dyas (tdyas@eden.rutgers.edu)
@@ -35,6 +35,8 @@
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/moduleparam.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 
 #include <sound/core.h>
 #include <sound/pcm.h>
@@ -44,7 +46,6 @@
 
 #include <asm/io.h>
 #include <asm/irq.h>
-#include <asm/sbus.h>
 #include <asm/prom.h>
 
 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;	/* Index 0-MAX */
@@ -335,8 +336,8 @@
 	int			pgain;
 	int			mgain;
 
+	struct of_device	*op;
 	unsigned int		irq;
-	unsigned int		regs_size;
 	struct snd_amd7930	*next;
 };
 
@@ -765,7 +766,6 @@
 			       /* playback count */ 1,
 			       /* capture count */  1, &pcm)) < 0)
 		return err;
-	snd_assert(pcm != NULL, return -EINVAL);
 
 	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_amd7930_playback_ops);
 	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_amd7930_capture_ops);
@@ -788,13 +788,6 @@
 
 static int snd_amd7930_info_volume(struct snd_kcontrol *kctl, struct snd_ctl_elem_info *uinfo)
 {
-	int type = kctl->private_value;
-
-	snd_assert(type == VOLUME_MONITOR ||
-		   type == VOLUME_CAPTURE ||
-		   type == VOLUME_PLAYBACK, return -EINVAL);
-	(void) type;
-
 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
 	uinfo->count = 1;
 	uinfo->value.integer.min = 0;
@@ -809,10 +802,6 @@
 	int type = kctl->private_value;
 	int *swval;
 
-	snd_assert(type == VOLUME_MONITOR ||
-		   type == VOLUME_CAPTURE ||
-		   type == VOLUME_PLAYBACK, return -EINVAL);
-
 	switch (type) {
 	case VOLUME_MONITOR:
 		swval = &amd->mgain;
@@ -838,10 +827,6 @@
 	int type = kctl->private_value;
 	int *swval, change;
 
-	snd_assert(type == VOLUME_MONITOR ||
-		   type == VOLUME_CAPTURE ||
-		   type == VOLUME_PLAYBACK, return -EINVAL);
-
 	switch (type) {
 	case VOLUME_MONITOR:
 		swval = &amd->mgain;
@@ -904,7 +889,8 @@
 	struct snd_card *card;
 	int idx, err;
 
-	snd_assert(amd != NULL && amd->card != NULL, return -EINVAL);
+	if (snd_BUG_ON(!amd || !amd->card))
+		return -EINVAL;
 
 	card = amd->card;
 	strcpy(card->mixername, card->shortname);
@@ -920,13 +906,16 @@
 
 static int snd_amd7930_free(struct snd_amd7930 *amd)
 {
+	struct of_device *op = amd->op;
+
 	amd7930_idle(amd);
 
 	if (amd->irq)
 		free_irq(amd->irq, amd);
 
 	if (amd->regs)
-		sbus_iounmap(amd->regs, amd->regs_size);
+		of_iounmap(&op->resource[0], amd->regs,
+			   resource_size(&op->resource[0]));
 
 	kfree(amd);
 
@@ -945,13 +934,12 @@
 };
 
 static int __devinit snd_amd7930_create(struct snd_card *card,
-					struct resource *rp,
-					unsigned int reg_size,
+					struct of_device *op,
 					int irq, int dev,
 					struct snd_amd7930 **ramd)
 {
-	unsigned long flags;
 	struct snd_amd7930 *amd;
+	unsigned long flags;
 	int err;
 
 	*ramd = NULL;
@@ -961,9 +949,10 @@
 
 	spin_lock_init(&amd->lock);
 	amd->card = card;
-	amd->regs_size = reg_size;
+	amd->op = op;
 
-	amd->regs = sbus_ioremap(rp, 0, amd->regs_size, "amd7930");
+	amd->regs = of_ioremap(&op->resource[0], 0,
+			       resource_size(&op->resource[0]), "amd7930");
 	if (!amd->regs) {
 		snd_printk("amd7930-%d: Unable to map chip registers.\n", dev);
 		return -EIO;
@@ -1012,12 +1001,15 @@
 	return 0;
 }
 
-static int __devinit amd7930_attach_common(struct resource *rp, int irq)
+static int __devinit amd7930_sbus_probe(struct of_device *op, const struct of_device_id *match)
 {
+	struct resource *rp = &op->resource[0];
 	static int dev_num;
 	struct snd_card *card;
 	struct snd_amd7930 *amd;
-	int err;
+	int err, irq;
+
+	irq = op->irqs[0];
 
 	if (dev_num >= SNDRV_CARDS)
 		return -ENODEV;
@@ -1038,8 +1030,7 @@
 		(unsigned long long)rp->start,
 		irq);
 
-	if ((err = snd_amd7930_create(card, rp,
-				      (rp->end - rp->start) + 1,
+	if ((err = snd_amd7930_create(card, op,
 				      irq, dev_num, &amd)) < 0)
 		goto out_err;
 
@@ -1064,43 +1055,7 @@
 	return err;
 }
 
-static int __devinit amd7930_obio_attach(struct device_node *dp)
-{
-	const struct linux_prom_registers *regs;
-	const struct linux_prom_irqs *irqp;
-	struct resource res, *rp;
-	int len;
-
-	irqp = of_get_property(dp, "intr", &len);
-	if (!irqp) {
-		snd_printk("%s: Firmware node lacks IRQ property.\n",
-			   dp->full_name);
-		return -ENODEV;
-	}
-
-	regs = of_get_property(dp, "reg", &len);
-	if (!regs) {
-		snd_printk("%s: Firmware node lacks register property.\n",
-			   dp->full_name);
-		return -ENODEV;
-	}
-
-	rp = &res;
-	rp->start = regs->phys_addr;
-	rp->end = rp->start + regs->reg_size - 1;
-	rp->flags = IORESOURCE_IO | (regs->which_io & 0xff);
-
-	return amd7930_attach_common(rp, irqp->pri);
-}
-
-static int __devinit amd7930_sbus_probe(struct of_device *dev, const struct of_device_id *match)
-{
-	struct sbus_dev *sdev = to_sbus_device(&dev->dev);
-
-	return amd7930_attach_common(&sdev->resource[0], sdev->irqs[0]);
-}
-
-static struct of_device_id amd7930_match[] = {
+static const struct of_device_id amd7930_match[] = {
 	{
 		.name = "audio",
 	},
@@ -1115,20 +1070,7 @@
 
 static int __init amd7930_init(void)
 {
-	struct device_node *dp;
-
-	/* Try to find the sun4c "audio" node first. */
-	dp = of_find_node_by_path("/");
-	dp = dp->child;
-	while (dp) {
-		if (!strcmp(dp->name, "audio"))
-			amd7930_obio_attach(dp);
-
-		dp = dp->sibling;
-	}
-
-	/* Probe each SBUS for amd7930 chips. */
-	return of_register_driver(&amd7930_sbus_driver, &sbus_bus_type);
+	return of_register_driver(&amd7930_sbus_driver, &of_bus_type);
 }
 
 static void __exit amd7930_exit(void)
diff --git a/sound/sparc/cs4231.c b/sound/sparc/cs4231.c
index 1c4797b..d44bf98 100644
--- a/sound/sparc/cs4231.c
+++ b/sound/sparc/cs4231.c
@@ -1,6 +1,6 @@
 /*
  * Driver for CS4231 sound chips found on Sparcs.
- * Copyright (C) 2002 David S. Miller <davem@redhat.com>
+ * Copyright (C) 2002, 2008 David S. Miller <davem@davemloft.net>
  *
  * Based entirely upon drivers/sbus/audio/cs4231.c which is:
  * Copyright (C) 1996, 1997, 1998 Derrick J Brashear (shadow@andrew.cmu.edu)
@@ -17,7 +17,8 @@
 #include <linux/moduleparam.h>
 #include <linux/irq.h>
 #include <linux/io.h>
-
+#include <linux/of.h>
+#include <linux/of_device.h>
 
 #include <sound/core.h>
 #include <sound/pcm.h>
@@ -29,13 +30,12 @@
 
 #ifdef CONFIG_SBUS
 #define SBUS_SUPPORT
-#include <asm/sbus.h>
 #endif
 
 #if defined(CONFIG_PCI) && defined(CONFIG_SPARC64)
 #define EBUS_SUPPORT
 #include <linux/pci.h>
-#include <asm/ebus.h>
+#include <asm/ebus_dma.h>
 #endif
 
 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;	/* Index 0-MAX */
@@ -70,8 +70,6 @@
 	int		(*request)(struct cs4231_dma_control *dma_cont,
 				   dma_addr_t bus_addr, size_t len);
 	unsigned int	(*address)(struct cs4231_dma_control *dma_cont);
-	void		(*preallocate)(struct snd_cs4231 *chip,
-				       struct snd_pcm *pcm);
 #ifdef EBUS_SUPPORT
 	struct		ebus_dma_info	ebus_info;
 #endif
@@ -114,21 +112,12 @@
 	struct mutex		mce_mutex;	/* mutex for mce register */
 	struct mutex		open_mutex;	/* mutex for ALSA open/close */
 
-	union {
-#ifdef SBUS_SUPPORT
-		struct sbus_dev		*sdev;
-#endif
-#ifdef EBUS_SUPPORT
-		struct pci_dev		*pdev;
-#endif
-	} dev_u;
+	struct of_device	*op;
 	unsigned int		irq[2];
 	unsigned int		regs_size;
 	struct snd_cs4231	*next;
 };
 
-static struct snd_cs4231 *cs4231_list;
-
 /* Eventually we can use sound/isa/cs423x/cs4231_lib.c directly, but for
  * now....  -DaveM
  */
@@ -267,27 +256,19 @@
 
 static u8 __cs4231_readb(struct snd_cs4231 *cp, void __iomem *reg_addr)
 {
-#ifdef EBUS_SUPPORT
 	if (cp->flags & CS4231_FLAG_EBUS)
 		return readb(reg_addr);
 	else
-#endif
-#ifdef SBUS_SUPPORT
 		return sbus_readb(reg_addr);
-#endif
 }
 
 static void __cs4231_writeb(struct snd_cs4231 *cp, u8 val,
 			    void __iomem *reg_addr)
 {
-#ifdef EBUS_SUPPORT
 	if (cp->flags & CS4231_FLAG_EBUS)
 		return writeb(val, reg_addr);
 	else
-#endif
-#ifdef SBUS_SUPPORT
 		return sbus_writeb(val, reg_addr);
-#endif
 }
 
 /*
@@ -1258,7 +1239,9 @@
 	pcm->info_flags = SNDRV_PCM_INFO_JOINT_DUPLEX;
 	strcpy(pcm->name, "CS4231");
 
-	chip->p_dma.preallocate(chip, pcm);
+	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
+					      &chip->op->dev,
+					      64 * 1024, 128 * 1024);
 
 	chip->pcm = pcm;
 
@@ -1560,7 +1543,8 @@
 	struct snd_cs4231 *chip = card->private_data;
 	int err, idx;
 
-	snd_assert(chip != NULL && chip->pcm != NULL, return -EINVAL);
+	if (snd_BUG_ON(!chip || !chip->pcm))
+		return -EINVAL;
 
 	strcpy(card->mixername, chip->pcm->name);
 
@@ -1626,8 +1610,7 @@
 	if (err < 0)
 		goto out_err;
 
-	chip->next = cs4231_list;
-	cs4231_list = chip;
+	dev_set_drvdata(&chip->op->dev, chip);
 
 	dev++;
 	return 0;
@@ -1782,24 +1765,19 @@
 	return sbus_readl(base->regs + base->dir + APCVA);
 }
 
-static void sbus_dma_preallocate(struct snd_cs4231 *chip, struct snd_pcm *pcm)
-{
-	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_SBUS,
-					snd_dma_sbus_data(chip->dev_u.sdev),
-					64 * 1024, 128 * 1024);
-}
-
 /*
  * Init and exit routines
  */
 
 static int snd_cs4231_sbus_free(struct snd_cs4231 *chip)
 {
+	struct of_device *op = chip->op;
+
 	if (chip->irq[0])
 		free_irq(chip->irq[0], chip);
 
 	if (chip->port)
-		sbus_iounmap(chip->port, chip->regs_size);
+		of_iounmap(&op->resource[0], chip->port, chip->regs_size);
 
 	return 0;
 }
@@ -1816,7 +1794,7 @@
 };
 
 static int __init snd_cs4231_sbus_create(struct snd_card *card,
-					 struct sbus_dev *sdev,
+					 struct of_device *op,
 					 int dev)
 {
 	struct snd_cs4231 *chip = card->private_data;
@@ -1827,13 +1805,13 @@
 	spin_lock_init(&chip->p_dma.sbus_info.lock);
 	mutex_init(&chip->mce_mutex);
 	mutex_init(&chip->open_mutex);
-	chip->dev_u.sdev = sdev;
-	chip->regs_size = sdev->reg_addrs[0].reg_size;
+	chip->op = op;
+	chip->regs_size = resource_size(&op->resource[0]);
 	memcpy(&chip->image, &snd_cs4231_original_image,
 	       sizeof(snd_cs4231_original_image));
 
-	chip->port = sbus_ioremap(&sdev->resource[0], 0,
-				  chip->regs_size, "cs4231");
+	chip->port = of_ioremap(&op->resource[0], 0,
+				chip->regs_size, "cs4231");
 	if (!chip->port) {
 		snd_printdd("cs4231-%d: Unable to map chip registers.\n", dev);
 		return -EIO;
@@ -1848,22 +1826,20 @@
 	chip->p_dma.enable = sbus_dma_enable;
 	chip->p_dma.request = sbus_dma_request;
 	chip->p_dma.address = sbus_dma_addr;
-	chip->p_dma.preallocate = sbus_dma_preallocate;
 
 	chip->c_dma.prepare = sbus_dma_prepare;
 	chip->c_dma.enable = sbus_dma_enable;
 	chip->c_dma.request = sbus_dma_request;
 	chip->c_dma.address = sbus_dma_addr;
-	chip->c_dma.preallocate = sbus_dma_preallocate;
 
-	if (request_irq(sdev->irqs[0], snd_cs4231_sbus_interrupt,
+	if (request_irq(op->irqs[0], snd_cs4231_sbus_interrupt,
 			IRQF_SHARED, "cs4231", chip)) {
 		snd_printdd("cs4231-%d: Unable to grab SBUS IRQ %d\n",
-			    dev, sdev->irqs[0]);
+			    dev, op->irqs[0]);
 		snd_cs4231_sbus_free(chip);
 		return -EBUSY;
 	}
-	chip->irq[0] = sdev->irqs[0];
+	chip->irq[0] = op->irqs[0];
 
 	if (snd_cs4231_probe(chip) < 0) {
 		snd_cs4231_sbus_free(chip);
@@ -1880,9 +1856,9 @@
 	return 0;
 }
 
-static int __init cs4231_sbus_attach(struct sbus_dev *sdev)
+static int __devinit cs4231_sbus_probe(struct of_device *op, const struct of_device_id *match)
 {
-	struct resource *rp = &sdev->resource[0];
+	struct resource *rp = &op->resource[0];
 	struct snd_card *card;
 	int err;
 
@@ -1894,9 +1870,9 @@
 		card->shortname,
 		rp->flags & 0xffL,
 		(unsigned long long)rp->start,
-		sdev->irqs[0]);
+		op->irqs[0]);
 
-	err = snd_cs4231_sbus_create(card, sdev, dev);
+	err = snd_cs4231_sbus_create(card, op, dev);
 	if (err < 0) {
 		snd_card_free(card);
 		return err;
@@ -1949,30 +1925,25 @@
 	return ebus_dma_addr(&dma_cont->ebus_info);
 }
 
-static void _ebus_dma_preallocate(struct snd_cs4231 *chip, struct snd_pcm *pcm)
-{
-	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
-				      snd_dma_pci_data(chip->dev_u.pdev),
-				      64*1024, 128*1024);
-}
-
 /*
  * Init and exit routines
  */
 
 static int snd_cs4231_ebus_free(struct snd_cs4231 *chip)
 {
+	struct of_device *op = chip->op;
+
 	if (chip->c_dma.ebus_info.regs) {
 		ebus_dma_unregister(&chip->c_dma.ebus_info);
-		iounmap(chip->c_dma.ebus_info.regs);
+		of_iounmap(&op->resource[2], chip->c_dma.ebus_info.regs, 0x10);
 	}
 	if (chip->p_dma.ebus_info.regs) {
 		ebus_dma_unregister(&chip->p_dma.ebus_info);
-		iounmap(chip->p_dma.ebus_info.regs);
+		of_iounmap(&op->resource[1], chip->p_dma.ebus_info.regs, 0x10);
 	}
 
 	if (chip->port)
-		iounmap(chip->port);
+		of_iounmap(&op->resource[0], chip->port, 0x10);
 
 	return 0;
 }
@@ -1989,7 +1960,7 @@
 };
 
 static int __init snd_cs4231_ebus_create(struct snd_card *card,
-					 struct linux_ebus_device *edev,
+					 struct of_device *op,
 					 int dev)
 {
 	struct snd_cs4231 *chip = card->private_data;
@@ -2001,35 +1972,35 @@
 	mutex_init(&chip->mce_mutex);
 	mutex_init(&chip->open_mutex);
 	chip->flags |= CS4231_FLAG_EBUS;
-	chip->dev_u.pdev = edev->bus->self;
+	chip->op = op;
 	memcpy(&chip->image, &snd_cs4231_original_image,
 	       sizeof(snd_cs4231_original_image));
 	strcpy(chip->c_dma.ebus_info.name, "cs4231(capture)");
 	chip->c_dma.ebus_info.flags = EBUS_DMA_FLAG_USE_EBDMA_HANDLER;
 	chip->c_dma.ebus_info.callback = snd_cs4231_ebus_capture_callback;
 	chip->c_dma.ebus_info.client_cookie = chip;
-	chip->c_dma.ebus_info.irq = edev->irqs[0];
+	chip->c_dma.ebus_info.irq = op->irqs[0];
 	strcpy(chip->p_dma.ebus_info.name, "cs4231(play)");
 	chip->p_dma.ebus_info.flags = EBUS_DMA_FLAG_USE_EBDMA_HANDLER;
 	chip->p_dma.ebus_info.callback = snd_cs4231_ebus_play_callback;
 	chip->p_dma.ebus_info.client_cookie = chip;
-	chip->p_dma.ebus_info.irq = edev->irqs[1];
+	chip->p_dma.ebus_info.irq = op->irqs[1];
 
 	chip->p_dma.prepare = _ebus_dma_prepare;
 	chip->p_dma.enable = _ebus_dma_enable;
 	chip->p_dma.request = _ebus_dma_request;
 	chip->p_dma.address = _ebus_dma_addr;
-	chip->p_dma.preallocate = _ebus_dma_preallocate;
 
 	chip->c_dma.prepare = _ebus_dma_prepare;
 	chip->c_dma.enable = _ebus_dma_enable;
 	chip->c_dma.request = _ebus_dma_request;
 	chip->c_dma.address = _ebus_dma_addr;
-	chip->c_dma.preallocate = _ebus_dma_preallocate;
 
-	chip->port = ioremap(edev->resource[0].start, 0x10);
-	chip->p_dma.ebus_info.regs = ioremap(edev->resource[1].start, 0x10);
-	chip->c_dma.ebus_info.regs = ioremap(edev->resource[2].start, 0x10);
+	chip->port = of_ioremap(&op->resource[0], 0, 0x10, "cs4231");
+	chip->p_dma.ebus_info.regs =
+		of_ioremap(&op->resource[1], 0, 0x10, "cs4231_pdma");
+	chip->c_dma.ebus_info.regs =
+		of_ioremap(&op->resource[2], 0, 0x10, "cs4231_cdma");
 	if (!chip->port || !chip->p_dma.ebus_info.regs ||
 	    !chip->c_dma.ebus_info.regs) {
 		snd_cs4231_ebus_free(chip);
@@ -2077,7 +2048,7 @@
 	return 0;
 }
 
-static int __init cs4231_ebus_attach(struct linux_ebus_device *edev)
+static int __devinit cs4231_ebus_probe(struct of_device *op, const struct of_device_id *match)
 {
 	struct snd_card *card;
 	int err;
@@ -2088,10 +2059,10 @@
 
 	sprintf(card->longname, "%s at 0x%lx, irq %d",
 		card->shortname,
-		edev->resource[0].start,
-		edev->irqs[0]);
+		op->resource[0].start,
+		op->irqs[0]);
 
-	err = snd_cs4231_ebus_create(card, edev, dev);
+	err = snd_cs4231_ebus_create(card, op, dev);
 	if (err < 0) {
 		snd_card_free(card);
 		return err;
@@ -2101,68 +2072,57 @@
 }
 #endif
 
+static int __devinit cs4231_probe(struct of_device *op, const struct of_device_id *match)
+{
+#ifdef EBUS_SUPPORT
+	if (!strcmp(op->node->parent->name, "ebus"))
+		return cs4231_ebus_probe(op, match);
+#endif
+#ifdef SBUS_SUPPORT
+	if (!strcmp(op->node->parent->name, "sbus") ||
+	    !strcmp(op->node->parent->name, "sbi"))
+		return cs4231_sbus_probe(op, match);
+#endif
+	return -ENODEV;
+}
+
+static int __devexit cs4231_remove(struct of_device *op)
+{
+	struct snd_cs4231 *chip = dev_get_drvdata(&op->dev);
+
+	snd_card_free(chip->card);
+
+	return 0;
+}
+
+static const struct of_device_id cs4231_match[] = {
+	{
+		.name = "SUNW,CS4231",
+	},
+	{
+		.name = "audio",
+		.compatible = "SUNW,CS4231",
+	},
+	{},
+};
+
+MODULE_DEVICE_TABLE(of, cs4231_match);
+
+static struct of_platform_driver cs4231_driver = {
+	.name		= "audio",
+	.match_table	= cs4231_match,
+	.probe		= cs4231_probe,
+	.remove		= __devexit_p(cs4231_remove),
+};
+
 static int __init cs4231_init(void)
 {
-#ifdef SBUS_SUPPORT
-	struct sbus_bus *sbus;
-	struct sbus_dev *sdev;
-#endif
-#ifdef EBUS_SUPPORT
-	struct linux_ebus *ebus;
-	struct linux_ebus_device *edev;
-#endif
-	int found;
-
-	found = 0;
-
-#ifdef SBUS_SUPPORT
-	for_all_sbusdev(sdev, sbus) {
-		if (!strcmp(sdev->prom_name, "SUNW,CS4231")) {
-			if (cs4231_sbus_attach(sdev) == 0)
-				found++;
-		}
-	}
-#endif
-#ifdef EBUS_SUPPORT
-	for_each_ebus(ebus) {
-		for_each_ebusdev(edev, ebus) {
-			int match = 0;
-
-			if (!strcmp(edev->prom_node->name, "SUNW,CS4231")) {
-				match = 1;
-			} else if (!strcmp(edev->prom_node->name, "audio")) {
-				const char *compat;
-
-				compat = of_get_property(edev->prom_node,
-							 "compatible", NULL);
-				if (compat && !strcmp(compat, "SUNW,CS4231"))
-					match = 1;
-			}
-
-			if (match &&
-			    cs4231_ebus_attach(edev) == 0)
-				found++;
-		}
-	}
-#endif
-
-
-	return (found > 0) ? 0 : -EIO;
+	return of_register_driver(&cs4231_driver, &of_bus_type);
 }
 
 static void __exit cs4231_exit(void)
 {
-	struct snd_cs4231 *p = cs4231_list;
-
-	while (p != NULL) {
-		struct snd_cs4231 *next = p->next;
-
-		snd_card_free(p->card);
-
-		p = next;
-	}
-
-	cs4231_list = NULL;
+	of_unregister_driver(&cs4231_driver);
 }
 
 module_init(cs4231_init);
diff --git a/sound/sparc/dbri.c b/sound/sparc/dbri.c
index ee2e1b4..c257ad8 100644
--- a/sound/sparc/dbri.c
+++ b/sound/sparc/dbri.c
@@ -57,6 +57,7 @@
 #include <linux/delay.h>
 #include <linux/irq.h>
 #include <linux/io.h>
+#include <linux/dma-mapping.h>
 
 #include <sound/core.h>
 #include <sound/pcm.h>
@@ -66,7 +67,7 @@
 #include <sound/initval.h>
 
 #include <linux/of.h>
-#include <asm/sbus.h>
+#include <linux/of_device.h>
 #include <asm/atomic.h>
 
 MODULE_AUTHOR("Rudolf Koenig, Brent Baccala and Martin Habets");
@@ -297,7 +298,7 @@
 /* This structure holds the information for both chips (DBRI & CS4215) */
 struct snd_dbri {
 	int regs_size, irq;	/* Needed for unload */
-	struct sbus_dev *sdev;	/* SBUS device info */
+	struct of_device *op;	/* OF device info */
 	spinlock_t lock;
 
 	struct dbri_dma *dma;	/* Pointer to our DMA block */
@@ -2093,14 +2094,15 @@
 	 */
 	if (info->dvma_buffer == 0) {
 		if (DBRI_STREAMNO(substream) == DBRI_PLAY)
-			direction = SBUS_DMA_TODEVICE;
+			direction = DMA_TO_DEVICE;
 		else
-			direction = SBUS_DMA_FROMDEVICE;
+			direction = DMA_FROM_DEVICE;
 
-		info->dvma_buffer = sbus_map_single(dbri->sdev,
-					runtime->dma_area,
-					params_buffer_bytes(hw_params),
-					direction);
+		info->dvma_buffer =
+			dma_map_single(&dbri->op->dev,
+				       runtime->dma_area,
+				       params_buffer_bytes(hw_params),
+				       direction);
 	}
 
 	direction = params_buffer_bytes(hw_params);
@@ -2121,12 +2123,12 @@
 	 */
 	if (info->dvma_buffer) {
 		if (DBRI_STREAMNO(substream) == DBRI_PLAY)
-			direction = SBUS_DMA_TODEVICE;
+			direction = DMA_TO_DEVICE;
 		else
-			direction = SBUS_DMA_FROMDEVICE;
+			direction = DMA_FROM_DEVICE;
 
-		sbus_unmap_single(dbri->sdev, info->dvma_buffer,
-				  substream->runtime->buffer_size, direction);
+		dma_unmap_single(&dbri->op->dev, info->dvma_buffer,
+				 substream->runtime->buffer_size, direction);
 		info->dvma_buffer = 0;
 	}
 	if (info->pipe != -1) {
@@ -2223,7 +2225,6 @@
 			       /* playback count */ 1,
 			       /* capture count */  1, &pcm)) < 0)
 		return err;
-	snd_assert(pcm != NULL, return -EINVAL);
 
 	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_dbri_ops);
 	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_dbri_ops);
@@ -2263,9 +2264,10 @@
 {
 	struct snd_dbri *dbri = snd_kcontrol_chip(kcontrol);
 	struct dbri_streaminfo *info;
-	snd_assert(dbri != NULL, return -EINVAL);
+
+	if (snd_BUG_ON(!dbri))
+		return -EINVAL;
 	info = &dbri->stream_info[kcontrol->private_value];
-	snd_assert(info != NULL, return -EINVAL);
 
 	ucontrol->value.integer.value[0] = info->left_gain;
 	ucontrol->value.integer.value[1] = info->right_gain;
@@ -2331,7 +2333,9 @@
 	int shift = (kcontrol->private_value >> 8) & 0xff;
 	int mask = (kcontrol->private_value >> 16) & 0xff;
 	int invert = (kcontrol->private_value >> 24) & 1;
-	snd_assert(dbri != NULL, return -EINVAL);
+
+	if (snd_BUG_ON(!dbri))
+		return -EINVAL;
 
 	if (elem < 4)
 		ucontrol->value.integer.value[0] =
@@ -2356,7 +2360,9 @@
 	int invert = (kcontrol->private_value >> 24) & 1;
 	int changed = 0;
 	unsigned short val;
-	snd_assert(dbri != NULL, return -EINVAL);
+
+	if (snd_BUG_ON(!dbri))
+		return -EINVAL;
 
 	val = (ucontrol->value.integer.value[0] & mask);
 	if (invert == 1)
@@ -2432,7 +2438,8 @@
 	int idx, err;
 	struct snd_dbri *dbri;
 
-	snd_assert(card != NULL && card->private_data != NULL, return -EINVAL);
+	if (snd_BUG_ON(!card || !card->private_data))
+		return -EINVAL;
 	dbri = card->private_data;
 
 	strcpy(card->mixername, card->shortname);
@@ -2514,31 +2521,32 @@
 static void snd_dbri_free(struct snd_dbri *dbri);
 
 static int __devinit snd_dbri_create(struct snd_card *card,
-				  struct sbus_dev *sdev,
-				  int irq, int dev)
+				     struct of_device *op,
+				     int irq, int dev)
 {
 	struct snd_dbri *dbri = card->private_data;
 	int err;
 
 	spin_lock_init(&dbri->lock);
-	dbri->sdev = sdev;
+	dbri->op = op;
 	dbri->irq = irq;
 
-	dbri->dma = sbus_alloc_consistent(sdev, sizeof(struct dbri_dma),
-					  &dbri->dma_dvma);
+	dbri->dma = dma_alloc_coherent(&op->dev,
+				       sizeof(struct dbri_dma),
+				       &dbri->dma_dvma, GFP_ATOMIC);
 	memset((void *)dbri->dma, 0, sizeof(struct dbri_dma));
 
 	dprintk(D_GEN, "DMA Cmd Block 0x%p (0x%08x)\n",
 		dbri->dma, dbri->dma_dvma);
 
 	/* Map the registers into memory. */
-	dbri->regs_size = sdev->reg_addrs[0].reg_size;
-	dbri->regs = sbus_ioremap(&sdev->resource[0], 0,
-				  dbri->regs_size, "DBRI Registers");
+	dbri->regs_size = resource_size(&op->resource[0]);
+	dbri->regs = of_ioremap(&op->resource[0], 0,
+				dbri->regs_size, "DBRI Registers");
 	if (!dbri->regs) {
 		printk(KERN_ERR "DBRI: could not allocate registers\n");
-		sbus_free_consistent(sdev, sizeof(struct dbri_dma),
-				     (void *)dbri->dma, dbri->dma_dvma);
+		dma_free_coherent(&op->dev, sizeof(struct dbri_dma),
+				  (void *)dbri->dma, dbri->dma_dvma);
 		return -EIO;
 	}
 
@@ -2546,9 +2554,9 @@
 			  "DBRI audio", dbri);
 	if (err) {
 		printk(KERN_ERR "DBRI: Can't get irq %d\n", dbri->irq);
-		sbus_iounmap(dbri->regs, dbri->regs_size);
-		sbus_free_consistent(sdev, sizeof(struct dbri_dma),
-				     (void *)dbri->dma, dbri->dma_dvma);
+		of_iounmap(&op->resource[0], dbri->regs, dbri->regs_size);
+		dma_free_coherent(&op->dev, sizeof(struct dbri_dma),
+				  (void *)dbri->dma, dbri->dma_dvma);
 		return err;
 	}
 
@@ -2572,27 +2580,23 @@
 		free_irq(dbri->irq, dbri);
 
 	if (dbri->regs)
-		sbus_iounmap(dbri->regs, dbri->regs_size);
+		of_iounmap(&dbri->op->resource[0], dbri->regs, dbri->regs_size);
 
 	if (dbri->dma)
-		sbus_free_consistent(dbri->sdev, sizeof(struct dbri_dma),
-				     (void *)dbri->dma, dbri->dma_dvma);
+		dma_free_coherent(&dbri->op->dev,
+				  sizeof(struct dbri_dma),
+				  (void *)dbri->dma, dbri->dma_dvma);
 }
 
-static int __devinit dbri_probe(struct of_device *of_dev,
-				const struct of_device_id *match)
+static int __devinit dbri_probe(struct of_device *op, const struct of_device_id *match)
 {
-	struct sbus_dev *sdev = to_sbus_device(&of_dev->dev);
 	struct snd_dbri *dbri;
-	int irq;
 	struct resource *rp;
 	struct snd_card *card;
 	static int dev = 0;
+	int irq;
 	int err;
 
-	dprintk(D_GEN, "DBRI: Found %s in SBUS slot %d\n",
-		sdev->prom_name, sdev->slot);
-
 	if (dev >= SNDRV_CARDS)
 		return -ENODEV;
 	if (!enable[dev]) {
@@ -2600,7 +2604,7 @@
 		return -ENOENT;
 	}
 
-	irq = sdev->irqs[0];
+	irq = op->irqs[0];
 	if (irq <= 0) {
 		printk(KERN_ERR "DBRI-%d: No IRQ.\n", dev);
 		return -ENODEV;
@@ -2613,12 +2617,12 @@
 
 	strcpy(card->driver, "DBRI");
 	strcpy(card->shortname, "Sun DBRI");
-	rp = &sdev->resource[0];
+	rp = &op->resource[0];
 	sprintf(card->longname, "%s at 0x%02lx:0x%016Lx, irq %d",
 		card->shortname,
 		rp->flags & 0xffL, (unsigned long long)rp->start, irq);
 
-	err = snd_dbri_create(card, sdev, irq, dev);
+	err = snd_dbri_create(card, op, irq, dev);
 	if (err < 0) {
 		snd_card_free(card);
 		return err;
@@ -2635,7 +2639,7 @@
 
 	/* /proc file handling */
 	snd_dbri_proc(card);
-	dev_set_drvdata(&of_dev->dev, card);
+	dev_set_drvdata(&op->dev, card);
 
 	err = snd_card_register(card);
 	if (err < 0)
@@ -2643,7 +2647,7 @@
 
 	printk(KERN_INFO "audio%d at %p (irq %d) is DBRI(%c)+CS4215(%d)\n",
 	       dev, dbri->regs,
-	       dbri->irq, sdev->prom_name[9], dbri->mm.version);
+	       dbri->irq, op->node->name[9], dbri->mm.version);
 	dev++;
 
 	return 0;
@@ -2654,19 +2658,19 @@
 	return err;
 }
 
-static int __devexit dbri_remove(struct of_device *dev)
+static int __devexit dbri_remove(struct of_device *op)
 {
-	struct snd_card *card = dev_get_drvdata(&dev->dev);
+	struct snd_card *card = dev_get_drvdata(&op->dev);
 
 	snd_dbri_free(card->private_data);
 	snd_card_free(card);
 
-	dev_set_drvdata(&dev->dev, NULL);
+	dev_set_drvdata(&op->dev, NULL);
 
 	return 0;
 }
 
-static struct of_device_id dbri_match[] = {
+static const struct of_device_id dbri_match[] = {
 	{
 		.name = "SUNW,DBRIe",
 	},
@@ -2688,7 +2692,7 @@
 /* Probe for the dbri chip and then attach the driver. */
 static int __init dbri_init(void)
 {
-	return of_register_driver(&dbri_sbus_driver, &sbus_bus_type);
+	return of_register_driver(&dbri_sbus_driver, &of_bus_type);
 }
 
 static void __exit dbri_exit(void)
diff --git a/sound/synth/emux/emux.c b/sound/synth/emux/emux.c
index c89d2ea..f16a3fc 100644
--- a/sound/synth/emux/emux.c
+++ b/sound/synth/emux/emux.c
@@ -93,10 +93,10 @@
 	int err;
 	struct snd_sf_callback sf_cb;
 
-	snd_assert(emu->hw != NULL, return -EINVAL);
-	snd_assert(emu->max_voices > 0, return -EINVAL);
-	snd_assert(card != NULL, return -EINVAL);
-	snd_assert(name != NULL, return -EINVAL);
+	if (snd_BUG_ON(!emu->hw || emu->max_voices <= 0))
+		return -EINVAL;
+	if (snd_BUG_ON(!card || !name))
+		return -EINVAL;
 
 	emu->card = card;
 	emu->name = kstrdup(name, GFP_KERNEL);
diff --git a/sound/synth/emux/emux_nrpn.c b/sound/synth/emux/emux_nrpn.c
index c6917ba..00fc005 100644
--- a/sound/synth/emux/emux_nrpn.c
+++ b/sound/synth/emux/emux_nrpn.c
@@ -289,8 +289,8 @@
 	struct snd_emux_port *port;
 
 	port = p;
-	snd_assert(port != NULL, return);
-	snd_assert(chan != NULL, return);
+	if (snd_BUG_ON(!port || !chan))
+		return;
 
 	if (chan->control[MIDI_CTL_NONREG_PARM_NUM_MSB] == 127 &&
 	    chan->control[MIDI_CTL_NONREG_PARM_NUM_LSB] <= 26) {
@@ -379,8 +379,8 @@
 	struct snd_emux *emu;
 
 	port = p;
-	snd_assert(port != NULL, return);
-	snd_assert(chset != NULL, return);
+	if (snd_BUG_ON(!port || !chset))
+		return;
 	emu = port->emu;
 
 	switch (parsed) {
diff --git a/sound/synth/emux/emux_oss.c b/sound/synth/emux/emux_oss.c
index f60a98e..5c47b6c 100644
--- a/sound/synth/emux/emux_oss.c
+++ b/sound/synth/emux/emux_oss.c
@@ -114,7 +114,8 @@
 	char tmpname[64];
 
 	emu = closure;
-	snd_assert(arg != NULL && emu != NULL, return -ENXIO);
+	if (snd_BUG_ON(!arg || !emu))
+		return -ENXIO;
 
 	mutex_lock(&emu->register_mutex);
 
@@ -183,12 +184,15 @@
 	struct snd_emux *emu;
 	struct snd_emux_port *p;
 
-	snd_assert(arg != NULL, return -ENXIO);
+	if (snd_BUG_ON(!arg))
+		return -ENXIO;
 	p = arg->private_data;
-	snd_assert(p != NULL, return -ENXIO);
+	if (snd_BUG_ON(!p))
+		return -ENXIO;
 
 	emu = p->emu;
-	snd_assert(emu != NULL, return -ENXIO);
+	if (snd_BUG_ON(!emu))
+		return -ENXIO;
 
 	mutex_lock(&emu->register_mutex);
 	snd_emux_sounds_off_all(p);
@@ -212,12 +216,15 @@
 	struct snd_emux_port *p;
 	int rc;
 
-	snd_assert(arg != NULL, return -ENXIO);
+	if (snd_BUG_ON(!arg))
+		return -ENXIO;
 	p = arg->private_data;
-	snd_assert(p != NULL, return -ENXIO);
+	if (snd_BUG_ON(!p))
+		return -ENXIO;
 
 	emu = p->emu;
-	snd_assert(emu != NULL, return -ENXIO);
+	if (snd_BUG_ON(!emu))
+		return -ENXIO;
 
 	if (format == GUS_PATCH)
 		rc = snd_soundfont_load_guspatch(emu->sflist, buf, count,
@@ -252,12 +259,15 @@
 	struct snd_emux_port *p;
 	struct snd_emux *emu;
 
-	snd_assert(arg != NULL, return -ENXIO);
+	if (snd_BUG_ON(!arg))
+		return -ENXIO;
 	p = arg->private_data;
-	snd_assert(p != NULL, return -ENXIO);
+	if (snd_BUG_ON(!p))
+		return -ENXIO;
 
 	emu = p->emu;
-	snd_assert(emu != NULL, return -ENXIO);
+	if (snd_BUG_ON(!emu))
+		return -ENXIO;
 
 	switch (cmd) {
 	case SNDCTL_SEQ_RESETSAMPLES:
@@ -282,9 +292,11 @@
 {
 	struct snd_emux_port *p;
 
-	snd_assert(arg != NULL, return -ENXIO);
+	if (snd_BUG_ON(!arg))
+		return -ENXIO;
 	p = arg->private_data;
-	snd_assert(p != NULL, return -ENXIO);
+	if (snd_BUG_ON(!p))
+		return -ENXIO;
 	snd_emux_reset_port(p);
 	return 0;
 }
@@ -302,9 +314,11 @@
 	unsigned char cmd, *data;
 
 	p = private_data;
-	snd_assert(p != NULL, return -EINVAL);
+	if (snd_BUG_ON(!p))
+		return -EINVAL;
 	emu = p->emu;
-	snd_assert(emu != NULL, return -EINVAL);
+	if (snd_BUG_ON(!emu))
+		return -EINVAL;
 	if (ev->type != SNDRV_SEQ_EVENT_OSS)
 		return snd_emux_event_input(ev, direct, private_data, atomic, hop);
 
diff --git a/sound/synth/emux/emux_seq.c b/sound/synth/emux/emux_seq.c
index d176cc0..335aa2c 100644
--- a/sound/synth/emux/emux_seq.c
+++ b/sound/synth/emux/emux_seq.c
@@ -257,7 +257,8 @@
 	struct snd_emux_port *port;
 
 	port = private_data;
-	snd_assert(port != NULL && ev != NULL, return -EINVAL);
+	if (snd_BUG_ON(!port || !ev))
+		return -EINVAL;
 
 	snd_midi_process_event(&emux_ops, ev, &port->chset);
 
@@ -308,9 +309,11 @@
 	struct snd_emux *emu;
 
 	p = private_data;
-	snd_assert(p != NULL, return -EINVAL);
+	if (snd_BUG_ON(!p))
+		return -EINVAL;
 	emu = p->emu;
-	snd_assert(emu != NULL, return -EINVAL);
+	if (snd_BUG_ON(!emu))
+		return -EINVAL;
 
 	mutex_lock(&emu->register_mutex);
 	snd_emux_init_port(p);
@@ -329,9 +332,11 @@
 	struct snd_emux *emu;
 
 	p = private_data;
-	snd_assert(p != NULL, return -EINVAL);
+	if (snd_BUG_ON(!p))
+		return -EINVAL;
 	emu = p->emu;
-	snd_assert(emu != NULL, return -EINVAL);
+	if (snd_BUG_ON(!emu))
+		return -EINVAL;
 
 	mutex_lock(&emu->register_mutex);
 	snd_emux_sounds_off_all(p);
diff --git a/sound/synth/emux/emux_synth.c b/sound/synth/emux/emux_synth.c
index b343818..2cc6f6f 100644
--- a/sound/synth/emux/emux_synth.c
+++ b/sound/synth/emux/emux_synth.c
@@ -66,12 +66,12 @@
 	struct snd_emux_port *port;
 
 	port = p;
-	snd_assert(port != NULL && chan != NULL, return);
+	if (snd_BUG_ON(!port || !chan))
+		return;
 
 	emu = port->emu;
-	snd_assert(emu != NULL, return);
-	snd_assert(emu->ops.get_voice != NULL, return);
-	snd_assert(emu->ops.trigger != NULL, return);
+	if (snd_BUG_ON(!emu || !emu->ops.get_voice || !emu->ops.trigger))
+		return;
 
 	key = note; /* remember the original note */
 	nvoices = get_zone(emu, port, &note, vel, chan, table);
@@ -164,11 +164,12 @@
 	struct snd_emux_port *port;
 
 	port = p;
-	snd_assert(port != NULL && chan != NULL, return);
+	if (snd_BUG_ON(!port || !chan))
+		return;
 
 	emu = port->emu;
-	snd_assert(emu != NULL, return);
-	snd_assert(emu->ops.release != NULL, return);
+	if (snd_BUG_ON(!emu || !emu->ops.release))
+		return;
 
 	spin_lock_irqsave(&emu->voice_lock, flags);
 	for (ch = 0; ch < emu->max_voices; ch++) {
@@ -242,11 +243,12 @@
 	struct snd_emux_port *port;
 
 	port = p;
-	snd_assert(port != NULL && chan != NULL, return);
+	if (snd_BUG_ON(!port || !chan))
+		return;
 
 	emu = port->emu;
-	snd_assert(emu != NULL, return);
-	snd_assert(emu->ops.update != NULL, return);
+	if (snd_BUG_ON(!emu || !emu->ops.update))
+		return;
 
 	spin_lock_irqsave(&emu->voice_lock, flags);
 	for (ch = 0; ch < emu->max_voices; ch++) {
@@ -276,8 +278,8 @@
 		return;
 
 	emu = port->emu;
-	snd_assert(emu != NULL, return);
-	snd_assert(emu->ops.update != NULL, return);
+	if (snd_BUG_ON(!emu || !emu->ops.update))
+		return;
 
 	spin_lock_irqsave(&emu->voice_lock, flags);
 	for (i = 0; i < emu->max_voices; i++) {
@@ -303,8 +305,8 @@
 		return;
 
 	emu = port->emu;
-	snd_assert(emu != NULL, return);
-	snd_assert(emu->ops.update != NULL, return);
+	if (snd_BUG_ON(!emu || !emu->ops.update))
+		return;
 
 	spin_lock_irqsave(&emu->voice_lock, flags);
 	for (i = 0; i < emu->max_voices; i++) {
@@ -326,7 +328,8 @@
 	struct snd_emux_port *port;
 
 	port = p;
-	snd_assert(port != NULL && chan != NULL, return);
+	if (snd_BUG_ON(!port || !chan))
+		return;
 
 	switch (type) {
 	case MIDI_CTL_MSB_MAIN_VOLUME:
@@ -400,11 +403,12 @@
 	struct snd_emux_port *port;
 
 	port = p;
-	snd_assert(port != NULL && chan != NULL, return);
+	if (snd_BUG_ON(!port || !chan))
+		return;
 
 	emu = port->emu;
-	snd_assert(emu != NULL, return);
-	snd_assert(emu->ops.terminate != NULL, return);
+	if (snd_BUG_ON(!emu || !emu->ops.terminate))
+		return;
 
 	terminate_note1(emu, note, chan, 1);
 }
@@ -451,10 +455,11 @@
 	struct snd_emux_voice *vp;
 	unsigned long flags;
 
-	snd_assert(port != NULL, return);
+	if (snd_BUG_ON(!port))
+		return;
 	emu = port->emu;
-	snd_assert(emu != NULL, return);
-	snd_assert(emu->ops.terminate != NULL, return);
+	if (snd_BUG_ON(!emu || !emu->ops.terminate))
+		return;
 
 	spin_lock_irqsave(&emu->voice_lock, flags);
 	for (i = 0; i < emu->max_voices; i++) {
diff --git a/sound/synth/util_mem.c b/sound/synth/util_mem.c
index deabe5f..c85522e 100644
--- a/sound/synth/util_mem.c
+++ b/sound/synth/util_mem.c
@@ -55,7 +55,8 @@
 {
 	struct list_head *p;
 
-	snd_assert(hdr != NULL, return);
+	if (!hdr)
+		return;
 	/* release all blocks */
 	while ((p = hdr->block.next) != &hdr->block) {
 		list_del(p);
@@ -74,8 +75,8 @@
 	unsigned int units, prev_offset;
 	struct list_head *p;
 
-	snd_assert(hdr != NULL, return NULL);
-	snd_assert(size > 0, return NULL);
+	if (snd_BUG_ON(!hdr || size <= 0))
+		return NULL;
 
 	/* word alignment */
 	units = size;
@@ -161,7 +162,8 @@
  */
 int snd_util_mem_free(struct snd_util_memhdr *hdr, struct snd_util_memblk *blk)
 {
-	snd_assert(hdr && blk, return -EINVAL);
+	if (snd_BUG_ON(!hdr || !blk))
+		return -EINVAL;
 
 	mutex_lock(&hdr->block_mutex);
 	__snd_util_mem_free(hdr, blk);
diff --git a/sound/usb/Kconfig b/sound/usb/Kconfig
index ffcdc8f..4f0eac9 100644
--- a/sound/usb/Kconfig
+++ b/sound/usb/Kconfig
@@ -67,5 +67,17 @@
 	   * Native Instruments Kore Controller 2
 	   * Native Instruments Audio Kontrol 1
 
+config SND_USB_US122L
+	tristate "Tascam US-122L USB driver"
+	depends on X86 && EXPERIMENTAL
+	select SND_HWDEP
+	select SND_RAWMIDI
+	help
+	  Say Y here to include support for Tascam US-122L USB Audio/MIDI
+	  interfaces.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called snd-usb-us122l.
+
 endif	# SND_USB
 
diff --git a/sound/usb/Makefile b/sound/usb/Makefile
index aa252ef..abb288b 100644
--- a/sound/usb/Makefile
+++ b/sound/usb/Makefile
@@ -8,5 +8,6 @@
 # Toplevel Module Dependency
 obj-$(CONFIG_SND_USB_AUDIO) += snd-usb-audio.o snd-usb-lib.o
 obj-$(CONFIG_SND_USB_USX2Y) += snd-usb-lib.o
+obj-$(CONFIG_SND_USB_US122L) += snd-usb-lib.o
 
 obj-$(CONFIG_SND) += usx2y/ caiaq/
diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c
index b8cfb7c..bbd70d5 100644
--- a/sound/usb/usbaudio.c
+++ b/sound/usb/usbaudio.c
@@ -71,6 +71,7 @@
 static int nrpacks = 8;		/* max. number of packets per urb */
 static int async_unlink = 1;
 static int device_setup[SNDRV_CARDS]; /* device parameter for this card*/
+static int ignore_ctl_error;
 
 module_param_array(index, int, NULL, 0444);
 MODULE_PARM_DESC(index, "Index value for the USB audio adapter.");
@@ -88,7 +89,9 @@
 MODULE_PARM_DESC(async_unlink, "Use async unlink mode.");
 module_param_array(device_setup, int, NULL, 0444);
 MODULE_PARM_DESC(device_setup, "Specific device setup (if needed).");
-
+module_param(ignore_ctl_error, bool, 0444);
+MODULE_PARM_DESC(ignore_ctl_error,
+		 "Ignore errors from USB controller for mixer interfaces.");
 
 /*
  * debug the h/w constraints
@@ -481,7 +484,7 @@
 }
 
 /*
- * process after E-Mu 0202/0404 high speed playback sync complete
+ * process after E-Mu 0202/0404/Tracker Pre high speed playback sync complete
  *
  * These devices return the number of samples per packet instead of the number
  * of samples per microframe.
@@ -841,7 +844,8 @@
 		return -EBADFD;
 
 	for (i = 0; i < subs->nurbs; i++) {
-		snd_assert(subs->dataurb[i].urb, return -EINVAL);
+		if (snd_BUG_ON(!subs->dataurb[i].urb))
+			return -EINVAL;
 		if (subs->ops.prepare(subs, runtime, subs->dataurb[i].urb) < 0) {
 			snd_printk(KERN_ERR "cannot prepare datapipe for urb %d\n", i);
 			goto __error;
@@ -849,7 +853,8 @@
 	}
 	if (subs->syncpipe) {
 		for (i = 0; i < SYNC_URBS; i++) {
-			snd_assert(subs->syncurb[i].urb, return -EINVAL);
+			if (snd_BUG_ON(!subs->syncurb[i].urb))
+				return -EINVAL;
 			if (subs->ops.prepare_sync(subs, runtime, subs->syncurb[i].urb) < 0) {
 				snd_printk(KERN_ERR "cannot prepare syncpipe for urb %d\n", i);
 				goto __error;
@@ -1321,10 +1326,12 @@
 	int err;
 
 	iface = usb_ifnum_to_if(dev, fmt->iface);
-	snd_assert(iface, return -EINVAL);
+	if (WARN_ON(!iface))
+		return -EINVAL;
 	alts = &iface->altsetting[fmt->altset_idx];
 	altsd = get_iface_desc(alts);
-	snd_assert(altsd->bAlternateSetting == fmt->altsetting, return -EINVAL);
+	if (WARN_ON(altsd->bAlternateSetting != fmt->altsetting))
+		return -EINVAL;
 
 	if (fmt == subs->cur_audiofmt)
 		return 0;
@@ -2257,6 +2264,7 @@
 		switch (as->chip->usb_id) {
 		case USB_ID(0x041e, 0x3f02): /* E-Mu 0202 USB */
 		case USB_ID(0x041e, 0x3f04): /* E-Mu 0404 USB */
+		case USB_ID(0x041e, 0x3f0a): /* E-Mu Tracker Pre */
 			subs->ops.retire_sync = retire_playback_sync_urb_hs_emu;
 			break;
 		}
@@ -2989,12 +2997,12 @@
 }
 
 /*
- * Create a stream for an Edirol UA-700/UA-25 interface.  The only way
- * to detect the sample rate is by looking at wMaxPacketSize.
+ * Create a stream for an Edirol UA-700/UA-25/UA-4FX interface.  
+ * The only way to detect the sample rate is by looking at wMaxPacketSize.
  */
-static int create_ua700_ua25_quirk(struct snd_usb_audio *chip,
-				   struct usb_interface *iface,
-				   const struct snd_usb_audio_quirk *quirk)
+static int create_uaxx_quirk(struct snd_usb_audio *chip,
+			      struct usb_interface *iface,
+			      const struct snd_usb_audio_quirk *quirk)
 {
 	static const struct audioformat ua_format = {
 		.format = SNDRV_PCM_FORMAT_S24_3LE,
@@ -3009,8 +3017,8 @@
 	struct audioformat *fp;
 	int stream, err;
 
-	/* both PCM and MIDI interfaces have 2 altsettings */
-	if (iface->num_altsetting != 2)
+	/* both PCM and MIDI interfaces have 2 or more altsettings */
+	if (iface->num_altsetting < 2)
 		return -ENXIO;
 	alts = &iface->altsetting[1];
 	altsd = get_iface_desc(alts);
@@ -3024,20 +3032,20 @@
 			.type = QUIRK_MIDI_FIXED_ENDPOINT,
 			.data = &ua700_ep
 		};
-		static const struct snd_usb_midi_endpoint_info ua25_ep = {
+		static const struct snd_usb_midi_endpoint_info uaxx_ep = {
 			.out_cables = 0x0001,
 			.in_cables  = 0x0001
 		};
-		static const struct snd_usb_audio_quirk ua25_quirk = {
+		static const struct snd_usb_audio_quirk uaxx_quirk = {
 			.type = QUIRK_MIDI_FIXED_ENDPOINT,
-			.data = &ua25_ep
+			.data = &uaxx_ep
 		};
 		if (chip->usb_id == USB_ID(0x0582, 0x002b))
 			return snd_usb_create_midi_interface(chip, iface,
 							     &ua700_quirk);
 		else
 			return snd_usb_create_midi_interface(chip, iface,
-							     &ua25_quirk);
+							     &uaxx_quirk);
 	}
 
 	if (altsd->bNumEndpoints != 1)
@@ -3369,9 +3377,9 @@
 		[QUIRK_MIDI_CME] = snd_usb_create_midi_interface,
 		[QUIRK_AUDIO_STANDARD_INTERFACE] = create_standard_audio_quirk,
 		[QUIRK_AUDIO_FIXED_ENDPOINT] = create_fixed_stream_quirk,
-		[QUIRK_AUDIO_EDIROL_UA700_UA25] = create_ua700_ua25_quirk,
 		[QUIRK_AUDIO_EDIROL_UA1000] = create_ua1000_quirk,
 		[QUIRK_AUDIO_EDIROL_UA101] = create_ua101_quirk,
+		[QUIRK_AUDIO_EDIROL_UAXX] = create_uaxx_quirk
 	};
 
 	if (quirk->type < QUIRK_TYPE_COUNT) {
@@ -3629,7 +3637,7 @@
 	if (err > 0) {
 		/* create normal USB audio interfaces */
 		if (snd_usb_create_streams(chip, ifnum) < 0 ||
-		    snd_usb_create_mixer(chip, ifnum) < 0) {
+		    snd_usb_create_mixer(chip, ifnum, ignore_ctl_error) < 0) {
 			goto __error;
 		}
 	}
diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h
index 7cf18c3..36e4f7a2 100644
--- a/sound/usb/usbaudio.h
+++ b/sound/usb/usbaudio.h
@@ -156,11 +156,12 @@
 	QUIRK_MIDI_RAW,
 	QUIRK_MIDI_EMAGIC,
 	QUIRK_MIDI_CME,
+	QUIRK_MIDI_US122L,
 	QUIRK_AUDIO_STANDARD_INTERFACE,
 	QUIRK_AUDIO_FIXED_ENDPOINT,
-	QUIRK_AUDIO_EDIROL_UA700_UA25,
 	QUIRK_AUDIO_EDIROL_UA1000,
 	QUIRK_AUDIO_EDIROL_UA101,
+	QUIRK_AUDIO_EDIROL_UAXX,
 
 	QUIRK_TYPE_COUNT
 };
@@ -222,7 +223,8 @@
 		    __u8 request, __u8 requesttype, __u16 value, __u16 index,
 		    void *data, __u16 size, int timeout);
 
-int snd_usb_create_mixer(struct snd_usb_audio *chip, int ctrlif);
+int snd_usb_create_mixer(struct snd_usb_audio *chip, int ctrlif,
+			 int ignore_error);
 void snd_usb_mixer_disconnect(struct list_head *p);
 
 int snd_usb_create_midi_interface(struct snd_usb_audio *chip, struct usb_interface *iface,
diff --git a/sound/usb/usbmidi.c b/sound/usb/usbmidi.c
index 6676a177..5962e4b 100644
--- a/sound/usb/usbmidi.c
+++ b/sound/usb/usbmidi.c
@@ -669,6 +669,42 @@
 	.output = snd_usbmidi_raw_output,
 };
 
+static void snd_usbmidi_us122l_input(struct snd_usb_midi_in_endpoint *ep,
+				     uint8_t *buffer, int buffer_length)
+{
+	if (buffer_length != 9)
+		return;
+	buffer_length = 8;
+	while (buffer_length && buffer[buffer_length - 1] == 0xFD)
+		buffer_length--;
+	if (buffer_length)
+		snd_usbmidi_input_data(ep, 0, buffer, buffer_length);
+}
+
+static void snd_usbmidi_us122l_output(struct snd_usb_midi_out_endpoint *ep)
+{
+	int count;
+
+	if (!ep->ports[0].active)
+		return;
+	count = ep->urb->dev->speed == USB_SPEED_HIGH ? 1 : 2;
+	count = snd_rawmidi_transmit(ep->ports[0].substream,
+				     ep->urb->transfer_buffer,
+				     count);
+	if (count < 1) {
+		ep->ports[0].active = 0;
+		return;
+	}
+
+	memset(ep->urb->transfer_buffer + count, 0xFD, 9 - count);
+	ep->urb->transfer_buffer_length = count;
+}
+
+static struct usb_protocol_ops snd_usbmidi_122l_ops = {
+	.input = snd_usbmidi_us122l_input,
+	.output = snd_usbmidi_us122l_output,
+};
+
 /*
  * Emagic USB MIDI protocol: raw MIDI with "F5 xx" port switching.
  */
@@ -1076,6 +1112,15 @@
 		}
 		if (ep->in)
 			usb_kill_urb(ep->in->urb);
+		/* free endpoints here; later call can result in Oops */
+		if (ep->out) {
+			snd_usbmidi_out_endpoint_delete(ep->out);
+			ep->out = NULL;
+		}
+		if (ep->in) {
+			snd_usbmidi_in_endpoint_delete(ep->in);
+			ep->in = NULL;
+		}
 	}
 	del_timer_sync(&umidi->error_timer);
 }
@@ -1714,6 +1759,9 @@
 			umidi->usb_protocol_ops =
 				&snd_usbmidi_maudio_broken_running_status_ops;
 		break;
+	case QUIRK_MIDI_US122L:
+		umidi->usb_protocol_ops = &snd_usbmidi_122l_ops;
+		/* fall through */
 	case QUIRK_MIDI_FIXED_ENDPOINT:
 		memcpy(&endpoints[0], quirk->data,
 		       sizeof(struct snd_usb_midi_endpoint_info));
diff --git a/sound/usb/usbmixer.c b/sound/usb/usbmixer.c
index 89c63d0..a492461 100644
--- a/sound/usb/usbmixer.c
+++ b/sound/usb/usbmixer.c
@@ -59,12 +59,13 @@
 	u8  offset;
 	u8  length;
 	u8  packet_length;
+	u8  min_packet_length; /* minimum accepted length of the URB result */
 	u8  mute_mixer_id;
 	u32 mute_code;
 } rc_configs[] = {
-	{ USB_ID(0x041e, 0x3000), 0, 1, 2,  18, 0x0013 }, /* Extigy       */
-	{ USB_ID(0x041e, 0x3020), 2, 1, 6,  18, 0x0013 }, /* Audigy 2 NX  */
-	{ USB_ID(0x041e, 0x3040), 2, 2, 6,  2,  0x6e91 }, /* Live! 24-bit */
+	{ USB_ID(0x041e, 0x3000), 0, 1, 2, 1,  18, 0x0013 }, /* Extigy       */
+	{ USB_ID(0x041e, 0x3020), 2, 1, 6, 6,  18, 0x0013 }, /* Audigy 2 NX  */
+	{ USB_ID(0x041e, 0x3040), 2, 2, 6, 6,  2,  0x6e91 }, /* Live! 24-bit */
 };
 
 struct usb_mixer_interface {
@@ -1388,7 +1389,8 @@
 	struct usb_mixer_elem_info *cval = kcontrol->private_data;
 	char **itemlist = (char **)kcontrol->private_value;
 
-	snd_assert(itemlist, return -EINVAL);
+	if (snd_BUG_ON(!itemlist))
+		return -EINVAL;
 	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
 	uinfo->count = 1;
 	uinfo->value.enumerated.items = cval->max;
@@ -1781,7 +1783,7 @@
 	const struct rc_config *rc = mixer->rc_cfg;
 	u32 code;
 
-	if (urb->status < 0 || urb->actual_length < rc->packet_length)
+	if (urb->status < 0 || urb->actual_length < rc->min_packet_length)
 		return;
 
 	code = mixer->rc_buffer[rc->offset];
@@ -2012,7 +2014,8 @@
 	}
 }
 
-int snd_usb_create_mixer(struct snd_usb_audio *chip, int ctrlif)
+int snd_usb_create_mixer(struct snd_usb_audio *chip, int ctrlif,
+			 int ignore_error)
 {
 	static struct snd_device_ops dev_ops = {
 		.dev_free = snd_usb_mixer_dev_free
@@ -2027,9 +2030,7 @@
 		return -ENOMEM;
 	mixer->chip = chip;
 	mixer->ctrlif = ctrlif;
-#ifdef IGNORE_CTL_ERROR
-	mixer->ignore_ctl_error = 1;
-#endif
+	mixer->ignore_ctl_error = ignore_error;
 	mixer->id_elems = kcalloc(256, sizeof(*mixer->id_elems), GFP_KERNEL);
 	if (!mixer->id_elems) {
 		kfree(mixer);
diff --git a/sound/usb/usbquirks.h b/sound/usb/usbquirks.h
index 9ea726c..69689e7 100644
--- a/sound/usb/usbquirks.h
+++ b/sound/usb/usbquirks.h
@@ -62,6 +62,13 @@
 	.idProduct = 0x3f04,
 	.bInterfaceClass = USB_CLASS_AUDIO,
 },
+{
+	/* E-Mu Tracker Pre */
+	.match_flags = USB_DEVICE_ID_MATCH_DEVICE,
+	.idVendor = 0x041e,
+	.idProduct = 0x3f0a,
+	.bInterfaceClass = USB_CLASS_AUDIO,
+},
 
 /*
  * Logitech QuickCam: bDeviceClass is vendor-specific, so generic interface
@@ -855,15 +862,15 @@
 		.data = (const struct snd_usb_audio_quirk[]) {
 			{
 				.ifnum = 1,
-				.type = QUIRK_AUDIO_EDIROL_UA700_UA25
+				.type = QUIRK_AUDIO_EDIROL_UAXX
 			},
 			{
 				.ifnum = 2,
-				.type = QUIRK_AUDIO_EDIROL_UA700_UA25
+				.type = QUIRK_AUDIO_EDIROL_UAXX
 			},
 			{
 				.ifnum = 3,
-				.type = QUIRK_AUDIO_EDIROL_UA700_UA25
+				.type = QUIRK_AUDIO_EDIROL_UAXX
 			},
 			{
 				.ifnum = -1
@@ -1197,15 +1204,15 @@
 		.data = (const struct snd_usb_audio_quirk[]) {
 			{
 				.ifnum = 0,
-				.type = QUIRK_AUDIO_EDIROL_UA700_UA25
+				.type = QUIRK_AUDIO_EDIROL_UAXX
 			},
 			{
 				.ifnum = 1,
-				.type = QUIRK_AUDIO_EDIROL_UA700_UA25
+				.type = QUIRK_AUDIO_EDIROL_UAXX
 			},
 			{
 				.ifnum = 2,
-				.type = QUIRK_AUDIO_EDIROL_UA700_UA25
+				.type = QUIRK_AUDIO_EDIROL_UAXX
 			},
 			{
 				.ifnum = -1
@@ -1338,6 +1345,36 @@
 		}
 	}
 },
+{
+	/*
+	 * This quirk is for the "Advanced Driver" mode. If off, the UA-4FX
+	 * is standard compliant, but has only 16-bit PCM and no MIDI.
+	 */
+	USB_DEVICE(0x0582, 0x00a3),
+	.driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
+		.vendor_name = "EDIROL",
+		.product_name = "UA-4FX",
+		.ifnum = QUIRK_ANY_INTERFACE,
+		.type = QUIRK_COMPOSITE,
+		.data = (const struct snd_usb_audio_quirk[]) {
+			{
+				.ifnum = 0,
+				.type = QUIRK_AUDIO_EDIROL_UAXX
+			},
+			{
+				.ifnum = 1,
+				.type = QUIRK_AUDIO_EDIROL_UAXX
+			},
+			{
+				.ifnum = 2,
+				.type = QUIRK_AUDIO_EDIROL_UAXX
+			},
+			{
+				.ifnum = -1
+			}
+		}
+	}
+},
 	/* TODO: add Edirol MD-P1 support */
 {
 	USB_DEVICE(0x582, 0x00a6),
@@ -1383,7 +1420,6 @@
 		}
 	}
 },
-
 {
 	/* Roland SonicCell */
 	USB_DEVICE(0x0582, 0x00c2),
@@ -1415,7 +1451,35 @@
 		}
 	}
 },
-
+{
+	/* BOSS GT-10 */
+	USB_DEVICE(0x0582, 0x00da),
+	.driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
+		.ifnum = QUIRK_ANY_INTERFACE,
+		.type = QUIRK_COMPOSITE,
+		.data = (const struct snd_usb_audio_quirk[]) {
+			{
+				.ifnum = 0,
+				.type = QUIRK_AUDIO_STANDARD_INTERFACE
+			},
+			{
+				.ifnum = 1,
+				.type = QUIRK_AUDIO_STANDARD_INTERFACE
+			},
+			{
+				.ifnum = 2,
+				.type = QUIRK_MIDI_FIXED_ENDPOINT,
+				.data = & (const struct snd_usb_midi_endpoint_info) {
+					.out_cables = 0x0001,
+					.in_cables  = 0x0001
+				}
+			},
+			{
+				.ifnum = -1
+			}
+		}
+	}
+},
 
 /* Guillemot devices */
 {
diff --git a/sound/usb/usx2y/Makefile b/sound/usb/usx2y/Makefile
index 9ac22bc..7489330 100644
--- a/sound/usb/usx2y/Makefile
+++ b/sound/usb/usx2y/Makefile
@@ -1,3 +1,5 @@
 snd-usb-usx2y-objs := usbusx2y.o usX2Yhwdep.o usx2yhwdeppcm.o
+snd-usb-us122l-objs := us122l.o
 
 obj-$(CONFIG_SND_USB_USX2Y) += snd-usb-usx2y.o
+obj-$(CONFIG_SND_USB_US122L) += snd-usb-us122l.o
diff --git a/sound/usb/usx2y/us122l.c b/sound/usb/usx2y/us122l.c
new file mode 100644
index 0000000..b441fe2
--- /dev/null
+++ b/sound/usb/usx2y/us122l.c
@@ -0,0 +1,692 @@
+/*
+ * Copyright (C) 2007, 2008 Karsten Wiese <fzu@wemgehoertderstaat.de>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <sound/core.h>
+#include <sound/hwdep.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+#define MODNAME "US122L"
+#include "usb_stream.c"
+#include "../usbaudio.h"
+#include "us122l.h"
+
+MODULE_AUTHOR("Karsten Wiese <fzu@wemgehoertderstaat.de>");
+MODULE_DESCRIPTION("TASCAM "NAME_ALLCAPS" Version 0.5");
+MODULE_LICENSE("GPL");
+
+static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;	/* Index 0-max */
+static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;	/* Id for this card */
+							/* Enable this card */
+static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
+
+module_param_array(index, int, NULL, 0444);
+MODULE_PARM_DESC(index, "Index value for "NAME_ALLCAPS".");
+module_param_array(id, charp, NULL, 0444);
+MODULE_PARM_DESC(id, "ID string for "NAME_ALLCAPS".");
+module_param_array(enable, bool, NULL, 0444);
+MODULE_PARM_DESC(enable, "Enable "NAME_ALLCAPS".");
+
+static int snd_us122l_card_used[SNDRV_CARDS];
+
+
+static int us122l_create_usbmidi(struct snd_card *card)
+{
+	static struct snd_usb_midi_endpoint_info quirk_data = {
+		.out_ep = 4,
+		.in_ep = 3,
+		.out_cables =	0x001,
+		.in_cables =	0x001
+	};
+	static struct snd_usb_audio_quirk quirk = {
+		.vendor_name =	"US122L",
+		.product_name =	NAME_ALLCAPS,
+		.ifnum = 	1,
+		.type = QUIRK_MIDI_US122L,
+		.data = &quirk_data
+	};
+	struct usb_device *dev = US122L(card)->chip.dev;
+	struct usb_interface *iface = usb_ifnum_to_if(dev, 1);
+
+	return snd_usb_create_midi_interface(&US122L(card)->chip,
+					     iface, &quirk);
+}
+
+/*
+ * Wrapper for usb_control_msg().
+ * Allocates a temp buffer to prevent dmaing from/to the stack.
+ */
+static int us122l_ctl_msg(struct usb_device *dev, unsigned int pipe,
+			  __u8 request, __u8 requesttype,
+			  __u16 value, __u16 index, void *data,
+			  __u16 size, int timeout)
+{
+	int err;
+	void *buf = NULL;
+
+	if (size > 0) {
+		buf = kmemdup(data, size, GFP_KERNEL);
+		if (!buf)
+			return -ENOMEM;
+	}
+	err = usb_control_msg(dev, pipe, request, requesttype,
+			      value, index, buf, size, timeout);
+	if (size > 0) {
+		memcpy(data, buf, size);
+		kfree(buf);
+	}
+	return err;
+}
+
+static void pt_info_set(struct usb_device *dev, u8 v)
+{
+	int ret;
+
+	ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+			      'I',
+			      USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+			      v, 0, NULL, 0, 1000);
+	snd_printdd(KERN_DEBUG "%i\n", ret);
+}
+
+static void usb_stream_hwdep_vm_open(struct vm_area_struct *area)
+{
+	struct us122l *us122l = area->vm_private_data;
+	atomic_inc(&us122l->mmap_count);
+	snd_printdd(KERN_DEBUG "%i\n", atomic_read(&us122l->mmap_count));
+}
+
+static int usb_stream_hwdep_vm_fault(struct vm_area_struct *area,
+				     struct vm_fault *vmf)
+{
+	unsigned long offset;
+	struct page *page;
+	void *vaddr;
+	struct us122l *us122l = area->vm_private_data;
+	struct usb_stream *s;
+	int vm_f = VM_FAULT_SIGBUS;
+
+	mutex_lock(&us122l->mutex);
+	s = us122l->sk.s;
+	if (!s)
+		goto out;
+
+	offset = vmf->pgoff << PAGE_SHIFT;
+	if (offset < PAGE_ALIGN(s->read_size))
+		vaddr = (char *)s + offset;
+	else {
+		offset -= PAGE_ALIGN(s->read_size);
+		if (offset >= PAGE_ALIGN(s->write_size))
+			goto out;
+
+		vaddr = us122l->sk.write_page + offset;
+	}
+	page = virt_to_page(vaddr);
+
+	get_page(page);
+	mutex_unlock(&us122l->mutex);
+
+	vmf->page = page;
+	vm_f = 0;
+out:
+	return vm_f;
+}
+
+static void usb_stream_hwdep_vm_close(struct vm_area_struct *area)
+{
+	struct us122l *us122l = area->vm_private_data;
+	atomic_dec(&us122l->mmap_count);
+	snd_printdd(KERN_DEBUG "%i\n", atomic_read(&us122l->mmap_count));
+}
+
+static struct vm_operations_struct usb_stream_hwdep_vm_ops = {
+	.open = usb_stream_hwdep_vm_open,
+	.fault = usb_stream_hwdep_vm_fault,
+	.close = usb_stream_hwdep_vm_close,
+};
+
+
+static int usb_stream_hwdep_open(struct snd_hwdep *hw, struct file *file)
+{
+	struct us122l	*us122l = hw->private_data;
+	struct usb_interface *iface;
+	snd_printdd(KERN_DEBUG "%p %p\n", hw, file);
+	if (hw->used >= 2)
+		return -EBUSY;
+
+	if (!us122l->first)
+		us122l->first = file;
+	iface = usb_ifnum_to_if(us122l->chip.dev, 1);
+	usb_autopm_get_interface(iface);
+	return 0;
+}
+
+static int usb_stream_hwdep_release(struct snd_hwdep *hw, struct file *file)
+{
+	struct us122l	*us122l = hw->private_data;
+	struct usb_interface *iface = usb_ifnum_to_if(us122l->chip.dev, 1);
+	snd_printdd(KERN_DEBUG "%p %p\n", hw, file);
+	usb_autopm_put_interface(iface);
+	if (us122l->first == file)
+		us122l->first = NULL;
+	mutex_lock(&us122l->mutex);
+	if (us122l->master == file)
+		us122l->master = us122l->slave;
+
+	us122l->slave = NULL;
+	mutex_unlock(&us122l->mutex);
+	return 0;
+}
+
+static int usb_stream_hwdep_mmap(struct snd_hwdep *hw,
+				 struct file *filp, struct vm_area_struct *area)
+{
+	unsigned long	size = area->vm_end - area->vm_start;
+	struct us122l	*us122l = hw->private_data;
+	unsigned long offset;
+	struct usb_stream *s;
+	int err = 0;
+	bool read;
+
+	offset = area->vm_pgoff << PAGE_SHIFT;
+	mutex_lock(&us122l->mutex);
+	s = us122l->sk.s;
+	read = offset < s->read_size;
+	if (read && area->vm_flags & VM_WRITE) {
+		err = -EPERM;
+		goto out;
+	}
+	snd_printdd(KERN_DEBUG "%lu %u\n", size,
+		    read ? s->read_size : s->write_size);
+	/* if userspace tries to mmap beyond end of our buffer, fail */
+	if (size > PAGE_ALIGN(read ? s->read_size : s->write_size)) {
+		snd_printk(KERN_WARNING "%lu > %u\n", size,
+			   read ? s->read_size : s->write_size);
+		err = -EINVAL;
+		goto out;
+	}
+
+	area->vm_ops = &usb_stream_hwdep_vm_ops;
+	area->vm_flags |= VM_RESERVED;
+	area->vm_private_data = us122l;
+	atomic_inc(&us122l->mmap_count);
+out:
+	mutex_unlock(&us122l->mutex);
+	return err;
+}
+
+static unsigned int usb_stream_hwdep_poll(struct snd_hwdep *hw,
+					  struct file *file, poll_table *wait)
+{
+	struct us122l	*us122l = hw->private_data;
+	struct usb_stream *s = us122l->sk.s;
+	unsigned	*polled;
+	unsigned int	mask;
+
+	poll_wait(file, &us122l->sk.sleep, wait);
+
+	switch (s->state) {
+	case usb_stream_ready:
+		if (us122l->first == file)
+			polled = &s->periods_polled;
+		else
+			polled = &us122l->second_periods_polled;
+		if (*polled != s->periods_done) {
+			*polled = s->periods_done;
+			mask = POLLIN | POLLOUT | POLLWRNORM;
+			break;
+		}
+		/* Fall through */
+		mask = 0;
+		break;
+	default:
+		mask = POLLIN | POLLOUT | POLLWRNORM | POLLERR;
+		break;
+	}
+	return mask;
+}
+
+static void us122l_stop(struct us122l *us122l)
+{
+	struct list_head *p;
+	list_for_each(p, &us122l->chip.midi_list)
+		snd_usbmidi_input_stop(p);
+
+	usb_stream_stop(&us122l->sk);
+	usb_stream_free(&us122l->sk);
+}
+
+static int us122l_set_sample_rate(struct usb_device *dev, int rate)
+{
+	unsigned int ep = 0x81;
+	unsigned char data[3];
+	int err;
+
+	data[0] = rate;
+	data[1] = rate >> 8;
+	data[2] = rate >> 16;
+	err = us122l_ctl_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR,
+			     USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_OUT,
+			     SAMPLING_FREQ_CONTROL << 8, ep, data, 3, 1000);
+	if (err < 0)
+		snd_printk(KERN_ERR "%d: cannot set freq %d to ep 0x%x\n",
+			   dev->devnum, rate, ep);
+	return err;
+}
+
+static bool us122l_start(struct us122l *us122l,
+			 unsigned rate, unsigned period_frames)
+{
+	struct list_head *p;
+	int err;
+	unsigned use_packsize = 0;
+	bool success = false;
+
+	if (us122l->chip.dev->speed == USB_SPEED_HIGH) {
+		/* The us-122l's descriptor defaults to iso max_packsize 78,
+		   which isn't needed for samplerates <= 48000.
+		   Lets save some memory:
+		*/
+		switch (rate) {
+		case 44100:
+			use_packsize = 36;
+			break;
+		case 48000:
+			use_packsize = 42;
+			break;
+		case 88200:
+			use_packsize = 72;
+			break;
+		}
+	}
+	if (!usb_stream_new(&us122l->sk, us122l->chip.dev, 1, 2,
+			    rate, use_packsize, period_frames, 6))
+		goto out;
+
+	err = us122l_set_sample_rate(us122l->chip.dev, rate);
+	if (err < 0) {
+		us122l_stop(us122l);
+		snd_printk(KERN_ERR "us122l_set_sample_rate error \n");
+		goto out;
+	}
+	err = usb_stream_start(&us122l->sk);
+	if (err < 0) {
+		us122l_stop(us122l);
+		snd_printk(KERN_ERR "us122l_start error %i \n", err);
+		goto out;
+	}
+	list_for_each(p, &us122l->chip.midi_list)
+		snd_usbmidi_input_start(p);
+	success = true;
+out:
+	return success;
+}
+
+static int usb_stream_hwdep_ioctl(struct snd_hwdep *hw, struct file *file,
+				  unsigned cmd, unsigned long arg)
+{
+	struct usb_stream_config *cfg;
+	struct us122l *us122l = hw->private_data;
+	unsigned min_period_frames;
+	int err = 0;
+	bool high_speed;
+
+	if (cmd != SNDRV_USB_STREAM_IOCTL_SET_PARAMS)
+		return -ENOTTY;
+
+	cfg = kmalloc(sizeof(*cfg), GFP_KERNEL);
+	if (!cfg)
+		return -ENOMEM;
+
+	if (copy_from_user(cfg, (void *)arg, sizeof(*cfg))) {
+		err = -EFAULT;
+		goto free;
+	}
+	if (cfg->version != USB_STREAM_INTERFACE_VERSION) {
+		err = -ENXIO;
+		goto free;
+	}
+	high_speed = us122l->chip.dev->speed == USB_SPEED_HIGH;
+	if ((cfg->sample_rate != 44100 && cfg->sample_rate != 48000  &&
+	     (!high_speed ||
+	      (cfg->sample_rate != 88200 && cfg->sample_rate != 96000))) ||
+	    cfg->frame_size != 6 ||
+	    cfg->period_frames > 0x3000) {
+		err = -EINVAL;
+		goto free;
+	}
+	switch (cfg->sample_rate) {
+	case 44100:
+		min_period_frames = 48;
+		break;
+	case 48000:
+		min_period_frames = 52;
+		break;
+	default:
+		min_period_frames = 104;
+		break;
+	}
+	if (!high_speed)
+		min_period_frames <<= 1;
+	if (cfg->period_frames < min_period_frames) {
+		err = -EINVAL;
+		goto free;
+	}
+
+	snd_power_wait(hw->card, SNDRV_CTL_POWER_D0);
+
+	mutex_lock(&us122l->mutex);
+	if (!us122l->master)
+		us122l->master = file;
+	else if (us122l->master != file) {
+		if (memcmp(cfg, &us122l->sk.s->cfg, sizeof(*cfg))) {
+			err = -EIO;
+			goto unlock;
+		}
+		us122l->slave = file;
+	}
+	if (!us122l->sk.s ||
+	    memcmp(cfg, &us122l->sk.s->cfg, sizeof(*cfg)) ||
+	    us122l->sk.s->state == usb_stream_xrun) {
+		us122l_stop(us122l);
+		if (!us122l_start(us122l, cfg->sample_rate, cfg->period_frames))
+			err = -EIO;
+		else
+			err = 1;
+	}
+unlock:
+	mutex_unlock(&us122l->mutex);
+free:
+	kfree(cfg);
+	return err;
+}
+
+#define SND_USB_STREAM_ID "USB STREAM"
+static int usb_stream_hwdep_new(struct snd_card *card)
+{
+	int err;
+	struct snd_hwdep *hw;
+	struct usb_device *dev = US122L(card)->chip.dev;
+
+	err = snd_hwdep_new(card, SND_USB_STREAM_ID, 0, &hw);
+	if (err < 0)
+		return err;
+
+	hw->iface = SNDRV_HWDEP_IFACE_USB_STREAM;
+	hw->private_data = US122L(card);
+	hw->ops.open = usb_stream_hwdep_open;
+	hw->ops.release = usb_stream_hwdep_release;
+	hw->ops.ioctl = usb_stream_hwdep_ioctl;
+	hw->ops.ioctl_compat = usb_stream_hwdep_ioctl;
+	hw->ops.mmap = usb_stream_hwdep_mmap;
+	hw->ops.poll = usb_stream_hwdep_poll;
+
+	sprintf(hw->name, "/proc/bus/usb/%03d/%03d/hwdeppcm",
+		dev->bus->busnum, dev->devnum);
+	return 0;
+}
+
+
+static bool us122l_create_card(struct snd_card *card)
+{
+	int err;
+	struct us122l *us122l = US122L(card);
+
+	err = usb_set_interface(us122l->chip.dev, 1, 1);
+	if (err) {
+		snd_printk(KERN_ERR "usb_set_interface error \n");
+		return false;
+	}
+
+	pt_info_set(us122l->chip.dev, 0x11);
+	pt_info_set(us122l->chip.dev, 0x10);
+
+	if (!us122l_start(us122l, 44100, 256))
+		return false;
+
+	err = us122l_create_usbmidi(card);
+	if (err < 0) {
+		snd_printk(KERN_ERR "us122l_create_usbmidi error %i \n", err);
+		us122l_stop(us122l);
+		return false;
+	}
+	err = usb_stream_hwdep_new(card);
+	if (err < 0) {
+/* release the midi resources */
+		struct list_head *p;
+		list_for_each(p, &us122l->chip.midi_list)
+			snd_usbmidi_disconnect(p);
+
+		us122l_stop(us122l);
+		return false;
+	}
+	return true;
+}
+
+static struct snd_card *usx2y_create_card(struct usb_device *device)
+{
+	int		dev;
+	struct snd_card *card;
+	for (dev = 0; dev < SNDRV_CARDS; ++dev)
+		if (enable[dev] && !snd_us122l_card_used[dev])
+			break;
+	if (dev >= SNDRV_CARDS)
+		return NULL;
+	card = snd_card_new(index[dev], id[dev], THIS_MODULE,
+			    sizeof(struct us122l));
+	if (!card)
+		return NULL;
+	snd_us122l_card_used[US122L(card)->chip.index = dev] = 1;
+
+	US122L(card)->chip.dev = device;
+	US122L(card)->chip.card = card;
+	mutex_init(&US122L(card)->mutex);
+	init_waitqueue_head(&US122L(card)->sk.sleep);
+	INIT_LIST_HEAD(&US122L(card)->chip.midi_list);
+	strcpy(card->driver, "USB "NAME_ALLCAPS"");
+	sprintf(card->shortname, "TASCAM "NAME_ALLCAPS"");
+	sprintf(card->longname, "%s (%x:%x if %d at %03d/%03d)",
+		card->shortname,
+		le16_to_cpu(device->descriptor.idVendor),
+		le16_to_cpu(device->descriptor.idProduct),
+		0,
+		US122L(card)->chip.dev->bus->busnum,
+		US122L(card)->chip.dev->devnum
+		);
+	snd_card_set_dev(card, &device->dev);
+	return card;
+}
+
+static void *us122l_usb_probe(struct usb_interface *intf,
+			      const struct usb_device_id *device_id)
+{
+	struct usb_device *device = interface_to_usbdev(intf);
+	struct snd_card *card = usx2y_create_card(device);
+
+	if (!card)
+		return NULL;
+
+	if (!us122l_create_card(card) ||
+	    snd_card_register(card) < 0) {
+		snd_card_free(card);
+		return NULL;
+	}
+
+	usb_get_dev(device);
+	return card;
+}
+
+static int snd_us122l_probe(struct usb_interface *intf,
+			    const struct usb_device_id *id)
+{
+	struct snd_card *card;
+	snd_printdd(KERN_DEBUG"%p:%i\n",
+		    intf, intf->cur_altsetting->desc.bInterfaceNumber);
+	if (intf->cur_altsetting->desc.bInterfaceNumber != 1)
+		return 0;
+
+	card = us122l_usb_probe(usb_get_intf(intf), id);
+
+	if (card) {
+		usb_set_intfdata(intf, card);
+		return 0;
+	}
+
+	usb_put_intf(intf);
+	return -EIO;
+}
+
+static void snd_us122l_disconnect(struct usb_interface *intf)
+{
+	struct snd_card *card;
+	struct us122l *us122l;
+	struct list_head *p;
+
+	card = usb_get_intfdata(intf);
+	if (!card)
+		return;
+
+	snd_card_disconnect(card);
+
+	us122l = US122L(card);
+	mutex_lock(&us122l->mutex);
+	us122l_stop(us122l);
+	mutex_unlock(&us122l->mutex);
+	us122l->chip.shutdown = 1;
+
+/* release the midi resources */
+	list_for_each(p, &us122l->chip.midi_list) {
+		snd_usbmidi_disconnect(p);
+	}
+
+	usb_put_intf(intf);
+	usb_put_dev(US122L(card)->chip.dev);
+
+	while (atomic_read(&us122l->mmap_count))
+		msleep(500);
+
+	snd_card_free(card);
+}
+
+static int snd_us122l_suspend(struct usb_interface *intf, pm_message_t message)
+{
+	struct snd_card *card;
+	struct us122l *us122l;
+	struct list_head *p;
+
+	card = dev_get_drvdata(&intf->dev);
+	if (!card)
+		return 0;
+	snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
+
+	us122l = US122L(card);
+	if (!us122l)
+		return 0;
+
+	list_for_each(p, &us122l->chip.midi_list)
+		snd_usbmidi_input_stop(p);
+
+	mutex_lock(&us122l->mutex);
+	usb_stream_stop(&us122l->sk);
+	mutex_unlock(&us122l->mutex);
+
+	return 0;
+}
+
+static int snd_us122l_resume(struct usb_interface *intf)
+{
+	struct snd_card *card;
+	struct us122l *us122l;
+	struct list_head *p;
+	int err;
+
+	card = dev_get_drvdata(&intf->dev);
+	if (!card)
+		return 0;
+
+	us122l = US122L(card);
+	if (!us122l)
+		return 0;
+
+	mutex_lock(&us122l->mutex);
+	/* needed, doesn't restart without: */
+	err = usb_set_interface(us122l->chip.dev, 1, 1);
+	if (err) {
+		snd_printk(KERN_ERR "usb_set_interface error \n");
+		goto unlock;
+	}
+
+	pt_info_set(us122l->chip.dev, 0x11);
+	pt_info_set(us122l->chip.dev, 0x10);
+
+	err = us122l_set_sample_rate(us122l->chip.dev,
+				     us122l->sk.s->cfg.sample_rate);
+	if (err < 0) {
+		snd_printk(KERN_ERR "us122l_set_sample_rate error \n");
+		goto unlock;
+	}
+	err = usb_stream_start(&us122l->sk);
+	if (err)
+		goto unlock;
+
+	list_for_each(p, &us122l->chip.midi_list)
+		snd_usbmidi_input_start(p);
+unlock:
+	mutex_unlock(&us122l->mutex);
+	snd_power_change_state(card, SNDRV_CTL_POWER_D0);
+	return err;
+}
+
+static struct usb_device_id snd_us122l_usb_id_table[] = {
+	{
+		.match_flags =	USB_DEVICE_ID_MATCH_DEVICE,
+		.idVendor =	0x0644,
+		.idProduct =	USB_ID_US122L
+	},
+/*  	{ */		/* US-144 maybe works when @USB1.1. Untested. */
+/* 		.match_flags =	USB_DEVICE_ID_MATCH_DEVICE, */
+/* 		.idVendor =	0x0644, */
+/* 		.idProduct =	USB_ID_US144 */
+/* 	}, */
+	{ /* terminator */ }
+};
+
+MODULE_DEVICE_TABLE(usb, snd_us122l_usb_id_table);
+static struct usb_driver snd_us122l_usb_driver = {
+	.name =		"snd-usb-us122l",
+	.probe =	snd_us122l_probe,
+	.disconnect =	snd_us122l_disconnect,
+	.suspend =	snd_us122l_suspend,
+	.resume =	snd_us122l_resume,
+	.reset_resume =	snd_us122l_resume,
+	.id_table =	snd_us122l_usb_id_table,
+	.supports_autosuspend = 1
+};
+
+
+static int __init snd_us122l_module_init(void)
+{
+	return usb_register(&snd_us122l_usb_driver);
+}
+
+static void __exit snd_us122l_module_exit(void)
+{
+	usb_deregister(&snd_us122l_usb_driver);
+}
+
+module_init(snd_us122l_module_init)
+module_exit(snd_us122l_module_exit)
diff --git a/sound/usb/usx2y/us122l.h b/sound/usb/usx2y/us122l.h
new file mode 100644
index 0000000..3d10c4b
--- /dev/null
+++ b/sound/usb/usx2y/us122l.h
@@ -0,0 +1,27 @@
+#ifndef US122L_H
+#define US122L_H
+
+
+struct us122l {
+	struct snd_usb_audio 	chip;
+	int			stride;
+	struct usb_stream_kernel sk;
+
+	struct mutex		mutex;
+	struct file		*first;
+	unsigned		second_periods_polled;
+	struct file		*master;
+	struct file		*slave;
+
+	atomic_t		mmap_count;
+};
+
+
+#define US122L(c) ((struct us122l *)(c)->private_data)
+
+#define NAME_ALLCAPS "US-122L"
+
+#define USB_ID_US122L 0x800E
+#define USB_ID_US144 0x800F
+
+#endif
diff --git a/sound/usb/usx2y/usb_stream.c b/sound/usb/usx2y/usb_stream.c
new file mode 100644
index 0000000..ff23cc1
--- /dev/null
+++ b/sound/usb/usx2y/usb_stream.c
@@ -0,0 +1,761 @@
+/*
+ * Copyright (C) 2007, 2008 Karsten Wiese <fzu@wemgehoertderstaat.de>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/usb.h>
+
+#include "usb_stream.h"
+
+
+/*                             setup                                  */
+
+static unsigned usb_stream_next_packet_size(struct usb_stream_kernel *sk)
+{
+	struct usb_stream *s = sk->s;
+	sk->out_phase_peeked = (sk->out_phase & 0xffff) + sk->freqn;
+	return (sk->out_phase_peeked >> 16) * s->cfg.frame_size;
+}
+
+static void playback_prep_freqn(struct usb_stream_kernel *sk, struct urb *urb)
+{
+	struct usb_stream *s = sk->s;
+	unsigned l = 0;
+	int pack;
+
+	urb->iso_frame_desc[0].offset = 0;
+	urb->iso_frame_desc[0].length =	usb_stream_next_packet_size(sk);
+	sk->out_phase = sk->out_phase_peeked;
+	urb->transfer_buffer_length = urb->iso_frame_desc[0].length;
+
+	for (pack = 1; pack < sk->n_o_ps; pack++) {
+		l = usb_stream_next_packet_size(sk);
+		if (s->idle_outsize + urb->transfer_buffer_length + l >
+		    s->period_size)
+			goto check;
+
+		sk->out_phase = sk->out_phase_peeked;
+		urb->iso_frame_desc[pack].offset = urb->transfer_buffer_length;
+		urb->iso_frame_desc[pack].length = l;
+		urb->transfer_buffer_length += l;
+	}
+	snd_printdd(KERN_DEBUG "%i\n", urb->transfer_buffer_length);
+
+check:
+	urb->number_of_packets = pack;
+	s->idle_outsize += urb->transfer_buffer_length - s->period_size;
+	snd_printdd(KERN_DEBUG "idle=%i ul=%i ps=%i\n", s->idle_outsize,
+		    urb->transfer_buffer_length, s->period_size);
+}
+
+static void init_pipe_urbs(struct usb_stream_kernel *sk, unsigned use_packsize,
+			   struct urb **urbs, char *transfer,
+			   struct usb_device *dev, int pipe)
+{
+	int u, p;
+	int maxpacket = use_packsize ?
+		use_packsize : usb_maxpacket(dev, pipe, usb_pipeout(pipe));
+	int transfer_length = maxpacket * sk->n_o_ps;
+
+	for (u = 0; u < USB_STREAM_NURBS;
+	     ++u, transfer += transfer_length) {
+		struct urb *urb = urbs[u];
+		struct usb_iso_packet_descriptor *desc;
+		urb->transfer_flags = URB_ISO_ASAP;
+		urb->transfer_buffer = transfer;
+		urb->dev = dev;
+		urb->pipe = pipe;
+		urb->number_of_packets = sk->n_o_ps;
+		urb->context = sk;
+		urb->interval = 1;
+		if (usb_pipeout(pipe))
+			continue;
+
+		urb->transfer_buffer_length = transfer_length;
+		desc = urb->iso_frame_desc;
+		desc->offset = 0;
+		desc->length = maxpacket;
+		for (p = 1; p < sk->n_o_ps; ++p) {
+			desc[p].offset = desc[p - 1].offset + maxpacket;
+			desc[p].length = maxpacket;
+		}
+	}
+}
+
+static void init_urbs(struct usb_stream_kernel *sk, unsigned use_packsize,
+		      struct usb_device *dev, int in_pipe, int out_pipe)
+{
+	struct usb_stream	*s = sk->s;
+	char			*indata = (char *)s + sizeof(*s) +
+					sizeof(struct usb_stream_packet) *
+					s->inpackets;
+	int			u;
+
+	for (u = 0; u < USB_STREAM_NURBS; ++u) {
+		sk->inurb[u] = usb_alloc_urb(sk->n_o_ps, GFP_KERNEL);
+		sk->outurb[u] = usb_alloc_urb(sk->n_o_ps, GFP_KERNEL);
+	}
+
+	init_pipe_urbs(sk, use_packsize, sk->inurb, indata, dev, in_pipe);
+	init_pipe_urbs(sk, use_packsize, sk->outurb, sk->write_page, dev,
+		       out_pipe);
+}
+
+
+/*
+ * convert a sampling rate into our full speed format (fs/1000 in Q16.16)
+ * this will overflow at approx 524 kHz
+ */
+static inline unsigned get_usb_full_speed_rate(unsigned rate)
+{
+	return ((rate << 13) + 62) / 125;
+}
+
+/*
+ * convert a sampling rate into USB high speed format (fs/8000 in Q16.16)
+ * this will overflow at approx 4 MHz
+ */
+static inline unsigned get_usb_high_speed_rate(unsigned rate)
+{
+	return ((rate << 10) + 62) / 125;
+}
+
+void usb_stream_free(struct usb_stream_kernel *sk)
+{
+	struct usb_stream *s;
+	unsigned u;
+
+	for (u = 0; u < USB_STREAM_NURBS; ++u) {
+		usb_free_urb(sk->inurb[u]);
+		sk->inurb[u] = NULL;
+		usb_free_urb(sk->outurb[u]);
+		sk->outurb[u] = NULL;
+	}
+
+	s = sk->s;
+	if (!s)
+		return;
+
+	free_pages((unsigned long)sk->write_page, get_order(s->write_size));
+	sk->write_page = NULL;
+	free_pages((unsigned long)s, get_order(s->read_size));
+	sk->s = NULL;
+}
+
+struct usb_stream *usb_stream_new(struct usb_stream_kernel *sk,
+				  struct usb_device *dev,
+				  unsigned in_endpoint, unsigned out_endpoint,
+				  unsigned sample_rate, unsigned use_packsize,
+				  unsigned period_frames, unsigned frame_size)
+{
+	int packets, max_packsize;
+	int in_pipe, out_pipe;
+	int read_size = sizeof(struct usb_stream);
+	int write_size;
+	int usb_frames = dev->speed == USB_SPEED_HIGH ? 8000 : 1000;
+	int pg;
+
+	in_pipe = usb_rcvisocpipe(dev, in_endpoint);
+	out_pipe = usb_sndisocpipe(dev, out_endpoint);
+
+	max_packsize = use_packsize ?
+		use_packsize : usb_maxpacket(dev, in_pipe, 0);
+
+	/*
+		t_period = period_frames / sample_rate
+		iso_packs = t_period / t_iso_frame
+			= (period_frames / sample_rate) * (1 / t_iso_frame)
+	*/
+
+	packets = period_frames * usb_frames / sample_rate + 1;
+
+	if (dev->speed == USB_SPEED_HIGH)
+		packets = (packets + 7) & ~7;
+
+	read_size += packets * USB_STREAM_URBDEPTH *
+		(max_packsize + sizeof(struct usb_stream_packet));
+
+	max_packsize = usb_maxpacket(dev, out_pipe, 1);
+	write_size = max_packsize * packets * USB_STREAM_URBDEPTH;
+
+	if (read_size >= 256*PAGE_SIZE || write_size >= 256*PAGE_SIZE) {
+		snd_printk(KERN_WARNING "a size exceeds 128*PAGE_SIZE\n");
+		goto out;
+	}
+
+	pg = get_order(read_size);
+	sk->s = (void *) __get_free_pages(GFP_KERNEL|__GFP_COMP|__GFP_ZERO, pg);
+	if (!sk->s) {
+		snd_printk(KERN_WARNING "couldn't __get_free_pages()\n");
+		goto out;
+	}
+	sk->s->cfg.version = USB_STREAM_INTERFACE_VERSION;
+
+	sk->s->read_size = read_size;
+
+	sk->s->cfg.sample_rate = sample_rate;
+	sk->s->cfg.frame_size = frame_size;
+	sk->n_o_ps = packets;
+	sk->s->inpackets = packets * USB_STREAM_URBDEPTH;
+	sk->s->cfg.period_frames = period_frames;
+	sk->s->period_size = frame_size * period_frames;
+
+	sk->s->write_size = write_size;
+	pg = get_order(write_size);
+
+	sk->write_page =
+		(void *)__get_free_pages(GFP_KERNEL|__GFP_COMP|__GFP_ZERO, pg);
+	if (!sk->write_page) {
+		snd_printk(KERN_WARNING "couldn't __get_free_pages()\n");
+		usb_stream_free(sk);
+		return NULL;
+	}
+
+	/* calculate the frequency in 16.16 format */
+	if (dev->speed == USB_SPEED_FULL)
+		sk->freqn = get_usb_full_speed_rate(sample_rate);
+	else
+		sk->freqn = get_usb_high_speed_rate(sample_rate);
+
+	init_urbs(sk, use_packsize, dev, in_pipe, out_pipe);
+	sk->s->state = usb_stream_stopped;
+out:
+	return sk->s;
+}
+
+
+/*                             start                                  */
+
+static bool balance_check(struct usb_stream_kernel *sk, struct urb *urb)
+{
+	bool r;
+	if (unlikely(urb->status)) {
+		if (urb->status != -ESHUTDOWN && urb->status != -ENOENT)
+			snd_printk(KERN_WARNING "status=%i\n", urb->status);
+		sk->iso_frame_balance = 0x7FFFFFFF;
+		return false;
+	}
+	r = sk->iso_frame_balance == 0;
+	if (!r)
+		sk->i_urb = urb;
+	return r;
+}
+
+static bool balance_playback(struct usb_stream_kernel *sk, struct urb *urb)
+{
+	sk->iso_frame_balance += urb->number_of_packets;
+	return balance_check(sk, urb);
+}
+
+static bool balance_capture(struct usb_stream_kernel *sk, struct urb *urb)
+{
+	sk->iso_frame_balance -= urb->number_of_packets;
+	return balance_check(sk, urb);
+}
+
+static void subs_set_complete(struct urb **urbs, void (*complete)(struct urb *))
+{
+	int u;
+
+	for (u = 0; u < USB_STREAM_NURBS; u++) {
+		struct urb *urb = urbs[u];
+		urb->complete = complete;
+	}
+}
+
+int usb_stream_prepare_playback(struct usb_stream_kernel *sk, struct urb *inurb)
+{
+	struct usb_stream *s = sk->s;
+	struct urb *io;
+	struct usb_iso_packet_descriptor *id, *od;
+	int p, l = 0;
+
+	io = sk->idle_outurb;
+	od = io->iso_frame_desc;
+	io->transfer_buffer_length = 0;
+
+	for (p = 0; s->sync_packet < 0; ++p, ++s->sync_packet) {
+		struct urb *ii = sk->completed_inurb;
+		id = ii->iso_frame_desc +
+			ii->number_of_packets + s->sync_packet;
+		l = id->actual_length;
+
+		od[p].length = l;
+		od[p].offset = io->transfer_buffer_length;
+		io->transfer_buffer_length += l;
+	}
+
+	for (;
+	     s->sync_packet < inurb->number_of_packets && p < sk->n_o_ps;
+	     ++p, ++s->sync_packet) {
+		l = inurb->iso_frame_desc[s->sync_packet].actual_length;
+
+		if (s->idle_outsize + io->transfer_buffer_length + l >
+		    s->period_size)
+			goto check_ok;
+
+		od[p].length = l;
+		od[p].offset = io->transfer_buffer_length;
+		io->transfer_buffer_length += l;
+	}
+
+check_ok:
+	s->sync_packet -= inurb->number_of_packets;
+	if (s->sync_packet < -2 || s->sync_packet > 0) {
+		snd_printk(KERN_WARNING "invalid sync_packet = %i;"
+			   " p=%i nop=%i %i %x %x %x > %x\n",
+			   s->sync_packet, p, inurb->number_of_packets,
+			   s->idle_outsize + io->transfer_buffer_length + l,
+			   s->idle_outsize, io->transfer_buffer_length,  l,
+			   s->period_size);
+		return -1;
+	}
+	if (io->transfer_buffer_length % s->cfg.frame_size) {
+		snd_printk(KERN_WARNING"invalid outsize = %i\n",
+			   io->transfer_buffer_length);
+		return -1;
+	}
+	s->idle_outsize += io->transfer_buffer_length - s->period_size;
+	io->number_of_packets = p;
+	if (s->idle_outsize > 0) {
+		snd_printk(KERN_WARNING "idle=%i\n", s->idle_outsize);
+		return -1;
+	}
+	return 0;
+}
+
+static void prepare_inurb(int number_of_packets, struct urb *iu)
+{
+	struct usb_iso_packet_descriptor *id;
+	int p;
+
+	iu->number_of_packets = number_of_packets;
+	id = iu->iso_frame_desc;
+	id->offset = 0;
+	for (p = 0; p < iu->number_of_packets - 1; ++p)
+		id[p + 1].offset = id[p].offset + id[p].length;
+
+	iu->transfer_buffer_length =
+		id[0].length * iu->number_of_packets;
+}
+
+static int submit_urbs(struct usb_stream_kernel *sk,
+		       struct urb *inurb, struct urb *outurb)
+{
+	int err;
+	prepare_inurb(sk->idle_outurb->number_of_packets, sk->idle_inurb);
+	err = usb_submit_urb(sk->idle_inurb, GFP_ATOMIC);
+	if (err < 0) {
+		snd_printk(KERN_ERR "%i\n", err);
+		return err;
+	}
+	sk->idle_inurb = sk->completed_inurb;
+	sk->completed_inurb = inurb;
+	err = usb_submit_urb(sk->idle_outurb, GFP_ATOMIC);
+	if (err < 0) {
+		snd_printk(KERN_ERR "%i\n", err);
+		return err;
+	}
+	sk->idle_outurb = sk->completed_outurb;
+	sk->completed_outurb = outurb;
+	return 0;
+}
+
+#ifdef DEBUG_LOOP_BACK
+/*
+  This loop_back() shows how to read/write the period data.
+ */
+static void loop_back(struct usb_stream *s)
+{
+	char *i, *o;
+	int il, ol, l, p;
+	struct urb *iu;
+	struct usb_iso_packet_descriptor *id;
+
+	o = s->playback1st_to;
+	ol = s->playback1st_size;
+	l = 0;
+
+	if (s->insplit_pack >= 0) {
+		iu = sk->idle_inurb;
+		id = iu->iso_frame_desc;
+		p = s->insplit_pack;
+	} else
+		goto second;
+loop:
+	for (; p < iu->number_of_packets && l < s->period_size; ++p) {
+		i = iu->transfer_buffer + id[p].offset;
+		il = id[p].actual_length;
+		if (l + il > s->period_size)
+			il = s->period_size - l;
+		if (il <= ol) {
+			memcpy(o, i, il);
+			o += il;
+			ol -= il;
+		} else {
+			memcpy(o, i, ol);
+			singen_6pack(o, ol);
+			o = s->playback_to;
+			memcpy(o, i + ol, il - ol);
+			o += il - ol;
+			ol = s->period_size - s->playback1st_size;
+		}
+		l += il;
+	}
+	if (iu == sk->completed_inurb) {
+		if (l != s->period_size)
+			printk(KERN_DEBUG"%s:%i %i\n", __func__, __LINE__,
+			       l/(int)s->cfg.frame_size);
+
+		return;
+	}
+second:
+	iu = sk->completed_inurb;
+	id = iu->iso_frame_desc;
+	p = 0;
+	goto loop;
+
+}
+#else
+static void loop_back(struct usb_stream *s)
+{
+}
+#endif
+
+static void stream_idle(struct usb_stream_kernel *sk,
+			struct urb *inurb, struct urb *outurb)
+{
+	struct usb_stream *s = sk->s;
+	int l, p;
+	int insize = s->idle_insize;
+	int urb_size = 0;
+
+	s->inpacket_split = s->next_inpacket_split;
+	s->inpacket_split_at = s->next_inpacket_split_at;
+	s->next_inpacket_split = -1;
+	s->next_inpacket_split_at = 0;
+
+	for (p = 0; p < inurb->number_of_packets; ++p) {
+		struct usb_iso_packet_descriptor *id = inurb->iso_frame_desc;
+		l = id[p].actual_length;
+		if (unlikely(l == 0 || id[p].status)) {
+			snd_printk(KERN_WARNING "underrun, status=%u\n",
+				   id[p].status);
+			goto err_out;
+		}
+		s->inpacket_head++;
+		s->inpacket_head %= s->inpackets;
+		if (s->inpacket_split == -1)
+			s->inpacket_split = s->inpacket_head;
+
+		s->inpacket[s->inpacket_head].offset =
+			id[p].offset + (inurb->transfer_buffer - (void *)s);
+		s->inpacket[s->inpacket_head].length = l;
+		if (insize + l > s->period_size &&
+		    s->next_inpacket_split == -1) {
+			s->next_inpacket_split = s->inpacket_head;
+			s->next_inpacket_split_at = s->period_size - insize;
+		}
+		insize += l;
+		urb_size += l;
+	}
+	s->idle_insize += urb_size - s->period_size;
+	if (s->idle_insize < 0) {
+		snd_printk(KERN_WARNING "%i\n",
+			   (s->idle_insize)/(int)s->cfg.frame_size);
+		goto err_out;
+	}
+	s->insize_done += urb_size;
+
+	l = s->idle_outsize;
+	s->outpacket[0].offset = (sk->idle_outurb->transfer_buffer -
+				  sk->write_page) - l;
+
+	if (usb_stream_prepare_playback(sk, inurb) < 0)
+		goto err_out;
+
+	s->outpacket[0].length = sk->idle_outurb->transfer_buffer_length + l;
+	s->outpacket[1].offset = sk->completed_outurb->transfer_buffer -
+		sk->write_page;
+
+	if (submit_urbs(sk, inurb, outurb) < 0)
+		goto err_out;
+
+	loop_back(s);
+	s->periods_done++;
+	wake_up_all(&sk->sleep);
+	return;
+err_out:
+	s->state = usb_stream_xrun;
+	wake_up_all(&sk->sleep);
+}
+
+static void i_capture_idle(struct urb *urb)
+{
+	struct usb_stream_kernel *sk = urb->context;
+	if (balance_capture(sk, urb))
+		stream_idle(sk, urb, sk->i_urb);
+}
+
+static void i_playback_idle(struct urb *urb)
+{
+	struct usb_stream_kernel *sk = urb->context;
+	if (balance_playback(sk, urb))
+		stream_idle(sk, sk->i_urb, urb);
+}
+
+static void stream_start(struct usb_stream_kernel *sk,
+			 struct urb *inurb, struct urb *outurb)
+{
+	struct usb_stream *s = sk->s;
+	if (s->state >= usb_stream_sync1) {
+		int l, p, max_diff, max_diff_0;
+		int urb_size = 0;
+		unsigned frames_per_packet, min_frames = 0;
+		frames_per_packet = (s->period_size - s->idle_insize);
+		frames_per_packet <<= 8;
+		frames_per_packet /=
+			s->cfg.frame_size * inurb->number_of_packets;
+		frames_per_packet++;
+
+		max_diff_0 = s->cfg.frame_size;
+		if (s->cfg.period_frames >= 256)
+			max_diff_0 <<= 1;
+		if (s->cfg.period_frames >= 1024)
+			max_diff_0 <<= 1;
+		max_diff = max_diff_0;
+		for (p = 0; p < inurb->number_of_packets; ++p) {
+			int diff;
+			l = inurb->iso_frame_desc[p].actual_length;
+			urb_size += l;
+
+			min_frames += frames_per_packet;
+			diff = urb_size -
+				(min_frames >> 8) * s->cfg.frame_size;
+			if (diff < max_diff) {
+				snd_printdd(KERN_DEBUG "%i %i %i %i\n",
+					    s->insize_done,
+					    urb_size / (int)s->cfg.frame_size,
+					    inurb->number_of_packets, diff);
+				max_diff = diff;
+			}
+		}
+		s->idle_insize -= max_diff - max_diff_0;
+		s->idle_insize += urb_size - s->period_size;
+		if (s->idle_insize < 0) {
+			snd_printk("%i %i %i\n",
+				   s->idle_insize, urb_size, s->period_size);
+			return;
+		} else if (s->idle_insize == 0) {
+			s->next_inpacket_split =
+				(s->inpacket_head + 1) % s->inpackets;
+			s->next_inpacket_split_at = 0;
+		} else {
+			unsigned split = s->inpacket_head;
+			l = s->idle_insize;
+			while (l > s->inpacket[split].length) {
+				l -= s->inpacket[split].length;
+				if (split == 0)
+					split = s->inpackets - 1;
+				else
+					split--;
+			}
+			s->next_inpacket_split = split;
+			s->next_inpacket_split_at =
+				s->inpacket[split].length - l;
+		}
+
+		s->insize_done += urb_size;
+
+		if (usb_stream_prepare_playback(sk, inurb) < 0)
+			return;
+
+	} else
+		playback_prep_freqn(sk, sk->idle_outurb);
+
+	if (submit_urbs(sk, inurb, outurb) < 0)
+		return;
+
+	if (s->state == usb_stream_sync1 && s->insize_done > 360000) {
+		/* just guesswork                            ^^^^^^ */
+		s->state = usb_stream_ready;
+		subs_set_complete(sk->inurb, i_capture_idle);
+		subs_set_complete(sk->outurb, i_playback_idle);
+	}
+}
+
+static void i_capture_start(struct urb *urb)
+{
+	struct usb_iso_packet_descriptor *id = urb->iso_frame_desc;
+	struct usb_stream_kernel *sk = urb->context;
+	struct usb_stream *s = sk->s;
+	int p;
+	int empty = 0;
+
+	if (urb->status) {
+		snd_printk(KERN_WARNING "status=%i\n", urb->status);
+		return;
+	}
+
+	for (p = 0; p < urb->number_of_packets; ++p) {
+		int l = id[p].actual_length;
+		if (l < s->cfg.frame_size) {
+			++empty;
+			if (s->state >= usb_stream_sync0) {
+				snd_printk(KERN_WARNING "%i\n", l);
+				return;
+			}
+		}
+		s->inpacket_head++;
+		s->inpacket_head %= s->inpackets;
+		s->inpacket[s->inpacket_head].offset =
+			id[p].offset + (urb->transfer_buffer - (void *)s);
+		s->inpacket[s->inpacket_head].length = l;
+	}
+#ifdef SHOW_EMPTY
+	if (empty) {
+		printk(KERN_DEBUG"%s:%i: %i", __func__, __LINE__,
+		       urb->iso_frame_desc[0].actual_length);
+		for (pack = 1; pack < urb->number_of_packets; ++pack) {
+			int l = urb->iso_frame_desc[pack].actual_length;
+			printk(" %i", l);
+		}
+		printk("\n");
+	}
+#endif
+	if (!empty && s->state < usb_stream_sync1)
+		++s->state;
+
+	if (balance_capture(sk, urb))
+		stream_start(sk, urb, sk->i_urb);
+}
+
+static void i_playback_start(struct urb *urb)
+{
+	struct usb_stream_kernel *sk = urb->context;
+	if (balance_playback(sk, urb))
+		stream_start(sk, sk->i_urb, urb);
+}
+
+int usb_stream_start(struct usb_stream_kernel *sk)
+{
+	struct usb_stream *s = sk->s;
+	int frame = 0, iters = 0;
+	int u, err;
+	int try = 0;
+
+	if (s->state != usb_stream_stopped)
+		return -EAGAIN;
+
+	subs_set_complete(sk->inurb, i_capture_start);
+	subs_set_complete(sk->outurb, i_playback_start);
+	memset(sk->write_page, 0, s->write_size);
+dotry:
+	s->insize_done = 0;
+	s->idle_insize = 0;
+	s->idle_outsize = 0;
+	s->sync_packet = -1;
+	s->inpacket_head = -1;
+	sk->iso_frame_balance = 0;
+	++try;
+	for (u = 0; u < 2; u++) {
+		struct urb *inurb = sk->inurb[u];
+		struct urb *outurb = sk->outurb[u];
+		playback_prep_freqn(sk, outurb);
+		inurb->number_of_packets = outurb->number_of_packets;
+		inurb->transfer_buffer_length =
+			inurb->number_of_packets *
+			inurb->iso_frame_desc[0].length;
+		preempt_disable();
+		if (u == 0) {
+			int now;
+			struct usb_device *dev = inurb->dev;
+			frame = usb_get_current_frame_number(dev);
+			do {
+				now = usb_get_current_frame_number(dev);
+				++iters;
+			} while (now > -1 && now == frame);
+		}
+		err = usb_submit_urb(inurb, GFP_ATOMIC);
+		if (err < 0) {
+			preempt_enable();
+			snd_printk(KERN_ERR"usb_submit_urb(sk->inurb[%i])"
+				   " returned %i\n", u, err);
+			return err;
+		}
+		err = usb_submit_urb(outurb, GFP_ATOMIC);
+		if (err < 0) {
+			preempt_enable();
+			snd_printk(KERN_ERR"usb_submit_urb(sk->outurb[%i])"
+				   " returned %i\n", u, err);
+			return err;
+		}
+		preempt_enable();
+		if (inurb->start_frame != outurb->start_frame) {
+			snd_printd(KERN_DEBUG
+				   "u[%i] start_frames differ in:%u out:%u\n",
+				   u, inurb->start_frame, outurb->start_frame);
+			goto check_retry;
+		}
+	}
+	snd_printdd(KERN_DEBUG "%i %i\n", frame, iters);
+	try = 0;
+check_retry:
+	if (try) {
+		usb_stream_stop(sk);
+		if (try < 5) {
+			msleep(1500);
+			snd_printd(KERN_DEBUG "goto dotry;\n");
+			goto dotry;
+		}
+		snd_printk(KERN_WARNING"couldn't start"
+			   " all urbs on the same start_frame.\n");
+		return -EFAULT;
+	}
+
+	sk->idle_inurb = sk->inurb[USB_STREAM_NURBS - 2];
+	sk->idle_outurb = sk->outurb[USB_STREAM_NURBS - 2];
+	sk->completed_inurb = sk->inurb[USB_STREAM_NURBS - 1];
+	sk->completed_outurb = sk->outurb[USB_STREAM_NURBS - 1];
+
+/* wait, check */
+	{
+		int wait_ms = 3000;
+		while (s->state != usb_stream_ready && wait_ms > 0) {
+			snd_printdd(KERN_DEBUG "%i\n", s->state);
+			msleep(200);
+			wait_ms -= 200;
+		}
+	}
+
+	return s->state == usb_stream_ready ? 0 : -EFAULT;
+}
+
+
+/*                             stop                                   */
+
+void usb_stream_stop(struct usb_stream_kernel *sk)
+{
+	int u;
+	if (!sk->s)
+		return;
+	for (u = 0; u < USB_STREAM_NURBS; ++u) {
+		usb_kill_urb(sk->inurb[u]);
+		usb_kill_urb(sk->outurb[u]);
+	}
+	sk->s->state = usb_stream_stopped;
+	msleep(400);
+}
diff --git a/sound/usb/usx2y/usb_stream.h b/sound/usb/usx2y/usb_stream.h
new file mode 100644
index 0000000..4dd74ab
--- /dev/null
+++ b/sound/usb/usx2y/usb_stream.h
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2007, 2008 Karsten Wiese <fzu@wemgehoertderstaat.de>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#define USB_STREAM_INTERFACE_VERSION 2
+
+#define SNDRV_USB_STREAM_IOCTL_SET_PARAMS \
+	_IOW('H', 0x90, struct usb_stream_config)
+
+struct usb_stream_packet {
+	unsigned offset;
+	unsigned length;
+};
+
+
+struct usb_stream_config {
+	unsigned version;
+	unsigned sample_rate;
+	unsigned period_frames;
+	unsigned frame_size;
+};
+
+struct usb_stream {
+	struct usb_stream_config cfg;
+	unsigned read_size;
+	unsigned write_size;
+
+	int period_size;
+
+	unsigned state;
+
+	int idle_insize;
+	int idle_outsize;
+	int sync_packet;
+	unsigned insize_done;
+	unsigned periods_done;
+	unsigned periods_polled;
+
+	struct usb_stream_packet outpacket[2];
+	unsigned		 inpackets;
+	unsigned		 inpacket_head;
+	unsigned		 inpacket_split;
+	unsigned		 inpacket_split_at;
+	unsigned		 next_inpacket_split;
+	unsigned		 next_inpacket_split_at;
+	struct usb_stream_packet inpacket[0];
+};
+
+enum usb_stream_state {
+	usb_stream_invalid,
+	usb_stream_stopped,
+	usb_stream_sync0,
+	usb_stream_sync1,
+	usb_stream_ready,
+	usb_stream_running,
+	usb_stream_xrun,
+};
+
+#if __KERNEL__
+
+#define USB_STREAM_NURBS 4
+#define USB_STREAM_URBDEPTH 4
+
+struct usb_stream_kernel {
+	struct usb_stream *s;
+
+	void *write_page;
+
+	unsigned n_o_ps;
+
+	struct urb *inurb[USB_STREAM_NURBS];
+	struct urb *idle_inurb;
+	struct urb *completed_inurb;
+	struct urb *outurb[USB_STREAM_NURBS];
+	struct urb *idle_outurb;
+	struct urb *completed_outurb;
+	struct urb *i_urb;
+
+	int iso_frame_balance;
+
+	wait_queue_head_t sleep;
+
+	unsigned out_phase;
+	unsigned out_phase_peeked;
+	unsigned freqn;
+};
+
+struct usb_stream *usb_stream_new(struct usb_stream_kernel *sk,
+				  struct usb_device *dev,
+				  unsigned in_endpoint, unsigned out_endpoint,
+				  unsigned sample_rate, unsigned use_packsize,
+				  unsigned period_frames, unsigned frame_size);
+void usb_stream_free(struct usb_stream_kernel *);
+int usb_stream_start(struct usb_stream_kernel *);
+void usb_stream_stop(struct usb_stream_kernel *);
+
+
+#endif